summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>2013-05-10 18:56:23 +0000
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>2013-05-10 18:56:23 +0000
commit7d2950f11a8136b91c0db844bda760e6efba213a (patch)
tree1c8a17e717afa20ffa6f58fa6d30f1682683c0db
downloadcups-release-1.5b1.tar.gz
Import cups.org releasesrelease-1.5b1
git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/tags/release-1.5b1@4306 a1ca3aef-8c08-0410-bb20-df032aa958be
-rw-r--r--CHANGES-1.0.txt217
-rw-r--r--CHANGES-1.1.txt3462
-rw-r--r--CHANGES-1.2.txt1261
-rw-r--r--CHANGES-1.3.txt856
-rw-r--r--CHANGES-1.4.txt835
-rw-r--r--CHANGES.txt98
-rw-r--r--CREDITS.txt49
-rw-r--r--INSTALL.txt207
-rw-r--r--IPPTOOL.txt86
-rw-r--r--LICENSE.txt971
-rw-r--r--Makedefs.in308
-rw-r--r--Makefile330
-rw-r--r--README.txt164
-rw-r--r--backend/Dependencies101
-rw-r--r--backend/Makefile285
-rw-r--r--backend/backend-private.h323
-rw-r--r--backend/dnssd.c921
-rw-r--r--backend/ieee1284.c473
-rw-r--r--backend/ipp.c2981
-rw-r--r--backend/lpd.c1342
-rw-r--r--backend/network.c300
-rw-r--r--backend/parallel.c676
-rwxr-xr-xbackend/pseudo30
-rw-r--r--backend/runloop.c526
-rw-r--r--backend/serial.c1327
-rw-r--r--backend/snmp-supplies.c985
-rw-r--r--backend/snmp.c1375
-rw-r--r--backend/snmp.txt172
-rw-r--r--backend/socket.c527
-rw-r--r--backend/test1284.c84
-rw-r--r--backend/testbackend.c651
-rw-r--r--backend/testsupplies.c83
-rw-r--r--backend/usb-darwin.c2297
-rw-r--r--backend/usb-libusb.c834
-rw-r--r--backend/usb-unix.c623
-rw-r--r--backend/usb.c264
-rw-r--r--berkeley/Dependencies34
-rw-r--r--berkeley/Makefile167
-rw-r--r--berkeley/lpc.c449
-rw-r--r--berkeley/lpq.c678
-rw-r--r--berkeley/lpr.c417
-rw-r--r--berkeley/lprm.c217
-rw-r--r--cgi-bin/Dependencies75
-rw-r--r--cgi-bin/Makefile382
-rw-r--r--cgi-bin/admin.c4341
-rw-r--r--cgi-bin/api-cgi.header34
-rw-r--r--cgi-bin/api-cgi.shtml17
-rw-r--r--cgi-bin/cgi-private.h35
-rw-r--r--cgi-bin/cgi.h119
-rw-r--r--cgi-bin/classes.c558
-rw-r--r--cgi-bin/help-index.c1331
-rw-r--r--cgi-bin/help-index.h87
-rw-r--r--cgi-bin/help.c392
-rw-r--r--cgi-bin/html.c239
-rw-r--r--cgi-bin/ipp-var.c1592
-rw-r--r--cgi-bin/jobs.c214
-rw-r--r--cgi-bin/libcupscgi.exp42
-rw-r--r--cgi-bin/makedocset.c486
-rw-r--r--cgi-bin/multipart.datbin0 -> 50411 bytes
-rw-r--r--cgi-bin/printers.c578
-rw-r--r--cgi-bin/search.c381
-rw-r--r--cgi-bin/template.c733
-rw-r--r--cgi-bin/testcgi.c75
-rw-r--r--cgi-bin/testhi.c113
-rw-r--r--cgi-bin/testhi.html31
-rw-r--r--cgi-bin/testtemplate.c103
-rw-r--r--cgi-bin/var.c1305
-rw-r--r--cgi-bin/websearch.c116
-rw-r--r--conf/Makefile143
-rw-r--r--conf/cupsd.conf.in140
-rw-r--r--conf/mime.convs.in101
-rw-r--r--conf/mime.types174
-rw-r--r--conf/pam.opendirectory5
-rw-r--r--conf/pam.securityserver7
-rw-r--r--conf/pam.std.in2
-rw-r--r--conf/snmp.conf.in13
-rw-r--r--config-scripts/cups-3264.m4140
-rw-r--r--config-scripts/cups-common.m4425
-rw-r--r--config-scripts/cups-compiler.m4552
-rw-r--r--config-scripts/cups-defaults.m4510
-rw-r--r--config-scripts/cups-directories.m4440
-rw-r--r--config-scripts/cups-dnssd.m464
-rw-r--r--config-scripts/cups-gssapi.m4135
-rw-r--r--config-scripts/cups-image.m4112
-rw-r--r--config-scripts/cups-largefile.m452
-rw-r--r--config-scripts/cups-launchd.m443
-rw-r--r--config-scripts/cups-ldap.m452
-rw-r--r--config-scripts/cups-libtool.m439
-rw-r--r--config-scripts/cups-manpages.m496
-rw-r--r--config-scripts/cups-network.m474
-rw-r--r--config-scripts/cups-opsys.m435
-rw-r--r--config-scripts/cups-pam.m4102
-rw-r--r--config-scripts/cups-pdf.m4113
-rw-r--r--config-scripts/cups-poll.m422
-rw-r--r--config-scripts/cups-scripting.m4100
-rw-r--r--config-scripts/cups-sharedlibs.m4270
-rw-r--r--config-scripts/cups-slp.m438
-rw-r--r--config-scripts/cups-ssl.m4173
-rw-r--r--config-scripts/cups-threads.m454
-rw-r--r--config.h.in741
-rw-r--r--configure.in98
-rwxr-xr-xcups-config.in160
-rw-r--r--cups/Dependencies735
-rw-r--r--cups/Makefile680
-rw-r--r--cups/adminutil.c2458
-rw-r--r--cups/adminutil.h78
-rw-r--r--cups/api-array.header34
-rw-r--r--cups/api-array.shtml196
-rw-r--r--cups/api-cups.header40
-rw-r--r--cups/api-cups.shtml443
-rw-r--r--cups/api-filedir.header36
-rw-r--r--cups/api-filedir.shtml31
-rw-r--r--cups/api-filter.header41
-rw-r--r--cups/api-filter.shtml765
-rw-r--r--cups/api-httpipp.header37
-rw-r--r--cups/api-httpipp.shtml323
-rw-r--r--cups/api-overview.header53
-rw-r--r--cups/api-overview.shtml94
-rw-r--r--cups/api-ppd.header36
-rw-r--r--cups/api-ppd.shtml217
-rw-r--r--cups/array-private.h51
-rw-r--r--cups/array.c1326
-rw-r--r--cups/array.h92
-rw-r--r--cups/attr.c335
-rw-r--r--cups/auth.c877
-rw-r--r--cups/backchannel.c199
-rw-r--r--cups/backend.c140
-rw-r--r--cups/backend.h78
-rw-r--r--cups/conflicts.c1214
-rw-r--r--cups/cups-private.h213
-rw-r--r--cups/cups.h345
-rw-r--r--cups/custom.c122
-rw-r--r--cups/debug-private.h108
-rw-r--r--cups/debug.c583
-rw-r--r--cups/dest.c2169
-rw-r--r--cups/dir.c472
-rw-r--r--cups/dir.h69
-rw-r--r--cups/emit.c1217
-rw-r--r--cups/encode.c636
-rw-r--r--cups/file-private.h137
-rw-r--r--cups/file.c2721
-rw-r--r--cups/file.h112
-rw-r--r--cups/getdevices.c283
-rw-r--r--cups/getifaddrs.c266
-rw-r--r--cups/getputfile.c502
-rw-r--r--cups/globals.c354
-rw-r--r--cups/http-addr.c700
-rw-r--r--cups/http-addrlist.c677
-rw-r--r--cups/http-private.h407
-rw-r--r--cups/http-support.c1900
-rw-r--r--cups/http.c4512
-rw-r--r--cups/http.h479
-rw-r--r--cups/ipp-private.h87
-rw-r--r--cups/ipp-support.c813
-rw-r--r--cups/ipp.c3206
-rw-r--r--cups/ipp.h518
-rw-r--r--cups/langprintf.c352
-rw-r--r--cups/language-private.h91
-rw-r--r--cups/language.c1509
-rw-r--r--cups/language.h115
-rw-r--r--cups/libcups2.def338
-rw-r--r--cups/libcups_s.exp83
-rw-r--r--cups/localize.c779
-rw-r--r--cups/mark.c1099
-rw-r--r--cups/md5-private.h79
-rw-r--r--cups/md5.c346
-rw-r--r--cups/md5passwd.c142
-rw-r--r--cups/notify.c202
-rw-r--r--cups/options.c711
-rw-r--r--cups/page.c396
-rw-r--r--cups/ppd-cache.c2374
-rw-r--r--cups/ppd-private.h188
-rw-r--r--cups/ppd.c3144
-rw-r--r--cups/ppd.h450
-rw-r--r--cups/pwg-media.c848
-rw-r--r--cups/pwg-private.h102
-rw-r--r--cups/raster.h405
-rw-r--r--cups/request.c1099
-rw-r--r--cups/sidechannel.c575
-rw-r--r--cups/sidechannel.h147
-rw-r--r--cups/snmp-private.h145
-rw-r--r--cups/snmp.c1737
-rw-r--r--cups/snprintf.c362
-rw-r--r--cups/sspi-private.h82
-rw-r--r--cups/sspi.c1485
-rw-r--r--cups/string-private.h203
-rw-r--r--cups/string.c759
-rw-r--r--cups/tempfile.c233
-rw-r--r--cups/test.ppd262
-rw-r--r--cups/test2.ppd252
-rw-r--r--cups/testadmin.c120
-rw-r--r--cups/testarray.c480
-rw-r--r--cups/testconflicts.c127
-rw-r--r--cups/testcups.c416
-rw-r--r--cups/testfile.c821
-rw-r--r--cups/testhttp.c594
-rw-r--r--cups/testi18n.c619
-rw-r--r--cups/testipp.c867
-rw-r--r--cups/testlang.c114
-rw-r--r--cups/testoptions.c116
-rw-r--r--cups/testppd.c1082
-rw-r--r--cups/testpwg.c497
-rw-r--r--cups/testsnmp.c304
-rw-r--r--cups/thread-private.h97
-rw-r--r--cups/thread.c317
-rw-r--r--cups/transcode.c717
-rw-r--r--cups/transcode.h81
-rw-r--r--cups/usersys.c802
-rw-r--r--cups/utf8demo.txt213
-rw-r--r--cups/util.c1800
-rw-r--r--cups/versioning.h85
-rw-r--r--data/Makefile166
-rw-r--r--data/classified6
-rw-r--r--data/confidential6
-rw-r--r--data/cups.irix3
-rw-r--r--data/cups.pam2
-rw-r--r--data/cups.suse2
-rw-r--r--data/epson.h27
-rw-r--r--data/escp.h34
-rw-r--r--data/font.defs55
-rw-r--r--data/hp.h24
-rw-r--r--data/label.h28
-rw-r--r--data/media.defs205
-rw-r--r--data/pcl.h38
-rw-r--r--data/psglyphs1051
-rw-r--r--data/raster.defs94
-rw-r--r--data/secret6
-rw-r--r--data/smiley.ps28
-rw-r--r--data/standard6
-rw-r--r--data/testprint.in7
-rw-r--r--data/topsecret6
-rw-r--r--data/unclassified6
-rw-r--r--data/utf-840
-rw-r--r--desktop/Makefile135
-rw-r--r--desktop/cups-128.pngbin0 -> 4888 bytes
-rw-r--r--desktop/cups-16.pngbin0 -> 503 bytes
-rw-r--r--desktop/cups-256.pngbin0 -> 10147 bytes
-rw-r--r--desktop/cups-32.pngbin0 -> 1042 bytes
-rw-r--r--desktop/cups-512.pngbin0 -> 21029 bytes
-rw-r--r--desktop/cups-64.pngbin0 -> 2234 bytes
-rw-r--r--desktop/cups.conf13
-rw-r--r--desktop/cups.desktop.in39
-rw-r--r--desktop/cups.icnsbin0 -> 107501 bytes
-rw-r--r--desktop/cups.svg533
-rw-r--r--doc/Makefile266
-rw-r--r--doc/cups-printable.css329
-rw-r--r--doc/cups.css462
-rw-r--r--doc/de/index.html.in107
-rw-r--r--doc/es/index.html.in107
-rw-r--r--doc/eu/index.html.in106
-rw-r--r--doc/help/accounting.html62
-rw-r--r--doc/help/api-array.html1062
-rw-r--r--doc/help/api-cgi.html1126
-rw-r--r--doc/help/api-cups.html2521
-rw-r--r--doc/help/api-driver.html1156
-rw-r--r--doc/help/api-filedir.html995
-rw-r--r--doc/help/api-filter.html1625
-rw-r--r--doc/help/api-httpipp.html4377
-rw-r--r--doc/help/api-mime.html833
-rw-r--r--doc/help/api-overview.html501
-rw-r--r--doc/help/api-ppd.html2189
-rw-r--r--doc/help/api-ppdc.html2197
-rw-r--r--doc/help/api-raster.html1416
-rw-r--r--doc/help/cgi.html86
-rw-r--r--doc/help/glossary.html219
-rw-r--r--doc/help/kerberos.html122
-rw-r--r--doc/help/license.html1076
-rw-r--r--doc/help/network.html684
-rw-r--r--doc/help/options.html778
-rw-r--r--doc/help/overview.html70
-rw-r--r--doc/help/policies.html601
-rw-r--r--doc/help/postscript-driver.html663
-rw-r--r--doc/help/ppd-compiler.html1279
-rw-r--r--doc/help/raster-driver.html579
-rw-r--r--doc/help/ref-access_log.html140
-rw-r--r--doc/help/ref-classes-conf.html566
-rw-r--r--doc/help/ref-client-conf.html56
-rw-r--r--doc/help/ref-cupsd-conf.html.in3198
-rw-r--r--doc/help/ref-error_log.html55
-rw-r--r--doc/help/ref-mailto-conf.html108
-rw-r--r--doc/help/ref-page_log.html77
-rw-r--r--doc/help/ref-ppdcfile.html2449
-rw-r--r--doc/help/ref-printers-conf.html720
-rw-r--r--doc/help/ref-snmp-conf.html146
-rw-r--r--doc/help/ref-subscriptions-conf.html354
-rw-r--r--doc/help/security.html172
-rw-r--r--doc/help/sharing.html184
-rw-r--r--doc/help/spec-banner.html156
-rw-r--r--doc/help/spec-browsing.html118
-rw-r--r--doc/help/spec-cmp.html1218
-rw-r--r--doc/help/spec-command.html218
-rw-r--r--doc/help/spec-design.html184
-rw-r--r--doc/help/spec-ipp.html2879
-rw-r--r--doc/help/spec-pdf.html24
-rw-r--r--doc/help/spec-postscript.html148
-rw-r--r--doc/help/spec-ppd.html2342
-rw-r--r--doc/help/spec-raster.html720
-rw-r--r--doc/help/spec-stp.html133
-rw-r--r--doc/help/standard.html.in181
-rw-r--r--doc/help/translation.html852
-rw-r--r--doc/help/whatsnew.html61
-rw-r--r--doc/id/index.html.in107
-rw-r--r--doc/images/color-wheel.pngbin0 -> 13148 bytes
-rw-r--r--doc/images/cups-block-diagram.pngbin0 -> 76386 bytes
-rw-r--r--doc/images/cups-block-diagram.svg841
-rw-r--r--doc/images/cups-command-chain.pngbin0 -> 14902 bytes
-rw-r--r--doc/images/cups-command-chain.svg439
-rw-r--r--doc/images/cups-icon.pngbin0 -> 4888 bytes
-rw-r--r--doc/images/cups-postscript-chain.pngbin0 -> 17498 bytes
-rw-r--r--doc/images/cups-postscript-chain.svg531
-rw-r--r--doc/images/cups-raster-chain.pngbin0 -> 16916 bytes
-rw-r--r--doc/images/cups-raster-chain.svg534
-rw-r--r--doc/images/cups.pngbin0 -> 4888 bytes
-rw-r--r--doc/images/cups.svg533
-rw-r--r--doc/images/generic.pngbin0 -> 16913 bytes
-rw-r--r--doc/images/left.gifbin0 -> 1492 bytes
-rw-r--r--doc/images/left.xcf.gzbin0 -> 1194 bytes
-rw-r--r--doc/images/raster-organization.pngbin0 -> 20974 bytes
-rw-r--r--doc/images/raster-organization.svg189
-rw-r--r--doc/images/raster.pngbin0 -> 37656 bytes
-rw-r--r--doc/images/raster.svg386
-rw-r--r--doc/images/right.gifbin0 -> 341 bytes
-rw-r--r--doc/images/sample-image.pngbin0 -> 3541 bytes
-rw-r--r--doc/images/sel.gifbin0 -> 362 bytes
-rw-r--r--doc/images/smiley.jpgbin0 -> 14120 bytes
-rw-r--r--doc/images/unsel.gifbin0 -> 127 bytes
-rw-r--r--doc/images/wait.gifbin0 -> 1810 bytes
-rw-r--r--doc/images/webinterface.pngbin0 -> 150003 bytes
-rw-r--r--doc/index.html.in107
-rw-r--r--doc/it/index.html.in107
-rw-r--r--doc/ja/index.html.in107
-rw-r--r--doc/pl/index.html.in107
-rw-r--r--doc/robots.txt31
-rw-r--r--doc/ru/index.html.in103
-rw-r--r--driver/Dependencies75
-rw-r--r--driver/Makefile382
-rw-r--r--driver/api-driver.header34
-rw-r--r--driver/api-driver.shtml18
-rw-r--r--driver/attr.c109
-rw-r--r--driver/check.c111
-rw-r--r--driver/cmyk.c1955
-rw-r--r--driver/commandtoescpx.c245
-rw-r--r--driver/commandtopclx.c172
-rw-r--r--driver/dither.c306
-rw-r--r--driver/driver.h249
-rw-r--r--driver/image.pgmbin0 -> 152380 bytes
-rw-r--r--driver/image.ppmbin0 -> 457020 bytes
-rw-r--r--driver/libcupsdriver.exp30
-rw-r--r--driver/lut.c202
-rw-r--r--driver/pack.c307
-rw-r--r--driver/pcl-common.c272
-rw-r--r--driver/pcl-common.h71
-rw-r--r--driver/rastertoescpx.c1931
-rw-r--r--driver/rastertopclx.c1956
-rw-r--r--driver/rgb.c558
-rw-r--r--driver/srgb.c79
-rw-r--r--driver/testcmyk.c437
-rw-r--r--driver/testdither.c191
-rw-r--r--driver/testdriver.c176
-rw-r--r--driver/testrgb.c348
-rw-r--r--examples/Makefile128
-rw-r--r--examples/color.drv44
-rw-r--r--examples/constraint.drv48
-rw-r--r--examples/custom.drv41
-rw-r--r--examples/grouping.drv36
-rw-r--r--examples/laserjet-basic.drv88
-rw-r--r--examples/laserjet-pjl.drv101
-rw-r--r--examples/minimum.drv26
-rw-r--r--examples/postscript.drv46
-rw-r--r--examples/r300-basic.drv75
-rw-r--r--examples/r300-colorman.drv85
-rw-r--r--examples/r300-remote.drv85
-rw-r--r--filter/Dependencies486
-rw-r--r--filter/Makefile527
-rw-r--r--filter/api-raster.header37
-rw-r--r--filter/api-raster.shtml160
-rw-r--r--filter/bannertops.c1094
-rw-r--r--filter/commandtops.c371
-rw-r--r--filter/common.c535
-rw-r--r--filter/common.h78
-rw-r--r--filter/error.c287
-rw-r--r--filter/gziptoany.c112
-rw-r--r--filter/image-bmp.c545
-rw-r--r--filter/image-colorspace.c1567
-rw-r--r--filter/image-gif.c698
-rw-r--r--filter/image-jpeg.c322
-rw-r--r--filter/image-photocd.c333
-rw-r--r--filter/image-pix.c240
-rw-r--r--filter/image-png.c315
-rw-r--r--filter/image-pnm.c320
-rw-r--r--filter/image-private.h220
-rw-r--r--filter/image-sgi.c295
-rw-r--r--filter/image-sgi.h86
-rw-r--r--filter/image-sgilib.c890
-rw-r--r--filter/image-sun.c407
-rw-r--r--filter/image-tiff.c1715
-rw-r--r--filter/image-zoom.c361
-rw-r--r--filter/image.c812
-rw-r--r--filter/image.h130
-rw-r--r--filter/imagetops.c1078
-rw-r--r--filter/imagetoraster.c4367
-rw-r--r--filter/interpret.c1688
-rw-r--r--filter/libcupsimage2.def14
-rw-r--r--filter/libcupsimage_s.exp16
-rw-r--r--filter/pdftops.c621
-rw-r--r--filter/postscript-driver.header32
-rw-r--r--filter/postscript-driver.shtml276
-rw-r--r--filter/ppd-compiler.header34
-rw-r--r--filter/ppd-compiler.shtml883
-rw-r--r--filter/pstext.c511
-rw-r--r--filter/pstext.h74
-rw-r--r--filter/pstops.c3489
-rw-r--r--filter/raster-driver.header32
-rw-r--r--filter/raster-driver.shtml194
-rw-r--r--filter/raster.c1376
-rw-r--r--filter/rasterbench.c355
-rw-r--r--filter/rastertoepson.c1160
-rw-r--r--filter/rastertohp.c889
-rw-r--r--filter/rastertolabel.c1315
-rw-r--r--filter/rastertopwg.c218
-rw-r--r--filter/spec-ppd.header32
-rw-r--r--filter/spec-ppd.shtml1900
-rw-r--r--filter/testimage.c99
-rw-r--r--filter/testraster.c1078
-rw-r--r--filter/textcommon.c1214
-rw-r--r--filter/textcommon.h114
-rw-r--r--filter/texttops.c1165
-rw-r--r--fonts/Makefile118
-rw-r--r--fonts/Monospace2744
-rw-r--r--fonts/Monospace-Bold2354
-rw-r--r--fonts/Monospace-BoldOblique2445
-rw-r--r--fonts/Monospace-Oblique2706
-rwxr-xr-xinstall-sh222
-rw-r--r--locale/Dependencies26
-rw-r--r--locale/Makefile219
-rw-r--r--locale/checkpo.c413
-rw-r--r--locale/cups.footer5
-rw-r--r--locale/cups.header27
-rw-r--r--locale/cups.pot6976
-rw-r--r--locale/cups.strings1547
-rw-r--r--locale/cups_da.po7113
-rw-r--r--locale/cups_de.po7155
-rw-r--r--locale/cups_es.po7215
-rw-r--r--locale/cups_eu.po7231
-rw-r--r--locale/cups_fi.po7130
-rw-r--r--locale/cups_fr.po7233
-rw-r--r--locale/cups_id.po6982
-rw-r--r--locale/cups_it.po7273
-rw-r--r--locale/cups_ja.po7205
-rw-r--r--locale/cups_ko.po7068
-rw-r--r--locale/cups_nl.po7175
-rw-r--r--locale/cups_no.po7082
-rw-r--r--locale/cups_pl.po7143
-rw-r--r--locale/cups_pt.po7151
-rw-r--r--locale/cups_pt_BR.po7156
-rw-r--r--locale/cups_ru.po7133
-rw-r--r--locale/cups_sv.po7098
-rw-r--r--locale/cups_zh.po7020
-rw-r--r--locale/cups_zh_TW.po7018
-rw-r--r--locale/locale.txt32
-rw-r--r--locale/po2strings.c281
-rw-r--r--locale/strings2po.c175
-rw-r--r--locale/translate.c439
-rw-r--r--man/Makefile236
-rw-r--r--man/backend.man196
-rw-r--r--man/cancel.man75
-rw-r--r--man/classes.conf.man110
-rw-r--r--man/client.conf.man.in55
-rw-r--r--man/cups-config.man117
-rw-r--r--man/cups-deviced.man.in44
-rw-r--r--man/cups-driverd.man.in122
-rw-r--r--man/cups-lpd.man.in124
-rw-r--r--man/cups-polld.man38
-rw-r--r--man/cups-snmp.conf.man73
-rw-r--r--man/cupsaccept.man79
-rw-r--r--man/cupsaddsmb.man.in214
-rw-r--r--man/cupsctl.man107
-rw-r--r--man/cupsd.conf.man.in762
-rw-r--r--man/cupsd.man.in72
-rw-r--r--man/cupsenable.man93
-rw-r--r--man/cupsfilter.man91
-rw-r--r--man/cupstestdsc.man50
-rw-r--r--man/cupstestppd.man165
-rw-r--r--man/filter.man256
-rw-r--r--man/ipptool.man130
-rw-r--r--man/ipptoolfile.man511
-rw-r--r--man/lp.man262
-rw-r--r--man/lpadmin.man228
-rw-r--r--man/lpc.man71
-rw-r--r--man/lpinfo.man115
-rw-r--r--man/lpmove.man66
-rw-r--r--man/lpoptions.man.in135
-rw-r--r--man/lppasswd.man68
-rw-r--r--man/lpq.man72
-rw-r--r--man/lpr.man122
-rw-r--r--man/lprm.man65
-rw-r--r--man/lpstat.man143
-rw-r--r--man/mailto.conf.man60
-rw-r--r--man/mantohtml.c720
-rw-r--r--man/mime.convs.man46
-rw-r--r--man/mime.types.man115
-rw-r--r--man/notifier.man157
-rw-r--r--man/ppdc.man80
-rw-r--r--man/ppdcfile.man171
-rw-r--r--man/ppdhtml.man46
-rw-r--r--man/ppdi.man46
-rw-r--r--man/ppdmerge.man47
-rw-r--r--man/ppdpo.man52
-rw-r--r--man/printers.conf.man124
-rw-r--r--man/subscriptions.conf.man89
-rw-r--r--monitor/Dependencies18
-rw-r--r--monitor/Makefile146
-rw-r--r--monitor/bcp.c292
-rw-r--r--monitor/tbcp.c285
-rw-r--r--notifier/Dependencies24
-rw-r--r--notifier/Makefile162
-rw-r--r--notifier/dbus.c552
-rw-r--r--notifier/mailto.c646
-rw-r--r--notifier/rss.c731
-rw-r--r--notifier/testnotify.c127
-rwxr-xr-xpackaging/InstallationCheck11
-rw-r--r--packaging/LICENSE.rtf434
-rw-r--r--packaging/WELCOME.rtf24
-rw-r--r--packaging/cups-desc.plist.in14
-rw-r--r--packaging/cups-info.plist.in26
-rw-r--r--packaging/cups.list.in800
-rw-r--r--packaging/cups.spec.in376
-rw-r--r--packaging/installer.gifbin0 -> 3392 bytes
-rw-r--r--packaging/installer.tifbin0 -> 5538 bytes
-rw-r--r--ppdc/Dependencies238
-rw-r--r--ppdc/Makefile404
-rw-r--r--ppdc/api-ppdc.header34
-rw-r--r--ppdc/api-ppdc.shtml18
-rw-r--r--ppdc/foo-fr.po11
-rw-r--r--ppdc/foo.drv547
-rw-r--r--ppdc/genstrings.cxx215
-rw-r--r--ppdc/ppdc-array.cxx168
-rw-r--r--ppdc/ppdc-attr.cxx66
-rw-r--r--ppdc/ppdc-catalog.cxx897
-rw-r--r--ppdc/ppdc-choice.cxx61
-rw-r--r--ppdc/ppdc-constraint.cxx64
-rw-r--r--ppdc/ppdc-driver.cxx1339
-rw-r--r--ppdc/ppdc-file.cxx109
-rw-r--r--ppdc/ppdc-filter.cxx60
-rw-r--r--ppdc/ppdc-font.cxx66
-rw-r--r--ppdc/ppdc-group.cxx103
-rw-r--r--ppdc/ppdc-import.cxx343
-rw-r--r--ppdc/ppdc-mediasize.cxx85
-rw-r--r--ppdc/ppdc-message.cxx58
-rw-r--r--ppdc/ppdc-option.cxx129
-rw-r--r--ppdc/ppdc-private.h40
-rw-r--r--ppdc/ppdc-profile.cxx65
-rw-r--r--ppdc/ppdc-shared.cxx88
-rw-r--r--ppdc/ppdc-source.cxx3900
-rw-r--r--ppdc/ppdc-string.cxx62
-rw-r--r--ppdc/ppdc-variable.cxx71
-rw-r--r--ppdc/ppdc.cxx469
-rw-r--r--ppdc/ppdc.h532
-rw-r--r--ppdc/ppdhtml.cxx186
-rw-r--r--ppdc/ppdi.cxx142
-rw-r--r--ppdc/ppdmerge.cxx379
-rw-r--r--ppdc/ppdpo.cxx268
-rw-r--r--ppdc/sample.drv1254
-rw-r--r--ppdc/testcatalog.cxx63
-rw-r--r--scheduler/Dependencies352
-rw-r--r--scheduler/Makefile579
-rw-r--r--scheduler/api-mime.header34
-rw-r--r--scheduler/api-mime.shtml17
-rw-r--r--scheduler/auth.c2586
-rw-r--r--scheduler/auth.h152
-rw-r--r--scheduler/banners.c224
-rw-r--r--scheduler/banners.h45
-rw-r--r--scheduler/cert.c442
-rw-r--r--scheduler/cert.h56
-rw-r--r--scheduler/classes.c868
-rw-r--r--scheduler/classes.h36
-rw-r--r--scheduler/client.c5188
-rw-r--r--scheduler/client.h137
-rw-r--r--scheduler/conf.c4202
-rw-r--r--scheduler/conf.h299
-rw-r--r--scheduler/cups-deviced.c810
-rw-r--r--scheduler/cups-driverd.cxx2569
-rw-r--r--scheduler/cups-exec.c106
-rw-r--r--scheduler/cups-lpd.c1627
-rw-r--r--scheduler/cups-lpd.xinetd.in12
-rw-r--r--scheduler/cups-polld.c469
-rw-r--r--scheduler/cups.sh.in233
-rw-r--r--scheduler/cups.xml.in214
-rw-r--r--scheduler/cupsd.h248
-rw-r--r--scheduler/cupsfilter.c1497
-rw-r--r--scheduler/dirsvc.c5579
-rw-r--r--scheduler/dirsvc.h213
-rw-r--r--scheduler/env.c271
-rw-r--r--scheduler/file.c450
-rw-r--r--scheduler/filter.c504
-rw-r--r--scheduler/ipp.c12256
-rw-r--r--scheduler/job.c4731
-rw-r--r--scheduler/job.h164
-rw-r--r--scheduler/libcupsmime.exp21
-rw-r--r--scheduler/listen.c431
-rw-r--r--scheduler/log.c1077
-rw-r--r--scheduler/main.c2075
-rw-r--r--scheduler/mime-private.h48
-rw-r--r--scheduler/mime.c960
-rw-r--r--scheduler/mime.h162
-rw-r--r--scheduler/network.c300
-rw-r--r--scheduler/network.h52
-rw-r--r--scheduler/org.cups.cups-lpd.plist.in33
-rw-r--r--scheduler/org.cups.cupsd.plist62
-rw-r--r--scheduler/policy.c517
-rw-r--r--scheduler/policy.h63
-rw-r--r--scheduler/printers.c5427
-rw-r--r--scheduler/printers.h177
-rw-r--r--scheduler/process.c656
-rw-r--r--scheduler/quotas.c244
-rw-r--r--scheduler/select.c951
-rw-r--r--scheduler/server.c184
-rw-r--r--scheduler/statbuf.c330
-rw-r--r--scheduler/statbuf.h49
-rw-r--r--scheduler/subscriptions.c1638
-rw-r--r--scheduler/subscriptions.h166
-rw-r--r--scheduler/sysman.c1020
-rw-r--r--scheduler/sysman.h64
-rw-r--r--scheduler/testdirsvc.c324
-rw-r--r--scheduler/testlpd.c550
-rw-r--r--scheduler/testmime.c531
-rw-r--r--scheduler/testspeed.c365
-rw-r--r--scheduler/testsub.c522
-rw-r--r--scheduler/type.c1216
-rw-r--r--scheduler/util.c471
-rw-r--r--scheduler/util.h71
-rw-r--r--scripting/perl/CUPS.pm144
-rw-r--r--scripting/perl/CUPS.xs270
-rw-r--r--scripting/perl/Makefile.PL17
-rw-r--r--scripting/perl/README35
-rw-r--r--scripting/perl/test.pl17
-rw-r--r--scripting/php/Dependencies7
-rw-r--r--scripting/php/Makefile153
-rw-r--r--scripting/php/README157
-rw-r--r--scripting/php/phpcups.c487
-rw-r--r--scripting/php/phpcups.h67
-rwxr-xr-xscripting/php/phpcups.php60
-rw-r--r--standards/Makefile163
-rw-r--r--standards/X.690-0207.pdfbin0 -> 524444 bytes
-rw-r--r--standards/cs-ipp20-20090731-5100.10.pdfbin0 -> 91763 bytes
-rw-r--r--standards/cs-ippstate10-20090731-5100.9.pdfbin0 -> 194529 bytes
-rw-r--r--standards/papi-1.0.pdfbin0 -> 503784 bytes
-rw-r--r--standards/pwg5100.1.pdfbin0 -> 37359 bytes
-rw-r--r--standards/pwg5100.2.pdfbin0 -> 37360 bytes
-rw-r--r--standards/pwg5100.3.pdfbin0 -> 262279 bytes
-rw-r--r--standards/pwg5100.5.pdfbin0 -> 2288291 bytes
-rw-r--r--standards/pwg5100.6.pdfbin0 -> 500649 bytes
-rw-r--r--standards/pwg5100.7.pdfbin0 -> 1090862 bytes
-rw-r--r--standards/pwg5100.8.pdfbin0 -> 395397 bytes
-rw-r--r--standards/pwg5101.1.pdfbin0 -> 924222 bytes
-rw-r--r--standards/pwg5105.1.pdfbin0 -> 2021826 bytes
-rw-r--r--standards/pwg5107.1.pdfbin0 -> 150688 bytes
-rw-r--r--standards/rfc1155.txt1235
-rw-r--r--standards/rfc1157.txt2019
-rw-r--r--standards/rfc1179.txt787
-rw-r--r--standards/rfc1213.txt3923
-rw-r--r--standards/rfc1321.txt1179
-rw-r--r--standards/rfc2046.txt2467
-rw-r--r--standards/rfc2222.txt899
-rw-r--r--standards/rfc2246.txt4483
-rw-r--r--standards/rfc2487.txt451
-rw-r--r--standards/rfc2554.txt619
-rw-r--r--standards/rfc2567.txt2411
-rw-r--r--standards/rfc2568.txt563
-rw-r--r--standards/rfc2569.txt1571
-rw-r--r--standards/rfc2578.txt2541
-rw-r--r--standards/rfc2579.txt1533
-rw-r--r--standards/rfc2595.txt843
-rw-r--r--standards/rfc2616.txt9859
-rw-r--r--standards/rfc2617.txt1907
-rw-r--r--standards/rfc2712.txt395
-rw-r--r--standards/rfc2790.txt2803
-rw-r--r--standards/rfc2817.txt731
-rw-r--r--standards/rfc2818.txt395
-rw-r--r--standards/rfc2821.txt4427
-rw-r--r--standards/rfc2822.txt2859
-rw-r--r--standards/rfc2910.txt2579
-rw-r--r--standards/rfc2911.txt12547
-rw-r--r--standards/rfc2965.txt1459
-rw-r--r--standards/rfc3196.txt5379
-rw-r--r--standards/rfc3239.txt843
-rw-r--r--standards/rfc3282.txt451
-rw-r--r--standards/rfc3380.txt3307
-rw-r--r--standards/rfc3381.txt955
-rw-r--r--standards/rfc3382.txt2131
-rw-r--r--standards/rfc3391.txt1403
-rw-r--r--standards/rfc3510.txt899
-rw-r--r--standards/rfc3712.txt1851
-rw-r--r--standards/rfc3805.txt9579
-rw-r--r--standards/rfc3808.txt787
-rw-r--r--standards/rfc3875.txt2019
-rw-r--r--standards/rfc3986.txt3419
-rw-r--r--standards/rfc3995.txt5323
-rw-r--r--standards/rfc3996.txt1739
-rw-r--r--standards/rfc3997.txt955
-rw-r--r--standards/rfc3998.txt2579
-rw-r--r--standards/rfc4122.txt1795
-rw-r--r--standards/rfc4234.txt899
-rw-r--r--standards/rfc4646.txt3307
-rw-r--r--standards/rfctohtml.c504
-rw-r--r--standards/wake-on-lan.pdfbin0 -> 37276 bytes
-rw-r--r--standards/wd-ippmailto10-20050519.pdfbin0 -> 75741 bytes
-rw-r--r--systemv/Dependencies108
-rw-r--r--systemv/Makefile293
-rw-r--r--systemv/cancel.c376
-rw-r--r--systemv/cupsaccept.c239
-rw-r--r--systemv/cupsaddsmb.c303
-rw-r--r--systemv/cupsctl.c235
-rw-r--r--systemv/cupstestdsc.c442
-rw-r--r--systemv/cupstestppd.c3795
-rw-r--r--systemv/lp.c723
-rw-r--r--systemv/lpadmin.c1521
-rw-r--r--systemv/lpinfo.c498
-rw-r--r--systemv/lpmove.c213
-rw-r--r--systemv/lpoptions.c565
-rw-r--r--systemv/lppasswd.c489
-rw-r--r--systemv/lpstat.c2051
-rw-r--r--templates/Makefile204
-rw-r--r--templates/add-class.tmpl40
-rw-r--r--templates/add-printer.tmpl47
-rw-r--r--templates/add-rss-subscription.tmpl44
-rw-r--r--templates/admin.tmpl110
-rw-r--r--templates/choose-device.tmpl53
-rw-r--r--templates/choose-make.tmpl64
-rw-r--r--templates/choose-model.tmpl60
-rw-r--r--templates/choose-serial.tmpl52
-rw-r--r--templates/choose-uri.tmpl44
-rw-r--r--templates/class-added.tmpl8
-rw-r--r--templates/class-confirm.tmpl10
-rw-r--r--templates/class-deleted.tmpl7
-rw-r--r--templates/class-jobs-header.tmpl3
-rw-r--r--templates/class-modified.tmpl8
-rw-r--r--templates/class.tmpl44
-rw-r--r--templates/classes-header.tmpl1
-rw-r--r--templates/classes.tmpl11
-rw-r--r--templates/command.tmpl12
-rw-r--r--templates/de/add-class.tmpl40
-rw-r--r--templates/de/add-printer.tmpl47
-rw-r--r--templates/de/add-rss-subscription.tmpl44
-rw-r--r--templates/de/admin.tmpl110
-rw-r--r--templates/de/choose-device.tmpl54
-rw-r--r--templates/de/choose-make.tmpl64
-rw-r--r--templates/de/choose-model.tmpl60
-rw-r--r--templates/de/choose-serial.tmpl52
-rw-r--r--templates/de/choose-uri.tmpl44
-rw-r--r--templates/de/class-added.tmpl8
-rw-r--r--templates/de/class-confirm.tmpl10
-rw-r--r--templates/de/class-deleted.tmpl7
-rw-r--r--templates/de/class-jobs-header.tmpl3
-rw-r--r--templates/de/class-modified.tmpl8
-rw-r--r--templates/de/class.tmpl44
-rw-r--r--templates/de/classes-header.tmpl1
-rw-r--r--templates/de/classes.tmpl11
-rw-r--r--templates/de/command.tmpl12
-rw-r--r--templates/de/edit-config.tmpl24
-rw-r--r--templates/de/error-op.tmpl9
-rw-r--r--templates/de/error.tmpl9
-rw-r--r--templates/de/header.tmpl.in29
-rw-r--r--templates/de/help-header.tmpl51
-rw-r--r--templates/de/help-printable.tmpl9
-rw-r--r--templates/de/help-trailer.tmpl1
-rw-r--r--templates/de/job-cancel.tmpl7
-rw-r--r--templates/de/job-hold.tmpl7
-rw-r--r--templates/de/job-move.tmpl27
-rw-r--r--templates/de/job-moved.tmpl8
-rw-r--r--templates/de/job-release.tmpl7
-rw-r--r--templates/de/job-restart.tmpl7
-rw-r--r--templates/de/jobs-header.tmpl5
-rw-r--r--templates/de/jobs.tmpl37
-rw-r--r--templates/de/list-available-printers.tmpl11
-rw-r--r--templates/de/modify-class.tmpl34
-rw-r--r--templates/de/modify-printer.tmpl42
-rw-r--r--templates/de/norestart.tmpl8
-rw-r--r--templates/de/option-boolean.tmpl6
-rw-r--r--templates/de/option-conflict.tmpl7
-rw-r--r--templates/de/option-header.tmpl5
-rw-r--r--templates/de/option-pickmany.tmpl6
-rw-r--r--templates/de/option-pickone.tmpl18
-rw-r--r--templates/de/option-trailer.tmpl5
-rw-r--r--templates/de/pager.tmpl6
-rw-r--r--templates/de/printer-accept.tmpl9
-rw-r--r--templates/de/printer-added.tmpl8
-rw-r--r--templates/de/printer-configured.tmpl8
-rw-r--r--templates/de/printer-confirm.tmpl10
-rw-r--r--templates/de/printer-default.tmpl13
-rw-r--r--templates/de/printer-deleted.tmpl7
-rw-r--r--templates/de/printer-jobs-header.tmpl3
-rw-r--r--templates/de/printer-modified.tmpl8
-rw-r--r--templates/de/printer-purge.tmpl9
-rw-r--r--templates/de/printer-reject.tmpl9
-rw-r--r--templates/de/printer-start.tmpl9
-rw-r--r--templates/de/printer-stop.tmpl9
-rw-r--r--templates/de/printer.tmpl47
-rw-r--r--templates/de/printers-header.tmpl1
-rw-r--r--templates/de/printers.tmpl11
-rw-r--r--templates/de/restart.tmpl8
-rw-r--r--templates/de/samba-export.tmpl55
-rw-r--r--templates/de/samba-exported.tmpl1
-rw-r--r--templates/de/search.tmpl10
-rw-r--r--templates/de/set-printer-options-header.tmpl26
-rw-r--r--templates/de/set-printer-options-trailer.tmpl16
-rw-r--r--templates/de/subscription-added.tmpl5
-rw-r--r--templates/de/subscription-canceled.tmpl5
-rw-r--r--templates/de/test-page.tmpl8
-rw-r--r--templates/de/trailer.tmpl8
-rw-r--r--templates/de/users.tmpl30
-rw-r--r--templates/edit-config.tmpl24
-rw-r--r--templates/error-op.tmpl9
-rw-r--r--templates/error.tmpl9
-rw-r--r--templates/es/add-class.tmpl40
-rw-r--r--templates/es/add-printer.tmpl47
-rw-r--r--templates/es/add-rss-subscription.tmpl44
-rw-r--r--templates/es/admin.tmpl110
-rw-r--r--templates/es/choose-device.tmpl54
-rw-r--r--templates/es/choose-make.tmpl64
-rw-r--r--templates/es/choose-model.tmpl60
-rw-r--r--templates/es/choose-serial.tmpl52
-rw-r--r--templates/es/choose-uri.tmpl44
-rw-r--r--templates/es/class-added.tmpl7
-rw-r--r--templates/es/class-confirm.tmpl10
-rw-r--r--templates/es/class-deleted.tmpl7
-rw-r--r--templates/es/class-jobs-header.tmpl3
-rw-r--r--templates/es/class-modified.tmpl6
-rw-r--r--templates/es/class.tmpl44
-rw-r--r--templates/es/classes-header.tmpl1
-rw-r--r--templates/es/classes.tmpl11
-rw-r--r--templates/es/command.tmpl12
-rw-r--r--templates/es/edit-config.tmpl24
-rw-r--r--templates/es/error-op.tmpl9
-rw-r--r--templates/es/error.tmpl9
-rw-r--r--templates/es/header.tmpl.in29
-rw-r--r--templates/es/help-header.tmpl51
-rw-r--r--templates/es/help-printable.tmpl9
-rw-r--r--templates/es/help-trailer.tmpl1
-rw-r--r--templates/es/job-cancel.tmpl7
-rw-r--r--templates/es/job-hold.tmpl7
-rw-r--r--templates/es/job-move.tmpl27
-rw-r--r--templates/es/job-moved.tmpl8
-rw-r--r--templates/es/job-release.tmpl7
-rw-r--r--templates/es/job-restart.tmpl7
-rw-r--r--templates/es/jobs-header.tmpl5
-rw-r--r--templates/es/jobs.tmpl37
-rw-r--r--templates/es/list-available-printers.tmpl11
-rw-r--r--templates/es/modify-class.tmpl34
-rw-r--r--templates/es/modify-printer.tmpl42
-rw-r--r--templates/es/norestart.tmpl8
-rw-r--r--templates/es/option-boolean.tmpl6
-rw-r--r--templates/es/option-conflict.tmpl7
-rw-r--r--templates/es/option-header.tmpl5
-rw-r--r--templates/es/option-pickmany.tmpl6
-rw-r--r--templates/es/option-pickone.tmpl18
-rw-r--r--templates/es/option-trailer.tmpl5
-rw-r--r--templates/es/pager.tmpl6
-rw-r--r--templates/es/printer-accept.tmpl9
-rw-r--r--templates/es/printer-added.tmpl7
-rw-r--r--templates/es/printer-configured.tmpl8
-rw-r--r--templates/es/printer-confirm.tmpl10
-rw-r--r--templates/es/printer-default.tmpl13
-rw-r--r--templates/es/printer-deleted.tmpl7
-rw-r--r--templates/es/printer-jobs-header.tmpl3
-rw-r--r--templates/es/printer-modified.tmpl7
-rw-r--r--templates/es/printer-purge.tmpl8
-rw-r--r--templates/es/printer-reject.tmpl9
-rw-r--r--templates/es/printer-start.tmpl9
-rw-r--r--templates/es/printer-stop.tmpl9
-rw-r--r--templates/es/printer.tmpl47
-rw-r--r--templates/es/printers-header.tmpl1
-rw-r--r--templates/es/printers.tmpl11
-rw-r--r--templates/es/restart.tmpl8
-rw-r--r--templates/es/samba-export.tmpl55
-rw-r--r--templates/es/samba-exported.tmpl1
-rw-r--r--templates/es/search.tmpl10
-rw-r--r--templates/es/set-printer-options-header.tmpl26
-rw-r--r--templates/es/set-printer-options-trailer.tmpl16
-rw-r--r--templates/es/subscription-added.tmpl5
-rw-r--r--templates/es/subscription-canceled.tmpl5
-rw-r--r--templates/es/test-page.tmpl8
-rw-r--r--templates/es/trailer.tmpl8
-rw-r--r--templates/es/users.tmpl30
-rw-r--r--templates/eu/add-class.tmpl40
-rw-r--r--templates/eu/add-printer.tmpl47
-rw-r--r--templates/eu/add-rss-subscription.tmpl44
-rw-r--r--templates/eu/admin.tmpl110
-rw-r--r--templates/eu/choose-device.tmpl54
-rw-r--r--templates/eu/choose-make.tmpl64
-rw-r--r--templates/eu/choose-model.tmpl60
-rw-r--r--templates/eu/choose-serial.tmpl52
-rw-r--r--templates/eu/choose-uri.tmpl43
-rw-r--r--templates/eu/class-added.tmpl7
-rw-r--r--templates/eu/class-confirm.tmpl9
-rw-r--r--templates/eu/class-deleted.tmpl7
-rw-r--r--templates/eu/class-jobs-header.tmpl3
-rw-r--r--templates/eu/class-modified.tmpl7
-rw-r--r--templates/eu/class.tmpl44
-rw-r--r--templates/eu/classes-header.tmpl1
-rw-r--r--templates/eu/classes.tmpl11
-rw-r--r--templates/eu/command.tmpl12
-rw-r--r--templates/eu/edit-config.tmpl24
-rw-r--r--templates/eu/error-op.tmpl9
-rw-r--r--templates/eu/error.tmpl9
-rw-r--r--templates/eu/header.tmpl.in29
-rw-r--r--templates/eu/help-header.tmpl49
-rw-r--r--templates/eu/help-printable.tmpl9
-rw-r--r--templates/eu/help-trailer.tmpl1
-rw-r--r--templates/eu/job-cancel.tmpl7
-rw-r--r--templates/eu/job-hold.tmpl7
-rw-r--r--templates/eu/job-move.tmpl27
-rw-r--r--templates/eu/job-moved.tmpl8
-rw-r--r--templates/eu/job-release.tmpl7
-rw-r--r--templates/eu/job-restart.tmpl7
-rw-r--r--templates/eu/jobs-header.tmpl5
-rw-r--r--templates/eu/jobs.tmpl37
-rw-r--r--templates/eu/list-available-printers.tmpl11
-rw-r--r--templates/eu/modify-class.tmpl34
-rw-r--r--templates/eu/modify-printer.tmpl42
-rw-r--r--templates/eu/norestart.tmpl7
-rw-r--r--templates/eu/option-boolean.tmpl6
-rw-r--r--templates/eu/option-conflict.tmpl7
-rw-r--r--templates/eu/option-header.tmpl5
-rw-r--r--templates/eu/option-pickmany.tmpl6
-rw-r--r--templates/eu/option-pickone.tmpl18
-rw-r--r--templates/eu/option-trailer.tmpl5
-rw-r--r--templates/eu/pager.tmpl6
-rw-r--r--templates/eu/printer-accept.tmpl8
-rw-r--r--templates/eu/printer-added.tmpl7
-rw-r--r--templates/eu/printer-configured.tmpl8
-rw-r--r--templates/eu/printer-confirm.tmpl9
-rw-r--r--templates/eu/printer-default.tmpl11
-rw-r--r--templates/eu/printer-deleted.tmpl7
-rw-r--r--templates/eu/printer-jobs-header.tmpl3
-rw-r--r--templates/eu/printer-modified.tmpl8
-rw-r--r--templates/eu/printer-purge.tmpl8
-rw-r--r--templates/eu/printer-reject.tmpl8
-rw-r--r--templates/eu/printer-start.tmpl8
-rw-r--r--templates/eu/printer-stop.tmpl8
-rw-r--r--templates/eu/printer.tmpl47
-rw-r--r--templates/eu/printers-header.tmpl1
-rw-r--r--templates/eu/printers.tmpl11
-rw-r--r--templates/eu/restart.tmpl8
-rw-r--r--templates/eu/samba-export.tmpl54
-rw-r--r--templates/eu/samba-exported.tmpl1
-rw-r--r--templates/eu/search.tmpl10
-rw-r--r--templates/eu/set-printer-options-header.tmpl26
-rw-r--r--templates/eu/set-printer-options-trailer.tmpl16
-rw-r--r--templates/eu/subscription-added.tmpl5
-rw-r--r--templates/eu/subscription-canceled.tmpl5
-rw-r--r--templates/eu/test-page.tmpl7
-rw-r--r--templates/eu/trailer.tmpl8
-rw-r--r--templates/eu/users.tmpl30
-rw-r--r--templates/header.tmpl.in29
-rw-r--r--templates/help-header.tmpl51
-rw-r--r--templates/help-printable.tmpl9
-rw-r--r--templates/help-trailer.tmpl1
-rw-r--r--templates/id/add-class.tmpl40
-rw-r--r--templates/id/add-printer.tmpl43
-rw-r--r--templates/id/add-rss-subscription.tmpl44
-rw-r--r--templates/id/admin.tmpl110
-rw-r--r--templates/id/choose-device.tmpl54
-rw-r--r--templates/id/choose-make.tmpl64
-rw-r--r--templates/id/choose-model.tmpl60
-rw-r--r--templates/id/choose-serial.tmpl52
-rw-r--r--templates/id/choose-uri.tmpl43
-rw-r--r--templates/id/class-added.tmpl7
-rw-r--r--templates/id/class-confirm.tmpl10
-rw-r--r--templates/id/class-deleted.tmpl7
-rw-r--r--templates/id/class-jobs-header.tmpl3
-rw-r--r--templates/id/class-modified.tmpl7
-rw-r--r--templates/id/class.tmpl44
-rw-r--r--templates/id/classes-header.tmpl1
-rw-r--r--templates/id/classes.tmpl11
-rw-r--r--templates/id/command.tmpl12
-rw-r--r--templates/id/edit-config.tmpl24
-rw-r--r--templates/id/error-op.tmpl9
-rw-r--r--templates/id/error.tmpl9
-rw-r--r--templates/id/header.tmpl.in29
-rw-r--r--templates/id/help-header.tmpl47
-rw-r--r--templates/id/help-printable.tmpl9
-rw-r--r--templates/id/help-trailer.tmpl1
-rw-r--r--templates/id/job-cancel.tmpl7
-rw-r--r--templates/id/job-hold.tmpl7
-rw-r--r--templates/id/job-move.tmpl27
-rw-r--r--templates/id/job-moved.tmpl8
-rw-r--r--templates/id/job-release.tmpl7
-rw-r--r--templates/id/job-restart.tmpl7
-rw-r--r--templates/id/jobs-header.tmpl5
-rw-r--r--templates/id/jobs.tmpl36
-rw-r--r--templates/id/list-available-printers.tmpl11
-rw-r--r--templates/id/modify-class.tmpl34
-rw-r--r--templates/id/modify-printer.tmpl38
-rw-r--r--templates/id/norestart.tmpl7
-rw-r--r--templates/id/option-boolean.tmpl6
-rw-r--r--templates/id/option-conflict.tmpl7
-rw-r--r--templates/id/option-header.tmpl5
-rw-r--r--templates/id/option-pickmany.tmpl6
-rw-r--r--templates/id/option-pickone.tmpl18
-rw-r--r--templates/id/option-trailer.tmpl5
-rw-r--r--templates/id/pager.tmpl6
-rw-r--r--templates/id/printer-accept.tmpl9
-rw-r--r--templates/id/printer-added.tmpl7
-rw-r--r--templates/id/printer-configured.tmpl8
-rw-r--r--templates/id/printer-confirm.tmpl10
-rw-r--r--templates/id/printer-default.tmpl11
-rw-r--r--templates/id/printer-deleted.tmpl7
-rw-r--r--templates/id/printer-jobs-header.tmpl3
-rw-r--r--templates/id/printer-modified.tmpl7
-rw-r--r--templates/id/printer-purge.tmpl9
-rw-r--r--templates/id/printer-reject.tmpl9
-rw-r--r--templates/id/printer-start.tmpl9
-rw-r--r--templates/id/printer-stop.tmpl9
-rw-r--r--templates/id/printer.tmpl47
-rw-r--r--templates/id/printers-header.tmpl1
-rw-r--r--templates/id/printers.tmpl11
-rw-r--r--templates/id/restart.tmpl8
-rw-r--r--templates/id/samba-export.tmpl55
-rw-r--r--templates/id/samba-exported.tmpl1
-rw-r--r--templates/id/search.tmpl10
-rw-r--r--templates/id/set-printer-options-header.tmpl26
-rw-r--r--templates/id/set-printer-options-trailer.tmpl16
-rw-r--r--templates/id/subscription-added.tmpl5
-rw-r--r--templates/id/subscription-canceled.tmpl5
-rw-r--r--templates/id/test-page.tmpl8
-rw-r--r--templates/id/trailer.tmpl8
-rw-r--r--templates/id/users.tmpl30
-rw-r--r--templates/it/add-class.tmpl40
-rw-r--r--templates/it/add-printer.tmpl43
-rw-r--r--templates/it/add-rss-subscription.tmpl44
-rw-r--r--templates/it/admin.tmpl110
-rw-r--r--templates/it/choose-device.tmpl54
-rw-r--r--templates/it/choose-make.tmpl64
-rw-r--r--templates/it/choose-model.tmpl60
-rw-r--r--templates/it/choose-serial.tmpl52
-rw-r--r--templates/it/choose-uri.tmpl44
-rw-r--r--templates/it/class-added.tmpl8
-rw-r--r--templates/it/class-confirm.tmpl10
-rw-r--r--templates/it/class-deleted.tmpl7
-rw-r--r--templates/it/class-jobs-header.tmpl3
-rw-r--r--templates/it/class-modified.tmpl8
-rw-r--r--templates/it/class.tmpl44
-rw-r--r--templates/it/classes-header.tmpl1
-rw-r--r--templates/it/classes.tmpl11
-rw-r--r--templates/it/command.tmpl12
-rw-r--r--templates/it/edit-config.tmpl24
-rw-r--r--templates/it/error-op.tmpl9
-rw-r--r--templates/it/error.tmpl9
-rw-r--r--templates/it/help-header.tmpl50
-rw-r--r--templates/it/help-printable.tmpl9
-rw-r--r--templates/it/help-trailer.tmpl1
-rw-r--r--templates/it/job-cancel.tmpl7
-rw-r--r--templates/it/job-hold.tmpl7
-rw-r--r--templates/it/job-move.tmpl27
-rw-r--r--templates/it/job-moved.tmpl8
-rw-r--r--templates/it/job-release.tmpl7
-rw-r--r--templates/it/job-restart.tmpl7
-rw-r--r--templates/it/jobs-header.tmpl5
-rw-r--r--templates/it/jobs.tmpl37
-rw-r--r--templates/it/list-available-printers.tmpl11
-rw-r--r--templates/it/modify-class.tmpl34
-rw-r--r--templates/it/modify-printer.tmpl38
-rw-r--r--templates/it/norestart.tmpl7
-rw-r--r--templates/it/option-boolean.tmpl6
-rw-r--r--templates/it/option-conflict.tmpl7
-rw-r--r--templates/it/option-header.tmpl5
-rw-r--r--templates/it/option-pickmany.tmpl6
-rw-r--r--templates/it/option-pickone.tmpl18
-rw-r--r--templates/it/option-trailer.tmpl5
-rw-r--r--templates/it/pager.tmpl6
-rw-r--r--templates/it/printer-accept.tmpl9
-rw-r--r--templates/it/printer-added.tmpl7
-rw-r--r--templates/it/printer-configured.tmpl8
-rw-r--r--templates/it/printer-confirm.tmpl10
-rw-r--r--templates/it/printer-default.tmpl12
-rw-r--r--templates/it/printer-deleted.tmpl7
-rw-r--r--templates/it/printer-jobs-header.tmpl3
-rw-r--r--templates/it/printer-modified.tmpl8
-rw-r--r--templates/it/printer-purge.tmpl9
-rw-r--r--templates/it/printer-reject.tmpl9
-rw-r--r--templates/it/printer-start.tmpl9
-rw-r--r--templates/it/printer-stop.tmpl9
-rw-r--r--templates/it/printer.tmpl47
-rw-r--r--templates/it/printers-header.tmpl1
-rw-r--r--templates/it/printers.tmpl11
-rw-r--r--templates/it/restart.tmpl8
-rw-r--r--templates/it/samba-export.tmpl54
-rw-r--r--templates/it/samba-exported.tmpl1
-rw-r--r--templates/it/search.tmpl10
-rw-r--r--templates/it/set-printer-options-header.tmpl26
-rw-r--r--templates/it/set-printer-options-trailer.tmpl16
-rw-r--r--templates/it/subscription-added.tmpl5
-rw-r--r--templates/it/subscription-canceled.tmpl5
-rw-r--r--templates/it/test-page.tmpl8
-rw-r--r--templates/it/trailer.tmpl8
-rw-r--r--templates/it/users.tmpl30
-rw-r--r--templates/ja/add-class.tmpl40
-rw-r--r--templates/ja/add-printer.tmpl47
-rw-r--r--templates/ja/add-rss-subscription.tmpl44
-rw-r--r--templates/ja/admin.tmpl110
-rw-r--r--templates/ja/choose-device.tmpl54
-rw-r--r--templates/ja/choose-make.tmpl64
-rw-r--r--templates/ja/choose-model.tmpl60
-rw-r--r--templates/ja/choose-serial.tmpl52
-rw-r--r--templates/ja/choose-uri.tmpl43
-rw-r--r--templates/ja/class-added.tmpl7
-rw-r--r--templates/ja/class-confirm.tmpl10
-rw-r--r--templates/ja/class-deleted.tmpl7
-rw-r--r--templates/ja/class-jobs-header.tmpl3
-rw-r--r--templates/ja/class-modified.tmpl7
-rw-r--r--templates/ja/class.tmpl44
-rw-r--r--templates/ja/classes-header.tmpl1
-rw-r--r--templates/ja/classes.tmpl11
-rw-r--r--templates/ja/command.tmpl12
-rw-r--r--templates/ja/edit-config.tmpl24
-rw-r--r--templates/ja/error-op.tmpl9
-rw-r--r--templates/ja/error.tmpl9
-rw-r--r--templates/ja/header.tmpl.in29
-rw-r--r--templates/ja/help-header.tmpl51
-rw-r--r--templates/ja/help-printable.tmpl9
-rw-r--r--templates/ja/help-trailer.tmpl1
-rw-r--r--templates/ja/job-cancel.tmpl7
-rw-r--r--templates/ja/job-hold.tmpl6
-rw-r--r--templates/ja/job-move.tmpl27
-rw-r--r--templates/ja/job-moved.tmpl8
-rw-r--r--templates/ja/job-release.tmpl7
-rw-r--r--templates/ja/job-restart.tmpl7
-rw-r--r--templates/ja/jobs-header.tmpl5
-rw-r--r--templates/ja/jobs.tmpl37
-rw-r--r--templates/ja/list-available-printers.tmpl11
-rw-r--r--templates/ja/modify-class.tmpl34
-rw-r--r--templates/ja/modify-printer.tmpl42
-rw-r--r--templates/ja/norestart.tmpl7
-rw-r--r--templates/ja/option-boolean.tmpl6
-rw-r--r--templates/ja/option-conflict.tmpl7
-rw-r--r--templates/ja/option-header.tmpl5
-rw-r--r--templates/ja/option-pickmany.tmpl6
-rw-r--r--templates/ja/option-pickone.tmpl18
-rw-r--r--templates/ja/option-trailer.tmpl5
-rw-r--r--templates/ja/pager.tmpl6
-rw-r--r--templates/ja/printer-accept.tmpl9
-rw-r--r--templates/ja/printer-added.tmpl6
-rw-r--r--templates/ja/printer-configured.tmpl7
-rw-r--r--templates/ja/printer-confirm.tmpl9
-rw-r--r--templates/ja/printer-default.tmpl12
-rw-r--r--templates/ja/printer-deleted.tmpl6
-rw-r--r--templates/ja/printer-jobs-header.tmpl3
-rw-r--r--templates/ja/printer-modified.tmpl7
-rw-r--r--templates/ja/printer-purge.tmpl9
-rw-r--r--templates/ja/printer-reject.tmpl9
-rw-r--r--templates/ja/printer-start.tmpl9
-rw-r--r--templates/ja/printer-stop.tmpl8
-rw-r--r--templates/ja/printer.tmpl47
-rw-r--r--templates/ja/printers-header.tmpl1
-rw-r--r--templates/ja/printers.tmpl11
-rw-r--r--templates/ja/restart.tmpl8
-rw-r--r--templates/ja/samba-export.tmpl56
-rw-r--r--templates/ja/samba-exported.tmpl1
-rw-r--r--templates/ja/search.tmpl10
-rw-r--r--templates/ja/set-printer-options-header.tmpl26
-rw-r--r--templates/ja/set-printer-options-trailer.tmpl16
-rw-r--r--templates/ja/subscription-added.tmpl5
-rw-r--r--templates/ja/subscription-canceled.tmpl5
-rw-r--r--templates/ja/test-page.tmpl8
-rw-r--r--templates/ja/trailer.tmpl8
-rw-r--r--templates/ja/users.tmpl30
-rw-r--r--templates/job-cancel.tmpl7
-rw-r--r--templates/job-hold.tmpl7
-rw-r--r--templates/job-move.tmpl27
-rw-r--r--templates/job-moved.tmpl8
-rw-r--r--templates/job-release.tmpl7
-rw-r--r--templates/job-restart.tmpl7
-rw-r--r--templates/jobs-header.tmpl5
-rw-r--r--templates/jobs.tmpl36
-rw-r--r--templates/list-available-printers.tmpl11
-rw-r--r--templates/modify-class.tmpl34
-rw-r--r--templates/modify-printer.tmpl42
-rw-r--r--templates/norestart.tmpl8
-rw-r--r--templates/option-boolean.tmpl6
-rw-r--r--templates/option-conflict.tmpl7
-rw-r--r--templates/option-header.tmpl5
-rw-r--r--templates/option-pickmany.tmpl6
-rw-r--r--templates/option-pickone.tmpl18
-rw-r--r--templates/option-trailer.tmpl5
-rw-r--r--templates/pager.tmpl6
-rw-r--r--templates/pl/add-class.tmpl40
-rw-r--r--templates/pl/add-printer.tmpl47
-rw-r--r--templates/pl/add-rss-subscription.tmpl44
-rw-r--r--templates/pl/admin.tmpl110
-rw-r--r--templates/pl/choose-device.tmpl54
-rw-r--r--templates/pl/choose-make.tmpl64
-rw-r--r--templates/pl/choose-model.tmpl60
-rw-r--r--templates/pl/choose-serial.tmpl52
-rw-r--r--templates/pl/choose-uri.tmpl44
-rw-r--r--templates/pl/class-added.tmpl8
-rw-r--r--templates/pl/class-confirm.tmpl10
-rw-r--r--templates/pl/class-deleted.tmpl7
-rw-r--r--templates/pl/class-jobs-header.tmpl3
-rw-r--r--templates/pl/class-modified.tmpl8
-rw-r--r--templates/pl/class.tmpl44
-rw-r--r--templates/pl/classes-header.tmpl1
-rw-r--r--templates/pl/classes.tmpl11
-rw-r--r--templates/pl/command.tmpl12
-rw-r--r--templates/pl/edit-config.tmpl24
-rw-r--r--templates/pl/error-op.tmpl9
-rw-r--r--templates/pl/error.tmpl9
-rw-r--r--templates/pl/header.tmpl.in29
-rw-r--r--templates/pl/help-header.tmpl51
-rw-r--r--templates/pl/help-printable.tmpl9
-rw-r--r--templates/pl/help-trailer.tmpl1
-rw-r--r--templates/pl/job-cancel.tmpl7
-rw-r--r--templates/pl/job-hold.tmpl7
-rw-r--r--templates/pl/job-move.tmpl27
-rw-r--r--templates/pl/job-moved.tmpl8
-rw-r--r--templates/pl/job-release.tmpl7
-rw-r--r--templates/pl/job-restart.tmpl7
-rw-r--r--templates/pl/jobs-header.tmpl5
-rw-r--r--templates/pl/jobs.tmpl37
-rw-r--r--templates/pl/list-available-printers.tmpl11
-rw-r--r--templates/pl/modify-class.tmpl34
-rw-r--r--templates/pl/modify-printer.tmpl42
-rw-r--r--templates/pl/norestart.tmpl8
-rw-r--r--templates/pl/option-boolean.tmpl6
-rw-r--r--templates/pl/option-conflict.tmpl7
-rw-r--r--templates/pl/option-header.tmpl5
-rw-r--r--templates/pl/option-pickmany.tmpl6
-rw-r--r--templates/pl/option-pickone.tmpl18
-rw-r--r--templates/pl/option-trailer.tmpl5
-rw-r--r--templates/pl/pager.tmpl6
-rw-r--r--templates/pl/printer-accept.tmpl9
-rw-r--r--templates/pl/printer-added.tmpl8
-rw-r--r--templates/pl/printer-configured.tmpl8
-rw-r--r--templates/pl/printer-confirm.tmpl10
-rw-r--r--templates/pl/printer-default.tmpl13
-rw-r--r--templates/pl/printer-deleted.tmpl7
-rw-r--r--templates/pl/printer-jobs-header.tmpl3
-rw-r--r--templates/pl/printer-modified.tmpl8
-rw-r--r--templates/pl/printer-purge.tmpl9
-rw-r--r--templates/pl/printer-reject.tmpl9
-rw-r--r--templates/pl/printer-start.tmpl9
-rw-r--r--templates/pl/printer-stop.tmpl9
-rw-r--r--templates/pl/printer.tmpl47
-rw-r--r--templates/pl/printers-header.tmpl1
-rw-r--r--templates/pl/printers.tmpl11
-rw-r--r--templates/pl/restart.tmpl8
-rw-r--r--templates/pl/samba-export.tmpl55
-rw-r--r--templates/pl/samba-exported.tmpl1
-rw-r--r--templates/pl/search.tmpl10
-rw-r--r--templates/pl/set-printer-options-header.tmpl26
-rw-r--r--templates/pl/set-printer-options-trailer.tmpl16
-rw-r--r--templates/pl/subscription-added.tmpl5
-rw-r--r--templates/pl/subscription-canceled.tmpl5
-rw-r--r--templates/pl/test-page.tmpl8
-rw-r--r--templates/pl/trailer.tmpl8
-rw-r--r--templates/pl/users.tmpl30
-rw-r--r--templates/printer-accept.tmpl9
-rw-r--r--templates/printer-added.tmpl8
-rw-r--r--templates/printer-configured.tmpl8
-rw-r--r--templates/printer-confirm.tmpl10
-rw-r--r--templates/printer-default.tmpl13
-rw-r--r--templates/printer-deleted.tmpl7
-rw-r--r--templates/printer-jobs-header.tmpl3
-rw-r--r--templates/printer-modified.tmpl8
-rw-r--r--templates/printer-purge.tmpl9
-rw-r--r--templates/printer-reject.tmpl9
-rw-r--r--templates/printer-start.tmpl9
-rw-r--r--templates/printer-stop.tmpl9
-rw-r--r--templates/printer.tmpl47
-rw-r--r--templates/printers-header.tmpl1
-rw-r--r--templates/printers.tmpl11
-rw-r--r--templates/restart.tmpl8
-rw-r--r--templates/ru/Makefile201
-rw-r--r--templates/ru/add-class.tmpl40
-rw-r--r--templates/ru/add-printer.tmpl47
-rw-r--r--templates/ru/add-rss-subscription.tmpl44
-rw-r--r--templates/ru/admin.tmpl110
-rw-r--r--templates/ru/choose-device.tmpl54
-rw-r--r--templates/ru/choose-make.tmpl64
-rw-r--r--templates/ru/choose-model.tmpl59
-rw-r--r--templates/ru/choose-serial.tmpl52
-rw-r--r--templates/ru/choose-uri.tmpl43
-rw-r--r--templates/ru/class-added.tmpl7
-rw-r--r--templates/ru/class-confirm.tmpl10
-rw-r--r--templates/ru/class-deleted.tmpl7
-rw-r--r--templates/ru/class-jobs-header.tmpl3
-rw-r--r--templates/ru/class-modified.tmpl7
-rw-r--r--templates/ru/class.tmpl44
-rw-r--r--templates/ru/classes-header.tmpl1
-rw-r--r--templates/ru/classes.tmpl11
-rw-r--r--templates/ru/command.tmpl12
-rw-r--r--templates/ru/edit-config.tmpl24
-rw-r--r--templates/ru/error-op.tmpl9
-rw-r--r--templates/ru/error.tmpl9
-rw-r--r--templates/ru/header.tmpl.in29
-rw-r--r--templates/ru/help-header.tmpl46
-rw-r--r--templates/ru/help-printable.tmpl9
-rw-r--r--templates/ru/help-trailer.tmpl1
-rw-r--r--templates/ru/job-cancel.tmpl7
-rw-r--r--templates/ru/job-hold.tmpl7
-rw-r--r--templates/ru/job-move.tmpl27
-rw-r--r--templates/ru/job-moved.tmpl7
-rw-r--r--templates/ru/job-release.tmpl7
-rw-r--r--templates/ru/job-restart.tmpl7
-rw-r--r--templates/ru/jobs-header.tmpl6
-rw-r--r--templates/ru/jobs.tmpl37
-rw-r--r--templates/ru/list-available-printers.tmpl11
-rw-r--r--templates/ru/modify-class.tmpl34
-rw-r--r--templates/ru/modify-printer.tmpl42
-rw-r--r--templates/ru/norestart.tmpl7
-rw-r--r--templates/ru/option-boolean.tmpl6
-rw-r--r--templates/ru/option-conflict.tmpl7
-rw-r--r--templates/ru/option-header.tmpl5
-rw-r--r--templates/ru/option-pickmany.tmpl6
-rw-r--r--templates/ru/option-pickone.tmpl18
-rw-r--r--templates/ru/option-trailer.tmpl5
-rw-r--r--templates/ru/pager.tmpl6
-rw-r--r--templates/ru/printer-accept.tmpl9
-rw-r--r--templates/ru/printer-added.tmpl8
-rw-r--r--templates/ru/printer-configured.tmpl8
-rw-r--r--templates/ru/printer-confirm.tmpl10
-rw-r--r--templates/ru/printer-default.tmpl12
-rw-r--r--templates/ru/printer-deleted.tmpl7
-rw-r--r--templates/ru/printer-jobs-header.tmpl3
-rw-r--r--templates/ru/printer-modified.tmpl8
-rw-r--r--templates/ru/printer-purge.tmpl9
-rw-r--r--templates/ru/printer-reject.tmpl9
-rw-r--r--templates/ru/printer-start.tmpl9
-rw-r--r--templates/ru/printer-stop.tmpl9
-rw-r--r--templates/ru/printer.tmpl47
-rw-r--r--templates/ru/printers-header.tmpl1
-rw-r--r--templates/ru/printers.tmpl11
-rw-r--r--templates/ru/restart.tmpl8
-rw-r--r--templates/ru/samba-export.tmpl54
-rw-r--r--templates/ru/samba-exported.tmpl1
-rw-r--r--templates/ru/search.tmpl10
-rw-r--r--templates/ru/set-printer-options-header.tmpl26
-rw-r--r--templates/ru/set-printer-options-trailer.tmpl16
-rw-r--r--templates/ru/subscription-added.tmpl5
-rw-r--r--templates/ru/subscription-canceled.tmpl5
-rw-r--r--templates/ru/test-page.tmpl8
-rw-r--r--templates/ru/trailer.tmpl6
-rw-r--r--templates/ru/users.tmpl30
-rw-r--r--templates/samba-export.tmpl55
-rw-r--r--templates/samba-exported.tmpl1
-rw-r--r--templates/search.tmpl10
-rw-r--r--templates/set-printer-options-header.tmpl26
-rw-r--r--templates/set-printer-options-trailer.tmpl16
-rw-r--r--templates/subscription-added.tmpl5
-rw-r--r--templates/subscription-canceled.tmpl5
-rw-r--r--templates/test-page.tmpl8
-rw-r--r--templates/trailer.tmpl8
-rw-r--r--templates/users.tmpl30
-rw-r--r--test/4.1-requests.test159
-rw-r--r--test/4.2-cups-printer-ops.test327
-rw-r--r--test/4.3-job-ops.test330
-rw-r--r--test/4.4-subscription-ops.test153
-rwxr-xr-xtest/5.1-lpadmin.sh55
-rwxr-xr-xtest/5.2-lpc.sh31
-rwxr-xr-xtest/5.3-lpq.sh31
-rwxr-xr-xtest/5.4-lpstat.sh43
-rwxr-xr-xtest/5.5-lp.sh86
-rwxr-xr-xtest/5.6-lpr.sh86
-rwxr-xr-xtest/5.7-lprm.sh47
-rwxr-xr-xtest/5.8-cancel.sh45
-rwxr-xr-xtest/5.9-lpinfo.sh55
-rw-r--r--test/Dependencies19
-rw-r--r--test/Makefile181
-rw-r--r--test/create-job-format.test56
-rw-r--r--test/create-job-sheets.test55
-rw-r--r--test/create-job-timeout.test54
-rw-r--r--test/create-job.test52
-rw-r--r--test/create-printer-subscription.test49
-rw-r--r--test/get-completed-jobs.test51
-rw-r--r--test/get-devices.test21
-rw-r--r--test/get-job-attributes.test27
-rw-r--r--test/get-job-attributes2.test28
-rw-r--r--test/get-jobs.test53
-rw-r--r--test/get-ppd-printer.test20
-rw-r--r--test/get-ppd.test20
-rw-r--r--test/get-ppds-drv-only.test24
-rw-r--r--test/get-ppds-language.test21
-rw-r--r--test/get-ppds-make-and-model.test21
-rw-r--r--test/get-ppds-make.test21
-rw-r--r--test/get-ppds-product.test21
-rw-r--r--test/get-ppds-psversion.test21
-rw-r--r--test/get-ppds.test21
-rw-r--r--test/get-printer-attributes-2.0.test48
-rw-r--r--test/get-printer-attributes.test38
-rw-r--r--test/get-printers.test19
-rw-r--r--test/get-subscriptions.test21
-rw-r--r--test/ipp-1.1.test748
-rw-r--r--test/ipp-2.0.test80
-rw-r--r--test/ipp-2.1.test95
-rw-r--r--test/ipp-backend.test22
-rw-r--r--test/ippserver.c4380
-rw-r--r--test/ipptool.c4921
-rw-r--r--test/print-job-hold.test41
-rw-r--r--test/print-job-media-col.test46
-rw-r--r--test/print-job.test28
-rw-r--r--test/print-uri.test27
-rw-r--r--test/printer.opacitybin0 -> 18493 bytes
-rw-r--r--test/printer.pngbin0 -> 5133 bytes
-rwxr-xr-xtest/run-stp-tests.sh870
-rw-r--r--test/set-attrs-hold.test180
-rw-r--r--test/str-header.html30
-rw-r--r--test/str-trailer.html2
-rw-r--r--test/testfile.jpgbin0 -> 204156 bytes
-rw-r--r--test/testfile.pdfbin0 -> 279746 bytes
-rw-r--r--test/testfile.ps598
-rw-r--r--test/testfile.txt60
-rw-r--r--test/testhp.ppd187
-rw-r--r--test/testps.ppd183
-rwxr-xr-xtest/waitjobs.sh60
-rwxr-xr-xtools/checkglobals32
-rwxr-xr-xtools/listpublic12
-rwxr-xr-xtools/makeipptoolpkg84
-rwxr-xr-xtools/makesrcdist91
-rwxr-xr-xtools/pdftops-darwin.sh44
-rwxr-xr-xtools/products.php50
-rwxr-xr-xtools/testosx137
-rwxr-xr-xtools/testrpm32
-rw-r--r--vc2005/cups.sln78
-rw-r--r--vc2005/cupstestppd.vcproj356
-rw-r--r--vc2005/ipptool.vcproj199
-rw-r--r--vc2005/libcups2.vcproj1611
-rw-r--r--vc2005/libcupsimage2.vcproj395
-rw-r--r--vc2005/testfile.vcproj202
-rw-r--r--vc2005/testhttp.vcproj202
-rw-r--r--vcnet/config.h788
-rw-r--r--vcnet/cups.sln91
-rw-r--r--vcnet/cupstestppd.vcproj353
-rw-r--r--vcnet/ipptool.vcproj385
-rw-r--r--vcnet/libcups2.vcproj1608
-rw-r--r--vcnet/libcupsimage2.vcproj388
-rw-r--r--vcnet/regex/COPYRIGHT20
-rw-r--r--vcnet/regex/Makefile130
-rw-r--r--vcnet/regex/README32
-rw-r--r--vcnet/regex/WHATSNEW108
-rw-r--r--vcnet/regex/cclass.h31
-rw-r--r--vcnet/regex/cname.h102
-rw-r--r--vcnet/regex/debug.c242
-rw-r--r--vcnet/regex/debug.ih14
-rw-r--r--vcnet/regex/engine.c1019
-rw-r--r--vcnet/regex/engine.ih35
-rw-r--r--vcnet/regex/main.c510
-rw-r--r--vcnet/regex/main.ih19
-rw-r--r--vcnet/regex/mkh76
-rw-r--r--vcnet/regex/regcomp.c1603
-rw-r--r--vcnet/regex/regcomp.ih51
-rw-r--r--vcnet/regex/regerror.c126
-rw-r--r--vcnet/regex/regerror.ih12
-rw-r--r--vcnet/regex/regex.3509
-rw-r--r--vcnet/regex/regex.7235
-rw-r--r--vcnet/regex/regex.h74
-rw-r--r--vcnet/regex/regex2.h134
-rw-r--r--vcnet/regex/regexec.c138
-rw-r--r--vcnet/regex/regfree.c37
-rw-r--r--vcnet/regex/split.c316
-rw-r--r--vcnet/regex/tests477
-rw-r--r--vcnet/regex/utils.h22
-rw-r--r--vcnet/testfile.vcproj201
-rwxr-xr-xvcnet/testhttp.vcproj201
-rw-r--r--xcode/CUPS.xcodeproj/project.pbxproj4614
-rw-r--r--xcode/config.h736
1465 files changed, 637638 insertions, 0 deletions
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 <pam/pam_appl.h> instead of
+ <security/pam_appl.h>.
+ - 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 <stdlib.h> 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, <Limit>, <LimitExcept>, 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 <sys/ioctl.h>, 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-1.2.txt b/CHANGES-1.2.txt
new file mode 100644
index 000000000..7b0b1f2de
--- /dev/null
+++ b/CHANGES-1.2.txt
@@ -0,0 +1,1261 @@
+CHANGES-1.2.txt
+---------------
+
+CHANGES IN CUPS V1.2.12
+
+ - The PHP cups_print_file() function crashed if the options
+ array contained non-string option values (STR #2430)
+ - The image/tiff file matching rule incorrectly identified
+ some text files as TIFF files (STR #2431)
+ - The filter(7) man page incorrectly documented the
+ "PAGE: total #-pages" message (STR #2427)
+ - PCL text files were mis-identified as HP-GL/2 and
+ caused the HP-GL/2 filter to hang (STR #2423)
+ - When printing to a queue with user ACLs, the scheduler
+ incorrectly returned a quota error instead of a "not
+ allowed to print" error (STR #2409)
+ - cupsaddsmb could get in a loop if no printer drivers
+ were installed (STR #2407)
+ - cupsRasterReadHeader() did not byte-swap the header
+ properly when compiled with certain versions of GCC.
+ - The IPP backend did not send the document-format
+ attribute for filtered jobs (STR #2411)
+ - Some PPD files could cause a crash in ppdOpen2 (STR
+ #2408)
+ - The web admin interface incorrectly handled the "share
+ printers" and "show remote printers" settings (STR
+ #2393)
+ - The scheduler's log messages about AuthClass and
+ AuthGroupName advised using a replacement directive but
+ had the wrong syntax (STR #2400)
+ - Updated the PostScript/PJL and HP-GL/2 MIME rules to
+ look in the first 4k of the file, not just the first 1k
+ (STR #2386)
+ - Updated the Italian localization (STR #2382)
+
+
+CHANGES IN CUPS V1.2.11
+
+ - Fixed the "relaying from" log message (STR #2376)
+ - Updated the launchd support on Mac OS X to better
+ support reconfiguration.
+ - "make distclean" didn't remove all generated files
+ (STR #2366)
+ - Fixed a bug in the advertisement of classes (STR
+ #2373)
+ - The IPP backend now stays running until the job is
+ actually printed by the remote server; previously
+ it would stop monitoring the job if it was held or
+ temporarily stopped (STR #2352)
+ - PDF files were not always printed using the correct
+ orientation (STR #2348)
+ - The scheduler could crash if you specified a bad file:
+ URI for a printer (STR #2351)
+ - The Renew-Subscription operation now returns the
+ notify-lease-duration value that was used (STR #2346)
+ - The IPP backend sent job options to IPP printers,
+ however some printers tried to override the options
+ embedded in the PS/PCL stream with those job options
+ (STR #2349)
+ - ppdLocalize() now also tries a country-specific
+ localization for when localizing to a generic locale
+ name.
+ - The cupstestppd program now allows for partial
+ localizations to reduce the size of universal PPD
+ files.
+ - Chinese PPD files were incorrectly tagged with the
+ "cn" locale (should have been "zh")
+ - The backends now manage the printer-state-reasons
+ attribute more accurately (STR #2345)
+ - Java, PHP, Perl, and Python scripts did not work
+ properly (STR #2342)
+ - The scheduler would take forever to start if the
+ maximum number of file descriptors was set to
+ "unlimited" (STR #2329)
+ - The page-ranges option was incorrectly applied to the
+ banner pages (STR #2336)
+ - Fixed some GCC compile warnings (STR #2340)
+ - The DBUS notification code was broken for older
+ versions of DBUS (STR #2327)
+ - The IPv6 code did not compile on HP-UX 11.23 (STR
+ #2331)
+ - PPD constraints did not work properly with custom
+ options.
+ - Regular PPD options with the name "CustomFoo" did
+ not work.
+ - The USB backend did not work on NetBSD (STR #2324)
+ - The printer-state-reasons attribute was incorrectly
+ cleared after a job completed (STR #2323)
+ - The scheduler did not set the printer operation policy
+ on startup, only on soft reload (STR #2319)
+ - The AP_FIRSTPAGE_InputSlot option did not clear any
+ ManualFeed setting that was made, which caused problems
+ with some PPD files (STR #2318)
+ - cupsDoFileRequest() and cupsDoRequest() did not abort
+ when getting an error in the response (STR #2315)
+ - The scheduler did not schedule jobs properly to remote
+ or nested classes (STR #2317)
+ - Updated the mime.types and mime.convs headers to warn
+ that the files are overwritten when CUPS is installed.
+ Local changes should go in local.types or local.convs,
+ respectively (STR #2310)
+ - The scheduler could get in an infinite loop if a
+ printer in an implicit class disappeared (STR #2311)
+ - The pstops filter did not handle %%EndFeature comments
+ properly (STR #2306)
+ - Fixed a problem with the Polish web page printer icons
+ (STR #2305)
+ - ppdLocalize() now also localizes the cupsICCProfile
+ attributes.
+ - The scheduler still had a reference to the incorrect
+ "notify-recipient" attribute (STR #2307)
+ - The "make check" and "make test" subscription tests did
+ not set the locale (STR #2307)
+ - The "make check" and "make test" subscription tests
+ incorrectly used the notify-recipient attribute instead
+ of notify-recipient-uri (STR #2307)
+ - cupsRasterInterpretPPD() incorrectly limited the
+ cupsBorderlessScalingFactor when specified in the
+ job options.
+
+
+CHANGES IN CUPS V1.2.10
+
+ - ppdLocalize() now supports localizing for Japanese
+ using the "jp" locale name used by the ppdmerge
+ program from the CUPS DDK 1.1.0 (STR #2301)
+ - _cupsAdminSetServerSettings() did not support changing
+ of top-level directives as designed.
+ - The init script path check was broken.
+ - CUPS incorrectly used the attribute "notify-recipient"
+ instead of "notify-recicpient-uri" in several places
+ (STR #2297)
+ - Fixed a configure script bug on MirBSD (STR #2294)
+ - The pdftops filter did not limit the amount of recursion
+ of page sets (STR #2293)
+ - Custom page sizes with fractional point sizes did not
+ work (STR #2296)
+ - The lpoptions command would crash when adding or removing
+ options on a system with no printers (STR #2295)
+
+
+CHANGES IN CUPS V1.2.9
+
+ - The scheduler did not use the default job-sheets
+ (banners) for implicit classes (STR #2284)
+ - The scheduler could crash when listing complete jobs
+ that had been unloaded from memory (STR #2288)
+ - The French localization was doubled up (STR #2287)
+ - Build system fixes for several platforms (STR #2260,
+ STR #2275)
+ - The scheduler's openssl certificate generation code was
+ broken on some platforms (STR #2282)
+ - The scheduler's log rotation check for devices was
+ broken (STR #2278)
+ - The LPD mini-daemon did not handle the document-format
+ option correctly (STR #2266)
+ - The pdftops filter ignored the "match" size option in the
+ pdftops.conf file (STR #2285)
+ - cupstestppd now validates UTF-8 text strings in
+ globalized PPD files (STR #2283)
+ - The outputorder=reverse option did not work with all
+ printers (STR #2279)
+ - Classes containing other classes did not always work
+ (STR #2255)
+ - Printer location and description information was lost
+ if the corresponding string contained the "#" character
+ (STR #2254)
+ - cupsRemoveOption() did not work properly (STR #2264)
+ - The USB backend did not work with some USB to parallel
+ cables on Mac OS X.
+ - The test page did not print the rulers properly on
+ large media sizes (STR #2252)
+ - The text filter could crash when pretty printing certain
+ types of files (STR #2158)
+
+
+CHANGES IN CUPS V1.2.8
+
+ - Documentation fixes (STR #2141, STR #2157)
+ - The HTTP upgrade redirection used by the scheduler did
+ not work with Internet Explorer (STR #2235)
+ - Members of a class with Unicode names did not appear
+ correctly in the web interface (STR #2154)
+ - Changing the "Save debugging information" setting in
+ the web interface no longer affects the other server
+ settings (STR #1993)
+ - The scheduler did not choose SSL certificates correctly
+ on Mac OS X (STR #2225)
+ - The scheduler could get in an infinite loop when
+ printing to a remote class (STR #2228)
+ - The jobs web page did not have separating space after
+ the number of pages column (STR #2230)
+ - Added French localization (STR #2221)
+ - Updated Spanish localization (STR #2223)
+ - Updated Japanese localization (STR #2216)
+ - cupsBorderlessScalingFacter was limited to a range of
+ 0.9 to 1.1, but some printers need larger values (STR
+ #2222)
+ - Landscape printing of PDF files did not always work
+ (STR #2149)
+ - Fixed slow USB printing on Minolta printers (STR #2104,
+ STR #2219)
+ - The ZPL label printer driver could produce stretched
+ output (PR #6448)
+ - The IPP backend now clears the printer-state-message
+ when there are no outstanding errors or warnings (STR
+ #2126)
+ - The CUPS Java scripting support did not work with
+ recent versions of Java due to the use of Sun's private
+ Base64 class (STR #2152)
+ - The scheduler did not pass HTTP GET form variables to
+ custom CGI programs (STR #2173)
+ - The lpoptions command now displays the reason why a PPD
+ file cannot be found (STR #2184)
+ - The scheduler did not accept "none" as a browse
+ protocol name (STR #2200)
+ - The scheduler still loaded the remote printer cache,
+ even when browsing was disabled (STR #2198)
+ - The SNMP backend now shows OfficeJet printers with the
+ "HP" manufacturer prefix (STR #2151)
+ - Web interface HTML cleanup (STR #2153)
+ - The parallel backend consumed 100% CPU on FreeBSD due
+ to an apparently common parallel port driver bug (STR
+ #2161)
+ - ippReadIO() incorrectly returned IPP_IDLE when the
+ initial IPP message header could not be read (STR
+ #2179)
+ - cupsRasterInterpretPPD() did not support custom options
+ (STR #1960)
+ - Collated output produced by the PostScript filter could
+ lose some options (STR #2137)
+ - job-hold-until with time values for the next day would
+ be held for 60 days (STR #2144)
+ - Some types of Sun raster files did not print correctly
+ (STR #2107)
+ - Raw PBM files did not print correctly (STR #2106)
+ - The SNMP backend no longer uses IPP with HP printers,
+ as some recent firmware versions appear to not work
+ (STR #2055)
+ - cupsMarkOptions() did not handle the
+ multiple-document-handling option (STR #2135)
+ - lpstat did not show the local job ID of active printers
+ (STR #2125)
+ - The backends incorrectly used STATUS:
+ media-tray-empty-error messages for out-of-paper
+ conditions (STR #2123, STR #2124)
+ - cupsGetPPD2() returned the wrong error when the PPD
+ file did not exist (STR #2122)
+ - cupsDoAuthentication() did not translate the password
+ prompt (STR #2121)
+ - httpGetLength2() did not handle error messages without
+ content correctly (STR #2133)
+ - Added support for 32/64-bit libraries on HP-UX Itanium
+ systems (STR #2115)
+ - Fixed a configure script problem with the 32/64-bit
+ library support (STR #2114)
+ - The PostScript filter did not properly output document
+ setup commands for reversed output (STR #2111)
+ - The scheduler did not parse IPv6 netmasks properly (STR
+ #2117)
+
+
+CHANGES IN CUPS V1.2.7
+
+ - Documentation updates (STR #2089)
+ - Added an Italian translation (STR #2105)
+ - The PostScript filter now rotates the bounding box
+ values as needed (STR #2079)
+ - The scheduler no longer loads the remote printer cache
+ when browsing is disabled (STR #2084)
+ - The scheduler no longer writes a new launchd
+ configuration file if it doesn't have to (STR #2083)
+ - Updated the USB and PAP backends for Mac OS X (STR
+ #2086)
+ - The scheduler now picks up on changes to IPv6 and DNS
+ configuration on Mac OS X (STR #2085)
+ - The lpstat program could still hang (STR #2098)
+ - Fixed an inefficiency in the SNMP IPP detection code
+ (STR #2100)
+ - The SSL negotiation code did not implement short
+ timeouts (STR #2091)
+
+
+CHANGES IN CUPS V1.2.6
+
+ - The web interface was not localized on Mac OS X (STR
+ #2075)
+ - "lpc status" did not show the number of queued jobs for
+ disabled queues (STR #2069)
+ - The lpstat program could hang (STR #2073)
+ - The serial backend did not support the new USB serial
+ filenames on Linux (STR #2061)
+ - The parallel backend did not support bidirectional I/O
+ properly (STR #2056)
+ - The network backends now log the numeric address that
+ is being used (STR #2046)
+ - Fixed a compile error when using libpaper.
+ - Fixed a compile error when compiling on Solaris with
+ threading enabled (STR #2049, STR #2050)
+ - Missing printer-state-changed event for
+ printer-state-message updates (STR #2047)
+
+
+CHANGES IN CUPS V1.2.5
+
+ - Documentation updates (STR #2038)
+ - The SNMP backend no longer uses IPP for Epson printers
+ (STR #2028)
+ - Updated the configure script for Tru64 UNIX 5.1 (STR
+ #2033)
+ - Tru64 5.1B's getaddrinfo() and getnameinfo() functions
+ leak file descriptors (STR #2034)
+ - cupsAddDest() didn't add the parent destination's
+ options and attributes.
+ - ppdConflicts() did not handle custom option
+ constraints.
+ - Raw printing of gzip'd files did not work (STR #2009)
+ - The scheduler no longer preserves default option
+ choices when the new PPD no longer provides the old
+ default choice (STR #1929)
+ - The Linux SCSI backend is now only built if the SCSI
+ development headers are installed.
+ - USB printing to Minolta printers did not work (STR
+ #2019)
+ - Windows clients could not monitor the queue status (STR
+ #2006)
+ - The scheduler didn't log the operation name in the
+ access_log file for Create-Job and Print-Job requests.
+ - The PostScript filter now separates collated copies
+ with any required JCL commands so that JCL-based
+ finishing options act on the individual copies and not
+ all of the copies as a single document.
+ - The PostScript filter now disables duplex printing when
+ printing a 1-page document.
+ - cups-lpd didn't pass the correct
+ job-originating-host-name value (STR #2023)
+ - Fixed some speling errors in the German message catalog
+ (STR #2012)
+ - cupstestppd did not catch PPD files with bad
+ UIConstraints values (STR #2016)
+ - The USB backend did not work with the current udev-
+ created printers if the first printer was disconnected
+ (STR #2017)
+ - Mirrored and rotated printing did not work with some
+ documents (STR #2004)
+ - 2-sided printing with banners did not work properly on
+ some printers (STR #2018)
+ - Updated the raw type rule to handle PJL within the
+ first 4k of a print job (STR #1969)
+ - Added an Estonian translation (STR #1957)
+ - Clarified the documentation for the cupsd.conf @LOCAL
+ and @IF(name) allow/deny functionality (STR #1992)
+ - The PostScript filters did not escape the Title and For
+ comments in the print job header (STR #1988)
+ - The scheduler would use 100% CPU if browsing was
+ disabled and the cupsd.conf file contained BrowsePoll
+ lines (STR #1994)
+ - The cupsDirRead() function did not work properly on
+ non-POSIX-compliant systems (STR #2001)
+ - The cupsFile functions didn't handle read/write errors
+ properly (STR #1996)
+ - The DBUS support now works with older versions of the
+ DBUS library.
+
+
+CHANGES IN CUPS V1.2.4
+
+ - The --with-printcap configure option did not work (STR
+ #1984)
+ - The character set reported by cupsLangGet() did not
+ always reflect the default character set of a given
+ locale (STR #1983)
+ - Older Lexmark and Tektronix printers did not work with
+ IPP (STR #1980)
+ - Failsafe printing did not work (PR #6328)
+ - Some web interface redirects did not work (STR #1978)
+ - The web interface change settings button could
+ introduce a "Port 0" line in cupsd.conf if there was no
+ loopback connection available (STR #1979)
+ - The web interface change settings and edit
+ configuration file buttons would truncate the
+ cupsd.conf file (STR #1976)
+ - The German web interface used the wrong printer icon
+ images (STR #1973)
+ - The "All Documents" link in the on-line help was
+ missing a trailing slash (STR #1971)
+ - The Polish web interface translation used the wrong
+ URLs for the job history (STR #1963)
+ - The "reprint job" button did not work (STR #1956)
+ - The scheduler did not always report printer or job
+ events properly (STR #1955)
+ - The scheduler always stopped the queue on error,
+ regardless of the exit code, if the error policy was
+ set to "stop-printer" (STR #1959)
+ - ppdEmitJCL() included UTF-8 characters in the JCL job
+ name, which caused problems on some printers (STR
+ #1959)
+ - Fixed a buffering problem that cause high CPU usage
+ (STR #1968)
+ - The command-line applications did not convert
+ command-line strings to UTF-8 as needed (STR #1958)
+ - cupsDirRead() incorrectly aborted when reading a
+ symbolic link that pointed to a file/directory that did
+ not exist (STR #1953)
+ - The cupsInterpretRasterPPD() function did not handle
+ custom page sizes properly.
+
+
+CHANGES IN CUPS V1.2.3
+
+ - The scheduler did not send job-state or
+ job-config-changed events when a job was held,
+ released, or changed (STR #1947)
+ - The scheduler now aborts if the configuration file and
+ directory checks fail (STR #1941)
+ - Fixed a problem with ippPort() not using the port
+ number that was set via the client.conf file or
+ CUPS_SERVER environment variable (STR #1945)
+ - HTTP headers were not buffered (STR #1899)
+ - Some IPP printers (HP) did not like UTF-8 job names
+ (STR #1837)
+ - The CUPS desktop icon is now localized for Polish (STR
+ #1920)
+ - Printer options were not always honored when printing
+ from Windows clients (STR #1839)
+ - The openssl command would lock up the scheduler when
+ generating an encryption certificate on some platforms
+ due to a lack of entropy for the random number
+ generator (STR #1876)
+ - The web admin page did not recognize that "Listen 631"
+ enabled remote access (STR #1908)
+ - The web admin page did not check whether changes were
+ made to the Basic Server Settings check boxes (STR
+ #1908)
+ - The IPP backend could generate N*N copies in certain
+ edge cases.
+ - The scheduler did not restore remote printers properly
+ when BrowseShortNames was enabled (STR #1893)
+ - Polling did not handle changes to the network
+ environment on Mac OS X (STR #1896)
+ - The "make test" subscription tests used invalid
+ notify-recipient-uri values (STR #1910)
+ - Printers could be left in an undefined state on system
+ sleep (STR #1905)
+ - The Berkeley and System V commands did not always use
+ the expected character set (STR #1915)
+ - Remote printing fixes (STR #1881)
+ - The cupstestppd utility did not validate translation
+ strings for custom options properly.
+ - Multi-language PPD files were not properly localized in
+ the web interface (STR #1913)
+ - The admin page's simple settings options did not check
+ for local domain socket or IPv6 addresses and did not
+ use "localhost" as the listen address.
+ - An empty BrowseProtocols, BrowseLocalProtocols, or
+ BrowseRemoteProtocols line would crash the scheduler
+ instead of disabling the corresponding browsing options.
+ - The scheduler now logs IPP operation status as debug
+ messages instead of info or error.
+ - cupsFileRewind() didn't clear the end-of-file state.
+ - cupstestppd didn't report the actual misspelling of the
+ 1284DeviceID attribute (STR #1849)
+ - BrowseRelay didn't work on Debian (STR #1887)
+ - configure --without-languages didn't work (STR #1879)
+ - Manually added remote printers did not work (STR #1881)
+ - The <cups/backend.h> header was not installed.
+ - Updated the build files for Autoconf 2.60 (STR #1853)
+ - The scheduler incorrectly terminated the polling
+ processes after receiving a partial log line.
+ - The cups-lpd mini-daemon reported "No printer-state
+ attribute found" errors when reporting the queue status
+ (PR #6250, STR #1821)
+ - SNMP backend improvements (STR #1737, STR #1742, STR
+ #1790, STR #1835, STR #1880)
+ - The scheduler erroneously reported an error with the
+ CGI pipe (STR #1860)
+ - Fixed HP-UX compile problems (STR #1858, STR #1859)
+ - cupstestppd crashed with some PPD files (STR #1864)
+ - The <cups/dir.h> and <cups/file.h> header files did not
+ work with C++.
+
+
+CHANGES IN CUPS V1.2.2
+
+ - Documentation updates (STR #1765, STR #1780)
+ - CUPS didn't know about alternate character set names
+ for Asian text (STR #1819)
+ - The lpoptions -o and -r options did not work unless you
+ specified a printer.
+ - The lpoptions command incorrectly allowed users to set
+ printer attributes like printer-type (STR #1791)
+ - httpWait() did not flush the write buffer, causing "bad
+ request" errors when communicating with CUPS 1.1.x
+ servers (STR #1717)
+ - Polling did not sanitize the printer description,
+ location, or make and model strings like broadcasts
+ did.
+ - Polled printers did not show the server's default
+ job-sheets option value.
+ - The Samba password prompt was not properly localized
+ (STR #1814)
+ - Added a German translation (STR #1842)
+ - The scheduler now creates self-signed SSL certficates
+ automatically when using OpenSSL and CDSA for
+ encryption, just as for GNU TLS.
+ - The SNMP backend sporatically reported some printers as
+ "unknown" (STR #1774)
+ - The scheduler now forces BrowseTimeout to be at least
+ twice the BrowseInterval value and non-zero to avoid
+ common configuration errors.
+ - The scheduler incorrectly returned printer URIs of the
+ form "ipp://server/printers/classname" for classes (STR
+ #1813)
+ - Updated Japanese localization (STR #1805)
+ - The scheduler's SSL certificate/key directory was not
+ created on installation (STR #1788)
+ - Added a mailto.conf man page and help page (STR #1754)
+ - The parallel and USB backends no longer wait for the
+ printer to go on-line - this caused problems with
+ certain printers that don't follow with the IEEE-1284
+ standard (STR #1738)
+ - The scheduler could crash on a reload when implicit
+ classes were present (STR #1828)
+ - The IPP backend incorrectly used the CUPS_ENCRYPTION
+ environment variable to determine the default
+ encryption mode when printing (STR #1820)
+ - USB printing did not work on Solaris (STR #1756)
+ - The scheduler sorted job priorities in the wrong order
+ (STR #1811)
+ - The scheduler did not automatically restart notifiers
+ that exited or crashed (STR #1793)
+ - IPv6 support did not work on NetBSD (STR #1834)
+ - The EPM packaging file did not work (STR #1804)
+ - The scheduler used up the CPU if BrowseRemoteProtocols
+ was empty (STR #1792)
+ - Custom page sizes did not work (STR #1787)
+ - The SNMP backend could crash on some systems when SNMP
+ logging was enabled (STR #1789)
+ - Browsing could produce some funny printer names when
+ ServerName was set to an IP address (STR #1799)
+ - Fixed the log message for BrowseRelay (STR #1798)
+ - Fixes to allow CUPS to compile on MirBSD (STR #1796)
+ - The scheduler incorrectly set the FINAL_CONTENT_TYPE
+ environment variable (STR #1795)
+ - The pdftops filter incorrectly embedded a "produced by"
+ comment, causing PDF printing not to work on some
+ operating systems (STR #1801)
+ - Sending raw jobs from a client system could cause the
+ client's scheduler to eventually crash (STR #1786)
+ - The scheduler now checks that the notifier exists prior
+ to accepting a new subscription request.
+ - The scheduler now reports the supported
+ notify-recipient schemes based on the contents of the
+ ServerBin/notifier directory.
+ - Event notifications did not include the
+ notify-sequence-number or other required attributes
+ (STR #1747)
+ - Allow/Deny addresses of the form "11.22.33.*" did not
+ work on Linux (STR #1769)
+ - cupsGetPPD() did not work if the scheduler was only
+ listening on a domain socket (STR #1766)
+ - The scheduler could crash advertising a class (STR
+ #1768)
+ - The scheduler could crash if the default printer was
+ deleted (STR #1776)
+ - Added a new default CUPS raster format (v3) which does
+ not compress the raster stream in order to provide the
+ same cupsRasterReadPixels() and cupsRasterWritePixels()
+ performance as CUPS 1.1.x.
+ - The cupsaddsmb man page listed the wrong files for the
+ CUPS driver.
+ - Some configure --with options did not work (STR #1746)
+ - "Allow @IF(name)" didn't work if "name" wasn't the
+ first network interface (STR #1758)
+ - The lpstat command did not use the correct character
+ set when reporting the date and time (STR #1751)
+ - The cupsaddsmb command and web interface did not update
+ the Windows PPD files properly, resulting in corrupt
+ PPD files for the Windows client to use (STR #1750)
+ - The cupsd.conf man page didn't describe the Listen
+ domain socket syntax (STR #1753)
+ - The scheduler no longer tries to support more than
+ FD_SETSIZE file descriptors.
+ - CDSA (encryption) support fixes for MacOS X.
+ - The lppasswd program needs to be setuid to root to
+ create and update the /etc/cups/passwd.md5 file (STR
+ #1735)
+ - 32/64-bit library installation was broken (STR #1741)
+ - The USB backend now reports a "no such device" error
+ when using the old filename-based USB URIs instead of
+ the "success" error.
+ - Increased the HTTP and IPP read timeouts to 10 seconds,
+ as 1 second was too short on congested networks (STR
+ #1719)
+ - The SNMP backend now uses the device description over
+ the printer-make-and-model attribute when the attribute
+ contains a generic name (STR #1728)
+ - Fixed another file descriptor leak when printing raw
+ files (STR #1736)
+ - Raw queues were not shared via LDAP (STR #1739)
+ - The pstops filter didn't always embed PageSetup
+ commands from the PPD file (STR #1740)
+ - "make install" didn't work if you disabled all of the
+ localizations.
+ - The scheduler didn't always choose the least costly
+ filter.
+ - Fixed parsing of IPv6 addresses in Allow, Deny,
+ BrowseAllow, BrowseDeny, and BrowseRelay directives
+ (STR #1713)
+ - Printers that were shared via LDAP did not get added to
+ the LDAP server properly (STR #1733)
+ - LDAP browsing would crash the scheduler if a required
+ value was missing (STR #1731)
+ - Special cases for the "localhost" hostname did not
+ work, causing printing to not work when the /etc/hosts
+ file did not contain a localhost entry (STR #1723)
+ - Updated the Spanish translation (STR #1720, STR #1770)
+ - Reverse-order page output was broken when N-up or
+ landscape orientations were used (STR #1725)
+ - The parallel, serial, socket, and USB backends needed
+ print data before they would report back-channel data,
+ causing problems with several new drivers (STR #1724)
+
+
+CHANGES IN CUPS V1.2.1
+
+ - "lprm -h hostname" did not work (STR #1800)
+ - The web interface did not handle reloads properly for
+ MSIE (STR #1716)
+ - The configure script no longer adds linker rpath
+ options when they are unnecessary.
+ - The scheduler could crash printing a debug message on
+ Solaris (STR #1714)
+ - The --enable-32bit and --enable-64bit configure options
+ did not always work.
+ - The password prompt showed the domain socket address
+ instead of "localhost" for local authentication (STR
+ #1706)
+ - The web interface filtered the list of printers even if
+ the user wasn't logged in (STR #1700)
+ - The IPP backend did not work reliably with some Xerox
+ printers (STR #1704)
+ - Trailing banners were not added when printing a single
+ file (STR #1698)
+ - The web interface support programs crashed on Solaris
+ (STR #1699)
+ - cupstestppd incorrectly reported problems with
+ *1284DeviceID attributes (STR #1710)
+ - Browsing could get disabled after a restart (STR #1670)
+ - Custom page sizes were not parsed properly (STR #1709)
+ - The -U option wasn't supported by lpadmin (STR #1702)
+ - The -u option didn't work with lpadmin (STR #1703)
+ - The scheduler did not create non-blocking back-channel
+ pipes, which caused problems when the printer driver
+ did not read the back-channel data (STR #1705)
+ - The scheduler no longer uses chunking in responses to
+ clients - this caused problems with older versions of
+ CUPS like 1.1.17 (PR #6143)
+ - Automatic raw printing was broken (STR #1667)
+ - 6-up printing was broken (STR #1697)
+ - The pstops filter did not disable CTRL-D processing on
+ the printer/RIP.
+ - ppdOpen*() did not load custom options properly (STR
+ #1680)
+ - "Set Printer Options" in the web interface did not
+ update the DefaultImageableArea or
+ DefaultPaperDimension attributes in the PPD file (STR
+ #1689)
+ - Fixed compile errors (STR #1682, STR #1684, STR #1685,
+ STR #1690)
+ - The lpstat command displayed the wrong error message
+ for a missing destination (STR #1683)
+ - Revised and completed the Polish translation (STR
+ #1669)
+ - Stopped jobs did not show up in the list of active jobs
+ (STR #1676)
+ - The configure script did not use the GNU TLS
+ "libgnutls-config" script to find the proper compiler
+ and linker options.
+ - The imagetoraster filter did not correctly generate
+ several 1, 2, and 4-bit color modes.
+ - cupsRasterWritePixels() could lose track of the current
+ output row.
+ - cupsRasterReadPixels() did not automatically swap
+ 12/16-bit chunked pixel data.
+ - Moved the private _cups_raster_s structure out of the
+ public header.
+ - Updated the CUPS raster format specification to include
+ encoding rules and colorspace definitions.
+ - The Zebra PPD files had the wrong PostScript code for
+ the "default" option choices.
+ - The imagetoraster filter did not generate correct CIE
+ XYZ or Lab color data.
+ - The cups-config script did not work when invoked from a
+ source directory (STR #1673)
+ - The SNMP backend did not compile on systems that used
+ the getifaddrs emulation functions (STR #1668)
+
+
+CHANGES IN CUPS V1.2.0
+
+ - Documentation updates (STR #1618, STR #1620, STR #1622,
+ STR #1637)
+ - Static file copy buffers reduced from 64k to 32k to
+ work around bogus MallocDebug library assumptions (STR
+ #1660)
+ - The scheduler did not decode the backend exit code
+ properly (STR #1648)
+ - The MacOS X USB backend did not report the 1284 device ID,
+ nor did it fix device IDs returned by HP printers.
+ - The scheduler started more slowly than 1.1.x with large
+ numbers of printers (STR #1653)
+ - cupsRasterInterpretPPD() didn't support the
+ cupsPreferredBitsPerColor attribute, and imagetoraster
+ didn't use the new API.
+ - The "make test" script did not create all of the necessary
+ subdirectories for testing (STR #1638)
+ - The scheduler did not prevent rotation of logs
+ redirected to /dev/null (STR #1651)
+ - "make test" did not include the SNMP backend in the
+ test environment (STR #1625)
+ - The EPM packaging files did not work (STR #1621)
+ - "Use Default Configuration" inserted a broken
+ configuration file (STR #1624)
+ - Redirects in the web interface did not always preserve
+ the encrypted status of a connection (STR #1603)
+ - Added the Apple "pap" backend.
+ - Added CUPS library to CUPS Image shared library
+ linkage to support Linux --as-needed linker option
+ (STR #1606)
+ - Fixed support for --enable-pie (STR #1609)
+ - The pdftops filter did not validate the length of the
+ encryption key (STR #1608)
+ - Updated the Polish localization.
+ - "Encryption Required" in the cupsd.conf file now only
+ requires encryption when the connection is not over the
+ loopback interface or domain socket.
+ - Printer names containing "+" were not quoted properly in
+ the web interface (STR #1600)
+ - The SNMP backend now reports the make and model in the
+ information string so that the auto-generated printer
+ name is more useful than just an IP address.
+
+
+CHANGES IN CUPS V1.2rc3
+
+ - The cups-lpd program always did reverse lookups on the
+ client address, which could be a performance problem.
+ Added a "-n" option to disable lookups.
+ - When configured with SSL support, require encryption by
+ default when displaying the /admin location (STR #1592)
+ - The next job ID was not computed correctly if the job
+ cache file got out of sync with the spool directory
+ (STR #1582)
+ - The PNG image handling code used deprecated functions
+ from libpng (STR #1587)
+ - Added a Polish translation (STR #1584, STR #1586)
+ - More changes to the scheduler to improve battery life
+ on portable devices (STR #1583)
+ - Changed the default log level for status messages back
+ to "DEBUG" to be consistent with CUPS 1.1.x (STR #1579)
+ - The error string was not set properly when
+ cupsDoFileRequest() was given the name of a directory
+ (STR #1578)
+ - Fixed handling of job-hold-until (STR #1581)
+ - Added explicit notes to the cupsaddsmb man page
+ explaining that the driver filenames are case-sensitive
+ under UNIX and that they must be all lowercase (Windows
+ 2000) or all UPPERCASE (Windows 95/98/Me) to work (STR
+ #1568)
+ - The USB backend incorrectly split the manufacturer name
+ if it contained spaces (STR #1566)
+ - The scheduler would hang when listing PPD files for a
+ manufacturer whose name contained spaces (STR #1567)
+ - Added the SNMP backend for network printer discovery
+ (STR #1555)
+ - cupstestppd now fails PPD files with 1284DeviceId
+ instead of 1284DeviceID, and cups-driverd uses a
+ case-insensitive comparison when looking for it (STR
+ #1573)
+ - cupsDoFileRequest() and cupsDoRequest() now work
+ properly with non-blocking HTTP connections.
+ - Added Swedish translation (STR #1569)
+ - "make install" now installs the MIME files with world
+ read permissions (STR #1565)
+ - More CDSA encryption support fixes (STR #1563)
+ - Updated the default mime.types file to support printing
+ of files that do not have a locally-recognized MIME
+ media type to raw or System V queues.
+ - Updated the serial port detection code on Linux (STR
+ #1562)
+ - Added some more error checking to httpGetHostname()
+ (STR #1561)
+ - The title of some administration pages was not
+ localized (STR #1548)
+ - The edit-config.tmpl file was not generated or
+ installed for the Spanish or Japanese localizations
+ (STR #1547)
+ - The mimeDelete() function freed the types before the
+ filters, but the filters needed the type data (STR #1558)
+ - The scheduler didn't keep track of the status pipes
+ properly, leading to a bad select() for multi-file jobs
+ (STR #1559)
+ - The cupstestdsc program didn't validate the ordinal
+ page number value for %%Page: comments.
+
+
+CHANGES IN CUPS V1.2rc2
+
+ - The scheduler was not always using the string pool,
+ causing random crashes.
+ - The lpmove and the web interface's Move Job button did
+ not work with stopped jobs (STR #1534)
+ - The PostScript filter did not handle the page-set
+ option properly with number-up printing (STR #1543)
+ - The scheduler now only warns about unsupported ACLs
+ once (STR #1532)
+ - The "fitplot" option did not work with output from
+ Mozilla (STR #1542)
+ - The imagetops filter did not work with Level 2 or 3
+ printers (STR #1533)
+ - The scheduler now recognizes PostScript files with PJL
+ commands that do not include an ENTER LANGUAGE command.
+ - Added --with-printcap configure option.
+ - 64-bit SSL fixes for MacOS X.
+ - The scheduler didn't send some printer state change
+ events.
+ - The scheduler didn't send jobs to busy remote printers.
+ - Fixed some problems with the launchd support.
+ - Added new USB printer backend for MacOS X.
+ - The PostScript filter now handles files that start with
+ an incomplete PJL header (PR #6076)
+ - The web interface language selection code did not try
+ the generic language localization (STR #1531)
+ - The language cache, string pool, and transcoding caches
+ are now process global instead of per-thread to avoid
+ problems with GNOME and to allow for data sharing
+ between threads (STR #1530)
+ - Fixed a CUPS 1.1.x compatibility bug (STR #1528)
+ - The web interface redirection after certain printer
+ administration tasks was broken (STR #1516)
+ - Web interface authorization could get stuck (STR #1512)
+ - Localization updates (STR #1513, STR #1518, STR #1520)
+ - The pstops filter didn't work with some files (STR
+ #1523)
+ - "./configure --enable-static" didn't work (STR #1522)
+ - The scheduler was not using the configured default
+ Group (STR #1521)
+ - The web interface still did not show the localized time
+ and date for some locales and systems (STR #1509)
+ - httpAddrGetList() would crash on systems without
+ getaddrinfo().
+ - Socket URIs without a trailing slash would cause the
+ port number to not be accepted (STR #1519)
+ - Local raw and System V printers were not advertised as
+ such for printer browsing (STR #1502)
+ - The RPM spec file incorrectly put duplicate copies of
+ the Japanese and Spanish web interface templates in the
+ main cups package (STR #1517)
+ - cupsSetDests() did not explicitly set the permissions
+ of the /etc/cups/lpoptions file (STR #1508)
+ - The lpq command crashed with the -h option (STR #1515)
+
+
+CHANGES IN CUPS V1.2rc1
+
+ - Documentation updates (STR #1497, STR #1498)
+ - The scheduler now redirects browsers to https: URLs
+ when encryption is required.
+ - The scheduler would crash when printing with a banner
+ (STR #1500)
+ - cups-driverd did not use the LanguageEncoding attribute
+ in PPD files to convert the NickName to UTF-8 (STR
+ #1503)
+ - The lpadmin command could not set the
+ printer-error-policy attribute (STR #1504)
+ - The web interface did not show the time and date in the
+ correct format for the locale (STR #1505)
+ - CUPS no longer accepts print jobs if a printer does not
+ support the file format (STR #1501)
+ - Cleaned up the PostScript filter (pstops) so that it
+ properly supports %%IncludeFeature and page scaling
+ (STR #1453)
+ - Fixed the cupsFileRewind() and cupsFileSeek() functions
+ to work properly with uncompressed files.
+ - Added cupsFileGetLine(), cupsFileStderr(),
+ cupsFileStdin(), and cupsFileStdout() functions to the
+ CUPS library.
+ - Added a new cupstestdsc program to test the DSC
+ conformance of PostScript files.
+ - Added KDE/GNOME icons and a Manage Printers menu item.
+ - Added --enable-image and --enable-pdftops configure
+ options to control whether the image and PDF filters
+ are built and installed (default = yes for all
+ platforms but MacOS X)
+ - Fixed a minor memory leak in the PPD API.
+ - Fixed transcoding issues (STR #1493)
+ - The scheduler now enforces a minimum job cost of 100
+ when doing FilterLimit checks.
+ - The scheduler would leak file descriptors when printing
+ to raw queues (STR #1491)
+ - The IPv6 support did not compile on Tru64 UNIX (STR
+ #1488)
+ - ppdOpen2() now converts the NickName and all UI text to
+ UTF-8 (STR #1475)
+ - The Set Allowed Users web page did not work (STR #1486)
+ - When the default policy was not set or set to a non-
+ existing policy, the scheduler did not set the default
+ policy name to "default" (STR #1484)
+ - The Zebra CPCL driver did not use the correct righthand
+ margin for the 4" wide label sizes.
+ - Fixed a problem with the parsing of fractional real
+ numbers in PPD files.
+ - Added Spanish localization files (STR #1480)
+ - Fixed localization of a few scheduler messages (STR
+ #1478)
+ - Fixed support for HEAD requests in the scheduler (STR
+ #1481)
+
+
+CHANGES IN CUPS V1.2b2
+
+ - Updated the CUPS design description.
+ - Added --enable-32bit and --enable-64bit configure
+ options to allow building of separate 32/64-bit
+ libraries on systems that support both environments
+ (STR #1472)
+ - Various compiler warning fixes.
+ - Fixes for Solaris 10 builds against old GNU TLS and
+ LDAP libraries.
+ - Added a cupsArrayUserData() function to retrieve the
+ user data pointer for an array (useful for typing
+ arrays)
+ - The ppdEmitString() function did not compute the
+ required buffer size properly, leading to dropped
+ characters on the end of the printer commands in pstops
+ and imagetops (STR #1470)
+
+
+CHANGES IN CUPS V1.2b1
+
+ - The serial backend now supports Equinox 8-port serial
+ hubs (STR #526)
+ - The IPP backend now supports a compression option to
+ compress print files as they are sent to the remote
+ server (STR #956)
+ - The CUPS browse protocol now supports passing of
+ default options and browse timeout values from the
+ server to the clients (STR #800)
+ - Implicit classes that timed out could cause the
+ scheduler to crash (STR #1439)
+ - Added DragonFly support in local device backends (STR
+ #1362)
+ - Added LDAP printer browsing support (STR #338)
+ - Added official support for printer maintenance commands
+ via the CUPS Command file format and hooks in the
+ printer-type and web interfaces (STR #932)
+ - The HP-GL/2 filter could get in an infinite loop trying
+ to convert HP-PCL files (STR #1415)
+ - CUPS now implements the HTTP/1.1 Expect header (STR
+ #1407)
+ - Options in PPD files are no longer automatically put in
+ an "Extra" group; rather, all options that are not
+ inside an Open/CloseGroup will be placed in the
+ "General" group (STR #1385)
+ - The scheduler now creates a job-uuid attribute that
+ uniquely identifies a job on a network (STR #1410)
+ - The init script now unsets the TMPDIR environment
+ variable to prevent user temporary directories from
+ being used by cupsd accidentally (STR #1424)
+ - Added support for launchd on MacOS X.
+ - Added support for notify_post on MacOS X.
+ - Added support for DBUS on Linux.
+ - All of the Berkeley (except for lpc) and System V
+ commands now support specification of user, host, and
+ port (STR #1028, STR #1029, STR #1087)
+ - The lpmove command now allows you to move all jobs for
+ a given queue (STR #56)
+ - The web interface now supports moving of a job or jobs
+ to another queue (STR #56)
+ - 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 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/CHANGES-1.3.txt b/CHANGES-1.3.txt
new file mode 100644
index 000000000..9af534f9b
--- /dev/null
+++ b/CHANGES-1.3.txt
@@ -0,0 +1,856 @@
+CHANGES-1.3.txt
+---------------
+
+CHANGES IN CUPS V1.3.11
+
+ - The scheduler did not prevent nested classes (STR #3211)
+ - The scheduler did not reprint processing jobs that were moved to
+ another destination (STR #3222)
+ - The scheduler did not reset the current job file when stopping a
+ printer (STR #3226)
+ - The scheduler did not handle POSTs to custom CGIs properly (STR #3221)
+ - The pdftops filter did not print landscape PDF pages properly
+ (STR #2881)
+ - The scheduler did not handle partial header lines properly from CGI
+ programs (STR #3194)
+ - The web interface could hang on OpenBSD (STR #3176, STR #3196)
+ - The scheduler and cupsfilter utility did not handle rules starting
+ with a negation operator properly (STR #3160)
+ - The scheduler and cupsfilter utility would crash with certain MIME
+ .types rules (STR #3159)
+ - httpSetField wasn't bracketing IPv6 numeric addresses for the Host:
+ field (STR #3164)
+ - The ServerName, if specified, was not treated as a valid alias for the
+ local system (STR #3167)
+ - "make epm" did not work (STR #3166)
+ - "lpstat -h server" showed non-shared printers (STR #3147)
+ - "make check" did not work on Linux (STR #3161)
+
+
+CHANGES IN CUPS V1.3.10
+
+ - Documentation fixes (STR #2994, STR #2995, STR #3008, STR #3056,
+ STR #3057)
+ - SECURITY: The scheduler now protects against DNS rebinding attacks
+ (STR #3118)
+ - SECURITY: Fixed TIFF integer overflow in image filters (STR #3031)
+ - The scheduler did not support the job-hold-until attribute with the
+ Restart-Job operation (STR #3130)
+ - SECURITY: The PNG image reading code did not validate the
+ image size properly, leading to a potential buffer overflow
+ (STR #2974)
+ - The rastertohp driver did not set the 1-sided printing mode when
+ needed (STR #3131)
+ - Now use a wrapper program instead of our fork of the Xpdf code to
+ support printing of PDF files. The new wrapper supports using Xpdf,
+ poppler, or Ghostscript to convert PDF files to PostScript (STR #3129)
+ - Long job names caused problems with some PJL printers (STR #3125)
+ - The lpq command did not work when showing all destinations (STR #3117)
+ - The scheduler used a codeset name of UTF8 which is not supported on
+ Solaris (STR #3113)
+ - cupsGetJobs() did not work with a NULL destination (STR #3107)
+ - Fixed a localization problem for option choices (incorrectly) named
+ "Custom" (STR #3106)
+ - The fallback OpenSSL random number seeding would not work (STR #3079)
+ - The scheduler might miss a child signal, causing high CPU usage.
+ - The scheduler did not enforce quotas after the job history was
+ unloaded (STR #3078)
+ - The job-k-limit, job-page-limit, and job-quota-period attributes
+ could not be set using the lpadmin command (STR #3077)
+ - httpSeparateURI() did not error out on URIs with a missing port
+ number after a colon.
+ - Fixed a Valgrind-detected initialization error when creating a
+ missing directory on startup.
+ - The scheduler did not always read all of the HTTP headers from a
+ CGI script/program.
+ - The scheduler did not always set the "air" property in Bonjour/DNS-SD
+ registrations.
+ - The scheduler incorrectly compared Mac OS X UUIDs for access
+ control, preventing access in certain configurations.
+ - The IPP backend incorrectly reset the required authentication
+ to Kerberos when authentication failed.
+ - The scheduler no longer looks up the local hostname by default;
+ turn on hostname lookups to restore the previous behavior.
+ - The scheduler did not always load MIME type rules correctly
+ (STR #3059)
+ - The test page did not format correctly on A4 paper (STR #3060)
+ - The web interface sometimes incorrectly redirected users to
+ 127.0.0.1 (STR #3022)
+ - cupsPrintFile*() did not send the document filename for single
+ file submissions (STR #3055)
+ - The scheduler did not update the member-names attribute when
+ removing the last printer from a class.
+ - The scheduler did not report PPD Products with parenthesis
+ in them properly (STR #3046)
+ - The wrong italic fonts were listed in the UTF-8 charset file
+ for the text filter.
+ - The backends did not return an OK status for the
+ CUPS_SC_CMD_GET_BIDI side-channel command (STR #3029)
+ - The scheduler did not purge jobs that were missing a
+ time-at-creation attribute, indicating a bad job control file
+ (STR #3030)
+ - The "-o job-hold-until=week-end" option did not work properly
+ (STR #3025)
+ - The Solaris USB printer device does not support select or poll
+ (STR #3028)
+ - The scheduler would crash if you exceeded the MaxSubscriptions
+ limit.
+ - The lp "-H immediate" option did not specify that the job
+ should not be held (STR #3013)
+ - The scheduler did not support the "Connection: close"
+ HTTP header (STR #3010)
+ - The mailto notifier didn't terminate messages properly
+ (STR #3011)
+ - Backends could spin trying to read back-channel data
+ (STR #3001)
+ - The HP-GL/2 filter was using the wrong default colors
+ (STR #2966)
+ - The scheduler incorrectly allowed Get-Jobs operations without a
+ printer-uri (STR #2996)
+ - The compression option was not being encoded properly
+ (STR #2997)
+ - Added a missing character map for JIS-X0213/ShiftJIS.
+ - The scheduler now rejects ATTR: messages with empty values.
+ - The scheduler could consume all CPU handling closed connections
+ (STR #2988)
+ - Fixed some configure script bugs with rc/xinetd directories
+ (STR #2970)
+ - The Epson sample driver PPDs contained errors (STR #2979)
+
+
+CHANGES IN CUPS V1.3.9
+
+ - SECURITY: The HP-GL/2 filter did not range check pen numbers
+ (STR #2911)
+ - SECURITY: The SGI image file reader did not range check
+ 16-bit run lengths (STR #2918)
+ - SECURITY: The text filter did not range check cpi, lpi, or
+ column values (STR #2919)
+ - Documentation updates (STR #2904, STR #2944)
+ - The French web admin page was never updated (STR #2963)
+ - The IPP backend did not retry print jobs when the printer
+ reported itself as busy or unavailable (STR #2951)
+ - The "Set Allowed Users" web interface did not handle trailing
+ whitespace correctly (STR #2956)
+ - The PostScript filter did not work with Adobe applications
+ using custom page sizes (STR #2968)
+ - The Mac OS X USB backend did not work with some printers
+ that reported a bad 1284 device ID.
+ - The scheduler incorrectly resolved the client connection
+ address when HostNameLookups was set to Off (STR #2946)
+ - The IPP backend incorrectly stopped the local queue if
+ the remote server reported the "paused" state.
+ - The cupsGetDests() function did not catch all types of
+ request errors.
+ - The scheduler did not always log "job queued" messages
+ (STR #2943)
+ - The scheduler did not support destination filtering using
+ the printer-location attribute properly (STR #2945)
+ - The scheduler did not send the server-started,
+ server-restarted, or server-stopped events (STR #2927)
+ - The scheduler no longer enforces configuration file
+ permissions on symlinked files (STR #2937)
+ - CUPS now reinitializes the DNS resolver on failures
+ (STR #2920)
+ - The CUPS desktop menu item was broken (STR #2924)
+ - The PPD parser was too strict about missing keyword
+ values in "relaxed" mode.
+ - The PostScript filter incorrectly mirrored landscape
+ documents.
+ - The scheduler did not correctly update the
+ auth-info-required value(s) if the AuthType was Default.
+ - The scheduler required Kerberos authentication for
+ all operations on remote Kerberized printers instead
+ of just for the operations that needed it.
+ - The socket backend could wait indefinitely for back-
+ channel data with some devices.
+ - PJL panel messages were not reset correctly on older
+ printers (STR #2909)
+ - cupsfilter used the wrong default path (STR #2908)
+ - Fixed address matching for "BrowseAddress @IF(name)"
+ (STR #2910)
+ - Fixed compiles on AIX.
+ - Firefox 3 did not work with the CUPS web interface in SSL
+ mode (STR #2892)
+ - Custom options with multiple parameters were not emitted
+ correctly.
+ - Refined the cupstestppd utility.
+ - ppdEmit*() did not support custom JCL options (STR #2889)
+ - The cupstestppd utility incorrectly reported missing
+ "en" base translations (STR #2887)
+
+
+CHANGES IN CUPS V1.3.8
+
+ - Documentation updates (STR #2785, STR #2861, STR #2862)
+ - The scheduler did not add the ending job sheet when the
+ job was released.
+ - The IPP backend did not relay marker-* attributes.
+ - The CUPS GNOME/KDE menu item was not localized for
+ Chinese (STR #2880)
+ - The CUPS GNOME/KDE menu item was not localized for
+ Japanese (STR #2876)
+ - The cupstestppd utility reported mixed line endings for
+ Mac OS and Windows PPD files (STR #2874)
+ - The pdftops filter did not print landscape orientation PDF
+ pages correctly on all printers (STR #2850)
+ - The scheduler did not handle expiring of implicit classes
+ or their members properly, leading to a configuration where
+ one of the members would have a short name (STR #2766)
+ - The scheduler and cupstestppd utilities did not support
+ cupsFilter and cupsPreFilter programs with spaces in their
+ names (STR #2866)
+ - Removed unused variables and assignments found by the
+ LLVM "clang" tool.
+ - Added NULL checks recommended by the LLVM "clang" tool.
+ - The scheduler would crash if you started a printer that
+ pointed to a backend that did not exist (STR #2865)
+ - The ppdLocalize functions incorrectly mapped all generic
+ locales to country-specific locales.
+ - The cups-driverd program did not support Simplified Chinese
+ or Traditional Chinese language version strings (STR #2851)
+ - Added an Indonesian translation (STR #2792)
+ - Fixed a timing issue in the backends that could cause data
+ corruption with the CUPS_SC_CMD_DRAIN_OUTPUT side-channel
+ command (STR #2858)
+ - The scheduler did not support "HostNameLookups" with all of
+ the boolean names (STR #2861)
+ - Fixed a compile problem with glibc 2.8 (STR #2860)
+ - The scheduler incorrectly filtered out queues with ACLs and
+ authentication.
+ - The PostScript filter did not support %%IncludeFeature lines
+ in the page setup section of each page (STR #2831)
+ - The scheduler did not generate printer-state events when the
+ default printer was changed (STR #2764)
+ - cupstestppd incorrectly reported a warning about the PPD format
+ version in some locales (STR #2854)
+ - cupsGetPPD() and friends incorrectly returned a PPD file for
+ a class with no printers.
+ - The member-uris values for local printers in a class returned
+ by the scheduler did not reflect the connected hostname or
+ port.
+ - The CUPS PHP extension was not thread-safe (STR #2828)
+ - The scheduler incorrectly added the document-format-default
+ attribute to the list of "common" printer attributes, which
+ over time would slow down the printing system (STR #2755,
+ STR #2836)
+ - The cups-deviced and cups-driverd helper programs did not set
+ the CFProcessPath environment variable on Mac OS X (STR #2837)
+ - "lpstat -p" could report the wrong job as printing (STR #2845)
+ - The scheduler would crash when some cupsd.conf directives
+ were missing values (STR #2849)
+ - The web interface "move jobs" operation redirected users to
+ the wrong URL (STR #2815)
+ - The Polish web interface translation contained errors
+ (STR #2815)
+ - The scheduler did not report PostScript printer PPDs with
+ filters as PostScript devices.
+ - The scheduler did not set the job document-format attribute
+ for jobs submitted using Create-Job and Send-Document.
+ - cupsFileTell() did not work for log files opened in append
+ mode (STR #2810)
+ - The scheduler did not set QUERY_STRING all of the time
+ for CGI scripts (STR #2781, STR #2816)
+ - The scheduler now returns an error for bad job-sheets
+ values (STR #2775)
+ - Authenticated remote printing did not work over domain
+ sockets (STR #2750)
+ - The scheduler incorrectly logged errors for print filters
+ when a job was canceled (STR #2806, #2808)
+ - The scheduler no longer allows multiple RSS subscriptions
+ with the same URI (STR #2789)
+ - The scheduler now supports Kerberized printing with
+ multiple server names (STR #2783)
+ - "Satisfy any" did not work in IPP policies (STR #2782)
+ - The CUPS imaging library would crash with very large
+ images - more than 16Mx16M pixels (STR #2805)
+ - The PNG image loading code would crash with large images
+ (STR #2790)
+ - The scheduler did not limit the total number of filters.
+ - The scheduler now ensures that the RSS directory has
+ the correct permissions.
+ - The RSS notifier did not quote the feed URL in the RSS
+ file it created (STR #2801)
+ - The web interface allowed the creation and cancellation
+ of RSS subscriptions without a username (STR #2774)
+ - Increased the default MaxCopies value on Mac OS X to
+ 9999 to match the limit imposed by the print dialog.
+ - The scheduler did not reject requests with an empty
+ Content-Length field (STR #2787)
+ - The scheduler did not log the current date and time and
+ did not escape special characters in request URIs when
+ logging bad requests to the access_log file (STR #2788)
+
+
+CHANGES IN CUPS V1.3.7
+
+ - CVE-2008-0047: cgiCompileSearch buffer overflow (STR #2729)
+ - CVE-2008-1373: CUPS GIF image filter overflow (STR #2765)
+ - Updated the "make check" tests to do a more thorough
+ automated test.
+ - cups-driverd complained about missing directories (STR
+ #2777)
+ - cupsaddsmb would leave the Samba username and password on
+ disk if no Windows drivers were installed (STR #2779)
+ - The Linux USB backend used 100% CPU when a printer was
+ disconnected (STR #2769)
+ - The sample raster drivers did not properly handle SIGTERM
+ (STR #2770)
+ - The scheduler sent notify_post() messages too often on
+ Mac OS X.
+ - Kerberos access to the web interface did not work
+ (STR #2748)
+ - The scheduler did not support "AuthType Default" in IPP
+ policies (STR #2749)
+ - The scheduler did not support the "HideImplicitMembers"
+ directive as documented (STR #2760)
+ - "make check" didn't return a non-zero exit code on
+ error (STR #2758)
+ - The scheduler incorrectly logged AUTH_foo environment
+ variables in debug mode (STR #2751)
+ - The image filters inverted PBM files (STR #2746)
+ - cupsctl would crash if the scheduler was not running
+ (STR #2741)
+ - The scheduler could crash when printing using a port
+ monitor (STR #2742)
+ - The scheduler would crash if PAM was broken (STR #2734)
+ - The image filters did not work with some CMYK JPEG files
+ produced by Adobe applications (STR #2727)
+ - The Mac OS X USB backend did not work with printers that
+ did not report a make or model.
+ - The job-sheets option was not encoded properly (STR #2715)
+ - The scheduler incorrectly complained about missing LSB
+ PPD directories.
+
+
+CHANGES IN CUPS V1.3.6
+
+ - Documentation updates (STR #2646, STR #2647, STR #2649)
+ - Fixed a problem with the web interface "Use Kerberos
+ Authentication" check box (STR #2703)
+ - The scheduler unconditionally overwrote the printer-state-
+ message with "process-name failed" when a filter or backend
+ failed, preventing a useful error message from being shown
+ to the user.
+ - Policies on CUPS-Move-Job didn't work as expected (STR
+ #2699)
+ - The configure script only supported D-BUS on Linux
+ (STR #2702)
+ - The scheduler did not support </LimitExcept> (STR #2701)
+ - The scheduler did not reset the job-hold-until attribute
+ after a job's hold time was reached.
+ - The scheduler did not support printer supply attributes
+ (STR #1307)
+ - The Kerberos credentials provided by some Windows KDCs
+ were still too large - now use a dynamic buffer to
+ support credentials up to 64k in size (STR #2695)
+ - Printing a test page from the web interface incorrectly
+ defaulted to the "guest" user (STR #2688)
+ - The cupsEncodeOptions2() function did not parse multiple-
+ value attribute values properly (STR #2690)
+ - The scheduler incorrectly sent printer-stopped events for
+ status updates from the print filters (STR #2680)
+ - The IPP backend could crash when handling printer errors
+ (STR #2667)
+ - Multi-file jobs did not print to remote CUPS servers
+ (STR #2673)
+ - The scheduler did not provide the Apple language ID to
+ job filters.
+ - Kerberos authentication did not work with the web
+ interface (STR #2606, STR #2669)
+ - The requesing-user-name-allowed and -denied functionality
+ did not work for Kerberos-authenticated usernames (STR
+ #2670)
+ - CUPS didn't compile on HP-UX 11i (STR #2679)
+ - cupsEncodeOptions2() did not handle option values like
+ "What's up, doc?" properly.
+ - Added lots of memory allocation checks (Fortify)
+ - The scheduler would crash if it was unable to add a job
+ file (Fortify)
+ - ppdOpen*() did not check all memory allocations (Coverity)
+ - ippReadIO() did not check all memory allocations (Coverity)
+ - The PostScript filter did not detect read errors (Coverity)
+ - The scheduler did not check for a missing job-sheets-completed
+ attribute when sending an event notification (Coverity)
+ - "Set Printer Options" might not work with raw queues (Coverity)
+ - cupsRasterInterpretPPD() could crash on certain PostScript
+ errors (Coverity)
+ - The USB backend did not check for back-channel support
+ properly on all systems (Coverity)
+ - Fixed memory leaks in the GIF and PNM image loading code
+ (Coverity)
+ - Removed some dead code in the CUPS API and scheduler (Coverity)
+ - Fixed two overflow bugs in the HP-GL/2 filter (Coverity)
+ - Fixed another ASN1 string parsing bug (STR #2665)
+ - The RSS notifier directory was not installed with the
+ correct permissions.
+ - The standard CUPS backends could use 100% CPU while waiting
+ for print data (STR #2664)
+ - Filename-based MIME rules did not work (STR #2659)
+ - The cups-polld program did not exit if the scheduler crashed
+ (STR #2640)
+ - The scheduler would crash if you tried to set the port-monitor
+ on a raw queue (STR #2639)
+ - The scheduler could crash if a polled remote printer was
+ converted to a class (STR #2656)
+ - The web interface and cupsctl did not correctly reflect
+ the "allow printing from the Internet" state (STR #2650)
+ - The scheduler incorrectly treated MIME types as case-
+ sensitive (STR #2657)
+ - The Java support classes did not send UTF-8 strings to
+ the scheduler (STR #2651)
+ - The CGI code did not handle interrupted POST requests
+ properly (STR #2652)
+ - The PostScript filter incorrectly handled number-up when
+ the number of pages was evenly divisible by the number-up
+ value.
+ - The PDF filter incorrectly filtered pages when page-ranges
+ and number-up were both specified (STR #2643)
+ - The IPP backend did not handle printing of pictwps files
+ to a non-Mac CUPS server properly.
+ - The scheduler did not detect network interface changes
+ on operating systems other than Mac OS X (STR #2631)
+ - The scheduler now logs the UNIX error message when it
+ is unable to create a request file such as a print job.
+ - Added support for --enable-pie on Mac OS X.
+
+
+CHANGES IN CUPS V1.3.5
+
+ - The SNMP backend did not check for negative string
+ lengths (STR #2589)
+ - The scheduler incorrectly removed auth-info attributes,
+ potentially leading to a loss of all options for a job.
+ - The scheduler stopped sending CUPS browse packets on a
+ restart when using fixed addresses (STR #2618)
+ - Fixed PDF filter security issues (CVE-2007-4352
+ CVE-2007-5392 CVE-2007-5393)
+ - Changing settings would always change the DefaultAuthType
+ and Allow lines (STR #2580)
+ - The scheduler would crash when submitting an undefined
+ format file from Samba with LogLevel debug2 (STR #2600)
+ - The scheduler did not use poll() when epoll() was not
+ supported by the running kernel (STR #2582)
+ - Fixed a compile problem with Heimdal Kerberos (STR #2592)
+ - The USB backend now retries connections to a printer
+ indefinitely rather than stopping the queue.
+ - Printers with untranslated JCL options were not exported
+ to Samba correctly (STR #2570)
+ - The USB backend did not work with some Minolta USB
+ printers (STR #2604)
+ - The strcasecmp() emulation code did not compile (STR
+ #2612)
+ - The scheduler would crash if a job was sent to an empty
+ class (STR #2605)
+ - The lpc command did not work in non-UTF-8 locales (STR
+ #2595)
+ - Subscriptions for printer-stopped events also received
+ other state changes (STR #2572)
+ - cupstestppd incorrectly reported translation errors for
+ the "en" locale.
+ - ppdOpen() did not handle custom options properly when the
+ Custom attribute appeared before the OpenUI for that
+ option.
+ - The scheduler could crash when deleting a printer or
+ listing old jobs.
+ - The Mac OS X USB backend did not allow for requeuing of
+ jobs submitted to a class.
+ - lpmove didn't accept a job ID by itself.
+ - The scheduler incorrectly removed job history information
+ for remote print jobs.
+ - The scheduler incorrectly sent the
+ "com.apple.printerListChanged" message for printer state
+ changes.
+ - The PostScript filter drew the page borders (when enabled)
+ outside the imageable area.
+ - The LPD and IPP backends did not default to the correct
+ port numbers when using alternate scheme names.
+ - The scheduler incorrectly deleted hardwired remote
+ printers on system sleep.
+ - The scheduler would abort if a bad browse protocol name
+ was listed in the cupsd.conf file.
+ - The online cupsd.conf help file incorrectly showed
+ "dns-sd" instead of "dnssd" for Bonjour sharing.
+ - The scheduler could crash changing the port-monitor value.
+ - The scheduler generated CoreFoundation errors when run as
+ a background process.
+ - When printing with number-up > 1, it was possible to get
+ an extra blank page.
+
+
+CHANGES IN CUPS V1.3.4
+
+ - Documentation updates (STR #2560, STR #2563, STR #2569)
+ - CUPS now maps the "nb" locale to "no" on all platforms
+ (STR #2575)
+ - CUPS did not work with a Windows 2003 R2 KDC (STR #2568)
+ - ippReadIO() could read past the end of a buffer (STR
+ #2561)
+ - The scheduler would crash on shutdown if it was unable
+ to create a Kerberos context.
+ - Multiple AuthTypes in cupsd.conf did not work (STR
+ #2545)
+ - The snmp.conf file referenced the wrong man page (STR
+ #2564)
+ - The cupsaddsmb program didn't handle domain sockets
+ properly (STR #2556)
+ - The scheduler now validates device URIs when adding
+ printers.
+ - Updated httpSeparateURI() to support hostnames with
+ the backslash character.
+ - Updated the Japanese localization (STR #2546)
+ - The parallel backend now gets the current IEEE-1284
+ device ID string on Linux (STR #2553)
+ - The IPP backend now checks the job status at
+ variable intervals (from 1 to 10 seconds) instead
+ of every 10 seconds for faster remote printing
+ (STR #2548)
+ - "lpr -p" and "lpr -l" did not work (STR #2544)
+ - Compilation failed when a previous version of CUPS
+ was installed and was included in the SSL include
+ path (STR #2538)
+ - The scheduler did not reject requests with charsets
+ other than US-ASCII or UTF-8, and the CUPS API
+ incorrectly passed the locale charset to the scheduler
+ instead of UTF-8 (STR #2537)
+ - cups-deviced did not filter out duplicate devices.
+ - The AppleTalk backend incorrectly added a scheme
+ listing when AppleTalk was disabled or no printers
+ were found.
+ - The PostScript filter generated N^2 copies when the
+ printer supported collated copies and user requested
+ reverse-order output.
+ - The scheduler did not reprint all of the files in a
+ job that was held.
+ - The scheduler did not update the printcap file after
+ removing stale remote queues.
+ - The cupsd.conf man page incorrectly referenced
+ "AuthType Kerberos" instead of "AuthType Negotiate".
+
+
+CHANGES IN CUPS V1.3.3
+
+ - The scheduler did not use the attributes-natural-language
+ attribute when passing the LANG environment variable to
+ cups-deviced or cups-driverd.
+ - The scheduler did not use the printer-op-policy when
+ modifying classes or printers (STR #2525)
+ - The auth-info-required attribute was not always updated
+ for remote queues that required authentication.
+ - The German web interface localization contained errors
+ (STR #2523)
+ - The Swedish localization contained errors (STR #2522)
+
+
+CHANGES IN CUPS V1.3.2
+
+ - The 1.3.1 release was incorrectly created from the
+ 1.4.x source tree (STR #2519)
+ - Added support for 32/64-bit libraries on HP-UX
+ (STR #2520)
+ - The scheduler incorrectly used portrait as the default
+ orientation (STR #2513)
+ - The scheduler no longer writes the printcap file for
+ every remote printer update (STR #2512)
+ - Remote raw printing with multiple copies did not work
+ (STR #2518)
+ - Updated the configure script to require at least autoconf
+ 2.60 (STR #2515)
+ - Some gzip'd PPD files were not read in their entirety
+ (STR #2510)
+
+
+CHANGES IN CUPS V1.3.1
+
+ - Documentation updates.
+ - The USB backend on Mac OS X could hang if the driver and
+ printer did not match.
+ - Delegated Kerberos credentials were not working.
+ - "make distclean" incorrectly removed the edit-config.tmpl
+ files (STR #2508)
+ - Fix compile problem on HP-UX (STR #2501)
+ - The cupstestppd utility now tests for resolutions greater
+ than 99999 DPI to detect a missing "x" between the X and Y
+ resolutions.
+ - Fixed many problems in the various translations and added
+ a new "checkpo" utility to validate them.
+ - The cupstestppd utility now tests the custom page size code
+ for CUPS raster drivers.
+ - cupsLangDefault() did not attempt to return a language that
+ was supported by the calling application.
+ - If a remote printer stopped while a job was being sent, the
+ local queue would also get stopped and the job re-queued,
+ resulting in duplicate prints in some cases.
+ - A few Apple-specific job options needed to be omitted when
+ printing a banner page.
+ - The new peer credential support did not compile on FreeBSD
+ (STR #2495)
+ - Direct links to help files did not set the current section
+ so the table-of-contents was not shown.
+ - The configure script did not support --localedir=foo (STR #2488)
+ - The backends were not displaying their localized messages.
+ - CUPS-Authenticate-Job did not require Kerberos authentication
+ on queues protected by Kerberos.
+ - The Zebra ZPL driver did not work with Brady label printers
+ (STR #2487)
+ - Norwegian wasn't localized on Mac OS X.
+ - getnameinfo() returns an error on some systems when DNS is
+ not available, leading to numerous problems (STR #2486)
+ - The cupsfilter command did not work properly on Mac OS X.
+ - The scheduler makefile contained a typo (STR #2483)
+ - The TBCP and BCP port monitors did not handle the trailing
+ CTRL-D in some PostScript output properly.
+ - Fixed the localization instructions and German template for
+ the "Find New Printers" button (STR #2478)
+ - The web interface did not work with the Chinese localization
+ (STR #2477)
+ - The web interface home page did not work for languages that
+ were only partially localized (STR #2472)
+ - Updated the Spanish web interface localization (STR #2473)
+ - ppdLocalize() did not work for country-specific localizations.
+
+
+CHANGES IN CUPS V1.3.0
+
+ - The scheduler did not handle out-of-file conditions
+ gracefully when accepting new connections, leading to
+ heavy CPU usage.
+ - The scheduler did not detect ServerBin misconfigurations
+ (STR #2470)
+ - "AuthType Default" did not work as expected when the
+ "DefaultAuthType foo" line appeared after it in the
+ cupsd.conf file.
+ - The on-line help did not describe many common printing
+ options (STR #1846)
+ - The IPP backend did not return the "auth required" status
+ when printing to a Kerberos-protected queue.
+ - The scheduler was not looking in the correct directories
+ for LSB PPD files (STR #2464)
+ - Changed references to ESP Ghostscript to GPL Ghostscript
+ (STR #2463)
+ - The PostScript filter did not cleanly terminate when
+ the job was canceled or stopped.
+ - Fixed generation of Kerberos credentials for remote
+ printing. Note that this requires a recent version of
+ MIT Kerberos with a working krb5_cc_new_unique()
+ function or Heimdal Kerberos.
+ - Added Portuguese and updated Italian message catalogs.
+
+
+CHANGES IN CUPS V1.3rc2
+
+ - Added more range checking to the pdftops filter.
+ - The scheduler would crash if a remote IPP queue was stopped
+ (STR #2460)
+ - The scheduler did not allow "DefaultAuthType None".
+
+
+CHANGES IN CUPS V1.3rc1
+
+ - Updated the German localization (STR #2443)
+ - cupsAdminGetServerSettings() did not handle </Foo> properly.
+ - When lprm and cancel are run with no job ID, they now will
+ cancel the first stopped job if no pending or processing
+ jobs are left in the queue.
+ - The scheduler now logs successful print jobs, filter
+ failures, and the job file types at the default log
+ level (STR #2458)
+ - The scheduler now logs the usernames it is using for
+ authorization at LogLevel debug instead of debug2 (STR #2448)
+ - Added Intellitech Intellibar and Zebra CPCL PPDs to the list
+ of installed PPDs.
+ - Added 6" and 8" wide label sizes for the Zebra ZPL Label
+ Printer driver (STR #2442)
+ - The cupsaddsmb program and web interface now support
+ exporting of 64-bit Windows drivers, when available
+ (STR #2439)
+ - Moving a job that was printing did not stop the job on the
+ original printer (STR #2262)
+ - The cups-lpd mini-daemon did not work on Mac OS X server.
+ - Added httpGetAuthString() and httpSetAuthString() APIs to get
+ and set the current (cached) authorization string to use for
+ HTTP requests.
+ - Updated the default cupsd.conf policy to list the
+ "administrative" operations separately from the "printer
+ control" operations so that it is easier to define a
+ group of users that are "printer operators".
+ - The web interface now pulls the default cupsd.conf file
+ from cupsd.conf.default in the CUPS config directory.
+ - Added a help file for using Kerberos with CUPS.
+ - The scheduler now strips the "@KDC" portion of Kerberos
+ usernames since those usernames typically do not appear in
+ the group membership lists used by CUPS.
+ - cupsMarkOptions() could (incorrectly) leave multiple option
+ choices marked.
+ - Backends could (incorrectly) run as root during discovery
+ (STR #2454)
+ - Avahi is now supported for DNS-SD (Bonjour) printer sharing
+ (STR #2455)
+ - The default cupsd.conf file had typos and old operation names
+ (STR #2450)
+ - The scheduler now erases authentication cache files using the
+ 7-pass US DoD algorithm.
+ - Delegated Kerberos credentials (proxy authentication) did not
+ work.
+ - The filter makefile did not optimize the libcupsimage.2.dylib
+ with a sectorder file.
+ - The IPP backend incorrectly wrote an empty printer message
+ when processing the "none" state reason.
+ - The USB backend could deadlock on Mac OS X while performing
+ a side-channel command.
+ - The scheduler did not prevent remote queues from being
+ shared/published.
+ - The scheduler did not remove the temporary request file on
+ authentication errors.
+ - ppdLocalizeIPPReason() did not handle "scheme:" schemes or
+ "file" URLs.
+ - ppdLocalizeIPPReason() was not exported on Mac OS X.
+
+
+CHANGES IN CUPS V1.3b1
+
+ - Copyright updates - CUPS is now owned by Apple Inc.
+ - Documentation updates (STR #1775, STR #2027, STR #2130,
+ STR #2131, STR #2263, STR #2356, STR #2397)
+ - Added new cupsfilter utility (STR #1734)
+ - Added new job-printer-state-message and
+ job-printer-state-reasons attributes to jobs (STR #2418)
+ - Added LDAP+SSL support (STR #1967)
+ - CUPS now supports authentication via peer credentials
+ over domain sockets (STR #2242, STR #2277)
+ - The CUPS sample driver PPDs are now generated by the PPD
+ compiler and include all of the localized languages by
+ default (STR #2164)
+ - You can now specify "AuthType Default" in the cupsd.conf
+ file to use the default authentication defined by the
+ DefaultAuthType directive.
+ - The SNMP backend no longer adds a default Address line
+ when none is specified in the snmp.conf file; this allows
+ the backend to be easily disabled as needed (STR #2434)
+ - Added a new cupsctl command for doing basic changes to
+ the cupsd.conf file (STR #1777)
+ - Added a new ppdLocalizeIPPReason() function to get the
+ localized text/URI for a given IPP reason keyword for a
+ driver.
+ - Removed the deskjet2.ppd driver, as it only worked with
+ a very small subset of HP DeskJet printers and was
+ confusing to users. The rastertohp driver still
+ supports the deskjet2.ppd options for existing queues.
+ - The scheduler did not add a trailing banner page if a
+ client did not specify the last document in a job (STR
+ #1711)
+ - The scheduler did not report Bonjour shared printers as
+ remote printers (STR #2384)
+ - Added new -R and -W options to the cupstestppd program
+ for greater control over the testing of PPDs.
+ - Added a new cupsGetServerPPD() function for getting
+ an available PPD from the server (STR #2334)
+ - Added a new cupsDoIORequest() function for reading
+ and writing files via IPP requests (STR #2334)
+ - Added a new CUPS_GET_PPD operation for getting an
+ available PPD file on the server (STR #2334)
+ - CUPS_GET_PPDS now reports multiple ppd-product values
+ based on the PPD ModelName and Product strings (STR
+ #2334, STR #2383)
+ - CUPS_GET_PPDS now reports the PSVersion attributes
+ from a PPD file in the ppd-psversion attribute
+ (STR #2334)
+ - CUPS_GET_PPDS now reports the cupsModelNumber attribute
+ from a PPD file in the ppd-model-number attribute (STR
+ #2383)
+ - CUPS_GET_PPDS now reports a driver type string in the
+ ppd-type attribute based on the cupsFax and cupsFilter
+ attributes in a PPD file (STR #2383)
+ - Added a new printer attribute called "cups-version"
+ which reports the version of CUPS that is running
+ (STR #2240)
+ - backendRunLoop() now aborts immediately on SIGTERM
+ if no data has been written yet (STR #2103)
+ - Due to poor IPP support from the vendors, the SNMP
+ backend no longer tries IPP connections; instead,
+ it now uses a lookup file with fallback to port 9100
+ (socket://address) and 515 (lpd://address) printing
+ (STR #2035, STR #2354)
+ - The scheduler now recreates the CUPS log directory as
+ needed (STR #2353)
+ - cupsLangDefault() now maps new-style Apple locale names
+ to the traditional ll_CC form (STR #2357)
+ - Add new cupsArrayNew2() API to support hashed lookups
+ of array elements (STR #2358)
+ - ppdConflicts() optimizations (STR #2358)
+ - The cupstestppd program now tests for existing filters,
+ icons, profiles, and dialog extensions (STR #2326)
+ - The web interface no longer lists new printers on the
+ main administration page. Instead, a new "List Available
+ Printers" button is provided that shows a separate page
+ with the list of printers.
+ - The web interface now supports setting the banner and
+ policy options on raw printers and classes (STR #2238)
+ - The socket backend now reads any pending back-channel
+ data before shutting down the socket (STR #2325)
+ - Added a new ErrorPolicy directive in the cupsd.conf
+ file (STR #1871)
+ - Printers that use JCL options are now exported to Samba
+ correctly (STR #1985)
+ - The IPP backend now relays printer-state-message values
+ from the server to the client (STR #2109)
+ - Added support for the PWG printer-alert and
+ printer-alert-description attributes (STR #2088)
+ - Added support for LPD "stream" mode (STR #2036)
+ - The scheduler now reports the PostScript product string
+ from PPD files in CUPS-Get-PPDs responses (STR #1900)
+ - Raw printing with queues pointing to the file pseudo-
+ device and multiple files and/or banners now works (STR
+ #1933)
+ - Added new public cupsAdminGetServerSettings() and
+ cupsAdminSetServerSettings() APIs.
+ - Added new "makebuttons" script in the "tools" directory
+ for creating web interface buttons (STR #2231)
+ - Added support for DNS-SD (aka "Bonjour") printer sharing
+ (STR #1171)
+ - Job operations (cancel, hold, release, etc.) from the
+ web interface now return back to the original page (STR
+ #2239)
+ - The classes or printers list is now shown after a
+ successful deletion from the web interface (STR #1999)
+ - The default configuration now allows browse packets from
+ any address (STR #2008)
+ - The web interface now provides an "allow printing from the
+ Internet" check box (STR #1897)
+ - The notify-events-default and
+ notify-lease-duration-default attributes can now be set
+ (STR #1671)
+ - Server-side default options are now sent to clients when
+ the "printer-defaults" attribute group is requested (STR
+ #1923)
+ - Added support for Linux "relro" linker option (STR #1614)
+ - CUPS now validates the number-up option value (STR #1329)
+ - The on-line help now provides better search capabilities
+ (STR #1701)
+ - The web interface "Add This Printer" button now allows you
+ to change the printer name, description, and location
+ (STR #1646)
+ - Added support for Mac OS X authorization services
+ (STR #2206)
+ - Added support for driver-specific pre-filters (STR #2108)
+ - Added a new side-channel API for drivers and backends
+ for basic device control and information queries (STR
+ #1898)
+ - The scheduler now uses poll(), epoll(), or /dev/kqueue
+ instead of select() when possible (STR #1261)
+ - Added new cupsArrayGetIndex() and cupsArrayGetInsert()
+ functions to get the current index and insertion
+ positions of an array.
+ - Added a new --with-max-copies configure option (STR
+ #2090)
+ - Added new cupsRemoveDest() and cupsSetDefaultDest()
+ functions.
+ - Added support for cupsPJLCharset attribute in PPD files
+ which specifies the character set that is used in PJL
+ strings (STR #1969)
+ - Moved the definition of the (private) _http_s structure
+ to http-private.h; code that directly accesses the
+ http_t members will no longer compile!
+ - Added support for setting the document-format-default
+ attribute on a per-printer basis.
+ - Added support for IntelliBar label printers.
diff --git a/CHANGES-1.4.txt b/CHANGES-1.4.txt
new file mode 100644
index 000000000..9376825a8
--- /dev/null
+++ b/CHANGES-1.4.txt
@@ -0,0 +1,835 @@
+CHANGES-1.4.txt
+---------------
+
+CHANGES IN CUPS V1.4.7
+
+ - Documentation changes (STR #3710, STR #3720, STR #3745, STR #3750,
+ STR #3757, STR #3758, STR #3782, STR #3826, STR #3829, STR #3837)
+ - Web interface fixes (STR #3412, STR #3345, STR #3455, STR #3707,
+ STR #3755, STR #3769, STR #3783)
+ - Configure script fixes (STR #3659, STR #3691)
+ - Compilation fixes (STR #3718, STR #3771, STR #3774)
+ - The scheduler might leave old job data files in the spool directory
+ (STR #3795)
+ - CUPS did not work with locales using the ASCII character set
+ (STR #3832)
+ - httpAddrString() did not return a URI-style IPv6 numeric address
+ (STR #3814)
+ - Fixed an issue when reading compressed CUPS raster streams (STR #3812)
+ - Fixed an issue with PostScript printer auto-configuration (STR #3443)
+ - Fixed some compatibility issues with the libusb-based USB backend
+ (STR #3799)
+ - The network backends no longer try to collect SNMP supply and status
+ information for raw queues (STR #3809)
+ - The DBUS notifier did not report job state changes (STR #3805)
+ - The scheduler did not always report that the "normal" print-quality
+ value was supported (STR #3803)
+ - The gziptoany filter did not report the correct error if it was unable
+ to write the uncompressed document to the next filter or backend in
+ the chain (STR #3797)
+ - The Epson and Oki 9-pin drivers had a bad resolution option
+ (STR #3798)
+ - The scheduler did not always register the correct default ICC profile
+ on Mac OS X.
+ - The scheduler did not use the job owner when authorizing access for
+ the CUPS-Get-Document operation, preventing non-admins from accessing
+ their own jobs.
+ - CUPS did not work with some printers that incorrectly implemented the
+ HTTP/1.1 standard (STR #3778, STR #3791)
+ - The scheduler did not retry fax jobs properly.
+ - The scheduler now recognizes an empty cupsCommands PPD keyword as
+ meaning that CUPS commands are not supported for a printer (STR #3773)
+ - Fixed a crash bug in the scheduler when the application/octet-stream
+ MIME type was not defined (STR #3690)
+ - Polled printers were advertised more slowly than necessary (STR #3574)
+ - cupsResolveConflicts() did not handle resolving multiple UIConstraints
+ issues (STR #3705)
+ - The SetEnv and PassEnv directives had no effect (STR #3664)
+ - The libusb-based USB backend printed slowly to the LaserJet 1300 and
+ other printers (STR #3405)
+ - "lp" and "lpr" failed to print with Kerberos enabled (STR #3768)
+ - The cupsctl program now displays an error if you try to directly set
+ the Port or Listen directives (STR #3749)
+ - PPD files with "*JobPatchFile: bla" no longer fail to load in relaxed
+ conformance mode (STR #3747)
+ - The scheduler generated a bad notify-text string for printer state
+ change notifications (STR #3739)
+ - The scheduler incorrectly updated printers.conf when it really needed
+ to update classes.conf or remote.cache (STR #3726)
+ - Hardwired remote printers with options did not work (STR #3717)
+ - Accessing the CUPS web interface using a CNAME-based hostname would
+ sometimes fail due to redirection to the actual hostname (STR #3701)
+ - Subscription events had a misspelled attribute (STR #3693)
+ - "make check" failed if LC_MESSAGES was set (STR #3765)
+ - Fixed the configure script to always look for the pkg-config script
+ (STR #3761)
+ - The scheduler now only looks up interface hostnames if HostNameLookups
+ are enabled (STR #3737)
+ - Fixed a compilation problem on DragonFly BSD (STR #3738)
+ - The default PageLogFormat value had the username and job ID swapped
+ from CUPS 1.3.x (STR #3727)
+ - The scheduler could crash if a browsed printer times out while a job
+ is printing (STR #3754)
+ - The scheduler incorrectly mapped custom page sizes to standard sizes
+ (STR #3764)
+ - cupsfilter and pstops did not map IPP attributes to PPD options due to
+ a change in cupsMarkOptions (STR #3756)
+ - The scheduler did not always show the most recent status message from
+ the print filters (STR #3731)
+ - The PostScript filter did not apply the mirror and number-up options
+ properly, leading to offset and clipped output (STR #3732)
+ - The network backends always reported "low toner" or "out of toner"
+ states, even for inkjet printers (STR #3733)
+
+
+CHANGES IN CUPS V1.4.6
+
+ - Fixed a "make check" issue on Solaris (STR #3729)
+ - Regression: The pstops filter did not support landscape printing of
+ PostScript files (STR #3722)
+ - The scheduler killed retried (fax) jobs after restarting them
+ (STR #3697)
+ - The cupsAdminSetServerSettings() function disabled sharing when
+ debug logging was enabled (STR #3712)
+
+
+CHANGES IN CUPS V1.4.5
+
+ - Documentation fixes (STR #3542, STR #3650)
+ - Localization fixes (STR #3635, STR #3636, STR #3647, STR #3666)
+ - Security: Fixed a memory corruption bug reported in CVE-2010-2941
+ (STR #3648)
+ - The CUPS API incorrectly mapped the HTTP_UNAUTHORIZED status to the
+ IPP_NOT_AUTHORIZED status code, when IPP_NOT_AUTHENTICATED would be
+ the correct mapping (STR #3684)
+ - The scheduler would restart jobs while shutting down (STR #3679)
+ - Fixed a PPD loader bug that could cause a crash in cupsd (STR #3680)
+ - Improved the mapping of non-standard PPD and PWG names (STR #3671)
+ - The scheduler did not initialize Kerberos in all cases (STR #3662)
+ - cupsAdminSetServerSettings duplicated Listen and Order lines
+ (STR #3645)
+ - Added DeviceN colorspace support to the CUPS Raster format (STR #3419)
+ - ppdMarkDefaults() did not clear the marked field of the previous
+ choices (STR #3642)
+ - The serial backend would not allow a raw job to be canceled
+ (STR #3649)
+ - The socket backend could go into an infinite loop with certain
+ printers (STR #3622)
+ - Setting the PRINTER or LPDEST environment variables to "name/instance"
+ did not work (STR #3485)
+ - The scheduler did not handle the JobRetryLimit setting properly
+ (STR #3466)
+ - The lpstat command always showed a remote job ID of 0 for shared
+ printers (STR #3627)
+ - Increased the write timeout for the libusb-based USB backend to 5
+ minutes (STR #3595)
+ - The libusb-base USB backend did not check whether the printer has a
+ serial number (STR #3590)
+ - The lpadmin command did not support setting of custom option values
+ (STR #3631)
+ - The lpadmin command did not support setting of the location or
+ description of a class (STR #3613)
+ - The cupsaddsmb command did not give up after too many failed attempts
+ (STR #3615)
+ - The CUPS library no longer uses certain problematic ctype macros that
+ change based on the locale's character set.
+ - PJL value substitution of more than 9 values was broken (STR #3621)
+ - Custom options with missing string values caused ppdEmit* to segfault
+ (STR #3620)
+ - Fixed an issue with the Italian version of the web interface
+ (STR #3624)
+ - Fixed the Solaris SMF configuration file for cups-lpd (STR #3611)
+ - The scheduler did not set the notify-subscribed-event attribute when
+ delivering printer-added or printer-modified events (STR #3608)
+ - The mailto notifier could get into an infinite loop (STR #3609)
+ - Date/time information was not shown in banner pages.
+ - Relational operators were broken in #if/#elif/#else/#endif expressions
+ for the PPD compiler.
+ - Moving a job via the web interface failed without asking for
+ authentication (STR #3559)
+ - The scheduler now clears the printer-state-reasons when the driver is
+ changed (STR #3570)
+ - The web interface did not allow a user to change the driver
+ (STR #3537, STR #3601)
+ - The scheduler was not setting the PATH_INFO environment variable when
+ needed (STR #3600)
+ - The scheduler incorrectly set the CUPSD_AUTH_TYPE environment
+ variable instead of AUTH_TYPE (STR #3599)
+ - Fixed a buffer overrun in the PPD compiler (STR #3594)
+ - Fixed some additional IPP job template attribute mapping issues in the
+ scheduler.
+
+
+CHANGES IN CUPS V1.4.4
+
+ - Documentation updates (STR #3453, STR #3527, STR #3528, STR #3529)
+ - Security: The fix for CVE-2009-3553 was incomplete (STR #3490)
+ - Security: The texttops filter did not check the results of allocations
+ (STR #3516)
+ - Security: The web admin interface could disclose the contents of
+ memory (STR #3577)
+ - Security: CUPS could overwrite files as root in directories owned or
+ writable by non-root users (STR #3510)
+ - The cups-config utility did not return the correct linker options on
+ AIX (STR #3587)
+ - Fixed some IPP conformance issues with the scheduler's
+ ippget-event-life, operations-supported, output-bin, and sides
+ attributes (STR #3554)
+ - The OpenSSL interfaces have been made thread-safe and the GNU TLS
+ interface is explicitly forbidden when threading is enabled
+ (STR #3461)
+ - Fixed an IPP conformance issue with the scheduler's Send-Document
+ implementation (STR #3514)
+ - Added additional validation checks for the 1284 device ID (STR #3534)
+ - Fixed a problem with the RPM spec file (STR #3544)
+ - The lpstat command did not limit the job list to the specified
+ printers (STR #3541)
+ - The cupsfilter command did not set the RIP_MAX_CACHE environment
+ variable (STR #3531)
+ - Fixed support for media-col and page size variants (STR #3394)
+ - The PostScript filter did not support all media selection options for
+ the first page (STR #3525)
+ - The scheduler did not always remove job control files (STR #3425)
+ - The scheduler could crash on restart if classes were defined
+ (STR #3524)
+ - The scheduler no longer looks up network interface hostnames by
+ default on Mac OS X (STR #3523)
+ - ippWriteIO did not write collection (member) attributes properly in
+ all cases (STR #3521)
+ - The "cupsctl --remote-any" and corresponding web interface check box
+ (allow printing from the Internet) did not work reliably (STR #3520)
+ - The lpq and lpr commands would sometimes choose different default
+ printers (STR #3503)
+ - cupsDo*Request did not flush error text, leading to multiple issues
+ (STR #3325, STR #3519)
+ - cupsDoAuthentication did not cancel password authentication after 3
+ failures (STR #3518)
+ - Fixed several LDAP browsing bugs (STR #3392)
+ - The Dymo driver did not support copies (STR #3457)
+ - The scheduler did not update the classes.conf file when deleting a
+ printer belonging to a class (STR #3505)
+ - The lppasswd command did not use localized password prompts
+ (STR #3492)
+ - The socket backend no longer waits for back-channel data on platforms
+ other than Mac OS X (STR #3495)
+ - The scheduler didn't send events when a printer started accepting or
+ rejecting jobs (STR #3480)
+ - The web interface now includes additional CSRF protection (STR #3498)
+
+
+CHANGES IN CUPS V1.4.3
+
+ - SECURITY: The scheduler could try responding on a closed client
+ connection, leading to a crash (STR #3200)
+ - SECURITY: The lppasswd program allowed the localization files to be
+ overridden when running in setuid mode (STR #3482)
+ - Localization updates (STR #3352, STR #3409, STR #3422, STR #3452,
+ STR #3473, STR #3502)
+ - Documentation updates (STR #3451, STR #3504)
+ - The IPP backend now sets the printer-state-message to "Ready to
+ print." at the end of a successful job (STR #3460)
+ - The PPD compiler did not correctly add the manufacturer to the output
+ filename when using the "-m" option (STR #3469)
+ - The IPP backend did not handle authentication properly for the Get-
+ Printer-Attributes operation (STR 3458)
+ - Getting SNMP values larger than 127 bytes did not work.
+ - IPP conformance: Get-Jobs has a default value for requested-attributes
+ (STR #3383)
+ - cupsPrintFiles() did not report all errors (STR #3449)
+ - cupsAddDest() could read freed memory (STR #3448)
+ - The DBUS notifier did not build (STR #3447)
+ - The scheduler would crash when an active printer was deleted.
+ - The snmp backend did not work with some printers (STR #3413)
+ - The web interface did not show the conflicting values when setting
+ options (STR #3440)
+ - Setting options in the web interface did not always work (STR #3439)
+ - The scheduler did not use the Get-Job-Attributes policy for a printer
+ (STR #3431)
+ - The scheduler added two job-name attributes to each job object
+ (STR #3428)
+ - CSS files would not print (STR #3442)
+ - The scheduler did not clean out completed jobs when PreserveJobHistory
+ was turned off (STR #3425)
+ - The web interface did not show completed jobs for a printer
+ (STR #3436)
+ - Authenticated printing did not always work when printing directly to
+ a remote server (STR #3435)
+ - The USB backend did not work on Solaris (STR #3423)
+ - cupstestppd didn't catch problems with JobPatchFile definitions
+ (STR #3421)
+ - The socket backend could crash if a SNMP string had a negative length.
+ - Fixed some termination issues with the USB backend on Mac OS X.
+ - The side-channel APIs did not handle interrupts properly.
+ - The network backends incorrectly cleared the media-empty-warning
+ state.
+ - The web interface did not allow users to successfully add serial
+ printers (STR #3391)
+ - cupsTempFd() did not work in some situations (STR #3382)
+ - Some C API headers were missing C++ wrapper logic.
+ - The PPD compiler did not localize single-language PPD options properly
+ (STR #3386)
+ - Modifying a printer from the web interface sometimes caused the wrong
+ driver to be selected (STR #3418)
+ - The scheduler did not handle out-of-memory conditions properly when
+ loading a job (STR #3407)
+ - When adding printers from the web interface, the dynamic updates of
+ the device list made it hard to pick a device (STR #3406)
+ - Fixed a typo in the web interface admin page template (STR 3403)
+ - The web interface did not preserve the "printer is shared" state when
+ modifying a printer (STR #3390)
+ - The PPD compiler incorrectly inserted translations of empty strings
+ (STR #3411)
+ - The scheduler did not reset the SIGPIPE handler of child processes
+ (STR #3399)
+ - cupsGetNamedDest() incorrectly returned the default printer if the
+ named printer did not exist (STR #3397)
+ - Fixed a GNU TLS error handling bug (STR #3381)
+
+
+CHANGES IN CUPS V1.4.2
+
+ - SECURITY: The CUPS web interface was vulnerable to several XSS and
+ HTTP header/body attacks via attribute injection (STR #3367,
+ STR #3401)
+ - Fixed localization errors (STR #3359, STR #3372, STR #3380, STR #3387)
+ - The documentation for classes.conf and printers.conf did not provide
+ the correct instructions for manual changes (STR #3351)
+ - The scheduler did not always rebuild printer cache files when the
+ driver was changed (STR #3356)
+ - The documentation makefile failed to install localizations when using
+ newer versions of Bash (STR #3360)
+ - The configure script did not use the --with-xinetd value for the
+ default LPD configuration path (STR #3347)
+ - The configure script incorrectly required glib for DBUS support
+ (STR #3346)
+ - The cupstestppd program incorrectly reported filters with bad
+ permisssions as missing (STR #3363)
+ - The cups.desktop file used the wrong locale names (STR #3358)
+ - cupsSideChannelRead() did not return an error for short reads.
+ - The installed PAM configuration file did not use the correct options
+ with the pam_unix2 module (STR #3313)
+ - The scheduler did not preserve default options that contained special
+ characters (STR #3340)
+ - The scheduler did not remove old pre-filters when updating a printer
+ driver (STR #3342)
+ - The HP/GL-2 filter did not check for early end-of-file (STR #3319)
+ - The USB backend did not compile on some platforms (STR #3332)
+ - cupsSideChannelSNMPWalk() could go into an infinite loop with broken
+ SNMP implementations.
+
+
+CHANGES IN CUPS V1.4.1
+
+ - Documention fixes (STR #3296)
+ - SNMP supply levels and states were wrong for some printers.
+ - The IPP backend did not update the auth-info-required value.
+ - The libusb-based USB backend would hang at the end of the job
+ (STR #3315, STR #3318)
+ - DNS-SD registrations for raw queues had an empty "ty" key (STR #3299)
+ - The JPEG and BMP MIME type rules were broken (STR #3284)
+ - cupsGetNamedDest returned the default printer when the named
+ destination did not exist (STR #3285)
+ - The JobKillDelay was not triggered for canceled jobs (STR #3292)
+ - The PPD compiler could get in an infinite loop (STR #3293)
+ - The configure check for dns-sd.h was broken (STR #3297)
+ - The "Query Printer for Default Options" page did not go away if the
+ query job was held (STR #3302)
+ - Boolean options did not show up as selected in the web interface
+ (STR #3303)
+ - The scheduler did not cache or report driver information files
+ correctly, leading to a variety of issues (STR #3283, STR #3297,
+ STR #3305)
+ - cupsDoIORequest() did not abort on permanent errors (STR #3311)
+ - Modifying a class in the web interface did not work (STR #3312)
+ - BrowseLocalProtocols could be cleared when changing the sharing
+ setting (STR #3287)
+ - The scheduler could return an empty supported document format
+ (STR #3308)
+ - The PPD compiler generated invalid PPD files when the locale used
+ something other than "." for the decimal point (STR #3300)
+ - The IPP backend did not handle some non-comforming IPP printer
+ implementations (STR #3262)
+ - The scheduler leaked three file descriptors to each job filter
+ (STR #3263)
+ - The scheduler now uses a default CUPS-Get-Devices timeout of 15
+ seconds (STR #3307)
+
+
+CHANGES IN CUPS V1.4.0
+
+ - Localization updates (STR #3223, STR #3246, STR #3248, STR #3250)
+ - Documentation updates (STR #3225, STR #3230, STR #3242, STR #3260)
+ - The --with-pdftops configure option did not accept a full path to the
+ filter (STR #3278)
+ - The banner filter did not position the back side image correctly
+ (STR #3277)
+ - The dnssd backend could crash (STR #3272)
+ - The 1284 device ID sometimes contained trailing garbage (STR #3266)
+ - The USB backend returned different URIs for some printers than in
+ CUPS 1.3 (STR #3259)
+ - The scheduler did not do local job-hold-until processing for remote
+ queues (STR #3258)
+ - The scheduler did not try all possible SSL certificates on Mac OS X.
+ - The scheduler did not always remove a file descriptor when using the
+ kqueue interface (STR #3256)
+ - The scheduler did not protect against bad job control files in all
+ cases (STR #3253)
+ - The scheduler did not encode "+" in model names (STR #3254)
+ - The web interface didn't show the default options (STR #3244)
+ - The IPP and LPD backends needed print data before they would do an
+ SNMP query.
+ - Fixed a GNU TLS compatibility issue (STR #3231)
+ - Fixed a HTML error in the add and modify printer web interface
+ templates (STR #3229)
+ - The scheduler did not minimize the number of printer state events that
+ were generated by filter STATE: messages, which could lead to poor
+ performance.
+ - The USB backend on Mac OS X did not cleanly cancel a job.
+ - The network backends now set the connecting-to-device printer-state-
+ reasons value when looking up the address and copying the print data
+ for consistency.
+ - The scheduler now supports the com.apple.print.recoverable-warning
+ reason on all platforms.
+
+
+CHANGES IN CUPS V1.4rc1
+
+ - The PPD compiler documentation was missing information on localization
+ (STR #3212)
+ - The IPP backend now reconnects after every request when talking to
+ printers that claim IPP support but only use HTTP/1.0.
+ - The PPD compiler crashed when both "Resolution" and "Group foo Option
+ Resolution" were specified in the .drv file.
+ - The PPD compiler's #if/#elif/#else/#endif did not work for undefined
+ variables (STR #3210)
+ - Static libraries could not be installed by a non-root user on systems
+ needing a ranlib program (STR #3209)
+ - The scheduler incorrectly always tried to copy Kerberos credentials
+ for print jobs.
+ - Updated the Spanish localization (STR #3204)
+ - The scheduler crashed when getting the default paper size from
+ libpaper (STR #3205, STR #3206)
+ - The PPD compiler now defines six variables: CUPS_VERSION,
+ CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR, CUPS_VERSION_PATCH,
+ PLATFORM_NAME, and PLATFORM_ARCH (STR #3203)
+ - Fixed a whitespace skipping bug in cupsRasterInterpretPPD.
+ - The scheduler did not return HTTP 403 (Forbidden) for authenticated
+ users that were not authorized to do IPP operations (STR #3193)
+ - The scheduler did not report more than 8 Product strings from a PPD
+ file. Some PPD files have as many as 24.
+ - ppdOpen*() could crash if a keyword had no value string (something
+ that cupstestppd looks for...)
+ - cupsLangDefault() did not return the correct language on Mac OS X.
+ - The Mac OS X USB backend did not handle aborted or stalled pipe
+ conditions properly, which prevented drivers from ejecting partial
+ pages when a job was canceled or held.
+
+
+CHANGES IN CUPS V1.4b3
+
+ - Documentation fixes (STR #3044, STR #3057, STR #3153, STR #3158,
+ STR #3173)
+ - Added complete localizations for German, Japanese, Polish, and
+ Russian and partial localizations for Chinese, Danish, Finnish,
+ French, Italian, Korean, Norwegian, Portuguese, and Swedish
+ (STR #3096, STR #3098, STR #3109, STR #3111, STR #3141)
+ - Updated the configure check for -fstack-protector (STR #3198)
+ - The network backends now correctly convert SNMP supply descriptions to
+ UTF-8 encoding as needed.
+ - The scheduler could crash when deleting an attribute (STR #3197)
+ - The cups-driverd program did not detect symlink loops (STR #3185)
+ - The EPSON 24-pin series driver should now feed the correct amount
+ (STR #2624)
+ - The scheduler now automatically logs the last N debug messages for
+ failed print jobs.
+ - You can now modify a raw print queue (STR #3133)
+ - Fixed a number of ppdi issues and added a unit test to validate that
+ ppdc + ppdi can generate and import the same data (STR #3152)
+ - Moving jobs in the web interface now shows an error if you only have
+ one printer or class added (STR #3094)
+ - Since classes have never truly supported the printer-error-policy
+ stuff added in CUPS 1.2, update the code to reflect the current
+ reality and support only the retry-current-job policy for now
+ (STR #3171)
+ - Revised the password callback support (STR #2953)
+ - ppdEmit*() did not choose between PageSize and PageRegion properly.
+ - Make some fairly substantial changes to the Kerberos support code so
+ that CUPS can work in multi-realm environments and does not require
+ delegatable credentials. Shared printing still requires delegation,
+ however "delegation by policy" can be enabled in the KDC to make this
+ all work.
+ - "AccessLogLevel actions" did not hide client-error-not-found errors.
+ - AP_FIRST_InputSlot did not work with number-up.
+ - cupsBackChannelRead() and cupsBackChannelWrite() could fail due to a
+ lack of kernel buffers.
+ - The IPP and LPD backends did not respond to side-channel requests
+ while copying print data to a temporary file.
+ - cupsWriteRequestData() flushed the output buffer unnecessarily,
+ causing reduced performance in some situations.
+ - If a CGI process died before sending its MIME headers, the request
+ would hang on the client.
+ - The printer/class/job search feature on the web interface did not
+ work (STR #3132)
+ - The scheduler did not write the printers out for classes.
+ - CUPS-Get-PPDs did not work properly when filtering by language,
+ product, or psversion (STR #3136)
+ - The scheduler now kills job filters when it takes more than 30 seconds
+ (configurable) to cancel or hold the job.
+ - The cupstestppd program did not validate the capitalization of
+ filenames in the PPD file.
+ - The cupstestppd program did not validate the PageSize and PageRegion
+ values.
+ - The cups-deviced helper program could miss reporting some backend
+ devices (STR #3108)
+ - The cupsSideChannelSNMP* functions did not work.
+ - The scheduler could consume 100% CPU when jobs were canceled.
+ - Clicking on "Select Another Make/Manufacturer" in the web interface
+ incorrectly added the printer (STR #3095)
+ - The scheduler no longer uses programs with insecure file
+ permissions.
+ - httpAssembleURI*() did not escape backslashes in hostnames.
+ - The dnssd backend did not unquote "full names" before creating the
+ device URI.
+ - The scheduler now supports JobRetryInterval values less than 10
+ seconds.
+ - Updated the Spanish localization (STR #3090)
+ - The scheduler did not redo Bonjour/DNS-SD registrations when updating
+ them failed.
+ - The "authenticated" policy incorrectly required authentication for
+ status operations.
+ - ppdOpen*() incorrectly loaded PPDs with multiple JobPatchFile
+ keywords.
+ - The network backends no longer report the SNMP "offline" or
+ maintenance status bits since they are inconsistently implemented and
+ often unreliable.
+ - The scheduler no longer logs child processes killed via SIGKILL as
+ "crashed".
+ - The printer link shown on the "job moved" template was bad (STR #3085)
+ - Updated the HTML templates to use the final HTML 4 DOCTYPE (STR #3086)
+ - The scheduler did not track the "paused" reason properly if a
+ printer had other reasons associated with it.
+ - cupsSendRequest() did not clear old local certificate auth data.
+ - The PPD compiler did not search for localization files properly
+ (STR #3084)
+ - cupsGetNamedDest() did not use the fallback default like
+ cupsGetDests*() (STR #3082)
+ - The scheduler now provides a LogTimeFormat directive to enable
+ microseconds in the date and time that are logged.
+ - The scheduler now provides a MultipleOperationTimeout directive to
+ control the timeout for multi-file print jobs.
+ - The configure script incorrectly allowed Avahi to be used for DNS-SD
+ printer discovery (STR #3065)
+ - The web interface and scheduler did not support URIs up to 1024 bytes
+ in length (STR #3072)
+ - Fixed pdftops issues with page sizes (STR #3063)
+ - Fixed pdftops issues with Ghostscript (STR #3062)
+ - The scheduler incorrectly registered default profiles for PostScript
+ printers with no specified colorspace.
+ - The scheduler incorrectly created an empty org.cups.printers.plist
+ file on Mac OS X.
+ - cupsGetPPD3() did not look for local PPDs in the right directory.
+ - SNMP lookups via side-channel did not work for NULL-VALUE and
+ and OCTET-STRING OIDs containing nul characters.
+ - The libusb-based USB backend did not work.
+ - The scheduler did not set the printer-commands attribute correctly
+ for some PPDs.
+ - The ppdi utility did not work.
+ - The web interface no longer uses multi-part output with old or broken
+ web browsers (STR #3049)
+ - CUPS now conforms to the draft IPP/2.0 and IPP/2.1 specification.
+ - Added a new cupsGetConflicts() API to get a list of conflicting
+ options.
+ - The PPD compiler didn't localize options or choices that did not
+ have associated translation text (STR #3045)
+ - Updated the Spanish localization (STR #3043)
+ - Fixed build problems (STR #3040, STR #3047)
+ - cupsResolveConflicts() did not resolve using the default option
+ choice in some cases due to the mirror UIConstraints that are
+ present in most PPD files.
+ - The scheduler did not honor MIME type priorities.
+ - The commandtops filter incorrectly used the JCLBegin code to end
+ its jobs.
+ - The default BrowseLocalProtocols value was not set properly.
+ - Since the commandtops filter does not actually support ReportLevels
+ all on its own, don't list that printer command by default for PS
+ printers.
+ - The scheduler did not give filters a chance to log errors or update
+ printer attributes when a job was canceled.
+ - The scheduler did not clear the "connecting-to-device" reason keyword
+ when a job finished.
+
+
+CHANGES IN CUPS V1.4b2
+
+ - Documentation updates (STR #2983, STR #2998, STR #3021)
+ - The cupstestppd utility now validates the FileVersion and
+ FormatVersion values in PPD files.
+ - The default cupsd.conf file did not reflect the
+ --with-local-protocols value set at compile-time (STR #3037)
+ - The cupsGetPPD* APIs now create symlinks to local PPD files
+ rather than copying them whenever possible.
+ - Various performance optimizations in the string pool, dests, and
+ options implementations.
+ - The cupsGetDests* APIs now return the marker and printer-commands
+ attributes.
+ - Side-channel SNMP lookups would not work when cupsSNMPSupplies
+ was set to False in the PPD file.
+ - Localized the device descriptions for the SCSI, serial,
+ and network backends (STR #3014)
+ - Added a Spanish localization (STR #3015)
+ - Added support for marker-low-levels and marker-high-levels
+ attributes.
+ - The scheduler could hang writing a long log line.
+ - The cupsGetDevices() function now has an "include_schemes"
+ parameter.
+ - The lpinfo command now supports --include-schemes and
+ --exclude-schemes options.
+ - The CUPS-Get-PPDs operation now supports the include-schemes
+ and exclude-schemes attributes.
+ - The CUPS-Get-Devices operation now supports the include-schemes
+ attribute.
+ - The print filters now support a replacement for the fitplot
+ option called "fit-to-page".
+ - The LPD backend no longer tries to collect page accounting
+ information since the LPD protocol does not allow us to
+ prevent race conditions.
+ - The scheduler did not save the last marker-change-time value.
+ - Fixed a problem with printing to some IPP printers, including
+ CUPS 1.1.x.
+ - Fixed a redirection problem with the printer web page (STR #3012)
+ - Fixed a PPD compiler problem with the loading of message
+ catalogs (STR #2990)
+ - Fixed a PPD compiler problem with the loading of .strings files
+ (STR #2989)
+ - The cupsfilter utility did not set the CONTENT_TYPE environment
+ variable when running filters.
+ - The scheduler now waits to allow system sleep until the jobs
+ have all stopped.
+ - The IPP, LPD, and socket backends used different "connecting"
+ progress messages.
+
+
+CHANGES IN CUPS V1.4b1
+
+ - Documentation updates (STR #2567)
+ - The PPD compiler now allows local message catalogs to
+ override the standard CUPS translations (STR #2642)
+ - The ppdmerge command did not merge custom option strings
+ (STR #2863)
+ - The scheduler now supports the Hold-New-Jobs and
+ Release-Held-New-Jobs operations; these are exposed via the
+ cupsdisable and cupsenable commands (STR #2332)
+ - The lpstat command is now much faster when displaying the
+ status of a single printer (STR #2843)
+ - The scheduler now caches information from PPD files to provide
+ significantly faster startup time with large numbers of PPDs
+ (STR #1293)
+ - CUPS-Get-Driver now provides much better driver matching based
+ on the IEEE-1284 device ID and make/model strings (STR #2707)
+ - Now support the cupsSNMPSupplies keyword to control whether
+ the network backends query the SNMP Printer MIB for supply
+ levels.
+ - Now support and use a new banner file format for better text
+ support and easier customization (STR #2490)
+ - The scheduler now sets the PRINTER_INFO and PRINTER_LOCATION
+ environment variables from the corresponding IPP attributes.
+ - The ippRead*() and ippWrite*() functions no longer use a
+ stack-based buffer (STR #2388)
+ - The CUPS-Add-Modify-Printer operation now allows you to set
+ the printer-state-reasons attribute.
+ - The "set printer options" page now supports auto-configuration
+ of printer options (STR #1440)
+ - The web interface now provides an advanced server settings
+ form.
+ - The web interface's "modify printer" pages now make it
+ easier to change just one setting (STR #1919)
+ - The scheduler now supports a plist PrintcapFormat.
+ - The scheduler now supports multiple addresses in Allow and
+ Deny lines, just like Apache (STR #2947)
+ - Added CUPS_JOBTYPE environment variable for job filters so
+ they know whether they are printing a banner or document
+ file (STR #2799)
+ - Added support for printer filtering by the cupsfilter
+ command (STR #2562)
+ - Added a SSLOptions directive to allow Windows clients to
+ talk to CUPS in FIPS mode (STR #2827)
+ - Renamed the accept and reject commands to cupsaccept and
+ cupsreject; the old names are still available (STR #2936)
+ - The locale/translate utility needed an update to work with
+ Google (STR #2882)
+ - The lpstat command now supports a -H option to display the
+ default server (STR #2833)
+ - The scheduler now supports a FatalErrors directive to control
+ which errors should cause the scheduler to exit (STR #2536)
+ - The scheduler now uses the php-cgi program if it is available
+ (STR #2923)
+ - The scheduler now supports a DefaultPaperSize directive
+ (STR #2848)
+ - The scheduler now passes the job-originating-host-name
+ value to filters in the options argument (STR #2558)
+ - CUPS now supports job tickets in PDF files (STR #2903)
+ - Added a DBUS notifier (STR #2529)
+ - The LPD mini-daemon now passes the document name when queuing
+ print jobs (STR #2482)
+ - The IPP backend did not relay com.apple.print.recoverable-message
+ values.
+ - The scheduler now supports a job-media-progress attribute to
+ track the progress of individual pages.
+ - The sample HP driver now supports A5 (STR #2798)
+ - The CUPS web interface menu item now uses the xdg-open
+ command, when available (STR #2724)
+ - The cups-lpd program now supports the -h option (STR #2794)
+ - The scheduler now sets the PAM_TTY parameter and the
+ PAM_ESTABLISH_CRED credential flag (STR #2745)
+ - The scheduler now logs unsuccessful requests to the error_log
+ file as errors (STR #2616)
+ - Added support for a "retry-current-job" error policy that
+ retries the current job immediately when the backend encounters
+ an error (STR #2555)
+ - The scheduler now returns a "forbidden" error when a user
+ correctly authenticates but does not have permission to
+ continue further (STR #2101)
+ - The scheduler now loads both the server and CA certificates
+ (if present) from the ServerCertificate file (STR #2146)
+ - New RSS subscriptions now create their feed files immediately
+ (STR #2853)
+ - Added support for a device-location attribute which provides
+ the physical location of a printer device.
+ - Added a cupsBackendReport() API which handles quoting of the
+ device data by a backend.
+ - Added support for custom options in the web interface
+ (STR #1729)
+ - Added support for Mozilla LDAP, reconnection to LDAP servers,
+ and improved LDAP performance (STR #1962)
+ - Added Solaris SMF support (STR #1477)
+ - Added optional support for using TCP wrappers to limit access
+ to CUPS (STR #263)
+ - Added ppdPageSizeLimits API.
+ - Added support for new cupsMediaQualifier2, cupsMediaQualifier3,
+ cupsMinSize, and cupsMaxSize attributes.
+ - Added cupsResolveConflicts and ppdInstallableConflict APIs.
+ - Added support for new cupsUIConstraints and cupsUIResolver
+ attributes for better option conflict detection and
+ resolution.
+ - Increased the maximum size of 1284 device ID strings to
+ 256 bytes (STR #2877)
+ - Added an AccessLogLevel directive to cupsd.conf to control
+ what is logged to the access_log file.
+ - The default LogLevel is now "warn" instead of "info" to reduce
+ the amount of logging that is done to disk by default.
+ - The PPD compiler did not include OID query keywords in PPD
+ files (STR #2871)
+ - The cups-driverd helper program now directly supports driver
+ information files.
+ - The USB backend now uses libusb when available (STR #1575)
+ - Added ppdLocalizeAttr function to get the localized version
+ of an attribute.
+ - MIME types now support a priority() attribute (STR #2719)
+ - The standard MIME types are now installed in
+ DataDir/mime (STR #2719)
+ - The lpoptions command now describes custom options and
+ the necessary parameters (STR #2660)
+ - The ppdmerge program did not support Simplified Chinese
+ or Traditional Chinese language version strings (STR #2851)
+ - The PPD compiler now supports localizable attributes
+ (STR #2738)
+ - The ppdpo utility now includes cupsIPPReasons values in
+ the message catalogs it generates (STR #2754)
+ - The PPD compiler now supports conditional directives
+ (STR #2636)
+ - The ppdc utility now supports a "-t" option to test PPD
+ files (STR #2739)
+ - The ppdc utility now supports a "-m" option to use the
+ ModelName value as the output filename.
+ - The ppdc utility now supports a FileName directive to
+ set an alternate output filename (STR #2740)
+ - The side-channel API now supports SNMP queries for the
+ standard network backends.
+ - Added a PageLogFormat directive to the cupsd.conf file to
+ control the format of lines in the page_log file.
+ - Filters can now send PPD: messages to stderr to set PPD
+ keywords like DefaultPageSize while a job is printing.
+ - Added a mdns backend for discovery and printing to printers
+ that advertise themselves via DNS-SD (Bonjour)
+ - The ipp, lpd, and socket backends now support DNS-SD service
+ name resolution.
+ - The scheduler now uses a single shared file descriptor for
+ all DNS-SD registrations (STR #2674)
+ - The ipp, lpd, and socket backends now support SNMP-based
+ page accounting and supply level monitoring (STR #1655)
+ - Added support for cupsPJLDisplay attribute to control what
+ PJL commands are used to display the job information.
+ - Driver information files can now be installed in
+ /Library/Printers/PPDs.drv on Mac OS X.
+ - The CUPS image library now supports reading images larger
+ than 2GB.
+ - The scheduler now delays writing config and state files to
+ reduce disk activity (STR #2684)
+ - The CUPS-Get-Devices operation now supports the
+ exclude-schemes and timeout attributes to control which
+ backends are polled and for how long.
+ - The cups-deviced helper application now runs backends in
+ parallel to get the list of devices faster.
+ - Added --enable-pap configure option.
+ - The default cupsd.conf file now includes an "authenticated"
+ policy which requires authentication for remote print jobs.
+ - Added support for Czech and Hungarian in PPD files
+ (STR #2735, STR #2736)
+ - The PPD compiler tools now support Mac OS X .strings files
+ for localization (STR #2737)
+ - ppdOpen*() now default the colorspace member to PPD_CS_N
+ when no DefaultColorSpace attribute is present in the PPD
+ file.
+ - The build system has been updated to support separate
+ installation of data, program, header, and library files.
+ - All support libraries are now built as shared libraries
+ by default.
+ - The scheduler now manages ICC color profiles on Mac OS X.
+ - The network backends (ipp, lpd, socket) now support
+ SNMP-based supply and page count monitoring (STR #1655)
+ - The lppasswd program is no longer installed setuid to
+ root to make the default installation more secure.
+ - Added a new ppdLocalizeMarkerName() function to get
+ the localized version of a marker-names value.
+ - The scheduler now provides the printer-dns-sd-name
+ attribute for printers shared via DNS-SD/Bonjour.
+ - The pdftops filter now executes the Xpdf or poppler
+ pdftops utility to convert PDF files (STR #1471)
+ - Bonjour printer registrations now advertise as local or
+ global based on the current access policies for the
+ printer.
+ - cupsGetDests*() and cupsSetDests*() now track the last
+ used printer preference on Mac OS X.
+ - Added a new streaming request API (STR #2261)
+ - Added a new cupsGetNamedDest() function to the CUPS
+ library for faster printing with lp and lpr (STR #2638)
+ - The scheduler now sets the PAM RHOST value on systems
+ that support it (STR #2637)
+ - The scheduler now sandboxes child processes when
+ possible.
+ - The Cancel-Job operation now supports a purge-job
+ attriibute to purge a specified job.
+ - ppdEmit* and ppdCollect* now use the NonUIOrderDependency
+ attributes for custom option selections.
+ - The web interface now enables/disables the printer
+ sharing (formerly publishing) controls based on the
+ server-is-sharing-printers state (STR #2233)
+ - The scheduler now tracks printer sharing via the
+ server-is-sharing-printers attribute, and manages LPD
+ and SMB sharing as well (STR #2233)
+ - The web interface now allows you to go back to the make/
+ manufacturer page if there is no matching printer driver
+ on the model page (STR #2436)
+ - The printer list now shows the default media, banner, and
+ duplex options as well as the color and duplex capabilities
+ of printers (STR #1175)
+ - The web interface look-n-feel has been updated (STR #2492)
+ - The scheduler now supports a CUPS-Get-Document operation
+ that returns the specified print job document (STR #118)
+ - The cupsfilter utility now supports a "-J jobid" option
+ to filter the document from the specified job.
+ - The scheduler (cupsd) now supports a new option (-t) to
+ do a syntax check of the cupsd.conf file (STR #2003)
+ - Added new cupsGetPPD3() API to allow applications to
+ cache PPDs safely (STR #1473)
+ - Added generic PostScript and PCL printer driver PPDs.
diff --git a/CHANGES.txt b/CHANGES.txt
new file mode 100644
index 000000000..ff26f57d6
--- /dev/null
+++ b/CHANGES.txt
@@ -0,0 +1,98 @@
+CHANGES.txt - 2011-05-20
+------------------------
+
+CHANGES IN CUPS V1.5b1
+
+ - The CUPS library now supports per-connection HTTP timeouts and
+ callbacks.
+ - The CUPS library now supports (limited) SSL/TLS X.509 certificate
+ validation and revocation (STR #1616)
+ - Updated the PostScript filter to support IncludeFeature in more
+ circumstances (STR #3417)
+ - The schedule did not correctly parse some IPv6 addresses and masks in
+ the cupsd.conf file (STR #3533)
+ - Fixed a case-insensitive string comparison issue for locales that do
+ not treat "I" and "i" as equivalent (STR #3800)
+ - The scheduler reported an incorrect job-printer-uri value when sharing
+ was not enabled (STR #3639)
+ - The scheduler now allows the ServerAlias directive to contain multiple
+ hostnames separated by spaces or commas (STR #3813)
+ - The scheduler now sets the process group for child processes and
+ manages the group (STR #2829)
+ - Fixed some minor issues discovered by a Coverity scan (STR #3838)
+ - The scheduler now more carefully creates and removes configuration,
+ cache, and state files (STR #3715)
+ - The lpadmin command now allows default option values to be deleted
+ (STR #2959)
+ - The lpadmin command now allows the cupsIPPSupplies and
+ cupsSNMPSupplies keywords to be set in a PPD file (STR #3825)
+ - Moving a held job no longer releases it (STR #3839)
+ - Restored support for GNU TLS and OpenSSL with threading enabled
+ (STR #3605)
+ - Fixed a confusing error message from cups-polld (STR #3806)
+ - Increased the default RIPCache value to 128MB (STR #3535)
+ - MIME errors are now routed to the error_log file (STR #2410)
+ - Updated PDF filter to support new Ghostscript ps2write device
+ (STR #3766)
+ - Updated PDF filter to support new Poppler option to preserve page
+ sizes in PDF files when the user has not selected a particular media
+ size (STR #3689)
+ - Added new PWG Raster filter for IPP Everywhere printer support.
+ - Added job-uuid, printer-uuid, and subscription-uuid attributes.
+ - Added support for the cupsSingleFile PPD keyword.
+ - Dropped support for the printer-state-history attribute (STR #3654)
+ - Added support for a new cupsIPPSupplies keyword in PPD files to allow
+ drivers to disable IPP supply level reporting.
+ - Added support for a new cupsFilter2 keyword in PPD files to allow for
+ the propagation of the actual MIME media type produced by a filter.
+ - The scheduler did not always get the correct Kerberos username when
+ authenticating (STR #3670)
+ - Added new cupsRasterOpenIO function and CUPS_RASTER_WRITE_PWG to the
+ CUPS imaging library to support printing to IPP Everywhere raster
+ printers.
+ - The scheduler now provides default values for the pages-per-minute and
+ pages-per-minute-color attributes for PPD files that lack a
+ Throughput keyword.
+ - Email notifications did not work on Mac OS X.
+ - The cupstestppd program now shows an error for files missing a
+ CloseGroup keyword (STR #3668)
+ - Name resolution errors no longer cause queues to stop (STR #3719,
+ STR #3753)
+ - Added a new cups-exec helper program that applies security profiles
+ to filters, port monitors, backends, CGI programs, and mini-daemons.
+ - The web interface can now be disabled using the WebInterface directive
+ in cupsd.conf (STR #2625)
+ - The scheduler now provides privacy controls for jobs and subscriptions
+ (STR #2969)
+ - Added new cupsArrayNew3 API which offers memory management of array
+ elements.
+ - Added several new color spaces to the CUPS raster format (STR #3419)
+ - The Validate-Job operation now uses the same policy as Print-Job by
+ default.
+ - CUPS now uses iconv to implement all of its character encoding
+ support (STR #3097)
+ - The scheduler now implements the Cancel-Jobs, Cancel-My-Jobs, and
+ Close-Job operations along with the job-ids operation attribute from
+ PWG 5100.11.
+ - The main CUPS header (<cups/cups.h>) no longer includes the PPD header
+ (<cups/ppd.h>).
+ - The scheduler and CUPS API now support the print-quality job template
+ attribute.
+ - The scheduler no longer supports the old Mac OS X Server quota
+ plugin.
+ - The scheduler now allows writing to /Users/Shared from print filters
+ on Mac OS X.
+ - CUPS no longer supports the old ~/.cupsrc or ~/.lpoptions files from
+ CUPS 1.1.x. The ~/.cups/client.conf and ~/.cups/lpoptions files that
+ were introduced in CUPS 1.2 must now be used.
+ - The ipptest tool is now a first-class user program and has several
+ improvements along with new documentation (STR #3484)
+ - The cupstestppd tool now warns about non-unique filenames and
+ provides a way to ignore all filename warnings.
+ - Dropped support for the recoverable: and recovered: message prefixes.
+ - The scheduler now requires that filters and backends have group write
+ permissions disabled.
+ - The PPD compiler now checks for overlapping filenames when writing
+ PPD files.
+ - The HP-GL/2 filter is no longer included with CUPS (STR #3322)
+ - The SCSI backend is no longer included with CUPS (STR #3500)
diff --git a/CREDITS.txt b/CREDITS.txt
new file mode 100644
index 000000000..a241eef4d
--- /dev/null
+++ b/CREDITS.txt
@@ -0,0 +1,49 @@
+CREDITS.txt - 2010-03-13
+------------------------
+
+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().
+ Philippe Combes - French localization and buttons script.
+ 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.
+ I–aki Larra–aga - Basque localization.
+ Kenshi Muto - Japanese localization, patches, and
+ testing.
+ Tomohiro Kato - Japanese localization.
+ Kiko - Bug fixes.
+ Sergey V. Kovalyov - ESP Print Pro and CUPS beta tester.
+ Marek Laane - Estonian translation.
+ Mark Lawrence - Microsoft interoperability testing.
+ Jeff Licquia - Bug fixes, beta testing, evangelism.
+ Jason McMullan - Original CUPS RPM distributions.
+ Wes Morgan - *BSD fixes.
+ Daniel Nylander - Swedish localization.
+ Niklas 'Nille' kerstršm - Swedish localization.
+ Giulio Orsero - Bug fixes and testing.
+ Michal Osowiecki - Polish localization.
+ Citra Paska - Indonesian localization.
+ Kurt Pfeifle - Bug fixes, beta testing, evangelism.
+ Vincenzo Reale - Italian localization.
+ Petter Reinholdtsen - HP-UX compiler stuff.
+ Juan Pablo Gonz‡lez Riopedre - Spanish localization.
+ Opher Shachar - Hebrew localization.
+ Stuart Stevens - HP JetDirect IPP information.
+ Andrea Suatoni - IRIX desktop integration and testing.
+ Teppo Turliainen - Finnish localization.
+ Tim Waugh - Lots of patches, testing, and Linux
+ integration.
+ Yugami - LDAP browsing support.
+
+If I've missed someone, please let me know by sending an email to
+"msweet@apple.com".
diff --git a/INSTALL.txt b/INSTALL.txt
new file mode 100644
index 000000000..782737edc
--- /dev/null
+++ b/INSTALL.txt
@@ -0,0 +1,207 @@
+INSTALL - CUPS v1.5b1 - 2011-05-20
+----------------------------------
+
+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 AND ARE NOT ****
+**** RUNNING MAC OS X, YOU WILL ALSO NEED TO INSTALL GPL ****
+**** GHOSTSCRIPT WITH THE "cups" DRIVER AFTER YOU INSTALL ****
+**** CUPS. ****
+
+
+BEFORE YOU BEGIN
+
+ You'll need ANSI-compliant C and C++ compilers, plus a make program and
+ POSIX-compliant shell (/bin/sh). The GNU compiler tools and Bash work well
+ and we have tested the current CUPS code against several versions of GCC
+ with excellent results.
+
+ The makefiles used by the project should work with most versions of make.
+ We've tested them with GNU make as well as the make programs shipped by
+ Compaq, HP, SGI, and Sun. BSD users should use GNU make (gmake) since BSD
+ make does not support "include".
+
+ Besides these tools you'll want the JPEG, PNG, TIFF, and ZLIB libraries for
+ image support, the CDSA, GNU TLS, or OpenSSL libraries for encryption
+ support, the OpenLDAP and OpenSLP libraries for directory services support,
+ and either MIT (1.6.3 or higher) or Heimdal Kerberos for Kerberos support.
+ 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 does not include the Ghostscript-based
+ PostScript filter needed by non-PostScript printers. You *must* download
+ GPL Ghostscript separately from the CUPS web site if you want to print
+ PostScript files to non-PostScript printers on operating systems other than
+ Mac OS X.
+
+
+COMPILING THE SUBVERSION REPOSITORY CODE
+
+ The CUPS Subversion repository doesn't hold a copy of the pre-built
+ configure script. You'll need to run the GNU autoconf software (2.60 or
+ higher) to create it:
+
+ autoconf
+
+
+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
+
+ 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
+
+ To see a complete list of configuration options, use the --help option:
+
+ ./configure --help
+
+ If any of the dependent libraries are not installed in a system default
+ location (typically "/usr/include" and "/usr/lib") you'll need to set the
+ CFLAGS, CPPFLAGS, CXXFLAGS, DSOFLAGS, and LDFLAGS environment variables
+ prior to running configure:
+
+ setenv CFLAGS "-I/some/directory"
+ setenv CPPFLAGS "-I/some/directory"
+ setenv CXXFLAGS "-I/some/directory"
+ setenv DSOFLAGS "-L/some/directory"
+ setenv LDFLAGS "-L/some/directory"
+ ./configure ...
+
+ or:
+
+ CFLAGS="-I/some/directory" \
+ CPPFLAGS="-I/some/directory" \
+ CXXFLAGS="-I/some/directory" \
+ DSOFLAGS="-L/some/directory" \
+ LDFLAGS="-L/some/directory" \
+ ./configure ...
+
+ The "--enable-debug" option compiles CUPS with debugging information
+ enabled. Additional debug logging support can be enabled using the
+ "--enable-debug-printfs" option - these debug messages are enabled using the
+ CUPS_DEBUG_LOG environment variable at run-time.
+
+ CUPS also includes an extensive set of unit tests that can be used to find
+ and diagnose a variety of common problems - use the "--enable-unit-tests"
+ configure option to run them at build time.
+
+ Once you have configured things, just type:
+
+ make ENTER
+
+ or if you have FreeBSD, NetBSD, or OpenBSD type:
+
+ gmake ENTER
+
+ to build the software.
+
+
+TESTING THE SOFTWARE
+
+ Aside from the built-in unit tests, CUPS includes an automated test
+ framework for testing the entire printing system. To run the tests, just
+ type:
+
+ make check ENTER
+
+ or if you have FreeBSD, NetBSD, or OpenBSD type:
+
+ gmake check ENTER
+
+ The test framework runs a copy of the CUPS scheduler (cupsd) on port 8631
+ in /tmp/cups-$USER and produces a nice HTML report of the results.
+
+
+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 ("packaging/cups.spec") or EPM list file
+ ("packaging/cups.list"). The latter also supports building of binary RPMs,
+ so it may be more convenient to use.
+
+ You can find the RPM software at:
+
+ http://www.rpm.org/
+
+ The EPM software is available at:
+
+ http://www.epmhome.org/
+
+
+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 <format> ENTER
+
+ or
+
+ gmake <format> ENTER
+
+ for FreeBSD, NetBSD, and OpenBSD. The <format> target is one of the
+ following:
+
+ epm - Builds a script + tarfile package
+ aix - Builds an AIX package
+ bsd - Builds a *BSD package
+ deb - Builds a Debian package
+ depot - Builds a HP-UX package (also swinstall)
+ inst - Builds an IRIX package (also tardist)
+ pkg - Builds a Solaris package
+ rpm - Builds a RPM package
+ setld - Build a Tru64 UNIX package
+ slackware - Build a Slackware package
+ swinstall - Build a HP-UX package (also depot)
+ tardist - Builds an IRIX package (also inst)
+
+
+GETTING DEBUG LOGGING FROM CUPS
+
+ When configured with the "--enable-debug-printfs" option, CUPS compiles in
+ additional debug logging support in the scheduler, CUPS API, and CUPS
+ Imaging API. The following environment variables are used to enable and
+ control debug logging:
+
+ CUPS_DEBUG_FILTER Specifies a POSIX regular expression to control
+ which messages are logged.
+ CUPS_DEBUG_LEVEL Specifies a number from 0 to 9 to control the
+ verbosity of the logging. The default level is 1.
+ CUPS_DEBUG_LOG Specifies a log file to use. Specify the name "-"
+ to send the messages to stderr. Prefix a filename
+ with "+" to append to an existing file.
+
+
+REPORTING PROBLEMS
+
+ If you have problems, READ THE DOCUMENTATION FIRST! If the documentation
+ does not solve your problems, please post a message on the "cups.general"
+ forum at:
+
+ http://www.cups.org/newsgroups.php
+
+ Include your operating system and version, compiler and version, and any
+ errors or problems you've run into. The "config.log" file and the output
+ from the configure script and make 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.
diff --git a/IPPTOOL.txt b/IPPTOOL.txt
new file mode 100644
index 000000000..52094ea3d
--- /dev/null
+++ b/IPPTOOL.txt
@@ -0,0 +1,86 @@
+IPPTOOL.txt - 2011-05-20
+------------------------
+
+
+INTRODUCTION
+
+ Starting with CUPS 1.5, CUPS now installs a user program called ipptool that
+ can be used to send arbitrary IPP requests to a CUPS server or IPP printer.
+ This tool started life as part of the CUPS automated test suite and has
+ grown to support complex conformance tests and a simple way to query
+ printer, job, and subscription attributes.
+
+
+BASIC USAGE
+
+ The ipptool command requires a printer URI and one or more "test" files that
+ describe the operations, attributes to display, and expected status and
+ attribute values. Several standard files are included with CUPS, for example
+ to show a list of pending print jobs on a CUPS printer called "myprinter"
+ you'd run:
+
+ ipptool ipp://localhost/printers/myprinter get-jobs.test
+
+ which would produce something like this:
+
+ job-id job-state job-name job-originating-user-name
+ ------ ------------ ------------ -------------------------
+ 72 pending testfile.pdf msweet
+ 73 pending testfile.ps msweet
+ 74 pending-held testfile.jpg msweet
+ 75 pending-held testfile.txt msweet
+
+ To get output suitable for import into a spreadsheet, use the "-c" (CSV)
+ option:
+
+ ipptool -c ipp://localhost/printers/myprinter get-jobs.test
+
+ which would produce something like this:
+
+ job-id,job-state,job-name,job-originating-user-name
+ 72,pending,testfile.pdf,msweet
+ 73,pending,testfile.ps,msweet
+ 74,pending-held,testfile.jpg,msweet
+ 75,pending-held,testfile.txt,msweet
+
+
+CONFORMANCE TESTS
+
+ We provide basic IPP conformance tests for IPP/1.1, IPP/2.0, and IPP/2.1.
+ For a given printer URI, the following commands perform tests at each level:
+
+ ipptool -t printer-uri ipp-1.1.test
+ ipptool -t -V 2.0 printer-uri ipp-2.0.test
+ ipptool -t -V 2.1 printer-uri ipp-2.1.test
+
+
+READING THE DOCUMENTATION
+
+ The command usage is described in the ipptest(1) man page, while the file
+ format is described in the ipptestfile(5) man page.
+
+
+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
+
+ See the CUPS web site at "http://www.cups.org/" for other resources.
+
+
+LEGAL STUFF
+
+ CUPS is Copyright 2007-2011 by Apple Inc. CUPS and the CUPS logo are
+ trademarks of Apple Inc.
+
+ The MD5 Digest code is Copyright 1999 Aladdin Enterprises.
+
+ This software is based in part on the work of the Independent JPEG Group.
+
+ CUPS is provided under the terms of version 2 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 "doc/help/license.html" or "LICENSE.txt" files for more information.
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 000000000..7d80518a3
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,971 @@
+ CUPS License Agreement
+
+ Copyright 2007-2011 by Apple Inc.
+ 1 Infinite Loop
+ Cupertino, CA 95014 USA
+
+ WWW: http://www.cups.org/
+
+
+INTRODUCTION
+
+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 and CUPS Imaging libraries
+located in the "cups" and "filter" subdirectories of the CUPS
+source distribution and the files in the "test" subdirectory. The
+GNU GPL applies to the remainder of the CUPS distribution.
+
+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.
+
+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 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 and CUPS Imaging libraries
+under other licenses and/or conditions as appropriate for your
+application, driver, or filter.
+
+
+LICENSE EXCEPTIONS
+
+In addition, as the copyright holder of CUPS, Apple Inc. 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. Apple Inc. 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.
+
+
+KERBEROS SUPPORT CODE
+
+The Kerberos support code ("KSC") is copyright 2006 by Jelmer
+Vernooij and is provided 'as-is', without any express or implied
+warranty. In no event will the author or Apple Inc. be held
+liable for any damages arising from the use of the KSC.
+
+Sources files containing KSC have the following text at the top
+of each source file:
+
+ This file contains Kerberos support code, copyright 2006 by
+ Jelmer Vernooij.
+
+The KSC copyright and license apply only to Kerberos-related
+feature code in CUPS. Such code is typically conditionally
+compiled based on the present of the HAVE_GSSAPI preprocessor
+definition.
+
+Permission is granted to anyone to use the KSC for any purpose,
+including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+ 1. The origin of the KSC must not be misrepresented; you
+ must not claim that you wrote the original software. If
+ you use the KSC in a product, an acknowledgment in the
+ product documentation would be appreciated but is not
+ required.
+
+ 2. Altered source versions must be plainly marked as such,
+ and must not be misrepresented as being the original
+ software.
+
+ 3. This notice may not be removed or altered from any source
+ distribution.
+
+
+TRADEMARKS
+
+CUPS and the CUPS logo (the "CUPS Marks") are trademarks of Apple
+Inc. Apple grants you a non-exclusive and non-transferable right
+to use the CUPS Marks in any direct port or binary distribution
+incorporating CUPS software and in any promotional material
+therefor. You agree that your products will meet the highest
+levels of quality and integrity for similar goods, not be unlawful,
+and be developed, manufactured, and distributed in compliance with
+this license. You will not interfere with Apple's rights in the
+CUPS Marks, and all use of the CUPS Marks shall inure to the
+benefit of Apple. This license does not apply to use of the CUPS
+Marks in a derivative products, which requires prior written
+permission from Apple Inc.
+
+ 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <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., 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.
+
+ <signature of Ty Coon>, 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.
+
+ <one line to give the library's name and a brief 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 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.
+
+ <signature of Ty Coon>, 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..654eea48c
--- /dev/null
+++ b/Makedefs.in
@@ -0,0 +1,308 @@
+#
+# "$Id$"
+#
+# Common makefile definitions for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2007 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+#
+# Programs...
+#
+
+AR = @AR@
+AWK = @AWK@
+CC = @LIBTOOL@ @CC@
+CHMOD = @CHMOD@
+CXX = @LIBTOOL@ @CXX@
+DSO = @DSO@
+DSOXX = @DSOXX@
+HTMLDOC = @HTMLDOC@
+INSTALL = @INSTALL@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LN = @LN@ -sf
+MV = @MV@
+PHPCONFIG = @PHPCONFIG@
+RANLIB = @RANLIB@
+RM = @RM@ -f
+RMDIR = @RMDIR@
+SED = @SED@
+SHELL = /bin/sh
+
+#
+# Installation programs...
+#
+
+INSTALL_BIN = $(LIBTOOL) $(INSTALL) -c -m 555 @INSTALL_STRIP@
+INSTALL_CONFIG = $(INSTALL) -c -m @CUPS_CONFIG_FILE_PERM@
+INSTALL_DATA = $(INSTALL) -c -m 444
+INSTALL_DIR = $(INSTALL) -d
+INSTALL_LIB = $(LIBTOOL) $(INSTALL) -c -m 555 @INSTALL_STRIP@
+INSTALL_MAN = $(INSTALL) -c -m 444
+INSTALL_SCRIPT = $(INSTALL) -c -m 555
+
+#
+# Default user, group, and system groups for the scheduler...
+#
+
+CUPS_USER = @CUPS_USER@
+CUPS_GROUP = @CUPS_GROUP@
+CUPS_SYSTEM_GROUPS = @CUPS_SYSTEM_GROUPS@
+CUPS_PRIMARY_SYSTEM_GROUP = @CUPS_PRIMARY_SYSTEM_GROUP@
+
+#
+# Default permissions...
+#
+
+CUPS_CONFIG_FILE_PERM = @CUPS_CONFIG_FILE_PERM@
+CUPS_LOG_FILE_PERM = @CUPS_LOG_FILE_PERM@
+
+#
+# Languages to install...
+#
+
+LANGUAGES = @LANGUAGES@
+INSTALL_LANGUAGES = @INSTALL_LANGUAGES@
+UNINSTALL_LANGUAGES = @UNINSTALL_LANGUAGES@
+
+#
+# Libraries...
+#
+
+LIBCUPS = @LIBCUPS@
+LIBCUPSCGI = @LIBCUPSCGI@
+LIBCUPSDRIVER = @LIBCUPSDRIVER@
+LIBCUPSIMAGE = @LIBCUPSIMAGE@
+LIBCUPSMIME = @LIBCUPSMIME@
+LIBCUPSPPDC = @LIBCUPSPPDC@
+LIBCUPSSTATIC = @LIBCUPSSTATIC@
+LIBJPEG = @LIBJPEG@
+LIBLDAP = @LIBLDAP@
+LIBMALLOC = @LIBMALLOC@
+LIBPAPER = @LIBPAPER@
+LIBPNG = @LIBPNG@
+LIBSLP = @LIBSLP@
+LIBGSSAPI = @LIBGSSAPI@
+LIBTIFF = @LIBTIFF@
+LIBUSB = @LIBUSB@
+LIBWRAP = @LIBWRAP@
+LIBZ = @LIBZ@
+
+#
+# Install static libraries?
+#
+
+INSTALLSTATIC = @INSTALLSTATIC@
+
+#
+# IPP backend aliases...
+#
+
+IPPALIASES = @IPPALIASES@
+
+#
+# Install XPC backends?
+#
+
+INSTALLXPC = @INSTALLXPC@
+
+#
+# Program options...
+#
+# ARCHFLAGS Defines the default architecture build options.
+# ARCH32FLAGS Defines the 32-bit architecture build options, used
+# when compiling separate 32/64-bit libraries.
+# ARCH64FLAGS Defines the 64-bit architecture build options, used
+# when compiling separate 32/64-bit libraries.
+# OPTIM Defines the common compiler optimization/debugging options
+# for all architectures.
+# OPTIONS Defines other compile-time options (currently only -DDEBUG
+# for extra debug info)
+#
+
+ALL_CFLAGS = -I.. -D_CUPS_SOURCE $(CFLAGS) $(SSLFLAGS) \
+ @LARGEFILE@ @PTHREAD_FLAGS@ $(OPTIONS)
+ALL_CXXFLAGS = -I.. -D_CUPS_SOURCE $(CXXFLAGS) $(SSLFLAGS) \
+ @LARGEFILE@ @PTHREAD_FLAGS@ $(OPTIONS)
+ARCHFLAGS = @ARCHFLAGS@
+ARFLAGS = @ARFLAGS@
+BACKLIBS = @BACKLIBS@
+BANNERTOPS = @BANNERTOPS@
+BUILDDIRS = @BUILDDIRS@
+CFLAGS = @CPPFLAGS@ @CFLAGS@
+COMMONLIBS = @LIBS@
+CXXFLAGS = @CPPFLAGS@ @CXXFLAGS@
+CXXLIBS = @CXXLIBS@
+DBUS_NOTIFIER = @DBUS_NOTIFIER@
+DBUS_NOTIFIERLIBS = @DBUS_NOTIFIERLIBS@
+DNSSD_BACKEND = @DNSSD_BACKEND@
+DSOFLAGS = -L../cups @DSOFLAGS@
+DSOLIBS = @DSOLIBS@ $(COMMONLIBS)
+DNSSDLIBS = @DNSSDLIBS@
+FONTS = @FONTS@
+IMGLIBS = @IMGLIBS@
+IMGFILTERS = @IMGFILTERS@
+LAUNCHDLIBS = @LAUNCHDLIBS@
+LDFLAGS = -L../cgi-bin -L../cups -L../filter -L../ppdc \
+ -L../scheduler @LDARCHFLAGS@ \
+ @LDFLAGS@ @RELROFLAGS@ @PIEFLAGS@ $(OPTIM)
+LEGACY_BACKENDS = @LEGACY_BACKENDS@
+LINKCUPS = @LINKCUPS@ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(LIBZ)
+LINKCUPSIMAGE = @LINKCUPSIMAGE@
+LIBS = $(LINKCUPS) $(COMMONLIBS)
+OPTIM = @OPTIM@
+OPTIONS =
+PAMLIBS = @PAMLIBS@
+PAP = @PAP@
+PDFTOPS = @PDFTOPS@
+PHPDIR = @PHPDIR@
+PHPOPTIONS = @PHPOPTIONS@ -I../.. `$(PHPCONFIG) --includes`
+SERVERLIBS = @SERVERLIBS@
+SSLFLAGS = @SSLFLAGS@
+SSLLIBS = @SSLLIBS@
+TEXTTOPS = @TEXTTOPS@
+UNITTESTS = @UNITTESTS@
+
+
+#
+# Separate 32/64-bit library support...
+#
+
+ARCH32FLAGS = @ARCH32FLAGS@
+DSO32FLAGS = @DSO32FLAGS@
+INSTALL32 = @INSTALL32@
+LIB32CUPS = @LIB32CUPS@
+LIB32CUPSIMAGE = @LIB32CUPSIMAGE@
+LIB32DIR = $(BUILDROOT)@LIB32DIR@
+UNINSTALL32 = @UNINSTALL32@
+
+ARCH64FLAGS = @ARCH64FLAGS@
+DSO64FLAGS = @DSO64FLAGS@
+INSTALL64 = @INSTALL64@
+LIB64CUPS = @LIB64CUPS@
+LIB64CUPSIMAGE = @LIB64CUPSIMAGE@
+LIB64DIR = $(BUILDROOT)@LIB64DIR@
+UNINSTALL64 = @UNINSTALL64@
+
+#
+# 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...
+#
+# The "datarootdir" variable may not get defined if you are using
+# a version of autoconf prior to 2.60.
+#
+# This is immediately followed by definition in ALL CAPS for the
+# needed directories...
+#
+
+bindir = @bindir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+exec_prefix = @exec_prefix@
+includedir = @includedir@
+infodir = @infodir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+privateinclude = @privateinclude@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+top_srcdir = @top_srcdir@
+
+BUILDROOT = $(DSTROOT)
+
+AMANDIR = $(BUILDROOT)@AMANDIR@
+BINDIR = $(BUILDROOT)@bindir@
+BUNDLEDIR = @CUPS_BUNDLEDIR@
+CACHEDIR = $(BUILDROOT)@CUPS_CACHEDIR@
+DATADIR = $(BUILDROOT)@CUPS_DATADIR@
+DOCDIR = $(BUILDROOT)@CUPS_DOCROOT@
+ICONDIR = @ICONDIR@
+INCLUDEDIR = $(BUILDROOT)$(includedir)
+INITDIR = @INITDIR@
+INITDDIR = @INITDDIR@
+LIBDIR = $(BUILDROOT)$(libdir)
+LOCALEDIR = $(BUILDROOT)@CUPS_LOCALEDIR@
+LOGDIR = $(BUILDROOT)@CUPS_LOGDIR@
+MANDIR = $(BUILDROOT)@mandir@
+MENUDIR = @MENUDIR@
+PMANDIR = $(BUILDROOT)@PMANDIR@
+PRIVATEINCLUDE = $(BUILDROOT)@PRIVATEINCLUDE@
+RCLEVELS = @RCLEVELS@
+RCSTART = @RCSTART@
+RCSTOP = @RCSTOP@
+REQUESTS = $(BUILDROOT)@CUPS_REQUESTS@
+SBINDIR = $(BUILDROOT)@sbindir@
+SERVERBIN = $(BUILDROOT)@CUPS_SERVERBIN@
+SERVERROOT = $(BUILDROOT)@CUPS_SERVERROOT@
+SMFMANIFESTDIR = @SMFMANIFESTDIR@
+STATEDIR = $(BUILDROOT)@CUPS_STATEDIR@
+XINETD = @XINETD@
+
+MAN1EXT = @MAN1EXT@
+MAN5EXT = @MAN5EXT@
+MAN7EXT = @MAN7EXT@
+MAN8EXT = @MAN8EXT@
+MAN8DIR = @MAN8DIR@
+
+PAMDIR = @PAMDIR@
+PAMFILE = @PAMFILE@
+
+DEFAULT_LAUNCHD_CONF = @DEFAULT_LAUNCHD_CONF@
+DBUSDIR = @DBUSDIR@
+
+
+#
+# Rules...
+#
+
+.SILENT:
+.SUFFIXES: .1 .1.gz .1m .1m.gz .3 .3.gz .5 .5.gz .7 .7.gz .8 .8.gz .a .c .cxx .h .man .o .32.o .64.o .gz
+
+.c.o:
+ echo Compiling $<...
+ $(CC) $(ARCHFLAGS) $(OPTIM) $(ALL_CFLAGS) -c -o $@ $<
+
+.c.32.o:
+ echo Compiling 32-bit $<...
+ $(CC) $(ARCH32FLAGS) $(OPTIM) $(ALL_CFLAGS) -c -o $@ $<
+
+.c.64.o:
+ echo Compiling 64-bit $<...
+ $(CC) $(ARCH64FLAGS) $(OPTIM) $(ALL_CFLAGS) -c -o $@ $<
+
+.cxx.o:
+ echo Compiling $<...
+ $(CXX) $(ARCHFLAGS) $(OPTIM) $(ALL_CXXFLAGS) -c -o $@ $<
+
+.man.1 .man.1m .man.3 .man.5 .man.7 .man.8:
+ echo Linking $<...
+ $(RM) $@
+ $(LN) $< $@
+
+.man.1.gz .man.1m.gz .man.3.gz .man.5.gz .man.7.gz .man.8.gz .man.gz:
+ echo -n Compressing $<...
+ $(RM) $@
+ gzip -v9 <$< >$@
+
+
+#
+# End of "$Id$"
+#
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000..319fd18f7
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,330 @@
+#
+# "$Id$"
+#
+# Top-level Makefile for CUPS.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 1997-2007 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include Makedefs
+
+
+#
+# Directories to make...
+#
+
+DIRS = cups test $(BUILDDIRS) $(PHPDIR) $(FONTS)
+
+
+#
+# Make all targets...
+#
+
+all:
+ chmod +x cups-config
+ echo Using ARCHFLAGS="$(ARCHFLAGS)"
+ echo Using ALL_CFLAGS="$(ALL_CFLAGS)"
+ echo Using ALL_CXXFLAGS="$(ALL_CXXFLAGS)"
+ echo Using CC="$(CC)"
+ echo Using CXX="$(CC)"
+ echo Using DSOFLAGS="$(DSOFLAGS)"
+ echo Using LDFLAGS="$(LDFLAGS)"
+ echo Using LIBS="$(LIBS)"
+ for dir in $(DIRS); do\
+ echo Making all in $$dir... ;\
+ (cd $$dir ; $(MAKE) $(MFLAGS) all $(UNITTESTS)) || exit 1;\
+ done
+
+
+#
+# Make library targets...
+#
+
+libs:
+ echo Using ARCHFLAGS="$(ARCHFLAGS)"
+ echo Using ALL_CFLAGS="$(ALL_CFLAGS)"
+ echo Using ALL_CXXFLAGS="$(ALL_CXXFLAGS)"
+ echo Using CC="$(CC)"
+ echo Using CXX="$(CC)"
+ echo Using DSOFLAGS="$(DSOFLAGS)"
+ echo Using LDFLAGS="$(LDFLAGS)"
+ echo Using LIBS="$(LIBS)"
+ for dir in $(DIRS); do\
+ echo Making libraries in $$dir... ;\
+ (cd $$dir ; $(MAKE) $(MFLAGS) libs) || exit 1;\
+ done
+
+
+#
+# Make unit test targets...
+#
+
+unittests:
+ echo Using ARCHFLAGS="$(ARCHFLAGS)"
+ echo Using ALL_CFLAGS="$(ALL_CFLAGS)"
+ echo Using ALL_CXXFLAGS="$(ALL_CXXFLAGS)"
+ echo Using CC="$(CC)"
+ echo Using CXX="$(CC)"
+ echo Using DSOFLAGS="$(DSOFLAGS)"
+ echo Using LDFLAGS="$(LDFLAGS)"
+ echo Using LIBS="$(LIBS)"
+ for dir in $(DIRS); do\
+ echo Making all in $$dir... ;\
+ (cd $$dir ; $(MAKE) $(MFLAGS) unittests) || 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
+
+
+#
+# Remove all non-distribution files...
+#
+
+distclean: clean
+ $(RM) Makedefs config.h config.log config.status
+ $(RM) cups-config
+ $(RM) conf/cupsd.conf conf/mime.convs conf/pam.std conf/snmp.conf
+ $(RM) doc/help/ref-cupsd-conf.html doc/help/standard.html doc/index.html
+ $(RM) man/client.conf.man
+ $(RM) man/cups-deviced.man man/cups-driverd.man
+ $(RM) man/cups-lpd.man man/cupsaddsmb.man man/cupsd.man
+ $(RM) man/cupsd.conf.man man/drv.man man/lpoptions.man
+ $(RM) packaging/cups.list
+ $(RM) packaging/cups-desc.plist packaging/cups-info.plist
+ $(RM) templates/header.tmpl
+ $(RM) desktop/cups.desktop
+ $(RM) scheduler/cups.sh scheduler/cups-lpd.xinetd
+ $(RM) scheduler/org.cups.cups-lpd.plist scheduler/cups.xml
+ -$(RM) doc/*/index.html
+ -$(RM) templates/*/header.tmpl
+ -$(RM) -r autom4te*.cache clang cups/charmaps cups/locale driver/test
+
+
+#
+# Make dependencies
+#
+
+depend:
+ for dir in $(DIRS); do\
+ echo Making dependencies in $$dir... ;\
+ (cd $$dir; $(MAKE) $(MFLAGS) depend) || exit 1;\
+ done
+
+
+#
+# Run the clang.llvm.org static code analysis tool on the C sources.
+# (at least checker-231 is required for scan-build to work this way)
+#
+
+.PHONY: clang clang-changes
+clang:
+ $(RM) -r clang
+ scan-build -V -k -o `pwd`/clang $(MAKE) $(MFLAGS) clean all
+clang-changes:
+ scan-build -V -k -o `pwd`/clang $(MAKE) $(MFLAGS) all
+
+
+#
+# Generate a ctags file...
+#
+
+ctags:
+ ctags -R .
+
+
+#
+# Install everything...
+#
+
+install: install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+ echo Making all in cups...
+ (cd cups; $(MAKE) $(MFLAGS) all)
+ for dir in $(DIRS); do\
+ echo Installing data files in $$dir... ;\
+ (cd $$dir; $(MAKE) $(MFLAGS) install-data) || exit 1;\
+ done
+ echo Installing cups-config script...
+ $(INSTALL_DIR) -m 755 $(BINDIR)
+ $(INSTALL_SCRIPT) cups-config $(BINDIR)/cups-config
+
+
+#
+# Install header files...
+#
+
+install-headers:
+ for dir in $(DIRS); do\
+ echo Installing header files in $$dir... ;\
+ (cd $$dir; $(MAKE) $(MFLAGS) install-headers) || exit 1;\
+ done
+ if test "x$(privateinclude)" != x; then \
+ echo Installing config.h into $(PRIVATEINCLUDE)...; \
+ $(INSTALL_DIR) -m 755 $(PRIVATEINCLUDE); \
+ $(INSTALL_DATA) config.h $(PRIVATEINCLUDE)/config.h; \
+ fi
+
+
+#
+# Install programs...
+#
+
+install-exec: all
+ for dir in $(DIRS); do\
+ echo Installing programs in $$dir... ;\
+ (cd $$dir; $(MAKE) $(MFLAGS) install-exec) || exit 1;\
+ done
+
+
+#
+# Install libraries...
+#
+
+install-libs: libs
+ for dir in $(DIRS); do\
+ echo Installing libraries in $$dir... ;\
+ (cd $$dir; $(MAKE) $(MFLAGS) install-libs) || exit 1;\
+ done
+
+
+#
+# Uninstall object and target files...
+#
+
+uninstall:
+ for dir in $(DIRS); do\
+ echo Uninstalling in $$dir... ;\
+ (cd $$dir; $(MAKE) $(MFLAGS) uninstall) || exit 1;\
+ done
+ echo Uninstalling cups-config script...
+ $(RM) $(BINDIR)/cups-config
+ -$(RMDIR) $(BINDIR)
+
+
+#
+# Run the test suite...
+#
+
+test: all unittests
+ echo Running CUPS test suite...
+ cd test; ./run-stp-tests.sh
+
+
+check: all unittests
+ echo Running CUPS test suite with defaults...
+ cd test; ./run-stp-tests.sh 1 0 n
+
+
+#
+# Create HTML documentation...
+#
+
+apihelp:
+ for dir in cgi-bin cups filter driver ppdc scheduler; do\
+ echo Generating API help in $$dir... ;\
+ (cd $$dir; $(MAKE) $(MFLAGS) apihelp) || exit 1;\
+ done
+
+framedhelp:
+ for dir in cgi-bin cups filter driver ppdc scheduler; do\
+ echo Generating framed API help in $$dir... ;\
+ (cd $$dir; $(MAKE) $(MFLAGS) framedhelp) || exit 1;\
+ done
+
+
+#
+# Create an Xcode docset...
+#
+
+docset: apihelp
+ echo Generating docset directory tree...
+ $(RM) -r org.cups.docset
+ mkdir -p org.cups.docset/Contents/Resources/Documentation/help
+ mkdir -p org.cups.docset/Contents/Resources/Documentation/images
+ cd man; $(MAKE) $(MFLAGS) html
+ cd doc; $(MAKE) $(MFLAGS) docset
+ cd cgi-bin; $(MAKE) $(MFLAGS) makedocset
+ cgi-bin/makedocset org.cups.docset \
+ `svnversion . | sed -e '1,$$s/[a-zA-Z]//g'` \
+ doc/help/api-*.tokens
+ $(RM) doc/help/api-*.tokens
+ echo Indexing docset...
+ /Developer/usr/bin/docsetutil index org.cups.docset
+ echo Generating docset archive and feed...
+ $(RM) org.cups.docset.atom
+ /Developer/usr/bin/docsetutil package --output org.cups.docset.xar \
+ --atom org.cups.docset.atom \
+ --download-url http://www.cups.org/org.cups.docset.xar \
+ org.cups.docset
+
+
+#
+# Lines of code computation...
+#
+
+sloc:
+ for dir in cups cupslite scheduler; do \
+ (cd $$dir; $(MAKE) $(MFLAGS) sloc) || exit 1;\
+ done
+
+
+#
+# Make software distributions using EPM (http://www.epmhome.org/)...
+#
+
+EPMFLAGS = -v --output-dir dist $(EPMARCH)
+
+aix bsd deb depot inst pkg setld slackware swinstall tardist:
+ epm $(EPMFLAGS) -f $@ cups packaging/cups.list
+
+epm:
+ epm $(EPMFLAGS) -s packaging/installer.gif cups packaging/cups.list
+
+rpm:
+ epm $(EPMFLAGS) -f rpm -s packaging/installer.gif cups packaging/cups.list
+
+.PHONEY: dist
+dist: all
+ $(RM) -r dist
+ $(MAKE) $(MFLAGS) epm
+ case `uname` in \
+ *BSD*) $(MAKE) $(MFLAGS) bsd;; \
+ Darwin*) $(MAKE) $(MFLAGS) osx;; \
+ IRIX*) $(MAKE) $(MFLAGS) tardist;; \
+ Linux*) test ! -x /usr/bin/rpm || $(MAKE) $(MFLAGS) rpm;; \
+ SunOS*) $(MAKE) $(MFLAGS) pkg;; \
+ esac
+
+
+#
+# Don't run top-level build targets in parallel...
+#
+
+.NOTPARALLEL:
+
+
+#
+# End of "$Id$".
+#
diff --git a/README.txt b/README.txt
new file mode 100644
index 000000000..33a4861d6
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,164 @@
+README - CUPS v1.5b1 - 2011-05-20
+---------------------------------
+
+Looking for compile instructions? Read the file "INSTALL.txt"
+instead...
+
+
+INTRODUCTION
+
+ CUPS is a standards-based, open source printing system developed by Apple
+ Inc. for Mac OS® X and other UNIX®-like operating systems. CUPS uses the
+ Internet Printing Protocol ("IPP") and provides System V and Berkeley
+ command-line interfaces, a web interface, and a C API to manage printers and
+ print jobs. It supports printing to both local (parallel, serial, USB) and
+ networked printers, and printers can be shared from one computer to another,
+ even over the Internet!
+
+ Internally, CUPS uses PostScript Printer Description ("PPD") files to
+ describe printer capabilities and features and a wide variety of generic
+ and device-specific programs to convert and print many types of files.
+ Sample drivers are included with CUPS to support many Dymo, EPSON, HP,
+ Intellitech, OKIDATA, and Zebra printers. Many more drivers are available
+ online and (in some cases) on the driver CD-ROM that came with your printer.
+
+ CUPS is licensed under the GNU General Public License and GNU Library
+ General Public License versions 2. See the file "LICENSE.txt" for more
+ information.
+
+
+READING THE DOCUMENTATION
+
+ Once you have installed the software you can access the documentation (and
+ a bunch of other stuff) online at:
+
+ http://localhost:631/
+
+ If you're having trouble getting that far, the documentation is located
+ under the "doc/help" directory.
+
+ 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
+
+ See the CUPS web site at "http://www.cups.org/" for other resources.
+
+
+SETTING UP PRINTER QUEUES USING YOUR WEB BROWSER
+
+ CUPS includes a web-based administration tool that allows you to manage
+ printers, classes, and jobs on your server. Open the following URL in your
+ browser to access the printer administration tools:
+
+ http://localhost:631/admin/
+
+ DO NOT use the hostname for your machine - it will not work with the default
+ CUPS configuration. To enable administration access on other addresses,
+ check the "Allow Remote Administration" box and click on the "Change
+ Settings" button.
+
+ You will be asked for the administration password (root or any other user in
+ the sys/system/root/admin/lpadmin group on your system) when performing any
+ administrative function.
+
+
+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.
+
+ CUPS includes several sample PPD files you can use:
+
+ Driver PPD Name
+ ----------------------------- ------------------------------
+ Dymo Label Printers drv:///sample.drv/dymo.ppd
+ Intellitech Intellibar drv:///sample.drv/intelbar.ppd
+ EPSON Stylus Color Series drv:///sample.drv/stcolor.ppd
+ EPSON Stylus Photo Series drv:///sample.drv/stphoto.ppd
+ EPSON Stylus New Color Series drv:///sample.drv/stcolor2.ppd
+ EPSON Stylus New Photo Series drv:///sample.drv/stphoto2.ppd
+ EPSON 9-pin Series drv:///sample.drv/epson9.ppd
+ EPSON 24-pin Series drv:///sample.drv/epson24.ppd
+ Generic PCL Laser Printer drv:///sample.drv/generpcl.ppd
+ Generic PostScript Printer drv:///sample.drv/generic.ppd
+ HP DeskJet Series drv:///sample.drv/deskjet.ppd
+ HP LaserJet Series drv:///sample.drv/laserjet.ppd
+ OKIDATA 9-Pin Series drv:///sample.drv/okidata9.ppd
+ OKIDATA 24-Pin Series drv:///sample.drv/okidat24.ppd
+ Zebra CPCL Label Printer drv:///sample.drv/zebracpl.ppd
+ Zebra EPL1 Label Printer drv:///sample.drv/zebraep1.ppd
+ Zebra EPL2 Label Printer drv:///sample.drv/zebraep2.ppd
+ Zebra ZPL Label Printer drv:///sample.drv/zebra.ppd
+
+ Run the "lpinfo -m" command to list the available drivers:
+
+ lpinfo -m
+
+ Run the "lpinfo -v" command to list the available printers:
+
+ lpinfo -v
+
+ Then use the correct URI to add the printer using the "lpadmin" command:
+
+ lpadmin -p printername -E -v device-uri -m ppd-name
+
+ Network printers typically use "socket" or "lpd" URIs:
+
+ lpadmin -p printername -E -v socket://11.22.33.44 -m ppd-name
+ lpadmin -p printername -E -v lpd://11.22.33.44/ -m ppd-name
+
+ The sample drivers provide basic printing capabilities, but generally do not
+ exercise the full potential of the printers or CUPS. The CUPS web site
+ provides links and drivers:
+
+ http://www.cups.org/ppd.php PPD files
+ http://www.cups.org/links.php Links to other drivers
+
+
+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 -o media=A4 -o resolution=600dpi filename
+ lpr -o media=A4 -o resolution=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 -o raw filename
+ lpr -l filename
+
+ This will prevent the filters from misinterpreting your print
+ file.
+
+
+LEGAL STUFF
+
+ CUPS is Copyright 2007-2011 by Apple Inc. CUPS and the CUPS logo are
+ trademarks of Apple Inc.
+
+ The MD5 Digest code is Copyright 1999 Aladdin Enterprises.
+
+ This software is based in part on the work of the Independent JPEG Group.
+
+ CUPS is provided under the terms of version 2 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 "doc/help/license.html" or "LICENSE.txt" files for more information.
diff --git a/backend/Dependencies b/backend/Dependencies
new file mode 100644
index 000000000..4f99c17ef
--- /dev/null
+++ b/backend/Dependencies
@@ -0,0 +1,101 @@
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+ipp.o: backend-private.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ipp.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+ipp.o: ../cups/language.h ../cups/string-private.h ../config.h
+ipp.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ipp.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ipp.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ipp.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ipp.o: ../cups/thread-private.h ../cups/snmp-private.h ../cups/backend.h
+ipp.o: ../cups/sidechannel.h ../cups/array-private.h
+lpd.o: ../cups/http-private.h ../config.h ../cups/http.h
+lpd.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+lpd.o: backend-private.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+lpd.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+lpd.o: ../cups/language.h ../cups/string-private.h ../cups/debug-private.h
+lpd.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+lpd.o: ../cups/pwg-private.h ../cups/http-private.h
+lpd.o: ../cups/language-private.h ../cups/transcode.h
+lpd.o: ../cups/thread-private.h ../cups/snmp-private.h ../cups/backend.h
+lpd.o: ../cups/sidechannel.h
+dnssd.o: backend-private.h ../cups/cups-private.h ../cups/cups.h
+dnssd.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+dnssd.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+dnssd.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+dnssd.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+dnssd.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+dnssd.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+dnssd.o: ../cups/transcode.h ../cups/thread-private.h ../cups/snmp-private.h
+dnssd.o: ../cups/backend.h ../cups/sidechannel.h ../cups/array.h
+parallel.o: backend-private.h ../cups/cups-private.h ../cups/cups.h
+parallel.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+parallel.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+parallel.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+parallel.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+parallel.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+parallel.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+parallel.o: ../cups/transcode.h ../cups/thread-private.h
+parallel.o: ../cups/snmp-private.h ../cups/backend.h ../cups/sidechannel.h
+serial.o: backend-private.h ../cups/cups-private.h ../cups/cups.h
+serial.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+serial.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+serial.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+serial.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+serial.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+serial.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+serial.o: ../cups/transcode.h ../cups/thread-private.h ../cups/snmp-private.h
+serial.o: ../cups/backend.h ../cups/sidechannel.h
+snmp.o: backend-private.h ../cups/cups-private.h ../cups/cups.h
+snmp.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+snmp.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+snmp.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+snmp.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+snmp.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+snmp.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+snmp.o: ../cups/transcode.h ../cups/thread-private.h ../cups/snmp-private.h
+snmp.o: ../cups/backend.h ../cups/sidechannel.h ../cups/array.h
+snmp.o: ../cups/file.h ../cups/http-private.h
+socket.o: ../cups/http-private.h ../config.h ../cups/http.h
+socket.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+socket.o: backend-private.h ../cups/cups-private.h ../cups/cups.h
+socket.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+socket.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+socket.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+socket.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+socket.o: ../cups/language-private.h ../cups/transcode.h
+socket.o: ../cups/thread-private.h ../cups/snmp-private.h ../cups/backend.h
+socket.o: ../cups/sidechannel.h
+test1284.o: ../cups/string-private.h ../config.h ieee1284.c backend-private.h
+test1284.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+test1284.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+test1284.o: ../cups/language.h ../cups/string-private.h
+test1284.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+test1284.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+test1284.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+test1284.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+test1284.o: ../cups/thread-private.h ../cups/snmp-private.h ../cups/backend.h
+test1284.o: ../cups/sidechannel.h
+testbackend.o: ../cups/string-private.h ../config.h ../cups/cups.h
+testbackend.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+testbackend.o: ../cups/http.h ../cups/array.h ../cups/language.h
+testbackend.o: ../cups/sidechannel.h
+testsupplies.o: backend-private.h ../cups/cups-private.h ../cups/cups.h
+testsupplies.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+testsupplies.o: ../cups/http.h ../cups/array.h ../cups/language.h
+testsupplies.o: ../cups/string-private.h ../config.h ../cups/debug-private.h
+testsupplies.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+testsupplies.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+testsupplies.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+testsupplies.o: ../cups/language-private.h ../cups/transcode.h
+testsupplies.o: ../cups/thread-private.h ../cups/snmp-private.h
+testsupplies.o: ../cups/backend.h ../cups/sidechannel.h
+usb.o: backend-private.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+usb.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+usb.o: ../cups/language.h ../cups/string-private.h ../config.h
+usb.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+usb.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+usb.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+usb.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+usb.o: ../cups/thread-private.h ../cups/snmp-private.h ../cups/backend.h
+usb.o: ../cups/sidechannel.h
diff --git a/backend/Makefile b/backend/Makefile
new file mode 100644
index 000000000..1f298bfa7
--- /dev/null
+++ b/backend/Makefile
@@ -0,0 +1,285 @@
+#
+# "$Id$"
+#
+# Backend makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2007 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# This file is subject to the Apple OS-Developed Software exception.
+#
+
+include ../Makedefs
+
+#
+# Object files...
+#
+
+RBACKENDS = ipp lpd $(DNSSD_BACKEND)
+UBACKENDS = $(LEGACY_BACKENDS) serial snmp socket usb
+UNITTESTS = test1284 testbackend testsupplies
+TARGETS = libbackend.a $(RBACKENDS) $(UBACKENDS)
+LIBOBJS = ieee1284.o network.o runloop.o snmp-supplies.o
+OBJS = ipp.o lpd.o dnssd.o parallel.o serial.o snmp.o \
+ socket.o test1284.o testbackend.o testsupplies.o usb.o
+
+
+#
+# Make all targets...
+#
+
+all: $(TARGETS)
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests: $(UNITTESTS)
+
+
+#
+# Clean all object files...
+#
+
+clean:
+ $(RM) $(OBJS) $(TARGETS) $(UNITTESTS) $(LIBOBJS) http mdns
+
+
+#
+# Update dependencies (without system header dependencies...)
+#
+
+depend:
+ makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+
+
+#
+# Install programs...
+#
+
+install-exec: $(INSTALLXPC)
+ echo Installing backends in $(SERVERBIN)/backend
+ $(INSTALL_DIR) -m 755 $(SERVERBIN)/backend
+ for file in $(RBACKENDS); do \
+ $(LIBTOOL) $(INSTALL_BIN) -m 700 $$file $(SERVERBIN)/backend; \
+ done
+ for file in $(UBACKENDS); do \
+ $(INSTALL_BIN) $$file $(SERVERBIN)/backend; \
+ done
+ for file in $(IPPALIASES); do \
+ $(RM) $(SERVERBIN)/backend/$$file; \
+ $(LN) ipp $(SERVERBIN)/backend/$$file; \
+ done
+ if test "x$(DNSSD_BACKEND)" != x; then \
+ $(RM) $(SERVERBIN)/backend/mdns; \
+ $(LN) $(DNSSD_BACKEND) $(SERVERBIN)/backend/mdns; \
+ fi
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ for file in $(TARGETS); do \
+ cp $$file $(SYMROOT); \
+ done \
+ fi
+
+install-xpc: ipp
+ echo Installing XPC backends in $(SERVERBIN)/apple
+ $(INSTALL_DIR) -m 755 $(SERVERBIN)/apple
+ $(LIBTOOL) $(INSTALL_BIN) ipp $(SERVERBIN)/apple
+ for file in $(IPPALIASES); do \
+ $(RM) $(SERVERBIN)/apple/$$file; \
+ $(LN) ipp $(SERVERBIN)/apple/$$file; \
+ done
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall all targets...
+#
+
+uninstall:
+ $(RM) $(SERVERBIN)/apple/ipp
+ for file in $(IPPALIASES); do \
+ $(RM) $(SERVERBIN)/apple/$$file; \
+ done
+ -$(RMDIR) $(SERVERBIN)/apple
+ for file in $(RBACKENDS) $(UBACKENDS); do \
+ $(RM) $(SERVERBIN)/backend/$$file; \
+ done
+ for file in $(IPPALIASES); do \
+ $(RM) $(SERVERBIN)/backend/$$file; \
+ done
+ -$(RMDIR) $(SERVERBIN)/backend
+ -$(RMDIR) $(SERVERBIN)
+
+
+#
+# test1284
+#
+
+test1284: test1284.o ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o test1284 test1284.o ../cups/$(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# testbackend
+#
+
+testbackend: testbackend.o ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o testbackend testbackend.o ../cups/$(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# testsupplies
+#
+
+testsupplies: testsupplies.o libbackend.a ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o testsupplies testsupplies.o libbackend.a \
+ ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ $(COMMONLIBS) $(LIBZ)
+
+
+#
+# libbackend.a
+#
+
+libbackend.a: $(LIBOBJS)
+ echo Archiving $@...
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ $(LIBOBJS)
+ $(RANLIB) $@
+
+
+#
+# dnssd
+#
+
+dnssd: dnssd.o ../cups/$(LIBCUPS) libbackend.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o dnssd dnssd.o libbackend.a $(LIBS)
+ $(RM) mdns
+ $(LN) dnssd mdns
+
+
+#
+# ipp
+#
+
+ipp: ipp.o ../cups/$(LIBCUPS) libbackend.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o ipp ipp.o libbackend.a $(LIBS)
+ $(RM) http
+ $(LN) ipp http
+
+
+#
+# lpd
+#
+
+lpd: lpd.o ../cups/$(LIBCUPS) libbackend.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpd lpd.o libbackend.a $(LIBS)
+
+
+#
+# parallel
+#
+
+parallel: parallel.o ../cups/$(LIBCUPS) libbackend.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o parallel parallel.o libbackend.a $(LIBS)
+
+
+#
+# serial
+#
+
+serial: serial.o ../cups/$(LIBCUPS) libbackend.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o serial serial.o libbackend.a $(BACKLIBS) $(LIBS)
+
+
+#
+# snmp
+#
+
+snmp: snmp.o ../cups/$(LIBCUPS) libbackend.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o snmp snmp.o libbackend.a $(LIBS)
+
+
+#
+# socket
+#
+
+socket: socket.o ../cups/$(LIBCUPS) libbackend.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o socket socket.o libbackend.a $(LIBS)
+
+
+#
+# usb
+#
+
+usb: usb.o ../cups/$(LIBCUPS) libbackend.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o usb usb.o libbackend.a $(LIBUSB) \
+ $(BACKLIBS) $(LIBS)
+usb.o: usb.c usb-darwin.c usb-libusb.c usb-unix.c
+
+
+#
+# Dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id$".
+#
diff --git a/backend/backend-private.h b/backend/backend-private.h
new file mode 100644
index 000000000..626681859
--- /dev/null
+++ b/backend/backend-private.h
@@ -0,0 +1,323 @@
+/*
+ * "$Id$"
+ *
+ * Backend support definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_BACKEND_PRIVATE_H_
+# define _CUPS_BACKEND_PRIVATE_H_
+
+
+/*
+ * Include necessary headers.
+ */
+
+# include <cups/cups-private.h>
+# include <cups/snmp-private.h>
+# include <cups/backend.h>
+# include <cups/sidechannel.h>
+# include <signal.h>
+
+# ifdef __linux
+# include <sys/ioctl.h>
+# include <linux/lp.h>
+# define IOCNR_GET_DEVICE_ID 1
+# define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
+# include <linux/parport.h>
+# include <linux/ppdev.h>
+# include <unistd.h>
+# include <fcntl.h>
+# endif /* __linux */
+
+# ifdef __sun
+# ifdef __sparc
+# include <sys/ecppio.h>
+# else
+# include <sys/ioccom.h>
+# include <sys/ecppsys.h>
+# endif /* __sparc */
+# endif /* __sun */
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * OID constants...
+ */
+
+/* Host MIB */
+#define CUPS_OID_mib2 1,3,6,1,2,1
+
+#define CUPS_OID_system CUPS_OID_mib2,1
+#define CUPS_OID_sysLocation CUPS_OID_system,6
+
+#define CUPS_OID_host CUPS_OID_mib2,25
+
+#define CUPS_OID_hrSystem CUPS_OID_host,1
+
+#define CUPS_OID_hrStorage CUPS_OID_host,2
+
+#define CUPS_OID_hrDevice CUPS_OID_host,3
+#define CUPS_OID_hrDeviceTable CUPS_OID_hrDevice,2
+#define CUPS_OID_hrDeviceEntry CUPS_OID_hrDeviceTable,1
+#define CUPS_OID_hrDeviceIndex CUPS_OID_hrDeviceEntry,1
+#define CUPS_OID_hrDeviceType CUPS_OID_hrDeviceEntry,2
+#define CUPS_OID_hrDeviceDescr CUPS_OID_hrDeviceEntry,3
+
+#define CUPS_OID_hrPrinterTable CUPS_OID_hrDevice,5
+#define CUPS_OID_hrPrinterEntry CUPS_OID_hrPrinterTable,1
+#define CUPS_OID_hrPrinterStatus CUPS_OID_hrPrinterEntry,1
+#define CUPS_OID_hrPrinterDetectedErrorState CUPS_OID_hrPrinterEntry,2
+
+/* Printer MIB */
+#define CUPS_OID_printmib CUPS_OID_mib2,43
+
+#define CUPS_OID_prtGeneral CUPS_OID_printmib,5
+#define CUPS_OID_prtGeneralTable CUPS_OID_prtGeneral,1
+#define CUPS_OID_prtGeneralEntry CUPS_OID_prtGeneralTable,1
+#define CUPS_OID_prtGeneralCurrentLocalization CUPS_OID_prtGeneralEntry,2
+#define CUPS_OID_prtGeneralPrinterName CUPS_OID_prtGeneralEntry,16
+#define CUPS_OID_prtGeneralSerialNumber CUPS_OID_prtGeneralEntry,17
+
+#define CUPS_OID_prtCover CUPS_OID_printmib,6
+#define CUPS_OID_prtCoverTable CUPS_OID_prtCover,1
+#define CUPS_OID_prtCoverEntry CUPS_OID_prtCoverTable,1
+#define CUPS_OID_prtCoverDescription CUPS_OID_prtCoverEntry,2
+#define CUPS_OID_prtCoverStatus CUPS_OID_prtCoverEntry,3
+
+#define CUPS_OID_prtLocalization CUPS_OID_printmib,7
+#define CUPS_OID_prtLocalizationTable CUPS_OID_prtLocalization,1
+#define CUPS_OID_prtLocalizationEntry CUPS_OID_prtLocalizationTable,1
+#define CUPS_OID_prtLocalizationCharacterSet CUPS_OID_prtLocalizationEntry,4
+
+#define CUPS_OID_prtMarker CUPS_OID_printmib,10
+#define CUPS_OID_prtMarkerTable CUPS_OID_prtMarker,2
+#define CUPS_OID_prtMarkerEntry CUPS_OID_prtMarkerTable,1
+#define CUPS_OID_prtMarkerLifeCount CUPS_OID_prtMarkerEntry,4
+
+#define CUPS_OID_prtMarkerSupplies CUPS_OID_printmib,11
+#define CUPS_OID_prtMarkerSuppliesTable CUPS_OID_prtMarkerSupplies,1
+#define CUPS_OID_prtMarkerSuppliesEntry CUPS_OID_prtMarkerSuppliesTable,1
+#define CUPS_OID_prtMarkerSuppliesIndex CUPS_OID_prtMarkerSuppliesEntry,1
+#define CUPS_OID_prtMarkerSuppliesMarkerIndex CUPS_OID_prtMarkerSuppliesEntry,2
+#define CUPS_OID_prtMarkerSuppliesColorantIndex CUPS_OID_prtMarkerSuppliesEntry,3
+#define CUPS_OID_prtMarkerSuppliesClass CUPS_OID_prtMarkerSuppliesEntry,4
+#define CUPS_OID_prtMarkerSuppliesType CUPS_OID_prtMarkerSuppliesEntry,5
+#define CUPS_OID_prtMarkerSuppliesDescription CUPS_OID_prtMarkerSuppliesEntry,6
+#define CUPS_OID_prtMarkerSuppliesSupplyUnit CUPS_OID_prtMarkerSuppliesEntry,7
+#define CUPS_OID_prtMarkerSuppliesMaxCapacity CUPS_OID_prtMarkerSuppliesEntry,8
+#define CUPS_OID_prtMarkerSuppliesLevel CUPS_OID_prtMarkerSuppliesEntry,9
+
+#define CUPS_OID_prtMarkerColorant CUPS_OID_printmib,12
+#define CUPS_OID_prtMarkerColorantTable CUPS_OID_prtMarkerColorant,1
+#define CUPS_OID_prtMarkerColorantEntry CUPS_OID_prtMarkerColorantTable,1
+#define CUPS_OID_prtMarkerColorantIndex CUPS_OID_prtMarkerColorantEntry,1
+#define CUPS_OID_prtMarkerColorantMarkerIndex CUPS_OID_prtMarkerColorantEntry,2
+#define CUPS_OID_prtMarkerColorantRole CUPS_OID_prtMarkerColorantEntry,3
+#define CUPS_OID_prtMarkerColorantValue CUPS_OID_prtMarkerColorantEntry,4
+#define CUPS_OID_prtMarkerColorantTonality CUPS_OID_prtMarkerColorantEntry,5
+
+#define CUPS_OID_prtInterpreter CUPS_OID_printmib,15
+#define CUPS_OID_prtInterpreterTable CUPS_OID_prtInterpreter,1
+#define CUPS_OID_prtInterpreterEntry CUPS_OID_prtInterpreterTable,1
+#define CUPS_OID_prtInterpreterLangFamily CUPS_OID_prtInterpreterEntry,2
+#define CUPS_OID_prtInterpreterLangLevel CUPS_OID_prtInterpreterEntry,3
+
+/* Printer Port Monitor MIB */
+#define CUPS_OID_enterprises 1,3,6,1,4,1
+#define CUPS_OID_pwg CUPS_OID_enterprises,2699,1
+#define CUPS_OID_ppmMIB CUPS_OID_pwg,2
+#define CUPS_OID_ppmMIBObjects CUPS_OID_ppmMIB,1
+
+#define CUPS_OID_ppmGeneral CUPS_OID_ppmMIBObjects,1
+
+#define CUPS_OID_ppmPrinter CUPS_OID_ppmMIBObjects,2
+#define CUPS_OID_ppmPrinterTable CUPS_OID_ppmPrinter,1
+#define CUPS_OID_ppmPrinterEntry CUPS_OID_ppmPrinterTable,1
+#define CUPS_OID_ppmPrinterIndex CUPS_OID_ppmPrinterEntry,1
+#define CUPS_OID_ppmPrinterName CUPS_OID_ppmPrinterEntry,2
+#define CUPS_OID_ppmPrinterIEEE1284DeviceId CUPS_OID_ppmPrinterEntry,3
+#define CUPS_OID_ppmPrinterNumberOfPorts CUPS_OID_ppmPrinterEntry,4
+#define CUPS_OID_ppmPrinterPreferredPortIndex CUPS_OID_ppmPrinterEntry,5
+#define CUPS_OID_ppmPrinterHrDeviceIndex CUPS_OID_ppmPrinterEntry,6
+#define CUPS_OID_ppmPrinterSnmpCommunityName CUPS_OID_ppmPrinterEntry,7
+#define CUPS_OID_ppmPrinterSnmpQueryEnabled CUPS_OID_ppmPrinterEntry,8
+
+#define CUPS_OID_ppmPort CUPS_OID_ppmMIBObjects,3
+#define CUPS_OID_ppmPortTable CUPS_OID_ppmPort,1
+#define CUPS_OID_ppmPortEntry CUPS_OID_ppmPortTable,1
+#define CUPS_OID_ppmPortIndex CUPS_OID_ppmPortEntry,1
+#define CUPS_OID_ppmPortEnabled CUPS_OID_ppmPortEntry,2
+#define CUPS_OID_ppmPortName CUPS_OID_ppmPortEntry,3
+#define CUPS_OID_ppmPortServiceNameOrURI CUPS_OID_ppmPortEntry,4
+#define CUPS_OID_ppmPortProtocolType CUPS_OID_ppmPortEntry,5
+#define CUPS_OID_ppmPortProtocolTargetPort CUPS_OID_ppmPortEntry,6
+#define CUPS_OID_ppmPortProtocolAltSourceEnabled CUPS_OID_ppmPortEntry,7
+#define CUPS_OID_ppmPortPrtChannelIndex CUPS_OID_ppmPortEntry,8
+#define CUPS_OID_ppmPortLprByteCountEnabled CUPS_OID_ppmPortEntry,9
+
+
+/*
+ * State constants...
+ */
+
+#define CUPS_TC_other 1
+#define CUPS_TC_unknown 2
+
+#define CUPS_TC_idle 3
+#define CUPS_TC_printing 4
+#define CUPS_TC_warmup 5
+
+/* These come from the hrPrinterDetectedErrorState OCTET-STRING */
+#define CUPS_TC_lowPaper 0x8000
+#define CUPS_TC_noPaper 0x4000
+#define CUPS_TC_lowToner 0x2000
+#define CUPS_TC_noToner 0x1000
+#define CUPS_TC_doorOpen 0x0800
+#define CUPS_TC_jammed 0x0400
+#define CUPS_TC_offline 0x0200
+#define CUPS_TC_serviceRequested 0x0100
+#define CUPS_TC_inputTrayMissing 0x0080
+#define CUPS_TC_outputTrayMissing 0x0040
+#define CUPS_TC_markerSupplyMissing 0x0020
+#define CUPS_TC_outputNearFull 0x0010
+#define CUPS_TC_outputFull 0x0008
+#define CUPS_TC_inputTrayEmpty 0x0004
+#define CUPS_TC_overduePreventMaint 0x0002
+
+#define CUPS_TC_prtCoverStatus_coverOpen 3
+#define CUPS_TC_prtCoverStatus_coverClosed 4
+#define CUPS_TC_prtCoverStatus_interlockOpen 5
+#define CUPS_TC_prtCoverStatus_interlockClosed 6
+
+#define CUPS_TC_langPCL 3
+#define CUPS_TC_langHPGL 4
+#define CUPS_TC_langPJL 5
+#define CUPS_TC_langPS 6
+#define CUPS_TC_langEscapeP 9
+#define CUPS_TC_langCCITT 26
+#define CUPS_TC_langLIPS 39
+#define CUPS_TC_langTIFF 40
+#define CUPS_TC_langPCLXL 47
+#define CUPS_TC_langPDF 54
+#define CUPS_TC_langJPEG 61
+
+#define CUPS_TC_supplyThatIsConsumed 3
+#define CUPS_TC_receptacleThatIsFilled 4
+
+#define CUPS_TC_process 3
+#define CUPS_TC_spot 4
+
+#define CUPS_TC_toner 3
+#define CUPS_TC_wasteToner 4
+#define CUPS_TC_ink 5
+#define CUPS_TC_inkCartridge 6
+#define CUPS_TC_inkRibbon 7
+#define CUPS_TC_wasteInk 8
+#define CUPS_TC_opc 9
+#define CUPS_TC_developer 10
+#define CUPS_TC_fuserOil 11
+#define CUPS_TC_solidWax 12
+#define CUPS_TC_ribbonWax 13
+#define CUPS_TC_wasteWax 14
+#define CUPS_TC_fuser 15
+#define CUPS_TC_coronaWire 16
+#define CUPS_TC_fuserOilWick 17
+#define CUPS_TC_cleanerUnit 18
+#define CUPS_TC_fuserCleaningPad 19
+#define CUPS_TC_transferUnit 20
+#define CUPS_TC_tonerCartridge 21
+#define CUPS_TC_fuserOiler 22
+#define CUPS_TC_water 23
+#define CUPS_TC_wasteWater 24
+#define CUPS_TC_glueWaterAdditive 25
+#define CUPS_TC_wastePaper 26
+#define CUPS_TC_bindingSupply 27
+#define CUPS_TC_bandingSupply 28
+#define CUPS_TC_stitchingWire 29
+#define CUPS_TC_shrinkWrap 30
+#define CUPS_TC_paperWrap 31
+#define CUPS_TC_staples 32
+#define CUPS_TC_inserts 33
+#define CUPS_TC_covers 34
+
+/* These come from RFC 3808 to define character sets we support */
+/* Also see http://www.iana.org/assignments/character-sets */
+#define CUPS_TC_csASCII 3
+#define CUPS_TC_csISOLatin1 4
+#define CUPS_TC_csShiftJIS 17
+#define CUPS_TC_csUTF8 106
+#define CUPS_TC_csUnicode 1000 /* UCS2 BE */
+#define CUPS_TC_csUCS4 1001 /* UCS4 BE */
+#define CUPS_TC_csUnicodeASCII 1002
+#define CUPS_TC_csUnicodeLatin1 1003
+#define CUPS_TC_csUTF16BE 1013
+#define CUPS_TC_csUTF16LE 1014
+#define CUPS_TC_csUTF32 1017
+#define CUPS_TC_csUTF32BE 1018
+#define CUPS_TC_csUTF32LE 1019
+
+
+/*
+ * Types...
+ */
+
+typedef int (*_cups_sccb_t)(int print_fd, int device_fd, int snmp_fd,
+ http_addr_t *addr, int use_bc);
+
+
+/*
+ * Prototypes...
+ */
+
+extern void backendCheckSideChannel(int snmp_fd, http_addr_t *addr);
+extern int backendDrainOutput(int print_fd, int device_fd);
+extern int backendGetDeviceID(int fd, char *device_id,
+ int device_id_size,
+ char *make_model,
+ int make_model_size,
+ const char *scheme, char *uri,
+ int uri_size);
+extern int backendGetMakeModel(const char *device_id,
+ char *make_model,
+ int make_model_size);
+extern int backendNetworkSideCB(int print_fd, int device_fd,
+ int snmp_fd, http_addr_t *addr,
+ int use_bc);
+extern ssize_t backendRunLoop(int print_fd, int device_fd, int snmp_fd,
+ http_addr_t *addr, int use_bc,
+ int update_state, _cups_sccb_t side_cb);
+extern int backendSNMPSupplies(int snmp_fd, http_addr_t *addr,
+ int *page_count,
+ int *printer_state);
+extern int backendWaitLoop(int snmp_fd, http_addr_t *addr,
+ int use_bc, _cups_sccb_t side_cb);
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_BACKEND_PRIVATE_H_ */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/dnssd.c b/backend/dnssd.c
new file mode 100644
index 000000000..ac547ab54
--- /dev/null
+++ b/backend/dnssd.c
@@ -0,0 +1,921 @@
+/*
+ * "$Id$"
+ *
+ * DNS-SD discovery backend for CUPS.
+ *
+ * Copyright 2008-2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Browse for printers.
+ * browse_callback() - Browse devices.
+ * browse_local_callback() - Browse local devices.
+ * compare_devices() - Compare two devices.
+ * exec_backend() - Execute the backend that corresponds to the
+ * resolved service name.
+ * get_device() - Create or update a device.
+ * query_callback() - Process query data.
+ * sigterm_handler() - Handle termination signals...
+ * unquote() - Unquote a name string.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "backend-private.h"
+#include <cups/array.h>
+#include <dns_sd.h>
+
+
+/*
+ * Device structure...
+ */
+
+typedef enum
+{
+ CUPS_DEVICE_PRINTER = 0, /* lpd://... */
+ CUPS_DEVICE_IPP, /* ipp://... */
+ CUPS_DEVICE_FAX_IPP, /* ipp://... */
+ CUPS_DEVICE_PDL_DATASTREAM, /* socket://... */
+ CUPS_DEVICE_RIOUSBPRINT /* riousbprint://... */
+} cups_devtype_t;
+
+
+typedef struct
+{
+ DNSServiceRef ref; /* Service reference for resolve */
+ char *name, /* Service name */
+ *domain, /* Domain name */
+ *fullName, /* Full name */
+ *make_and_model, /* Make and model from TXT record */
+ *device_id; /* 1284 device ID from TXT record */
+ cups_devtype_t type; /* Device registration type */
+ int priority, /* Priority associated with type */
+ cups_shared, /* CUPS shared printer? */
+ sent; /* Did we list the device? */
+} cups_device_t;
+
+
+/*
+ * Local globals...
+ */
+
+static int job_canceled = 0;
+ /* Set to 1 on SIGTERM */
+
+
+/*
+ * Local functions...
+ */
+
+static void browse_callback(DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *serviceName,
+ const char *regtype,
+ const char *replyDomain, void *context);
+static void browse_local_callback(DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *serviceName,
+ const char *regtype,
+ const char *replyDomain,
+ void *context);
+static int compare_devices(cups_device_t *a, cups_device_t *b);
+static void exec_backend(char **argv);
+static cups_device_t *get_device(cups_array_t *devices,
+ const char *serviceName,
+ const char *regtype,
+ const char *replyDomain);
+static void query_callback(DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *fullName, uint16_t rrtype,
+ uint16_t rrclass, uint16_t rdlen,
+ const void *rdata, uint32_t ttl,
+ void *context);
+static void sigterm_handler(int sig);
+static void unquote(char *dst, const char *src, size_t dstsize);
+
+
+/*
+ * 'main()' - Browse for printers.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ const char *name; /* Backend name */
+ DNSServiceRef main_ref, /* Main service reference */
+ fax_ipp_ref, /* IPP fax service reference */
+ ipp_ref, /* IPP service reference */
+ ipp_tls_ref, /* IPP w/TLS service reference */
+ local_fax_ipp_ref, /* Local IPP fax service reference */
+ local_ipp_ref, /* Local IPP service reference */
+ local_ipp_tls_ref, /* Local IPP w/TLS service reference */
+ local_printer_ref, /* Local LPD service reference */
+ pdl_datastream_ref, /* AppSocket service reference */
+ printer_ref, /* LPD service reference */
+ riousbprint_ref; /* Remote IO service reference */
+ int fd; /* Main file descriptor */
+ fd_set input; /* Input set for select() */
+ struct timeval timeout; /* Timeout for select() */
+ cups_array_t *devices; /* Device array */
+ cups_device_t *device; /* Current device */
+ char uriName[1024]; /* Unquoted fullName for URI */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Don't buffer stderr, and catch SIGTERM...
+ */
+
+ setbuf(stderr, NULL);
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, sigterm_handler);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = sigterm_handler;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, sigterm_handler);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc >= 6)
+ exec_backend(argv);
+ else if (argc != 1)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options [file]"),
+ argv[0]);
+ return (1);
+ }
+
+ /*
+ * Only do discovery when run as "dnssd"...
+ */
+
+ if ((name = strrchr(argv[0], '/')) != NULL)
+ name ++;
+ else
+ name = argv[0];
+
+ if (strcmp(name, "dnssd"))
+ return (0);
+
+ /*
+ * Create an array to track devices...
+ */
+
+ devices = cupsArrayNew((cups_array_func_t)compare_devices, NULL);
+
+ /*
+ * Browse for different kinds of printers...
+ */
+
+ if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError)
+ {
+ perror("ERROR: Unable to create service connection");
+ return (1);
+ }
+
+ fd = DNSServiceRefSockFD(main_ref);
+
+ fax_ipp_ref = main_ref;
+ DNSServiceBrowse(&fax_ipp_ref, kDNSServiceFlagsShareConnection, 0,
+ "_fax-ipp._tcp", NULL, browse_callback, devices);
+
+ ipp_ref = main_ref;
+ DNSServiceBrowse(&ipp_ref, kDNSServiceFlagsShareConnection, 0,
+ "_ipp._tcp", NULL, browse_callback, devices);
+
+ ipp_tls_ref = main_ref;
+ DNSServiceBrowse(&ipp_tls_ref, kDNSServiceFlagsShareConnection, 0,
+ "_ipp-tls._tcp", NULL, browse_callback, devices);
+
+ local_fax_ipp_ref = main_ref;
+ DNSServiceBrowse(&local_fax_ipp_ref, kDNSServiceFlagsShareConnection,
+ kDNSServiceInterfaceIndexLocalOnly,
+ "_fax-ipp._tcp", NULL, browse_local_callback, devices);
+
+ local_ipp_ref = main_ref;
+ DNSServiceBrowse(&local_ipp_ref, kDNSServiceFlagsShareConnection,
+ kDNSServiceInterfaceIndexLocalOnly,
+ "_ipp._tcp", NULL, browse_local_callback, devices);
+
+ local_ipp_tls_ref = main_ref;
+ DNSServiceBrowse(&local_ipp_tls_ref, kDNSServiceFlagsShareConnection,
+ kDNSServiceInterfaceIndexLocalOnly,
+ "_ipp-tls._tcp", NULL, browse_local_callback, devices);
+
+ local_printer_ref = main_ref;
+ DNSServiceBrowse(&local_printer_ref, kDNSServiceFlagsShareConnection,
+ kDNSServiceInterfaceIndexLocalOnly,
+ "_printer._tcp", NULL, browse_local_callback, devices);
+
+ pdl_datastream_ref = main_ref;
+ DNSServiceBrowse(&pdl_datastream_ref, kDNSServiceFlagsShareConnection, 0,
+ "_pdl-datastream._tcp", NULL, browse_callback, devices);
+
+ printer_ref = main_ref;
+ DNSServiceBrowse(&printer_ref, kDNSServiceFlagsShareConnection, 0,
+ "_printer._tcp", NULL, browse_callback, devices);
+
+ riousbprint_ref = main_ref;
+ DNSServiceBrowse(&riousbprint_ref, kDNSServiceFlagsShareConnection, 0,
+ "_riousbprint._tcp", NULL, browse_callback, devices);
+
+ /*
+ * Loop until we are killed...
+ */
+
+ while (!job_canceled)
+ {
+ FD_ZERO(&input);
+ FD_SET(fd, &input);
+
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+
+ if (select(fd + 1, &input, NULL, NULL, &timeout) < 0)
+ continue;
+
+ if (FD_ISSET(fd, &input))
+ {
+ /*
+ * Process results of our browsing...
+ */
+
+ DNSServiceProcessResult(main_ref);
+ }
+ else
+ {
+ /*
+ * Announce any devices we've found...
+ */
+
+ DNSServiceErrorType status; /* DNS query status */
+ cups_device_t *best; /* Best matching device */
+ char device_uri[1024]; /* Device URI */
+ int count; /* Number of queries */
+
+
+ for (device = (cups_device_t *)cupsArrayFirst(devices),
+ best = NULL, count = 0;
+ device;
+ device = (cups_device_t *)cupsArrayNext(devices))
+ if (!device->ref && !device->sent)
+ {
+ /*
+ * Found the device, now get the TXT record(s) for it...
+ */
+
+ if (count < 10)
+ {
+ device->ref = main_ref;
+
+ fprintf(stderr, "DEBUG: Querying \"%s\"...\n", device->fullName);
+
+ status = DNSServiceQueryRecord(&(device->ref),
+ kDNSServiceFlagsShareConnection,
+ 0, device->fullName,
+ kDNSServiceType_TXT,
+ kDNSServiceClass_IN, query_callback,
+ devices);
+ if (status != kDNSServiceErr_NoError)
+ {
+ fputs("ERROR: Unable to query for TXT records!\n", stderr);
+ fprintf(stderr, "DEBUG: DNSServiceQueryRecord returned %d\n",
+ status);
+ }
+ else
+ count ++;
+ }
+ }
+ else if (!device->sent)
+ {
+ /*
+ * Got the TXT records, now report the device...
+ */
+
+ DNSServiceRefDeallocate(device->ref);
+ device->ref = 0;
+
+ if (!best)
+ best = device;
+ else if (_cups_strcasecmp(best->name, device->name) ||
+ _cups_strcasecmp(best->domain, device->domain))
+ {
+ unquote(uriName, best->fullName, sizeof(uriName));
+
+ httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri),
+ "dnssd", NULL, uriName, 0,
+ best->cups_shared ? "/cups" : "/");
+
+ cupsBackendReport("network", device_uri, best->make_and_model,
+ best->name, best->device_id, NULL);
+ best->sent = 1;
+ best = device;
+ }
+ else if (best->priority > device->priority ||
+ (best->priority == device->priority &&
+ best->type < device->type))
+ {
+ best->sent = 1;
+ best = device;
+ }
+ else
+ device->sent = 1;
+ }
+
+ if (best)
+ {
+ unquote(uriName, best->fullName, sizeof(uriName));
+
+ httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri),
+ "dnssd", NULL, uriName, 0,
+ best->cups_shared ? "/cups" : "/");
+
+ cupsBackendReport("network", device_uri, best->make_and_model,
+ best->name, best->device_id, NULL);
+ best->sent = 1;
+ }
+ }
+ }
+
+ return (CUPS_BACKEND_OK);
+}
+
+
+/*
+ * 'browse_callback()' - Browse devices.
+ */
+
+static void
+browse_callback(
+ DNSServiceRef sdRef, /* I - Service reference */
+ DNSServiceFlags flags, /* I - Option flags */
+ uint32_t interfaceIndex, /* I - Interface number */
+ DNSServiceErrorType errorCode, /* I - Error, if any */
+ const char *serviceName, /* I - Name of service/device */
+ const char *regtype, /* I - Type of service */
+ const char *replyDomain, /* I - Service domain */
+ void *context) /* I - Devices array */
+{
+ fprintf(stderr, "DEBUG2: browse_callback(sdRef=%p, flags=%x, "
+ "interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", "
+ "regtype=\"%s\", replyDomain=\"%s\", context=%p)\n",
+ sdRef, flags, interfaceIndex, errorCode,
+ serviceName ? serviceName : "(null)",
+ regtype ? regtype : "(null)",
+ replyDomain ? replyDomain : "(null)",
+ context);
+
+ /*
+ * Only process "add" data...
+ */
+
+ if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
+ return;
+
+ /*
+ * Get the device...
+ */
+
+ get_device((cups_array_t *)context, serviceName, regtype, replyDomain);
+}
+
+
+/*
+ * 'browse_local_callback()' - Browse local devices.
+ */
+
+static void
+browse_local_callback(
+ DNSServiceRef sdRef, /* I - Service reference */
+ DNSServiceFlags flags, /* I - Option flags */
+ uint32_t interfaceIndex, /* I - Interface number */
+ DNSServiceErrorType errorCode, /* I - Error, if any */
+ const char *serviceName, /* I - Name of service/device */
+ const char *regtype, /* I - Type of service */
+ const char *replyDomain, /* I - Service domain */
+ void *context) /* I - Devices array */
+{
+ cups_device_t *device; /* Device */
+
+
+ fprintf(stderr, "DEBUG2: browse_local_callback(sdRef=%p, flags=%x, "
+ "interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", "
+ "regtype=\"%s\", replyDomain=\"%s\", context=%p)\n",
+ sdRef, flags, interfaceIndex, errorCode,
+ serviceName ? serviceName : "(null)",
+ regtype ? regtype : "(null)",
+ replyDomain ? replyDomain : "(null)",
+ context);
+
+ /*
+ * Only process "add" data...
+ */
+
+ if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
+ return;
+
+ /*
+ * Get the device...
+ */
+
+ device = get_device((cups_array_t *)context, serviceName, regtype,
+ replyDomain);
+
+ /*
+ * Hide locally-registered devices...
+ */
+
+ fprintf(stderr, "DEBUG: Hiding local printer \"%s\"...\n",
+ device->fullName);
+ device->sent = 1;
+}
+
+
+/*
+ * 'compare_devices()' - Compare two devices.
+ */
+
+static int /* O - Result of comparison */
+compare_devices(cups_device_t *a, /* I - First device */
+ cups_device_t *b) /* I - Second device */
+{
+ return (strcmp(a->name, b->name));
+}
+
+
+/*
+ * 'exec_backend()' - Execute the backend that corresponds to the
+ * resolved service name.
+ */
+
+static void
+exec_backend(char **argv) /* I - Command-line arguments */
+{
+ const char *resolved_uri, /* Resolved device URI */
+ *cups_serverbin; /* Location of programs */
+ char scheme[1024], /* Scheme from URI */
+ *ptr, /* Pointer into scheme */
+ filename[1024]; /* Backend filename */
+
+
+ /*
+ * Resolve the device URI...
+ */
+
+ job_canceled = -1;
+
+ while ((resolved_uri = cupsBackendDeviceURI(argv)) == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer."));
+ sleep(10);
+
+ if (getenv("CLASS") != NULL)
+ exit(CUPS_BACKEND_FAILED);
+ }
+
+ /*
+ * Extract the scheme from the URI...
+ */
+
+ strlcpy(scheme, resolved_uri, sizeof(scheme));
+ if ((ptr = strchr(scheme, ':')) != NULL)
+ *ptr = '\0';
+
+ /*
+ * Get the filename of the backend...
+ */
+
+ if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
+ cups_serverbin = CUPS_SERVERBIN;
+
+ snprintf(filename, sizeof(filename), "%s/backend/%s", cups_serverbin, scheme);
+
+ /*
+ * Overwrite the device URI and run the new backend...
+ */
+
+ setenv("DEVICE_URI", resolved_uri, 1);
+
+ argv[0] = (char *)resolved_uri;
+
+ fprintf(stderr, "DEBUG: Executing backend \"%s\"...\n", filename);
+
+ execv(filename, argv);
+
+ fprintf(stderr, "ERROR: Unable to execute backend \"%s\": %s\n", filename,
+ strerror(errno));
+ exit(CUPS_BACKEND_STOP);
+}
+
+
+/*
+ * 'get_device()' - Create or update a device.
+ */
+
+static cups_device_t * /* O - Device */
+get_device(cups_array_t *devices, /* I - Device array */
+ const char *serviceName, /* I - Name of service/device */
+ const char *regtype, /* I - Type of service */
+ const char *replyDomain) /* I - Service domain */
+{
+ cups_device_t key, /* Search key */
+ *device; /* Device */
+ char fullName[kDNSServiceMaxDomainName];
+ /* Full name for query */
+
+
+ /*
+ * See if this is a new device...
+ */
+
+ key.name = (char *)serviceName;
+
+ if (!strcmp(regtype, "_ipp._tcp.") ||
+ !strcmp(regtype, "_ipp-tls._tcp."))
+ key.type = CUPS_DEVICE_IPP;
+ else if (!strcmp(regtype, "_fax-ipp._tcp."))
+ key.type = CUPS_DEVICE_FAX_IPP;
+ else if (!strcmp(regtype, "_printer._tcp."))
+ key.type = CUPS_DEVICE_PRINTER;
+ else if (!strcmp(regtype, "_pdl-datastream._tcp."))
+ key.type = CUPS_DEVICE_PDL_DATASTREAM;
+ else
+ key.type = CUPS_DEVICE_RIOUSBPRINT;
+
+ for (device = cupsArrayFind(devices, &key);
+ device;
+ device = cupsArrayNext(devices))
+ if (_cups_strcasecmp(device->name, key.name))
+ break;
+ else if (device->type == key.type)
+ {
+ if (!_cups_strcasecmp(device->domain, "local.") &&
+ _cups_strcasecmp(device->domain, replyDomain))
+ {
+ /*
+ * Update the .local listing to use the "global" domain name instead.
+ * The backend will try local lookups first, then the global domain name.
+ */
+
+ free(device->domain);
+ device->domain = strdup(replyDomain);
+
+ DNSServiceConstructFullName(fullName, device->name, regtype,
+ replyDomain);
+ free(device->fullName);
+ device->fullName = strdup(fullName);
+ }
+
+ return (device);
+ }
+
+ /*
+ * Yes, add the device...
+ */
+
+ fprintf(stderr, "DEBUG: Found \"%s.%s%s\"...\n", serviceName, regtype,
+ replyDomain);
+
+ device = calloc(sizeof(cups_device_t), 1);
+ device->name = strdup(serviceName);
+ device->domain = strdup(replyDomain);
+ device->type = key.type;
+ device->priority = 50;
+
+ cupsArrayAdd(devices, device);
+
+ /*
+ * Set the "full name" of this service, which is used for queries...
+ */
+
+ DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain);
+ device->fullName = strdup(fullName);
+
+ return (device);
+}
+
+
+/*
+ * 'query_callback()' - Process query data.
+ */
+
+static void
+query_callback(
+ DNSServiceRef sdRef, /* I - Service reference */
+ DNSServiceFlags flags, /* I - Data flags */
+ uint32_t interfaceIndex, /* I - Interface */
+ DNSServiceErrorType errorCode, /* I - Error, if any */
+ const char *fullName, /* I - Full service name */
+ uint16_t rrtype, /* I - Record type */
+ uint16_t rrclass, /* I - Record class */
+ uint16_t rdlen, /* I - Length of record data */
+ const void *rdata, /* I - Record data */
+ uint32_t ttl, /* I - Time-to-live */
+ void *context) /* I - Devices array */
+{
+ cups_array_t *devices; /* Device array */
+ char name[1024], /* Service name */
+ *ptr; /* Pointer into string */
+ cups_device_t dkey, /* Search key */
+ *device; /* Device */
+
+
+ fprintf(stderr, "DEBUG2: query_callback(sdRef=%p, flags=%x, "
+ "interfaceIndex=%d, errorCode=%d, fullName=\"%s\", "
+ "rrtype=%u, rrclass=%u, rdlen=%u, rdata=%p, ttl=%u, "
+ "context=%p)\n",
+ sdRef, flags, interfaceIndex, errorCode,
+ fullName ? fullName : "(null)", rrtype, rrclass, rdlen, rdata, ttl,
+ context);
+
+ /*
+ * Only process "add" data...
+ */
+
+ if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
+ return;
+
+ /*
+ * Lookup the service in the devices array.
+ */
+
+ devices = (cups_array_t *)context;
+ dkey.name = name;
+
+ unquote(name, fullName, sizeof(name));
+
+ if ((dkey.domain = strstr(name, "._tcp.")) != NULL)
+ dkey.domain += 6;
+ else
+ dkey.domain = (char *)"local.";
+
+ if ((ptr = strstr(name, "._")) != NULL)
+ *ptr = '\0';
+
+ if (strstr(fullName, "_ipp._tcp.") ||
+ strstr(fullName, "_ipp-tls._tcp."))
+ dkey.type = CUPS_DEVICE_IPP;
+ else if (strstr(fullName, "_fax-ipp._tcp."))
+ dkey.type = CUPS_DEVICE_FAX_IPP;
+ else if (strstr(fullName, "_printer._tcp."))
+ dkey.type = CUPS_DEVICE_PRINTER;
+ else if (strstr(fullName, "_pdl-datastream._tcp."))
+ dkey.type = CUPS_DEVICE_PDL_DATASTREAM;
+ else
+ dkey.type = CUPS_DEVICE_RIOUSBPRINT;
+
+ for (device = cupsArrayFind(devices, &dkey);
+ device;
+ device = cupsArrayNext(devices))
+ {
+ if (_cups_strcasecmp(device->name, dkey.name) ||
+ _cups_strcasecmp(device->domain, dkey.domain))
+ {
+ device = NULL;
+ break;
+ }
+ else if (device->type == dkey.type)
+ {
+ /*
+ * Found it, pull out the priority and make and model from the TXT
+ * record and save it...
+ */
+
+ const uint8_t *data, /* Pointer into data */
+ *datanext, /* Next key/value pair */
+ *dataend; /* End of entire TXT record */
+ uint8_t datalen; /* Length of current key/value pair */
+ char key[256], /* Key string */
+ value[256], /* Value string */
+ make_and_model[512],
+ /* Manufacturer and model */
+ model[256], /* Model */
+ device_id[2048];/* 1284 device ID */
+
+
+ device_id[0] = '\0';
+ make_and_model[0] = '\0';
+
+ strcpy(model, "Unknown");
+
+ for (data = rdata, dataend = data + rdlen;
+ data < dataend;
+ data = datanext)
+ {
+ /*
+ * Read a key/value pair starting with an 8-bit length. Since the
+ * length is 8 bits and the size of the key/value buffers is 256, we
+ * don't need to check for overflow...
+ */
+
+ datalen = *data++;
+
+ if (!datalen || (data + datalen) >= dataend)
+ break;
+
+ datanext = data + datalen;
+
+ for (ptr = key; data < datanext && *data != '='; data ++)
+ *ptr++ = *data;
+ *ptr = '\0';
+
+ if (data < datanext && *data == '=')
+ {
+ data ++;
+
+ if (data < datanext)
+ memcpy(value, data, datanext - data);
+ value[datanext - data] = '\0';
+ }
+ else
+ continue;
+
+ if (!_cups_strncasecmp(key, "usb_", 4))
+ {
+ /*
+ * Add USB device ID information...
+ */
+
+ ptr = device_id + strlen(device_id);
+ snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%s:%s;",
+ key + 4, value);
+ }
+
+ if (!_cups_strcasecmp(key, "usb_MFG") || !_cups_strcasecmp(key, "usb_MANU") ||
+ !_cups_strcasecmp(key, "usb_MANUFACTURER"))
+ strcpy(make_and_model, value);
+ else if (!_cups_strcasecmp(key, "usb_MDL") || !_cups_strcasecmp(key, "usb_MODEL"))
+ strcpy(model, value);
+ else if (!_cups_strcasecmp(key, "product") && !strstr(value, "Ghostscript"))
+ {
+ if (value[0] == '(')
+ {
+ /*
+ * Strip parenthesis...
+ */
+
+ if ((ptr = value + strlen(value) - 1) > value && *ptr == ')')
+ *ptr = '\0';
+
+ strcpy(model, value + 1);
+ }
+ else
+ strcpy(model, value);
+ }
+ else if (!_cups_strcasecmp(key, "ty"))
+ {
+ strcpy(model, value);
+
+ if ((ptr = strchr(model, ',')) != NULL)
+ *ptr = '\0';
+ }
+ else if (!_cups_strcasecmp(key, "priority"))
+ device->priority = atoi(value);
+ else if ((device->type == CUPS_DEVICE_IPP ||
+ device->type == CUPS_DEVICE_PRINTER) &&
+ !_cups_strcasecmp(key, "printer-type"))
+ {
+ /*
+ * This is a CUPS printer!
+ */
+
+ device->cups_shared = 1;
+
+ if (device->type == CUPS_DEVICE_PRINTER)
+ device->sent = 1;
+ }
+ }
+
+ if (device->device_id)
+ free(device->device_id);
+
+ if (!device_id[0] && strcmp(model, "Unknown"))
+ {
+ if (make_and_model[0])
+ snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;",
+ make_and_model, model);
+ else if (!_cups_strncasecmp(model, "designjet ", 10))
+ snprintf(device_id, sizeof(device_id), "MFG:HP;MDL:%s", model + 10);
+ else if (!_cups_strncasecmp(model, "stylus ", 7))
+ snprintf(device_id, sizeof(device_id), "MFG:EPSON;MDL:%s", model + 7);
+ else if ((ptr = strchr(model, ' ')) != NULL)
+ {
+ /*
+ * Assume the first word is the make...
+ */
+
+ memcpy(make_and_model, model, ptr - model);
+ make_and_model[ptr - model] = '\0';
+
+ snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s",
+ make_and_model, ptr + 1);
+ }
+ }
+
+ if (device_id[0])
+ device->device_id = strdup(device_id);
+ else
+ device->device_id = NULL;
+
+ if (device->make_and_model)
+ free(device->make_and_model);
+
+ if (make_and_model[0])
+ {
+ strlcat(make_and_model, " ", sizeof(make_and_model));
+ strlcat(make_and_model, model, sizeof(make_and_model));
+
+ device->make_and_model = strdup(make_and_model);
+ }
+ else
+ device->make_and_model = strdup(model);
+ break;
+ }
+ }
+
+ if (!device)
+ fprintf(stderr, "DEBUG: Ignoring TXT record for \"%s\"...\n", fullName);
+}
+
+
+/*
+ * 'sigterm_handler()' - Handle termination signals...
+ */
+
+static void
+sigterm_handler(int sig) /* I - Signal number (unused) */
+{
+ (void)sig;
+
+ if (job_canceled)
+ exit(CUPS_BACKEND_OK);
+ else
+ job_canceled = 1;
+}
+
+
+/*
+ * 'unquote()' - Unquote a name string.
+ */
+
+static void
+unquote(char *dst, /* I - Destination buffer */
+ const char *src, /* I - Source string */
+ size_t dstsize) /* I - Size of destination buffer */
+{
+ char *dstend = dst + dstsize - 1; /* End of destination buffer */
+
+
+ while (*src && dst < dstend)
+ {
+ if (*src == '\\')
+ {
+ src ++;
+ if (isdigit(src[0] & 255) && isdigit(src[1] & 255) &&
+ isdigit(src[2] & 255))
+ {
+ *dst++ = ((((src[0] - '0') * 10) + src[1] - '0') * 10) + src[2] - '0';
+ src += 3;
+ }
+ else
+ *dst++ = *src++;
+ }
+ else
+ *dst++ = *src ++;
+ }
+
+ *dst = '\0';
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/ieee1284.c b/backend/ieee1284.c
new file mode 100644
index 000000000..d4064ccb5
--- /dev/null
+++ b/backend/ieee1284.c
@@ -0,0 +1,473 @@
+/*
+ * "$Id$"
+ *
+ * IEEE-1284 support functions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * backendGetDeviceID() - Get the IEEE-1284 device ID string and
+ * corresponding URI.
+ * backendGetMakeModel() - Get the make and model string from the device ID.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "backend-private.h"
+#include <cups/cups-private.h>
+
+
+/*
+ * 'backendGetDeviceID()' - Get the IEEE-1284 device ID string and
+ * corresponding URI.
+ */
+
+int /* O - 0 on success, -1 on failure */
+backendGetDeviceID(
+ 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 */
+{
+#ifdef __APPLE__ /* This function is a no-op */
+ (void)fd;
+ (void)device_id;
+ (void)device_id_size;
+ (void)make_model;
+ (void)make_model_size;
+ (void)scheme;
+ (void)uri;
+ (void)uri_size;
+
+ return (-1);
+
+#else /* Get the device ID from the specified file descriptor... */
+# ifdef __linux
+ int length; /* Length of device ID info */
+ int got_id = 0;
+# endif /* __linux */
+# if defined(__sun) && defined(ECPPIOC_GETDEVID)
+ struct ecpp_device_id did; /* Device ID buffer */
+# endif /* __sun && ECPPIOC_GETDEVID */
+
+
+ DEBUG_printf(("backendGetDeviceID(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 (!device_id || device_id_size < 32)
+ {
+ DEBUG_puts("backendGetDeviceID: Bad args!");
+ return (-1);
+ }
+
+ if (make_model)
+ *make_model = '\0';
+
+ if (fd >= 0)
+ {
+ /*
+ * Get the device ID string...
+ */
+
+ *device_id = '\0';
+
+# ifdef __linux
+ if (ioctl(fd, LPIOC_GET_DEVICE_ID(device_id_size), device_id))
+ {
+ /*
+ * Linux has to implement things differently for every device it seems.
+ * Since the standard parallel port driver does not provide a simple
+ * ioctl() to get the 1284 device ID, we have to open the "raw" parallel
+ * device corresponding to this port and do some negotiation trickery
+ * to get the current device ID.
+ */
+
+ if (uri && !strncmp(uri, "parallel:/dev/", 14))
+ {
+ char devparport[16]; /* /dev/parportN */
+ int devparportfd, /* File descriptor for raw device */
+ mode; /* Port mode */
+
+
+ /*
+ * Since the Linux parallel backend only supports 4 parallel port
+ * devices, just grab the trailing digit and use it to construct a
+ * /dev/parportN filename...
+ */
+
+ snprintf(devparport, sizeof(devparport), "/dev/parport%s",
+ uri + strlen(uri) - 1);
+
+ if ((devparportfd = open(devparport, O_RDWR | O_NOCTTY)) != -1)
+ {
+ /*
+ * Claim the device...
+ */
+
+ if (!ioctl(devparportfd, PPCLAIM))
+ {
+ fcntl(devparportfd, F_SETFL, fcntl(devparportfd, F_GETFL) | O_NONBLOCK);
+
+ mode = IEEE1284_MODE_COMPAT;
+
+ if (!ioctl(devparportfd, PPNEGOT, &mode))
+ {
+ /*
+ * Put the device into Device ID mode...
+ */
+
+ mode = IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID;
+
+ if (!ioctl(devparportfd, PPNEGOT, &mode))
+ {
+ /*
+ * Read the 1284 device ID...
+ */
+
+ if ((length = read(devparportfd, device_id,
+ device_id_size - 1)) >= 2)
+ {
+ device_id[length] = '\0';
+ got_id = 1;
+ }
+ }
+ }
+
+ /*
+ * Release the device...
+ */
+
+ ioctl(devparportfd, PPRELEASE);
+ }
+
+ close(devparportfd);
+ }
+ }
+ }
+ else
+ got_id = 1;
+
+ if (got_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)
+ length = (((unsigned)device_id[1] & 255) << 8) +
+ ((unsigned)device_id[0] & 255);
+
+ if (length > device_id_size)
+ length = device_id_size;
+
+ /*
+ * The length field counts the number of bytes in the string
+ * including the length field itself (2 bytes). The minimum
+ * length for a valid/usable device ID is 14 bytes:
+ *
+ * <LENGTH> MFG: <MFG> ;MDL: <MDL> ;
+ * 2 + 4 + 1 + 5 + 1 + 1
+ */
+
+ if (length < 14)
+ {
+ /*
+ * Can't use this device ID, so don't try to copy it...
+ */
+
+ device_id[0] = '\0';
+ got_id = 0;
+ }
+ else
+ {
+ /*
+ * Copy the device ID text to the beginning of the buffer and
+ * nul-terminate.
+ */
+
+ length -= 2;
+
+ memmove(device_id, device_id + 2, length);
+ device_id[length] = '\0';
+ }
+ }
+# ifdef DEBUG
+ else
+ DEBUG_printf(("backendGetDeviceID: 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
+ DEBUG_printf(("backendGetDeviceID: ioctl failed - %s\n",
+ strerror(errno)));
+# endif /* DEBUG */
+# endif /* __sun && ECPPIOC_GETDEVID */
+ }
+
+ DEBUG_printf(("backendGetDeviceID: device_id=\"%s\"\n", device_id));
+
+ if (scheme && uri)
+ *uri = '\0';
+
+ if (!*device_id)
+ return (-1);
+
+ /*
+ * Get the make and model...
+ */
+
+ if (make_model)
+ backendGetMakeModel(device_id, make_model, make_model_size);
+
+ /*
+ * Then generate a device URI...
+ */
+
+ if (scheme && uri && uri_size > 32)
+ {
+ int num_values; /* Number of keys and values */
+ cups_option_t *values; /* Keys and values in device ID */
+ const char *mfg, /* Manufacturer */
+ *mdl, /* Model */
+ *sern; /* Serial number */
+ char temp[256], /* Temporary manufacturer string */
+ *tempptr; /* Pointer into temp string */
+
+
+ /*
+ * Get the make, model, and serial numbers...
+ */
+
+ num_values = _cupsGet1284Values(device_id, &values);
+
+ if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL)
+ if ((sern = cupsGetOption("SERN", num_values, values)) == NULL)
+ sern = cupsGetOption("SN", num_values, values);
+
+ if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL)
+ mfg = cupsGetOption("MFG", num_values, values);
+
+ if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL)
+ mdl = cupsGetOption("MDL", num_values, values);
+
+ if (mfg)
+ {
+ if (!_cups_strcasecmp(mfg, "Hewlett-Packard"))
+ mfg = "HP";
+ else if (!_cups_strcasecmp(mfg, "Lexmark International"))
+ mfg = "Lexmark";
+ }
+ else
+ {
+ strlcpy(temp, make_model, sizeof(temp));
+
+ if ((tempptr = strchr(temp, ' ')) != NULL)
+ *tempptr = '\0';
+
+ mfg = temp;
+ }
+
+ if (!mdl)
+ mdl = "";
+
+ if (!_cups_strncasecmp(mdl, mfg, strlen(mfg)))
+ {
+ mdl += strlen(mfg);
+
+ while (isspace(*mdl & 255))
+ mdl ++;
+ }
+
+ /*
+ * Generate the device URI from the manufacturer, make_model, and
+ * serial number strings.
+ */
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, uri_size, scheme, NULL, mfg, 0,
+ "/%s%s%s", mdl, sern ? "?serial=" : "", sern ? sern : "");
+
+ cupsFreeOptions(num_values, values);
+ }
+
+ return (0);
+#endif /* __APPLE__ */
+}
+
+
+/*
+ * 'backendGetMakeModel()' - Get the make and model string from the device ID.
+ */
+
+int /* O - 0 on success, -1 on failure */
+backendGetMakeModel(
+ const char *device_id, /* O - 1284 device ID */
+ char *make_model, /* O - Make/model */
+ int make_model_size) /* I - Size of buffer */
+{
+ int num_values; /* Number of keys and values */
+ cups_option_t *values; /* Keys and values */
+ const char *mfg, /* Manufacturer string */
+ *mdl, /* Model string */
+ *des; /* Description string */
+
+
+ DEBUG_printf(("backendGetMakeModel(device_id=\"%s\", "
+ "make_model=%p, make_model_size=%d)\n", device_id,
+ make_model, make_model_size));
+
+ /*
+ * Range check input...
+ */
+
+ if (!device_id || !*device_id || !make_model || make_model_size < 32)
+ {
+ DEBUG_puts("backendGetMakeModel: Bad args!");
+ return (-1);
+ }
+
+ *make_model = '\0';
+
+ /*
+ * Look for the description field...
+ */
+
+ num_values = _cupsGet1284Values(device_id, &values);
+
+ if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL)
+ mdl = cupsGetOption("MDL", num_values, values);
+
+ if (mdl)
+ {
+ /*
+ * Build a make-model string from the manufacturer and model attributes...
+ */
+
+ if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL)
+ mfg = cupsGetOption("MFG", num_values, values);
+
+ if (!mfg || !_cups_strncasecmp(mdl, mfg, strlen(mfg)))
+ {
+ /*
+ * Just copy the model string, since it has the manufacturer...
+ */
+
+ _ppdNormalizeMakeAndModel(mdl, make_model, make_model_size);
+ }
+ else
+ {
+ /*
+ * Concatenate the make and model...
+ */
+
+ char temp[1024]; /* Temporary make and model */
+
+ snprintf(temp, sizeof(temp), "%s %s", mfg, mdl);
+
+ _ppdNormalizeMakeAndModel(temp, make_model, make_model_size);
+ }
+ }
+ else if ((des = cupsGetOption("DESCRIPTION", num_values, values)) != NULL ||
+ (des = cupsGetOption("DES", num_values, values)) != NULL)
+ {
+ /*
+ * 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 (strlen(des) >= 8)
+ {
+ const char *ptr; /* Pointer into description */
+ int letters, /* Number of letters seen */
+ spaces; /* Number of spaces seen */
+
+
+ for (ptr = des, letters = 0, spaces = 0; *ptr; ptr ++)
+ {
+ if (isspace(*ptr & 255))
+ spaces ++;
+ else if (isalpha(*ptr & 255))
+ letters ++;
+
+ if (spaces && letters)
+ break;
+ }
+
+ if (spaces && letters)
+ _ppdNormalizeMakeAndModel(des, make_model, make_model_size);
+ }
+ }
+
+ if (!make_model[0])
+ {
+ /*
+ * Use "Unknown" as the printer make and model...
+ */
+
+ strlcpy(make_model, "Unknown", make_model_size);
+ }
+
+ cupsFreeOptions(num_values, values);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/ipp.c b/backend/ipp.c
new file mode 100644
index 000000000..609a84e6b
--- /dev/null
+++ b/backend/ipp.c
@@ -0,0 +1,2981 @@
+/*
+ * "$Id$"
+ *
+ * IPP backend for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "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.
+ * cancel_job() - Cancel a print job.
+ * check_printer_state() - Check the printer state.
+ * compress_files() - Compress print files.
+ * monitor_printer() - Monitor the printer state.
+ * new_request() - Create a new print creation or validation request.
+ * password_cb() - Disable the password prompt for
+ * cupsDoFileRequest().
+ * report_attr() - Report an IPP attribute value.
+ * report_printer_state() - Report the printer state.
+ * run_as_user() - Run the IPP backend as the printing user.
+ * timeout_cb() - Handle HTTP timeouts.
+ * sigterm_handler() - Handle 'terminate' signals that stop the backend.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "backend-private.h"
+#include <cups/array-private.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#if defined(HAVE_GSSAPI) && defined(HAVE_XPC)
+# include <xpc/xpc.h>
+# define kPMPrintUIToolAgent "com.apple.printuitool.agent"
+# define kPMStartJob 100
+# define kPMWaitForJob 101
+extern void xpc_connection_set_target_uid(xpc_connection_t connection,
+ uid_t uid);
+#endif /* HAVE_GSSAPI && HAVE_XPC */
+
+
+/*
+ * Types...
+ */
+
+typedef struct _cups_monitor_s /**** Monitoring data ****/
+{
+ const char *uri, /* Printer URI */
+ *hostname, /* Hostname */
+ *user, /* Username */
+ *resource; /* Resource path */
+ int port, /* Port number */
+ version, /* IPP version */
+ job_id; /* Job ID for submitted job */
+ http_encryption_t encryption; /* Use encryption? */
+ ipp_jstate_t job_state; /* Current job state */
+ ipp_pstate_t printer_state; /* Current printer state */
+} _cups_monitor_t;
+
+
+/*
+ * Globals...
+ */
+
+static const char *auth_info_required;
+ /* New auth-info-required value */
+#if defined(HAVE_GSSAPI) && defined(HAVE_XPC)
+static int child_pid = 0; /* Child process ID */
+#endif /* HAVE_GSSAPI && HAVE_XPC */
+static const char * const jattrs[] = /* Job attributes we want */
+{
+ "job-impressions-completed",
+ "job-media-sheets-completed",
+ "job-state",
+ "job-state-reasons"
+};
+static int job_canceled = 0;
+ /* Job cancelled? */
+static char *password = NULL;
+ /* Password for device URI */
+static int password_tries = 0;
+ /* Password tries */
+static const char * const pattrs[] = /* Printer attributes we want */
+{
+ "copies-supported",
+ "cups-version",
+ "document-format-supported",
+ "marker-colors",
+ "marker-high-levels",
+ "marker-levels",
+ "marker-low-levels",
+ "marker-message",
+ "marker-names",
+ "marker-types",
+ "media-col-supported",
+ "multiple-document-handling-supported",
+ "operations-supported",
+ "printer-alert",
+ "printer-alert-description",
+ "printer-is-accepting-jobs",
+ "printer-state",
+ "printer-state-message",
+ "printer-state-reasons",
+};
+static const char * const remote_job_states[] =
+{ /* Remote job state keywords */
+ "+cups-remote-pending",
+ "+cups-remote-pending-held",
+ "+cups-remote-processing",
+ "+cups-remote-stopped",
+ "+cups-remote-canceled",
+ "+cups-remote-aborted",
+ "+cups-remote-completed"
+};
+static _cups_mutex_t report_mutex = _CUPS_MUTEX_INITIALIZER;
+ /* Mutex to control access */
+static int num_attr_cache = 0;
+ /* Number of cached attributes */
+static cups_option_t *attr_cache = NULL;
+ /* Cached attributes */
+static cups_array_t *state_reasons; /* Array of printe-state-reasons keywords */
+static char tmpfilename[1024] = "";
+ /* Temporary spool file name */
+
+
+/*
+ * Local functions...
+ */
+
+static void cancel_job(http_t *http, const char *uri, int id,
+ const char *resource, const char *user,
+ int version);
+static ipp_pstate_t check_printer_state(http_t *http, const char *uri,
+ const char *resource,
+ const char *user, int version);
+#ifdef HAVE_LIBZ
+static void compress_files(int num_files, char **files);
+#endif /* HAVE_LIBZ */
+static void *monitor_printer(_cups_monitor_t *monitor);
+static ipp_t *new_request(ipp_op_t op, int version, const char *uri,
+ const char *user, const char *title,
+ int num_options, cups_option_t *options,
+ const char *compression, int copies,
+ const char *format, _ppd_cache_t *pc,
+ ipp_attribute_t *media_col_sup,
+ ipp_attribute_t *doc_handling_sup);
+static const char *password_cb(const char *);
+static void report_attr(ipp_attribute_t *attr);
+static void report_printer_state(ipp_t *ipp);
+#if defined(HAVE_GSSAPI) && defined(HAVE_XPC)
+static int run_as_user(int argc, char *argv[], uid_t uid,
+ const char *device_uri, int fd);
+#endif /* HAVE_GSSAPI && HAVE_XPC */
+static void sigterm_handler(int sig);
+static int timeout_cb(http_t *http, void *user_data);
+static void update_reasons(ipp_attribute_t *attr, const char *s);
+
+
+/*
+ * '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 args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ int send_options; /* Send job options? */
+ int num_options; /* Number of printer options */
+ cups_option_t *options; /* Printer options */
+ const char *device_uri; /* Device URI */
+ char scheme[255], /* Scheme in URI */
+ hostname[1024], /* Hostname */
+ username[255], /* Username info */
+ resource[1024], /* Resource info (printer name) */
+ addrname[256], /* Address name */
+ *optptr, /* Pointer to URI options */
+ *name, /* Name of option */
+ *value, /* Value of option */
+ sep; /* Separator character */
+ http_addrlist_t *addrlist; /* Address of printer */
+ int snmp_fd, /* SNMP socket */
+ start_count, /* Page count via SNMP at start */
+ page_count, /* Page count via SNMP */
+ have_supplies; /* Printer supports supply levels? */
+ int num_files; /* Number of files to print */
+ char **files, /* Files to print */
+ *compatfile = NULL; /* Compatibility filename */
+ off_t compatsize = 0; /* Size of compatibility file */
+ int port; /* Port number (not used) */
+ char portname[255]; /* Port name */
+ char uri[HTTP_MAX_URI]; /* Updated URI without user/pass */
+ http_status_t http_status; /* Status of HTTP request */
+ 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 */
+ time_t start_time; /* Time of first connect */
+ int contimeout; /* Connection timeout */
+ int delay, /* Delay for retries */
+ prev_delay; /* Previous delay */
+ const char *compression; /* Compression mode */
+ int waitjob, /* Wait for job complete? */
+ waitprinter; /* Wait for printer ready? */
+ _cups_monitor_t monitor; /* Monitoring data */
+ ipp_attribute_t *job_id_attr; /* job-id attribute */
+ int job_id; /* job-id value */
+ ipp_attribute_t *job_sheets; /* job-media-sheets-completed */
+ ipp_attribute_t *job_state; /* job-state */
+ ipp_attribute_t *copies_sup; /* copies-supported */
+ ipp_attribute_t *cups_version; /* cups-version */
+ ipp_attribute_t *format_sup; /* document-format-supported */
+ ipp_attribute_t *media_col_sup; /* media-col-supported */
+ ipp_attribute_t *operations_sup; /* operations-supported */
+ ipp_attribute_t *doc_handling_sup; /* multiple-document-handling-supported */
+ ipp_attribute_t *printer_state; /* printer-state attribute */
+ ipp_attribute_t *printer_accepting; /* printer-is-accepting-jobs */
+ int validate_job; /* Does printer support Validate-Job? */
+ int copies, /* Number of copies for job */
+ copies_remaining; /* Number of copies remaining */
+ const char *content_type, /* CONTENT_TYPE environment variable */
+ *final_content_type, /* FINAL_CONTENT_TYPE environment var */
+ *document_format; /* document-format value */
+ int fd; /* File descriptor */
+ off_t bytes = 0; /* Bytes copied */
+ char buffer[16384]; /* Copy buffer */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+ int version; /* IPP version */
+ ppd_file_t *ppd; /* PPD file */
+ _ppd_cache_t *pc; /* PPD cache and mapping data */
+ fd_set input; /* Input set for select() */
+
+
+ /*
+ * 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\" \"%s (%s)\"\n",
+ s, _cupsLangString(cupsLangDefault(),
+ _("Internet Printing Protocol")), s);
+ return (CUPS_BACKEND_OK);
+ }
+ else if (argc < 6)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options [file]"),
+ argv[0]);
+ return (CUPS_BACKEND_STOP);
+ }
+
+ /*
+ * Get the device URI...
+ */
+
+ while ((device_uri = cupsBackendDeviceURI(argv)) == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer."));
+ sleep(10);
+
+ if (getenv("CLASS") != NULL)
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ if ((auth_info_required = getenv("AUTH_INFO_REQUIRED")) == NULL)
+ auth_info_required = "none";
+
+ state_reasons = _cupsArrayNewStrings(getenv("PRINTER_STATE_REASONS"));
+
+#ifdef HAVE_GSSAPI
+ /*
+ * For Kerberos, become the printing user (if we can) to get the credentials
+ * that way.
+ */
+
+ if (!getuid() && (value = getenv("AUTH_UID")) != NULL)
+ {
+ uid_t uid = (uid_t)atoi(value);
+ /* User ID */
+
+# ifdef HAVE_XPC
+ if (uid > 0)
+ {
+ if (argc == 6)
+ return (run_as_user(argc, argv, uid, device_uri, 0));
+ else
+ {
+ int status = 0; /* Exit status */
+
+ for (i = 6; i < argc && !status && !job_canceled; i ++)
+ {
+ if ((fd = open(argv[i], O_RDONLY)) >= 0)
+ {
+ status = run_as_user(argc, argv, uid, device_uri, fd);
+ close(fd);
+ }
+ else
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ status = CUPS_BACKEND_FAILED;
+ }
+ }
+
+ return (status);
+ }
+ }
+
+# else /* No XPC, just try to run as the user ID */
+ if (uid > 0)
+ seteuid(uid);
+# endif /* HAVE_XPC */
+ }
+#endif /* HAVE_GSSAPI */
+
+ /*
+ * Get the (final) content type...
+ */
+
+ if ((content_type = getenv("CONTENT_TYPE")) == NULL)
+ content_type = "application/octet-stream";
+
+ if ((final_content_type = getenv("FINAL_CONTENT_TYPE")) == NULL)
+ {
+ final_content_type = content_type;
+
+ if (!strncmp(final_content_type, "printer/", 8))
+ final_content_type = "application/vnd.cups-raw";
+ }
+
+ /*
+ * Extract the hostname and printer name from the URI...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme),
+ username, sizeof(username), hostname, sizeof(hostname), &port,
+ resource, sizeof(resource));
+
+ if (!port)
+ port = IPP_PORT; /* Default to port 631 */
+
+ if (!strcmp(scheme, "https"))
+ cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
+ else
+ cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED);
+
+ /*
+ * See if there are any options...
+ */
+
+ compression = NULL;
+ version = 20;
+ waitjob = 1;
+ waitprinter = 1;
+ contimeout = 7 * 24 * 60 * 60;
+
+ 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...
+ */
+
+ name = optptr;
+
+ while (*optptr && *optptr != '=' && *optptr != '+' && *optptr != '&')
+ optptr ++;
+
+ if ((sep = *optptr) != '\0')
+ *optptr++ = '\0';
+
+ if (sep == '=')
+ {
+ /*
+ * Get the value...
+ */
+
+ value = optptr;
+
+ while (*optptr && *optptr != '+' && *optptr != '&')
+ optptr ++;
+
+ if (*optptr)
+ *optptr++ = '\0';
+ }
+ else
+ value = (char *)"";
+
+ /*
+ * Process the option...
+ */
+
+ if (!_cups_strcasecmp(name, "waitjob"))
+ {
+ /*
+ * Wait for job completion?
+ */
+
+ waitjob = !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "yes") ||
+ !_cups_strcasecmp(value, "true");
+ }
+ else if (!_cups_strcasecmp(name, "waitprinter"))
+ {
+ /*
+ * Wait for printer idle?
+ */
+
+ waitprinter = !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "yes") ||
+ !_cups_strcasecmp(value, "true");
+ }
+ else if (!_cups_strcasecmp(name, "encryption"))
+ {
+ /*
+ * Enable/disable encryption?
+ */
+
+ if (!_cups_strcasecmp(value, "always"))
+ cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
+ else if (!_cups_strcasecmp(value, "required"))
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+ else if (!_cups_strcasecmp(value, "never"))
+ cupsSetEncryption(HTTP_ENCRYPT_NEVER);
+ else if (!_cups_strcasecmp(value, "ifrequested"))
+ cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED);
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unknown encryption option value: \"%s\"."),
+ value);
+ }
+ }
+ else if (!_cups_strcasecmp(name, "version"))
+ {
+ if (!strcmp(value, "1.0"))
+ version = 10;
+ else if (!strcmp(value, "1.1"))
+ version = 11;
+ else if (!strcmp(value, "2.0"))
+ version = 20;
+ else if (!strcmp(value, "2.1"))
+ version = 21;
+ else if (!strcmp(value, "2.2"))
+ version = 22;
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unknown version option value: \"%s\"."),
+ value);
+ }
+ }
+#ifdef HAVE_LIBZ
+ else if (!_cups_strcasecmp(name, "compression"))
+ {
+ if (!_cups_strcasecmp(value, "true") || !_cups_strcasecmp(value, "yes") ||
+ !_cups_strcasecmp(value, "on") || !_cups_strcasecmp(value, "gzip"))
+ compression = "gzip";
+ }
+#endif /* HAVE_LIBZ */
+ else if (!_cups_strcasecmp(name, "contimeout"))
+ {
+ /*
+ * Set the connection timeout...
+ */
+
+ if (atoi(value) > 0)
+ contimeout = atoi(value);
+ }
+ else
+ {
+ /*
+ * Unknown option...
+ */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unknown option \"%s\" with value \"%s\"."),
+ name, value);
+ }
+ }
+ }
+
+ /*
+ * 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)
+ {
+ num_files = 0;
+ send_options = !_cups_strcasecmp(final_content_type, "application/pdf") ||
+ !_cups_strcasecmp(final_content_type, "application/vnd.cups-pdf") ||
+ !_cups_strncasecmp(final_content_type, "image/", 6);
+
+ fputs("DEBUG: Sending stdin for job...\n", stderr);
+ }
+ else
+ {
+ /*
+ * Point to the files on the command-line...
+ */
+
+ num_files = argc - 6;
+ files = argv + 6;
+ send_options = 1;
+
+#ifdef HAVE_LIBZ
+ if (compression)
+ compress_files(num_files, files);
+#endif /* HAVE_LIBZ */
+
+ fprintf(stderr, "DEBUG: %d files to send in job...\n", num_files);
+ }
+
+ /*
+ * 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
+ {
+ /*
+ * Try loading authentication information from the environment.
+ */
+
+ const char *ptr = getenv("AUTH_USERNAME");
+
+ if (ptr)
+ cupsSetUser(ptr);
+
+ password = getenv("AUTH_PASSWORD");
+ }
+
+ /*
+ * Try finding the remote server...
+ */
+
+ start_time = time(NULL);
+
+ sprintf(portname, "%d", port);
+
+ update_reasons(NULL, "+connecting-to-device");
+ fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname);
+
+ while ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Unable to locate printer \"%s\"."), hostname);
+ sleep(10);
+
+ if (getenv("CLASS") != NULL)
+ {
+ update_reasons(NULL, "-connecting-to-device");
+ return (CUPS_BACKEND_STOP);
+ }
+ }
+
+ http = _httpCreate(hostname, port, addrlist, cupsEncryption(), AF_UNSPEC);
+ httpSetTimeout(http, 30.0, timeout_cb, NULL);
+
+ /*
+ * See if the printer supports SNMP...
+ */
+
+ if ((snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family)) >= 0)
+ {
+ have_supplies = !backendSNMPSupplies(snmp_fd, &(addrlist->addr),
+ &start_count, NULL);
+ }
+ else
+ have_supplies = start_count = 0;
+
+ /*
+ * Wait for data from the filter...
+ */
+
+ if (num_files == 0)
+ {
+ if (!backendWaitLoop(snmp_fd, &(addrlist->addr), 0, backendNetworkSideCB))
+ return (CUPS_BACKEND_OK);
+ else if ((bytes = read(0, buffer, sizeof(buffer))) <= 0)
+ return (CUPS_BACKEND_OK);
+ }
+
+ /*
+ * Try connecting to the remote server...
+ */
+
+ delay = _cupsNextDelay(0, &prev_delay);
+
+ do
+ {
+ fprintf(stderr, "DEBUG: Connecting to %s:%d\n", hostname, port);
+ _cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer."));
+
+ if (httpReconnect(http))
+ {
+ int error = errno; /* Connection error */
+
+ if (http->status == HTTP_PKI_ERROR)
+ update_reasons(NULL, "+cups-certificate-error");
+
+ if (job_canceled)
+ break;
+
+ 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.
+ */
+
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Unable to contact printer, queuing on next "
+ "printer in class."));
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ update_reasons(NULL, "-connecting-to-device");
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno));
+
+ if (errno == ECONNREFUSED || errno == EHOSTDOWN ||
+ errno == EHOSTUNREACH)
+ {
+ if (contimeout && (time(NULL) - start_time) > contimeout)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The printer is not responding."));
+ update_reasons(NULL, "-connecting-to-device");
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ switch (error)
+ {
+ case EHOSTDOWN :
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("The printer may not exist or "
+ "is unavailable at this time."));
+ break;
+
+ case EHOSTUNREACH :
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("The printer is unreachable at this "
+ "time."));
+ break;
+
+ case ECONNREFUSED :
+ default :
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("The printer is busy."));
+ break;
+ }
+
+ sleep(delay);
+
+ delay = _cupsNextDelay(delay, &prev_delay);
+ }
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The printer is not responding."));
+ sleep(30);
+ }
+
+ if (job_canceled)
+ break;
+ }
+ else
+ update_reasons(NULL, "-cups-certificate-error");
+ }
+ while (http->fd < 0);
+
+ if (job_canceled || !http)
+ return (CUPS_BACKEND_FAILED);
+
+ update_reasons(NULL, "-connecting-to-device");
+ _cupsLangPrintFilter(stderr, "INFO", _("Connected to printer."));
+
+ fprintf(stderr, "DEBUG: Connected to %s:%d...\n",
+ httpAddrString(http->hostaddr, addrname, sizeof(addrname)),
+ _httpAddrPort(http->hostaddr));
+
+ /*
+ * 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...
+ */
+
+ httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), scheme, NULL, hostname,
+ port, resource);
+
+ /*
+ * First validate the destination and see if the device supports multiple
+ * copies...
+ */
+
+ copies_sup = NULL;
+ cups_version = NULL;
+ format_sup = NULL;
+ media_col_sup = NULL;
+ supported = NULL;
+ operations_sup = NULL;
+ doc_handling_sup = NULL;
+ validate_job = 0;
+
+ do
+ {
+ /*
+ * Check for side-channel requests...
+ */
+
+ backendCheckSideChannel(snmp_fd, http->hostaddr);
+
+ /*
+ * Build the IPP request...
+ */
+
+ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+ request->request.op.version[0] = version / 10;
+ request->request.op.version[1] = version % 10;
+
+ 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 (http->version < HTTP_1_1)
+ {
+ fprintf(stderr, "DEBUG: Printer responded with HTTP version %d.%d.\n",
+ http->version / 100, http->version % 100);
+ update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
+ "cups-ipp-wrong-http-version");
+ }
+
+ supported = cupsDoRequest(http, request, resource);
+ ipp_status = cupsLastError();
+
+ fprintf(stderr, "DEBUG: Get-Printer-Attributes: %s (%s)\n",
+ ippErrorString(ipp_status), cupsLastErrorString());
+
+ if (ipp_status > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "DEBUG: Get-Printer-Attributes returned %s.\n",
+ ippErrorString(ipp_status));
+
+ if (ipp_status == IPP_PRINTER_BUSY ||
+ ipp_status == IPP_SERVICE_UNAVAILABLE)
+ {
+ if (contimeout && (time(NULL) - start_time) > contimeout)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The printer is not responding."));
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ _cupsLangPrintFilter(stderr, "INFO", _("The printer is busy."));
+
+ report_printer_state(supported);
+
+ sleep(delay);
+
+ delay = _cupsNextDelay(delay, &prev_delay);
+ }
+ else if ((ipp_status == IPP_BAD_REQUEST ||
+ ipp_status == IPP_VERSION_NOT_SUPPORTED) && version > 10)
+ {
+ /*
+ * Switch to IPP/1.1 or IPP/1.0...
+ */
+
+ if (version >= 20)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printer does not support IPP/%d.%d, trying "
+ "IPP/%s."), version / 10, version % 10, "1.1");
+ version = 11;
+ }
+ else
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printer does not support IPP/%d.%d, trying "
+ "IPP/%s."), version / 10, version % 10, "1.0");
+ version = 10;
+ }
+
+ httpReconnect(http);
+ }
+ else if (ipp_status == IPP_NOT_FOUND)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The printer URI is incorrect or no longer "
+ "exists."));
+
+ ippDelete(supported);
+
+ return (CUPS_BACKEND_STOP);
+ }
+ else if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
+ {
+ if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
+ "Negotiate", 9))
+ auth_info_required = "negotiate";
+
+ fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
+ return (CUPS_BACKEND_AUTH_REQUIRED);
+ }
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to get printer status."));
+ sleep(10);
+ }
+
+ ippDelete(supported);
+ supported = NULL;
+ continue;
+ }
+
+ if (!getenv("CLASS"))
+ {
+ /*
+ * Check printer-is-accepting-jobs = false and printer-state-reasons for the
+ * "spool-area-full" keyword...
+ */
+
+ int busy = 0;
+
+ if ((printer_accepting = ippFindAttribute(supported,
+ "printer-is-accepting-jobs",
+ IPP_TAG_BOOLEAN)) != NULL &&
+ !printer_accepting->values[0].boolean)
+ busy = 1;
+ else if (!printer_accepting)
+ update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
+ "cups-ipp-missing-printer-is-accepting-jobs");
+
+ if ((printer_state = ippFindAttribute(supported,
+ "printer-state-reasons",
+ IPP_TAG_KEYWORD)) != NULL && !busy)
+ {
+ for (i = 0; i < printer_state->num_values; i ++)
+ if (!strcmp(printer_state->values[0].string.text,
+ "spool-area-full") ||
+ !strncmp(printer_state->values[0].string.text, "spool-area-full-",
+ 16))
+ {
+ busy = 1;
+ break;
+ }
+ }
+ else
+ update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
+ "cups-ipp-missing-printer-state-reasons");
+
+ if (busy)
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("The printer is busy."));
+
+ report_printer_state(supported);
+
+ sleep(delay);
+
+ delay = _cupsNextDelay(delay, &prev_delay);
+
+ ippDelete(supported);
+ supported = NULL;
+ continue;
+ }
+ }
+
+ /*
+ * Check for supported attributes...
+ */
+
+ if ((copies_sup = ippFindAttribute(supported, "copies-supported",
+ IPP_TAG_RANGE)) != NULL)
+ {
+ /*
+ * Has the "copies-supported" attribute - does it have an upper
+ * bound > 1?
+ */
+
+ fprintf(stderr, "DEBUG: copies-supported=%d-%d\n",
+ copies_sup->values[0].range.lower,
+ copies_sup->values[0].range.upper);
+
+ if (copies_sup->values[0].range.upper <= 1)
+ copies_sup = NULL; /* No */
+ }
+
+ cups_version = ippFindAttribute(supported, "cups-version", IPP_TAG_TEXT);
+
+ if ((format_sup = ippFindAttribute(supported, "document-format-supported",
+ IPP_TAG_MIMETYPE)) != NULL)
+ {
+ 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);
+ }
+
+ if ((media_col_sup = ippFindAttribute(supported, "media-col-supported",
+ IPP_TAG_KEYWORD)) != NULL)
+ {
+ fprintf(stderr, "DEBUG: media-col-supported (%d values)\n",
+ media_col_sup->num_values);
+ for (i = 0; i < media_col_sup->num_values; i ++)
+ fprintf(stderr, "DEBUG: [%d] = \"%s\"\n", i,
+ media_col_sup->values[i].string.text);
+ }
+
+ if ((operations_sup = ippFindAttribute(supported, "operations-supported",
+ IPP_TAG_ENUM)) != NULL)
+ {
+ for (i = 0; i < operations_sup->num_values; i ++)
+ if (operations_sup->values[i].integer == IPP_PRINT_JOB)
+ break;
+
+ if (i >= operations_sup->num_values)
+ update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
+ "cups-ipp-missing-print-job");
+
+ for (i = 0; i < operations_sup->num_values; i ++)
+ if (operations_sup->values[i].integer == IPP_CANCEL_JOB)
+ break;
+
+ if (i >= operations_sup->num_values)
+ update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
+ "cups-ipp-missing-cancel-job");
+
+ for (i = 0; i < operations_sup->num_values; i ++)
+ if (operations_sup->values[i].integer == IPP_GET_JOB_ATTRIBUTES)
+ break;
+
+ if (i >= operations_sup->num_values)
+ update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
+ "cups-ipp-missing-get-job-attributes");
+
+ for (i = 0; i < operations_sup->num_values; i ++)
+ if (operations_sup->values[i].integer == IPP_GET_PRINTER_ATTRIBUTES)
+ break;
+
+ if (i >= operations_sup->num_values)
+ update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
+ "cups-ipp-missing-get-printer-attributes");
+
+ for (i = 0; i < operations_sup->num_values; i ++)
+ if (operations_sup->values[i].integer == IPP_VALIDATE_JOB)
+ {
+ validate_job = 1;
+ break;
+ }
+
+ if (!validate_job)
+ update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
+ "cups-ipp-missing-validate-job");
+ }
+ else
+ update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
+ "cups-ipp-missing-operations-supported");
+
+ doc_handling_sup = ippFindAttribute(supported,
+ "multiple-document-handling-supported",
+ IPP_TAG_KEYWORD);
+
+ 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.
+ */
+
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Unable to contact printer, queuing on next "
+ "printer in class."));
+
+ ippDelete(supported);
+ httpClose(http);
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+
+ /*
+ * See if the printer supports multiple copies...
+ */
+
+ copies = atoi(argv[4]);
+
+ if (copies_sup || argc < 7)
+ {
+ copies_remaining = 1;
+
+ if (argc < 7 && !send_options)
+ copies = 1;
+ }
+ else
+ copies_remaining = copies;
+
+ /*
+ * Prepare remaining printing options...
+ */
+
+ options = NULL;
+ pc = NULL;
+
+ if (send_options)
+ {
+ num_options = cupsParseOptions(argv[5], 0, &options);
+
+ if (!cups_version && media_col_sup)
+ {
+ /*
+ * Load the PPD file and generate PWG attribute mapping information...
+ */
+
+ ppd = ppdOpenFile(getenv("PPD"));
+ pc = _ppdCacheCreateWithPPD(ppd);
+
+ ppdClose(ppd);
+ }
+ }
+ else
+ num_options = 0;
+
+ document_format = NULL;
+
+ if (format_sup != NULL)
+ {
+ for (i = 0; i < format_sup->num_values; i ++)
+ if (!_cups_strcasecmp(final_content_type, format_sup->values[i].string.text))
+ {
+ document_format = final_content_type;
+ break;
+ }
+
+ if (!document_format)
+ {
+ for (i = 0; i < format_sup->num_values; i ++)
+ if (!_cups_strcasecmp("application/octet-stream",
+ format_sup->values[i].string.text))
+ {
+ document_format = "application/octet-stream";
+ break;
+ }
+ }
+ }
+
+ /*
+ * If the printer does not support HTTP/1.1 (which IPP requires), copy stdin
+ * to a temporary file so that we can do a HTTP/1.0 submission...
+ *
+ * (I hate compatibility hacks!)
+ */
+
+ if (http->version < HTTP_1_1 && num_files == 0)
+ {
+ if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0)
+ {
+ perror("DEBUG: Unable to create temporary file");
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ _cupsLangPrintFilter(stderr, "INFO", _("Copying print data."));
+
+ compatsize = backendRunLoop(-1, fd, snmp_fd, &(addrlist->addr), 0, 0,
+ backendNetworkSideCB);
+
+ close(fd);
+
+ compatfile = tmpfilename;
+ files = &compatfile;
+ num_files = 1;
+ }
+ else if (http->version < HTTP_1_1 && num_files == 1)
+ {
+ struct stat fileinfo; /* File information */
+
+ if (!stat(files[0], &fileinfo))
+ compatsize = fileinfo.st_size;
+ }
+
+ /*
+ * Start monitoring the printer in the background...
+ */
+
+ monitor.uri = uri;
+ monitor.hostname = hostname;
+ monitor.user = argv[2];
+ monitor.resource = resource;
+ monitor.port = port;
+ monitor.version = version;
+ monitor.job_id = 0;
+ monitor.encryption = cupsEncryption();
+ monitor.job_state = IPP_JOB_PENDING;
+ monitor.printer_state = IPP_PRINTER_IDLE;
+
+ _cupsThreadCreate((_cups_thread_func_t)monitor_printer, &monitor);
+
+ /*
+ * Validate access to the printer...
+ */
+
+ while (!job_canceled && validate_job)
+ {
+ request = new_request(IPP_VALIDATE_JOB, version, uri, argv[2], argv[3],
+ num_options, options, compression,
+ copies_sup ? copies : 1, document_format, pc,
+ media_col_sup, doc_handling_sup);
+
+ ippDelete(cupsDoRequest(http, request, resource));
+
+ ipp_status = cupsLastError();
+
+ fprintf(stderr, "DEBUG: Validate-Job: %s (%s)\n",
+ ippErrorString(ipp_status), cupsLastErrorString());
+
+ if (job_canceled)
+ break;
+
+ if (ipp_status == IPP_SERVICE_UNAVAILABLE || ipp_status == IPP_PRINTER_BUSY)
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("The printer is busy."));
+ sleep(10);
+ }
+ else if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN ||
+ ipp_status == IPP_AUTHENTICATION_CANCELED)
+ {
+ /*
+ * Update auth-info-required as needed...
+ */
+
+ fprintf(stderr, "DEBUG: WWW-Authenticate=\"%s\"\n",
+ httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE));
+
+ /*
+ * Normal authentication goes through the password callback, which sets
+ * auth_info_required to "username,password". Kerberos goes directly
+ * through GSSAPI, so look for Negotiate in the WWW-Authenticate header
+ * here and set auth_info_required as needed...
+ */
+
+ if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
+ "Negotiate", 9))
+ auth_info_required = "negotiate";
+
+ goto cleanup;
+ }
+ else if (ipp_status == IPP_OPERATION_NOT_SUPPORTED)
+ {
+ /*
+ * This is all too common...
+ */
+
+ update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
+ "cups-ipp-missing-validate-job");
+ break;
+ }
+ else if (ipp_status < IPP_REDIRECTION_OTHER_SITE)
+ break;
+ }
+
+ /*
+ * Then issue the print-job request...
+ */
+
+ job_id = 0;
+
+ while (!job_canceled && copies_remaining > 0)
+ {
+ /*
+ * Check for side-channel requests...
+ */
+
+ backendCheckSideChannel(snmp_fd, http->hostaddr);
+
+ /*
+ * Build the IPP job creation request...
+ */
+
+ if (job_canceled)
+ break;
+
+ request = new_request(num_files > 1 ? IPP_CREATE_JOB : IPP_PRINT_JOB,
+ version, uri, argv[2], argv[3], num_options, options,
+ compression, copies_sup ? copies : 1, document_format,
+ pc, media_col_sup, doc_handling_sup);
+
+ /*
+ * Do the request...
+ */
+
+ if (num_files > 1)
+ response = cupsDoRequest(http, request, resource);
+ else
+ {
+ size_t length = 0; /* Length of request */
+
+ if (compatsize > 0)
+ {
+ fputs("DEBUG: Sending file using HTTP/1.0 Content-Length...\n", stderr);
+ length = ippLength(request) + (size_t)compatsize;
+ }
+ else
+ fputs("DEBUG: Sending file using HTTP/1.1 chunking...\n", stderr);
+
+ http_status = cupsSendRequest(http, request, resource, length);
+ if (http_status == HTTP_CONTINUE && request->state == IPP_DATA)
+ {
+ if (num_files == 1)
+ fd = open(files[0], O_RDONLY);
+ else
+ {
+ fd = 0;
+ http_status = cupsWriteRequestData(http, buffer, bytes);
+ }
+
+ while (http_status == HTTP_CONTINUE)
+ {
+ /*
+ * Check for side-channel requests and more print data...
+ */
+
+ FD_ZERO(&input);
+ FD_SET(fd, &input);
+ FD_SET(snmp_fd, &input);
+
+ while (select(fd > snmp_fd ? fd + 1 : snmp_fd + 1, &input, NULL, NULL,
+ NULL) <= 0 && !job_canceled);
+
+ if (FD_ISSET(snmp_fd, &input))
+ backendCheckSideChannel(snmp_fd, http->hostaddr);
+
+ if (FD_ISSET(fd, &input))
+ {
+ if ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
+ {
+ fprintf(stderr, "DEBUG: Read %d bytes...\n", (int)bytes);
+
+ if (cupsWriteRequestData(http, buffer, bytes) != HTTP_CONTINUE)
+ break;
+ }
+ else if (bytes == 0 || (errno != EINTR && errno != EAGAIN))
+ break;
+ }
+ }
+
+ if (num_files == 1)
+ close(fd);
+ }
+
+ response = cupsGetResponse(http, resource);
+ ippDelete(request);
+ }
+
+ ipp_status = cupsLastError();
+
+ fprintf(stderr, "DEBUG: %s: %s (%s)\n",
+ num_files > 1 ? "Create-Job" : "Print-Job",
+ ippErrorString(ipp_status), cupsLastErrorString());
+
+ if (ipp_status > IPP_OK_CONFLICT)
+ {
+ job_id = 0;
+
+ if (job_canceled)
+ break;
+
+ if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
+ ipp_status == IPP_PRINTER_BUSY)
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("The printer is busy."));
+ sleep(10);
+
+ if (num_files == 0)
+ {
+ /*
+ * We can't re-submit when we have no files to print, so exit
+ * immediately with the right status code...
+ */
+
+ goto cleanup;
+ }
+ }
+ else
+ {
+ /*
+ * Update auth-info-required as needed...
+ */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Print file was not accepted."));
+
+ if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
+ {
+ fprintf(stderr, "DEBUG: WWW-Authenticate=\"%s\"\n",
+ httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE));
+
+ /*
+ * Normal authentication goes through the password callback, which sets
+ * auth_info_required to "username,password". Kerberos goes directly
+ * through GSSAPI, so look for Negotiate in the WWW-Authenticate header
+ * here and set auth_info_required as needed...
+ */
+
+ if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
+ "Negotiate", 9))
+ auth_info_required = "negotiate";
+ }
+ else
+ sleep(10);
+
+ if (num_files == 0)
+ {
+ /*
+ * We can't re-submit when we have no files to print, so exit
+ * immediately with the right status code...
+ */
+
+ goto cleanup;
+ }
+ }
+ }
+ else if ((job_id_attr = ippFindAttribute(response, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Print file accepted - job ID unknown."));
+ update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
+ "cups-ipp-missing-job-id");
+ job_id = 0;
+ }
+ else
+ {
+ monitor.job_id = job_id = job_id_attr->values[0].integer;
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Print file accepted - job ID %d."), job_id);
+ }
+
+ ippDelete(response);
+
+ if (job_canceled)
+ break;
+
+ if (job_id && num_files > 1)
+ {
+ for (i = 0; i < num_files; i ++)
+ {
+ /*
+ * Check for side-channel requests...
+ */
+
+ backendCheckSideChannel(snmp_fd, http->hostaddr);
+
+ /*
+ * Send the next file in the job...
+ */
+
+ request = ippNewRequest(IPP_SEND_DOCUMENT);
+ request->request.op.version[0] = version / 10;
+ request->request.op.version[1] = version % 10;
+
+ 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]);
+
+ if ((i + 1) == num_files)
+ ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
+ "document-format", NULL, content_type);
+
+ fprintf(stderr, "DEBUG: Sending file %d using chunking...\n", i + 1);
+ http_status = cupsSendRequest(http, request, resource, 0);
+ if (http_status == HTTP_CONTINUE && request->state == IPP_DATA &&
+ (fd = open(files[i], O_RDONLY)) >= 0)
+ {
+ while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
+ {
+ if (cupsWriteRequestData(http, buffer, bytes) != HTTP_CONTINUE)
+ break;
+ else
+ {
+ /*
+ * Check for side-channel requests...
+ */
+
+ backendCheckSideChannel(snmp_fd, http->hostaddr);
+ }
+ }
+
+ close(fd);
+ }
+
+ ippDelete(cupsGetResponse(http, resource));
+ ippDelete(request);
+
+ fprintf(stderr, "DEBUG: Send-Document: %s (%s)\n",
+ ippErrorString(cupsLastError()), cupsLastErrorString());
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ ipp_status = cupsLastError();
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to add document to print job."));
+ break;
+ }
+ }
+ }
+
+ if (ipp_status <= IPP_OK_CONFLICT && argc > 6)
+ {
+ fprintf(stderr, "PAGE: 1 %d\n", copies_sup ? atoi(argv[4]) : 1);
+ copies_remaining --;
+ }
+ else if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
+ ipp_status == IPP_PRINTER_BUSY)
+ continue;
+ else
+ copies_remaining --;
+
+ /*
+ * Wait for the job to complete...
+ */
+
+ if (!job_id || !waitjob)
+ continue;
+
+ _cupsLangPrintFilter(stderr, "INFO", _("Waiting for job to complete."));
+
+ for (delay = _cupsNextDelay(0, &prev_delay); !job_canceled;)
+ {
+ /*
+ * Check for side-channel requests...
+ */
+
+ backendCheckSideChannel(snmp_fd, http->hostaddr);
+
+ /*
+ * Build an IPP_GET_JOB_ATTRIBUTES request...
+ */
+
+ request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
+ request->request.op.version[0] = version / 10;
+ request->request.op.version[1] = version % 10;
+
+ 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...
+ */
+
+ httpReconnect(http);
+ response = cupsDoRequest(http, request, resource);
+ ipp_status = cupsLastError();
+
+ if (ipp_status == IPP_NOT_FOUND)
+ {
+ /*
+ * Job has gone away and/or the server has no job history...
+ */
+
+ update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
+ "cups-ipp-missing-job-history");
+ ippDelete(response);
+
+ ipp_status = IPP_OK;
+ break;
+ }
+
+ fprintf(stderr, "DEBUG: Get-Job-Attributes: %s (%s)\n",
+ ippErrorString(ipp_status), cupsLastErrorString());
+
+ if (ipp_status > IPP_OK_CONFLICT)
+ {
+ if (ipp_status != IPP_SERVICE_UNAVAILABLE &&
+ ipp_status != IPP_PRINTER_BUSY)
+ {
+ ippDelete(response);
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to get print job status."));
+ break;
+ }
+ }
+
+ if (response)
+ {
+ if ((job_state = ippFindAttribute(response, "job-state",
+ IPP_TAG_ENUM)) != NULL)
+ {
+ /*
+ * Reflect the remote job state in the local queue...
+ */
+
+ if (cups_version &&
+ job_state->values[0].integer >= IPP_JOB_PENDING &&
+ job_state->values[0].integer <= IPP_JOB_COMPLETED)
+ update_reasons(NULL,
+ remote_job_states[job_state->values[0].integer -
+ IPP_JOB_PENDING]);
+
+ if ((job_sheets = ippFindAttribute(response,
+ "job-media-sheets-completed",
+ IPP_TAG_INTEGER)) == NULL)
+ job_sheets = ippFindAttribute(response,
+ "job-impressions-completed",
+ IPP_TAG_INTEGER);
+
+ if (job_sheets)
+ fprintf(stderr, "PAGE: total %d\n",
+ job_sheets->values[0].integer);
+
+ /*
+ * Stop polling if the job is finished or pending-held...
+ */
+
+ if (job_state->values[0].integer > IPP_JOB_STOPPED)
+ {
+ ippDelete(response);
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * If the printer does not return a job-state attribute, it does not
+ * conform to the IPP specification - break out immediately and fail
+ * the job...
+ */
+
+ update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
+ "cups-ipp-missing-job-state");
+ ipp_status = IPP_INTERNAL_ERROR;
+ break;
+ }
+ }
+
+ ippDelete(response);
+
+ /*
+ * Wait before polling again...
+ */
+
+ sleep(delay);
+
+ delay = _cupsNextDelay(delay, &prev_delay);
+ }
+ }
+
+ /*
+ * Cancel the job as needed...
+ */
+
+ if (job_canceled && job_id)
+ cancel_job(http, uri, job_id, resource, argv[2], version);
+
+ /*
+ * Check the printer state and report it if necessary...
+ */
+
+ check_printer_state(http, uri, resource, argv[2], version);
+
+ /*
+ * Collect the final page count as needed...
+ */
+
+ if (have_supplies &&
+ !backendSNMPSupplies(snmp_fd, http->hostaddr, &page_count, NULL) &&
+ page_count > start_count)
+ fprintf(stderr, "PAGE: total %d\n", page_count - start_count);
+
+#ifdef HAVE_GSSAPI
+ /*
+ * See if we used Kerberos at all...
+ */
+
+ if (http->gssctx)
+ auth_info_required = "negotiate";
+#endif /* HAVE_GSSAPI */
+
+ /*
+ * Free memory...
+ */
+
+ cleanup:
+
+ cupsFreeOptions(num_options, options);
+ _ppdCacheDestroy(pc);
+
+ httpClose(http);
+
+ ippDelete(supported);
+
+ /*
+ * Remove the temporary file(s) if necessary...
+ */
+
+ if (tmpfilename[0])
+ unlink(tmpfilename);
+
+#ifdef HAVE_LIBZ
+ if (compression)
+ {
+ for (i = 0; i < num_files; i ++)
+ unlink(files[i]);
+ }
+#endif /* HAVE_LIBZ */
+
+ /*
+ * Return the queue status...
+ */
+
+ if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN ||
+ ipp_status == IPP_AUTHENTICATION_CANCELED ||
+ ipp_status <= IPP_OK_CONFLICT)
+ fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
+
+ if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN ||
+ ipp_status == IPP_AUTHENTICATION_CANCELED)
+ return (CUPS_BACKEND_AUTH_REQUIRED);
+ else if (ipp_status == IPP_INTERNAL_ERROR)
+ return (CUPS_BACKEND_STOP);
+ else if (ipp_status == IPP_DOCUMENT_FORMAT ||
+ ipp_status == IPP_CONFLICT)
+ return (CUPS_BACKEND_FAILED);
+ else if (ipp_status > IPP_OK_CONFLICT)
+ return (CUPS_BACKEND_RETRY_CURRENT);
+ else
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("Ready to print."));
+ return (CUPS_BACKEND_OK);
+ }
+}
+
+
+/*
+ * 'cancel_job()' - Cancel a print job.
+ */
+
+static void
+cancel_job(http_t *http, /* I - HTTP connection */
+ const char *uri, /* I - printer-uri */
+ int id, /* I - job-id */
+ const char *resource, /* I - Resource path */
+ const char *user, /* I - requesting-user-name */
+ int version) /* I - IPP version */
+{
+ ipp_t *request; /* Cancel-Job request */
+
+
+ _cupsLangPrintFilter(stderr, "INFO", _("Canceling print job."));
+
+ request = ippNewRequest(IPP_CANCEL_JOB);
+ request->request.op.version[0] = version / 10;
+ request->request.op.version[1] = version % 10;
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", id);
+
+ if (user && user[0])
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+
+ /*
+ * Do the request...
+ */
+
+ ippDelete(cupsDoRequest(http, request, resource));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ _cupsLangPrintFilter(stderr, "ERROR", _("Unable to cancel print job."));
+}
+
+
+/*
+ * 'check_printer_state()' - Check the printer state.
+ */
+
+static ipp_pstate_t /* O - Current printer-state */
+check_printer_state(
+ http_t *http, /* I - HTTP connection */
+ 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 */
+ ipp_attribute_t *attr; /* Attribute in response */
+ ipp_pstate_t printer_state = IPP_PRINTER_STOPPED;
+ /* Current printer-state */
+
+
+ /*
+ * Send a Get-Printer-Attributes request and log the results...
+ */
+
+ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+ request->request.op.version[0] = version / 10;
+ request->request.op.version[1] = version % 10;
+
+ 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);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs);
+
+ if ((response = cupsDoRequest(http, request, resource)) != NULL)
+ {
+ report_printer_state(response);
+
+ if ((attr = ippFindAttribute(response, "printer-state",
+ IPP_TAG_ENUM)) != NULL)
+ printer_state = (ipp_pstate_t)attr->values[0].integer;
+
+ ippDelete(response);
+ }
+
+ fprintf(stderr, "DEBUG: Get-Printer-Attributes: %s (%s)\n",
+ ippErrorString(cupsLastError()), cupsLastErrorString());
+
+ /*
+ * Return the printer-state value...
+ */
+
+ return (printer_state);
+}
+
+
+#ifdef HAVE_LIBZ
+/*
+ * 'compress_files()' - Compress print files.
+ */
+
+static void
+compress_files(int num_files, /* I - Number of files */
+ char **files) /* I - Files */
+{
+ int i, /* Looping var */
+ fd; /* Temporary file descriptor */
+ ssize_t bytes; /* Bytes read/written */
+ size_t total; /* Total bytes read */
+ cups_file_t *in, /* Input file */
+ *out; /* Output file */
+ struct stat outinfo; /* Output file information */
+ char filename[1024], /* Temporary filename */
+ buffer[32768]; /* Copy buffer */
+
+
+ fprintf(stderr, "DEBUG: Compressing %d job files...\n", num_files);
+ for (i = 0; i < num_files; i ++)
+ {
+ if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to create compressed print file"));
+ exit(CUPS_BACKEND_FAILED);
+ }
+
+ if ((out = cupsFileOpenFd(fd, "w9")) == NULL)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open compressed print file"));
+ exit(CUPS_BACKEND_FAILED);
+ }
+
+ if ((in = cupsFileOpen(files[i], "r")) == NULL)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ cupsFileClose(out);
+ exit(CUPS_BACKEND_FAILED);
+ }
+
+ total = 0;
+ while ((bytes = cupsFileRead(in, buffer, sizeof(buffer))) > 0)
+ if (cupsFileWrite(out, buffer, bytes) < bytes)
+ {
+ _cupsLangPrintError("ERROR",
+ _("Unable to generate compressed print file"));
+ cupsFileClose(in);
+ cupsFileClose(out);
+ exit(CUPS_BACKEND_FAILED);
+ }
+ else
+ total += bytes;
+
+ cupsFileClose(out);
+ cupsFileClose(in);
+
+ files[i] = strdup(filename);
+
+ if (!stat(filename, &outinfo))
+ fprintf(stderr,
+ "DEBUG: File %d compressed to %.1f%% of original size, "
+ CUPS_LLFMT " bytes...\n",
+ i + 1, 100.0 * outinfo.st_size / total,
+ CUPS_LLCAST outinfo.st_size);
+ }
+}
+#endif /* HAVE_LIBZ */
+
+
+/*
+ * 'monitor_printer()' - Monitor the printer state.
+ */
+
+static void * /* O - Thread exit code */
+monitor_printer(
+ _cups_monitor_t *monitor) /* I - Monitoring data */
+{
+ http_t *http; /* Connection to printer */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* Attribute in response */
+ int delay, /* Current delay */
+ prev_delay; /* Previous delay */
+
+
+ /*
+ * Make a copy of the printer connection...
+ */
+
+ http = _httpCreate(monitor->hostname, monitor->port, NULL, monitor->encryption,
+ AF_UNSPEC);
+ httpSetTimeout(http, 30.0, timeout_cb, NULL);
+ cupsSetPasswordCB(password_cb);
+
+ /*
+ * Loop until the job is canceled, aborted, or completed.
+ */
+
+ delay = _cupsNextDelay(0, &prev_delay);
+
+ while (monitor->job_state < IPP_JOB_CANCELED && !job_canceled)
+ {
+ /*
+ * Reconnect to the printer...
+ */
+
+ if (!httpReconnect(http))
+ {
+ /*
+ * Connected, so check on the printer state...
+ */
+
+ monitor->printer_state = check_printer_state(http, monitor->uri,
+ monitor->resource,
+ monitor->user,
+ monitor->version);
+
+ if (monitor->job_id > 0)
+ {
+ /*
+ * Check the status of the job itself...
+ */
+
+ request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
+ request->request.op.version[0] = monitor->version / 10;
+ request->request.op.version[1] = monitor->version % 10;
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, monitor->uri);
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
+ monitor->job_id);
+
+ if (monitor->user && monitor->user[0])
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, monitor->user);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ (int)(sizeof(jattrs) / sizeof(jattrs[0])), NULL, jattrs);
+
+ /*
+ * Do the request...
+ */
+
+ response = cupsDoRequest(http, request, monitor->resource);
+
+ fprintf(stderr, "DEBUG: Get-Job-Attributes: %s (%s)\n",
+ ippErrorString(cupsLastError()), cupsLastErrorString());
+
+ if ((attr = ippFindAttribute(response, "job-state",
+ IPP_TAG_ENUM)) != NULL)
+ monitor->job_state = (ipp_jstate_t)attr->values[0].integer;
+ else
+ monitor->job_state = IPP_JOB_COMPLETED;
+
+ ippDelete(response);
+ }
+
+ /*
+ * Disconnect from the printer - we'll reconnect on the next poll...
+ */
+
+ _httpDisconnect(http);
+ }
+
+ /*
+ * Sleep for N seconds...
+ */
+
+ sleep(delay);
+
+ delay = _cupsNextDelay(delay, &prev_delay);
+ }
+
+ /*
+ * Cleanup and return...
+ */
+
+ httpClose(http);
+
+ return (NULL);
+}
+
+
+/*
+ * 'new_request()' - Create a new print creation or validation request.
+ */
+
+static ipp_t * /* O - Request data */
+new_request(
+ ipp_op_t op, /* I - IPP operation code */
+ int version, /* I - IPP version number */
+ const char *uri, /* I - printer-uri value */
+ const char *user, /* I - requesting-user-name value */
+ const char *title, /* I - job-name value */
+ int num_options, /* I - Number of options to send */
+ cups_option_t *options, /* I - Options to send */
+ const char *compression, /* I - compression value or NULL */
+ int copies, /* I - copies value or 0 */
+ const char *format, /* I - documet-format value or NULL */
+ _ppd_cache_t *pc, /* I - PPD cache and mapping data */
+ ipp_attribute_t *media_col_sup, /* I - media-col-supported values */
+ ipp_attribute_t *doc_handling_sup) /* I - multiple-document-handling-supported values */
+{
+ int i; /* Looping var */
+ ipp_t *request; /* Request data */
+ const char *keyword; /* PWG keyword */
+ _pwg_size_t *size; /* PWG media size */
+ ipp_t *media_col, /* media-col value */
+ *media_size; /* media-size value */
+ const char *media_source, /* media-source value */
+ *media_type, /* media-type value */
+ *collate_str; /* multiple-document-handling value */
+
+
+ /*
+ * Create the IPP request...
+ */
+
+ request = ippNewRequest(op);
+ request->request.op.version[0] = version / 10;
+ request->request.op.version[1] = version % 10;
+
+ fprintf(stderr, "DEBUG: %s IPP/%d.%d\n",
+ ippOpString(request->request.op.operation_id),
+ request->request.op.version[0],
+ request->request.op.version[1]);
+
+ /*
+ * Add standard attributes...
+ */
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+ fprintf(stderr, "DEBUG: printer-uri=\"%s\"\n", uri);
+
+ if (user && *user)
+ {
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+ fprintf(stderr, "DEBUG: requesting-user-name=\"%s\"\n", user);
+ }
+
+ if (title && *title)
+ {
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
+ title);
+ fprintf(stderr, "DEBUG: job-name=\"%s\"\n", title);
+ }
+
+ if (format)
+ {
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
+ "document-format", NULL, format);
+ fprintf(stderr, "DEBUG: document-format=\"%s\"\n", format);
+ }
+
+#ifdef HAVE_LIBZ
+ if (compression)
+ {
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "compression", NULL, compression);
+ fprintf(stderr, "DEBUG: compression=\"%s\"\n", compression);
+ }
+#endif /* HAVE_LIBZ */
+
+ /*
+ * Handle options on the command-line...
+ */
+
+ if (num_options > 0)
+ {
+ if (pc)
+ {
+ /*
+ * Send standard IPP attributes...
+ */
+
+ if ((keyword = cupsGetOption("PageSize", num_options, options)) == NULL)
+ keyword = cupsGetOption("media", num_options, options);
+
+ if ((size = _ppdCacheGetSize(pc, keyword)) != NULL)
+ {
+ /*
+ * Add a media-col value...
+ */
+
+ media_size = ippNew();
+ ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "x-dimension", size->width);
+ ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "y-dimension", size->length);
+
+ media_col = ippNew();
+ ippAddCollection(media_col, IPP_TAG_ZERO, "media-size", media_size);
+
+ media_source = _ppdCacheGetSource(pc, cupsGetOption("InputSlot",
+ num_options,
+ options));
+ media_type = _ppdCacheGetType(pc, cupsGetOption("MediaType",
+ num_options,
+ options));
+
+ for (i = 0; i < media_col_sup->num_values; i ++)
+ {
+ if (!strcmp(media_col_sup->values[i].string.text,
+ "media-left-margin"))
+ ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "media-left-margin", size->left);
+ else if (!strcmp(media_col_sup->values[i].string.text,
+ "media-bottom-margin"))
+ ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "media-bottom-margin", size->left);
+ else if (!strcmp(media_col_sup->values[i].string.text,
+ "media-right-margin"))
+ ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "media-right-margin", size->left);
+ else if (!strcmp(media_col_sup->values[i].string.text,
+ "media-top-margin"))
+ ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "media-top-margin", size->left);
+ else if (!strcmp(media_col_sup->values[i].string.text,
+ "media-source") && media_source)
+ ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD,
+ "media-source", NULL, media_source);
+ else if (!strcmp(media_col_sup->values[i].string.text,
+ "media-type") && media_type)
+ ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD,
+ "media-type", NULL, media_type);
+ }
+
+ ippAddCollection(request, IPP_TAG_JOB, "media-col", media_col);
+ }
+
+ if ((keyword = cupsGetOption("output-bin", num_options,
+ options)) == NULL)
+ keyword = _ppdCacheGetBin(pc, cupsGetOption("OutputBin", num_options,
+ options));
+
+ if (keyword)
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-bin",
+ NULL, keyword);
+
+ if ((keyword = cupsGetOption("output-mode", num_options,
+ options)) != NULL)
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-mode",
+ NULL, keyword);
+ else if ((keyword = cupsGetOption("ColorModel", num_options,
+ options)) != NULL)
+ {
+ if (!_cups_strcasecmp(keyword, "Gray"))
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-mode",
+ NULL, "monochrome");
+ else
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-mode",
+ NULL, "color");
+ }
+
+ if ((keyword = cupsGetOption("print-quality", num_options,
+ options)) != NULL)
+ ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality",
+ atoi(keyword));
+ else if ((keyword = cupsGetOption("cupsPrintQuality", num_options,
+ options)) != NULL)
+ {
+ if (!_cups_strcasecmp(keyword, "draft"))
+ ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality",
+ IPP_QUALITY_DRAFT);
+ else if (!_cups_strcasecmp(keyword, "normal"))
+ ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality",
+ IPP_QUALITY_NORMAL);
+ else if (!_cups_strcasecmp(keyword, "high"))
+ ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality",
+ IPP_QUALITY_HIGH);
+ }
+
+ if ((keyword = cupsGetOption("sides", num_options, options)) != NULL)
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides",
+ NULL, keyword);
+ else if (pc->sides_option &&
+ (keyword = cupsGetOption(pc->sides_option, num_options,
+ options)) != NULL)
+ {
+ if (!_cups_strcasecmp(keyword, pc->sides_1sided))
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides",
+ NULL, "one-sided");
+ else if (!_cups_strcasecmp(keyword, pc->sides_2sided_long))
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides",
+ NULL, "two-sided-long-edge");
+ if (!_cups_strcasecmp(keyword, pc->sides_2sided_short))
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides",
+ NULL, "two-sided-short-edge");
+ }
+
+ if (doc_handling_sup &&
+ (keyword = cupsGetOption("collate", num_options, options)) != NULL)
+ {
+ if (!_cups_strcasecmp(keyword, "true"))
+ collate_str = "separate-documents-collated-copies";
+ else
+ collate_str = "separate-documents-uncollated-copies";
+
+ for (i = 0; i < doc_handling_sup->num_values; i ++)
+ if (!strcmp(doc_handling_sup->values[i].string.text, collate_str))
+ {
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "multiple-document-handling", NULL, collate_str);
+ break;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * When talking to another CUPS server, send all options...
+ */
+
+ cupsEncodeOptions(request, num_options, options);
+ }
+
+ if (copies > 1)
+ ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies", copies);
+ }
+
+ return (request);
+}
+
+
+/*
+ * 'password_cb()' - Disable the password prompt for cupsDoFileRequest().
+ */
+
+static const char * /* O - Password */
+password_cb(const char *prompt) /* I - Prompt (not used) */
+{
+ (void)prompt;
+
+ /*
+ * Remember that we need to authenticate...
+ */
+
+ auth_info_required = "username,password";
+
+ if (password && *password && password_tries < 3)
+ {
+ password_tries ++;
+
+ return (password);
+ }
+ else
+ {
+ /*
+ * Give up after 3 tries or if we don't have a password to begin with...
+ */
+
+ return (NULL);
+ }
+}
+
+
+/*
+ * 'report_attr()' - Report an IPP attribute value.
+ */
+
+static void
+report_attr(ipp_attribute_t *attr) /* I - Attribute */
+{
+ int i; /* Looping var */
+ char value[1024], /* Value string */
+ *valptr, /* Pointer into value string */
+ *attrptr; /* Pointer into attribute value */
+ const char *cached; /* Cached attribute */
+
+
+ /*
+ * Convert the attribute values into quoted strings...
+ */
+
+ for (i = 0, valptr = value;
+ i < attr->num_values && valptr < (value + sizeof(value) - 10);
+ i ++)
+ {
+ if (i > 0)
+ *valptr++ = ',';
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ snprintf(valptr, sizeof(value) - (valptr - value), "%d",
+ attr->values[i].integer);
+ valptr += strlen(valptr);
+ break;
+
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ *valptr++ = '\"';
+ for (attrptr = attr->values[i].string.text;
+ *attrptr && valptr < (value + sizeof(value) - 10);
+ attrptr ++)
+ {
+ if (*attrptr == '\\' || *attrptr == '\"')
+ *valptr++ = '\\';
+
+ *valptr++ = *attrptr;
+ }
+ *valptr++ = '\"';
+ break;
+
+ default :
+ /*
+ * Unsupported value type...
+ */
+
+ return;
+ }
+ }
+
+ *valptr = '\0';
+
+ _cupsMutexLock(&report_mutex);
+
+ if ((cached = cupsGetOption(attr->name, num_attr_cache,
+ attr_cache)) == NULL || strcmp(cached, value))
+ {
+ /*
+ * Tell the scheduler about the new values...
+ */
+
+ num_attr_cache = cupsAddOption(attr->name, value, num_attr_cache,
+ &attr_cache);
+ fprintf(stderr, "ATTR: %s=%s\n", attr->name, value);
+ }
+
+ _cupsMutexUnlock(&report_mutex);
+}
+
+
+/*
+ * 'report_printer_state()' - Report the printer state.
+ */
+
+static void
+report_printer_state(ipp_t *ipp) /* I - IPP response */
+{
+ ipp_attribute_t *pa, /* printer-alert */
+ *pam, /* printer-alert-message */
+ *psm, /* printer-state-message */
+ *reasons, /* printer-state-reasons */
+ *marker; /* marker-* attributes */
+ char value[1024], /* State/message string */
+ *valptr; /* Pointer into string */
+ static int ipp_supplies = -1;
+ /* Report supply levels? */
+
+
+ /*
+ * Report alerts and messages...
+ */
+
+ if ((pa = ippFindAttribute(ipp, "printer-alert", IPP_TAG_TEXT)) != NULL)
+ report_attr(pa);
+
+ if ((pam = ippFindAttribute(ipp, "printer-alert-message",
+ IPP_TAG_TEXT)) != NULL)
+ report_attr(pam);
+
+ if ((psm = ippFindAttribute(ipp, "printer-state-message",
+ IPP_TAG_TEXT)) != NULL)
+ {
+ char *ptr; /* Pointer into message */
+
+
+ strlcpy(value, "INFO: ", sizeof(value));
+ for (ptr = psm->values[0].string.text, valptr = value + 6;
+ *ptr && valptr < (value + sizeof(value) - 6);
+ ptr ++)
+ {
+ if (*ptr < ' ' && *ptr > 0 && *ptr != '\t')
+ {
+ /*
+ * Substitute "<XX>" for the control character; sprintf is safe because
+ * we always leave 6 chars free at the end...
+ */
+
+ sprintf(valptr, "<%02X>", *ptr);
+ valptr += 4;
+ }
+ else
+ *valptr++ = *ptr;
+ }
+
+ *valptr++ = '\n';
+ *valptr = '\0';
+
+ fputs(value, stderr);
+ }
+
+ /*
+ * Now report printer-state-reasons, filtering out some of the reasons we never
+ * want to set...
+ */
+
+ if ((reasons = ippFindAttribute(ipp, "printer-state-reasons",
+ IPP_TAG_KEYWORD)) == NULL)
+ return;
+
+ update_reasons(reasons, NULL);
+
+ /*
+ * Relay the current marker-* attribute values...
+ */
+
+ if (ipp_supplies < 0)
+ {
+ ppd_file_t *ppd; /* PPD file */
+ ppd_attr_t *ppdattr; /* Attribute in PPD file */
+
+ if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL &&
+ (ppdattr = ppdFindAttr(ppd, "cupsIPPSupplies", NULL)) != NULL &&
+ ppdattr->value && _cups_strcasecmp(ppdattr->value, "true"))
+ ipp_supplies = 0;
+ else
+ ipp_supplies = 1;
+
+ ppdClose(ppd);
+ }
+
+ if (ipp_supplies > 0)
+ {
+ if ((marker = ippFindAttribute(ipp, "marker-colors", IPP_TAG_NAME)) != NULL)
+ report_attr(marker);
+ if ((marker = ippFindAttribute(ipp, "marker-high-levels",
+ IPP_TAG_INTEGER)) != NULL)
+ report_attr(marker);
+ if ((marker = ippFindAttribute(ipp, "marker-levels",
+ IPP_TAG_INTEGER)) != NULL)
+ report_attr(marker);
+ if ((marker = ippFindAttribute(ipp, "marker-low-levels",
+ IPP_TAG_INTEGER)) != NULL)
+ report_attr(marker);
+ if ((marker = ippFindAttribute(ipp, "marker-message",
+ IPP_TAG_TEXT)) != NULL)
+ report_attr(marker);
+ if ((marker = ippFindAttribute(ipp, "marker-names", IPP_TAG_NAME)) != NULL)
+ report_attr(marker);
+ if ((marker = ippFindAttribute(ipp, "marker-types",
+ IPP_TAG_KEYWORD)) != NULL)
+ report_attr(marker);
+ }
+}
+
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_XPC)
+/*
+ * 'run_as_user()' - Run the IPP backend as the printing user.
+ *
+ * This function uses an XPC-based user agent to run the backend as the printing
+ * user. We need to do this in order to have access to the user's Kerberos
+ * credentials.
+ */
+
+static int /* O - Exit status */
+run_as_user(int argc, /* I - Number of command-line args */
+ char *argv[], /* I - Command-line arguments */
+ uid_t uid, /* I - User ID */
+ const char *device_uri, /* I - Device URI */
+ int fd) /* I - File to print */
+{
+ const char *auth_negotiate;/* AUTH_NEGOTIATE env var */
+ xpc_connection_t conn; /* Connection to XPC service */
+ xpc_object_t request; /* Request message dictionary */
+ __block xpc_object_t response; /* Response message dictionary */
+ dispatch_semaphore_t sem; /* Semaphore for waiting for response */
+ int status = CUPS_BACKEND_FAILED;
+ /* Status of request */
+
+
+ fprintf(stderr, "DEBUG: Running IPP backend as UID %d.\n", (int)uid);
+
+ /*
+ * Connect to the user agent for the specified UID...
+ */
+
+ conn = xpc_connection_create_mach_service(kPMPrintUIToolAgent,
+ dispatch_get_global_queue(0, 0), 0);
+ if (!conn)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to start backend process."));
+ fputs("DEBUG: Unable to create connection to agent.\n", stderr);
+ goto cleanup;
+ }
+
+ xpc_connection_set_event_handler(conn,
+ ^(xpc_object_t event)
+ {
+ xpc_type_t messageType = xpc_get_type(event);
+
+ if (messageType == XPC_TYPE_ERROR)
+ {
+ if (event == XPC_ERROR_CONNECTION_INTERRUPTED)
+ fprintf(stderr, "DEBUG: Interrupted connection to service %s.\n",
+ xpc_connection_get_name(conn));
+ else if (event == XPC_ERROR_CONNECTION_INVALID)
+ fprintf(stderr, "DEBUG: Connection invalid for service %s.\n",
+ xpc_connection_get_name(conn));
+ else
+ fprintf(stderr, "DEBUG: Unxpected error for service %s: %s\n",
+ xpc_connection_get_name(conn),
+ xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
+ }
+ });
+ xpc_connection_set_target_uid(conn, uid);
+ xpc_connection_resume(conn);
+
+ /*
+ * Try starting the backend...
+ */
+
+ request = xpc_dictionary_create(NULL, NULL, 0);
+ xpc_dictionary_set_int64(request, "command", kPMStartJob);
+ xpc_dictionary_set_string(request, "device-uri", device_uri);
+ xpc_dictionary_set_string(request, "job-id", argv[1]);
+ xpc_dictionary_set_string(request, "user", argv[2]);
+ xpc_dictionary_set_string(request, "title", argv[3]);
+ xpc_dictionary_set_string(request, "copies", argv[4]);
+ xpc_dictionary_set_string(request, "options", argv[5]);
+ xpc_dictionary_set_string(request, "auth-info-required",
+ getenv("AUTH_INFO_REQUIRED"));
+ if ((auth_negotiate = getenv("AUTH_NEGOTIATE")) != NULL)
+ xpc_dictionary_set_string(request, "auth-negotiate", auth_negotiate);
+ xpc_dictionary_set_fd(request, "stdin", fd);
+ xpc_dictionary_set_fd(request, "stderr", 2);
+ xpc_dictionary_set_fd(request, "side-channel", CUPS_SC_FD);
+
+ sem = dispatch_semaphore_create(0);
+ response = NULL;
+
+ xpc_connection_send_message_with_reply(conn, request,
+ dispatch_get_global_queue(0,0),
+ ^(xpc_object_t reply)
+ {
+ /* Save the response and wake up */
+ if (xpc_get_type(reply)
+ == XPC_TYPE_DICTIONARY)
+ response = xpc_retain(reply);
+
+ dispatch_semaphore_signal(sem);
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ xpc_release(request);
+ dispatch_release(sem);
+
+ if (response)
+ {
+ child_pid = xpc_dictionary_get_int64(response, "child-pid");
+
+ xpc_release(response);
+
+ if (child_pid)
+ fprintf(stderr, "DEBUG: Child PID=%d.\n", child_pid);
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to start backend process."));
+ fputs("DEBUG: No child PID.\n", stderr);
+ goto cleanup;
+ }
+ }
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to start backend process."));
+ fputs("DEBUG: No reply from agent.\n", stderr);
+ goto cleanup;
+ }
+
+ /*
+ * Then wait for the backend to finish...
+ */
+
+ request = xpc_dictionary_create(NULL, NULL, 0);
+ xpc_dictionary_set_int64(request, "command", kPMWaitForJob);
+ xpc_dictionary_set_fd(request, "stderr", 2);
+
+ sem = dispatch_semaphore_create(0);
+ response = NULL;
+
+ xpc_connection_send_message_with_reply(conn, request,
+ dispatch_get_global_queue(0,0),
+ ^(xpc_object_t reply)
+ {
+ /* Save the response and wake up */
+ if (xpc_get_type(reply)
+ == XPC_TYPE_DICTIONARY)
+ response = xpc_retain(reply);
+
+ dispatch_semaphore_signal(sem);
+ });
+
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ xpc_release(request);
+ dispatch_release(sem);
+
+ if (response)
+ {
+ status = xpc_dictionary_get_int64(response, "status");
+
+ if (status == SIGTERM || status == SIGKILL || status == SIGPIPE)
+ {
+ fprintf(stderr, "DEBUG: Child terminated on signal %d.\n", status);
+ status = CUPS_BACKEND_FAILED;
+ }
+ else if (WIFSIGNALED(status))
+ {
+ fprintf(stderr, "DEBUG: Child crashed on signal %d.\n", status);
+ status = CUPS_BACKEND_STOP;
+ }
+ else if (WIFEXITED(status))
+ {
+ status = WEXITSTATUS(status);
+ fprintf(stderr, "DEBUG: Child exited with status %d.\n", status);
+ }
+
+ xpc_release(response);
+ }
+ else
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to get backend exit status."));
+
+ cleanup:
+
+ if (conn)
+ {
+ xpc_connection_suspend(conn);
+ xpc_connection_cancel(conn);
+ xpc_release(conn);
+ }
+
+ return (status);
+}
+#endif /* HAVE_GSSAPI && HAVE_XPC */
+
+
+/*
+ * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
+ */
+
+static void
+sigterm_handler(int sig) /* I - Signal */
+{
+ (void)sig; /* remove compiler warnings... */
+
+#if defined(HAVE_GSSAPI) && defined(HAVE_XPC)
+ if (child_pid)
+ {
+ kill(child_pid, sig);
+ child_pid = 0;
+ }
+#endif /* HAVE_GSSAPI && HAVE_XPC */
+
+ if (!job_canceled)
+ {
+ /*
+ * Flag that the job should be canceled...
+ */
+
+ job_canceled = 1;
+ return;
+ }
+
+ /*
+ * The scheduler already tried to cancel us once, now just terminate
+ * after removing our temp file!
+ */
+
+ if (tmpfilename[0])
+ unlink(tmpfilename);
+
+ exit(1);
+}
+
+
+/*
+ * 'timeout_cb()' - Handle HTTP timeouts.
+ */
+
+static int /* O - 1 to continue, 0 to cancel */
+timeout_cb(http_t *http, /* I - Connection to server (unused) */
+ void *user_data) /* I - User data (unused) */
+{
+ (void)http;
+ (void)user_data;
+
+ return (!job_canceled);
+}
+
+
+/*
+ * 'update_reasons()' - Update the printer-state-reasons values.
+ */
+
+static void
+update_reasons(ipp_attribute_t *attr, /* I - printer-state-reasons or NULL */
+ const char *s) /* I - STATE: string or NULL */
+{
+ char op; /* Add (+), remove (-), replace (\0) */
+ cups_array_t *new_reasons; /* New reasons array */
+ char *reason, /* Current reason */
+ add[2048], /* Reasons added string */
+ *addptr, /* Pointer into add string */
+ rem[2048], /* Reasons removed string */
+ *remptr; /* Pointer into remove string */
+ const char *addprefix, /* Current add string prefix */
+ *remprefix; /* Current remove string prefix */
+
+
+ fprintf(stderr, "DEBUG: update_reasons(attr=%d(%s%s), s=\"%s\")\n",
+ attr ? attr->num_values : 0, attr ? attr->values[0].string.text : "",
+ attr && attr->num_values > 1 ? ",..." : "", s ? s : "(null)");
+
+ /*
+ * Create an array of new reason keyword strings...
+ */
+
+ if (attr)
+ {
+ int i; /* Looping var */
+
+ new_reasons = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+ op = '\0';
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ reason = attr->values[i].string.text;
+
+ if (strcmp(reason, "none") &&
+ strcmp(reason, "none-report") &&
+ strcmp(reason, "paused") &&
+ strcmp(reason, "com.apple.print.recoverable-warning") &&
+ strncmp(reason, "cups-", 5))
+ cupsArrayAdd(new_reasons, reason);
+ }
+ }
+ else if (s)
+ {
+ if (*s == '+' || *s == '-')
+ op = *s++;
+ else
+ op = '\0';
+
+ new_reasons = _cupsArrayNewStrings(s);
+ }
+ else
+ return;
+
+ /*
+ * Compute the changes...
+ */
+
+ add[0] = '\0';
+ addprefix = "STATE: +";
+ addptr = add;
+ rem[0] = '\0';
+ remprefix = "STATE: -";
+ remptr = rem;
+
+ fprintf(stderr, "DEBUG2: op='%c', new_reasons=%d, state_reasons=%d\n",
+ op ? op : ' ', cupsArrayCount(new_reasons),
+ cupsArrayCount(state_reasons));
+
+ _cupsMutexLock(&report_mutex);
+
+ if (op == '+')
+ {
+ /*
+ * Add reasons...
+ */
+
+ for (reason = (char *)cupsArrayFirst(new_reasons);
+ reason;
+ reason = (char *)cupsArrayNext(new_reasons))
+ {
+ if (!cupsArrayFind(state_reasons, reason))
+ {
+ if (!strncmp(reason, "cups-remote-", 12))
+ {
+ /*
+ * If we are setting cups-remote-xxx, remove all other cups-remote-xxx
+ * keywords...
+ */
+
+ char *temp; /* Current reason in state_reasons */
+
+ cupsArraySave(state_reasons);
+
+ for (temp = (char *)cupsArrayFirst(state_reasons);
+ temp;
+ temp = (char *)cupsArrayNext(state_reasons))
+ if (!strncmp(temp, "cups-remote-", 12))
+ {
+ snprintf(remptr, sizeof(rem) - (remptr - rem), "%s%s", remprefix,
+ temp);
+ remptr += strlen(remptr);
+ remprefix = ",";
+
+ cupsArrayRemove(state_reasons, temp);
+ break;
+ }
+
+ cupsArrayRestore(state_reasons);
+ }
+
+ cupsArrayAdd(state_reasons, reason);
+
+ snprintf(addptr, sizeof(add) - (addptr - add), "%s%s", addprefix,
+ reason);
+ addptr += strlen(addptr);
+ addprefix = ",";
+ }
+ }
+ }
+ else if (op == '-')
+ {
+ /*
+ * Remove reasons...
+ */
+
+ for (reason = (char *)cupsArrayFirst(new_reasons);
+ reason;
+ reason = (char *)cupsArrayNext(new_reasons))
+ {
+ if (cupsArrayFind(state_reasons, reason))
+ {
+ snprintf(remptr, sizeof(rem) - (remptr - rem), "%s%s", remprefix,
+ reason);
+ remptr += strlen(remptr);
+ remprefix = ",";
+
+ cupsArrayRemove(state_reasons, reason);
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Replace reasons...
+ */
+
+ for (reason = (char *)cupsArrayFirst(state_reasons);
+ reason;
+ reason = (char *)cupsArrayNext(state_reasons))
+ {
+ if (strncmp(reason, "cups-", 5) && !cupsArrayFind(new_reasons, reason))
+ {
+ snprintf(remptr, sizeof(rem) - (remptr - rem), "%s%s", remprefix,
+ reason);
+ remptr += strlen(remptr);
+ remprefix = ",";
+
+ cupsArrayRemove(state_reasons, reason);
+ }
+ }
+
+ for (reason = (char *)cupsArrayFirst(new_reasons);
+ reason;
+ reason = (char *)cupsArrayNext(new_reasons))
+ {
+ if (!cupsArrayFind(state_reasons, reason))
+ {
+ cupsArrayAdd(state_reasons, reason);
+
+ snprintf(addptr, sizeof(add) - (addptr - add), "%s%s", addprefix,
+ reason);
+ addptr += strlen(addptr);
+ addprefix = ",";
+ }
+ }
+ }
+
+ _cupsMutexUnlock(&report_mutex);
+
+ /*
+ * Report changes and return...
+ */
+
+ if (add[0] && rem[0])
+ fprintf(stderr, "%s\n%s\n", add, rem);
+ else if (add[0])
+ fprintf(stderr, "%s\n", add);
+ else if (rem[0])
+ fprintf(stderr, "%s\n", rem);
+}
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/lpd.c b/backend/lpd.c
new file mode 100644
index 000000000..006bb5831
--- /dev/null
+++ b/backend/lpd.c
@@ -0,0 +1,1342 @@
+/*
+ * "$Id$"
+ *
+ * Line Printer Daemon backend for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "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 <cups/http-private.h>
+#include "backend-private.h"
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+
+#ifdef WIN32
+# include <winsock.h>
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#endif /* WIN32 */
+#ifdef __APPLE__
+# include <CoreFoundation/CFNumber.h>
+# include <CoreFoundation/CFPreferences.h>
+#endif /* __APPLE__ */
+
+
+/*
+ * Globals...
+ */
+
+static char tmpfilename[1024] = ""; /* Temporary spool file name */
+static int abort_job = 0; /* Non-zero if we get SIGTERM */
+
+
+/*
+ * Print mode...
+ */
+
+#define MODE_STANDARD 0 /* Queue a copy */
+#define MODE_STREAM 1 /* Stream a copy */
+
+
+/*
+ * 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, http_addrlist_t *addrlist,
+ const char *printer, int print_fd, int snmp_fd,
+ int mode, const char *user, const char *title,
+ int copies, int banner, int format, int order,
+ int reserve, int manual_copies, int timeout,
+ int contimeout);
+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 */
+{
+ const char *device_uri; /* Device URI */
+ char scheme[255], /* Scheme in URI */
+ hostname[1024], /* Hostname */
+ username[255], /* Username info */
+ resource[1024], /* Resource info (printer name) */
+ *options, /* Pointer to options */
+ *name, /* Name of option */
+ *value, /* Value of option */
+ sep, /* Separator character */
+ *filename, /* File to print */
+ title[256]; /* Title string */
+ int port; /* Port number */
+ char portname[256]; /* Port name (string) */
+ http_addrlist_t *addrlist; /* List of addresses for printer */
+ int snmp_fd; /* SNMP socket */
+ int fd; /* Print file */
+ int status; /* Status of LPD job */
+ int mode; /* Print mode */
+ 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 */
+ contimeout, /* Connection timeout */
+ copies; /* Number of copies */
+ ssize_t bytes = 0; /* Initial bytes read */
+ char buffer[16384]; /* Initial print 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);
+
+ /*
+ * 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)
+ {
+ printf("network lpd \"Unknown\" \"%s\"\n",
+ _cupsLangString(cupsLangDefault(), _("LPD/LPR Host or Printer")));
+ return (CUPS_BACKEND_OK);
+ }
+ else if (argc < 6 || argc > 7)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options [file]"),
+ argv[0]);
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ /*
+ * Extract the hostname and printer name from the URI...
+ */
+
+ while ((device_uri = cupsBackendDeviceURI(argv)) == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer."));
+ sleep(10);
+
+ if (getenv("CLASS") != NULL)
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme),
+ username, sizeof(username), hostname, sizeof(hostname), &port,
+ resource, sizeof(resource));
+
+ if (!port)
+ port = 515; /* Default to port 515 */
+
+ 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...
+ */
+
+ mode = MODE_STANDARD;
+ banner = 0;
+ format = 'l';
+ order = ORDER_CONTROL_DATA;
+ reserve = RESERVE_ANY;
+ manual_copies = 1;
+ timeout = 300;
+ contimeout = 7 * 24 * 60 * 60;
+
+#ifdef __APPLE__
+ /*
+ * We want to pass UTF-8 characters by default, not re-map them (3071945)
+ */
+
+ sanitize_title = 0;
+#else
+ /*
+ * Otherwise we want to re-map UTF-8 to "safe" characters by default...
+ */
+
+ sanitize_title = 1;
+#endif /* __APPLE__ */
+
+ 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...
+ */
+
+ name = options;
+
+ while (*options && *options != '=' && *options != '+' && *options != '&')
+ options ++;
+
+ if ((sep = *options) != '\0')
+ *options++ = '\0';
+
+ if (sep == '=')
+ {
+ /*
+ * Get the value...
+ */
+
+ value = options;
+
+ while (*options && *options != '+' && *options != '&')
+ options ++;
+
+ if (*options)
+ *options++ = '\0';
+ }
+ else
+ value = (char *)"";
+
+ /*
+ * Process the option...
+ */
+
+ if (!_cups_strcasecmp(name, "banner"))
+ {
+ /*
+ * Set the banner...
+ */
+
+ banner = !value[0] || !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "true");
+ }
+ else if (!_cups_strcasecmp(name, "format") && value[0])
+ {
+ /*
+ * Set output format...
+ */
+
+ if (strchr("cdfglnoprtv", value[0]))
+ format = value[0];
+ else
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unknown format character: \"%c\"."),
+ value[0]);
+ }
+ else if (!_cups_strcasecmp(name, "mode") && value[0])
+ {
+ /*
+ * Set control/data order...
+ */
+
+ if (!_cups_strcasecmp(value, "standard"))
+ mode = MODE_STANDARD;
+ else if (!_cups_strcasecmp(value, "stream"))
+ mode = MODE_STREAM;
+ else
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unknown print mode: \"%s\"."), value);
+ }
+ else if (!_cups_strcasecmp(name, "order") && value[0])
+ {
+ /*
+ * Set control/data order...
+ */
+
+ if (!_cups_strcasecmp(value, "control,data"))
+ order = ORDER_CONTROL_DATA;
+ else if (!_cups_strcasecmp(value, "data,control"))
+ order = ORDER_DATA_CONTROL;
+ else
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unknown file order: \"%s\"."), value);
+ }
+ else if (!_cups_strcasecmp(name, "reserve"))
+ {
+ /*
+ * Set port reservation mode...
+ */
+
+ if (!value[0] || !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "true") ||
+ !_cups_strcasecmp(value, "rfc1179"))
+ reserve = RESERVE_RFC1179;
+ else if (!_cups_strcasecmp(value, "any"))
+ reserve = RESERVE_ANY;
+ else
+ reserve = RESERVE_NONE;
+ }
+ else if (!_cups_strcasecmp(name, "manual_copies"))
+ {
+ /*
+ * Set manual copies...
+ */
+
+ manual_copies = !value[0] || !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "true");
+ }
+ else if (!_cups_strcasecmp(name, "sanitize_title"))
+ {
+ /*
+ * Set sanitize title...
+ */
+
+ sanitize_title = !value[0] || !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "true");
+ }
+ else if (!_cups_strcasecmp(name, "timeout"))
+ {
+ /*
+ * Set the timeout...
+ */
+
+ if (atoi(value) > 0)
+ timeout = atoi(value);
+ }
+ else if (!_cups_strcasecmp(name, "contimeout"))
+ {
+ /*
+ * Set the connection timeout...
+ */
+
+ if (atoi(value) > 0)
+ contimeout = atoi(value);
+ }
+ }
+ }
+
+ if (mode == MODE_STREAM)
+ order = ORDER_CONTROL_DATA;
+
+ /*
+ * Find the printer...
+ */
+
+ snprintf(portname, sizeof(portname), "%d", port);
+
+ fputs("STATE: +connecting-to-device\n", stderr);
+ fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname);
+
+ while ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Unable to locate printer \"%s\"."), hostname);
+ sleep(10);
+
+ if (getenv("CLASS") != NULL)
+ {
+ fputs("STATE: -connecting-to-device\n", stderr);
+ exit(CUPS_BACKEND_FAILED);
+ }
+ }
+
+ snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family);
+
+ /*
+ * Wait for data from the filter...
+ */
+
+ if (argc == 6)
+ {
+ if (!backendWaitLoop(snmp_fd, &(addrlist->addr), 0, backendNetworkSideCB))
+ return (CUPS_BACKEND_OK);
+ else if (mode == MODE_STANDARD &&
+ (bytes = read(0, buffer, sizeof(buffer))) <= 0)
+ return (CUPS_BACKEND_OK);
+ }
+
+ /*
+ * 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 && mode == MODE_STANDARD)
+ {
+ /*
+ * Copy stdin to a temporary file...
+ */
+
+ if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0)
+ {
+ perror("DEBUG: Unable to create temporary file");
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ _cupsLangPrintFilter(stderr, "INFO", _("Copying print data."));
+
+ if (bytes > 0)
+ write(fd, buffer, bytes);
+
+ backendRunLoop(-1, fd, snmp_fd, &(addrlist->addr), 0, 0,
+ backendNetworkSideCB);
+ }
+ else if (argc == 6)
+ {
+ /*
+ * Stream from stdin...
+ */
+
+ filename = NULL;
+ fd = 0;
+ }
+ else
+ {
+ filename = argv[6];
+ fd = open(filename, O_RDONLY);
+
+ if (fd == -1)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+
+ /*
+ * 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...
+ */
+
+ char *ptr;
+
+ 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, addrlist, resource + 1, fd, snmp_fd, mode,
+ username, title, copies, banner, format, order, reserve,
+ manual_copies, timeout, contimeout);
+
+ if (!status)
+ fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4]));
+ }
+ else
+ status = lpd_queue(hostname, addrlist, resource + 1, fd, snmp_fd, mode,
+ username, title, 1, banner, format, order, reserve, 1,
+ timeout, contimeout);
+
+ /*
+ * Remove the temporary file if necessary...
+ */
+
+ if (tmpfilename[0])
+ unlink(tmpfilename);
+
+ if (fd)
+ close(fd);
+
+ if (snmp_fd >= 0)
+ _cupsSNMPClose(snmp_fd);
+
+ /*
+ * 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 canceled...
+ */
+
+ 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("DEBUG: Unable to send LPD command");
+ return (-1);
+ }
+
+ /*
+ * Read back the status from the command and return it...
+ */
+
+ fputs("DEBUG: Reading command status...\n", stderr);
+
+ alarm(timeout);
+
+ if (recv(fd, &status, 1, 0) < 1)
+ {
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("Printer did not respond after %d seconds."),
+ 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 */
+ http_addrlist_t *addrlist, /* I - List of host addresses */
+ const char *printer, /* I - Printer/queue name */
+ int print_fd, /* I - File to print */
+ int snmp_fd, /* I - SNMP socket */
+ int mode, /* I - Print mode */
+ 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... */
+ int contimeout) /* I - Connection timeout */
+{
+ 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 */
+ int delay; /* Delay for retries... */
+ char addrname[256]; /* Address name */
+ http_addrlist_t *addr; /* Socket address */
+ int have_supplies; /* Printer supports supply levels? */
+ int copy; /* Copies written */
+ time_t start_time; /* Time of first connect */
+ size_t nbytes; /* Number of bytes written */
+ off_t tbytes; /* Total bytes written */
+ char buffer[32768]; /* 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 */
+
+ /*
+ * Remember when we started trying to connect to the printer...
+ */
+
+ start_time = time(NULL);
+
+ /*
+ * Loop forever trying to print the file...
+ */
+
+ while (!abort_job)
+ {
+ /*
+ * First try to reserve a port for this connection...
+ */
+
+ fprintf(stderr, "DEBUG: Connecting to %s:%d for printer %s\n", hostname,
+ _httpAddrPort(&(addrlist->addr)), printer);
+ _cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer."));
+
+ for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024, addr = addrlist,
+ delay = 5;;
+ addr = addr->next)
+ {
+ /*
+ * Stop if this job has been canceled...
+ */
+
+ if (abort_job)
+ 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("DEBUG: 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("DEBUG: Unable to reserve port");
+ sleep(1);
+
+ continue;
+ }
+ }
+
+ /*
+ * Connect to the printer or server...
+ */
+
+ if (abort_job)
+ {
+ close(fd);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ if (!connect(fd, &(addr->addr.addr), httpAddrLength(&(addr->addr))))
+ break;
+
+ error = errno;
+ close(fd);
+
+ 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.
+ */
+
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Unable to contact printer, queuing on next "
+ "printer in class."));
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(error));
+
+ if (error == ECONNREFUSED || error == EHOSTDOWN ||
+ error == EHOSTUNREACH)
+ {
+ if (contimeout && (time(NULL) - start_time) > contimeout)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The printer is not responding."));
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ switch (error)
+ {
+ case EHOSTDOWN :
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("The printer may not exist or "
+ "is unavailable at this time."));
+ break;
+
+ case EHOSTUNREACH :
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("The printer is unreachable at "
+ "this time."));
+ break;
+
+ case ECONNREFUSED :
+ default :
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("The printer is busy."));
+ break;
+ }
+
+ sleep(delay);
+
+ if (delay < 30)
+ delay += 5;
+ }
+ else if (error == EADDRINUSE)
+ {
+ /*
+ * Try on another port...
+ */
+
+ sleep(1);
+ }
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The printer is not responding."));
+ sleep(30);
+ }
+ }
+
+ fputs("STATE: -connecting-to-device\n", stderr);
+ _cupsLangPrintFilter(stderr, "INFO", _("Connected to printer."));
+
+ fprintf(stderr, "DEBUG: Connected to %s:%d (local port %d)...\n",
+ httpAddrString(&(addr->addr), addrname, sizeof(addrname)),
+ _httpAddrPort(&(addr->addr)), lport);
+
+ /*
+ * See if the printer supports SNMP...
+ */
+
+ if (snmp_fd >= 0)
+ have_supplies = !backendSNMPSupplies(snmp_fd, &(addrlist->addr), NULL,
+ NULL);
+ else
+ have_supplies = 0;
+
+ /*
+ * Check for side-channel requests...
+ */
+
+ backendCheckSideChannel(snmp_fd, &(addrlist->addr));
+
+ /*
+ * Next, open the print file and figure out its size...
+ */
+
+ if (print_fd)
+ {
+ /*
+ * Use the size from the print file...
+ */
+
+ if (fstat(print_fd, &filestats))
+ {
+ close(fd);
+
+ perror("DEBUG: unable to stat print file");
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ filestats.st_size *= manual_copies;
+ }
+ else
+ {
+ /*
+ * Use a "very large value" for the size so that the printer will
+ * keep printing until we close the connection...
+ */
+
+#ifdef _LARGEFILE_SOURCE
+ filestats.st_size = (size_t)(999999999999.0);
+#else
+ filestats.st_size = 2147483647;
+#endif /* _LARGEFILE_SOURCE */
+ }
+
+ /*
+ * 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) */
+ {
+ close(fd);
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ httpGetHostname(NULL, 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)
+ {
+ /*
+ * Check for side-channel requests...
+ */
+
+ backendCheckSideChannel(snmp_fd, &(addr->addr));
+
+ /*
+ * Send the control file...
+ */
+
+ if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
+ (int)getpid() % 1000, localhost))
+ {
+ close(fd);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ fprintf(stderr, "DEBUG: Sending control file (%u bytes)\n",
+ (unsigned)strlen(control));
+
+ if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
+ {
+ status = errno;
+ perror("DEBUG: Unable to write control file");
+
+ }
+ else
+ {
+ alarm(timeout);
+
+ if (read(fd, &status, 1) < 1)
+ {
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("Printer did not respond after %d seconds."),
+ timeout);
+ status = errno;
+ }
+
+ alarm(0);
+ }
+
+ if (status != 0)
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Remote host did not accept control file (%d)."),
+ status);
+ else
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Control file sent successfully."));
+ }
+ else
+ status = 0;
+
+ if (status == 0)
+ {
+ /*
+ * Check for side-channel requests...
+ */
+
+ backendCheckSideChannel(snmp_fd, &(addr->addr));
+
+ /*
+ * 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))
+ {
+ close(fd);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ fprintf(stderr, "DEBUG: Sending data file (" CUPS_LLFMT " bytes)\n",
+ CUPS_LLCAST filestats.st_size);
+
+ tbytes = 0;
+ for (copy = 0; copy < manual_copies; copy ++)
+ {
+ lseek(print_fd, 0, SEEK_SET);
+
+ while ((nbytes = read(print_fd, buffer, sizeof(buffer))) > 0)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Spooling job, %.0f%% complete."),
+ 100.0 * tbytes / filestats.st_size);
+
+ if (lpd_write(fd, buffer, nbytes) < nbytes)
+ {
+ perror("DEBUG: Unable to send print file to printer");
+ break;
+ }
+ else
+ tbytes += nbytes;
+ }
+ }
+
+ if (mode == MODE_STANDARD)
+ {
+ if (tbytes < filestats.st_size)
+ status = errno;
+ else if (lpd_write(fd, "", 1) < 1)
+ {
+ perror("DEBUG: 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)
+ {
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("Printer did not respond after %d seconds."),
+ timeout);
+ status = 0;
+ }
+
+ alarm(0);
+ }
+ }
+ else
+ status = 0;
+
+ if (status != 0)
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Remote host did not accept data file (%d)."),
+ status);
+ else
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Data file sent successfully."));
+ }
+
+ if (status == 0 && order == ORDER_DATA_CONTROL)
+ {
+ /*
+ * Check for side-channel requests...
+ */
+
+ backendCheckSideChannel(snmp_fd, &(addr->addr));
+
+ /*
+ * Send control file...
+ */
+
+ if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
+ (int)getpid() % 1000, localhost))
+ {
+ close(fd);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ fprintf(stderr, "DEBUG: Sending control file (%lu bytes)\n",
+ (unsigned long)strlen(control));
+
+ if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
+ {
+ status = errno;
+ perror("DEBUG: Unable to write control file");
+ }
+ else
+ {
+ alarm(timeout);
+
+ if (read(fd, &status, 1) < 1)
+ {
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("Printer did not respond after %d seconds."),
+ timeout);
+ status = errno;
+ }
+
+ alarm(0);
+ }
+
+ if (status != 0)
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Remote host did not accept control file (%d)."),
+ status);
+ else
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Control file sent successfully."));
+ }
+
+ /*
+ * Collect the final supply levels as needed...
+ */
+
+ if (have_supplies)
+ backendSNMPSupplies(snmp_fd, &(addr->addr), NULL, NULL);
+
+ /*
+ * Close the socket connection and input file...
+ */
+
+ close(fd);
+
+ if (status == 0)
+ return (CUPS_BACKEND_OK);
+
+ /*
+ * Waiting for a retry...
+ */
+
+ sleep(30);
+ }
+
+ /*
+ * If we get here, then the job has been canceled...
+ */
+
+ 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...
+ */
+
+ _httpAddrSetPort(&addr, *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$".
+ */
diff --git a/backend/network.c b/backend/network.c
new file mode 100644
index 000000000..fb42f791f
--- /dev/null
+++ b/backend/network.c
@@ -0,0 +1,300 @@
+/*
+ * "$Id$"
+ *
+ * Common backend network APIs for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2006-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * backendCheckSideChannel() - Check the side-channel for pending requests.
+ * backendNetworkSideCB() - Handle common network side-channel commands.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "backend-private.h"
+#include <limits.h>
+#ifdef __hpux
+# include <sys/time.h>
+#else
+# include <sys/select.h>
+#endif /* __hpux */
+
+
+/*
+ * 'backendCheckSideChannel()' - Check the side-channel for pending requests.
+ */
+
+
+void
+backendCheckSideChannel(
+ int snmp_fd, /* I - SNMP socket */
+ http_addr_t *addr) /* I - Address of device */
+{
+ fd_set input; /* Select input set */
+ struct timeval timeout; /* Select timeout */
+
+
+ FD_ZERO(&input);
+ FD_SET(CUPS_SC_FD, &input);
+
+ timeout.tv_sec = timeout.tv_usec = 0;
+
+ if (select(CUPS_SC_FD + 1, &input, NULL, NULL, &timeout) > 0)
+ backendNetworkSideCB(-1, -1, snmp_fd, addr, 0);
+}
+
+
+/*
+ * 'backendNetworkSideCB()' - Handle common network side-channel commands.
+ */
+
+int /* O - -1 on error, 0 on success */
+backendNetworkSideCB(
+ int print_fd, /* I - Print file or -1 */
+ int device_fd, /* I - Device file or -1 */
+ int snmp_fd, /* I - SNMP socket */
+ http_addr_t *addr, /* I - Address of device */
+ int use_bc) /* I - Use back-channel data? */
+{
+ cups_sc_command_t command; /* Request command */
+ cups_sc_status_t status; /* Request/response status */
+ char data[2048]; /* Request/response data */
+ int datalen; /* Request/response data size */
+ const char *device_id; /* 1284DEVICEID env var */
+
+
+ datalen = sizeof(data);
+
+ if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
+ return (-1);
+
+ switch (command)
+ {
+ case CUPS_SC_CMD_DRAIN_OUTPUT :
+ /*
+ * Our sockets disable the Nagle algorithm and data is sent immediately.
+ */
+
+ if (device_fd < 0)
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ else if (backendDrainOutput(print_fd, device_fd))
+ status = CUPS_SC_STATUS_IO_ERROR;
+ else
+ status = CUPS_SC_STATUS_OK;
+
+ datalen = 0;
+ break;
+
+ case CUPS_SC_CMD_GET_BIDI :
+ status = CUPS_SC_STATUS_OK;
+ data[0] = use_bc;
+ datalen = 1;
+ break;
+
+ case CUPS_SC_CMD_SNMP_GET :
+ case CUPS_SC_CMD_SNMP_GET_NEXT :
+ fprintf(stderr, "DEBUG: CUPS_SC_CMD_SNMP_%s: %d (%s)\n",
+ command == CUPS_SC_CMD_SNMP_GET ? "GET" : "GET_NEXT", datalen,
+ data);
+
+ if (datalen < 2)
+ {
+ status = CUPS_SC_STATUS_BAD_MESSAGE;
+ datalen = 0;
+ break;
+ }
+
+ if (snmp_fd >= 0)
+ {
+ cups_snmp_t packet; /* Packet from printer */
+
+
+ if (!_cupsSNMPStringToOID(data, packet.object_name, CUPS_SNMP_MAX_OID))
+ {
+ status = CUPS_SC_STATUS_BAD_MESSAGE;
+ datalen = 0;
+ break;
+ }
+
+ status = CUPS_SC_STATUS_IO_ERROR;
+ datalen = 0;
+
+ if (_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(),
+ command == CUPS_SC_CMD_SNMP_GET ?
+ CUPS_ASN1_GET_REQUEST :
+ CUPS_ASN1_GET_NEXT_REQUEST, 1,
+ packet.object_name))
+ {
+ if (_cupsSNMPRead(snmp_fd, &packet, 1.0))
+ {
+ char *dataptr; /* Pointer into data */
+ int i; /* Looping var */
+
+
+ if (!_cupsSNMPOIDToString(packet.object_name, data, sizeof(data)))
+ {
+ fputs("DEBUG: Bad OID returned!\n", stderr);
+ break;
+ }
+
+ datalen = (int)strlen(data) + 1;
+ dataptr = data + datalen;
+
+ switch (packet.object_type)
+ {
+ case CUPS_ASN1_BOOLEAN :
+ snprintf(dataptr, sizeof(data) - (dataptr - data), "%d",
+ packet.object_value.boolean);
+ datalen += (int)strlen(dataptr);
+ break;
+
+ case CUPS_ASN1_INTEGER :
+ snprintf(dataptr, sizeof(data) - (dataptr - data), "%d",
+ packet.object_value.integer);
+ datalen += (int)strlen(dataptr);
+ break;
+
+ case CUPS_ASN1_BIT_STRING :
+ case CUPS_ASN1_OCTET_STRING :
+ if (packet.object_value.string.num_bytes < 0)
+ i = 0;
+ else if (packet.object_value.string.num_bytes <
+ (sizeof(data) - (dataptr - data)))
+ i = packet.object_value.string.num_bytes;
+ else
+ i = (int)(sizeof(data) - (dataptr - data));
+
+ memcpy(dataptr, packet.object_value.string.bytes, i);
+
+ datalen += i;
+ break;
+
+ case CUPS_ASN1_OID :
+ _cupsSNMPOIDToString(packet.object_value.oid, dataptr,
+ sizeof(data) - (dataptr - data));
+ datalen += (int)strlen(dataptr);
+ break;
+
+ case CUPS_ASN1_HEX_STRING :
+ for (i = 0;
+ i < packet.object_value.string.num_bytes &&
+ dataptr < (data + sizeof(data) - 3);
+ i ++, dataptr += 2)
+ sprintf(dataptr, "%02X",
+ packet.object_value.string.bytes[i]);
+ datalen += (int)strlen(dataptr);
+ break;
+
+ case CUPS_ASN1_COUNTER :
+ snprintf(dataptr, sizeof(data) - (dataptr - data), "%d",
+ packet.object_value.counter);
+ datalen += (int)strlen(dataptr);
+ break;
+
+ case CUPS_ASN1_GAUGE :
+ snprintf(dataptr, sizeof(data) - (dataptr - data), "%u",
+ packet.object_value.gauge);
+ datalen += (int)strlen(dataptr);
+ break;
+
+ case CUPS_ASN1_TIMETICKS :
+ snprintf(dataptr, sizeof(data) - (dataptr - data), "%u",
+ packet.object_value.timeticks);
+ datalen += (int)strlen(dataptr);
+ break;
+
+ default :
+ fprintf(stderr, "DEBUG: Unknown OID value type %02X!\n",
+ packet.object_type);
+
+ case CUPS_ASN1_NULL_VALUE :
+ dataptr[0] = '\0';
+ break;
+ }
+
+ fprintf(stderr, "DEBUG: Returning %s %s\n", data, data + datalen);
+
+ status = CUPS_SC_STATUS_OK;
+ }
+ else
+ fputs("DEBUG: SNMP read error...\n", stderr);
+ }
+ else
+ fputs("DEBUG: SNMP write error...\n", stderr);
+ break;
+ }
+
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ datalen = 0;
+ break;
+
+ case CUPS_SC_CMD_GET_DEVICE_ID :
+ if (snmp_fd >= 0)
+ {
+ cups_snmp_t packet; /* Packet from printer */
+ static const int ppmPrinterIEEE1284DeviceId[] =
+ { CUPS_OID_ppmPrinterIEEE1284DeviceId,1,-1 };
+
+
+ status = CUPS_SC_STATUS_IO_ERROR;
+ datalen = 0;
+
+ if (_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(),
+ CUPS_ASN1_GET_REQUEST, 1,
+ ppmPrinterIEEE1284DeviceId))
+ {
+ if (_cupsSNMPRead(snmp_fd, &packet, 1.0) &&
+ packet.object_type == CUPS_ASN1_OCTET_STRING)
+ {
+ strlcpy(data, (char *)packet.object_value.string.bytes,
+ sizeof(data));
+ datalen = (int)strlen(data);
+ status = CUPS_SC_STATUS_OK;
+ }
+ }
+
+ break;
+ }
+
+ if ((device_id = getenv("1284DEVICEID")) != NULL)
+ {
+ strlcpy(data, device_id, sizeof(data));
+ datalen = (int)strlen(data);
+ status = CUPS_SC_STATUS_OK;
+ break;
+ }
+
+ case CUPS_SC_CMD_GET_CONNECTED :
+ status = CUPS_SC_STATUS_OK;
+ data[0] = device_fd != -1;
+ datalen = 1;
+ break;
+
+ default :
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ datalen = 0;
+ break;
+ }
+
+ return (cupsSideChannelWrite(command, status, data, datalen, 1.0));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/parallel.c b/backend/parallel.c
new file mode 100644
index 000000000..d99855a6d
--- /dev/null
+++ b/backend/parallel.c
@@ -0,0 +1,676 @@
+/*
+ * "$Id$"
+ *
+ * Parallel port backend for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "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.
+ * side_cb() - Handle side-channel requests...
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "backend-private.h"
+
+#ifdef __hpux
+# include <sys/time.h>
+#else
+# include <sys/select.h>
+#endif /* __hpux */
+
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+# include <fcntl.h>
+# include <termios.h>
+# include <sys/socket.h>
+#endif /* WIN32 */
+
+#ifdef __sgi
+# include <invent.h>
+# 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...
+ */
+
+static void list_devices(void);
+static int side_cb(int print_fd, int device_fd, int snmp_fd,
+ http_addr_t *addr, int use_bc);
+
+
+/*
+ * '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 print_fd, /* Print file */
+ device_fd, /* Parallel device */
+ use_bc; /* Read back-channel data? */
+ int copies; /* Number of copies to print */
+ ssize_t tbytes; /* Total number of bytes written */
+ struct termios opts; /* Parallel port options */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * 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)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options [file]"),
+ 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)
+ {
+ print_fd = 0;
+ copies = 1;
+ }
+ else
+ {
+ /*
+ * Try to open the print file...
+ */
+
+ if ((print_fd = open(argv[6], O_RDONLY)) < 0)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ copies = atoi(argv[4]);
+ }
+
+ /*
+ * Extract the device name and options from the URI...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv),
+ 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...
+ */
+
+ fputs("STATE: +connecting-to-device\n", stderr);
+
+ do
+ {
+#if defined(__linux) || defined(__FreeBSD__)
+ /*
+ * The Linux and FreeBSD parallel port drivers currently are broken WRT
+ * select() and bidirection I/O...
+ */
+
+ device_fd = open(resource, O_WRONLY | O_EXCL);
+ use_bc = 0;
+
+#else
+ if ((device_fd = open(resource, O_RDWR | O_EXCL)) < 0)
+ {
+ device_fd = open(resource, O_WRONLY | O_EXCL);
+ use_bc = 0;
+ }
+ else
+ use_bc = 1;
+#endif /* __linux || __FreeBSD__ */
+
+ if (device_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.
+ */
+
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Unable to contact printer, queuing on next "
+ "printer in class."));
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ if (errno == EBUSY)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printer busy; will retry in 30 seconds."));
+ sleep(30);
+ }
+ else if (errno == ENXIO || errno == EIO || errno == ENOENT)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printer not connected; will retry in 30 "
+ "seconds."));
+ sleep(30);
+ }
+ else
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open device file"));
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+ }
+ while (device_fd < 0);
+
+ fputs("STATE: -connecting-to-device\n", stderr);
+
+ /*
+ * Set any options provided...
+ */
+
+ tcgetattr(device_fd, &opts);
+
+ opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
+
+ /**** No options supported yet ****/
+
+ tcsetattr(device_fd, TCSANOW, &opts);
+
+ /*
+ * Finally, send the print file...
+ */
+
+ tbytes = 0;
+
+ while (copies > 0 && tbytes >= 0)
+ {
+ copies --;
+
+ if (print_fd != 0)
+ {
+ fputs("PAGE: 1 1\n", stderr);
+ lseek(print_fd, 0, SEEK_SET);
+ }
+
+ tbytes = backendRunLoop(print_fd, device_fd, -1, NULL, use_bc, 1, side_cb);
+
+ if (print_fd != 0 && tbytes >= 0)
+ _cupsLangPrintFilter(stderr, "INFO", _("Print file sent."));
+ }
+
+ /*
+ * Close the socket connection and input file and return...
+ */
+
+ close(device_fd);
+
+ if (print_fd != 0)
+ close(print_fd);
+
+ return (CUPS_BACKEND_OK);
+}
+
+
+/*
+ * 'list_devices()' - List all parallel devices.
+ */
+
+static 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 */
+ info[1024], /* Info string */
+ uri[1024]; /* Device URI */
+
+
+ if (!access("/dev/parallel/", 0))
+ strcpy(basedevice, "/dev/parallel/");
+ else if (!access("/dev/printers/", 0))
+ strcpy(basedevice, "/dev/printers/");
+ 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...
+ */
+
+ snprintf(uri, sizeof(uri), "parallel:%s", device);
+
+ if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
+ make_model, sizeof(make_model),
+ NULL, uri, sizeof(uri)))
+ {
+ snprintf(info, sizeof(info), "%s LPT #%d", make_model, i + 1);
+ cupsBackendReport("direct", uri, make_model, info, device_id, NULL);
+ }
+ else
+ {
+ snprintf(info, sizeof(info), "LPT #%d", i + 1);
+ cupsBackendReport("direct", uri, NULL, info, NULL, NULL);
+ }
+
+ 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__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+ 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
+}
+
+
+/*
+ * 'side_cb()' - Handle side-channel requests...
+ */
+
+static int /* O - 0 on success, -1 on error */
+side_cb(int print_fd, /* I - Print file */
+ int device_fd, /* I - Device file */
+ int snmp_fd, /* I - SNMP socket (unused) */
+ http_addr_t *addr, /* I - Device address (unused) */
+ int use_bc) /* I - Using back-channel? */
+{
+ cups_sc_command_t command; /* Request command */
+ cups_sc_status_t status; /* Request/response status */
+ char data[2048]; /* Request/response data */
+ int datalen; /* Request/response data size */
+
+
+ (void)snmp_fd;
+ (void)addr;
+
+ datalen = sizeof(data);
+
+ if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
+ return (-1);
+
+ switch (command)
+ {
+ case CUPS_SC_CMD_DRAIN_OUTPUT :
+ if (backendDrainOutput(print_fd, device_fd))
+ status = CUPS_SC_STATUS_IO_ERROR;
+ else if (tcdrain(device_fd))
+ status = CUPS_SC_STATUS_IO_ERROR;
+ else
+ status = CUPS_SC_STATUS_OK;
+
+ datalen = 0;
+ break;
+
+ case CUPS_SC_CMD_GET_BIDI :
+ status = CUPS_SC_STATUS_OK;
+ data[0] = use_bc;
+ datalen = 1;
+ break;
+
+ case CUPS_SC_CMD_GET_DEVICE_ID :
+ memset(data, 0, sizeof(data));
+
+ if (backendGetDeviceID(device_fd, data, sizeof(data) - 1,
+ NULL, 0, NULL, NULL, 0))
+ {
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ datalen = 0;
+ }
+ else
+ {
+ status = CUPS_SC_STATUS_OK;
+ datalen = strlen(data);
+ }
+ break;
+
+ default :
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ datalen = 0;
+ break;
+ }
+
+ return (cupsSideChannelWrite(command, status, data, datalen, 1.0));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/pseudo b/backend/pseudo
new file mode 100755
index 000000000..3a82a522a
--- /dev/null
+++ b/backend/pseudo
@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Psuedo-backend for CUPS testing purposes.
+#
+# Copyright 2011 by Apple Inc.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# This file is subject to the Apple OS-Developed Software exception.
+#
+
+if test $# = 0; then
+ echo 'direct pseudo:///deskjet "HP DeskJet" "HP DeskJet (pseudo)" "MFG:HP;MDL:DeskJet;CMD:PCL;" "Nowhere"'
+ echo 'direct pseudo:///laserjet "HP LaserJet" "HP LaserJet (pseudo)" "MFG:HP;MDL:LaserJet;CMD:PCL;" "Nowhere"'
+ exit 0
+fi
+
+cat $6 >/dev/null
+sleep 5
+exit 0
+
+#
+# End of "$Id$".
+#
diff --git a/backend/runloop.c b/backend/runloop.c
new file mode 100644
index 000000000..c2a262a44
--- /dev/null
+++ b/backend/runloop.c
@@ -0,0 +1,526 @@
+/*
+ * "$Id$"
+ *
+ * Common run loop APIs for CUPS backends.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2006-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * backendDrainOutput() - Drain pending print data to the device.
+ * backendRunLoop() - Read and write print and back-channel data.
+ * backendWaitLoop() - Wait for input from stdin while handling
+ * side-channel queries.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "backend-private.h"
+#include <limits.h>
+#ifdef __hpux
+# include <sys/time.h>
+#else
+# include <sys/select.h>
+#endif /* __hpux */
+
+
+/*
+ * 'backendDrainOutput()' - Drain pending print data to the device.
+ */
+
+int /* O - 0 on success, -1 on error */
+backendDrainOutput(int print_fd, /* I - Print file descriptor */
+ int device_fd) /* I - Device file descriptor */
+{
+ int nfds; /* Maximum file descriptor value + 1 */
+ fd_set input; /* Input set for reading */
+ ssize_t print_bytes, /* Print bytes read */
+ bytes; /* Bytes written */
+ char print_buffer[8192], /* Print data buffer */
+ *print_ptr; /* Pointer into print data buffer */
+ struct timeval timeout; /* Timeout for read... */
+
+
+ fprintf(stderr, "DEBUG: backendDrainOutput(print_fd=%d, device_fd=%d)\n",
+ print_fd, device_fd);
+
+ /*
+ * Figure out the maximum file descriptor value to use with select()...
+ */
+
+ nfds = (print_fd > device_fd ? print_fd : device_fd) + 1;
+
+ /*
+ * Now loop until we are out of data from print_fd...
+ */
+
+ for (;;)
+ {
+ /*
+ * Use select() to determine whether we have data to copy around...
+ */
+
+ FD_ZERO(&input);
+ FD_SET(print_fd, &input);
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ if (select(nfds, &input, NULL, NULL, &timeout) < 0)
+ return (-1);
+
+ if (!FD_ISSET(print_fd, &input))
+ return (0);
+
+ if ((print_bytes = read(print_fd, print_buffer,
+ sizeof(print_buffer))) < 0)
+ {
+ /*
+ * Read error - bail if we don't see EAGAIN or EINTR...
+ */
+
+ if (errno != EAGAIN || errno != EINTR)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to read print data"));
+ return (-1);
+ }
+
+ print_bytes = 0;
+ }
+ else if (print_bytes == 0)
+ {
+ /*
+ * End of file, return...
+ */
+
+ return (0);
+ }
+
+ fprintf(stderr, "DEBUG: Read %d bytes of print data...\n",
+ (int)print_bytes);
+
+ for (print_ptr = print_buffer; print_bytes > 0;)
+ {
+ if ((bytes = write(device_fd, print_ptr, print_bytes)) < 0)
+ {
+ /*
+ * Write error - bail if we don't see an error we can retry...
+ */
+
+ if (errno != ENOSPC && errno != ENXIO && errno != EAGAIN &&
+ errno != EINTR && errno != ENOTTY)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to write print data"));
+ return (-1);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n", (int)bytes);
+
+ print_bytes -= bytes;
+ print_ptr += bytes;
+ }
+ }
+ }
+}
+
+
+/*
+ * 'backendRunLoop()' - Read and write print and back-channel data.
+ */
+
+ssize_t /* O - Total bytes on success, -1 on error */
+backendRunLoop(
+ int print_fd, /* I - Print file descriptor */
+ int device_fd, /* I - Device file descriptor */
+ int snmp_fd, /* I - SNMP socket or -1 if none */
+ http_addr_t *addr, /* I - Address of device */
+ int use_bc, /* I - Use back-channel? */
+ int update_state, /* I - Update printer-state-reasons? */
+ _cups_sccb_t side_cb) /* I - Side-channel callback */
+{
+ int nfds; /* Maximum file descriptor value + 1 */
+ fd_set input, /* Input set for reading */
+ output; /* Output set for writing */
+ ssize_t print_bytes, /* Print bytes read */
+ bc_bytes, /* Backchannel bytes read */
+ total_bytes, /* Total bytes written */
+ bytes; /* Bytes written */
+ int paperout; /* "Paper out" status */
+ int offline; /* "Off-line" status */
+ char print_buffer[8192], /* Print data buffer */
+ *print_ptr, /* Pointer into print data buffer */
+ bc_buffer[1024]; /* Back-channel data buffer */
+ struct timeval timeout; /* Timeout for select() */
+ time_t curtime, /* Current time */
+ snmp_update = 0;
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ fprintf(stderr,
+ "DEBUG: backendRunLoop(print_fd=%d, device_fd=%d, snmp_fd=%d, "
+ "addr=%p, use_bc=%d, side_cb=%p)\n",
+ print_fd, device_fd, snmp_fd, addr, use_bc, side_cb);
+
+ /*
+ * If we are printing data from a print driver on stdin, ignore SIGTERM
+ * so that the driver can finish out any page data, e.g. to eject the
+ * current page. We only do this for stdin printing as otherwise there
+ * is no way to cancel a raw print job...
+ */
+
+ if (!print_fd)
+ {
+#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 */
+ }
+ else if (print_fd < 0)
+ {
+ /*
+ * Copy print data from stdin, but don't mess with the signal handlers...
+ */
+
+ print_fd = 0;
+ }
+
+ /*
+ * Figure out the maximum file descriptor value to use with select()...
+ */
+
+ nfds = (print_fd > device_fd ? print_fd : device_fd) + 1;
+
+ /*
+ * Now loop until we are out of data from print_fd...
+ */
+
+ for (print_bytes = 0, print_ptr = print_buffer, offline = -1,
+ paperout = -1, total_bytes = 0;;)
+ {
+ /*
+ * Use select() to determine whether we have data to copy around...
+ */
+
+ FD_ZERO(&input);
+ if (!print_bytes)
+ FD_SET(print_fd, &input);
+ if (use_bc)
+ FD_SET(device_fd, &input);
+ if (!print_bytes && side_cb)
+ FD_SET(CUPS_SC_FD, &input);
+
+ FD_ZERO(&output);
+ if (print_bytes || (!use_bc && !side_cb))
+ FD_SET(device_fd, &output);
+
+ if (use_bc || side_cb)
+ {
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+
+ if (select(nfds, &input, &output, NULL, &timeout) < 0)
+ {
+ /*
+ * Pause printing to clear any pending errors...
+ */
+
+ if (errno == ENXIO && offline != 1 && update_state)
+ {
+ fputs("STATE: +offline-report\n", stderr);
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printer is not currently connected."));
+ offline = 1;
+ }
+ else if (errno == EINTR && total_bytes == 0)
+ {
+ fputs("DEBUG: Received an interrupt before any bytes were "
+ "written, aborting.\n", stderr);
+ return (0);
+ }
+
+ sleep(1);
+ continue;
+ }
+ }
+
+ /*
+ * Check if we have a side-channel request ready...
+ */
+
+ if (side_cb && FD_ISSET(CUPS_SC_FD, &input))
+ {
+ /*
+ * Do the side-channel request, then start back over in the select
+ * loop since it may have read from print_fd...
+ */
+
+ if ((*side_cb)(print_fd, device_fd, snmp_fd, addr, use_bc))
+ side_cb = NULL;
+ continue;
+ }
+
+ /*
+ * Check if we have back-channel data ready...
+ */
+
+ if (FD_ISSET(device_fd, &input))
+ {
+ if ((bc_bytes = read(device_fd, bc_buffer, sizeof(bc_buffer))) > 0)
+ {
+ fprintf(stderr,
+ "DEBUG: Received " CUPS_LLFMT " bytes of back-channel data\n",
+ CUPS_LLCAST bc_bytes);
+ cupsBackChannelWrite(bc_buffer, bc_bytes, 1.0);
+ }
+ else if (bc_bytes < 0 && errno != EAGAIN && errno != EINTR)
+ {
+ fprintf(stderr, "DEBUG: Error reading back-channel data: %s\n",
+ strerror(errno));
+ use_bc = 0;
+ }
+ else if (bc_bytes == 0)
+ use_bc = 0;
+ }
+
+ /*
+ * Check if we have print data ready...
+ */
+
+ if (FD_ISSET(print_fd, &input))
+ {
+ if ((print_bytes = read(print_fd, print_buffer,
+ sizeof(print_buffer))) < 0)
+ {
+ /*
+ * Read error - bail if we don't see EAGAIN or EINTR...
+ */
+
+ if (errno != EAGAIN || errno != EINTR)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to read print data"));
+ return (-1);
+ }
+
+ print_bytes = 0;
+ }
+ else if (print_bytes == 0)
+ {
+ /*
+ * End of file, break out of the loop...
+ */
+
+ break;
+ }
+
+ print_ptr = print_buffer;
+
+ fprintf(stderr, "DEBUG: Read %d bytes of print data...\n",
+ (int)print_bytes);
+ }
+
+ /*
+ * Check if the device is ready to receive data and we have data to
+ * send...
+ */
+
+ if (print_bytes && FD_ISSET(device_fd, &output))
+ {
+ if ((bytes = write(device_fd, print_ptr, print_bytes)) < 0)
+ {
+ /*
+ * Write error - bail if we don't see an error we can retry...
+ */
+
+ if (errno == ENOSPC)
+ {
+ if (paperout != 1 && update_state)
+ {
+ fputs("STATE: +media-empty-warning\n", stderr);
+ fputs("DEBUG: Out of paper\n", stderr);
+ paperout = 1;
+ }
+ }
+ else if (errno == ENXIO)
+ {
+ if (offline != 1 && update_state)
+ {
+ fputs("STATE: +offline-report\n", stderr);
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printer is not currently connected."));
+ offline = 1;
+ }
+ }
+ else if (errno != EAGAIN && errno != EINTR && errno != ENOTTY)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to write print data"));
+ return (-1);
+ }
+ }
+ else
+ {
+ if (paperout && update_state)
+ {
+ fputs("STATE: -media-empty-warning\n", stderr);
+ paperout = 0;
+ }
+
+ if (offline && update_state)
+ {
+ fputs("STATE: -offline-report\n", stderr);
+ _cupsLangPrintFilter(stderr, "INFO", _("Printer is now connected."));
+ offline = 0;
+ }
+
+ fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n", (int)bytes);
+
+ print_bytes -= bytes;
+ print_ptr += bytes;
+ total_bytes += bytes;
+ }
+ }
+
+ /*
+ * Do SNMP updates periodically...
+ */
+
+ if (snmp_fd >= 0 && time(&curtime) >= snmp_update)
+ {
+ if (backendSNMPSupplies(snmp_fd, addr, NULL, NULL))
+ snmp_update = INT_MAX;
+ else
+ snmp_update = curtime + 5;
+ }
+ }
+
+ /*
+ * Return with success...
+ */
+
+ return (total_bytes);
+}
+
+
+/*
+ * 'backendWaitLoop()' - Wait for input from stdin while handling side-channel
+ * queries.
+ */
+
+int /* O - 1 if data is ready, 0 if not */
+backendWaitLoop(
+ int snmp_fd, /* I - SNMP socket or -1 if none */
+ http_addr_t *addr, /* I - Address of device */
+ int use_bc, /* I - Use back-channel? */
+ _cups_sccb_t side_cb) /* I - Side-channel callback */
+{
+ fd_set input; /* Input set for reading */
+ time_t curtime, /* Current time */
+ snmp_update = 0;
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ fprintf(stderr, "DEBUG: backendWaitLoop(snmp_fd=%d, addr=%p, side_cb=%p)\n",
+ snmp_fd, addr, side_cb);
+
+ /*
+ * Now loop until we receive data from stdin...
+ */
+
+ for (;;)
+ {
+ /*
+ * Use select() to determine whether we have data to copy around...
+ */
+
+ FD_ZERO(&input);
+ FD_SET(0, &input);
+ if (side_cb)
+ FD_SET(CUPS_SC_FD, &input);
+
+ if (select(CUPS_SC_FD + 1, &input, NULL, NULL, NULL) < 0)
+ {
+ /*
+ * Pause printing to clear any pending errors...
+ */
+
+ if (errno == EINTR)
+ {
+ fputs("DEBUG: Received an interrupt before any bytes were "
+ "written, aborting.\n", stderr);
+ return (0);
+ }
+
+ sleep(1);
+ continue;
+ }
+
+ /*
+ * Check for input on stdin...
+ */
+
+ if (FD_ISSET(0, &input))
+ break;
+
+ /*
+ * Check if we have a side-channel request ready...
+ */
+
+ if (side_cb && FD_ISSET(CUPS_SC_FD, &input))
+ {
+ /*
+ * Do the side-channel request, then start back over in the select
+ * loop since it may have read from print_fd...
+ */
+
+ if ((*side_cb)(0, -1, snmp_fd, addr, use_bc))
+ side_cb = NULL;
+ continue;
+ }
+
+ /*
+ * Do SNMP updates periodically...
+ */
+
+ if (snmp_fd >= 0 && time(&curtime) >= snmp_update)
+ {
+ if (backendSNMPSupplies(snmp_fd, addr, NULL, NULL))
+ snmp_update = INT_MAX;
+ else
+ snmp_update = curtime + 5;
+ }
+ }
+
+ /*
+ * Return with success...
+ */
+
+ return (1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/serial.c b/backend/serial.c
new file mode 100644
index 000000000..4223fcf5d
--- /dev/null
+++ b/backend/serial.c
@@ -0,0 +1,1327 @@
+/*
+ * "$Id$"
+ *
+ * Serial port backend for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "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.
+ * side_cb() - Handle side-channel requests...
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "backend-private.h"
+#include <stdio.h>
+
+#ifdef __hpux
+# include <sys/modem.h>
+#endif /* __hpux */
+
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+# include <fcntl.h>
+# include <termios.h>
+# ifdef __hpux
+# include <sys/time.h>
+# else
+# include <sys/select.h>
+# endif /* __hpux */
+# ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+# endif /* HAVE_SYS_IOCTL_H */
+#endif /* WIN32 */
+
+#ifdef __sgi
+# include <invent.h>
+# 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 <CoreFoundation/CoreFoundation.h>
+# include <IOKit/IOKitLib.h>
+# include <IOKit/serial/IOSerialKeys.h>
+# include <IOKit/IOBSD.h>
+#endif /* __APPLE__ */
+
+#if defined(__linux) && defined(TIOCGSERIAL)
+# include <linux/serial.h>
+# include <linux/ioctl.h>
+#endif /* __linux && TIOCGSERIAL */
+
+
+/*
+ * Local functions...
+ */
+
+static void list_devices(void);
+static int side_cb(int print_fd, int device_fd, int use_bc);
+
+
+/*
+ * '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, /* Name of option */
+ *value, /* Value of option */
+ sep; /* Option separator */
+ int port; /* Port number (not used) */
+ int copies; /* Number of copies to print */
+ int side_eof = 0, /* Saw EOF on side-channel? */
+ print_fd, /* Print file */
+ device_fd; /* Serial device */
+ int nfds; /* Maximum file descriptor value + 1 */
+ fd_set input, /* Input set for reading */
+ output; /* Output set for writing */
+ ssize_t print_bytes, /* Print bytes read */
+ bc_bytes, /* Backchannel bytes read */
+ total_bytes, /* Total bytes written */
+ bytes; /* Bytes written */
+ int dtrdsr; /* Do dtr/dsr flow control? */
+ int print_size; /* Size of output buffer for writes */
+ char print_buffer[8192], /* Print data buffer */
+ *print_ptr, /* Pointer into print data buffer */
+ bc_buffer[1024]; /* Back-channel data buffer */
+ struct termios opts; /* Serial port options */
+ struct termios origopts; /* Original port options */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * 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)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options [file]"),
+ 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)
+ {
+ print_fd = 0;
+ copies = 1;
+ }
+ else
+ {
+ /*
+ * Try to open the print file...
+ */
+
+ if ((print_fd = open(argv[6], O_RDONLY)) < 0)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ copies = atoi(argv[4]);
+ }
+
+ /*
+ * Extract the device name and options from the URI...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv),
+ 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...
+ */
+
+ fputs("STATE: +connecting-to-device\n", stderr);
+
+ do
+ {
+ if ((device_fd = open(resource, O_RDWR | 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.
+ */
+
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Unable to contact printer, queuing on next "
+ "printer in class."));
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ if (errno == EBUSY)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printer busy; will retry in 30 seconds."));
+ sleep(30);
+ }
+ else
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open device file"));
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+ }
+ while (device_fd < 0);
+
+ fputs("STATE: -connecting-to-device\n", stderr);
+
+ /*
+ * Set any options provided...
+ */
+
+ tcgetattr(device_fd, &origopts);
+ tcgetattr(device_fd, &opts);
+
+ opts.c_lflag &= ~(ICANON | ECHO | ISIG);
+ /* Raw mode */
+ opts.c_oflag &= ~OPOST; /* Don't post-process */
+
+ print_size = 96; /* 9600 baud / 10 bits/char / 10Hz */
+ dtrdsr = 0; /* No dtr/dsr flow control */
+
+ if (options)
+ {
+ while (*options)
+ {
+ /*
+ * Get the name...
+ */
+
+ name = options;
+
+ while (*options && *options != '=' && *options != '+' && *options != '&')
+ options ++;
+
+ if ((sep = *options) != '\0')
+ *options++ = '\0';
+
+ if (sep == '=')
+ {
+ /*
+ * Get the value...
+ */
+
+ value = options;
+
+ while (*options && *options != '+' && *options != '&')
+ options ++;
+
+ if (*options)
+ *options++ = '\0';
+ }
+ else
+ value = (char *)"";
+
+ /*
+ * Process the option...
+ */
+
+ if (!_cups_strcasecmp(name, "baud"))
+ {
+ /*
+ * Set the baud rate...
+ */
+
+ print_size = 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 :
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("Unsupported baud rate: %s"), value);
+ break;
+ }
+#endif /* B19200 == 19200 */
+ }
+ else if (!_cups_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 (!_cups_strcasecmp(name, "parity"))
+ {
+ /*
+ * Set parity checking...
+ */
+
+ if (!_cups_strcasecmp(value, "even"))
+ {
+ opts.c_cflag |= PARENB;
+ opts.c_cflag &= ~PARODD;
+ }
+ else if (!_cups_strcasecmp(value, "odd"))
+ {
+ opts.c_cflag |= PARENB;
+ opts.c_cflag |= PARODD;
+ }
+ else if (!_cups_strcasecmp(value, "none"))
+ opts.c_cflag &= ~PARENB;
+ else if (!_cups_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 (!_cups_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 (!_cups_strcasecmp(name, "flow"))
+ {
+ /*
+ * Set flow control...
+ */
+
+ if (!_cups_strcasecmp(value, "none"))
+ {
+ opts.c_iflag &= ~(IXON | IXOFF);
+ opts.c_cflag &= ~CRTSCTS;
+ }
+ else if (!_cups_strcasecmp(value, "soft"))
+ {
+ opts.c_iflag |= IXON | IXOFF;
+ opts.c_cflag &= ~CRTSCTS;
+ }
+ else if (!_cups_strcasecmp(value, "hard") ||
+ !_cups_strcasecmp(value, "rtscts"))
+ {
+ opts.c_iflag &= ~(IXON | IXOFF);
+ opts.c_cflag |= CRTSCTS;
+ }
+ else if (!_cups_strcasecmp(value, "dtrdsr"))
+ {
+ opts.c_iflag &= ~(IXON | IXOFF);
+ opts.c_cflag &= ~CRTSCTS;
+
+ dtrdsr = 1;
+ }
+ }
+ else if (!_cups_strcasecmp(name, "stop"))
+ {
+ switch (atoi(value))
+ {
+ case 1 :
+ opts.c_cflag &= ~CSTOPB;
+ break;
+
+ case 2 :
+ opts.c_cflag |= CSTOPB;
+ break;
+ }
+ }
+ }
+ }
+
+ tcsetattr(device_fd, TCSANOW, &opts);
+ fcntl(device_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 (!print_fd)
+ {
+#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 */
+ }
+
+ /*
+ * Figure out the maximum file descriptor value to use with select()...
+ */
+
+ nfds = (print_fd > device_fd ? print_fd : device_fd) + 1;
+
+ /*
+ * Finally, send the print file. Ordinarily we would just use the
+ * backendRunLoop() function, however since we need to use smaller
+ * writes and may need to do DSR/DTR flow control, we duplicate much
+ * of the code here instead...
+ */
+
+ if (print_size > sizeof(print_buffer))
+ print_size = sizeof(print_buffer);
+
+ total_bytes = 0;
+
+ while (copies > 0)
+ {
+ copies --;
+
+ if (print_fd != 0)
+ {
+ fputs("PAGE: 1 1\n", stderr);
+ lseek(print_fd, 0, SEEK_SET);
+ }
+
+ /*
+ * Now loop until we are out of data from print_fd...
+ */
+
+ for (print_bytes = 0, print_ptr = print_buffer;;)
+ {
+ /*
+ * Use select() to determine whether we have data to copy around...
+ */
+
+ FD_ZERO(&input);
+ if (!print_bytes)
+ FD_SET(print_fd, &input);
+ FD_SET(device_fd, &input);
+ if (!print_bytes && !side_eof)
+ FD_SET(CUPS_SC_FD, &input);
+
+ FD_ZERO(&output);
+ if (print_bytes)
+ FD_SET(device_fd, &output);
+
+ if (select(nfds, &input, &output, NULL, NULL) < 0)
+ continue; /* Ignore errors here */
+
+ /*
+ * Check if we have a side-channel request ready...
+ */
+
+ if (FD_ISSET(CUPS_SC_FD, &input))
+ {
+ /*
+ * Do the side-channel request, then start back over in the select
+ * loop since it may have read from print_fd...
+ */
+
+ if (side_cb(print_fd, device_fd, 1))
+ side_eof = 1;
+ continue;
+ }
+
+ /*
+ * Check if we have back-channel data ready...
+ */
+
+ if (FD_ISSET(device_fd, &input))
+ {
+ if ((bc_bytes = read(device_fd, bc_buffer, sizeof(bc_buffer))) > 0)
+ {
+ fprintf(stderr,
+ "DEBUG: Received " CUPS_LLFMT " bytes of back-channel data\n",
+ CUPS_LLCAST bc_bytes);
+ cupsBackChannelWrite(bc_buffer, bc_bytes, 1.0);
+ }
+ }
+
+ /*
+ * Check if we have print data ready...
+ */
+
+ if (FD_ISSET(print_fd, &input))
+ {
+ if ((print_bytes = read(print_fd, print_buffer, print_size)) < 0)
+ {
+ /*
+ * Read error - bail if we don't see EAGAIN or EINTR...
+ */
+
+ if (errno != EAGAIN || errno != EINTR)
+ {
+ perror("DEBUG: Unable to read print data");
+
+ tcsetattr(device_fd, TCSADRAIN, &origopts);
+
+ close(device_fd);
+
+ if (print_fd != 0)
+ close(print_fd);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ print_bytes = 0;
+ }
+ else if (print_bytes == 0)
+ {
+ /*
+ * End of file, break out of the loop...
+ */
+
+ break;
+ }
+
+ print_ptr = print_buffer;
+ }
+
+ /*
+ * Check if the device is ready to receive data and we have data to
+ * send...
+ */
+
+ if (print_bytes && FD_ISSET(device_fd, &output))
+ {
+ if (dtrdsr)
+ {
+ /*
+ * Check the port and sleep until DSR is set...
+ */
+
+ int status;
+
+
+ if (!ioctl(device_fd, TIOCMGET, &status))
+ if (!(status & TIOCM_DSR))
+ {
+ /*
+ * Wait for DSR to go high...
+ */
+
+ fputs("DEBUG: DSR is low; waiting for device...\n", stderr);
+
+ do
+ {
+ /*
+ * Poll every 100ms...
+ */
+
+ usleep(100000);
+
+ if (ioctl(device_fd, TIOCMGET, &status))
+ break;
+ }
+ while (!(status & TIOCM_DSR));
+
+ fputs("DEBUG: DSR is high; writing to device...\n", stderr);
+ }
+ }
+
+ if ((bytes = write(device_fd, print_ptr, print_bytes)) < 0)
+ {
+ /*
+ * Write error - bail if we don't see an error we can retry...
+ */
+
+ if (errno != EAGAIN && errno != EINTR && errno != ENOTTY)
+ {
+ perror("DEBUG: Unable to write print data");
+
+ tcsetattr(device_fd, TCSADRAIN, &origopts);
+
+ close(device_fd);
+
+ if (print_fd != 0)
+ close(print_fd);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "DEBUG: Wrote %d bytes...\n", (int)bytes);
+
+ print_bytes -= bytes;
+ print_ptr += bytes;
+ total_bytes += bytes;
+ }
+ }
+ }
+ }
+
+ /*
+ * Close the serial port and input file and return...
+ */
+
+ tcsetattr(device_fd, TCSADRAIN, &origopts);
+
+ close(device_fd);
+
+ if (print_fd != 0)
+ close(print_fd);
+
+ return (CUPS_BACKEND_OK);
+}
+
+
+/*
+ * 'list_devices()' - List all serial devices.
+ */
+
+static void
+list_devices(void)
+{
+#if defined(__hpux) || defined(__sgi) || defined(__sun) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+ static char *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz";
+ /* Funky hex numbering used for some *
+ * devices */
+#endif /* __hpux || __sgi || __sun || __FreeBSD__ || __OpenBSD__ || __FreeBSD_kernel__ */
+
+
+#ifdef __linux
+ int i, j; /* Looping vars */
+ int fd; /* File descriptor */
+ char device[255]; /* Device filename */
+ char info[255]; /* Device info/description */
+# ifdef TIOCGSERIAL
+ struct serial_struct serinfo; /* serial port info */
+# endif /* TIOCGSERIAL */
+
+
+ for (i = 0; i < 100; i ++)
+ {
+ sprintf(device, "/dev/ttyS%d", i);
+
+ if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
+ {
+# ifdef TIOCGSERIAL
+ /*
+ * See if this port exists...
+ */
+
+ serinfo.reserved_char[0] = 0;
+
+ if (!ioctl(fd, TIOCGSERIAL, &serinfo))
+ {
+ if (serinfo.type == PORT_UNKNOWN)
+ {
+ /*
+ * Nope...
+ */
+
+ close(fd);
+ continue;
+ }
+ }
+# endif /* TIOCGSERIAL */
+
+ close(fd);
+
+ snprintf(info, sizeof(info),
+ _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
+
+# if defined(_ARCH_PPC) || defined(powerpc) || defined(__powerpc)
+ printf("serial serial:%s?baud=230400 \"Unknown\" \"%s\"\n", device, info);
+# else
+ printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
+# endif /* _ARCH_PPC || powerpc || __powerpc */
+ }
+ }
+
+ for (i = 0; i < 16; i ++)
+ {
+ snprintf(info, sizeof(info),
+ _cupsLangString(cupsLangDefault(), _("USB Serial Port #%d")),
+ i + 1);
+
+ 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\" \"%s\"\n", device, info);
+ }
+
+ sprintf(device, "/dev/ttyUSB%d", i);
+ if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
+ {
+ close(fd);
+ printf("serial serial:%s?baud=230400 \"Unknown\" \"%s\"\n", device, info);
+ }
+ }
+
+ for (i = 0; i < 64; i ++)
+ {
+ for (j = 0; j < 8; j ++)
+ {
+ sprintf(device, "/dev/ttyQ%02de%d", i, j);
+ if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
+ {
+ close(fd);
+
+ printf("serial serial:%s?baud=115200 \"Unknown\" "
+ "\"Equinox ESP %d Port #%d\"\n", device, i, j + 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 */
+ char info[255]; /* Device info/description */
+
+
+ /*
+ * Standard serial ports...
+ */
+
+ for (i = 0; i < 26; i ++)
+ {
+ sprintf(device, "/dev/cua/%c", 'a' + i);
+ if (!access(device, 0))
+ {
+ snprintf(info, sizeof(info),
+ _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
+
+# ifdef B115200
+ printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
+# else
+ printf("serial serial:%s?baud=38400 \"Unknown\" \"%s\"\n", device, info);
+# 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__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+ int i, j; /* Looping vars */
+ int fd; /* File descriptor */
+ char device[255]; /* Device filename */
+ char info[255]; /* Device info/description */
+
+
+ /*
+ * 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);
+
+ snprintf(info, sizeof(info),
+ _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
+
+ printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
+ }
+ }
+
+ /*
+ * 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 */
+ char info[255]; /* Device info/description */
+
+
+ /*
+ * 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);
+
+ snprintf(info, sizeof(info),
+ _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
+
+ printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
+ }
+ }
+
+ /*
+ * 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;
+
+
+ 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;
+ CFTypeRef hiddenVal;
+ char serialName[128];
+ char bsdPath[1024];
+ Boolean result;
+
+
+ /* Check if hidden... */
+ hiddenVal = IORegistryEntrySearchCFProperty(serialService,
+ kIOServicePlane,
+ CFSTR("HiddenPort"),
+ kCFAllocatorDefault,
+ kIORegistryIterateRecursively |
+ kIORegistryIterateParents);
+ if (hiddenVal)
+ CFRelease(hiddenVal); /* This interface should not be used */
+ else
+ {
+ 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);
+ }
+
+ /*
+ * Release the iterator.
+ */
+
+ IOObjectRelease(serialPortIterator);
+ }
+ }
+#endif
+}
+
+
+/*
+ * 'side_cb()' - Handle side-channel requests...
+ */
+
+static int /* O - 0 on success, -1 on error */
+side_cb(int print_fd, /* I - Print file */
+ int device_fd, /* I - Device file */
+ int use_bc) /* I - Using back-channel? */
+{
+ cups_sc_command_t command; /* Request command */
+ cups_sc_status_t status; /* Request/response status */
+ char data[2048]; /* Request/response data */
+ int datalen; /* Request/response data size */
+
+
+ datalen = sizeof(data);
+
+ if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
+ return (-1);
+
+ switch (command)
+ {
+ case CUPS_SC_CMD_DRAIN_OUTPUT :
+ if (backendDrainOutput(print_fd, device_fd))
+ status = CUPS_SC_STATUS_IO_ERROR;
+ else if (tcdrain(device_fd))
+ status = CUPS_SC_STATUS_IO_ERROR;
+ else
+ status = CUPS_SC_STATUS_OK;
+
+ datalen = 0;
+ break;
+
+ case CUPS_SC_CMD_GET_BIDI :
+ status = CUPS_SC_STATUS_OK;
+ data[0] = use_bc;
+ datalen = 1;
+ break;
+
+ default :
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ datalen = 0;
+ break;
+ }
+
+ return (cupsSideChannelWrite(command, status, data, datalen, 1.0));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/snmp-supplies.c b/backend/snmp-supplies.c
new file mode 100644
index 000000000..1bd8b7fa5
--- /dev/null
+++ b/backend/snmp-supplies.c
@@ -0,0 +1,985 @@
+/*
+ * "$Id$"
+ *
+ * SNMP supplies functions for CUPS.
+ *
+ * Copyright 2008-2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * backendSNMPSupplies() - Get the current supplies for a device.
+ * backend_init_supplies() - Initialize the supplies list.
+ * backend_walk_cb() - Interpret the supply value responses.
+ * utf16_to_utf8() - Convert UTF-16 text to UTF-8.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "backend-private.h"
+#include <cups/array.h>
+
+
+/*
+ * Local constants...
+ */
+
+#define CUPS_MAX_SUPPLIES 32 /* Maximum number of supplies for a printer */
+#define CUPS_SUPPLY_TIMEOUT 2.0 /* Timeout for SNMP lookups */
+
+#define CUPS_DEVELOPER_LOW 1
+#define CUPS_DEVELOPER_EMPTY 2
+#define CUPS_MARKER_SUPPLY_LOW 4
+#define CUPS_MARKER_SUPPLY_EMPTY 8
+#define CUPS_OPC_NEAR_EOL 16
+#define CUPS_OPC_LIFE_OVER 32
+#define CUPS_TONER_LOW 64
+#define CUPS_TONER_EMPTY 128
+
+
+/*
+ * Local structures...
+ */
+
+typedef struct /**** Printer supply data ****/
+{
+ char name[CUPS_SNMP_MAX_STRING], /* Name of supply */
+ color[8]; /* Color: "#RRGGBB" or "none" */
+ int colorant, /* Colorant index */
+ type, /* Supply type */
+ max_capacity, /* Maximum capacity */
+ level; /* Current level value */
+} backend_supplies_t;
+
+typedef struct /**** Printer state table ****/
+{
+ int bit; /* State bit */
+ const char *keyword; /* IPP printer-state-reasons keyword */
+} backend_state_t;
+
+
+/*
+ * Local globals...
+ */
+
+static http_addr_t current_addr; /* Current address */
+static int current_state = -1;
+ /* Current device state bits */
+static int charset = -1; /* Character set for supply names */
+static int num_supplies = 0;
+ /* Number of supplies found */
+static backend_supplies_t supplies[CUPS_MAX_SUPPLIES];
+ /* Supply information */
+static int supply_state = -1;
+ /* Supply state info */
+
+static const int hrDeviceDescr[] =
+ { CUPS_OID_hrDeviceDescr, 1, -1 };
+ /* Device description OID */
+static const int hrPrinterStatus[] =
+ { CUPS_OID_hrPrinterStatus, 1, -1 };
+ /* Current state OID */
+static const int hrPrinterDetectedErrorState[] =
+ { CUPS_OID_hrPrinterDetectedErrorState, 1, -1 };
+ /* Current printer state bits OID */
+static const int prtGeneralCurrentLocalization[] =
+ { CUPS_OID_prtGeneralCurrentLocalization, 1, -1 };
+static const int prtLocalizationCharacterSet[] =
+ { CUPS_OID_prtLocalizationCharacterSet, 1, 1, -1 },
+ prtLocalizationCharacterSetOffset =
+ (sizeof(prtLocalizationCharacterSet) /
+ sizeof(prtLocalizationCharacterSet[0]));
+static const int prtMarkerColorantValue[] =
+ { CUPS_OID_prtMarkerColorantValue, -1 },
+ /* Colorant OID */
+ prtMarkerColorantValueOffset =
+ (sizeof(prtMarkerColorantValue) /
+ sizeof(prtMarkerColorantValue[0]));
+ /* Offset to colorant index */
+static const int prtMarkerLifeCount[] =
+ { CUPS_OID_prtMarkerLifeCount, 1, 1, -1 };
+ /* Page counter OID */
+static const int prtMarkerSuppliesEntry[] =
+ { CUPS_OID_prtMarkerSuppliesEntry, -1 };
+ /* Supplies OID */
+static const int prtMarkerSuppliesColorantIndex[] =
+ { CUPS_OID_prtMarkerSuppliesColorantIndex, -1 },
+ /* Colorant index OID */
+ prtMarkerSuppliesColorantIndexOffset =
+ (sizeof(prtMarkerSuppliesColorantIndex) /
+ sizeof(prtMarkerSuppliesColorantIndex[0]));
+ /* Offset to supply index */
+static const int prtMarkerSuppliesDescription[] =
+ { CUPS_OID_prtMarkerSuppliesDescription, -1 },
+ /* Description OID */
+ prtMarkerSuppliesDescriptionOffset =
+ (sizeof(prtMarkerSuppliesDescription) /
+ sizeof(prtMarkerSuppliesDescription[0]));
+ /* Offset to supply index */
+static const int prtMarkerSuppliesLevel[] =
+ { CUPS_OID_prtMarkerSuppliesLevel, -1 },
+ /* Level OID */
+ prtMarkerSuppliesLevelOffset =
+ (sizeof(prtMarkerSuppliesLevel) /
+ sizeof(prtMarkerSuppliesLevel[0]));
+ /* Offset to supply index */
+static const int prtMarkerSuppliesMaxCapacity[] =
+ { CUPS_OID_prtMarkerSuppliesMaxCapacity, -1 },
+ /* Max capacity OID */
+ prtMarkerSuppliesMaxCapacityOffset =
+ (sizeof(prtMarkerSuppliesMaxCapacity) /
+ sizeof(prtMarkerSuppliesMaxCapacity[0]));
+ /* Offset to supply index */
+static const int prtMarkerSuppliesType[] =
+ { CUPS_OID_prtMarkerSuppliesType, -1 },
+ /* Type OID */
+ prtMarkerSuppliesTypeOffset =
+ (sizeof(prtMarkerSuppliesType) /
+ sizeof(prtMarkerSuppliesType[0]));
+ /* Offset to supply index */
+
+static const backend_state_t const printer_states[] =
+ {
+ { CUPS_TC_lowPaper, "media-low-report" },
+ { CUPS_TC_noPaper | CUPS_TC_inputTrayEmpty, "media-empty-warning" },
+ /* { CUPS_TC_lowToner, "toner-low-report" }, */ /* now use prtMarkerSupplies */
+ /* { CUPS_TC_noToner, "toner-empty-warning" }, */ /* now use prtMarkerSupplies */
+ { CUPS_TC_doorOpen, "door-open-report" },
+ { CUPS_TC_jammed, "media-jam-warning" },
+ /* { CUPS_TC_offline, "offline-report" }, */ /* unreliable */
+ /* { CUPS_TC_serviceRequested | CUPS_TC_overduePreventMaint, "service-needed-warning" }, */ /* unreliable */
+ { CUPS_TC_inputTrayMissing, "input-tray-missing-warning" },
+ { CUPS_TC_outputTrayMissing, "output-tray-missing-warning" },
+ { CUPS_TC_markerSupplyMissing, "marker-supply-missing-warning" },
+ { CUPS_TC_outputNearFull, "output-area-almost-full-report" },
+ { CUPS_TC_outputFull, "output-area-full-warning" }
+ };
+
+static const backend_state_t const supply_states[] =
+ {
+ { CUPS_DEVELOPER_LOW, "developer-low-report" },
+ { CUPS_DEVELOPER_EMPTY, "developer-empty-warning" },
+ { CUPS_MARKER_SUPPLY_LOW, "marker-supply-low-report" },
+ { CUPS_MARKER_SUPPLY_EMPTY, "marker-supply-empty-warning" },
+ { CUPS_OPC_NEAR_EOL, "opc-near-eol-report" },
+ { CUPS_OPC_LIFE_OVER, "opc-life-over-warning" },
+ { CUPS_TONER_LOW, "toner-low-report" },
+ { CUPS_TONER_EMPTY, "toner-empty-warning" }
+ };
+
+
+/*
+ * Local functions...
+ */
+
+static void backend_init_supplies(int snmp_fd, http_addr_t *addr);
+static void backend_walk_cb(cups_snmp_t *packet, void *data);
+static void utf16_to_utf8(cups_utf8_t *dst, const unsigned char *src,
+ size_t srcsize, size_t dstsize, int le);
+
+
+/*
+ * 'backendSNMPSupplies()' - Get the current supplies for a device.
+ */
+
+int /* O - 0 on success, -1 on error */
+backendSNMPSupplies(
+ int snmp_fd, /* I - SNMP socket */
+ http_addr_t *addr, /* I - Printer address */
+ int *page_count, /* O - Page count */
+ int *printer_state) /* O - Printer state */
+{
+ if (!httpAddrEqual(addr, &current_addr))
+ backend_init_supplies(snmp_fd, addr);
+ else if (num_supplies > 0)
+ _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel,
+ CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
+
+ if (page_count)
+ *page_count = -1;
+
+ if (printer_state)
+ *printer_state = -1;
+
+ if (num_supplies > 0)
+ {
+ int i, /* Looping var */
+ percent, /* Percent full */
+ new_state, /* New state value */
+ change_state, /* State change */
+ new_supply_state = 0; /* Supply state */
+ char value[CUPS_MAX_SUPPLIES * 4],
+ /* marker-levels value string */
+ *ptr; /* Pointer into value string */
+ cups_snmp_t packet; /* SNMP response packet */
+
+ /*
+ * Generate the marker-levels value string...
+ */
+
+ for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
+ {
+ if (supplies[i].max_capacity > 0)
+ percent = 100 * supplies[i].level / supplies[i].max_capacity;
+ else
+ percent = 50;
+
+ if (percent <= 10)
+ {
+ switch (supplies[i].type)
+ {
+ case CUPS_TC_toner :
+ case CUPS_TC_tonerCartridge :
+ if (percent <= 1)
+ new_supply_state |= CUPS_TONER_EMPTY;
+ else
+ new_supply_state |= CUPS_TONER_LOW;
+ break;
+ case CUPS_TC_wasteToner :
+ case CUPS_TC_wasteInk :
+ break;
+ case CUPS_TC_ink :
+ case CUPS_TC_inkCartridge :
+ case CUPS_TC_inkRibbon :
+ case CUPS_TC_solidWax :
+ case CUPS_TC_ribbonWax :
+ if (percent <= 1)
+ new_supply_state |= CUPS_MARKER_SUPPLY_EMPTY;
+ else
+ new_supply_state |= CUPS_MARKER_SUPPLY_LOW;
+ break;
+ case CUPS_TC_developer :
+ if (percent <= 1)
+ new_supply_state |= CUPS_DEVELOPER_EMPTY;
+ else
+ new_supply_state |= CUPS_DEVELOPER_LOW;
+ break;
+ case CUPS_TC_coronaWire :
+ case CUPS_TC_fuser :
+ case CUPS_TC_opc :
+ case CUPS_TC_transferUnit :
+ if (percent <= 1)
+ new_supply_state |= CUPS_OPC_LIFE_OVER;
+ else
+ new_supply_state |= CUPS_OPC_NEAR_EOL;
+ break;
+ }
+ }
+
+ if (i)
+ *ptr++ = ',';
+
+ if (supplies[i].max_capacity > 0)
+ sprintf(ptr, "%d", percent);
+ else
+ strcpy(ptr, "-1");
+ }
+
+ fprintf(stderr, "ATTR: marker-levels=%s\n", value);
+
+ if (supply_state < 0)
+ change_state = 0xffff;
+ else
+ change_state = supply_state ^ new_supply_state;
+
+ fprintf(stderr, "DEBUG: new_supply_state=%x, change_state=%x\n",
+ new_supply_state, change_state);
+
+ for (i = 0;
+ i < (int)(sizeof(supply_states) / sizeof(supply_states[0]));
+ i ++)
+ if (change_state & supply_states[i].bit)
+ {
+ fprintf(stderr, "STATE: %c%s\n",
+ (new_supply_state & supply_states[i].bit) ? '+' : '-',
+ supply_states[i].keyword);
+ }
+
+ supply_state = new_supply_state;
+
+ /*
+ * Get the current printer status bits...
+ */
+
+ if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
+ hrPrinterDetectedErrorState))
+ return (-1);
+
+ if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
+ packet.object_type != CUPS_ASN1_OCTET_STRING)
+ return (-1);
+
+ if (packet.object_value.string.num_bytes == 2)
+ new_state = (packet.object_value.string.bytes[0] << 8) |
+ packet.object_value.string.bytes[1];
+ else if (packet.object_value.string.num_bytes == 1)
+ new_state = (packet.object_value.string.bytes[0] << 8);
+ else
+ new_state = 0;
+
+ if (current_state < 0)
+ change_state = 0xffff;
+ else
+ change_state = current_state ^ new_state;
+
+ fprintf(stderr, "DEBUG: new_state=%x, change_state=%x\n", new_state,
+ change_state);
+
+ for (i = 0;
+ i < (int)(sizeof(printer_states) / sizeof(printer_states[0]));
+ i ++)
+ if (change_state & printer_states[i].bit)
+ {
+ fprintf(stderr, "STATE: %c%s\n",
+ (new_state & printer_states[i].bit) ? '+' : '-',
+ printer_states[i].keyword);
+ }
+
+ current_state = new_state;
+
+ /*
+ * Get the current printer state...
+ */
+
+ if (printer_state)
+ {
+ if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
+ hrPrinterStatus))
+ return (-1);
+
+ if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
+ packet.object_type != CUPS_ASN1_INTEGER)
+ return (-1);
+
+ *printer_state = packet.object_value.integer;
+ }
+
+ /*
+ * Get the current page count...
+ */
+
+ if (page_count)
+ {
+ if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
+ prtMarkerLifeCount))
+ return (-1);
+
+ if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
+ packet.object_type != CUPS_ASN1_COUNTER)
+ return (-1);
+
+ *page_count = packet.object_value.counter;
+ }
+
+ return (0);
+ }
+ else
+ return (-1);
+}
+
+
+/*
+ * 'backend_init_supplies()' - Initialize the supplies list.
+ */
+
+static void
+backend_init_supplies(
+ int snmp_fd, /* I - SNMP socket */
+ http_addr_t *addr) /* I - Printer address */
+{
+ int i, /* Looping var */
+ type; /* Current marker type */
+ cups_file_t *cachefile; /* Cache file */
+ const char *cachedir; /* CUPS_CACHEDIR value */
+ char addrstr[1024], /* Address string */
+ cachefilename[1024], /* Cache filename */
+ description[CUPS_SNMP_MAX_STRING],
+ /* Device description string */
+ value[CUPS_MAX_SUPPLIES * (CUPS_SNMP_MAX_STRING * 2 + 3)],
+ /* Value string */
+ *ptr, /* Pointer into value string */
+ *name_ptr; /* Pointer into name string */
+ cups_snmp_t packet; /* SNMP response packet */
+ ppd_file_t *ppd; /* PPD file for this queue */
+ ppd_attr_t *ppdattr; /* cupsSNMPSupplies attribute */
+ static const char * const types[] = /* Supply types */
+ {
+ "other",
+ "unknown",
+ "toner",
+ "wasteToner",
+ "ink",
+ "inkCartridge",
+ "inkRibbon",
+ "wasteInk",
+ "opc",
+ "developer",
+ "fuserOil",
+ "solidWax",
+ "ribbonWax",
+ "wasteWax",
+ "fuser",
+ "coronaWire",
+ "fuserOilWick",
+ "cleanerUnit",
+ "fuserCleaningPad",
+ "transferUnit",
+ "tonerCartridge",
+ "fuserOiler",
+ "water",
+ "wasteWater",
+ "glueWaterAdditive",
+ "wastePaper",
+ "bindingSupply",
+ "bandingSupply",
+ "stitchingWire",
+ "shrinkWrap",
+ "paperWrap",
+ "staples",
+ "inserts",
+ "covers"
+ };
+
+
+ /*
+ * Reset state information...
+ */
+
+ current_addr = *addr;
+ current_state = -1;
+ num_supplies = -1;
+ charset = -1;
+
+ memset(supplies, 0, sizeof(supplies));
+
+ /*
+ * See if we should be getting supply levels via SNMP...
+ */
+
+ if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL ||
+ ((ppdattr = ppdFindAttr(ppd, "cupsSNMPSupplies", NULL)) != NULL &&
+ ppdattr->value && _cups_strcasecmp(ppdattr->value, "true")))
+ {
+ ppdClose(ppd);
+ return;
+ }
+
+ ppdClose(ppd);
+
+ /*
+ * Get the device description...
+ */
+
+ if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
+ hrDeviceDescr))
+ return;
+
+ if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
+ packet.object_type != CUPS_ASN1_OCTET_STRING)
+ {
+ strlcpy(description, "Unknown", sizeof(description));
+ num_supplies = 0;
+ }
+ else
+ strlcpy(description, (char *)packet.object_value.string.bytes,
+ sizeof(description));
+
+ fprintf(stderr, "DEBUG2: hrDeviceDesc=\"%s\"\n", description);
+
+ /*
+ * See if we have already queried this device...
+ */
+
+ httpAddrString(addr, addrstr, sizeof(addrstr));
+
+ if ((cachedir = getenv("CUPS_CACHEDIR")) == NULL)
+ cachedir = CUPS_CACHEDIR;
+
+ snprintf(cachefilename, sizeof(cachefilename), "%s/%s.snmp", cachedir,
+ addrstr);
+
+ if ((cachefile = cupsFileOpen(cachefilename, "r")) != NULL)
+ {
+ /*
+ * Yes, read the cache file:
+ *
+ * 2 num_supplies charset
+ * device description
+ * supply structures...
+ */
+
+ if (cupsFileGets(cachefile, value, sizeof(value)))
+ {
+ if (sscanf(value, "2 %d%d", &num_supplies, &charset) == 2 &&
+ num_supplies <= CUPS_MAX_SUPPLIES &&
+ cupsFileGets(cachefile, value, sizeof(value)))
+ {
+ if (!strcmp(description, value))
+ cupsFileRead(cachefile, (char *)supplies,
+ num_supplies * sizeof(backend_supplies_t));
+ else
+ {
+ num_supplies = -1;
+ charset = -1;
+ }
+ }
+ else
+ {
+ num_supplies = -1;
+ charset = -1;
+ }
+ }
+
+ cupsFileClose(cachefile);
+ }
+
+ /*
+ * If the cache information isn't correct, scan for supplies...
+ */
+
+ if (charset < 0)
+ {
+ /*
+ * Get the configured character set...
+ */
+
+ int oid[CUPS_SNMP_MAX_OID]; /* OID for character set */
+
+
+ if (!_cupsSNMPWrite(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
+ prtGeneralCurrentLocalization))
+ return;
+
+ if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
+ packet.object_type != CUPS_ASN1_INTEGER)
+ {
+ fprintf(stderr,
+ "DEBUG: prtGeneralCurrentLocalization type is %x, expected %x!\n",
+ packet.object_type, CUPS_ASN1_INTEGER);
+ return;
+ }
+
+ fprintf(stderr, "DEBUG2: prtGeneralCurrentLocalization=%d\n",
+ packet.object_value.integer);
+
+ _cupsSNMPCopyOID(oid, prtLocalizationCharacterSet, CUPS_SNMP_MAX_OID);
+ oid[prtLocalizationCharacterSetOffset - 2] = packet.object_value.integer;
+
+
+ if (!_cupsSNMPWrite(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
+ oid))
+ return;
+
+ if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
+ packet.object_type != CUPS_ASN1_INTEGER)
+ {
+ fprintf(stderr,
+ "DEBUG: prtLocalizationCharacterSet type is %x, expected %x!\n",
+ packet.object_type, CUPS_ASN1_INTEGER);
+ return;
+ }
+
+ fprintf(stderr, "DEBUG2: prtLocalizationCharacterSet=%d\n",
+ packet.object_value.integer);
+ charset = packet.object_value.integer;
+ }
+
+ if (num_supplies < 0)
+ {
+ /*
+ * Walk the printer configuration information...
+ */
+
+ _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry,
+ CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
+ }
+
+ /*
+ * Save the cached information...
+ */
+
+ if (num_supplies < 0)
+ num_supplies = 0;
+
+ if ((cachefile = cupsFileOpen(cachefilename, "w")) != NULL)
+ {
+ cupsFilePrintf(cachefile, "2 %d %d\n", num_supplies, charset);
+ cupsFilePrintf(cachefile, "%s\n", description);
+
+ if (num_supplies > 0)
+ cupsFileWrite(cachefile, (char *)supplies,
+ num_supplies * sizeof(backend_supplies_t));
+
+ cupsFileClose(cachefile);
+ }
+
+ if (num_supplies <= 0)
+ return;
+
+ /*
+ * Get the colors...
+ */
+
+ for (i = 0; i < num_supplies; i ++)
+ strcpy(supplies[i].color, "none");
+
+ _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(), prtMarkerColorantValue,
+ CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
+
+ /*
+ * Output the marker-colors attribute...
+ */
+
+ for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
+ {
+ if (i)
+ *ptr++ = ',';
+
+ strcpy(ptr, supplies[i].color);
+ }
+
+ fprintf(stderr, "ATTR: marker-colors=%s\n", value);
+
+ /*
+ * Output the marker-names attribute...
+ */
+
+ for (i = 0, ptr = value; i < num_supplies; i ++)
+ {
+ if (i)
+ *ptr++ = ',';
+
+ *ptr++ = '\"';
+ for (name_ptr = supplies[i].name; *name_ptr;)
+ {
+ if (*name_ptr == '\\' || *name_ptr == '\"')
+ *ptr++ = '\\';
+
+ *ptr++ = *name_ptr++;
+ }
+ *ptr++ = '\"';
+ }
+
+ *ptr = '\0';
+
+ fprintf(stderr, "ATTR: marker-names=%s\n", value);
+
+ /*
+ * Output the marker-types attribute...
+ */
+
+ for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
+ {
+ if (i)
+ *ptr++ = ',';
+
+ type = supplies[i].type;
+
+ if (type < CUPS_TC_other || type > CUPS_TC_covers)
+ strcpy(ptr, "unknown");
+ else
+ strcpy(ptr, types[type - CUPS_TC_other]);
+ }
+
+ fprintf(stderr, "ATTR: marker-types=%s\n", value);
+}
+
+
+/*
+ * 'backend_walk_cb()' - Interpret the supply value responses.
+ */
+
+static void
+backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */
+ void *data) /* I - User data (unused) */
+{
+ int i, j, k; /* Looping vars */
+ static const char * const colors[8][2] =
+ { /* Standard color names */
+ { "black", "#000000" },
+ { "blue", "#0000FF" },
+ { "cyan", "#00FFFF" },
+ { "green", "#00FF00" },
+ { "magenta", "#FF00FF" },
+ { "red", "#FF0000" },
+ { "white", "#FFFFFF" },
+ { "yellow", "#FFFF00" }
+ };
+
+
+ (void)data;
+
+ if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerColorantValue) &&
+ packet->object_type == CUPS_ASN1_OCTET_STRING)
+ {
+ /*
+ * Get colorant...
+ */
+
+ i = packet->object_name[prtMarkerColorantValueOffset];
+
+ fprintf(stderr, "DEBUG2: prtMarkerColorantValue.1.%d = \"%s\"\n", i,
+ (char *)packet->object_value.string.bytes);
+
+ for (j = 0; j < num_supplies; j ++)
+ if (supplies[j].colorant == i)
+ {
+ for (k = 0; k < (int)(sizeof(colors) / sizeof(colors[0])); k ++)
+ if (!strcmp(colors[k][0], (char *)packet->object_value.string.bytes))
+ {
+ strcpy(supplies[j].color, colors[k][1]);
+ break;
+ }
+ }
+ }
+ else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesColorantIndex))
+ {
+ /*
+ * Get colorant index...
+ */
+
+ i = packet->object_name[prtMarkerSuppliesColorantIndexOffset];
+ if (i < 1 || i > CUPS_MAX_SUPPLIES ||
+ packet->object_type != CUPS_ASN1_INTEGER)
+ return;
+
+ fprintf(stderr, "DEBUG2: prtMarkerSuppliesColorantIndex.1.%d = %d\n", i,
+ packet->object_value.integer);
+
+ if (i > num_supplies)
+ num_supplies = i;
+
+ supplies[i - 1].colorant = packet->object_value.integer;
+ }
+ else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesDescription))
+ {
+ /*
+ * Get supply name/description...
+ */
+
+ i = packet->object_name[prtMarkerSuppliesDescriptionOffset];
+ if (i < 1 || i > CUPS_MAX_SUPPLIES ||
+ packet->object_type != CUPS_ASN1_OCTET_STRING)
+ return;
+
+ if (i > num_supplies)
+ num_supplies = i;
+
+ switch (charset)
+ {
+ case CUPS_TC_csASCII :
+ case CUPS_TC_csUTF8 :
+ case CUPS_TC_csUnicodeASCII :
+ strlcpy(supplies[i - 1].name,
+ (char *)packet->object_value.string.bytes,
+ sizeof(supplies[0].name));
+ break;
+
+ case CUPS_TC_csISOLatin1 :
+ case CUPS_TC_csUnicodeLatin1 :
+ cupsCharsetToUTF8((cups_utf8_t *)supplies[i - 1].name,
+ (char *)packet->object_value.string.bytes,
+ sizeof(supplies[0].name), CUPS_ISO8859_1);
+ break;
+
+ case CUPS_TC_csShiftJIS :
+ cupsCharsetToUTF8((cups_utf8_t *)supplies[i - 1].name,
+ (char *)packet->object_value.string.bytes,
+ sizeof(supplies[0].name), CUPS_JIS_X0213);
+ break;
+
+ case CUPS_TC_csUCS4 :
+ case CUPS_TC_csUTF32 :
+ case CUPS_TC_csUTF32BE :
+ case CUPS_TC_csUTF32LE :
+ cupsUTF32ToUTF8((cups_utf8_t *)supplies[i - 1].name,
+ (cups_utf32_t *)packet->object_value.string.bytes,
+ sizeof(supplies[0].name));
+ break;
+
+ case CUPS_TC_csUnicode :
+ case CUPS_TC_csUTF16BE :
+ case CUPS_TC_csUTF16LE :
+ utf16_to_utf8((cups_utf8_t *)supplies[i - 1].name,
+ packet->object_value.string.bytes,
+ packet->object_value.string.num_bytes,
+ sizeof(supplies[0].name), charset == CUPS_TC_csUTF16LE);
+ break;
+
+ default :
+ /*
+ * If we get here, the printer is using an unknown character set and
+ * we just want to copy characters that look like ASCII...
+ */
+
+ {
+ char *src, *dst; /* Pointers into strings */
+
+
+ /*
+ * Loop safe because both the object_value and supplies char arrays
+ * are CUPS_SNMP_MAX_STRING elements long.
+ */
+
+ for (src = (char *)packet->object_value.string.bytes,
+ dst = supplies[i - 1].name;
+ *src;
+ src ++)
+ {
+ if ((*src & 0x80) || *src < ' ' || *src == 0x7f)
+ *dst++ = '?';
+ else
+ *dst++ = *src;
+ }
+
+ *dst = '\0';
+ }
+ break;
+ }
+
+ fprintf(stderr, "DEBUG2: prtMarkerSuppliesDescription.1.%d = \"%s\"\n", i,
+ supplies[i - 1].name);
+
+ }
+ else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesLevel))
+ {
+ /*
+ * Get level...
+ */
+
+ i = packet->object_name[prtMarkerSuppliesLevelOffset];
+ if (i < 1 || i > CUPS_MAX_SUPPLIES ||
+ packet->object_type != CUPS_ASN1_INTEGER)
+ return;
+
+ fprintf(stderr, "DEBUG2: prtMarkerSuppliesLevel.1.%d = %d\n", i,
+ packet->object_value.integer);
+
+ if (i > num_supplies)
+ num_supplies = i;
+
+ supplies[i - 1].level = packet->object_value.integer;
+ }
+ else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity))
+ {
+ /*
+ * Get max capacity...
+ */
+
+ i = packet->object_name[prtMarkerSuppliesMaxCapacityOffset];
+ if (i < 1 || i > CUPS_MAX_SUPPLIES ||
+ packet->object_type != CUPS_ASN1_INTEGER)
+ return;
+
+ fprintf(stderr, "DEBUG2: prtMarkerSuppliesMaxCapacity.1.%d = %d\n", i,
+ packet->object_value.integer);
+
+ if (i > num_supplies)
+ num_supplies = i;
+
+ supplies[i - 1].max_capacity = packet->object_value.integer;
+ }
+ else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesType))
+ {
+ /*
+ * Get marker type...
+ */
+
+ i = packet->object_name[prtMarkerSuppliesTypeOffset];
+ if (i < 1 || i > CUPS_MAX_SUPPLIES ||
+ packet->object_type != CUPS_ASN1_INTEGER)
+ return;
+
+ fprintf(stderr, "DEBUG2: prtMarkerSuppliesType.1.%d = %d\n", i,
+ packet->object_value.integer);
+
+ if (i > num_supplies)
+ num_supplies = i;
+
+ supplies[i - 1].type = packet->object_value.integer;
+ }
+}
+
+
+/*
+ * 'utf16_to_utf8()' - Convert UTF-16 text to UTF-8.
+ */
+
+static void
+utf16_to_utf8(
+ cups_utf8_t *dst, /* I - Destination buffer */
+ const unsigned char *src, /* I - Source string */
+ size_t srcsize, /* I - Size of source string */
+ size_t dstsize, /* I - Size of destination buffer */
+ int le) /* I - Source is little-endian? */
+{
+ cups_utf32_t ch, /* Current character */
+ temp[CUPS_SNMP_MAX_STRING],
+ /* UTF-32 string */
+ *ptr; /* Pointer into UTF-32 string */
+
+
+ for (ptr = temp; srcsize >= 2;)
+ {
+ if (le)
+ ch = src[0] | (src[1] << 8);
+ else
+ ch = (src[0] << 8) | src[1];
+
+ src += 2;
+ srcsize -= 2;
+
+ if (ch >= 0xd800 && ch <= 0xdbff && srcsize >= 2)
+ {
+ /*
+ * Multi-word UTF-16 char...
+ */
+
+ int lch; /* Lower word */
+
+
+ if (le)
+ lch = src[0] | (src[1] << 8);
+ else
+ lch = (src[0] << 8) | src[1];
+
+ if (lch >= 0xdc00 && lch <= 0xdfff)
+ {
+ src += 2;
+ srcsize -= 2;
+
+ ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
+ }
+ }
+
+ if (ptr < (temp + CUPS_SNMP_MAX_STRING - 1))
+ *ptr++ = ch;
+ }
+
+ *ptr = '\0';
+
+ cupsUTF32ToUTF8(dst, temp, dstsize);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/snmp.c b/backend/snmp.c
new file mode 100644
index 000000000..86aeff743
--- /dev/null
+++ b/backend/snmp.c
@@ -0,0 +1,1375 @@
+/*
+ * "$Id$"
+ *
+ * SNMP discovery backend for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2006-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Discover printers via SNMP.
+ * add_array() - Add a string to an array.
+ * add_cache() - Add a cached device...
+ * add_device_uri() - Add a device URI to the cache.
+ * alarm_handler() - Handle alarm signals...
+ * compare_cache() - Compare two cache entries.
+ * debug_printf() - Display some debugging information.
+ * fix_make_model() - Fix common problems in the make-and-model
+ * string.
+ * free_array() - Free an array of strings.
+ * free_cache() - Free the array of cached devices.
+ * get_interface_addresses() - Get the broadcast address(es) associated with
+ * an interface.
+ * list_device() - List a device we found...
+ * password_cb() - Handle authentication requests.
+ * probe_device() - Probe a device to discover whether it is a
+ * printer.
+ * read_snmp_conf() - Read the snmp.conf file.
+ * read_snmp_response() - Read and parse a SNMP response...
+ * run_time() - Return the total running time...
+ * scan_devices() - Scan for devices using SNMP.
+ * try_connect() - Try connecting on a port...
+ * update_cache() - Update a cached device...
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "backend-private.h"
+#include <cups/array.h>
+#include <cups/file.h>
+#include <cups/http-private.h>
+#include <regex.h>
+
+
+/*
+ * This backend implements SNMP printer discovery. It uses a broadcast-
+ * based approach to get SNMP response packets from potential printers,
+ * requesting OIDs from the Host and Port Monitor MIBs, does a URI
+ * lookup based on the device description string, and finally a probe of
+ * port 9100 (AppSocket) and 515 (LPD).
+ *
+ * The current focus is on printers with internal network cards, although
+ * the code also works with many external print servers as well.
+ *
+ * The backend reads the snmp.conf file from the CUPS_SERVERROOT directory
+ * which can contain comments, blank lines, or any number of the following
+ * directives:
+ *
+ * Address ip-address
+ * Address @LOCAL
+ * Address @IF(name)
+ * Community name
+ * DebugLevel N
+ * DeviceURI "regex pattern" uri
+ * HostNameLookups on
+ * HostNameLookups off
+ * MaxRunTime N
+ *
+ * The default is to use:
+ *
+ * Address @LOCAL
+ * Community public
+ * DebugLevel 0
+ * HostNameLookups off
+ * MaxRunTime 120
+ *
+ * This backend is known to work with the following network printers and
+ * print servers:
+ *
+ * Axis OfficeBasic, 5400, 5600
+ * Brother
+ * EPSON
+ * Genicom
+ * HP JetDirect
+ * Lexmark
+ * Sharp
+ * Tektronix
+ * Xerox
+ *
+ * It does not currently work with:
+ *
+ * DLink
+ * Linksys
+ * Netgear
+ * Okidata
+ *
+ * (for all of these, they do not support the Host MIB)
+ */
+
+/*
+ * Types...
+ */
+
+enum /**** Request IDs for each field ****/
+{
+ DEVICE_TYPE = 1,
+ DEVICE_DESCRIPTION,
+ DEVICE_LOCATION,
+ DEVICE_ID,
+ DEVICE_URI,
+ DEVICE_PRODUCT
+};
+
+typedef struct device_uri_s /**** DeviceURI values ****/
+{
+ regex_t re; /* Regular expression to match */
+ cups_array_t *uris; /* URIs */
+} device_uri_t;
+
+typedef struct snmp_cache_s /**** SNMP scan cache ****/
+{
+ http_addr_t address; /* Address of device */
+ char *addrname, /* Name of device */
+ *uri, /* device-uri */
+ *id, /* device-id */
+ *info, /* device-info */
+ *location, /* device-location */
+ *make_and_model; /* device-make-and-model */
+ int sent; /* Has this device been listed? */
+} snmp_cache_t;
+
+
+/*
+ * Local functions...
+ */
+
+static char *add_array(cups_array_t *a, const char *s);
+static void add_cache(http_addr_t *addr, const char *addrname,
+ const char *uri, const char *id,
+ const char *make_and_model);
+static device_uri_t *add_device_uri(char *value);
+static void alarm_handler(int sig);
+static int compare_cache(snmp_cache_t *a, snmp_cache_t *b);
+static void debug_printf(const char *format, ...);
+static void fix_make_model(char *make_model,
+ const char *old_make_model,
+ int make_model_size);
+static void free_array(cups_array_t *a);
+static void free_cache(void);
+static http_addrlist_t *get_interface_addresses(const char *ifname);
+static void list_device(snmp_cache_t *cache);
+static const char *password_cb(const char *prompt);
+static void probe_device(snmp_cache_t *device);
+static void read_snmp_conf(const char *address);
+static void read_snmp_response(int fd);
+static double run_time(void);
+static void scan_devices(int ipv4, int ipv6);
+static int try_connect(http_addr_t *addr, const char *addrname,
+ int port);
+static void update_cache(snmp_cache_t *device, const char *uri,
+ const char *id, const char *make_model);
+
+
+/*
+ * Local globals...
+ */
+
+static cups_array_t *Addresses = NULL;
+static cups_array_t *Communities = NULL;
+static cups_array_t *Devices = NULL;
+static int DebugLevel = 0;
+static const int DescriptionOID[] = { CUPS_OID_hrDeviceDescr, 1, -1 };
+static const int LocationOID[] = { CUPS_OID_sysLocation, 0, -1 };
+static const int DeviceTypeOID[] = { CUPS_OID_hrDeviceType, 1, -1 };
+static const int DeviceIdOID[] = { CUPS_OID_ppmPrinterIEEE1284DeviceId, 1, -1 };
+static const int UriOID[] = { CUPS_OID_ppmPortServiceNameOrURI, 1, 1, -1 };
+static const int LexmarkProductOID[] = { 1,3,6,1,4,1,641,2,1,2,1,2,1,-1 };
+static const int LexmarkProductOID2[] = { 1,3,6,1,4,1,674,10898,100,2,1,2,1,2,1,-1 };
+static const int LexmarkDeviceIdOID[] = { 1,3,6,1,4,1,641,2,1,2,1,3,1,-1 };
+static const int XeroxProductOID[] = { 1,3,6,1,4,1,128,2,1,3,1,2,0,-1 };
+static cups_array_t *DeviceURIs = NULL;
+static int HostNameLookups = 0;
+static int MaxRunTime = 120;
+static struct timeval StartTime;
+
+
+/*
+ * 'main()' - Discover printers via SNMP.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments (6 or 7) */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int ipv4, /* SNMP IPv4 socket */
+ ipv6; /* SNMP IPv6 socket */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Check command-line options...
+ */
+
+ if (argc > 2)
+ {
+ _cupsLangPuts(stderr, _("Usage: snmp [host-or-ip-address]"));
+ return (1);
+ }
+
+ /*
+ * Set the password callback for IPP operations...
+ */
+
+ cupsSetPasswordCB(password_cb);
+
+ /*
+ * Catch SIGALRM signals...
+ */
+
+#ifdef HAVE_SIGSET
+ sigset(SIGALRM, alarm_handler);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGALRM);
+ action.sa_handler = alarm_handler;
+ sigaction(SIGALRM, &action, NULL);
+#else
+ signal(SIGALRM, alarm_handler);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Open the SNMP socket...
+ */
+
+ if ((ipv4 = _cupsSNMPOpen(AF_INET)) < 0)
+ return (1);
+
+#ifdef AF_INET6
+ if ((ipv6 = _cupsSNMPOpen(AF_INET6)) < 0)
+ return (1);
+#else
+ ipv6 = -1;
+#endif /* AF_INET6 */
+
+ /*
+ * Read the configuration file and any cache data...
+ */
+
+ read_snmp_conf(argv[1]);
+
+ _cupsSNMPSetDebug(DebugLevel);
+
+ Devices = cupsArrayNew((cups_array_func_t)compare_cache, NULL);
+
+ /*
+ * Scan for devices...
+ */
+
+ scan_devices(ipv4, ipv6);
+
+ /*
+ * Close, free, and return with no errors...
+ */
+
+ _cupsSNMPClose(ipv4);
+ if (ipv6 >= 0)
+ _cupsSNMPClose(ipv6);
+
+ free_array(Addresses);
+ free_array(Communities);
+ free_cache();
+
+ return (0);
+}
+
+
+/*
+ * 'add_array()' - Add a string to an array.
+ */
+
+static char * /* O - New string */
+add_array(cups_array_t *a, /* I - Array */
+ const char *s) /* I - String to add */
+{
+ char *dups; /* New string */
+
+
+ dups = strdup(s);
+
+ cupsArrayAdd(a, dups);
+
+ return (dups);
+}
+
+
+/*
+ * 'add_cache()' - Add a cached device...
+ */
+
+static void
+add_cache(http_addr_t *addr, /* I - Device IP address */
+ const char *addrname, /* I - IP address or name string */
+ const char *uri, /* I - Device URI */
+ const char *id, /* I - 1284 device ID */
+ const char *make_and_model) /* I - Make and model */
+{
+ snmp_cache_t *temp; /* New device entry */
+
+
+ debug_printf("DEBUG: add_cache(addr=%p, addrname=\"%s\", uri=\"%s\", "
+ "id=\"%s\", make_and_model=\"%s\")\n",
+ addr, addrname, uri ? uri : "(null)", id ? id : "(null)",
+ make_and_model ? make_and_model : "(null)");
+
+ temp = calloc(1, sizeof(snmp_cache_t));
+ memcpy(&(temp->address), addr, sizeof(temp->address));
+
+ temp->addrname = strdup(addrname);
+
+ if (uri)
+ temp->uri = strdup(uri);
+
+ if (id)
+ temp->id = strdup(id);
+
+ if (make_and_model)
+ temp->make_and_model = strdup(make_and_model);
+
+ cupsArrayAdd(Devices, temp);
+
+ if (uri)
+ list_device(temp);
+}
+
+
+/*
+ * 'add_device_uri()' - Add a device URI to the cache.
+ *
+ * The value string is modified (chopped up) as needed.
+ */
+
+static device_uri_t * /* O - Device URI */
+add_device_uri(char *value) /* I - Value from snmp.conf */
+{
+ device_uri_t *device_uri; /* Device URI */
+ char *start; /* Start of value */
+
+
+ /*
+ * Allocate memory as needed...
+ */
+
+ if (!DeviceURIs)
+ DeviceURIs = cupsArrayNew(NULL, NULL);
+
+ if (!DeviceURIs)
+ return (NULL);
+
+ if ((device_uri = calloc(1, sizeof(device_uri_t))) == NULL)
+ return (NULL);
+
+ if ((device_uri->uris = cupsArrayNew(NULL, NULL)) == NULL)
+ {
+ free(device_uri);
+ return (NULL);
+ }
+
+ /*
+ * Scan the value string for the regular expression and URI(s)...
+ */
+
+ value ++; /* Skip leading " */
+
+ for (start = value; *value && *value != '\"'; value ++)
+ if (*value == '\\' && value[1])
+ _cups_strcpy(value, value + 1);
+
+ if (!*value)
+ {
+ fputs("ERROR: Missing end quote for DeviceURI!\n", stderr);
+
+ cupsArrayDelete(device_uri->uris);
+ free(device_uri);
+
+ return (NULL);
+ }
+
+ *value++ = '\0';
+
+ if (regcomp(&(device_uri->re), start, REG_EXTENDED | REG_ICASE))
+ {
+ fputs("ERROR: Bad regular expression for DeviceURI!\n", stderr);
+
+ cupsArrayDelete(device_uri->uris);
+ free(device_uri);
+
+ return (NULL);
+ }
+
+ while (*value)
+ {
+ while (isspace(*value & 255))
+ value ++;
+
+ if (!*value)
+ break;
+
+ for (start = value; *value && !isspace(*value & 255); value ++);
+
+ if (*value)
+ *value++ = '\0';
+
+ cupsArrayAdd(device_uri->uris, strdup(start));
+ }
+
+ /*
+ * Add the device URI to the list and return it...
+ */
+
+ cupsArrayAdd(DeviceURIs, device_uri);
+
+ return (device_uri);
+}
+
+
+/*
+ * 'alarm_handler()' - Handle alarm signals...
+ */
+
+static void
+alarm_handler(int sig) /* I - Signal number */
+{
+ /*
+ * Do nothing...
+ */
+
+ (void)sig;
+
+#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
+ signal(SIGALRM, alarm_handler);
+#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
+
+ if (DebugLevel)
+ write(2, "DEBUG: ALARM!\n", 14);
+}
+
+
+/*
+ * 'compare_cache()' - Compare two cache entries.
+ */
+
+static int /* O - Result of comparison */
+compare_cache(snmp_cache_t *a, /* I - First cache entry */
+ snmp_cache_t *b) /* I - Second cache entry */
+{
+ return (_cups_strcasecmp(a->addrname, b->addrname));
+}
+
+
+/*
+ * 'debug_printf()' - Display some debugging information.
+ */
+
+static void
+debug_printf(const char *format, /* I - Printf-style format string */
+ ...) /* I - Additional arguments as needed */
+{
+ va_list ap; /* Pointer to arguments */
+
+
+ if (!DebugLevel)
+ return;
+
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+}
+
+
+/*
+ * 'fix_make_model()' - Fix common problems in the make-and-model string.
+ */
+
+static void
+fix_make_model(
+ char *make_model, /* I - New make-and-model string */
+ const char *old_make_model, /* I - Old make-and-model string */
+ int make_model_size) /* I - Size of new string buffer */
+{
+ char *mmptr; /* Pointer into make-and-model string */
+
+
+ /*
+ * Fix some common problems with the make-and-model string so
+ * that printer driver detection works better...
+ */
+
+ if (!_cups_strncasecmp(old_make_model, "Hewlett-Packard", 15))
+ {
+ /*
+ * Strip leading Hewlett-Packard and hp prefixes and replace
+ * with a single HP manufacturer prefix...
+ */
+
+ mmptr = (char *)old_make_model + 15;
+
+ while (isspace(*mmptr & 255))
+ mmptr ++;
+
+ if (!_cups_strncasecmp(mmptr, "hp", 2))
+ {
+ mmptr += 2;
+
+ while (isspace(*mmptr & 255))
+ mmptr ++;
+ }
+
+ make_model[0] = 'H';
+ make_model[1] = 'P';
+ make_model[2] = ' ';
+ strlcpy(make_model + 3, mmptr, make_model_size - 3);
+ }
+ else if (!_cups_strncasecmp(old_make_model, "deskjet", 7))
+ snprintf(make_model, make_model_size, "HP DeskJet%s", old_make_model + 7);
+ else if (!_cups_strncasecmp(old_make_model, "officejet", 9))
+ snprintf(make_model, make_model_size, "HP OfficeJet%s", old_make_model + 9);
+ else if (!_cups_strncasecmp(old_make_model, "stylus_pro_", 11))
+ snprintf(make_model, make_model_size, "EPSON Stylus Pro %s",
+ old_make_model + 11);
+ else
+ strlcpy(make_model, old_make_model, make_model_size);
+
+ if ((mmptr = strstr(make_model, ", Inc.,")) != NULL)
+ {
+ /*
+ * Strip inc. from name, e.g. "Tektronix, Inc., Phaser 560"
+ * becomes "Tektronix Phaser 560"...
+ */
+
+ _cups_strcpy(mmptr, mmptr + 7);
+ }
+
+ if ((mmptr = strstr(make_model, " Network")) != NULL)
+ {
+ /*
+ * Drop unnecessary informational text, e.g. "Xerox DocuPrint N2025
+ * Network LaserJet - 2.12" becomes "Xerox DocuPrint N2025"...
+ */
+
+ *mmptr = '\0';
+ }
+
+ if ((mmptr = strchr(make_model, ',')) != NULL)
+ {
+ /*
+ * Drop anything after a trailing comma...
+ */
+
+ *mmptr = '\0';
+ }
+}
+
+
+/*
+ * 'free_array()' - Free an array of strings.
+ */
+
+static void
+free_array(cups_array_t *a) /* I - Array */
+{
+ char *s; /* Current string */
+
+
+ for (s = (char *)cupsArrayFirst(a); s; s = (char *)cupsArrayNext(a))
+ free(s);
+
+ cupsArrayDelete(a);
+}
+
+
+/*
+ * 'free_cache()' - Free the array of cached devices.
+ */
+
+static void
+free_cache(void)
+{
+ snmp_cache_t *cache; /* Cached device */
+
+
+ for (cache = (snmp_cache_t *)cupsArrayFirst(Devices);
+ cache;
+ cache = (snmp_cache_t *)cupsArrayNext(Devices))
+ {
+ free(cache->addrname);
+
+ if (cache->uri)
+ free(cache->uri);
+
+ if (cache->id)
+ free(cache->id);
+
+ if (cache->make_and_model)
+ free(cache->make_and_model);
+
+ free(cache);
+ }
+
+ cupsArrayDelete(Devices);
+ Devices = NULL;
+}
+
+
+/*
+ * 'get_interface_addresses()' - Get the broadcast address(es) associated
+ * with an interface.
+ */
+
+static http_addrlist_t * /* O - List of addresses */
+get_interface_addresses(
+ const char *ifname) /* I - Interface name */
+{
+ struct ifaddrs *addrs, /* Interface address list */
+ *addr; /* Current interface address */
+ http_addrlist_t *first, /* First address in list */
+ *last, /* Last address in list */
+ *current; /* Current address */
+
+
+ if (getifaddrs(&addrs) < 0)
+ return (NULL);
+
+ for (addr = addrs, first = NULL, last = NULL; addr; addr = addr->ifa_next)
+ if ((addr->ifa_flags & IFF_BROADCAST) && addr->ifa_broadaddr &&
+ addr->ifa_broadaddr->sa_family == AF_INET &&
+ (!ifname || !strcmp(ifname, addr->ifa_name)))
+ {
+ current = calloc(1, sizeof(http_addrlist_t));
+
+ memcpy(&(current->addr), addr->ifa_broadaddr,
+ sizeof(struct sockaddr_in));
+
+ if (!last)
+ first = current;
+ else
+ last->next = current;
+
+ last = current;
+ }
+
+ freeifaddrs(addrs);
+
+ return (first);
+}
+
+
+/*
+ * 'list_device()' - List a device we found...
+ */
+
+static void
+list_device(snmp_cache_t *cache) /* I - Cached device */
+{
+ if (cache->uri)
+ cupsBackendReport("network", cache->uri, cache->make_and_model,
+ cache->info, cache->id, cache->location);
+}
+
+
+/*
+ * 'password_cb()' - Handle authentication requests.
+ *
+ * All we do right now is return NULL, indicating that no authentication
+ * is possible.
+ */
+
+static const char * /* O - Password (NULL) */
+password_cb(const char *prompt) /* I - Prompt message */
+{
+ (void)prompt; /* Anti-compiler-warning-code */
+
+ return (NULL);
+}
+
+
+/*
+ * 'probe_device()' - Probe a device to discover whether it is a printer.
+ *
+ * TODO: Try using the Port Monitor MIB to discover the correct protocol
+ * to use - first need a commercially-available printer that supports
+ * it, though...
+ */
+
+static void
+probe_device(snmp_cache_t *device) /* I - Device */
+{
+ char uri[1024], /* Full device URI */
+ *uriptr, /* Pointer into URI */
+ *format; /* Format string for device */
+ device_uri_t *device_uri; /* Current DeviceURI match */
+
+
+ debug_printf("DEBUG: %.3f Probing %s...\n", run_time(), device->addrname);
+
+#ifdef __APPLE__
+ /*
+ * If the printer supports Bonjour/mDNS, don't report it from the SNMP backend.
+ */
+
+ if (!try_connect(&(device->address), device->addrname, 5353))
+ {
+ debug_printf("DEBUG: %s supports mDNS, not reporting!\n", device->addrname);
+ return;
+ }
+#endif /* __APPLE__ */
+
+ /*
+ * Lookup the device in the match table...
+ */
+
+ for (device_uri = (device_uri_t *)cupsArrayFirst(DeviceURIs);
+ device_uri;
+ device_uri = (device_uri_t *)cupsArrayNext(DeviceURIs))
+ if (device->make_and_model &&
+ !regexec(&(device_uri->re), device->make_and_model, 0, NULL, 0))
+ {
+ /*
+ * Found a match, add the URIs...
+ */
+
+ for (format = (char *)cupsArrayFirst(device_uri->uris);
+ format;
+ format = (char *)cupsArrayNext(device_uri->uris))
+ {
+ for (uriptr = uri; *format && uriptr < (uri + sizeof(uri) - 1);)
+ if (*format == '%' && format[1] == 's')
+ {
+ /*
+ * Insert hostname/address...
+ */
+
+ strlcpy(uriptr, device->addrname, sizeof(uri) - (uriptr - uri));
+ uriptr += strlen(uriptr);
+ format += 2;
+ }
+ else
+ *uriptr++ = *format++;
+
+ *uriptr = '\0';
+
+ update_cache(device, uri, NULL, NULL);
+ }
+
+ return;
+ }
+
+ /*
+ * Then try the standard ports...
+ */
+
+ if (!try_connect(&(device->address), device->addrname, 9100))
+ {
+ debug_printf("DEBUG: %s supports AppSocket!\n", device->addrname);
+
+ snprintf(uri, sizeof(uri), "socket://%s", device->addrname);
+ update_cache(device, uri, NULL, NULL);
+ }
+ else if (!try_connect(&(device->address), device->addrname, 515))
+ {
+ debug_printf("DEBUG: %s supports LPD!\n", device->addrname);
+
+ snprintf(uri, sizeof(uri), "lpd://%s/", device->addrname);
+ update_cache(device, uri, NULL, NULL);
+ }
+}
+
+
+/*
+ * 'read_snmp_conf()' - Read the snmp.conf file.
+ */
+
+static void
+read_snmp_conf(const char *address) /* I - Single address to probe */
+{
+ cups_file_t *fp; /* File pointer */
+ char filename[1024], /* Filename */
+ line[1024], /* Line from file */
+ *value; /* Value on line */
+ int linenum; /* Line number */
+ const char *cups_serverroot; /* CUPS_SERVERROOT env var */
+ const char *debug; /* CUPS_DEBUG_LEVEL env var */
+ const char *runtime; /* CUPS_MAX_RUN_TIME env var */
+
+
+ /*
+ * Initialize the global address and community lists...
+ */
+
+ Addresses = cupsArrayNew(NULL, NULL);
+ Communities = cupsArrayNew(NULL, NULL);
+
+ if (address)
+ add_array(Addresses, address);
+
+ if ((debug = getenv("CUPS_DEBUG_LEVEL")) != NULL)
+ DebugLevel = atoi(debug);
+
+ if ((runtime = getenv("CUPS_MAX_RUN_TIME")) != NULL)
+ MaxRunTime = atoi(runtime);
+
+ /*
+ * Find the snmp.conf file...
+ */
+
+ if ((cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL)
+ cups_serverroot = CUPS_SERVERROOT;
+
+ snprintf(filename, sizeof(filename), "%s/snmp.conf", cups_serverroot);
+
+ if ((fp = cupsFileOpen(filename, "r")) != NULL)
+ {
+ /*
+ * Read the snmp.conf file...
+ */
+
+ linenum = 0;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ if (!value)
+ fprintf(stderr, "ERROR: Missing value on line %d of %s!\n", linenum,
+ filename);
+ else if (!_cups_strcasecmp(line, "Address"))
+ {
+ if (!address)
+ add_array(Addresses, value);
+ }
+ else if (!_cups_strcasecmp(line, "Community"))
+ add_array(Communities, value);
+ else if (!_cups_strcasecmp(line, "DebugLevel"))
+ DebugLevel = atoi(value);
+ else if (!_cups_strcasecmp(line, "DeviceURI"))
+ {
+ if (*value != '\"')
+ fprintf(stderr,
+ "ERROR: Missing double quote for regular expression on "
+ "line %d of %s!\n", linenum, filename);
+ else
+ add_device_uri(value);
+ }
+ else if (!_cups_strcasecmp(line, "HostNameLookups"))
+ HostNameLookups = !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "yes") ||
+ !_cups_strcasecmp(value, "true") ||
+ !_cups_strcasecmp(value, "double");
+ else if (!_cups_strcasecmp(line, "MaxRunTime"))
+ MaxRunTime = atoi(value);
+ else
+ fprintf(stderr, "ERROR: Unknown directive %s on line %d of %s!\n",
+ line, linenum, filename);
+ }
+
+ cupsFileClose(fp);
+ }
+
+ /*
+ * Use defaults if parameters are undefined...
+ */
+
+ if (cupsArrayCount(Addresses) == 0)
+ {
+ /*
+ * If we have no addresses, exit immediately...
+ */
+
+ fprintf(stderr,
+ "DEBUG: No address specified and no Address line in %s...\n",
+ filename);
+ exit(0);
+ }
+
+ if (cupsArrayCount(Communities) == 0)
+ {
+ fputs("INFO: Using default SNMP Community public\n", stderr);
+ add_array(Communities, "public");
+ }
+}
+
+
+/*
+ * 'read_snmp_response()' - Read and parse a SNMP response...
+ */
+
+static void
+read_snmp_response(int fd) /* I - SNMP socket file descriptor */
+{
+ char addrname[256]; /* Source address name */
+ cups_snmp_t packet; /* Decoded packet */
+ snmp_cache_t key, /* Search key */
+ *device; /* Matching device */
+
+
+ /*
+ * Read the response data...
+ */
+
+ if (!_cupsSNMPRead(fd, &packet, -1.0))
+ {
+ fprintf(stderr, "ERROR: Unable to read data from socket: %s\n",
+ strerror(errno));
+ return;
+ }
+
+ if (HostNameLookups)
+ httpAddrLookup(&(packet.address), addrname, sizeof(addrname));
+ else
+ httpAddrString(&(packet.address), addrname, sizeof(addrname));
+
+ debug_printf("DEBUG: %.3f Received data from %s...\n", run_time(), addrname);
+
+ /*
+ * Look for the response status code in the SNMP message header...
+ */
+
+ if (packet.error)
+ {
+ fprintf(stderr, "ERROR: Bad SNMP packet from %s: %s\n", addrname,
+ packet.error);
+
+ return;
+ }
+
+ debug_printf("DEBUG: community=\"%s\"\n", packet.community);
+ debug_printf("DEBUG: request-id=%d\n", packet.request_id);
+ debug_printf("DEBUG: error-status=%d\n", packet.error_status);
+
+ if (packet.error_status)
+ return;
+
+ /*
+ * Find a matching device in the cache...
+ */
+
+ key.addrname = addrname;
+ device = (snmp_cache_t *)cupsArrayFind(Devices, &key);
+
+ /*
+ * Process the message...
+ */
+
+ switch (packet.request_id)
+ {
+ case DEVICE_TYPE :
+ /*
+ * Got the device type response...
+ */
+
+ if (device)
+ {
+ debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n",
+ addrname);
+ return;
+ }
+
+ /*
+ * Add the device and request the device data...
+ */
+
+ add_cache(&(packet.address), addrname, NULL, NULL, NULL);
+
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_DESCRIPTION, DescriptionOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_ID, DeviceIdOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_URI, UriOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_LOCATION, LocationOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_PRODUCT, LexmarkProductOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_PRODUCT, LexmarkProductOID2);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_ID, LexmarkDeviceIdOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_PRODUCT, XeroxProductOID);
+ break;
+
+ case DEVICE_DESCRIPTION :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING)
+ {
+ /*
+ * Update an existing cache entry...
+ */
+
+ char make_model[256]; /* Make and model */
+
+
+ if (strchr((char *)packet.object_value.string.bytes, ':') &&
+ strchr((char *)packet.object_value.string.bytes, ';'))
+ {
+ /*
+ * Description is the IEEE-1284 device ID...
+ */
+
+ if (!device->id)
+ device->id = strdup((char *)packet.object_value.string.bytes);
+
+ backendGetMakeModel((char *)packet.object_value.string.bytes,
+ make_model, sizeof(make_model));
+
+ if (device->info)
+ free(device->info);
+
+ device->info = strdup(make_model);
+ }
+ else
+ {
+ /*
+ * Description is plain text...
+ */
+
+ fix_make_model(make_model, (char *)packet.object_value.string.bytes,
+ sizeof(make_model));
+
+ if (device->info)
+ free(device->info);
+
+ device->info = strdup((char *)packet.object_value.string.bytes);
+ }
+
+ if (!device->make_and_model)
+ device->make_and_model = strdup(make_model);
+ }
+ break;
+
+ case DEVICE_ID :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+ (!device->id ||
+ strlen(device->id) < packet.object_value.string.num_bytes))
+ {
+ /*
+ * Update an existing cache entry...
+ */
+
+ char make_model[256]; /* Make and model */
+
+
+ if (device->id)
+ free(device->id);
+
+ device->id = strdup((char *)packet.object_value.string.bytes);
+
+ /*
+ * Convert the ID to a make and model string...
+ */
+
+ backendGetMakeModel((char *)packet.object_value.string.bytes,
+ make_model, sizeof(make_model));
+ if (device->make_and_model)
+ free(device->make_and_model);
+
+ device->make_and_model = strdup(make_model);
+ }
+ break;
+
+ case DEVICE_LOCATION :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+ !device->location)
+ device->location = strdup((char *)packet.object_value.string.bytes);
+ break;
+
+ case DEVICE_PRODUCT :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+ !device->id)
+ {
+ /*
+ * Update an existing cache entry...
+ */
+
+ if (!device->info)
+ device->info = strdup((char *)packet.object_value.string.bytes);
+
+ if (device->make_and_model)
+ free(device->make_and_model);
+
+ device->make_and_model = strdup((char *)packet.object_value.string.bytes);
+ }
+ break;
+
+ case DEVICE_URI :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+ !device->uri && packet.object_value.string.num_bytes > 0)
+ {
+ /*
+ * Update an existing cache entry...
+ */
+
+ if (!strncmp((char *)packet.object_value.string.bytes, "lpr:", 4))
+ {
+ /*
+ * We want "lpd://..." for the URI...
+ */
+
+ packet.object_value.string.bytes[2] = 'd';
+ }
+
+ device->uri = strdup((char *)packet.object_value.string.bytes);
+ }
+ break;
+ }
+}
+
+
+/*
+ * 'run_time()' - Return the total running time...
+ */
+
+static double /* O - Number of seconds */
+run_time(void)
+{
+ struct timeval curtime; /* Current time */
+
+
+ gettimeofday(&curtime, NULL);
+
+ return (curtime.tv_sec - StartTime.tv_sec +
+ 0.000001 * (curtime.tv_usec - StartTime.tv_usec));
+}
+
+
+/*
+ * 'scan_devices()' - Scan for devices using SNMP.
+ */
+
+static void
+scan_devices(int ipv4, /* I - SNMP IPv4 socket */
+ int ipv6) /* I - SNMP IPv6 socket */
+{
+ int fd, /* File descriptor for this address */
+ busy; /* Are we busy processing something? */
+ char *address, /* Current address */
+ *community; /* Current community */
+ fd_set input; /* Input set for select() */
+ struct timeval timeout; /* Timeout for select() */
+ time_t endtime; /* End time for scan */
+ http_addrlist_t *addrs, /* List of addresses */
+ *addr; /* Current address */
+ snmp_cache_t *device; /* Current device */
+ char temp[1024]; /* Temporary address string */
+
+
+ gettimeofday(&StartTime, NULL);
+
+ /*
+ * First send all of the broadcast queries...
+ */
+
+ for (address = (char *)cupsArrayFirst(Addresses);
+ address;
+ address = (char *)cupsArrayNext(Addresses))
+ {
+ if (!strcmp(address, "@LOCAL"))
+ addrs = get_interface_addresses(NULL);
+ else if (!strncmp(address, "@IF(", 4))
+ {
+ char ifname[255]; /* Interface name */
+
+ strlcpy(ifname, address + 4, sizeof(ifname));
+ if (ifname[0])
+ ifname[strlen(ifname) - 1] = '\0';
+
+ addrs = get_interface_addresses(ifname);
+ }
+ else
+ addrs = httpAddrGetList(address, AF_UNSPEC, NULL);
+
+ if (!addrs)
+ {
+ fprintf(stderr, "ERROR: Unable to scan \"%s\"!\n", address);
+ continue;
+ }
+
+ for (community = (char *)cupsArrayFirst(Communities);
+ community;
+ community = (char *)cupsArrayNext(Communities))
+ {
+ debug_printf("DEBUG: Scanning for devices in \"%s\" via \"%s\"...\n",
+ community, address);
+
+ for (addr = addrs; addr; addr = addr->next)
+ {
+#ifdef AF_INET6
+ if (_httpAddrFamily(&(addr->addr)) == AF_INET6)
+ fd = ipv6;
+ else
+#endif /* AF_INET6 */
+ fd = ipv4;
+
+ debug_printf("DEBUG: Sending get request to %s...\n",
+ httpAddrString(&(addr->addr), temp, sizeof(temp)));
+
+ _cupsSNMPWrite(fd, &(addr->addr), CUPS_SNMP_VERSION_1, community,
+ CUPS_ASN1_GET_REQUEST, DEVICE_TYPE, DeviceTypeOID);
+ }
+ }
+
+ httpAddrFreeList(addrs);
+ }
+
+ /*
+ * Then read any responses that come in over the next 3 seconds...
+ */
+
+ endtime = time(NULL) + MaxRunTime;
+
+ FD_ZERO(&input);
+
+ while (time(NULL) < endtime)
+ {
+ timeout.tv_sec = 2;
+ timeout.tv_usec = 0;
+
+ FD_SET(ipv4, &input);
+ if (ipv6 >= 0)
+ FD_SET(ipv6, &input);
+
+ fd = ipv4 > ipv6 ? ipv4 : ipv6;
+ if (select(fd + 1, &input, NULL, NULL, &timeout) < 0)
+ {
+ fprintf(stderr, "ERROR: %.3f select() for %d/%d failed: %s\n", run_time(),
+ ipv4, ipv6, strerror(errno));
+ break;
+ }
+
+ busy = 0;
+
+ if (FD_ISSET(ipv4, &input))
+ {
+ read_snmp_response(ipv4);
+ busy = 1;
+ }
+
+ if (ipv6 >= 0 && FD_ISSET(ipv6, &input))
+ {
+ read_snmp_response(ipv6);
+ busy = 1;
+ }
+
+ if (!busy)
+ {
+ /*
+ * List devices with complete information...
+ */
+
+ int sent_something = 0;
+
+ for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
+ device;
+ device = (snmp_cache_t *)cupsArrayNext(Devices))
+ if (!device->sent && device->info && device->make_and_model)
+ {
+ if (device->uri)
+ list_device(device);
+ else
+ probe_device(device);
+
+ device->sent = sent_something = 1;
+ }
+
+ if (!sent_something)
+ break;
+ }
+ }
+
+ debug_printf("DEBUG: %.3f Scan complete!\n", run_time());
+}
+
+
+/*
+ * 'try_connect()' - Try connecting on a port...
+ */
+
+static int /* O - 0 on success or -1 on error */
+try_connect(http_addr_t *addr, /* I - Socket address */
+ const char *addrname, /* I - Hostname or IP address */
+ int port) /* I - Port number */
+{
+ int fd; /* Socket */
+ int status; /* Connection status */
+
+
+ debug_printf("DEBUG: %.3f Trying %s://%s:%d...\n", run_time(),
+ port == 515 ? "lpd" : "socket", addrname, port);
+
+ if ((fd = socket(_httpAddrFamily(addr), SOCK_STREAM, 0)) < 0)
+ {
+ fprintf(stderr, "ERROR: Unable to create socket: %s\n",
+ strerror(errno));
+ return (-1);
+ }
+
+ _httpAddrSetPort(addr, port);
+
+ alarm(1);
+
+ status = connect(fd, (void *)addr, httpAddrLength(addr));
+
+ close(fd);
+ alarm(0);
+
+ return (status);
+}
+
+
+/*
+ * 'update_cache()' - Update a cached device...
+ */
+
+static void
+update_cache(snmp_cache_t *device, /* I - Device */
+ const char *uri, /* I - Device URI */
+ const char *id, /* I - Device ID */
+ const char *make_model) /* I - Device make and model */
+{
+ if (device->uri)
+ free(device->uri);
+
+ device->uri = strdup(uri);
+
+ if (id)
+ {
+ if (device->id)
+ free(device->id);
+
+ device->id = strdup(id);
+ }
+
+ if (make_model)
+ {
+ if (device->make_and_model)
+ free(device->make_and_model);
+
+ device->make_and_model = strdup(make_model);
+ }
+
+ list_device(device);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/snmp.txt b/backend/snmp.txt
new file mode 100644
index 000000000..77a38c498
--- /dev/null
+++ b/backend/snmp.txt
@@ -0,0 +1,172 @@
+snmp.txt - 2006-04-19
+---------------------
+
+This file lists the "interesting" bits from the command:
+
+ snmpwalk -v 1 -c public HOST .1
+
+for many network print servers and internal cards. It is mainly here
+for SNMP documentation and development purposes.
+
+
+AXIS 5600
+
+SNMPv2-MIB::sysDescr.0 = STRING: HP ETHERNET MULTI-ENVIRONMENT,ROM J.sp.00,JETDIRECT EX,JD28,EEPROM 6.16.5
+SNMPv2-MIB::sysName.0 = STRING:
+HOST-RESOURCES-MIB::hrDeviceType.1 = OID: HOST-RESOURCES-TYPES::hrDevicePrinter
+HOST-RESOURCES-MIB::hrDeviceType.2 = OID: HOST-RESOURCES-TYPES::hrDevicePrinter
+HOST-RESOURCES-MIB::hrDeviceType.3 = OID: HOST-RESOURCES-TYPES::hrDevicePrinter
+HOST-RESOURCES-MIB::hrDeviceDescr.1 = STRING: Hewlett-Packard hp LaserJet 3380
+HOST-RESOURCES-MIB::hrDeviceDescr.2 = STRING: Axis AXIS 5600
+HOST-RESOURCES-MIB::hrDeviceDescr.3 = STRING: Axis AXIS 5600
+HOST-RESOURCES-MIB::hrDeviceID.1 = OID: SNMPv2-SMI::zeroDotZero
+HOST-RESOURCES-MIB::hrDeviceID.2 = OID: SNMPv2-SMI::zeroDotZero
+HOST-RESOURCES-MIB::hrDeviceID.3 = OID: SNMPv2-SMI::zeroDotZero
+SNMPv2-SMI::enterprises.11.2.4.3.10.8.0 = STRING: "AXIS433AE8"
+SNMPv2-SMI::enterprises.368.2.3.2.601.0 = INTEGER: 9100
+SNMPv2-SMI::enterprises.368.2.3.2.602.0 = INTEGER: 9101
+SNMPv2-SMI::enterprises.368.2.3.2.603.0 = INTEGER: 9102
+SNMPv2-SMI::enterprises.368.2.3.10.901.0 = STRING: "AXIS433AE8"
+
+
+AXIS OfficeBasic
+
+SNMPv2-MIB::sysDescr.0 = STRING: AXIS OfficeBasic Parallel Network Print Server V6.43 Sep 4 2003
+HOST-RESOURCES-MIB::hrDeviceType.1 = OID: HOST-RESOURCES-TYPES::hrDevicePrinter
+HOST-RESOURCES-MIB::hrDeviceDescr.1 = STRING: EPSON Stylus Photo 870
+HOST-RESOURCES-MIB::hrDeviceID.1 = OID: SNMPv2-SMI::zeroDotZero
+
+
+DLink DP-301P+
+
+SNMPv2-MIB::sysDescr.0 = STRING: D-Link DP-301P+ Print Server
+
+
+Genicom ML280
+
+SNMPv2-MIB::sysDescr.0 = STRING: GENICOM microLaser 280
+SNMPv2-MIB::sysName.0 = STRING: PRQ_004F75
+HOST-RESOURCES-MIB::hrDeviceType.1 = OID: HOST-RESOURCES-TYPES::hrDevicePrinter
+HOST-RESOURCES-MIB::hrDeviceDescr.1 = STRING: MANUFACTURER:GENICOM;MODEL:microLaser 280;
+HOST-RESOURCES-MIB::hrDeviceID.1 = OID: SNMPv2-SMI::enterprises.3369.1.1.2.4
+
+
+EPSON Type-B Network Card
+
+SNMPv2-MIB::sysDescr.0 = STRING: EPSON Type-B 10Base-T/100Base-TX Print Server
+SNMPv2-MIB::sysName.0 = STRING: StylusPro7600-BB87A8
+HOST-RESOURCES-MIB::hrDeviceType.1 = OID: HOST-RESOURCES-TYPES::hrDevicePrinter
+HOST-RESOURCES-MIB::hrDeviceDescr.1 = STRING: EPSON Stylus Pro 7600
+HOST-RESOURCES-MIB::hrDeviceID.1 = OID: SNMPv2-SMI::enterprises.1248.1.2.1.22.69.109.117.108.97.116.101.83.116.121.108.117.115.32.80.114.111.32.55.54.48.48
+SNMPv2-SMI::enterprises.11.2.3.9.1.1.7.0 = STRING: "MFG:EPSON;CMD:ESCPL2,BDC;MDL:Stylus Pro 7600;CLS:PRINTER;DES:EPSON Stylus Pro 7600;"
+SNMPv2-SMI::enterprises.1248.1.2.2.1.1.1.1.1 = STRING: "MFG:EPSON;CMD:ESCPL2,BDC;MDL:Stylus Pro 7600;CLS:PRINTER;DES:EPSON Stylus Pro 7600;"
+
+
+EPSON Wireless 802.11b Print Server
+
+SNMPv2-MIB::sysDescr.0 = STRING: EPSON Wireless LAN Print Interface compatible with an HP JETDIRECT EX
+SNMPv2-MIB::sysName.0 = STRING: EAI_0F550B
+HOST-RESOURCES-MIB::hrDeviceType.1 = OID: HOST-RESOURCES-TYPES::hrDevicePrinter
+HOST-RESOURCES-MIB::hrDeviceDescr.1 = STRING:
+HOST-RESOURCES-MIB::hrDeviceID.1 = OID: SNMPv2-SMI::zeroDotZero
+
+
+HP JetDirect EX3plus
+
+SNMPv2-MIB::sysDescr.0 = STRING: HP ETHERNET MULTI-ENVIRONMENT,ROM D.04.03,JETDIRECT EX,JD26,EEPROM D.05.22
+SNMPv2-MIB::sysName.0 = STRING: NPID1EC0F
+
+
+HP LJ4000
+
+SNMPv2-MIB::sysDescr.0 = STRING: HP ETHERNET MULTI-ENVIRONMENT,ROM G.05.34,JETDIRECT,JD30,EEPROM G.08.32
+SNMPv2-MIB::sysName.0 = STRING:
+HOST-RESOURCES-MIB::hrDeviceType.1 = OID: HOST-RESOURCES-TYPES::hrDevicePrinter
+HOST-RESOURCES-MIB::hrDeviceDescr.1 = STRING: HP LaserJet 4000 Series
+HOST-RESOURCES-MIB::hrDeviceID.1 = OID: SNMPv2-SMI::enterprises.11.2.3.9.1.2.5
+
+
+HP CLJ4550
+
+SNMPv2-MIB::sysDescr.0 = STRING: HP ETHERNET MULTI-ENVIRONMENT,ROM L.20.07,JETDIRECT,JD84,EEPROM L.21.22,CIDATE 07/06/2001
+SNMPv2-MIB::sysName.0 = STRING: NPI02FDE7
+HOST-RESOURCES-MIB::hrDeviceDescr.1 = STRING: HP Color LaserJet 4550
+HOST-RESOURCES-MIB::hrDeviceDescr.2 = STRING: Hewlett-Packard Dynamic RAM Disk
+HOST-RESOURCES-MIB::hrDeviceID.1 = OID: SNMPv2-SMI::enterprises.11.2.3.9.1.2.14
+
+
+Lexmark C522
+
+SNMPv2-MIB::sysDescr.0 = STRING: Lexmark C522 version NS.NP.N212 kernel 2.6.6 All-N-1
+SNMPv2-MIB::sysName.0 = STRING: ET0004000D0CCA
+HOST-RESOURCES-MIB::hrDeviceType.1 = OID: HOST-RESOURCES-TYPES::hrDevicePrinter
+HOST-RESOURCES-MIB::hrDeviceType.2 = OID: HOST-RESOURCES-TYPES::hrDeviceNonVolatileMemory
+HOST-RESOURCES-MIB::hrDeviceType.3 = OID: HOST-RESOURCES-TYPES::hrDeviceProcessor
+HOST-RESOURCES-MIB::hrDeviceType.4 = OID: HOST-RESOURCES-TYPES::hrDeviceSerialPort
+HOST-RESOURCES-MIB::hrDeviceType.5 = OID: HOST-RESOURCES-TYPES::hrDeviceNetwork
+HOST-RESOURCES-MIB::hrDeviceDescr.1 = STRING: Lexmark C522 9421TTV LS.FA.P129
+HOST-RESOURCES-MIB::hrDeviceDescr.2 = STRING: Nonvolatile RAM
+HOST-RESOURCES-MIB::hrDeviceDescr.3 = STRING: IBM 750 Rev CXr
+HOST-RESOURCES-MIB::hrDeviceDescr.4 = STRING: USB Interface
+HOST-RESOURCES-MIB::hrDeviceDescr.5 = STRING: Network Interface
+HOST-RESOURCES-MIB::hrDeviceID.1 = OID: SNMPv2-SMI::zeroDotZero
+HOST-RESOURCES-MIB::hrDeviceID.2 = OID: SNMPv2-SMI::zeroDotZero
+HOST-RESOURCES-MIB::hrDeviceID.3 = OID: SNMPv2-SMI::zeroDotZero
+HOST-RESOURCES-MIB::hrDeviceID.4 = OID: SNMPv2-SMI::zeroDotZero
+HOST-RESOURCES-MIB::hrDeviceID.5 = OID: SNMPv2-SMI::enterprises.641.1
+SNMPv2-SMI::enterprises.641.2.1.2.1.2.1 = STRING: "Lexmark C522"
+SNMPv2-SMI::enterprises.641.2.1.2.1.3.1 = STRING: "MANUFACTURER:Lexmark International;COMMAND SET:;MODEL:Lexmark C522"
+
+
+Linksys EPSX3
+
+SNMPv2-MIB::sysDescr.0 = STRING: ETHERNET MULTI-ENVIRONMENT.ROM, JETDIRECT EX, EEPROM 6016
+
+
+NetGear PS113
+
+SNMPv2-MIB::sysDescr.0 = STRING: A SNMP proxy agent.
+
+
+Okidata C7200
+
+SNMPv2-MIB::sysDescr.0 = STRING: OkiLAN 6200e
+SNMPv2-MIB::sysName.0 = STRING: OKI7009715
+HOST-RESOURCES-MIB::hrDeviceType.1 = OID: HOST-RESOURCES-TYPES::hrDevicePrinter
+HOST-RESOURCES-MIB::hrDeviceType.2 = OID: HOST-RESOURCES-TYPES::hrDeviceNonVolat
+ileMemory
+HOST-RESOURCES-MIB::hrDeviceDescr.1 = STRING: C7200
+HOST-RESOURCES-MIB::hrDeviceDescr.2 = STRING: FLASH0
+HOST-RESOURCES-MIB::hrDeviceID.1 = OID: SNMPv2-SMI::enterprises.2001.1.1.1.1
+HOST-RESOURCES-MIB::hrDeviceID.2 = OID: SNMPv2-SMI::zeroDotZero
+SNMPv2-SMI::mib-2.43.14.1.1.3.1.1 = STRING: "IEEE 1284"
+SNMPv2-SMI::mib-2.43.14.1.1.3.1.2 = STRING: "EtherTalk Phase 2"
+SNMPv2-SMI::mib-2.43.14.1.1.3.1.3 = STRING: "LPD"
+SNMPv2-SMI::mib-2.43.14.1.1.3.1.4 = STRING: "Netware Rprinter"
+SNMPv2-SMI::mib-2.43.14.1.1.3.1.5 = STRING: "Netware Bindery or NDS Pserver"
+SNMPv2-SMI::mib-2.43.14.1.1.3.1.6 = STRING: "Raw TCP Port 9100"
+SNMPv2-SMI::mib-2.43.14.1.1.3.1.7 = STRING: "FTP"
+SNMPv2-SMI::mib-2.43.14.1.1.3.1.8 = STRING: "DLC/LLC"
+SNMPv2-SMI::enterprises.2001.1.1.1.1.1.3530.0 = STRING: "C7200"
+
+
+Xerox N2025
+
+SNMPv2-MIB::sysDescr.0 = STRING: Xerox DocuPrint N2025 Network Laser Printer - 2.12-02
+SNMPv2-MIB::sysName.0 = STRING:
+HOST-RESOURCES-MIB::hrDeviceType.1 = OID: HOST-RESOURCES-TYPES::hrDevicePrinter
+HOST-RESOURCES-MIB::hrDeviceType.2 = OID: HOST-RESOURCES-TYPES::hrDeviceParallelPort
+HOST-RESOURCES-MIB::hrDeviceType.3 = OID: HOST-RESOURCES-TYPES::hrDeviceNetwork
+HOST-RESOURCES-MIB::hrDeviceType.6 = OID: HOST-RESOURCES-TYPES::hrDeviceProcessor
+HOST-RESOURCES-MIB::hrDeviceType.7 = OID: HOST-RESOURCES-TYPES::hrDeviceOther
+HOST-RESOURCES-MIB::hrDeviceType.9 = OID: HOST-RESOURCES-TYPES::hrDeviceVolatileMemory
+HOST-RESOURCES-MIB::hrDeviceType.10 = OID: HOST-RESOURCES-TYPES::hrDeviceNonVolatileMemory
+HOST-RESOURCES-MIB::hrDeviceDescr.1 = STRING: Xerox DocuPrint N2025 Network Laser Printer - 2.12-02
+HOST-RESOURCES-MIB::hrDeviceDescr.2 = STRING: IEEE 1284 port
+HOST-RESOURCES-MIB::hrDeviceDescr.3 = STRING: Ethernet port
+HOST-RESOURCES-MIB::hrDeviceDescr.6 = STRING: Motorola Power PC
+HOST-RESOURCES-MIB::hrDeviceDescr.7 = STRING: USB Port
+HOST-RESOURCES-MIB::hrDeviceDescr.9 = STRING: RAM Memory
+HOST-RESOURCES-MIB::hrDeviceDescr.10 = STRING: ROM Memory
+HOST-RESOURCES-MIB::hrDeviceID.1 = OID: SNMPv2-SMI::enterprises.253.8.62.1.3.2.17.1
+
diff --git a/backend/socket.c b/backend/socket.c
new file mode 100644
index 000000000..39c31fb09
--- /dev/null
+++ b/backend/socket.c
@@ -0,0 +1,527 @@
+/*
+ * "$Id$"
+ *
+ * AppSocket backend for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "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.
+ * wait_bc() - Wait for back-channel data...
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <cups/http-private.h>
+#include "backend-private.h"
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+# include <winsock.h>
+#else
+# include <unistd.h>
+# include <fcntl.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#endif /* WIN32 */
+
+
+/*
+ * Local functions...
+ */
+
+static int wait_bc(int device_fd, int secs);
+
+
+/*
+ * '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 */
+{
+ const char *device_uri; /* Device URI */
+ char scheme[255], /* Scheme in URI */
+ hostname[1024], /* Hostname */
+ username[255], /* Username info (not used) */
+ resource[1024], /* Resource info (not used) */
+ *options, /* Pointer to options */
+ *name, /* Name of option */
+ *value, /* Value of option */
+ sep; /* Option separator */
+ int print_fd; /* Print file */
+ int copies; /* Number of copies to print */
+ time_t start_time; /* Time of first connect */
+#ifdef __APPLE__
+ time_t current_time, /* Current time */
+ wait_time; /* Time to wait before shutting down socket */
+#endif /* __APPLE__ */
+ int contimeout; /* Connection timeout */
+ int waiteof; /* Wait for end-of-file? */
+ int port; /* Port number */
+ char portname[255]; /* Port name */
+ int delay; /* Delay for retries... */
+ int device_fd; /* AppSocket */
+ int error; /* Error code (if any) */
+ http_addrlist_t *addrlist, /* Address list */
+ *addr; /* Connected address */
+ char addrname[256]; /* Address name */
+ int snmp_fd, /* SNMP socket */
+ start_count, /* Page count via SNMP at start */
+ page_count, /* Page count via SNMP */
+ have_supplies; /* Printer supports supply levels? */
+ ssize_t bytes = 0, /* Initial bytes read */
+ tbytes; /* Total number of bytes written */
+ char buffer[1024]; /* Initial print 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);
+
+ /*
+ * 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)
+ {
+ printf("network socket \"Unknown\" \"%s\"\n",
+ _cupsLangString(cupsLangDefault(), _("AppSocket/HP JetDirect")));
+ return (CUPS_BACKEND_OK);
+ }
+ else if (argc < 6 || argc > 7)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options [file]"),
+ 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)
+ {
+ print_fd = 0;
+ copies = 1;
+ }
+ else
+ {
+ /*
+ * Try to open the print file...
+ */
+
+ if ((print_fd = open(argv[6], O_RDONLY)) < 0)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ copies = atoi(argv[4]);
+ }
+
+ /*
+ * Extract the hostname and port number from the URI...
+ */
+
+ while ((device_uri = cupsBackendDeviceURI(argv)) == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer."));
+ sleep(10);
+
+ if (getenv("CLASS") != NULL)
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme),
+ username, sizeof(username), hostname, sizeof(hostname), &port,
+ resource, sizeof(resource));
+
+ if (port == 0)
+ port = 9100; /* Default to HP JetDirect/Tektronix PhaserShare */
+
+ /*
+ * Get options, if any...
+ */
+
+ waiteof = 1;
+ contimeout = 7 * 24 * 60 * 60;
+
+ 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...
+ */
+
+ name = options;
+
+ while (*options && *options != '=' && *options != '+' && *options != '&')
+ options ++;
+
+ if ((sep = *options) != '\0')
+ *options++ = '\0';
+
+ if (sep == '=')
+ {
+ /*
+ * Get the value...
+ */
+
+ value = options;
+
+ while (*options && *options != '+' && *options != '&')
+ options ++;
+
+ if (*options)
+ *options++ = '\0';
+ }
+ else
+ value = (char *)"";
+
+ /*
+ * Process the option...
+ */
+
+ if (!_cups_strcasecmp(name, "waiteof"))
+ {
+ /*
+ * Set the wait-for-eof value...
+ */
+
+ waiteof = !value[0] || !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "true");
+ }
+ else if (!_cups_strcasecmp(name, "contimeout"))
+ {
+ /*
+ * Set the connection timeout...
+ */
+
+ if (atoi(value) > 0)
+ contimeout = atoi(value);
+ }
+ }
+ }
+
+ /*
+ * Then try finding the remote host...
+ */
+
+ start_time = time(NULL);
+
+ sprintf(portname, "%d", port);
+
+ fputs("STATE: +connecting-to-device\n", stderr);
+ fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname);
+
+ while ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Unable to locate printer \"%s\"."), hostname);
+ sleep(10);
+
+ if (getenv("CLASS") != NULL)
+ {
+ fputs("STATE: -connecting-to-device\n", stderr);
+ return (CUPS_BACKEND_STOP);
+ }
+ }
+
+ /*
+ * See if the printer supports SNMP...
+ */
+
+ if ((snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family)) >= 0)
+ {
+ have_supplies = !backendSNMPSupplies(snmp_fd, &(addrlist->addr),
+ &start_count, NULL);
+ }
+ else
+ have_supplies = start_count = 0;
+
+ /*
+ * Wait for data from the filter...
+ */
+
+ if (print_fd == 0)
+ {
+ if (!backendWaitLoop(snmp_fd, &(addrlist->addr), 1, backendNetworkSideCB))
+ return (CUPS_BACKEND_OK);
+ else if ((bytes = read(0, buffer, sizeof(buffer))) <= 0)
+ return (CUPS_BACKEND_OK);
+ }
+
+ /*
+ * Connect to the printer...
+ */
+
+ fprintf(stderr, "DEBUG: Connecting to %s:%d\n", hostname, port);
+ _cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer."));
+
+ for (delay = 5;;)
+ {
+ if ((addr = httpAddrConnect(addrlist, &device_fd)) == NULL)
+ {
+ error = errno;
+ device_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.
+ */
+
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Unable to contact printer, queuing on next "
+ "printer in class."));
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(error));
+
+ if (error == ECONNREFUSED || error == EHOSTDOWN ||
+ error == EHOSTUNREACH)
+ {
+ if (contimeout && (time(NULL) - start_time) > contimeout)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The printer is not responding."));
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ switch (error)
+ {
+ case EHOSTDOWN :
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("The printer may not exist or "
+ "is unavailable at this time."));
+ break;
+
+ case EHOSTUNREACH :
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("The printer is unreachable at this "
+ "time."));
+ break;
+
+ case ECONNREFUSED :
+ default :
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("The printer is busy."));
+ break;
+ }
+
+ sleep(delay);
+
+ if (delay < 30)
+ delay += 5;
+ }
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The printer is not responding."));
+ sleep(30);
+ }
+ }
+ else
+ break;
+ }
+
+ fputs("STATE: -connecting-to-device\n", stderr);
+ _cupsLangPrintFilter(stderr, "INFO", _("Connected to printer."));
+
+ fprintf(stderr, "DEBUG: Connected to %s:%d...\n",
+ httpAddrString(&(addr->addr), addrname, sizeof(addrname)),
+ _httpAddrPort(&(addr->addr)));
+
+ /*
+ * Print everything...
+ */
+
+ tbytes = 0;
+
+ if (bytes > 0)
+ tbytes += write(device_fd, buffer, bytes);
+
+ while (copies > 0 && tbytes >= 0)
+ {
+ copies --;
+
+ if (print_fd != 0)
+ {
+ fputs("PAGE: 1 1\n", stderr);
+ lseek(print_fd, 0, SEEK_SET);
+ }
+
+ tbytes = backendRunLoop(print_fd, device_fd, snmp_fd, &(addrlist->addr), 1,
+ 0, backendNetworkSideCB);
+
+ if (print_fd != 0 && tbytes >= 0)
+ _cupsLangPrintFilter(stderr, "INFO", _("Print file sent."));
+ }
+
+#ifdef __APPLE__
+ /*
+ * Wait up to 5 seconds to get any pending back-channel data...
+ */
+
+ wait_time = time(NULL) + 5;
+ while (wait_time >= time(&current_time))
+ if (wait_bc(device_fd, wait_time - current_time) <= 0)
+ break;
+#endif /* __APPLE__ */
+
+ if (waiteof)
+ {
+ /*
+ * Shutdown the socket and wait for the other end to finish...
+ */
+
+ _cupsLangPrintFilter(stderr, "INFO", _("Waiting for printer to finish."));
+
+ shutdown(device_fd, 1);
+
+ while (wait_bc(device_fd, 90) > 0);
+ }
+
+ /*
+ * Collect the final page count as needed...
+ */
+
+ if (have_supplies &&
+ !backendSNMPSupplies(snmp_fd, &(addrlist->addr), &page_count, NULL) &&
+ page_count > start_count)
+ fprintf(stderr, "PAGE: total %d\n", page_count - start_count);
+
+ /*
+ * Close the socket connection...
+ */
+
+ close(device_fd);
+
+ httpAddrFreeList(addrlist);
+
+ /*
+ * Close the input file and return...
+ */
+
+ if (print_fd != 0)
+ close(print_fd);
+
+ _cupsLangPrintFilter(stderr, "INFO", _("Ready to print."));
+
+ return (CUPS_BACKEND_OK);
+}
+
+
+/*
+ * 'wait_bc()' - Wait for back-channel data...
+ */
+
+static int /* O - # bytes read or -1 on error */
+wait_bc(int device_fd, /* I - Socket */
+ int secs) /* I - Seconds to wait */
+{
+ struct timeval timeout; /* Timeout for select() */
+ fd_set input; /* Input set for select() */
+ ssize_t bytes; /* Number of back-channel bytes read */
+ char buffer[1024]; /* Back-channel buffer */
+
+
+ /*
+ * Wait up to "secs" seconds for backchannel data...
+ */
+
+ timeout.tv_sec = secs;
+ timeout.tv_usec = 0;
+
+ FD_ZERO(&input);
+ FD_SET(device_fd, &input);
+
+ if (select(device_fd + 1, &input, NULL, NULL, &timeout) > 0)
+ {
+ /*
+ * Grab the data coming back and spit it out to stderr...
+ */
+
+ if ((bytes = read(device_fd, buffer, sizeof(buffer))) > 0)
+ {
+ fprintf(stderr, "DEBUG: Received %d bytes of back-channel data\n",
+ (int)bytes);
+ cupsBackChannelWrite(buffer, bytes, 1.0);
+ }
+
+ return (bytes);
+ }
+ else
+ return (-1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/test1284.c b/backend/test1284.c
new file mode 100644
index 000000000..49bef87ee
--- /dev/null
+++ b/backend/test1284.c
@@ -0,0 +1,84 @@
+/*
+ * "$Id$"
+ *
+ * IEEE-1284 support functions test program for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Test the device-ID functions.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <cups/string-private.h>
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+# include <fcntl.h>
+#endif /* WIN32 */
+
+#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]);
+
+ backendGetDeviceID(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$".
+ */
diff --git a/backend/testbackend.c b/backend/testbackend.c
new file mode 100644
index 000000000..2c2d5beaf
--- /dev/null
+++ b/backend/testbackend.c
@@ -0,0 +1,651 @@
+/*
+ * "$Id$"
+ *
+ * Backend test program for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Run the named backend.
+ * sigterm_handler() - Flag when we get SIGTERM.
+ * usage() - Show usage information.
+ * walk_cb() - Show results of cupsSideChannelSNMPWalk...
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <cups/string-private.h>
+#include <cups/cups.h>
+#include <cups/sidechannel.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+
+/*
+ * Local globals...
+ */
+
+static int job_canceled = 0;
+
+
+/*
+ * Local functions...
+ */
+
+static void sigterm_handler(int sig);
+static void usage(void);
+static void walk_cb(const char *oid, const char *data, int datalen,
+ void *context);
+
+
+/*
+ * 'main()' - Run the named backend.
+ *
+ * Usage:
+ *
+ * betest [-s] [-t] device-uri job-id user title copies options [file]
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int first_arg, /* First argument for backend */
+ do_cancel = 0, /* Simulate a cancel-job via SIGTERM */
+ do_ps = 0, /* Do PostScript query+test? */
+ do_pcl = 0, /* Do PCL query+test? */
+ do_side_tests = 0, /* Test side-channel ops? */
+ do_trickle = 0, /* Trickle data to backend */
+ do_walk = 0, /* Do OID lookup (0) or walking (1) */
+ show_log = 0; /* Show log messages from backends? */
+ const char *oid = ".1.3.6.1.2.1.43.10.2.1.4.1.1";
+ /* OID to lookup or walk */
+ char scheme[255], /* Scheme in URI == backend */
+ backend[1024]; /* Backend path */
+ const char *serverbin; /* CUPS_SERVERBIN environment variable */
+ int fd, /* Temporary file descriptor */
+ back_fds[2], /* Back-channel pipe */
+ side_fds[2], /* Side-channel socket */
+ data_fds[2], /* Data pipe */
+ back_pid = -1, /* Backend process ID */
+ data_pid = -1, /* Trickle process ID */
+ pid, /* Process ID */
+ status; /* Exit status */
+
+
+ /*
+ * See if we have side-channel tests to do...
+ */
+
+ for (first_arg = 1;
+ argv[first_arg] && argv[first_arg][0] == '-';
+ first_arg ++)
+ if (!strcmp(argv[first_arg], "-d"))
+ show_log = 1;
+ else if (!strcmp(argv[first_arg], "-cancel"))
+ do_cancel = 1;
+ else if (!strcmp(argv[first_arg], "-pcl"))
+ do_pcl = 1;
+ else if (!strcmp(argv[first_arg], "-ps"))
+ do_ps = 1;
+ else if (!strcmp(argv[first_arg], "-s"))
+ do_side_tests = 1;
+ else if (!strcmp(argv[first_arg], "-t"))
+ do_trickle = 1;
+ else if (!strcmp(argv[first_arg], "-get") && (first_arg + 1) < argc)
+ {
+ first_arg ++;
+
+ do_side_tests = 1;
+ oid = argv[first_arg];
+ }
+ else if (!strcmp(argv[first_arg], "-walk") && (first_arg + 1) < argc)
+ {
+ first_arg ++;
+
+ do_side_tests = 1;
+ do_walk = 1;
+ oid = argv[first_arg];
+ }
+ else
+ usage();
+
+ argc -= first_arg;
+ if (argc < 6 || argc > 7 || (argc == 7 && do_trickle))
+ usage();
+
+ /*
+ * Extract the scheme from the device-uri - that's the program we want to
+ * execute.
+ */
+
+ if (sscanf(argv[first_arg], "%254[^:]", scheme) != 1)
+ {
+ fputs("testbackend: Bad device-uri - no colon!\n", stderr);
+ return (1);
+ }
+
+ if (!access(scheme, X_OK))
+ strlcpy(backend, scheme, sizeof(backend));
+ else
+ {
+ if ((serverbin = getenv("CUPS_SERVERBIN")) == NULL)
+ serverbin = CUPS_SERVERBIN;
+
+ snprintf(backend, sizeof(backend), "%s/backend/%s", serverbin, scheme);
+ if (access(backend, X_OK))
+ {
+ fprintf(stderr, "testbackend: Unknown device scheme \"%s\"!\n", scheme);
+ return (1);
+ }
+ }
+
+ /*
+ * Create the back-channel pipe and side-channel socket...
+ */
+
+ open("/dev/null", O_WRONLY); /* Make sure fd 3 and 4 are used */
+ open("/dev/null", O_WRONLY);
+
+ pipe(back_fds);
+ fcntl(back_fds[0], F_SETFL, fcntl(back_fds[0], F_GETFL) | O_NONBLOCK);
+ fcntl(back_fds[1], F_SETFL, fcntl(back_fds[1], F_GETFL) | O_NONBLOCK);
+
+ socketpair(AF_LOCAL, SOCK_STREAM, 0, side_fds);
+ fcntl(side_fds[0], F_SETFL, fcntl(side_fds[0], F_GETFL) | O_NONBLOCK);
+ fcntl(side_fds[1], F_SETFL, fcntl(side_fds[1], F_GETFL) | O_NONBLOCK);
+
+ /*
+ * Execute the trickle process as needed...
+ */
+
+ if (do_trickle || do_pcl || do_ps || do_cancel)
+ {
+ pipe(data_fds);
+
+ signal(SIGTERM, sigterm_handler);
+
+ if ((data_pid = fork()) == 0)
+ {
+ /*
+ * Trickle/query child comes here. Rearrange file descriptors so that
+ * FD 1, 3, and 4 point to the backend...
+ */
+
+ if ((fd = open("/dev/null", O_RDONLY)) != 0)
+ {
+ dup2(fd, 0);
+ close(fd);
+ }
+
+ if (data_fds[1] != 1)
+ {
+ dup2(data_fds[1], 1);
+ close(data_fds[1]);
+ }
+ close(data_fds[0]);
+
+ if (back_fds[0] != 3)
+ {
+ dup2(back_fds[0], 3);
+ close(back_fds[0]);
+ }
+ close(back_fds[1]);
+
+ if (side_fds[0] != 4)
+ {
+ dup2(side_fds[0], 4);
+ close(side_fds[0]);
+ }
+ close(side_fds[1]);
+
+ if (do_trickle)
+ {
+ /*
+ * Write 10 spaces, 1 per second...
+ */
+
+ int i; /* Looping var */
+
+ for (i = 0; i < 10; i ++)
+ {
+ write(1, " ", 1);
+ sleep(1);
+ }
+ }
+ else if (do_cancel)
+ {
+ /*
+ * Write PS or PCL lines until we see SIGTERM...
+ */
+
+ int line = 0, page = 0; /* Current line and page */
+ ssize_t bytes; /* Number of bytes of response data */
+ char buffer[1024]; /* Output buffer */
+
+
+ if (do_pcl)
+ write(1, "\033E", 2);
+ else
+ write(1, "%!\n/Courier findfont 12 scalefont setfont 0 setgray\n", 52);
+
+ while (!job_canceled)
+ {
+ if (line == 0)
+ {
+ page ++;
+
+ if (do_pcl)
+ snprintf(buffer, sizeof(buffer), "PCL Page %d\r\n\r\n", page);
+ else
+ snprintf(buffer, sizeof(buffer),
+ "18 732 moveto (PS Page %d) show\n", page);
+
+ write(1, buffer, strlen(buffer));
+ }
+
+ line ++;
+
+ if (do_pcl)
+ snprintf(buffer, sizeof(buffer), "Line %d\r\n", line);
+ else
+ snprintf(buffer, sizeof(buffer), "18 %d moveto (Line %d) show\n",
+ 720 - line * 12, line);
+
+ write(1, buffer, strlen(buffer));
+
+ if (line >= 55)
+ {
+ /*
+ * Eject after 55 lines...
+ */
+
+ line = 0;
+ if (do_pcl)
+ write(1, "\014", 1);
+ else
+ write(1, "showpage\n", 9);
+ }
+
+ /*
+ * Check for back-channel data...
+ */
+
+ if ((bytes = cupsBackChannelRead(buffer, sizeof(buffer), 0)) > 0)
+ write(2, buffer, bytes);
+
+ /*
+ * Throttle output to ~100hz...
+ */
+
+ usleep(10000);
+ }
+
+ /*
+ * Eject current page with info...
+ */
+
+ if (do_pcl)
+ snprintf(buffer, sizeof(buffer),
+ "Canceled on line %d of page %d\r\n\014\033E", line, page);
+ else
+ snprintf(buffer, sizeof(buffer),
+ "\n18 %d moveto (Canceled on line %d of page %d)\nshowpage\n",
+ 720 - line * 12, line, page);
+
+ write(1, buffer, strlen(buffer));
+
+ /*
+ * See if we get any back-channel data...
+ */
+
+ while ((bytes = cupsBackChannelRead(buffer, sizeof(buffer), 5.0)) > 0)
+ write(2, buffer, bytes);
+
+ exit(0);
+ }
+ else
+ {
+ /*
+ * Do PS or PCL query + test pages.
+ */
+
+ char buffer[1024]; /* Buffer for response data */
+ ssize_t bytes; /* Number of bytes of response data */
+ double timeout; /* Timeout */
+ const char *data; /* Data to send */
+ static const char *pcl_data = /* PCL data */
+ "\033%-12345X@PJL\r\n"
+ "@PJL JOB NAME = \"Hello, World!\"\r\n"
+ "@PJL INFO USTATUS\r\n"
+ "@PJL ENTER LANGUAGE = PCL\r\n"
+ "\033E"
+ "Hello, World!\n"
+ "\014"
+ "\033%-12345X@PJL\r\n"
+ "@PJL EOJ NAME=\"Hello, World!\"\r\n"
+ "\033%-12345X";
+ static const char *ps_data = /* PostScript data */
+ "%!\n"
+ "save\n"
+ "product = flush\n"
+ "currentpagedevice /PageSize get aload pop\n"
+ "2 copy gt {exch} if\n"
+ "(Unknown)\n"
+ "19 dict\n"
+ "dup [612 792] (Letter) put\n"
+ "dup [612 1008] (Legal) put\n"
+ "dup [612 935] (w612h935) put\n"
+ "dup [522 756] (Executive) put\n"
+ "dup [595 842] (A4) put\n"
+ "dup [420 595] (A5) put\n"
+ "dup [499 709] (ISOB5) put\n"
+ "dup [516 728] (B5) put\n"
+ "dup [612 936] (w612h936) put\n"
+ "dup [284 419] (Postcard) put\n"
+ "dup [419.5 567] (DoublePostcard) put\n"
+ "dup [558 774] (w558h774) put\n"
+ "dup [553 765] (w553h765) put\n"
+ "dup [522 737] (w522h737) put\n"
+ "dup [499 709] (EnvISOB5) put\n"
+ "dup [297 684] (Env10) put\n"
+ "dup [459 649] (EnvC5) put\n"
+ "dup [312 624] (EnvDL) put\n"
+ "dup [279 540] (EnvMonarch) put\n"
+ "{ exch aload pop 4 index sub abs 5 le exch\n"
+ " 5 index sub abs 5 le and\n"
+ " {exch pop exit} {pop} ifelse\n"
+ "} bind forall\n"
+ "= flush pop pop\n"
+ "/Courier findfont 12 scalefont setfont\n"
+ "0 setgray 36 720 moveto (Hello, ) show product show (!) show\n"
+ "showpage\n"
+ "restore\n"
+ "\004";
+
+
+ if (do_pcl)
+ data = pcl_data;
+ else
+ data = ps_data;
+
+ write(1, data, strlen(data));
+ write(2, "DEBUG: START\n", 13);
+ timeout = 60.0;
+ while ((bytes = cupsBackChannelRead(buffer, sizeof(buffer),
+ timeout)) > 0)
+ {
+ write(2, buffer, bytes);
+ timeout = 5.0;
+ }
+ write(2, "\nDEBUG: END\n", 12);
+ }
+
+ exit(0);
+ }
+ else if (data_pid < 0)
+ {
+ perror("testbackend: Unable to fork");
+ return (1);
+ }
+ }
+ else
+ data_fds[0] = data_fds[1] = -1;
+
+ /*
+ * Execute the backend...
+ */
+
+ if ((back_pid = fork()) == 0)
+ {
+ /*
+ * Child comes here...
+ */
+
+ if (do_trickle || do_ps || do_pcl || do_cancel)
+ {
+ if (data_fds[0] != 0)
+ {
+ dup2(data_fds[0], 0);
+ close(data_fds[0]);
+ }
+ close(data_fds[1]);
+ }
+
+ if (!show_log)
+ {
+ if ((fd = open("/dev/null", O_WRONLY)) != 2)
+ {
+ dup2(fd, 2);
+ close(fd);
+ }
+ }
+
+ if (back_fds[1] != 3)
+ {
+ dup2(back_fds[1], 3);
+ close(back_fds[0]);
+ }
+ close(back_fds[1]);
+
+ if (side_fds[1] != 4)
+ {
+ dup2(side_fds[1], 4);
+ close(side_fds[0]);
+ }
+ close(side_fds[1]);
+
+ execv(backend, argv + first_arg);
+ fprintf(stderr, "testbackend: Unable to execute \"%s\": %s\n", backend,
+ strerror(errno));
+ return (errno);
+ }
+ else if (back_pid < 0)
+ {
+ perror("testbackend: Unable to fork");
+ return (1);
+ }
+
+ /*
+ * Parent comes here, setup back and side channel file descriptors...
+ */
+
+ if (do_trickle || do_ps || do_pcl || do_cancel)
+ {
+ close(data_fds[0]);
+ close(data_fds[1]);
+ }
+
+ if (back_fds[0] != 3)
+ {
+ dup2(back_fds[0], 3);
+ close(back_fds[0]);
+ }
+ close(back_fds[1]);
+
+ if (side_fds[0] != 4)
+ {
+ dup2(side_fds[0], 4);
+ close(side_fds[0]);
+ }
+ close(side_fds[1]);
+
+ /*
+ * Do side-channel tests as needed, then wait for the backend...
+ */
+
+ if (do_side_tests)
+ {
+ int length; /* Length of buffer */
+ char buffer[2049]; /* Buffer for reponse */
+ cups_sc_status_t scstatus; /* Status of side-channel command */
+ static const char * const statuses[] =
+ {
+ "CUPS_SC_STATUS_NONE", /* No status */
+ "CUPS_SC_STATUS_OK", /* Operation succeeded */
+ "CUPS_SC_STATUS_IO_ERROR", /* An I/O error occurred */
+ "CUPS_SC_STATUS_TIMEOUT", /* The backend did not respond */
+ "CUPS_SC_STATUS_NO_RESPONSE", /* The device did not respond */
+ "CUPS_SC_STATUS_BAD_MESSAGE", /* The command/response message was invalid */
+ "CUPS_SC_STATUS_TOO_BIG", /* Response too big */
+ "CUPS_SC_STATUS_NOT_IMPLEMENTED" /* Command not implemented */
+ };
+
+
+ sleep(2);
+
+ length = 0;
+ scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_DRAIN_OUTPUT, buffer,
+ &length, 60.0);
+ printf("CUPS_SC_CMD_DRAIN_OUTPUT returned %s\n", statuses[scstatus]);
+
+ length = 1;
+ scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_BIDI, buffer,
+ &length, 5.0);
+ printf("CUPS_SC_CMD_GET_BIDI returned %s, %d\n", statuses[scstatus], buffer[0]);
+
+ length = sizeof(buffer) - 1;
+ scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_DEVICE_ID, buffer,
+ &length, 5.0);
+ buffer[length] = '\0';
+ printf("CUPS_SC_CMD_GET_DEVICE_ID returned %s, \"%s\"\n",
+ statuses[scstatus], buffer);
+
+ length = 1;
+ scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_GET_STATE, buffer,
+ &length, 5.0);
+ printf("CUPS_SC_CMD_GET_STATE returned %s, %02X\n", statuses[scstatus],
+ buffer[0] & 255);
+
+ if (do_walk)
+ {
+ /*
+ * Walk the OID tree...
+ */
+
+ scstatus = cupsSideChannelSNMPWalk(oid, 5.0, walk_cb, NULL);
+ printf("CUPS_SC_CMD_SNMP_WALK returned %s\n", statuses[scstatus]);
+ }
+ else
+ {
+ /*
+ * Lookup the same OID twice...
+ */
+
+ length = sizeof(buffer);
+ scstatus = cupsSideChannelSNMPGet(oid, buffer, &length, 5.0);
+ printf("CUPS_SC_CMD_SNMP_GET %s returned %s, %s\n", oid,
+ statuses[scstatus], buffer);
+
+ length = sizeof(buffer);
+ scstatus = cupsSideChannelSNMPGet(oid, buffer, &length, 5.0);
+ printf("CUPS_SC_CMD_SNMP_GET %s returned %s, %s\n", oid,
+ statuses[scstatus], buffer);
+ }
+
+ length = 0;
+ scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_SOFT_RESET, buffer,
+ &length, 5.0);
+ printf("CUPS_SC_CMD_SOFT_RESET returned %s\n", statuses[scstatus]);
+ }
+
+ if (do_cancel)
+ {
+ sleep(1);
+ kill(data_pid, SIGTERM);
+ kill(back_pid, SIGTERM);
+ }
+
+ while ((pid = wait(&status)) > 0)
+ {
+ if (status)
+ {
+ if (WIFEXITED(status))
+ printf("%s exited with status %d!\n",
+ pid == back_pid ? backend : "test",
+ WEXITSTATUS(status));
+ else
+ printf("%s crashed with signal %d!\n",
+ pid == back_pid ? backend : "test",
+ WTERMSIG(status));
+ }
+ }
+
+ /*
+ * Exit accordingly...
+ */
+
+ return (status != 0);
+}
+
+
+/*
+ * 'sigterm_handler()' - Flag when we get SIGTERM.
+ */
+
+static void
+sigterm_handler(int sig) /* I - Signal */
+{
+ (void)sig;
+
+ job_canceled = 1;
+}
+
+
+/*
+ * 'usage()' - Show usage information.
+ */
+
+static void
+usage(void)
+{
+ puts("Usage: testbackend [-cancel] [-d] [-ps | -pcl] [-s [-oid OID] "
+ "[-walk OID]] [-t] device-uri job-id user title copies options [file]");
+ puts("");
+ puts("Options:");
+ puts(" -cancel Simulate a canceled print job after 2 seconds.");
+ puts(" -d Show log messages from backend.");
+ puts(" -oid OID Lookup the specified SNMP OID.");
+ puts(" (.1.3.6.1.2.1.43.10.2.1.4.1.1 is a good one for printers)");
+ puts(" -pcl Send PCL+PJL query and test page to backend.");
+ puts(" -ps Send PostScript query and test page to backend.");
+ puts(" -s Do side-channel + SNMP tests.");
+ puts(" -t Send spaces slowly to backend ('trickle').");
+ puts(" -walk OID Walk the specified SNMP OID.");
+ puts(" (.1.3.6.1.2.1.43 is a good one for printers)");
+
+ exit(1);
+}
+
+
+/*
+ * 'walk_cb()' - Show results of cupsSideChannelSNMPWalk...
+ */
+
+static void
+walk_cb(const char *oid, /* I - OID */
+ const char *data, /* I - Data */
+ int datalen, /* I - Length of data */
+ void *context) /* I - Context (unused) */
+{
+ printf("CUPS_SC_CMD_SNMP_WALK %s=%s (%d bytes)\n", oid, data, datalen);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/testsupplies.c b/backend/testsupplies.c
new file mode 100644
index 000000000..6cbdf8091
--- /dev/null
+++ b/backend/testsupplies.c
@@ -0,0 +1,83 @@
+/*
+ * "$Id$"
+ *
+ * SNMP supplies test program for CUPS.
+ *
+ * Copyright 2008-2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Show the supplies state of a printer.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "backend-private.h"
+
+
+/*
+ * 'main()' - Show the supplies state of a printer.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ http_addrlist_t *host; /* Host addresses */
+ int snmp_fd; /* SNMP socket */
+ int page_count, /* Current page count */
+ printer_state; /* Current printer state */
+
+
+ if (argc != 2)
+ {
+ puts("Usage: testsupplies ip-or-hostname");
+ return (1);
+ }
+
+ if ((host = httpAddrGetList(argv[1], AF_UNSPEC, "9100")) == NULL)
+ {
+ perror(argv[1]);
+ return (1);
+ }
+
+ if ((snmp_fd = _cupsSNMPOpen(host->addr.addr.sa_family)) < 0)
+ {
+ perror(argv[1]);
+ return (1);
+ }
+
+ for (;;)
+ {
+ fputs("backendSNMPSupplies: ", stdout);
+
+ if (backendSNMPSupplies(snmp_fd, &(host->addr), &page_count,
+ &printer_state))
+ {
+ puts("FAIL");
+ return (1);
+ }
+
+ printf("backendSNMPSupplies: %s (page_count=%d, printer_state=%d)\n",
+ page_count < 0 || printer_state < CUPS_TC_other ||
+ printer_state > CUPS_TC_warmup ? "FAIL" : "PASS",
+ page_count, printer_state);
+
+ sleep(5);
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/usb-darwin.c b/backend/usb-darwin.c
new file mode 100644
index 000000000..8ec680563
--- /dev/null
+++ b/backend/usb-darwin.c
@@ -0,0 +1,2297 @@
+/*
+* "$Id$"
+*
+* Copyright 2005-2011 Apple 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:
+*
+ * list_devices() - List all USB devices.
+ * print_device() - Print a file to a USB device.
+ * read_thread() - Thread to read the backchannel data on.
+ * sidechannel_thread() - Handle side-channel requests.
+ * iterate_printers() - Iterate over all the printers.
+ * device_added() - Device added notifier.
+ * list_device_cb() - list_device iterator callback.
+ * find_device_cb() - print_device iterator callback.
+ * status_timer_cb() - Status timer callback.
+ * copy_deviceinfo() - Copy strings from the 1284 device ID.
+ * release_deviceinfo() - Release deviceinfo strings.
+ * load_classdriver() - Load a classdriver.
+ * unload_classdriver() - Unload a classdriver.
+ * load_printerdriver() - Load vendor's classdriver.
+ * registry_open() - Open a connection to the printer.
+ * registry_close() - Close the connection to the printer.
+ * copy_deviceid() - Copy the 1284 device id string.
+ * copy_devicestring() - Copy the 1284 device id string.
+ * copy_value_for_key() - Copy value string associated with a key.
+ * cfstr_create_trim() - Create CFString and trim whitespace characters.
+ * parse_options() - Parse URI options.
+ * sigterm_handler() - SIGTERM handler.
+ * next_line() - Find the next line in a buffer.
+ * parse_pserror() - Scan the backchannel data for postscript errors.
+ * soft_reset() - Send a soft reset to the device.
+ * get_device_id() - Return IEEE-1284 device ID.
+*/
+
+/*
+ * Include necessary headers.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <libgen.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/mach_time.h>
+#include <cups/debug-private.h>
+#include <cups/file-private.h>
+#include <cups/sidechannel.h>
+#include <cups/language-private.h>
+#include "backend-private.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOCFPlugIn.h>
+
+#include <spawn.h>
+#include <pthread.h>
+
+extern char **environ;
+
+
+/*
+ * DEBUG_WRITES, if defined, causes the backend to write data to the printer in
+ * 512 byte increments, up to 8192 bytes, to make debugging with a USB bus
+ * analyzer easier.
+ */
+
+#define DEBUG_WRITES 0
+
+/*
+ * WAIT_EOF_DELAY is number of seconds we'll wait for responses from
+ * the printer after we've finished sending all the data
+ */
+#define WAIT_EOF_DELAY 7
+#define WAIT_SIDE_DELAY 3
+#define DEFAULT_TIMEOUT 5000L
+
+#define USB_INTERFACE_KIND CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID190)
+#define kUSBLanguageEnglish 0x409
+
+#define PRINTER_POLLING_INTERVAL 5 /* seconds */
+#define INITIAL_LOG_INTERVAL PRINTER_POLLING_INTERVAL
+#define SUBSEQUENT_LOG_INTERVAL 3 * INITIAL_LOG_INTERVAL
+
+#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 kUSBClassDriverProperty CFSTR("USB Printing Class")
+
+#define kUSBGenericTOPrinterClassDriver CFSTR("/System/Library/Printers/Libraries/USBGenericPrintingClass.plugin")
+#define kUSBPrinterClassDeviceNotOpen -9664 /*kPMInvalidIOMContext*/
+
+
+/*
+ * Section 5.3 USB Printing Class spec
+ */
+#define kUSBPrintingSubclass 1
+#define kUSBPrintingProtocolNoOpen 0
+#define kUSBPrintingProtocolUnidirectional 1
+#define kUSBPrintingProtocolBidirectional 2
+
+typedef IOUSBInterfaceInterface190 **printer_interface_t;
+
+typedef struct iodevice_request_s /**** Device request ****/
+{
+ UInt8 requestType;
+ UInt8 request;
+ UInt16 value;
+ UInt16 index;
+ UInt16 length;
+ void *buffer;
+} iodevice_request_t;
+
+typedef union /**** Centronics status byte ****/
+{
+ char b;
+ struct
+ {
+ unsigned reserved0:2;
+ unsigned paperError:1;
+ unsigned select:1;
+ unsigned notError:1;
+ unsigned reserved1:3;
+ } status;
+} centronics_status_t;
+
+typedef struct classdriver_s /**** g.classdriver context ****/
+{
+ IUNKNOWN_C_GUTS;
+ CFPlugInRef plugin; /* release plugin */
+ IUnknownVTbl **factory; /* Factory */
+ void *vendorReference; /* vendor class specific usage */
+ UInt32 location; /* unique location in bus topology */
+ UInt8 interfaceNumber; /* Interface number */
+ UInt16 vendorID; /* Vendor id */
+ UInt16 productID; /* Product id */
+ printer_interface_t interface; /* identify the device to IOKit */
+ UInt8 outpipe; /* mandatory bulkOut pipe */
+ UInt8 inpipe; /* optional bulkIn pipe */
+
+ /* general class requests */
+ kern_return_t (*DeviceRequest)(struct classdriver_s **printer, iodevice_request_t *iorequest, UInt16 timeout);
+ kern_return_t (*GetString)(struct classdriver_s **printer, UInt8 whichString, UInt16 language, UInt16 timeout, CFStringRef *result);
+
+ /* standard printer class requests */
+ kern_return_t (*SoftReset)(struct classdriver_s **printer, UInt16 timeout);
+ kern_return_t (*GetCentronicsStatus)(struct classdriver_s **printer, centronics_status_t *result, UInt16 timeout);
+ kern_return_t (*GetDeviceID)(struct classdriver_s **printer, CFStringRef *devid, UInt16 timeout);
+
+ /* standard bulk device requests */
+ kern_return_t (*ReadPipe)(struct classdriver_s **printer, UInt8 *buffer, UInt32 *count);
+ kern_return_t (*WritePipe)(struct classdriver_s **printer, UInt8 *buffer, UInt32 *count, Boolean eoj);
+
+ /* interface requests */
+ kern_return_t (*Open)(struct classdriver_s **printer, UInt32 location, UInt8 protocol);
+ kern_return_t (*Abort)(struct classdriver_s **printer);
+ kern_return_t (*Close)(struct classdriver_s **printer);
+
+ /* initialize and terminate */
+ kern_return_t (*Initialize)(struct classdriver_s **printer, struct classdriver_s **baseclass);
+ kern_return_t (*Terminate)(struct classdriver_s **printer);
+
+} classdriver_t;
+
+typedef Boolean (*iterator_callback_t)(void *refcon, io_service_t obj);
+
+typedef struct iterator_reference_s /**** Iterator reference data */
+{
+ iterator_callback_t callback;
+ void *userdata;
+ Boolean keepRunning;
+} iterator_reference_t;
+
+typedef struct globals_s
+{
+ io_service_t printer_obj;
+ classdriver_t **classdriver;
+
+ pthread_mutex_t read_thread_mutex;
+ pthread_cond_t read_thread_cond;
+ int read_thread_stop;
+ int read_thread_done;
+
+ pthread_mutex_t readwrite_lock_mutex;
+ pthread_cond_t readwrite_lock_cond;
+ int readwrite_lock;
+
+ CFStringRef make;
+ CFStringRef model;
+ CFStringRef serial;
+ UInt32 location;
+ UInt8 interfaceNum;
+
+ CFRunLoopTimerRef status_timer;
+
+ int print_fd; /* File descriptor to print */
+ ssize_t print_bytes; /* Print bytes read */
+#if DEBUG_WRITES
+ ssize_t debug_bytes; /* Current bytes to read */
+#endif /* DEBUG_WRITES */
+
+ Boolean wait_eof;
+ int drain_output; /* Drain all pending output */
+ int bidi_flag; /* 0=unidirectional, 1=bidirectional */
+
+ pthread_mutex_t sidechannel_thread_mutex;
+ pthread_cond_t sidechannel_thread_cond;
+ int sidechannel_thread_stop;
+ int sidechannel_thread_done;
+} globals_t;
+
+
+/*
+ * Globals...
+ */
+
+globals_t g = { 0 }; /* Globals */
+
+
+/*
+ * Local functions...
+ */
+
+static Boolean find_device_cb(void *refcon, io_service_t obj);
+static Boolean list_device_cb(void *refcon, io_service_t obj);
+static CFStringRef cfstr_create_trim(const char *cstr);
+static CFStringRef copy_value_for_key(CFStringRef deviceID, CFStringRef *keys);
+static kern_return_t load_classdriver(CFStringRef driverPath, printer_interface_t interface, classdriver_t ***printerDriver);
+static kern_return_t load_printerdriver(CFStringRef *driverBundlePath);
+static kern_return_t registry_close(void);
+static kern_return_t registry_open(CFStringRef *driverBundlePath);
+static kern_return_t unload_classdriver(classdriver_t ***classdriver);
+static OSStatus copy_deviceid(classdriver_t **printer, CFStringRef *deviceID);
+static void *read_thread(void *reference);
+static void *sidechannel_thread(void *reference);
+static void copy_deviceinfo(CFStringRef deviceIDString, CFStringRef *make, CFStringRef *model, CFStringRef *serial);
+static void copy_devicestring(io_service_t usbInterface, CFStringRef *deviceID, UInt32 *deviceLocation, UInt8 *interfaceNum);
+static void device_added(void *userdata, io_iterator_t iterator);
+static void get_device_id(cups_sc_status_t *status, char *data, int *datalen);
+static void iterate_printers(iterator_callback_t callBack, void *userdata);
+static void parse_options(char *options, char *serial, int serial_size, UInt32 *location, Boolean *wait_eof);
+static void release_deviceinfo(CFStringRef *make, CFStringRef *model, CFStringRef *serial);
+static void setup_cfLanguage(void);
+static void soft_reset(void);
+static void status_timer_cb(CFRunLoopTimerRef timer, void *info);
+
+#if defined(__i386__) || defined(__x86_64__)
+static pid_t child_pid; /* Child PID */
+static void run_legacy_backend(int argc, char *argv[], int fd); /* Starts child backend process running as a ppc executable */
+#endif /* __i386__ || __x86_64__ */
+static void sigterm_handler(int sig); /* SIGTERM handler */
+
+#ifdef PARSE_PS_ERRORS
+static const char *next_line (const char *buffer);
+static void parse_pserror (char *sockBuffer, int len);
+#endif /* PARSE_PS_ERRORS */
+
+#pragma mark -
+
+/*
+ * 'list_devices()' - List all USB devices.
+ */
+
+void list_devices()
+{
+ iterate_printers(list_device_cb, NULL);
+}
+
+
+/*
+ * '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 */
+ char *options, /* I - Device options/serial number */
+ int print_fd, /* I - File descriptor to print */
+ int copies, /* I - Copies to print */
+ int argc, /* I - Number of command-line arguments (6 or 7) */
+ char *argv[]) /* I - Command-line arguments */
+{
+ char serial[1024]; /* Serial number buffer */
+ OSStatus status; /* Function results */
+ IOReturn iostatus; /* Current IO status */
+ pthread_t read_thread_id, /* Read thread */
+ sidechannel_thread_id;/* Side-channel thread */
+ int have_sidechannel = 0; /* Was the side-channel thread started? */
+ struct stat sidechannel_info; /* Side-channel file descriptor info */
+ char print_buffer[8192], /* Print data buffer */
+ *print_ptr; /* Pointer into print data buffer */
+ UInt32 location; /* Unique location in bus topology */
+ fd_set input_set; /* Input set for select() */
+ CFStringRef driverBundlePath; /* Class driver path */
+ int countdown, /* Logging interval */
+ nfds; /* Number of file descriptors */
+ ssize_t total_bytes; /* Total bytes written */
+ UInt32 bytes; /* Bytes written */
+ struct timeval *timeout, /* Timeout pointer */
+ tv; /* Time value */
+ struct timespec cond_timeout; /* pthread condition timeout */
+
+
+ (void)uri;
+
+ /*
+ * See if the side-channel descriptor is valid...
+ */
+
+ have_sidechannel = !fstat(CUPS_SC_FD, &sidechannel_info) &&
+ S_ISSOCK(sidechannel_info.st_mode);
+
+ /*
+ * Localize using CoreFoundation...
+ */
+
+ setup_cfLanguage();
+
+ parse_options(options, serial, sizeof(serial), &location, &g.wait_eof);
+
+ if (resource[0] == '/')
+ resource++;
+
+ g.print_fd = print_fd;
+ g.make = cfstr_create_trim(hostname);
+ g.model = cfstr_create_trim(resource);
+ g.serial = cfstr_create_trim(serial);
+ g.location = location;
+
+ if (!g.make || !g.model)
+ {
+ fprintf(stderr, "DEBUG: Fatal USB error.\n");
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("There was an unrecoverable USB error."));
+
+ if (!g.make)
+ fputs("DEBUG: USB make string is NULL\n", stderr);
+ if (!g.model)
+ fputs("DEBUG: USB model string is NULL\n", stderr);
+
+ return (CUPS_BACKEND_STOP);
+ }
+
+ fputs("STATE: +connecting-to-device\n", stderr);
+
+ countdown = INITIAL_LOG_INTERVAL;
+
+ do
+ {
+ if (g.printer_obj)
+ {
+ IOObjectRelease(g.printer_obj);
+ unload_classdriver(&g.classdriver);
+ g.printer_obj = 0x0;
+ g.classdriver = 0x0;
+ }
+
+ fprintf(stderr, "DEBUG: Looking for '%s %s'\n", hostname, resource);
+
+ iterate_printers(find_device_cb, NULL);
+
+ fputs("DEBUG: Opening connection\n", stderr);
+
+ driverBundlePath = NULL;
+
+ status = registry_open(&driverBundlePath);
+
+#if defined(__i386__) || defined(__x86_64__)
+ /*
+ * If we were unable to load the class drivers for this printer it's
+ * probably because they're ppc or i386. In this case try to run this
+ * backend as i386 or ppc executables so we can use them...
+ */
+ if (status == -2)
+ {
+ run_legacy_backend(argc, argv, print_fd);
+ /* Never returns here */
+ }
+#endif /* __i386__ || __x86_64__ */
+
+ if (status == -2)
+ {
+ /*
+ * If we still were unable to load the class drivers for this printer log
+ * the error and stop the queue...
+ */
+
+ if (driverBundlePath == NULL || !CFStringGetCString(driverBundlePath, print_buffer, sizeof(print_buffer), kCFStringEncodingUTF8))
+ strlcpy(print_buffer, "USB class driver", sizeof(print_buffer));
+
+ fputs("STATE: +apple-missing-usbclassdriver-error\n", stderr);
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("There was an unrecoverable USB error."));
+ fprintf(stderr, "DEBUG: Could not load %s\n", print_buffer);
+
+ if (driverBundlePath)
+ CFRelease(driverBundlePath);
+
+ return (CUPS_BACKEND_STOP);
+ }
+
+ if (driverBundlePath)
+ CFRelease(driverBundlePath);
+
+ if (status != noErr)
+ {
+ sleep(PRINTER_POLLING_INTERVAL);
+ countdown -= PRINTER_POLLING_INTERVAL;
+ if (countdown <= 0)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Waiting for printer to become available."));
+ fprintf(stderr, "DEBUG: USB printer status: 0x%08x\n", (int)status);
+ countdown = SUBSEQUENT_LOG_INTERVAL; /* subsequent log entries, every 15 seconds */
+ }
+ }
+ } while (status != noErr);
+
+ fputs("STATE: -connecting-to-device\n", stderr);
+
+ /*
+ * 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 (!print_fd)
+ {
+ struct sigaction action; /* POSIX signal action */
+
+
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+ }
+
+ /*
+ * Start the side channel thread if the descriptor is valid...
+ */
+
+ pthread_mutex_init(&g.readwrite_lock_mutex, NULL);
+ pthread_cond_init(&g.readwrite_lock_cond, NULL);
+ g.readwrite_lock = 1;
+
+ if (have_sidechannel)
+ {
+ g.sidechannel_thread_stop = 0;
+ g.sidechannel_thread_done = 0;
+
+ pthread_cond_init(&g.sidechannel_thread_cond, NULL);
+ pthread_mutex_init(&g.sidechannel_thread_mutex, NULL);
+
+ if (pthread_create(&sidechannel_thread_id, NULL, sidechannel_thread, NULL))
+ {
+ fprintf(stderr, "DEBUG: Fatal USB error.\n");
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("There was an unrecoverable USB error."));
+ fputs("DEBUG: Couldn't create side-channel thread\n", stderr);
+ registry_close();
+ return (CUPS_BACKEND_STOP);
+ }
+ }
+
+ /*
+ * Get the read thread going...
+ */
+
+ g.read_thread_stop = 0;
+ g.read_thread_done = 0;
+
+ pthread_cond_init(&g.read_thread_cond, NULL);
+ pthread_mutex_init(&g.read_thread_mutex, NULL);
+
+ if (pthread_create(&read_thread_id, NULL, read_thread, NULL))
+ {
+ fprintf(stderr, "DEBUG: Fatal USB error.\n");
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("There was an unrecoverable USB error."));
+ fputs("DEBUG: Couldn't create read thread\n", stderr);
+ registry_close();
+ return (CUPS_BACKEND_STOP);
+ }
+
+ /*
+ * The main thread sends the print file...
+ */
+
+ g.drain_output = 0;
+ g.print_bytes = 0;
+ total_bytes = 0;
+ print_ptr = print_buffer;
+
+ while (status == noErr && copies-- > 0)
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("Sending data to printer."));
+
+ if (print_fd != STDIN_FILENO)
+ {
+ fputs("PAGE: 1 1\n", stderr);
+ lseek(print_fd, 0, SEEK_SET);
+ }
+
+ while (status == noErr)
+ {
+ FD_ZERO(&input_set);
+
+ if (!g.print_bytes)
+ FD_SET(print_fd, &input_set);
+
+ /*
+ * Calculate select timeout...
+ * If we have data waiting to send timeout is 100ms.
+ * else if we're draining print_fd timeout is 0.
+ * else we're waiting forever...
+ */
+
+ if (g.print_bytes)
+ {
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000; /* 100ms */
+ timeout = &tv;
+ }
+ else if (g.drain_output)
+ {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ timeout = &tv;
+ }
+ else
+ timeout = NULL;
+
+ /*
+ * I/O is unlocked around select...
+ */
+
+ pthread_mutex_lock(&g.readwrite_lock_mutex);
+ g.readwrite_lock = 0;
+ pthread_cond_signal(&g.readwrite_lock_cond);
+ pthread_mutex_unlock(&g.readwrite_lock_mutex);
+
+ nfds = select(print_fd + 1, &input_set, NULL, NULL, timeout);
+
+ /*
+ * Reacquire the lock...
+ */
+
+ pthread_mutex_lock(&g.readwrite_lock_mutex);
+ while (g.readwrite_lock)
+ pthread_cond_wait(&g.readwrite_lock_cond, &g.readwrite_lock_mutex);
+ g.readwrite_lock = 1;
+ pthread_mutex_unlock(&g.readwrite_lock_mutex);
+
+ if (nfds < 0)
+ {
+ if (errno == EINTR && total_bytes == 0)
+ {
+ fputs("DEBUG: Received an interrupt before any bytes were "
+ "written, aborting\n", stderr);
+ registry_close();
+ return (CUPS_BACKEND_OK);
+ }
+ else if (errno != EAGAIN && errno != EINTR)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to read print data."));
+ perror("DEBUG: select");
+ registry_close();
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+
+ /*
+ * If drain output has finished send a response...
+ */
+
+ if (g.drain_output && !nfds && !g.print_bytes)
+ {
+ /* Send a response... */
+ cupsSideChannelWrite(CUPS_SC_CMD_DRAIN_OUTPUT, CUPS_SC_STATUS_OK, NULL, 0, 1.0);
+ g.drain_output = 0;
+ }
+
+ /*
+ * Check if we have print data ready...
+ */
+
+ if (FD_ISSET(print_fd, &input_set))
+ {
+#if DEBUG_WRITES
+ g.debug_bytes += 512;
+ if (g.debug_bytes > sizeof(print_buffer))
+ g.debug_bytes = 512;
+
+ g.print_bytes = read(print_fd, print_buffer, g.debug_bytes);
+
+#else
+ g.print_bytes = read(print_fd, print_buffer, sizeof(print_buffer));
+#endif /* DEBUG_WRITES */
+
+ if (g.print_bytes < 0)
+ {
+ /*
+ * Read error - bail if we don't see EAGAIN or EINTR...
+ */
+
+ if (errno != EAGAIN && errno != EINTR)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to read print data."));
+ perror("DEBUG: read");
+ registry_close();
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ g.print_bytes = 0;
+ }
+ else if (g.print_bytes == 0)
+ {
+ /*
+ * End of file, break out of the loop...
+ */
+
+ break;
+ }
+
+ print_ptr = print_buffer;
+
+ fprintf(stderr, "DEBUG: Read %d bytes of print data...\n",
+ (int)g.print_bytes);
+ }
+
+ if (g.print_bytes)
+ {
+ bytes = g.print_bytes;
+ iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
+
+ /*
+ * Ignore timeout errors, but retain the number of bytes written to
+ * avoid sending duplicate data (<rdar://problem/6254911>)...
+ */
+
+ if (iostatus == kIOUSBTransactionTimeout)
+ {
+ fputs("DEBUG: Got USB transaction timeout during write\n", stderr);
+ iostatus = 0;
+ }
+
+ /*
+ * If we've stalled, retry the write...
+ */
+
+ else if (iostatus == kIOUSBPipeStalled)
+ {
+ fputs("DEBUG: Got USB pipe stalled during write\n", stderr);
+
+ bytes = g.print_bytes;
+ iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
+ }
+
+ /*
+ * Retry a write after an aborted write since we probably just got
+ * SIGTERM (<rdar://problem/6860126>)...
+ */
+
+ else if (iostatus == kIOReturnAborted)
+ {
+ fputs("DEBUG: Got USB return aborted during write\n", stderr);
+
+ IOReturn err = (*g.classdriver)->Abort(g.classdriver);
+ fprintf(stderr, "DEBUG: USB class driver Abort returned %x\n", err);
+
+#if DEBUG_WRITES
+ sleep(5);
+#endif /* DEBUG_WRITES */
+
+ bytes = g.print_bytes;
+ iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
+ }
+
+ if (iostatus)
+ {
+ /*
+ * Write error - bail if we don't see an error we can retry...
+ */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to send data to printer."));
+ fprintf(stderr, "DEBUG: USB class driver WritePipe returned %x\n",
+ iostatus);
+
+ IOReturn err = (*g.classdriver)->Abort(g.classdriver);
+ fprintf(stderr, "DEBUG: USB class driver Abort returned %x\n",
+ err);
+
+ status = CUPS_BACKEND_FAILED;
+ break;
+ }
+ else if (bytes > 0)
+ {
+ fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n", (int)bytes);
+
+ g.print_bytes -= bytes;
+ print_ptr += bytes;
+ total_bytes += bytes;
+ }
+ }
+
+ if (print_fd != 0 && status == noErr)
+ fprintf(stderr, "DEBUG: Sending print file, %lld bytes...\n",
+ (off_t)total_bytes);
+ }
+ }
+
+ fprintf(stderr, "DEBUG: Sent %lld bytes...\n", (off_t)total_bytes);
+
+ if (!print_fd)
+ {
+ /*
+ * Re-enable the SIGTERM handler so pthread_kill() will work...
+ */
+
+ struct sigaction action; /* POSIX signal action */
+
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGTERM);
+ action.sa_handler = sigterm_handler;
+ sigaction(SIGTERM, &action, NULL);
+ }
+
+ /*
+ * Wait for the side channel thread to exit...
+ */
+
+ if (have_sidechannel)
+ {
+ close(CUPS_SC_FD);
+ pthread_mutex_lock(&g.readwrite_lock_mutex);
+ g.readwrite_lock = 0;
+ pthread_cond_signal(&g.readwrite_lock_cond);
+ pthread_mutex_unlock(&g.readwrite_lock_mutex);
+
+ g.sidechannel_thread_stop = 1;
+ pthread_mutex_lock(&g.sidechannel_thread_mutex);
+
+ if (!g.sidechannel_thread_done)
+ {
+ gettimeofday(&tv, NULL);
+ cond_timeout.tv_sec = tv.tv_sec + WAIT_SIDE_DELAY;
+ cond_timeout.tv_nsec = tv.tv_usec * 1000;
+
+ while (!g.sidechannel_thread_done)
+ {
+ if (pthread_cond_timedwait(&g.sidechannel_thread_cond,
+ &g.sidechannel_thread_mutex,
+ &cond_timeout) != 0)
+ break;
+ }
+
+ if (!g.sidechannel_thread_done)
+ {
+ /*
+ * Force the side-channel thread to exit...
+ */
+
+ fputs("DEBUG: Force the side-channel thread to exit...\n", stderr);
+ pthread_kill(sidechannel_thread_id, SIGTERM);
+ }
+ }
+
+ pthread_mutex_unlock(&g.sidechannel_thread_mutex);
+
+ pthread_join(sidechannel_thread_id, NULL);
+
+ pthread_cond_destroy(&g.sidechannel_thread_cond);
+ pthread_mutex_destroy(&g.sidechannel_thread_mutex);
+ }
+
+ pthread_cond_destroy(&g.readwrite_lock_cond);
+ pthread_mutex_destroy(&g.readwrite_lock_mutex);
+
+ /*
+ * Signal the read thread to stop...
+ */
+
+ g.read_thread_stop = 1;
+
+ /*
+ * Give the read thread WAIT_EOF_DELAY seconds to complete all the data. If
+ * we are not signaled in that time then force the thread to exit.
+ */
+
+ pthread_mutex_lock(&g.read_thread_mutex);
+
+ if (!g.read_thread_done)
+ {
+ gettimeofday(&tv, NULL);
+ cond_timeout.tv_sec = tv.tv_sec + WAIT_EOF_DELAY;
+ cond_timeout.tv_nsec = tv.tv_usec * 1000;
+
+ while (!g.read_thread_done)
+ {
+ if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex,
+ &cond_timeout) != 0)
+ break;
+ }
+
+ if (!g.read_thread_done)
+ {
+ /*
+ * Force the read thread to exit...
+ */
+
+ g.wait_eof = 0;
+ fputs("DEBUG: Force the read thread to exit...\n", stderr);
+ pthread_kill(read_thread_id, SIGTERM);
+ }
+ }
+
+ pthread_mutex_unlock(&g.read_thread_mutex);
+
+ pthread_join(read_thread_id, NULL); /* wait for the read thread to return */
+
+ pthread_cond_destroy(&g.read_thread_cond);
+ pthread_mutex_destroy(&g.read_thread_mutex);
+
+ /*
+ * Close the connection and input file and general clean up...
+ */
+
+ registry_close();
+
+ if (print_fd != STDIN_FILENO)
+ close(print_fd);
+
+ if (g.make != NULL)
+ CFRelease(g.make);
+
+ if (g.model != NULL)
+ CFRelease(g.model);
+
+ if (g.serial != NULL)
+ CFRelease(g.serial);
+
+ if (g.printer_obj != 0x0)
+ IOObjectRelease(g.printer_obj);
+
+ return status;
+}
+
+
+/*
+ * 'read_thread()' - Thread to read the backchannel data on.
+ */
+
+static void *read_thread(void *reference)
+{
+ UInt8 readbuffer[512];
+ UInt32 rbytes;
+ kern_return_t readstatus;
+ struct mach_timebase_info timeBaseInfo;
+ uint64_t start,
+ delay;
+
+
+ (void)reference;
+
+ /* Calculate what 250 milliSeconds are in mach absolute time...
+ */
+ mach_timebase_info(&timeBaseInfo);
+ delay = ((uint64_t)250000000 * (uint64_t)timeBaseInfo.denom) / (uint64_t)timeBaseInfo.numer;
+
+ do
+ {
+ /*
+ * Remember when we started so we can throttle the loop after the read call...
+ */
+
+ start = mach_absolute_time();
+
+ rbytes = sizeof(readbuffer);
+ readstatus = (*g.classdriver)->ReadPipe(g.classdriver, readbuffer, &rbytes);
+ if (readstatus == kIOReturnSuccess && rbytes > 0)
+ {
+ fprintf(stderr, "DEBUG: Read %d bytes of back-channel data...\n",
+ (int)rbytes);
+ cupsBackChannelWrite((char*)readbuffer, rbytes, 1.0);
+
+ /* 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 (g.wait_eof && readbuffer[rbytes-1] == 0x4)
+ break;
+
+#ifdef PARSE_PS_ERRORS
+ parse_pserror(readbuffer, rbytes);
+#endif
+ }
+ else if (readstatus == kIOUSBTransactionTimeout)
+ fputs("DEBUG: Got USB transaction timeout during read\n", stderr);
+ else if (readstatus == kIOUSBPipeStalled)
+ fputs("DEBUG: Got USB pipe stalled during read\n", stderr);
+ else if (readstatus == kIOReturnAborted)
+ fputs("DEBUG: Got USB return aborted during read\n", stderr);
+
+ /*
+ * Make sure this loop executes no more than once every 250 miliseconds...
+ */
+
+ if ((readstatus != kIOReturnSuccess || rbytes == 0) && (g.wait_eof || !g.read_thread_stop))
+ mach_wait_until(start + delay);
+
+ } while (g.wait_eof || !g.read_thread_stop); /* Abort from main thread tests error here */
+
+ /*
+ * Let the main thread know that we have completed the read thread...
+ */
+
+ pthread_mutex_lock(&g.read_thread_mutex);
+ g.read_thread_done = 1;
+ pthread_cond_signal(&g.read_thread_cond);
+ pthread_mutex_unlock(&g.read_thread_mutex);
+
+ return NULL;
+}
+
+
+/*
+ * 'sidechannel_thread()' - Handle side-channel requests.
+ */
+
+static void*
+sidechannel_thread(void *reference)
+{
+ cups_sc_command_t command; /* Request command */
+ cups_sc_status_t status; /* Request/response status */
+ char data[2048]; /* Request/response data */
+ int datalen; /* Request/response data size */
+
+
+ (void)reference;
+
+ do
+ {
+ datalen = sizeof(data);
+
+ if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
+ {
+ if (status == CUPS_SC_STATUS_TIMEOUT)
+ continue;
+ else
+ break;
+ }
+
+ switch (command)
+ {
+ case CUPS_SC_CMD_SOFT_RESET: /* Do a soft reset */
+ fputs("DEBUG: CUPS_SC_CMD_SOFT_RESET received from driver...\n",
+ stderr);
+
+ if ((*g.classdriver)->SoftReset != NULL)
+ {
+ soft_reset();
+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, NULL, 0, 1.0);
+ fputs("DEBUG: Returning status CUPS_STATUS_OK with no bytes...\n",
+ stderr);
+ }
+ else
+ {
+ cupsSideChannelWrite(command, CUPS_SC_STATUS_NOT_IMPLEMENTED,
+ NULL, 0, 1.0);
+ fputs("DEBUG: Returning status CUPS_STATUS_NOT_IMPLEMENTED with "
+ "no bytes...\n", stderr);
+ }
+ break;
+
+ case CUPS_SC_CMD_DRAIN_OUTPUT: /* Drain all pending output */
+ fputs("DEBUG: CUPS_SC_CMD_DRAIN_OUTPUT received from driver...\n",
+ stderr);
+
+ g.drain_output = 1;
+ break;
+
+ case CUPS_SC_CMD_GET_BIDI: /* Is the connection bidirectional? */
+ fputs("DEBUG: CUPS_SC_CMD_GET_BIDI received from driver...\n",
+ stderr);
+
+ data[0] = g.bidi_flag;
+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0);
+
+ fprintf(stderr,
+ "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n",
+ data[0]);
+ break;
+
+ case CUPS_SC_CMD_GET_DEVICE_ID: /* Return IEEE-1284 device ID */
+ fputs("DEBUG: CUPS_SC_CMD_GET_DEVICE_ID received from driver...\n",
+ stderr);
+
+ datalen = sizeof(data);
+ get_device_id(&status, data, &datalen);
+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, datalen, 1.0);
+
+ if (datalen < sizeof(data))
+ data[datalen] = '\0';
+ else
+ data[sizeof(data) - 1] = '\0';
+
+ fprintf(stderr,
+ "DEBUG: Returning CUPS_SC_STATUS_OK with %d bytes (%s)...\n",
+ datalen, data);
+ break;
+
+ case CUPS_SC_CMD_GET_STATE: /* Return device state */
+ fputs("DEBUG: CUPS_SC_CMD_GET_STATE received from driver...\n",
+ stderr);
+
+ data[0] = CUPS_SC_STATE_ONLINE;
+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0);
+
+ fprintf(stderr,
+ "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n",
+ data[0]);
+ break;
+
+ default:
+ fprintf(stderr, "DEBUG: Unknown side-channel command (%d) received "
+ "from driver...\n", command);
+
+ cupsSideChannelWrite(command, CUPS_SC_STATUS_NOT_IMPLEMENTED,
+ NULL, 0, 1.0);
+
+ fputs("DEBUG: Returned CUPS_SC_STATUS_NOT_IMPLEMENTED with no bytes...\n",
+ stderr);
+ break;
+ }
+ }
+ while (!g.sidechannel_thread_stop);
+
+ pthread_mutex_lock(&g.sidechannel_thread_mutex);
+ g.sidechannel_thread_done = 1;
+ pthread_cond_signal(&g.sidechannel_thread_cond);
+ pthread_mutex_unlock(&g.sidechannel_thread_mutex);
+
+ return NULL;
+}
+
+
+#pragma mark -
+/*
+ * 'iterate_printers()' - Iterate over all the printers.
+ */
+
+static void iterate_printers(iterator_callback_t callBack,
+ void *userdata)
+{
+ mach_port_t masterPort = 0x0;
+ kern_return_t kr = IOMasterPort (bootstrap_port, &masterPort);
+
+ if (kr == kIOReturnSuccess && masterPort != 0x0)
+ {
+ io_iterator_t addIterator = 0x0;
+
+ iterator_reference_t reference = { callBack, userdata, true };
+ IONotificationPortRef addNotification = IONotificationPortCreate(masterPort);
+
+ int klass = kUSBPrintingClass;
+ int subklass = kUSBPrintingSubclass;
+
+ CFNumberRef usb_klass = CFNumberCreate(NULL, kCFNumberIntType, &klass);
+ CFNumberRef usb_subklass = CFNumberCreate(NULL, kCFNumberIntType, &subklass);
+ CFMutableDictionaryRef usbPrinterMatchDictionary = IOServiceMatching(kIOUSBInterfaceClassName);
+
+ CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceClass"), usb_klass);
+ CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceSubClass"), usb_subklass);
+
+ CFRelease(usb_klass);
+ CFRelease(usb_subklass);
+
+ kr = IOServiceAddMatchingNotification(addNotification, kIOMatchedNotification, usbPrinterMatchDictionary, &device_added, &reference, &addIterator);
+ if (addIterator != 0x0)
+ {
+ device_added (&reference, addIterator);
+
+ if (reference.keepRunning)
+ {
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(addNotification), kCFRunLoopDefaultMode);
+ CFRunLoopRun();
+ }
+ IOObjectRelease(addIterator);
+ }
+ mach_port_deallocate(mach_task_self(), masterPort);
+ }
+}
+
+
+/*
+ * 'device_added()' - Device added notifier.
+ */
+
+static void device_added(void *userdata,
+ io_iterator_t iterator)
+{
+ iterator_reference_t *reference = userdata;
+
+ io_service_t obj;
+ while (reference->keepRunning && (obj = IOIteratorNext(iterator)) != 0x0)
+ {
+ if (reference->callback != NULL)
+ reference->keepRunning = reference->callback(reference->userdata, obj);
+
+ IOObjectRelease(obj);
+ }
+
+ /* One last call to the call back now that we are not longer have printers left to iterate...
+ */
+ if (reference->keepRunning)
+ reference->keepRunning = reference->callback(reference->userdata, 0x0);
+
+ if (!reference->keepRunning)
+ CFRunLoopStop(CFRunLoopGetCurrent());
+}
+
+
+/*
+ * 'list_device_cb()' - list_device iterator callback.
+ */
+
+static Boolean list_device_cb(void *refcon,
+ io_service_t obj)
+{
+ Boolean keepRunning = (obj != 0x0);
+
+
+ (void)refcon;
+
+ if (keepRunning)
+ {
+ CFStringRef deviceIDString = NULL;
+ UInt32 deviceLocation = 0;
+ UInt8 interfaceNum = 0;
+
+ copy_devicestring(obj, &deviceIDString, &deviceLocation, &interfaceNum);
+ if (deviceIDString != NULL)
+ {
+ CFStringRef make = NULL, model = NULL, serial = NULL;
+ char uristr[1024], makestr[1024], modelstr[1024], serialstr[1024];
+ char optionsstr[1024], idstr[1024], make_modelstr[1024];
+
+ copy_deviceinfo(deviceIDString, &make, &model, &serial);
+ CFStringGetCString(deviceIDString, idstr, sizeof(idstr),
+ kCFStringEncodingUTF8);
+ backendGetMakeModel(idstr, make_modelstr, sizeof(make_modelstr));
+
+ modelstr[0] = '/';
+
+ if (!make ||
+ !CFStringGetCString(make, makestr, sizeof(makestr),
+ kCFStringEncodingUTF8))
+ strcpy(makestr, "Unknown");
+
+ if (!model ||
+ !CFStringGetCString(model, &modelstr[1], sizeof(modelstr)-1,
+ kCFStringEncodingUTF8))
+ strcpy(modelstr + 1, "Printer");
+
+ optionsstr[0] = '\0';
+ if (serial != NULL)
+ {
+ CFStringGetCString(serial, serialstr, sizeof(serialstr), kCFStringEncodingUTF8);
+ snprintf(optionsstr, sizeof(optionsstr), "?serial=%s", serialstr);
+ }
+ else if (deviceLocation != 0)
+ snprintf(optionsstr, sizeof(optionsstr), "?location=%x", (unsigned)deviceLocation);
+
+ httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
+ strlcat(uristr, optionsstr, sizeof(uristr));
+
+ cupsBackendReport("direct", uristr, make_modelstr, make_modelstr, idstr,
+ NULL);
+
+ release_deviceinfo(&make, &model, &serial);
+ CFRelease(deviceIDString);
+ }
+ }
+
+ return keepRunning;
+}
+
+
+/*
+ * 'find_device_cb()' - print_device iterator callback.
+ */
+
+static Boolean find_device_cb(void *refcon,
+ io_service_t obj)
+{
+ Boolean keepLooking = true;
+
+ if (obj != 0x0)
+ {
+ CFStringRef idString = NULL;
+ UInt32 location = -1;
+ UInt8 interfaceNum = 0;
+
+ copy_devicestring(obj, &idString, &location, &interfaceNum);
+ if (idString != NULL)
+ {
+ CFStringRef make = NULL, model = NULL, serial = NULL;
+
+ copy_deviceinfo(idString, &make, &model, &serial);
+ if (make && CFStringCompare(make, g.make, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ {
+ if (model && CFStringCompare(model, g.model, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ {
+ if (g.serial != NULL && CFStringGetLength(g.serial) > 0)
+ {
+ if (serial != NULL && CFStringCompare(serial, g.serial, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ {
+ IOObjectRetain(obj);
+ g.printer_obj = obj;
+ keepLooking = false;
+ }
+ }
+ else
+ {
+ if (g.printer_obj != 0)
+ IOObjectRelease(g.printer_obj);
+
+ g.printer_obj = obj;
+ IOObjectRetain(obj);
+
+ if (g.location == 0 || g.location == location)
+ keepLooking = false;
+ }
+ if ( !keepLooking )
+ g.interfaceNum = interfaceNum;
+ }
+ }
+
+ release_deviceinfo(&make, &model, &serial);
+ CFRelease(idString);
+ }
+ }
+ else
+ {
+ keepLooking = (g.printer_obj == 0);
+ if (obj == 0x0 && keepLooking)
+ {
+ CFRunLoopTimerContext context = { 0, refcon, NULL, NULL, NULL };
+ CFRunLoopTimerRef timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + 1.0, 10, 0x0, 0x0, status_timer_cb, &context);
+ if (timer != NULL)
+ {
+ CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
+ g.status_timer = timer;
+ }
+ }
+ }
+
+ if (!keepLooking && g.status_timer != NULL)
+ {
+ fputs("STATE: -offline-report\n", stderr);
+ _cupsLangPrintFilter(stderr, "INFO", _("Printer is now online."));
+ CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), g.status_timer, kCFRunLoopDefaultMode);
+ CFRelease(g.status_timer);
+ g.status_timer = NULL;
+ }
+
+ return keepLooking;
+}
+
+
+/*
+ * 'status_timer_cb()' - Status timer callback.
+ */
+
+static void status_timer_cb(CFRunLoopTimerRef timer,
+ void *info)
+{
+ (void)timer;
+ (void)info;
+
+ fputs("STATE: +offline-report\n", stderr);
+ _cupsLangPrintFilter(stderr, "INFO", _("Printer is offline."));
+
+ 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.
+ *
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ exit(CUPS_BACKEND_FAILED);
+ }
+}
+
+
+#pragma mark -
+/*
+ * 'copy_deviceinfo()' - Copy strings from the 1284 device ID.
+ */
+
+static void copy_deviceinfo(CFStringRef deviceIDString,
+ CFStringRef *make,
+ CFStringRef *model,
+ CFStringRef *serial)
+{
+ CFStringRef modelKeys[] = { CFSTR("MDL:"), CFSTR("MODEL:"), NULL };
+ CFStringRef makeKeys[] = { CFSTR("MFG:"), CFSTR("MANUFACTURER:"), NULL };
+ CFStringRef serialKeys[] = { CFSTR("SN:"), CFSTR("SERN:"), NULL };
+
+ if (make != NULL)
+ *make = copy_value_for_key(deviceIDString, makeKeys);
+
+ if (model != NULL)
+ *model = copy_value_for_key(deviceIDString, modelKeys);
+
+ if (serial != NULL)
+ *serial = copy_value_for_key(deviceIDString, serialKeys);
+}
+
+
+/*
+ * 'release_deviceinfo()' - Release deviceinfo strings.
+ */
+
+static void release_deviceinfo(CFStringRef *make,
+ CFStringRef *model,
+ CFStringRef *serial)
+{
+ if (make != NULL && *make != NULL)
+ {
+ CFRelease(*make);
+ *make = NULL;
+ }
+
+ if (model != NULL && *model != NULL)
+ {
+ CFRelease(*model);
+ *model = NULL;
+ }
+
+ if (serial != NULL && *serial != NULL)
+ {
+ CFRelease(*serial);
+ *serial = NULL;
+ }
+}
+
+
+#pragma mark -
+/*
+ * 'load_classdriver()' - Load a classdriver.
+ */
+
+static kern_return_t load_classdriver(CFStringRef driverPath,
+ printer_interface_t interface,
+ classdriver_t ***printerDriver)
+{
+ kern_return_t kr = kUSBPrinterClassDeviceNotOpen;
+ classdriver_t **driver = NULL;
+ CFStringRef bundle = driverPath ? driverPath : kUSBGenericTOPrinterClassDriver;
+ char bundlestr[1024]; /* Bundle path */
+ CFURLRef url; /* URL for driver */
+ CFPlugInRef plugin = NULL; /* Plug-in address */
+
+
+ CFStringGetCString(bundle, bundlestr, sizeof(bundlestr), kCFStringEncodingUTF8);
+
+ /*
+ * Validate permissions for the class driver...
+ */
+
+ _cups_fc_result_t result = _cupsFileCheck(bundlestr,
+ _CUPS_FILE_CHECK_DIRECTORY, 1,
+ _cupsFileCheckFilter, NULL);
+
+ if (result && driverPath)
+ return (load_classdriver(NULL, interface, printerDriver));
+ else if (result)
+ return (kr);
+
+ /*
+ * Try loading the class driver...
+ */
+
+ url = CFURLCreateWithFileSystemPath(NULL, bundle, kCFURLPOSIXPathStyle, true);
+
+ if (url)
+ {
+ plugin = CFPlugInCreate(NULL, url);
+ CFRelease(url);
+ }
+ else
+ plugin = NULL;
+
+ if (plugin)
+ {
+ CFArrayRef factories = CFPlugInFindFactoriesForPlugInTypeInPlugIn(kUSBPrinterClassTypeID, plugin);
+ if (factories != NULL && CFArrayGetCount(factories) > 0)
+ {
+ CFUUIDRef factoryID = CFArrayGetValueAtIndex(factories, 0);
+ IUnknownVTbl **iunknown = CFPlugInInstanceCreate(NULL, factoryID, kUSBPrinterClassTypeID);
+ if (iunknown != NULL)
+ {
+ kr = (*iunknown)->QueryInterface(iunknown, CFUUIDGetUUIDBytes(kUSBPrinterClassInterfaceID), (LPVOID *)&driver);
+ if (kr == kIOReturnSuccess && driver != NULL)
+ {
+ classdriver_t **genericDriver = NULL;
+ if (driverPath != NULL && CFStringCompare(driverPath, kUSBGenericTOPrinterClassDriver, 0) != kCFCompareEqualTo)
+ kr = load_classdriver(NULL, interface, &genericDriver);
+
+ if (kr == kIOReturnSuccess)
+ {
+ (*driver)->interface = interface;
+ (*driver)->Initialize(driver, genericDriver);
+
+ (*driver)->plugin = plugin;
+ (*driver)->interface = interface;
+ *printerDriver = driver;
+ }
+ }
+ (*iunknown)->Release(iunknown);
+ }
+ CFRelease(factories);
+ }
+ }
+
+ fprintf(stderr, "DEBUG: load_classdriver(%s) (kr:0x%08x)\n", bundlestr, (int)kr);
+
+ return (kr);
+}
+
+
+/*
+ * 'unload_classdriver()' - Unload a classdriver.
+ */
+
+static kern_return_t unload_classdriver(classdriver_t ***classdriver)
+{
+ if (*classdriver != NULL)
+ {
+ (**classdriver)->Release(*classdriver);
+ *classdriver = NULL;
+ }
+
+ return kIOReturnSuccess;
+}
+
+
+/*
+ * 'load_printerdriver()' - Load vendor's classdriver.
+ *
+ * If driverBundlePath is not NULL on return it is the callers responsbility to release it!
+ */
+
+static kern_return_t load_printerdriver(CFStringRef *driverBundlePath)
+{
+ IOCFPlugInInterface **iodev = NULL;
+ SInt32 score;
+ kern_return_t kr;
+ printer_interface_t interface;
+ HRESULT res;
+
+ kr = IOCreatePlugInInterfaceForService(g.printer_obj, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
+ if (kr == kIOReturnSuccess)
+ {
+ if ((res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &interface)) == noErr)
+ {
+ *driverBundlePath = IORegistryEntryCreateCFProperty(g.printer_obj, kUSBClassDriverProperty, NULL, kNilOptions);
+
+ kr = load_classdriver(*driverBundlePath, interface, &g.classdriver);
+
+ if (kr != kIOReturnSuccess)
+ (*interface)->Release(interface);
+ }
+ IODestroyPlugInInterface(iodev);
+ }
+ return kr;
+}
+
+
+/*
+ * 'registry_open()' - Open a connection to the printer.
+ */
+
+static kern_return_t registry_open(CFStringRef *driverBundlePath)
+{
+ g.bidi_flag = 0; /* 0=unidirectional */
+
+ kern_return_t kr = load_printerdriver(driverBundlePath);
+ if (kr != kIOReturnSuccess)
+ kr = -2;
+
+ if (g.classdriver != NULL)
+ {
+ (*g.classdriver)->interfaceNumber = g.interfaceNum;
+ kr = (*g.classdriver)->Open(g.classdriver, g.location, kUSBPrintingProtocolBidirectional);
+ if (kr != kIOReturnSuccess || (*g.classdriver)->interface == NULL)
+ {
+ kr = (*g.classdriver)->Open(g.classdriver, g.location, kUSBPrintingProtocolUnidirectional);
+ if (kr == kIOReturnSuccess)
+ {
+ if ((*g.classdriver)->interface == NULL)
+ {
+ (*g.classdriver)->Close(g.classdriver);
+ kr = -1;
+ }
+ }
+ }
+ else
+ g.bidi_flag = 1; /* 1=bidirectional */
+ }
+
+ if (kr != kIOReturnSuccess)
+ unload_classdriver(&g.classdriver);
+
+ return kr;
+}
+
+
+/*
+ * 'registry_close()' - Close the connection to the printer.
+ */
+
+static kern_return_t registry_close(void)
+{
+ if (g.classdriver != NULL)
+ (*g.classdriver)->Close(g.classdriver);
+
+ unload_classdriver(&g.classdriver);
+ return kIOReturnSuccess;
+}
+
+
+/*
+ * 'copy_deviceid()' - Copy the 1284 device id string.
+ */
+
+static OSStatus copy_deviceid(classdriver_t **classdriver,
+ CFStringRef *deviceID)
+{
+ CFStringRef devID = NULL,
+
+ deviceMake = NULL,
+ deviceModel = NULL,
+ deviceSerial = NULL;
+
+ OSStatus err = (*classdriver)->GetDeviceID(classdriver, &devID, DEFAULT_TIMEOUT);
+
+ copy_deviceinfo(devID, &deviceMake, &deviceModel, &deviceSerial);
+
+ if (deviceMake == NULL || deviceModel == NULL || deviceSerial == NULL)
+ {
+ IOUSBDeviceDescriptor desc;
+ iodevice_request_t request;
+
+ request.requestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+ request.request = kUSBRqGetDescriptor;
+ request.value = (kUSBDeviceDesc << 8) | 0;
+ request.index = 0;
+ request.length = sizeof(desc);
+ request.buffer = &desc;
+ err = (*classdriver)->DeviceRequest(classdriver, &request, DEFAULT_TIMEOUT);
+ if (err == kIOReturnSuccess)
+ {
+ CFMutableStringRef newDevID = CFStringCreateMutable(NULL, 0);
+
+ if (deviceMake == NULL)
+ {
+ CFStringRef data = NULL;
+ err = (*classdriver)->GetString(classdriver, desc.iManufacturer, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &data);
+ if (data != NULL)
+ {
+ CFStringAppendFormat(newDevID, NULL, CFSTR("MFG:%@;"), data);
+ CFRelease(data);
+ }
+ }
+
+ if (deviceModel == NULL)
+ {
+ CFStringRef data = NULL;
+ err = (*classdriver)->GetString(classdriver, desc.iProduct, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &data);
+ if (data != NULL)
+ {
+ CFStringAppendFormat(newDevID, NULL, CFSTR("MDL:%@;"), data);
+ CFRelease(data);
+ }
+ }
+
+ if (deviceSerial == NULL && desc.iSerialNumber != 0)
+ {
+ CFStringRef data = NULL;
+ err = (*classdriver)->GetString(classdriver, desc.iSerialNumber, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &data);
+ if (data != NULL)
+ {
+ CFStringAppendFormat(newDevID, NULL, CFSTR("SERN:%@;"), data);
+ CFRelease(data);
+ }
+ }
+
+ if (devID != NULL)
+ {
+ CFStringAppend(newDevID, devID);
+ CFRelease(devID);
+ }
+
+ *deviceID = newDevID;
+ }
+ }
+ else
+ {
+ *deviceID = devID;
+ }
+ release_deviceinfo(&deviceMake, &deviceModel, &deviceSerial);
+
+ return err;
+}
+
+
+/*
+ * 'copy_devicestring()' - Copy the 1284 device id string.
+ */
+
+static void copy_devicestring(io_service_t usbInterface,
+ CFStringRef *deviceID,
+ UInt32 *deviceLocation,
+ UInt8 *interfaceNumber )
+{
+ IOCFPlugInInterface **iodev = NULL;
+ SInt32 score;
+ kern_return_t kr;
+ printer_interface_t interface;
+ HRESULT res;
+ classdriver_t **klassDriver = NULL;
+ CFStringRef driverBundlePath;
+
+ if ((kr = IOCreatePlugInInterfaceForService(usbInterface,
+ kIOUSBInterfaceUserClientTypeID,
+ kIOCFPlugInInterfaceID,
+ &iodev, &score)) == kIOReturnSuccess)
+ {
+ if ((res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *)
+ &interface)) == noErr)
+ {
+ (*interface)->GetLocationID(interface, deviceLocation);
+ (*interface)->GetInterfaceNumber(interface, interfaceNumber);
+
+ driverBundlePath = IORegistryEntryCreateCFProperty(usbInterface,
+ kUSBClassDriverProperty,
+ NULL, kNilOptions);
+
+ kr = load_classdriver(driverBundlePath, interface, &klassDriver);
+
+ if (kr != kIOReturnSuccess && driverBundlePath != NULL)
+ kr = load_classdriver(NULL, interface, &klassDriver);
+
+ if (kr == kIOReturnSuccess && klassDriver != NULL)
+ kr = copy_deviceid(klassDriver, deviceID);
+
+ unload_classdriver(&klassDriver);
+
+ if (driverBundlePath != NULL)
+ CFRelease(driverBundlePath);
+
+ /* (*interface)->Release(interface); */
+ }
+ IODestroyPlugInInterface(iodev);
+ }
+}
+
+
+#pragma mark -
+/*
+ * 'copy_value_for_key()' - Copy value string associated with a key.
+ */
+
+static CFStringRef copy_value_for_key(CFStringRef deviceID,
+ CFStringRef *keys)
+{
+ CFStringRef value = NULL;
+ CFArrayRef kvPairs = deviceID != NULL ? CFStringCreateArrayBySeparatingStrings(NULL, deviceID, CFSTR(";")) : NULL;
+ CFIndex max = kvPairs != NULL ? CFArrayGetCount(kvPairs) : 0;
+ CFIndex idx = 0;
+
+ while (idx < max && value == NULL)
+ {
+ CFStringRef kvpair = CFArrayGetValueAtIndex(kvPairs, idx);
+ CFIndex idxx = 0;
+ while (keys[idxx] != NULL && value == NULL)
+ {
+ CFRange range = CFStringFind(kvpair, keys[idxx], kCFCompareCaseInsensitive);
+ if (range.length != -1)
+ {
+ if (range.location != 0)
+ {
+ CFMutableStringRef theString = CFStringCreateMutableCopy(NULL, 0, kvpair);
+ CFStringTrimWhitespace(theString);
+ range = CFStringFind(theString, keys[idxx], kCFCompareCaseInsensitive);
+ if (range.location == 0)
+ value = CFStringCreateWithSubstring(NULL, theString, CFRangeMake(range.length, CFStringGetLength(theString) - range.length));
+
+ CFRelease(theString);
+ }
+ else
+ {
+ CFStringRef theString = CFStringCreateWithSubstring(NULL, kvpair, CFRangeMake(range.length, CFStringGetLength(kvpair) - range.length));
+ CFMutableStringRef theString2 = CFStringCreateMutableCopy(NULL, 0, theString);
+ CFRelease(theString);
+
+ CFStringTrimWhitespace(theString2);
+ value = theString2;
+ }
+ }
+ idxx++;
+ }
+ idx++;
+ }
+
+ if (kvPairs != NULL)
+ CFRelease(kvPairs);
+ return value;
+}
+
+
+/*
+ * 'cfstr_create_trim()' - Create CFString and trim whitespace characters.
+ */
+
+CFStringRef cfstr_create_trim(const char *cstr)
+{
+ CFStringRef cfstr;
+ CFMutableStringRef cfmutablestr = NULL;
+
+ if ((cfstr = CFStringCreateWithCString(NULL, cstr, kCFStringEncodingUTF8)) != NULL)
+ {
+ if ((cfmutablestr = CFStringCreateMutableCopy(NULL, 1024, cfstr)) != NULL)
+ CFStringTrimWhitespace(cfmutablestr);
+
+ CFRelease(cfstr);
+ }
+ return (CFStringRef) cfmutablestr;
+}
+
+
+#pragma mark -
+/*
+ * 'parse_options()' - Parse URI options.
+ */
+
+static void parse_options(char *options,
+ char *serial,
+ int serial_size,
+ UInt32 *location,
+ Boolean *wait_eof)
+{
+ char sep, /* Separator character */
+ *name, /* Name of option */
+ *value; /* Value of option */
+
+
+ if (serial)
+ *serial = '\0';
+ if (location)
+ *location = 0;
+
+ if (!options)
+ return;
+
+ while (*options)
+ {
+ /*
+ * Get the name...
+ */
+
+ name = options;
+
+ while (*options && *options != '=' && *options != '+' && *options != '&')
+ options ++;
+
+ if ((sep = *options) != '\0')
+ *options++ = '\0';
+
+ if (sep == '=')
+ {
+ /*
+ * Get the value...
+ */
+
+ value = options;
+
+ while (*options && *options != '+' && *options != '&')
+ options ++;
+
+ if (*options)
+ *options++ = '\0';
+ }
+ else
+ value = (char *)"";
+
+ /*
+ * Process the option...
+ */
+
+ if (!_cups_strcasecmp(name, "waiteof"))
+ {
+ if (!_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "yes") ||
+ !_cups_strcasecmp(value, "true"))
+ *wait_eof = true;
+ else if (!_cups_strcasecmp(value, "off") ||
+ !_cups_strcasecmp(value, "no") ||
+ !_cups_strcasecmp(value, "false"))
+ *wait_eof = false;
+ else
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("Boolean expected for waiteof option \"%s\"."),
+ value);
+ }
+ else if (!_cups_strcasecmp(name, "serial"))
+ strlcpy(serial, value, serial_size);
+ else if (!_cups_strcasecmp(name, "location") && location)
+ *location = strtol(value, NULL, 16);
+ }
+}
+
+
+/*!
+ * @function setup_cfLanguage
+ * @abstract Convert the contents of the CUPS 'APPLE_LANGUAGE' environment
+ * variable into a one element CF array of languages.
+ *
+ * @discussion Each submitted job comes with a natural language. CUPS passes
+ * that language in an environment variable. We take that language
+ * and jam it into the AppleLanguages array so that CF will use
+ * it when reading localized resources. We need to do this before
+ * any CF code reads and caches the languages array, so this function
+ * should be called early in main()
+ */
+static void setup_cfLanguage(void)
+{
+ CFStringRef lang[1] = {NULL};
+ CFArrayRef langArray = NULL;
+ const char *requestedLang = NULL;
+
+ if ((requestedLang = getenv("APPLE_LANGUAGE")) == NULL)
+ requestedLang = getenv("LANG");
+
+ if (requestedLang != NULL)
+ {
+ lang[0] = CFStringCreateWithCString(kCFAllocatorDefault, requestedLang, kCFStringEncodingUTF8);
+ langArray = CFArrayCreate(kCFAllocatorDefault, (const void **)lang, sizeof(lang) / sizeof(lang[0]), &kCFTypeArrayCallBacks);
+
+ CFPreferencesSetValue(CFSTR("AppleLanguages"), langArray, kCFPreferencesCurrentApplication, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
+ fprintf(stderr, "DEBUG: usb: AppleLanguages=\"%s\"\n", requestedLang);
+
+ CFRelease(lang[0]);
+ CFRelease(langArray);
+ }
+ else
+ fputs("DEBUG: usb: LANG and APPLE_LANGUAGE environment variables missing.\n", stderr);
+}
+
+#pragma mark -
+#if defined(__i386__) || defined(__x86_64__)
+/*!
+ * @function run_legacy_backend
+ *
+ * @abstract Starts child backend process running as a ppc or i386 executable.
+ *
+ * @result Never returns; always calls exit().
+ *
+ * @discussion
+ */
+static void run_legacy_backend(int argc,
+ char *argv[],
+ int fd)
+{
+ int i;
+ int exitstatus = 0;
+ int childstatus;
+ pid_t waitpid_status;
+ char *my_argv[32];
+ char *usb_legacy_status;
+
+ /*
+ * If we're running as x86_64 or i386 and couldn't load the class driver
+ * (because it's ppc or i386), then try to re-exec ourselves in ppc or i386
+ * mode to try again. If we don't have a ppc or i386 architecture we may be
+ * running with the same architecture again so guard against this by setting
+ * and testing an environment variable...
+ */
+
+# ifdef __x86_64__
+ usb_legacy_status = getenv("USB_I386_STATUS");
+# else
+ usb_legacy_status = getenv("USB_PPC_STATUS");
+# endif /* __x86_64__ */
+
+ if (!usb_legacy_status)
+ {
+ /*
+ * Setup a SIGTERM handler then block it before forking...
+ */
+
+ int err; /* posix_spawn result */
+ struct sigaction action; /* POSIX signal action */
+ sigset_t newmask, /* New signal mask */
+ oldmask; /* Old signal mask */
+ char usbpath[1024]; /* Path to USB backend */
+ const char *cups_serverbin;/* Path to CUPS binaries */
+
+
+ memset(&action, 0, sizeof(action));
+ sigaddset(&action.sa_mask, SIGTERM);
+ action.sa_handler = sigterm_handler;
+ sigaction(SIGTERM, &action, NULL);
+
+ sigemptyset(&newmask);
+ sigaddset(&newmask, SIGTERM);
+ sigprocmask(SIG_BLOCK, &newmask, &oldmask);
+
+ /*
+ * Set the environment variable...
+ */
+
+# ifdef __x86_64__
+ setenv("USB_I386_STATUS", "1", false);
+# else
+ setenv("USB_PPC_STATUS", "1", false);
+# endif /* __x86_64__ */
+
+ /*
+ * Tell the kernel to use the specified CPU architecture...
+ */
+
+# ifdef __x86_64__
+ cpu_type_t cpu = CPU_TYPE_I386;
+# else
+ cpu_type_t cpu = CPU_TYPE_POWERPC;
+# endif /* __x86_64__ */
+ size_t ocount = 1;
+ posix_spawnattr_t attrs;
+
+ if (!posix_spawnattr_init(&attrs))
+ {
+ posix_spawnattr_setsigdefault(&attrs, &oldmask);
+ if (posix_spawnattr_setbinpref_np(&attrs, 1, &cpu, &ocount) || ocount != 1)
+ {
+# ifdef __x86_64__
+ perror("DEBUG: Unable to set binary preference to i386");
+# else
+ perror("DEBUG: Unable to set binary preference to ppc");
+# endif /* __x86_64__ */
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to use legacy USB class driver."));
+ exit(CUPS_BACKEND_STOP);
+ }
+ }
+
+ /*
+ * Set up the arguments and call posix_spawn...
+ */
+
+ if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
+ cups_serverbin = CUPS_SERVERBIN;
+ snprintf(usbpath, sizeof(usbpath), "%s/backend/usb", cups_serverbin);
+
+ for (i = 0; i < argc && i < (sizeof(my_argv) / sizeof(my_argv[0])) - 1; i ++)
+ my_argv[i] = argv[i];
+
+ my_argv[i] = NULL;
+
+ if ((err = posix_spawn(&child_pid, usbpath, NULL, &attrs, my_argv,
+ environ)) != 0)
+ {
+ fprintf(stderr, "DEBUG: Unable to exec %s: %s\n", usbpath,
+ strerror(err));
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to use legacy USB class driver."));
+ exit(CUPS_BACKEND_STOP);
+ }
+
+ /*
+ * Unblock signals...
+ */
+
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+ /*
+ * Close the fds we won't be using then wait for the child backend to exit.
+ */
+
+ close(fd);
+ close(1);
+
+ fprintf(stderr, "DEBUG: Started usb(legacy) backend (PID %d)\n",
+ (int)child_pid);
+
+ while ((waitpid_status = waitpid(child_pid, &childstatus, 0)) == (pid_t)-1 && errno == EINTR)
+ usleep(1000);
+
+ if (WIFSIGNALED(childstatus))
+ {
+ exitstatus = CUPS_BACKEND_STOP;
+ fprintf(stderr, "DEBUG: usb(legacy) backend %d crashed on signal %d\n",
+ child_pid, WTERMSIG(childstatus));
+ }
+ else
+ {
+ if ((exitstatus = WEXITSTATUS(childstatus)) != 0)
+ fprintf(stderr,
+ "DEBUG: usb(legacy) backend %d stopped with status %d\n",
+ child_pid, exitstatus);
+ else
+ fprintf(stderr, "DEBUG: usb(legacy) backend %d exited with no errors\n",
+ child_pid);
+ }
+ }
+ else
+ {
+ fputs("DEBUG: usb(legacy) backend running native again\n", stderr);
+ exitstatus = CUPS_BACKEND_STOP;
+ }
+
+ exit(exitstatus);
+}
+#endif /* __i386__ || __x86_64__ */
+
+
+/*
+ * 'sigterm_handler()' - SIGTERM handler.
+ */
+
+static void
+sigterm_handler(int sig) /* I - Signal */
+{
+#if defined(__i386__) || defined(__x86_64__)
+ /*
+ * If we started a child process pass the signal on to it...
+ */
+
+ if (child_pid)
+ {
+ /*
+ * If we started a child process pass the signal on to it...
+ */
+
+ int status;
+
+ kill(child_pid, sig);
+ while (waitpid(child_pid, &status, 0) < 0 && errno == EINTR);
+
+ if (WIFEXITED(status))
+ exit(WEXITSTATUS(status));
+ else if (status == SIGTERM || status == SIGKILL)
+ exit(0);
+ else
+ {
+ fprintf(stderr, "DEBUG: Child crashed on signal %d\n", status);
+ exit(CUPS_BACKEND_STOP);
+ }
+ }
+#endif /* __i386__ || __x86_64__ */
+}
+
+
+#ifdef PARSE_PS_ERRORS
+/*
+ * 'next_line()' - Find the next line in a buffer.
+ */
+
+static const char *next_line (const char *buffer)
+{
+ const char *cptr, *lptr = NULL;
+
+ for (cptr = buffer; *cptr && lptr == NULL; cptr++)
+ if (*cptr == '\n' || *cptr == '\r')
+ lptr = cptr;
+ return lptr;
+}
+
+
+/*
+ * 'parse_pserror()' - Scan the backchannel data for postscript errors.
+ */
+
+static void parse_pserror(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 *)next_line((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 (_cups_strncasecmp(pCommentBegin, "%%[ Error:", 10) == 0)
+ logLevel = "DEBUG";
+ else if (_cups_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 *)next_line((const char *)gErrorBuffer);
+ }
+}
+#endif /* PARSE_PS_ERRORS */
+
+
+/*
+ * 'soft_reset()' - Send a soft reset to the device.
+ */
+
+static void soft_reset(void)
+{
+ fd_set input_set; /* Input set for select() */
+ struct timeval tv; /* Time value */
+ char buffer[2048]; /* Buffer */
+ struct timespec cond_timeout; /* pthread condition timeout */
+
+ /*
+ * Send an abort once a second until the I/O lock is released by the main thread...
+ */
+
+ pthread_mutex_lock(&g.readwrite_lock_mutex);
+ while (g.readwrite_lock)
+ {
+ (*g.classdriver)->Abort(g.classdriver);
+
+ gettimeofday(&tv, NULL);
+ cond_timeout.tv_sec = tv.tv_sec + 1;
+ cond_timeout.tv_nsec = tv.tv_usec * 1000;
+
+ while (g.readwrite_lock)
+ {
+ if (pthread_cond_timedwait(&g.readwrite_lock_cond,
+ &g.readwrite_lock_mutex,
+ &cond_timeout) != 0)
+ break;
+ }
+ }
+
+ g.readwrite_lock = 1;
+ pthread_mutex_unlock(&g.readwrite_lock_mutex);
+
+ /*
+ * Flush bytes waiting on print_fd...
+ */
+
+ g.print_bytes = 0;
+
+ FD_ZERO(&input_set);
+ FD_SET(g.print_fd, &input_set);
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ while (select(g.print_fd+1, &input_set, NULL, NULL, &tv) > 0)
+ if (read(g.print_fd, buffer, sizeof(buffer)) <= 0)
+ break;
+
+ /*
+ * Send the reset...
+ */
+
+ (*g.classdriver)->SoftReset(g.classdriver, DEFAULT_TIMEOUT);
+
+ /*
+ * Release the I/O lock...
+ */
+
+ pthread_mutex_lock(&g.readwrite_lock_mutex);
+ g.readwrite_lock = 0;
+ pthread_cond_signal(&g.readwrite_lock_cond);
+ pthread_mutex_unlock(&g.readwrite_lock_mutex);
+}
+
+
+/*
+ * 'get_device_id()' - Return IEEE-1284 device ID.
+ */
+
+static void get_device_id(cups_sc_status_t *status,
+ char *data,
+ int *datalen)
+{
+ CFStringRef deviceIDString = NULL;
+
+ /* GetDeviceID */
+ copy_deviceid(g.classdriver, &deviceIDString);
+
+ if (deviceIDString)
+ {
+ CFStringGetCString(deviceIDString, data, *datalen, kCFStringEncodingUTF8);
+ *datalen = strlen(data);
+ CFRelease(deviceIDString);
+ }
+ *status = CUPS_SC_STATUS_OK;
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/usb-libusb.c b/backend/usb-libusb.c
new file mode 100644
index 000000000..7f8c74a08
--- /dev/null
+++ b/backend/usb-libusb.c
@@ -0,0 +1,834 @@
+/*
+ * "$Id$"
+ *
+ * Libusb interface code for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * list_devices() - List the available printers.
+ * print_device() - Print a file to a USB device.
+ * close_device() - Close the connection to the USB printer.
+ * find_device() - Find or enumerate USB printers.
+ * get_device_id() - Get the IEEE-1284 device ID for the printer.
+ * list_cb() - List USB printers for discovery.
+ * make_device_uri() - Create a device URI for a USB printer.
+ * open_device() - Open a connection to the USB printer.
+ * print_cb() - Find a USB printer for printing.
+ * side_cb() - Handle side-channel requests.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <usb.h>
+#include <poll.h>
+#include <cups/cups-private.h>
+
+
+/*
+ * Local types...
+ */
+
+typedef struct usb_printer_s /**** USB Printer Data ****/
+{
+ struct usb_device *device; /* Device info */
+ int conf, /* Configuration */
+ iface, /* Interface */
+ altset, /* Alternate setting */
+ write_endp, /* Write endpoint */
+ read_endp; /* Read endpoint */
+ struct usb_dev_handle *handle; /* Open handle to device */
+} usb_printer_t;
+
+typedef int (*usb_cb_t)(usb_printer_t *, const char *, const char *,
+ const void *);
+
+
+/*
+ * Local functions...
+ */
+
+static int close_device(usb_printer_t *printer);
+static usb_printer_t *find_device(usb_cb_t cb, const void *data);
+static int get_device_id(usb_printer_t *printer, char *buffer,
+ size_t bufsize);
+static int list_cb(usb_printer_t *printer, const char *device_uri,
+ const char *device_id, const void *data);
+static char *make_device_uri(usb_printer_t *printer,
+ const char *device_id,
+ char *uri, size_t uri_size);
+static int open_device(usb_printer_t *printer, int verbose);
+static int print_cb(usb_printer_t *printer, const char *device_uri,
+ const char *device_id, const void *data);
+static ssize_t side_cb(usb_printer_t *printer, int print_fd);
+
+
+/*
+ * 'list_devices()' - List the available printers.
+ */
+
+void
+list_devices(void)
+{
+ fputs("DEBUG: list_devices\n", stderr);
+ find_device(list_cb, NULL);
+}
+
+
+/*
+ * '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 */
+ char *options, /* I - Device options/serial number */
+ int print_fd, /* I - File descriptor to print */
+ int copies, /* I - Copies to print */
+ int argc, /* I - Number of command-line arguments (6 or 7) */
+ char *argv[]) /* I - Command-line arguments */
+{
+ usb_printer_t *printer; /* Printer */
+ ssize_t bytes, /* Bytes read/written */
+ tbytes; /* Total bytes written */
+ char buffer[512]; /* Print data buffer */
+ struct sigaction action; /* Actions for POSIX signals */
+ struct pollfd pfds[2]; /* Poll descriptors */
+
+
+ fputs("DEBUG: print_device\n", stderr);
+
+ /*
+ * Connect to the printer...
+ */
+
+ while ((printer = find_device(print_cb, uri)) == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Waiting for printer to become available."));
+ sleep(5);
+ }
+
+
+ /*
+ * If we are printing data from a print driver on stdin, ignore SIGTERM
+ * so that the driver can finish out any page data, e.g. to eject the
+ * current page. We only do this for stdin printing as otherwise there
+ * is no way to cancel a raw print job...
+ */
+
+ if (!print_fd)
+ {
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+ }
+
+ tbytes = 0;
+
+ pfds[0].fd = print_fd;
+ pfds[0].events = POLLIN;
+ pfds[1].fd = CUPS_SC_FD;
+ pfds[1].events = POLLIN;
+
+ while (copies > 0 && tbytes >= 0)
+ {
+ copies --;
+
+ if (print_fd != 0)
+ {
+ fputs("PAGE: 1 1\n", stderr);
+ lseek(print_fd, 0, SEEK_SET);
+ }
+
+ /*
+ * TODO: Add back-channel support, along with better write error handling.
+ */
+
+ while (poll(pfds, 2, -1) > 0)
+ {
+ /*
+ * CUPS STR #3318: USB process hangs on end-of-file, making further
+ * printing impossible
+ *
+ * From a strict interpretation of POSIX poll(), POLLHUP should never be
+ * set without POLLIN, since POLLIN is the event you request. That said,
+ * it appears that some versions of Linux break this.
+ */
+
+ if (pfds[0].revents & (POLLIN | POLLHUP))
+ {
+ if ((bytes = read(print_fd, buffer, sizeof(buffer))) > 0)
+ {
+ if (usb_bulk_write(printer->handle, printer->write_endp, buffer,
+ bytes, 3600000) < 0)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to send data to printer."));
+ tbytes = -1;
+ break;
+ }
+
+ tbytes += bytes;
+ }
+ else if (bytes == 0 || (bytes < 0 && errno != EAGAIN && errno != EINTR))
+ break;
+ }
+
+ if (pfds[1].revents & (POLLIN | POLLHUP))
+ {
+ if ((bytes = side_cb(printer, print_fd)) < 0)
+ pfds[1].events = 0; /* Filter has gone away... */
+ else
+ tbytes += bytes;
+ }
+ }
+ }
+
+ /*
+ * Close our connection and return...
+ */
+
+ close_device(printer);
+
+ return (CUPS_BACKEND_OK);
+}
+
+
+/*
+ * 'close_device()' - Close the connection to the USB printer.
+ */
+
+static int /* I - 0 on success, -1 on failure */
+close_device(usb_printer_t *printer) /* I - Printer */
+{
+ if (printer->handle)
+ {
+ /*
+ * Release interfaces before closing so that we know all data is written
+ * to the device...
+ */
+
+ int number = printer->device->config[printer->conf].
+ interface[printer->iface].
+ altsetting[printer->altset].bInterfaceNumber;
+ usb_release_interface(printer->handle, number);
+
+ if (number != 0)
+ usb_release_interface(printer->handle, 0);
+
+ /*
+ * Close the interface and return...
+ */
+
+ usb_close(printer->handle);
+ printer->handle = NULL;
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'find_device()' - Find or enumerate USB printers.
+ */
+
+static usb_printer_t * /* O - Found printer */
+find_device(usb_cb_t cb, /* I - Callback function */
+ const void *data) /* I - User data for callback */
+{
+ struct usb_bus *bus; /* Current bus */
+ struct usb_device *device; /* Current device */
+ struct usb_config_descriptor *confptr;/* Pointer to current configuration */
+ struct usb_interface *ifaceptr; /* Pointer to current interface */
+ struct usb_interface_descriptor *altptr;
+ /* Pointer to current alternate setting */
+ struct usb_endpoint_descriptor *endpptr;
+ /* Pointer to current endpoint */
+ int conf, /* Current configuration */
+ iface, /* Current interface */
+ altset, /* Current alternate setting */
+ protocol, /* Current protocol */
+ endp, /* Current endpoint */
+ read_endp, /* Current read endpoint */
+ write_endp; /* Current write endpoint */
+ char device_id[1024],/* IEEE-1284 device ID */
+ device_uri[1024];
+ /* Device URI */
+ static usb_printer_t printer; /* Current printer */
+
+
+ /*
+ * Initialize libusb...
+ */
+
+ usb_init();
+ fprintf(stderr, "DEBUG: usb_find_busses=%d\n", usb_find_busses());
+ fprintf(stderr, "DEBUG: usb_find_devices=%d\n", usb_find_devices());
+
+ /*
+ * Then loop through the devices it found...
+ */
+
+ for (bus = usb_get_busses(); bus; bus = bus->next)
+ for (device = bus->devices; device; device = device->next)
+ {
+ /*
+ * Ignore devices with no configuration data and anything that is not
+ * a printer...
+ */
+
+ if (!device->config || !device->descriptor.idVendor ||
+ !device->descriptor.idProduct)
+ continue;
+
+ for (conf = 0, confptr = device->config;
+ conf < device->descriptor.bNumConfigurations;
+ conf ++, confptr ++)
+ for (iface = 0, ifaceptr = confptr->interface;
+ iface < confptr->bNumInterfaces;
+ iface ++, ifaceptr ++)
+ {
+ /*
+ * Some printers offer multiple interfaces...
+ */
+
+ protocol = 0;
+
+ for (altset = 0, altptr = ifaceptr->altsetting;
+ altset < ifaceptr->num_altsetting;
+ altset ++, altptr ++)
+ {
+ /*
+ * Currently we only support unidirectional and bidirectional
+ * printers. Future versions of this code will support the
+ * 1284.4 (packet mode) protocol as well.
+ */
+
+ if (altptr->bInterfaceClass != USB_CLASS_PRINTER ||
+ altptr->bInterfaceSubClass != 1 ||
+ (altptr->bInterfaceProtocol != 1 && /* Unidirectional */
+ altptr->bInterfaceProtocol != 2) || /* Bidirectional */
+ altptr->bInterfaceProtocol < protocol)
+ continue;
+
+ read_endp = -1;
+ write_endp = -1;
+
+ for (endp = 0, endpptr = altptr->endpoint;
+ endp < altptr->bNumEndpoints;
+ endp ++, endpptr ++)
+ if ((endpptr->bmAttributes & USB_ENDPOINT_TYPE_MASK) ==
+ USB_ENDPOINT_TYPE_BULK)
+ {
+ if (endpptr->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ read_endp = endp;
+ else
+ write_endp = endp;
+ }
+
+ if (write_endp >= 0)
+ {
+ /*
+ * Save the best match so far...
+ */
+
+ protocol = altptr->bInterfaceProtocol;
+ printer.altset = altset;
+ printer.write_endp = write_endp;
+ printer.read_endp = read_endp;
+ }
+ }
+
+ if (protocol > 0)
+ {
+ printer.device = device;
+ printer.conf = conf;
+ printer.iface = iface;
+ printer.handle = NULL;
+
+ if (!open_device(&printer, data != NULL))
+ {
+ if (!get_device_id(&printer, device_id, sizeof(device_id)))
+ {
+ make_device_uri(&printer, device_id, device_uri,
+ sizeof(device_uri));
+
+ if ((*cb)(&printer, device_uri, device_id, data))
+ {
+ printer.read_endp = printer.device->config[printer.conf].
+ interface[printer.iface].
+ altsetting[printer.altset].
+ endpoint[printer.read_endp].
+ bEndpointAddress;
+ printer.write_endp = printer.device->config[printer.conf].
+ interface[printer.iface].
+ altsetting[printer.altset].
+ endpoint[printer.write_endp].
+ bEndpointAddress;
+ return (&printer);
+ }
+ }
+
+ close_device(&printer);
+ }
+ }
+ }
+ }
+
+ /*
+ * If we get this far without returning, then we haven't found a printer
+ * to print to...
+ */
+
+ return (NULL);
+}
+
+
+/*
+ * 'get_device_id()' - Get the IEEE-1284 device ID for the printer.
+ */
+
+static int /* O - 0 on success, -1 on error */
+get_device_id(usb_printer_t *printer, /* I - Printer */
+ char *buffer, /* I - String buffer */
+ size_t bufsize) /* I - Number of bytes in buffer */
+{
+ int length; /* Length of device ID */
+
+
+ if (usb_control_msg(printer->handle,
+ USB_TYPE_CLASS | USB_ENDPOINT_IN | USB_RECIP_INTERFACE,
+ 0, printer->conf, (printer->iface << 8) | printer->altset,
+ buffer, bufsize, 5000) < 0)
+ {
+ *buffer = '\0';
+ return (-1);
+ }
+
+ /*
+ * 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)buffer[0] & 255) << 8) +
+ ((unsigned)buffer[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 > bufsize)
+ length = (((unsigned)buffer[1] & 255) << 8) +
+ ((unsigned)buffer[0] & 255);
+
+ if (length > bufsize)
+ length = bufsize;
+
+ length -= 2;
+
+ /*
+ * Copy the device ID text to the beginning of the buffer and
+ * nul-terminate.
+ */
+
+ memmove(buffer, buffer + 2, length);
+ buffer[length] = '\0';
+
+ return (0);
+}
+
+
+/*
+ * 'list_cb()' - List USB printers for discovery.
+ */
+
+static int /* O - 0 to continue, 1 to stop */
+list_cb(usb_printer_t *printer, /* I - Printer */
+ const char *device_uri, /* I - Device URI */
+ const char *device_id, /* I - IEEE-1284 device ID */
+ const void *data) /* I - User data (not used) */
+{
+ char make_model[1024]; /* Make and model */
+
+
+ /*
+ * Get the device URI and make/model strings...
+ */
+
+ backendGetMakeModel(device_id, make_model, sizeof(make_model));
+
+ /*
+ * Report the printer...
+ */
+
+ cupsBackendReport("direct", device_uri, make_model, make_model, device_id,
+ NULL);
+
+ /*
+ * Keep going...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'make_device_uri()' - Create a device URI for a USB printer.
+ */
+
+static char * /* O - Device URI */
+make_device_uri(
+ usb_printer_t *printer, /* I - Printer */
+ const char *device_id, /* I - IEEE-1284 device ID */
+ char *uri, /* I - Device URI buffer */
+ size_t uri_size) /* I - Size of device URI buffer */
+{
+ char options[1024]; /* Device URI options */
+ int num_values; /* Number of 1284 parameters */
+ cups_option_t *values; /* 1284 parameters */
+ const char *mfg, /* Manufacturer */
+ *mdl, /* Model */
+ *des, /* Description */
+ *sern; /* Serial number */
+ char tempmfg[256], /* Temporary manufacturer string */
+ tempsern[256], /* Temporary serial number string */
+ *tempptr; /* Pointer into temp string */
+
+
+ /*
+ * Get the make, model, and serial numbers...
+ */
+
+ num_values = _cupsGet1284Values(device_id, &values);
+
+ if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL)
+ if ((sern = cupsGetOption("SERN", num_values, values)) == NULL)
+ if ((sern = cupsGetOption("SN", num_values, values)) == NULL &&
+ printer->device->descriptor.iSerialNumber)
+ {
+ /*
+ * Try getting the serial number from the device itself...
+ */
+
+ int length = usb_get_string_simple(printer->handle,
+ printer->device->descriptor.
+ iSerialNumber,
+ tempsern, sizeof(tempsern) - 1);
+ if (length > 0)
+ {
+ tempsern[length] = '\0';
+ sern = tempsern;
+ }
+ }
+
+ if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL)
+ mfg = cupsGetOption("MFG", num_values, values);
+
+ if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL)
+ mdl = cupsGetOption("MDL", num_values, values);
+
+#ifdef __APPLE__
+ /*
+ * To maintain compatibility with the original IOKit-based backend on Mac OS X,
+ * don't map manufacturer names...
+ */
+
+ if (!mfg)
+
+#else
+ /*
+ * To maintain compatibility with the original character device backend on
+ * Linux and *BSD, map manufacturer names...
+ */
+
+ if (mfg)
+ {
+ if (!_cups_strcasecmp(mfg, "Hewlett-Packard"))
+ mfg = "HP";
+ else if (!_cups_strcasecmp(mfg, "Lexmark International"))
+ mfg = "Lexmark";
+ }
+ else
+#endif /* __APPLE__ */
+ {
+ /*
+ * No manufacturer? Use the model string or description...
+ */
+
+ if (mdl)
+ _ppdNormalizeMakeAndModel(mdl, tempmfg, sizeof(tempmfg));
+ else if ((des = cupsGetOption("DESCRIPTION", num_values, values)) != NULL ||
+ (des = cupsGetOption("DES", num_values, values)) != NULL)
+ _ppdNormalizeMakeAndModel(des, tempmfg, sizeof(tempmfg));
+ else
+ strlcpy(tempmfg, "Unknown", sizeof(tempmfg));
+
+ if ((tempptr = strchr(tempmfg, ' ')) != NULL)
+ *tempptr = '\0';
+
+ mfg = tempmfg;
+ }
+
+ /*
+ * Generate the device URI from the manufacturer, model, serial number,
+ * and interface number...
+ */
+
+ if (sern)
+ {
+ if (printer->iface > 0)
+ snprintf(options, sizeof(options), "?serial=%s&interface=%d", sern,
+ printer->iface);
+ else
+ snprintf(options, sizeof(options), "?serial=%s", sern);
+ }
+ else if (printer->iface > 0)
+ snprintf(options, sizeof(options), "?interface=%d", printer->iface);
+ else
+ options[0] = '\0';
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, uri_size, "usb", NULL, mfg, 0,
+ "/%s%s", mdl, options);
+
+ cupsFreeOptions(num_values, values);
+
+ return (uri);
+}
+
+
+/*
+ * 'open_device()' - Open a connection to the USB printer.
+ */
+
+static int /* O - 0 on success, -1 on error */
+open_device(usb_printer_t *printer, /* I - Printer */
+ int verbose) /* I - Update connecting-to-device state? */
+{
+ int number; /* Configuration/interface/altset numbers */
+
+
+ /*
+ * Return immediately if we are already connected...
+ */
+
+ if (printer->handle)
+ return (0);
+
+ /*
+ * Try opening the printer...
+ */
+
+ if ((printer->handle = usb_open(printer->device)) == NULL)
+ return (-1);
+
+ /*
+ * Then set the desired configuration...
+ */
+
+ if (verbose)
+ fputs("STATE: +connecting-to-device\n", stderr);
+
+ number = printer->device->config[printer->conf].bConfigurationValue;
+
+ if (usb_set_configuration(printer->handle, number) < 0)
+ {
+ /*
+ * If the set fails, chances are that the printer only supports a
+ * single configuration. Technically these printers don't conform to
+ * the USB printer specification, but otherwise they'll work...
+ */
+
+ if (errno != EBUSY)
+ fprintf(stderr, "DEBUG: Failed to set configuration %d for %04x:%04x\n",
+ number, printer->device->descriptor.idVendor,
+ printer->device->descriptor.idProduct);
+ }
+
+ /*
+ * Claim interfaces as needed...
+ */
+
+ number = printer->device->config[printer->conf].interface[printer->iface].
+ altsetting[printer->altset].bInterfaceNumber;
+ while (usb_claim_interface(printer->handle, number) < 0)
+ {
+ if (errno != EBUSY)
+ fprintf(stderr, "DEBUG: Failed to claim interface %d for %04x:%04x: %s\n",
+ number, printer->device->descriptor.idVendor,
+ printer->device->descriptor.idProduct, strerror(errno));
+
+ goto error;
+ }
+
+#if 0 /* STR #3801: Claiming interface 0 causes problems with some printers */
+ if (number != 0)
+ while (usb_claim_interface(printer->handle, 0) < 0)
+ {
+ if (errno != EBUSY)
+ fprintf(stderr, "DEBUG: Failed to claim interface 0 for %04x:%04x: %s\n",
+ printer->device->descriptor.idVendor,
+ printer->device->descriptor.idProduct, strerror(errno));
+
+ goto error;
+ }
+#endif /* 0 */
+
+ /*
+ * Set alternate setting...
+ */
+
+ number = printer->device->config[printer->conf].interface[printer->iface].
+ altsetting[printer->altset].bAlternateSetting;
+ while (usb_set_altinterface(printer->handle, number) < 0)
+ {
+ if (errno != EBUSY)
+ fprintf(stderr,
+ "DEBUG: Failed to set alternate interface %d for %04x:%04x: %s\n",
+ number, printer->device->descriptor.idVendor,
+ printer->device->descriptor.idProduct, strerror(errno));
+
+ goto error;
+ }
+
+ if (verbose)
+ fputs("STATE: -connecting-to-device\n", stderr);
+
+ return (0);
+
+ /*
+ * If we get here, there was a hard error...
+ */
+
+ error:
+
+ if (verbose)
+ fputs("STATE: -connecting-to-device\n", stderr);
+
+ usb_close(printer->handle);
+ printer->handle = NULL;
+
+ return (-1);
+}
+
+
+/*
+ * 'print_cb()' - Find a USB printer for printing.
+ */
+
+static int /* O - 0 to continue, 1 to stop (found) */
+print_cb(usb_printer_t *printer, /* I - Printer */
+ const char *device_uri, /* I - Device URI */
+ const char *device_id, /* I - IEEE-1284 device ID */
+ const void *data) /* I - User data (make, model, S/N) */
+{
+ return (!strcmp((char *)data, device_uri));
+}
+
+
+/*
+ * 'side_cb()' - Handle side-channel requests.
+ */
+
+static ssize_t /* O - Number of bytes written */
+side_cb(usb_printer_t *printer, /* I - Printer */
+ int print_fd) /* I - File to print */
+{
+ ssize_t bytes, /* Bytes read/written */
+ tbytes; /* Total bytes written */
+ char buffer[512]; /* Print data buffer */
+ struct pollfd pfd; /* Poll descriptor */
+ cups_sc_command_t command; /* Request command */
+ cups_sc_status_t status; /* Request/response status */
+ char data[2048]; /* Request/response data */
+ int datalen; /* Request/response data size */
+
+
+ tbytes = 0;
+ datalen = sizeof(data);
+
+ if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
+ return (-1);
+
+ switch (command)
+ {
+ case CUPS_SC_CMD_DRAIN_OUTPUT :
+ pfd.fd = print_fd;
+ pfd.events = POLLIN;
+
+ while (poll(&pfd, 1, 1000) > 0)
+ {
+ if ((bytes = read(print_fd, buffer, sizeof(buffer))) > 0)
+ {
+ while (usb_bulk_write(printer->handle, printer->write_endp, buffer,
+ bytes, 5000) < 0)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to send data to printer."));
+ tbytes = -1;
+ break;
+ }
+
+ tbytes += bytes;
+ }
+ else if (bytes < 0 && errno != EAGAIN && errno != EINTR)
+ break;
+ }
+
+ if (tbytes < 0)
+ status = CUPS_SC_STATUS_IO_ERROR;
+ else
+ status = CUPS_SC_STATUS_OK;
+
+ datalen = 0;
+ break;
+
+ case CUPS_SC_CMD_GET_BIDI :
+ status = CUPS_SC_STATUS_OK;
+ data[0] = 0; /* TODO: Change to 1 when read supported */
+ datalen = 1;
+ break;
+
+ case CUPS_SC_CMD_GET_DEVICE_ID :
+ if (get_device_id(printer, data, sizeof(data)))
+ {
+ status = CUPS_SC_STATUS_IO_ERROR;
+ datalen = 0;
+ }
+ else
+ {
+ status = CUPS_SC_STATUS_OK;
+ datalen = strlen(data);
+ }
+ break;
+
+ default :
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ datalen = 0;
+ break;
+ }
+
+ cupsSideChannelWrite(command, status, data, datalen, 1.0);
+
+ return (tbytes);
+}
+
+
+/*
+ * End of "$Id$".
+ */
+
diff --git a/backend/usb-unix.c b/backend/usb-unix.c
new file mode 100644
index 000000000..b0365e470
--- /dev/null
+++ b/backend/usb-unix.c
@@ -0,0 +1,623 @@
+/*
+ * "$Id$"
+ *
+ * USB port backend for CUPS.
+ *
+ * This file is included from "usb.c" when compiled on UNIX/Linux.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * print_device() - Print a file to a USB device.
+ * list_devices() - List all USB devices.
+ * open_device() - Open a USB device...
+ * side_cb() - Handle side-channel requests...
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <sys/select.h>
+
+
+/*
+ * Local functions...
+ */
+
+static int open_device(const char *uri, int *use_bc);
+static int side_cb(int print_fd, int device_fd, int snmp_fd,
+ http_addr_t *addr, int use_bc);
+
+
+/*
+ * '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 */
+ char *options, /* I - Device options/serial number */
+ int print_fd, /* I - File descriptor to print */
+ int copies, /* I - Copies to print */
+ int argc, /* I - Number of command-line arguments (6 or 7) */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int use_bc; /* Use backchannel path? */
+ int device_fd; /* USB device */
+ ssize_t tbytes; /* Total number of bytes written */
+ struct termios opts; /* Parallel port options */
+
+
+ (void)argc;
+ (void)argv;
+
+ /*
+ * Open the USB port device...
+ */
+
+ fputs("STATE: +connecting-to-device\n", stderr);
+
+ do
+ {
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+ /*
+ * *BSD's ulpt driver currently does not support the
+ * back-channel, incorrectly returns data ready on a select(),
+ * and locks up on read()...
+ */
+
+ use_bc = 0;
+
+#elif defined(__sun)
+ /*
+ * CUPS STR #3028: Solaris' usbprn driver apparently does not support
+ * select() or poll(), so we can't support backchannel...
+ */
+
+ use_bc = 0;
+
+#else
+ /*
+ * Disable backchannel data when printing to Brother, Canon, or
+ * Minolta USB printers - apparently these printers will return
+ * the IEEE-1284 device ID over and over and over when they get
+ * a read request...
+ */
+
+ use_bc = _cups_strcasecmp(hostname, "Brother") &&
+ _cups_strcasecmp(hostname, "Canon") &&
+ _cups_strncasecmp(hostname, "Konica", 6) &&
+ _cups_strncasecmp(hostname, "Minolta", 7);
+#endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __DragonFly__ */
+
+ if ((device_fd = open_device(uri, &use_bc)) == -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.
+ */
+
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Unable to contact printer, queuing on next "
+ "printer in class."));
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ if (errno == EBUSY)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printer busy, will retry in 10 seconds."));
+ sleep(10);
+ }
+ else if (errno == ENXIO || errno == EIO || errno == ENOENT ||
+ errno == ENODEV)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printer not connected, will retry in 30 "
+ "seconds."));
+ sleep(30);
+ }
+ else
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open device file"));
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+ }
+ while (device_fd < 0);
+
+ fputs("STATE: -connecting-to-device\n", stderr);
+
+ /*
+ * Set any options provided...
+ */
+
+ tcgetattr(device_fd, &opts);
+
+ opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
+
+ /**** No options supported yet ****/
+
+ tcsetattr(device_fd, TCSANOW, &opts);
+
+ /*
+ * Finally, send the print file...
+ */
+
+ tbytes = 0;
+
+ while (copies > 0 && tbytes >= 0)
+ {
+ copies --;
+
+ if (print_fd != 0)
+ {
+ fputs("PAGE: 1 1\n", stderr);
+ lseek(print_fd, 0, SEEK_SET);
+ }
+
+#ifdef __sun
+ /*
+ * CUPS STR #3028: Solaris' usbprn driver apparently does not support
+ * select() or poll(), so we can't support the sidechannel either...
+ */
+
+ tbytes = backendRunLoop(print_fd, device_fd, -1, NULL, use_bc, 1, NULL);
+
+#else
+ tbytes = backendRunLoop(print_fd, device_fd, -1, NULL, use_bc, 1, side_cb);
+#endif /* __sun */
+
+ if (print_fd != 0 && tbytes >= 0)
+ _cupsLangPrintFilter(stderr, "INFO", _("Print file sent."));
+ }
+
+ /*
+ * Close the USB port and return...
+ */
+
+ close(device_fd);
+
+ return (CUPS_BACKEND_OK);
+}
+
+
+/*
+ * 'list_devices()' - List all USB devices.
+ */
+
+void
+list_devices(void)
+{
+#ifdef __linux
+ int i; /* Looping var */
+ int fd; /* File descriptor */
+ char device[255], /* Device filename */
+ device_id[1024], /* Device ID string */
+ device_uri[1024], /* Device URI string */
+ make_model[1024]; /* Make and model */
+
+
+ /*
+ * Try to open each USB device...
+ */
+
+ for (i = 0; i < 16; i ++)
+ {
+ /*
+ * Linux has a long history of changing the standard filenames used
+ * for USB printer devices. We get the honor of trying them all...
+ */
+
+ sprintf(device, "/dev/usblp%d", i);
+
+ if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
+ {
+ if (errno != ENOENT)
+ continue;
+
+ sprintf(device, "/dev/usb/lp%d", i);
+
+ if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
+ {
+ if (errno != ENOENT)
+ continue;
+
+ sprintf(device, "/dev/usb/usblp%d", i);
+
+ if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
+ continue;
+ }
+ }
+
+ if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
+ make_model, sizeof(make_model),
+ "usb", device_uri, sizeof(device_uri)))
+ cupsBackendReport("direct", device_uri, make_model, make_model,
+ device_id, NULL);
+
+ 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 */
+
+
+ /*
+ * Open each USB device...
+ */
+
+ for (i = 0; i < 8; i ++)
+ {
+ sprintf(device, "/dev/usb/printer%d", i);
+
+ if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0)
+ {
+ if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
+ make_model, sizeof(make_model),
+ "usb", device_uri, sizeof(device_uri)))
+ cupsBackendReport("direct", device_uri, make_model, make_model,
+ device_id, NULL);
+
+ close(fd);
+ }
+ }
+#elif defined(__hpux)
+#elif defined(__osf)
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+ 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...
+ */
+
+static int /* O - File descriptor or -1 on error */
+open_device(const char *uri, /* I - Device URI */
+ int *use_bc) /* O - Set to 0 for unidirectional */
+{
+ int fd; /* File descriptor */
+
+
+ /*
+ * 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
+ {
+ /*
+ * Do not allow direct devices anymore...
+ */
+
+ errno = ENODEV;
+ return (-1);
+ }
+ 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? */
+ char device[255], /* Device filename */
+ device_id[1024], /* Device ID string */
+ make_model[1024], /* Make and model */
+ device_uri[1024]; /* Device URI string */
+
+
+ /*
+ * Find the correct USB device...
+ */
+
+ for (;;)
+ {
+ for (busy = 0, i = 0; i < 16; i ++)
+ {
+ /*
+ * Linux has a long history of changing the standard filenames used
+ * for USB printer devices. We get the honor of trying them all...
+ */
+
+ sprintf(device, "/dev/usblp%d", i);
+
+ if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
+ {
+ sprintf(device, "/dev/usb/lp%d", i);
+
+ if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
+ {
+ sprintf(device, "/dev/usb/usblp%d", i);
+
+ if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
+ continue;
+ }
+ }
+
+ if (fd >= 0)
+ {
+ backendGetDeviceID(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)
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printer is busy, will retry in 5 seconds."));
+
+ sleep(5);
+ }
+ }
+#elif defined(__sun) && defined(ECPPIOC_GETDEVID)
+ {
+ /*
+ * Do not allow direct devices anymore...
+ */
+
+ errno = ENODEV;
+ return (-1);
+ }
+ 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? */
+ char device[255], /* Device filename */
+ device_id[1024], /* Device ID string */
+ make_model[1024], /* Make and model */
+ device_uri[1024]; /* Device URI string */
+
+
+ /*
+ * 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_WRONLY | O_EXCL)) >= 0)
+ backendGetDeviceID(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...
+ */
+
+ fputs("DEBUG: Setting use_bc to 0!\n", stderr);
+
+ *use_bc = 0;
+
+ 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)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printer is busy, will retry in 5 seconds."));
+ sleep(5);
+ }
+ }
+ while (busy);
+
+ /*
+ * Couldn't find the printer, return "no such device or address"...
+ */
+
+ errno = ENODEV;
+
+ return (-1);
+ }
+#else
+ {
+ if (*use_bc)
+ fd = open(uri + 4, O_RDWR | O_EXCL);
+ else
+ fd = -1;
+
+ if (fd < 0)
+ {
+ fd = open(uri + 4, O_WRONLY | O_EXCL);
+ *use_bc = 0;
+ }
+
+ return (fd);
+ }
+#endif /* __linux */
+ else
+ {
+ errno = ENODEV;
+ return (-1);
+ }
+}
+
+
+/*
+ * 'side_cb()' - Handle side-channel requests...
+ */
+
+static int /* O - 0 on success, -1 on error */
+side_cb(int print_fd, /* I - Print file */
+ int device_fd, /* I - Device file */
+ int snmp_fd, /* I - SNMP socket (unused) */
+ http_addr_t *addr, /* I - Device address (unused) */
+ int use_bc) /* I - Using back-channel? */
+{
+ cups_sc_command_t command; /* Request command */
+ cups_sc_status_t status; /* Request/response status */
+ char data[2048]; /* Request/response data */
+ int datalen; /* Request/response data size */
+
+
+ (void)snmp_fd;
+ (void)addr;
+
+ datalen = sizeof(data);
+
+ if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
+ return (-1);
+
+ switch (command)
+ {
+ case CUPS_SC_CMD_DRAIN_OUTPUT :
+ if (backendDrainOutput(print_fd, device_fd))
+ status = CUPS_SC_STATUS_IO_ERROR;
+ else if (tcdrain(device_fd))
+ status = CUPS_SC_STATUS_IO_ERROR;
+ else
+ status = CUPS_SC_STATUS_OK;
+
+ datalen = 0;
+ break;
+
+ case CUPS_SC_CMD_GET_BIDI :
+ status = CUPS_SC_STATUS_OK;
+ data[0] = use_bc;
+ datalen = 1;
+ break;
+
+ case CUPS_SC_CMD_GET_DEVICE_ID :
+ memset(data, 0, sizeof(data));
+
+ if (backendGetDeviceID(device_fd, data, sizeof(data) - 1,
+ NULL, 0, NULL, NULL, 0))
+ {
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ datalen = 0;
+ }
+ else
+ {
+ status = CUPS_SC_STATUS_OK;
+ datalen = strlen(data);
+ }
+ break;
+
+ default :
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ datalen = 0;
+ break;
+ }
+
+ return (cupsSideChannelWrite(command, status, data, datalen, 1.0));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/backend/usb.c b/backend/usb.c
new file mode 100644
index 000000000..d72535e93
--- /dev/null
+++ b/backend/usb.c
@@ -0,0 +1,264 @@
+/*
+ * "$Id$"
+ *
+ * USB port backend for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "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 <ApplicationServices/ApplicationServices.h>
+#endif /* __APPLE__ */
+
+#include "backend-private.h"
+
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+# include <fcntl.h>
+# include <termios.h>
+#endif /* WIN32 */
+
+
+/*
+ * Local functions...
+ */
+
+void list_devices(void);
+int print_device(const char *uri, const char *hostname,
+ const char *resource, char *options,
+ int print_fd, int copies, int argc, char *argv[]);
+
+
+/*
+ * Include the vendor-specific USB implementation...
+ */
+
+#ifdef HAVE_USB_H
+# include "usb-libusb.c"
+#elif defined(__APPLE__)
+# include "usb-darwin.c"
+#elif defined(__linux) || defined(__sun) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+# 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 */
+ char *options, /* I - Device options/serial number */
+ int print_fd, /* I - File descriptor to print */
+ int copies, /* I - Copies to print */
+ int argc, /* I - Number of command-line arguments (6 or 7) */
+ char *argv[]) /* I - Command-line arguments */
+{
+ /*
+ * 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)print_fd;
+ (void)copies;
+ (void)argc;
+ (void)argv;
+
+ 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 print_fd; /* 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)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options [file]"),
+ argv[0]);
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ /*
+ * Extract the device name and options from the URI...
+ */
+
+ uri = cupsBackendDeviceURI(argv);
+
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, uri,
+ method, sizeof(method), username, sizeof(username),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(resource)) < HTTP_URI_OK)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("No device URI found in argv[0] or in DEVICE_URI "
+ "environment variable."));
+ return (1);
+ }
+
+ /*
+ * 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)
+ {
+ print_fd = 0;
+ copies = 1;
+ }
+ else
+ {
+ /*
+ * Try to open the print file...
+ */
+
+ if ((print_fd = open(argv[6], O_RDONLY)) < 0)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ copies = atoi(argv[4]);
+ }
+
+ /*
+ * Finally, send the print file...
+ */
+
+ status = print_device(uri, hostname, resource, options, print_fd, copies,
+ argc, argv);
+
+ /*
+ * Close the input file and return...
+ */
+
+ if (print_fd != 0)
+ close(print_fd);
+
+ return (status);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/berkeley/Dependencies b/berkeley/Dependencies
new file mode 100644
index 000000000..de9ba9799
--- /dev/null
+++ b/berkeley/Dependencies
@@ -0,0 +1,34 @@
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+lpc.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+lpc.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+lpc.o: ../cups/language.h ../cups/string-private.h ../config.h
+lpc.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+lpc.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+lpc.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+lpc.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+lpc.o: ../cups/thread-private.h
+lpq.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+lpq.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+lpq.o: ../cups/language.h ../cups/string-private.h ../config.h
+lpq.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+lpq.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+lpq.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+lpq.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+lpq.o: ../cups/thread-private.h
+lpr.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+lpr.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+lpr.o: ../cups/language.h ../cups/string-private.h ../config.h
+lpr.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+lpr.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+lpr.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+lpr.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+lpr.o: ../cups/thread-private.h
+lprm.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+lprm.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+lprm.o: ../cups/language.h ../cups/string-private.h ../config.h
+lprm.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+lprm.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+lprm.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+lprm.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+lprm.o: ../cups/thread-private.h
diff --git a/berkeley/Makefile b/berkeley/Makefile
new file mode 100644
index 000000000..3f6810916
--- /dev/null
+++ b/berkeley/Makefile
@@ -0,0 +1,167 @@
+#
+# "$Id$"
+#
+# Berkeley commands makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2006 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "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)
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# 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-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+
+
+#
+# Install programs...
+#
+
+install-exec:
+ echo Installing Berkeley user printing commands in $(BINDIR)...
+ $(INSTALL_DIR) -m 755 $(BINDIR)
+ $(INSTALL_BIN) lpq $(BINDIR)
+ $(INSTALL_BIN) lpr $(BINDIR)
+ $(INSTALL_BIN) lprm $(BINDIR)
+ echo Installing Berkeley admin printing commands in $(BINDIR)...
+ $(INSTALL_DIR) -m 755 $(SBINDIR)
+ $(INSTALL_BIN) lpc $(SBINDIR)
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ for file in $(TARGETS); do \
+ cp $$file $(SYMROOT); \
+ done \
+ fi
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall all targets...
+#
+
+uninstall:
+ $(RM) $(BINDIR)/lpq
+ $(RM) $(BINDIR)/lpr
+ $(RM) $(BINDIR)/lprm
+ $(RM) $(SBINDIR)/lpc
+ -$(RMDIR) $(SBINDIR)
+ -$(RMDIR) $(BINDIR)
+
+
+#
+# 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$".
+#
diff --git a/berkeley/lpc.c b/berkeley/lpc.c
new file mode 100644
index 000000000..e410d0b58
--- /dev/null
+++ b/berkeley/lpc.c
@@ -0,0 +1,449 @@
+/*
+ * "$Id$"
+ *
+ * "lpc" command for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "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 <cups/cups-private.h>
+
+
+/*
+ * 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 */
+
+
+ _cupsSetLocale(argv);
+
+ /*
+ * 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...
+ */
+
+ _cupsLangPuts(stdout, _("lpc> ")); /* TODO: Need no-newline version */
+ 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...
+ */
+
+ _cupsLangPuts(stdout, _("lpc> ")); /* TODO: Need no newline version */
+ 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...
+ */
+
+ _cupsLangPuts(stdout, _("lpc> ")); /* TODO: Need no newline version */
+ }
+ }
+
+ /*
+ * 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,
+ _("%s is not implemented by the CUPS version of lpc."),
+ command);
+}
+
+
+/*
+ * 'show_help()' - Show help messages.
+ */
+
+static void
+show_help(const char *command) /* I - Command to describe or NULL */
+{
+ if (!command)
+ {
+ _cupsLangPrintf(stdout,
+ _("Commands may be abbreviated. Commands are:\n"
+ "\n"
+ "exit help quit status ?"));
+ }
+ else if (!compare_strings(command, "help", 1) || !strcmp(command, "?"))
+ _cupsLangPrintf(stdout, _("help\t\tGet help on commands."));
+ else if (!compare_strings(command, "status", 4))
+ _cupsLangPrintf(stdout, _("status\t\tShow status of daemon and queue."));
+ else
+ _cupsLangPrintf(stdout, _("?Invalid help command unknown."));
+}
+
+
+/*
+ * '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 */
+ ipp_attribute_t *attr; /* Current attribute */
+ 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 */
+ static const char *requested[] = /* Requested attributes */
+ {
+ "device-uri",
+ "printer-is-accepting-jobs",
+ "printer-name",
+ "printer-state",
+ "queued-job-count"
+ };
+
+
+ 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 = ippNewRequest(CUPS_GET_PRINTERS);
+
+ 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, "device-uri") &&
+ attr->value_tag == IPP_TAG_URI)
+ device = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "printer-is-accepting-jobs") &&
+ attr->value_tag == IPP_TAG_BOOLEAN)
+ accepting = attr->values[0].boolean;
+ else if (!strcmp(attr->name, "printer-name") &&
+ attr->value_tag == IPP_TAG_NAME)
+ printer = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "printer-state") &&
+ attr->value_tag == IPP_TAG_ENUM)
+ pstate = (ipp_pstate_t)attr->values[0].integer;
+ else if (!strcmp(attr->name, "queued-job-count") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ jobcount = attr->values[0].integer;
+
+ 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)
+ {
+ /*
+ * Display it...
+ */
+
+ printf("%s:\n", printer);
+ if (!strncmp(device, "file:", 5))
+ _cupsLangPrintf(stdout,
+ _("\tprinter is on device \'%s\' speed -1"),
+ device + 5);
+ else
+ {
+ /*
+ * Just show the scheme...
+ */
+
+ if ((delimiter = strchr(device, ':')) != NULL )
+ {
+ *delimiter = '\0';
+ _cupsLangPrintf(stdout,
+ _("\tprinter is on device \'%s\' speed -1"),
+ device);
+ }
+ }
+
+ if (accepting)
+ _cupsLangPuts(stdout, _("\tqueuing is enabled"));
+ else
+ _cupsLangPuts(stdout, _("\tqueuing is disabled"));
+
+ if (pstate != IPP_PRINTER_STOPPED)
+ _cupsLangPuts(stdout, _("\tprinting is enabled"));
+ else
+ _cupsLangPuts(stdout, _("\tprinting is disabled"));
+
+ if (jobcount == 0)
+ _cupsLangPuts(stdout, _("\tno entries"));
+ else
+ _cupsLangPrintf(stdout, _("\t%d entries"), jobcount);
+
+ _cupsLangPuts(stdout, _("\tdaemon present"));
+ }
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/berkeley/lpq.c b/berkeley/lpq.c
new file mode 100644
index 000000000..c0b7f43a0
--- /dev/null
+++ b/berkeley/lpq.c
@@ -0,0 +1,678 @@
+/*
+ * "$Id$"
+ *
+ * "lpq" command for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "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 <cups/cups-private.h>
+
+
+/*
+ * Local functions...
+ */
+
+static http_t *connect_server(const char *, http_t *);
+static int show_jobs(const char *, http_t *, const char *,
+ const char *, const int, const int);
+static void show_printer(const char *, 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 */
+
+
+ _cupsSetLocale(argv);
+
+ /*
+ * Check for command-line options...
+ */
+
+ http = NULL;
+ dest = NULL;
+ user = NULL;
+ id = 0;
+ interval = 0;
+ longstatus = 0;
+ all = 0;
+ num_dests = 0;
+ dests = NULL;
+
+ 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
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+
+ if (http)
+ httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
+#else
+ _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
+ argv[0]);
+#endif /* HAVE_SSL */
+ break;
+
+ case 'U' : /* Username */
+ if (argv[i][2] != '\0')
+ cupsSetUser(argv[i] + 2);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected username after "
+ "\"-U\" option."), argv[0]);
+ return (1);
+ }
+
+ cupsSetUser(argv[i]);
+ }
+ 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';
+
+ http = connect_server(argv[0], http);
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests2(http, &dests);
+
+ if (cupsGetDest(dest, instance, num_dests, dests) == NULL)
+ {
+ if (instance)
+ _cupsLangPrintf(stderr,
+ _("%s: Error - unknown destination \"%s/%s\"."),
+ argv[0], dest, instance);
+ else
+ _cupsLangPrintf(stderr, _("%s: Unknown destination \"%s\"."),
+ argv[0], dest);
+
+ return (1);
+ }
+ break;
+
+ case 'a' : /* All printers */
+ all = 1;
+ break;
+
+ case 'h' : /* Connect to host */
+ if (http)
+ {
+ httpClose(http);
+ http = NULL;
+ }
+
+ if (argv[i][2] != '\0')
+ cupsSetServer(argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected hostname after "
+ "\"-h\" option."), argv[0]);
+ return (1);
+ }
+ else
+ cupsSetServer(argv[i]);
+ }
+ 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];
+
+ http = connect_server(argv[0], http);
+
+ if (dest == NULL && !all)
+ {
+ if (num_dests == 0)
+ num_dests = cupsGetDests2(http, &dests);
+
+ 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,
+ _("%s: Error - %s environment variable names "
+ "non-existent destination \"%s\"."), argv[0], val,
+ dest);
+ else
+ _cupsLangPrintf(stderr,
+ _("%s: Error - no default destination available."),
+ argv[0]);
+ httpClose(http);
+ cupsFreeDests(num_dests, dests);
+ return (1);
+ }
+ }
+
+ /*
+ * Show the status in a loop...
+ */
+
+ for (;;)
+ {
+ if (dest)
+ show_printer(argv[0], http, dest);
+
+ i = show_jobs(argv[0], 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);
+}
+
+
+/*
+ * 'connect_server()' - Connect to the server as necessary...
+ */
+
+static http_t * /* O - New HTTP connection */
+connect_server(const char *command, /* I - Command name */
+ http_t *http) /* I - Current HTTP connection */
+{
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption());
+
+ if (http == NULL)
+ {
+ _cupsLangPrintf(stderr, _("%s: Unable to connect to server."), command);
+ exit(1);
+ }
+ }
+
+ return (http);
+}
+
+
+/*
+ * 'show_jobs()' - Show jobs.
+ */
+
+static int /* O - Number of jobs in queue */
+show_jobs(const char *command, /* I - Command name */
+ 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 */
+ 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 * const jobattrs[] =/* Job attributes we want to see */
+ {
+ "copies",
+ "job-id",
+ "job-k-octets",
+ "job-name",
+ "job-originating-user-name",
+ "job-printer-uri",
+ "job-priority",
+ "job-state"
+ };
+ static const char * const ranks[10] = /* Ranking strings */
+ {
+ "th",
+ "st",
+ "nd",
+ "rd",
+ "th",
+ "th",
+ "th",
+ "th",
+ "th",
+ "th"
+ };
+
+
+ DEBUG_printf(("show_jobs(http=%p, dest=%p, user=%p, id=%d, longstatus%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
+ * requested-attributes
+ */
+
+ request = ippNewRequest(id ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS);
+
+ if (id)
+ {
+ snprintf(resource, sizeof(resource), "ipp://localhost/jobs/%d", id);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
+ NULL, resource);
+ }
+ else if (dest)
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, resource, sizeof(resource), "ipp",
+ NULL, "localhost", 0, "/printers/%s", dest);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, resource);
+ }
+ else
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, "ipp://localhost/");
+
+ if (user)
+ {
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+ ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
+ }
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ (int)(sizeof(jobattrs) / sizeof(jobattrs[0])), NULL, jobattrs);
+
+ /*
+ * 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, "%s: %s", command, cupsLastErrorString());
+ 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") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ jobid = attr->values[0].integer;
+
+ if (!strcmp(attr->name, "job-k-octets") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ jobsize = attr->values[0].integer;
+
+#ifdef __osf__
+ if (!strcmp(attr->name, "job-priority") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ jobpriority = attr->values[0].integer;
+#endif /* __osf__ */
+
+ if (!strcmp(attr->name, "job-state") &&
+ attr->value_tag == IPP_TAG_ENUM)
+ jobstate = (ipp_jstate_t)attr->values[0].integer;
+
+ if (!strcmp(attr->name, "job-printer-uri") &&
+ attr->value_tag == IPP_TAG_URI)
+ if ((jobdest = strrchr(attr->values[0].string.text, '/')) != NULL)
+ jobdest ++;
+
+ if (!strcmp(attr->name, "job-originating-user-name") &&
+ attr->value_tag == IPP_TAG_NAME)
+ jobuser = attr->values[0].string.text;
+
+ if (!strcmp(attr->name, "job-name") &&
+ attr->value_tag == IPP_TAG_NAME)
+ jobname = attr->values[0].string.text;
+
+ if (!strcmp(attr->name, "copies") &&
+ 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,
+ /* TRANSLATORS: Pri is job priority. */
+ _("Rank Owner Pri Job Files"
+ " Total Size"));
+#else
+ _cupsLangPuts(stdout,
+ _("Rank Owner Job File(s)"
+ " Total Size"));
+#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, "\n");
+
+ if (jobcopies > 1)
+ snprintf(namestr, sizeof(namestr), "%d copies of %s", jobcopies,
+ jobname);
+ else
+ strlcpy(namestr, jobname, sizeof(namestr));
+
+ _cupsLangPrintf(stdout, _("%s: %-33.33s [job %d localhost]"),
+ jobuser, rankstr, jobid);
+ _cupsLangPrintf(stdout, _(" %-39.39s %.0f bytes"),
+ namestr, 1024.0 * jobsize);
+ }
+ else
+#ifdef __osf__
+ _cupsLangPrintf(stdout,
+ _("%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes"),
+ rankstr, jobuser, jobpriority, jobid, jobname,
+ 1024.0 * jobsize);
+#else
+ _cupsLangPrintf(stdout,
+ _("%-7s %-7.7s %-7d %-31.31s %.0f bytes"),
+ rankstr, jobuser, jobid, jobname, 1024.0 * jobsize);
+#endif /* __osf */
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
+ return (0);
+ }
+
+ if (jobcount == 0)
+ _cupsLangPuts(stdout, _("no entries"));
+
+ return (jobcount);
+}
+
+
+/*
+ * 'show_printer()' - Show printer status.
+ */
+
+static void
+show_printer(const char *command, /* I - Command name */
+ 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 */
+ 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 = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, 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, "%s: %s", command, cupsLastErrorString());
+ 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, _("%s is ready"), dest);
+ break;
+ case IPP_PRINTER_PROCESSING :
+ _cupsLangPrintf(stdout, _("%s is ready and printing"),
+ dest);
+ break;
+ case IPP_PRINTER_STOPPED :
+ _cupsLangPrintf(stdout, _("%s is not ready"), dest);
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
+}
+
+
+/*
+ * 'usage()' - Show program usage.
+ */
+
+static void
+usage(void)
+{
+ _cupsLangPuts(stderr,
+ _("Usage: lpq [-P dest] [-U username] [-h hostname[:port]] "
+ "[-l] [+interval]"));
+ exit(1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/berkeley/lpr.c b/berkeley/lpr.c
new file mode 100644
index 000000000..bf4682057
--- /dev/null
+++ b/berkeley/lpr.c
@@ -0,0 +1,417 @@
+/*
+ * "$Id$"
+ *
+ * "lpr" command for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Parse options and send files for printing.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * '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 */
+ cups_dest_t *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 */
+
+
+ _cupsSetLocale(argv);
+
+ deletefile = 0;
+ printer = NULL;
+ dest = NULL;
+ num_options = 0;
+ options = NULL;
+ num_files = 0;
+ title = NULL;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ switch (ch = argv[i][1])
+ {
+ case 'E' : /* Encrypt */
+#ifdef HAVE_SSL
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+#else
+ _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
+ argv[0]);
+#endif /* HAVE_SSL */
+ break;
+
+ case 'U' : /* Username */
+ if (argv[i][2] != '\0')
+ cupsSetUser(argv[i] + 2);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected username after "
+ "\"-U\" option."), argv[0]);
+ return (1);
+ }
+
+ cupsSetUser(argv[i]);
+ }
+ break;
+
+ case 'H' : /* Connect to host */
+ if (argv[i][2] != '\0')
+ cupsSetServer(argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected hostname after "
+ "\"-H\" option."), argv[0]);
+ return (1);
+ }
+ else
+ cupsSetServer(argv[i]);
+ }
+ 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,
+ _("%s: Error - expected value after \"-%c\" "
+ "option."), argv[0], 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,
+ _("%s: Warning - \"%c\" format modifier not "
+ "supported - output may not be correct."),
+ argv[0], ch);
+ break;
+
+ case 'o' : /* Option */
+ if (argv[i][2] != '\0')
+ num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected option=value after "
+ "\"-o\" option."), argv[0]);
+ return (1);
+ }
+
+ num_options = cupsParseOptions(argv[i], num_options, &options);
+ }
+ break;
+
+ case 'l' : /* Literal/raw */
+ num_options = cupsAddOption("raw", "true", num_options, &options);
+ break;
+
+ case 'p' : /* Prettyprint */
+ num_options = cupsAddOption("prettyprint", "true", 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 */
+ {
+ char email[1024]; /* EMail address */
+
+
+ snprintf(email, sizeof(email), "mailto:%s@%s", cupsUser(),
+ httpGetHostname(NULL, buffer, sizeof(buffer)));
+ num_options = cupsAddOption("notify-recipient-uri", email,
+ num_options, &options);
+ }
+ 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)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected destination after "
+ "\"-P\" option."), argv[0]);
+ return (1);
+ }
+
+ printer = argv[i];
+ }
+
+ if ((instance = strrchr(printer, '/')) != NULL)
+ *instance++ = '\0';
+
+ if ((dest = cupsGetNamedDest(NULL, printer, instance)) != 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)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected copies after "
+ "\"-#\" option."), argv[0]);
+ 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,
+ _("%s: Error - expected name after \"-%c\" "
+ "option."), argv[0], ch);
+ return (1);
+ }
+
+ title = argv[i];
+ }
+ break;
+
+ default :
+ _cupsLangPrintf(stderr,
+ _("%s: Error - unknown option \"%c\"."), argv[0],
+ argv[i][1]);
+ return (1);
+ }
+ else if (num_files < 1000)
+ {
+ /*
+ * Print a file...
+ */
+
+ if (access(argv[i], R_OK) != 0)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - unable to access \"%s\" - %s"),
+ argv[0], 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,
+ _("%s: Error - too many files - \"%s\"."), argv[0],
+ argv[i]);
+ /*
+ * See if we have any files to print; if not, print from stdin...
+ */
+
+ if (printer == NULL)
+ {
+ if ((dest = cupsGetNamedDest(NULL, NULL, NULL)) != 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 && !cupsGetNamedDest(NULL, printer, NULL))
+ _cupsLangPrintf(stderr,
+ _("%s: Error - %s environment variable names "
+ "non-existent destination \"%s\"."), argv[0], val,
+ printer);
+ else if (cupsLastError() == IPP_NOT_FOUND)
+ _cupsLangPrintf(stderr,
+ _("%s: Error - no default destination available."),
+ argv[0]);
+ else
+ _cupsLangPrintf(stderr, _("%s: Error - scheduler not responding."),
+ argv[0]);
+
+ 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 if ((job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, printer,
+ title ? title : "(stdin)",
+ num_options, options)) > 0)
+ {
+ http_status_t status; /* Write status */
+ const char *format; /* Document format */
+ ssize_t bytes; /* Bytes read */
+
+
+ if (cupsGetOption("raw", num_options, options))
+ format = CUPS_FORMAT_RAW;
+ else if ((format = cupsGetOption("document-format", num_options,
+ options)) == NULL)
+ format = CUPS_FORMAT_AUTO;
+
+ status = cupsStartDocument(CUPS_HTTP_DEFAULT, printer, job_id, NULL,
+ format, 1);
+
+ while (status == HTTP_CONTINUE &&
+ (bytes = read(0, buffer, sizeof(buffer))) > 0)
+ status = cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, bytes);
+
+ if (status != HTTP_CONTINUE)
+ {
+ _cupsLangPrintf(stderr, _("%s: Error - unable to queue from stdin - %s."),
+ argv[0], httpStatus(status));
+ return (1);
+ }
+
+ if (cupsFinishDocument(CUPS_HTTP_DEFAULT, printer) != IPP_OK)
+ job_id = 0;
+ }
+
+ if (job_id < 1)
+ {
+ _cupsLangPrintf(stderr, "%s: %s", argv[0], cupsLastErrorString());
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/berkeley/lprm.c b/berkeley/lprm.c
new file mode 100644
index 000000000..e2d03e359
--- /dev/null
+++ b/berkeley/lprm.c
@@ -0,0 +1,217 @@
+/*
+ * "$Id$"
+ *
+ * "lprm" command for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Parse options and cancel jobs.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * '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 */
+{
+ int i; /* Looping var */
+ int job_id; /* Job ID */
+ const char *name; /* Destination printer */
+ char *instance; /* Pointer to instance name */
+ cups_dest_t *dest, /* Destination */
+ *defdest; /* Default destination */
+ int did_cancel; /* Did we cancel something? */
+
+
+ _cupsSetLocale(argv);
+
+ /*
+ * Setup to cancel individual print jobs...
+ */
+
+ did_cancel = 0;
+ defdest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, NULL, NULL);
+ name = defdest ? defdest->name : NULL;
+
+ /*
+ * 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
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+#else
+ _cupsLangPrintf(stderr,
+ _("%s: Sorry, no encryption support."), argv[0]);
+#endif /* HAVE_SSL */
+ break;
+
+ case 'P' : /* Cancel jobs on a printer */
+ if (argv[i][2])
+ name = argv[i] + 2;
+ else
+ {
+ i ++;
+ name = argv[i];
+ }
+
+ if ((instance = strchr(name, '/')) != NULL)
+ *instance = '\0';
+
+ if ((dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, name,
+ NULL)) == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - unknown destination \"%s\"."),
+ argv[0], name);
+ goto error;
+ }
+
+ cupsFreeDests(1, dest);
+ break;
+
+ case 'U' : /* Username */
+ if (argv[i][2] != '\0')
+ cupsSetUser(argv[i] + 2);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected username after "
+ "\"-U\" option."), argv[0]);
+ goto error;
+ }
+
+ cupsSetUser(argv[i]);
+ }
+ break;
+
+ case 'h' : /* Connect to host */
+ if (argv[i][2] != '\0')
+ cupsSetServer(argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected hostname after "
+ "\"-h\" option."), argv[0]);
+ goto error;
+ }
+ else
+ cupsSetServer(argv[i]);
+ }
+
+ if (defdest)
+ cupsFreeDests(1, defdest);
+
+ defdest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, NULL, NULL);
+ name = defdest ? defdest->name : NULL;
+ break;
+
+ default :
+ _cupsLangPrintf(stderr, _("%s: Error - unknown option \"%c\"."),
+ argv[0], argv[i][1]);
+ goto error;
+ }
+ else
+ {
+ /*
+ * Cancel a job or printer...
+ */
+
+ if ((dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, argv[i], NULL)) != NULL)
+ cupsFreeDests(1, dest);
+
+ if (dest)
+ {
+ name = argv[i];
+ job_id = 0;
+ }
+ else if (isdigit(argv[i][0] & 255))
+ {
+ name = NULL;
+ job_id = atoi(argv[i]);
+ }
+ else if (!strcmp(argv[i], "-"))
+ {
+ /*
+ * Cancel all jobs
+ */
+
+ job_id = -1;
+ }
+ else
+ {
+ _cupsLangPrintf(stderr, _("%s: Error - unknown destination \"%s\"."),
+ argv[0], argv[i]);
+ goto error;
+ }
+
+ if (cupsCancelJob2(CUPS_HTTP_DEFAULT, name, job_id, 0) != IPP_OK)
+ {
+ _cupsLangPrintf(stderr, "%s: %s", argv[0], cupsLastErrorString());
+ goto error;
+ }
+
+ did_cancel = 1;
+ }
+
+ /*
+ * If nothing has been canceled yet, cancel the current job on the specified
+ * (or default) printer...
+ */
+
+ if (!did_cancel && cupsCancelJob2(CUPS_HTTP_DEFAULT, name, 0, 0) != IPP_OK)
+ {
+ _cupsLangPrintf(stderr, "%s: %s", argv[0], cupsLastErrorString());
+ goto error;
+ }
+
+ if (defdest)
+ cupsFreeDests(1, defdest);
+
+ return (0);
+
+ /*
+ * If we get here there was an error, so clean up...
+ */
+
+ error:
+
+ if (defdest)
+ cupsFreeDests(1, defdest);
+
+ return (1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/Dependencies b/cgi-bin/Dependencies
new file mode 100644
index 000000000..9a5f11d57
--- /dev/null
+++ b/cgi-bin/Dependencies
@@ -0,0 +1,75 @@
+# DO NOT DELETE
+
+help-index.o: cgi-private.h cgi.h ../cups/cups.h ../cups/file.h
+help-index.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+help-index.o: ../cups/array.h ../cups/language.h ../cups/array.h help-index.h
+help-index.o: ../cups/debug-private.h ../cups/language-private.h
+help-index.o: ../cups/transcode.h ../cups/string-private.h ../config.h
+help-index.o: ../cups/dir.h
+html.o: cgi-private.h cgi.h ../cups/cups.h ../cups/file.h
+html.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+html.o: ../cups/language.h ../cups/array.h help-index.h
+html.o: ../cups/debug-private.h ../cups/language-private.h
+html.o: ../cups/transcode.h ../cups/string-private.h ../config.h
+ipp-var.o: cgi-private.h cgi.h ../cups/cups.h ../cups/file.h
+ipp-var.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+ipp-var.o: ../cups/language.h ../cups/array.h help-index.h
+ipp-var.o: ../cups/debug-private.h ../cups/language-private.h
+ipp-var.o: ../cups/transcode.h ../cups/string-private.h ../config.h
+search.o: cgi-private.h cgi.h ../cups/cups.h ../cups/file.h
+search.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+search.o: ../cups/language.h ../cups/array.h help-index.h
+search.o: ../cups/debug-private.h ../cups/language-private.h
+search.o: ../cups/transcode.h ../cups/string-private.h ../config.h
+template.o: cgi-private.h cgi.h ../cups/cups.h ../cups/file.h
+template.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+template.o: ../cups/language.h ../cups/array.h help-index.h
+template.o: ../cups/debug-private.h ../cups/language-private.h
+template.o: ../cups/transcode.h ../cups/string-private.h ../config.h
+var.o: cgi-private.h cgi.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+var.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+var.o: ../cups/array.h help-index.h ../cups/debug-private.h
+var.o: ../cups/language-private.h ../cups/transcode.h
+var.o: ../cups/string-private.h ../config.h ../cups/http.h
+var.o: ../cups/md5-private.h
+admin.o: cgi-private.h cgi.h ../cups/cups.h ../cups/file.h
+admin.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+admin.o: ../cups/language.h ../cups/array.h help-index.h
+admin.o: ../cups/debug-private.h ../cups/language-private.h
+admin.o: ../cups/transcode.h ../cups/string-private.h ../config.h
+admin.o: ../cups/adminutil.h ../cups/cups.h ../cups/ppd.h
+classes.o: cgi-private.h cgi.h ../cups/cups.h ../cups/file.h
+classes.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+classes.o: ../cups/language.h ../cups/array.h help-index.h
+classes.o: ../cups/debug-private.h ../cups/language-private.h
+classes.o: ../cups/transcode.h ../cups/string-private.h ../config.h
+help.o: cgi-private.h cgi.h ../cups/cups.h ../cups/file.h
+help.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+help.o: ../cups/language.h ../cups/array.h help-index.h
+help.o: ../cups/debug-private.h ../cups/language-private.h
+help.o: ../cups/transcode.h ../cups/string-private.h ../config.h
+jobs.o: cgi-private.h cgi.h ../cups/cups.h ../cups/file.h
+jobs.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+jobs.o: ../cups/language.h ../cups/array.h help-index.h
+jobs.o: ../cups/debug-private.h ../cups/language-private.h
+jobs.o: ../cups/transcode.h ../cups/string-private.h ../config.h
+makedocset.o: cgi.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+makedocset.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+makedocset.o: ../cups/array.h help-index.h
+printers.o: cgi-private.h cgi.h ../cups/cups.h ../cups/file.h
+printers.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+printers.o: ../cups/language.h ../cups/array.h help-index.h
+printers.o: ../cups/debug-private.h ../cups/language-private.h
+printers.o: ../cups/transcode.h ../cups/string-private.h ../config.h
+testcgi.o: cgi.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+testcgi.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+testcgi.o: ../cups/array.h help-index.h
+testhi.o: cgi.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+testhi.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+testhi.o: ../cups/array.h help-index.h
+testtemplate.o: cgi.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+testtemplate.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+testtemplate.o: ../cups/language.h ../cups/array.h help-index.h
+websearch.o: cgi.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+websearch.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+websearch.o: ../cups/array.h help-index.h
diff --git a/cgi-bin/Makefile b/cgi-bin/Makefile
new file mode 100644
index 000000000..e6f404f21
--- /dev/null
+++ b/cgi-bin/Makefile
@@ -0,0 +1,382 @@
+#
+# "$Id$"
+#
+# CGI makefile for CUPS.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 1997-2006 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+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 \
+ makedocset.o \
+ printers.o \
+ testcgi.o \
+ testhi.o \
+ testtemplate.o \
+ websearch.o
+CGIS = \
+ admin.cgi \
+ classes.cgi \
+ help.cgi \
+ jobs.cgi \
+ printers.cgi
+LIBTARGETS = \
+ libcupscgi.a \
+ $(LIBCUPSCGI) \
+ websearch
+
+UNITTARGETS = \
+ testcgi \
+ testhi \
+ testtemplate
+
+TARGETS = \
+ $(LIBTARGETS) \
+ $(CGIS)
+
+
+#
+# Make all targets...
+#
+
+all: $(TARGETS)
+
+
+#
+# Make library targets...
+#
+
+libs: $(LIBTARGETS) $(UNITTESTS)
+
+
+#
+# Make unit tests...
+#
+
+unittests: $(UNITTARGETS)
+
+
+#
+# Clean all object files...
+#
+
+clean:
+ $(RM) $(OBJS) $(TARGETS) $(UNITTARGETS) makedocset
+ $(RM) libcupscgi.so libcupscgi.sl libcupscgi.dylib
+
+
+#
+# Update dependencies (without system header dependencies...)
+#
+
+depend:
+ makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+
+
+#
+# Install programs...
+#
+
+install-exec:
+ $(INSTALL_DIR) -m 755 $(SERVERBIN)/cgi-bin
+ for file in $(CGIS); do \
+ $(INSTALL_BIN) $$file $(SERVERBIN)/cgi-bin; \
+ done
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ for file in $(CGIS); do \
+ cp $$file $(SYMROOT); \
+ done \
+ fi
+
+
+#
+# Install headers...
+#
+
+install-headers:
+ echo Installing header files in $(INCLUDEDIR)/cups...
+ $(INSTALL_DIR) -m 755 $(INCLUDEDIR)/cups
+ $(INSTALL_DATA) cgi.h $(INCLUDEDIR)/cups
+ $(INSTALL_DATA) help-index.h $(INCLUDEDIR)/cups
+
+
+#
+# Install libraries...
+#
+
+install-libs: $(INSTALLSTATIC)
+ echo Installing libraries in $(LIBDIR)...
+ $(INSTALL_DIR) -m 755 $(LIBDIR)
+ $(INSTALL_LIB) $(LIBCUPSCGI) $(LIBDIR)
+ if test $(LIBCUPSCGI) = "libcupscgi.so.1" -o $(LIBCUPSCGI) = "libcupscgi.sl.1"; then \
+ $(RM) $(LIBDIR)/`basename $(LIBCUPSCGI) .1`; \
+ $(LN) $(LIBCUPSCGI) $(LIBDIR)/`basename $(LIBCUPSCGI) .1`; \
+ fi
+ if test $(LIBCUPSCGI) = "libcupscgi.1.dylib"; then \
+ $(RM) $(LIBDIR)/libcupscgi.dylib; \
+ $(LN) $(LIBCUPSCGI) $(LIBDIR)/libcupscgi.dylib; \
+ fi
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ cp $(LIBCUPSCGI) $(SYMROOT); \
+ fi
+
+installstatic:
+ $(INSTALL_DIR) -m 755 $(LIBDIR)
+ $(INSTALL_LIB) -m 755 libcupscgi.a $(LIBDIR)
+ $(RANLIB) $(LIBDIR)/libcupscgi.a
+ $(CHMOD) 555 $(LIBDIR)/libcupscgi.a
+
+
+#
+# Uninstall all targets...
+#
+
+uninstall:
+ for file in $(CGIS); do \
+ $(RM) $(SERVERBIN)/cgi-bin/$$file; \
+ done
+ -$(RMDIR) $(SERVERBIN)/cgi-bin
+ $(RM) $(LIBDIR)/libcupscgi.1.dylib
+ $(RM) $(LIBDIR)/libcupscgi.a
+ $(RM) $(LIBDIR)/libcupscgi.dylib
+ $(RM) $(LIBDIR)/libcupscgi_s.a
+ $(RM) $(LIBDIR)/libcupscgi.sl
+ $(RM) $(LIBDIR)/libcupscgi.sl.1
+ $(RM) $(LIBDIR)/libcupscgi.so
+ $(RM) $(LIBDIR)/libcupscgi.so.1
+ -$(RMDIR) $(LIBDIR)
+ $(RM) $(INCLUDEDIR)/cups/cgi.h
+ $(RM) $(INCLUDEDIR)/cups/help-index.h
+ -$(RMDIR) $(INCLUDEDIR)/cups
+
+
+#
+# Automatic API help files...
+#
+
+apihelp:
+ mxmldoc --section "Programming" \
+ --title "CGI API" \
+ --css ../doc/cups-printable.css \
+ --header api-cgi.header --intro api-cgi.shtml \
+ cgi.h help-index.h $(LIBOBJS:.o=.c) >../doc/help/api-cgi.html
+ mxmldoc --tokens help/api-cgi.html api-cgi.xml >../doc/help/api-cgi.tokens
+ $(RM) api-cgi.xml
+
+framedhelp:
+ mxmldoc --framed api-cgi \
+ --section "Programming" \
+ --title "CGI API" \
+ --css ../doc/cups-printable.css \
+ --header api-cgi.header --intro api-cgi.shtml \
+ cgi.h help-index.h $(LIBOBJS:.o=.c)
+
+
+#
+# libcupscgi.so.1, libcupscgi.sl.1
+#
+
+libcupscgi.so.1 libcupscgi.sl.1: $(LIBOBJS)
+ echo Linking $@...
+ $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS) $(LIBS)
+ $(RM) `basename $@ .1`
+ $(LN) $@ `basename $@ .1`
+
+
+#
+# libcupscgi.1.dylib
+#
+
+libcupscgi.1.dylib: $(LIBOBJS) libcupscgi.exp
+ echo Linking $@...
+ $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ \
+ -install_name $(libdir)/$@ \
+ -current_version 1.0.0 \
+ -compatibility_version 1.0.0 \
+ -exported_symbols_list libcupscgi.exp \
+ $(LIBOBJS) $(LIBS)
+ $(RM) libcupscgi.dylib
+ $(LN) $@ libcupscgi.dylib
+
+
+#
+# libcupscgi_s.a
+#
+
+libcupscgi_s.a: $(LIBOBJS)
+ echo Creating $@...
+ $(DSO) $(DSOFLAGS) -o libcupscgi_s.o $(LIBOBJS) $(LIBS)
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ libcupscgi_s.o
+
+
+#
+# libcupscgi.la
+#
+
+libcupscgi.la: $(LIBOBJS)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS:.o=.lo) -rpath $(LIBDIR) \
+ -version-info 1:0 $(LIBS)
+
+
+#
+# libcupscgi.a
+#
+
+libcupscgi.a: $(LIBOBJS)
+ echo Archiving $@...
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ $(LIBOBJS)
+ $(RANLIB) $@
+
+
+#
+# admin.cgi
+#
+
+admin.cgi: admin.o ../Makedefs ../cups/$(LIBCUPS) $(LIBCUPSCGI)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ admin.o -lcupscgi $(LIBS)
+
+
+#
+# classes.cgi
+#
+
+classes.cgi: classes.o ../Makedefs ../cups/$(LIBCUPS) $(LIBCUPSCGI)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ classes.o -lcupscgi $(LIBS)
+
+
+#
+# help.cgi
+#
+
+help.cgi: help.o ../Makedefs ../cups/$(LIBCUPS) $(LIBCUPSCGI)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ help.o -lcupscgi $(LIBS)
+
+
+#
+# jobs.cgi
+#
+
+jobs.cgi: jobs.o ../Makedefs ../cups/$(LIBCUPS) $(LIBCUPSCGI)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ jobs.o -lcupscgi $(LIBS)
+
+
+#
+# makedocset
+#
+
+makedocset: makedocset.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ makedocset.o libcupscgi.a \
+ ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \
+ $(LIBZ) $(LIBGSSAPI)
+
+
+#
+# printers.cgi
+#
+
+printers.cgi: printers.o ../Makedefs ../cups/$(LIBCUPS) $(LIBCUPSCGI)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ printers.o -L. -lcupscgi $(LIBS)
+
+
+#
+# testcgi
+#
+
+testcgi: testcgi.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testcgi.o libcupscgi.a \
+ ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \
+ $(LIBZ) $(LIBGSSAPI)
+ echo Testing CGI API...
+ ./testcgi
+
+
+#
+# testhi
+#
+
+testhi: testhi.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testhi.o libcupscgi.a \
+ ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \
+ $(LIBZ) $(LIBGSSAPI)
+ echo Testing help index API...
+ ./testhi
+
+
+#
+# testtemplate
+#
+
+testtemplate: testtemplate.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testtemplate.o libcupscgi.a ../cups/$(LIBCUPSSTATIC) \
+ $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) $(LIBZ) $(LIBGSSAPI)
+
+
+#
+# websearch
+#
+
+websearch: websearch.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ websearch.o libcupscgi.a \
+ ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \
+ $(LIBZ) $(LIBGSSAPI)
+
+
+#
+# Dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id$".
+#
diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c
new file mode 100644
index 000000000..99b8e7b48
--- /dev/null
+++ b/cgi-bin/admin.c
@@ -0,0 +1,4341 @@
+/*
+ * "$Id$"
+ *
+ * Administration CGI for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Main entry for CGI.
+ * choose_device_cb() - Add a device to the device selection page.
+ * do_add_rss_subscription() - Add a RSS subscription.
+ * do_am_class() - Add or modify a class.
+ * do_am_printer() - Add or modify a printer.
+ * do_cancel_subscription() - Cancel a subscription.
+ * do_config_server() - Configure server settings.
+ * do_delete_class() - Delete a class.
+ * do_delete_printer() - Delete a printer.
+ * do_export() - Export printers to Samba.
+ * do_list_printers() - List available printers.
+ * do_menu() - Show the main menu.
+ * do_set_allowed_users() - Set the allowed/denied users for a queue.
+ * do_set_default() - Set the server default printer/class.
+ * do_set_options() - Configure the default options for a queue.
+ * do_set_sharing() - Set printer-is-shared value.
+ * get_option_value() - Return the value of an option.
+ * get_points() - Get a value in points.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi-private.h"
+#include <cups/adminutil.h>
+#include <cups/ppd.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <limits.h>
+
+
+/*
+ * Local globals...
+ */
+
+static int current_device = 0; /* Current device shown */
+
+
+/*
+ * Local functions...
+ */
+
+static void choose_device_cb(const char *device_class,
+ const char *device_id, const char *device_info,
+ const char *device_make_and_model,
+ const char *device_uri,
+ const char *device_location,
+ const char *title);
+static void do_add_rss_subscription(http_t *http);
+static void do_am_class(http_t *http, int modify);
+static void do_am_printer(http_t *http, int modify);
+static void do_cancel_subscription(http_t *http);
+static void do_config_server(http_t *http);
+static void do_delete_class(http_t *http);
+static void do_delete_printer(http_t *http);
+static void do_export(http_t *http);
+static void do_list_printers(http_t *http);
+static void do_menu(http_t *http);
+static void do_set_allowed_users(http_t *http);
+static void do_set_default(http_t *http);
+static void do_set_options(http_t *http, int is_class);
+static void do_set_sharing(http_t *http);
+static char *get_option_value(ppd_file_t *ppd, const char *name,
+ char *buffer, size_t bufsize);
+static double get_points(double number, const char *uval);
+
+
+/*
+ * 'main()' - Main entry for CGI.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ http_t *http; /* Connection to the server */
+ const char *op; /* Operation name */
+
+
+ /*
+ * Connect to the HTTP server...
+ */
+
+ fputs("DEBUG: admin.cgi started...\n", stderr);
+
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ if (!http)
+ {
+ perror("ERROR: Unable to connect to cupsd");
+ fprintf(stderr, "DEBUG: cupsServer()=\"%s\"\n",
+ cupsServer() ? cupsServer() : "(null)");
+ fprintf(stderr, "DEBUG: ippPort()=%d\n", ippPort());
+ fprintf(stderr, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
+ exit(1);
+ }
+
+ fprintf(stderr, "DEBUG: http=%p\n", http);
+
+ /*
+ * Set the web interface section...
+ */
+
+ cgiSetVariable("SECTION", "admin");
+ cgiSetVariable("REFRESH_PAGE", "");
+
+ /*
+ * See if we have form data...
+ */
+
+ if (!cgiInitialize() || !cgiGetVariable("OP"))
+ {
+ /*
+ * Nope, send the administration menu...
+ */
+
+ fputs("DEBUG: No form data, showing main menu...\n", stderr);
+
+ do_menu(http);
+ }
+ else if ((op = cgiGetVariable("OP")) != NULL && cgiIsPOST())
+ {
+ /*
+ * Do the operation...
+ */
+
+ fprintf(stderr, "DEBUG: op=\"%s\"...\n", op);
+
+ if (!*op)
+ {
+ const char *printer = getenv("PRINTER_NAME"),
+ /* Printer or class name */
+ *server_port = getenv("SERVER_PORT");
+ /* Port number string */
+ int port = atoi(server_port ? server_port : "0");
+ /* Port number */
+ char uri[1024]; /* URL */
+
+ if (printer)
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri),
+ getenv("HTTPS") ? "https" : "http", NULL,
+ getenv("SERVER_NAME"), port, "/%s/%s",
+ cgiGetVariable("IS_CLASS") ? "classes" : "printers",
+ printer);
+ else
+ httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri),
+ getenv("HTTPS") ? "https" : "http", NULL,
+ getenv("SERVER_NAME"), port, "/admin");
+
+ printf("Location: %s\n\n", uri);
+ }
+ else if (!strcmp(op, "set-allowed-users"))
+ do_set_allowed_users(http);
+ else if (!strcmp(op, "set-as-default"))
+ do_set_default(http);
+ else if (!strcmp(op, "set-sharing"))
+ do_set_sharing(http);
+ else if (!strcmp(op, "find-new-printers") ||
+ !strcmp(op, "list-available-printers"))
+ do_list_printers(http);
+ else if (!strcmp(op, "add-class"))
+ do_am_class(http, 0);
+ else if (!strcmp(op, "add-printer"))
+ do_am_printer(http, 0);
+ else if (!strcmp(op, "modify-class"))
+ do_am_class(http, 1);
+ else if (!strcmp(op, "modify-printer"))
+ do_am_printer(http, 1);
+ else if (!strcmp(op, "delete-class"))
+ do_delete_class(http);
+ else if (!strcmp(op, "delete-printer"))
+ do_delete_printer(http);
+ else if (!strcmp(op, "set-class-options"))
+ do_set_options(http, 1);
+ else if (!strcmp(op, "set-printer-options"))
+ do_set_options(http, 0);
+ else if (!strcmp(op, "config-server"))
+ do_config_server(http);
+ else if (!strcmp(op, "export-samba"))
+ do_export(http);
+ else if (!strcmp(op, "add-rss-subscription"))
+ do_add_rss_subscription(http);
+ else if (!strcmp(op, "cancel-subscription"))
+ do_cancel_subscription(http);
+ else
+ {
+ /*
+ * Bad operation code - display an error...
+ */
+
+ cgiStartHTML(cgiText(_("Administration")));
+ cgiCopyTemplateLang("error-op.tmpl");
+ cgiEndHTML();
+ }
+ }
+ else if (op && !strcmp(op, "redirect"))
+ {
+ const char *url; /* Redirection URL... */
+ char prefix[1024]; /* URL prefix */
+
+
+ if (getenv("HTTPS"))
+ snprintf(prefix, sizeof(prefix), "https://%s:%s",
+ getenv("SERVER_NAME"), getenv("SERVER_PORT"));
+ else
+ snprintf(prefix, sizeof(prefix), "http://%s:%s",
+ getenv("SERVER_NAME"), getenv("SERVER_PORT"));
+
+ fprintf(stderr, "DEBUG: redirecting with prefix %s!\n", prefix);
+
+ if ((url = cgiGetVariable("URL")) != NULL)
+ {
+ char encoded[1024], /* Encoded URL string */
+ *ptr; /* Pointer into encoded string */
+
+
+ ptr = encoded;
+ if (*url != '/')
+ *ptr++ = '/';
+
+ for (; *url && ptr < (encoded + sizeof(encoded) - 4); url ++)
+ {
+ if (strchr("%@&+ <>#=", *url) || *url < ' ' || *url & 128)
+ {
+ /*
+ * Percent-encode this character; safe because we have at least 4
+ * bytes left in the array...
+ */
+
+ sprintf(ptr, "%%%02X", *url & 255);
+ ptr += 3;
+ }
+ else
+ *ptr++ = *url;
+ }
+
+ *ptr = '\0';
+
+ if (*url)
+ {
+ /*
+ * URL was too long, just redirect to the admin page...
+ */
+
+ printf("Location: %s/admin\n\n", prefix);
+ }
+ else
+ {
+ /*
+ * URL is OK, redirect there...
+ */
+
+ printf("Location: %s%s\n\n", prefix, encoded);
+ }
+ }
+ else
+ printf("Location: %s/admin\n\n", prefix);
+ }
+ else
+ {
+ /*
+ * Form data but no operation code - display an error...
+ */
+
+ cgiStartHTML(cgiText(_("Administration")));
+ cgiCopyTemplateLang("error-op.tmpl");
+ cgiEndHTML();
+ }
+
+ /*
+ * Close the HTTP server connection...
+ */
+
+ httpClose(http);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'choose_device_cb()' - Add a device to the device selection page.
+ */
+
+static void
+choose_device_cb(
+ const char *device_class, /* I - Class */
+ const char *device_id, /* I - 1284 device ID */
+ const char *device_info, /* I - Description */
+ const char *device_make_and_model, /* I - Make and model */
+ const char *device_uri, /* I - Device URI */
+ const char *device_location, /* I - Location */
+ const char *title) /* I - Page title */
+{
+ /*
+ * For modern browsers, start a multi-part page so we can show that something
+ * is happening. Non-modern browsers just get everything at the end...
+ */
+
+ if (current_device == 0 && cgiSupportsMultipart())
+ {
+ cgiStartMultipart();
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("choose-device.tmpl");
+ cgiEndHTML();
+ fflush(stdout);
+ }
+
+
+ /*
+ * Add the device to the array...
+ */
+
+ cgiSetArray("device_class", current_device, device_class);
+ cgiSetArray("device_id", current_device, device_id);
+ cgiSetArray("device_info", current_device, device_info);
+ cgiSetArray("device_make_and_model", current_device, device_make_and_model);
+ cgiSetArray("device_uri", current_device, device_uri);
+ cgiSetArray("device_location", current_device, device_location);
+
+ current_device ++;
+}
+
+
+/*
+ * 'do_add_rss_subscription()' - Add a RSS subscription.
+ */
+
+static void
+do_add_rss_subscription(http_t *http) /* I - HTTP connection */
+{
+ ipp_t *request, /* IPP request data */
+ *response; /* IPP response data */
+ char rss_uri[1024]; /* RSS notify-recipient URI */
+ int num_events; /* Number of events */
+ const char *events[12], /* Subscribed events */
+ *subscription_name, /* Subscription name */
+ *printer_uri, /* Printer URI */
+ *ptr, /* Pointer into name */
+ *user; /* Username */
+ int max_events; /* Maximum number of events */
+
+
+ /*
+ * See if we have all of the required information...
+ */
+
+ subscription_name = cgiGetVariable("SUBSCRIPTION_NAME");
+ printer_uri = cgiGetVariable("PRINTER_URI");
+ num_events = 0;
+
+ if (cgiGetVariable("EVENT_JOB_CREATED"))
+ events[num_events ++] = "job-created";
+ if (cgiGetVariable("EVENT_JOB_COMPLETED"))
+ events[num_events ++] = "job-completed";
+ if (cgiGetVariable("EVENT_JOB_STOPPED"))
+ events[num_events ++] = "job-stopped";
+ if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
+ events[num_events ++] = "job-config-changed";
+ if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
+ events[num_events ++] = "printer-stopped";
+ if (cgiGetVariable("EVENT_PRINTER_ADDED"))
+ events[num_events ++] = "printer-added";
+ if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
+ events[num_events ++] = "printer-modified";
+ if (cgiGetVariable("EVENT_PRINTER_DELETED"))
+ events[num_events ++] = "printer-deleted";
+ if (cgiGetVariable("EVENT_SERVER_STARTED"))
+ events[num_events ++] = "server-started";
+ if (cgiGetVariable("EVENT_SERVER_STOPPED"))
+ events[num_events ++] = "server-stopped";
+ if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
+ events[num_events ++] = "server-restarted";
+ if (cgiGetVariable("EVENT_SERVER_AUDIT"))
+ events[num_events ++] = "server-audit";
+
+ if ((ptr = cgiGetVariable("MAX_EVENTS")) != NULL)
+ max_events = atoi(ptr);
+ else
+ max_events = 0;
+
+ if (!subscription_name || !printer_uri || !num_events ||
+ max_events <= 0 || max_events > 9999)
+ {
+ /*
+ * Don't have everything we need, so get the available printers
+ * and classes and (re)show the add page...
+ */
+
+ if (cgiGetVariable("EVENT_JOB_CREATED"))
+ cgiSetVariable("EVENT_JOB_CREATED", "CHECKED");
+ if (cgiGetVariable("EVENT_JOB_COMPLETED"))
+ cgiSetVariable("EVENT_JOB_COMPLETED", "CHECKED");
+ if (cgiGetVariable("EVENT_JOB_STOPPED"))
+ cgiSetVariable("EVENT_JOB_STOPPED", "CHECKED");
+ if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED"))
+ cgiSetVariable("EVENT_JOB_CONFIG_CHANGED", "CHECKED");
+ if (cgiGetVariable("EVENT_PRINTER_STOPPED"))
+ cgiSetVariable("EVENT_PRINTER_STOPPED", "CHECKED");
+ if (cgiGetVariable("EVENT_PRINTER_ADDED"))
+ cgiSetVariable("EVENT_PRINTER_ADDED", "CHECKED");
+ if (cgiGetVariable("EVENT_PRINTER_MODIFIED"))
+ cgiSetVariable("EVENT_PRINTER_MODIFIED", "CHECKED");
+ if (cgiGetVariable("EVENT_PRINTER_DELETED"))
+ cgiSetVariable("EVENT_PRINTER_DELETED", "CHECKED");
+ if (cgiGetVariable("EVENT_SERVER_STARTED"))
+ cgiSetVariable("EVENT_SERVER_STARTED", "CHECKED");
+ if (cgiGetVariable("EVENT_SERVER_STOPPED"))
+ cgiSetVariable("EVENT_SERVER_STOPPED", "CHECKED");
+ if (cgiGetVariable("EVENT_SERVER_RESTARTED"))
+ cgiSetVariable("EVENT_SERVER_RESTARTED", "CHECKED");
+ if (cgiGetVariable("EVENT_SERVER_AUDIT"))
+ cgiSetVariable("EVENT_SERVER_AUDIT", "CHECKED");
+
+ request = ippNewRequest(CUPS_GET_PRINTERS);
+ response = cupsDoRequest(http, request, "/");
+
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+ ippDelete(response);
+
+ cgiStartHTML(cgiText(_("Add RSS Subscription")));
+
+ cgiCopyTemplateLang("add-rss-subscription.tmpl");
+
+ cgiEndHTML();
+ return;
+ }
+
+ /*
+ * Make sure we have a username...
+ */
+
+ if ((user = getenv("REMOTE_USER")) == NULL)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+
+ /*
+ * Validate the subscription name...
+ */
+
+ for (ptr = subscription_name; *ptr; ptr ++)
+ if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' ||
+ *ptr == '?' || *ptr == '#')
+ break;
+
+ if (*ptr)
+ {
+ cgiSetVariable("ERROR",
+ cgiText(_("The subscription name may not "
+ "contain spaces, slashes (/), question marks (?), "
+ "or the pound sign (#).")));
+ cgiStartHTML(_("Add RSS Subscription"));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ /*
+ * Add the subscription...
+ */
+
+ ptr = subscription_name + strlen(subscription_name) - 4;
+ if (ptr < subscription_name || strcmp(ptr, ".rss"))
+ httpAssembleURIf(HTTP_URI_CODING_ALL, rss_uri, sizeof(rss_uri), "rss",
+ NULL, NULL, 0, "/%s.rss?max_events=%d", subscription_name,
+ max_events);
+ else
+ httpAssembleURIf(HTTP_URI_CODING_ALL, rss_uri, sizeof(rss_uri), "rss",
+ NULL, NULL, 0, "/%s?max_events=%d", subscription_name,
+ max_events);
+
+ request = ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION);
+
+ if (!_cups_strcasecmp(printer_uri, "#ALL#"))
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, "ipp://localhost/");
+ else
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, printer_uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, user);
+
+ ippAddString(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
+ "notify-recipient-uri", NULL, rss_uri);
+ ippAddStrings(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events",
+ num_events, NULL, events);
+ ippAddInteger(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+ "notify-lease-duration", 0);
+
+ ippDelete(cupsDoRequest(http, request, "/"));
+
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+ else if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML(_("Add RSS Subscription"));
+ cgiShowIPPError(_("Unable to add RSS subscription:"));
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the admin page...
+ */
+
+ cgiSetVariable("refresh_page", "5;URL=/admin");
+ cgiStartHTML(_("Add RSS Subscription"));
+ cgiCopyTemplateLang("subscription-added.tmpl");
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'do_am_class()' - Add or modify a class.
+ */
+
+static void
+do_am_class(http_t *http, /* I - HTTP connection */
+ 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 */
+ char uri[HTTP_MAX_URI]; /* Device or printer URI */
+ const char *name, /* Pointer to class name */
+ *op, /* Operation 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 = cgiText(modify ? _("Modify Class") : _("Add Class"));
+ op = cgiGetVariable("OP");
+ 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
+ */
+
+ request = ippNewRequest(CUPS_GET_PRINTERS);
+
+ 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_CLASS | CUPS_PRINTER_REMOTE |
+ CUPS_PRINTER_IMPLICIT);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ cgiClearVariables();
+ if (op)
+ cgiSetVariable("OP", op);
+ if (name)
+ cgiSetVariable("PRINTER_NAME", name);
+
+ 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 || _cups_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 || _cups_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 = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, 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 (!_cups_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;
+ }
+
+ if (!name)
+ {
+ cgiStartHTML(title);
+ cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
+ cgiCopyTemplateLang("error.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",
+ cgiText(_("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 = ippNewRequest(CUPS_ADD_CLASS);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/classes/%s", 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 = _cupsStrAlloc(cgiGetArray("MEMBER_URIS", i));
+ }
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ippDelete(cupsDoRequest(http, request, "/admin/"));
+
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+ else if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML(title);
+ cgiShowIPPError(modify ? _("Unable to modify class:") :
+ _("Unable to add class:"));
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the class page...
+ */
+
+ char refresh[1024]; /* Refresh URL */
+
+ cgiFormEncode(uri, name, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "5;URL=/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 */
+ int modify) /* I - Modify the printer? */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_t *request, /* IPP request */
+ *response, /* IPP response */
+ *oldinfo; /* Old printer information */
+ 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
+ };
+
+
+ ptr = cgiGetVariable("DEVICE_URI");
+ fprintf(stderr, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
+ ptr ? ptr : "(null)");
+
+ title = cgiText(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 = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, 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;
+
+ 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 ((name = cgiGetVariable("PRINTER_NAME")) != NULL)
+ {
+ for (ptr = name; *ptr; ptr ++)
+ if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
+ break;
+
+ if (*ptr || ptr == name || strlen(name) > 127)
+ {
+ cgiSetVariable("ERROR",
+ cgiText(_("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;
+ }
+ }
+
+ if ((var = cgiGetVariable("DEVICE_URI")) != NULL)
+ {
+ if ((uriptr = strrchr(var, '|')) != 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 (!_cups_strncasecmp(make, "laserjet", 8) ||
+ !_cups_strncasecmp(make, "deskjet", 7) ||
+ !_cups_strncasecmp(make, "designjet", 9))
+ strcpy(make, "HP");
+ else if (!_cups_strncasecmp(make, "phaser", 6))
+ strcpy(make, "Xerox");
+ else if (!_cups_strncasecmp(make, "stylus", 6))
+ strcpy(make, "Epson");
+ else
+ strcpy(make, "Generic");
+
+ if (!cgiGetVariable("CURRENT_MAKE"))
+ cgiSetVariable("CURRENT_MAKE", make);
+
+ if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
+ cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr);
+
+ if (!modify)
+ {
+ char template[128], /* Template name */
+ *tptr; /* Pointer into template name */
+
+ cgiSetVariable("PRINTER_INFO", uriptr);
+
+ for (tptr = template;
+ tptr < (template + sizeof(template) - 1) && *uriptr;
+ uriptr ++)
+ if (isalnum(*uriptr & 255) || *uriptr == '_' || *uriptr == '-' ||
+ *uriptr == '.')
+ *tptr++ = *uriptr;
+ else if ((*uriptr == ' ' || *uriptr == '/') && tptr > template &&
+ tptr[-1] != '_')
+ *tptr++ = '_';
+ else if (*uriptr == '?' || *uriptr == '(')
+ break;
+
+ *tptr = '\0';
+
+ cgiSetVariable("TEMPLATE_NAME", template);
+ }
+ }
+ }
+
+ if (!var)
+ {
+ /*
+ * Look for devices so the user can pick something...
+ */
+
+ 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);
+ }
+
+ /*
+ * Scan for devices for up to 30 seconds...
+ */
+
+ fputs("DEBUG: Getting list of devices...\n", stderr);
+
+ current_device = 0;
+ if (cupsGetDevices(http, 5, CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE,
+ (cups_device_cb_t)choose_device_cb,
+ (void *)title) == IPP_OK)
+ {
+ fputs("DEBUG: Got device list!\n", stderr);
+
+ if (cgiSupportsMultipart())
+ cgiStartMultipart();
+
+ cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("choose-device.tmpl");
+ cgiEndHTML();
+
+ if (cgiSupportsMultipart())
+ cgiEndMultipart();
+ }
+ else
+ {
+ fprintf(stderr,
+ "ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
+ cupsLastError(), cupsLastErrorString());
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+ else
+ {
+ cgiStartHTML(title);
+ cgiShowIPPError(modify ? _("Unable to modify printer:") :
+ _("Unable to add printer:"));
+ cgiEndHTML();
+ return;
+ }
+ }
+ }
+ else if (!strchr(var, '/') ||
+ (!strncmp(var, "lpd://", 6) && !strchr(var + 6, '/')))
+ {
+ 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("CURRENT_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 (!name || !cgiGetVariable("PRINTER_LOCATION"))
+ {
+ cgiStartHTML(title);
+
+ if (modify)
+ {
+ /*
+ * Update the location and description of an existing printer...
+ */
+
+ if (oldinfo)
+ {
+ if ((attr = ippFindAttribute(oldinfo, "printer-info",
+ IPP_TAG_TEXT)) != NULL)
+ cgiSetVariable("PRINTER_INFO", attr->values[0].string.text);
+
+ if ((attr = ippFindAttribute(oldinfo, "printer-location",
+ IPP_TAG_TEXT)) != NULL)
+ cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text);
+
+ if ((attr = ippFindAttribute(oldinfo, "printer-is-shared",
+ IPP_TAG_BOOLEAN)) != NULL)
+ cgiSetVariable("PRINTER_IS_SHARED",
+ attr->values[0].boolean ? "1" : "0");
+ }
+
+ cgiCopyTemplateLang("modify-printer.tmpl");
+ }
+ else
+ {
+ /*
+ * Get the name, location, and description for a new printer...
+ */
+
+#ifdef __APPLE__
+ if (!strncmp(var, "usb:", 4))
+ cgiSetVariable("printer_is_shared", "1");
+ else
+#endif /* __APPLE__ */
+ cgiSetVariable("printer_is_shared", "0");
+
+ cgiCopyTemplateLang("add-printer.tmpl");
+ }
+
+ cgiEndHTML();
+
+ if (oldinfo)
+ ippDelete(oldinfo);
+
+ return;
+ }
+ else if (!file &&
+ (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
+ {
+ if (modify && !cgiGetVariable("SELECT_MAKE"))
+ {
+ /*
+ * 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 */
+
+
+ /* TODO: Use cupsGetFile() API... */
+ 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)
+ {
+ httpFlush(http);
+
+ 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 = httpRead2(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));
+ }
+ }
+
+ /*
+ * Build a CUPS_GET_PPDS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ request = ippNewRequest(CUPS_GET_PPDS);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, "ipp://localhost/printers/");
+
+ if ((var = cgiGetVariable("PPD_MAKE")) == NULL)
+ var = cgiGetVariable("CURRENT_MAKE");
+ if (var && !cgiGetVariable("SELECT_MAKE"))
+ {
+ const char *make_model; /* Make and model */
+
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
+ "ppd-make", NULL, var);
+
+ if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
+ "ppd-make-and-model", NULL, make_model);
+ }
+ 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...
+ */
+
+ if (cgiSetIPPVars(response, NULL, NULL, NULL, 0) == 0 && !modify)
+ {
+ /*
+ * No PPD files with this make, try again with all makes...
+ */
+
+ ippDelete(response);
+
+ request = ippNewRequest(CUPS_GET_PPDS);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, "ipp://localhost/printers/");
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "ppd-make");
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("choose-make.tmpl");
+ cgiEndHTML();
+ }
+ else if (!var || cgiGetVariable("SELECT_MAKE"))
+ {
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("choose-make.tmpl");
+ cgiEndHTML();
+ }
+ else
+ {
+ /*
+ * Let the user choose a model...
+ */
+
+ cgiStartHTML(title);
+ if (!cgiGetVariable("PPD_MAKE"))
+ cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
+ if (!modify)
+ cgiSetVariable("CURRENT_MAKE_AND_MODEL",
+ cgiGetArray("PPD_MAKE_AND_MODEL", 0));
+ cgiCopyTemplateLang("choose-model.tmpl");
+ cgiEndHTML();
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ cgiStartHTML(title);
+ cgiShowIPPError(_("Unable to get list of printer drivers:"));
+ 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-is-shared
+ * printer-state
+ */
+
+ request = ippNewRequest(CUPS_ADD_PRINTER);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, 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)
+ {
+ var = cgiGetVariable("PPD_NAME");
+ if (strcmp(var, "__no_change__"))
+ ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name",
+ NULL, var);
+ }
+
+ 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))
+ {
+ /*
+ * 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);
+
+ var = cgiGetVariable("printer_is_shared");
+ ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-shared",
+ var && (!strcmp(var, "1") || !strcmp(var, "on")));
+
+ ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
+ IPP_PRINTER_IDLE);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if (file)
+ ippDelete(cupsDoFileRequest(http, request, "/admin/", file->tempfile));
+ else
+ ippDelete(cupsDoRequest(http, request, "/admin/"));
+
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+ else if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML(title);
+ cgiShowIPPError(modify ? _("Unable to modify printer:") :
+ _("Unable to add printer:"));
+ }
+ else if (modify)
+ {
+ /*
+ * Redirect successful updates back to the printer page...
+ */
+
+ char refresh[1024]; /* Refresh URL */
+
+
+ cgiFormEncode(uri, name, sizeof(uri));
+
+ snprintf(refresh, sizeof(refresh),
+ "5;/admin/?OP=redirect&URL=/printers/%s", uri);
+
+ cgiSetVariable("refresh_page", refresh);
+
+ cgiStartHTML(title);
+
+ cgiCopyTemplateLang("printer-modified.tmpl");
+ }
+ else
+ {
+ /*
+ * Set the printer options...
+ */
+
+ cgiSetVariable("OP", "set-printer-options");
+ do_set_options(http, 0);
+ return;
+ }
+
+ cgiEndHTML();
+ }
+
+ if (oldinfo)
+ ippDelete(oldinfo);
+}
+
+
+/*
+ * 'do_cancel_subscription()' - Cancel a subscription.
+ */
+
+static void
+do_cancel_subscription(http_t *http)/* I - HTTP connection */
+{
+ ipp_t *request; /* IPP request data */
+ const char *var, /* Form variable */
+ *user; /* Username */
+ int id; /* Subscription ID */
+
+
+ /*
+ * See if we have all of the required information...
+ */
+
+ if ((var = cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL)
+ id = atoi(var);
+ else
+ id = 0;
+
+ if (id <= 0)
+ {
+ cgiSetVariable("ERROR", cgiText(_("Bad subscription ID")));
+ cgiStartHTML(_("Cancel RSS Subscription"));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ /*
+ * Require a username...
+ */
+
+ if ((user = getenv("REMOTE_USER")) == NULL)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+
+ /*
+ * Cancel the subscription...
+ */
+
+ request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, "ipp://localhost/");
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
+ "notify-subscription-id", id);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, user);
+
+ ippDelete(cupsDoRequest(http, request, "/"));
+
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+ else if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML(_("Cancel RSS Subscription"));
+ cgiShowIPPError(_("Unable to cancel RSS subscription:"));
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the admin page...
+ */
+
+ cgiSetVariable("refresh_page", "5;URL=/admin");
+ cgiStartHTML(_("Cancel RSS Subscription"));
+ cgiCopyTemplateLang("subscription-canceled.tmpl");
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'do_config_server()' - Configure server settings.
+ */
+
+static void
+do_config_server(http_t *http) /* I - HTTP connection */
+{
+ if (cgiGetVariable("CHANGESETTINGS"))
+ {
+ /*
+ * Save basic setting changes...
+ */
+
+ int num_settings; /* Number of server settings */
+ cups_option_t *settings; /* Server settings */
+ int advanced, /* Advanced settings shown? */
+ changed; /* Have settings changed? */
+ const char *debug_logging, /* DEBUG_LOGGING value */
+ *remote_admin, /* REMOTE_ADMIN value */
+ *remote_any, /* REMOTE_ANY value */
+ *remote_printers,
+ /* REMOTE_PRINTERS value */
+ *share_printers,/* SHARE_PRINTERS value */
+ *user_cancel_any,
+ /* USER_CANCEL_ANY value */
+ *browse_web_if = NULL,
+ /* BrowseWebIF value */
+ *preserve_job_history = NULL,
+ /* PreserveJobHistory value */
+ *preserve_job_files = NULL,
+ /* PreserveJobFiles value */
+ *max_clients = NULL,
+ /* MaxClients value */
+ *max_jobs = NULL,
+ /* MaxJobs value */
+ *max_log_size = NULL;
+ /* MaxLogSize value */
+ char local_protocols[255],
+ /* BrowseLocalProtocols */
+ remote_protocols[255];
+ /* BrowseRemoteProtocols */
+ const char *current_browse_web_if,
+ /* BrowseWebIF value */
+ *current_preserve_job_history,
+ /* PreserveJobHistory value */
+ *current_preserve_job_files,
+ /* PreserveJobFiles value */
+ *current_max_clients,
+ /* MaxClients value */
+ *current_max_jobs,
+ /* MaxJobs value */
+ *current_max_log_size,
+ /* MaxLogSize value */
+ *current_local_protocols,
+ /* BrowseLocalProtocols */
+ *current_remote_protocols;
+ /* BrowseRemoteProtocols */
+#ifdef HAVE_GSSAPI
+ char default_auth_type[255];
+ /* DefaultAuthType value */
+ const char *val; /* Setting value */
+#endif /* HAVE_GSSAPI */
+
+
+ /*
+ * Get the checkbox values from the form...
+ */
+
+ debug_logging = cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
+ remote_admin = cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
+ remote_any = cgiGetVariable("REMOTE_ANY") ? "1" : "0";
+ remote_printers = cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0";
+ share_printers = cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
+ user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
+
+ advanced = cgiGetVariable("ADVANCEDSETTINGS") != NULL;
+ if (advanced)
+ {
+ /*
+ * Get advanced settings...
+ */
+
+ browse_web_if = cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
+ preserve_job_history = cgiGetVariable("PRESERVE_JOB_HISTORY") ? "Yes" : "No";
+ preserve_job_files = cgiGetVariable("PRESERVE_JOB_FILES") ? "Yes" : "No";
+ max_clients = cgiGetVariable("MAX_CLIENTS");
+ max_jobs = cgiGetVariable("MAX_JOBS");
+ max_log_size = cgiGetVariable("MAX_LOG_SIZE");
+
+ if (!max_clients || atoi(max_clients) <= 0)
+ max_clients = "100";
+
+ if (!max_jobs || atoi(max_jobs) <= 0)
+ max_jobs = "500";
+
+ if (!max_log_size || atof(max_log_size) <= 0.0)
+ max_log_size = "1m";
+
+ if (cgiGetVariable("BROWSE_LOCAL_CUPS"))
+ strcpy(local_protocols, "cups");
+ else
+ local_protocols[0] = '\0';
+
+#ifdef HAVE_DNSSD
+ if (cgiGetVariable("BROWSE_LOCAL_DNSSD"))
+ {
+ if (local_protocols[0])
+ strcat(local_protocols, " dnssd");
+ else
+ strcat(local_protocols, "dnssd");
+ }
+#endif /* HAVE_DNSSD */
+
+#ifdef HAVE_LDAP
+ if (cgiGetVariable("BROWSE_LOCAL_LDAP"))
+ {
+ if (local_protocols[0])
+ strcat(local_protocols, " ldap");
+ else
+ strcat(local_protocols, "ldap");
+ }
+#endif /* HAVE_LDAP */
+
+#ifdef HAVE_LIBSLP
+ if (cgiGetVariable("BROWSE_LOCAL_SLP"))
+ {
+ if (local_protocols[0])
+ strcat(local_protocols, " slp");
+ else
+ strcat(local_protocols, "slp");
+ }
+#endif /* HAVE_SLP */
+
+ if (cgiGetVariable("BROWSE_REMOTE_CUPS"))
+ strcpy(remote_protocols, "cups");
+ else
+ remote_protocols[0] = '\0';
+
+#ifdef HAVE_LDAP
+ if (cgiGetVariable("BROWSE_REMOTE_LDAP"))
+ {
+ if (remote_protocols[0])
+ strcat(remote_protocols, " ldap");
+ else
+ strcat(remote_protocols, "ldap");
+ }
+#endif /* HAVE_LDAP */
+
+#ifdef HAVE_LIBSLP
+ if (cgiGetVariable("BROWSE_REMOTE_SLP"))
+ {
+ if (remote_protocols[0])
+ strcat(remote_protocols, " slp");
+ else
+ strcat(remote_protocols, "slp");
+ }
+#endif /* HAVE_SLP */
+ }
+
+ /*
+ * Get the current server settings...
+ */
+
+ if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
+ {
+ cgiStartHTML(cgiText(_("Change Settings")));
+ cgiSetVariable("MESSAGE",
+ cgiText(_("Unable to change server settings:")));
+ cgiSetVariable("ERROR", cupsLastErrorString());
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+#ifdef HAVE_GSSAPI
+ /*
+ * Get authentication settings...
+ */
+
+ if (cgiGetVariable("KERBEROS"))
+ strlcpy(default_auth_type, "Negotiate", sizeof(default_auth_type));
+ else
+ {
+ val = cupsGetOption("DefaultAuthType", num_settings, settings);
+
+ if (!val || !_cups_strcasecmp(val, "Negotiate"))
+ strlcpy(default_auth_type, "Basic", sizeof(default_auth_type));
+ else
+ strlcpy(default_auth_type, val, sizeof(default_auth_type));
+ }
+
+ fprintf(stderr, "DEBUG: DefaultAuthType %s\n", default_auth_type);
+#endif /* HAVE_GSSAPI */
+
+ if ((current_browse_web_if = cupsGetOption("BrowseWebIF", num_settings,
+ settings)) == NULL)
+ current_browse_web_if = "No";
+
+ if ((current_preserve_job_history = cupsGetOption("PreserveJobHistory",
+ num_settings,
+ settings)) == NULL)
+ current_preserve_job_history = "Yes";
+
+ if ((current_preserve_job_files = cupsGetOption("PreserveJobFiles",
+ num_settings,
+ settings)) == NULL)
+ current_preserve_job_files = "No";
+
+ if ((current_max_clients = cupsGetOption("MaxClients", num_settings,
+ settings)) == NULL)
+ current_max_clients = "100";
+
+ if ((current_max_jobs = cupsGetOption("MaxJobs", num_settings,
+ settings)) == NULL)
+ current_max_jobs = "500";
+
+ if ((current_max_log_size = cupsGetOption("MaxLogSize", num_settings,
+ settings)) == NULL)
+ current_max_log_size = "1m";
+
+ if ((current_local_protocols = cupsGetOption("BrowseLocalProtocols",
+ num_settings,
+ settings)) == NULL)
+ current_local_protocols = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS;
+
+ if ((current_remote_protocols = cupsGetOption("BrowseRemoteProtocols",
+ num_settings,
+ settings)) == NULL)
+ current_remote_protocols = CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS;
+
+ /*
+ * See if the settings have changed...
+ */
+
+ changed = strcmp(debug_logging, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING,
+ num_settings, settings)) ||
+ strcmp(remote_admin, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN,
+ num_settings, settings)) ||
+ strcmp(remote_any, cupsGetOption(CUPS_SERVER_REMOTE_ANY,
+ num_settings, settings)) ||
+ strcmp(remote_printers, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS,
+ num_settings, settings)) ||
+ strcmp(share_printers, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS,
+ num_settings, settings)) ||
+#ifdef HAVE_GSSAPI
+ !cupsGetOption("DefaultAuthType", num_settings, settings) ||
+ strcmp(default_auth_type, cupsGetOption("DefaultAuthType",
+ num_settings, settings)) ||
+#endif /* HAVE_GSSAPI */
+ strcmp(user_cancel_any, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY,
+ num_settings, settings));
+
+ if (advanced && !changed)
+ changed = _cups_strcasecmp(local_protocols, current_local_protocols) ||
+ _cups_strcasecmp(remote_protocols, current_remote_protocols) ||
+ _cups_strcasecmp(browse_web_if, current_browse_web_if) ||
+ _cups_strcasecmp(preserve_job_history, current_preserve_job_history) ||
+ _cups_strcasecmp(preserve_job_files, current_preserve_job_files) ||
+ _cups_strcasecmp(max_clients, current_max_clients) ||
+ _cups_strcasecmp(max_jobs, current_max_jobs) ||
+ _cups_strcasecmp(max_log_size, current_max_log_size);
+
+ if (changed)
+ {
+ /*
+ * Settings *have* changed, so save the changes...
+ */
+
+ cupsFreeOptions(num_settings, settings);
+
+ num_settings = 0;
+ num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
+ debug_logging, num_settings, &settings);
+ num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
+ remote_admin, num_settings, &settings);
+ num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
+ remote_any, num_settings, &settings);
+ num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
+ remote_printers, num_settings, &settings);
+ num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
+ share_printers, num_settings, &settings);
+ num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
+ user_cancel_any, num_settings, &settings);
+#ifdef HAVE_GSSAPI
+ num_settings = cupsAddOption("DefaultAuthType", default_auth_type,
+ num_settings, &settings);
+#endif /* HAVE_GSSAPI */
+
+ if (advanced)
+ {
+ /*
+ * Add advanced settings...
+ */
+
+ if (_cups_strcasecmp(local_protocols, current_local_protocols))
+ num_settings = cupsAddOption("BrowseLocalProtocols", local_protocols,
+ num_settings, &settings);
+ if (_cups_strcasecmp(remote_protocols, current_remote_protocols))
+ num_settings = cupsAddOption("BrowseRemoteProtocols", remote_protocols,
+ num_settings, &settings);
+ if (_cups_strcasecmp(browse_web_if, current_browse_web_if))
+ num_settings = cupsAddOption("BrowseWebIF", browse_web_if,
+ num_settings, &settings);
+ if (_cups_strcasecmp(preserve_job_history, current_preserve_job_history))
+ num_settings = cupsAddOption("PreserveJobHistory",
+ preserve_job_history, num_settings,
+ &settings);
+ if (_cups_strcasecmp(preserve_job_files, current_preserve_job_files))
+ num_settings = cupsAddOption("PreserveJobFiles", preserve_job_files,
+ num_settings, &settings);
+ if (_cups_strcasecmp(max_clients, current_max_clients))
+ num_settings = cupsAddOption("MaxClients", max_clients, num_settings,
+ &settings);
+ if (_cups_strcasecmp(max_jobs, current_max_jobs))
+ num_settings = cupsAddOption("MaxJobs", max_jobs, num_settings,
+ &settings);
+ if (_cups_strcasecmp(max_log_size, current_max_log_size))
+ num_settings = cupsAddOption("MaxLogSize", max_log_size, num_settings,
+ &settings);
+ }
+
+ if (!cupsAdminSetServerSettings(http, num_settings, settings))
+ {
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+
+ cgiStartHTML(cgiText(_("Change Settings")));
+ cgiSetVariable("MESSAGE",
+ cgiText(_("Unable to change server settings:")));
+ cgiSetVariable("ERROR", cupsLastErrorString());
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ {
+ if (advanced)
+ cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/admin/?ADVANCEDSETTINGS=YES");
+ else
+ cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
+ cgiStartHTML(cgiText(_("Change Settings")));
+ cgiCopyTemplateLang("restart.tmpl");
+ }
+ }
+ else
+ {
+ /*
+ * No changes...
+ */
+
+ cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
+ cgiStartHTML(cgiText(_("Change Settings")));
+ cgiCopyTemplateLang("norestart.tmpl");
+ }
+
+ cupsFreeOptions(num_settings, settings);
+
+ cgiEndHTML();
+ }
+ else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
+ {
+ /*
+ * 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(cgiText(_("Edit Configuration File")));
+ cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:")));
+ cgiSetVariable("ERROR", strerror(errno));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ perror(tempfile);
+ return;
+ }
+
+ if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
+ {
+ cgiStartHTML(cgiText(_("Edit Configuration File")));
+ cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary 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_UNAUTHORIZED)
+ {
+ puts("Status: 401\n");
+ unlink(tempfile);
+ exit(0);
+ }
+ else if (status != HTTP_CREATED)
+ {
+ cgiSetVariable("MESSAGE",
+ cgiText(_("Unable to upload cupsd.conf file:")));
+ cgiSetVariable("ERROR", httpStatus(status));
+
+ cgiStartHTML(cgiText(_("Edit Configuration File")));
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ else
+ {
+ cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
+
+ cgiStartHTML(cgiText(_("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 */
+ *bufptr, /* Pointer into buffer */
+ *bufend; /* End of buffer */
+ int ch; /* Character from 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(cgiText(_("Edit Configuration File")));
+ cgiSetVariable("MESSAGE",
+ cgiText(_("Unable to access cupsd.conf file:")));
+ cgiSetVariable("ERROR", strerror(errno));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ perror(filename);
+ return;
+ }
+
+ if (info.st_size > (1024 * 1024))
+ {
+ cgiStartHTML(cgiText(_("Edit Configuration File")));
+ cgiSetVariable("MESSAGE",
+ cgiText(_("Unable to access cupsd.conf file:")));
+ cgiSetVariable("ERROR",
+ cgiText(_("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(cgiText(_("Edit Configuration File")));
+ cgiSetVariable("MESSAGE",
+ cgiText(_("Unable to access cupsd.conf file:")));
+ cgiSetVariable("ERROR", strerror(errno));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ perror(filename);
+ return;
+ }
+
+ /*
+ * Allocate memory and load the file into a string buffer...
+ */
+
+ if ((buffer = calloc(1, info.st_size + 1)) != NULL)
+ {
+ cupsFileRead(cupsd, buffer, info.st_size);
+ cgiSetVariable("CUPSDCONF", buffer);
+ free(buffer);
+ }
+
+ cupsFileClose(cupsd);
+
+ /*
+ * Then get the default cupsd.conf file and put that into a string as
+ * well...
+ */
+
+ strlcat(filename, ".default", sizeof(filename));
+
+ if (!stat(filename, &info) && info.st_size < (1024 * 1024) &&
+ (cupsd = cupsFileOpen(filename, "r")) != NULL)
+ {
+ if ((buffer = calloc(1, 2 * info.st_size + 1)) != NULL)
+ {
+ bufend = buffer + 2 * info.st_size - 1;
+
+ for (bufptr = buffer;
+ bufptr < bufend && (ch = cupsFileGetChar(cupsd)) != EOF;)
+ {
+ if (ch == '\\' || ch == '\"')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = ch;
+ }
+ else if (ch == '\n')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = 'n';
+ }
+ else if (ch == '\t')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = 't';
+ }
+ else if (ch >= ' ')
+ *bufptr++ = ch;
+ }
+
+ *bufptr = '\0';
+
+ cgiSetVariable("CUPSDCONF_DEFAULT", buffer);
+ free(buffer);
+ }
+
+ cupsFileClose(cupsd);
+ }
+
+ /*
+ * Show the current config file...
+ */
+
+ cgiStartHTML(cgiText(_("Edit Configuration File")));
+
+ cgiCopyTemplateLang("edit-config.tmpl");
+
+ cgiEndHTML();
+ }
+}
+
+
+/*
+ * 'do_delete_class()' - Delete a class.
+ */
+
+static void
+do_delete_class(http_t *http) /* I - HTTP connection */
+{
+ ipp_t *request; /* IPP request */
+ char uri[HTTP_MAX_URI]; /* Job URI */
+ const char *pclass; /* Printer class name */
+
+
+ /*
+ * Get form variables...
+ */
+
+ if (cgiGetVariable("CONFIRM") == NULL)
+ {
+ cgiStartHTML(cgiText(_("Delete Class")));
+ cgiCopyTemplateLang("class-confirm.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/classes/%s", pclass);
+ else
+ {
+ cgiStartHTML(cgiText(_("Delete Class")));
+ cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ /*
+ * Build a CUPS_DELETE_CLASS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ request = ippNewRequest(CUPS_DELETE_CLASS);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ippDelete(cupsDoRequest(http, request, "/admin/"));
+
+ /*
+ * Show the results...
+ */
+
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+ else if (cupsLastError() <= IPP_OK_CONFLICT)
+ {
+ /*
+ * Redirect successful updates back to the classes page...
+ */
+
+ cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
+ }
+
+ cgiStartHTML(cgiText(_("Delete Class")));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ cgiShowIPPError(_("Unable to delete class:"));
+ else
+ cgiCopyTemplateLang("class-deleted.tmpl");
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'do_delete_printer()' - Delete a printer.
+ */
+
+static void
+do_delete_printer(http_t *http) /* I - HTTP connection */
+{
+ ipp_t *request; /* IPP request */
+ char uri[HTTP_MAX_URI]; /* Job URI */
+ const char *printer; /* Printer printer name */
+
+
+ /*
+ * Get form variables...
+ */
+
+ if (cgiGetVariable("CONFIRM") == NULL)
+ {
+ cgiStartHTML(cgiText(_("Delete Printer")));
+ cgiCopyTemplateLang("printer-confirm.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/printers/%s", printer);
+ else
+ {
+ cgiStartHTML(cgiText(_("Delete Printer")));
+ cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ /*
+ * Build a CUPS_DELETE_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ request = ippNewRequest(CUPS_DELETE_PRINTER);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ippDelete(cupsDoRequest(http, request, "/admin/"));
+
+ /*
+ * Show the results...
+ */
+
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+ else if (cupsLastError() <= IPP_OK_CONFLICT)
+ {
+ /*
+ * Redirect successful updates back to the printers page...
+ */
+
+ cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
+ }
+
+ cgiStartHTML(cgiText(_("Delete Printer")));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ cgiShowIPPError(_("Unable to delete printer:"));
+ else
+ cgiCopyTemplateLang("printer-deleted.tmpl");
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'do_export()' - Export printers to Samba.
+ */
+
+static void
+do_export(http_t *http) /* I - HTTP connection */
+{
+ int i, j; /* Looping vars */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ const char *username, /* Samba username */
+ *password, /* Samba password */
+ *export_all; /* Export all printers? */
+ int export_count, /* Number of printers to export */
+ printer_count; /* Number of available printers */
+ const char *name, /* What name to pull */
+ *dest; /* Current destination */
+ char ppd[1024]; /* PPD file */
+
+
+ /*
+ * Get form data...
+ */
+
+ username = cgiGetVariable("USERNAME");
+ password = cgiGetVariable("PASSWORD");
+ export_all = cgiGetVariable("EXPORT_ALL");
+ export_count = cgiGetSize("EXPORT_NAME");
+
+ /*
+ * Get list of available printers...
+ */
+
+ cgiSetSize("PRINTER_NAME", 0);
+ cgiSetSize("PRINTER_EXPORT", 0);
+
+ request = ippNewRequest(CUPS_GET_PRINTERS);
+
+ 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 | CUPS_PRINTER_REMOTE |
+ CUPS_PRINTER_IMPLICIT);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "printer-name");
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+ ippDelete(response);
+
+ if (!export_all)
+ {
+ printer_count = cgiGetSize("PRINTER_NAME");
+
+ for (i = 0; i < printer_count; i ++)
+ {
+ dest = cgiGetArray("PRINTER_NAME", i);
+
+ for (j = 0; j < export_count; j ++)
+ if (!_cups_strcasecmp(dest, cgiGetArray("EXPORT_NAME", j)))
+ break;
+
+ cgiSetArray("PRINTER_EXPORT", i, j < export_count ? "Y" : "");
+ }
+ }
+ }
+
+ /*
+ * Export or get the printers to export...
+ */
+
+ if (username && *username && password && *password &&
+ (export_all || export_count > 0))
+ {
+ /*
+ * Do export...
+ */
+
+ fputs("DEBUG: Export printers...\n", stderr);
+
+ if (export_all)
+ {
+ name = "PRINTER_NAME";
+ export_count = cgiGetSize("PRINTER_NAME");
+ }
+ else
+ name = "EXPORT_NAME";
+
+ for (i = 0; i < export_count; i ++)
+ {
+ dest = cgiGetArray(name, i);
+
+ if (!cupsAdminCreateWindowsPPD(http, dest, ppd, sizeof(ppd)))
+ break;
+
+ j = cupsAdminExportSamba(dest, ppd, "localhost", username, password,
+ stderr);
+
+ unlink(ppd);
+
+ if (!j)
+ break;
+ }
+
+ if (i < export_count)
+ cgiSetVariable("ERROR", cupsLastErrorString());
+ else
+ {
+ cgiStartHTML(cgiText(_("Export Printers to Samba")));
+ cgiCopyTemplateLang("samba-exported.tmpl");
+ cgiEndHTML();
+ return;
+ }
+ }
+ else if (username && !*username)
+ cgiSetVariable("ERROR",
+ cgiText(_("A Samba username is required to export "
+ "printer drivers")));
+ else if (username && (!password || !*password))
+ cgiSetVariable("ERROR",
+ cgiText(_("A Samba password is required to export "
+ "printer drivers")));
+
+ /*
+ * Show form...
+ */
+
+ cgiStartHTML(cgiText(_("Export Printers to Samba")));
+ cgiCopyTemplateLang("samba-export.tmpl");
+ cgiEndHTML();
+}
+
+
+/*
+ * 'do_list_printers()' - List available printers.
+ */
+
+static void
+do_list_printers(http_t *http) /* I - HTTP connection */
+{
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* IPP attribute */
+
+
+ cgiStartHTML(cgiText(_("List Available Printers")));
+ fflush(stdout);
+
+ /*
+ * Get the list of printers and their devices...
+ */
+
+ request = ippNewRequest(CUPS_GET_PRINTERS);
+
+ 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 */
+ cups_array_t *printer_devices; /* Printer devices for local printers */
+ char *printer_device; /* Current printer device */
+
+
+ /*
+ * Allocate an array and copy the device strings...
+ */
+
+ printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+
+ for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
+ attr;
+ attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
+ {
+ cupsArrayAdd(printer_devices, _cupsStrAlloc(attr->values[0].string.text));
+ }
+
+ /*
+ * Free the printer list and get the device list...
+ */
+
+ ippDelete(response);
+
+ request = ippNewRequest(CUPS_GET_DEVICES);
+
+ 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") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ device_info = attr->values[0].string.text;
+
+ if (!strcmp(attr->name, "device-make-and-model") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ device_make_and_model = attr->values[0].string.text;
+
+ if (!strcmp(attr->name, "device-uri") &&
+ 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 &&
+ _cups_strcasecmp(device_make_and_model, "unknown") &&
+ strchr(device_uri, ':'))
+ {
+ /*
+ * Yes, now see if there is already a printer for this
+ * device...
+ */
+
+ if (!cupsArrayFind(printer_devices, (void *)device_uri))
+ {
+ /*
+ * Not found, so it must be a new printer...
+ */
+
+ char option[1024], /* Form variables for this device */
+ *option_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.
+ */
+
+ if (_cups_strncasecmp(device_info, "unknown", 7))
+ ptr = device_info;
+ else if ((ptr = strstr(device_uri, "://")) != NULL)
+ ptr += 3;
+ else
+ ptr = device_make_and_model;
+
+ for (option_ptr = option;
+ option_ptr < (option + sizeof(option) - 1) && *ptr;
+ ptr ++)
+ if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' ||
+ *ptr == '.')
+ *option_ptr++ = *ptr;
+ else if ((*ptr == ' ' || *ptr == '/') && option_ptr > option &&
+ option_ptr[-1] != '_')
+ *option_ptr++ = '_';
+ else if (*ptr == '?' || *ptr == '(')
+ break;
+
+ *option_ptr = '\0';
+
+ cgiSetArray("TEMPLATE_NAME", i, option);
+
+ /*
+ * 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_uri", i, device_uri);
+ i ++;
+ }
+ }
+
+ if (!attr)
+ break;
+ }
+
+ ippDelete(response);
+
+ /*
+ * Free the device list...
+ */
+
+ for (printer_device = (char *)cupsArrayFirst(printer_devices);
+ printer_device;
+ printer_device = (char *)cupsArrayNext(printer_devices))
+ _cupsStrFree(printer_device);
+
+ cupsArrayDelete(printer_devices);
+ }
+ }
+
+ /*
+ * Finally, show the printer list...
+ */
+
+ cgiCopyTemplateLang("list-available-printers.tmpl");
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'do_menu()' - Show the main menu.
+ */
+
+static void
+do_menu(http_t *http) /* I - HTTP connection */
+{
+ int num_settings; /* Number of server settings */
+ cups_option_t *settings; /* Server settings */
+ const char *val; /* Setting value */
+ char filename[1024]; /* Temporary filename */
+ const char *datadir; /* Location of data files */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+
+
+ /*
+ * Get the current server settings...
+ */
+
+ if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
+ {
+ cgiSetVariable("SETTINGS_MESSAGE",
+ cgiText(_("Unable to open cupsd.conf file:")));
+ cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
+ }
+
+ if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
+ settings)) != NULL && atoi(val))
+ cgiSetVariable("DEBUG_LOGGING", "CHECKED");
+
+ if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
+ settings)) != NULL && atoi(val))
+ cgiSetVariable("REMOTE_ADMIN", "CHECKED");
+
+ if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings,
+ settings)) != NULL && atoi(val))
+ cgiSetVariable("REMOTE_ANY", "CHECKED");
+
+ if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, num_settings,
+ settings)) != NULL && atoi(val))
+ cgiSetVariable("REMOTE_PRINTERS", "CHECKED");
+
+ if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
+ settings)) != NULL && atoi(val))
+ cgiSetVariable("SHARE_PRINTERS", "CHECKED");
+
+ if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
+ settings)) != NULL && atoi(val))
+ cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
+
+#ifdef HAVE_GSSAPI
+ cgiSetVariable("HAVE_GSSAPI", "1");
+
+ if ((val = cupsGetOption("DefaultAuthType", num_settings,
+ settings)) != NULL && !_cups_strcasecmp(val, "Negotiate"))
+ cgiSetVariable("KERBEROS", "CHECKED");
+ else
+#endif /* HAVE_GSSAPI */
+ cgiSetVariable("KERBEROS", "");
+
+#ifdef HAVE_DNSSD
+ cgiSetVariable("HAVE_DNSSD", "1");
+#endif /* HAVE_DNSSD */
+
+#ifdef HAVE_LDAP
+ cgiSetVariable("HAVE_LDAP", "1");
+#endif /* HAVE_LDAP */
+
+#ifdef HAVE_LIBSLP
+ cgiSetVariable("HAVE_LIBSLP", "1");
+#endif /* HAVE_LIBSLP */
+
+ if ((val = cupsGetOption("BrowseRemoteProtocols", num_settings,
+ settings)) == NULL)
+ if ((val = cupsGetOption("BrowseProtocols", num_settings,
+ settings)) == NULL)
+ val = CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS;
+
+ if (strstr(val, "cups") || strstr(val, "CUPS"))
+ cgiSetVariable("BROWSE_REMOTE_CUPS", "CHECKED");
+
+ if (strstr(val, "ldap") || strstr(val, "LDAP"))
+ cgiSetVariable("BROWSE_REMOTE_LDAP", "CHECKED");
+
+ if (strstr(val, "slp") || strstr(val, "SLP"))
+ cgiSetVariable("BROWSE_REMOTE_SLP", "CHECKED");
+
+ if ((val = cupsGetOption("BrowseLocalProtocols", num_settings,
+ settings)) == NULL)
+ if ((val = cupsGetOption("BrowseProtocols", num_settings,
+ settings)) == NULL)
+ val = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS;
+
+ if (strstr(val, "cups") || strstr(val, "CUPS"))
+ cgiSetVariable("BROWSE_LOCAL_CUPS", "CHECKED");
+
+ if (strstr(val, "dnssd") || strstr(val, "DNSSD") ||
+ strstr(val, "dns-sd") || strstr(val, "DNS-SD") ||
+ strstr(val, "bonjour") || strstr(val, "BONJOUR"))
+ cgiSetVariable("BROWSE_LOCAL_DNSSD", "CHECKED");
+
+ if (strstr(val, "ldap") || strstr(val, "LDAP"))
+ cgiSetVariable("BROWSE_LOCAL_LDAP", "CHECKED");
+
+ if (strstr(val, "slp") || strstr(val, "SLP"))
+ cgiSetVariable("BROWSE_LOCAL_SLP", "CHECKED");
+
+ if ((val = cupsGetOption("BrowseWebIF", num_settings,
+ settings)) == NULL)
+ val = "No";
+
+ if (!_cups_strcasecmp(val, "yes") || !_cups_strcasecmp(val, "on") ||
+ !_cups_strcasecmp(val, "true"))
+ cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
+
+ if ((val = cupsGetOption("PreserveJobHistory", num_settings,
+ settings)) == NULL)
+ val = "Yes";
+
+ if (!_cups_strcasecmp(val, "yes") || !_cups_strcasecmp(val, "on") ||
+ !_cups_strcasecmp(val, "true"))
+ {
+ cgiSetVariable("PRESERVE_JOB_HISTORY", "CHECKED");
+
+ if ((val = cupsGetOption("PreserveJobFiles", num_settings,
+ settings)) == NULL)
+ val = "No";
+
+ if (!_cups_strcasecmp(val, "yes") || !_cups_strcasecmp(val, "on") ||
+ !_cups_strcasecmp(val, "true"))
+ cgiSetVariable("PRESERVE_JOB_FILES", "CHECKED");
+ }
+
+ if ((val = cupsGetOption("MaxClients", num_settings, settings)) == NULL)
+ val = "100";
+
+ cgiSetVariable("MAX_CLIENTS", val);
+
+ if ((val = cupsGetOption("MaxJobs", num_settings, settings)) == NULL)
+ val = "500";
+
+ cgiSetVariable("MAX_JOBS", val);
+
+ if ((val = cupsGetOption("MaxLogSize", num_settings, settings)) == NULL)
+ val = "1m";
+
+ cgiSetVariable("MAX_LOG_SIZE", val);
+
+ cupsFreeOptions(num_settings, settings);
+
+ /*
+ * See if Samba and the Windows drivers are installed...
+ */
+
+ if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+
+ snprintf(filename, sizeof(filename), "%s/drivers/pscript5.dll", datadir);
+ if (!access(filename, R_OK))
+ {
+ /*
+ * Found Windows 2000 driver file, see if we have smbclient and
+ * rpcclient...
+ */
+
+ if (cupsFileFind("smbclient", getenv("PATH"), 1, filename,
+ sizeof(filename)) &&
+ cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
+ sizeof(filename)))
+ cgiSetVariable("HAVE_SAMBA", "Y");
+ else
+ {
+ if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename,
+ sizeof(filename)))
+ fputs("ERROR: smbclient not found!\n", stderr);
+
+ if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename,
+ sizeof(filename)))
+ fputs("ERROR: rpcclient not found!\n", stderr);
+ }
+ }
+ else
+ perror(filename);
+
+ /*
+ * Subscriptions...
+ */
+
+ request = ippNewRequest(IPP_GET_SUBSCRIPTIONS);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, "ipp://localhost/");
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+ ippDelete(response);
+ }
+
+ /*
+ * Finally, show the main menu template...
+ */
+
+ cgiStartHTML(cgiText(_("Administration")));
+
+ cgiCopyTemplateLang("admin.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 */
+{
+ 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) */
+ *is_class, /* Is a class? */
+ *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 */
+ static const char * const attrs[] = /* Requested attributes */
+ {
+ "requesting-user-name-allowed",
+ "requesting-user-name-denied"
+ };
+
+
+ is_class = cgiGetVariable("IS_CLASS");
+ printer = cgiGetVariable("PRINTER_NAME");
+
+ if (!printer)
+ {
+ cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
+ cgiStartHTML(cgiText(_("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 = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
+ printer);
+ 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, "/")) != NULL)
+ {
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+ ippDelete(response);
+ }
+
+ cgiStartHTML(cgiText(_("Set Allowed Users")));
+
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+ else if (cupsLastError() > IPP_OK_CONFLICT)
+ cgiShowIPPError(_("Unable to get printer attributes:"));
+ 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)
+ break;
+
+ 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/Class request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name-{allowed,denied}
+ */
+
+ request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
+ printer);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ if (num_users == 0)
+ ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "requesting-user-name-allowed", NULL, "all");
+ else
+ {
+ attr = ippAddStrings(request, IPP_TAG_PRINTER, 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)
+ break;
+
+ 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 = _cupsStrAlloc(ptr);
+
+ /*
+ * Advance to the next name...
+ */
+
+ ptr = end;
+ }
+ }
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ippDelete(cupsDoRequest(http, request, "/admin/"));
+
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+ else if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML(cgiText(_("Set Allowed Users")));
+ cgiShowIPPError(_("Unable to change printer:"));
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the printer page...
+ */
+
+ char url[1024], /* Printer/class URL */
+ refresh[1024]; /* Refresh URL */
+
+
+ cgiRewriteURL(uri, url, sizeof(url), NULL);
+ cgiFormEncode(uri, url, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s",
+ uri);
+ cgiSetVariable("refresh_page", refresh);
+
+ cgiStartHTML(cgiText(_("Set Allowed Users")));
+
+ cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
+ "printer-modified.tmpl");
+ }
+
+ cgiEndHTML();
+ }
+}
+
+
+/*
+ * 'do_set_default()' - Set the server default printer/class.
+ */
+
+static void
+do_set_default(http_t *http) /* I - HTTP connection */
+{
+ const char *title; /* Page title */
+ ipp_t *request; /* IPP request */
+ char uri[HTTP_MAX_URI]; /* Printer URI */
+ const char *printer, /* Printer name (purge-jobs) */
+ *is_class; /* Is a class? */
+
+
+ is_class = cgiGetVariable("IS_CLASS");
+ printer = cgiGetVariable("PRINTER_NAME");
+ title = cgiText(_("Set As Server Default"));
+
+ if (!printer)
+ {
+ cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ /*
+ * Build a printer request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ request = ippNewRequest(CUPS_SET_DEFAULT);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
+ printer);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ippDelete(cupsDoRequest(http, request, "/admin/"));
+
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+ else if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML(title);
+ cgiShowIPPError(_("Unable to set server default:"));
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the printer page...
+ */
+
+ char url[1024], /* Printer/class URL */
+ refresh[1024]; /* Refresh URL */
+
+
+ cgiRewriteURL(uri, url, sizeof(url), NULL);
+ cgiFormEncode(uri, url, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
+ cgiSetVariable("refresh_page", refresh);
+
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("printer-default.tmpl");
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'do_set_options()' - Configure the default options for a queue.
+ */
+
+static void
+do_set_options(http_t *http, /* I - HTTP connection */
+ int is_class) /* I - Set options for class? */
+{
+ 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 */
+ 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 */
+ value[1024], /* Option value */
+ 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_coption_t *coption; /* Custom option */
+ ppd_cparam_t *cparam; /* Custom parameter */
+ ppd_attr_t *ppdattr; /* PPD attribute */
+ const char *title; /* Page title */
+
+
+ title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options"));
+
+ fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http,
+ is_class);
+
+ /*
+ * Get the printer name...
+ */
+
+ if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
+ printer);
+ else
+ {
+ cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri);
+
+ /*
+ * If the user clicks on the Auto-Configure button, send an AutoConfigure
+ * command file to the printer...
+ */
+
+ if (cgiGetVariable("AUTOCONFIGURE"))
+ {
+ cgiPrintCommand(http, printer, "AutoConfigure", "Set Default Options");
+ return;
+ }
+
+ /*
+ * Get the PPD file...
+ */
+
+ if (is_class)
+ filename = NULL;
+ else
+ filename = cupsGetPPD2(http, printer);
+
+ if (filename)
+ {
+ fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename);
+
+ if ((ppd = ppdOpenFile(filename)) == NULL)
+ {
+ cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i)));
+ cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:")));
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+ }
+ else
+ {
+ fputs("DEBUG: No PPD file\n", stderr);
+ ppd = NULL;
+ }
+
+ if (cgiGetVariable("job_sheets_start") != NULL ||
+ cgiGetVariable("job_sheets_end") != NULL)
+ have_options = 1;
+ else
+ have_options = 0;
+
+ if (ppd)
+ {
+ ppdMarkDefaults(ppd);
+
+ for (option = ppdFirstOption(ppd);
+ option;
+ option = ppdNextOption(ppd))
+ {
+ if ((var = cgiGetVariable(option->keyword)) != NULL)
+ {
+ have_options = 1;
+ ppdMarkOption(ppd, option->keyword, var);
+ fprintf(stderr, "DEBUG: Set %s to %s...\n", option->keyword, var);
+ }
+ else
+ fprintf(stderr, "DEBUG: Didn't find %s...\n", option->keyword);
+ }
+ }
+
+ if (!have_options || ppdConflicts(ppd))
+ {
+ /*
+ * Show the options to the user...
+ */
+
+ fputs("DEBUG: Showing options...\n", stderr);
+
+ /*
+ * Show auto-configure button if supported...
+ */
+
+ if (ppd)
+ {
+ if (ppd->num_filters == 0 ||
+ ((ppdattr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL &&
+ ppdattr->value && strstr(ppdattr->value, "AutoConfigure")))
+ cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
+ else
+ {
+ for (i = 0; i < ppd->num_filters; i ++)
+ if (!strncmp(ppd->filters[i], "application/vnd.cups-postscript", 31))
+ {
+ cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
+ break;
+ }
+ }
+ }
+
+ /*
+ * Get the printer attributes...
+ */
+
+ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/printers/%s", printer);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ response = cupsDoRequest(http, request, "/");
+
+ /*
+ * List the groups used as "tabs"...
+ */
+
+ i = 0;
+
+ if (ppd)
+ {
+ for (group = ppd->groups;
+ i < ppd->num_groups;
+ i ++, group ++)
+ {
+ cgiSetArray("GROUP_ID", i, group->name);
+
+ if (!strcmp(group->name, "InstallableOptions"))
+ cgiSetArray("GROUP", i, cgiText(_("Options Installed")));
+ else
+ cgiSetArray("GROUP", i, group->text);
+ }
+ }
+
+ if (ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO))
+ {
+ cgiSetArray("GROUP_ID", i, "CUPS_BANNERS");
+ cgiSetArray("GROUP", i ++, cgiText(_("Banners")));
+ }
+
+ if (ippFindAttribute(response, "printer-error-policy-supported",
+ IPP_TAG_ZERO) ||
+ ippFindAttribute(response, "printer-op-policy-supported",
+ IPP_TAG_ZERO))
+ {
+ cgiSetArray("GROUP_ID", i, "CUPS_POLICIES");
+ cgiSetArray("GROUP", i ++, cgiText(_("Policies")));
+ }
+
+ if ((attr = ippFindAttribute(response, "port-monitor-supported",
+ IPP_TAG_NAME)) != NULL && attr->num_values > 1)
+ {
+ cgiSetArray("GROUP_ID", i, "CUPS_PORT_MONITOR");
+ cgiSetArray("GROUP", i, cgiText(_("Port Monitor")));
+ }
+
+ cgiStartHTML(cgiText(_("Set Printer Options")));
+ cgiCopyTemplateLang("set-printer-options-header.tmpl");
+
+ if (ppd)
+ {
+ ppdLocalize(ppd);
+
+ 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);
+
+ for (m = 0; m < option->num_choices; m ++)
+ {
+ if (option->choices[m].marked)
+ {
+ cgiSetArray("cchoice", k, option->choices[m].text);
+ break;
+ }
+ }
+
+ k ++;
+ }
+
+ cgiCopyTemplateLang("option-conflict.tmpl");
+ }
+
+ for (i = ppd->num_groups, group = ppd->groups;
+ i > 0;
+ i --, group ++)
+ {
+ for (j = group->num_options, option = group->options;
+ j > 0;
+ j --, option ++)
+ {
+ if (!strcmp(option->keyword, "PageRegion"))
+ continue;
+
+ if (option->num_choices > 1)
+ break;
+ }
+
+ if (j == 0)
+ continue;
+
+ cgiSetVariable("GROUP_ID", group->name);
+
+ if (!strcmp(group->name, "InstallableOptions"))
+ cgiSetVariable("GROUP", cgiText(_("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") || option->num_choices < 2)
+ 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 ++)
+ {
+ 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);
+ }
+
+ cgiSetSize("PARAMS", 0);
+ cgiSetSize("PARAMTEXT", 0);
+ cgiSetSize("PARAMVALUE", 0);
+ cgiSetSize("INPUTTYPE", 0);
+
+ if ((coption = ppdFindCustomOption(ppd, option->keyword)))
+ {
+ const char *units = NULL; /* Units value, if any */
+
+ cgiSetVariable("ISCUSTOM", "1");
+
+ for (cparam = ppdFirstCustomParam(coption), m = 0;
+ cparam;
+ cparam = ppdNextCustomParam(coption), m ++)
+ {
+ if (!_cups_strcasecmp(option->keyword, "PageSize") &&
+ _cups_strcasecmp(cparam->name, "Width") &&
+ _cups_strcasecmp(cparam->name, "Height"))
+ {
+ m --;
+ continue;
+ }
+
+ cgiSetArray("PARAMS", m, cparam->name);
+ cgiSetArray("PARAMTEXT", m, cparam->text);
+ cgiSetArray("INPUTTYPE", m, "text");
+
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_POINTS :
+ if (!_cups_strncasecmp(option->defchoice, "Custom.", 7))
+ {
+ units = option->defchoice + strlen(option->defchoice) - 2;
+
+ if (strcmp(units, "mm") && strcmp(units, "cm") &&
+ strcmp(units, "in") && strcmp(units, "ft"))
+ {
+ if (units[1] == 'm')
+ units ++;
+ else
+ units = "pt";
+ }
+ }
+ else
+ units = "pt";
+
+ if (!strcmp(units, "mm"))
+ snprintf(value, sizeof(value), "%g",
+ cparam->current.custom_points / 72.0 * 25.4);
+ else if (!strcmp(units, "cm"))
+ snprintf(value, sizeof(value), "%g",
+ cparam->current.custom_points / 72.0 * 2.54);
+ else if (!strcmp(units, "in"))
+ snprintf(value, sizeof(value), "%g",
+ cparam->current.custom_points / 72.0);
+ else if (!strcmp(units, "ft"))
+ snprintf(value, sizeof(value), "%g",
+ cparam->current.custom_points / 72.0 / 12.0);
+ else if (!strcmp(units, "m"))
+ snprintf(value, sizeof(value), "%g",
+ cparam->current.custom_points / 72.0 * 0.0254);
+ else
+ snprintf(value, sizeof(value), "%g",
+ cparam->current.custom_points);
+ cgiSetArray("PARAMVALUE", m, value);
+ break;
+
+ case PPD_CUSTOM_CURVE :
+ case PPD_CUSTOM_INVCURVE :
+ case PPD_CUSTOM_REAL :
+ snprintf(value, sizeof(value), "%g",
+ cparam->current.custom_real);
+ cgiSetArray("PARAMVALUE", m, value);
+ break;
+
+ case PPD_CUSTOM_INT:
+ snprintf(value, sizeof(value), "%d",
+ cparam->current.custom_int);
+ cgiSetArray("PARAMVALUE", m, value);
+ break;
+
+ case PPD_CUSTOM_PASSCODE:
+ case PPD_CUSTOM_PASSWORD:
+ if (cparam->current.custom_password)
+ cgiSetArray("PARAMVALUE", m,
+ cparam->current.custom_password);
+ else
+ cgiSetArray("PARAMVALUE", m, "");
+ cgiSetArray("INPUTTYPE", m, "password");
+ break;
+
+ case PPD_CUSTOM_STRING:
+ if (cparam->current.custom_string)
+ cgiSetArray("PARAMVALUE", m,
+ cparam->current.custom_string);
+ else
+ cgiSetArray("PARAMVALUE", m, "");
+ break;
+ }
+ }
+
+ if (units)
+ {
+ cgiSetArray("PARAMS", m, "Units");
+ cgiSetArray("PARAMTEXT", m, cgiText(_("Units")));
+ cgiSetArray("PARAMVALUE", m, units);
+ }
+ }
+ else
+ cgiSetVariable("ISCUSTOM", "0");
+
+ 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");
+ }
+ }
+
+ if ((attr = ippFindAttribute(response, "job-sheets-supported",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ /*
+ * Add the job sheets options...
+ */
+
+ cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
+ cgiSetVariable("GROUP", cgiText(_("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",
+ /* TRANSLATORS: Banner/cover sheet before the print job. */
+ cgiText(_("Starting Banner")));
+ cgiSetVariable("DEFCHOICE", attr != NULL ?
+ attr->values[0].string.text : "");
+
+ cgiCopyTemplateLang("option-pickone.tmpl");
+
+ cgiSetVariable("KEYWORD", "job_sheets_end");
+ cgiSetVariable("KEYTEXT",
+ /* TRANSLATORS: Banner/cover sheet after the print job. */
+ cgiText(_("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_ID", "CUPS_POLICIES");
+ cgiSetVariable("GROUP", cgiText(_("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", cgiText(_("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", cgiText(_("Operation Policy")));
+ cgiSetVariable("DEFCHOICE", attr == NULL ?
+ "" : attr->values[0].string.text);
+
+ cgiCopyTemplateLang("option-pickone.tmpl");
+ }
+
+ cgiCopyTemplateLang("option-trailer.tmpl");
+ }
+
+ /*
+ * Binary protocol support...
+ */
+
+ if ((attr = ippFindAttribute(response, "port-monitor-supported",
+ IPP_TAG_NAME)) != NULL && attr->num_values > 1)
+ {
+ cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
+ cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
+
+ cgiSetSize("CHOICES", attr->num_values);
+ cgiSetSize("TEXT", attr->num_values);
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ cgiSetArray("CHOICES", i, attr->values[i].string.text);
+ cgiSetArray("TEXT", i, attr->values[i].string.text);
+ }
+
+ attr = ippFindAttribute(response, "port-monitor", IPP_TAG_NAME);
+ cgiSetVariable("KEYWORD", "port_monitor");
+ cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
+ cgiSetVariable("DEFCHOICE", attr ? attr->values[0].string.text : "none");
+
+ cgiCopyTemplateLang("option-header.tmpl");
+ cgiCopyTemplateLang("option-pickone.tmpl");
+ cgiCopyTemplateLang("option-trailer.tmpl");
+ }
+
+ cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
+ cgiEndHTML();
+
+ ippDelete(response);
+ }
+ else
+ {
+ /*
+ * Set default options...
+ */
+
+ fputs("DEBUG: Setting options...\n", stderr);
+
+ if (filename)
+ {
+ out = cupsTempFile2(tempfile, sizeof(tempfile));
+ in = cupsFileOpen(filename, "r");
+
+ if (!in || !out)
+ {
+ cgiSetVariable("ERROR", strerror(errno));
+ cgiStartHTML(cgiText(_("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))
+ 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") ||
+ !strcmp(keyword, "PaperDimension") ||
+ !strcmp(keyword, "ImageableArea"))
+ var = get_option_value(ppd, "PageSize", value, sizeof(value));
+ else
+ var = get_option_value(ppd, keyword, value, sizeof(value));
+
+ if (!var)
+ cupsFilePrintf(out, "%s\n", line);
+ else
+ cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
+ }
+ }
+
+ cupsFileClose(in);
+ cupsFileClose(out);
+ }
+ else
+ {
+ /*
+ * Make sure temporary filename is cleared when there is no PPD...
+ */
+
+ tempfile[0] = '\0';
+ }
+
+ /*
+ * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
+ * following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * job-sheets-default
+ * printer-error-policy
+ * printer-op-policy
+ * [ppd file]
+ */
+
+ request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS :
+ CUPS_ADD_MODIFY_PRINTER);
+
+ 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 = _cupsStrAlloc(cgiGetVariable("job_sheets_start"));
+ attr->values[1].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_end"));
+
+ if ((var = cgiGetVariable("printer_error_policy")) != NULL)
+ ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "printer-error-policy", NULL, var);
+
+ if ((var = cgiGetVariable("printer_op_policy")) != NULL)
+ ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "printer-op-policy", NULL, var);
+
+ if ((var = cgiGetVariable("port_monitor")) != NULL)
+ ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "port-monitor", NULL, var);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if (filename)
+ ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile));
+ else
+ ippDelete(cupsDoRequest(http, request, "/admin/"));
+
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+ else if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML(title);
+ cgiShowIPPError(_("Unable to set options:"));
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the printer page...
+ */
+
+ char refresh[1024]; /* Refresh URL */
+
+
+ cgiFormEncode(uri, printer, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
+ is_class ? "classes" : "printers", uri);
+ cgiSetVariable("refresh_page", refresh);
+
+ cgiStartHTML(title);
+
+ cgiCopyTemplateLang("printer-configured.tmpl");
+ }
+
+ cgiEndHTML();
+
+ if (filename)
+ unlink(tempfile);
+ }
+
+ if (filename)
+ unlink(filename);
+}
+
+
+/*
+ * 'do_set_sharing()' - Set printer-is-shared value.
+ */
+
+static void
+do_set_sharing(http_t *http) /* I - HTTP connection */
+{
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ char uri[HTTP_MAX_URI]; /* Printer URI */
+ const char *printer, /* Printer name */
+ *is_class, /* Is a class? */
+ *shared; /* Sharing value */
+
+
+ is_class = cgiGetVariable("IS_CLASS");
+ printer = cgiGetVariable("PRINTER_NAME");
+ shared = cgiGetVariable("SHARED");
+
+ if (!printer || !shared)
+ {
+ cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
+ cgiStartHTML(cgiText(_("Set Publishing")));
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+ return;
+ }
+
+ /*
+ * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
+ * following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * printer-is-shared
+ */
+
+ request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
+ printer);
+ 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)
+ {
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+ ippDelete(response);
+ }
+
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+ else if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML(cgiText(_("Set Publishing")));
+ cgiShowIPPError(_("Unable to change printer-is-shared attribute:"));
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the printer page...
+ */
+
+ char url[1024], /* Printer/class URL */
+ refresh[1024]; /* Refresh URL */
+
+
+ cgiRewriteURL(uri, url, sizeof(url), NULL);
+ cgiFormEncode(uri, url, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
+ cgiSetVariable("refresh_page", refresh);
+
+ cgiStartHTML(cgiText(_("Set Publishing")));
+ cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
+ "printer-modified.tmpl");
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'get_option_value()' - Return the value of an option.
+ *
+ * This function also handles generation of custom option values.
+ */
+
+static char * /* O - Value string or NULL on error */
+get_option_value(
+ ppd_file_t *ppd, /* I - PPD file */
+ const char *name, /* I - Option name */
+ char *buffer, /* I - String buffer */
+ size_t bufsize) /* I - Size of buffer */
+{
+ char *bufptr, /* Pointer into buffer */
+ *bufend; /* End of buffer */
+ ppd_coption_t *coption; /* Custom option */
+ ppd_cparam_t *cparam; /* Current custom parameter */
+ char keyword[256]; /* Parameter name */
+ const char *val, /* Parameter value */
+ *uval; /* Units value */
+ long integer; /* Integer value */
+ double number, /* Number value */
+ number_points; /* Number in points */
+
+
+ /*
+ * See if we have a custom option choice...
+ */
+
+ if ((val = cgiGetVariable(name)) == NULL)
+ {
+ /*
+ * Option not found!
+ */
+
+ return (NULL);
+ }
+ else if (_cups_strcasecmp(val, "Custom") ||
+ (coption = ppdFindCustomOption(ppd, name)) == NULL)
+ {
+ /*
+ * Not a custom choice...
+ */
+
+ strlcpy(buffer, val, bufsize);
+ return (buffer);
+ }
+
+ /*
+ * OK, we have a custom option choice, format it...
+ */
+
+ *buffer = '\0';
+
+ if (!strcmp(coption->keyword, "PageSize"))
+ {
+ const char *lval; /* Length string value */
+ double width, /* Width value */
+ width_points, /* Width in points */
+ length, /* Length value */
+ length_points; /* Length in points */
+
+
+ val = cgiGetVariable("PageSize.Width");
+ lval = cgiGetVariable("PageSize.Height");
+ uval = cgiGetVariable("PageSize.Units");
+
+ if (!val || !lval || !uval ||
+ (width = strtod(val, NULL)) == 0.0 ||
+ (length = strtod(lval, NULL)) == 0.0 ||
+ (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
+ strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
+ return (NULL);
+
+ width_points = get_points(width, uval);
+ length_points = get_points(length, uval);
+
+ if (width_points < ppd->custom_min[0] ||
+ width_points > ppd->custom_max[0] ||
+ length_points < ppd->custom_min[1] ||
+ length_points > ppd->custom_max[1])
+ return (NULL);
+
+ snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval);
+ }
+ else if (cupsArrayCount(coption->params) == 1)
+ {
+ cparam = ppdFirstCustomParam(coption);
+ snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name);
+
+ if ((val = cgiGetVariable(keyword)) == NULL)
+ return (NULL);
+
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_CURVE :
+ case PPD_CUSTOM_INVCURVE :
+ case PPD_CUSTOM_REAL :
+ if ((number = strtod(val, NULL)) == 0.0 ||
+ number < cparam->minimum.custom_real ||
+ number > cparam->maximum.custom_real)
+ return (NULL);
+
+ snprintf(buffer, bufsize, "Custom.%g", number);
+ break;
+
+ case PPD_CUSTOM_INT :
+ if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
+ integer == LONG_MAX ||
+ integer < cparam->minimum.custom_int ||
+ integer > cparam->maximum.custom_int)
+ return (NULL);
+
+ snprintf(buffer, bufsize, "Custom.%ld", integer);
+ break;
+
+ case PPD_CUSTOM_POINTS :
+ snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
+
+ if ((number = strtod(val, NULL)) == 0.0 ||
+ (uval = cgiGetVariable(keyword)) == NULL ||
+ (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
+ strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
+ return (NULL);
+
+ number_points = get_points(number, uval);
+ if (number_points < cparam->minimum.custom_points ||
+ number_points > cparam->maximum.custom_points)
+ return (NULL);
+
+ snprintf(buffer, bufsize, "Custom.%g%s", number, uval);
+ break;
+
+ case PPD_CUSTOM_PASSCODE :
+ for (uval = val; *uval; uval ++)
+ if (!isdigit(*uval & 255))
+ return (NULL);
+
+ case PPD_CUSTOM_PASSWORD :
+ case PPD_CUSTOM_STRING :
+ integer = (long)strlen(val);
+ if (integer < cparam->minimum.custom_string ||
+ integer > cparam->maximum.custom_string)
+ return (NULL);
+
+ snprintf(buffer, bufsize, "Custom.%s", val);
+ break;
+ }
+ }
+ else
+ {
+ const char *prefix = "{"; /* Prefix string */
+
+
+ bufptr = buffer;
+ bufend = buffer + bufsize;
+
+ for (cparam = ppdFirstCustomParam(coption);
+ cparam;
+ cparam = ppdNextCustomParam(coption))
+ {
+ snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword,
+ cparam->name);
+
+ if ((val = cgiGetVariable(keyword)) == NULL)
+ return (NULL);
+
+ snprintf(bufptr, bufend - bufptr, "%s%s=", prefix, cparam->name);
+ bufptr += strlen(bufptr);
+ prefix = " ";
+
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_CURVE :
+ case PPD_CUSTOM_INVCURVE :
+ case PPD_CUSTOM_REAL :
+ if ((number = strtod(val, NULL)) == 0.0 ||
+ number < cparam->minimum.custom_real ||
+ number > cparam->maximum.custom_real)
+ return (NULL);
+
+ snprintf(bufptr, bufend - bufptr, "%g", number);
+ break;
+
+ case PPD_CUSTOM_INT :
+ if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
+ integer == LONG_MAX ||
+ integer < cparam->minimum.custom_int ||
+ integer > cparam->maximum.custom_int)
+ return (NULL);
+
+ snprintf(bufptr, bufend - bufptr, "%ld", integer);
+ break;
+
+ case PPD_CUSTOM_POINTS :
+ snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
+
+ if ((number = strtod(val, NULL)) == 0.0 ||
+ (uval = cgiGetVariable(keyword)) == NULL ||
+ (strcmp(uval, "pt") && strcmp(uval, "in") &&
+ strcmp(uval, "ft") && strcmp(uval, "cm") &&
+ strcmp(uval, "mm") && strcmp(uval, "m")))
+ return (NULL);
+
+ number_points = get_points(number, uval);
+ if (number_points < cparam->minimum.custom_points ||
+ number_points > cparam->maximum.custom_points)
+ return (NULL);
+
+ snprintf(bufptr, bufend - bufptr, "%g%s", number, uval);
+ break;
+
+ case PPD_CUSTOM_PASSCODE :
+ for (uval = val; *uval; uval ++)
+ if (!isdigit(*uval & 255))
+ return (NULL);
+
+ case PPD_CUSTOM_PASSWORD :
+ case PPD_CUSTOM_STRING :
+ integer = (long)strlen(val);
+ if (integer < cparam->minimum.custom_string ||
+ integer > cparam->maximum.custom_string)
+ return (NULL);
+
+ if ((bufptr + 2) > bufend)
+ return (NULL);
+
+ bufend --;
+ *bufptr++ = '\"';
+
+ while (*val && bufptr < bufend)
+ {
+ if (*val == '\\' || *val == '\"')
+ {
+ if ((bufptr + 1) >= bufend)
+ return (NULL);
+
+ *bufptr++ = '\\';
+ }
+
+ *bufptr++ = *val++;
+ }
+
+ if (bufptr >= bufend)
+ return (NULL);
+
+ *bufptr++ = '\"';
+ *bufptr = '\0';
+ bufend ++;
+ break;
+ }
+
+ bufptr += strlen(bufptr);
+ }
+
+ if (bufptr == buffer || (bufend - bufptr) < 2)
+ return (NULL);
+
+ strcpy(bufptr, "}");
+ }
+
+ return (buffer);
+}
+
+
+/*
+ * 'get_points()' - Get a value in points.
+ */
+
+static double /* O - Number in points */
+get_points(double number, /* I - Original number */
+ const char *uval) /* I - Units */
+{
+ if (!strcmp(uval, "mm")) /* Millimeters */
+ return (number * 72.0 / 25.4);
+ else if (!strcmp(uval, "cm")) /* Centimeters */
+ return (number * 72.0 / 2.54);
+ else if (!strcmp(uval, "in")) /* Inches */
+ return (number * 72.0);
+ else if (!strcmp(uval, "ft")) /* Feet */
+ return (number * 72.0 * 12.0);
+ else if (!strcmp(uval, "m")) /* Meters */
+ return (number * 72.0 / 0.0254);
+ else /* Points */
+ return (number);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/api-cgi.header b/cgi-bin/api-cgi.header
new file mode 100644
index 000000000..e3355a6b9
--- /dev/null
+++ b/cgi-bin/api-cgi.header
@@ -0,0 +1,34 @@
+<!--
+ "$Id: api-array.header 8087 2008-10-27 21:37:05Z mike $"
+
+ CGI API header for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>CGI API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/cgi.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcupscgi</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/cgi-bin/api-cgi.shtml b/cgi-bin/api-cgi.shtml
new file mode 100644
index 000000000..cf0413a5e
--- /dev/null
+++ b/cgi-bin/api-cgi.shtml
@@ -0,0 +1,17 @@
+<!--
+ "$Id: api-array.shtml 7616 2008-05-28 00:34:13Z mike $"
+
+ CGI API introduction for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>The CGI API provides Common Gateway Interface functions for CUPS.</p>
diff --git a/cgi-bin/cgi-private.h b/cgi-bin/cgi-private.h
new file mode 100644
index 000000000..a2c4e9d7a
--- /dev/null
+++ b/cgi-bin/cgi-private.h
@@ -0,0 +1,35 @@
+/*
+ * "$Id$"
+ *
+ * Private CGI definitions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi.h"
+#include <cups/debug-private.h>
+#include <cups/language-private.h>
+#include <cups/string-private.h>
+
+
+/*
+ * Limits...
+ */
+
+#define CUPS_PAGE_MAX 100 /* Maximum items per page */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/cgi.h b/cgi-bin/cgi.h
new file mode 100644
index 000000000..61eb7fc75
--- /dev/null
+++ b/cgi-bin/cgi.h
@@ -0,0 +1,119 @@
+/*
+ * "$Id$"
+ *
+ * CGI support library definitions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPS_CGI_H_
+# define _CUPS_CGI_H_
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <time.h>
+# include <sys/stat.h>
+
+# ifdef WIN32
+# include <direct.h>
+# include <io.h>
+# else
+# include <unistd.h>
+# endif /* WIN32 */
+
+# include <cups/cups.h>
+# include <cups/array.h>
+# include "help-index.h"
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+/*
+ * 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 cgiClearVariables(void);
+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 void cgiEndMultipart(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 const char *cgiGetCookie(const char *name);
+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 void cgiMoveJobs(http_t *http, const char *dest, int job_id);
+extern void cgiPrintCommand(http_t *http, const char *dest,
+ const char *command, const char *title);
+extern void cgiPrintTestPage(http_t *http, const char *dest);
+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 cgiShowIPPError(const char *message);
+extern void cgiShowJobs(http_t *http, const char *dest);
+extern void cgiStartHTML(const char *title);
+extern void cgiStartMultipart(void);
+extern int cgiSupportsMultipart(void);
+extern const char *cgiText(const char *message);
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_CGI_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/classes.c b/cgi-bin/classes.c
new file mode 100644
index 000000000..293b2c3a8
--- /dev/null
+++ b/cgi-bin/classes.c
@@ -0,0 +1,558 @@
+/*
+ * "$Id$"
+ *
+ * Class status CGI for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Main entry for CGI.
+ * do_class_op() - Do a class operation.
+ * show_all_classes() - Show all classes...
+ * show_class() - Show a single class.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi-private.h"
+
+
+/*
+ * Local functions...
+ */
+
+static void do_class_op(http_t *http, const char *printer, ipp_op_t op,
+ const char *title);
+static void show_all_classes(http_t *http, const char *username);
+static void show_class(http_t *http, const char *printer);
+
+
+/*
+ * 'main()' - Main entry for CGI.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ const char *pclass; /* Class name */
+ const char *user; /* Username */
+ http_t *http; /* Connection to the server */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* IPP attribute */
+ 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");
+ cgiSetVariable("REFRESH_PAGE", "");
+
+ /*
+ * See if we are displaying a printer or all classes...
+ */
+
+ if ((pclass = getenv("PATH_INFO")) != NULL)
+ {
+ pclass ++;
+
+ if (!*pclass)
+ pclass = NULL;
+
+ if (pclass)
+ cgiSetVariable("PRINTER_NAME", pclass);
+ }
+
+ /*
+ * See who is logged in...
+ */
+
+ user = getenv("REMOTE_USER");
+
+ /*
+ * Connect to the HTTP server...
+ */
+
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ /*
+ * Get the default printer...
+ */
+
+ if (!op || !cgiIsPOST())
+ {
+ /*
+ * Get the default destination...
+ */
+
+ request = ippNewRequest(CUPS_GET_DEFAULT);
+
+ 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);
+ }
+
+ /*
+ * See if we need to show a list of classes or the status of a
+ * single printer...
+ */
+
+ if (!pclass)
+ show_all_classes(http, user);
+ else
+ show_class(http, pclass);
+ }
+ else if (pclass)
+ {
+ if (!*op)
+ {
+ const char *server_port = getenv("SERVER_PORT");
+ /* Port number string */
+ int port = atoi(server_port ? server_port : "0");
+ /* Port number */
+ char uri[1024]; /* URL */
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri),
+ getenv("HTTPS") ? "https" : "http", NULL,
+ getenv("SERVER_NAME"), port, "/classes/%s", pclass);
+
+ printf("Location: %s\n\n", uri);
+ }
+ else if (!strcmp(op, "start-class"))
+ do_class_op(http, pclass, IPP_RESUME_PRINTER, cgiText(_("Resume Class")));
+ else if (!strcmp(op, "stop-class"))
+ do_class_op(http, pclass, IPP_PAUSE_PRINTER, cgiText(_("Pause Class")));
+ else if (!strcmp(op, "accept-jobs"))
+ do_class_op(http, pclass, CUPS_ACCEPT_JOBS, cgiText(_("Accept Jobs")));
+ else if (!strcmp(op, "reject-jobs"))
+ do_class_op(http, pclass, CUPS_REJECT_JOBS, cgiText(_("Reject Jobs")));
+ else if (!strcmp(op, "purge-jobs"))
+ do_class_op(http, pclass, IPP_PURGE_JOBS, cgiText(_("Purge Jobs")));
+ else if (!_cups_strcasecmp(op, "print-test-page"))
+ cgiPrintTestPage(http, pclass);
+ else if (!_cups_strcasecmp(op, "move-jobs"))
+ cgiMoveJobs(http, pclass, 0);
+ else
+ {
+ /*
+ * Unknown/bad operation...
+ */
+
+ cgiStartHTML(pclass);
+ cgiCopyTemplateLang("error-op.tmpl");
+ cgiEndHTML();
+ }
+ }
+ else
+ {
+ /*
+ * Unknown/bad operation...
+ */
+
+ cgiStartHTML(cgiText(_("Classes")));
+ cgiCopyTemplateLang("error-op.tmpl");
+ cgiEndHTML();
+ }
+
+ /*
+ * Close the HTTP server connection...
+ */
+
+ httpClose(http);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'do_class_op()' - Do a class operation.
+ */
+
+static void
+do_class_op(http_t *http, /* I - HTTP connection */
+ const char *printer, /* I - Printer name */
+ ipp_op_t op, /* I - Operation to perform */
+ const char *title) /* I - Title of page */
+{
+ ipp_t *request; /* IPP request */
+ char uri[HTTP_MAX_URI], /* Printer URI */
+ resource[HTTP_MAX_URI]; /* Path for request */
+
+
+ /*
+ * Build a printer request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ request = ippNewRequest(op);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/classes/%s", printer);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ snprintf(resource, sizeof(resource), "/classes/%s", printer);
+ ippDelete(cupsDoRequest(http, request, resource));
+
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+ else if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML(title);
+ cgiShowIPPError(_("Unable to do maintenance command:"));
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the printer page...
+ */
+
+ char url[1024], /* Printer/class URL */
+ refresh[1024]; /* Refresh URL */
+
+
+ cgiRewriteURL(uri, url, sizeof(url), NULL);
+ cgiFormEncode(uri, url, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "5;URL=%s", uri);
+ cgiSetVariable("refresh_page", refresh);
+
+ cgiStartHTML(title);
+
+ cgiSetVariable("IS_CLASS", "YES");
+
+ 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");
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'show_all_classes()' - Show all classes...
+ */
+
+static void
+show_all_classes(http_t *http, /* I - Connection to server */
+ const char *user) /* I - Username */
+{
+ int i; /* Looping var */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ cups_array_t *classes; /* Array of class objects */
+ ipp_attribute_t *pclass; /* Class object */
+ int ascending, /* Order of classes (0 = descending) */
+ first, /* First class to show */
+ count; /* Number of classes */
+ const char *var; /* Form variable */
+ void *search; /* Search data */
+ char val[1024]; /* Form variable */
+
+
+ /*
+ * Show the standard header...
+ */
+
+ cgiStartHTML(cgiText(_("Classes")));
+
+ /*
+ * Build a CUPS_GET_CLASSES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requesting-user-name
+ */
+
+ request = ippNewRequest(CUPS_GET_CLASSES);
+
+ if (user)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+
+ cgiGetAttributes(request, "classes.tmpl");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ /*
+ * Get a list of matching job objects.
+ */
+
+ if ((var = cgiGetVariable("QUERY")) != NULL &&
+ !cgiGetVariable("CLEAR"))
+ search = cgiCompileSearch(var);
+ else
+ search = NULL;
+
+ classes = cgiGetIPPObjects(response, search);
+ count = cupsArrayCount(classes);
+
+ if (search)
+ cgiFreeSearch(search);
+
+ /*
+ * Figure out which classes 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(val, "%d", count);
+ cgiSetVariable("TOTAL", val);
+
+ if ((var = cgiGetVariable("ORDER")) != NULL)
+ ascending = !_cups_strcasecmp(var, "asc");
+ else
+ ascending = 1;
+
+ if (ascending)
+ {
+ for (i = 0, pclass = (ipp_attribute_t *)cupsArrayIndex(classes, first);
+ i < CUPS_PAGE_MAX && pclass;
+ i ++, pclass = (ipp_attribute_t *)cupsArrayNext(classes))
+ cgiSetIPPObjectVars(pclass, NULL, i);
+ }
+ else
+ {
+ for (i = 0, pclass = (ipp_attribute_t *)cupsArrayIndex(classes, count - first - 1);
+ i < CUPS_PAGE_MAX && pclass;
+ i ++, pclass = (ipp_attribute_t *)cupsArrayPrev(classes))
+ cgiSetIPPObjectVars(pclass, NULL, i);
+ }
+
+ /*
+ * Save navigation URLs...
+ */
+
+ cgiSetVariable("THISURL", "/classes/");
+
+ if (first > 0)
+ {
+ sprintf(val, "%d", first - CUPS_PAGE_MAX);
+ cgiSetVariable("PREV", val);
+ }
+
+ if ((first + CUPS_PAGE_MAX) < count)
+ {
+ sprintf(val, "%d", first + CUPS_PAGE_MAX);
+ cgiSetVariable("NEXT", val);
+ }
+
+ /*
+ * Then show everything...
+ */
+
+ cgiCopyTemplateLang("search.tmpl");
+
+ cgiCopyTemplateLang("classes-header.tmpl");
+
+ if (count > CUPS_PAGE_MAX)
+ cgiCopyTemplateLang("pager.tmpl");
+
+ cgiCopyTemplateLang("classes.tmpl");
+
+ if (count > CUPS_PAGE_MAX)
+ cgiCopyTemplateLang("pager.tmpl");
+
+ /*
+ * Delete the response...
+ */
+
+ cupsArrayDelete(classes);
+ ippDelete(response);
+ }
+ else
+ {
+ /*
+ * Show the error...
+ */
+
+ cgiShowIPPError(_("Unable to get class list:"));
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'show_class()' - Show a single class.
+ */
+
+static void
+show_class(http_t *http, /* I - Connection to server */
+ const char *pclass) /* I - Name of class */
+{
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* IPP attribute */
+ char uri[HTTP_MAX_URI]; /* Printer URI */
+ char refresh[1024]; /* Refresh URL */
+
+
+ /*
+ * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/classes/%s", pclass);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
+ uri);
+
+ cgiGetAttributes(request, "class.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 (pclass && (attr = ippFindAttribute(response, "printer-state",
+ IPP_TAG_ENUM)) != NULL &&
+ attr->values[0].integer == IPP_PRINTER_PROCESSING)
+ {
+ /*
+ * Class is processing - automatically refresh the page until we
+ * are done printing...
+ */
+
+ cgiFormEncode(uri, pclass, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "10;URL=/classes/%s", uri);
+ cgiSetVariable("refresh_page", refresh);
+ }
+
+ /*
+ * Delete the response...
+ */
+
+ ippDelete(response);
+
+ /*
+ * Show the standard header...
+ */
+
+ cgiStartHTML(pclass);
+
+ /*
+ * Show the class status...
+ */
+
+ cgiCopyTemplateLang("class.tmpl");
+
+ /*
+ * Show jobs for the specified class...
+ */
+
+ cgiCopyTemplateLang("class-jobs-header.tmpl");
+ cgiShowJobs(http, pclass);
+ }
+ else
+ {
+ /*
+ * Show the IPP error...
+ */
+
+ cgiStartHTML(pclass);
+ cgiShowIPPError(_("Unable to get class status:"));
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/help-index.c b/cgi-bin/help-index.c
new file mode 100644
index 000000000..07d6c79e3
--- /dev/null
+++ b/cgi-bin/help-index.c
@@ -0,0 +1,1331 @@
+/*
+ * "$Id$"
+ *
+ * Online help index routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "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_add_word() - Add a word to a node.
+ * help_compile_search() - Convert a search string into a regular expression.
+ * help_delete_node() - Free all memory used by a node.
+ * help_delete_word() - Free all memory used by a word.
+ * 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.
+ * help_sort_words() - Sort words alphabetically.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi-private.h"
+#include <cups/dir.h>
+
+
+/*
+ * List of common English words that should not be indexed...
+ */
+
+static char help_common_words[][6] =
+ {
+ "about",
+ "all",
+ "an",
+ "and",
+ "are",
+ "as",
+ "at",
+ "be",
+ "been",
+ "but",
+ "by",
+ "call",
+ "can",
+ "come",
+ "could",
+ "day",
+ "did",
+ "do",
+ "down",
+ "each",
+ "find",
+ "first",
+ "for",
+ "from",
+ "go",
+ "had",
+ "has",
+ "have",
+ "he",
+ "her",
+ "him",
+ "his",
+ "hot",
+ "how",
+ "if",
+ "in",
+ "is",
+ "it",
+ "know",
+ "like",
+ "long",
+ "look",
+ "make",
+ "many",
+ "may",
+ "more",
+ "most",
+ "my",
+ "no",
+ "now",
+ "of",
+ "on",
+ "one",
+ "or",
+ "other",
+ "out",
+ "over",
+ "said",
+ "see",
+ "she",
+ "side",
+ "so",
+ "some",
+ "sound",
+ "than",
+ "that",
+ "the",
+ "their",
+ "them",
+ "then",
+ "there",
+ "these",
+ "they",
+ "thing",
+ "this",
+ "time",
+ "to",
+ "two",
+ "up",
+ "use",
+ "was",
+ "water",
+ "way",
+ "we",
+ "were",
+ "what",
+ "when",
+ "which",
+ "who",
+ "will",
+ "with",
+ "word",
+ "would",
+ "write",
+ "you",
+ "your"
+ };
+
+
+/*
+ * Local functions...
+ */
+
+static help_word_t *help_add_word(help_node_t *n, const char *text);
+static void help_delete_node(help_node_t *n);
+static void help_delete_word(help_word_t *w);
+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(help_node_t *p1, help_node_t *p2);
+static int help_sort_by_score(help_node_t *p1, help_node_t *p2);
+static int help_sort_words(help_word_t *w1, help_word_t *w2);
+
+
+/*
+ * 'helpDeleteIndex()' - Delete an index, freeing all memory used.
+ */
+
+void
+helpDeleteIndex(help_index_t *hi) /* I - Help index */
+{
+ help_node_t *node; /* Current node */
+
+
+ DEBUG_printf(("helpDeleteIndex(hi=%p)\n", hi));
+
+ if (!hi)
+ return;
+
+ for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
+ node;
+ node = (help_node_t *)cupsArrayNext(hi->nodes))
+ {
+ if (!hi->search)
+ help_delete_node(node);
+ }
+
+ cupsArrayDelete(hi->nodes);
+ cupsArrayDelete(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 */
+
+
+ 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;
+
+ /*
+ * Return any match...
+ */
+
+ return ((help_node_t *)cupsArrayFind(hi->nodes, &key));
+}
+
+
+/*
+ * '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? */
+ help_node_t *node; /* Current node */
+ help_word_t *word; /* Current word */
+
+
+ DEBUG_printf(("helpLoadIndex(hifile=\"%s\", directory=\"%s\")\n",
+ hifile, directory));
+
+ /*
+ * Create a new, empty index.
+ */
+
+ if ((hi = (help_index_t *)calloc(1, sizeof(help_index_t))) == NULL)
+ return (NULL);
+
+ hi->nodes = cupsArrayNew((cups_array_func_t)help_sort_by_name, NULL);
+ hi->sorted = cupsArrayNew((cups_array_func_t)help_sort_by_score, NULL);
+
+ if (!hi->nodes || !hi->sorted)
+ {
+ cupsArrayDelete(hi->nodes);
+ cupsArrayDelete(hi->sorted);
+ free(hi);
+ return (NULL);
+ }
+
+ /*
+ * 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, "HELPV2"))
+ {
+ /*
+ * Got a valid header line, now read the data lines...
+ */
+
+ node = NULL;
+
+ 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"
+ * SP count word
+ */
+
+ if (line[0] == ' ')
+ {
+ /*
+ * Read a word in the current node...
+ */
+
+ if (!node || (ptr = strrchr(line, ' ')) == NULL)
+ continue;
+
+ if ((word = help_add_word(node, ptr + 1)) != NULL)
+ word->count = atoi(line + 1);
+ }
+ else
+ {
+ /*
+ * Add a node...
+ */
+
+ 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;
+
+ node->score = -1;
+
+ cupsArrayAdd(hi->nodes, node);
+ }
+ }
+ }
+
+ cupsFileClose(fp);
+ }
+
+ /*
+ * Scan for new/updated files...
+ */
+
+ update = help_load_directory(hi, directory, NULL);
+
+ /*
+ * Remove any files that are no longer installed...
+ */
+
+ for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
+ node;
+ node = (help_node_t *)cupsArrayNext(hi->nodes))
+ if (node->score < 0)
+ {
+ /*
+ * Delete this node...
+ */
+
+ cupsArrayRemove(hi->nodes, node);
+ help_delete_node(node);
+ }
+
+ /*
+ * Add nodes to the sorted array...
+ */
+
+ for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
+ node;
+ node = (help_node_t *)cupsArrayNext(hi->nodes))
+ cupsArrayAdd(hi->sorted, node);
+
+ /*
+ * Save the index if we updated it...
+ */
+
+ if (update)
+ helpSaveIndex(hi, hifile);
+
+ /*
+ * 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 */
+ help_node_t *node; /* Current node */
+ help_word_t *word; /* Current word */
+
+
+ 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, "HELPV2\n");
+
+ for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
+ node;
+ node = (help_node_t *)cupsArrayNext(hi->nodes))
+ {
+ /*
+ * Write the current node with/without the anchor...
+ */
+
+ 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, (int)node->mtime,
+ CUPS_LLCAST node->offset, CUPS_LLCAST node->length,
+ node->section ? node->section : "", node->text) < 0)
+ break;
+ }
+
+ /*
+ * Then write the words associated with the node...
+ */
+
+ for (word = (help_word_t *)cupsArrayFirst(node->words);
+ word;
+ word = (help_word_t *)cupsArrayNext(node->words))
+ if (cupsFilePrintf(fp, " %d %s\n", word->count, word->text) < 0)
+ break;
+ }
+
+ cupsFileFlush(fp);
+
+ if (cupsFileClose(fp) < 0)
+ return (-1);
+ else if (node)
+ 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 */
+{
+ help_index_t *search; /* Search index */
+ help_node_t *node; /* Current node */
+ help_word_t *word; /* Current word */
+ 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);
+
+ /*
+ * Reset the scores of all nodes to 0...
+ */
+
+ for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
+ node;
+ node = (help_node_t *)cupsArrayNext(hi->nodes))
+ node->score = 0;
+
+ /*
+ * Find the first node to search in...
+ */
+
+ if (filename)
+ {
+ node = helpFindNode(hi, filename, NULL);
+ if (!node)
+ return (NULL);
+ }
+ else
+ node = (help_node_t *)cupsArrayFirst(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->nodes = cupsArrayNew((cups_array_func_t)help_sort_by_name, NULL);
+ search->sorted = cupsArrayNew((cups_array_func_t)help_sort_by_score, NULL);
+
+ if (!search->nodes || !search->sorted)
+ {
+ cupsArrayDelete(search->nodes);
+ cupsArrayDelete(search->sorted);
+ free(search);
+ cgiFreeSearch(sc);
+ return (NULL);
+ }
+
+ search->search = 1;
+
+ /*
+ * Check each node in the index, adding matching nodes to the
+ * search index...
+ */
+
+ for (; node; node = (help_node_t *)cupsArrayNext(hi->nodes))
+ if (section && strcmp(node->section, section))
+ continue;
+ else if (filename && strcmp(node->filename, filename))
+ continue;
+ else
+ {
+ matches = cgiDoSearch(sc, node->text);
+
+ for (word = (help_word_t *)cupsArrayFirst(node->words);
+ word;
+ word = (help_word_t *)cupsArrayNext(node->words))
+ if (cgiDoSearch(sc, word->text) > 0)
+ matches += word->count;
+
+ if (matches > 0)
+ {
+ /*
+ * Found a match, add the node to the search index...
+ */
+
+ node->score = matches;
+
+ cupsArrayAdd(search->nodes, node);
+ cupsArrayAdd(search->sorted, node);
+ }
+ }
+
+ /*
+ * Free the search context...
+ */
+
+ cgiFreeSearch(sc);
+
+ /*
+ * Return the results...
+ */
+
+ return (search);
+}
+
+
+/*
+ * 'help_add_word()' - Add a word to a node.
+ */
+
+static help_word_t * /* O - New word */
+help_add_word(help_node_t *n, /* I - Node */
+ const char *text) /* I - Word text */
+{
+ help_word_t *w, /* New word */
+ key; /* Search key */
+
+
+ DEBUG_printf(("help_add_word(n=%p, text=\"%s\")\n", n, text));
+
+ /*
+ * Create the words array as needed...
+ */
+
+ if (!n->words)
+ n->words = cupsArrayNew((cups_array_func_t)help_sort_words, NULL);
+
+ /*
+ * See if the word is already added...
+ */
+
+ key.text = (char *)text;
+
+ if ((w = (help_word_t *)cupsArrayFind(n->words, &key)) == NULL)
+ {
+ /*
+ * Create a new word...
+ */
+
+ if ((w = calloc(1, sizeof(help_word_t))) == NULL)
+ return (NULL);
+
+ if ((w->text = strdup(text)) == NULL)
+ {
+ free(w);
+ return (NULL);
+ }
+
+ cupsArrayAdd(n->words, w);
+ }
+
+ /*
+ * Bump the counter for this word and return it...
+ */
+
+ w->count ++;
+
+ return (w);
+}
+
+
+/*
+ * 'help_delete_node()' - Free all memory used by a node.
+ */
+
+static void
+help_delete_node(help_node_t *n) /* I - Node */
+{
+ help_word_t *w; /* Current word */
+
+
+ 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);
+
+ for (w = (help_word_t *)cupsArrayFirst(n->words);
+ w;
+ w = (help_word_t *)cupsArrayNext(n->words))
+ help_delete_word(w);
+
+ cupsArrayDelete(n->words);
+
+ free(n);
+}
+
+
+/*
+ * 'help_delete_word()' - Free all memory used by a word.
+ */
+
+static void
+help_delete_word(help_word_t *w) /* I - Word */
+{
+ DEBUG_printf(("help_delete_word(w=%p)\n", w));
+
+ if (!w)
+ return;
+
+ if (w->text)
+ free(w->text);
+
+ free(w);
+}
+
+
+/*
+ * '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 */
+{
+ 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)
+ {
+ /*
+ * Skip "." files...
+ */
+
+ if (dent->filename[0] == '.')
+ continue;
+
+ /*
+ * 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->mtime == dent->fileinfo.st_mtime)
+ {
+ /*
+ * Same modification time, so mark all of the nodes
+ * for this file as up-to-date...
+ */
+
+ for (; node; node = (help_node_t *)cupsArrayNext(hi->nodes))
+ if (!strcmp(node->filename, relname))
+ node->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 */
+ char line[1024], /* Line from file */
+ temp[1024], /* Temporary word */
+ section[1024], /* Section */
+ *ptr, /* Pointer into line */
+ *anchor, /* Anchor name */
+ *text; /* Text for anchor */
+ off_t offset; /* File offset */
+ char quote; /* Quote character */
+ help_word_t *word; /* Current word */
+ int wordlen; /* Length of word */
+
+
+ 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 "<TITLE>", "<A NAME", or "<!-- SECTION:" prefix...
+ */
+
+ if (!_cups_strncasecmp(line, "<!-- SECTION:", 13))
+ {
+ /*
+ * Got section line, copy it!
+ */
+
+ for (ptr = line + 13; isspace(*ptr & 255); ptr ++);
+
+ strlcpy(section, ptr, sizeof(section));
+ if ((ptr = strstr(section, "-->")) != 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 (!_cups_strncasecmp(ptr, "TITLE>", 6))
+ {
+ /*
+ * Found the title...
+ */
+
+ anchor = NULL;
+ ptr += 6;
+ }
+ else if (!_cups_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 ((node = helpFindNode(hi, relative, anchor)) != NULL)
+ {
+ /*
+ * Node already in the index, so replace the text and other
+ * data...
+ */
+
+ cupsArrayRemove(hi->nodes, node);
+
+ if (node->section)
+ free(node->section);
+
+ if (node->text)
+ free(node->text);
+
+ if (node->words)
+ {
+ for (word = (help_word_t *)cupsArrayFirst(node->words);
+ word;
+ word = (help_word_t *)cupsArrayNext(node->words))
+ help_delete_word(word);
+
+ cupsArrayDelete(node->words);
+ node->words = NULL;
+ }
+
+ 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);
+ }
+
+ /*
+ * 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';
+
+ /*
+ * (Re)add the node to the array...
+ */
+
+ cupsArrayAdd(hi->nodes, node);
+
+ if (!anchor)
+ node = NULL;
+ break;
+ }
+
+ if (node)
+ {
+ /*
+ * Scan this line for words...
+ */
+
+ for (ptr = line; *ptr; ptr ++)
+ {
+ /*
+ * Skip HTML stuff...
+ */
+
+ if (*ptr == '<')
+ {
+ if (!strncmp(ptr, "<!--", 4))
+ {
+ /*
+ * Skip HTML comment...
+ */
+
+ if ((text = strstr(ptr + 4, "-->")) == NULL)
+ ptr += strlen(ptr) - 1;
+ else
+ ptr = text + 2;
+ }
+ else
+ {
+ /*
+ * Skip HTML element...
+ */
+
+ for (ptr ++; *ptr && *ptr != '>'; ptr ++)
+ {
+ if (*ptr == '\"' || *ptr == '\'')
+ {
+ for (quote = *ptr++; *ptr && *ptr != quote; ptr ++);
+
+ if (!*ptr)
+ ptr --;
+ }
+ }
+
+ if (!*ptr)
+ ptr --;
+ }
+
+ continue;
+ }
+ else if (*ptr == '&')
+ {
+ /*
+ * Skip HTML entity...
+ */
+
+ for (ptr ++; *ptr && *ptr != ';'; ptr ++);
+
+ if (!*ptr)
+ ptr --;
+
+ continue;
+ }
+ else if (!isalnum(*ptr & 255))
+ continue;
+
+ /*
+ * Found the start of a word, search until we find the end...
+ */
+
+ for (text = ptr, ptr ++; *ptr && isalnum(*ptr & 255); ptr ++);
+
+ wordlen = ptr - text;
+
+ memcpy(temp, text, wordlen);
+ temp[wordlen] = '\0';
+
+ ptr --;
+
+ if (wordlen > 1 && !bsearch(temp, help_common_words,
+ (sizeof(help_common_words) /
+ sizeof(help_common_words[0])),
+ sizeof(help_common_words[0]),
+ (int (*)(const void *, const void *))
+ _cups_strcasecmp))
+ help_add_word(node, temp);
+ }
+ }
+
+ /*
+ * 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)", (long)mtime, (long)offset,
+ (long)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(help_node_t *n1, /* I - First node */
+ help_node_t *n2) /* I - Second node */
+{
+ int diff; /* Difference */
+
+
+ DEBUG_printf(("help_sort_by_name(n1=%p(%s#%s), n2=%p(%s#%s)\n",
+ n1, n1->filename, n1->anchor ? n1->anchor : "",
+ n2, n2->filename, n2->anchor ? n2->anchor : ""));
+
+ if ((diff = strcmp(n1->filename, n2->filename)) != 0)
+ return (diff);
+
+ if (!n1->anchor && !n2->anchor)
+ return (0);
+ else if (!n1->anchor)
+ return (-1);
+ else if (!n2->anchor)
+ return (1);
+ else
+ return (strcmp(n1->anchor, n2->anchor));
+}
+
+
+/*
+ * 'help_sort_nodes_by_score()' - Sort nodes by score and text.
+ */
+
+static int /* O - Difference */
+help_sort_by_score(help_node_t *n1, /* I - First node */
+ help_node_t *n2) /* I - Second node */
+{
+ int diff; /* Difference */
+
+
+ DEBUG_printf(("help_sort_by_score(n1=%p(%d \"%s\" \"%s\"), "
+ "n2=%p(%d \"%s\" \"%s\")\n",
+ n1, n1->score, n1->section ? n1->section : "", n1->text,
+ n2, n2->score, n2->section ? n2->section : "", n2->text));
+
+ if (n1->score != n2->score)
+ return (n2->score - n1->score);
+
+ if (n1->section && !n2->section)
+ return (1);
+ else if (!n1->section && n2->section)
+ return (-1);
+ else if (n1->section && n2->section &&
+ (diff = strcmp(n1->section, n2->section)) != 0)
+ return (diff);
+
+ return (_cups_strcasecmp(n1->text, n2->text));
+}
+
+
+/*
+ * 'help_sort_words()' - Sort words alphabetically.
+ */
+
+static int /* O - Difference */
+help_sort_words(help_word_t *w1, /* I - Second word */
+ help_word_t *w2) /* I - Second word */
+{
+ DEBUG_printf(("help_sort_words(w1=%p(\"%s\"), w2=%p(\"%s\"))\n",
+ w1, w1->text, w2, w2->text));
+
+ return (_cups_strcasecmp(w1->text, w2->text));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/help-index.h b/cgi-bin/help-index.h
new file mode 100644
index 000000000..41d8d93db
--- /dev/null
+++ b/cgi-bin/help-index.h
@@ -0,0 +1,87 @@
+/*
+ * "$Id$"
+ *
+ * Online help index definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPS_HELP_INDEX_H_
+# define _CUPS_HELP_INDEX_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include <cups/array.h>
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+/*
+ * Data structures...
+ */
+
+typedef struct help_word_s /**** Help word structure... ****/
+{
+ int count; /* Number of occurrences */
+ char *text; /* Word text */
+} help_word_t;
+
+typedef struct help_node_s /**** 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 */
+ cups_array_t *words; /* Words after this node */
+ 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_s /**** Help index structure ****/
+{
+ int search; /* 1 = search index, 0 = normal */
+ cups_array_t *nodes; /* Nodes sorted by filename */
+ cups_array_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);
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_HELP_INDEX_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/help.c b/cgi-bin/help.c
new file mode 100644
index 000000000..32b6db693
--- /dev/null
+++ b/cgi-bin/help.c
@@ -0,0 +1,392 @@
+/*
+ * "$Id$"
+ *
+ * Online help CGI for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "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; /* Looping var */
+ const char *query; /* Search query */
+ const char *cache_dir; /* CUPS_CACHEDIR 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 */
+ int printable; /* Show printable version? */
+
+
+ /*
+ * Get any form variables...
+ */
+
+ cgiInitialize();
+
+ printable = cgiGetVariable("PRINTABLE") != NULL;
+
+ /*
+ * Set the web interface section...
+ */
+
+ cgiSetVariable("SECTION", "help");
+ cgiSetVariable("REFRESH_PAGE", "");
+
+ /*
+ * Load the help index...
+ */
+
+ if ((cache_dir = getenv("CUPS_CACHEDIR")) == NULL)
+ cache_dir = CUPS_CACHEDIR;
+
+ snprintf(filename, sizeof(filename), "%s/help.index", cache_dir);
+
+ 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(cgiText(_("Online Help")));
+ cgiSetVariable("ERROR", "Unable to load help index!");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ return (1);
+ }
+
+ fprintf(stderr, "DEBUG: %d nodes in help index...\n",
+ cupsArrayCount(hi->nodes));
+
+ /*
+ * See if we are viewing a file...
+ */
+
+ for (i = 0; i < argc; i ++)
+ fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);
+
+ if ((helpfile = getenv("PATH_INFO")) != NULL)
+ {
+ helpfile ++;
+
+ if (!*helpfile)
+ helpfile = NULL;
+ }
+
+ 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(cgiText(_("Online Help")));
+ cgiSetVariable("ERROR", "Unable to access help file!");
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ return (1);
+ }
+
+ if ((n = helpFindNode(hi, helpfile, NULL)) == NULL)
+ {
+ cgiStartHTML(cgiText(_("Online 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->text);
+ cgiSetVariable("TOPIC", n->section);
+
+ /*
+ * Send a standard page header...
+ */
+
+ if (printable)
+ puts("Content-Type: text/html;charset=utf-8\n");
+ else
+ cgiStartHTML(n->text);
+ }
+ else
+ {
+ /*
+ * Send a standard page header...
+ */
+
+ cgiStartHTML(cgiText(_("Online Help")));
+ }
+
+ /*
+ * Do a search as needed...
+ */
+
+ if (cgiGetVariable("CLEAR"))
+ cgiSetVariable("QUERY", "");
+
+ query = cgiGetVariable("QUERY");
+ topic = cgiGetVariable("TOPIC");
+ si = helpSearchIndex(hi, query, topic, helpfile);
+
+ cgiClearVariables();
+ if (query)
+ cgiSetVariable("QUERY", query);
+ if (topic)
+ cgiSetVariable("TOPIC", topic);
+
+ fprintf(stderr, "DEBUG: query=\"%s\", topic=\"%s\"\n",
+ query ? query : "(null)", topic ? topic : "(null)");
+
+ if (si)
+ {
+ help_node_t *nn; /* Parent node */
+
+
+ fprintf(stderr,
+ "DEBUG: si=%p, si->sorted=%p, cupsArrayCount(si->sorted)=%d\n", si,
+ si->sorted, cupsArrayCount(si->sorted));
+
+ for (i = 0, n = (help_node_t *)cupsArrayFirst(si->sorted);
+ n;
+ i ++, n = (help_node_t *)cupsArrayNext(si->sorted))
+ {
+ if (helpfile && n->anchor)
+ snprintf(line, sizeof(line), "#%s", n->anchor);
+ else if (n->anchor)
+ snprintf(line, sizeof(line), "/help/%s?QUERY=%s#%s", n->filename,
+ query ? query : "", n->anchor);
+ else
+ snprintf(line, sizeof(line), "/help/%s?QUERY=%s", n->filename,
+ query ? query : "");
+
+ cgiSetArray("QTEXT", i, n->text);
+ cgiSetArray("QLINK", i, line);
+
+ if (!helpfile && n->anchor)
+ {
+ nn = helpFindNode(hi, n->filename, NULL);
+
+ snprintf(line, sizeof(line), "/help/%s?QUERY=%s", nn->filename,
+ query ? query : "");
+
+ cgiSetArray("QPTEXT", i, nn->text);
+ cgiSetArray("QPLINK", i, line);
+ }
+ else
+ {
+ cgiSetArray("QPTEXT", i, "");
+ cgiSetArray("QPLINK", i, "");
+ }
+
+ fprintf(stderr, "DEBUG: [%d] = \"%s\" @ \"%s\"\n", i, n->text, line);
+ }
+
+ helpDeleteIndex(si);
+ }
+
+ /*
+ * OK, now list the bookmarks within the index...
+ */
+
+ for (i = 0, section = NULL, n = (help_node_t *)cupsArrayFirst(hi->sorted);
+ n;
+ n = (help_node_t *)cupsArrayNext(hi->sorted))
+ {
+ if (n->anchor)
+ continue;
+
+ /*
+ * Add a section link as needed...
+ */
+
+ if (n->section &&
+ (!section || strcmp(n->section, section)))
+ {
+ /*
+ * Add a link for this node...
+ */
+
+ snprintf(line, sizeof(line), "/help/?TOPIC=%s&QUERY=%s",
+ cgiFormEncode(topic_data, n->section, sizeof(topic_data)),
+ query ? query : "");
+ cgiSetArray("BMLINK", i, line);
+ cgiSetArray("BMTEXT", i, n->section);
+ cgiSetArray("BMINDENT", i, "0");
+
+ i ++;
+ section = n->section;
+ }
+
+ if (!topic || strcmp(n->section, topic))
+ continue;
+
+ /*
+ * Add a link for this node...
+ */
+
+ snprintf(line, sizeof(line), "/help/%s?TOPIC=%s&QUERY=%s", n->filename,
+ cgiFormEncode(topic_data, n->section, sizeof(topic_data)),
+ query ? query : "");
+ cgiSetArray("BMLINK", i, line);
+ cgiSetArray("BMTEXT", i, n->text);
+ cgiSetArray("BMINDENT", i, "1");
+
+ i ++;
+
+ if (helpfile && !strcmp(helpfile, n->filename))
+ {
+ help_node_t *nn; /* Pointer to sub-node */
+
+
+ cupsArraySave(hi->sorted);
+
+ for (nn = (help_node_t *)cupsArrayFirst(hi->sorted);
+ nn;
+ nn = (help_node_t *)cupsArrayNext(hi->sorted))
+ if (nn->anchor && !strcmp(helpfile, nn->filename))
+ {
+ /*
+ * Add a link for this node...
+ */
+
+ snprintf(line, sizeof(line), "#%s", nn->anchor);
+ cgiSetArray("BMLINK", i, line);
+ cgiSetArray("BMTEXT", i, nn->text);
+ cgiSetArray("BMINDENT", i, "2");
+
+ i ++;
+ }
+
+ cupsArrayRestore(hi->sorted);
+ }
+ }
+
+ /*
+ * Show the search and bookmark content...
+ */
+
+ if (!helpfile || !printable)
+ cgiCopyTemplateLang("help-header.tmpl");
+ else
+ cgiCopyTemplateLang("help-printable.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 (!_cups_strncasecmp(line, "</BODY>", 7))
+ break;
+
+ printf("%s\n", line);
+ }
+ else if (!_cups_strncasecmp(line, "<BODY", 5))
+ inbody = 1;
+ }
+
+ cupsFileClose(fp);
+ }
+ else
+ {
+ perror(filename);
+ cgiSetVariable("ERROR", "Unable to open help file.");
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ }
+
+ /*
+ * Send a standard trailer...
+ */
+
+ if (!printable)
+ {
+ cgiCopyTemplateLang("help-trailer.tmpl");
+ cgiEndHTML();
+ }
+ else
+ puts("</BODY>\n</HTML>");
+
+ /*
+ * Delete the index...
+ */
+
+ helpDeleteIndex(hi);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/html.c b/cgi-bin/html.c
new file mode 100644
index 000000000..9db5438eb
--- /dev/null
+++ b/cgi-bin/html.c
@@ -0,0 +1,239 @@
+/*
+ * "$Id$"
+ *
+ * HTML support functions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cgiEndHTML() - End a HTML page.
+ * cgiEndMultipart() - End the delivery of a multipart web page.
+ * cgiFormEncode() - Encode a string as a form variable.
+ * cgiStartHTML() - Start a HTML page.
+ * cgiStartMultipart() - Start a multipart delivery of a web page.
+ * cgiSupportsMultipart() - Does the browser support multi-part documents?
+ * cgi_null_passwd() - Return a NULL password for authentication.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi-private.h"
+
+
+/*
+ * Local globals...
+ */
+
+static const char *cgi_multipart = NULL;
+ /* Multipart separator, if any */
+
+
+/*
+ * Local functions...
+ */
+
+static const char *cgi_null_passwd(const char *prompt);
+
+
+/*
+ * 'cgiEndHTML()' - End a HTML page.
+ */
+
+void
+cgiEndHTML(void)
+{
+ /*
+ * Send the standard trailer...
+ */
+
+ cgiCopyTemplateLang("trailer.tmpl");
+}
+
+
+/*
+ * 'cgiEndMultipart()' - End the delivery of a multipart web page.
+ */
+
+void
+cgiEndMultipart(void)
+{
+ if (cgi_multipart)
+ {
+ printf("\n%s--\n", cgi_multipart);
+ fflush(stdout);
+ }
+}
+
+
+/*
+ * 'cgiFormEncode()' - Encode a string as a form variable.
+ */
+
+char * /* O - Destination string */
+cgiFormEncode(char *dst, /* I - Destination string */
+ const char *src, /* I - Source string */
+ size_t dstsize) /* I - Size of destination string */
+{
+ char *dstptr, /* Pointer into destination */
+ *dstend; /* End of destination */
+ static const char *hex = /* Hexadecimal characters */
+ "0123456789ABCDEF";
+
+
+ /*
+ * Mark the end of the string...
+ */
+
+ dstend = dst + dstsize - 1;
+
+ /*
+ * Loop through the source string and copy...
+ */
+
+ for (dstptr = dst; *src && dstptr < dstend;)
+ {
+ switch (*src)
+ {
+ case ' ' :
+ /*
+ * Encode spaces with a "+"...
+ */
+
+ *dstptr++ = '+';
+ src ++;
+ break;
+
+ case '&' :
+ case '%' :
+ case '+' :
+ /*
+ * Encode special characters with %XX escape...
+ */
+
+ if (dstptr < (dstend - 2))
+ {
+ *dstptr++ = '%';
+ *dstptr++ = hex[(*src & 255) >> 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...
+ */
+
+ if (cgi_multipart)
+ puts(cgi_multipart);
+
+ puts("Content-Type: text/html;charset=utf-8\n");
+
+ /*
+ * Send a standard header...
+ */
+
+ cgiSetVariable("TITLE", title);
+ cgiSetServerVersion();
+
+ cgiCopyTemplateLang("header.tmpl");
+}
+
+
+/*
+ * 'cgiStartMultipart()' - Start a multipart delivery of a web page.
+ */
+
+void
+cgiStartMultipart(void)
+{
+ puts("MIME-Version: 1.0\n"
+ "Content-Type: multipart/x-mixed-replace; boundary=\"CUPS-MULTIPART\"\n");
+ fflush(stdout);
+
+ cgi_multipart = "--CUPS-MULTIPART";
+}
+
+
+/*
+ * 'cgiSupportsMultipart()' - Does the browser support multi-part documents?
+ */
+
+int /* O - 1 if multi-part supported, 0 otherwise */
+cgiSupportsMultipart(void)
+{
+ /*
+ * Too many bug reports for browsers that don't support it, and too much pain
+ * to whitelist known-good browsers, so for now we just punt on multi-part
+ * support... :(
+ */
+
+ return (0);
+}
+
+
+/*
+ * '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 ? prompt : "(null)");
+
+ return (NULL);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/ipp-var.c b/cgi-bin/ipp-var.c
new file mode 100644
index 000000000..09288f28c
--- /dev/null
+++ b/cgi-bin/ipp-var.c
@@ -0,0 +1,1592 @@
+/*
+ * "$Id$"
+ *
+ * CGI <-> IPP variable routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cgiGetAttributes() - Get the list of attributes that are needed by the
+ * template file.
+ * cgiGetIPPObjects() - Get the objects in an IPP response.
+ * cgiMoveJobs() - Move one or more jobs.
+ * cgiPrintCommand() - Print a CUPS command job.
+ * cgiPrintTestPage() - Print a test page.
+ * 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.
+ * cgiShowIPPError() - Show the last IPP error message.
+ * cgiShowJobs() - Show print jobs.
+ * cgiText() - Return localized text.
+ */
+
+/*
+ * 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;
+ attrs[0] = NULL; /* Eliminate compiler warning */
+
+ 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]);
+ }
+
+ fclose(in);
+}
+
+
+/*
+ * 'cgiGetIPPObjects()' - 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);
+}
+
+
+/*
+ * 'cgiMoveJobs()' - Move one or more jobs.
+ *
+ * At least one of dest or job_id must be non-zero/NULL.
+ */
+
+void
+cgiMoveJobs(http_t *http, /* I - Connection to server */
+ const char *dest, /* I - Destination or NULL */
+ int job_id) /* I - Job ID or 0 for all */
+{
+ int i; /* Looping var */
+ const char *user; /* Username */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *name; /* Destination name */
+ const char *job_printer_uri; /* JOB_PRINTER_URI form variable */
+ char current_dest[1024]; /* Current destination */
+
+
+ /*
+ * Make sure we have a username...
+ */
+
+ if ((user = getenv("REMOTE_USER")) == NULL)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+
+ /*
+ * See if the user has already selected a new destination...
+ */
+
+ if ((job_printer_uri = cgiGetVariable("JOB_PRINTER_URI")) == NULL)
+ {
+ /*
+ * Make sure necessary form variables are set...
+ */
+
+ if (job_id)
+ {
+ char temp[255]; /* Temporary string */
+
+
+ sprintf(temp, "%d", job_id);
+ cgiSetVariable("JOB_ID", temp);
+ }
+
+ if (dest)
+ cgiSetVariable("PRINTER_NAME", dest);
+
+ /*
+ * No new destination specified, show the user what the available
+ * printers/classes are...
+ */
+
+ if (!dest)
+ {
+ /*
+ * Get the current destination for job N...
+ */
+
+ char job_uri[1024]; /* Job URI */
+
+
+ request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
+
+ snprintf(job_uri, sizeof(job_uri), "ipp://localhost/jobs/%d", job_id);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
+ NULL, job_uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "job-printer-uri");
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ if ((attr = ippFindAttribute(response, "job-printer-uri",
+ IPP_TAG_URI)) != NULL)
+ {
+ /*
+ * Pull the name from the URI...
+ */
+
+ strlcpy(current_dest, strrchr(attr->values[0].string.text, '/') + 1,
+ sizeof(current_dest));
+ dest = current_dest;
+ }
+
+ ippDelete(response);
+ }
+
+ if (!dest)
+ {
+ /*
+ * Couldn't get the current destination...
+ */
+
+ cgiStartHTML(cgiText(_("Move Job")));
+ cgiShowIPPError(_("Unable to find destination for job"));
+ cgiEndHTML();
+ return;
+ }
+ }
+
+ /*
+ * Get the list of available destinations...
+ */
+
+ request = ippNewRequest(CUPS_GET_PRINTERS);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "printer-uri-supported");
+
+ if (user)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+
+ 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_SCANNER);
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ for (i = 0, attr = ippFindAttribute(response, "printer-uri-supported",
+ IPP_TAG_URI);
+ attr;
+ attr = ippFindNextAttribute(response, "printer-uri-supported",
+ IPP_TAG_URI))
+ {
+ /*
+ * Pull the name from the URI...
+ */
+
+ name = strrchr(attr->values[0].string.text, '/') + 1;
+
+ /*
+ * If the name is not the same as the current destination, add it!
+ */
+
+ if (_cups_strcasecmp(name, dest))
+ {
+ cgiSetArray("JOB_PRINTER_URI", i, attr->values[0].string.text);
+ cgiSetArray("JOB_PRINTER_NAME", i, name);
+ i ++;
+ }
+ }
+
+ ippDelete(response);
+ }
+
+ /*
+ * Show the form...
+ */
+
+ if (job_id)
+ cgiStartHTML(cgiText(_("Move Job")));
+ else
+ cgiStartHTML(cgiText(_("Move All Jobs")));
+
+ if (cgiGetSize("JOB_PRINTER_NAME") > 0)
+ cgiCopyTemplateLang("job-move.tmpl");
+ else
+ {
+ if (job_id)
+ cgiSetVariable("MESSAGE", cgiText(_("Unable to move job")));
+ else
+ cgiSetVariable("MESSAGE", cgiText(_("Unable to move jobs")));
+
+ cgiSetVariable("ERROR", cgiText(_("No destinations added.")));
+ cgiCopyTemplateLang("error.tmpl");
+ }
+ }
+ else
+ {
+ /*
+ * Try moving the job or jobs...
+ */
+
+ char uri[1024], /* Job/printer URI */
+ resource[1024], /* Post resource */
+ refresh[1024]; /* Refresh URL */
+ const char *job_printer_name; /* New printer name */
+
+
+ request = ippNewRequest(CUPS_MOVE_JOB);
+
+ if (job_id)
+ {
+ /*
+ * Move 1 job...
+ */
+
+ snprintf(resource, sizeof(resource), "/jobs/%d", job_id);
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", job_id);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
+ NULL, uri);
+ }
+ else
+ {
+ /*
+ * Move all active jobs on a destination...
+ */
+
+ snprintf(resource, sizeof(resource), "/%s/%s",
+ cgiGetVariable("SECTION"), dest);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", ippPort(), "/%s/%s",
+ cgiGetVariable("SECTION"), dest);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+ }
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-printer-uri",
+ NULL, job_printer_uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+
+ ippDelete(cupsDoRequest(http, request, resource));
+
+ /*
+ * Show the results...
+ */
+
+ job_printer_name = strrchr(job_printer_uri, '/') + 1;
+
+ if (cupsLastError() <= IPP_OK_CONFLICT)
+ {
+ const char *path = strstr(job_printer_uri, "/printers/");
+ if (!path)
+ {
+ path = strstr(job_printer_uri, "/classes/");
+ cgiSetVariable("IS_CLASS", "YES");
+ }
+
+ if (path)
+ {
+ cgiFormEncode(uri, path, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "2;URL=%s", uri);
+ cgiSetVariable("refresh_page", refresh);
+ }
+ }
+
+ if (job_id)
+ cgiStartHTML(cgiText(_("Move Job")));
+ else
+ cgiStartHTML(cgiText(_("Move All Jobs")));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ if (job_id)
+ cgiShowIPPError(_("Unable to move job"));
+ else
+ cgiShowIPPError(_("Unable to move jobs"));
+ }
+ else
+ {
+ cgiSetVariable("JOB_PRINTER_NAME", job_printer_name);
+ cgiCopyTemplateLang("job-moved.tmpl");
+ }
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'cgiPrintCommand()' - Print a CUPS command job.
+ */
+
+void
+cgiPrintCommand(http_t *http, /* I - Connection to server */
+ const char *dest, /* I - Destination printer */
+ const char *command, /* I - Command to send */
+ const char *title) /* I - Page/job title */
+{
+ int job_id; /* Command file job */
+ char uri[HTTP_MAX_URI], /* Job URI */
+ resource[1024], /* Printer resource path */
+ refresh[1024], /* Refresh URL */
+ command_file[1024]; /* Command "file" */
+ http_status_t status; /* Document status */
+ cups_option_t hold_option; /* job-hold-until option */
+ const char *user; /* User name */
+ ipp_t *request, /* Get-Job-Attributes request */
+ *response; /* Get-Job-Attributes response */
+ ipp_attribute_t *attr; /* Current job attribute */
+ static const char const *job_attrs[] =/* Job attributes we want */
+ {
+ "job-state",
+ "job-printer-state-message"
+ };
+
+
+ /*
+ * Create the CUPS command file...
+ */
+
+ snprintf(command_file, sizeof(command_file), "#CUPS-COMMAND\n%s\n", command);
+
+ /*
+ * Show status...
+ */
+
+ if (cgiSupportsMultipart())
+ {
+ cgiStartMultipart();
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("command.tmpl");
+ cgiEndHTML();
+ fflush(stdout);
+ }
+
+ /*
+ * Send the command file job...
+ */
+
+ hold_option.name = "job-hold-until";
+ hold_option.value = "no-hold";
+
+ if ((user = getenv("REMOTE_USER")) != NULL)
+ cupsSetUser(user);
+ else
+ cupsSetUser("anonymous");
+
+ if ((job_id = cupsCreateJob(http, dest, title,
+ 1, &hold_option)) < 1)
+ {
+ cgiSetVariable("MESSAGE", cgiText(_("Unable to send command to printer driver")));
+ cgiSetVariable("ERROR", cupsLastErrorString());
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ if (cgiSupportsMultipart())
+ cgiEndMultipart();
+ return;
+ }
+
+ status = cupsStartDocument(http, dest, job_id, NULL, CUPS_FORMAT_COMMAND, 1);
+ if (status == HTTP_CONTINUE)
+ status = cupsWriteRequestData(http, command_file,
+ strlen(command_file));
+ if (status == HTTP_CONTINUE)
+ cupsFinishDocument(http, dest);
+
+ if (cupsLastError() >= IPP_REDIRECTION_OTHER_SITE)
+ {
+ cgiSetVariable("MESSAGE", cgiText(_("Unable to send command to printer driver")));
+ cgiSetVariable("ERROR", cupsLastErrorString());
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("error.tmpl");
+ cgiEndHTML();
+
+ if (cgiSupportsMultipart())
+ cgiEndMultipart();
+
+ cupsCancelJob(dest, job_id);
+ return;
+ }
+
+ /*
+ * Wait for the job to complete...
+ */
+
+ if (cgiSupportsMultipart())
+ {
+ for (;;)
+ {
+ /*
+ * Get the current job state...
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", job_id);
+ request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
+ NULL, uri);
+ if (user)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", 2, NULL, job_attrs);
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+ attr = ippFindAttribute(response, "job-state", IPP_TAG_ENUM);
+ if (!attr || attr->values[0].integer >= IPP_JOB_STOPPED ||
+ attr->values[0].integer == IPP_JOB_HELD)
+ {
+ ippDelete(response);
+ break;
+ }
+
+ /*
+ * Job not complete, so update the status...
+ */
+
+ ippDelete(response);
+
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("command.tmpl");
+ cgiEndHTML();
+ fflush(stdout);
+
+ sleep(5);
+ }
+ }
+
+ /*
+ * Send the final page that reloads the printer's page...
+ */
+
+ snprintf(resource, sizeof(resource), "/printers/%s", dest);
+
+ cgiFormEncode(uri, resource, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "5;URL=%s", uri);
+ cgiSetVariable("refresh_page", refresh);
+
+ cgiStartHTML(title);
+ cgiCopyTemplateLang("command.tmpl");
+ cgiEndHTML();
+
+ if (cgiSupportsMultipart())
+ cgiEndMultipart();
+}
+
+
+/*
+ * 'cgiPrintTestPage()' - Print a test page.
+ */
+
+void
+cgiPrintTestPage(http_t *http, /* I - Connection to server */
+ const char *dest) /* I - Destination printer/class */
+{
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ char uri[HTTP_MAX_URI], /* Printer URI */
+ resource[1024], /* POST resource path */
+ refresh[1024], /* Refresh URL */
+ filename[1024]; /* Test page filename */
+ const char *datadir; /* CUPS_DATADIR env var */
+ const char *user; /* Username */
+
+
+ /*
+ * See who is logged in...
+ */
+
+ user = getenv("REMOTE_USER");
+
+ /*
+ * Locate the test page file...
+ */
+
+ if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+
+ snprintf(filename, sizeof(filename), "%s/data/testprint", datadir);
+
+ /*
+ * Point to the printer/class...
+ */
+
+ snprintf(resource, sizeof(resource), "/%s/%s", cgiGetVariable("SECTION"),
+ dest);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", ippPort(), "/%s/%s", cgiGetVariable("SECTION"),
+ dest);
+
+ /*
+ * Build an IPP_PRINT_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ */
+
+ request = ippNewRequest(IPP_PRINT_JOB);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ if (user)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
+ NULL, "Test Page");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoFileRequest(http, request, resource,
+ filename)) != NULL)
+ {
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+ ippDelete(response);
+ }
+
+ if (cupsLastError() <= IPP_OK_CONFLICT)
+ {
+ /*
+ * Automatically reload the printer status page...
+ */
+
+ cgiFormEncode(uri, resource, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "2;URL=%s", uri);
+ cgiSetVariable("refresh_page", refresh);
+ }
+ else if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+
+ cgiStartHTML(cgiText(_("Print Test Page")));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ cgiShowIPPError(_("Unable to print test page:"));
+ else
+ {
+ cgiSetVariable("PRINTER_NAME", dest);
+
+ cgiCopyTemplateLang("test-page.tmpl");
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * '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 scheme[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(NULL, servername, sizeof(servername));
+
+ /*
+ * Then flag whether we are using SSL on this connection...
+ */
+
+ ishttps = getenv("HTTPS") != NULL;
+ }
+
+ /*
+ * Convert the URI to a URL...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass,
+ sizeof(userpass), hostname, sizeof(hostname), &port,
+ rawresource, sizeof(rawresource));
+
+ if (!strcmp(scheme, "ipp") ||
+ !strcmp(scheme, "http") ||
+ !strcmp(scheme, "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 (!_cups_strcasecmp(hostname, "127.0.0.1") ||
+ !_cups_strcasecmp(hostname, "[::1]") ||
+ !_cups_strcasecmp(hostname, "localhost") ||
+ !_cups_strncasecmp(hostname, "localhost.", 10) ||
+ !_cups_strcasecmp(hostname, server) ||
+ !_cups_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 ? prefix : "(null)", 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);
+ }
+
+ /*
+ * Localize event names in "notify_events" variable...
+ */
+
+ if (!strcmp(name, "notify_events"))
+ {
+ size_t remaining; /* Remaining bytes in buffer */
+
+
+ value[0] = '\0';
+ valptr = value;
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (valptr >= (value + sizeof(value) - 3))
+ break;
+
+ if (i)
+ {
+ *valptr++ = ',';
+ *valptr++ = ' ';
+ }
+
+ remaining = sizeof(value) - (valptr - value);
+
+ if (!strcmp(attr->values[i].string.text, "printer-stopped"))
+ strlcpy(valptr, _("Printer Paused"), remaining);
+ else if (!strcmp(attr->values[i].string.text, "printer-added"))
+ strlcpy(valptr, _("Printer Added"), remaining);
+ else if (!strcmp(attr->values[i].string.text, "printer-modified"))
+ strlcpy(valptr, _("Printer Modified"), remaining);
+ else if (!strcmp(attr->values[i].string.text, "printer-deleted"))
+ strlcpy(valptr, _("Printer Deleted"), remaining);
+ else if (!strcmp(attr->values[i].string.text, "job-created"))
+ strlcpy(valptr, _("Job Created"), remaining);
+ else if (!strcmp(attr->values[i].string.text, "job-completed"))
+ strlcpy(valptr, _("Job Completed"), remaining);
+ else if (!strcmp(attr->values[i].string.text, "job-stopped"))
+ strlcpy(valptr, _("Job Stopped"), remaining);
+ else if (!strcmp(attr->values[i].string.text, "job-config-changed"))
+ strlcpy(valptr, _("Job Options Changed"), remaining);
+ else if (!strcmp(attr->values[i].string.text, "server-restarted"))
+ strlcpy(valptr, _("Server Restarted"), remaining);
+ else if (!strcmp(attr->values[i].string.text, "server-started"))
+ strlcpy(valptr, _("Server Started"), remaining);
+ else if (!strcmp(attr->values[i].string.text, "server-stopped"))
+ strlcpy(valptr, _("Server Stopped"), remaining);
+ else if (!strcmp(attr->values[i].string.text, "server-audit"))
+ strlcpy(valptr, _("Server Security Auditing"), remaining);
+ else
+ strlcpy(valptr, attr->values[i].string.text, remaining);
+
+ valptr += strlen(valptr);
+ }
+
+ cgiSetArray("notify_events", element, value);
+ continue;
+ }
+
+ /*
+ * Add "notify_printer_name" variable if we have a "notify_printer_uri"
+ * attribute...
+ */
+
+ if (!strcmp(name, "notify_printer_uri"))
+ {
+ if ((valptr = strrchr(attr->values[0].string.text, '/')) == NULL)
+ valptr = "unknown";
+ else
+ valptr ++;
+
+ cgiSetArray("notify_printer_name", element, valptr);
+ }
+
+ /*
+ * Add "notify_recipient_name" variable if we have a "notify_recipient_uri"
+ * attribute, and rewrite recipient URI...
+ */
+
+ if (!strcmp(name, "notify_recipient_uri"))
+ {
+ char uri[1024], /* New URI */
+ scheme[32], /* Scheme portion of URI */
+ userpass[256], /* Username/password portion of URI */
+ host[1024], /* Hostname portion of URI */
+ resource[1024], /* Resource portion of URI */
+ *options; /* Options in URI */
+ int port; /* Port number */
+
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text,
+ scheme, sizeof(scheme), userpass, sizeof(userpass),
+ host, sizeof(host), &port, resource, sizeof(resource));
+
+ if (!strcmp(scheme, "rss"))
+ {
+ /*
+ * RSS notification...
+ */
+
+ if ((options = strchr(resource, '?')) != NULL)
+ *options = '\0';
+
+ if (host[0])
+ {
+ /*
+ * Link to remote feed...
+ */
+
+ httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "http",
+ userpass, host, port, resource);
+ strlcpy(name, uri, sizeof(name));
+ }
+ else
+ {
+ /*
+ * Link to local feed...
+ */
+
+ snprintf(uri, sizeof(uri), "/rss%s", resource);
+ strlcpy(name, resource + 1, sizeof(name));
+ }
+ }
+ else
+ {
+ /*
+ * Other...
+ */
+
+ strlcpy(uri, attr->values[0].string.text, sizeof(uri));
+ strlcpy(name, resource, sizeof(name));
+ }
+
+ cgiSetArray("notify_recipient_uri", element, uri);
+ cgiSetArray("notify_recipient_name", element, name);
+ continue;
+ }
+
+ /*
+ * 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, ':') &&
+ strcmp(name, "device_uri"))
+ {
+ /*
+ * 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),
+ "<A HREF=\"%s\">%s</A>", url,
+ strrchr(attr->values[i].string.text, '/') + 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_name : "(null)",
+ filter_value ? filter_value : "(null)",
+ prefix ? prefix : "(null)", 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 &&
+ !_cups_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);
+
+ return (element);
+}
+
+
+/*
+ * 'cgiShowIPPError()' - Show the last IPP error message.
+ *
+ * The caller must still call cgiStartHTML() and cgiEndHTML().
+ */
+
+void
+cgiShowIPPError(const char *message) /* I - Contextual message */
+{
+ cgiSetVariable("MESSAGE", cgiText(message));
+ cgiSetVariable("ERROR", cupsLastErrorString());
+ cgiCopyTemplateLang("error.tmpl");
+}
+
+
+/*
+ * '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 */
+ *query, /* Query string */
+ *section; /* Section in web interface */
+ void *search; /* Search data */
+ char url[1024], /* Printer URI */
+ val[1024]; /* Form variable */
+
+
+ /*
+ * Build an IPP_GET_JOBS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ request = ippNewRequest(IPP_GET_JOBS);
+
+ if (dest)
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, 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, "printer-uri", NULL,
+ "ipp://localhost/");
+
+ 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 ((query = cgiGetVariable("QUERY")) != NULL &&
+ !cgiGetVariable("CLEAR"))
+ search = cgiCompileSearch(query);
+ else
+ {
+ query = NULL;
+ 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;
+
+ if ((var = cgiGetVariable("ORDER")) != NULL)
+ ascending = !_cups_strcasecmp(var, "asc");
+ else
+ ascending = !which_jobs || !_cups_strcasecmp(which_jobs, "not-completed");
+
+ section = cgiGetVariable("SECTION");
+
+ cgiClearVariables();
+
+ if (query)
+ cgiSetVariable("QUERY", query);
+
+ cgiSetVariable("ORDER", ascending ? "asc" : "dec");
+
+ cgiSetVariable("SECTION", section);
+
+ sprintf(val, "%d", count);
+ cgiSetVariable("TOTAL", val);
+
+ if (which_jobs)
+ cgiSetVariable("WHICH_JOBS", which_jobs);
+
+ 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...
+ */
+
+ if (dest)
+ {
+ snprintf(val, sizeof(val), "/%s/%s", section, dest);
+ cgiSetVariable("PRINTER_NAME", dest);
+ cgiSetVariable("PRINTER_URI_SUPPORTED", val);
+ }
+ else
+ strlcpy(val, "/jobs/", sizeof(val));
+
+ cgiSetVariable("THISURL", val);
+
+ if (first > 0)
+ {
+ sprintf(val, "%d", first - CUPS_PAGE_MAX);
+ cgiSetVariable("PREV", val);
+ }
+
+ if ((first + CUPS_PAGE_MAX) < count)
+ {
+ sprintf(val, "%d", first + CUPS_PAGE_MAX);
+ cgiSetVariable("NEXT", val);
+ }
+
+ /*
+ * Then show everything...
+ */
+
+ if (dest)
+ cgiSetVariable("SEARCH_DEST", dest);
+
+ cgiCopyTemplateLang("search.tmpl");
+
+ cgiCopyTemplateLang("jobs-header.tmpl");
+
+ if (count > CUPS_PAGE_MAX)
+ cgiCopyTemplateLang("pager.tmpl");
+
+ cgiCopyTemplateLang("jobs.tmpl");
+
+ if (count > CUPS_PAGE_MAX)
+ cgiCopyTemplateLang("pager.tmpl");
+
+ cupsArrayDelete(jobs);
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * 'cgiText()' - Return localized text.
+ */
+
+const char * /* O - Localized message */
+cgiText(const char *message) /* I - Message */
+{
+ static cups_lang_t *language = NULL;
+ /* Language */
+
+
+ if (!language)
+ language = cupsLangDefault();
+
+ return (_cupsLangString(language, message));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/jobs.c b/cgi-bin/jobs.c
new file mode 100644
index 000000000..6c4f09852
--- /dev/null
+++ b/cgi-bin/jobs.c
@@ -0,0 +1,214 @@
+/*
+ * "$Id$"
+ *
+ * Job status CGI for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "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, int job_id, 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 */
+{
+ http_t *http; /* Connection to the server */
+ const char *op; /* Operation name */
+ const char *job_id_var; /* Job ID form variable */
+ int job_id; /* Job ID */
+
+
+ /*
+ * Get any form variables...
+ */
+
+ cgiInitialize();
+
+ /*
+ * Set the web interface section...
+ */
+
+ cgiSetVariable("SECTION", "jobs");
+ cgiSetVariable("REFRESH_PAGE", "");
+
+ /*
+ * Connect to the HTTP server...
+ */
+
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ /*
+ * Get the job ID, if any...
+ */
+
+ if ((job_id_var = cgiGetVariable("JOB_ID")) != NULL)
+ job_id = atoi(job_id_var);
+ else
+ job_id = 0;
+
+ /*
+ * Do the operation...
+ */
+
+ if ((op = cgiGetVariable("OP")) != NULL && job_id > 0 && cgiIsPOST())
+ {
+ /*
+ * Do the operation...
+ */
+
+ if (!strcmp(op, "cancel-job"))
+ do_job_op(http, job_id, IPP_CANCEL_JOB);
+ else if (!strcmp(op, "hold-job"))
+ do_job_op(http, job_id, IPP_HOLD_JOB);
+ else if (!strcmp(op, "move-job"))
+ cgiMoveJobs(http, NULL, job_id);
+ else if (!strcmp(op, "release-job"))
+ do_job_op(http, job_id, IPP_RELEASE_JOB);
+ else if (!strcmp(op, "restart-job"))
+ do_job_op(http, job_id, IPP_RESTART_JOB);
+ else
+ {
+ /*
+ * Bad operation code... Display an error...
+ */
+
+ cgiStartHTML(cgiText(_("Jobs")));
+ cgiCopyTemplateLang("error-op.tmpl");
+ cgiEndHTML();
+ }
+ }
+ else
+ {
+ /*
+ * Show a list of jobs...
+ */
+
+ cgiStartHTML(cgiText(_("Jobs")));
+ cgiShowJobs(http, NULL);
+ cgiEndHTML();
+ }
+
+ /*
+ * Close the HTTP server connection...
+ */
+
+ httpClose(http);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'do_job_op()' - Do a job operation.
+ */
+
+static void
+do_job_op(http_t *http, /* I - HTTP connection */
+ int job_id, /* I - Job ID */
+ ipp_op_t op) /* I - Operation to perform */
+{
+ ipp_t *request; /* IPP request */
+ char uri[HTTP_MAX_URI]; /* Job URI */
+ const char *user; /* Username */
+
+
+ /*
+ * 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 = ippNewRequest(op);
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", job_id);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
+ NULL, uri);
+
+ if ((user = getenv("REMOTE_USER")) == NULL)
+ user = "guest";
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ippDelete(cupsDoRequest(http, request, "/jobs"));
+
+ if (cupsLastError() <= IPP_OK_CONFLICT && getenv("HTTP_REFERER"))
+ {
+ /*
+ * Redirect successful updates back to the parent page...
+ */
+
+ char url[1024]; /* Encoded URL */
+
+
+ strcpy(url, "5;URL=");
+ cgiFormEncode(url + 6, getenv("HTTP_REFERER"), sizeof(url) - 6);
+ cgiSetVariable("refresh_page", url);
+ }
+ else if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+
+ cgiStartHTML(cgiText(_("Jobs")));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ cgiShowIPPError(_("Job operation failed:"));
+ 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");
+
+ cgiEndHTML();
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/libcupscgi.exp b/cgi-bin/libcupscgi.exp
new file mode 100644
index 000000000..3a26229d7
--- /dev/null
+++ b/cgi-bin/libcupscgi.exp
@@ -0,0 +1,42 @@
+_cgiCheckVariables
+_cgiClearVariables
+_cgiCompileSearch
+_cgiCopyTemplateFile
+_cgiCopyTemplateLang
+_cgiDoSearch
+_cgiEndHTML
+_cgiEndMultipart
+_cgiFormEncode
+_cgiFreeSearch
+_cgiGetArray
+_cgiGetAttributes
+_cgiGetCookie
+_cgiGetFile
+_cgiGetIPPObjects
+_cgiGetSize
+_cgiGetTemplateDir
+_cgiGetVariable
+_cgiInitialize
+_cgiIsPOST
+_cgiMoveJobs
+_cgiPrintCommand
+_cgiPrintTestPage
+_cgiRewriteURL
+_cgiSetArray
+_cgiSetIPPObjectVars
+_cgiSetIPPVars
+_cgiSetCookie
+_cgiSetServerVersion
+_cgiSetSize
+_cgiSetVariable
+_cgiShowIPPError
+_cgiShowJobs
+_cgiStartHTML
+_cgiStartMultipart
+_cgiSupportsMultipart
+_cgiText
+_helpDeleteIndex
+_helpFindNode
+_helpLoadIndex
+_helpSaveIndex
+_helpSearchIndex
diff --git a/cgi-bin/makedocset.c b/cgi-bin/makedocset.c
new file mode 100644
index 000000000..577282889
--- /dev/null
+++ b/cgi-bin/makedocset.c
@@ -0,0 +1,486 @@
+/*
+ * "$Id$"
+ *
+ * Xcode documentation set generator.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Usage:
+ *
+ * makedocset directory *.tokens
+ *
+ * Contents:
+ *
+ * main() - Test the help index code.
+ * compare_html() - Compare the titles of two HTML files.
+ * compare_sections() - Compare the names of two help sections.
+ * compare_sections_files() - Compare the number of files and section names.
+ * write_index() - Write an index file for the CUPS help.
+ * write_info() - Write the Info.plist file.
+ * write_nodes() - Write the Nodes.xml file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi.h"
+#include <errno.h>
+
+
+/*
+ * Local structures...
+ */
+
+typedef struct _cups_html_s /**** Help file ****/
+{
+ char *path; /* Path to help file */
+ char *title; /* Title of help file */
+} _cups_html_t;
+
+typedef struct _cups_section_s /**** Help section ****/
+{
+ char *name; /* Section name */
+ cups_array_t *files; /* Files in this section */
+} _cups_section_t;
+
+
+/*
+ * Local functions...
+ */
+
+static int compare_html(_cups_html_t *a, _cups_html_t *b);
+static int compare_sections(_cups_section_t *a, _cups_section_t *b);
+static int compare_sections_files(_cups_section_t *a, _cups_section_t *b);
+static void write_index(const char *path, help_index_t *hi);
+static void write_info(const char *path, const char *revision);
+static void write_nodes(const char *path, help_index_t *hi);
+
+
+/*
+ * 'main()' - Test the help index code.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ char path[1024], /* Path to documentation */
+ line[1024]; /* Line from file */
+ help_index_t *hi; /* Help index */
+ cups_file_t *tokens, /* Tokens.xml file */
+ *fp; /* Current file */
+
+
+ if (argc < 4)
+ {
+ puts("Usage: makedocset directory revision *.tokens");
+ return (1);
+ }
+
+ /*
+ * Index the help documents...
+ */
+
+ snprintf(path, sizeof(path), "%s/Contents/Resources/Documentation", argv[1]);
+ if ((hi = helpLoadIndex(NULL, path)) == NULL)
+ {
+ fputs("makedocset: Unable to index help files!\n", stderr);
+ return (1);
+ }
+
+ snprintf(path, sizeof(path), "%s/Contents/Resources/Documentation/index.html",
+ argv[1]);
+ write_index(path, hi);
+
+ snprintf(path, sizeof(path), "%s/Contents/Resources/Nodes.xml", argv[1]);
+ write_nodes(path, hi);
+
+ /*
+ * Write the Info.plist file...
+ */
+
+ snprintf(path, sizeof(path), "%s/Contents/Info.plist", argv[1]);
+ write_info(path, argv[2]);
+
+ /*
+ * Merge the Tokens.xml files...
+ */
+
+ snprintf(path, sizeof(path), "%s/Contents/Resources/Tokens.xml", argv[1]);
+ if ((tokens = cupsFileOpen(path, "w")) == NULL)
+ {
+ fprintf(stderr, "makedocset: Unable to create \"%s\": %s\n", path,
+ strerror(errno));
+ return (1);
+ }
+
+ cupsFilePuts(tokens, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ cupsFilePuts(tokens, "<Tokens version=\"1.0\">\n");
+
+ for (i = 3; i < argc; i ++)
+ {
+ if ((fp = cupsFileOpen(argv[i], "r")) == NULL)
+ {
+ fprintf(stderr, "makedocset: Unable to open \"%s\": %s\n", argv[i],
+ strerror(errno));
+ return (1);
+ }
+
+ if (!cupsFileGets(fp, line, sizeof(line)) || strncmp(line, "<?xml ", 6) ||
+ !cupsFileGets(fp, line, sizeof(line)) || strncmp(line, "<Tokens ", 8))
+ {
+ fprintf(stderr, "makedocset: Bad Tokens.xml file \"%s\"!\n", argv[i]);
+ return (1);
+ }
+
+ while (cupsFileGets(fp, line, sizeof(line)))
+ {
+ if (strcmp(line, "</Tokens>"))
+ cupsFilePrintf(tokens, "%s\n", line);
+ }
+
+ cupsFileClose(fp);
+ }
+
+ cupsFilePuts(tokens, "</Tokens>\n");
+
+ cupsFileClose(tokens);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'compare_html()' - Compare the titles of two HTML files.
+ */
+
+static int /* O - Result of comparison */
+compare_html(_cups_html_t *a, /* I - First file */
+ _cups_html_t *b) /* I - Second file */
+{
+ return (_cups_strcasecmp(a->title, b->title));
+}
+
+
+/*
+ * 'compare_sections()' - Compare the names of two help sections.
+ */
+
+static int /* O - Result of comparison */
+compare_sections(_cups_section_t *a, /* I - First section */
+ _cups_section_t *b) /* I - Second section */
+{
+ return (_cups_strcasecmp(a->name, b->name));
+}
+
+
+/*
+ * 'compare_sections_files()' - Compare the number of files and section names.
+ */
+
+static int /* O - Result of comparison */
+compare_sections_files(
+ _cups_section_t *a, /* I - First section */
+ _cups_section_t *b) /* I - Second section */
+{
+ int ret = cupsArrayCount(b->files) - cupsArrayCount(a->files);
+
+ if (ret)
+ return (ret);
+ else
+ return (_cups_strcasecmp(a->name, b->name));
+}
+
+
+/*
+ * 'write_index()' - Write an index file for the CUPS help.
+ */
+
+static void
+write_index(const char *path, /* I - File to write */
+ help_index_t *hi) /* I - Index of files */
+{
+ cups_file_t *fp; /* Output file */
+ help_node_t *node; /* Current help node */
+ _cups_section_t *section, /* Current section */
+ key; /* Section search key */
+ _cups_html_t *html; /* Current HTML file */
+ cups_array_t *sections, /* Sections in index */
+ *sections_files,/* Sections sorted by size */
+ *columns[3]; /* Columns in final HTML file */
+ int column, /* Current column */
+ lines[3], /* Number of lines in each column */
+ min_column, /* Smallest column */
+ min_lines; /* Smallest number of lines */
+
+
+ /*
+ * Build an array of sections and their files.
+ */
+
+ sections = cupsArrayNew((cups_array_func_t)compare_sections, NULL);
+
+ for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
+ node;
+ node = (help_node_t *)cupsArrayNext(hi->nodes))
+ {
+ if (node->anchor)
+ continue;
+
+ key.name = node->section ? node->section : "Miscellaneous";
+ if ((section = (_cups_section_t *)cupsArrayFind(sections, &key)) == NULL)
+ {
+ section = (_cups_section_t *)calloc(1, sizeof(_cups_section_t));
+ section->name = key.name;
+ section->files = cupsArrayNew((cups_array_func_t)compare_html, NULL);
+
+ cupsArrayAdd(sections, section);
+ }
+
+ html = (_cups_html_t *)calloc(1, sizeof(_cups_html_t));
+ html->path = node->filename;
+ html->title = node->text;
+
+ cupsArrayAdd(section->files, html);
+ }
+
+ /*
+ * Build a sorted list of sections based on the number of files in each section
+ * and the section name...
+ */
+
+ sections_files = cupsArrayNew((cups_array_func_t)compare_sections_files,
+ NULL);
+ for (section = (_cups_section_t *)cupsArrayFirst(sections);
+ section;
+ section = (_cups_section_t *)cupsArrayNext(sections))
+ cupsArrayAdd(sections_files, section);
+
+ /*
+ * Then build three columns to hold everything, trying to balance the number of
+ * lines in each column...
+ */
+
+ for (column = 0; column < 3; column ++)
+ {
+ columns[column] = cupsArrayNew((cups_array_func_t)compare_sections, NULL);
+ lines[column] = 0;
+ }
+
+ for (section = (_cups_section_t *)cupsArrayFirst(sections_files);
+ section;
+ section = (_cups_section_t *)cupsArrayNext(sections_files))
+ {
+ for (min_column = 0, min_lines = lines[0], column = 1;
+ column < 3;
+ column ++)
+ {
+ if (lines[column] < min_lines)
+ {
+ min_column = column;
+ min_lines = lines[column];
+ }
+ }
+
+ cupsArrayAdd(columns[min_column], section);
+ lines[min_column] += cupsArrayCount(section->files) + 2;
+ }
+
+ /*
+ * Write the HTML file...
+ */
+
+ if ((fp = cupsFileOpen(path, "w")) == NULL)
+ {
+ fprintf(stderr, "makedocset: Unable to create %s: %s\n", path,
+ strerror(errno));
+ exit(1);
+ }
+
+ cupsFilePuts(fp, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 "
+ "Transitional//EN\" "
+ "\"http://www.w3.org/TR/html4/loose.dtd\">\n"
+ "<html>\n"
+ "<head>\n"
+ "<title>CUPS Documentation</title>\n"
+ "<link rel='stylesheet' type='text/css' "
+ "href='cups-printable.css'>\n"
+ "</head>\n"
+ "<body>\n"
+ "<h1 class='title'>CUPS Documentation</h1>\n"
+ "<table width='100%' summary=''>\n"
+ "<tr>\n");
+
+ for (column = 0; column < 3; column ++)
+ {
+ if (column)
+ cupsFilePuts(fp, "<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>\n");
+
+ cupsFilePuts(fp, "<td valign='top' width='33%'>");
+ for (section = (_cups_section_t *)cupsArrayFirst(columns[column]);
+ section;
+ section = (_cups_section_t *)cupsArrayNext(columns[column]))
+ {
+ cupsFilePrintf(fp, "<h2 class='title'>%s</h2>\n", section->name);
+ for (html = (_cups_html_t *)cupsArrayFirst(section->files);
+ html;
+ html = (_cups_html_t *)cupsArrayNext(section->files))
+ cupsFilePrintf(fp, "<p class='compact'><a href='%s'>%s</a></p>\n",
+ html->path, html->title);
+ }
+ cupsFilePuts(fp, "</td>\n");
+ }
+ cupsFilePuts(fp, "</tr>\n"
+ "</table>\n"
+ "</body>\n"
+ "</html>\n");
+ cupsFileClose(fp);
+}
+
+
+/*
+ * 'write_info()' - Write the Info.plist file.
+ */
+
+static void
+write_info(const char *path, /* I - File to write */
+ const char *revision) /* I - Subversion revision number */
+{
+ cups_file_t *fp; /* File */
+
+
+ if ((fp = cupsFileOpen(path, "w")) == NULL)
+ {
+ fprintf(stderr, "makedocset: Unable to create %s: %s\n", path,
+ strerror(errno));
+ exit(1);
+ }
+
+ cupsFilePrintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+ "<plist version=\"1.0\">\n"
+ "<dict>\n"
+ "\t<key>CFBundleIdentifier</key>\n"
+ "\t<string>org.cups.docset</string>\n"
+ "\t<key>CFBundleName</key>\n"
+ "\t<string>CUPS Documentation</string>\n"
+ "\t<key>CFBundleVersion</key>\n"
+ "\t<string>%d.%d.%s</string>\n"
+ "\t<key>CFBundleShortVersionString</key>\n"
+ "\t<string>%d.%d.%d</string>\n"
+ "\t<key>DocSetFeedName</key>\n"
+ "\t<string>cups.org</string>\n"
+ "\t<key>DocSetFeedURL</key>\n"
+ "\t<string>http://www.cups.org/org.cups.docset.atom"
+ "</string>\n"
+ "\t<key>DocSetPublisherIdentifier</key>\n"
+ "\t<string>org.cups</string>\n"
+ "\t<key>DocSetPublisherName</key>\n"
+ "\t<string>CUPS</string>\n"
+ "</dict>\n"
+ "</plist>\n",
+ CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR, revision,
+ CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR, CUPS_VERSION_PATCH);
+
+ cupsFileClose(fp);
+}
+
+
+/*
+ * 'write_nodes()' - Write the Nodes.xml file.
+ */
+
+static void
+write_nodes(const char *path, /* I - File to write */
+ help_index_t *hi) /* I - Index of files */
+{
+ cups_file_t *fp; /* Output file */
+ int id; /* Current node ID */
+ help_node_t *node; /* Current help node */
+ int subnodes; /* Currently in Subnodes for file? */
+ int needclose; /* Need to close the current node? */
+
+
+ if ((fp = cupsFileOpen(path, "w")) == NULL)
+ {
+ fprintf(stderr, "makedocset: Unable to create %s: %s\n", path,
+ strerror(errno));
+ exit(1);
+ }
+
+ cupsFilePuts(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<DocSetNodes version=\"1.0\">\n"
+ "<TOC>\n"
+ "<Node id=\"0\">\n"
+ "<Name>CUPS Documentation</Name>\n"
+ "<Path>Documentation/index.html</Path>\n"
+ "</Node>\n");
+
+ for (node = (help_node_t *)cupsArrayFirst(hi->nodes), id = 1, subnodes = 0,
+ needclose = 0;
+ node;
+ node = (help_node_t *)cupsArrayNext(hi->nodes), id ++)
+ {
+ if (node->anchor)
+ {
+ if (!subnodes)
+ {
+ cupsFilePuts(fp, "<Subnodes>\n");
+ subnodes = 1;
+ }
+
+ cupsFilePrintf(fp, "<Node id=\"%d\">\n"
+ "<Path>Documentation/%s</Path>\n"
+ "<Anchor>%s</Anchor>\n"
+ "<Name>%s</Name>\n"
+ "</Node>\n", id, node->filename, node->anchor,
+ node->text);
+ }
+ else
+ {
+ if (subnodes)
+ {
+ cupsFilePuts(fp, "</Subnodes>\n");
+ subnodes = 0;
+ }
+
+ if (needclose)
+ cupsFilePuts(fp, "</Node>\n");
+
+ cupsFilePrintf(fp, "<Node id=\"%d\">\n"
+ "<Path>Documentation/%s</Path>\n"
+ "<Name>%s</Name>\n", id, node->filename, node->text);
+ needclose = 1;
+ }
+ }
+
+ if (subnodes)
+ cupsFilePuts(fp, "</Subnodes>\n");
+
+ if (needclose)
+ cupsFilePuts(fp, "</Node>\n");
+
+ cupsFilePuts(fp, "</TOC>\n"
+ "</DocSetNodes>\n");
+
+ cupsFileClose(fp);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/multipart.dat b/cgi-bin/multipart.dat
new file mode 100644
index 000000000..91c5bb5b4
--- /dev/null
+++ b/cgi-bin/multipart.dat
Binary files differ
diff --git a/cgi-bin/printers.c b/cgi-bin/printers.c
new file mode 100644
index 000000000..adea388a4
--- /dev/null
+++ b/cgi-bin/printers.c
@@ -0,0 +1,578 @@
+/*
+ * "$Id$"
+ *
+ * Printer status CGI for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Main entry for CGI.
+ * do_printer_op() - Do a printer operation.
+ * show_all_printers() - Show all printers...
+ * show_printer() - Show a single printer.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi-private.h"
+#include <errno.h>
+
+
+/*
+ * Local functions...
+ */
+
+static void do_printer_op(http_t *http, const char *printer, ipp_op_t op,
+ const char *title);
+static void show_all_printers(http_t *http, const char *username);
+static void show_printer(http_t *http, const char *printer);
+
+
+/*
+ * 'main()' - Main entry for CGI.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ const char *printer; /* Printer name */
+ const char *user; /* Username */
+ http_t *http; /* Connection to the server */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* IPP attribute */
+ 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", "printers");
+ cgiSetVariable("REFRESH_PAGE", "");
+
+ /*
+ * See if we are displaying a printer or all printers...
+ */
+
+ if ((printer = getenv("PATH_INFO")) != NULL)
+ {
+ printer ++;
+
+ if (!*printer)
+ printer = NULL;
+
+ if (printer)
+ cgiSetVariable("PRINTER_NAME", printer);
+ }
+
+ /*
+ * See who is logged in...
+ */
+
+ user = getenv("REMOTE_USER");
+
+ /*
+ * Connect to the HTTP server...
+ */
+
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ /*
+ * Get the default printer...
+ */
+
+ if (!op || !cgiIsPOST())
+ {
+ /*
+ * Get the default destination...
+ */
+
+ request = ippNewRequest(CUPS_GET_DEFAULT);
+
+ 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);
+ }
+
+ /*
+ * See if we need to show a list of printers or the status of a
+ * single printer...
+ */
+
+ if (!printer)
+ show_all_printers(http, user);
+ else
+ show_printer(http, printer);
+ }
+ else if (printer)
+ {
+ if (!*op)
+ {
+ const char *server_port = getenv("SERVER_PORT");
+ /* Port number string */
+ int port = atoi(server_port ? server_port : "0");
+ /* Port number */
+ char uri[1024]; /* URL */
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri),
+ getenv("HTTPS") ? "https" : "http", NULL,
+ getenv("SERVER_NAME"), port, "/printers/%s", printer);
+
+ printf("Location: %s\n\n", uri);
+ }
+ else if (!strcmp(op, "start-printer"))
+ do_printer_op(http, printer, IPP_RESUME_PRINTER,
+ cgiText(_("Resume Printer")));
+ else if (!strcmp(op, "stop-printer"))
+ do_printer_op(http, printer, IPP_PAUSE_PRINTER,
+ cgiText(_("Pause Printer")));
+ else if (!strcmp(op, "accept-jobs"))
+ do_printer_op(http, printer, CUPS_ACCEPT_JOBS, cgiText(_("Accept Jobs")));
+ else if (!strcmp(op, "reject-jobs"))
+ do_printer_op(http, printer, CUPS_REJECT_JOBS, cgiText(_("Reject Jobs")));
+ else if (!strcmp(op, "purge-jobs"))
+ do_printer_op(http, printer, IPP_PURGE_JOBS, cgiText(_("Purge Jobs")));
+ else if (!_cups_strcasecmp(op, "print-self-test-page"))
+ cgiPrintCommand(http, printer, "PrintSelfTestPage",
+ cgiText(_("Print Self-Test Page")));
+ else if (!_cups_strcasecmp(op, "clean-print-heads"))
+ cgiPrintCommand(http, printer, "Clean all",
+ cgiText(_("Clean Print Heads")));
+ else if (!_cups_strcasecmp(op, "print-test-page"))
+ cgiPrintTestPage(http, printer);
+ else if (!_cups_strcasecmp(op, "move-jobs"))
+ cgiMoveJobs(http, printer, 0);
+ else
+ {
+ /*
+ * Unknown/bad operation...
+ */
+
+ cgiStartHTML(printer);
+ cgiCopyTemplateLang("error-op.tmpl");
+ cgiEndHTML();
+ }
+ }
+ else
+ {
+ /*
+ * Unknown/bad operation...
+ */
+
+ cgiStartHTML(cgiText(_("Printers")));
+ cgiCopyTemplateLang("error-op.tmpl");
+ cgiEndHTML();
+ }
+
+ /*
+ * Close the HTTP server connection...
+ */
+
+ httpClose(http);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'do_printer_op()' - Do a printer operation.
+ */
+
+static void
+do_printer_op(http_t *http, /* I - HTTP connection */
+ const char *printer, /* I - Printer name */
+ ipp_op_t op, /* I - Operation to perform */
+ const char *title) /* I - Title of page */
+{
+ ipp_t *request; /* IPP request */
+ char uri[HTTP_MAX_URI], /* Printer URI */
+ resource[HTTP_MAX_URI]; /* Path for request */
+
+
+ /*
+ * Build a printer request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ request = ippNewRequest(op);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, 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...
+ */
+
+ snprintf(resource, sizeof(resource), "/printers/%s", printer);
+ ippDelete(cupsDoRequest(http, request, resource));
+
+ if (cupsLastError() == IPP_NOT_AUTHORIZED)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+ else if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ cgiStartHTML(title);
+ cgiShowIPPError(_("Unable to do maintenance command:"));
+ }
+ else
+ {
+ /*
+ * Redirect successful updates back to the printer page...
+ */
+
+ char url[1024], /* Printer/class URL */
+ refresh[1024]; /* Refresh URL */
+
+
+ cgiRewriteURL(uri, url, sizeof(url), NULL);
+ cgiFormEncode(uri, url, sizeof(uri));
+ snprintf(refresh, sizeof(refresh), "5;URL=%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");
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'show_all_printers()' - Show all printers...
+ */
+
+static void
+show_all_printers(http_t *http, /* I - Connection to server */
+ const char *user) /* I - Username */
+{
+ int i; /* Looping var */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ cups_array_t *printers; /* Array of printer objects */
+ ipp_attribute_t *printer; /* Printer object */
+ int ascending, /* Order of printers (0 = descending) */
+ first, /* First printer to show */
+ count; /* Number of printers */
+ const char *var; /* Form variable */
+ void *search; /* Search data */
+ char val[1024]; /* Form variable */
+
+
+ fprintf(stderr, "DEBUG: show_all_printers(http=%p, user=\"%s\")\n",
+ http, user ? user : "(null)");
+
+ /*
+ * Show the standard header...
+ */
+
+ cgiStartHTML(cgiText(_("Printers")));
+
+ /*
+ * Build a CUPS_GET_PRINTERS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-type
+ * printer-type-mask
+ * requesting-user-name
+ */
+
+ request = ippNewRequest(CUPS_GET_PRINTERS);
+
+ 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 (user)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+
+ cgiGetAttributes(request, "printers.tmpl");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ /*
+ * Get a list of matching job objects.
+ */
+
+ if ((var = cgiGetVariable("QUERY")) != NULL &&
+ !cgiGetVariable("CLEAR"))
+ search = cgiCompileSearch(var);
+ else
+ search = NULL;
+
+ printers = cgiGetIPPObjects(response, search);
+ count = cupsArrayCount(printers);
+
+ if (search)
+ cgiFreeSearch(search);
+
+ /*
+ * Figure out which printers 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(val, "%d", count);
+ cgiSetVariable("TOTAL", val);
+
+ if ((var = cgiGetVariable("ORDER")) != NULL)
+ ascending = !_cups_strcasecmp(var, "asc");
+ else
+ ascending = 1;
+
+ if (ascending)
+ {
+ for (i = 0, printer = (ipp_attribute_t *)cupsArrayIndex(printers, first);
+ i < CUPS_PAGE_MAX && printer;
+ i ++, printer = (ipp_attribute_t *)cupsArrayNext(printers))
+ cgiSetIPPObjectVars(printer, NULL, i);
+ }
+ else
+ {
+ for (i = 0, printer = (ipp_attribute_t *)cupsArrayIndex(printers, count - first - 1);
+ i < CUPS_PAGE_MAX && printer;
+ i ++, printer = (ipp_attribute_t *)cupsArrayPrev(printers))
+ cgiSetIPPObjectVars(printer, NULL, i);
+ }
+
+ /*
+ * Save navigation URLs...
+ */
+
+ cgiSetVariable("THISURL", "/printers/");
+
+ if (first > 0)
+ {
+ sprintf(val, "%d", first - CUPS_PAGE_MAX);
+ cgiSetVariable("PREV", val);
+ }
+
+ if ((first + CUPS_PAGE_MAX) < count)
+ {
+ sprintf(val, "%d", first + CUPS_PAGE_MAX);
+ cgiSetVariable("NEXT", val);
+ }
+
+ /*
+ * Then show everything...
+ */
+
+ cgiCopyTemplateLang("search.tmpl");
+
+ cgiCopyTemplateLang("printers-header.tmpl");
+
+ if (count > CUPS_PAGE_MAX)
+ cgiCopyTemplateLang("pager.tmpl");
+
+ cgiCopyTemplateLang("printers.tmpl");
+
+ if (count > CUPS_PAGE_MAX)
+ cgiCopyTemplateLang("pager.tmpl");
+
+ /*
+ * Delete the response...
+ */
+
+ cupsArrayDelete(printers);
+ ippDelete(response);
+ }
+ else
+ {
+ /*
+ * Show the error...
+ */
+
+ cgiShowIPPError(_("Unable to get printer list:"));
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'show_printer()' - Show a single printer.
+ */
+
+static void
+show_printer(http_t *http, /* I - Connection to server */
+ const char *printer) /* I - Name of printer */
+{
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* IPP attribute */
+ char uri[HTTP_MAX_URI]; /* Printer URI */
+ char refresh[1024]; /* Refresh URL */
+
+
+ fprintf(stderr, "DEBUG: show_printer(http=%p, printer=\"%s\")\n",
+ http, printer ? printer : "(null)");
+
+ /*
+ * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/printers/%s", printer);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
+ uri);
+
+ cgiGetAttributes(request, "printer.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;URL=/printers/%s", uri);
+ cgiSetVariable("refresh_page", refresh);
+ }
+
+ /*
+ * Delete the response...
+ */
+
+ ippDelete(response);
+
+ /*
+ * Show the standard header...
+ */
+
+ cgiStartHTML(printer);
+
+ /*
+ * Show the printer status...
+ */
+
+ cgiCopyTemplateLang("printer.tmpl");
+
+ /*
+ * Show jobs for the specified printer...
+ */
+
+ cgiCopyTemplateLang("printer-jobs-header.tmpl");
+ cgiShowJobs(http, printer);
+ }
+ else
+ {
+ /*
+ * Show the IPP error...
+ */
+
+ cgiStartHTML(printer);
+ cgiShowIPPError(_("Unable to get printer status:"));
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/search.c b/cgi-bin/search.c
new file mode 100644
index 000000000..e2a1c5c5d
--- /dev/null
+++ b/cgi-bin/search.c
@@ -0,0 +1,381 @@
+/*
+ * "$Id$"
+ *
+ * Search routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "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 <regex.h>
+
+
+/*
+ * '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(("cgiCompileSearch(query=\"%s\")\n", query));
+
+ /*
+ * Range check input...
+ */
+
+ if (!query)
+ return (NULL);
+
+ /*
+ * Allocate a regular expression storage structure...
+ */
+
+ if ((re = (regex_t *)calloc(1, sizeof(regex_t))) == NULL)
+ return (NULL);
+
+ /*
+ * 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;
+
+ if ((s = (char *)malloc(slen)) == NULL)
+ {
+ free(re);
+ return (NULL);
+ }
+
+ /*
+ * 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 && !_cups_strncasecmp(qptr, "AND", 3))
+ {
+ /*
+ * Logical AND with the following text...
+ */
+
+ if (sptr > s)
+ prefix = ".*";
+
+ qptr = qend;
+ }
+ else if (wlen == 2 && !_cups_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) + 2 * 4 * wlen + 2 * strlen(prefix) + 11;
+ if (lword)
+ wlen += strlen(lword);
+
+ 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++;
+ }
+
+ *sptr = '\0';
+
+ /*
+ * For "word1 AND word2", add reciprocal "word2 AND word1"...
+ */
+
+ if (!strcmp(prefix, ".*") && lword)
+ {
+ char *lword2; /* New "last word" */
+
+
+ if ((lword2 = strdup(sword)) == NULL)
+ {
+ free(lword);
+ free(s);
+ free(re);
+ return (NULL);
+ }
+
+ 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$".
+ */
diff --git a/cgi-bin/template.c b/cgi-bin/template.c
new file mode 100644
index 000000000..cdf1544bb
--- /dev/null
+++ b/cgi-bin/template.c
@@ -0,0 +1,733 @@
+/*
+ * "$Id$"
+ *
+ * CGI template function.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "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"
+#include <errno.h>
+#include <regex.h>
+
+
+/*
+ * Local functions...
+ */
+
+static void cgi_copy(FILE *out, FILE *in, int element, char term,
+ int indent);
+static void cgi_puts(const char *s, FILE *out);
+static void cgi_puturi(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 */
+
+
+ fprintf(stderr, "DEBUG2: cgiCopyTemplateFile(out=%p, tmpl=\"%s\")\n", out,
+ tmpl ? tmpl : "(null)");
+
+ /*
+ * Range check input...
+ */
+
+ if (!tmpl || !out)
+ return;
+
+ /*
+ * Open the template file...
+ */
+
+ if ((in = fopen(tmpl, "r")) == NULL)
+ {
+ fprintf(stderr, "ERROR: Unable to open template file \"%s\" - %s\n",
+ tmpl ? tmpl : "(null)", strerror(errno));
+ return;
+ }
+
+ /*
+ * Parse the file to the end...
+ */
+
+ cgi_copy(out, in, 0, 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 */
+{
+ char filename[1024], /* Filename */
+ locale[16], /* Locale name */
+ *locptr; /* Pointer into locale name */
+ const char *directory, /* Directory for templates */
+ *lang; /* Language */
+ FILE *in; /* Input file */
+
+
+ fprintf(stderr, "DEBUG2: cgiCopyTemplateLang(tmpl=\"%s\")\n",
+ tmpl ? tmpl : "(null)");
+
+ /*
+ * Convert the language to a locale name...
+ */
+
+ locale[0] = '\0';
+
+ if ((lang = getenv("LANG")) != NULL)
+ {
+ locale[0] = '/';
+ strlcpy(locale + 1, lang, sizeof(locale) - 1);
+
+ if ((locptr = strchr(locale, '.')) != NULL)
+ *locptr = '\0'; /* Strip charset */
+ }
+
+ fprintf(stderr, "DEBUG2: lang=\"%s\", locale=\"%s\"...\n",
+ lang ? lang : "(null)", locale);
+
+ /*
+ * See if we have a template file for this language...
+ */
+
+ directory = cgiGetTemplateDir();
+
+ snprintf(filename, sizeof(filename), "%s%s/%s", directory, locale, tmpl);
+ if ((in = fopen(filename, "r")) == NULL)
+ {
+ locale[3] = '\0';
+
+ snprintf(filename, sizeof(filename), "%s%s/%s", directory, locale, tmpl);
+ if ((in = fopen(filename, "r")) == NULL)
+ {
+ snprintf(filename, sizeof(filename), "%s/%s", directory, tmpl);
+ in = fopen(filename, "r");
+ }
+ }
+
+ fprintf(stderr, "DEBUG2: Template file is \"%s\"...\n", filename);
+
+ /*
+ * Open the template file...
+ */
+
+ if (!in)
+ {
+ fprintf(stderr, "ERROR: Unable to open template file \"%s\" - %s\n",
+ filename, strerror(errno));
+ return;
+ }
+
+ /*
+ * Parse the file to the end...
+ */
+
+ cgi_copy(stdout, in, 0, 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 indent) /* I - Debug info indentation */
+{
+ 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 */
+ int uriencode; /* Encode as URI */
+ regex_t re; /* Regular expression to match */
+
+
+ fprintf(stderr, "DEBUG2: %*sStarting at file position %ld...\n", indent, "",
+ ftell(in));
+
+ /*
+ * Parse the file to the end...
+ */
+
+ while ((ch = getc(in)) != EOF)
+ if (ch == term)
+ break;
+ else if (ch == '{')
+ {
+ /*
+ * Get a variable name...
+ */
+
+ uriencode = 0;
+
+ for (s = name; (ch = getc(in)) != EOF;)
+ if (strchr("}]<>=!~ \t\n", ch))
+ break;
+ else if (s == name && ch == '%')
+ uriencode = 1;
+ else if (s > name && ch == '?')
+ break;
+ else if (s < (name + sizeof(name) - 1))
+ *s++ = ch;
+
+ *s = '\0';
+
+ if (s == name && isspace(ch & 255))
+ {
+ fprintf(stderr, "DEBUG2: %*sLone { at %ld...\n", indent, "", ftell(in));
+
+ if (out)
+ {
+ putc('{', out);
+ putc(ch, out);
+ }
+
+ continue;
+ }
+
+ if (ch == '}')
+ fprintf(stderr, "DEBUG2: %*s\"{%s}\" at %ld...\n", indent, "", name,
+ ftell(in));
+
+ /*
+ * 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);
+
+ fprintf(stderr, "DEBUG2: %*sLooping on \"%s\" at %ld, count=%d...\n",
+ indent, "", name + 1, pos, count);
+
+ if (count > 0)
+ {
+ for (i = 0; i < count; i ++)
+ {
+ if (i)
+ fseek(in, pos, SEEK_SET);
+
+ cgi_copy(out, in, i, '}', indent + 2);
+ }
+ }
+ else
+ cgi_copy(NULL, in, 0, '}', indent + 2);
+
+ fprintf(stderr, "DEBUG2: %*sFinished looping on \"%s\"...\n", indent,
+ "", name + 1);
+
+ continue;
+ }
+ else if (name[0] == '$')
+ {
+ /*
+ * Insert cookie value or nothing if not defined.
+ */
+
+ if ((value = cgiGetCookie(name + 1)) != NULL)
+ outptr = value;
+ else
+ {
+ outval[0] = '\0';
+ outptr = outval;
+ }
+ }
+ 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)
+ {
+ if (uriencode)
+ cgi_puturi(outptr, out);
+ else if (!_cups_strcasecmp(name, "?cupsdconf_default"))
+ fputs(outptr, stdout);
+ else
+ cgi_puts(outptr, out);
+ }
+
+ continue;
+ }
+
+ /*
+ * OK, process one of the following checks:
+ *
+ * {name?exist:not-exist} Exists?
+ * {name=value?true:false} Equal
+ * {name<value?true:false} Less than
+ * {name>value?true:false} Greater than
+ * {name!value?true:false} Not equal
+ * {name~refex?true:false} Regex match
+ */
+
+ op = ch;
+
+ if (ch == '?')
+ {
+ /*
+ * Test for existance...
+ */
+
+ if (name[0] == '?')
+ result = cgiGetArray(name + 1, element) != NULL;
+ else if (name[0] == '#')
+ result = cgiGetVariable(name + 1) != NULL;
+ else
+ result = cgiGetArray(name, element) != NULL;
+
+ result = result && outptr[0];
+ compare[0] = '\0';
+ }
+ else
+ {
+ /*
+ * Compare to a string...
+ */
+
+ 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 != '?')
+ {
+ fprintf(stderr,
+ "DEBUG2: %*sBad terminator '%c' at file position %ld...\n",
+ indent, "", ch, ftell(in));
+ return;
+ }
+
+ /*
+ * Do the comparison...
+ */
+
+ switch (op)
+ {
+ case '<' :
+ result = _cups_strcasecmp(outptr, compare) < 0;
+ break;
+ case '>' :
+ result = _cups_strcasecmp(outptr, compare) > 0;
+ break;
+ case '=' :
+ result = _cups_strcasecmp(outptr, compare) == 0;
+ break;
+ case '!' :
+ result = _cups_strcasecmp(outptr, compare) != 0;
+ break;
+ case '~' :
+ fprintf(stderr, "DEBUG: Regular expression \"%s\"\n", compare);
+
+ if (regcomp(&re, compare, REG_EXTENDED | REG_ICASE))
+ {
+ fprintf(stderr,
+ "ERROR: Unable to compile regular expresion \"%s\"!\n",
+ compare);
+ result = 0;
+ }
+ else
+ {
+ regmatch_t matches[10];
+
+ result = 0;
+
+ if (!regexec(&re, outptr, 10, matches, 0))
+ {
+ int i;
+ for (i = 0; i < 10; i ++)
+ {
+ fprintf(stderr, "DEBUG: matches[%d].rm_so=%d\n", i,
+ (int)matches[i].rm_so);
+ if (matches[i].rm_so < 0)
+ break;
+
+ result ++;
+ }
+ }
+
+ regfree(&re);
+ }
+ break;
+ default :
+ result = 1;
+ break;
+ }
+ }
+
+ fprintf(stderr,
+ "DEBUG2: %*sStarting \"{%s%c%s\" at %ld, result=%d...\n",
+ indent, "", name, op, compare, ftell(in), result);
+
+ if (result)
+ {
+ /*
+ * Comparison true; output first part and ignore second...
+ */
+
+ fprintf(stderr, "DEBUG2: %*sOutput first part...\n", indent, "");
+ cgi_copy(out, in, element, ':', indent + 2);
+
+ fprintf(stderr, "DEBUG2: %*sSkip second part...\n", indent, "");
+ cgi_copy(NULL, in, element, '}', indent + 2);
+ }
+ else
+ {
+ /*
+ * Comparison false; ignore first part and output second...
+ */
+
+ fprintf(stderr, "DEBUG2: %*sSkip first part...\n", indent, "");
+ cgi_copy(NULL, in, element, ':', indent + 2);
+
+ fprintf(stderr, "DEBUG2: %*sOutput second part...\n", indent, "");
+ cgi_copy(out, in, element, '}', indent + 2);
+ }
+
+ fprintf(stderr, "DEBUG2: %*sFinished \"{%s%c%s\", out=%p...\n", indent, "",
+ name, op, compare, out);
+ }
+ else if (ch == '\\') /* Quoted char */
+ {
+ if (out)
+ putc(getc(in), out);
+ else
+ getc(in);
+ }
+ else if (out)
+ putc(ch, out);
+
+ if (ch == EOF)
+ fprintf(stderr, "DEBUG2: %*sReturning at file position %ld on EOF...\n",
+ indent, "", ftell(in));
+ else
+ fprintf(stderr,
+ "DEBUG2: %*sReturning at file position %ld on character '%c'...\n",
+ indent, "", ftell(in), ch);
+
+ if (ch == EOF && term)
+ fprintf(stderr, "ERROR: %*sSaw EOF, expected '%c'!\n", indent, "", term);
+
+ /*
+ * 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 <A HREF="url"> and </A>, otherwise quote it...
+ */
+
+ if (!_cups_strncasecmp(s, "<A HREF=\"", 9))
+ {
+ fputs("<A HREF=\"", out);
+ s += 9;
+
+ while (*s && *s != '\"')
+ {
+ if (*s == '&')
+ fputs("&amp;", out);
+ else
+ putc(*s, out);
+
+ s ++;
+ }
+
+ if (*s)
+ s ++;
+
+ fputs("\">", out);
+ }
+ else if (!_cups_strncasecmp(s, "</A>", 4))
+ {
+ fputs("</A>", out);
+ s += 3;
+ }
+ else
+ fputs("&lt;", out);
+ }
+ else if (*s == '>')
+ fputs("&gt;", out);
+ else if (*s == '\"')
+ fputs("&quot;", out);
+ else if (*s == '\'')
+ fputs("&#39;", out);
+ else if (*s == '&')
+ fputs("&amp;", out);
+ else
+ putc(*s, out);
+
+ s ++;
+ }
+}
+
+
+/*
+ * 'cgi_puturi()' - Put a URI string to the output file, quoting as needed...
+ */
+
+static void
+cgi_puturi(const char *s, /* I - String to output */
+ FILE *out) /* I - Output file */
+{
+ while (*s)
+ {
+ if (strchr("%@&+ <>#=", *s) || *s < ' ' || *s & 128)
+ fprintf(out, "%%%02X", *s & 255);
+ else
+ putc(*s, out);
+
+ s ++;
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/testcgi.c b/cgi-bin/testcgi.c
new file mode 100644
index 000000000..dfda3d7ea
--- /dev/null
+++ b/cgi-bin/testcgi.c
@@ -0,0 +1,75 @@
+/*
+ * "$Id$"
+ *
+ * CGI test program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "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$".
+ */
diff --git a/cgi-bin/testhi.c b/cgi-bin/testhi.c
new file mode 100644
index 000000000..ce1b94b01
--- /dev/null
+++ b/cgi-bin/testhi.c
@@ -0,0 +1,113 @@
+/*
+ * "$Id$"
+ *
+ * Help index test program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "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, cups_array_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->nodes);
+ list_nodes("sorted", hi->sorted);
+
+ /*
+ * Do any searches...
+ */
+
+ if (argc > 1)
+ {
+ search = helpSearchIndex(hi, argv[1], NULL, argv[2]);
+
+ if (search)
+ {
+ list_nodes(argv[1], 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 */
+ cups_array_t *nodes) /* I - Nodes */
+{
+ int i; /* Looping var */
+ help_node_t *node; /* Current node */
+
+
+ printf("%s (%d nodes):\n", title, cupsArrayCount(nodes));
+ for (i = 1, node = (help_node_t *)cupsArrayFirst(nodes);
+ node;
+ i ++, node = (help_node_t *)cupsArrayNext(nodes))
+ {
+ if (node->anchor)
+ printf(" %d: %s#%s \"%s\"", i, node->filename, node->anchor,
+ node->text);
+ else
+ printf(" %d: %s \"%s\"", i, node->filename, node->text);
+
+ printf(" (%d words)\n", cupsArrayCount(node->words));
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/testhi.html b/cgi-bin/testhi.html
new file mode 100644
index 000000000..0000e9eff
--- /dev/null
+++ b/cgi-bin/testhi.html
@@ -0,0 +1,31 @@
+<HTML>
+<HEAD>
+ <TITLE>Test File for Help Index Code</TITLE>
+</HEAD>
+<BODY>
+
+<P>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.</P>
+
+<H1><A NAME="FIRST">This is the First Anchor</A></H1>
+
+<P>This&nbsp;is some text for the <em>first</em> anchor.</P>
+
+
+<H1><A NAME="2ND">This is the Second Anchor</A></H1>
+
+<P>This is some text for the first anchor.</P>
+
+<P>John asked Mary to the dance.</P>
+
+
+<H1><A NAME="THIRD">This is the Third Anchor</A></H1>
+
+<P>This is some text for the third anchor. <A NAME="INLINE">This
+is an in-line anchor that crosses a line.</A></P>
+
+</BODY>
+</HTML>
diff --git a/cgi-bin/testtemplate.c b/cgi-bin/testtemplate.c
new file mode 100644
index 000000000..02c017365
--- /dev/null
+++ b/cgi-bin/testtemplate.c
@@ -0,0 +1,103 @@
+/*
+ * "$Id$"
+ *
+ * CGI template test program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Test the template code.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi.h"
+
+
+/*
+ * 'main()' - Test the template code.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ char *value; /* Value in name=value */
+ FILE *out; /* Where to send output */
+
+
+ /*
+ * Don't buffer stdout or stderr so that the mixed output is sane...
+ */
+
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+
+ /*
+ * Loop through the command-line, assigning variables for any args with
+ * "name=value"...
+ */
+
+ out = stdout;
+
+ for (i = 1; i < argc; i ++)
+ {
+ if (!strcmp(argv[i], "-o"))
+ {
+ i ++;
+ if (i < argc)
+ {
+ out = fopen(argv[i], "w");
+ if (!out)
+ {
+ perror(argv[i]);
+ return (1);
+ }
+ }
+ }
+ else if (!strcmp(argv[i], "-e"))
+ {
+ i ++;
+
+ if (i < argc)
+ {
+ if (!freopen(argv[i], "w", stderr))
+ {
+ perror(argv[i]);
+ return (1);
+ }
+ }
+ }
+ else if (!strcmp(argv[i], "-q"))
+ freopen("/dev/null", "w", stderr);
+ else if ((value = strchr(argv[i], '=')) != NULL)
+ {
+ *value++ = '\0';
+ cgiSetVariable(argv[i], value);
+ }
+ else
+ cgiCopyTemplateFile(out, argv[i]);
+ }
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cgi-bin/var.c b/cgi-bin/var.c
new file mode 100644
index 000000000..616bf2b56
--- /dev/null
+++ b/cgi-bin/var.c
@@ -0,0 +1,1305 @@
+/*
+ * "$Id$"
+ *
+ * CGI form variable and array functions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cgiCheckVariables() - Check for the presence of "required"
+ * variables.
+ * cgiClearVariables() - Clear all form variables.
+ * cgiGetArray() - Get an element from a form array.
+ * cgiGetCookie() - Get a cookie value.
+ * 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.
+ * cgiSetCookie() - Set a cookie value.
+ * 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_cookies() - Initialize cookies.
+ * 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_set_sid() - Set the CUPS session ID.
+ * cgi_sort_variables() - Sort all form variables for faster lookup.
+ * cgi_unlink_file() - Remove the uploaded form.
+ */
+
+/*#define DEBUG*/
+#include "cgi-private.h"
+#include <cups/http.h>
+#include <cups/md5-private.h>
+
+
+/*
+ * Session ID name
+ */
+
+#define CUPS_SID "org.cups.sid"
+
+
+/*
+ * 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 num_cookies = 0;/* Number of cookies */
+static cups_option_t *cookies = NULL;/* Cookies */
+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 void cgi_initialize_cookies(void);
+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 const char *cgi_set_sid(void);
+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);
+}
+
+
+/*
+ * 'cgiClearVariables()' - Clear all form variables.
+ */
+
+void
+cgiClearVariables(void)
+{
+ int i, j; /* Looping vars */
+ _cgi_var_t *v; /* Current variable */
+
+
+ for (v = form_vars, i = form_count; i > 0; v ++, i --)
+ {
+ _cupsStrFree(v->name);
+ for (j = 0; j < v->nvalues; j ++)
+ if (v->values[j])
+ _cupsStrFree(v->values[j]);
+ }
+
+ form_count = 0;
+
+ cgi_unlink_file();
+}
+
+
+/*
+ * '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 (element < 0 || element >= var->nvalues)
+ return (NULL);
+
+ return (_cupsStrRetain(var->values[element]));
+}
+
+
+/*
+ * 'cgiGetCookie()' - Get a cookie value.
+ */
+
+const char * /* O - Value or NULL */
+cgiGetCookie(const char *name) /* I - Name of cookie */
+{
+ return (cupsGetOption(name, num_cookies, cookies));
+}
+
+
+/*
+ * '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)
+ DEBUG_printf(("cgiGetVariable(\"%s\") is returning NULL...\n", name));
+ else
+ DEBUG_printf(("cgiGetVariable(\"%s\") is returning \"%s\"...\n", name,
+ var->values[var->nvalues - 1]));
+#endif /* DEBUG */
+
+ return ((var == NULL) ? NULL : _cupsStrRetain(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 */
+ *content_type, /* Content-Type of post data */
+ *cups_sid_cookie, /* SID cookie */
+ *cups_sid_form; /* SID form variable */
+
+
+ /*
+ * Setup a password callback for authentication...
+ */
+
+ cupsSetPasswordCB(cgi_passwd);
+
+ /*
+ * Set the locale so that times, etc. are formatted properly...
+ */
+
+ setlocale(LC_ALL, "");
+
+#ifdef DEBUG
+ /*
+ * Disable output buffering to find bugs...
+ */
+
+ setbuf(stdout, NULL);
+#endif /* DEBUG */
+
+ /*
+ * Get cookies...
+ */
+
+ cgi_initialize_cookies();
+
+ if ((cups_sid_cookie = cgiGetCookie(CUPS_SID)) == NULL)
+ {
+ fputs("DEBUG: " CUPS_SID " cookie not found, initializing!\n", stderr);
+ cups_sid_cookie = cgi_set_sid();
+ }
+
+ fprintf(stderr, "DEBUG: " CUPS_SID " cookie is \"%s\"\n", cups_sid_cookie);
+
+ /*
+ * 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 (!_cups_strcasecmp(method, "GET"))
+ return (cgi_initialize_get());
+ else if (!_cups_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))
+ {
+ if (!cgi_initialize_multipart(boundary))
+ return (0);
+ }
+ else if (!cgi_initialize_post())
+ return (0);
+
+ if ((cups_sid_form = cgiGetVariable(CUPS_SID)) == NULL ||
+ strcmp(cups_sid_cookie, cups_sid_form))
+ {
+ if (cups_sid_form)
+ fprintf(stderr, "DEBUG: " CUPS_SID " form variable is \"%s\"\n",
+ cups_sid_form);
+ else
+ fputs("DEBUG: " CUPS_SID " form variable is not present.\n", stderr);
+
+ cgiClearVariables();
+ return (0);
+ }
+ else
+ return (1);
+ }
+ 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)
+ {
+ const char **temp; /* Temporary pointer */
+
+ temp = (const char **)realloc((void *)(var->values),
+ sizeof(char *) * (element + 16));
+ if (!temp)
+ return;
+
+ var->avalues = element + 16;
+ var->values = temp;
+ }
+
+ if (element >= var->nvalues)
+ {
+ for (i = var->nvalues; i < element; i ++)
+ var->values[i] = NULL;
+
+ var->nvalues = element + 1;
+ }
+ else if (var->values[element])
+ _cupsStrFree((char *)var->values[element]);
+
+ var->values[element] = _cupsStrAlloc(value);
+ }
+}
+
+
+/*
+ * 'cgiSetCookie()' - Set a cookie value.
+ */
+
+void
+cgiSetCookie(const char *name, /* I - Name */
+ const char *value, /* I - Value */
+ const char *path, /* I - Path (typically "/") */
+ const char *domain, /* I - Domain name */
+ time_t expires, /* I - Expiration date (0 for session) */
+ int secure) /* I - Require SSL */
+{
+ num_cookies = cupsAddOption(name, value, num_cookies, &cookies);
+
+ printf("Set-Cookie: %s=%s;", name, value);
+ if (path)
+ printf("; path=%s", path);
+ if (domain)
+ printf("; domain=%s", domain);
+ if (expires)
+ {
+ char date[256]; /* Date string */
+
+ printf("; expires=%s", httpGetDateString2(expires, date, sizeof(date)));
+ }
+ if (secure)
+ puts("; secure;");
+ else
+ puts(";");
+}
+
+
+/*
+ * '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)
+ {
+ const char **temp; /* Temporary pointer */
+
+ temp = (const char **)realloc((void *)(var->values),
+ sizeof(char *) * (size + 16));
+ if (!temp)
+ return;
+
+ var->avalues = size + 16;
+ var->values = temp;
+ }
+
+ 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])
+ _cupsStrFree((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])
+ _cupsStrFree((char *)var->values[i]);
+
+ var->values[0] = _cupsStrAlloc(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;
+
+ DEBUG_printf(("cgi_add_variable: Adding variable \'%s\' with value "
+ "\'%s\'...\n", name, value));
+
+ if (form_count >= form_alloc)
+ {
+ _cgi_var_t *temp_vars; /* Temporary form pointer */
+
+
+ if (form_alloc == 0)
+ temp_vars = malloc(sizeof(_cgi_var_t) * 16);
+ else
+ temp_vars = realloc(form_vars, (form_alloc + 16) * sizeof(_cgi_var_t));
+
+ if (!temp_vars)
+ return;
+
+ form_vars = temp_vars;
+ form_alloc += 16;
+ }
+
+ var = form_vars + form_count;
+
+ if ((var->values = calloc(element + 1, sizeof(char *))) == NULL)
+ return;
+
+ var->name = _cupsStrAlloc(name);
+ var->nvalues = element + 1;
+ var->avalues = element + 1;
+ var->values[element] = _cupsStrAlloc(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 (_cups_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_cookies()' - Initialize cookies.
+ */
+
+static void
+cgi_initialize_cookies(void)
+{
+ const char *cookie; /* HTTP_COOKIE environment variable */
+ char name[128], /* Name string */
+ value[512], /* Value string */
+ *ptr; /* Pointer into name/value */
+
+
+ if ((cookie = getenv("HTTP_COOKIE")) == NULL)
+ return;
+
+ while (*cookie)
+ {
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (isspace(*cookie & 255))
+ cookie ++;
+ if (!*cookie)
+ break;
+
+ /*
+ * Copy the name...
+ */
+
+ for (ptr = name; *cookie && *cookie != '=';)
+ if (ptr < (name + sizeof(name) - 1))
+ *ptr++ = *cookie++;
+ else
+ break;
+
+ if (*cookie != '=')
+ break;
+
+ *ptr = '\0';
+ cookie ++;
+
+ /*
+ * Then the value...
+ */
+
+ if (*cookie == '\"')
+ {
+ for (cookie ++, ptr = value; *cookie && *cookie != '\"';)
+ if (ptr < (value + sizeof(value) - 1))
+ *ptr++ = *cookie++;
+ else
+ break;
+
+ if (*cookie == '\"')
+ cookie ++;
+ }
+ else
+ {
+ for (ptr = value; *cookie && *cookie != ';';)
+ if (ptr < (value + sizeof(value) - 1))
+ *ptr++ = *cookie++;
+ else
+ break;
+ }
+
+ if (*cookie == ';')
+ cookie ++;
+ else if (*cookie)
+ break;
+
+ *ptr = '\0';
+
+ /*
+ * Then add the cookie to an array as long as the name doesn't start with
+ * "$"...
+ */
+
+ if (name[0] != '$')
+ num_cookies = cupsAddOption(name, value, num_cookies, &cookies);
+ }
+}
+
+
+/*
+ * '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 */
+
+
+ DEBUG_puts("cgi_initialize_get: Initializing variables using GET method...");
+
+ /*
+ * 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 (!_cups_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 (!_cups_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 */
+
+
+ DEBUG_puts("cgi_initialize_post: Initializing variables using POST method...");
+
+ /*
+ * 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);
+ }
+ else
+ nbytes = 0;
+ }
+ else if (nbytes == 0)
+ {
+ /*
+ * CUPS STR #3176: OpenBSD: Early end-of-file on POST data causes 100% CPU
+ *
+ * This should never happen, but does on OpenBSD. If we see early end-of-
+ * file, treat this as an error and process no data.
+ */
+
+ 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 (!isxdigit(data[1] & 255) || !isxdigit(data[2] & 255))
+ return (0);
+
+ 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 && isspace(*s & 255))
+ *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 ? prompt : "(null)");
+
+ /*
+ * 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_set_sid()' - Set the CUPS session ID.
+ */
+
+static const char * /* O - New session ID */
+cgi_set_sid(void)
+{
+ char buffer[512], /* SID data */
+ sid[33]; /* SID string */
+ _cups_md5_state_t md5; /* MD5 state */
+ unsigned char sum[16]; /* MD5 sum */
+ const char *remote_addr, /* REMOTE_ADDR */
+ *server_name, /* SERVER_NAME */
+ *server_port; /* SERVER_PORT */
+
+
+ if ((remote_addr = getenv("REMOTE_ADDR")) == NULL)
+ remote_addr = "REMOTE_ADDR";
+ if ((server_name = getenv("SERVER_NAME")) == NULL)
+ server_name = "SERVER_NAME";
+ if ((server_port = getenv("SERVER_PORT")) == NULL)
+ server_port = "SERVER_PORT";
+
+ CUPS_SRAND(time(NULL));
+ snprintf(buffer, sizeof(buffer), "%s:%s:%s:%02X%02X%02X%02X%02X%02X%02X%02X",
+ remote_addr, server_name, server_port,
+ (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
+ (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
+ (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
+ (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255);
+ _cupsMD5Init(&md5);
+ _cupsMD5Append(&md5, (unsigned char *)buffer, (int)strlen(buffer));
+ _cupsMD5Finish(&md5, sum);
+
+ cgiSetCookie(CUPS_SID, httpMD5String(sum, sid), "/", NULL, 0, 0);
+
+ return (cupsGetOption(CUPS_SID, num_cookies, cookies));
+}
+
+
+/*
+ * 'cgi_sort_variables()' - Sort all form variables for faster lookup.
+ */
+
+static void
+cgi_sort_variables(void)
+{
+#ifdef DEBUG
+ int i;
+
+
+ DEBUG_puts("cgi_sort_variables: 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
+ DEBUG_puts("cgi_sort_variables: Sorted variable list is:");
+ for (i = 0; i < form_count; i ++)
+ DEBUG_printf(("cgi_sort_variables: %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$".
+ */
diff --git a/cgi-bin/websearch.c b/cgi-bin/websearch.c
new file mode 100644
index 000000000..351f92db0
--- /dev/null
+++ b/cgi-bin/websearch.c
@@ -0,0 +1,116 @@
+/*
+ * "$Id$"
+ *
+ * Web search program for www.cups.org.
+ *
+ * Copyright 2007-2009 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Usage:
+ *
+ * websearch directory "search string"
+ *
+ * Contents:
+ *
+ * main() - Search a directory of help files.
+ * list_nodes() - List matching nodes.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi.h"
+
+
+/*
+ * Local functions...
+ */
+
+static void list_nodes(help_index_t *hi, const char *title,
+ cups_array_t *nodes);
+
+
+/*
+ * 'main()' - Test the help index code.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ help_index_t *hi, /* Help index */
+ *search; /* Search index */
+ char indexname[1024]; /* Name of index file */
+
+
+ if (argc != 3)
+ {
+ puts("Usage: websearch directory \"search terms\"");
+ return (1);
+ }
+
+ /*
+ * Load the help index...
+ */
+
+ snprintf(indexname, sizeof(indexname), "%s/.index", argv[1]);
+ hi = helpLoadIndex(indexname, argv[1]);
+
+ /*
+ * Do any searches...
+ */
+
+ search = helpSearchIndex(hi, argv[2], NULL, NULL);
+
+ if (search)
+ list_nodes(hi, argv[1], search->sorted);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'list_nodes()' - List nodes in an array...
+ */
+
+static void
+list_nodes(help_index_t *hi, /* I - Help index */
+ const char *title, /* I - Title string */
+ cups_array_t *nodes) /* I - Nodes */
+{
+ help_node_t *node, /* Current node */
+ *file; /* File node */
+
+
+ printf("%d\n", cupsArrayCount(nodes));
+ for (node = (help_node_t *)cupsArrayFirst(nodes);
+ node;
+ node = (help_node_t *)cupsArrayNext(nodes))
+ {
+ if (node->anchor)
+ {
+ file = helpFindNode(hi, node->filename, NULL);
+ printf("%d|%s#%s|%s|%s\n", node->score, node->filename, node->anchor,
+ node->text, file ? file->text : node->filename);
+ }
+ else
+ printf("%d|%s|%s|%s\n", node->score, node->filename, node->text,
+ node->text);
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/conf/Makefile b/conf/Makefile
new file mode 100644
index 000000000..b35b593f7
--- /dev/null
+++ b/conf/Makefile
@@ -0,0 +1,143 @@
+#
+# "$Id$"
+#
+# Configuration file makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1993-2006 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+#
+# Config files...
+#
+
+KEEP = cupsd.conf snmp.conf
+REPLACE = mime.convs mime.types
+
+
+#
+# Make everything...
+#
+
+all:
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Clean all config and object files...
+#
+
+clean:
+
+
+#
+# Dummy depend...
+#
+
+depend:
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+ for file in $(KEEP); do \
+ if test -r $(SERVERROOT)/$$file ; then \
+ $(INSTALL_CONFIG) -g $(CUPS_GROUP) $$file $(SERVERROOT)/$$file.N ; \
+ else \
+ $(INSTALL_CONFIG) -g $(CUPS_GROUP) $$file $(SERVERROOT) ; \
+ fi ; \
+ done
+ $(INSTALL_CONFIG) -g $(CUPS_GROUP) cupsd.conf $(SERVERROOT)/cupsd.conf.default
+ $(INSTALL_DIR) -m 755 $(DATADIR)/mime
+ for file in $(REPLACE); do \
+ if test -r $(DATADIR)/mime/$$file ; then \
+ $(MV) $(DATADIR)/mime/$$file $(DATADIR)/mime/$$file.O ; \
+ fi ; \
+ if test -r $(SERVERROOT)/$$file ; then \
+ $(MV) $(SERVERROOT)/$$file $(DATADIR)/mime/$$file.O ; \
+ fi ; \
+ $(INSTALL_DATA) $$file $(DATADIR)/mime ; \
+ done
+ -if test x$(PAMDIR) != x; then \
+ $(INSTALL_DIR) -m 755 $(BUILDROOT)$(PAMDIR); \
+ if test -r $(BUILDROOT)$(PAMDIR)/cups ; then \
+ $(INSTALL_DATA) $(PAMFILE) $(BUILDROOT)$(PAMDIR)/cups.N ; \
+ else \
+ $(INSTALL_DATA) $(PAMFILE) $(BUILDROOT)$(PAMDIR)/cups ; \
+ fi ; \
+ fi
+
+
+#
+# Install programs...
+#
+
+install-exec:
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall files...
+#
+
+uninstall:
+ for file in $(KEEP) $(REPLACE) cupsd.conf.default; do \
+ $(RM) $(SERVERROOT)/$$file; \
+ done
+ -$(RMDIR) $(SERVERROOT)
+ for file in $(REPLACE); do \
+ $(RM) $(DATADIR)/mime/$$file; \
+ done
+ -$(RMDIR) $(DATADIR)/mime
+ -if test x$(PAMDIR) != x; then \
+ $(RM) $(BUILDROOT)$(PAMDIR)/cups; \
+ $(RMDIR) $(BUILDROOT)$(PAMDIR); \
+ fi
+
+
+#
+# End of "$Id$".
+#
diff --git a/conf/cupsd.conf.in b/conf/cupsd.conf.in
new file mode 100644
index 000000000..2ce33e3d7
--- /dev/null
+++ b/conf/cupsd.conf.in
@@ -0,0 +1,140 @@
+#
+# "$Id$"
+#
+# Sample configuration file for the CUPS scheduler. See "man cupsd.conf" for a
+# complete description of this file.
+#
+
+# Log general information in error_log - change "@CUPS_LOG_LEVEL@" to "debug"
+# for troubleshooting...
+LogLevel @CUPS_LOG_LEVEL@
+
+# Administrator user group...
+SystemGroup @CUPS_SYSTEM_GROUPS@
+@CUPS_SYSTEM_AUTHKEY@
+
+# 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 all
+BrowseLocalProtocols @CUPS_BROWSE_LOCAL_PROTOCOLS@
+
+# Default authentication type, when authentication is required...
+DefaultAuthType Basic
+
+# Web interface setting...
+WebInterface @CUPS_WEBIF@
+
+# Restrict access to the server...
+<Location />
+ Order allow,deny
+</Location>
+
+# Restrict access to the admin pages...
+<Location /admin>
+ Order allow,deny
+</Location>
+
+# Restrict access to configuration files...
+<Location /admin/conf>
+ AuthType Default
+ Require user @SYSTEM
+ Order allow,deny
+</Location>
+
+# Set the default printer/job policies...
+<Policy default>
+ # Job/subscription privacy...
+ JobPrivateAccess default
+ JobPrivateValues default
+ SubscriptionPrivateAccess default
+ SubscriptionPrivateValues default
+
+ # Job-related operations must be done by the owner or an administrator...
+ <Limit Create-Job Print-Job Print-URI Validate-Job>
+ Order deny,allow
+ </Limit>
+
+ <Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document>
+ Require user @OWNER @SYSTEM
+ Order deny,allow
+ </Limit>
+
+ # All administration operations require an administrator to authenticate...
+ <Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default CUPS-Get-Devices>
+ AuthType Default
+ Require user @SYSTEM
+ Order deny,allow
+ </Limit>
+
+ # All printer operations require a printer operator to authenticate...
+ <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
+ AuthType Default
+ Require user @CUPS_DEFAULT_PRINTOPERATOR_AUTH@
+ Order deny,allow
+ </Limit>
+
+ # Only the owner or an administrator can cancel or authenticate a job...
+ <Limit Cancel-Job CUPS-Authenticate-Job>
+ Require user @OWNER @CUPS_DEFAULT_PRINTOPERATOR_AUTH@
+ Order deny,allow
+ </Limit>
+
+ <Limit All>
+ Order deny,allow
+ </Limit>
+</Policy>
+
+# Set the authenticated printer/job policies...
+<Policy authenticated>
+ # Job/subscription privacy...
+ JobPrivateAccess default
+ JobPrivateValues default
+ SubscriptionPrivateAccess default
+ SubscriptionPrivateValues default
+
+ # Job-related operations must be done by the owner or an administrator...
+ <Limit Create-Job Print-Job Print-URI Validate-Job>
+ AuthType Default
+ Order deny,allow
+ </Limit>
+
+ <Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document>
+ AuthType Default
+ Require user @OWNER @SYSTEM
+ Order deny,allow
+ </Limit>
+
+ # All administration operations require an administrator to authenticate...
+ <Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default>
+ AuthType Default
+ Require user @SYSTEM
+ Order deny,allow
+ </Limit>
+
+ # All printer operations require a printer operator to authenticate...
+ <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
+ AuthType Default
+ Require user @CUPS_DEFAULT_PRINTOPERATOR_AUTH@
+ Order deny,allow
+ </Limit>
+
+ # Only the owner or an administrator can cancel or authenticate a job...
+ <Limit Cancel-Job CUPS-Authenticate-Job>
+ AuthType Default
+ Require user @OWNER @CUPS_DEFAULT_PRINTOPERATOR_AUTH@
+ Order deny,allow
+ </Limit>
+
+ <Limit All>
+ Order deny,allow
+ </Limit>
+</Policy>
+
+#
+# End of "$Id$".
+#
diff --git a/conf/mime.convs.in b/conf/mime.convs.in
new file mode 100644
index 000000000..d48b84ba9
--- /dev/null
+++ b/conf/mime.convs.in
@@ -0,0 +1,101 @@
+#
+# "$Id$"
+#
+# DO NOT EDIT THIS FILE, AS IT IS OVERWRITTEN WHEN YOU INSTALL NEW
+# VERSIONS OF CUPS. Instead, create a "local.convs" file that
+# reflects your local configuration changes.
+#
+# Base MIME conversions file for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2007 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "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
+#
+
+@DEFAULT_PDFTOPS@application/pdf application/vnd.cups-postscript 66 pdftops
+application/postscript application/vnd.cups-postscript 66 pstops
+@DEFAULT_TEXTTOPS@application/x-cshell application/postscript 33 texttops
+@DEFAULT_TEXTTOPS@application/x-csource application/postscript 33 texttops
+@DEFAULT_TEXTTOPS@application/x-perl application/postscript 33 texttops
+@DEFAULT_TEXTTOPS@application/x-shell application/postscript 33 texttops
+@DEFAULT_TEXTTOPS@text/plain application/postscript 33 texttops
+@DEFAULT_TEXTTOPS@text/css application/postscript 33 texttops
+@DEFAULT_TEXTTOPS@text/html application/postscript 33 texttops
+@DEFAULT_IMAGEFILTERS@image/gif application/vnd.cups-postscript 66 imagetops
+@DEFAULT_IMAGEFILTERS@image/png application/vnd.cups-postscript 66 imagetops
+@DEFAULT_IMAGEFILTERS@image/jpeg application/vnd.cups-postscript 66 imagetops
+@DEFAULT_IMAGEFILTERS@image/tiff application/vnd.cups-postscript 66 imagetops
+@DEFAULT_IMAGEFILTERS@image/x-bitmap application/vnd.cups-postscript 66 imagetops
+@DEFAULT_IMAGEFILTERS@image/x-photocd application/vnd.cups-postscript 66 imagetops
+@DEFAULT_IMAGEFILTERS@image/x-portable-anymap application/vnd.cups-postscript 66 imagetops
+@DEFAULT_IMAGEFILTERS@image/x-portable-bitmap application/vnd.cups-postscript 66 imagetops
+@DEFAULT_IMAGEFILTERS@image/x-portable-graymap application/vnd.cups-postscript 66 imagetops
+@DEFAULT_IMAGEFILTERS@image/x-portable-pixmap application/vnd.cups-postscript 66 imagetops
+@DEFAULT_IMAGEFILTERS@image/x-sgi-rgb application/vnd.cups-postscript 66 imagetops
+@DEFAULT_IMAGEFILTERS@image/x-xbitmap application/vnd.cups-postscript 66 imagetops
+@DEFAULT_IMAGEFILTERS@image/x-xpixmap application/vnd.cups-postscript 66 imagetops
+@DEFAULT_IMAGEFILTERS@image/x-sun-raster application/vnd.cups-postscript 66 imagetops
+@DEFAULT_BANNERTOPS@application/vnd.cups-banner application/postscript 33 bannertops
+
+########################################################################
+#
+# Raster filters...
+#
+
+@DEFAULT_IMAGEFILTERS@image/gif application/vnd.cups-raster 100 imagetoraster
+@DEFAULT_IMAGEFILTERS@image/png application/vnd.cups-raster 100 imagetoraster
+@DEFAULT_IMAGEFILTERS@image/jpeg application/vnd.cups-raster 100 imagetoraster
+@DEFAULT_IMAGEFILTERS@image/tiff application/vnd.cups-raster 100 imagetoraster
+@DEFAULT_IMAGEFILTERS@image/x-bitmap application/vnd.cups-raster 100 imagetoraster
+@DEFAULT_IMAGEFILTERS@image/x-photocd application/vnd.cups-raster 100 imagetoraster
+@DEFAULT_IMAGEFILTERS@image/x-portable-anymap application/vnd.cups-raster 100 imagetoraster
+@DEFAULT_IMAGEFILTERS@image/x-portable-bitmap application/vnd.cups-raster 100 imagetoraster
+@DEFAULT_IMAGEFILTERS@image/x-portable-graymap application/vnd.cups-raster 100 imagetoraster
+@DEFAULT_IMAGEFILTERS@image/x-portable-pixmap application/vnd.cups-raster 100 imagetoraster
+@DEFAULT_IMAGEFILTERS@image/x-sgi-rgb application/vnd.cups-raster 100 imagetoraster
+@DEFAULT_IMAGEFILTERS@image/x-xbitmap application/vnd.cups-raster 100 imagetoraster
+@DEFAULT_IMAGEFILTERS@image/x-xpixmap application/vnd.cups-raster 100 imagetoraster
+@DEFAULT_IMAGEFILTERS@image/x-sun-raster application/vnd.cups-raster 100 imagetoraster
+
+# PWG Raster filter for IPP Everywhere...
+application/vnd.cups-raster image/pwg-raster 100 rastertopwg
+
+########################################################################
+#
+# Raw filter...
+#
+# Uncomment the following filter to allow printing of arbitrary files
+# without the -oraw option.
+#
+
+@DEFAULT_RAW_PRINTING@application/octet-stream application/vnd.cups-raw 0 -
+
+#
+# End of "$Id$".
+#
diff --git a/conf/mime.types b/conf/mime.types
new file mode 100644
index 000000000..9ef8752b6
--- /dev/null
+++ b/conf/mime.types
@@ -0,0 +1,174 @@
+#
+# "$Id: mime.types 9667 2011-04-01 04:48:21Z mike $"
+#
+# Base MIME types file for CUPS.
+#
+# DO NOT EDIT THIS FILE, AS IT IS OVERWRITTEN WHEN YOU INSTALL NEW
+# VERSIONS OF CUPS. Instead, create a "local.types" file that
+# reflects your local configuration changes.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2007 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "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)
+# priority(number) Sets priority of type (0=lowest,
+# 100=default, 200=highest)
+# 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. If two types use the same
+# rules to resolve a type and have the same priority, e.g. "doc" extension for
+# "text/bar" and "text/foo", the returned type will be the first type as
+# sorted in alphanumerically ascending order without regard to case. Thus,
+# the "text/bar" type will match the "doc" extension first unless the
+# "text/foo" type has specified a higher priority.
+#
+# 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 <hex> notation.
+#
+
+########################################################################
+#
+# Application-generated files...
+#
+
+#application/msword doc string(0,<D0CF11E0A1B11AE1>)
+application/pdf pdf string(0,%PDF)
+application/postscript ai eps ps string(0,%!) string(0,<04>%!) \
+ contains(0,128,<1B>%-12345X) + \
+ (contains(0,4096,"LANGUAGE=POSTSCRIPT") \
+ contains(0,4096,"LANGUAGE = Postscript") \
+ contains(0,4096,"LANGUAGE = PostScript") \
+ contains(0,4096,"LANGUAGE = POSTSCRIPT") \
+ (contains(0,4096,<0a>%!) + \
+ !contains(0,4096,"ENTER LANGUAGE")))
+
+########################################################################
+#
+# 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,<FFD8FF>) +\
+ (char(3,0xe0) char(3,0xe1) char(3,0xe2) char(3,0xe3)\
+ char(3,0xe4) char(3,0xe5) char(3,0xe6) char(3,0xe7)\
+ char(3,0xe8) char(3,0xe9) char(3,0xea) char(3,0xeb)\
+ char(3,0xec) char(3,0xed) char(3,0xee) char(3,0xef))
+image/pwg-raster string(0,"RaS2") + string(356,<0000000000000000>) priority(100)
+image/tiff tiff tif string(0,MM<002A>) string(0,II<2A00>)
+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,"<HTML>") istring(0,"<!DOCTYPE"))
+text/plain txt printable(0,1024)
+text/css css
+
+
+########################################################################
+#
+# RSS feed type...
+#
+
+application/rss+xml rss
+
+
+########################################################################
+#
+# CUPS-specific types...
+#
+
+application/vnd.cups-banner string(0,'#CUPS-BANNER')
+application/vnd.cups-command string(0,'#CUPS-COMMAND')
+application/vnd.cups-pdf
+application/vnd.cups-postscript
+application/vnd.cups-ppd ppd string(0,"*PPD-Adobe:")
+application/vnd.cups-raster string(0,"RaSt") string(0,"tSaR") \
+ string(0,"RaS2") string(0,"2SaR") \
+ string(0,"RaS3") string(0,"3SaR")
+application/vnd.cups-raw (string(0,<1B>E) + !string(2,<1B>%0B)) \
+ string(0,<1B>@) \
+ (contains(0,128,<1B>%-12345X) + \
+ (contains(0,4096,"LANGUAGE=PCL") \
+ contains(0,4096,"LANGUAGE = PCL")))
+
+########################################################################
+#
+# Raw print file support...
+#
+# Comment the following type to prevent raw file printing.
+#
+
+application/octet-stream
+
+#
+# End of "$Id: mime.types 9667 2011-04-01 04:48:21Z mike $".
+#
diff --git a/conf/pam.opendirectory b/conf/pam.opendirectory
new file mode 100644
index 000000000..b336306a8
--- /dev/null
+++ b/conf/pam.opendirectory
@@ -0,0 +1,5 @@
+# cups: auth account password session
+auth required pam_opendirectory.so
+account required pam_permit.so
+password required pam_deny.so
+session required pam_permit.so
diff --git a/conf/pam.securityserver b/conf/pam.securityserver
new file mode 100644
index 000000000..ff724da4d
--- /dev/null
+++ b/conf/pam.securityserver
@@ -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.std.in b/conf/pam.std.in
new file mode 100644
index 000000000..68fb50af3
--- /dev/null
+++ b/conf/pam.std.in
@@ -0,0 +1,2 @@
+auth required @PAMMODAUTH@
+account required @PAMMOD@
diff --git a/conf/snmp.conf.in b/conf/snmp.conf.in
new file mode 100644
index 000000000..43855ab66
--- /dev/null
+++ b/conf/snmp.conf.in
@@ -0,0 +1,13 @@
+#
+# "$Id$"
+#
+# Sample SNMP configuration file for CUPS. See "man cups-snmp.conf" for a
+# complete description of this file.
+#
+
+@CUPS_SNMP_ADDRESS@
+@CUPS_SNMP_COMMUNITY@
+
+#
+# End of "$Id$".
+#
diff --git a/config-scripts/cups-3264.m4 b/config-scripts/cups-3264.m4
new file mode 100644
index 000000000..107289aba
--- /dev/null
+++ b/config-scripts/cups-3264.m4
@@ -0,0 +1,140 @@
+dnl
+dnl "$Id: cups-3264.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
+dnl 32/64-bit library support stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+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 Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+dnl Setup support for separate 32/64-bit library generation...
+AC_ARG_ENABLE(32bit, [ --enable-32bit generate 32-bit libraries on 32/64-bit systems])
+
+INSTALL32=""
+LIB32CUPS=""
+LIB32CUPSIMAGE=""
+LIB32DIR=""
+UNINSTALL32=""
+
+AC_SUBST(INSTALL32)
+AC_SUBST(LIB32CUPS)
+AC_SUBST(LIB32CUPSIMAGE)
+AC_SUBST(LIB32DIR)
+AC_SUBST(UNINSTALL32)
+
+AC_ARG_ENABLE(64bit, [ --enable-64bit generate 64-bit libraries on 32/64-bit systems])
+
+INSTALL64=""
+LIB64CUPS=""
+LIB64CUPSIMAGE=""
+LIB64DIR=""
+UNINSTALL64=""
+
+AC_SUBST(INSTALL64)
+AC_SUBST(LIB64CUPS)
+AC_SUBST(LIB64CUPSIMAGE)
+AC_SUBST(LIB64DIR)
+AC_SUBST(UNINSTALL64)
+
+case "$uname" in
+ HP-UX*)
+ if test "x$enable_32bit" = xyes; then
+ # Build 32-bit libraries, 64-bit base...
+ INSTALL32="install32bit"
+ LIB32CUPS="32bit/libcups.so.2"
+ LIB32CUPSIMAGE="32bit/libcupsimage.so.2"
+ LIB32DIR="$exec_prefix/lib"
+ if test -d /usr/lib/hpux32; then
+ LIB32DIR="${LIB32DIR}/hpux32"
+ fi
+ UNINSTALL32="uninstall32bit"
+ fi
+
+ if test "x$enable_64bit" = xyes; then
+ # Build 64-bit libraries, 32-bit base...
+ INSTALL64="install64bit"
+ LIB64CUPS="64bit/libcups.so.2"
+ LIB64CUPSIMAGE="64bit/libcupsimage.so.2"
+ LIB64DIR="$exec_prefix/lib"
+ if test -d /usr/lib/hpux64; then
+ LIB64DIR="${LIB64DIR}/hpux64"
+ fi
+ UNINSTALL64="uninstall64bit"
+ fi
+ ;;
+
+ IRIX)
+ if test "x$enable_32bit" = xyes; then
+ INSTALL32="install32bit"
+ LIB32CUPS="32bit/libcups.so.2"
+ LIB32CUPSIMAGE="32bit/libcupsimage.so.2"
+ LIB32DIR="$prefix/lib32"
+ UNINSTALL32="uninstall32bit"
+ fi
+
+ if test "x$enable_64bit" = xyes; then
+ # Build 64-bit libraries, 32-bit base...
+ INSTALL64="install64bit"
+ LIB64CUPS="64bit/libcups.so.2"
+ LIB64CUPSIMAGE="64bit/libcupsimage.so.2"
+ LIB64DIR="$prefix/lib64"
+ UNINSTALL64="uninstall64bit"
+ fi
+ ;;
+
+ Linux*)
+ if test "x$enable_32bit" = xyes; then
+ # Build 32-bit libraries, 64-bit base...
+ INSTALL32="install32bit"
+ LIB32CUPS="32bit/libcups.so.2"
+ LIB32CUPSIMAGE="32bit/libcupsimage.so.2"
+ LIB32DIR="$exec_prefix/lib"
+ if test -d /usr/lib32; then
+ LIB32DIR="${LIB32DIR}32"
+ fi
+ UNINSTALL32="uninstall32bit"
+ fi
+
+ if test "x$enable_64bit" = xyes; then
+ # Build 64-bit libraries, 32-bit base...
+ INSTALL64="install64bit"
+ LIB64CUPS="64bit/libcups.so.2"
+ LIB64CUPSIMAGE="64bit/libcupsimage.so.2"
+ LIB64DIR="$exec_prefix/lib"
+ if test -d /usr/lib64; then
+ LIB64DIR="${LIB64DIR}64"
+ fi
+ UNINSTALL64="uninstall64bit"
+ fi
+ ;;
+
+ SunOS*)
+ if test "x$enable_32bit" = xyes; then
+ # Build 32-bit libraries, 64-bit base...
+ INSTALL32="install32bit"
+ LIB32CUPS="32bit/libcups.so.2"
+ LIB32CUPSIMAGE="32bit/libcupsimage.so.2"
+ LIB32DIR="$exec_prefix/lib/32"
+ UNINSTALL32="uninstall32bit"
+ fi
+
+ if test "x$enable_64bit" = xyes; then
+ # Build 64-bit libraries, 32-bit base...
+ INSTALL64="install64bit"
+ LIB64CUPS="64bit/libcups.so.2"
+ LIB64CUPSIMAGE="64bit/libcupsimage.so.2"
+ LIB64DIR="$exec_prefix/lib/64"
+ UNINSTALL64="uninstall64bit"
+ fi
+ ;;
+esac
+
+dnl
+dnl End of "$Id: cups-3264.m4 9771 2011-05-12 05:21:56Z mike $".
+dnl
diff --git a/config-scripts/cups-common.m4 b/config-scripts/cups-common.m4
new file mode 100644
index 000000000..baa1b47b1
--- /dev/null
+++ b/config-scripts/cups-common.m4
@@ -0,0 +1,425 @@
+dnl
+dnl "$Id: cups-common.m4 9793 2011-05-20 03:49:49Z mike $"
+dnl
+dnl Common configuration stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+dnl Copyright 1997-2007 by Easy Software Products, all rights reserved.
+dnl
+dnl These coded instructions, statements, and computer programs are the
+dnl property of Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+dnl We need at least autoconf 2.60...
+AC_PREREQ(2.60)
+
+dnl Set the name of the config header file...
+AC_CONFIG_HEADER(config.h)
+
+dnl Version number information...
+CUPS_VERSION="1.5b1"
+CUPS_REVISION=""
+#if test -z "$CUPS_REVISION" -a -d .svn; then
+# CUPS_REVISION="-r`svnversion . | awk -F: '{print $NF}' | sed -e '1,$s/[[a-zA-Z]]*//g'`"
+#fi
+CUPS_BUILD="cups-$CUPS_VERSION"
+
+AC_ARG_WITH(cups_build, [ --with-cups-build set "cups-config --build" string ],
+ CUPS_BUILD="$withval")
+
+AC_SUBST(CUPS_VERSION)
+AC_SUBST(CUPS_REVISION)
+AC_SUBST(CUPS_BUILD)
+AC_DEFINE_UNQUOTED(CUPS_SVERSION, "CUPS v$CUPS_VERSION$CUPS_REVISION")
+AC_DEFINE_UNQUOTED(CUPS_MINIMAL, "CUPS/$CUPS_VERSION$CUPS_REVISION")
+
+dnl Default compiler flags...
+CFLAGS="${CFLAGS:=}"
+CPPFLAGS="${CPPFLAGS:=}"
+CXXFLAGS="${CXXFLAGS:=}"
+LDFLAGS="${LDFLAGS:=}"
+
+dnl Checks for programs...
+AC_PROG_AWK
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_CXX
+AC_PROG_RANLIB
+AC_PATH_PROG(AR,ar)
+AC_PATH_PROG(CHMOD,chmod)
+AC_PATH_PROG(HTMLDOC,htmldoc)
+AC_PATH_PROG(LD,ld)
+AC_PATH_PROG(LN,ln)
+AC_PATH_PROG(MV,mv)
+AC_PATH_PROG(RM,rm)
+AC_PATH_PROG(RMDIR,rmdir)
+AC_PATH_PROG(SED,sed)
+AC_PATH_PROG(XDGOPEN,xdg-open)
+if test "x$XDGOPEN" = x; then
+ CUPS_HTMLVIEW="htmlview"
+else
+ CUPS_HTMLVIEW="$XDGOPEN"
+fi
+AC_SUBST(CUPS_HTMLVIEW)
+
+AC_MSG_CHECKING(for install-sh script)
+INSTALL="`pwd`/install-sh"
+AC_SUBST(INSTALL)
+AC_MSG_RESULT(using $INSTALL)
+
+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
+
+dnl Static library option...
+INSTALLSTATIC=""
+AC_ARG_ENABLE(static, [ --enable-static install static libraries])
+
+if test x$enable_static = xyes; then
+ echo Installing static libraries...
+ INSTALLSTATIC="installstatic"
+fi
+
+AC_SUBST(INSTALLSTATIC)
+
+dnl Check for pkg-config, which is used for some other tests later on...
+AC_PATH_PROG(PKGCONFIG, pkg-config)
+
+dnl Check for libraries...
+AC_SEARCH_LIBS(crypt, crypt)
+AC_SEARCH_LIBS(getspent, sec gen)
+
+LIBMALLOC=""
+AC_ARG_ENABLE(mallinfo, [ --enable-mallinfo build with malloc debug logging])
+
+if test x$enable_mallinfo = xyes; then
+ SAVELIBS="$LIBS"
+ LIBS=""
+ AC_SEARCH_LIBS(mallinfo, malloc, AC_DEFINE(HAVE_MALLINFO))
+ LIBMALLOC="$LIBS"
+ LIBS="$SAVELIBS"
+fi
+
+AC_SUBST(LIBMALLOC)
+
+dnl Check for libpaper support...
+AC_ARG_ENABLE(libpaper, [ --enable-libpaper build with libpaper support])
+
+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))
+AC_CHECK_HEADER(sys/param.h,AC_DEFINE(HAVE_SYS_PARAM_H))
+AC_CHECK_HEADER(sys/ucred.h,AC_DEFINE(HAVE_SYS_UCRED_H))
+AC_CHECK_HEADER(scsi/sg.h,AC_DEFINE(HAVE_SCSI_SG_H))
+
+dnl Checks for iconv.h and iconv_open
+AC_CHECK_HEADER(iconv.h,
+ SAVELIBS="$LIBS"
+ LIBS=""
+ AC_SEARCH_LIBS(iconv_open,iconv,
+ AC_DEFINE(HAVE_ICONV_H)
+ SAVELIBS="$SAVELIBS $LIBS")
+ LIBS="$SAVELIBS")
+
+dnl Checks for statfs and its many headers...
+AC_CHECK_HEADER(sys/mount.h,AC_DEFINE(HAVE_SYS_MOUNT_H))
+AC_CHECK_HEADER(sys/statfs.h,AC_DEFINE(HAVE_SYS_STATFS_H))
+AC_CHECK_HEADER(sys/statvfs.h,AC_DEFINE(HAVE_SYS_STATVFS_H))
+AC_CHECK_HEADER(sys/vfs.h,AC_DEFINE(HAVE_SYS_VFS_H))
+AC_CHECK_FUNCS(statfs statvfs)
+
+dnl Checks for string functions.
+AC_CHECK_FUNCS(strdup 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 Check for random number functions...
+AC_CHECK_FUNCS(random lrand48 arc4random)
+
+dnl Check for geteuid function.
+AC_CHECK_FUNCS(geteuid)
+
+dnl Check for setpgid function.
+AC_CHECK_FUNCS(setpgid)
+
+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 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 <time.h>],[struct tm t;
+ int o = t.tm_gmtoff;],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_TM_GMTOFF),
+ AC_MSG_RESULT(no))
+
+dnl See if the stat structure has the st_gen member...
+AC_MSG_CHECKING(for st_gen member in stat structure)
+AC_TRY_COMPILE([#include <sys/stat.h>],[struct stat t;
+ int o = t.st_gen;],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_ST_GEN),
+ AC_MSG_RESULT(no))
+
+dnl See if we have the removefile(3) function for securely removing files
+AC_CHECK_FUNCS(removefile)
+
+dnl See if we have libusb...
+AC_ARG_ENABLE(libusb, [ --enable-libusb use libusb for USB printing])
+
+LIBUSB=""
+AC_SUBST(LIBUSB)
+
+if test x$enable_libusb = xyes; then
+ check_libusb=yes
+elif test x$enable_libusb != xno -a $uname != Darwin; then
+ check_libusb=yes
+else
+ check_libusb=no
+fi
+
+if test $check_libusb = yes; then
+ AC_CHECK_LIB(usb, usb_get_string_simple,[
+ AC_CHECK_HEADER(usb.h,
+ AC_DEFINE(HAVE_USB_H)
+ LIBUSB="-lusb")])
+fi
+
+dnl See if we have libwrap for TCP wrappers support...
+AC_ARG_ENABLE(tcp_wrappers, [ --enable-tcp-wrappers use libwrap for TCP wrappers support])
+
+LIBWRAP=""
+AC_SUBST(LIBWRAP)
+
+if test x$enable_tcp_wrappers = xyes; then
+ AC_CHECK_LIB(wrap, hosts_access,[
+ AC_CHECK_HEADER(tcpd.h,
+ AC_DEFINE(HAVE_TCPD_H)
+ LIBWRAP="-lwrap")])
+fi
+
+dnl Flags for "ar" command...
+case $uname in
+ Darwin* | *BSD*)
+ ARFLAGS="-rcv"
+ ;;
+ *)
+ ARFLAGS="crvs"
+ ;;
+esac
+
+AC_SUBST(ARFLAGS)
+
+dnl Prep libraries specifically for cupsd and backends...
+BACKLIBS=""
+SERVERLIBS=""
+AC_SUBST(BACKLIBS)
+AC_SUBST(SERVERLIBS)
+
+dnl See if we have POSIX ACL support...
+SAVELIBS="$LIBS"
+LIBS=""
+AC_ARG_ENABLE(acl, [ --enable-acl build with POSIX ACL support])
+if test "x$enable_acl" != xno; then
+ AC_SEARCH_LIBS(acl_init, acl, AC_DEFINE(HAVE_ACL_INIT))
+ SERVERLIBS="$SERVERLIBS $LIBS"
+fi
+LIBS="$SAVELIBS"
+
+dnl Check for DBUS support
+if test -d /etc/dbus-1; then
+ DBUSDIR="/etc/dbus-1"
+else
+ DBUSDIR=""
+fi
+
+AC_ARG_ENABLE(dbus, [ --enable-dbus build with DBUS support])
+AC_ARG_WITH(dbusdir, [ --with-dbusdir set DBUS configuration directory ],
+ DBUSDIR="$withval")
+
+DBUS_NOTIFIER=""
+DBUS_NOTIFIERLIBS=""
+
+if test "x$enable_dbus" != xno -a "x$PKGCONFIG" != x; then
+ AC_MSG_CHECKING(for DBUS)
+ if $PKGCONFIG --exists dbus-1; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_DBUS)
+ CFLAGS="$CFLAGS `$PKGCONFIG --cflags dbus-1` -DDBUS_API_SUBJECT_TO_CHANGE"
+ SERVERLIBS="$SERVERLIBS `$PKGCONFIG --libs dbus-1`"
+ DBUS_NOTIFIER="dbus"
+ DBUS_NOTIFIERLIBS="`$PKGCONFIG --libs dbus-1`"
+ SAVELIBS="$LIBS"
+ LIBS="$LIBS $DBUS_NOTIFIERLIBS"
+ AC_CHECK_FUNC(dbus_message_iter_init_append,
+ AC_DEFINE(HAVE_DBUS_MESSAGE_ITER_INIT_APPEND))
+ LIBS="$SAVELIBS"
+ else
+ AC_MSG_RESULT(no)
+ fi
+fi
+
+AC_SUBST(DBUSDIR)
+AC_SUBST(DBUS_NOTIFIER)
+AC_SUBST(DBUS_NOTIFIERLIBS)
+
+dnl Extra platform-specific libraries...
+CUPS_DEFAULT_PRINTOPERATOR_AUTH="@SYSTEM"
+CUPS_SYSTEM_AUTHKEY=""
+INSTALLXPC=""
+LEGACY_BACKENDS="parallel"
+
+case $uname in
+ Darwin*)
+ LEGACY_BACKENDS=""
+ BACKLIBS="$BACKLIBS -framework IOKit"
+ SERVERLIBS="$SERVERLIBS -framework IOKit -weak_framework ApplicationServices"
+ LIBS="-framework SystemConfiguration -framework CoreFoundation -framework Security $LIBS"
+
+ dnl Check for framework headers...
+ AC_CHECK_HEADER(ApplicationServices/ApplicationServices.h,AC_DEFINE(HAVE_APPLICATIONSERVICES_H))
+ AC_CHECK_HEADER(CoreFoundation/CoreFoundation.h,AC_DEFINE(HAVE_COREFOUNDATION_H))
+ AC_CHECK_HEADER(CoreFoundation/CFPriv.h,AC_DEFINE(HAVE_CFPRIV_H))
+ AC_CHECK_HEADER(CoreFoundation/CFBundlePriv.h,AC_DEFINE(HAVE_CFBUNDLEPRIV_H))
+ AC_CHECK_HEADER(IOKit/pwr_mgt/IOPMLibPrivate.h,AC_DEFINE(HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H))
+
+ dnl Check for dynamic store function...
+ AC_CHECK_FUNCS(SCDynamicStoreCopyComputerName)
+
+ dnl Check for new ColorSync APIs...
+ SAVELIBS="$LIBS"
+ LIBS="$LIBS -framework ApplicationServices"
+ AC_CHECK_FUNCS(ColorSyncRegisterDevice)
+ LIBS="$SAVELIBS"
+
+ dnl Check for the new membership functions in MacOSX 10.4...
+ AC_CHECK_HEADER(membership.h,AC_DEFINE(HAVE_MEMBERSHIP_H))
+ AC_CHECK_HEADER(membershipPriv.h,AC_DEFINE(HAVE_MEMBERSHIPPRIV_H))
+ AC_CHECK_FUNCS(mbr_uid_to_uuid)
+
+ dnl Check for the vproc_transaction_begin/end stuff...
+ AC_CHECK_FUNCS(vproc_transaction_begin)
+
+ dnl Need <dlfcn.h> header...
+ AC_CHECK_HEADER(dlfcn.h,AC_DEFINE(HAVE_DLFCN_H))
+
+ dnl Check for notify_post support
+ AC_CHECK_HEADER(notify.h,AC_DEFINE(HAVE_NOTIFY_H))
+ AC_CHECK_FUNCS(notify_post)
+
+ dnl Check for Authorization Services support
+ AC_ARG_WITH(adminkey, [ --with-adminkey set the default SystemAuthKey value],
+ default_adminkey="$withval",
+ default_adminkey="default")
+ AC_ARG_WITH(operkey, [ --with-operkey set the default operator @AUTHKEY value],
+ default_operkey="$withval",
+ default_operkey="default")
+
+ AC_CHECK_HEADER(Security/Authorization.h, [
+ AC_DEFINE(HAVE_AUTHORIZATION_H)
+
+ if test "x$default_adminkey" != xdefault; then
+ CUPS_SYSTEM_AUTHKEY="SystemGroupAuthKey $default_adminkey"
+ elif grep -q system.print.operator /etc/authorization; then
+ CUPS_SYSTEM_AUTHKEY="SystemGroupAuthKey system.print.admin"
+ else
+ CUPS_SYSTEM_AUTHKEY="SystemGroupAuthKey system.preferences"
+ fi
+
+ if test "x$default_operkey" != xdefault; then
+ CUPS_DEFAULT_PRINTOPERATOR_AUTH="@AUTHKEY($default_operkey) @admin @lpadmin"
+ elif grep -q system.print.operator /etc/authorization; then
+ CUPS_DEFAULT_PRINTOPERATOR_AUTH="@AUTHKEY(system.print.operator) @admin @lpadmin"
+ else
+ CUPS_DEFAULT_PRINTOPERATOR_AUTH="@AUTHKEY(system.print.admin) @admin @lpadmin"
+ fi])
+ AC_CHECK_HEADER(Security/SecBasePriv.h,AC_DEFINE(HAVE_SECBASEPRIV_H))
+
+ dnl Check for sandbox/Seatbelt support
+ if test $uversion -ge 100; then
+ AC_CHECK_HEADER(sandbox.h,AC_DEFINE(HAVE_SANDBOX_H))
+ fi
+
+ dnl Check for XPC support
+ AC_CHECK_HEADER(xpc/xpc.h,
+ AC_DEFINE(HAVE_XPC)
+ INSTALLXPC="install-xpc")
+ ;;
+esac
+
+AC_SUBST(CUPS_DEFAULT_PRINTOPERATOR_AUTH)
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_PRINTOPERATOR_AUTH, "$CUPS_DEFAULT_PRINTOPERATOR_AUTH")
+AC_SUBST(CUPS_SYSTEM_AUTHKEY)
+AC_SUBST(INSTALLXPC)
+AC_SUBST(LEGACY_BACKENDS)
+
+dnl Check for build components
+COMPONENTS="all"
+
+AC_ARG_WITH(components, [ --with-components set components to build:
+ - "all" (default) builds everything
+ - "core" builds libcups and ipptool],
+ COMPONENTS="$withval")
+
+case "$COMPONENTS" in
+ all)
+ BUILDDIRS="filter backend berkeley cgi-bin driver monitor notifier ppdc scheduler systemv conf data locale man doc examples templates"
+ ;;
+
+ core)
+ BUILDDIRS="data locale"
+ ;;
+
+ *)
+ AC_MSG_ERROR([Bad build component "$COMPONENT" specified!])
+ ;;
+esac
+
+AC_SUBST(BUILDDIRS)
+
+dnl
+dnl End of "$Id: cups-common.m4 9793 2011-05-20 03:49:49Z mike $".
+dnl
diff --git a/config-scripts/cups-compiler.m4 b/config-scripts/cups-compiler.m4
new file mode 100644
index 000000000..e1df71000
--- /dev/null
+++ b/config-scripts/cups-compiler.m4
@@ -0,0 +1,552 @@
+dnl
+dnl "$Id: cups-compiler.m4 9770 2011-05-12 04:51:01Z mike $"
+dnl
+dnl Compiler stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+dnl Copyright 1997-2007 by Easy Software Products, all rights reserved.
+dnl
+dnl These coded instructions, statements, and computer programs are the
+dnl property of Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+dnl Clear the debugging and non-shared library options unless the user asks
+dnl for them...
+INSTALL_STRIP=""
+OPTIM=""
+AC_SUBST(INSTALL_STRIP)
+AC_SUBST(OPTIM)
+
+AC_ARG_WITH(optim, [ --with-optim set optimization flags ])
+AC_ARG_ENABLE(debug, [ --enable-debug build with debugging symbols])
+AC_ARG_ENABLE(debug_guards, [ --enable-debug-guards build with memory allocation guards])
+AC_ARG_ENABLE(debug_printfs, [ --enable-debug-printfs build with CUPS_DEBUG_LOG support])
+AC_ARG_ENABLE(unit_tests, [ --enable-unit-tests build and run unit tests])
+
+dnl For debugging, keep symbols, otherwise strip them...
+if test x$enable_debug = xyes; then
+ OPTIM="-g"
+else
+ INSTALL_STRIP="-s"
+fi
+
+dnl Debug printfs can slow things down, so provide a separate option for that
+if test x$enable_debug_printfs = xyes; then
+ CFLAGS="$CFLAGS -DDEBUG"
+ CXXFLAGS="$CXXFLAGS -DDEBUG"
+fi
+
+dnl Debug guards use an extra 4 bytes for some structures like strings in the
+dnl string pool, so provide a separate option for that
+if test x$enable_debug_guards = xyes; then
+ CFLAGS="$CFLAGS -DDEBUG_GUARDS"
+ CXXFLAGS="$CXXFLAGS -DDEBUG_GUARDS"
+fi
+
+dnl Unit tests take up time during a compile...
+if test x$enable_unit_tests = xyes; then
+ UNITTESTS="unittests"
+else
+ UNITTESTS=""
+fi
+AC_SUBST(UNITTESTS)
+
+dnl Setup general architecture flags...
+AC_ARG_WITH(archflags, [ --with-archflags set default architecture flags ])
+AC_ARG_WITH(ldarchflags, [ --with-ldarchflags set program architecture flags ])
+
+if test -z "$with_archflags"; then
+ ARCHFLAGS=""
+else
+ ARCHFLAGS="$with_archflags"
+fi
+
+if test -z "$with_ldarchflags"; then
+ if test "$uname" = Darwin; then
+ # Only create 32-bit programs by default
+ LDARCHFLAGS="`echo $ARCHFLAGS | sed -e '1,$s/-arch x86_64//' -e '1,$s/-arch ppc64//'`"
+ else
+ LDARCHFLAGS="$ARCHFLAGS"
+ fi
+else
+ LDARCHFLAGS="$with_ldarchflags"
+fi
+
+AC_SUBST(ARCHFLAGS)
+AC_SUBST(LDARCHFLAGS)
+
+dnl Setup support for separate 32/64-bit library generation...
+AC_ARG_WITH(arch32flags, [ --with-arch32flags set 32-bit architecture flags])
+ARCH32FLAGS=""
+AC_SUBST(ARCH32FLAGS)
+
+AC_ARG_WITH(arch64flags, [ --with-arch64flags set 64-bit architecture flags])
+ARCH64FLAGS=""
+AC_SUBST(ARCH64FLAGS)
+
+dnl Read-only data/program support on Linux...
+AC_ARG_ENABLE(relro, [ --enable-relro build with the GCC relro option])
+
+dnl Update compiler options...
+CXXLIBS="${CXXLIBS:=}"
+AC_SUBST(CXXLIBS)
+
+PIEFLAGS=""
+AC_SUBST(PIEFLAGS)
+
+RELROFLAGS=""
+AC_SUBST(RELROFLAGS)
+
+PHPOPTIONS=""
+AC_SUBST(PHPOPTIONS)
+
+if test -n "$GCC"; then
+ # Add GCC-specific compiler options...
+ 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
+
+ # Generate position-independent code as needed...
+ if test $PICFLAG = 1 -a $uname != AIX; then
+ OPTIM="-fPIC $OPTIM"
+ fi
+
+ # The -fstack-protector option is available with some versions of
+ # GCC and adds "stack canaries" which detect when the return address
+ # has been overwritten, preventing many types of exploit attacks.
+ AC_MSG_CHECKING(if GCC supports -fstack-protector)
+ OLDCFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -fstack-protector"
+ AC_TRY_LINK(,,
+ OPTIM="$OPTIM -fstack-protector"
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no))
+ CFLAGS="$OLDCFLAGS"
+
+ # The -fPIE option is available with some versions of GCC and adds
+ # randomization of addresses, which avoids another class of exploits
+ # that depend on a fixed address for common functions.
+ AC_MSG_CHECKING(if GCC supports -fPIE)
+ OLDCFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -fPIE"
+ AC_TRY_COMPILE(,,
+ [PIEFLAGS="-fPIE -Wl,-pie"
+ AC_MSG_RESULT(yes)],
+ AC_MSG_RESULT(no))
+ CFLAGS="$OLDCFLAGS"
+
+ if test "x$with_optim" = x; then
+ # Add useful warning options for tracking down problems...
+ OPTIM="-Wall -Wno-format-y2k -Wunused $OPTIM"
+ # Additional warning options for development testing...
+ if test -d .svn; then
+ OPTIM="-Wshadow $OPTIM"
+ CFLAGS="-Werror-implicit-function-declaration $CFLAGS"
+ PHPOPTIONS="-Wno-shadow"
+ fi
+ fi
+
+ case "$uname" in
+ Darwin*)
+ # -D_FORTIFY_SOURCE=2 adds additional object size
+ # checking, basically wrapping all string functions
+ # with buffer-limited ones. Not strictly needed for
+ # CUPS since we already use buffer-limited calls, but
+ # this will catch any additions that are broken.
+ CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2"
+
+ if test x$enable_pie = xyes; then
+ # GCC 4 on Mac OS X needs -Wl,-pie as well
+ LDFLAGS="$LDFLAGS -Wl,-pie"
+ fi
+ ;;
+
+ HP-UX*)
+ if test "x$enable_32bit" = xyes; then
+ # Build 32-bit libraries, 64-bit base...
+ if test -z "$with_arch32flags"; then
+ ARCH32FLAGS="-milp32"
+ else
+ ARCH32FLAGS="$with_arch32flags"
+ fi
+
+ if test -z "$with_archflags"; then
+ if test -z "$with_arch64flags"; then
+ ARCHFLAGS="-mlp64"
+ else
+ ARCHFLAGS="$with_arch64flags"
+ fi
+ fi
+ fi
+
+ if test "x$enable_64bit" = xyes; then
+ # Build 64-bit libraries, 32-bit base...
+ if test -z "$with_arch64flags"; then
+ ARCH64FLAGS="-mlp64"
+ else
+ ARCH64FLAGS="$with_arch64flags"
+ fi
+
+ if test -z "$with_archflags"; then
+ if test -z "$with_arch32flags"; then
+ ARCHFLAGS="-milp32"
+ else
+ ARCHFLAGS="$with_arch32flags"
+ fi
+ fi
+ fi
+ ;;
+
+ IRIX)
+ if test "x$enable_32bit" = xyes; then
+ # Build 32-bit libraries, 64-bit base...
+ if test -z "$with_arch32flags"; then
+ ARCH32FLAGS="-n32 -mips3"
+ else
+ ARCH32FLAGS="$with_arch32flags"
+ fi
+
+ if test -z "$with_archflags"; then
+ if test -z "$with_arch64flags"; then
+ ARCHFLAGS="-64 -mips4"
+ else
+ ARCHFLAGS="$with_arch64flags"
+ fi
+ fi
+ fi
+
+ if test "x$enable_64bit" = xyes; then
+ # Build 64-bit libraries, 32-bit base...
+ if test -z "$with_arch64flags"; then
+ ARCH64FLAGS="-64 -mips4"
+ else
+ ARCH64FLAGS="$with_arch64flags"
+ fi
+
+ if test -z "$with_archflags"; then
+ if test -z "$with_arch32flags"; then
+ ARCHFLAGS="-n32 -mips3"
+ else
+ ARCHFLAGS="$with_arch32flags"
+ fi
+ fi
+ fi
+ ;;
+
+ Linux*)
+ # The -z relro option is provided by the Linux linker command to
+ # make relocatable data read-only.
+ if test x$enable_relro = xyes; then
+ RELROFLAGS="-Wl,-z,relro"
+ fi
+
+ if test "x$enable_32bit" = xyes; then
+ # Build 32-bit libraries, 64-bit base...
+ if test -z "$with_arch32flags"; then
+ ARCH32FLAGS="-m32"
+ else
+ ARCH32FLAGS="$with_arch32flags"
+ fi
+
+ if test -z "$with_archflags"; then
+ if test -z "$with_arch64flags"; then
+ ARCHFLAGS="-m64"
+ else
+ ARCHFLAGS="$with_arch64flags"
+ fi
+ fi
+ fi
+
+ if test "x$enable_64bit" = xyes; then
+ # Build 64-bit libraries, 32-bit base...
+ if test -z "$with_arch64flags"; then
+ ARCH64FLAGS="-m64"
+ else
+ ARCH64FLAGS="$with_arch64flags"
+ fi
+
+ if test -z "$with_archflags"; then
+ if test -z "$with_arch32flags"; then
+ ARCHFLAGS="-m32"
+ else
+ ARCHFLAGS="$with_arch32flags"
+ fi
+ fi
+ fi
+ ;;
+
+ SunOS*)
+ if test "x$enable_32bit" = xyes; then
+ # Build 32-bit libraries, 64-bit base...
+ if test -z "$with_arch32flags"; then
+ ARCH32FLAGS="-m32"
+ else
+ ARCH32FLAGS="$with_arch32flags"
+ fi
+
+ if test -z "$with_archflags"; then
+ if test -z "$with_arch64flags"; then
+ ARCHFLAGS="-m64"
+ else
+ ARCHFLAGS="$with_arch64flags"
+ fi
+ fi
+ fi
+
+ if test "x$enable_64bit" = xyes; then
+ # Build 64-bit libraries, 32-bit base...
+ if test -z "$with_arch64flags"; then
+ ARCH64FLAGS="-m64"
+ else
+ ARCH64FLAGS="$with_arch64flags"
+ fi
+
+ if test -z "$with_archflags"; then
+ if test -z "$with_arch32flags"; then
+ ARCHFLAGS="-m32"
+ else
+ ARCHFLAGS="$with_arch32flags"
+ fi
+ fi
+ fi
+ ;;
+ esac
+else
+ # Add vendor-specific compiler options...
+ 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 $PICFLAG = 1; then
+ OPTIM="+z $OPTIM"
+ fi
+
+ if test "x$enable_32bit" = xyes; then
+ # Build 32-bit libraries, 64-bit base...
+ if test -z "$with_arch32flags"; then
+ ARCH32FLAGS="+DD32"
+ else
+ ARCH32FLAGS="$with_arch32flags"
+ fi
+
+ if test -z "$with_archflags"; then
+ if test -z "$with_arch64flags"; then
+ ARCHFLAGS="+DD64"
+ else
+ ARCHFLAGS="$with_arch64flags"
+ fi
+ fi
+ fi
+
+ if test "x$enable_64bit" = xyes; then
+ # Build 64-bit libraries, 32-bit base...
+ if test -z "$with_arch64flags"; then
+ ARCH64FLAGS="+DD64"
+ else
+ ARCH64FLAGS="$with_arch64flags"
+ fi
+
+ if test -z "$with_archflags"; then
+ if test -z "$with_arch32flags"; then
+ ARCHFLAGS="+DD32"
+ else
+ ARCHFLAGS="$with_arch32flags"
+ fi
+ fi
+ 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 "x$with_optim" = x; then
+ OPTIM="-fullwarn -woff 1183,1209,1349,1506,3201 $OPTIM"
+ fi
+
+ if test "x$enable_32bit" = xyes; then
+ # Build 32-bit libraries, 64-bit base...
+ if test -z "$with_arch32flags"; then
+ ARCH32FLAGS="-n32 -mips3"
+ else
+ ARCH32FLAGS="$with_arch32flags"
+ fi
+
+ if test -z "$with_archflags"; then
+ if test -z "$with_arch64flags"; then
+ ARCHFLAGS="-64 -mips4"
+ else
+ ARCHFLAGS="$with_arch64flags"
+ fi
+ fi
+ fi
+
+ if test "x$enable_64bit" = xyes; then
+ # Build 64-bit libraries, 32-bit base...
+ if test -z "$with_arch64flags"; then
+ ARCH64FLAGS="-64 -mips4"
+ else
+ ARCH64FLAGS="$with_arch64flags"
+ fi
+
+ if test -z "$with_archflags"; then
+ if test -z "$with_arch32flags"; then
+ ARCHFLAGS="-n32 -mips3"
+ else
+ ARCHFLAGS="$with_arch32flags"
+ fi
+ fi
+ fi
+ ;;
+ OSF*)
+ # Tru64 UNIX aka Digital UNIX aka OSF/1
+ if test -z "$OPTIM"; then
+ if test "x$with_optim" = x; then
+ OPTIM="-O"
+ else
+ OPTIM="$with_optim"
+ fi
+ fi
+ ;;
+ SunOS*)
+ # Solaris
+ if test -z "$OPTIM"; then
+ if test "x$with_optim" = x; then
+ OPTIM="-xO2"
+ else
+ OPTIM="$with_optim $OPTIM"
+ fi
+ fi
+
+ if test $PICFLAG = 1; then
+ OPTIM="-KPIC $OPTIM"
+ fi
+
+ if test "x$enable_32bit" = xyes; then
+ # Compiling on a Solaris system, build 64-bit
+ # binaries with separate 32-bit libraries...
+ ARCH32FLAGS="-xarch=generic"
+
+ if test "x$with_optim" = x; then
+ # Suppress all of Sun's questionable
+ # warning messages, and default to
+ # 64-bit compiles of everything else...
+ OPTIM="-w $OPTIM"
+ fi
+
+ if test -z "$with_archflags"; then
+ if test -z "$with_arch64flags"; then
+ ARCHFLAGS="-xarch=generic64"
+ else
+ ARCHFLAGS="$with_arch64flags"
+ fi
+ fi
+ else
+ if test "x$enable_64bit" = xyes; then
+ # Build 64-bit libraries...
+ ARCH64FLAGS="-xarch=generic64"
+ fi
+
+ if test "x$with_optim" = x; then
+ # Suppress all of Sun's questionable
+ # warning messages, and default to
+ # 32-bit compiles of everything else...
+ OPTIM="-w $OPTIM"
+ fi
+
+ if test -z "$with_archflags"; then
+ if test -z "$with_arch32flags"; then
+ ARCHFLAGS="-xarch=generic"
+ else
+ ARCHFLAGS="$with_arch32flags"
+ fi
+ fi
+ 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 LDFLAGS environment"
+ echo "variables before running configure."
+ ;;
+ esac
+fi
+
+# Add general compiler options per platform...
+case $uname in
+ HP-UX*)
+ # 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"
+
+ # HP-UX 11.23 (at least) needs this definition to get the
+ # IPv6 header to work...
+ OPTIM="$OPTIM -D_HPUX_SOURCE"
+ ;;
+
+ Linux*)
+ # glibc 2.8 and higher breaks peer credentials unless you
+ # define _GNU_SOURCE...
+ OPTIM="$OPTIM -D_GNU_SOURCE"
+ ;;
+
+ OSF*)
+ # Tru64 UNIX aka Digital UNIX aka OSF/1 need to be told
+ # to be POSIX-compliant...
+ OPTIM="$OPTIM -D_XOPEN_SOURCE=500 -D_XOPEN_SOURCE_EXTENDED -D_OSF_SOURCE"
+ ;;
+esac
+
+dnl
+dnl End of "$Id: cups-compiler.m4 9770 2011-05-12 04:51:01Z mike $".
+dnl
diff --git a/config-scripts/cups-defaults.m4 b/config-scripts/cups-defaults.m4
new file mode 100644
index 000000000..f56ca5565
--- /dev/null
+++ b/config-scripts/cups-defaults.m4
@@ -0,0 +1,510 @@
+dnl
+dnl "$Id: cups-defaults.m4 9750 2011-05-06 22:53:53Z mike $"
+dnl
+dnl Default cupsd configuration settings for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+dnl Copyright 2006-2007 by Easy Software Products, all rights reserved.
+dnl
+dnl These coded instructions, statements, and computer programs are the
+dnl property of Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+dnl Default languages...
+LANGUAGES="`ls -1 locale/cups_*.po | sed -e '1,$s/locale\/cups_//' -e '1,$s/\.po//' | tr '\n' ' '`"
+
+AC_ARG_WITH(languages, [ --with-languages set installed languages, default=all ],[
+ case "$withval" in
+ none | no) LANGUAGES="" ;;
+ all) ;;
+ *) LANGUAGES="$withval" ;;
+ esac])
+AC_SUBST(LANGUAGES)
+
+dnl Mac OS X bundle-based localization support
+AC_ARG_WITH(bundledir, [ --with-bundledir set Mac OS X localization bundle directory ],
+ CUPS_BUNDLEDIR="$withval",
+ if test "x$uname" = xDarwin -a $uversion -ge 100; then
+ CUPS_BUNDLEDIR="/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/PrintCore.framework/Versions/A"
+ LANGUAGES=""
+ else
+ CUPS_BUNDLEDIR=""
+ fi)
+
+AC_SUBST(CUPS_BUNDLEDIR)
+if test "x$CUPS_BUNDLEDIR" != x; then
+ AC_DEFINE_UNQUOTED(CUPS_BUNDLEDIR, "$CUPS_BUNDLEDIR")
+fi
+
+dnl Default ConfigFilePerm
+AC_ARG_WITH(config_file_perm, [ --with-config-file-perm set default ConfigFilePerm value, default=0640],
+ CUPS_CONFIG_FILE_PERM="$withval",
+ if test "x$uname" = xDarwin; then
+ CUPS_CONFIG_FILE_PERM="644"
+ else
+ CUPS_CONFIG_FILE_PERM="640"
+ fi)
+AC_SUBST(CUPS_CONFIG_FILE_PERM)
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_CONFIG_FILE_PERM, 0$CUPS_CONFIG_FILE_PERM)
+
+dnl Default LogFilePerm
+AC_ARG_WITH(log_file_perm, [ --with-log-file-perm set default LogFilePerm value, default=0644],
+ CUPS_LOG_FILE_PERM="$withval",
+ CUPS_LOG_FILE_PERM="644")
+AC_SUBST(CUPS_LOG_FILE_PERM)
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_LOG_FILE_PERM, 0$CUPS_LOG_FILE_PERM)
+
+dnl Default FatalErrors
+AC_ARG_WITH(fatal_errors, [ --with-fatal-errors set default FatalErrors value, default=config],
+ CUPS_FATAL_ERRORS="$withval",
+ CUPS_FATAL_ERRORS="config")
+AC_SUBST(CUPS_FATAL_ERRORS)
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_FATAL_ERRORS, "$CUPS_FATAL_ERRORS")
+
+
+dnl Default LogLevel
+AC_ARG_WITH(log_level, [ --with-log-level set default LogLevel value, default=warn],
+ CUPS_LOG_LEVEL="$withval",
+ CUPS_LOG_LEVEL="warn")
+AC_SUBST(CUPS_LOG_LEVEL)
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_LOG_LEVEL, "$CUPS_LOG_LEVEL")
+
+dnl Default AccessLogLevel
+AC_ARG_WITH(access_log_level, [ --with-access-log-level set default AccessLogLevel value, default=actions],
+ CUPS_ACCESS_LOG_LEVEL="$withval",
+ CUPS_ACCESS_LOG_LEVEL="actions")
+AC_SUBST(CUPS_ACCESS_LOG_LEVEL)
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_ACCESS_LOG_LEVEL, "$CUPS_ACCESS_LOG_LEVEL")
+
+dnl Default Browsing
+AC_ARG_ENABLE(browsing, [ --disable-browsing disable Browsing by default])
+if test "x$enable_browsing" = xno; then
+ CUPS_BROWSING="No"
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_BROWSING, 0)
+else
+ CUPS_BROWSING="Yes"
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_BROWSING, 1)
+fi
+AC_SUBST(CUPS_BROWSING)
+
+dnl Default BrowseLocalProtocols
+AC_ARG_WITH(local_protocols, [ --with-local-protocols set default BrowseLocalProtocols, default="CUPS"],
+ default_local_protocols="$withval",
+ default_local_protocols="default")
+
+if test x$with_local_protocols != xno; then
+ if test "x$default_local_protocols" = "xdefault"; then
+ if test "x$DNSSDLIBS" != "x"; then
+ CUPS_BROWSE_LOCAL_PROTOCOLS="CUPS dnssd"
+ else
+ CUPS_BROWSE_LOCAL_PROTOCOLS="CUPS"
+ fi
+ else
+ CUPS_BROWSE_LOCAL_PROTOCOLS="$default_local_protocols"
+ fi
+else
+ CUPS_BROWSE_LOCAL_PROTOCOLS=""
+fi
+
+AC_SUBST(CUPS_BROWSE_LOCAL_PROTOCOLS)
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS,
+ "$CUPS_BROWSE_LOCAL_PROTOCOLS")
+
+dnl Default BrowseRemoteProtocols
+AC_ARG_WITH(remote_protocols, [ --with-remote-protocols set default BrowseRemoteProtocols, default="CUPS"],
+ default_remote_protocols="$withval",
+ default_remote_protocols="default")
+
+if test x$with_remote_protocols != xno; then
+ if test "x$default_remote_protocols" = "xdefault"; then
+ if test "$uname" = "Darwin" -a $uversion -ge 90; then
+ CUPS_BROWSE_REMOTE_PROTOCOLS=""
+ else
+ CUPS_BROWSE_REMOTE_PROTOCOLS="CUPS"
+ fi
+ else
+ CUPS_BROWSE_REMOTE_PROTOCOLS="$default_remote_protocols"
+ fi
+else
+ CUPS_BROWSE_REMOTE_PROTOCOLS=""
+fi
+
+AC_SUBST(CUPS_BROWSE_REMOTE_PROTOCOLS)
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS,
+ "$CUPS_BROWSE_REMOTE_PROTOCOLS")
+
+dnl Default BrowseShortNames
+AC_ARG_ENABLE(browse_short, [ --disable-browse-short-names
+ disable BrowseShortNames by default])
+if test "x$enable_browse_short" = xno; then
+ CUPS_BROWSE_SHORT_NAMES="No"
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_BROWSE_SHORT_NAMES, 0)
+else
+ CUPS_BROWSE_SHORT_NAMES="Yes"
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_BROWSE_SHORT_NAMES, 1)
+fi
+AC_SUBST(CUPS_BROWSE_SHORT_NAMES)
+
+dnl Default DefaultShared
+AC_ARG_ENABLE(default_shared, [ --disable-default-shared
+ disable DefaultShared by default])
+if test "x$enable_default_shared" = xno; then
+ CUPS_DEFAULT_SHARED="No"
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_DEFAULT_SHARED, 0)
+else
+ CUPS_DEFAULT_SHARED="Yes"
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_DEFAULT_SHARED, 1)
+fi
+AC_SUBST(CUPS_DEFAULT_SHARED)
+
+dnl Default ImplicitClasses
+AC_ARG_ENABLE(implicit, [ --disable-implicit-classes
+ disable ImplicitClasses by default])
+if test "x$enable_implicit" = xno; then
+ CUPS_IMPLICIT_CLASSES="No"
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_IMPLICIT_CLASSES, 0)
+else
+ CUPS_IMPLICIT_CLASSES="Yes"
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_IMPLICIT_CLASSES, 1)
+fi
+AC_SUBST(CUPS_IMPLICIT_CLASSES)
+
+dnl Default UseNetworkDefault
+AC_ARG_ENABLE(use_network_default, [ --enable-use-network-default
+ set UseNetworkDefault to Yes by default])
+if test "x$enable_use_network_default" != xno; then
+ AC_MSG_CHECKING(whether to use network default printers)
+ if test "x$enable_use_network_default" = xyes -o $uname != Darwin; then
+ CUPS_USE_NETWORK_DEFAULT="Yes"
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_USE_NETWORK_DEFAULT, 1)
+ AC_MSG_RESULT(yes)
+ else
+ CUPS_USE_NETWORK_DEFAULT="No"
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_USE_NETWORK_DEFAULT, 0)
+ AC_MSG_RESULT(no)
+ fi
+else
+ CUPS_USE_NETWORK_DEFAULT="No"
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_USE_NETWORK_DEFAULT, 0)
+fi
+AC_SUBST(CUPS_USE_NETWORK_DEFAULT)
+
+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 x$uname = xDarwin; then
+ if test x`id -u _lp 2>/dev/null` = x; then
+ CUPS_USER="lp";
+ else
+ CUPS_USER="_lp";
+ fi
+ AC_MSG_RESULT($CUPS_USER)
+ elif 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="nobody"
+ AC_MSG_RESULT(not found, using "$CUPS_USER")
+ fi
+ else
+ CUPS_USER="nobody"
+ AC_MSG_RESULT(no password file, using "$CUPS_USER")
+ fi)
+
+if test "x$CUPS_USER" = "xroot" -o "x$CUPS_USER" = "x0"; then
+ AC_MSG_ERROR([The default user for CUPS cannot be root!])
+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 x$uname = xDarwin; then
+ if test x`id -g _lp 2>/dev/null` = x; then
+ CUPS_GROUP="lp";
+ else
+ CUPS_GROUP="_lp";
+ fi
+ AC_MSG_RESULT($CUPS_GROUP)
+ elif test -f /etc/group; then
+ GROUP_LIST="_lp lp nobody"
+ 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="nobody"
+ AC_MSG_RESULT(not found, using "$CUPS_GROUP")
+ fi
+ else
+ CUPS_GROUP="nobody"
+ AC_MSG_RESULT(no group file, using "$CUPS_GROUP")
+ fi)
+
+if test "x$CUPS_GROUP" = "xroot" -o "x$CUPS_GROUP" = "xwheel" -o "x$CUPS_GROUP" = "x0"; then
+ AC_MSG_ERROR([The default group for CUPS cannot be root!])
+fi
+
+AC_ARG_WITH(system_groups, [ --with-system-groups set default system groups for CUPS],
+ CUPS_SYSTEM_GROUPS="$withval",
+ if test x$uname = xDarwin; then
+ CUPS_SYSTEM_GROUPS="admin"
+ else
+ AC_MSG_CHECKING(for default system groups)
+ if test -f /etc/group; then
+ CUPS_SYSTEM_GROUPS=""
+ GROUP_LIST="lpadmin sys system root"
+ for group in $GROUP_LIST; do
+ if test "`grep \^${group}: /etc/group`" != ""; then
+ if test "x$CUPS_SYSTEM_GROUPS" = x; then
+ CUPS_SYSTEM_GROUPS="$group"
+ else
+ CUPS_SYSTEM_GROUPS="$CUPS_SYSTEM_GROUPS $group"
+ fi
+ fi
+ done
+
+ if test "x$CUPS_SYSTEM_GROUPS" = x; then
+ CUPS_SYSTEM_GROUPS="$GROUP_LIST"
+ AC_MSG_RESULT(no groups found, using "$CUPS_SYSTEM_GROUPS")
+ else
+ AC_MSG_RESULT("$CUPS_SYSTEM_GROUPS")
+ fi
+ else
+ CUPS_SYSTEM_GROUPS="$GROUP_LIST"
+ AC_MSG_RESULT(no group file, using "$CUPS_SYSTEM_GROUPS")
+ fi
+ fi)
+
+CUPS_PRIMARY_SYSTEM_GROUP="`echo $CUPS_SYSTEM_GROUPS | awk '{print $1}'`"
+
+for group in $CUPS_SYSTEM_GROUPS; do
+ if test "x$CUPS_GROUP" = "x$group"; then
+ AC_MSG_ERROR([The default system groups cannot contain the default CUPS group!])
+ fi
+done
+
+AC_SUBST(CUPS_USER)
+AC_SUBST(CUPS_GROUP)
+AC_SUBST(CUPS_SYSTEM_GROUPS)
+AC_SUBST(CUPS_PRIMARY_SYSTEM_GROUP)
+
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_USER, "$CUPS_USER")
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_GROUP, "$CUPS_GROUP")
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_SYSTEM_GROUPS, "$CUPS_SYSTEM_GROUPS")
+
+dnl Default printcap file...
+AC_ARG_WITH(printcap, [ --with-printcap set default printcap file],
+ default_printcap="$withval",
+ default_printcap="default")
+
+if test x$default_printcap != xno; then
+ if test "x$default_printcap" = "xdefault"; then
+ case $uname in
+ Darwin*)
+ if test $uversion -ge 90; then
+ CUPS_DEFAULT_PRINTCAP="/Library/Preferences/org.cups.printers.plist"
+ else
+ CUPS_DEFAULT_PRINTCAP="/etc/printcap"
+ fi
+ ;;
+ SunOS*)
+ CUPS_DEFAULT_PRINTCAP="/etc/printers.conf"
+ ;;
+ *)
+ CUPS_DEFAULT_PRINTCAP="/etc/printcap"
+ ;;
+ esac
+ else
+ CUPS_DEFAULT_PRINTCAP="$default_printcap"
+ fi
+else
+ CUPS_DEFAULT_PRINTCAP=""
+fi
+
+AC_SUBST(CUPS_DEFAULT_PRINTCAP)
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_PRINTCAP, "$CUPS_DEFAULT_PRINTCAP")
+
+dnl Default LPD config file...
+AC_ARG_WITH(lpdconfigfile, [ --with-lpdconfigfile set default LPDConfigFile URI],
+ default_lpdconfigfile="$withval",
+ default_lpdconfigfile="default")
+
+if test x$default_lpdconfigfile != xno; then
+ if test "x$default_lpdconfigfile" = "xdefault"; then
+ case $uname in
+ Darwin*)
+ CUPS_DEFAULT_LPD_CONFIG_FILE="launchd:///System/Library/LaunchDaemons/org.cups.cups-lpd.plist"
+ ;;
+ *)
+ if test "x$XINETD" != x; then
+ CUPS_DEFAULT_LPD_CONFIG_FILE="xinetd://$XINETD/cups-lpd"
+ else
+ CUPS_DEFAULT_LPD_CONFIG_FILE=""
+ fi
+ ;;
+ esac
+ else
+ CUPS_DEFAULT_LPD_CONFIG_FILE="$default_lpdconfigfile"
+ fi
+else
+ CUPS_DEFAULT_LPD_CONFIG_FILE=""
+fi
+
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_LPD_CONFIG_FILE, "$CUPS_DEFAULT_LPD_CONFIG_FILE")
+
+dnl Default SMB config file...
+AC_ARG_WITH(smbconfigfile, [ --with-smbconfigfile set default SMBConfigFile URI],
+ default_smbconfigfile="$withval",
+ default_smbconfigfile="default")
+
+if test x$default_smbconfigfile != xno; then
+ if test "x$default_smbconfigfile" = "xdefault"; then
+ if test -f /etc/smb.conf; then
+ CUPS_DEFAULT_SMB_CONFIG_FILE="samba:///etc/smb.conf"
+ else
+ CUPS_DEFAULT_SMB_CONFIG_FILE=""
+ fi
+ else
+ CUPS_DEFAULT_SMB_CONFIG_FILE="$default_smbconfigfile"
+ fi
+else
+ CUPS_DEFAULT_SMB_CONFIG_FILE=""
+fi
+
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_SMB_CONFIG_FILE, "$CUPS_DEFAULT_SMB_CONFIG_FILE")
+
+dnl Default MaxCopies value...
+AC_ARG_WITH(max-copies, [ --with-max-copies set default max copies value, default=9999 ],
+ CUPS_MAX_COPIES="$withval",
+ CUPS_MAX_COPIES="9999")
+
+AC_SUBST(CUPS_MAX_COPIES)
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_MAX_COPIES, $CUPS_MAX_COPIES)
+
+dnl Default raw printing state
+AC_ARG_ENABLE(raw_printing, [ --disable-raw-printing do not allow raw printing by default])
+if test "x$enable_raw_printing" != xno; then
+ DEFAULT_RAW_PRINTING=""
+else
+ DEFAULT_RAW_PRINTING="#"
+fi
+AC_SUBST(DEFAULT_RAW_PRINTING)
+
+dnl Default SNMP options...
+AC_ARG_WITH(snmp-address, [ --with-snmp-address set SNMP query address, default=auto ],
+ if test "x$withval" = x; then
+ CUPS_SNMP_ADDRESS=""
+ else
+ CUPS_SNMP_ADDRESS="Address $withval"
+ fi,
+ if test "x$uname" = xDarwin; then
+ CUPS_SNMP_ADDRESS=""
+ else
+ CUPS_SNMP_ADDRESS="Address @LOCAL"
+ fi)
+
+AC_ARG_WITH(snmp-community, [ --with-snmp-community set SNMP community, default=public ],
+ CUPS_SNMP_COMMUNITY="Community $withval",
+ CUPS_SNMP_COMMUNITY="Community public")
+
+AC_SUBST(CUPS_SNMP_ADDRESS)
+AC_SUBST(CUPS_SNMP_COMMUNITY)
+
+dnl New default port definition for IPP...
+AC_ARG_WITH(ipp-port, [ --with-ipp-port set port number for IPP, default=631 ],
+ DEFAULT_IPP_PORT="$withval",
+ DEFAULT_IPP_PORT="631")
+
+AC_SUBST(DEFAULT_IPP_PORT)
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_IPP_PORT,$DEFAULT_IPP_PORT)
+
+dnl Filters
+AC_ARG_ENABLE(bannertops, [ --enable-bannertops always build the banner filter ])
+AC_ARG_ENABLE(texttops, [ --enable-texttops always build the text filter ])
+
+if test "x$enable_bannertops" = xno; then
+ BANNERTOPS=""
+ DEFAULT_BANNERTOPS="#"
+elif test "x$enable_bannertops" = xyes; then
+ BANNERTOPS="bannertops"
+ DEFAULT_BANNERTOPS=""
+elif test $uname = Darwin; then
+ BANNERTOPS=""
+ DEFAULT_BANNERTOPS="#"
+else
+ BANNERTOPS="bannertops"
+ DEFAULT_BANNERTOPS=""
+fi
+
+if test "x$enable_texttops" = xno; then
+ TEXTTOPS=""
+ DEFAULT_TEXTTOPS="#"
+elif test "x$enable_texttops" = xyes; then
+ TEXTTOPS="texttops"
+ DEFAULT_TEXTTOPS=""
+elif test $uname = Darwin; then
+ TEXTTOPS=""
+ DEFAULT_TEXTTOPS="#"
+else
+ TEXTTOPS="texttops"
+ DEFAULT_TEXTTOPS=""
+fi
+
+AC_SUBST(BANNERTOPS)
+AC_SUBST(DEFAULT_BANNERTOPS)
+AC_SUBST(DEFAULT_TEXTTOPS)
+AC_SUBST(TEXTTOPS)
+
+dnl Fonts
+if test "x$BANNERTOPS" = x -a "x$TEXTTOPS" = x; then
+ FONTS=""
+else
+ FONTS="fonts"
+fi
+
+AC_SUBST(FONTS)
+
+dnl Web interface...
+AC_ARG_ENABLE(webif, [ --enable-webif enable the web interface by default, default=no for Mac OS X])
+case "x$enable_webif" in
+ xno)
+ CUPS_WEBIF=No
+ CUPS_DEFAULT_WEBIF=0
+ ;;
+ xyes)
+ CUPS_WEBIF=Yes
+ CUPS_DEFAULT_WEBIF=1
+ ;;
+ *)
+ if test $uname = Darwin; then
+ CUPS_WEBIF=No
+ CUPS_DEFAULT_WEBIF=0
+ else
+ CUPS_WEBIF=Yes
+ CUPS_DEFAULT_WEBIF=1
+ fi
+ ;;
+esac
+
+AC_SUBST(CUPS_WEBIF)
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_WEBIF, $CUPS_DEFAULT_WEBIF)
+
+dnl
+dnl End of "$Id: cups-defaults.m4 9750 2011-05-06 22:53:53Z mike $".
+dnl
diff --git a/config-scripts/cups-directories.m4 b/config-scripts/cups-directories.m4
new file mode 100644
index 000000000..4159f4cf8
--- /dev/null
+++ b/config-scripts/cups-directories.m4
@@ -0,0 +1,440 @@
+dnl
+dnl "$Id: cups-directories.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
+dnl Directory stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+dnl Copyright 1997-2007 by Easy Software Products, all rights reserved.
+dnl
+dnl These coded instructions, statements, and computer programs are the
+dnl property of Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "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
+
+AC_DEFINE_UNQUOTED(CUPS_BINDIR, "$bindir")
+
+dnl Fix "sbindir" variable...
+if test "$sbindir" = "\${exec_prefix}/sbin"; then
+ sbindir="$exec_prefix/sbin"
+fi
+
+AC_DEFINE_UNQUOTED(CUPS_SBINDIR, "$sbindir")
+
+dnl Fix "sharedstatedir" variable if it hasn't been specified...
+if test "$sharedstatedir" = "\${prefix}/com" -a "$prefix" = "/"; then
+ sharedstatedir="/usr/com"
+fi
+
+dnl Fix "datarootdir" variable if it hasn't been specified...
+if test "$datarootdir" = "\${prefix}/share"; then
+ if test "$prefix" = "/"; then
+ datarootdir="/usr/share"
+ else
+ datarootdir="$prefix/share"
+ fi
+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
+elif test "$datadir" = "\${datarootdir}"; then
+ datadir="$datarootdir"
+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...
+if test "$libdir" = "\${exec_prefix}/lib"; then
+ case "$uname" in
+ IRIX*)
+ libdir="$exec_prefix/lib32"
+ ;;
+ Linux*)
+ if test -d /usr/lib64; then
+ libdir="$exec_prefix/lib64"
+ fi
+ ;;
+ HP-UX*)
+ if test -d /usr/lib/hpux32; then
+ libdir="$exec_prefix/lib/hpux32"
+ fi
+ ;;
+ esac
+fi
+
+dnl Setup private include directory...
+AC_ARG_WITH(privateinclude, [ --with-privateinclude set path for private include files, default=none],privateinclude="$withval",privateinclude="")
+if test "x$privateinclude" != x -a "x$privateinclude" != xnone; then
+ PRIVATEINCLUDE="$privateinclude/cups"
+else
+ privateinclude=""
+ PRIVATEINCLUDE=""
+fi
+AC_SUBST(privateinclude)
+AC_SUBST(PRIVATEINCLUDE)
+
+dnl Setup init.d locations...
+AC_ARG_WITH(rcdir, [ --with-rcdir set path for rc scripts],rcdir="$withval",rcdir="")
+AC_ARG_WITH(rclevels, [ --with-rclevels set run levels for rc scripts],rclevels="$withval",rclevels="2 3 5")
+AC_ARG_WITH(rcstart, [ --with-rcstart set start number for rc scripts],rcstart="$withval",rcstart="99")
+AC_ARG_WITH(rcstop, [ --with-rcstop set stop number for rc scripts],rcstop="$withval",rcstop="00")
+AC_ARG_WITH(smfmanifestdir, [ --with-smfmanifestdir set path for Solaris SMF manifest],smfmanifestdir="$withval",smfmanifestdir="")
+
+INITDIR=""
+INITDDIR=""
+RCLEVELS="$rclevels"
+RCSTART="$rcstart"
+RCSTOP="$rcstop"
+SMFMANIFESTDIR=""
+
+if test x$rcdir = x; then
+ case "$uname" in
+ AIX*)
+ INITDIR="/etc/rc.d"
+ ;;
+
+ Darwin*)
+ # Darwin and MacOS X...
+ if test -x /sbin/launchd; then
+ INITDDIR="/System/Library/LaunchDaemons"
+ else
+ INITDDIR="/System/Library/StartupItems/PrintingServices"
+ fi
+ ;;
+
+ FreeBSD* | OpenBSD* | MirBSD* | ekkoBSD*)
+ # FreeBSD and OpenBSD
+ ;;
+
+ HP-UX*)
+ INITDIR="/sbin"
+ RCLEVELS="2"
+ RCSTART="380"
+ RCSTOP="620"
+ ;;
+
+ IRIX*)
+ # IRIX
+ INITDIR="/etc"
+ RCSTART="60"
+ RCSTOP="25"
+ ;;
+
+ Linux | GNU | GNU/k*BSD*)
+ # Linux/HURD seems to choose an init.d directory at random...
+ if test -d /sbin/init.d; then
+ # SuSE
+ INITDIR="/sbin/init.d"
+ else
+ if test -d /etc/init.d; then
+ # Others
+ INITDIR="/etc"
+ else
+ # RedHat
+ INITDIR="/etc/rc.d"
+ fi
+ fi
+ RCSTART="81"
+ RCSTOP="36"
+ ;;
+
+ NetBSD*)
+ # NetBSD
+ INITDDIR="/etc/rc.d"
+ ;;
+
+ OSF1*)
+ INITDIR="/sbin"
+ ;;
+
+ SunOS*)
+ # Solaris
+ if test "x$smfmanifestdir" != x; then
+ SMFMANIFESTDIR=$smfmanifestdir
+ else
+ INITDIR="/etc"
+ RCSTART="81"
+ fi
+ ;;
+
+ *)
+ INITDIR="/etc"
+ ;;
+
+ esac
+elif test "x$rcdir" != xno; then
+ if test "x$rclevels" = x; then
+ INITDDIR="$rcdir"
+ else
+ INITDIR="$rcdir"
+ fi
+fi
+
+AC_SUBST(INITDIR)
+AC_SUBST(INITDDIR)
+AC_SUBST(RCLEVELS)
+AC_SUBST(RCSTART)
+AC_SUBST(RCSTOP)
+AC_SUBST(SMFMANIFESTDIR)
+
+dnl Xinetd support...
+AC_ARG_WITH(xinetd, [ --with-xinetd set path for xinetd config files],XINETD="$withval",XINETD="")
+
+if test "x$XINETD" = x -a ! -x /sbin/launchd; then
+ for dir in /private/etc/xinetd.d /etc/xinetd.d /usr/local/etc/xinetd.d; do
+ if test -d $dir; then
+ XINETD="$dir"
+ break
+ fi
+ done
+elif test "x$XINETD" = xno; then
+ XINETD=""
+fi
+
+AC_SUBST(XINETD)
+
+dnl LPD sharing support...
+AC_ARG_WITH(lpdconfig, [ --with-lpdconfig set URI for LPD config file],
+ LPDCONFIG="$withval", LPDCONFIG="")
+
+if test "x$LPDCONFIG" = x; then
+ if test -f /System/Library/LaunchDaemons/org.cups.cups-lpd.plist; then
+ LPDCONFIG="launchd:///System/Library/LaunchDaemons/org.cups.cups-lpd.plist"
+ elif test "x$XINETD" != x; then
+ LPDCONFIG="xinetd://$XINETD/cups-lpd"
+ fi
+fi
+
+if test "x$LPDCONFIG" = xoff; then
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_LPD_CONFIG, "")
+else
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_LPD_CONFIG, "$LPDCONFIG")
+fi
+
+dnl SMB sharing support...
+AC_ARG_WITH(smbconfig, [ --with-smbconfig set URI for Samba config file],
+ SMBCONFIG="$withval", SMBCONFIG="")
+
+if test "x$SMBCONFIG" = x; then
+ if test -f /System/Library/LaunchDaemons/smbd.plist; then
+ SMBCONFIG="launchd:///System/Library/LaunchDaemons/smbd.plist"
+ else
+ for dir in /etc /etc/samba /usr/local/etc; do
+ if test -f $dir/smb.conf; then
+ SMBCONFIG="samba://$dir/smb.conf"
+ break
+ fi
+ done
+ fi
+fi
+
+if test "x$SMBCONFIG" = xoff; then
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_SMB_CONFIG, "")
+else
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_SMB_CONFIG, "$SMBCONFIG")
+fi
+
+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
+ if test "x$uname" = xDarwin; then
+ CUPS_CACHEDIR="$localstatedir/spool/cups/cache"
+ else
+ CUPS_CACHEDIR="$localstatedir/cache/cups"
+ fi
+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)
+
+# Icon directory
+AC_ARG_WITH(icondir, [ --with-icondir set path for application icons],icondir="$withval",icondir="")
+
+if test "x$icondir" = x -a -d /usr/share/icons; then
+ ICONDIR="/usr/share/icons"
+else
+ ICONDIR="$icondir"
+fi
+
+AC_SUBST(ICONDIR)
+
+# Menu directory
+AC_ARG_WITH(menudir, [ --with-menudir set path for application menus],menudir="$withval",menudir="")
+
+if test "x$menudir" = x -a -d /usr/share/applications; then
+ MENUDIR="/usr/share/applications"
+else
+ MENUDIR="$menudir"
+fi
+
+AC_SUBST(MENUDIR)
+
+# 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
+if test "$localedir" = "\${datarootdir}/locale"; then
+ case "$uname" in
+ Linux | GNU | *BSD* | Darwin*)
+ CUPS_LOCALEDIR="$datarootdir/locale"
+ ;;
+
+ OSF1* | AIX*)
+ CUPS_LOCALEDIR="$exec_prefix/lib/nls/msg"
+ ;;
+
+ *)
+ # This is the standard System V location...
+ CUPS_LOCALEDIR="$exec_prefix/lib/locale"
+ ;;
+ esac
+else
+ CUPS_LOCALEDIR="$localedir"
+fi
+
+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="$exec_prefix/lib/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
+case "$uname" in
+ Darwin*)
+ # Darwin (Mac OS X)
+ CUPS_STATEDIR="$CUPS_SERVERROOT"
+ ;;
+ *)
+ # All others
+ CUPS_STATEDIR="$localstatedir/run/cups"
+ ;;
+esac
+AC_DEFINE_UNQUOTED(CUPS_STATEDIR, "$CUPS_STATEDIR")
+AC_SUBST(CUPS_STATEDIR)
+
+dnl
+dnl End of "$Id: cups-directories.m4 9771 2011-05-12 05:21:56Z mike $".
+dnl
diff --git a/config-scripts/cups-dnssd.m4 b/config-scripts/cups-dnssd.m4
new file mode 100644
index 000000000..e6bb8555d
--- /dev/null
+++ b/config-scripts/cups-dnssd.m4
@@ -0,0 +1,64 @@
+dnl
+dnl "$Id: cups-dnssd.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
+dnl DNS Service Discovery (aka Bonjour) stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+dnl
+dnl These coded instructions, statements, and computer programs are the
+dnl property of Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+AC_ARG_ENABLE(dnssd, [ --disable-dnssd disable DNS Service Discovery support])
+AC_ARG_WITH(dnssd-libs, [ --with-dnssd-libs set directory for DNS Service Discovery library],
+ LDFLAGS="-L$withval $LDFLAGS"
+ DSOFLAGS="-L$withval $DSOFLAGS",)
+AC_ARG_WITH(dnssd-includes, [ --with-dnssd-includes set directory for DNS Service Discovery includes],
+ CFLAGS="-I$withval $CFLAGS"
+ CPPFLAGS="-I$withval $CPPFLAGS",)
+
+DNSSDLIBS=""
+DNSSD_BACKEND=""
+
+if test x$enable_dnssd != xno; then
+ AC_CHECK_HEADER(dns_sd.h, [
+ case "$uname" in
+ Darwin*)
+ # Darwin and MacOS X...
+ AC_DEFINE(HAVE_DNSSD)
+ AC_DEFINE(HAVE_COREFOUNDATION)
+ AC_DEFINE(HAVE_SYSTEMCONFIGURATION)
+ DNSSDLIBS="-framework CoreFoundation -framework SystemConfiguration"
+ DNSSD_BACKEND="dnssd"
+ ;;
+ *)
+ # All others...
+ AC_MSG_CHECKING(for current version of dns_sd library)
+ SAVELIBS="$LIBS"
+ LIBS="$LIBS -ldns_sd"
+ AC_TRY_COMPILE([#include <dns_sd.h>],
+ [int constant = kDNSServiceFlagsShareConnection;
+ unsigned char txtRecord[100];
+ uint8_t valueLen;
+ TXTRecordGetValuePtr(sizeof(txtRecord),
+ txtRecord, "value", &valueLen);],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_DNSSD)
+ DNSSDLIBS="-ldns_sd"
+ DNSSD_BACKEND="dnssd",
+ AC_MSG_RESULT(no))
+ LIBS="$SAVELIBS"
+ ;;
+ esac
+ ])
+fi
+
+AC_SUBST(DNSSDLIBS)
+AC_SUBST(DNSSD_BACKEND)
+
+dnl
+dnl End of "$Id: cups-dnssd.m4 9771 2011-05-12 05:21:56Z mike $".
+dnl
diff --git a/config-scripts/cups-gssapi.m4 b/config-scripts/cups-gssapi.m4
new file mode 100644
index 000000000..b1b1b2e2d
--- /dev/null
+++ b/config-scripts/cups-gssapi.m4
@@ -0,0 +1,135 @@
+dnl
+dnl "$Id: cups-gssapi.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
+dnl GSSAPI/Kerberos library detection for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+dnl Copyright 2006-2007 by Easy Software Products.
+dnl
+dnl This file contains Kerberos support code, copyright 2006 by
+dnl Jelmer Vernooij.
+dnl
+dnl These coded instructions, statements, and computer programs are the
+dnl property of Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+AC_ARG_ENABLE(gssapi, [ --disable-gssapi disable GSSAPI support])
+
+LIBGSSAPI=""
+AC_SUBST(LIBGSSAPI)
+
+if test x$enable_gssapi != xno; then
+ AC_PATH_PROG(KRB5CONFIG, krb5-config)
+ if test "x$KRB5CONFIG" != x; then
+ case "$uname" in
+ Darwin)
+ # Mac OS X weak-links to the Kerberos framework...
+ LIBGSSAPI="-weak_framework Kerberos"
+ AC_MSG_CHECKING(for GSS framework)
+ if test -d /System/Library/Frameworks/GSS.framework; then
+ AC_MSG_RESULT(yes)
+ LIBGSSAPI="$LIBGSSAPI -weak_framework GSS"
+ else
+ AC_MSG_RESULT(no)
+ fi
+ ;;
+ SunOS*)
+ # Solaris has a non-standard krb5-config, don't use it!
+ AC_CHECK_LIB(gss, gss_display_status,
+ AC_DEFINE(HAVE_GSSAPI, 1, [Whether GSSAPI is available])
+ CFLAGS="`$KRB5CONFIG --cflags` $CFLAGS"
+ CPPFLAGS="`$KRB5CONFIG --cflags` $CPPFLAGS"
+ LIBGSSAPI="-lgss `$KRB5CONFIG --libs`")
+ ;;
+ *)
+ # Other platforms just ask for GSSAPI
+ CFLAGS="`$KRB5CONFIG --cflags gssapi` $CFLAGS"
+ CPPFLAGS="`$KRB5CONFIG --cflags gssapi` $CPPFLAGS"
+ LIBGSSAPI="`$KRB5CONFIG --libs gssapi`"
+ ;;
+ esac
+ AC_DEFINE(HAVE_GSSAPI, 1, [Whether GSSAPI is available])
+ else
+ # Check for vendor-specific implementations...
+ case "$uname" in
+ HP-UX*)
+ AC_CHECK_LIB(gss, gss_display_status,
+ AC_DEFINE(HAVE_GSSAPI, 1, [Whether GSSAPI is available])
+ LIBGSSAPI="-lgss -lgssapi_krb5")
+ ;;
+ SunOS*)
+ AC_CHECK_LIB(gss, gss_display_status,
+ AC_DEFINE(HAVE_GSSAPI, 1, [Whether GSSAPI is available])
+ LIBGSSAPI="-lgss")
+ ;;
+ esac
+ fi
+
+ if test "x$LIBGSSAPI" != x; then
+ AC_CHECK_HEADER(krb5.h, AC_DEFINE(HAVE_KRB5_H))
+ if test -d /System/Library/Frameworks/GSS.framework; then
+ AC_CHECK_HEADER(GSS/gssapi.h, AC_DEFINE(HAVE_GSS_GSSAPI_H))
+ AC_CHECK_HEADER(GSS/gssapi_generic.h, AC_DEFINE(HAVE_GSSAPI_GENERIC_H))
+ AC_CHECK_HEADER(GSS/gssapi_krb5.h, AC_DEFINE(HAVE_GSSAPI_KRB5_H))
+ AC_CHECK_HEADER(GSS/gssapi_spi.h, AC_DEFINE(HAVE_GSS_GSSAPI_SPI_H))
+ else
+ AC_CHECK_HEADER(gssapi.h, AC_DEFINE(HAVE_GSSAPI_H))
+ AC_CHECK_HEADER(gssapi/gssapi.h, AC_DEFINE(HAVE_GSSAPI_GSSAPI_H))
+ AC_CHECK_HEADER(gssapi/gssapi_generic.h, AC_DEFINE(HAVE_GSSAPI_GENERIC_H))
+ AC_CHECK_HEADER(gssapi/gssapi_krb5.h, AC_DEFINE(HAVE_GSSAPI_KRB5_H))
+ fi
+
+ SAVELIBS="$LIBS"
+ LIBS="$LIBS $LIBGSSAPI"
+
+ AC_CHECK_FUNC(__ApplePrivate_gss_acquire_cred_ex_f,
+ AC_DEFINE(HAVE_GSS_ACQUIRE_CRED_EX_F))
+
+ AC_MSG_CHECKING(for GSS_C_NT_HOSTBASED_SERVICE)
+ if test x$ac_cv_header_gssapi_gssapi_h = xyes; then
+ AC_TRY_COMPILE([ #include <gssapi/gssapi.h> ],
+ [ gss_OID foo = GSS_C_NT_HOSTBASED_SERVICE; ],
+ AC_DEFINE(HAVE_GSS_C_NT_HOSTBASED_SERVICE)
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no))
+ elif test x$ac_cv_header_gss_gssapi_h = xyes; then
+ AC_TRY_COMPILE([ #include <GSS/gssapi.h> ],
+ [ gss_OID foo = GSS_C_NT_HOSTBASED_SERVICE; ],
+ AC_DEFINE(HAVE_GSS_C_NT_HOSTBASED_SERVICE)
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no))
+ else
+ AC_TRY_COMPILE([ #include <gssapi.h> ],
+ [ gss_OID foo = GSS_C_NT_HOSTBASED_SERVICE; ],
+ AC_DEFINE(HAVE_GSS_C_NT_HOSTBASED_SERVICE)
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no))
+ fi
+
+ LIBS="$SAVELIBS"
+ fi
+fi
+
+dnl Default GSS service name...
+AC_ARG_WITH(gssservicename, [ --with-gssservicename set default gss service name],
+ default_gssservicename="$withval",
+ default_gssservicename="default")
+
+if test x$default_gssservicename != xno; then
+ if test "x$default_gssservicename" = "xdefault"; then
+ CUPS_DEFAULT_GSSSERVICENAME="host"
+ else
+ CUPS_DEFAULT_GSSSERVICENAME="$default_gssservicename"
+ fi
+else
+ CUPS_DEFAULT_GSSSERVICENAME=""
+fi
+
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_GSSSERVICENAME, "$CUPS_DEFAULT_GSSSERVICENAME")
+
+dnl
+dnl End of "$Id: cups-gssapi.m4 9771 2011-05-12 05:21:56Z mike $".
+dnl
diff --git a/config-scripts/cups-image.m4 b/config-scripts/cups-image.m4
new file mode 100644
index 000000000..8c0be0969
--- /dev/null
+++ b/config-scripts/cups-image.m4
@@ -0,0 +1,112 @@
+dnl
+dnl "$Id: cups-image.m4 9750 2011-05-06 22:53:53Z mike $"
+dnl
+dnl Image library/filter stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+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 Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+dnl See if we want the image filters included at all...
+AC_ARG_ENABLE(image, [ --enable-image always build the image filters])
+
+DEFAULT_IMAGEFILTERS="#"
+IMGFILTERS=""
+if test "x$enable_image" != xno; then
+ AC_MSG_CHECKING(whether to build image filters)
+ if test "x$enable_image" = xyes -o $uname != Darwin; then
+ IMGFILTERS="imagetops imagetoraster"
+ DEFAULT_IMAGEFILTERS=""
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi
+fi
+
+AC_SUBST(DEFAULT_IMAGEFILTERS)
+AC_SUBST(IMGFILTERS)
+
+dnl Check for image libraries...
+AC_ARG_ENABLE(jpeg, [ --disable-jpeg disable JPEG support])
+AC_ARG_ENABLE(png, [ --disable-png disable PNG support])
+AC_ARG_ENABLE(tiff, [ --disable-tiff disable TIFF support])
+
+LIBJPEG=""
+LIBPNG=""
+LIBTIFF=""
+LIBZ=""
+
+AC_SUBST(LIBJPEG)
+AC_SUBST(LIBPNG)
+AC_SUBST(LIBTIFF)
+AC_SUBST(LIBZ)
+
+dnl Image libraries use math library functions...
+AC_SEARCH_LIBS(pow, m)
+
+dnl Save the current libraries since we don't want the image libraries
+dnl included with every program...
+SAVELIBS="$LIBS"
+
+dnl JPEG library...
+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
+
+dnl ZLIB library...
+AC_CHECK_HEADER(zlib.h,
+ AC_CHECK_LIB(z, gzgets,
+ AC_DEFINE(HAVE_LIBZ)
+ LIBZ="-lz"
+ LIBS="$LIBS -lz"))
+
+dnl PNG library...
+if test x$enable_png != xno; then
+ AC_CHECK_HEADER(png.h,
+ AC_CHECK_LIB(png, png_create_read_struct,
+ AC_DEFINE(HAVE_LIBPNG)
+ LIBPNG="-lpng"))
+else
+ AC_MSG_NOTICE([PNG support disabled with --disable-png.])
+fi
+
+dnl TIFF library...
+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 9750 2011-05-06 22:53:53Z mike $".
+dnl
diff --git a/config-scripts/cups-largefile.m4 b/config-scripts/cups-largefile.m4
new file mode 100644
index 000000000..c4eab9a84
--- /dev/null
+++ b/config-scripts/cups-largefile.m4
@@ -0,0 +1,52 @@
+dnl
+dnl "$Id: cups-largefile.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
+dnl Large file support stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+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 Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "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 x$ac_cv_sys_large_files = x1; then
+ LARGEFILE="$LARGEFILE -D_LARGE_FILES"
+ fi
+
+ if test x$ac_cv_sys_file_offset_bits = x64; 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 9771 2011-05-12 05:21:56Z mike $".
+dnl
diff --git a/config-scripts/cups-launchd.m4 b/config-scripts/cups-launchd.m4
new file mode 100644
index 000000000..5da5e077e
--- /dev/null
+++ b/config-scripts/cups-launchd.m4
@@ -0,0 +1,43 @@
+dnl
+dnl "$Id: cups-launchd.m4 8983 2010-02-13 02:20:23Z mike $"
+dnl
+dnl launchd stuff for CUPS.
+dnl
+dnl Copyright 2007-2010 by Apple Inc.
+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 Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+
+AC_ARG_ENABLE(launchd, [ --disable-launchd disable launchd support])
+
+DEFAULT_LAUNCHD_CONF=""
+LAUNCHDLIBS=""
+
+if test x$enable_launchd != xno; then
+ AC_CHECK_FUNC(launch_msg, AC_DEFINE(HAVE_LAUNCHD))
+ AC_CHECK_HEADER(launch.h, AC_DEFINE(HAVE_LAUNCH_H))
+
+ case "$uname" in
+ Darwin*)
+ # Darwin, MacOS X
+ DEFAULT_LAUNCHD_CONF="/System/Library/LaunchDaemons/org.cups.cupsd.plist"
+ # liblaunch is already part of libSystem
+ ;;
+ *)
+ # All others; this test will need to be updated
+ ;;
+ esac
+fi
+
+AC_SUBST(DEFAULT_LAUNCHD_CONF)
+AC_SUBST(LAUNCHDLIBS)
+
+dnl
+dnl End of "$Id: cups-launchd.m4 8983 2010-02-13 02:20:23Z mike $".
+dnl
diff --git a/config-scripts/cups-ldap.m4 b/config-scripts/cups-ldap.m4
new file mode 100644
index 000000000..7d68323ab
--- /dev/null
+++ b/config-scripts/cups-ldap.m4
@@ -0,0 +1,52 @@
+dnl
+dnl "$Id: cups-ldap.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
+dnl LDAP configuration stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+dnl Copyright 2003-2006 by Easy Software Products, all rights reserved.
+dnl
+dnl These coded instructions, statements, and computer programs are the
+dnl property of Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+AC_ARG_ENABLE(ldap, [ --disable-ldap disable LDAP support])
+AC_ARG_WITH(ldap-libs, [ --with-ldap-libs set directory for LDAP library],
+ LDFLAGS="-L$withval $LDFLAGS"
+ DSOFLAGS="-L$withval $DSOFLAGS",)
+AC_ARG_WITH(ldap-includes, [ --with-ldap-includes set directory for LDAP includes],
+ CFLAGS="-I$withval $CFLAGS"
+ CPPFLAGS="-I$withval $CPPFLAGS",)
+
+LIBLDAP=""
+
+if test x$enable_ldap != xno; then
+ AC_CHECK_HEADER(ldap.h, [
+ AC_CHECK_LIB(ldap, ldap_initialize,
+ AC_DEFINE(HAVE_LDAP)
+ AC_DEFINE(HAVE_OPENLDAP)
+ LIBLDAP="-lldap"
+ AC_CHECK_LIB(ldap, ldap_start_tls,
+ AC_DEFINE(HAVE_LDAP_SSL)),
+
+ AC_CHECK_LIB(ldap, ldap_init,
+ AC_DEFINE(HAVE_LDAP)
+ AC_DEFINE(HAVE_MOZILLA_LDAP)
+ LIBLDAP="-lldap"
+ AC_CHECK_HEADER(ldap_ssl.h, AC_DEFINE(HAVE_LDAP_SSL_H),,[#include <ldap.h>])
+ AC_CHECK_LIB(ldap, ldapssl_init,
+ AC_DEFINE(HAVE_LDAP_SSL)))
+ )
+ AC_CHECK_LIB(ldap, ldap_set_rebind_proc, AC_DEFINE(HAVE_LDAP_REBIND_PROC))
+ ])
+fi
+
+AC_SUBST(LIBLDAP)
+
+
+dnl
+dnl End of "$Id: cups-ldap.m4 9771 2011-05-12 05:21:56Z mike $".
+dnl
diff --git a/config-scripts/cups-libtool.m4 b/config-scripts/cups-libtool.m4
new file mode 100644
index 000000000..5b95b3997
--- /dev/null
+++ b/config-scripts/cups-libtool.m4
@@ -0,0 +1,39 @@
+dnl
+dnl "$Id: cups-libtool.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
+dnl Libtool stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+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 Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+AC_ARG_ENABLE(libtool_unsupported, [ --enable-libtool-unsupported
+ build with libtool (UNSUPPORTED!)],
+ [if test x$enable_libtool_unsupported != xno; then
+ LIBTOOL="$enable_libtool_unsupported"
+ enable_shared=no
+ echo "WARNING: libtool is not supported or endorsed by Apple Inc."
+ echo " WE DO NOT PROVIDE SUPPORT FOR LIBTOOL PROBLEMS."
+ 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 9771 2011-05-12 05:21:56Z mike $".
+dnl
diff --git a/config-scripts/cups-manpages.m4 b/config-scripts/cups-manpages.m4
new file mode 100644
index 000000000..3a7afd730
--- /dev/null
+++ b/config-scripts/cups-manpages.m4
@@ -0,0 +1,96 @@
+dnl
+dnl "$Id: cups-manpages.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
+dnl Manpage stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+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 Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+dnl Fix "mandir" variable...
+if test "$mandir" = "\${datarootdir}/man" -a "$prefix" = "/"; then
+ # New GNU "standards" break previous ones, so make sure we use
+ # the right default location for the operating system...
+ mandir="\${prefix}/man"
+fi
+
+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
+ IRIX*)
+ # SGI IRIX
+ MAN1EXT=1
+ MAN5EXT=5
+ MAN7EXT=7
+ MAN8EXT=1m
+ MAN8DIR=1
+ ;;
+ SunOS* | HP-UX*)
+ # Solaris and HP-UX
+ MAN1EXT=1
+ MAN5EXT=5
+ MAN7EXT=7
+ MAN8EXT=1m
+ MAN8DIR=1m
+ ;;
+ Linux* | GNU* | Darwin*)
+ # Linux, GNU Hurd, and Mac OS X
+ MAN1EXT=1.gz
+ MAN5EXT=5.gz
+ MAN7EXT=7.gz
+ MAN8EXT=8.gz
+ MAN8DIR=8
+ ;;
+ *)
+ # All others
+ MAN1EXT=1
+ MAN5EXT=5
+ MAN7EXT=7
+ MAN8EXT=8
+ MAN8DIR=8
+ ;;
+esac
+
+AC_SUBST(MAN1EXT)
+AC_SUBST(MAN5EXT)
+AC_SUBST(MAN7EXT)
+AC_SUBST(MAN8EXT)
+AC_SUBST(MAN8DIR)
+
+dnl
+dnl End of "$Id: cups-manpages.m4 9771 2011-05-12 05:21:56Z mike $".
+dnl
diff --git a/config-scripts/cups-network.m4 b/config-scripts/cups-network.m4
new file mode 100644
index 000000000..9b591ed12
--- /dev/null
+++ b/config-scripts/cups-network.m4
@@ -0,0 +1,74 @@
+dnl
+dnl "$Id: cups-network.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
+dnl Networking stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+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 Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+AC_CHECK_HEADER(resolv.h,AC_DEFINE(HAVE_RESOLV_H))
+AC_SEARCH_LIBS(socket, socket)
+AC_SEARCH_LIBS(gethostbyaddr, nsl)
+AC_SEARCH_LIBS(getifaddrs, nsl, AC_DEFINE(HAVE_GETIFADDRS))
+AC_SEARCH_LIBS(hstrerror, nsl socket resolv, AC_DEFINE(HAVE_HSTRERROR))
+AC_SEARCH_LIBS(rresvport_af, nsl, AC_DEFINE(HAVE_RRESVPORT_AF))
+AC_SEARCH_LIBS(__res_init, resolv bind, AC_DEFINE(HAVE_RES_INIT),
+ AC_SEARCH_LIBS(res_9_init, resolv bind, AC_DEFINE(HAVE_RES_INIT),
+ AC_SEARCH_LIBS(res_init, resolv bind, AC_DEFINE(HAVE_RES_INIT))))
+
+# Tru64 5.1b leaks file descriptors with these functions; disable until
+# we can come up with a test for this...
+if test "$uname" != "OSF1"; then
+ AC_SEARCH_LIBS(getaddrinfo, nsl, AC_DEFINE(HAVE_GETADDRINFO))
+ AC_SEARCH_LIBS(getnameinfo, nsl, AC_DEFINE(HAVE_GETNAMEINFO))
+fi
+
+AC_CHECK_MEMBER(struct sockaddr.sa_len,,, [#include <sys/socket.h>])
+AC_CHECK_HEADER(sys/sockio.h, AC_DEFINE(HAVE_SYS_SOCKIO_H))
+
+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)
+
+AC_CHECK_HEADERS(AppleTalk/at_proto.h,AC_DEFINE(HAVE_APPLETALK_AT_PROTO_H),,
+ [#include <netat/appletalk.h>])
+
+dnl
+dnl End of "$Id: cups-network.m4 9771 2011-05-12 05:21:56Z mike $".
+dnl
diff --git a/config-scripts/cups-opsys.m4 b/config-scripts/cups-opsys.m4
new file mode 100644
index 000000000..0effd6284
--- /dev/null
+++ b/config-scripts/cups-opsys.m4
@@ -0,0 +1,35 @@
+dnl
+dnl "$Id: cups-opsys.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
+dnl Operating system stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+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 Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+dnl Get the operating system, version number, and architecture...
+uname=`uname`
+uversion=`uname -r | sed -e '1,$s/^[[^0-9]]*\([[0-9]]*\)\.\([[0-9]]*\).*/\1\2/'`
+uarch=`uname -m`
+
+case "$uname" in
+ GNU* | GNU/*)
+ uname="GNU"
+ ;;
+ IRIX*)
+ uname="IRIX"
+ ;;
+ Linux*)
+ uname="Linux"
+ ;;
+esac
+
+dnl
+dnl "$Id: cups-opsys.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
diff --git a/config-scripts/cups-pam.m4 b/config-scripts/cups-pam.m4
new file mode 100644
index 000000000..9a770bfcd
--- /dev/null
+++ b/config-scripts/cups-pam.m4
@@ -0,0 +1,102 @@
+dnl
+dnl "$Id: cups-pam.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
+dnl PAM stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+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 Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+AC_ARG_ENABLE(pam, [ --disable-pam disable PAM support])
+AC_ARG_WITH(pam_module, [ --with-pam-module specify the PAM module to use])
+
+dnl Don't use PAM with AIX...
+if test $uname = AIX; then
+ enable_pam=no
+fi
+
+PAMDIR=""
+PAMFILE="pam.std"
+PAMLIBS=""
+PAMMOD="pam_unknown.so"
+PAMMODAUTH="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_LIB(pam,pam_set_item,AC_DEFINE(HAVE_PAM_SET_ITEM))
+ AC_CHECK_LIB(pam,pam_setcred,AC_DEFINE(HAVE_PAM_SETCRED))
+ 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/Mac OS X
+ if test "x$with_pam_module" != x; then
+ PAMFILE="pam.$with_pam_module"
+ elif test -f /usr/lib/pam/pam_opendirectory.so.2; then
+ PAMFILE="pam.opendirectory"
+ else
+ PAMFILE="pam.securityserver"
+ fi
+ ;;
+
+ *)
+ # All others; this test might need to be updated
+ # as Linux distributors move things around...
+ if test "x$with_pam_module" != x; then
+ PAMMOD="pam_${with_pam_module}.so"
+ elif test -f /lib/security/pam_unix2.so; then
+ PAMMOD="pam_unix2.so"
+ elif test -f /lib/security/pam_unix.so; then
+ PAMMOD="pam_unix.so"
+ fi
+
+ if test "x$PAMMOD" = xpam_unix.so; then
+ PAMMODAUTH="$PAMMOD shadow nodelay"
+ else
+ PAMMODAUTH="$PAMMOD nodelay"
+ fi
+ ;;
+ esac
+fi
+
+AC_SUBST(PAMDIR)
+AC_SUBST(PAMFILE)
+AC_SUBST(PAMLIBS)
+AC_SUBST(PAMMOD)
+AC_SUBST(PAMMODAUTH)
+
+dnl
+dnl End of "$Id: cups-pam.m4 9771 2011-05-12 05:21:56Z mike $".
+dnl
diff --git a/config-scripts/cups-pdf.m4 b/config-scripts/cups-pdf.m4
new file mode 100644
index 000000000..5743f7998
--- /dev/null
+++ b/config-scripts/cups-pdf.m4
@@ -0,0 +1,113 @@
+dnl
+dnl "$Id: cups-pdf.m4 9750 2011-05-06 22:53:53Z mike $"
+dnl
+dnl PDF filter configuration stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+dnl Copyright 2006 by Easy Software Products, all rights reserved.
+dnl
+dnl These coded instructions, statements, and computer programs are the
+dnl property of Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+AC_ARG_WITH(pdftops, [ --with-pdftops set pdftops filter (gs,/path/to/gs,pdftops,/path/to/pdftops,none), default=pdftops ])
+
+PDFTOPS=""
+CUPS_PDFTOPS=""
+CUPS_GHOSTSCRIPT=""
+
+case "x$with_pdftops" in
+ x) # Default/auto
+ if test $uname != Darwin; then
+ AC_PATH_PROG(CUPS_PDFTOPS, pdftops)
+ if test "x$CUPS_PDFTOPS" != x; then
+ AC_DEFINE(HAVE_PDFTOPS)
+ PDFTOPS="pdftops"
+ else
+ AC_PATH_PROG(CUPS_GHOSTSCRIPT, gs)
+ if test "x$CUPS_GHOSTSCRIPT" != x; then
+ AC_DEFINE(HAVE_GHOSTSCRIPT)
+ PDFTOPS="pdftops"
+ fi
+ fi
+ fi
+ ;;
+
+ xgs)
+ AC_PATH_PROG(CUPS_GHOSTSCRIPT, gs)
+ if test "x$CUPS_GHOSTSCRIPT" != x; then
+ AC_DEFINE(HAVE_GHOSTSCRIPT)
+ PDFTOPS="pdftops"
+ else
+ AC_MSG_ERROR(Unable to find gs program!)
+ exit 1
+ fi
+ ;;
+
+ x/*/gs) # Use /path/to/gs without any check:
+ CUPS_GHOSTSCRIPT="$with_pdftops"
+ AC_DEFINE(HAVE_GHOSTSCRIPT)
+ PDFTOPS="pdftops"
+ ;;
+
+ xpdftops)
+ AC_PATH_PROG(CUPS_PDFTOPS, pdftops)
+ if test "x$CUPS_PDFTOPS" != x; then
+ AC_DEFINE(HAVE_PDFTOPS)
+ PDFTOPS="pdftops"
+ else
+ AC_MSG_ERROR(Unable to find pdftops program!)
+ exit 1
+ fi
+ ;;
+
+ x/*/pdftops) # Use /path/to/pdftops without any check:
+ CUPS_PDFTOPS="$with_pdftops"
+ AC_DEFINE(HAVE_PDFTOPS)
+ PDFTOPS="pdftops"
+ ;;
+
+ xnone) # Make no pdftops filter if with_pdftops=none:
+ ;;
+
+ *) # Invalid with_pdftops value:
+ AC_MSG_ERROR(Invalid with_pdftops value!)
+ exit 1
+ ;;
+esac
+
+if test "x$CUPS_PDFTOPS" != x; then
+ AC_MSG_CHECKING(whether pdftops supports -origpagesizes)
+ if ($CUPS_PDFTOPS -h 2>&1 | grep -q -- -origpagesizes); then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_PDFTOPS_WITH_ORIGPAGESIZES)
+ else
+ AC_MSG_RESULT(no)
+ fi
+
+ DEFAULT_PDFTOPS=""
+elif test "x$CUPS_GHOSTSCRIPT" != x; then
+ AC_MSG_CHECKING(whether gs supports the ps2write device)
+ if ($CUPS_GHOSTSCRIPT -h 2>&1 | grep -q ps2write); then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_GHOSTSCRIPT_PS2WRITE)
+ else
+ AC_MSG_RESULT(no)
+ fi
+
+ DEFAULT_PDFTOPS=""
+else
+ DEFAULT_PDFTOPS="#"
+fi
+
+AC_DEFINE_UNQUOTED(CUPS_PDFTOPS, "$CUPS_PDFTOPS")
+AC_DEFINE_UNQUOTED(CUPS_GHOSTSCRIPT, "$CUPS_GHOSTSCRIPT")
+AC_SUBST(DEFAULT_PDFTOPS)
+AC_SUBST(PDFTOPS)
+
+dnl
+dnl End of "$Id: cups-pdf.m4 9750 2011-05-06 22:53:53Z mike $".
+dnl
diff --git a/config-scripts/cups-poll.m4 b/config-scripts/cups-poll.m4
new file mode 100644
index 000000000..46d1af5b4
--- /dev/null
+++ b/config-scripts/cups-poll.m4
@@ -0,0 +1,22 @@
+dnl
+dnl "$Id: cups-poll.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
+dnl Select/poll stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+dnl Copyright 2006 by Easy Software Products, all rights reserved.
+dnl
+dnl These coded instructions, statements, and computer programs are the
+dnl property of Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+AC_CHECK_FUNC(poll, AC_DEFINE(HAVE_POLL))
+AC_CHECK_FUNC(epoll_create, AC_DEFINE(HAVE_EPOLL))
+AC_CHECK_FUNC(kqueue, AC_DEFINE(HAVE_KQUEUE))
+
+dnl
+dnl End of "$Id: cups-poll.m4 9771 2011-05-12 05:21:56Z mike $".
+dnl
diff --git a/config-scripts/cups-scripting.m4 b/config-scripts/cups-scripting.m4
new file mode 100644
index 000000000..cfbde74d6
--- /dev/null
+++ b/config-scripts/cups-scripting.m4
@@ -0,0 +1,100 @@
+dnl
+dnl "$Id: cups-scripting.m4 9099 2010-04-11 07:16:05Z mike $"
+dnl
+dnl Scripting configuration stuff for CUPS.
+dnl
+dnl Copyright 2007-2010 by Apple Inc.
+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 Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "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(PHPCGI,php-cgi)
+ if test "x$PHPCGI" = x; then
+ AC_PATH_PROG(PHP,php)
+ CUPS_PHP="$PHP"
+ else
+ CUPS_PHP="$PHPCGI"
+ fi
+fi
+
+AC_DEFINE_UNQUOTED(CUPS_PHP, "$CUPS_PHP")
+
+if test "x$CUPS_PHP" = x; then
+ CUPS_PHP="no"
+else
+ AC_DEFINE(HAVE_PHP)
+fi
+
+PHPDIR=""
+if test "x$CUPS_PHP" != xno; then
+ AC_PATH_PROG(PHPCONFIG, php-config)
+
+ if test "x$PHPCONFIG" != x; then
+ PHPDIR="scripting/php"
+ fi
+fi
+
+AC_SUBST(PHPDIR)
+
+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 9099 2010-04-11 07:16:05Z mike $".
+dnl
diff --git a/config-scripts/cups-sharedlibs.m4 b/config-scripts/cups-sharedlibs.m4
new file mode 100644
index 000000000..75b3e8d14
--- /dev/null
+++ b/config-scripts/cups-sharedlibs.m4
@@ -0,0 +1,270 @@
+dnl
+dnl "$Id: cups-sharedlibs.m4 9153 2010-06-16 00:48:25Z mike $"
+dnl
+dnl Shared library support for CUPS.
+dnl
+dnl Copyright 2007-2010 by Apple Inc.
+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 Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+PICFLAG=1
+DSOFLAGS="${DSOFLAGS:=}"
+
+AC_ARG_ENABLE(shared, [ --disable-shared do not create shared libraries])
+
+cupsbase="cups"
+LIBCUPSBASE="lib$cupsbase"
+LIBCUPSSTATIC="lib$cupsbase.a"
+
+if test x$enable_shared != xno; then
+ case "$uname" in
+ SunOS*)
+ LIBCUPS="lib$cupsbase.so.2"
+ LIBCUPSCGI="libcupscgi.so.1"
+ LIBCUPSDRIVER="libcupsdriver.so.1"
+ LIBCUPSIMAGE="libcupsimage.so.2"
+ LIBCUPSMIME="libcupsmime.so.1"
+ LIBCUPSPPDC="libcupsppdc.so.1"
+ DSO="\$(CC)"
+ DSOXX="\$(CXX)"
+ DSOFLAGS="$DSOFLAGS -Wl,-h\`basename \$@\` -G \$(OPTIM)"
+ ;;
+ UNIX_S*)
+ LIBCUPS="lib$cupsbase.so.2"
+ LIBCUPSCGI="libcupscgi.so.1"
+ LIBCUPSDRIVER="libcupsdriver.so.1"
+ LIBCUPSIMAGE="libcupsimage.so.2"
+ LIBCUPSMIME="libcupsmime.so.1"
+ LIBCUPSPPDC="libcupsppdc.so.1"
+ DSO="\$(CC)"
+ DSOXX="\$(CXX)"
+ DSOFLAGS="$DSOFLAGS -Wl,-h,\`basename \$@\` -G \$(OPTIM)"
+ ;;
+ HP-UX*)
+ case "$uarch" in
+ ia64)
+ LIBCUPS="lib$cupsbase.so.2"
+ LIBCUPSCGI="libcupscgi.so.1"
+ LIBCUPSDRIVER="libcupsdriver.so.1"
+ LIBCUPSIMAGE="libcupsimage.so.2"
+ LIBCUPSMIME="libcupsmime.so.1"
+ LIBCUPSPPDC="libcupsppdc.so.1"
+ DSO="\$(CC)"
+ DSOXX="\$(CXX)"
+ DSOFLAGS="$DSOFLAGS -Wl,-b,-z,+h,\`basename \$@\`"
+ ;;
+ *)
+ LIBCUPS="lib$cupsbase.sl.2"
+ LIBCUPSCGI="libcupscgi.sl.1"
+ LIBCUPSDRIVER="libcupsdriver.sl.1"
+ LIBCUPSIMAGE="libcupsimage.sl.2"
+ LIBCUPSMIME="libcupsmime.sl.1"
+ LIBCUPSPPDC="libcupsppdc.sl.1"
+ DSO="\$(LD)"
+ DSOXX="\$(LD)"
+ DSOFLAGS="$DSOFLAGS -b -z +h \`basename \$@\`"
+ ;;
+ esac
+ ;;
+ IRIX)
+ LIBCUPS="lib$cupsbase.so.2"
+ LIBCUPSCGI="libcupscgi.so.1"
+ LIBCUPSDRIVER="libcupsdriver.so.1"
+ LIBCUPSIMAGE="libcupsimage.so.2"
+ LIBCUPSMIME="libcupsmime.so.1"
+ LIBCUPSPPDC="libcupsppdc.so.1"
+ DSO="\$(CC)"
+ DSOXX="\$(CXX)"
+ DSOFLAGS="$DSOFLAGS -set_version,sgi2.6,-soname,\`basename \$@\` -shared \$(OPTIM)"
+ ;;
+ OSF1* | Linux | GNU | *BSD*)
+ LIBCUPS="lib$cupsbase.so.2"
+ LIBCUPSCGI="libcupscgi.so.1"
+ LIBCUPSDRIVER="libcupsdriver.so.1"
+ LIBCUPSIMAGE="libcupsimage.so.2"
+ LIBCUPSMIME="libcupsmime.so.1"
+ LIBCUPSPPDC="libcupsppdc.so.1"
+ DSO="\$(CC)"
+ DSOXX="\$(CXX)"
+ DSOFLAGS="$DSOFLAGS -Wl,-soname,\`basename \$@\` -shared \$(OPTIM)"
+ ;;
+ Darwin*)
+ LIBCUPS="lib$cupsbase.2.dylib"
+ LIBCUPSCGI="libcupscgi.1.dylib"
+ LIBCUPSDRIVER="libcupsdriver.1.dylib"
+ LIBCUPSIMAGE="libcupsimage.2.dylib"
+ LIBCUPSMIME="libcupsmime.1.dylib"
+ LIBCUPSPPDC="libcupsppdc.1.dylib"
+ DSO="\$(CC)"
+ DSOXX="\$(CXX)"
+ DSOFLAGS="$DSOFLAGS -dynamiclib -single_module -lc"
+ ;;
+ AIX*)
+ LIBCUPS="lib${cupsbase}_s.a"
+ LIBCUPSBASE="${cupsbase}_s"
+ LIBCUPSCGI="libcupscgi_s.a"
+ LIBCUPSDRIVER="libcupsdriver_s.a"
+ LIBCUPSIMAGE="libcupsimage_s.a"
+ LIBCUPSMIME="libcupsmime_s.a"
+ LIBCUPSPPDC="libcupsppdc_s.a"
+ DSO="\$(CC)"
+ DSOXX="\$(CXX)"
+ DSOFLAGS="$DSOFLAGS -Wl,-bexpall,-bM:SRE,-bnoentry,-blibpath:\$(libdir)"
+ ;;
+ *)
+ echo "Warning: shared libraries may not be supported. Trying -shared"
+ echo " option with compiler."
+ LIBCUPS="lib$cupsbase.so.2"
+ LIBCUPSCGI="libcupscgi.so.1"
+ LIBCUPSDRIVER="libcupsdriver.so.1"
+ LIBCUPSIMAGE="libcupsimage.so.2"
+ LIBCUPSMIME="libcupsmime.so.1"
+ LIBCUPSPPDC="libcupsppdc.so.1"
+ DSO="\$(CC)"
+ DSOXX="\$(CXX)"
+ DSOFLAGS="$DSOFLAGS -Wl,-soname,\`basename \$@\` -shared \$(OPTIM)"
+ ;;
+ esac
+else
+ PICFLAG=0
+ LIBCUPS="lib$cupsbase.a"
+ LIBCUPSCGI="libcupscgi.a"
+ LIBCUPSDRIVER="libcupsdriver.a"
+ LIBCUPSIMAGE="libcupsimage.a"
+ LIBCUPSMIME="libcupsmime.a"
+ LIBCUPSPPDC="libcupsppdc.a"
+ DSO=":"
+ DSOXX=":"
+fi
+
+# 32-bit and 64-bit libraries need variations of the standard
+# DSOFLAGS...
+DSO32FLAGS="$DSOFLAGS"
+DSO64FLAGS="$DSOFLAGS"
+
+AC_SUBST(DSO)
+AC_SUBST(DSOXX)
+AC_SUBST(DSOFLAGS)
+AC_SUBST(DSO32FLAGS)
+AC_SUBST(DSO64FLAGS)
+AC_SUBST(LIBCUPS)
+AC_SUBST(LIBCUPSBASE)
+AC_SUBST(LIBCUPSCGI)
+AC_SUBST(LIBCUPSDRIVER)
+AC_SUBST(LIBCUPSIMAGE)
+AC_SUBST(LIBCUPSMIME)
+AC_SUBST(LIBCUPSPPDC)
+AC_SUBST(LIBCUPSSTATIC)
+
+if test x$enable_shared = xno; then
+ LINKCUPS="../cups/lib$cupsbase.a"
+ LINKCUPSIMAGE="../filter/libcupsimage.a"
+
+ EXTLINKCUPS="-lcups"
+ EXTLINKCUPSDRIVER="-lcupsdriver"
+ EXTLINKCUPSIMAGE="-lcupsimage"
+else
+ if test $uname = AIX; then
+ LINKCUPS="-l${cupsbase}_s"
+ LINKCUPSIMAGE="-lcupsimage_s"
+
+ EXTLINKCUPS="-lcups_s"
+ EXTLINKCUPSDRIVER="-lcupsdriver_s"
+ EXTLINKCUPSIMAGE="-lcupsimage_s"
+ else
+ LINKCUPS="-l${cupsbase}"
+ LINKCUPSIMAGE="-lcupsimage"
+
+ EXTLINKCUPS="-lcups"
+ EXTLINKCUPSDRIVER="-lcupsdriver"
+ EXTLINKCUPSIMAGE="-lcupsimage"
+ fi
+fi
+
+AC_SUBST(EXTLINKCUPS)
+AC_SUBST(EXTLINKCUPSDRIVER)
+AC_SUBST(EXTLINKCUPSIMAGE)
+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="\$(LIBTIFF) \$(LIBPNG) \$(LIBJPEG) \$(LIBZ)"
+ IMGLIBS=""
+
+ # Tell the run-time linkers where to find a DSO. Some platforms
+ # need this option, even when the library is installed in a
+ # standard location...
+ case $uname in
+ HP-UX*)
+ # HP-UX needs the path, even for /usr/lib...
+ case "$uarch" in
+ ia64)
+ DSOFLAGS="-Wl,+s,+b,$libdir $DSOFLAGS"
+ DSO32FLAGS="-Wl,+s,+b,$LIB32DIR $DSO32FLAGS"
+ DSO64FLAGS="-Wl,+s,+b,$LIB64DIR $DSO64FLAGS"
+ ;;
+ *)
+ DSOFLAGS="+s +b $libdir $DSOFLAGS"
+ DSO32FLAGS="+s +b $LIB32DIR $DSO32FLAGS"
+ DSO64FLAGS="+s +b $LIB64DIR $DSO64FLAGS"
+ ;;
+ esac
+ LDFLAGS="$LDFLAGS -Wl,+s,+b,$libdir"
+ EXPORT_LDFLAGS="-Wl,+s,+b,$libdir"
+ ;;
+ SunOS*)
+ # Solaris...
+ if test $exec_prefix != /usr; then
+ DSOFLAGS="-R$libdir $DSOFLAGS"
+ DSO32FLAGS="-R$LIB32DIR $DSO32FLAGS"
+ DSO64FLAGS="-R$LIB64DIR $DSO64FLAGS"
+ LDFLAGS="$LDFLAGS -R$libdir"
+ EXPORT_LDFLAGS="-R$libdir"
+ fi
+ ;;
+ *BSD*)
+ # *BSD...
+ if test $exec_prefix != /usr; then
+ DSOFLAGS="-Wl,-R$libdir $DSOFLAGS"
+ DSO32FLAGS="-Wl,-R$LIB32DIR $DSO32FLAGS"
+ DSO64FLAGS="-Wl,-R$LIB64DIR $DSO64FLAGS"
+ LDFLAGS="$LDFLAGS -Wl,-R$libdir"
+ EXPORT_LDFLAGS="-Wl,-R$libdir"
+ fi
+ ;;
+ IRIX | Linux | GNU)
+ # IRIX, Linux, and HURD...
+ if test $exec_prefix != /usr; then
+ DSOFLAGS="-Wl,-rpath,$libdir $DSOFLAGS"
+ DSO32FLAGS="-Wl,-rpath,$LIB32DIR $DSO32FLAGS"
+ DSO64FLAGS="-Wl,-rpath,$LIB64DIR $DSO64FLAGS"
+ LDFLAGS="$LDFLAGS -Wl,-rpath,$libdir"
+ EXPORT_LDFLAGS="-Wl,-rpath,$libdir"
+ fi
+ ;;
+ esac
+else
+ DSOLIBS=""
+ IMGLIBS="\$(LIBTIFF) \$(LIBPNG) \$(LIBJPEG) \$(LIBZ)"
+fi
+
+AC_SUBST(DSOLIBS)
+AC_SUBST(IMGLIBS)
+AC_SUBST(EXPORT_LDFLAGS)
+
+dnl
+dnl End of "$Id: cups-sharedlibs.m4 9153 2010-06-16 00:48:25Z mike $".
+dnl
diff --git a/config-scripts/cups-slp.m4 b/config-scripts/cups-slp.m4
new file mode 100644
index 000000000..c68162459
--- /dev/null
+++ b/config-scripts/cups-slp.m4
@@ -0,0 +1,38 @@
+dnl
+dnl "$Id: cups-slp.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
+dnl OpenSLP configuration stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+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 Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+AC_ARG_ENABLE(slp, [ --disable-slp disable SLP support])
+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"
+ 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-slp.m4 9771 2011-05-12 05:21:56Z mike $".
+dnl
diff --git a/config-scripts/cups-ssl.m4 b/config-scripts/cups-ssl.m4
new file mode 100644
index 000000000..76cac80ad
--- /dev/null
+++ b/config-scripts/cups-ssl.m4
@@ -0,0 +1,173 @@
+dnl
+dnl "$Id: cups-ssl.m4 9756 2011-05-11 00:52:08Z mike $"
+dnl
+dnl OpenSSL/GNUTLS stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+dnl Copyright 1997-2007 by Easy Software Products, all rights reserved.
+dnl
+dnl These coded instructions, statements, and computer programs are the
+dnl property of Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+AC_ARG_ENABLE(ssl, [ --disable-ssl disable SSL/TLS support])
+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"
+ CPPFLAGS="-I$withval $CPPFLAGS",)
+
+SSLFLAGS=""
+SSLLIBS=""
+have_ssl=0
+
+if test x$enable_ssl != xno; then
+ dnl Look for CDSA...
+ if test $have_ssl = 0 -a "x$enable_cdsassl" != "xno"; then
+ if test $uname = Darwin; then
+ AC_CHECK_HEADER(Security/SecureTransport.h, [
+ have_ssl=1
+ AC_DEFINE(HAVE_SSL)
+ AC_DEFINE(HAVE_CDSASSL)
+
+ dnl Check for the various security headers...
+ AC_CHECK_HEADER(Security/SecureTransportPriv.h,
+ AC_DEFINE(HAVE_SECURETRANSPORTPRIV_H))
+ AC_CHECK_HEADER(Security/SecCertificate.h,
+ AC_DEFINE(HAVE_SECCERTIFICATE_H))
+ AC_CHECK_HEADER(Security/SecItem.h,
+ AC_DEFINE(HAVE_SECITEM_H))
+ AC_CHECK_HEADER(Security/SecItemPriv.h,
+ AC_DEFINE(HAVE_SECITEMPRIV_H),,
+ [#include <Security/SecItem.h>])
+ AC_CHECK_HEADER(Security/SecPolicy.h,
+ AC_DEFINE(HAVE_SECPOLICY_H))
+ AC_CHECK_HEADER(Security/SecPolicyPriv.h,
+ AC_DEFINE(HAVE_SECPOLICYPRIV_H))
+ AC_CHECK_HEADER(Security/SecBasePriv.h,
+ AC_DEFINE(HAVE_SECBASEPRIV_H))
+ AC_CHECK_HEADER(Security/SecIdentitySearchPriv.h,
+ AC_DEFINE(HAVE_SECIDENTITYSEARCHPRIV_H))
+
+ dnl Check for SecCertificateCopyData..
+ AC_MSG_CHECKING(for SecCertificateCopyData)
+ if test $uversion -ge 100; then
+ AC_DEFINE(HAVE_SECCERTIFICATECOPYDATA)
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi
+
+ dnl Check for SecIdentitySearchCreateWithPolicy...
+ AC_MSG_CHECKING(for SecIdentitySearchCreateWithPolicy)
+ if test $uversion -ge 80; then
+ AC_DEFINE(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY)
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi
+
+ dnl Check for SecPolicyCreateSSL...
+ AC_MSG_CHECKING(for SecPolicyCreateSSL)
+ if test $uversion -ge 110; then
+ AC_DEFINE(HAVE_SECPOLICYCREATESSL)
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ fi])
+
+ AC_DEFINE(HAVE_CSSMERRORSTRING)
+ fi
+ fi
+
+ dnl Then look for GNU TLS...
+ if test $have_ssl = 0 -a "x$enable_gnutls" != "xno" -a "x$PKGCONFIG" != x; then
+ AC_PATH_PROG(LIBGNUTLSCONFIG,libgnutls-config)
+ AC_PATH_PROG(LIBGCRYPTCONFIG,libgcrypt-config)
+ if $PKGCONFIG --exists gnutls; then
+ have_ssl=1
+ SSLLIBS=`$PKGCONFIG --libs gnutls`
+ SSLFLAGS=`$PKGCONFIG --cflags gnutls`
+ AC_DEFINE(HAVE_SSL)
+ AC_DEFINE(HAVE_GNUTLS)
+ elif test "x$LIBGNUTLSCONFIG" != x; then
+ have_ssl=1
+ SSLLIBS=`$LIBGNUTLSCONFIG --libs`
+ SSLFLAGS=`$LIBGNUTLSCONFIG --cflags`
+ AC_DEFINE(HAVE_SSL)
+ AC_DEFINE(HAVE_GNUTLS)
+ fi
+
+ if test $have_ssl = 1; then
+ if $PKGCONFIG --exists gcrypt; then
+ SSLLIBS="$SSLLIBS `$PKGCONFIG --libs gcrypt`"
+ SSLFLAGS="$SSLFLAGS `$PKGCONFIG --cflags gcrypt`"
+ elif test "x$LIBGCRYPTCONFIG" != x; then
+ SSLLIBS="$SSLLIBS `$LIBGCRYPTCONFIG --libs`"
+ SSLFLAGS="$SSLFLAGS `$LIBGCRYPTCONFIG --cflags`"
+ fi
+ fi
+ fi
+
+ dnl Check for the OpenSSL library last...
+ if test $have_ssl = 0 -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,
+ [have_ssl=1
+ 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
+
+IPPALIASES="http"
+if test $have_ssl = 1; then
+ AC_MSG_RESULT([ Using SSLLIBS="$SSLLIBS"])
+ AC_MSG_RESULT([ Using SSLFLAGS="$SSLFLAGS"])
+ IPPALIASES="http https ipps"
+elif test x$enable_cdsa = xyes -o x$enable_gnutls = xyes -o x$enable_openssl = xyes; then
+ AC_MSG_ERROR([Unable to enable SSL support.])
+fi
+
+AC_SUBST(IPPALIASES)
+AC_SUBST(SSLFLAGS)
+AC_SUBST(SSLLIBS)
+
+EXPORT_SSLLIBS="$SSLLIBS"
+AC_SUBST(EXPORT_SSLLIBS)
+
+
+dnl
+dnl End of "$Id: cups-ssl.m4 9756 2011-05-11 00:52:08Z mike $".
+dnl
diff --git a/config-scripts/cups-threads.m4 b/config-scripts/cups-threads.m4
new file mode 100644
index 000000000..0743e3416
--- /dev/null
+++ b/config-scripts/cups-threads.m4
@@ -0,0 +1,54 @@
+dnl
+dnl "$Id: cups-threads.m4 9771 2011-05-12 05:21:56Z mike $"
+dnl
+dnl Threading stuff for CUPS.
+dnl
+dnl Copyright 2007-2011 by Apple Inc.
+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 Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "http://www.cups.org/".
+dnl
+
+AC_ARG_ENABLE(threads, [ --disable-threads disable multi-threading support])
+
+have_pthread=no
+PTHREAD_FLAGS=""
+
+if test "x$enable_threads" != xno; then
+ AC_CHECK_HEADER(pthread.h, AC_DEFINE(HAVE_PTHREAD_H))
+
+ if test x$ac_cv_header_pthread_h = xyes; then
+ dnl Check various threading options for the platforms we support
+ for flag in -lpthreads -lpthread -pthread; do
+ AC_MSG_CHECKING([for pthread_create using $flag])
+ SAVELIBS="$LIBS"
+ LIBS="$flag $LIBS"
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_create(0, 0, 0, 0);],
+ have_pthread=yes,
+ LIBS="$SAVELIBS")
+ AC_MSG_RESULT([$have_pthread])
+
+ if test $have_pthread = yes; then
+ PTHREAD_FLAGS="-D_THREAD_SAFE -D_REENTRANT"
+
+ # Solaris requires -D_POSIX_PTHREAD_SEMANTICS to
+ # be POSIX-compliant... :(
+ if test $uname = SunOS; then
+ PTHREAD_FLAGS="$PTHREAD_FLAGS -D_POSIX_PTHREAD_SEMANTICS"
+ fi
+ break
+ fi
+ done
+ fi
+fi
+
+AC_SUBST(PTHREAD_FLAGS)
+
+dnl
+dnl End of "$Id: cups-threads.m4 9771 2011-05-12 05:21:56Z mike $".
+dnl
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 000000000..f04c8f5dd
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,741 @@
+/*
+ * "$Id$"
+ *
+ * Configuration file for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPS_CONFIG_H_
+#define _CUPS_CONFIG_H_
+
+/*
+ * Version of software...
+ */
+
+#define CUPS_SVERSION ""
+#define CUPS_MINIMAL ""
+
+
+/*
+ * Default user and groups...
+ */
+
+#define CUPS_DEFAULT_USER "lp"
+#define CUPS_DEFAULT_GROUP "sys"
+#define CUPS_DEFAULT_SYSTEM_GROUPS "sys root system"
+#define CUPS_DEFAULT_PRINTOPERATOR_AUTH "@SYSTEM"
+
+
+/*
+ * Default file permissions...
+ */
+
+#define CUPS_DEFAULT_CONFIG_FILE_PERM 0640
+#define CUPS_DEFAULT_LOG_FILE_PERM 0644
+
+
+/*
+ * Default logging settings...
+ */
+
+#define CUPS_DEFAULT_LOG_LEVEL "warn"
+#define CUPS_DEFAULT_ACCESS_LOG_LEVEL "actions"
+
+
+/*
+ * Default fatal error settings...
+ */
+
+#define CUPS_DEFAULT_FATAL_ERRORS "config"
+
+
+/*
+ * Default browsing settings...
+ */
+
+#define CUPS_DEFAULT_BROWSING 1
+#define CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS "CUPS"
+#define CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS "CUPS"
+#define CUPS_DEFAULT_BROWSE_SHORT_NAMES 1
+#define CUPS_DEFAULT_DEFAULT_SHARED 1
+#define CUPS_DEFAULT_IMPLICIT_CLASSES 1
+#define CUPS_DEFAULT_USE_NETWORK_DEFAULT 1
+
+
+/*
+ * Default IPP port...
+ */
+
+#define CUPS_DEFAULT_IPP_PORT 631
+
+
+/*
+ * Default printcap file...
+ */
+
+#define CUPS_DEFAULT_PRINTCAP "/etc/printcap"
+
+
+/*
+ * Default Samba and LPD config files...
+ */
+
+#define CUPS_DEFAULT_SMB_CONFIG_FILE ""
+#define CUPS_DEFAULT_LPD_CONFIG_FILE ""
+
+
+/*
+ * Default MaxCopies value...
+ */
+
+#define CUPS_DEFAULT_MAX_COPIES 100
+
+
+/*
+ * Do we have domain socket support, and if so what is the default one?
+ */
+
+#undef CUPS_DEFAULT_DOMAINSOCKET
+
+
+/*
+ * Default WebInterface value...
+ */
+
+#undef CUPS_DEFAULT_WEBIF
+
+
+/*
+ * Where are files stored?
+ *
+ * Note: These are defaults, which can be overridden by environment
+ * variables at run-time...
+ */
+
+#define CUPS_BINDIR "/usr/bin"
+#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_SBINDIR "/usr/sbin"
+#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
+#undef HAVE_PAM_SET_ITEM
+#undef HAVE_PAM_SETCRED
+
+
+/*
+ * Do we have <shadow.h>?
+ */
+
+#undef HAVE_SHADOW_H
+
+
+/*
+ * Do we have <crypt.h>?
+ */
+
+#undef HAVE_CRYPT_H
+
+
+/*
+ * Do we have <scsi/sg.h>?
+ */
+
+#undef HAVE_SCSI_SG_H
+
+
+/*
+ * Use <string.h>, <strings.h>, and/or <bstring.h>?
+ */
+
+#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_STRLCAT
+#undef HAVE_STRLCPY
+
+
+/*
+ * Do we have the geteuid() function?
+ */
+
+#undef HAVE_GETEUID
+
+
+/*
+ * Do we have the setpgid() function?
+ */
+
+#undef HAVE_SETPGID
+
+
+/*
+ * 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 POSIX ACL functions?
+ */
+
+#undef HAVE_ACL_INIT
+
+
+/*
+ * 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
+
+
+/*
+ * What Security framework headers do we have?
+ */
+
+#undef HAVE_AUTHORIZATION_H
+#undef HAVE_SECBASEPRIV_H
+#undef HAVE_SECCERTIFICATE_H
+#undef HAVE_SECIDENTITYSEARCHPRIV_H
+#undef HAVE_SECITEM_H
+#undef HAVE_SECITEMPRIV_H
+#undef HAVE_SECPOLICY_H
+#undef HAVE_SECPOLICYPRIV_H
+#undef HAVE_SECURETRANSPORTPRIV_H
+
+
+/*
+ * Do we have the SecCertificateCopyData function?
+ */
+
+#undef HAVE_SECCERTIFICATECOPYDATA
+
+
+/*
+ * Do we have the SecIdentitySearchCreateWithPolicy function?
+ */
+
+#undef HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY
+
+
+/*
+ * Do we have the SecPolicyCreateSSL function?
+ */
+
+#undef HAVE_SECPOLICYCREATESSL
+
+
+/*
+ * Do we have the SecPolicyCreateSSL function?
+ */
+
+#undef HAVE_SECPOLICYCREATESSL
+
+
+/*
+ * Do we have the cssmErrorString function?
+ */
+
+#undef HAVE_CSSMERRORSTRING
+
+
+/*
+ * Do we have the SLP library?
+ */
+
+#undef HAVE_LIBSLP
+
+
+/*
+ * Do we have an LDAP library?
+ */
+
+#undef HAVE_LDAP
+#undef HAVE_OPENLDAP
+#undef HAVE_MOZILLA_LDAP
+#undef HAVE_LDAP_SSL_H
+#undef HAVE_LDAP_SSL
+#undef HAVE_LDAP_REBIND_PROC
+
+
+/*
+ * Do we have libpaper?
+ */
+
+#undef HAVE_LIBPAPER
+
+
+/*
+ * Do we have DNS Service Discovery (aka Bonjour)?
+ */
+
+#undef HAVE_DNSSD
+
+
+/*
+ * Do we have <sys/ioctl.h>?
+ */
+
+#undef HAVE_SYS_IOCTL_H
+
+
+/*
+ * Does the "stat" structure contain the "st_gen" member?
+ */
+
+#undef HAVE_ST_GEN
+
+
+/*
+ * 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 res_init()?
+ */
+
+#undef HAVE_RES_INIT
+
+
+/*
+ * Do we have <resolv.h>
+ */
+
+#undef HAVE_RESOLV_H
+
+
+/*
+ * Do we have the <sys/sockio.h> 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
+
+
+/*
+ * Do we have launchd support?
+ */
+
+#undef HAVE_LAUNCH_H
+#undef HAVE_LAUNCHD
+
+
+/*
+ * 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"
+
+
+/*
+ * Location of the poppler/Xpdf pdftops program...
+ */
+
+#undef HAVE_PDFTOPS
+#undef HAVE_PDFTOPS_WITH_ORIGPAGESIZES
+#define CUPS_PDFTOPS "/usr/bin/pdftops"
+
+
+/*
+ * Location of the Ghostscript gs program...
+ */
+
+#undef HAVE_GHOSTSCRIPT
+#undef HAVE_GHOSTSCRIPT_PS2WRITE
+#define CUPS_GHOSTSCRIPT "/usr/bin/gs"
+
+
+/*
+ * Do we have Darwin's CoreFoundation and SystemConfiguration frameworks?
+ */
+
+#undef HAVE_COREFOUNDATION
+#undef HAVE_SYSTEMCONFIGURATION
+
+
+/*
+ * Do we have CoreFoundation public and private headers?
+ */
+
+#undef HAVE_COREFOUNDATION_H
+#undef HAVE_CFPRIV_H
+#undef HAVE_CFBUNDLEPRIV_H
+
+
+/*
+ * Do we have ApplicationServices public headers?
+ */
+
+#undef HAVE_APPLICATIONSERVICES_H
+
+
+/*
+ * Do we have the SCDynamicStoreCopyComputerName function?
+ */
+
+#undef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME
+
+
+/*
+ * Do we have Mac OS X 10.4's mbr_XXX functions?
+ */
+
+#undef HAVE_MEMBERSHIP_H
+#undef HAVE_MEMBERSHIPPRIV_H
+#undef HAVE_MBR_UID_TO_UUID
+
+
+/*
+ * Do we have Darwin's notify_post header and function?
+ */
+
+#undef HAVE_NOTIFY_H
+#undef HAVE_NOTIFY_POST
+
+
+/*
+ * Do we have Darwin's IOKit private headers?
+ */
+
+#undef HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H
+
+
+/*
+ * Do we have DBUS?
+ */
+
+#undef HAVE_DBUS
+#undef HAVE_DBUS_MESSAGE_ITER_INIT_APPEND
+
+
+/*
+ * Do we have the GSSAPI support library (for Kerberos support)?
+ */
+
+#undef HAVE_GSS_ACQUIRE_CRED_EX_F
+#undef HAVE_GSS_C_NT_HOSTBASED_SERVICE
+#undef HAVE_GSS_GSSAPI_H
+#undef HAVE_GSS_GSSAPI_SPI_H
+#undef HAVE_GSSAPI
+#undef HAVE_GSSAPI_GENERIC_H
+#undef HAVE_GSSAPI_GSSAPI_H
+#undef HAVE_GSSAPI_H
+#undef HAVE_GSSAPI_KRB5_H
+#undef HAVE_KRB5_H
+
+
+/*
+ * Default GSS service name...
+ */
+
+#define CUPS_DEFAULT_GSSSERVICENAME ""
+
+
+/*
+ * Select/poll interfaces...
+ */
+
+#undef HAVE_POLL
+#undef HAVE_EPOLL
+#undef HAVE_KQUEUE
+
+
+/*
+ * Do we have the <dlfcn.h> header?
+ */
+
+#undef HAVE_DLFCN_H
+
+
+/*
+ * Do we have <sys/param.h>?
+ */
+
+#undef HAVE_SYS_PARAM_H
+
+
+/*
+ * Do we have <sys/ucred.h>?
+ */
+
+#undef HAVE_SYS_UCRED_H
+
+
+/*
+ * Do we have removefile()?
+ */
+
+#undef HAVE_REMOVEFILE
+
+
+/*
+ * Do we have <sandbox.h>?
+ */
+
+#undef HAVE_SANDBOX_H
+
+
+/*
+ * Which random number generator function to use...
+ */
+
+#undef HAVE_ARC4RANDOM
+#undef HAVE_RANDOM
+#undef HAVE_LRAND48
+
+#ifdef HAVE_ARC4RANDOM
+# define CUPS_RAND() arc4random()
+# define CUPS_SRAND(v) arc4random_stir()
+#elif defined(HAVE_RANDOM)
+# define CUPS_RAND() random()
+# define CUPS_SRAND(v) srandom(v)
+#elif defined(HAVE_LRAND48)
+# define CUPS_RAND() lrand48()
+# define CUPS_SRAND(v) srand48(v)
+#else
+# define CUPS_RAND() rand()
+# define CUPS_SRAND(v) srand(v)
+#endif /* HAVE_ARC4RANDOM */
+
+
+/*
+ * Do we have vproc_transaction_begin/end?
+ */
+
+#undef HAVE_VPROC_TRANSACTION_BEGIN
+
+
+/*
+ * Do we have libusb?
+ */
+
+#undef HAVE_USB_H
+
+
+/*
+ * Do we have libwrap and tcpd.h?
+ */
+
+#undef HAVE_TCPD_H
+
+
+/*
+ * Do we have <iconv.h>?
+ */
+
+#undef HAVE_ICONV_H
+
+
+/*
+ * Do we have statfs or statvfs and one of the corresponding headers?
+ */
+
+#undef HAVE_STATFS
+#undef HAVE_STATVFS
+#undef HAVE_SYS_MOUNT_H
+#undef HAVE_SYS_STATFS_H
+#undef HAVE_SYS_STATVFS_H
+#undef HAVE_SYS_VFS_H
+
+
+/*
+ * Location of Mac OS X localization bundle, if any.
+ */
+
+#undef CUPS_BUNDLEDIR
+
+
+/*
+ * Do we have the ColorSyncRegisterDevice function?
+ */
+
+#undef HAVE_COLORSYNCREGISTERDEVICE
+
+
+/*
+ * Do we have XPC?
+ */
+
+#undef HAVE_XPC
+
+
+#endif /* !_CUPS_CONFIG_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/configure.in b/configure.in
new file mode 100644
index 000000000..560f4f8e3
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,98 @@
+dnl
+dnl "$Id$"
+dnl
+dnl Configuration script for CUPS.
+dnl
+dnl Copyright 2007-2010 by Apple Inc.
+dnl Copyright 1997-2007 by Easy Software Products, all rights reserved.
+dnl
+dnl These coded instructions, statements, and computer programs are the
+dnl property of Apple Inc. and are protected by Federal copyright
+dnl law. Distribution and use rights are outlined in the file "LICENSE.txt"
+dnl which should have been included with this file. If this file is
+dnl file is missing or damaged, see the license at "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-3264.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-poll.m4)
+sinclude(config-scripts/cups-slp.m4)
+sinclude(config-scripts/cups-gssapi.m4)
+sinclude(config-scripts/cups-ldap.m4)
+sinclude(config-scripts/cups-threads.m4)
+sinclude(config-scripts/cups-ssl.m4)
+sinclude(config-scripts/cups-pam.m4)
+sinclude(config-scripts/cups-largefile.m4)
+sinclude(config-scripts/cups-dnssd.m4)
+sinclude(config-scripts/cups-launchd.m4)
+sinclude(config-scripts/cups-defaults.m4)
+sinclude(config-scripts/cups-pdf.m4)
+sinclude(config-scripts/cups-scripting.m4)
+
+INSTALL_LANGUAGES=""
+UNINSTALL_LANGUAGES=""
+LANGFILES=""
+if test "x$LANGUAGES" != x; then
+ INSTALL_LANGUAGES="install-languages"
+ UNINSTALL_LANGUAGES="uninstall-languages"
+ for lang in $LANGUAGES; do
+ if test -f doc/$lang/index.html.in; then
+ LANGFILES="$LANGFILES doc/$lang/index.html"
+ fi
+
+ if test -f templates/$lang/header.tmpl.in; then
+ LANGFILES="$LANGFILES templates/$lang/header.tmpl"
+ fi
+ done
+elif test "x$CUPS_BUNDLEDIR" != ""; then
+ INSTALL_LANGUAGES="install-langbundle"
+ UNINSTALL_LANGUAGES="uninstall-langbundle"
+fi
+
+AC_SUBST(INSTALL_LANGUAGES)
+AC_SUBST(UNINSTALL_LANGUAGES)
+
+AC_OUTPUT(Makedefs
+ conf/cupsd.conf
+ conf/mime.convs
+ conf/pam.std
+ conf/snmp.conf
+ cups-config
+ data/testprint
+ desktop/cups.desktop
+ doc/help/ref-cupsd-conf.html
+ doc/help/standard.html
+ doc/index.html
+ man/client.conf.man
+ man/cups-deviced.man
+ man/cups-driverd.man
+ man/cups-lpd.man
+ man/cupsaddsmb.man
+ man/cupsd.conf.man
+ man/cupsd.man
+ man/lpoptions.man
+ scheduler/cups-lpd.xinetd
+ scheduler/cups.sh
+ scheduler/cups.xml
+ scheduler/org.cups.cups-lpd.plist
+ templates/header.tmpl
+ packaging/cups.list
+ $LANGFILES)
+
+chmod +x cups-config
+
+dnl
+dnl End of "$Id$".
+dnl
diff --git a/cups-config.in b/cups-config.in
new file mode 100755
index 000000000..edeb9ef6a
--- /dev/null
+++ b/cups-config.in
@@ -0,0 +1,160 @@
+#! /bin/sh
+#
+# "$Id$"
+#
+# CUPS configuration utility.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 2001-2006 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+VERSION="@CUPS_VERSION@"
+APIVERSION="1.5"
+BUILD="@CUPS_BUILD@"
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+includedir=@includedir@
+libdir=@libdir@
+imagelibdir=@libdir@
+datarootdir=@datadir@
+datadir=@datadir@
+sysconfdir=@sysconfdir@
+cups_datadir=@CUPS_DATADIR@
+cups_serverbin=@CUPS_SERVERBIN@
+cups_serverroot=@CUPS_SERVERROOT@
+INSTALLSTATIC=@INSTALLSTATIC@
+
+# flags for C++ compiler:
+CFLAGS=""
+LDFLAGS="@EXPORT_LDFLAGS@"
+LIBS="@LIBGSSAPI@ @EXPORT_SSLLIBS@ @EXPORT_LIBZ@ @LIBS@"
+IMGLIBS="@EXPORT_LIBTIFF@ @EXPORT_LIBJPEG@ @EXPORT_LIBPNG@"
+
+# Check for local invocation...
+selfdir=`dirname $0`
+
+if test -f "$selfdir/cups/cups.h"; then
+ CFLAGS="-I$selfdir"
+ LDFLAGS="-L$selfdir/cups -L$selfdir/filter $LDFLAGS"
+ libdir="$selfdir/cups"
+ imagelibdir="$selfdir/filter"
+ if test ! -f "$selfdir/cups/raster.h"; then
+ ln -s ../filter/raster.h "$selfdir/cups"
+ fi
+else
+ if test $includedir != /usr/include; then
+ CFLAGS="$CFLAGS -I$includedir"
+ fi
+
+ if test $libdir != /usr/lib -a $libdir != /usr/lib32 -a $libdir != /usr/lib64; then
+ LDFLAGS="$LDFLAGS -L$libdir"
+ fi
+fi
+
+
+usage ()
+{
+ echo "Usage: cups-config --api-version"
+ echo " cups-config --build"
+ echo " cups-config --cflags"
+ echo " cups-config --datadir"
+ echo " cups-config --help"
+ echo " cups-config --ldflags"
+ echo " cups-config [--driver] [--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
+driver=no
+
+while test $# -gt 0; do
+ case $1 in
+ --api-version)
+ echo $APIVERSION
+ ;;
+ --build)
+ echo $BUILD
+ ;;
+ --cflags)
+ echo $CFLAGS
+ ;;
+ --datadir)
+ echo $cups_datadir
+ ;;
+ --driver)
+ driver=yes
+ ;;
+ --help)
+ usage 0
+ ;;
+ --image)
+ image=yes
+ ;;
+ --ldflags)
+ echo $LDFLAGS
+ ;;
+ --libs)
+ if test $static = no; then
+ libs="@EXTLINKCUPS@ $LIBS";
+ if test $image = yes; then
+ libs="@EXTLINKCUPSIMAGE@ $libs"
+ fi
+ if test $driver = yes; then
+ libs="@EXTLINKCUPSDRIVER@ $libs"
+ fi
+ else
+ libs="$libdir/libcups.a $LIBS";
+ if test $image = yes; then
+ libs="$libdir/libcupsimage.a $IMGLIBS $libs"
+ fi
+ if test $driver = yes; then
+ libs="$libdir/libcupsdriver.a $libs"
+ fi
+ fi
+ echo $libs
+ ;;
+ --serverbin)
+ echo $cups_serverbin
+ ;;
+ --serverroot)
+ echo $cups_serverroot
+ ;;
+ --static)
+ if test -z "$INSTALLSTATIC"; then
+ echo "WARNING: Static libraries not installed!" >&2
+ else
+ static=yes
+ fi
+ ;;
+ --version)
+ echo $VERSION
+ ;;
+ *)
+ usage 1
+ ;;
+ esac
+
+ shift
+done
+
+#
+# End of "$Id$".
+#
diff --git a/cups/Dependencies b/cups/Dependencies
new file mode 100644
index 000000000..5e6359f7d
--- /dev/null
+++ b/cups/Dependencies
@@ -0,0 +1,735 @@
+# DO NOT DELETE
+
+adminutil.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+adminutil.o: array.h language.h string-private.h ../config.h debug-private.h
+adminutil.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+adminutil.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+adminutil.o: language-private.h ../cups/transcode.h thread-private.h
+adminutil.o: adminutil.h
+array.o: string-private.h ../config.h debug-private.h array-private.h array.h
+array.o: versioning.h
+attr.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+attr.o: array.h language.h string-private.h ../config.h debug-private.h
+attr.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+attr.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+attr.o: language-private.h ../cups/transcode.h thread-private.h
+auth.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+auth.o: array.h language.h string-private.h ../config.h debug-private.h
+auth.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+auth.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+auth.o: language-private.h ../cups/transcode.h thread-private.h
+backchannel.o: cups.h
+backend.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+backend.o: array.h language.h string-private.h ../config.h debug-private.h
+backend.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+backend.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+backend.o: language-private.h ../cups/transcode.h thread-private.h backend.h
+conflicts.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+conflicts.o: array.h language.h string-private.h ../config.h debug-private.h
+conflicts.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+conflicts.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+conflicts.o: language-private.h ../cups/transcode.h thread-private.h
+custom.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+custom.o: array.h language.h string-private.h ../config.h debug-private.h
+custom.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+custom.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+custom.o: language-private.h ../cups/transcode.h thread-private.h
+debug.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+debug.o: array.h language.h string-private.h ../config.h debug-private.h
+debug.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+debug.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+debug.o: language-private.h ../cups/transcode.h thread-private.h
+dest.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+dest.o: array.h language.h string-private.h ../config.h debug-private.h
+dest.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+dest.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+dest.o: language-private.h ../cups/transcode.h thread-private.h
+dir.o: string-private.h ../config.h debug-private.h dir.h versioning.h
+emit.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+emit.o: array.h language.h string-private.h ../config.h debug-private.h
+emit.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+emit.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+emit.o: language-private.h ../cups/transcode.h thread-private.h
+encode.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+encode.o: array.h language.h string-private.h ../config.h debug-private.h
+encode.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+encode.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+encode.o: language-private.h ../cups/transcode.h thread-private.h
+file.o: file-private.h cups-private.h ../cups/cups.h file.h versioning.h
+file.o: ipp.h http.h array.h language.h string-private.h ../config.h
+file.o: debug-private.h ppd-private.h ../cups/ppd.h cups.h pwg-private.h
+file.o: http-private.h ../cups/http.h md5-private.h ipp-private.h
+file.o: ../cups/ipp.h language-private.h ../cups/transcode.h thread-private.h
+getdevices.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+getdevices.o: array.h language.h string-private.h ../config.h debug-private.h
+getdevices.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+getdevices.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+getdevices.o: language-private.h ../cups/transcode.h thread-private.h
+getifaddrs.o: http-private.h ../config.h ../cups/http.h md5-private.h
+getifaddrs.o: ipp-private.h ../cups/ipp.h
+getputfile.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+getputfile.o: array.h language.h string-private.h ../config.h debug-private.h
+getputfile.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+getputfile.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+getputfile.o: language-private.h ../cups/transcode.h thread-private.h
+globals.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+globals.o: array.h language.h string-private.h ../config.h debug-private.h
+globals.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+globals.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+globals.o: language-private.h ../cups/transcode.h thread-private.h
+http.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+http.o: array.h language.h string-private.h ../config.h debug-private.h
+http.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+http.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+http.o: language-private.h ../cups/transcode.h thread-private.h
+http-addr.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+http-addr.o: array.h language.h string-private.h ../config.h debug-private.h
+http-addr.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+http-addr.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+http-addr.o: language-private.h ../cups/transcode.h thread-private.h
+http-addrlist.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h
+http-addrlist.o: http.h array.h language.h string-private.h ../config.h
+http-addrlist.o: debug-private.h ppd-private.h ../cups/ppd.h cups.h
+http-addrlist.o: pwg-private.h http-private.h ../cups/http.h md5-private.h
+http-addrlist.o: ipp-private.h ../cups/ipp.h language-private.h
+http-addrlist.o: ../cups/transcode.h thread-private.h
+http-support.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h
+http-support.o: http.h array.h language.h string-private.h ../config.h
+http-support.o: debug-private.h ppd-private.h ../cups/ppd.h cups.h
+http-support.o: pwg-private.h http-private.h ../cups/http.h md5-private.h
+http-support.o: ipp-private.h ../cups/ipp.h language-private.h
+http-support.o: ../cups/transcode.h thread-private.h
+ipp.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h array.h
+ipp.o: language.h string-private.h ../config.h debug-private.h ppd-private.h
+ipp.o: ../cups/ppd.h cups.h pwg-private.h http-private.h ../cups/http.h
+ipp.o: md5-private.h ipp-private.h ../cups/ipp.h language-private.h
+ipp.o: ../cups/transcode.h thread-private.h
+ipp-support.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+ipp-support.o: array.h language.h string-private.h ../config.h
+ipp-support.o: debug-private.h ppd-private.h ../cups/ppd.h cups.h
+ipp-support.o: pwg-private.h http-private.h ../cups/http.h md5-private.h
+ipp-support.o: ipp-private.h ../cups/ipp.h language-private.h
+ipp-support.o: ../cups/transcode.h thread-private.h
+langprintf.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+langprintf.o: array.h language.h string-private.h ../config.h debug-private.h
+langprintf.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+langprintf.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+langprintf.o: language-private.h ../cups/transcode.h thread-private.h
+language.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+language.o: array.h language.h string-private.h ../config.h debug-private.h
+language.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+language.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+language.o: language-private.h ../cups/transcode.h thread-private.h
+localize.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+localize.o: array.h language.h string-private.h ../config.h debug-private.h
+localize.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+localize.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+localize.o: language-private.h ../cups/transcode.h thread-private.h
+mark.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+mark.o: array.h language.h string-private.h ../config.h debug-private.h
+mark.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+mark.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+mark.o: language-private.h ../cups/transcode.h thread-private.h
+md5.o: md5-private.h string-private.h ../config.h
+md5passwd.o: http-private.h ../config.h ../cups/http.h md5-private.h
+md5passwd.o: ipp-private.h ../cups/ipp.h string-private.h
+notify.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+notify.o: array.h language.h string-private.h ../config.h debug-private.h
+notify.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+notify.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+notify.o: language-private.h ../cups/transcode.h thread-private.h
+options.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+options.o: array.h language.h string-private.h ../config.h debug-private.h
+options.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+options.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+options.o: language-private.h ../cups/transcode.h thread-private.h
+page.o: string-private.h ../config.h debug-private.h ppd.h cups.h array.h
+page.o: versioning.h file.h
+ppd.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h array.h
+ppd.o: language.h string-private.h ../config.h debug-private.h ppd-private.h
+ppd.o: ../cups/ppd.h cups.h pwg-private.h http-private.h ../cups/http.h
+ppd.o: md5-private.h ipp-private.h ../cups/ipp.h language-private.h
+ppd.o: ../cups/transcode.h thread-private.h
+ppd-cache.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+ppd-cache.o: array.h language.h string-private.h ../config.h debug-private.h
+ppd-cache.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+ppd-cache.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+ppd-cache.o: language-private.h ../cups/transcode.h thread-private.h
+pwg-media.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+pwg-media.o: array.h language.h string-private.h ../config.h debug-private.h
+pwg-media.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+pwg-media.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+pwg-media.o: language-private.h ../cups/transcode.h thread-private.h
+request.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+request.o: array.h language.h string-private.h ../config.h debug-private.h
+request.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+request.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+request.o: language-private.h ../cups/transcode.h thread-private.h
+sidechannel.o: sidechannel.h versioning.h string-private.h ../config.h
+sidechannel.o: debug-private.h
+snmp.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+snmp.o: array.h language.h string-private.h ../config.h debug-private.h
+snmp.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+snmp.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+snmp.o: language-private.h ../cups/transcode.h thread-private.h
+snmp.o: snmp-private.h
+snprintf.o: string-private.h ../config.h
+string.o: string-private.h ../config.h debug-private.h thread-private.h
+string.o: array.h versioning.h
+tempfile.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+tempfile.o: array.h language.h string-private.h ../config.h debug-private.h
+tempfile.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+tempfile.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+tempfile.o: language-private.h ../cups/transcode.h thread-private.h
+thread.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+thread.o: array.h language.h string-private.h ../config.h debug-private.h
+thread.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+thread.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+thread.o: language-private.h ../cups/transcode.h thread-private.h
+transcode.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+transcode.o: array.h language.h string-private.h ../config.h debug-private.h
+transcode.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+transcode.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+transcode.o: language-private.h ../cups/transcode.h thread-private.h
+usersys.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+usersys.o: array.h language.h string-private.h ../config.h debug-private.h
+usersys.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+usersys.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+usersys.o: language-private.h ../cups/transcode.h thread-private.h
+util.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+util.o: array.h language.h string-private.h ../config.h debug-private.h
+util.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+util.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+util.o: language-private.h ../cups/transcode.h thread-private.h
+testadmin.o: adminutil.h cups.h string-private.h ../config.h
+testarray.o: string-private.h ../config.h debug-private.h array.h
+testarray.o: versioning.h dir.h
+testconflicts.o: cups.h ppd.h array.h versioning.h file.h string-private.h
+testconflicts.o: ../config.h
+testcups.o: string-private.h ../config.h cups.h ppd.h array.h versioning.h
+testcups.o: file.h
+testfile.o: string-private.h ../config.h debug-private.h file.h versioning.h
+testhttp.o: string-private.h ../config.h http-private.h ../cups/http.h
+testhttp.o: md5-private.h ipp-private.h ../cups/ipp.h
+testi18n.o: string-private.h ../config.h language-private.h
+testi18n.o: ../cups/transcode.h language.h array.h versioning.h
+testipp.o: file.h versioning.h string-private.h ../config.h ipp-private.h
+testipp.o: ../cups/ipp.h
+testoptions.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testoptions.o: array.h language.h string-private.h ../config.h
+testoptions.o: debug-private.h ppd-private.h ../cups/ppd.h cups.h
+testoptions.o: pwg-private.h http-private.h ../cups/http.h md5-private.h
+testoptions.o: ipp-private.h ../cups/ipp.h language-private.h
+testoptions.o: ../cups/transcode.h thread-private.h
+testlang.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testlang.o: array.h language.h string-private.h ../config.h debug-private.h
+testlang.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+testlang.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+testlang.o: language-private.h ../cups/transcode.h thread-private.h
+testppd.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testppd.o: array.h language.h string-private.h ../config.h debug-private.h
+testppd.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+testppd.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+testppd.o: language-private.h ../cups/transcode.h thread-private.h
+testpwg.o: ppd-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testpwg.o: array.h language.h ../cups/ppd.h cups.h pwg-private.h
+testpwg.o: file-private.h cups-private.h string-private.h ../config.h
+testpwg.o: debug-private.h http-private.h ../cups/http.h md5-private.h
+testpwg.o: ipp-private.h ../cups/ipp.h language-private.h ../cups/transcode.h
+testpwg.o: thread-private.h
+testsnmp.o: cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testsnmp.o: array.h language.h string-private.h ../config.h debug-private.h
+testsnmp.o: ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+testsnmp.o: ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+testsnmp.o: language-private.h ../cups/transcode.h thread-private.h
+testsnmp.o: snmp-private.h
+# DO NOT DELETE
+
+adminutil.32.o: adminutil.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+adminutil.32.o: adminutil.c array.h language.h string-private.h ../config.h debug-private.h
+adminutil.32.o: adminutil.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+adminutil.32.o: adminutil.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+adminutil.32.o: adminutil.c language-private.h ../cups/transcode.h thread-private.h
+adminutil.32.o: adminutil.c adminutil.h
+array.32.o: array.c string-private.h ../config.h debug-private.h array-private.h array.h
+array.32.o: array.c versioning.h
+attr.32.o: attr.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+attr.32.o: attr.c array.h language.h string-private.h ../config.h debug-private.h
+attr.32.o: attr.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+attr.32.o: attr.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+attr.32.o: attr.c language-private.h ../cups/transcode.h thread-private.h
+auth.32.o: auth.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+auth.32.o: auth.c array.h language.h string-private.h ../config.h debug-private.h
+auth.32.o: auth.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+auth.32.o: auth.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+auth.32.o: auth.c language-private.h ../cups/transcode.h thread-private.h
+backchannel.32.o: backchannel.c cups.h
+backend.32.o: backend.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+backend.32.o: backend.c array.h language.h string-private.h ../config.h debug-private.h
+backend.32.o: backend.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+backend.32.o: backend.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+backend.32.o: backend.c language-private.h ../cups/transcode.h thread-private.h backend.h
+conflicts.32.o: conflicts.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+conflicts.32.o: conflicts.c array.h language.h string-private.h ../config.h debug-private.h
+conflicts.32.o: conflicts.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+conflicts.32.o: conflicts.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+conflicts.32.o: conflicts.c language-private.h ../cups/transcode.h thread-private.h
+custom.32.o: custom.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+custom.32.o: custom.c array.h language.h string-private.h ../config.h debug-private.h
+custom.32.o: custom.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+custom.32.o: custom.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+custom.32.o: custom.c language-private.h ../cups/transcode.h thread-private.h
+debug.32.o: debug.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+debug.32.o: debug.c array.h language.h string-private.h ../config.h debug-private.h
+debug.32.o: debug.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+debug.32.o: debug.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+debug.32.o: debug.c language-private.h ../cups/transcode.h thread-private.h
+dest.32.o: dest.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+dest.32.o: dest.c array.h language.h string-private.h ../config.h debug-private.h
+dest.32.o: dest.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+dest.32.o: dest.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+dest.32.o: dest.c language-private.h ../cups/transcode.h thread-private.h
+dir.32.o: dir.c string-private.h ../config.h debug-private.h dir.h versioning.h
+emit.32.o: emit.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+emit.32.o: emit.c array.h language.h string-private.h ../config.h debug-private.h
+emit.32.o: emit.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+emit.32.o: emit.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+emit.32.o: emit.c language-private.h ../cups/transcode.h thread-private.h
+encode.32.o: encode.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+encode.32.o: encode.c array.h language.h string-private.h ../config.h debug-private.h
+encode.32.o: encode.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+encode.32.o: encode.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+encode.32.o: encode.c language-private.h ../cups/transcode.h thread-private.h
+file.32.o: file.c file-private.h cups-private.h ../cups/cups.h file.h versioning.h
+file.32.o: file.c ipp.h http.h array.h language.h string-private.h ../config.h
+file.32.o: file.c debug-private.h ppd-private.h ../cups/ppd.h cups.h pwg-private.h
+file.32.o: file.c http-private.h ../cups/http.h md5-private.h ipp-private.h
+file.32.o: file.c ../cups/ipp.h language-private.h ../cups/transcode.h thread-private.h
+getdevices.32.o: getdevices.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+getdevices.32.o: getdevices.c array.h language.h string-private.h ../config.h debug-private.h
+getdevices.32.o: getdevices.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+getdevices.32.o: getdevices.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+getdevices.32.o: getdevices.c language-private.h ../cups/transcode.h thread-private.h
+getifaddrs.32.o: getifaddrs.c http-private.h ../config.h ../cups/http.h md5-private.h
+getifaddrs.32.o: getifaddrs.c ipp-private.h ../cups/ipp.h
+getputfile.32.o: getputfile.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+getputfile.32.o: getputfile.c array.h language.h string-private.h ../config.h debug-private.h
+getputfile.32.o: getputfile.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+getputfile.32.o: getputfile.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+getputfile.32.o: getputfile.c language-private.h ../cups/transcode.h thread-private.h
+globals.32.o: globals.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+globals.32.o: globals.c array.h language.h string-private.h ../config.h debug-private.h
+globals.32.o: globals.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+globals.32.o: globals.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+globals.32.o: globals.c language-private.h ../cups/transcode.h thread-private.h
+http.32.o: http.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+http.32.o: http.c array.h language.h string-private.h ../config.h debug-private.h
+http.32.o: http.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+http.32.o: http.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+http.32.o: http.c language-private.h ../cups/transcode.h thread-private.h
+http-addr.32.o: http-addr.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+http-addr.32.o: http-addr.c array.h language.h string-private.h ../config.h debug-private.h
+http-addr.32.o: http-addr.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+http-addr.32.o: http-addr.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+http-addr.32.o: http-addr.c language-private.h ../cups/transcode.h thread-private.h
+http-addrlist.32.o: http-addrlist.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h
+http-addrlist.32.o: http-addrlist.c http.h array.h language.h string-private.h ../config.h
+http-addrlist.32.o: http-addrlist.c debug-private.h ppd-private.h ../cups/ppd.h cups.h
+http-addrlist.32.o: http-addrlist.c pwg-private.h http-private.h ../cups/http.h md5-private.h
+http-addrlist.32.o: http-addrlist.c ipp-private.h ../cups/ipp.h language-private.h
+http-addrlist.32.o: http-addrlist.c ../cups/transcode.h thread-private.h
+http-support.32.o: http-support.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h
+http-support.32.o: http-support.c http.h array.h language.h string-private.h ../config.h
+http-support.32.o: http-support.c debug-private.h ppd-private.h ../cups/ppd.h cups.h
+http-support.32.o: http-support.c pwg-private.h http-private.h ../cups/http.h md5-private.h
+http-support.32.o: http-support.c ipp-private.h ../cups/ipp.h language-private.h
+http-support.32.o: http-support.c ../cups/transcode.h thread-private.h
+ipp.32.o: ipp.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h array.h
+ipp.32.o: ipp.c language.h string-private.h ../config.h debug-private.h ppd-private.h
+ipp.32.o: ipp.c ../cups/ppd.h cups.h pwg-private.h http-private.h ../cups/http.h
+ipp.32.o: ipp.c md5-private.h ipp-private.h ../cups/ipp.h language-private.h
+ipp.32.o: ipp.c ../cups/transcode.h thread-private.h
+ipp-support.32.o: ipp-support.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+ipp-support.32.o: ipp-support.c array.h language.h string-private.h ../config.h
+ipp-support.32.o: ipp-support.c debug-private.h ppd-private.h ../cups/ppd.h cups.h
+ipp-support.32.o: ipp-support.c pwg-private.h http-private.h ../cups/http.h md5-private.h
+ipp-support.32.o: ipp-support.c ipp-private.h ../cups/ipp.h language-private.h
+ipp-support.32.o: ipp-support.c ../cups/transcode.h thread-private.h
+langprintf.32.o: langprintf.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+langprintf.32.o: langprintf.c array.h language.h string-private.h ../config.h debug-private.h
+langprintf.32.o: langprintf.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+langprintf.32.o: langprintf.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+langprintf.32.o: langprintf.c language-private.h ../cups/transcode.h thread-private.h
+language.32.o: language.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+language.32.o: language.c array.h language.h string-private.h ../config.h debug-private.h
+language.32.o: language.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+language.32.o: language.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+language.32.o: language.c language-private.h ../cups/transcode.h thread-private.h
+localize.32.o: localize.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+localize.32.o: localize.c array.h language.h string-private.h ../config.h debug-private.h
+localize.32.o: localize.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+localize.32.o: localize.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+localize.32.o: localize.c language-private.h ../cups/transcode.h thread-private.h
+mark.32.o: mark.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+mark.32.o: mark.c array.h language.h string-private.h ../config.h debug-private.h
+mark.32.o: mark.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+mark.32.o: mark.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+mark.32.o: mark.c language-private.h ../cups/transcode.h thread-private.h
+md5.32.o: md5.c md5-private.h string-private.h ../config.h
+md5passwd.32.o: md5passwd.c http-private.h ../config.h ../cups/http.h md5-private.h
+md5passwd.32.o: md5passwd.c ipp-private.h ../cups/ipp.h string-private.h
+notify.32.o: notify.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+notify.32.o: notify.c array.h language.h string-private.h ../config.h debug-private.h
+notify.32.o: notify.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+notify.32.o: notify.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+notify.32.o: notify.c language-private.h ../cups/transcode.h thread-private.h
+options.32.o: options.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+options.32.o: options.c array.h language.h string-private.h ../config.h debug-private.h
+options.32.o: options.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+options.32.o: options.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+options.32.o: options.c language-private.h ../cups/transcode.h thread-private.h
+page.32.o: page.c string-private.h ../config.h debug-private.h ppd.h cups.h array.h
+page.32.o: page.c versioning.h file.h
+ppd.32.o: ppd.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h array.h
+ppd.32.o: ppd.c language.h string-private.h ../config.h debug-private.h ppd-private.h
+ppd.32.o: ppd.c ../cups/ppd.h cups.h pwg-private.h http-private.h ../cups/http.h
+ppd.32.o: ppd.c md5-private.h ipp-private.h ../cups/ipp.h language-private.h
+ppd.32.o: ppd.c ../cups/transcode.h thread-private.h
+ppd-cache.32.o: ppd-cache.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+ppd-cache.32.o: ppd-cache.c array.h language.h string-private.h ../config.h debug-private.h
+ppd-cache.32.o: ppd-cache.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+ppd-cache.32.o: ppd-cache.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+ppd-cache.32.o: ppd-cache.c language-private.h ../cups/transcode.h thread-private.h
+pwg-media.32.o: pwg-media.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+pwg-media.32.o: pwg-media.c array.h language.h string-private.h ../config.h debug-private.h
+pwg-media.32.o: pwg-media.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+pwg-media.32.o: pwg-media.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+pwg-media.32.o: pwg-media.c language-private.h ../cups/transcode.h thread-private.h
+request.32.o: request.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+request.32.o: request.c array.h language.h string-private.h ../config.h debug-private.h
+request.32.o: request.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+request.32.o: request.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+request.32.o: request.c language-private.h ../cups/transcode.h thread-private.h
+sidechannel.32.o: sidechannel.c sidechannel.h versioning.h string-private.h ../config.h
+sidechannel.32.o: sidechannel.c debug-private.h
+snmp.32.o: snmp.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+snmp.32.o: snmp.c array.h language.h string-private.h ../config.h debug-private.h
+snmp.32.o: snmp.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+snmp.32.o: snmp.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+snmp.32.o: snmp.c language-private.h ../cups/transcode.h thread-private.h
+snmp.32.o: snmp.c snmp-private.h
+snprintf.32.o: snprintf.c string-private.h ../config.h
+string.32.o: string.c string-private.h ../config.h debug-private.h thread-private.h
+string.32.o: string.c array.h versioning.h
+tempfile.32.o: tempfile.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+tempfile.32.o: tempfile.c array.h language.h string-private.h ../config.h debug-private.h
+tempfile.32.o: tempfile.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+tempfile.32.o: tempfile.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+tempfile.32.o: tempfile.c language-private.h ../cups/transcode.h thread-private.h
+thread.32.o: thread.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+thread.32.o: thread.c array.h language.h string-private.h ../config.h debug-private.h
+thread.32.o: thread.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+thread.32.o: thread.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+thread.32.o: thread.c language-private.h ../cups/transcode.h thread-private.h
+transcode.32.o: transcode.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+transcode.32.o: transcode.c array.h language.h string-private.h ../config.h debug-private.h
+transcode.32.o: transcode.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+transcode.32.o: transcode.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+transcode.32.o: transcode.c language-private.h ../cups/transcode.h thread-private.h
+usersys.32.o: usersys.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+usersys.32.o: usersys.c array.h language.h string-private.h ../config.h debug-private.h
+usersys.32.o: usersys.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+usersys.32.o: usersys.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+usersys.32.o: usersys.c language-private.h ../cups/transcode.h thread-private.h
+util.32.o: util.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+util.32.o: util.c array.h language.h string-private.h ../config.h debug-private.h
+util.32.o: util.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+util.32.o: util.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+util.32.o: util.c language-private.h ../cups/transcode.h thread-private.h
+testadmin.32.o: testadmin.c adminutil.h cups.h string-private.h ../config.h
+testarray.32.o: testarray.c string-private.h ../config.h debug-private.h array.h
+testarray.32.o: testarray.c versioning.h dir.h
+testconflicts.32.o: testconflicts.c cups.h ppd.h array.h versioning.h file.h string-private.h
+testconflicts.32.o: testconflicts.c ../config.h
+testcups.32.o: testcups.c string-private.h ../config.h cups.h ppd.h array.h versioning.h
+testcups.32.o: testcups.c file.h
+testfile.32.o: testfile.c string-private.h ../config.h debug-private.h file.h versioning.h
+testhttp.32.o: testhttp.c string-private.h ../config.h http-private.h ../cups/http.h
+testhttp.32.o: testhttp.c md5-private.h ipp-private.h ../cups/ipp.h
+testi18n.32.o: testi18n.c string-private.h ../config.h language-private.h
+testi18n.32.o: testi18n.c ../cups/transcode.h language.h array.h versioning.h
+testipp.32.o: testipp.c file.h versioning.h string-private.h ../config.h ipp-private.h
+testipp.32.o: testipp.c ../cups/ipp.h
+testoptions.32.o: testoptions.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testoptions.32.o: testoptions.c array.h language.h string-private.h ../config.h
+testoptions.32.o: testoptions.c debug-private.h ppd-private.h ../cups/ppd.h cups.h
+testoptions.32.o: testoptions.c pwg-private.h http-private.h ../cups/http.h md5-private.h
+testoptions.32.o: testoptions.c ipp-private.h ../cups/ipp.h language-private.h
+testoptions.32.o: testoptions.c ../cups/transcode.h thread-private.h
+testlang.32.o: testlang.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testlang.32.o: testlang.c array.h language.h string-private.h ../config.h debug-private.h
+testlang.32.o: testlang.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+testlang.32.o: testlang.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+testlang.32.o: testlang.c language-private.h ../cups/transcode.h thread-private.h
+testppd.32.o: testppd.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testppd.32.o: testppd.c array.h language.h string-private.h ../config.h debug-private.h
+testppd.32.o: testppd.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+testppd.32.o: testppd.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+testppd.32.o: testppd.c language-private.h ../cups/transcode.h thread-private.h
+testpwg.32.o: testpwg.c ppd-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testpwg.32.o: testpwg.c array.h language.h ../cups/ppd.h cups.h pwg-private.h
+testpwg.32.o: testpwg.c file-private.h cups-private.h string-private.h ../config.h
+testpwg.32.o: testpwg.c debug-private.h http-private.h ../cups/http.h md5-private.h
+testpwg.32.o: testpwg.c ipp-private.h ../cups/ipp.h language-private.h ../cups/transcode.h
+testpwg.32.o: testpwg.c thread-private.h
+testsnmp.32.o: testsnmp.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testsnmp.32.o: testsnmp.c array.h language.h string-private.h ../config.h debug-private.h
+testsnmp.32.o: testsnmp.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+testsnmp.32.o: testsnmp.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+testsnmp.32.o: testsnmp.c language-private.h ../cups/transcode.h thread-private.h
+testsnmp.32.o: testsnmp.c snmp-private.h
+# DO NOT DELETE
+
+adminutil.64.o: adminutil.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+adminutil.64.o: adminutil.c array.h language.h string-private.h ../config.h debug-private.h
+adminutil.64.o: adminutil.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+adminutil.64.o: adminutil.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+adminutil.64.o: adminutil.c language-private.h ../cups/transcode.h thread-private.h
+adminutil.64.o: adminutil.c adminutil.h
+array.64.o: array.c string-private.h ../config.h debug-private.h array-private.h array.h
+array.64.o: array.c versioning.h
+attr.64.o: attr.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+attr.64.o: attr.c array.h language.h string-private.h ../config.h debug-private.h
+attr.64.o: attr.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+attr.64.o: attr.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+attr.64.o: attr.c language-private.h ../cups/transcode.h thread-private.h
+auth.64.o: auth.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+auth.64.o: auth.c array.h language.h string-private.h ../config.h debug-private.h
+auth.64.o: auth.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+auth.64.o: auth.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+auth.64.o: auth.c language-private.h ../cups/transcode.h thread-private.h
+backchannel.64.o: backchannel.c cups.h
+backend.64.o: backend.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+backend.64.o: backend.c array.h language.h string-private.h ../config.h debug-private.h
+backend.64.o: backend.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+backend.64.o: backend.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+backend.64.o: backend.c language-private.h ../cups/transcode.h thread-private.h backend.h
+conflicts.64.o: conflicts.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+conflicts.64.o: conflicts.c array.h language.h string-private.h ../config.h debug-private.h
+conflicts.64.o: conflicts.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+conflicts.64.o: conflicts.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+conflicts.64.o: conflicts.c language-private.h ../cups/transcode.h thread-private.h
+custom.64.o: custom.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+custom.64.o: custom.c array.h language.h string-private.h ../config.h debug-private.h
+custom.64.o: custom.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+custom.64.o: custom.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+custom.64.o: custom.c language-private.h ../cups/transcode.h thread-private.h
+debug.64.o: debug.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+debug.64.o: debug.c array.h language.h string-private.h ../config.h debug-private.h
+debug.64.o: debug.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+debug.64.o: debug.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+debug.64.o: debug.c language-private.h ../cups/transcode.h thread-private.h
+dest.64.o: dest.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+dest.64.o: dest.c array.h language.h string-private.h ../config.h debug-private.h
+dest.64.o: dest.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+dest.64.o: dest.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+dest.64.o: dest.c language-private.h ../cups/transcode.h thread-private.h
+dir.64.o: dir.c string-private.h ../config.h debug-private.h dir.h versioning.h
+emit.64.o: emit.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+emit.64.o: emit.c array.h language.h string-private.h ../config.h debug-private.h
+emit.64.o: emit.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+emit.64.o: emit.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+emit.64.o: emit.c language-private.h ../cups/transcode.h thread-private.h
+encode.64.o: encode.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+encode.64.o: encode.c array.h language.h string-private.h ../config.h debug-private.h
+encode.64.o: encode.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+encode.64.o: encode.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+encode.64.o: encode.c language-private.h ../cups/transcode.h thread-private.h
+file.64.o: file.c file-private.h cups-private.h ../cups/cups.h file.h versioning.h
+file.64.o: file.c ipp.h http.h array.h language.h string-private.h ../config.h
+file.64.o: file.c debug-private.h ppd-private.h ../cups/ppd.h cups.h pwg-private.h
+file.64.o: file.c http-private.h ../cups/http.h md5-private.h ipp-private.h
+file.64.o: file.c ../cups/ipp.h language-private.h ../cups/transcode.h thread-private.h
+getdevices.64.o: getdevices.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+getdevices.64.o: getdevices.c array.h language.h string-private.h ../config.h debug-private.h
+getdevices.64.o: getdevices.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+getdevices.64.o: getdevices.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+getdevices.64.o: getdevices.c language-private.h ../cups/transcode.h thread-private.h
+getifaddrs.64.o: getifaddrs.c http-private.h ../config.h ../cups/http.h md5-private.h
+getifaddrs.64.o: getifaddrs.c ipp-private.h ../cups/ipp.h
+getputfile.64.o: getputfile.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+getputfile.64.o: getputfile.c array.h language.h string-private.h ../config.h debug-private.h
+getputfile.64.o: getputfile.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+getputfile.64.o: getputfile.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+getputfile.64.o: getputfile.c language-private.h ../cups/transcode.h thread-private.h
+globals.64.o: globals.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+globals.64.o: globals.c array.h language.h string-private.h ../config.h debug-private.h
+globals.64.o: globals.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+globals.64.o: globals.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+globals.64.o: globals.c language-private.h ../cups/transcode.h thread-private.h
+http.64.o: http.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+http.64.o: http.c array.h language.h string-private.h ../config.h debug-private.h
+http.64.o: http.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+http.64.o: http.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+http.64.o: http.c language-private.h ../cups/transcode.h thread-private.h
+http-addr.64.o: http-addr.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+http-addr.64.o: http-addr.c array.h language.h string-private.h ../config.h debug-private.h
+http-addr.64.o: http-addr.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+http-addr.64.o: http-addr.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+http-addr.64.o: http-addr.c language-private.h ../cups/transcode.h thread-private.h
+http-addrlist.64.o: http-addrlist.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h
+http-addrlist.64.o: http-addrlist.c http.h array.h language.h string-private.h ../config.h
+http-addrlist.64.o: http-addrlist.c debug-private.h ppd-private.h ../cups/ppd.h cups.h
+http-addrlist.64.o: http-addrlist.c pwg-private.h http-private.h ../cups/http.h md5-private.h
+http-addrlist.64.o: http-addrlist.c ipp-private.h ../cups/ipp.h language-private.h
+http-addrlist.64.o: http-addrlist.c ../cups/transcode.h thread-private.h
+http-support.64.o: http-support.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h
+http-support.64.o: http-support.c http.h array.h language.h string-private.h ../config.h
+http-support.64.o: http-support.c debug-private.h ppd-private.h ../cups/ppd.h cups.h
+http-support.64.o: http-support.c pwg-private.h http-private.h ../cups/http.h md5-private.h
+http-support.64.o: http-support.c ipp-private.h ../cups/ipp.h language-private.h
+http-support.64.o: http-support.c ../cups/transcode.h thread-private.h
+ipp.64.o: ipp.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h array.h
+ipp.64.o: ipp.c language.h string-private.h ../config.h debug-private.h ppd-private.h
+ipp.64.o: ipp.c ../cups/ppd.h cups.h pwg-private.h http-private.h ../cups/http.h
+ipp.64.o: ipp.c md5-private.h ipp-private.h ../cups/ipp.h language-private.h
+ipp.64.o: ipp.c ../cups/transcode.h thread-private.h
+ipp-support.64.o: ipp-support.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+ipp-support.64.o: ipp-support.c array.h language.h string-private.h ../config.h
+ipp-support.64.o: ipp-support.c debug-private.h ppd-private.h ../cups/ppd.h cups.h
+ipp-support.64.o: ipp-support.c pwg-private.h http-private.h ../cups/http.h md5-private.h
+ipp-support.64.o: ipp-support.c ipp-private.h ../cups/ipp.h language-private.h
+ipp-support.64.o: ipp-support.c ../cups/transcode.h thread-private.h
+langprintf.64.o: langprintf.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+langprintf.64.o: langprintf.c array.h language.h string-private.h ../config.h debug-private.h
+langprintf.64.o: langprintf.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+langprintf.64.o: langprintf.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+langprintf.64.o: langprintf.c language-private.h ../cups/transcode.h thread-private.h
+language.64.o: language.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+language.64.o: language.c array.h language.h string-private.h ../config.h debug-private.h
+language.64.o: language.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+language.64.o: language.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+language.64.o: language.c language-private.h ../cups/transcode.h thread-private.h
+localize.64.o: localize.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+localize.64.o: localize.c array.h language.h string-private.h ../config.h debug-private.h
+localize.64.o: localize.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+localize.64.o: localize.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+localize.64.o: localize.c language-private.h ../cups/transcode.h thread-private.h
+mark.64.o: mark.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+mark.64.o: mark.c array.h language.h string-private.h ../config.h debug-private.h
+mark.64.o: mark.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+mark.64.o: mark.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+mark.64.o: mark.c language-private.h ../cups/transcode.h thread-private.h
+md5.64.o: md5.c md5-private.h string-private.h ../config.h
+md5passwd.64.o: md5passwd.c http-private.h ../config.h ../cups/http.h md5-private.h
+md5passwd.64.o: md5passwd.c ipp-private.h ../cups/ipp.h string-private.h
+notify.64.o: notify.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+notify.64.o: notify.c array.h language.h string-private.h ../config.h debug-private.h
+notify.64.o: notify.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+notify.64.o: notify.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+notify.64.o: notify.c language-private.h ../cups/transcode.h thread-private.h
+options.64.o: options.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+options.64.o: options.c array.h language.h string-private.h ../config.h debug-private.h
+options.64.o: options.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+options.64.o: options.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+options.64.o: options.c language-private.h ../cups/transcode.h thread-private.h
+page.64.o: page.c string-private.h ../config.h debug-private.h ppd.h cups.h array.h
+page.64.o: page.c versioning.h file.h
+ppd.64.o: ppd.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h array.h
+ppd.64.o: ppd.c language.h string-private.h ../config.h debug-private.h ppd-private.h
+ppd.64.o: ppd.c ../cups/ppd.h cups.h pwg-private.h http-private.h ../cups/http.h
+ppd.64.o: ppd.c md5-private.h ipp-private.h ../cups/ipp.h language-private.h
+ppd.64.o: ppd.c ../cups/transcode.h thread-private.h
+ppd-cache.64.o: ppd-cache.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+ppd-cache.64.o: ppd-cache.c array.h language.h string-private.h ../config.h debug-private.h
+ppd-cache.64.o: ppd-cache.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+ppd-cache.64.o: ppd-cache.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+ppd-cache.64.o: ppd-cache.c language-private.h ../cups/transcode.h thread-private.h
+pwg-media.64.o: pwg-media.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+pwg-media.64.o: pwg-media.c array.h language.h string-private.h ../config.h debug-private.h
+pwg-media.64.o: pwg-media.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+pwg-media.64.o: pwg-media.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+pwg-media.64.o: pwg-media.c language-private.h ../cups/transcode.h thread-private.h
+request.64.o: request.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+request.64.o: request.c array.h language.h string-private.h ../config.h debug-private.h
+request.64.o: request.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+request.64.o: request.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+request.64.o: request.c language-private.h ../cups/transcode.h thread-private.h
+sidechannel.64.o: sidechannel.c sidechannel.h versioning.h string-private.h ../config.h
+sidechannel.64.o: sidechannel.c debug-private.h
+snmp.64.o: snmp.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+snmp.64.o: snmp.c array.h language.h string-private.h ../config.h debug-private.h
+snmp.64.o: snmp.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+snmp.64.o: snmp.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+snmp.64.o: snmp.c language-private.h ../cups/transcode.h thread-private.h
+snmp.64.o: snmp.c snmp-private.h
+snprintf.64.o: snprintf.c string-private.h ../config.h
+string.64.o: string.c string-private.h ../config.h debug-private.h thread-private.h
+string.64.o: string.c array.h versioning.h
+tempfile.64.o: tempfile.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+tempfile.64.o: tempfile.c array.h language.h string-private.h ../config.h debug-private.h
+tempfile.64.o: tempfile.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+tempfile.64.o: tempfile.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+tempfile.64.o: tempfile.c language-private.h ../cups/transcode.h thread-private.h
+thread.64.o: thread.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+thread.64.o: thread.c array.h language.h string-private.h ../config.h debug-private.h
+thread.64.o: thread.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+thread.64.o: thread.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+thread.64.o: thread.c language-private.h ../cups/transcode.h thread-private.h
+transcode.64.o: transcode.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+transcode.64.o: transcode.c array.h language.h string-private.h ../config.h debug-private.h
+transcode.64.o: transcode.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+transcode.64.o: transcode.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+transcode.64.o: transcode.c language-private.h ../cups/transcode.h thread-private.h
+usersys.64.o: usersys.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+usersys.64.o: usersys.c array.h language.h string-private.h ../config.h debug-private.h
+usersys.64.o: usersys.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+usersys.64.o: usersys.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+usersys.64.o: usersys.c language-private.h ../cups/transcode.h thread-private.h
+util.64.o: util.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+util.64.o: util.c array.h language.h string-private.h ../config.h debug-private.h
+util.64.o: util.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+util.64.o: util.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+util.64.o: util.c language-private.h ../cups/transcode.h thread-private.h
+testadmin.64.o: testadmin.c adminutil.h cups.h string-private.h ../config.h
+testarray.64.o: testarray.c string-private.h ../config.h debug-private.h array.h
+testarray.64.o: testarray.c versioning.h dir.h
+testconflicts.64.o: testconflicts.c cups.h ppd.h array.h versioning.h file.h string-private.h
+testconflicts.64.o: testconflicts.c ../config.h
+testcups.64.o: testcups.c string-private.h ../config.h cups.h ppd.h array.h versioning.h
+testcups.64.o: testcups.c file.h
+testfile.64.o: testfile.c string-private.h ../config.h debug-private.h file.h versioning.h
+testhttp.64.o: testhttp.c string-private.h ../config.h http-private.h ../cups/http.h
+testhttp.64.o: testhttp.c md5-private.h ipp-private.h ../cups/ipp.h
+testi18n.64.o: testi18n.c string-private.h ../config.h language-private.h
+testi18n.64.o: testi18n.c ../cups/transcode.h language.h array.h versioning.h
+testipp.64.o: testipp.c file.h versioning.h string-private.h ../config.h ipp-private.h
+testipp.64.o: testipp.c ../cups/ipp.h
+testoptions.64.o: testoptions.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testoptions.64.o: testoptions.c array.h language.h string-private.h ../config.h
+testoptions.64.o: testoptions.c debug-private.h ppd-private.h ../cups/ppd.h cups.h
+testoptions.64.o: testoptions.c pwg-private.h http-private.h ../cups/http.h md5-private.h
+testoptions.64.o: testoptions.c ipp-private.h ../cups/ipp.h language-private.h
+testoptions.64.o: testoptions.c ../cups/transcode.h thread-private.h
+testlang.64.o: testlang.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testlang.64.o: testlang.c array.h language.h string-private.h ../config.h debug-private.h
+testlang.64.o: testlang.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+testlang.64.o: testlang.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+testlang.64.o: testlang.c language-private.h ../cups/transcode.h thread-private.h
+testppd.64.o: testppd.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testppd.64.o: testppd.c array.h language.h string-private.h ../config.h debug-private.h
+testppd.64.o: testppd.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+testppd.64.o: testppd.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+testppd.64.o: testppd.c language-private.h ../cups/transcode.h thread-private.h
+testpwg.64.o: testpwg.c ppd-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testpwg.64.o: testpwg.c array.h language.h ../cups/ppd.h cups.h pwg-private.h
+testpwg.64.o: testpwg.c file-private.h cups-private.h string-private.h ../config.h
+testpwg.64.o: testpwg.c debug-private.h http-private.h ../cups/http.h md5-private.h
+testpwg.64.o: testpwg.c ipp-private.h ../cups/ipp.h language-private.h ../cups/transcode.h
+testpwg.64.o: testpwg.c thread-private.h
+testsnmp.64.o: testsnmp.c cups-private.h ../cups/cups.h file.h versioning.h ipp.h http.h
+testsnmp.64.o: testsnmp.c array.h language.h string-private.h ../config.h debug-private.h
+testsnmp.64.o: testsnmp.c ppd-private.h ../cups/ppd.h cups.h pwg-private.h http-private.h
+testsnmp.64.o: testsnmp.c ../cups/http.h md5-private.h ipp-private.h ../cups/ipp.h
+testsnmp.64.o: testsnmp.c language-private.h ../cups/transcode.h thread-private.h
+testsnmp.64.o: testsnmp.c snmp-private.h
diff --git a/cups/Makefile b/cups/Makefile
new file mode 100644
index 000000000..85985c2db
--- /dev/null
+++ b/cups/Makefile
@@ -0,0 +1,680 @@
+#
+# "$Id$"
+#
+# API library Makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2006 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# This file is subject to the Apple OS-Developed Software exception.
+#
+
+include ../Makedefs
+
+#
+# Object files...
+#
+
+LIBOBJS = \
+ adminutil.o \
+ array.o \
+ attr.o \
+ auth.o \
+ backchannel.o \
+ backend.o \
+ conflicts.o \
+ custom.o \
+ debug.o \
+ dest.o \
+ dir.o \
+ emit.o \
+ encode.o \
+ file.o \
+ getdevices.o \
+ getifaddrs.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 \
+ localize.o \
+ mark.o \
+ md5.o \
+ md5passwd.o \
+ notify.o \
+ options.o \
+ page.o \
+ ppd.o \
+ ppd-cache.o \
+ pwg-media.o \
+ request.o \
+ sidechannel.o \
+ snmp.o \
+ snprintf.o \
+ string.o \
+ tempfile.o \
+ thread.o \
+ transcode.o \
+ usersys.o \
+ util.o
+LIB32OBJS = $(LIBOBJS:.o=.32.o)
+LIB64OBJS = $(LIBOBJS:.o=.64.o)
+OBJS = \
+ $(LIBOBJS) \
+ $(LIB32OBJS) \
+ $(LIB64OBJS) \
+ testadmin.o \
+ testarray.o \
+ testconflicts.o \
+ testcups.o \
+ testfile.o \
+ testhttp.o \
+ testi18n.o \
+ testipp.o \
+ testoptions.o \
+ testlang.o \
+ testppd.o \
+ testpwg.o \
+ testsnmp.o
+
+
+#
+# Header files to install...
+#
+
+HEADERS = \
+ adminutil.h \
+ array.h \
+ backend.h \
+ cups.h \
+ dir.h \
+ file.h \
+ http.h \
+ ipp.h \
+ language.h \
+ ppd.h \
+ raster.h \
+ sidechannel.h \
+ transcode.h \
+ versioning.h
+
+HEADERSPRIV = \
+ array-private.h \
+ cups-private.h \
+ debug-private.h \
+ file-private.h \
+ http-private.h \
+ ipp-private.h \
+ language-private.h \
+ md5-private.h \
+ ppd-private.h \
+ pwg-private.h \
+ snmp-private.h \
+ string-private.h \
+ thread-private.h
+
+
+#
+# Targets in this directory...
+#
+
+LIBTARGETS = \
+ $(LIBCUPSSTATIC) \
+ $(LIBCUPS) \
+ $(LIB32CUPS) \
+ $(LIB64CUPS)
+
+UNITTARGETS = \
+ testadmin \
+ testarray \
+ testconflicts \
+ testcups \
+ testfile \
+ testhttp \
+ testi18n \
+ testipp \
+ testlang \
+ testoptions \
+ testppd \
+ testpwg \
+ testsnmp
+
+TARGETS = \
+ $(LIBTARGETS)
+
+
+#
+# Make all targets...
+#
+
+all: $(TARGETS)
+
+
+#
+# Make library targets...
+#
+
+libs: $(LIBTARGETS)
+
+
+#
+# Make unit tests...
+#
+
+unittests: $(UNITTARGETS)
+
+
+#
+# Remove object and target files...
+#
+
+clean:
+ $(RM) $(OBJS) $(TARGETS) $(UNITTARGETS)
+ $(RM) libcups.so libcups.sl libcups.dylib
+ $(RM) -r 32bit 64bit
+
+
+#
+# Update dependencies (without system header dependencies...)
+#
+
+depend:
+ touch Dependencies.tmp
+ makedepend -Y -I.. -fDependencies.tmp $(OBJS:.o=.c) >/dev/null 2>&1
+ $(RM) Dependencies
+ cp Dependencies.tmp Dependencies
+ sed -E -e '1,$$s/^([^.]+)\.o:/\1\.32.o: \1\.c /' Dependencies.tmp >>Dependencies
+ sed -E -e '1,$$s/^([^.]+)\.o:/\1\.64.o: \1\.c /' Dependencies.tmp >>Dependencies
+ $(RM) Dependencies.tmp
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+
+
+#
+# Install programs...
+#
+
+install-exec:
+
+
+#
+# Install headers...
+#
+
+install-headers:
+ echo Installing header files into $(INCLUDEDIR)/cups...
+ $(INSTALL_DIR) -m 755 $(INCLUDEDIR)/cups
+ for file in $(HEADERS); do \
+ $(INSTALL_DATA) $$file $(INCLUDEDIR)/cups; \
+ done
+ if test "x$(privateinclude)" != x; then \
+ echo Installing private header files into $(PRIVATEINCLUDE)...; \
+ $(INSTALL_DIR) -m 755 $(PRIVATEINCLUDE); \
+ for file in $(HEADERSPRIV); do \
+ $(INSTALL_DATA) $$file $(PRIVATEINCLUDE)/$$file; \
+ done; \
+ fi
+
+
+#
+# Install libraries...
+#
+
+install-libs: $(INSTALLSTATIC) $(INSTALL32) $(INSTALL64)
+ echo Installing libraries in $(LIBDIR)...
+ $(INSTALL_DIR) -m 755 $(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 \
+ $(RM) $(LIBDIR)/libcups.dylib; \
+ $(LN) $(LIBCUPS) $(LIBDIR)/libcups.dylib; \
+ fi
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ cp $(LIBCUPS) $(SYMROOT); \
+ fi
+
+installstatic:
+ $(INSTALL_DIR) -m 755 $(LIBDIR)
+ $(INSTALL_LIB) -m 755 $(LIBCUPSSTATIC) $(LIBDIR)
+ $(RANLIB) $(LIBDIR)/$(LIBCUPSSTATIC)
+ $(CHMOD) 555 $(LIBDIR)/$(LIBCUPSSTATIC)
+
+install32bit:
+ echo Installing libraries in $(LIB32DIR)...
+ $(INSTALL_DIR) -m 755 $(LIB32DIR)
+ $(INSTALL_LIB) 32bit/libcups.so.2 $(LIB32DIR)/libcups.so.2
+ $(LN) libcups.so.2 $(LIB32DIR)/libcups.so
+
+install64bit:
+ echo Installing libraries in $(LIB64DIR)...
+ $(INSTALL_DIR) -m 755 $(LIB64DIR)
+ $(INSTALL_LIB) 64bit/libcups.so.2 $(LIB64DIR)/libcups.so.2
+ $(LN) libcups.so.2 $(LIB64DIR)/libcups.so
+
+
+#
+# Uninstall object and target files...
+#
+
+uninstall: $(UNINSTALL32) $(UNINSTALL64)
+ $(RM) $(LIBDIR)/libcups.2.dylib
+ $(RM) $(LIBDIR)/$(LIBCUPSSTATIC)
+ $(RM) $(LIBDIR)/libcups.dylib
+ $(RM) $(LIBDIR)/libcups_s.a
+ $(RM) $(LIBDIR)/libcups.sl
+ $(RM) $(LIBDIR)/libcups.sl.2
+ $(RM) $(LIBDIR)/libcups.so
+ $(RM) $(LIBDIR)/libcups.so.2
+ -$(RMDIR) $(LIBDIR)
+ for file in $(HEADERS); do \
+ $(RM) $(INCLUDEDIR)/cups/$$file; \
+ done
+ -$(RMDIR) $(INCLUDEDIR)/cups
+
+uninstall32bit:
+ $(RM) $(LIB32DIR)/libcups.so
+ $(RM) $(LIB32DIR)/libcups.so.2
+ -$(RMDIR) $(LIB32DIR)
+
+uninstall64bit:
+ $(RM) $(LIB64DIR)/libcups.so
+ $(RM) $(LIB64DIR)/libcups.so.2
+ -$(RMDIR) $(LIB64DIR)
+
+
+#
+# libcups.so.2, libcups.sl.2
+#
+
+libcups.so.2 libcups.sl.2: $(LIBOBJS)
+ echo Linking $@...
+ $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS) $(LIBGSSAPI) \
+ $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+ $(RM) `basename $@ .2`
+ $(LN) $@ `basename $@ .2`
+
+
+#
+# 32bit/libcups.so.2
+#
+
+32bit/libcups.so.2: $(LIB32OBJS)
+ echo Linking 32-bit $@...
+ -mkdir 32bit
+ $(DSO) $(ARCH32FLAGS) $(DSO32FLAGS) -o $@ $(LIB32OBJS) $(LIBGSSAPI) \
+ $(DNSSDLIBS) $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+ $(RM) 32bit/libcups.so
+ $(LN) libcups.so.2 32bit/libcups.so
+
+
+#
+# 64bit/libcups.so.2
+#
+
+64bit/libcups.so.2: $(LIB64OBJS)
+ echo Linking 64-bit $@...
+ -mkdir 64bit
+ $(DSO) $(ARCH64FLAGS) $(DSO64FLAGS) -o $@ $(LIB64OBJS) $(LIBGSSAPI) \
+ $(DNSSDLIBS) $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+ $(RM) 64bit/libcups.so
+ $(LN) libcups.so.2 64bit/libcups.so
+
+
+#
+# libcups.2.dylib
+#
+
+libcups.2.dylib: $(LIBOBJS) $(LIBCUPSORDER)
+ echo Creating export list for $@...
+ nm $(LIBOBJS) 2>/dev/null | grep "T _" | awk '{print $$3}' | \
+ grep -v -e '^(_cupsConnect|_cupsCharset|_cupsEncodingName|_cupsSetDefaults|_cupsSetHTTPError|_cupsUserDefault|_httpWait)$$' | \
+ sort >t.exp
+ echo Linking $@...
+ $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ \
+ -install_name $(libdir)/$@ \
+ -current_version 2.9.0 \
+ -compatibility_version 2.0.0 \
+ -exported_symbols_list t.exp \
+ $(LIBOBJS) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ $(COMMONLIBS) $(LIBZ)
+ $(RM) libcups.dylib t.exp
+ $(LN) $@ libcups.dylib
+
+
+#
+# libcups_s.a
+#
+
+libcups_s.a: $(LIBOBJS) libcups_s.exp
+ echo Creating $@...
+ $(DSO) $(DSOFLAGS) -Wl,-bexport:libcups_s.exp -o libcups_s.o \
+ $(LIBOBJS) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ $(COMMONLIBS) $(LIBZ) -lm
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ libcups_s.o
+
+
+#
+# libcups.la
+#
+
+libcups.la: $(LIBOBJS)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS:.o=.lo) \
+ -rpath $(LIBDIR) -version-info 2:9 $(LIBGSSAPI) $(SSLLIBS) \
+ $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# libcups.a
+#
+
+libcups.a: $(LIBOBJS)
+ echo Archiving $@...
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ $(LIBOBJS)
+ $(RANLIB) $@
+
+
+#
+# testadmin (dependency on static CUPS library is intentional)
+#
+
+testadmin: testadmin.o $(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testadmin.o $(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# testarray (dependency on static CUPS library is intentional)
+#
+
+testarray: testarray.o $(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testarray.o $(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+ echo Running array API tests...
+ ./testarray
+
+
+#
+# testconflicts (dependency on static CUPS library is intentional)
+#
+
+testconflicts: testconflicts.o $(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testconflicts.o $(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# testcups (dependency on static CUPS library is intentional)
+#
+
+testcups: testcups.o $(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testcups.o $(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# testfile (dependency on static CUPS library is intentional)
+#
+
+testfile: testfile.o $(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testfile.o $(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+ echo Running file API tests...
+ ./testfile
+
+
+#
+# testhttp (dependency on static CUPS library is intentional)
+#
+
+testhttp: testhttp.o $(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testhttp.o $(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+ echo Running HTTP API tests...
+ ./testhttp
+
+
+#
+# testipp (dependency on static CUPS library is intentional)
+#
+
+testipp: testipp.o $(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testipp.o $(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+ echo Running IPP API tests...
+ ./testipp
+
+
+#
+# testi18n (dependency on static CUPS library is intentional)
+#
+
+testi18n: testi18n.o $(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testi18n.o $(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+ echo Running internationalization API tests...
+ ./testi18n
+
+
+#
+# testlang (dependency on static CUPS library is intentional)
+#
+
+testlang: testlang.o $(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testlang.o $(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+ echo Running language API tests...
+ ./testlang
+
+
+#
+# testoptions (dependency on static CUPS library is intentional)
+#
+
+testoptions: testoptions.o $(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testoptions.o $(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+ echo Running option API tests...
+ ./testoptions
+
+
+#
+# testppd (dependency on static CUPS library is intentional)
+#
+
+testppd: testppd.o $(LIBCUPSSTATIC) test.ppd test2.ppd
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testppd.o $(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+ echo Running PPD API tests...
+ ./testppd
+
+
+#
+# testpwg (dependency on static CUPS library is intentional)
+#
+
+testpwg: testpwg.o $(LIBCUPSSTATIC) test.ppd
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testpwg.o $(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+ echo Running PWG API tests...
+ ./testpwg test.ppd
+
+
+#
+# testsnmp (dependency on static CUPS library is intentional)
+#
+
+testsnmp: testsnmp.o $(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testsnmp.o $(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# Automatic API help files...
+#
+
+apihelp:
+ echo Generating CUPS API help files...
+ mxmldoc --section "Programming" \
+ --title "Introduction to CUPS Programming" \
+ --css ../doc/cups-printable.css \
+ --header api-overview.header --intro api-overview.shtml \
+ >../doc/help/api-overview.html
+ mxmldoc --section "Programming" --title "Array API" \
+ --css ../doc/cups-printable.css \
+ --header api-array.header --intro api-array.shtml \
+ api-array.xml \
+ array.h array.c >../doc/help/api-array.html
+ mxmldoc --tokens help/api-array.html api-array.xml >../doc/help/api-array.tokens
+ $(RM) api-array.xml
+ mxmldoc --section "Programming" --title "CUPS API" \
+ --css ../doc/cups-printable.css \
+ --header api-cups.header --intro api-cups.shtml \
+ api-cups.xml \
+ cups.h adminutil.c dest.c language.c notify.c \
+ options.c tempfile.c usersys.c \
+ util.c >../doc/help/api-cups.html
+ mxmldoc --tokens help/api-cups.html api-cups.xml >../doc/help/api-cups.tokens
+ $(RM) api-cups.xml
+ mxmldoc --section "Programming" --title "File and Directory APIs" \
+ --css ../doc/cups-printable.css \
+ --header api-filedir.header --intro api-filedir.shtml \
+ api-filedir.xml \
+ file.h file.c dir.h dir.c >../doc/help/api-filedir.html
+ mxmldoc --tokens api-filedir.xml >../doc/help/api-filedir.tokens
+ $(RM) api-filedir.xml
+ mxmldoc --section "Programming" --title "PPD API" \
+ --css ../doc/cups-printable.css \
+ --header api-ppd.header --intro api-ppd.shtml \
+ api-ppd.xml \
+ ppd.h attr.c conflicts.c custom.c emit.c localize.c mark.c page.c \
+ ppd.c >../doc/help/api-ppd.html
+ mxmldoc --tokens help/api-ppd.html api-ppd.xml >../doc/help/api-ppd.tokens
+ $(RM) api-ppd.xml
+ mxmldoc --section "Programming" --title "HTTP and IPP APIs" \
+ --css ../doc/cups-printable.css \
+ --header api-httpipp.header --intro api-httpipp.shtml \
+ api-httpipp.xml \
+ http.h ipp.h auth.c getdevices.c getputfile.c encode.c \
+ http.c http-addr.c http-support.c ipp.c ipp-support.c \
+ md5passwd.c request.c >../doc/help/api-httpipp.html
+ mxmldoc --tokens help/api-httpipp.html api-httpipp.xml >../doc/help/api-httpipp.tokens
+ $(RM) api-httpipp.xml
+ mxmldoc --section "Programming" \
+ --title "Filter and Backend Programming" \
+ --css ../doc/cups-printable.css \
+ --header api-filter.header --intro api-filter.shtml \
+ api-filter.xml \
+ backchannel.c backend.h backend.c sidechannel.c sidechannel.h \
+ >../doc/help/api-filter.html
+ mxmldoc --tokens help/api-filter.html api-filter.xml >../doc/help/api-filter.tokens
+ $(RM) api-filter.xml
+
+framedhelp:
+ echo Generating CUPS API help files...
+ mxmldoc --framed api-overview \
+ --section "Programming" \
+ --title "Introduction to CUPS Programming" \
+ --css ../doc/cups-printable.css \
+ --header api-overview.header --intro api-overview.shtml
+ mxmldoc --framed api-array \
+ --section "Programming" --title "Array API" \
+ --css ../doc/cups-printable.css \
+ --header api-array.header --intro api-array.shtml \
+ array.h array.c
+ mxmldoc --framed api-cups \
+ --section "Programming" --title "CUPS API" \
+ --css ../doc/cups-printable.css \
+ --header api-cups.header --intro api-cups.shtml \
+ cups.h adminutil.c dest.c language.c notify.c \
+ options.c tempfile.c usersys.c \
+ util.c
+ mxmldoc --framed api-filedir \
+ --section "Programming" --title "File and Directory APIs" \
+ --css ../doc/cups-printable.css \
+ --header api-filedir.header --intro api-filedir.shtml \
+ file.h file.c dir.h dir.c
+ mxmldoc --framed api-ppd \
+ --section "Programming" --title "PPD API" \
+ --css ../doc/cups-printable.css \
+ --header api-ppd.header --intro api-ppd.shtml \
+ ppd.h attr.c conflicts.c custom.c emit.c localize.c mark.c \
+ page.c ppd.c
+ mxmldoc --framed api-httpipp \
+ --section "Programming" --title "HTTP and IPP APIs" \
+ --css ../doc/cups-printable.css \
+ --header api-httpipp.header --intro api-httpipp.shtml \
+ http.h ipp.h auth.c getdevices.c getputfile.c encode.c \
+ http.c http-addr.c http-support.c ipp.c ipp-support.c \
+ md5passwd.c request.c
+ mxmldoc --framed api-filter \
+ --section "Programming" \
+ --title "Filter and Backend Programming" \
+ --css ../doc/cups-printable.css \
+ --header api-filter.header --intro api-filter.shtml \
+ backchannel.c backend.h backend.c sidechannel.c sidechannel.h
+
+
+#
+# Lines of code computation...
+#
+
+sloc:
+ echo "libcupslite: \c"
+ sloccount $(LITEOBJS:.o=.c) 2>/dev/null | grep "Total Physical" | awk '{print $$9}'
+ echo "libcups: \c"
+ sloccount $(LIBOBJS:.o=.c) 2>/dev/null | grep "Total Physical" | awk '{print $$9}'
+
+
+#
+# Dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id$".
+#
diff --git a/cups/adminutil.c b/cups/adminutil.c
new file mode 100644
index 000000000..11d50227d
--- /dev/null
+++ b/cups/adminutil.c
@@ -0,0 +1,2458 @@
+/*
+ * "$Id$"
+ *
+ * Administration utility API definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2001-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsAdminCreateWindowsPPD() - Create the Windows PPD file for a printer.
+ * cupsAdminExportSamba() - Export a printer to Samba.
+ * cupsAdminGetServerSettings() - Get settings from the server.
+ * cupsAdminSetServerSettings() - Set settings on the server.
+ * do_samba_command() - Do a SAMBA command.
+ * get_cupsd_conf() - Get the current cupsd.conf file.
+ * invalidate_cupsd_cache() - Invalidate the cached cupsd.conf settings.
+ * write_option() - Write a CUPS option to a PPD file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include "adminutil.h"
+#include <fcntl.h>
+#include <sys/stat.h>
+#ifdef WIN32
+#else
+# include <unistd.h>
+# include <sys/wait.h>
+#endif /* WIN32 */
+
+
+/*
+ * Local functions...
+ */
+
+static int do_samba_command(const char *command,
+ const char *address,
+ const char *subcommand,
+ const char *authfile,
+ FILE *logfile);
+static http_status_t get_cupsd_conf(http_t *http, _cups_globals_t *cg,
+ time_t last_update, char *name,
+ int namelen, int *remote);
+static void invalidate_cupsd_cache(_cups_globals_t *cg);
+static void write_option(cups_file_t *dstfp, int order,
+ const char *name, const char *text,
+ const char *attrname,
+ ipp_attribute_t *suppattr,
+ ipp_attribute_t *defattr, int defval,
+ int valcount);
+
+
+/*
+ * 'cupsAdminCreateWindowsPPD()' - Create the Windows PPD file for a printer.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+char * /* O - PPD file or NULL */
+cupsAdminCreateWindowsPPD(
+ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *dest, /* I - Printer or class */
+ char *buffer, /* I - Filename buffer */
+ int bufsize) /* I - Size of filename buffer */
+{
+ const char *src; /* Source PPD filename */
+ cups_file_t *srcfp, /* Source PPD file */
+ *dstfp; /* Destination PPD file */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *suppattr, /* IPP -supported attribute */
+ *defattr; /* IPP -default attribute */
+ cups_lang_t *language; /* Current language */
+ char line[256], /* Line from PPD file */
+ junk[256], /* Extra junk to throw away */
+ *ptr, /* Pointer into line */
+ uri[1024], /* Printer URI */
+ option[41], /* Option */
+ choice[41]; /* Choice */
+ int jcloption, /* In a JCL option? */
+ jclorder, /* Next JCL order dependency */
+ linenum; /* Current line number */
+ time_t curtime; /* Current time */
+ struct tm *curdate; /* Current date */
+ static const char * const pattrs[] = /* Printer attributes we want */
+ {
+ "job-hold-until-supported",
+ "job-hold-until-default",
+ "job-sheets-supported",
+ "job-sheets-default",
+ "job-priority-supported",
+ "job-priority-default"
+ };
+
+
+ /*
+ * Range check the input...
+ */
+
+ if (buffer)
+ *buffer = '\0';
+
+ if (!http)
+ http = _cupsConnect();
+
+ if (!http || !dest || !buffer || bufsize < 2)
+ return (NULL);
+
+ /*
+ * Get the PPD file...
+ */
+
+ if ((src = cupsGetPPD2(http, dest)) == NULL)
+ return (NULL);
+
+ /*
+ * Get the supported banner pages, etc. for the printer...
+ */
+
+ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/printers/%s", dest);
+ 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 and get back a response...
+ */
+
+ response = cupsDoRequest(http, request, "/");
+ if (!response || cupsLastError() > IPP_OK_CONFLICT)
+ {
+ unlink(src);
+ return (NULL);
+ }
+
+ /*
+ * Open the original PPD file...
+ */
+
+ if ((srcfp = cupsFileOpen(src, "rb")) == NULL)
+ return (NULL);
+
+ /*
+ * Create a temporary output file using the destination buffer...
+ */
+
+ if ((dstfp = cupsTempFile2(buffer, bufsize)) == NULL)
+ {
+ cupsFileClose(srcfp);
+
+ unlink(src);
+
+ return (NULL);
+ }
+
+ /*
+ * Write a new header explaining that this isn't the original PPD...
+ */
+
+ cupsFilePuts(dstfp, "*PPD-Adobe: \"4.3\"\n");
+
+ curtime = time(NULL);
+ curdate = gmtime(&curtime);
+
+ cupsFilePrintf(dstfp, "*%% Modified on %04d%02d%02d%02d%02d%02d+0000 "
+ "for CUPS Windows Driver\n",
+ curdate->tm_year + 1900, curdate->tm_mon + 1, curdate->tm_mday,
+ curdate->tm_hour, curdate->tm_min, curdate->tm_sec);
+
+ /*
+ * Read the existing PPD file, converting all PJL commands to CUPS
+ * job ticket comments...
+ */
+
+ jcloption = 0;
+ jclorder = 0;
+ linenum = 0;
+ language = cupsLangDefault();
+
+ while (cupsFileGets(srcfp, line, sizeof(line)))
+ {
+ linenum ++;
+
+ if (!strncmp(line, "*PPD-Adobe:", 11))
+ {
+ /*
+ * Already wrote the PPD header...
+ */
+
+ continue;
+ }
+ else if (!strncmp(line, "*JCLBegin:", 10) ||
+ !strncmp(line, "*JCLToPSInterpreter:", 20) ||
+ !strncmp(line, "*JCLEnd:", 8) ||
+ !strncmp(line, "*Protocols:", 11))
+ {
+ /*
+ * Don't use existing JCL keywords; we'll create our own, below...
+ */
+
+ cupsFilePrintf(dstfp, "*%% Commented out for CUPS Windows Driver...\n"
+ "*%%%s\n", line + 1);
+ continue;
+ }
+ else if (!strncmp(line, "*JCLOpenUI", 10))
+ {
+ jcloption = 1;
+ cupsFilePrintf(dstfp, "%s\n", line);
+ }
+ else if (!strncmp(line, "*JCLCloseUI", 11))
+ {
+ jcloption = 0;
+ cupsFilePrintf(dstfp, "%s\n", line);
+ }
+ else if (jcloption && !strncmp(line, "*OrderDependency:", 17))
+ {
+ for (ptr = line + 17; _cups_isspace(*ptr); ptr ++);
+
+ ptr = strchr(ptr, ' ');
+
+ if (ptr)
+ {
+ cupsFilePrintf(dstfp, "*OrderDependency: %d%s\n", jclorder, ptr);
+ jclorder ++;
+ }
+ else
+ cupsFilePrintf(dstfp, "%s\n", line);
+ }
+ else if (jcloption &&
+ strncmp(line, "*End", 4) &&
+ strncmp(line, "*Default", 8))
+ {
+ if ((ptr = strchr(line, ':')) == NULL)
+ {
+ snprintf(line, sizeof(line),
+ _cupsLangString(language, _("Missing value on line %d.")),
+ linenum);
+ _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line, 0);
+
+ cupsFileClose(srcfp);
+ cupsFileClose(dstfp);
+
+ unlink(src);
+ unlink(buffer);
+
+ *buffer = '\0';
+
+ return (NULL);
+ }
+
+ if ((ptr = strchr(ptr, '\"')) == NULL)
+ {
+ snprintf(line, sizeof(line),
+ _cupsLangString(language,
+ _("Missing double quote on line %d.")),
+ linenum);
+ _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line, 0);
+
+ cupsFileClose(srcfp);
+ cupsFileClose(dstfp);
+
+ unlink(src);
+ unlink(buffer);
+
+ *buffer = '\0';
+
+ return (NULL);
+ }
+
+ if (sscanf(line, "*%40s%*[ \t]%40[^:/]", option, choice) != 2)
+ {
+ snprintf(line, sizeof(line),
+ _cupsLangString(language,
+ _("Bad option + choice on line %d.")),
+ linenum);
+ _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line, 0);
+
+ cupsFileClose(srcfp);
+ cupsFileClose(dstfp);
+
+ unlink(src);
+ unlink(buffer);
+
+ *buffer = '\0';
+
+ return (NULL);
+ }
+
+ if (strchr(ptr + 1, '\"') == NULL)
+ {
+ /*
+ * Skip remaining...
+ */
+
+ while (cupsFileGets(srcfp, junk, sizeof(junk)) != NULL)
+ {
+ linenum ++;
+
+ if (!strncmp(junk, "*End", 4))
+ break;
+ }
+ }
+
+ snprintf(ptr + 1, sizeof(line) - (ptr - line + 1),
+ "%%cupsJobTicket: %s=%s\n\"\n*End", option, choice);
+
+ cupsFilePrintf(dstfp, "*%% Changed for CUPS Windows Driver...\n%s\n",
+ line);
+ }
+ else
+ cupsFilePrintf(dstfp, "%s\n", line);
+ }
+
+ cupsFileClose(srcfp);
+ unlink(src);
+
+ if (linenum == 0)
+ {
+ _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, _("Empty PPD file."), 1);
+
+ cupsFileClose(dstfp);
+ unlink(buffer);
+
+ *buffer = '\0';
+
+ return (NULL);
+ }
+
+ /*
+ * Now add the CUPS-specific attributes and options...
+ */
+
+ cupsFilePuts(dstfp, "\n*% CUPS Job Ticket support and options...\n");
+ cupsFilePuts(dstfp, "*Protocols: PJL\n");
+ cupsFilePuts(dstfp, "*JCLBegin: \"%!PS-Adobe-3.0<0A>\"\n");
+ cupsFilePuts(dstfp, "*JCLToPSInterpreter: \"\"\n");
+ cupsFilePuts(dstfp, "*JCLEnd: \"\"\n");
+
+ cupsFilePuts(dstfp, "\n*OpenGroup: CUPS/CUPS Options\n\n");
+
+ if ((defattr = ippFindAttribute(response, "job-hold-until-default",
+ IPP_TAG_ZERO)) != NULL &&
+ (suppattr = ippFindAttribute(response, "job-hold-until-supported",
+ IPP_TAG_ZERO)) != NULL)
+ write_option(dstfp, jclorder ++, "cupsJobHoldUntil", "Hold Until",
+ "job-hold-until", suppattr, defattr, 0, 1);
+
+ if ((defattr = ippFindAttribute(response, "job-priority-default",
+ IPP_TAG_INTEGER)) != NULL &&
+ (suppattr = ippFindAttribute(response, "job-priority-supported",
+ IPP_TAG_RANGE)) != NULL)
+ write_option(dstfp, jclorder ++, "cupsJobPriority", "Priority",
+ "job-priority", suppattr, defattr, 0, 1);
+
+ if ((defattr = ippFindAttribute(response, "job-sheets-default",
+ IPP_TAG_ZERO)) != NULL &&
+ (suppattr = ippFindAttribute(response, "job-sheets-supported",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ write_option(dstfp, jclorder ++, "cupsJobSheetsStart", "Start Banner",
+ "job-sheets", suppattr, defattr, 0, 2);
+ write_option(dstfp, jclorder, "cupsJobSheetsEnd", "End Banner",
+ "job-sheets", suppattr, defattr, 1, 2);
+ }
+
+ cupsFilePuts(dstfp, "*CloseGroup: CUPS\n");
+ cupsFileClose(dstfp);
+
+ ippDelete(response);
+
+ return (buffer);
+}
+
+
+/*
+ * 'cupsAdminExportSamba()' - Export a printer to Samba.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsAdminExportSamba(
+ const char *dest, /* I - Destination to export */
+ const char *ppd, /* I - PPD file */
+ const char *samba_server, /* I - Samba server */
+ const char *samba_user, /* I - Samba username */
+ const char *samba_password, /* I - Samba password */
+ FILE *logfile) /* I - Log file, if any */
+{
+ int status; /* Status of Samba commands */
+ int have_drivers; /* Have drivers? */
+ char file[1024], /* File to test for */
+ authfile[1024], /* Temporary authentication file */
+ address[1024], /* Address for command */
+ subcmd[1024], /* Sub-command */
+ message[1024]; /* Error message */
+ cups_file_t *fp; /* Authentication file */
+ cups_lang_t *language; /* Current language */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Global data */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!dest || !ppd || !samba_server || !samba_user || !samba_password)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
+ return (0);
+ }
+
+ /*
+ * Create a temporary authentication file for Samba...
+ */
+
+ if ((fp = cupsTempFile2(authfile, sizeof(authfile))) == NULL)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
+ return (0);
+ }
+
+ cupsFilePrintf(fp, "username = %s\n", samba_user);
+ cupsFilePrintf(fp, "password = %s\n", samba_password);
+ cupsFileClose(fp);
+
+ /*
+ * See which drivers are available; the new CUPS v6 and Adobe drivers
+ * depend on the Windows 2k PS driver, so copy that driver first:
+ *
+ * Files:
+ *
+ * ps5ui.dll
+ * pscript.hlp
+ * pscript.ntf
+ * pscript5.dll
+ */
+
+ have_drivers = 0;
+ language = cupsLangDefault();
+
+ snprintf(file, sizeof(file), "%s/drivers/pscript5.dll", cg->cups_datadir);
+ if (!access(file, 0))
+ {
+ have_drivers |= 1;
+
+ /*
+ * Windows 2k driver is installed; do the smbclient commands needed
+ * to copy the Win2k drivers over...
+ */
+
+ snprintf(address, sizeof(address), "//%s/print$", samba_server);
+
+ snprintf(subcmd, sizeof(subcmd),
+ "mkdir W32X86;"
+ "put %s W32X86/%s.ppd;"
+ "put %s/drivers/ps5ui.dll W32X86/ps5ui.dll;"
+ "put %s/drivers/pscript.hlp W32X86/pscript.hlp;"
+ "put %s/drivers/pscript.ntf W32X86/pscript.ntf;"
+ "put %s/drivers/pscript5.dll W32X86/pscript5.dll",
+ ppd, dest, cg->cups_datadir, cg->cups_datadir,
+ cg->cups_datadir, cg->cups_datadir);
+
+ if ((status = do_samba_command("smbclient", address, subcmd,
+ authfile, logfile)) != 0)
+ {
+ snprintf(message, sizeof(message),
+ _cupsLangString(language,
+ _("Unable to copy Windows 2000 printer "
+ "driver files (%d).")), status);
+
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
+
+ if (logfile)
+ _cupsLangPuts(logfile, message);
+
+ unlink(authfile);
+
+ return (0);
+ }
+
+ /*
+ * See if we also have the CUPS driver files; if so, use them!
+ */
+
+ snprintf(file, sizeof(file), "%s/drivers/cupsps6.dll", cg->cups_datadir);
+ if (!access(file, 0))
+ {
+ /*
+ * Copy the CUPS driver files over...
+ */
+
+ snprintf(subcmd, sizeof(subcmd),
+ "put %s/drivers/cups6.ini W32X86/cups6.ini;"
+ "put %s/drivers/cupsps6.dll W32X86/cupsps6.dll;"
+ "put %s/drivers/cupsui6.dll W32X86/cupsui6.dll",
+ cg->cups_datadir, cg->cups_datadir, cg->cups_datadir);
+
+ if ((status = do_samba_command("smbclient", address, subcmd,
+ authfile, logfile)) != 0)
+ {
+ snprintf(message, sizeof(message),
+ _cupsLangString(language,
+ _("Unable to copy CUPS printer driver "
+ "files (%d).")), status);
+
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
+
+ if (logfile)
+ _cupsLangPuts(logfile, message);
+
+ unlink(authfile);
+
+ return (0);
+ }
+
+ /*
+ * Do the rpcclient command needed for the CUPS drivers...
+ */
+
+ snprintf(subcmd, sizeof(subcmd),
+ "adddriver \"Windows NT x86\" \"%s:"
+ "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:"
+ "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf,"
+ "cups6.ini,cupsps6.dll,cupsui6.dll\"",
+ dest, dest, dest);
+ }
+ else
+ {
+ /*
+ * Don't have the CUPS drivers, so just use the standard Windows
+ * drivers...
+ */
+
+ snprintf(subcmd, sizeof(subcmd),
+ "adddriver \"Windows NT x86\" \"%s:"
+ "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:"
+ "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf\"",
+ dest, dest, dest);
+ }
+
+ if ((status = do_samba_command("rpcclient", samba_server, subcmd,
+ authfile, logfile)) != 0)
+ {
+ snprintf(message, sizeof(message),
+ _cupsLangString(language,
+ _("Unable to install Windows 2000 printer "
+ "driver files (%d).")), status);
+
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
+
+ if (logfile)
+ _cupsLangPuts(logfile, message);
+
+ unlink(authfile);
+
+ return (0);
+ }
+ }
+
+ /*
+ * See if we have the Win9x PS driver...
+ */
+
+ snprintf(file, sizeof(file), "%s/drivers/ADOBEPS4.DRV", cg->cups_datadir);
+ if (!access(file, 0))
+ {
+ have_drivers |= 2;
+
+ /*
+ * Do the smbclient commands needed for the Adobe Win9x drivers...
+ */
+
+ snprintf(address, sizeof(address), "//%s/print$", samba_server);
+
+ snprintf(subcmd, sizeof(subcmd),
+ "mkdir WIN40;"
+ "put %s WIN40/%s.PPD;"
+ "put %s/drivers/ADFONTS.MFM WIN40/ADFONTS.MFM;"
+ "put %s/drivers/ADOBEPS4.DRV WIN40/ADOBEPS4.DRV;"
+ "put %s/drivers/ADOBEPS4.HLP WIN40/ADOBEPS4.HLP;"
+ "put %s/drivers/ICONLIB.DLL WIN40/ICONLIB.DLL;"
+ "put %s/drivers/PSMON.DLL WIN40/PSMON.DLL;",
+ ppd, dest, cg->cups_datadir, cg->cups_datadir,
+ cg->cups_datadir, cg->cups_datadir, cg->cups_datadir);
+
+ if ((status = do_samba_command("smbclient", address, subcmd,
+ authfile, logfile)) != 0)
+ {
+ snprintf(message, sizeof(message),
+ _cupsLangString(language,
+ _("Unable to copy Windows 9x printer "
+ "driver files (%d).")), status);
+
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
+
+ if (logfile)
+ _cupsLangPuts(logfile, message);
+
+ unlink(authfile);
+
+ return (0);
+ }
+
+ /*
+ * Do the rpcclient commands needed for the Adobe Win9x drivers...
+ */
+
+ snprintf(subcmd, sizeof(subcmd),
+ "adddriver \"Windows 4.0\" \"%s:ADOBEPS4.DRV:%s.PPD:NULL:"
+ "ADOBEPS4.HLP:PSMON.DLL:RAW:"
+ "ADOBEPS4.DRV,%s.PPD,ADOBEPS4.HLP,PSMON.DLL,ADFONTS.MFM,"
+ "ICONLIB.DLL\"",
+ dest, dest, dest);
+
+ if ((status = do_samba_command("rpcclient", samba_server, subcmd,
+ authfile, logfile)) != 0)
+ {
+ snprintf(message, sizeof(message),
+ _cupsLangString(language,
+ _("Unable to install Windows 9x printer "
+ "driver files (%d).")), status);
+
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
+
+ if (logfile)
+ _cupsLangPuts(logfile, message);
+
+ unlink(authfile);
+
+ return (0);
+ }
+ }
+
+ /*
+ * See if we have the 64-bit Windows PS driver...
+ *
+ * Files:
+ *
+ * x64/ps5ui.dll
+ * x64/pscript.hlp
+ * x64/pscript.ntf
+ * x64/pscript5.dll
+ */
+
+ snprintf(file, sizeof(file), "%s/drivers/x64/pscript5.dll", cg->cups_datadir);
+ if (!access(file, 0))
+ {
+ have_drivers |= 4;
+
+ /*
+ * 64-bit Windows driver is installed; do the smbclient commands needed
+ * to copy the Win64 drivers over...
+ */
+
+ snprintf(address, sizeof(address), "//%s/print$", samba_server);
+
+ snprintf(subcmd, sizeof(subcmd),
+ "mkdir x64;"
+ "put %s x64/%s.ppd;"
+ "put %s/drivers/x64/ps5ui.dll x64/ps5ui.dll;"
+ "put %s/drivers/x64/pscript.hlp x64/pscript.hlp;"
+ "put %s/drivers/x64/pscript.ntf x64/pscript.ntf;"
+ "put %s/drivers/x64/pscript5.dll x64/pscript5.dll",
+ ppd, dest, cg->cups_datadir, cg->cups_datadir,
+ cg->cups_datadir, cg->cups_datadir);
+
+ if ((status = do_samba_command("smbclient", address, subcmd,
+ authfile, logfile)) != 0)
+ {
+ snprintf(message, sizeof(message),
+ _cupsLangString(language,
+ _("Unable to copy 64-bit Windows printer "
+ "driver files (%d).")), status);
+
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
+
+ if (logfile)
+ _cupsLangPuts(logfile, message);
+
+ unlink(authfile);
+
+ return (0);
+ }
+
+ /*
+ * See if we also have the CUPS driver files; if so, use them!
+ */
+
+ snprintf(file, sizeof(file), "%s/drivers/x64/cupsps6.dll", cg->cups_datadir);
+ if (!access(file, 0))
+ {
+ /*
+ * Copy the CUPS driver files over...
+ */
+
+ snprintf(subcmd, sizeof(subcmd),
+ "put %s/drivers/x64/cups6.ini x64/cups6.ini;"
+ "put %s/drivers/x64/cupsps6.dll x64/cupsps6.dll;"
+ "put %s/drivers/x64/cupsui6.dll x64/cupsui6.dll",
+ cg->cups_datadir, cg->cups_datadir, cg->cups_datadir);
+
+ if ((status = do_samba_command("smbclient", address, subcmd,
+ authfile, logfile)) != 0)
+ {
+ snprintf(message, sizeof(message),
+ _cupsLangString(language,
+ _("Unable to copy 64-bit CUPS printer driver "
+ "files (%d).")), status);
+
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
+
+ if (logfile)
+ _cupsLangPuts(logfile, message);
+
+ unlink(authfile);
+
+ return (0);
+ }
+
+ /*
+ * Do the rpcclient command needed for the CUPS drivers...
+ */
+
+ snprintf(subcmd, sizeof(subcmd),
+ "adddriver \"Windows x64\" \"%s:"
+ "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:"
+ "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf,"
+ "cups6.ini,cupsps6.dll,cupsui6.dll\"",
+ dest, dest, dest);
+ }
+ else
+ {
+ /*
+ * Don't have the CUPS drivers, so just use the standard Windows
+ * drivers...
+ */
+
+ snprintf(subcmd, sizeof(subcmd),
+ "adddriver \"Windows x64\" \"%s:"
+ "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:"
+ "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf\"",
+ dest, dest, dest);
+ }
+
+ if ((status = do_samba_command("rpcclient", samba_server, subcmd,
+ authfile, logfile)) != 0)
+ {
+ snprintf(message, sizeof(message),
+ _cupsLangString(language,
+ _("Unable to install Windows 2000 printer "
+ "driver files (%d).")), status);
+
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
+
+ if (logfile)
+ _cupsLangPuts(logfile, message);
+
+ unlink(authfile);
+
+ return (0);
+ }
+ }
+
+ if (logfile && !(have_drivers & 1))
+ {
+ if (!have_drivers)
+ strlcpy(message,
+ _cupsLangString(language,
+ _("No Windows printer drivers are installed.")),
+ sizeof(message));
+ else
+ strlcpy(message,
+ _cupsLangString(language,
+ _("Warning, no Windows 2000 printer drivers "
+ "are installed.")),
+ sizeof(message));
+
+ _cupsSetError(IPP_NOT_FOUND, message, 0);
+ _cupsLangPuts(logfile, message);
+ }
+
+ if (have_drivers == 0)
+ {
+ _cupsSetError(IPP_NOT_FOUND, message, 0);
+
+ unlink(authfile);
+
+ return (0);
+ }
+
+ /*
+ * Finally, associate the drivers we just added with the queue...
+ */
+
+ snprintf(subcmd, sizeof(subcmd), "setdriver %s %s", dest, dest);
+
+ if ((status = do_samba_command("rpcclient", samba_server, subcmd,
+ authfile, logfile)) != 0)
+ {
+ snprintf(message, sizeof(message),
+ _cupsLangString(language,
+ _("Unable to set Windows printer driver (%d).")),
+ status);
+
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
+
+ if (logfile)
+ _cupsLangPuts(logfile, message);
+
+ unlink(authfile);
+
+ return (0);
+ }
+
+ unlink(authfile);
+
+ return (1);
+}
+
+
+/*
+ * 'cupsAdminGetServerSettings()' - Get settings from the server.
+ *
+ * The returned settings should be freed with cupsFreeOptions() when
+ * you are done with them.
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsAdminGetServerSettings(
+ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ int *num_settings, /* O - Number of settings */
+ cups_option_t **settings) /* O - Settings */
+{
+ int i; /* Looping var */
+ cups_file_t *cupsd; /* cupsd.conf file */
+ char cupsdconf[1024]; /* cupsd.conf filename */
+ int remote; /* Remote cupsd.conf file? */
+ http_status_t status; /* Status of getting cupsd.conf */
+ char line[1024], /* Line from cupsd.conf file */
+ *value; /* Value on line */
+ cups_option_t *setting; /* Current setting */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!http)
+ {
+ /*
+ * See if we are connected to the same server...
+ */
+
+ if (cg->http)
+ {
+ /*
+ * Compare the connection hostname, port, and encryption settings to
+ * the cached defaults; these were initialized the first time we
+ * connected...
+ */
+
+ if (strcmp(cg->http->hostname, cg->server) ||
+ cg->ipp_port != _httpAddrPort(cg->http->hostaddr) ||
+ (cg->http->encryption != cg->encryption &&
+ cg->http->encryption == HTTP_ENCRYPT_NEVER))
+ {
+ /*
+ * Need to close the current connection because something has changed...
+ */
+
+ httpClose(cg->http);
+ cg->http = NULL;
+ }
+ }
+
+ /*
+ * (Re)connect as needed...
+ */
+
+ if (!cg->http)
+ {
+ if ((cg->http = _httpCreate(cupsServer(), ippPort(), NULL,
+ cupsEncryption(), AF_UNSPEC)) == NULL)
+ {
+ if (errno)
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
+ else
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE,
+ _("Unable to connect to host."), 1);
+
+ if (num_settings)
+ *num_settings = 0;
+
+ if (settings)
+ *settings = NULL;
+
+ return (0);
+ }
+ }
+
+ http = cg->http;
+ }
+
+ if (!http || !num_settings || !settings)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
+
+ if (num_settings)
+ *num_settings = 0;
+
+ if (settings)
+ *settings = NULL;
+
+ return (0);
+ }
+
+ *num_settings = 0;
+ *settings = NULL;
+
+ /*
+ * Get the cupsd.conf file...
+ */
+
+ if ((status = get_cupsd_conf(http, cg, cg->cupsd_update, cupsdconf,
+ sizeof(cupsdconf), &remote)) == HTTP_OK)
+ {
+ if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL)
+ {
+ char message[1024]; /* Message string */
+
+
+ snprintf(message, sizeof(message),
+ _cupsLangString(cupsLangDefault(), _("Open of %s failed: %s")),
+ cupsdconf, strerror(errno));
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
+ }
+ }
+ else
+ cupsd = NULL;
+
+ if (cupsd)
+ {
+ /*
+ * Read the file, keeping track of what settings are enabled...
+ */
+
+ int remote_access = 0, /* Remote access allowed? */
+ remote_admin = 0, /* Remote administration allowed? */
+ remote_any = 0, /* Remote access from anywhere 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_location = 0, /* In a location section? */
+ in_policy = 0, /* In a policy section? */
+ in_cancel_job = 0, /* In a cancel-job section? */
+ in_admin_location = 0; /* In the /admin location? */
+
+
+ invalidate_cupsd_cache(cg);
+
+ cg->cupsd_update = time(NULL);
+ httpGetHostname(http, cg->cupsd_hostname, sizeof(cg->cupsd_hostname));
+
+ while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
+ {
+ if (!value && strncmp(line, "</", 2))
+ value = line + strlen(line);
+
+ if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")) && value)
+ {
+ char *port; /* Pointer to port number, if any */
+
+
+ if ((port = strrchr(value, ':')) != NULL)
+ *port = '\0';
+ else if (isdigit(*value & 255))
+ {
+ /*
+ * Listen on a port number implies remote access...
+ */
+
+ remote_access = 1;
+ continue;
+ }
+
+ if (_cups_strcasecmp(value, "localhost") && strcmp(value, "127.0.0.1")
+#ifdef AF_LOCAL
+ && *value != '/'
+#endif /* AF_LOCAL */
+#ifdef AF_INET6
+ && strcmp(value, "[::1]")
+#endif /* AF_INET6 */
+ )
+ remote_access = 1;
+ }
+ else if (!_cups_strcasecmp(line, "Browsing"))
+ {
+ browsing = !_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "true");
+ }
+ else if (!_cups_strcasecmp(line, "BrowseAddress"))
+ {
+ browse_address = 1;
+ }
+ else if (!_cups_strcasecmp(line, "BrowseAllow"))
+ {
+ browse_allow = 1;
+ }
+ else if (!_cups_strcasecmp(line, "BrowseOrder"))
+ {
+ browse_allow = !_cups_strncasecmp(value, "deny,", 5);
+ }
+ else if (!_cups_strcasecmp(line, "LogLevel"))
+ {
+ debug_logging = !_cups_strncasecmp(value, "debug", 5);
+ }
+ else if (!_cups_strcasecmp(line, "<Policy") && !_cups_strcasecmp(value, "default"))
+ {
+ in_policy = 1;
+ }
+ else if (!_cups_strcasecmp(line, "</Policy>"))
+ {
+ in_policy = 0;
+ }
+ else if (!_cups_strcasecmp(line, "<Limit") && in_policy && value)
+ {
+ /*
+ * See if the policy limit is for the Cancel-Job operation...
+ */
+
+ char *valptr; /* Pointer into value */
+
+
+ while (*value)
+ {
+ for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++);
+
+ if (*valptr)
+ *valptr++ = '\0';
+
+ if (!_cups_strcasecmp(value, "cancel-job") || !_cups_strcasecmp(value, "all"))
+ {
+ in_cancel_job = 1;
+ break;
+ }
+
+ for (value = valptr; _cups_isspace(*value); value ++);
+ }
+ }
+ else if (!_cups_strcasecmp(line, "</Limit>"))
+ {
+ in_cancel_job = 0;
+ }
+ else if (!_cups_strcasecmp(line, "Require") && in_cancel_job)
+ {
+ cancel_policy = 0;
+ }
+ else if (!_cups_strcasecmp(line, "<Location") && value)
+ {
+ in_admin_location = !_cups_strcasecmp(value, "/admin");
+ in_location = 1;
+ }
+ else if (!_cups_strcasecmp(line, "</Location>"))
+ {
+ in_admin_location = 0;
+ in_location = 0;
+ }
+ else if (!_cups_strcasecmp(line, "Allow") && value &&
+ _cups_strcasecmp(value, "localhost") && _cups_strcasecmp(value, "127.0.0.1")
+#ifdef AF_LOCAL
+ && *value != '/'
+#endif /* AF_LOCAL */
+#ifdef AF_INET6
+ && strcmp(value, "::1")
+#endif /* AF_INET6 */
+ )
+ {
+ if (in_admin_location)
+ remote_admin = 1;
+ else if (!_cups_strcasecmp(value, "all"))
+ remote_any = 1;
+ }
+ else if (line[0] != '<' && !in_location && !in_policy &&
+ _cups_strcasecmp(line, "Allow") &&
+ _cups_strcasecmp(line, "AuthType") &&
+ _cups_strcasecmp(line, "Deny") &&
+ _cups_strcasecmp(line, "Order") &&
+ _cups_strcasecmp(line, "Require") &&
+ _cups_strcasecmp(line, "Satisfy"))
+ cg->cupsd_num_settings = cupsAddOption(line, value,
+ cg->cupsd_num_settings,
+ &(cg->cupsd_settings));
+ }
+
+ cupsFileClose(cupsd);
+
+ cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
+ debug_logging ? "1" : "0",
+ cg->cupsd_num_settings,
+ &(cg->cupsd_settings));
+
+ cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
+ (remote_access && remote_admin) ?
+ "1" : "0",
+ cg->cupsd_num_settings,
+ &(cg->cupsd_settings));
+
+ cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
+ remote_any ? "1" : "0",
+ cg->cupsd_num_settings,
+ &(cg->cupsd_settings));
+
+ cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
+ (browsing && browse_allow) ?
+ "1" : "0",
+ cg->cupsd_num_settings,
+ &(cg->cupsd_settings));
+
+ cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
+ (remote_access && browsing &&
+ browse_address) ? "1" : "0",
+ cg->cupsd_num_settings,
+ &(cg->cupsd_settings));
+
+ cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
+ cancel_policy ? "1" : "0",
+ cg->cupsd_num_settings,
+ &(cg->cupsd_settings));
+ }
+ else if (status != HTTP_NOT_MODIFIED)
+ invalidate_cupsd_cache(cg);
+
+ /*
+ * Remove any temporary files and copy the settings array...
+ */
+
+ if (remote)
+ unlink(cupsdconf);
+
+ for (i = cg->cupsd_num_settings, setting = cg->cupsd_settings;
+ i > 0;
+ i --, setting ++)
+ *num_settings = cupsAddOption(setting->name, setting->value,
+ *num_settings, settings);
+
+ return (cg->cupsd_num_settings > 0);
+}
+
+
+/*
+ * 'cupsAdminSetServerSettings()' - Set settings on the server.
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsAdminSetServerSettings(
+ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ int num_settings, /* I - Number of settings */
+ cups_option_t *settings) /* I - Settings */
+{
+ int i; /* Looping var */
+ http_status_t status; /* GET/PUT status */
+ const char *server_port_env; /* SERVER_PORT env var */
+ int server_port; /* IPP port for server */
+ cups_file_t *cupsd; /* cupsd.conf file */
+ char cupsdconf[1024]; /* cupsd.conf filename */
+ int remote; /* Remote cupsd.conf file? */
+ char tempfile[1024]; /* Temporary new cupsd.conf */
+ cups_file_t *temp; /* Temporary file */
+ char line[1024], /* Line from cupsd.conf file */
+ *value; /* Value on line */
+ int linenum, /* Line number in file */
+ in_location, /* In a location section? */
+ in_policy, /* In a policy section? */
+ in_default_policy, /* In the default 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? */
+ const char *val; /* Setting value */
+ int remote_printers, /* Show remote printers */
+ share_printers, /* Share local printers */
+ remote_admin, /* Remote administration allowed? */
+ remote_any, /* Remote access from anywhere? */
+ 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 */
+ int cupsd_num_settings; /* New number of settings */
+ int old_remote_printers, /* Show remote printers */
+ old_share_printers, /* Share local printers */
+ old_remote_admin, /* Remote administration allowed? */
+ old_user_cancel_any, /* Cancel-job policy set? */
+ old_debug_logging; /* LogLevel debug set? */
+ cups_option_t *cupsd_settings, /* New settings */
+ *setting; /* Current setting */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!http)
+ http = _cupsConnect();
+
+ if (!http || !num_settings || !settings)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
+
+ return (0);
+ }
+
+ /*
+ * Get the cupsd.conf file...
+ */
+
+ if (get_cupsd_conf(http, cg, 0, cupsdconf, sizeof(cupsdconf),
+ &remote) == HTTP_OK)
+ {
+ if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
+ return (0);
+ }
+ }
+ else
+ return (0);
+
+ /*
+ * Get current settings...
+ */
+
+ if (!cupsAdminGetServerSettings(http, &cupsd_num_settings,
+ &cupsd_settings))
+ return (0);
+
+ if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, cupsd_num_settings,
+ cupsd_settings)) != NULL)
+ old_debug_logging = atoi(val);
+ else
+ old_debug_logging = 0;
+
+ DEBUG_printf(("1cupsAdminSetServerSettings: old debug_logging=%d",
+ old_debug_logging));
+
+ if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, cupsd_num_settings,
+ cupsd_settings)) != NULL)
+ old_remote_admin = atoi(val);
+ else
+ old_remote_admin = 0;
+
+ DEBUG_printf(("1cupsAdminSetServerSettings: old remote_admin=%d",
+ old_remote_admin));
+
+ if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, cupsd_num_settings,
+ cupsd_settings)) != NULL)
+ remote_any = atoi(val);
+ else
+ remote_any = 0;
+
+ DEBUG_printf(("1cupsAdminSetServerSettings: old remote_any=%d",
+ remote_any));
+
+ if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, cupsd_num_settings,
+ cupsd_settings)) != NULL)
+ old_remote_printers = atoi(val);
+ else
+ old_remote_printers = 1;
+
+ DEBUG_printf(("1cupsAdminSetServerSettings: old remote_printers=%d",
+ old_remote_printers));
+
+ if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, cupsd_num_settings,
+ cupsd_settings)) != NULL)
+ old_share_printers = atoi(val);
+ else
+ old_share_printers = 0;
+
+ DEBUG_printf(("1cupsAdminSetServerSettings: old share_printers=%d",
+ old_share_printers));
+
+ if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, cupsd_num_settings,
+ cupsd_settings)) != NULL)
+ old_user_cancel_any = atoi(val);
+ else
+ old_user_cancel_any = 0;
+
+ DEBUG_printf(("1cupsAdminSetServerSettings: old user_cancel_any=%d",
+ old_user_cancel_any));
+
+ cupsFreeOptions(cupsd_num_settings, cupsd_settings);
+
+ /*
+ * Get basic settings...
+ */
+
+ if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
+ settings)) != NULL)
+ {
+ debug_logging = atoi(val);
+
+ if (debug_logging == old_debug_logging)
+ {
+ /*
+ * No change to this setting...
+ */
+
+ debug_logging = -1;
+ }
+ }
+ else
+ debug_logging = -1;
+
+ DEBUG_printf(("1cupsAdminSetServerSettings: debug_logging=%d",
+ debug_logging));
+
+ if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings,
+ settings)) != NULL)
+ remote_any = atoi(val);
+
+ DEBUG_printf(("1cupsAdminSetServerSettings: remote_any=%d",
+ remote_any));
+
+ if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
+ settings)) != NULL)
+ {
+ remote_admin = atoi(val);
+
+ if (remote_admin == old_remote_admin)
+ {
+ /*
+ * No change to this setting...
+ */
+
+ remote_admin = -1;
+ }
+ }
+ else
+ remote_admin = -1;
+
+ DEBUG_printf(("1cupsAdminSetServerSettings: remote_admin=%d",
+ remote_admin));
+
+ if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, num_settings,
+ settings)) != NULL)
+ {
+ remote_printers = atoi(val);
+
+ if (remote_printers == old_remote_printers)
+ {
+ /*
+ * No change to this setting...
+ */
+
+ remote_printers = -1;
+ }
+ }
+ else
+ remote_printers = -1;
+
+ DEBUG_printf(("1cupsAdminSetServerSettings: remote_printers=%d",
+ remote_printers));
+
+ if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
+ settings)) != NULL)
+ {
+ share_printers = atoi(val);
+
+ if (share_printers == old_share_printers)
+ {
+ /*
+ * No change to this setting...
+ */
+
+ share_printers = -1;
+ }
+ }
+ else
+ share_printers = -1;
+
+ DEBUG_printf(("1cupsAdminSetServerSettings: share_printers=%d",
+ share_printers));
+
+ if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
+ settings)) != NULL)
+ {
+ user_cancel_any = atoi(val);
+
+ if (user_cancel_any == old_user_cancel_any)
+ {
+ /*
+ * No change to this setting...
+ */
+
+ user_cancel_any = -1;
+ }
+ }
+ else
+ user_cancel_any = -1;
+
+ DEBUG_printf(("1cupsAdminSetServerSettings: user_cancel_any=%d",
+ user_cancel_any));
+
+ /*
+ * Create a temporary file for the new cupsd.conf file...
+ */
+
+ if ((temp = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL)
+ {
+ cupsFileClose(cupsd);
+
+ if (remote)
+ unlink(cupsdconf);
+
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
+ return (0);
+ }
+
+ /*
+ * Copy the old file to the new, making changes along the way...
+ */
+
+ cupsd_num_settings = 0;
+ in_admin_location = 0;
+ in_cancel_job = 0;
+ in_conf_location = 0;
+ in_default_policy = 0;
+ in_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;
+
+ if ((server_port_env = getenv("SERVER_PORT")) != NULL)
+ {
+ if ((server_port = atoi(server_port_env)) <= 0)
+ server_port = ippPort();
+ }
+ else
+ server_port = ippPort();
+
+ if (server_port <= 0)
+ server_port = IPP_PORT;
+
+ while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
+ {
+ if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")) &&
+ (remote_admin >= 0 || remote_any > 0 || share_printers >= 0))
+ {
+ if (!wrote_port_listen)
+ {
+ wrote_port_listen = 1;
+
+ if (remote_admin > 0 || remote_any > 0 || share_printers > 0)
+ {
+ cupsFilePuts(temp, "# Allow remote access\n");
+ cupsFilePrintf(temp, "Port %d\n", server_port);
+ }
+ else
+ {
+ cupsFilePuts(temp, "# Only listen for connections from the local "
+ "machine.\n");
+ cupsFilePrintf(temp, "Listen localhost:%d\n", server_port);
+ }
+
+#ifdef CUPS_DEFAULT_DOMAINSOCKET
+ if ((!value || strcmp(CUPS_DEFAULT_DOMAINSOCKET, value)) &&
+ !access(CUPS_DEFAULT_DOMAINSOCKET, 0))
+ cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n");
+#endif /* CUPS_DEFAULT_DOMAINSOCKET */
+ }
+ else if (value && value[0] == '/'
+#ifdef CUPS_DEFAULT_DOMAINSOCKET
+ && strcmp(CUPS_DEFAULT_DOMAINSOCKET, value)
+#endif /* CUPS_DEFAULT_DOMAINSOCKET */
+ )
+ cupsFilePrintf(temp, "Listen %s\n", value);
+ }
+ else if ((!_cups_strcasecmp(line, "Browsing") ||
+ !_cups_strcasecmp(line, "BrowseAddress") ||
+ !_cups_strcasecmp(line, "BrowseAllow") ||
+ !_cups_strcasecmp(line, "BrowseDeny") ||
+ !_cups_strcasecmp(line, "BrowseLocalProtocols") ||
+ !_cups_strcasecmp(line, "BrowseRemoteProtocols") ||
+ !_cups_strcasecmp(line, "BrowseOrder")) &&
+ (remote_printers >= 0 || share_printers >= 0))
+ {
+ if (!wrote_browsing)
+ {
+ int new_remote_printers = (remote_printers > 0 ||
+ (remote_printers == -1 &&
+ old_remote_printers > 0));
+ int new_share_printers = (share_printers > 0 ||
+ (share_printers == -1 &&
+ old_share_printers > 0));
+
+ wrote_browsing = 1;
+
+ if (new_remote_printers || new_share_printers)
+ {
+ const char *localp = cupsGetOption("BrowseLocalProtocols",
+ num_settings, settings);
+ const char *remotep = cupsGetOption("BrowseRemoteProtocols",
+ num_settings, settings);
+
+ if (!localp || !localp[0])
+ localp = cupsGetOption("BrowseLocalProtocols", cupsd_num_settings,
+ cupsd_settings);
+
+ if (!remotep)
+ remotep = cupsGetOption("BrowseRemoteProtocols", cupsd_num_settings,
+ cupsd_settings);
+
+ if (new_remote_printers && new_share_printers)
+ cupsFilePuts(temp,
+ "# Enable printer sharing and shared printers.\n");
+ else if (new_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 (new_remote_printers)
+ {
+ cupsFilePuts(temp, "BrowseAllow all\n");
+
+ if (!remotep)
+ remotep = CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS;
+
+ cupsFilePrintf(temp, "BrowseRemoteProtocols %s\n", remotep);
+ }
+ else
+ cupsFilePuts(temp, "BrowseRemoteProtocols\n");
+
+ cupsd_num_settings = cupsAddOption("BrowseRemoteProtocols", remotep,
+ cupsd_num_settings,
+ &cupsd_settings);
+
+ if (new_share_printers)
+ {
+ cupsFilePuts(temp, "BrowseAddress @LOCAL\n");
+
+ if (!localp)
+ localp = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS;
+
+ cupsFilePrintf(temp, "BrowseLocalProtocols %s\n", localp);
+ }
+ else
+ cupsFilePuts(temp, "BrowseLocalProtocols\n");
+
+ cupsd_num_settings = cupsAddOption("BrowseLocalProtocols", localp,
+ cupsd_num_settings,
+ &cupsd_settings);
+ }
+ else
+ {
+ cupsFilePuts(temp,
+ "# Disable printer sharing and shared printers.\n");
+ cupsFilePuts(temp, "Browsing Off\n");
+ }
+ }
+ }
+ else if (!_cups_strcasecmp(line, "LogLevel") && debug_logging >= 0)
+ {
+ 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 " CUPS_DEFAULT_LOG_LEVEL "\n");
+ }
+ }
+ else if (!_cups_strcasecmp(line, "<Policy"))
+ {
+ in_default_policy = !_cups_strcasecmp(value, "default");
+ in_policy = 1;
+
+ cupsFilePrintf(temp, "%s %s>\n", line, value);
+ indent += 2;
+ }
+ else if (!_cups_strcasecmp(line, "</Policy>"))
+ {
+ indent -= 2;
+ if (!wrote_policy && in_default_policy)
+ {
+ wrote_policy = 1;
+
+ if (!user_cancel_any)
+ cupsFilePuts(temp, " # Only the owner or an administrator can "
+ "cancel a job...\n"
+ " <Limit Cancel-Job>\n"
+ " Order deny,allow\n"
+ " Require user @OWNER "
+ CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n"
+ " </Limit>\n");
+ }
+
+ in_policy = 0;
+ in_default_policy = 0;
+
+ cupsFilePuts(temp, "</Policy>\n");
+ }
+ else if (!_cups_strcasecmp(line, "<Location"))
+ {
+ in_location = 1;
+ indent += 2;
+ if (!strcmp(value, "/admin"))
+ in_admin_location = 1;
+ if (!strcmp(value, "/admin/conf"))
+ in_conf_location = 1;
+ else if (!strcmp(value, "/"))
+ in_root_location = 1;
+
+ cupsFilePrintf(temp, "%s %s>\n", line, value);
+ }
+ else if (!_cups_strcasecmp(line, "</Location>"))
+ {
+ in_location = 0;
+ indent -= 2;
+ if (in_admin_location && remote_admin >= 0)
+ {
+ wrote_admin_location = 1;
+
+ if (remote_admin)
+ cupsFilePuts(temp, " # Allow remote administration...\n");
+ else if (remote_admin == 0)
+ cupsFilePuts(temp, " # Restrict access to the admin pages...\n");
+
+ cupsFilePuts(temp, " Order allow,deny\n");
+
+ if (remote_admin)
+ cupsFilePrintf(temp, " Allow %s\n",
+ remote_any > 0 ? "all" : "@LOCAL");
+ }
+ else if (in_conf_location && remote_admin >= 0)
+ {
+ 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)
+ cupsFilePrintf(temp, " Allow %s\n",
+ remote_any > 0 ? "all" : "@LOCAL");
+ }
+ else if (in_root_location &&
+ (remote_admin >= 0 || remote_any > 0 || share_printers >= 0))
+ {
+ wrote_root_location = 1;
+
+ if (remote_admin > 0 && share_printers > 0)
+ cupsFilePuts(temp, " # Allow shared printing and remote "
+ "administration...\n");
+ else if (remote_admin > 0)
+ cupsFilePuts(temp, " # Allow remote administration...\n");
+ else if (share_printers > 0)
+ cupsFilePuts(temp, " # Allow shared printing...\n");
+ else if (remote_any > 0)
+ cupsFilePuts(temp, " # Allow remote access...\n");
+ else
+ cupsFilePuts(temp, " # Restrict access to the server...\n");
+
+ cupsFilePuts(temp, " Order allow,deny\n");
+
+ if (remote_admin > 0 || remote_any > 0 || share_printers > 0)
+ cupsFilePrintf(temp, " Allow %s\n",
+ remote_any > 0 ? "all" : "@LOCAL");
+ }
+
+ in_admin_location = 0;
+ in_conf_location = 0;
+ in_root_location = 0;
+
+ cupsFilePuts(temp, "</Location>\n");
+ }
+ else if (!_cups_strcasecmp(line, "<Limit"))
+ {
+ if (in_default_policy)
+ {
+ /*
+ * See if the policy limit is for the Cancel-Job operation...
+ */
+
+ char *valptr; /* Pointer into value */
+
+
+ if (!_cups_strcasecmp(value, "cancel-job") && user_cancel_any >= 0)
+ {
+ /*
+ * Don't write anything for this limit section...
+ */
+
+ in_cancel_job = 2;
+ }
+ else
+ {
+ cupsFilePrintf(temp, "%*s%s", indent, "", line);
+
+ while (*value)
+ {
+ for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++);
+
+ if (*valptr)
+ *valptr++ = '\0';
+
+ if (!_cups_strcasecmp(value, "cancel-job") && user_cancel_any >= 0)
+ {
+ /*
+ * Write everything except for this definition...
+ */
+
+ in_cancel_job = 1;
+ }
+ else
+ cupsFilePrintf(temp, " %s", value);
+
+ for (value = valptr; _cups_isspace(*value); value ++);
+ }
+
+ cupsFilePuts(temp, ">\n");
+ }
+ }
+ else
+ cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value);
+
+ indent += 2;
+ }
+ else if (!_cups_strcasecmp(line, "</Limit>") && in_cancel_job)
+ {
+ indent -= 2;
+
+ if (in_cancel_job == 1)
+ cupsFilePuts(temp, " </Limit>\n");
+
+ wrote_policy = 1;
+
+ if (!user_cancel_any)
+ cupsFilePuts(temp, " # Only the owner or an administrator can cancel "
+ "a job...\n"
+ " <Limit Cancel-Job>\n"
+ " Order deny,allow\n"
+ " Require user @OWNER "
+ CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n"
+ " </Limit>\n");
+
+ in_cancel_job = 0;
+ }
+ else if ((((in_admin_location || in_conf_location || in_root_location) &&
+ (remote_admin >= 0 || remote_any > 0)) ||
+ (in_root_location && share_printers >= 0)) &&
+ (!_cups_strcasecmp(line, "Allow") || !_cups_strcasecmp(line, "Deny") ||
+ !_cups_strcasecmp(line, "Order")))
+ continue;
+ else if (in_cancel_job == 2)
+ continue;
+ 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 (!in_policy && !in_location &&
+ (val = cupsGetOption(line, num_settings, settings)) != NULL)
+ {
+ /*
+ * Replace this directive's value with the new one...
+ */
+
+ cupsd_num_settings = cupsAddOption(line, val, cupsd_num_settings,
+ &cupsd_settings);
+
+ /*
+ * Write the new value in its place, without indentation since we
+ * only support setting root directives, not in sections...
+ */
+
+ cupsFilePrintf(temp, "%s %s\n", line, val);
+ }
+ else if (value)
+ {
+ if (!in_policy && !in_location)
+ {
+ /*
+ * Record the non-policy, non-location directives that we find
+ * in the server settings, since we cache this info and record it
+ * in cupsAdminGetServerSettings()...
+ */
+
+ cupsd_num_settings = cupsAddOption(line, value, cupsd_num_settings,
+ &cupsd_settings);
+ }
+
+ cupsFilePrintf(temp, "%*s%s %s\n", indent, "", line, value);
+ }
+ else
+ cupsFilePrintf(temp, "%*s%s\n", indent, "", line);
+ }
+
+ /*
+ * Write any missing info...
+ */
+
+ if (!wrote_browsing && (remote_printers >= 0 || share_printers >= 0))
+ {
+ if (remote_printers > 0 || share_printers > 0)
+ {
+ if (remote_printers > 0 && share_printers > 0)
+ cupsFilePuts(temp, "# Enable printer sharing and shared printers.\n");
+ else if (remote_printers > 0)
+ 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 > 0)
+ cupsFilePuts(temp, "BrowseAllow all\n");
+
+ if (share_printers > 0)
+ cupsFilePuts(temp, "BrowseAddress @LOCAL\n");
+ }
+ else
+ {
+ cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n");
+ cupsFilePuts(temp, "Browsing Off\n");
+ }
+ }
+
+ if (!wrote_loglevel && debug_logging >= 0)
+ {
+ 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 " CUPS_DEFAULT_LOG_LEVEL "\n");
+ }
+ }
+
+ if (!wrote_port_listen &&
+ (remote_admin >= 0 || remote_any > 0 || share_printers >= 0))
+ {
+ if (remote_admin > 0 || remote_any > 0 || share_printers > 0)
+ {
+ cupsFilePuts(temp, "# Allow remote access\n");
+ cupsFilePrintf(temp, "Port %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
+ if (!access(CUPS_DEFAULT_DOMAINSOCKET, 0))
+ cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n");
+#endif /* CUPS_DEFAULT_DOMAINSOCKET */
+ }
+
+ if (!wrote_root_location &&
+ (remote_admin >= 0 || remote_any > 0 || share_printers >= 0))
+ {
+ if (remote_admin > 0 && share_printers > 0)
+ cupsFilePuts(temp,
+ "# Allow shared printing and remote administration...\n");
+ else if (remote_admin > 0)
+ cupsFilePuts(temp, "# Allow remote administration...\n");
+ else if (share_printers > 0)
+ cupsFilePuts(temp, "# Allow shared printing...\n");
+ else if (remote_any > 0)
+ cupsFilePuts(temp, "# Allow remote access...\n");
+ else
+ cupsFilePuts(temp, "# Restrict access to the server...\n");
+
+ cupsFilePuts(temp, "<Location />\n"
+ " Order allow,deny\n");
+
+ if (remote_admin > 0 || remote_any > 0 || share_printers > 0)
+ cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL");
+
+ cupsFilePuts(temp, "</Location>\n");
+ }
+
+ if (!wrote_admin_location && remote_admin >= 0)
+ {
+ if (remote_admin)
+ cupsFilePuts(temp, "# Allow remote administration...\n");
+ else
+ cupsFilePuts(temp, "# Restrict access to the admin pages...\n");
+
+ cupsFilePuts(temp, "<Location /admin>\n"
+ " Order allow,deny\n");
+
+ if (remote_admin)
+ cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL");
+
+ cupsFilePuts(temp, "</Location>\n");
+ }
+
+ if (!wrote_conf_location && remote_admin >= 0)
+ {
+ 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, "<Location /admin/conf>\n"
+ " AuthType Default\n"
+ " Require user @SYSTEM\n"
+ " Order allow,deny\n");
+
+ if (remote_admin)
+ cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL");
+
+ cupsFilePuts(temp, "</Location>\n");
+ }
+
+ if (!wrote_policy && user_cancel_any >= 0)
+ {
+ cupsFilePuts(temp, "<Policy default>\n"
+ " # Job-related operations must be done by the owner "
+ "or an administrator...\n"
+ " <Limit Send-Document Send-URI Hold-Job Release-Job "
+ "Restart-Job Purge-Jobs Set-Job-Attributes "
+ "Create-Job-Subscription Renew-Subscription "
+ "Cancel-Subscription Get-Notifications Reprocess-Job "
+ "Cancel-Current-Job Suspend-Current-Job Resume-Job "
+ "CUPS-Move-Job>\n"
+ " Require user @OWNER @SYSTEM\n"
+ " Order deny,allow\n"
+ " </Limit>\n"
+ " # All administration operations require an "
+ "administrator to authenticate...\n"
+ " <Limit Pause-Printer Resume-Printer "
+ "Set-Printer-Attributes Enable-Printer "
+ "Disable-Printer Pause-Printer-After-Current-Job "
+ "Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer "
+ "Activate-Printer Restart-Printer Shutdown-Printer "
+ "Startup-Printer Promote-Job Schedule-Job-After "
+ "CUPS-Add-Printer CUPS-Delete-Printer "
+ "CUPS-Add-Class CUPS-Delete-Class "
+ "CUPS-Accept-Jobs CUPS-Reject-Jobs "
+ "CUPS-Set-Default CUPS-Add-Device CUPS-Delete-Device>\n"
+ " AuthType Default\n"
+ " Require user @SYSTEM\n"
+ " Order deny,allow\n"
+ "</Limit>\n");
+
+ if (!user_cancel_any)
+ cupsFilePuts(temp, " # Only the owner or an administrator can cancel "
+ "a job...\n"
+ " <Limit Cancel-Job>\n"
+ " Order deny,allow\n"
+ " Require user @OWNER "
+ CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n"
+ " </Limit>\n");
+
+ cupsFilePuts(temp, " <Limit All>\n"
+ " Order deny,allow\n"
+ " </Limit>\n"
+ "</Policy>\n");
+ }
+
+ for (i = num_settings, setting = settings; i > 0; i --, setting ++)
+ if (setting->name[0] != '_' &&
+ _cups_strcasecmp(setting->name, "Listen") &&
+ _cups_strcasecmp(setting->name, "Port") &&
+ !cupsGetOption(setting->name, cupsd_num_settings, cupsd_settings))
+ {
+ /*
+ * Add this directive to the list of directives we have written...
+ */
+
+ cupsd_num_settings = cupsAddOption(setting->name, setting->value,
+ cupsd_num_settings, &cupsd_settings);
+
+ /*
+ * Write the new value, without indentation since we only support
+ * setting root directives, not in sections...
+ */
+
+ cupsFilePrintf(temp, "%s %s\n", setting->name, setting->value);
+ }
+
+ cupsFileClose(cupsd);
+ cupsFileClose(temp);
+
+ /*
+ * Upload the configuration file to the server...
+ */
+
+ status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
+
+ if (status == HTTP_CREATED)
+ {
+ /*
+ * Updated OK, add the basic settings...
+ */
+
+ if (debug_logging >= 0)
+ cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
+ debug_logging ? "1" : "0",
+ cupsd_num_settings, &cupsd_settings);
+ else
+ cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
+ old_debug_logging ? "1" : "0",
+ cupsd_num_settings, &cupsd_settings);
+
+ if (remote_admin >= 0)
+ cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
+ remote_admin ? "1" : "0",
+ cupsd_num_settings, &cupsd_settings);
+ else
+ cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
+ old_remote_admin ? "1" : "0",
+ cupsd_num_settings, &cupsd_settings);
+
+ cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
+ remote_any ? "1" : "0",
+ cupsd_num_settings, &cupsd_settings);
+
+ if (remote_printers >= 0)
+ cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
+ remote_printers ? "1" : "0",
+ cupsd_num_settings, &cupsd_settings);
+ else
+ cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS,
+ old_remote_printers ? "1" : "0",
+ cupsd_num_settings, &cupsd_settings);
+
+ if (share_printers >= 0)
+ cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
+ share_printers ? "1" : "0",
+ cupsd_num_settings, &cupsd_settings);
+ else
+ cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
+ old_share_printers ? "1" : "0",
+ cupsd_num_settings, &cupsd_settings);
+
+ if (user_cancel_any >= 0)
+ cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
+ user_cancel_any ? "1" : "0",
+ cupsd_num_settings, &cupsd_settings);
+ else
+ cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
+ old_user_cancel_any ? "1" : "0",
+ cupsd_num_settings, &cupsd_settings);
+
+ /*
+ * Save the new values...
+ */
+
+ invalidate_cupsd_cache(cg);
+
+ cg->cupsd_num_settings = cupsd_num_settings;
+ cg->cupsd_settings = cupsd_settings;
+ cg->cupsd_update = time(NULL);
+
+ httpGetHostname(http, cg->cupsd_hostname, sizeof(cg->cupsd_hostname));
+ }
+ else
+ cupsFreeOptions(cupsd_num_settings, cupsd_settings);
+
+ /*
+ * Remote our temp files and return...
+ */
+
+ if (remote)
+ unlink(cupsdconf);
+
+ unlink(tempfile);
+
+ return (status == HTTP_CREATED);
+}
+
+
+/*
+ * 'do_samba_command()' - Do a SAMBA command.
+ */
+
+static int /* O - Status of command */
+do_samba_command(const char *command, /* I - Command to run */
+ const char *address, /* I - Address for command */
+ const char *subcmd, /* I - Sub-command */
+ const char *authfile, /* I - Samba authentication file */
+ FILE *logfile) /* I - Optional log file */
+{
+#ifdef WIN32
+ return (1); /* Always fail on Windows... */
+
+#else
+ int status; /* Status of command */
+ int pid; /* Process ID of child */
+
+
+ if (logfile)
+ _cupsLangPrintf(logfile,
+ _("Running command: %s %s -N -A %s -c \'%s\'"),
+ command, address, authfile, subcmd);
+
+ if ((pid = fork()) == 0)
+ {
+ /*
+ * Child goes here, redirect stdin/out/err and execute the command...
+ */
+
+ int fd = open("/dev/null", O_RDONLY);
+
+ if (fd > 0)
+ {
+ dup2(fd, 0);
+ close(fd);
+ }
+
+ if (logfile)
+ dup2(fileno(logfile), 1);
+ else if ((fd = open("/dev/null", O_WRONLY)) > 1)
+ {
+ dup2(fd, 1);
+ close(fd);
+ }
+
+ dup2(1, 2);
+
+ execlp(command, command, address, "-N", "-A", authfile, "-c", subcmd,
+ (char *)0);
+ exit(errno);
+ }
+ else if (pid < 0)
+ {
+ status = -1;
+
+ if (logfile)
+ _cupsLangPrintf(logfile, _("Unable to run \"%s\": %s"),
+ command, strerror(errno));
+ }
+ else
+ {
+ /*
+ * Wait for the process to complete...
+ */
+
+ while (wait(&status) != pid);
+ }
+
+ if (logfile)
+ _cupsLangPuts(logfile, "");
+
+ DEBUG_printf(("9do_samba_command: status=%d", status));
+
+ if (WIFEXITED(status))
+ return (WEXITSTATUS(status));
+ else
+ return (-WTERMSIG(status));
+#endif /* WIN32 */
+}
+
+
+/*
+ * 'get_cupsd_conf()' - Get the current cupsd.conf file.
+ */
+
+static http_status_t /* O - Status of request */
+get_cupsd_conf(
+ http_t *http, /* I - Connection to server */
+ _cups_globals_t *cg, /* I - Global data */
+ time_t last_update, /* I - Last update time for file */
+ char *name, /* I - Filename buffer */
+ int namesize, /* I - Size of filename buffer */
+ int *remote) /* O - Remote file? */
+{
+ int fd; /* Temporary file descriptor */
+#ifndef WIN32
+ struct stat info; /* cupsd.conf file information */
+#endif /* WIN32 */
+ http_status_t status; /* Status of getting cupsd.conf */
+ char host[HTTP_MAX_HOST]; /* Hostname for connection */
+
+
+ /*
+ * See if we already have the data we need...
+ */
+
+ httpGetHostname(http, host, sizeof(host));
+
+ if (_cups_strcasecmp(cg->cupsd_hostname, host))
+ invalidate_cupsd_cache(cg);
+
+ snprintf(name, namesize, "%s/cupsd.conf", cg->cups_serverroot);
+ *remote = 0;
+
+#ifndef WIN32
+ if (!_cups_strcasecmp(host, "localhost") && !access(name, R_OK))
+ {
+ /*
+ * Read the local file rather than using HTTP...
+ */
+
+ if (stat(name, &info))
+ {
+ char message[1024]; /* Message string */
+
+
+ snprintf(message, sizeof(message),
+ _cupsLangString(cupsLangDefault(), _("stat of %s failed: %s")),
+ name, strerror(errno));
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
+
+ *name = '\0';
+
+ return (HTTP_SERVER_ERROR);
+ }
+ else if (last_update && info.st_mtime <= last_update)
+ status = HTTP_NOT_MODIFIED;
+ else
+ status = HTTP_OK;
+ }
+ else
+#endif /* !WIN32 */
+ {
+ /*
+ * Read cupsd.conf via a HTTP GET request...
+ */
+
+ if ((fd = cupsTempFd(name, namesize)) < 0)
+ {
+ *name = '\0';
+
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
+
+ invalidate_cupsd_cache(cg);
+
+ return (HTTP_SERVER_ERROR);
+ }
+
+ *remote = 1;
+
+ httpClearFields(http);
+
+ if (last_update)
+ httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE,
+ httpGetDateString(last_update));
+
+ status = cupsGetFd(http, "/admin/conf/cupsd.conf", fd);
+
+ close(fd);
+
+ if (status != HTTP_OK)
+ {
+ unlink(name);
+ *name = '\0';
+ }
+ }
+
+ return (status);
+}
+
+
+/*
+ * 'invalidate_cupsd_cache()' - Invalidate the cached cupsd.conf settings.
+ */
+
+static void
+invalidate_cupsd_cache(
+ _cups_globals_t *cg) /* I - Global data */
+{
+ cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings);
+
+ cg->cupsd_hostname[0] = '\0';
+ cg->cupsd_update = 0;
+ cg->cupsd_num_settings = 0;
+ cg->cupsd_settings = NULL;
+}
+
+
+/*
+ * 'write_option()' - Write a CUPS option to a PPD file.
+ */
+
+static void
+write_option(cups_file_t *dstfp, /* I - PPD file */
+ int order, /* I - Order dependency */
+ const char *name, /* I - Option name */
+ const char *text, /* I - Option text */
+ const char *attrname, /* I - Attribute name */
+ ipp_attribute_t *suppattr, /* I - IPP -supported attribute */
+ ipp_attribute_t *defattr, /* I - IPP -default attribute */
+ int defval, /* I - Default value number */
+ int valcount) /* I - Number of values */
+{
+ int i; /* Looping var */
+
+
+ cupsFilePrintf(dstfp, "*JCLOpenUI *%s/%s: PickOne\n"
+ "*OrderDependency: %d JCLSetup *%s\n",
+ name, text, order, name);
+
+ if (defattr->value_tag == IPP_TAG_INTEGER)
+ {
+ /*
+ * Do numeric options with a range or list...
+ */
+
+ cupsFilePrintf(dstfp, "*Default%s: %d\n", name,
+ defattr->values[defval].integer);
+
+ if (suppattr->value_tag == IPP_TAG_RANGE)
+ {
+ /*
+ * List each number in the range...
+ */
+
+ for (i = suppattr->values[0].range.lower;
+ i <= suppattr->values[0].range.upper;
+ i ++)
+ {
+ cupsFilePrintf(dstfp, "*%s %d: \"", name, i);
+
+ if (valcount == 1)
+ cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\n\"\n*End\n",
+ attrname, i);
+ else if (defval == 0)
+ cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\"\n", attrname, i);
+ else if (defval < (valcount - 1))
+ cupsFilePrintf(dstfp, ",%d\"\n", i);
+ else
+ cupsFilePrintf(dstfp, ",%d\n\"\n*End\n", i);
+ }
+ }
+ else
+ {
+ /*
+ * List explicit numbers...
+ */
+
+ for (i = 0; i < suppattr->num_values; i ++)
+ {
+ cupsFilePrintf(dstfp, "*%s %d: \"", name, suppattr->values[i].integer);
+
+ if (valcount == 1)
+ cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\n\"\n*End\n", attrname,
+ suppattr->values[i].integer);
+ else if (defval == 0)
+ cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\"\n", attrname,
+ suppattr->values[i].integer);
+ else if (defval < (valcount - 1))
+ cupsFilePrintf(dstfp, ",%d\"\n", suppattr->values[i].integer);
+ else
+ cupsFilePrintf(dstfp, ",%d\n\"\n*End\n", suppattr->values[i].integer);
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Do text options with a list...
+ */
+
+ cupsFilePrintf(dstfp, "*Default%s: %s\n", name,
+ defattr->values[defval].string.text);
+
+ for (i = 0; i < suppattr->num_values; i ++)
+ {
+ cupsFilePrintf(dstfp, "*%s %s: \"", name,
+ suppattr->values[i].string.text);
+
+ if (valcount == 1)
+ cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%s\n\"\n*End\n", attrname,
+ suppattr->values[i].string.text);
+ else if (defval == 0)
+ cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%s\"\n", attrname,
+ suppattr->values[i].string.text);
+ else if (defval < (valcount - 1))
+ cupsFilePrintf(dstfp, ",%s\"\n", suppattr->values[i].string.text);
+ else
+ cupsFilePrintf(dstfp, ",%s\n\"\n*End\n",
+ suppattr->values[i].string.text);
+ }
+ }
+
+ cupsFilePrintf(dstfp, "*JCLCloseUI: *%s\n\n", name);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/adminutil.h b/cups/adminutil.h
new file mode 100644
index 000000000..89119a11a
--- /dev/null
+++ b/cups/adminutil.h
@@ -0,0 +1,78 @@
+/*
+ * "$Id$"
+ *
+ * Administration utility API definitions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2001-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_ADMINUTIL_H_
+# define _CUPS_ADMINUTIL_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include <stdio.h>
+# include "cups.h"
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Constants...
+ */
+
+# define CUPS_SERVER_DEBUG_LOGGING "_debug_logging"
+# define CUPS_SERVER_REMOTE_ADMIN "_remote_admin"
+# define CUPS_SERVER_REMOTE_ANY "_remote_any"
+# define CUPS_SERVER_REMOTE_PRINTERS "_remote_printers"
+# define CUPS_SERVER_SHARE_PRINTERS "_share_printers"
+# define CUPS_SERVER_USER_CANCEL_ANY "_user_cancel_any"
+
+
+/*
+ * Functions...
+ */
+
+extern int cupsAdminExportSamba(const char *dest, const char *ppd,
+ const char *samba_server,
+ const char *samba_user,
+ const char *samba_password,
+ FILE *logfile) _CUPS_API_1_2;
+extern char *cupsAdminCreateWindowsPPD(http_t *http, const char *dest,
+ char *buffer, int bufsize) _CUPS_API_1_2;
+
+extern int cupsAdminGetServerSettings(http_t *http,
+ int *num_settings,
+ cups_option_t **settings) _CUPS_API_1_3;
+extern int cupsAdminSetServerSettings(http_t *http,
+ int num_settings,
+ cups_option_t *settings) _CUPS_API_1_3;
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_ADMINUTIL_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/api-array.header b/cups/api-array.header
new file mode 100644
index 000000000..88e5341f8
--- /dev/null
+++ b/cups/api-array.header
@@ -0,0 +1,34 @@
+<!--
+ "$Id: api-array.header 9771 2011-05-12 05:21:56Z mike $"
+
+ Array API header for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Array API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/array.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcups</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/cups/api-array.shtml b/cups/api-array.shtml
new file mode 100644
index 000000000..7406a0d45
--- /dev/null
+++ b/cups/api-array.shtml
@@ -0,0 +1,196 @@
+<!--
+ "$Id: api-array.shtml 9727 2011-04-28 21:20:12Z mike $"
+
+ Array API introduction for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>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.
+Sorted arrays use a binary search algorithm from the last found or inserted
+element to quickly find matching elements in the array. Arrays created with the
+optional hash function can often find elements with a single lookup. The
+<a href='#cups_array_t'><code>cups_array_t</code></a> type is used when
+referring to a CUPS array.</p>
+
+<p>The CUPS scheduler (<tt>cupsd</tt>) and many of the CUPS API
+functions use the array API to efficiently manage large lists of
+data.</p>
+
+<h3><a name='MANAGING_ARRAYS'>Managing Arrays</a></h3>
+
+<p>Arrays are created using either the
+<a href='#cupsArrayNew'><code>cupsArrayNew</code></a>,
+<a href='#cupsArrayNew2'><code>cupsArrayNew2</code></a>, or
+<a href='#cupsArrayNew2'><code>cupsArrayNew3</code></a> functions. The
+first function creates a new array with the specified callback function
+and user data pointer:</p>
+
+<pre class='example'>
+#include &lt;cups/array.h&gt;
+
+static int compare_func(void *first, void *second, void *user_data);
+
+void *user_data;
+<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>(compare_func, user_data);
+</pre>
+
+<p>The comparison function (type
+<a href="#cups_arrayfunc_t"><code>cups_arrayfunc_t</code></a>) is called
+whenever an element is added to the array and can be <code>NULL</code> to
+create an unsorted array. The function returns -1 if the first element should
+come before the second, 0 if the first and second elements should have the same
+ordering, and 1 if the first element should come after the second.</p>
+
+<p>The "user_data" pointer is passed to your comparison function. Pass
+<code>NULL</code> if you do not need to associate the elements in your array
+with additional information.</p>
+
+<p>The <a href='#cupsArrayNew2'><code>cupsArrayNew2</code></a> function adds
+two more arguments to support hashed lookups, which can potentially provide
+instantaneous ("O(1)") lookups in your array:</p>
+
+<pre class='example'>
+#include &lt;cups/array.h&gt;
+
+#define HASH_SIZE 512 /* Size of hash table */
+
+static int compare_func(void *first, void *second, void *user_data);
+static int hash_func(void *element, void *user_data);
+
+void *user_data;
+<a href='#cups_array_t'>cups_array_t</a> *hash_array = <a href='#cupsArrayNew2'>cupsArrayNew2</a>(compare_func, user_data, hash_func, HASH_SIZE);
+</pre>
+
+<p>The hash function (type
+<a href="#cups_ahash_func_t"><code>cups_ahash_func_t</code></a>) should return a
+number from 0 to (hash_size-1) that (hopefully) uniquely identifies the
+element and is called whenever you look up an element in the array with
+<a href='#cupsArrayFind'><code>cupsArrayFind</code></a>. The hash size is
+only limited by available memory, but generally should not be larger than
+16384 to realize any performance improvement.</p>
+
+<p>The <a href='#cupsArrayNew3'><code>cupsArrayNew3</code></a> function adds
+copy and free callbacks to support basic memory management of elements:</p>
+
+<pre class='example'>
+#include &lt;cups/array.h&gt;
+
+#define HASH_SIZE 512 /* Size of hash table */
+
+static int compare_func(void *first, void *second, void *user_data);
+static void *copy_func(void *element, void *user_data);
+static void free_func(void *element, void *user_data);
+static int hash_func(void *element, void *user_data);
+
+void *user_data;
+<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew3'>cupsArrayNew3</a>(compare_func, user_data, NULL, 0, copy_func, free_func);
+
+<a href='#cups_array_t'>cups_array_t</a> *hash_array = <a href='#cupsArrayNew3'>cupsArrayNew3</a>(compare_func, user_data, hash_func, HASH_SIZE, copy_func, free_func);
+</pre>
+
+<p>Once you have created the array, you add elements using the
+<a href='#cupsArrayAdd'><code>cupsArrayAdd</code></a>
+<a href='#cupsArrayInsert'><code>cupsArrayInsert</code></a> functions.
+The first function adds an element to the array, adding the new element
+after any elements that have the same order, while the second inserts the
+element before others with the same order. For unsorted arrays,
+<a href='#cupsArrayAdd'><code>cupsArrayAdd</code></a> appends the element to
+the end of the array while
+<a href='#cupsArrayInsert'><code>cupsArrayInsert</code></a> inserts the
+element at the beginning of the array. For example, the following code
+creates a sorted array of character strings:</p>
+
+<pre class='example'>
+#include &lt;cups/array.h&gt;
+
+/* Use strcmp() to compare strings - it will ignore the user_data pointer */
+<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>((<a href='#cups_array_func_t'>cups_array_func_t</a>)strcmp, NULL);
+
+/* Add four strings to the array */
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "One Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Two Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Red Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Blue Fish");
+</pre>
+
+<p>Elements are removed using the
+<a href='#cupsArrayRemove'><code>cupsArrayRemove</code></a> function, for
+example:</p>
+
+<pre class='example'>
+#include &lt;cups/array.h&gt;
+
+/* Use strcmp() to compare strings - it will ignore the user_data pointer */
+<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>((<a href='#cups_array_func_t'>cups_array_func_t</a>)strcmp, NULL);
+
+/* Add four strings to the array */
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "One Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Two Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Red Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Blue Fish");
+
+/* Remove "Red Fish" */
+<a href='#cupsArrayRemove'>cupsArrayRemove</a>(array, "Red Fish");
+</pre>
+
+<p>Finally, you free the memory used by the array using the
+<a href='#cupsArrayDelete'><code>cupsArrayDelete</code></a> function. All
+of the memory for the array and hash table (if any) is freed, however <em>CUPS
+does not free the elements unless you provide copy and free functions</em>.</p>
+
+<h3><a name='FINDING_AND_ENUMERATING'>Finding and Enumerating Elements</a></h3>
+
+<p>CUPS provides several functions to find and enumerate elements in an
+array. Each one sets or updates a "current index" into the array, such that
+future lookups will start where the last one left off:</p>
+
+<dl>
+ <dt><a href='#cupsArrayFind'><code>cupsArrayFind</code></a></dt>
+ <dd>Returns the first matching element.</dd>
+ <dt><a href='#cupsArrayFirst'><code>cupsArrayFirst</code></a></dt>
+ <dd>Returns the first element in the array.</dd>
+ <dt><a href='#cupsArrayIndex'><code>cupsArrayIndex</code></a></dt>
+ <dd>Returns the Nth element in the array, starting at 0.</dd>
+ <dt><a href='#cupsArrayLast'><code>cupsArrayLast</code></a></dt>
+ <dd>Returns the last element in the array.</dd>
+ <dt><a href='#cupsArrayNext'><code>cupsArrayNext</code></a></dt>
+ <dd>Returns the next element in the array.</dd>
+ <dt><a href='#cupsArrayPrev'><code>cupsArrayPrev</code></a></dt>
+ <dd>Returns the previous element in the array.</dd>
+</dl>
+
+<p>Each of these functions returns <code>NULL</code> when there is no
+corresponding element. For example, a simple <code>for</code> loop using the
+<a href='#cupsArrayFirst'><code>cupsArrayFirst</code></a> and
+<a href='#cupsArrayNext'><code>cupsArrayNext</code></a> functions will
+enumerate all of the strings in our previous example:</p>
+
+<pre class='example'>
+#include &lt;cups/array.h&gt;
+
+/* Use strcmp() to compare strings - it will ignore the user_data pointer */
+<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>((<a href='#cups_array_func_t'>cups_array_func_t</a>)strcmp, NULL);
+
+/* Add four strings to the array */
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "One Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Two Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Red Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Blue Fish");
+
+/* Show all of the strings in the array */
+char *s;
+for (s = (char *)<a href='#cupsArrayFirst'>cupsArrayFirst</a>(array); s != NULL; s = (char *)<a href='#cupsArrayNext'>cupsArrayNext</a>(array))
+ puts(s);
+</pre>
diff --git a/cups/api-cups.header b/cups/api-cups.header
new file mode 100644
index 000000000..8e6d3c0b5
--- /dev/null
+++ b/cups/api-cups.header
@@ -0,0 +1,40 @@
+<!--
+ "$Id: api-cups.header 9771 2011-05-12 05:21:56Z mike $"
+
+ CUPS API header for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>CUPS API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/cups.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcups</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a><br>
+ Programming: <a href='api-array.html' target='_top'>Array API</a><br>
+ Programming: <a href='api-filedir.html' target='_top'>File and Directory APIs</a><br>
+ Programming: <a href='api-filter.html' target='_top'>Filter and Backend Programming</a><br>
+ Programming: <a href='api-httpipp.html' target='_top'>HTTP and IPP APIs</a><br>
+ Programming: <a href='api-ppd.html' target='_top'>PPD API</a><br>
+ Programming: <a href='api-raster.html' target='_top'>Raster API</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/cups/api-cups.shtml b/cups/api-cups.shtml
new file mode 100644
index 000000000..dcc4fe98a
--- /dev/null
+++ b/cups/api-cups.shtml
@@ -0,0 +1,443 @@
+<!--
+ "$Id: api-cups.shtml 9727 2011-04-28 21:20:12Z mike $"
+
+ API introduction for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>The CUPS API provides the convenience functions needed to support
+applications, filters, printer drivers, and backends that need to interface
+with the CUPS scheduler.</p>
+
+<h3><a name='CLIENTS_AND_SERVERS'>Clients and Servers</a></h3>
+
+<p>CUPS is based on the Internet Printing Protocol ("IPP"), which allows
+clients (applications) to communicate with a server (the scheduler) to get a
+list of printers, send print jobs, and so forth. You identify which server
+you want to communicate with using a pointer to the opaque structure
+<code>http_t</code>. All of the examples in this document use the
+<code>CUPS_HTTP_DEFAULT</code> constant, referring to the default connection
+to the scheduler. The <a href='api-httpipp.html' target='_top'>HTTP and IPP
+APIs</a> document provides more information on server connections.</p>
+
+<h3><a name='PRINTERS_AND_CLASSES'>Printers and Classes</a></h3>
+
+<p>Printers and classes (collections of printers) are accessed through
+the <a href="#cups_dest_t"><code>cups_dest_t</code></a> structure which
+includes the name (<code>name</code>), instance (<code>instance</code> -
+a way of selecting certain saved options/settings), and the options and
+attributes associated with that destination (<code>num_options</code> and
+<code>options</code>). Destinations are created using the
+<a href="#cupsGetDests"><code>cupsGetDests</code></a> function and freed
+using the <a href='#cupsFreeDests'><code>cupsFreeDests</code></a> function.
+The <a href='#cupsGetDest'><code>cupsGetDest</code></a> function finds a
+specific destination for printing:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+<a href='#cups_dest_t'>cups_dest_t</a> *dests;
+int num_dests = <a href='#cupsGetDests'>cupsGetDests</a>(&amp;dests);
+<a href='#cups_dest_t'>cups_dest_t</a> *dest = <a href='#cupsGetDest'>cupsGetDest</a>("name", NULL, num_dests, dests);
+
+/* do something with dest */
+
+<a href='#cupsFreeDests'>cupsFreeDests</a>(num_dests, dests);
+</pre>
+
+<p>Passing <code>NULL</code> to
+<a href='#cupsGetDest'><code>cupsGetDest</code></a> for the destination name
+will return the default destination. Similarly, passing a <code>NULL</code>
+instance will return the default instance for that destination.</p>
+
+<div class='table'><table summary='Table 1: Printer Attributes' width='80%'>
+<caption>Table 1: <a name='TABLE1'>Printer Attributes</a></caption>
+<thead>
+<tr>
+ <th>Attribute Name</th>
+ <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>"auth-info-required"</td>
+ <td>The type of authentication required for printing to this
+ destination: "none", "username,password", "domain,username,password",
+ or "negotiate" (Kerberos)</td>
+</tr>
+<tr>
+ <td>"printer-info"</td>
+ <td>The human-readable description of the destination such as "My
+ Laser Printer".</td>
+</tr>
+<tr>
+ <td>"printer-is-accepting-jobs"</td>
+ <td>"true" if the destination is accepting new jobs, "false" if
+ not.</td>
+</tr>
+<tr>
+ <td>"printer-is-shared"</td>
+ <td>"true" if the destination is being shared with other computers,
+ "false" if not.</td>
+</tr>
+<tr>
+ <td>"printer-location"</td>
+ <td>The human-readable location of the destination such as "Lab 4".</td>
+</tr>
+<tr>
+ <td>"printer-make-and-model"</td>
+ <td>The human-readable make and model of the destination such as "HP
+ LaserJet 4000 Series".</td>
+</tr>
+<tr>
+ <td>"printer-state"</td>
+ <td>"3" if the destination is idle, "4" if the destination is printing
+ a job, and "5" if the destination is stopped.</td>
+</tr>
+<tr>
+ <td>"printer-state-change-time"</td>
+ <td>The UNIX time when the destination entered the current state.</td>
+</tr>
+<tr>
+ <td>"printer-state-reasons"</td>
+ <td>Additional comma-delimited state keywords for the destination
+ such as "media-tray-empty-error" and "toner-low-warning".</td>
+</tr>
+<tr>
+ <td>"printer-type"</td>
+ <td>The <a href='#cups_printer_t'><code>cups_printer_t</code></a>
+ value associated with the destination.</td>
+</tr>
+</tbody>
+</table></div>
+
+<h3><a name='OPTIONS'>Options</a></h3>
+
+<p>Options are stored in arrays of
+<a href='#cups_option_t'><code>cups_option_t</code></a> structures. Each
+option has a name (<code>name</code>) and value (<code>value</code>)
+associated with it. The <a href='#cups_dest_t'><code>cups_dest_t</code></a>
+<code>num_options</code> and <code>options</code> members contain the
+default options for a particular destination, along with several informational
+attributes about the destination as shown in <a href='#TABLE1'>Table 1</a>.
+The <a href='#cupsGetOption'><code>cupsGetOption</code></a> function gets
+the value for the named option. For example, the following code lists the
+available destinations and their human-readable descriptions:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+<a href='#cups_dest_t'>cups_dest_t</a> *dests;
+int num_dests = <a href='#cupsGetDests'>cupsGetDests</a>(&amp;dests);
+<a href='#cups_dest_t'>cups_dest_t</a> *dest;
+int i;
+const char *value;
+
+for (i = num_dests, dest = dests; i > 0; i --, dest ++)
+ if (dest->instance == NULL)
+ {
+ value = <a href='#cupsGetOption'>cupsGetOption</a>("printer-info", dest->num_options, dest->options);
+ printf("%s (%s)\n", dest->name, value ? value : "no description");
+ }
+
+<a href='#cupsFreeDests'>cupsFreeDests</a>(num_dests, dests);
+</pre>
+
+<p>You can create your own option arrays using the
+<a href='#cupsAddOption'><code>cupsAddOption</code></a> function, which
+adds a single named option to an array:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+int num_options = 0;
+<a href='#cups_option_t'>cups_option_t</a> *options = NULL;
+
+/* The returned num_options value is updated as needed */
+num_options = <a href='#cupsAddOption'>cupsAddOption</a>("first", "value", num_options, &amp;options);
+
+/* This adds a second option value */
+num_options = <a href='#cupsAddOption'>cupsAddOption</a>("second", "value", num_options, &amp;options);
+
+/* This replaces the first option we added */
+num_options = <a href='#cupsAddOption'>cupsAddOption</a>("first", "new value", num_options, &amp;options);
+</pre>
+
+<p>Use a <code>for</code> loop to copy the options from a destination:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+int i;
+int num_options = 0;
+<a href='#cups_option_t'>cups_option_t</a> *options = NULL;
+<a href='#cups_dest_t'>cups_dest_t</a> *dest;
+
+for (i = 0; i < dest->num_options; i ++)
+ num_options = <a href='#cupsAddOption'>cupsAddOption</a>(dest->options[i].name, dest->options[i].value,
+ num_options, &amp;options);
+</pre>
+
+<p>Use the <a href='#cupsFreeOptions'><code>cupsFreeOptions</code></a>
+function to free the options array when you are done using it:</p>
+
+<pre class='example'>
+<a href='#cupsFreeOptions'>cupsFreeOptions</a>(num_options, options);
+</pre>
+
+<h3><a name='PRINT_JOBS'>Print Jobs</a></h3>
+
+<p>Print jobs are identified by a locally-unique job ID number from 1 to
+2<sup>31</sup>-1 and have options and one or more files for printing to a
+single destination. The <a href='#cupsPrintFile'><code>cupsPrintFile</code></a>
+function creates a new job with one file. The following code prints the CUPS
+test page file:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+<a href='#cups_dest_t'>cups_dest_t</a> *dest;
+int num_options;
+<a href='#cups_option_t'>cups_option_t</a> *options;
+int job_id;
+
+/* Print a single file */
+job_id = <a href='#cupsPrintFile'>cupsPrintFile</a>(dest->name, "/usr/share/cups/data/testprint.ps",
+ "Test Print", num_options, options);
+</pre>
+
+<p>The <a href='#cupsPrintFiles'><code>cupsPrintFiles</code></a> function
+creates a job with multiple files. The files are provided in a
+<code>char *</code> array:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+<a href='#cups_dest_t'>cups_dest_t</a> *dest;
+int num_options;
+<a href='#cups_option_t'>cups_option_t</a> *options;
+int job_id;
+char *files[3] = { "file1.pdf", "file2.pdf", "file3.pdf" };
+
+/* Print three files */
+job_id = <a href='#cupsPrintFiles'>cupsPrintFiles</a>(dest->name, 3, files, "Test Print", num_options, options);
+</pre>
+
+<p>Finally, the <a href='#cupsCreateJob'><code>cupsCreateJob</code></a>
+function creates a new job with no files in it. Files are added using the
+<a href='#cupsStartDocument'><code>cupsStartDocument</code></a>,
+<a href='api-httpipp.html#cupsWriteRequestData'><code>cupsWriteRequestData</code></a>,
+and <a href='#cupsFinishDocument'><code>cupsFinishDocument</code></a> functions.
+The following example creates a job with 10 text files for printing:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+<a href='#cups_dest_t'>cups_dest_t</a> *dest;
+int num_options;
+<a href='#cups_option_t'>cups_option_t</a> *options;
+int job_id;
+int i;
+char buffer[1024];
+
+/* Create the job */
+job_id = <a href='#cupsCreateJob'>cupsCreateJob</a>(CUPS_HTTP_DEFAULT, dest->name, "10 Text Files",
+ num_options, options);
+
+/* If the job is created, add 10 files */
+if (job_id > 0)
+{
+ for (i = 1; i &lt;= 10; i ++)
+ {
+ snprintf(buffer, sizeof(buffer), "file%d.txt", i);
+
+ <a href='#cupsStartDocument'>cupsStartDocument</a>(CUPS_HTTP_DEFAULT, dest->name, job_id, buffer,
+ CUPS_FORMAT_TEXT, i == 10);
+
+ snprintf(buffer, sizeof(buffer),
+ "File %d\n"
+ "\n"
+ "One fish,\n"
+ "Two fish,\n
+ "Red fish,\n
+ "Blue fish\n", i);
+
+ /* cupsWriteRequestData can be called as many times as needed */
+ <a href='#cupsWriteRequestData'>cupsWriteRequestData</a>(CUPS_HTTP_DEFAULT, buffer, strlen(buffer));
+
+ <a href='#cupsFinishDocument'>cupsFinishDocument</a>(CUPS_HTTP_DEFAULT, dest->name);
+ }
+}
+</pre>
+
+<p>Once you have created a job, you can monitor its status using the
+<a href='#cupsGetJobs'><code>cupsGetJobs</code></a> function, which returns
+an array of <a href='#cups_job_t'><code>cups_job_t</code></a> structures.
+Each contains the job ID (<code>id</code>), destination name
+(<code>dest</code>), title (<code>title</code>), and other information
+associated with the job. The job array is freed using the
+<a href='#cupsFreeJobs'><code>cupsFreeJobs</code></a> function. The following
+example monitors a specific job ID, showing the current job state once every
+5 seconds until the job is completed:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+<a href='#cups_dest_t'>cups_dest_t</a> *dest;
+int job_id;
+int num_jobs;
+<a href='#cups_job_t'>cups_job_t</a> *jobs;
+int i;
+ipp_jstate_t job_state = IPP_JOB_PENDING;
+
+while (job_state &lt; IPP_JOB_STOPPED)
+{
+ /* Get my jobs (1) with any state (-1) */
+ num_jobs = <a href='#cupsGetJobs'>cupsGetJobs</a>(&amp;jobs, dest->name, 1, -1);
+
+ /* Loop to find my job */
+ job_state = IPP_JOB_COMPLETED;
+
+ for (i = 0; i &lt; num_jobs; i ++)
+ if (jobs[i].id == job_id)
+ {
+ job_state = jobs[i].state;
+ break;
+ }
+
+ /* Free the job array */
+ <a href='#cupsFreeJobs'>cupsFreeJobs</a>(num_jobs, jobs);
+
+ /* Show the current state */
+ switch (job_state)
+ {
+ case IPP_JOB_PENDING :
+ printf("Job %d is pending.\n", job_id);
+ break;
+ case IPP_JOB_HELD :
+ printf("Job %d is held.\n", job_id);
+ break;
+ case IPP_JOB_PROCESSING :
+ printf("Job %d is processing.\n", job_id);
+ break;
+ case IPP_JOB_STOPPED :
+ printf("Job %d is stopped.\n", job_id);
+ break;
+ case IPP_JOB_CANCELED :
+ printf("Job %d is canceled.\n", job_id);
+ break;
+ case IPP_JOB_ABORTED :
+ printf("Job %d is aborted.\n", job_id);
+ break;
+ case IPP_JOB_COMPLETED :
+ printf("Job %d is completed.\n", job_id);
+ break;
+ }
+
+ /* Sleep if the job is not finished */
+ if (job_state &lt; IPP_JOB_STOPPED)
+ sleep(5);
+}
+</pre>
+
+<p>To cancel a job, use the
+<a href='#cupsCancelJob'><code>cupsCancelJob</code></a> function with the
+job ID:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+<a href='#cups_dest_t'>cups_dest_t</a> *dest;
+int job_id;
+
+<a href='#cupsCancelJob'>cupsCancelJob</a>(dest->name, job_id);
+</pre>
+
+<h3><a name='ERROR_HANDLING'>Error Handling</a></h3>
+
+<p>If any of the CUPS API printing functions returns an error, the reason for
+that error can be found by calling the
+<a href='#cupsLastError'><code>cupsLastError</code></a> and
+<a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> functions.
+<a href='#cupsLastError'><code>cupsLastError</code></a> returns the last IPP
+error code
+(<a href='api-httpipp.html#ipp_status_t'><code>ipp_status_t</code></a>)
+that was encountered, while
+<a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> returns
+a (localized) human-readable string that can be shown to the user. For example,
+if any of the job creation functions returns a job ID of 0, you can use
+<a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> to show
+the reason why the job could not be created:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+int job_id;
+
+if (job_id == 0)
+ puts(cupsLastErrorString());
+</pre>
+
+<h3><a name='PASSWORDS_AND_AUTHENTICATION'>Passwords and Authentication</a></h3>
+
+<p>CUPS supports authentication of any request, including submission of print
+jobs. The default mechanism for getting the username and password is to use the
+login user and a password from the console.</p>
+
+<p>To support other types of applications, in particular Graphical User
+Interfaces ("GUIs"), the CUPS API provides functions to set the default
+username and to register a callback function that returns a password string.</p>
+
+<p>The <a href="#cupsSetPasswordCB"><code>cupsSetPasswordCB</code></a>
+function is used to set a password callback in your program. Only one
+function can be used at any time.</p>
+
+<p>The <a href="#cupsSetUser"><code>cupsSetUser</code></a> function sets the
+current username for authentication. This function can be called by your
+password callback function to change the current username as needed.</p>
+
+<p>The following example shows a simple password callback that gets a
+username and password from the user:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+const char *
+my_password_cb(const char *prompt)
+{
+ char user[65];
+
+
+ puts(prompt);
+
+ /* Get a username from the user */
+ printf("Username: ");
+ if (fgets(user, sizeof(user), stdin) == NULL)
+ return (NULL);
+
+ /* Strip the newline from the string and set the user */
+ user[strlen(user) - 1] = '\0';
+
+ <a href='#cupsSetUser'>cupsSetUser</a>(user);
+
+ /* Use getpass() to ask for the password... */
+ return (getpass("Password: "));
+}
+
+<a href='#cupsSetPasswordCB'>cupsSetPasswordCB</a>(my_password_cb);
+</pre>
+
+<p>Similarly, a GUI could display the prompt string in a window with input
+fields for the username and password. The username should default to the
+string returned by the <a href="#cupsUser"><code>cupsUser</code></a>
+function.</p>
diff --git a/cups/api-filedir.header b/cups/api-filedir.header
new file mode 100644
index 000000000..63f629661
--- /dev/null
+++ b/cups/api-filedir.header
@@ -0,0 +1,36 @@
+<!--
+ "$Id: api-filedir.header 9771 2011-05-12 05:21:56Z mike $"
+
+ File and Directory API header for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>File and Directory APIs</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Headers</th>
+ <th>cups/file.h<br>
+ cups/dir.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcups</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a><br>
+ Programming: <a href='api-cups.html' target='_top'>CUPS API</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/cups/api-filedir.shtml b/cups/api-filedir.shtml
new file mode 100644
index 000000000..4a4a16ffd
--- /dev/null
+++ b/cups/api-filedir.shtml
@@ -0,0 +1,31 @@
+<!--
+ "$Id: api-filedir.shtml 9727 2011-04-28 21:20:12Z mike $"
+
+ File and directory API introduction for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2005 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name="OVERVIEW">Overview</a></h2>
+
+<p>The CUPS file and directory APIs provide portable interfaces
+for manipulating files and listing files and directories. Unlike
+stdio <code>FILE</code> streams, the <code>cupsFile</code> 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
+<code>cupsFile</code> functions.</p>
+
+<p>The <code>cupsDir</code> 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.</p>
diff --git a/cups/api-filter.header b/cups/api-filter.header
new file mode 100644
index 000000000..54e1d894a
--- /dev/null
+++ b/cups/api-filter.header
@@ -0,0 +1,41 @@
+<!--
+ "$Id: api-filter.header 9771 2011-05-12 05:21:56Z mike $"
+
+ Filter and backend programming header for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Filter and Backend Programming</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Headers</th>
+ <th>cups/backend.h<br>
+ cups/sidechannel.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcups</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a><br>
+ Programming: <a href='api-cups.html' target='_top'>CUPS API</a><br>
+ Programming: <a href='api-ppd.html' target='_top'>PPD API</a><br>
+ Programming: <a href='api-raster.html' target='_top'>Raster API</a><br>
+ Programming: <a href='postscript-driver.html' target='_top'>Developing PostScript Printer Drivers</a><br>
+ Programming: <a href='raster-driver.html' target='_top'>Developing Raster Printer Drivers</a><br>
+ Specifications: <a href='spec-design.html' target='_top'>CUPS Design Description</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/cups/api-filter.shtml b/cups/api-filter.shtml
new file mode 100644
index 000000000..edc822cdc
--- /dev/null
+++ b/cups/api-filter.shtml
@@ -0,0 +1,765 @@
+<!--
+ "$Id: api-filter.shtml 9799 2011-05-20 18:09:22Z mike $"
+
+ Filter and backend programming introduction for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name="OVERVIEW">Overview</a></h2>
+
+<p>Filters (which include printer drivers and port monitors) and backends
+are used to convert job files to a printable format and send that data to the
+printer itself. All of these programs use a common interface for processing
+print jobs and communicating status information to the scheduler. Each is run
+with a standard set of command-line arguments:<p>
+
+<dl class="code">
+
+ <dt>argv[1]</dt>
+ <dd>The job ID</dd>
+
+ <dt>argv[2]</dt>
+ <dd>The user printing the job</dd>
+
+ <dt>argv[3]</dt>
+ <dd>The job name/title</dd>
+
+ <dt>argv[4]</dt>
+ <dd>The number of copies to print</dd>
+
+ <dt>argv[5]</dt>
+ <dd>The options that were provided when the job was submitted</dd>
+
+ <dt>argv[6]</dt>
+ <dd>The file to print (first program only)</dd>
+</dl>
+
+<p>The scheduler runs one or more of these programs to print any given job. The
+first filter reads from the print file and writes to the standard output, while
+the remaining filters read from the standard input and write to the standard
+output. The backend is the last filter in the chain and writes to the
+device.</p>
+
+<p>Filters are always run as a non-privileged user, typically "lp", with no
+connection to the user's desktop. Backends are run either as a non-privileged
+user or as root if the file permissions do not allow user or group execution.
+The <a href="#PERMISSIONS">file permissions</a> section talks about this in
+more detail.</p>
+
+<h3><a name="SECURITY">Security Considerations</a></h3>
+
+<p>It is always important to use security programming practices. Filters and
+most backends are run as a non-privileged user, so the major security
+consideration is resource utilization - filters should not depend on unlimited
+amounts of CPU, memory, or disk space, and should protect against conditions
+that could lead to excess usage of any resource like infinite loops and
+unbounded recursion. In addition, filters must <em>never</em> allow the user to
+specify an arbitrary file path to a separator page, template, or other file
+used by the filter since that can lead to an unauthorized disclosure of
+information. <em>Always</em> treat input as suspect and validate it!</p>
+
+<p>If you are developing a backend that runs as root, make sure to check for
+potential buffer overflows, integer under/overflow conditions, and file
+accesses since these can lead to privilege escalations. When writing files,
+always validate the file path and <em>never</em> allow a user to determine
+where to store a file.</p>
+
+<blockquote><b>Note:</b>
+
+<p><em>Never</em> write files to a user's home directory. Aside from the
+security implications, CUPS is a network print service and as such the network
+user may not be the same as the local user and/or there may not be a local home
+directory to write to.</p>
+
+<p>In addition, some operating systems provide additional security mechanisms
+that further limit file system access, even for backends running as root. On
+Mac OS X, for example, no backend may write to a user's home directory.</p>
+</blockquote>
+
+<h3><a name="SIGNALS">Canceled Jobs and Signal Handling</a></h3>
+
+<p>The scheduler sends <code>SIGTERM</code> when a printing job is canceled or
+held. Filters, backends, and port monitors <em>must</em> catch
+<code>SIGTERM</code> and perform any cleanup necessary to produce a valid output
+file or return the printer to a known good state. The recommended behavior is to
+end the output on the current page, preferably on the current line or object
+being printed.</p>
+
+<p>Filters and backends may also receive <code>SIGPIPE</code> when an upstream or downstream filter/backend exits with a non-zero status. Developers should generally ignore <code>SIGPIPE</code> at the beginning of <code>main()</code> with the following function call:</p>
+
+<pre class="example">
+#include &lt;signal.h&gt;>
+
+...
+
+int
+main(int argc, char *argv[])
+{
+ signal(SIGPIPE, SIG_IGN);
+
+ ...
+}
+</pre>
+
+<h3><a name="PERMISSIONS">File Permissions</a></h3>
+
+<p>For security reasons, CUPS will only run filters and backends that are owned
+by root and do not have world or group write permissions. The recommended
+permissions for filters and backends are 0555 - read and execute but no write.
+Backends that must run as root should use permissions of 0500 - read and execute
+by root, no access for other users. Write permissions can be enabled for the
+root user only.</p>
+
+<p>To avoid a warning message, the directory containing your filter(s) must also
+be owned by root and have world and group write disabled - permissions of 0755
+or 0555 are strongly encouraged.</p>
+
+<h3><a name="TEMPFILES">Temporary Files</a></h3>
+
+<p>Temporary files should be created in the directory specified by the
+"TMPDIR" environment variable. The
+<a href="#cupsTempFile2"><code>cupsTempFile2</code></a> function can be
+used to safely create temporary files in this directory.</p>
+
+<h3><a name="COPIES">Copy Generation</a></h3>
+
+<p>The <code>argv[4]</code> argument specifies the number of copies to produce
+of the input file. In general, you should only generate copies if the
+<em>filename</em> argument is supplied. The only exception to this are
+filters that produce device-independent PostScript output, since the PostScript
+filter <var>pstops</var> is responsible for generating copies of PostScript
+files.</p>
+
+<h3><a name="EXITCODES">Exit Codes</a></h3>
+
+<p>Filters must exit with status 0 when they successfully generate print data
+or 1 when they encounter an error. Backends can return any of the
+<a href="#cups_backend_t"><code>cups_backend_t</code></a> constants.</p>
+
+<h3><a name="ENVIRONMENT">Environment Variables</a></h3>
+
+<p>The following environment variables are defined by the printing system
+when running print filters and backends:</p>
+
+<dl class="code">
+
+ <dt>APPLE_LANGUAGE</dt>
+ <dd>The Apple language identifier associated with the job
+ (Mac OS X only).</dd>
+
+ <dt>CHARSET</dt>
+ <dd>The job character set, typically "utf-8".</dd>
+
+ <dt>CLASS</dt>
+ <dd>When a job is submitted to a printer class, contains the name of
+ the destination printer class. Otherwise this environment
+ variable will not be set.</dd>
+
+ <dt>CONTENT_TYPE</dt>
+ <dd>The MIME type associated with the file (e.g.
+ application/postscript).</dd>
+
+ <dt>CUPS_CACHEDIR</dt>
+ <dd>The directory where cache files can be stored. Cache files can be
+ used to retain information between jobs or files in a job.</dd>
+
+ <dt>CUPS_DATADIR</dt>
+ <dd>The directory where (read-only) CUPS data files can be found.</dd>
+
+ <dt>CUPS_FILETYPE</dt>
+ <dd>The type of file being printed: "job-sheet" for a banner page and
+ "document" for a regular print file.</dd>
+
+ <dt>CUPS_SERVERROOT</dt>
+ <dd>The root directory of the server.</dd>
+
+ <dt>DEVICE_URI</dt>
+ <dd>The device-uri associated with the printer.</dd>
+
+ <dt>FINAL_CONTENT_TYPE</dt>
+ <dd>The MIME type associated with the printer (e.g.
+ application/vnd.cups-postscript).</dd>
+
+ <dt>LANG</dt>
+ <dd>The language locale associated with the job.</dd>
+
+ <dt>PPD</dt>
+ <dd>The full pathname of the PostScript Printer Description (PPD)
+ file for this printer.</dd>
+
+ <dt>PRINTER</dt>
+ <dd>The queue name of the class or printer.</dd>
+
+ <dt>RIP_CACHE</dt>
+ <dd>The recommended amount of memory to use for Raster Image
+ Processors (RIPs).</dd>
+
+ <dt>TMPDIR</dt>
+ <dd>The directory where temporary files should be created.</dd>
+
+</dl>
+
+<h3><a name="MESSAGES">Communicating with the Scheduler</a></h3>
+
+<p>Filters and backends communicate with the scheduler by writing messages
+to the standard error file. The scheduler reads messages from all filters in
+a job and processes the message based on its prefix. For example, the following
+code sets the current printer state message to "Printing page 5":</p>
+
+<pre class="example">
+int page = 5;
+
+fprintf(stderr, "INFO: Printing page %d\n", page);
+</pre>
+
+<p>Each message is a single line of text starting with one of the following
+prefix strings:</p>
+
+<dl class="code">
+
+ <dt>ALERT: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "alert" log level.</dd>
+
+ <dt>ATTR: attribute=value [attribute=value]</dt>
+ <dd>Sets the named printer or job attribute(s). Typically this is used
+ to set the <code>marker-colors</code>, <code>marker-high-levels</code>,
+ <code>marker-levels</code>, <code>marker-low-levels</code>,
+ <code>marker-message</code>, <code>marker-names</code>,
+ <code>marker-types</code>, <code>printer-alert</code>, and
+ <code>printer-alert-description</code> printer attributes. Standard
+ <code>marker-types</code> values are listed in <a href='#TABLE1'>Table
+ 1</a>.</dd>
+
+ <dt>CRIT: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "critical" log
+ level.</dd>
+
+ <dt>DEBUG: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "debug" log level.</dd>
+
+ <dt>DEBUG2: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "debug2" log level.</dd>
+
+ <dt>EMERG: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "emergency" log
+ level.</dd>
+
+ <dt>ERROR: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "error" log level.
+ Use "ERROR:" messages for non-persistent processing errors.</dd>
+
+ <dt>INFO: message</dt>
+ <dd>Sets the printer-state-message attribute. If the current log level
+ is set to "debug2", also adds the specified message to the current error
+ log file using the "info" log level.</dd>
+
+ <dt>NOTICE: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "notice" log level.</dd>
+
+ <dt>PAGE: page-number #-copies</dt>
+ <dt>PAGE: total #-pages</dt>
+ <dd>Adds an entry to the current page log file. The first form adds
+ #-copies to the job-media-sheets-completed attribute. The second
+ form sets the job-media-sheets-completed attribute to #-pages.</dd>
+
+ <dt>PPD: keyword=value [keyword=value ...]</dt>
+ <dd>Changes or adds keywords to the printer's PPD file. Typically
+ this is used to update installable options or default media settings
+ based on the printer configuration.</dd>
+
+ <dt>STATE: + printer-state-reason [printer-state-reason ...]</dt>
+ <dt>STATE: - printer-state-reason [printer-state-reason ...]</dt>
+ <dd>Sets or clears printer-state-reason keywords for the current queue.
+ Typically this is used to indicate persistent media, ink, toner, and
+ configuration conditions or errors on a printer.
+ <a href='#TABLE2'>Table 2</a> lists the standard state keywords -
+ use vendor-prefixed ("com.example.foo") keywords for custom states. See
+ <a href="#MANAGING_STATE">Managing Printer State in a Filter</a> for more
+ information.
+
+ <dt>WARNING: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "warning" log
+ level.</dd>
+
+</dl>
+
+<p>Messages without one of these prefixes are treated as if they began with
+the "DEBUG:" prefix string.</p>
+
+<div class='table'><table width='80%' summary='Table 1: Standard marker-types Values'>
+<caption>Table 1: <a name='TABLE1'>Standard marker-types Values</a></caption>
+<thead>
+<tr>
+ <th>marker-type</th>
+ <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>developer</td>
+ <td>Developer unit</td>
+</tr>
+<tr>
+ <td>fuser</td>
+ <td>Fuser unit</td>
+</tr>
+<tr>
+ <td>fuserCleaningPad</td>
+ <td>Fuser cleaning pad</td>
+</tr>
+<tr>
+ <td>fuserOil</td>
+ <td>Fuser oil</td>
+</tr>
+<tr>
+ <td>ink</td>
+ <td>Ink supply</td>
+</tr>
+<tr>
+ <td>opc</td>
+ <td>Photo conductor</td>
+</tr>
+<tr>
+ <td>solidWax</td>
+ <td>Wax supply</td>
+</tr>
+<tr>
+ <td>staples</td>
+ <td>Staple supply</td>
+</tr>
+<tr>
+ <td>toner</td>
+ <td>Toner supply</td>
+</tr>
+<tr>
+ <td>transferUnit</td>
+ <td>Transfer unit</td>
+</tr>
+<tr>
+ <td>wasteInk</td>
+ <td>Waste ink tank</td>
+</tr>
+<tr>
+ <td>wasteToner</td>
+ <td>Waste toner tank</td>
+</tr>
+<tr>
+ <td>wasteWax</td>
+ <td>Waste wax tank</td>
+</tr>
+</tbody>
+</table></div>
+
+<br>
+
+<div class='table'><table width='80%' summary='Table 2: Standard State Keywords'>
+<caption>Table 2: <a name='TABLE2'>Standard State Keywords</a></caption>
+<thead>
+<tr>
+ <th>Keyword</th>
+ <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>connecting-to-device</td>
+ <td>Connecting to printer but not printing yet.</td>
+</tr>
+<tr>
+ <td>cover-open</td>
+ <td>The printer's cover is open.</td>
+</tr>
+<tr>
+ <td>input-tray-missing</td>
+ <td>The paper tray is missing.</td>
+</tr>
+<tr>
+ <td>marker-supply-empty</td>
+ <td>The printer is out of ink.</td>
+</tr>
+<tr>
+ <td>marker-supply-low</td>
+ <td>The printer is almost out of ink.</td>
+</tr>
+<tr>
+ <td>marker-waste-almost-full</td>
+ <td>The printer's waste bin is almost full.</td>
+</tr>
+<tr>
+ <td>marker-waste-full</td>
+ <td>The printer's waste bin is full.</td>
+</tr>
+<tr>
+ <td>media-empty</td>
+ <td>The paper tray (any paper tray) is empty.</td>
+</tr>
+<tr>
+ <td>media-jam</td>
+ <td>There is a paper jam.</td>
+</tr>
+<tr>
+ <td>media-low</td>
+ <td>The paper tray (any paper tray) is almost empty.</td>
+</tr>
+<tr>
+ <td>media-needed</td>
+ <td>The paper tray needs to be filled (for a job that is printing).</td>
+</tr>
+<tr>
+ <td>paused</td>
+ <td>Stop the printer.</td>
+</tr>
+<tr>
+ <td>timed-out</td>
+ <td>Unable to connect to printer.</td>
+</tr>
+<tr>
+ <td>toner-empty</td>
+ <td>The printer is out of toner.</td>
+</tr>
+<tr>
+ <td>toner-low</td>
+ <td>The printer is low on toner.</td>
+</tr>
+</tbody>
+</table></div>
+
+<h4><a name="MANAGING_STATE">Managing Printer State in a Filter</a></h4>
+
+<p>Filters are responsible for managing the state keywords they set using
+"STATE:" messages. Typically you will update <em>all</em> of the keywords that
+are used by the filter at startup, for example:</p>
+
+<pre class="example">
+if (foo_condition != 0)
+ fputs("STATE: +com.example.foo\n", stderr);
+else
+ fputs("STATE: -com.example.foo\n", stderr);
+
+if (bar_condition != 0)
+ fputs("STATE: +com.example.bar\n", stderr);
+else
+ fputs("STATE: -com.example.bar\n", stderr);
+</pre>
+
+<p>Then as conditions change, your filter sends "STATE: +keyword" or "STATE:
+-keyword" messages as necessary to set or clear the corresponding keyword,
+respectively.</p>
+
+<p>State keywords are often used to notify the user of issues that span across
+jobs, for example "media-empty-warning" that indicates one or more paper trays
+are empty. These keywords should not be cleared unless the corresponding issue
+no longer exists.</p>
+
+<p>Filters should clear job-related keywords on startup and exit so that they
+do not remain set between jobs. For example, "connecting-to-device" is a job
+sub-state and not an issue that applies when a job is not printing.</p>
+
+<blockquote><b>Note:</b>
+
+<p>"STATE:" messages often provide visible alerts to the user. For example,
+on Mac OS X setting a printer-state-reason value with an "-error" or
+"-warning" suffix will cause the printer's dock item to bounce if the
+corresponding reason is localized with a cupsIPPReason keyword in the
+printer's PPD file.</p>
+
+<p>When providing a vendor-prefixed keyword, <em>always</em> provide the
+corresponding standard keyword (if any) to allow clients to respond to the
+condition correctly. For example, if you provide a vendor-prefixed keyword
+for a low cyan ink condition ("com.example.cyan-ink-low") you must also set the
+"marker-supply-low-warning" keyword. In such cases you should also refrain
+from localizing the vendor-prefixed keyword in the PPD file - otherwise both
+the generic and vendor-specific keyword will be shown in the user
+interface.</p>
+
+</blockquote></dd>
+
+<h4><a name="REPORTING_SUPPLIES">Reporting Supply Levels</a></h4>
+
+<p>CUPS tracks several "marker-*" attributes for ink/toner supply level
+reporting. These attributes allow applications to display the current supply
+levels for a printer without printer-specific software. <a href="#TABLE3">Table 3</a> lists the marker attributes and what they represent.</p>
+
+<p>Filters set marker attributes by sending "ATTR:" messages to stderr. For
+example, a filter supporting an inkjet printer with black and tri-color ink
+cartridges would use the following to initialize the supply attributes:</p>
+
+<pre class="example">
+fputs("ATTR: marker-colors=#000000,#00FFFF#FF00FF#FFFF00\n", stderr);
+fputs("ATTR: marker-low-levels=5,10\n", stderr);
+fputs("ATTR: marker-names=Black,Tri-Color\n", stderr);
+fputs("ATTR: marker-types=ink,ink\n", stderr);
+</pre>
+
+<p>Then periodically the filter queries the printer for its current supply
+levels and updates them with a separate "ATTR:" message:</p>
+
+<pre class="example">
+int black_level, tri_level;
+...
+fprintf(stderr, "ATTR: marker-levels=%d,%d\n", black_level, tri_level);
+</pre>
+
+<div class='table'><table width='80%' summary='Table 3: Supply Level Attributes'>
+<caption>Table 3: <a name='TABLE3'>Supply Level Attributes</a></caption>
+<thead>
+<tr>
+ <th>Attribute</th>
+ <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>marker-colors</td>
+ <td>A list of comma-separated colors; each color is either "none" or one or
+ more hex-encoded sRGB colors of the form "#RRGGBB".</td>
+</tr>
+<tr>
+ <td>marker-high-levels</td>
+ <td>A list of comma-separated "almost full" level values from 0 to 100; a
+ value of 100 should be used for supplies that are consumed/emptied like ink
+ cartridges.</td>
+</tr>
+<tr>
+ <td>marker-levels</td>
+ <td>A list of comma-separated level values for each supply. A value of -1
+ indicates the level is unavailable, -2 indicates unknown, and -3 indicates
+ the level is unknown but has not yet reached capacity. Values from 0 to 100
+ indicate the corresponding percentage.</td>
+</tr>
+<tr>
+ <td>marker-low-levels</td>
+ <td>A list of comma-separated "almost empty" level values from 0 to 100; a
+ value of 0 should be used for supplies that are filled like waste ink
+ tanks.</td>
+</tr>
+<tr>
+ <td>marker-message</td>
+ <td>A human-readable supply status message for the user like "12 pages of
+ ink remaining."</td>
+</tr>
+<tr>
+ <td>marker-names</td>
+ <td>A list of comma-separated supply names like "Cyan Ink", "Fuser",
+ etc.</td>
+</tr>
+<tr>
+ <td>marker-types</td>
+ <td>A list of comma-separated supply types; the types are listed in
+ <a href="#TABLE1">Table 1</a>.</td>
+</tr>
+</tbody>
+</table></div>
+
+<h3><a name="COMMUNICATING_BACKEND">Communicating with the Backend</a></h3>
+
+<p>Filters can communicate with the backend via the
+<a href="#cupsBackChannelRead"><code>cupsBackChannelRead</code></a> and
+<a href="#cupsSideChannelDoRequest"><code>cupsSideChannelDoRequest</code></a>
+functions. The
+<a href="#cupsBackChannelRead"><code>cupsBackChannelRead</code></a> function
+reads data that has been sent back from the device and is typically used to
+obtain status and configuration information. For example, the following code
+polls the backend for back-channel data:</p>
+
+<pre class="example">
+#include &lt;cups/cups.h&gt;
+
+char buffer[8192];
+ssize_t bytes;
+
+/* Use a timeout of 0.0 seconds to poll for back-channel data */
+bytes = cupsBackChannelRead(buffer, sizeof(buffer), 0.0);
+</pre>
+
+<p>Filters can also use <code>select()</code> or <code>poll()</code> on the
+back-channel file descriptor (3 or <code>CUPS_BC_FD</code>) to read data only
+when it is available.</p>
+
+<p>The
+<a href="#cupsSideChannelDoRequest"><code>cupsSideChannelDoRequest</code></a>
+function allows you to get out-of-band status information and do synchronization
+with the device. For example, the following code gets the current IEEE-1284
+device ID string from the backend:</p>
+
+<pre class="example">
+#include &lt;cups/sidechannel.h&gt;
+
+char data[2049];
+int datalen;
+<a href="#cups_sc_status_t">cups_sc_status_t</a> status;
+
+/* Tell cupsSideChannelDoRequest() how big our buffer is, less 1 byte for
+ nul-termination... */
+datalen = sizeof(data) - 1;
+
+/* Get the IEEE-1284 device ID, waiting for up to 1 second */
+status = <a href="#cupsSideChannelDoRequest">cupsSideChannelDoRequest</a>(CUPS_SC_CMD_GET_DEVICE_ID, data, &amp;datalen, 1.0);
+
+/* Use the returned value if OK was returned and the length is non-zero */
+if (status == CUPS_SC_STATUS_OK && datalen > 0)
+ data[datalen] = '\0';
+else
+ data[0] = '\0';
+</pre>
+
+<h4><a name="DRAIN_OUTPUT">Forcing All Output to a Printer</a></h4>
+
+<p>The
+<a href="#cupsSideChannelDoRequest"><code>cupsSideChannelDoRequest</code></a>
+function allows you to tell the backend to send all pending data to the printer.
+This is most often needed when sending query commands to the printer. For example:</p>
+
+<pre class="example">
+#include &lt;cups/cups.h&gt;
+#include &lt;cups/sidechannel.h&gt;
+
+char data[1024];
+int datalen = sizeof(data);
+<a href="#cups_sc_status_t">cups_sc_status_t</a> status;
+
+/* Flush pending output to stdout */
+fflush(stdout);
+
+/* Drain output to backend, waiting for up to 30 seconds */
+status = <a href="#cupsSideChannelDoRequest">cupsSideChannelDoRequest</a>(CUPS_SC_CMD_DRAIN_OUTPUT, data, &amp;datalen, 30.0);
+
+/* Read the response if the output was sent */
+if (status == CUPS_SC_STATUS_OK)
+{
+ ssize_t bytes;
+
+ /* Wait up to 10.0 seconds for back-channel data */
+ bytes = cupsBackChannelRead(data, sizeof(data), 10.0);
+ /* do something with the data from the printer */
+}
+</pre>
+
+<h3><a name="COMMUNICATING_FILTER">Communicating with Filters</a></h3>
+
+<p>Backends communicate with filters using the reciprocal functions
+<a href="#cupsBackChannelWrite"><code>cupsBackChannelWrite</code></a>,
+<a href="#cupsSideChannelRead"><code>cupsSideChannelRead</code></a>, and
+<a href="#cupsSideChannelWrite"><code>cupsSideChannelWrite</code></a>. We
+recommend writing back-channel data using a timeout of 1.0 seconds:</p>
+
+<pre class="example">
+#include &lt;cups/cups.h&gt;
+
+char buffer[8192];
+ssize_t bytes;
+
+/* Obtain data from printer/device */
+...
+
+/* Use a timeout of 1.0 seconds to give filters a chance to read */
+cupsBackChannelWrite(buffer, bytes, 1.0);
+</pre>
+
+<p>The <a href="#cupsSideChannelRead"><code>cupsSideChannelRead</code></a>
+function reads a side-channel command from a filter, driver, or port monitor.
+Backends can either poll for commands using a <code>timeout</code> of 0.0, wait
+indefinitely for commands using a <code>timeout</code> of -1.0 (probably in a
+separate thread for that purpose), or use <code>select</code> or
+<code>poll</code> on the <code>CUPS_SC_FD</code> file descriptor (4) to handle
+input and output on several file descriptors at the same time.</p>
+
+<p>Once a command is processed, the backend uses the
+<a href="#cupsSideChannelWrite"><code>cupsSideChannelWrite</code></a> function
+to send its response. For example, the following code shows how to poll for a
+side-channel command and respond to it:</p>
+
+<pre class="example">
+#include &lt;cups/sidechannel.h&gt;
+
+<a href="#cups_sc_command_t">cups_sc_command_t</a> command;
+<a href="#cups_sc_status_t">cups_sc_status_t</a> status;
+char data[2048];
+int datalen = sizeof(data);
+
+/* Poll for a command... */
+if (!<a href="#cupsSideChannelRead">cupsSideChannelRead</a>(&amp;command, &amp;status, data, &amp;datalen, 0.0))
+{
+ switch (command)
+ {
+ /* handle supported commands, fill data/datalen/status with values as needed */
+
+ default :
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ datalen = 0;
+ break;
+ }
+
+ /* Send a response... */
+ <a href="#cupsSideChannelWrite">cupsSideChannelWrite</a>(command, status, data, datalen, 1.0);
+}
+</pre>
+
+<h3><a name="SNMP">Doing SNMP Queries with Network Printers</a></h3>
+
+<p>The Simple Network Management Protocol (SNMP) allows you to get the current
+status, page counter, and supply levels from most network printers. Every
+piece of information is associated with an Object Identifier (OID), and
+every printer has a <em>community</em> name associated with it. OIDs can be
+queried directly or by "walking" over a range of OIDs with a common prefix.</p>
+
+<p>The two CUPS SNMP functions provide a simple API for querying network
+printers through the side-channel interface. Each accepts a string containing
+an OID like ".1.3.6.1.2.1.43.10.2.1.4.1.1" (the standard page counter OID)
+along with a timeout for the query.</p>
+
+<p>The <a href="#cupsSideChannelSNMPGet"><code>cupsSideChannelSNMPGet</code></a>
+function queries a single OID and returns the value as a string in a buffer
+you supply:</p>
+
+<pre class="example">
+#include &lt;cups/sidechannel.h&gt;
+
+char data[512];
+int datalen = sizeof(data);
+
+if (<a href="#cupsSideChannelSNMPGet">cupsSideChannelSNMPGet</a>(".1.3.6.1.2.1.43.10.2.1.4.1.1", data, &amp;datalen, 5.0)
+ == CUPS_SC_STATUS_OK)
+{
+ /* Do something with the value */
+ printf("Page counter is: %s\n", data);
+}
+</pre>
+
+<p>The
+<a href="#cupsSideChannelSNMPWalk"><code>cupsSideChannelSNMPWalk</code></a>
+function allows you to query a whole group of OIDs, calling a function of your
+choice for each OID that is found:</p>
+
+<pre class="example">
+#include &lt;cups/sidechannel.h&gt;
+
+void
+my_callback(const char *oid, const char *data, int datalen, void *context)
+{
+ /* Do something with the value */
+ printf("%s=%s\n", oid, data);
+}
+
+...
+
+void *my_data;
+
+<a href="#cupsSideChannelSNMPWalk">cupsSNMPSideChannelWalk</a>(".1.3.6.1.2.1.43", 5.0, my_callback, my_data);
+</pre>
diff --git a/cups/api-httpipp.header b/cups/api-httpipp.header
new file mode 100644
index 000000000..42dffb1ea
--- /dev/null
+++ b/cups/api-httpipp.header
@@ -0,0 +1,37 @@
+<!--
+ "$Id: api-httpipp.header 9771 2011-05-12 05:21:56Z mike $"
+
+ HTTP and IPP API header for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>HTTP and IPP APIs</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/cups.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcups</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html'>Introduction to CUPS Programming</a><br>
+ Programming: <a href='api-cups.html'>CUPS API</a><br>
+ References: <a href='spec-ipp.html'>CUPS Implementation of IPP</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/cups/api-httpipp.shtml b/cups/api-httpipp.shtml
new file mode 100644
index 000000000..484c00dae
--- /dev/null
+++ b/cups/api-httpipp.shtml
@@ -0,0 +1,323 @@
+<!--
+ "$Id: api-httpipp.shtml 9727 2011-04-28 21:20:12Z mike $"
+
+ HTTP and IPP API introduction for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>The CUPS HTTP and IPP APIs provide low-level access to the HTTP and IPP
+protocols and CUPS scheduler. They are typically used by monitoring and
+administration programs to perform specific functions not supported by the
+high-level CUPS API functions.</p>
+
+<p>The HTTP APIs use an opaque structure called
+<a href='#http_t'><code>http_t</code></a> to manage connections to
+a particular HTTP or IPP server. The
+<a href='#httpConnectEncrypt'><code>httpConnectEncrypt</code></a> function is
+used to create an instance of this structure for a particular server.
+The constant <code>CUPS_HTTP_DEFAULT</code> can be used with all of the
+<code>cups</code> functions to refer to the default CUPS server - the functions
+create a per-thread <a href='#http_t'><code>http_t</code></a> as needed.</p>
+
+<p>The IPP APIs use two structures for requests (messages sent to the CUPS
+scheduler) and responses (messages sent back to your application from the
+scheduler). The <a href='#ipp_t'><code>ipp_t</code></a> structure holds a
+complete request or response and is allocated using the
+<a href='#ippNew'><code>ippNew</code></a> or
+<a href='#ippNewRequest'><code>ippNewRequest</code></a> functions and
+freed using the <a href='#ippDelete'><code>ippDelete</code></a> function.</p>
+
+<p>The second structure is called
+<a href='#ipp_attribute_t'><code>ipp_attribute_t</code></a> and holds a
+single IPP attribute which consists of a group tag (<code>group_tag</code>), a
+value type tag (<code>value_tag</code>), the attribute name (<code>name</code>),
+and 1 or more values (<code>values[]</code>). Attributes are added to an
+<a href='#ipp_t'><code>ipp_t</code></a> structure using one of the
+<code>ippAdd</code> functions. For example, use
+<a href='#ippAddString'><code>ippAddString</code></a> to add a
+"requesting-user-name" string attribute to a request:</p>
+
+<pre class='example'>
+<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(IPP_GET_JOBS);
+
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+</pre>
+
+<p>Once you have created an IPP request, use the <code>cups</code>
+functions to send the request to and read the response from the server.
+For example, the <a href='#cupsDoRequest'><code>cupsDoRequest</code></a>
+function can be used for simple query operations that do not involve files:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+
+<a href='#ipp_t'>ipp_t</a> *<a name='get_jobs'>get_jobs</a>(void)
+{
+ <a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(IPP_GET_JOBS);
+
+ <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ return (<a href='#cupsDoRequest'>cupsDoRequest</a>(CUPS_HTTP_DEFAULT, request, "/"));
+}
+</pre>
+
+<p>The <a href='#cupsDoRequest'><code>cupsDoRequest</code></a> function frees
+the request structure and returns an IPP response structure or NULL pointer if
+the request could not be sent to the server. Once you have a response from
+the server, you can either use the
+<a href='#ippFindAttribute'><code>ippFindAttribute</code></a> and
+<a href='#ippFindNextAttribute'><code>ippFindNextAttribute</code></a> functions
+to find specific attributes, for example:</p>
+
+<pre class='example'>
+<a href='#ipp_t'>ipp_t</a> *response;
+<a href='#ipp_attribute_t'>ipp_attribute_t</a> *attr;
+
+attr = <a href='#ippFindAttribute'>ippFindAttribute</a>(response, "printer-state", IPP_TAG_ENUM);
+</pre>
+
+<p>You can also walk the list of attributes with a simple <code>for</code> loop
+like this:</p>
+
+<pre class='example'>
+<a href='#ipp_t'>ipp_t</a> *response;
+<a href='#ipp_attribute_t'>ipp_attribute_t</a> *attr;
+
+for (attr = response->attrs; attr != NULL; attr = attr->next)
+ if (attr->name == NULL)
+ puts("--SEPARATOR--");
+ else
+ puts(attr->name);
+</pre>
+
+<p>The <code>for</code> loop approach is normally used when collecting
+attributes for multiple objects (jobs, printers, etc.) in a response. Attributes
+with <code>NULL</code> names indicate a separator between the attributes of
+each object. For example, the following code will list the jobs returned from
+our previous <a href='#get_jobs'><code>get_jobs</code></a> example code:</p>
+
+<pre class='example'>
+<a href='#ipp_t'>ipp_t</a> *response = <a href='#get_jobs'>get_jobs</a>();
+
+if (response != NULL)
+{
+ <a href='#ipp_attribute_t'>ipp_attribute_t</a> *attr;
+ int job_id = 0;
+ char *job_name = NULL;
+ char *job_originating_user_name = NULL;
+
+ puts("Job ID Owner Title");
+ puts("------ ---------------- ---------------------------------");
+
+ for (attr = response->attrs; attr != NULL; attr = attr->next)
+ {
+ /* Attributes without names are separators between jobs */
+ if (attr->name == NULL)
+ {
+ if (job_id > 0 &amp;&amp; job_name != NULL &amp;&amp; job_originating_user_name != NULL)
+ printf("%5d %-16s %s\n", job_id, job_originating_user_name, job_name);
+
+ job_id = 0;
+ job_name = NULL;
+ job_originating_user_name = NULL;
+ continue;
+ }
+ else if (!strcmp(attr->name, "job-id") &amp;&amp; attr->value_tag == IPP_TAG_INTEGER)
+ job_id = attr->values[0].integer;
+ else if (!strcmp(attr->name, "job-name") &amp;&amp; attr->value_tag == IPP_TAG_NAME)
+ job_name = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "job-originating-user-name") &amp;&amp;
+ attr->value_tag == IPP_TAG_NAME)
+ job_originating_user_name = attr->values[0].string.text;
+ }
+
+ if (job_id > 0 &amp;&amp; job_name != NULL &amp;&amp; job_originating_user_name != NULL)
+ printf("%5d %-16s %s\n", job_id, job_originating_user_name, job_name);
+}
+</pre>
+
+<h3><a name='CREATING_URI_STRINGS'>Creating URI Strings</a></h3>
+
+<p>To ensure proper encoding, the
+<a href='#httpAssembleURIf'><code>httpAssembleURIf</code></a> function must be
+used to format a "printer-uri" string for all printer-based requests:</p>
+
+<pre class='example'>
+const char *name = "Foo";
+char uri[1024];
+<a href='#ipp_t'>ipp_t</a> *request;
+
+<a href='#httpAssembleURIf'>httpAssembleURIf</a>(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, cupsServer(),
+ ippPort(), "/printers/%s", name);
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
+</pre>
+
+<h3><a name='SENDING_REQUESTS_WITH_FILES'>Sending Requests with Files</a></h3>
+
+<p>The <a href='#cupsDoFileRequest'><code>cupsDoFileRequest</code></a> and
+<a href='#cupsDoIORequest'><code>cupsDoIORequest</code></a> functions are
+used for requests involving files. The
+<a href='#cupsDoFileRequest'><code>cupsDoFileRequest</code></a> function
+attaches the named file to a request and is typically used when sending a print
+file or changing a printer's PPD file:</p>
+
+<pre class='example'>
+const char *filename = "/usr/share/cups/data/testprint.ps";
+const char *name = "Foo";
+char uri[1024];
+char resource[1024];
+<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(IPP_PRINT_JOB);
+<a href='#ipp_t'>ipp_t</a> *response;
+
+/* Use httpAssembleURIf for the printer-uri string */
+<a href='#httpAssembleURIf'>httpAssembleURIf</a>(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, cupsServer(),
+ ippPort(), "/printers/%s", name);
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
+ NULL, "testprint.ps");
+
+/* Use snprintf for the resource path */
+snprintf(resource, sizeof(resource), "/printers/%s", name);
+
+response = <a href='#cupsDoFileRequest'>cupsDoFileRequest</a>(CUPS_HTTP_DEFAULT, request, resource, filename);
+</pre>
+
+<p>The <a href='#cupsDoIORequest'><code>cupsDoIORequest</code></a> function
+optionally attaches a file to the request and optionally saves a file in the
+response from the server. It is used when using a pipe for the request
+attachment or when using a request that returns a file, currently only
+<code>CUPS_GET_DOCUMENT</code> and <code>CUPS_GET_PPD</code>. For example,
+the following code will download the PPD file for the sample HP LaserJet
+printer driver:</p>
+
+<pre class='example'>
+char tempfile[1024];
+int tempfd;
+<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(CUPS_GET_PPD);
+<a href='#ipp_t'>ipp_t</a> *response;
+
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name",
+ NULL, "laserjet.ppd");
+
+tempfd = cupsTempFd(tempfile, sizeof(tempfile));
+
+response = <a href='#cupsDoIORequest'>cupsDoIORequest</a>(CUPS_HTTP_DEFAULT, request, "/", -1, tempfd);
+</pre>
+
+<p>The example passes <code>-1</code> for the input file descriptor to specify
+that no file is to be attached to the request. The PPD file attached to the
+response is written to the temporary file descriptor we created using the
+<code>cupsTempFd</code> function.</p>
+
+<h3><a name='ASYNCHRONOUS_REQUEST_PROCESSING'>Asynchronous Request Processing</a></h3>
+
+<p>The <a href='#cupsSendRequest'><code>cupsSendRequest</code></a> and
+<a href='#cupsGetResponse'><code>cupsGetResponse</code></a> support
+asynchronous communications with the server. Unlike the other request
+functions, the IPP request is not automatically freed, so remember to
+free your request with the <a href='#ippDelete'><code>ippDelete</code></a>
+function.</p>
+
+<p>File data is attached to the request using the
+<a href='#cupsWriteRequestData'><code>cupsWriteRequestData</code></a>
+function, while file data returned from the server is read using the
+<a href='#cupsReadResponseData'><code>cupsReadResponseData</code></a>
+function. We can rewrite the previous <code>CUPS_GET_PPD</code> example
+to use the asynchronous functions quite easily:</p>
+
+<pre class='example'>
+char tempfile[1024];
+int tempfd;
+<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(CUPS_GET_PPD);
+<a href='#ipp_t'>ipp_t</a> *response;
+
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name",
+ NULL, "laserjet.ppd");
+
+tempfd = cupsTempFd(tempfile, sizeof(tempfile));
+
+if (<a href='#cupsSendRequest'>cupsSendRequest</a>(CUPS_HTTP_DEFAULT, request, "/") == HTTP_CONTINUE)
+{
+ response = <a href='#cupsGetResponse'>cupsGetResponse</a>(CUPS_HTTP_DEFAULT, "/");
+
+ if (response != NULL)
+ {
+ ssize_t bytes;
+ char buffer[8192];
+
+ while ((bytes = <a href='#cupsReadResponseData'>cupsReadResponseData</a>(CUPS_HTTP_DEFAULT, buffer, sizeof(buffer))) > 0)
+ write(tempfd, buffer, bytes);
+ }
+}
+
+/* Free the request! */
+<a href='#ippDelete'>ippDelete</a>(request);
+</pre>
+
+<p>The <a href='#cupsSendRequest'><code>cupsSendRequest</code></a> function
+returns the initial HTTP request status, typically either
+<code>HTTP_CONTINUE</code> or <code>HTTP_UNAUTHORIZED</code>. The latter status
+is returned when the request requires authentication of some sort. The
+<a href='#cupsDoAuthentication'><code>cupsDoAuthentication</code></a> function
+must be called when your see <code>HTTP_UNAUTHORIZED</code> and the request
+re-sent. We can add authentication support to our example code by using a
+<code>do ... while</code> loop:</p>
+
+<pre class='example'>
+char tempfile[1024];
+int tempfd;
+<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(CUPS_GET_PPD);
+<a href='#ipp_t'>ipp_t</a> *response;
+http_status_t status;
+
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name",
+ NULL, "laserjet.ppd");
+
+tempfd = cupsTempFd(tempfile, sizeof(tempfile));
+
+/* Loop for authentication */
+do
+{
+ status = <a href='#cupsSendRequest'>cupsSendRequest</a>(CUPS_HTTP_DEFAULT, request, "/");
+
+ if (status == HTTP_UNAUTHORIZED)
+ {
+ /* Try to authenticate, break out of the loop if that fails */
+ if (<a href='#cupsDoAuthentication'>cupsDoAuthentication</a>(CUPS_HTTP_DEFAULT, "POST", "/"))
+ break;
+ }
+}
+while (status != HTTP_CONTINUE &amp;&amp; status != HTTP_UNAUTHORIZED);
+
+if (status == HTTP_CONTINUE)
+{
+ response = <a href='#cupsGetResponse'>cupsGetResponse</a>(CUPS_HTTP_DEFAULT, "/");
+
+ if (response != NULL)
+ {
+ ssize_t bytes;
+ char buffer[8192];
+
+ while ((bytes = <a href='#cupsReadResponseData'>cupsReadResponseData</a>(CUPS_HTTP_DEFAULT, buffer, sizeof(buffer))) > 0)
+ write(tempfd, buffer, bytes);
+ }
+}
+
+/* Free the request! */
+<a href='#ippDelete'>ippDelete</a>(request);
+</pre>
diff --git a/cups/api-overview.header b/cups/api-overview.header
new file mode 100644
index 000000000..ecb14b601
--- /dev/null
+++ b/cups/api-overview.header
@@ -0,0 +1,53 @@
+<!--
+ "$Id: api-cups.header 7279 2008-01-31 01:50:44Z mike $"
+
+ Introduction to CUPS programming header for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Introduction to CUPS Programming</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Headers</th>
+ <th>cups/cups.h<br>
+ cups/array.h<br>
+ cups/backend.h<br>
+ cups/dir.h<br>
+ cups/file.h<br>
+ cups/ppd.h<br>
+ cups/raster.h<br>
+ cups/sidechannel.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Libraries</th>
+ <td>-lcups<br>
+ -lcupsimage</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='raster-driver.html' target='_top'>Developing Raster Printer Drivers</a><br>
+ Programming: <a href='postscript-driver.html' target='_top'>Developing PostScript Printer Drivers</a><br>
+ Programming: <a href='api-filter.html' target='_top'>Filter and Backend Programming</a><br>
+ Programming: <a href='ppd-compiler.html' target='_top'>Introduction to the PPD Compiler</a><br>
+ Programming: <a href='api-array.html' target='_top'>Array API</a><br>
+ Programming: <a href='api-cups.html' target='_top'>CUPS API</a><br>
+ Programming: <a href='api-filedir.html' target='_top'>File and Directory APIs</a><br>
+ Programming: <a href='api-httpipp.html' target='_top'>HTTP and IPP APIs</a><br>
+ Programming: <a href='api-ppd.html' target='_top'>PPD API</a><br>
+ Programming: <a href='api-raster.html' target='_top'>Raster API</a><br>
+ References: <a href='ref-ppdcfile.html' target='_top'>PPD Compiler Driver Information File Reference</a><br>
+ Specifications: <a href='spec-ppd.html' target='_top'>CUPS PPD Extensions</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/cups/api-overview.shtml b/cups/api-overview.shtml
new file mode 100644
index 000000000..3ece1033c
--- /dev/null
+++ b/cups/api-overview.shtml
@@ -0,0 +1,94 @@
+<!--
+ "$Id: api-cups.header 7279 2008-01-31 01:50:44Z mike $"
+
+ Introduction to CUPS programming content for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class="title"><a name="OVERVIEW">Overview</a></h2>
+
+<p>CUPS provides two libraries that interface with the different parts of the
+printing system. The "cups" library provides all of the common application and
+filter functions while the "cupsimage" library provides all of the imaging
+functions used in raster printer drivers. The "cups" library functions are
+accessed by including the <var>&lt;cups/cups.h&gt;</var> header, while
+"cupsimage" functions are found in the <var>&lt;cups/raster.h&gt;</var>
+header.</p>
+
+<h2 class="title"><a name="COMPILING">Compiling Programs</a></h2>
+
+<p>The CUPS libraries can be used from any C, C++, or Objective C program.
+The method of compiling against the libraries varies depending on the
+operating system and installation of CUPS. The following sections show how
+to compile a simple program (shown below) in two common environments.</p>
+
+<p>The following simple program lists the available printers on the system:</p>
+
+<pre class="example">
+#include &lt;stdio.h&gt;
+#include &lt;cups/cups.h&gt;
+
+int main(void)
+{
+ int i;
+ cups_dest_t *dests, *dest;
+ int num_dests = cupsGetDests(&amp;dests);
+
+ for (i = num_dests, dest = dests; i &gt; 0; i --, dest ++)
+ {
+ if (dest->instance)
+ printf("%s/%s\n", dest->name, dest->instance);
+ else
+ puts(dest->name);
+ }
+
+ return (0);
+}
+</pre>
+
+<h3><a name="XCODE">Compiling with Xcode</a></h3>
+
+<p>In Xcode, choose <var>New Project...</var> from the <var>File</var> menu,
+then select the <var>Standard Tool</var> project type under <var>Command Line
+Utility</var>. Click <var>Next</var> and choose a project directory. Click
+<var>Next</var> to create the project.</p>
+
+<p>In the project window, double-click on the <var>Targets</var> group and
+control-click on the simple target to show the context menu. Choose
+<var>Existing Framework...</var> from the <var>Add</var> submenu. When the file
+chooser sheet appears, press the <kbd>/</kbd> key and enter "/usr/lib". Scroll
+down the file list and select the <var>libcups.dylib</var> file. Click the
+<var>Add</var> button in the file chooser and attributes sheets.</p>
+
+<p>In the project window, double-click on the <var>main.c</var> source file.
+Replace the template source code with the listing above and save it. Click the
+<var>Build and Go</var> button to build the sample program and run it.</p>
+
+<h3><a name="COMMANDLINE">Compiling with GCC</a></h3>
+
+<p>From the command-line, create a file called <var>sample.c</var> using your
+favorite editor and then run the following command to compile it with GCC and
+run it:</p>
+
+<pre class="command">
+gcc -o simple `cups-config --cflags` simple.c `cups-config --libs`
+./simple
+</pre>
+
+<p>The <code>cups-config</code> command provides the compiler flags
+("cups-config --cflags") and libraries ("cups-config --libs") needed for the
+local system.</p>
+
+<h2 class="title"><a name="WHERETOGO">Where to Go Next</a></h2>
+
+<p>If you are developing a print filter, driver, or backend, see the
+<a href="api-filter.html" target="_top">Filter and Backend Programming</a>
+guide. Raster printer driver developers should also read the
+<a href="api-raster.html" target="_top">Raster API</a> reference.</p>
diff --git a/cups/api-ppd.header b/cups/api-ppd.header
new file mode 100644
index 000000000..2dfcb5642
--- /dev/null
+++ b/cups/api-ppd.header
@@ -0,0 +1,36 @@
+<!--
+ "$Id: api-ppd.header 9771 2011-05-12 05:21:56Z mike $"
+
+ PPD API header for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>PPD API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/ppd.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcups</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a><br>
+ Programming: <a href='api-cups.html' target='_top'>CUPS API</a><br>
+ Specifications: <a href='spec-ppd.html' target='_top'>CUPS PPD Extensions</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/cups/api-ppd.shtml b/cups/api-ppd.shtml
new file mode 100644
index 000000000..e9beb9b09
--- /dev/null
+++ b/cups/api-ppd.shtml
@@ -0,0 +1,217 @@
+<!--
+ "$Id: api-ppd.shtml 9727 2011-04-28 21:20:12Z mike $"
+
+ PPD API introduction for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>The CUPS PPD API provides read-only access the data in PostScript Printer
+Description ("PPD") files which are used for all printers with a driver. With
+it you can obtain the data necessary to display printer options to users, mark
+option choices and check for conflicting choices, and output marked choices in
+PostScript output. The <a href="#ppd_file_t"><code>ppd_file_t</code></a>
+structure contains all of the information in a PPD file.</p>
+
+<blockquote><b>Note:</b>
+
+<p>The CUPS PPD API uses the terms "option" and "choice" instead of the Adobe
+terms "MainKeyword" and "OptionKeyword" to refer to specific printer options and
+features. CUPS also treats option ("MainKeyword") and choice ("OptionKeyword")
+values as case-insensitive strings, so option "InputSlot" and choice "Upper"
+are equivalent to "inputslot" and "upper", respectively.</p>
+</blockquote>
+
+<h3><a name="LOADING">Loading a PPD File</a></h3>
+
+<p>The <a href="#ppdOpenFile"><code>ppdOpenFile</code></a> function "opens" a
+PPD file and loads it into memory. For example, the following code opens the
+current printer's PPD file in a CUPS filter:</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd = <a href="#ppdOpenFile">ppdOpenFile</a>(getenv("PPD"));
+</pre>
+
+<p>The return value is a pointer to a new
+<a href="#ppd_file_t"><code>ppd_file_t</code></a> structure or <code>NULL</code>
+if the PPD file does not exist or cannot be loaded. The
+<a href="#ppdClose"><code>ppdClose</code></a> function frees the memory used
+by the structure:</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd;
+
+<a href="#ppdClose">ppdClose</a>(ppd);
+</pre>
+
+<p>Once closed, pointers to the <a href="#ppd_file_t"><code>ppd_file_t</code></a>
+structure and any data in it will no longer be valid.</p>
+
+<h3><a name="OPTIONS_AND_GROUPS">Options and Groups</a></h3>
+
+<p>PPD files support multiple options, which are stored in arrays of
+<a href="#ppd_option_t"><code>ppd_option_t</code></a> and
+<a href="#ppd_choice_t"><code>ppd_choice_t</code></a> structures.</p>
+
+<p>Each option in turn is associated with a group stored in a
+<a href="#ppd_group_t"><code>ppd_group_t</code></a> structure. Groups can be
+specified in the PPD file; if an option is not associated with a group
+then it is put in an automatically-generated "General" group. Groups can also
+have sub-groups, however CUPS currently ignores sub-groups because of past
+abuses of this functionality.</p>
+
+<p>Option choices are selected by marking them using one of three functions. The
+first is <a href="#ppdMarkDefaults"><code>ppdMarkDefaults</code></a> which
+selects all of the default options in the PPD file:</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd;
+
+<a href="#ppdMarkDefaults">ppdMarkDefaults</a>(ppd);
+</pre>
+
+<p>The second is <a href="#ppdMarkOption"><code>ppdMarkOption</code></a>
+which selects a single option choice in the PPD file. For example, the following
+code selects the upper paper tray:</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd;
+
+<a href="#ppdMarkOption">ppdMarkOption</a>(ppd, "InputSlot", "Upper");
+</pre>
+
+<p>The last function is
+<a href="#cupsMarkOptions"><code>cupsMarkOptions</code></a> which selects
+multiple option choices in the PPD file from an array of CUPS options, mapping
+IPP attributes like "media" and "sides" to their corresponding PPD options. You
+typically use this function in a print filter with
+<code>cupsParseOptions</code> and
+<a href="#ppdMarkDefaults"><code>ppdMarkDefaults</code></a> to select all of
+the option choices needed for the job, for example:</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd = <a href="#ppdOpenFile">ppdOpenFile</a>(getenv("PPD"));
+cups_option_t *options = NULL;
+int num_options = cupsParseOptions(argv[5], 0, &amp;options);
+
+<a href="#ppdMarkDefaults">ppdMarkDefaults</a>(ppd);
+<a href="#cupsMarkOptions">cupsMarkOptions</a>(ppd, num_options, options);
+cupsFreeOptions(num_options, options);
+</pre>
+
+<h3><a name="CONSTRAINTS">Constraints</a></h3>
+
+<p>PPD files support specification of conflict conditions, called
+constraints, between different options. Constraints are stored in an array of
+<a href="#ppd_const_t"><code>ppd_const_t</code></a> structures which specify
+the options and choices that conflict with each other. The
+<a href="#ppdConflicts"><code>ppdConflicts</code></a> function tells you
+how many of the selected options are incompatible. Since constraints are
+normally specified in pairs, the returned value is typically an even number.</p>
+
+<h3><a name="PAGE_SIZES">Page Sizes</a></h3>
+
+<p>Page sizes are special options which have physical dimensions and margins
+associated with them. The size information is stored in
+<a href="#ppd_size_t"><code>ppd_size_t</code></a> structures and is available
+by looking up the named size with the
+<a href="#ppdPageSize"><code>ppdPageSize</code></a> function. The page size and
+margins are returned in units called points; there are 72 points per inch. If
+you pass <code>NULL</code> for the size, the currently selected size is
+returned:</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd;
+<a href="#ppd_size_t">ppd_size_t</a> *size = <a href="#ppdPageSize">ppdPageSize</a>(ppd, NULL);
+</pre>
+
+<p>Besides the standard page sizes listed in a PPD file, some printers
+support variable or custom page sizes. Custom page sizes are supported if the
+<code>variables_sizes</code> member of the
+<a href="#ppd_file_t"><code>ppd_file_t</code></a> structure is non-zero.
+The <code>custom_min</code>, <code>custom_max</code>, and
+<code>custom_margins</code> members of the
+<a href="#ppd_file_t"><code>ppd_file_t</code></a> structure define the limits
+of the printable area. To get the resulting media size, use a page size string
+of the form "Custom.<I>width</I>x<I>length</I>", where "width" and "length" are
+in points. Custom page size names can also be specified in inches
+("Custom.<i>width</i>x<i>height</i>in"), centimeters
+("Custom.<i>width</i>x<i>height</i>cm"), or millimeters
+("Custom.<i>width</i>x<i>height</i>mm"):</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd;
+
+/* Get an 576x720 point custom page size */
+<a href="#ppd_size_t">ppd_size_t</a> *size = <a href="#ppdPageSize">ppdPageSize</a>(ppd, "Custom.576x720");
+
+/* Get an 8x10 inch custom page size */
+<a href="#ppd_size_t">ppd_size_t</a> *size = <a href="#ppdPageSize">ppdPageSize</a>(ppd, "Custom.8x10in");
+
+/* Get a 100x200 millimeter custom page size */
+<a href="#ppd_size_t">ppd_size_t</a> *size = <a href="#ppdPageSize">ppdPageSize</a>(ppd, "Custom.100x200mm");
+
+/* Get a 12.7x34.5 centimeter custom page size */
+<a href="#ppd_size_t">ppd_size_t</a> *size = <a href="#ppdPageSize">ppdPageSize</a>(ppd, "Custom.12.7x34.5cm");
+</pre>
+
+<p>If the PPD does not support variable page sizes, the
+<a href="#ppdPageSize"><code>ppdPageSize</code></a> function will return
+<code>NULL</code>.</p>
+
+<h3><a name="ATTRIBUTES">Attributes</a></h3>
+
+<p>Every PPD file is composed of one or more attributes. Most of these
+attributes are used to define groups, options, choices, and page sizes,
+however several informational attributes may be present which you can access
+in your program or filter. Attributes normally look like one of the following
+examples in a PPD file:</p>
+
+<pre class="example">
+*name: "value"
+*name spec: "value"
+*name spec/text: "value"
+</pre>
+
+<p>The <a href="#ppdFindAttr"><code>ppdFindAttr</code></a> and
+<a href="#ppdFindNextAttr"><code>ppdFindNextAttr</code></a> functions find the
+first and next instances, respectively, of the named attribute with the given
+"spec" string and return a <a href="#ppd_attr_t"><code>ppd_attr_t</code></a>
+structure. If you provide a NULL specifier string, all attributes with the
+given name will be returned. For example, the following code lists all of the
+<code>Product</code> attributes in a PPD file:</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd;
+<a href="#ppd_attr_t">ppd_attr_t</a> *attr;
+
+for (attr = <a href="#ppdFindAttr">ppdFindAttr</a>(ppd, "Product", NULL);
+ attr != NULL;
+ attr = <a href="#ppdFindNextAttr">ppdFindNextAttr</a>(ppd, "Product", NULL))
+ puts(attr->value);
+</pre>
diff --git a/cups/array-private.h b/cups/array-private.h
new file mode 100644
index 000000000..f6b24e3d0
--- /dev/null
+++ b/cups/array-private.h
@@ -0,0 +1,51 @@
+/*
+ * "$Id$"
+ *
+ * Private array definitions for CUPS.
+ *
+ * Copyright 2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_ARRAY_PRIVATE_H_
+# define _CUPS_ARRAY_PRIVATE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include "array.h"
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Functions...
+ */
+
+extern int _cupsArrayAddStrings(cups_array_t *a, const char *s)
+ _CUPS_API_1_5;
+extern cups_array_t *_cupsArrayNewStrings(const char *s) _CUPS_API_1_5;
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_ARRAY_PRIVATE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/array.c b/cups/array.c
new file mode 100644
index 000000000..71c161c7d
--- /dev/null
+++ b/cups/array.c
@@ -0,0 +1,1326 @@
+/*
+ * "$Id$"
+ *
+ * Sorted array routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsArrayAdd() - Add an element to the array.
+ * _cupsArrayAddStrings() - Add zero or more comma-delimited strings to an
+ * 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.
+ * cupsArrayGetIndex() - Get the index of the current element.
+ * cupsArrayGetInsert() - Get the index of the last inserted element.
+ * cupsArrayIndex() - Get the N-th element in the array.
+ * cupsArrayInsert() - Insert an element in the array.
+ * cupsArrayLast() - Get the last element in the array.
+ * cupsArrayNew() - Create a new array.
+ * cupsArrayNew2() - Create a new array with hash.
+ * cupsArrayNew3() - Create a new array with hash and/or free function.
+ * _cupsArrayNewStrings() - Create a new array of comma-delimited strings.
+ * 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 @link
+ * cupsArraySave@.
+ * cupsArraySave() - Mark the current element for a later @link
+ * cupsArrayRestore@.
+ * cupsArrayUserData() - Return the user data for an array.
+ * cups_array_add() - Insert or append an element to the array.
+ * cups_array_find() - Find an element in the array.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "string-private.h"
+#include "debug-private.h"
+#include "array-private.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 */
+ unique, /* Are all elements unique? */
+ 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 */
+ cups_ahash_func_t hashfunc; /* Hash function */
+ int hashsize, /* Size of hash */
+ *hash; /* Hash array */
+ cups_acopy_func_t copyfunc; /* Copy function */
+ cups_afree_func_t freefunc; /* Free function */
+};
+
+
+/*
+ * Local functions...
+ */
+
+static int cups_array_add(cups_array_t *a, void *e, int insert);
+static int cups_array_find(cups_array_t *a, void *e, int prev, int *rdiff);
+
+
+/*
+ * 'cupsArrayAdd()' - Add an element to the array.
+ *
+ * When adding an element to a sorted array, non-unique elements are
+ * appended at the end of the run of identical elements. For unsorted arrays,
+ * the element is appended to the end of the array.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsArrayAdd(cups_array_t *a, /* I - Array */
+ void *e) /* I - Element */
+{
+ DEBUG_printf(("2cupsArrayAdd(a=%p, e=%p)", a, e));
+
+ /*
+ * Range check input...
+ */
+
+ if (!a || !e)
+ {
+ DEBUG_puts("3cupsArrayAdd: returning 0");
+ return (0);
+ }
+
+ /*
+ * Append the element...
+ */
+
+ return (cups_array_add(a, e, 0));
+}
+
+
+/*
+ * '_cupsArrayAddStrings()' - Add zero or more comma-delimited strings to an
+ * array.
+ *
+ * Note: The array MUST be created using the @link _cupsArrayNewStrings@
+ * function. Duplicate strings are NOT added. If the string pointer "s" is NULL
+ * or the empty string, no strings are added to the array.
+ */
+
+int /* O - 1 on success, 0 on failure */
+_cupsArrayAddStrings(cups_array_t *a, /* I - Array */
+ const char *s) /* I - Comma-delimited strings or NULL */
+{
+ char *buffer, /* Copy of string */
+ *start, /* Start of string */
+ *end; /* End of string */
+ int status = 1; /* Status of add */
+
+
+ if (!a || !s || !*s)
+ return (0);
+
+ if (!strchr(s, ','))
+ {
+ /*
+ * String doesn't contain a comma, so add it as a single value...
+ */
+
+ if (!cupsArrayFind(a, (void *)s))
+ status = cupsArrayAdd(a, (void *)s);
+ }
+ else if ((buffer = strdup(s)) == NULL)
+ status = 0;
+ else
+ {
+ for (start = end = buffer; *end; start = end)
+ {
+ /*
+ * Find the end of the current delimited string and see if we need to add
+ * it...
+ */
+
+ if ((end = strchr(start, ',')) != NULL)
+ *end++ = '\0';
+ else
+ end = start + strlen(start);
+
+ if (!cupsArrayFind(a, start))
+ status &= cupsArrayAdd(a, start);
+ }
+
+ free(buffer);
+ }
+
+ return (status);
+}
+
+
+/*
+ * 'cupsArrayClear()' - Clear the array.
+ *
+ * This function is equivalent to removing all elements in the array.
+ * The caller is responsible for freeing the memory used by the
+ * elements themselves.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void
+cupsArrayClear(cups_array_t *a) /* I - Array */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!a)
+ return;
+
+ /*
+ * Free the existing elements as needed..
+ */
+
+ if (a->freefunc)
+ {
+ int i; /* Looping var */
+ void **e; /* Current element */
+
+ for (i = a->num_elements, e = a->elements; i > 0; i --, e ++)
+ (a->freefunc)(*e, a->data);
+ }
+
+ /*
+ * 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->unique = 1;
+ a->num_saved = 0;
+}
+
+
+/*
+ * 'cupsArrayCount()' - Get the number of elements in the array.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+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.
+ *
+ * The current element is undefined until you call @link cupsArrayFind@,
+ * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+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.
+ *
+ * The caller is responsible for freeing the memory used by the
+ * elements themselves.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void
+cupsArrayDelete(cups_array_t *a) /* I - Array */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!a)
+ return;
+
+ /*
+ * Free the elements if we have a free function (otherwise the caller is
+ * responsible for doing the dirty work...)
+ */
+
+ if (a->freefunc)
+ {
+ int i; /* Looping var */
+ void **e; /* Current element */
+
+ for (i = a->num_elements, e = a->elements; i > 0; i --, e ++)
+ (a->freefunc)(*e, a->data);
+ }
+
+ /*
+ * Free the array of element pointers...
+ */
+
+ if (a->alloc_elements)
+ free(a->elements);
+
+ if (a->hashsize)
+ free(a->hash);
+
+ free(a);
+}
+
+
+/*
+ * 'cupsArrayDup()' - Duplicate the array.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+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->unique = a->unique;
+ 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...
+ */
+
+ if (a->copyfunc)
+ {
+ /*
+ * Use the copy function to make a copy of each element...
+ */
+
+ int i; /* Looping var */
+
+ for (i = 0; i < a->num_elements; i ++)
+ da->elements[i] = (a->copyfunc)(a->elements[i], a->data);
+ }
+ else
+ {
+ /*
+ * Just copy raw 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.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void * /* O - Element found or @code NULL@ */
+cupsArrayFind(cups_array_t *a, /* I - Array */
+ void *e) /* I - Element */
+{
+ int current, /* Current element */
+ diff, /* Difference */
+ hash; /* Hash index */
+
+
+ /*
+ * 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...
+ */
+
+ if (a->hash)
+ {
+ hash = (*(a->hashfunc))(e, a->data);
+
+ if (hash < 0 || hash >= a->hashsize)
+ {
+ current = a->current;
+ hash = -1;
+ }
+ else
+ {
+ current = a->hash[hash];
+
+ if (current < 0 || current >= a->num_elements)
+ current = a->current;
+ }
+ }
+ else
+ {
+ current = a->current;
+ hash = -1;
+ }
+
+ current = cups_array_find(a, e, current, &diff);
+ if (!diff)
+ {
+ /*
+ * Found a match! If the array does not contain unique values, find
+ * the first element that is the same...
+ */
+
+ if (!a->unique && a->compare)
+ {
+ /*
+ * The array is not unique, find the first match...
+ */
+
+ while (current > 0 && !(*(a->compare))(e, a->elements[current - 1],
+ a->data))
+ current --;
+ }
+
+ a->current = current;
+
+ if (hash >= 0)
+ a->hash[hash] = current;
+
+ return (a->elements[current]);
+ }
+ else
+ {
+ /*
+ * No match...
+ */
+
+ a->current = -1;
+
+ return (NULL);
+ }
+}
+
+
+/*
+ * 'cupsArrayFirst()' - Get the first element in the array.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void * /* O - First element or @code NULL@ if the array is empty */
+cupsArrayFirst(cups_array_t *a) /* I - Array */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!a)
+ return (NULL);
+
+ /*
+ * Return the first element...
+ */
+
+ a->current = 0;
+
+ return (cupsArrayCurrent(a));
+}
+
+
+/*
+ * 'cupsArrayGetIndex()' - Get the index of the current element.
+ *
+ * The current element is undefined until you call @link cupsArrayFind@,
+ * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@.
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+int /* O - Index of the current element, starting at 0 */
+cupsArrayGetIndex(cups_array_t *a) /* I - Array */
+{
+ if (!a)
+ return (-1);
+ else
+ return (a->current);
+}
+
+
+/*
+ * 'cupsArrayGetInsert()' - Get the index of the last inserted element.
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+int /* O - Index of the last inserted element, starting at 0 */
+cupsArrayGetInsert(cups_array_t *a) /* I - Array */
+{
+ if (!a)
+ return (-1);
+ else
+ return (a->insert);
+}
+
+
+/*
+ * 'cupsArrayIndex()' - Get the N-th element in the array.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void * /* O - N-th element or @code 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));
+}
+
+
+/*
+ * 'cupsArrayInsert()' - Insert an element in the array.
+ *
+ * When inserting an element in a sorted array, non-unique elements are
+ * inserted at the beginning of the run of identical elements. For unsorted
+ * arrays, the element is inserted at the beginning of the array.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 0 on failure, 1 on success */
+cupsArrayInsert(cups_array_t *a, /* I - Array */
+ void *e) /* I - Element */
+{
+ DEBUG_printf(("2cupsArrayInsert(a=%p, e=%p)", a, e));
+
+ /*
+ * Range check input...
+ */
+
+ if (!a || !e)
+ {
+ DEBUG_puts("3cupsArrayInsert: returning 0");
+ return (0);
+ }
+
+ /*
+ * Insert the element...
+ */
+
+ return (cups_array_add(a, e, 1));
+}
+
+
+/*
+ * 'cupsArrayLast()' - Get the last element in the array.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void * /* O - Last element or @code NULL@ if the array is empty */
+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.
+ *
+ * The comparison function ("f") is used to create a sorted array. The function
+ * receives pointers to two elements and the user data pointer ("d") - the user
+ * data pointer argument can safely be omitted when not required so functions
+ * like @code strcmp@ can be used for sorted string arrays.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+cups_array_t * /* O - Array */
+cupsArrayNew(cups_array_func_t f, /* I - Comparison function or @code NULL@ for an unsorted array */
+ void *d) /* I - User data pointer or @code NULL@ */
+{
+ return (cupsArrayNew3(f, d, 0, 0, 0, 0));
+}
+
+
+/*
+ * 'cupsArrayNew2()' - Create a new array with hash.
+ *
+ * The comparison function ("f") is used to create a sorted array. The function
+ * receives pointers to two elements and the user data pointer ("d") - the user
+ * data pointer argument can safely be omitted when not required so functions
+ * like @code strcmp@ can be used for sorted string arrays.
+ *
+ * The hash function ("h") is used to implement cached lookups with the
+ * specified hash size ("hsize").
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+cups_array_t * /* O - Array */
+cupsArrayNew2(cups_array_func_t f, /* I - Comparison function or @code NULL@ for an unsorted array */
+ void *d, /* I - User data or @code NULL@ */
+ cups_ahash_func_t h, /* I - Hash function or @code NULL@ for unhashed lookups */
+ int hsize) /* I - Hash size (>= 0) */
+{
+ return (cupsArrayNew3(f, d, h, hsize, 0, 0));
+}
+
+
+/*
+ * 'cupsArrayNew3()' - Create a new array with hash and/or free function.
+ *
+ * The comparison function ("f") is used to create a sorted array. The function
+ * receives pointers to two elements and the user data pointer ("d") - the user
+ * data pointer argument can safely be omitted when not required so functions
+ * like @code strcmp@ can be used for sorted string arrays.
+ *
+ * The hash function ("h") is used to implement cached lookups with the
+ * specified hash size ("hsize").
+ *
+ * The copy function ("cf") is used to automatically copy/retain elements when
+ * added or the array is copied.
+ *
+ * The free function ("cf") is used to automatically free/release elements when
+ * removed or the array is deleted.
+ *
+ * @since CUPS 1.5/Mac OS X 10.7@
+ */
+
+cups_array_t * /* O - Array */
+cupsArrayNew3(cups_array_func_t f, /* I - Comparison function or @code NULL@ for an unsorted array */
+ void *d, /* I - User data or @code NULL@ */
+ cups_ahash_func_t h, /* I - Hash function or @code NULL@ for unhashed lookups */
+ int hsize, /* I - Hash size (>= 0) */
+ cups_acopy_func_t cf, /* I - Copy function */
+ cups_afree_func_t ff) /* I - Free function */
+{
+ 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;
+ a->unique = 1;
+
+ if (hsize > 0 && h)
+ {
+ a->hashfunc = h;
+ a->hashsize = hsize;
+ a->hash = malloc(hsize * sizeof(int));
+
+ if (!a->hash)
+ {
+ free(a);
+ return (NULL);
+ }
+
+ memset(a->hash, -1, hsize * sizeof(int));
+ }
+
+ a->copyfunc = cf;
+ a->freefunc = ff;
+
+ return (a);
+}
+
+
+/*
+ * '_cupsArrayNewStrings()' - Create a new array of comma-delimited strings.
+ *
+ * Note: The array automatically manages copies of the strings passed. If the
+ * string pointer "s" is NULL or the empty string, no strings are added to the
+ * newly created array.
+ */
+
+cups_array_t * /* O - Array */
+_cupsArrayNewStrings(const char *s) /* I - Comma-delimited strings or NULL */
+{
+ cups_array_t *a; /* Array */
+
+
+ if ((a = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0,
+ (cups_acopy_func_t)_cupsStrAlloc,
+ (cups_afree_func_t)_cupsStrFree)) != NULL)
+ _cupsArrayAddStrings(a, s);
+
+ return (a);
+}
+
+
+/*
+ * 'cupsArrayNext()' - Get the next element in the array.
+ *
+ * This function is equivalent to "cupsArrayIndex(a, cupsArrayGetIndex(a) + 1)".
+ *
+ * The next element is undefined until you call @link cupsArrayFind@,
+ * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@
+ * to set the current element.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void * /* O - Next element or @code 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.
+ *
+ * This function is equivalent to "cupsArrayIndex(a, cupsArrayGetIndex(a) - 1)".
+ *
+ * The previous element is undefined until you call @link cupsArrayFind@,
+ * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@
+ * to set the current element.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void * /* O - Previous element or @code 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.
+ *
+ * If more than one element matches "e", only the first matching element is
+ * removed.
+ *
+ * The caller is responsible for freeing the memory used by the
+ * removed element.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+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_array_find(a, e, a->current, &diff);
+ if (diff)
+ return (0);
+
+ /*
+ * Yes, now remove it...
+ */
+
+ a->num_elements --;
+
+ if (a->freefunc)
+ (a->freefunc)(a->elements[current], a->data);
+
+ 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 --;
+ else if (current == a->insert)
+ a->insert = -1;
+
+ for (i = 0; i < a->num_saved; i ++)
+ if (current <= a->saved[i])
+ a->saved[i] --;
+
+ if (a->num_elements <= 1)
+ a->unique = 1;
+
+ return (1);
+}
+
+
+/*
+ * 'cupsArrayRestore()' - Reset the current element to the last @link cupsArraySave@.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+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 @link cupsArrayRestore@.
+ *
+ * The current element is undefined until you call @link cupsArrayFind@,
+ * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@
+ * to set the current element.
+ *
+ * The save/restore stack is guaranteed to be at least 32 elements deep.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+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);
+}
+
+
+/*
+ * 'cupsArrayUserData()' - Return the user data for an array.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void * /* O - User data */
+cupsArrayUserData(cups_array_t *a) /* I - Array */
+{
+ if (a)
+ return (a->data);
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'cups_array_add()' - Insert or append an element to the array.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+static int /* O - 1 on success, 0 on failure */
+cups_array_add(cups_array_t *a, /* I - Array */
+ void *e, /* I - Element to add */
+ int insert) /* I - 1 = insert, 0 = append */
+{
+ int i, /* Looping var */
+ current, /* Current element */
+ diff; /* Comparison with current element */
+
+
+ DEBUG_printf(("7cups_array_add(a=%p, e=%p, insert=%d)", a, e, insert));
+
+ /*
+ * 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(("9cups_array_add: count=%d", count));
+
+ if (!temp)
+ {
+ DEBUG_puts("9cups_array_add: 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 beginning or end...
+ */
+
+ if (!a->num_elements || !a->compare)
+ {
+ /*
+ * No elements or comparison function, insert/append as needed...
+ */
+
+ if (insert)
+ current = 0; /* Insert at beginning */
+ else
+ current = a->num_elements; /* Append to the end */
+ }
+ else
+ {
+ /*
+ * Do a binary search for the insertion point...
+ */
+
+ current = cups_array_find(a, e, a->insert, &diff);
+
+ if (diff > 0)
+ {
+ /*
+ * Insert after the current element...
+ */
+
+ current ++;
+ }
+ else if (!diff)
+ {
+ /*
+ * Compared equal, make sure we add to the begining or end of
+ * the current run of equal elements...
+ */
+
+ a->unique = 0;
+
+ if (insert)
+ {
+ /*
+ * Insert at beginning of run...
+ */
+
+ while (current > 0 && !(*(a->compare))(e, a->elements[current - 1],
+ a->data))
+ current --;
+ }
+ else
+ {
+ /*
+ * Append at end of run...
+ */
+
+ do
+ {
+ current ++;
+ }
+ while (current < a->num_elements &&
+ !(*(a->compare))(e, a->elements[current], a->data));
+ }
+ }
+ }
+
+ /*
+ * 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(("9cups_array_add: insert element at index %d...", current));
+ }
+#ifdef DEBUG
+ else
+ DEBUG_printf(("9cups_array_add: append element at %d...", current));
+#endif /* DEBUG */
+
+ if (a->copyfunc)
+ {
+ if ((a->elements[current] = (a->copyfunc)(e, a->data)) == NULL)
+ {
+ DEBUG_puts("8cups_array_add: Copy function returned NULL, returning 0");
+ return (0);
+ }
+ }
+ else
+ a->elements[current] = e;
+
+ a->num_elements ++;
+ a->insert = current;
+
+#ifdef DEBUG
+ for (current = 0; current < a->num_elements; current ++)
+ DEBUG_printf(("9cups_array_add: a->elements[%d]=%p", current,
+ a->elements[current]));
+#endif /* DEBUG */
+
+ DEBUG_puts("9cups_array_add: returning 1");
+
+ return (1);
+}
+
+
+/*
+ * 'cups_array_find()' - Find an element in the array.
+ */
+
+static int /* O - Index of match */
+cups_array_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(("7cups_array_find(a=%p, e=%p, prev=%d, rdiff=%p)", a, e, prev,
+ rdiff));
+
+ if (a->compare)
+ {
+ /*
+ * Do a binary search for the element...
+ */
+
+ DEBUG_puts("9cups_array_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(("9cups_array_find: Returning %d, diff=%d", 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(("9cups_array_find: left=%d, right=%d, current=%d, diff=%d",
+ 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("9cups_array_find: linear search");
+
+ diff = 1;
+
+ for (current = 0; current < a->num_elements; current ++)
+ if (a->elements[current] == e)
+ {
+ diff = 0;
+ break;
+ }
+ }
+
+ /*
+ * Return the closest element and the difference...
+ */
+
+ DEBUG_printf(("8cups_array_find: Returning %d, diff=%d", current, diff));
+
+ *rdiff = diff;
+
+ return (current);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/array.h b/cups/array.h
new file mode 100644
index 000000000..385b7dffc
--- /dev/null
+++ b/cups/array.h
@@ -0,0 +1,92 @@
+/*
+ * "$Id$"
+ *
+ * Sorted array definitions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "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 "versioning.h"
+# include <stdlib.h>
+
+
+/*
+ * 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 ****/
+typedef int (*cups_ahash_func_t)(void *element, void *data);
+ /**** Array hash function ****/
+typedef void *(*cups_acopy_func_t)(void *element, void *data);
+ /**** Array element copy function ****/
+typedef void (*cups_afree_func_t)(void *element, void *data);
+ /**** Array element free function ****/
+
+
+/*
+ * Functions...
+ */
+
+extern int cupsArrayAdd(cups_array_t *a, void *e) _CUPS_API_1_2;
+extern void cupsArrayClear(cups_array_t *a) _CUPS_API_1_2;
+extern int cupsArrayCount(cups_array_t *a) _CUPS_API_1_2;
+extern void *cupsArrayCurrent(cups_array_t *a) _CUPS_API_1_2;
+extern void cupsArrayDelete(cups_array_t *a) _CUPS_API_1_2;
+extern cups_array_t *cupsArrayDup(cups_array_t *a) _CUPS_API_1_2;
+extern void *cupsArrayFind(cups_array_t *a, void *e) _CUPS_API_1_2;
+extern void *cupsArrayFirst(cups_array_t *a) _CUPS_API_1_2;
+extern int cupsArrayGetIndex(cups_array_t *a) _CUPS_API_1_3;
+extern int cupsArrayGetInsert(cups_array_t *a) _CUPS_API_1_3;
+extern void *cupsArrayIndex(cups_array_t *a, int n) _CUPS_API_1_2;
+extern int cupsArrayInsert(cups_array_t *a, void *e) _CUPS_API_1_2;
+extern void *cupsArrayLast(cups_array_t *a) _CUPS_API_1_2;
+extern cups_array_t *cupsArrayNew(cups_array_func_t f, void *d) _CUPS_API_1_2;
+extern cups_array_t *cupsArrayNew2(cups_array_func_t f, void *d,
+ cups_ahash_func_t h, int hsize) _CUPS_API_1_3;
+extern cups_array_t *cupsArrayNew3(cups_array_func_t f, void *d,
+ cups_ahash_func_t h, int hsize,
+ cups_acopy_func_t cf,
+ cups_afree_func_t ff) _CUPS_API_1_5;
+extern void *cupsArrayNext(cups_array_t *a) _CUPS_API_1_2;
+extern void *cupsArrayPrev(cups_array_t *a) _CUPS_API_1_2;
+extern int cupsArrayRemove(cups_array_t *a, void *e) _CUPS_API_1_2;
+extern void *cupsArrayRestore(cups_array_t *a) _CUPS_API_1_2;
+extern int cupsArraySave(cups_array_t *a) _CUPS_API_1_2;
+extern void *cupsArrayUserData(cups_array_t *a) _CUPS_API_1_2;
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_ARRAY_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/attr.c b/cups/attr.c
new file mode 100644
index 000000000..10e1dfd14
--- /dev/null
+++ b/cups/attr.c
@@ -0,0 +1,335 @@
+/*
+ * "$Id$"
+ *
+ * PPD model-specific attribute routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * ppdFindAttr() - Find the first matching attribute.
+ * ppdFindNextAttr() - Find the next matching attribute.
+ * _ppdNormalizeMakeAndModel() - Normalize a product/make-and-model string.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include "ppd-private.h"
+
+
+/*
+ * 'ppdFindAttr()' - Find the first matching attribute.
+ *
+ * @since CUPS 1.1.19/Mac OS X 10.3@
+ */
+
+ppd_attr_t * /* O - Attribute or @code 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 @code NULL@ */
+{
+ ppd_attr_t key, /* Search key */
+ *attr; /* Current attribute */
+
+
+ DEBUG_printf(("2ppdFindAttr(ppd=%p, name=\"%s\", spec=\"%s\")", ppd, name,
+ spec));
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !name || ppd->num_attrs == 0)
+ return (NULL);
+
+ /*
+ * Search for a matching attribute...
+ */
+
+ memset(&key, 0, sizeof(key));
+ strlcpy(key.name, name, sizeof(key.name));
+
+ /*
+ * Return the first matching attribute, if any...
+ */
+
+ if ((attr = (ppd_attr_t *)cupsArrayFind(ppd->sorted_attrs, &key)) != NULL)
+ {
+ if (spec)
+ {
+ /*
+ * Loop until we find the first matching attribute for "spec"...
+ */
+
+ while (attr && _cups_strcasecmp(spec, attr->spec))
+ {
+ if ((attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs)) != NULL &&
+ _cups_strcasecmp(attr->name, name))
+ attr = NULL;
+ }
+ }
+ }
+
+ return (attr);
+}
+
+
+/*
+ * 'ppdFindNextAttr()' - Find the next matching attribute.
+ *
+ * @since CUPS 1.1.19/Mac OS X 10.3@
+ */
+
+ppd_attr_t * /* O - Attribute or @code 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 @code NULL@ */
+{
+ ppd_attr_t *attr; /* Current attribute */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !name || ppd->num_attrs == 0)
+ return (NULL);
+
+ /*
+ * See if there are more attributes to return...
+ */
+
+ while ((attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs)) != NULL)
+ {
+ /*
+ * Check the next attribute to see if it is a match...
+ */
+
+ if (_cups_strcasecmp(attr->name, name))
+ {
+ /*
+ * Nope, reset the current pointer to the end of the array...
+ */
+
+ cupsArrayIndex(ppd->sorted_attrs, cupsArrayCount(ppd->sorted_attrs));
+
+ return (NULL);
+ }
+
+ if (!spec || !_cups_strcasecmp(attr->spec, spec))
+ break;
+ }
+
+ /*
+ * Return the next attribute's value...
+ */
+
+ return (attr);
+}
+
+
+/*
+ * '_ppdNormalizeMakeAndModel()' - Normalize a product/make-and-model string.
+ *
+ * This function tries to undo the mistakes made by many printer manufacturers
+ * to produce a clean make-and-model string we can use.
+ */
+
+char * /* O - Normalized make-and-model string or NULL on error */
+_ppdNormalizeMakeAndModel(
+ const char *make_and_model, /* I - Original make-and-model string */
+ char *buffer, /* I - String buffer */
+ size_t bufsize) /* I - Size of string buffer */
+{
+ char *bufptr; /* Pointer into buffer */
+
+
+ if (!make_and_model || !buffer || bufsize < 1)
+ {
+ if (buffer)
+ *buffer = '\0';
+
+ return (NULL);
+ }
+
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (_cups_isspace(*make_and_model))
+ make_and_model ++;
+
+ /*
+ * Remove parenthesis and add manufacturers as needed...
+ */
+
+ if (make_and_model[0] == '(')
+ {
+ strlcpy(buffer, make_and_model + 1, bufsize);
+
+ if ((bufptr = strrchr(buffer, ')')) != NULL)
+ *bufptr = '\0';
+ }
+ else if (!_cups_strncasecmp(make_and_model, "XPrint", 6))
+ {
+ /*
+ * Xerox XPrint...
+ */
+
+ snprintf(buffer, bufsize, "Xerox %s", make_and_model);
+ }
+ else if (!_cups_strncasecmp(make_and_model, "Eastman", 7))
+ {
+ /*
+ * Kodak...
+ */
+
+ snprintf(buffer, bufsize, "Kodak %s", make_and_model + 7);
+ }
+ else if (!_cups_strncasecmp(make_and_model, "laserwriter", 11))
+ {
+ /*
+ * Apple LaserWriter...
+ */
+
+ snprintf(buffer, bufsize, "Apple LaserWriter%s", make_and_model + 11);
+ }
+ else if (!_cups_strncasecmp(make_and_model, "colorpoint", 10))
+ {
+ /*
+ * Seiko...
+ */
+
+ snprintf(buffer, bufsize, "Seiko %s", make_and_model);
+ }
+ else if (!_cups_strncasecmp(make_and_model, "fiery", 5))
+ {
+ /*
+ * EFI...
+ */
+
+ snprintf(buffer, bufsize, "EFI %s", make_and_model);
+ }
+ else if (!_cups_strncasecmp(make_and_model, "ps ", 3) ||
+ !_cups_strncasecmp(make_and_model, "colorpass", 9))
+ {
+ /*
+ * Canon...
+ */
+
+ snprintf(buffer, bufsize, "Canon %s", make_and_model);
+ }
+ else if (!_cups_strncasecmp(make_and_model, "primera", 7))
+ {
+ /*
+ * Fargo...
+ */
+
+ snprintf(buffer, bufsize, "Fargo %s", make_and_model);
+ }
+ else if (!_cups_strncasecmp(make_and_model, "designjet", 9) ||
+ !_cups_strncasecmp(make_and_model, "deskjet", 7))
+ {
+ /*
+ * HP...
+ */
+
+ snprintf(buffer, bufsize, "HP %s", make_and_model);
+ }
+ else
+ strlcpy(buffer, make_and_model, bufsize);
+
+ /*
+ * Clean up the make...
+ */
+
+ if (!_cups_strncasecmp(buffer, "agfa", 4))
+ {
+ /*
+ * Replace with AGFA (all uppercase)...
+ */
+
+ buffer[0] = 'A';
+ buffer[1] = 'G';
+ buffer[2] = 'F';
+ buffer[3] = 'A';
+ }
+ else if (!_cups_strncasecmp(buffer, "Hewlett-Packard hp ", 19))
+ {
+ /*
+ * Just put "HP" on the front...
+ */
+
+ buffer[0] = 'H';
+ buffer[1] = 'P';
+ _cups_strcpy(buffer + 2, buffer + 18);
+ }
+ else if (!_cups_strncasecmp(buffer, "Hewlett-Packard ", 16))
+ {
+ /*
+ * Just put "HP" on the front...
+ */
+
+ buffer[0] = 'H';
+ buffer[1] = 'P';
+ _cups_strcpy(buffer + 2, buffer + 15);
+ }
+ else if (!_cups_strncasecmp(buffer, "Lexmark International", 21))
+ {
+ /*
+ * Strip "International"...
+ */
+
+ _cups_strcpy(buffer + 8, buffer + 21);
+ }
+ else if (!_cups_strncasecmp(buffer, "herk", 4))
+ {
+ /*
+ * Replace with LHAG...
+ */
+
+ buffer[0] = 'L';
+ buffer[1] = 'H';
+ buffer[2] = 'A';
+ buffer[3] = 'G';
+ }
+ else if (!_cups_strncasecmp(buffer, "linotype", 8))
+ {
+ /*
+ * Replace with LHAG...
+ */
+
+ buffer[0] = 'L';
+ buffer[1] = 'H';
+ buffer[2] = 'A';
+ buffer[3] = 'G';
+ _cups_strcpy(buffer + 4, buffer + 8);
+ }
+
+ /*
+ * Remove trailing whitespace and return...
+ */
+
+ for (bufptr = buffer + strlen(buffer) - 1;
+ bufptr >= buffer && _cups_isspace(*bufptr);
+ bufptr --);
+
+ bufptr[1] = '\0';
+
+ return (buffer[0] ? buffer : NULL);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/auth.c b/cups/auth.c
new file mode 100644
index 000000000..608c40c2b
--- /dev/null
+++ b/cups/auth.c
@@ -0,0 +1,877 @@
+/*
+ * "$Id$"
+ *
+ * Authentication functions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * This file contains Kerberos support code, copyright 2006 by
+ * Jelmer Vernooij.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsDoAuthentication() - Authenticate a request.
+ * _cupsSetNegotiateAuthString() - Set the Kerberos authentication string.
+ * cups_gss_acquire() - Kerberos credentials callback.
+ * cups_gss_getname() - Get CUPS service credentials for
+ * authentication.
+ * cups_gss_printf() - Show debug error messages from GSSAPI.
+ * cups_local_auth() - Get the local authorization certificate if
+ * available/applicable.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include <fcntl.h>
+#include <sys/stat.h>
+#if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+#else
+# include <unistd.h>
+#endif /* WIN32 || __EMX__ */
+
+#if HAVE_AUTHORIZATION_H
+# include <Security/Authorization.h>
+# ifdef HAVE_SECBASEPRIV_H
+# include <Security/SecBasePriv.h>
+# else
+extern const char *cssmErrorString(int error);
+# endif /* HAVE_SECBASEPRIV_H */
+#endif /* HAVE_AUTHORIZATION_H */
+
+#if defined(SO_PEERCRED) && defined(AF_LOCAL)
+# include <pwd.h>
+#endif /* SO_PEERCRED && AF_LOCAL */
+
+
+/*
+ * Local functions...
+ */
+
+#ifdef HAVE_GSSAPI
+# ifdef HAVE_GSS_ACQUIRE_CRED_EX_F
+# ifdef HAVE_GSS_GSSAPI_SPI_H
+# include <GSS/gssapi_spi.h>
+# else
+typedef struct gss_auth_identity
+{
+ uint32_t type;
+ uint32_t flags;
+ char *username;
+ char *realm;
+ char *password;
+ gss_buffer_t *credentialsRef;
+} gss_auth_identity_desc;
+extern OM_uint32 gss_acquire_cred_ex_f(gss_status_id_t, const gss_name_t,
+ OM_uint32, OM_uint32, const gss_OID,
+ gss_cred_usage_t, gss_auth_identity_t,
+ void *, void (*)(void *, OM_uint32,
+ gss_status_id_t,
+ gss_cred_id_t,
+ gss_OID_set,
+ OM_uint32));
+# endif /* HAVE_GSS_GSSAPI_SPI_H */
+# include <dispatch/dispatch.h>
+typedef struct _cups_gss_acquire_s /* Acquire callback data */
+{
+ dispatch_semaphore_t sem; /* Synchronization semaphore */
+ OM_uint32 major; /* Returned status code */
+ gss_cred_id_t creds; /* Returned credentials */
+} _cups_gss_acquire_t;
+
+static void cups_gss_acquire(void *ctx, OM_uint32 major,
+ gss_status_id_t status,
+ gss_cred_id_t creds, gss_OID_set oids,
+ OM_uint32 time_rec);
+# endif /* HAVE_GSS_ACQUIRE_CRED_EX_F */
+static gss_name_t cups_gss_getname(http_t *http, const char *service_name);
+# ifdef DEBUG
+static void cups_gss_printf(OM_uint32 major_status, OM_uint32 minor_status,
+ const char *message);
+# else
+# define cups_gss_printf(major, minor, message)
+# endif /* DEBUG */
+#endif /* HAVE_GSSAPI */
+static int cups_local_auth(http_t *http);
+
+
+/*
+ * 'cupsDoAuthentication()' - Authenticate a request.
+ *
+ * This function should be called in response to a @code HTTP_UNAUTHORIZED@
+ * status, prior to resubmitting your request.
+ *
+ * @since CUPS 1.1.20/Mac OS X 10.4@
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsDoAuthentication(
+ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ 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 */
+ int localauth; /* Local authentication result */
+ _cups_globals_t *cg; /* Global data */
+
+
+ DEBUG_printf(("cupsDoAuthentication(http=%p, method=\"%s\", resource=\"%s\")",
+ http, method, resource));
+
+ if (!http)
+ http = _cupsConnect();
+
+ if (!http || !method || !resource)
+ return (-1);
+
+ DEBUG_printf(("2cupsDoAuthentication: digest_tries=%d, userpass=\"%s\"",
+ http->digest_tries, http->userpass));
+ DEBUG_printf(("2cupsDoAuthentication: WWW-Authenticate=\"%s\"",
+ httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE)));
+
+ /*
+ * Clear the current authentication string...
+ */
+
+ httpSetAuthString(http, NULL, NULL);
+
+ /*
+ * See if we can do local authentication...
+ */
+
+ if (http->digest_tries < 3)
+ {
+ if ((localauth = cups_local_auth(http)) == 0)
+ {
+ DEBUG_printf(("2cupsDoAuthentication: authstring=\"%s\"",
+ http->authstring));
+
+ if (http->status == HTTP_UNAUTHORIZED)
+ http->digest_tries ++;
+
+ return (0);
+ }
+ else if (localauth == -1)
+ {
+ http->status = HTTP_AUTHORIZATION_CANCELED;
+ return (-1); /* Error or canceled */
+ }
+ }
+
+ /*
+ * Nope, see if we should retry the current username:password...
+ */
+
+ if ((http->digest_tries > 1 || !http->userpass[0]) &&
+ (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) ||
+ !strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Digest", 6)))
+ {
+ /*
+ * Nope - get a new password from the user...
+ */
+
+ cg = _cupsGlobals();
+
+ if (!cg->lang_default)
+ cg->lang_default = cupsLangDefault();
+
+ snprintf(prompt, sizeof(prompt),
+ _cupsLangString(cg->lang_default, _("Password for %s on %s? ")),
+ cupsUser(),
+ http->hostname[0] == '/' ? "localhost" : http->hostname);
+
+ http->digest_tries = _cups_strncasecmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE],
+ "Digest", 5) != 0;
+ http->userpass[0] = '\0';
+
+ if ((password = cupsGetPassword2(prompt, http, method, resource)) == NULL)
+ {
+ http->status = HTTP_AUTHORIZATION_CANCELED;
+ return (-1);
+ }
+
+ snprintf(http->userpass, sizeof(http->userpass), "%s:%s", cupsUser(),
+ password);
+ }
+ else if (http->status == HTTP_UNAUTHORIZED)
+ http->digest_tries ++;
+
+ if (http->status == HTTP_UNAUTHORIZED && http->digest_tries >= 3)
+ {
+ DEBUG_printf(("1cupsDoAuthentication: Too many authentication tries (%d)",
+ http->digest_tries));
+
+ http->status = HTTP_AUTHORIZATION_CANCELED;
+ return (-1);
+ }
+
+ /*
+ * Got a password; encode it for the server...
+ */
+
+#ifdef HAVE_GSSAPI
+ if (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9))
+ {
+ /*
+ * Kerberos authentication...
+ */
+
+ if (_cupsSetNegotiateAuthString(http, method, resource))
+ {
+ http->status = HTTP_AUTHORIZATION_CANCELED;
+ return (-1);
+ }
+ }
+ else
+#endif /* HAVE_GSSAPI */
+ if (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5))
+ {
+ /*
+ * Basic authentication...
+ */
+
+ char encode[256]; /* Base64 buffer */
+
+
+ httpEncode64_2(encode, sizeof(encode), http->userpass,
+ (int)strlen(http->userpass));
+ httpSetAuthString(http, "Basic", encode);
+ }
+ else if (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Digest", 6))
+ {
+ /*
+ * Digest authentication...
+ */
+
+ char encode[33], /* MD5 buffer */
+ digest[1024]; /* Digest auth data */
+
+
+ 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(digest, sizeof(digest),
+ "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", "
+ "response=\"%s\"", cupsUser(), realm, nonce, resource, encode);
+ httpSetAuthString(http, "Digest", digest);
+ }
+ else
+ {
+ DEBUG_printf(("1cupsDoAuthentication: Unknown auth type: \"%s\"",
+ http->fields[HTTP_FIELD_WWW_AUTHENTICATE]));
+ http->status = HTTP_AUTHORIZATION_CANCELED;
+ return (-1);
+ }
+
+ DEBUG_printf(("1cupsDoAuthentication: authstring=\"%s\"", http->authstring));
+
+ return (0);
+}
+
+
+#ifdef HAVE_GSSAPI
+/*
+ * '_cupsSetNegotiateAuthString()' - Set the Kerberos authentication string.
+ */
+
+int /* O - 0 on success, -1 on error */
+_cupsSetNegotiateAuthString(
+ http_t *http, /* I - Connection to server */
+ const char *method, /* I - Request method ("GET", "POST", "PUT") */
+ const char *resource) /* I - Resource path */
+{
+ OM_uint32 minor_status, /* Minor status code */
+ major_status; /* Major status code */
+ gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+ /* Output token */
+
+
+ (void)method;
+ (void)resource;
+
+# ifdef __APPLE__
+ /*
+ * If the weak-linked GSSAPI/Kerberos library is not present, don't try
+ * to use it...
+ */
+
+ if (gss_init_sec_context == NULL)
+ {
+ DEBUG_puts("1_cupsSetNegotiateAuthString: Weak-linked GSSAPI/Kerberos "
+ "framework is not present");
+ return (-1);
+ }
+# endif /* __APPLE__ */
+
+ if (http->gssname == GSS_C_NO_NAME)
+ {
+ http->gssname = cups_gss_getname(http, _cupsGSSServiceName());
+ }
+
+ if (http->gssctx != GSS_C_NO_CONTEXT)
+ {
+ gss_delete_sec_context(&minor_status, &http->gssctx, GSS_C_NO_BUFFER);
+ http->gssctx = GSS_C_NO_CONTEXT;
+ }
+
+ major_status = gss_init_sec_context(&minor_status, GSS_C_NO_CREDENTIAL,
+ &http->gssctx,
+ http->gssname, http->gssmech,
+ GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ GSS_C_NO_BUFFER, &http->gssmech,
+ &output_token, NULL, NULL);
+
+#ifdef HAVE_GSS_ACQUIRE_CRED_EX_F
+ if (major_status == GSS_S_NO_CRED)
+ {
+ /*
+ * Ask the user for credentials...
+ */
+
+ char prompt[1024], /* Prompt for user */
+ userbuf[256]; /* Kerberos username */
+ const char *username, /* Username string */
+ *password; /* Password string */
+ _cups_gss_acquire_t data; /* Callback data */
+ gss_auth_identity_desc identity; /* Kerberos user identity */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Per-thread global data */
+
+ if (!cg->lang_default)
+ cg->lang_default = cupsLangDefault();
+
+ snprintf(prompt, sizeof(prompt),
+ _cupsLangString(cg->lang_default, _("Password for %s on %s? ")),
+ cupsUser(), http->gsshost);
+
+ if ((password = cupsGetPassword2(prompt, http, method, resource)) == NULL)
+ return (-1);
+
+ /*
+ * Try to acquire credentials...
+ */
+
+ username = cupsUser();
+ if (!strchr(username, '@'))
+ {
+ snprintf(userbuf, sizeof(userbuf), "%s@%s", username, http->gsshost);
+ username = userbuf;
+ }
+
+ identity.type = GSS_AUTH_IDENTITY_TYPE_1;
+ identity.flags = 0;
+ identity.username = (char *)username;
+ identity.realm = (char *)"";
+ identity.password = (char *)password;
+ identity.credentialsRef = NULL;
+
+ data.sem = dispatch_semaphore_create(0);
+ data.major = 0;
+ data.creds = NULL;
+
+ if (data.sem)
+ {
+ major_status = gss_acquire_cred_ex_f(NULL, GSS_C_NO_NAME, 0,
+ GSS_C_INDEFINITE, GSS_KRB5_MECHANISM,
+ GSS_C_INITIATE, &identity, &data,
+ cups_gss_acquire);
+
+ if (major_status == GSS_S_COMPLETE)
+ {
+ dispatch_semaphore_wait(data.sem, DISPATCH_TIME_FOREVER);
+ major_status = data.major;
+ }
+
+ dispatch_release(data.sem);
+
+ if (major_status == GSS_S_COMPLETE)
+ {
+ OM_uint32 release_minor; /* Minor status from releasing creds */
+
+ major_status = gss_init_sec_context(&minor_status, data.creds,
+ &http->gssctx,
+ http->gssname, http->gssmech,
+ GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ GSS_C_NO_BUFFER, &http->gssmech,
+ &output_token, NULL, NULL);
+ gss_release_cred(&release_minor, &data.creds);
+ }
+ }
+ }
+ else
+#endif /* HAVE_GSS_ACQUIRED_CRED_EX_F */
+
+ if (GSS_ERROR(major_status))
+ {
+ cups_gss_printf(major_status, minor_status,
+ "_cupsSetNegotiateAuthString: Unable to initialize "
+ "security context");
+ return (-1);
+ }
+
+#ifdef DEBUG
+ else if (major_status == GSS_S_CONTINUE_NEEDED)
+ cups_gss_printf(major_status, minor_status,
+ "_cupsSetNegotiateAuthString: Continuation needed!");
+#endif /* DEBUG */
+
+ if (output_token.length > 0 && output_token.length <= 65536)
+ {
+ /*
+ * Allocate the authorization string since Windows KDCs can have
+ * arbitrarily large credentials...
+ */
+
+ int authsize = 10 + /* "Negotiate " */
+ output_token.length * 4 / 3 + 1 + /* Base64 */
+ 1; /* nul */
+
+ httpSetAuthString(http, NULL, NULL);
+
+ if ((http->authstring = malloc(authsize)) == NULL)
+ {
+ http->authstring = http->_authstring;
+ authsize = sizeof(http->_authstring);
+ }
+
+ strcpy(http->authstring, "Negotiate ");
+ httpEncode64_2(http->authstring + 10, authsize - 10, output_token.value,
+ output_token.length);
+
+ gss_release_buffer(&minor_status, &output_token);
+ }
+ else
+ {
+ DEBUG_printf(("1_cupsSetNegotiateAuthString: Kerberos credentials too "
+ "large - %d bytes!", (int)output_token.length));
+ gss_release_buffer(&minor_status, &output_token);
+
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+# ifdef HAVE_GSS_ACQUIRE_CRED_EX_F
+/*
+ * 'cups_gss_acquire()' - Kerberos credentials callback.
+ */
+static void
+cups_gss_acquire(
+ void *ctx, /* I - Caller context */
+ OM_uint32 major, /* I - Major error code */
+ gss_status_id_t status, /* I - Status (unused) */
+ gss_cred_id_t creds, /* I - Credentials (if any) */
+ gss_OID_set oids, /* I - Mechanism OIDs (unused) */
+ OM_uint32 time_rec) /* I - Timestamp (unused) */
+{
+ uint32_t min; /* Minor error code */
+ _cups_gss_acquire_t *data; /* Callback data */
+
+
+ (void)status;
+ (void)time_rec;
+
+ data = (_cups_gss_acquire_t *)ctx;
+ data->major = major;
+ data->creds = creds;
+
+ gss_release_oid_set(&min, &oids);
+ dispatch_semaphore_signal(data->sem);
+}
+# endif /* HAVE_GSS_ACQUIRE_CRED_EX_F */
+
+
+/*
+ * 'cups_gss_getname()' - Get CUPS service credentials for authentication.
+ */
+
+static gss_name_t /* O - Server name */
+cups_gss_getname(
+ http_t *http, /* I - Connection to server */
+ const char *service_name) /* I - Service name */
+{
+ gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
+ /* Service token */
+ OM_uint32 major_status, /* Major status code */
+ minor_status; /* Minor status code */
+ gss_name_t server_name; /* Server name */
+ char buf[1024]; /* Name buffer */
+
+
+ DEBUG_printf(("7cups_gss_getname(http=%p, service_name=\"%s\")", http,
+ service_name));
+
+
+ /*
+ * Get the hostname...
+ */
+
+ if (!http->gsshost[0])
+ {
+ httpGetHostname(http, http->gsshost, sizeof(http->gsshost));
+
+ if (!strcmp(http->gsshost, "localhost"))
+ {
+ if (gethostname(http->gsshost, sizeof(http->gsshost)) < 0)
+ {
+ DEBUG_printf(("1cups_gss_getname: gethostname() failed: %s",
+ strerror(errno)));
+ http->gsshost[0] = '\0';
+ return (NULL);
+ }
+
+ if (!strchr(http->gsshost, '.'))
+ {
+ /*
+ * The hostname is not a FQDN, so look it up...
+ */
+
+ struct hostent *host; /* Host entry to get FQDN */
+
+ if ((host = gethostbyname(http->gsshost)) != NULL && host->h_name)
+ {
+ /*
+ * Use the resolved hostname...
+ */
+
+ strlcpy(http->gsshost, host->h_name, sizeof(http->gsshost));
+ }
+ else
+ {
+ DEBUG_printf(("1cups_gss_getname: gethostbyname(\"%s\") failed.",
+ http->gsshost));
+ http->gsshost[0] = '\0';
+ return (NULL);
+ }
+ }
+ }
+ }
+
+ /*
+ * Get a service name we can use for authentication purposes...
+ */
+
+ snprintf(buf, sizeof(buf), "%s@%s", service_name, http->gsshost);
+
+ DEBUG_printf(("8cups_gss_getname: Looking up \"%s\".", buf));
+
+ token.value = buf;
+ token.length = strlen(buf);
+ server_name = GSS_C_NO_NAME;
+ major_status = gss_import_name(&minor_status, &token,
+ GSS_C_NT_HOSTBASED_SERVICE,
+ &server_name);
+
+ if (GSS_ERROR(major_status))
+ {
+ cups_gss_printf(major_status, minor_status,
+ "cups_gss_getname: gss_import_name() failed");
+ return (NULL);
+ }
+
+ return (server_name);
+}
+
+
+# ifdef DEBUG
+/*
+ * 'cups_gss_printf()' - Show debug error messages from GSSAPI.
+ */
+
+static void
+cups_gss_printf(OM_uint32 major_status,/* I - Major status code */
+ OM_uint32 minor_status,/* I - Minor status code */
+ const char *message) /* I - Prefix for error message */
+{
+ OM_uint32 err_major_status, /* Major status code for display */
+ err_minor_status; /* Minor status code for display */
+ OM_uint32 msg_ctx; /* Message context */
+ gss_buffer_desc major_status_string = GSS_C_EMPTY_BUFFER,
+ /* Major status message */
+ minor_status_string = GSS_C_EMPTY_BUFFER;
+ /* Minor status message */
+
+
+ msg_ctx = 0;
+ err_major_status = gss_display_status(&err_minor_status,
+ major_status,
+ GSS_C_GSS_CODE,
+ GSS_C_NO_OID,
+ &msg_ctx,
+ &major_status_string);
+
+ if (!GSS_ERROR(err_major_status))
+ gss_display_status(&err_minor_status, minor_status, GSS_C_MECH_CODE,
+ GSS_C_NULL_OID, &msg_ctx, &minor_status_string);
+
+ DEBUG_printf(("1%s: %s, %s", message, (char *)major_status_string.value,
+ (char *)minor_status_string.value));
+
+ gss_release_buffer(&err_minor_status, &major_status_string);
+ gss_release_buffer(&err_minor_status, &minor_status_string);
+}
+# endif /* DEBUG */
+#endif /* HAVE_GSSAPI */
+
+
+/*
+ * 'cups_local_auth()' - Get the local authorization certificate if
+ * available/applicable.
+ */
+
+static int /* O - 0 if available */
+ /* 1 if not available */
+ /* -1 error */
+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 trc[16], /* Try Root Certificate parameter */
+ filename[1024], /* Certificate filename */
+ certificate[33];/* Certificate string */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+# if defined(HAVE_AUTHORIZATION_H)
+ OSStatus status; /* Status */
+ AuthorizationItem auth_right; /* Authorization right */
+ AuthorizationRights auth_rights; /* Authorization rights */
+ AuthorizationFlags auth_flags; /* Authorization flags */
+ AuthorizationExternalForm auth_extrn; /* Authorization ref external */
+ char auth_key[1024]; /* Buffer */
+ char buffer[1024]; /* Buffer */
+# endif /* HAVE_AUTHORIZATION_H */
+
+
+ DEBUG_printf(("7cups_local_auth(http=%p) hostaddr=%s, hostname=\"%s\"",
+ http, httpAddrString(http->hostaddr, filename, sizeof(filename)), http->hostname));
+
+ /*
+ * See if we are accessing localhost...
+ */
+
+ if (!httpAddrLocalhost(http->hostaddr) &&
+ _cups_strcasecmp(http->hostname, "localhost") != 0)
+ {
+ DEBUG_puts("8cups_local_auth: Not a local connection!");
+ return (1);
+ }
+
+# if defined(HAVE_AUTHORIZATION_H)
+ /*
+ * Delete any previous authorization reference...
+ */
+
+ if (http->auth_ref)
+ {
+ AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults);
+ http->auth_ref = NULL;
+ }
+
+ if (!getenv("GATEWAY_INTERFACE") &&
+ httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey",
+ auth_key, sizeof(auth_key)))
+ {
+ status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
+ kAuthorizationFlagDefaults, &http->auth_ref);
+ if (status != errAuthorizationSuccess)
+ {
+ DEBUG_printf(("8cups_local_auth: AuthorizationCreate() returned %d (%s)",
+ (int)status, cssmErrorString(status)));
+ return (-1);
+ }
+
+ auth_right.name = auth_key;
+ auth_right.valueLength = 0;
+ auth_right.value = NULL;
+ auth_right.flags = 0;
+
+ auth_rights.count = 1;
+ auth_rights.items = &auth_right;
+
+ auth_flags = kAuthorizationFlagDefaults |
+ kAuthorizationFlagPreAuthorize |
+ kAuthorizationFlagInteractionAllowed |
+ kAuthorizationFlagExtendRights;
+
+ status = AuthorizationCopyRights(http->auth_ref, &auth_rights,
+ kAuthorizationEmptyEnvironment,
+ auth_flags, NULL);
+ if (status == errAuthorizationSuccess)
+ status = AuthorizationMakeExternalForm(http->auth_ref, &auth_extrn);
+
+ if (status == errAuthorizationSuccess)
+ {
+ /*
+ * Set the authorization string and return...
+ */
+
+ httpEncode64_2(buffer, sizeof(buffer), (void *)&auth_extrn,
+ sizeof(auth_extrn));
+
+ httpSetAuthString(http, "AuthRef", buffer);
+
+ DEBUG_printf(("8cups_local_auth: Returning authstring=\"%s\"",
+ http->authstring));
+ return (0);
+ }
+ else if (status == errAuthorizationCanceled)
+ return (-1);
+
+ DEBUG_printf(("9cups_local_auth: AuthorizationCopyRights() returned %d (%s)",
+ (int)status, cssmErrorString(status)));
+
+ /*
+ * Fall through to try certificates...
+ */
+ }
+# endif /* HAVE_AUTHORIZATION_H */
+
+# if defined(SO_PEERCRED) && defined(AF_LOCAL)
+ /*
+ * See if we can authenticate using the peer credentials provided over a
+ * domain socket; if so, specify "PeerCred username" as the authentication
+ * information...
+ */
+
+ if (
+# ifdef HAVE_GSSAPI
+ strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9) &&
+# endif /* HAVE_GSSAPI */
+# ifdef HAVE_AUTHORIZATION_H
+ !httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey",
+ auth_key, sizeof(auth_key)) &&
+# endif /* HAVE_AUTHORIZATION_H */
+ http->hostaddr->addr.sa_family == AF_LOCAL &&
+ !getenv("GATEWAY_INTERFACE")) /* Not via CGI programs... */
+ {
+ /*
+ * Verify that the current cupsUser() matches the current UID...
+ */
+
+ struct passwd *pwd; /* Password information */
+ const char *username; /* Current username */
+
+ username = cupsUser();
+
+ if ((pwd = getpwnam(username)) != NULL && pwd->pw_uid == getuid())
+ {
+ httpSetAuthString(http, "PeerCred", username);
+
+ DEBUG_printf(("8cups_local_auth: Returning authstring=\"%s\"",
+ http->authstring));
+
+ return (0);
+ }
+ }
+# endif /* SO_PEERCRED && AF_LOCAL */
+
+ /*
+ * 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)
+ {
+ /*
+ * No certificate for this PID; see if we can get the root certificate...
+ */
+
+ DEBUG_printf(("9cups_local_auth: Unable to open file %s: %s",
+ filename, strerror(errno)));
+
+# ifdef HAVE_GSSAPI
+ if (!strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9))
+ {
+ /*
+ * Kerberos required, don't try the root certificate...
+ */
+
+ return (1);
+ }
+# endif /* HAVE_GSSAPI */
+
+# ifdef HAVE_AUTHORIZATION_H
+ if (httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey",
+ auth_key, sizeof(auth_key)))
+ {
+ /*
+ * Don't use the root certificate as a replacement for an authkey...
+ */
+
+ return (1);
+ }
+# endif /* HAVE_AUTHORIZATION_H */
+ if (!httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "trc", trc,
+ sizeof(trc)))
+ {
+ /*
+ * Scheduler doesn't want us to use the root certificate...
+ */
+
+ return (1);
+ }
+
+ snprintf(filename, sizeof(filename), "%s/certs/0", cg->cups_statedir);
+ fp = fopen(filename, "r");
+ }
+
+ if (fp)
+ {
+ /*
+ * Read the certificate from the file...
+ */
+
+ fgets(certificate, sizeof(certificate), fp);
+ fclose(fp);
+
+ /*
+ * Set the authorization string and return...
+ */
+
+ httpSetAuthString(http, "Local", certificate);
+
+ DEBUG_printf(("8cups_local_auth: Returning authstring=\"%s\"",
+ http->authstring));
+
+ return (0);
+ }
+
+ return (1);
+#endif /* WIN32 || __EMX__ */
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/backchannel.c b/cups/backchannel.c
new file mode 100644
index 000000000..faf8ec069
--- /dev/null
+++ b/cups/backchannel.c
@@ -0,0 +1,199 @@
+/*
+ * "$Id$"
+ *
+ * Backchannel functions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "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 <errno.h>
+#ifdef WIN32
+# include <io.h>
+# include <fcntl.h>
+#else
+# include <sys/time.h>
+#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/backend. 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/Mac OS X 10.5@
+ */
+
+ssize_t /* O - Bytes read or -1 on error */
+cupsBackChannelRead(char *buffer, /* I - Buffer to read into */
+ size_t bytes, /* I - Bytes to read */
+ double timeout) /* I - Timeout in seconds, typically 0.0 to poll */
+{
+ 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 && errno != EAGAIN);
+
+ if (status < 0)
+ return (-1); /* Timeout! */
+
+ /*
+ * Read bytes from the pipe...
+ */
+
+#ifdef WIN32
+ return ((ssize_t)_read(3, buffer, (unsigned)bytes));
+#else
+ return (read(3, buffer, bytes));
+#endif /* WIN32 */
+}
+
+
+/*
+ * 'cupsBackChannelWrite()' - Write data to the backchannel.
+ *
+ * Writes "bytes" bytes to the backchannel/filter. 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/Mac OS X 10.5@
+ */
+
+ssize_t /* O - Bytes written or -1 on error */
+cupsBackChannelWrite(
+ const char *buffer, /* I - Buffer to write */
+ size_t bytes, /* I - Bytes to write */
+ double timeout) /* I - Timeout in seconds, typically 1.0 */
+{
+ fd_set output; /* Output set */
+ struct timeval tval; /* Timeout value */
+ int status; /* Select status */
+ ssize_t count; /* Current bytes */
+ size_t 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 && errno != EAGAIN);
+
+ if (status <= 0)
+ return (-1); /* Timeout! */
+
+ /*
+ * Write bytes to the pipe...
+ */
+
+#ifdef WIN32
+ count = (ssize_t)_write(3, buffer, (unsigned)(bytes - total));
+#else
+ count = write(3, buffer, bytes - total);
+#endif /* WIN32 */
+
+ 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 ((ssize_t)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$".
+ */
diff --git a/cups/backend.c b/cups/backend.c
new file mode 100644
index 000000000..d09794f8b
--- /dev/null
+++ b/cups/backend.c
@@ -0,0 +1,140 @@
+/*
+ * "$Id$"
+ *
+ * Backend functions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsBackendDeviceURI() - Get the device URI for a backend.
+ * cupsBackendReport() - Write a device line from a backend.
+ * quote_string() - Write a quoted string to stdout, escaping \ and ".
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include "backend.h"
+
+
+/*
+ * Local functions...
+ */
+
+static void quote_string(const char *s);
+
+
+/*
+ * 'cupsBackendDeviceURI()' - Get the device URI for a backend.
+ *
+ * The "argv" argument is the argv argument passed to main(). This
+ * function returns the device URI passed in the DEVICE_URI environment
+ * variable or the device URI passed in argv[0], whichever is found
+ * first.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+const char * /* O - Device URI or @code NULL@ */
+cupsBackendDeviceURI(char **argv) /* I - Command-line arguments */
+{
+ const char *device_uri, /* Device URI */
+ *auth_info_required; /* AUTH_INFO_REQUIRED env var */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global info */
+ int options; /* Resolve options */
+
+
+ if ((device_uri = getenv("DEVICE_URI")) == NULL)
+ {
+ if (!argv || !argv[0] || !strchr(argv[0], ':'))
+ return (NULL);
+
+ device_uri = argv[0];
+ }
+
+ options = _HTTP_RESOLVE_STDERR;
+ if ((auth_info_required = getenv("AUTH_INFO_REQUIRED")) != NULL &&
+ !strcmp(auth_info_required, "negotiate"))
+ options |= _HTTP_RESOLVE_FQDN;
+
+ return (_httpResolveURI(device_uri, cg->resolved_uri,
+ sizeof(cg->resolved_uri), options, NULL, NULL));
+}
+
+
+/*
+ * 'cupsBackendReport()' - Write a device line from a backend.
+ *
+ * This function writes a single device line to stdout for a backend.
+ * It handles quoting of special characters in the device-make-and-model,
+ * device-info, device-id, and device-location strings.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+void
+cupsBackendReport(
+ const char *device_scheme, /* I - device-scheme string */
+ const char *device_uri, /* I - device-uri string */
+ const char *device_make_and_model, /* I - device-make-and-model string or @code NULL@ */
+ const char *device_info, /* I - device-info string or @code NULL@ */
+ const char *device_id, /* I - device-id string or @code NULL@ */
+ const char *device_location) /* I - device-location string or @code NULL@ */
+{
+ if (!device_scheme || !device_uri)
+ return;
+
+ printf("%s %s", device_scheme, device_uri);
+ if (device_make_and_model && *device_make_and_model)
+ quote_string(device_make_and_model);
+ else
+ quote_string("unknown");
+ quote_string(device_info);
+ quote_string(device_id);
+ quote_string(device_location);
+ putchar('\n');
+ fflush(stdout);
+}
+
+
+/*
+ * 'quote_string()' - Write a quoted string to stdout, escaping \ and ".
+ */
+
+static void
+quote_string(const char *s) /* I - String to write */
+{
+ fputs(" \"", stdout);
+
+ if (s)
+ {
+ while (*s)
+ {
+ if (*s == '\\' || *s == '\"')
+ putchar('\\');
+
+ putchar(*s);
+
+ s ++;
+ }
+ }
+
+ putchar('\"');
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/backend.h b/cups/backend.h
new file mode 100644
index 000000000..85941c71a
--- /dev/null
+++ b/cups/backend.h
@@ -0,0 +1,78 @@
+/*
+ * "$Id$"
+ *
+ * Backend definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_BACKEND_H_
+# define _CUPS_BACKEND_H_
+
+
+/*
+ * Include necessary headers...
+ */
+
+# include "versioning.h"
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+/*
+ * Constants...
+ */
+
+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_AUTH_REQUIRED = 2, /* Job failed, authentication required */
+ CUPS_BACKEND_HOLD = 3, /* Job failed, hold job */
+ CUPS_BACKEND_STOP = 4, /* Job failed, stop queue */
+ CUPS_BACKEND_CANCEL = 5, /* Job failed, cancel job */
+ CUPS_BACKEND_RETRY = 6, /* Job failed, retry this job later */
+ CUPS_BACKEND_RETRY_CURRENT = 7 /* Job failed, retry this job immediately */
+};
+typedef enum cups_backend_e cups_backend_t;
+ /**** Backend exit codes ****/
+
+
+/*
+ * Prototypes...
+ */
+
+extern const char *cupsBackendDeviceURI(char **argv) _CUPS_API_1_2;
+extern void cupsBackendReport(const char *device_scheme,
+ const char *device_uri,
+ const char *device_make_and_model,
+ const char *device_info,
+ const char *device_id,
+ const char *device_location)
+ _CUPS_API_1_4;
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_BACKEND_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/conflicts.c b/cups/conflicts.c
new file mode 100644
index 000000000..dd1bf3deb
--- /dev/null
+++ b/cups/conflicts.c
@@ -0,0 +1,1214 @@
+/*
+ * "$Id$"
+ *
+ * Option marking routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * PostScript is a trademark of Adobe Systems, Inc.
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsGetConflicts() - Get a list of conflicting options in a marked
+ * PPD.
+ * cupsResolveConflicts() - Resolve conflicts in a marked PPD.
+ * ppdConflicts() - Check to see if there are any conflicts among
+ * the marked option choices.
+ * ppdInstallableConflict() - Test whether an option choice conflicts with an
+ * installable option.
+ * ppd_is_installable() - Determine whether an option is in the
+ * InstallableOptions group.
+ * ppd_load_constraints() - Load constraints from a PPD file.
+ * ppd_test_constraints() - See if any constraints are active.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include "ppd-private.h"
+
+
+/*
+ * Local constants...
+ */
+
+enum
+{
+ _PPD_NORMAL_CONSTRAINTS,
+ _PPD_OPTION_CONSTRAINTS,
+ _PPD_INSTALLABLE_CONSTRAINTS,
+ _PPD_ALL_CONSTRAINTS
+};
+
+
+/*
+ * Local functions...
+ */
+
+static int ppd_is_installable(ppd_group_t *installable,
+ const char *option);
+static void ppd_load_constraints(ppd_file_t *ppd);
+static cups_array_t *ppd_test_constraints(ppd_file_t *ppd,
+ const char *option,
+ const char *choice,
+ int num_options,
+ cups_option_t *options,
+ int which);
+
+
+/*
+ * 'cupsGetConflicts()' - Get a list of conflicting options in a marked PPD.
+ *
+ * This function gets a list of options that would conflict if "option" and
+ * "choice" were marked in the PPD. You would typically call this function
+ * after marking the currently selected options in the PPD in order to
+ * determine whether a new option selection would cause a conflict.
+ *
+ * The number of conflicting options are returned with "options" pointing to
+ * the conflicting options. The returned option array must be freed using
+ * @link cupsFreeOptions@.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+int /* O - Number of conflicting options */
+cupsGetConflicts(
+ ppd_file_t *ppd, /* I - PPD file */
+ const char *option, /* I - Option to test */
+ const char *choice, /* I - Choice to test */
+ cups_option_t **options) /* O - Conflicting options */
+{
+ int i, /* Looping var */
+ num_options; /* Number of conflicting options */
+ cups_array_t *active; /* Active conflicts */
+ _ppd_cups_uiconsts_t *c; /* Current constraints */
+ _ppd_cups_uiconst_t *cptr; /* Current constraint */
+ ppd_choice_t *marked; /* Marked choice */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (options)
+ *options = NULL;
+
+ if (!ppd || !option || !choice || !options)
+ return (0);
+
+ /*
+ * Test for conflicts...
+ */
+
+ active = ppd_test_constraints(ppd, option, choice, 0, NULL,
+ _PPD_ALL_CONSTRAINTS);
+
+ /*
+ * Loop through all of the UI constraints and add any options that conflict...
+ */
+
+ for (num_options = 0, c = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active);
+ c;
+ c = (_ppd_cups_uiconsts_t *)cupsArrayNext(active))
+ {
+ for (i = c->num_constraints, cptr = c->constraints;
+ i > 0;
+ i --, cptr ++)
+ if (_cups_strcasecmp(cptr->option->keyword, option))
+ {
+ if (cptr->choice)
+ num_options = cupsAddOption(cptr->option->keyword,
+ cptr->choice->choice, num_options,
+ options);
+ else if ((marked = ppdFindMarkedChoice(ppd,
+ cptr->option->keyword)) != NULL)
+ num_options = cupsAddOption(cptr->option->keyword, marked->choice,
+ num_options, options);
+ }
+ }
+
+ cupsArrayDelete(active);
+
+ return (num_options);
+}
+
+
+/*
+ * 'cupsResolveConflicts()' - Resolve conflicts in a marked PPD.
+ *
+ * This function attempts to resolve any conflicts in a marked PPD, returning
+ * a list of option changes that are required to resolve them. On input,
+ * "num_options" and "options" contain any pending option changes that have
+ * not yet been marked, while "option" and "choice" contain the most recent
+ * selection which may or may not be in "num_options" or "options".
+ *
+ * On successful return, "num_options" and "options" are updated to contain
+ * "option" and "choice" along with any changes required to resolve conflicts
+ * specified in the PPD file and 1 is returned.
+ *
+ * If option conflicts cannot be resolved, "num_options" and "options" are not
+ * changed and 0 is returned.
+ *
+ * When resolving conflicts, @code cupsResolveConflicts@ does not consider
+ * changes to the current page size (@code media@, @code PageSize@, and
+ * @code PageRegion@) or to the most recent option specified in "option".
+ * Thus, if the only way to resolve a conflict is to change the page size
+ * or the option the user most recently changed, @code cupsResolveConflicts@
+ * will return 0 to indicate it was unable to resolve the conflicts.
+ *
+ * The @code cupsResolveConflicts@ function uses one of two sources of option
+ * constraint information. The preferred constraint information is defined by
+ * @code cupsUIConstraints@ and @code cupsUIResolver@ attributes - in this
+ * case, the PPD file provides constraint resolution actions.
+ *
+ * The backup constraint information is defined by the
+ * @code UIConstraints@ and @code NonUIConstraints@ attributes. These
+ * constraints are resolved algorithmically by first selecting the default
+ * choice for the conflicting option, then iterating over all possible choices
+ * until a non-conflicting option choice is found.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsResolveConflicts(
+ ppd_file_t *ppd, /* I - PPD file */
+ const char *option, /* I - Newly selected option or @code NULL@ for none */
+ const char *choice, /* I - Newly selected choice or @code NULL@ for none */
+ int *num_options, /* IO - Number of additional selected options */
+ cups_option_t **options) /* IO - Additional selected options */
+{
+ int i, /* Looping var */
+ tries, /* Number of tries */
+ num_newopts; /* Number of new options */
+ cups_option_t *newopts; /* New options */
+ cups_array_t *active, /* Active constraints */
+ *pass, /* Resolvers for this pass */
+ *resolvers, /* Resolvers we have used */
+ *test; /* Test array for conflicts */
+ _ppd_cups_uiconsts_t *consts; /* Current constraints */
+ _ppd_cups_uiconst_t *constptr; /* Current constraint */
+ ppd_attr_t *resolver; /* Current resolver */
+ const char *resval; /* Pointer into resolver value */
+ char resoption[PPD_MAX_NAME],
+ /* Current resolver option */
+ reschoice[PPD_MAX_NAME],
+ /* Current resolver choice */
+ *resptr, /* Pointer into option/choice */
+ firstpage[255]; /* AP_FIRSTPAGE_Keyword string */
+ const char *value; /* Selected option value */
+ int changed; /* Did we change anything? */
+ ppd_choice_t *marked; /* Marked choice */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !num_options || !options || (option == NULL) != (choice == NULL))
+ return (0);
+
+ /*
+ * Build a shadow option array...
+ */
+
+ num_newopts = 0;
+ newopts = NULL;
+
+ for (i = 0; i < *num_options; i ++)
+ num_newopts = cupsAddOption((*options)[i].name, (*options)[i].value,
+ num_newopts, &newopts);
+ if (option && _cups_strcasecmp(option, "Collate"))
+ num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
+
+ /*
+ * Loop until we have no conflicts...
+ */
+
+ cupsArraySave(ppd->sorted_attrs);
+
+ resolvers = NULL;
+ pass = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL);
+ tries = 0;
+
+ while (tries < 100 &&
+ (active = ppd_test_constraints(ppd, NULL, NULL, num_newopts, newopts,
+ _PPD_ALL_CONSTRAINTS)) != NULL)
+ {
+ tries ++;
+
+ if (!resolvers)
+ resolvers = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL);
+
+ for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active), changed = 0;
+ consts;
+ consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(active))
+ {
+ if (consts->resolver[0])
+ {
+ /*
+ * Look up the resolver...
+ */
+
+ if (cupsArrayFind(pass, consts->resolver))
+ continue; /* Already applied this resolver... */
+
+ if (cupsArrayFind(resolvers, consts->resolver))
+ {
+ /*
+ * Resolver loop!
+ */
+
+ DEBUG_printf(("1ppdResolveConflicts: Resolver loop with %s!",
+ consts->resolver));
+ goto error;
+ }
+
+ if ((resolver = ppdFindAttr(ppd, "cupsUIResolver",
+ consts->resolver)) == NULL)
+ {
+ DEBUG_printf(("1ppdResolveConflicts: Resolver %s not found!",
+ consts->resolver));
+ goto error;
+ }
+
+ if (!resolver->value)
+ {
+ DEBUG_printf(("1ppdResolveConflicts: Resolver %s has no value!",
+ consts->resolver));
+ goto error;
+ }
+
+ /*
+ * Add the options from the resolver...
+ */
+
+ cupsArrayAdd(pass, consts->resolver);
+ cupsArrayAdd(resolvers, consts->resolver);
+
+ for (resval = resolver->value; *resval && !changed;)
+ {
+ while (_cups_isspace(*resval))
+ resval ++;
+
+ if (*resval != '*')
+ break;
+
+ for (resval ++, resptr = resoption;
+ *resval && !_cups_isspace(*resval);
+ resval ++)
+ if (resptr < (resoption + sizeof(resoption) - 1))
+ *resptr++ = *resval;
+
+ *resptr = '\0';
+
+ while (_cups_isspace(*resval))
+ resval ++;
+
+ for (resptr = reschoice;
+ *resval && !_cups_isspace(*resval);
+ resval ++)
+ if (resptr < (reschoice + sizeof(reschoice) - 1))
+ *resptr++ = *resval;
+
+ *resptr = '\0';
+
+ if (!resoption[0] || !reschoice[0])
+ break;
+
+ /*
+ * Is this the option we are changing?
+ */
+
+ snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s", resoption);
+
+ if (option &&
+ (!_cups_strcasecmp(resoption, option) ||
+ !_cups_strcasecmp(firstpage, option) ||
+ (!_cups_strcasecmp(option, "PageSize") &&
+ !_cups_strcasecmp(resoption, "PageRegion")) ||
+ (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") &&
+ !_cups_strcasecmp(resoption, "PageSize")) ||
+ (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") &&
+ !_cups_strcasecmp(resoption, "PageRegion")) ||
+ (!_cups_strcasecmp(option, "PageRegion") &&
+ !_cups_strcasecmp(resoption, "PageSize")) ||
+ (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion") &&
+ !_cups_strcasecmp(resoption, "PageSize")) ||
+ (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion") &&
+ !_cups_strcasecmp(resoption, "PageRegion"))))
+ continue;
+
+ /*
+ * Try this choice...
+ */
+
+ if ((test = ppd_test_constraints(ppd, resoption, reschoice,
+ num_newopts, newopts,
+ _PPD_ALL_CONSTRAINTS)) == NULL)
+ {
+ /*
+ * That worked...
+ */
+
+ changed = 1;
+ }
+ else
+ cupsArrayDelete(test);
+
+ /*
+ * Add the option/choice from the resolver regardless of whether it
+ * worked; this makes sure that we can cascade several changes to
+ * make things resolve...
+ */
+
+ num_newopts = cupsAddOption(resoption, reschoice, num_newopts,
+ &newopts);
+ }
+ }
+ else
+ {
+ /*
+ * Try resolving by choosing the default values for non-installable
+ * options, then by iterating through the possible choices...
+ */
+
+ int j; /* Looping var */
+ ppd_choice_t *cptr; /* Current choice */
+ ppd_size_t *size; /* Current page size */
+
+
+ for (i = consts->num_constraints, constptr = consts->constraints;
+ i > 0 && !changed;
+ i --, constptr ++)
+ {
+ /*
+ * Can't resolve by changing an installable option...
+ */
+
+ if (constptr->installable)
+ continue;
+
+ /*
+ * Is this the option we are changing?
+ */
+
+ if (option &&
+ (!_cups_strcasecmp(constptr->option->keyword, option) ||
+ (!_cups_strcasecmp(option, "PageSize") &&
+ !_cups_strcasecmp(constptr->option->keyword, "PageRegion")) ||
+ (!_cups_strcasecmp(option, "PageRegion") &&
+ !_cups_strcasecmp(constptr->option->keyword, "PageSize"))))
+ continue;
+
+ /*
+ * Get the current option choice...
+ */
+
+ if ((value = cupsGetOption(constptr->option->keyword, num_newopts,
+ newopts)) == NULL)
+ {
+ if (!_cups_strcasecmp(constptr->option->keyword, "PageSize") ||
+ !_cups_strcasecmp(constptr->option->keyword, "PageRegion"))
+ {
+ if ((value = cupsGetOption("PageSize", num_newopts,
+ newopts)) == NULL)
+ value = cupsGetOption("PageRegion", num_newopts, newopts);
+
+ if (!value)
+ {
+ if ((size = ppdPageSize(ppd, NULL)) != NULL)
+ value = size->name;
+ else
+ value = "";
+ }
+ }
+ else
+ {
+ marked = ppdFindMarkedChoice(ppd, constptr->option->keyword);
+ value = marked ? marked->choice : "";
+ }
+ }
+
+ if (!_cups_strncasecmp(value, "Custom.", 7))
+ value = "Custom";
+
+ /*
+ * Try the default choice...
+ */
+
+ test = NULL;
+
+ if (_cups_strcasecmp(value, constptr->option->defchoice) &&
+ (test = ppd_test_constraints(ppd, constptr->option->keyword,
+ constptr->option->defchoice,
+ num_newopts, newopts,
+ _PPD_OPTION_CONSTRAINTS)) == NULL)
+ {
+ /*
+ * That worked...
+ */
+
+ num_newopts = cupsAddOption(constptr->option->keyword,
+ constptr->option->defchoice,
+ num_newopts, &newopts);
+ changed = 1;
+ }
+ else
+ {
+ /*
+ * Try each choice instead...
+ */
+
+ for (j = constptr->option->num_choices,
+ cptr = constptr->option->choices;
+ j > 0;
+ j --, cptr ++)
+ {
+ cupsArrayDelete(test);
+ test = NULL;
+
+ if (_cups_strcasecmp(value, cptr->choice) &&
+ _cups_strcasecmp(constptr->option->defchoice, cptr->choice) &&
+ _cups_strcasecmp("Custom", cptr->choice) &&
+ (test = ppd_test_constraints(ppd, constptr->option->keyword,
+ cptr->choice, num_newopts,
+ newopts,
+ _PPD_OPTION_CONSTRAINTS)) == NULL)
+ {
+ /*
+ * This choice works...
+ */
+
+ num_newopts = cupsAddOption(constptr->option->keyword,
+ cptr->choice, num_newopts,
+ &newopts);
+ changed = 1;
+ break;
+ }
+ }
+
+ cupsArrayDelete(test);
+ }
+ }
+ }
+ }
+
+ if (!changed)
+ {
+ DEBUG_puts("1ppdResolveConflicts: Unable to automatically resolve "
+ "constraint!");
+ goto error;
+ }
+
+ cupsArrayClear(pass);
+ cupsArrayDelete(active);
+ active = NULL;
+ }
+
+ if (tries >= 100)
+ goto error;
+
+ /*
+ * Free the caller's option array...
+ */
+
+ cupsFreeOptions(*num_options, *options);
+
+ /*
+ * If Collate is the option we are testing, add it here. Otherwise, remove
+ * any Collate option from the resolve list since the filters automatically
+ * handle manual collation...
+ */
+
+ if (option && !_cups_strcasecmp(option, "Collate"))
+ num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
+ else
+ num_newopts = cupsRemoveOption("Collate", num_newopts, &newopts);
+
+ /*
+ * Return the new list of options to the caller...
+ */
+
+ *num_options = num_newopts;
+ *options = newopts;
+
+ cupsArrayDelete(pass);
+ cupsArrayDelete(resolvers);
+
+ cupsArrayRestore(ppd->sorted_attrs);
+
+ DEBUG_printf(("1cupsResolveConflicts: Returning %d options:", num_newopts));
+#ifdef DEBUG
+ for (i = 0; i < num_newopts; i ++)
+ DEBUG_printf(("1cupsResolveConflicts: options[%d]: %s=%s", i,
+ newopts[i].name, newopts[i].value));
+#endif /* DEBUG */
+
+ return (1);
+
+ /*
+ * If we get here, we failed to resolve...
+ */
+
+ error:
+
+ cupsFreeOptions(num_newopts, newopts);
+
+ cupsArrayDelete(active);
+ cupsArrayDelete(pass);
+ cupsArrayDelete(resolvers);
+
+ cupsArrayRestore(ppd->sorted_attrs);
+
+ DEBUG_puts("1cupsResolveConflicts: Unable to resolve conflicts!");
+
+ return (0);
+}
+
+
+/*
+ * 'ppdConflicts()' - Check to see if there are any conflicts among the
+ * marked option choices.
+ *
+ * The returned value is the same as returned by @link ppdMarkOption@.
+ */
+
+int /* O - Number of conflicts found */
+ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */
+{
+ int i, /* Looping variable */
+ conflicts; /* Number of conflicts */
+ cups_array_t *active; /* Active conflicts */
+ _ppd_cups_uiconsts_t *c; /* Current constraints */
+ _ppd_cups_uiconst_t *cptr; /* Current constraint */
+ ppd_option_t *o; /* Current option */
+
+
+ if (!ppd)
+ return (0);
+
+ /*
+ * Clear all conflicts...
+ */
+
+ cupsArraySave(ppd->options);
+
+ for (o = ppdFirstOption(ppd); o; o = ppdNextOption(ppd))
+ o->conflicted = 0;
+
+ cupsArrayRestore(ppd->options);
+
+ /*
+ * Test for conflicts...
+ */
+
+ active = ppd_test_constraints(ppd, NULL, NULL, 0, NULL,
+ _PPD_ALL_CONSTRAINTS);
+ conflicts = cupsArrayCount(active);
+
+ /*
+ * Loop through all of the UI constraints and flag any options
+ * that conflict...
+ */
+
+ for (c = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active);
+ c;
+ c = (_ppd_cups_uiconsts_t *)cupsArrayNext(active))
+ {
+ for (i = c->num_constraints, cptr = c->constraints;
+ i > 0;
+ i --, cptr ++)
+ cptr->option->conflicted = 1;
+ }
+
+ cupsArrayDelete(active);
+
+ /*
+ * Return the number of conflicts found...
+ */
+
+ return (conflicts);
+}
+
+
+/*
+ * 'ppdInstallableConflict()' - Test whether an option choice conflicts with
+ * an installable option.
+ *
+ * This function tests whether a particular option choice is available based
+ * on constraints against options in the "InstallableOptions" group.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+int /* O - 1 if conflicting, 0 if not conflicting */
+ppdInstallableConflict(
+ ppd_file_t *ppd, /* I - PPD file */
+ const char *option, /* I - Option */
+ const char *choice) /* I - Choice */
+{
+ cups_array_t *active; /* Active conflicts */
+
+
+ DEBUG_printf(("2ppdInstallableConflict(ppd=%p, option=\"%s\", choice=\"%s\")",
+ ppd, option, choice));
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !option || !choice)
+ return (0);
+
+ /*
+ * Test constraints using the new option...
+ */
+
+ active = ppd_test_constraints(ppd, option, choice, 0, NULL,
+ _PPD_INSTALLABLE_CONSTRAINTS);
+
+ cupsArrayDelete(active);
+
+ return (active != NULL);
+}
+
+
+/*
+ * 'ppd_is_installable()' - Determine whether an option is in the
+ * InstallableOptions group.
+ */
+
+static int /* O - 1 if installable, 0 if normal */
+ppd_is_installable(
+ ppd_group_t *installable, /* I - InstallableOptions group */
+ const char *name) /* I - Option name */
+{
+ if (installable)
+ {
+ int i; /* Looping var */
+ ppd_option_t *option; /* Current option */
+
+
+ for (i = installable->num_options, option = installable->options;
+ i > 0;
+ i --, option ++)
+ if (!_cups_strcasecmp(option->keyword, name))
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'ppd_load_constraints()' - Load constraints from a PPD file.
+ */
+
+static void
+ppd_load_constraints(ppd_file_t *ppd) /* I - PPD file */
+{
+ int i; /* Looping var */
+ ppd_const_t *oldconst; /* Current UIConstraints data */
+ ppd_attr_t *constattr; /* Current cupsUIConstraints attribute */
+ _ppd_cups_uiconsts_t *consts; /* Current cupsUIConstraints data */
+ _ppd_cups_uiconst_t *constptr; /* Current constraint */
+ ppd_group_t *installable; /* Installable options group */
+ const char *vptr; /* Pointer into constraint value */
+ char option[PPD_MAX_NAME], /* Option name/MainKeyword */
+ choice[PPD_MAX_NAME], /* Choice/OptionKeyword */
+ *ptr; /* Pointer into option or choice */
+
+
+ DEBUG_printf(("7ppd_load_constraints(ppd=%p)", ppd));
+
+ /*
+ * Create an array to hold the constraint data...
+ */
+
+ ppd->cups_uiconstraints = cupsArrayNew(NULL, NULL);
+
+ /*
+ * Find the installable options group if it exists...
+ */
+
+ for (i = ppd->num_groups, installable = ppd->groups;
+ i > 0;
+ i --, installable ++)
+ if (!_cups_strcasecmp(installable->name, "InstallableOptions"))
+ break;
+
+ if (i <= 0)
+ installable = NULL;
+
+ /*
+ * Load old-style [Non]UIConstraints data...
+ */
+
+ for (i = ppd->num_consts, oldconst = ppd->consts; i > 0; i --, oldconst ++)
+ {
+ /*
+ * Weed out nearby duplicates, since the PPD spec requires that you
+ * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"...
+ */
+
+ if (i > 1 &&
+ !_cups_strcasecmp(oldconst[0].option1, oldconst[1].option2) &&
+ !_cups_strcasecmp(oldconst[0].choice1, oldconst[1].choice2) &&
+ !_cups_strcasecmp(oldconst[0].option2, oldconst[1].option1) &&
+ !_cups_strcasecmp(oldconst[0].choice2, oldconst[1].choice1))
+ continue;
+
+ /*
+ * Allocate memory...
+ */
+
+ if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
+ {
+ DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
+ "UIConstraints!");
+ return;
+ }
+
+ if ((constptr = calloc(2, sizeof(_ppd_cups_uiconst_t))) == NULL)
+ {
+ free(consts);
+ DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
+ "UIConstraints!");
+ return;
+ }
+
+ /*
+ * Fill in the information...
+ */
+
+ consts->num_constraints = 2;
+ consts->constraints = constptr;
+
+ if (!_cups_strncasecmp(oldconst->option1, "Custom", 6) &&
+ !_cups_strcasecmp(oldconst->choice1, "True"))
+ {
+ constptr[0].option = ppdFindOption(ppd, oldconst->option1 + 6);
+ constptr[0].choice = ppdFindChoice(constptr[0].option, "Custom");
+ constptr[0].installable = 0;
+ }
+ else
+ {
+ constptr[0].option = ppdFindOption(ppd, oldconst->option1);
+ constptr[0].choice = ppdFindChoice(constptr[0].option,
+ oldconst->choice1);
+ constptr[0].installable = ppd_is_installable(installable,
+ oldconst->option1);
+ }
+
+ if (!constptr[0].option || (!constptr[0].choice && oldconst->choice1[0]))
+ {
+ DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
+ oldconst->option1, oldconst->choice1));
+ free(consts->constraints);
+ free(consts);
+ continue;
+ }
+
+ if (!_cups_strncasecmp(oldconst->option2, "Custom", 6) &&
+ !_cups_strcasecmp(oldconst->choice2, "True"))
+ {
+ constptr[1].option = ppdFindOption(ppd, oldconst->option2 + 6);
+ constptr[1].choice = ppdFindChoice(constptr[1].option, "Custom");
+ constptr[1].installable = 0;
+ }
+ else
+ {
+ constptr[1].option = ppdFindOption(ppd, oldconst->option2);
+ constptr[1].choice = ppdFindChoice(constptr[1].option,
+ oldconst->choice2);
+ constptr[1].installable = ppd_is_installable(installable,
+ oldconst->option2);
+ }
+
+ if (!constptr[1].option || (!constptr[1].choice && oldconst->choice2[0]))
+ {
+ DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
+ oldconst->option2, oldconst->choice2));
+ free(consts->constraints);
+ free(consts);
+ continue;
+ }
+
+ consts->installable = constptr[0].installable || constptr[1].installable;
+
+ /*
+ * Add it to the constraints array...
+ */
+
+ cupsArrayAdd(ppd->cups_uiconstraints, consts);
+ }
+
+ /*
+ * Then load new-style constraints...
+ */
+
+ for (constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL);
+ constattr;
+ constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL))
+ {
+ if (!constattr->value)
+ {
+ DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!");
+ continue;
+ }
+
+ for (i = 0, vptr = strchr(constattr->value, '*');
+ vptr;
+ i ++, vptr = strchr(vptr + 1, '*'));
+
+ if (i == 0)
+ {
+ DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!");
+ continue;
+ }
+
+ if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
+ {
+ DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
+ "cupsUIConstraints!");
+ return;
+ }
+
+ if ((constptr = calloc(i, sizeof(_ppd_cups_uiconst_t))) == NULL)
+ {
+ free(consts);
+ DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
+ "cupsUIConstraints!");
+ return;
+ }
+
+ consts->num_constraints = i;
+ consts->constraints = constptr;
+
+ strlcpy(consts->resolver, constattr->spec, sizeof(consts->resolver));
+
+ for (i = 0, vptr = strchr(constattr->value, '*');
+ vptr;
+ i ++, vptr = strchr(vptr, '*'), constptr ++)
+ {
+ /*
+ * Extract "*Option Choice" or just "*Option"...
+ */
+
+ for (vptr ++, ptr = option; *vptr && !_cups_isspace(*vptr); vptr ++)
+ if (ptr < (option + sizeof(option) - 1))
+ *ptr++ = *vptr;
+
+ *ptr = '\0';
+
+ while (_cups_isspace(*vptr))
+ vptr ++;
+
+ if (*vptr == '*')
+ choice[0] = '\0';
+ else
+ {
+ for (ptr = choice; *vptr && !_cups_isspace(*vptr); vptr ++)
+ if (ptr < (choice + sizeof(choice) - 1))
+ *ptr++ = *vptr;
+
+ *ptr = '\0';
+ }
+
+ if (!_cups_strncasecmp(option, "Custom", 6) && !_cups_strcasecmp(choice, "True"))
+ {
+ _cups_strcpy(option, option + 6);
+ strcpy(choice, "Custom");
+ }
+
+ constptr->option = ppdFindOption(ppd, option);
+ constptr->choice = ppdFindChoice(constptr->option, choice);
+ constptr->installable = ppd_is_installable(installable, option);
+ consts->installable |= constptr->installable;
+
+ if (!constptr->option || (!constptr->choice && choice[0]))
+ {
+ DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
+ option, choice));
+ break;
+ }
+ }
+
+ if (!vptr)
+ cupsArrayAdd(ppd->cups_uiconstraints, consts);
+ else
+ {
+ free(consts->constraints);
+ free(consts);
+ }
+ }
+}
+
+
+/*
+ * 'ppd_test_constraints()' - See if any constraints are active.
+ */
+
+static cups_array_t * /* O - Array of active constraints */
+ppd_test_constraints(
+ ppd_file_t *ppd, /* I - PPD file */
+ const char *option, /* I - Current option */
+ const char *choice, /* I - Current choice */
+ int num_options, /* I - Number of additional options */
+ cups_option_t *options, /* I - Additional options */
+ int which) /* I - Which constraints to test */
+{
+ int i; /* Looping var */
+ _ppd_cups_uiconsts_t *consts; /* Current constraints */
+ _ppd_cups_uiconst_t *constptr; /* Current constraint */
+ ppd_choice_t key, /* Search key */
+ *marked; /* Marked choice */
+ cups_array_t *active = NULL; /* Active constraints */
+ const char *value, /* Current value */
+ *firstvalue; /* AP_FIRSTPAGE_Keyword value */
+ char firstpage[255]; /* AP_FIRSTPAGE_Keyword string */
+
+
+ DEBUG_printf(("7ppd_test_constraints(ppd=%p, option=\"%s\", choice=\"%s\", "
+ "num_options=%d, options=%p, which=%d)", ppd, option, choice,
+ num_options, options, which));
+
+ if (!ppd->cups_uiconstraints)
+ ppd_load_constraints(ppd);
+
+ DEBUG_printf(("9ppd_test_constraints: %d constraints!",
+ cupsArrayCount(ppd->cups_uiconstraints)));
+
+ cupsArraySave(ppd->marked);
+
+ for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
+ consts;
+ consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
+ {
+ DEBUG_printf(("9ppd_test_constraints: installable=%d, resolver=\"%s\", "
+ "num_constraints=%d option1=\"%s\", choice1=\"%s\", "
+ "option2=\"%s\", choice2=\"%s\", ...",
+ consts->installable, consts->resolver, consts->num_constraints,
+ consts->constraints[0].option->keyword,
+ consts->constraints[0].choice ?
+ consts->constraints[0].choice->choice : "",
+ consts->constraints[1].option->keyword,
+ consts->constraints[1].choice ?
+ consts->constraints[1].choice->choice : ""));
+
+ if (consts->installable && which < _PPD_INSTALLABLE_CONSTRAINTS)
+ continue; /* Skip installable option constraint */
+
+ if (!consts->installable && which == _PPD_INSTALLABLE_CONSTRAINTS)
+ continue; /* Skip non-installable option constraint */
+
+ if (which == _PPD_OPTION_CONSTRAINTS && option)
+ {
+ /*
+ * Skip constraints that do not involve the current option...
+ */
+
+ for (i = consts->num_constraints, constptr = consts->constraints;
+ i > 0;
+ i --, constptr ++)
+ {
+ if (!_cups_strcasecmp(constptr->option->keyword, option))
+ break;
+
+ if (!_cups_strncasecmp(option, "AP_FIRSTPAGE_", 13) &&
+ !_cups_strcasecmp(constptr->option->keyword, option + 13))
+ break;
+ }
+
+ if (!i)
+ continue;
+ }
+
+ DEBUG_puts("9ppd_test_constraints: Testing...");
+
+ for (i = consts->num_constraints, constptr = consts->constraints;
+ i > 0;
+ i --, constptr ++)
+ {
+ DEBUG_printf(("9ppd_test_constraints: %s=%s?", constptr->option->keyword,
+ constptr->choice ? constptr->choice->choice : ""));
+
+ if (constptr->choice &&
+ (!_cups_strcasecmp(constptr->option->keyword, "PageSize") ||
+ !_cups_strcasecmp(constptr->option->keyword, "PageRegion")))
+ {
+ /*
+ * PageSize and PageRegion are used depending on the selected input slot
+ * and manual feed mode. Validate against the selected page size instead
+ * of an individual option...
+ */
+
+ if (option && choice &&
+ (!_cups_strcasecmp(option, "PageSize") ||
+ !_cups_strcasecmp(option, "PageRegion")))
+ {
+ value = choice;
+ }
+ else if ((value = cupsGetOption("PageSize", num_options,
+ options)) == NULL)
+ if ((value = cupsGetOption("PageRegion", num_options,
+ options)) == NULL)
+ if ((value = cupsGetOption("media", num_options, options)) == NULL)
+ {
+ ppd_size_t *size = ppdPageSize(ppd, NULL);
+
+ if (size)
+ value = size->name;
+ }
+
+ if (value && !_cups_strncasecmp(value, "Custom.", 7))
+ value = "Custom";
+
+ if (option && choice &&
+ (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") ||
+ !_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion")))
+ {
+ firstvalue = choice;
+ }
+ else if ((firstvalue = cupsGetOption("AP_FIRSTPAGE_PageSize",
+ num_options, options)) == NULL)
+ firstvalue = cupsGetOption("AP_FIRSTPAGE_PageRegion", num_options,
+ options);
+
+ if (firstvalue && !_cups_strncasecmp(firstvalue, "Custom.", 7))
+ firstvalue = "Custom";
+
+ if ((!value || _cups_strcasecmp(value, constptr->choice->choice)) &&
+ (!firstvalue || _cups_strcasecmp(firstvalue, constptr->choice->choice)))
+ {
+ DEBUG_puts("9ppd_test_constraints: NO");
+ break;
+ }
+ }
+ else if (constptr->choice)
+ {
+ /*
+ * Compare against the constrained choice...
+ */
+
+ if (option && choice && !_cups_strcasecmp(option, constptr->option->keyword))
+ {
+ if (!_cups_strncasecmp(choice, "Custom.", 7))
+ value = "Custom";
+ else
+ value = choice;
+ }
+ else if ((value = cupsGetOption(constptr->option->keyword, num_options,
+ options)) != NULL)
+ {
+ if (!_cups_strncasecmp(value, "Custom.", 7))
+ value = "Custom";
+ }
+ else if (constptr->choice->marked)
+ value = constptr->choice->choice;
+ else
+ value = NULL;
+
+ /*
+ * Now check AP_FIRSTPAGE_option...
+ */
+
+ snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s",
+ constptr->option->keyword);
+
+ if (option && choice && !_cups_strcasecmp(option, firstpage))
+ {
+ if (!_cups_strncasecmp(choice, "Custom.", 7))
+ firstvalue = "Custom";
+ else
+ firstvalue = choice;
+ }
+ else if ((firstvalue = cupsGetOption(firstpage, num_options,
+ options)) != NULL)
+ {
+ if (!_cups_strncasecmp(firstvalue, "Custom.", 7))
+ firstvalue = "Custom";
+ }
+ else
+ firstvalue = NULL;
+
+ DEBUG_printf(("9ppd_test_constraints: value=%s, firstvalue=%s", value,
+ firstvalue));
+
+ if ((!value || _cups_strcasecmp(value, constptr->choice->choice)) &&
+ (!firstvalue || _cups_strcasecmp(firstvalue, constptr->choice->choice)))
+ {
+ DEBUG_puts("9ppd_test_constraints: NO");
+ break;
+ }
+ }
+ else if (option && choice &&
+ !_cups_strcasecmp(option, constptr->option->keyword))
+ {
+ if (!_cups_strcasecmp(choice, "None") || !_cups_strcasecmp(choice, "Off") ||
+ !_cups_strcasecmp(choice, "False"))
+ {
+ DEBUG_puts("9ppd_test_constraints: NO");
+ break;
+ }
+ }
+ else if ((value = cupsGetOption(constptr->option->keyword, num_options,
+ options)) != NULL)
+ {
+ if (!_cups_strcasecmp(value, "None") || !_cups_strcasecmp(value, "Off") ||
+ !_cups_strcasecmp(value, "False"))
+ {
+ DEBUG_puts("9ppd_test_constraints: NO");
+ break;
+ }
+ }
+ else
+ {
+ key.option = constptr->option;
+
+ if ((marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key))
+ == NULL ||
+ (!_cups_strcasecmp(marked->choice, "None") ||
+ !_cups_strcasecmp(marked->choice, "Off") ||
+ !_cups_strcasecmp(marked->choice, "False")))
+ {
+ DEBUG_puts("9ppd_test_constraints: NO");
+ break;
+ }
+ }
+ }
+
+ if (i <= 0)
+ {
+ if (!active)
+ active = cupsArrayNew(NULL, NULL);
+
+ cupsArrayAdd(active, consts);
+ DEBUG_puts("9ppd_test_constraints: Added...");
+ }
+ }
+
+ cupsArrayRestore(ppd->marked);
+
+ DEBUG_printf(("8ppd_test_constraints: Found %d active constraints!",
+ cupsArrayCount(active)));
+
+ return (active);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/cups-private.h b/cups/cups-private.h
new file mode 100644
index 000000000..99b478320
--- /dev/null
+++ b/cups/cups-private.h
@@ -0,0 +1,213 @@
+/*
+ * "$Id$"
+ *
+ * Private definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_CUPS_PRIVATE_H_
+# define _CUPS_CUPS_PRIVATE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include <cups/cups.h>
+# include "string-private.h"
+# include "debug-private.h"
+# include "ppd-private.h"
+# include "http-private.h"
+# include "ipp-private.h"
+# include "language-private.h"
+# include "pwg-private.h"
+# include "thread-private.h"
+# ifdef __APPLE__
+# include <sys/cdefs.h>
+# include <CoreFoundation/CoreFoundation.h>
+# endif /* __APPLE__ */
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Types...
+ */
+
+typedef struct _cups_globals_s /**** CUPS global state data ****/
+{
+ /* Multiple places... */
+ const char *cups_datadir, /* CUPS_DATADIR environment var */
+ *cups_serverbin,/* CUPS_SERVERBIN environment var */
+ *cups_serverroot,
+ /* CUPS_SERVERROOT environment var */
+ *cups_statedir, /* CUPS_STATEDIR environment var */
+ *localedir; /* LOCALDIR environment var */
+
+ /* adminutil.c */
+ time_t cupsd_update; /* Last time we got or set cupsd.conf */
+ char cupsd_hostname[HTTP_MAX_HOST];
+ /* Hostname for connection */
+ int cupsd_num_settings;
+ /* Number of server settings */
+ cups_option_t *cupsd_settings;/* Server settings */
+
+ /* auth.c */
+# ifdef HAVE_GSSAPI
+ char gss_service_name[32];
+ /* Kerberos service name */
+# endif /* HAVE_GSSAPI */
+
+ /* backend.c */
+ char resolved_uri[1024];
+ /* Buffer for cupsBackendDeviceURI */
+
+ /* file.c */
+ cups_file_t *stdio_files[3];/* stdin, stdout, stderr */
+
+ /* http.c */
+ char http_date[256]; /* Date+time buffer */
+
+ /* http-addr.c */
+ unsigned ip_addr; /* Packed IPv4 address */
+ char *ip_ptrs[2]; /* Pointer to packed address */
+ struct hostent hostent; /* Host entry for IP address */
+# ifdef HAVE_GETADDRINFO
+ char hostname[1024]; /* Hostname */
+# endif /* HAVE_GETADDRINFO */
+ int need_res_init; /* Need to reinitialize resolver? */
+
+ /* ipp.c */
+ ipp_uchar_t ipp_date[11]; /* RFC-1903 date/time data */
+ _ipp_buffer_t *ipp_buffers; /* Buffer list */
+
+ /* ipp-support.c */
+ int ipp_port; /* IPP port number */
+ char ipp_unknown[255];
+ /* Unknown error statuses */
+
+ /* language.c */
+ cups_lang_t *lang_default; /* Default language */
+# ifdef __APPLE__
+ char language[32]; /* Cached language */
+# endif /* __APPLE__ */
+
+ /* ppd.c */
+ ppd_status_t ppd_status; /* Status of last ppdOpen*() */
+ int ppd_line; /* Current line number */
+ ppd_conform_t ppd_conform; /* Level of conformance required */
+
+ /* pwg-media.c */
+ cups_array_t *leg_size_lut, /* Lookup table for legacy names */
+ *ppd_size_lut, /* Lookup table for PPD names */
+ *pwg_size_lut; /* Lookup table for PWG names */
+ _pwg_media_t pwg_media; /* PWG media data for custom size */
+ char pwg_name[65]; /* PWG media name for custom size */
+
+ /* request.c */
+ http_t *http; /* Current server connection */
+ ipp_status_t last_error; /* Last IPP error */
+ char *last_status_message;
+ /* Last IPP status-message */
+
+ /* snmp.c */
+ char snmp_community[255];
+ /* Default SNMP community name */
+ int snmp_debug; /* Log SNMP IO to stderr? */
+
+ /* tempfile.c */
+ char tempfile[1024]; /* cupsTempFd/File buffer */
+
+ /* usersys.c */
+ http_encryption_t encryption; /* Encryption setting */
+ char user[65], /* User name */
+ server[256], /* Server address */
+ servername[256];/* Server hostname */
+ cups_password_cb2_t password_cb; /* Password callback */
+ void *password_data; /* Password user data */
+ http_tls_credentials_t tls_credentials;
+ /* Default client credentials */
+ cups_client_cert_cb_t client_cert_cb; /* Client certificate callback */
+ void *client_cert_data;
+ /* Client certificate user data */
+ cups_server_cert_cb_t server_cert_cb; /* Server certificate callback */
+ void *server_cert_data;
+ /* Server certificate user data */
+ int any_root, /* Allow any root */
+ expired_certs, /* Allow expired certs */
+ expired_root; /* Allow expired root */
+
+ /* util.c */
+ char def_printer[256];
+ /* Default printer */
+ char ppd_filename[HTTP_MAX_URI];
+ /* PPD filename */
+} _cups_globals_t;
+
+
+/*
+ * Prototypes...
+ */
+
+# ifdef __APPLE__
+extern CFStringRef _cupsAppleCopyDefaultPaperID(void);
+extern CFStringRef _cupsAppleCopyDefaultPrinter(void);
+extern int _cupsAppleGetUseLastPrinter(void);
+extern void _cupsAppleSetDefaultPaperID(CFStringRef name);
+extern void _cupsAppleSetDefaultPrinter(CFStringRef name);
+extern void _cupsAppleSetUseLastPrinter(int uselast);
+# endif /* __APPLE__ */
+
+extern http_t *_cupsConnect(void);
+extern int _cupsGet1284Values(const char *device_id,
+ cups_option_t **values);
+extern int _cupsGetDests(http_t *http, ipp_op_t op,
+ const char *name, cups_dest_t **dests);
+extern const char *_cupsGetPassword(const char *prompt);
+extern void _cupsGlobalLock(void);
+extern _cups_globals_t *_cupsGlobals(void);
+extern void _cupsGlobalUnlock(void);
+# ifdef HAVE_GSSAPI
+extern const char *_cupsGSSServiceName(void);
+# endif /* HAVE_GSSAPI */
+extern int _cupsNextDelay(int current, int *previous);
+extern void _cupsSetDefaults(void);
+extern void _cupsSetError(ipp_status_t status, const char *message,
+ int localize);
+extern void _cupsSetHTTPError(http_status_t status);
+# ifdef HAVE_GSSAPI
+extern int _cupsSetNegotiateAuthString(http_t *http,
+ const char *method,
+ const char *resource);
+# endif /* HAVE_GSSAPI */
+extern char *_cupsUserDefault(char *name, size_t namesize);
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_CUPS_PRIVATE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/cups.h b/cups/cups.h
new file mode 100644
index 000000000..37619aa77
--- /dev/null
+++ b/cups/cups.h
@@ -0,0 +1,345 @@
+/*
+ * "$Id$"
+ *
+ * API definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "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 <sys/types.h>
+# if defined(WIN32) && !defined(__CUPS_SSIZE_T_DEFINED)
+# define __CUPS_SSIZE_T_DEFINED
+# include <stddef.h>
+/* Windows does not support the ssize_t type, so map it to off_t... */
+typedef off_t ssize_t; /* @private@ */
+# endif /* WIN32 && !__CUPS_SSIZE_T_DEFINED */
+
+# include "file.h"
+# include "ipp.h"
+# include "language.h"
+
+
+/*
+ * With GCC 3.0 and higher, we can mark old APIs "deprecated" so you get
+ * a warning 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.0499
+# define CUPS_VERSION_MAJOR 1
+# define CUPS_VERSION_MINOR 5
+# define CUPS_VERSION_PATCH -1
+
+# define CUPS_BC_FD 3 /* Back-channel file descriptor for select/poll */
+# define CUPS_DATE_ANY (time_t)-1
+# define CUPS_EXCLUDE_NONE (const char *)0
+# define CUPS_FORMAT_AUTO "application/octet-stream"
+# define CUPS_FORMAT_COMMAND "application/vnd.cups-command"
+# define CUPS_FORMAT_PDF "application/pdf"
+# define CUPS_FORMAT_POSTSCRIPT "application/postscript"
+# define CUPS_FORMAT_RAW "application/vnd.cups-raw"
+# define CUPS_FORMAT_TEXT "text/plain"
+# define CUPS_HTTP_DEFAULT (http_t *)0
+# define CUPS_INCLUDE_ALL (const char *)0
+# define CUPS_JOBID_ALL -1
+# define CUPS_JOBID_CURRENT 0
+# define CUPS_LENGTH_VARIABLE (ssize_t)0
+# define CUPS_TIMEOUT_DEFAULT 0
+# define CUPS_WHICHJOBS_ALL -1
+# define CUPS_WHICHJOBS_ACTIVE 0
+# define CUPS_WHICHJOBS_COMPLETED 1
+
+
+/*
+ * Types and structures...
+ */
+
+typedef unsigned cups_ptype_t; /**** Printer type/capability bits ****/
+enum cups_ptype_e /**** Printer type/capability bit constants ****/
+{ /* 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/Mac OS X 10.5@ */
+ CUPS_PRINTER_NOT_SHARED = 0x200000, /* Printer is not shared @since CUPS 1.2/Mac OS X 10.5@ */
+ CUPS_PRINTER_AUTHENTICATED = 0x400000,/* Printer requires authentication @since CUPS 1.2/Mac OS X 10.5@ */
+ CUPS_PRINTER_COMMANDS = 0x800000, /* Printer supports maintenance commands @since CUPS 1.2/Mac OS X 10.5@ */
+ CUPS_PRINTER_DISCOVERED = 0x1000000, /* Printer was automatically discovered and added @since CUPS 1.3/Mac OS X 10.5@ */
+ CUPS_PRINTER_SCANNER = 0x2000000, /* Scanner-only device @since CUPS 1.4/Mac OS X 10.6@ */
+ CUPS_PRINTER_MFP = 0x4000000, /* Printer with scanning capabilities @since CUPS 1.4/Mac OS X 10.6@ */
+ CUPS_PRINTER_OPTIONS = 0x6fffc /* ~(CLASS | REMOTE | IMPLICIT | DEFAULT | FAX | REJECTING | DELETE | NOT_SHARED | AUTHENTICATED | COMMANDS | DISCOVERED) @private@ */
+};
+
+typedef const char *(*cups_password_cb_t)(const char *prompt);
+ /**** Password callback ****/
+
+typedef const char *(*cups_password_cb2_t)(const char *prompt, http_t *http,
+ const char *method,
+ const char *resource,
+ void *user_data);
+ /**** New password callback @since CUPS 1.4/Mac OS X 10.6@ ****/
+
+typedef void (*cups_device_cb_t)(const char *device_class,
+ const char *device_id, const char *device_info,
+ const char *device_make_and_model,
+ const char *device_uri,
+ const char *device_location, void *user_data);
+ /**** Device callback @since CUPS 1.4/Mac OS X 10.6@ ****/
+
+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 */
+ char *title; /* Title/job name */
+ char *user; /* User the submitted the job */
+ char *format; /* Document format */
+ ipp_jstate_t state; /* Job state */
+ int size; /* Size in kilobytes */
+ int priority; /* Priority (1-100) */
+ time_t completed_time; /* Time the job was completed */
+ time_t creation_time; /* Time the job was created */
+ time_t processing_time; /* Time the job was processed */
+} cups_job_t;
+
+typedef int (*cups_client_cert_cb_t)(http_t *http, void *tls,
+ cups_array_t *distinguished_names,
+ void *user_data);
+ /**** Client credentials callback @since CUPS 1.5/Mac OS X 10.7@ ****/
+
+typedef int (*cups_server_cert_cb_t)(http_t *http, void *tls,
+ cups_array_t *certs, void *user_data);
+ /**** Server credentials callback @since CUPS 1.5/Mac OS X 10.7@ ****/
+
+
+/*
+ * Functions...
+ */
+
+extern int cupsCancelJob(const char *name, int job_id);
+extern ipp_t *cupsDoFileRequest(http_t *http, ipp_t *request,
+ const char *resource,
+ const char *filename);
+extern ipp_t *cupsDoRequest(http_t *http, ipp_t *request,
+ const char *resource);
+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 *name,
+ int myjobs, int whichjobs);
+extern const char *cupsGetPPD(const char *name);
+extern int cupsGetPrinters(char ***printers) _CUPS_DEPRECATED;
+extern ipp_status_t cupsLastError(void);
+extern int cupsPrintFile(const char *name, const char *filename,
+ const char *title, int num_options,
+ cups_option_t *options);
+extern int cupsPrintFiles(const char *name, 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 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) _CUPS_API_1_1_20;
+extern http_status_t cupsGetFile(http_t *http, const char *resource,
+ const char *filename) _CUPS_API_1_1_20;
+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) _CUPS_API_1_1_20;
+extern http_status_t cupsPutFd(http_t *http, const char *resource, int fd) _CUPS_API_1_1_20;
+
+/**** New in CUPS 1.1.21 ****/
+extern const char *cupsGetDefault2(http_t *http) _CUPS_API_1_1_21;
+extern int cupsGetDests2(http_t *http, cups_dest_t **dests) _CUPS_API_1_1_21;
+extern int cupsGetJobs2(http_t *http, cups_job_t **jobs,
+ const char *name, int myjobs,
+ int whichjobs) _CUPS_API_1_1_21;
+extern const char *cupsGetPPD2(http_t *http, const char *name) _CUPS_API_1_1_21;
+extern int cupsPrintFile2(http_t *http, const char *name,
+ const char *filename,
+ const char *title, int num_options,
+ cups_option_t *options) _CUPS_API_1_1_21;
+extern int cupsPrintFiles2(http_t *http, const char *name,
+ int num_files, const char **files,
+ const char *title, int num_options,
+ cups_option_t *options) _CUPS_API_1_1_21;
+extern int cupsSetDests2(http_t *http, int num_dests,
+ cups_dest_t *dests) _CUPS_API_1_1_21;
+
+/**** New in CUPS 1.2/Mac OS X 10.5 ****/
+extern ssize_t cupsBackChannelRead(char *buffer, size_t bytes,
+ double timeout) _CUPS_API_1_2;
+extern ssize_t cupsBackChannelWrite(const char *buffer, size_t bytes,
+ double timeout) _CUPS_API_1_2;
+extern void cupsEncodeOptions2(ipp_t *ipp, int num_options,
+ cups_option_t *options,
+ ipp_tag_t group_tag) _CUPS_API_1_2;
+extern const char *cupsLastErrorString(void) _CUPS_API_1_2;
+extern char *cupsNotifySubject(cups_lang_t *lang, ipp_t *event) _CUPS_API_1_2;
+extern char *cupsNotifyText(cups_lang_t *lang, ipp_t *event) _CUPS_API_1_2;
+extern int cupsRemoveOption(const char *name, int num_options,
+ cups_option_t **options) _CUPS_API_1_2;
+extern cups_file_t *cupsTempFile2(char *filename, int len) _CUPS_API_1_2;
+
+/**** New in CUPS 1.3/Mac OS X 10.5 ****/
+extern ipp_t *cupsDoIORequest(http_t *http, ipp_t *request,
+ const char *resource, int infile,
+ int outfile) _CUPS_API_1_3;
+extern char *cupsGetServerPPD(http_t *http, const char *name) _CUPS_API_1_3;
+extern int cupsRemoveDest(const char *name,
+ const char *instance,
+ int num_dests, cups_dest_t **dests) _CUPS_API_1_3;
+extern void cupsSetDefaultDest(const char *name,
+ const char *instance,
+ int num_dests,
+ cups_dest_t *dests) _CUPS_API_1_3;
+
+/**** New in CUPS 1.4/Mac OS X 10.6 ****/
+extern ipp_status_t cupsCancelJob2(http_t *http, const char *name,
+ int job_id, int purge) _CUPS_API_1_4;
+extern int cupsCreateJob(http_t *http, const char *name,
+ const char *title, int num_options,
+ cups_option_t *options) _CUPS_API_1_4;
+extern ipp_status_t cupsFinishDocument(http_t *http,
+ const char *name) _CUPS_API_1_4;
+extern ipp_status_t cupsGetDevices(http_t *http, int timeout,
+ const char *include_schemes,
+ const char *exclude_schemes,
+ cups_device_cb_t callback,
+ void *user_data) _CUPS_API_1_4;
+extern cups_dest_t *cupsGetNamedDest(http_t *http, const char *name,
+ const char *instance) _CUPS_API_1_4;
+extern const char *cupsGetPassword2(const char *prompt, http_t *http,
+ const char *method,
+ const char *resource) _CUPS_API_1_4;
+extern http_status_t cupsGetPPD3(http_t *http, const char *name,
+ time_t *modtime, char *buffer,
+ size_t bufsize) _CUPS_API_1_4;
+extern ipp_t *cupsGetResponse(http_t *http,
+ const char *resource) _CUPS_API_1_4;
+extern ssize_t cupsReadResponseData(http_t *http, char *buffer,
+ size_t length) _CUPS_API_1_4;
+extern http_status_t cupsSendRequest(http_t *http, ipp_t *request,
+ const char *resource,
+ size_t length) _CUPS_API_1_4;
+extern void cupsSetPasswordCB2(cups_password_cb2_t cb,
+ void *user_data) _CUPS_API_1_4;
+extern http_status_t cupsStartDocument(http_t *http, const char *name,
+ int job_id, const char *docname,
+ const char *format,
+ int last_document) _CUPS_API_1_4;
+extern http_status_t cupsWriteRequestData(http_t *http, const char *buffer,
+ size_t length) _CUPS_API_1_4;
+
+/**** New in CUPS 1.5 ****/
+extern void cupsSetClientCertCB(cups_client_cert_cb_t cb,
+ void *user_data) _CUPS_API_1_5;
+extern int cupsSetCredentials(cups_array_t *certs) _CUPS_API_1_5;
+extern void cupsSetServerCertCB(cups_server_cert_cb_t cb,
+ void *user_data) _CUPS_API_1_5;
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_CUPS_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/custom.c b/cups/custom.c
new file mode 100644
index 000000000..94ff9bb46
--- /dev/null
+++ b/cups/custom.c
@@ -0,0 +1,122 @@
+/*
+ * "$Id$"
+ *
+ * PPD custom option routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * PostScript is a trademark of Adobe Systems, Inc.
+ *
+ * This code and any derivative of it may be used and distributed
+ * freely under the terms of the GNU General Public License when
+ * used with GNU Ghostscript or its derivatives. Use of the code
+ * (or any derivative of it) with software other than GNU
+ * GhostScript (or its derivatives) is governed by the CUPS license
+ * agreement.
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * ppdFindCustomOption() - Find a custom option.
+ * ppdFindCustomParam() - Find a parameter for a custom option.
+ * ppdFirstCustomParam() - Return the first parameter for a custom option.
+ * ppdNextCustomParam() - Return the next parameter for a custom option.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "cups-private.h"
+
+
+/*
+ * 'ppdFindCustomOption()' - Find a custom option.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ppd_coption_t * /* O - Custom option or NULL */
+ppdFindCustomOption(ppd_file_t *ppd, /* I - PPD file */
+ const char *keyword)/* I - Custom option name */
+{
+ ppd_coption_t key; /* Custom option search key */
+
+
+ if (!ppd)
+ return (NULL);
+
+ strlcpy(key.keyword, keyword, sizeof(key.keyword));
+ return ((ppd_coption_t *)cupsArrayFind(ppd->coptions, &key));
+}
+
+
+/*
+ * 'ppdFindCustomParam()' - Find a parameter for a custom option.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ppd_cparam_t * /* O - Custom parameter or NULL */
+ppdFindCustomParam(ppd_coption_t *opt, /* I - Custom option */
+ const char *name) /* I - Parameter name */
+{
+ ppd_cparam_t *param; /* Current custom parameter */
+
+
+ if (!opt)
+ return (NULL);
+
+ for (param = (ppd_cparam_t *)cupsArrayFirst(opt->params);
+ param;
+ param = (ppd_cparam_t *)cupsArrayNext(opt->params))
+ if (!_cups_strcasecmp(param->name, name))
+ break;
+
+ return (param);
+}
+
+
+/*
+ * 'ppdFirstCustomParam()' - Return the first parameter for a custom option.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ppd_cparam_t * /* O - Custom parameter or NULL */
+ppdFirstCustomParam(ppd_coption_t *opt) /* I - Custom option */
+{
+ if (!opt)
+ return (NULL);
+
+ return ((ppd_cparam_t *)cupsArrayFirst(opt->params));
+}
+
+
+/*
+ * 'ppdNextCustomParam()' - Return the next parameter for a custom option.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ppd_cparam_t * /* O - Custom parameter or NULL */
+ppdNextCustomParam(ppd_coption_t *opt) /* I - Custom option */
+{
+ if (!opt)
+ return (NULL);
+
+ return ((ppd_cparam_t *)cupsArrayNext(opt->params));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/debug-private.h b/cups/debug-private.h
new file mode 100644
index 000000000..c739fa68a
--- /dev/null
+++ b/cups/debug-private.h
@@ -0,0 +1,108 @@
+/*
+ * "$Id$"
+ *
+ * Private debugging macros for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_DEBUG_PRIVATE_H_
+# define _CUPS_DEBUG_PRIVATE_H_
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * 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...
+ *
+ * Newlines are not required on the end of messages, as both add one when
+ * writing the output.
+ *
+ * If the first character is a digit, then it represents the "log level" of the
+ * message from 0 to 9. The default level is 1. The following defines the
+ * current levels we use:
+ *
+ * 0 = public APIs, other than value accessor functions
+ * 1 = return values for public APIs
+ * 2 = public value accessor APIs, progress for public APIs
+ * 3 = return values for value accessor APIs
+ * 4 = private APIs, progress for value accessor APIs
+ * 5 = return values for private APIs
+ * 6 = progress for private APIs
+ * 7 = static functions
+ * 8 = return values for static functions
+ * 9 = progress for static functions
+ *
+ * The DEBUG_set macro allows an application to programmatically enable (or
+ * disable) debug logging. The arguments correspond to the CUPS_DEBUG_LOG,
+ * CUPS_DEBUG_LEVEL, and CUPS_DEBUG_FILTER environment variables.
+ */
+
+# ifdef DEBUG
+# ifdef WIN32
+# ifdef LIBCUPS2_EXPORTS
+# define DLLExport __declspec(dllexport)
+# else
+# define DLLExport
+# endif /* LIBCUPS2_EXPORTS */
+# else
+# define DLLExport
+# endif /* WIN32 */
+# define DEBUG_puts(x) _cups_debug_puts(x)
+# define DEBUG_printf(x) _cups_debug_printf x
+# define DEBUG_set(logfile,level,filter) _cups_debug_set(logfile,level,filter,1)
+# else
+# define DLLExport
+# define DEBUG_puts(x)
+# define DEBUG_printf(x)
+# define DEBUG_set(logfile,level,filter)
+# endif /* DEBUG */
+
+
+/*
+ * Prototypes...
+ */
+
+extern int _cups_debug_fd;
+extern int _cups_debug_level;
+extern void DLLExport _cups_debug_printf(const char *format, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 1, 2)))
+#endif /* __GNUC__ */
+;
+extern void DLLExport _cups_debug_puts(const char *s);
+extern void DLLExport _cups_debug_set(const char *logfile,
+ const char *level, const char *filter,
+ int force);
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_DEBUG_PRIVATE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/debug.c b/cups/debug.c
new file mode 100644
index 000000000..29d6b4821
--- /dev/null
+++ b/cups/debug.c
@@ -0,0 +1,583 @@
+/*
+ * "$Id$"
+ *
+ * Debugging functions for CUPS.
+ *
+ * Copyright 2008-2010 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * debug_vsnprintf() - Format a string into a fixed size buffer.
+ * _cups_debug_printf() - Write a formatted line to the log.
+ * _cups_debug_puts() - Write a single line to the log.
+ * _cups_debug_set() - Enable or disable debug logging.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include "thread-private.h"
+#ifdef WIN32
+# include <sys/timeb.h>
+# include <time.h>
+# include <io.h>
+# define getpid (int)GetCurrentProcessId
+static int /* O - 0 on success, -1 on failure */
+gettimeofday(struct timeval *tv, /* I - Timeval struct */
+ void *tz) /* I - Timezone */
+{
+ struct _timeb timebuffer; /* Time buffer struct */
+ _ftime(&timebuffer);
+ tv->tv_sec = (long)timebuffer.time;
+ tv->tv_usec = timebuffer.millitm * 1000;
+ return 0;
+}
+#else
+# include <sys/time.h>
+# include <unistd.h>
+#endif /* WIN32 */
+#include <fcntl.h>
+#include <regex.h>
+
+
+/*
+ * Globals...
+ */
+
+int _cups_debug_fd = -1;
+ /* Debug log file descriptor */
+int _cups_debug_level = 1;
+ /* Log level (0 to 9) */
+
+
+#ifdef DEBUG
+/*
+ * Local globals...
+ */
+
+static regex_t *debug_filter = NULL;
+ /* Filter expression for messages */
+static int debug_init = 0; /* Did we initialize debugging? */
+static _cups_mutex_t debug_mutex = _CUPS_MUTEX_INITIALIZER;
+ /* Mutex to control initialization */
+
+
+/*
+ * 'debug_vsnprintf()' - Format a string into a fixed size buffer.
+ */
+
+static int /* O - Number of bytes formatted */
+debug_vsnprintf(char *buffer, /* O - Output buffer */
+ size_t bufsize, /* O - Size of output buffer */
+ const char *format, /* I - printf-style format string */
+ va_list ap) /* I - Pointer to additional arguments */
+{
+ char *bufptr, /* Pointer to position in buffer */
+ *bufend, /* Pointer to end of buffer */
+ size, /* Size character (h, l, L) */
+ type; /* Format type character */
+ int width, /* Width of field */
+ prec; /* Number of characters of precision */
+ char tformat[100], /* Temporary format string for sprintf() */
+ *tptr, /* Pointer into temporary format */
+ temp[1024]; /* Buffer for formatted numbers */
+ char *s; /* Pointer to string */
+ int bytes; /* Total number of bytes needed */
+
+
+ if (!buffer || bufsize < 2 || !format)
+ return (-1);
+
+ /*
+ * Loop through the format string, formatting as needed...
+ */
+
+ bufptr = buffer;
+ bufend = buffer + bufsize - 1;
+ bytes = 0;
+
+ while (*format)
+ {
+ if (*format == '%')
+ {
+ tptr = tformat;
+ *tptr++ = *format++;
+
+ if (*format == '%')
+ {
+ if (bufptr < bufend)
+ *bufptr++ = *format;
+ bytes ++;
+ format ++;
+ continue;
+ }
+ else if (strchr(" -+#\'", *format))
+ *tptr++ = *format++;
+
+ if (*format == '*')
+ {
+ /*
+ * Get width from argument...
+ */
+
+ format ++;
+ width = va_arg(ap, int);
+
+ snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
+ tptr += strlen(tptr);
+ }
+ else
+ {
+ width = 0;
+
+ while (isdigit(*format & 255))
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ width = width * 10 + *format++ - '0';
+ }
+ }
+
+ if (*format == '.')
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ format ++;
+
+ if (*format == '*')
+ {
+ /*
+ * Get precision from argument...
+ */
+
+ format ++;
+ prec = va_arg(ap, int);
+
+ snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
+ tptr += strlen(tptr);
+ }
+ else
+ {
+ prec = 0;
+
+ while (isdigit(*format & 255))
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ prec = prec * 10 + *format++ - '0';
+ }
+ }
+ }
+
+ if (*format == 'l' && format[1] == 'l')
+ {
+ size = 'L';
+
+ if (tptr < (tformat + sizeof(tformat) - 2))
+ {
+ *tptr++ = 'l';
+ *tptr++ = 'l';
+ }
+
+ format += 2;
+ }
+ else if (*format == 'h' || *format == 'l' || *format == 'L')
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ size = *format++;
+ }
+ else
+ size = 0;
+
+ if (!*format)
+ break;
+
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ type = *format++;
+ *tptr = '\0';
+
+ switch (type)
+ {
+ case 'E' : /* Floating point formats */
+ case 'G' :
+ case 'e' :
+ case 'f' :
+ case 'g' :
+ if ((width + 2) > sizeof(temp))
+ break;
+
+ sprintf(temp, tformat, va_arg(ap, double));
+
+ bytes += (int)strlen(temp);
+
+ if (bufptr)
+ {
+ if ((bufptr + strlen(temp)) > bufend)
+ {
+ strncpy(bufptr, temp, (size_t)(bufend - bufptr));
+ bufptr = bufend;
+ }
+ else
+ {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'B' : /* Integer formats */
+ case 'X' :
+ case 'b' :
+ case 'd' :
+ case 'i' :
+ case 'o' :
+ case 'u' :
+ case 'x' :
+ if ((width + 2) > sizeof(temp))
+ break;
+
+# ifdef HAVE_LONG_LONG
+ if (size == 'L')
+ sprintf(temp, tformat, va_arg(ap, long long));
+ else
+# endif /* HAVE_LONG_LONG */
+ if (size == 'l')
+ sprintf(temp, tformat, va_arg(ap, long));
+ else
+ sprintf(temp, tformat, va_arg(ap, int));
+
+ bytes += (int)strlen(temp);
+
+ if (bufptr)
+ {
+ if ((bufptr + strlen(temp)) > bufend)
+ {
+ strncpy(bufptr, temp, (size_t)(bufend - bufptr));
+ bufptr = bufend;
+ }
+ else
+ {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'p' : /* Pointer value */
+ if ((width + 2) > sizeof(temp))
+ break;
+
+ sprintf(temp, tformat, va_arg(ap, void *));
+
+ bytes += (int)strlen(temp);
+
+ if (bufptr)
+ {
+ if ((bufptr + strlen(temp)) > bufend)
+ {
+ strncpy(bufptr, temp, (size_t)(bufend - bufptr));
+ bufptr = bufend;
+ }
+ else
+ {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'c' : /* Character or character array */
+ bytes += width;
+
+ if (bufptr)
+ {
+ if (width <= 1)
+ *bufptr++ = va_arg(ap, int);
+ else
+ {
+ if ((bufptr + width) > bufend)
+ width = (int)(bufend - bufptr);
+
+ memcpy(bufptr, va_arg(ap, char *), (size_t)width);
+ bufptr += width;
+ }
+ }
+ break;
+
+ case 's' : /* String */
+ if ((s = va_arg(ap, char *)) == NULL)
+ s = "(null)";
+
+ /*
+ * Copy the C string, replacing control chars and \ with
+ * C character escapes...
+ */
+
+ for (bufend --; *s && bufptr < bufend; s ++)
+ {
+ if (*s == '\n')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = 'n';
+ }
+ else if (*s == '\r')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = 'r';
+ }
+ else if (*s == '\t')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = 't';
+ }
+ else if (*s == '\\')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = '\\';
+ }
+ else if (*s == '\'')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = '\'';
+ }
+ else if (*s == '\"')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = '\"';
+ }
+ else if ((*s & 255) < ' ')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = '0';
+ *bufptr++ = '0' + *s / 8;
+ *bufptr++ = '0' + (*s & 7);
+ }
+ else
+ *bufptr++ = *s;
+ }
+
+ bufend ++;
+ break;
+
+ case 'n' : /* Output number of chars so far */
+ *(va_arg(ap, int *)) = bytes;
+ break;
+ }
+ }
+ else
+ {
+ bytes ++;
+
+ if (bufptr < bufend)
+ *bufptr++ = *format;
+
+ format ++;
+ }
+ }
+
+ /*
+ * Nul-terminate the string and return the number of characters needed.
+ */
+
+ *bufptr = '\0';
+
+ return (bytes);
+}
+
+
+/*
+ * '_cups_debug_printf()' - Write a formatted line to the log.
+ */
+
+void DLLExport
+_cups_debug_printf(const char *format, /* I - Printf-style format string */
+ ...) /* I - Additional arguments as needed */
+{
+ va_list ap; /* Pointer to arguments */
+ struct timeval curtime; /* Current time */
+ char buffer[2048]; /* Output buffer */
+ size_t bytes; /* Number of bytes in buffer */
+ int level; /* Log level in message */
+
+
+ /*
+ * See if we need to do any logging...
+ */
+
+ if (!debug_init)
+ _cups_debug_set(getenv("CUPS_DEBUG_LOG"), getenv("CUPS_DEBUG_LEVEL"),
+ getenv("CUPS_DEBUG_FILTER"), 0);
+
+ if (_cups_debug_fd < 0)
+ return;
+
+ /*
+ * Filter as needed...
+ */
+
+ if (isdigit(format[0]))
+ level = *format++ - '0';
+ else
+ level = 0;
+
+ if (level > _cups_debug_level)
+ return;
+
+ if (debug_filter)
+ {
+ int result; /* Filter result */
+
+ _cupsMutexLock(&debug_mutex);
+ result = regexec(debug_filter, format, 0, NULL, 0);
+ _cupsMutexUnlock(&debug_mutex);
+
+ if (result)
+ return;
+ }
+
+ /*
+ * Format the message...
+ */
+
+ gettimeofday(&curtime, NULL);
+ snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d.%03d ",
+ (int)((curtime.tv_sec / 3600) % 24),
+ (int)((curtime.tv_sec / 60) % 60),
+ (int)(curtime.tv_sec % 60), (int)(curtime.tv_usec / 1000));
+
+ va_start(ap, format);
+ debug_vsnprintf(buffer + 13, sizeof(buffer) - 14, format, ap);
+ va_end(ap);
+
+ bytes = strlen(buffer);
+ if (buffer[bytes - 1] != '\n')
+ {
+ buffer[bytes] = '\n';
+ bytes ++;
+ buffer[bytes] = '\0';
+ }
+
+ /*
+ * Write it out...
+ */
+
+ write(_cups_debug_fd, buffer, bytes);
+}
+
+
+/*
+ * '_cups_debug_puts()' - Write a single line to the log.
+ */
+
+void DLLExport
+_cups_debug_puts(const char *s) /* I - String to output */
+{
+ char format[4]; /* C%s */
+
+
+ format[0] = *s++;
+ format[1] = '%';
+ format[2] = 's';
+ format[3] = '\0';
+
+ _cups_debug_printf(format, s);
+}
+
+
+/*
+ * '_cups_debug_set()' - Enable or disable debug logging.
+ */
+
+void DLLExport
+_cups_debug_set(const char *logfile, /* I - Log file or NULL */
+ const char *level, /* I - Log level or NULL */
+ const char *filter, /* I - Filter string or NULL */
+ int force) /* I - Force initialization */
+{
+ _cupsMutexLock(&debug_mutex);
+
+ if (!debug_init || force)
+ {
+ /*
+ * Restore debug settings to defaults...
+ */
+
+ if (_cups_debug_fd != -1)
+ {
+ close(_cups_debug_fd);
+ _cups_debug_fd = -1;
+ }
+
+ if (debug_filter)
+ {
+ regfree((regex_t *)debug_filter);
+ debug_filter = NULL;
+ }
+
+ _cups_debug_level = 1;
+
+ /*
+ * Open logs, set log levels, etc.
+ */
+
+ if (!logfile)
+ _cups_debug_fd = -1;
+ else if (!strcmp(logfile, "-"))
+ _cups_debug_fd = 2;
+ else
+ {
+ char buffer[1024]; /* Filename buffer */
+
+ snprintf(buffer, sizeof(buffer), logfile, getpid());
+
+ if (buffer[0] == '+')
+ _cups_debug_fd = open(buffer + 1, O_WRONLY | O_APPEND | O_CREAT, 0644);
+ else
+ _cups_debug_fd = open(buffer, O_WRONLY | O_TRUNC | O_CREAT, 0644);
+ }
+
+ if (level)
+ _cups_debug_level = atoi(level);
+
+ if (filter)
+ {
+ if ((debug_filter = (regex_t *)calloc(1, sizeof(regex_t))) == NULL)
+ fputs("Unable to allocate memory for CUPS_DEBUG_FILTER - results not "
+ "filtered!\n", stderr);
+ else if (regcomp(debug_filter, filter, REG_EXTENDED))
+ {
+ fputs("Bad regular expression in CUPS_DEBUG_FILTER - results not "
+ "filtered!\n", stderr);
+ free(debug_filter);
+ debug_filter = NULL;
+ }
+ }
+
+ debug_init = 1;
+ }
+
+ _cupsMutexUnlock(&debug_mutex);
+}
+#endif /* DEBUG */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/dest.c b/cups/dest.c
new file mode 100644
index 000000000..6ea984a76
--- /dev/null
+++ b/cups/dest.c
@@ -0,0 +1,2169 @@
+/*
+ * "$Id$"
+ *
+ * User-defined destination (and option) support for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "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.
+ * _cupsAppleCopyDefaultPaperID() - Get the default paper ID.
+ * _cupsAppleCopyDefaultPrinter() - Get the default printer at this location.
+ * _cupsAppleGetUseLastPrinter() - Get whether to use the last used printer.
+ * _cupsAppleSetDefaultPaperID() - Set the default paper id.
+ * _cupsAppleSetDefaultPrinter() - Set the default printer for this location.
+ * _cupsAppleSetUseLastPrinter() - Set whether to use the last used printer.
+ * cupsFreeDests() - Free the memory used by the list of
+ * destinations.
+ * cupsGetDest() - Get the named destination from the list.
+ * _cupsGetDests() - Get destinations from a server.
+ * cupsGetDests() - Get the list of destinations from the
+ * default server.
+ * cupsGetDests2() - Get the list of destinations from the
+ * specified server.
+ * cupsGetNamedDest() - Get options for the named destination.
+ * cupsRemoveDest() - Remove a destination from the destination
+ * list.
+ * cupsSetDefaultDest() - Set the default destination.
+ * cupsSetDests() - Save the list of destinations for the
+ * default server.
+ * cupsSetDests2() - Save the list of destinations for the
+ * specified server.
+ * _cupsUserDefault() - Get the user default printer from
+ * environment variables and location
+ * information.
+ * appleCopyLocations() - Copy the location history array.
+ * appleCopyNetwork() - Get the network ID for the current
+ * location.
+ * appleGetPaperSize() - Get the default paper size.
+ * appleGetPrinter() - Get a printer from the history array.
+ * cups_add_dest() - Add a destination to the array.
+ * cups_compare_dests() - Compare two destinations.
+ * cups_find_dest() - Find a destination using a binary search.
+ * cups_get_default() - Get the default destination from an
+ * lpoptions file.
+ * cups_get_dests() - Get destinations from a file.
+ * cups_make_string() - Make a comma-separated string of values
+ * from an IPP attribute.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include <sys/stat.h>
+
+#ifdef HAVE_NOTIFY_H
+# include <notify.h>
+#endif /* HAVE_NOTIFY_H */
+
+#ifdef __APPLE__
+# include <SystemConfiguration/SystemConfiguration.h>
+# define kCUPSPrintingPrefs CFSTR("org.cups.PrintingPrefs")
+# define kDefaultPaperIDKey CFSTR("DefaultPaperID")
+# define kLastUsedPrintersKey CFSTR("LastUsedPrinters")
+# define kLocationNetworkKey CFSTR("Network")
+# define kLocationPrinterIDKey CFSTR("PrinterID")
+# define kUseLastPrinter CFSTR("UseLastPrinter")
+#endif /* __APPLE__ */
+
+
+/*
+ * Local functions...
+ */
+
+#ifdef __APPLE__
+static CFArrayRef appleCopyLocations(void);
+static CFStringRef appleCopyNetwork(void);
+static char *appleGetPaperSize(char *name, int namesize);
+static CFStringRef appleGetPrinter(CFArrayRef locations, CFStringRef network,
+ CFIndex *locindex);
+#endif /* __APPLE__ */
+static cups_dest_t *cups_add_dest(const char *name, const char *instance,
+ int *num_dests, cups_dest_t **dests);
+static int cups_compare_dests(cups_dest_t *a, cups_dest_t *b);
+static int cups_find_dest(const char *name, const char *instance,
+ int num_dests, cups_dest_t *dests, int prev,
+ int *rdiff);
+static char *cups_get_default(const char *filename, char *namebuf,
+ size_t namesize, const char **instance);
+static int cups_get_dests(const char *filename, const char *match_name,
+ const char *match_inst, int user_default_set,
+ int num_dests, cups_dest_t **dests);
+static char *cups_make_string(ipp_attribute_t *attr, char *buffer,
+ size_t bufsize);
+
+
+/*
+ * 'cupsAddDest()' - Add a destination to the list of destinations.
+ *
+ * This function cannot be used to add a new class or printer queue,
+ * it only adds a new container of saved options for the named
+ * destination or instance.
+ *
+ * If the named destination already exists, the destination list is
+ * returned unchanged. Adding a new instance of a destination creates
+ * a copy of that destination's options.
+ *
+ * Use the @link 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 - Destination name */
+ const char *instance, /* I - Instance name or @code 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 */
+ cups_dest_t *parent = NULL; /* Parent destination */
+ cups_option_t *doption, /* Current destination option */
+ *poption; /* Current parent option */
+
+
+ if (!name || !dests)
+ return (0);
+
+ if (!cupsGetDest(name, instance, num_dests, *dests))
+ {
+ if (instance && !cupsGetDest(name, NULL, num_dests, *dests))
+ return (num_dests);
+
+ dest = cups_add_dest(name, instance, &num_dests, dests);
+
+ /*
+ * Find the base dest again now the array has been realloc'd.
+ */
+
+ parent = cupsGetDest(name, NULL, num_dests, *dests);
+
+ if (instance && parent && parent->num_options > 0)
+ {
+ /*
+ * Copy options from parent...
+ */
+
+ dest->options = calloc(sizeof(cups_option_t), parent->num_options);
+
+ if (dest->options)
+ {
+ dest->num_options = parent->num_options;
+
+ for (i = dest->num_options, doption = dest->options,
+ poption = parent->options;
+ i > 0;
+ i --, doption ++, poption ++)
+ {
+ doption->name = _cupsStrRetain(poption->name);
+ doption->value = _cupsStrRetain(poption->value);
+ }
+ }
+ }
+ }
+
+ return (num_dests);
+}
+
+
+#ifdef __APPLE__
+/*
+ * '_cupsAppleCopyDefaultPaperID()' - Get the default paper ID.
+ */
+
+CFStringRef /* O - Default paper ID */
+_cupsAppleCopyDefaultPaperID(void)
+{
+ return (CFPreferencesCopyAppValue(kDefaultPaperIDKey,
+ kCUPSPrintingPrefs));
+}
+
+
+/*
+ * '_cupsAppleCopyDefaultPrinter()' - Get the default printer at this location.
+ */
+
+CFStringRef /* O - Default printer name */
+_cupsAppleCopyDefaultPrinter(void)
+{
+ CFStringRef network; /* Network location */
+ CFArrayRef locations; /* Location array */
+ CFStringRef locprinter; /* Current printer */
+
+
+ /*
+ * Use location-based defaults only if "use last printer" is selected in the
+ * system preferences...
+ */
+
+ if (!_cupsAppleGetUseLastPrinter())
+ {
+ DEBUG_puts("1_cupsAppleCopyDefaultPrinter: Not using last printer as "
+ "default.");
+ return (NULL);
+ }
+
+ /*
+ * Get the current location...
+ */
+
+ if ((network = appleCopyNetwork()) == NULL)
+ {
+ DEBUG_puts("1_cupsAppleCopyDefaultPrinter: Unable to get current "
+ "network.");
+ return (NULL);
+ }
+
+//# ifdef DEBUG
+// CFStringGetCString(network, name, namesize, kCFStringEncodingUTF8);
+// DEBUG_printf(("2_cupsUserDefault: network=\"%s\"", name));
+//# endif /* DEBUG */
+
+ /*
+ * Lookup the network in the preferences...
+ */
+
+ if ((locations = appleCopyLocations()) == NULL)
+ {
+ /*
+ * Missing or bad location array, so no location-based default...
+ */
+
+ DEBUG_puts("1_cupsAppleCopyDefaultPrinter: Missing or bad last used "
+ "printer array.");
+
+ CFRelease(network);
+
+ return (NULL);
+ }
+
+ DEBUG_printf(("1_cupsAppleCopyDefaultPrinter: Got locations, %d entries.",
+ (int)CFArrayGetCount(locations)));
+
+ if ((locprinter = appleGetPrinter(locations, network, NULL)) != NULL)
+ CFRetain(locprinter);
+
+ CFRelease(network);
+ CFRelease(locations);
+
+ return (locprinter);
+}
+
+
+/*
+ * '_cupsAppleGetUseLastPrinter()' - Get whether to use the last used printer.
+ */
+
+int /* O - 1 to use last printer, 0 otherwise */
+_cupsAppleGetUseLastPrinter(void)
+{
+ Boolean uselast, /* Use last printer preference value */
+ uselast_set; /* Valid is set? */
+
+
+ if (getenv("CUPS_DISABLE_APPLE_DEFAULT"))
+ return (0);
+
+ uselast = CFPreferencesGetAppBooleanValue(kUseLastPrinter,
+ kCUPSPrintingPrefs,
+ &uselast_set);
+ if (!uselast_set)
+ return (1);
+ else
+ return (uselast);
+}
+
+
+/*
+ * '_cupsAppleSetDefaultPaperID()' - Set the default paper id.
+ */
+
+void
+_cupsAppleSetDefaultPaperID(
+ CFStringRef name) /* I - New paper ID */
+{
+ CFPreferencesSetAppValue(kDefaultPaperIDKey, name, kCUPSPrintingPrefs);
+ CFPreferencesAppSynchronize(kCUPSPrintingPrefs);
+ notify_post("com.apple.printerPrefsChange");
+}
+
+
+/*
+ * '_cupsAppleSetDefaultPrinter()' - Set the default printer for this location.
+ */
+
+void
+_cupsAppleSetDefaultPrinter(
+ CFStringRef name) /* I - Default printer/class name */
+{
+ CFStringRef network; /* Current network */
+ CFArrayRef locations; /* Old locations array */
+ CFIndex locindex; /* Index in locations array */
+ CFStringRef locprinter; /* Current printer */
+ CFMutableArrayRef newlocations; /* New locations array */
+ CFMutableDictionaryRef newlocation; /* New location */
+
+
+ /*
+ * Get the current location...
+ */
+
+ if ((network = appleCopyNetwork()) == NULL)
+ {
+ DEBUG_puts("1_cupsAppleSetDefaultPrinter: Unable to get current network...");
+ return;
+ }
+
+ /*
+ * Lookup the network in the preferences...
+ */
+
+ if ((locations = appleCopyLocations()) != NULL)
+ locprinter = appleGetPrinter(locations, network, &locindex);
+ else
+ {
+ locprinter = NULL;
+ locindex = -1;
+ }
+
+ if (!locprinter || CFStringCompare(locprinter, name, 0) != kCFCompareEqualTo)
+ {
+ /*
+ * Need to change the locations array...
+ */
+
+ if (locations)
+ {
+ newlocations = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0,
+ locations);
+
+ if (locprinter)
+ CFArrayRemoveValueAtIndex(newlocations, locindex);
+ }
+ else
+ newlocations = CFArrayCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeArrayCallBacks);
+
+ newlocation = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ if (newlocation && newlocations)
+ {
+ /*
+ * Put the new location at the front of the array...
+ */
+
+ CFDictionaryAddValue(newlocation, kLocationNetworkKey, network);
+ CFDictionaryAddValue(newlocation, kLocationPrinterIDKey, name);
+ CFArrayInsertValueAtIndex(newlocations, 0, newlocation);
+
+ /*
+ * Limit the number of locations to 10...
+ */
+
+ while (CFArrayGetCount(newlocations) > 10)
+ CFArrayRemoveValueAtIndex(newlocations, 10);
+
+ /*
+ * Push the changes out...
+ */
+
+ CFPreferencesSetAppValue(kLastUsedPrintersKey, newlocations,
+ kCUPSPrintingPrefs);
+ CFPreferencesAppSynchronize(kCUPSPrintingPrefs);
+ notify_post("com.apple.printerPrefsChange");
+ }
+
+ if (newlocations)
+ CFRelease(newlocations);
+
+ if (newlocation)
+ CFRelease(newlocation);
+ }
+
+ if (locations)
+ CFRelease(locations);
+
+ CFRelease(network);
+}
+
+
+/*
+ * '_cupsAppleSetUseLastPrinter()' - Set whether to use the last used printer.
+ */
+
+void
+_cupsAppleSetUseLastPrinter(
+ int uselast) /* O - 1 to use last printer, 0 otherwise */
+{
+ CFPreferencesSetAppValue(kUseLastPrinter,
+ uselast ? kCFBooleanTrue : kCFBooleanFalse,
+ kCUPSPrintingPrefs);
+ CFPreferencesAppSynchronize(kCUPSPrintingPrefs);
+ notify_post("com.apple.printerPrefsChange");
+}
+#endif /* __APPLE__ */
+
+
+/*
+ * '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 ++)
+ {
+ _cupsStrFree(dest->name);
+ _cupsStrFree(dest->instance);
+
+ cupsFreeOptions(dest->num_options, dest->options);
+ }
+
+ free(dests);
+}
+
+
+/*
+ * 'cupsGetDest()' - Get the named destination from the list.
+ *
+ * Use the @link cupsGetDests@ or @link cupsGetDests2@ functions to get a
+ * list of supported destinations for the current user.
+ */
+
+cups_dest_t * /* O - Destination pointer or @code NULL@ */
+cupsGetDest(const char *name, /* I - Destination name or @code NULL@ for the default destination */
+ const char *instance, /* I - Instance name or @code NULL@ */
+ int num_dests, /* I - Number of destinations */
+ cups_dest_t *dests) /* I - Destinations */
+{
+ int diff, /* Result of comparison */
+ match; /* Matching index */
+
+
+ if (num_dests <= 0 || !dests)
+ return (NULL);
+
+ if (!name)
+ {
+ /*
+ * 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...
+ */
+
+ match = cups_find_dest(name, instance, num_dests, dests, -1, &diff);
+
+ if (!diff)
+ return (dests + match);
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * '_cupsGetDests()' - Get destinations from a server.
+ *
+ * "op" is CUPS_GET_PRINTERS to get a full list, CUPS_GET_DEFAULT to get the
+ * system-wide default printer, or IPP_GET_PRINTER_ATTRIBUTES for a known
+ * printer.
+ *
+ * "name" is the name of an existing printer and is only used when "op" is
+ * IPP_GET_PRINTER_ATTRIBUTES.
+ *
+ * "dest" is initialized to point to the array of destinations.
+ *
+ * 0 is returned if there are no printers, no default printer, or the named
+ * printer does not exist, respectively.
+ *
+ * Free the memory used by the destination array using the @link cupsFreeDests@
+ * function.
+ *
+ * Note: On Mac OS X this function also gets the default paper from the system
+ * preferences (~/L/P/org.cups.PrintingPrefs.plist) and includes it in the
+ * options array for each destination that supports it.
+ */
+
+int /* O - Number of destinations */
+_cupsGetDests(http_t *http, /* I - Connection to server or CUPS_HTTP_DEFAULT */
+ ipp_op_t op, /* I - IPP operation */
+ const char *name, /* I - Name of destination */
+ cups_dest_t **dests) /* IO - Destinations */
+{
+ int num_dests = 0; /* Number of destinations */
+ cups_dest_t *dest; /* Current destination */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *printer_name; /* printer-name attribute */
+ char uri[1024]; /* printer-uri value */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+#ifdef __APPLE__
+ char media_default[41]; /* Default paper size */
+#endif /* __APPLE__ */
+ char optname[1024], /* Option name */
+ value[2048], /* Option value */
+ *ptr; /* Pointer into name/value */
+ static const char * const pattrs[] = /* Attributes we're interested in */
+ {
+ "auth-info-required",
+ "device-uri",
+ "job-sheets-default",
+ "marker-change-time",
+ "marker-colors",
+ "marker-high-levels",
+ "marker-levels",
+ "marker-low-levels",
+ "marker-message",
+ "marker-names",
+ "marker-types",
+#ifdef __APPLE__
+ "media-supported",
+#endif /* __APPLE__ */
+ "printer-commands",
+ "printer-defaults",
+ "printer-info",
+ "printer-is-accepting-jobs",
+ "printer-is-shared",
+ "printer-location",
+ "printer-make-and-model",
+ "printer-name",
+ "printer-state",
+ "printer-state-change-time",
+ "printer-state-reasons",
+ "printer-type",
+ "printer-uri-supported"
+ };
+
+
+#ifdef __APPLE__
+ /*
+ * Get the default paper size...
+ */
+
+ appleGetPaperSize(media_default, sizeof(media_default));
+#endif /* __APPLE__ */
+
+ /*
+ * Build a CUPS_GET_PRINTERS or IPP_GET_PRINTER_ATTRIBUTES request, which
+ * require the following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requesting-user-name
+ * printer-uri [for IPP_GET_PRINTER_ATTRIBUTES]
+ */
+
+ request = ippNewRequest(op);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
+ NULL, pattrs);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, cupsUser());
+
+ if (name && op != CUPS_GET_DEFAULT)
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", ippPort(), "/printers/%s", name);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
+ uri);
+ }
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ 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 printer...
+ */
+
+ printer_name = NULL;
+ num_options = 0;
+ options = NULL;
+
+ for (; attr && attr->group_tag == IPP_TAG_PRINTER; attr = attr->next)
+ {
+ if (attr->value_tag != IPP_TAG_INTEGER &&
+ attr->value_tag != IPP_TAG_ENUM &&
+ attr->value_tag != IPP_TAG_BOOLEAN &&
+ attr->value_tag != IPP_TAG_TEXT &&
+ attr->value_tag != IPP_TAG_TEXTLANG &&
+ attr->value_tag != IPP_TAG_NAME &&
+ attr->value_tag != IPP_TAG_NAMELANG &&
+ attr->value_tag != IPP_TAG_KEYWORD &&
+ attr->value_tag != IPP_TAG_RANGE &&
+ attr->value_tag != IPP_TAG_URI)
+ continue;
+
+ if (!strcmp(attr->name, "auth-info-required") ||
+ !strcmp(attr->name, "device-uri") ||
+ !strcmp(attr->name, "marker-change-time") ||
+ !strcmp(attr->name, "marker-colors") ||
+ !strcmp(attr->name, "marker-high-levels") ||
+ !strcmp(attr->name, "marker-levels") ||
+ !strcmp(attr->name, "marker-low-levels") ||
+ !strcmp(attr->name, "marker-message") ||
+ !strcmp(attr->name, "marker-names") ||
+ !strcmp(attr->name, "marker-types") ||
+ !strcmp(attr->name, "printer-commands") ||
+ !strcmp(attr->name, "printer-info") ||
+ !strcmp(attr->name, "printer-is-shared") ||
+ !strcmp(attr->name, "printer-make-and-model") ||
+ !strcmp(attr->name, "printer-state") ||
+ !strcmp(attr->name, "printer-state-change-time") ||
+ !strcmp(attr->name, "printer-type") ||
+ !strcmp(attr->name, "printer-is-accepting-jobs") ||
+ !strcmp(attr->name, "printer-location") ||
+ !strcmp(attr->name, "printer-state-reasons") ||
+ !strcmp(attr->name, "printer-uri-supported"))
+ {
+ /*
+ * Add a printer description attribute...
+ */
+
+ num_options = cupsAddOption(attr->name,
+ cups_make_string(attr, value,
+ sizeof(value)),
+ num_options, &options);
+ }
+#ifdef __APPLE__
+ else if (!strcmp(attr->name, "media-supported"))
+ {
+ /*
+ * See if we can set a default media size...
+ */
+
+ int i; /* Looping var */
+
+ for (i = 0; i < attr->num_values; i ++)
+ if (!_cups_strcasecmp(media_default, attr->values[i].string.text))
+ {
+ num_options = cupsAddOption("media", media_default, num_options,
+ &options);
+ break;
+ }
+ }
+#endif /* __APPLE__ */
+ else if (!strcmp(attr->name, "printer-name") &&
+ attr->value_tag == IPP_TAG_NAME)
+ printer_name = attr->values[0].string.text;
+ else if (strncmp(attr->name, "notify-", 7) &&
+ (attr->value_tag == IPP_TAG_BOOLEAN ||
+ attr->value_tag == IPP_TAG_ENUM ||
+ attr->value_tag == IPP_TAG_INTEGER ||
+ attr->value_tag == IPP_TAG_KEYWORD ||
+ attr->value_tag == IPP_TAG_NAME ||
+ attr->value_tag == IPP_TAG_RANGE) &&
+ (ptr = strstr(attr->name, "-default")) != NULL)
+ {
+ /*
+ * Add a default option...
+ */
+
+ strlcpy(optname, attr->name, sizeof(optname));
+ optname[ptr - attr->name] = '\0';
+
+ if (_cups_strcasecmp(optname, "media") ||
+ !cupsGetOption("media", num_options, options))
+ num_options = cupsAddOption(optname,
+ cups_make_string(attr, value,
+ sizeof(value)),
+ num_options, &options);
+ }
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (!printer_name)
+ {
+ cupsFreeOptions(num_options, options);
+
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ if ((dest = cups_add_dest(printer_name, NULL, &num_dests, dests)) != NULL)
+ {
+ dest->num_options = num_options;
+ dest->options = options;
+ }
+ else
+ cupsFreeOptions(num_options, options);
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+
+ /*
+ * Return the count...
+ */
+
+ return (num_dests);
+}
+
+
+/*
+ * 'cupsGetDests()' - Get the list of destinations from the default server.
+ *
+ * Starting with CUPS 1.2, the returned list of destinations include the
+ * printer-info, printer-is-accepting-jobs, printer-is-shared,
+ * printer-make-and-model, printer-state, printer-state-change-time,
+ * printer-state-reasons, and printer-type attributes as options. CUPS 1.4
+ * adds the marker-change-time, marker-colors, marker-high-levels,
+ * marker-levels, marker-low-levels, marker-message, marker-names,
+ * marker-types, and printer-commands attributes as well.
+ *
+ * Use the @link cupsFreeDests@ function to free the destination list and
+ * the @link cupsGetDest@ function to find a particular destination.
+ */
+
+int /* O - Number of destinations */
+cupsGetDests(cups_dest_t **dests) /* O - Destinations */
+{
+ return (cupsGetDests2(CUPS_HTTP_DEFAULT, dests));
+}
+
+
+/*
+ * 'cupsGetDests2()' - Get the list of destinations from the specified server.
+ *
+ * Starting with CUPS 1.2, the returned list of destinations include the
+ * printer-info, printer-is-accepting-jobs, printer-is-shared,
+ * printer-make-and-model, printer-state, printer-state-change-time,
+ * printer-state-reasons, and printer-type attributes as options. CUPS 1.4
+ * adds the marker-change-time, marker-colors, marker-high-levels,
+ * marker-levels, marker-low-levels, marker-message, marker-names,
+ * marker-types, and printer-commands attributes as well.
+ *
+ * Use the @link cupsFreeDests@ function to free the destination list and
+ * the @link cupsGetDest@ function to find a particular destination.
+ *
+ * @since CUPS 1.1.21/Mac OS X 10.4@
+ */
+
+int /* O - Number of destinations */
+cupsGetDests2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ 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 ~/.cups/lpoptions file */
+ const char *defprinter; /* Default printer */
+ char name[1024], /* Copy of printer name */
+ *instance, /* Pointer to instance name */
+ *user_default; /* User default printer */
+ int num_reals; /* Number of real queues */
+ cups_dest_t *reals; /* Real queues */
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ /*
+ * Range check the input...
+ */
+
+ if (!dests)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad NULL dests pointer"), 1);
+ return (0);
+ }
+
+ /*
+ * Grab the printers and classes...
+ */
+
+ *dests = (cups_dest_t *)0;
+ num_dests = _cupsGetDests(http, CUPS_GET_PRINTERS, NULL, dests);
+
+ if (cupsLastError() >= IPP_REDIRECTION_OTHER_SITE)
+ {
+ cupsFreeDests(num_dests, *dests);
+ *dests = (cups_dest_t *)0;
+ return (0);
+ }
+
+ /*
+ * 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 ((user_default = _cupsUserDefault(name, sizeof(name))) != NULL)
+ defprinter = name;
+ else if ((defprinter = cupsGetDefault2(http)) != NULL)
+ {
+ strlcpy(name, defprinter, sizeof(name));
+ defprinter = name;
+ }
+
+ if (defprinter)
+ {
+ /*
+ * Separate printer and instance 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
+ instance = NULL;
+
+ /*
+ * Load the /etc/cups/lpoptions and ~/.cups/lpoptions files...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
+ num_dests = cups_get_dests(filename, NULL, NULL, user_default != NULL,
+ num_dests, dests);
+
+ if ((home = getenv("HOME")) != NULL)
+ {
+ snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
+
+ num_dests = cups_get_dests(filename, NULL, NULL, user_default != NULL,
+ num_dests, dests);
+ }
+
+ /*
+ * Validate the current default destination - this prevents old
+ * Default lines in /etc/cups/lpoptions and ~/.cups/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...
+ */
+
+ if (num_dests > 0)
+ _cupsSetError(IPP_OK, NULL, 0);
+
+ return (num_dests);
+}
+
+
+/*
+ * 'cupsGetNamedDest()' - Get options for the named destination.
+ *
+ * This function is optimized for retrieving a single destination and should
+ * be used instead of @link cupsGetDests@ and @link cupsGetDest@ when you either
+ * know the name of the destination or want to print to the default destination.
+ * If @code NULL@ is returned, the destination does not exist or there is no
+ * default destination.
+ *
+ * If "http" is @code CUPS_HTTP_DEFAULT@, the connection to the default print
+ * server will be used.
+ *
+ * If "name" is @code NULL@, the default printer for the current user will be
+ * returned.
+ *
+ * The returned destination must be freed using @link cupsFreeDests@ with a
+ * "num_dests" value of 1.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+cups_dest_t * /* O - Destination or @code NULL@ */
+cupsGetNamedDest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *name, /* I - Destination name or @code NULL@ for the default destination */
+ const char *instance) /* I - Instance name or @code NULL@ */
+{
+ cups_dest_t *dest; /* Destination */
+ char filename[1024], /* Path to lpoptions */
+ defname[256]; /* Default printer name */
+ const char *home = getenv("HOME"); /* Home directory */
+ int set_as_default = 0; /* Set returned destination as default */
+ ipp_op_t op = IPP_GET_PRINTER_ATTRIBUTES;
+ /* IPP operation to get server ops */
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ /*
+ * If "name" is NULL, find the default destination...
+ */
+
+ if (!name)
+ {
+ set_as_default = 1;
+ name = _cupsUserDefault(defname, sizeof(defname));
+
+ if (name)
+ {
+ char *ptr; /* Temporary pointer... */
+
+ if ((ptr = strchr(defname, '/')) != NULL)
+ {
+ *ptr++ = '\0';
+ instance = ptr;
+ }
+ else
+ instance = NULL;
+ }
+ else if (home)
+ {
+ /*
+ * No default in the environment, try the user's lpoptions files...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
+
+ name = cups_get_default(filename, defname, sizeof(defname), &instance);
+ }
+
+ if (!name)
+ {
+ /*
+ * Still not there? Try the system lpoptions file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/lpoptions",
+ cg->cups_serverroot);
+ name = cups_get_default(filename, defname, sizeof(defname), &instance);
+ }
+
+ if (!name)
+ {
+ /*
+ * No locally-set default destination, ask the server...
+ */
+
+ op = CUPS_GET_DEFAULT;
+ }
+ }
+
+ /*
+ * Get the printer's attributes...
+ */
+
+ if (!_cupsGetDests(http, op, name, &dest))
+ {
+ if (op == CUPS_GET_DEFAULT || (name && !set_as_default))
+ return (NULL);
+
+ /*
+ * The default printer from environment variables or from a
+ * configuration file does not exist. Find out the real default.
+ */
+
+ if (!_cupsGetDests(http, CUPS_GET_DEFAULT, NULL, &dest))
+ return (NULL);
+ }
+
+ if (instance)
+ dest->instance = _cupsStrAlloc(instance);
+
+ if (set_as_default)
+ dest->is_default = 1;
+
+ /*
+ * Then add local options...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
+ cups_get_dests(filename, name, instance, 1, 1, &dest);
+
+ if (home)
+ {
+ snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
+
+ cups_get_dests(filename, name, instance, 1, 1, &dest);
+ }
+
+ /*
+ * Return the result...
+ */
+
+ return (dest);
+}
+
+
+/*
+ * 'cupsRemoveDest()' - Remove a destination from the destination list.
+ *
+ * Removing a destination/instance does not delete the class or printer
+ * queue, merely the lpoptions for that destination/instance. Use the
+ * @link cupsSetDests@ or @link cupsSetDests2@ functions to save the new
+ * options for the user.
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+int /* O - New number of destinations */
+cupsRemoveDest(const char *name, /* I - Destination name */
+ const char *instance, /* I - Instance name or @code NULL@ */
+ int num_dests, /* I - Number of destinations */
+ cups_dest_t **dests) /* IO - Destinations */
+{
+ int i; /* Index into destinations */
+ cups_dest_t *dest; /* Pointer to destination */
+
+
+ /*
+ * Find the destination...
+ */
+
+ if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL)
+ return (num_dests);
+
+ /*
+ * Free memory...
+ */
+
+ _cupsStrFree(dest->name);
+ _cupsStrFree(dest->instance);
+ cupsFreeOptions(dest->num_options, dest->options);
+
+ /*
+ * Remove the destination from the array...
+ */
+
+ num_dests --;
+
+ i = dest - *dests;
+
+ if (i < num_dests)
+ memmove(dest, dest + 1, (num_dests - i) * sizeof(cups_dest_t));
+
+ return (num_dests);
+}
+
+
+/*
+ * 'cupsSetDefaultDest()' - Set the default destination.
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+void
+cupsSetDefaultDest(
+ const char *name, /* I - Destination name */
+ const char *instance, /* I - Instance name or @code NULL@ */
+ int num_dests, /* I - Number of destinations */
+ cups_dest_t *dests) /* I - Destinations */
+{
+ int i; /* Looping var */
+ cups_dest_t *dest; /* Current destination */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!name || num_dests <= 0 || !dests)
+ return;
+
+ /*
+ * Loop through the array and set the "is_default" flag for the matching
+ * destination...
+ */
+
+ for (i = num_dests, dest = dests; i > 0; i --, dest ++)
+ dest->is_default = !_cups_strcasecmp(name, dest->name) &&
+ ((!instance && !dest->instance) ||
+ (instance && dest->instance &&
+ !_cups_strcasecmp(instance, dest->instance)));
+}
+
+
+/*
+ * 'cupsSetDests()' - Save the list of destinations for the default server.
+ *
+ * This function saves the destinations to /etc/cups/lpoptions when run
+ * as root and ~/.cups/lpoptions when run as a normal user.
+ */
+
+void
+cupsSetDests(int num_dests, /* I - Number of destinations */
+ cups_dest_t *dests) /* I - Destinations */
+{
+ cupsSetDests2(CUPS_HTTP_DEFAULT, num_dests, dests);
+}
+
+
+/*
+ * 'cupsSetDests2()' - Save the list of destinations for the specified server.
+ *
+ * This function saves the destinations to /etc/cups/lpoptions when run
+ * as root and ~/.cups/lpoptions when run as a normal user.
+ *
+ * @since CUPS 1.1.21/Mac OS X 10.4@
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsSetDests2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ 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 */
+ _ipp_option_t *match; /* Matching attribute for option */
+ FILE *fp; /* File pointer */
+#ifndef WIN32
+ const char *home; /* HOME environment variable */
+#endif /* WIN32 */
+ 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(); /* Pointer to library globals */
+
+
+ /*
+ * Range check the input...
+ */
+
+ if (!num_dests || !dests)
+ return (-1);
+
+ /*
+ * Get the server destinations...
+ */
+
+ num_temps = _cupsGetDests(http, CUPS_GET_PRINTERS, NULL, &temps);
+
+ if (cupsLastError() >= IPP_REDIRECTION_OTHER_SITE)
+ {
+ cupsFreeDests(num_temps, temps);
+ return (-1);
+ }
+
+ /*
+ * 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, NULL, NULL, 0, num_temps, &temps);
+
+ /*
+ * Point to user defaults...
+ */
+
+ if ((home = getenv("HOME")) != NULL)
+ {
+ /*
+ * Create ~/.cups subdirectory...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/.cups", home);
+ if (access(filename, 0))
+ mkdir(filename, 0700);
+
+ snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
+ }
+ }
+#endif /* !WIN32 */
+
+ /*
+ * Try to open the file...
+ */
+
+ if ((fp = fopen(filename, "w")) == NULL)
+ {
+ cupsFreeDests(num_temps, temps);
+ return (-1);
+ }
+
+#ifndef WIN32
+ /*
+ * Set the permissions to 0644 when saving to the /etc/cups/lpoptions
+ * file...
+ */
+
+ if (!getuid())
+ fchmod(fileno(fp), 0644);
+#endif /* !WIN32 */
+
+ /*
+ * 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 this option is a printer attribute; if so, skip it...
+ */
+
+ if ((match = _ippFindOption(option->name)) != NULL &&
+ match->group_tag == IPP_TAG_PRINTER)
+ continue;
+
+ /*
+ * 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 &&
+ !_cups_strcasecmp(val, option->value))
+ 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, ' ') ||
+ strchr(option->value, '\\') ||
+ strchr(option->value, '\"') ||
+ strchr(option->value, '\''))
+ {
+ /*
+ * Quote the value...
+ */
+
+ fprintf(fp, " %s=\"", option->name);
+
+ for (val = option->value; *val; val ++)
+ {
+ if (strchr("\"\'\\", *val))
+ putc('\\', fp);
+
+ putc(*val, fp);
+ }
+
+ putc('\"', fp);
+ }
+ else
+ {
+ /*
+ * Store the literal value...
+ */
+
+ fprintf(fp, " %s=%s", option->name, option->value);
+ }
+ }
+ else
+ fprintf(fp, " %s", option->name);
+ }
+
+ if (wrote)
+ fputs("\n", fp);
+ }
+
+ /*
+ * Free the temporary destinations and close the file...
+ */
+
+ cupsFreeDests(num_temps, temps);
+
+ fclose(fp);
+
+#ifdef __APPLE__
+ /*
+ * Set the default printer for this location - this allows command-line
+ * and GUI applications to share the same default destination...
+ */
+
+ if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL)
+ {
+ CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault,
+ dest->name,
+ kCFStringEncodingUTF8);
+ /* Default printer name */
+
+ if (name)
+ {
+ _cupsAppleSetDefaultPrinter(name);
+ CFRelease(name);
+ }
+ }
+#endif /* __APPLE__ */
+
+#ifdef HAVE_NOTIFY_POST
+ /*
+ * Send a notification so that MacOS X applications can know about the
+ * change, too.
+ */
+
+ notify_post("com.apple.printerListChange");
+#endif /* HAVE_NOTIFY_POST */
+
+ return (0);
+}
+
+
+/*
+ * '_cupsUserDefault()' - Get the user default printer from environment
+ * variables and location information.
+ */
+
+char * /* O - Default printer or NULL */
+_cupsUserDefault(char *name, /* I - Name buffer */
+ size_t namesize) /* I - Size of name buffer */
+{
+ const char *env; /* LPDEST or PRINTER env variable */
+#ifdef __APPLE__
+ CFStringRef locprinter; /* Last printer as this location */
+#endif /* __APPLE__ */
+
+
+ if ((env = getenv("LPDEST")) == NULL)
+ if ((env = getenv("PRINTER")) != NULL && !strcmp(env, "lp"))
+ env = NULL;
+
+ if (env)
+ {
+ strlcpy(name, env, namesize);
+ return (name);
+ }
+
+#ifdef __APPLE__
+ /*
+ * Use location-based defaults if "use last printer" is selected in the
+ * system preferences...
+ */
+
+ if ((locprinter = _cupsAppleCopyDefaultPrinter()) != NULL)
+ {
+ CFStringGetCString(locprinter, name, namesize, kCFStringEncodingUTF8);
+ CFRelease(locprinter);
+ }
+ else
+ name[0] = '\0';
+
+ DEBUG_printf(("1_cupsUserDefault: Returning \"%s\".", name));
+
+ return (*name ? name : NULL);
+
+#else
+ /*
+ * No location-based defaults on this platform...
+ */
+
+ name[0] = '\0';
+ return (NULL);
+#endif /* __APPLE__ */
+}
+
+
+#ifdef __APPLE__
+/*
+ * 'appleCopyLocations()' - Copy the location history array.
+ */
+
+static CFArrayRef /* O - Location array or NULL */
+appleCopyLocations(void)
+{
+ CFArrayRef locations; /* Location array */
+
+
+ /*
+ * Look up the location array in the preferences...
+ */
+
+ if ((locations = CFPreferencesCopyAppValue(kLastUsedPrintersKey,
+ kCUPSPrintingPrefs)) == NULL)
+ return (NULL);
+
+ if (CFGetTypeID(locations) != CFArrayGetTypeID())
+ {
+ CFRelease(locations);
+ return (NULL);
+ }
+
+ return (locations);
+}
+
+
+/*
+ * 'appleCopyNetwork()' - Get the network ID for the current location.
+ */
+
+static CFStringRef /* O - Network ID */
+appleCopyNetwork(void)
+{
+ SCDynamicStoreRef dynamicStore; /* System configuration data */
+ CFStringRef key; /* Current network configuration key */
+ CFDictionaryRef ip_dict; /* Network configuration data */
+ CFStringRef network = NULL; /* Current network ID */
+
+
+ if ((dynamicStore = SCDynamicStoreCreate(NULL, CFSTR("libcups"), NULL,
+ NULL)) != NULL)
+ {
+ /*
+ * First use the IPv6 router address, if available, since that will generally
+ * be a globally-unique link-local address.
+ */
+
+ if ((key = SCDynamicStoreKeyCreateNetworkGlobalEntity(
+ NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6)) != NULL)
+ {
+ if ((ip_dict = SCDynamicStoreCopyValue(dynamicStore, key)) != NULL)
+ {
+ if ((network = CFDictionaryGetValue(ip_dict,
+ kSCPropNetIPv6Router)) != NULL)
+ CFRetain(network);
+
+ CFRelease(ip_dict);
+ }
+
+ CFRelease(key);
+ }
+
+ /*
+ * If that doesn't work, try the IPv4 router address. This isn't as unique
+ * and will likely be a 10.x.y.z or 192.168.y.z address...
+ */
+
+ if (!network)
+ {
+ if ((key = SCDynamicStoreKeyCreateNetworkGlobalEntity(
+ NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4)) != NULL)
+ {
+ if ((ip_dict = SCDynamicStoreCopyValue(dynamicStore, key)) != NULL)
+ {
+ if ((network = CFDictionaryGetValue(ip_dict,
+ kSCPropNetIPv4Router)) != NULL)
+ CFRetain(network);
+
+ CFRelease(ip_dict);
+ }
+
+ CFRelease(key);
+ }
+ }
+
+ CFRelease(dynamicStore);
+ }
+
+ return (network);
+}
+
+
+/*
+ * 'appleGetPaperSize()' - Get the default paper size.
+ */
+
+char * /* O - Default paper size */
+appleGetPaperSize(char *name, /* I - Paper size name buffer */
+ int namesize) /* I - Size of buffer */
+{
+ CFStringRef defaultPaperID; /* Default paper ID */
+ _pwg_media_t *pwgmedia; /* PWG media size */
+
+
+ defaultPaperID = _cupsAppleCopyDefaultPaperID();
+ if (!defaultPaperID ||
+ CFGetTypeID(defaultPaperID) != CFStringGetTypeID() ||
+ !CFStringGetCString(defaultPaperID, name, namesize,
+ kCFStringEncodingUTF8))
+ name[0] = '\0';
+ else if ((pwgmedia = _pwgMediaForLegacy(name)) != NULL)
+ strlcpy(name, pwgmedia->pwg, namesize);
+
+ if (defaultPaperID)
+ CFRelease(defaultPaperID);
+
+ return (name);
+}
+
+
+/*
+ * 'appleGetPrinter()' - Get a printer from the history array.
+ */
+
+static CFStringRef /* O - Printer name or NULL */
+appleGetPrinter(CFArrayRef locations, /* I - Location array */
+ CFStringRef network, /* I - Network name */
+ CFIndex *locindex) /* O - Index in array */
+{
+ CFIndex i, /* Looping var */
+ count; /* Number of locations */
+ CFDictionaryRef location; /* Current location */
+ CFStringRef locnetwork, /* Current network */
+ locprinter; /* Current printer */
+
+
+ for (i = 0, count = CFArrayGetCount(locations); i < count; i ++)
+ if ((location = CFArrayGetValueAtIndex(locations, i)) != NULL &&
+ CFGetTypeID(location) == CFDictionaryGetTypeID())
+ {
+ if ((locnetwork = CFDictionaryGetValue(location,
+ kLocationNetworkKey)) != NULL &&
+ CFGetTypeID(locnetwork) == CFStringGetTypeID() &&
+ CFStringCompare(network, locnetwork, 0) == kCFCompareEqualTo &&
+ (locprinter = CFDictionaryGetValue(location,
+ kLocationPrinterIDKey)) != NULL &&
+ CFGetTypeID(locprinter) == CFStringGetTypeID())
+ {
+ if (locindex)
+ *locindex = i;
+
+ return (locprinter);
+ }
+ }
+
+ return (NULL);
+}
+#endif /* __APPLE__ */
+
+
+/*
+ * 'cups_add_dest()' - Add a destination to the array.
+ *
+ * Unlike cupsAddDest(), this function does not check for duplicates.
+ */
+
+static cups_dest_t * /* O - New destination */
+cups_add_dest(const char *name, /* I - Name of destination */
+ const char *instance, /* I - Instance or NULL */
+ int *num_dests, /* IO - Number of destinations */
+ cups_dest_t **dests) /* IO - Destinations */
+{
+ int insert, /* Insertion point */
+ diff; /* Result of comparison */
+ cups_dest_t *dest; /* Destination pointer */
+
+
+ /*
+ * 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)
+ return (NULL);
+
+ *dests = dest;
+
+ /*
+ * Find where to insert the destination...
+ */
+
+ if (*num_dests == 0)
+ insert = 0;
+ else
+ {
+ insert = cups_find_dest(name, instance, *num_dests, *dests, *num_dests - 1,
+ &diff);
+
+ if (diff > 0)
+ insert ++;
+ }
+
+ /*
+ * Move the array elements as needed...
+ */
+
+ if (insert < *num_dests)
+ memmove(*dests + insert + 1, *dests + insert,
+ (*num_dests - insert) * sizeof(cups_dest_t));
+
+ (*num_dests) ++;
+
+ /*
+ * Initialize the destination...
+ */
+
+ dest = *dests + insert;
+ dest->name = _cupsStrAlloc(name);
+ dest->instance = _cupsStrAlloc(instance);
+ dest->is_default = 0;
+ dest->num_options = 0;
+ dest->options = (cups_option_t *)0;
+
+ return (dest);
+}
+
+
+/*
+ * 'cups_compare_dests()' - Compare two destinations.
+ */
+
+static int /* O - Result of comparison */
+cups_compare_dests(cups_dest_t *a, /* I - First destination */
+ cups_dest_t *b) /* I - Second destination */
+{
+ int diff; /* Difference */
+
+
+ if ((diff = _cups_strcasecmp(a->name, b->name)) != 0)
+ return (diff);
+ else if (a->instance && b->instance)
+ return (_cups_strcasecmp(a->instance, b->instance));
+ else
+ return ((a->instance && !b->instance) - (!a->instance && b->instance));
+}
+
+
+/*
+ * 'cups_find_dest()' - Find a destination using a binary search.
+ */
+
+static int /* O - Index of match */
+cups_find_dest(const char *name, /* I - Destination name */
+ const char *instance, /* I - Instance or NULL */
+ int num_dests, /* I - Number of destinations */
+ cups_dest_t *dests, /* I - Destinations */
+ int prev, /* I - Previous index */
+ int *rdiff) /* O - Difference of match */
+{
+ int left, /* Low mark for binary search */
+ right, /* High mark for binary search */
+ current, /* Current index */
+ diff; /* Result of comparison */
+ cups_dest_t key; /* Search key */
+
+
+ key.name = (char *)name;
+ key.instance = (char *)instance;
+
+ if (prev >= 0)
+ {
+ /*
+ * Start search on either side of previous...
+ */
+
+ if ((diff = cups_compare_dests(&key, dests + prev)) == 0 ||
+ (diff < 0 && prev == 0) ||
+ (diff > 0 && prev == (num_dests - 1)))
+ {
+ *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 = num_dests - 1;
+ }
+ }
+ else
+ {
+ /*
+ * Start search in the middle...
+ */
+
+ left = 0;
+ right = num_dests - 1;
+ }
+
+ do
+ {
+ current = (left + right) / 2;
+ diff = cups_compare_dests(&key, dests + current);
+
+ 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 = cups_compare_dests(&key, dests + left)) <= 0)
+ current = left;
+ else
+ {
+ diff = cups_compare_dests(&key, dests + right);
+ current = right;
+ }
+ }
+
+ /*
+ * Return the closest destination and the difference...
+ */
+
+ *rdiff = diff;
+
+ return (current);
+}
+
+
+/*
+ * 'cups_get_default()' - Get the default destination from an lpoptions file.
+ */
+
+static char * /* O - Default destination or NULL */
+cups_get_default(const char *filename, /* I - File to read */
+ char *namebuf, /* I - Name buffer */
+ size_t namesize, /* I - Size of name buffer */
+ const char **instance) /* I - Instance */
+{
+ cups_file_t *fp; /* lpoptions file */
+ char line[8192], /* Line from file */
+ *value, /* Value for line */
+ *nameptr; /* Pointer into name */
+ int linenum; /* Current line */
+
+
+ *namebuf = '\0';
+
+ if ((fp = cupsFileOpen(filename, "r")) != NULL)
+ {
+ linenum = 0;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ if (!_cups_strcasecmp(line, "default") && value)
+ {
+ strlcpy(namebuf, value, namesize);
+
+ if ((nameptr = strchr(namebuf, ' ')) != NULL)
+ *nameptr = '\0';
+ if ((nameptr = strchr(namebuf, '\t')) != NULL)
+ *nameptr = '\0';
+
+ if ((nameptr = strchr(namebuf, '/')) != NULL)
+ *nameptr++ = '\0';
+
+ *instance = nameptr;
+ break;
+ }
+ }
+
+ cupsFileClose(fp);
+ }
+
+ return (*namebuf ? namebuf : NULL);
+}
+
+
+/*
+ * '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 */
+ const char *match_name, /* I - Destination name we want */
+ const char *match_inst, /* I - Instance name we want */
+ int user_default_set, /* I - User default printer set? */
+ int num_dests, /* I - Number of destinations */
+ cups_dest_t **dests) /* IO - Destinations */
+{
+ int i; /* Looping var */
+ cups_dest_t *dest; /* Current destination */
+ cups_file_t *fp; /* File pointer */
+ char line[8192], /* Line from file */
+ *lineptr, /* Pointer into line */
+ *name, /* Name of destination/option */
+ *instance; /* Instance of destination */
+ int linenum; /* Current line number */
+
+
+ DEBUG_printf(("7cups_get_dests(filename=\"%s\", match_name=\"%s\", "
+ "match_inst=\"%s\", user_default_set=%d, num_dests=%d, "
+ "dests=%p)", filename, match_name, match_inst,
+ user_default_set, num_dests, dests));
+
+ /*
+ * Try to open the file...
+ */
+
+ if ((fp = cupsFileOpen(filename, "r")) == NULL)
+ return (num_dests);
+
+ /*
+ * Read each printer; each line looks like:
+ *
+ * Dest name[/instance] options
+ * Default name[/instance] options
+ */
+
+ linenum = 0;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &lineptr, &linenum))
+ {
+ /*
+ * See what type of line it is...
+ */
+
+ DEBUG_printf(("9cups_get_dests: linenum=%d line=\"%s\" lineptr=\"%s\"",
+ linenum, line, lineptr));
+
+ if ((_cups_strcasecmp(line, "dest") && _cups_strcasecmp(line, "default")) || !lineptr)
+ {
+ DEBUG_puts("9cups_get_dests: Not a dest or default line...");
+ continue;
+ }
+
+ name = lineptr;
+
+ /*
+ * Search for an instance...
+ */
+
+ while (!isspace(*lineptr & 255) && *lineptr && *lineptr != '/')
+ lineptr ++;
+
+ if (*lineptr == '/')
+ {
+ /*
+ * Found an instance...
+ */
+
+ *lineptr++ = '\0';
+ instance = lineptr;
+
+ /*
+ * Search for an instance...
+ */
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+ }
+ else
+ instance = NULL;
+
+ if (*lineptr)
+ *lineptr++ = '\0';
+
+ DEBUG_printf(("9cups_get_dests: name=\"%s\", instance=\"%s\"", name,
+ instance));
+
+ /*
+ * See if the primary instance of the destination exists; if not,
+ * ignore this entry and move on...
+ */
+
+ if (match_name)
+ {
+ if (_cups_strcasecmp(name, match_name) ||
+ (!instance && match_inst) ||
+ (instance && !match_inst) ||
+ (instance && _cups_strcasecmp(instance, match_inst)))
+ continue;
+
+ dest = *dests;
+ }
+ else if (cupsGetDest(name, NULL, num_dests, *dests) == NULL)
+ {
+ DEBUG_puts("9cups_get_dests: Not found!");
+ continue;
+ }
+ else
+ {
+ /*
+ * Add the destination...
+ */
+
+ num_dests = cupsAddDest(name, instance, num_dests, dests);
+
+ if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL)
+ {
+ /*
+ * Out of memory!
+ */
+
+ DEBUG_puts("9cups_get_dests: Out of memory!");
+ break;
+ }
+ }
+
+ /*
+ * Add options until we hit the end of the line...
+ */
+
+ dest->num_options = cupsParseOptions(lineptr, dest->num_options,
+ &(dest->options));
+
+ /*
+ * If we found what we were looking for, stop now...
+ */
+
+ if (match_name)
+ break;
+
+ /*
+ * Set this as default if needed...
+ */
+
+ if (!user_default_set && !_cups_strcasecmp(line, "default"))
+ {
+ DEBUG_puts("9cups_get_dests: Setting as default...");
+
+ for (i = 0; i < num_dests; i ++)
+ (*dests)[i].is_default = 0;
+
+ dest->is_default = 1;
+ }
+ }
+
+ /*
+ * Close the file and return...
+ */
+
+ cupsFileClose(fp);
+
+ return (num_dests);
+}
+
+
+/*
+ * 'cups_make_string()' - Make a comma-separated string of values from an IPP
+ * attribute.
+ */
+
+static char * /* O - New string */
+cups_make_string(
+ ipp_attribute_t *attr, /* I - Attribute to convert */
+ char *buffer, /* I - Buffer */
+ size_t bufsize) /* I - Size of buffer */
+{
+ int i; /* Looping var */
+ char *ptr, /* Pointer into buffer */
+ *end, /* Pointer to end of buffer */
+ *valptr; /* Pointer into string attribute */
+
+
+ /*
+ * Return quickly if we have a single string value...
+ */
+
+ if (attr->num_values == 1 &&
+ attr->value_tag != IPP_TAG_INTEGER &&
+ attr->value_tag != IPP_TAG_ENUM &&
+ attr->value_tag != IPP_TAG_BOOLEAN &&
+ attr->value_tag != IPP_TAG_RANGE)
+ return (attr->values[0].string.text);
+
+ /*
+ * Copy the values to the string, separating with commas and escaping strings
+ * as needed...
+ */
+
+ end = buffer + bufsize - 1;
+
+ for (i = 0, ptr = buffer; i < attr->num_values && ptr < end; i ++)
+ {
+ if (i)
+ *ptr++ = ',';
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ snprintf(ptr, end - ptr + 1, "%d", attr->values[i].integer);
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ if (attr->values[i].boolean)
+ strlcpy(ptr, "true", end - ptr + 1);
+ else
+ strlcpy(ptr, "false", end - ptr + 1);
+ break;
+
+ case IPP_TAG_RANGE :
+ if (attr->values[i].range.lower == attr->values[i].range.upper)
+ snprintf(ptr, end - ptr + 1, "%d", attr->values[i].range.lower);
+ else
+ snprintf(ptr, end - ptr + 1, "%d-%d", attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ break;
+
+ default :
+ for (valptr = attr->values[i].string.text;
+ *valptr && ptr < end;)
+ {
+ if (strchr(" \t\n\\\'\"", *valptr))
+ {
+ if (ptr >= (end - 1))
+ break;
+
+ *ptr++ = '\\';
+ }
+
+ *ptr++ = *valptr++;
+ }
+
+ *ptr = '\0';
+ break;
+ }
+
+ ptr += strlen(ptr);
+ }
+
+ *ptr = '\0';
+
+ return (buffer);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/dir.c b/cups/dir.c
new file mode 100644
index 000000000..490296e09
--- /dev/null
+++ b/cups/dir.c
@@ -0,0 +1,472 @@
+/*
+ * "$Id$"
+ *
+ * Directory routines for CUPS.
+ *
+ * This set of APIs abstracts enumeration of directory entries.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "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 "string-private.h"
+#include "debug-private.h"
+#include "dir.h"
+
+
+/*
+ * Windows implementation...
+ */
+
+#ifdef WIN32
+# include <windows.h>
+
+/*
+ * Types and structures...
+ */
+
+struct _cups_dir_s /**** Directory data structure ****/
+{
+ char directory[1024]; /* Directory filename */
+ HANDLE dir; /* Directory handle */
+ cups_dentry_t entry; /* Directory entry */
+};
+
+
+/*
+ * '_cups_dir_time()' - Convert a FILETIME value to a UNIX time value.
+ */
+
+time_t /* O - UNIX time */
+_cups_dir_time(FILETIME ft) /* I - File time */
+{
+ ULONGLONG val; /* File time in 0.1 usecs */
+
+
+ /*
+ * Convert file time (1/10 microseconds since Jan 1, 1601) to UNIX
+ * time (seconds since Jan 1, 1970). There are 11,644,732,800 seconds
+ * between them...
+ */
+
+ val = ft.dwLowDateTime + ((ULONGLONG)ft.dwHighDateTime << 32);
+ return ((time_t)(val / 10000000 - 11644732800));
+}
+
+
+/*
+ * 'cupsDirClose()' - Close a directory.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void
+cupsDirClose(cups_dir_t *dp) /* I - Directory pointer */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!dp)
+ return;
+
+ /*
+ * Close an open directory handle...
+ */
+
+ if (dp->dir != INVALID_HANDLE_VALUE)
+ FindClose(dp->dir);
+
+ /*
+ * Free memory used...
+ */
+
+ free(dp);
+}
+
+
+/*
+ * 'cupsDirOpen()' - Open a directory.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+cups_dir_t * /* O - Directory pointer or @code NULL@ if the directory could not be opened. */
+cupsDirOpen(const char *directory) /* I - Directory name */
+{
+ cups_dir_t *dp; /* Directory */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!directory)
+ return (NULL);
+
+ /*
+ * Allocate memory for the directory structure...
+ */
+
+ dp = (cups_dir_t *)calloc(1, sizeof(cups_dir_t));
+ if (!dp)
+ return (NULL);
+
+ /*
+ * Copy the directory name for later use...
+ */
+
+ dp->dir = INVALID_HANDLE_VALUE;
+
+ strlcpy(dp->directory, directory, sizeof(dp->directory));
+
+ /*
+ * Return the new directory structure...
+ */
+
+ return (dp);
+}
+
+
+/*
+ * 'cupsDirRead()' - Read the next directory entry.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+cups_dentry_t * /* O - Directory entry or @code NULL@ if there are no more */
+cupsDirRead(cups_dir_t *dp) /* I - Directory pointer */
+{
+ WIN32_FIND_DATA entry; /* Directory entry data */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!dp)
+ return (NULL);
+
+ /*
+ * See if we have already started finding files...
+ */
+
+ if (dp->dir == INVALID_HANDLE_VALUE)
+ {
+ /*
+ * No, find the first file...
+ */
+
+ dp->dir = FindFirstFile(dp->directory, &entry);
+ if (dp->dir == INVALID_HANDLE_VALUE)
+ return (NULL);
+ }
+ else if (!FindNextFile(dp->dir, &entry))
+ return (NULL);
+
+ /*
+ * Copy the name over and convert the file information...
+ */
+
+ strlcpy(dp->entry.filename, entry.cFileName, sizeof(dp->entry.filename));
+
+ if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ dp->entry.fileinfo.st_mode = 0755 | S_IFDIR;
+ else
+ dp->entry.fileinfo.st_mode = 0644;
+
+ dp->entry.fileinfo.st_atime = _cups_dir_time(entry.ftLastAccessTime);
+ dp->entry.fileinfo.st_ctime = _cups_dir_time(entry.ftCreationTime);
+ dp->entry.fileinfo.st_mtime = _cups_dir_time(entry.ftLastWriteTime);
+ dp->entry.fileinfo.st_size = entry.nFileSizeLow + ((unsigned long long)entry.nFileSizeHigh << 32);
+
+ /*
+ * Return the entry...
+ */
+
+ return (&(dp->entry));
+}
+
+
+/*
+ * 'cupsDirRewind()' - Rewind to the start of the directory.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void
+cupsDirRewind(cups_dir_t *dp) /* I - Directory pointer */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!dp)
+ return;
+
+ /*
+ * Close an open directory handle...
+ */
+
+ if (dp->dir != INVALID_HANDLE_VALUE)
+ {
+ FindClose(dp->dir);
+ dp->dir = INVALID_HANDLE_VALUE;
+ }
+}
+
+
+#else
+
+/*
+ * POSIX implementation...
+ */
+
+# include <sys/types.h>
+# include <dirent.h>
+
+
+/*
+ * Types and structures...
+ */
+
+struct _cups_dir_s /**** Directory data structure ****/
+{
+ char directory[1024]; /* Directory filename */
+ DIR *dir; /* Directory file */
+ cups_dentry_t entry; /* Directory entry */
+};
+
+
+/*
+ * 'cupsDirClose()' - Close a directory.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void
+cupsDirClose(cups_dir_t *dp) /* I - Directory pointer */
+{
+ DEBUG_printf(("cupsDirClose(dp=%p)", dp));
+
+ /*
+ * Range check input...
+ */
+
+ if (!dp)
+ return;
+
+ /*
+ * Close the directory and free memory...
+ */
+
+ closedir(dp->dir);
+ free(dp);
+}
+
+
+/*
+ * 'cupsDirOpen()' - Open a directory.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+cups_dir_t * /* O - Directory pointer or @code NULL@ if the directory could not be opened. */
+cupsDirOpen(const char *directory) /* I - Directory name */
+{
+ cups_dir_t *dp; /* Directory */
+
+
+ DEBUG_printf(("cupsDirOpen(directory=\"%s\")", directory));
+
+ /*
+ * Range check input...
+ */
+
+ if (!directory)
+ return (NULL);
+
+ /*
+ * Allocate memory for the directory structure...
+ */
+
+ dp = (cups_dir_t *)calloc(1, sizeof(cups_dir_t));
+ if (!dp)
+ return (NULL);
+
+ /*
+ * Open the directory...
+ */
+
+ dp->dir = opendir(directory);
+ if (!dp->dir)
+ {
+ free(dp);
+ return (NULL);
+ }
+
+ /*
+ * Copy the directory name for later use...
+ */
+
+ strlcpy(dp->directory, directory, sizeof(dp->directory));
+
+ /*
+ * Return the new directory structure...
+ */
+
+ return (dp);
+}
+
+
+/*
+ * 'cupsDirRead()' - Read the next directory entry.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+cups_dentry_t * /* O - Directory entry or @code NULL@ when there are no more */
+cupsDirRead(cups_dir_t *dp) /* I - Directory pointer */
+{
+ struct dirent *entry; /* Pointer to entry */
+ char filename[1024]; /* Full filename */
+# ifdef HAVE_PTHREAD_H
+ char buffer[sizeof(struct dirent) + 1024];
+ /* Directory entry buffer */
+# endif /* HAVE_PTHREAD_H */
+
+
+ DEBUG_printf(("2cupsDirRead(dp=%p)", dp));
+
+ /*
+ * Range check input...
+ */
+
+ if (!dp)
+ return (NULL);
+
+ /*
+ * Try reading an entry that is not "." or ".."...
+ */
+
+ for (;;)
+ {
+# ifdef HAVE_PTHREAD_H
+ /*
+ * Read the next entry using the reentrant version of readdir...
+ */
+
+ if (readdir_r(dp->dir, (struct dirent *)buffer, &entry))
+ {
+ DEBUG_printf(("3cupsDirRead: readdir_r() failed - %s\n", strerror(errno)));
+ return (NULL);
+ }
+
+ if (!entry)
+ {
+ DEBUG_puts("3cupsDirRead: readdir_r() returned a NULL pointer!");
+ return (NULL);
+ }
+
+ DEBUG_printf(("4cupsDirRead: readdir_r() returned \"%s\"...",
+ entry->d_name));
+
+# else
+ /*
+ * Read the next entry using the original version of readdir...
+ */
+
+ if ((entry = readdir(dp->dir)) == NULL)
+ {
+ DEBUG_puts("3cupsDirRead: readdir() returned a NULL pointer!");
+ return (NULL);
+ }
+
+ DEBUG_printf(("4cupsDirRead: readdir() returned \"%s\"...", entry->d_name));
+
+# endif /* HAVE_PTHREAD_H */
+
+ /*
+ * Skip "." and ".."...
+ */
+
+ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
+ continue;
+
+ /*
+ * Copy the name over and get the file information...
+ */
+
+ strlcpy(dp->entry.filename, entry->d_name, sizeof(dp->entry.filename));
+
+ snprintf(filename, sizeof(filename), "%s/%s", dp->directory, entry->d_name);
+
+ if (stat(filename, &(dp->entry.fileinfo)))
+ {
+ DEBUG_printf(("3cupsDirRead: stat() failed for \"%s\" - %s...", filename,
+ strerror(errno)));
+ continue;
+ }
+
+ /*
+ * Return the entry...
+ */
+
+ return (&(dp->entry));
+ }
+}
+
+
+/*
+ * 'cupsDirRewind()' - Rewind to the start of the directory.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void
+cupsDirRewind(cups_dir_t *dp) /* I - Directory pointer */
+{
+ DEBUG_printf(("cupsDirRewind(dp=%p)", dp));
+
+ /*
+ * Range check input...
+ */
+
+ if (!dp)
+ return;
+
+ /*
+ * Rewind the directory...
+ */
+
+ rewinddir(dp->dir);
+}
+
+
+#endif /* WIN32 */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/dir.h b/cups/dir.h
new file mode 100644
index 000000000..75e5b1e61
--- /dev/null
+++ b/cups/dir.h
@@ -0,0 +1,69 @@
+/*
+ * "$Id$"
+ *
+ * Public directory definitions for CUPS.
+ *
+ * This set of APIs abstracts enumeration of directory entries.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPS_DIR_H_
+# define _CUPS_DIR_H_
+
+
+/*
+ * Include necessary headers...
+ */
+
+# include "versioning.h"
+# include <sys/stat.h>
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Data types...
+ */
+
+typedef struct _cups_dir_s cups_dir_t; /**** Directory type ****/
+
+typedef struct cups_dentry_s /**** Directory entry type ****/
+{
+ char filename[260]; /* File name */
+ struct stat fileinfo; /* File information */
+} cups_dentry_t;
+
+
+/*
+ * Prototypes...
+ */
+
+extern void cupsDirClose(cups_dir_t *dp) _CUPS_API_1_2;
+extern cups_dir_t *cupsDirOpen(const char *directory) _CUPS_API_1_2;
+extern cups_dentry_t *cupsDirRead(cups_dir_t *dp) _CUPS_API_1_2;
+extern void cupsDirRewind(cups_dir_t *dp) _CUPS_API_1_2;
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_DIR_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/emit.c b/cups/emit.c
new file mode 100644
index 000000000..9e871c21e
--- /dev/null
+++ b/cups/emit.c
@@ -0,0 +1,1217 @@
+/*
+ * "$Id$"
+ *
+ * PPD code emission routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * PostScript is a trademark of Adobe Systems, Inc.
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * ppdCollect() - Collect all marked options that reside in the
+ * specified section.
+ * ppdCollect2() - Collect all marked options that reside in the
+ * specified section and minimum order.
+ * ppdEmit() - Emit code for marked options to a file.
+ * ppdEmitAfterOrder() - Emit a subset of the code for marked options to a
+ * file.
+ * ppdEmitFd() - Emit code for marked options to a file.
+ * ppdEmitJCL() - Emit code for JCL options to a file.
+ * ppdEmitJCLEnd() - Emit JCLEnd code to a file.
+ * ppdEmitString() - Get a string containing the code for marked
+ * options.
+ * ppd_compare_cparams() - Compare the order of two custom parameters.
+ * ppd_handle_media() - Handle media selection...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+#else
+# include <unistd.h>
+#endif /* WIN32 || __EMX__ */
+
+
+/*
+ * Local functions...
+ */
+
+static int ppd_compare_cparams(ppd_cparam_t *a, ppd_cparam_t *b);
+static void ppd_handle_media(ppd_file_t *ppd);
+
+
+/*
+ * Local globals...
+ */
+
+static const char ppd_custom_code[] =
+ "pop pop pop\n"
+ "<</PageSize[5 -2 roll]/ImagingBBox null>>setpagedevice\n";
+
+
+/*
+ * 'ppdCollect()' - Collect all marked options that reside in the specified
+ * section.
+ *
+ * The choices array should be freed using @code free@ when you are
+ * finished with it.
+ */
+
+int /* O - Number of options marked */
+ppdCollect(ppd_file_t *ppd, /* I - PPD file data */
+ ppd_section_t section, /* I - Section to collect */
+ ppd_choice_t ***choices) /* O - Pointers to choices */
+{
+ return (ppdCollect2(ppd, section, 0.0, choices));
+}
+
+
+/*
+ * 'ppdCollect2()' - Collect all marked options that reside in the
+ * specified section and minimum order.
+ *
+ * The choices array should be freed using @code free@ when you are
+ * finished with it.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - Number of options marked */
+ppdCollect2(ppd_file_t *ppd, /* I - PPD file data */
+ ppd_section_t section, /* I - Section to collect */
+ float min_order, /* I - Minimum OrderDependency value */
+ ppd_choice_t ***choices) /* O - Pointers to choices */
+{
+ ppd_choice_t *c; /* Current choice */
+ ppd_section_t csection; /* Current section */
+ float corder; /* Current OrderDependency value */
+ int count; /* Number of choices collected */
+ ppd_choice_t **collect; /* Collected choices */
+ float *orders; /* Collected order values */
+
+
+ DEBUG_printf(("ppdCollect2(ppd=%p, section=%d, min_order=%f, choices=%p)",
+ ppd, section, min_order, choices));
+
+ if (!ppd || !choices)
+ {
+ if (choices)
+ *choices = NULL;
+
+ return (0);
+ }
+
+ /*
+ * Allocate memory for up to N selected choices...
+ */
+
+ count = 0;
+ if ((collect = calloc(sizeof(ppd_choice_t *),
+ cupsArrayCount(ppd->marked))) == NULL)
+ {
+ *choices = NULL;
+ return (0);
+ }
+
+ if ((orders = calloc(sizeof(float), cupsArrayCount(ppd->marked))) == NULL)
+ {
+ *choices = NULL;
+ free(collect);
+ return (0);
+ }
+
+ /*
+ * Loop through all options and add choices as needed...
+ */
+
+ for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
+ c;
+ c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
+ {
+ csection = c->option->section;
+ corder = c->option->order;
+
+ if (!strcmp(c->choice, "Custom"))
+ {
+ ppd_attr_t *attr; /* NonUIOrderDependency value */
+ float aorder; /* Order value */
+ char asection[17], /* Section name */
+ amain[PPD_MAX_NAME + 1],
+ aoption[PPD_MAX_NAME];
+ /* *CustomFoo and True */
+
+
+ for (attr = ppdFindAttr(ppd, "NonUIOrderDependency", NULL);
+ attr;
+ attr = ppdFindNextAttr(ppd, "NonUIOrderDependency", NULL))
+ if (attr->value &&
+ sscanf(attr->value, "%f%16s%41s%40s", &aorder, asection, amain,
+ aoption) == 4 &&
+ !strncmp(amain, "*Custom", 7) &&
+ !strcmp(amain + 7, c->option->keyword) && !strcmp(aoption, "True"))
+ {
+ /*
+ * Use this NonUIOrderDependency...
+ */
+
+ corder = aorder;
+
+ if (!strcmp(asection, "DocumentSetup"))
+ csection = PPD_ORDER_DOCUMENT;
+ else if (!strcmp(asection, "ExitServer"))
+ csection = PPD_ORDER_EXIT;
+ else if (!strcmp(asection, "JCLSetup"))
+ csection = PPD_ORDER_JCL;
+ else if (!strcmp(asection, "PageSetup"))
+ csection = PPD_ORDER_PAGE;
+ else if (!strcmp(asection, "Prolog"))
+ csection = PPD_ORDER_PROLOG;
+ else
+ csection = PPD_ORDER_ANY;
+
+ break;
+ }
+ }
+
+ if (csection == section && corder >= min_order)
+ {
+ collect[count] = c;
+ orders[count] = corder;
+ count ++;
+ }
+ }
+
+ /*
+ * If we have more than 1 marked choice, sort them...
+ */
+
+ if (count > 1)
+ {
+ int i, j; /* Looping vars */
+
+ for (i = 0; i < (count - 1); i ++)
+ for (j = i + 1; j < count; j ++)
+ if (orders[i] > orders[j])
+ {
+ c = collect[i];
+ corder = orders[i];
+ collect[i] = collect[j];
+ orders[i] = orders[j];
+ collect[j] = c;
+ orders[j] = corder;
+ }
+ }
+
+ free(orders);
+
+ DEBUG_printf(("2ppdCollect2: %d marked choices...", count));
+
+ /*
+ * Return the array and number of choices; if 0, free the array since
+ * it isn't needed.
+ */
+
+ if (count > 0)
+ {
+ *choices = collect;
+ return (count);
+ }
+ else
+ {
+ *choices = NULL;
+ free(collect);
+ return (0);
+ }
+}
+
+
+/*
+ * 'ppdEmit()' - Emit code for marked options to a file.
+ */
+
+int /* O - 0 on success, -1 on failure */
+ppdEmit(ppd_file_t *ppd, /* I - PPD file record */
+ FILE *fp, /* I - File to write to */
+ ppd_section_t section) /* I - Section to write */
+{
+ return (ppdEmitAfterOrder(ppd, fp, section, 0, 0.0));
+}
+
+
+/*
+ * 'ppdEmitAfterOrder()' - Emit a subset of the code for marked options to a file.
+ *
+ * When "limit" is non-zero, this function only emits options whose
+ * OrderDependency value is greater than or equal to "min_order".
+ *
+ * When "limit" is zero, this function is identical to ppdEmit().
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 0 on success, -1 on failure */
+ppdEmitAfterOrder(
+ ppd_file_t *ppd, /* I - PPD file record */
+ FILE *fp, /* I - File to write to */
+ ppd_section_t section, /* I - Section to write */
+ int limit, /* I - Non-zero to use min_order */
+ float min_order) /* I - Lowest OrderDependency */
+{
+ char *buffer; /* Option code */
+ int status; /* Return status */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !fp)
+ return (-1);
+
+ /*
+ * Get the string...
+ */
+
+ buffer = ppdEmitString(ppd, section, limit ? min_order : 0.0);
+
+ /*
+ * Write it as needed and return...
+ */
+
+ if (buffer)
+ {
+ status = fputs(buffer, fp) < 0 ? -1 : 0;
+
+ free(buffer);
+ }
+ else
+ status = 0;
+
+ return (status);
+}
+
+
+/*
+ * 'ppdEmitFd()' - Emit code for marked options to a file.
+ */
+
+int /* O - 0 on success, -1 on failure */
+ppdEmitFd(ppd_file_t *ppd, /* I - PPD file record */
+ int fd, /* I - File to write to */
+ ppd_section_t section) /* I - Section to write */
+{
+ char *buffer, /* Option code */
+ *bufptr; /* Pointer into code */
+ size_t buflength; /* Length of option code */
+ ssize_t bytes; /* Bytes written */
+ int status; /* Return status */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || fd < 0)
+ return (-1);
+
+ /*
+ * Get the string...
+ */
+
+ buffer = ppdEmitString(ppd, section, 0.0);
+
+ /*
+ * Write it as needed and return...
+ */
+
+ if (buffer)
+ {
+ buflength = strlen(buffer);
+ bufptr = buffer;
+ bytes = 0;
+
+ while (buflength > 0)
+ {
+#ifdef WIN32
+ if ((bytes = (ssize_t)write(fd, bufptr, (unsigned)buflength)) < 0)
+#else
+ if ((bytes = write(fd, bufptr, buflength)) < 0)
+#endif /* WIN32 */
+ {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+
+ break;
+ }
+
+ buflength -= bytes;
+ bufptr += bytes;
+ }
+
+ status = bytes < 0 ? -1 : 0;
+
+ free(buffer);
+ }
+ else
+ status = 0;
+
+ return (status);
+}
+
+
+/*
+ * 'ppdEmitJCL()' - Emit code for JCL options to a file.
+ */
+
+int /* O - 0 on success, -1 on failure */
+ppdEmitJCL(ppd_file_t *ppd, /* I - PPD file record */
+ FILE *fp, /* I - File to write to */
+ int job_id, /* I - Job ID */
+ const char *user, /* I - Username */
+ const char *title) /* I - Title */
+{
+ char *ptr; /* Pointer into JCL string */
+ char temp[65], /* Local title string */
+ displaymsg[33]; /* Local display string */
+
+
+ /*
+ * Range check the input...
+ */
+
+ if (!ppd || !ppd->jcl_begin || !ppd->jcl_ps)
+ return (0);
+
+ /*
+ * See if the printer supports HP PJL...
+ */
+
+ if (!strncmp(ppd->jcl_begin, "\033%-12345X@", 10))
+ {
+ /*
+ * This printer uses HP PJL commands for output; filter the output
+ * so that we only have a single "@PJL JOB" command in the header...
+ *
+ * To avoid bugs in the PJL implementation of certain vendors' products
+ * (Xerox in particular), we add a dummy "@PJL" command at the beginning
+ * of the PJL commands to initialize PJL processing.
+ */
+
+ ppd_attr_t *charset; /* PJL charset */
+ ppd_attr_t *display; /* PJL display command */
+
+
+ if ((charset = ppdFindAttr(ppd, "cupsPJLCharset", NULL)) != NULL)
+ {
+ if (!charset->value || _cups_strcasecmp(charset->value, "UTF-8"))
+ charset = NULL;
+ }
+
+ if ((display = ppdFindAttr(ppd, "cupsPJLDisplay", NULL)) != NULL)
+ {
+ if (!display->value)
+ display = NULL;
+ }
+
+ fputs("\033%-12345X@PJL\n", fp);
+ for (ptr = ppd->jcl_begin + 9; *ptr;)
+ if (!strncmp(ptr, "@PJL JOB", 8))
+ {
+ /*
+ * Skip job command...
+ */
+
+ for (;*ptr; ptr ++)
+ if (*ptr == '\n')
+ break;
+
+ if (*ptr)
+ ptr ++;
+ }
+ else
+ {
+ /*
+ * Copy line...
+ */
+
+ for (;*ptr; ptr ++)
+ {
+ putc(*ptr, fp);
+ if (*ptr == '\n')
+ break;
+ }
+
+ if (*ptr)
+ ptr ++;
+ }
+
+ /*
+ * Clean up the job title...
+ */
+
+ if ((ptr = strrchr(title, '/')) != NULL)
+ {
+ /*
+ * Only show basename of file path...
+ */
+
+ title = ptr + 1;
+ }
+
+ if (!strncmp(title, "smbprn.", 7))
+ {
+ /*
+ * Skip leading smbprn.######## from Samba jobs...
+ */
+
+ for (title += 7; *title && isdigit(*title & 255); title ++);
+ while (_cups_isspace(*title))
+ title ++;
+
+ if ((ptr = strstr(title, " - ")) != NULL)
+ {
+ /*
+ * Skip application name in "Some Application - Title of job"...
+ */
+
+ title = ptr + 3;
+ }
+ }
+
+ /*
+ * Replace double quotes with single quotes and UTF-8 characters with
+ * question marks so that the title does not cause a PJL syntax error.
+ */
+
+ strlcpy(temp, title, sizeof(temp));
+
+ for (ptr = temp; *ptr; ptr ++)
+ if (*ptr == '\"')
+ *ptr = '\'';
+ else if (!charset && (*ptr & 128))
+ *ptr = '?';
+
+ /*
+ * CUPS STR #3125: Long PJL JOB NAME causes problems with some printers
+ *
+ * Generate the display message, truncating at 32 characters + nul to avoid
+ * issues with some printer's PJL implementations...
+ */
+
+ snprintf(displaymsg, sizeof(displaymsg), "%d %s %s", job_id, user, temp);
+
+ /*
+ * Send PJL JOB and PJL RDYMSG commands before we enter PostScript mode...
+ */
+
+ if (display && strcmp(display->value, "job"))
+ {
+ fprintf(fp, "@PJL JOB NAME = \"%s\"\n", temp);
+
+ if (display && !strcmp(display->value, "rdymsg"))
+ fprintf(fp, "@PJL RDYMSG DISPLAY = \"%s\"\n", displaymsg);
+ }
+ else
+ fprintf(fp, "@PJL JOB NAME = \"%s\" DISPLAY = \"%s\"\n", temp,
+ displaymsg);
+ }
+ else
+ fputs(ppd->jcl_begin, fp);
+
+ ppdEmit(ppd, fp, PPD_ORDER_JCL);
+ fputs(ppd->jcl_ps, fp);
+
+ return (0);
+}
+
+
+/*
+ * 'ppdEmitJCLEnd()' - Emit JCLEnd code to a file.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 0 on success, -1 on failure */
+ppdEmitJCLEnd(ppd_file_t *ppd, /* I - PPD file record */
+ FILE *fp) /* I - File to write to */
+{
+ /*
+ * Range check the input...
+ */
+
+ if (!ppd)
+ return (0);
+
+ if (!ppd->jcl_end)
+ {
+ if (ppd->num_filters == 0)
+ putc(0x04, fp);
+
+ return (0);
+ }
+
+ /*
+ * See if the printer supports HP PJL...
+ */
+
+ if (!strncmp(ppd->jcl_end, "\033%-12345X@", 10))
+ {
+ /*
+ * This printer uses HP PJL commands for output; filter the output
+ * so that we only have a single "@PJL JOB" command in the header...
+ *
+ * To avoid bugs in the PJL implementation of certain vendors' products
+ * (Xerox in particular), we add a dummy "@PJL" command at the beginning
+ * of the PJL commands to initialize PJL processing.
+ */
+
+ fputs("\033%-12345X@PJL\n", fp);
+ fputs("@PJL RDYMSG DISPLAY = \"\"\n", fp);
+ fputs(ppd->jcl_end + 9, fp);
+ }
+ else
+ fputs(ppd->jcl_end, fp);
+
+ return (0);
+}
+
+
+/*
+ * 'ppdEmitString()' - Get a string containing the code for marked options.
+ *
+ * When "min_order" is greater than zero, this function only includes options
+ * whose OrderDependency value is greater than or equal to "min_order".
+ * Otherwise, all options in the specified section are included in the
+ * returned string.
+ *
+ * The return string is allocated on the heap and should be freed using
+ * @code free@ when you are done with it.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+char * /* O - String containing option code or @code NULL@ if there is no option code */
+ppdEmitString(ppd_file_t *ppd, /* I - PPD file record */
+ ppd_section_t section, /* I - Section to write */
+ float min_order) /* I - Lowest OrderDependency */
+{
+ int i, j, /* Looping vars */
+ count; /* Number of choices */
+ ppd_choice_t **choices; /* Choices */
+ ppd_size_t *size; /* Custom page size */
+ ppd_coption_t *coption; /* Custom option */
+ ppd_cparam_t *cparam; /* Custom parameter */
+ size_t bufsize; /* Size of string buffer needed */
+ char *buffer, /* String buffer */
+ *bufptr, /* Pointer into buffer */
+ *bufend; /* End of buffer */
+ struct lconv *loc; /* Locale data */
+
+
+ DEBUG_printf(("ppdEmitString(ppd=%p, section=%d, min_order=%f)",
+ ppd, section, min_order));
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd)
+ return (NULL);
+
+ /*
+ * Use PageSize or PageRegion as required...
+ */
+
+ ppd_handle_media(ppd);
+
+ /*
+ * Collect the options we need to emit...
+ */
+
+ if ((count = ppdCollect2(ppd, section, min_order, &choices)) == 0)
+ return (NULL);
+
+ /*
+ * Count the number of bytes that are required to hold all of the
+ * option code...
+ */
+
+ for (i = 0, bufsize = 1; i < count; i ++)
+ {
+ if (section == PPD_ORDER_JCL)
+ {
+ if (!_cups_strcasecmp(choices[i]->choice, "Custom") &&
+ (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
+ != NULL)
+ {
+ /*
+ * Add space to account for custom parameter substitution...
+ */
+
+ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+ cparam;
+ cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
+ {
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_CURVE :
+ case PPD_CUSTOM_INVCURVE :
+ case PPD_CUSTOM_POINTS :
+ case PPD_CUSTOM_REAL :
+ case PPD_CUSTOM_INT :
+ bufsize += 10;
+ break;
+
+ case PPD_CUSTOM_PASSCODE :
+ case PPD_CUSTOM_PASSWORD :
+ case PPD_CUSTOM_STRING :
+ if (cparam->current.custom_string)
+ bufsize += strlen(cparam->current.custom_string);
+ break;
+ }
+ }
+ }
+ }
+ else if (section != PPD_ORDER_EXIT)
+ {
+ bufsize += 3; /* [{\n */
+
+ if ((!_cups_strcasecmp(choices[i]->option->keyword, "PageSize") ||
+ !_cups_strcasecmp(choices[i]->option->keyword, "PageRegion")) &&
+ !_cups_strcasecmp(choices[i]->choice, "Custom"))
+ {
+ DEBUG_puts("2ppdEmitString: Custom size set!");
+
+ bufsize += 37; /* %%BeginFeature: *CustomPageSize True\n */
+ bufsize += 50; /* Five 9-digit numbers + newline */
+ }
+ else if (!_cups_strcasecmp(choices[i]->choice, "Custom") &&
+ (coption = ppdFindCustomOption(ppd,
+ choices[i]->option->keyword))
+ != NULL)
+ {
+ bufsize += 23 + strlen(choices[i]->option->keyword) + 6;
+ /* %%BeginFeature: *Customkeyword True\n */
+
+
+ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+ cparam;
+ cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
+ {
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_CURVE :
+ case PPD_CUSTOM_INVCURVE :
+ case PPD_CUSTOM_POINTS :
+ case PPD_CUSTOM_REAL :
+ case PPD_CUSTOM_INT :
+ bufsize += 10;
+ break;
+
+ case PPD_CUSTOM_PASSCODE :
+ case PPD_CUSTOM_PASSWORD :
+ case PPD_CUSTOM_STRING :
+ bufsize += 3;
+ if (cparam->current.custom_string)
+ bufsize += 4 * strlen(cparam->current.custom_string);
+ break;
+ }
+ }
+ }
+ else
+ bufsize += 17 + strlen(choices[i]->option->keyword) + 1 +
+ strlen(choices[i]->choice) + 1;
+ /* %%BeginFeature: *keyword choice\n */
+
+ bufsize += 13; /* %%EndFeature\n */
+ bufsize += 22; /* } stopped cleartomark\n */
+ }
+
+ if (choices[i]->code)
+ bufsize += strlen(choices[i]->code) + 1;
+ else
+ bufsize += strlen(ppd_custom_code);
+ }
+
+ /*
+ * Allocate memory...
+ */
+
+ DEBUG_printf(("2ppdEmitString: Allocating %d bytes for string...",
+ (int)bufsize));
+
+ if ((buffer = calloc(1, bufsize)) == NULL)
+ {
+ free(choices);
+ return (NULL);
+ }
+
+ bufend = buffer + bufsize - 1;
+ loc = localeconv();
+
+ /*
+ * Copy the option code to the buffer...
+ */
+
+ for (i = 0, bufptr = buffer; i < count; i ++, bufptr += strlen(bufptr))
+ if (section == PPD_ORDER_JCL)
+ {
+ if (!_cups_strcasecmp(choices[i]->choice, "Custom") &&
+ choices[i]->code &&
+ (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
+ != NULL)
+ {
+ /*
+ * Handle substitutions in custom JCL options...
+ */
+
+ char *cptr; /* Pointer into code */
+ int pnum; /* Parameter number */
+
+
+ for (cptr = choices[i]->code; *cptr && bufptr < bufend;)
+ {
+ if (*cptr == '\\')
+ {
+ cptr ++;
+
+ if (isdigit(*cptr & 255))
+ {
+ /*
+ * Substitute parameter...
+ */
+
+ pnum = *cptr++ - '0';
+ while (isdigit(*cptr & 255))
+ pnum = pnum * 10 + *cptr++ - '0';
+
+ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+ cparam;
+ cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
+ if (cparam->order == pnum)
+ break;
+
+ if (cparam)
+ {
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_CURVE :
+ case PPD_CUSTOM_INVCURVE :
+ case PPD_CUSTOM_POINTS :
+ case PPD_CUSTOM_REAL :
+ bufptr = _cupsStrFormatd(bufptr, bufend,
+ cparam->current.custom_real,
+ loc);
+ break;
+
+ case PPD_CUSTOM_INT :
+ snprintf(bufptr, bufend - bufptr, "%d",
+ cparam->current.custom_int);
+ bufptr += strlen(bufptr);
+ break;
+
+ case PPD_CUSTOM_PASSCODE :
+ case PPD_CUSTOM_PASSWORD :
+ case PPD_CUSTOM_STRING :
+ if (cparam->current.custom_string)
+ {
+ strlcpy(bufptr, cparam->current.custom_string,
+ bufend - bufptr);
+ bufptr += strlen(bufptr);
+ }
+ break;
+ }
+ }
+ }
+ else if (*cptr)
+ *bufptr++ = *cptr++;
+ }
+ else
+ *bufptr++ = *cptr++;
+ }
+ }
+ else
+ {
+ /*
+ * Otherwise just copy the option code directly...
+ */
+
+ strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1);
+ bufptr += strlen(bufptr);
+ }
+ }
+ else if (section != PPD_ORDER_EXIT)
+ {
+ /*
+ * Add wrapper commands to prevent printer errors for unsupported
+ * options...
+ */
+
+ strlcpy(bufptr, "[{\n", bufend - bufptr + 1);
+ bufptr += 3;
+
+ /*
+ * Send DSC comments with option...
+ */
+
+ DEBUG_printf(("2ppdEmitString: Adding code for %s=%s...",
+ choices[i]->option->keyword, choices[i]->choice));
+
+ if ((!_cups_strcasecmp(choices[i]->option->keyword, "PageSize") ||
+ !_cups_strcasecmp(choices[i]->option->keyword, "PageRegion")) &&
+ !_cups_strcasecmp(choices[i]->choice, "Custom"))
+ {
+ /*
+ * Variable size; write out standard size options, using the
+ * parameter positions defined in the PPD file...
+ */
+
+ ppd_attr_t *attr; /* PPD attribute */
+ int pos, /* Position of custom value */
+ orientation; /* Orientation to use */
+ float values[5]; /* Values for custom command */
+
+
+ strlcpy(bufptr, "%%BeginFeature: *CustomPageSize True\n",
+ bufend - bufptr + 1);
+ bufptr += 37;
+
+ size = ppdPageSize(ppd, "Custom");
+
+ memset(values, 0, sizeof(values));
+
+ if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL)
+ {
+ pos = atoi(attr->value) - 1;
+
+ if (pos < 0 || pos > 4)
+ pos = 0;
+ }
+ else
+ pos = 0;
+
+ values[pos] = size->width;
+
+ if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL)
+ {
+ pos = atoi(attr->value) - 1;
+
+ if (pos < 0 || pos > 4)
+ pos = 1;
+ }
+ else
+ pos = 1;
+
+ values[pos] = size->length;
+
+ /*
+ * According to the Adobe PPD specification, an orientation of 1
+ * will produce a print that comes out upside-down with the X
+ * axis perpendicular to the direction of feed, which is exactly
+ * what we want to be consistent with non-PS printers.
+ *
+ * We could also use an orientation of 3 to produce output that
+ * comes out rightside-up (this is the default for many large format
+ * printer PPDs), however for consistency we will stick with the
+ * value 1.
+ *
+ * If we wanted to get fancy, we could use orientations of 0 or
+ * 2 and swap the width and length, however we don't want to get
+ * fancy, we just want it to work consistently.
+ *
+ * The orientation value is range limited by the Orientation
+ * parameter definition, so certain non-PS printer drivers that
+ * only support an Orientation of 0 will get the value 0 as
+ * expected.
+ */
+
+ orientation = 1;
+
+ if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize",
+ "Orientation")) != NULL)
+ {
+ int min_orient, max_orient; /* Minimum and maximum orientations */
+
+
+ if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient,
+ &max_orient) != 3)
+ pos = 4;
+ else
+ {
+ pos --;
+
+ if (pos < 0 || pos > 4)
+ pos = 4;
+
+ if (orientation > max_orient)
+ orientation = max_orient;
+ else if (orientation < min_orient)
+ orientation = min_orient;
+ }
+ }
+ else
+ pos = 4;
+
+ values[pos] = (float)orientation;
+
+ for (pos = 0; pos < 5; pos ++)
+ {
+ bufptr = _cupsStrFormatd(bufptr, bufend, values[pos], loc);
+ *bufptr++ = '\n';
+ }
+
+ if (!choices[i]->code)
+ {
+ /*
+ * This can happen with certain buggy PPD files that don't include
+ * a CustomPageSize command sequence... We just use a generic
+ * Level 2 command sequence...
+ */
+
+ strlcpy(bufptr, ppd_custom_code, bufend - bufptr + 1);
+ bufptr += strlen(bufptr);
+ }
+ }
+ else if (!_cups_strcasecmp(choices[i]->choice, "Custom") &&
+ (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
+ != NULL)
+ {
+ /*
+ * Custom option...
+ */
+
+ const char *s; /* Pointer into string value */
+ cups_array_t *params; /* Parameters in the correct output order */
+
+
+ params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);
+
+ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+ cparam;
+ cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
+ cupsArrayAdd(params, cparam);
+
+ snprintf(bufptr, bufend - bufptr + 1,
+ "%%%%BeginFeature: *Custom%s True\n", coption->keyword);
+ bufptr += strlen(bufptr);
+
+ for (cparam = (ppd_cparam_t *)cupsArrayFirst(params);
+ cparam;
+ cparam = (ppd_cparam_t *)cupsArrayNext(params))
+ {
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_CURVE :
+ case PPD_CUSTOM_INVCURVE :
+ case PPD_CUSTOM_POINTS :
+ case PPD_CUSTOM_REAL :
+ bufptr = _cupsStrFormatd(bufptr, bufend,
+ cparam->current.custom_real, loc);
+ *bufptr++ = '\n';
+ break;
+
+ case PPD_CUSTOM_INT :
+ snprintf(bufptr, bufend - bufptr + 1, "%d\n",
+ cparam->current.custom_int);
+ bufptr += strlen(bufptr);
+ break;
+
+ case PPD_CUSTOM_PASSCODE :
+ case PPD_CUSTOM_PASSWORD :
+ case PPD_CUSTOM_STRING :
+ *bufptr++ = '(';
+
+ if (cparam->current.custom_string)
+ {
+ for (s = cparam->current.custom_string; *s; s ++)
+ {
+ if (*s < ' ' || *s == '(' || *s == ')' || *s >= 127)
+ {
+ snprintf(bufptr, bufend - bufptr + 1, "\\%03o", *s & 255);
+ bufptr += strlen(bufptr);
+ }
+ else
+ *bufptr++ = *s;
+ }
+ }
+
+ *bufptr++ = ')';
+ *bufptr++ = '\n';
+ break;
+ }
+ }
+
+ cupsArrayDelete(params);
+ }
+ else
+ {
+ snprintf(bufptr, bufend - bufptr + 1, "%%%%BeginFeature: *%s %s\n",
+ choices[i]->option->keyword, choices[i]->choice);
+ bufptr += strlen(bufptr);
+ }
+
+ if (choices[i]->code && choices[i]->code[0])
+ {
+ j = (int)strlen(choices[i]->code);
+ memcpy(bufptr, choices[i]->code, j);
+ bufptr += j;
+
+ if (choices[i]->code[j - 1] != '\n')
+ *bufptr++ = '\n';
+ }
+
+ strlcpy(bufptr, "%%EndFeature\n"
+ "} stopped cleartomark\n", bufend - bufptr + 1);
+ bufptr += strlen(bufptr);
+
+ DEBUG_printf(("2ppdEmitString: Offset in string is %d...",
+ (int)(bufptr - buffer)));
+ }
+ else
+ {
+ strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1);
+ bufptr += strlen(bufptr);
+ }
+
+ /*
+ * Nul-terminate, free, and return...
+ */
+
+ *bufptr = '\0';
+
+ free(choices);
+
+ return (buffer);
+}
+
+
+/*
+ * 'ppd_compare_cparams()' - Compare the order of two custom parameters.
+ */
+
+static int /* O - Result of comparison */
+ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */
+ ppd_cparam_t *b) /* I - Second parameter */
+{
+ return (a->order - b->order);
+}
+
+
+/*
+ * 'ppd_handle_media()' - Handle media selection...
+ */
+
+static void
+ppd_handle_media(ppd_file_t *ppd) /* I - PPD file */
+{
+ ppd_choice_t *manual_feed, /* ManualFeed choice, if any */
+ *input_slot; /* InputSlot choice, if any */
+ ppd_size_t *size; /* Current media size */
+ ppd_attr_t *rpr; /* RequiresPageRegion value */
+
+
+ /*
+ * This function determines what page size code to use, if any, for the
+ * current media size, InputSlot, and ManualFeed selections.
+ *
+ * We use the PageSize code if:
+ *
+ * 1. A custom media size is selected.
+ * 2. ManualFeed and InputSlot are not selected (or do not exist).
+ * 3. ManualFeed is selected but is False and InputSlot is not selected or
+ * the selection has no code - the latter check done to support "auto" or
+ * "printer default" InputSlot options.
+ *
+ * We use the PageRegion code if:
+ *
+ * 4. RequiresPageRegion does not exist and the PPD contains cupsFilter
+ * keywords, indicating this is a CUPS-based driver.
+ * 5. RequiresPageRegion exists for the selected InputSlot (or "All" for any
+ * InputSlot or ManualFeed selection) and is True.
+ *
+ * If none of the 5 conditions are true, no page size code is used and we
+ * unmark any existing PageSize or PageRegion choices.
+ */
+
+ if ((size = ppdPageSize(ppd, NULL)) == NULL)
+ return;
+
+ manual_feed = ppdFindMarkedChoice(ppd, "ManualFeed");
+ input_slot = ppdFindMarkedChoice(ppd, "InputSlot");
+
+ if (input_slot != NULL)
+ rpr = ppdFindAttr(ppd, "RequiresPageRegion", input_slot->choice);
+ else
+ rpr = NULL;
+
+ if (!rpr)
+ rpr = ppdFindAttr(ppd, "RequiresPageRegion", "All");
+
+ if (!_cups_strcasecmp(size->name, "Custom") ||
+ (!manual_feed && !input_slot) ||
+ (manual_feed && !_cups_strcasecmp(manual_feed->choice, "False") &&
+ (!input_slot || (input_slot->code && !input_slot->code[0]))) ||
+ (!rpr && ppd->num_filters > 0))
+ {
+ /*
+ * Use PageSize code...
+ */
+
+ ppdMarkOption(ppd, "PageSize", size->name);
+ }
+ else if (rpr && rpr->value && !_cups_strcasecmp(rpr->value, "True"))
+ {
+ /*
+ * Use PageRegion code...
+ */
+
+ ppdMarkOption(ppd, "PageRegion", size->name);
+ }
+ else
+ {
+ /*
+ * Do not use PageSize or PageRegion code...
+ */
+
+ ppd_choice_t *page; /* PageSize/Region choice, if any */
+
+ if ((page = ppdFindMarkedChoice(ppd, "PageSize")) != NULL)
+ {
+ /*
+ * Unmark PageSize...
+ */
+
+ page->marked = 0;
+ cupsArrayRemove(ppd->marked, page);
+ }
+
+ if ((page = ppdFindMarkedChoice(ppd, "PageRegion")) != NULL)
+ {
+ /*
+ * Unmark PageRegion...
+ */
+
+ page->marked = 0;
+ cupsArrayRemove(ppd->marked, page);
+ }
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/encode.c b/cups/encode.c
new file mode 100644
index 000000000..51acfd6e6
--- /dev/null
+++ b/cups/encode.c
@@ -0,0 +1,636 @@
+/*
+ * "$Id$"
+ *
+ * Option encoding routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsEncodeOptions() - Encode printer options into IPP attributes.
+ * cupsEncodeOptions2() - Encode printer options into IPP attributes for
+ * a group.
+ * _ippFindOption() - Find the attribute information for an option.
+ * compare_ipp_options() - Compare two IPP options.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+
+
+/*
+ * Local list of option names and the value tags they should use...
+ *
+ * **** THIS LIST MUST BE SORTED ****
+ */
+
+static const _ipp_option_t ipp_options[] =
+{
+ { 1, "auth-info", IPP_TAG_TEXT, IPP_TAG_JOB },
+ { 1, "auth-info-required", IPP_TAG_KEYWORD, IPP_TAG_PRINTER },
+ { 0, "blackplot", IPP_TAG_BOOLEAN, IPP_TAG_JOB },
+ { 0, "blackplot-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER },
+ { 0, "brightness", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "brightness-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "columns", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "columns-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "compression", IPP_TAG_KEYWORD, IPP_TAG_OPERATION },
+ { 0, "copies", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "copies-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "device-uri", IPP_TAG_URI, IPP_TAG_PRINTER },
+ { 0, "document-format", IPP_TAG_MIMETYPE, IPP_TAG_OPERATION },
+ { 0, "document-format-default", IPP_TAG_MIMETYPE, IPP_TAG_PRINTER },
+ { 1, "exclude-schemes", IPP_TAG_NAME, IPP_TAG_OPERATION },
+ { 1, "finishings", IPP_TAG_ENUM, IPP_TAG_JOB },
+ { 1, "finishings-default", IPP_TAG_ENUM, IPP_TAG_PRINTER },
+ { 0, "fit-to-page", IPP_TAG_BOOLEAN, IPP_TAG_JOB },
+ { 0, "fit-to-page-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER },
+ { 0, "fitplot", IPP_TAG_BOOLEAN, IPP_TAG_JOB },
+ { 0, "fitplot-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER },
+ { 0, "gamma", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "gamma-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "hue", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "hue-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 1, "include-schemes", IPP_TAG_NAME, IPP_TAG_OPERATION },
+ { 0, "job-impressions", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "job-k-limit", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "job-page-limit", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "job-priority", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "job-quota-period", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 1, "job-sheets", IPP_TAG_NAME, IPP_TAG_JOB },
+ { 1, "job-sheets-default", IPP_TAG_NAME, IPP_TAG_PRINTER },
+ { 0, "job-uuid", IPP_TAG_URI, IPP_TAG_JOB },
+ { 0, "landscape", IPP_TAG_BOOLEAN, IPP_TAG_JOB },
+ { 1, "marker-change-time", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 1, "marker-colors", IPP_TAG_NAME, IPP_TAG_PRINTER },
+ { 1, "marker-high-levels", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 1, "marker-levels", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 1, "marker-low-levels", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "marker-message", IPP_TAG_TEXT, IPP_TAG_PRINTER },
+ { 1, "marker-names", IPP_TAG_NAME, IPP_TAG_PRINTER },
+ { 1, "marker-types", IPP_TAG_KEYWORD, IPP_TAG_PRINTER },
+ { 1, "media", IPP_TAG_KEYWORD, IPP_TAG_JOB },
+ { 0, "media-col", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB },
+ { 0, "media-col-default", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_PRINTER },
+ { 0, "media-color", IPP_TAG_KEYWORD, IPP_TAG_JOB },
+ { 1, "media-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER },
+ { 0, "media-key", IPP_TAG_KEYWORD, IPP_TAG_JOB },
+ { 0, "media-size", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB },
+ { 0, "media-type", IPP_TAG_KEYWORD, IPP_TAG_JOB },
+ { 0, "mirror", IPP_TAG_BOOLEAN, IPP_TAG_JOB },
+ { 0, "mirror-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER },
+ { 0, "natural-scaling", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "natural-scaling-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "notify-charset", IPP_TAG_CHARSET, IPP_TAG_SUBSCRIPTION },
+ { 1, "notify-events", IPP_TAG_KEYWORD, IPP_TAG_SUBSCRIPTION },
+ { 1, "notify-events-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER },
+ { 0, "notify-lease-duration", IPP_TAG_INTEGER, IPP_TAG_SUBSCRIPTION },
+ { 0, "notify-lease-duration-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "notify-natural-language", IPP_TAG_LANGUAGE, IPP_TAG_SUBSCRIPTION },
+ { 0, "notify-pull-method", IPP_TAG_KEYWORD, IPP_TAG_SUBSCRIPTION },
+ { 0, "notify-recipient-uri", IPP_TAG_URI, IPP_TAG_SUBSCRIPTION },
+ { 0, "notify-time-interval", IPP_TAG_INTEGER, IPP_TAG_SUBSCRIPTION },
+ { 0, "notify-user-data", IPP_TAG_STRING, IPP_TAG_SUBSCRIPTION },
+ { 0, "number-up", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "number-up-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "orientation-requested", IPP_TAG_ENUM, IPP_TAG_JOB },
+ { 0, "orientation-requested-default", IPP_TAG_ENUM, IPP_TAG_PRINTER },
+ { 0, "page-bottom", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "page-bottom-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "page-left", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "page-left-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 1, "page-ranges", IPP_TAG_RANGE, IPP_TAG_JOB },
+ { 1, "page-ranges-default", IPP_TAG_RANGE, IPP_TAG_PRINTER },
+ { 0, "page-right", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "page-right-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "page-top", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "page-top-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "penwidth", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "penwidth-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "port-monitor", IPP_TAG_NAME, IPP_TAG_PRINTER },
+ { 0, "ppd-name", IPP_TAG_NAME, IPP_TAG_PRINTER },
+ { 0, "ppi", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "ppi-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "prettyprint", IPP_TAG_BOOLEAN, IPP_TAG_JOB },
+ { 0, "prettyprint-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER },
+ { 0, "print-quality", IPP_TAG_ENUM, IPP_TAG_JOB },
+ { 0, "print-quality-default", IPP_TAG_ENUM, IPP_TAG_PRINTER },
+ { 1, "printer-commands", IPP_TAG_KEYWORD, IPP_TAG_PRINTER },
+ { 0, "printer-error-policy", IPP_TAG_NAME, IPP_TAG_PRINTER },
+ { 0, "printer-info", IPP_TAG_TEXT, IPP_TAG_PRINTER },
+ { 0, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER },
+ { 0, "printer-is-shared", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER },
+ { 0, "printer-location", IPP_TAG_TEXT, IPP_TAG_PRINTER },
+ { 0, "printer-make-and-model", IPP_TAG_TEXT, IPP_TAG_PRINTER },
+ { 0, "printer-more-info", IPP_TAG_URI, IPP_TAG_PRINTER },
+ { 0, "printer-op-policy", IPP_TAG_NAME, IPP_TAG_PRINTER },
+ { 0, "printer-resolution", IPP_TAG_RESOLUTION, IPP_TAG_JOB },
+ { 0, "printer-state", IPP_TAG_ENUM, IPP_TAG_PRINTER },
+ { 0, "printer-state-change-time", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 1, "printer-state-reasons", IPP_TAG_KEYWORD, IPP_TAG_PRINTER },
+ { 0, "printer-type", IPP_TAG_ENUM, IPP_TAG_PRINTER },
+ { 0, "printer-uri", IPP_TAG_URI, IPP_TAG_OPERATION },
+ { 1, "printer-uri-supported", IPP_TAG_URI, IPP_TAG_PRINTER },
+ { 0, "queued-job-count", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "raw", IPP_TAG_MIMETYPE, IPP_TAG_OPERATION },
+ { 1, "requested-attributes", IPP_TAG_NAME, IPP_TAG_OPERATION },
+ { 1, "requesting-user-name-allowed", IPP_TAG_NAME, IPP_TAG_PRINTER },
+ { 1, "requesting-user-name-denied", IPP_TAG_NAME, IPP_TAG_PRINTER },
+ { 0, "resolution", IPP_TAG_RESOLUTION, IPP_TAG_JOB },
+ { 0, "resolution-default", IPP_TAG_RESOLUTION, IPP_TAG_PRINTER },
+ { 0, "saturation", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "saturation-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "scaling", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "scaling-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
+ { 0, "sides", IPP_TAG_KEYWORD, IPP_TAG_JOB },
+ { 0, "sides-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER },
+ { 0, "wrap", IPP_TAG_BOOLEAN, IPP_TAG_JOB },
+ { 0, "wrap-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER },
+ { 0, "x-dimension", IPP_TAG_INTEGER, IPP_TAG_JOB },
+ { 0, "y-dimension", IPP_TAG_INTEGER, IPP_TAG_JOB }
+};
+
+
+/*
+ * Local functions...
+ */
+
+static int compare_ipp_options(_ipp_option_t *a, _ipp_option_t *b);
+
+
+/*
+ * 'cupsEncodeOptions()' - Encode printer options into IPP attributes.
+ *
+ * This function adds operation, job, and then subscription attributes,
+ * in that order. Use the cupsEncodeOptions2() function to add attributes
+ * for a single group.
+ */
+
+void
+cupsEncodeOptions(ipp_t *ipp, /* I - Request to add to */
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ DEBUG_printf(("cupsEncodeOptions(%p, %d, %p)", ipp, num_options, options));
+
+ /*
+ * Add the options in the proper groups & order...
+ */
+
+ cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_OPERATION);
+ cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_JOB);
+ cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_SUBSCRIPTION);
+}
+
+
+/*
+ * 'cupsEncodeOptions2()' - Encode printer options into IPP attributes for a group.
+ *
+ * This function only adds attributes for a single group. Call this
+ * function multiple times for each group, or use cupsEncodeOptions()
+ * to add the standard groups.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void
+cupsEncodeOptions2(
+ ipp_t *ipp, /* I - Request to add to */
+ int num_options, /* I - Number of options */
+ cups_option_t *options, /* I - Options */
+ ipp_tag_t group_tag) /* I - Group to encode */
+{
+ int i, j; /* Looping vars */
+ int count; /* Number of values */
+ char *s, /* Pointer into option value */
+ *val, /* Pointer to option value */
+ *copy, /* Copy of option value */
+ *sep, /* Option separator */
+ quote; /* Quote character */
+ ipp_attribute_t *attr; /* IPP attribute */
+ ipp_tag_t value_tag; /* IPP value tag */
+ cups_option_t *option; /* Current option */
+ ipp_t *collection; /* Collection value */
+ int num_cols; /* Number of collection values */
+ cups_option_t *cols; /* Collection values */
+
+
+ DEBUG_printf(("cupsEncodeOptions2(ipp=%p, num_options=%d, options=%p, "
+ "group_tag=%x)", ipp, num_options, options, group_tag));
+
+ /*
+ * Range check input...
+ */
+
+ if (!ipp || num_options < 1 || !options)
+ return;
+
+ /*
+ * Do special handling for the document-format/raw options...
+ */
+
+ if (group_tag == IPP_TAG_OPERATION)
+ {
+ /*
+ * Handle the document format stuff first...
+ */
+
+ if ((val = (char *)cupsGetOption("document-format", num_options, options)) != NULL)
+ ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
+ NULL, val);
+ else if (cupsGetOption("raw", num_options, options))
+ ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
+ NULL, "application/vnd.cups-raw");
+ else
+ ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
+ NULL, "application/octet-stream");
+ }
+
+ /*
+ * Then loop through the options...
+ */
+
+ for (i = num_options, option = options; i > 0; i --, option ++)
+ {
+ _ipp_option_t *match; /* Matching attribute */
+
+
+ /*
+ * Skip document format options that are handled above...
+ */
+
+ if (!_cups_strcasecmp(option->name, "raw") ||
+ !_cups_strcasecmp(option->name, "document-format") ||
+ !option->name[0])
+ continue;
+
+ /*
+ * Figure out the proper value and group tags for this option...
+ */
+
+ if ((match = _ippFindOption(option->name)) != NULL)
+ {
+ if (match->group_tag != group_tag)
+ continue;
+
+ value_tag = match->value_tag;
+ }
+ else
+ {
+ int namelen; /* Length of name */
+
+
+ namelen = (int)strlen(option->name);
+
+ if (namelen < 9 || strcmp(option->name + namelen - 8, "-default"))
+ {
+ if (group_tag != IPP_TAG_JOB)
+ continue;
+ }
+ else if (group_tag != IPP_TAG_PRINTER)
+ continue;
+
+ if (!_cups_strcasecmp(option->value, "true") ||
+ !_cups_strcasecmp(option->value, "false"))
+ value_tag = IPP_TAG_BOOLEAN;
+ else
+ value_tag = IPP_TAG_NAME;
+ }
+
+ /*
+ * Count the number of values...
+ */
+
+ if (match && match->multivalue)
+ {
+ for (count = 1, sep = option->value, quote = 0; *sep; sep ++)
+ {
+ if (*sep == quote)
+ quote = 0;
+ else if (!quote && (*sep == '\'' || *sep == '\"'))
+ {
+ /*
+ * Skip quoted option value...
+ */
+
+ quote = *sep++;
+ }
+ else if (*sep == ',' && !quote)
+ count ++;
+ else if (*sep == '\\' && sep[1])
+ sep ++;
+ }
+ }
+ else
+ count = 1;
+
+ DEBUG_printf(("2cupsEncodeOptions2: option=\"%s\", count=%d",
+ option->name, count));
+
+ /*
+ * Allocate memory for the attribute values...
+ */
+
+ if ((attr = _ippAddAttr(ipp, count)) == NULL)
+ {
+ /*
+ * Ran out of memory!
+ */
+
+ DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for attributes!");
+ return;
+ }
+
+ /*
+ * Now figure out what type of value we have...
+ */
+
+ attr->group_tag = group_tag;
+ attr->value_tag = value_tag;
+
+ /*
+ * Copy the name over...
+ */
+
+ attr->name = _cupsStrAlloc(option->name);
+
+ if (count > 1)
+ {
+ /*
+ * Make a copy of the value we can fiddle with...
+ */
+
+ if ((copy = strdup(option->value)) == NULL)
+ {
+ /*
+ * Ran out of memory!
+ */
+
+ DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for value copy!");
+ ippDeleteAttribute(ipp, attr);
+ return;
+ }
+
+ val = copy;
+ }
+ else
+ {
+ /*
+ * Since we have a single value, use the value directly...
+ */
+
+ val = option->value;
+ copy = NULL;
+ }
+
+ /*
+ * Scan the value string for values...
+ */
+
+ for (j = 0, sep = val; j < count; val = sep, j ++)
+ {
+ /*
+ * Find the end of this value and mark it if needed...
+ */
+
+ if (count > 1)
+ {
+ for (quote = 0; *sep; sep ++)
+ {
+ if (*sep == quote)
+ {
+ /*
+ * Finish quoted value...
+ */
+
+ quote = 0;
+ }
+ else if (!quote && (*sep == '\'' || *sep == '\"'))
+ {
+ /*
+ * Handle quoted option value...
+ */
+
+ quote = *sep;
+ }
+ else if (*sep == ',' && count > 1)
+ break;
+ else if (*sep == '\\' && sep[1])
+ {
+ /*
+ * Skip quoted character...
+ */
+
+ sep ++;
+ }
+ }
+
+ if (*sep == ',')
+ *sep++ = '\0';
+ }
+
+ /*
+ * Copy the option value(s) over as needed by the type...
+ */
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ /*
+ * Integer/enumeration value...
+ */
+
+ attr->values[j].integer = strtol(val, &s, 10);
+
+ DEBUG_printf(("2cupsEncodeOptions2: Added integer option value "
+ "%d...", attr->values[j].integer));
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ if (!_cups_strcasecmp(val, "true") ||
+ !_cups_strcasecmp(val, "on") ||
+ !_cups_strcasecmp(val, "yes"))
+ {
+ /*
+ * Boolean value - true...
+ */
+
+ attr->values[j].boolean = 1;
+
+ DEBUG_puts("2cupsEncodeOptions2: Added boolean true value...");
+ }
+ else
+ {
+ /*
+ * Boolean value - false...
+ */
+
+ attr->values[j].boolean = 0;
+
+ DEBUG_puts("2cupsEncodeOptions2: Added boolean false value...");
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ /*
+ * Range...
+ */
+
+ if (*val == '-')
+ {
+ attr->values[j].range.lower = 1;
+ s = val;
+ }
+ else
+ attr->values[j].range.lower = strtol(val, &s, 10);
+
+ if (*s == '-')
+ {
+ if (s[1])
+ attr->values[j].range.upper = strtol(s + 1, NULL, 10);
+ else
+ attr->values[j].range.upper = 2147483647;
+ }
+ else
+ attr->values[j].range.upper = attr->values[j].range.lower;
+
+ DEBUG_printf(("2cupsEncodeOptions2: Added range option value "
+ "%d-%d...", attr->values[j].range.lower,
+ attr->values[j].range.upper));
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ /*
+ * Resolution...
+ */
+
+ attr->values[j].resolution.xres = strtol(val, &s, 10);
+
+ if (*s == 'x')
+ attr->values[j].resolution.yres = strtol(s + 1, &s, 10);
+ else
+ attr->values[j].resolution.yres = attr->values[j].resolution.xres;
+
+ if (!_cups_strcasecmp(s, "dpc"))
+ attr->values[j].resolution.units = IPP_RES_PER_CM;
+ else
+ attr->values[j].resolution.units = IPP_RES_PER_INCH;
+
+ DEBUG_printf(("2cupsEncodeOptions2: Added resolution option value "
+ "%s...", val));
+ break;
+
+ case IPP_TAG_STRING :
+ /*
+ * octet-string
+ */
+
+ attr->values[j].unknown.length = (int)strlen(val);
+ attr->values[j].unknown.data = strdup(val);
+
+ DEBUG_printf(("2cupsEncodeOptions2: Added octet-string value "
+ "\"%s\"...", (char *)attr->values[j].unknown.data));
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ /*
+ * Collection value
+ */
+
+ num_cols = cupsParseOptions(val, 0, &cols);
+ if ((collection = ippNew()) == NULL)
+ {
+ cupsFreeOptions(num_cols, cols);
+
+ if (copy)
+ free(copy);
+
+ ippDeleteAttribute(ipp, attr);
+ return;
+ }
+
+ attr->values[j].collection = collection;
+ cupsEncodeOptions2(collection, num_cols, cols, IPP_TAG_JOB);
+ cupsFreeOptions(num_cols, cols);
+ break;
+
+ default :
+ if ((attr->values[j].string.text = _cupsStrAlloc(val)) == NULL)
+ {
+ /*
+ * Ran out of memory!
+ */
+
+ DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for string!");
+
+ if (copy)
+ free(copy);
+
+ ippDeleteAttribute(ipp, attr);
+ return;
+ }
+
+ DEBUG_printf(("2cupsEncodeOptions2: Added string value \"%s\"...",
+ val));
+ break;
+ }
+ }
+
+ if (copy)
+ free(copy);
+ }
+}
+
+
+/*
+ * '_ippFindOption()' - Find the attribute information for an option.
+ */
+
+_ipp_option_t * /* O - Attribute information */
+_ippFindOption(const char *name) /* I - Option/attribute name */
+{
+ _ipp_option_t key; /* Search key */
+
+
+ /*
+ * Lookup the proper value and group tags for this option...
+ */
+
+ key.name = name;
+
+ return ((_ipp_option_t *)bsearch(&key, ipp_options,
+ sizeof(ipp_options) / sizeof(ipp_options[0]),
+ sizeof(ipp_options[0]),
+ (int (*)(const void *, const void *))
+ compare_ipp_options));
+}
+
+
+/*
+ * 'compare_ipp_options()' - Compare two IPP options.
+ */
+
+static int /* O - Result of comparison */
+compare_ipp_options(_ipp_option_t *a, /* I - First option */
+ _ipp_option_t *b) /* I - Second option */
+{
+ return (strcmp(a->name, b->name));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/file-private.h b/cups/file-private.h
new file mode 100644
index 000000000..60a250148
--- /dev/null
+++ b/cups/file-private.h
@@ -0,0 +1,137 @@
+/*
+ * "$Id$"
+ *
+ * Private file definitions for CUPS.
+ *
+ * Since stdio files max out at 256 files on many systems, we have to
+ * write similar functions without this limit. At the same time, using
+ * our own file functions allows us to provide transparent support of
+ * gzip'd print files, PPD files, etc.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPS_FILE_PRIVATE_H_
+# define _CUPS_FILE_PRIVATE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include "cups-private.h"
+# include <stdio.h>
+# include <stdlib.h>
+# include <stdarg.h>
+# include <fcntl.h>
+
+# ifdef HAVE_LIBZ
+# include <zlib.h>
+# endif /* HAVE_LIBZ */
+# ifdef WIN32
+# include <io.h>
+# include <sys/locking.h>
+# endif /* WIN32 */
+
+
+/*
+ * Some operating systems support large files via open flag O_LARGEFILE...
+ */
+
+# ifndef O_LARGEFILE
+# define O_LARGEFILE 0
+# endif /* !O_LARGEFILE */
+
+
+/*
+ * Some operating systems don't define O_BINARY, which is used by Microsoft
+ * and IBM to flag binary files...
+ */
+
+# ifndef O_BINARY
+# define O_BINARY 0
+# endif /* !O_BINARY */
+
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Types and structures...
+ */
+
+typedef enum /**** _cupsFileCheck return values ****/
+{
+ _CUPS_FILE_CHECK_OK = 0, /* Everything OK */
+ _CUPS_FILE_CHECK_MISSING = 1, /* File is missing */
+ _CUPS_FILE_CHECK_PERMISSIONS = 2, /* File (or parent dir) has bad perms */
+ _CUPS_FILE_CHECK_WRONG_TYPE = 3, /* File has wrong type */
+ _CUPS_FILE_CHECK_RELATIVE_PATH = 4 /* File contains a relative path */
+} _cups_fc_result_t;
+
+typedef enum /**** _cupsFileCheck file type values ****/
+{
+ _CUPS_FILE_CHECK_FILE = 0, /* Check the file and parent directory */
+ _CUPS_FILE_CHECK_PROGRAM = 1, /* Check the program and parent directory */
+ _CUPS_FILE_CHECK_FILE_ONLY = 2, /* Check the file only */
+ _CUPS_FILE_CHECK_DIRECTORY = 3 /* Check the directory */
+} _cups_fc_filetype_t;
+
+typedef void (*_cups_fc_func_t)(void *context, _cups_fc_result_t result,
+ const char *message);
+
+struct _cups_file_s /**** CUPS file structure... ****/
+
+{
+ int fd; /* File descriptor */
+ char mode, /* Mode ('r' or 'w') */
+ compressed, /* Compression used? */
+ is_stdio, /* stdin/out/err? */
+ eof, /* End of file? */
+ buf[4096], /* Buffer */
+ *ptr, /* Pointer into buffer */
+ *end; /* End of buffer data */
+ off_t pos, /* Position in file */
+ bufpos; /* File position for start of buffer */
+
+#ifdef HAVE_LIBZ
+ z_stream stream; /* (De)compression stream */
+ Bytef cbuf[4096]; /* (De)compression buffer */
+ uLong crc; /* (De)compression CRC */
+#endif /* HAVE_LIBZ */
+
+ char *printf_buffer; /* cupsFilePrintf buffer */
+ size_t printf_size; /* Size of cupsFilePrintf buffer */
+};
+
+
+/*
+ * Prototypes...
+ */
+
+extern _cups_fc_result_t _cupsFileCheck(const char *filename,
+ _cups_fc_filetype_t filetype,
+ int dorootchecks,
+ _cups_fc_func_t cb,
+ void *context);
+extern void _cupsFileCheckFilter(void *context,
+ _cups_fc_result_t result,
+ const char *message);
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_FILE_PRIVATE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/file.c b/cups/file.c
new file mode 100644
index 000000000..8574eaa90
--- /dev/null
+++ b/cups/file.c
@@ -0,0 +1,2721 @@
+/*
+ * "$Id$"
+ *
+ * File functions for CUPS.
+ *
+ * Since stdio files max out at 256 files on many systems, we have to
+ * write similar functions without this limit. At the same time, using
+ * our own file functions allows us to provide transparent support of
+ * gzip'd print files, PPD files, etc.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * _cupsFileCheck() - Check the permissions of the given filename.
+ * _cupsFileCheckFilter() - Report file check results as CUPS filter messages.
+ * cupsFileClose() - Close a CUPS file.
+ * cupsFileCompression() - Return whether a file is compressed.
+ * cupsFileEOF() - Return the end-of-file status.
+ * cupsFileFind() - Find a file using the specified path.
+ * cupsFileFlush() - Flush pending output.
+ * cupsFileGetChar() - Get a single character from a file.
+ * cupsFileGetConf() - Get a line from a configuration file.
+ * cupsFileGetLine() - Get a CR and/or LF-terminated line that may
+ * contain binary data.
+ * cupsFileGets() - Get a CR and/or LF-terminated line.
+ * cupsFileLock() - Temporarily lock access to a file.
+ * cupsFileNumber() - Return the file descriptor associated with a CUPS
+ * file.
+ * cupsFileOpen() - Open a CUPS file.
+ * cupsFileOpenFd() - Open a CUPS file using a file descriptor.
+ * cupsFilePeekChar() - Peek at the next character from a file.
+ * cupsFilePrintf() - Write a formatted string.
+ * cupsFilePutChar() - Write a character.
+ * cupsFilePuts() - Write a string.
+ * cupsFileRead() - Read from a file.
+ * cupsFileRewind() - Set the current file position to the beginning of
+ * the file.
+ * cupsFileSeek() - Seek in a file.
+ * cupsFileStderr() - Return a CUPS file associated with stderr.
+ * cupsFileStdin() - Return a CUPS file associated with stdin.
+ * cupsFileStdout() - Return a CUPS file associated with stdout.
+ * cupsFileTell() - Return the current file position.
+ * cupsFileUnlock() - Unlock access to a file.
+ * cupsFileWrite() - Write to a file.
+ * cups_compress() - Compress a buffer of data.
+ * cups_fill() - Fill the input buffer.
+ * cups_read() - Read from a file descriptor.
+ * cups_write() - Write to a file descriptor.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "file-private.h"
+#include <sys/stat.h>
+#include <sys/types.h>
+
+
+/*
+ * Local functions...
+ */
+
+#ifdef HAVE_LIBZ
+static ssize_t cups_compress(cups_file_t *fp, const char *buf, size_t bytes);
+#endif /* HAVE_LIBZ */
+static ssize_t cups_fill(cups_file_t *fp);
+static int cups_open(const char *filename, int mode);
+static ssize_t cups_read(cups_file_t *fp, char *buf, size_t bytes);
+static ssize_t cups_write(cups_file_t *fp, const char *buf, size_t bytes);
+
+
+/*
+ * '_cupsFileCheck()' - Check the permissions of the given filename.
+ */
+
+_cups_fc_result_t /* O - Check result */
+_cupsFileCheck(
+ const char *filename, /* I - Filename to check */
+ _cups_fc_filetype_t filetype, /* I - Type of file checks? */
+ int dorootchecks, /* I - Check for root permissions? */
+ _cups_fc_func_t cb, /* I - Callback function */
+ void *context) /* I - Context pointer for callback */
+
+{
+ struct stat fileinfo; /* File information */
+ char message[1024], /* Message string */
+ temp[1024], /* Parent directory filename */
+ *ptr; /* Pointer into parent directory */
+ _cups_fc_result_t result; /* Check result */
+
+
+ /*
+ * Does the filename contain a relative path ("../")?
+ */
+
+ if (strstr(filename, "../"))
+ {
+ /*
+ * Yes, fail it!
+ */
+
+ result = _CUPS_FILE_CHECK_RELATIVE_PATH;
+ goto finishup;
+ }
+
+ /*
+ * Does the program even exist and is it accessible?
+ */
+
+ if (stat(filename, &fileinfo))
+ {
+ /*
+ * Nope...
+ */
+
+ result = _CUPS_FILE_CHECK_MISSING;
+ goto finishup;
+ }
+
+ /*
+ * Check the execute bit...
+ */
+
+ result = _CUPS_FILE_CHECK_OK;
+
+ switch (filetype)
+ {
+ case _CUPS_FILE_CHECK_DIRECTORY :
+ if (!S_ISDIR(fileinfo.st_mode))
+ result = _CUPS_FILE_CHECK_WRONG_TYPE;
+ break;
+
+ default :
+ if (!S_ISREG(fileinfo.st_mode))
+ result = _CUPS_FILE_CHECK_WRONG_TYPE;
+ break;
+ }
+
+ if (result)
+ goto finishup;
+
+ /*
+ * Are we doing root checks?
+ */
+
+ if (!dorootchecks)
+ {
+ /*
+ * Nope, so anything (else) goes...
+ */
+
+ goto finishup;
+ }
+
+ /*
+ * Verify permission of the file itself:
+ *
+ * 1. Must be owned by root
+ * 2. Must not be writable by group unless group is root/wheel/admin
+ * 3. Must not be setuid
+ * 4. Must not be writable by others
+ */
+
+ if (fileinfo.st_uid || /* 1. Must be owned by root */
+#ifdef __APPLE__
+ ((fileinfo.st_mode & S_IWGRP) && fileinfo.st_gid &&
+ fileinfo.st_gid != 80) || /* 2. Must not be writable by group */
+#else
+ ((fileinfo.st_mode & S_IWGRP) && fileinfo.st_gid) ||
+ /* 2. Must not be writable by group */
+#endif /* __APPLE__ */
+ (fileinfo.st_mode & S_ISUID) || /* 3. Must not be setuid */
+ (fileinfo.st_mode & S_IWOTH)) /* 4. Must not be writable by others */
+ {
+ result = _CUPS_FILE_CHECK_PERMISSIONS;
+ goto finishup;
+ }
+
+ if (filetype == _CUPS_FILE_CHECK_DIRECTORY ||
+ filetype == _CUPS_FILE_CHECK_FILE_ONLY)
+ goto finishup;
+
+ /*
+ * Now check the containing directory...
+ */
+
+ strlcpy(temp, filename, sizeof(temp));
+ if ((ptr = strrchr(temp, '/')) != NULL)
+ {
+ if (ptr == temp)
+ ptr[1] = '\0';
+ else
+ *ptr = '\0';
+ }
+
+ if (stat(temp, &fileinfo))
+ {
+ /*
+ * Doesn't exist?!?
+ */
+
+ result = _CUPS_FILE_CHECK_MISSING;
+ filetype = _CUPS_FILE_CHECK_DIRECTORY;
+ filename = temp;
+
+ goto finishup;
+ }
+
+ if (fileinfo.st_uid || /* 1. Must be owned by root */
+#ifdef __APPLE__
+ ((fileinfo.st_mode & S_IWGRP) && fileinfo.st_gid &&
+ fileinfo.st_gid != 80) || /* 2. Must not be writable by group */
+#else
+ ((fileinfo.st_mode & S_IWGRP) && fileinfo.st_gid) ||
+ /* 2. Must not be writable by group */
+#endif /* __APPLE__ */
+ (fileinfo.st_mode & S_ISUID) || /* 3. Must not be setuid */
+ (fileinfo.st_mode & S_IWOTH)) /* 4. Must not be writable by others */
+ {
+ result = _CUPS_FILE_CHECK_PERMISSIONS;
+ filetype = _CUPS_FILE_CHECK_DIRECTORY;
+ filename = temp;
+ }
+
+ /*
+ * Common return point...
+ */
+
+ finishup:
+
+ if (cb)
+ {
+ cups_lang_t *lang = cupsLangDefault();
+ /* Localization information */
+
+ switch (result)
+ {
+ case _CUPS_FILE_CHECK_OK :
+ if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("Directory \"%s\" permissions OK "
+ "(0%o/uid=%d/gid=%d).")),
+ filename, fileinfo.st_mode, (int)fileinfo.st_uid,
+ (int)fileinfo.st_gid);
+ else
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("File \"%s\" permissions OK "
+ "(0%o/uid=%d/gid=%d).")),
+ filename, fileinfo.st_mode, (int)fileinfo.st_uid,
+ (int)fileinfo.st_gid);
+ break;
+
+ case _CUPS_FILE_CHECK_MISSING :
+ if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("Directory \"%s\" not available: "
+ "%s")),
+ filename, strerror(errno));
+ else
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("File \"%s\" not available: %s")),
+ filename, strerror(errno));
+ break;
+
+ case _CUPS_FILE_CHECK_PERMISSIONS :
+ if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("Directory \"%s\" has insecure "
+ "permissions "
+ "(0%o/uid=%d/gid=%d).")),
+ filename, fileinfo.st_mode, (int)fileinfo.st_uid,
+ (int)fileinfo.st_gid);
+ else
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("File \"%s\" has insecure "
+ "permissions "
+ "(0%o/uid=%d/gid=%d).")),
+ filename, fileinfo.st_mode, (int)fileinfo.st_uid,
+ (int)fileinfo.st_gid);
+ break;
+
+ case _CUPS_FILE_CHECK_WRONG_TYPE :
+ if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("Directory \"%s\" is a file.")),
+ filename);
+ else
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("File \"%s\" is a directory.")),
+ filename);
+ break;
+
+ case _CUPS_FILE_CHECK_RELATIVE_PATH :
+ if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("Directory \"%s\" contains a "
+ "relative path.")), filename);
+ else
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("File \"%s\" contains a relative "
+ "path.")), filename);
+ break;
+ }
+
+ (*cb)(context, result, message);
+ }
+
+ return (result);
+}
+
+
+/*
+ * '_cupsFileCheckFilter()' - Report file check results as CUPS filter messages.
+ */
+
+void
+_cupsFileCheckFilter(
+ void *context, /* I - Context pointer (unused) */
+ _cups_fc_result_t result, /* I - Result code */
+ const char *message) /* I - Message text */
+{
+ const char *prefix; /* Messaging prefix */
+
+
+ (void)context;
+
+ switch (result)
+ {
+ case _CUPS_FILE_CHECK_OK :
+ prefix = "DEBUG2";
+ break;
+
+ case _CUPS_FILE_CHECK_MISSING :
+ case _CUPS_FILE_CHECK_WRONG_TYPE :
+ prefix = "ERROR";
+ fputs("STATE: +cups-missing-filter-warning\n", stderr);
+ break;
+
+ case _CUPS_FILE_CHECK_PERMISSIONS :
+ case _CUPS_FILE_CHECK_RELATIVE_PATH :
+ prefix = "ERROR";
+ fputs("STATE: +cups-insecure-filter-warning\n", stderr);
+ break;
+ }
+
+ fprintf(stderr, "%s: %s\n", prefix, message);
+}
+
+
+/*
+ * 'cupsFileClose()' - Close a CUPS file.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsFileClose(cups_file_t *fp) /* I - CUPS file */
+{
+ int fd; /* File descriptor */
+ char mode; /* Open mode */
+ int status; /* Return status */
+ int is_stdio; /* Is a stdio file? */
+
+
+ DEBUG_printf(("cupsFileClose(fp=%p)", fp));
+
+ /*
+ * Range check...
+ */
+
+ if (!fp)
+ return (-1);
+
+ /*
+ * Flush pending write data...
+ */
+
+ if (fp->mode == 'w')
+ status = cupsFileFlush(fp);
+ else
+ status = 0;
+
+#ifdef HAVE_LIBZ
+ if (fp->compressed && status >= 0)
+ {
+ if (fp->mode == 'r')
+ {
+ /*
+ * Free decompression data...
+ */
+
+ inflateEnd(&fp->stream);
+ }
+ else
+ {
+ /*
+ * Flush any remaining compressed data...
+ */
+
+ unsigned char trailer[8]; /* Trailer CRC and length */
+ int done; /* Done writing... */
+
+
+ fp->stream.avail_in = 0;
+
+ for (done = 0;;)
+ {
+ if (fp->stream.next_out > fp->cbuf)
+ {
+ if (cups_write(fp, (char *)fp->cbuf,
+ fp->stream.next_out - fp->cbuf) < 0)
+ status = -1;
+
+ fp->stream.next_out = fp->cbuf;
+ fp->stream.avail_out = sizeof(fp->cbuf);
+ }
+
+ if (done || status < 0)
+ break;
+
+ done = deflate(&fp->stream, Z_FINISH) == Z_STREAM_END &&
+ fp->stream.next_out == fp->cbuf;
+ }
+
+ /*
+ * Write the CRC and length...
+ */
+
+ trailer[0] = fp->crc;
+ trailer[1] = fp->crc >> 8;
+ trailer[2] = fp->crc >> 16;
+ trailer[3] = fp->crc >> 24;
+ trailer[4] = fp->pos;
+ trailer[5] = fp->pos >> 8;
+ trailer[6] = fp->pos >> 16;
+ trailer[7] = fp->pos >> 24;
+
+ if (cups_write(fp, (char *)trailer, 8) < 0)
+ status = -1;
+
+ /*
+ * Free all memory used by the compression stream...
+ */
+
+ deflateEnd(&(fp->stream));
+ }
+ }
+#endif /* HAVE_LIBZ */
+
+ /*
+ * Save the file descriptor we used and free memory...
+ */
+
+ fd = fp->fd;
+ mode = fp->mode;
+ is_stdio = fp->is_stdio;
+
+ if (fp->printf_buffer)
+ free(fp->printf_buffer);
+
+ free(fp);
+
+ /*
+ * Close the file, returning the close status...
+ */
+
+ if (mode == 's')
+ {
+ if (closesocket(fd) < 0)
+ status = -1;
+ }
+ else if (!is_stdio)
+ {
+ if (close(fd) < 0)
+ status = -1;
+ }
+
+ return (status);
+}
+
+
+/*
+ * 'cupsFileCompression()' - Return whether a file is compressed.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - @code CUPS_FILE_NONE@ or @code CUPS_FILE_GZIP@ */
+cupsFileCompression(cups_file_t *fp) /* I - CUPS file */
+{
+ return (fp ? fp->compressed : CUPS_FILE_NONE);
+}
+
+
+/*
+ * 'cupsFileEOF()' - Return the end-of-file status.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 1 on end of file, 0 otherwise */
+cupsFileEOF(cups_file_t *fp) /* I - CUPS file */
+{
+ return (fp ? fp->eof : 1);
+}
+
+
+/*
+ * 'cupsFileFind()' - Find a file using the specified path.
+ *
+ * This function allows the paths in the path string to be separated by
+ * colons (UNIX standard) or semicolons (Windows standard) and stores the
+ * result in the buffer supplied. If the file cannot be found in any of
+ * the supplied paths, @code NULL@ is returned. A @code NULL@ path only
+ * matches the current directory.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+const char * /* O - Full path to file or @code NULL@ if not found */
+cupsFileFind(const char *filename, /* I - File to find */
+ const char *path, /* I - Colon/semicolon-separated path */
+ int executable, /* I - 1 = executable files, 0 = any file/dir */
+ char *buffer, /* I - Filename buffer */
+ int bufsize) /* I - Size of filename buffer */
+{
+ char *bufptr, /* Current position in buffer */
+ *bufend; /* End of buffer */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("cupsFileFind(filename=\"%s\", path=\"%s\", executable=%d, "
+ "buffer=%p, bufsize=%d)", filename, path, executable, buffer,
+ bufsize));
+
+ if (!filename || !buffer || bufsize < 2)
+ return (NULL);
+
+ if (!path)
+ {
+ /*
+ * No path, so check current directory...
+ */
+
+ if (!access(filename, 0))
+ {
+ strlcpy(buffer, filename, bufsize);
+ return (buffer);
+ }
+ else
+ return (NULL);
+ }
+
+ /*
+ * Now check each path and return the first match...
+ */
+
+ bufend = buffer + bufsize - 1;
+ bufptr = buffer;
+
+ while (*path)
+ {
+#ifdef WIN32
+ if (*path == ';' || (*path == ':' && ((bufptr - buffer) > 1 || !isalpha(buffer[0] & 255))))
+#else
+ if (*path == ';' || *path == ':')
+#endif /* WIN32 */
+ {
+ if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
+ *bufptr++ = '/';
+
+ strlcpy(bufptr, filename, bufend - bufptr);
+
+#ifdef WIN32
+ if (!access(buffer, 0))
+#else
+ if (!access(buffer, executable ? X_OK : 0))
+#endif /* WIN32 */
+ {
+ DEBUG_printf(("1cupsFileFind: Returning \"%s\"", buffer));
+ return (buffer);
+ }
+
+ bufptr = buffer;
+ }
+ else if (bufptr < bufend)
+ *bufptr++ = *path;
+
+ path ++;
+ }
+
+ /*
+ * Check the last path...
+ */
+
+ if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
+ *bufptr++ = '/';
+
+ strlcpy(bufptr, filename, bufend - bufptr);
+
+ if (!access(buffer, 0))
+ {
+ DEBUG_printf(("1cupsFileFind: Returning \"%s\"", buffer));
+ return (buffer);
+ }
+ else
+ {
+ DEBUG_puts("1cupsFileFind: Returning NULL");
+ return (NULL);
+ }
+}
+
+
+/*
+ * 'cupsFileFlush()' - Flush pending output.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsFileFlush(cups_file_t *fp) /* I - CUPS file */
+{
+ ssize_t bytes; /* Bytes to write */
+
+
+ DEBUG_printf(("cupsFileFlush(fp=%p)", fp));
+
+ /*
+ * Range check input...
+ */
+
+ if (!fp || fp->mode != 'w')
+ {
+ DEBUG_puts("1cupsFileFlush: Attempt to flush a read-only file...");
+ return (-1);
+ }
+
+ bytes = (ssize_t)(fp->ptr - fp->buf);
+
+ DEBUG_printf(("2cupsFileFlush: Flushing " CUPS_LLFMT " bytes...",
+ CUPS_LLCAST bytes));
+
+ if (bytes > 0)
+ {
+#ifdef HAVE_LIBZ
+ if (fp->compressed)
+ bytes = cups_compress(fp, fp->buf, bytes);
+ else
+#endif /* HAVE_LIBZ */
+ bytes = cups_write(fp, fp->buf, bytes);
+
+ if (bytes < 0)
+ return (-1);
+
+ fp->ptr = fp->buf;
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'cupsFileGetChar()' - Get a single character from a file.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - Character or -1 on end of file */
+cupsFileGetChar(cups_file_t *fp) /* I - CUPS file */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!fp || (fp->mode != 'r' && fp->mode != 's'))
+ {
+ DEBUG_puts("5cupsFileGetChar: Bad arguments!");
+ return (-1);
+ }
+
+ /*
+ * If the input buffer is empty, try to read more data...
+ */
+
+ if (fp->ptr >= fp->end)
+ if (cups_fill(fp) < 0)
+ {
+ DEBUG_puts("5cupsFileGetChar: Unable to fill buffer!");
+ return (-1);
+ }
+
+ /*
+ * Return the next character in the buffer...
+ */
+
+ DEBUG_printf(("5cupsFileGetChar: Returning %d...", *(fp->ptr) & 255));
+
+ fp->pos ++;
+
+ DEBUG_printf(("6cupsFileGetChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ return (*(fp->ptr)++ & 255);
+}
+
+
+/*
+ * 'cupsFileGetConf()' - Get a line from a configuration file.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+char * /* O - Line read or @code NULL@ on end of file or error */
+cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */
+ char *buf, /* O - String buffer */
+ size_t buflen, /* I - Size of string buffer */
+ char **value, /* O - Pointer to value */
+ int *linenum) /* IO - Current line number */
+{
+ char *ptr; /* Pointer into line */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("2cupsFileGetConf(fp=%p, buf=%p, buflen=" CUPS_LLFMT
+ ", value=%p, linenum=%p)", fp, buf, CUPS_LLCAST buflen,
+ value, linenum));
+
+ if (!fp || (fp->mode != 'r' && fp->mode != 's') ||
+ !buf || buflen < 2 || !value)
+ {
+ if (value)
+ *value = NULL;
+
+ return (NULL);
+ }
+
+ /*
+ * Read the next non-comment line...
+ */
+
+ *value = NULL;
+
+ while (cupsFileGets(fp, buf, buflen))
+ {
+ (*linenum) ++;
+
+ /*
+ * Strip any comments...
+ */
+
+ if ((ptr = strchr(buf, '#')) != NULL)
+ {
+ if (ptr > buf && ptr[-1] == '\\')
+ {
+ // Unquote the #...
+ _cups_strcpy(ptr - 1, ptr);
+ }
+ else
+ {
+ // Strip the comment and any trailing whitespace...
+ while (ptr > buf)
+ {
+ if (!_cups_isspace(ptr[-1]))
+ break;
+
+ ptr --;
+ }
+
+ *ptr = '\0';
+ }
+ }
+
+ /*
+ * Strip leading whitespace...
+ */
+
+ for (ptr = buf; _cups_isspace(*ptr); ptr ++);
+
+ if (ptr > buf)
+ _cups_strcpy(buf, ptr);
+
+ /*
+ * See if there is anything left...
+ */
+
+ if (buf[0])
+ {
+ /*
+ * Yes, grab any value and return...
+ */
+
+ for (ptr = buf; *ptr; ptr ++)
+ if (_cups_isspace(*ptr))
+ break;
+
+ if (*ptr)
+ {
+ /*
+ * Have a value, skip any other spaces...
+ */
+
+ while (_cups_isspace(*ptr))
+ *ptr++ = '\0';
+
+ if (*ptr)
+ *value = ptr;
+
+ /*
+ * Strip trailing whitespace and > for lines that begin with <...
+ */
+
+ ptr += strlen(ptr) - 1;
+
+ if (buf[0] == '<' && *ptr == '>')
+ *ptr-- = '\0';
+ else if (buf[0] == '<' && *ptr != '>')
+ {
+ /*
+ * Syntax error...
+ */
+
+ *value = NULL;
+ return (buf);
+ }
+
+ while (ptr > *value && _cups_isspace(*ptr))
+ *ptr-- = '\0';
+ }
+
+ /*
+ * Return the line...
+ */
+
+ return (buf);
+ }
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * 'cupsFileGetLine()' - Get a CR and/or LF-terminated line that may
+ * contain binary data.
+ *
+ * This function differs from @link cupsFileGets@ in that the trailing CR
+ * and LF are preserved, as is any binary data on the line. The buffer is
+ * nul-terminated, however you should use the returned length to determine
+ * the number of bytes on the line.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+size_t /* O - Number of bytes on line or 0 on end of file */
+cupsFileGetLine(cups_file_t *fp, /* I - File to read from */
+ char *buf, /* I - Buffer */
+ size_t buflen) /* I - Size of buffer */
+{
+ int ch; /* Character from file */
+ char *ptr, /* Current position in line buffer */
+ *end; /* End of line buffer */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("2cupsFileGetLine(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")",
+ fp, buf, CUPS_LLCAST buflen));
+
+ if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 3)
+ return (0);
+
+ /*
+ * Now loop until we have a valid line...
+ */
+
+ for (ptr = buf, end = buf + buflen - 2; ptr < end ;)
+ {
+ if (fp->ptr >= fp->end)
+ if (cups_fill(fp) <= 0)
+ break;
+
+ *ptr++ = ch = *(fp->ptr)++;
+ fp->pos ++;
+
+ if (ch == '\r')
+ {
+ /*
+ * Check for CR LF...
+ */
+
+ if (fp->ptr >= fp->end)
+ if (cups_fill(fp) <= 0)
+ break;
+
+ if (*(fp->ptr) == '\n')
+ {
+ *ptr++ = *(fp->ptr)++;
+ fp->pos ++;
+ }
+
+ break;
+ }
+ else if (ch == '\n')
+ {
+ /*
+ * Line feed ends a line...
+ */
+
+ break;
+ }
+ }
+
+ *ptr = '\0';
+
+ DEBUG_printf(("4cupsFileGetLine: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ return (ptr - buf);
+}
+
+
+/*
+ * 'cupsFileGets()' - Get a CR and/or LF-terminated line.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+char * /* O - Line read or @code NULL@ on end of file or error */
+cupsFileGets(cups_file_t *fp, /* I - CUPS file */
+ char *buf, /* O - String buffer */
+ size_t buflen) /* I - Size of string buffer */
+{
+ int ch; /* Character from file */
+ char *ptr, /* Current position in line buffer */
+ *end; /* End of line buffer */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("2cupsFileGets(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")", fp, buf,
+ CUPS_LLCAST buflen));
+
+ if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2)
+ return (NULL);
+
+ /*
+ * Now loop until we have a valid line...
+ */
+
+ for (ptr = buf, end = buf + buflen - 1; ptr < end ;)
+ {
+ if (fp->ptr >= fp->end)
+ if (cups_fill(fp) <= 0)
+ {
+ if (ptr == buf)
+ return (NULL);
+ else
+ break;
+ }
+
+ ch = *(fp->ptr)++;
+ fp->pos ++;
+
+ if (ch == '\r')
+ {
+ /*
+ * Check for CR LF...
+ */
+
+ if (fp->ptr >= fp->end)
+ if (cups_fill(fp) <= 0)
+ break;
+
+ if (*(fp->ptr) == '\n')
+ {
+ fp->ptr ++;
+ fp->pos ++;
+ }
+
+ break;
+ }
+ else if (ch == '\n')
+ {
+ /*
+ * Line feed ends a line...
+ */
+
+ break;
+ }
+ else
+ *ptr++ = ch;
+ }
+
+ *ptr = '\0';
+
+ DEBUG_printf(("4cupsFileGets: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ return (buf);
+}
+
+
+/*
+ * 'cupsFileLock()' - Temporarily lock access to a file.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsFileLock(cups_file_t *fp, /* I - CUPS file */
+ int block) /* I - 1 to wait for the lock, 0 to fail right away */
+{
+ /*
+ * Range check...
+ */
+
+ if (!fp || fp->mode == 's')
+ return (-1);
+
+ /*
+ * Try the lock...
+ */
+
+#ifdef WIN32
+ return (_locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0));
+#else
+ return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0));
+#endif /* WIN32 */
+}
+
+
+/*
+ * 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - File descriptor */
+cupsFileNumber(cups_file_t *fp) /* I - CUPS file */
+{
+ if (fp)
+ return (fp->fd);
+ else
+ return (-1);
+}
+
+
+/*
+ * 'cupsFileOpen()' - Open a CUPS file.
+ *
+ * The "mode" parameter can be "r" to read, "w" to write, overwriting any
+ * existing file, "a" to append to an existing file or create a new file,
+ * or "s" to open a socket connection.
+ *
+ * When opening for writing ("w"), an optional number from 1 to 9 can be
+ * supplied which enables Flate compression of the file. Compression is
+ * not supported for the "a" (append) mode.
+ *
+ * When opening a socket connection, the filename is a string of the form
+ * "address:port" or "hostname:port". The socket will make an IPv4 or IPv6
+ * connection as needed, generally preferring IPv6 connections when there is
+ * a choice.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+cups_file_t * /* O - CUPS file or @code NULL@ if the file or socket cannot be opened */
+cupsFileOpen(const char *filename, /* I - Name of file */
+ const char *mode) /* I - Open mode */
+{
+ cups_file_t *fp; /* New CUPS file */
+ int fd; /* File descriptor */
+ char hostname[1024], /* Hostname */
+ *portname; /* Port "name" (number or service) */
+ http_addrlist_t *addrlist; /* Host address list */
+
+
+ DEBUG_printf(("cupsFileOpen(filename=\"%s\", mode=\"%s\")", filename,
+ mode));
+
+ /*
+ * Range check input...
+ */
+
+ if (!filename || !mode ||
+ (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') ||
+ (*mode == 'a' && isdigit(mode[1] & 255)))
+ return (NULL);
+
+ /*
+ * Open the file...
+ */
+
+ switch (*mode)
+ {
+ case 'a' : /* Append file */
+ fd = cups_open(filename,
+ O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY);
+ break;
+
+ case 'r' : /* Read file */
+ fd = open(filename, O_RDONLY | O_LARGEFILE | O_BINARY, 0);
+ break;
+
+ case 'w' : /* Write file */
+ fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY);
+ if (fd < 0 && errno == ENOENT)
+ {
+ fd = cups_open(filename,
+ O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE | O_BINARY);
+ if (fd < 0 && errno == EEXIST)
+ fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY);
+ }
+
+ if (fd >= 0)
+#ifdef WIN32
+ _chsize(fd, 0);
+#else
+ ftruncate(fd, 0);
+#endif /* WIN32 */
+ break;
+
+ case 's' : /* Read/write socket */
+ strlcpy(hostname, filename, sizeof(hostname));
+ if ((portname = strrchr(hostname, ':')) != NULL)
+ *portname++ = '\0';
+ else
+ return (NULL);
+
+ /*
+ * Lookup the hostname and service...
+ */
+
+ if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
+ return (NULL);
+
+ /*
+ * Connect to the server...
+ */
+
+ if (!httpAddrConnect(addrlist, &fd))
+ {
+ httpAddrFreeList(addrlist);
+ return (NULL);
+ }
+
+ httpAddrFreeList(addrlist);
+ break;
+
+ default : /* Remove bogus compiler warning... */
+ return (NULL);
+ }
+
+ if (fd < 0)
+ return (NULL);
+
+ /*
+ * Create the CUPS file structure...
+ */
+
+ if ((fp = cupsFileOpenFd(fd, mode)) == NULL)
+ {
+ if (*mode == 's')
+ closesocket(fd);
+ else
+ close(fd);
+ }
+
+ /*
+ * Return it...
+ */
+
+ return (fp);
+}
+
+/*
+ * 'cupsFileOpenFd()' - Open a CUPS file using a file descriptor.
+ *
+ * The "mode" parameter can be "r" to read, "w" to write, "a" to append,
+ * or "s" to treat the file descriptor as a bidirectional socket connection.
+ *
+ * When opening for writing ("w"), an optional number from 1 to 9 can be
+ * supplied which enables Flate compression of the file. Compression is
+ * not supported for the "a" (append) mode.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+cups_file_t * /* O - CUPS file or @code NULL@ if the file could not be opened */
+cupsFileOpenFd(int fd, /* I - File descriptor */
+ const char *mode) /* I - Open mode */
+{
+ cups_file_t *fp; /* New CUPS file */
+
+
+ DEBUG_printf(("cupsFileOpenFd(fd=%d, mode=\"%s\")", fd, mode));
+
+ /*
+ * Range check input...
+ */
+
+ if (fd < 0 || !mode ||
+ (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') ||
+ (*mode == 'a' && isdigit(mode[1] & 255)))
+ return (NULL);
+
+ /*
+ * Allocate memory...
+ */
+
+ if ((fp = calloc(1, sizeof(cups_file_t))) == NULL)
+ return (NULL);
+
+ /*
+ * Open the file...
+ */
+
+ fp->fd = fd;
+
+ switch (*mode)
+ {
+ case 'a' :
+ fp->pos = lseek(fd, 0, SEEK_END);
+
+ case 'w' :
+ fp->mode = 'w';
+ fp->ptr = fp->buf;
+ fp->end = fp->buf + sizeof(fp->buf);
+
+#ifdef HAVE_LIBZ
+ if (mode[1] >= '1' && mode[1] <= '9')
+ {
+ /*
+ * Open a compressed stream, so write the standard gzip file
+ * header...
+ */
+
+ unsigned char header[10]; /* gzip file header */
+ time_t curtime; /* Current time */
+
+
+ curtime = time(NULL);
+ header[0] = 0x1f;
+ header[1] = 0x8b;
+ header[2] = Z_DEFLATED;
+ header[3] = 0;
+ header[4] = curtime;
+ header[5] = curtime >> 8;
+ header[6] = curtime >> 16;
+ header[7] = curtime >> 24;
+ header[8] = 0;
+ header[9] = 0x03;
+
+ cups_write(fp, (char *)header, 10);
+
+ /*
+ * Initialize the compressor...
+ */
+
+ deflateInit2(&(fp->stream), mode[1] - '0', Z_DEFLATED, -15, 8,
+ Z_DEFAULT_STRATEGY);
+
+ fp->stream.next_out = fp->cbuf;
+ fp->stream.avail_out = sizeof(fp->cbuf);
+ fp->compressed = 1;
+ fp->crc = crc32(0L, Z_NULL, 0);
+ }
+#endif /* HAVE_LIBZ */
+ break;
+
+ case 'r' :
+ fp->mode = 'r';
+ break;
+
+ case 's' :
+ fp->mode = 's';
+ break;
+
+ default : /* Remove bogus compiler warning... */
+ return (NULL);
+ }
+
+ /*
+ * Don't pass this file to child processes...
+ */
+
+#ifndef WIN32
+ fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC);
+#endif /* !WIN32 */
+
+ return (fp);
+}
+
+
+/*
+ * 'cupsFilePeekChar()' - Peek at the next character from a file.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - Character or -1 on end of file */
+cupsFilePeekChar(cups_file_t *fp) /* I - CUPS file */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!fp || (fp->mode != 'r' && fp->mode != 's'))
+ return (-1);
+
+ /*
+ * If the input buffer is empty, try to read more data...
+ */
+
+ if (fp->ptr >= fp->end)
+ if (cups_fill(fp) < 0)
+ return (-1);
+
+ /*
+ * Return the next character in the buffer...
+ */
+
+ return (*(fp->ptr) & 255);
+}
+
+
+/*
+ * 'cupsFilePrintf()' - Write a formatted string.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - Number of bytes written or -1 on error */
+cupsFilePrintf(cups_file_t *fp, /* I - CUPS file */
+ const char *format, /* I - Printf-style format string */
+ ...) /* I - Additional args as necessary */
+{
+ va_list ap; /* Argument list */
+ ssize_t bytes; /* Formatted size */
+
+
+ DEBUG_printf(("2cupsFilePrintf(fp=%p, format=\"%s\", ...)", fp, format));
+
+ if (!fp || !format || (fp->mode != 'w' && fp->mode != 's'))
+ return (-1);
+
+ if (!fp->printf_buffer)
+ {
+ /*
+ * Start with an 1k printf buffer...
+ */
+
+ if ((fp->printf_buffer = malloc(1024)) == NULL)
+ return (-1);
+
+ fp->printf_size = 1024;
+ }
+
+ va_start(ap, format);
+ bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
+ va_end(ap);
+
+ if (bytes >= (ssize_t)fp->printf_size)
+ {
+ /*
+ * Expand the printf buffer...
+ */
+
+ char *temp; /* Temporary buffer pointer */
+
+
+ if (bytes > 65535)
+ return (-1);
+
+ if ((temp = realloc(fp->printf_buffer, bytes + 1)) == NULL)
+ return (-1);
+
+ fp->printf_buffer = temp;
+ fp->printf_size = bytes + 1;
+
+ va_start(ap, format);
+ bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
+ va_end(ap);
+ }
+
+ if (fp->mode == 's')
+ {
+ if (cups_write(fp, fp->printf_buffer, bytes) < 0)
+ return (-1);
+
+ fp->pos += bytes;
+
+ DEBUG_printf(("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ return (bytes);
+ }
+
+ if ((fp->ptr + bytes) > fp->end)
+ if (cupsFileFlush(fp))
+ return (-1);
+
+ fp->pos += bytes;
+
+ DEBUG_printf(("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ if (bytes > sizeof(fp->buf))
+ {
+#ifdef HAVE_LIBZ
+ if (fp->compressed)
+ return (cups_compress(fp, fp->printf_buffer, bytes));
+ else
+#endif /* HAVE_LIBZ */
+ return (cups_write(fp, fp->printf_buffer, bytes));
+ }
+ else
+ {
+ memcpy(fp->ptr, fp->printf_buffer, bytes);
+ fp->ptr += bytes;
+ return (bytes);
+ }
+}
+
+
+/*
+ * 'cupsFilePutChar()' - Write a character.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsFilePutChar(cups_file_t *fp, /* I - CUPS file */
+ int c) /* I - Character to write */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!fp || (fp->mode != 'w' && fp->mode != 's'))
+ return (-1);
+
+ if (fp->mode == 's')
+ {
+ /*
+ * Send character immediately over socket...
+ */
+
+ char ch; /* Output character */
+
+
+ ch = c;
+
+ if (send(fp->fd, &ch, 1, 0) < 1)
+ return (-1);
+ }
+ else
+ {
+ /*
+ * Buffer it up...
+ */
+
+ if (fp->ptr >= fp->end)
+ if (cupsFileFlush(fp))
+ return (-1);
+
+ *(fp->ptr) ++ = c;
+ }
+
+ fp->pos ++;
+
+ DEBUG_printf(("4cupsFilePutChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ return (0);
+}
+
+
+/*
+ * 'cupsFilePutConf()' - Write a configuration line.
+ *
+ * This function handles any comment escaping of the value.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+ssize_t /* O - Number of bytes written or -1 on error */
+cupsFilePutConf(cups_file_t *fp, /* I - CUPS file */
+ const char *directive, /* I - Directive */
+ const char *value) /* I - Value */
+{
+ ssize_t bytes, /* Number of bytes written */
+ temp; /* Temporary byte count */
+ const char *ptr; /* Pointer into value */
+
+
+ if (!fp || !directive || !*directive)
+ return (-1);
+
+ if ((bytes = cupsFilePuts(fp, directive)) < 0)
+ return (-1);
+
+ if (cupsFilePutChar(fp, ' ') < 0)
+ return (-1);
+ bytes ++;
+
+ if (value && *value)
+ {
+ if ((ptr = strchr(value, '#')) != NULL)
+ {
+ /*
+ * Need to quote the first # in the info string...
+ */
+
+ if ((temp = cupsFileWrite(fp, value, ptr - value)) < 0)
+ return (-1);
+ bytes += temp;
+
+ if (cupsFilePutChar(fp, '\\') < 0)
+ return (-1);
+ bytes ++;
+
+ if ((temp = cupsFilePuts(fp, ptr)) < 0)
+ return (-1);
+ bytes += temp;
+ }
+ else if ((temp = cupsFilePuts(fp, value)) < 0)
+ return (-1);
+ else
+ bytes += temp;
+ }
+
+ if (cupsFilePutChar(fp, '\n') < 0)
+ return (-1);
+ else
+ return (bytes + 1);
+}
+
+
+/*
+ * 'cupsFilePuts()' - Write a string.
+ *
+ * Like the @code fputs@ function, no newline is appended to the string.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - Number of bytes written or -1 on error */
+cupsFilePuts(cups_file_t *fp, /* I - CUPS file */
+ const char *s) /* I - String to write */
+{
+ ssize_t bytes; /* Bytes to write */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!fp || !s || (fp->mode != 'w' && fp->mode != 's'))
+ return (-1);
+
+ /*
+ * Write the string...
+ */
+
+ bytes = (int)strlen(s);
+
+ if (fp->mode == 's')
+ {
+ if (cups_write(fp, s, bytes) < 0)
+ return (-1);
+
+ fp->pos += bytes;
+
+ DEBUG_printf(("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ return (bytes);
+ }
+
+ if ((fp->ptr + bytes) > fp->end)
+ if (cupsFileFlush(fp))
+ return (-1);
+
+ fp->pos += bytes;
+
+ DEBUG_printf(("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ if (bytes > sizeof(fp->buf))
+ {
+#ifdef HAVE_LIBZ
+ if (fp->compressed)
+ return (cups_compress(fp, s, bytes));
+ else
+#endif /* HAVE_LIBZ */
+ return (cups_write(fp, s, bytes));
+ }
+ else
+ {
+ memcpy(fp->ptr, s, bytes);
+ fp->ptr += bytes;
+ return (bytes);
+ }
+}
+
+
+/*
+ * 'cupsFileRead()' - Read from a file.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ssize_t /* O - Number of bytes read or -1 on error */
+cupsFileRead(cups_file_t *fp, /* I - CUPS file */
+ char *buf, /* O - Buffer */
+ size_t bytes) /* I - Number of bytes to read */
+{
+ size_t total; /* Total bytes read */
+ ssize_t count; /* Bytes read */
+
+
+ DEBUG_printf(("2cupsFileRead(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf,
+ CUPS_LLCAST bytes));
+
+ /*
+ * Range check input...
+ */
+
+ if (!fp || !buf || (fp->mode != 'r' && fp->mode != 's'))
+ return (-1);
+
+ if (bytes == 0)
+ return (0);
+
+ /*
+ * Loop until all bytes are read...
+ */
+
+ total = 0;
+ while (bytes > 0)
+ {
+ if (fp->ptr >= fp->end)
+ if (cups_fill(fp) <= 0)
+ {
+ DEBUG_printf(("4cupsFileRead: cups_fill() returned -1, total="
+ CUPS_LLFMT, CUPS_LLCAST total));
+
+ if (total > 0)
+ return ((ssize_t)total);
+ else
+ return (-1);
+ }
+
+ count = (ssize_t)(fp->end - fp->ptr);
+ if (count > (ssize_t)bytes)
+ count = (ssize_t)bytes;
+
+ memcpy(buf, fp->ptr, count);
+ fp->ptr += count;
+ fp->pos += count;
+
+ DEBUG_printf(("4cupsFileRead: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ /*
+ * Update the counts for the last read...
+ */
+
+ bytes -= count;
+ total += count;
+ buf += count;
+ }
+
+ /*
+ * Return the total number of bytes read...
+ */
+
+ DEBUG_printf(("3cupsFileRead: total=" CUPS_LLFMT, CUPS_LLCAST total));
+
+ return ((ssize_t)total);
+}
+
+
+/*
+ * 'cupsFileRewind()' - Set the current file position to the beginning of the
+ * file.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+off_t /* O - New file position or -1 on error */
+cupsFileRewind(cups_file_t *fp) /* I - CUPS file */
+{
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("cupsFileRewind(fp=%p)", fp));
+ DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ if (!fp || fp->mode != 'r')
+ return (-1);
+
+ /*
+ * Handle special cases...
+ */
+
+ if (fp->bufpos == 0)
+ {
+ /*
+ * No seeking necessary...
+ */
+
+ fp->pos = 0;
+
+ if (fp->ptr)
+ {
+ fp->ptr = fp->buf;
+ fp->eof = 0;
+ }
+
+ DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ return (0);
+ }
+
+ /*
+ * Otherwise, seek in the file and cleanup any compression buffers...
+ */
+
+#ifdef HAVE_LIBZ
+ if (fp->compressed)
+ {
+ inflateEnd(&fp->stream);
+ fp->compressed = 0;
+ }
+#endif /* HAVE_LIBZ */
+
+ if (lseek(fp->fd, 0, SEEK_SET))
+ {
+ DEBUG_printf(("1cupsFileRewind: lseek failed: %s", strerror(errno)));
+ return (-1);
+ }
+
+ fp->bufpos = 0;
+ fp->pos = 0;
+ fp->ptr = NULL;
+ fp->end = NULL;
+ fp->eof = 0;
+
+ DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ return (0);
+}
+
+
+/*
+ * 'cupsFileSeek()' - Seek in a file.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+off_t /* O - New file position or -1 on error */
+cupsFileSeek(cups_file_t *fp, /* I - CUPS file */
+ off_t pos) /* I - Position in file */
+{
+ ssize_t bytes; /* Number bytes in buffer */
+
+
+ DEBUG_printf(("cupsFileSeek(fp=%p, pos=" CUPS_LLFMT ")", fp,
+ CUPS_LLCAST pos));
+ DEBUG_printf(("2cupsFileSeek: fp->pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+ DEBUG_printf(("2cupsFileSeek: fp->ptr=%p, fp->end=%p", fp->ptr, fp->end));
+
+ /*
+ * Range check input...
+ */
+
+ if (!fp || pos < 0 || fp->mode != 'r')
+ return (-1);
+
+ /*
+ * Handle special cases...
+ */
+
+ if (pos == 0)
+ return (cupsFileRewind(fp));
+
+ if (fp->ptr)
+ {
+ bytes = (ssize_t)(fp->end - fp->buf);
+
+ DEBUG_printf(("2cupsFileSeek: bytes=" CUPS_LLFMT, CUPS_LLCAST bytes));
+
+ if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
+ {
+ /*
+ * No seeking necessary...
+ */
+
+ fp->pos = pos;
+ fp->ptr = fp->buf + pos - fp->bufpos;
+ fp->eof = 0;
+
+ return (pos);
+ }
+ }
+
+#ifdef HAVE_LIBZ
+ if (!fp->compressed && !fp->ptr)
+ {
+ /*
+ * Preload a buffer to determine whether the file is compressed...
+ */
+
+ if (cups_fill(fp) < 0)
+ return (-1);
+ }
+#endif /* HAVE_LIBZ */
+
+ /*
+ * Seek forwards or backwards...
+ */
+
+ fp->eof = 0;
+
+ if (pos < fp->bufpos)
+ {
+ /*
+ * Need to seek backwards...
+ */
+
+ DEBUG_puts("2cupsFileSeek: SEEK BACKWARDS");
+
+#ifdef HAVE_LIBZ
+ if (fp->compressed)
+ {
+ inflateEnd(&fp->stream);
+
+ lseek(fp->fd, 0, SEEK_SET);
+ fp->bufpos = 0;
+ fp->pos = 0;
+ fp->ptr = NULL;
+ fp->end = NULL;
+
+ while ((bytes = cups_fill(fp)) > 0)
+ if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
+ break;
+
+ if (bytes <= 0)
+ return (-1);
+
+ fp->ptr = fp->buf + pos - fp->bufpos;
+ fp->pos = pos;
+ }
+ else
+#endif /* HAVE_LIBZ */
+ {
+ fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
+ fp->pos = fp->bufpos;
+ fp->ptr = NULL;
+ fp->end = NULL;
+
+ DEBUG_printf(("2cupsFileSeek: lseek() returned " CUPS_LLFMT,
+ CUPS_LLCAST fp->pos));
+ }
+ }
+ else
+ {
+ /*
+ * Need to seek forwards...
+ */
+
+ DEBUG_puts("2cupsFileSeek: SEEK FORWARDS");
+
+#ifdef HAVE_LIBZ
+ if (fp->compressed)
+ {
+ while ((bytes = cups_fill(fp)) > 0)
+ {
+ if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
+ break;
+ }
+
+ if (bytes <= 0)
+ return (-1);
+
+ fp->ptr = fp->buf + pos - fp->bufpos;
+ fp->pos = pos;
+ }
+ else
+#endif /* HAVE_LIBZ */
+ {
+ fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
+ fp->pos = fp->bufpos;
+ fp->ptr = NULL;
+ fp->end = NULL;
+
+ DEBUG_printf(("2cupsFileSeek: lseek() returned " CUPS_LLFMT,
+ CUPS_LLCAST fp->pos));
+ }
+ }
+
+ DEBUG_printf(("2cupsFileSeek: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ return (fp->pos);
+}
+
+
+/*
+ * 'cupsFileStderr()' - Return a CUPS file associated with stderr.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+cups_file_t * /* O - CUPS file */
+cupsFileStderr(void)
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
+
+
+ /*
+ * Open file descriptor 2 as needed...
+ */
+
+ if (!cg->stdio_files[2])
+ {
+ /*
+ * Flush any pending output on the stdio file...
+ */
+
+ fflush(stderr);
+
+ /*
+ * Open file descriptor 2...
+ */
+
+ if ((cg->stdio_files[2] = cupsFileOpenFd(2, "w")) != NULL)
+ cg->stdio_files[2]->is_stdio = 1;
+ }
+
+ return (cg->stdio_files[2]);
+}
+
+
+/*
+ * 'cupsFileStdin()' - Return a CUPS file associated with stdin.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+cups_file_t * /* O - CUPS file */
+cupsFileStdin(void)
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
+
+
+ /*
+ * Open file descriptor 0 as needed...
+ */
+
+ if (!cg->stdio_files[0])
+ {
+ /*
+ * Open file descriptor 0...
+ */
+
+ if ((cg->stdio_files[0] = cupsFileOpenFd(0, "r")) != NULL)
+ cg->stdio_files[0]->is_stdio = 1;
+ }
+
+ return (cg->stdio_files[0]);
+}
+
+
+/*
+ * 'cupsFileStdout()' - Return a CUPS file associated with stdout.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+cups_file_t * /* O - CUPS file */
+cupsFileStdout(void)
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
+
+
+ /*
+ * Open file descriptor 1 as needed...
+ */
+
+ if (!cg->stdio_files[1])
+ {
+ /*
+ * Flush any pending output on the stdio file...
+ */
+
+ fflush(stdout);
+
+ /*
+ * Open file descriptor 1...
+ */
+
+ if ((cg->stdio_files[1] = cupsFileOpenFd(1, "w")) != NULL)
+ cg->stdio_files[1]->is_stdio = 1;
+ }
+
+ return (cg->stdio_files[1]);
+}
+
+
+/*
+ * 'cupsFileTell()' - Return the current file position.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+off_t /* O - File position */
+cupsFileTell(cups_file_t *fp) /* I - CUPS file */
+{
+ DEBUG_printf(("2cupsFileTell(fp=%p)", fp));
+ DEBUG_printf(("3cupsFileTell: pos=" CUPS_LLFMT,
+ CUPS_LLCAST (fp ? fp->pos : -1)));
+
+ return (fp ? fp->pos : 0);
+}
+
+
+/*
+ * 'cupsFileUnlock()' - Unlock access to a file.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsFileUnlock(cups_file_t *fp) /* I - CUPS file */
+{
+ /*
+ * Range check...
+ */
+
+ DEBUG_printf(("cupsFileUnlock(fp=%p)", fp));
+
+ if (!fp || fp->mode == 's')
+ return (-1);
+
+ /*
+ * Unlock...
+ */
+
+#ifdef WIN32
+ return (_locking(fp->fd, _LK_UNLCK, 0));
+#else
+ return (lockf(fp->fd, F_ULOCK, 0));
+#endif /* WIN32 */
+}
+
+
+/*
+ * 'cupsFileWrite()' - Write to a file.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ssize_t /* O - Number of bytes written or -1 on error */
+cupsFileWrite(cups_file_t *fp, /* I - CUPS file */
+ const char *buf, /* I - Buffer */
+ size_t bytes) /* I - Number of bytes to write */
+{
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("2cupsFileWrite(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")",
+ fp, buf, CUPS_LLCAST bytes));
+
+ if (!fp || !buf || (fp->mode != 'w' && fp->mode != 's'))
+ return (-1);
+
+ if (bytes == 0)
+ return (0);
+
+ /*
+ * Write the buffer...
+ */
+
+ if (fp->mode == 's')
+ {
+ if (cups_write(fp, buf, bytes) < 0)
+ return (-1);
+
+ fp->pos += (off_t)bytes;
+
+ DEBUG_printf(("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ return ((ssize_t)bytes);
+ }
+
+ if ((fp->ptr + bytes) > fp->end)
+ if (cupsFileFlush(fp))
+ return (-1);
+
+ fp->pos += (off_t)bytes;
+
+ DEBUG_printf(("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+
+ if (bytes > sizeof(fp->buf))
+ {
+#ifdef HAVE_LIBZ
+ if (fp->compressed)
+ return (cups_compress(fp, buf, bytes));
+ else
+#endif /* HAVE_LIBZ */
+ return (cups_write(fp, buf, bytes));
+ }
+ else
+ {
+ memcpy(fp->ptr, buf, bytes);
+ fp->ptr += bytes;
+ return ((ssize_t)bytes);
+ }
+}
+
+
+#ifdef HAVE_LIBZ
+/*
+ * 'cups_compress()' - Compress a buffer of data.
+ */
+
+static ssize_t /* O - Number of bytes written or -1 */
+cups_compress(cups_file_t *fp, /* I - CUPS file */
+ const char *buf, /* I - Buffer */
+ size_t bytes) /* I - Number bytes */
+{
+ DEBUG_printf(("7cups_compress(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf,
+ CUPS_LLCAST bytes));
+
+ /*
+ * Update the CRC...
+ */
+
+ fp->crc = crc32(fp->crc, (const Bytef *)buf, bytes);
+
+ /*
+ * Deflate the bytes...
+ */
+
+ fp->stream.next_in = (Bytef *)buf;
+ fp->stream.avail_in = bytes;
+
+ while (fp->stream.avail_in > 0)
+ {
+ /*
+ * Flush the current buffer...
+ */
+
+ DEBUG_printf(("9cups_compress: avail_in=%d, avail_out=%d",
+ fp->stream.avail_in, fp->stream.avail_out));
+
+ if (fp->stream.avail_out < (int)(sizeof(fp->cbuf) / 8))
+ {
+ if (cups_write(fp, (char *)fp->cbuf, fp->stream.next_out - fp->cbuf) < 0)
+ return (-1);
+
+ fp->stream.next_out = fp->cbuf;
+ fp->stream.avail_out = sizeof(fp->cbuf);
+ }
+
+ deflate(&(fp->stream), Z_NO_FLUSH);
+ }
+
+ return (bytes);
+}
+#endif /* HAVE_LIBZ */
+
+
+/*
+ * 'cups_fill()' - Fill the input buffer.
+ */
+
+static ssize_t /* O - Number of bytes or -1 */
+cups_fill(cups_file_t *fp) /* I - CUPS file */
+{
+ ssize_t bytes; /* Number of bytes read */
+#ifdef HAVE_LIBZ
+ int status; /* Decompression status */
+ const unsigned char *ptr, /* Pointer into buffer */
+ *end; /* End of buffer */
+#endif /* HAVE_LIBZ */
+
+
+ DEBUG_printf(("7cups_fill(fp=%p)", fp));
+ DEBUG_printf(("9cups_fill: fp->ptr=%p, fp->end=%p, fp->buf=%p, "
+ "fp->bufpos=" CUPS_LLFMT ", fp->eof=%d",
+ fp->ptr, fp->end, fp->buf, CUPS_LLCAST fp->bufpos, fp->eof));
+
+ if (fp->ptr && fp->end)
+ fp->bufpos += fp->end - fp->buf;
+
+#ifdef HAVE_LIBZ
+ DEBUG_printf(("9cups_fill: fp->compressed=%d", fp->compressed));
+
+ while (!fp->ptr || fp->compressed)
+ {
+ /*
+ * Check to see if we have read any data yet; if not, see if we have a
+ * compressed file...
+ */
+
+ if (!fp->ptr)
+ {
+ /*
+ * Reset the file position in case we are seeking...
+ */
+
+ fp->compressed = 0;
+
+ /*
+ * Read the first bytes in the file to determine if we have a gzip'd
+ * file...
+ */
+
+ if ((bytes = cups_read(fp, (char *)fp->buf, sizeof(fp->buf))) < 0)
+ {
+ /*
+ * Can't read from file!
+ */
+
+ DEBUG_printf(("9cups_fill: cups_read() returned " CUPS_LLFMT,
+ CUPS_LLCAST bytes));
+
+ return (-1);
+ }
+
+ if (bytes < 10 || fp->buf[0] != 0x1f ||
+ (fp->buf[1] & 255) != 0x8b ||
+ fp->buf[2] != 8 || (fp->buf[3] & 0xe0) != 0)
+ {
+ /*
+ * Not a gzip'd file!
+ */
+
+ fp->ptr = fp->buf;
+ fp->end = fp->buf + bytes;
+
+ DEBUG_printf(("9cups_fill: Returning " CUPS_LLFMT,
+ CUPS_LLCAST bytes));
+
+ return (bytes);
+ }
+
+ /*
+ * Parse header junk: extra data, original name, and comment...
+ */
+
+ ptr = (unsigned char *)fp->buf + 10;
+ end = (unsigned char *)fp->buf + bytes;
+
+ if (fp->buf[3] & 0x04)
+ {
+ /*
+ * Skip extra data...
+ */
+
+ if ((ptr + 2) > end)
+ {
+ /*
+ * Can't read from file!
+ */
+
+ return (-1);
+ }
+
+ bytes = ((unsigned char)ptr[1] << 8) | (unsigned char)ptr[0];
+ ptr += 2 + bytes;
+
+ if (ptr > end)
+ {
+ /*
+ * Can't read from file!
+ */
+
+ return (-1);
+ }
+ }
+
+ if (fp->buf[3] & 0x08)
+ {
+ /*
+ * Skip original name data...
+ */
+
+ while (ptr < end && *ptr)
+ ptr ++;
+
+ if (ptr < end)
+ ptr ++;
+ else
+ {
+ /*
+ * Can't read from file!
+ */
+
+ return (-1);
+ }
+ }
+
+ if (fp->buf[3] & 0x10)
+ {
+ /*
+ * Skip comment data...
+ */
+
+ while (ptr < end && *ptr)
+ ptr ++;
+
+ if (ptr < end)
+ ptr ++;
+ else
+ {
+ /*
+ * Can't read from file!
+ */
+
+ return (-1);
+ }
+ }
+
+ if (fp->buf[3] & 0x02)
+ {
+ /*
+ * Skip header CRC data...
+ */
+
+ ptr += 2;
+
+ if (ptr > end)
+ {
+ /*
+ * Can't read from file!
+ */
+
+ return (-1);
+ }
+ }
+
+ /*
+ * Copy the flate-compressed data to the compression buffer...
+ */
+
+ if ((bytes = end - ptr) > 0)
+ memcpy(fp->cbuf, ptr, bytes);
+
+ /*
+ * Setup the decompressor data...
+ */
+
+ fp->stream.zalloc = (alloc_func)0;
+ fp->stream.zfree = (free_func)0;
+ fp->stream.opaque = (voidpf)0;
+ fp->stream.next_in = (Bytef *)fp->cbuf;
+ fp->stream.next_out = NULL;
+ fp->stream.avail_in = bytes;
+ fp->stream.avail_out = 0;
+ fp->crc = crc32(0L, Z_NULL, 0);
+
+ if (inflateInit2(&(fp->stream), -15) != Z_OK)
+ return (-1);
+
+ fp->compressed = 1;
+ }
+
+ if (fp->compressed)
+ {
+ /*
+ * If we have reached end-of-file, return immediately...
+ */
+
+ if (fp->eof)
+ return (-1);
+
+ /*
+ * Fill the decompression buffer as needed...
+ */
+
+ if (fp->stream.avail_in == 0)
+ {
+ if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0)
+ return (-1);
+
+ fp->stream.next_in = fp->cbuf;
+ fp->stream.avail_in = bytes;
+ }
+
+ /*
+ * Decompress data from the buffer...
+ */
+
+ fp->stream.next_out = (Bytef *)fp->buf;
+ fp->stream.avail_out = sizeof(fp->buf);
+
+ status = inflate(&(fp->stream), Z_NO_FLUSH);
+
+ if (fp->stream.next_out > (Bytef *)fp->buf)
+ fp->crc = crc32(fp->crc, (Bytef *)fp->buf,
+ fp->stream.next_out - (Bytef *)fp->buf);
+
+ if (status == Z_STREAM_END)
+ {
+ /*
+ * Read the CRC and length...
+ */
+
+ unsigned char trailer[8]; /* Trailer bytes */
+ uLong tcrc; /* Trailer CRC */
+
+
+ if (read(fp->fd, trailer, sizeof(trailer)) < sizeof(trailer))
+ {
+ /*
+ * Can't get it, so mark end-of-file...
+ */
+
+ fp->eof = 1;
+ }
+ else
+ {
+ tcrc = (((((trailer[3] << 8) | trailer[2]) << 8) | trailer[1]) << 8) |
+ trailer[0];
+
+ if (tcrc != fp->crc)
+ {
+ /*
+ * Bad CRC, mark end-of-file...
+ */
+
+ DEBUG_printf(("9cups_fill: tcrc=%08x, fp->crc=%08x",
+ (unsigned int)tcrc, (unsigned int)fp->crc));
+
+ fp->eof = 1;
+
+ return (-1);
+ }
+
+ /*
+ * Otherwise, reset the compressed flag so that we re-read the
+ * file header...
+ */
+
+ fp->compressed = 0;
+ }
+ }
+
+ bytes = sizeof(fp->buf) - fp->stream.avail_out;
+
+ /*
+ * Return the decompressed data...
+ */
+
+ fp->ptr = fp->buf;
+ fp->end = fp->buf + bytes;
+
+ if (bytes)
+ return (bytes);
+ }
+ }
+#endif /* HAVE_LIBZ */
+
+ /*
+ * Read a buffer's full of data...
+ */
+
+ if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0)
+ {
+ /*
+ * Can't read from file!
+ */
+
+ fp->eof = 1;
+ fp->ptr = fp->buf;
+ fp->end = fp->buf;
+
+ return (-1);
+ }
+
+ /*
+ * Return the bytes we read...
+ */
+
+ fp->eof = 0;
+ fp->ptr = fp->buf;
+ fp->end = fp->buf + bytes;
+
+ return (bytes);
+}
+
+
+/*
+ * 'cups_open()' - Safely open a file for writing.
+ *
+ * We don't allow appending to directories or files that are hard-linked or
+ * symlinked.
+ */
+
+static int /* O - File descriptor or -1 otherwise */
+cups_open(const char *filename, /* I - Filename */
+ int mode) /* I - Open mode */
+{
+ int fd; /* File descriptor */
+ struct stat fileinfo; /* File information */
+#ifndef WIN32
+ struct stat linkinfo; /* Link information */
+#endif /* !WIN32 */
+
+
+ /*
+ * Open the file...
+ */
+
+ if ((fd = open(filename, mode, 0666)) < 0)
+ return (-1);
+
+ /*
+ * Then verify that the file descriptor doesn't point to a directory or hard-
+ * linked file.
+ */
+
+ if (fstat(fd, &fileinfo))
+ {
+ close(fd);
+ return (-1);
+ }
+
+ if (fileinfo.st_nlink != 1)
+ {
+ close(fd);
+ errno = EPERM;
+ return (-1);
+ }
+
+#ifdef WIN32
+ if (fileinfo.st_mode & _S_IFDIR)
+#else
+ if (S_ISDIR(fileinfo.st_mode))
+#endif /* WIN32 */
+ {
+ close(fd);
+ errno = EISDIR;
+ return (-1);
+ }
+
+#ifndef WIN32
+ /*
+ * Then use lstat to determine whether the filename is a symlink...
+ */
+
+ if (lstat(filename, &linkinfo))
+ {
+ close(fd);
+ return (-1);
+ }
+
+ if (S_ISLNK(linkinfo.st_mode) ||
+ fileinfo.st_dev != linkinfo.st_dev ||
+ fileinfo.st_ino != linkinfo.st_ino ||
+#ifdef HAVE_ST_GEN
+ fileinfo.st_gen != linkinfo.st_gen ||
+#endif /* HAVE_ST_GEN */
+ fileinfo.st_nlink != linkinfo.st_nlink ||
+ fileinfo.st_mode != linkinfo.st_mode)
+ {
+ /*
+ * Yes, don't allow!
+ */
+
+ close(fd);
+ errno = EPERM;
+ return (-1);
+ }
+#endif /* !WIN32 */
+
+ return (fd);
+}
+
+
+/*
+ * 'cups_read()' - Read from a file descriptor.
+ */
+
+static ssize_t /* O - Number of bytes read or -1 */
+cups_read(cups_file_t *fp, /* I - CUPS file */
+ char *buf, /* I - Buffer */
+ size_t bytes) /* I - Number bytes */
+{
+ ssize_t total; /* Total bytes read */
+
+
+ DEBUG_printf(("7cups_read(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf,
+ CUPS_LLCAST bytes));
+
+ /*
+ * Loop until we read at least 0 bytes...
+ */
+
+ for (;;)
+ {
+#ifdef WIN32
+ if (fp->mode == 's')
+ total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0);
+ else
+ total = (ssize_t)read(fp->fd, buf, (unsigned)bytes);
+#else
+ if (fp->mode == 's')
+ total = recv(fp->fd, buf, bytes, 0);
+ else
+ total = read(fp->fd, buf, bytes);
+#endif /* WIN32 */
+
+ DEBUG_printf(("9cups_read: total=" CUPS_LLFMT, CUPS_LLCAST total));
+
+ if (total >= 0)
+ break;
+
+ /*
+ * Reads can be interrupted by signals and unavailable resources...
+ */
+
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ else
+ return (-1);
+ }
+
+ /*
+ * Return the total number of bytes read...
+ */
+
+ return (total);
+}
+
+
+/*
+ * 'cups_write()' - Write to a file descriptor.
+ */
+
+static ssize_t /* O - Number of bytes written or -1 */
+cups_write(cups_file_t *fp, /* I - CUPS file */
+ const char *buf, /* I - Buffer */
+ size_t bytes) /* I - Number bytes */
+{
+ size_t total; /* Total bytes written */
+ ssize_t count; /* Count this time */
+
+
+ DEBUG_printf(("7cups_write(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf,
+ CUPS_LLCAST bytes));
+
+ /*
+ * Loop until all bytes are written...
+ */
+
+ total = 0;
+ while (bytes > 0)
+ {
+#ifdef WIN32
+ if (fp->mode == 's')
+ count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0);
+ else
+ count = (ssize_t)write(fp->fd, buf, (unsigned)bytes);
+#else
+ if (fp->mode == 's')
+ count = send(fp->fd, buf, bytes, 0);
+ else
+ count = write(fp->fd, buf, bytes);
+#endif /* WIN32 */
+
+ DEBUG_printf(("9cups_write: count=" CUPS_LLFMT, CUPS_LLCAST count));
+
+ if (count < 0)
+ {
+ /*
+ * Writes can be interrupted by signals and unavailable resources...
+ */
+
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ else
+ return (-1);
+ }
+
+ /*
+ * Update the counts for the last write call...
+ */
+
+ bytes -= count;
+ total += count;
+ buf += count;
+ }
+
+ /*
+ * Return the total number of bytes written...
+ */
+
+ return ((ssize_t)total);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/file.h b/cups/file.h
new file mode 100644
index 000000000..6c9870109
--- /dev/null
+++ b/cups/file.h
@@ -0,0 +1,112 @@
+/*
+ * "$Id$"
+ *
+ * Public file definitions for CUPS.
+ *
+ * Since stdio files max out at 256 files on many systems, we have to
+ * write similar functions without this limit. At the same time, using
+ * our own file functions allows us to provide transparent support of
+ * gzip'd print files, PPD files, etc.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPS_FILE_H_
+# define _CUPS_FILE_H_
+
+
+/*
+ * Include necessary headers...
+ */
+
+# include "versioning.h"
+# include <stddef.h>
+# include <sys/types.h>
+# if defined(WIN32) && !defined(__CUPS_SSIZE_T_DEFINED)
+# define __CUPS_SSIZE_T_DEFINED
+/* Windows does not support the ssize_t type, so map it to off_t... */
+typedef off_t ssize_t; /* @private@ */
+# endif /* WIN32 && !__CUPS_SSIZE_T_DEFINED */
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * CUPS file definitions...
+ */
+
+# define CUPS_FILE_NONE 0 /* No compression */
+# define CUPS_FILE_GZIP 1 /* GZIP compression */
+
+
+/*
+ * Types and structures...
+ */
+
+typedef struct _cups_file_s cups_file_t;/**** CUPS file type ****/
+
+
+/*
+ * Prototypes...
+ */
+
+extern int cupsFileClose(cups_file_t *fp) _CUPS_API_1_2;
+extern int cupsFileCompression(cups_file_t *fp) _CUPS_API_1_2;
+extern int cupsFileEOF(cups_file_t *fp) _CUPS_API_1_2;
+extern const char *cupsFileFind(const char *filename, const char *path,
+ int executable, char *buffer,
+ int bufsize) _CUPS_API_1_2;
+extern int cupsFileFlush(cups_file_t *fp) _CUPS_API_1_2;
+extern int cupsFileGetChar(cups_file_t *fp) _CUPS_API_1_2;
+extern char *cupsFileGetConf(cups_file_t *fp, char *buf, size_t buflen,
+ char **value, int *linenum) _CUPS_API_1_2;
+extern size_t cupsFileGetLine(cups_file_t *fp, char *buf,
+ size_t buflen) _CUPS_API_1_2;
+extern char *cupsFileGets(cups_file_t *fp, char *buf, size_t buflen) _CUPS_API_1_2;
+extern int cupsFileLock(cups_file_t *fp, int block) _CUPS_API_1_2;
+extern int cupsFileNumber(cups_file_t *fp) _CUPS_API_1_2;
+extern cups_file_t *cupsFileOpen(const char *filename, const char *mode) _CUPS_API_1_2;
+extern cups_file_t *cupsFileOpenFd(int fd, const char *mode) _CUPS_API_1_2;
+extern int cupsFilePeekChar(cups_file_t *fp) _CUPS_API_1_2;
+extern int cupsFilePrintf(cups_file_t *fp, const char *format, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+#endif /* __GNUC__ */
+_CUPS_API_1_2;
+extern int cupsFilePutChar(cups_file_t *fp, int c) _CUPS_API_1_2;
+extern ssize_t cupsFilePutConf(cups_file_t *fp, const char *directive,
+ const char *value) _CUPS_API_1_4;
+extern int cupsFilePuts(cups_file_t *fp, const char *s) _CUPS_API_1_2;
+extern ssize_t cupsFileRead(cups_file_t *fp, char *buf, size_t bytes) _CUPS_API_1_2;
+extern off_t cupsFileRewind(cups_file_t *fp) _CUPS_API_1_2;
+extern off_t cupsFileSeek(cups_file_t *fp, off_t pos) _CUPS_API_1_2;
+extern cups_file_t *cupsFileStderr(void) _CUPS_API_1_2;
+extern cups_file_t *cupsFileStdin(void) _CUPS_API_1_2;
+extern cups_file_t *cupsFileStdout(void) _CUPS_API_1_2;
+extern off_t cupsFileTell(cups_file_t *fp) _CUPS_API_1_2;
+extern int cupsFileUnlock(cups_file_t *fp) _CUPS_API_1_2;
+extern ssize_t cupsFileWrite(cups_file_t *fp, const char *buf, size_t bytes) _CUPS_API_1_2;
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_FILE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/getdevices.c b/cups/getdevices.c
new file mode 100644
index 000000000..a74a593c7
--- /dev/null
+++ b/cups/getdevices.c
@@ -0,0 +1,283 @@
+/*
+ * "$Id$"
+ *
+ * cupsGetDevices implementation for CUPS.
+ *
+ * Copyright 2008-2010 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsGetDevices() - Get available printer devices.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+
+
+/*
+ * 'cupsGetDevices()' - Get available printer devices.
+ *
+ * This function sends a CUPS-Get-Devices request and streams the discovered
+ * devices to the specified callback function. The "timeout" parameter controls
+ * how long the request lasts, while the "include_schemes" and "exclude_schemes"
+ * parameters provide comma-delimited lists of backends to include or omit from
+ * the request respectively.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+ipp_status_t /* O - Request status - @code IPP_OK@ on success. */
+cupsGetDevices(
+ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ int timeout, /* I - Timeout in seconds or @code CUPS_TIMEOUT_DEFAULT@ */
+ const char *include_schemes, /* I - Comma-separated URI schemes to include or @code CUPS_INCLUDE_ALL@ */
+ const char *exclude_schemes, /* I - Comma-separated URI schemes to exclude or @code CUPS_EXCLUDE_NONE@ */
+ cups_device_cb_t callback, /* I - Callback function */
+ void *user_data) /* I - User data pointer */
+{
+ ipp_t *request, /* CUPS-Get-Devices request */
+ *response; /* CUPS-Get-Devices response */
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *device_class, /* device-class value */
+ *device_id, /* device-id value */
+ *device_info, /* device-info value */
+ *device_location, /* device-location value */
+ *device_make_and_model, /* device-make-and-model value */
+ *device_uri; /* device-uri value */
+ int blocking; /* Current blocking-IO mode */
+ cups_option_t option; /* in/exclude-schemes option */
+ http_status_t status; /* HTTP status of request */
+ ipp_state_t state; /* IPP response state */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("cupsGetDevices(http=%p, timeout=%d, include_schemes=\"%s\", "
+ "exclude_schemes=\"%s\", callback=%p, user_data=%p)", http,
+ timeout, include_schemes, exclude_schemes, callback,
+ user_data));
+
+ if (!callback)
+ return (IPP_INTERNAL_ERROR);
+
+ if (!http)
+ http = _cupsConnect();
+
+ if (!http)
+ return (IPP_SERVICE_UNAVAILABLE);
+
+ /*
+ * Create a CUPS-Get-Devices request...
+ */
+
+ request = ippNewRequest(CUPS_GET_DEVICES);
+
+ if (timeout > 0)
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "timeout",
+ timeout);
+
+ if (include_schemes)
+ {
+ option.name = "include-schemes";
+ option.value = (char *)include_schemes;
+
+ cupsEncodeOptions2(request, 1, &option, IPP_TAG_OPERATION);
+ }
+
+ if (exclude_schemes)
+ {
+ option.name = "exclude-schemes";
+ option.value = (char *)exclude_schemes;
+
+ cupsEncodeOptions2(request, 1, &option, IPP_TAG_OPERATION);
+ }
+
+ /*
+ * Send the request and do any necessary authentication...
+ */
+
+ do
+ {
+ DEBUG_puts("2cupsGetDevices: Sending request...");
+ status = cupsSendRequest(http, request, "/", ippLength(request));
+
+ DEBUG_puts("2cupsGetDevices: Waiting for response status...");
+ while (status == HTTP_CONTINUE)
+ status = httpUpdate(http);
+
+ if (status != HTTP_OK)
+ {
+ httpFlush(http);
+
+ if (status == HTTP_UNAUTHORIZED)
+ {
+ /*
+ * See if we can do authentication...
+ */
+
+ DEBUG_puts("2cupsGetDevices: Need authorization...");
+
+ if (!cupsDoAuthentication(http, "POST", "/"))
+ httpReconnect(http);
+ else
+ {
+ status = HTTP_AUTHORIZATION_CANCELED;
+ break;
+ }
+ }
+
+#ifdef HAVE_SSL
+ else if (status == HTTP_UPGRADE_REQUIRED)
+ {
+ /*
+ * Force a reconnect with encryption...
+ */
+
+ DEBUG_puts("2cupsGetDevices: Need encryption...");
+
+ if (!httpReconnect(http))
+ httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
+ }
+#endif /* HAVE_SSL */
+ }
+ }
+ while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED);
+
+ DEBUG_printf(("2cupsGetDevices: status=%d", status));
+
+ ippDelete(request);
+
+ if (status != HTTP_OK)
+ {
+ _cupsSetHTTPError(status);
+ return (cupsLastError());
+ }
+
+ /*
+ * Read the response in non-blocking mode...
+ */
+
+ blocking = httpGetBlocking(http);
+ httpBlocking(http, 0);
+
+ response = ippNew();
+ device_class = NULL;
+ device_id = NULL;
+ device_info = NULL;
+ device_location = "";
+ device_make_and_model = NULL;
+ device_uri = NULL;
+ attr = NULL;
+
+ DEBUG_puts("2cupsGetDevices: Reading response...");
+
+ do
+ {
+ if ((state = ippRead(http, response)) == IPP_ERROR)
+ break;
+
+ DEBUG_printf(("2cupsGetDevices: state=%d, response->last=%p", state,
+ response->last));
+
+ if (!response->attrs)
+ continue;
+
+ while (attr != response->last)
+ {
+ if (!attr)
+ attr = response->attrs;
+ else
+ attr = attr->next;
+
+ DEBUG_printf(("2cupsGetDevices: attr->name=\"%s\", attr->value_tag=%d",
+ attr->name, attr->value_tag));
+
+ if (!attr->name)
+ {
+ if (device_class && device_id && device_info && device_make_and_model &&
+ device_uri)
+ (*callback)(device_class, device_id, device_info,
+ device_make_and_model, device_uri, device_location,
+ user_data);
+
+ device_class = NULL;
+ device_id = NULL;
+ device_info = NULL;
+ device_location = "";
+ device_make_and_model = NULL;
+ device_uri = NULL;
+ }
+ else if (!strcmp(attr->name, "device-class") &&
+ attr->value_tag == IPP_TAG_KEYWORD)
+ device_class = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "device-id") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ device_id = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "device-info") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ device_info = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "device-location") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ device_location = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "device-make-and-model") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ device_make_and_model = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "device-uri") &&
+ attr->value_tag == IPP_TAG_URI)
+ device_uri = attr->values[0].string.text;
+ }
+ }
+ while (state != IPP_DATA);
+
+ DEBUG_printf(("2cupsGetDevices: state=%d, response->last=%p", state,
+ response->last));
+
+ if (device_class && device_id && device_info && device_make_and_model &&
+ device_uri)
+ (*callback)(device_class, device_id, device_info,
+ device_make_and_model, device_uri, device_location, user_data);
+
+ /*
+ * Set the IPP status and return...
+ */
+
+ httpBlocking(http, blocking);
+ httpFlush(http);
+
+ if (status == HTTP_ERROR)
+ _cupsSetError(IPP_ERROR, NULL, 0);
+ else
+ {
+ attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
+
+ DEBUG_printf(("cupsGetDevices: status-code=%s, status-message=\"%s\"",
+ ippErrorString(response->request.status.status_code),
+ attr ? attr->values[0].string.text : ""));
+
+ _cupsSetError(response->request.status.status_code,
+ attr ? attr->values[0].string.text :
+ ippErrorString(response->request.status.status_code), 0);
+ }
+
+ ippDelete(response);
+
+ return (cupsLastError());
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/getifaddrs.c b/cups/getifaddrs.c
new file mode 100644
index 000000000..8111e224d
--- /dev/null
+++ b/cups/getifaddrs.c
@@ -0,0 +1,266 @@
+/*
+ * "$Id$"
+ *
+ * Network interface functions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * _cups_getifaddrs() - Get a list of network interfaces on the system.
+ * _cups_freeifaddrs() - Free an interface list...
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "http-private.h"
+
+
+#ifndef HAVE_GETIFADDRS
+/*
+ * '_cups_getifaddrs()' - Get a list of network interfaces on the system.
+ */
+
+int /* O - 0 on success, -1 on error */
+_cups_getifaddrs(struct ifaddrs **addrs)/* O - List of interfaces */
+{
+ int sock; /* Socket */
+ char buffer[65536], /* Buffer for address info */
+ *bufptr, /* Pointer into buffer */
+ *bufend; /* End of buffer */
+ struct ifconf conf; /* Interface configurations */
+ struct sockaddr addr; /* Address data */
+ struct ifreq *ifp; /* Interface data */
+ int ifpsize; /* Size of interface data */
+ struct ifaddrs *temp; /* Pointer to current interface */
+ struct ifreq request; /* Interface request */
+
+
+ /*
+ * Start with an empty list...
+ */
+
+ if (addrs == NULL)
+ return (-1);
+
+ *addrs = NULL;
+
+ /*
+ * Create a UDP socket to get the interface data...
+ */
+
+ memset (&addr, 0, sizeof(addr));
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return (-1);
+
+ /*
+ * Try to get the list of interfaces...
+ */
+
+ conf.ifc_len = sizeof(buffer);
+ conf.ifc_buf = buffer;
+
+ if (ioctl(sock, SIOCGIFCONF, &conf) < 0)
+ {
+ /*
+ * Couldn't get the list of interfaces...
+ */
+
+ close(sock);
+ return (-1);
+ }
+
+ /*
+ * OK, got the list of interfaces, now lets step through the
+ * buffer to pull them out...
+ */
+
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+# define sockaddr_len(a) ((a)->sa_len)
+# else
+# define sockaddr_len(a) (sizeof(struct sockaddr))
+# endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+
+ for (bufptr = buffer, bufend = buffer + conf.ifc_len;
+ bufptr < bufend;
+ bufptr += ifpsize)
+ {
+ /*
+ * Get the current interface information...
+ */
+
+ ifp = (struct ifreq *)bufptr;
+ ifpsize = sizeof(ifp->ifr_name) + sockaddr_len(&(ifp->ifr_addr));
+
+ if (ifpsize < sizeof(struct ifreq))
+ ifpsize = sizeof(struct ifreq);
+
+ memset(&request, 0, sizeof(request));
+ memcpy(request.ifr_name, ifp->ifr_name, sizeof(ifp->ifr_name));
+
+ /*
+ * Check the status of the interface...
+ */
+
+ if (ioctl(sock, SIOCGIFFLAGS, &request) < 0)
+ continue;
+
+ /*
+ * Allocate memory for a single interface record...
+ */
+
+ if ((temp = calloc(1, sizeof(struct ifaddrs))) == NULL)
+ {
+ /*
+ * Unable to allocate memory...
+ */
+
+ close(sock);
+ return (-1);
+ }
+
+ /*
+ * Add this record to the front of the list and copy the name, flags,
+ * and network address...
+ */
+
+ temp->ifa_next = *addrs;
+ *addrs = temp;
+ temp->ifa_name = strdup(ifp->ifr_name);
+ temp->ifa_flags = request.ifr_flags;
+ if ((temp->ifa_addr = calloc(1, sockaddr_len(&(ifp->ifr_addr)))) != NULL)
+ memcpy(temp->ifa_addr, &(ifp->ifr_addr), sockaddr_len(&(ifp->ifr_addr)));
+
+ /*
+ * Try to get the netmask for the interface...
+ */
+
+ if (!ioctl(sock, SIOCGIFNETMASK, &request))
+ {
+ /*
+ * Got it, make a copy...
+ */
+
+ if ((temp->ifa_netmask = calloc(1, sizeof(request.ifr_netmask))) != NULL)
+ memcpy(temp->ifa_netmask, &(request.ifr_netmask),
+ sizeof(request.ifr_netmask));
+ }
+
+ /*
+ * Then get the broadcast or point-to-point (destination) address,
+ * if applicable...
+ */
+
+ if (temp->ifa_flags & IFF_BROADCAST)
+ {
+ /*
+ * Have a broadcast address, so get it!
+ */
+
+ if (!ioctl(sock, SIOCGIFBRDADDR, &request))
+ {
+ /*
+ * Got it, make a copy...
+ */
+
+ if ((temp->ifa_broadaddr =
+ calloc(1, sizeof(request.ifr_broadaddr))) != NULL)
+ memcpy(temp->ifa_broadaddr, &(request.ifr_broadaddr),
+ sizeof(request.ifr_broadaddr));
+ }
+ }
+ else if (temp->ifa_flags & IFF_POINTOPOINT)
+ {
+ /*
+ * Point-to-point interface; grab the remote address...
+ */
+
+ if (!ioctl(sock, SIOCGIFDSTADDR, &request))
+ {
+ temp->ifa_dstaddr = malloc(sizeof(request.ifr_dstaddr));
+ memcpy(temp->ifa_dstaddr, &(request.ifr_dstaddr),
+ sizeof(request.ifr_dstaddr));
+ }
+ }
+ }
+
+ /*
+ * OK, we're done with the socket, close it and return 0...
+ */
+
+ close(sock);
+
+ return (0);
+}
+
+
+/*
+ * '_cups_freeifaddrs()' - Free an interface list...
+ */
+
+void
+_cups_freeifaddrs(struct ifaddrs *addrs)/* I - Interface list to free */
+{
+ struct ifaddrs *next; /* Next interface in list */
+
+
+ while (addrs != NULL)
+ {
+ /*
+ * Make a copy of the next interface pointer...
+ */
+
+ next = addrs->ifa_next;
+
+ /*
+ * Free data values as needed...
+ */
+
+ if (addrs->ifa_name)
+ {
+ free(addrs->ifa_name);
+ addrs->ifa_name = NULL;
+ }
+
+ if (addrs->ifa_addr)
+ {
+ free(addrs->ifa_addr);
+ addrs->ifa_addr = NULL;
+ }
+
+ if (addrs->ifa_netmask)
+ {
+ free(addrs->ifa_netmask);
+ addrs->ifa_netmask = NULL;
+ }
+
+ if (addrs->ifa_dstaddr)
+ {
+ free(addrs->ifa_dstaddr);
+ addrs->ifa_dstaddr = NULL;
+ }
+
+ /*
+ * Free this node and continue to the next...
+ */
+
+ free(addrs);
+
+ addrs = next;
+ }
+}
+#endif /* !HAVE_GETIFADDRS */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/getputfile.c b/cups/getputfile.c
new file mode 100644
index 000000000..80f6e7be4
--- /dev/null
+++ b/cups/getputfile.c
@@ -0,0 +1,502 @@
+/*
+ * "$Id$"
+ *
+ * Get/put file functions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsGetFd() - Get a file from the server.
+ * cupsGetFile() - Get a file from the server.
+ * cupsPutFd() - Put a file on the server.
+ * cupsPutFile() - Put a file on the server.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include <fcntl.h>
+#include <sys/stat.h>
+#if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+#else
+# include <unistd.h>
+#endif /* WIN32 || __EMX__ */
+
+
+/*
+ * 'cupsGetFd()' - Get a file from the server.
+ *
+ * This function returns @code HTTP_OK@ when the file is successfully retrieved.
+ *
+ * @since CUPS 1.1.20/Mac OS X 10.4@
+ */
+
+http_status_t /* O - HTTP status */
+cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *resource, /* I - Resource name */
+ int fd) /* I - File descriptor */
+{
+ int bytes; /* Number of bytes read */
+ char buffer[8192]; /* Buffer for file */
+ http_status_t status; /* HTTP status from server */
+ char if_modified_since[HTTP_MAX_VALUE];
+ /* If-Modified-Since header */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("cupsGetFd(http=%p, resource=\"%s\", fd=%d)", http,
+ resource, fd));
+
+ if (!resource || fd < 0)
+ {
+ if (http)
+ http->error = EINVAL;
+
+ return (HTTP_ERROR);
+ }
+
+ if (!http)
+ if ((http = _cupsConnect()) == NULL)
+ return (HTTP_SERVICE_UNAVAILABLE);
+
+ /*
+ * Then send GET requests to the HTTP server...
+ */
+
+ strlcpy(if_modified_since, httpGetField(http, HTTP_FIELD_IF_MODIFIED_SINCE),
+ sizeof(if_modified_since));
+
+ do
+ {
+ httpClearFields(http);
+ httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
+ httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE, if_modified_since);
+
+ if (httpGet(http, resource))
+ {
+ if (httpReconnect(http))
+ {
+ status = HTTP_ERROR;
+ break;
+ }
+ else
+ {
+ status = HTTP_UNAUTHORIZED;
+ continue;
+ }
+ }
+
+ while ((status = httpUpdate(http)) == HTTP_CONTINUE);
+
+ if (status == HTTP_UNAUTHORIZED)
+ {
+ /*
+ * Flush any error message...
+ */
+
+ httpFlush(http);
+
+ /*
+ * See if we can do authentication...
+ */
+
+ if (cupsDoAuthentication(http, "GET", resource))
+ {
+ status = HTTP_AUTHORIZATION_CANCELED;
+ break;
+ }
+
+ if (httpReconnect(http))
+ {
+ status = HTTP_ERROR;
+ break;
+ }
+
+ continue;
+ }
+#ifdef HAVE_SSL
+ else if (status == HTTP_UPGRADE_REQUIRED)
+ {
+ /* Flush any error message... */
+ httpFlush(http);
+
+ /* Reconnect... */
+ if (httpReconnect(http))
+ {
+ status = HTTP_ERROR;
+ break;
+ }
+
+ /* Upgrade with encryption... */
+ httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
+
+ /* Try again, this time with encryption enabled... */
+ continue;
+ }
+#endif /* HAVE_SSL */
+ }
+ while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED);
+
+ /*
+ * See if we actually got the file or an error...
+ */
+
+ if (status == HTTP_OK)
+ {
+ /*
+ * Yes, copy the file...
+ */
+
+ while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
+ write(fd, buffer, bytes);
+ }
+ else
+ {
+ _cupsSetHTTPError(status);
+ httpFlush(http);
+ }
+
+ /*
+ * Return the request status...
+ */
+
+ DEBUG_printf(("1cupsGetFd: Returning %d...", status));
+
+ return (status);
+}
+
+
+/*
+ * 'cupsGetFile()' - Get a file from the server.
+ *
+ * This function returns @code HTTP_OK@ when the file is successfully retrieved.
+ *
+ * @since CUPS 1.1.20/Mac OS X 10.4@
+ */
+
+http_status_t /* O - HTTP status */
+cupsGetFile(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *resource, /* I - Resource name */
+ const char *filename) /* I - Filename */
+{
+ int fd; /* File descriptor */
+ http_status_t status; /* Status */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!http || !resource || !filename)
+ {
+ if (http)
+ http->error = EINVAL;
+
+ return (HTTP_ERROR);
+ }
+
+ /*
+ * Create the file...
+ */
+
+ if ((fd = open(filename, O_WRONLY | O_EXCL | O_TRUNC)) < 0)
+ {
+ /*
+ * Couldn't open the file!
+ */
+
+ http->error = errno;
+
+ return (HTTP_ERROR);
+ }
+
+ /*
+ * Get the file...
+ */
+
+ status = cupsGetFd(http, resource, fd);
+
+ /*
+ * If the file couldn't be gotten, then remove the file...
+ */
+
+ close(fd);
+
+ if (status != HTTP_OK)
+ unlink(filename);
+
+ /*
+ * Return the HTTP status code...
+ */
+
+ return (status);
+}
+
+
+/*
+ * 'cupsPutFd()' - Put a file on the server.
+ *
+ * This function returns @code HTTP_CREATED@ when the file is stored
+ * successfully.
+ *
+ * @since CUPS 1.1.20/Mac OS X 10.4@
+ */
+
+http_status_t /* O - HTTP status */
+cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *resource, /* I - Resource name */
+ int fd) /* I - File descriptor */
+{
+ int bytes, /* Number of bytes read */
+ retries; /* Number of retries */
+ char buffer[8192]; /* Buffer for file */
+ http_status_t status; /* HTTP status from server */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("cupsPutFd(http=%p, resource=\"%s\", fd=%d)", http,
+ resource, fd));
+
+ if (!resource || fd < 0)
+ {
+ if (http)
+ http->error = EINVAL;
+
+ return (HTTP_ERROR);
+ }
+
+ if (!http)
+ if ((http = _cupsConnect()) == NULL)
+ return (HTTP_SERVICE_UNAVAILABLE);
+
+ /*
+ * Then send PUT requests to the HTTP server...
+ */
+
+ retries = 0;
+
+ do
+ {
+ DEBUG_printf(("2cupsPutFd: starting attempt, authstring=\"%s\"...",
+ http->authstring));
+
+ httpClearFields(http);
+ httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
+ httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked");
+ httpSetExpect(http, HTTP_CONTINUE);
+
+ if (httpPut(http, resource))
+ {
+ if (httpReconnect(http))
+ {
+ status = HTTP_ERROR;
+ break;
+ }
+ else
+ {
+ status = HTTP_UNAUTHORIZED;
+ continue;
+ }
+ }
+
+ /*
+ * Wait up to 1 second for a 100-continue response...
+ */
+
+ if (httpWait(http, 1000))
+ status = httpUpdate(http);
+ else
+ status = HTTP_CONTINUE;
+
+ if (status == HTTP_CONTINUE)
+ {
+ /*
+ * Copy the file...
+ */
+
+ lseek(fd, 0, SEEK_SET);
+
+ while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
+ if (httpCheck(http))
+ {
+ if ((status = httpUpdate(http)) != HTTP_CONTINUE)
+ break;
+ }
+ else
+ httpWrite2(http, buffer, bytes);
+ }
+
+ if (status == HTTP_CONTINUE)
+ {
+ httpWrite2(http, buffer, 0);
+
+ while ((status = httpUpdate(http)) == HTTP_CONTINUE);
+ }
+
+ if (status == HTTP_ERROR && !retries)
+ {
+ DEBUG_printf(("2cupsPutFd: retry on status %d", status));
+
+ retries ++;
+
+ /* Flush any error message... */
+ httpFlush(http);
+
+ /* Reconnect... */
+ if (httpReconnect(http))
+ {
+ status = HTTP_ERROR;
+ break;
+ }
+
+ /* Try again... */
+ continue;
+ }
+
+ DEBUG_printf(("2cupsPutFd: status=%d", status));
+
+ if (status == HTTP_UNAUTHORIZED)
+ {
+ /*
+ * Flush any error message...
+ */
+
+ httpFlush(http);
+
+ /*
+ * See if we can do authentication...
+ */
+
+ if (cupsDoAuthentication(http, "PUT", resource))
+ {
+ status = HTTP_AUTHORIZATION_CANCELED;
+ break;
+ }
+
+ if (httpReconnect(http))
+ {
+ status = HTTP_ERROR;
+ break;
+ }
+
+ continue;
+ }
+#ifdef HAVE_SSL
+ else if (status == HTTP_UPGRADE_REQUIRED)
+ {
+ /* Flush any error message... */
+ httpFlush(http);
+
+ /* Reconnect... */
+ if (httpReconnect(http))
+ {
+ status = HTTP_ERROR;
+ break;
+ }
+
+ /* Upgrade with encryption... */
+ httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
+
+ /* Try again, this time with encryption enabled... */
+ continue;
+ }
+#endif /* HAVE_SSL */
+ }
+ while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED ||
+ (status == HTTP_ERROR && retries < 2));
+
+ /*
+ * See if we actually put the file or an error...
+ */
+
+ if (status != HTTP_CREATED)
+ {
+ _cupsSetHTTPError(status);
+ httpFlush(http);
+ }
+
+ DEBUG_printf(("1cupsPutFd: Returning %d...", status));
+
+ return (status);
+}
+
+
+/*
+ * 'cupsPutFile()' - Put a file on the server.
+ *
+ * This function returns @code HTTP_CREATED@ when the file is stored
+ * successfully.
+ *
+ * @since CUPS 1.1.20/Mac OS X 10.4@
+ */
+
+http_status_t /* O - HTTP status */
+cupsPutFile(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *resource, /* I - Resource name */
+ const char *filename) /* I - Filename */
+{
+ int fd; /* File descriptor */
+ http_status_t status; /* Status */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!http || !resource || !filename)
+ {
+ if (http)
+ http->error = EINVAL;
+
+ return (HTTP_ERROR);
+ }
+
+ /*
+ * Open the local file...
+ */
+
+ if ((fd = open(filename, O_RDONLY)) < 0)
+ {
+ /*
+ * Couldn't open the file!
+ */
+
+ http->error = errno;
+
+ return (HTTP_ERROR);
+ }
+
+ /*
+ * Put the file...
+ */
+
+ status = cupsPutFd(http, resource, fd);
+
+ close(fd);
+
+ return (status);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/globals.c b/cups/globals.c
new file mode 100644
index 000000000..6a00eb594
--- /dev/null
+++ b/cups/globals.c
@@ -0,0 +1,354 @@
+/*
+ * "$Id$"
+ *
+ * Global variable access routines for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsGlobalLock() - Lock the global mutex.
+ * _cupsGlobals() - Return a pointer to thread local storage
+ * _cupsGlobalUnlock() - Unlock the global mutex.
+ * DllMain() - Main entry for library.
+ * cups_globals_alloc() - Allocate and initialize global data.
+ * cups_globals_free() - Free global data.
+ * cups_globals_init() - Initialize environment variables.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+
+
+/*
+ * Local globals...
+ */
+
+
+static _cups_threadkey_t cups_globals_key = _CUPS_THREADKEY_INITIALIZER;
+ /* Thread local storage key */
+#ifdef HAVE_PTHREAD_H
+static pthread_once_t cups_globals_key_once = PTHREAD_ONCE_INIT;
+ /* One-time initialization object */
+#endif /* HAVE_PTHREAD_H */
+static _cups_mutex_t cups_global_mutex = _CUPS_MUTEX_INITIALIZER;
+ /* Global critical section */
+
+
+/*
+ * Local functions...
+ */
+
+static _cups_globals_t *cups_globals_alloc(void);
+static void cups_globals_free(_cups_globals_t *g);
+#ifdef HAVE_PTHREAD_H
+static void cups_globals_init(void);
+#endif /* HAVE_PTHREAD_H */
+
+
+/*
+ * '_cupsGlobalLock()' - Lock the global mutex.
+ */
+
+void
+_cupsGlobalLock(void)
+{
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_lock(&cups_global_mutex);
+#elif defined(WIN32)
+ EnterCriticalSection(&cups_global_mutex.m_criticalSection);
+#endif /* HAVE_PTHREAD_H */
+}
+
+
+/*
+ * '_cupsGlobals()' - Return a pointer to thread local storage
+ */
+
+_cups_globals_t * /* O - Pointer to global data */
+_cupsGlobals(void)
+{
+ _cups_globals_t *cg; /* Pointer to global data */
+
+
+#ifdef HAVE_PTHREAD_H
+ /*
+ * Initialize the global data exactly once...
+ */
+
+ pthread_once(&cups_globals_key_once, cups_globals_init);
+#endif /* HAVE_PTHREAD_H */
+
+ /*
+ * See if we have allocated the data yet...
+ */
+
+ if ((cg = (_cups_globals_t *)_cupsThreadGetData(cups_globals_key)) == NULL)
+ {
+ /*
+ * No, allocate memory as set the pointer for the key...
+ */
+
+ if ((cg = cups_globals_alloc()) != NULL)
+ _cupsThreadSetData(cups_globals_key, cg);
+ }
+
+ /*
+ * Return the pointer to the data...
+ */
+
+ return (cg);
+}
+
+
+/*
+ * '_cupsGlobalUnlock()' - Unlock the global mutex.
+ */
+
+void
+_cupsGlobalUnlock(void)
+{
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_unlock(&cups_global_mutex);
+#elif defined(WIN32)
+ LeaveCriticalSection(&cups_global_mutex.m_criticalSection);
+#endif /* HAVE_PTHREAD_H */
+}
+
+
+#ifdef WIN32
+/*
+ * 'DllMain()' - Main entry for library.
+ */
+
+BOOL WINAPI /* O - Success/failure */
+DllMain(HINSTANCE hinst, /* I - DLL module handle */
+ DWORD reason, /* I - Reason */
+ LPVOID reserved) /* I - Unused */
+{
+ _cups_globals_t *cg; /* Global data */
+
+
+ (void)hinst;
+ (void)reserved;
+
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH : /* Called on library initialization */
+ InitializeCriticalSection(&cups_global_mutex.m_criticalSection);
+
+ if ((cups_globals_key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
+ return (FALSE);
+ break;
+
+ case DLL_THREAD_DETACH : /* Called when a thread terminates */
+ if ((cg = (_cups_globals_t *)TlsGetValue(cups_globals_key)) != NULL)
+ cups_globals_free(cg);
+ break;
+
+ case DLL_PROCESS_DETACH : /* Called when library is unloaded */
+ if ((cg = (_cups_globals_t *)TlsGetValue(cups_globals_key)) != NULL)
+ cups_globals_free(cg);
+
+ TlsFree(cups_globals_key);
+ DeleteCriticalSection(&cups_global_mutex.m_criticalSection);
+ break;
+
+ default:
+ break;
+ }
+
+ return (TRUE);
+}
+#endif /* WIN32 */
+
+
+/*
+ * 'cups_globals_alloc()' - Allocate and initialize global data.
+ */
+
+static _cups_globals_t * /* O - Pointer to global data */
+cups_globals_alloc(void)
+{
+ _cups_globals_t *cg = malloc(sizeof(_cups_globals_t));
+ /* Pointer to global data */
+#ifdef WIN32
+ HKEY key; /* Registry key */
+ DWORD size; /* Size of string */
+ static char installdir[1024], /* Install directory */
+ confdir[1024], /* Server root directory */
+ localedir[1024]; /* Locale directory */
+#endif /* WIN32 */
+
+
+ if (!cg)
+ return (NULL);
+
+ /*
+ * Clear the global storage and set the default encryption and password
+ * callback values...
+ */
+
+ memset(cg, 0, sizeof(_cups_globals_t));
+ cg->encryption = (http_encryption_t)-1;
+ cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
+ cg->any_root = 1;
+ cg->expired_certs = 1;
+ cg->expired_root = 1;
+
+ /*
+ * Then set directories as appropriate...
+ */
+
+#ifdef WIN32
+ /*
+ * Open the registry...
+ */
+
+ strcpy(installdir, "C:/Program Files/cups.org");
+
+ if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\cups.org", 0, KEY_READ,
+ &key))
+ {
+ /*
+ * Grab the installation directory...
+ */
+
+ size = sizeof(installdir);
+ RegQueryValueEx(key, "installdir", NULL, NULL, installdir, &size);
+ RegCloseKey(key);
+ }
+
+ snprintf(confdir, sizeof(confdir), "%s/conf", installdir);
+ snprintf(localedir, sizeof(localedir), "%s/locale", installdir);
+
+ if ((cg->cups_datadir = getenv("CUPS_DATADIR")) == NULL)
+ cg->cups_datadir = installdir;
+
+ if ((cg->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
+ cg->cups_serverbin = installdir;
+
+ if ((cg->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL)
+ cg->cups_serverroot = confdir;
+
+ if ((cg->cups_statedir = getenv("CUPS_STATEDIR")) == NULL)
+ cg->cups_statedir = confdir;
+
+ if ((cg->localedir = getenv("LOCALEDIR")) == NULL)
+ cg->localedir = localedir;
+
+#else
+# ifdef HAVE_GETEUID
+ if ((geteuid() != getuid() && getuid()) || getegid() != getgid())
+# else
+ if (!getuid())
+# endif /* HAVE_GETEUID */
+ {
+ /*
+ * When running setuid/setgid, don't allow environment variables to override
+ * the directories...
+ */
+
+ cg->cups_datadir = CUPS_DATADIR;
+ cg->cups_serverbin = CUPS_SERVERBIN;
+ cg->cups_serverroot = CUPS_SERVERROOT;
+ cg->cups_statedir = CUPS_STATEDIR;
+ cg->localedir = CUPS_LOCALEDIR;
+ }
+ else
+ {
+ /*
+ * Allow directories to be overridden by environment variables.
+ */
+
+ if ((cg->cups_datadir = getenv("CUPS_DATADIR")) == NULL)
+ cg->cups_datadir = CUPS_DATADIR;
+
+ if ((cg->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
+ cg->cups_serverbin = CUPS_SERVERBIN;
+
+ if ((cg->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL)
+ cg->cups_serverroot = CUPS_SERVERROOT;
+
+ if ((cg->cups_statedir = getenv("CUPS_STATEDIR")) == NULL)
+ cg->cups_statedir = CUPS_STATEDIR;
+
+ if ((cg->localedir = getenv("LOCALEDIR")) == NULL)
+ cg->localedir = CUPS_LOCALEDIR;
+ }
+#endif /* WIN32 */
+
+ return (cg);
+}
+
+
+/*
+ * 'cups_globals_free()' - Free global data.
+ */
+
+static void
+cups_globals_free(_cups_globals_t *cg) /* I - Pointer to global data */
+{
+ _ipp_buffer_t *buffer, /* Current IPP read/write buffer */
+ *next; /* Next buffer */
+
+
+ if (cg->last_status_message)
+ _cupsStrFree(cg->last_status_message);
+
+ for (buffer = cg->ipp_buffers; buffer; buffer = next)
+ {
+ next = buffer->next;
+ free(buffer);
+ }
+
+ cupsArrayDelete(cg->leg_size_lut);
+ cupsArrayDelete(cg->ppd_size_lut);
+ cupsArrayDelete(cg->pwg_size_lut);
+
+ httpClose(cg->http);
+
+ _httpFreeCredentials(cg->tls_credentials);
+
+ cupsFileClose(cg->stdio_files[0]);
+ cupsFileClose(cg->stdio_files[1]);
+ cupsFileClose(cg->stdio_files[2]);
+
+ cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings);
+
+ free(cg);
+}
+
+
+#ifdef HAVE_PTHREAD_H
+/*
+ * 'cups_globals_init()' - Initialize environment variables.
+ */
+
+static void
+cups_globals_init(void)
+{
+ /*
+ * Register the global data for this thread...
+ */
+
+ pthread_key_create(&cups_globals_key, (void (*)(void *))cups_globals_free);
+}
+#endif /* HAVE_PTHREAD_H */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/http-addr.c b/cups/http-addr.c
new file mode 100644
index 000000000..64f4db358
--- /dev/null
+++ b/cups/http-addr.c
@@ -0,0 +1,700 @@
+/*
+ * "$Id$"
+ *
+ * HTTP address routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * httpAddrAny() - Check for the "any" address.
+ * httpAddrEqual() - Compare two addresses.
+ * httpAddrLocalhost() - Check for the local loopback address.
+ * httpAddrLookup() - Lookup the hostname associated with the address.
+ * _httpAddrPort() - Get the port number associated with an address.
+ * _httpAddrSetPort() - Set the port number associated with an address.
+ * httpAddrString() - Convert an IP address to a dotted string.
+ * httpGetHostByName() - Lookup a hostname or IP address, and return
+ * address records for the specified name.
+ * httpGetHostname() - Get the FQDN for the local system.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#ifdef HAVE_RESOLV_H
+# include <resolv.h>
+#endif /* HAVE_RESOLV_H */
+#ifdef HAVE_COREFOUNDATION
+# include <CoreFoundation/CoreFoundation.h>
+#endif /* HAVE_COREFOUNDATION */
+#ifdef HAVE_SYSTEMCONFIGURATION
+# include <SystemConfiguration/SystemConfiguration.h>
+#endif /* HAVE_SYSTEMCONFIGURATION */
+
+
+/*
+ * 'httpAddrAny()' - Check for the "any" address.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 1 if "any", 0 otherwise */
+httpAddrAny(const http_addr_t *addr) /* I - Address to check */
+{
+ if (!addr)
+ return (0);
+
+#ifdef AF_INET6
+ if (addr->addr.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr)))
+ return (1);
+#endif /* AF_INET6 */
+
+ if (addr->addr.sa_family == AF_INET &&
+ ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000)
+ return (1);
+
+ return (0);
+}
+
+
+/*
+ * 'httpAddrEqual()' - Compare two addresses.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 1 if equal, 0 if not */
+httpAddrEqual(const http_addr_t *addr1, /* I - First address */
+ const http_addr_t *addr2) /* I - Second address */
+{
+ if (!addr1 && !addr2)
+ return (1);
+
+ if (!addr1 || !addr2)
+ return (0);
+
+ if (addr1->addr.sa_family != addr2->addr.sa_family)
+ return (0);
+
+#ifdef AF_LOCAL
+ if (addr1->addr.sa_family == AF_LOCAL)
+ return (!strcmp(addr1->un.sun_path, addr2->un.sun_path));
+#endif /* AF_LOCAL */
+
+#ifdef AF_INET6
+ if (addr1->addr.sa_family == AF_INET6)
+ return (!memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16));
+#endif /* AF_INET6 */
+
+ return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr);
+}
+
+
+/*
+ * 'httpAddrLength()' - Return the length of the address in bytes.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - Length in bytes */
+httpAddrLength(const http_addr_t *addr) /* I - Address */
+{
+ if (!addr)
+ return (0);
+
+#ifdef AF_INET6
+ if (addr->addr.sa_family == AF_INET6)
+ return (sizeof(addr->ipv6));
+ else
+#endif /* AF_INET6 */
+#ifdef AF_LOCAL
+ if (addr->addr.sa_family == AF_LOCAL)
+ return (offsetof(struct sockaddr_un, sun_path) +
+ strlen(addr->un.sun_path) + 1);
+ else
+#endif /* AF_LOCAL */
+ if (addr->addr.sa_family == AF_INET)
+ return (sizeof(addr->ipv4));
+ else
+ return (0);
+
+}
+
+
+/*
+ * 'httpAddrLocalhost()' - Check for the local loopback address.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 1 if local host, 0 otherwise */
+httpAddrLocalhost(
+ const http_addr_t *addr) /* I - Address to check */
+{
+ if (!addr)
+ return (1);
+
+#ifdef AF_INET6
+ if (addr->addr.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr)))
+ return (1);
+#endif /* AF_INET6 */
+
+#ifdef AF_LOCAL
+ if (addr->addr.sa_family == AF_LOCAL)
+ return (1);
+#endif /* AF_LOCAL */
+
+ if (addr->addr.sa_family == AF_INET &&
+ (ntohl(addr->ipv4.sin_addr.s_addr) & 0xff000000) == 0x7f000000)
+ return (1);
+
+ return (0);
+}
+
+
+#ifdef __sgi
+# define ADDR_CAST (struct sockaddr *)
+#else
+# define ADDR_CAST (char *)
+#endif /* __sgi */
+
+
+/*
+ * 'httpAddrLookup()' - Lookup the hostname associated with the address.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+char * /* O - Host name */
+httpAddrLookup(
+ const http_addr_t *addr, /* I - Address to lookup */
+ char *name, /* I - Host name buffer */
+ int namelen) /* I - Size of name buffer */
+{
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Global data */
+
+
+ DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)", addr, name,
+ namelen));
+
+ /*
+ * Range check input...
+ */
+
+ if (!addr || !name || namelen <= 2)
+ {
+ if (name && namelen >= 1)
+ *name = '\0';
+
+ return (NULL);
+ }
+
+#ifdef AF_LOCAL
+ if (addr->addr.sa_family == AF_LOCAL)
+ {
+ strlcpy(name, addr->un.sun_path, namelen);
+ return (name);
+ }
+#endif /* AF_LOCAL */
+
+ /*
+ * Optimize lookups for localhost/loopback addresses...
+ */
+
+ if (httpAddrLocalhost(addr))
+ {
+ strlcpy(name, "localhost", namelen);
+ return (name);
+ }
+
+#ifdef HAVE_RES_INIT
+ /*
+ * STR #2920: Initialize resolver after failure in cups-polld
+ *
+ * If the previous lookup failed, re-initialize the resolver to prevent
+ * temporary network errors from persisting. This *should* be handled by
+ * the resolver libraries, but apparently the glibc folks do not agree.
+ *
+ * We set a flag at the end of this function if we encounter an error that
+ * requires reinitialization of the resolver functions. We then call
+ * res_init() if the flag is set on the next call here or in httpAddrLookup().
+ */
+
+ if (cg->need_res_init)
+ {
+ res_init();
+
+ cg->need_res_init = 0;
+ }
+#endif /* HAVE_RES_INIT */
+
+#ifdef HAVE_GETNAMEINFO
+ {
+ /*
+ * STR #2486: httpAddrLookup() fails when getnameinfo() returns EAI_AGAIN
+ *
+ * FWIW, I think this is really a bug in the implementation of
+ * getnameinfo(), but falling back on httpAddrString() is easy to
+ * do...
+ */
+
+ int error = getnameinfo(&addr->addr, httpAddrLength(addr), name, namelen,
+ NULL, 0, 0);
+
+ if (error)
+ {
+ if (error == EAI_FAIL)
+ cg->need_res_init = 1;
+
+ return (httpAddrString(addr, name, namelen));
+ }
+ }
+#else
+ {
+ struct hostent *host; /* Host from name service */
+
+
+# ifdef AF_INET6
+ if (addr->addr.sa_family == AF_INET6)
+ host = gethostbyaddr(ADDR_CAST &(addr->ipv6.sin6_addr),
+ sizeof(struct in_addr), AF_INET6);
+ else
+# endif /* AF_INET6 */
+ host = gethostbyaddr(ADDR_CAST &(addr->ipv4.sin_addr),
+ sizeof(struct in_addr), AF_INET);
+
+ if (host == NULL)
+ {
+ /*
+ * No hostname, so return the raw address...
+ */
+
+ if (h_errno == NO_RECOVERY)
+ cg->need_res_init = 1;
+
+ return (httpAddrString(addr, name, namelen));
+ }
+
+ strlcpy(name, host->h_name, namelen);
+ }
+#endif /* HAVE_GETNAMEINFO */
+
+ DEBUG_printf(("1httpAddrLookup: returning \"%s\"...", name));
+
+ return (name);
+}
+
+
+/*
+ * '_httpAddrPort()' - Get the port number associated with an address.
+ */
+
+int /* O - Port number */
+_httpAddrPort(http_addr_t *addr) /* I - Address */
+{
+ if (!addr)
+ return (ippPort());
+#ifdef AF_INET6
+ else if (addr->addr.sa_family == AF_INET6)
+ return (ntohs(addr->ipv6.sin6_port));
+#endif /* AF_INET6 */
+ else if (addr->addr.sa_family == AF_INET)
+ return (ntohs(addr->ipv4.sin_port));
+ else
+ return (ippPort());
+}
+
+
+/*
+ * '_httpAddrSetPort()' - Set the port number associated with an address.
+ */
+
+void
+_httpAddrSetPort(http_addr_t *addr, /* I - Address */
+ int port) /* I - Port */
+{
+ if (!addr || port <= 0)
+ return;
+
+#ifdef AF_INET6
+ if (addr->addr.sa_family == AF_INET6)
+ addr->ipv6.sin6_port = htons(port);
+ else
+#endif /* AF_INET6 */
+ if (addr->addr.sa_family == AF_INET)
+ addr->ipv4.sin_port = htons(port);
+}
+
+
+/*
+ * 'httpAddrString()' - Convert an address to a numeric string.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+char * /* O - Numeric address string */
+httpAddrString(const http_addr_t *addr, /* I - Address to convert */
+ char *s, /* I - String buffer */
+ int slen) /* I - Length of string */
+{
+ DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)", addr, s, slen));
+
+ /*
+ * Range check input...
+ */
+
+ if (!addr || !s || slen <= 2)
+ {
+ if (s && slen >= 1)
+ *s = '\0';
+
+ return (NULL);
+ }
+
+#ifdef AF_LOCAL
+ if (addr->addr.sa_family == AF_LOCAL)
+ strlcpy(s, addr->un.sun_path, slen);
+ else
+#endif /* AF_LOCAL */
+ if (addr->addr.sa_family == AF_INET)
+ {
+ unsigned temp; /* Temporary address */
+
+
+ temp = ntohl(addr->ipv4.sin_addr.s_addr);
+
+ snprintf(s, slen, "%d.%d.%d.%d", (temp >> 24) & 255,
+ (temp >> 16) & 255, (temp >> 8) & 255, temp & 255);
+ }
+#ifdef AF_INET6
+ else if (addr->addr.sa_family == AF_INET6)
+ {
+ char *sptr, /* Pointer into string */
+ temps[64]; /* Temporary string for address */
+
+# ifdef HAVE_GETNAMEINFO
+ if (getnameinfo(&addr->addr, httpAddrLength(addr), temps, sizeof(temps),
+ NULL, 0, NI_NUMERICHOST))
+ {
+ /*
+ * If we get an error back, then the address type is not supported
+ * and we should zero out the buffer...
+ */
+
+ s[0] = '\0';
+
+ return (NULL);
+ }
+ else if ((sptr = strchr(temps, '%')) != NULL)
+ {
+ /*
+ * Convert "%zone" to "+zone" to match URI form...
+ */
+
+ *sptr = '+';
+ }
+
+# else
+ int i; /* Looping var */
+ unsigned temp; /* Current value */
+ const char *prefix; /* Prefix for address */
+
+
+ prefix = "";
+ for (sptr = temps, i = 0; i < 4 && addr->ipv6.sin6_addr.s6_addr32[i]; i ++)
+ {
+ temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]);
+
+ snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix,
+ (temp >> 16) & 0xffff);
+ prefix = ":";
+ sptr += strlen(sptr);
+
+ temp &= 0xffff;
+
+ if (temp || i == 3 || addr->ipv6.sin6_addr.s6_addr32[i + 1])
+ {
+ snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix, temp);
+ sptr += strlen(sptr);
+ }
+ }
+
+ if (i < 4)
+ {
+ while (i < 4 && !addr->ipv6.sin6_addr.s6_addr32[i])
+ i ++;
+
+ if (i < 4)
+ {
+ snprintf(sptr, sizeof(temps) - (sptr - temps), "%s:", prefix);
+ prefix = ":";
+ sptr += strlen(sptr);
+
+ for (; i < 4; i ++)
+ {
+ temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]);
+
+ if ((temp & 0xffff0000) ||
+ (i > 0 && addr->ipv6.sin6_addr.s6_addr32[i - 1]))
+ {
+ snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix,
+ (temp >> 16) & 0xffff);
+ sptr += strlen(sptr);
+ }
+
+ snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix,
+ temp & 0xffff);
+ sptr += strlen(sptr);
+ }
+ }
+ else if (sptr == s)
+ {
+ /*
+ * Empty address...
+ */
+
+ strlcpy(temps, "::", sizeof(temps));
+ }
+ else
+ {
+ /*
+ * Empty at end...
+ */
+
+ strlcpy(sptr, "::", sizeof(temps) - (sptr - temps));
+ }
+ }
+# endif /* HAVE_GETNAMEINFO */
+
+ /*
+ * Add "[v1." and "]" around IPv6 address to convert to URI form.
+ */
+
+ snprintf(s, slen, "[v1.%s]", temps);
+ }
+#endif /* AF_INET6 */
+ else
+ strlcpy(s, "UNKNOWN", slen);
+
+ DEBUG_printf(("1httpAddrString: returning \"%s\"...", s));
+
+ return (s);
+}
+
+
+/*
+ * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return
+ * address records for the specified name.
+ *
+ * @deprecated@
+ */
+
+struct hostent * /* O - Host entry */
+httpGetHostByName(const char *name) /* I - Hostname or IP address */
+{
+ const char *nameptr; /* Pointer into name */
+ unsigned ip[4]; /* IP address components */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Pointer to library globals */
+
+
+ DEBUG_printf(("httpGetHostByName(name=\"%s\")", name));
+
+ /*
+ * Avoid lookup delays and configuration problems when connecting
+ * to the localhost address...
+ */
+
+ if (!strcmp(name, "localhost"))
+ name = "127.0.0.1";
+
+ /*
+ * This function is needed because some operating systems have a
+ * buggy implementation of gethostbyname() that does not support
+ * IP addresses. If the first character of the name string is a
+ * number, then sscanf() is used to extract the IP components.
+ * We then pack the components into an IPv4 address manually,
+ * since the inet_aton() function is deprecated. We use the
+ * htonl() macro to get the right byte order for the address.
+ *
+ * We also support domain sockets when supported by the underlying
+ * OS...
+ */
+
+#ifdef AF_LOCAL
+ if (name[0] == '/')
+ {
+ /*
+ * A domain socket address, so make an AF_LOCAL entry and return it...
+ */
+
+ cg->hostent.h_name = (char *)name;
+ cg->hostent.h_aliases = NULL;
+ cg->hostent.h_addrtype = AF_LOCAL;
+ cg->hostent.h_length = strlen(name) + 1;
+ cg->hostent.h_addr_list = cg->ip_ptrs;
+ cg->ip_ptrs[0] = (char *)name;
+ cg->ip_ptrs[1] = NULL;
+
+ DEBUG_puts("1httpGetHostByName: returning domain socket address...");
+
+ return (&cg->hostent);
+ }
+#endif /* AF_LOCAL */
+
+ for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++);
+
+ if (!*nameptr)
+ {
+ /*
+ * We have an IPv4 address; break it up and provide the host entry
+ * to the caller.
+ */
+
+ if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4)
+ return (NULL); /* Must have 4 numbers */
+
+ if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
+ return (NULL); /* Invalid byte ranges! */
+
+ cg->ip_addr = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) |
+ ip[3]));
+
+ /*
+ * Fill in the host entry and return it...
+ */
+
+ cg->hostent.h_name = (char *)name;
+ cg->hostent.h_aliases = NULL;
+ cg->hostent.h_addrtype = AF_INET;
+ cg->hostent.h_length = 4;
+ cg->hostent.h_addr_list = cg->ip_ptrs;
+ cg->ip_ptrs[0] = (char *)&(cg->ip_addr);
+ cg->ip_ptrs[1] = NULL;
+
+ DEBUG_puts("1httpGetHostByName: returning IPv4 address...");
+
+ return (&cg->hostent);
+ }
+ else
+ {
+ /*
+ * Use the gethostbyname() function to get the IPv4 address for
+ * the name...
+ */
+
+ DEBUG_puts("1httpGetHostByName: returning domain lookup address(es)...");
+
+ return (gethostbyname(name));
+ }
+}
+
+
+/*
+ * 'httpGetHostname()' - Get the FQDN for the connection or local system.
+ *
+ * When "http" points to a connected socket, return the hostname or
+ * address that was used in the call to httpConnect() or httpConnectEncrypt().
+ * Otherwise, return the FQDN for the local system using both gethostname()
+ * and gethostbyname() to get the local hostname with domain.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+const char * /* O - FQDN for connection or system */
+httpGetHostname(http_t *http, /* I - HTTP connection or NULL */
+ char *s, /* I - String buffer for name */
+ int slen) /* I - Size of buffer */
+{
+ if (!s || slen <= 1)
+ return (NULL);
+
+ if (http)
+ {
+ if (http->hostname[0] == '/')
+ strlcpy(s, "localhost", slen);
+ else
+ strlcpy(s, http->hostname, slen);
+ }
+ else
+ {
+ /*
+ * Get the hostname...
+ */
+
+ if (gethostname(s, slen) < 0)
+ strlcpy(s, "localhost", slen);
+
+ if (!strchr(s, '.'))
+ {
+#ifdef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME
+ /*
+ * The hostname is not a FQDN, so use the local hostname from the
+ * SystemConfiguration framework...
+ */
+
+ SCDynamicStoreRef sc = SCDynamicStoreCreate(kCFAllocatorDefault,
+ CFSTR("libcups"), NULL, NULL);
+ /* System configuration data */
+ CFStringRef local = sc ? SCDynamicStoreCopyLocalHostName(sc) : NULL;
+ /* Local host name */
+ char localStr[1024]; /* Local host name C string */
+
+ if (local && CFStringGetCString(local, localStr, sizeof(localStr),
+ kCFStringEncodingUTF8))
+ {
+ /*
+ * Append ".local." to the hostname we get...
+ */
+
+ snprintf(s, slen, "%s.local.", localStr);
+ }
+
+ if (local)
+ CFRelease(local);
+ if (sc)
+ CFRelease(sc);
+
+#else
+ /*
+ * The hostname is not a FQDN, so look it up...
+ */
+
+ struct hostent *host; /* Host entry to get FQDN */
+
+ if ((host = gethostbyname(s)) != NULL && host->h_name)
+ {
+ /*
+ * Use the resolved hostname...
+ */
+
+ strlcpy(s, host->h_name, slen);
+ }
+#endif /* HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME */
+ }
+ }
+
+ /*
+ * Return the hostname with as much domain info as we have...
+ */
+
+ return (s);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/http-addrlist.c b/cups/http-addrlist.c
new file mode 100644
index 000000000..02abed9dd
--- /dev/null
+++ b/cups/http-addrlist.c
@@ -0,0 +1,677 @@
+/*
+ * "$Id$"
+ *
+ * HTTP address list routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * httpAddrConnect() - Connect to any of the addresses in the list.
+ * httpAddrFreeList() - Free an address list.
+ * httpAddrGetList() - Get a list of addresses for a hostname.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#ifdef HAVE_RESOLV_H
+# include <resolv.h>
+#endif /* HAVE_RESOLV_H */
+
+
+/*
+ * 'httpAddrConnect()' - Connect to any of the addresses in the list.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+http_addrlist_t * /* O - Connected address or NULL on failure */
+httpAddrConnect(
+ http_addrlist_t *addrlist, /* I - List of potential addresses */
+ int *sock) /* O - Socket */
+{
+ int val; /* Socket option value */
+#ifdef __APPLE__
+ struct timeval timeout; /* Socket timeout value */
+#endif /* __APPLE__ */
+#ifdef DEBUG
+ char temp[256]; /* Temporary address string */
+#endif /* DEBUG */
+
+
+ DEBUG_printf(("httpAddrConnect(addrlist=%p, sock=%p)", addrlist, sock));
+
+ if (!sock)
+ {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /*
+ * Loop through each address until we connect or run out of addresses...
+ */
+
+ while (addrlist)
+ {
+ /*
+ * Create the socket...
+ */
+
+ DEBUG_printf(("2httpAddrConnect: Trying %s:%d...",
+ httpAddrString(&(addrlist->addr), temp, sizeof(temp)),
+ _httpAddrPort(&(addrlist->addr))));
+
+ if ((*sock = (int)socket(_httpAddrFamily(&(addrlist->addr)), SOCK_STREAM,
+ 0)) < 0)
+ {
+ /*
+ * Don't abort yet, as this could just be an issue with the local
+ * system not being configured with IPv4/IPv6/domain socket enabled...
+ */
+
+ addrlist = addrlist->next;
+ continue;
+ }
+
+ /*
+ * Set options...
+ */
+
+ val = 1;
+#ifdef WIN32
+ setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&val,
+ sizeof(val));
+#else
+ setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+#endif /* WIN32 */
+
+#ifdef SO_REUSEPORT
+ val = 1;
+ setsockopt(*sock, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
+#endif /* SO_REUSEPORT */
+
+#ifdef SO_NOSIGPIPE
+ val = 1;
+ setsockopt(*sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val));
+#endif /* SO_NOSIGPIPE */
+
+#ifdef __APPLE__
+ /*
+ * Use a 30-second read timeout when connecting to limit the amount of time
+ * we block...
+ */
+
+ timeout.tv_sec = 30;
+ timeout.tv_usec = 0;
+ setsockopt(*sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+#endif /* __APPLE__ */
+
+ /*
+ * Using TCP_NODELAY improves responsiveness, especially on systems
+ * with a slow loopback interface...
+ */
+
+ val = 1;
+#ifdef WIN32
+ setsockopt(*sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&val,
+ sizeof(val));
+#else
+ setsockopt(*sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+#endif /* WIN32 */
+
+#ifdef FD_CLOEXEC
+ /*
+ * Close this socket when starting another process...
+ */
+
+ fcntl(*sock, F_SETFD, FD_CLOEXEC);
+#endif /* FD_CLOEXEC */
+
+ /*
+ * Then connect...
+ */
+
+ if (!connect(*sock, &(addrlist->addr.addr),
+ httpAddrLength(&(addrlist->addr))))
+ {
+ DEBUG_printf(("1httpAddrConnect: Connected to %s:%d...",
+ httpAddrString(&(addrlist->addr), temp, sizeof(temp)),
+ _httpAddrPort(&(addrlist->addr))));
+ break;
+ }
+
+ DEBUG_printf(("1httpAddrConnect: Unable to connect to %s:%d: %s",
+ httpAddrString(&(addrlist->addr), temp, sizeof(temp)),
+ _httpAddrPort(&(addrlist->addr)), strerror(errno)));
+
+ /*
+ * Close this socket and move to the next address...
+ */
+
+#ifdef WIN32
+ closesocket(*sock);
+#else
+ close(*sock);
+#endif /* WIN32 */
+
+ *sock = -1;
+ addrlist = addrlist->next;
+ }
+
+ if (!addrlist)
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, _("Unable to connect to server"), 1);
+
+ return (addrlist);
+}
+
+
+/*
+ * 'httpAddrFreeList()' - Free an address list.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void
+httpAddrFreeList(
+ http_addrlist_t *addrlist) /* I - Address list to free */
+{
+ http_addrlist_t *next; /* Next address in list */
+
+
+ /*
+ * Free each address in the list...
+ */
+
+ while (addrlist)
+ {
+ next = addrlist->next;
+
+ free(addrlist);
+
+ addrlist = next;
+ }
+}
+
+
+/*
+ * 'httpAddrGetList()' - Get a list of addresses for a hostname.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+http_addrlist_t * /* O - List of addresses or NULL */
+httpAddrGetList(const char *hostname, /* I - Hostname, IP address, or NULL for passive listen address */
+ int family, /* I - Address family or AF_UNSPEC */
+ const char *service) /* I - Service name or port number */
+{
+ http_addrlist_t *first, /* First address in list */
+ *addr, /* Current address in list */
+ *temp; /* New address */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Global data */
+
+
+#ifdef DEBUG
+ _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, "
+ "service=\"%s\")\n",
+ hostname ? hostname : "(nil)",
+ family == AF_UNSPEC ? "UNSPEC" :
+# ifdef AF_LOCAL
+ family == AF_LOCAL ? "LOCAL" :
+# endif /* AF_LOCAL */
+# ifdef AF_INET6
+ family == AF_INET6 ? "INET6" :
+# endif /* AF_INET6 */
+ family == AF_INET ? "INET" : "???", service);
+#endif /* DEBUG */
+
+#ifdef HAVE_RES_INIT
+ /*
+ * STR #2920: Initialize resolver after failure in cups-polld
+ *
+ * If the previous lookup failed, re-initialize the resolver to prevent
+ * temporary network errors from persisting. This *should* be handled by
+ * the resolver libraries, but apparently the glibc folks do not agree.
+ *
+ * We set a flag at the end of this function if we encounter an error that
+ * requires reinitialization of the resolver functions. We then call
+ * res_init() if the flag is set on the next call here or in httpAddrLookup().
+ */
+
+ if (cg->need_res_init)
+ {
+ res_init();
+
+ cg->need_res_init = 0;
+ }
+#endif /* HAVE_RES_INIT */
+
+
+ /*
+ * Lookup the address the best way we can...
+ */
+
+ first = addr = NULL;
+
+#ifdef AF_LOCAL
+ if (hostname && hostname[0] == '/')
+ {
+ /*
+ * Domain socket address...
+ */
+
+ if ((first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t))) != NULL)
+ {
+ first->addr.un.sun_family = AF_LOCAL;
+ strlcpy(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path));
+ }
+ }
+ else
+#endif /* AF_LOCAL */
+ if (!hostname || _cups_strcasecmp(hostname, "localhost"))
+ {
+#ifdef HAVE_GETADDRINFO
+ struct addrinfo hints, /* Address lookup hints */
+ *results, /* Address lookup results */
+ *current; /* Current result */
+ char ipv6[64], /* IPv6 address */
+ *ipv6zone; /* Pointer to zone separator */
+ int ipv6len; /* Length of IPv6 address */
+ int error; /* getaddrinfo() error */
+
+
+ /*
+ * Lookup the address as needed...
+ */
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_flags = hostname ? 0 : AI_PASSIVE;
+ hints.ai_socktype = SOCK_STREAM;
+
+ if (hostname && *hostname == '[')
+ {
+ /*
+ * Remove brackets from numeric IPv6 address...
+ */
+
+ if (!strncmp(hostname, "[v1.", 4))
+ {
+ /*
+ * Copy the newer address format which supports link-local addresses...
+ */
+
+ strlcpy(ipv6, hostname + 4, sizeof(ipv6));
+ if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
+ {
+ ipv6[ipv6len] = '\0';
+ hostname = ipv6;
+
+ /*
+ * Convert "+zone" in address to "%zone"...
+ */
+
+ if ((ipv6zone = strrchr(ipv6, '+')) != NULL)
+ *ipv6zone = '%';
+ }
+ }
+ else
+ {
+ /*
+ * Copy the regular non-link-local IPv6 address...
+ */
+
+ strlcpy(ipv6, hostname + 1, sizeof(ipv6));
+ if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
+ {
+ ipv6[ipv6len] = '\0';
+ hostname = ipv6;
+ }
+ }
+ }
+
+ if ((error = getaddrinfo(hostname, service, &hints, &results)) == 0)
+ {
+ /*
+ * Copy the results to our own address list structure...
+ */
+
+ for (current = results; current; current = current->ai_next)
+ if (current->ai_family == AF_INET || current->ai_family == AF_INET6)
+ {
+ /*
+ * Copy the address over...
+ */
+
+ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
+ if (!temp)
+ {
+ httpAddrFreeList(first);
+ return (NULL);
+ }
+
+ if (current->ai_family == AF_INET6)
+ memcpy(&(temp->addr.ipv6), current->ai_addr,
+ sizeof(temp->addr.ipv6));
+ else
+ memcpy(&(temp->addr.ipv4), current->ai_addr,
+ sizeof(temp->addr.ipv4));
+
+ /*
+ * Append the address to the list...
+ */
+
+ if (!first)
+ first = temp;
+
+ if (addr)
+ addr->next = temp;
+
+ addr = temp;
+ }
+
+ /*
+ * Free the results from getaddrinfo()...
+ */
+
+ freeaddrinfo(results);
+ }
+ else if (error == EAI_FAIL)
+ cg->need_res_init = 1;
+
+#else
+ if (hostname)
+ {
+ int i; /* Looping vars */
+ unsigned ip[4]; /* IPv4 address components */
+ const char *ptr; /* Pointer into hostname */
+ struct hostent *host; /* Result of lookup */
+ struct servent *port; /* Port number for service */
+ int portnum; /* Port number */
+
+
+ /*
+ * Lookup the service...
+ */
+
+ if (!service)
+ portnum = 0;
+ else if (isdigit(*service & 255))
+ portnum = atoi(service);
+ else if ((port = getservbyname(service, NULL)) != NULL)
+ portnum = ntohs(port->s_port);
+ else if (!strcmp(service, "http"))
+ portnum = 80;
+ else if (!strcmp(service, "https"))
+ portnum = 443;
+ else if (!strcmp(service, "ipp") || !strcmp(service, "ipps"))
+ portnum = 631;
+ else if (!strcmp(service, "lpd"))
+ portnum = 515;
+ else if (!strcmp(service, "socket"))
+ portnum = 9100;
+ else
+ return (NULL);
+
+ /*
+ * This code is needed because some operating systems have a
+ * buggy implementation of gethostbyname() that does not support
+ * IPv4 addresses. If the hostname string is an IPv4 address, then
+ * sscanf() is used to extract the IPv4 components. We then pack
+ * the components into an IPv4 address manually, since the
+ * inet_aton() function is deprecated. We use the htonl() macro
+ * to get the right byte order for the address.
+ */
+
+ for (ptr = hostname; isdigit(*ptr & 255) || *ptr == '.'; ptr ++);
+
+ if (!*ptr)
+ {
+ /*
+ * We have an IPv4 address; break it up and create an IPv4 address...
+ */
+
+ if (sscanf(hostname, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) == 4 &&
+ ip[0] <= 255 && ip[1] <= 255 && ip[2] <= 255 && ip[3] <= 255)
+ {
+ first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
+ if (!first)
+ return (NULL);
+
+ first->addr.ipv4.sin_family = AF_INET;
+ first->addr.ipv4.sin_addr.s_addr = htonl(((((((ip[0] << 8) |
+ ip[1]) << 8) |
+ ip[2]) << 8) | ip[3]));
+ first->addr.ipv4.sin_port = htons(portnum);
+ }
+ }
+ else if ((host = gethostbyname(hostname)) != NULL &&
+# ifdef AF_INET6
+ (host->h_addrtype == AF_INET || host->h_addrtype == AF_INET6))
+# else
+ host->h_addrtype == AF_INET)
+# endif /* AF_INET6 */
+ {
+ for (i = 0; host->h_addr_list[i]; i ++)
+ {
+ /*
+ * Copy the address over...
+ */
+
+ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
+ if (!temp)
+ {
+ httpAddrFreeList(first);
+ return (NULL);
+ }
+
+# ifdef AF_INET6
+ if (host->h_addrtype == AF_INET6)
+ {
+ temp->addr.ipv6.sin6_family = AF_INET6;
+ memcpy(&(temp->addr.ipv6.sin6_addr), host->h_addr_list[i],
+ sizeof(temp->addr.ipv6));
+ temp->addr.ipv6.sin6_port = htons(portnum);
+ }
+ else
+# endif /* AF_INET6 */
+ {
+ temp->addr.ipv4.sin_family = AF_INET;
+ memcpy(&(temp->addr.ipv4.sin_addr), host->h_addr_list[i],
+ sizeof(temp->addr.ipv4));
+ temp->addr.ipv4.sin_port = htons(portnum);
+ }
+
+ /*
+ * Append the address to the list...
+ */
+
+ if (!first)
+ first = temp;
+
+ if (addr)
+ addr->next = temp;
+
+ addr = temp;
+ }
+ }
+ else if (h_errno == NO_RECOVERY)
+ cg->need_res_init = 1;
+ }
+#endif /* HAVE_GETADDRINFO */
+ }
+
+ /*
+ * Detect some common errors and handle them sanely...
+ */
+
+ if (!addr && (!hostname || !_cups_strcasecmp(hostname, "localhost")))
+ {
+ struct servent *port; /* Port number for service */
+ int portnum; /* Port number */
+
+
+ /*
+ * Lookup the service...
+ */
+
+ if (!service)
+ portnum = 0;
+ else if (isdigit(*service & 255))
+ portnum = atoi(service);
+ else if ((port = getservbyname(service, NULL)) != NULL)
+ portnum = ntohs(port->s_port);
+ else if (!strcmp(service, "http"))
+ portnum = 80;
+ else if (!strcmp(service, "https"))
+ portnum = 443;
+ else if (!strcmp(service, "ipp") || !strcmp(service, "ipps"))
+ portnum = 631;
+ else if (!strcmp(service, "lpd"))
+ portnum = 515;
+ else if (!strcmp(service, "socket"))
+ portnum = 9100;
+ else
+ {
+ httpAddrFreeList(first);
+ return (NULL);
+ }
+
+ if (hostname && !_cups_strcasecmp(hostname, "localhost"))
+ {
+ /*
+ * Unfortunately, some users ignore all of the warnings in the
+ * /etc/hosts file and delete "localhost" from it. If we get here
+ * then we were unable to resolve the name, so use the IPv6 and/or
+ * IPv4 loopback interface addresses...
+ */
+
+#ifdef AF_INET6
+ if (family != AF_INET)
+ {
+ /*
+ * Add [::1] to the address list...
+ */
+
+ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
+ if (!temp)
+ {
+ httpAddrFreeList(first);
+ return (NULL);
+ }
+
+ temp->addr.ipv6.sin6_family = AF_INET6;
+ temp->addr.ipv6.sin6_port = htons(portnum);
+# ifdef WIN32
+ temp->addr.ipv6.sin6_addr.u.Byte[15] = 1;
+# else
+ temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1);
+# endif /* WIN32 */
+
+ if (!first)
+ first = temp;
+
+ addr = temp;
+ }
+
+ if (family != AF_INET6)
+#endif /* AF_INET6 */
+ {
+ /*
+ * Add 127.0.0.1 to the address list...
+ */
+
+ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
+ if (!temp)
+ {
+ httpAddrFreeList(first);
+ return (NULL);
+ }
+
+ temp->addr.ipv4.sin_family = AF_INET;
+ temp->addr.ipv4.sin_port = htons(portnum);
+ temp->addr.ipv4.sin_addr.s_addr = htonl(0x7f000001);
+
+ if (!first)
+ first = temp;
+
+ if (addr)
+ addr->next = temp;
+ }
+ }
+ else if (!hostname)
+ {
+ /*
+ * Provide one or more passive listening addresses...
+ */
+
+#ifdef AF_INET6
+ if (family != AF_INET)
+ {
+ /*
+ * Add [::] to the address list...
+ */
+
+ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
+ if (!temp)
+ {
+ httpAddrFreeList(first);
+ return (NULL);
+ }
+
+ temp->addr.ipv6.sin6_family = AF_INET6;
+ temp->addr.ipv6.sin6_port = htons(portnum);
+
+ if (!first)
+ first = temp;
+
+ addr = temp;
+ }
+
+ if (family != AF_INET6)
+#endif /* AF_INET6 */
+ {
+ /*
+ * Add 0.0.0.0 to the address list...
+ */
+
+ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
+ if (!temp)
+ {
+ httpAddrFreeList(first);
+ return (NULL);
+ }
+
+ temp->addr.ipv4.sin_family = AF_INET;
+ temp->addr.ipv4.sin_port = htons(portnum);
+
+ if (!first)
+ first = temp;
+
+ if (addr)
+ addr->next = temp;
+ }
+ }
+ }
+
+ /*
+ * Return the address list...
+ */
+
+ return (first);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/http-private.h b/cups/http-private.h
new file mode 100644
index 000000000..64379d7a5
--- /dev/null
+++ b/cups/http-private.h
@@ -0,0 +1,407 @@
+/*
+ * "$Id$"
+ *
+ * Private HTTP definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_HTTP_PRIVATE_H_
+# define _CUPS_HTTP_PRIVATE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include "config.h"
+# include <stddef.h>
+# include <stdlib.h>
+
+# ifdef __sun
+# include <sys/select.h>
+# endif /* __sun */
+
+# include <limits.h>
+# ifdef WIN32
+# include <io.h>
+# include <winsock2.h>
+# else
+# include <unistd.h>
+# include <fcntl.h>
+# include <sys/socket.h>
+# define closesocket(f) close(f)
+# endif /* WIN32 */
+
+# ifdef HAVE_GSSAPI
+# ifdef HAVE_GSS_GSSAPI_H
+# include <GSS/gssapi.h>
+# ifdef HAVE_GSSAPI_GENERIC_H
+# include <GSS/gssapi_generic.h>
+# endif /* HAVE_GSSAPI_GENERIC_H */
+# ifdef HAVE_GSSAPI_KRB5_H
+# include <GSS/gssapi_krb5.h>
+# endif /* HAVE_GSSAPI_KRB5_H */
+# elif defined(HAVE_GSSAPI_GSSAPI_H)
+# include <gssapi/gssapi.h>
+# ifdef HAVE_GSSAPI_GENERIC_H
+# include <gssapi/gssapi_generic.h>
+# endif /* HAVE_GSSAPI_GENERIC_H */
+# ifdef HAVE_GSSAPI_KRB5_H
+# include <gssapi/gssapi_krb5.h>
+# endif /* HAVE_GSSAPI_KRB5_H */
+# elif defined(HAVE_GSSAPI_H)
+# include <gssapi.h>
+# endif /* HAVE_GSS_GSSAPI_H */
+# ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE
+# define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+# endif /* !HAVE_GSS_C_NT_HOSTBASED_SERVICE */
+# ifdef HAVE_KRB5_H
+# include <krb5.h>
+# endif /* HAVE_KRB5_H */
+# endif /* HAVE_GSSAPI */
+
+# ifdef HAVE_AUTHORIZATION_H
+# include <Security/Authorization.h>
+# endif /* HAVE_AUTHORIZATION_H */
+
+# if defined(__sgi) || (defined(__APPLE__) && !defined(_SOCKLEN_T))
+/*
+ * IRIX and MacOS X 10.2.x do not define socklen_t, and in fact use an int instead of
+ * unsigned type for length values...
+ */
+
+typedef int socklen_t;
+# endif /* __sgi || (__APPLE__ && !_SOCKLEN_T) */
+
+# include <cups/http.h>
+# include "md5-private.h"
+# include "ipp-private.h"
+
+# if defined HAVE_LIBSSL
+# include <openssl/err.h>
+# include <openssl/rand.h>
+# include <openssl/ssl.h>
+# elif defined HAVE_GNUTLS
+# include <gnutls/gnutls.h>
+# include <gnutls/x509.h>
+# include <gcrypt.h>
+# elif defined(HAVE_CDSASSL)
+# include <CoreFoundation/CoreFoundation.h>
+# include <Security/Security.h>
+# include <Security/SecureTransport.h>
+# ifdef HAVE_SECURETRANSPORTPRIV_H
+# include <Security/SecureTransportPriv.h>
+# endif /* HAVE_SECURETRANSPORTPRIV_H */
+# ifdef HAVE_SECITEM_H
+# include <Security/SecItem.h>
+# endif /* HAVE_SECITEM_H */
+# ifdef HAVE_SECBASEPRIV_H
+# include <Security/SecBasePriv.h>
+# endif /* HAVE_SECBASEPRIV_H */
+# ifdef HAVE_SECCERTIFICATE_H
+# include <Security/SecCertificate.h>
+# include <Security/SecIdentity.h>
+# endif /* HAVE_SECCERTIFICATE_H */
+# ifdef HAVE_SECITEMPRIV_H
+# include <Security/SecItemPriv.h>
+# endif /* HAVE_SECITEMPRIV_H */
+# ifdef HAVE_SECIDENTITYSEARCHPRIV_H
+# include <Security/SecIdentitySearchPriv.h>
+# endif /* HAVE_SECIDENTITYSEARCHPRIV_H */
+# ifdef HAVE_SECPOLICYPRIV_H
+# include <Security/SecPolicyPriv.h>
+# endif /* HAVE_SECPOLICYPRIV_H */
+# elif defined(HAVE_SSPISSL)
+# include "sspi-private.h"
+# endif /* HAVE_LIBSSL */
+
+# ifndef WIN32
+# include <net/if.h>
+# ifdef HAVE_GETIFADDRS
+# include <ifaddrs.h>
+# else
+# include <sys/ioctl.h>
+# ifdef HAVE_SYS_SOCKIO_H
+# include <sys/sockio.h>
+# endif /* HAVE_SYS_SOCKIO_H */
+# endif /* HAVE_GETIFADDRS */
+# endif /* !WIN32 */
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Constants...
+ */
+
+
+#define _HTTP_RESOLVE_DEFAULT 0 /* Just resolve with default options */
+#define _HTTP_RESOLVE_STDERR 1 /* Log resolve progress to stderr */
+#define _HTTP_RESOLVE_FQDN 2 /* Resolve to a FQDN */
+
+
+/*
+ * Types and functions for SSL support...
+ */
+
+# if defined HAVE_LIBSSL
+/*
+ * The OpenSSL library provides its own SSL/TLS context structure for its
+ * IO and protocol management. However, we need to provide our own BIO
+ * (basic IO) implementation to do timeouts...
+ */
+
+typedef SSL *http_tls_t;
+typedef void *http_tls_credentials_t;
+
+extern BIO_METHOD *_httpBIOMethods(void);
+
+# elif defined HAVE_GNUTLS
+/*
+ * The GNU TLS library is more of a "bare metal" SSL/TLS library...
+ */
+
+typedef gnutls_session http_tls_t;
+typedef void *http_tls_credentials_t;
+
+extern ssize_t _httpReadGNUTLS(gnutls_transport_ptr ptr, void *data,
+ size_t length);
+extern ssize_t _httpWriteGNUTLS(gnutls_transport_ptr ptr, const void *data,
+ size_t length);
+
+# elif defined(HAVE_CDSASSL)
+/*
+ * Darwin's Security framework provides its own SSL/TLS context structure
+ * for its IO and protocol management...
+ */
+
+# if !defined(HAVE_SECBASEPRIV_H) && defined(HAVE_CSSMERRORSTRING) /* Declare prototype for function in that header... */
+extern const char *cssmErrorString(int error);
+# endif /* !HAVE_SECBASEPRIV_H && HAVE_CSSMERRORSTRING */
+# ifndef HAVE_SECITEMPRIV_H /* Declare constants from that header... */
+extern const CFTypeRef kSecClassCertificate;
+extern const CFTypeRef kSecClassIdentity;
+# endif /* !HAVE_SECITEMPRIV_H */
+# if !defined(HAVE_SECIDENTITYSEARCHPRIV_H) && defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY) /* Declare prototype for function in that header... */
+extern OSStatus SecIdentitySearchCreateWithPolicy(SecPolicyRef policy,
+ CFStringRef idString, CSSM_KEYUSE keyUsage,
+ CFTypeRef keychainOrArray,
+ Boolean returnOnlyValidIdentities,
+ SecIdentitySearchRef* searchRef);
+# endif /* !HAVE_SECIDENTITYSEARCHPRIV_H && HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY */
+# if !defined(HAVE_SECPOLICYPRIV_H) && defined(HAVE_SECPOLICYSETVALUE) /* Declare prototype for function in that header... */
+extern OSStatus SecPolicySetValue(SecPolicyRef policyRef,
+ const CSSM_DATA *value);
+# endif /* !HAVE_SECPOLICYPRIV_H && HAVE_SECPOLICYSETVALUE */
+
+typedef SSLContextRef http_tls_t;
+typedef CFArrayRef http_tls_credentials_t;
+
+extern OSStatus _httpReadCDSA(SSLConnectionRef connection, void *data,
+ size_t *dataLength);
+extern OSStatus _httpWriteCDSA(SSLConnectionRef connection, const void *data,
+ size_t *dataLength);
+
+# elif defined(HAVE_SSPISSL)
+/*
+ * Windows' SSPI library gets a CUPS wrapper...
+ */
+
+typedef _sspi_struct_t * http_tls_t;
+typedef void *http_tls_credentials_t;
+
+# else
+/*
+ * Otherwise define stub types since we have no SSL support...
+ */
+
+typedef void *http_tls_t;
+typedef void *http_tls_credentials_t;
+# endif /* HAVE_LIBSSL */
+
+struct _http_s /**** HTTP connection structure. ****/
+{
+ int fd; /* File descriptor for this socket */
+ int blocking; /* To block or not to block */
+ int error; /* Last error on read */
+ time_t activity; /* Time since last read/write */
+ http_state_t state; /* State of client */
+ http_status_t status; /* Status of last request */
+ http_version_t version; /* Protocol version */
+ http_keepalive_t keep_alive; /* Keep-alive supported? */
+ struct sockaddr_in _hostaddr; /* Address of connected host @deprecated@ */
+ char hostname[HTTP_MAX_HOST],
+ /* Name of connected host */
+ fields[HTTP_FIELD_MAX][HTTP_MAX_VALUE];
+ /* Field values */
+ char *data; /* Pointer to data buffer */
+ http_encoding_t data_encoding; /* Chunked or not */
+ int _data_remaining;/* Number of bytes left @deprecated@ */
+ int used; /* Number of bytes used in buffer */
+ char buffer[HTTP_MAX_BUFFER];
+ /* Buffer for incoming data */
+ int auth_type; /* Authentication in use */
+ _cups_md5_state_t md5_state; /* MD5 state */
+ char nonce[HTTP_MAX_VALUE];
+ /* Nonce value */
+ int nonce_count; /* Nonce count */
+ http_tls_t tls; /* TLS state information */
+ http_encryption_t encryption; /* Encryption requirements */
+ /**** New in CUPS 1.1.19 ****/
+ fd_set *input_set; /* select() set for httpWait() @deprecated@ */
+ http_status_t expect; /* Expect: header @since CUPS 1.1.19@ */
+ char *cookie; /* Cookie value(s) @since CUPS 1.1.19@ */
+ /**** New in CUPS 1.1.20 ****/
+ char _authstring[HTTP_MAX_VALUE],
+ /* Current Authentication value. @deprecated@ */
+ userpass[HTTP_MAX_VALUE];
+ /* Username:password string @since CUPS 1.1.20@ */
+ int digest_tries; /* Number of tries for digest auth @since CUPS 1.1.20@ */
+ /**** New in CUPS 1.2 ****/
+ off_t data_remaining; /* Number of bytes left @since CUPS 1.2@ */
+ http_addr_t *hostaddr; /* Current host address and port @since CUPS 1.2@ */
+ http_addrlist_t *addrlist; /* List of valid addresses @since CUPS 1.2@ */
+ char wbuffer[HTTP_MAX_BUFFER];
+ /* Buffer for outgoing data */
+ int wused; /* Write buffer bytes used @since CUPS 1.2@ */
+ /**** New in CUPS 1.3 ****/
+ char *field_authorization;
+ /* Authorization field @since CUPS 1.3@ */
+ char *authstring; /* Current authorization field @since CUPS 1.3 */
+# ifdef HAVE_GSSAPI
+ gss_OID gssmech; /* Authentication mechanism @since CUPS 1.3@ */
+ gss_ctx_id_t gssctx; /* Authentication context @since CUPS 1.3@ */
+ gss_name_t gssname; /* Authentication server name @since CUPS 1.3@ */
+# endif /* HAVE_GSSAPI */
+# ifdef HAVE_AUTHORIZATION_H
+ AuthorizationRef auth_ref; /* Authorization ref @since CUPS 1.3@ */
+# endif /* HAVE_AUTHORIZATION_H */
+ /**** New in CUPS 1.5 ****/
+ http_tls_credentials_t tls_credentials;
+ /* TLS credentials @since CUPS 1.5/Mac OS X 10.7@ */
+ http_timeout_cb_t timeout_cb; /* Timeout callback @since CUPS 1.5/Mac OS X 10.7@ */
+ void *timeout_data; /* User data pointer @since CUPS 1.5/Mac OS X 10.7@ */
+ struct timeval timeout_value; /* Timeout in seconds */
+# ifdef HAVE_GSSAPI
+ char gsshost[256]; /* Hostname for Kerberos */
+# endif /* HAVE_GSSAPI */
+};
+
+
+/*
+ * Some OS's don't have hstrerror(), most notably Solaris...
+ */
+
+# ifndef HAVE_HSTRERROR
+extern const char *_cups_hstrerror(int error);
+# define hstrerror _cups_hstrerror
+# elif defined(_AIX) || defined(__osf__)
+/*
+ * AIX and Tru64 UNIX don't provide a prototype but do provide the function...
+ */
+extern const char *hstrerror(int error);
+# endif /* !HAVE_HSTRERROR */
+
+
+/*
+ * Some OS's don't have getifaddrs() and freeifaddrs()...
+ */
+
+# if !defined(WIN32) && !defined(HAVE_GETIFADDRS)
+# ifdef ifa_dstaddr
+# undef ifa_dstaddr
+# endif /* ifa_dstaddr */
+# ifndef ifr_netmask
+# define ifr_netmask ifr_addr
+# endif /* !ifr_netmask */
+
+struct ifaddrs /**** Interface Structure ****/
+{
+ struct ifaddrs *ifa_next; /* Next interface in list */
+ char *ifa_name; /* Name of interface */
+ unsigned int ifa_flags; /* Flags (up, point-to-point, etc.) */
+ struct sockaddr *ifa_addr, /* Network address */
+ *ifa_netmask; /* Address mask */
+ union
+ {
+ struct sockaddr *ifu_broadaddr; /* Broadcast address of this interface. */
+ struct sockaddr *ifu_dstaddr; /* Point-to-point destination address. */
+ } ifa_ifu;
+
+ void *ifa_data; /* Interface statistics */
+};
+
+# ifndef ifa_broadaddr
+# define ifa_broadaddr ifa_ifu.ifu_broadaddr
+# endif /* !ifa_broadaddr */
+# ifndef ifa_dstaddr
+# define ifa_dstaddr ifa_ifu.ifu_dstaddr
+# endif /* !ifa_dstaddr */
+
+extern int _cups_getifaddrs(struct ifaddrs **addrs);
+# define getifaddrs _cups_getifaddrs
+extern void _cups_freeifaddrs(struct ifaddrs *addrs);
+# define freeifaddrs _cups_freeifaddrs
+# endif /* !WIN32 && !HAVE_GETIFADDRS */
+
+
+/*
+ * Prototypes...
+ */
+
+#define _httpAddrFamily(addrp) (addrp)->addr.sa_family
+extern int _httpAddrPort(http_addr_t *addr);
+extern void _httpAddrSetPort(http_addr_t *addr, int port);
+extern char *_httpAssembleUUID(const char *server, int port,
+ const char *name, int number,
+ char *buffer, size_t bufsize);
+extern http_tls_credentials_t
+ _httpConvertCredentials(cups_array_t *credentials);
+extern http_t *_httpCreate(const char *host, int port,
+ http_addrlist_t *addrlist,
+ http_encryption_t encryption,
+ int family);
+extern char *_httpDecodeURI(char *dst, const char *src,
+ size_t dstsize);
+extern void _httpDisconnect(http_t *http);
+extern char *_httpEncodeURI(char *dst, const char *src,
+ size_t dstsize);
+extern void _httpFreeCredentials(http_tls_credentials_t credentials);
+extern ssize_t _httpPeek(http_t *http, char *buffer, size_t length);
+extern const char *_httpResolveURI(const char *uri, char *resolved_uri,
+ size_t resolved_size, int options,
+ int (*cb)(void *context),
+ void *context);
+extern int _httpUpdate(http_t *http, http_status_t *status);
+extern int _httpWait(http_t *http, int msec, int usessl);
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_HTTP_PRIVATE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/http-support.c b/cups/http-support.c
new file mode 100644
index 000000000..d77010750
--- /dev/null
+++ b/cups/http-support.c
@@ -0,0 +1,1900 @@
+/*
+ * "$Id$"
+ *
+ * HTTP support routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * httpAssembleURI() - Assemble a uniform resource identifier from its
+ * components.
+ * httpAssembleURIf() - Assemble a uniform resource identifier from its
+ * components with a formatted resource.
+ * _httpAssembleUUID() - Make a UUID URI conforming to RFC 4122.
+ * httpDecode64() - Base64-decode a string.
+ * httpDecode64_2() - Base64-decode a string.
+ * httpEncode64() - Base64-encode a string.
+ * httpEncode64_2() - Base64-encode a string.
+ * httpGetDateString() - Get a formatted date/time string from a time value.
+ * httpGetDateString2() - Get a formatted date/time string from a time value.
+ * httpGetDateTime() - Get a time value from a formatted date/time string.
+ * httpSeparate() - Separate a Universal Resource Identifier into its
+ * components.
+ * httpSeparate2() - Separate a Universal Resource Identifier into its
+ * components.
+ * httpSeparateURI() - Separate a Universal Resource Identifier into its
+ * components.
+ * httpStatus() - Return a short string describing a HTTP status code.
+ * _cups_hstrerror() - hstrerror() emulation function for Solaris and
+ * others.
+ * _httpDecodeURI() - Percent-decode a HTTP request URI.
+ * _httpEncodeURI() - Percent-encode a HTTP request URI.
+ * _httpResolveURI() - Resolve a DNS-SD URI.
+ * http_copy_decode() - Copy and decode a URI.
+ * http_copy_encode() - Copy and encode a URI.
+ * http_resolve_cb() - Build a device URI for the given service name.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#ifdef HAVE_DNSSD
+# include <dns_sd.h>
+# ifdef WIN32
+# include <io.h>
+# elif defined(HAVE_POLL)
+# include <poll.h>
+# else
+# include <sys/select.h>
+# endif /* WIN32 */
+#endif /* HAVE_DNSSD */
+
+
+/*
+ * Local types...
+ */
+
+typedef struct _http_uribuf_s /* URI buffer */
+{
+ char *buffer; /* Pointer to buffer */
+ size_t bufsize; /* Size of buffer */
+ int options; /* Options passed to _httpResolveURI */
+} _http_uribuf_t;
+
+
+/*
+ * Local globals...
+ */
+
+static const char * const http_days[7] =
+ {
+ "Sun",
+ "Mon",
+ "Tue",
+ "Wed",
+ "Thu",
+ "Fri",
+ "Sat"
+ };
+static const char * const http_months[12] =
+ {
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec"
+ };
+
+
+/*
+ * Local functions...
+ */
+
+static const char *http_copy_decode(char *dst, const char *src,
+ int dstsize, const char *term,
+ int decode);
+static char *http_copy_encode(char *dst, const char *src,
+ char *dstend, const char *reserved,
+ const char *term, int encode);
+#ifdef HAVE_DNSSD
+static void DNSSD_API http_resolve_cb(DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *fullName,
+ const char *hostTarget,
+ uint16_t port, uint16_t txtLen,
+ const unsigned char *txtRecord,
+ void *context);
+#endif /* HAVE_DNSSD */
+
+
+/*
+ * 'httpAssembleURI()' - Assemble a uniform resource identifier from its
+ * components.
+ *
+ * This function escapes reserved characters in the URI depending on the
+ * value of the "encoding" argument. You should use this function in
+ * place of traditional string functions whenever you need to create a
+ * URI string.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+http_uri_status_t /* O - URI status */
+httpAssembleURI(
+ http_uri_coding_t encoding, /* I - Encoding flags */
+ char *uri, /* I - URI buffer */
+ int urilen, /* I - Size of URI buffer */
+ const char *scheme, /* I - Scheme name */
+ const char *username, /* I - Username */
+ const char *host, /* I - Hostname or address */
+ int port, /* I - Port number */
+ const char *resource) /* I - Resource */
+{
+ char *ptr, /* Pointer into URI buffer */
+ *end; /* End of URI buffer */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!uri || urilen < 1 || !scheme || port < 0)
+ {
+ if (uri)
+ *uri = '\0';
+
+ return (HTTP_URI_BAD_ARGUMENTS);
+ }
+
+ /*
+ * Assemble the URI starting with the scheme...
+ */
+
+ end = uri + urilen - 1;
+ ptr = http_copy_encode(uri, scheme, end, NULL, NULL, 0);
+
+ if (!ptr)
+ goto assemble_overflow;
+
+ if (!strcmp(scheme, "mailto"))
+ {
+ /*
+ * mailto: only has :, no //...
+ */
+
+ if (ptr < end)
+ *ptr++ = ':';
+ else
+ goto assemble_overflow;
+ }
+ else
+ {
+ /*
+ * Schemes other than mailto: all have //...
+ */
+
+ if ((ptr + 2) < end)
+ {
+ *ptr++ = ':';
+ *ptr++ = '/';
+ *ptr++ = '/';
+ }
+ else
+ goto assemble_overflow;
+ }
+
+ /*
+ * Next the username and hostname, if any...
+ */
+
+ if (host)
+ {
+ if (username && *username)
+ {
+ /*
+ * Add username@ first...
+ */
+
+ ptr = http_copy_encode(ptr, username, end, "/?@", NULL,
+ encoding & HTTP_URI_CODING_USERNAME);
+
+ if (!ptr)
+ goto assemble_overflow;
+
+ if (ptr < end)
+ *ptr++ = '@';
+ else
+ goto assemble_overflow;
+ }
+
+ /*
+ * Then add the hostname. Since IPv6 is a particular pain to deal
+ * with, we have several special cases to deal with. If we get
+ * an IPv6 address with brackets around it, assume it is already in
+ * URI format. Since DNS-SD service names can sometimes look like
+ * raw IPv6 addresses, we specifically look for "._tcp" in the name,
+ * too...
+ */
+
+ if (host[0] != '[' && strchr(host, ':') && !strstr(host, "._tcp"))
+ {
+ /*
+ * We have a raw IPv6 address...
+ */
+
+ if (strchr(host, '%'))
+ {
+ /*
+ * We have a link-local address, add "[v1." prefix...
+ */
+
+ if ((ptr + 4) < end)
+ {
+ *ptr++ = '[';
+ *ptr++ = 'v';
+ *ptr++ = '1';
+ *ptr++ = '.';
+ }
+ else
+ goto assemble_overflow;
+ }
+ else
+ {
+ /*
+ * We have a normal address, add "[" prefix...
+ */
+
+ if (ptr < end)
+ *ptr++ = '[';
+ else
+ goto assemble_overflow;
+ }
+
+ /*
+ * Copy the rest of the IPv6 address, and terminate with "]".
+ */
+
+ while (ptr < end && *host)
+ {
+ if (*host == '%')
+ {
+ *ptr++ = '+'; /* Convert zone separator */
+ host ++;
+ }
+ else
+ *ptr++ = *host++;
+ }
+
+ if (*host)
+ goto assemble_overflow;
+
+ if (ptr < end)
+ *ptr++ = ']';
+ else
+ goto assemble_overflow;
+ }
+ else
+ {
+ /*
+ * Otherwise, just copy the host string...
+ */
+
+ ptr = http_copy_encode(ptr, host, end, ":/?#[]@\\\"", NULL,
+ encoding & HTTP_URI_CODING_HOSTNAME);
+
+ if (!ptr)
+ goto assemble_overflow;
+ }
+
+ /*
+ * Finish things off with the port number...
+ */
+
+ if (port > 0)
+ {
+ snprintf(ptr, end - ptr + 1, ":%d", port);
+ ptr += strlen(ptr);
+
+ if (ptr >= end)
+ goto assemble_overflow;
+ }
+ }
+
+ /*
+ * Last but not least, add the resource string...
+ */
+
+ if (resource)
+ {
+ char *query; /* Pointer to query string */
+
+
+ /*
+ * Copy the resource string up to the query string if present...
+ */
+
+ query = strchr(resource, '?');
+ ptr = http_copy_encode(ptr, resource, end, NULL, "?",
+ encoding & HTTP_URI_CODING_RESOURCE);
+ if (!ptr)
+ goto assemble_overflow;
+
+ if (query)
+ {
+ /*
+ * Copy query string without encoding...
+ */
+
+ ptr = http_copy_encode(ptr, query, end, NULL, NULL,
+ encoding & HTTP_URI_CODING_QUERY);
+ if (!ptr)
+ goto assemble_overflow;
+ }
+ }
+ else if (ptr < end)
+ *ptr++ = '/';
+ else
+ goto assemble_overflow;
+
+ /*
+ * Nul-terminate the URI buffer and return with no errors...
+ */
+
+ *ptr = '\0';
+
+ return (HTTP_URI_OK);
+
+ /*
+ * Clear the URI string and return an overflow error; I don't usually
+ * like goto's, but in this case it makes sense...
+ */
+
+ assemble_overflow:
+
+ *uri = '\0';
+ return (HTTP_URI_OVERFLOW);
+}
+
+
+/*
+ * 'httpAssembleURIf()' - Assemble a uniform resource identifier from its
+ * components with a formatted resource.
+ *
+ * This function creates a formatted version of the resource string
+ * argument "resourcef" and escapes reserved characters in the URI
+ * depending on the value of the "encoding" argument. You should use
+ * this function in place of traditional string functions whenever
+ * you need to create a URI string.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+http_uri_status_t /* O - URI status */
+httpAssembleURIf(
+ http_uri_coding_t encoding, /* I - Encoding flags */
+ char *uri, /* I - URI buffer */
+ int urilen, /* I - Size of URI buffer */
+ const char *scheme, /* I - Scheme name */
+ const char *username, /* I - Username */
+ const char *host, /* I - Hostname or address */
+ int port, /* I - Port number */
+ const char *resourcef, /* I - Printf-style resource */
+ ...) /* I - Additional arguments as needed */
+{
+ va_list ap; /* Pointer to additional arguments */
+ char resource[1024]; /* Formatted resource string */
+ int bytes; /* Bytes in formatted string */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!uri || urilen < 1 || !scheme || port < 0 || !resourcef)
+ {
+ if (uri)
+ *uri = '\0';
+
+ return (HTTP_URI_BAD_ARGUMENTS);
+ }
+
+ /*
+ * Format the resource string and assemble the URI...
+ */
+
+ va_start(ap, resourcef);
+ bytes = vsnprintf(resource, sizeof(resource), resourcef, ap);
+ va_end(ap);
+
+ if (bytes >= sizeof(resource))
+ {
+ *uri = '\0';
+ return (HTTP_URI_OVERFLOW);
+ }
+ else
+ return (httpAssembleURI(encoding, uri, urilen, scheme, username, host,
+ port, resource));
+}
+
+
+/*
+ * '_httpAssembleUUID()' - Make a UUID URI conforming to RFC 4122.
+ *
+ * The buffer needs to be at least 46 bytes in size.
+ */
+
+char * /* I - UUID string */
+_httpAssembleUUID(const char *server, /* I - Server name */
+ int port, /* I - Port number */
+ const char *name, /* I - Object name or NULL */
+ int number, /* I - Object number or 0 */
+ char *buffer, /* I - String buffer */
+ size_t bufsize) /* I - Size of buffer */
+{
+ char data[1024]; /* Source string for MD5 */
+ _cups_md5_state_t md5state; /* MD5 state */
+ unsigned char md5sum[16]; /* MD5 digest/sum */
+
+
+ /*
+ * Build a version 3 UUID conforming to RFC 4122.
+ *
+ * Start with the MD5 sum of the server, port, object name and
+ * number, and some random data on the end.
+ */
+
+ snprintf(data, sizeof(data), "%s:%d:%s:%d:%04x:%04x", server,
+ port, name ? name : server, number,
+ CUPS_RAND() & 0xffff, CUPS_RAND() & 0xffff);
+
+ _cupsMD5Init(&md5state);
+ _cupsMD5Append(&md5state, (unsigned char *)data, strlen(data));
+ _cupsMD5Finish(&md5state, md5sum);
+
+ /*
+ * Generate the UUID from the MD5...
+ */
+
+ snprintf(buffer, bufsize,
+ "urn:uuid:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
+ "%02x%02x%02x%02x%02x%02x",
+ md5sum[0], md5sum[1], md5sum[2], md5sum[3], md5sum[4], md5sum[5],
+ (md5sum[6] & 15) | 0x30, md5sum[7], (md5sum[8] & 0x3f) | 0x40,
+ md5sum[9], md5sum[10], md5sum[11], md5sum[12], md5sum[13],
+ md5sum[14], md5sum[15]);
+
+ return (buffer);
+}
+
+
+/*
+ * 'httpDecode64()' - Base64-decode a string.
+ *
+ * This function is deprecated. Use the httpDecode64_2() function instead
+ * which provides buffer length arguments.
+ *
+ * @deprecated@
+ */
+
+char * /* O - Decoded string */
+httpDecode64(char *out, /* I - String to write to */
+ const char *in) /* I - String to read from */
+{
+ int outlen; /* Output buffer length */
+
+
+ /*
+ * Use the old maximum buffer size for binary compatibility...
+ */
+
+ outlen = 512;
+
+ return (httpDecode64_2(out, &outlen, in));
+}
+
+
+/*
+ * 'httpDecode64_2()' - Base64-decode a string.
+ *
+ * @since CUPS 1.1.21/Mac OS X 10.4@
+ */
+
+char * /* O - Decoded string */
+httpDecode64_2(char *out, /* I - String to write to */
+ int *outlen, /* IO - Size of output string */
+ const char *in) /* I - String to read from */
+{
+ int pos, /* Bit position */
+ base64; /* Value of this character */
+ char *outptr, /* Output pointer */
+ *outend; /* End of output buffer */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!out || !outlen || *outlen < 1 || !in)
+ return (NULL);
+
+ if (!*in)
+ {
+ *out = '\0';
+ *outlen = 0;
+
+ return (out);
+ }
+
+ /*
+ * Convert from base-64 to bytes...
+ */
+
+ for (outptr = out, outend = out + *outlen - 1, pos = 0; *in != '\0'; in ++)
+ {
+ /*
+ * Decode this character into a number from 0 to 63...
+ */
+
+ if (*in >= 'A' && *in <= 'Z')
+ base64 = *in - 'A';
+ else if (*in >= 'a' && *in <= 'z')
+ base64 = *in - 'a' + 26;
+ else if (*in >= '0' && *in <= '9')
+ base64 = *in - '0' + 52;
+ else if (*in == '+')
+ base64 = 62;
+ else if (*in == '/')
+ base64 = 63;
+ else if (*in == '=')
+ break;
+ else
+ continue;
+
+ /*
+ * Store the result in the appropriate chars...
+ */
+
+ switch (pos)
+ {
+ case 0 :
+ if (outptr < outend)
+ *outptr = base64 << 2;
+ pos ++;
+ break;
+ case 1 :
+ if (outptr < outend)
+ *outptr++ |= (base64 >> 4) & 3;
+ if (outptr < outend)
+ *outptr = (base64 << 4) & 255;
+ pos ++;
+ break;
+ case 2 :
+ if (outptr < outend)
+ *outptr++ |= (base64 >> 2) & 15;
+ if (outptr < outend)
+ *outptr = (base64 << 6) & 255;
+ pos ++;
+ break;
+ case 3 :
+ if (outptr < outend)
+ *outptr++ |= base64;
+ pos = 0;
+ break;
+ }
+ }
+
+ *outptr = '\0';
+
+ /*
+ * Return the decoded string and size...
+ */
+
+ *outlen = (int)(outptr - out);
+
+ return (out);
+}
+
+
+/*
+ * 'httpEncode64()' - Base64-encode a string.
+ *
+ * This function is deprecated. Use the httpEncode64_2() function instead
+ * which provides buffer length arguments.
+ *
+ * @deprecated@
+ */
+
+char * /* O - Encoded string */
+httpEncode64(char *out, /* I - String to write to */
+ const char *in) /* I - String to read from */
+{
+ return (httpEncode64_2(out, 512, in, (int)strlen(in)));
+}
+
+
+/*
+ * 'httpEncode64_2()' - Base64-encode a string.
+ *
+ * @since CUPS 1.1.21/Mac OS X 10.4@
+ */
+
+char * /* O - Encoded string */
+httpEncode64_2(char *out, /* I - String to write to */
+ int outlen, /* I - Size of output string */
+ const char *in, /* I - String to read from */
+ int inlen) /* I - Size of input string */
+{
+ char *outptr, /* Output pointer */
+ *outend; /* End of output buffer */
+ static const char base64[] = /* Base64 characters... */
+ {
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "+/"
+ };
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!out || outlen < 1 || !in)
+ return (NULL);
+
+ /*
+ * Convert bytes to base-64...
+ */
+
+ for (outptr = out, outend = out + outlen - 1; inlen > 0; in ++, inlen --)
+ {
+ /*
+ * Encode the up to 3 characters as 4 Base64 numbers...
+ */
+
+ if (outptr < outend)
+ *outptr ++ = base64[(in[0] & 255) >> 2];
+
+ if (outptr < outend)
+ {
+ if (inlen > 1)
+ *outptr ++ = base64[(((in[0] & 255) << 4) | ((in[1] & 255) >> 4)) & 63];
+ else
+ *outptr ++ = base64[((in[0] & 255) << 4) & 63];
+ }
+
+ in ++;
+ inlen --;
+ if (inlen <= 0)
+ {
+ if (outptr < outend)
+ *outptr ++ = '=';
+ if (outptr < outend)
+ *outptr ++ = '=';
+ break;
+ }
+
+ if (outptr < outend)
+ {
+ if (inlen > 1)
+ *outptr ++ = base64[(((in[0] & 255) << 2) | ((in[1] & 255) >> 6)) & 63];
+ else
+ *outptr ++ = base64[((in[0] & 255) << 2) & 63];
+ }
+
+ in ++;
+ inlen --;
+ if (inlen <= 0)
+ {
+ if (outptr < outend)
+ *outptr ++ = '=';
+ break;
+ }
+
+ if (outptr < outend)
+ *outptr ++ = base64[in[0] & 63];
+ }
+
+ *outptr = '\0';
+
+ /*
+ * Return the encoded string...
+ */
+
+ return (out);
+}
+
+
+/*
+ * 'httpGetDateString()' - Get a formatted date/time string from a time value.
+ *
+ * @deprecated@
+ */
+
+const char * /* O - Date/time string */
+httpGetDateString(time_t t) /* I - UNIX time */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ return (httpGetDateString2(t, cg->http_date, sizeof(cg->http_date)));
+}
+
+
+/*
+ * 'httpGetDateString2()' - Get a formatted date/time string from a time value.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+const char * /* O - Date/time string */
+httpGetDateString2(time_t t, /* I - UNIX time */
+ char *s, /* I - String buffer */
+ int slen) /* I - Size of string buffer */
+{
+ struct tm *tdate; /* UNIX date/time data */
+
+
+ tdate = gmtime(&t);
+ snprintf(s, slen, "%s, %02d %s %d %02d:%02d:%02d GMT",
+ http_days[tdate->tm_wday], tdate->tm_mday,
+ http_months[tdate->tm_mon], tdate->tm_year + 1900,
+ tdate->tm_hour, tdate->tm_min, tdate->tm_sec);
+
+ return (s);
+}
+
+
+/*
+ * 'httpGetDateTime()' - Get a time value from a formatted date/time string.
+ */
+
+time_t /* O - UNIX time */
+httpGetDateTime(const char *s) /* I - Date/time string */
+{
+ int i; /* Looping var */
+ char mon[16]; /* Abbreviated month name */
+ int day, year; /* Day of month and year */
+ int hour, min, sec; /* Time */
+ int days; /* Number of days since 1970 */
+ static const int normal_days[] = /* Days to a month, normal years */
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
+ static const int leap_days[] = /* Days to a month, leap years */
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
+
+
+ DEBUG_printf(("2httpGetDateTime(s=\"%s\")", s));
+
+ /*
+ * Extract the date and time from the formatted string...
+ */
+
+ if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6)
+ return (0);
+
+ DEBUG_printf(("4httpGetDateTime: day=%d, mon=\"%s\", year=%d, hour=%d, "
+ "min=%d, sec=%d", day, mon, year, hour, min, sec));
+
+ /*
+ * Convert the month name to a number from 0 to 11.
+ */
+
+ for (i = 0; i < 12; i ++)
+ if (!_cups_strcasecmp(mon, http_months[i]))
+ break;
+
+ if (i >= 12)
+ return (0);
+
+ DEBUG_printf(("4httpGetDateTime: i=%d", i));
+
+ /*
+ * Now convert the date and time to a UNIX time value in seconds since
+ * 1970. We can't use mktime() since the timezone may not be UTC but
+ * the date/time string *is* UTC.
+ */
+
+ if ((year & 3) == 0 && ((year % 100) != 0 || (year % 400) == 0))
+ days = leap_days[i] + day - 1;
+ else
+ days = normal_days[i] + day - 1;
+
+ DEBUG_printf(("4httpGetDateTime: days=%d", days));
+
+ days += (year - 1970) * 365 + /* 365 days per year (normally) */
+ ((year - 1) / 4 - 492) - /* + leap days */
+ ((year - 1) / 100 - 19) + /* - 100 year days */
+ ((year - 1) / 400 - 4); /* + 400 year days */
+
+ DEBUG_printf(("4httpGetDateTime: days=%d\n", days));
+
+ return (days * 86400 + hour * 3600 + min * 60 + sec);
+}
+
+
+/*
+ * 'httpSeparate()' - Separate a Universal Resource Identifier into its
+ * components.
+ *
+ * This function is deprecated; use the httpSeparateURI() function instead.
+ *
+ * @deprecated@
+ */
+
+void
+httpSeparate(const char *uri, /* I - Universal Resource Identifier */
+ char *scheme, /* O - Scheme [32] (http, https, etc.) */
+ char *username, /* O - Username [1024] */
+ char *host, /* O - Hostname [1024] */
+ int *port, /* O - Port number to use */
+ char *resource) /* O - Resource/filename [1024] */
+{
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, 32, username,
+ HTTP_MAX_URI, host, HTTP_MAX_URI, port, resource,
+ HTTP_MAX_URI);
+}
+
+
+/*
+ * 'httpSeparate2()' - Separate a Universal Resource Identifier into its
+ * components.
+ *
+ * This function is deprecated; use the httpSeparateURI() function instead.
+ *
+ * @since CUPS 1.1.21/Mac OS X 10.4@
+ * @deprecated@
+ */
+
+void
+httpSeparate2(const char *uri, /* I - Universal Resource Identifier */
+ char *scheme, /* O - Scheme (http, https, etc.) */
+ int schemelen, /* I - Size of scheme buffer */
+ char *username, /* O - Username */
+ int usernamelen, /* I - Size of username buffer */
+ char *host, /* O - Hostname */
+ int hostlen, /* I - Size of hostname buffer */
+ int *port, /* O - Port number to use */
+ char *resource, /* O - Resource/filename */
+ int resourcelen) /* I - Size of resource buffer */
+{
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, schemelen, username,
+ usernamelen, host, hostlen, port, resource, resourcelen);
+}
+
+
+/*
+ * 'httpSeparateURI()' - Separate a Universal Resource Identifier into its
+ * components.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+http_uri_status_t /* O - Result of separation */
+httpSeparateURI(
+ http_uri_coding_t decoding, /* I - Decoding flags */
+ const char *uri, /* I - Universal Resource Identifier */
+ char *scheme, /* O - Scheme (http, https, etc.) */
+ int schemelen, /* I - Size of scheme buffer */
+ char *username, /* O - Username */
+ int usernamelen, /* I - Size of username buffer */
+ char *host, /* O - Hostname */
+ int hostlen, /* I - Size of hostname buffer */
+ int *port, /* O - Port number to use */
+ char *resource, /* O - Resource/filename */
+ int resourcelen) /* I - Size of resource buffer */
+{
+ char *ptr, /* Pointer into string... */
+ *end; /* End of string */
+ const char *sep; /* Separator character */
+ http_uri_status_t status; /* Result of separation */
+
+
+ /*
+ * Initialize everything to blank...
+ */
+
+ if (scheme && schemelen > 0)
+ *scheme = '\0';
+
+ if (username && usernamelen > 0)
+ *username = '\0';
+
+ if (host && hostlen > 0)
+ *host = '\0';
+
+ if (port)
+ *port = 0;
+
+ if (resource && resourcelen > 0)
+ *resource = '\0';
+
+ /*
+ * Range check input...
+ */
+
+ if (!uri || !port || !scheme || schemelen <= 0 || !username ||
+ usernamelen <= 0 || !host || hostlen <= 0 || !resource ||
+ resourcelen <= 0)
+ return (HTTP_URI_BAD_ARGUMENTS);
+
+ if (!*uri)
+ return (HTTP_URI_BAD_URI);
+
+ /*
+ * Grab the scheme portion of the URI...
+ */
+
+ status = HTTP_URI_OK;
+
+ if (!strncmp(uri, "//", 2))
+ {
+ /*
+ * Workaround for HP IPP client bug...
+ */
+
+ strlcpy(scheme, "ipp", schemelen);
+ status = HTTP_URI_MISSING_SCHEME;
+ }
+ else if (*uri == '/')
+ {
+ /*
+ * Filename...
+ */
+
+ strlcpy(scheme, "file", schemelen);
+ status = HTTP_URI_MISSING_SCHEME;
+ }
+ else
+ {
+ /*
+ * Standard URI with scheme...
+ */
+
+ for (ptr = scheme, end = scheme + schemelen - 1;
+ *uri && *uri != ':' && ptr < end;)
+ if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789-+.", *uri) != NULL)
+ *ptr++ = *uri++;
+ else
+ break;
+
+ *ptr = '\0';
+
+ if (*uri != ':')
+ {
+ *scheme = '\0';
+ return (HTTP_URI_BAD_SCHEME);
+ }
+
+ uri ++;
+ }
+
+ /*
+ * Set the default port number...
+ */
+
+ if (!strcmp(scheme, "http"))
+ *port = 80;
+ else if (!strcmp(scheme, "https"))
+ *port = 443;
+ else if (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps"))
+ *port = 631;
+ else if (!_cups_strcasecmp(scheme, "lpd"))
+ *port = 515;
+ else if (!strcmp(scheme, "socket")) /* Not yet registered with IANA... */
+ *port = 9100;
+ else if (strcmp(scheme, "file") && strcmp(scheme, "mailto"))
+ status = HTTP_URI_UNKNOWN_SCHEME;
+
+ /*
+ * Now see if we have a hostname...
+ */
+
+ if (!strncmp(uri, "//", 2))
+ {
+ /*
+ * Yes, extract it...
+ */
+
+ uri += 2;
+
+ /*
+ * Grab the username, if any...
+ */
+
+ if ((sep = strpbrk(uri, "@/")) != NULL && *sep == '@')
+ {
+ /*
+ * Get a username:password combo...
+ */
+
+ uri = http_copy_decode(username, uri, usernamelen, "@",
+ decoding & HTTP_URI_CODING_USERNAME);
+
+ if (!uri)
+ {
+ *username = '\0';
+ return (HTTP_URI_BAD_USERNAME);
+ }
+
+ uri ++;
+ }
+
+ /*
+ * Then the hostname/IP address...
+ */
+
+ if (*uri == '[')
+ {
+ /*
+ * Grab IPv6 address...
+ */
+
+ uri ++;
+ if (!strncmp(uri, "v1.", 3))
+ uri += 3; /* Skip IPvN leader... */
+
+ uri = http_copy_decode(host, uri, hostlen, "]",
+ decoding & HTTP_URI_CODING_HOSTNAME);
+
+ if (!uri)
+ {
+ *host = '\0';
+ return (HTTP_URI_BAD_HOSTNAME);
+ }
+
+ /*
+ * Validate value...
+ */
+
+ if (*uri != ']')
+ {
+ *host = '\0';
+ return (HTTP_URI_BAD_HOSTNAME);
+ }
+
+ uri ++;
+
+ for (ptr = host; *ptr; ptr ++)
+ if (*ptr == '+')
+ {
+ /*
+ * Convert zone separator to % and stop here...
+ */
+
+ *ptr = '%';
+ break;
+ }
+ else if (*ptr != ':' && *ptr != '.' && !isxdigit(*ptr & 255))
+ {
+ *host = '\0';
+ return (HTTP_URI_BAD_HOSTNAME);
+ }
+ }
+ else
+ {
+ /*
+ * Validate the hostname or IPv4 address first...
+ */
+
+ for (ptr = (char *)uri; *ptr; ptr ++)
+ if (strchr(":?/", *ptr))
+ break;
+ else if (!strchr("abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789"
+ "-._~"
+ "%"
+ "!$&'()*+,;=\\", *ptr))
+ {
+ *host = '\0';
+ return (HTTP_URI_BAD_HOSTNAME);
+ }
+
+ /*
+ * Then copy the hostname or IPv4 address to the buffer...
+ */
+
+ uri = http_copy_decode(host, uri, hostlen, ":?/",
+ decoding & HTTP_URI_CODING_HOSTNAME);
+
+ if (!uri)
+ {
+ *host = '\0';
+ return (HTTP_URI_BAD_HOSTNAME);
+ }
+ }
+
+ /*
+ * Validate hostname for file scheme - only empty and localhost are
+ * acceptable.
+ */
+
+ if (!strcmp(scheme, "file") && strcmp(host, "localhost") && host[0])
+ {
+ *host = '\0';
+ return (HTTP_URI_BAD_HOSTNAME);
+ }
+
+ /*
+ * See if we have a port number...
+ */
+
+ if (*uri == ':')
+ {
+ /*
+ * Yes, collect the port number...
+ */
+
+ if (!isdigit(uri[1] & 255))
+ {
+ *port = 0;
+ return (HTTP_URI_BAD_PORT);
+ }
+
+ *port = strtol(uri + 1, (char **)&uri, 10);
+
+ if (*uri != '/' && *uri)
+ {
+ *port = 0;
+ return (HTTP_URI_BAD_PORT);
+ }
+ }
+ }
+
+ /*
+ * The remaining portion is the resource string...
+ */
+
+ if (*uri == '?' || !*uri)
+ {
+ /*
+ * Hostname but no path...
+ */
+
+ status = HTTP_URI_MISSING_RESOURCE;
+ *resource = '/';
+
+ /*
+ * Copy any query string...
+ */
+
+ if (*uri == '?')
+ uri = http_copy_decode(resource + 1, uri, resourcelen - 1, NULL,
+ decoding & HTTP_URI_CODING_QUERY);
+ else
+ resource[1] = '\0';
+ }
+ else
+ {
+ uri = http_copy_decode(resource, uri, resourcelen, "?",
+ decoding & HTTP_URI_CODING_RESOURCE);
+
+ if (uri && *uri == '?')
+ {
+ /*
+ * Concatenate any query string...
+ */
+
+ char *resptr = resource + strlen(resource);
+
+ uri = http_copy_decode(resptr, uri, resourcelen - (int)(resptr - resource),
+ NULL, decoding & HTTP_URI_CODING_QUERY);
+ }
+ }
+
+ if (!uri)
+ {
+ *resource = '\0';
+ return (HTTP_URI_BAD_RESOURCE);
+ }
+
+ /*
+ * Return the URI separation status...
+ */
+
+ return (status);
+}
+
+
+/*
+ * 'httpStatus()' - Return a short string describing a HTTP status code.
+ *
+ * The returned string is localized to the current POSIX locale and is based
+ * on the status strings defined in RFC 2616.
+ */
+
+const char * /* O - Localized status string */
+httpStatus(http_status_t status) /* I - HTTP status code */
+{
+ const char *s; /* Status string */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+
+
+ if (!cg->lang_default)
+ cg->lang_default = cupsLangDefault();
+
+ switch (status)
+ {
+ case HTTP_CONTINUE :
+ s = _("Continue");
+ break;
+ case HTTP_SWITCHING_PROTOCOLS :
+ s = _("Switching Protocols");
+ break;
+ case HTTP_OK :
+ s = _("OK");
+ break;
+ case HTTP_CREATED :
+ s = _("Created");
+ break;
+ case HTTP_ACCEPTED :
+ s = _("Accepted");
+ break;
+ case HTTP_NO_CONTENT :
+ s = _("No Content");
+ break;
+ case HTTP_MOVED_PERMANENTLY :
+ s = _("Moved Permanently");
+ break;
+ case HTTP_SEE_OTHER :
+ s = _("See Other");
+ break;
+ case HTTP_NOT_MODIFIED :
+ s = _("Not Modified");
+ break;
+ case HTTP_BAD_REQUEST :
+ s = _("Bad Request");
+ break;
+ case HTTP_UNAUTHORIZED :
+ case HTTP_AUTHORIZATION_CANCELED :
+ s = _("Unauthorized");
+ break;
+ case HTTP_FORBIDDEN :
+ s = _("Forbidden");
+ break;
+ case HTTP_NOT_FOUND :
+ s = _("Not Found");
+ break;
+ case HTTP_REQUEST_TOO_LARGE :
+ s = _("Request Entity Too Large");
+ break;
+ case HTTP_URI_TOO_LONG :
+ s = _("URI Too Long");
+ break;
+ case HTTP_UPGRADE_REQUIRED :
+ s = _("Upgrade Required");
+ break;
+ case HTTP_NOT_IMPLEMENTED :
+ s = _("Not Implemented");
+ break;
+ case HTTP_NOT_SUPPORTED :
+ s = _("Not Supported");
+ break;
+ case HTTP_EXPECTATION_FAILED :
+ s = _("Expectation Failed");
+ break;
+ case HTTP_SERVICE_UNAVAILABLE :
+ s = _("Service Unavailable");
+ break;
+ case HTTP_SERVER_ERROR :
+ s = _("Internal Server Error");
+ break;
+ case HTTP_PKI_ERROR :
+ s = _("SSL/TLS Negotiation Error");
+ break;
+ case HTTP_WEBIF_DISABLED :
+ s = _("Web Interface is Disabled");
+ break;
+
+ default :
+ s = _("Unknown");
+ break;
+ }
+
+ return (_cupsLangString(cg->lang_default, s));
+}
+
+
+#ifndef HAVE_HSTRERROR
+/*
+ * '_cups_hstrerror()' - hstrerror() emulation function for Solaris and others.
+ */
+
+const char * /* O - Error string */
+_cups_hstrerror(int error) /* I - Error number */
+{
+ static const char * const errors[] = /* Error strings */
+ {
+ "OK",
+ "Host not found.",
+ "Try again.",
+ "Unrecoverable lookup error.",
+ "No data associated with name."
+ };
+
+
+ if (error < 0 || error > 4)
+ return ("Unknown hostname lookup error.");
+ else
+ return (errors[error]);
+}
+#endif /* !HAVE_HSTRERROR */
+
+
+/*
+ * '_httpDecodeURI()' - Percent-decode a HTTP request URI.
+ */
+
+char * /* O - Decoded URI or NULL on error */
+_httpDecodeURI(char *dst, /* I - Destination buffer */
+ const char *src, /* I - Source URI */
+ size_t dstsize) /* I - Size of destination buffer */
+{
+ if (http_copy_decode(dst, src, (int)dstsize, NULL, 1))
+ return (dst);
+ else
+ return (NULL);
+}
+
+
+/*
+ * '_httpEncodeURI()' - Percent-encode a HTTP request URI.
+ */
+
+char * /* O - Encoded URI */
+_httpEncodeURI(char *dst, /* I - Destination buffer */
+ const char *src, /* I - Source URI */
+ size_t dstsize) /* I - Size of destination buffer */
+{
+ http_copy_encode(dst, src, dst + dstsize - 1, NULL, NULL, 1);
+ return (dst);
+}
+
+
+/*
+ * '_httpResolveURI()' - Resolve a DNS-SD URI.
+ */
+
+const char * /* O - Resolved URI */
+_httpResolveURI(
+ const char *uri, /* I - DNS-SD URI */
+ char *resolved_uri, /* I - Buffer for resolved URI */
+ size_t resolved_size, /* I - Size of URI buffer */
+ int options, /* I - Resolve options */
+ int (*cb)(void *context), /* I - Continue callback function */
+ void *context) /* I - Context pointer for callback */
+{
+ char scheme[32], /* URI components... */
+ userpass[256],
+ hostname[1024],
+ resource[1024];
+ int port;
+#ifdef DEBUG
+ http_uri_status_t status; /* URI decode status */
+#endif /* DEBUG */
+
+
+ DEBUG_printf(("4_httpResolveURI(uri=\"%s\", resolved_uri=%p, "
+ "resolved_size=" CUPS_LLFMT ")", uri, resolved_uri,
+ CUPS_LLCAST resolved_size));
+
+ /*
+ * Get the device URI...
+ */
+
+#ifdef DEBUG
+ if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme,
+ sizeof(scheme), userpass, sizeof(userpass),
+ hostname, sizeof(hostname), &port, resource,
+ sizeof(resource))) < HTTP_URI_OK)
+#else
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme,
+ sizeof(scheme), userpass, sizeof(userpass),
+ hostname, sizeof(hostname), &port, resource,
+ sizeof(resource)) < HTTP_URI_OK)
+#endif /* DEBUG */
+ {
+ if (options & _HTTP_RESOLVE_STDERR)
+ _cupsLangPrintFilter(stderr, "ERROR", _("Bad device-uri \"%s\"."), uri);
+
+ DEBUG_printf(("6_httpResolveURI: httpSeparateURI returned %d!", status));
+ DEBUG_puts("5_httpResolveURI: Returning NULL");
+ return (NULL);
+ }
+
+ /*
+ * Resolve it as needed...
+ */
+
+ if (strstr(hostname, "._tcp"))
+ {
+#ifdef HAVE_DNSSD
+# ifdef WIN32
+# pragma comment(lib, "dnssd.lib")
+# endif /* WIN32 */
+ DNSServiceRef ref, /* DNS-SD master service reference */
+ domainref, /* DNS-SD service reference for domain */
+ localref; /* DNS-SD service reference for .local */
+ int domainsent = 0, /* Send the domain resolve? */
+ offline = 0; /* offline-report state set? */
+ char *regtype, /* Pointer to type in hostname */
+ *domain; /* Pointer to domain in hostname */
+ _http_uribuf_t uribuf; /* URI buffer */
+#ifdef HAVE_POLL
+ struct pollfd polldata; /* Polling data */
+#else /* select() */
+ fd_set input_set; /* Input set for select() */
+ struct timeval stimeout; /* Timeout value for select() */
+#endif /* HAVE_POLL */
+
+ if (options & _HTTP_RESOLVE_STDERR)
+ fprintf(stderr, "DEBUG: Resolving \"%s\"...\n", hostname);
+
+ /*
+ * Separate the hostname into service name, registration type, and domain...
+ */
+
+ for (regtype = strstr(hostname, "._tcp") - 2;
+ regtype > hostname;
+ regtype --)
+ if (regtype[0] == '.' && regtype[1] == '_')
+ {
+ /*
+ * Found ._servicetype in front of ._tcp...
+ */
+
+ *regtype++ = '\0';
+ break;
+ }
+
+ if (regtype <= hostname)
+ {
+ DEBUG_puts("5_httpResolveURI: Bad hostname, returning NULL");
+ return (NULL);
+ }
+
+ for (domain = strchr(regtype, '.');
+ domain;
+ domain = strchr(domain + 1, '.'))
+ if (domain[1] != '_')
+ break;
+
+ if (domain)
+ *domain++ = '\0';
+
+ uribuf.buffer = resolved_uri;
+ uribuf.bufsize = resolved_size;
+ uribuf.options = options;
+ resolved_uri[0] = '\0';
+
+ DEBUG_printf(("6_httpResolveURI: Resolving hostname=\"%s\", regtype=\"%s\", "
+ "domain=\"%s\"\n", hostname, regtype, domain));
+ if (options & _HTTP_RESOLVE_STDERR)
+ {
+ fputs("STATE: +connecting-to-device\n", stderr);
+ fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"%s\", "
+ "domain=\"local.\"...\n", hostname, regtype);
+ }
+
+ uri = NULL;
+
+ if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError)
+ {
+ localref = ref;
+ if (DNSServiceResolve(&localref, kDNSServiceFlagsShareConnection, 0,
+ hostname, regtype, "local.", http_resolve_cb,
+ &uribuf) == kDNSServiceErr_NoError)
+ {
+ int fds; /* Number of ready descriptors */
+ time_t timeout, /* Poll timeout */
+ start_time = time(NULL);/* Start time */
+
+ for (;;)
+ {
+ if (options & _HTTP_RESOLVE_STDERR)
+ _cupsLangPrintFilter(stderr, "INFO", _("Looking for printer."));
+
+ if (cb && !(*cb)(context))
+ {
+ DEBUG_puts("5_httpResolveURI: callback returned 0 (stop)");
+ break;
+ }
+
+ /*
+ * For the first minute (or forever if we have a callback), wakeup
+ * every 2 seconds to emit a "looking for printer" message...
+ */
+
+ timeout = (time(NULL) < (start_time + 60) || cb) ? 2000 : -1;
+
+#ifdef HAVE_POLL
+ polldata.fd = DNSServiceRefSockFD(ref);
+ polldata.events = POLLIN;
+
+ fds = poll(&polldata, 1, timeout);
+
+#else /* select() */
+ FD_ZERO(&input_set);
+ FD_SET(DNSServiceRefSockFD(ref), &input_set);
+
+ stimeout.tv_sec = ((int)timeout) / 1000;
+ stimeout.tv_usec = ((int)(timeout) * 1000) % 1000000;
+
+ fds = select(DNSServiceRefSockFD(ref)+1, &input_set, NULL, NULL,
+ timeout < 0.0 ? NULL : &stimeout);
+#endif /* HAVE_POLL */
+
+ if (fds < 0)
+ {
+ if (errno != EINTR && errno != EAGAIN)
+ {
+ DEBUG_printf(("5_httpResolveURI: poll error: %s", strerror(errno)));
+ break;
+ }
+ }
+ else if (fds == 0)
+ {
+ /*
+ * Wait 2 seconds for a response to the local resolve; if nothing
+ * comes in, do an additional domain resolution...
+ */
+
+ if (domainsent == 0 && (domain && _cups_strcasecmp(domain, "local.")))
+ {
+ if (options & _HTTP_RESOLVE_STDERR)
+ fprintf(stderr,
+ "DEBUG: Resolving \"%s\", regtype=\"%s\", "
+ "domain=\"%s\"...\n", hostname, regtype,
+ domain ? domain : "");
+
+ domainref = ref;
+ if (DNSServiceResolve(&domainref, kDNSServiceFlagsShareConnection,
+ 0, hostname, regtype, domain,
+ http_resolve_cb, &uribuf)
+ == kDNSServiceErr_NoError)
+ domainsent = 1;
+ }
+
+ /*
+ * If it hasn't resolved within 5 seconds set the offline-report
+ * printer-state-reason...
+ */
+
+ if ((options & _HTTP_RESOLVE_STDERR) && offline == 0 &&
+ time(NULL) > (start_time + 5))
+ {
+ fputs("STATE: +offline-report\n", stderr);
+ offline = 1;
+ }
+ }
+ else
+ {
+ if (DNSServiceProcessResult(ref) == kDNSServiceErr_NoError)
+ {
+ uri = resolved_uri;
+ break;
+ }
+ }
+ }
+
+ if (domainsent)
+ DNSServiceRefDeallocate(domainref);
+
+ DNSServiceRefDeallocate(localref);
+ }
+
+ DNSServiceRefDeallocate(ref);
+ }
+
+ if (options & _HTTP_RESOLVE_STDERR)
+ {
+ if (uri)
+ fprintf(stderr, "DEBUG: Resolved as \"%s\"...\n", uri);
+ else
+ fputs("DEBUG: Unable to resolve URI\n", stderr);
+
+ fputs("STATE: -connecting-to-device,offline-report\n", stderr);
+ }
+
+#else
+ /*
+ * No DNS-SD support...
+ */
+
+ uri = NULL;
+#endif /* HAVE_DNSSD */
+
+ if ((options & _HTTP_RESOLVE_STDERR) && !uri)
+ _cupsLangPrintFilter(stderr, "ERROR", _("Unable to find printer."));
+ }
+ else
+ {
+ /*
+ * Nothing more to do...
+ */
+
+ strlcpy(resolved_uri, uri, resolved_size);
+ uri = resolved_uri;
+ }
+
+ DEBUG_printf(("5_httpResolveURI: Returning \"%s\"", uri));
+
+ return (uri);
+}
+
+
+/*
+ * 'http_copy_decode()' - Copy and decode a URI.
+ */
+
+static const char * /* O - New source pointer or NULL on error */
+http_copy_decode(char *dst, /* O - Destination buffer */
+ const char *src, /* I - Source pointer */
+ int dstsize, /* I - Destination size */
+ const char *term, /* I - Terminating characters */
+ int decode) /* I - Decode %-encoded values */
+{
+ char *ptr, /* Pointer into buffer */
+ *end; /* End of buffer */
+ int quoted; /* Quoted character */
+
+
+ /*
+ * Copy the src to the destination until we hit a terminating character
+ * or the end of the string.
+ */
+
+ for (ptr = dst, end = dst + dstsize - 1;
+ *src && (!term || !strchr(term, *src));
+ src ++)
+ if (ptr < end)
+ {
+ if (*src == '%' && decode)
+ {
+ if (isxdigit(src[1] & 255) && isxdigit(src[2] & 255))
+ {
+ /*
+ * Grab a hex-encoded character...
+ */
+
+ src ++;
+ if (isalpha(*src))
+ quoted = (tolower(*src) - 'a' + 10) << 4;
+ else
+ quoted = (*src - '0') << 4;
+
+ src ++;
+ if (isalpha(*src))
+ quoted |= tolower(*src) - 'a' + 10;
+ else
+ quoted |= *src - '0';
+
+ *ptr++ = quoted;
+ }
+ else
+ {
+ /*
+ * Bad hex-encoded character...
+ */
+
+ *ptr = '\0';
+ return (NULL);
+ }
+ }
+ else
+ *ptr++ = *src;
+ }
+
+ *ptr = '\0';
+
+ return (src);
+}
+
+
+/*
+ * 'http_copy_encode()' - Copy and encode a URI.
+ */
+
+static char * /* O - End of current URI */
+http_copy_encode(char *dst, /* O - Destination buffer */
+ const char *src, /* I - Source pointer */
+ char *dstend, /* I - End of destination buffer */
+ const char *reserved, /* I - Extra reserved characters */
+ const char *term, /* I - Terminating characters */
+ int encode) /* I - %-encode reserved chars? */
+{
+ static const char hex[] = "0123456789ABCDEF";
+
+
+ while (*src && dst < dstend)
+ {
+ if (term && *src == *term)
+ return (dst);
+
+ if (encode && (*src == '%' || *src <= ' ' || *src & 128 ||
+ (reserved && strchr(reserved, *src))))
+ {
+ /*
+ * Hex encode reserved characters...
+ */
+
+ if ((dst + 2) >= dstend)
+ break;
+
+ *dst++ = '%';
+ *dst++ = hex[(*src >> 4) & 15];
+ *dst++ = hex[*src & 15];
+
+ src ++;
+ }
+ else
+ *dst++ = *src++;
+ }
+
+ *dst = '\0';
+
+ if (*src)
+ return (NULL);
+ else
+ return (dst);
+}
+
+
+#ifdef HAVE_DNSSD
+/*
+ * 'http_resolve_cb()' - Build a device URI for the given service name.
+ */
+
+static void DNSSD_API
+http_resolve_cb(
+ DNSServiceRef sdRef, /* I - Service reference */
+ DNSServiceFlags flags, /* I - Results flags */
+ uint32_t interfaceIndex, /* I - Interface number */
+ DNSServiceErrorType errorCode, /* I - Error, if any */
+ const char *fullName, /* I - Full service name */
+ const char *hostTarget, /* I - Hostname */
+ uint16_t port, /* I - Port number */
+ uint16_t txtLen, /* I - Length of TXT record */
+ const unsigned char *txtRecord, /* I - TXT record data */
+ void *context) /* I - Pointer to URI buffer */
+{
+ const char *scheme, /* URI scheme */
+ *hostptr; /* Pointer into hostTarget */
+ char rp[257], /* Remote printer */
+ fqdn[256]; /* FQDN of the .local name */
+ const void *value; /* Value from TXT record */
+ uint8_t valueLen; /* Length of value */
+ _http_uribuf_t *uribuf; /* URI buffer */
+
+
+ DEBUG_printf(("7http_resolve_cb(sdRef=%p, flags=%x, interfaceIndex=%u, "
+ "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, "
+ "txtLen=%u, txtRecord=%p, context=%p)", sdRef, flags,
+ interfaceIndex, errorCode, fullName, hostTarget, port, txtLen,
+ txtRecord, context));
+
+ uribuf = (_http_uribuf_t *)context;
+
+ /*
+ * Figure out the scheme from the full name...
+ */
+
+ if (strstr(fullName, "._ipps") || strstr(fullName, "._ipp-tls"))
+ scheme = "ipps";
+ else if (strstr(fullName, "._ipp") || strstr(fullName, "._fax-ipp"))
+ scheme = "ipp";
+ else if (strstr(fullName, "._http."))
+ scheme = "http";
+ else if (strstr(fullName, "._https."))
+ scheme = "https";
+ else if (strstr(fullName, "._printer."))
+ scheme = "lpd";
+ else if (strstr(fullName, "._pdl-datastream."))
+ scheme = "socket";
+ else
+ scheme = "riousbprint";
+
+ /*
+ * Extract the "remote printer" key from the TXT record...
+ */
+
+ if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, "rp",
+ &valueLen)) != NULL)
+ {
+ /*
+ * Convert to resource by concatenating with a leading "/"...
+ */
+
+ rp[0] = '/';
+ memcpy(rp + 1, value, valueLen);
+ rp[valueLen + 1] = '\0';
+ }
+ else
+ rp[0] = '\0';
+
+ /*
+ * Lookup the FQDN if needed...
+ */
+
+ if ((uribuf->options & _HTTP_RESOLVE_FQDN) &&
+ (hostptr = hostTarget + strlen(hostTarget) - 7) > hostTarget &&
+ !_cups_strcasecmp(hostptr, ".local."))
+ {
+ /*
+ * OK, we got a .local name but the caller needs a real domain. Start by
+ * getting the IP address of the .local name and then do reverse-lookups...
+ */
+
+ http_addrlist_t *addrlist, /* List of addresses */
+ *addr; /* Current address */
+
+ DEBUG_printf(("8http_resolve_cb: Looking up \"%s\".", hostTarget));
+
+ snprintf(fqdn, sizeof(fqdn), "%d", ntohs(port));
+ if ((addrlist = httpAddrGetList(hostTarget, AF_UNSPEC, fqdn)) != NULL)
+ {
+ for (addr = addrlist; addr; addr = addr->next)
+ {
+ int error = getnameinfo(&(addr->addr.addr),
+ httpAddrLength(&(addr->addr)),
+ fqdn, sizeof(fqdn), NULL, 0, NI_NAMEREQD);
+
+ if (!error)
+ {
+ DEBUG_printf(("8http_resolve_cb: Found \"%s\".", fqdn));
+
+ if ((hostptr = fqdn + strlen(fqdn) - 6) <= fqdn ||
+ _cups_strcasecmp(hostptr, ".local"))
+ {
+ hostTarget = fqdn;
+ break;
+ }
+ }
+#ifdef DEBUG
+ else
+ DEBUG_printf(("8http_resolve_cb: \"%s\" did not resolve: %d",
+ httpAddrString(&(addr->addr), fqdn, sizeof(fqdn)),
+ error));
+#endif /* DEBUG */
+ }
+ }
+ }
+
+ /*
+ * Assemble the final device URI...
+ */
+
+ httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, uribuf->bufsize, scheme,
+ NULL, hostTarget, ntohs(port), rp);
+
+ DEBUG_printf(("8http_resolve_cb: Resolved URI is \"%s\"...", uribuf->buffer));
+}
+#endif /* HAVE_DNSSD */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/http.c b/cups/http.c
new file mode 100644
index 000000000..348474d44
--- /dev/null
+++ b/cups/http.c
@@ -0,0 +1,4512 @@
+/*
+ * "$Id$"
+ *
+ * HTTP routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * This file contains Kerberos support code, copyright 2006 by
+ * Jelmer Vernooij.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * httpAddCredential() - Allocates and adds a single credential to an
+ * array.
+ * _httpBIOMethods() - Get the OpenSSL BIO methods for HTTP
+ * connections.
+ * httpBlocking() - Set blocking/non-blocking behavior on a
+ * connection.
+ * httpCheck() - Check to see if there is a pending response
+ * from the server.
+ * httpClearCookie() - Clear the cookie value(s).
+ * httpClearFields() - Clear HTTP request fields.
+ * httpClose() - Close an HTTP connection.
+ * httpConnect() - Connect to a HTTP server.
+ * httpConnectEncrypt() - Connect to a HTTP server using encryption.
+ * httpCopyCredentials() - Copy the credentials associated with an
+ * encrypted connection.
+ * _httpConvertCredentials() - Convert credentials to the internal format.
+ * _httpCreate() - Create an unconnected HTTP connection.
+ * httpDelete() - Send a DELETE request to the server.
+ * _httpDisconnect() - Disconnect a HTTP connection.
+ * httpEncryption() - Set the required encryption on the link.
+ * httpError() - Get the last error on a connection.
+ * httpFlush() - Flush data from a HTTP connection.
+ * httpFlushWrite() - Flush data in write buffer.
+ * _httpFreeCredentials() - Free internal credentials.
+ * httpFreeCredentials() - Free an array of credentials.
+ * httpGet() - Send a GET request to the server.
+ * httpGetAuthString() - Get the current authorization string.
+ * httpGetBlocking() - Get the blocking/non-block state of a
+ * connection.
+ * httpGetCookie() - Get any cookie data from the response.
+ * httpGetFd() - Get the file descriptor associated with a
+ * connection.
+ * httpGetField() - Get a field value from a request/response.
+ * httpGetLength() - Get the amount of data remaining from the
+ * content-length or transfer-encoding fields.
+ * httpGetLength2() - Get the amount of data remaining from the
+ * content-length or transfer-encoding fields.
+ * httpGetStatus() - Get the status of the last HTTP request.
+ * httpGetSubField() - Get a sub-field value.
+ * httpGetSubField2() - Get a sub-field value.
+ * httpGets() - Get a line of text from a HTTP connection.
+ * httpHead() - Send a HEAD request to the server.
+ * httpInitialize() - Initialize the HTTP interface library and set
+ * the default HTTP proxy (if any).
+ * httpOptions() - Send an OPTIONS request to the server.
+ * _httpPeek() - Peek at data from a HTTP connection.
+ * httpPost() - Send a POST request to the server.
+ * httpPrintf() - Print a formatted string to a HTTP connection.
+ * httpPut() - Send a PUT request to the server.
+ * httpRead() - Read data from a HTTP connection.
+ * httpRead2() - Read data from a HTTP connection.
+ * _httpReadCDSA() - Read function for the CDSA library.
+ * _httpReadGNUTLS() - Read function for the GNU TLS library.
+ * httpReconnect() - Reconnect to a HTTP server.
+ * httpSetAuthString() - Set the current authorization string.
+ * httpSetCredentials() - Set the credentials associated with an
+ * encrypted connection.
+ * httpSetCookie() - Set the cookie value(s).
+ * httpSetExpect() - Set the Expect: header in a request.
+ * httpSetField() - Set the value of an HTTP header.
+ * httpSetLength() - Set the content-length and content-encoding.
+ * httpSetTimeout() - Set read/write timeouts and an optional
+ * callback.
+ * httpTrace() - Send an TRACE request to the server.
+ * _httpUpdate() - Update the current HTTP status for incoming
+ * data.
+ * httpUpdate() - Update the current HTTP state for incoming
+ * data.
+ * _httpWait() - Wait for data available on a connection (no
+ * flush).
+ * httpWait() - Wait for data available on a connection.
+ * httpWrite() - Write data to a HTTP connection.
+ * httpWrite2() - Write data to a HTTP connection.
+ * _httpWriteCDSA() - Write function for the CDSA library.
+ * _httpWriteGNUTLS() - Write function for the GNU TLS library.
+ * http_bio_ctrl() - Control the HTTP connection.
+ * http_bio_free() - Free OpenSSL data.
+ * http_bio_new() - Initialize an OpenSSL BIO structure.
+ * http_bio_puts() - Send a string for OpenSSL.
+ * http_bio_read() - Read data for OpenSSL.
+ * http_bio_write() - Write data for OpenSSL.
+ * http_debug_hex() - Do a hex dump of a buffer.
+ * http_field() - Return the field index for a field name.
+ * http_read_ssl() - Read from a SSL/TLS connection.
+ * http_locking_cb() - Lock/unlock a thread's mutex.
+ * http_send() - Send a request with all fields and the trailing
+ * blank line.
+ * http_set_credentials() - Set the SSL/TLS credentials.
+ * http_setup_ssl() - Set up SSL/TLS support on a connection.
+ * http_shutdown_ssl() - Shut down SSL/TLS on a connection.
+ * http_threadid_cb() - Return the current thread ID.
+ * http_upgrade() - Force upgrade to TLS encryption.
+ * http_write() - Write a buffer to a HTTP connection.
+ * http_write_chunk() - Write a chunked buffer.
+ * http_write_ssl() - Write to a SSL/TLS connection.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include <fcntl.h>
+#ifdef WIN32
+# include <tchar.h>
+#else
+# include <signal.h>
+# include <sys/time.h>
+# include <sys/resource.h>
+#endif /* WIN32 */
+#ifdef HAVE_POLL
+# include <sys/poll.h>
+#endif /* HAVE_POLL */
+
+
+/*
+ * Some operating systems have done away with the Fxxxx constants for
+ * the fcntl() call; this works around that "feature"...
+ */
+
+#ifndef FNONBLK
+# define FNONBLK O_NONBLOCK
+#endif /* !FNONBLK */
+
+
+/*
+ * Local functions...
+ */
+
+#ifdef DEBUG
+static void http_debug_hex(const char *prefix, const char *buffer,
+ int bytes);
+#endif /* DEBUG */
+static http_field_t http_field(const char *name);
+static int http_send(http_t *http, http_state_t request,
+ const char *uri);
+static int http_write(http_t *http, const char *buffer,
+ int length);
+static int http_write_chunk(http_t *http, const char *buffer,
+ int length);
+#ifdef HAVE_SSL
+static int http_read_ssl(http_t *http, char *buf, int len);
+# if defined(HAVE_CDSASSL) && defined(HAVE_SECCERTIFICATECOPYDATA)
+static int http_set_credentials(http_t *http);
+# endif /* HAVE_CDSASSL ** HAVE_SECCERTIFICATECOPYDATA */
+static int http_setup_ssl(http_t *http);
+static void http_shutdown_ssl(http_t *http);
+static int http_upgrade(http_t *http);
+static int http_write_ssl(http_t *http, const char *buf, int len);
+#endif /* HAVE_SSL */
+
+
+/*
+ * Local globals...
+ */
+
+static const char * const http_fields[] =
+ {
+ "Accept-Language",
+ "Accept-Ranges",
+ "Authorization",
+ "Connection",
+ "Content-Encoding",
+ "Content-Language",
+ "Content-Length",
+ "Content-Location",
+ "Content-MD5",
+ "Content-Range",
+ "Content-Type",
+ "Content-Version",
+ "Date",
+ "Host",
+ "If-Modified-Since",
+ "If-Unmodified-since",
+ "Keep-Alive",
+ "Last-Modified",
+ "Link",
+ "Location",
+ "Range",
+ "Referer",
+ "Retry-After",
+ "Transfer-Encoding",
+ "Upgrade",
+ "User-Agent",
+ "WWW-Authenticate"
+ };
+#ifdef DEBUG
+static const char * const http_states[] =
+ {
+ "HTTP_WAITING",
+ "HTTP_OPTIONS",
+ "HTTP_GET",
+ "HTTP_GET_SEND",
+ "HTTP_HEAD",
+ "HTTP_POST",
+ "HTTP_POST_RECV",
+ "HTTP_POST_SEND",
+ "HTTP_PUT",
+ "HTTP_PUT_RECV",
+ "HTTP_DELETE",
+ "HTTP_TRACE",
+ "HTTP_CLOSE",
+ "HTTP_STATUS"
+ };
+#endif /* DEBUG */
+
+
+#if defined(HAVE_SSL) && defined(HAVE_LIBSSL)
+/*
+ * BIO methods for OpenSSL...
+ */
+
+static int http_bio_write(BIO *h, const char *buf, int num);
+static int http_bio_read(BIO *h, char *buf, int size);
+static int http_bio_puts(BIO *h, const char *str);
+static long http_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
+static int http_bio_new(BIO *h);
+static int http_bio_free(BIO *data);
+
+static BIO_METHOD http_bio_methods =
+ {
+ BIO_TYPE_SOCKET,
+ "http",
+ http_bio_write,
+ http_bio_read,
+ http_bio_puts,
+ NULL, /* http_bio_gets, */
+ http_bio_ctrl,
+ http_bio_new,
+ http_bio_free,
+ NULL,
+ };
+#endif /* HAVE_SSL && HAVE_LIBSSL */
+
+
+/*
+ * 'httpAddCredential()' - Allocates and adds a single credential to an array.
+ *
+ * Use @code cupsArrayNew(NULL, NULL)@ to create a credentials array.
+ *
+ * @since CUPS 1.5/Mac OS X 10.7@
+ */
+
+int /* O - 0 on success, -1 on error */
+httpAddCredential(
+ cups_array_t *credentials, /* I - Credentials array */
+ const void *data, /* I - PEM-encoded X.509 data */
+ size_t datalen) /* I - Length of data */
+{
+ http_credential_t *credential; /* Credential data */
+
+
+ if ((credential = malloc(sizeof(http_credential_t))) != NULL)
+ {
+ credential->datalen = datalen;
+
+ if ((credential->data = malloc(datalen)) != NULL)
+ {
+ memcpy(credential->data, data, datalen);
+ cupsArrayAdd(credentials, credential);
+ return (0);
+ }
+
+ free(credential);
+ }
+
+ return (-1);
+}
+
+
+#if defined(HAVE_SSL) && defined(HAVE_LIBSSL)
+/*
+ * '_httpBIOMethods()' - Get the OpenSSL BIO methods for HTTP connections.
+ */
+
+BIO_METHOD * /* O - BIO methods for OpenSSL */
+_httpBIOMethods(void)
+{
+ return (&http_bio_methods);
+}
+#endif /* HAVE_SSL && HAVE_LIBSSL */
+
+
+/*
+ * 'httpBlocking()' - Set blocking/non-blocking behavior on a connection.
+ */
+
+void
+httpBlocking(http_t *http, /* I - Connection to server */
+ int b) /* I - 1 = blocking, 0 = non-blocking */
+{
+ if (http)
+ http->blocking = b;
+}
+
+
+/*
+ * 'httpCheck()' - Check to see if there is a pending response from the server.
+ */
+
+int /* O - 0 = no data, 1 = data available */
+httpCheck(http_t *http) /* I - Connection to server */
+{
+ return (httpWait(http, 0));
+}
+
+
+/*
+ * 'httpClearCookie()' - Clear the cookie value(s).
+ *
+ * @since CUPS 1.1.19/Mac OS X 10.3@
+ */
+
+void
+httpClearCookie(http_t *http) /* I - Connection to server */
+{
+ if (!http)
+ return;
+
+ if (http->cookie)
+ {
+ free(http->cookie);
+ http->cookie = NULL;
+ }
+}
+
+
+/*
+ * 'httpClearFields()' - Clear HTTP request fields.
+ */
+
+void
+httpClearFields(http_t *http) /* I - Connection to server */
+{
+ if (http)
+ {
+ memset(http->fields, 0, sizeof(http->fields));
+ if (http->hostname[0] == '/')
+ httpSetField(http, HTTP_FIELD_HOST, "localhost");
+ else
+ httpSetField(http, HTTP_FIELD_HOST, http->hostname);
+
+ if (http->field_authorization)
+ {
+ free(http->field_authorization);
+ http->field_authorization = NULL;
+ }
+
+ http->expect = (http_status_t)0;
+ }
+}
+
+
+/*
+ * 'httpClose()' - Close an HTTP connection.
+ */
+
+void
+httpClose(http_t *http) /* I - Connection to server */
+{
+#ifdef HAVE_GSSAPI
+ OM_uint32 minor_status; /* Minor status code */
+#endif /* HAVE_GSSAPI */
+
+
+ DEBUG_printf(("httpClose(http=%p)", http));
+
+ /*
+ * Range check input...
+ */
+
+ if (!http)
+ return;
+
+ /*
+ * Close any open connection...
+ */
+
+ _httpDisconnect(http);
+
+ /*
+ * Free memory used...
+ */
+
+ httpAddrFreeList(http->addrlist);
+
+ if (http->cookie)
+ free(http->cookie);
+
+#ifdef HAVE_GSSAPI
+ if (http->gssctx != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&minor_status, &http->gssctx, GSS_C_NO_BUFFER);
+
+ if (http->gssname != GSS_C_NO_NAME)
+ gss_release_name(&minor_status, &http->gssname);
+#endif /* HAVE_GSSAPI */
+
+#ifdef HAVE_AUTHORIZATION_H
+ if (http->auth_ref)
+ AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults);
+#endif /* HAVE_AUTHORIZATION_H */
+
+ httpClearFields(http);
+
+ if (http->authstring && http->authstring != http->_authstring)
+ free(http->authstring);
+
+ free(http);
+}
+
+
+/*
+ * 'httpConnect()' - Connect to a HTTP server.
+ *
+ * This function is deprecated - use @link httpConnectEncrypt@ instead.
+ *
+ * @deprecated@
+ */
+
+http_t * /* O - New HTTP connection */
+httpConnect(const char *host, /* I - Host to connect to */
+ int port) /* I - Port number */
+{
+ return (httpConnectEncrypt(host, port, HTTP_ENCRYPT_IF_REQUESTED));
+}
+
+
+/*
+ * 'httpConnectEncrypt()' - Connect to a HTTP server using encryption.
+ */
+
+http_t * /* O - New HTTP connection */
+httpConnectEncrypt(
+ const char *host, /* I - Host to connect to */
+ int port, /* I - Port number */
+ http_encryption_t encryption) /* I - Type of encryption to use */
+{
+ http_t *http; /* New HTTP connection */
+
+
+ DEBUG_printf(("httpConnectEncrypt(host=\"%s\", port=%d, encryption=%d)",
+ host, port, encryption));
+
+ /*
+ * Create the HTTP structure...
+ */
+
+ if ((http = _httpCreate(host, port, NULL, encryption, AF_UNSPEC)) == NULL)
+ return (NULL);
+
+ /*
+ * Connect to the remote system...
+ */
+
+ if (!httpReconnect(http))
+ return (http);
+
+ /*
+ * Could not connect to any known address - bail out!
+ */
+
+ httpAddrFreeList(http->addrlist);
+
+ free(http);
+
+ return (NULL);
+}
+
+
+/*
+ * 'httpCopyCredentials()' - Copy the credentials associated with an encrypted
+ * connection.
+ *
+ * @since CUPS 1.5/Mac OS X 10.7@
+ */
+
+int /* O - Status of call (0 = success) */
+httpCopyCredentials(
+ http_t *http, /* I - Connection to server */
+ cups_array_t **credentials) /* O - Array of credentials */
+{
+# ifdef HAVE_LIBSSL
+# elif defined(HAVE_GNUTLS)
+# elif defined(HAVE_CDSASSL) && defined(HAVE_SECCERTIFICATECOPYDATA)
+ OSStatus error; /* Error code */
+ CFIndex count; /* Number of credentials */
+ CFArrayRef peerCerts; /* Peer certificates */
+ SecCertificateRef secCert; /* Certificate reference */
+ CFDataRef data; /* Certificate data */
+ int i; /* Looping var */
+# elif defined(HAVE_SSPISSL)
+# endif /* HAVE_LIBSSL */
+
+
+ if (credentials)
+ *credentials = NULL;
+
+ if (!http || !http->tls || !credentials)
+ return (-1);
+
+# ifdef HAVE_LIBSSL
+ return (-1);
+
+# elif defined(HAVE_GNUTLS)
+ return (-1);
+
+# elif defined(HAVE_CDSASSL) && defined(HAVE_SECCERTIFICATECOPYDATA)
+ if (!(error = SSLCopyPeerCertificates(http->tls, &peerCerts)) && peerCerts)
+ {
+ if ((*credentials = cupsArrayNew(NULL, NULL)) != NULL)
+ {
+ for (i = 0, count = CFArrayGetCount(peerCerts); i < count; i++)
+ {
+ secCert = (SecCertificateRef)CFArrayGetValueAtIndex(peerCerts, i);
+ if ((data = SecCertificateCopyData(secCert)))
+ {
+ httpAddCredential(*credentials, CFDataGetBytePtr(data),
+ CFDataGetLength(data));
+ CFRelease(data);
+ }
+ }
+ }
+
+ CFRelease(peerCerts);
+ }
+
+ return (error);
+
+# elif defined(HAVE_SSPISSL)
+ return (-1);
+
+# else
+ return (-1);
+# endif /* HAVE_LIBSSL */
+}
+
+
+/*
+ * '_httpConvertCredentials()' - Convert credentials to the internal format.
+ */
+
+http_tls_credentials_t /* O - Internal credentials */
+_httpConvertCredentials(
+ cups_array_t *credentials) /* I - Array of credentials */
+{
+ if (!credentials)
+ return (NULL);
+
+# ifdef HAVE_LIBSSL
+ return (NULL);
+
+# elif defined(HAVE_GNUTLS)
+ return (NULL);
+
+# elif defined(HAVE_CDSASSL) && defined(HAVE_SECCERTIFICATECOPYDATA)
+ CFMutableArrayRef peerCerts; /* Peer credentials reference */
+ SecCertificateRef secCert; /* Certificate reference */
+ CFDataRef data; /* Credential data reference */
+ http_credential_t *credential; /* Credential data */
+
+
+ if ((peerCerts = CFArrayCreateMutable(kCFAllocatorDefault,
+ cupsArrayCount(credentials),
+ &kCFTypeArrayCallBacks)) == NULL)
+ return (NULL);
+
+ for (credential = (http_credential_t *)cupsArrayFirst(credentials);
+ credential;
+ credential = (http_credential_t *)cupsArrayNext(credentials))
+ {
+ if ((data = CFDataCreate(kCFAllocatorDefault, credential->data,
+ credential->datalen)))
+ {
+ if ((secCert = SecCertificateCreateWithData(kCFAllocatorDefault, data))
+ != NULL)
+ {
+ CFArrayAppendValue(peerCerts, secCert);
+ CFRelease(secCert);
+ }
+
+ CFRelease(data);
+ }
+ }
+
+ return (peerCerts);
+
+# elif defined(HAVE_SSPISSL)
+ return (NULL);
+
+# else
+ return (NULL);
+# endif /* HAVE_LIBSSL */
+}
+
+
+/*
+ * '_httpCreate()' - Create an unconnected HTTP connection.
+ */
+
+http_t * /* O - HTTP connection */
+_httpCreate(
+ const char *host, /* I - Hostname */
+ int port, /* I - Port number */
+ http_addrlist_t *addrlist, /* I - Address list or NULL */
+ http_encryption_t encryption, /* I - Encryption to use */
+ int family) /* I - Address family or AF_UNSPEC */
+{
+ http_t *http; /* New HTTP connection */
+ char service[255]; /* Service name */
+
+
+ DEBUG_printf(("4_httpCreate(host=\"%s\", port=%d, encryption=%d)",
+ host, port, encryption));
+
+ if (!host)
+ return (NULL);
+
+ httpInitialize();
+
+ /*
+ * Lookup the host...
+ */
+
+ sprintf(service, "%d", port);
+
+ if (!addrlist)
+ if ((addrlist = httpAddrGetList(host, family, service)) == NULL)
+ return (NULL);
+
+ /*
+ * Allocate memory for the structure...
+ */
+
+ if ((http = calloc(sizeof(http_t), 1)) == NULL)
+ {
+ httpAddrFreeList(addrlist);
+ return (NULL);
+ }
+
+ /*
+ * Initialize the HTTP data...
+ */
+
+ http->activity = time(NULL);
+ http->addrlist = addrlist;
+ http->blocking = 1;
+ http->fd = -1;
+#ifdef HAVE_GSSAPI
+ http->gssctx = GSS_C_NO_CONTEXT;
+ http->gssname = GSS_C_NO_NAME;
+#endif /* HAVE_GSSAPI */
+ http->version = HTTP_1_1;
+
+ strlcpy(http->hostname, host, sizeof(http->hostname));
+
+ if (port == 443) /* Always use encryption for https */
+ http->encryption = HTTP_ENCRYPT_ALWAYS;
+ else
+ http->encryption = encryption;
+
+ /*
+ * Return the new structure...
+ */
+
+ return (http);
+}
+
+
+/*
+ * 'httpDelete()' - Send a DELETE request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpDelete(http_t *http, /* I - Connection to server */
+ const char *uri) /* I - URI to delete */
+{
+ return (http_send(http, HTTP_DELETE, uri));
+}
+
+
+/*
+ * '_httpDisconnect()' - Disconnect a HTTP connection.
+ */
+
+void
+_httpDisconnect(http_t *http) /* I - Connection to server */
+{
+#ifdef HAVE_SSL
+ if (http->tls)
+ http_shutdown_ssl(http);
+#endif /* HAVE_SSL */
+
+#ifdef WIN32
+ closesocket(http->fd);
+#else
+ close(http->fd);
+#endif /* WIN32 */
+
+ http->fd = -1;
+}
+
+
+/*
+ * 'httpEncryption()' - Set the required encryption on the link.
+ */
+
+int /* O - -1 on error, 0 on success */
+httpEncryption(http_t *http, /* I - Connection to server */
+ http_encryption_t e) /* I - New encryption preference */
+{
+ DEBUG_printf(("httpEncryption(http=%p, e=%d)", http, e));
+
+#ifdef HAVE_SSL
+ if (!http)
+ return (0);
+
+ http->encryption = e;
+
+ if ((http->encryption == HTTP_ENCRYPT_ALWAYS && !http->tls) ||
+ (http->encryption == HTTP_ENCRYPT_NEVER && http->tls))
+ return (httpReconnect(http));
+ else if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
+ return (http_upgrade(http));
+ else
+ return (0);
+#else
+ if (e == HTTP_ENCRYPT_ALWAYS || e == HTTP_ENCRYPT_REQUIRED)
+ return (-1);
+ else
+ return (0);
+#endif /* HAVE_SSL */
+}
+
+
+/*
+ * 'httpError()' - Get the last error on a connection.
+ */
+
+int /* O - Error code (errno) value */
+httpError(http_t *http) /* I - Connection to server */
+{
+ if (http)
+ return (http->error);
+ else
+ return (EINVAL);
+}
+
+
+/*
+ * 'httpFlush()' - Flush data from a HTTP connection.
+ */
+
+void
+httpFlush(http_t *http) /* I - Connection to server */
+{
+ char buffer[8192]; /* Junk buffer */
+ int blocking; /* To block or not to block */
+ http_state_t oldstate; /* Old state */
+
+
+ DEBUG_printf(("httpFlush(http=%p), state=%s", http,
+ http_states[http->state]));
+
+ /*
+ * Temporarily set non-blocking mode so we don't get stuck in httpRead()...
+ */
+
+ blocking = http->blocking;
+ http->blocking = 0;
+
+ /*
+ * Read any data we can...
+ */
+
+ oldstate = http->state;
+ while (httpRead2(http, buffer, sizeof(buffer)) > 0);
+
+ /*
+ * Restore blocking and reset the connection if we didn't get all of
+ * the remaining data...
+ */
+
+ http->blocking = blocking;
+
+ if (http->state == oldstate && http->state != HTTP_WAITING && http->fd >= 0)
+ {
+ /*
+ * Didn't get the data back, so close the current connection.
+ */
+
+ http->state = HTTP_WAITING;
+
+#ifdef HAVE_SSL
+ if (http->tls)
+ http_shutdown_ssl(http);
+#endif /* HAVE_SSL */
+
+#ifdef WIN32
+ closesocket(http->fd);
+#else
+ close(http->fd);
+#endif /* WIN32 */
+
+ http->fd = -1;
+ }
+}
+
+
+/*
+ * 'httpFlushWrite()' - Flush data in write buffer.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - Bytes written or -1 on error */
+httpFlushWrite(http_t *http) /* I - Connection to server */
+{
+ int bytes; /* Bytes written */
+
+
+ DEBUG_printf(("httpFlushWrite(http=%p)", http));
+
+ if (!http || !http->wused)
+ {
+ DEBUG_puts(http ? "1httpFlushWrite: Write buffer is empty." :
+ "1httpFlushWrite: No connection.");
+ return (0);
+ }
+
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED)
+ bytes = http_write_chunk(http, http->wbuffer, http->wused);
+ else
+ bytes = http_write(http, http->wbuffer, http->wused);
+
+ http->wused = 0;
+
+ DEBUG_printf(("1httpFlushWrite: Returning %d, errno=%d.", bytes, errno));
+
+ return (bytes);
+}
+
+
+/*
+ * '_httpFreeCredentials()' - Free internal credentials.
+ */
+
+void
+_httpFreeCredentials(
+ http_tls_credentials_t credentials) /* I - Internal credentials */
+{
+ if (!credentials)
+ return;
+
+#ifdef HAVE_LIBSSL
+ (void)credentials;
+
+#elif defined(HAVE_GNUTLS)
+ (void)credentials;
+
+#elif defined(HAVE_CDSASSL)
+ CFRelease(credentials);
+
+#elif defined(HAVE_SSPISSL)
+ (void)credentials;
+
+#endif /* HAVE_LIBSSL */
+}
+
+
+/*
+ * 'httpFreeCredentials()' - Free an array of credentials.
+ */
+
+void
+httpFreeCredentials(
+ cups_array_t *credentials) /* I - Array of credentials */
+{
+ http_credential_t *credential; /* Credential */
+
+
+ for (credential = (http_credential_t *)cupsArrayFirst(credentials);
+ credential;
+ credential = (http_credential_t *)cupsArrayNext(credentials))
+ {
+ cupsArrayRemove(credentials, credential);
+ free((void *)credential->data);
+ free(credential);
+ }
+
+ cupsArrayDelete(credentials);
+}
+
+
+/*
+ * 'httpGet()' - Send a GET request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpGet(http_t *http, /* I - Connection to server */
+ const char *uri) /* I - URI to get */
+{
+ return (http_send(http, HTTP_GET, uri));
+}
+
+
+/*
+ * 'httpGetAuthString()' - Get the current authorization string.
+ *
+ * The authorization string is set by cupsDoAuthentication() and
+ * httpSetAuthString(). Use httpGetAuthString() to retrieve the
+ * string to use with httpSetField() for the HTTP_FIELD_AUTHORIZATION
+ * value.
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+char * /* O - Authorization string */
+httpGetAuthString(http_t *http) /* I - Connection to server */
+{
+ if (http)
+ return (http->authstring);
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'httpGetBlocking()' - Get the blocking/non-block state of a connection.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 1 if blocking, 0 if non-blocking */
+httpGetBlocking(http_t *http) /* I - Connection to server */
+{
+ return (http ? http->blocking : 0);
+}
+
+
+/*
+ * 'httpGetCookie()' - Get any cookie data from the response.
+ *
+ * @since CUPS 1.1.19/Mac OS X 10.3@
+ */
+
+const char * /* O - Cookie data or NULL */
+httpGetCookie(http_t *http) /* I - HTTP connecion */
+{
+ return (http ? http->cookie : NULL);
+}
+
+
+/*
+ * 'httpGetFd()' - Get the file descriptor associated with a connection.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - File descriptor or -1 if none */
+httpGetFd(http_t *http) /* I - Connection to server */
+{
+ return (http ? http->fd : -1);
+}
+
+
+/*
+ * 'httpGetField()' - Get a field value from a request/response.
+ */
+
+const char * /* O - Field value */
+httpGetField(http_t *http, /* I - Connection to server */
+ http_field_t field) /* I - Field to get */
+{
+ if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
+ return (NULL);
+ else if (field == HTTP_FIELD_AUTHORIZATION &&
+ http->field_authorization)
+ {
+ /*
+ * Special case for WWW-Authenticate: as its contents can be
+ * longer than HTTP_MAX_VALUE...
+ */
+
+ return (http->field_authorization);
+ }
+ else
+ return (http->fields[field]);
+}
+
+
+/*
+ * 'httpGetLength()' - Get the amount of data remaining from the
+ * content-length or transfer-encoding fields.
+ *
+ * This function is deprecated and will not return lengths larger than
+ * 2^31 - 1; use httpGetLength2() instead.
+ *
+ * @deprecated@
+ */
+
+int /* O - Content length */
+httpGetLength(http_t *http) /* I - Connection to server */
+{
+ /*
+ * Get the read content length and return the 32-bit value.
+ */
+
+ if (http)
+ {
+ httpGetLength2(http);
+
+ return (http->_data_remaining);
+ }
+ else
+ return (-1);
+}
+
+
+/*
+ * 'httpGetLength2()' - Get the amount of data remaining from the
+ * content-length or transfer-encoding fields.
+ *
+ * This function returns the complete content length, even for
+ * content larger than 2^31 - 1.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+off_t /* O - Content length */
+httpGetLength2(http_t *http) /* I - Connection to server */
+{
+ DEBUG_printf(("2httpGetLength2(http=%p), state=%s", http,
+ http_states[http->state]));
+
+ if (!http)
+ return (-1);
+
+ if (!_cups_strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked"))
+ {
+ DEBUG_puts("4httpGetLength2: chunked request!");
+
+ http->data_encoding = HTTP_ENCODE_CHUNKED;
+ http->data_remaining = 0;
+ }
+ else
+ {
+ http->data_encoding = HTTP_ENCODE_LENGTH;
+
+ /*
+ * The following is a hack for HTTP servers that don't send a
+ * content-length or transfer-encoding field...
+ *
+ * If there is no content-length then the connection must close
+ * after the transfer is complete...
+ */
+
+ if (!http->fields[HTTP_FIELD_CONTENT_LENGTH][0])
+ {
+ /*
+ * Default content length is 0 for errors and 2^31-1 for other
+ * successful requests...
+ */
+
+ if (http->status >= HTTP_MULTIPLE_CHOICES)
+ http->data_remaining = 0;
+ else
+ http->data_remaining = 2147483647;
+ }
+ else
+ http->data_remaining = strtoll(http->fields[HTTP_FIELD_CONTENT_LENGTH],
+ NULL, 10);
+
+ DEBUG_printf(("4httpGetLength2: content_length=" CUPS_LLFMT,
+ CUPS_LLCAST http->data_remaining));
+ }
+
+ if (http->data_remaining <= INT_MAX)
+ http->_data_remaining = (int)http->data_remaining;
+ else
+ http->_data_remaining = INT_MAX;
+
+ return (http->data_remaining);
+}
+
+
+/*
+ * 'httpGetStatus()' - Get the status of the last HTTP request.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+http_status_t /* O - HTTP status */
+httpGetStatus(http_t *http) /* I - Connection to server */
+{
+ return (http ? http->status : HTTP_ERROR);
+}
+
+
+/*
+ * 'httpGetSubField()' - Get a sub-field value.
+ *
+ * @deprecated@
+ */
+
+char * /* O - Value or NULL */
+httpGetSubField(http_t *http, /* I - Connection to server */
+ http_field_t field, /* I - Field index */
+ const char *name, /* I - Name of sub-field */
+ char *value) /* O - Value string */
+{
+ return (httpGetSubField2(http, field, name, value, HTTP_MAX_VALUE));
+}
+
+
+/*
+ * 'httpGetSubField2()' - Get a sub-field value.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+char * /* O - Value or NULL */
+httpGetSubField2(http_t *http, /* I - Connection to server */
+ http_field_t field, /* I - Field index */
+ const char *name, /* I - Name of sub-field */
+ char *value, /* O - Value string */
+ int valuelen) /* I - Size of value buffer */
+{
+ const char *fptr; /* Pointer into field */
+ char temp[HTTP_MAX_VALUE], /* Temporary buffer for name */
+ *ptr, /* Pointer into string buffer */
+ *end; /* End of value buffer */
+
+ DEBUG_printf(("2httpGetSubField2(http=%p, field=%d, name=\"%s\", value=%p, "
+ "valuelen=%d)", http, field, name, value, valuelen));
+
+ if (!http || !name || !value || valuelen < 2 ||
+ field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
+ return (NULL);
+
+ end = value + valuelen - 1;
+
+ for (fptr = http->fields[field]; *fptr;)
+ {
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (_cups_isspace(*fptr))
+ fptr ++;
+
+ if (*fptr == ',')
+ {
+ fptr ++;
+ continue;
+ }
+
+ /*
+ * Get the sub-field name...
+ */
+
+ for (ptr = temp;
+ *fptr && *fptr != '=' && !_cups_isspace(*fptr) &&
+ ptr < (temp + sizeof(temp) - 1);
+ *ptr++ = *fptr++);
+
+ *ptr = '\0';
+
+ DEBUG_printf(("4httpGetSubField2: name=\"%s\"", temp));
+
+ /*
+ * Skip trailing chars up to the '='...
+ */
+
+ while (_cups_isspace(*fptr))
+ fptr ++;
+
+ if (!*fptr)
+ break;
+
+ if (*fptr != '=')
+ continue;
+
+ /*
+ * Skip = and leading whitespace...
+ */
+
+ fptr ++;
+
+ while (_cups_isspace(*fptr))
+ fptr ++;
+
+ if (*fptr == '\"')
+ {
+ /*
+ * Read quoted string...
+ */
+
+ for (ptr = value, fptr ++;
+ *fptr && *fptr != '\"' && ptr < end;
+ *ptr++ = *fptr++);
+
+ *ptr = '\0';
+
+ while (*fptr && *fptr != '\"')
+ fptr ++;
+
+ if (*fptr)
+ fptr ++;
+ }
+ else
+ {
+ /*
+ * Read unquoted string...
+ */
+
+ for (ptr = value;
+ *fptr && !_cups_isspace(*fptr) && *fptr != ',' && ptr < end;
+ *ptr++ = *fptr++);
+
+ *ptr = '\0';
+
+ while (*fptr && !_cups_isspace(*fptr) && *fptr != ',')
+ fptr ++;
+ }
+
+ DEBUG_printf(("4httpGetSubField2: value=\"%s\"", value));
+
+ /*
+ * See if this is the one...
+ */
+
+ if (!strcmp(name, temp))
+ {
+ DEBUG_printf(("3httpGetSubField2: Returning \"%s\"", value));
+ return (value);
+ }
+ }
+
+ value[0] = '\0';
+
+ DEBUG_puts("3httpGetSubField2: Returning NULL");
+
+ return (NULL);
+}
+
+
+/*
+ * 'httpGets()' - Get a line of text from a HTTP connection.
+ */
+
+char * /* O - Line or NULL */
+httpGets(char *line, /* I - Line to read into */
+ int length, /* I - Max length of buffer */
+ http_t *http) /* I - Connection to server */
+{
+ char *lineptr, /* Pointer into line */
+ *lineend, /* End of line */
+ *bufptr, /* Pointer into input buffer */
+ *bufend; /* Pointer to end of buffer */
+ int bytes, /* Number of bytes read */
+ eol; /* End-of-line? */
+
+
+ DEBUG_printf(("2httpGets(line=%p, length=%d, http=%p)", line, length, http));
+
+ if (http == NULL || line == NULL)
+ return (NULL);
+
+ /*
+ * Read a line from the buffer...
+ */
+
+ http->error = 0;
+ lineptr = line;
+ lineend = line + length - 1;
+ eol = 0;
+
+ while (lineptr < lineend)
+ {
+ /*
+ * Pre-load the buffer as needed...
+ */
+
+#ifdef WIN32
+ WSASetLastError(0);
+#else
+ errno = 0;
+#endif /* WIN32 */
+
+ while (http->used == 0)
+ {
+ /*
+ * No newline; see if there is more data to be read...
+ */
+
+ while (!_httpWait(http, http->blocking ? 30000 : 10000, 1))
+ {
+ if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+ continue;
+
+ DEBUG_puts("3httpGets: Timed out!");
+#ifdef WIN32
+ http->error = WSAETIMEDOUT;
+#else
+ http->error = ETIMEDOUT;
+#endif /* WIN32 */
+ return (NULL);
+ }
+
+#ifdef HAVE_SSL
+ if (http->tls)
+ bytes = http_read_ssl(http, http->buffer + http->used,
+ HTTP_MAX_BUFFER - http->used);
+ else
+#endif /* HAVE_SSL */
+ bytes = recv(http->fd, http->buffer + http->used,
+ HTTP_MAX_BUFFER - http->used, 0);
+
+ DEBUG_printf(("4httpGets: read %d bytes...", bytes));
+
+ if (bytes < 0)
+ {
+ /*
+ * Nope, can't get a line this time...
+ */
+
+#ifdef WIN32
+ DEBUG_printf(("3httpGets: recv() error %d!", WSAGetLastError()));
+
+ if (WSAGetLastError() == WSAEINTR)
+ continue;
+ else if (WSAGetLastError() == WSAEWOULDBLOCK)
+ {
+ if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+ continue;
+
+ http->error = WSAGetLastError();
+ }
+ else if (WSAGetLastError() != http->error)
+ {
+ http->error = WSAGetLastError();
+ continue;
+ }
+
+#else
+ DEBUG_printf(("3httpGets: recv() error %d!", errno));
+
+ if (errno == EINTR)
+ continue;
+ else if (errno == EWOULDBLOCK || errno == EAGAIN)
+ {
+ if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+ continue;
+ else if (!http->timeout_cb && errno == EAGAIN)
+ continue;
+
+ http->error = errno;
+ }
+ else if (errno != http->error)
+ {
+ http->error = errno;
+ continue;
+ }
+#endif /* WIN32 */
+
+ return (NULL);
+ }
+ else if (bytes == 0)
+ {
+ http->error = EPIPE;
+
+ return (NULL);
+ }
+
+ /*
+ * Yup, update the amount used...
+ */
+
+ http->used += bytes;
+ }
+
+ /*
+ * Now copy as much of the current line as possible...
+ */
+
+ for (bufptr = http->buffer, bufend = http->buffer + http->used;
+ lineptr < lineend && bufptr < bufend;)
+ {
+ if (*bufptr == 0x0a)
+ {
+ eol = 1;
+ bufptr ++;
+ break;
+ }
+ else if (*bufptr == 0x0d)
+ bufptr ++;
+ else
+ *lineptr++ = *bufptr++;
+ }
+
+ http->used -= (int)(bufptr - http->buffer);
+ if (http->used > 0)
+ memmove(http->buffer, bufptr, http->used);
+
+ if (eol)
+ {
+ /*
+ * End of line...
+ */
+
+ http->activity = time(NULL);
+
+ *lineptr = '\0';
+
+ DEBUG_printf(("3httpGets: Returning \"%s\"", line));
+
+ return (line);
+ }
+ }
+
+ DEBUG_puts("3httpGets: No new line available!");
+
+ return (NULL);
+}
+
+
+/*
+ * 'httpHead()' - Send a HEAD request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpHead(http_t *http, /* I - Connection to server */
+ const char *uri) /* I - URI for head */
+{
+ DEBUG_printf(("httpHead(http=%p, uri=\"%s\")", http, uri));
+ return (http_send(http, HTTP_HEAD, uri));
+}
+
+
+/*
+ * 'httpInitialize()' - Initialize the HTTP interface library and set the
+ * default HTTP proxy (if any).
+ */
+
+void
+httpInitialize(void)
+{
+ static int initialized = 0; /* Have we been called before? */
+#ifdef WIN32
+ WSADATA winsockdata; /* WinSock data */
+#endif /* WIN32 */
+#ifdef HAVE_LIBSSL
+ int i; /* Looping var */
+ unsigned char data[1024]; /* Seed data */
+#endif /* HAVE_LIBSSL */
+
+
+ _cupsGlobalLock();
+ if (initialized)
+ {
+ _cupsGlobalUnlock();
+ return;
+ }
+
+#ifdef WIN32
+ WSAStartup(MAKEWORD(2,2), &winsockdata);
+
+#elif !defined(SO_NOSIGPIPE)
+ /*
+ * Ignore SIGPIPE signals...
+ */
+
+# ifdef HAVE_SIGSET
+ sigset(SIGPIPE, SIG_IGN);
+
+# elif defined(HAVE_SIGACTION)
+ struct sigaction action; /* POSIX sigaction data */
+
+
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+
+# else
+ signal(SIGPIPE, SIG_IGN);
+# endif /* !SO_NOSIGPIPE */
+#endif /* WIN32 */
+
+#ifdef HAVE_GNUTLS
+ /*
+ * Initialize GNU TLS...
+ */
+
+ gnutls_global_init();
+
+#elif defined(HAVE_LIBSSL)
+ /*
+ * Initialize OpenSSL...
+ */
+
+ SSL_load_error_strings();
+ SSL_library_init();
+
+ /*
+ * Using the current time is a dubious random seed, but on some systems
+ * it is the best we can do (on others, this seed isn't even used...)
+ */
+
+ CUPS_SRAND(time(NULL));
+
+ for (i = 0; i < sizeof(data); i ++)
+ data[i] = CUPS_RAND();
+
+ RAND_seed(data, sizeof(data));
+#endif /* HAVE_GNUTLS */
+
+ initialized = 1;
+ _cupsGlobalUnlock();
+}
+
+
+/*
+ * 'httpOptions()' - Send an OPTIONS request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpOptions(http_t *http, /* I - Connection to server */
+ const char *uri) /* I - URI for options */
+{
+ return (http_send(http, HTTP_OPTIONS, uri));
+}
+
+
+/*
+ * '_httpPeek()' - Peek at data from a HTTP connection.
+ *
+ * This function copies available data from the given HTTP connection, reading
+ * a buffer as needed. The data is still available for reading using
+ * @link httpRead@ or @link httpRead2@.
+ *
+ * For non-blocking connections the usual timeouts apply.
+ */
+
+ssize_t /* O - Number of bytes copied */
+_httpPeek(http_t *http, /* I - Connection to server */
+ char *buffer, /* I - Buffer for data */
+ size_t length) /* I - Maximum number of bytes */
+{
+ ssize_t bytes; /* Bytes read */
+ char len[32]; /* Length string */
+
+
+ DEBUG_printf(("_httpPeek(http=%p, buffer=%p, length=" CUPS_LLFMT ")",
+ http, buffer, CUPS_LLCAST length));
+
+ if (http == NULL || buffer == NULL)
+ return (-1);
+
+ http->activity = time(NULL);
+ http->error = 0;
+
+ if (length <= 0)
+ return (0);
+
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED &&
+ http->data_remaining <= 0)
+ {
+ DEBUG_puts("2_httpPeek: Getting chunk length...");
+
+ if (httpGets(len, sizeof(len), http) == NULL)
+ {
+ DEBUG_puts("1_httpPeek: Could not get length!");
+ return (0);
+ }
+
+ http->data_remaining = strtoll(len, NULL, 16);
+ if (http->data_remaining < 0)
+ {
+ DEBUG_puts("1_httpPeek: Negative chunk length!");
+ return (0);
+ }
+ }
+
+ DEBUG_printf(("2_httpPeek: data_remaining=" CUPS_LLFMT,
+ CUPS_LLCAST http->data_remaining));
+
+ if (http->data_remaining <= 0)
+ {
+ /*
+ * A zero-length chunk ends a transfer; unless we are reading POST
+ * data, go idle...
+ */
+
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED)
+ httpGets(len, sizeof(len), http);
+
+ if (http->state == HTTP_POST_RECV)
+ http->state ++;
+ else
+ http->state = HTTP_WAITING;
+
+ /*
+ * Prevent future reads for this request...
+ */
+
+ http->data_encoding = HTTP_ENCODE_LENGTH;
+
+ return (0);
+ }
+ else if (length > (size_t)http->data_remaining)
+ length = (size_t)http->data_remaining;
+
+ if (http->used == 0)
+ {
+ /*
+ * Buffer small reads for better performance...
+ */
+
+ if (!http->blocking)
+ {
+ while (!httpWait(http, 10000))
+ {
+ if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+ continue;
+
+ return (0);
+ }
+ }
+
+ if (http->data_remaining > sizeof(http->buffer))
+ bytes = sizeof(http->buffer);
+ else
+ bytes = http->data_remaining;
+
+#ifdef HAVE_SSL
+ if (http->tls)
+ bytes = http_read_ssl(http, http->buffer, bytes);
+ else
+#endif /* HAVE_SSL */
+ {
+ DEBUG_printf(("2_httpPeek: reading %d bytes from socket into buffer...",
+ (int)bytes));
+
+ bytes = recv(http->fd, http->buffer, bytes, 0);
+
+ DEBUG_printf(("2_httpPeek: read %d bytes from socket into buffer...",
+ (int)bytes));
+ }
+
+ if (bytes > 0)
+ http->used = bytes;
+ else if (bytes < 0)
+ {
+#ifdef WIN32
+ if (WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK)
+ {
+ http->error = WSAGetLastError();
+ return (-1);
+ }
+#else
+ if (errno != EINTR && errno != EAGAIN)
+ {
+ http->error = errno;
+ return (-1);
+ }
+#endif /* WIN32 */
+ }
+ else
+ {
+ http->error = EPIPE;
+ return (0);
+ }
+ }
+
+ if (http->used > 0)
+ {
+ if (length > (size_t)http->used)
+ length = (size_t)http->used;
+
+ bytes = (ssize_t)length;
+
+ DEBUG_printf(("2_httpPeek: grabbing %d bytes from input buffer...",
+ (int)bytes));
+
+ memcpy(buffer, http->buffer, length);
+ }
+ else
+ bytes = 0;
+
+ if (bytes < 0)
+ {
+#ifdef WIN32
+ if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)
+ bytes = 0;
+ else
+ http->error = WSAGetLastError();
+#else
+ if (errno == EINTR || errno == EAGAIN)
+ bytes = 0;
+ else
+ http->error = errno;
+#endif /* WIN32 */
+ }
+ else if (bytes == 0)
+ {
+ http->error = EPIPE;
+ return (0);
+ }
+
+#ifdef DEBUG
+ http_debug_hex("_httpPeek", buffer, (int)bytes);
+#endif /* DEBUG */
+
+ return (bytes);
+}
+
+
+/*
+ * 'httpPost()' - Send a POST request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpPost(http_t *http, /* I - Connection to server */
+ const char *uri) /* I - URI for post */
+{
+ return (http_send(http, HTTP_POST, uri));
+}
+
+
+/*
+ * 'httpPrintf()' - Print a formatted string to a HTTP connection.
+ *
+ * @private@
+ */
+
+int /* O - Number of bytes written */
+httpPrintf(http_t *http, /* I - Connection to server */
+ const char *format, /* I - printf-style format string */
+ ...) /* I - Additional args as needed */
+{
+ int bytes; /* Number of bytes to write */
+ char buf[16384]; /* Buffer for formatted string */
+ va_list ap; /* Variable argument pointer */
+
+
+ DEBUG_printf(("2httpPrintf(http=%p, format=\"%s\", ...)", http, format));
+
+ va_start(ap, format);
+ bytes = vsnprintf(buf, sizeof(buf), format, ap);
+ va_end(ap);
+
+ DEBUG_printf(("3httpPrintf: %s", buf));
+
+ if (http->data_encoding == HTTP_ENCODE_FIELDS)
+ return (httpWrite2(http, buf, bytes));
+ else
+ {
+ if (http->wused)
+ {
+ DEBUG_puts("4httpPrintf: flushing existing data...");
+
+ if (httpFlushWrite(http) < 0)
+ return (-1);
+ }
+
+ return (http_write(http, buf, bytes));
+ }
+}
+
+
+/*
+ * 'httpPut()' - Send a PUT request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpPut(http_t *http, /* I - Connection to server */
+ const char *uri) /* I - URI to put */
+{
+ DEBUG_printf(("httpPut(http=%p, uri=\"%s\")", http, uri));
+ return (http_send(http, HTTP_PUT, uri));
+}
+
+
+/*
+ * 'httpRead()' - Read data from a HTTP connection.
+ *
+ * This function is deprecated. Use the httpRead2() function which can
+ * read more than 2GB of data.
+ *
+ * @deprecated@
+ */
+
+int /* O - Number of bytes read */
+httpRead(http_t *http, /* I - Connection to server */
+ char *buffer, /* I - Buffer for data */
+ int length) /* I - Maximum number of bytes */
+{
+ return ((int)httpRead2(http, buffer, length));
+}
+
+
+/*
+ * 'httpRead2()' - Read data from a HTTP connection.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ssize_t /* O - Number of bytes read */
+httpRead2(http_t *http, /* I - Connection to server */
+ char *buffer, /* I - Buffer for data */
+ size_t length) /* I - Maximum number of bytes */
+{
+ ssize_t bytes; /* Bytes read */
+ char len[32]; /* Length string */
+
+
+ DEBUG_printf(("httpRead2(http=%p, buffer=%p, length=" CUPS_LLFMT ")",
+ http, buffer, CUPS_LLCAST length));
+
+ if (http == NULL || buffer == NULL)
+ return (-1);
+
+ http->activity = time(NULL);
+ http->error = 0;
+
+ if (length <= 0)
+ return (0);
+
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED &&
+ http->data_remaining <= 0)
+ {
+ DEBUG_puts("2httpRead2: Getting chunk length...");
+
+ if (httpGets(len, sizeof(len), http) == NULL)
+ {
+ DEBUG_puts("1httpRead2: Could not get length!");
+ return (0);
+ }
+
+ http->data_remaining = strtoll(len, NULL, 16);
+ if (http->data_remaining < 0)
+ {
+ DEBUG_puts("1httpRead2: Negative chunk length!");
+ return (0);
+ }
+ }
+
+ DEBUG_printf(("2httpRead2: data_remaining=" CUPS_LLFMT,
+ CUPS_LLCAST http->data_remaining));
+
+ if (http->data_remaining <= 0)
+ {
+ /*
+ * A zero-length chunk ends a transfer; unless we are reading POST
+ * data, go idle...
+ */
+
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED)
+ httpGets(len, sizeof(len), http);
+
+ if (http->state == HTTP_POST_RECV)
+ http->state ++;
+ else
+ http->state = HTTP_WAITING;
+
+ /*
+ * Prevent future reads for this request...
+ */
+
+ http->data_encoding = HTTP_ENCODE_LENGTH;
+
+ return (0);
+ }
+ else if (length > (size_t)http->data_remaining)
+ length = (size_t)http->data_remaining;
+
+ if (http->used == 0 && length <= 256)
+ {
+ /*
+ * Buffer small reads for better performance...
+ */
+
+ if (!http->blocking)
+ {
+ while (!httpWait(http, 10000))
+ {
+ if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+ continue;
+
+ return (0);
+ }
+ }
+
+ if (http->data_remaining > sizeof(http->buffer))
+ bytes = sizeof(http->buffer);
+ else
+ bytes = http->data_remaining;
+
+#ifdef HAVE_SSL
+ if (http->tls)
+ bytes = http_read_ssl(http, http->buffer, bytes);
+ else
+#endif /* HAVE_SSL */
+ {
+ DEBUG_printf(("2httpRead2: reading %d bytes from socket into buffer...",
+ (int)bytes));
+
+ bytes = recv(http->fd, http->buffer, bytes, 0);
+
+ DEBUG_printf(("2httpRead2: read %d bytes from socket into buffer...",
+ (int)bytes));
+ }
+
+ if (bytes > 0)
+ http->used = bytes;
+ else if (bytes < 0)
+ {
+#ifdef WIN32
+ if (WSAGetLastError() != WSAEINTR)
+ {
+ http->error = WSAGetLastError();
+ return (-1);
+ }
+ else if (WSAGetLastError() == WSAEWOULDBLOCK)
+ {
+ if (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data))
+ {
+ http->error = WSAEWOULDBLOCK;
+ return (-1);
+ }
+ }
+#else
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ {
+ if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data))
+ {
+ http->error = errno;
+ return (-1);
+ }
+ else if (!http->timeout_cb && errno != EAGAIN)
+ {
+ http->error = errno;
+ return (-1);
+ }
+ }
+ else if (errno != EINTR)
+ {
+ http->error = errno;
+ return (-1);
+ }
+#endif /* WIN32 */
+ }
+ else
+ {
+ http->error = EPIPE;
+ return (0);
+ }
+ }
+
+ if (http->used > 0)
+ {
+ if (length > (size_t)http->used)
+ length = (size_t)http->used;
+
+ bytes = (ssize_t)length;
+
+ DEBUG_printf(("2httpRead2: grabbing %d bytes from input buffer...",
+ (int)bytes));
+
+ memcpy(buffer, http->buffer, length);
+ http->used -= (int)length;
+
+ if (http->used > 0)
+ memmove(http->buffer, http->buffer + length, http->used);
+ }
+#ifdef HAVE_SSL
+ else if (http->tls)
+ {
+ if (!http->blocking)
+ {
+ while (!httpWait(http, 10000))
+ {
+ if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+ continue;
+
+ return (0);
+ }
+ }
+
+ bytes = (ssize_t)http_read_ssl(http, buffer, (int)length);
+ }
+#endif /* HAVE_SSL */
+ else
+ {
+ if (!http->blocking)
+ {
+ while (!httpWait(http, 10000))
+ {
+ if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+ continue;
+
+ return (0);
+ }
+ }
+
+ DEBUG_printf(("2httpRead2: reading " CUPS_LLFMT " bytes from socket...",
+ CUPS_LLCAST length));
+
+#ifdef WIN32
+ while ((bytes = (ssize_t)recv(http->fd, buffer, (int)length, 0)) < 0)
+ {
+ if (WSAGetLastError() == WSAEWOULDBLOCK)
+ {
+ if (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data))
+ break;
+ }
+ else if (WSAGetLastError() != WSAEINTR)
+ break;
+ }
+#else
+ while ((bytes = recv(http->fd, buffer, length, 0)) < 0)
+ {
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ {
+ if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data))
+ break;
+ else if (!http->timeout_cb && errno != EAGAIN)
+ break;
+ }
+ else if (errno != EINTR)
+ break;
+ }
+#endif /* WIN32 */
+
+ DEBUG_printf(("2httpRead2: read " CUPS_LLFMT " bytes from socket...",
+ CUPS_LLCAST bytes));
+ }
+
+ if (bytes > 0)
+ {
+ http->data_remaining -= bytes;
+
+ if (http->data_remaining <= INT_MAX)
+ http->_data_remaining = (int)http->data_remaining;
+ else
+ http->_data_remaining = INT_MAX;
+ }
+ else if (bytes < 0)
+ {
+#ifdef WIN32
+ if (WSAGetLastError() == WSAEINTR)
+ bytes = 0;
+ else
+ http->error = WSAGetLastError();
+#else
+ if (errno == EINTR || (errno == EAGAIN && !http->timeout_cb))
+ bytes = 0;
+ else
+ http->error = errno;
+#endif /* WIN32 */
+ }
+ else
+ {
+ http->error = EPIPE;
+ return (0);
+ }
+
+ if (http->data_remaining == 0)
+ {
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED)
+ httpGets(len, sizeof(len), http);
+
+ if (http->data_encoding != HTTP_ENCODE_CHUNKED)
+ {
+ if (http->state == HTTP_POST_RECV)
+ http->state ++;
+ else
+ http->state = HTTP_WAITING;
+ }
+ }
+
+#ifdef DEBUG
+ http_debug_hex("httpRead2", buffer, (int)bytes);
+#endif /* DEBUG */
+
+ return (bytes);
+}
+
+
+#if defined(HAVE_SSL) && defined(HAVE_CDSASSL)
+/*
+ * '_httpReadCDSA()' - Read function for the CDSA library.
+ */
+
+OSStatus /* O - -1 on error, 0 on success */
+_httpReadCDSA(
+ SSLConnectionRef connection, /* I - SSL/TLS connection */
+ void *data, /* I - Data buffer */
+ size_t *dataLength) /* IO - Number of bytes */
+{
+ OSStatus result; /* Return value */
+ ssize_t bytes; /* Number of bytes read */
+ http_t *http; /* HTTP connection */
+
+
+ http = (http_t *)connection;
+
+ if (!http->blocking)
+ {
+ /*
+ * Make sure we have data before we read...
+ */
+
+ while (!_httpWait(http, 10000, 0))
+ {
+ if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+ continue;
+
+ http->error = ETIMEDOUT;
+ return (-1);
+ }
+ }
+
+ do
+ {
+ bytes = recv(http->fd, data, *dataLength, 0);
+ }
+ while (bytes == -1 && (errno == EINTR || errno == EAGAIN));
+
+ if (bytes == *dataLength)
+ {
+ result = 0;
+ }
+ else if (bytes > 0)
+ {
+ *dataLength = bytes;
+ result = errSSLWouldBlock;
+ }
+ else
+ {
+ *dataLength = 0;
+
+ if (bytes == 0)
+ result = errSSLClosedGraceful;
+ else if (errno == EAGAIN)
+ result = errSSLWouldBlock;
+ else
+ result = errSSLClosedAbort;
+ }
+
+ return (result);
+}
+#endif /* HAVE_SSL && HAVE_CDSASSL */
+
+
+#if defined(HAVE_SSL) && defined(HAVE_GNUTLS)
+/*
+ * '_httpReadGNUTLS()' - Read function for the GNU TLS library.
+ */
+
+ssize_t /* O - Number of bytes read or -1 on error */
+_httpReadGNUTLS(
+ gnutls_transport_ptr ptr, /* I - Connection to server */
+ void *data, /* I - Buffer */
+ size_t length) /* I - Number of bytes to read */
+{
+ http_t *http; /* HTTP connection */
+
+
+ http = (http_t *)ptr;
+
+ if (!http->blocking)
+ {
+ /*
+ * Make sure we have data before we read...
+ */
+
+ while (!_httpWait(http, 10000, 0))
+ {
+ if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+ continue;
+
+ http->error = ETIMEDOUT;
+ return (-1);
+ }
+ }
+
+ return (recv(http->fd, data, length, 0));
+}
+#endif /* HAVE_SSL && HAVE_GNUTLS */
+
+
+/*
+ * 'httpReconnect()' - Reconnect to a HTTP server.
+ */
+
+int /* O - 0 on success, non-zero on failure */
+httpReconnect(http_t *http) /* I - Connection to server */
+{
+ http_addrlist_t *addr; /* Connected address */
+#ifdef DEBUG
+ http_addrlist_t *current; /* Current address */
+ char temp[256]; /* Temporary address string */
+#endif /* DEBUG */
+
+
+ DEBUG_printf(("httpReconnect(http=%p)", http));
+
+ if (!http)
+ return (-1);
+
+#ifdef HAVE_SSL
+ if (http->tls)
+ {
+ DEBUG_puts("2httpReconnect: Shutting down SSL/TLS...");
+ http_shutdown_ssl(http);
+ }
+#endif /* HAVE_SSL */
+
+ /*
+ * Close any previously open socket...
+ */
+
+ if (http->fd >= 0)
+ {
+ DEBUG_printf(("2httpReconnect: Closing socket %d...", http->fd));
+
+#ifdef WIN32
+ closesocket(http->fd);
+#else
+ close(http->fd);
+#endif /* WIN32 */
+
+ http->fd = -1;
+ }
+
+ /*
+ * Connect to the server...
+ */
+
+#ifdef DEBUG
+ for (current = http->addrlist; current; current = current->next)
+ DEBUG_printf(("2httpReconnect: Address %s:%d",
+ httpAddrString(&(current->addr), temp, sizeof(temp)),
+ _httpAddrPort(&(current->addr))));
+#endif /* DEBUG */
+
+ if ((addr = httpAddrConnect(http->addrlist, &(http->fd))) == NULL)
+ {
+ /*
+ * Unable to connect...
+ */
+
+#ifdef WIN32
+ http->error = WSAGetLastError();
+#else
+ http->error = errno;
+#endif /* WIN32 */
+ http->status = HTTP_ERROR;
+
+ DEBUG_printf(("1httpReconnect: httpAddrConnect failed: %s",
+ strerror(http->error)));
+
+ return (-1);
+ }
+
+ DEBUG_printf(("2httpReconnect: New socket=%d", http->fd));
+
+ if (http->timeout_value.tv_sec > 0)
+ {
+#ifdef WIN32
+ DWORD timeout_value = http->timeout_value.tv_sec * 1000 +
+ http->timeout_value.tv_usec / 1000;
+ /* Timeout in milliseconds */
+
+ setsockopt(http->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout_value,
+ sizeof(timeout_value));
+ setsockopt(http->fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout_value,
+ sizeof(timeout_value));
+#else
+ setsockopt(http->fd, SOL_SOCKET, SO_RCVTIMEO, &(http->timeout_value),
+ sizeof(http->timeout_value));
+ setsockopt(http->fd, SOL_SOCKET, SO_SNDTIMEO, &(http->timeout_value),
+ sizeof(http->timeout_value));
+#endif /* WIN32 */
+ }
+
+ http->hostaddr = &(addr->addr);
+ http->error = 0;
+ http->status = HTTP_CONTINUE;
+
+#ifdef HAVE_SSL
+ if (http->encryption == HTTP_ENCRYPT_ALWAYS)
+ {
+ /*
+ * Always do encryption via SSL.
+ */
+
+ if (http_setup_ssl(http) != 0)
+ {
+# ifdef WIN32
+ closesocket(http->fd);
+# else
+ close(http->fd);
+# endif /* WIN32 */
+
+ return (-1);
+ }
+ }
+ else if (http->encryption == HTTP_ENCRYPT_REQUIRED)
+ return (http_upgrade(http));
+#endif /* HAVE_SSL */
+
+ DEBUG_printf(("1httpReconnect: Connected to %s:%d...",
+ httpAddrString(http->hostaddr, temp, sizeof(temp)),
+ _httpAddrPort(http->hostaddr)));
+
+ return (0);
+}
+
+
+/*
+ * 'httpSetAuthString()' - Set the current authorization string.
+ *
+ * This function just stores a copy of the current authorization string in
+ * the HTTP connection object. You must still call httpSetField() to set
+ * HTTP_FIELD_AUTHORIZATION prior to issuing a HTTP request using httpGet(),
+ * httpHead(), httpOptions(), httpPost, or httpPut().
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+void
+httpSetAuthString(http_t *http, /* I - Connection to server */
+ const char *scheme, /* I - Auth scheme (NULL to clear it) */
+ const char *data) /* I - Auth data (NULL for none) */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!http)
+ return;
+
+ if (http->authstring && http->authstring != http->_authstring)
+ free(http->authstring);
+
+ http->authstring = http->_authstring;
+
+ if (scheme)
+ {
+ /*
+ * Set the current authorization string...
+ */
+
+ int len = (int)strlen(scheme) + (data ? (int)strlen(data) + 1 : 0) + 1;
+ char *temp;
+
+ if (len > (int)sizeof(http->_authstring))
+ {
+ if ((temp = malloc(len)) == NULL)
+ len = sizeof(http->_authstring);
+ else
+ http->authstring = temp;
+ }
+
+ if (data)
+ snprintf(http->authstring, len, "%s %s", scheme, data);
+ else
+ strlcpy(http->authstring, scheme, len);
+ }
+ else
+ {
+ /*
+ * Clear the current authorization string...
+ */
+
+ http->_authstring[0] = '\0';
+ }
+}
+
+
+/*
+ * 'httpSetCredentials()' - Set the credentials associated with an encrypted
+ * connection.
+ *
+ * @since CUPS 1.5/Mac OS X 10.7@
+ */
+
+int /* O - Status of call (0 = success) */
+httpSetCredentials(http_t *http, /* I - Connection to server */
+ cups_array_t *credentials) /* I - Array of credentials */
+{
+ if (!http || cupsArrayCount(credentials) < 1)
+ return (-1);
+
+ _httpFreeCredentials(http->tls_credentials);
+
+ http->tls_credentials = _httpConvertCredentials(credentials);
+
+ return (http->tls_credentials ? 0 : -1);
+}
+
+
+/*
+ * 'httpSetCookie()' - Set the cookie value(s).
+ *
+ * @since CUPS 1.1.19/Mac OS X 10.3@
+ */
+
+void
+httpSetCookie(http_t *http, /* I - Connection */
+ const char *cookie) /* I - Cookie string */
+{
+ if (!http)
+ return;
+
+ if (http->cookie)
+ free(http->cookie);
+
+ if (cookie)
+ http->cookie = strdup(cookie);
+ else
+ http->cookie = NULL;
+}
+
+
+/*
+ * 'httpSetExpect()' - Set the Expect: header in a request.
+ *
+ * Currently only HTTP_CONTINUE is supported for the "expect" argument.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void
+httpSetExpect(http_t *http, /* I - Connection to server */
+ http_status_t expect) /* I - HTTP status to expect (HTTP_CONTINUE) */
+{
+ if (http)
+ http->expect = expect;
+}
+
+
+/*
+ * 'httpSetField()' - Set the value of an HTTP header.
+ */
+
+void
+httpSetField(http_t *http, /* I - Connection to server */
+ http_field_t field, /* I - Field index */
+ const char *value) /* I - Value */
+{
+ if (http == NULL ||
+ field < HTTP_FIELD_ACCEPT_LANGUAGE ||
+ field > HTTP_FIELD_WWW_AUTHENTICATE ||
+ value == NULL)
+ return;
+
+ strlcpy(http->fields[field], value, HTTP_MAX_VALUE);
+
+ if (field == HTTP_FIELD_AUTHORIZATION)
+ {
+ /*
+ * Special case for Authorization: as its contents can be
+ * longer than HTTP_MAX_VALUE
+ */
+
+ if (http->field_authorization)
+ free(http->field_authorization);
+
+ http->field_authorization = strdup(value);
+ }
+ else if (field == HTTP_FIELD_HOST)
+ {
+ /*
+ * Special-case for Host: as we don't want a trailing "." on the hostname and
+ * need to bracket IPv6 numeric addresses.
+ */
+
+ char *ptr = strchr(value, ':');
+
+ if (value[0] != '[' && ptr && strchr(ptr + 1, ':'))
+ {
+ /*
+ * Bracket IPv6 numeric addresses...
+ *
+ * This is slightly inefficient (basically copying twice), but is an edge
+ * case and not worth optimizing...
+ */
+
+ snprintf(http->fields[HTTP_FIELD_HOST],
+ sizeof(http->fields[HTTP_FIELD_HOST]), "[%s]", value);
+ }
+ else
+ {
+ /*
+ * Check for a trailing dot on the hostname...
+ */
+
+ ptr = http->fields[HTTP_FIELD_HOST];
+
+ if (*ptr)
+ {
+ ptr += strlen(ptr) - 1;
+
+ if (*ptr == '.')
+ *ptr = '\0';
+ }
+ }
+ }
+}
+
+
+/*
+ * 'httpSetLength()' - Set the content-length and content-encoding.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+void
+httpSetLength(http_t *http, /* I - Connection to server */
+ size_t length) /* I - Length (0 for chunked) */
+{
+ if (!http)
+ return;
+
+ if (!length)
+ {
+ strcpy(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked");
+ http->fields[HTTP_FIELD_CONTENT_LENGTH][0] = '\0';
+ }
+ else
+ {
+ http->fields[HTTP_FIELD_TRANSFER_ENCODING][0] = '\0';
+ snprintf(http->fields[HTTP_FIELD_CONTENT_LENGTH], HTTP_MAX_VALUE,
+ CUPS_LLFMT, CUPS_LLCAST length);
+ }
+}
+
+
+/*
+ * 'httpSetTimeout()' - Set read/write timeouts and an optional callback.
+ *
+ * The optional timeout callback receives both the HTTP connection and a user
+ * data pointer and must return 1 to continue or 0 to error (time) out.
+ *
+ * @since CUPS 1.5/Mac OS X 10.7@
+ */
+
+void
+httpSetTimeout(
+ http_t *http, /* I - Connection to server */
+ double timeout, /* I - Number of seconds for timeout,
+ must be greater than 0 */
+ http_timeout_cb_t cb, /* I - Callback function or NULL */
+ void *user_data) /* I - User data pointer */
+{
+ if (!http || timeout <= 0.0)
+ return;
+
+ http->timeout_cb = cb;
+ http->timeout_data = user_data;
+ http->timeout_value.tv_sec = (int)timeout;
+ http->timeout_value.tv_usec = (int)(timeout * 1000000) % 1000000;
+
+ if (http->fd >= 0)
+ {
+#ifdef WIN32
+ DWORD timeout_value = http->timeout_value.tv_sec * 1000 +
+ http->timeout_value.tv_usec / 1000;
+ /* Timeout in milliseconds */
+
+ setsockopt(http->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout_value,
+ sizeof(timeout_value));
+ setsockopt(http->fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout_value,
+ sizeof(timeout_value));
+
+#else
+ setsockopt(http->fd, SOL_SOCKET, SO_RCVTIMEO, &(http->timeout_value),
+ sizeof(http->timeout_value));
+ setsockopt(http->fd, SOL_SOCKET, SO_SNDTIMEO, &(http->timeout_value),
+ sizeof(http->timeout_value));
+#endif /* WIN32 */
+ }
+}
+
+
+/*
+ * 'httpTrace()' - Send an TRACE request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpTrace(http_t *http, /* I - Connection to server */
+ const char *uri) /* I - URI for trace */
+{
+ return (http_send(http, HTTP_TRACE, uri));
+}
+
+
+/*
+ * '_httpUpdate()' - Update the current HTTP status for incoming data.
+ *
+ * Note: Unlike httpUpdate(), this function does not flush pending write data
+ * and only retrieves a single status line from the HTTP connection.
+ */
+
+int /* O - 1 to continue, 0 to stop */
+_httpUpdate(http_t *http, /* I - Connection to server */
+ http_status_t *status) /* O - Current HTTP status */
+{
+ char line[32768], /* Line from connection... */
+ *value; /* Pointer to value on line */
+ http_field_t field; /* Field index */
+ int major, minor; /* HTTP version numbers */
+
+
+ DEBUG_printf(("_httpUpdate(http=%p, status=%p), state=%s", http, status,
+ http_states[http->state]));
+
+ /*
+ * Grab a single line from the connection...
+ */
+
+ if (!httpGets(line, sizeof(line), http))
+ {
+ *status = HTTP_ERROR;
+ return (0);
+ }
+
+ DEBUG_printf(("2_httpUpdate: Got \"%s\"", line));
+
+ if (line[0] == '\0')
+ {
+ /*
+ * Blank line means the start of the data section (if any). Return
+ * the result code, too...
+ *
+ * If we get status 100 (HTTP_CONTINUE), then we *don't* change states.
+ * Instead, we just return HTTP_CONTINUE to the caller and keep on
+ * tryin'...
+ */
+
+ if (http->status == HTTP_CONTINUE)
+ {
+ *status = http->status;
+ return (0);
+ }
+
+ if (http->status < HTTP_BAD_REQUEST)
+ http->digest_tries = 0;
+
+#ifdef HAVE_SSL
+ if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls)
+ {
+ if (http_setup_ssl(http) != 0)
+ {
+# ifdef WIN32
+ closesocket(http->fd);
+# else
+ close(http->fd);
+# endif /* WIN32 */
+
+ *status = http->status = HTTP_ERROR;
+ return (0);
+ }
+
+ *status = HTTP_CONTINUE;
+ return (0);
+ }
+#endif /* HAVE_SSL */
+
+ httpGetLength2(http);
+
+ switch (http->state)
+ {
+ case HTTP_GET :
+ case HTTP_POST :
+ case HTTP_POST_RECV :
+ case HTTP_PUT :
+ http->state ++;
+ case HTTP_POST_SEND :
+ case HTTP_HEAD :
+ break;
+
+ default :
+ http->state = HTTP_WAITING;
+ break;
+ }
+
+ *status = http->status;
+ return (0);
+ }
+ else if (!strncmp(line, "HTTP/", 5))
+ {
+ /*
+ * Got the beginning of a response...
+ */
+
+ int intstatus; /* Status value as an integer */
+
+ if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &intstatus) != 3)
+ {
+ *status = http->status = HTTP_ERROR;
+ return (0);
+ }
+
+ http->version = (http_version_t)(major * 100 + minor);
+ *status = http->status = (http_status_t)intstatus;
+ }
+ else if ((value = strchr(line, ':')) != NULL)
+ {
+ /*
+ * Got a value...
+ */
+
+ *value++ = '\0';
+ while (_cups_isspace(*value))
+ value ++;
+
+ /*
+ * Be tolerants of servers that send unknown attribute fields...
+ */
+
+ if (!_cups_strcasecmp(line, "expect"))
+ {
+ /*
+ * "Expect: 100-continue" or similar...
+ */
+
+ http->expect = (http_status_t)atoi(value);
+ }
+ else if (!_cups_strcasecmp(line, "cookie"))
+ {
+ /*
+ * "Cookie: name=value[; name=value ...]" - replaces previous cookies...
+ */
+
+ httpSetCookie(http, value);
+ }
+ else if ((field = http_field(line)) != HTTP_FIELD_UNKNOWN)
+ httpSetField(http, field, value);
+#ifdef DEBUG
+ else
+ DEBUG_printf(("1_httpUpdate: unknown field %s seen!", line));
+#endif /* DEBUG */
+ }
+ else
+ {
+ DEBUG_printf(("1_httpUpdate: Bad response line \"%s\"!", line));
+ *status = http->status = HTTP_ERROR;
+ return (0);
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'httpUpdate()' - Update the current HTTP state for incoming data.
+ */
+
+http_status_t /* O - HTTP status */
+httpUpdate(http_t *http) /* I - Connection to server */
+{
+ http_status_t status; /* Request status */
+
+
+ DEBUG_printf(("httpUpdate(http=%p), state=%s", http,
+ http_states[http->state]));
+
+ /*
+ * Flush pending data, if any...
+ */
+
+ if (http->wused)
+ {
+ DEBUG_puts("2httpUpdate: flushing buffer...");
+
+ if (httpFlushWrite(http) < 0)
+ return (HTTP_ERROR);
+ }
+
+ /*
+ * If we haven't issued any commands, then there is nothing to "update"...
+ */
+
+ if (http->state == HTTP_WAITING)
+ return (HTTP_CONTINUE);
+
+ /*
+ * Grab all of the lines we can from the connection...
+ */
+
+ while (_httpUpdate(http, &status));
+
+ /*
+ * See if there was an error...
+ */
+
+ if (http->error == EPIPE && http->status > HTTP_CONTINUE)
+ {
+ DEBUG_printf(("1httpUpdate: Returning status %d...", http->status));
+ return (http->status);
+ }
+
+ if (http->error)
+ {
+ DEBUG_printf(("1httpUpdate: socket error %d - %s", http->error,
+ strerror(http->error)));
+ http->status = HTTP_ERROR;
+ return (HTTP_ERROR);
+ }
+
+ /*
+ * Return the current status...
+ */
+
+ return (status);
+}
+
+
+/*
+ * '_httpWait()' - Wait for data available on a connection (no flush).
+ */
+
+int /* O - 1 if data is available, 0 otherwise */
+_httpWait(http_t *http, /* I - Connection to server */
+ int msec, /* I - Milliseconds to wait */
+ int usessl) /* I - Use SSL context? */
+{
+#ifdef HAVE_POLL
+ struct pollfd pfd; /* Polled file descriptor */
+#else
+ fd_set input_set; /* select() input set */
+ struct timeval timeout; /* Timeout */
+#endif /* HAVE_POLL */
+ int nfds; /* Result from select()/poll() */
+
+
+ DEBUG_printf(("4_httpWait(http=%p, msec=%d, usessl=%d)", http, msec, usessl));
+
+ if (http->fd < 0)
+ {
+ DEBUG_printf(("5_httpWait: Returning 0 since fd=%d", http->fd));
+ return (0);
+ }
+
+ /*
+ * Check the SSL/TLS buffers for data first...
+ */
+
+#ifdef HAVE_SSL
+ if (http->tls && usessl)
+ {
+# ifdef HAVE_LIBSSL
+ if (SSL_pending(http->tls))
+ {
+ DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data.");
+ return (1);
+ }
+
+# elif defined(HAVE_GNUTLS)
+ if (gnutls_record_check_pending(http->tls))
+ {
+ DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data.");
+ return (1);
+ }
+
+# elif defined(HAVE_CDSASSL)
+ size_t bytes; /* Bytes that are available */
+
+ if (!SSLGetBufferedReadSize(http->tls, &bytes) &&
+ bytes > 0)
+ {
+ DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data.");
+ return (1);
+ }
+# endif /* HAVE_LIBSSL */
+ }
+#endif /* HAVE_SSL */
+
+ /*
+ * Then try doing a select() or poll() to poll the socket...
+ */
+
+#ifdef HAVE_POLL
+ pfd.fd = http->fd;
+ pfd.events = POLLIN;
+
+ while ((nfds = poll(&pfd, 1, msec)) < 0 &&
+ (errno == EINTR || errno == EAGAIN));
+
+#else
+ do
+ {
+ FD_ZERO(&input_set);
+ FD_SET(http->fd, &input_set);
+
+ DEBUG_printf(("6_httpWait: msec=%d, http->fd=%d", msec, http->fd));
+
+ if (msec >= 0)
+ {
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+
+ nfds = select(http->fd + 1, &input_set, NULL, NULL, &timeout);
+ }
+ else
+ nfds = select(http->fd + 1, &input_set, NULL, NULL, NULL);
+
+ DEBUG_printf(("6_httpWait: select() returned %d...", nfds));
+ }
+# ifdef WIN32
+ while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
+ WSAGetLastError() == WSAEWOULDBLOCK));
+# else
+ while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
+# endif /* WIN32 */
+#endif /* HAVE_POLL */
+
+ DEBUG_printf(("5_httpWait: returning with nfds=%d, errno=%d...", nfds,
+ errno));
+
+ return (nfds > 0);
+}
+
+
+/*
+ * 'httpWait()' - Wait for data available on a connection.
+ *
+ * @since CUPS 1.1.19/Mac OS X 10.3@
+ */
+
+int /* O - 1 if data is available, 0 otherwise */
+httpWait(http_t *http, /* I - Connection to server */
+ int msec) /* I - Milliseconds to wait */
+{
+ /*
+ * First see if there is data in the buffer...
+ */
+
+ DEBUG_printf(("2httpWait(http=%p, msec=%d)", http, msec));
+
+ if (http == NULL)
+ return (0);
+
+ if (http->used)
+ {
+ DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
+ return (1);
+ }
+
+ /*
+ * Flush pending data, if any...
+ */
+
+ if (http->wused)
+ {
+ DEBUG_puts("3httpWait: Flushing write buffer.");
+
+ if (httpFlushWrite(http) < 0)
+ return (0);
+ }
+
+ /*
+ * If not, check the SSL/TLS buffers and do a select() on the connection...
+ */
+
+ return (_httpWait(http, msec, 1));
+}
+
+
+/*
+ * 'httpWrite()' - Write data to a HTTP connection.
+ *
+ * This function is deprecated. Use the httpWrite2() function which can
+ * write more than 2GB of data.
+ *
+ * @deprecated@
+ */
+
+int /* O - Number of bytes written */
+httpWrite(http_t *http, /* I - Connection to server */
+ const char *buffer, /* I - Buffer for data */
+ int length) /* I - Number of bytes to write */
+{
+ return ((int)httpWrite2(http, buffer, length));
+}
+
+
+/*
+ * 'httpWrite2()' - Write data to a HTTP connection.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ssize_t /* O - Number of bytes written */
+httpWrite2(http_t *http, /* I - Connection to server */
+ const char *buffer, /* I - Buffer for data */
+ size_t length) /* I - Number of bytes to write */
+{
+ ssize_t bytes; /* Bytes written */
+
+
+ DEBUG_printf(("httpWrite2(http=%p, buffer=%p, length=" CUPS_LLFMT ")", http,
+ buffer, CUPS_LLCAST length));
+
+ /*
+ * Range check input...
+ */
+
+ if (http == NULL || buffer == NULL)
+ return (-1);
+
+ /*
+ * Mark activity on the connection...
+ */
+
+ http->activity = time(NULL);
+
+ /*
+ * Buffer small writes for better performance...
+ */
+
+ if (length > 0)
+ {
+ if (http->wused && (length + http->wused) > sizeof(http->wbuffer))
+ {
+ DEBUG_printf(("2httpWrite2: Flushing buffer (wused=%d, length="
+ CUPS_LLFMT ")", http->wused, CUPS_LLCAST length));
+
+ httpFlushWrite(http);
+ }
+
+ if ((length + http->wused) <= sizeof(http->wbuffer) &&
+ length < sizeof(http->wbuffer))
+ {
+ /*
+ * Write to buffer...
+ */
+
+ DEBUG_printf(("2httpWrite2: Copying " CUPS_LLFMT " bytes to wbuffer...",
+ CUPS_LLCAST length));
+
+ memcpy(http->wbuffer + http->wused, buffer, length);
+ http->wused += (int)length;
+ bytes = (ssize_t)length;
+ }
+ else
+ {
+ /*
+ * Otherwise write the data directly...
+ */
+
+ DEBUG_printf(("2httpWrite2: Writing " CUPS_LLFMT " bytes to socket...",
+ CUPS_LLCAST length));
+
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED)
+ bytes = (ssize_t)http_write_chunk(http, buffer, (int)length);
+ else
+ bytes = (ssize_t)http_write(http, buffer, (int)length);
+
+ DEBUG_printf(("2httpWrite2: Wrote " CUPS_LLFMT " bytes...",
+ CUPS_LLCAST bytes));
+ }
+
+ if (http->data_encoding == HTTP_ENCODE_LENGTH)
+ http->data_remaining -= bytes;
+ }
+ else
+ bytes = 0;
+
+ /*
+ * Handle end-of-request processing...
+ */
+
+ if ((http->data_encoding == HTTP_ENCODE_CHUNKED && length == 0) ||
+ (http->data_encoding == HTTP_ENCODE_LENGTH && http->data_remaining == 0))
+ {
+ /*
+ * Finished with the transfer; unless we are sending POST or PUT
+ * data, go idle...
+ */
+
+ DEBUG_puts("2httpWrite: changing states...");
+
+ if (http->wused)
+ httpFlushWrite(http);
+
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED)
+ {
+ /*
+ * Send a 0-length chunk at the end of the request...
+ */
+
+ http_write(http, "0\r\n\r\n", 5);
+
+ /*
+ * Reset the data state...
+ */
+
+ http->data_encoding = HTTP_ENCODE_LENGTH;
+ http->data_remaining = 0;
+ }
+ }
+
+ return (bytes);
+}
+
+
+#if defined(HAVE_SSL) && defined(HAVE_CDSASSL)
+/*
+ * '_httpWriteCDSA()' - Write function for the CDSA library.
+ */
+
+OSStatus /* O - -1 on error, 0 on success */
+_httpWriteCDSA(
+ SSLConnectionRef connection, /* I - SSL/TLS connection */
+ const void *data, /* I - Data buffer */
+ size_t *dataLength) /* IO - Number of bytes */
+{
+ OSStatus result; /* Return value */
+ ssize_t bytes; /* Number of bytes read */
+ http_t *http; /* HTTP connection */
+
+
+ http = (http_t *)connection;
+
+ do
+ {
+ bytes = write(http->fd, data, *dataLength);
+ }
+ while (bytes == -1 && (errno == EINTR || errno == EAGAIN));
+
+ if (bytes == *dataLength)
+ {
+ result = 0;
+ }
+ else if (bytes >= 0)
+ {
+ *dataLength = bytes;
+ result = errSSLWouldBlock;
+ }
+ else
+ {
+ *dataLength = 0;
+
+ if (errno == EAGAIN)
+ result = errSSLWouldBlock;
+ else
+ result = errSSLClosedAbort;
+ }
+
+ return (result);
+}
+#endif /* HAVE_SSL && HAVE_CDSASSL */
+
+
+#if defined(HAVE_SSL) && defined(HAVE_GNUTLS)
+/*
+ * '_httpWriteGNUTLS()' - Write function for the GNU TLS library.
+ */
+
+ssize_t /* O - Number of bytes written or -1 on error */
+_httpWriteGNUTLS(
+ gnutls_transport_ptr ptr, /* I - Connection to server */
+ const void *data, /* I - Data buffer */
+ size_t length) /* I - Number of bytes to write */
+{
+ return (send(((http_t *)ptr)->fd, data, length, 0));
+}
+#endif /* HAVE_SSL && HAVE_GNUTLS */
+
+
+#if defined(HAVE_SSL) && defined(HAVE_LIBSSL)
+/*
+ * 'http_bio_ctrl()' - Control the HTTP connection.
+ */
+
+static long /* O - Result/data */
+http_bio_ctrl(BIO *h, /* I - BIO data */
+ int cmd, /* I - Control command */
+ long arg1, /* I - First argument */
+ void *arg2) /* I - Second argument */
+{
+ switch (cmd)
+ {
+ default :
+ return (0);
+
+ case BIO_CTRL_RESET :
+ h->ptr = NULL;
+ return (0);
+
+ case BIO_C_SET_FILE_PTR :
+ h->ptr = arg2;
+ h->init = 1;
+ return (1);
+
+ case BIO_C_GET_FILE_PTR :
+ if (arg2)
+ {
+ *((void **)arg2) = h->ptr;
+ return (1);
+ }
+ else
+ return (0);
+
+ case BIO_CTRL_DUP :
+ case BIO_CTRL_FLUSH :
+ return (1);
+ }
+}
+
+
+/*
+ * 'http_bio_free()' - Free OpenSSL data.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+http_bio_free(BIO *h) /* I - BIO data */
+{
+ if (!h)
+ return (0);
+
+ if (h->shutdown)
+ {
+ h->init = 0;
+ h->flags = 0;
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'http_bio_new()' - Initialize an OpenSSL BIO structure.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+http_bio_new(BIO *h) /* I - BIO data */
+{
+ if (!h)
+ return (0);
+
+ h->init = 0;
+ h->num = 0;
+ h->ptr = NULL;
+ h->flags = 0;
+
+ return (1);
+}
+
+
+/*
+ * 'http_bio_puts()' - Send a string for OpenSSL.
+ */
+
+static int /* O - Bytes written */
+http_bio_puts(BIO *h, /* I - BIO data */
+ const char *str) /* I - String to write */
+{
+#ifdef WIN32
+ return (send(((http_t *)h->ptr)->fd, str, (int)strlen(str), 0));
+#else
+ return (send(((http_t *)h->ptr)->fd, str, strlen(str), 0));
+#endif /* WIN32 */
+}
+
+
+/*
+ * 'http_bio_read()' - Read data for OpenSSL.
+ */
+
+static int /* O - Bytes read */
+http_bio_read(BIO *h, /* I - BIO data */
+ char *buf, /* I - Buffer */
+ int size) /* I - Number of bytes to read */
+{
+ http_t *http; /* HTTP connection */
+
+
+ http = (http_t *)h->ptr;
+
+ if (!http->blocking)
+ {
+ /*
+ * Make sure we have data before we read...
+ */
+
+ while (!_httpWait(http, 10000, 0))
+ {
+ if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+ continue;
+
+#ifdef WIN32
+ http->error = WSAETIMEDOUT;
+#else
+ http->error = ETIMEDOUT;
+#endif /* WIN32 */
+
+ return (-1);
+ }
+ }
+
+ return (recv(http->fd, buf, size, 0));
+}
+
+
+/*
+ * 'http_bio_write()' - Write data for OpenSSL.
+ */
+
+static int /* O - Bytes written */
+http_bio_write(BIO *h, /* I - BIO data */
+ const char *buf, /* I - Buffer to write */
+ int num) /* I - Number of bytes to write */
+{
+ return (send(((http_t *)h->ptr)->fd, buf, num, 0));
+}
+#endif /* HAVE_SSL && HAVE_LIBSSL */
+
+
+#ifdef DEBUG
+/*
+ * 'http_debug_hex()' - Do a hex dump of a buffer.
+ */
+
+static void
+http_debug_hex(const char *prefix, /* I - Prefix for line */
+ const char *buffer, /* I - Buffer to dump */
+ int bytes) /* I - Bytes to dump */
+{
+ int i, j, /* Looping vars */
+ ch; /* Current character */
+ char line[255], /* Line buffer */
+ *start, /* Start of line after prefix */
+ *ptr; /* Pointer into line */
+
+
+ if (_cups_debug_fd < 0 || _cups_debug_level < 6)
+ return;
+
+ DEBUG_printf(("6%s: %d bytes:\n", prefix, bytes));
+
+ snprintf(line, sizeof(line), "6%s: ", prefix);
+ start = line + strlen(line);
+
+ for (i = 0; i < bytes; i += 16)
+ {
+ for (j = 0, ptr = start; j < 16 && (i + j) < bytes; j ++, ptr += 2)
+ sprintf(ptr, "%02X", buffer[i + j] & 255);
+
+ while (j < 16)
+ {
+ strcpy(ptr, " ");
+ ptr += 2;
+ j ++;
+ }
+
+ strcpy(ptr, " ");
+ ptr += 2;
+
+ for (j = 0; j < 16 && (i + j) < bytes; j ++)
+ {
+ ch = buffer[i + j] & 255;
+
+ if (ch < ' ' || ch >= 127)
+ ch = '.';
+
+ *ptr++ = ch;
+ }
+
+ *ptr = '\0';
+ DEBUG_puts(line);
+ }
+}
+#endif /* DEBUG */
+
+
+/*
+ * 'http_field()' - Return the field index for a field name.
+ */
+
+static http_field_t /* O - Field index */
+http_field(const char *name) /* I - String name */
+{
+ int i; /* Looping var */
+
+
+ for (i = 0; i < HTTP_FIELD_MAX; i ++)
+ if (_cups_strcasecmp(name, http_fields[i]) == 0)
+ return ((http_field_t)i);
+
+ return (HTTP_FIELD_UNKNOWN);
+}
+
+
+#ifdef HAVE_SSL
+/*
+ * 'http_read_ssl()' - Read from a SSL/TLS connection.
+ */
+
+static int /* O - Bytes read */
+http_read_ssl(http_t *http, /* I - Connection to server */
+ char *buf, /* I - Buffer to store data */
+ int len) /* I - Length of buffer */
+{
+# if defined(HAVE_LIBSSL)
+ return (SSL_read((SSL *)(http->tls), buf, len));
+
+# elif defined(HAVE_GNUTLS)
+ ssize_t result; /* Return value */
+
+
+ result = gnutls_record_recv(http->tls, buf, len);
+
+ if (result < 0 && !errno)
+ {
+ /*
+ * Convert GNU TLS error to errno value...
+ */
+
+ switch (result)
+ {
+ case GNUTLS_E_INTERRUPTED :
+ errno = EINTR;
+ break;
+
+ case GNUTLS_E_AGAIN :
+ errno = EAGAIN;
+ break;
+
+ default :
+ errno = EPIPE;
+ break;
+ }
+
+ result = -1;
+ }
+
+ return ((int)result);
+
+# elif defined(HAVE_CDSASSL)
+ int result; /* Return value */
+ OSStatus error; /* Error info */
+ size_t processed; /* Number of bytes processed */
+
+
+ error = SSLRead(http->tls, buf, len, &processed);
+
+ switch (error)
+ {
+ case 0 :
+ result = (int)processed;
+ break;
+
+ case errSSLWouldBlock :
+ if (processed)
+ result = (int)processed;
+ else
+ {
+ result = -1;
+ errno = EINTR;
+ }
+ break;
+
+ case errSSLClosedGraceful :
+ default :
+ if (processed)
+ result = (int)processed;
+ else
+ {
+ result = -1;
+ errno = EPIPE;
+ }
+ break;
+ }
+
+ return (result);
+# elif defined(HAVE_SSPISSL)
+ return _sspiRead((_sspi_struct_t*) http->tls, buf, len);
+# endif /* HAVE_LIBSSL */
+}
+#endif /* HAVE_SSL */
+
+
+/*
+ * 'http_send()' - Send a request with all fields and the trailing blank line.
+ */
+
+static int /* O - 0 on success, non-zero on error */
+http_send(http_t *http, /* I - Connection to server */
+ http_state_t request, /* I - Request code */
+ const char *uri) /* I - URI */
+{
+ int i; /* Looping var */
+ char buf[1024]; /* Encoded URI buffer */
+ static const char * const codes[] =
+ { /* Request code strings */
+ NULL,
+ "OPTIONS",
+ "GET",
+ NULL,
+ "HEAD",
+ "POST",
+ NULL,
+ NULL,
+ "PUT",
+ NULL,
+ "DELETE",
+ "TRACE",
+ "CLOSE"
+ };
+
+
+ DEBUG_printf(("7http_send(http=%p, request=HTTP_%s, uri=\"%s\")",
+ http, codes[request], uri));
+
+ if (http == NULL || uri == NULL)
+ return (-1);
+
+ /*
+ * Set the User-Agent field if it isn't already...
+ */
+
+ if (!http->fields[HTTP_FIELD_USER_AGENT][0])
+ httpSetField(http, HTTP_FIELD_USER_AGENT, CUPS_MINIMAL);
+
+ /*
+ * Encode the URI as needed...
+ */
+
+ _httpEncodeURI(buf, uri, sizeof(buf));
+
+ /*
+ * See if we had an error the last time around; if so, reconnect...
+ */
+
+ if (http->status == HTTP_ERROR || http->status >= HTTP_BAD_REQUEST)
+ if (httpReconnect(http))
+ return (-1);
+
+ /*
+ * Flush any written data that is pending...
+ */
+
+ if (http->wused)
+ {
+ if (httpFlushWrite(http) < 0)
+ if (httpReconnect(http))
+ return (-1);
+ }
+
+ /*
+ * Send the request header...
+ */
+
+ http->state = request;
+ http->data_encoding = HTTP_ENCODE_FIELDS;
+
+ if (request == HTTP_POST || request == HTTP_PUT)
+ http->state ++;
+
+ http->status = HTTP_CONTINUE;
+
+#ifdef HAVE_SSL
+ if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
+ {
+ httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
+ httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.0,SSL/2.0,SSL/3.0");
+ }
+#endif /* HAVE_SSL */
+
+ if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
+ {
+ http->status = HTTP_ERROR;
+ return (-1);
+ }
+
+ for (i = 0; i < HTTP_FIELD_MAX; i ++)
+ if (http->fields[i][0] != '\0')
+ {
+ DEBUG_printf(("9http_send: %s: %s", http_fields[i],
+ httpGetField(http, i)));
+
+ if (httpPrintf(http, "%s: %s\r\n", http_fields[i],
+ httpGetField(http, i)) < 1)
+ {
+ http->status = HTTP_ERROR;
+ return (-1);
+ }
+ }
+
+ if (http->cookie)
+ if (httpPrintf(http, "Cookie: $Version=0; %s\r\n", http->cookie) < 1)
+ {
+ http->status = HTTP_ERROR;
+ return (-1);
+ }
+
+ if (http->expect == HTTP_CONTINUE &&
+ (http->state == HTTP_POST_RECV || http->state == HTTP_PUT_RECV))
+ if (httpPrintf(http, "Expect: 100-continue\r\n") < 1)
+ {
+ http->status = HTTP_ERROR;
+ return (-1);
+ }
+
+ if (httpPrintf(http, "\r\n") < 1)
+ {
+ http->status = HTTP_ERROR;
+ return (-1);
+ }
+
+ if (httpFlushWrite(http) < 0)
+ return (-1);
+
+ httpGetLength2(http);
+ httpClearFields(http);
+
+ /*
+ * The Kerberos and AuthRef authentication strings can only be used once...
+ */
+
+ if (http->field_authorization && http->authstring &&
+ (!strncmp(http->authstring, "Negotiate", 9) ||
+ !strncmp(http->authstring, "AuthRef", 7)))
+ {
+ http->_authstring[0] = '\0';
+
+ if (http->authstring != http->_authstring)
+ free(http->authstring);
+
+ http->authstring = http->_authstring;
+ }
+
+ return (0);
+}
+
+
+#ifdef HAVE_SSL
+# if defined(HAVE_CDSASSL) && defined(HAVE_SECCERTIFICATECOPYDATA)
+/*
+ * 'http_set_credentials()' - Set the SSL/TLS credentials.
+ */
+
+static int /* O - Status of connection */
+http_set_credentials(http_t *http) /* I - Connection to server */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+ OSStatus error = 0; /* Error code */
+ http_tls_credentials_t credentials = NULL;
+ /* TLS credentials */
+
+
+ DEBUG_printf(("7http_set_credentials(%p)", http));
+
+ /*
+ * Prefer connection specific credentials...
+ */
+
+ if ((credentials = http->tls_credentials) == NULL)
+ credentials = cg->tls_credentials;
+
+# if HAVE_SECPOLICYCREATESSL
+ /*
+ * Otherwise root around in the user's keychain to see if one can be found...
+ */
+
+ if (!credentials)
+ {
+ CFDictionaryRef query; /* Query dictionary */
+ CFTypeRef matches = NULL; /* Matching credentials */
+ CFArrayRef dn_array = NULL;/* Distinguished names array */
+ CFTypeRef keys[] = { kSecClass,
+ kSecMatchLimit,
+ kSecReturnRef };
+ /* Keys for dictionary */
+ CFTypeRef values[] = { kSecClassCertificate,
+ kSecMatchLimitOne,
+ kCFBooleanTrue };
+ /* Values for dictionary */
+
+ /*
+ * Get the names associated with the server.
+ */
+
+ if ((error = SSLCopyDistinguishedNames(http->tls, &dn_array)) != noErr)
+ {
+ DEBUG_printf(("4http_set_credentials: SSLCopyDistinguishedNames, error=%d",
+ (int)error));
+ return (error);
+ }
+
+ /*
+ * Create a query which will return all identities that can sign and match
+ * the passed in policy.
+ */
+
+ query = CFDictionaryCreate(NULL,
+ (const void**)(&keys[0]),
+ (const void**)(&values[0]),
+ sizeof(keys) / sizeof(keys[0]),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ if (query)
+ {
+ error = SecItemCopyMatching(query, &matches);
+ DEBUG_printf(("4http_set_credentials: SecItemCopyMatching, error=%d",
+ (int)error));
+ CFRelease(query);
+ }
+
+ if (matches)
+ CFRelease(matches);
+
+ if (dn_array)
+ CFRelease(dn_array);
+ }
+# endif /* HAVE_SECPOLICYCREATESSL */
+
+ if (credentials)
+ {
+ error = SSLSetCertificate(http->tls, credentials);
+ DEBUG_printf(("4http_set_credentials: SSLSetCertificate, error=%d",
+ (int)error));
+ }
+ else
+ DEBUG_puts("4http_set_credentials: No credentials to set.");
+
+ return (error);
+}
+# endif /* HAVE_CDSASSL && HAVE_SECCERTIFICATECOPYDATA */
+
+
+/*
+ * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
+ */
+
+static int /* O - Status of connection */
+http_setup_ssl(http_t *http) /* I - Connection to server */
+{
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Pointer to library globals */
+ int any_root; /* Allow any root */
+
+# ifdef HAVE_LIBSSL
+ SSL_CTX *context; /* Context for encryption */
+ BIO *bio; /* BIO data */
+# elif defined(HAVE_GNUTLS)
+ gnutls_certificate_client_credentials *credentials;
+ /* TLS credentials */
+# elif defined(HAVE_CDSASSL)
+ OSStatus error; /* Error code */
+ const char *message = NULL; /* Error message */
+ char *hostname; /* Hostname */
+# ifdef HAVE_SECCERTIFICATECOPYDATA
+ cups_array_t *credentials; /* Credentials array */
+ cups_array_t *names; /* CUPS distinguished names */
+ CFArrayRef dn_array; /* CF distinguished names array */
+ CFIndex count; /* Number of credentials */
+ CFDataRef data; /* Certificate data */
+ int i; /* Looping var */
+ http_credential_t
+ *credential; /* Credential data */
+# endif /* HAVE_SECCERTIFICATECOPYDATA */
+# elif defined(HAVE_SSPISSL)
+ TCHAR username[256]; /* Username returned from GetUserName() */
+ TCHAR commonName[256]; /* Common name for certificate */
+ DWORD dwSize; /* 32 bit size */
+# endif /* HAVE_LIBSSL */
+
+
+ DEBUG_printf(("7http_setup_ssl(http=%p)", http));
+
+ /*
+ * Always allow self-signed certificates for the local loopback address...
+ */
+
+ if (httpAddrLocalhost(http->hostaddr))
+ any_root = 1;
+ else
+ any_root = cg->any_root;
+
+# ifdef HAVE_LIBSSL
+ context = SSL_CTX_new(SSLv23_client_method());
+
+ SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */
+
+ bio = BIO_new(_httpBIOMethods());
+ BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)http);
+
+ http->tls = SSL_new(context);
+ SSL_set_bio(http->tls_credentials, bio, bio);
+
+ if (SSL_connect(http->tls) != 1)
+ {
+# ifdef DEBUG
+ unsigned long error; /* Error code */
+
+ while ((error = ERR_get_error()) != 0)
+ DEBUG_printf(("8http_setup_ssl: %s", ERR_error_string(error, NULL)));
+# endif /* DEBUG */
+
+ SSL_CTX_free(context);
+ SSL_free(http->tls);
+ http->tls = NULL;
+
+# ifdef WIN32
+ http->error = WSAGetLastError();
+# else
+ http->error = errno;
+# endif /* WIN32 */
+ http->status = HTTP_ERROR;
+
+ return (HTTP_ERROR);
+ }
+
+# elif defined(HAVE_GNUTLS)
+ credentials = (gnutls_certificate_client_credentials *)
+ malloc(sizeof(gnutls_certificate_client_credentials));
+ if (credentials == NULL)
+ {
+ http->error = errno;
+ http->status = HTTP_ERROR;
+
+ return (-1);
+ }
+
+ gnutls_certificate_allocate_credentials(credentials);
+
+ gnutls_init(&http->tls, GNUTLS_CLIENT);
+ gnutls_set_default_priority(http->tls);
+ gnutls_credentials_set(http->tls, GNUTLS_CRD_CERTIFICATE, *credentials);
+ gnutls_transport_set_ptr(http->tls, (gnutls_transport_ptr)http);
+ gnutls_transport_set_pull_function(http->tls, _httpReadGNUTLS);
+ gnutls_transport_set_push_function(http->tls, _httpWriteGNUTLS);
+
+ if ((gnutls_handshake(http->tls)) != GNUTLS_E_SUCCESS)
+ {
+ http->error = errno;
+ http->status = HTTP_ERROR;
+
+ gnutls_deinit(http->tls);
+ gnutls_certificate_free_credentials(*credentials);
+ free(credentials);
+ http->tls = NULL;
+
+ return (-1);
+ }
+
+ http->tls_credentials = credentials;
+
+# elif defined(HAVE_CDSASSL)
+ if ((error = SSLNewContext(false, &http->tls)))
+ {
+ http->error = error;
+ http->status = HTTP_ERROR;
+
+ return (-1);
+ }
+
+ error = SSLSetConnection(http->tls, http);
+ DEBUG_printf(("4http_setup_ssl: SSLSetConnection, error=%d", (int)error));
+
+ if (!error)
+ {
+ error = SSLSetIOFuncs(http->tls, _httpReadCDSA, _httpWriteCDSA);
+ DEBUG_printf(("4http_setup_ssl: SSLSetIOFuncs, error=%d", (int)error));
+ }
+
+ if (!error)
+ {
+ error = SSLSetProtocolVersionEnabled(http->tls, kSSLProtocol2, false);
+ DEBUG_printf(("4http_setup_ssl: SSLSetProtocolVersionEnabled, error=%d",
+ (int)error));
+ }
+
+ if (!error)
+ {
+ error = SSLSetAllowsAnyRoot(http->tls, any_root);
+ DEBUG_printf(("4http_setup_ssl: SSLSetAllowsAnyRoot(%d), error=%d",
+ any_root, (int)error));
+ }
+
+ if (!error)
+ {
+ error = SSLSetAllowsExpiredCerts(http->tls, cg->expired_certs);
+ DEBUG_printf(("4http_setup_ssl: SSLSetAllowsExpiredCerts(%d), error=%d",
+ cg->expired_certs, (int)error));
+ }
+
+ if (!error)
+ {
+ error = SSLSetAllowsExpiredRoots(http->tls, cg->expired_root);
+ DEBUG_printf(("4http_setup_ssl: SSLSetAllowsExpiredRoots(%d), error=%d",
+ cg->expired_root, (int)error));
+ }
+
+# ifdef HAVE_SECCERTIFICATECOPYDATA
+ if (!error)
+ {
+ if (cg->client_cert_cb)
+ {
+ error = SSLSetSessionOption(http->tls,
+ kSSLSessionOptionBreakOnCertRequested, true);
+ DEBUG_printf(("4http_setup_ssl: kSSLSessionOptionBreakOnCertRequested, "
+ "error=%d", (int)error));
+ }
+ else
+ {
+ error = http_set_credentials(http);
+ DEBUG_printf(("4http_setup_ssl: http_set_credentials, error=%d",
+ (int)error));
+ }
+ }
+
+ /*
+ * If there's a server certificate callback installed let it evaluate the
+ * certificate(s) during the handshake...
+ */
+
+ if (!error && cg->server_cert_cb != NULL)
+ {
+ error = SSLSetEnableCertVerify(http->tls, false);
+ DEBUG_printf(("4http_setup_ssl: SSLSetEnableCertVerify, error=%d",
+ (int)error));
+
+ if (!error)
+ {
+ error = SSLSetSessionOption(http->tls,
+ kSSLSessionOptionBreakOnServerAuth, true);
+ DEBUG_printf(("4http_setup_ssl: kSSLSessionOptionBreakOnServerAuth, "
+ "error=%d", (int)error));
+ }
+ }
+# endif /* HAVE_SECCERTIFICATECOPYDATA */
+
+ if (!error)
+ {
+ hostname = httpAddrLocalhost(http->hostaddr) ? "localhost" : http->hostname;
+ error = SSLSetPeerDomainName(http->tls, hostname, strlen(hostname));
+
+ DEBUG_printf(("4http_setup_ssl: SSLSetPeerDomainName, error=%d",
+ (int)error));
+ }
+
+ if (!error)
+ {
+ int done = 0; /* Are we done yet? */
+
+ while (!error && !done)
+ {
+ error = SSLHandshake(http->tls);
+
+ DEBUG_printf(("4_httpWait: SSLHandshake returned %d.", (int)error));
+
+ switch (error)
+ {
+ case noErr :
+ done = 1;
+ break;
+
+ case errSSLWouldBlock :
+ usleep(1000);
+ break;
+
+# ifdef HAVE_SECCERTIFICATECOPYDATA
+ case errSSLServerAuthCompleted :
+ error = 0;
+ if (cg->server_cert_cb)
+ {
+ error = httpCopyCredentials(http, &credentials);
+ if (!error)
+ {
+ error = (cg->server_cert_cb)(http, http->tls, credentials,
+ cg->server_cert_data);
+ httpFreeCredentials(credentials);
+ }
+
+ DEBUG_printf(("4_httpWait: Server certificate callback returned "
+ "%d.", (int)error));
+ }
+ break;
+
+ case errSSLClientCertRequested :
+ error = 0;
+
+ if (cg->client_cert_cb)
+ {
+ names = NULL;
+ if (!(error = SSLCopyDistinguishedNames(http->tls, &dn_array)) &&
+ dn_array)
+ {
+ if ((names = cupsArrayNew(NULL, NULL)) != NULL)
+ {
+ for (i = 0, count = CFArrayGetCount(dn_array); i < count; i++)
+ {
+ data = (CFDataRef)CFArrayGetValueAtIndex(dn_array, i);
+
+ if ((credential = malloc(sizeof(*credential))))
+ {
+ credential->datalen = CFDataGetLength(data);
+ if ((credential->data = malloc(credential->datalen)))
+ {
+ memcpy((void *)credential->data, CFDataGetBytePtr(data),
+ credential->datalen);
+ cupsArrayAdd(names, credential);
+ }
+ }
+ }
+ }
+
+ CFRelease(dn_array);
+ }
+
+ if (!error)
+ {
+ error = (cg->client_cert_cb)(http, http->tls, names,
+ cg->client_cert_data);
+
+ DEBUG_printf(("4_httpWait: Client certificate callback "
+ "returned %d.", (int)error));
+ }
+
+ httpFreeCredentials(names);
+ }
+ break;
+# endif /* HAVE_SECCERTIFICATECOPYDATA */
+
+ case errSSLUnknownRootCert :
+ message = _("Unable to establish a secure connection to host "
+ "(untrusted certificate).");
+ break;
+
+ case errSSLNoRootCert :
+ message = _("Unable to establish a secure connection to host "
+ "(self-signed certificate).");
+ break;
+
+ case errSSLCertExpired :
+ message = _("Unable to establish a secure connection to host "
+ "(expired certificate).");
+ break;
+
+ case errSSLCertNotYetValid :
+ message = _("Unable to establish a secure connection to host "
+ "(certificate not yet valid).");
+ break;
+
+ case errSSLHostNameMismatch :
+ message = _("Unable to establish a secure connection to host "
+ "(host name mismatch).");
+ break;
+
+ case errSSLXCertChainInvalid :
+ message = _("Unable to establish a secure connection to host "
+ "(certificate chain invalid).");
+ break;
+
+ case errSSLConnectionRefused :
+ message = _("Unable to establish a secure connection to host "
+ "(peer dropped connection before responding).");
+ break;
+
+ default :
+ break;
+ }
+ }
+ }
+
+ if (error)
+ {
+ http->error = error;
+ http->status = HTTP_ERROR;
+ errno = ECONNREFUSED;
+
+ SSLDisposeContext(http->tls);
+ http->tls = NULL;
+
+ /*
+ * If an error string wasn't set by the callbacks use a generic one...
+ */
+
+ if (!message)
+#ifdef HAVE_CSSMERRORSTRING
+ message = cssmErrorString(error);
+#else
+ message = _("Unable to establish a secure connection to host.");
+#endif /* HAVE_CSSMERRORSTRING */
+
+ _cupsSetError(IPP_PKI_ERROR, message, 1);
+
+ return (-1);
+ }
+
+# elif defined(HAVE_SSPISSL)
+ http->tls = _sspiAlloc();
+
+ if (!http->tls)
+ return (-1);
+
+ http->tls->sock = http->fd;
+ dwSize = sizeof(username) / sizeof(TCHAR);
+ GetUserName(username, &dwSize);
+ _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR),
+ sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username);
+
+ if (!_sspiGetCredentials(http->tls_credentials, L"ClientContainer",
+ commonName, FALSE))
+ {
+ _sspiFree(http->tls_credentials);
+ http->tls_credentials = NULL;
+ return (-1);
+ }
+
+ _sspiSetAllowsAnyRoot(http->tls_credentials, TRUE);
+ _sspiSetAllowsExpiredCerts(http->tls_credentials, TRUE);
+
+ if (!_sspiConnect(http->tls_credentials, http->hostname))
+ {
+ _sspiFree(http->tls_credentials);
+ http->tls_credentials = NULL;
+ return (-1);
+ }
+# endif /* HAVE_CDSASSL */
+
+ return (0);
+}
+#endif /* HAVE_SSL */
+
+
+#ifdef HAVE_SSL
+/*
+ * 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection.
+ */
+
+static void
+http_shutdown_ssl(http_t *http) /* I - Connection to server */
+{
+# ifdef HAVE_LIBSSL
+ SSL_CTX *context; /* Context for encryption */
+
+ context = SSL_get_SSL_CTX(http->tls_credentials);
+
+ SSL_shutdown(http->tls_credentials);
+ SSL_CTX_free(context);
+ SSL_free(http->tls_credentials);
+
+# elif defined(HAVE_GNUTLS)
+ gnutls_certificate_client_credentials *credentials;
+ /* TLS credentials */
+
+ credentials = (gnutls_certificate_client_credentials *)(http->tls_credentials);
+
+ gnutls_bye(http->tls, GNUTLS_SHUT_RDWR);
+ gnutls_deinit(http->tls);
+ gnutls_certificate_free_credentials(*credentials);
+ free(credentials);
+
+# elif defined(HAVE_CDSASSL)
+ while (SSLClose(http->tls) == errSSLWouldBlock)
+ usleep(1000);
+
+ SSLDisposeContext(http->tls);
+
+ if (http->tls_credentials)
+ CFRelease(http->tls_credentials);
+
+# elif defined(HAVE_SSPISSL)
+ _sspiFree(http->tls_credentials);
+# endif /* HAVE_LIBSSL */
+
+ http->tls = NULL;
+ http->tls_credentials = NULL;
+}
+#endif /* HAVE_SSL */
+
+
+#ifdef HAVE_SSL
+/*
+ * 'http_upgrade()' - Force upgrade to TLS encryption.
+ */
+
+static int /* O - Status of connection */
+http_upgrade(http_t *http) /* I - Connection to server */
+{
+ int ret; /* Return value */
+ http_t myhttp; /* Local copy of HTTP data */
+
+
+ DEBUG_printf(("7http_upgrade(%p)", http));
+
+ /*
+ * Flush the connection to make sure any previous "Upgrade" message
+ * has been read.
+ */
+
+ httpFlush(http);
+
+ /*
+ * Copy the HTTP data to a local variable so we can do the OPTIONS
+ * request without interfering with the existing request data...
+ */
+
+ memcpy(&myhttp, http, sizeof(myhttp));
+
+ /*
+ * Send an OPTIONS request to the server, requiring SSL or TLS
+ * encryption on the link...
+ */
+
+ http->field_authorization = NULL; /* Don't free the auth string */
+
+ httpClearFields(http);
+ httpSetField(http, HTTP_FIELD_CONNECTION, "upgrade");
+ httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2, TLS/1.1, TLS/1.0, SSL/3.0");
+
+ if ((ret = httpOptions(http, "*")) == 0)
+ {
+ /*
+ * Wait for the secure connection...
+ */
+
+ while (httpUpdate(http) == HTTP_CONTINUE);
+ }
+
+ /*
+ * Restore the HTTP request data...
+ */
+
+ memcpy(http->fields, myhttp.fields, sizeof(http->fields));
+ http->data_encoding = myhttp.data_encoding;
+ http->data_remaining = myhttp.data_remaining;
+ http->_data_remaining = myhttp._data_remaining;
+ http->expect = myhttp.expect;
+ http->field_authorization = myhttp.field_authorization;
+ http->digest_tries = myhttp.digest_tries;
+
+ /*
+ * See if we actually went secure...
+ */
+
+ if (!http->tls)
+ {
+ /*
+ * Server does not support HTTP upgrade...
+ */
+
+ DEBUG_puts("8http_upgrade: Server does not support HTTP upgrade!");
+
+# ifdef WIN32
+ closesocket(http->fd);
+# else
+ close(http->fd);
+# endif
+
+ http->fd = -1;
+
+ return (-1);
+ }
+ else
+ return (ret);
+}
+#endif /* HAVE_SSL */
+
+
+/*
+ * 'http_write()' - Write a buffer to a HTTP connection.
+ */
+
+static int /* O - Number of bytes written */
+http_write(http_t *http, /* I - Connection to server */
+ const char *buffer, /* I - Buffer for data */
+ int length) /* I - Number of bytes to write */
+{
+ int tbytes, /* Total bytes sent */
+ bytes; /* Bytes sent */
+
+
+ DEBUG_printf(("2http_write(http=%p, buffer=%p, length=%d)", http, buffer,
+ length));
+ http->error = 0;
+ tbytes = 0;
+
+ while (length > 0)
+ {
+#ifdef HAVE_SSL
+ if (http->tls)
+ bytes = http_write_ssl(http, buffer, length);
+ else
+#endif /* HAVE_SSL */
+ bytes = send(http->fd, buffer, length, 0);
+
+ if (bytes < 0)
+ {
+#ifdef WIN32
+ if (WSAGetLastError() == WSAEINTR)
+ continue;
+ else if (WSAGetLastError() == WSAEWOULDBLOCK)
+ {
+ if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+ continue;
+
+ http->error = WSAGetLastError();
+ }
+ else if (WSAGetLastError() != http->error &&
+ WSAGetLastError() != WSAECONNRESET)
+ {
+ http->error = WSAGetLastError();
+ continue;
+ }
+
+#else
+ if (errno == EINTR)
+ continue;
+ else if (errno == EWOULDBLOCK || errno == EAGAIN)
+ {
+ if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+ continue;
+ else if (!http->timeout_cb && errno == EAGAIN)
+ continue;
+
+ http->error = errno;
+ }
+ else if (errno != http->error && errno != ECONNRESET)
+ {
+ http->error = errno;
+ continue;
+ }
+#endif /* WIN32 */
+
+ DEBUG_printf(("3http_write: error writing data (%s).",
+ strerror(http->error)));
+
+ return (-1);
+ }
+
+ buffer += bytes;
+ tbytes += bytes;
+ length -= bytes;
+ }
+
+#ifdef DEBUG
+ http_debug_hex("http_write", buffer - tbytes, tbytes);
+#endif /* DEBUG */
+
+ DEBUG_printf(("3http_write: Returning %d.", tbytes));
+
+ return (tbytes);
+}
+
+
+/*
+ * 'http_write_chunk()' - Write a chunked buffer.
+ */
+
+static int /* O - Number bytes written */
+http_write_chunk(http_t *http, /* I - Connection to server */
+ const char *buffer, /* I - Buffer to write */
+ int length) /* I - Length of buffer */
+{
+ char header[255]; /* Chunk header */
+ int bytes; /* Bytes written */
+
+
+ DEBUG_printf(("7http_write_chunk(http=%p, buffer=%p, length=%d)",
+ http, buffer, length));
+
+ /*
+ * Write the chunk header, data, and trailer.
+ */
+
+ sprintf(header, "%x\r\n", length);
+ if (http_write(http, header, (int)strlen(header)) < 0)
+ {
+ DEBUG_puts("8http_write_chunk: http_write of length failed!");
+ return (-1);
+ }
+
+ if ((bytes = http_write(http, buffer, length)) < 0)
+ {
+ DEBUG_puts("8http_write_chunk: http_write of buffer failed!");
+ return (-1);
+ }
+
+ if (http_write(http, "\r\n", 2) < 0)
+ {
+ DEBUG_puts("8http_write_chunk: http_write of CR LF failed!");
+ return (-1);
+ }
+
+ return (bytes);
+}
+
+
+#ifdef HAVE_SSL
+/*
+ * 'http_write_ssl()' - Write to a SSL/TLS connection.
+ */
+
+static int /* O - Bytes written */
+http_write_ssl(http_t *http, /* I - Connection to server */
+ const char *buf, /* I - Buffer holding data */
+ int len) /* I - Length of buffer */
+{
+ ssize_t result; /* Return value */
+
+
+ DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len));
+
+# if defined(HAVE_LIBSSL)
+ result = SSL_write((SSL *)(http->tls), buf, len);
+
+# elif defined(HAVE_GNUTLS)
+ result = gnutls_record_send(http->tls, buf, len);
+
+ if (result < 0 && !errno)
+ {
+ /*
+ * Convert GNU TLS error to errno value...
+ */
+
+ switch (result)
+ {
+ case GNUTLS_E_INTERRUPTED :
+ errno = EINTR;
+ break;
+
+ case GNUTLS_E_AGAIN :
+ errno = EAGAIN;
+ break;
+
+ default :
+ errno = EPIPE;
+ break;
+ }
+
+ result = -1;
+ }
+
+# elif defined(HAVE_CDSASSL)
+ OSStatus error; /* Error info */
+ size_t processed; /* Number of bytes processed */
+
+
+ error = SSLWrite(http->tls, buf, len, &processed);
+
+ switch (error)
+ {
+ case 0 :
+ result = (int)processed;
+ break;
+
+ case errSSLWouldBlock :
+ if (processed)
+ result = (int)processed;
+ else
+ {
+ result = -1;
+ errno = EINTR;
+ }
+ break;
+
+ case errSSLClosedGraceful :
+ default :
+ if (processed)
+ result = (int)processed;
+ else
+ {
+ result = -1;
+ errno = EPIPE;
+ }
+ break;
+ }
+# elif defined(HAVE_SSPISSL)
+ return _sspiWrite((_sspi_struct_t *)http->tls, (void *)buf, len);
+# endif /* HAVE_LIBSSL */
+
+ DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result));
+
+ return ((int)result);
+}
+#endif /* HAVE_SSL */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/http.h b/cups/http.h
new file mode 100644
index 000000000..e63dda113
--- /dev/null
+++ b/cups/http.h
@@ -0,0 +1,479 @@
+/*
+ * "$Id$"
+ *
+ * Hyper-Text Transport Protocol definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_HTTP_H_
+# define _CUPS_HTTP_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include "versioning.h"
+# include "array.h"
+# include <string.h>
+# include <time.h>
+# include <sys/types.h>
+# ifdef WIN32
+# ifndef __CUPS_SSIZE_T_DEFINED
+# define __CUPS_SSIZE_T_DEFINED
+/* Windows does not support the ssize_t type, so map it to off_t... */
+typedef off_t ssize_t; /* @private@ */
+# endif /* !__CUPS_SSIZE_T_DEFINED */
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# else
+# ifdef __sgi
+# define INET6 /* IRIX IPv6 support... */
+# endif /* __sgi */
+# include <unistd.h>
+# include <sys/time.h>
+# include <sys/socket.h>
+# include <netdb.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netinet/in_systm.h>
+# include <netinet/ip.h>
+# if !defined(__APPLE__) || !defined(TCP_NODELAY)
+# include <netinet/tcp.h>
+# endif /* !__APPLE__ || !TCP_NODELAY */
+# if defined(AF_UNIX) && !defined(AF_LOCAL)
+# define AF_LOCAL AF_UNIX /* Older UNIX's have old names... */
+# endif /* AF_UNIX && !AF_LOCAL */
+# ifdef AF_LOCAL
+# include <sys/un.h>
+# endif /* AF_LOCAL */
+# if defined(LOCAL_PEERCRED) && !defined(SO_PEERCRED)
+# define SO_PEERCRED LOCAL_PEERCRED
+# endif /* LOCAL_PEERCRED && !SO_PEERCRED */
+# endif /* WIN32 */
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Oh, the wonderful world of IPv6 compatibility. Apparently some
+ * implementations expose the (more logical) 32-bit address parts
+ * to everyone, while others only expose it to kernel code... To
+ * make supporting IPv6 even easier, each vendor chose different
+ * core structure and union names, so the same defines or code
+ * can't be used on all platforms.
+ *
+ * The following will likely need tweaking on new platforms that
+ * support IPv6 - the "s6_addr32" define maps to the 32-bit integer
+ * array in the in6_addr union, which is named differently on various
+ * platforms.
+ */
+
+#if defined(AF_INET6) && !defined(s6_addr32)
+# if defined(__sun)
+# define s6_addr32 _S6_un._S6_u32
+# elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)|| defined(__DragonFly__)
+# define s6_addr32 __u6_addr.__u6_addr32
+# elif defined(__osf__)
+# define s6_addr32 s6_un.sa6_laddr
+# elif defined(WIN32)
+/*
+ * Windows only defines byte and 16-bit word members of the union and
+ * requires special casing of all raw address code...
+ */
+# define s6_addr32 error_need_win32_specific_code
+# endif /* __sun */
+#endif /* AF_INET6 && !s6_addr32 */
+
+
+/*
+ * Limits...
+ */
+
+# define HTTP_MAX_URI 1024 /* Max length of URI string */
+# define HTTP_MAX_HOST 256 /* Max length of hostname string */
+# define HTTP_MAX_BUFFER 2048 /* Max length of data buffer */
+# define HTTP_MAX_VALUE 256 /* Max header field value length */
+
+
+/*
+ * Types and structures...
+ */
+
+typedef enum http_auth_e /**** HTTP authentication types ****/
+{
+ HTTP_AUTH_NONE, /* No authentication in use */
+ HTTP_AUTH_BASIC, /* Basic authentication in use */
+ HTTP_AUTH_MD5, /* Digest authentication in use */
+ HTTP_AUTH_MD5_SESS, /* MD5-session authentication in use */
+ HTTP_AUTH_MD5_INT, /* Digest authentication in use for body */
+ HTTP_AUTH_MD5_SESS_INT, /* MD5-session authentication in use for body */
+ HTTP_AUTH_NEGOTIATE /* GSSAPI authentication in use @since CUPS 1.3/Mac OS X 10.5@ */
+} http_auth_t;
+
+typedef enum http_encoding_e /**** HTTP transfer encoding values ****/
+{
+ HTTP_ENCODE_LENGTH, /* Data is sent with Content-Length */
+ HTTP_ENCODE_CHUNKED, /* Data is chunked */
+ HTTP_ENCODE_FIELDS /* Sending HTTP fields */
+} http_encoding_t;
+
+typedef enum http_encryption_e /**** HTTP encryption values ****/
+{
+ HTTP_ENCRYPT_IF_REQUESTED, /* Encrypt if requested (TLS upgrade) */
+ HTTP_ENCRYPT_NEVER, /* Never encrypt */
+ HTTP_ENCRYPT_REQUIRED, /* Encryption is required (TLS upgrade) */
+ HTTP_ENCRYPT_ALWAYS /* Always encrypt (SSL) */
+} http_encryption_t;
+
+typedef enum http_field_e /**** HTTP field names ****/
+{
+ HTTP_FIELD_UNKNOWN = -1, /* Unknown field */
+ HTTP_FIELD_ACCEPT_LANGUAGE, /* Accept-Language field */
+ HTTP_FIELD_ACCEPT_RANGES, /* Accept-Ranges field */
+ HTTP_FIELD_AUTHORIZATION, /* Authorization field */
+ HTTP_FIELD_CONNECTION, /* Connection field */
+ HTTP_FIELD_CONTENT_ENCODING, /* Content-Encoding field */
+ HTTP_FIELD_CONTENT_LANGUAGE, /* Content-Language field */
+ HTTP_FIELD_CONTENT_LENGTH, /* Content-Length field */
+ HTTP_FIELD_CONTENT_LOCATION, /* Content-Location field */
+ HTTP_FIELD_CONTENT_MD5, /* Content-MD5 field */
+ HTTP_FIELD_CONTENT_RANGE, /* Content-Range field */
+ HTTP_FIELD_CONTENT_TYPE, /* Content-Type field */
+ HTTP_FIELD_CONTENT_VERSION, /* Content-Version field */
+ HTTP_FIELD_DATE, /* Date field */
+ HTTP_FIELD_HOST, /* Host field */
+ HTTP_FIELD_IF_MODIFIED_SINCE, /* If-Modified-Since field */
+ HTTP_FIELD_IF_UNMODIFIED_SINCE, /* If-Unmodified-Since field */
+ HTTP_FIELD_KEEP_ALIVE, /* Keep-Alive field */
+ HTTP_FIELD_LAST_MODIFIED, /* Last-Modified field */
+ HTTP_FIELD_LINK, /* Link field */
+ HTTP_FIELD_LOCATION, /* Location field */
+ HTTP_FIELD_RANGE, /* Range field */
+ HTTP_FIELD_REFERER, /* Referer field */
+ HTTP_FIELD_RETRY_AFTER, /* Retry-After field */
+ HTTP_FIELD_TRANSFER_ENCODING, /* Transfer-Encoding field */
+ HTTP_FIELD_UPGRADE, /* Upgrade field */
+ HTTP_FIELD_USER_AGENT, /* User-Agent field */
+ HTTP_FIELD_WWW_AUTHENTICATE, /* WWW-Authenticate field */
+ HTTP_FIELD_MAX /* Maximum field index */
+} http_field_t;
+
+typedef enum http_keepalive_e /**** HTTP keep-alive values ****/
+{
+ HTTP_KEEPALIVE_OFF = 0, /* No keep alive support */
+ HTTP_KEEPALIVE_ON /* Use keep alive */
+} http_keepalive_t;
+
+typedef enum http_state_e /**** HTTP state values; states
+ **** are server-oriented...
+ ****/
+{
+ HTTP_WAITING, /* Waiting for command */
+ HTTP_OPTIONS, /* OPTIONS command, waiting for blank line */
+ HTTP_GET, /* GET command, waiting for blank line */
+ HTTP_GET_SEND, /* GET command, sending data */
+ HTTP_HEAD, /* HEAD command, waiting for blank line */
+ HTTP_POST, /* POST command, waiting for blank line */
+ HTTP_POST_RECV, /* POST command, receiving data */
+ HTTP_POST_SEND, /* POST command, sending data */
+ HTTP_PUT, /* PUT command, waiting for blank line */
+ HTTP_PUT_RECV, /* PUT command, receiving data */
+ HTTP_DELETE, /* DELETE command, waiting for blank line */
+ HTTP_TRACE, /* TRACE command, waiting for blank line */
+ HTTP_CLOSE, /* CLOSE command, waiting for blank line */
+ HTTP_STATUS /* Command complete, sending status */
+} http_state_t;
+
+typedef enum http_status_e /**** HTTP status codes ****/
+{
+ HTTP_ERROR = -1, /* An error response from httpXxxx() */
+
+ HTTP_CONTINUE = 100, /* Everything OK, keep going... */
+ HTTP_SWITCHING_PROTOCOLS, /* HTTP upgrade to TLS/SSL */
+
+ HTTP_OK = 200, /* OPTIONS/GET/HEAD/POST/TRACE command was successful */
+ HTTP_CREATED, /* PUT command was successful */
+ HTTP_ACCEPTED, /* DELETE command was successful */
+ HTTP_NOT_AUTHORITATIVE, /* Information isn't authoritative */
+ HTTP_NO_CONTENT, /* Successful command, no new data */
+ HTTP_RESET_CONTENT, /* Content was reset/recreated */
+ HTTP_PARTIAL_CONTENT, /* Only a partial file was recieved/sent */
+
+ HTTP_MULTIPLE_CHOICES = 300, /* Multiple files match request */
+ HTTP_MOVED_PERMANENTLY, /* Document has moved permanently */
+ HTTP_MOVED_TEMPORARILY, /* Document has moved temporarily */
+ HTTP_SEE_OTHER, /* See this other link... */
+ HTTP_NOT_MODIFIED, /* File not modified */
+ HTTP_USE_PROXY, /* Must use a proxy to access this URI */
+
+ HTTP_BAD_REQUEST = 400, /* Bad request */
+ HTTP_UNAUTHORIZED, /* Unauthorized to access host */
+ HTTP_PAYMENT_REQUIRED, /* Payment required */
+ HTTP_FORBIDDEN, /* Forbidden to access this URI */
+ HTTP_NOT_FOUND, /* URI was not found */
+ HTTP_METHOD_NOT_ALLOWED, /* Method is not allowed */
+ HTTP_NOT_ACCEPTABLE, /* Not Acceptable */
+ HTTP_PROXY_AUTHENTICATION, /* Proxy Authentication is Required */
+ HTTP_REQUEST_TIMEOUT, /* Request timed out */
+ HTTP_CONFLICT, /* Request is self-conflicting */
+ HTTP_GONE, /* Server has gone away */
+ HTTP_LENGTH_REQUIRED, /* A content length or encoding is required */
+ HTTP_PRECONDITION, /* Precondition failed */
+ HTTP_REQUEST_TOO_LARGE, /* Request entity too large */
+ HTTP_URI_TOO_LONG, /* URI too long */
+ HTTP_UNSUPPORTED_MEDIATYPE, /* The requested media type is unsupported */
+ HTTP_REQUESTED_RANGE, /* The requested range is not satisfiable */
+ HTTP_EXPECTATION_FAILED, /* The expectation given in an Expect header field was not met */
+ HTTP_UPGRADE_REQUIRED = 426, /* Upgrade to SSL/TLS required */
+
+ HTTP_SERVER_ERROR = 500, /* Internal server error */
+ HTTP_NOT_IMPLEMENTED, /* Feature not implemented */
+ HTTP_BAD_GATEWAY, /* Bad gateway */
+ HTTP_SERVICE_UNAVAILABLE, /* Service is unavailable */
+ HTTP_GATEWAY_TIMEOUT, /* Gateway connection timed out */
+ HTTP_NOT_SUPPORTED, /* HTTP version not supported */
+
+ HTTP_AUTHORIZATION_CANCELED = 1000, /* User canceled authorization @since CUPS 1.4@ */
+ HTTP_PKI_ERROR, /* Error negotiating a secure connection @since CUPS 1.5/Mac OS X 10.7@ */
+ HTTP_WEBIF_DISABLED /* Web interface is disabled @private@ */
+} http_status_t;
+
+typedef enum http_uri_status_e /**** URI separation status @since CUPS 1.2@ ****/
+{
+ HTTP_URI_OVERFLOW = -8, /* URI buffer for httpAssembleURI is too small */
+ HTTP_URI_BAD_ARGUMENTS = -7, /* Bad arguments to function (error) */
+ HTTP_URI_BAD_RESOURCE = -6, /* Bad resource in URI (error) */
+ HTTP_URI_BAD_PORT = -5, /* Bad port number in URI (error) */
+ HTTP_URI_BAD_HOSTNAME = -4, /* Bad hostname in URI (error) */
+ HTTP_URI_BAD_USERNAME = -3, /* Bad username in URI (error) */
+ HTTP_URI_BAD_SCHEME = -2, /* Bad scheme in URI (error) */
+ HTTP_URI_BAD_URI = -1, /* Bad/empty URI (error) */
+ HTTP_URI_OK = 0, /* URI decoded OK */
+ HTTP_URI_MISSING_SCHEME, /* Missing scheme in URI (warning) */
+ HTTP_URI_UNKNOWN_SCHEME, /* Unknown scheme in URI (warning) */
+ HTTP_URI_MISSING_RESOURCE /* Missing resource in URI (warning) */
+} http_uri_status_t;
+
+typedef enum http_uri_coding_e /**** URI en/decode flags ****/
+{
+ HTTP_URI_CODING_NONE = 0, /* Don't en/decode anything */
+ HTTP_URI_CODING_USERNAME = 1, /* En/decode the username portion */
+ HTTP_URI_CODING_HOSTNAME = 2, /* En/decode the hostname portion */
+ HTTP_URI_CODING_RESOURCE = 4, /* En/decode the resource portion */
+ HTTP_URI_CODING_MOST = 7, /* En/decode all but the query */
+ HTTP_URI_CODING_QUERY = 8, /* En/decode the query portion */
+ HTTP_URI_CODING_ALL = 15 /* En/decode everything */
+} http_uri_coding_t;
+
+typedef enum http_version_e /**** HTTP version numbers ****/
+{
+ HTTP_0_9 = 9, /* HTTP/0.9 */
+ HTTP_1_0 = 100, /* HTTP/1.0 */
+ HTTP_1_1 = 101 /* HTTP/1.1 */
+} http_version_t;
+
+typedef union _http_addr_u /**** Socket address union, which
+ **** makes using IPv6 and other
+ **** address types easier and
+ **** more portable. @since CUPS 1.2/Mac OS X 10.5@
+ ****/
+{
+ struct sockaddr addr; /* Base structure for family value */
+ struct sockaddr_in ipv4; /* IPv4 address */
+#ifdef AF_INET6
+ struct sockaddr_in6 ipv6; /* IPv6 address */
+#endif /* AF_INET6 */
+#ifdef AF_LOCAL
+ struct sockaddr_un un; /* Domain socket file */
+#endif /* AF_LOCAL */
+ char pad[256]; /* Padding to ensure binary compatibility */
+} http_addr_t;
+
+typedef struct http_addrlist_s /**** Socket address list, which is
+ **** used to enumerate all of the
+ **** addresses that are associated
+ **** with a hostname. @since CUPS 1.2/Mac OS X 10.5@
+ ****/
+{
+ struct http_addrlist_s *next; /* Pointer to next address in list */
+ http_addr_t addr; /* Address */
+} http_addrlist_t;
+
+typedef struct _http_s http_t; /**** HTTP connection type ****/
+
+typedef struct http_credential_s /**** HTTP credential data @since CUPS 1.5/Mac OS X 10.7@ ****/
+{
+ void *data; /* Pointer to credential data */
+ size_t datalen; /* Credential length */
+} http_credential_t;
+
+typedef int (*http_timeout_cb_t)(http_t *http, void *user_data);
+ /**** HTTP timeout callback @since CUPS 1.5/Mac OS X 10.7@ ****/
+
+
+
+/*
+ * Prototypes...
+ */
+
+extern void httpBlocking(http_t *http, int b);
+extern int httpCheck(http_t *http);
+extern void httpClearFields(http_t *http);
+extern void httpClose(http_t *http);
+extern http_t *httpConnect(const char *host, int port);
+extern http_t *httpConnectEncrypt(const char *host, int port,
+ http_encryption_t encryption);
+extern int httpDelete(http_t *http, const char *uri);
+extern int httpEncryption(http_t *http, http_encryption_t e);
+extern int httpError(http_t *http);
+extern void httpFlush(http_t *http);
+extern int httpGet(http_t *http, const char *uri);
+extern char *httpGets(char *line, int length, http_t *http);
+extern const char *httpGetDateString(time_t t);
+extern time_t httpGetDateTime(const char *s);
+extern const char *httpGetField(http_t *http, http_field_t field);
+extern struct hostent *httpGetHostByName(const char *name);
+extern char *httpGetSubField(http_t *http, http_field_t field,
+ const char *name, char *value);
+extern int httpHead(http_t *http, const char *uri);
+extern void httpInitialize(void);
+extern int httpOptions(http_t *http, const char *uri);
+extern int httpPost(http_t *http, const char *uri);
+extern int httpPrintf(http_t *http, const char *format, ...)
+# ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+# endif /* __GNUC__ */
+;
+extern int httpPut(http_t *http, const char *uri);
+extern int httpRead(http_t *http, char *buffer, int length) _CUPS_DEPRECATED;
+extern int httpReconnect(http_t *http);
+extern void httpSeparate(const char *uri, char *method,
+ char *username, char *host, int *port,
+ char *resource) _CUPS_DEPRECATED;
+extern void httpSetField(http_t *http, http_field_t field,
+ const char *value);
+extern const char *httpStatus(http_status_t status);
+extern int httpTrace(http_t *http, const char *uri);
+extern http_status_t httpUpdate(http_t *http);
+extern int httpWrite(http_t *http, const char *buffer, int length) _CUPS_DEPRECATED;
+extern char *httpEncode64(char *out, const char *in) _CUPS_DEPRECATED;
+extern char *httpDecode64(char *out, const char *in) _CUPS_DEPRECATED;
+extern int httpGetLength(http_t *http) _CUPS_DEPRECATED;
+extern char *httpMD5(const char *, const char *, const char *,
+ char [33]);
+extern char *httpMD5Final(const char *, const char *, const char *,
+ char [33]);
+extern char *httpMD5String(const unsigned char *, char [33]);
+
+/**** New in CUPS 1.1.19 ****/
+extern void httpClearCookie(http_t *http) _CUPS_API_1_1_19;
+extern const char *httpGetCookie(http_t *http) _CUPS_API_1_1_19;
+extern void httpSetCookie(http_t *http, const char *cookie) _CUPS_API_1_1_19;
+extern int httpWait(http_t *http, int msec) _CUPS_API_1_1_19;
+
+/**** New in CUPS 1.1.21 ****/
+extern char *httpDecode64_2(char *out, int *outlen, const char *in) _CUPS_API_1_1_21;
+extern char *httpEncode64_2(char *out, int outlen, const char *in,
+ int inlen) _CUPS_API_1_1_21;
+extern void httpSeparate2(const char *uri,
+ char *method, int methodlen,
+ char *username, int usernamelen,
+ char *host, int hostlen, int *port,
+ char *resource, int resourcelen) _CUPS_DEPRECATED;
+
+/**** New in CUPS 1.2/Mac OS X 10.5 ****/
+extern int httpAddrAny(const http_addr_t *addr) _CUPS_API_1_2;
+extern http_addrlist_t *httpAddrConnect(http_addrlist_t *addrlist, int *sock) _CUPS_API_1_2;
+extern int httpAddrEqual(const http_addr_t *addr1,
+ const http_addr_t *addr2) _CUPS_API_1_2;
+extern void httpAddrFreeList(http_addrlist_t *addrlist) _CUPS_API_1_2;
+extern http_addrlist_t *httpAddrGetList(const char *hostname, int family,
+ const char *service) _CUPS_API_1_2;
+extern int httpAddrLength(const http_addr_t *addr) _CUPS_API_1_2;
+extern int httpAddrLocalhost(const http_addr_t *addr) _CUPS_API_1_2;
+extern char *httpAddrLookup(const http_addr_t *addr,
+ char *name, int namelen) _CUPS_API_1_2;
+extern char *httpAddrString(const http_addr_t *addr,
+ char *s, int slen) _CUPS_API_1_2;
+extern http_uri_status_t httpAssembleURI(http_uri_coding_t encoding,
+ char *uri, int urilen,
+ const char *scheme,
+ const char *username,
+ const char *host, int port,
+ const char *resource) _CUPS_API_1_2;
+extern http_uri_status_t httpAssembleURIf(http_uri_coding_t encoding,
+ char *uri, int urilen,
+ const char *scheme,
+ const char *username,
+ const char *host, int port,
+ const char *resourcef, ...) _CUPS_API_1_2;
+extern int httpFlushWrite(http_t *http) _CUPS_API_1_2;
+extern int httpGetBlocking(http_t *http) _CUPS_API_1_2;
+extern const char *httpGetDateString2(time_t t, char *s, int slen) _CUPS_API_1_2;
+extern int httpGetFd(http_t *http) _CUPS_API_1_2;
+extern const char *httpGetHostname(http_t *http, char *s, int slen) _CUPS_API_1_2;
+extern off_t httpGetLength2(http_t *http) _CUPS_API_1_2;
+extern http_status_t httpGetStatus(http_t *http) _CUPS_API_1_2;
+extern char *httpGetSubField2(http_t *http, http_field_t field,
+ const char *name, char *value,
+ int valuelen) _CUPS_API_1_2;
+extern ssize_t httpRead2(http_t *http, char *buffer, size_t length) _CUPS_API_1_2;
+extern http_uri_status_t httpSeparateURI(http_uri_coding_t decoding,
+ const char *uri,
+ char *scheme, int schemelen,
+ char *username, int usernamelen,
+ char *host, int hostlen, int *port,
+ char *resource, int resourcelen) _CUPS_API_1_2;
+extern void httpSetExpect(http_t *http, http_status_t expect) _CUPS_API_1_2;
+extern void httpSetLength(http_t *http, size_t length) _CUPS_API_1_2;
+extern ssize_t httpWrite2(http_t *http, const char *buffer,
+ size_t length) _CUPS_API_1_2;
+
+/**** New in CUPS 1.3/Mac OS X 10.5 ****/
+extern char *httpGetAuthString(http_t *http) _CUPS_API_1_3;
+extern void httpSetAuthString(http_t *http, const char *scheme,
+ const char *data) _CUPS_API_1_3;
+
+/**** New in CUPS 1.5/Mac OS X 10.7 ****/
+extern int httpAddCredential(cups_array_t *credentials,
+ const void *data, size_t datalen)
+ _CUPS_API_1_5;
+extern int httpCopyCredentials(http_t *http,
+ cups_array_t **credentials)
+ _CUPS_API_1_5;
+extern void httpFreeCredentials(cups_array_t *certs) _CUPS_API_1_5;
+extern int httpSetCredentials(http_t *http, cups_array_t *certs)
+ _CUPS_API_1_5;
+extern void httpSetTimeout(http_t *http, double timeout,
+ http_timeout_cb_t cb, void *user_data);
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_HTTP_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/ipp-private.h b/cups/ipp-private.h
new file mode 100644
index 000000000..8a473c110
--- /dev/null
+++ b/cups/ipp-private.h
@@ -0,0 +1,87 @@
+/*
+ * "$Id$"
+ *
+ * Private IPP definitions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_IPP_PRIVATE_H_
+# define _CUPS_IPP_PRIVATE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include <cups/ipp.h>
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Constants...
+ */
+
+# define IPP_BUF_SIZE (IPP_MAX_LENGTH + 2)
+ /* Size of buffer */
+
+
+/*
+ * Structures...
+ */
+
+typedef struct _ipp_buffer_s /**** Read/write buffer ****/
+{
+ unsigned char d[IPP_BUF_SIZE];/* Data buffer */
+ struct _ipp_buffer_s *next; /* Next buffer in list */
+ int used; /* Is this buffer used? */
+} _ipp_buffer_t;
+
+typedef struct /**** Attribute mapping data ****/
+{
+ int multivalue; /* Option has multiple values? */
+ const char *name; /* Option/attribute name */
+ ipp_tag_t value_tag; /* Value tag for this attribute */
+ ipp_tag_t group_tag; /* Group tag for this attribute */
+} _ipp_option_t;
+
+
+/*
+ * Prototypes for private functions...
+ */
+
+extern ipp_attribute_t *_ippAddAttr(ipp_t *ipp, int num_values);
+extern size_t _ippAttrString(ipp_attribute_t *attr, char *buffer,
+ size_t bufsize);
+extern _ipp_option_t *_ippFindOption(const char *name);
+extern void _ippFreeAttr(ipp_attribute_t *attr);
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_IPP_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/ipp-support.c b/cups/ipp-support.c
new file mode 100644
index 000000000..8770619da
--- /dev/null
+++ b/cups/ipp-support.c
@@ -0,0 +1,813 @@
+/*
+ * "$Id$"
+ *
+ * Internet Printing Protocol support functions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _ippAttrString() - Convert the attribute's value to a string.
+ * ippErrorString() - Return a name for the given status code.
+ * ippErrorValue() - Return a status code for the given name.
+ * ippOpString() - Return a name for the given operation id.
+ * ippOpValue() - Return an operation id for the given name.
+ * ippPort() - Return the default IPP port number.
+ * ippSetPort() - Set the default port number.
+ * ippTagString() - Return the tag name corresponding to a tag value.
+ * ippTagValue() - Return the tag value corresponding to a tag name.
+ * ipp_col_string() - Convert a collection to a string.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+
+
+/*
+ * Local globals...
+ */
+
+static const char * const ipp_status_oks[] = /* "OK" status codes */
+ {
+ "successful-ok",
+ "successful-ok-ignored-or-substituted-attributes",
+ "successful-ok-conflicting-attributes",
+ "successful-ok-ignored-subscriptions",
+ "successful-ok-ignored-notifications",
+ "successful-ok-too-many-events",
+ "successful-ok-but-cancel-subscription",
+ "successful-ok-events-complete"
+ },
+ * const ipp_status_400s[] = /* Client errors */
+ {
+ "client-error-bad-request",
+ "client-error-forbidden",
+ "client-error-not-authenticated",
+ "client-error-not-authorized",
+ "client-error-not-possible",
+ "client-error-timeout",
+ "client-error-not-found",
+ "client-error-gone",
+ "client-error-request-entity-too-large",
+ "client-error-request-value-too-long",
+ "client-error-document-format-not-supported",
+ "client-error-attributes-or-values-not-supported",
+ "client-error-uri-scheme-not-supported",
+ "client-error-charset-not-supported",
+ "client-error-conflicting-attributes",
+ "client-error-compression-not-supported",
+ "client-error-compression-error",
+ "client-error-document-format-error",
+ "client-error-document-access-error",
+ "client-error-attributes-not-settable",
+ "client-error-ignored-all-subscriptions",
+ "client-error-too-many-subscriptions",
+ "client-error-ignored-all-notifications",
+ "client-error-print-support-file-not-found"
+ },
+ * const ipp_status_500s[] = /* Server errors */
+ {
+ "server-error-internal-error",
+ "server-error-operation-not-supported",
+ "server-error-service-unavailable",
+ "server-error-version-not-supported",
+ "server-error-device-error",
+ "server-error-temporary-error",
+ "server-error-not-accepting-jobs",
+ "server-error-busy",
+ "server-error-job-canceled",
+ "server-error-multiple-document-jobs-not-supported",
+ "server-error-printer-is-deactivated"
+ },
+ * const ipp_status_1000s[] = /* CUPS internal */
+ {
+ "cups-authorization-canceled",
+ "cups-pki-error",
+ "cups-upgrade-required"
+ };
+static char * const ipp_std_ops[] =
+ {
+ /* 0x0000 - 0x000f */
+ "unknown-00",
+ "unknown-01",
+ "Print-Job",
+ "Print-URI",
+ "Validate-Job",
+ "Create-Job",
+ "Send-Document",
+ "Send-URI",
+ "Cancel-Job",
+ "Get-Job-Attributes",
+ "Get-Jobs",
+ "Get-Printer-Attributes",
+ "Hold-Job",
+ "Release-Job",
+ "Restart-Job",
+ "unknown-0f",
+
+ /* 0x0010 - 0x001f */
+ "Pause-Printer",
+ "Resume-Printer",
+ "Purge-Jobs",
+ "Set-Printer-Attributes",
+ "Set-Job-Attributes",
+ "Get-Printer-Supported-Values",
+ "Create-Printer-Subscription",
+ "Create-Job-Subscription",
+ "Get-Subscription-Attributes",
+ "Get-Subscriptions",
+ "Renew-Subscription",
+ "Cancel-Subscription",
+ "Get-Notifications",
+ "Send-Notifications",
+ "unknown-1e",
+ "unknown-1f",
+
+ /* 0x0020 - 0x002f */
+ "unknown-20",
+ "Get-Printer-Support-Files",
+ "Enable-Printer",
+ "Disable-Printer",
+ "Pause-Printer-After-Current-Job",
+ "Hold-New-Jobs",
+ "Release-Held-New-Jobs",
+ "Deactivate-Printer",
+ "Activate-Printer",
+ "Restart-Printer",
+ "Shutdown-Printer",
+ "Startup-Printer",
+ "Reprocess-Job",
+ "Cancel-Current-Job",
+ "Suspend-Current-Job",
+ "Resume-Job",
+
+ /* 0x0030 - 0x003b */
+ "Promote-Job",
+ "Schedule-Job-After",
+ "unknown-32",
+ "Cancel-Document",
+ "Get-Document-Attributes",
+ "Get-Documents",
+ "Delete-Document",
+ "Set-Document-Attributes",
+ "Cancel-Jobs",
+ "Cancel-My-Jobs",
+ "Resubmit-Job",
+ "Close-Job"
+ },
+ * const ipp_cups_ops[] =
+ {
+ "CUPS-Get-Default",
+ "CUPS-Get-Printers",
+ "CUPS-Add-Modify-Printer",
+ "CUPS-Delete-Printer",
+ "CUPS-Get-Classes",
+ "CUPS-Add-Modify-Class",
+ "CUPS-Delete-Class",
+ "CUPS-Accept-Jobs",
+ "CUPS-Reject-Jobs",
+ "CUPS-Set-Default",
+ "CUPS-Get-Devices",
+ "CUPS-Get-PPDs",
+ "CUPS-Move-Job",
+ "CUPS-Authenticate-Job",
+ "CUPS-Get-PPD"
+ },
+ * const ipp_cups_ops2[] =
+ {
+ "CUPS-Get-Document"
+ },
+ * const ipp_tag_names[] =
+ { /* Value/group tag names */
+ "zero", /* 0x00 */
+ "operation-attributes-tag",
+ /* 0x01 */
+ "job-attributes-tag", /* 0x02 */
+ "end-of-attributes-tag",
+ /* 0x03 */
+ "printer-attributes-tag",
+ /* 0x04 */
+ "unsupported-attributes-tag",
+ /* 0x05 */
+ "subscription-attributes-tag",
+ /* 0x06 */
+ "event-notification-attributes-tag",
+ /* 0x07 */
+ "unknown-08", /* 0x08 */
+ "unknown-09", /* 0x09 */
+ "unknown-0a", /* 0x0a */
+ "unknown-0b", /* 0x0b */
+ "unknown-0c", /* 0x0c */
+ "unknown-0d", /* 0x0d */
+ "unknown-0e", /* 0x0e */
+ "unknown-0f", /* 0x0f */
+ "unsupported", /* 0x10 */
+ "default", /* 0x11 */
+ "unknown", /* 0x12 */
+ "no-value", /* 0x13 */
+ "unknown-14", /* 0x14 */
+ "not-settable", /* 0x15 */
+ "delete-attribute", /* 0x16 */
+ "admin-define", /* 0x17 */
+ "unknown-18", /* 0x18 */
+ "unknown-19", /* 0x19 */
+ "unknown-1a", /* 0x1a */
+ "unknown-1b", /* 0x1b */
+ "unknown-1c", /* 0x1c */
+ "unknown-1d", /* 0x1d */
+ "unknown-1e", /* 0x1e */
+ "unknown-1f", /* 0x1f */
+ "unknown-20", /* 0x20 */
+ "integer", /* 0x21 */
+ "boolean", /* 0x22 */
+ "enum", /* 0x23 */
+ "unknown-24", /* 0x24 */
+ "unknown-25", /* 0x25 */
+ "unknown-26", /* 0x26 */
+ "unknown-27", /* 0x27 */
+ "unknown-28", /* 0x28 */
+ "unknown-29", /* 0x29 */
+ "unknown-2a", /* 0x2a */
+ "unknown-2b", /* 0x2b */
+ "unknown-2c", /* 0x2c */
+ "unknown-2d", /* 0x2d */
+ "unknown-2e", /* 0x2e */
+ "unknown-2f", /* 0x2f */
+ "octetString", /* 0x30 */
+ "dateTime", /* 0x31 */
+ "resolution", /* 0x32 */
+ "rangeOfInteger", /* 0x33 */
+ "collection", /* 0x34 */
+ "textWithLanguage", /* 0x35 */
+ "nameWithLanguage", /* 0x36 */
+ "endCollection", /* 0x37 */
+ "unknown-38", /* 0x38 */
+ "unknown-39", /* 0x39 */
+ "unknown-3a", /* 0x3a */
+ "unknown-3b", /* 0x3b */
+ "unknown-3c", /* 0x3c */
+ "unknown-3d", /* 0x3d */
+ "unknown-3e", /* 0x3e */
+ "unknown-3f", /* 0x3f */
+ "unknown-40", /* 0x40 */
+ "textWithoutLanguage",/* 0x41 */
+ "nameWithoutLanguage",/* 0x42 */
+ "unknown-43", /* 0x43 */
+ "keyword", /* 0x44 */
+ "uri", /* 0x45 */
+ "uriScheme", /* 0x46 */
+ "charset", /* 0x47 */
+ "naturalLanguage", /* 0x48 */
+ "mimeMediaType", /* 0x49 */
+ "memberAttrName" /* 0x4a */
+ };
+static const char * const job_states[] =
+{ /* job-state enums */
+ "pending",
+ "pending-held",
+ "processing",
+ "processing-stopped",
+ "canceled",
+ "aborted",
+ "completed"
+};
+static const char * const printer_states[] =
+{ /* printer-state enums */
+ "idle",
+ "processing",
+ "stopped",
+};
+
+
+/*
+ * Local functions...
+ */
+
+static size_t ipp_col_string(ipp_t *col, char *buffer, size_t bufsize);
+
+
+/*
+ * '_ippAttrString()' - Convert the attribute's value to a string.
+ *
+ * Returns the number of bytes that would be written, not including the
+ * trailing nul. The buffer pointer can be NULL to get the required length,
+ * just like (v)snprintf.
+ */
+
+size_t /* O - Number of bytes less nul */
+_ippAttrString(ipp_attribute_t *attr, /* I - Attribute */
+ char *buffer, /* I - String buffer or NULL */
+ size_t bufsize) /* I - Size of string buffer */
+{
+ int i; /* Looping var */
+ char *bufptr, /* Pointer into buffer */
+ *bufend, /* End of buffer */
+ temp[256]; /* Temporary string */
+ const char *ptr; /* Pointer into string */
+ ipp_value_t *val; /* Current value */
+
+
+ if (!attr || !attr->name)
+ {
+ if (buffer)
+ *buffer = '\0';
+
+ return (0);
+ }
+
+ bufptr = buffer;
+ if (buffer)
+ bufend = buffer + bufsize - 1;
+ else
+ bufend = NULL;
+
+ for (i = attr->num_values, val = attr->values; i > 0; i --, val ++)
+ {
+ if (val > attr->values)
+ {
+ if (buffer && bufptr < bufend)
+ *bufptr++ = ',';
+ else
+ bufptr ++;
+ }
+
+ switch (attr->value_tag & ~IPP_TAG_COPY)
+ {
+ case IPP_TAG_ENUM :
+ if (!strcmp(attr->name, "printer-state") &&
+ val->integer >= IPP_PRINTER_IDLE &&
+ val->integer <= IPP_PRINTER_STOPPED)
+ {
+ ptr = printer_states[val->integer - IPP_PRINTER_IDLE];
+
+ if (buffer && bufptr < bufend)
+ strlcpy(bufptr, ptr, bufend - bufptr + 1);
+
+ bufptr += strlen(ptr);
+ break;
+ }
+ else if (!strcmp(attr->name, "job-state") &&
+ val->integer >= IPP_JOB_PENDING &&
+ val->integer <= IPP_JOB_COMPLETED)
+ {
+ ptr = job_states[val->integer - IPP_JOB_PENDING];
+
+ if (buffer && bufptr < bufend)
+ strlcpy(bufptr, ptr, bufend - bufptr + 1);
+
+ bufptr += strlen(ptr);
+ break;
+ }
+
+ case IPP_TAG_INTEGER :
+ if (buffer && bufptr < bufend)
+ bufptr += snprintf(bufptr, bufend - bufptr + 1, "%d", val->integer);
+ else
+ bufptr += snprintf(temp, sizeof(temp), "%d", val->integer);
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ if (buffer && bufptr < bufend)
+ strlcpy(bufptr, val->boolean ? "true" : "false",
+ bufend - bufptr + 1);
+
+ bufptr += val->boolean ? 4 : 5;
+ break;
+
+ case IPP_TAG_RANGE :
+ if (buffer && bufptr < bufend)
+ bufptr += snprintf(bufptr, bufend - bufptr + 1, "%d-%d",
+ val->range.lower, val->range.upper);
+ else
+ bufptr += snprintf(temp, sizeof(temp), "%d-%d", val->range.lower,
+ val->range.upper);
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ if (buffer && bufptr < bufend)
+ bufptr += snprintf(bufptr, bufend - bufptr + 1, "%dx%d%s",
+ val->resolution.xres, val->resolution.yres,
+ val->resolution.units == IPP_RES_PER_INCH ?
+ "dpi" : "dpc");
+ else
+ bufptr += snprintf(temp, sizeof(temp), "%dx%d%s",
+ val->resolution.xres, val->resolution.yres,
+ val->resolution.units == IPP_RES_PER_INCH ?
+ "dpi" : "dpc");
+ break;
+
+ case IPP_TAG_DATE :
+ {
+ unsigned year; /* Year */
+
+ year = (val->date[0] << 8) + val->date[1];
+
+ if (val->date[9] == 0 && val->date[10] == 0)
+ snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02uZ",
+ year, val->date[2], val->date[3], val->date[4],
+ val->date[5], val->date[6]);
+ else
+ snprintf(temp, sizeof(temp),
+ "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u",
+ year, val->date[2], val->date[3], val->date[4],
+ val->date[5], val->date[6], val->date[8], val->date[9],
+ val->date[10]);
+
+ if (buffer && bufptr < bufend)
+ strlcpy(bufptr, temp, bufend - bufptr + 1);
+
+ bufptr += strlen(temp);
+ }
+ break;
+
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_URI :
+ case IPP_TAG_MIMETYPE :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ if (!val->string.text)
+ break;
+
+ for (ptr = val->string.text; *ptr; ptr ++)
+ {
+ if (*ptr == '\\' || *ptr == '\"')
+ {
+ if (buffer && bufptr < bufend)
+ *bufptr = '\\';
+ bufptr ++;
+ }
+
+ if (buffer && bufptr < bufend)
+ *bufptr = *ptr;
+ bufptr ++;
+ }
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ if (buffer && bufptr < bufend)
+ bufptr += ipp_col_string(val->collection, bufptr,
+ bufend - bufptr + 1);
+ else
+ bufptr += ipp_col_string(val->collection, NULL, 0);
+ break;
+
+ case IPP_TAG_STRING :
+ for (ptr = val->string.text; *ptr; ptr ++)
+ {
+ if (*ptr == '\\' || _cups_isspace(*ptr))
+ {
+ if (buffer && bufptr < bufend)
+ *bufptr = '\\';
+ bufptr ++;
+
+ if (buffer && bufptr < bufend)
+ *bufptr = *ptr;
+ bufptr ++;
+ }
+ else if (!isprint(*ptr & 255))
+ {
+ if (buffer && bufptr < bufend)
+ bufptr += snprintf(bufptr, bufend - bufptr + 1, "\\%03o",
+ *ptr & 255);
+ else
+ bufptr += snprintf(temp, sizeof(temp), "\\%03o",
+ *ptr & 255);
+ }
+ else
+ {
+ if (buffer && bufptr < bufend)
+ *bufptr = *ptr;
+ bufptr ++;
+ }
+ }
+ break;
+
+ default :
+ ptr = ippTagString(attr->value_tag);
+ if (buffer && bufptr < bufend)
+ strlcpy(bufptr, ptr, bufend - bufptr + 1);
+ bufptr += strlen(ptr);
+ break;
+ }
+ }
+
+ if (buffer && bufptr < bufend)
+ *bufptr = '\0';
+ else if (bufend)
+ *bufend = '\0';
+
+ return (bufptr - buffer);
+}
+
+
+/*
+ * 'ippErrorString()' - Return a name for the given status code.
+ */
+
+const char * /* O - Text string */
+ippErrorString(ipp_status_t error) /* I - Error status */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ /*
+ * See if the error code is a known value...
+ */
+
+ if (error >= IPP_OK && error <= IPP_OK_EVENTS_COMPLETE)
+ return (ipp_status_oks[error]);
+ else if (error == IPP_REDIRECTION_OTHER_SITE)
+ return ("redirection-other-site");
+ else if (error == CUPS_SEE_OTHER)
+ return ("cups-see-other");
+ else if (error >= IPP_BAD_REQUEST && error <= IPP_PRINT_SUPPORT_FILE_NOT_FOUND)
+ return (ipp_status_400s[error - IPP_BAD_REQUEST]);
+ else if (error >= IPP_INTERNAL_ERROR && error <= IPP_PRINTER_IS_DEACTIVATED)
+ return (ipp_status_500s[error - IPP_INTERNAL_ERROR]);
+ else if (error >= IPP_AUTHENTICATION_CANCELED && error <= IPP_UPGRADE_REQUIRED)
+ return (ipp_status_1000s[error - IPP_AUTHENTICATION_CANCELED]);
+
+ /*
+ * No, build an "unknown-xxxx" error string...
+ */
+
+ sprintf(cg->ipp_unknown, "unknown-%04x", error);
+
+ return (cg->ipp_unknown);
+}
+
+
+/*
+ * 'ippErrorValue()' - Return a status code for the given name.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ipp_status_t /* O - IPP status code */
+ippErrorValue(const char *name) /* I - Name */
+{
+ int i;
+
+
+ for (i = 0; i < (sizeof(ipp_status_oks) / sizeof(ipp_status_oks[0])); i ++)
+ if (!_cups_strcasecmp(name, ipp_status_oks[i]))
+ return ((ipp_status_t)i);
+
+ if (!_cups_strcasecmp(name, "redirection-other-site"))
+ return (IPP_REDIRECTION_OTHER_SITE);
+
+ if (!_cups_strcasecmp(name, "cups-see-other"))
+ return (CUPS_SEE_OTHER);
+
+ for (i = 0; i < (sizeof(ipp_status_400s) / sizeof(ipp_status_400s[0])); i ++)
+ if (!_cups_strcasecmp(name, ipp_status_400s[i]))
+ return ((ipp_status_t)(i + 0x400));
+
+ for (i = 0; i < (sizeof(ipp_status_500s) / sizeof(ipp_status_500s[0])); i ++)
+ if (!_cups_strcasecmp(name, ipp_status_500s[i]))
+ return ((ipp_status_t)(i + 0x500));
+
+ for (i = 0; i < (sizeof(ipp_status_1000s) / sizeof(ipp_status_1000s[0])); i ++)
+ if (!_cups_strcasecmp(name, ipp_status_1000s[i]))
+ return ((ipp_status_t)(i + 0x1000));
+
+ return ((ipp_status_t)-1);
+}
+
+
+/*
+ * 'ippOpString()' - Return a name for the given operation id.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+const char * /* O - Name */
+ippOpString(ipp_op_t op) /* I - Operation ID */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ /*
+ * See if the operation ID is a known value...
+ */
+
+ if (op >= IPP_PRINT_JOB && op <= IPP_CLOSE_JOB)
+ return (ipp_std_ops[op]);
+ else if (op == IPP_PRIVATE)
+ return ("windows-ext");
+ else if (op >= CUPS_GET_DEFAULT && op <= CUPS_GET_PPD)
+ return (ipp_cups_ops[op - CUPS_GET_DEFAULT]);
+ else if (op == CUPS_GET_DOCUMENT)
+ return (ipp_cups_ops2[0]);
+
+ /*
+ * No, build an "unknown-xxxx" operation string...
+ */
+
+ sprintf(cg->ipp_unknown, "unknown-%04x", op);
+
+ return (cg->ipp_unknown);
+}
+
+
+/*
+ * 'ippOpValue()' - Return an operation id for the given name.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ipp_op_t /* O - Operation ID */
+ippOpValue(const char *name) /* I - Textual name */
+{
+ int i;
+
+
+ for (i = 0; i < (sizeof(ipp_std_ops) / sizeof(ipp_std_ops[0])); i ++)
+ if (!_cups_strcasecmp(name, ipp_std_ops[i]))
+ return ((ipp_op_t)i);
+
+ if (!_cups_strcasecmp(name, "windows-ext"))
+ return (IPP_PRIVATE);
+
+ for (i = 0; i < (sizeof(ipp_cups_ops) / sizeof(ipp_cups_ops[0])); i ++)
+ if (!_cups_strcasecmp(name, ipp_cups_ops[i]))
+ return ((ipp_op_t)(i + 0x4001));
+
+ for (i = 0; i < (sizeof(ipp_cups_ops2) / sizeof(ipp_cups_ops2[0])); i ++)
+ if (!_cups_strcasecmp(name, ipp_cups_ops2[i]))
+ return ((ipp_op_t)(i + 0x4027));
+
+ if (!_cups_strcasecmp(name, "CUPS-Add-Class"))
+ return (CUPS_ADD_MODIFY_CLASS);
+
+ if (!_cups_strcasecmp(name, "CUPS-Add-Printer"))
+ return (CUPS_ADD_MODIFY_PRINTER);
+
+ return ((ipp_op_t)-1);
+}
+
+
+/*
+ * 'ippPort()' - Return the default IPP port number.
+ */
+
+int /* O - Port number */
+ippPort(void)
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ DEBUG_puts("ippPort()");
+
+ if (!cg->ipp_port)
+ _cupsSetDefaults();
+
+ DEBUG_printf(("1ippPort: Returning %d...", cg->ipp_port));
+
+ return (cg->ipp_port);
+}
+
+
+/*
+ * 'ippSetPort()' - Set the default port number.
+ */
+
+void
+ippSetPort(int p) /* I - Port number to use */
+{
+ DEBUG_printf(("ippSetPort(p=%d)", p));
+
+ _cupsGlobals()->ipp_port = p;
+}
+
+
+/*
+ * 'ippTagString()' - Return the tag name corresponding to a tag value.
+ *
+ * The returned names are defined in RFC 2911 and 3382.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+const char * /* O - Tag name */
+ippTagString(ipp_tag_t tag) /* I - Tag value */
+{
+ tag &= IPP_TAG_MASK;
+
+ if (tag < (ipp_tag_t)(sizeof(ipp_tag_names) / sizeof(ipp_tag_names[0])))
+ return (ipp_tag_names[tag]);
+ else
+ return ("UNKNOWN");
+}
+
+
+/*
+ * 'ippTagValue()' - Return the tag value corresponding to a tag name.
+ *
+ * The tag names are defined in RFC 2911 and 3382.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+ipp_tag_t /* O - Tag value */
+ippTagValue(const char *name) /* I - Tag name */
+{
+ int i; /* Looping var */
+
+
+ for (i = 0; i < (sizeof(ipp_tag_names) / sizeof(ipp_tag_names[0])); i ++)
+ if (!_cups_strcasecmp(name, ipp_tag_names[i]))
+ return ((ipp_tag_t)i);
+
+ if (!_cups_strcasecmp(name, "operation"))
+ return (IPP_TAG_OPERATION);
+ else if (!_cups_strcasecmp(name, "job"))
+ return (IPP_TAG_JOB);
+ else if (!_cups_strcasecmp(name, "printer"))
+ return (IPP_TAG_PRINTER);
+ else if (!_cups_strcasecmp(name, "unsupported"))
+ return (IPP_TAG_UNSUPPORTED_GROUP);
+ else if (!_cups_strcasecmp(name, "subscription"))
+ return (IPP_TAG_SUBSCRIPTION);
+ else if (!_cups_strcasecmp(name, "event"))
+ return (IPP_TAG_EVENT_NOTIFICATION);
+ else if (!_cups_strcasecmp(name, "language"))
+ return (IPP_TAG_LANGUAGE);
+ else if (!_cups_strcasecmp(name, "mimetype"))
+ return (IPP_TAG_MIMETYPE);
+ else if (!_cups_strcasecmp(name, "name"))
+ return (IPP_TAG_NAME);
+ else if (!_cups_strcasecmp(name, "text"))
+ return (IPP_TAG_TEXT);
+ else if (!_cups_strcasecmp(name, "begCollection"))
+ return (IPP_TAG_BEGIN_COLLECTION);
+ else
+ return (IPP_TAG_ZERO);
+}
+
+
+/*
+ * 'ipp_col_string()' - Convert a collection to a string.
+ */
+
+static size_t /* O - Number of bytes */
+ipp_col_string(ipp_t *col, /* I - Collection attribute */
+ char *buffer, /* I - Buffer or NULL */
+ size_t bufsize) /* I - Size of buffer */
+{
+ char *bufptr, /* Position in buffer */
+ *bufend, /* End of buffer */
+ temp[256]; /* Temporary string */
+ ipp_attribute_t *attr; /* Current member attribute */
+
+
+ bufptr = buffer;
+ bufend = buffer + bufsize - 1;
+
+ if (buffer && bufptr < bufend)
+ *bufptr = '{';
+ bufptr ++;
+
+ for (attr = col->attrs; attr; attr = attr->next)
+ {
+ if (!attr->name)
+ continue;
+
+ if (buffer && bufptr < bufend)
+ bufptr += snprintf(bufptr, bufend - bufptr + 1, "%s=", attr->name);
+ else
+ bufptr += strlen(attr->name) + 1;
+
+ if (buffer && bufptr < bufend)
+ bufptr += _ippAttrString(attr, bufptr, bufend - bufptr + 1);
+ else
+ bufptr += _ippAttrString(attr, temp, sizeof(temp));
+ }
+
+ if (buffer && bufptr < bufend)
+ *bufptr = '}';
+ bufptr ++;
+
+ return (bufptr - buffer);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/ipp.c b/cups/ipp.c
new file mode 100644
index 000000000..1a04caf95
--- /dev/null
+++ b/cups/ipp.c
@@ -0,0 +1,3206 @@
+/*
+ * "$Id$"
+ *
+ * Internet Printing Protocol functions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * ippAddBoolean() - Add a boolean attribute to an IPP message.
+ * ippAddBooleans() - Add an array of boolean values.
+ * ippAddDate() - Add a date attribute to an IPP message.
+ * ippAddInteger() - Add a integer attribute to an IPP message.
+ * ippAddIntegers() - Add an array of integer values.
+ * ippAddOctetString() - Add an octetString value to an IPP message.
+ * ippAddString() - Add a language-encoded string to an IPP message.
+ * ippAddStrings() - Add language-encoded strings to an IPP message.
+ * ippAddRange() - Add a range of values to an IPP message.
+ * ippAddRanges() - Add ranges of values to an IPP message.
+ * ippAddResolution() - Add a resolution value to an IPP message.
+ * ippAddResolutions() - Add resolution values to an IPP message.
+ * ippAddSeparator() - Add a group separator to an IPP message.
+ * ippDateToTime() - Convert from RFC 1903 Date/Time format to
+ * UNIX time in seconds.
+ * ippDelete() - Delete an IPP message.
+ * ippDeleteAttribute() - Delete a single attribute in an IPP message.
+ * ippFindAttribute() - Find a named attribute in a request...
+ * ippFindNextAttribute() - Find the next named attribute in a request...
+ * ippLength() - Compute the length of an IPP message.
+ * ippNew() - Allocate a new IPP message.
+ * ippNewRequest() - Allocate a new IPP message.
+ * ippRead() - Read data for an IPP message from a HTTP
+ * connection.
+ * ippReadFile() - Read data for an IPP message from a file.
+ * ippReadIO() - Read data for an IPP message.
+ * ippTimeToDate() - Convert from UNIX time to RFC 1903 format.
+ * ippWrite() - Write data for an IPP message to a HTTP
+ * connection.
+ * ippWriteFile() - Write data for an IPP message to a file.
+ * ippWriteIO() - Write data for an IPP message.
+ * _ippAddAttr() - Add a new attribute to the request.
+ * _ippFreeAttr() - Free an attribute.
+ * ipp_length() - Compute the length of an IPP message or
+ * collection value.
+ * ipp_read_http() - Semi-blocking read on a HTTP connection...
+ * ipp_read_file() - Read IPP data from a file.
+ * ipp_write_file() - Write IPP data to a file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#ifdef WIN32
+# include <io.h>
+#endif /* WIN32 */
+
+
+/*
+ * Local functions...
+ */
+
+static unsigned char *ipp_buffer_get(void);
+static void ipp_buffer_release(unsigned char *b);
+static size_t ipp_length(ipp_t *ipp, int collection);
+static ssize_t ipp_read_http(http_t *http, ipp_uchar_t *buffer,
+ size_t length);
+static ssize_t ipp_read_file(int *fd, ipp_uchar_t *buffer,
+ size_t length);
+static ssize_t ipp_write_file(int *fd, ipp_uchar_t *buffer,
+ size_t length);
+
+
+/*
+ * 'ippAddBoolean()' - Add a boolean attribute to an IPP message.
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddBoolean(ipp_t *ipp, /* I - IPP message */
+ ipp_tag_t group, /* I - IPP group */
+ const char *name, /* I - Name of attribute */
+ char value) /* I - Value of attribute */
+{
+ ipp_attribute_t *attr; /* New attribute */
+
+
+ DEBUG_printf(("ippAddBoolean(ipp=%p, group=%02x(%s), name=\"%s\", value=%d)",
+ ipp, group, ippTagString(group), name, value));
+
+ if (!ipp || !name)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, 1)) == NULL)
+ return (NULL);
+
+ attr->name = _cupsStrAlloc(name);
+ attr->group_tag = group;
+ attr->value_tag = IPP_TAG_BOOLEAN;
+ attr->values[0].boolean = value;
+
+ return (attr);
+}
+
+
+/*
+ * 'ippAddBooleans()' - Add an array of boolean values.
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddBooleans(ipp_t *ipp, /* I - IPP message */
+ ipp_tag_t group, /* I - IPP group */
+ const char *name, /* I - Name of attribute */
+ int num_values, /* I - Number of values */
+ const char *values) /* I - Values */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *attr; /* New attribute */
+ ipp_value_t *value; /* Current value */
+
+
+ DEBUG_printf(("ippAddBooleans(ipp=%p, group=%02x(%s), name=\"%s\", "
+ "num_values=%d, values=%p)", ipp, group, ippTagString(group),
+ name, num_values, values));
+
+ if (!ipp || !name || num_values < 1)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
+ return (NULL);
+
+ attr->name = _cupsStrAlloc(name);
+ attr->group_tag = group;
+ attr->value_tag = IPP_TAG_BOOLEAN;
+
+ if (values != NULL)
+ for (i = 0, value = attr->values;
+ i < num_values;
+ i ++, value ++)
+ value->boolean = values[i];
+
+ return (attr);
+}
+
+
+/*
+ * 'ippAddCollection()' - Add a collection value.
+ *
+ * @since CUPS 1.1.19/Mac OS X 10.3@
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddCollection(ipp_t *ipp, /* I - IPP message */
+ ipp_tag_t group, /* I - IPP group */
+ const char *name, /* I - Name of attribute */
+ ipp_t *value) /* I - Value */
+{
+ ipp_attribute_t *attr; /* New attribute */
+
+
+ DEBUG_printf(("ippAddCollection(ipp=%p, group=%02x(%s), name=\"%s\", "
+ "value=%p)", ipp, group, ippTagString(group), name, value));
+
+ if (!ipp || !name)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, 1)) == NULL)
+ return (NULL);
+
+ attr->name = _cupsStrAlloc(name);
+ attr->group_tag = group;
+ attr->value_tag = IPP_TAG_BEGIN_COLLECTION;
+ attr->values[0].collection = value;
+
+ value->use ++;
+
+ return (attr);
+}
+
+
+/*
+ * 'ippAddCollections()' - Add an array of collection values.
+ *
+ * @since CUPS 1.1.19/Mac OS X 10.3@
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddCollections(
+ ipp_t *ipp, /* I - IPP message */
+ ipp_tag_t group, /* I - IPP group */
+ const char *name, /* I - Name of attribute */
+ int num_values, /* I - Number of values */
+ const ipp_t **values) /* I - Values */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *attr; /* New attribute */
+ ipp_value_t *value; /* Current value */
+
+
+ DEBUG_printf(("ippAddCollections(ipp=%p, group=%02x(%s), name=\"%s\", "
+ "num_values=%d, values=%p)", ipp, group, ippTagString(group),
+ name, num_values, values));
+
+ if (!ipp || !name || num_values < 1)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
+ return (NULL);
+
+ attr->name = _cupsStrAlloc(name);
+ attr->group_tag = group;
+ attr->value_tag = IPP_TAG_BEGIN_COLLECTION;
+
+ if (values != NULL)
+ {
+ for (i = 0, value = attr->values;
+ i < num_values;
+ i ++, value ++)
+ {
+ value->collection = (ipp_t *)values[i];
+ value->collection->use ++;
+ }
+ }
+
+ return (attr);
+}
+
+
+/*
+ * 'ippAddDate()' - Add a date attribute to an IPP message.
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddDate(ipp_t *ipp, /* I - IPP message */
+ ipp_tag_t group, /* I - IPP group */
+ const char *name, /* I - Name of attribute */
+ const ipp_uchar_t *value) /* I - Value */
+{
+ ipp_attribute_t *attr; /* New attribute */
+
+
+ DEBUG_printf(("ippAddDate(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)",
+ ipp, group, ippTagString(group), name, value));
+
+ if (!ipp || !name || !value)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, 1)) == NULL)
+ return (NULL);
+
+ attr->name = _cupsStrAlloc(name);
+ attr->group_tag = group;
+ attr->value_tag = IPP_TAG_DATE;
+ memcpy(attr->values[0].date, value, 11);
+
+ return (attr);
+}
+
+
+/*
+ * 'ippAddInteger()' - Add a integer attribute to an IPP message.
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddInteger(ipp_t *ipp, /* I - IPP message */
+ ipp_tag_t group, /* I - IPP group */
+ ipp_tag_t type, /* I - Type of attribute */
+ const char *name, /* I - Name of attribute */
+ int value) /* I - Value of attribute */
+{
+ ipp_attribute_t *attr; /* New attribute */
+
+
+ DEBUG_printf(("ippAddInteger(ipp=%p, group=%02x(%s), type=%02x(%s), "
+ "name=\"%s\", value=%d)", ipp, group, ippTagString(group),
+ type, ippTagString(type), name, value));
+
+ if (!ipp || !name)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, 1)) == NULL)
+ return (NULL);
+
+ attr->name = _cupsStrAlloc(name);
+ attr->group_tag = group;
+ attr->value_tag = type;
+ attr->values[0].integer = value;
+
+ return (attr);
+}
+
+
+/*
+ * 'ippAddIntegers()' - Add an array of integer values.
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddIntegers(ipp_t *ipp, /* I - IPP message */
+ ipp_tag_t group, /* I - IPP group */
+ ipp_tag_t type, /* I - Type of attribute */
+ const char *name, /* I - Name of attribute */
+ int num_values, /* I - Number of values */
+ const int *values) /* I - Values */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *attr; /* New attribute */
+ ipp_value_t *value; /* Current value */
+
+
+ DEBUG_printf(("ippAddIntegers(ipp=%p, group=%02x(%s), type=%02x(%s), "
+ "name=\"%s\", num_values=%d, values=%p)", ipp,
+ group, ippTagString(group), type, ippTagString(type), name,
+ num_values, values));
+
+ if (!ipp || !name || num_values < 1)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
+ return (NULL);
+
+ attr->name = _cupsStrAlloc(name);
+ attr->group_tag = group;
+ attr->value_tag = type;
+
+ if (values != NULL)
+ for (i = 0, value = attr->values;
+ i < num_values;
+ i ++, value ++)
+ value->integer = values[i];
+
+ return (attr);
+}
+
+
+/*
+ * 'ippAddOctetString()' - Add an octetString value to an IPP message.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddOctetString(ipp_t *ipp, /* I - IPP message */
+ ipp_tag_t group, /* I - IPP group */
+ const char *name, /* I - Name of attribute */
+ const void *data, /* I - octetString data */
+ int datalen) /* I - Length of data in bytes */
+{
+ ipp_attribute_t *attr; /* New attribute */
+
+
+ if (ipp == NULL || name == NULL)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, 1)) == NULL)
+ return (NULL);
+
+ /*
+ * Initialize the attribute data...
+ */
+
+ attr->name = _cupsStrAlloc(name);
+ attr->group_tag = group;
+ attr->value_tag = IPP_TAG_STRING;
+ attr->values[0].unknown.length = datalen;
+
+ if (data)
+ {
+ if ((attr->values[0].unknown.data = malloc(datalen)) == NULL)
+ {
+ ippDeleteAttribute(ipp, attr);
+ return (NULL);
+ }
+
+ memcpy(attr->values[0].unknown.data, data, datalen);
+ }
+
+ /*
+ * Return the new attribute...
+ */
+
+ return (attr);
+}
+
+
+/*
+ * 'ippAddString()' - Add a language-encoded string to an IPP message.
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddString(ipp_t *ipp, /* I - IPP message */
+ ipp_tag_t group, /* I - IPP group */
+ ipp_tag_t type, /* I - Type of attribute */
+ const char *name, /* I - Name of attribute */
+ const char *charset, /* I - Character set */
+ const char *value) /* I - Value */
+{
+ ipp_attribute_t *attr; /* New attribute */
+ char buffer[1024], /* Language/charset value buffer */
+ *bufptr; /* Pointer into buffer */
+
+
+ DEBUG_printf(("ippAddString(ipp=%p, group=%02x(%s), type=%02x(%s), "
+ "name=\"%s\", charset=\"%s\", value=\"%s\")", ipp,
+ group, ippTagString(group), type, ippTagString(type), name,
+ charset, value));
+
+ if (!ipp || !name)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, 1)) == NULL)
+ return (NULL);
+
+ /*
+ * Force value to be English for the POSIX locale...
+ */
+
+ if (type == IPP_TAG_LANGUAGE && !_cups_strcasecmp(value, "C"))
+ value = "en";
+
+ /*
+ * Convert language and charset values to lowercase and change _ to - as
+ * needed...
+ */
+
+ if ((type == IPP_TAG_LANGUAGE || type == IPP_TAG_CHARSET) && value)
+ {
+ strlcpy(buffer, value, sizeof(buffer));
+ value = buffer;
+
+ for (bufptr = buffer; *bufptr; bufptr ++)
+ if (*bufptr == '_')
+ *bufptr = '-';
+ else
+ *bufptr = tolower(*bufptr & 255);
+ }
+
+ /*
+ * Initialize the attribute data...
+ */
+
+ attr->name = _cupsStrAlloc(name);
+ attr->group_tag = group;
+ attr->value_tag = type;
+ attr->values[0].string.charset = ((int)type & IPP_TAG_COPY) ? (char *)charset :
+ charset ? _cupsStrAlloc(charset) : NULL;
+ attr->values[0].string.text = ((int)type & IPP_TAG_COPY) ? (char *)value :
+ value ? _cupsStrAlloc(value) : NULL;
+
+ return (attr);
+}
+
+
+/*
+ * 'ippAddStrings()' - Add language-encoded strings to an IPP message.
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddStrings(
+ ipp_t *ipp, /* I - IPP message */
+ ipp_tag_t group, /* I - IPP group */
+ ipp_tag_t type, /* I - Type of attribute */
+ const char *name, /* I - Name of attribute */
+ int num_values, /* I - Number of values */
+ const char *charset, /* I - Character set */
+ const char * const *values) /* I - Values */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *attr; /* New attribute */
+ ipp_value_t *value; /* Current value */
+ char buffer[1024], /* Language/charset value buffer */
+ *bufptr; /* Pointer into buffer */
+
+
+ DEBUG_printf(("ippAddStrings(ipp=%p, group=%02x(%s), type=%02x(%s), "
+ "name=\"%s\", num_values=%d, charset=\"%s\", values=%p)", ipp,
+ group, ippTagString(group), type, ippTagString(type), name,
+ num_values, charset, values));
+
+ if (!ipp || !name || num_values < 1)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
+ return (NULL);
+
+ /*
+ * Initialize the attribute data...
+ */
+
+ attr->name = _cupsStrAlloc(name);
+ attr->group_tag = group;
+ attr->value_tag = type;
+
+ for (i = 0, value = attr->values;
+ i < num_values;
+ i ++, value ++)
+ {
+ if (i == 0)
+ value->string.charset = ((int)type & IPP_TAG_COPY) ? (char *)charset :
+ charset ? _cupsStrAlloc(charset) : NULL;
+ else
+ value->string.charset = attr->values[0].string.charset;
+
+ if (values != NULL)
+ {
+ if ((int)type & IPP_TAG_COPY)
+ value->string.text = (char *)values[i];
+ else if (type == IPP_TAG_LANGUAGE && !_cups_strcasecmp(values[i], "C"))
+ {
+ /*
+ * Force language to be English for the POSIX locale...
+ */
+
+ value->string.text = ((int)type & IPP_TAG_COPY) ? "en" :
+ _cupsStrAlloc("en");
+ }
+ else if (type == IPP_TAG_LANGUAGE || type == IPP_TAG_CHARSET)
+ {
+ /*
+ * Convert language values to lowercase and change _ to - as needed...
+ */
+
+ strlcpy(buffer, values[i], sizeof(buffer));
+
+ for (bufptr = buffer; *bufptr; bufptr ++)
+ if (*bufptr == '_')
+ *bufptr = '-';
+ else
+ *bufptr = tolower(*bufptr & 255);
+
+ value->string.text = _cupsStrAlloc(buffer);
+ }
+ else
+ value->string.text = _cupsStrAlloc(values[i]);
+
+ }
+ }
+
+ return (attr);
+}
+
+
+/*
+ * 'ippAddRange()' - Add a range of values to an IPP message.
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddRange(ipp_t *ipp, /* I - IPP message */
+ ipp_tag_t group, /* I - IPP group */
+ const char *name, /* I - Name of attribute */
+ int lower, /* I - Lower value */
+ int upper) /* I - Upper value */
+{
+ ipp_attribute_t *attr; /* New attribute */
+
+
+ DEBUG_printf(("ippAddRange(ipp=%p, group=%02x(%s), name=\"%s\", lower=%d, "
+ "upper=%d)", ipp, group, ippTagString(group), name, lower,
+ upper));
+
+ if (!ipp || !name)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, 1)) == NULL)
+ return (NULL);
+
+ attr->name = _cupsStrAlloc(name);
+ attr->group_tag = group;
+ attr->value_tag = IPP_TAG_RANGE;
+ attr->values[0].range.lower = lower;
+ attr->values[0].range.upper = upper;
+
+ return (attr);
+}
+
+
+/*
+ * 'ippAddRanges()' - Add ranges of values to an IPP message.
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddRanges(ipp_t *ipp, /* I - IPP message */
+ ipp_tag_t group, /* I - IPP group */
+ const char *name, /* I - Name of attribute */
+ int num_values, /* I - Number of values */
+ const int *lower, /* I - Lower values */
+ const int *upper) /* I - Upper values */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *attr; /* New attribute */
+ ipp_value_t *value; /* Current value */
+
+
+ DEBUG_printf(("ippAddRanges(ipp=%p, group=%02x(%s), name=\"%s\", "
+ "num_values=%d, lower=%p, upper=%p)", ipp, group,
+ ippTagString(group), name, num_values, lower, upper));
+
+ if (!ipp || !name || num_values < 1)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
+ return (NULL);
+
+ attr->name = _cupsStrAlloc(name);
+ attr->group_tag = group;
+ attr->value_tag = IPP_TAG_RANGE;
+
+ if (lower != NULL && upper != NULL)
+ for (i = 0, value = attr->values;
+ i < num_values;
+ i ++, value ++)
+ {
+ value->range.lower = lower[i];
+ value->range.upper = upper[i];
+ }
+
+ return (attr);
+}
+
+
+/*
+ * 'ippAddResolution()' - Add a resolution value to an IPP message.
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddResolution(ipp_t *ipp, /* I - IPP message */
+ ipp_tag_t group, /* I - IPP group */
+ const char *name, /* I - Name of attribute */
+ ipp_res_t units, /* I - Units for resolution */
+ int xres, /* I - X resolution */
+ int yres) /* I - Y resolution */
+{
+ ipp_attribute_t *attr; /* New attribute */
+
+
+ DEBUG_printf(("ippAddResolution(ipp=%p, group=%02x(%s), name=\"%s\", "
+ "units=%d, xres=%d, yres=%d)", ipp, group,
+ ippTagString(group), name, units, xres, yres));
+
+ if (!ipp || !name)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, 1)) == NULL)
+ return (NULL);
+
+ attr->name = _cupsStrAlloc(name);
+ attr->group_tag = group;
+ attr->value_tag = IPP_TAG_RESOLUTION;
+ attr->values[0].resolution.xres = xres;
+ attr->values[0].resolution.yres = yres;
+ attr->values[0].resolution.units = units;
+
+ return (attr);
+}
+
+
+/*
+ * 'ippAddResolutions()' - Add resolution values to an IPP message.
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddResolutions(ipp_t *ipp, /* I - IPP message */
+ ipp_tag_t group, /* I - IPP group */
+ const char *name, /* I - Name of attribute */
+ int num_values,/* I - Number of values */
+ ipp_res_t units, /* I - Units for resolution */
+ const int *xres, /* I - X resolutions */
+ const int *yres) /* I - Y resolutions */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *attr; /* New attribute */
+ ipp_value_t *value; /* Current value */
+
+
+ DEBUG_printf(("ippAddResolutions(ipp=%p, group=%02x(%s), name=\"%s\", "
+ "num_value=%d, units=%d, xres=%p, yres=%p)", ipp, group,
+ ippTagString(group), name, num_values, units, xres, yres));
+
+ if (!ipp || !name || num_values < 1)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
+ return (NULL);
+
+ attr->name = _cupsStrAlloc(name);
+ attr->group_tag = group;
+ attr->value_tag = IPP_TAG_RESOLUTION;
+
+ if (xres != NULL && yres != NULL)
+ for (i = 0, value = attr->values;
+ i < num_values;
+ i ++, value ++)
+ {
+ value->resolution.xres = xres[i];
+ value->resolution.yres = yres[i];
+ value->resolution.units = units;
+ }
+
+ return (attr);
+}
+
+
+/*
+ * 'ippAddSeparator()' - Add a group separator to an IPP message.
+ */
+
+ipp_attribute_t * /* O - New attribute */
+ippAddSeparator(ipp_t *ipp) /* I - IPP message */
+{
+ ipp_attribute_t *attr; /* New attribute */
+
+
+ DEBUG_printf(("ippAddSeparator(ipp=%p)", ipp));
+
+ if (!ipp)
+ return (NULL);
+
+ if ((attr = _ippAddAttr(ipp, 0)) == NULL)
+ return (NULL);
+
+ attr->group_tag = IPP_TAG_ZERO;
+ attr->value_tag = IPP_TAG_ZERO;
+
+ return (attr);
+}
+
+
+/*
+ * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
+ * in seconds.
+ */
+
+time_t /* O - UNIX time value */
+ippDateToTime(const ipp_uchar_t *date) /* I - RFC 1903 date info */
+{
+ struct tm unixdate; /* UNIX date/time info */
+ time_t t; /* Computed time */
+
+
+ if (!date)
+ return (0);
+
+ memset(&unixdate, 0, sizeof(unixdate));
+
+ /*
+ * RFC-1903 date/time format is:
+ *
+ * Byte(s) Description
+ * ------- -----------
+ * 0-1 Year (0 to 65535)
+ * 2 Month (1 to 12)
+ * 3 Day (1 to 31)
+ * 4 Hours (0 to 23)
+ * 5 Minutes (0 to 59)
+ * 6 Seconds (0 to 60, 60 = "leap second")
+ * 7 Deciseconds (0 to 9)
+ * 8 +/- UTC
+ * 9 UTC hours (0 to 11)
+ * 10 UTC minutes (0 to 59)
+ */
+
+ unixdate.tm_year = ((date[0] << 8) | date[1]) - 1900;
+ unixdate.tm_mon = date[2] - 1;
+ unixdate.tm_mday = date[3];
+ unixdate.tm_hour = date[4];
+ unixdate.tm_min = date[5];
+ unixdate.tm_sec = date[6];
+
+ t = mktime(&unixdate);
+
+ if (date[8] == '-')
+ t += date[9] * 3600 + date[10] * 60;
+ else
+ t -= date[9] * 3600 + date[10] * 60;
+
+ return (t);
+}
+
+
+/*
+ * 'ippDelete()' - Delete an IPP message.
+ */
+
+void
+ippDelete(ipp_t *ipp) /* I - IPP message */
+{
+ ipp_attribute_t *attr, /* Current attribute */
+ *next; /* Next attribute */
+
+
+ DEBUG_printf(("ippDelete(ipp=%p)", ipp));
+
+ if (!ipp)
+ return;
+
+ ipp->use --;
+ if (ipp->use > 0)
+ return;
+
+ for (attr = ipp->attrs; attr != NULL; attr = next)
+ {
+ next = attr->next;
+ _ippFreeAttr(attr);
+ }
+
+ free(ipp);
+}
+
+
+/*
+ * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
+ *
+ * @since CUPS 1.1.19/Mac OS X 10.3@
+ */
+
+void
+ippDeleteAttribute(
+ ipp_t *ipp, /* I - IPP message */
+ ipp_attribute_t *attr) /* I - Attribute to delete */
+{
+ ipp_attribute_t *current, /* Current attribute */
+ *prev; /* Previous attribute */
+
+
+ DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p(%s))", ipp, attr,
+ attr ? attr->name : "(null)"));
+
+ /*
+ * Find the attribute in the list...
+ */
+
+ for (current = ipp->attrs, prev = NULL;
+ current != NULL && current != attr;
+ prev = current, current = current->next);
+
+ if (current)
+ {
+ /*
+ * Found it, remove the attribute from the list...
+ */
+
+ if (prev)
+ prev->next = current->next;
+ else
+ ipp->attrs = current->next;
+
+ if (current == ipp->last)
+ ipp->last = prev;
+
+ /*
+ * Free memory used by the attribute...
+ */
+
+ _ippFreeAttr(current);
+ }
+}
+
+
+/*
+ * 'ippFindAttribute()' - Find a named attribute in a request...
+ */
+
+ipp_attribute_t * /* O - Matching attribute */
+ippFindAttribute(ipp_t *ipp, /* I - IPP message */
+ const char *name, /* I - Name of attribute */
+ ipp_tag_t type) /* I - Type of attribute */
+{
+ DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", ipp,
+ name, type, ippTagString(type)));
+
+ if (!ipp || !name)
+ return (NULL);
+
+ /*
+ * Reset the current pointer...
+ */
+
+ ipp->current = NULL;
+
+ /*
+ * Search for the attribute...
+ */
+
+ return (ippFindNextAttribute(ipp, name, type));
+}
+
+
+/*
+ * 'ippFindNextAttribute()' - Find the next named attribute in a request...
+ */
+
+ipp_attribute_t * /* O - Matching attribute */
+ippFindNextAttribute(ipp_t *ipp, /* I - IPP message */
+ const char *name, /* I - Name of attribute */
+ ipp_tag_t type) /* I - Type of attribute */
+{
+ ipp_attribute_t *attr; /* Current atttribute */
+ ipp_tag_t value_tag; /* Value tag */
+
+
+ DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))",
+ ipp, name, type, ippTagString(type)));
+
+ if (!ipp || !name)
+ return (NULL);
+
+ if (ipp->current)
+ {
+ ipp->prev = ipp->current;
+ attr = ipp->current->next;
+ }
+ else
+ {
+ ipp->prev = NULL;
+ attr = ipp->attrs;
+ }
+
+ for (; attr != NULL; ipp->prev = attr, attr = attr->next)
+ {
+ DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", attr,
+ attr->name));
+
+ value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_MASK);
+
+ if (attr->name != NULL && _cups_strcasecmp(attr->name, name) == 0 &&
+ (value_tag == type || type == IPP_TAG_ZERO ||
+ (value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) ||
+ (value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME)))
+ {
+ ipp->current = attr;
+
+ return (attr);
+ }
+ }
+
+ ipp->current = NULL;
+ ipp->prev = NULL;
+
+ return (NULL);
+}
+
+
+/*
+ * 'ippLength()' - Compute the length of an IPP message.
+ */
+
+size_t /* O - Size of IPP message */
+ippLength(ipp_t *ipp) /* I - IPP message */
+{
+ return (ipp_length(ipp, 0));
+}
+
+
+/*
+ * 'ippNew()' - Allocate a new IPP message.
+ */
+
+ipp_t * /* O - New IPP message */
+ippNew(void)
+{
+ ipp_t *temp; /* New IPP message */
+
+
+ DEBUG_puts("ippNew()");
+
+ if ((temp = (ipp_t *)calloc(1, sizeof(ipp_t))) != NULL)
+ {
+ /*
+ * Default to IPP 1.1...
+ */
+
+ temp->request.any.version[0] = 1;
+ temp->request.any.version[1] = 1;
+ temp->use = 1;
+ }
+
+ DEBUG_printf(("1ippNew: Returning %p", temp));
+
+ return (temp);
+}
+
+
+/*
+ * 'ippNewRequest()' - Allocate a new IPP request message.
+ *
+ * The new request message is initialized with the attributes-charset and
+ * attributes-natural-language attributes added. The
+ * attributes-natural-language value is derived from the current locale.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ipp_t * /* O - IPP request message */
+ippNewRequest(ipp_op_t op) /* I - Operation code */
+{
+ ipp_t *request; /* IPP request message */
+ cups_lang_t *language; /* Current language localization */
+
+
+ DEBUG_printf(("ippNewRequest(op=%02x(%s))", op, ippOpString(op)));
+
+ /*
+ * Create a new IPP message...
+ */
+
+ if ((request = ippNew()) == NULL)
+ return (NULL);
+
+ /*
+ * Set the operation and request ID...
+ */
+
+ request->request.op.operation_id = op;
+ request->request.op.request_id = 1;
+
+ /*
+ * Use UTF-8 as the character set...
+ */
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, "utf-8");
+
+ /*
+ * Get the language from the current locale...
+ */
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ /*
+ * Return the new request...
+ */
+
+ return (request);
+}
+
+
+/*
+ * 'ippRead()' - Read data for an IPP message from a HTTP connection.
+ */
+
+ipp_state_t /* O - Current state */
+ippRead(http_t *http, /* I - HTTP connection */
+ ipp_t *ipp) /* I - IPP data */
+{
+ DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT,
+ http, ipp, CUPS_LLCAST (http ? http->data_remaining : -1)));
+
+ if (!http)
+ return (IPP_ERROR);
+
+ DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http->state,
+ http->used));
+
+ return (ippReadIO(http, (ipp_iocb_t)ipp_read_http, http->blocking, NULL,
+ ipp));
+}
+
+
+/*
+ * 'ippReadFile()' - Read data for an IPP message from a file.
+ *
+ * @since CUPS 1.1.19/Mac OS X 10.3@
+ */
+
+ipp_state_t /* O - Current state */
+ippReadFile(int fd, /* I - HTTP data */
+ ipp_t *ipp) /* I - IPP data */
+{
+ DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd, ipp));
+
+ return (ippReadIO(&fd, (ipp_iocb_t)ipp_read_file, 1, NULL, ipp));
+}
+
+
+/*
+ * 'ippReadIO()' - Read data for an IPP message.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ipp_state_t /* O - Current state */
+ippReadIO(void *src, /* I - Data source */
+ ipp_iocb_t cb, /* I - Read callback function */
+ int blocking, /* I - Use blocking IO? */
+ ipp_t *parent, /* I - Parent request, if any */
+ ipp_t *ipp) /* I - IPP data */
+{
+ int n; /* Length of data */
+ unsigned char *buffer, /* Data buffer */
+ string[IPP_MAX_NAME],
+ /* Small string buffer */
+ *bufptr; /* Pointer into buffer */
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_tag_t tag; /* Current tag */
+ ipp_tag_t value_tag; /* Current value tag */
+ ipp_value_t *value; /* Current value */
+
+
+ DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
+ src, cb, blocking, parent, ipp));
+ DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp->state));
+
+ if (!src || !ipp)
+ return (IPP_ERROR);
+
+ if ((buffer = ipp_buffer_get()) == NULL)
+ {
+ DEBUG_puts("1ippReadIO: Unable to get read buffer!");
+ return (IPP_ERROR);
+ }
+
+ switch (ipp->state)
+ {
+ case IPP_IDLE :
+ ipp->state ++; /* Avoid common problem... */
+
+ case IPP_HEADER :
+ if (parent == NULL)
+ {
+ /*
+ * Get the request header...
+ */
+
+ if ((*cb)(src, buffer, 8) < 8)
+ {
+ DEBUG_puts("1ippReadIO: Unable to read header!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ /*
+ * Then copy the request header over...
+ */
+
+ ipp->request.any.version[0] = buffer[0];
+ ipp->request.any.version[1] = buffer[1];
+ ipp->request.any.op_status = (buffer[2] << 8) | buffer[3];
+ ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) |
+ buffer[6]) << 8) | buffer[7];
+
+ DEBUG_printf(("2ippReadIO: version=%d.%d", buffer[0], buffer[1]));
+ DEBUG_printf(("2ippReadIO: op_status=%04x",
+ ipp->request.any.op_status));
+ DEBUG_printf(("2ippReadIO: request_id=%d",
+ ipp->request.any.request_id));
+ }
+
+ ipp->state = IPP_ATTRIBUTE;
+ ipp->current = NULL;
+ ipp->curtag = IPP_TAG_ZERO;
+ ipp->prev = ipp->last;
+
+ /*
+ * If blocking is disabled, stop here...
+ */
+
+ if (!blocking)
+ break;
+
+ case IPP_ATTRIBUTE :
+ for (;;)
+ {
+ if ((*cb)(src, buffer, 1) < 1)
+ {
+ DEBUG_puts("1ippReadIO: Callback returned EOF/error");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p",
+ ipp->current, ipp->prev));
+
+ /*
+ * Read this attribute...
+ */
+
+ tag = (ipp_tag_t)buffer[0];
+
+ if (tag == IPP_TAG_END)
+ {
+ /*
+ * No more attributes left...
+ */
+
+ DEBUG_puts("2ippReadIO: IPP_TAG_END!");
+
+ ipp->state = IPP_DATA;
+ break;
+ }
+ else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
+ {
+ /*
+ * Group tag... Set the current group and continue...
+ */
+
+ if (ipp->curtag == tag)
+ ipp->prev = ippAddSeparator(ipp);
+ else if (ipp->current)
+ ipp->prev = ipp->current;
+
+ ipp->curtag = tag;
+ ipp->current = NULL;
+ DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag,
+ ippTagString(tag), ipp->prev));
+ continue;
+ }
+
+ DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag,
+ ippTagString(tag)));
+
+ /*
+ * Get the name...
+ */
+
+ if ((*cb)(src, buffer, 2) < 2)
+ {
+ DEBUG_puts("1ippReadIO: unable to read name length!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ n = (buffer[0] << 8) | buffer[1];
+
+ if (n >= IPP_BUF_SIZE)
+ {
+ DEBUG_printf(("1ippReadIO: bad name length %d!", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ DEBUG_printf(("2ippReadIO: name length=%d", n));
+
+ if (n == 0 && tag != IPP_TAG_MEMBERNAME &&
+ tag != IPP_TAG_END_COLLECTION)
+ {
+ /*
+ * More values for current attribute...
+ */
+
+ if (ipp->current == NULL)
+ {
+ DEBUG_puts("1ippReadIO: Attribute without name and no current");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ attr = ipp->current;
+ value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_MASK);
+
+ /*
+ * Make sure we aren't adding a new value of a different
+ * type...
+ */
+
+ if (value_tag == IPP_TAG_ZERO)
+ {
+ /*
+ * Setting the value of a collection member...
+ */
+
+ attr->value_tag = tag;
+ }
+ else if (value_tag == IPP_TAG_TEXTLANG ||
+ value_tag == IPP_TAG_NAMELANG ||
+ (value_tag >= IPP_TAG_TEXT &&
+ value_tag <= IPP_TAG_MIMETYPE))
+ {
+ /*
+ * String values can sometimes come across in different
+ * forms; accept sets of differing values...
+ */
+
+ if (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG &&
+ (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE) &&
+ tag != IPP_TAG_NOVALUE)
+ {
+ DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
+ value_tag, ippTagString(value_tag), tag,
+ ippTagString(tag)));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+ }
+ else if (value_tag != tag)
+ {
+ DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
+ value_tag, ippTagString(value_tag), tag,
+ ippTagString(tag)));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ /*
+ * Finally, reallocate the attribute array as needed...
+ */
+
+ if (attr->num_values == 1 ||
+ (attr->num_values > 0 &&
+ (attr->num_values & (IPP_MAX_VALUES - 1)) == 0))
+ {
+ ipp_attribute_t *temp; /* Pointer to new buffer */
+
+
+ DEBUG_printf(("2ippReadIO: reallocating for up to %d values...",
+ attr->num_values + IPP_MAX_VALUES));
+
+ /*
+ * Reallocate memory...
+ */
+
+ if ((temp = realloc(attr, sizeof(ipp_attribute_t) +
+ (attr->num_values + IPP_MAX_VALUES - 1) *
+ sizeof(ipp_value_t))) == NULL)
+ {
+ DEBUG_puts("1ippReadIO: Unable to resize attribute");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if (temp != attr)
+ {
+ /*
+ * Reset pointers in the list...
+ */
+
+ if (ipp->prev)
+ ipp->prev->next = temp;
+ else
+ ipp->attrs = temp;
+
+ attr = ipp->current = ipp->last = temp;
+ }
+ }
+ }
+ else if (tag == IPP_TAG_MEMBERNAME)
+ {
+ /*
+ * Name must be length 0!
+ */
+
+ if (n)
+ {
+ DEBUG_puts("1ippReadIO: member name not empty!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if (ipp->current)
+ ipp->prev = ipp->current;
+
+ attr = ipp->current = _ippAddAttr(ipp, 1);
+
+ DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, "
+ "ipp->prev=%p", ipp->current, ipp->prev));
+
+ attr->group_tag = ipp->curtag;
+ attr->value_tag = IPP_TAG_ZERO;
+ attr->num_values = 0;
+ }
+ else if (tag != IPP_TAG_END_COLLECTION)
+ {
+ /*
+ * New attribute; read the name and add it...
+ */
+
+ if ((*cb)(src, buffer, n) < n)
+ {
+ DEBUG_puts("1ippReadIO: unable to read name!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ buffer[n] = '\0';
+
+ if (ipp->current)
+ ipp->prev = ipp->current;
+
+ if ((attr = ipp->current = _ippAddAttr(ipp, 1)) == NULL)
+ {
+ DEBUG_puts("1ippReadIO: unable to allocate attribute!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, "
+ "ipp->prev=%p", buffer, ipp->current, ipp->prev));
+
+ attr->group_tag = ipp->curtag;
+ attr->value_tag = tag;
+ attr->name = _cupsStrAlloc((char *)buffer);
+ attr->num_values = 0;
+ }
+ else
+ attr = NULL;
+
+ if (tag != IPP_TAG_END_COLLECTION)
+ value = attr->values + attr->num_values;
+ else
+ value = NULL;
+
+ if ((*cb)(src, buffer, 2) < 2)
+ {
+ DEBUG_puts("1ippReadIO: unable to read value length!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ n = (buffer[0] << 8) | buffer[1];
+ DEBUG_printf(("2ippReadIO: value length=%d", n));
+
+ switch (tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ if (n != 4)
+ {
+ DEBUG_printf(("1ippReadIO: bad value length %d!", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if ((*cb)(src, buffer, 4) < 4)
+ {
+ DEBUG_puts("1ippReadIO: Unable to read integer value!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
+ buffer[3];
+
+ value->integer = n;
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ if (n != 1)
+ {
+ DEBUG_printf(("1ippReadIO: bad value length %d!", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if ((*cb)(src, buffer, 1) < 1)
+ {
+ DEBUG_puts("1ippReadIO: Unable to read boolean value!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ value->boolean = buffer[0];
+ break;
+
+ case IPP_TAG_NOVALUE :
+ case IPP_TAG_NOTSETTABLE :
+ case IPP_TAG_DELETEATTR :
+ case IPP_TAG_ADMINDEFINE :
+ /*
+ * These value types are not supposed to have values, however
+ * some vendors (Brother) do not implement IPP correctly and so
+ * we need to map non-empty values to text...
+ */
+
+ if (attr->value_tag == tag)
+ {
+ if (n == 0)
+ break;
+
+ attr->value_tag = IPP_TAG_TEXT;
+ }
+
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ if (n >= IPP_BUF_SIZE)
+ {
+ DEBUG_printf(("1ippReadIO: bad value length %d!", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if ((*cb)(src, buffer, n) < n)
+ {
+ DEBUG_puts("1ippReadIO: unable to read name!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ buffer[n] = '\0';
+ value->string.text = _cupsStrAlloc((char *)buffer);
+ DEBUG_printf(("2ippReadIO: value=\"%s\"", value->string.text));
+ break;
+
+ case IPP_TAG_DATE :
+ if (n != 11)
+ {
+ DEBUG_printf(("1ippReadIO: bad value length %d!", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if ((*cb)(src, value->date, 11) < 11)
+ {
+ DEBUG_puts("1ippReadIO: Unable to read date value!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ if (n != 9)
+ {
+ DEBUG_printf(("1ippReadIO: bad value length %d!", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if ((*cb)(src, buffer, 9) < 9)
+ {
+ DEBUG_puts("1ippReadIO: Unable to read resolution value!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ value->resolution.xres =
+ (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
+ buffer[3];
+ value->resolution.yres =
+ (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
+ buffer[7];
+ value->resolution.units =
+ (ipp_res_t)buffer[8];
+ break;
+
+ case IPP_TAG_RANGE :
+ if (n != 8)
+ {
+ DEBUG_printf(("1ippReadIO: bad value length %d!", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if ((*cb)(src, buffer, 8) < 8)
+ {
+ DEBUG_puts("1ippReadIO: Unable to read range value!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ value->range.lower =
+ (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
+ buffer[3];
+ value->range.upper =
+ (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
+ buffer[7];
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ if (n >= IPP_BUF_SIZE || n < 4)
+ {
+ DEBUG_printf(("1ippReadIO: bad value length %d!", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if ((*cb)(src, buffer, n) < n)
+ {
+ DEBUG_puts("1ippReadIO: Unable to read string w/language "
+ "value!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+
+ /*
+ * text-with-language and name-with-language are composite
+ * values:
+ *
+ * charset-length
+ * charset
+ * text-length
+ * text
+ */
+
+ n = (bufptr[0] << 8) | bufptr[1];
+
+ if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) ||
+ n >= sizeof(string))
+ {
+ DEBUG_printf(("1ippReadIO: bad value length %d!", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ memcpy(string, bufptr + 2, n);
+ string[n] = '\0';
+
+ value->string.charset = _cupsStrAlloc((char *)string);
+
+ bufptr += 2 + n;
+ n = (bufptr[0] << 8) | bufptr[1];
+
+ if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE))
+ {
+ DEBUG_printf(("1ippReadIO: bad value length %d!", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr[2 + n] = '\0';
+ value->string.text = _cupsStrAlloc((char *)bufptr + 2);
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ /*
+ * Oh, boy, here comes a collection value, so read it...
+ */
+
+ value->collection = ippNew();
+
+ if (n > 0)
+ {
+ DEBUG_puts("1ippReadIO: begCollection tag with value length "
+ "> 0!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_ERROR)
+ {
+ DEBUG_puts("1ippReadIO: Unable to read collection value!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+ break;
+
+ case IPP_TAG_END_COLLECTION :
+ ipp_buffer_release(buffer);
+
+ if (n > 0)
+ {
+ DEBUG_puts("1ippReadIO: endCollection tag with value length "
+ "> 0!");
+ return (IPP_ERROR);
+ }
+
+ DEBUG_puts("1ippReadIO: endCollection tag...");
+ return (ipp->state = IPP_DATA);
+
+ case IPP_TAG_MEMBERNAME :
+ /*
+ * The value the name of the member in the collection, which
+ * we need to carry over...
+ */
+
+ if (n >= IPP_BUF_SIZE)
+ {
+ DEBUG_printf(("1ippReadIO: bad value length %d!", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if ((*cb)(src, buffer, n) < n)
+ {
+ DEBUG_puts("1ippReadIO: Unable to read member name value!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ buffer[n] = '\0';
+ attr->name = _cupsStrAlloc((char *)buffer);
+
+ /*
+ * Since collection members are encoded differently than
+ * regular attributes, make sure we don't start with an
+ * empty value...
+ */
+
+ attr->num_values --;
+
+ DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr->name));
+ break;
+
+ default : /* Other unsupported values */
+ if (n > IPP_MAX_LENGTH)
+ {
+ DEBUG_printf(("1ippReadIO: bad value length %d!", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if (!value)
+ {
+ DEBUG_puts("1ippReadIO: NULL value!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ value->unknown.length = n;
+ if (n > 0)
+ {
+ if ((value->unknown.data = malloc(n)) == NULL)
+ {
+ DEBUG_puts("1ippReadIO: Unable to allocate value");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if ((*cb)(src, value->unknown.data, n) < n)
+ {
+ DEBUG_puts("1ippReadIO: Unable to read unsupported value!");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+ }
+ else
+ value->unknown.data = NULL;
+ break;
+ }
+
+ attr->num_values ++;
+
+ /*
+ * If blocking is disabled, stop here...
+ */
+
+ if (!blocking)
+ break;
+ }
+ break;
+
+ case IPP_DATA :
+ break;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+
+ DEBUG_printf(("1ippReadIO: returning ipp->state=%d!", ipp->state));
+ ipp_buffer_release(buffer);
+
+ return (ipp->state);
+}
+
+
+/*
+ * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
+ */
+
+const ipp_uchar_t * /* O - RFC-1903 date/time data */
+ippTimeToDate(time_t t) /* I - UNIX time value */
+{
+ struct tm *unixdate; /* UNIX unixdate/time info */
+ ipp_uchar_t *date = _cupsGlobals()->ipp_date;
+ /* RFC-1903 date/time data */
+
+
+ /*
+ * RFC-1903 date/time format is:
+ *
+ * Byte(s) Description
+ * ------- -----------
+ * 0-1 Year (0 to 65535)
+ * 2 Month (1 to 12)
+ * 3 Day (1 to 31)
+ * 4 Hours (0 to 23)
+ * 5 Minutes (0 to 59)
+ * 6 Seconds (0 to 60, 60 = "leap second")
+ * 7 Deciseconds (0 to 9)
+ * 8 +/- UTC
+ * 9 UTC hours (0 to 11)
+ * 10 UTC minutes (0 to 59)
+ */
+
+ unixdate = gmtime(&t);
+ unixdate->tm_year += 1900;
+
+ date[0] = unixdate->tm_year >> 8;
+ date[1] = unixdate->tm_year;
+ date[2] = unixdate->tm_mon + 1;
+ date[3] = unixdate->tm_mday;
+ date[4] = unixdate->tm_hour;
+ date[5] = unixdate->tm_min;
+ date[6] = unixdate->tm_sec;
+ date[7] = 0;
+ date[8] = '+';
+ date[9] = 0;
+ date[10] = 0;
+
+ return (date);
+}
+
+
+/*
+ * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
+ */
+
+ipp_state_t /* O - Current state */
+ippWrite(http_t *http, /* I - HTTP connection */
+ ipp_t *ipp) /* I - IPP data */
+{
+ DEBUG_printf(("ippWrite(http=%p, ipp=%p)", http, ipp));
+
+ if (!http)
+ return (IPP_ERROR);
+
+ return (ippWriteIO(http, (ipp_iocb_t)httpWrite2, http->blocking, NULL, ipp));
+}
+
+
+/*
+ * 'ippWriteFile()' - Write data for an IPP message to a file.
+ *
+ * @since CUPS 1.1.19/Mac OS X 10.3@
+ */
+
+ipp_state_t /* O - Current state */
+ippWriteFile(int fd, /* I - HTTP data */
+ ipp_t *ipp) /* I - IPP data */
+{
+ DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd, ipp));
+
+ ipp->state = IPP_IDLE;
+
+ return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp));
+}
+
+
+/*
+ * 'ippWriteIO()' - Write data for an IPP message.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ipp_state_t /* O - Current state */
+ippWriteIO(void *dst, /* I - Destination */
+ ipp_iocb_t cb, /* I - Write callback function */
+ int blocking, /* I - Use blocking IO? */
+ ipp_t *parent, /* I - Parent IPP message */
+ ipp_t *ipp) /* I - IPP data */
+{
+ int i; /* Looping var */
+ int n; /* Length of data */
+ unsigned char *buffer, /* Data buffer */
+ *bufptr; /* Pointer into buffer */
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_value_t *value; /* Current value */
+
+
+ DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
+ dst, cb, blocking, parent, ipp));
+
+ if (!dst || !ipp)
+ return (IPP_ERROR);
+
+ if ((buffer = ipp_buffer_get()) == NULL)
+ {
+ DEBUG_puts("1ippWriteIO: Unable to get write buffer");
+ return (IPP_ERROR);
+ }
+
+ switch (ipp->state)
+ {
+ case IPP_IDLE :
+ ipp->state ++; /* Avoid common problem... */
+
+ case IPP_HEADER :
+ if (parent == NULL)
+ {
+ /*
+ * Send the request header:
+ *
+ * Version = 2 bytes
+ * Operation/Status Code = 2 bytes
+ * Request ID = 4 bytes
+ * Total = 8 bytes
+ */
+
+ bufptr = buffer;
+
+ *bufptr++ = ipp->request.any.version[0];
+ *bufptr++ = ipp->request.any.version[1];
+ *bufptr++ = ipp->request.any.op_status >> 8;
+ *bufptr++ = ipp->request.any.op_status;
+ *bufptr++ = ipp->request.any.request_id >> 24;
+ *bufptr++ = ipp->request.any.request_id >> 16;
+ *bufptr++ = ipp->request.any.request_id >> 8;
+ *bufptr++ = ipp->request.any.request_id;
+
+ DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer[0], buffer[1]));
+ DEBUG_printf(("2ippWriteIO: op_status=%04x",
+ ipp->request.any.op_status));
+ DEBUG_printf(("2ippWriteIO: request_id=%d",
+ ipp->request.any.request_id));
+
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP header...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+ }
+
+ /*
+ * Reset the state engine to point to the first attribute
+ * in the request/response, with no current group.
+ */
+
+ ipp->state = IPP_ATTRIBUTE;
+ ipp->current = ipp->attrs;
+ ipp->curtag = IPP_TAG_ZERO;
+
+ DEBUG_printf(("1ippWriteIO: ipp->current=%p", ipp->current));
+
+ /*
+ * If blocking is disabled, stop here...
+ */
+
+ if (!blocking)
+ break;
+
+ case IPP_ATTRIBUTE :
+ while (ipp->current != NULL)
+ {
+ /*
+ * Write this attribute...
+ */
+
+ bufptr = buffer;
+ attr = ipp->current;
+
+ ipp->current = ipp->current->next;
+
+ if (!parent)
+ {
+ if (ipp->curtag != attr->group_tag)
+ {
+ /*
+ * Send a group tag byte...
+ */
+
+ ipp->curtag = attr->group_tag;
+
+ if (attr->group_tag == IPP_TAG_ZERO)
+ continue;
+
+ DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
+ attr->group_tag, ippTagString(attr->group_tag)));
+ *bufptr++ = attr->group_tag;
+ }
+ else if (attr->group_tag == IPP_TAG_ZERO)
+ continue;
+ }
+
+ DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr->name,
+ attr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attr->value_tag)));
+
+ /*
+ * Write the attribute tag and name. The current implementation
+ * does not support the extension value tags above 0x7f, so all
+ * value tags are 1 byte.
+ *
+ * The attribute name length does not include the trailing nul
+ * character in the source string.
+ *
+ * Collection values (parent != NULL) are written differently...
+ */
+
+ if (parent == NULL)
+ {
+ /*
+ * Get the length of the attribute name, and make sure it won't
+ * overflow the buffer...
+ */
+
+ if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 4))
+ {
+ DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ /*
+ * Write the value tag, name length, and name string...
+ */
+
+ DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
+ attr->value_tag, ippTagString(attr->value_tag)));
+ DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
+ attr->name));
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+ memcpy(bufptr, attr->name, n);
+ bufptr += n;
+ }
+ else
+ {
+ /*
+ * Get the length of the attribute name, and make sure it won't
+ * overflow the buffer...
+ */
+
+ if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 7))
+ {
+ DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ /*
+ * Write the member name tag, name length, name string, value tag,
+ * and empty name for the collection member attribute...
+ */
+
+ DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
+ IPP_TAG_MEMBERNAME));
+ DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
+ attr->name));
+ DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
+ attr->value_tag, ippTagString(attr->value_tag)));
+ DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
+
+ *bufptr++ = IPP_TAG_MEMBERNAME;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+ memcpy(bufptr, attr->name, n);
+ bufptr += n;
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ /*
+ * Now write the attribute value(s)...
+ */
+
+ switch (attr->value_tag & ~IPP_TAG_COPY)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if ((IPP_BUF_SIZE - (bufptr - buffer)) < 9)
+ {
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP "
+ "attribute...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ /*
+ * Integers and enumerations are both 4-byte signed
+ * (twos-complement) values.
+ *
+ * Put the 2-byte length and 4-byte value into the buffer...
+ */
+
+ *bufptr++ = 0;
+ *bufptr++ = 4;
+ *bufptr++ = value->integer >> 24;
+ *bufptr++ = value->integer >> 16;
+ *bufptr++ = value->integer >> 8;
+ *bufptr++ = value->integer;
+ }
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if ((IPP_BUF_SIZE - (bufptr - buffer)) < 6)
+ {
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP "
+ "attribute...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ /*
+ * Boolean values are 1-byte; 0 = false, 1 = true.
+ *
+ * Put the 2-byte length and 1-byte value into the buffer...
+ */
+
+ *bufptr++ = 0;
+ *bufptr++ = 1;
+ *bufptr++ = value->boolean;
+ }
+ break;
+
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
+ attr->value_tag,
+ ippTagString(attr->value_tag)));
+ DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
+
+ if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
+ {
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP "
+ "attribute...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ if (value->string.text != NULL)
+ n = (int)strlen(value->string.text);
+ else
+ n = 0;
+
+ if (n > (IPP_BUF_SIZE - 2))
+ {
+ DEBUG_printf(("1ippWriteIO: String too long (%d)", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n,
+ value->string.text));
+
+ if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
+ {
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP "
+ "attribute...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ /*
+ * All simple strings consist of the 2-byte length and
+ * character data without the trailing nul normally found
+ * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
+ * bytes since the 2-byte length is a signed (twos-complement)
+ * value.
+ *
+ * Put the 2-byte length and string characters in the buffer.
+ */
+
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ if (n > 0)
+ {
+ memcpy(bufptr, value->string.text, n);
+ bufptr += n;
+ }
+ }
+ break;
+
+ case IPP_TAG_DATE :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if ((IPP_BUF_SIZE - (bufptr - buffer)) < 16)
+ {
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP "
+ "attribute...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ /*
+ * Date values consist of a 2-byte length and an
+ * 11-byte date/time structure defined by RFC 1903.
+ *
+ * Put the 2-byte length and 11-byte date/time
+ * structure in the buffer.
+ */
+
+ *bufptr++ = 0;
+ *bufptr++ = 11;
+ memcpy(bufptr, value->date, 11);
+ bufptr += 11;
+ }
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if ((IPP_BUF_SIZE - (bufptr - buffer)) < 14)
+ {
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP "
+ "attribute...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ /*
+ * Resolution values consist of a 2-byte length,
+ * 4-byte horizontal resolution value, 4-byte vertical
+ * resolution value, and a 1-byte units value.
+ *
+ * Put the 2-byte length and resolution value data
+ * into the buffer.
+ */
+
+ *bufptr++ = 0;
+ *bufptr++ = 9;
+ *bufptr++ = value->resolution.xres >> 24;
+ *bufptr++ = value->resolution.xres >> 16;
+ *bufptr++ = value->resolution.xres >> 8;
+ *bufptr++ = value->resolution.xres;
+ *bufptr++ = value->resolution.yres >> 24;
+ *bufptr++ = value->resolution.yres >> 16;
+ *bufptr++ = value->resolution.yres >> 8;
+ *bufptr++ = value->resolution.yres;
+ *bufptr++ = value->resolution.units;
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if ((IPP_BUF_SIZE - (bufptr - buffer)) < 13)
+ {
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP "
+ "attribute...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ /*
+ * Range values consist of a 2-byte length,
+ * 4-byte lower value, and 4-byte upper value.
+ *
+ * Put the 2-byte length and range value data
+ * into the buffer.
+ */
+
+ *bufptr++ = 0;
+ *bufptr++ = 8;
+ *bufptr++ = value->range.lower >> 24;
+ *bufptr++ = value->range.lower >> 16;
+ *bufptr++ = value->range.lower >> 8;
+ *bufptr++ = value->range.lower;
+ *bufptr++ = value->range.upper >> 24;
+ *bufptr++ = value->range.upper >> 16;
+ *bufptr++ = value->range.upper >> 8;
+ *bufptr++ = value->range.upper;
+ }
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
+ {
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP "
+ "attribute...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ /*
+ * textWithLanguage and nameWithLanguage values consist
+ * of a 2-byte length for both strings and their
+ * individual lengths, a 2-byte length for the
+ * character string, the character string without the
+ * trailing nul, a 2-byte length for the character
+ * set string, and the character set string without
+ * the trailing nul.
+ */
+
+ n = 4;
+
+ if (value->string.charset != NULL)
+ n += (int)strlen(value->string.charset);
+
+ if (value->string.text != NULL)
+ n += (int)strlen(value->string.text);
+
+ if (n > (IPP_BUF_SIZE - 2))
+ {
+ DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
+ "too long (%d)", n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
+ {
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP "
+ "attribute...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ /* Length of entire value */
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Length of charset */
+ if (value->string.charset != NULL)
+ n = (int)strlen(value->string.charset);
+ else
+ n = 0;
+
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Charset */
+ if (n > 0)
+ {
+ memcpy(bufptr, value->string.charset, n);
+ bufptr += n;
+ }
+
+ /* Length of text */
+ if (value->string.text != NULL)
+ n = (int)strlen(value->string.text);
+ else
+ n = 0;
+
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Text */
+ if (n > 0)
+ {
+ memcpy(bufptr, value->string.text, n);
+ bufptr += n;
+ }
+ }
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ /*
+ * Collections are written with the begin-collection
+ * tag first with a value of 0 length, followed by the
+ * attributes in the collection, then the end-collection
+ * value...
+ */
+
+ if ((IPP_BUF_SIZE - (bufptr - buffer)) < 5)
+ {
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP "
+ "attribute...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ /*
+ * Write a data length of 0 and flush the buffer...
+ */
+
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP "
+ "attribute...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+
+ /*
+ * Then write the collection attribute...
+ */
+
+ value->collection->state = IPP_IDLE;
+
+ if (ippWriteIO(dst, cb, 1, ipp,
+ value->collection) == IPP_ERROR)
+ {
+ DEBUG_puts("1ippWriteIO: Unable to write collection value");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+ }
+ break;
+
+ default :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
+ {
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP "
+ "attribute...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ /*
+ * An unknown value might some new value that a
+ * vendor has come up with. It consists of a
+ * 2-byte length and the bytes in the unknown
+ * value buffer.
+ */
+
+ n = value->unknown.length;
+
+ if (n > (IPP_BUF_SIZE - 2))
+ {
+ DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
+ n));
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
+ {
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP "
+ "attribute...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ /* Length of unknown value */
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Value */
+ if (n > 0)
+ {
+ memcpy(bufptr, value->unknown.data, n);
+ bufptr += n;
+ }
+ }
+ break;
+ }
+
+ /*
+ * Write the data out...
+ */
+
+ if (bufptr > buffer)
+ {
+ if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ DEBUG_printf(("2ippWriteIO: wrote %d bytes",
+ (int)(bufptr - buffer)));
+ }
+
+ /*
+ * If blocking is disabled, stop here...
+ */
+
+ if (!blocking)
+ break;
+ }
+
+ if (ipp->current == NULL)
+ {
+ /*
+ * Done with all of the attributes; add the end-of-attributes
+ * tag or end-collection attribute...
+ */
+
+ if (parent == NULL)
+ {
+ buffer[0] = IPP_TAG_END;
+ n = 1;
+ }
+ else
+ {
+ buffer[0] = IPP_TAG_END_COLLECTION;
+ buffer[1] = 0; /* empty name */
+ buffer[2] = 0;
+ buffer[3] = 0; /* empty value */
+ buffer[4] = 0;
+ n = 5;
+ }
+
+ if ((*cb)(dst, buffer, n) < 0)
+ {
+ DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
+ ipp_buffer_release(buffer);
+ return (IPP_ERROR);
+ }
+
+ ipp->state = IPP_DATA;
+ }
+ break;
+
+ case IPP_DATA :
+ break;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+
+ ipp_buffer_release(buffer);
+
+ return (ipp->state);
+}
+
+
+/*
+ * '_ippAddAttr()' - Add a new attribute to the request.
+ */
+
+ipp_attribute_t * /* O - New attribute */
+_ippAddAttr(ipp_t *ipp, /* I - IPP message */
+ int num_values) /* I - Number of values */
+{
+ ipp_attribute_t *attr; /* New attribute */
+
+
+ DEBUG_printf(("4_ippAddAttr(ipp=%p, num_values=%d)", ipp, num_values));
+
+ if (!ipp || num_values < 0)
+ return (NULL);
+
+ attr = calloc(sizeof(ipp_attribute_t) +
+ (num_values - 1) * sizeof(ipp_value_t), 1);
+
+ if (attr != NULL)
+ {
+ attr->num_values = num_values;
+
+ if (ipp->last == NULL)
+ ipp->attrs = attr;
+ else
+ ipp->last->next = attr;
+
+ ipp->last = attr;
+ }
+
+ DEBUG_printf(("5_ippAddAttr: Returning %p", attr));
+
+ return (attr);
+}
+
+
+/*
+ * '_ippFreeAttr()' - Free an attribute.
+ */
+
+void
+_ippFreeAttr(ipp_attribute_t *attr) /* I - Attribute to free */
+{
+ int i; /* Looping var */
+ ipp_value_t *value; /* Current value */
+
+
+ DEBUG_printf(("4_ippFreeAttr(attr=%p)", attr));
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_RESERVED_STRING :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ _cupsStrFree(value->string.text);
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if (value->string.charset && i == 0)
+ _cupsStrFree(value->string.charset);
+ _cupsStrFree(value->string.text);
+ }
+ break;
+
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ case IPP_TAG_BOOLEAN :
+ case IPP_TAG_DATE :
+ case IPP_TAG_RESOLUTION :
+ case IPP_TAG_RANGE :
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ ippDelete(value->collection);
+ break;
+
+ case IPP_TAG_STRING :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ free(value->unknown.data);
+ break;
+
+ default :
+ if (!((int)attr->value_tag & IPP_TAG_COPY))
+ {
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ if (value->unknown.data)
+ free(value->unknown.data);
+ }
+ break;
+ }
+
+ if (attr->name)
+ _cupsStrFree(attr->name);
+
+ free(attr);
+}
+
+
+/*
+ * 'ipp_buffer_get()' - Get a read/write buffer.
+ */
+
+static unsigned char * /* O - Buffer */
+ipp_buffer_get(void)
+{
+ _ipp_buffer_t *buffer; /* Current buffer */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Global data */
+
+
+ for (buffer = cg->ipp_buffers; buffer; buffer = buffer->next)
+ if (!buffer->used)
+ {
+ buffer->used = 1;
+ return (buffer->d);
+ }
+
+ if ((buffer = malloc(sizeof(_ipp_buffer_t))) == NULL)
+ return (NULL);
+
+ buffer->used = 1;
+ buffer->next = cg->ipp_buffers;
+ cg->ipp_buffers = buffer;
+
+ return (buffer->d);
+}
+
+
+/*
+ * 'ipp_buffer_release()' - Release a read/write buffer.
+ */
+
+static void
+ipp_buffer_release(unsigned char *b) /* I - Buffer to release */
+{
+ ((_ipp_buffer_t *)b)->used = 0;
+}
+
+
+/*
+ * 'ipp_length()' - Compute the length of an IPP message or collection value.
+ */
+
+static size_t /* O - Size of IPP message */
+ipp_length(ipp_t *ipp, /* I - IPP message or collection */
+ int collection) /* I - 1 if a collection, 0 otherwise */
+{
+ int i; /* Looping var */
+ int bytes; /* Number of bytes */
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_tag_t group; /* Current group */
+ ipp_value_t *value; /* Current value */
+
+
+ if (ipp == NULL)
+ return (0);
+
+ /*
+ * Start with 8 bytes for the IPP message header...
+ */
+
+ bytes = collection ? 0 : 8;
+
+ /*
+ * Then add the lengths of each attribute...
+ */
+
+ group = IPP_TAG_ZERO;
+
+ for (attr = ipp->attrs; attr != NULL; attr = attr->next)
+ {
+ if (attr->group_tag != group && !collection)
+ {
+ group = attr->group_tag;
+ if (group == IPP_TAG_ZERO)
+ continue;
+
+ bytes ++; /* Group tag */
+ }
+
+ if (!attr->name)
+ continue;
+
+ DEBUG_printf(("9ipp_length: attr->name=\"%s\", attr->num_values=%d, "
+ "bytes=%d", attr->name, attr->num_values, bytes));
+
+ bytes += (int)strlen(attr->name); /* Name */
+ bytes += attr->num_values; /* Value tag for each value */
+ bytes += 2 * attr->num_values; /* Name lengths */
+ bytes += 2 * attr->num_values; /* Value lengths */
+
+ if (collection)
+ bytes += 5; /* Add membername overhead */
+
+ switch (attr->value_tag & ~IPP_TAG_COPY)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ bytes += 4 * attr->num_values;
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ bytes += attr->num_values;
+ break;
+
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ if (value->string.text != NULL)
+ bytes += (int)strlen(value->string.text);
+ break;
+
+ case IPP_TAG_DATE :
+ bytes += 11 * attr->num_values;
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ bytes += 9 * attr->num_values;
+ break;
+
+ case IPP_TAG_RANGE :
+ bytes += 8 * attr->num_values;
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ bytes += 4 * attr->num_values;/* Charset + text length */
+
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ {
+ if (value->string.charset != NULL)
+ bytes += (int)strlen(value->string.charset);
+
+ if (value->string.text != NULL)
+ bytes += (int)strlen(value->string.text);
+ }
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ bytes += (int)ipp_length(value->collection, 1);
+ break;
+
+ default :
+ for (i = 0, value = attr->values;
+ i < attr->num_values;
+ i ++, value ++)
+ bytes += value->unknown.length;
+ break;
+ }
+ }
+
+ /*
+ * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
+ * for the "end of collection" tag and return...
+ */
+
+ if (collection)
+ bytes += 5;
+ else
+ bytes ++;
+
+ DEBUG_printf(("8ipp_length: Returning %d bytes", bytes));
+
+ return (bytes);
+}
+
+
+/*
+ * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
+ */
+
+static ssize_t /* O - Number of bytes read */
+ipp_read_http(http_t *http, /* I - Client connection */
+ ipp_uchar_t *buffer, /* O - Buffer for data */
+ size_t length) /* I - Total length */
+{
+ int tbytes, /* Total bytes read */
+ bytes; /* Bytes read this pass */
+ char len[32]; /* Length string */
+
+
+ DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)",
+ http, buffer, (int)length));
+
+ /*
+ * Loop until all bytes are read...
+ */
+
+ for (tbytes = 0, bytes = 0;
+ tbytes < (int)length;
+ tbytes += bytes, buffer += bytes)
+ {
+ DEBUG_printf(("9ipp_read_http: tbytes=%d, http->state=%d", tbytes,
+ http->state));
+
+ if (http->state == HTTP_WAITING)
+ break;
+
+ if (http->used > 0 && http->data_encoding == HTTP_ENCODE_LENGTH)
+ {
+ /*
+ * Do "fast read" from HTTP buffer directly...
+ */
+
+ if (http->used > (int)(length - tbytes))
+ bytes = (int)(length - tbytes);
+ else
+ bytes = http->used;
+
+ if (bytes == 1)
+ buffer[0] = http->buffer[0];
+ else
+ memcpy(buffer, http->buffer, bytes);
+
+ http->used -= bytes;
+ http->data_remaining -= bytes;
+
+ if (http->data_remaining <= INT_MAX)
+ http->_data_remaining = (int)http->data_remaining;
+ else
+ http->_data_remaining = INT_MAX;
+
+ if (http->used > 0)
+ memmove(http->buffer, http->buffer + bytes, http->used);
+
+ if (http->data_remaining == 0)
+ {
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED)
+ {
+ /*
+ * Get the trailing CR LF after the chunk...
+ */
+
+ if (!httpGets(len, sizeof(len), http))
+ return (-1);
+ }
+
+ if (http->data_encoding != HTTP_ENCODE_CHUNKED)
+ {
+ if (http->state == HTTP_POST_RECV)
+ http->state ++;
+ else
+ http->state = HTTP_WAITING;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Wait a maximum of 1 second for data...
+ */
+
+ if (!http->blocking)
+ {
+ /*
+ * Wait up to 10 seconds for more data on non-blocking sockets...
+ */
+
+ if (!httpWait(http, 10000))
+ {
+ /*
+ * Signal no data...
+ */
+
+ bytes = -1;
+ break;
+ }
+ }
+
+ if ((bytes = httpRead2(http, (char *)buffer, length - tbytes)) < 0)
+ {
+#ifdef WIN32
+ break;
+#else
+ if (errno != EAGAIN && errno != EINTR)
+ break;
+
+ bytes = 0;
+#endif /* WIN32 */
+ }
+ else if (bytes == 0)
+ break;
+ }
+ }
+
+ /*
+ * Return the number of bytes read...
+ */
+
+ if (tbytes == 0 && bytes < 0)
+ tbytes = -1;
+
+ DEBUG_printf(("8ipp_read_http: Returning %d bytes", tbytes));
+
+ return (tbytes);
+}
+
+
+/*
+ * 'ipp_read_file()' - Read IPP data from a file.
+ */
+
+static ssize_t /* O - Number of bytes read */
+ipp_read_file(int *fd, /* I - File descriptor */
+ ipp_uchar_t *buffer, /* O - Read buffer */
+ size_t length) /* I - Number of bytes to read */
+{
+#ifdef WIN32
+ return ((ssize_t)read(*fd, buffer, (unsigned)length));
+#else
+ return (read(*fd, buffer, length));
+#endif /* WIN32 */
+}
+
+
+/*
+ * 'ipp_write_file()' - Write IPP data to a file.
+ */
+
+static ssize_t /* O - Number of bytes written */
+ipp_write_file(int *fd, /* I - File descriptor */
+ ipp_uchar_t *buffer, /* I - Data to write */
+ size_t length) /* I - Number of bytes to write */
+{
+#ifdef WIN32
+ return ((ssize_t)write(*fd, buffer, (unsigned)length));
+#else
+ return (write(*fd, buffer, length));
+#endif /* WIN32 */
+}
+
+
+#ifdef __linux
+/*
+ * The following symbol definitions are provided only for KDE
+ * compatibility during the CUPS 1.2 testing period and will be
+ * removed in a future release of CUPS. These are PRIVATE APIs
+ * from CUPS 1.1.x that the KDE developers chose to use...
+ */
+
+ipp_attribute_t * /* O - New attribute */
+_ipp_add_attr(ipp_t *ipp, /* I - IPP message */
+ int num_values) /* I - Number of values */
+{
+ return (_ippAddAttr(ipp, num_values));
+}
+
+void
+_ipp_free_attr(ipp_attribute_t *attr) /* I - Attribute to free */
+{
+ _ippFreeAttr(attr);
+}
+#endif /* __linux */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/ipp.h b/cups/ipp.h
new file mode 100644
index 000000000..b3e9eb92e
--- /dev/null
+++ b/cups/ipp.h
@@ -0,0 +1,518 @@
+/*
+ * "$Id$"
+ *
+ * Internet Printing Protocol definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_IPP_H_
+# define _CUPS_IPP_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include "http.h"
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * IPP version string...
+ */
+
+# define IPP_VERSION "\002\001"
+
+/*
+ * IPP registered port number...
+ *
+ * Note: Applications should never use IPP_PORT, but instead use the
+ * ippPort() function to allow overrides via the IPP_PORT environment
+ * variable and services file if needed!
+ */
+
+# define IPP_PORT 631
+
+/*
+ * Common limits...
+ */
+
+# define IPP_MAX_LENGTH 32767 /* Maximum size of any single value */
+# define IPP_MAX_NAME 256 /* Maximum length of common name values */
+# define IPP_MAX_VALUES 8 /* Power-of-2 allocation increment */
+
+
+/*
+ * Types and structures...
+ */
+
+typedef enum ipp_tag_e /**** Format tags for attributes ****/
+{
+ IPP_TAG_ZERO = 0x00, /* Zero tag - used for separators */
+ IPP_TAG_OPERATION, /* Operation group */
+ IPP_TAG_JOB, /* Job group */
+ IPP_TAG_END, /* End-of-attributes */
+ IPP_TAG_PRINTER, /* Printer group */
+ IPP_TAG_UNSUPPORTED_GROUP, /* Unsupported attributes group */
+ IPP_TAG_SUBSCRIPTION, /* Subscription group */
+ IPP_TAG_EVENT_NOTIFICATION, /* Event group */
+ IPP_TAG_UNSUPPORTED_VALUE = 0x10, /* Unsupported value */
+ IPP_TAG_DEFAULT, /* Default value */
+ IPP_TAG_UNKNOWN, /* Unknown value */
+ IPP_TAG_NOVALUE, /* No-value value */
+ IPP_TAG_NOTSETTABLE = 0x15, /* Not-settable value */
+ IPP_TAG_DELETEATTR, /* Delete-attribute value */
+ IPP_TAG_ADMINDEFINE, /* Admin-defined value */
+ IPP_TAG_INTEGER = 0x21, /* Integer value */
+ IPP_TAG_BOOLEAN, /* Boolean value */
+ IPP_TAG_ENUM, /* Enumeration value */
+ IPP_TAG_STRING = 0x30, /* Octet string value */
+ IPP_TAG_DATE, /* Date/time value */
+ IPP_TAG_RESOLUTION, /* Resolution value */
+ IPP_TAG_RANGE, /* Range value */
+ IPP_TAG_BEGIN_COLLECTION, /* Beginning of collection value */
+ IPP_TAG_TEXTLANG, /* Text-with-language value */
+ IPP_TAG_NAMELANG, /* Name-with-language value */
+ IPP_TAG_END_COLLECTION, /* End of collection value */
+ IPP_TAG_TEXT = 0x41, /* Text value */
+ IPP_TAG_NAME, /* Name value */
+ IPP_TAG_RESERVED_STRING, /* Reserved for future string value @private@ */
+ IPP_TAG_KEYWORD, /* Keyword value */
+ IPP_TAG_URI, /* URI value */
+ IPP_TAG_URISCHEME, /* URI scheme value */
+ IPP_TAG_CHARSET, /* Character set value */
+ IPP_TAG_LANGUAGE, /* Language value */
+ IPP_TAG_MIMETYPE, /* MIME media type value */
+ IPP_TAG_MEMBERNAME, /* Collection member name value */
+ IPP_TAG_MASK = 0x7fffffff, /* Mask for copied attribute values */
+ IPP_TAG_COPY = -0x7fffffff-1 /* Bitflag for copied attribute values */
+} ipp_tag_t;
+
+typedef enum ipp_res_e /**** Resolution units ****/
+{
+ IPP_RES_PER_INCH = 3, /* Pixels per inch */
+ IPP_RES_PER_CM /* Pixels per centimeter */
+} ipp_res_t;
+
+typedef enum ipp_finish_e /**** Finishings ****/
+{
+ IPP_FINISHINGS_NONE = 3, /* No finishing */
+ IPP_FINISHINGS_STAPLE, /* Staple (any location) */
+ IPP_FINISHINGS_PUNCH, /* Punch (any location/count) */
+ IPP_FINISHINGS_COVER, /* Add cover */
+ IPP_FINISHINGS_BIND, /* Bind */
+ IPP_FINISHINGS_SADDLE_STITCH, /* Staple interior */
+ IPP_FINISHINGS_EDGE_STITCH, /* Stitch along any side */
+ IPP_FINISHINGS_FOLD, /* Fold (any type) */
+ IPP_FINISHINGS_TRIM, /* Trim (any type) */
+ IPP_FINISHINGS_BALE, /* Bale (any type) */
+ IPP_FINISHINGS_BOOKLET_MAKER, /* Fold to make booklet */
+ IPP_FINISHINGS_JOB_OFFSET, /* Offset for binding (any type) */
+ IPP_FINISHINGS_STAPLE_TOP_LEFT = 20, /* Staple top left corner */
+ IPP_FINISHINGS_STAPLE_BOTTOM_LEFT, /* Staple bottom left corner */
+ IPP_FINISHINGS_STAPLE_TOP_RIGHT, /* Staple top right corner */
+ IPP_FINISHINGS_STAPLE_BOTTOM_RIGHT, /* Staple bottom right corner */
+ IPP_FINISHINGS_EDGE_STITCH_LEFT, /* Stitch along left side */
+ IPP_FINISHINGS_EDGE_STITCH_TOP, /* Stitch along top edge */
+ IPP_FINISHINGS_EDGE_STITCH_RIGHT, /* Stitch along right side */
+ IPP_FINISHINGS_EDGE_STITCH_BOTTOM, /* Stitch along bottom edge */
+ IPP_FINISHINGS_STAPLE_DUAL_LEFT, /* Two staples on left */
+ IPP_FINISHINGS_STAPLE_DUAL_TOP, /* Two staples on top */
+ IPP_FINISHINGS_STAPLE_DUAL_RIGHT, /* Two staples on right */
+ IPP_FINISHINGS_STAPLE_DUAL_BOTTOM, /* Two staples on bottom */
+ IPP_FINISHINGS_BIND_LEFT = 50, /* Bind on left */
+ IPP_FINISHINGS_BIND_TOP, /* Bind on top */
+ IPP_FINISHINGS_BIND_RIGHT, /* Bind on right */
+ IPP_FINISHINGS_BIND_BOTTOM /* Bind on bottom */
+} ipp_finish_t;
+
+typedef enum ipp_orient_e /**** Orientation values ****/
+{
+ IPP_PORTRAIT = 3, /* No rotation */
+ IPP_LANDSCAPE, /* 90 degrees counter-clockwise */
+ IPP_REVERSE_LANDSCAPE, /* 90 degrees clockwise */
+ IPP_REVERSE_PORTRAIT /* 180 degrees */
+} ipp_orient_t;
+
+typedef enum ipp_quality_e /**** Qualities ****/
+{
+ IPP_QUALITY_DRAFT = 3, /* Draft quality */
+ IPP_QUALITY_NORMAL, /* Normal quality */
+ IPP_QUALITY_HIGH /* High quality */
+} ipp_quality_t;
+
+typedef enum ipp_jstate_e /**** Job states ****/
+{
+ IPP_JOB_PENDING = 3, /* Job is waiting to be printed */
+ IPP_JOB_HELD, /* Job is held for printing */
+ IPP_JOB_PROCESSING, /* Job is currently printing */
+ IPP_JOB_STOPPED, /* Job has been stopped */
+ IPP_JOB_CANCELED, /* Job has been canceled */
+ IPP_JOB_ABORTED, /* Job has aborted due to error */
+ IPP_JOB_COMPLETED /* Job has completed successfully */
+} ipp_jstate_t;
+#define IPP_JOB_CANCELLED IPP_JOB_CANCELED
+
+typedef enum ipp_pstate_e /**** Printer states ****/
+{
+ IPP_PRINTER_IDLE = 3, /* Printer is idle */
+ IPP_PRINTER_PROCESSING, /* Printer is working */
+ IPP_PRINTER_STOPPED /* Printer is stopped */
+} ipp_pstate_t;
+
+typedef enum ipp_state_e /**** IPP states ****/
+{
+ IPP_ERROR = -1, /* An error occurred */
+ IPP_IDLE, /* Nothing is happening/request completed */
+ IPP_HEADER, /* The request header needs to be sent/received */
+ IPP_ATTRIBUTE, /* One or more attributes need to be sent/received */
+ IPP_DATA /* IPP request data needs to be sent/received */
+} ipp_state_t;
+
+typedef enum ipp_op_e /**** IPP operations ****/
+{
+ IPP_PRINT_JOB = 0x0002, /* Print a single file */
+ IPP_PRINT_URI, /* Print a single URL @private@ */
+ IPP_VALIDATE_JOB, /* Validate job options */
+ IPP_CREATE_JOB, /* Create an empty print job */
+ IPP_SEND_DOCUMENT, /* Add a file to a job */
+ IPP_SEND_URI, /* Add a URL to a job @private@ */
+ IPP_CANCEL_JOB, /* Cancel a job */
+ IPP_GET_JOB_ATTRIBUTES, /* Get job attributes */
+ IPP_GET_JOBS, /* Get a list of jobs */
+ IPP_GET_PRINTER_ATTRIBUTES, /* Get printer attributes */
+ IPP_HOLD_JOB, /* Hold a job for printing */
+ IPP_RELEASE_JOB, /* Release a job for printing */
+ IPP_RESTART_JOB, /* Reprint a job */
+ IPP_PAUSE_PRINTER = 0x0010, /* Stop a printer */
+ IPP_RESUME_PRINTER, /* Start a printer */
+ IPP_PURGE_JOBS, /* Cancel all jobs */
+ IPP_SET_PRINTER_ATTRIBUTES, /* Set printer attributes @private@ */
+ IPP_SET_JOB_ATTRIBUTES, /* Set job attributes */
+ IPP_GET_PRINTER_SUPPORTED_VALUES, /* Get supported attribute values */
+ IPP_CREATE_PRINTER_SUBSCRIPTION, /* Create a printer subscription @since CUPS 1.2/Mac OS X 10.5@ */
+ IPP_CREATE_JOB_SUBSCRIPTION, /* Create a job subscription @since CUPS 1.2/Mac OS X 10.5@ */
+ IPP_GET_SUBSCRIPTION_ATTRIBUTES, /* Get subscription attributes @since CUPS 1.2/Mac OS X 10.5@ */
+ IPP_GET_SUBSCRIPTIONS, /* Get list of subscriptions @since CUPS 1.2/Mac OS X 10.5@ */
+ IPP_RENEW_SUBSCRIPTION, /* Renew a printer subscription @since CUPS 1.2/Mac OS X 10.5@ */
+ IPP_CANCEL_SUBSCRIPTION, /* Cancel a subscription @since CUPS 1.2/Mac OS X 10.5@ */
+ IPP_GET_NOTIFICATIONS, /* Get notification events @since CUPS 1.2/Mac OS X 10.5@ */
+ IPP_SEND_NOTIFICATIONS, /* Send notification events @private@ */
+ IPP_GET_PRINT_SUPPORT_FILES = 0x0021, /* Get printer support files @private@ */
+ IPP_ENABLE_PRINTER, /* Start a printer */
+ IPP_DISABLE_PRINTER, /* Stop a printer */
+ IPP_PAUSE_PRINTER_AFTER_CURRENT_JOB, /* Stop printer after the current job @private@ */
+ IPP_HOLD_NEW_JOBS, /* Hold new jobs @private@ */
+ IPP_RELEASE_HELD_NEW_JOBS, /* Release new jobs @private@ */
+ IPP_DEACTIVATE_PRINTER, /* Stop a printer @private@ */
+ IPP_ACTIVATE_PRINTER, /* Start a printer @private@ */
+ IPP_RESTART_PRINTER, /* Restart a printer @private@ */
+ IPP_SHUTDOWN_PRINTER, /* Turn a printer off @private@ */
+ IPP_STARTUP_PRINTER, /* Turn a printer on @private@ */
+ IPP_REPROCESS_JOB, /* Reprint a job @private@ */
+ IPP_CANCEL_CURRENT_JOB, /* Cancel the current job @private@ */
+ IPP_SUSPEND_CURRENT_JOB, /* Suspend the current job @private@ */
+ IPP_RESUME_JOB, /* Resume the current job @private@ */
+ IPP_PROMOTE_JOB, /* Promote a job to print sooner @private@ */
+ IPP_SCHEDULE_JOB_AFTER, /* Schedule a job to print after another @private@ */
+ IPP_CANCEL_DOCUMENT = 0x0033, /* Cancel-Document @private@ */
+ IPP_GET_DOCUMENT_ATTRIBUTES, /* Get-Document-Attributes @private@ */
+ IPP_GET_DOCUMENTS, /* Get-Documents @private@ */
+ IPP_DELETE_DOCUMENT, /* Delete-Document @private@ */
+ IPP_SET_DOCUMENT_ATTRIBUTES, /* Set-Document-Attributes @private@ */
+ IPP_CANCEL_JOBS, /* Cancel-Jobs */
+ IPP_CANCEL_MY_JOBS, /* Cancel-My-Jobs */
+ IPP_RESUBMIT_JOB, /* Resubmit-Job */
+ IPP_CLOSE_JOB, /* Close-Job */
+ IPP_PRIVATE = 0x4000, /* Reserved @private@ */
+ CUPS_GET_DEFAULT, /* Get the default printer */
+ CUPS_GET_PRINTERS, /* Get a list of printers and/or classes */
+ CUPS_ADD_MODIFY_PRINTER, /* Add or modify a printer */
+ CUPS_DELETE_PRINTER, /* Delete a printer */
+ CUPS_GET_CLASSES, /* Get a list of classes @deprecated@ */
+ CUPS_ADD_MODIFY_CLASS, /* Add or modify a class */
+ CUPS_DELETE_CLASS, /* Delete a class */
+ CUPS_ACCEPT_JOBS, /* Accept new jobs on a printer */
+ CUPS_REJECT_JOBS, /* Reject new jobs on a printer */
+ CUPS_SET_DEFAULT, /* Set the default printer */
+ CUPS_GET_DEVICES, /* Get a list of supported devices */
+ CUPS_GET_PPDS, /* Get a list of supported drivers */
+ CUPS_MOVE_JOB, /* Move a job to a different printer */
+ CUPS_AUTHENTICATE_JOB, /* Authenticate a job @since CUPS 1.2/Mac OS X 10.5@ */
+ CUPS_GET_PPD, /* Get a PPD file @since CUPS 1.3/Mac OS X 10.5@ */
+ CUPS_GET_DOCUMENT = 0x4027 /* Get a document file @since CUPS 1.4/Mac OS X 10.6@ */
+} ipp_op_t;
+
+/* Old names for the operations */
+#define CUPS_ADD_PRINTER CUPS_ADD_MODIFY_PRINTER
+#define CUPS_ADD_CLASS CUPS_ADD_MODIFY_CLASS
+
+typedef enum ipp_status_e /**** IPP status codes ****/
+{
+ IPP_OK = 0x0000, /* successful-ok */
+ IPP_OK_SUBST, /* successful-ok-ignored-or-substituted-attributes */
+ IPP_OK_CONFLICT, /* successful-ok-conflicting-attributes */
+ IPP_OK_IGNORED_SUBSCRIPTIONS, /* successful-ok-ignored-subscriptions */
+ IPP_OK_IGNORED_NOTIFICATIONS, /* successful-ok-ignored-notifications */
+ IPP_OK_TOO_MANY_EVENTS, /* successful-ok-too-many-events */
+ IPP_OK_BUT_CANCEL_SUBSCRIPTION, /* successful-ok-but-cancel-subscription */
+ IPP_OK_EVENTS_COMPLETE, /* successful-ok-events-complete */
+ IPP_REDIRECTION_OTHER_SITE = 0x200, /* redirection-other-site @private@ */
+ CUPS_SEE_OTHER = 0x280, /* cups-see-other */
+ IPP_BAD_REQUEST = 0x0400, /* client-error-bad-request */
+ IPP_FORBIDDEN, /* client-error-forbidden */
+ IPP_NOT_AUTHENTICATED, /* client-error-not-authenticated */
+ IPP_NOT_AUTHORIZED, /* client-error-not-authorized */
+ IPP_NOT_POSSIBLE, /* client-error-not-possible */
+ IPP_TIMEOUT, /* client-error-timeout */
+ IPP_NOT_FOUND, /* client-error-not-found */
+ IPP_GONE, /* client-error-gone */
+ IPP_REQUEST_ENTITY, /* client-error-request-entity-too-large */
+ IPP_REQUEST_VALUE, /* client-error-request-value-too-long */
+ IPP_DOCUMENT_FORMAT, /* client-error-document-format-not-supported */
+ IPP_ATTRIBUTES, /* client-error-attributes-or-values-not-supported */
+ IPP_URI_SCHEME, /* client-error-uri-scheme-not-supported */
+ IPP_CHARSET, /* client-error-charset-not-supported */
+ IPP_CONFLICT, /* client-error-conflicting-attributes */
+ IPP_COMPRESSION_NOT_SUPPORTED, /* client-error-compression-not-supported */
+ IPP_COMPRESSION_ERROR, /* client-error-compression-error */
+ IPP_DOCUMENT_FORMAT_ERROR, /* client-error-document-format-error */
+ IPP_DOCUMENT_ACCESS_ERROR, /* client-error-document-access-error */
+ IPP_ATTRIBUTES_NOT_SETTABLE, /* client-error-attributes-not-settable */
+ IPP_IGNORED_ALL_SUBSCRIPTIONS, /* client-error-ignored-all-subscriptions */
+ IPP_TOO_MANY_SUBSCRIPTIONS, /* client-error-too-many-subscriptions */
+ IPP_IGNORED_ALL_NOTIFICATIONS, /* client-error-ignored-all-notifications */
+ IPP_PRINT_SUPPORT_FILE_NOT_FOUND, /* client-error-print-support-file-not-found */
+
+ IPP_INTERNAL_ERROR = 0x0500, /* server-error-internal-error */
+ IPP_OPERATION_NOT_SUPPORTED, /* server-error-operation-not-supported */
+ IPP_SERVICE_UNAVAILABLE, /* server-error-service-unavailable */
+ IPP_VERSION_NOT_SUPPORTED, /* server-error-version-not-supported */
+ IPP_DEVICE_ERROR, /* server-error-device-error */
+ IPP_TEMPORARY_ERROR, /* server-error-temporary-error */
+ IPP_NOT_ACCEPTING, /* server-error-not-accepting-jobs */
+ IPP_PRINTER_BUSY, /* server-error-busy */
+ IPP_ERROR_JOB_CANCELED, /* server-error-job-canceled */
+ IPP_MULTIPLE_JOBS_NOT_SUPPORTED, /* server-error-multiple-document-jobs-not-supported */
+ IPP_PRINTER_IS_DEACTIVATED, /* server-error-printer-is-deactivated */
+
+ IPP_AUTHENTICATION_CANCELED = 0x1000, /* Authentication canceled by user @since CUPS 1.5/Mac OS X 10.7@ */
+ IPP_PKI_ERROR, /* Error negotiating a secure connection @since CUPS 1.5/Mac OS X 10.7@ */
+ IPP_UPGRADE_REQUIRED /* TLS upgrade required */
+} ipp_status_t;
+#define IPP_ERROR_JOB_CANCELLED IPP_ERROR_JOB_CANCELED
+
+typedef unsigned char ipp_uchar_t; /**** Unsigned 8-bit integer/character ****/
+
+/**** New in CUPS 1.2 ****/
+typedef ssize_t (*ipp_iocb_t)(void *, ipp_uchar_t *, size_t);
+ /**** IPP IO Callback Function @since CUPS 1.2/Mac OS X 10.5@ ****/
+
+typedef union ipp_request_u /**** Request Header ****/
+{
+ struct /* Any Header */
+ {
+ ipp_uchar_t version[2]; /* Protocol version number */
+ int op_status; /* Operation ID or status code*/
+ int request_id; /* Request ID */
+ } any;
+
+ struct /* Operation Header */
+ {
+ ipp_uchar_t version[2]; /* Protocol version number */
+ ipp_op_t operation_id; /* Operation ID */
+ int request_id; /* Request ID */
+ } op;
+
+ struct /* Status Header */
+ {
+ ipp_uchar_t version[2]; /* Protocol version number */
+ ipp_status_t status_code; /* Status code */
+ int request_id; /* Request ID */
+ } status;
+
+ /**** New in CUPS 1.1.19 ****/
+ struct /* Event Header @since CUPS 1.1.19/Mac OS X 10.3@ */
+ {
+ ipp_uchar_t version[2]; /* Protocol version number */
+ ipp_status_t status_code; /* Status code */
+ int request_id; /* Request ID */
+ } event;
+} ipp_request_t;
+
+/**** New in CUPS 1.1.19 ****/
+typedef struct ipp_s ipp_t;
+
+typedef union ipp_value_u /**** Attribute Value ****/
+{
+ int integer; /* Integer/enumerated value */
+
+ char boolean; /* Boolean value */
+
+ ipp_uchar_t date[11]; /* Date/time value */
+
+ struct
+ {
+ int xres, /* Horizontal resolution */
+ yres; /* Vertical resolution */
+ ipp_res_t units; /* Resolution units */
+ } resolution; /* Resolution value */
+
+ struct
+ {
+ int lower, /* Lower value */
+ upper; /* Upper value */
+ } range; /* Range of integers value */
+
+ struct
+ {
+ char *charset; /* Character set */
+ char *text; /* String */
+ } string; /* String with language value */
+
+ struct
+ {
+ int length; /* Length of attribute */
+ void *data; /* Data in attribute */
+ } unknown; /* Unknown attribute type */
+
+/**** New in CUPS 1.1.19 ****/
+ ipp_t *collection; /* Collection value @since CUPS 1.1.19/Mac OS X 10.3@ */
+} ipp_value_t;
+
+typedef struct ipp_attribute_s /**** Attribute ****/
+{
+ struct ipp_attribute_s *next; /* Next attribute in list */
+ ipp_tag_t group_tag, /* Job/Printer/Operation group tag */
+ value_tag; /* What type of value is it? */
+ char *name; /* Name of attribute */
+ int num_values; /* Number of values */
+ ipp_value_t values[1]; /* Values */
+} ipp_attribute_t;
+
+struct ipp_s /**** IPP Request/Response/Notification ****/
+{
+ ipp_state_t state; /* State of request */
+ ipp_request_t request; /* Request header */
+ ipp_attribute_t *attrs; /* Attributes */
+ ipp_attribute_t *last; /* Last attribute in list */
+ ipp_attribute_t *current; /* Current attribute (for read/write) */
+ ipp_tag_t curtag; /* Current attribute group tag */
+
+/**** New in CUPS 1.2 ****/
+ ipp_attribute_t *prev; /* Previous attribute (for read) @since CUPS 1.2/Mac OS X 10.5@ */
+
+/**** New in CUPS 1.4.4 ****/
+ int use; /* Use count @since CUPS 1.4.4/Mac OS X 10.6.?@ */
+};
+
+
+/*
+ * Prototypes...
+ */
+
+extern ipp_attribute_t *ippAddBoolean(ipp_t *ipp, ipp_tag_t group,
+ const char *name, char value);
+extern ipp_attribute_t *ippAddBooleans(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int num_values,
+ const char *values);
+extern ipp_attribute_t *ippAddDate(ipp_t *ipp, ipp_tag_t group,
+ const char *name, const ipp_uchar_t *value);
+extern ipp_attribute_t *ippAddInteger(ipp_t *ipp, ipp_tag_t group,
+ ipp_tag_t type, const char *name,
+ int value);
+extern ipp_attribute_t *ippAddIntegers(ipp_t *ipp, ipp_tag_t group,
+ ipp_tag_t type, const char *name,
+ int num_values, const int *values);
+extern ipp_attribute_t *ippAddRange(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int lower, int upper);
+extern ipp_attribute_t *ippAddRanges(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int num_values,
+ const int *lower, const int *upper);
+extern ipp_attribute_t *ippAddResolution(ipp_t *ipp, ipp_tag_t group,
+ const char *name, ipp_res_t units,
+ int xres, int yres);
+extern ipp_attribute_t *ippAddResolutions(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int num_values,
+ ipp_res_t units, const int *xres,
+ const int *yres);
+extern ipp_attribute_t *ippAddSeparator(ipp_t *ipp);
+extern ipp_attribute_t *ippAddString(ipp_t *ipp, ipp_tag_t group,
+ ipp_tag_t type, const char *name,
+ const char *charset, const char *value);
+extern ipp_attribute_t *ippAddStrings(ipp_t *ipp, ipp_tag_t group,
+ ipp_tag_t type, const char *name,
+ int num_values, const char *charset,
+ const char * const *values);
+extern time_t ippDateToTime(const ipp_uchar_t *date);
+extern void ippDelete(ipp_t *ipp);
+extern const char *ippErrorString(ipp_status_t error);
+extern ipp_attribute_t *ippFindAttribute(ipp_t *ipp, const char *name,
+ ipp_tag_t type);
+extern ipp_attribute_t *ippFindNextAttribute(ipp_t *ipp, const char *name,
+ ipp_tag_t type);
+extern size_t ippLength(ipp_t *ipp);
+extern ipp_t *ippNew(void);
+extern ipp_state_t ippRead(http_t *http, ipp_t *ipp);
+extern const ipp_uchar_t *ippTimeToDate(time_t t);
+extern ipp_state_t ippWrite(http_t *http, ipp_t *ipp);
+extern int ippPort(void);
+extern void ippSetPort(int p);
+
+/**** New in CUPS 1.1.19 ****/
+extern ipp_attribute_t *ippAddCollection(ipp_t *ipp, ipp_tag_t group,
+ const char *name, ipp_t *value) _CUPS_API_1_1_19;
+extern ipp_attribute_t *ippAddCollections(ipp_t *ipp, ipp_tag_t group,
+ const char *name, int num_values,
+ const ipp_t **values) _CUPS_API_1_1_19;
+extern void ippDeleteAttribute(ipp_t *ipp, ipp_attribute_t *attr) _CUPS_API_1_1_19;
+extern ipp_state_t ippReadFile(int fd, ipp_t *ipp) _CUPS_API_1_1_19;
+extern ipp_state_t ippWriteFile(int fd, ipp_t *ipp) _CUPS_API_1_1_19;
+
+/**** New in CUPS 1.2 ****/
+extern ipp_attribute_t *ippAddOctetString(ipp_t *ipp, ipp_tag_t group,
+ const char *name,
+ const void *data, int datalen) _CUPS_API_1_2;
+extern ipp_status_t ippErrorValue(const char *name) _CUPS_API_1_2;
+extern ipp_t *ippNewRequest(ipp_op_t op) _CUPS_API_1_2;
+extern const char *ippOpString(ipp_op_t op) _CUPS_API_1_2;
+extern ipp_op_t ippOpValue(const char *name) _CUPS_API_1_2;
+extern ipp_state_t ippReadIO(void *src, ipp_iocb_t cb, int blocking,
+ ipp_t *parent, ipp_t *ipp) _CUPS_API_1_2;
+extern ipp_state_t ippWriteIO(void *dst, ipp_iocb_t cb, int blocking,
+ ipp_t *parent, ipp_t *ipp) _CUPS_API_1_2;
+
+/**** New in CUPS 1.4 ****/
+extern const char *ippTagString(ipp_tag_t tag) _CUPS_API_1_4;
+extern ipp_tag_t ippTagValue(const char *name) _CUPS_API_1_4;
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_IPP_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/langprintf.c b/cups/langprintf.c
new file mode 100644
index 000000000..9a308dbf2
--- /dev/null
+++ b/cups/langprintf.c
@@ -0,0 +1,352 @@
+/*
+ * "$Id$"
+ *
+ * Localized printf/puts functions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2002-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsLangPrintError() - Print a message followed by a standard error.
+ * _cupsLangPrintFilter() - Print a formatted filter message string to a file.
+ * _cupsLangPrintf() - Print a formatted message string to a file.
+ * _cupsLangPuts() - Print a static message string to a file.
+ * _cupsSetLocale() - Set the current locale and transcode the
+ * command-line.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+
+
+/*
+ * '_cupsLangPrintError()' - Print a message followed by a standard error.
+ */
+
+void
+_cupsLangPrintError(const char *prefix, /* I - Non-localized message prefix */
+ const char *message)/* I - Message */
+{
+ int bytes; /* Number of bytes formatted */
+ int last_errno; /* Last error */
+ char buffer[2048], /* Message buffer */
+ *bufptr, /* Pointer into buffer */
+ output[8192]; /* Output buffer */
+ _cups_globals_t *cg; /* Global data */
+
+
+ /*
+ * Range check...
+ */
+
+ if (!message)
+ return;
+
+ /*
+ * Save the errno value...
+ */
+
+ last_errno = errno;
+
+ /*
+ * Get the message catalog...
+ */
+
+ cg = _cupsGlobals();
+
+ if (!cg->lang_default)
+ cg->lang_default = cupsLangDefault();
+
+ /*
+ * Format the message...
+ */
+
+ if (prefix)
+ {
+ snprintf(buffer, sizeof(buffer), "%s:", prefix);
+ bufptr = buffer + strlen(buffer);
+ }
+ else
+ bufptr = buffer;
+
+ snprintf(bufptr, sizeof(buffer) - (bufptr - buffer),
+ /* TRANSLATORS: Message is "subject: error" */
+ _cupsLangString(cg->lang_default, _("%s: %s")),
+ _cupsLangString(cg->lang_default, message), strerror(last_errno));
+ strlcat(buffer, "\n", sizeof(buffer));
+
+ /*
+ * Convert and write to stderr...
+ */
+
+ bytes = cupsUTF8ToCharset(output, (cups_utf8_t *)buffer, sizeof(output),
+ cg->lang_default->encoding);
+
+ if (bytes > 0)
+ fwrite(output, 1, bytes, stderr);
+}
+
+
+/*
+ * '_cupsLangPrintFilter()' - Print a formatted filter message string to a file.
+ */
+
+int /* O - Number of bytes written */
+_cupsLangPrintFilter(
+ FILE *fp, /* I - File to write to */
+ const char *prefix, /* I - Non-localized message prefix */
+ const char *message, /* I - Message string to use */
+ ...) /* I - Additional arguments as needed */
+{
+ int bytes; /* Number of bytes formatted */
+ char temp[2048], /* Temporary format buffer */
+ buffer[2048], /* Message buffer */
+ output[8192]; /* Output buffer */
+ va_list ap; /* Pointer to additional arguments */
+ _cups_globals_t *cg; /* Global data */
+
+
+ /*
+ * Range check...
+ */
+
+ if (!fp || !message)
+ return (-1);
+
+ cg = _cupsGlobals();
+
+ if (!cg->lang_default)
+ cg->lang_default = cupsLangDefault();
+
+ /*
+ * Format the string...
+ */
+
+ va_start(ap, message);
+ snprintf(temp, sizeof(temp), "%s: %s\n", prefix,
+ _cupsLangString(cg->lang_default, message));
+ vsnprintf(buffer, sizeof(buffer), temp, ap);
+ va_end(ap);
+
+ /*
+ * Transcode to the destination charset...
+ */
+
+ bytes = cupsUTF8ToCharset(output, (cups_utf8_t *)buffer, sizeof(output),
+ cg->lang_default->encoding);
+
+ /*
+ * Write the string and return the number of bytes written...
+ */
+
+ if (bytes > 0)
+ return ((int)fwrite(output, 1, bytes, fp));
+ else
+ return (bytes);
+}
+
+
+/*
+ * '_cupsLangPrintf()' - Print a formatted message string to a file.
+ */
+
+int /* O - Number of bytes written */
+_cupsLangPrintf(FILE *fp, /* I - File to write to */
+ const char *message, /* I - Message string to use */
+ ...) /* I - Additional arguments as needed */
+{
+ int bytes; /* Number of bytes formatted */
+ char buffer[2048], /* Message buffer */
+ output[8192]; /* Output buffer */
+ va_list ap; /* Pointer to additional arguments */
+ _cups_globals_t *cg; /* Global data */
+
+
+ /*
+ * Range check...
+ */
+
+ if (!fp || !message)
+ return (-1);
+
+ cg = _cupsGlobals();
+
+ if (!cg->lang_default)
+ cg->lang_default = cupsLangDefault();
+
+ /*
+ * Format the string...
+ */
+
+ va_start(ap, message);
+ vsnprintf(buffer, sizeof(buffer) - 1,
+ _cupsLangString(cg->lang_default, message), ap);
+ va_end(ap);
+
+ strlcat(buffer, "\n", sizeof(buffer));
+
+ /*
+ * Transcode to the destination charset...
+ */
+
+ bytes = cupsUTF8ToCharset(output, (cups_utf8_t *)buffer, sizeof(output),
+ cg->lang_default->encoding);
+
+ /*
+ * Write the string and return the number of bytes written...
+ */
+
+ if (bytes > 0)
+ return ((int)fwrite(output, 1, bytes, fp));
+ else
+ return (bytes);
+}
+
+
+/*
+ * '_cupsLangPuts()' - Print a static message string to a file.
+ */
+
+int /* O - Number of bytes written */
+_cupsLangPuts(FILE *fp, /* I - File to write to */
+ const char *message) /* I - Message string to use */
+{
+ int bytes; /* Number of bytes formatted */
+ char output[8192]; /* Message buffer */
+ _cups_globals_t *cg; /* Global data */
+
+
+ /*
+ * Range check...
+ */
+
+ if (!fp || !message)
+ return (-1);
+
+ cg = _cupsGlobals();
+
+ if (!cg->lang_default)
+ cg->lang_default = cupsLangDefault();
+
+ /*
+ * Transcode to the destination charset...
+ */
+
+ bytes = cupsUTF8ToCharset(output,
+ (cups_utf8_t *)_cupsLangString(cg->lang_default,
+ message),
+ sizeof(output) - 4, cg->lang_default->encoding);
+ bytes += cupsUTF8ToCharset(output + bytes, (cups_utf8_t *)"\n",
+ sizeof(output) - bytes,
+ cg->lang_default->encoding);
+
+ /*
+ * Write the string and return the number of bytes written...
+ */
+
+ if (bytes > 0)
+ return ((int)fwrite(output, 1, bytes, fp));
+ else
+ return (bytes);
+}
+
+
+/*
+ * '_cupsSetLocale()' - Set the current locale and transcode the command-line.
+ */
+
+void
+_cupsSetLocale(char *argv[]) /* IO - Command-line arguments */
+{
+ int i; /* Looping var */
+ char buffer[8192]; /* Command-line argument buffer */
+ _cups_globals_t *cg; /* Global data */
+#ifdef LC_TIME
+ const char *lc_time; /* Current LC_TIME value */
+ char new_lc_time[255], /* New LC_TIME value */
+ *charset; /* Pointer to character set */
+#endif /* LC_TIME */
+
+
+ /*
+ * Set the locale so that times, etc. are displayed properly.
+ *
+ * Unfortunately, while we need the localized time value, we *don't*
+ * want to use the localized charset for the time value, so we need
+ * to set LC_TIME to the locale name with .UTF-8 on the end (if
+ * the locale includes a character set specifier...)
+ */
+
+ setlocale(LC_ALL, "");
+
+#ifdef LC_TIME
+ if ((lc_time = setlocale(LC_TIME, NULL)) == NULL)
+ lc_time = setlocale(LC_ALL, NULL);
+
+ if (lc_time)
+ {
+ strlcpy(new_lc_time, lc_time, sizeof(new_lc_time));
+ if ((charset = strchr(new_lc_time, '.')) == NULL)
+ charset = new_lc_time + strlen(new_lc_time);
+
+ strlcpy(charset, ".UTF-8", sizeof(new_lc_time) - (charset - new_lc_time));
+ }
+ else
+ strcpy(new_lc_time, "C");
+
+ setlocale(LC_TIME, new_lc_time);
+#endif /* LC_TIME */
+
+ /*
+ * Initialize the default language info...
+ */
+
+ cg = _cupsGlobals();
+
+ if (!cg->lang_default)
+ cg->lang_default = cupsLangDefault();
+
+ /*
+ * Transcode the command-line arguments from the locale charset to
+ * UTF-8...
+ */
+
+ if (cg->lang_default->encoding != CUPS_US_ASCII &&
+ cg->lang_default->encoding != CUPS_UTF8)
+ {
+ for (i = 1; argv[i]; i ++)
+ {
+ /*
+ * Try converting from the locale charset to UTF-8...
+ */
+
+ if (cupsCharsetToUTF8((cups_utf8_t *)buffer, argv[i], sizeof(buffer),
+ cg->lang_default->encoding) < 0)
+ continue;
+
+ /*
+ * Save the new string if it differs from the original...
+ */
+
+ if (strcmp(buffer, argv[i]))
+ argv[i] = strdup(buffer);
+ }
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/language-private.h b/cups/language-private.h
new file mode 100644
index 000000000..0c10ca54c
--- /dev/null
+++ b/cups/language-private.h
@@ -0,0 +1,91 @@
+/*
+ * "$Id$"
+ *
+ * Private localization support for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_LANGUAGE_PRIVATE_H_
+# define _CUPS_LANGUAGE_PRIVATE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include <stdio.h>
+# include <cups/transcode.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Macro for localized text...
+ */
+
+# define _(x) x
+
+
+/*
+ * Types...
+ */
+
+typedef struct _cups_message_s /**** Message catalog entry ****/
+{
+ char *id, /* Original string */
+ *str; /* Localized string */
+} _cups_message_t;
+
+
+/*
+ * Prototypes...
+ */
+
+# ifdef __APPLE__
+extern const char *_cupsAppleLanguage(const char *locale, char *language,
+ size_t langsize);
+# endif /* __APPLE__ */
+extern void _cupsCharmapFlush(void);
+extern const char *_cupsEncodingName(cups_encoding_t encoding);
+extern void _cupsLangPrintError(const char *prefix,
+ const char *message);
+extern int _cupsLangPrintFilter(FILE *fp, const char *prefix,
+ const char *message, ...)
+# ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 3, 4)))
+# endif /* __GNUC__ */
+;
+extern int _cupsLangPrintf(FILE *fp, const char *message, ...)
+# ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+# endif /* __GNUC__ */
+;
+extern int _cupsLangPuts(FILE *fp, const char *message);
+extern const char *_cupsLangString(cups_lang_t *lang,
+ const char *message);
+extern void _cupsMessageFree(cups_array_t *a);
+extern cups_array_t *_cupsMessageLoad(const char *filename, int unquote);
+extern const char *_cupsMessageLookup(cups_array_t *a, const char *m);
+extern void _cupsSetLocale(char *argv[]);
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_LANGUAGE_PRIVATE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/language.c b/cups/language.c
new file mode 100644
index 000000000..ffc9cd126
--- /dev/null
+++ b/cups/language.c
@@ -0,0 +1,1509 @@
+/*
+ * "$Id$"
+ *
+ * I18N/language support for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsAppleLanguage() - Get the Apple language identifier associated with
+ * a locale ID.
+ * _cupsEncodingName() - Return the character encoding name string for the
+ * given encoding enumeration.
+ * cupsLangDefault() - Return the default language.
+ * cupsLangEncoding() - Return the character encoding (us-ascii, etc.) for
+ * the given language.
+ * cupsLangFlush() - Flush all language data out of the cache.
+ * cupsLangFree() - Free language data.
+ * cupsLangGet() - Get a language.
+ * _cupsLangString() - Get a message string.
+ * _cupsMessageFree() - Free a messages array.
+ * _cupsMessageLoad() - Load a .po file into a messages array.
+ * _cupsMessageLookup() - Lookup a message string.
+ * appleLangDefault() - Get the default locale string.
+ * appleMessageLoad() - Load a message catalog from a localizable bundle.
+ * cups_cache_lookup() - Lookup a language in the cache...
+ * cups_message_compare() - Compare two messages.
+ * cups_message_free() - Free a message.
+ * cups_unquote() - Unquote characters in strings...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#ifdef HAVE_LANGINFO_H
+# include <langinfo.h>
+#endif /* HAVE_LANGINFO_H */
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+#endif /* WIN32 */
+#ifdef HAVE_COREFOUNDATION_H
+# include <CoreFoundation/CoreFoundation.h>
+#endif /* HAVE_COREFOUNDATION_H */
+
+
+/*
+ * Local globals...
+ */
+
+static _cups_mutex_t lang_mutex = _CUPS_MUTEX_INITIALIZER;
+ /* Mutex to control access to cache */
+static cups_lang_t *lang_cache = NULL;
+ /* Language string cache */
+static const char * const lang_encodings[] =
+ { /* Encoding strings */
+ "us-ascii", "iso-8859-1",
+ "iso-8859-2", "iso-8859-3",
+ "iso-8859-4", "iso-8859-5",
+ "iso-8859-6", "iso-8859-7",
+ "iso-8859-8", "iso-8859-9",
+ "iso-8859-10", "utf-8",
+ "iso-8859-13", "iso-8859-14",
+ "iso-8859-15", "cp874",
+ "cp1250", "cp1251",
+ "cp1252", "cp1253",
+ "cp1254", "cp1255",
+ "cp1256", "cp1257",
+ "cp1258", "koi8-r",
+ "koi8-u", "iso-8859-11",
+ "iso-8859-16", "mac-roman",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "cp932", "cp936",
+ "cp949", "cp950",
+ "cp1361", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "euc-cn", "euc-jp",
+ "euc-kr", "euc-tw",
+ "jis-x0213"
+ };
+
+#ifdef __APPLE__
+typedef struct
+{
+ const char * const language; /* Language ID */
+ const char * const locale; /* Locale ID */
+} _apple_language_locale_t;
+
+static const _apple_language_locale_t apple_language_locale[] =
+{ /* Locale to language ID LUT */
+ { "en", "en_US" },
+ { "nb", "no" },
+ { "zh-Hans", "zh_CN" },
+ { "zh-Hant", "zh_TW" }
+};
+#endif /* __APPLE__ */
+
+
+/*
+ * Local functions...
+ */
+
+
+#ifdef __APPLE__
+static const char *appleLangDefault(void);
+# ifdef CUPS_BUNDLEDIR
+# ifndef CF_RETURNS_RETAINED
+# if __has_feature(attribute_cf_returns_retained)
+# define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+# else
+# define CF_RETURNS_RETAINED
+# endif /* __has_feature(attribute_cf_returns_retained) */
+# endif /* !CF_RETURNED_RETAINED */
+static cups_array_t *appleMessageLoad(const char *locale)
+ CF_RETURNS_RETAINED;
+# endif /* CUPS_BUNDLEDIR */
+#endif /* __APPLE__ */
+static cups_lang_t *cups_cache_lookup(const char *name,
+ cups_encoding_t encoding);
+static int cups_message_compare(_cups_message_t *m1,
+ _cups_message_t *m2);
+static void cups_message_free(_cups_message_t *m);
+static void cups_unquote(char *d, const char *s);
+
+
+#ifdef __APPLE__
+/*
+ * '_cupsAppleLanguage()' - Get the Apple language identifier associated with a
+ * locale ID.
+ */
+
+const char * /* O - Language ID */
+_cupsAppleLanguage(const char *locale, /* I - Locale ID */
+ char *language,/* I - Language ID buffer */
+ size_t langsize) /* I - Size of language ID buffer */
+{
+ int i; /* Looping var */
+ CFStringRef localeid, /* CF locale identifier */
+ langid; /* CF language identifier */
+
+
+ /*
+ * Copy the locale name and convert, as needed, to the Apple-specific
+ * locale identifier...
+ */
+
+ switch (strlen(locale))
+ {
+ default :
+ /*
+ * Invalid locale...
+ */
+
+ strlcpy(language, "en", langsize);
+ break;
+
+ case 2 :
+ strlcpy(language, locale, langsize);
+ break;
+
+ case 5 :
+ strlcpy(language, locale, langsize);
+
+ if (language[2] == '-')
+ {
+ /*
+ * Convert ll-cc to ll_CC...
+ */
+
+ language[2] = '_';
+ language[3] = toupper(language[3] & 255);
+ language[4] = toupper(language[4] & 255);
+ }
+ break;
+ }
+
+ for (i = 0;
+ i < (int)(sizeof(apple_language_locale) /
+ sizeof(apple_language_locale[0]));
+ i ++)
+ if (!strcmp(locale, apple_language_locale[i].locale))
+ {
+ strlcpy(language, apple_language_locale[i].language, sizeof(language));
+ break;
+ }
+
+ /*
+ * Attempt to map the locale ID to a language ID...
+ */
+
+ if ((localeid = CFStringCreateWithCString(kCFAllocatorDefault, language,
+ kCFStringEncodingASCII)) != NULL)
+ {
+ if ((langid = CFLocaleCreateCanonicalLanguageIdentifierFromString(
+ kCFAllocatorDefault, localeid)) != NULL)
+ {
+ CFStringGetCString(langid, language, langsize, kCFStringEncodingASCII);
+ CFRelease(langid);
+ }
+
+ CFRelease(localeid);
+ }
+
+ /*
+ * Return what we got...
+ */
+
+ return (language);
+}
+#endif /* __APPLE__ */
+
+
+/*
+ * '_cupsEncodingName()' - Return the character encoding name string
+ * for the given encoding enumeration.
+ */
+
+const char * /* O - Character encoding */
+_cupsEncodingName(
+ cups_encoding_t encoding) /* I - Encoding value */
+{
+ if (encoding < 0 ||
+ encoding >= (sizeof(lang_encodings) / sizeof(const char *)))
+ {
+ DEBUG_printf(("1_cupsEncodingName(encoding=%d) = out of range (\"%s\")",
+ encoding, lang_encodings[0]));
+ return (lang_encodings[0]);
+ }
+ else
+ {
+ DEBUG_printf(("1_cupsEncodingName(encoding=%d) = \"%s\"",
+ encoding, lang_encodings[encoding]));
+ return (lang_encodings[encoding]);
+ }
+}
+
+
+/*
+ * 'cupsLangDefault()' - Return the default language.
+ */
+
+cups_lang_t * /* O - Language data */
+cupsLangDefault(void)
+{
+ return (cupsLangGet(NULL));
+}
+
+
+/*
+ * 'cupsLangEncoding()' - Return the character encoding (us-ascii, etc.)
+ * for the given language.
+ */
+
+const char * /* O - Character encoding */
+cupsLangEncoding(cups_lang_t *lang) /* I - Language data */
+{
+ if (lang == NULL)
+ return ((char*)lang_encodings[0]);
+ else
+ return ((char*)lang_encodings[lang->encoding]);
+}
+
+
+/*
+ * 'cupsLangFlush()' - Flush all language data out of the cache.
+ */
+
+void
+cupsLangFlush(void)
+{
+ cups_lang_t *lang, /* Current language */
+ *next; /* Next language */
+
+
+ /*
+ * Free all languages in the cache...
+ */
+
+ _cupsMutexLock(&lang_mutex);
+
+ for (lang = lang_cache; lang != NULL; lang = next)
+ {
+ /*
+ * Free all messages...
+ */
+
+ _cupsMessageFree(lang->strings);
+
+ /*
+ * Then free the language structure itself...
+ */
+
+ next = lang->next;
+ free(lang);
+ }
+
+ lang_cache = NULL;
+
+ _cupsMutexUnlock(&lang_mutex);
+}
+
+
+/*
+ * 'cupsLangFree()' - Free language data.
+ *
+ * This does not actually free anything; use @link cupsLangFlush@ for that.
+ */
+
+void
+cupsLangFree(cups_lang_t *lang) /* I - Language to free */
+{
+ _cupsMutexLock(&lang_mutex);
+
+ if (lang != NULL && lang->used > 0)
+ lang->used --;
+
+ _cupsMutexUnlock(&lang_mutex);
+}
+
+
+/*
+ * 'cupsLangGet()' - Get a language.
+ */
+
+cups_lang_t * /* O - Language data */
+cupsLangGet(const char *language) /* I - Language or locale */
+{
+ int i; /* Looping var */
+#ifndef __APPLE__
+ char locale[255]; /* Copy of locale name */
+#endif /* !__APPLE__ */
+ char langname[16], /* Requested language name */
+ country[16], /* Country code */
+ charset[16], /* Character set */
+ *csptr, /* Pointer to CODESET string */
+ *ptr, /* Pointer into language/charset */
+ real[48]; /* Real language name */
+ cups_encoding_t encoding; /* Encoding to use */
+ cups_lang_t *lang; /* Current language... */
+#if !defined(__APPLE__) || !defined(CUPS_BUNDLEDIR)
+ char filename[1024]; /* Filename for language locale file */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Pointer to library globals */
+#endif /* !__APPLE__ || !CUPS_BUNDLEDIR */
+ static const char * const locale_encodings[] =
+ { /* Locale charset names */
+ "ASCII", "ISO88591", "ISO88592", "ISO88593",
+ "ISO88594", "ISO88595", "ISO88596", "ISO88597",
+ "ISO88598", "ISO88599", "ISO885910", "UTF8",
+ "ISO885913", "ISO885914", "ISO885915", "CP874",
+ "CP1250", "CP1251", "CP1252", "CP1253",
+ "CP1254", "CP1255", "CP1256", "CP1257",
+ "CP1258", "KOI8R", "KOI8U", "ISO885911",
+ "ISO885916", "MACROMAN", "", "",
+
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+
+ "CP932", "CP936", "CP949", "CP950",
+ "CP1361", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "", "", "", "",
+
+ "EUCCN", "EUCJP", "EUCKR", "EUCTW",
+ "SHIFT_JISX0213"
+ };
+
+
+ DEBUG_printf(("2cupsLangGet(language=\"%s\")", language));
+
+#ifdef __APPLE__
+ /*
+ * Set the character set to UTF-8...
+ */
+
+ strcpy(charset, "UTF8");
+
+ /*
+ * Apple's setlocale doesn't give us the user's localization
+ * preference so we have to look it up this way...
+ */
+
+ if (!language)
+ {
+ if (!getenv("SOFTWARE") || (language = getenv("LANG")) == NULL)
+ language = appleLangDefault();
+
+ DEBUG_printf(("4cupsLangGet: language=\"%s\"", language));
+ }
+
+#else
+ /*
+ * Set the charset to "unknown"...
+ */
+
+ charset[0] = '\0';
+
+ /*
+ * Use setlocale() to determine the currently set locale, and then
+ * fallback to environment variables to avoid setting the locale,
+ * since setlocale() is not thread-safe!
+ */
+
+ if (!language)
+ {
+ /*
+ * First see if the locale has been set; if it is still "C" or
+ * "POSIX", use the environment to get the default...
+ */
+
+# ifdef LC_MESSAGES
+ ptr = setlocale(LC_MESSAGES, NULL);
+# else
+ ptr = setlocale(LC_ALL, NULL);
+# endif /* LC_MESSAGES */
+
+ DEBUG_printf(("4cupsLangGet: current locale is \"%s\"", ptr));
+
+ if (!ptr || !strcmp(ptr, "C") || !strcmp(ptr, "POSIX"))
+ {
+ /*
+ * Get the character set from the LC_CTYPE locale setting...
+ */
+
+ if ((ptr = getenv("LC_CTYPE")) == NULL)
+ if ((ptr = getenv("LC_ALL")) == NULL)
+ if ((ptr = getenv("LANG")) == NULL)
+ ptr = "en_US";
+
+ if ((csptr = strchr(ptr, '.')) != NULL)
+ {
+ /*
+ * Extract the character set from the environment...
+ */
+
+ for (ptr = charset, csptr ++; *csptr; csptr ++)
+ if (ptr < (charset + sizeof(charset) - 1) && _cups_isalnum(*csptr))
+ *ptr++ = *csptr;
+
+ *ptr = '\0';
+ }
+
+ /*
+ * Get the locale for messages from the LC_MESSAGES locale setting...
+ */
+
+ if ((ptr = getenv("LC_MESSAGES")) == NULL)
+ if ((ptr = getenv("LC_ALL")) == NULL)
+ if ((ptr = getenv("LANG")) == NULL)
+ ptr = "en_US";
+ }
+
+ if (ptr)
+ {
+ strlcpy(locale, ptr, sizeof(locale));
+ language = locale;
+
+ /*
+ * CUPS STR #2575: Map "nb" to "no" for back-compatibility...
+ */
+
+ if (!strncmp(locale, "nb", 2))
+ locale[1] = 'o';
+
+ DEBUG_printf(("4cupsLangGet: new language value is \"%s\"", language));
+ }
+ }
+#endif /* __APPLE__ */
+
+ /*
+ * If "language" is NULL at this point, then chances are we are using
+ * a language that is not installed for the base OS.
+ */
+
+ if (!language)
+ {
+ /*
+ * Switch to the POSIX ("C") locale...
+ */
+
+ language = "C";
+ }
+
+#ifdef CODESET
+ /*
+ * On systems that support the nl_langinfo(CODESET) call, use
+ * this value as the character set...
+ */
+
+ if (!charset[0] && (csptr = nl_langinfo(CODESET)) != NULL)
+ {
+ /*
+ * Copy all of the letters and numbers in the CODESET string...
+ */
+
+ for (ptr = charset; *csptr; csptr ++)
+ if (_cups_isalnum(*csptr) && ptr < (charset + sizeof(charset) - 1))
+ *ptr++ = *csptr;
+
+ *ptr = '\0';
+
+ DEBUG_printf(("4cupsLangGet: charset set to \"%s\" via "
+ "nl_langinfo(CODESET)...", charset));
+ }
+#endif /* CODESET */
+
+ /*
+ * If we don't have a character set by now, default to UTF-8...
+ */
+
+ if (!charset[0])
+ strcpy(charset, "UTF8");
+
+ /*
+ * Parse the language string passed in to a locale string. "C" is the
+ * standard POSIX locale and is copied unchanged. Otherwise the
+ * language string is converted from ll-cc[.charset] (language-country)
+ * to ll_CC[.CHARSET] to match the file naming convention used by all
+ * POSIX-compliant operating systems. Invalid language names are mapped
+ * to the POSIX locale.
+ */
+
+ country[0] = '\0';
+
+ if (language == NULL || !language[0] ||
+ !strcmp(language, "POSIX"))
+ strcpy(langname, "C");
+ else
+ {
+ /*
+ * Copy the parts of the locale string over safely...
+ */
+
+ for (ptr = langname; *language; language ++)
+ if (*language == '_' || *language == '-' || *language == '.')
+ break;
+ else if (ptr < (langname + sizeof(langname) - 1))
+ *ptr++ = tolower(*language & 255);
+
+ *ptr = '\0';
+
+ if (*language == '_' || *language == '-')
+ {
+ /*
+ * Copy the country code...
+ */
+
+ for (language ++, ptr = country; *language; language ++)
+ if (*language == '.')
+ break;
+ else if (ptr < (country + sizeof(country) - 1))
+ *ptr++ = toupper(*language & 255);
+
+ *ptr = '\0';
+ }
+
+ if (*language == '.' && !charset[0])
+ {
+ /*
+ * Copy the encoding...
+ */
+
+ for (language ++, ptr = charset; *language; language ++)
+ if (_cups_isalnum(*language) && ptr < (charset + sizeof(charset) - 1))
+ *ptr++ = toupper(*language & 255);
+
+ *ptr = '\0';
+ }
+
+ /*
+ * Force a POSIX locale for an invalid language name...
+ */
+
+ if (strlen(langname) != 2)
+ {
+ strcpy(langname, "C");
+ country[0] = '\0';
+ charset[0] = '\0';
+ }
+ }
+
+ DEBUG_printf(("4cupsLangGet: langname=\"%s\", country=\"%s\", charset=\"%s\"",
+ langname, country, charset));
+
+ /*
+ * Figure out the desired encoding...
+ */
+
+ encoding = CUPS_AUTO_ENCODING;
+
+ if (charset[0])
+ {
+ for (i = 0;
+ i < (int)(sizeof(locale_encodings) / sizeof(locale_encodings[0]));
+ i ++)
+ if (!_cups_strcasecmp(charset, locale_encodings[i]))
+ {
+ encoding = (cups_encoding_t)i;
+ break;
+ }
+
+ if (encoding == CUPS_AUTO_ENCODING)
+ {
+ /*
+ * Map alternate names for various character sets...
+ */
+
+ if (!_cups_strcasecmp(charset, "iso-2022-jp") ||
+ !_cups_strcasecmp(charset, "sjis"))
+ encoding = CUPS_WINDOWS_932;
+ else if (!_cups_strcasecmp(charset, "iso-2022-cn"))
+ encoding = CUPS_WINDOWS_936;
+ else if (!_cups_strcasecmp(charset, "iso-2022-kr"))
+ encoding = CUPS_WINDOWS_949;
+ else if (!_cups_strcasecmp(charset, "big5"))
+ encoding = CUPS_WINDOWS_950;
+ }
+ }
+
+ DEBUG_printf(("4cupsLangGet: encoding=%d(%s)", encoding,
+ encoding == CUPS_AUTO_ENCODING ? "auto" :
+ lang_encodings[encoding]));
+
+ /*
+ * See if we already have this language/country loaded...
+ */
+
+ if (country[0])
+ {
+ snprintf(real, sizeof(real), "%s_%s", langname, country);
+
+#if !defined(__APPLE__) || !defined(CUPS_BUNDLEDIR)
+ snprintf(filename, sizeof(filename), "%s/%s/cups_%s.po", cg->localedir,
+ real, real);
+#endif /* !__APPLE__ || !CUPS_BUNDLEDIR */
+ }
+ else
+ {
+ strcpy(real, langname);
+#if !defined(__APPLE__) || !defined(CUPS_BUNDLEDIR)
+ filename[0] = '\0'; /* anti-compiler-warning-code */
+#endif /* !__APPLE__ || !CUPS_BUNDLEDIR */
+ }
+
+ _cupsMutexLock(&lang_mutex);
+
+ if ((lang = cups_cache_lookup(real, encoding)) != NULL)
+ {
+ _cupsMutexUnlock(&lang_mutex);
+
+ DEBUG_printf(("3cupsLangGet: Using cached copy of \"%s\"...", real));
+
+ return (lang);
+ }
+
+#if !defined(__APPLE__) || !defined(CUPS_BUNDLEDIR)
+ if (!country[0] || access(filename, 0))
+ {
+ /*
+ * Country localization not available, look for generic localization...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/%s/cups_%s.po", cg->localedir,
+ langname, langname);
+
+ if (access(filename, 0))
+ {
+ /*
+ * No generic localization, so use POSIX...
+ */
+
+ DEBUG_printf(("4cupsLangGet: access(\"%s\", 0): %s", filename,
+ strerror(errno)));
+
+ snprintf(filename, sizeof(filename), "%s/C/cups_C.po", cg->localedir);
+ }
+ }
+#endif /* !__APPLE__ || !CUPS_BUNDLEDIR */
+
+ /*
+ * See if there is a free language available; if so, use that
+ * record...
+ */
+
+ for (lang = lang_cache; lang != NULL; lang = lang->next)
+ if (lang->used == 0)
+ break;
+
+ if (lang == NULL)
+ {
+ /*
+ * Allocate memory for the language and add it to the cache.
+ */
+
+ if ((lang = calloc(sizeof(cups_lang_t), 1)) == NULL)
+ {
+ _cupsMutexUnlock(&lang_mutex);
+
+ return (NULL);
+ }
+
+ lang->next = lang_cache;
+ lang_cache = lang;
+ }
+ else
+ {
+ /*
+ * Free all old strings as needed...
+ */
+
+ _cupsMessageFree(lang->strings);
+ }
+
+ /*
+ * Then assign the language and encoding fields...
+ */
+
+ lang->used ++;
+ strlcpy(lang->language, real, sizeof(lang->language));
+
+ if (encoding != CUPS_AUTO_ENCODING)
+ lang->encoding = encoding;
+ else
+ lang->encoding = CUPS_UTF8;
+
+ /*
+ * Read the strings from the file...
+ */
+
+#if defined(__APPLE__) && defined(CUPS_BUNDLEDIR)
+ lang->strings = appleMessageLoad(lang->language);
+#else
+ lang->strings = _cupsMessageLoad(filename, 1);
+#endif /* __APPLE__ && CUPS_BUNDLEDIR */
+
+ /*
+ * Return...
+ */
+
+ _cupsMutexUnlock(&lang_mutex);
+
+ return (lang);
+}
+
+
+/*
+ * '_cupsLangString()' - Get a message string.
+ *
+ * The returned string is UTF-8 encoded; use cupsUTF8ToCharset() to
+ * convert the string to the language encoding.
+ */
+
+const char * /* O - Localized message */
+_cupsLangString(cups_lang_t *lang, /* I - Language */
+ const char *message) /* I - Message */
+{
+ const char *s; /* Localized message */
+
+ /*
+ * Range check input...
+ */
+
+ if (!lang || !message)
+ return (message);
+
+ _cupsMutexLock(&lang_mutex);
+
+ s = _cupsMessageLookup(lang->strings, message);
+
+ _cupsMutexUnlock(&lang_mutex);
+
+ return (s);
+}
+
+
+/*
+ * '_cupsMessageFree()' - Free a messages array.
+ */
+
+void
+_cupsMessageFree(cups_array_t *a) /* I - Message array */
+{
+#if defined(__APPLE__) && defined(CUPS_BUNDLEDIR)
+ /*
+ * Release the cups.strings dictionary as needed...
+ */
+
+ if (cupsArrayUserData(a))
+ CFRelease((CFDictionaryRef)cupsArrayUserData(a));
+#endif /* __APPLE__ && CUPS_BUNDLEDIR */
+
+ /*
+ * Free the array...
+ */
+
+ cupsArrayDelete(a);
+}
+
+
+/*
+ * '_cupsMessageLoad()' - Load a .po file into a messages array.
+ */
+
+cups_array_t * /* O - New message array */
+_cupsMessageLoad(const char *filename, /* I - Message catalog to load */
+ int unquote) /* I - Unescape \foo in strings? */
+{
+ cups_file_t *fp; /* Message file */
+ cups_array_t *a; /* Message array */
+ _cups_message_t *m; /* Current message */
+ char s[4096], /* String buffer */
+ *ptr, /* Pointer into buffer */
+ *temp; /* New string */
+ int length; /* Length of combined strings */
+
+
+ DEBUG_printf(("4_cupsMessageLoad(filename=\"%s\")", filename));
+
+ /*
+ * Create an array to hold the messages...
+ */
+
+ if ((a = cupsArrayNew3((cups_array_func_t)cups_message_compare, NULL,
+ (cups_ahash_func_t)NULL, 0,
+ (cups_acopy_func_t)NULL,
+ (cups_afree_func_t)cups_message_free)) == NULL)
+ {
+ DEBUG_puts("5_cupsMessageLoad: Unable to allocate array!");
+ return (NULL);
+ }
+
+ /*
+ * Open the message catalog file...
+ */
+
+ if ((fp = cupsFileOpen(filename, "r")) == NULL)
+ {
+ DEBUG_printf(("5_cupsMessageLoad: Unable to open file: %s",
+ strerror(errno)));
+ return (a);
+ }
+
+ /*
+ * Read messages from the catalog file until EOF...
+ *
+ * The format is the GNU gettext .po format, which is fairly simple:
+ *
+ * msgid "some text"
+ * msgstr "localized text"
+ *
+ * The ID and localized text can span multiple lines using the form:
+ *
+ * msgid ""
+ * "some long text"
+ * msgstr ""
+ * "localized text spanning "
+ * "multiple lines"
+ */
+
+ m = NULL;
+
+ while (cupsFileGets(fp, s, sizeof(s)) != NULL)
+ {
+ /*
+ * Skip blank and comment lines...
+ */
+
+ if (s[0] == '#' || !s[0])
+ continue;
+
+ /*
+ * Strip the trailing quote...
+ */
+
+ if ((ptr = strrchr(s, '\"')) == NULL)
+ continue;
+
+ *ptr = '\0';
+
+ /*
+ * Find start of value...
+ */
+
+ if ((ptr = strchr(s, '\"')) == NULL)
+ continue;
+
+ ptr ++;
+
+ /*
+ * Unquote the text...
+ */
+
+ if (unquote)
+ cups_unquote(ptr, ptr);
+
+ /*
+ * Create or add to a message...
+ */
+
+ if (!strncmp(s, "msgid", 5))
+ {
+ /*
+ * Add previous message as needed...
+ */
+
+ if (m)
+ cupsArrayAdd(a, m);
+
+ /*
+ * Create a new message with the given msgid string...
+ */
+
+ if ((m = (_cups_message_t *)calloc(1, sizeof(_cups_message_t))) == NULL)
+ {
+ cupsFileClose(fp);
+ return (a);
+ }
+
+ if ((m->id = strdup(ptr)) == NULL)
+ {
+ free(m);
+ cupsFileClose(fp);
+ return (a);
+ }
+ }
+ else if (s[0] == '\"' && m)
+ {
+ /*
+ * Append to current string...
+ */
+
+ length = (int)strlen(m->str ? m->str : m->id);
+
+ if ((temp = realloc(m->str ? m->str : m->id,
+ length + strlen(ptr) + 1)) == NULL)
+ {
+ cupsFileClose(fp);
+ return (a);
+ }
+
+ if (m->str)
+ {
+ /*
+ * Copy the new portion to the end of the msgstr string - safe
+ * to use strcpy because the buffer is allocated to the correct
+ * size...
+ */
+
+ m->str = temp;
+
+ strcpy(m->str + length, ptr);
+ }
+ else
+ {
+ /*
+ * Copy the new portion to the end of the msgid string - safe
+ * to use strcpy because the buffer is allocated to the correct
+ * size...
+ */
+
+ m->id = temp;
+
+ strcpy(m->id + length, ptr);
+ }
+ }
+ else if (!strncmp(s, "msgstr", 6) && m)
+ {
+ /*
+ * Set the string...
+ */
+
+ if ((m->str = strdup(ptr)) == NULL)
+ {
+ cupsFileClose(fp);
+ return (a);
+ }
+ }
+ }
+
+ /*
+ * Add the last message string to the array as needed...
+ */
+
+ if (m)
+ cupsArrayAdd(a, m);
+
+ /*
+ * Close the message catalog file and return the new array...
+ */
+
+ cupsFileClose(fp);
+
+ DEBUG_printf(("5_cupsMessageLoad: Returning %d messages...",
+ cupsArrayCount(a)));
+
+ return (a);
+}
+
+
+/*
+ * '_cupsMessageLookup()' - Lookup a message string.
+ */
+
+const char * /* O - Localized message */
+_cupsMessageLookup(cups_array_t *a, /* I - Message array */
+ const char *m) /* I - Message */
+{
+ _cups_message_t key, /* Search key */
+ *match; /* Matching message */
+
+
+ /*
+ * Lookup the message string; if it doesn't exist in the catalog,
+ * then return the message that was passed to us...
+ */
+
+ key.id = (char *)m;
+ match = (_cups_message_t *)cupsArrayFind(a, &key);
+
+#if defined(__APPLE__) && defined(CUPS_BUNDLEDIR)
+ if (!match && cupsArrayUserData(a))
+ {
+ /*
+ * Try looking the string up in the cups.strings dictionary...
+ */
+
+ CFDictionaryRef dict; /* cups.strings dictionary */
+ CFStringRef cfm, /* Message as a CF string */
+ cfstr; /* Localized text as a CF string */
+
+ dict = (CFDictionaryRef)cupsArrayUserData(a);
+ cfm = CFStringCreateWithCString(kCFAllocatorDefault, m,
+ kCFStringEncodingUTF8);
+ match = calloc(1, sizeof(_cups_message_t));
+ match->id = strdup(m);
+ cfstr = cfm ? CFDictionaryGetValue(dict, cfm) : NULL;
+
+ if (cfstr)
+ {
+ char buffer[1024]; /* Message buffer */
+
+ CFStringGetCString(cfstr, buffer, sizeof(buffer), kCFStringEncodingUTF8);
+ match->str = strdup(buffer);
+
+ DEBUG_printf(("1_cupsMessageLookup: Found \"%s\" as \"%s\"...",
+ m, buffer));
+ }
+ else
+ {
+ match->str = strdup(m);
+
+ DEBUG_printf(("1_cupsMessageLookup: Did not find \"%s\"...", m));
+ }
+
+ cupsArrayAdd(a, match);
+
+ if (cfm)
+ CFRelease(cfm);
+ }
+#endif /* __APPLE__ && CUPS_BUNDLEDIR */
+
+ if (match && match->str)
+ return (match->str);
+ else
+ return (m);
+}
+
+
+#ifdef __APPLE__
+/*
+ * 'appleLangDefault()' - Get the default locale string.
+ */
+
+static const char * /* O - Locale string */
+appleLangDefault(void)
+{
+ int i; /* Looping var */
+ CFBundleRef bundle; /* Main bundle (if any) */
+ CFArrayRef bundleList; /* List of localizations in bundle */
+ CFPropertyListRef localizationList;
+ /* List of localization data */
+ CFStringRef languageName; /* Current name */
+ CFStringRef localeName; /* Canonical from of name */
+ char *lang; /* LANG environment variable */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Pointer to library globals */
+
+
+ DEBUG_puts("2appleLangDefault()");
+
+ /*
+ * Only do the lookup and translation the first time.
+ */
+
+ if (!cg->language[0])
+ {
+ if (getenv("SOFTWARE") != NULL && (lang = getenv("LANG")) != NULL)
+ {
+ strlcpy(cg->language, lang, sizeof(cg->language));
+ return (cg->language);
+ }
+ else if ((bundle = CFBundleGetMainBundle()) != NULL &&
+ (bundleList = CFBundleCopyBundleLocalizations(bundle)) != NULL)
+ {
+ localizationList =
+ CFBundleCopyPreferredLocalizationsFromArray(bundleList);
+
+ CFRelease(bundleList);
+ }
+ else
+ localizationList =
+ CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
+ kCFPreferencesCurrentApplication);
+
+ if (localizationList)
+ {
+ if (CFGetTypeID(localizationList) == CFArrayGetTypeID() &&
+ CFArrayGetCount(localizationList) > 0)
+ {
+ languageName = CFArrayGetValueAtIndex(localizationList, 0);
+
+ if (languageName &&
+ CFGetTypeID(languageName) == CFStringGetTypeID())
+ {
+ localeName = CFLocaleCreateCanonicalLocaleIdentifierFromString(
+ kCFAllocatorDefault, languageName);
+
+ if (localeName)
+ {
+ CFStringGetCString(localeName, cg->language, sizeof(cg->language),
+ kCFStringEncodingASCII);
+ CFRelease(localeName);
+
+ DEBUG_printf(("9appleLangDefault: cg->language=\"%s\"",
+ cg->language));
+
+ /*
+ * Map new language identifiers to locales...
+ */
+
+ for (i = 0;
+ i < (int)(sizeof(apple_language_locale) /
+ sizeof(apple_language_locale[0]));
+ i ++)
+ {
+ if (!strcmp(cg->language, apple_language_locale[i].language))
+ {
+ DEBUG_printf(("9appleLangDefault: mapping \"%s\" to \"%s\"...",
+ cg->language, apple_language_locale[i].locale));
+ strlcpy(cg->language, apple_language_locale[i].locale,
+ sizeof(cg->language));
+ break;
+ }
+ }
+
+ /*
+ * Convert language subtag into region subtag...
+ */
+
+ if (cg->language[2] == '-')
+ cg->language[2] = '_';
+
+ if (!strchr(cg->language, '.'))
+ strlcat(cg->language, ".UTF-8", sizeof(cg->language));
+ }
+ }
+ }
+
+ CFRelease(localizationList);
+ }
+
+ /*
+ * If we didn't find the language, default to en_US...
+ */
+
+ if (!cg->language[0])
+ strlcpy(cg->language, "en_US.UTF-8", sizeof(cg->language));
+ }
+
+ /*
+ * Return the cached locale...
+ */
+
+ return (cg->language);
+}
+
+
+# ifdef CUPS_BUNDLEDIR
+/*
+ * 'appleMessageLoad()' - Load a message catalog from a localizable bundle.
+ */
+
+static cups_array_t * /* O - Message catalog */
+appleMessageLoad(const char *locale) /* I - Locale ID */
+{
+ char filename[1024], /* Path to cups.strings file */
+ applelang[256]; /* Apple language ID */
+ CFURLRef url; /* URL to cups.strings file */
+ CFReadStreamRef stream = NULL; /* File stream */
+ CFPropertyListRef plist = NULL; /* Localization file */
+#ifdef DEBUG
+ CFErrorRef error = NULL; /* Error when opening file */
+#endif /* DEBUG */
+
+
+ DEBUG_printf(("appleMessageLoad(locale=\"%s\")", locale));
+
+ /*
+ * Load the cups.strings file...
+ */
+
+ snprintf(filename, sizeof(filename),
+ CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings",
+ _cupsAppleLanguage(locale, applelang, sizeof(applelang)));
+ DEBUG_printf(("1appleMessageLoad: filename=\"%s\"", filename));
+
+ if (access(filename, 0))
+ {
+ /*
+ * Try alternate lproj directory names...
+ */
+
+ if (!strncmp(locale, "en", 2))
+ locale = "English";
+ else if (!strncmp(locale, "nb", 2) || !strncmp(locale, "nl", 2))
+ locale = "Dutch";
+ else if (!strncmp(locale, "fr", 2))
+ locale = "French";
+ else if (!strncmp(locale, "de", 2))
+ locale = "German";
+ else if (!strncmp(locale, "it", 2))
+ locale = "Italian";
+ else if (!strncmp(locale, "ja", 2))
+ locale = "Japanese";
+ else if (!strncmp(locale, "es", 2))
+ locale = "Spanish";
+
+ snprintf(filename, sizeof(filename),
+ CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", locale);
+ DEBUG_printf(("1appleMessageLoad: alternate filename=\"%s\"", filename));
+ }
+
+ url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
+ (UInt8 *)filename,
+ strlen(filename), false);
+ if (url)
+ {
+ stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
+ if (stream)
+ {
+ /*
+ * Read the property list containing the localization data.
+ *
+ * NOTE: This code currently generates a clang "potential leak"
+ * warning, but the object is released in _cupsMessageFree().
+ */
+
+ CFReadStreamOpen(stream);
+
+#ifdef DEBUG
+ plist = CFPropertyListCreateWithStream(kCFAllocatorDefault, stream, 0,
+ kCFPropertyListImmutable, NULL,
+ &error);
+ if (error)
+ {
+ CFStringRef msg = CFErrorCopyDescription(error);
+ /* Error message */
+
+ CFStringGetCString(msg, filename, sizeof(filename),
+ kCFStringEncodingUTF8);
+ DEBUG_printf(("1appleMessageLoad: %s", filename));
+
+ CFRelease(msg);
+ CFRelease(error);
+ }
+
+#else
+ plist = CFPropertyListCreateWithStream(kCFAllocatorDefault, stream, 0,
+ kCFPropertyListImmutable, NULL,
+ NULL);
+#endif /* DEBUG */
+
+ if (plist && CFGetTypeID(plist) != CFDictionaryGetTypeID())
+ {
+ CFRelease(plist);
+ plist = NULL;
+ }
+
+ CFRelease(stream);
+ }
+
+ CFRelease(url);
+ }
+
+ DEBUG_printf(("1appleMessageLoad: url=%p, stream=%p, plist=%p", url, stream,
+ plist));
+
+ /*
+ * Create and return an empty array to act as a cache for messages, passing the
+ * plist as the user data.
+ */
+
+ return (cupsArrayNew3((cups_array_func_t)cups_message_compare, (void *)plist,
+ (cups_ahash_func_t)NULL, 0,
+ (cups_acopy_func_t)NULL,
+ (cups_afree_func_t)cups_message_free));
+}
+# endif /* CUPS_BUNDLEDIR */
+#endif /* __APPLE__ */
+
+
+/*
+ * 'cups_cache_lookup()' - Lookup a language in the cache...
+ */
+
+static cups_lang_t * /* O - Language data or NULL */
+cups_cache_lookup(
+ const char *name, /* I - Name of locale */
+ cups_encoding_t encoding) /* I - Encoding of locale */
+{
+ cups_lang_t *lang; /* Current language */
+
+
+ DEBUG_printf(("7cups_cache_lookup(name=\"%s\", encoding=%d(%s))", name,
+ encoding, encoding == CUPS_AUTO_ENCODING ? "auto" :
+ lang_encodings[encoding]));
+
+ /*
+ * Loop through the cache and return a match if found...
+ */
+
+ for (lang = lang_cache; lang != NULL; lang = lang->next)
+ {
+ DEBUG_printf(("9cups_cache_lookup: lang=%p, language=\"%s\", "
+ "encoding=%d(%s)", lang, lang->language, lang->encoding,
+ lang_encodings[lang->encoding]));
+
+ if (!strcmp(lang->language, name) &&
+ (encoding == CUPS_AUTO_ENCODING || encoding == lang->encoding))
+ {
+ lang->used ++;
+
+ DEBUG_puts("8cups_cache_lookup: returning match!");
+
+ return (lang);
+ }
+ }
+
+ DEBUG_puts("8cups_cache_lookup: returning NULL!");
+
+ return (NULL);
+}
+
+
+/*
+ * 'cups_message_compare()' - Compare two messages.
+ */
+
+static int /* O - Result of comparison */
+cups_message_compare(
+ _cups_message_t *m1, /* I - First message */
+ _cups_message_t *m2) /* I - Second message */
+{
+ return (strcmp(m1->id, m2->id));
+}
+
+
+/*
+ * 'cups_message_free()' - Free a message.
+ */
+
+static void
+cups_message_free(_cups_message_t *m) /* I - Message */
+{
+ if (m->id)
+ free(m->id);
+
+ if (m->str)
+ free(m->str);
+
+ free(m);
+}
+
+
+/*
+ * 'cups_unquote()' - Unquote characters in strings...
+ */
+
+static void
+cups_unquote(char *d, /* O - Unquoted string */
+ const char *s) /* I - Original string */
+{
+ while (*s)
+ {
+ if (*s == '\\')
+ {
+ s ++;
+ if (isdigit(*s))
+ {
+ *d = 0;
+
+ while (isdigit(*s))
+ {
+ *d = *d * 8 + *s - '0';
+ s ++;
+ }
+
+ d ++;
+ }
+ else
+ {
+ if (*s == 'n')
+ *d ++ = '\n';
+ else if (*s == 'r')
+ *d ++ = '\r';
+ else if (*s == 't')
+ *d ++ = '\t';
+ else
+ *d++ = *s;
+
+ s ++;
+ }
+ }
+ else
+ *d++ = *s++;
+ }
+
+ *d = '\0';
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/language.h b/cups/language.h
new file mode 100644
index 000000000..0b8acdee4
--- /dev/null
+++ b/cups/language.h
@@ -0,0 +1,115 @@
+/*
+ * "$Id$"
+ *
+ * Multi-language support for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_LANGUAGE_H_
+# define _CUPS_LANGUAGE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include <locale.h>
+# include "array.h"
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Types...
+ */
+
+typedef enum cups_encoding_e /**** Language Encodings ****/
+{
+ CUPS_AUTO_ENCODING = -1, /* Auto-detect the encoding @private@ */
+ CUPS_US_ASCII, /* US ASCII */
+ CUPS_ISO8859_1, /* ISO-8859-1 */
+ CUPS_ISO8859_2, /* ISO-8859-2 */
+ CUPS_ISO8859_3, /* ISO-8859-3 */
+ CUPS_ISO8859_4, /* ISO-8859-4 */
+ CUPS_ISO8859_5, /* ISO-8859-5 */
+ CUPS_ISO8859_6, /* ISO-8859-6 */
+ CUPS_ISO8859_7, /* ISO-8859-7 */
+ CUPS_ISO8859_8, /* ISO-8859-8 */
+ CUPS_ISO8859_9, /* ISO-8859-9 */
+ CUPS_ISO8859_10, /* ISO-8859-10 */
+ CUPS_UTF8, /* UTF-8 */
+ CUPS_ISO8859_13, /* ISO-8859-13 */
+ CUPS_ISO8859_14, /* ISO-8859-14 */
+ CUPS_ISO8859_15, /* ISO-8859-15 */
+ CUPS_WINDOWS_874, /* CP-874 */
+ CUPS_WINDOWS_1250, /* CP-1250 */
+ CUPS_WINDOWS_1251, /* CP-1251 */
+ CUPS_WINDOWS_1252, /* CP-1252 */
+ CUPS_WINDOWS_1253, /* CP-1253 */
+ CUPS_WINDOWS_1254, /* CP-1254 */
+ CUPS_WINDOWS_1255, /* CP-1255 */
+ CUPS_WINDOWS_1256, /* CP-1256 */
+ CUPS_WINDOWS_1257, /* CP-1257 */
+ CUPS_WINDOWS_1258, /* CP-1258 */
+ CUPS_KOI8_R, /* KOI-8-R */
+ CUPS_KOI8_U, /* KOI-8-U */
+ CUPS_ISO8859_11, /* ISO-8859-11 */
+ CUPS_ISO8859_16, /* ISO-8859-16 */
+ CUPS_MAC_ROMAN, /* MacRoman */
+ CUPS_ENCODING_SBCS_END = 63, /* End of single-byte encodings @private@ */
+
+ CUPS_WINDOWS_932, /* Japanese JIS X0208-1990 */
+ CUPS_WINDOWS_936, /* Simplified Chinese GB 2312-80 */
+ CUPS_WINDOWS_949, /* Korean KS C5601-1992 */
+ CUPS_WINDOWS_950, /* Traditional Chinese Big Five */
+ CUPS_WINDOWS_1361, /* Korean Johab */
+ CUPS_ENCODING_DBCS_END = 127, /* End of double-byte encodings @private@ */
+
+ CUPS_EUC_CN, /* EUC Simplified Chinese */
+ CUPS_EUC_JP, /* EUC Japanese */
+ CUPS_EUC_KR, /* EUC Korean */
+ CUPS_EUC_TW, /* EUC Traditional Chinese */
+ CUPS_JIS_X0213, /* JIS X0213 aka Shift JIS */
+ CUPS_ENCODING_VBCS_END = 191 /* End of variable-length encodings @private@ */
+} cups_encoding_t;
+
+typedef struct cups_lang_s /**** Language Cache Structure ****/
+{
+ struct cups_lang_s *next; /* Next language in cache */
+ int used; /* Number of times this entry has been used. */
+ cups_encoding_t encoding; /* Text encoding */
+ char language[16]; /* Language/locale name */
+ cups_array_t *strings; /* Message strings @private@ */
+} cups_lang_t;
+
+
+/*
+ * Prototypes...
+ */
+
+extern cups_lang_t *cupsLangDefault(void);
+extern const char *cupsLangEncoding(cups_lang_t *lang);
+extern void cupsLangFlush(void);
+extern void cupsLangFree(cups_lang_t *lang);
+extern cups_lang_t *cupsLangGet(const char *language);
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_LANGUAGE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/libcups2.def b/cups/libcups2.def
new file mode 100644
index 000000000..6d589d2ec
--- /dev/null
+++ b/cups/libcups2.def
@@ -0,0 +1,338 @@
+LIBRARY libcups2
+VERSION 2.9
+EXPORTS
+_cupsGet1284Values
+_cupsGetDests
+_cupsGetPassword
+_cupsGlobals
+_cupsLangPrintError
+_cupsLangPrintf
+_cupsLangPuts
+_cupsLangString
+_cupsMD5Append
+_cupsMD5Finish
+_cupsMD5Init
+_cupsMessageFree
+_cupsMessageLoad
+_cupsMessageLookup
+_cupsNextDelay
+_cupsSetError
+_cupsSetLocale
+_cupsStrAlloc
+_cupsStrFlush
+_cupsStrFormatd
+_cupsStrFree
+_cupsStrRetain
+_cupsStrScand
+_cupsStrStatistics
+_cups_strcpy
+_cups_strlcat
+_cups_strlcpy
+_httpAddrPort
+_httpAddrSetPort
+_httpAssembleUUID
+_httpCreate
+_httpEncodeURI
+_httpPeek
+_httpResolveURI
+_httpSetTimeout
+_httpWait
+_ippAddAttr
+_ippAttrString
+_ippFindOption
+_ippFreeAttr
+_ppdFreeLanguages
+_ppdGetEncoding
+_ppdGetLanguages
+_ppdHashName
+_ppdLocalizedAttr
+_ppdNormalizeMakeAndModel
+_ppdParseOptions
+_pwgCreateWithFile
+_pwgDestroy
+_pwgWriteFile
+_pwgGenerateSize
+_pwgInitSize
+_pwgMediaForLegacy
+_pwgMediaForPPD
+_pwgMediaForPWG
+_pwgMediaForSize
+_pwgCreateWithPPD
+_pwgGetBin
+_pwgGetInputSlot
+_pwgGetMediaType
+_pwgGetOutputBin
+_pwgGetPageSize
+_pwgGetSize
+_pwgGetSource
+_pwgGetType
+_pwgInputSlotForSource
+_pwgMediaTypeForType
+_pwgPageSizeForMedia
+cupsAddDest
+cupsAddOption
+cupsAdminCreateWindowsPPD
+cupsAdminExportSamba
+cupsArrayAdd
+cupsArrayClear
+cupsArrayCount
+cupsArrayCurrent
+cupsArrayDelete
+cupsArrayDup
+cupsArrayFind
+cupsArrayFirst
+cupsArrayGetIndex
+cupsArrayGetInsert
+cupsArrayIndex
+cupsArrayInsert
+cupsArrayLast
+cupsArrayNew
+cupsArrayNew2
+cupsArrayNew3
+cupsArrayNext
+cupsArrayPrev
+cupsArrayRemove
+cupsArrayRestore
+cupsArraySave
+cupsArrayUserData
+cupsCancelJob
+cupsCharsetToUTF8
+cupsDirClose
+cupsDirOpen
+cupsDirRead
+cupsDirRewind
+cupsDoAuthentication
+cupsDoFileRequest
+cupsDoIORequest
+cupsDoRequest
+cupsEncodeOptions
+cupsEncodeOptions2
+cupsEncryption
+cupsFileClose
+cupsFileCompression
+cupsFileEOF
+cupsFileFind
+cupsFileFlush
+cupsFileGetChar
+cupsFileGetConf
+cupsFileGetLine
+cupsFileGets
+cupsFileLock
+cupsFileNumber
+cupsFileOpen
+cupsFileOpenFd
+cupsFilePeekChar
+cupsFilePrintf
+cupsFilePutChar
+cupsFilePuts
+cupsFileRead
+cupsFileRewind
+cupsFileSeek
+cupsFileStderr
+cupsFileStdin
+cupsFileStdout
+cupsFileTell
+cupsFileUnlock
+cupsFileWrite
+cupsFreeDests
+cupsFreeJobs
+cupsFreeOptions
+cupsGetClasses
+cupsGetDefault
+cupsGetDefault2
+cupsGetDest
+cupsGetDests
+cupsGetDests2
+cupsGetFd
+cupsGetFile
+cupsGetJobs
+cupsGetJobs2
+cupsGetOption
+cupsGetPPD
+cupsGetPPD2
+cupsGetPassword
+cupsGetPrinters
+cupsGetResponse
+cupsLangDefault
+cupsLangEncoding
+cupsLangFlush
+cupsLangFree
+cupsLangGet
+cupsLastError
+cupsLastErrorString
+cupsMarkOptions
+cupsNotifySubject
+cupsNotifyText
+cupsParseOptions
+cupsPrintFile
+cupsPrintFile2
+cupsPrintFiles
+cupsPrintFiles2
+cupsPutFd
+cupsPutFile
+cupsRemoveOption
+cupsResolveConflicts
+cupsSendRequest
+cupsServer
+cupsSetClientCertCB
+cupsSetCredentials
+cupsSetDests
+cupsSetDests2
+cupsSetEncryption
+cupsSetPasswordCB
+cupsSetServer
+cupsSetServerCertCB
+cupsSetUser
+cupsTempFd
+cupsTempFile
+cupsTempFile2
+cupsUTF32ToUTF8
+cupsUTF8ToCharset
+cupsUTF8ToUTF32
+cupsUser
+cupsWriteRequestData
+httpAddCredential
+httpAddrAny
+httpAddrConnect
+httpAddrEqual
+httpAddrFreeList
+httpAddrGetList
+httpAddrLength
+httpAddrLocalhost
+httpAddrLookup
+httpAddrString
+httpAssembleURI
+httpAssembleURIf
+httpBlocking
+httpCheck
+httpClearCookie
+httpClearFields
+httpClose
+httpConnect
+httpConnectEncrypt
+httpCopyCredentials
+httpDecode64
+httpDecode64_2
+httpDelete
+httpEncode64
+httpEncode64_2
+httpEncryption
+httpError
+httpFlush
+httpFlushWrite
+httpFreeCredentials
+httpGet
+httpGetBlocking
+httpGetCookie
+httpGetDateString
+httpGetDateString2
+httpGetDateTime
+httpGetFd
+httpGetField
+httpGetHostByName
+httpGetHostname
+httpGetLength
+httpGetLength2
+httpGetStatus
+httpGetSubField
+httpGetSubField2
+httpGets
+httpHead
+httpInitialize
+httpMD5
+httpMD5Final
+httpMD5String
+httpOptions
+httpPost
+httpPrintf
+httpPut
+httpRead
+httpRead2
+httpReconnect
+httpSeparate
+httpSeparate2
+httpSeparateURI
+httpSetCookie
+httpSetCredentials
+httpSetExpect
+httpSetField
+httpSetLength
+httpStatus
+httpTrace
+httpUpdate
+httpWait
+httpWrite
+httpWrite2
+ippAddBoolean
+ippAddBooleans
+ippAddCollection
+ippAddCollections
+ippAddDate
+ippAddInteger
+ippAddIntegers
+ippAddOctetString
+ippAddRange
+ippAddRanges
+ippAddResolution
+ippAddResolutions
+ippAddSeparator
+ippAddString
+ippAddStrings
+ippDateToTime
+ippDelete
+ippDeleteAttribute
+ippErrorString
+ippErrorValue
+ippFindAttribute
+ippFindNextAttribute
+ippLength
+ippNew
+ippNewRequest
+ippOpString
+ippOpValue
+ippPort
+ippRead
+ippReadFile
+ippReadIO
+ippSetPort
+ippTagString
+ippTagValue
+ippTimeToDate
+ippWrite
+ippWriteFile
+ippWriteIO
+ppdClose
+ppdCollect
+ppdCollect2
+ppdConflicts
+ppdEmit
+ppdEmitAfterOrder
+ppdEmitFd
+ppdEmitJCL
+ppdEmitJCLEnd
+ppdEmitString
+ppdErrorString
+ppdFindAttr
+ppdFindChoice
+ppdFindCustomOption
+ppdFindCustomParam
+ppdFindMarkedChoice
+ppdFindNextAttr
+ppdFindOption
+ppdFirstCustomParam
+ppdFirstOption
+ppdIsMarked
+ppdLastError
+ppdLocalize
+ppdMarkDefaults
+ppdMarkOption
+ppdNextCustomParam
+ppdNextOption
+ppdOpen
+ppdOpen2
+ppdOpenFd
+ppdOpenFile
+ppdPageLength
+ppdPageSize
+ppdPageWidth
+ppdSetConformance
diff --git a/cups/libcups_s.exp b/cups/libcups_s.exp
new file mode 100644
index 000000000..4d095537a
--- /dev/null
+++ b/cups/libcups_s.exp
@@ -0,0 +1,83 @@
+_cups_debug_fd
+_cupsGet1284Values
+_cupsGetDests
+_cupsGetPassword
+_cupsGlobals
+_cupsLangPrintError
+_cupsLangPrintf
+_cupsLangPuts
+_cupsLangString
+_cupsMD5Append
+_cupsMD5Finish
+_cupsMD5Init
+_cupsMessageFree
+_cupsMessageLoad
+_cupsMessageLookup
+_cupsNextDelay
+_cupsSetError
+_cupsSetLocale
+_cupsSNMPClose
+_cupsSNMPCopyOID
+_cupsSNMPDefaultCommunity
+_cupsSNMPIsOID
+_cupsSNMPIsOIDPrefixed
+_cupsSNMPOIDToString
+_cupsSNMPOpen
+_cupsSNMPRead
+_cupsSNMPSetDebug
+_cupsSNMPStringToOID
+_cupsSNMPWalk
+_cupsSNMPWrite
+_cupsStrAlloc
+_cupsStrFlush
+_cupsStrFormatd
+_cupsStrFree
+_cupsStrRetain
+_cupsStrScand
+_cupsStrStatistics
+_cups_getifaddrs
+_cups_freeifaddrs
+_cups_strcpy
+_cups_strlcat
+_cups_strlcpy
+_httpAddrPort
+_httpAddrSetPort
+_httpAssembleUUID
+_httpBIOMethods
+_httpCreate
+_httpEncodeURI
+_httpPeek
+_httpResolveURI
+_httpSetTimeout
+_httpWait
+_ippAddAttr
+_ippFindOption
+_ippFreeAttr
+_ppdFreeLanguages
+_ppdGetEncoding
+_ppdGetLanguages
+_ppdHashName
+_ppdLocalizedAttr
+_ppdNormalizeMakeAndModel
+_ppdParseOptions
+_pwgCreateWithFile
+_pwgDestroy
+_pwgWriteFile
+_pwgGenerateSize
+_pwgInitSize
+_pwgMediaForLegacy
+_pwgMediaForPPD
+_pwgMediaForPWG
+_pwgMediaForSize
+_pwgCreateWithPPD
+_pwgGetBin
+_pwgGetInputSlot
+_pwgGetMediaType
+_pwgGetOutputBin
+_pwgGetPageSize
+_pwgGetSize
+_pwgGetSource
+_pwgGetType
+_pwgInputSlotForSource
+_pwgMediaTypeForType
+_pwgPageSizeForMedia
diff --git a/cups/localize.c b/cups/localize.c
new file mode 100644
index 000000000..4d134751a
--- /dev/null
+++ b/cups/localize.c
@@ -0,0 +1,779 @@
+/*
+ * "$Id$"
+ *
+ * PPD localization routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * PostScript is a trademark of Adobe Systems, Inc.
+ *
+ * This code and any derivative of it may be used and distributed
+ * freely under the terms of the GNU General Public License when
+ * used with GNU Ghostscript or its derivatives. Use of the code
+ * (or any derivative of it) with software other than GNU
+ * GhostScript (or its derivatives) is governed by the CUPS license
+ * agreement.
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * ppdLocalize() - Localize the PPD file to the current locale.
+ * ppdLocalizeAttr() - Localize an attribute.
+ * ppdLocalizeIPPReason() - Get the localized version of a cupsIPPReason
+ * attribute.
+ * ppdLocalizeMarkerName() - Get the localized version of a marker-names
+ * attribute value.
+ * _ppdFreeLanguages() - Free an array of languages from _ppdGetLanguages.
+ * _ppdGetLanguages() - Get an array of languages from a PPD file.
+ * _ppdHashName() - Generate a hash value for a device or profile
+ * name.
+ * _ppdLocalizedAttr() - Find a localized attribute.
+ * ppd_ll_CC() - Get the current locale names.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "cups-private.h"
+#include "ppd-private.h"
+
+
+/*
+ * Local functions...
+ */
+
+static cups_lang_t *ppd_ll_CC(char *ll_CC, int ll_CC_size);
+
+
+/*
+ * 'ppdLocalize()' - Localize the PPD file to the current locale.
+ *
+ * All groups, options, and choices are localized, as are ICC profile
+ * descriptions, printer presets, and custom option parameters. Each
+ * localized string uses the UTF-8 character encoding.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 0 on success, -1 on error */
+ppdLocalize(ppd_file_t *ppd) /* I - PPD file */
+{
+ int i, j, k; /* Looping vars */
+ ppd_group_t *group; /* Current group */
+ ppd_option_t *option; /* Current option */
+ ppd_choice_t *choice; /* Current choice */
+ ppd_coption_t *coption; /* Current custom option */
+ ppd_cparam_t *cparam; /* Current custom parameter */
+ ppd_attr_t *attr, /* Current attribute */
+ *locattr; /* Localized attribute */
+ char ckeyword[PPD_MAX_NAME], /* Custom keyword */
+ ll_CC[6]; /* Language + country locale */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("ppdLocalize(ppd=%p)", ppd));
+
+ if (!ppd)
+ return (-1);
+
+ /*
+ * Get the default language...
+ */
+
+ ppd_ll_CC(ll_CC, sizeof(ll_CC));
+
+ /*
+ * Now lookup all of the groups, options, choices, etc.
+ */
+
+ for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
+ {
+ if ((locattr = _ppdLocalizedAttr(ppd, "Translation", group->name,
+ ll_CC)) != NULL)
+ strlcpy(group->text, locattr->text, sizeof(group->text));
+
+ for (j = group->num_options, option = group->options; j > 0; j --, option ++)
+ {
+ if ((locattr = _ppdLocalizedAttr(ppd, "Translation", option->keyword,
+ ll_CC)) != NULL)
+ strlcpy(option->text, locattr->text, sizeof(option->text));
+
+ for (k = option->num_choices, choice = option->choices;
+ k > 0;
+ k --, choice ++)
+ {
+ if (strcmp(choice->choice, "Custom") ||
+ !ppdFindCustomOption(ppd, option->keyword))
+ locattr = _ppdLocalizedAttr(ppd, option->keyword, choice->choice,
+ ll_CC);
+ else
+ {
+ snprintf(ckeyword, sizeof(ckeyword), "Custom%s", option->keyword);
+
+ locattr = _ppdLocalizedAttr(ppd, ckeyword, "True", ll_CC);
+ }
+
+ if (locattr)
+ strlcpy(choice->text, locattr->text, sizeof(choice->text));
+ }
+ }
+ }
+
+ /*
+ * Translate any custom parameters...
+ */
+
+ for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions);
+ coption;
+ coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions))
+ {
+ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+ cparam;
+ cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
+ {
+ snprintf(ckeyword, sizeof(ckeyword), "ParamCustom%s", coption->keyword);
+
+ if ((locattr = _ppdLocalizedAttr(ppd, ckeyword, cparam->name,
+ ll_CC)) != NULL)
+ strlcpy(cparam->text, locattr->text, sizeof(cparam->text));
+ }
+ }
+
+ /*
+ * Translate ICC profile names...
+ */
+
+ if ((attr = ppdFindAttr(ppd, "APCustomColorMatchingName", NULL)) != NULL)
+ {
+ if ((locattr = _ppdLocalizedAttr(ppd, "APCustomColorMatchingName",
+ attr->spec, ll_CC)) != NULL)
+ strlcpy(attr->text, locattr->text, sizeof(attr->text));
+ }
+
+ for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
+ attr;
+ attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
+ {
+ cupsArraySave(ppd->sorted_attrs);
+
+ if ((locattr = _ppdLocalizedAttr(ppd, "cupsICCProfile", attr->spec,
+ ll_CC)) != NULL)
+ strlcpy(attr->text, locattr->text, sizeof(attr->text));
+
+ cupsArrayRestore(ppd->sorted_attrs);
+ }
+
+ /*
+ * Translate printer presets...
+ */
+
+ for (attr = ppdFindAttr(ppd, "APPrinterPreset", NULL);
+ attr;
+ attr = ppdFindNextAttr(ppd, "APPrinterPreset", NULL))
+ {
+ cupsArraySave(ppd->sorted_attrs);
+
+ if ((locattr = _ppdLocalizedAttr(ppd, "APPrinterPreset", attr->spec,
+ ll_CC)) != NULL)
+ strlcpy(attr->text, locattr->text, sizeof(attr->text));
+
+ cupsArrayRestore(ppd->sorted_attrs);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'ppdLocalizeAttr()' - Localize an attribute.
+ *
+ * This function uses the current locale to find the localized attribute for
+ * the given main and option keywords. If no localized version of the
+ * attribute exists for the current locale, the unlocalized version is returned.
+ */
+
+ppd_attr_t * /* O - Localized attribute or @code NULL@ if none exists */
+ppdLocalizeAttr(ppd_file_t *ppd, /* I - PPD file */
+ const char *keyword, /* I - Main keyword */
+ const char *spec) /* I - Option keyword or @code NULL@ for none */
+{
+ ppd_attr_t *locattr; /* Localized attribute */
+ char ll_CC[6]; /* Language + country locale */
+
+
+ /*
+ * Get the default language...
+ */
+
+ ppd_ll_CC(ll_CC, sizeof(ll_CC));
+
+ /*
+ * Find the localized attribute...
+ */
+
+ if (spec)
+ locattr = _ppdLocalizedAttr(ppd, keyword, spec, ll_CC);
+ else
+ locattr = _ppdLocalizedAttr(ppd, "Translation", keyword, ll_CC);
+
+ if (!locattr)
+ locattr = ppdFindAttr(ppd, keyword, spec);
+
+ return (locattr);
+}
+
+
+/*
+ * 'ppdLocalizeIPPReason()' - Get the localized version of a cupsIPPReason
+ * attribute.
+ *
+ * This function uses the current locale to find the corresponding reason
+ * text or URI from the attribute value. If "scheme" is NULL or "text",
+ * the returned value contains human-readable (UTF-8) text from the translation
+ * string or attribute value. Otherwise the corresponding URI is returned.
+ *
+ * If no value of the requested scheme can be found, NULL is returned.
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+const char * /* O - Value or NULL if not found */
+ppdLocalizeIPPReason(
+ ppd_file_t *ppd, /* I - PPD file */
+ const char *reason, /* I - IPP reason keyword to look up */
+ const char *scheme, /* I - URI scheme or NULL for text */
+ char *buffer, /* I - Value buffer */
+ size_t bufsize) /* I - Size of value buffer */
+{
+ cups_lang_t *lang; /* Current language */
+ ppd_attr_t *locattr; /* Localized attribute */
+ char ll_CC[6], /* Language + country locale */
+ *bufptr, /* Pointer into buffer */
+ *bufend, /* Pointer to end of buffer */
+ *valptr; /* Pointer into value */
+ int ch, /* Hex-encoded character */
+ schemelen; /* Length of scheme name */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (buffer)
+ *buffer = '\0';
+
+ if (!ppd || !reason || (scheme && !*scheme) ||
+ !buffer || bufsize < PPD_MAX_TEXT)
+ return (NULL);
+
+ /*
+ * Get the default language...
+ */
+
+ lang = ppd_ll_CC(ll_CC, sizeof(ll_CC));
+
+ /*
+ * Find the localized attribute...
+ */
+
+ if ((locattr = _ppdLocalizedAttr(ppd, "cupsIPPReason", reason,
+ ll_CC)) == NULL)
+ locattr = ppdFindAttr(ppd, "cupsIPPReason", reason);
+
+ if (!locattr)
+ {
+ if (lang && (!scheme || !strcmp(scheme, "text")))
+ {
+ /*
+ * Try to localize a standard printer-state-reason keyword...
+ */
+
+ const char *message = NULL; /* Localized message */
+
+ if (!strncmp(reason, "media-needed", 12))
+ message = _("The paper tray needs to be filled.");
+ else if (!strncmp(reason, "media-jam", 9))
+ message = _("There is a paper jam.");
+ else if (!strncmp(reason, "offline", 7) ||
+ !strncmp(reason, "shutdown", 8))
+ message = _("The printer is not connected.");
+ else if (!strncmp(reason, "toner-low", 9))
+ message = _("The printer is low on toner.");
+ else if (!strncmp(reason, "toner-empty", 11))
+ message = _("The printer is out of toner.");
+ else if (!strncmp(reason, "cover-open", 10))
+ message = _("The printer's cover is open.");
+ else if (!strncmp(reason, "interlock-open", 14))
+ message = _("The printer's interlock is open.");
+ else if (!strncmp(reason, "door-open", 9))
+ message = _("The printer's door is open.");
+ else if (!strncmp(reason, "input-tray-missing", 18))
+ message = _("The paper tray is missing.");
+ else if (!strncmp(reason, "media-low", 9))
+ message = _("The paper tray is almost empty.");
+ else if (!strncmp(reason, "media-empty", 11))
+ message = _("The paper tray is empty.");
+ else if (!strncmp(reason, "output-tray-missing", 19))
+ message = _("The output bin is missing.");
+ else if (!strncmp(reason, "output-area-almost-full", 23))
+ message = _("The output bin is almost full.");
+ else if (!strncmp(reason, "output-area-full", 16))
+ message = _("The output bin is full.");
+ else if (!strncmp(reason, "marker-supply-low", 17))
+ message = _("The printer is almost out of ink.");
+ else if (!strncmp(reason, "marker-supply-empty", 19))
+ message = _("The printer is out of ink.");
+ else if (!strncmp(reason, "marker-waste-almost-full", 24))
+ message = _("The printer's waste bin is almost full.");
+ else if (!strncmp(reason, "marker-waste-full", 17))
+ message = _("The printer's waste bin is full.");
+ else if (!strncmp(reason, "fuser-over-temp", 15))
+ message = _("The fuser's temperature is high.");
+ else if (!strncmp(reason, "fuser-under-temp", 16))
+ message = _("The fuser's temperature is low.");
+ else if (!strncmp(reason, "opc-near-eol", 12))
+ message = _("The optical photoconductor will need to be replaced soon.");
+ else if (!strncmp(reason, "opc-life-over", 13))
+ message = _("The optical photoconductor needs to be replaced.");
+ else if (!strncmp(reason, "developer-low", 13))
+ message = _("The developer unit will need to be replaced soon.");
+ else if (!strncmp(reason, "developer-empty", 15))
+ message = _("The developer unit needs to be replaced.");
+
+ if (message)
+ {
+ strlcpy(buffer, _cupsLangString(lang, message), bufsize);
+ return (buffer);
+ }
+ }
+
+ return (NULL);
+ }
+
+ /*
+ * Now find the value we need...
+ */
+
+ bufend = buffer + bufsize - 1;
+
+ if (!scheme || !strcmp(scheme, "text"))
+ {
+ /*
+ * Copy a text value (either the translation text or text:... URIs from
+ * the value...
+ */
+
+ strlcpy(buffer, locattr->text, bufsize);
+
+ for (valptr = locattr->value, bufptr = buffer; *valptr && bufptr < bufend;)
+ {
+ if (!strncmp(valptr, "text:", 5))
+ {
+ /*
+ * Decode text: URI and add to the buffer...
+ */
+
+ valptr += 5;
+
+ while (*valptr && !_cups_isspace(*valptr) && bufptr < bufend)
+ {
+ if (*valptr == '%' && isxdigit(valptr[1] & 255) &&
+ isxdigit(valptr[2] & 255))
+ {
+ /*
+ * Pull a hex-encoded character from the URI...
+ */
+
+ valptr ++;
+
+ if (isdigit(*valptr & 255))
+ ch = (*valptr - '0') << 4;
+ else
+ ch = (tolower(*valptr) - 'a' + 10) << 4;
+ valptr ++;
+
+ if (isdigit(*valptr & 255))
+ *bufptr++ = ch | (*valptr - '0');
+ else
+ *bufptr++ = ch | (tolower(*valptr) - 'a' + 10);
+ valptr ++;
+ }
+ else if (*valptr == '+')
+ {
+ *bufptr++ = ' ';
+ valptr ++;
+ }
+ else
+ *bufptr++ = *valptr++;
+ }
+ }
+ else
+ {
+ /*
+ * Skip this URI...
+ */
+
+ while (*valptr && !_cups_isspace(*valptr))
+ valptr++;
+ }
+
+ /*
+ * Skip whitespace...
+ */
+
+ while (_cups_isspace(*valptr))
+ valptr ++;
+ }
+
+ if (bufptr > buffer)
+ *bufptr = '\0';
+
+ return (buffer);
+ }
+ else
+ {
+ /*
+ * Copy a URI...
+ */
+
+ schemelen = strlen(scheme);
+ if (scheme[schemelen - 1] == ':') /* Force scheme to be just the name */
+ schemelen --;
+
+ for (valptr = locattr->value, bufptr = buffer; *valptr && bufptr < bufend;)
+ {
+ if ((!strncmp(valptr, scheme, schemelen) && valptr[schemelen] == ':') ||
+ (*valptr == '/' && !strcmp(scheme, "file")))
+ {
+ /*
+ * Copy URI...
+ */
+
+ while (*valptr && !_cups_isspace(*valptr) && bufptr < bufend)
+ *bufptr++ = *valptr++;
+
+ *bufptr = '\0';
+
+ return (buffer);
+ }
+ else
+ {
+ /*
+ * Skip this URI...
+ */
+
+ while (*valptr && !_cups_isspace(*valptr))
+ valptr++;
+ }
+
+ /*
+ * Skip whitespace...
+ */
+
+ while (_cups_isspace(*valptr))
+ valptr ++;
+ }
+
+ return (NULL);
+ }
+}
+
+
+/*
+ * 'ppdLocalizeMarkerName()' - Get the localized version of a marker-names
+ * attribute value.
+ *
+ * This function uses the current locale to find the corresponding name
+ * text from the attribute value. If no localized text for the requested
+ * name can be found, @code NULL@ is returned.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+const char * /* O - Value or @code NULL@ if not found */
+ppdLocalizeMarkerName(
+ ppd_file_t *ppd, /* I - PPD file */
+ const char *name) /* I - Marker name to look up */
+{
+ ppd_attr_t *locattr; /* Localized attribute */
+ char ll_CC[6]; /* Language + country locale */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !name)
+ return (NULL);
+
+ /*
+ * Get the default language...
+ */
+
+ ppd_ll_CC(ll_CC, sizeof(ll_CC));
+
+ /*
+ * Find the localized attribute...
+ */
+
+ if ((locattr = _ppdLocalizedAttr(ppd, "cupsMarkerName", name,
+ ll_CC)) == NULL)
+ locattr = ppdFindAttr(ppd, "cupsMarkerName", name);
+
+ return (locattr ? locattr->text : NULL);
+}
+
+
+/*
+ * '_ppdFreeLanguages()' - Free an array of languages from _ppdGetLanguages.
+ */
+
+void
+_ppdFreeLanguages(
+ cups_array_t *languages) /* I - Languages array */
+{
+ char *language; /* Current language */
+
+
+ for (language = (char *)cupsArrayFirst(languages);
+ language;
+ language = (char *)cupsArrayNext(languages))
+ free(language);
+
+ cupsArrayDelete(languages);
+}
+
+
+/*
+ * '_ppdGetLanguages()' - Get an array of languages from a PPD file.
+ */
+
+cups_array_t * /* O - Languages array */
+_ppdGetLanguages(ppd_file_t *ppd) /* I - PPD file */
+{
+ cups_array_t *languages; /* Languages array */
+ ppd_attr_t *attr; /* cupsLanguages attribute */
+ char *value, /* Copy of attribute value */
+ *start, /* Start of current language */
+ *ptr; /* Pointer into languages */
+
+
+ /*
+ * See if we have a cupsLanguages attribute...
+ */
+
+ if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) == NULL || !attr->value)
+ return (NULL);
+
+ /*
+ * Yes, load the list...
+ */
+
+ if ((languages = cupsArrayNew((cups_array_func_t)strcmp, NULL)) == NULL)
+ return (NULL);
+
+ if ((value = strdup(attr->value)) == NULL)
+ {
+ cupsArrayDelete(languages);
+ return (NULL);
+ }
+
+ for (ptr = value; *ptr;)
+ {
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (_cups_isspace(*ptr))
+ ptr ++;
+
+ if (!*ptr)
+ break;
+
+ /*
+ * Find the end of this language name...
+ */
+
+ for (start = ptr; *ptr && !_cups_isspace(*ptr); ptr ++);
+
+ if (*ptr)
+ *ptr++ = '\0';
+
+ if (!strcmp(start, "en"))
+ continue;
+
+ cupsArrayAdd(languages, strdup(start));
+ }
+
+ /*
+ * Free the temporary string and return either an array with one or more
+ * values or a NULL pointer...
+ */
+
+ free(value);
+
+ if (cupsArrayCount(languages) == 0)
+ {
+ cupsArrayDelete(languages);
+ return (NULL);
+ }
+ else
+ return (languages);
+}
+
+
+/*
+ * '_ppdHashName()' - Generate a hash value for a device or profile name.
+ *
+ * This function is primarily used on Mac OS X, but is generally accessible
+ * since cupstestppd needs to check for profile name collisions in PPD files...
+ */
+
+unsigned /* O - Hash value */
+_ppdHashName(const char *name) /* I - Name to hash */
+{
+ int mult; /* Multiplier */
+ unsigned hash = 0; /* Hash value */
+
+
+ for (mult = 1; *name && mult <= 128; mult ++, name ++)
+ hash += (*name & 255) * mult;
+
+ return (hash);
+}
+
+
+/*
+ * '_ppdLocalizedAttr()' - Find a localized attribute.
+ */
+
+ppd_attr_t * /* O - Localized attribute or NULL */
+_ppdLocalizedAttr(ppd_file_t *ppd, /* I - PPD file */
+ const char *keyword, /* I - Main keyword */
+ const char *spec, /* I - Option keyword */
+ const char *ll_CC) /* I - Language + country locale */
+{
+ char lkeyword[PPD_MAX_NAME]; /* Localization keyword */
+ ppd_attr_t *attr; /* Current attribute */
+
+
+ DEBUG_printf(("4_ppdLocalizedAttr(ppd=%p, keyword=\"%s\", spec=\"%s\", "
+ "ll_CC=\"%s\")", ppd, keyword, spec, ll_CC));
+
+ /*
+ * Look for Keyword.ll_CC, then Keyword.ll...
+ */
+
+ snprintf(lkeyword, sizeof(lkeyword), "%s.%s", ll_CC, keyword);
+ if ((attr = ppdFindAttr(ppd, lkeyword, spec)) == NULL)
+ {
+ snprintf(lkeyword, sizeof(lkeyword), "%2.2s.%s", ll_CC, keyword);
+ attr = ppdFindAttr(ppd, lkeyword, spec);
+
+ if (!attr)
+ {
+ if (!strncmp(ll_CC, "ja", 2))
+ {
+ /*
+ * Due to a bug in the CUPS DDK 1.1.0 ppdmerge program, Japanese
+ * PPD files were incorrectly assigned "jp" as the locale name
+ * instead of "ja". Support both the old (incorrect) and new
+ * locale names for Japanese...
+ */
+
+ snprintf(lkeyword, sizeof(lkeyword), "jp.%s", keyword);
+ attr = ppdFindAttr(ppd, lkeyword, spec);
+ }
+ else if (!strncmp(ll_CC, "no", 2))
+ {
+ /*
+ * Norway has two languages, "Bokmal" (the primary one)
+ * and "Nynorsk" (new Norwegian); we map "no" to "nb" here as
+ * recommended by the locale folks...
+ */
+
+ snprintf(lkeyword, sizeof(lkeyword), "nb.%s", keyword);
+ attr = ppdFindAttr(ppd, lkeyword, spec);
+ }
+ }
+ }
+
+#ifdef DEBUG
+ if (attr)
+ DEBUG_printf(("5_ppdLocalizedAttr: *%s %s/%s: \"%s\"\n", attr->name,
+ attr->spec, attr->text, attr->value ? attr->value : ""));
+ else
+ DEBUG_puts("5_ppdLocalizedAttr: NOT FOUND");
+#endif /* DEBUG */
+
+ return (attr);
+}
+
+
+/*
+ * 'ppd_ll_CC()' - Get the current locale names.
+ */
+
+static cups_lang_t * /* O - Current language */
+ppd_ll_CC(char *ll_CC, /* O - Country-specific locale name */
+ int ll_CC_size) /* I - Size of country-specific name */
+{
+ cups_lang_t *lang; /* Current language */
+
+
+ /*
+ * Get the current locale...
+ */
+
+ if ((lang = cupsLangDefault()) == NULL)
+ {
+ strlcpy(ll_CC, "en_US", ll_CC_size);
+ return (NULL);
+ }
+
+ /*
+ * Copy the locale name...
+ */
+
+ strlcpy(ll_CC, lang->language, ll_CC_size);
+
+ if (strlen(ll_CC) == 2)
+ {
+ /*
+ * Map "ll" to primary/origin country locales to have the best
+ * chance of finding a match...
+ */
+
+ if (!strcmp(ll_CC, "cs"))
+ strlcpy(ll_CC, "cs_CZ", ll_CC_size);
+ else if (!strcmp(ll_CC, "en"))
+ strlcpy(ll_CC, "en_US", ll_CC_size);
+ else if (!strcmp(ll_CC, "ja"))
+ strlcpy(ll_CC, "ja_JP", ll_CC_size);
+ else if (!strcmp(ll_CC, "sv"))
+ strlcpy(ll_CC, "sv_SE", ll_CC_size);
+ else if (!strcmp(ll_CC, "zh")) /* Simplified Chinese */
+ strlcpy(ll_CC, "zh_CN", ll_CC_size);
+ }
+
+ DEBUG_printf(("8ppd_ll_CC: lang->language=\"%s\", ll_CC=\"%s\"...",
+ lang->language, ll_CC));
+ return (lang);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/mark.c b/cups/mark.c
new file mode 100644
index 000000000..cfeea0d9f
--- /dev/null
+++ b/cups/mark.c
@@ -0,0 +1,1099 @@
+/*
+ * "$Id$"
+ *
+ * Option marking routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * PostScript is a trademark of Adobe Systems, Inc.
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsMarkOptions() - Mark command-line options in a PPD file.
+ * ppdFindChoice() - Return a pointer to an option choice.
+ * ppdFindMarkedChoice() - Return the marked choice for the specified option.
+ * ppdFindOption() - Return a pointer to the specified option.
+ * ppdIsMarked() - Check to see if an option is marked.
+ * ppdMarkDefaults() - Mark all default options in the PPD file.
+ * ppdMarkOption() - Mark an option in a PPD file and return the number
+ * of conflicts.
+ * ppdFirstOption() - Return the first option in the PPD file.
+ * ppdNextOption() - Return the next option in the PPD file.
+ * _ppdParseOptions() - Parse options from a PPD file.
+ * ppd_debug_marked() - Output the marked array to stdout...
+ * ppd_defaults() - Set the defaults for this group and all sub-groups.
+ * ppd_mark_choices() - Mark one or more option choices from a string.
+ * ppd_mark_option() - Quickly mark an option without checking for
+ * conflicts.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+
+
+/*
+ * Local functions...
+ */
+
+#ifdef DEBUG
+static void ppd_debug_marked(ppd_file_t *ppd, const char *title);
+#else
+# define ppd_debug_marked(ppd,title)
+#endif /* DEBUG */
+static void ppd_defaults(ppd_file_t *ppd, ppd_group_t *g);
+static void ppd_mark_choices(ppd_file_t *ppd, const char *s);
+static void ppd_mark_option(ppd_file_t *ppd, const char *option,
+ const char *choice);
+
+
+/*
+ * 'cupsMarkOptions()' - Mark command-line options in a PPD file.
+ *
+ * This function maps the IPP "finishings", "media", "mirror",
+ * "multiple-document-handling", "output-bin", "print-color-mode",
+ * "print-quality", "printer-resolution", and "sides" attributes to their
+ * corresponding PPD options and choices.
+ */
+
+int /* O - 1 if conflicts exist, 0 otherwise */
+cupsMarkOptions(
+ ppd_file_t *ppd, /* I - PPD file */
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ int i, j; /* Looping vars */
+ char *ptr, /* Pointer into string */
+ s[255]; /* Temporary string */
+ const char *val, /* Pointer into value */
+ *media, /* media option */
+ *output_bin, /* output-bin option */
+ *page_size, /* PageSize option */
+ *ppd_keyword, /* PPD keyword */
+ *print_color_mode, /* print-color-mode option */
+ *print_quality, /* print-quality option */
+ *sides; /* sides option */
+ cups_option_t *optptr; /* Current option */
+ ppd_attr_t *attr; /* PPD attribute */
+ _ppd_cache_t *cache; /* PPD cache and mapping data */
+
+
+ /*
+ * Check arguments...
+ */
+
+ if (!ppd || num_options <= 0 || !options)
+ return (0);
+
+ ppd_debug_marked(ppd, "Before...");
+
+ /*
+ * Do special handling for finishings, media, output-bin, output-mode,
+ * print-color-mode, print-quality, and PageSize...
+ */
+
+ media = cupsGetOption("media", num_options, options);
+ output_bin = cupsGetOption("output-bin", num_options, options);
+ page_size = cupsGetOption("PageSize", num_options, options);
+ print_quality = cupsGetOption("print-quality", num_options, options);
+ sides = cupsGetOption("sides", num_options, options);
+
+ if ((print_color_mode = cupsGetOption("print-color-mode", num_options,
+ options)) == NULL)
+ print_color_mode = cupsGetOption("output-mode", num_options, options);
+
+ if ((media || output_bin || print_color_mode || print_quality || sides) &&
+ !ppd->cache)
+ {
+ /*
+ * Load PPD cache and mapping data as needed...
+ */
+
+ ppd->cache = _ppdCacheCreateWithPPD(ppd);
+ }
+
+ cache = ppd->cache;
+
+ if (media)
+ {
+ /*
+ * Loop through the option string, separating it at commas and marking each
+ * individual option as long as the corresponding PPD option (PageSize,
+ * InputSlot, etc.) is not also set.
+ *
+ * For PageSize, we also check for an empty option value since some versions
+ * of MacOS X use it to specify auto-selection of the media based solely on
+ * the size.
+ */
+
+ for (val = media; *val;)
+ {
+ /*
+ * Extract the sub-option from the string...
+ */
+
+ for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);)
+ *ptr++ = *val++;
+ *ptr++ = '\0';
+
+ if (*val == ',')
+ val ++;
+
+ /*
+ * Mark it...
+ */
+
+ if (!page_size || !page_size[0])
+ {
+ if (!_cups_strncasecmp(s, "Custom.", 7) || ppdPageSize(ppd, s))
+ ppd_mark_option(ppd, "PageSize", s);
+ else if ((ppd_keyword = _ppdCacheGetPageSize(cache, NULL, s, NULL)) != NULL)
+ ppd_mark_option(ppd, "PageSize", ppd_keyword);
+ }
+
+ if (cache && cache->source_option &&
+ !cupsGetOption(cache->source_option, num_options, options) &&
+ (ppd_keyword = _ppdCacheGetInputSlot(cache, NULL, s)) != NULL)
+ ppd_mark_option(ppd, cache->source_option, ppd_keyword);
+
+ if (!cupsGetOption("MediaType", num_options, options) &&
+ (ppd_keyword = _ppdCacheGetMediaType(cache, NULL, s)) != NULL)
+ ppd_mark_option(ppd, "MediaType", ppd_keyword);
+ }
+ }
+
+ if (cache)
+ {
+ if (!cupsGetOption("com.apple.print.DocumentTicket.PMSpoolFormat",
+ num_options, options) &&
+ !cupsGetOption("APPrinterPreset", num_options, options) &&
+ (print_color_mode || print_quality))
+ {
+ /*
+ * Map output-mode and print-quality to a preset...
+ */
+
+ _pwg_print_color_mode_t pwg_pcm;/* print-color-mode index */
+ _pwg_print_quality_t pwg_pq; /* print-quality index */
+ cups_option_t *preset;/* Current preset option */
+
+ if (print_color_mode && !strcmp(print_color_mode, "monochrome"))
+ pwg_pcm = _PWG_PRINT_COLOR_MODE_MONOCHROME;
+ else
+ pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR;
+
+ if (print_quality)
+ {
+ pwg_pq = atoi(print_quality) - IPP_QUALITY_DRAFT;
+ if (pwg_pq < _PWG_PRINT_QUALITY_DRAFT)
+ pwg_pq = _PWG_PRINT_QUALITY_DRAFT;
+ else if (pwg_pq > _PWG_PRINT_QUALITY_HIGH)
+ pwg_pq = _PWG_PRINT_QUALITY_HIGH;
+ }
+ else
+ pwg_pq = _PWG_PRINT_QUALITY_NORMAL;
+
+ if (cache->num_presets[pwg_pcm][pwg_pq] == 0)
+ {
+ /*
+ * Try to find a preset that works so that we maximize the chances of us
+ * getting a good print using IPP attributes.
+ */
+
+ if (cache->num_presets[pwg_pcm][_PWG_PRINT_QUALITY_NORMAL] > 0)
+ pwg_pq = _PWG_PRINT_QUALITY_NORMAL;
+ else if (cache->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][pwg_pq] > 0)
+ pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR;
+ else
+ {
+ pwg_pq = _PWG_PRINT_QUALITY_NORMAL;
+ pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR;
+ }
+ }
+
+ if (cache->num_presets[pwg_pcm][pwg_pq] > 0)
+ {
+ /*
+ * Copy the preset options as long as the corresponding names are not
+ * already defined in the IPP request...
+ */
+
+ for (i = cache->num_presets[pwg_pcm][pwg_pq],
+ preset = cache->presets[pwg_pcm][pwg_pq];
+ i > 0;
+ i --, preset ++)
+ {
+ if (!cupsGetOption(preset->name, num_options, options))
+ ppd_mark_option(ppd, preset->name, preset->value);
+ }
+ }
+ }
+
+ if (output_bin && !cupsGetOption("OutputBin", num_options, options) &&
+ (ppd_keyword = _ppdCacheGetOutputBin(cache, output_bin)) != NULL)
+ {
+ /*
+ * Map output-bin to OutputBin...
+ */
+
+ ppd_mark_option(ppd, "OutputBin", ppd_keyword);
+ }
+
+ if (sides && cache->sides_option &&
+ !cupsGetOption(cache->sides_option, num_options, options))
+ {
+ /*
+ * Map sides to duplex option...
+ */
+
+ if (!strcmp(sides, "one-sided"))
+ ppd_mark_option(ppd, cache->sides_option, cache->sides_1sided);
+ else if (!strcmp(sides, "two-sided-long-edge"))
+ ppd_mark_option(ppd, cache->sides_option, cache->sides_2sided_long);
+ else if (!strcmp(sides, "two-sided-short-edge"))
+ ppd_mark_option(ppd, cache->sides_option, cache->sides_2sided_short);
+ }
+ }
+
+ /*
+ * Mark other options...
+ */
+
+ for (i = num_options, optptr = options; i > 0; i --, optptr ++)
+ if (!_cups_strcasecmp(optptr->name, "media") ||
+ !_cups_strcasecmp(optptr->name, "output-bin") ||
+ !_cups_strcasecmp(optptr->name, "output-mode") ||
+ !_cups_strcasecmp(optptr->name, "print-quality") ||
+ !_cups_strcasecmp(optptr->name, "sides"))
+ continue;
+ else if (!_cups_strcasecmp(optptr->name, "resolution") ||
+ !_cups_strcasecmp(optptr->name, "printer-resolution"))
+ {
+ ppd_mark_option(ppd, "Resolution", optptr->value);
+ ppd_mark_option(ppd, "SetResolution", optptr->value);
+ /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */
+ ppd_mark_option(ppd, "JCLResolution", optptr->value);
+ /* HP */
+ ppd_mark_option(ppd, "CNRes_PGP", optptr->value);
+ /* Canon */
+ }
+ else if (!_cups_strcasecmp(optptr->name, "multiple-document-handling"))
+ {
+ if (!cupsGetOption("Collate", num_options, options) &&
+ ppdFindOption(ppd, "Collate"))
+ {
+ if (_cups_strcasecmp(optptr->value, "separate-documents-uncollated-copies"))
+ ppd_mark_option(ppd, "Collate", "True");
+ else
+ ppd_mark_option(ppd, "Collate", "False");
+ }
+ }
+ else if (!_cups_strcasecmp(optptr->name, "finishings"))
+ {
+ /*
+ * Lookup cupsIPPFinishings attributes for each value...
+ */
+
+ for (ptr = optptr->value; *ptr;)
+ {
+ /*
+ * Get the next finishings number...
+ */
+
+ if (!isdigit(*ptr & 255))
+ break;
+
+ if ((j = strtol(ptr, &ptr, 10)) < 3)
+ break;
+
+ /*
+ * Skip separator as needed...
+ */
+
+ if (*ptr == ',')
+ ptr ++;
+
+ /*
+ * Look it up in the PPD file...
+ */
+
+ sprintf(s, "%d", j);
+
+ if ((attr = ppdFindAttr(ppd, "cupsIPPFinishings", s)) == NULL)
+ continue;
+
+ /*
+ * Apply "*Option Choice" settings from the attribute value...
+ */
+
+ ppd_mark_choices(ppd, attr->value);
+ }
+ }
+ else if (!_cups_strcasecmp(optptr->name, "APPrinterPreset"))
+ {
+ /*
+ * Lookup APPrinterPreset value...
+ */
+
+ if ((attr = ppdFindAttr(ppd, "APPrinterPreset", optptr->value)) != NULL)
+ {
+ /*
+ * Apply "*Option Choice" settings from the attribute value...
+ */
+
+ ppd_mark_choices(ppd, attr->value);
+ }
+ }
+ else if (!_cups_strcasecmp(optptr->name, "mirror"))
+ ppd_mark_option(ppd, "MirrorPrint", optptr->value);
+ else
+ ppd_mark_option(ppd, optptr->name, optptr->value);
+
+ ppd_debug_marked(ppd, "After...");
+
+ return (ppdConflicts(ppd) > 0);
+}
+
+
+/*
+ * 'ppdFindChoice()' - Return a pointer to an option choice.
+ */
+
+ppd_choice_t * /* O - Choice pointer or @code NULL@ */
+ppdFindChoice(ppd_option_t *o, /* I - Pointer to option */
+ const char *choice) /* I - Name of choice */
+{
+ int i; /* Looping var */
+ ppd_choice_t *c; /* Current choice */
+
+
+ if (!o || !choice)
+ return (NULL);
+
+ if (choice[0] == '{' || !_cups_strncasecmp(choice, "Custom.", 7))
+ choice = "Custom";
+
+ for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
+ if (!_cups_strcasecmp(c->choice, choice))
+ return (c);
+
+ return (NULL);
+}
+
+
+/*
+ * 'ppdFindMarkedChoice()' - Return the marked choice for the specified option.
+ */
+
+ppd_choice_t * /* O - Pointer to choice or @code NULL@ */
+ppdFindMarkedChoice(ppd_file_t *ppd, /* I - PPD file */
+ const char *option) /* I - Keyword/option name */
+{
+ ppd_choice_t key, /* Search key for choice */
+ *marked; /* Marked choice */
+
+
+ DEBUG_printf(("2ppdFindMarkedChoice(ppd=%p, option=\"%s\")", ppd, option));
+
+ if ((key.option = ppdFindOption(ppd, option)) == NULL)
+ {
+ DEBUG_puts("3ppdFindMarkedChoice: Option not found, returning NULL");
+ return (NULL);
+ }
+
+ marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key);
+
+ DEBUG_printf(("3ppdFindMarkedChoice: Returning %p(%s)...", marked,
+ marked ? marked->choice : "NULL"));
+
+ return (marked);
+}
+
+
+/*
+ * 'ppdFindOption()' - Return a pointer to the specified option.
+ */
+
+ppd_option_t * /* O - Pointer to option or @code NULL@ */
+ppdFindOption(ppd_file_t *ppd, /* I - PPD file data */
+ const char *option) /* I - Option/Keyword name */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !option)
+ return (NULL);
+
+ if (ppd->options)
+ {
+ /*
+ * Search in the array...
+ */
+
+ ppd_option_t key; /* Option search key */
+
+
+ strlcpy(key.keyword, option, sizeof(key.keyword));
+
+ return ((ppd_option_t *)cupsArrayFind(ppd->options, &key));
+ }
+ else
+ {
+ /*
+ * Search in each group...
+ */
+
+ int i, j; /* Looping vars */
+ ppd_group_t *group; /* Current group */
+ ppd_option_t *optptr; /* Current option */
+
+
+ for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
+ for (j = group->num_options, optptr = group->options;
+ j > 0;
+ j --, optptr ++)
+ if (!_cups_strcasecmp(optptr->keyword, option))
+ return (optptr);
+
+ return (NULL);
+ }
+}
+
+
+/*
+ * 'ppdIsMarked()' - Check to see if an option is marked.
+ */
+
+int /* O - Non-zero if option is marked */
+ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */
+ const char *option, /* I - Option/Keyword name */
+ const char *choice) /* I - Choice name */
+{
+ ppd_choice_t key, /* Search key */
+ *c; /* Choice pointer */
+
+
+ if (!ppd)
+ return (0);
+
+ if ((key.option = ppdFindOption(ppd, option)) == NULL)
+ return (0);
+
+ if ((c = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) == NULL)
+ return (0);
+
+ return (!strcmp(c->choice, choice));
+}
+
+
+/*
+ * 'ppdMarkDefaults()' - Mark all default options in the PPD file.
+ */
+
+void
+ppdMarkDefaults(ppd_file_t *ppd) /* I - PPD file record */
+{
+ int i; /* Looping variables */
+ ppd_group_t *g; /* Current group */
+ ppd_choice_t *c; /* Current choice */
+
+
+ if (!ppd)
+ return;
+
+ /*
+ * Clean out the marked array...
+ */
+
+ for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
+ c;
+ c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
+ {
+ cupsArrayRemove(ppd->marked, c);
+ c->marked = 0;
+ }
+
+ /*
+ * Then repopulate it with the defaults...
+ */
+
+ for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
+ ppd_defaults(ppd, g);
+}
+
+
+/*
+ * 'ppdMarkOption()' - Mark an option in a PPD file and return the number of
+ * conflicts.
+ */
+
+int /* O - Number of conflicts */
+ppdMarkOption(ppd_file_t *ppd, /* I - PPD file record */
+ const char *option, /* I - Keyword */
+ const char *choice) /* I - Option name */
+{
+ DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")",
+ ppd, option, choice));
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !option || !choice)
+ return (0);
+
+ /*
+ * Mark the option...
+ */
+
+ ppd_mark_option(ppd, option, choice);
+
+ /*
+ * Return the number of conflicts...
+ */
+
+ return (ppdConflicts(ppd));
+}
+
+
+/*
+ * 'ppdFirstOption()' - Return the first option in the PPD file.
+ *
+ * Options are returned from all groups in ascending alphanumeric order.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ppd_option_t * /* O - First option or @code NULL@ */
+ppdFirstOption(ppd_file_t *ppd) /* I - PPD file */
+{
+ if (!ppd)
+ return (NULL);
+ else
+ return ((ppd_option_t *)cupsArrayFirst(ppd->options));
+}
+
+
+/*
+ * 'ppdNextOption()' - Return the next option in the PPD file.
+ *
+ * Options are returned from all groups in ascending alphanumeric order.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ppd_option_t * /* O - Next option or @code NULL@ */
+ppdNextOption(ppd_file_t *ppd) /* I - PPD file */
+{
+ if (!ppd)
+ return (NULL);
+ else
+ return ((ppd_option_t *)cupsArrayNext(ppd->options));
+}
+
+
+/*
+ * '_ppdParseOptions()' - Parse options from a PPD file.
+ *
+ * This function looks for strings of the form:
+ *
+ * *option choice ... *optionN choiceN
+ * property value ... propertyN valueN
+ *
+ * It stops when it finds a string that doesn't match this format.
+ */
+
+int /* O - Number of options */
+_ppdParseOptions(
+ const char *s, /* I - String to parse */
+ int num_options, /* I - Number of options */
+ cups_option_t **options, /* IO - Options */
+ _ppd_parse_t which) /* I - What to parse */
+{
+ char option[PPD_MAX_NAME * 2 + 1], /* Current option/property */
+ choice[PPD_MAX_NAME], /* Current choice/value */
+ *ptr; /* Pointer into option or choice */
+
+
+ if (!s)
+ return (num_options);
+
+ /*
+ * Read all of the "*Option Choice" and "property value" pairs from the
+ * string, add them to an options array as we go...
+ */
+
+ while (*s)
+ {
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (_cups_isspace(*s))
+ s ++;
+
+ /*
+ * Get the option/property name...
+ */
+
+ ptr = option;
+ while (*s && !_cups_isspace(*s) && ptr < (option + sizeof(option) - 1))
+ *ptr++ = *s++;
+
+ if (ptr == s || !_cups_isspace(*s))
+ break;
+
+ *ptr = '\0';
+
+ /*
+ * Get the choice...
+ */
+
+ while (_cups_isspace(*s))
+ s ++;
+
+ if (!*s)
+ break;
+
+ ptr = choice;
+ while (*s && !_cups_isspace(*s) && ptr < (choice + sizeof(choice) - 1))
+ *ptr++ = *s++;
+
+ if (*s && !_cups_isspace(*s))
+ break;
+
+ *ptr = '\0';
+
+ /*
+ * Add it to the options array...
+ */
+
+ if (option[0] == '*' && which != _PPD_PARSE_PROPERTIES)
+ num_options = cupsAddOption(option + 1, choice, num_options, options);
+ else if (option[0] != '*' && which != _PPD_PARSE_OPTIONS)
+ num_options = cupsAddOption(option, choice, num_options, options);
+ }
+
+ return (num_options);
+}
+
+
+#ifdef DEBUG
+/*
+ * 'ppd_debug_marked()' - Output the marked array to stdout...
+ */
+
+static void
+ppd_debug_marked(ppd_file_t *ppd, /* I - PPD file data */
+ const char *title) /* I - Title for list */
+{
+ ppd_choice_t *c; /* Current choice */
+
+
+ DEBUG_printf(("2cupsMarkOptions: %s", title));
+
+ for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
+ c;
+ c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
+ DEBUG_printf(("2cupsMarkOptions: %s=%s", c->option->keyword, c->choice));
+}
+#endif /* DEBUG */
+
+
+/*
+ * 'ppd_defaults()' - Set the defaults for this group and all sub-groups.
+ */
+
+static void
+ppd_defaults(ppd_file_t *ppd, /* I - PPD file */
+ ppd_group_t *g) /* I - Group to default */
+{
+ int i; /* Looping var */
+ ppd_option_t *o; /* Current option */
+ ppd_group_t *sg; /* Current sub-group */
+
+
+ for (i = g->num_options, o = g->options; i > 0; i --, o ++)
+ if (_cups_strcasecmp(o->keyword, "PageRegion") != 0)
+ ppdMarkOption(ppd, o->keyword, o->defchoice);
+
+ for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++)
+ ppd_defaults(ppd, sg);
+}
+
+
+/*
+ * 'ppd_mark_choices()' - Mark one or more option choices from a string.
+ */
+
+static void
+ppd_mark_choices(ppd_file_t *ppd, /* I - PPD file */
+ const char *s) /* I - "*Option Choice ..." string */
+{
+ int i, /* Looping var */
+ num_options; /* Number of options */
+ cups_option_t *options, /* Options */
+ *option; /* Current option */
+
+
+ if (!s)
+ return;
+
+ options = NULL;
+ num_options = _ppdParseOptions(s, 0, &options, 0);
+
+ for (i = num_options, option = options; i > 0; i --, option ++)
+ ppd_mark_option(ppd, option->name, option->value);
+
+ cupsFreeOptions(num_options, options);
+}
+
+
+/*
+ * 'ppd_mark_option()' - Quick mark an option without checking for conflicts.
+ */
+
+static void
+ppd_mark_option(ppd_file_t *ppd, /* I - PPD file */
+ const char *option, /* I - Option name */
+ const char *choice) /* I - Choice name */
+{
+ int i, j; /* Looping vars */
+ ppd_option_t *o; /* Option pointer */
+ ppd_choice_t *c, /* Choice pointer */
+ *oldc, /* Old choice pointer */
+ key; /* Search key for choice */
+ struct lconv *loc; /* Locale data */
+
+
+ DEBUG_printf(("7ppd_mark_option(ppd=%p, option=\"%s\", choice=\"%s\")",
+ ppd, option, choice));
+
+ /*
+ * AP_D_InputSlot is the "default input slot" on MacOS X, and setting
+ * it clears the regular InputSlot choices...
+ */
+
+ if (!_cups_strcasecmp(option, "AP_D_InputSlot"))
+ {
+ cupsArraySave(ppd->options);
+
+ if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
+ {
+ key.option = o;
+ if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+ {
+ oldc->marked = 0;
+ cupsArrayRemove(ppd->marked, oldc);
+ }
+ }
+
+ cupsArrayRestore(ppd->options);
+ }
+
+ /*
+ * Check for custom options...
+ */
+
+ cupsArraySave(ppd->options);
+
+ o = ppdFindOption(ppd, option);
+
+ cupsArrayRestore(ppd->options);
+
+ if (!o)
+ return;
+
+ loc = localeconv();
+
+ if (!_cups_strncasecmp(choice, "Custom.", 7))
+ {
+ /*
+ * Handle a custom option...
+ */
+
+ if ((c = ppdFindChoice(o, "Custom")) == NULL)
+ return;
+
+ if (!_cups_strcasecmp(option, "PageSize"))
+ {
+ /*
+ * Handle custom page sizes...
+ */
+
+ ppdPageSize(ppd, choice);
+ }
+ else
+ {
+ /*
+ * Handle other custom options...
+ */
+
+ ppd_coption_t *coption; /* Custom option */
+ ppd_cparam_t *cparam; /* Custom parameter */
+ char *units; /* Custom points units */
+
+
+ if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
+ {
+ if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL)
+ return;
+
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_CURVE :
+ case PPD_CUSTOM_INVCURVE :
+ case PPD_CUSTOM_REAL :
+ cparam->current.custom_real = (float)_cupsStrScand(choice + 7,
+ NULL, loc);
+ break;
+
+ case PPD_CUSTOM_POINTS :
+ cparam->current.custom_points = (float)_cupsStrScand(choice + 7,
+ &units,
+ loc);
+
+ if (units)
+ {
+ if (!_cups_strcasecmp(units, "cm"))
+ cparam->current.custom_points *= 72.0f / 2.54f;
+ else if (!_cups_strcasecmp(units, "mm"))
+ cparam->current.custom_points *= 72.0f / 25.4f;
+ else if (!_cups_strcasecmp(units, "m"))
+ cparam->current.custom_points *= 72.0f / 0.0254f;
+ else if (!_cups_strcasecmp(units, "in"))
+ cparam->current.custom_points *= 72.0f;
+ else if (!_cups_strcasecmp(units, "ft"))
+ cparam->current.custom_points *= 12.0f * 72.0f;
+ }
+ break;
+
+ case PPD_CUSTOM_INT :
+ cparam->current.custom_int = atoi(choice + 7);
+ break;
+
+ case PPD_CUSTOM_PASSCODE :
+ case PPD_CUSTOM_PASSWORD :
+ case PPD_CUSTOM_STRING :
+ if (cparam->current.custom_string)
+ _cupsStrFree(cparam->current.custom_string);
+
+ cparam->current.custom_string = _cupsStrAlloc(choice + 7);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Make sure that we keep the option marked below...
+ */
+
+ choice = "Custom";
+ }
+ else if (choice[0] == '{')
+ {
+ /*
+ * Handle multi-value custom options...
+ */
+
+ ppd_coption_t *coption; /* Custom option */
+ ppd_cparam_t *cparam; /* Custom parameter */
+ char *units; /* Custom points units */
+ int num_vals; /* Number of values */
+ cups_option_t *vals, /* Values */
+ *val; /* Value */
+
+
+ if ((c = ppdFindChoice(o, "Custom")) == NULL)
+ return;
+
+ if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
+ {
+ num_vals = cupsParseOptions(choice, 0, &vals);
+
+ for (i = 0, val = vals; i < num_vals; i ++, val ++)
+ {
+ if ((cparam = ppdFindCustomParam(coption, val->name)) == NULL)
+ continue;
+
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_CURVE :
+ case PPD_CUSTOM_INVCURVE :
+ case PPD_CUSTOM_REAL :
+ cparam->current.custom_real = (float)_cupsStrScand(val->value,
+ NULL, loc);
+ break;
+
+ case PPD_CUSTOM_POINTS :
+ cparam->current.custom_points = (float)_cupsStrScand(val->value,
+ &units,
+ loc);
+
+ if (units)
+ {
+ if (!_cups_strcasecmp(units, "cm"))
+ cparam->current.custom_points *= 72.0f / 2.54f;
+ else if (!_cups_strcasecmp(units, "mm"))
+ cparam->current.custom_points *= 72.0f / 25.4f;
+ else if (!_cups_strcasecmp(units, "m"))
+ cparam->current.custom_points *= 72.0f / 0.0254f;
+ else if (!_cups_strcasecmp(units, "in"))
+ cparam->current.custom_points *= 72.0f;
+ else if (!_cups_strcasecmp(units, "ft"))
+ cparam->current.custom_points *= 12.0f * 72.0f;
+ }
+ break;
+
+ case PPD_CUSTOM_INT :
+ cparam->current.custom_int = atoi(val->value);
+ break;
+
+ case PPD_CUSTOM_PASSCODE :
+ case PPD_CUSTOM_PASSWORD :
+ case PPD_CUSTOM_STRING :
+ if (cparam->current.custom_string)
+ _cupsStrFree(cparam->current.custom_string);
+
+ cparam->current.custom_string = _cupsStrRetain(val->value);
+ break;
+ }
+ }
+
+ cupsFreeOptions(num_vals, vals);
+ }
+ }
+ else
+ {
+ for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
+ if (!_cups_strcasecmp(c->choice, choice))
+ break;
+
+ if (!i)
+ return;
+ }
+
+ /*
+ * Option found; mark it and then handle unmarking any other options.
+ */
+
+ if (o->ui != PPD_UI_PICKMANY)
+ {
+ /*
+ * Unmark all other choices...
+ */
+
+ if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL)
+ {
+ oldc->marked = 0;
+ cupsArrayRemove(ppd->marked, oldc);
+ }
+
+ if (!_cups_strcasecmp(option, "PageSize") || !_cups_strcasecmp(option, "PageRegion"))
+ {
+ /*
+ * Mark current page size...
+ */
+
+ for (j = 0; j < ppd->num_sizes; j ++)
+ ppd->sizes[j].marked = !_cups_strcasecmp(ppd->sizes[j].name,
+ choice);
+
+ /*
+ * Unmark the current PageSize or PageRegion setting, as
+ * appropriate...
+ */
+
+ cupsArraySave(ppd->options);
+
+ if (!_cups_strcasecmp(option, "PageSize"))
+ {
+ if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
+ {
+ key.option = o;
+ if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+ {
+ oldc->marked = 0;
+ cupsArrayRemove(ppd->marked, oldc);
+ }
+ }
+ }
+ else
+ {
+ if ((o = ppdFindOption(ppd, "PageSize")) != NULL)
+ {
+ key.option = o;
+ if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+ {
+ oldc->marked = 0;
+ cupsArrayRemove(ppd->marked, oldc);
+ }
+ }
+ }
+
+ cupsArrayRestore(ppd->options);
+ }
+ else if (!_cups_strcasecmp(option, "InputSlot"))
+ {
+ /*
+ * Unmark ManualFeed option...
+ */
+
+ cupsArraySave(ppd->options);
+
+ if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
+ {
+ key.option = o;
+ if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+ {
+ oldc->marked = 0;
+ cupsArrayRemove(ppd->marked, oldc);
+ }
+ }
+
+ cupsArrayRestore(ppd->options);
+ }
+ else if (!_cups_strcasecmp(option, "ManualFeed") &&
+ !_cups_strcasecmp(choice, "True"))
+ {
+ /*
+ * Unmark InputSlot option...
+ */
+
+ cupsArraySave(ppd->options);
+
+ if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
+ {
+ key.option = o;
+ if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+ {
+ oldc->marked = 0;
+ cupsArrayRemove(ppd->marked, oldc);
+ }
+ }
+
+ cupsArrayRestore(ppd->options);
+ }
+ }
+
+ c->marked = 1;
+
+ cupsArrayAdd(ppd->marked, c);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/md5-private.h b/cups/md5-private.h
new file mode 100644
index 000000000..3667cf0b3
--- /dev/null
+++ b/cups/md5-private.h
@@ -0,0 +1,79 @@
+/*
+ * "$Id$"
+ *
+ * Private MD5 definitions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2005 by Easy Software Products
+ *
+ * Copyright (C) 1999 Aladdin Enterprises. All rights reserved.
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * L. Peter Deutsch
+ * ghost@aladdin.com
+ */
+
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321.
+ It is derived directly from the text of the RFC and not from the
+ reference implementation.
+
+ The original and principal author of md5.h is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+ added conditionalization for C++ compilation from Martin
+ Purschke <purschke@bnl.gov>.
+ 1999-05-03 lpd Original version.
+ */
+
+#ifndef _CUPS_MD5_PRIVATE_H_
+# define _CUPS_MD5_PRIVATE_H_
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct _cups_md5_state_s {
+ unsigned int count[2]; /* message length in bits, lsw first */
+ unsigned int abcd[4]; /* digest buffer */
+ unsigned char buf[64]; /* accumulate block */
+} _cups_md5_state_t;
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+/* Initialize the algorithm. */
+void _cupsMD5Init(_cups_md5_state_t *pms);
+
+/* Append a string to the message. */
+void _cupsMD5Append(_cups_md5_state_t *pms, const unsigned char *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void _cupsMD5Finish(_cups_md5_state_t *pms, unsigned char digest[16]);
+
+# ifdef __cplusplus
+} /* end extern "C" */
+# endif /* __cplusplus */
+#endif /* !_CUPS_MD5_PRIVATE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/md5.c b/cups/md5.c
new file mode 100644
index 000000000..1f46a957c
--- /dev/null
+++ b/cups/md5.c
@@ -0,0 +1,346 @@
+/*
+ * "$Id$"
+ *
+ * Private MD5 implementation for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2005 by Easy Software Products
+ *
+ * Copyright (C) 1999 Aladdin Enterprises. All rights reserved.
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * L. Peter Deutsch
+ * ghost@aladdin.com
+ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321.
+ It is derived directly from the text of the RFC and not from the
+ reference implementation.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+#include "md5-private.h"
+#include "string-private.h"
+
+#define T1 0xd76aa478
+#define T2 0xe8c7b756
+#define T3 0x242070db
+#define T4 0xc1bdceee
+#define T5 0xf57c0faf
+#define T6 0x4787c62a
+#define T7 0xa8304613
+#define T8 0xfd469501
+#define T9 0x698098d8
+#define T10 0x8b44f7af
+#define T11 0xffff5bb1
+#define T12 0x895cd7be
+#define T13 0x6b901122
+#define T14 0xfd987193
+#define T15 0xa679438e
+#define T16 0x49b40821
+#define T17 0xf61e2562
+#define T18 0xc040b340
+#define T19 0x265e5a51
+#define T20 0xe9b6c7aa
+#define T21 0xd62f105d
+#define T22 0x02441453
+#define T23 0xd8a1e681
+#define T24 0xe7d3fbc8
+#define T25 0x21e1cde6
+#define T26 0xc33707d6
+#define T27 0xf4d50d87
+#define T28 0x455a14ed
+#define T29 0xa9e3e905
+#define T30 0xfcefa3f8
+#define T31 0x676f02d9
+#define T32 0x8d2a4c8a
+#define T33 0xfffa3942
+#define T34 0x8771f681
+#define T35 0x6d9d6122
+#define T36 0xfde5380c
+#define T37 0xa4beea44
+#define T38 0x4bdecfa9
+#define T39 0xf6bb4b60
+#define T40 0xbebfbc70
+#define T41 0x289b7ec6
+#define T42 0xeaa127fa
+#define T43 0xd4ef3085
+#define T44 0x04881d05
+#define T45 0xd9d4d039
+#define T46 0xe6db99e5
+#define T47 0x1fa27cf8
+#define T48 0xc4ac5665
+#define T49 0xf4292244
+#define T50 0x432aff97
+#define T51 0xab9423a7
+#define T52 0xfc93a039
+#define T53 0x655b59c3
+#define T54 0x8f0ccc92
+#define T55 0xffeff47d
+#define T56 0x85845dd1
+#define T57 0x6fa87e4f
+#define T58 0xfe2ce6e0
+#define T59 0xa3014314
+#define T60 0x4e0811a1
+#define T61 0xf7537e82
+#define T62 0xbd3af235
+#define T63 0x2ad7d2bb
+#define T64 0xeb86d391
+
+static void
+_cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/)
+{
+ unsigned int
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ unsigned int t;
+
+#ifndef ARCH_IS_BIG_ENDIAN
+# define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */
+#endif
+#if ARCH_IS_BIG_ENDIAN
+
+ /*
+ * On big-endian machines, we must arrange the bytes in the right
+ * order. (This also works on machines of unknown byte order.)
+ */
+ unsigned int X[16];
+ const unsigned char *xp = data;
+ int i;
+
+ for (i = 0; i < 16; ++i, xp += 4)
+ X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+
+#else /* !ARCH_IS_BIG_ENDIAN */
+
+ /*
+ * On little-endian machines, we can process properly aligned data
+ * without copying it.
+ */
+ unsigned int xbuf[16];
+ const unsigned int *X;
+
+ if (!((data - (const unsigned char *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const unsigned int *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+#endif
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void
+_cupsMD5Init(_cups_md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = 0xefcdab89;
+ pms->abcd[2] = 0x98badcfe;
+ pms->abcd[3] = 0x10325476;
+}
+
+void
+_cupsMD5Append(_cups_md5_state_t *pms, const unsigned char *data, int nbytes)
+{
+ const unsigned char *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ unsigned int nbits = (unsigned int)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ _cups_md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ _cups_md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void
+_cupsMD5Finish(_cups_md5_state_t *pms, unsigned char digest[16])
+{
+ static const unsigned char pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ unsigned char data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (unsigned char)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ _cupsMD5Append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ _cupsMD5Append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (unsigned char)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/md5passwd.c b/cups/md5passwd.c
new file mode 100644
index 000000000..a0dc2cf5b
--- /dev/null
+++ b/cups/md5passwd.c
@@ -0,0 +1,142 @@
+/*
+ * "$Id$"
+ *
+ * MD5 password support for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * httpMD5() - Compute the MD5 sum of the username:group:password.
+ * httpMD5Nonce() - Combine the MD5 sum of the username, group, and password
+ * with the server-supplied nonce value.
+ * httpMD5String() - Convert an MD5 sum to a character string.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "http-private.h"
+#include "string-private.h"
+
+
+/*
+ * 'httpMD5()' - Compute the MD5 sum of the username:group:password.
+ */
+
+char * /* O - MD5 sum */
+httpMD5(const char *username, /* I - User name */
+ const char *realm, /* I - Realm name */
+ const char *passwd, /* I - Password string */
+ char md5[33]) /* O - MD5 string */
+{
+ _cups_md5_state_t state; /* MD5 state info */
+ unsigned char sum[16]; /* Sum data */
+ char line[256]; /* Line to sum */
+
+
+ /*
+ * Compute the MD5 sum of the user name, group name, and password.
+ */
+
+ snprintf(line, sizeof(line), "%s:%s:%s", username, realm, passwd);
+ _cupsMD5Init(&state);
+ _cupsMD5Append(&state, (unsigned char *)line, (int)strlen(line));
+ _cupsMD5Finish(&state, sum);
+
+ /*
+ * Return the sum...
+ */
+
+ return (httpMD5String(sum, md5));
+}
+
+
+/*
+ * 'httpMD5Final()' - Combine the MD5 sum of the username, group, and password
+ * with the server-supplied nonce value, method, and
+ * request-uri.
+ */
+
+char * /* O - New sum */
+httpMD5Final(const char *nonce, /* I - Server nonce value */
+ const char *method, /* I - METHOD (GET, POST, etc.) */
+ const char *resource, /* I - Resource path */
+ char md5[33]) /* IO - MD5 sum */
+{
+ _cups_md5_state_t state; /* MD5 state info */
+ unsigned char sum[16]; /* Sum data */
+ char line[1024]; /* Line of data */
+ char a2[33]; /* Hash of method and resource */
+
+
+ /*
+ * First compute the MD5 sum of the method and resource...
+ */
+
+ snprintf(line, sizeof(line), "%s:%s", method, resource);
+ _cupsMD5Init(&state);
+ _cupsMD5Append(&state, (unsigned char *)line, (int)strlen(line));
+ _cupsMD5Finish(&state, sum);
+ httpMD5String(sum, a2);
+
+ /*
+ * Then combine A1 (MD5 of username, realm, and password) with the nonce
+ * and A2 (method + resource) values to get the final MD5 sum for the
+ * request...
+ */
+
+ snprintf(line, sizeof(line), "%s:%s:%s", md5, nonce, a2);
+
+ _cupsMD5Init(&state);
+ _cupsMD5Append(&state, (unsigned char *)line, (int)strlen(line));
+ _cupsMD5Finish(&state, sum);
+
+ return (httpMD5String(sum, md5));
+}
+
+
+/*
+ * 'httpMD5String()' - Convert an MD5 sum to a character string.
+ */
+
+char * /* O - MD5 sum in hex */
+httpMD5String(const unsigned char *sum, /* I - MD5 sum data */
+ char md5[33])
+ /* O - MD5 sum in hex */
+{
+ int i; /* Looping var */
+ char *md5ptr; /* Pointer into MD5 string */
+ static const char hex[] = "0123456789abcdef";
+ /* Hex digits */
+
+
+ /*
+ * Convert the MD5 sum to hexadecimal...
+ */
+
+ for (i = 16, md5ptr = md5; i > 0; i --, sum ++)
+ {
+ *md5ptr++ = hex[*sum >> 4];
+ *md5ptr++ = hex[*sum & 15];
+ }
+
+ *md5ptr = '\0';
+
+ return (md5);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/notify.c b/cups/notify.c
new file mode 100644
index 000000000..82913cb9b
--- /dev/null
+++ b/cups/notify.c
@@ -0,0 +1,202 @@
+/*
+ * "$Id$"
+ *
+ * Notification routines for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2005-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsNotifySubject() - Return the subject for the given notification
+ * message.
+ * cupsNotifyText() - Return the text for the given notification message.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+
+
+/*
+ * 'cupsNotifySubject()' - Return the subject for the given notification message.
+ *
+ * The returned string must be freed by the caller using @code free@.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+char * /* O - Subject string or @code NULL@ */
+cupsNotifySubject(cups_lang_t *lang, /* I - Language data */
+ ipp_t *event) /* I - Event data */
+{
+ char buffer[1024]; /* Subject buffer */
+ const char *prefix, /* Prefix on subject */
+ *state; /* Printer/job state string */
+ ipp_attribute_t *job_id, /* notify-job-id */
+ *job_name, /* job-name */
+ *job_state, /* job-state */
+ *printer_name, /* printer-name */
+ *printer_state, /* printer-state */
+ *printer_uri, /* notify-printer-uri */
+ *subscribed; /* notify-subscribed-event */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!event || !lang)
+ return (NULL);
+
+ /*
+ * Get the required attributes...
+ */
+
+ job_id = ippFindAttribute(event, "notify-job-id", IPP_TAG_INTEGER);
+ job_name = ippFindAttribute(event, "job-name", IPP_TAG_NAME);
+ job_state = ippFindAttribute(event, "job-state", IPP_TAG_ENUM);
+ printer_name = ippFindAttribute(event, "printer-name", IPP_TAG_NAME);
+ printer_state = ippFindAttribute(event, "printer-state", IPP_TAG_ENUM);
+ printer_uri = ippFindAttribute(event, "notify-printer-uri", IPP_TAG_URI);
+ subscribed = ippFindAttribute(event, "notify-subscribed-event",
+ IPP_TAG_KEYWORD);
+
+
+ if (job_id && printer_name && printer_uri && job_state)
+ {
+ /*
+ * Job event...
+ */
+
+ prefix = _cupsLangString(lang, _("Print Job:"));
+
+ switch (job_state->values[0].integer)
+ {
+ case IPP_JOB_PENDING :
+ state = _cupsLangString(lang, _("pending"));
+ break;
+ case IPP_JOB_HELD :
+ state = _cupsLangString(lang, _("held"));
+ break;
+ case IPP_JOB_PROCESSING :
+ state = _cupsLangString(lang, _("processing"));
+ break;
+ case IPP_JOB_STOPPED :
+ state = _cupsLangString(lang, _("stopped"));
+ break;
+ case IPP_JOB_CANCELED :
+ state = _cupsLangString(lang, _("canceled"));
+ break;
+ case IPP_JOB_ABORTED :
+ state = _cupsLangString(lang, _("aborted"));
+ break;
+ case IPP_JOB_COMPLETED :
+ state = _cupsLangString(lang, _("completed"));
+ break;
+ default :
+ state = _cupsLangString(lang, _("unknown"));
+ break;
+ }
+
+ snprintf(buffer, sizeof(buffer), "%s %s-%d (%s) %s",
+ prefix,
+ printer_name->values[0].string.text,
+ job_id->values[0].integer,
+ job_name ? job_name->values[0].string.text :
+ _cupsLangString(lang, _("untitled")),
+ state);
+ }
+ else if (printer_uri && printer_name && printer_state)
+ {
+ /*
+ * Printer event...
+ */
+
+ prefix = _cupsLangString(lang, _("Printer:"));
+
+ switch (printer_state->values[0].integer)
+ {
+ case IPP_PRINTER_IDLE :
+ state = _cupsLangString(lang, _("idle"));
+ break;
+ case IPP_PRINTER_PROCESSING :
+ state = _cupsLangString(lang, _("processing"));
+ break;
+ case IPP_PRINTER_STOPPED :
+ state = _cupsLangString(lang, _("stopped"));
+ break;
+ default :
+ state = _cupsLangString(lang, _("unknown"));
+ break;
+ }
+
+ snprintf(buffer, sizeof(buffer), "%s %s %s",
+ prefix,
+ printer_name->values[0].string.text,
+ state);
+ }
+ else if (subscribed)
+ strlcpy(buffer, subscribed->values[0].string.text, sizeof(buffer));
+ else
+ return (NULL);
+
+ /*
+ * Duplicate and return the subject string...
+ */
+
+ return (strdup(buffer));
+}
+
+
+/*
+ * 'cupsNotifyText()' - Return the text for the given notification message.
+ *
+ * The returned string must be freed by the caller using @code free@.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+char * /* O - Message text or @code NULL@ */
+cupsNotifyText(cups_lang_t *lang, /* I - Language data */
+ ipp_t *event) /* I - Event data */
+{
+ ipp_attribute_t *notify_text; /* notify-text */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!event || !lang)
+ return (NULL);
+
+ /*
+ * Get the notify-text attribute from the server...
+ */
+
+ if ((notify_text = ippFindAttribute(event, "notify-text",
+ IPP_TAG_TEXT)) == NULL)
+ return (NULL);
+
+ /*
+ * Return a copy...
+ */
+
+ return (strdup(notify_text->values[0].string.text));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/options.c b/cups/options.c
new file mode 100644
index 000000000..4cff43c0f
--- /dev/null
+++ b/cups/options.c
@@ -0,0 +1,711 @@
+/*
+ * "$Id$"
+ *
+ * Option routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsAddOption() - Add an option to an option array.
+ * cupsFreeOptions() - Free all memory used by options.
+ * cupsGetOption() - Get an option value.
+ * cupsParseOptions() - Parse options from a command-line argument.
+ * cupsRemoveOption() - Remove an option from an option array.
+ * _cupsGet1284Values() - Get 1284 device ID keys and values.
+ * cups_compare_options() - Compare two options.
+ * cups_find_option() - Find an option using a binary search.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+
+
+/*
+ * Local functions...
+ */
+
+static int cups_compare_options(cups_option_t *a, cups_option_t *b);
+static int cups_find_option(const char *name, int num_options,
+ cups_option_t *option, int prev, int *rdiff);
+
+
+/*
+ * 'cupsAddOption()' - Add an option to an option array.
+ *
+ * New option arrays can be initialized simply by passing 0 for the
+ * "num_options" parameter.
+ */
+
+int /* O - Number of options */
+cupsAddOption(const char *name, /* I - Name of option */
+ const char *value, /* I - Value of option */
+ int num_options,/* I - Number of options */
+ cups_option_t **options) /* IO - Pointer to options */
+{
+ cups_option_t *temp; /* Pointer to new option */
+ int insert, /* Insertion point */
+ diff; /* Result of search */
+
+
+ DEBUG_printf(("2cupsAddOption(name=\"%s\", value=\"%s\", num_options=%d, "
+ "options=%p)", name, value, num_options, options));
+
+ if (!name || !name[0] || !value || !options || num_options < 0)
+ {
+ DEBUG_printf(("3cupsAddOption: Returning %d", num_options));
+ return (num_options);
+ }
+
+ /*
+ * Look for an existing option with the same name...
+ */
+
+ if (num_options == 0)
+ {
+ insert = 0;
+ diff = 1;
+ }
+ else
+ {
+ insert = cups_find_option(name, num_options, *options, num_options - 1,
+ &diff);
+
+ if (diff > 0)
+ insert ++;
+ }
+
+ if (diff)
+ {
+ /*
+ * No matching option name...
+ */
+
+ DEBUG_printf(("4cupsAddOption: New option inserted at index %d...",
+ insert));
+
+ if (num_options == 0)
+ temp = (cups_option_t *)malloc(sizeof(cups_option_t));
+ else
+ temp = (cups_option_t *)realloc(*options, sizeof(cups_option_t) *
+ (num_options + 1));
+
+ if (temp == NULL)
+ {
+ DEBUG_puts("3cupsAddOption: Unable to expand option array, returning 0");
+ return (0);
+ }
+
+ *options = temp;
+
+ if (insert < num_options)
+ {
+ DEBUG_printf(("4cupsAddOption: Shifting %d options...",
+ (int)(num_options - insert)));
+ memmove(temp + insert + 1, temp + insert,
+ (num_options - insert) * sizeof(cups_option_t));
+ }
+
+ temp += insert;
+ temp->name = _cupsStrAlloc(name);
+ num_options ++;
+ }
+ else
+ {
+ /*
+ * Match found; free the old value...
+ */
+
+ DEBUG_printf(("4cupsAddOption: Option already exists at index %d...",
+ insert));
+
+ temp = *options + insert;
+ _cupsStrFree(temp->value);
+ }
+
+ temp->value = _cupsStrAlloc(value);
+
+ DEBUG_printf(("3cupsAddOption: Returning %d", num_options));
+
+ return (num_options);
+}
+
+
+/*
+ * 'cupsFreeOptions()' - Free all memory used by options.
+ */
+
+void
+cupsFreeOptions(
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Pointer to options */
+{
+ int i; /* Looping var */
+
+
+ DEBUG_printf(("cupsFreeOptions(num_options=%d, options=%p)", num_options,
+ options));
+
+ if (num_options <= 0 || !options)
+ return;
+
+ for (i = 0; i < num_options; i ++)
+ {
+ _cupsStrFree(options[i].name);
+ _cupsStrFree(options[i].value);
+ }
+
+ free(options);
+}
+
+
+/*
+ * 'cupsGetOption()' - Get an option value.
+ */
+
+const char * /* O - Option value or @code NULL@ */
+cupsGetOption(const char *name, /* I - Name of option */
+ int num_options,/* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ int diff, /* Result of comparison */
+ match; /* Matching index */
+
+
+ DEBUG_printf(("2cupsGetOption(name=\"%s\", num_options=%d, options=%p)",
+ name, num_options, options));
+
+ if (!name || num_options <= 0 || !options)
+ {
+ DEBUG_puts("3cupsGetOption: Returning NULL");
+ return (NULL);
+ }
+
+ match = cups_find_option(name, num_options, options, -1, &diff);
+
+ if (!diff)
+ {
+ DEBUG_printf(("3cupsGetOption: Returning \"%s\"", options[match].value));
+ return (options[match].value);
+ }
+
+ DEBUG_puts("3cupsGetOption: Returning NULL");
+ return (NULL);
+}
+
+
+/*
+ * 'cupsParseOptions()' - Parse options from a command-line argument.
+ *
+ * This function converts space-delimited name/value pairs according
+ * to the PAPI text option ABNF specification. Collection values
+ * ("name={a=... b=... c=...}") are stored with the curley brackets
+ * intact - use @code cupsParseOptions@ on the value to extract the
+ * collection attributes.
+ */
+
+int /* O - Number of options found */
+cupsParseOptions(
+ const char *arg, /* I - Argument to parse */
+ int num_options, /* I - Number of options */
+ cups_option_t **options) /* O - Options found */
+{
+ char *copyarg, /* Copy of input string */
+ *ptr, /* Pointer into string */
+ *name, /* Pointer to name */
+ *value, /* Pointer to value */
+ sep, /* Separator character */
+ quote; /* Quote character */
+
+
+ DEBUG_printf(("cupsParseOptions(arg=\"%s\", num_options=%d, options=%p)",
+ arg, num_options, options));
+
+ /*
+ * Range check input...
+ */
+
+ if (!arg)
+ {
+ DEBUG_printf(("1cupsParseOptions: Returning %d", num_options));
+ return (num_options);
+ }
+
+ if (!options || num_options < 0)
+ {
+ DEBUG_puts("1cupsParseOptions: Returning 0");
+ return (0);
+ }
+
+ /*
+ * Make a copy of the argument string and then divide it up...
+ */
+
+ if ((copyarg = strdup(arg)) == NULL)
+ {
+ DEBUG_puts("1cupsParseOptions: Unable to copy arg string");
+ DEBUG_printf(("1cupsParseOptions: Returning %d", num_options));
+ return (num_options);
+ }
+
+ if (*copyarg == '{')
+ {
+ /*
+ * Remove surrounding {} so we can parse "{name=value ... name=value}"...
+ */
+
+ if ((ptr = copyarg + strlen(copyarg) - 1) > copyarg && *ptr == '}')
+ {
+ *ptr = '\0';
+ ptr = copyarg + 1;
+ }
+ else
+ ptr = copyarg;
+ }
+ else
+ ptr = copyarg;
+
+ /*
+ * Skip leading spaces...
+ */
+
+ while (_cups_isspace(*ptr))
+ ptr ++;
+
+ /*
+ * Loop through the string...
+ */
+
+ while (*ptr != '\0')
+ {
+ /*
+ * Get the name up to a SPACE, =, or end-of-string...
+ */
+
+ name = ptr;
+ while (!strchr("\f\n\r\t\v =", *ptr) && *ptr)
+ ptr ++;
+
+ /*
+ * Avoid an empty name...
+ */
+
+ if (ptr == name)
+ break;
+
+ /*
+ * Skip trailing spaces...
+ */
+
+ while (_cups_isspace(*ptr))
+ *ptr++ = '\0';
+
+ if ((sep = *ptr) == '=')
+ *ptr++ = '\0';
+
+ DEBUG_printf(("2cupsParseOptions: name=\"%s\"", name));
+
+ if (sep != '=')
+ {
+ /*
+ * Boolean option...
+ */
+
+ if (!_cups_strncasecmp(name, "no", 2))
+ num_options = cupsAddOption(name + 2, "false", num_options,
+ options);
+ else
+ num_options = cupsAddOption(name, "true", num_options, options);
+
+ continue;
+ }
+
+ /*
+ * Remove = and parse the value...
+ */
+
+ value = ptr;
+
+ while (*ptr && !_cups_isspace(*ptr))
+ {
+ if (*ptr == ',')
+ ptr ++;
+ else if (*ptr == '\'' || *ptr == '\"')
+ {
+ /*
+ * Quoted string constant...
+ */
+
+ quote = *ptr;
+ _cups_strcpy(ptr, ptr + 1);
+
+ while (*ptr != quote && *ptr)
+ {
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+
+ ptr ++;
+ }
+
+ if (*ptr)
+ _cups_strcpy(ptr, ptr + 1);
+ }
+ else if (*ptr == '{')
+ {
+ /*
+ * Collection value...
+ */
+
+ int depth;
+
+ for (depth = 0; *ptr; ptr ++)
+ {
+ if (*ptr == '{')
+ depth ++;
+ else if (*ptr == '}')
+ {
+ depth --;
+ if (!depth)
+ {
+ ptr ++;
+ break;
+ }
+ }
+ else if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+ }
+ }
+ else
+ {
+ /*
+ * Normal space-delimited string...
+ */
+
+ while (*ptr && !_cups_isspace(*ptr))
+ {
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+
+ ptr ++;
+ }
+ }
+ }
+
+ if (*ptr != '\0')
+ *ptr++ = '\0';
+
+ DEBUG_printf(("2cupsParseOptions: value=\"%s\"", value));
+
+ /*
+ * Skip trailing whitespace...
+ */
+
+ while (_cups_isspace(*ptr))
+ ptr ++;
+
+ /*
+ * Add the string value...
+ */
+
+ num_options = cupsAddOption(name, value, num_options, options);
+ }
+
+ /*
+ * Free the copy of the argument we made and return the number of options
+ * found.
+ */
+
+ free(copyarg);
+
+ DEBUG_printf(("1cupsParseOptions: Returning %d", num_options));
+
+ return (num_options);
+}
+
+
+/*
+ * 'cupsRemoveOption()' - Remove an option from an option array.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - New number of options */
+cupsRemoveOption(
+ const char *name, /* I - Option name */
+ int num_options, /* I - Current number of options */
+ cups_option_t **options) /* IO - Options */
+{
+ int i; /* Looping var */
+ cups_option_t *option; /* Current option */
+
+
+ DEBUG_printf(("2cupsRemoveOption(name=\"%s\", num_options=%d, options=%p)",
+ name, num_options, options));
+
+ /*
+ * Range check input...
+ */
+
+ if (!name || num_options < 1 || !options)
+ {
+ DEBUG_printf(("3cupsRemoveOption: Returning %d", num_options));
+ return (num_options);
+ }
+
+ /*
+ * Loop for the option...
+ */
+
+ for (i = num_options, option = *options; i > 0; i --, option ++)
+ if (!_cups_strcasecmp(name, option->name))
+ break;
+
+ if (i)
+ {
+ /*
+ * Remove this option from the array...
+ */
+
+ DEBUG_puts("4cupsRemoveOption: Found option, removing it...");
+
+ num_options --;
+ i --;
+
+ _cupsStrFree(option->name);
+ _cupsStrFree(option->value);
+
+ if (i > 0)
+ memmove(option, option + 1, i * sizeof(cups_option_t));
+ }
+
+ /*
+ * Return the new number of options...
+ */
+
+ DEBUG_printf(("3cupsRemoveOption: Returning %d", num_options));
+ return (num_options);
+}
+
+
+/*
+ * '_cupsGet1284Values()' - Get 1284 device ID keys and values.
+ *
+ * The returned dictionary is a CUPS option array that can be queried with
+ * cupsGetOption and freed with cupsFreeOptions.
+ */
+
+int /* O - Number of key/value pairs */
+_cupsGet1284Values(
+ const char *device_id, /* I - IEEE-1284 device ID string */
+ cups_option_t **values) /* O - Array of key/value pairs */
+{
+ int num_values; /* Number of values */
+ char key[256], /* Key string */
+ value[256], /* Value string */
+ *ptr; /* Pointer into key/value */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (values)
+ *values = NULL;
+
+ if (!device_id || !values)
+ return (0);
+
+ /*
+ * Parse the 1284 device ID value into keys and values. The format is
+ * repeating sequences of:
+ *
+ * [whitespace]key:value[whitespace];
+ */
+
+ num_values = 0;
+ while (*device_id)
+ {
+ while (_cups_isspace(*device_id))
+ device_id ++;
+
+ if (!*device_id)
+ break;
+
+ for (ptr = key; *device_id && *device_id != ':'; device_id ++)
+ if (ptr < (key + sizeof(key) - 1))
+ *ptr++ = *device_id;
+
+ if (!*device_id)
+ break;
+
+ while (ptr > key && _cups_isspace(ptr[-1]))
+ ptr --;
+
+ *ptr = '\0';
+ device_id ++;
+
+ while (_cups_isspace(*device_id))
+ device_id ++;
+
+ if (!*device_id)
+ break;
+
+ for (ptr = value; *device_id && *device_id != ';'; device_id ++)
+ if (ptr < (value + sizeof(value) - 1))
+ *ptr++ = *device_id;
+
+ if (!*device_id)
+ break;
+
+ while (ptr > value && _cups_isspace(ptr[-1]))
+ ptr --;
+
+ *ptr = '\0';
+ device_id ++;
+
+ num_values = cupsAddOption(key, value, num_values, values);
+ }
+
+ return (num_values);
+}
+
+
+/*
+ * 'cups_compare_options()' - Compare two options.
+ */
+
+static int /* O - Result of comparison */
+cups_compare_options(cups_option_t *a, /* I - First option */
+ cups_option_t *b) /* I - Second option */
+{
+ return (_cups_strcasecmp(a->name, b->name));
+}
+
+
+/*
+ * 'cups_find_option()' - Find an option using a binary search.
+ */
+
+static int /* O - Index of match */
+cups_find_option(
+ const char *name, /* I - Option name */
+ int num_options, /* I - Number of options */
+ cups_option_t *options, /* I - Options */
+ int prev, /* I - Previous index */
+ int *rdiff) /* O - Difference of match */
+{
+ int left, /* Low mark for binary search */
+ right, /* High mark for binary search */
+ current, /* Current index */
+ diff; /* Result of comparison */
+ cups_option_t key; /* Search key */
+
+
+ DEBUG_printf(("7cups_find_option(name=\"%s\", num_options=%d, options=%p, "
+ "prev=%d, rdiff=%p)", name, num_options, options, prev,
+ rdiff));
+
+#ifdef DEBUG
+ for (left = 0; left < num_options; left ++)
+ DEBUG_printf(("9cups_find_option: options[%d].name=\"%s\", .value=\"%s\"",
+ left, options[left].name, options[left].value));
+#endif /* DEBUG */
+
+ key.name = (char *)name;
+
+ if (prev >= 0)
+ {
+ /*
+ * Start search on either side of previous...
+ */
+
+ if ((diff = cups_compare_options(&key, options + prev)) == 0 ||
+ (diff < 0 && prev == 0) ||
+ (diff > 0 && prev == (num_options - 1)))
+ {
+ *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 = num_options - 1;
+ }
+ }
+ else
+ {
+ /*
+ * Start search in the middle...
+ */
+
+ left = 0;
+ right = num_options - 1;
+ }
+
+ do
+ {
+ current = (left + right) / 2;
+ diff = cups_compare_options(&key, options + current);
+
+ 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 = cups_compare_options(&key, options + left)) <= 0)
+ current = left;
+ else
+ {
+ diff = cups_compare_options(&key, options + right);
+ current = right;
+ }
+ }
+
+ /*
+ * Return the closest destination and the difference...
+ */
+
+ *rdiff = diff;
+
+ return (current);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/page.c b/cups/page.c
new file mode 100644
index 000000000..b14713fb0
--- /dev/null
+++ b/cups/page.c
@@ -0,0 +1,396 @@
+/*
+ * "$Id$"
+ *
+ * Page size functions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * PostScript is a trademark of Adobe Systems, Inc.
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * ppdPageSize() - Get the page size record for the given size.
+ * ppdPageSizeLimits() - Return the custom page size limits.
+ * ppdPageWidth() - Get the page width for the given size.
+ * ppdPageLength() - Get the page length for the given size.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "string-private.h"
+#include "debug-private.h"
+#include "ppd.h"
+
+
+/*
+ * 'ppdPageSize()' - Get the page size record for the given size.
+ */
+
+ppd_size_t * /* O - Size record for page or NULL */
+ppdPageSize(ppd_file_t *ppd, /* I - PPD file record */
+ const char *name) /* I - Size name */
+{
+ int i; /* Looping var */
+ ppd_size_t *size; /* Current page size */
+ double w, l; /* Width and length of page */
+ char *nameptr; /* Pointer into name */
+ struct lconv *loc; /* Locale data */
+ ppd_coption_t *coption; /* Custom option for page size */
+ ppd_cparam_t *cparam; /* Custom option parameter */
+
+
+ DEBUG_printf(("2ppdPageSize(ppd=%p, name=\"%s\")", ppd, name));
+
+ if (!ppd)
+ {
+ DEBUG_puts("3ppdPageSize: Bad PPD pointer, returning NULL...");
+ return (NULL);
+ }
+
+ if (name)
+ {
+ if (!strncmp(name, "Custom.", 7) && ppd->variable_sizes)
+ {
+ /*
+ * Find the custom page size...
+ */
+
+ for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
+ if (!strcmp("Custom", size->name))
+ break;
+
+ if (!i)
+ {
+ DEBUG_puts("3ppdPageSize: No custom sizes, returning NULL...");
+ return (NULL);
+ }
+
+ /*
+ * Variable size; size name can be one of the following:
+ *
+ * Custom.WIDTHxLENGTHin - Size in inches
+ * Custom.WIDTHxLENGTHft - Size in feet
+ * Custom.WIDTHxLENGTHcm - Size in centimeters
+ * Custom.WIDTHxLENGTHmm - Size in millimeters
+ * Custom.WIDTHxLENGTHm - Size in meters
+ * Custom.WIDTHxLENGTH[pt] - Size in points
+ */
+
+ loc = localeconv();
+ w = _cupsStrScand(name + 7, &nameptr, loc);
+ if (!nameptr || *nameptr != 'x')
+ return (NULL);
+
+ l = _cupsStrScand(nameptr + 1, &nameptr, loc);
+ if (!nameptr)
+ return (NULL);
+
+ if (!_cups_strcasecmp(nameptr, "in"))
+ {
+ w *= 72.0;
+ l *= 72.0;
+ }
+ else if (!_cups_strcasecmp(nameptr, "ft"))
+ {
+ w *= 12.0 * 72.0;
+ l *= 12.0 * 72.0;
+ }
+ else if (!_cups_strcasecmp(nameptr, "mm"))
+ {
+ w *= 72.0 / 25.4;
+ l *= 72.0 / 25.4;
+ }
+ else if (!_cups_strcasecmp(nameptr, "cm"))
+ {
+ w *= 72.0 / 2.54;
+ l *= 72.0 / 2.54;
+ }
+ else if (!_cups_strcasecmp(nameptr, "m"))
+ {
+ w *= 72.0 / 0.0254;
+ l *= 72.0 / 0.0254;
+ }
+
+ size->width = (float)w;
+ size->length = (float)l;
+ size->left = ppd->custom_margins[0];
+ size->bottom = ppd->custom_margins[1];
+ size->right = (float)(w - ppd->custom_margins[2]);
+ size->top = (float)(l - ppd->custom_margins[3]);
+
+ /*
+ * Update the custom option records for the page size, too...
+ */
+
+ if ((coption = ppdFindCustomOption(ppd, "PageSize")) != NULL)
+ {
+ if ((cparam = ppdFindCustomParam(coption, "Width")) != NULL)
+ cparam->current.custom_points = (float)w;
+
+ if ((cparam = ppdFindCustomParam(coption, "Height")) != NULL)
+ cparam->current.custom_points = (float)l;
+ }
+
+ /*
+ * Return the page size...
+ */
+
+ DEBUG_printf(("3ppdPageSize: Returning %p (\"%s\", %gx%g)", size,
+ size->name, size->width, size->length));
+
+ return (size);
+ }
+ else
+ {
+ /*
+ * Lookup by name...
+ */
+
+ for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
+ if (!_cups_strcasecmp(name, size->name))
+ {
+ DEBUG_printf(("3ppdPageSize: Returning %p (\"%s\", %gx%g)", size,
+ size->name, size->width, size->length));
+
+ return (size);
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Find default...
+ */
+
+ for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
+ if (size->marked)
+ {
+ DEBUG_printf(("3ppdPageSize: Returning %p (\"%s\", %gx%g)", size,
+ size->name, size->width, size->length));
+
+ return (size);
+ }
+ }
+
+ DEBUG_puts("3ppdPageSize: Size not found, returning NULL");
+
+ return (NULL);
+}
+
+
+/*
+ * 'ppdPageSizeLimits()' - Return the custom page size limits.
+ *
+ * This function returns the minimum and maximum custom page sizes and printable
+ * areas based on the currently-marked (selected) options.
+ *
+ * If the specified PPD file does not support custom page sizes, both
+ * "minimum" and "maximum" are filled with zeroes.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+int /* O - 1 if custom sizes are supported, 0 otherwise */
+ppdPageSizeLimits(ppd_file_t *ppd, /* I - PPD file record */
+ ppd_size_t *minimum, /* O - Minimum custom size */
+ ppd_size_t *maximum) /* O - Maximum custom size */
+{
+ ppd_choice_t *qualifier2, /* Second media qualifier */
+ *qualifier3; /* Third media qualifier */
+ ppd_attr_t *attr; /* Attribute */
+ float width, /* Min/max width */
+ length; /* Min/max length */
+ char spec[PPD_MAX_NAME]; /* Selector for min/max */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !ppd->variable_sizes || !minimum || !maximum)
+ {
+ if (minimum)
+ memset(minimum, 0, sizeof(ppd_size_t));
+
+ if (maximum)
+ memset(maximum, 0, sizeof(ppd_size_t));
+
+ return (0);
+ }
+
+ /*
+ * See if we have the cupsMediaQualifier2 and cupsMediaQualifier3 attributes...
+ */
+
+ cupsArraySave(ppd->sorted_attrs);
+
+ if ((attr = ppdFindAttr(ppd, "cupsMediaQualifier2", NULL)) != NULL &&
+ attr->value)
+ qualifier2 = ppdFindMarkedChoice(ppd, attr->value);
+ else
+ qualifier2 = NULL;
+
+ if ((attr = ppdFindAttr(ppd, "cupsMediaQualifier3", NULL)) != NULL &&
+ attr->value)
+ qualifier3 = ppdFindMarkedChoice(ppd, attr->value);
+ else
+ qualifier3 = NULL;
+
+ /*
+ * Figure out the current minimum width and length...
+ */
+
+ width = ppd->custom_min[0];
+ length = ppd->custom_min[1];
+
+ if (qualifier2)
+ {
+ /*
+ * Try getting cupsMinSize...
+ */
+
+ if (qualifier3)
+ {
+ snprintf(spec, sizeof(spec), ".%s.%s", qualifier2->choice,
+ qualifier3->choice);
+ attr = ppdFindAttr(ppd, "cupsMinSize", spec);
+ }
+ else
+ attr = NULL;
+
+ if (!attr)
+ {
+ snprintf(spec, sizeof(spec), ".%s.", qualifier2->choice);
+ attr = ppdFindAttr(ppd, "cupsMinSize", spec);
+ }
+
+ if (!attr && qualifier3)
+ {
+ snprintf(spec, sizeof(spec), "..%s", qualifier3->choice);
+ attr = ppdFindAttr(ppd, "cupsMinSize", spec);
+ }
+
+ if ((attr && attr->value &&
+ sscanf(attr->value, "%f%f", &width, &length) != 2) || !attr)
+ {
+ width = ppd->custom_min[0];
+ length = ppd->custom_min[1];
+ }
+ }
+
+ minimum->width = width;
+ minimum->length = length;
+ minimum->left = ppd->custom_margins[0];
+ minimum->bottom = ppd->custom_margins[1];
+ minimum->right = width - ppd->custom_margins[2];
+ minimum->top = length - ppd->custom_margins[3];
+
+ /*
+ * Figure out the current maximum width and length...
+ */
+
+ width = ppd->custom_max[0];
+ length = ppd->custom_max[1];
+
+ if (qualifier2)
+ {
+ /*
+ * Try getting cupsMaxSize...
+ */
+
+ if (qualifier3)
+ {
+ snprintf(spec, sizeof(spec), ".%s.%s", qualifier2->choice,
+ qualifier3->choice);
+ attr = ppdFindAttr(ppd, "cupsMaxSize", spec);
+ }
+ else
+ attr = NULL;
+
+ if (!attr)
+ {
+ snprintf(spec, sizeof(spec), ".%s.", qualifier2->choice);
+ attr = ppdFindAttr(ppd, "cupsMaxSize", spec);
+ }
+
+ if (!attr && qualifier3)
+ {
+ snprintf(spec, sizeof(spec), "..%s", qualifier3->choice);
+ attr = ppdFindAttr(ppd, "cupsMaxSize", spec);
+ }
+
+ if (!attr ||
+ (attr->value && sscanf(attr->value, "%f%f", &width, &length) != 2))
+ {
+ width = ppd->custom_max[0];
+ length = ppd->custom_max[1];
+ }
+ }
+
+ maximum->width = width;
+ maximum->length = length;
+ maximum->left = ppd->custom_margins[0];
+ maximum->bottom = ppd->custom_margins[1];
+ maximum->right = width - ppd->custom_margins[2];
+ maximum->top = length - ppd->custom_margins[3];
+
+ /*
+ * Return the min and max...
+ */
+
+ cupsArrayRestore(ppd->sorted_attrs);
+
+ return (1);
+}
+
+
+/*
+ * 'ppdPageWidth()' - Get the page width for the given size.
+ */
+
+float /* O - Width of page in points or 0.0 */
+ppdPageWidth(ppd_file_t *ppd, /* I - PPD file record */
+ const char *name) /* I - Size name */
+{
+ ppd_size_t *size; /* Page size */
+
+
+ if ((size = ppdPageSize(ppd, name)) == NULL)
+ return (0.0);
+ else
+ return (size->width);
+}
+
+
+/*
+ * 'ppdPageLength()' - Get the page length for the given size.
+ */
+
+float /* O - Length of page in points or 0.0 */
+ppdPageLength(ppd_file_t *ppd, /* I - PPD file */
+ const char *name) /* I - Size name */
+{
+ ppd_size_t *size; /* Page size */
+
+
+ if ((size = ppdPageSize(ppd, name)) == NULL)
+ return (0.0);
+ else
+ return (size->length);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/ppd-cache.c b/cups/ppd-cache.c
new file mode 100644
index 000000000..b19610981
--- /dev/null
+++ b/cups/ppd-cache.c
@@ -0,0 +1,2374 @@
+/*
+ * "$Id$"
+ *
+ * PPD cache implementation for CUPS.
+ *
+ * Copyright 2010-2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _ppdCacheCreateWithFile() - Create PPD cache and mapping data from a
+ * written file.
+ * _ppdCacheCreateWithPPD() - Create PWG mapping data from a PPD file.
+ * _ppdCacheDestroy() - Free all memory used for PWG mapping data.
+ * _ppdCacheGetBin() - Get the PWG output-bin keyword associated with
+ * a PPD OutputBin.
+ * _ppdCacheGetInputSlot() - Get the PPD InputSlot associated with the job
+ * attributes or a keyword string.
+ * _ppdCacheGetMediaType() - Get the PPD MediaType associated with the job
+ * attributes or a keyword string.
+ * _ppdCacheGetOutputBin() - Get the PPD OutputBin associated with the
+ * keyword string.
+ * _ppdCacheGetPageSize() - Get the PPD PageSize associated with the job
+ * attributes or a keyword string.
+ * _ppdCacheGetSize() - Get the PWG size associated with a PPD
+ * PageSize.
+ * _ppdCacheGetSource() - Get the PWG media-source associated with a PPD
+ * InputSlot.
+ * _ppdCacheGetType() - Get the PWG media-type associated with a PPD
+ * MediaType.
+ * _ppdCacheWriteFile() - Write PWG mapping data to a file.
+ * _pwgInputSlotForSource() - Get the InputSlot name for the given PWG
+ * media-source.
+ * _pwgMediaTypeForType() - Get the MediaType name for the given PWG
+ * media-type.
+ * _pwgPageSizeForMedia() - Get the PageSize name for the given media.
+ * pwg_ppdize_name() - Convert an IPP keyword to a PPD keyword.
+ * pwg_unppdize_name() - Convert a PPD keyword to a lowercase IPP
+ * keyword.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include <math.h>
+
+
+/*
+ * Macro to test for two almost-equal PWG measurements.
+ */
+
+#define _PWG_EQUIVALENT(x, y) (abs((x)-(y)) < 2)
+
+
+/*
+ * Local functions...
+ */
+
+static void pwg_ppdize_name(const char *ipp, char *name, size_t namesize);
+static void pwg_unppdize_name(const char *ppd, char *name, size_t namesize);
+
+
+/*
+ * '_ppdCacheCreateWithFile()' - Create PPD cache and mapping data from a
+ * written file.
+ *
+ * Use the @link _ppdCacheWriteFile@ function to write PWG mapping data to a
+ * file.
+ */
+
+_ppd_cache_t * /* O - PPD cache and mapping data */
+_ppdCacheCreateWithFile(
+ const char *filename, /* I - File to read */
+ ipp_t **attrs) /* IO - IPP attributes, if any */
+{
+ cups_file_t *fp; /* File */
+ _ppd_cache_t *pc; /* PWG mapping data */
+ _pwg_size_t *size; /* Current size */
+ _pwg_map_t *map; /* Current map */
+ int linenum, /* Current line number */
+ num_bins, /* Number of bins in file */
+ num_sizes, /* Number of sizes in file */
+ num_sources, /* Number of sources in file */
+ num_types; /* Number of types in file */
+ char line[2048], /* Current line */
+ *value, /* Pointer to value in line */
+ *valueptr, /* Pointer into value */
+ pwg_keyword[128], /* PWG keyword */
+ ppd_keyword[PPD_MAX_NAME];
+ /* PPD keyword */
+ _pwg_print_color_mode_t print_color_mode;
+ /* Print color mode for preset */
+ _pwg_print_quality_t print_quality; /* Print quality for preset */
+
+
+ DEBUG_printf(("_ppdCacheCreateWithFile(filename=\"%s\")", filename));
+
+ /*
+ * Range check input...
+ */
+
+ if (attrs)
+ *attrs = NULL;
+
+ if (!filename)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
+ return (NULL);
+ }
+
+ /*
+ * Open the file...
+ */
+
+ if ((fp = cupsFileOpen(filename, "r")) == NULL)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno), 0);
+ return (NULL);
+ }
+
+ /*
+ * Read the first line and make sure it has "#CUPS-PPD-CACHE-version" in it...
+ */
+
+ if (!cupsFileGets(fp, line, sizeof(line)))
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno), 0);
+ DEBUG_puts("_ppdCacheCreateWithFile: Unable to read first line.");
+ cupsFileClose(fp);
+ return (NULL);
+ }
+
+ if (strncmp(line, "#CUPS-PPD-CACHE-", 16))
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ DEBUG_printf(("_ppdCacheCreateWithFile: Wrong first line \"%s\".", line));
+ cupsFileClose(fp);
+ return (NULL);
+ }
+
+ if (atoi(line + 16) != _PPD_CACHE_VERSION)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Out of date PPD cache file."), 1);
+ DEBUG_printf(("_ppdCacheCreateWithFile: Cache file has version %s, "
+ "expected %d.", line + 16, _PPD_CACHE_VERSION));
+ cupsFileClose(fp);
+ return (NULL);
+ }
+
+ /*
+ * Allocate the mapping data structure...
+ */
+
+ if ((pc = calloc(1, sizeof(_ppd_cache_t))) == NULL)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno), 0);
+ DEBUG_puts("_ppdCacheCreateWithFile: Unable to allocate _ppd_cache_t.");
+ goto create_error;
+ }
+
+ /*
+ * Read the file...
+ */
+
+ linenum = 0;
+ num_bins = 0;
+ num_sizes = 0;
+ num_sources = 0;
+ num_types = 0;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: line=\"%s\", value=\"%s\", "
+ "linenum=%d", line, value, linenum));
+
+ if (!value)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Missing value on line %d.",
+ linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+ else if (!_cups_strcasecmp(line, "Filter"))
+ {
+ if (!pc->filters)
+ pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0,
+ (cups_acopy_func_t)_cupsStrAlloc,
+ (cups_afree_func_t)_cupsStrFree);
+
+ cupsArrayAdd(pc->filters, value);
+ }
+ else if (!_cups_strcasecmp(line, "PreFilter"))
+ {
+ if (!pc->prefilters)
+ pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0,
+ (cups_acopy_func_t)_cupsStrAlloc,
+ (cups_afree_func_t)_cupsStrFree);
+
+ cupsArrayAdd(pc->prefilters, value);
+ }
+ else if (!_cups_strcasecmp(line, "Product"))
+ {
+ pc->product = _cupsStrAlloc(value);
+ }
+ else if (!_cups_strcasecmp(line, "SingleFile"))
+ {
+ pc->single_file = !_cups_strcasecmp(value, "true");
+ }
+ else if (!_cups_strcasecmp(line, "IPP"))
+ {
+ off_t pos = cupsFileTell(fp), /* Position in file */
+ length = strtol(value, NULL, 10);
+ /* Length of IPP attributes */
+
+ if (attrs && *attrs)
+ {
+ DEBUG_puts("_ppdCacheCreateWithFile: IPP listed multiple times.");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+ else if (length <= 0)
+ {
+ DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP length.");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if (attrs)
+ {
+ /*
+ * Read IPP attributes into the provided variable...
+ */
+
+ *attrs = ippNew();
+
+ if (ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL,
+ *attrs) != IPP_DATA)
+ {
+ DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP data.");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+ }
+ else
+ {
+ /*
+ * Skip the IPP data entirely...
+ */
+
+ cupsFileSeek(fp, pos + length);
+ }
+
+ if (cupsFileTell(fp) != (pos + length))
+ {
+ DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP data.");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "NumBins"))
+ {
+ if (num_bins > 0)
+ {
+ DEBUG_puts("_ppdCacheCreateWithFile: NumBins listed multiple times.");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if ((num_bins = atoi(value)) <= 0 || num_bins > 65536)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumBins value %d on line "
+ "%d.", num_sizes, linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if ((pc->bins = calloc(num_bins, sizeof(_pwg_map_t))) == NULL)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d bins.",
+ num_sizes));
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno), 0);
+ goto create_error;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "Bin"))
+ {
+ if (sscanf(value, "%127s%40s", pwg_keyword, ppd_keyword) != 2)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Bad Bin on line %d.", linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if (pc->num_bins >= num_bins)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Too many Bin's on line %d.",
+ linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ map = pc->bins + pc->num_bins;
+ map->pwg = _cupsStrAlloc(pwg_keyword);
+ map->ppd = _cupsStrAlloc(ppd_keyword);
+
+ pc->num_bins ++;
+ }
+ else if (!_cups_strcasecmp(line, "NumSizes"))
+ {
+ if (num_sizes > 0)
+ {
+ DEBUG_puts("_ppdCacheCreateWithFile: NumSizes listed multiple times.");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if ((num_sizes = atoi(value)) <= 0 || num_sizes > 65536)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumSizes value %d on line "
+ "%d.", num_sizes, linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if ((pc->sizes = calloc(num_sizes, sizeof(_pwg_size_t))) == NULL)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d sizes.",
+ num_sizes));
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno), 0);
+ goto create_error;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "Size"))
+ {
+ if (pc->num_sizes >= num_sizes)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Too many Size's on line %d.",
+ linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ size = pc->sizes + pc->num_sizes;
+
+ if (sscanf(value, "%127s%40s%d%d%d%d%d%d", pwg_keyword, ppd_keyword,
+ &(size->width), &(size->length), &(size->left),
+ &(size->bottom), &(size->right), &(size->top)) != 8)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Bad Size on line %d.",
+ linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ size->map.pwg = _cupsStrAlloc(pwg_keyword);
+ size->map.ppd = _cupsStrAlloc(ppd_keyword);
+
+ pc->num_sizes ++;
+ }
+ else if (!_cups_strcasecmp(line, "CustomSize"))
+ {
+ if (pc->custom_max_width > 0)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Too many CustomSize's on line "
+ "%d.", linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if (sscanf(value, "%d%d%d%d%d%d%d%d", &(pc->custom_max_width),
+ &(pc->custom_max_length), &(pc->custom_min_width),
+ &(pc->custom_min_length), &(pc->custom_size.left),
+ &(pc->custom_size.bottom), &(pc->custom_size.right),
+ &(pc->custom_size.top)) != 8)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Bad CustomSize on line %d.",
+ linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), "custom", "max",
+ pc->custom_max_width, pc->custom_max_length);
+ pc->custom_max_keyword = _cupsStrAlloc(pwg_keyword);
+
+ _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), "custom", "min",
+ pc->custom_min_width, pc->custom_min_length);
+ pc->custom_min_keyword = _cupsStrAlloc(pwg_keyword);
+ }
+ else if (!_cups_strcasecmp(line, "SourceOption"))
+ {
+ pc->source_option = _cupsStrAlloc(value);
+ }
+ else if (!_cups_strcasecmp(line, "NumSources"))
+ {
+ if (num_sources > 0)
+ {
+ DEBUG_puts("_ppdCacheCreateWithFile: NumSources listed multiple "
+ "times.");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if ((num_sources = atoi(value)) <= 0 || num_sources > 65536)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumSources value %d on "
+ "line %d.", num_sources, linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if ((pc->sources = calloc(num_sources, sizeof(_pwg_map_t))) == NULL)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d sources.",
+ num_sources));
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno), 0);
+ goto create_error;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "Source"))
+ {
+ if (sscanf(value, "%127s%40s", pwg_keyword, ppd_keyword) != 2)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Bad Source on line %d.",
+ linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if (pc->num_sources >= num_sources)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Too many Source's on line %d.",
+ linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ map = pc->sources + pc->num_sources;
+ map->pwg = _cupsStrAlloc(pwg_keyword);
+ map->ppd = _cupsStrAlloc(ppd_keyword);
+
+ pc->num_sources ++;
+ }
+ else if (!_cups_strcasecmp(line, "NumTypes"))
+ {
+ if (num_types > 0)
+ {
+ DEBUG_puts("_ppdCacheCreateWithFile: NumTypes listed multiple times.");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if ((num_types = atoi(value)) <= 0 || num_types > 65536)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumTypes value %d on "
+ "line %d.", num_types, linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if ((pc->types = calloc(num_types, sizeof(_pwg_map_t))) == NULL)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d types.",
+ num_types));
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno), 0);
+ goto create_error;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "Type"))
+ {
+ if (sscanf(value, "%127s%40s", pwg_keyword, ppd_keyword) != 2)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Bad Type on line %d.",
+ linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if (pc->num_types >= num_types)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Too many Type's on line %d.",
+ linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ map = pc->types + pc->num_types;
+ map->pwg = _cupsStrAlloc(pwg_keyword);
+ map->ppd = _cupsStrAlloc(ppd_keyword);
+
+ pc->num_types ++;
+ }
+ else if (!_cups_strcasecmp(line, "Preset"))
+ {
+ /*
+ * Preset output-mode print-quality name=value ...
+ */
+
+ print_color_mode = (_pwg_print_color_mode_t)strtol(value, &valueptr, 10);
+ print_quality = (_pwg_print_quality_t)strtol(valueptr, &valueptr, 10);
+
+ if (print_color_mode < _PWG_PRINT_COLOR_MODE_MONOCHROME ||
+ print_color_mode >= _PWG_PRINT_COLOR_MODE_MAX ||
+ print_quality < _PWG_PRINT_QUALITY_DRAFT ||
+ print_quality >= _PWG_PRINT_QUALITY_MAX ||
+ valueptr == value || !*valueptr)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Bad Preset on line %d.",
+ linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ pc->num_presets[print_color_mode][print_quality] =
+ cupsParseOptions(valueptr, 0,
+ pc->presets[print_color_mode] + print_quality);
+ }
+ else if (!_cups_strcasecmp(line, "SidesOption"))
+ pc->sides_option = _cupsStrAlloc(value);
+ else if (!_cups_strcasecmp(line, "Sides1Sided"))
+ pc->sides_1sided = _cupsStrAlloc(value);
+ else if (!_cups_strcasecmp(line, "Sides2SidedLong"))
+ pc->sides_2sided_long = _cupsStrAlloc(value);
+ else if (!_cups_strcasecmp(line, "Sides2SidedShort"))
+ pc->sides_2sided_short = _cupsStrAlloc(value);
+ else
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Unknown %s on line %d.", line,
+ linenum));
+ }
+ }
+
+ if (pc->num_sizes < num_sizes)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Not enough sizes (%d < %d).",
+ pc->num_sizes, num_sizes));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if (pc->num_sources < num_sources)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Not enough sources (%d < %d).",
+ pc->num_sources, num_sources));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ if (pc->num_types < num_types)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithFile: Not enough types (%d < %d).",
+ pc->num_types, num_types));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PPD cache file."), 1);
+ goto create_error;
+ }
+
+ cupsFileClose(fp);
+
+ return (pc);
+
+ /*
+ * If we get here the file was bad - free any data and return...
+ */
+
+ create_error:
+
+ cupsFileClose(fp);
+ _ppdCacheDestroy(pc);
+
+ if (attrs)
+ {
+ ippDelete(*attrs);
+ *attrs = NULL;
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * '_ppdCacheCreateWithPPD()' - Create PWG mapping data from a PPD file.
+ */
+
+_ppd_cache_t * /* O - PPD cache and mapping data */
+_ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */
+{
+ int i, j, k; /* Looping vars */
+ _ppd_cache_t *pc; /* PWG mapping data */
+ ppd_option_t *input_slot, /* InputSlot option */
+ *media_type, /* MediaType option */
+ *output_bin, /* OutputBin option */
+ *color_model, /* ColorModel option */
+ *duplex; /* Duplex option */
+ ppd_choice_t *choice; /* Current InputSlot/MediaType */
+ _pwg_map_t *map; /* Current source/type map */
+ ppd_attr_t *ppd_attr; /* Current PPD preset attribute */
+ int num_options; /* Number of preset options and props */
+ cups_option_t *options; /* Preset options and properties */
+ ppd_size_t *ppd_size; /* Current PPD size */
+ _pwg_size_t *pwg_size; /* Current PWG size */
+ char pwg_keyword[3 + PPD_MAX_NAME + 1 + 12 + 1 + 12 + 3],
+ /* PWG keyword string */
+ ppd_name[PPD_MAX_NAME];
+ /* Normalized PPD name */
+ const char *pwg_name; /* Standard PWG media name */
+ _pwg_media_t *pwg_media; /* PWG media data */
+ _pwg_print_color_mode_t pwg_print_color_mode;
+ /* print-color-mode index */
+ _pwg_print_quality_t pwg_print_quality;
+ /* print-quality index */
+ int similar; /* Are the old and new size similar? */
+ _pwg_size_t *old_size; /* Current old size */
+ int old_imageable, /* Old imageable length in 2540ths */
+ old_borderless, /* Old borderless state */
+ old_known_pwg; /* Old PWG name is well-known */
+ int new_width, /* New width in 2540ths */
+ new_length, /* New length in 2540ths */
+ new_left, /* New left margin in 2540ths */
+ new_bottom, /* New bottom margin in 2540ths */
+ new_right, /* New right margin in 2540ths */
+ new_top, /* New top margin in 2540ths */
+ new_imageable, /* New imageable length in 2540ths */
+ new_borderless, /* New borderless state */
+ new_known_pwg; /* New PWG name is well-known */
+ _pwg_size_t *new_size; /* New size to add, if any */
+ const char *filter; /* Current filter */
+
+
+ DEBUG_printf(("_ppdCacheCreateWithPPD(ppd=%p)", ppd));
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd)
+ return (NULL);
+
+ /*
+ * Allocate memory...
+ */
+
+ if ((pc = calloc(1, sizeof(_ppd_cache_t))) == NULL)
+ {
+ DEBUG_puts("_ppdCacheCreateWithPPD: Unable to allocate _ppd_cache_t.");
+ goto create_error;
+ }
+
+ /*
+ * Copy and convert size data...
+ */
+
+ if (ppd->num_sizes == 0)
+ {
+ DEBUG_puts("_ppdCacheCreateWithPPD: No page sizes in PPD.");
+ goto create_error;
+ }
+
+ if ((pc->sizes = calloc(ppd->num_sizes, sizeof(_pwg_size_t))) == NULL)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
+ "_pwg_size_t's.", ppd->num_sizes));
+ goto create_error;
+ }
+
+ for (i = ppd->num_sizes, pwg_size = pc->sizes, ppd_size = ppd->sizes;
+ i > 0;
+ i --, ppd_size ++)
+ {
+ /*
+ * Don't copy over custom size...
+ */
+
+ if (!_cups_strcasecmp(ppd_size->name, "Custom"))
+ continue;
+
+ /*
+ * Convert the PPD size name to the corresponding PWG keyword name.
+ */
+
+ if ((pwg_media = _pwgMediaForPPD(ppd_size->name)) != NULL)
+ {
+ /*
+ * Standard name, do we have conflicts?
+ */
+
+ for (j = 0; j < pc->num_sizes; j ++)
+ if (!strcmp(pc->sizes[j].map.pwg, pwg_media->pwg))
+ {
+ pwg_media = NULL;
+ break;
+ }
+ }
+
+ if (pwg_media)
+ {
+ /*
+ * Standard name and no conflicts, use it!
+ */
+
+ pwg_name = pwg_media->pwg;
+ new_known_pwg = 1;
+ }
+ else
+ {
+ /*
+ * Not a standard name; convert it to a PWG vendor name of the form:
+ *
+ * pp_lowerppd_WIDTHxHEIGHTuu
+ */
+
+ pwg_name = pwg_keyword;
+ new_known_pwg = 0;
+
+ pwg_unppdize_name(ppd_size->name, ppd_name, sizeof(ppd_name));
+ _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), NULL, ppd_name,
+ _PWG_FROMPTS(ppd_size->width),
+ _PWG_FROMPTS(ppd_size->length));
+ }
+
+ /*
+ * If we have a similar paper with non-zero margins then we only
+ * want to keep it if it has a larger imageable area length.
+ */
+
+ new_width = _PWG_FROMPTS(ppd_size->width);
+ new_length = _PWG_FROMPTS(ppd_size->length);
+ new_left = _PWG_FROMPTS(ppd_size->left);
+ new_bottom = _PWG_FROMPTS(ppd_size->bottom);
+ new_right = _PWG_FROMPTS(ppd_size->width - ppd_size->right);
+ new_top = _PWG_FROMPTS(ppd_size->length - ppd_size->top);
+ new_imageable = new_length - new_top - new_bottom;
+ new_borderless = new_bottom == 0 && new_top == 0 &&
+ new_left == 0 && new_right == 0;
+
+ for (k = pc->num_sizes, similar = 0, old_size = pc->sizes, new_size = NULL;
+ k > 0 && !similar;
+ k --, old_size ++)
+ {
+ old_imageable = old_size->length - old_size->top - old_size->bottom;
+ old_borderless = old_size->left == 0 && old_size->bottom == 0 &&
+ old_size->right == 0 && old_size->top == 0;
+ old_known_pwg = strncmp(old_size->map.pwg, "oe_", 3) &&
+ strncmp(old_size->map.pwg, "om_", 3);
+
+ similar = old_borderless == new_borderless &&
+ _PWG_EQUIVALENT(old_size->width, new_width) &&
+ _PWG_EQUIVALENT(old_size->length, new_length);
+
+ if (similar &&
+ (new_known_pwg || (!old_known_pwg && new_imageable > old_imageable)))
+ {
+ /*
+ * The new paper has a larger imageable area so it could replace
+ * the older paper. Regardless of the imageable area, we always
+ * prefer the size with a well-known PWG name.
+ */
+
+ new_size = old_size;
+ _cupsStrFree(old_size->map.ppd);
+ _cupsStrFree(old_size->map.pwg);
+ }
+ }
+
+ if (!similar)
+ {
+ /*
+ * The paper was unique enough to deserve its own entry so add it to the
+ * end.
+ */
+
+ new_size = pwg_size ++;
+ pc->num_sizes ++;
+ }
+
+ if (new_size)
+ {
+ /*
+ * Save this size...
+ */
+
+ new_size->map.ppd = _cupsStrAlloc(ppd_size->name);
+ new_size->map.pwg = _cupsStrAlloc(pwg_name);
+ new_size->width = new_width;
+ new_size->length = new_length;
+ new_size->left = new_left;
+ new_size->bottom = new_bottom;
+ new_size->right = new_right;
+ new_size->top = new_top;
+ }
+ }
+
+ if (ppd->variable_sizes)
+ {
+ /*
+ * Generate custom size data...
+ */
+
+ _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), "custom", "max",
+ _PWG_FROMPTS(ppd->custom_max[0]),
+ _PWG_FROMPTS(ppd->custom_max[1]));
+ pc->custom_max_keyword = _cupsStrAlloc(pwg_keyword);
+ pc->custom_max_width = _PWG_FROMPTS(ppd->custom_max[0]);
+ pc->custom_max_length = _PWG_FROMPTS(ppd->custom_max[1]);
+
+ _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), "custom", "min",
+ _PWG_FROMPTS(ppd->custom_min[0]),
+ _PWG_FROMPTS(ppd->custom_min[1]));
+ pc->custom_min_keyword = _cupsStrAlloc(pwg_keyword);
+ pc->custom_min_width = _PWG_FROMPTS(ppd->custom_min[0]);
+ pc->custom_min_length = _PWG_FROMPTS(ppd->custom_min[1]);
+
+ pc->custom_size.left = _PWG_FROMPTS(ppd->custom_margins[0]);
+ pc->custom_size.bottom = _PWG_FROMPTS(ppd->custom_margins[1]);
+ pc->custom_size.right = _PWG_FROMPTS(ppd->custom_margins[2]);
+ pc->custom_size.top = _PWG_FROMPTS(ppd->custom_margins[3]);
+ }
+
+ /*
+ * Copy and convert InputSlot data...
+ */
+
+ if ((input_slot = ppdFindOption(ppd, "InputSlot")) == NULL)
+ input_slot = ppdFindOption(ppd, "HPPaperSource");
+
+ if (input_slot)
+ {
+ pc->source_option = _cupsStrAlloc(input_slot->keyword);
+
+ if ((pc->sources = calloc(input_slot->num_choices,
+ sizeof(_pwg_map_t))) == NULL)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
+ "_pwg_map_t's for InputSlot.", input_slot->num_choices));
+ goto create_error;
+ }
+
+ pc->num_sources = input_slot->num_choices;
+
+ for (i = input_slot->num_choices, choice = input_slot->choices,
+ map = pc->sources;
+ i > 0;
+ i --, choice ++, map ++)
+ {
+ if (!_cups_strncasecmp(choice->choice, "Auto", 4) ||
+ !_cups_strcasecmp(choice->choice, "Default"))
+ pwg_name = "auto";
+ else if (!_cups_strcasecmp(choice->choice, "Cassette"))
+ pwg_name = "main";
+ else if (!_cups_strcasecmp(choice->choice, "PhotoTray"))
+ pwg_name = "photo";
+ else if (!_cups_strcasecmp(choice->choice, "CDTray"))
+ pwg_name = "disc";
+ else if (!_cups_strncasecmp(choice->choice, "Multipurpose", 12) ||
+ !_cups_strcasecmp(choice->choice, "MP") ||
+ !_cups_strcasecmp(choice->choice, "MPTray"))
+ pwg_name = "alternate";
+ else if (!_cups_strcasecmp(choice->choice, "LargeCapacity"))
+ pwg_name = "large-capacity";
+ else if (!_cups_strncasecmp(choice->choice, "Lower", 5))
+ pwg_name = "bottom";
+ else if (!_cups_strncasecmp(choice->choice, "Middle", 6))
+ pwg_name = "middle";
+ else if (!_cups_strncasecmp(choice->choice, "Upper", 5))
+ pwg_name = "top";
+ else if (!_cups_strncasecmp(choice->choice, "Side", 4))
+ pwg_name = "side";
+ else if (!_cups_strcasecmp(choice->choice, "Roll") ||
+ !_cups_strcasecmp(choice->choice, "Roll1"))
+ pwg_name = "main-roll";
+ else if (!_cups_strcasecmp(choice->choice, "Roll2"))
+ pwg_name = "alternate-roll";
+ else
+ {
+ /*
+ * Convert PPD name to lowercase...
+ */
+
+ pwg_name = pwg_keyword;
+ pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
+ }
+
+ map->pwg = _cupsStrAlloc(pwg_name);
+ map->ppd = _cupsStrAlloc(choice->choice);
+ }
+ }
+
+ /*
+ * Copy and convert MediaType data...
+ */
+
+ if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
+ {
+ if ((pc->types = calloc(media_type->num_choices,
+ sizeof(_pwg_map_t))) == NULL)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
+ "_pwg_map_t's for MediaType.", media_type->num_choices));
+ goto create_error;
+ }
+
+ pc->num_types = media_type->num_choices;
+
+ for (i = media_type->num_choices, choice = media_type->choices,
+ map = pc->types;
+ i > 0;
+ i --, choice ++, map ++)
+ {
+ if (!_cups_strncasecmp(choice->choice, "Auto", 4) ||
+ !_cups_strcasecmp(choice->choice, "Any") ||
+ !_cups_strcasecmp(choice->choice, "Default"))
+ pwg_name = "auto";
+ else if (!_cups_strncasecmp(choice->choice, "Card", 4))
+ pwg_name = "cardstock";
+ else if (!_cups_strncasecmp(choice->choice, "Env", 3))
+ pwg_name = "envelope";
+ else if (!_cups_strncasecmp(choice->choice, "Gloss", 5))
+ pwg_name = "photographic-glossy";
+ else if (!_cups_strcasecmp(choice->choice, "HighGloss"))
+ pwg_name = "photographic-high-gloss";
+ else if (!_cups_strcasecmp(choice->choice, "Matte"))
+ pwg_name = "photographic-matte";
+ else if (!_cups_strncasecmp(choice->choice, "Plain", 5))
+ pwg_name = "stationery";
+ else if (!_cups_strncasecmp(choice->choice, "Coated", 6))
+ pwg_name = "stationery-coated";
+ else if (!_cups_strcasecmp(choice->choice, "Inkjet"))
+ pwg_name = "stationery-inkjet";
+ else if (!_cups_strcasecmp(choice->choice, "Letterhead"))
+ pwg_name = "stationery-letterhead";
+ else if (!_cups_strncasecmp(choice->choice, "Preprint", 8))
+ pwg_name = "stationery-preprinted";
+ else if (!_cups_strncasecmp(choice->choice, "Transparen", 10))
+ pwg_name = "transparency";
+ else
+ {
+ /*
+ * Convert PPD name to lowercase...
+ */
+
+ pwg_name = pwg_keyword;
+ pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
+ }
+
+ map->pwg = _cupsStrAlloc(pwg_name);
+ map->ppd = _cupsStrAlloc(choice->choice);
+ }
+ }
+
+ /*
+ * Copy and convert OutputBin data...
+ */
+
+ if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
+ {
+ if ((pc->bins = calloc(output_bin->num_choices,
+ sizeof(_pwg_map_t))) == NULL)
+ {
+ DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
+ "_pwg_map_t's for OutputBin.", output_bin->num_choices));
+ goto create_error;
+ }
+
+ pc->num_bins = output_bin->num_choices;
+
+ for (i = output_bin->num_choices, choice = output_bin->choices,
+ map = pc->bins;
+ i > 0;
+ i --, choice ++, map ++)
+ {
+ pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
+
+ map->pwg = _cupsStrAlloc(pwg_keyword);
+ map->ppd = _cupsStrAlloc(choice->choice);
+ }
+ }
+
+ if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL)
+ {
+ /*
+ * Copy and convert APPrinterPreset (output-mode + print-quality) data...
+ */
+
+ const char *quality, /* com.apple.print.preset.quality value */
+ *output_mode, /* com.apple.print.preset.output-mode value */
+ *color_model_val, /* ColorModel choice */
+ *graphicsType, /* com.apple.print.preset.graphicsType value */
+ *media_front_coating; /* com.apple.print.preset.media-front-coating value */
+
+ do
+ {
+ num_options = _ppdParseOptions(ppd_attr->value, 0, &options,
+ _PPD_PARSE_ALL);
+
+ if ((quality = cupsGetOption("com.apple.print.preset.quality",
+ num_options, options)) != NULL)
+ {
+ /*
+ * Get the print-quality for this preset...
+ */
+
+ if (!strcmp(quality, "low"))
+ pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT;
+ else if (!strcmp(quality, "high"))
+ pwg_print_quality = _PWG_PRINT_QUALITY_HIGH;
+ else
+ pwg_print_quality = _PWG_PRINT_QUALITY_NORMAL;
+
+ /*
+ * Ignore graphicsType "Photo" presets that are not high quality.
+ */
+
+ graphicsType = cupsGetOption("com.apple.print.preset.graphicsType",
+ num_options, options);
+
+ if (pwg_print_quality != _PWG_PRINT_QUALITY_HIGH && graphicsType &&
+ !strcmp(graphicsType, "Photo"))
+ continue;
+
+ /*
+ * Ignore presets for normal and draft quality where the coating
+ * isn't "none" or "autodetect".
+ */
+
+ media_front_coating = cupsGetOption(
+ "com.apple.print.preset.media-front-coating",
+ num_options, options);
+
+ if (pwg_print_quality != _PWG_PRINT_QUALITY_HIGH &&
+ media_front_coating &&
+ strcmp(media_front_coating, "none") &&
+ strcmp(media_front_coating, "autodetect"))
+ continue;
+
+ /*
+ * Get the output mode for this preset...
+ */
+
+ output_mode = cupsGetOption("com.apple.print.preset.output-mode",
+ num_options, options);
+ color_model_val = cupsGetOption("ColorModel", num_options, options);
+
+ if (output_mode)
+ {
+ if (!strcmp(output_mode, "monochrome"))
+ pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_MONOCHROME;
+ else
+ pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
+ }
+ else if (color_model_val)
+ {
+ if (!_cups_strcasecmp(color_model_val, "Gray"))
+ pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_MONOCHROME;
+ else
+ pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
+ }
+ else
+ pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
+
+ /*
+ * Save the options for this combination as needed...
+ */
+
+ if (!pc->num_presets[pwg_print_color_mode][pwg_print_quality])
+ pc->num_presets[pwg_print_color_mode][pwg_print_quality] =
+ _ppdParseOptions(ppd_attr->value, 0,
+ pc->presets[pwg_print_color_mode] +
+ pwg_print_quality, _PPD_PARSE_OPTIONS);
+ }
+
+ cupsFreeOptions(num_options, options);
+ }
+ while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset", NULL)) != NULL);
+ }
+
+ if (!pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_DRAFT] &&
+ !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_NORMAL] &&
+ !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_HIGH])
+ {
+ /*
+ * Try adding some common color options to create grayscale presets. These
+ * are listed in order of popularity...
+ */
+
+ const char *color_option = NULL, /* Color control option */
+ *gray_choice = NULL; /* Choice to select grayscale */
+
+ if ((color_model = ppdFindOption(ppd, "ColorModel")) != NULL &&
+ ppdFindChoice(color_model, "Gray"))
+ {
+ color_option = "ColorModel";
+ gray_choice = "Gray";
+ }
+ else if ((color_model = ppdFindOption(ppd, "HPColorMode")) != NULL &&
+ ppdFindChoice(color_model, "grayscale"))
+ {
+ color_option = "HPColorMode";
+ gray_choice = "grayscale";
+ }
+ else if ((color_model = ppdFindOption(ppd, "BRMonoColor")) != NULL &&
+ ppdFindChoice(color_model, "Mono"))
+ {
+ color_option = "BRMonoColor";
+ gray_choice = "Mono";
+ }
+ else if ((color_model = ppdFindOption(ppd, "CNIJSGrayScale")) != NULL &&
+ ppdFindChoice(color_model, "1"))
+ {
+ color_option = "CNIJSGrayScale";
+ gray_choice = "1";
+ }
+ else if ((color_model = ppdFindOption(ppd, "HPColorAsGray")) != NULL &&
+ ppdFindChoice(color_model, "True"))
+ {
+ color_option = "HPColorAsGray";
+ gray_choice = "True";
+ }
+
+ if (color_option && gray_choice)
+ {
+ /*
+ * Copy and convert ColorModel (output-mode) data...
+ */
+
+ cups_option_t *coption, /* Color option */
+ *moption; /* Monochrome option */
+
+ for (pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT;
+ pwg_print_quality < _PWG_PRINT_QUALITY_MAX;
+ pwg_print_quality ++)
+ {
+ if (pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][pwg_print_quality])
+ {
+ /*
+ * Copy the color options...
+ */
+
+ num_options = pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR]
+ [pwg_print_quality];
+ options = calloc(sizeof(cups_option_t), num_options);
+
+ if (options)
+ {
+ for (i = num_options, moption = options,
+ coption = pc->presets[_PWG_PRINT_COLOR_MODE_COLOR]
+ [pwg_print_quality];
+ i > 0;
+ i --, moption ++, coption ++)
+ {
+ moption->name = _cupsStrRetain(coption->name);
+ moption->value = _cupsStrRetain(coption->value);
+ }
+
+ pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
+ num_options;
+ pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
+ options;
+ }
+ }
+ else if (pwg_print_quality != _PWG_PRINT_QUALITY_NORMAL)
+ continue;
+
+ /*
+ * Add the grayscale option to the preset...
+ */
+
+ pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
+ cupsAddOption(color_option, gray_choice,
+ pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME]
+ [pwg_print_quality],
+ pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] +
+ pwg_print_quality);
+ }
+ }
+ }
+
+ /*
+ * Copy and convert Duplex (sides) data...
+ */
+
+ if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
+ if ((duplex = ppdFindOption(ppd, "JCLDuplex")) == NULL)
+ if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
+ if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
+ duplex = ppdFindOption(ppd, "KD03Duplex");
+
+ if (duplex)
+ {
+ pc->sides_option = _cupsStrAlloc(duplex->keyword);
+
+ for (i = duplex->num_choices, choice = duplex->choices;
+ i > 0;
+ i --, choice ++)
+ {
+ if ((!_cups_strcasecmp(choice->choice, "None") ||
+ !_cups_strcasecmp(choice->choice, "False")) && !pc->sides_1sided)
+ pc->sides_1sided = _cupsStrAlloc(choice->choice);
+ else if ((!_cups_strcasecmp(choice->choice, "DuplexNoTumble") ||
+ !_cups_strcasecmp(choice->choice, "LongEdge") ||
+ !_cups_strcasecmp(choice->choice, "Top")) && !pc->sides_2sided_long)
+ pc->sides_2sided_long = _cupsStrAlloc(choice->choice);
+ else if ((!_cups_strcasecmp(choice->choice, "DuplexTumble") ||
+ !_cups_strcasecmp(choice->choice, "ShortEdge") ||
+ !_cups_strcasecmp(choice->choice, "Bottom")) &&
+ !pc->sides_2sided_short)
+ pc->sides_2sided_short = _cupsStrAlloc(choice->choice);
+ }
+ }
+
+ /*
+ * Copy filters and pre-filters...
+ */
+
+ pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0,
+ (cups_acopy_func_t)_cupsStrAlloc,
+ (cups_afree_func_t)_cupsStrFree);
+
+ cupsArrayAdd(pc->filters,
+ "application/vnd.cups-raw application/octet-stream 0 -");
+
+ if ((ppd_attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) != NULL)
+ {
+ do
+ {
+ cupsArrayAdd(pc->filters, ppd_attr->value);
+ }
+ while ((ppd_attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL)) != NULL);
+ }
+ else if (ppd->num_filters > 0)
+ {
+ for (i = 0; i < ppd->num_filters; i ++)
+ cupsArrayAdd(pc->filters, ppd->filters[i]);
+ }
+ else
+ cupsArrayAdd(pc->filters, "application/vnd.cups-postscript 0 -");
+
+ /*
+ * See if we have a command filter...
+ */
+
+ for (filter = (const char *)cupsArrayFirst(pc->filters);
+ filter;
+ filter = (const char *)cupsArrayNext(pc->filters))
+ if (!_cups_strncasecmp(filter, "application/vnd.cups-command", 28) &&
+ _cups_isspace(filter[28]))
+ break;
+
+ if (!filter &&
+ ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) == NULL ||
+ _cups_strcasecmp(ppd_attr->value, "none")))
+ {
+ /*
+ * No command filter and no cupsCommands keyword telling us not to use one.
+ * See if this is a PostScript printer, and if so add a PostScript command
+ * filter...
+ */
+
+ for (filter = (const char *)cupsArrayFirst(pc->filters);
+ filter;
+ filter = (const char *)cupsArrayNext(pc->filters))
+ if (!_cups_strncasecmp(filter, "application/vnd.cups-postscript", 31) &&
+ _cups_isspace(filter[31]))
+ break;
+
+ if (filter)
+ cupsArrayAdd(pc->filters,
+ "application/vnd.cups-command application/postscript 0 -");
+ }
+
+ if ((ppd_attr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL)
+ {
+ pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0,
+ (cups_acopy_func_t)_cupsStrAlloc,
+ (cups_afree_func_t)_cupsStrFree);
+
+ do
+ {
+ cupsArrayAdd(pc->prefilters, ppd_attr->value);
+ }
+ while ((ppd_attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL)) != NULL);
+ }
+
+ if ((ppd_attr = ppdFindAttr(ppd, "cupsSingleFile", NULL)) != NULL)
+ pc->single_file = !_cups_strcasecmp(ppd_attr->value, "true");
+
+ /*
+ * Copy the product string, if any...
+ */
+
+ if (ppd->product)
+ pc->product = _cupsStrAlloc(ppd->product);
+
+ /*
+ * Return the cache data...
+ */
+
+ return (pc);
+
+ /*
+ * If we get here we need to destroy the PWG mapping data and return NULL...
+ */
+
+ create_error:
+
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Out of memory."), 1);
+ _ppdCacheDestroy(pc);
+
+ return (NULL);
+}
+
+
+/*
+ * '_ppdCacheDestroy()' - Free all memory used for PWG mapping data.
+ */
+
+void
+_ppdCacheDestroy(_ppd_cache_t *pc) /* I - PPD cache and mapping data */
+{
+ int i; /* Looping var */
+ _pwg_map_t *map; /* Current map */
+ _pwg_size_t *size; /* Current size */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!pc)
+ return;
+
+ /*
+ * Free memory as needed...
+ */
+
+ if (pc->bins)
+ {
+ for (i = pc->num_bins, map = pc->bins; i > 0; i --, map ++)
+ {
+ _cupsStrFree(map->pwg);
+ _cupsStrFree(map->ppd);
+ }
+
+ free(pc->bins);
+ }
+
+ if (pc->sizes)
+ {
+ for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
+ {
+ _cupsStrFree(size->map.pwg);
+ _cupsStrFree(size->map.ppd);
+ }
+
+ free(pc->sizes);
+ }
+
+ if (pc->source_option)
+ _cupsStrFree(pc->source_option);
+
+ if (pc->sources)
+ {
+ for (i = pc->num_sources, map = pc->sources; i > 0; i --, map ++)
+ {
+ _cupsStrFree(map->pwg);
+ _cupsStrFree(map->ppd);
+ }
+
+ free(pc->sources);
+ }
+
+ if (pc->types)
+ {
+ for (i = pc->num_types, map = pc->types; i > 0; i --, map ++)
+ {
+ _cupsStrFree(map->pwg);
+ _cupsStrFree(map->ppd);
+ }
+
+ free(pc->types);
+ }
+
+ if (pc->custom_max_keyword)
+ _cupsStrFree(pc->custom_max_keyword);
+
+ if (pc->custom_min_keyword)
+ _cupsStrFree(pc->custom_min_keyword);
+
+ _cupsStrFree(pc->product);
+ cupsArrayDelete(pc->filters);
+ cupsArrayDelete(pc->prefilters);
+
+ free(pc);
+}
+
+
+/*
+ * '_ppdCacheGetBin()' - Get the PWG output-bin keyword associated with a PPD
+ * OutputBin.
+ */
+
+const char * /* O - output-bin or NULL */
+_ppdCacheGetBin(
+ _ppd_cache_t *pc, /* I - PPD cache and mapping data */
+ const char *output_bin) /* I - PPD OutputBin string */
+{
+ int i; /* Looping var */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!pc || !output_bin)
+ return (NULL);
+
+ /*
+ * Look up the OutputBin string...
+ */
+
+
+ for (i = 0; i < pc->num_bins; i ++)
+ if (!_cups_strcasecmp(output_bin, pc->bins[i].ppd))
+ return (pc->bins[i].pwg);
+
+ return (NULL);
+}
+
+
+/*
+ * '_ppdCacheGetInputSlot()' - Get the PPD InputSlot associated with the job
+ * attributes or a keyword string.
+ */
+
+const char * /* O - PPD InputSlot or NULL */
+_ppdCacheGetInputSlot(
+ _ppd_cache_t *pc, /* I - PPD cache and mapping data */
+ ipp_t *job, /* I - Job attributes or NULL */
+ const char *keyword) /* I - Keyword string or NULL */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!pc || pc->num_sources == 0 || (!job && !keyword))
+ return (NULL);
+
+ if (job && !keyword)
+ {
+ /*
+ * Lookup the media-col attribute and any media-source found there...
+ */
+
+ ipp_attribute_t *media_col, /* media-col attribute */
+ *media_source; /* media-source attribute */
+ _pwg_size_t size; /* Dimensional size */
+ int margins_set; /* Were the margins set? */
+
+ media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION);
+ if (media_col &&
+ (media_source = ippFindAttribute(media_col->values[0].collection,
+ "media-source",
+ IPP_TAG_KEYWORD)) != NULL)
+ {
+ /*
+ * Use the media-source value from media-col...
+ */
+
+ keyword = media_source->values[0].string.text;
+ }
+ else if (_pwgInitSize(&size, job, &margins_set))
+ {
+ /*
+ * For media <= 5x7, look for a photo tray...
+ */
+
+ if (size.width <= (5 * 2540) && size.length <= (7 * 2540))
+ keyword = "photo";
+ }
+ }
+
+ if (keyword)
+ {
+ int i; /* Looping var */
+
+ for (i = 0; i < pc->num_sources; i ++)
+ if (!_cups_strcasecmp(keyword, pc->sources[i].pwg))
+ return (pc->sources[i].ppd);
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * '_ppdCacheGetMediaType()' - Get the PPD MediaType associated with the job
+ * attributes or a keyword string.
+ */
+
+const char * /* O - PPD MediaType or NULL */
+_ppdCacheGetMediaType(
+ _ppd_cache_t *pc, /* I - PPD cache and mapping data */
+ ipp_t *job, /* I - Job attributes or NULL */
+ const char *keyword) /* I - Keyword string or NULL */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!pc || pc->num_types == 0 || (!job && !keyword))
+ return (NULL);
+
+ if (job && !keyword)
+ {
+ /*
+ * Lookup the media-col attribute and any media-source found there...
+ */
+
+ ipp_attribute_t *media_col, /* media-col attribute */
+ *media_type; /* media-type attribute */
+
+ media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION);
+ if (media_col)
+ {
+ if ((media_type = ippFindAttribute(media_col->values[0].collection,
+ "media-type",
+ IPP_TAG_KEYWORD)) == NULL)
+ media_type = ippFindAttribute(media_col->values[0].collection,
+ "media-type", IPP_TAG_NAME);
+
+ if (media_type)
+ keyword = media_type->values[0].string.text;
+ }
+ }
+
+ if (keyword)
+ {
+ int i; /* Looping var */
+
+ for (i = 0; i < pc->num_types; i ++)
+ if (!_cups_strcasecmp(keyword, pc->types[i].pwg))
+ return (pc->types[i].ppd);
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * '_ppdCacheGetOutputBin()' - Get the PPD OutputBin associated with the keyword
+ * string.
+ */
+
+const char * /* O - PPD OutputBin or NULL */
+_ppdCacheGetOutputBin(
+ _ppd_cache_t *pc, /* I - PPD cache and mapping data */
+ const char *output_bin) /* I - Keyword string */
+{
+ int i; /* Looping var */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!pc || !output_bin)
+ return (NULL);
+
+ /*
+ * Look up the OutputBin string...
+ */
+
+
+ for (i = 0; i < pc->num_bins; i ++)
+ if (!_cups_strcasecmp(output_bin, pc->bins[i].pwg))
+ return (pc->bins[i].ppd);
+
+ return (NULL);
+}
+
+
+/*
+ * '_ppdCacheGetPageSize()' - Get the PPD PageSize associated with the job
+ * attributes or a keyword string.
+ */
+
+const char * /* O - PPD PageSize or NULL */
+_ppdCacheGetPageSize(
+ _ppd_cache_t *pc, /* I - PPD cache and mapping data */
+ ipp_t *job, /* I - Job attributes or NULL */
+ const char *keyword, /* I - Keyword string or NULL */
+ int *exact) /* O - 1 if exact match, 0 otherwise */
+{
+ int i; /* Looping var */
+ _pwg_size_t *size, /* Current size */
+ *closest, /* Closest size */
+ jobsize; /* Size data from job */
+ int margins_set, /* Were the margins set? */
+ dwidth, /* Difference in width */
+ dlength, /* Difference in length */
+ dleft, /* Difference in left margins */
+ dright, /* Difference in right margins */
+ dbottom, /* Difference in bottom margins */
+ dtop, /* Difference in top margins */
+ dmin, /* Minimum difference */
+ dclosest; /* Closest difference */
+ const char *ppd_name; /* PPD media name */
+
+
+ DEBUG_printf(("_ppdCacheGetPageSize(pc=%p, job=%p, keyword=\"%s\", exact=%p)",
+ pc, job, keyword, exact));
+
+ /*
+ * Range check input...
+ */
+
+ if (!pc || (!job && !keyword))
+ return (NULL);
+
+ if (exact)
+ *exact = 0;
+
+ ppd_name = keyword;
+
+ if (job)
+ {
+ /*
+ * Try getting the PPD media name from the job attributes...
+ */
+
+ ipp_attribute_t *attr; /* Job attribute */
+
+ if ((attr = ippFindAttribute(job, "PageSize", IPP_TAG_ZERO)) == NULL)
+ if ((attr = ippFindAttribute(job, "PageRegion", IPP_TAG_ZERO)) == NULL)
+ attr = ippFindAttribute(job, "media", IPP_TAG_ZERO);
+
+#ifdef DEBUG
+ if (attr)
+ DEBUG_printf(("1_ppdCacheGetPageSize: Found attribute %s (%s)",
+ attr->name, ippTagString(attr->value_tag)));
+ else
+ DEBUG_puts("1_ppdCacheGetPageSize: Did not find media attribute.");
+#endif /* DEBUG */
+
+ if (attr && (attr->value_tag == IPP_TAG_NAME ||
+ attr->value_tag == IPP_TAG_KEYWORD))
+ ppd_name = attr->values[0].string.text;
+ }
+
+ DEBUG_printf(("1_ppdCacheGetPageSize: ppd_name=\"%s\"", ppd_name));
+
+ if (ppd_name)
+ {
+ /*
+ * Try looking up the named PPD size first...
+ */
+
+ for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
+ {
+ DEBUG_printf(("2_ppdCacheGetPageSize: size[%d]=[\"%s\" \"%s\"]",
+ (int)(size - pc->sizes), size->map.pwg, size->map.ppd));
+
+ if (!_cups_strcasecmp(ppd_name, size->map.ppd) ||
+ !_cups_strcasecmp(ppd_name, size->map.pwg))
+ {
+ if (exact)
+ *exact = 1;
+
+ DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\"", ppd_name));
+
+ return (size->map.ppd);
+ }
+ }
+ }
+
+ if (job && !keyword)
+ {
+ /*
+ * Get the size using media-col or media, with the preference being
+ * media-col.
+ */
+
+ if (!_pwgInitSize(&jobsize, job, &margins_set))
+ return (NULL);
+ }
+ else
+ {
+ /*
+ * Get the size using a media keyword...
+ */
+
+ _pwg_media_t *media; /* Media definition */
+
+
+ if ((media = _pwgMediaForPWG(keyword)) == NULL)
+ if ((media = _pwgMediaForLegacy(keyword)) == NULL)
+ if ((media = _pwgMediaForPPD(keyword)) == NULL)
+ return (NULL);
+
+ jobsize.width = media->width;
+ jobsize.length = media->length;
+ margins_set = 0;
+ }
+
+ /*
+ * Now that we have the dimensions and possibly the margins, look at the
+ * available sizes and find the match...
+ */
+
+ closest = NULL;
+ dclosest = 999999999;
+
+ if (!ppd_name || _cups_strncasecmp(ppd_name, "Custom.", 7) ||
+ _cups_strncasecmp(ppd_name, "custom_", 7))
+ {
+ for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
+ {
+ /*
+ * Adobe uses a size matching algorithm with an epsilon of 5 points, which
+ * is just about 176/2540ths...
+ */
+
+ dwidth = size->width - jobsize.width;
+ dlength = size->length - jobsize.length;
+
+ if (dwidth <= -176 || dwidth >= 176 || dlength <= -176 || dlength >= 176)
+ continue;
+
+ if (margins_set)
+ {
+ /*
+ * Use a tighter epsilon of 1 point (35/2540ths) for margins...
+ */
+
+ dleft = size->left - jobsize.left;
+ dright = size->right - jobsize.right;
+ dtop = size->top - jobsize.top;
+ dbottom = size->bottom - jobsize.bottom;
+
+ if (dleft <= -35 || dleft >= 35 || dright <= -35 || dright >= 35 ||
+ dtop <= -35 || dtop >= 35 || dbottom <= -35 || dbottom >= 35)
+ {
+ dleft = dleft < 0 ? -dleft : dleft;
+ dright = dright < 0 ? -dright : dright;
+ dbottom = dbottom < 0 ? -dbottom : dbottom;
+ dtop = dtop < 0 ? -dtop : dtop;
+ dmin = dleft + dright + dbottom + dtop;
+
+ if (dmin < dclosest)
+ {
+ dclosest = dmin;
+ closest = size;
+ }
+
+ continue;
+ }
+ }
+
+ if (exact)
+ *exact = 1;
+
+ DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\"", size->map.ppd));
+
+ return (size->map.ppd);
+ }
+ }
+
+ if (closest)
+ {
+ DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\" (closest)",
+ closest->map.ppd));
+
+ return (closest->map.ppd);
+ }
+
+ /*
+ * If we get here we need to check for custom page size support...
+ */
+
+ if (jobsize.width >= pc->custom_min_width &&
+ jobsize.width <= pc->custom_max_width &&
+ jobsize.length >= pc->custom_min_length &&
+ jobsize.length <= pc->custom_max_length)
+ {
+ /*
+ * In range, format as Custom.WWWWxLLLL (points).
+ */
+
+ snprintf(pc->custom_ppd_size, sizeof(pc->custom_ppd_size), "Custom.%dx%d",
+ (int)_PWG_TOPTS(jobsize.width), (int)_PWG_TOPTS(jobsize.length));
+
+ if (margins_set && exact)
+ {
+ dleft = pc->custom_size.left - jobsize.left;
+ dright = pc->custom_size.right - jobsize.right;
+ dtop = pc->custom_size.top - jobsize.top;
+ dbottom = pc->custom_size.bottom - jobsize.bottom;
+
+ if (dleft > -35 && dleft < 35 && dright > -35 && dright < 35 &&
+ dtop > -35 && dtop < 35 && dbottom > -35 && dbottom < 35)
+ *exact = 1;
+ }
+ else if (exact)
+ *exact = 1;
+
+ DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\" (custom)",
+ pc->custom_ppd_size));
+
+ return (pc->custom_ppd_size);
+ }
+
+ /*
+ * No custom page size support or the size is out of range - return NULL.
+ */
+
+ DEBUG_puts("1_ppdCacheGetPageSize: Returning NULL");
+
+ return (NULL);
+}
+
+
+/*
+ * '_ppdCacheGetSize()' - Get the PWG size associated with a PPD PageSize.
+ */
+
+_pwg_size_t * /* O - PWG size or NULL */
+_ppdCacheGetSize(
+ _ppd_cache_t *pc, /* I - PPD cache and mapping data */
+ const char *page_size) /* I - PPD PageSize */
+{
+ int i;
+ _pwg_size_t *size; /* Current size */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!pc || !page_size)
+ return (NULL);
+
+ if (!_cups_strncasecmp(page_size, "Custom.", 7))
+ {
+ /*
+ * Custom size; size name can be one of the following:
+ *
+ * Custom.WIDTHxLENGTHin - Size in inches
+ * Custom.WIDTHxLENGTHft - Size in feet
+ * Custom.WIDTHxLENGTHcm - Size in centimeters
+ * Custom.WIDTHxLENGTHmm - Size in millimeters
+ * Custom.WIDTHxLENGTHm - Size in meters
+ * Custom.WIDTHxLENGTH[pt] - Size in points
+ */
+
+ double w, l; /* Width and length of page */
+ char *ptr; /* Pointer into PageSize */
+ struct lconv *loc; /* Locale data */
+
+ loc = localeconv();
+ w = (float)_cupsStrScand(page_size + 7, &ptr, loc);
+ if (!ptr || *ptr != 'x')
+ return (NULL);
+
+ l = (float)_cupsStrScand(ptr + 1, &ptr, loc);
+ if (!ptr)
+ return (NULL);
+
+ if (!_cups_strcasecmp(ptr, "in"))
+ {
+ w *= 2540.0;
+ l *= 2540.0;
+ }
+ else if (!_cups_strcasecmp(ptr, "ft"))
+ {
+ w *= 12.0 * 2540.0;
+ l *= 12.0 * 2540.0;
+ }
+ else if (!_cups_strcasecmp(ptr, "mm"))
+ {
+ w *= 100.0;
+ l *= 100.0;
+ }
+ else if (!_cups_strcasecmp(ptr, "cm"))
+ {
+ w *= 1000.0;
+ l *= 1000.0;
+ }
+ else if (!_cups_strcasecmp(ptr, "m"))
+ {
+ w *= 100000.0;
+ l *= 100000.0;
+ }
+ else
+ {
+ w *= 2540.0 / 72.0;
+ l *= 2540.0 / 72.0;
+ }
+
+ pc->custom_size.width = (int)w;
+ pc->custom_size.length = (int)l;
+
+ return (&(pc->custom_size));
+ }
+
+ /*
+ * Not a custom size - look it up...
+ */
+
+ for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
+ if (!_cups_strcasecmp(page_size, size->map.ppd))
+ return (size);
+
+ return (NULL);
+}
+
+
+/*
+ * '_ppdCacheGetSource()' - Get the PWG media-source associated with a PPD
+ * InputSlot.
+ */
+
+const char * /* O - PWG media-source keyword */
+_ppdCacheGetSource(
+ _ppd_cache_t *pc, /* I - PPD cache and mapping data */
+ const char *input_slot) /* I - PPD InputSlot */
+{
+ int i; /* Looping var */
+ _pwg_map_t *source; /* Current source */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!pc || !input_slot)
+ return (NULL);
+
+ for (i = pc->num_sources, source = pc->sources; i > 0; i --, source ++)
+ if (!_cups_strcasecmp(input_slot, source->ppd))
+ return (source->pwg);
+
+ return (NULL);
+}
+
+
+/*
+ * '_ppdCacheGetType()' - Get the PWG media-type associated with a PPD
+ * MediaType.
+ */
+
+const char * /* O - PWG media-type keyword */
+_ppdCacheGetType(
+ _ppd_cache_t *pc, /* I - PPD cache and mapping data */
+ const char *media_type) /* I - PPD MediaType */
+{
+ int i; /* Looping var */
+ _pwg_map_t *type; /* Current type */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!pc || !media_type)
+ return (NULL);
+
+ for (i = pc->num_types, type = pc->types; i > 0; i --, type ++)
+ if (!_cups_strcasecmp(media_type, type->ppd))
+ return (type->pwg);
+
+ return (NULL);
+}
+
+
+/*
+ * '_ppdCacheWriteFile()' - Write PWG mapping data to a file.
+ */
+
+int /* O - 1 on success, 0 on failure */
+_ppdCacheWriteFile(
+ _ppd_cache_t *pc, /* I - PPD cache and mapping data */
+ const char *filename, /* I - File to write */
+ ipp_t *attrs) /* I - Attributes to write, if any */
+{
+ int i, j, k; /* Looping vars */
+ cups_file_t *fp; /* Output file */
+ _pwg_size_t *size; /* Current size */
+ _pwg_map_t *map; /* Current map */
+ cups_option_t *option; /* Current option */
+ const char *value; /* Filter/pre-filter value */
+ char newfile[1024]; /* New filename */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!pc || !filename)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
+ return (0);
+ }
+
+ /*
+ * Open the file and write with compression...
+ */
+
+ snprintf(newfile, sizeof(newfile), "%s.N", filename);
+ if ((fp = cupsFileOpen(newfile, "w9")) == NULL)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno), 0);
+ return (0);
+ }
+
+ /*
+ * Standard header...
+ */
+
+ cupsFilePrintf(fp, "#CUPS-PPD-CACHE-%d\n", _PPD_CACHE_VERSION);
+
+ /*
+ * Output bins...
+ */
+
+ if (pc->num_bins > 0)
+ {
+ cupsFilePrintf(fp, "NumBins %d\n", pc->num_bins);
+ for (i = pc->num_bins, map = pc->bins; i > 0; i --, map ++)
+ cupsFilePrintf(fp, "Bin %s %s\n", map->pwg, map->ppd);
+ }
+
+ /*
+ * Media sizes...
+ */
+
+ cupsFilePrintf(fp, "NumSizes %d\n", pc->num_sizes);
+ for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
+ cupsFilePrintf(fp, "Size %s %s %d %d %d %d %d %d\n", size->map.pwg,
+ size->map.ppd, size->width, size->length, size->left,
+ size->bottom, size->right, size->top);
+ if (pc->custom_max_width > 0)
+ cupsFilePrintf(fp, "CustomSize %d %d %d %d %d %d %d %d\n",
+ pc->custom_max_width, pc->custom_max_length,
+ pc->custom_min_width, pc->custom_min_length,
+ pc->custom_size.left, pc->custom_size.bottom,
+ pc->custom_size.right, pc->custom_size.top);
+
+ /*
+ * Media sources...
+ */
+
+ if (pc->source_option)
+ cupsFilePrintf(fp, "SourceOption %s\n", pc->source_option);
+
+ if (pc->num_sources > 0)
+ {
+ cupsFilePrintf(fp, "NumSources %d\n", pc->num_sources);
+ for (i = pc->num_sources, map = pc->sources; i > 0; i --, map ++)
+ cupsFilePrintf(fp, "Source %s %s\n", map->pwg, map->ppd);
+ }
+
+ /*
+ * Media types...
+ */
+
+ if (pc->num_types > 0)
+ {
+ cupsFilePrintf(fp, "NumTypes %d\n", pc->num_types);
+ for (i = pc->num_types, map = pc->types; i > 0; i --, map ++)
+ cupsFilePrintf(fp, "Type %s %s\n", map->pwg, map->ppd);
+ }
+
+ /*
+ * Presets...
+ */
+
+ for (i = _PWG_PRINT_COLOR_MODE_MONOCHROME; i < _PWG_PRINT_COLOR_MODE_MAX; i ++)
+ for (j = _PWG_PRINT_QUALITY_DRAFT; j < _PWG_PRINT_QUALITY_MAX; j ++)
+ if (pc->num_presets[i][j])
+ {
+ cupsFilePrintf(fp, "Preset %d %d", i, j);
+ for (k = pc->num_presets[i][j], option = pc->presets[i][j];
+ k > 0;
+ k --, option ++)
+ cupsFilePrintf(fp, " %s=%s", option->name, option->value);
+ cupsFilePutChar(fp, '\n');
+ }
+
+ /*
+ * Duplex/sides...
+ */
+
+ if (pc->sides_option)
+ cupsFilePrintf(fp, "SidesOption %s\n", pc->sides_option);
+
+ if (pc->sides_1sided)
+ cupsFilePrintf(fp, "Sides1Sided %s\n", pc->sides_1sided);
+
+ if (pc->sides_2sided_long)
+ cupsFilePrintf(fp, "Sides2SidedLong %s\n", pc->sides_2sided_long);
+
+ if (pc->sides_2sided_short)
+ cupsFilePrintf(fp, "Sides2SidedShort %s\n", pc->sides_2sided_short);
+
+ /*
+ * Product, cupsFilter, cupsFilter2, and cupsPreFilter...
+ */
+
+ if (pc->product)
+ cupsFilePutConf(fp, "Product", pc->product);
+
+ for (value = (const char *)cupsArrayFirst(pc->filters);
+ value;
+ value = (const char *)cupsArrayNext(pc->filters))
+ cupsFilePutConf(fp, "Filter", value);
+
+ for (value = (const char *)cupsArrayFirst(pc->prefilters);
+ value;
+ value = (const char *)cupsArrayNext(pc->prefilters))
+ cupsFilePutConf(fp, "PreFilter", value);
+
+ cupsFilePrintf(fp, "SingleFile %s\n", pc->single_file ? "true" : "false");
+
+ /*
+ * IPP attributes, if any...
+ */
+
+ if (attrs)
+ {
+ cupsFilePrintf(fp, "IPP " CUPS_LLFMT "\n", CUPS_LLCAST ippLength(attrs));
+
+ attrs->state = IPP_IDLE;
+ ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL, attrs);
+ }
+
+ /*
+ * Close and return...
+ */
+
+ if (cupsFileClose(fp))
+ {
+ unlink(newfile);
+ return (0);
+ }
+
+ unlink(filename);
+ return (!rename(newfile, filename));
+}
+
+
+/*
+ * '_pwgInputSlotForSource()' - Get the InputSlot name for the given PWG
+ * media-source.
+ */
+
+const char * /* O - InputSlot name */
+_pwgInputSlotForSource(
+ const char *media_source, /* I - PWG media-source */
+ char *name, /* I - Name buffer */
+ size_t namesize) /* I - Size of name buffer */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!media_source || !name || namesize < PPD_MAX_NAME)
+ return (NULL);
+
+ if (_cups_strcasecmp(media_source, "main"))
+ strlcpy(name, "Cassette", namesize);
+ else if (_cups_strcasecmp(media_source, "alternate"))
+ strlcpy(name, "Multipurpose", namesize);
+ else if (_cups_strcasecmp(media_source, "large-capacity"))
+ strlcpy(name, "LargeCapacity", namesize);
+ else if (_cups_strcasecmp(media_source, "bottom"))
+ strlcpy(name, "Lower", namesize);
+ else if (_cups_strcasecmp(media_source, "middle"))
+ strlcpy(name, "Middle", namesize);
+ else if (_cups_strcasecmp(media_source, "top"))
+ strlcpy(name, "Upper", namesize);
+ else if (_cups_strcasecmp(media_source, "rear"))
+ strlcpy(name, "Rear", namesize);
+ else if (_cups_strcasecmp(media_source, "side"))
+ strlcpy(name, "Side", namesize);
+ else if (_cups_strcasecmp(media_source, "envelope"))
+ strlcpy(name, "Envelope", namesize);
+ else if (_cups_strcasecmp(media_source, "main-roll"))
+ strlcpy(name, "Roll", namesize);
+ else if (_cups_strcasecmp(media_source, "alternate-roll"))
+ strlcpy(name, "Roll2", namesize);
+ else
+ pwg_ppdize_name(media_source, name, namesize);
+
+ return (name);
+}
+
+
+/*
+ * '_pwgMediaTypeForType()' - Get the MediaType name for the given PWG
+ * media-type.
+ */
+
+const char * /* O - MediaType name */
+_pwgMediaTypeForType(
+ const char *media_type, /* I - PWG media-type */
+ char *name, /* I - Name buffer */
+ size_t namesize) /* I - Size of name buffer */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!media_type || !name || namesize < PPD_MAX_NAME)
+ return (NULL);
+
+ if (_cups_strcasecmp(media_type, "auto"))
+ strlcpy(name, "Auto", namesize);
+ else if (_cups_strcasecmp(media_type, "cardstock"))
+ strlcpy(name, "Cardstock", namesize);
+ else if (_cups_strcasecmp(media_type, "envelope"))
+ strlcpy(name, "Envelope", namesize);
+ else if (_cups_strcasecmp(media_type, "photographic-glossy"))
+ strlcpy(name, "Glossy", namesize);
+ else if (_cups_strcasecmp(media_type, "photographic-high-gloss"))
+ strlcpy(name, "HighGloss", namesize);
+ else if (_cups_strcasecmp(media_type, "photographic-matte"))
+ strlcpy(name, "Matte", namesize);
+ else if (_cups_strcasecmp(media_type, "stationery"))
+ strlcpy(name, "Plain", namesize);
+ else if (_cups_strcasecmp(media_type, "stationery-coated"))
+ strlcpy(name, "Coated", namesize);
+ else if (_cups_strcasecmp(media_type, "stationery-inkjet"))
+ strlcpy(name, "Inkjet", namesize);
+ else if (_cups_strcasecmp(media_type, "stationery-letterhead"))
+ strlcpy(name, "Letterhead", namesize);
+ else if (_cups_strcasecmp(media_type, "stationery-preprinted"))
+ strlcpy(name, "Preprinted", namesize);
+ else if (_cups_strcasecmp(media_type, "transparency"))
+ strlcpy(name, "Transparency", namesize);
+ else
+ pwg_ppdize_name(media_type, name, namesize);
+
+ return (name);
+}
+
+
+/*
+ * '_pwgPageSizeForMedia()' - Get the PageSize name for the given media.
+ */
+
+const char * /* O - PageSize name */
+_pwgPageSizeForMedia(
+ _pwg_media_t *media, /* I - Media */
+ char *name, /* I - PageSize name buffer */
+ size_t namesize) /* I - Size of name buffer */
+{
+ const char *sizeptr, /* Pointer to size in PWG name */
+ *dimptr; /* Pointer to dimensions in PWG name */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!media || !name || namesize < PPD_MAX_NAME)
+ return (NULL);
+
+ /*
+ * Copy or generate a PageSize name...
+ */
+
+ if (media->ppd)
+ {
+ /*
+ * Use a standard Adobe name...
+ */
+
+ strlcpy(name, media->ppd, namesize);
+ }
+ else if (!media->pwg || !strncmp(media->pwg, "custom_", 7) ||
+ (sizeptr = strchr(media->pwg, '_')) == NULL ||
+ (dimptr = strchr(sizeptr + 1, '_')) == NULL ||
+ (size_t)(dimptr - sizeptr) > namesize)
+ {
+ /*
+ * Use a name of the form "wNNNhNNN"...
+ */
+
+ snprintf(name, namesize, "w%dh%d", (int)_PWG_TOPTS(media->width),
+ (int)_PWG_TOPTS(media->length));
+ }
+ else
+ {
+ /*
+ * Copy the size name from class_sizename_dimensions...
+ */
+
+ memcpy(name, sizeptr + 1, dimptr - sizeptr - 1);
+ name[dimptr - sizeptr - 1] = '\0';
+ }
+
+ return (name);
+}
+
+
+/*
+ * 'pwg_ppdize_name()' - Convert an IPP keyword to a PPD keyword.
+ */
+
+static void
+pwg_ppdize_name(const char *ipp, /* I - IPP keyword */
+ char *name, /* I - Name buffer */
+ size_t namesize) /* I - Size of name buffer */
+{
+ char *ptr, /* Pointer into name buffer */
+ *end; /* End of name buffer */
+
+
+ *name = toupper(*ipp++);
+
+ for (ptr = name + 1, end = name + namesize - 1; *ipp && ptr < end;)
+ {
+ if (*ipp == '-' && _cups_isalpha(ipp[1]))
+ {
+ ipp ++;
+ *ptr++ = toupper(*ipp++ & 255);
+ }
+ else
+ *ptr++ = *ipp++;
+ }
+
+ *ptr = '\0';
+}
+
+
+/*
+ * 'pwg_unppdize_name()' - Convert a PPD keyword to a lowercase IPP keyword.
+ */
+
+static void
+pwg_unppdize_name(const char *ppd, /* I - PPD keyword */
+ char *name, /* I - Name buffer */
+ size_t namesize) /* I - Size of name buffer */
+{
+ char *ptr, /* Pointer into name buffer */
+ *end; /* End of name buffer */
+
+
+ for (ptr = name, end = name + namesize - 1; *ppd && ptr < end; ppd ++)
+ {
+ if (_cups_isalnum(*ppd) || *ppd == '-')
+ *ptr++ = tolower(*ppd & 255);
+ else if (*ppd == '_' || *ppd == '.')
+ *ptr++ = '-';
+
+ if (!_cups_isupper(*ppd) && _cups_isalnum(*ppd) &&
+ _cups_isupper(ppd[1]) && ptr < end)
+ *ptr++ = '-';
+ }
+
+ *ptr = '\0';
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/ppd-private.h b/cups/ppd-private.h
new file mode 100644
index 000000000..baf7fd169
--- /dev/null
+++ b/cups/ppd-private.h
@@ -0,0 +1,188 @@
+/*
+ * "$Id$"
+ *
+ * Private PPD definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * PostScript is a trademark of Adobe Systems, Inc.
+ *
+ * This code and any derivative of it may be used and distributed
+ * freely under the terms of the GNU General Public License when
+ * used with GNU Ghostscript or its derivatives. Use of the code
+ * (or any derivative of it) with software other than GNU
+ * GhostScript (or its derivatives) is governed by the CUPS license
+ * agreement.
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_PPD_PRIVATE_H_
+# define _CUPS_PPD_PRIVATE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include <cups/cups.h>
+# include <cups/ppd.h>
+# include "pwg-private.h"
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Constants...
+ */
+
+# define _PPD_CACHE_VERSION 1 /* Version number in cache file */
+
+
+/*
+ * Types and structures...
+ */
+
+typedef enum _ppd_parse_e /**** Selector for _ppdParseOptions ****/
+{
+ _PPD_PARSE_OPTIONS, /* Parse only the options */
+ _PPD_PARSE_PROPERTIES, /* Parse only the properties */
+ _PPD_PARSE_ALL /* Parse everything */
+} _ppd_parse_t;
+
+typedef struct _ppd_cups_uiconst_s /**** Constraint from cupsUIConstraints ****/
+{
+ ppd_option_t *option; /* Constrained option */
+ ppd_choice_t *choice; /* Constrained choice or @code NULL@ */
+ int installable; /* Installable option? */
+} _ppd_cups_uiconst_t;
+
+typedef struct _ppd_cups_uiconsts_s /**** cupsUIConstraints ****/
+{
+ char resolver[PPD_MAX_NAME]; /* Resolver name */
+ int installable, /* Constrained against any installable options? */
+ num_constraints; /* Number of constraints */
+ _ppd_cups_uiconst_t *constraints; /* Constraints */
+} _ppd_cups_uiconsts_t;
+
+typedef enum _pwg_print_color_mode_e /**** PWG print-color-mode indices ****/
+{
+ _PWG_PRINT_COLOR_MODE_MONOCHROME = 0, /* print-color-mode=monochrome */
+ _PWG_PRINT_COLOR_MODE_COLOR, /* print-color-mode=color */
+ /* Other proposed values are not supported by CUPS yet. */
+ _PWG_PRINT_COLOR_MODE_MAX
+} _pwg_print_color_mode_t;
+
+typedef enum _pwg_print_quality_e /**** PWG print-quality indices ****/
+{
+ _PWG_PRINT_QUALITY_DRAFT = 0, /* print-quality=3 */
+ _PWG_PRINT_QUALITY_NORMAL, /* print-quality=4 */
+ _PWG_PRINT_QUALITY_HIGH, /* print-quality=5 */
+ _PWG_PRINT_QUALITY_MAX
+} _pwg_print_quality_t;
+
+struct _ppd_cache_s /**** PPD cache and PWG conversion data ****/
+{
+ int num_bins; /* Number of output bins */
+ _pwg_map_t *bins; /* Output bins */
+ int num_sizes; /* Number of media sizes */
+ _pwg_size_t *sizes; /* Media sizes */
+ int custom_max_width, /* Maximum custom width in 2540ths */
+ custom_max_length, /* Maximum custom length in 2540ths */
+ custom_min_width, /* Minimum custom width in 2540ths */
+ custom_min_length; /* Minimum custom length in 2540ths */
+ char *custom_max_keyword, /* Maximum custom size PWG keyword */
+ *custom_min_keyword, /* Minimum custom size PWG keyword */
+ custom_ppd_size[41]; /* Custom PPD size name */
+ _pwg_size_t custom_size; /* Custom size record */
+ char *source_option; /* PPD option for media source */
+ int num_sources; /* Number of media sources */
+ _pwg_map_t *sources; /* Media sources */
+ int num_types; /* Number of media types */
+ _pwg_map_t *types; /* Media types */
+ int num_presets[_PWG_PRINT_COLOR_MODE_MAX][_PWG_PRINT_QUALITY_MAX];
+ /* Number of print-color-mode/print-quality options */
+ cups_option_t *presets[_PWG_PRINT_COLOR_MODE_MAX][_PWG_PRINT_QUALITY_MAX];
+ /* print-color-mode/print-quality options */
+ char *sides_option, /* PPD option for sides */
+ *sides_1sided, /* Choice for one-sided */
+ *sides_2sided_long, /* Choice for two-sided-long-edge */
+ *sides_2sided_short; /* Choice for two-sided-short-edge */
+ char *product; /* Product value */
+ cups_array_t *filters, /* cupsFilter/cupsFilter2 values */
+ *prefilters; /* cupsPreFilter values */
+ int single_file; /* cupsSingleFile value */
+};
+
+
+/*
+ * Prototypes...
+ */
+
+extern _ppd_cache_t *_ppdCacheCreateWithFile(const char *filename,
+ ipp_t **attrs);
+extern _ppd_cache_t *_ppdCacheCreateWithPPD(ppd_file_t *ppd);
+extern void _ppdCacheDestroy(_ppd_cache_t *pc);
+extern const char *_ppdCacheGetBin(_ppd_cache_t *pc,
+ const char *output_bin);
+extern const char *_ppdCacheGetInputSlot(_ppd_cache_t *pc, ipp_t *job,
+ const char *keyword);
+extern const char *_ppdCacheGetMediaType(_ppd_cache_t *pc, ipp_t *job,
+ const char *keyword);
+extern const char *_ppdCacheGetOutputBin(_ppd_cache_t *pc,
+ const char *keyword);
+extern const char *_ppdCacheGetPageSize(_ppd_cache_t *pc, ipp_t *job,
+ const char *keyword, int *exact);
+extern _pwg_size_t *_ppdCacheGetSize(_ppd_cache_t *pc,
+ const char *page_size);
+extern const char *_ppdCacheGetSource(_ppd_cache_t *pc,
+ const char *input_slot);
+extern const char *_ppdCacheGetType(_ppd_cache_t *pc,
+ const char *media_type);
+extern int _ppdCacheWriteFile(_ppd_cache_t *pc,
+ const char *filename, ipp_t *attrs);
+extern void _ppdFreeLanguages(cups_array_t *languages);
+extern cups_encoding_t _ppdGetEncoding(const char *name);
+extern cups_array_t *_ppdGetLanguages(ppd_file_t *ppd);
+extern unsigned _ppdHashName(const char *name);
+extern ppd_attr_t *_ppdLocalizedAttr(ppd_file_t *ppd, const char *keyword,
+ const char *spec, const char *ll_CC);
+extern char *_ppdNormalizeMakeAndModel(const char *make_and_model,
+ char *buffer,
+ size_t bufsize);
+extern int _ppdParseOptions(const char *s, int num_options,
+ cups_option_t **options,
+ _ppd_parse_t which);
+extern const char *_pwgInputSlotForSource(const char *media_source,
+ char *name, size_t namesize);
+extern const char *_pwgMediaTypeForType(const char *media_type,
+ char *name, size_t namesize);
+extern const char *_pwgPageSizeForMedia(_pwg_media_t *media,
+ char *name, size_t namesize);
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_PPD_PRIVATE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/ppd.c b/cups/ppd.c
new file mode 100644
index 000000000..9080c6e37
--- /dev/null
+++ b/cups/ppd.c
@@ -0,0 +1,3144 @@
+/*
+ * "$Id$"
+ *
+ * PPD file routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * PostScript is a trademark of Adobe Systems, Inc.
+ *
+ * This code and any derivative of it may be used and distributed
+ * freely under the terms of the GNU General Public License when
+ * used with GNU Ghostscript or its derivatives. Use of the code
+ * (or any derivative of it) with software other than GNU
+ * GhostScript (or its derivatives) is governed by the CUPS license
+ * agreement.
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * ppdClose() - Free all memory used by the PPD file.
+ * ppdErrorString() - Returns the text assocated with a status.
+ * _ppdGetEncoding() - Get the CUPS encoding value for the given
+ * LanguageEncoding.
+ * ppdLastError() - Return the status from the last ppdOpen*().
+ * ppdOpen() - Read a PPD file into memory.
+ * ppdOpen2() - Read a PPD file into memory.
+ * ppdOpenFd() - Read a PPD file into memory.
+ * ppdOpenFile() - Read a PPD file into memory.
+ * ppdSetConformance() - Set the conformance level for PPD files.
+ * ppd_add_attr() - Add an attribute to the PPD data.
+ * ppd_add_choice() - Add a choice to an option.
+ * ppd_add_size() - Add a page size.
+ * ppd_compare_attrs() - Compare two attributes.
+ * ppd_compare_choices() - Compare two choices...
+ * ppd_compare_coptions() - Compare two custom options.
+ * ppd_compare_options() - Compare two options.
+ * ppd_decode() - Decode a string value...
+ * ppd_free_group() - Free a single UI group.
+ * ppd_free_option() - Free a single option.
+ * ppd_get_coption() - Get a custom option record.
+ * ppd_get_cparam() - Get a custom parameter record.
+ * ppd_get_group() - Find or create the named group as needed.
+ * ppd_get_option() - Find or create the named option as needed.
+ * ppd_hash_option() - Generate a hash of the option name...
+ * ppd_read() - Read a line from a PPD file, skipping comment
+ * lines as necessary.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "cups-private.h"
+#include "ppd-private.h"
+
+
+/*
+ * Definitions...
+ */
+
+#if defined(WIN32) || defined(__EMX__)
+# define READ_BINARY "rb" /* Open a binary file for reading */
+# define WRITE_BINARY "wb" /* Open a binary file for writing */
+#else
+# define READ_BINARY "r" /* Open a binary file for reading */
+# define WRITE_BINARY "w" /* Open a binary file for writing */
+#endif /* WIN32 || __EMX__ */
+
+#define ppd_free(p) if (p) free(p) /* Safe free macro */
+
+#define PPD_KEYWORD 1 /* Line contained a keyword */
+#define PPD_OPTION 2 /* Line contained an option name */
+#define PPD_TEXT 4 /* Line contained human-readable text */
+#define PPD_STRING 8 /* Line contained a string or code */
+
+#define PPD_HASHSIZE 512 /* Size of hash */
+
+
+/*
+ * Line buffer structure...
+ */
+
+typedef struct _ppd_line_s
+{
+ char *buffer; /* Pointer to buffer */
+ size_t bufsize; /* Size of the buffer */
+} _ppd_line_t;
+
+
+/*
+ * Local functions...
+ */
+
+static ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name,
+ const char *spec, const char *text,
+ const char *value);
+static ppd_choice_t *ppd_add_choice(ppd_option_t *option, const char *name);
+static ppd_size_t *ppd_add_size(ppd_file_t *ppd, const char *name);
+static int ppd_compare_attrs(ppd_attr_t *a, ppd_attr_t *b);
+static int ppd_compare_choices(ppd_choice_t *a, ppd_choice_t *b);
+static int ppd_compare_coptions(ppd_coption_t *a,
+ ppd_coption_t *b);
+static int ppd_compare_options(ppd_option_t *a, ppd_option_t *b);
+static int ppd_decode(char *string);
+static void ppd_free_group(ppd_group_t *group);
+static void ppd_free_option(ppd_option_t *option);
+static ppd_coption_t *ppd_get_coption(ppd_file_t *ppd, const char *name);
+static ppd_cparam_t *ppd_get_cparam(ppd_coption_t *opt,
+ const char *param,
+ const char *text);
+static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name,
+ const char *text, _cups_globals_t *cg,
+ cups_encoding_t encoding);
+static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name);
+static int ppd_hash_option(ppd_option_t *option);
+static int ppd_read(cups_file_t *fp, _ppd_line_t *line,
+ char *keyword, char *option, char *text,
+ char **string, int ignoreblank,
+ _cups_globals_t *cg);
+
+
+/*
+ * 'ppdClose()' - Free all memory used by the PPD file.
+ */
+
+void
+ppdClose(ppd_file_t *ppd) /* I - PPD file record */
+{
+ int i; /* Looping var */
+ ppd_emul_t *emul; /* Current emulation */
+ ppd_group_t *group; /* Current group */
+ char **font; /* Current font */
+ char **filter; /* Current filter */
+ ppd_attr_t **attr; /* Current attribute */
+ ppd_coption_t *coption; /* Current custom option */
+ ppd_cparam_t *cparam; /* Current custom parameter */
+
+
+ /*
+ * Range check arguments...
+ */
+
+ if (!ppd)
+ return;
+
+ /*
+ * Free all strings at the top level...
+ */
+
+ _cupsStrFree(ppd->lang_encoding);
+ _cupsStrFree(ppd->nickname);
+ if (ppd->patches)
+ free(ppd->patches);
+ _cupsStrFree(ppd->jcl_begin);
+ _cupsStrFree(ppd->jcl_end);
+ _cupsStrFree(ppd->jcl_ps);
+
+ /*
+ * Free any emulations...
+ */
+
+ if (ppd->num_emulations > 0)
+ {
+ for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++)
+ {
+ _cupsStrFree(emul->start);
+ _cupsStrFree(emul->stop);
+ }
+
+ ppd_free(ppd->emulations);
+ }
+
+ /*
+ * Free any UI groups, subgroups, and options...
+ */
+
+ if (ppd->num_groups > 0)
+ {
+ for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
+ ppd_free_group(group);
+
+ ppd_free(ppd->groups);
+ }
+
+ cupsArrayDelete(ppd->options);
+ cupsArrayDelete(ppd->marked);
+
+ /*
+ * Free any page sizes...
+ */
+
+ if (ppd->num_sizes > 0)
+ ppd_free(ppd->sizes);
+
+ /*
+ * Free any constraints...
+ */
+
+ if (ppd->num_consts > 0)
+ ppd_free(ppd->consts);
+
+ /*
+ * Free any filters...
+ */
+
+ if (ppd->num_filters > 0)
+ {
+ for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
+ _cupsStrFree(*filter);
+
+ ppd_free(ppd->filters);
+ }
+
+ /*
+ * Free any fonts...
+ */
+
+ if (ppd->num_fonts > 0)
+ {
+ for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
+ _cupsStrFree(*font);
+
+ ppd_free(ppd->fonts);
+ }
+
+ /*
+ * Free any profiles...
+ */
+
+ if (ppd->num_profiles > 0)
+ ppd_free(ppd->profiles);
+
+ /*
+ * Free any attributes...
+ */
+
+ if (ppd->num_attrs > 0)
+ {
+ for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++)
+ {
+ _cupsStrFree((*attr)->value);
+ ppd_free(*attr);
+ }
+
+ ppd_free(ppd->attrs);
+ }
+
+ cupsArrayDelete(ppd->sorted_attrs);
+
+ /*
+ * Free custom options...
+ */
+
+ for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions);
+ coption;
+ coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions))
+ {
+ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+ cparam;
+ cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
+ {
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_PASSCODE :
+ case PPD_CUSTOM_PASSWORD :
+ case PPD_CUSTOM_STRING :
+ _cupsStrFree(cparam->current.custom_string);
+ break;
+
+ default :
+ break;
+ }
+
+ free(cparam);
+ }
+
+ cupsArrayDelete(coption->params);
+
+ free(coption);
+ }
+
+ cupsArrayDelete(ppd->coptions);
+
+ /*
+ * Free constraints...
+ */
+
+ if (ppd->cups_uiconstraints)
+ {
+ _ppd_cups_uiconsts_t *consts; /* Current constraints */
+
+
+ for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
+ consts;
+ consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
+ {
+ free(consts->constraints);
+ free(consts);
+ }
+
+ cupsArrayDelete(ppd->cups_uiconstraints);
+ }
+
+ /*
+ * Free any PPD cache/mapping data...
+ */
+
+ if (ppd->cache)
+ _ppdCacheDestroy(ppd->cache);
+
+ /*
+ * Free the whole record...
+ */
+
+ ppd_free(ppd);
+}
+
+
+/*
+ * 'ppdErrorString()' - Returns the text assocated with a status.
+ *
+ * @since CUPS 1.1.19/Mac OS X 10.3@
+ */
+
+const char * /* O - Status string */
+ppdErrorString(ppd_status_t status) /* I - PPD status */
+{
+ static const char * const messages[] =/* Status messages */
+ {
+ _("OK"),
+ _("Unable to open PPD file"),
+ _("NULL PPD file pointer"),
+ _("Memory allocation error"),
+ _("Missing PPD-Adobe-4.x header"),
+ _("Missing value string"),
+ _("Internal error"),
+ _("Bad OpenGroup"),
+ _("OpenGroup without a CloseGroup first"),
+ _("Bad OpenUI/JCLOpenUI"),
+ _("OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"),
+ _("Bad OrderDependency"),
+ _("Bad UIConstraints"),
+ _("Missing asterisk in column 1"),
+ _("Line longer than the maximum allowed (255 characters)"),
+ _("Illegal control character"),
+ _("Illegal main keyword string"),
+ _("Illegal option keyword string"),
+ _("Illegal translation string"),
+ _("Illegal whitespace character"),
+ _("Bad custom parameter"),
+ _("Missing option keyword"),
+ _("Bad value string"),
+ _("Missing CloseGroup")
+ };
+
+
+ if (status < PPD_OK || status >= PPD_MAX_STATUS)
+ return (_cupsLangString(cupsLangDefault(), _("Unknown")));
+ else
+ return (_cupsLangString(cupsLangDefault(), messages[status]));
+}
+
+
+/*
+ * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
+ * LanguageEncoding.
+ */
+
+cups_encoding_t /* O - CUPS encoding value */
+_ppdGetEncoding(const char *name) /* I - LanguageEncoding string */
+{
+ if (!_cups_strcasecmp(name, "ISOLatin1"))
+ return (CUPS_ISO8859_1);
+ else if (!_cups_strcasecmp(name, "ISOLatin2"))
+ return (CUPS_ISO8859_2);
+ else if (!_cups_strcasecmp(name, "ISOLatin5"))
+ return (CUPS_ISO8859_5);
+ else if (!_cups_strcasecmp(name, "JIS83-RKSJ"))
+ return (CUPS_JIS_X0213);
+ else if (!_cups_strcasecmp(name, "MacStandard"))
+ return (CUPS_MAC_ROMAN);
+ else if (!_cups_strcasecmp(name, "WindowsANSI"))
+ return (CUPS_WINDOWS_1252);
+ else
+ return (CUPS_UTF8);
+}
+
+
+/*
+ * 'ppdLastError()' - Return the status from the last ppdOpen*().
+ *
+ * @since CUPS 1.1.19/Mac OS X 10.3@
+ */
+
+ppd_status_t /* O - Status code */
+ppdLastError(int *line) /* O - Line number */
+{
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Global data */
+
+
+ if (line)
+ *line = cg->ppd_line;
+
+ return (cg->ppd_status);
+}
+
+
+/*
+ * 'ppdOpen()' - Read a PPD file into memory.
+ */
+
+ppd_file_t * /* O - PPD file record */
+ppdOpen(FILE *fp) /* I - File to read from */
+{
+ ppd_file_t *ppd; /* PPD file record */
+ cups_file_t *cf; /* CUPS file */
+
+
+ /*
+ * Reopen the stdio file as a CUPS file...
+ */
+
+ if ((cf = cupsFileOpenFd(fileno(fp), "r")) == NULL)
+ return (NULL);
+
+ /*
+ * Load the PPD file using the newer API...
+ */
+
+ ppd = ppdOpen2(cf);
+
+ /*
+ * Close the CUPS file and return the PPD...
+ */
+
+ cupsFileClose(cf);
+
+ return (ppd);
+}
+
+
+/*
+ * 'ppdOpen2()' - Read a PPD file into memory.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
+ppdOpen2(cups_file_t *fp) /* I - File to read from */
+{
+ int i, j, k; /* Looping vars */
+ int count; /* Temporary count */
+ _ppd_line_t line; /* Line buffer */
+ ppd_file_t *ppd; /* PPD file record */
+ ppd_group_t *group, /* Current group */
+ *subgroup; /* Current sub-group */
+ ppd_option_t *option; /* Current option */
+ ppd_choice_t *choice; /* Current choice */
+ ppd_const_t *constraint; /* Current constraint */
+ ppd_size_t *size; /* Current page size */
+ int mask; /* Line data mask */
+ char keyword[PPD_MAX_NAME],
+ /* Keyword from file */
+ name[PPD_MAX_NAME],
+ /* Option from file */
+ text[PPD_MAX_LINE],
+ /* Human-readable text from file */
+ *string, /* Code/text from file */
+ *sptr, /* Pointer into string */
+ *nameptr, /* Pointer into name */
+ *temp, /* Temporary string pointer */
+ **tempfonts; /* Temporary fonts pointer */
+ float order; /* Order dependency number */
+ ppd_section_t section; /* Order dependency section */
+ ppd_profile_t *profile; /* Pointer to color profile */
+ char **filter; /* Pointer to filter */
+ struct lconv *loc; /* Locale data */
+ int ui_keyword; /* Is this line a UI keyword? */
+ cups_encoding_t encoding; /* Encoding of PPD file */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Global data */
+ char custom_name[PPD_MAX_NAME];
+ /* CustomFoo attribute name */
+ ppd_attr_t *custom_attr; /* CustomFoo attribute */
+ static const char * const ui_keywords[] =
+ {
+#ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
+ /*
+ * Adobe defines some 41 keywords as "UI", meaning that they are
+ * user interface elements and that they should be treated as such
+ * even if the PPD creator doesn't use Open/CloseUI around them.
+ *
+ * Since this can cause previously invisible options to appear and
+ * confuse users, the default is to only treat the PageSize and
+ * PageRegion keywords this way.
+ */
+ /* Boolean keywords */
+ "BlackSubstitution",
+ "Booklet",
+ "Collate",
+ "ManualFeed",
+ "MirrorPrint",
+ "NegativePrint",
+ "Sorter",
+ "TraySwitch",
+
+ /* PickOne keywords */
+ "AdvanceMedia",
+ "BindColor",
+ "BindEdge",
+ "BindType",
+ "BindWhen",
+ "BitsPerPixel",
+ "ColorModel",
+ "CutMedia",
+ "Duplex",
+ "FoldType",
+ "FoldWhen",
+ "InputSlot",
+ "JCLFrameBufferSize",
+ "JCLResolution",
+ "Jog",
+ "MediaColor",
+ "MediaType",
+ "MediaWeight",
+ "OutputBin",
+ "OutputMode",
+ "OutputOrder",
+ "PageRegion",
+ "PageSize",
+ "Resolution",
+ "Separations",
+ "Signature",
+ "Slipsheet",
+ "Smoothing",
+ "StapleLocation",
+ "StapleOrientation",
+ "StapleWhen",
+ "StapleX",
+ "StapleY"
+#else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
+ "PageRegion",
+ "PageSize"
+#endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
+ };
+
+
+ DEBUG_printf(("ppdOpen2(fp=%p)", fp));
+
+ /*
+ * Default to "OK" status...
+ */
+
+ cg->ppd_status = PPD_OK;
+ cg->ppd_line = 0;
+
+ /*
+ * Range check input...
+ */
+
+ if (fp == NULL)
+ {
+ cg->ppd_status = PPD_NULL_FILE;
+ return (NULL);
+ }
+
+ /*
+ * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
+ */
+
+ line.buffer = NULL;
+ line.bufsize = 0;
+
+ mask = ppd_read(fp, &line, keyword, name, text, &string, 0, cg);
+
+ DEBUG_printf(("2ppdOpen2: mask=%x, keyword=\"%s\"...", mask, keyword));
+
+ if (mask == 0 ||
+ strcmp(keyword, "PPD-Adobe") ||
+ string == NULL || string[0] != '4')
+ {
+ /*
+ * Either this is not a PPD file, or it is not a 4.x PPD file.
+ */
+
+ if (cg->ppd_status == PPD_OK)
+ cg->ppd_status = PPD_MISSING_PPDADOBE4;
+
+ _cupsStrFree(string);
+ ppd_free(line.buffer);
+
+ return (NULL);
+ }
+
+ DEBUG_printf(("2ppdOpen2: keyword=%s, string=%p", keyword, string));
+
+ _cupsStrFree(string);
+
+ /*
+ * Allocate memory for the PPD file record...
+ */
+
+ if ((ppd = calloc(1, sizeof(ppd_file_t))) == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ _cupsStrFree(string);
+ ppd_free(line.buffer);
+
+ return (NULL);
+ }
+
+ ppd->language_level = 2;
+ ppd->color_device = 0;
+ ppd->colorspace = PPD_CS_N;
+ ppd->landscape = -90;
+ ppd->coptions = cupsArrayNew((cups_array_func_t)ppd_compare_coptions,
+ NULL);
+
+ /*
+ * Read lines from the PPD file and add them to the file record...
+ */
+
+ group = NULL;
+ subgroup = NULL;
+ option = NULL;
+ choice = NULL;
+ ui_keyword = 0;
+ encoding = CUPS_ISO8859_1;
+ loc = localeconv();
+
+ while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, cg)) != 0)
+ {
+ DEBUG_printf(("2ppdOpen2: mask=%x, keyword=\"%s\", name=\"%s\", "
+ "text=\"%s\", string=%d chars...", mask, keyword, name, text,
+ string ? (int)strlen(string) : 0));
+
+ if (strncmp(keyword, "Default", 7) && !string &&
+ cg->ppd_conform != PPD_CONFORM_RELAXED)
+ {
+ /*
+ * Need a string value!
+ */
+
+ cg->ppd_status = PPD_MISSING_VALUE;
+
+ goto error;
+ }
+ else if (!string)
+ continue;
+
+ /*
+ * Certain main keywords (as defined by the PPD spec) may be used
+ * without the usual OpenUI/CloseUI stuff. Presumably this is just
+ * so that Adobe wouldn't completely break compatibility with PPD
+ * files prior to v4.0 of the spec, but it is hopelessly
+ * inconsistent... Catch these main keywords and automatically
+ * create the corresponding option, as needed...
+ */
+
+ if (ui_keyword)
+ {
+ /*
+ * Previous line was a UI keyword...
+ */
+
+ option = NULL;
+ ui_keyword = 0;
+ }
+
+ if (option == NULL &&
+ (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
+ (PPD_KEYWORD | PPD_OPTION | PPD_STRING))
+ {
+ for (i = 0; i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])); i ++)
+ if (!strcmp(keyword, ui_keywords[i]))
+ break;
+
+ if (i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])))
+ {
+ /*
+ * Create the option in the appropriate group...
+ */
+
+ ui_keyword = 1;
+
+ DEBUG_printf(("2ppdOpen2: FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!",
+ keyword));
+
+ if (!group)
+ {
+ if ((group = ppd_get_group(ppd, "General", _("General"), cg,
+ encoding)) == NULL)
+ goto error;
+
+ DEBUG_printf(("2ppdOpen2: Adding to group %s...", group->text));
+ option = ppd_get_option(group, keyword);
+ group = NULL;
+ }
+ else
+ option = ppd_get_option(group, keyword);
+
+ if (option == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ /*
+ * Now fill in the initial information for the option...
+ */
+
+ if (!strncmp(keyword, "JCL", 3))
+ option->section = PPD_ORDER_JCL;
+ else
+ option->section = PPD_ORDER_ANY;
+
+ option->order = 10.0f;
+
+ if (i < 8)
+ option->ui = PPD_UI_BOOLEAN;
+ else
+ option->ui = PPD_UI_PICKONE;
+
+ for (j = 0; j < ppd->num_attrs; j ++)
+ if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
+ !strcmp(ppd->attrs[j]->name + 7, keyword) &&
+ ppd->attrs[j]->value)
+ {
+ DEBUG_printf(("2ppdOpen2: Setting Default%s to %s via attribute...",
+ option->keyword, ppd->attrs[j]->value));
+ strlcpy(option->defchoice, ppd->attrs[j]->value,
+ sizeof(option->defchoice));
+ break;
+ }
+
+ if (!strcmp(keyword, "PageSize"))
+ strlcpy(option->text, _("Media Size"), sizeof(option->text));
+ else if (!strcmp(keyword, "MediaType"))
+ strlcpy(option->text, _("Media Type"), sizeof(option->text));
+ else if (!strcmp(keyword, "InputSlot"))
+ strlcpy(option->text, _("Media Source"), sizeof(option->text));
+ else if (!strcmp(keyword, "ColorModel"))
+ strlcpy(option->text, _("Output Mode"), sizeof(option->text));
+ else if (!strcmp(keyword, "Resolution"))
+ strlcpy(option->text, _("Resolution"), sizeof(option->text));
+ else
+ strlcpy(option->text, keyword, sizeof(option->text));
+ }
+ }
+
+ if (!strcmp(keyword, "LanguageLevel"))
+ ppd->language_level = atoi(string);
+ else if (!strcmp(keyword, "LanguageEncoding"))
+ {
+ /*
+ * Say all PPD files are UTF-8, since we convert to UTF-8...
+ */
+
+ ppd->lang_encoding = _cupsStrAlloc("UTF-8");
+ encoding = _ppdGetEncoding(string);
+ }
+ else if (!strcmp(keyword, "LanguageVersion"))
+ ppd->lang_version = string;
+ else if (!strcmp(keyword, "Manufacturer"))
+ ppd->manufacturer = string;
+ else if (!strcmp(keyword, "ModelName"))
+ ppd->modelname = string;
+ else if (!strcmp(keyword, "Protocols"))
+ ppd->protocols = string;
+ else if (!strcmp(keyword, "PCFileName"))
+ ppd->pcfilename = string;
+ else if (!strcmp(keyword, "NickName"))
+ {
+ if (encoding != CUPS_UTF8)
+ {
+ cups_utf8_t utf8[256]; /* UTF-8 version of NickName */
+
+
+ cupsCharsetToUTF8(utf8, string, sizeof(utf8), encoding);
+ ppd->nickname = _cupsStrAlloc((char *)utf8);
+ }
+ else
+ ppd->nickname = _cupsStrAlloc(string);
+ }
+ else if (!strcmp(keyword, "Product"))
+ ppd->product = string;
+ else if (!strcmp(keyword, "ShortNickName"))
+ ppd->shortnickname = string;
+ else if (!strcmp(keyword, "TTRasterizer"))
+ ppd->ttrasterizer = string;
+ else if (!strcmp(keyword, "JCLBegin"))
+ {
+ ppd->jcl_begin = _cupsStrAlloc(string);
+ ppd_decode(ppd->jcl_begin); /* Decode quoted string */
+ }
+ else if (!strcmp(keyword, "JCLEnd"))
+ {
+ ppd->jcl_end = _cupsStrAlloc(string);
+ ppd_decode(ppd->jcl_end); /* Decode quoted string */
+ }
+ else if (!strcmp(keyword, "JCLToPSInterpreter"))
+ {
+ ppd->jcl_ps = _cupsStrAlloc(string);
+ ppd_decode(ppd->jcl_ps); /* Decode quoted string */
+ }
+ else if (!strcmp(keyword, "AccurateScreensSupport"))
+ ppd->accurate_screens = !strcmp(string, "True");
+ else if (!strcmp(keyword, "ColorDevice"))
+ ppd->color_device = !strcmp(string, "True");
+ else if (!strcmp(keyword, "ContoneOnly"))
+ ppd->contone_only = !strcmp(string, "True");
+ else if (!strcmp(keyword, "cupsFlipDuplex"))
+ ppd->flip_duplex = !strcmp(string, "True");
+ else if (!strcmp(keyword, "cupsManualCopies"))
+ ppd->manual_copies = !strcmp(string, "True");
+ else if (!strcmp(keyword, "cupsModelNumber"))
+ ppd->model_number = atoi(string);
+ else if (!strcmp(keyword, "cupsColorProfile"))
+ {
+ if (ppd->num_profiles == 0)
+ profile = malloc(sizeof(ppd_profile_t));
+ else
+ profile = realloc(ppd->profiles, sizeof(ppd_profile_t) *
+ (ppd->num_profiles + 1));
+
+ if (!profile)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ ppd->profiles = profile;
+ profile += ppd->num_profiles;
+ ppd->num_profiles ++;
+
+ memset(profile, 0, sizeof(ppd_profile_t));
+ strlcpy(profile->resolution, name, sizeof(profile->resolution));
+ strlcpy(profile->media_type, text, sizeof(profile->media_type));
+
+ profile->density = (float)_cupsStrScand(string, &sptr, loc);
+ profile->gamma = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[0][0] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[0][1] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[0][2] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[1][0] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[1][1] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[1][2] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[2][0] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[2][1] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[2][2] = (float)_cupsStrScand(sptr, &sptr, loc);
+ }
+ else if (!strcmp(keyword, "cupsFilter"))
+ {
+ if (ppd->num_filters == 0)
+ filter = malloc(sizeof(char *));
+ else
+ filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1));
+
+ if (filter == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ ppd->filters = filter;
+ filter += ppd->num_filters;
+ ppd->num_filters ++;
+
+ /*
+ * Copy filter string and prevent it from being freed below...
+ */
+
+ *filter = string;
+ string = NULL;
+ }
+ else if (!strcmp(keyword, "Throughput"))
+ ppd->throughput = atoi(string);
+ else if (!strcmp(keyword, "Font"))
+ {
+ /*
+ * Add this font to the list of available fonts...
+ */
+
+ if (ppd->num_fonts == 0)
+ tempfonts = (char **)malloc(sizeof(char *));
+ else
+ tempfonts = (char **)realloc(ppd->fonts,
+ sizeof(char *) * (ppd->num_fonts + 1));
+
+ if (tempfonts == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ ppd->fonts = tempfonts;
+ ppd->fonts[ppd->num_fonts] = _cupsStrAlloc(name);
+ ppd->num_fonts ++;
+ }
+ else if (!strncmp(keyword, "ParamCustom", 11))
+ {
+ ppd_coption_t *coption; /* Custom option */
+ ppd_cparam_t *cparam; /* Custom parameter */
+ int corder; /* Order number */
+ char ctype[33], /* Data type */
+ cminimum[65], /* Minimum value */
+ cmaximum[65]; /* Maximum value */
+
+
+ /*
+ * Get the custom option and parameter...
+ */
+
+ if ((coption = ppd_get_coption(ppd, keyword + 11)) == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ if ((cparam = ppd_get_cparam(coption, name, text)) == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ /*
+ * Get the parameter data...
+ */
+
+ if (!string ||
+ sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum,
+ cmaximum) != 4)
+ {
+ cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
+
+ goto error;
+ }
+
+ cparam->order = corder;
+
+ if (!strcmp(ctype, "curve"))
+ {
+ cparam->type = PPD_CUSTOM_CURVE;
+ cparam->minimum.custom_curve = (float)_cupsStrScand(cminimum, NULL, loc);
+ cparam->maximum.custom_curve = (float)_cupsStrScand(cmaximum, NULL, loc);
+ }
+ else if (!strcmp(ctype, "int"))
+ {
+ cparam->type = PPD_CUSTOM_INT;
+ cparam->minimum.custom_int = atoi(cminimum);
+ cparam->maximum.custom_int = atoi(cmaximum);
+ }
+ else if (!strcmp(ctype, "invcurve"))
+ {
+ cparam->type = PPD_CUSTOM_INVCURVE;
+ cparam->minimum.custom_invcurve = (float)_cupsStrScand(cminimum, NULL, loc);
+ cparam->maximum.custom_invcurve = (float)_cupsStrScand(cmaximum, NULL, loc);
+ }
+ else if (!strcmp(ctype, "passcode"))
+ {
+ cparam->type = PPD_CUSTOM_PASSCODE;
+ cparam->minimum.custom_passcode = atoi(cminimum);
+ cparam->maximum.custom_passcode = atoi(cmaximum);
+ }
+ else if (!strcmp(ctype, "password"))
+ {
+ cparam->type = PPD_CUSTOM_PASSWORD;
+ cparam->minimum.custom_password = atoi(cminimum);
+ cparam->maximum.custom_password = atoi(cmaximum);
+ }
+ else if (!strcmp(ctype, "points"))
+ {
+ cparam->type = PPD_CUSTOM_POINTS;
+ cparam->minimum.custom_points = (float)_cupsStrScand(cminimum, NULL, loc);
+ cparam->maximum.custom_points = (float)_cupsStrScand(cmaximum, NULL, loc);
+ }
+ else if (!strcmp(ctype, "real"))
+ {
+ cparam->type = PPD_CUSTOM_REAL;
+ cparam->minimum.custom_real = (float)_cupsStrScand(cminimum, NULL, loc);
+ cparam->maximum.custom_real = (float)_cupsStrScand(cmaximum, NULL, loc);
+ }
+ else if (!strcmp(ctype, "string"))
+ {
+ cparam->type = PPD_CUSTOM_STRING;
+ cparam->minimum.custom_string = atoi(cminimum);
+ cparam->maximum.custom_string = atoi(cmaximum);
+ }
+ else
+ {
+ cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
+
+ goto error;
+ }
+
+ /*
+ * Now special-case for CustomPageSize...
+ */
+
+ if (!strcmp(coption->keyword, "PageSize"))
+ {
+ if (!strcmp(name, "Width"))
+ {
+ ppd->custom_min[0] = cparam->minimum.custom_points;
+ ppd->custom_max[0] = cparam->maximum.custom_points;
+ }
+ else if (!strcmp(name, "Height"))
+ {
+ ppd->custom_min[1] = cparam->minimum.custom_points;
+ ppd->custom_max[1] = cparam->maximum.custom_points;
+ }
+ }
+ }
+ else if (!strcmp(keyword, "HWMargins"))
+ {
+ for (i = 0, sptr = string; i < 4; i ++)
+ ppd->custom_margins[i] = (float)_cupsStrScand(sptr, &sptr, loc);
+ }
+ else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
+ {
+ ppd_option_t *custom_option; /* Custom option */
+
+ DEBUG_puts("2ppdOpen2: Processing Custom option...");
+
+ /*
+ * Get the option and custom option...
+ */
+
+ if (!ppd_get_coption(ppd, keyword + 6))
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ if (option && !_cups_strcasecmp(option->keyword, keyword + 6))
+ custom_option = option;
+ else
+ custom_option = ppdFindOption(ppd, keyword + 6);
+
+ if (custom_option)
+ {
+ /*
+ * Add the "custom" option...
+ */
+
+ if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
+ if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
+ {
+ DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
+
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ strlcpy(choice->text, text[0] ? text : _("Custom"),
+ sizeof(choice->text));
+
+ choice->code = _cupsStrAlloc(string);
+
+ if (custom_option->section == PPD_ORDER_JCL)
+ ppd_decode(choice->code);
+ }
+
+ /*
+ * Now process custom page sizes specially...
+ */
+
+ if (!strcmp(keyword, "CustomPageSize"))
+ {
+ /*
+ * Add a "Custom" page size entry...
+ */
+
+ ppd->variable_sizes = 1;
+
+ ppd_add_size(ppd, "Custom");
+
+ if (option && !_cups_strcasecmp(option->keyword, "PageRegion"))
+ custom_option = option;
+ else
+ custom_option = ppdFindOption(ppd, "PageRegion");
+
+ if (custom_option)
+ {
+ if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
+ if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
+ {
+ DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
+
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ strlcpy(choice->text, text[0] ? text : _("Custom"),
+ sizeof(choice->text));
+ }
+ }
+ }
+ else if (!strcmp(keyword, "LandscapeOrientation"))
+ {
+ if (!strcmp(string, "Minus90"))
+ ppd->landscape = -90;
+ else if (!strcmp(string, "Plus90"))
+ ppd->landscape = 90;
+ }
+ else if (!strcmp(keyword, "Emulators") && string)
+ {
+ for (count = 1, sptr = string; sptr != NULL;)
+ if ((sptr = strchr(sptr, ' ')) != NULL)
+ {
+ count ++;
+ while (*sptr == ' ')
+ sptr ++;
+ }
+
+ ppd->num_emulations = count;
+ if ((ppd->emulations = calloc(count, sizeof(ppd_emul_t))) == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ for (i = 0, sptr = string; i < count; i ++)
+ {
+ for (nameptr = ppd->emulations[i].name;
+ *sptr != '\0' && *sptr != ' ';
+ sptr ++)
+ if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
+ *nameptr++ = *sptr;
+
+ *nameptr = '\0';
+
+ while (*sptr == ' ')
+ sptr ++;
+ }
+ }
+ else if (!strncmp(keyword, "StartEmulator_", 14))
+ {
+ ppd_decode(string);
+
+ for (i = 0; i < ppd->num_emulations; i ++)
+ if (!strcmp(keyword + 14, ppd->emulations[i].name))
+ {
+ ppd->emulations[i].start = string;
+ string = NULL;
+ }
+ }
+ else if (!strncmp(keyword, "StopEmulator_", 13))
+ {
+ ppd_decode(string);
+
+ for (i = 0; i < ppd->num_emulations; i ++)
+ if (!strcmp(keyword + 13, ppd->emulations[i].name))
+ {
+ ppd->emulations[i].stop = string;
+ string = NULL;
+ }
+ }
+ else if (!strcmp(keyword, "JobPatchFile"))
+ {
+ /*
+ * CUPS STR #3421: Check for "*JobPatchFile: int: string"
+ */
+
+ if (isdigit(*string & 255))
+ {
+ for (sptr = string + 1; isdigit(*sptr & 255); sptr ++);
+
+ if (*sptr == ':')
+ {
+ /*
+ * Found "*JobPatchFile: int: string"...
+ */
+
+ cg->ppd_status = PPD_BAD_VALUE;
+
+ goto error;
+ }
+ }
+
+ if (!name[0] && cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ /*
+ * Found "*JobPatchFile: string"...
+ */
+
+ cg->ppd_status = PPD_MISSING_OPTION_KEYWORD;
+
+ goto error;
+ }
+
+ if (ppd->patches == NULL)
+ ppd->patches = strdup(string);
+ else
+ {
+ temp = realloc(ppd->patches, strlen(ppd->patches) +
+ strlen(string) + 1);
+ if (temp == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ ppd->patches = temp;
+
+ strcpy(ppd->patches + strlen(ppd->patches), string);
+ }
+ }
+ else if (!strcmp(keyword, "OpenUI"))
+ {
+ /*
+ * Don't allow nesting of options...
+ */
+
+ if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_NESTED_OPEN_UI;
+
+ goto error;
+ }
+
+ /*
+ * Add an option record to the current sub-group, group, or file...
+ */
+
+ DEBUG_printf(("2ppdOpen2: name=\"%s\" (%d)", name, (int)strlen(name)));
+
+ if (name[0] == '*')
+ _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
+
+ for (i = (int)strlen(name) - 1; i > 0 && _cups_isspace(name[i]); i --)
+ name[i] = '\0'; /* Eliminate trailing spaces */
+
+ DEBUG_printf(("2ppdOpen2: OpenUI of %s in group %s...", name,
+ group ? group->text : "(null)"));
+
+ if (subgroup != NULL)
+ option = ppd_get_option(subgroup, name);
+ else if (group == NULL)
+ {
+ if ((group = ppd_get_group(ppd, "General", _("General"), cg,
+ encoding)) == NULL)
+ goto error;
+
+ DEBUG_printf(("2ppdOpen2: Adding to group %s...", group->text));
+ option = ppd_get_option(group, name);
+ group = NULL;
+ }
+ else
+ option = ppd_get_option(group, name);
+
+ if (option == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ /*
+ * Now fill in the initial information for the option...
+ */
+
+ if (string && !strcmp(string, "PickMany"))
+ option->ui = PPD_UI_PICKMANY;
+ else if (string && !strcmp(string, "Boolean"))
+ option->ui = PPD_UI_BOOLEAN;
+ else if (string && !strcmp(string, "PickOne"))
+ option->ui = PPD_UI_PICKONE;
+ else if (cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_BAD_OPEN_UI;
+
+ goto error;
+ }
+ else
+ option->ui = PPD_UI_PICKONE;
+
+ for (j = 0; j < ppd->num_attrs; j ++)
+ if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
+ !strcmp(ppd->attrs[j]->name + 7, name) &&
+ ppd->attrs[j]->value)
+ {
+ DEBUG_printf(("2ppdOpen2: Setting Default%s to %s via attribute...",
+ option->keyword, ppd->attrs[j]->value));
+ strlcpy(option->defchoice, ppd->attrs[j]->value,
+ sizeof(option->defchoice));
+ break;
+ }
+
+ if (text[0])
+ cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
+ sizeof(option->text), encoding);
+ else
+ {
+ if (!strcmp(name, "PageSize"))
+ strlcpy(option->text, _("Media Size"), sizeof(option->text));
+ else if (!strcmp(name, "MediaType"))
+ strlcpy(option->text, _("Media Type"), sizeof(option->text));
+ else if (!strcmp(name, "InputSlot"))
+ strlcpy(option->text, _("Media Source"), sizeof(option->text));
+ else if (!strcmp(name, "ColorModel"))
+ strlcpy(option->text, _("Output Mode"), sizeof(option->text));
+ else if (!strcmp(name, "Resolution"))
+ strlcpy(option->text, _("Resolution"), sizeof(option->text));
+ else
+ strlcpy(option->text, name, sizeof(option->text));
+ }
+
+ option->section = PPD_ORDER_ANY;
+
+ _cupsStrFree(string);
+ string = NULL;
+
+ /*
+ * Add a custom option choice if we have already seen a CustomFoo
+ * attribute...
+ */
+
+ if (!_cups_strcasecmp(name, "PageRegion"))
+ strcpy(custom_name, "CustomPageSize");
+ else
+ snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
+
+ if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
+ {
+ if ((choice = ppdFindChoice(option, "Custom")) == NULL)
+ if ((choice = ppd_add_choice(option, "Custom")) == NULL)
+ {
+ DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
+
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ strlcpy(choice->text,
+ custom_attr->text[0] ? custom_attr->text : _("Custom"),
+ sizeof(choice->text));
+ choice->code = _cupsStrRetain(custom_attr->value);
+ }
+ }
+ else if (!strcmp(keyword, "JCLOpenUI"))
+ {
+ /*
+ * Don't allow nesting of options...
+ */
+
+ if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_NESTED_OPEN_UI;
+
+ goto error;
+ }
+
+ /*
+ * Find the JCL group, and add if needed...
+ */
+
+ group = ppd_get_group(ppd, "JCL", _("JCL"), cg, encoding);
+
+ if (group == NULL)
+ goto error;
+
+ /*
+ * Add an option record to the current JCLs...
+ */
+
+ if (name[0] == '*')
+ _cups_strcpy(name, name + 1);
+
+ option = ppd_get_option(group, name);
+
+ if (option == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ /*
+ * Now fill in the initial information for the option...
+ */
+
+ if (string && !strcmp(string, "PickMany"))
+ option->ui = PPD_UI_PICKMANY;
+ else if (string && !strcmp(string, "Boolean"))
+ option->ui = PPD_UI_BOOLEAN;
+ else if (string && !strcmp(string, "PickOne"))
+ option->ui = PPD_UI_PICKONE;
+ else
+ {
+ cg->ppd_status = PPD_BAD_OPEN_UI;
+
+ goto error;
+ }
+
+ for (j = 0; j < ppd->num_attrs; j ++)
+ if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
+ !strcmp(ppd->attrs[j]->name + 7, name) &&
+ ppd->attrs[j]->value)
+ {
+ DEBUG_printf(("2ppdOpen2: Setting Default%s to %s via attribute...",
+ option->keyword, ppd->attrs[j]->value));
+ strlcpy(option->defchoice, ppd->attrs[j]->value,
+ sizeof(option->defchoice));
+ break;
+ }
+
+ if (text[0])
+ cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
+ sizeof(option->text), encoding);
+ else
+ strlcpy(option->text, name, sizeof(option->text));
+
+ option->section = PPD_ORDER_JCL;
+ group = NULL;
+
+ _cupsStrFree(string);
+ string = NULL;
+
+ /*
+ * Add a custom option choice if we have already seen a CustomFoo
+ * attribute...
+ */
+
+ snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
+
+ if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
+ {
+ if ((choice = ppd_add_choice(option, "Custom")) == NULL)
+ {
+ DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
+
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ strlcpy(choice->text,
+ custom_attr->text[0] ? custom_attr->text : _("Custom"),
+ sizeof(choice->text));
+ choice->code = _cupsStrRetain(custom_attr->value);
+ }
+ }
+ else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
+ {
+ option = NULL;
+
+ _cupsStrFree(string);
+ string = NULL;
+ }
+ else if (!strcmp(keyword, "OpenGroup"))
+ {
+ /*
+ * Open a new group...
+ */
+
+ if (group != NULL)
+ {
+ cg->ppd_status = PPD_NESTED_OPEN_GROUP;
+
+ goto error;
+ }
+
+ if (!string)
+ {
+ cg->ppd_status = PPD_BAD_OPEN_GROUP;
+
+ goto error;
+ }
+
+ /*
+ * Separate the group name from the text (name/text)...
+ */
+
+ if ((sptr = strchr(string, '/')) != NULL)
+ *sptr++ = '\0';
+ else
+ sptr = string;
+
+ /*
+ * Fix up the text...
+ */
+
+ ppd_decode(sptr);
+
+ /*
+ * Find/add the group...
+ */
+
+ group = ppd_get_group(ppd, string, sptr, cg, encoding);
+
+ if (group == NULL)
+ goto error;
+
+ _cupsStrFree(string);
+ string = NULL;
+ }
+ else if (!strcmp(keyword, "CloseGroup"))
+ {
+ group = NULL;
+
+ _cupsStrFree(string);
+ string = NULL;
+ }
+ else if (!strcmp(keyword, "OrderDependency"))
+ {
+ order = (float)_cupsStrScand(string, &sptr, loc);
+
+ if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
+ {
+ cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
+
+ goto error;
+ }
+
+ if (keyword[0] == '*')
+ _cups_strcpy(keyword, keyword + 1);
+
+ if (!strcmp(name, "ExitServer"))
+ section = PPD_ORDER_EXIT;
+ else if (!strcmp(name, "Prolog"))
+ section = PPD_ORDER_PROLOG;
+ else if (!strcmp(name, "DocumentSetup"))
+ section = PPD_ORDER_DOCUMENT;
+ else if (!strcmp(name, "PageSetup"))
+ section = PPD_ORDER_PAGE;
+ else if (!strcmp(name, "JCLSetup"))
+ section = PPD_ORDER_JCL;
+ else
+ section = PPD_ORDER_ANY;
+
+ if (option == NULL)
+ {
+ ppd_group_t *gtemp;
+
+
+ /*
+ * Only valid for Non-UI options...
+ */
+
+ for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++)
+ if (gtemp->text[0] == '\0')
+ break;
+
+ if (i > 0)
+ for (i = 0; i < gtemp->num_options; i ++)
+ if (!strcmp(keyword, gtemp->options[i].keyword))
+ {
+ gtemp->options[i].section = section;
+ gtemp->options[i].order = order;
+ break;
+ }
+ }
+ else
+ {
+ option->section = section;
+ option->order = order;
+ }
+
+ _cupsStrFree(string);
+ string = NULL;
+ }
+ else if (!strncmp(keyword, "Default", 7))
+ {
+ if (string == NULL)
+ continue;
+
+ /*
+ * Drop UI text, if any, from value...
+ */
+
+ if (strchr(string, '/') != NULL)
+ *strchr(string, '/') = '\0';
+
+ /*
+ * Assign the default value as appropriate...
+ */
+
+ if (!strcmp(keyword, "DefaultColorSpace"))
+ {
+ /*
+ * Set default colorspace...
+ */
+
+ if (!strcmp(string, "CMY"))
+ ppd->colorspace = PPD_CS_CMY;
+ else if (!strcmp(string, "CMYK"))
+ ppd->colorspace = PPD_CS_CMYK;
+ else if (!strcmp(string, "RGB"))
+ ppd->colorspace = PPD_CS_RGB;
+ else if (!strcmp(string, "RGBK"))
+ ppd->colorspace = PPD_CS_RGBK;
+ else if (!strcmp(string, "N"))
+ ppd->colorspace = PPD_CS_N;
+ else
+ ppd->colorspace = PPD_CS_GRAY;
+ }
+ else if (option && !strcmp(keyword + 7, option->keyword))
+ {
+ /*
+ * Set the default as part of the current option...
+ */
+
+ DEBUG_printf(("2ppdOpen2: Setting %s to %s...", keyword, string));
+
+ strlcpy(option->defchoice, string, sizeof(option->defchoice));
+
+ DEBUG_printf(("2ppdOpen2: %s is now %s...", keyword, option->defchoice));
+ }
+ else
+ {
+ /*
+ * Lookup option and set if it has been defined...
+ */
+
+ ppd_option_t *toption; /* Temporary option */
+
+
+ if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
+ {
+ DEBUG_printf(("2ppdOpen2: Setting %s to %s...", keyword, string));
+ strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
+ }
+ }
+ }
+ else if (!strcmp(keyword, "UIConstraints") ||
+ !strcmp(keyword, "NonUIConstraints"))
+ {
+ if (!string)
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
+ if (ppd->num_consts == 0)
+ constraint = calloc(2, sizeof(ppd_const_t));
+ else
+ constraint = realloc(ppd->consts,
+ (ppd->num_consts + 2) * sizeof(ppd_const_t));
+
+ if (constraint == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ ppd->consts = constraint;
+ constraint += ppd->num_consts;
+ ppd->num_consts ++;
+
+ switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
+ constraint->choice1, constraint->option2,
+ constraint->choice2))
+ {
+ case 0 : /* Error */
+ case 1 : /* Error */
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+
+ case 2 : /* Two options... */
+ /*
+ * Check for broken constraints like "* Option"...
+ */
+
+ if (cg->ppd_conform == PPD_CONFORM_STRICT &&
+ (!strcmp(constraint->option1, "*") ||
+ !strcmp(constraint->choice1, "*")))
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
+ /*
+ * The following strcpy's are safe, as optionN and
+ * choiceN are all the same size (size defined by PPD spec...)
+ */
+
+ if (constraint->option1[0] == '*')
+ _cups_strcpy(constraint->option1, constraint->option1 + 1);
+ else if (cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
+ if (constraint->choice1[0] == '*')
+ _cups_strcpy(constraint->option2, constraint->choice1 + 1);
+ else if (cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
+ constraint->choice1[0] = '\0';
+ constraint->choice2[0] = '\0';
+ break;
+
+ case 3 : /* Two options, one choice... */
+ /*
+ * Check for broken constraints like "* Option"...
+ */
+
+ if (cg->ppd_conform == PPD_CONFORM_STRICT &&
+ (!strcmp(constraint->option1, "*") ||
+ !strcmp(constraint->choice1, "*") ||
+ !strcmp(constraint->option2, "*")))
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
+ /*
+ * The following _cups_strcpy's are safe, as optionN and
+ * choiceN are all the same size (size defined by PPD spec...)
+ */
+
+ if (constraint->option1[0] == '*')
+ _cups_strcpy(constraint->option1, constraint->option1 + 1);
+ else if (cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
+ if (constraint->choice1[0] == '*')
+ {
+ if (cg->ppd_conform == PPD_CONFORM_STRICT &&
+ constraint->option2[0] == '*')
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
+ _cups_strcpy(constraint->choice2, constraint->option2);
+ _cups_strcpy(constraint->option2, constraint->choice1 + 1);
+ constraint->choice1[0] = '\0';
+ }
+ else
+ {
+ if (constraint->option2[0] == '*')
+ _cups_strcpy(constraint->option2, constraint->option2 + 1);
+ else if (cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
+ constraint->choice2[0] = '\0';
+ }
+ break;
+
+ case 4 : /* Two options, two choices... */
+ /*
+ * Check for broken constraints like "* Option"...
+ */
+
+ if (cg->ppd_conform == PPD_CONFORM_STRICT &&
+ (!strcmp(constraint->option1, "*") ||
+ !strcmp(constraint->choice1, "*") ||
+ !strcmp(constraint->option2, "*") ||
+ !strcmp(constraint->choice2, "*")))
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
+ if (constraint->option1[0] == '*')
+ _cups_strcpy(constraint->option1, constraint->option1 + 1);
+ else if (cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
+ if (cg->ppd_conform == PPD_CONFORM_STRICT &&
+ constraint->choice1[0] == '*')
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
+ if (constraint->option2[0] == '*')
+ _cups_strcpy(constraint->option2, constraint->option2 + 1);
+ else if (cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
+ if (cg->ppd_conform == PPD_CONFORM_STRICT &&
+ constraint->choice2[0] == '*')
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+ break;
+ }
+
+ /*
+ * Don't add this one as an attribute...
+ */
+
+ _cupsStrFree(string);
+ string = NULL;
+ }
+ else if (!strcmp(keyword, "PaperDimension"))
+ {
+ if ((size = ppdPageSize(ppd, name)) == NULL)
+ size = ppd_add_size(ppd, name);
+
+ if (size == NULL)
+ {
+ /*
+ * Unable to add or find size!
+ */
+
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ size->width = (float)_cupsStrScand(string, &sptr, loc);
+ size->length = (float)_cupsStrScand(sptr, NULL, loc);
+
+ _cupsStrFree(string);
+ string = NULL;
+ }
+ else if (!strcmp(keyword, "ImageableArea"))
+ {
+ if ((size = ppdPageSize(ppd, name)) == NULL)
+ size = ppd_add_size(ppd, name);
+
+ if (size == NULL)
+ {
+ /*
+ * Unable to add or find size!
+ */
+
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ size->left = (float)_cupsStrScand(string, &sptr, loc);
+ size->bottom = (float)_cupsStrScand(sptr, &sptr, loc);
+ size->right = (float)_cupsStrScand(sptr, &sptr, loc);
+ size->top = (float)_cupsStrScand(sptr, NULL, loc);
+
+ _cupsStrFree(string);
+ string = NULL;
+ }
+ else if (option != NULL &&
+ (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
+ (PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
+ !strcmp(keyword, option->keyword))
+ {
+ DEBUG_printf(("2ppdOpen2: group=%p, subgroup=%p", group, subgroup));
+
+ if (!strcmp(keyword, "PageSize"))
+ {
+ /*
+ * Add a page size...
+ */
+
+ if (ppdPageSize(ppd, name) == NULL)
+ ppd_add_size(ppd, name);
+ }
+
+ /*
+ * Add the option choice...
+ */
+
+ if ((choice = ppd_add_choice(option, name)) == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ if (text[0])
+ cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
+ sizeof(choice->text), encoding);
+ else if (!strcmp(name, "True"))
+ strcpy(choice->text, _("Yes"));
+ else if (!strcmp(name, "False"))
+ strcpy(choice->text, _("No"));
+ else
+ strlcpy(choice->text, name, sizeof(choice->text));
+
+ if (option->section == PPD_ORDER_JCL)
+ ppd_decode(string); /* Decode quoted string */
+
+ choice->code = string;
+ string = NULL; /* Don't add as an attribute below */
+ }
+
+ /*
+ * Add remaining lines with keywords and string values as attributes...
+ */
+
+ if (string &&
+ (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
+ ppd_add_attr(ppd, keyword, name, text, string);
+ else
+ _cupsStrFree(string);
+ }
+
+ /*
+ * Check for a missing CloseGroup...
+ */
+
+ if (group && cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_MISSING_CLOSE_GROUP;
+ goto error;
+ }
+
+ ppd_free(line.buffer);
+
+ /*
+ * Reset language preferences...
+ */
+
+#ifdef DEBUG
+ if (!cupsFileEOF(fp))
+ DEBUG_printf(("1ppdOpen2: Premature EOF at %lu...\n",
+ (unsigned long)cupsFileTell(fp)));
+#endif /* DEBUG */
+
+ if (cg->ppd_status != PPD_OK)
+ {
+ /*
+ * Had an error reading the PPD file, cannot continue!
+ */
+
+ ppdClose(ppd);
+
+ return (NULL);
+ }
+
+ /*
+ * Create the sorted options array and set the option back-pointer for
+ * each choice and custom option...
+ */
+
+ ppd->options = cupsArrayNew2((cups_array_func_t)ppd_compare_options, NULL,
+ (cups_ahash_func_t)ppd_hash_option,
+ PPD_HASHSIZE);
+
+ for (i = ppd->num_groups, group = ppd->groups;
+ i > 0;
+ i --, group ++)
+ {
+ for (j = group->num_options, option = group->options;
+ j > 0;
+ j --, option ++)
+ {
+ ppd_coption_t *coption; /* Custom option */
+
+
+ cupsArrayAdd(ppd->options, option);
+
+ for (k = 0; k < option->num_choices; k ++)
+ option->choices[k].option = option;
+
+ if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
+ coption->option = option;
+ }
+ }
+
+ /*
+ * Create an array to track the marked choices...
+ */
+
+ ppd->marked = cupsArrayNew((cups_array_func_t)ppd_compare_choices, NULL);
+
+ /*
+ * Return the PPD file structure...
+ */
+
+ return (ppd);
+
+ /*
+ * Common exit point for errors to save code size...
+ */
+
+ error:
+
+ _cupsStrFree(string);
+ ppd_free(line.buffer);
+
+ ppdClose(ppd);
+
+ return (NULL);
+}
+
+
+/*
+ * 'ppdOpenFd()' - Read a PPD file into memory.
+ */
+
+ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
+ppdOpenFd(int fd) /* I - File to read from */
+{
+ cups_file_t *fp; /* CUPS file pointer */
+ ppd_file_t *ppd; /* PPD file record */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Global data */
+
+
+ /*
+ * Set the line number to 0...
+ */
+
+ cg->ppd_line = 0;
+
+ /*
+ * Range check input...
+ */
+
+ if (fd < 0)
+ {
+ cg->ppd_status = PPD_NULL_FILE;
+
+ return (NULL);
+ }
+
+ /*
+ * Try to open the file and parse it...
+ */
+
+ if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
+ {
+ ppd = ppdOpen2(fp);
+
+ cupsFileClose(fp);
+ }
+ else
+ {
+ cg->ppd_status = PPD_FILE_OPEN_ERROR;
+ ppd = NULL;
+ }
+
+ return (ppd);
+}
+
+
+/*
+ * 'ppdOpenFile()' - Read a PPD file into memory.
+ */
+
+ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
+ppdOpenFile(const char *filename) /* I - File to read from */
+{
+ cups_file_t *fp; /* File pointer */
+ ppd_file_t *ppd; /* PPD file record */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Global data */
+
+
+ /*
+ * Set the line number to 0...
+ */
+
+ cg->ppd_line = 0;
+
+ /*
+ * Range check input...
+ */
+
+ if (filename == NULL)
+ {
+ cg->ppd_status = PPD_NULL_FILE;
+
+ return (NULL);
+ }
+
+ /*
+ * Try to open the file and parse it...
+ */
+
+ if ((fp = cupsFileOpen(filename, "r")) != NULL)
+ {
+ ppd = ppdOpen2(fp);
+
+ cupsFileClose(fp);
+ }
+ else
+ {
+ cg->ppd_status = PPD_FILE_OPEN_ERROR;
+ ppd = NULL;
+ }
+
+ return (ppd);
+}
+
+
+/*
+ * 'ppdSetConformance()' - Set the conformance level for PPD files.
+ *
+ * @since CUPS 1.1.20/Mac OS X 10.4@
+ */
+
+void
+ppdSetConformance(ppd_conform_t c) /* I - Conformance level */
+{
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Global data */
+
+
+ cg->ppd_conform = c;
+}
+
+
+/*
+ * 'ppd_add_attr()' - Add an attribute to the PPD data.
+ */
+
+static ppd_attr_t * /* O - New attribute */
+ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */
+ const char *name, /* I - Attribute name */
+ const char *spec, /* I - Specifier string, if any */
+ const char *text, /* I - Text string, if any */
+ const char *value) /* I - Value of attribute */
+{
+ ppd_attr_t **ptr, /* New array */
+ *temp; /* New attribute */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (ppd == NULL || name == NULL || spec == NULL)
+ return (NULL);
+
+ /*
+ * Create the array as needed...
+ */
+
+ if (!ppd->sorted_attrs)
+ ppd->sorted_attrs = cupsArrayNew((cups_array_func_t)ppd_compare_attrs,
+ NULL);
+
+ /*
+ * Allocate memory for the new attribute...
+ */
+
+ if (ppd->num_attrs == 0)
+ ptr = malloc(sizeof(ppd_attr_t *));
+ else
+ ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
+
+ if (ptr == NULL)
+ return (NULL);
+
+ ppd->attrs = ptr;
+ ptr += ppd->num_attrs;
+
+ if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
+ return (NULL);
+
+ *ptr = temp;
+
+ ppd->num_attrs ++;
+
+ /*
+ * Copy data over...
+ */
+
+ strlcpy(temp->name, name, sizeof(temp->name));
+ strlcpy(temp->spec, spec, sizeof(temp->spec));
+ strlcpy(temp->text, text, sizeof(temp->text));
+ temp->value = (char *)value;
+
+ /*
+ * Add the attribute to the sorted array...
+ */
+
+ cupsArrayAdd(ppd->sorted_attrs, temp);
+
+ /*
+ * Return the attribute...
+ */
+
+ return (temp);
+}
+
+
+/*
+ * 'ppd_add_choice()' - Add a choice to an option.
+ */
+
+static ppd_choice_t * /* O - Named choice */
+ppd_add_choice(ppd_option_t *option, /* I - Option */
+ const char *name) /* I - Name of choice */
+{
+ ppd_choice_t *choice; /* Choice */
+
+
+ if (option->num_choices == 0)
+ choice = malloc(sizeof(ppd_choice_t));
+ else
+ choice = realloc(option->choices,
+ sizeof(ppd_choice_t) * (option->num_choices + 1));
+
+ if (choice == NULL)
+ return (NULL);
+
+ option->choices = choice;
+ choice += option->num_choices;
+ option->num_choices ++;
+
+ memset(choice, 0, sizeof(ppd_choice_t));
+ strlcpy(choice->choice, name, sizeof(choice->choice));
+
+ return (choice);
+}
+
+
+/*
+ * 'ppd_add_size()' - Add a page size.
+ */
+
+static ppd_size_t * /* O - Named size */
+ppd_add_size(ppd_file_t *ppd, /* I - PPD file */
+ const char *name) /* I - Name of size */
+{
+ ppd_size_t *size; /* Size */
+
+
+ if (ppd->num_sizes == 0)
+ size = malloc(sizeof(ppd_size_t));
+ else
+ size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
+
+ if (size == NULL)
+ return (NULL);
+
+ ppd->sizes = size;
+ size += ppd->num_sizes;
+ ppd->num_sizes ++;
+
+ memset(size, 0, sizeof(ppd_size_t));
+ strlcpy(size->name, name, sizeof(size->name));
+
+ return (size);
+}
+
+
+/*
+ * 'ppd_compare_attrs()' - Compare two attributes.
+ */
+
+static int /* O - Result of comparison */
+ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
+ ppd_attr_t *b) /* I - Second attribute */
+{
+ return (_cups_strcasecmp(a->name, b->name));
+}
+
+
+/*
+ * 'ppd_compare_choices()' - Compare two choices...
+ */
+
+static int /* O - Result of comparison */
+ppd_compare_choices(ppd_choice_t *a, /* I - First choice */
+ ppd_choice_t *b) /* I - Second choice */
+{
+ return (strcmp(a->option->keyword, b->option->keyword));
+}
+
+
+/*
+ * 'ppd_compare_coptions()' - Compare two custom options.
+ */
+
+static int /* O - Result of comparison */
+ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
+ ppd_coption_t *b) /* I - Second option */
+{
+ return (_cups_strcasecmp(a->keyword, b->keyword));
+}
+
+
+/*
+ * 'ppd_compare_options()' - Compare two options.
+ */
+
+static int /* O - Result of comparison */
+ppd_compare_options(ppd_option_t *a, /* I - First option */
+ ppd_option_t *b) /* I - Second option */
+{
+ return (_cups_strcasecmp(a->keyword, b->keyword));
+}
+
+
+/*
+ * 'ppd_decode()' - Decode a string value...
+ */
+
+static int /* O - Length of decoded string */
+ppd_decode(char *string) /* I - String to decode */
+{
+ char *inptr, /* Input pointer */
+ *outptr; /* Output pointer */
+
+
+ inptr = string;
+ outptr = string;
+
+ while (*inptr != '\0')
+ if (*inptr == '<' && isxdigit(inptr[1] & 255))
+ {
+ /*
+ * Convert hex to 8-bit values...
+ */
+
+ inptr ++;
+ while (isxdigit(*inptr & 255))
+ {
+ if (_cups_isalpha(*inptr))
+ *outptr = (tolower(*inptr) - 'a' + 10) << 4;
+ else
+ *outptr = (*inptr - '0') << 4;
+
+ inptr ++;
+
+ if (!isxdigit(*inptr & 255))
+ break;
+
+ if (_cups_isalpha(*inptr))
+ *outptr |= tolower(*inptr) - 'a' + 10;
+ else
+ *outptr |= *inptr - '0';
+
+ inptr ++;
+ outptr ++;
+ }
+
+ while (*inptr != '>' && *inptr != '\0')
+ inptr ++;
+ while (*inptr == '>')
+ inptr ++;
+ }
+ else
+ *outptr++ = *inptr++;
+
+ *outptr = '\0';
+
+ return ((int)(outptr - string));
+}
+
+
+/*
+ * 'ppd_free_group()' - Free a single UI group.
+ */
+
+static void
+ppd_free_group(ppd_group_t *group) /* I - Group to free */
+{
+ int i; /* Looping var */
+ ppd_option_t *option; /* Current option */
+ ppd_group_t *subgroup; /* Current sub-group */
+
+
+ if (group->num_options > 0)
+ {
+ for (i = group->num_options, option = group->options;
+ i > 0;
+ i --, option ++)
+ ppd_free_option(option);
+
+ ppd_free(group->options);
+ }
+
+ if (group->num_subgroups > 0)
+ {
+ for (i = group->num_subgroups, subgroup = group->subgroups;
+ i > 0;
+ i --, subgroup ++)
+ ppd_free_group(subgroup);
+
+ ppd_free(group->subgroups);
+ }
+}
+
+
+/*
+ * 'ppd_free_option()' - Free a single option.
+ */
+
+static void
+ppd_free_option(ppd_option_t *option) /* I - Option to free */
+{
+ int i; /* Looping var */
+ ppd_choice_t *choice; /* Current choice */
+
+
+ if (option->num_choices > 0)
+ {
+ for (i = option->num_choices, choice = option->choices;
+ i > 0;
+ i --, choice ++)
+ {
+ _cupsStrFree(choice->code);
+ }
+
+ ppd_free(option->choices);
+ }
+}
+
+
+/*
+ * 'ppd_get_coption()' - Get a custom option record.
+ */
+
+static ppd_coption_t * /* O - Custom option... */
+ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */
+ const char *name) /* I - Name of option */
+{
+ ppd_coption_t *copt; /* New custom option */
+
+
+ /*
+ * See if the option already exists...
+ */
+
+ if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
+ return (copt);
+
+ /*
+ * Not found, so create the custom option record...
+ */
+
+ if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
+ return (NULL);
+
+ strlcpy(copt->keyword, name, sizeof(copt->keyword));
+
+ copt->params = cupsArrayNew((cups_array_func_t)NULL, NULL);
+
+ cupsArrayAdd(ppd->coptions, copt);
+
+ /*
+ * Return the new record...
+ */
+
+ return (copt);
+}
+
+
+/*
+ * 'ppd_get_cparam()' - Get a custom parameter record.
+ */
+
+static ppd_cparam_t * /* O - Extended option... */
+ppd_get_cparam(ppd_coption_t *opt, /* I - PPD file */
+ const char *param, /* I - Name of parameter */
+ const char *text) /* I - Human-readable text */
+{
+ ppd_cparam_t *cparam; /* New custom parameter */
+
+
+ /*
+ * See if the parameter already exists...
+ */
+
+ if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
+ return (cparam);
+
+ /*
+ * Not found, so create the custom parameter record...
+ */
+
+ if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
+ return (NULL);
+
+ strlcpy(cparam->name, param, sizeof(cparam->name));
+ strlcpy(cparam->text, text[0] ? text : param, sizeof(cparam->text));
+
+ /*
+ * Add this record to the array...
+ */
+
+ cupsArrayAdd(opt->params, cparam);
+
+ /*
+ * Return the new record...
+ */
+
+ return (cparam);
+}
+
+
+/*
+ * 'ppd_get_group()' - Find or create the named group as needed.
+ */
+
+static ppd_group_t * /* O - Named group */
+ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
+ const char *name, /* I - Name of group */
+ const char *text, /* I - Text for group */
+ _cups_globals_t *cg, /* I - Global data */
+ cups_encoding_t encoding) /* I - Encoding of text */
+{
+ int i; /* Looping var */
+ ppd_group_t *group; /* Group */
+
+
+ DEBUG_printf(("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)",
+ ppd, name, text, cg));
+
+ for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
+ if (!strcmp(group->name, name))
+ break;
+
+ if (i == 0)
+ {
+ DEBUG_printf(("8ppd_get_group: Adding group %s...", name));
+
+ if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
+ {
+ cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
+
+ return (NULL);
+ }
+
+ if (ppd->num_groups == 0)
+ group = malloc(sizeof(ppd_group_t));
+ else
+ group = realloc(ppd->groups,
+ (ppd->num_groups + 1) * sizeof(ppd_group_t));
+
+ if (group == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ return (NULL);
+ }
+
+ ppd->groups = group;
+ group += ppd->num_groups;
+ ppd->num_groups ++;
+
+ memset(group, 0, sizeof(ppd_group_t));
+ strlcpy(group->name, name, sizeof(group->name));
+
+ cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
+ sizeof(group->text), encoding);
+ }
+
+ return (group);
+}
+
+
+/*
+ * 'ppd_get_option()' - Find or create the named option as needed.
+ */
+
+static ppd_option_t * /* O - Named option */
+ppd_get_option(ppd_group_t *group, /* I - Group */
+ const char *name) /* I - Name of option */
+{
+ int i; /* Looping var */
+ ppd_option_t *option; /* Option */
+
+
+ DEBUG_printf(("7ppd_get_option(group=%p(\"%s\"), name=\"%s\")",
+ group, group->name, name));
+
+ for (i = group->num_options, option = group->options; i > 0; i --, option ++)
+ if (!strcmp(option->keyword, name))
+ break;
+
+ if (i == 0)
+ {
+ if (group->num_options == 0)
+ option = malloc(sizeof(ppd_option_t));
+ else
+ option = realloc(group->options,
+ (group->num_options + 1) * sizeof(ppd_option_t));
+
+ if (option == NULL)
+ return (NULL);
+
+ group->options = option;
+ option += group->num_options;
+ group->num_options ++;
+
+ memset(option, 0, sizeof(ppd_option_t));
+ strlcpy(option->keyword, name, sizeof(option->keyword));
+ }
+
+ return (option);
+}
+
+
+/*
+ * 'ppd_hash_option()' - Generate a hash of the option name...
+ */
+
+static int /* O - Hash index */
+ppd_hash_option(ppd_option_t *option) /* I - Option */
+{
+ int hash = 0; /* Hash index */
+ const char *k; /* Pointer into keyword */
+
+
+ for (hash = option->keyword[0], k = option->keyword + 1; *k;)
+ hash = 33 * hash + *k++;
+
+ return (hash & 511);
+}
+
+
+/*
+ * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
+ * necessary.
+ */
+
+static int /* O - Bitmask of fields read */
+ppd_read(cups_file_t *fp, /* I - File to read from */
+ _ppd_line_t *line, /* I - Line buffer */
+ char *keyword, /* O - Keyword from line */
+ char *option, /* O - Option from line */
+ char *text, /* O - Human-readable text from line */
+ char **string, /* O - Code/string data */
+ int ignoreblank, /* I - Ignore blank lines? */
+ _cups_globals_t *cg) /* I - Global data */
+{
+ int ch, /* Character from file */
+ col, /* Column in line */
+ colon, /* Colon seen? */
+ endquote, /* Waiting for an end quote */
+ mask, /* Mask to be returned */
+ startline, /* Start line */
+ textlen; /* Length of text */
+ char *keyptr, /* Keyword pointer */
+ *optptr, /* Option pointer */
+ *textptr, /* Text pointer */
+ *strptr, /* Pointer into string */
+ *lineptr; /* Current position in line buffer */
+
+
+ /*
+ * Now loop until we have a valid line...
+ */
+
+ *string = NULL;
+ col = 0;
+ startline = cg->ppd_line + 1;
+
+ if (!line->buffer)
+ {
+ line->bufsize = 1024;
+ line->buffer = malloc(1024);
+
+ if (!line->buffer)
+ return (0);
+ }
+
+ do
+ {
+ /*
+ * Read the line...
+ */
+
+ lineptr = line->buffer;
+ endquote = 0;
+ colon = 0;
+
+ while ((ch = cupsFileGetChar(fp)) != EOF)
+ {
+ if (lineptr >= (line->buffer + line->bufsize - 1))
+ {
+ /*
+ * Expand the line buffer...
+ */
+
+ char *temp; /* Temporary line pointer */
+
+
+ line->bufsize += 1024;
+ if (line->bufsize > 262144)
+ {
+ /*
+ * Don't allow lines longer than 256k!
+ */
+
+ cg->ppd_line = startline;
+ cg->ppd_status = PPD_LINE_TOO_LONG;
+
+ return (0);
+ }
+
+ temp = realloc(line->buffer, line->bufsize);
+ if (!temp)
+ {
+ cg->ppd_line = startline;
+ cg->ppd_status = PPD_LINE_TOO_LONG;
+
+ return (0);
+ }
+
+ lineptr = temp + (lineptr - line->buffer);
+ line->buffer = temp;
+ }
+
+ if (ch == '\r' || ch == '\n')
+ {
+ /*
+ * Line feed or carriage return...
+ */
+
+ cg->ppd_line ++;
+ col = 0;
+
+ if (ch == '\r')
+ {
+ /*
+ * Check for a trailing line feed...
+ */
+
+ if ((ch = cupsFilePeekChar(fp)) == EOF)
+ {
+ ch = '\n';
+ break;
+ }
+
+ if (ch == 0x0a)
+ cupsFileGetChar(fp);
+ }
+
+ if (lineptr == line->buffer && ignoreblank)
+ continue; /* Skip blank lines */
+
+ ch = '\n';
+
+ if (!endquote) /* Continue for multi-line text */
+ break;
+
+ *lineptr++ = '\n';
+ }
+ else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ /*
+ * Other control characters...
+ */
+
+ cg->ppd_line = startline;
+ cg->ppd_status = PPD_ILLEGAL_CHARACTER;
+
+ return (0);
+ }
+ else if (ch != 0x1a)
+ {
+ /*
+ * Any other character...
+ */
+
+ *lineptr++ = ch;
+ col ++;
+
+ if (col > (PPD_MAX_LINE - 1))
+ {
+ /*
+ * Line is too long...
+ */
+
+ cg->ppd_line = startline;
+ cg->ppd_status = PPD_LINE_TOO_LONG;
+
+ return (0);
+ }
+
+ if (ch == ':' && strncmp(line->buffer, "*%", 2) != 0)
+ colon = 1;
+
+ if (ch == '\"' && colon)
+ endquote = !endquote;
+ }
+ }
+
+ if (endquote)
+ {
+ /*
+ * Didn't finish this quoted string...
+ */
+
+ while ((ch = cupsFileGetChar(fp)) != EOF)
+ if (ch == '\"')
+ break;
+ else if (ch == '\r' || ch == '\n')
+ {
+ cg->ppd_line ++;
+ col = 0;
+
+ if (ch == '\r')
+ {
+ /*
+ * Check for a trailing line feed...
+ */
+
+ if ((ch = cupsFilePeekChar(fp)) == EOF)
+ break;
+ if (ch == 0x0a)
+ cupsFileGetChar(fp);
+ }
+ }
+ else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ /*
+ * Other control characters...
+ */
+
+ cg->ppd_line = startline;
+ cg->ppd_status = PPD_ILLEGAL_CHARACTER;
+
+ return (0);
+ }
+ else if (ch != 0x1a)
+ {
+ col ++;
+
+ if (col > (PPD_MAX_LINE - 1))
+ {
+ /*
+ * Line is too long...
+ */
+
+ cg->ppd_line = startline;
+ cg->ppd_status = PPD_LINE_TOO_LONG;
+
+ return (0);
+ }
+ }
+ }
+
+ if (ch != '\n')
+ {
+ /*
+ * Didn't finish this line...
+ */
+
+ while ((ch = cupsFileGetChar(fp)) != EOF)
+ if (ch == '\r' || ch == '\n')
+ {
+ /*
+ * Line feed or carriage return...
+ */
+
+ cg->ppd_line ++;
+ col = 0;
+
+ if (ch == '\r')
+ {
+ /*
+ * Check for a trailing line feed...
+ */
+
+ if ((ch = cupsFilePeekChar(fp)) == EOF)
+ break;
+ if (ch == 0x0a)
+ cupsFileGetChar(fp);
+ }
+
+ break;
+ }
+ else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ /*
+ * Other control characters...
+ */
+
+ cg->ppd_line = startline;
+ cg->ppd_status = PPD_ILLEGAL_CHARACTER;
+
+ return (0);
+ }
+ else if (ch != 0x1a)
+ {
+ col ++;
+
+ if (col > (PPD_MAX_LINE - 1))
+ {
+ /*
+ * Line is too long...
+ */
+
+ cg->ppd_line = startline;
+ cg->ppd_status = PPD_LINE_TOO_LONG;
+
+ return (0);
+ }
+ }
+ }
+
+ if (lineptr > line->buffer && lineptr[-1] == '\n')
+ lineptr --;
+
+ *lineptr = '\0';
+
+ DEBUG_printf(("9ppd_read: LINE=\"%s\"", line->buffer));
+
+ /*
+ * The dynamically created PPDs for older style Mac OS X
+ * drivers include a large blob of data inserted as comments
+ * at the end of the file. As an optimization we can stop
+ * reading the PPD when we get to the start of this data.
+ */
+
+ if (!strcmp(line->buffer, "*%APLWORKSET START"))
+ return (0);
+
+ if (ch == EOF && lineptr == line->buffer)
+ return (0);
+
+ /*
+ * Now parse it...
+ */
+
+ mask = 0;
+ lineptr = line->buffer + 1;
+
+ keyword[0] = '\0';
+ option[0] = '\0';
+ text[0] = '\0';
+ *string = NULL;
+
+ if ((!line->buffer[0] || /* Blank line */
+ !strncmp(line->buffer, "*%", 2) || /* Comment line */
+ !strcmp(line->buffer, "*End")) && /* End of multi-line string */
+ ignoreblank) /* Ignore these? */
+ {
+ startline = cg->ppd_line + 1;
+ continue;
+ }
+
+ if (!strcmp(line->buffer, "*")) /* (Bad) comment line */
+ {
+ if (cg->ppd_conform == PPD_CONFORM_RELAXED)
+ {
+ startline = cg->ppd_line + 1;
+ continue;
+ }
+ else
+ {
+ cg->ppd_line = startline;
+ cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
+
+ return (0);
+ }
+ }
+
+ if (line->buffer[0] != '*') /* All lines start with an asterisk */
+ {
+ /*
+ * Allow lines consisting of just whitespace...
+ */
+
+ for (lineptr = line->buffer; *lineptr; lineptr ++)
+ if (*lineptr && !_cups_isspace(*lineptr))
+ break;
+
+ if (*lineptr)
+ {
+ cg->ppd_status = PPD_MISSING_ASTERISK;
+ return (0);
+ }
+ else if (ignoreblank)
+ continue;
+ else
+ return (0);
+ }
+
+ /*
+ * Get a keyword...
+ */
+
+ keyptr = keyword;
+
+ while (*lineptr && *lineptr != ':' && !_cups_isspace(*lineptr))
+ {
+ if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
+ (keyptr - keyword) >= (PPD_MAX_NAME - 1))
+ {
+ cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
+ return (0);
+ }
+
+ *keyptr++ = *lineptr++;
+ }
+
+ *keyptr = '\0';
+
+ if (!strcmp(keyword, "End"))
+ continue;
+
+ mask |= PPD_KEYWORD;
+
+ if (_cups_isspace(*lineptr))
+ {
+ /*
+ * Get an option name...
+ */
+
+ while (_cups_isspace(*lineptr))
+ lineptr ++;
+
+ optptr = option;
+
+ while (*lineptr && !_cups_isspace(*lineptr) && *lineptr != ':' &&
+ *lineptr != '/')
+ {
+ if (*lineptr <= ' ' || *lineptr > 126 ||
+ (optptr - option) >= (PPD_MAX_NAME - 1))
+ {
+ cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
+ return (0);
+ }
+
+ *optptr++ = *lineptr++;
+ }
+
+ *optptr = '\0';
+
+ if (_cups_isspace(*lineptr) && cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
+ return (0);
+ }
+
+ while (_cups_isspace(*lineptr))
+ lineptr ++;
+
+ mask |= PPD_OPTION;
+
+ if (*lineptr == '/')
+ {
+ /*
+ * Get human-readable text...
+ */
+
+ lineptr ++;
+
+ textptr = text;
+
+ while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
+ {
+ if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
+ (textptr - text) >= (PPD_MAX_LINE - 1))
+ {
+ cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
+ return (0);
+ }
+
+ *textptr++ = *lineptr++;
+ }
+
+ *textptr = '\0';
+ textlen = ppd_decode(text);
+
+ if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
+ return (0);
+ }
+
+ mask |= PPD_TEXT;
+ }
+ }
+
+ if (_cups_isspace(*lineptr) && cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
+ return (0);
+ }
+
+ while (_cups_isspace(*lineptr))
+ lineptr ++;
+
+ if (*lineptr == ':')
+ {
+ /*
+ * Get string after triming leading and trailing whitespace...
+ */
+
+ lineptr ++;
+ while (_cups_isspace(*lineptr))
+ lineptr ++;
+
+ strptr = lineptr + strlen(lineptr) - 1;
+ while (strptr >= lineptr && _cups_isspace(*strptr))
+ *strptr-- = '\0';
+
+ if (*strptr == '\"')
+ {
+ /*
+ * Quoted string by itself, remove quotes...
+ */
+
+ *strptr = '\0';
+ lineptr ++;
+ }
+
+ *string = _cupsStrAlloc(lineptr);
+
+ mask |= PPD_STRING;
+ }
+ }
+ while (mask == 0);
+
+ return (mask);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/ppd.h b/cups/ppd.h
new file mode 100644
index 000000000..1aaa139bc
--- /dev/null
+++ b/cups/ppd.h
@@ -0,0 +1,450 @@
+/*
+ * "$Id$"
+ *
+ * PostScript Printer Description definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * PostScript is a trademark of Adobe Systems, Inc.
+ *
+ * This code and any derivative of it may be used and distributed
+ * freely under the terms of the GNU General Public License when
+ * used with GNU Ghostscript or its derivatives. Use of the code
+ * (or any derivative of it) with software other than GNU
+ * GhostScript (or its derivatives) is governed by the CUPS license
+ * agreement.
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_PPD_H_
+# define _CUPS_PPD_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include <stdio.h>
+# include "cups.h"
+# include "array.h"
+# include "file.h"
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * PPD version...
+ */
+
+# define PPD_VERSION 4.3 /* Kept in sync with Adobe version number */
+
+
+/*
+ * PPD size limits (defined in Adobe spec)
+ */
+
+# define PPD_MAX_NAME 41 /* Maximum size of name + 1 for nul */
+# define PPD_MAX_TEXT 81 /* Maximum size of text + 1 for nul */
+# define PPD_MAX_LINE 256 /* Maximum size of line + 1 for nul */
+
+
+/*
+ * Types and structures...
+ */
+
+typedef enum ppd_ui_e /**** UI Types ****/
+{
+ PPD_UI_BOOLEAN, /* True or False option */
+ PPD_UI_PICKONE, /* Pick one from a list */
+ PPD_UI_PICKMANY /* Pick zero or more from a list */
+} ppd_ui_t;
+
+typedef enum ppd_section_e /**** Order dependency sections ****/
+{
+ PPD_ORDER_ANY, /* Option code can be anywhere in the file */
+ PPD_ORDER_DOCUMENT, /* ... must be in the DocumentSetup section */
+ PPD_ORDER_EXIT, /* ... must be sent prior to the document */
+ PPD_ORDER_JCL, /* ... must be sent as a JCL command */
+ PPD_ORDER_PAGE, /* ... must be in the PageSetup section */
+ PPD_ORDER_PROLOG /* ... must be in the Prolog section */
+} ppd_section_t;
+
+typedef enum ppd_cs_e /**** Colorspaces ****/
+{
+ PPD_CS_CMYK = -4, /* CMYK colorspace */
+ PPD_CS_CMY, /* CMY colorspace */
+ PPD_CS_GRAY = 1, /* Grayscale colorspace */
+ PPD_CS_RGB = 3, /* RGB colorspace */
+ PPD_CS_RGBK, /* RGBK (K = gray) colorspace */
+ PPD_CS_N /* DeviceN colorspace */
+} ppd_cs_t;
+
+typedef enum ppd_status_e /**** Status Codes @since CUPS 1.1.19/Mac OS X 10.3@ ****/
+{
+ PPD_OK = 0, /* OK */
+ PPD_FILE_OPEN_ERROR, /* Unable to open PPD file */
+ PPD_NULL_FILE, /* NULL PPD file pointer */
+ PPD_ALLOC_ERROR, /* Memory allocation error */
+ PPD_MISSING_PPDADOBE4, /* Missing PPD-Adobe-4.x header */
+ PPD_MISSING_VALUE, /* Missing value string */
+ PPD_INTERNAL_ERROR, /* Internal error */
+ PPD_BAD_OPEN_GROUP, /* Bad OpenGroup */
+ PPD_NESTED_OPEN_GROUP, /* OpenGroup without a CloseGroup first */
+ PPD_BAD_OPEN_UI, /* Bad OpenUI/JCLOpenUI */
+ PPD_NESTED_OPEN_UI, /* OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first */
+ PPD_BAD_ORDER_DEPENDENCY, /* Bad OrderDependency */
+ PPD_BAD_UI_CONSTRAINTS, /* Bad UIConstraints */
+ PPD_MISSING_ASTERISK, /* Missing asterisk in column 0 */
+ PPD_LINE_TOO_LONG, /* Line longer than 255 chars */
+ PPD_ILLEGAL_CHARACTER, /* Illegal control character */
+ PPD_ILLEGAL_MAIN_KEYWORD, /* Illegal main keyword string */
+ PPD_ILLEGAL_OPTION_KEYWORD, /* Illegal option keyword string */
+ PPD_ILLEGAL_TRANSLATION, /* Illegal translation string */
+ PPD_ILLEGAL_WHITESPACE, /* Illegal whitespace character */
+ PPD_BAD_CUSTOM_PARAM, /* Bad custom parameter */
+ PPD_MISSING_OPTION_KEYWORD, /* Missing option keyword */
+ PPD_BAD_VALUE, /* Bad value string */
+ PPD_MISSING_CLOSE_GROUP, /* Missing CloseGroup */
+ PPD_MAX_STATUS /* @private@ */
+} ppd_status_t;
+
+enum ppd_conform_e /**** Conformance Levels @since CUPS 1.1.19/Mac OS X 10.3@ ****/
+{
+ PPD_CONFORM_RELAXED, /* Relax whitespace and control char */
+ PPD_CONFORM_STRICT /* Require strict conformance */
+};
+
+typedef enum ppd_conform_e ppd_conform_t;
+ /**** Conformance Levels @since CUPS 1.1.19/Mac OS X 10.3@ ****/
+
+typedef struct ppd_attr_s /**** PPD Attribute Structure @since CUPS 1.1.19/Mac OS X 10.3@ ****/
+{
+ char name[PPD_MAX_NAME]; /* Name of attribute (cupsXYZ) */
+ char spec[PPD_MAX_NAME]; /* Specifier string, if any */
+ char text[PPD_MAX_TEXT]; /* Human-readable text, if any */
+ char *value; /* Value string */
+} ppd_attr_t;
+
+typedef struct ppd_option_s ppd_option_t;
+ /**** Options ****/
+
+typedef struct ppd_choice_s /**** Option choices ****/
+{
+ char marked; /* 0 if not selected, 1 otherwise */
+ char choice[PPD_MAX_NAME]; /* Computer-readable option name */
+ char text[PPD_MAX_TEXT]; /* Human-readable option name */
+ char *code; /* Code to send for this option */
+ ppd_option_t *option; /* Pointer to parent option structure */
+} ppd_choice_t;
+
+struct ppd_option_s /**** Options ****/
+{
+ char conflicted; /* 0 if no conflicts exist, 1 otherwise */
+ char keyword[PPD_MAX_NAME]; /* Option keyword name ("PageSize", etc.) */
+ char defchoice[PPD_MAX_NAME];/* Default option choice */
+ char text[PPD_MAX_TEXT]; /* Human-readable text */
+ ppd_ui_t ui; /* Type of UI option */
+ ppd_section_t section; /* Section for command */
+ float order; /* Order number */
+ int num_choices; /* Number of option choices */
+ ppd_choice_t *choices; /* Option choices */
+};
+
+typedef struct ppd_group_s /**** Groups ****/
+{
+ /**** Group text strings are limited to 39 chars + nul in order to
+ **** preserve binary compatibility and allow applications to get
+ **** the group's keyword name.
+ ****/
+ char text[PPD_MAX_TEXT - PPD_MAX_NAME];
+ /* Human-readable group name */
+ char name[PPD_MAX_NAME]; /* Group name @since CUPS 1.1.18/Mac OS X 10.3@ */
+ int num_options; /* Number of options */
+ ppd_option_t *options; /* Options */
+ int num_subgroups; /* Number of sub-groups */
+ struct ppd_group_s *subgroups; /* Sub-groups (max depth = 1) */
+} ppd_group_t;
+
+typedef struct ppd_const_s /**** Constraints ****/
+{
+ char option1[PPD_MAX_NAME]; /* First keyword */
+ char choice1[PPD_MAX_NAME]; /* First option/choice (blank for all) */
+ char option2[PPD_MAX_NAME]; /* Second keyword */
+ char choice2[PPD_MAX_NAME]; /* Second option/choice (blank for all) */
+} ppd_const_t;
+
+typedef struct ppd_size_s /**** Page Sizes ****/
+{
+ int marked; /* Page size selected? */
+ char name[PPD_MAX_NAME]; /* Media size option */
+ float width; /* Width of media in points */
+ float length; /* Length of media in points */
+ float left; /* Left printable margin in points */
+ float bottom; /* Bottom printable margin in points */
+ float right; /* Right printable margin in points */
+ float top; /* Top printable margin in points */
+} ppd_size_t;
+
+typedef struct ppd_emul_s /**** Emulators ****/
+{
+ char name[PPD_MAX_NAME]; /* Emulator name */
+ char *start; /* Code to switch to this emulation */
+ char *stop; /* Code to stop this emulation */
+} ppd_emul_t;
+
+typedef struct ppd_profile_s /**** sRGB Color Profiles ****/
+{
+ char resolution[PPD_MAX_NAME];
+ /* Resolution or "-" */
+ char media_type[PPD_MAX_NAME];
+ /* Media type or "-" */
+ float density; /* Ink density to use */
+ float gamma; /* Gamma correction to use */
+ float matrix[3][3]; /* Transform matrix */
+} ppd_profile_t;
+
+/**** New in CUPS 1.2/Mac OS X 10.5 ****/
+typedef enum ppd_cptype_e /**** Custom Parameter Type @since CUPS 1.2/Mac OS X 10.5@ ****/
+{
+ PPD_CUSTOM_CURVE, /* Curve value for f(x) = x^value */
+ PPD_CUSTOM_INT, /* Integer number value */
+ PPD_CUSTOM_INVCURVE, /* Curve value for f(x) = x^(1/value) */
+ PPD_CUSTOM_PASSCODE, /* String of (hidden) numbers */
+ PPD_CUSTOM_PASSWORD, /* String of (hidden) characters */
+ PPD_CUSTOM_POINTS, /* Measurement value in points */
+ PPD_CUSTOM_REAL, /* Real number value */
+ PPD_CUSTOM_STRING /* String of characters */
+} ppd_cptype_t;
+
+typedef union ppd_cplimit_u /**** Custom Parameter Limit @since CUPS 1.2/Mac OS X 10.5@ ****/
+{
+ float custom_curve; /* Gamma value */
+ int custom_int; /* Integer value */
+ float custom_invcurve; /* Gamma value */
+ int custom_passcode; /* Passcode length */
+ int custom_password; /* Password length */
+ float custom_points; /* Measurement value */
+ float custom_real; /* Real value */
+ int custom_string; /* String length */
+} ppd_cplimit_t;
+
+typedef union ppd_cpvalue_u /**** Custom Parameter Value @since CUPS 1.2/Mac OS X 10.5@ ****/
+{
+ float custom_curve; /* Gamma value */
+ int custom_int; /* Integer value */
+ float custom_invcurve; /* Gamma value */
+ char *custom_passcode; /* Passcode value */
+ char *custom_password; /* Password value */
+ float custom_points; /* Measurement value */
+ float custom_real; /* Real value */
+ char *custom_string; /* String value */
+} ppd_cpvalue_t;
+
+typedef struct ppd_cparam_s /**** Custom Parameter @since CUPS 1.2/Mac OS X 10.5@ ****/
+{
+ char name[PPD_MAX_NAME]; /* Parameter name */
+ char text[PPD_MAX_TEXT]; /* Human-readable text */
+ int order; /* Order (0 to N) */
+ ppd_cptype_t type; /* Parameter type */
+ ppd_cplimit_t minimum, /* Minimum value */
+ maximum; /* Maximum value */
+ ppd_cpvalue_t current; /* Current value */
+} ppd_cparam_t;
+
+typedef struct ppd_coption_s /**** Custom Option @since CUPS 1.2/Mac OS X 10.5@ ****/
+{
+ char keyword[PPD_MAX_NAME]; /* Name of option that is being extended... */
+ ppd_option_t *option; /* Option that is being extended... */
+ int marked; /* Extended option is marked */
+ cups_array_t *params; /* Parameters */
+} ppd_coption_t;
+
+typedef struct _ppd_cache_s _ppd_cache_t;
+ /**** PPD cache and mapping data @since CUPS 1.5/Mac OS X 10.7@ @private@ ****/
+
+typedef struct ppd_file_s /**** PPD File ****/
+{
+ int language_level; /* Language level of device */
+ int color_device; /* 1 = color device, 0 = grayscale */
+ int variable_sizes; /* 1 = supports variable sizes, 0 = doesn't */
+ int accurate_screens; /* 1 = supports accurate screens, 0 = not */
+ int contone_only; /* 1 = continuous tone only, 0 = not */
+ int landscape; /* -90 or 90 */
+ int model_number; /* Device-specific model number */
+ int manual_copies; /* 1 = Copies done manually, 0 = hardware */
+ int throughput; /* Pages per minute */
+ ppd_cs_t colorspace; /* Default colorspace */
+ char *patches; /* Patch commands to be sent to printer */
+ int num_emulations; /* Number of emulations supported */
+ ppd_emul_t *emulations; /* Emulations and the code to invoke them */
+ char *jcl_begin; /* Start JCL commands */
+ char *jcl_ps; /* Enter PostScript interpreter */
+ char *jcl_end; /* End JCL commands */
+ char *lang_encoding; /* Language encoding */
+ char *lang_version; /* Language version (English, Spanish, etc.) */
+ char *modelname; /* Model name (general) */
+ char *ttrasterizer; /* Truetype rasterizer */
+ char *manufacturer; /* Manufacturer name */
+ char *product; /* Product name (from PS RIP/interpreter) */
+ char *nickname; /* Nickname (specific) */
+ char *shortnickname; /* Short version of nickname */
+ int num_groups; /* Number of UI groups */
+ ppd_group_t *groups; /* UI groups */
+ int num_sizes; /* Number of page sizes */
+ ppd_size_t *sizes; /* Page sizes */
+ float custom_min[2]; /* Minimum variable page size */
+ float custom_max[2]; /* Maximum variable page size */
+ float custom_margins[4]; /* Margins around page */
+ int num_consts; /* Number of UI/Non-UI constraints */
+ ppd_const_t *consts; /* UI/Non-UI constraints */
+ int num_fonts; /* Number of pre-loaded fonts */
+ char **fonts; /* Pre-loaded fonts */
+ int num_profiles; /* Number of sRGB color profiles @deprecated@ */
+ ppd_profile_t *profiles; /* sRGB color profiles @deprecated@ */
+ int num_filters; /* Number of filters */
+ char **filters; /* Filter strings... */
+
+ /**** New in CUPS 1.1 ****/
+ int flip_duplex; /* 1 = Flip page for back sides @deprecated@ */
+
+ /**** New in CUPS 1.1.19 ****/
+ char *protocols; /* Protocols (BCP, TBCP) string @since CUPS 1.1.19/Mac OS X 10.3@ */
+ char *pcfilename; /* PCFileName string @since CUPS 1.1.19/Mac OS X 10.3@ */
+ int num_attrs; /* Number of attributes @since CUPS 1.1.19/Mac OS X 10.3@ @private@ */
+ int cur_attr; /* Current attribute @since CUPS 1.1.19/Mac OS X 10.3@ @private@ */
+ ppd_attr_t **attrs; /* Attributes @since CUPS 1.1.19/Mac OS X 10.3@ @private@ */
+
+ /**** New in CUPS 1.2/Mac OS X 10.5 ****/
+ cups_array_t *sorted_attrs; /* Attribute lookup array @since CUPS 1.2/Mac OS X 10.5@ @private@ */
+ cups_array_t *options; /* Option lookup array @since CUPS 1.2/Mac OS X 10.5@ @private@ */
+ cups_array_t *coptions; /* Custom options array @since CUPS 1.2/Mac OS X 10.5@ @private@ */
+
+ /**** New in CUPS 1.3/Mac OS X 10.5 ****/
+ cups_array_t *marked; /* Marked choices @since CUPS 1.3/Mac OS X 10.5@ @private@ */
+
+ /**** New in CUPS 1.4/Mac OS X 10.6 ****/
+ cups_array_t *cups_uiconstraints; /* cupsUIConstraints @since CUPS 1.4/Mac OS X 10.6@ @private@ */
+
+ /**** New in CUPS 1.5 ****/
+ _ppd_cache_t *cache; /* PPD cache and mapping data @since CUPS 1.5/Mac OS X 10.7@ @private@ */
+} ppd_file_t;
+
+
+/*
+ * Prototypes...
+ */
+
+extern int cupsMarkOptions(ppd_file_t *ppd, int num_options,
+ cups_option_t *options);
+extern void ppdClose(ppd_file_t *ppd);
+extern int ppdCollect(ppd_file_t *ppd, ppd_section_t section,
+ ppd_choice_t ***choices);
+extern int ppdConflicts(ppd_file_t *ppd);
+extern int ppdEmit(ppd_file_t *ppd, FILE *fp,
+ ppd_section_t section);
+extern int ppdEmitFd(ppd_file_t *ppd, int fd,
+ ppd_section_t section);
+extern int ppdEmitJCL(ppd_file_t *ppd, FILE *fp, int job_id,
+ const char *user, const char *title);
+extern ppd_choice_t *ppdFindChoice(ppd_option_t *o, const char *option);
+extern ppd_choice_t *ppdFindMarkedChoice(ppd_file_t *ppd, const char *keyword);
+extern ppd_option_t *ppdFindOption(ppd_file_t *ppd, const char *keyword);
+extern int ppdIsMarked(ppd_file_t *ppd, const char *keyword,
+ const char *option);
+extern void ppdMarkDefaults(ppd_file_t *ppd);
+extern int ppdMarkOption(ppd_file_t *ppd, const char *keyword,
+ const char *option);
+extern ppd_file_t *ppdOpen(FILE *fp);
+extern ppd_file_t *ppdOpenFd(int fd);
+extern ppd_file_t *ppdOpenFile(const char *filename);
+extern float ppdPageLength(ppd_file_t *ppd, const char *name);
+extern ppd_size_t *ppdPageSize(ppd_file_t *ppd, const char *name);
+extern float ppdPageWidth(ppd_file_t *ppd, const char *name);
+
+/**** New in CUPS 1.1.19 ****/
+extern const char *ppdErrorString(ppd_status_t status) _CUPS_API_1_1_19;
+extern ppd_attr_t *ppdFindAttr(ppd_file_t *ppd, const char *name,
+ const char *spec) _CUPS_API_1_1_19;
+extern ppd_attr_t *ppdFindNextAttr(ppd_file_t *ppd, const char *name,
+ const char *spec) _CUPS_API_1_1_19;
+extern ppd_status_t ppdLastError(int *line) _CUPS_API_1_1_19;
+
+/**** New in CUPS 1.1.20 ****/
+extern void ppdSetConformance(ppd_conform_t c) _CUPS_API_1_1_20;
+
+/**** New in CUPS 1.2 ****/
+extern int ppdCollect2(ppd_file_t *ppd, ppd_section_t section,
+ float min_order, ppd_choice_t ***choices) _CUPS_API_1_2;
+extern int ppdEmitAfterOrder(ppd_file_t *ppd, FILE *fp,
+ ppd_section_t section, int limit,
+ float min_order) _CUPS_API_1_2;
+extern int ppdEmitJCLEnd(ppd_file_t *ppd, FILE *fp) _CUPS_API_1_2;
+extern char *ppdEmitString(ppd_file_t *ppd, ppd_section_t section,
+ float min_order) _CUPS_API_1_2;
+extern ppd_coption_t *ppdFindCustomOption(ppd_file_t *ppd,
+ const char *keyword) _CUPS_API_1_2;
+extern ppd_cparam_t *ppdFindCustomParam(ppd_coption_t *opt,
+ const char *name) _CUPS_API_1_2;
+extern ppd_cparam_t *ppdFirstCustomParam(ppd_coption_t *opt) _CUPS_API_1_2;
+extern ppd_option_t *ppdFirstOption(ppd_file_t *ppd) _CUPS_API_1_2;
+extern ppd_cparam_t *ppdNextCustomParam(ppd_coption_t *opt) _CUPS_API_1_2;
+extern ppd_option_t *ppdNextOption(ppd_file_t *ppd) _CUPS_API_1_2;
+extern int ppdLocalize(ppd_file_t *ppd) _CUPS_API_1_2;
+extern ppd_file_t *ppdOpen2(cups_file_t *fp) _CUPS_API_1_2;
+
+/**** New in CUPS 1.3/Mac OS X 10.5 ****/
+extern const char *ppdLocalizeIPPReason(ppd_file_t *ppd,
+ const char *reason,
+ const char *scheme,
+ char *buffer,
+ size_t bufsize) _CUPS_API_1_3;
+
+/**** New in CUPS 1.4/Mac OS X 10.6 ****/
+extern int cupsGetConflicts(ppd_file_t *ppd, const char *option,
+ const char *choice,
+ cups_option_t **options)
+ _CUPS_API_1_4;
+extern int cupsResolveConflicts(ppd_file_t *ppd, const char *option,
+ const char *choice,
+ int *num_options,
+ cups_option_t **options)
+ _CUPS_API_1_4;
+extern int ppdInstallableConflict(ppd_file_t *ppd,
+ const char *option,
+ const char *choice)
+ _CUPS_API_1_4;
+extern ppd_attr_t *ppdLocalizeAttr(ppd_file_t *ppd, const char *keyword,
+ const char *spec) _CUPS_API_1_4;
+extern const char *ppdLocalizeMarkerName(ppd_file_t *ppd,
+ const char *name) _CUPS_API_1_4;
+extern int ppdPageSizeLimits(ppd_file_t *ppd,
+ ppd_size_t *minimum,
+ ppd_size_t *maximum) _CUPS_API_1_4;
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_PPD_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/pwg-media.c b/cups/pwg-media.c
new file mode 100644
index 000000000..267e718a7
--- /dev/null
+++ b/cups/pwg-media.c
@@ -0,0 +1,848 @@
+/*
+ * "$Id$"
+ *
+ * PWG media name API implementation for CUPS.
+ *
+ * Copyright 2009-2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _pwgGenerateSize() - Generate a PWG size keyword.
+ * _pwgInitSize() - Initialize a PWG size using IPP job template
+ * attributes.
+ * _pwgMediaForLegacy() - Find a PWG media size by ISO/IPP legacy name.
+ * _pwgMediaForPPD() - Find a PWG media size by Adobe PPD name.
+ * _pwgMediaForPWG() - Find a PWG media size by 5101.1 self-describing
+ * name.
+ * _pwgMediaForSize() - Get the PWG media name for a given size.
+ * pwg_compare_legacy() - Compare two sizes using the legacy names.
+ * pwg_compare_ppd() - Compare two sizes using the PPD names.
+ * pwg_compare_pwg() - Compare two sizes using the PWG names.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include <math.h>
+
+
+/*
+ * Local macros...
+ */
+
+#define _PWG_MEDIA_IN(p,l,a,x,y) {p, l, a, (int)(x * 2540), (int)(y * 2540)}
+#define _PWG_MEDIA_MM(p,l,a,x,y) {p, l, a, (int)(x * 100), (int)(y * 100)}
+
+
+/*
+ * Local functions...
+ */
+
+static int pwg_compare_legacy(_pwg_media_t *a, _pwg_media_t *b);
+static int pwg_compare_pwg(_pwg_media_t *a, _pwg_media_t *b);
+static int pwg_compare_ppd(_pwg_media_t *a, _pwg_media_t *b);
+
+
+/*
+ * Local globals...
+ */
+
+static _pwg_media_t const cups_pwg_media[] =
+{ /* Media size lookup table */
+ /* North American Standard Sheet Media Sizes */
+ _PWG_MEDIA_IN("na_index-3x5_3x5in", NULL, "3x5", 3, 5),
+ _PWG_MEDIA_IN("na_personal_3.625x6.5in", NULL, "EnvPersonal", 3.625, 6.5),
+ _PWG_MEDIA_IN("na_monarch_3.875x7.5in", "monarch-envelope", "EnvMonarch", 3.875, 7.5),
+ _PWG_MEDIA_IN("na_number-9_3.875x8.875in", "na-number-9-envelope", "Env9", 3.875, 8.875),
+ _PWG_MEDIA_IN("na_index-4x6_4x6in", NULL, "4x6", 4, 6),
+ _PWG_MEDIA_IN("na_number-10_4.125x9.5in", "na-number-10-envelope", "Env10", 4.125, 9.5),
+ _PWG_MEDIA_IN("na_a2_4.375x5.75in", NULL, NULL, 4.375, 5.75),
+ _PWG_MEDIA_IN("na_number-11_4.5x10.375in", NULL, "Env11", 4.5, 10.375),
+ _PWG_MEDIA_IN("na_number-12_4.75x11in", NULL, "Env12", 4.75, 11),
+ _PWG_MEDIA_IN("na_5x7_5x7in", NULL, "5x7", 5, 7),
+ _PWG_MEDIA_IN("na_index-5x8_5x8in", NULL, "5x8", 5, 8),
+ _PWG_MEDIA_IN("na_number-14_5x11.5in", NULL, "Env14", 5, 11.5),
+ _PWG_MEDIA_IN("na_invoice_5.5x8.5in", "invoice", "Statement", 5.5, 8.5),
+ _PWG_MEDIA_IN("na_index-4x6-ext_6x8in", NULL, NULL, 6, 8),
+ _PWG_MEDIA_IN("na_6x9_6x9in", "na-6x9-envelope", "6x9", 6, 9),
+ _PWG_MEDIA_IN("na_c5_6.5x9.5in", NULL, "6.5x9.5", 6.5, 9.5),
+ _PWG_MEDIA_IN("na_7x9_7x9in", "na-7x9-envelope", "7x9", 7, 9),
+ _PWG_MEDIA_IN("na_executive_7.25x10.5in", "executive", "Executive", 7.25, 10.5),
+ _PWG_MEDIA_IN("na_govt-letter_8x10in", "na-8x10", "8x10", 8, 10),
+ _PWG_MEDIA_IN("na_govt-legal_8x13in", NULL, "8x13", 8, 13),
+ _PWG_MEDIA_IN("na_quarto_8.5x10.83in", "quarto", "Quarto", 8.5, 10.83),
+ _PWG_MEDIA_IN("na_letter_8.5x11in", "na-letter", "Letter", 8.5, 11),
+ _PWG_MEDIA_IN("na_fanfold-eur_8.5x12in", NULL, "FanFoldGerman", 8.5, 12),
+ _PWG_MEDIA_IN("na_letter-plus_8.5x12.69in", NULL, "LetterPlus", 8.5, 12.69),
+ _PWG_MEDIA_IN("na_foolscap_8.5x13in", NULL, "FanFoldGermanLegal", 8.5, 13),
+ _PWG_MEDIA_IN("na_legal_8.5x14in", "na-legal", "Legal", 8.5, 14),
+ _PWG_MEDIA_IN("na_super-a_8.94x14in", NULL, "SuperA", 8.94, 14),
+ _PWG_MEDIA_IN("na_9x11_9x11in", "na-9x11-envelope", "9x11", 9, 11),
+ _PWG_MEDIA_IN("na_arch-a_9x12in", "arch-a", "ARCHA", 9, 12),
+ _PWG_MEDIA_IN("na_letter-extra_9.5x12in", NULL, "LetterExtra", 9.5, 12),
+ _PWG_MEDIA_IN("na_legal-extra_9.5x15in", NULL, "LegalExtra", 9.5, 15),
+ _PWG_MEDIA_IN("na_10x11_10x11in", NULL, "10x11", 10, 11),
+ _PWG_MEDIA_IN("na_10x13_10x13in", "na-10x13-envelope", "10x13", 10, 13),
+ _PWG_MEDIA_IN("na_10x14_10x14in", "na-10x14-envelope", "10x14", 10, 14),
+ _PWG_MEDIA_IN("na_10x15_10x15in", "na-10x15-envelope", "10x15", 10, 15),
+ _PWG_MEDIA_IN("na_11x12_11x12in", NULL, "11x12", 11, 12),
+ _PWG_MEDIA_IN("na_edp_11x14in", NULL, "11x14", 11, 14),
+ _PWG_MEDIA_IN("na_fanfold-us_11x14.875in", NULL, NULL, 11, 14.875),
+ _PWG_MEDIA_IN("na_11x15_11x15in", NULL, "11x15", 11, 15),
+ _PWG_MEDIA_IN("na_ledger_11x17in", "tabloid", "Tabloid", 11, 17),
+ _PWG_MEDIA_IN("na_eur-edp_12x14in", NULL, NULL, 12, 14),
+ _PWG_MEDIA_IN("na_arch-b_12x18in", "arch-b", "ARCHB", 12, 18),
+ _PWG_MEDIA_IN("na_12x19_12x19in", NULL, "12x19", 12, 19),
+ _PWG_MEDIA_IN("na_b-plus_12x19.17in", NULL, "SuperB", 12, 19.17),
+ _PWG_MEDIA_IN("na_super-b_13x19in", "super-b", NULL, 13, 19),
+ _PWG_MEDIA_IN("na_c_17x22in", "c", "AnsiC", 17, 22),
+ _PWG_MEDIA_IN("na_arch-c_18x24in", "arch-c", "ARCHC", 18, 24),
+ _PWG_MEDIA_IN("na_d_22x34in", "d", "AnsiD", 22, 34),
+ _PWG_MEDIA_IN("na_arch-d_24x36in", "arch-d", "ARCHD", 24, 36),
+ _PWG_MEDIA_IN("asme_f_28x40in", "f", NULL, 28, 40),
+ _PWG_MEDIA_IN("na_wide-format_30x42in", NULL, NULL, 30, 42),
+ _PWG_MEDIA_IN("na_e_34x44in", "e", "AnsiE", 34, 44),
+ _PWG_MEDIA_IN("na_arch-e_36x48in", "arch-e", "ARCHE", 36, 48),
+ _PWG_MEDIA_IN("na_f_44x68in", NULL, "AnsiF", 44, 68),
+
+ /* Chinese Standard Sheet Media Inch Sizes */
+ _PWG_MEDIA_IN("roc_16k_7.75x10.75in", NULL, "roc16k", 7.75, 10.75),
+ _PWG_MEDIA_IN("roc_8k_10.75x15.5in", NULL, NULL, 10.75, 15.5),
+
+ /* ISO Standard Sheet Media Sizes */
+ _PWG_MEDIA_MM("iso_a10_26x37mm", "iso-a10", "A10", 26, 37),
+ _PWG_MEDIA_MM("iso_a9_37x52mm", "iso-a9", "A9", 37, 52),
+ _PWG_MEDIA_MM("iso_a8_52x74mm", "iso-a8", "A8", 52, 74),
+ _PWG_MEDIA_MM("iso_a7_74x105mm", "iso-a7", "A7", 74, 105),
+ _PWG_MEDIA_MM("iso_a6_105x148mm", "iso-a6", "A6", 105, 148),
+ _PWG_MEDIA_MM("iso_a5_148x210mm", "iso-a5", "A5", 148, 210),
+ _PWG_MEDIA_MM("iso_a5-extra_174x235mm", NULL, "A5Extra", 174, 235),
+ _PWG_MEDIA_MM("iso_a4_210x297mm", "iso-a4", "A4", 210, 297),
+ _PWG_MEDIA_MM("iso_a4-tab_225x297mm", NULL, NULL, 225, 297),
+ _PWG_MEDIA_MM("iso_a4-extra_235.5x322.3mm", NULL, "A4Extra", 235.5, 322.3),
+ _PWG_MEDIA_MM("iso_a3_297x420mm", "iso-a3", "A3", 297, 420),
+ _PWG_MEDIA_MM("iso_a4x3_297x630mm", "iso-a4x3", NULL, 297, 630),
+ _PWG_MEDIA_MM("iso_a4x4_297x841mm", "iso-a4x4", NULL, 297, 841),
+ _PWG_MEDIA_MM("iso_a4x5_297x1051mm", "iso-a4x5", NULL, 297, 1051),
+ _PWG_MEDIA_MM("iso_a4x6_297x1261mm", "iso-a4x6", NULL, 297, 1261),
+ _PWG_MEDIA_MM("iso_a4x7_297x1471mm", "iso-a4x7", NULL, 297, 1471),
+ _PWG_MEDIA_MM("iso_a4x8_297x1682mm", "iso-a4x8", NULL, 297, 1682),
+ _PWG_MEDIA_MM("iso_a4x9_297x1892mm", "iso-a4x9", NULL, 297, 1892),
+ _PWG_MEDIA_MM("iso_a3-extra_322x445mm", "iso-a3-extra", "A3Extra", 322, 445),
+ _PWG_MEDIA_MM("iso_a2_420x594mm", "iso-a2", "A2", 420, 594),
+ _PWG_MEDIA_MM("iso_a3x3_420x891mm", "iso-a3x3", NULL, 420, 891),
+ _PWG_MEDIA_MM("iso_a3x4_420x1189mm", "iso-a3x4", NULL, 420, 1189),
+ _PWG_MEDIA_MM("iso_a3x5_420x1486mm", "iso-a3x5", NULL, 420, 1486),
+ _PWG_MEDIA_MM("iso_a3x6_420x1783mm", "iso-a3x6", NULL, 420, 1783),
+ _PWG_MEDIA_MM("iso_a3x7_420x2080mm", "iso-a3x7", NULL, 420, 2080),
+ _PWG_MEDIA_MM("iso_a1_594x841mm", "iso-a1", "A1", 594, 841),
+ _PWG_MEDIA_MM("iso_a2x3_594x1261mm", "iso-a2x3", NULL, 594, 1261),
+ _PWG_MEDIA_MM("iso_a2x4_594x1682mm", "iso-a2x4", NULL, 594, 1682),
+ _PWG_MEDIA_MM("iso_a2x5_594x2102mm", "iso-a2x5", NULL, 594, 2102),
+ _PWG_MEDIA_MM("iso_a0_841x1189mm", "iso-a0", "A0", 841, 1189),
+ _PWG_MEDIA_MM("iso_a1x3_841x1783mm", "iso-a1x3", NULL, 841, 1783),
+ _PWG_MEDIA_MM("iso_a1x4_841x2378mm", "iso-a1x4", NULL, 841, 2378),
+ _PWG_MEDIA_MM("iso_2a0_1189x1682mm", NULL, NULL, 1189, 1682),
+ _PWG_MEDIA_MM("iso_a0x3_1189x2523mm", NULL, NULL, 1189, 2523),
+ _PWG_MEDIA_MM("iso_b10_31x44mm", "iso-b10", "ISOB10", 31, 44),
+ _PWG_MEDIA_MM("iso_b9_44x62mm", "iso-b9", "ISOB9", 44, 62),
+ _PWG_MEDIA_MM("iso_b8_62x88mm", "iso-b8", "ISOB8", 62, 88),
+ _PWG_MEDIA_MM("iso_b7_88x125mm", "iso-b7", "ISOB7", 88, 125),
+ _PWG_MEDIA_MM("iso_b6_125x176mm", "iso-b6", "ISOB6", 125, 176),
+ _PWG_MEDIA_MM("iso_b6c4_125x324mm", NULL, NULL, 125, 324),
+ _PWG_MEDIA_MM("iso_b5_176x250mm", "iso-b5", "ISOB5", 176, 250),
+ _PWG_MEDIA_MM("iso_b5-extra_201x276mm", NULL, "ISOB5Extra", 201, 276),
+ _PWG_MEDIA_MM("iso_b4_250x353mm", "iso-b4", "ISOB4", 250, 353),
+ _PWG_MEDIA_MM("iso_b3_353x500mm", "iso-b3", "ISOB3", 353, 500),
+ _PWG_MEDIA_MM("iso_b2_500x707mm", "iso-b2", "ISOB2", 500, 707),
+ _PWG_MEDIA_MM("iso_b1_707x1000mm", "iso-b1", "ISOB1", 707, 1000),
+ _PWG_MEDIA_MM("iso_b0_1000x1414mm", "iso-b0", "ISOB0", 1000, 1414),
+ _PWG_MEDIA_MM("iso_c10_28x40mm", "iso-c10", NULL, 28, 40),
+ _PWG_MEDIA_MM("iso_c9_40x57mm", "iso-c9", NULL, 40, 57),
+ _PWG_MEDIA_MM("iso_c8_57x81mm", "iso-c8", NULL, 57, 81),
+ _PWG_MEDIA_MM("iso_c7_81x114mm", "iso-c7", "EnvC7", 81, 114),
+ _PWG_MEDIA_MM("iso_c7c6_81x162mm", NULL, NULL, 81, 162),
+ _PWG_MEDIA_MM("iso_c6_114x162mm", "iso-c6", "EnvC6", 114, 162),
+ _PWG_MEDIA_MM("iso_c6c5_114x229mm", NULL, "EnvC65", 114, 229),
+ _PWG_MEDIA_MM("iso_c5_162x229mm", "iso-c5", "EnvC5", 162, 229),
+ _PWG_MEDIA_MM("iso_c4_229x324mm", "iso-c4", "EnvC4", 229, 324),
+ _PWG_MEDIA_MM("iso_c3_324x458mm", "iso-c3", "EnvC3", 324, 458),
+ _PWG_MEDIA_MM("iso_c2_458x648mm", "iso-c2", "EnvC2", 458, 648),
+ _PWG_MEDIA_MM("iso_c1_648x917mm", "iso-c1", "EnvC1", 648, 917),
+ _PWG_MEDIA_MM("iso_c0_917x1297mm", "iso-c0", "EnvC0", 917, 1297),
+ _PWG_MEDIA_MM("iso_dl_110x220mm", "iso-designated", "EnvDL", 110, 220),
+ _PWG_MEDIA_MM("iso_ra2_430x610mm", "iso-ra2", NULL, 430, 610),
+ _PWG_MEDIA_MM("iso_sra2_450x640mm", "iso-sra2", NULL, 450, 640),
+ _PWG_MEDIA_MM("iso_ra1_610x860mm", "iso-ra1", NULL, 610, 860),
+ _PWG_MEDIA_MM("iso_sra1_640x900mm", "iso-sra1", NULL, 640, 900),
+ _PWG_MEDIA_MM("iso_ra0_860x1220mm", "iso-ra0", NULL, 860, 1220),
+ _PWG_MEDIA_MM("iso_sra0_900x1280mm", "iso-sra0", NULL, 900, 1280),
+
+ /* Japanese Standard Sheet Media Sizes */
+ _PWG_MEDIA_MM("jis_b10_32x45mm", "jis-b10", "B10", 32, 45),
+ _PWG_MEDIA_MM("jis_b9_45x64mm", "jis-b9", "B9", 45, 64),
+ _PWG_MEDIA_MM("jis_b8_64x91mm", "jis-b8", "B8", 64, 91),
+ _PWG_MEDIA_MM("jis_b7_91x128mm", "jis-b7", "B7", 91, 128),
+ _PWG_MEDIA_MM("jis_b6_128x182mm", "jis-b6", "B6", 128, 182),
+ _PWG_MEDIA_MM("jis_b5_182x257mm", "jis-b5", "B5", 182, 257),
+ _PWG_MEDIA_MM("jis_b4_257x364mm", "jis-b4", "B4", 257, 364),
+ _PWG_MEDIA_MM("jis_b3_364x515mm", "jis-b3", "B3", 364, 515),
+ _PWG_MEDIA_MM("jis_b2_515x728mm", "jis-b2", "B2", 515, 728),
+ _PWG_MEDIA_MM("jis_b1_728x1030mm", "jis-b1", "B1", 728, 1030),
+ _PWG_MEDIA_MM("jis_b0_1030x1456mm", "jis-b0", "B0", 1030, 1456),
+ _PWG_MEDIA_MM("jis_exec_216x330mm", NULL, NULL, 216, 330),
+ _PWG_MEDIA_MM("jpn_chou4_90x205mm", NULL, "EnvChou4", 90, 205),
+ _PWG_MEDIA_MM("jpn_hagaki_100x148mm", NULL, "Postcard", 100, 148),
+ _PWG_MEDIA_MM("jpn_you4_105x235mm", NULL, "EnvYou4", 105, 235),
+ _PWG_MEDIA_MM("jpn_chou2_111.1x146mm", NULL, NULL, 111.1, 146),
+ _PWG_MEDIA_MM("jpn_chou3_120x235mm", NULL, "EnvChou3", 120, 235),
+ _PWG_MEDIA_MM("jpn_oufuku_148x200mm", NULL, "DoublePostcardRotated", 148, 200),
+ _PWG_MEDIA_MM("jpn_kahu_240x322.1mm", NULL, NULL, 240, 322.1),
+ _PWG_MEDIA_MM("jpn_kaku2_240x332mm", NULL, "EnvKaku2", 240, 332),
+
+ /* Chinese Standard Sheet Media Sizes */
+ _PWG_MEDIA_MM("prc_32k_97x151mm", NULL, "PRC32K", 97, 151),
+ _PWG_MEDIA_MM("prc_1_102x165mm", NULL, "EnvPRC1", 102, 165),
+ _PWG_MEDIA_MM("prc_2_102x176mm", NULL, "EnvPRC2", 102, 176),
+ _PWG_MEDIA_MM("prc_4_110x208mm", NULL, "EnvPRC4", 110, 208),
+ _PWG_MEDIA_MM("prc_5_110x220mm", NULL, "EnvPRC5", 110, 220),
+ _PWG_MEDIA_MM("prc_8_120x309mm", NULL, "EnvPRC8", 120, 309),
+ _PWG_MEDIA_MM("prc_6_120x320mm", NULL, NULL, 120, 320),
+ _PWG_MEDIA_MM("prc_3_125x176mm", NULL, "EnvPRC3", 125, 176),
+ _PWG_MEDIA_MM("prc_16k_146x215mm", NULL, "PRC16K", 146, 215),
+ _PWG_MEDIA_MM("prc_7_160x230mm", NULL, "EnvPRC7", 160, 230),
+ _PWG_MEDIA_MM("om_juuro-ku-kai_198x275mm", NULL, NULL, 198, 275),
+ _PWG_MEDIA_MM("om_pa-kai_267x389mm", NULL, NULL, 267, 389),
+ _PWG_MEDIA_MM("om_dai-pa-kai_275x395mm", NULL, NULL, 275, 395),
+ _PWG_MEDIA_MM("prc_10_324x458mm", NULL, "EnvPRC10", 324, 458),
+
+ /* Other Metric Standard Sheet Media Sizes */
+ _PWG_MEDIA_MM("om_small-photo_100x150mm", NULL, NULL, 100, 150),
+ _PWG_MEDIA_MM("om_italian_110x230mm", NULL, "EnvItalian", 110, 230),
+ _PWG_MEDIA_MM("om_postfix_114x229mm", NULL, NULL, 114, 229),
+ _PWG_MEDIA_MM("om_large-photo_200x300", NULL, NULL, 200, 300),
+ _PWG_MEDIA_MM("om_folio_210x330mm", "folio", "Folio", 210, 330),
+ _PWG_MEDIA_MM("om_folio-sp_215x315mm", NULL, NULL, 215, 315),
+ _PWG_MEDIA_MM("om_invite_220x220mm", NULL, "EnvInvite", 220, 220)
+};
+
+
+/*
+ * '_pwgGenerateSize()' - Generate a PWG size keyword.
+ */
+
+void
+_pwgGenerateSize(char *keyword, /* I - Keyword buffer */
+ size_t keysize, /* I - Size of keyword buffer */
+ const char *prefix, /* I - Prefix for PWG size or NULL */
+ const char *name, /* I - Size name or NULL */
+ int width, /* I - Width of page in 2540ths */
+ int length) /* I - Length of page in 2540ths */
+{
+ struct lconv *loc; /* Locale conversion data */
+ double uwidth, /* Width in inches or millimeters */
+ ulength; /* Height in inches or millimeters */
+ const char *units; /* Units to report */
+ char usize[12 + 1 + 12 + 3], /* Unit size: NNNNNNNNNNNNxNNNNNNNNNNNNuu */
+ *uptr; /* Pointer into unit size */
+
+
+ loc = localeconv();
+
+ if ((width % 635) == 0 && (length % 635) == 0)
+ {
+ /*
+ * Use inches since the size is a multiple of 1/4 inch.
+ */
+
+ uwidth = width / 2540.0;
+ ulength = length / 2540.0;
+ units = "in";
+
+ if (!prefix)
+ prefix = "oe";
+ }
+ else
+ {
+ /*
+ * Use millimeters since the size is not a multiple of 1/4 inch.
+ */
+
+ uwidth = width * 0.01;
+ ulength = length * 0.01;
+ units = "mm";
+
+ if (!prefix)
+ prefix = "om";
+ }
+
+ uptr = usize;
+ _cupsStrFormatd(uptr, uptr + 12, uwidth, loc);
+ uptr += strlen(uptr);
+ *uptr++ = 'x';
+ _cupsStrFormatd(uptr, uptr + 12, ulength, loc);
+ uptr += strlen(uptr);
+
+ /*
+ * Safe because usize can hold up to 12 + 1 + 12 + 4 bytes.
+ */
+
+ strcpy(uptr, units);
+
+ if (!name)
+ name = usize;
+
+ /*
+ * Format the name...
+ */
+
+ snprintf(keyword, keysize, "%s_%s_%s", prefix, name, usize);
+}
+
+
+/*
+ * '_pwgInitSize()' - Initialize a PWG size using IPP job template attributes.
+ */
+
+int /* O - 1 if size was initialize, 0 otherwise */
+_pwgInitSize(_pwg_size_t *size, /* I - Size to initialize */
+ ipp_t *job, /* I - Job template attributes */
+ int *margins_set) /* O - 1 if margins were set, 0 otherwise */
+{
+ ipp_attribute_t *media, /* media attribute */
+ *media_bottom_margin, /* media-bottom-margin member attribute */
+ *media_col, /* media-col attribute */
+ *media_left_margin, /* media-left-margin member attribute */
+ *media_right_margin, /* media-right-margin member attribute */
+ *media_size, /* media-size member attribute */
+ *media_top_margin, /* media-top-margin member attribute */
+ *x_dimension, /* x-dimension member attribute */
+ *y_dimension; /* y-dimension member attribute */
+ _pwg_media_t *pwg; /* PWG media value */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!size || !job || !margins_set)
+ return (0);
+
+ /*
+ * Look for media-col and then media...
+ */
+
+ memset(size, 0, sizeof(_pwg_size_t));
+ *margins_set = 0;
+
+ if ((media_col = ippFindAttribute(job, "media-col",
+ IPP_TAG_BEGIN_COLLECTION)) != NULL)
+ {
+ /*
+ * Got media-col, look for media-size member attribute...
+ */
+
+ if ((media_size = ippFindAttribute(media_col->values[0].collection,
+ "media-size",
+ IPP_TAG_BEGIN_COLLECTION)) != NULL)
+ {
+ /*
+ * Got media-size, look for x-dimension and y-dimension member
+ * attributes...
+ */
+
+ x_dimension = ippFindAttribute(media_size->values[0].collection,
+ "x-dimension", IPP_TAG_INTEGER);
+ y_dimension = ippFindAttribute(media_size->values[0].collection,
+ "y-dimension", IPP_TAG_INTEGER);
+
+ if (x_dimension && y_dimension)
+ {
+ size->width = x_dimension->values[0].integer;
+ size->length = y_dimension->values[0].integer;
+ }
+ else if (!x_dimension)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR,
+ _("Missing x-dimension in media-size."), 1);
+ return (0);
+ }
+ else if (!y_dimension)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR,
+ _("Missing y-dimension in media-size."), 1);
+ return (0);
+ }
+ }
+ else
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Missing media-size in media-col."),
+ 1);
+ return (0);
+ }
+
+ /* media-*-margin */
+ media_bottom_margin = ippFindAttribute(media_col->values[0].collection,
+ "media-bottom-margin",
+ IPP_TAG_INTEGER);
+ media_left_margin = ippFindAttribute(media_col->values[0].collection,
+ "media-left-margin",
+ IPP_TAG_INTEGER);
+ media_right_margin = ippFindAttribute(media_col->values[0].collection,
+ "media-right-margin",
+ IPP_TAG_INTEGER);
+ media_top_margin = ippFindAttribute(media_col->values[0].collection,
+ "media-top-margin",
+ IPP_TAG_INTEGER);
+ if (media_bottom_margin && media_left_margin && media_right_margin &&
+ media_top_margin)
+ {
+ *margins_set = 1;
+ size->bottom = media_bottom_margin->values[0].integer;
+ size->left = media_left_margin->values[0].integer;
+ size->right = media_right_margin->values[0].integer;
+ size->top = media_top_margin->values[0].integer;
+ }
+ }
+ else
+ {
+ if ((media = ippFindAttribute(job, "media", IPP_TAG_NAME)) == NULL)
+ if ((media = ippFindAttribute(job, "media", IPP_TAG_KEYWORD)) == NULL)
+ if ((media = ippFindAttribute(job, "PageSize", IPP_TAG_NAME)) == NULL)
+ media = ippFindAttribute(job, "PageRegion", IPP_TAG_NAME);
+
+ if (media)
+ {
+ const char *name = media->values[0].string.text;
+ /* Name string */
+
+ if ((pwg = _pwgMediaForPWG(name)) == NULL)
+ {
+ /*
+ * Not a PWG name, try a legacy name...
+ */
+
+ if ((pwg = _pwgMediaForLegacy(name)) == NULL)
+ {
+ /*
+ * Not a legacy name, try a PPD name...
+ */
+
+ const char *suffix; /* Suffix on media string */
+
+ pwg = _pwgMediaForPPD(name);
+ if (pwg &&
+ (suffix = name + strlen(name) - 10 /* .FullBleed */) > name &&
+ !_cups_strcasecmp(suffix, ".FullBleed"))
+ {
+ /*
+ * Indicate that margins are set with the default values of 0.
+ */
+
+ *margins_set = 1;
+ }
+ }
+ }
+
+ if (pwg)
+ {
+ size->width = pwg->width;
+ size->length = pwg->length;
+ }
+ else
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Unsupported media value."), 1);
+ return (0);
+ }
+ }
+ else
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Missing media or media-col."), 1);
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
+
+/*
+ * '_pwgMediaForLegacy()' - Find a PWG media size by ISO/IPP legacy name.
+ */
+
+_pwg_media_t * /* O - Matching size or NULL */
+_pwgMediaForLegacy(
+ const char *legacy) /* I - Legacy size name */
+{
+ _pwg_media_t key; /* Search key */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!legacy)
+ return (NULL);
+
+ /*
+ * Build the lookup table for PWG names as needed...
+ */
+
+ if (!cg->leg_size_lut)
+ {
+ int i; /* Looping var */
+ _pwg_media_t *size; /* Current size */
+
+ cg->leg_size_lut = cupsArrayNew((cups_array_func_t)pwg_compare_legacy,
+ NULL);
+
+ for (i = (int)(sizeof(cups_pwg_media) / sizeof(cups_pwg_media[0])),
+ size = (_pwg_media_t *)cups_pwg_media;
+ i > 0;
+ i --, size ++)
+ if (size->legacy)
+ cupsArrayAdd(cg->leg_size_lut, size);
+ }
+
+ /*
+ * Lookup the name...
+ */
+
+ key.legacy = legacy;
+ return ((_pwg_media_t *)cupsArrayFind(cg->leg_size_lut, &key));
+}
+
+
+/*
+ * '_pwgMediaForPPD()' - Find a PWG media size by Adobe PPD name.
+ */
+
+_pwg_media_t * /* O - Matching size or NULL */
+_pwgMediaForPPD(const char *ppd) /* I - PPD size name */
+{
+ _pwg_media_t key, /* Search key */
+ *size; /* Matching size */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd)
+ return (NULL);
+
+ /*
+ * Build the lookup table for PWG names as needed...
+ */
+
+ if (!cg->ppd_size_lut)
+ {
+ int i; /* Looping var */
+
+ cg->ppd_size_lut = cupsArrayNew((cups_array_func_t)pwg_compare_ppd, NULL);
+
+ for (i = (int)(sizeof(cups_pwg_media) / sizeof(cups_pwg_media[0])),
+ size = (_pwg_media_t *)cups_pwg_media;
+ i > 0;
+ i --, size ++)
+ if (size->ppd)
+ cupsArrayAdd(cg->ppd_size_lut, size);
+ }
+
+ /*
+ * Lookup the name...
+ */
+
+ key.ppd = ppd;
+ if ((size = (_pwg_media_t *)cupsArrayFind(cg->ppd_size_lut, &key)) == NULL)
+ {
+ /*
+ * See if the name is of the form:
+ *
+ * [Custom.]WIDTHxLENGTH[.FullBleed] - Size in points/inches [borderless]
+ * [Custom.]WIDTHxLENGTHcm[.FullBleed] - Size in centimeters [borderless]
+ * [Custom.]WIDTHxLENGTHft[.FullBleed] - Size in feet [borderless]
+ * [Custom.]WIDTHxLENGTHin[.FullBleed] - Size in inches [borderless]
+ * [Custom.]WIDTHxLENGTHm[.FullBleed] - Size in meters [borderless]
+ * [Custom.]WIDTHxLENGTHmm[.FullBleed] - Size in millimeters [borderless]
+ * [Custom.]WIDTHxLENGTHpt[.FullBleed] - Size in points [borderless]
+ */
+
+ double w, l, /* Width and length of page */
+ factor; /* Unit scaling factor */
+ char *ptr; /* Pointer into name */
+ struct lconv *loc; /* Locale data */
+ int custom; /* Custom page size? */
+
+ if (!_cups_strncasecmp(ppd, "Custom.", 7))
+ {
+ custom = 1;
+ factor = 2540.0 / 72.0;
+ ptr = (char *)ppd + 7;
+ }
+ else
+ {
+ custom = 0;
+ factor = 2540.0;
+ ptr = (char *)ppd;
+ }
+
+ loc = localeconv();
+ w = _cupsStrScand(ptr, &ptr, loc);
+
+ if (ptr && ptr > ppd && *ptr == 'x')
+ {
+ l = _cupsStrScand(ptr + 1, &ptr, loc);
+
+ if (ptr &&
+ (!*ptr ||
+ !_cups_strcasecmp(ptr, "FullBleed") ||
+ !_cups_strcasecmp(ptr, ".FullBleed") ||
+ !_cups_strcasecmp(ptr, "cm") ||
+ !_cups_strcasecmp(ptr, "cm.FullBleed") ||
+ !_cups_strcasecmp(ptr, "ft") ||
+ !_cups_strcasecmp(ptr, "ft.FullBleed") ||
+ !_cups_strcasecmp(ptr, "in") ||
+ !_cups_strcasecmp(ptr, "in.FullBleed") ||
+ !_cups_strcasecmp(ptr, "m") ||
+ !_cups_strcasecmp(ptr, "m.FullBleed") ||
+ !_cups_strcasecmp(ptr, "mm") ||
+ !_cups_strcasecmp(ptr, "mm.FullBleed") ||
+ !_cups_strcasecmp(ptr, "pt") ||
+ !_cups_strcasecmp(ptr, "pt.FullBleed")))
+ {
+ size = &(cg->pwg_media);
+
+ if (!_cups_strncasecmp(ptr, "cm", 2))
+ factor = 1000.0;
+ else if (!_cups_strncasecmp(ptr, "ft", 2))
+ factor = 2540.0 * 12.0;
+ else if (!_cups_strncasecmp(ptr, "in", 2))
+ factor = 2540.0;
+ else if (!_cups_strncasecmp(ptr, "mm", 2))
+ factor = 100.0;
+ else if (*ptr == 'm' || *ptr == 'M')
+ factor = 100000.0;
+ else if (!_cups_strncasecmp(ptr, "pt", 2))
+ factor = 2540.0 / 72.0;
+
+ /*
+ * Not a standard size; convert it to a PWG custom name of the form:
+ *
+ * [oe|om]_WIDTHxHEIGHTuu_WIDTHxHEIGHTuu
+ */
+
+ size->width = (int)(w * factor);
+ size->length = (int)(l * factor);
+ size->pwg = cg->pwg_name;
+
+ _pwgGenerateSize(cg->pwg_name, sizeof(cg->pwg_name),
+ custom ? "custom" : NULL, custom ? ppd + 7 : NULL,
+ size->width, size->length);
+ }
+ }
+ }
+
+ return (size);
+}
+
+
+/*
+ * '_pwgMediaForPWG()' - Find a PWG media size by 5101.1 self-describing name.
+ */
+
+_pwg_media_t * /* O - Matching size or NULL */
+_pwgMediaForPWG(const char *pwg) /* I - PWG size name */
+{
+ char *ptr; /* Pointer into name */
+ _pwg_media_t key, /* Search key */
+ *size; /* Matching size */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!pwg)
+ return (NULL);
+
+ /*
+ * Build the lookup table for PWG names as needed...
+ */
+
+ if (!cg->pwg_size_lut)
+ {
+ int i; /* Looping var */
+
+ cg->pwg_size_lut = cupsArrayNew((cups_array_func_t)pwg_compare_pwg, NULL);
+
+ for (i = (int)(sizeof(cups_pwg_media) / sizeof(cups_pwg_media[0])),
+ size = (_pwg_media_t *)cups_pwg_media;
+ i > 0;
+ i --, size ++)
+ cupsArrayAdd(cg->pwg_size_lut, size);
+ }
+
+ /*
+ * Lookup the name...
+ */
+
+ key.pwg = pwg;
+ if ((size = (_pwg_media_t *)cupsArrayFind(cg->pwg_size_lut, &key)) == NULL &&
+ (ptr = (char *)strchr(pwg, '_')) != NULL &&
+ (ptr = (char *)strchr(ptr + 1, '_')) != NULL)
+ {
+ /*
+ * Try decoding the self-describing name of the form:
+ *
+ * class_name_WWWxHHHin
+ * class_name_WWWxHHHmm
+ */
+
+ double w, l; /* Width and length of page */
+ struct lconv *loc; /* Locale data */
+
+ ptr ++;
+ loc = localeconv();
+ w = _cupsStrScand(ptr, &ptr, loc);
+
+ if (ptr && *ptr == 'x')
+ {
+ l = _cupsStrScand(ptr + 1, &ptr, loc);
+
+ if (ptr && (!strcmp(ptr, "in") || !strcmp(ptr, "mm")))
+ {
+ size = &(cg->pwg_media);
+
+ if (!strcmp(ptr, "mm"))
+ {
+ size->width = (int)(w * 100);
+ size->length = (int)(l * 100);
+ }
+ else
+ {
+ size->width = (int)(w * 2540);
+ size->length = (int)(l * 2540);
+ }
+
+ strlcpy(cg->pwg_name, pwg, sizeof(cg->pwg_name));
+ size->pwg = cg->pwg_name;
+ }
+ }
+ }
+
+ return (size);
+}
+
+
+/*
+ * '_pwgMediaForSize()' - Get the PWG media name for a given size.
+ */
+
+_pwg_media_t * /* O - PWG media name */
+_pwgMediaForSize(int width, /* I - Width in 2540ths */
+ int length) /* I - Length in 2540ths */
+{
+ int i; /* Looping var */
+ _pwg_media_t *media; /* Current media */
+ int dw, dl; /* Difference in width and length */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (width <= 0 || length <= 0)
+ return (NULL);
+
+ /*
+ * Look for a standard size...
+ */
+
+ for (i = (int)(sizeof(cups_pwg_media) / sizeof(cups_pwg_media[0])),
+ media = (_pwg_media_t *)cups_pwg_media;
+ i > 0;
+ i --, media ++)
+ {
+ /*
+ * Adobe uses a size matching algorithm with an epsilon of 5 points, which
+ * is just about 176/2540ths...
+ */
+
+ dw = media->width - width;
+ dl = media->length - length;
+
+ if (dw > -176 && dw < 176 && dl > -176 && dl < 176)
+ return (media);
+ }
+
+ /*
+ * Not a standard size; convert it to a PWG custom name of the form:
+ *
+ * custom_WIDTHxHEIGHTuu_WIDTHxHEIGHTuu
+ */
+
+ _pwgGenerateSize(cg->pwg_name, sizeof(cg->pwg_name), "custom", NULL, width,
+ length);
+
+ cg->pwg_media.pwg = cg->pwg_name;
+ cg->pwg_media.width = width;
+ cg->pwg_media.length = length;
+
+ return (&(cg->pwg_media));
+}
+
+
+/*
+ * 'pwg_compare_legacy()' - Compare two sizes using the legacy names.
+ */
+
+static int /* O - Result of comparison */
+pwg_compare_legacy(_pwg_media_t *a, /* I - First size */
+ _pwg_media_t *b) /* I - Second size */
+{
+ return (strcmp(a->legacy, b->legacy));
+}
+
+
+/*
+ * 'pwg_compare_ppd()' - Compare two sizes using the PPD names.
+ */
+
+static int /* O - Result of comparison */
+pwg_compare_ppd(_pwg_media_t *a, /* I - First size */
+ _pwg_media_t *b) /* I - Second size */
+{
+ return (strcmp(a->ppd, b->ppd));
+}
+
+
+/*
+ * 'pwg_compare_pwg()' - Compare two sizes using the PWG names.
+ */
+
+static int /* O - Result of comparison */
+pwg_compare_pwg(_pwg_media_t *a, /* I - First size */
+ _pwg_media_t *b) /* I - Second size */
+{
+ return (strcmp(a->pwg, b->pwg));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/pwg-private.h b/cups/pwg-private.h
new file mode 100644
index 000000000..41849b48c
--- /dev/null
+++ b/cups/pwg-private.h
@@ -0,0 +1,102 @@
+/*
+ * "$Id$"
+ *
+ * Private PWG media API definitions for CUPS.
+ *
+ * Copyright 2009-2010 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_PWG_PRIVATE_H_
+# define _CUPS_PWG_PRIVATE_H_
+
+
+/*
+ * Include necessary headers...
+ */
+
+# include <cups/cups.h>
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Macros...
+ */
+
+/* Convert from points to 2540ths */
+# define _PWG_FROMPTS(n) (int)((n) * 2540 / 72)
+/* Convert from 2540ths to points */
+# define _PWG_TOPTS(n) ((n) * 72.0 / 2540.0)
+
+
+/*
+ * Types and structures...
+ */
+
+typedef struct _pwg_map_s /**** Map element - PPD to/from PWG */
+{
+ char *pwg, /* PWG media keyword */
+ *ppd; /* PPD option keyword */
+} _pwg_map_t;
+
+typedef struct _pwg_media_s /**** Common media size data ****/
+{
+ const char *pwg, /* PWG 5101.1 "self describing" name */
+ *legacy, /* IPP/ISO legacy name */
+ *ppd; /* Standard Adobe PPD name */
+ int width, /* Width in 2540ths */
+ length; /* Length in 2540ths */
+} _pwg_media_t;
+
+typedef struct _pwg_size_s /**** Size element - PPD to/from PWG */
+{
+ _pwg_map_t map; /* Map element */
+ int width, /* Width in 2540ths */
+ length, /* Length in 2540ths */
+ left, /* Left margin in 2540ths */
+ bottom, /* Bottom margin in 2540ths */
+ right, /* Right margin in 2540ths */
+ top; /* Top margin in 2540ths */
+} _pwg_size_t;
+
+
+/*
+ * Functions...
+ */
+
+extern void _pwgGenerateSize(char *keyword, size_t keysize,
+ const char *prefix,
+ const char *name,
+ int width, int length);
+extern int _pwgInitSize(_pwg_size_t *size, ipp_t *job,
+ int *margins_set);
+extern _pwg_media_t *_pwgMediaForLegacy(const char *legacy);
+extern _pwg_media_t *_pwgMediaForPPD(const char *ppd);
+extern _pwg_media_t *_pwgMediaForPWG(const char *pwg);
+extern _pwg_media_t *_pwgMediaForSize(int width, int length);
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_PWG_PRIVATE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/raster.h b/cups/raster.h
new file mode 100644
index 000000000..1510df2d6
--- /dev/null
+++ b/cups/raster.h
@@ -0,0 +1,405 @@
+/*
+ * "$Id$"
+ *
+ * Raster file definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * This file is part of the CUPS Imaging library.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_RASTER_H_
+# define _CUPS_RASTER_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include "cups.h"
+# include "ppd.h"
+
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+/*
+ * Every non-PostScript printer driver that supports raster images
+ * should use the application/vnd.cups-raster image file format.
+ * Since both the PostScript RIP (pstoraster, based on GNU/GPL
+ * Ghostscript) and Image RIP (imagetoraster, located in the filter
+ * directory) use it, using this format saves you a lot of work.
+ * Also, the PostScript RIP passes any printer options that are in
+ * a PS file to your driver this way as well...
+ */
+
+/*
+ * Constants...
+ */
+
+# define CUPS_RASTER_SYNC 0x52615333 /* RaS3 */
+# define CUPS_RASTER_REVSYNC 0x33536152 /* 3SaR */
+
+# define CUPS_RASTER_SYNCv1 0x52615374 /* RaSt */
+# define CUPS_RASTER_REVSYNCv1 0x74536152 /* tSaR */
+
+# define CUPS_RASTER_SYNCv2 0x52615332 /* RaS2 */
+# define CUPS_RASTER_REVSYNCv2 0x32536152 /* 2SaR */
+
+# define CUPS_RASTER_SYNC_PWG CUPS_RASTER_SYNCv2
+
+
+/*
+ * The following definition can be used to determine if the
+ * colorimetric colorspaces (CIEXYZ, CIELAB, and ICCn) are
+ * defined...
+ */
+
+# define CUPS_RASTER_HAVE_COLORIMETRIC 1
+
+/*
+ * The following definition can be used to determine if the
+ * device colorspaces (DEVICEn) are defined...
+ */
+
+# define CUPS_RASTER_HAVE_DEVICE 1
+
+/*
+ * The following definition can be used to determine if PWG Raster is supported.
+ */
+
+# define CUPS_RASTER_HAVE_PWGRASTER 1
+
+
+/*
+ * Types...
+ */
+
+typedef enum cups_adv_e /**** AdvanceMedia attribute values ****/
+{
+ CUPS_ADVANCE_NONE = 0, /* Never advance the roll */
+ CUPS_ADVANCE_FILE = 1, /* Advance the roll after this file */
+ CUPS_ADVANCE_JOB = 2, /* Advance the roll after this job */
+ CUPS_ADVANCE_SET = 3, /* Advance the roll after this set */
+ CUPS_ADVANCE_PAGE = 4 /* Advance the roll after this page */
+} cups_adv_t;
+
+typedef enum cups_bool_e /**** Boolean type ****/
+{
+ CUPS_FALSE = 0, /* Logical false */
+ CUPS_TRUE = 1 /* Logical true */
+} cups_bool_t;
+
+typedef enum cups_cspace_e /**** cupsColorSpace attribute values ****/
+{
+ CUPS_CSPACE_W = 0, /* Luminance (DeviceGray, gamma 2.2 by default) */
+ CUPS_CSPACE_RGB = 1, /* Red, green, blue (DeviceRGB, sRGB by default) */
+ CUPS_CSPACE_RGBA = 2, /* Red, green, blue, alpha (DeviceRGB, sRGB by default) */
+ CUPS_CSPACE_K = 3, /* Black (DeviceK) */
+ CUPS_CSPACE_CMY = 4, /* Cyan, magenta, yellow (DeviceCMY) */
+ CUPS_CSPACE_YMC = 5, /* Yellow, magenta, cyan @deprecated@ */
+ CUPS_CSPACE_CMYK = 6, /* Cyan, magenta, yellow, black (DeviceCMYK) */
+ CUPS_CSPACE_YMCK = 7, /* Yellow, magenta, cyan, black @deprecated@ */
+ CUPS_CSPACE_KCMY = 8, /* Black, cyan, magenta, yellow @deprecated@ */
+ CUPS_CSPACE_KCMYcm = 9, /* Black, cyan, magenta, yellow, light-cyan, light-magenta @deprecated@ */
+ CUPS_CSPACE_GMCK = 10, /* Gold, magenta, yellow, black @deprecated@ */
+ CUPS_CSPACE_GMCS = 11, /* Gold, magenta, yellow, silver @deprecated@ */
+ CUPS_CSPACE_WHITE = 12, /* White ink (as black) @deprecated@ */
+ CUPS_CSPACE_GOLD = 13, /* Gold foil @deprecated@ */
+ CUPS_CSPACE_SILVER = 14, /* Silver foil @deprecated@ */
+
+ CUPS_CSPACE_CIEXYZ = 15, /* CIE XYZ @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_CIELab = 16, /* CIE Lab @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_RGBW = 17, /* Red, green, blue, white (DeviceRGB, sRGB by default) @since CUPS 1.2/Mac OS X 10.5@ */
+ CUPS_CSPACE_SW = 18, /* Luminance (gamma 2.2) @since CUPS 1.4.5@ */
+ CUPS_CSPACE_SRGB = 19, /* Red, green, blue (sRGB) @since CUPS 1.4.5@ */
+ CUPS_CSPACE_ADOBERGB = 20, /* Red, green, blue (Adobe RGB) @since CUPS 1.4.5@ */
+
+ CUPS_CSPACE_ICC1 = 32, /* ICC-based, 1 color @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_ICC2 = 33, /* ICC-based, 2 colors @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_ICC3 = 34, /* ICC-based, 3 colors @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_ICC4 = 35, /* ICC-based, 4 colors @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_ICC5 = 36, /* ICC-based, 5 colors @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_ICC6 = 37, /* ICC-based, 6 colors @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_ICC7 = 38, /* ICC-based, 7 colors @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_ICC8 = 39, /* ICC-based, 8 colors @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_ICC9 = 40, /* ICC-based, 9 colors @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_ICCA = 41, /* ICC-based, 10 colors @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_ICCB = 42, /* ICC-based, 11 colors @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_ICCC = 43, /* ICC-based, 12 colors @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_ICCD = 44, /* ICC-based, 13 colors @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_ICCE = 45, /* ICC-based, 14 colors @since CUPS 1.1.19/Mac OS X 10.3@ */
+ CUPS_CSPACE_ICCF = 46, /* ICC-based, 15 colors @since CUPS 1.1.19/Mac OS X 10.3@ */
+
+ CUPS_CSPACE_DEVICE1 = 48, /* DeviceN, 1 color @since CUPS 1.4.5@ */
+ CUPS_CSPACE_DEVICE2 = 49, /* DeviceN, 2 colors @since CUPS 1.4.5@ */
+ CUPS_CSPACE_DEVICE3 = 50, /* DeviceN, 3 colors @since CUPS 1.4.5@ */
+ CUPS_CSPACE_DEVICE4 = 51, /* DeviceN, 4 colors @since CUPS 1.4.5@ */
+ CUPS_CSPACE_DEVICE5 = 52, /* DeviceN, 5 colors @since CUPS 1.4.5@ */
+ CUPS_CSPACE_DEVICE6 = 53, /* DeviceN, 6 colors @since CUPS 1.4.5@ */
+ CUPS_CSPACE_DEVICE7 = 54, /* DeviceN, 7 colors @since CUPS 1.4.5@ */
+ CUPS_CSPACE_DEVICE8 = 55, /* DeviceN, 8 colors @since CUPS 1.4.5@ */
+ CUPS_CSPACE_DEVICE9 = 56, /* DeviceN, 9 colors @since CUPS 1.4.5@ */
+ CUPS_CSPACE_DEVICEA = 57, /* DeviceN, 10 colors @since CUPS 1.4.5@ */
+ CUPS_CSPACE_DEVICEB = 58, /* DeviceN, 11 colors @since CUPS 1.4.5@ */
+ CUPS_CSPACE_DEVICEC = 59, /* DeviceN, 12 colors @since CUPS 1.4.5@ */
+ CUPS_CSPACE_DEVICED = 60, /* DeviceN, 13 colors @since CUPS 1.4.5@ */
+ CUPS_CSPACE_DEVICEE = 61, /* DeviceN, 14 colors @since CUPS 1.4.5@ */
+ CUPS_CSPACE_DEVICEF = 62 /* DeviceN, 15 colors @since CUPS 1.4.5@ */
+} cups_cspace_t;
+
+typedef enum cups_cut_e /**** CutMedia attribute values ****/
+{
+ CUPS_CUT_NONE = 0, /* Never cut the roll */
+ CUPS_CUT_FILE = 1, /* Cut the roll after this file */
+ CUPS_CUT_JOB = 2, /* Cut the roll after this job */
+ CUPS_CUT_SET = 3, /* Cut the roll after this set */
+ CUPS_CUT_PAGE = 4 /* Cut the roll after this page */
+} cups_cut_t;
+
+typedef enum cups_edge_e /**** LeadingEdge attribute values ****/
+{
+ CUPS_EDGE_TOP = 0, /* Leading edge is the top of the page */
+ CUPS_EDGE_RIGHT = 1, /* Leading edge is the right of the page */
+ CUPS_EDGE_BOTTOM = 2, /* Leading edge is the bottom of the page */
+ CUPS_EDGE_LEFT = 3 /* Leading edge is the left of the page */
+} cups_edge_t;
+
+typedef enum cups_jog_e /**** Jog attribute values ****/
+{
+ CUPS_JOG_NONE = 0, /* Never move pages */
+ CUPS_JOG_FILE = 1, /* Move pages after this file */
+ CUPS_JOG_JOB = 2, /* Move pages after this job */
+ CUPS_JOG_SET = 3 /* Move pages after this set */
+} cups_jog_t;
+
+enum cups_mode_e /**** cupsRasterOpen modes ****/
+{
+ CUPS_RASTER_READ = 0, /* Open stream for reading */
+ CUPS_RASTER_WRITE = 1, /* Open stream for writing */
+ CUPS_RASTER_WRITE_COMPRESSED = 2, /* Open stream for compressed writing @since CUPS 1.3/Mac OS X 10.5@ */
+ CUPS_RASTER_WRITE_PWG = 3 /* Open stream for compressed writing in PWG mode @since CUPS 1.5/Mac OS X 10.7@ */
+};
+
+typedef enum cups_mode_e cups_mode_t; /**** cupsRasterOpen modes ****/
+
+typedef enum cups_order_e /**** cupsColorOrder attribute values ****/
+{
+ CUPS_ORDER_CHUNKED = 0, /* CMYK CMYK CMYK ... */
+ CUPS_ORDER_BANDED = 1, /* CCC MMM YYY KKK ... */
+ CUPS_ORDER_PLANAR = 2 /* CCC ... MMM ... YYY ... KKK ... */
+} cups_order_t;
+
+typedef enum cups_orient_e /**** Orientation attribute values ****/
+{
+ CUPS_ORIENT_0 = 0, /* Don't rotate the page */
+ CUPS_ORIENT_90 = 1, /* Rotate the page counter-clockwise */
+ CUPS_ORIENT_180 = 2, /* Turn the page upside down */
+ CUPS_ORIENT_270 = 3 /* Rotate the page clockwise */
+} cups_orient_t;
+
+
+/*
+ * The page header structure contains the standard PostScript page device
+ * dictionary, along with some CUPS-specific parameters that are provided
+ * by the RIPs...
+ *
+ * The API supports a "version 1" (from CUPS 1.0 and 1.1) and a "version 2"
+ * (from CUPS 1.2 and higher) page header, for binary compatibility.
+ */
+
+typedef struct cups_page_header_s /**** Version 1 page header @deprecated@ ****/
+{
+ /**** Standard Page Device Dictionary String Values ****/
+ char MediaClass[64]; /* MediaClass string */
+ char MediaColor[64]; /* MediaColor string */
+ char MediaType[64]; /* MediaType string */
+ char OutputType[64]; /* OutputType string */
+
+ /**** Standard Page Device Dictionary Integer Values ****/
+ unsigned AdvanceDistance; /* AdvanceDistance value in points */
+ cups_adv_t AdvanceMedia; /* AdvanceMedia value (@link cups_adv_t@) */
+ cups_bool_t Collate; /* Collated copies value */
+ cups_cut_t CutMedia; /* CutMedia value (@link cups_cut_t@) */
+ cups_bool_t Duplex; /* Duplexed (double-sided) value */
+ unsigned HWResolution[2]; /* Resolution in dots-per-inch */
+ unsigned ImagingBoundingBox[4]; /* Pixel region that is painted (points, left, bottom, right, top) */
+ cups_bool_t InsertSheet; /* InsertSheet value */
+ cups_jog_t Jog; /* Jog value (@link cups_jog_t@) */
+ cups_edge_t LeadingEdge; /* LeadingEdge value (@link cups_edge_t@) */
+ unsigned Margins[2]; /* Lower-lefthand margins in points */
+ cups_bool_t ManualFeed; /* ManualFeed value */
+ unsigned MediaPosition; /* MediaPosition value */
+ unsigned MediaWeight; /* MediaWeight value in grams/m^2 */
+ cups_bool_t MirrorPrint; /* MirrorPrint value */
+ cups_bool_t NegativePrint; /* NegativePrint value */
+ unsigned NumCopies; /* Number of copies to produce */
+ cups_orient_t Orientation; /* Orientation value (@link cups_orient_t@) */
+ cups_bool_t OutputFaceUp; /* OutputFaceUp value */
+ unsigned PageSize[2]; /* Width and length of page in points */
+ cups_bool_t Separations; /* Separations value */
+ cups_bool_t TraySwitch; /* TraySwitch value */
+ cups_bool_t Tumble; /* Tumble value */
+
+ /**** CUPS Page Device Dictionary Values ****/
+ unsigned cupsWidth; /* Width of page image in pixels */
+ unsigned cupsHeight; /* Height of page image in pixels */
+ unsigned cupsMediaType; /* Media type code */
+ unsigned cupsBitsPerColor; /* Number of bits for each color */
+ unsigned cupsBitsPerPixel; /* Number of bits for each pixel */
+ unsigned cupsBytesPerLine; /* Number of bytes per line */
+ cups_order_t cupsColorOrder; /* Order of colors */
+ cups_cspace_t cupsColorSpace; /* True colorspace */
+ unsigned cupsCompression; /* Device compression to use */
+ unsigned cupsRowCount; /* Rows per band */
+ unsigned cupsRowFeed; /* Feed between bands */
+ unsigned cupsRowStep; /* Spacing between lines */
+} cups_page_header_t;
+
+/**** New in CUPS 1.2 ****/
+typedef struct cups_page_header2_s /**** Version 2 page header @since CUPS 1.2/Mac OS X 10.5@ ****/
+{
+ /**** Standard Page Device Dictionary String Values ****/
+ char MediaClass[64]; /* MediaClass string */
+ char MediaColor[64]; /* MediaColor string */
+ char MediaType[64]; /* MediaType string */
+ char OutputType[64]; /* OutputType string */
+
+ /**** Standard Page Device Dictionary Integer Values ****/
+ unsigned AdvanceDistance; /* AdvanceDistance value in points */
+ cups_adv_t AdvanceMedia; /* AdvanceMedia value (@link cups_adv_t@) */
+ cups_bool_t Collate; /* Collated copies value */
+ cups_cut_t CutMedia; /* CutMedia value (@link cups_cut_t@) */
+ cups_bool_t Duplex; /* Duplexed (double-sided) value */
+ unsigned HWResolution[2]; /* Resolution in dots-per-inch */
+ unsigned ImagingBoundingBox[4]; /* Pixel region that is painted (points, left, bottom, right, top) */
+ cups_bool_t InsertSheet; /* InsertSheet value */
+ cups_jog_t Jog; /* Jog value (@link cups_jog_t@) */
+ cups_edge_t LeadingEdge; /* LeadingEdge value (@link cups_edge_t@) */
+ unsigned Margins[2]; /* Lower-lefthand margins in points */
+ cups_bool_t ManualFeed; /* ManualFeed value */
+ unsigned MediaPosition; /* MediaPosition value */
+ unsigned MediaWeight; /* MediaWeight value in grams/m^2 */
+ cups_bool_t MirrorPrint; /* MirrorPrint value */
+ cups_bool_t NegativePrint; /* NegativePrint value */
+ unsigned NumCopies; /* Number of copies to produce */
+ cups_orient_t Orientation; /* Orientation value (@link cups_orient_t@) */
+ cups_bool_t OutputFaceUp; /* OutputFaceUp value */
+ unsigned PageSize[2]; /* Width and length of page in points */
+ cups_bool_t Separations; /* Separations value */
+ cups_bool_t TraySwitch; /* TraySwitch value */
+ cups_bool_t Tumble; /* Tumble value */
+
+ /**** CUPS Page Device Dictionary Values ****/
+ unsigned cupsWidth; /* Width of page image in pixels */
+ unsigned cupsHeight; /* Height of page image in pixels */
+ unsigned cupsMediaType; /* Media type code */
+ unsigned cupsBitsPerColor; /* Number of bits for each color */
+ unsigned cupsBitsPerPixel; /* Number of bits for each pixel */
+ unsigned cupsBytesPerLine; /* Number of bytes per line */
+ cups_order_t cupsColorOrder; /* Order of colors */
+ cups_cspace_t cupsColorSpace; /* True colorspace */
+ unsigned cupsCompression; /* Device compression to use */
+ unsigned cupsRowCount; /* Rows per band */
+ unsigned cupsRowFeed; /* Feed between bands */
+ unsigned cupsRowStep; /* Spacing between lines */
+
+ /**** Version 2 Dictionary Values ****/
+ unsigned cupsNumColors; /* Number of color compoents @since CUPS 1.2/Mac OS X 10.5@ */
+ float cupsBorderlessScalingFactor;
+ /* Scaling that was applied to page data @since CUPS 1.2/Mac OS X 10.5@ */
+ float cupsPageSize[2]; /* Floating point PageSize (scaling *
+ * factor not applied) @since CUPS 1.2/Mac OS X 10.5@ */
+ float cupsImagingBBox[4]; /* Floating point ImagingBoundingBox
+ * (scaling factor not applied, left,
+ * bottom, right, top) @since CUPS 1.2/Mac OS X 10.5@ */
+ unsigned cupsInteger[16]; /* User-defined integer values @since CUPS 1.2/Mac OS X 10.5@ */
+ float cupsReal[16]; /* User-defined floating-point values @since CUPS 1.2/Mac OS X 10.5@ */
+ char cupsString[16][64]; /* User-defined string values @since CUPS 1.2/Mac OS X 10.5@ */
+ char cupsMarkerType[64]; /* Ink/toner type @since CUPS 1.2/Mac OS X 10.5@ */
+ char cupsRenderingIntent[64];/* Color rendering intent @since CUPS 1.2/Mac OS X 10.5@ */
+ char cupsPageSizeName[64]; /* PageSize name @since CUPS 1.2/Mac OS X 10.5@ */
+} cups_page_header2_t;
+
+typedef struct _cups_raster_s cups_raster_t;
+ /**** Raster stream data ****/
+
+typedef int (*cups_interpret_cb_t)(cups_page_header2_t *header, int preferred_bits);
+ /**** cupsRasterInterpretPPD callback function
+ *
+ * This function is called by
+ * @link cupsRasterInterpretPPD@ to
+ * validate (and update, as needed)
+ * the page header attributes. The
+ * "preferred_bits" argument provides
+ * the value of the
+ * @code cupsPreferredBitsPerColor@
+ * key from the PostScript page device
+ * dictionary and is 0 if undefined.
+ ****/
+
+/**** New in CUPS 1.5 ****/
+typedef ssize_t (*cups_raster_iocb_t)(void *ctx, unsigned char *buffer, size_t length);
+ /**** cupsRasterOpenIO callback function
+ *
+ * This function is specified when
+ * creating a raster stream with
+ * @link cupsRasterOpenIO@ and handles
+ * generic reading and writing of raster
+ * data. It must return -1 on error or
+ * the number of bytes specified by
+ * "length" on success.
+ ****/
+
+
+/*
+ * Prototypes...
+ */
+
+extern void cupsRasterClose(cups_raster_t *r);
+extern cups_raster_t *cupsRasterOpen(int fd, cups_mode_t mode);
+extern unsigned cupsRasterReadHeader(cups_raster_t *r,
+ cups_page_header_t *h) _CUPS_DEPRECATED;
+extern unsigned cupsRasterReadPixels(cups_raster_t *r,
+ unsigned char *p, unsigned len);
+extern unsigned cupsRasterWriteHeader(cups_raster_t *r,
+ cups_page_header_t *h) _CUPS_DEPRECATED;
+extern unsigned cupsRasterWritePixels(cups_raster_t *r,
+ unsigned char *p, unsigned len);
+
+/**** New in CUPS 1.2 ****/
+extern int cupsRasterInterpretPPD(cups_page_header2_t *h,
+ ppd_file_t *ppd,
+ int num_options,
+ cups_option_t *options,
+ cups_interpret_cb_t func) _CUPS_API_1_2;
+extern unsigned cupsRasterReadHeader2(cups_raster_t *r,
+ cups_page_header2_t *h) _CUPS_API_1_2;
+extern unsigned cupsRasterWriteHeader2(cups_raster_t *r,
+ cups_page_header2_t *h) _CUPS_API_1_2;
+
+/**** New in CUPS 1.3 ****/
+extern const char *cupsRasterErrorString(void) _CUPS_API_1_3;
+
+/**** New in CUPS 1.5 ****/
+extern cups_raster_t *cupsRasterOpenIO(cups_raster_iocb_t iocb, void *ctx,
+ cups_mode_t mode);
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_RASTER_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/request.c b/cups/request.c
new file mode 100644
index 000000000..f2735ec89
--- /dev/null
+++ b/cups/request.c
@@ -0,0 +1,1099 @@
+/*
+ * "$Id$"
+ *
+ * IPP utilities for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsDoFileRequest() - Do an IPP request with a file.
+ * cupsDoIORequest() - Do an IPP request with file descriptors.
+ * cupsDoRequest() - Do an IPP request.
+ * cupsGetResponse() - Get a response to an IPP request.
+ * cupsLastError() - Return the last IPP status code.
+ * cupsLastErrorString() - Return the last IPP status-message.
+ * _cupsNextDelay() - Return the next retry delay value.
+ * cupsReadResponseData() - Read additional data after the IPP response.
+ * cupsSendRequest() - Send an IPP request.
+ * cupsWriteRequestData() - Write additional data after an IPP request.
+ * _cupsConnect() - Get the default server connection...
+ * _cupsSetError() - Set the last IPP status code and status-message.
+ * _cupsSetHTTPError() - Set the last error using the HTTP status.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include <fcntl.h>
+#include <sys/stat.h>
+#if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+#else
+# include <unistd.h>
+#endif /* WIN32 || __EMX__ */
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif /* O_BINARY */
+
+
+/*
+ * 'cupsDoFileRequest()' - Do an IPP request with a file.
+ *
+ * This function sends the IPP request to the specified server, retrying
+ * and authenticating as necessary. The request is freed with @link ippDelete@
+ * after receiving a valid IPP response.
+ */
+
+ipp_t * /* O - Response data */
+cupsDoFileRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ ipp_t *request, /* I - IPP request */
+ const char *resource, /* I - HTTP resource for POST */
+ const char *filename) /* I - File to send or @code NULL@ for none */
+{
+ ipp_t *response; /* IPP response data */
+ int infile; /* Input file */
+
+
+ DEBUG_printf(("cupsDoFileRequest(http=%p, request=%p(%s), resource=\"%s\", "
+ "filename=\"%s\")", http, request,
+ request ? ippOpString(request->request.op.operation_id) : "?",
+ resource, filename));
+
+ if (filename)
+ {
+ if ((infile = open(filename, O_RDONLY | O_BINARY)) < 0)
+ {
+ /*
+ * Can't get file information!
+ */
+
+ _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
+ NULL, 0);
+
+ ippDelete(request);
+
+ return (NULL);
+ }
+ }
+ else
+ infile = -1;
+
+ response = cupsDoIORequest(http, request, resource, infile, -1);
+
+ if (infile >= 0)
+ close(infile);
+
+ return (response);
+}
+
+
+/*
+ * 'cupsDoIORequest()' - Do an IPP request with file descriptors.
+ *
+ * This function sends the IPP request to the specified server, retrying
+ * and authenticating as necessary. The request is freed with ippDelete()
+ * after receiving a valid IPP response.
+ *
+ * If "infile" is a valid file descriptor, cupsDoIORequest() copies
+ * all of the data from the file after the IPP request message.
+ *
+ * If "outfile" is a valid file descriptor, cupsDoIORequest() copies
+ * all of the data after the IPP response message to the file.
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+ipp_t * /* O - Response data */
+cupsDoIORequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ ipp_t *request, /* I - IPP request */
+ const char *resource, /* I - HTTP resource for POST */
+ int infile, /* I - File to read from or -1 for none */
+ int outfile) /* I - File to write to or -1 for none */
+{
+ ipp_t *response = NULL; /* IPP response data */
+ size_t length = 0; /* Content-Length value */
+ http_status_t status; /* Status of HTTP request */
+ struct stat fileinfo; /* File information */
+ int bytes; /* Number of bytes read/written */
+ char buffer[32768]; /* Output buffer */
+
+
+ DEBUG_printf(("cupsDoIORequest(http=%p, request=%p(%s), resource=\"%s\", "
+ "infile=%d, outfile=%d)", http, request,
+ request ? ippOpString(request->request.op.operation_id) : "?",
+ resource, infile, outfile));
+
+ /*
+ * Range check input...
+ */
+
+ if (!request || !resource)
+ {
+ ippDelete(request);
+
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
+
+ return (NULL);
+ }
+
+ /*
+ * Get the default connection as needed...
+ */
+
+ if (!http)
+ if ((http = _cupsConnect()) == NULL)
+ {
+ ippDelete(request);
+
+ return (NULL);
+ }
+
+ /*
+ * See if we have a file to send...
+ */
+
+ if (infile >= 0)
+ {
+ if (fstat(infile, &fileinfo))
+ {
+ /*
+ * Can't get file information!
+ */
+
+ _cupsSetError(errno == EBADF ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
+ NULL, 0);
+
+ ippDelete(request);
+
+ return (NULL);
+ }
+
+#ifdef WIN32
+ if (fileinfo.st_mode & _S_IFDIR)
+#else
+ if (S_ISDIR(fileinfo.st_mode))
+#endif /* WIN32 */
+ {
+ /*
+ * Can't send a directory...
+ */
+
+ ippDelete(request);
+
+ _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR), 0);
+
+ return (NULL);
+ }
+
+#ifndef WIN32
+ if (!S_ISREG(fileinfo.st_mode))
+ length = 0; /* Chunk when piping */
+ else
+#endif /* !WIN32 */
+ length = ippLength(request) + fileinfo.st_size;
+ }
+ else
+ length = ippLength(request);
+
+ DEBUG_printf(("2cupsDoIORequest: Request length=%ld, total length=%ld",
+ (long)ippLength(request), (long)length));
+
+ /*
+ * Clear any "Local" authentication data since it is probably stale...
+ */
+
+ if (http->authstring && !strncmp(http->authstring, "Local ", 6))
+ httpSetAuthString(http, NULL, NULL);
+
+ /*
+ * Loop until we can send the request without authorization problems.
+ */
+
+ while (response == NULL)
+ {
+ DEBUG_puts("2cupsDoIORequest: setup...");
+
+ /*
+ * Send the request...
+ */
+
+ status = cupsSendRequest(http, request, resource, length);
+
+ DEBUG_printf(("2cupsDoIORequest: status=%d", status));
+
+ if (status == HTTP_CONTINUE && request->state == IPP_DATA && infile >= 0)
+ {
+ DEBUG_puts("2cupsDoIORequest: file write...");
+
+ /*
+ * Send the file with the request...
+ */
+
+#ifndef WIN32
+ if (S_ISREG(fileinfo.st_mode))
+#endif /* WIN32 */
+ lseek(infile, 0, SEEK_SET);
+
+ while ((bytes = (int)read(infile, buffer, sizeof(buffer))) > 0)
+ {
+ if (httpCheck(http))
+ {
+ _httpUpdate(http, &status);
+
+ if (status >= HTTP_MULTIPLE_CHOICES)
+ break;
+ }
+
+ if (httpWrite2(http, buffer, bytes) < bytes)
+ break;
+ }
+ }
+
+ /*
+ * Get the server's response...
+ */
+
+ if (status == HTTP_CONTINUE || status == HTTP_OK)
+ {
+ response = cupsGetResponse(http, resource);
+ status = http->status;
+ }
+ else
+ httpFlush(http);
+
+ DEBUG_printf(("2cupsDoIORequest: status=%d", status));
+
+ if (status == HTTP_ERROR ||
+ (status >= HTTP_BAD_REQUEST && status != HTTP_UNAUTHORIZED &&
+ status != HTTP_UPGRADE_REQUIRED))
+ {
+ _cupsSetHTTPError(status);
+ break;
+ }
+
+ if (response)
+ {
+ if (outfile >= 0)
+ {
+ /*
+ * Write trailing data to file...
+ */
+
+ while ((bytes = (int)httpRead2(http, buffer, sizeof(buffer))) > 0)
+ if (write(outfile, buffer, bytes) < bytes)
+ break;
+ }
+ else
+ {
+ /*
+ * Flush any remaining data...
+ */
+
+ httpFlush(http);
+ }
+ }
+ }
+
+ /*
+ * Delete the original request and return the response...
+ */
+
+ ippDelete(request);
+
+ return (response);
+}
+
+
+/*
+ * 'cupsDoRequest()' - Do an IPP request.
+ *
+ * This function sends the IPP request to the specified server, retrying
+ * and authenticating as necessary. The request is freed with ippDelete()
+ * after receiving a valid IPP response.
+ */
+
+ipp_t * /* O - Response data */
+cupsDoRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ ipp_t *request, /* I - IPP request */
+ const char *resource) /* I - HTTP resource for POST */
+{
+ DEBUG_printf(("cupsDoRequest(http=%p, request=%p(%s), resource=\"%s\")",
+ http, request,
+ request ? ippOpString(request->request.op.operation_id) : "?",
+ resource));
+
+ return (cupsDoIORequest(http, request, resource, -1, -1));
+}
+
+
+/*
+ * 'cupsGetResponse()' - Get a response to an IPP request.
+ *
+ * Use this function to get the response for an IPP request sent using
+ * cupsSendDocument() or cupsSendRequest(). For requests that return
+ * additional data, use httpRead() after getting a successful response.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+ipp_t * /* O - Response or @code NULL@ on HTTP error */
+cupsGetResponse(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *resource) /* I - HTTP resource for POST */
+{
+ http_status_t status; /* HTTP status */
+ ipp_state_t state; /* IPP read state */
+ ipp_t *response = NULL; /* IPP response */
+
+
+ DEBUG_printf(("cupsGetResponse(http=%p, resource=\"%s\")", http, resource));
+
+ /*
+ * Connect to the default server as needed...
+ */
+
+ if (!http)
+ http = _cupsConnect();
+
+ if (!http || (http->state != HTTP_POST_RECV && http->state != HTTP_POST_SEND))
+ return (NULL);
+
+ /*
+ * Check for an unfinished chunked request...
+ */
+
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED)
+ {
+ /*
+ * Send a 0-length chunk to finish off the request...
+ */
+
+ DEBUG_puts("2cupsGetResponse: Finishing chunked POST...");
+
+ if (httpWrite2(http, "", 0) < 0)
+ return (NULL);
+ }
+
+ /*
+ * Wait for a response from the server...
+ */
+
+ DEBUG_printf(("2cupsGetResponse: Update loop, http->status=%d...",
+ http->status));
+
+ do
+ {
+ status = httpUpdate(http);
+ }
+ while (status != HTTP_ERROR && http->state == HTTP_POST_RECV);
+
+ DEBUG_printf(("2cupsGetResponse: status=%d", status));
+
+ if (status == HTTP_OK)
+ {
+ /*
+ * Get the IPP response...
+ */
+
+ response = ippNew();
+
+ while ((state = ippRead(http, response)) != IPP_DATA)
+ if (state == IPP_ERROR)
+ break;
+
+ if (state == IPP_ERROR)
+ {
+ /*
+ * Flush remaining data and delete the response...
+ */
+
+ DEBUG_puts("1cupsGetResponse: IPP read error!");
+
+ httpFlush(http);
+
+ ippDelete(response);
+ response = NULL;
+
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
+ }
+ }
+ else if (status != HTTP_ERROR)
+ {
+ /*
+ * Flush any error message...
+ */
+
+ httpFlush(http);
+
+ /*
+ * Then handle encryption and authentication...
+ */
+
+ if (status == HTTP_UNAUTHORIZED)
+ {
+ /*
+ * See if we can do authentication...
+ */
+
+ DEBUG_puts("2cupsGetResponse: Need authorization...");
+
+ if (!cupsDoAuthentication(http, "POST", resource))
+ httpReconnect(http);
+ else
+ status = HTTP_AUTHORIZATION_CANCELED;
+ }
+
+#ifdef HAVE_SSL
+ else if (status == HTTP_UPGRADE_REQUIRED)
+ {
+ /*
+ * Force a reconnect with encryption...
+ */
+
+ DEBUG_puts("2cupsGetResponse: Need encryption...");
+
+ if (!httpReconnect(http))
+ httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
+ }
+#endif /* HAVE_SSL */
+ }
+
+ if (response)
+ {
+ ipp_attribute_t *attr; /* status-message attribute */
+
+
+ attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
+
+ DEBUG_printf(("1cupsGetResponse: status-code=%s, status-message=\"%s\"",
+ ippErrorString(response->request.status.status_code),
+ attr ? attr->values[0].string.text : ""));
+
+ _cupsSetError(response->request.status.status_code,
+ attr ? attr->values[0].string.text :
+ ippErrorString(response->request.status.status_code), 0);
+ }
+ else if (status != HTTP_OK)
+ _cupsSetHTTPError(status);
+
+ return (response);
+}
+
+
+/*
+ * 'cupsLastError()' - Return the last IPP status code.
+ */
+
+ipp_status_t /* O - IPP status code from last request */
+cupsLastError(void)
+{
+ return (_cupsGlobals()->last_error);
+}
+
+
+/*
+ * 'cupsLastErrorString()' - Return the last IPP status-message.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+const char * /* O - status-message text from last request */
+cupsLastErrorString(void)
+{
+ return (_cupsGlobals()->last_status_message);
+}
+
+
+/*
+ * '_cupsNextDelay()' - Return the next retry delay value.
+ *
+ * This function currently returns the Fibonacci sequence 1 1 2 3 5 8.
+ *
+ * Pass 0 for the current delay value to initialize the sequence.
+ */
+
+int /* O - Next delay value */
+_cupsNextDelay(int current, /* I - Current delay value or 0 */
+ int *previous) /* IO - Previous delay value */
+{
+ int next; /* Next delay value */
+
+
+ if (current > 0)
+ {
+ next = (current + *previous) % 12;
+ *previous = next < current ? 0 : current;
+ }
+ else
+ {
+ next = 1;
+ *previous = 0;
+ }
+
+ return (next);
+}
+
+
+/*
+ * 'cupsReadResponseData()' - Read additional data after the IPP response.
+ *
+ * This function is used after cupsGetResponse() to read the PPD or document
+ * files for CUPS_GET_PPD and CUPS_GET_DOCUMENT requests, respectively.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+ssize_t /* O - Bytes read, 0 on EOF, -1 on error */
+cupsReadResponseData(
+ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ char *buffer, /* I - Buffer to use */
+ size_t length) /* I - Number of bytes to read */
+{
+ /*
+ * Get the default connection as needed...
+ */
+
+ DEBUG_printf(("cupsReadResponseData(http=%p, buffer=%p, "
+ "length=" CUPS_LLFMT ")", http, buffer, CUPS_LLCAST length));
+
+ if (!http)
+ {
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Pointer to library globals */
+
+ if ((http = cg->http) == NULL)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, _("No active connection"), 1);
+ return (-1);
+ }
+ }
+
+ /*
+ * Then read from the HTTP connection...
+ */
+
+ return (httpRead2(http, buffer, length));
+}
+
+
+/*
+ * 'cupsSendRequest()' - Send an IPP request.
+ *
+ * Use httpWrite() to write any additional data (document, PPD file, etc.)
+ * for the request, cupsGetResponse() to get the IPP response, and httpRead()
+ * to read any additional data following the response. Only one request can be
+ * sent/queued at a time.
+ *
+ * Unlike cupsDoFileRequest(), cupsDoIORequest(), and cupsDoRequest(), the
+ * request is not freed.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+http_status_t /* O - Initial HTTP status */
+cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ ipp_t *request, /* I - IPP request */
+ const char *resource, /* I - Resource path */
+ size_t length) /* I - Length of data to follow or @code CUPS_LENGTH_VARIABLE@ */
+{
+ http_status_t status; /* Status of HTTP request */
+ int got_status; /* Did we get the status? */
+ ipp_state_t state; /* State of IPP processing */
+ http_status_t expect; /* Expect: header to use */
+
+
+ DEBUG_printf(("cupsSendRequest(http=%p, request=%p(%s), resource=\"%s\", "
+ "length=" CUPS_LLFMT ")", http, request,
+ request ? ippOpString(request->request.op.operation_id) : "?",
+ resource, CUPS_LLCAST length));
+
+ /*
+ * Range check input...
+ */
+
+ if (!request || !resource)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
+
+ return (HTTP_ERROR);
+ }
+
+ /*
+ * Get the default connection as needed...
+ */
+
+ if (!http)
+ if ((http = _cupsConnect()) == NULL)
+ return (HTTP_SERVICE_UNAVAILABLE);
+
+#ifdef HAVE_SSL
+ /*
+ * See if we have an auth-info attribute and are communicating over
+ * a non-local link. If so, encrypt the link so that we can pass
+ * the authentication information securely...
+ */
+
+ if (ippFindAttribute(request, "auth-info", IPP_TAG_TEXT) &&
+ !httpAddrLocalhost(http->hostaddr) && !http->tls &&
+ httpEncryption(http, HTTP_ENCRYPT_REQUIRED))
+ {
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
+ return (HTTP_SERVICE_UNAVAILABLE);
+ }
+#endif /* HAVE_SSL */
+
+ /*
+ * Reconnect if the last response had a "Connection: close"...
+ */
+
+ if (!_cups_strcasecmp(http->fields[HTTP_FIELD_CONNECTION], "close"))
+ if (httpReconnect(http))
+ {
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
+ return (HTTP_SERVICE_UNAVAILABLE);
+ }
+
+ /*
+ * Loop until we can send the request without authorization problems.
+ */
+
+ expect = HTTP_CONTINUE;
+
+ for (;;)
+ {
+ DEBUG_puts("2cupsSendRequest: Setup...");
+
+ /*
+ * Setup the HTTP variables needed...
+ */
+
+ httpClearFields(http);
+ httpSetExpect(http, expect);
+ httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
+ httpSetLength(http, length);
+
+#ifdef HAVE_GSSAPI
+ if (http->authstring && !strncmp(http->authstring, "Negotiate", 9))
+ {
+ /*
+ * Do not use cached Kerberos credentials since they will look like a
+ * "replay" attack...
+ */
+
+ _cupsSetNegotiateAuthString(http, "POST", resource);
+ }
+#endif /* HAVE_GSSAPI */
+
+ httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
+
+ DEBUG_printf(("2cupsSendRequest: authstring=\"%s\"", http->authstring));
+
+ /*
+ * Try the request...
+ */
+
+ DEBUG_puts("2cupsSendRequest: Sending HTTP POST...");
+
+ if (httpPost(http, resource))
+ {
+ if (httpReconnect(http))
+ {
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
+ return (HTTP_SERVICE_UNAVAILABLE);
+ }
+ else
+ continue;
+ }
+
+ /*
+ * Send the IPP data...
+ */
+
+ DEBUG_puts("2cupsSendRequest: Writing IPP request...");
+
+ request->state = IPP_IDLE;
+ status = HTTP_CONTINUE;
+ got_status = 0;
+
+ while ((state = ippWrite(http, request)) != IPP_DATA)
+ if (state == IPP_ERROR)
+ break;
+ else if (httpCheck(http))
+ {
+ got_status = 1;
+
+ _httpUpdate(http, &status);
+ if (status >= HTTP_MULTIPLE_CHOICES)
+ break;
+ }
+
+ if (state == IPP_ERROR)
+ {
+ http->status = HTTP_ERROR;
+ http->state = HTTP_WAITING;
+
+ return (HTTP_ERROR);
+ }
+
+ /*
+ * Wait up to 1 second to get the 100-continue response as needed...
+ */
+
+ if (!got_status)
+ {
+ if (expect == HTTP_CONTINUE)
+ {
+ DEBUG_puts("2cupsSendRequest: Waiting for 100-continue...");
+
+ if (httpWait(http, 1000))
+ _httpUpdate(http, &status);
+ }
+ else if (httpCheck(http))
+ _httpUpdate(http, &status);
+ }
+
+ DEBUG_printf(("2cupsSendRequest: status=%d", status));
+
+ /*
+ * Process the current HTTP status...
+ */
+
+ if (status >= HTTP_MULTIPLE_CHOICES)
+ httpFlush(http);
+
+ switch (status)
+ {
+ case HTTP_ERROR :
+ case HTTP_CONTINUE :
+ case HTTP_OK :
+ return (status);
+
+ case HTTP_UNAUTHORIZED :
+ if (cupsDoAuthentication(http, "POST", resource))
+ return (HTTP_AUTHORIZATION_CANCELED);
+
+ if (httpReconnect(http))
+ {
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
+ return (HTTP_SERVICE_UNAVAILABLE);
+ }
+ break;
+
+#ifdef HAVE_SSL
+ case HTTP_UPGRADE_REQUIRED :
+ /*
+ * Flush any error message, reconnect, and then upgrade with
+ * encryption...
+ */
+
+ if (httpReconnect(http))
+ {
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
+ return (HTTP_SERVICE_UNAVAILABLE);
+ }
+
+ if (httpEncryption(http, HTTP_ENCRYPT_REQUIRED))
+ {
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
+ return (HTTP_SERVICE_UNAVAILABLE);
+ }
+ break;
+#endif /* HAVE_SSL */
+
+ case HTTP_EXPECTATION_FAILED :
+ /*
+ * Don't try using the Expect: header the next time around...
+ */
+
+ expect = (http_status_t)0;
+
+ if (httpReconnect(http))
+ {
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
+ return (HTTP_SERVICE_UNAVAILABLE);
+ }
+ break;
+
+ default :
+ /*
+ * Some other error...
+ */
+
+ return (status);
+ }
+ }
+}
+
+
+/*
+ * 'cupsWriteRequestData()' - Write additional data after an IPP request.
+ *
+ * This function is used after @link cupsSendRequest@ to provide a PPD and
+ * after @link cupsStartDocument@ to provide a document file.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+http_status_t /* O - @code HTTP_CONTINUE@ if OK or HTTP status on error */
+cupsWriteRequestData(
+ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *buffer, /* I - Bytes to write */
+ size_t length) /* I - Number of bytes to write */
+{
+ int wused; /* Previous bytes in buffer */
+
+
+ /*
+ * Get the default connection as needed...
+ */
+
+ DEBUG_printf(("cupsWriteRequestData(http=%p, buffer=%p, "
+ "length=" CUPS_LLFMT ")", http, buffer, CUPS_LLCAST length));
+
+ if (!http)
+ {
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Pointer to library globals */
+
+ if ((http = cg->http) == NULL)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, _("No active connection"), 1);
+ DEBUG_puts("1cupsWriteRequestData: Returning HTTP_ERROR.");
+ return (HTTP_ERROR);
+ }
+ }
+
+ /*
+ * Then write to the HTTP connection...
+ */
+
+ wused = http->wused;
+
+ if (httpWrite2(http, buffer, length) < 0)
+ {
+ DEBUG_puts("1cupsWriteRequestData: Returning HTTP_ERROR.");
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(http->error), 0);
+ return (HTTP_ERROR);
+ }
+
+ /*
+ * Finally, check if we have any pending data from the server...
+ */
+
+ if (length >= HTTP_MAX_BUFFER ||
+ http->wused < wused ||
+ (wused > 0 && http->wused == length))
+ {
+ /*
+ * We've written something to the server, so check for response data...
+ */
+
+ if (_httpWait(http, 0, 1))
+ {
+ http_status_t status; /* Status from _httpUpdate */
+
+ _httpUpdate(http, &status);
+ if (status >= HTTP_MULTIPLE_CHOICES)
+ {
+ _cupsSetHTTPError(status);
+ httpFlush(http);
+ }
+
+ DEBUG_printf(("1cupsWriteRequestData: Returning %d.\n", status));
+ return (status);
+ }
+ }
+
+ DEBUG_puts("1cupsWriteRequestData: Returning HTTP_CONTINUE.");
+ return (HTTP_CONTINUE);
+}
+
+
+/*
+ * '_cupsConnect()' - Get the default server connection...
+ */
+
+http_t * /* O - HTTP connection */
+_cupsConnect(void)
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ /*
+ * See if we are connected to the same server...
+ */
+
+ if (cg->http)
+ {
+ /*
+ * Compare the connection hostname, port, and encryption settings to
+ * the cached defaults; these were initialized the first time we
+ * connected...
+ */
+
+ if (strcmp(cg->http->hostname, cg->server) ||
+ cg->ipp_port != _httpAddrPort(cg->http->hostaddr) ||
+ (cg->http->encryption != cg->encryption &&
+ cg->http->encryption == HTTP_ENCRYPT_NEVER))
+ {
+ /*
+ * Need to close the current connection because something has changed...
+ */
+
+ httpClose(cg->http);
+ cg->http = NULL;
+ }
+ }
+
+ /*
+ * (Re)connect as needed...
+ */
+
+ if (!cg->http)
+ {
+ if ((cg->http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ if (errno)
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
+ else
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE,
+ _("Unable to connect to host."), 1);
+ }
+ }
+
+ /*
+ * Return the cached connection...
+ */
+
+ return (cg->http);
+}
+
+
+/*
+ * '_cupsSetError()' - Set the last IPP status code and status-message.
+ */
+
+void
+_cupsSetError(ipp_status_t status, /* I - IPP status code */
+ const char *message, /* I - status-message value */
+ int localize) /* I - Localize the message? */
+{
+ _cups_globals_t *cg; /* Global data */
+
+
+ if (!message && errno)
+ {
+ message = strerror(errno);
+ localize = 0;
+ }
+
+ cg = _cupsGlobals();
+ cg->last_error = status;
+
+ if (cg->last_status_message)
+ {
+ _cupsStrFree(cg->last_status_message);
+
+ cg->last_status_message = NULL;
+ }
+
+ if (message)
+ {
+ if (localize)
+ {
+ /*
+ * Get the message catalog...
+ */
+
+ if (!cg->lang_default)
+ cg->lang_default = cupsLangDefault();
+
+ cg->last_status_message = _cupsStrAlloc(_cupsLangString(cg->lang_default,
+ message));
+ }
+ else
+ cg->last_status_message = _cupsStrAlloc(message);
+ }
+
+ DEBUG_printf(("4_cupsSetError: last_error=%s, last_status_message=\"%s\"",
+ ippErrorString(cg->last_error), cg->last_status_message));
+}
+
+
+/*
+ * '_cupsSetHTTPError()' - Set the last error using the HTTP status.
+ */
+
+void
+_cupsSetHTTPError(http_status_t status) /* I - HTTP status code */
+{
+ switch (status)
+ {
+ case HTTP_NOT_FOUND :
+ _cupsSetError(IPP_NOT_FOUND, httpStatus(status), 0);
+ break;
+
+ case HTTP_UNAUTHORIZED :
+ _cupsSetError(IPP_NOT_AUTHENTICATED, httpStatus(status), 0);
+ break;
+
+ case HTTP_AUTHORIZATION_CANCELED :
+ _cupsSetError(IPP_AUTHENTICATION_CANCELED, httpStatus(status), 0);
+ break;
+
+ case HTTP_FORBIDDEN :
+ _cupsSetError(IPP_FORBIDDEN, httpStatus(status), 0);
+ break;
+
+ case HTTP_BAD_REQUEST :
+ _cupsSetError(IPP_BAD_REQUEST, httpStatus(status), 0);
+ break;
+
+ case HTTP_REQUEST_TOO_LARGE :
+ _cupsSetError(IPP_REQUEST_VALUE, httpStatus(status), 0);
+ break;
+
+ case HTTP_NOT_IMPLEMENTED :
+ _cupsSetError(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status), 0);
+ break;
+
+ case HTTP_NOT_SUPPORTED :
+ _cupsSetError(IPP_VERSION_NOT_SUPPORTED, httpStatus(status), 0);
+ break;
+
+ case HTTP_UPGRADE_REQUIRED :
+ _cupsSetError(IPP_UPGRADE_REQUIRED, httpStatus(status), 0);
+ break;
+
+ case HTTP_PKI_ERROR :
+ _cupsSetError(IPP_PKI_ERROR, httpStatus(status), 0);
+ break;
+
+ case HTTP_ERROR :
+ _cupsSetError(IPP_INTERNAL_ERROR, httpStatus(status), 0);
+ break;
+
+ default :
+ DEBUG_printf(("4_cupsSetHTTPError: HTTP error %d mapped to "
+ "IPP_SERVICE_UNAVAILABLE!", status));
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status), 0);
+ break;
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/sidechannel.c b/cups/sidechannel.c
new file mode 100644
index 000000000..f795b6210
--- /dev/null
+++ b/cups/sidechannel.c
@@ -0,0 +1,575 @@
+/*
+ * "$Id$"
+ *
+ * Side-channel API code for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsSideChannelDoRequest() - Send a side-channel command to a backend and
+ * wait for a response.
+ * cupsSideChannelRead() - Read a side-channel message.
+ * cupsSideChannelSNMPGet() - Query a SNMP OID's value.
+ * cupsSideChannelSNMPWalk() - Query multiple SNMP OID values.
+ * cupsSideChannelWrite() - Write a side-channel message.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "sidechannel.h"
+#include "string-private.h"
+#include "debug-private.h"
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+#endif /* WIN32 */
+#ifdef __hpux
+# include <sys/time.h>
+#elif !defined(WIN32)
+# include <sys/select.h>
+#endif /* __hpux */
+#ifndef WIN32
+# include <sys/time.h>
+#endif /* !WIN32 */
+#ifdef HAVE_POLL
+# include <sys/poll.h>
+#endif /* HAVE_POLL */
+
+
+/*
+ * 'cupsSideChannelDoRequest()' - Send a side-channel command to a backend and wait for a response.
+ *
+ * This function is normally only called by filters, drivers, or port
+ * monitors in order to communicate with the backend used by the current
+ * printer. Programs must be prepared to handle timeout or "not
+ * implemented" status codes, which indicate that the backend or device
+ * do not support the specified side-channel command.
+ *
+ * The "datalen" parameter must be initialized to the size of the buffer
+ * pointed to by the "data" parameter. cupsSideChannelDoRequest() will
+ * update the value to contain the number of data bytes in the buffer.
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+cups_sc_status_t /* O - Status of command */
+cupsSideChannelDoRequest(
+ cups_sc_command_t command, /* I - Command to send */
+ char *data, /* O - Response data buffer pointer */
+ int *datalen, /* IO - Size of data buffer on entry, number of bytes in buffer on return */
+ double timeout) /* I - Timeout in seconds */
+{
+ cups_sc_status_t status; /* Status of command */
+ cups_sc_command_t rcommand; /* Response command */
+
+
+ if (cupsSideChannelWrite(command, CUPS_SC_STATUS_NONE, NULL, 0, timeout))
+ return (CUPS_SC_STATUS_TIMEOUT);
+
+ if (cupsSideChannelRead(&rcommand, &status, data, datalen, timeout))
+ return (CUPS_SC_STATUS_TIMEOUT);
+
+ if (rcommand != command)
+ return (CUPS_SC_STATUS_BAD_MESSAGE);
+
+ return (status);
+}
+
+
+/*
+ * 'cupsSideChannelRead()' - Read a side-channel message.
+ *
+ * This function is normally only called by backend programs to read
+ * commands from a filter, driver, or port monitor program. The
+ * caller must be prepared to handle incomplete or invalid messages
+ * and return the corresponding status codes.
+ *
+ * The "datalen" parameter must be initialized to the size of the buffer
+ * pointed to by the "data" parameter. cupsSideChannelDoRequest() will
+ * update the value to contain the number of data bytes in the buffer.
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsSideChannelRead(
+ cups_sc_command_t *command, /* O - Command code */
+ cups_sc_status_t *status, /* O - Status code */
+ char *data, /* O - Data buffer pointer */
+ int *datalen, /* IO - Size of data buffer on entry, number of bytes in buffer on return */
+ double timeout) /* I - Timeout in seconds */
+{
+ char buffer[16388]; /* Message buffer */
+ int bytes; /* Bytes read */
+ int templen; /* Data length from message */
+ int nfds; /* Number of file descriptors */
+#ifdef HAVE_POLL
+ struct pollfd pfd; /* Poll structure for poll() */
+#else /* select() */
+ fd_set input_set; /* Input set for select() */
+ struct timeval stimeout; /* Timeout value for select() */
+#endif /* HAVE_POLL */
+
+
+ DEBUG_printf(("cupsSideChannelRead(command=%p, status=%p, data=%p, "
+ "datalen=%p(%d), timeout=%.3f)", command, status, data,
+ datalen, datalen ? *datalen : -1, timeout));
+
+ /*
+ * Range check input...
+ */
+
+ if (!command || !status)
+ return (-1);
+
+ /*
+ * See if we have pending data on the side-channel socket...
+ */
+
+#ifdef HAVE_POLL
+ pfd.fd = CUPS_SC_FD;
+ pfd.events = POLLIN;
+
+ while ((nfds = poll(&pfd, 1,
+ timeout < 0.0 ? -1 : (long)(timeout * 1000))) < 0 &&
+ (errno == EINTR || errno == EAGAIN))
+ ;
+
+#else /* select() */
+ FD_ZERO(&input_set);
+ FD_SET(CUPS_SC_FD, &input_set);
+
+ stimeout.tv_sec = (int)timeout;
+ stimeout.tv_usec = (int)(timeout * 1000000) % 1000000;
+
+ while ((nfds = select(CUPS_SC_FD + 1, &input_set, NULL, NULL,
+ timeout < 0.0 ? NULL : &stimeout)) < 0 &&
+ (errno == EINTR || errno == EAGAIN))
+ ;
+
+#endif /* HAVE_POLL */
+
+ if (nfds < 1)
+ {
+ *status = nfds==0 ? CUPS_SC_STATUS_TIMEOUT : CUPS_SC_STATUS_IO_ERROR;
+ return (-1);
+ }
+
+ /*
+ * Read a side-channel message for the format:
+ *
+ * Byte(s) Description
+ * ------- -------------------------------------------
+ * 0 Command code
+ * 1 Status code
+ * 2-3 Data length (network byte order) <= 16384
+ * 4-N Data
+ */
+
+ while ((bytes = read(CUPS_SC_FD, buffer, sizeof(buffer))) < 0)
+ if (errno != EINTR && errno != EAGAIN)
+ {
+ DEBUG_printf(("1cupsSideChannelRead: Read error: %s", strerror(errno)));
+ *command = CUPS_SC_CMD_NONE;
+ *status = CUPS_SC_STATUS_IO_ERROR;
+ return (-1);
+ }
+
+ /*
+ * Watch for EOF or too few bytes...
+ */
+
+ if (bytes < 4)
+ {
+ DEBUG_printf(("1cupsSideChannelRead: Short read of %d bytes", bytes));
+ *command = CUPS_SC_CMD_NONE;
+ *status = CUPS_SC_STATUS_BAD_MESSAGE;
+ return (-1);
+ }
+
+ /*
+ * Validate the command code in the message...
+ */
+
+ if (buffer[0] < CUPS_SC_CMD_SOFT_RESET ||
+ buffer[0] >= CUPS_SC_CMD_MAX)
+ {
+ DEBUG_printf(("1cupsSideChannelRead: Bad command %d!", buffer[0]));
+ *command = CUPS_SC_CMD_NONE;
+ *status = CUPS_SC_STATUS_BAD_MESSAGE;
+ return (-1);
+ }
+
+ *command = (cups_sc_command_t)buffer[0];
+
+ /*
+ * Validate the data length in the message...
+ */
+
+ templen = ((buffer[2] & 255) << 8) | (buffer[3] & 255);
+
+ if (templen > 0 && (!data || !datalen))
+ {
+ /*
+ * Either the response is bigger than the provided buffer or the
+ * response is bigger than we've read...
+ */
+
+ *status = CUPS_SC_STATUS_TOO_BIG;
+ }
+ else if (!datalen || templen > *datalen || templen > (bytes - 4))
+ {
+ /*
+ * Either the response is bigger than the provided buffer or the
+ * response is bigger than we've read...
+ */
+
+ *status = CUPS_SC_STATUS_TOO_BIG;
+ }
+ else
+ {
+ /*
+ * The response data will fit, copy it over and provide the actual
+ * length...
+ */
+
+ *status = (cups_sc_status_t)buffer[1];
+ *datalen = templen;
+
+ memcpy(data, buffer + 4, templen);
+ }
+
+ DEBUG_printf(("1cupsSideChannelRead: Returning status=%d", *status));
+
+ return (0);
+}
+
+
+/*
+ * 'cupsSideChannelSNMPGet()' - Query a SNMP OID's value.
+ *
+ * This function asks the backend to do a SNMP OID query on behalf of the
+ * filter, port monitor, or backend using the default community name.
+ *
+ * "oid" contains a numeric OID consisting of integers separated by periods,
+ * for example ".1.3.6.1.2.1.43". Symbolic names from SNMP MIBs are not
+ * supported and must be converted to their numeric forms.
+ *
+ * On input, "data" and "datalen" provide the location and size of the
+ * buffer to hold the OID value as a string. HEX-String (binary) values are
+ * converted to hexadecimal strings representing the binary data, while
+ * NULL-Value and unknown OID types are returned as the empty string.
+ * The returned "datalen" does not include the trailing nul.
+ *
+ * @code CUPS_SC_STATUS_NOT_IMPLEMENTED@ is returned by backends that do not
+ * support SNMP queries. @code CUPS_SC_STATUS_NO_RESPONSE@ is returned when
+ * the printer does not respond to the SNMP query.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+cups_sc_status_t /* O - Query status */
+cupsSideChannelSNMPGet(
+ const char *oid, /* I - OID to query */
+ char *data, /* I - Buffer for OID value */
+ int *datalen, /* IO - Size of OID buffer on entry, size of value on return */
+ double timeout) /* I - Timeout in seconds */
+{
+ cups_sc_status_t status; /* Status of command */
+ cups_sc_command_t rcommand; /* Response command */
+ char real_data[2048];/* Real data buffer for response */
+ int real_datalen, /* Real length of data buffer */
+ real_oidlen; /* Length of returned OID string */
+
+
+ DEBUG_printf(("cupsSideChannelSNMPGet(oid=\"%s\", data=%p, datalen=%p(%d), "
+ "timeout=%.3f)", oid, data, datalen, datalen ? *datalen : -1,
+ timeout));
+
+ /*
+ * Range check input...
+ */
+
+ if (!oid || !*oid || !data || !datalen || *datalen < 2)
+ return (CUPS_SC_STATUS_BAD_MESSAGE);
+
+ *data = '\0';
+
+ /*
+ * Send the request to the backend and wait for a response...
+ */
+
+ if (cupsSideChannelWrite(CUPS_SC_CMD_SNMP_GET, CUPS_SC_STATUS_NONE, oid,
+ (int)strlen(oid) + 1, timeout))
+ return (CUPS_SC_STATUS_TIMEOUT);
+
+ real_datalen = sizeof(real_data);
+ if (cupsSideChannelRead(&rcommand, &status, real_data, &real_datalen, timeout))
+ return (CUPS_SC_STATUS_TIMEOUT);
+
+ if (rcommand != CUPS_SC_CMD_SNMP_GET)
+ return (CUPS_SC_STATUS_BAD_MESSAGE);
+
+ if (status == CUPS_SC_STATUS_OK)
+ {
+ /*
+ * Parse the response of the form "oid\0value"...
+ */
+
+ real_oidlen = strlen(real_data) + 1;
+ real_datalen -= real_oidlen;
+
+ if ((real_datalen + 1) > *datalen)
+ return (CUPS_SC_STATUS_TOO_BIG);
+
+ memcpy(data, real_data + real_oidlen, real_datalen);
+ data[real_datalen] = '\0';
+
+ *datalen = real_datalen;
+ }
+
+ return (status);
+}
+
+
+/*
+ * 'cupsSideChannelSNMPWalk()' - Query multiple SNMP OID values.
+ *
+ * This function asks the backend to do multiple SNMP OID queries on behalf
+ * of the filter, port monitor, or backend using the default community name.
+ * All OIDs under the "parent" OID are queried and the results are sent to
+ * the callback function you provide.
+ *
+ * "oid" contains a numeric OID consisting of integers separated by periods,
+ * for example ".1.3.6.1.2.1.43". Symbolic names from SNMP MIBs are not
+ * supported and must be converted to their numeric forms.
+ *
+ * "timeout" specifies the timeout for each OID query. The total amount of
+ * time will depend on the number of OID values found and the time required
+ * for each query.
+ *
+ * "cb" provides a function to call for every value that is found. "context"
+ * is an application-defined pointer that is sent to the callback function
+ * along with the OID and current data. The data passed to the callback is the
+ * same as returned by @link cupsSideChannelSNMPGet@.
+ *
+ * @code CUPS_SC_STATUS_NOT_IMPLEMENTED@ is returned by backends that do not
+ * support SNMP queries. @code CUPS_SC_STATUS_NO_RESPONSE@ is returned when
+ * the printer does not respond to the first SNMP query.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+cups_sc_status_t /* O - Status of first query of @code CUPS_SC_STATUS_OK@ on success */
+cupsSideChannelSNMPWalk(
+ const char *oid, /* I - First numeric OID to query */
+ double timeout, /* I - Timeout for each query in seconds */
+ cups_sc_walk_func_t cb, /* I - Function to call with each value */
+ void *context) /* I - Application-defined pointer to send to callback */
+{
+ cups_sc_status_t status; /* Status of command */
+ cups_sc_command_t rcommand; /* Response command */
+ char real_data[2048];/* Real data buffer for response */
+ int real_datalen, /* Real length of data buffer */
+ real_oidlen, /* Length of returned OID string */
+ oidlen; /* Length of first OID */
+ const char *current_oid; /* Current OID */
+ char last_oid[2048]; /* Last OID */
+
+
+ DEBUG_printf(("cupsSideChannelSNMPWalk(oid=\"%s\", timeout=%.3f, cb=%p, "
+ "context=%p)", oid, timeout, cb, context));
+
+ /*
+ * Range check input...
+ */
+
+ if (!oid || !*oid || !cb)
+ return (CUPS_SC_STATUS_BAD_MESSAGE);
+
+ /*
+ * Loop until the OIDs don't match...
+ */
+
+ current_oid = oid;
+ oidlen = (int)strlen(oid);
+ last_oid[0] = '\0';
+
+ do
+ {
+ /*
+ * Send the request to the backend and wait for a response...
+ */
+
+ if (cupsSideChannelWrite(CUPS_SC_CMD_SNMP_GET_NEXT, CUPS_SC_STATUS_NONE,
+ current_oid, (int)strlen(current_oid) + 1, timeout))
+ return (CUPS_SC_STATUS_TIMEOUT);
+
+ real_datalen = sizeof(real_data);
+ if (cupsSideChannelRead(&rcommand, &status, real_data, &real_datalen,
+ timeout))
+ return (CUPS_SC_STATUS_TIMEOUT);
+
+ if (rcommand != CUPS_SC_CMD_SNMP_GET_NEXT)
+ return (CUPS_SC_STATUS_BAD_MESSAGE);
+
+ if (status == CUPS_SC_STATUS_OK)
+ {
+ /*
+ * Parse the response of the form "oid\0value"...
+ */
+
+ if (strncmp(real_data, oid, oidlen) || real_data[oidlen] != '.' ||
+ !strcmp(real_data, last_oid))
+ {
+ /*
+ * Done with this set of OIDs...
+ */
+
+ return (CUPS_SC_STATUS_OK);
+ }
+
+ if (real_datalen < sizeof(real_data))
+ real_data[real_datalen] = '\0';
+
+ real_oidlen = strlen(real_data) + 1;
+ real_datalen -= real_oidlen;
+
+ /*
+ * Call the callback with the OID and data...
+ */
+
+ (*cb)(real_data, real_data + real_oidlen, real_datalen, context);
+
+ /*
+ * Update the current OID...
+ */
+
+ current_oid = real_data;
+ strlcpy(last_oid, current_oid, sizeof(last_oid));
+ }
+ }
+ while (status == CUPS_SC_STATUS_OK);
+
+ return (status);
+}
+
+
+/*
+ * 'cupsSideChannelWrite()' - Write a side-channel message.
+ *
+ * This function is normally only called by backend programs to send
+ * responses to a filter, driver, or port monitor program.
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsSideChannelWrite(
+ cups_sc_command_t command, /* I - Command code */
+ cups_sc_status_t status, /* I - Status code */
+ const char *data, /* I - Data buffer pointer */
+ int datalen, /* I - Number of bytes of data */
+ double timeout) /* I - Timeout in seconds */
+{
+ char buffer[16388]; /* Message buffer */
+ int bytes; /* Bytes written */
+#ifdef HAVE_POLL
+ struct pollfd pfd; /* Poll structure for poll() */
+#else /* select() */
+ fd_set output_set; /* Output set for select() */
+ struct timeval stimeout; /* Timeout value for select() */
+#endif /* HAVE_POLL */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (command < CUPS_SC_CMD_SOFT_RESET || command >= CUPS_SC_CMD_MAX ||
+ datalen < 0 || datalen > 16384 || (datalen > 0 && !data))
+ return (-1);
+
+ /*
+ * See if we can safely write to the side-channel socket...
+ */
+
+#ifdef HAVE_POLL
+ pfd.fd = CUPS_SC_FD;
+ pfd.events = POLLOUT;
+
+ if (timeout < 0.0)
+ {
+ if (poll(&pfd, 1, -1) < 1)
+ return (-1);
+ }
+ else if (poll(&pfd, 1, (long)(timeout * 1000)) < 1)
+ return (-1);
+
+#else /* select() */
+ FD_ZERO(&output_set);
+ FD_SET(CUPS_SC_FD, &output_set);
+
+ if (timeout < 0.0)
+ {
+ if (select(CUPS_SC_FD + 1, NULL, &output_set, NULL, NULL) < 1)
+ return (-1);
+ }
+ else
+ {
+ stimeout.tv_sec = (int)timeout;
+ stimeout.tv_usec = (int)(timeout * 1000000) % 1000000;
+
+ if (select(CUPS_SC_FD + 1, NULL, &output_set, NULL, &stimeout) < 1)
+ return (-1);
+ }
+#endif /* HAVE_POLL */
+
+ /*
+ * Write a side-channel message in the format:
+ *
+ * Byte(s) Description
+ * ------- -------------------------------------------
+ * 0 Command code
+ * 1 Status code
+ * 2-3 Data length (network byte order) <= 16384
+ * 4-N Data
+ */
+
+ buffer[0] = command;
+ buffer[1] = status;
+ buffer[2] = datalen >> 8;
+ buffer[3] = datalen & 255;
+
+ bytes = 4;
+
+ if (datalen > 0)
+ {
+ memcpy(buffer + 4, data, datalen);
+ bytes += datalen;
+ }
+
+ while (write(CUPS_SC_FD, buffer, bytes) < 0)
+ if (errno != EINTR && errno != EAGAIN)
+ return (-1);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/sidechannel.h b/cups/sidechannel.h
new file mode 100644
index 000000000..ac91a5292
--- /dev/null
+++ b/cups/sidechannel.h
@@ -0,0 +1,147 @@
+/*
+ * "$Id$"
+ *
+ * Side-channel API definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_SIDECHANNEL_H_
+# define _CUPS_SIDECHANNEL_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include "versioning.h"
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Constants...
+ */
+
+#define CUPS_SC_FD 4 /* File descriptor for select/poll */
+
+
+/*
+ * Enumerations...
+ */
+
+enum cups_sc_bidi_e /**** Bidirectional capability values ****/
+{
+ CUPS_SC_BIDI_NOT_SUPPORTED = 0, /* Bidirectional I/O is not supported */
+ CUPS_SC_BIDI_SUPPORTED = 1 /* Bidirectional I/O is supported */
+};
+typedef enum cups_sc_bidi_e cups_sc_bidi_t;
+ /**** Bidirectional capabilities ****/
+
+enum cups_sc_command_e /**** Request command codes ****/
+{
+ CUPS_SC_CMD_NONE = 0, /* No command @private@ */
+ CUPS_SC_CMD_SOFT_RESET = 1, /* Do a soft reset */
+ CUPS_SC_CMD_DRAIN_OUTPUT = 2, /* Drain all pending output */
+ CUPS_SC_CMD_GET_BIDI = 3, /* Return bidirectional capabilities */
+ CUPS_SC_CMD_GET_DEVICE_ID = 4, /* Return the IEEE-1284 device ID */
+ CUPS_SC_CMD_GET_STATE = 5, /* Return the device state */
+ CUPS_SC_CMD_SNMP_GET = 6, /* Query an SNMP OID @since CUPS 1.4/Mac OS X 10.6@ */
+ CUPS_SC_CMD_SNMP_GET_NEXT = 7, /* Query the next SNMP OID @since CUPS 1.4/Mac OS X 10.6@ */
+ CUPS_SC_CMD_GET_CONNECTED = 8, /* Return whether the backend is "connected" to the printer @since CUPS 1.5/Mac OS X 10.7@ */
+ CUPS_SC_CMD_MAX /* End of valid values @private@ */
+};
+typedef enum cups_sc_command_e cups_sc_command_t;
+ /**** Request command codes ****/
+
+enum cups_sc_connected_e /**** Connectivity values ****/
+{
+ CUPS_SC_NOT_CONNECTED = 0, /* Backend is not "connected" to printer */
+ CUPS_SC_CONNECTED = 1 /* Backend is "connected" to printer */
+};
+typedef enum cups_sc_connected_e cups_sc_connected_t;
+ /**** Connectivity values ****/
+
+
+enum cups_sc_state_e /**** Printer state bits ****/
+{
+ CUPS_SC_STATE_OFFLINE = 0, /* Device is offline */
+ CUPS_SC_STATE_ONLINE = 1, /* Device is online */
+ CUPS_SC_STATE_BUSY = 2, /* Device is busy */
+ CUPS_SC_STATE_ERROR = 4, /* Other error condition */
+ CUPS_SC_STATE_MEDIA_LOW = 16, /* Paper low condition */
+ CUPS_SC_STATE_MEDIA_EMPTY = 32, /* Paper out condition */
+ CUPS_SC_STATE_MARKER_LOW = 64, /* Toner/ink low condition */
+ CUPS_SC_STATE_MARKER_EMPTY = 128 /* Toner/ink out condition */
+};
+typedef enum cups_sc_state_e cups_sc_state_t;
+ /**** Printer state bits ****/
+
+enum cups_sc_status_e /**** Response status codes ****/
+{
+ CUPS_SC_STATUS_NONE, /* No status */
+ CUPS_SC_STATUS_OK, /* Operation succeeded */
+ CUPS_SC_STATUS_IO_ERROR, /* An I/O error occurred */
+ CUPS_SC_STATUS_TIMEOUT, /* The backend did not respond */
+ CUPS_SC_STATUS_NO_RESPONSE, /* The device did not respond */
+ CUPS_SC_STATUS_BAD_MESSAGE, /* The command/response message was invalid */
+ CUPS_SC_STATUS_TOO_BIG, /* Response too big */
+ CUPS_SC_STATUS_NOT_IMPLEMENTED /* Command not implemented */
+};
+typedef enum cups_sc_status_e cups_sc_status_t;
+ /**** Response status codes ****/
+
+typedef void (*cups_sc_walk_func_t)(const char *oid, const char *data,
+ int datalen, void *context);
+ /**** SNMP walk callback ****/
+
+
+/*
+ * Prototypes...
+ */
+
+extern cups_sc_status_t cupsSideChannelDoRequest(cups_sc_command_t command,
+ char *data, int *datalen,
+ double timeout) _CUPS_API_1_3;
+extern int cupsSideChannelRead(cups_sc_command_t *command,
+ cups_sc_status_t *status,
+ char *data, int *datalen,
+ double timeout) _CUPS_API_1_3;
+extern int cupsSideChannelWrite(cups_sc_command_t command,
+ cups_sc_status_t status,
+ const char *data, int datalen,
+ double timeout) _CUPS_API_1_3;
+
+/**** New in CUPS 1.4 ****/
+extern cups_sc_status_t cupsSideChannelSNMPGet(const char *oid, char *data,
+ int *datalen, double timeout)
+ _CUPS_API_1_4;
+extern cups_sc_status_t cupsSideChannelSNMPWalk(const char *oid, double timeout,
+ cups_sc_walk_func_t cb,
+ void *context) _CUPS_API_1_4;
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_SIDECHANNEL_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/snmp-private.h b/cups/snmp-private.h
new file mode 100644
index 000000000..2c6d95371
--- /dev/null
+++ b/cups/snmp-private.h
@@ -0,0 +1,145 @@
+/*
+ * "$Id$"
+ *
+ * Private SNMP definitions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2006-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_SNMP_PRIVATE_H_
+# define _CUPS_SNMP_PRIVATE_H_
+
+
+/*
+ * Include necessary headers.
+ */
+
+#include <cups/http.h>
+
+
+/*
+ * Constants...
+ */
+
+#define CUPS_SNMP_PORT 161 /* SNMP well-known port */
+#define CUPS_SNMP_MAX_OID 128 /* Maximum number of OID numbers */
+#define CUPS_SNMP_MAX_PACKET 1472 /* Maximum size of SNMP packet */
+#define CUPS_SNMP_MAX_STRING 512 /* Maximum size of string */
+#define CUPS_SNMP_VERSION_1 0 /* SNMPv1 */
+
+
+/*
+ * Types...
+ */
+
+enum cups_asn1_e /**** ASN1 request/object types ****/
+{
+ CUPS_ASN1_END_OF_CONTENTS = 0x00, /* End-of-contents */
+ CUPS_ASN1_BOOLEAN = 0x01, /* BOOLEAN */
+ CUPS_ASN1_INTEGER = 0x02, /* INTEGER or ENUMERATION */
+ CUPS_ASN1_BIT_STRING = 0x03, /* BIT STRING */
+ CUPS_ASN1_OCTET_STRING = 0x04, /* OCTET STRING */
+ CUPS_ASN1_NULL_VALUE = 0x05, /* NULL VALUE */
+ CUPS_ASN1_OID = 0x06, /* OBJECT IDENTIFIER */
+ CUPS_ASN1_SEQUENCE = 0x30, /* SEQUENCE */
+ CUPS_ASN1_HEX_STRING = 0x40, /* Binary string aka Hex-STRING */
+ CUPS_ASN1_COUNTER = 0x41, /* 32-bit unsigned aka Counter32 */
+ CUPS_ASN1_GAUGE = 0x42, /* 32-bit unsigned aka Gauge32 */
+ CUPS_ASN1_TIMETICKS = 0x43, /* 32-bit unsigned aka Timeticks32 */
+ CUPS_ASN1_GET_REQUEST = 0xa0, /* GetRequest-PDU */
+ CUPS_ASN1_GET_NEXT_REQUEST = 0xa1, /* GetNextRequest-PDU */
+ CUPS_ASN1_GET_RESPONSE = 0xa2 /* GetResponse-PDU */
+};
+typedef enum cups_asn1_e cups_asn1_t; /**** ASN1 request/object types ****/
+
+typedef struct cups_snmp_string_s /**** String value ****/
+{
+ unsigned char bytes[CUPS_SNMP_MAX_STRING];
+ /* Bytes in string */
+ int num_bytes; /* Number of bytes */
+} cups_snmp_string_t;
+
+union cups_snmp_value_u /**** Object value ****/
+{
+ int boolean; /* Boolean value */
+ int integer; /* Integer value */
+ unsigned counter; /* Counter value */
+ unsigned gauge; /* Gauge value */
+ unsigned timeticks; /* Timeticks value */
+ int oid[CUPS_SNMP_MAX_OID]; /* OID value */
+ cups_snmp_string_t string; /* String value */
+};
+
+typedef struct cups_snmp_s /**** SNMP data packet ****/
+{
+ const char *error; /* Encode/decode error */
+ http_addr_t address; /* Source address */
+ int version; /* Version number */
+ char community[CUPS_SNMP_MAX_STRING];
+ /* Community name */
+ cups_asn1_t request_type; /* Request type */
+ int request_id; /* request-id value */
+ int error_status; /* error-status value */
+ int error_index; /* error-index value */
+ int object_name[CUPS_SNMP_MAX_OID];
+ /* object-name value */
+ cups_asn1_t object_type; /* object-value type */
+ union cups_snmp_value_u
+ object_value; /* object-value value */
+} cups_snmp_t;
+
+typedef void (*cups_snmp_cb_t)(cups_snmp_t *packet, void *data);
+
+/*
+ * Prototypes...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+extern void _cupsSNMPClose(int fd) _CUPS_API_1_4;
+extern int *_cupsSNMPCopyOID(int *dst, const int *src, int dstsize)
+ _CUPS_API_1_4;
+extern const char *_cupsSNMPDefaultCommunity(void) _CUPS_API_1_4;
+extern int _cupsSNMPIsOID(cups_snmp_t *packet, const int *oid)
+ _CUPS_API_1_4;
+extern int _cupsSNMPIsOIDPrefixed(cups_snmp_t *packet,
+ const int *prefix) _CUPS_API_1_4;
+extern char *_cupsSNMPOIDToString(const int *src, char *dst,
+ size_t dstsize) _CUPS_API_1_4;
+extern int _cupsSNMPOpen(int family) _CUPS_API_1_4;
+extern cups_snmp_t *_cupsSNMPRead(int fd, cups_snmp_t *packet,
+ double timeout) _CUPS_API_1_4;
+extern void _cupsSNMPSetDebug(int level) _CUPS_API_1_4;
+extern int *_cupsSNMPStringToOID(const char *src,
+ int *dst, int dstsize)
+ _CUPS_API_1_4;
+extern int _cupsSNMPWalk(int fd, http_addr_t *address, int version,
+ const char *community, const int *prefix,
+ double timeout, cups_snmp_cb_t cb,
+ void *data) _CUPS_API_1_4;
+extern int _cupsSNMPWrite(int fd, http_addr_t *address, int version,
+ const char *community,
+ cups_asn1_t request_type,
+ const unsigned request_id,
+ const int *oid) _CUPS_API_1_4;
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_SNMP_PRIVATE_H_ */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/snmp.c b/cups/snmp.c
new file mode 100644
index 000000000..69858b17d
--- /dev/null
+++ b/cups/snmp.c
@@ -0,0 +1,1737 @@
+/*
+ * "$Id$"
+ *
+ * SNMP functions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2006-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsSNMPClose() - Close a SNMP socket.
+ * _cupsSNMPCopyOID() - Copy an OID.
+ * _cupsSNMPDefaultCommunity() - Get the default SNMP community name.
+ * _cupsSNMPIsOID() - Test whether a SNMP response contains the
+ * specified OID.
+ * _cupsSNMPIsOIDPrefixed() - Test whether a SNMP response uses the
+ * specified OID prefix.
+ * _cupsSNMPOIDToString() - Convert an OID to a string.
+ * _cupsSNMPOpen() - Open a SNMP socket.
+ * _cupsSNMPRead() - Read and parse a SNMP response.
+ * _cupsSNMPSetDebug() - Enable/disable debug logging to stderr.
+ * _cupsSNMPStringToOID() - Convert a numeric OID string to an OID array.
+ * _cupsSNMPWalk() - Enumerate a group of OIDs.
+ * _cupsSNMPWrite() - Send an SNMP query packet.
+ * asn1_debug() - Decode an ASN1-encoded message.
+ * asn1_decode_snmp() - Decode a SNMP packet.
+ * asn1_encode_snmp() - Encode a SNMP packet.
+ * asn1_get_integer() - Get an integer value.
+ * asn1_get_length() - Get a value length.
+ * asn1_get_oid() - Get an OID value.
+ * asn1_get_packed() - Get a packed integer value.
+ * asn1_get_string() - Get a string value.
+ * asn1_get_type() - Get a value type.
+ * asn1_set_integer() - Set an integer value.
+ * asn1_set_length() - Set a value length.
+ * asn1_set_oid() - Set an OID value.
+ * asn1_set_packed() - Set a packed integer value.
+ * asn1_size_integer() - Figure out the number of bytes needed for an
+ * integer value.
+ * asn1_size_length() - Figure out the number of bytes needed for a
+ * length value.
+ * asn1_size_oid() - Figure out the numebr of bytes needed for an
+ * OID value.
+ * asn1_size_packed() - Figure out the number of bytes needed for a
+ * packed integer value.
+ * snmp_set_error() - Set the localized error for a packet.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "cups-private.h"
+#include "snmp-private.h"
+#ifdef HAVE_POLL
+# include <sys/poll.h>
+#endif /* HAVE_POLL */
+
+
+/*
+ * Local functions...
+ */
+
+static void asn1_debug(const char *prefix, unsigned char *buffer,
+ size_t len, int indent);
+static int asn1_decode_snmp(unsigned char *buffer, size_t len,
+ cups_snmp_t *packet);
+static int asn1_encode_snmp(unsigned char *buffer, size_t len,
+ cups_snmp_t *packet);
+static int asn1_get_integer(unsigned char **buffer,
+ unsigned char *bufend,
+ int length);
+static int asn1_get_oid(unsigned char **buffer,
+ unsigned char *bufend,
+ int length, int *oid, int oidsize);
+static int asn1_get_packed(unsigned char **buffer,
+ unsigned char *bufend);
+static char *asn1_get_string(unsigned char **buffer,
+ unsigned char *bufend,
+ int length, char *string,
+ int strsize);
+static unsigned asn1_get_length(unsigned char **buffer,
+ unsigned char *bufend);
+static int asn1_get_type(unsigned char **buffer,
+ unsigned char *bufend);
+static void asn1_set_integer(unsigned char **buffer,
+ int integer);
+static void asn1_set_length(unsigned char **buffer,
+ unsigned length);
+static void asn1_set_oid(unsigned char **buffer,
+ const int *oid);
+static void asn1_set_packed(unsigned char **buffer,
+ int integer);
+static int asn1_size_integer(int integer);
+static int asn1_size_length(int length);
+static int asn1_size_oid(const int *oid);
+static int asn1_size_packed(int integer);
+static void snmp_set_error(cups_snmp_t *packet,
+ const char *message);
+
+
+/*
+ * '_cupsSNMPClose()' - Close a SNMP socket.
+ */
+
+void
+_cupsSNMPClose(int fd) /* I - SNMP socket file descriptor */
+{
+ DEBUG_printf(("4_cupsSNMPClose(fd=%d)", fd));
+
+#ifdef WIN32
+ closesocket(fd);
+#else
+ close(fd);
+#endif /* WIN32 */
+}
+
+
+/*
+ * '_cupsSNMPCopyOID()' - Copy an OID.
+ *
+ * The array pointed to by "src" is terminated by the value -1.
+ */
+
+int * /* O - New OID */
+_cupsSNMPCopyOID(int *dst, /* I - Destination OID */
+ const int *src, /* I - Source OID */
+ int dstsize) /* I - Number of integers in dst */
+{
+ int i; /* Looping var */
+
+
+ DEBUG_printf(("4_cupsSNMPCopyOID(dst=%p, src=%p, dstsize=%d)", dst, src,
+ dstsize));
+
+ for (i = 0, dstsize --; src[i] >= 0 && i < dstsize; i ++)
+ dst[i] = src[i];
+
+ dst[i] = -1;
+
+ return (dst);
+}
+
+
+/*
+ * '_cupsSNMPDefaultCommunity()' - Get the default SNMP community name.
+ *
+ * The default community name is the first community name found in the
+ * snmp.conf file. If no community name is defined there, "public" is used.
+ */
+
+const char * /* O - Default community name */
+_cupsSNMPDefaultCommunity(void)
+{
+ cups_file_t *fp; /* snmp.conf file */
+ char line[1024], /* Line from file */
+ *value; /* Value from file */
+ int linenum; /* Line number in file */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+
+
+ DEBUG_puts("4_cupsSNMPDefaultCommunity()");
+
+ if (!cg->snmp_community[0])
+ {
+ strlcpy(cg->snmp_community, "public", sizeof(cg->snmp_community));
+
+ snprintf(line, sizeof(line), "%s/snmp.conf", cg->cups_serverroot);
+ if ((fp = cupsFileOpen(line, "r")) != NULL)
+ {
+ linenum = 0;
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ if (!_cups_strcasecmp(line, "Community") && value)
+ {
+ strlcpy(cg->snmp_community, value, sizeof(cg->snmp_community));
+ break;
+ }
+
+ cupsFileClose(fp);
+ }
+ }
+
+ DEBUG_printf(("5_cupsSNMPDefaultCommunity: Returning \"%s\"",
+ cg->snmp_community));
+
+ return (cg->snmp_community);
+}
+
+
+/*
+ * '_cupsSNMPIsOID()' - Test whether a SNMP response contains the specified OID.
+ *
+ * The array pointed to by "oid" is terminated by the value -1.
+ */
+
+int /* O - 1 if equal, 0 if not equal */
+_cupsSNMPIsOID(cups_snmp_t *packet, /* I - Response packet */
+ const int *oid) /* I - OID */
+{
+ int i; /* Looping var */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("4_cupsSNMPIsOID(packet=%p, oid=%p)", packet, oid));
+
+ if (!packet || !oid)
+ {
+ DEBUG_puts("5_cupsSNMPIsOID: Returning 0");
+
+ return (0);
+ }
+
+ /*
+ * Compare OIDs...
+ */
+
+ for (i = 0;
+ i < CUPS_SNMP_MAX_OID && oid[i] >= 0 && packet->object_name[i] >= 0;
+ i ++)
+ if (oid[i] != packet->object_name[i])
+ {
+ DEBUG_puts("5_cupsSNMPIsOID: Returning 0");
+
+ return (0);
+ }
+
+ DEBUG_printf(("5_cupsSNMPIsOID: Returning %d",
+ i < CUPS_SNMP_MAX_OID && oid[i] == packet->object_name[i]));
+
+ return (i < CUPS_SNMP_MAX_OID && oid[i] == packet->object_name[i]);
+}
+
+
+/*
+ * '_cupsSNMPIsOIDPrefixed()' - Test whether a SNMP response uses the specified
+ * OID prefix.
+ *
+ * The array pointed to by "prefix" is terminated by the value -1.
+ */
+
+int /* O - 1 if prefixed, 0 if not prefixed */
+_cupsSNMPIsOIDPrefixed(
+ cups_snmp_t *packet, /* I - Response packet */
+ const int *prefix) /* I - OID prefix */
+{
+ int i; /* Looping var */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("4_cupsSNMPIsOIDPrefixed(packet=%p, prefix=%p)", packet,
+ prefix));
+
+ if (!packet || !prefix)
+ {
+ DEBUG_puts("5_cupsSNMPIsOIDPrefixed: Returning 0");
+
+ return (0);
+ }
+
+ /*
+ * Compare OIDs...
+ */
+
+ for (i = 0;
+ i < CUPS_SNMP_MAX_OID && prefix[i] >= 0 && packet->object_name[i] >= 0;
+ i ++)
+ if (prefix[i] != packet->object_name[i])
+ {
+ DEBUG_puts("5_cupsSNMPIsOIDPrefixed: Returning 0");
+
+ return (0);
+ }
+
+ DEBUG_printf(("5_cupsSNMPIsOIDPrefixed: Returning %d",
+ i < CUPS_SNMP_MAX_OID));
+
+ return (i < CUPS_SNMP_MAX_OID);
+}
+
+
+/*
+ * '_cupsSNMPOIDToString()' - Convert an OID to a string.
+ */
+
+
+char * /* O - New string or @code NULL@ on error */
+_cupsSNMPOIDToString(const int *src, /* I - OID */
+ char *dst, /* I - String buffer */
+ size_t dstsize) /* I - Size of string buffer */
+{
+ char *dstptr, /* Pointer into string buffer */
+ *dstend; /* End of string buffer */
+
+
+ DEBUG_printf(("4_cupsSNMPOIDToString(src=%p, dst=%p, dstsize=" CUPS_LLFMT ")",
+ src, dst, CUPS_LLCAST dstsize));
+
+ /*
+ * Range check input...
+ */
+
+ if (!src || !dst || dstsize < 4)
+ return (NULL);
+
+ /*
+ * Loop through the OID array and build a string...
+ */
+
+ for (dstptr = dst, dstend = dstptr + dstsize - 1;
+ *src >= 0 && dstptr < dstend;
+ src ++, dstptr += strlen(dstptr))
+ snprintf(dstptr, dstend - dstptr + 1, ".%d", *src);
+
+ if (*src >= 0)
+ return (NULL);
+ else
+ return (dst);
+}
+
+
+/*
+ * '_cupsSNMPOpen()' - Open a SNMP socket.
+ */
+
+int /* O - SNMP socket file descriptor */
+_cupsSNMPOpen(int family) /* I - Address family - @code AF_INET@ or @code AF_INET6@ */
+{
+ int fd; /* SNMP socket file descriptor */
+ int val; /* Socket option value */
+
+
+ /*
+ * Create the SNMP socket...
+ */
+
+ DEBUG_printf(("4_cupsSNMPOpen(family=%d)", family));
+
+ if ((fd = socket(family, SOCK_DGRAM, 0)) < 0)
+ {
+ DEBUG_printf(("5_cupsSNMPOpen: Returning -1 (%s)", strerror(errno)));
+
+ return (-1);
+ }
+
+ /*
+ * Set the "broadcast" flag...
+ */
+
+ val = 1;
+
+#ifdef WIN32
+ if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *)&val, sizeof(val)))
+#else
+ if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
+#endif /* WIN32 */
+ {
+ DEBUG_printf(("5_cupsSNMPOpen: Returning -1 (%s)", strerror(errno)));
+
+ close(fd);
+
+ return (-1);
+ }
+
+ DEBUG_printf(("5_cupsSNMPOpen: Returning %d", fd));
+
+ return (fd);
+}
+
+
+/*
+ * '_cupsSNMPRead()' - Read and parse a SNMP response.
+ *
+ * If "timeout" is negative, @code _cupsSNMPRead@ will wait for a response
+ * indefinitely.
+ */
+
+cups_snmp_t * /* O - SNMP packet or @code NULL@ if none */
+_cupsSNMPRead(int fd, /* I - SNMP socket file descriptor */
+ cups_snmp_t *packet, /* I - SNMP packet buffer */
+ double timeout) /* I - Timeout in seconds */
+{
+ unsigned char buffer[CUPS_SNMP_MAX_PACKET];
+ /* Data packet */
+ int bytes; /* Number of bytes received */
+ socklen_t addrlen; /* Source address length */
+ http_addr_t address; /* Source address */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("4_cupsSNMPRead(fd=%d, packet=%p, timeout=%.1f)", fd, packet,
+ timeout));
+
+ if (fd < 0 || !packet)
+ {
+ DEBUG_puts("5_cupsSNMPRead: Returning NULL");
+
+ return (NULL);
+ }
+
+ /*
+ * Optionally wait for a response...
+ */
+
+ if (timeout >= 0.0)
+ {
+ int ready; /* Data ready on socket? */
+#ifdef HAVE_POLL
+ struct pollfd pfd; /* Polled file descriptor */
+
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+
+ while ((ready = poll(&pfd, 1, (int)(timeout * 1000.0))) < 0 &&
+ (errno == EINTR || errno == EAGAIN));
+
+#else
+ fd_set input_set; /* select() input set */
+ struct timeval stimeout; /* select() timeout */
+
+ do
+ {
+ FD_ZERO(&input_set);
+ FD_SET(fd, &input_set);
+
+ stimeout.tv_sec = (int)timeout;
+ stimeout.tv_usec = (int)((timeout - stimeout.tv_sec) * 1000000);
+
+ ready = select(fd + 1, &input_set, NULL, NULL, &stimeout);
+ }
+# ifdef WIN32
+ while (ready < 0 && WSAGetLastError() == WSAEINTR);
+# else
+ while (ready < 0 && (errno == EINTR || errno == EAGAIN));
+# endif /* WIN32 */
+#endif /* HAVE_POLL */
+
+ /*
+ * If we don't have any data ready, return right away...
+ */
+
+ if (ready <= 0)
+ {
+ DEBUG_puts("5_cupsSNMPRead: Returning NULL (timeout)");
+
+ return (NULL);
+ }
+ }
+
+ /*
+ * Read the response data...
+ */
+
+ addrlen = sizeof(address);
+
+ if ((bytes = recvfrom(fd, buffer, sizeof(buffer), 0, (void *)&address,
+ &addrlen)) < 0)
+ {
+ DEBUG_printf(("5_cupsSNMPRead: Returning NULL (%s)", strerror(errno)));
+
+ return (NULL);
+ }
+
+ /*
+ * Look for the response status code in the SNMP message header...
+ */
+
+ asn1_debug("DEBUG: IN ", buffer, bytes, 0);
+
+ asn1_decode_snmp(buffer, bytes, packet);
+
+ memcpy(&(packet->address), &address, sizeof(packet->address));
+
+ /*
+ * Return decoded data packet...
+ */
+
+ DEBUG_puts("5_cupsSNMPRead: Returning packet");
+
+ return (packet);
+}
+
+
+/*
+ * '_cupsSNMPSetDebug()' - Enable/disable debug logging to stderr.
+ */
+
+void
+_cupsSNMPSetDebug(int level) /* I - 1 to enable debug output, 0 otherwise */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+
+
+ DEBUG_printf(("4_cupsSNMPSetDebug(level=%d)", level));
+
+ cg->snmp_debug = level;
+}
+
+
+/*
+ * '_cupsSNMPStringToOID()' - Convert a numeric OID string to an OID array.
+ *
+ * This function converts a string of the form ".N.N.N.N.N" to the
+ * corresponding OID array terminated by -1.
+ *
+ * @code NULL@ is returned if the array is not large enough or the string is
+ * not a valid OID number.
+ */
+
+int * /* O - Pointer to OID array or @code NULL@ on error */
+_cupsSNMPStringToOID(const char *src, /* I - OID string */
+ int *dst, /* I - OID array */
+ int dstsize)/* I - Number of integers in OID array */
+{
+ int *dstptr, /* Pointer into OID array */
+ *dstend; /* End of OID array */
+
+
+ DEBUG_printf(("4_cupsSNMPStringToOID(src=\"%s\", dst=%p, dstsize=%d)",
+ src, dst, dstsize));
+
+ /*
+ * Range check input...
+ */
+
+ if (!src || !dst || dstsize < 2)
+ return (NULL);
+
+ /*
+ * Skip leading "."...
+ */
+
+ if (*src == '.')
+ src ++;
+
+ /*
+ * Loop to the end of the string...
+ */
+
+ for (dstend = dst + dstsize - 1, dstptr = dst, *dstptr = 0;
+ *src && dstptr < dstend;
+ src ++)
+ {
+ if (*src == '.')
+ {
+ dstptr ++;
+ *dstptr = 0;
+ }
+ else if (isdigit(*src & 255))
+ *dstptr = *dstptr * 10 + *src - '0';
+ else
+ break;
+ }
+
+ if (*src)
+ return (NULL);
+
+ /*
+ * Terminate the end of the OID array and return...
+ */
+
+ dstptr[1] = -1;
+
+ return (dst);
+}
+
+
+/*
+ * '_cupsSNMPWalk()' - Enumerate a group of OIDs.
+ *
+ * This function queries all of the OIDs with the specified OID prefix,
+ * calling the "cb" function for every response that is received.
+ *
+ * The array pointed to by "prefix" is terminated by the value -1.
+ *
+ * If "timeout" is negative, @code _cupsSNMPWalk@ will wait for a response
+ * indefinitely.
+ */
+
+int /* O - Number of OIDs found or -1 on error */
+_cupsSNMPWalk(int fd, /* I - SNMP socket */
+ http_addr_t *address, /* I - Address to query */
+ int version, /* I - SNMP version */
+ const char *community,/* I - Community name */
+ const int *prefix, /* I - OID prefix */
+ double timeout, /* I - Timeout for each response in seconds */
+ cups_snmp_cb_t cb, /* I - Function to call for each response */
+ void *data) /* I - User data pointer that is passed to the callback function */
+{
+ int count = 0; /* Number of OIDs found */
+ int request_id = 0; /* Current request ID */
+ cups_snmp_t packet; /* Current response packet */
+ int lastoid[CUPS_SNMP_MAX_OID];
+ /* Last OID we got */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("4_cupsSNMPWalk(fd=%d, address=%p, version=%d, "
+ "community=\"%s\", prefix=%p, timeout=%.1f, cb=%p, data=%p)",
+ fd, address, version, community, prefix, timeout, cb, data));
+
+ if (fd < 0 || !address || version != CUPS_SNMP_VERSION_1 || !community ||
+ !prefix || !cb)
+ {
+ DEBUG_puts("5_cupsSNMPWalk: Returning -1");
+
+ return (-1);
+ }
+
+ /*
+ * Copy the OID prefix and then loop until we have no more OIDs...
+ */
+
+ _cupsSNMPCopyOID(packet.object_name, prefix, CUPS_SNMP_MAX_OID);
+ lastoid[0] = -1;
+
+ for (;;)
+ {
+ request_id ++;
+
+ if (!_cupsSNMPWrite(fd, address, version, community,
+ CUPS_ASN1_GET_NEXT_REQUEST, request_id,
+ packet.object_name))
+ {
+ DEBUG_puts("5_cupsSNMPWalk: Returning -1");
+
+ return (-1);
+ }
+
+ if (!_cupsSNMPRead(fd, &packet, timeout))
+ {
+ DEBUG_puts("5_cupsSNMPWalk: Returning -1");
+
+ return (-1);
+ }
+
+ if (!_cupsSNMPIsOIDPrefixed(&packet, prefix) ||
+ _cupsSNMPIsOID(&packet, lastoid))
+ {
+ DEBUG_printf(("5_cupsSNMPWalk: Returning %d", count));
+
+ return (count);
+ }
+
+ if (packet.error || packet.error_status)
+ {
+ DEBUG_printf(("5_cupsSNMPWalk: Returning %d", count > 0 ? count : -1));
+
+ return (count > 0 ? count : -1);
+ }
+
+ _cupsSNMPCopyOID(lastoid, packet.object_name, CUPS_SNMP_MAX_OID);
+
+ count ++;
+
+ (*cb)(&packet, data);
+ }
+}
+
+
+/*
+ * '_cupsSNMPWrite()' - Send an SNMP query packet.
+ *
+ * The array pointed to by "oid" is terminated by the value -1.
+ */
+
+int /* O - 1 on success, 0 on error */
+_cupsSNMPWrite(
+ int fd, /* I - SNMP socket */
+ http_addr_t *address, /* I - Address to send to */
+ int version, /* I - SNMP version */
+ const char *community, /* I - Community name */
+ cups_asn1_t request_type, /* I - Request type */
+ const unsigned request_id, /* I - Request ID */
+ const int *oid) /* I - OID */
+{
+ int i; /* Looping var */
+ cups_snmp_t packet; /* SNMP message packet */
+ unsigned char buffer[CUPS_SNMP_MAX_PACKET];
+ /* SNMP message buffer */
+ int bytes; /* Size of message */
+ http_addr_t temp; /* Copy of address */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("4_cupsSNMPWrite(fd=%d, address=%p, version=%d, "
+ "community=\"%s\", request_type=%d, request_id=%u, oid=%p)",
+ fd, address, version, community, request_type, request_id, oid));
+
+ if (fd < 0 || !address || version != CUPS_SNMP_VERSION_1 || !community ||
+ (request_type != CUPS_ASN1_GET_REQUEST &&
+ request_type != CUPS_ASN1_GET_NEXT_REQUEST) || request_id < 1 || !oid)
+ {
+ DEBUG_puts("5_cupsSNMPWrite: Returning 0 (bad arguments)");
+
+ return (0);
+ }
+
+ /*
+ * Create the SNMP message...
+ */
+
+ memset(&packet, 0, sizeof(packet));
+
+ packet.version = version;
+ packet.request_type = request_type;
+ packet.request_id = request_id;
+ packet.object_type = CUPS_ASN1_NULL_VALUE;
+
+ strlcpy(packet.community, community, sizeof(packet.community));
+
+ for (i = 0; oid[i] >= 0 && i < (CUPS_SNMP_MAX_OID - 1); i ++)
+ packet.object_name[i] = oid[i];
+ packet.object_name[i] = -1;
+
+ if (oid[i] >= 0)
+ {
+ DEBUG_puts("5_cupsSNMPWrite: Returning 0 (OID too big)");
+
+ errno = E2BIG;
+ return (0);
+ }
+
+ bytes = asn1_encode_snmp(buffer, sizeof(buffer), &packet);
+
+ if (bytes < 0)
+ {
+ DEBUG_puts("5_cupsSNMPWrite: Returning 0 (request too big)");
+
+ errno = E2BIG;
+ return (0);
+ }
+
+ asn1_debug("DEBUG: OUT ", buffer, bytes, 0);
+
+ /*
+ * Send the message...
+ */
+
+ temp = *address;
+
+ _httpAddrSetPort(&temp, CUPS_SNMP_PORT);
+
+ return (sendto(fd, buffer, bytes, 0, (void *)&temp,
+ httpAddrLength(&temp)) == bytes);
+}
+
+
+/*
+ * 'asn1_debug()' - Decode an ASN1-encoded message.
+ */
+
+static void
+asn1_debug(const char *prefix, /* I - Prefix string */
+ unsigned char *buffer, /* I - Buffer */
+ size_t len, /* I - Length of buffer */
+ int indent) /* I - Indentation */
+{
+ int i; /* Looping var */
+ unsigned char *bufend; /* End of buffer */
+ int integer; /* Number value */
+ int oid[CUPS_SNMP_MAX_OID]; /* OID value */
+ char string[CUPS_SNMP_MAX_STRING];
+ /* String value */
+ unsigned char value_type; /* Type of value */
+ int value_length; /* Length of value */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+
+
+ if (cg->snmp_debug <= 0)
+ return;
+
+ if (cg->snmp_debug > 1 && indent == 0)
+ {
+ /*
+ * Do a hex dump of the packet...
+ */
+
+ int j;
+
+ fprintf(stderr, "%sHex Dump (%d bytes):\n", prefix, (int)len);
+
+ for (i = 0; i < (int)len; i += 16)
+ {
+ fprintf(stderr, "%s%04x:", prefix, i);
+
+ for (j = 0; j < 16 && (i + j) < (int)len; j ++)
+ {
+ if (j && !(j & 3))
+ fprintf(stderr, " %02x", buffer[i + j]);
+ else
+ fprintf(stderr, " %02x", buffer[i + j]);
+ }
+
+ while (j < 16)
+ {
+ if (j && !(j & 3))
+ fputs(" ", stderr);
+ else
+ fputs(" ", stderr);
+
+ j ++;
+ }
+
+ fputs(" ", stderr);
+
+ for (j = 0; j < 16 && (i + j) < (int)len; j ++)
+ if (buffer[i + j] < ' ' || buffer[i + j] >= 0x7f)
+ putc('.', stderr);
+ else
+ putc(buffer[i + j], stderr);
+
+ putc('\n', stderr);
+ }
+ }
+
+ if (indent == 0)
+ fprintf(stderr, "%sMessage:\n", prefix);
+
+ bufend = buffer + len;
+
+ while (buffer < bufend)
+ {
+ /*
+ * Get value type...
+ */
+
+ value_type = asn1_get_type(&buffer, bufend);
+ value_length = asn1_get_length(&buffer, bufend);
+
+ switch (value_type)
+ {
+ case CUPS_ASN1_BOOLEAN :
+ integer = asn1_get_integer(&buffer, bufend, value_length);
+
+ fprintf(stderr, "%s%*sBOOLEAN %d bytes %d\n", prefix, indent, "",
+ value_length, integer);
+ break;
+
+ case CUPS_ASN1_INTEGER :
+ integer = asn1_get_integer(&buffer, bufend, value_length);
+
+ fprintf(stderr, "%s%*sINTEGER %d bytes %d\n", prefix, indent, "",
+ value_length, integer);
+ break;
+
+ case CUPS_ASN1_COUNTER :
+ integer = asn1_get_integer(&buffer, bufend, value_length);
+
+ fprintf(stderr, "%s%*sCOUNTER %d bytes %u\n", prefix, indent, "",
+ value_length, (unsigned)integer);
+ break;
+
+ case CUPS_ASN1_GAUGE :
+ integer = asn1_get_integer(&buffer, bufend, value_length);
+
+ fprintf(stderr, "%s%*sGAUGE %d bytes %u\n", prefix, indent, "",
+ value_length, (unsigned)integer);
+ break;
+
+ case CUPS_ASN1_TIMETICKS :
+ integer = asn1_get_integer(&buffer, bufend, value_length);
+
+ fprintf(stderr, "%s%*sTIMETICKS %d bytes %u\n", prefix, indent, "",
+ value_length, (unsigned)integer);
+ break;
+
+ case CUPS_ASN1_OCTET_STRING :
+ fprintf(stderr, "%s%*sOCTET STRING %d bytes \"%s\"\n", prefix,
+ indent, "", value_length,
+ asn1_get_string(&buffer, bufend, value_length, string,
+ sizeof(string)));
+ break;
+
+ case CUPS_ASN1_HEX_STRING :
+ asn1_get_string(&buffer, bufend, value_length, string,
+ sizeof(string));
+ fprintf(stderr, "%s%*sHex-STRING %d bytes", prefix,
+ indent, "", value_length);
+ for (i = 0; i < value_length; i ++)
+ fprintf(stderr, " %02X", string[i] & 255);
+ putc('\n', stderr);
+ break;
+
+ case CUPS_ASN1_NULL_VALUE :
+ fprintf(stderr, "%s%*sNULL VALUE %d bytes\n", prefix, indent, "",
+ value_length);
+
+ buffer += value_length;
+ break;
+
+ case CUPS_ASN1_OID :
+ integer = asn1_get_oid(&buffer, bufend, value_length, oid,
+ CUPS_SNMP_MAX_OID);
+
+ fprintf(stderr, "%s%*sOID %d bytes ", prefix, indent, "",
+ value_length);
+ for (i = 0; i < integer; i ++)
+ fprintf(stderr, ".%d", oid[i]);
+ putc('\n', stderr);
+ break;
+
+ case CUPS_ASN1_SEQUENCE :
+ fprintf(stderr, "%s%*sSEQUENCE %d bytes\n", prefix, indent, "",
+ value_length);
+ asn1_debug(prefix, buffer, value_length, indent + 4);
+
+ buffer += value_length;
+ break;
+
+ case CUPS_ASN1_GET_NEXT_REQUEST :
+ fprintf(stderr, "%s%*sGet-Next-Request-PDU %d bytes\n", prefix,
+ indent, "", value_length);
+ asn1_debug(prefix, buffer, value_length, indent + 4);
+
+ buffer += value_length;
+ break;
+
+ case CUPS_ASN1_GET_REQUEST :
+ fprintf(stderr, "%s%*sGet-Request-PDU %d bytes\n", prefix, indent, "",
+ value_length);
+ asn1_debug(prefix, buffer, value_length, indent + 4);
+
+ buffer += value_length;
+ break;
+
+ case CUPS_ASN1_GET_RESPONSE :
+ fprintf(stderr, "%s%*sGet-Response-PDU %d bytes\n", prefix, indent,
+ "", value_length);
+ asn1_debug(prefix, buffer, value_length, indent + 4);
+
+ buffer += value_length;
+ break;
+
+ default :
+ fprintf(stderr, "%s%*sUNKNOWN(%x) %d bytes\n", prefix, indent, "",
+ value_type, value_length);
+
+ buffer += value_length;
+ break;
+ }
+ }
+}
+
+
+/*
+ * 'asn1_decode_snmp()' - Decode a SNMP packet.
+ */
+
+static int /* O - 0 on success, -1 on error */
+asn1_decode_snmp(unsigned char *buffer, /* I - Buffer */
+ size_t len, /* I - Size of buffer */
+ cups_snmp_t *packet) /* I - SNMP packet */
+{
+ unsigned char *bufptr, /* Pointer into the data */
+ *bufend; /* End of data */
+ int length; /* Length of value */
+
+
+ /*
+ * Initialize the decoding...
+ */
+
+ memset(packet, 0, sizeof(cups_snmp_t));
+ packet->object_name[0] = -1;
+
+ bufptr = buffer;
+ bufend = buffer + len;
+
+ if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE)
+ snmp_set_error(packet, _("Packet does not start with SEQUENCE"));
+ else if (asn1_get_length(&bufptr, bufend) == 0)
+ snmp_set_error(packet, _("SEQUENCE uses indefinite length"));
+ else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER)
+ snmp_set_error(packet, _("No version number"));
+ else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
+ snmp_set_error(packet, _("Version uses indefinite length"));
+ else if ((packet->version = asn1_get_integer(&bufptr, bufend, length))
+ != CUPS_SNMP_VERSION_1)
+ snmp_set_error(packet, _("Bad SNMP version number"));
+ else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_OCTET_STRING)
+ snmp_set_error(packet, _("No community name"));
+ else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
+ snmp_set_error(packet, _("Community name uses indefinite length"));
+ else
+ {
+ asn1_get_string(&bufptr, bufend, length, packet->community,
+ sizeof(packet->community));
+
+ if ((packet->request_type = asn1_get_type(&bufptr, bufend))
+ != CUPS_ASN1_GET_RESPONSE)
+ snmp_set_error(packet, _("Packet does not contain a Get-Response-PDU"));
+ else if (asn1_get_length(&bufptr, bufend) == 0)
+ snmp_set_error(packet, _("Get-Response-PDU uses indefinite length"));
+ else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER)
+ snmp_set_error(packet, _("No request-id"));
+ else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
+ snmp_set_error(packet, _("request-id uses indefinite length"));
+ else
+ {
+ packet->request_id = asn1_get_integer(&bufptr, bufend, length);
+
+ if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER)
+ snmp_set_error(packet, _("No error-status"));
+ else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
+ snmp_set_error(packet, _("error-status uses indefinite length"));
+ else
+ {
+ packet->error_status = asn1_get_integer(&bufptr, bufend, length);
+
+ if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER)
+ snmp_set_error(packet, _("No error-index"));
+ else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
+ snmp_set_error(packet, _("error-index uses indefinite length"));
+ else
+ {
+ packet->error_index = asn1_get_integer(&bufptr, bufend, length);
+
+ if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE)
+ snmp_set_error(packet, _("No variable-bindings SEQUENCE"));
+ else if (asn1_get_length(&bufptr, bufend) == 0)
+ snmp_set_error(packet,
+ _("variable-bindings uses indefinite length"));
+ else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE)
+ snmp_set_error(packet, _("No VarBind SEQUENCE"));
+ else if (asn1_get_length(&bufptr, bufend) == 0)
+ snmp_set_error(packet, _("VarBind uses indefinite length"));
+ else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_OID)
+ snmp_set_error(packet, _("No name OID"));
+ else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
+ snmp_set_error(packet, _("Name OID uses indefinite length"));
+ else
+ {
+ asn1_get_oid(&bufptr, bufend, length, packet->object_name,
+ CUPS_SNMP_MAX_OID);
+
+ packet->object_type = asn1_get_type(&bufptr, bufend);
+
+ if ((length = asn1_get_length(&bufptr, bufend)) == 0 &&
+ packet->object_type != CUPS_ASN1_NULL_VALUE &&
+ packet->object_type != CUPS_ASN1_OCTET_STRING)
+ snmp_set_error(packet, _("Value uses indefinite length"));
+ else
+ {
+ switch (packet->object_type)
+ {
+ case CUPS_ASN1_BOOLEAN :
+ packet->object_value.boolean =
+ asn1_get_integer(&bufptr, bufend, length);
+ break;
+
+ case CUPS_ASN1_INTEGER :
+ packet->object_value.integer =
+ asn1_get_integer(&bufptr, bufend, length);
+ break;
+
+ case CUPS_ASN1_NULL_VALUE :
+ break;
+
+ case CUPS_ASN1_OCTET_STRING :
+ case CUPS_ASN1_BIT_STRING :
+ case CUPS_ASN1_HEX_STRING :
+ packet->object_value.string.num_bytes = length;
+ asn1_get_string(&bufptr, bufend, length,
+ (char *)packet->object_value.string.bytes,
+ CUPS_SNMP_MAX_STRING);
+ break;
+
+ case CUPS_ASN1_OID :
+ asn1_get_oid(&bufptr, bufend, length,
+ packet->object_value.oid, CUPS_SNMP_MAX_OID);
+ break;
+
+ case CUPS_ASN1_COUNTER :
+ packet->object_value.counter =
+ asn1_get_integer(&bufptr, bufend, length);
+ break;
+
+ case CUPS_ASN1_GAUGE :
+ packet->object_value.gauge =
+ asn1_get_integer(&bufptr, bufend, length);
+ break;
+
+ case CUPS_ASN1_TIMETICKS :
+ packet->object_value.timeticks =
+ asn1_get_integer(&bufptr, bufend, length);
+ break;
+
+ default :
+ snmp_set_error(packet, _("Unsupported value type"));
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return (packet->error ? -1 : 0);
+}
+
+
+/*
+ * 'asn1_encode_snmp()' - Encode a SNMP packet.
+ */
+
+static int /* O - Length on success, -1 on error */
+asn1_encode_snmp(unsigned char *buffer, /* I - Buffer */
+ size_t bufsize, /* I - Size of buffer */
+ cups_snmp_t *packet) /* I - SNMP packet */
+{
+ unsigned char *bufptr; /* Pointer into buffer */
+ int total, /* Total length */
+ msglen, /* Length of entire message */
+ commlen, /* Length of community string */
+ reqlen, /* Length of request */
+ listlen, /* Length of variable list */
+ varlen, /* Length of variable */
+ namelen, /* Length of object name OID */
+ valuelen; /* Length of object value */
+
+
+ /*
+ * Get the lengths of the community string, OID, and message...
+ */
+
+
+ namelen = asn1_size_oid(packet->object_name);
+
+ switch (packet->object_type)
+ {
+ case CUPS_ASN1_NULL_VALUE :
+ valuelen = 0;
+ break;
+
+ case CUPS_ASN1_BOOLEAN :
+ valuelen = asn1_size_integer(packet->object_value.boolean);
+ break;
+
+ case CUPS_ASN1_INTEGER :
+ valuelen = asn1_size_integer(packet->object_value.integer);
+ break;
+
+ case CUPS_ASN1_OCTET_STRING :
+ valuelen = packet->object_value.string.num_bytes;
+ break;
+
+ case CUPS_ASN1_OID :
+ valuelen = asn1_size_oid(packet->object_value.oid);
+ break;
+
+ default :
+ packet->error = "Unknown object type";
+ return (-1);
+ }
+
+ varlen = 1 + asn1_size_length(namelen) + namelen +
+ 1 + asn1_size_length(valuelen) + valuelen;
+ listlen = 1 + asn1_size_length(varlen) + varlen;
+ reqlen = 2 + asn1_size_integer(packet->request_id) +
+ 2 + asn1_size_integer(packet->error_status) +
+ 2 + asn1_size_integer(packet->error_index) +
+ 1 + asn1_size_length(listlen) + listlen;
+ commlen = strlen(packet->community);
+ msglen = 2 + asn1_size_integer(packet->version) +
+ 1 + asn1_size_length(commlen) + commlen +
+ 1 + asn1_size_length(reqlen) + reqlen;
+ total = 1 + asn1_size_length(msglen) + msglen;
+
+ if (total > (int)bufsize)
+ {
+ packet->error = "Message too large for buffer";
+ return (-1);
+ }
+
+ /*
+ * Then format the message...
+ */
+
+ bufptr = buffer;
+
+ *bufptr++ = CUPS_ASN1_SEQUENCE; /* SNMPv1 message header */
+ asn1_set_length(&bufptr, msglen);
+
+ asn1_set_integer(&bufptr, packet->version);
+ /* version */
+
+ *bufptr++ = CUPS_ASN1_OCTET_STRING; /* community */
+ asn1_set_length(&bufptr, commlen);
+ memcpy(bufptr, packet->community, commlen);
+ bufptr += commlen;
+
+ *bufptr++ = packet->request_type; /* Get-Request-PDU/Get-Next-Request-PDU */
+ asn1_set_length(&bufptr, reqlen);
+
+ asn1_set_integer(&bufptr, packet->request_id);
+
+ asn1_set_integer(&bufptr, packet->error_status);
+
+ asn1_set_integer(&bufptr, packet->error_index);
+
+ *bufptr++ = CUPS_ASN1_SEQUENCE; /* variable-bindings */
+ asn1_set_length(&bufptr, listlen);
+
+ *bufptr++ = CUPS_ASN1_SEQUENCE; /* variable */
+ asn1_set_length(&bufptr, varlen);
+
+ asn1_set_oid(&bufptr, packet->object_name);
+ /* ObjectName */
+
+ switch (packet->object_type)
+ {
+ case CUPS_ASN1_NULL_VALUE :
+ *bufptr++ = CUPS_ASN1_NULL_VALUE;
+ /* ObjectValue */
+ *bufptr++ = 0; /* Length */
+ break;
+
+ case CUPS_ASN1_BOOLEAN :
+ asn1_set_integer(&bufptr, packet->object_value.boolean);
+ break;
+
+ case CUPS_ASN1_INTEGER :
+ asn1_set_integer(&bufptr, packet->object_value.integer);
+ break;
+
+ case CUPS_ASN1_OCTET_STRING :
+ *bufptr++ = CUPS_ASN1_OCTET_STRING;
+ asn1_set_length(&bufptr, valuelen);
+ memcpy(bufptr, packet->object_value.string.bytes, valuelen);
+ bufptr += valuelen;
+ break;
+
+ case CUPS_ASN1_OID :
+ asn1_set_oid(&bufptr, packet->object_value.oid);
+ break;
+
+ default :
+ break;
+ }
+
+ return (bufptr - buffer);
+}
+
+
+/*
+ * 'asn1_get_integer()' - Get an integer value.
+ */
+
+static int /* O - Integer value */
+asn1_get_integer(
+ unsigned char **buffer, /* IO - Pointer in buffer */
+ unsigned char *bufend, /* I - End of buffer */
+ int length) /* I - Length of value */
+{
+ int value; /* Integer value */
+
+
+ if (length > sizeof(int))
+ {
+ (*buffer) += length;
+ return (0);
+ }
+
+ for (value = (**buffer & 0x80) ? -1 : 0;
+ length > 0 && *buffer < bufend;
+ length --, (*buffer) ++)
+ value = (value << 8) | **buffer;
+
+ return (value);
+}
+
+
+/*
+ * 'asn1_get_length()' - Get a value length.
+ */
+
+static unsigned /* O - Length */
+asn1_get_length(unsigned char **buffer, /* IO - Pointer in buffer */
+ unsigned char *bufend) /* I - End of buffer */
+{
+ unsigned length; /* Length */
+
+
+ length = **buffer;
+ (*buffer) ++;
+
+ if (length & 128)
+ {
+ int count; /* Number of bytes for length */
+
+
+ if ((count = length & 127) > sizeof(unsigned))
+ {
+ (*buffer) += count;
+ return (0);
+ }
+
+ for (length = 0;
+ count > 0 && *buffer < bufend;
+ count --, (*buffer) ++)
+ length = (length << 8) | **buffer;
+ }
+
+ return (length);
+}
+
+
+/*
+ * 'asn1_get_oid()' - Get an OID value.
+ */
+
+static int /* O - Number of OIDs */
+asn1_get_oid(
+ unsigned char **buffer, /* IO - Pointer in buffer */
+ unsigned char *bufend, /* I - End of buffer */
+ int length, /* I - Length of value */
+ int *oid, /* I - OID buffer */
+ int oidsize) /* I - Size of OID buffer */
+{
+ unsigned char *valend; /* End of value */
+ int *oidptr, /* Current OID */
+ *oidend; /* End of OID buffer */
+ int number; /* OID number */
+
+
+ valend = *buffer + length;
+ oidptr = oid;
+ oidend = oid + oidsize - 1;
+
+ if (valend > bufend)
+ valend = bufend;
+
+ number = asn1_get_packed(buffer, bufend);
+
+ if (number < 80)
+ {
+ *oidptr++ = number / 40;
+ number = number % 40;
+ *oidptr++ = number;
+ }
+ else
+ {
+ *oidptr++ = 2;
+ number -= 80;
+ *oidptr++ = number;
+ }
+
+ while (*buffer < valend)
+ {
+ number = asn1_get_packed(buffer, bufend);
+
+ if (oidptr < oidend)
+ *oidptr++ = number;
+ }
+
+ *oidptr = -1;
+
+ return (oidptr - oid);
+}
+
+
+/*
+ * 'asn1_get_packed()' - Get a packed integer value.
+ */
+
+static int /* O - Value */
+asn1_get_packed(
+ unsigned char **buffer, /* IO - Pointer in buffer */
+ unsigned char *bufend) /* I - End of buffer */
+{
+ int value; /* Value */
+
+
+ value = 0;
+
+ while ((**buffer & 128) && *buffer < bufend)
+ {
+ value = (value << 7) | (**buffer & 127);
+ (*buffer) ++;
+ }
+
+ if (*buffer < bufend)
+ {
+ value = (value << 7) | **buffer;
+ (*buffer) ++;
+ }
+
+ return (value);
+}
+
+
+/*
+ * 'asn1_get_string()' - Get a string value.
+ */
+
+static char * /* O - String */
+asn1_get_string(
+ unsigned char **buffer, /* IO - Pointer in buffer */
+ unsigned char *bufend, /* I - End of buffer */
+ int length, /* I - Value length */
+ char *string, /* I - String buffer */
+ int strsize) /* I - String buffer size */
+{
+ if (length > (bufend - *buffer))
+ length = bufend - *buffer;
+
+ if (length < 0)
+ {
+ /*
+ * Disallow negative lengths!
+ */
+
+ *string = '\0';
+ }
+ else if (length < strsize)
+ {
+ /*
+ * String is smaller than the buffer...
+ */
+
+ if (length > 0)
+ memcpy(string, *buffer, length);
+
+ string[length] = '\0';
+ }
+ else
+ {
+ /*
+ * String is larger than the buffer...
+ */
+
+ memcpy(string, *buffer, strsize - 1);
+ string[strsize - 1] = '\0';
+ }
+
+ if (length > 0)
+ (*buffer) += length;
+
+ return (length < 0 ? NULL : string);
+}
+
+
+/*
+ * 'asn1_get_type()' - Get a value type.
+ */
+
+static int /* O - Type */
+asn1_get_type(unsigned char **buffer, /* IO - Pointer in buffer */
+ unsigned char *bufend) /* I - End of buffer */
+{
+ int type; /* Type */
+
+
+ type = **buffer;
+ (*buffer) ++;
+
+ if ((type & 31) == 31)
+ type = asn1_get_packed(buffer, bufend);
+
+ return (type);
+}
+
+
+/*
+ * 'asn1_set_integer()' - Set an integer value.
+ */
+
+static void
+asn1_set_integer(unsigned char **buffer,/* IO - Pointer in buffer */
+ int integer) /* I - Integer value */
+{
+ **buffer = CUPS_ASN1_INTEGER;
+ (*buffer) ++;
+
+ if (integer > 0x7fffff || integer < -0x800000)
+ {
+ **buffer = 4;
+ (*buffer) ++;
+ **buffer = integer >> 24;
+ (*buffer) ++;
+ **buffer = integer >> 16;
+ (*buffer) ++;
+ **buffer = integer >> 8;
+ (*buffer) ++;
+ **buffer = integer;
+ (*buffer) ++;
+ }
+ else if (integer > 0x7fff || integer < -0x8000)
+ {
+ **buffer = 3;
+ (*buffer) ++;
+ **buffer = integer >> 16;
+ (*buffer) ++;
+ **buffer = integer >> 8;
+ (*buffer) ++;
+ **buffer = integer;
+ (*buffer) ++;
+ }
+ else if (integer > 0x7f || integer < -0x80)
+ {
+ **buffer = 2;
+ (*buffer) ++;
+ **buffer = integer >> 8;
+ (*buffer) ++;
+ **buffer = integer;
+ (*buffer) ++;
+ }
+ else
+ {
+ **buffer = 1;
+ (*buffer) ++;
+ **buffer = integer;
+ (*buffer) ++;
+ }
+}
+
+
+/*
+ * 'asn1_set_length()' - Set a value length.
+ */
+
+static void
+asn1_set_length(unsigned char **buffer, /* IO - Pointer in buffer */
+ unsigned length) /* I - Length value */
+{
+ if (length > 255)
+ {
+ **buffer = 0x82; /* 2-byte length */
+ (*buffer) ++;
+ **buffer = length >> 8;
+ (*buffer) ++;
+ **buffer = length;
+ (*buffer) ++;
+ }
+ else if (length > 127)
+ {
+ **buffer = 0x81; /* 1-byte length */
+ (*buffer) ++;
+ **buffer = length;
+ (*buffer) ++;
+ }
+ else
+ {
+ **buffer = length; /* Length */
+ (*buffer) ++;
+ }
+}
+
+
+/*
+ * 'asn1_set_oid()' - Set an OID value.
+ */
+
+static void
+asn1_set_oid(unsigned char **buffer, /* IO - Pointer in buffer */
+ const int *oid) /* I - OID value */
+{
+ **buffer = CUPS_ASN1_OID;
+ (*buffer) ++;
+
+ asn1_set_length(buffer, asn1_size_oid(oid));
+
+ if (oid[1] < 0)
+ {
+ asn1_set_packed(buffer, oid[0] * 40);
+ return;
+ }
+
+ asn1_set_packed(buffer, oid[0] * 40 + oid[1]);
+
+ for (oid += 2; *oid >= 0; oid ++)
+ asn1_set_packed(buffer, *oid);
+}
+
+
+/*
+ * 'asn1_set_packed()' - Set a packed integer value.
+ */
+
+static void
+asn1_set_packed(unsigned char **buffer, /* IO - Pointer in buffer */
+ int integer) /* I - Integer value */
+{
+ if (integer > 0xfffffff)
+ {
+ **buffer = ((integer >> 28) & 0x7f) | 0x80;
+ (*buffer) ++;
+ }
+
+ if (integer > 0x1fffff)
+ {
+ **buffer = ((integer >> 21) & 0x7f) | 0x80;
+ (*buffer) ++;
+ }
+
+ if (integer > 0x3fff)
+ {
+ **buffer = ((integer >> 14) & 0x7f) | 0x80;
+ (*buffer) ++;
+ }
+
+ if (integer > 0x7f)
+ {
+ **buffer = ((integer >> 7) & 0x7f) | 0x80;
+ (*buffer) ++;
+ }
+
+ **buffer = integer & 0x7f;
+ (*buffer) ++;
+}
+
+
+/*
+ * 'asn1_size_integer()' - Figure out the number of bytes needed for an
+ * integer value.
+ */
+
+static int /* O - Size in bytes */
+asn1_size_integer(int integer) /* I - Integer value */
+{
+ if (integer > 0x7fffff || integer < -0x800000)
+ return (4);
+ else if (integer > 0x7fff || integer < -0x8000)
+ return (3);
+ else if (integer > 0x7f || integer < -0x80)
+ return (2);
+ else
+ return (1);
+}
+
+
+/*
+ * 'asn1_size_length()' - Figure out the number of bytes needed for a
+ * length value.
+ */
+
+static int /* O - Size in bytes */
+asn1_size_length(int length) /* I - Length value */
+{
+ if (length > 0xff)
+ return (3);
+ else if (length > 0x7f)
+ return (2);
+ else
+ return (1);
+}
+
+
+/*
+ * 'asn1_size_oid()' - Figure out the numebr of bytes needed for an
+ * OID value.
+ */
+
+static int /* O - Size in bytes */
+asn1_size_oid(const int *oid) /* I - OID value */
+{
+ int length; /* Length of value */
+
+
+ if (oid[1] < 0)
+ return (asn1_size_packed(oid[0] * 40));
+
+ for (length = asn1_size_packed(oid[0] * 40 + oid[1]), oid += 2;
+ *oid >= 0;
+ oid ++)
+ length += asn1_size_packed(*oid);
+
+ return (length);
+}
+
+
+/*
+ * 'asn1_size_packed()' - Figure out the number of bytes needed for a
+ * packed integer value.
+ */
+
+static int /* O - Size in bytes */
+asn1_size_packed(int integer) /* I - Integer value */
+{
+ if (integer > 0xfffffff)
+ return (5);
+ else if (integer > 0x1fffff)
+ return (4);
+ else if (integer > 0x3fff)
+ return (3);
+ else if (integer > 0x7f)
+ return (2);
+ else
+ return (1);
+}
+
+
+/*
+ * 'snmp_set_error()' - Set the localized error for a packet.
+ */
+
+static void
+snmp_set_error(cups_snmp_t *packet, /* I - Packet */
+ const char *message) /* I - Error message */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+
+
+ if (!cg->lang_default)
+ cg->lang_default = cupsLangDefault();
+
+ packet->error = _cupsLangString(cg->lang_default, message);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/snprintf.c b/cups/snprintf.c
new file mode 100644
index 000000000..595be6594
--- /dev/null
+++ b/cups/snprintf.c
@@ -0,0 +1,362 @@
+/*
+ * "$Id$"
+ *
+ * snprintf functions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cups_vsnprintf() - Format a string into a fixed size buffer.
+ * _cups_snprintf() - Format a string into a fixed size buffer.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "string-private.h"
+
+
+#ifndef HAVE_VSNPRINTF
+/*
+ * '_cups_vsnprintf()' - Format a string into a fixed size buffer.
+ */
+
+int /* O - Number of bytes formatted */
+_cups_vsnprintf(char *buffer, /* O - Output buffer */
+ size_t bufsize, /* O - Size of output buffer */
+ const char *format, /* I - printf-style format string */
+ va_list ap) /* I - Pointer to additional arguments */
+{
+ char *bufptr, /* Pointer to position in buffer */
+ *bufend, /* Pointer to end of buffer */
+ sign, /* Sign of format width */
+ size, /* Size character (h, l, L) */
+ type; /* Format type character */
+ int width, /* Width of field */
+ prec; /* Number of characters of precision */
+ char tformat[100], /* Temporary format string for sprintf() */
+ *tptr, /* Pointer into temporary format */
+ temp[1024]; /* Buffer for formatted numbers */
+ char *s; /* Pointer to string */
+ int slen; /* Length of string */
+ int bytes; /* Total number of bytes needed */
+
+
+ /*
+ * Loop through the format string, formatting as needed...
+ */
+
+ bufptr = buffer;
+ bufend = buffer + bufsize - 1;
+ bytes = 0;
+
+ while (*format)
+ {
+ if (*format == '%')
+ {
+ tptr = tformat;
+ *tptr++ = *format++;
+
+ if (*format == '%')
+ {
+ if (bufptr && bufptr < bufend) *bufptr++ = *format;
+ bytes ++;
+ format ++;
+ continue;
+ }
+ else if (strchr(" -+#\'", *format))
+ {
+ *tptr++ = *format;
+ sign = *format++;
+ }
+ else
+ sign = 0;
+
+ if (*format == '*')
+ {
+ /*
+ * Get width from argument...
+ */
+
+ format ++;
+ width = va_arg(ap, int);
+
+ snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
+ tptr += strlen(tptr);
+ }
+ else
+ {
+ width = 0;
+
+ while (isdigit(*format & 255))
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ width = width * 10 + *format++ - '0';
+ }
+ }
+
+ if (*format == '.')
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ format ++;
+
+ if (*format == '*')
+ {
+ /*
+ * Get precision from argument...
+ */
+
+ format ++;
+ prec = va_arg(ap, int);
+
+ snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
+ tptr += strlen(tptr);
+ }
+ else
+ {
+ prec = 0;
+
+ while (isdigit(*format & 255))
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ prec = prec * 10 + *format++ - '0';
+ }
+ }
+ }
+ else
+ prec = -1;
+
+ if (*format == 'l' && format[1] == 'l')
+ {
+ size = 'L';
+
+ if (tptr < (tformat + sizeof(tformat) - 2))
+ {
+ *tptr++ = 'l';
+ *tptr++ = 'l';
+ }
+
+ format += 2;
+ }
+ else if (*format == 'h' || *format == 'l' || *format == 'L')
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ size = *format++;
+ }
+
+ if (!*format)
+ break;
+
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ type = *format++;
+ *tptr = '\0';
+
+ switch (type)
+ {
+ case 'E' : /* Floating point formats */
+ case 'G' :
+ case 'e' :
+ case 'f' :
+ case 'g' :
+ if ((width + 2) > sizeof(temp))
+ break;
+
+ sprintf(temp, tformat, va_arg(ap, double));
+
+ bytes += (int)strlen(temp);
+
+ if (bufptr)
+ {
+ if ((bufptr + strlen(temp)) > bufend)
+ {
+ strncpy(bufptr, temp, (size_t)(bufend - bufptr));
+ bufptr = bufend;
+ }
+ else
+ {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'B' : /* Integer formats */
+ case 'X' :
+ case 'b' :
+ case 'd' :
+ case 'i' :
+ case 'o' :
+ case 'u' :
+ case 'x' :
+ if ((width + 2) > sizeof(temp))
+ break;
+
+ sprintf(temp, tformat, va_arg(ap, int));
+
+ bytes += (int)strlen(temp);
+
+ if (bufptr)
+ {
+ if ((bufptr + strlen(temp)) > bufend)
+ {
+ strncpy(bufptr, temp, (size_t)(bufend - bufptr));
+ bufptr = bufend;
+ }
+ else
+ {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'p' : /* Pointer value */
+ if ((width + 2) > sizeof(temp))
+ break;
+
+ sprintf(temp, tformat, va_arg(ap, void *));
+
+ bytes += (int)strlen(temp);
+
+ if (bufptr)
+ {
+ if ((bufptr + strlen(temp)) > bufend)
+ {
+ strncpy(bufptr, temp, (size_t)(bufend - bufptr));
+ bufptr = bufend;
+ }
+ else
+ {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'c' : /* Character or character array */
+ bytes += width;
+
+ if (bufptr)
+ {
+ if (width <= 1)
+ *bufptr++ = va_arg(ap, int);
+ else
+ {
+ if ((bufptr + width) > bufend)
+ width = (int)(bufend - bufptr);
+
+ memcpy(bufptr, va_arg(ap, char *), (size_t)width);
+ bufptr += width;
+ }
+ }
+ break;
+
+ case 's' : /* String */
+ if ((s = va_arg(ap, char *)) == NULL)
+ s = "(null)";
+
+ slen = (int)strlen(s);
+ if (slen > width && prec != width)
+ width = slen;
+
+ bytes += width;
+
+ if (bufptr)
+ {
+ if ((bufptr + width) > bufend)
+ width = (int)(bufend - bufptr);
+
+ if (slen > width)
+ slen = width;
+
+ if (sign == '-')
+ {
+ strncpy(bufptr, s, (size_t)slen);
+ memset(bufptr + slen, ' ', (size_t)(width - slen));
+ }
+ else
+ {
+ memset(bufptr, ' ', (size_t)(width - slen));
+ strncpy(bufptr + width - slen, s, (size_t)slen);
+ }
+
+ bufptr += width;
+ }
+ break;
+
+ case 'n' : /* Output number of chars so far */
+ *(va_arg(ap, int *)) = bytes;
+ break;
+ }
+ }
+ else
+ {
+ bytes ++;
+
+ if (bufptr && bufptr < bufend)
+ *bufptr++ = *format;
+
+ format ++;
+ }
+ }
+
+ /*
+ * Nul-terminate the string and return the number of characters needed.
+ */
+
+ *bufptr = '\0';
+
+ return (bytes);
+}
+#endif /* !HAVE_VSNPRINT */
+
+
+#ifndef HAVE_SNPRINTF
+/*
+ * '_cups_snprintf()' - Format a string into a fixed size buffer.
+ */
+
+int /* O - Number of bytes formatted */
+_cups_snprintf(char *buffer, /* O - Output buffer */
+ size_t bufsize, /* O - Size of output buffer */
+ const char *format, /* I - printf-style format string */
+ ...) /* I - Additional arguments as needed */
+{
+ int bytes; /* Number of bytes formatted */
+ va_list ap; /* Pointer to additional arguments */
+
+
+ va_start(ap, format);
+ bytes = vsnprintf(buffer, bufsize, format, ap);
+ va_end(ap);
+
+ return (bytes);
+}
+#endif /* !HAVE_SNPRINTF */
+
+
+/*
+ * End of "$Id$".
+ */
+
diff --git a/cups/sspi-private.h b/cups/sspi-private.h
new file mode 100644
index 000000000..e8f36c2d1
--- /dev/null
+++ b/cups/sspi-private.h
@@ -0,0 +1,82 @@
+/*
+ * Private SSPI definitions for CUPS.
+ *
+ * Copyright 2010 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPS_SSPI_PRIVATE_H_
+# define _CUPS_SSPI_PRIVATE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include <config.h>
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# include <wincrypt.h>
+# include <wintrust.h>
+# include <schannel.h>
+# define SECURITY_WIN32
+# include <security.h>
+# include <sspi.h>
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+typedef struct /**** SSPI/SSL data structure ****/
+{
+ SOCKET sock; /* TCP/IP socket */
+ CredHandle creds; /* Credentials */
+ CtxtHandle context; /* SSL context */
+ BOOL contextInitialized; /* Is context init'd? */
+ SecPkgContext_StreamSizes streamSizes; /* SSL data stream sizes */
+ BYTE *decryptBuffer; /* Data pre-decryption*/
+ size_t decryptBufferLength; /* Length of decrypt buffer */
+ size_t decryptBufferUsed; /* Bytes used in buffer */
+ BYTE *readBuffer; /* Data post-decryption */
+ size_t readBufferLength; /* Length of read buffer */
+ size_t readBufferUsed; /* Bytes used in buffer */
+ DWORD certFlags; /* Cert verification flags */
+} _sspi_struct_t;
+
+
+/*
+ * Prototypes...
+ */
+_sspi_struct_t *_sspiAlloc(void);
+BOOL _sspiAccept(_sspi_struct_t *conn);
+BOOL _sspiConnect(_sspi_struct_t *conn,
+ const CHAR *hostname);
+void _sspiFree(_sspi_struct_t *conn);
+BOOL _sspiGetCredentials(_sspi_struct_t *conn,
+ const LPWSTR containerName,
+ const TCHAR *commonName,
+ BOOL server);
+int _sspiPending(_sspi_struct_t *conn);
+int _sspiRead(_sspi_struct_t *conn,
+ void *buf, size_t len);
+void _sspiSetAllowsAnyRoot(_sspi_struct_t *conn,
+ BOOL allow);
+void _sspiSetAllowsExpiredCerts(_sspi_struct_t *conn,
+ BOOL allow);
+int _sspiWrite(_sspi_struct_t *conn,
+ void *buf, size_t len);
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_SSPI_PRIVATE_H_ */
diff --git a/cups/sspi.c b/cups/sspi.c
new file mode 100644
index 000000000..0efcb5679
--- /dev/null
+++ b/cups/sspi.c
@@ -0,0 +1,1485 @@
+/*
+ * "$Id$"
+ *
+ * Windows SSPI SSL implementation for CUPS.
+ *
+ * Copyright 2010-2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * sspi_alloc() - Allocate SSPI ssl object
+ * _sspiGetCredentials() - Retrieve an SSL/TLS certificate from the
+ * system store If one cannot be found, one is
+ * created.
+ * _sspiConnect() - Make an SSL connection. This function
+ * assumes a TCP/IP connection has already been
+ * successfully made
+ * _sspiAccept() - Accept an SSL/TLS connection
+ * _sspiSetAllowsAnyRoot() - Set the client cert policy for untrusted
+ * root certs
+ * _sspiSetAllowsExpiredCerts() - Set the client cert policy for expired root
+ * certs
+ * _sspiWrite() - Write a buffer to an ssl socket
+ * _sspiRead() - Read a buffer from an ssl socket
+ * _sspiPending() - Returns the number of available bytes
+ * _sspiFree() - Close a connection and free resources
+ * sspi_verify_certificate() - Verify a server certificate
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "sspi-private.h"
+#include "debug-private.h"
+
+
+/* required to link this library for certificate functions */
+#pragma comment(lib, "Crypt32.lib")
+#pragma comment(lib, "Secur32.lib")
+#pragma comment(lib, "Ws2_32.lib")
+
+
+#if !defined(SECURITY_FLAG_IGNORE_UNKNOWN_CA)
+# define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100 /* Untrusted root */
+#endif
+
+#if !defined(SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)
+# define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID 0x00002000 /* Expired X509 Cert. */
+#endif
+
+static DWORD sspi_verify_certificate(PCCERT_CONTEXT serverCert,
+ const CHAR *serverName,
+ DWORD dwCertFlags);
+
+
+/*
+ * 'sspi_alloc()' - Allocate SSPI ssl object
+ */
+_sspi_struct_t* /* O - New SSPI/SSL object */
+_sspiAlloc(void)
+{
+ _sspi_struct_t *conn = calloc(sizeof(_sspi_struct_t), 1);
+
+ if (conn)
+ conn->sock = INVALID_SOCKET;
+
+ return (conn);
+}
+
+
+/*
+ * '_sspiGetCredentials()' - Retrieve an SSL/TLS certificate from the system store
+ * If one cannot be found, one is created.
+ */
+BOOL /* O - 1 on success, 0 on failure */
+_sspiGetCredentials(_sspi_struct_t *conn,
+ /* I - Client connection */
+ const LPWSTR container,
+ /* I - Cert container name */
+ const TCHAR *cn, /* I - Common name of certificate */
+ BOOL isServer)
+ /* I - Is caller a server? */
+{
+ HCERTSTORE store = NULL; /* Certificate store */
+ PCCERT_CONTEXT storedContext = NULL;
+ /* Context created from the store */
+ PCCERT_CONTEXT createdContext = NULL;
+ /* Context created by us */
+ DWORD dwSize = 0; /* 32 bit size */
+ PBYTE p = NULL; /* Temporary storage */
+ HCRYPTPROV hProv = (HCRYPTPROV) NULL;
+ /* Handle to a CSP */
+ CERT_NAME_BLOB sib; /* Arbitrary array of bytes */
+ SCHANNEL_CRED SchannelCred; /* Schannel credential data */
+ TimeStamp tsExpiry; /* Time stamp */
+ SECURITY_STATUS Status; /* Status */
+ HCRYPTKEY hKey = (HCRYPTKEY) NULL;
+ /* Handle to crypto key */
+ CRYPT_KEY_PROV_INFO kpi; /* Key container info */
+ SYSTEMTIME et; /* System time */
+ CERT_EXTENSIONS exts; /* Array of cert extensions */
+ CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */
+ BOOL ok = TRUE; /* Return value */
+
+ if (!conn)
+ return (FALSE);
+ if (!cn)
+ return (FALSE);
+
+ if (!CryptAcquireContextW(&hProv, (LPWSTR) container, MS_DEF_PROV_W,
+ PROV_RSA_FULL,
+ CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
+ {
+ if (GetLastError() == NTE_EXISTS)
+ {
+ if (!CryptAcquireContextW(&hProv, (LPWSTR) container, MS_DEF_PROV_W,
+ PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
+ {
+ DEBUG_printf(("_sspiGetCredentials: CryptAcquireContext failed: %x\n",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+ }
+ }
+
+ store = CertOpenStore(CERT_STORE_PROV_SYSTEM,
+ X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,
+ hProv,
+ CERT_SYSTEM_STORE_LOCAL_MACHINE |
+ CERT_STORE_NO_CRYPT_RELEASE_FLAG |
+ CERT_STORE_OPEN_EXISTING_FLAG,
+ L"MY");
+
+ if (!store)
+ {
+ DEBUG_printf(("_sspiGetCredentials: CertOpenSystemStore failed: %x\n",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ dwSize = 0;
+
+ if (!CertStrToName(X509_ASN_ENCODING, cn, CERT_OID_NAME_STR,
+ NULL, NULL, &dwSize, NULL))
+ {
+ DEBUG_printf(("_sspiGetCredentials: CertStrToName failed: %x\n",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ p = (PBYTE) malloc(dwSize);
+
+ if (!p)
+ {
+ DEBUG_printf(("_sspiGetCredentials: malloc failed for %d bytes", dwSize));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ if (!CertStrToName(X509_ASN_ENCODING, cn, CERT_OID_NAME_STR, NULL,
+ p, &dwSize, NULL))
+ {
+ DEBUG_printf(("_sspiGetCredentials: CertStrToName failed: %x",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ sib.cbData = dwSize;
+ sib.pbData = p;
+
+ storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,
+ 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
+
+ if (!storedContext)
+ {
+ /*
+ * If we couldn't find the context, then we'll
+ * create a new one
+ */
+ if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey))
+ {
+ DEBUG_printf(("_sspiGetCredentials: CryptGenKey failed: %x",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ ZeroMemory(&kpi, sizeof(kpi));
+ kpi.pwszContainerName = (LPWSTR) container;
+ kpi.pwszProvName = MS_DEF_PROV_W;
+ kpi.dwProvType = PROV_RSA_FULL;
+ kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
+ kpi.dwKeySpec = AT_KEYEXCHANGE;
+
+ GetSystemTime(&et);
+ et.wYear += 10;
+
+ ZeroMemory(&exts, sizeof(exts));
+
+ createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL,
+ &et, &exts);
+
+ if (!createdContext)
+ {
+ DEBUG_printf(("_sspiGetCredentials: CertCreateSelfSignCertificate failed: %x",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ if (!CertAddCertificateContextToStore(store, createdContext,
+ CERT_STORE_ADD_REPLACE_EXISTING,
+ &storedContext))
+ {
+ DEBUG_printf(("_sspiGetCredentials: CertAddCertificateContextToStore failed: %x",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ ZeroMemory(&ckp, sizeof(ckp));
+ ckp.pwszContainerName = (LPWSTR) container;
+ ckp.pwszProvName = MS_DEF_PROV_W;
+ ckp.dwProvType = PROV_RSA_FULL;
+ ckp.dwFlags = CRYPT_MACHINE_KEYSET;
+ ckp.dwKeySpec = AT_KEYEXCHANGE;
+
+ if (!CertSetCertificateContextProperty(storedContext,
+ CERT_KEY_PROV_INFO_PROP_ID,
+ 0, &ckp))
+ {
+ DEBUG_printf(("_sspiGetCredentials: CertSetCertificateContextProperty failed: %x",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+ }
+
+ ZeroMemory(&SchannelCred, sizeof(SchannelCred));
+
+ SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
+ SchannelCred.cCreds = 1;
+ SchannelCred.paCred = &storedContext;
+
+ /*
+ * SSPI doesn't seem to like it if grbitEnabledProtocols
+ * is set for a client
+ */
+ if (isServer)
+ SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1;
+
+ /*
+ * Create an SSPI credential.
+ */
+ Status = AcquireCredentialsHandle(NULL, UNISP_NAME,
+ isServer ? SECPKG_CRED_INBOUND:SECPKG_CRED_OUTBOUND,
+ NULL, &SchannelCred, NULL, NULL, &conn->creds,
+ &tsExpiry);
+ if (Status != SEC_E_OK)
+ {
+ DEBUG_printf(("_sspiGetCredentials: AcquireCredentialsHandle failed: %x", Status));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+cleanup:
+
+ /*
+ * Cleanup
+ */
+ if (hKey)
+ CryptDestroyKey(hKey);
+
+ if (createdContext)
+ CertFreeCertificateContext(createdContext);
+
+ if (storedContext)
+ CertFreeCertificateContext(storedContext);
+
+ if (p)
+ free(p);
+
+ if (store)
+ CertCloseStore(store, 0);
+
+ if (hProv)
+ CryptReleaseContext(hProv, 0);
+
+ return (ok);
+}
+
+
+/*
+ * '_sspiConnect()' - Make an SSL connection. This function
+ * assumes a TCP/IP connection has already
+ * been successfully made
+ */
+BOOL /* O - 1 on success, 0 on failure */
+_sspiConnect(_sspi_struct_t *conn, /* I - Client connection */
+ const CHAR *hostname) /* I - Server hostname */
+{
+ PCCERT_CONTEXT serverCert; /* Server certificate */
+ DWORD dwSSPIFlags; /* SSL connection attributes we want */
+ DWORD dwSSPIOutFlags; /* SSL connection attributes we got */
+ TimeStamp tsExpiry; /* Time stamp */
+ SECURITY_STATUS scRet; /* Status */
+ DWORD cbData; /* Data count */
+ SecBufferDesc inBuffer; /* Array of SecBuffer structs */
+ SecBuffer inBuffers[2]; /* Security package buffer */
+ SecBufferDesc outBuffer; /* Array of SecBuffer structs */
+ SecBuffer outBuffers[1]; /* Security package buffer */
+ BOOL ok = TRUE; /* Return value */
+
+ serverCert = NULL;
+
+ dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
+ ISC_REQ_REPLAY_DETECT |
+ ISC_REQ_CONFIDENTIALITY |
+ ISC_RET_EXTENDED_ERROR |
+ ISC_REQ_ALLOCATE_MEMORY |
+ ISC_REQ_STREAM;
+
+ /*
+ * Initiate a ClientHello message and generate a token.
+ */
+ outBuffers[0].pvBuffer = NULL;
+ outBuffers[0].BufferType = SECBUFFER_TOKEN;
+ outBuffers[0].cbBuffer = 0;
+
+ outBuffer.cBuffers = 1;
+ outBuffer.pBuffers = outBuffers;
+ outBuffer.ulVersion = SECBUFFER_VERSION;
+
+ scRet = InitializeSecurityContext(&conn->creds, NULL, TEXT(""), dwSSPIFlags,
+ 0, SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
+ &outBuffer, &dwSSPIOutFlags, &tsExpiry);
+
+ if (scRet != SEC_I_CONTINUE_NEEDED)
+ {
+ DEBUG_printf(("_sspiConnect: InitializeSecurityContext(1) failed: %x", scRet));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ /*
+ * Send response to server if there is one.
+ */
+ if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
+ {
+ cbData = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
+
+ if ((cbData == SOCKET_ERROR) || !cbData)
+ {
+ DEBUG_printf(("_sspiConnect: send failed: %d", WSAGetLastError()));
+ FreeContextBuffer(outBuffers[0].pvBuffer);
+ DeleteSecurityContext(&conn->context);
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ DEBUG_printf(("_sspiConnect: %d bytes of handshake data sent", cbData));
+
+ /*
+ * Free output buffer.
+ */
+ FreeContextBuffer(outBuffers[0].pvBuffer);
+ outBuffers[0].pvBuffer = NULL;
+ }
+
+ dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION |
+ ISC_REQ_SEQUENCE_DETECT |
+ ISC_REQ_REPLAY_DETECT |
+ ISC_REQ_CONFIDENTIALITY |
+ ISC_RET_EXTENDED_ERROR |
+ ISC_REQ_ALLOCATE_MEMORY |
+ ISC_REQ_STREAM;
+
+ conn->decryptBufferUsed = 0;
+
+ /*
+ * Loop until the handshake is finished or an error occurs.
+ */
+ scRet = SEC_I_CONTINUE_NEEDED;
+
+ while(scRet == SEC_I_CONTINUE_NEEDED ||
+ scRet == SEC_E_INCOMPLETE_MESSAGE ||
+ scRet == SEC_I_INCOMPLETE_CREDENTIALS)
+ {
+ if ((conn->decryptBufferUsed == 0) || (scRet == SEC_E_INCOMPLETE_MESSAGE))
+ {
+ if (conn->decryptBufferLength <= conn->decryptBufferUsed)
+ {
+ conn->decryptBufferLength += 4096;
+ conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer, conn->decryptBufferLength);
+
+ if (!conn->decryptBuffer)
+ {
+ DEBUG_printf(("_sspiConnect: unable to allocate %d byte decrypt buffer",
+ conn->decryptBufferLength));
+ SetLastError(E_OUTOFMEMORY);
+ ok = FALSE;
+ goto cleanup;
+ }
+ }
+
+ cbData = recv(conn->sock, conn->decryptBuffer + conn->decryptBufferUsed,
+ (int) (conn->decryptBufferLength - conn->decryptBufferUsed), 0);
+
+ if (cbData == SOCKET_ERROR)
+ {
+ DEBUG_printf(("_sspiConnect: recv failed: %d", WSAGetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+ else if (cbData == 0)
+ {
+ DEBUG_printf(("_sspiConnect: server unexpectedly disconnected"));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ DEBUG_printf(("_sspiConnect: %d bytes of handshake data received",
+ cbData));
+
+ conn->decryptBufferUsed += cbData;
+ }
+
+ /*
+ * Set up the input buffers. Buffer 0 is used to pass in data
+ * received from the server. Schannel will consume some or all
+ * of this. Leftover data (if any) will be placed in buffer 1 and
+ * given a buffer type of SECBUFFER_EXTRA.
+ */
+ inBuffers[0].pvBuffer = conn->decryptBuffer;
+ inBuffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed;
+ inBuffers[0].BufferType = SECBUFFER_TOKEN;
+
+ inBuffers[1].pvBuffer = NULL;
+ inBuffers[1].cbBuffer = 0;
+ inBuffers[1].BufferType = SECBUFFER_EMPTY;
+
+ inBuffer.cBuffers = 2;
+ inBuffer.pBuffers = inBuffers;
+ inBuffer.ulVersion = SECBUFFER_VERSION;
+
+ /*
+ * Set up the output buffers. These are initialized to NULL
+ * so as to make it less likely we'll attempt to free random
+ * garbage later.
+ */
+ outBuffers[0].pvBuffer = NULL;
+ outBuffers[0].BufferType= SECBUFFER_TOKEN;
+ outBuffers[0].cbBuffer = 0;
+
+ outBuffer.cBuffers = 1;
+ outBuffer.pBuffers = outBuffers;
+ outBuffer.ulVersion = SECBUFFER_VERSION;
+
+ /*
+ * Call InitializeSecurityContext.
+ */
+ scRet = InitializeSecurityContext(&conn->creds, &conn->context, NULL, dwSSPIFlags,
+ 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL,
+ &outBuffer, &dwSSPIOutFlags, &tsExpiry);
+
+ /*
+ * If InitializeSecurityContext was successful (or if the error was
+ * one of the special extended ones), send the contends of the output
+ * buffer to the server.
+ */
+ if (scRet == SEC_E_OK ||
+ scRet == SEC_I_CONTINUE_NEEDED ||
+ FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
+ {
+ if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
+ {
+ cbData = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
+
+ if ((cbData == SOCKET_ERROR) || !cbData)
+ {
+ DEBUG_printf(("_sspiConnect: send failed: %d", WSAGetLastError()));
+ FreeContextBuffer(outBuffers[0].pvBuffer);
+ DeleteSecurityContext(&conn->context);
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ DEBUG_printf(("_sspiConnect: %d bytes of handshake data sent", cbData));
+
+ /*
+ * Free output buffer.
+ */
+ FreeContextBuffer(outBuffers[0].pvBuffer);
+ outBuffers[0].pvBuffer = NULL;
+ }
+ }
+
+ /*
+ * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE,
+ * then we need to read more data from the server and try again.
+ */
+ if (scRet == SEC_E_INCOMPLETE_MESSAGE)
+ continue;
+
+ /*
+ * If InitializeSecurityContext returned SEC_E_OK, then the
+ * handshake completed successfully.
+ */
+ if (scRet == SEC_E_OK)
+ {
+ /*
+ * If the "extra" buffer contains data, this is encrypted application
+ * protocol layer stuff. It needs to be saved. The application layer
+ * will later decrypt it with DecryptMessage.
+ */
+ DEBUG_printf(("_sspiConnect: Handshake was successful"));
+
+ if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
+ {
+ if (conn->decryptBufferLength < inBuffers[1].cbBuffer)
+ {
+ conn->decryptBuffer = realloc(conn->decryptBuffer, inBuffers[1].cbBuffer);
+
+ if (!conn->decryptBuffer)
+ {
+ DEBUG_printf(("_sspiConnect: unable to allocate %d bytes for decrypt buffer",
+ inBuffers[1].cbBuffer));
+ SetLastError(E_OUTOFMEMORY);
+ ok = FALSE;
+ goto cleanup;
+ }
+ }
+
+ memmove(conn->decryptBuffer,
+ conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer),
+ inBuffers[1].cbBuffer);
+
+ conn->decryptBufferUsed = inBuffers[1].cbBuffer;
+
+ DEBUG_printf(("_sspiConnect: %d bytes of app data was bundled with handshake data",
+ conn->decryptBufferUsed));
+ }
+ else
+ conn->decryptBufferUsed = 0;
+
+ /*
+ * Bail out to quit
+ */
+ break;
+ }
+
+ /*
+ * Check for fatal error.
+ */
+ if (FAILED(scRet))
+ {
+ DEBUG_printf(("_sspiConnect: InitializeSecurityContext(2) failed: %x", scRet));
+ ok = FALSE;
+ break;
+ }
+
+ /*
+ * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
+ * then the server just requested client authentication.
+ */
+ if (scRet == SEC_I_INCOMPLETE_CREDENTIALS)
+ {
+ /*
+ * Unimplemented
+ */
+ DEBUG_printf(("_sspiConnect: server requested client credentials"));
+ ok = FALSE;
+ break;
+ }
+
+ /*
+ * Copy any leftover data from the "extra" buffer, and go around
+ * again.
+ */
+ if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
+ {
+ memmove(conn->decryptBuffer,
+ conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer),
+ inBuffers[1].cbBuffer);
+
+ conn->decryptBufferUsed = inBuffers[1].cbBuffer;
+ }
+ else
+ {
+ conn->decryptBufferUsed = 0;
+ }
+ }
+
+ if (ok)
+ {
+ conn->contextInitialized = TRUE;
+
+ /*
+ * Get the server cert
+ */
+ scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID*) &serverCert );
+
+ if (scRet != SEC_E_OK)
+ {
+ DEBUG_printf(("_sspiConnect: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %x", scRet));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ scRet = sspi_verify_certificate(serverCert, hostname, conn->certFlags);
+
+ if (scRet != SEC_E_OK)
+ {
+ DEBUG_printf(("_sspiConnect: sspi_verify_certificate failed: %x", scRet));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ /*
+ * Find out how big the header/trailer will be:
+ */
+ scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes);
+
+ if (scRet != SEC_E_OK)
+ {
+ DEBUG_printf(("_sspiConnect: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %x", scRet));
+ ok = FALSE;
+ }
+ }
+
+cleanup:
+
+ if (serverCert)
+ CertFreeCertificateContext(serverCert);
+
+ return (ok);
+}
+
+
+/*
+ * '_sspiAccept()' - Accept an SSL/TLS connection
+ */
+BOOL /* O - 1 on success, 0 on failure */
+_sspiAccept(_sspi_struct_t *conn) /* I - Client connection */
+{
+ DWORD dwSSPIFlags; /* SSL connection attributes we want */
+ DWORD dwSSPIOutFlags; /* SSL connection attributes we got */
+ TimeStamp tsExpiry; /* Time stamp */
+ SECURITY_STATUS scRet; /* SSPI Status */
+ SecBufferDesc inBuffer; /* Array of SecBuffer structs */
+ SecBuffer inBuffers[2]; /* Security package buffer */
+ SecBufferDesc outBuffer; /* Array of SecBuffer structs */
+ SecBuffer outBuffers[1]; /* Security package buffer */
+ DWORD num = 0; /* 32 bit status value */
+ BOOL fInitContext = TRUE;
+ /* Has the context been init'd? */
+ BOOL ok = TRUE; /* Return value */
+
+ if (!conn)
+ return (FALSE);
+
+ dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |
+ ASC_REQ_REPLAY_DETECT |
+ ASC_REQ_CONFIDENTIALITY |
+ ASC_REQ_EXTENDED_ERROR |
+ ASC_REQ_ALLOCATE_MEMORY |
+ ASC_REQ_STREAM;
+
+ conn->decryptBufferUsed = 0;
+
+ /*
+ * Set OutBuffer for AcceptSecurityContext call
+ */
+ outBuffer.cBuffers = 1;
+ outBuffer.pBuffers = outBuffers;
+ outBuffer.ulVersion = SECBUFFER_VERSION;
+
+ scRet = SEC_I_CONTINUE_NEEDED;
+
+ while (scRet == SEC_I_CONTINUE_NEEDED ||
+ scRet == SEC_E_INCOMPLETE_MESSAGE ||
+ scRet == SEC_I_INCOMPLETE_CREDENTIALS)
+ {
+ if ((conn->decryptBufferUsed == 0) || (scRet == SEC_E_INCOMPLETE_MESSAGE))
+ {
+ if (conn->decryptBufferLength <= conn->decryptBufferUsed)
+ {
+ conn->decryptBufferLength += 4096;
+ conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer,
+ conn->decryptBufferLength);
+
+ if (!conn->decryptBuffer)
+ {
+ DEBUG_printf(("_sspiAccept: unable to allocate %d byte decrypt buffer",
+ conn->decryptBufferLength));
+ ok = FALSE;
+ goto cleanup;
+ }
+ }
+
+ for (;;)
+ {
+ num = recv(conn->sock,
+ conn->decryptBuffer + conn->decryptBufferUsed,
+ (int)(conn->decryptBufferLength - conn->decryptBufferUsed),
+ 0);
+
+ if ((num == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
+ Sleep(1);
+ else
+ break;
+ }
+
+ if (num == SOCKET_ERROR)
+ {
+ DEBUG_printf(("_sspiAccept: recv failed: %d", WSAGetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+ else if (num == 0)
+ {
+ DEBUG_printf(("_sspiAccept: client disconnected"));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ DEBUG_printf(("_sspiAccept: received %d (handshake) bytes from client",
+ num));
+ conn->decryptBufferUsed += num;
+ }
+
+ /*
+ * InBuffers[1] is for getting extra data that
+ * SSPI/SCHANNEL doesn't proccess on this
+ * run around the loop.
+ */
+ inBuffers[0].pvBuffer = conn->decryptBuffer;
+ inBuffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed;
+ inBuffers[0].BufferType = SECBUFFER_TOKEN;
+
+ inBuffers[1].pvBuffer = NULL;
+ inBuffers[1].cbBuffer = 0;
+ inBuffers[1].BufferType = SECBUFFER_EMPTY;
+
+ inBuffer.cBuffers = 2;
+ inBuffer.pBuffers = inBuffers;
+ inBuffer.ulVersion = SECBUFFER_VERSION;
+
+ /*
+ * Initialize these so if we fail, pvBuffer contains NULL,
+ * so we don't try to free random garbage at the quit
+ */
+ outBuffers[0].pvBuffer = NULL;
+ outBuffers[0].BufferType = SECBUFFER_TOKEN;
+ outBuffers[0].cbBuffer = 0;
+
+ scRet = AcceptSecurityContext(&conn->creds, (fInitContext?NULL:&conn->context),
+ &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP,
+ (fInitContext?&conn->context:NULL), &outBuffer,
+ &dwSSPIOutFlags, &tsExpiry);
+
+ fInitContext = FALSE;
+
+ if (scRet == SEC_E_OK ||
+ scRet == SEC_I_CONTINUE_NEEDED ||
+ (FAILED(scRet) && ((dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR) != 0)))
+ {
+ if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
+ {
+ /*
+ * Send response to server if there is one
+ */
+ num = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
+
+ if ((num == SOCKET_ERROR) || (num == 0))
+ {
+ DEBUG_printf(("_sspiAccept: handshake send failed: %d", WSAGetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ DEBUG_printf(("_sspiAccept: send %d handshake bytes to client",
+ outBuffers[0].cbBuffer));
+
+ FreeContextBuffer(outBuffers[0].pvBuffer);
+ outBuffers[0].pvBuffer = NULL;
+ }
+ }
+
+ if (scRet == SEC_E_OK)
+ {
+ /*
+ * If there's extra data then save it for
+ * next time we go to decrypt
+ */
+ if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
+ {
+ memcpy(conn->decryptBuffer,
+ (LPBYTE) (conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer)),
+ inBuffers[1].cbBuffer);
+ conn->decryptBufferUsed = inBuffers[1].cbBuffer;
+ }
+ else
+ {
+ conn->decryptBufferUsed = 0;
+ }
+
+ ok = TRUE;
+ break;
+ }
+ else if (FAILED(scRet) && (scRet != SEC_E_INCOMPLETE_MESSAGE))
+ {
+ DEBUG_printf(("_sspiAccept: AcceptSecurityContext failed: %x", scRet));
+ ok = FALSE;
+ break;
+ }
+
+ if (scRet != SEC_E_INCOMPLETE_MESSAGE &&
+ scRet != SEC_I_INCOMPLETE_CREDENTIALS)
+ {
+ if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
+ {
+ memcpy(conn->decryptBuffer,
+ (LPBYTE) (conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer)),
+ inBuffers[1].cbBuffer);
+ conn->decryptBufferUsed = inBuffers[1].cbBuffer;
+ }
+ else
+ {
+ conn->decryptBufferUsed = 0;
+ }
+ }
+ }
+
+ if (ok)
+ {
+ conn->contextInitialized = TRUE;
+
+ /*
+ * Find out how big the header will be:
+ */
+ scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes);
+
+ if (scRet != SEC_E_OK)
+ {
+ DEBUG_printf(("_sspiAccept: QueryContextAttributes failed: %x", scRet));
+ ok = FALSE;
+ }
+ }
+
+cleanup:
+
+ return (ok);
+}
+
+
+/*
+ * '_sspiSetAllowsAnyRoot()' - Set the client cert policy for untrusted root certs
+ */
+void
+_sspiSetAllowsAnyRoot(_sspi_struct_t *conn,
+ /* I - Client connection */
+ BOOL allow)
+ /* I - Allow any root */
+{
+ conn->certFlags = (allow) ? conn->certFlags | SECURITY_FLAG_IGNORE_UNKNOWN_CA :
+ conn->certFlags & ~SECURITY_FLAG_IGNORE_UNKNOWN_CA;
+}
+
+
+/*
+ * '_sspiSetAllowsExpiredCerts()' - Set the client cert policy for expired root certs
+ */
+void
+_sspiSetAllowsExpiredCerts(_sspi_struct_t *conn,
+ /* I - Client connection */
+ BOOL allow)
+ /* I - Allow expired certs */
+{
+ conn->certFlags = (allow) ? conn->certFlags | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID :
+ conn->certFlags & ~SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
+}
+
+
+/*
+ * '_sspiWrite()' - Write a buffer to an ssl socket
+ */
+int /* O - Bytes written or SOCKET_ERROR */
+_sspiWrite(_sspi_struct_t *conn, /* I - Client connection */
+ void *buf, /* I - Buffer */
+ size_t len) /* I - Buffer length */
+{
+ SecBufferDesc message; /* Array of SecBuffer struct */
+ SecBuffer buffers[4] = { 0 }; /* Security package buffer */
+ BYTE *buffer = NULL; /* Scratch buffer */
+ int bufferLen; /* Buffer length */
+ size_t bytesLeft; /* Bytes left to write */
+ int index = 0; /* Index into buffer */
+ int num = 0; /* Return value */
+
+ if (!conn || !buf || !len)
+ {
+ WSASetLastError(WSAEINVAL);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+
+ bufferLen = conn->streamSizes.cbMaximumMessage +
+ conn->streamSizes.cbHeader +
+ conn->streamSizes.cbTrailer;
+
+ buffer = (BYTE*) malloc(bufferLen);
+
+ if (!buffer)
+ {
+ DEBUG_printf(("_sspiWrite: buffer alloc of %d bytes failed", bufferLen));
+ WSASetLastError(E_OUTOFMEMORY);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+
+ bytesLeft = len;
+
+ while (bytesLeft)
+ {
+ size_t chunk = min(conn->streamSizes.cbMaximumMessage, /* Size of data to write */
+ bytesLeft);
+ SECURITY_STATUS scRet; /* SSPI status */
+
+ /*
+ * Copy user data into the buffer, starting
+ * just past the header
+ */
+ memcpy(buffer + conn->streamSizes.cbHeader,
+ ((BYTE*) buf) + index,
+ chunk);
+
+ /*
+ * Setup the SSPI buffers
+ */
+ message.ulVersion = SECBUFFER_VERSION;
+ message.cBuffers = 4;
+ message.pBuffers = buffers;
+ buffers[0].pvBuffer = buffer;
+ buffers[0].cbBuffer = conn->streamSizes.cbHeader;
+ buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
+ buffers[1].pvBuffer = buffer + conn->streamSizes.cbHeader;
+ buffers[1].cbBuffer = (unsigned long) chunk;
+ buffers[1].BufferType = SECBUFFER_DATA;
+ buffers[2].pvBuffer = buffer + conn->streamSizes.cbHeader + chunk;
+ buffers[2].cbBuffer = conn->streamSizes.cbTrailer;
+ buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
+ buffers[3].BufferType = SECBUFFER_EMPTY;
+
+ /*
+ * Encrypt the data
+ */
+ scRet = EncryptMessage(&conn->context, 0, &message, 0);
+
+ if (FAILED(scRet))
+ {
+ DEBUG_printf(("_sspiWrite: EncryptMessage failed: %x", scRet));
+ WSASetLastError(WSASYSCALLFAILURE);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+
+ /*
+ * Send the data. Remember the size of
+ * the total data to send is the size
+ * of the header, the size of the data
+ * the caller passed in and the size
+ * of the trailer
+ */
+ num = send(conn->sock,
+ buffer,
+ buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer,
+ 0);
+
+ if ((num == SOCKET_ERROR) || (num == 0))
+ {
+ DEBUG_printf(("_sspiWrite: send failed: %ld", WSAGetLastError()));
+ goto cleanup;
+ }
+
+ bytesLeft -= (int) chunk;
+ index += (int) chunk;
+ }
+
+ num = (int) len;
+
+cleanup:
+
+ if (buffer)
+ free(buffer);
+
+ return (num);
+}
+
+
+/*
+ * '_sspiRead()' - Read a buffer from an ssl socket
+ */
+int /* O - Bytes read or SOCKET_ERROR */
+_sspiRead(_sspi_struct_t *conn, /* I - Client connection */
+ void *buf, /* I - Buffer */
+ size_t len) /* I - Buffer length */
+{
+ SecBufferDesc message; /* Array of SecBuffer struct */
+ SecBuffer buffers[4] = { 0 }; /* Security package buffer */
+ int num = 0; /* Return value */
+
+ if (!conn)
+ {
+ WSASetLastError(WSAEINVAL);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+
+ /*
+ * If there are bytes that have already been
+ * decrypted and have not yet been read, return
+ * those
+ */
+ if (buf && (conn->readBufferUsed > 0))
+ {
+ int bytesToCopy = (int) min(conn->readBufferUsed, len); /* Amount of bytes to copy */
+ /* from read buffer */
+
+ memcpy(buf, conn->readBuffer, bytesToCopy);
+ conn->readBufferUsed -= bytesToCopy;
+
+ if (conn->readBufferUsed > 0)
+ /*
+ * If the caller didn't request all the bytes
+ * we have in the buffer, then move the unread
+ * bytes down
+ */
+ memmove(conn->readBuffer,
+ conn->readBuffer + bytesToCopy,
+ conn->readBufferUsed);
+
+ num = bytesToCopy;
+ }
+ else
+ {
+ PSecBuffer pDataBuffer; /* Data buffer */
+ PSecBuffer pExtraBuffer; /* Excess data buffer */
+ SECURITY_STATUS scRet; /* SSPI status */
+ int i; /* Loop control variable */
+
+ /*
+ * Initialize security buffer structs
+ */
+ message.ulVersion = SECBUFFER_VERSION;
+ message.cBuffers = 4;
+ message.pBuffers = buffers;
+
+ do
+ {
+ /*
+ * If there is not enough space in the
+ * buffer, then increase it's size
+ */
+ if (conn->decryptBufferLength <= conn->decryptBufferUsed)
+ {
+ conn->decryptBufferLength += 4096;
+ conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer,
+ conn->decryptBufferLength);
+
+ if (!conn->decryptBuffer)
+ {
+ DEBUG_printf(("_sspiRead: unable to allocate %d byte buffer",
+ conn->decryptBufferLength));
+ WSASetLastError(E_OUTOFMEMORY);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+ }
+
+ buffers[0].pvBuffer = conn->decryptBuffer;
+ buffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed;
+ buffers[0].BufferType = SECBUFFER_DATA;
+ buffers[1].BufferType = SECBUFFER_EMPTY;
+ buffers[2].BufferType = SECBUFFER_EMPTY;
+ buffers[3].BufferType = SECBUFFER_EMPTY;
+
+ scRet = DecryptMessage(&conn->context, &message, 0, NULL);
+
+ if (scRet == SEC_E_INCOMPLETE_MESSAGE)
+ {
+ if (buf)
+ {
+ num = recv(conn->sock,
+ conn->decryptBuffer + conn->decryptBufferUsed,
+ (int)(conn->decryptBufferLength - conn->decryptBufferUsed),
+ 0);
+ if (num == SOCKET_ERROR)
+ {
+ DEBUG_printf(("_sspiRead: recv failed: %d", WSAGetLastError()));
+ goto cleanup;
+ }
+ else if (num == 0)
+ {
+ DEBUG_printf(("_sspiRead: server disconnected"));
+ goto cleanup;
+ }
+
+ conn->decryptBufferUsed += num;
+ }
+ else
+ {
+ num = (int) conn->readBufferUsed;
+ goto cleanup;
+ }
+ }
+ }
+ while (scRet == SEC_E_INCOMPLETE_MESSAGE);
+
+ if (scRet == SEC_I_CONTEXT_EXPIRED)
+ {
+ DEBUG_printf(("_sspiRead: context expired"));
+ WSASetLastError(WSAECONNRESET);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+ else if (scRet != SEC_E_OK)
+ {
+ DEBUG_printf(("_sspiRead: DecryptMessage failed: %lx", scRet));
+ WSASetLastError(WSASYSCALLFAILURE);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+
+ /*
+ * The decryption worked. Now, locate data buffer.
+ */
+ pDataBuffer = NULL;
+ pExtraBuffer = NULL;
+ for (i = 1; i < 4; i++)
+ {
+ if (buffers[i].BufferType == SECBUFFER_DATA)
+ pDataBuffer = &buffers[i];
+ else if (!pExtraBuffer && (buffers[i].BufferType == SECBUFFER_EXTRA))
+ pExtraBuffer = &buffers[i];
+ }
+
+ /*
+ * If a data buffer is found, then copy
+ * the decrypted bytes to the passed-in
+ * buffer
+ */
+ if (pDataBuffer)
+ {
+ int bytesToCopy = min(pDataBuffer->cbBuffer, (int) len);
+ /* Number of bytes to copy into buf */
+ int bytesToSave = pDataBuffer->cbBuffer - bytesToCopy;
+ /* Number of bytes to save in our read buffer */
+
+ if (bytesToCopy)
+ memcpy(buf, pDataBuffer->pvBuffer, bytesToCopy);
+
+ /*
+ * If there are more decrypted bytes than can be
+ * copied to the passed in buffer, then save them
+ */
+ if (bytesToSave)
+ {
+ if ((int)(conn->readBufferLength - conn->readBufferUsed) < bytesToSave)
+ {
+ conn->readBufferLength = conn->readBufferUsed + bytesToSave;
+ conn->readBuffer = realloc(conn->readBuffer,
+ conn->readBufferLength);
+
+ if (!conn->readBuffer)
+ {
+ DEBUG_printf(("_sspiRead: unable to allocate %d bytes", conn->readBufferLength));
+ WSASetLastError(E_OUTOFMEMORY);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+ }
+
+ memcpy(((BYTE*) conn->readBuffer) + conn->readBufferUsed,
+ ((BYTE*) pDataBuffer->pvBuffer) + bytesToCopy,
+ bytesToSave);
+
+ conn->readBufferUsed += bytesToSave;
+ }
+
+ num = (buf) ? bytesToCopy : (int) conn->readBufferUsed;
+ }
+ else
+ {
+ DEBUG_printf(("_sspiRead: unable to find data buffer"));
+ WSASetLastError(WSASYSCALLFAILURE);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+
+ /*
+ * If the decryption process left extra bytes,
+ * then save those back in decryptBuffer. They will
+ * be processed the next time through the loop.
+ */
+ if (pExtraBuffer)
+ {
+ memmove(conn->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
+ conn->decryptBufferUsed = pExtraBuffer->cbBuffer;
+ }
+ else
+ {
+ conn->decryptBufferUsed = 0;
+ }
+ }
+
+cleanup:
+
+ return (num);
+}
+
+
+/*
+ * '_sspiPending()' - Returns the number of available bytes
+ */
+int /* O - Number of available bytes */
+_sspiPending(_sspi_struct_t *conn) /* I - Client connection */
+{
+ return (_sspiRead(conn, NULL, 0));
+}
+
+
+/*
+ * '_sspiFree()' - Close a connection and free resources
+ */
+void
+_sspiFree(_sspi_struct_t *conn) /* I - Client connection */
+{
+ if (!conn)
+ return;
+
+ if (conn->contextInitialized)
+ {
+ SecBufferDesc message; /* Array of SecBuffer struct */
+ SecBuffer buffers[1] = { 0 };
+ /* Security package buffer */
+ DWORD dwType; /* Type */
+ DWORD status; /* Status */
+
+ /*
+ * Notify schannel that we are about to close the connection.
+ */
+ dwType = SCHANNEL_SHUTDOWN;
+
+ buffers[0].pvBuffer = &dwType;
+ buffers[0].BufferType = SECBUFFER_TOKEN;
+ buffers[0].cbBuffer = sizeof(dwType);
+
+ message.cBuffers = 1;
+ message.pBuffers = buffers;
+ message.ulVersion = SECBUFFER_VERSION;
+
+ status = ApplyControlToken(&conn->context, &message);
+
+ if (SUCCEEDED(status))
+ {
+ PBYTE pbMessage; /* Message buffer */
+ DWORD cbMessage; /* Message buffer count */
+ DWORD cbData; /* Data count */
+ DWORD dwSSPIFlags; /* SSL attributes we requested */
+ DWORD dwSSPIOutFlags; /* SSL attributes we received */
+ TimeStamp tsExpiry; /* Time stamp */
+
+ dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |
+ ASC_REQ_REPLAY_DETECT |
+ ASC_REQ_CONFIDENTIALITY |
+ ASC_REQ_EXTENDED_ERROR |
+ ASC_REQ_ALLOCATE_MEMORY |
+ ASC_REQ_STREAM;
+
+ buffers[0].pvBuffer = NULL;
+ buffers[0].BufferType = SECBUFFER_TOKEN;
+ buffers[0].cbBuffer = 0;
+
+ message.cBuffers = 1;
+ message.pBuffers = buffers;
+ message.ulVersion = SECBUFFER_VERSION;
+
+ status = AcceptSecurityContext(&conn->creds, &conn->context, NULL,
+ dwSSPIFlags, SECURITY_NATIVE_DREP, NULL,
+ &message, &dwSSPIOutFlags, &tsExpiry);
+
+ if (SUCCEEDED(status))
+ {
+ pbMessage = buffers[0].pvBuffer;
+ cbMessage = buffers[0].cbBuffer;
+
+ /*
+ * Send the close notify message to the client.
+ */
+ if (pbMessage && cbMessage)
+ {
+ cbData = send(conn->sock, pbMessage, cbMessage, 0);
+ if ((cbData == SOCKET_ERROR) || (cbData == 0))
+ {
+ status = WSAGetLastError();
+ DEBUG_printf(("_sspiFree: sending close notify failed: %d", status));
+ }
+ else
+ {
+ FreeContextBuffer(pbMessage);
+ }
+ }
+ }
+ else
+ {
+ DEBUG_printf(("_sspiFree: AcceptSecurityContext failed: %x", status));
+ }
+ }
+ else
+ {
+ DEBUG_printf(("_sspiFree: ApplyControlToken failed: %x", status));
+ }
+
+ DeleteSecurityContext(&conn->context);
+ conn->contextInitialized = FALSE;
+ }
+
+ if (conn->decryptBuffer)
+ {
+ free(conn->decryptBuffer);
+ conn->decryptBuffer = NULL;
+ }
+
+ if (conn->readBuffer)
+ {
+ free(conn->readBuffer);
+ conn->readBuffer = NULL;
+ }
+
+ if (conn->sock != INVALID_SOCKET)
+ {
+ closesocket(conn->sock);
+ conn->sock = INVALID_SOCKET;
+ }
+
+ free(conn);
+}
+
+
+/*
+ * 'sspi_verify_certificate()' - Verify a server certificate
+ */
+static DWORD /* 0 - Error code (0 == No error) */
+sspi_verify_certificate(PCCERT_CONTEXT serverCert,
+ /* I - Server certificate */
+ const CHAR *serverName,
+ /* I - Server name */
+ DWORD dwCertFlags)
+ /* I - Verification flags */
+{
+ HTTPSPolicyCallbackData httpsPolicy;
+ /* HTTPS Policy Struct */
+ CERT_CHAIN_POLICY_PARA policyPara;
+ /* Cert chain policy parameters */
+ CERT_CHAIN_POLICY_STATUS policyStatus;
+ /* Cert chain policy status */
+ CERT_CHAIN_PARA chainPara;
+ /* Used for searching and matching criteria */
+ PCCERT_CHAIN_CONTEXT chainContext = NULL;
+ /* Certificate chain */
+ PWSTR serverNameUnicode = NULL;
+ /* Unicode server name */
+ LPSTR rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH,
+ szOID_SERVER_GATED_CRYPTO,
+ szOID_SGC_NETSCAPE };
+ /* How are we using this certificate? */
+ DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
+ /* Number of ites in rgszUsages */
+ DWORD count; /* 32 bit count variable */
+ DWORD status; /* Return value */
+
+ if (!serverCert)
+ {
+ status = SEC_E_WRONG_PRINCIPAL;
+ goto cleanup;
+ }
+
+ /*
+ * Convert server name to unicode.
+ */
+ if (!serverName || (strlen(serverName) == 0))
+ {
+ status = SEC_E_WRONG_PRINCIPAL;
+ goto cleanup;
+ }
+
+ count = MultiByteToWideChar(CP_ACP, 0, serverName, -1, NULL, 0);
+ serverNameUnicode = LocalAlloc(LMEM_FIXED, count * sizeof(WCHAR));
+ if (!serverNameUnicode)
+ {
+ status = SEC_E_INSUFFICIENT_MEMORY;
+ goto cleanup;
+ }
+ count = MultiByteToWideChar(CP_ACP, 0, serverName, -1, serverNameUnicode, count);
+ if (count == 0)
+ {
+ status = SEC_E_WRONG_PRINCIPAL;
+ goto cleanup;
+ }
+
+ /*
+ * Build certificate chain.
+ */
+ ZeroMemory(&chainPara, sizeof(chainPara));
+ chainPara.cbSize = sizeof(chainPara);
+ chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
+ chainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages;
+ chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;
+
+ if (!CertGetCertificateChain(NULL, serverCert, NULL, serverCert->hCertStore,
+ &chainPara, 0, NULL, &chainContext))
+ {
+ status = GetLastError();
+ DEBUG_printf(("CertGetCertificateChain returned 0x%x\n", status));
+ goto cleanup;
+ }
+
+ /*
+ * Validate certificate chain.
+ */
+ ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData));
+ httpsPolicy.cbStruct = sizeof(HTTPSPolicyCallbackData);
+ httpsPolicy.dwAuthType = AUTHTYPE_SERVER;
+ httpsPolicy.fdwChecks = dwCertFlags;
+ httpsPolicy.pwszServerName = serverNameUnicode;
+
+ memset(&policyPara, 0, sizeof(policyPara));
+ policyPara.cbSize = sizeof(policyPara);
+ policyPara.pvExtraPolicyPara = &httpsPolicy;
+
+ memset(&policyStatus, 0, sizeof(policyStatus));
+ policyStatus.cbSize = sizeof(policyStatus);
+
+ if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext,
+ &policyPara, &policyStatus))
+ {
+ status = GetLastError();
+ DEBUG_printf(("CertVerifyCertificateChainPolicy returned %d", status));
+ goto cleanup;
+ }
+
+ if (policyStatus.dwError)
+ {
+ status = policyStatus.dwError;
+ goto cleanup;
+ }
+
+ status = SEC_E_OK;
+
+cleanup:
+
+ if (chainContext)
+ CertFreeCertificateChain(chainContext);
+
+ if (serverNameUnicode)
+ LocalFree(serverNameUnicode);
+
+ return (status);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/string-private.h b/cups/string-private.h
new file mode 100644
index 000000000..e16d63b84
--- /dev/null
+++ b/cups/string-private.h
@@ -0,0 +1,203 @@
+/*
+ * "$Id$"
+ *
+ * Private string definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_STRING_PRIVATE_H_
+# define _CUPS_STRING_PRIVATE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <stdarg.h>
+# include <ctype.h>
+# include <errno.h>
+# include <locale.h>
+
+# include "config.h"
+
+# ifdef HAVE_STRING_H
+# include <string.h>
+# endif /* HAVE_STRING_H */
+
+# ifdef HAVE_STRINGS_H
+# include <strings.h>
+# endif /* HAVE_STRINGS_H */
+
+# ifdef HAVE_BSTRING_H
+# include <bstring.h>
+# endif /* HAVE_BSTRING_H */
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * String pool structures...
+ */
+
+# define _CUPS_STR_GUARD 0x12344321
+
+typedef struct _cups_sp_item_s /**** String Pool Item ****/
+{
+# ifdef DEBUG_GUARDS
+ unsigned int guard; /* Guard word */
+# endif /* DEBUG_GUARDS */
+ unsigned int ref_count; /* Reference count */
+ char str[1]; /* String */
+} _cups_sp_item_t;
+
+
+/*
+ * Replacements for the ctype macros that are not affected by locale, since we
+ * really only care about testing for ASCII characters when parsing files, etc.
+ *
+ * The _CUPS_INLINE definition controls whether we get an inline function body,
+ * and external function body, or an external definition.
+ */
+
+# if defined(__GNUC__) || __STDC_VERSION__ >= 199901L
+# define _CUPS_INLINE static inline
+# elif defined(_MSC_VER)
+# define _CUPS_INLINE static __inline
+# elif defined(_CUPS_STRING_C_)
+# define _CUPS_INLINE
+# endif /* __GNUC__ || __STDC_VERSION__ */
+
+# ifdef _CUPS_INLINE
+_CUPS_INLINE int /* O - 1 on match, 0 otherwise */
+_cups_isalnum(int ch) /* I - Character to test */
+{
+ return ((ch >= '0' && ch <= '9') ||
+ (ch >= 'A' && ch <= 'Z') ||
+ (ch >= 'a' && ch <= 'z'));
+}
+
+_CUPS_INLINE int /* O - 1 on match, 0 otherwise */
+_cups_isalpha(int ch) /* I - Character to test */
+{
+ return ((ch >= 'A' && ch <= 'Z') ||
+ (ch >= 'a' && ch <= 'z'));
+}
+
+_CUPS_INLINE int /* O - 1 on match, 0 otherwise */
+_cups_isspace(int ch) /* I - Character to test */
+{
+ return (ch == ' ' || ch == '\f' || ch == '\n' || ch == '\r' || ch == '\t' ||
+ ch == '\v');
+}
+
+_CUPS_INLINE int /* O - 1 on match, 0 otherwise */
+_cups_isupper(int ch) /* I - Character to test */
+{
+ return (ch >= 'A' && ch <= 'Z');
+}
+
+_CUPS_INLINE int /* O - Converted character */
+_cups_tolower(int ch) /* I - Character to convert */
+{
+ return (_cups_isupper(ch) ? ch - 'A' + 'a' : ch);
+}
+# else
+extern int _cups_isalnum(int ch);
+extern int _cups_isalpha(int ch);
+extern int _cups_isspace(int ch);
+extern int _cups_isupper(int ch);
+extern int _cups_tolower(int ch);
+# endif /* _CUPS_INLINE */
+
+
+/*
+ * Prototypes...
+ */
+
+extern void _cups_strcpy(char *dst, const char *src);
+
+# ifndef HAVE_STRDUP
+extern char *_cups_strdup(const char *);
+# define strdup _cups_strdup
+# endif /* !HAVE_STRDUP */
+
+extern int _cups_strcasecmp(const char *, const char *);
+
+extern int _cups_strncasecmp(const char *, const char *, size_t n);
+
+# ifndef HAVE_STRLCAT
+extern size_t _cups_strlcat(char *, const char *, size_t);
+# define strlcat _cups_strlcat
+# endif /* !HAVE_STRLCAT */
+
+# ifndef HAVE_STRLCPY
+extern size_t _cups_strlcpy(char *, const char *, size_t);
+# define strlcpy _cups_strlcpy
+# endif /* !HAVE_STRLCPY */
+
+# ifndef HAVE_SNPRINTF
+extern int _cups_snprintf(char *, size_t, const char *, ...)
+# ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 3, 4)))
+# endif /* __GNUC__ */
+;
+# define snprintf _cups_snprintf
+# endif /* !HAVE_SNPRINTF */
+
+# ifndef HAVE_VSNPRINTF
+extern int _cups_vsnprintf(char *, size_t, const char *, va_list);
+# define vsnprintf _cups_vsnprintf
+# endif /* !HAVE_VSNPRINTF */
+
+/*
+ * String pool functions...
+ */
+
+extern char *_cupsStrAlloc(const char *s);
+extern void _cupsStrFlush(void);
+extern void _cupsStrFree(const char *s);
+extern char *_cupsStrRetain(const char *s);
+extern size_t _cupsStrStatistics(size_t *alloc_bytes, size_t *total_bytes);
+
+
+/*
+ * Floating point number functions...
+ */
+
+extern char *_cupsStrFormatd(char *buf, char *bufend, double number,
+ struct lconv *loc);
+extern double _cupsStrScand(const char *buf, char **bufptr,
+ struct lconv *loc);
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_STRING_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/string.c b/cups/string.c
new file mode 100644
index 000000000..60e346453
--- /dev/null
+++ b/cups/string.c
@@ -0,0 +1,759 @@
+/*
+ * "$Id$"
+ *
+ * String functions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsStrAlloc() - Allocate/reference a string.
+ * _cupsStrFlush() - Flush the string pool.
+ * _cupsStrFormatd() - Format a floating-point number.
+ * _cupsStrFree() - Free/dereference a string.
+ * _cupsStrRetain() - Increment the reference count of a string.
+ * _cupsStrScand() - Scan a string for a floating-point number.
+ * _cupsStrStatistics() - Return allocation statistics for string pool.
+ * _cups_strcpy() - Copy a string allowing for overlapping strings.
+ * _cups_strdup() - Duplicate a string.
+ * _cups_strcasecmp() - Do a case-insensitive comparison.
+ * _cups_strncasecmp() - Do a case-insensitive comparison on up to N chars.
+ * _cups_strlcat() - Safely concatenate two strings.
+ * _cups_strlcpy() - Safely copy two strings.
+ * compare_sp_items() - Compare two string pool items...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#define _CUPS_STRING_C_
+#include "string-private.h"
+#include "debug-private.h"
+#include "thread-private.h"
+#include "array.h"
+#include <stddef.h>
+#include <limits.h>
+
+
+/*
+ * Local globals...
+ */
+
+static _cups_mutex_t sp_mutex = _CUPS_MUTEX_INITIALIZER;
+ /* Mutex to control access to pool */
+static cups_array_t *stringpool = NULL;
+ /* Global string pool */
+
+
+/*
+ * Local functions...
+ */
+
+static int compare_sp_items(_cups_sp_item_t *a, _cups_sp_item_t *b);
+
+
+/*
+ * '_cupsStrAlloc()' - Allocate/reference a string.
+ */
+
+char * /* O - String pointer */
+_cupsStrAlloc(const char *s) /* I - String */
+{
+ _cups_sp_item_t *item, /* String pool item */
+ *key; /* Search key */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!s)
+ return (NULL);
+
+ /*
+ * Get the string pool...
+ */
+
+ _cupsMutexLock(&sp_mutex);
+
+ if (!stringpool)
+ stringpool = cupsArrayNew((cups_array_func_t)compare_sp_items, NULL);
+
+ if (!stringpool)
+ {
+ _cupsMutexUnlock(&sp_mutex);
+
+ return (NULL);
+ }
+
+ /*
+ * See if the string is already in the pool...
+ */
+
+ key = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str));
+
+ if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, key)) != NULL)
+ {
+ /*
+ * Found it, return the cached string...
+ */
+
+ item->ref_count ++;
+
+#ifdef DEBUG_GUARDS
+ DEBUG_printf(("5_cupsStrAlloc: Using string %p(%s) for \"%s\", guard=%08x, "
+ "ref_count=%d", item, item->str, s, item->guard,
+ item->ref_count));
+
+ if (item->guard != _CUPS_STR_GUARD)
+ abort();
+#endif /* DEBUG_GUARDS */
+
+ _cupsMutexUnlock(&sp_mutex);
+
+ return (item->str);
+ }
+
+ /*
+ * Not found, so allocate a new one...
+ */
+
+ item = (_cups_sp_item_t *)calloc(1, sizeof(_cups_sp_item_t) + strlen(s));
+ if (!item)
+ {
+ _cupsMutexUnlock(&sp_mutex);
+
+ return (NULL);
+ }
+
+ item->ref_count = 1;
+ strcpy(item->str, s);
+
+#ifdef DEBUG_GUARDS
+ item->guard = _CUPS_STR_GUARD;
+
+ DEBUG_printf(("5_cupsStrAlloc: Created string %p(%s) for \"%s\", guard=%08x, "
+ "ref_count=%d", item, item->str, s, item->guard,
+ item->ref_count));
+#endif /* DEBUG_GUARDS */
+
+ /*
+ * Add the string to the pool and return it...
+ */
+
+ cupsArrayAdd(stringpool, item);
+
+ _cupsMutexUnlock(&sp_mutex);
+
+ return (item->str);
+}
+
+
+/*
+ * '_cupsStrFlush()' - Flush the string pool.
+ */
+
+void
+_cupsStrFlush(void)
+{
+ _cups_sp_item_t *item; /* Current item */
+
+
+ DEBUG_printf(("4_cupsStrFlush: %d strings in array",
+ cupsArrayCount(stringpool)));
+
+ _cupsMutexLock(&sp_mutex);
+
+ for (item = (_cups_sp_item_t *)cupsArrayFirst(stringpool);
+ item;
+ item = (_cups_sp_item_t *)cupsArrayNext(stringpool))
+ free(item);
+
+ cupsArrayDelete(stringpool);
+ stringpool = NULL;
+
+ _cupsMutexUnlock(&sp_mutex);
+}
+
+
+/*
+ * '_cupsStrFormatd()' - Format a floating-point number.
+ */
+
+char * /* O - Pointer to end of string */
+_cupsStrFormatd(char *buf, /* I - String */
+ char *bufend, /* I - End of string buffer */
+ double number, /* I - Number to format */
+ struct lconv *loc) /* I - Locale data */
+{
+ char *bufptr, /* Pointer into buffer */
+ temp[1024], /* Temporary string */
+ *tempdec, /* Pointer to decimal point */
+ *tempptr; /* Pointer into temporary string */
+ const char *dec; /* Decimal point */
+ int declen; /* Length of decimal point */
+
+
+ /*
+ * Format the number using the "%.12f" format and then eliminate
+ * unnecessary trailing 0's.
+ */
+
+ snprintf(temp, sizeof(temp), "%.12f", number);
+ for (tempptr = temp + strlen(temp) - 1;
+ tempptr > temp && *tempptr == '0';
+ *tempptr-- = '\0');
+
+ /*
+ * Next, find the decimal point...
+ */
+
+ if (loc && loc->decimal_point)
+ {
+ dec = loc->decimal_point;
+ declen = (int)strlen(dec);
+ }
+ else
+ {
+ dec = ".";
+ declen = 1;
+ }
+
+ if (declen == 1)
+ tempdec = strchr(temp, *dec);
+ else
+ tempdec = strstr(temp, dec);
+
+ /*
+ * Copy everything up to the decimal point...
+ */
+
+ if (tempdec)
+ {
+ for (tempptr = temp, bufptr = buf;
+ tempptr < tempdec && bufptr < bufend;
+ *bufptr++ = *tempptr++);
+
+ tempptr += declen;
+
+ if (*tempptr && bufptr < bufend)
+ {
+ *bufptr++ = '.';
+
+ while (*tempptr && bufptr < bufend)
+ *bufptr++ = *tempptr++;
+ }
+
+ *bufptr = '\0';
+ }
+ else
+ {
+ strlcpy(buf, temp, bufend - buf + 1);
+ bufptr = buf + strlen(buf);
+ }
+
+ return (bufptr);
+}
+
+
+/*
+ * '_cupsStrFree()' - Free/dereference a string.
+ */
+
+void
+_cupsStrFree(const char *s) /* I - String to free */
+{
+ _cups_sp_item_t *item, /* String pool item */
+ *key; /* Search key */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!s)
+ return;
+
+ /*
+ * Check the string pool...
+ *
+ * We don't need to lock the mutex yet, as we only want to know if
+ * the stringpool is initialized. The rest of the code will still
+ * work if it is initialized before we lock...
+ */
+
+ if (!stringpool)
+ return;
+
+ /*
+ * See if the string is already in the pool...
+ */
+
+ _cupsMutexLock(&sp_mutex);
+
+ key = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str));
+
+#ifdef DEBUG_GUARDS
+ if (key->guard != _CUPS_STR_GUARD)
+ {
+ DEBUG_printf(("5_cupsStrFree: Freeing string %p(%s), guard=%08x, "
+ "ref_count=%d", key, key->str, key->guard, key->ref_count));
+ abort();
+ }
+#endif /* DEBUG_GUARDS */
+
+ if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, key)) != NULL &&
+ item == key)
+ {
+ /*
+ * Found it, dereference...
+ */
+
+ item->ref_count --;
+
+ if (!item->ref_count)
+ {
+ /*
+ * Remove and free...
+ */
+
+ cupsArrayRemove(stringpool, item);
+
+ free(item);
+ }
+ }
+
+ _cupsMutexUnlock(&sp_mutex);
+}
+
+
+/*
+ * '_cupsStrRetain()' - Increment the reference count of a string.
+ *
+ * Note: This function does not verify that the passed pointer is in the
+ * string pool, so any calls to it MUST know they are passing in a
+ * good pointer.
+ */
+
+char * /* O - Pointer to string */
+_cupsStrRetain(const char *s) /* I - String to retain */
+{
+ _cups_sp_item_t *item; /* Pointer to string pool item */
+
+
+ if (s)
+ {
+ item = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str));
+
+#ifdef DEBUG_GUARDS
+ if (item->guard != _CUPS_STR_GUARD)
+ {
+ DEBUG_printf(("5_cupsStrRetain: Retaining string %p(%s), guard=%08x, "
+ "ref_count=%d", item, s, item->guard, item->ref_count));
+ abort();
+ }
+#endif /* DEBUG_GUARDS */
+
+ _cupsMutexLock(&sp_mutex);
+
+ item->ref_count ++;
+
+ _cupsMutexUnlock(&sp_mutex);
+ }
+
+ return ((char *)s);
+}
+
+
+/*
+ * '_cupsStrScand()' - Scan a string for a floating-point number.
+ *
+ * This function handles the locale-specific BS so that a decimal
+ * point is always the period (".")...
+ */
+
+double /* O - Number */
+_cupsStrScand(const char *buf, /* I - Pointer to number */
+ char **bufptr, /* O - New pointer or NULL on error */
+ struct lconv *loc) /* I - Locale data */
+{
+ char temp[1024], /* Temporary buffer */
+ *tempptr; /* Pointer into temporary buffer */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!buf)
+ return (0.0);
+
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (_cups_isspace(*buf))
+ buf ++;
+
+ /*
+ * Copy leading sign, numbers, period, and then numbers...
+ */
+
+ tempptr = temp;
+ if (*buf == '-' || *buf == '+')
+ *tempptr++ = *buf++;
+
+ while (isdigit(*buf & 255))
+ if (tempptr < (temp + sizeof(temp) - 1))
+ *tempptr++ = *buf++;
+ else
+ {
+ if (bufptr)
+ *bufptr = NULL;
+
+ return (0.0);
+ }
+
+ if (*buf == '.')
+ {
+ /*
+ * Read fractional portion of number...
+ */
+
+ buf ++;
+
+ if (loc && loc->decimal_point)
+ {
+ strlcpy(tempptr, loc->decimal_point, sizeof(temp) - (tempptr - temp));
+ tempptr += strlen(tempptr);
+ }
+ else if (tempptr < (temp + sizeof(temp) - 1))
+ *tempptr++ = '.';
+ else
+ {
+ if (bufptr)
+ *bufptr = NULL;
+
+ return (0.0);
+ }
+
+ while (isdigit(*buf & 255))
+ if (tempptr < (temp + sizeof(temp) - 1))
+ *tempptr++ = *buf++;
+ else
+ {
+ if (bufptr)
+ *bufptr = NULL;
+
+ return (0.0);
+ }
+ }
+
+ if (*buf == 'e' || *buf == 'E')
+ {
+ /*
+ * Read exponent...
+ */
+
+ if (tempptr < (temp + sizeof(temp) - 1))
+ *tempptr++ = *buf++;
+ else
+ {
+ if (bufptr)
+ *bufptr = NULL;
+
+ return (0.0);
+ }
+
+ if (*buf == '+' || *buf == '-')
+ {
+ if (tempptr < (temp + sizeof(temp) - 1))
+ *tempptr++ = *buf++;
+ else
+ {
+ if (bufptr)
+ *bufptr = NULL;
+
+ return (0.0);
+ }
+ }
+
+ while (isdigit(*buf & 255))
+ if (tempptr < (temp + sizeof(temp) - 1))
+ *tempptr++ = *buf++;
+ else
+ {
+ if (bufptr)
+ *bufptr = NULL;
+
+ return (0.0);
+ }
+ }
+
+ /*
+ * Nul-terminate the temporary string and return the value...
+ */
+
+ if (bufptr)
+ *bufptr = (char *)buf;
+
+ *tempptr = '\0';
+
+ return (strtod(temp, NULL));
+}
+
+
+/*
+ * '_cupsStrStatistics()' - Return allocation statistics for string pool.
+ */
+
+size_t /* O - Number of strings */
+_cupsStrStatistics(size_t *alloc_bytes, /* O - Allocated bytes */
+ size_t *total_bytes) /* O - Total string bytes */
+{
+ size_t count, /* Number of strings */
+ abytes, /* Allocated string bytes */
+ tbytes, /* Total string bytes */
+ len; /* Length of string */
+ _cups_sp_item_t *item; /* Current item */
+
+
+ /*
+ * Loop through strings in pool, counting everything up...
+ */
+
+ _cupsMutexLock(&sp_mutex);
+
+ for (count = 0, abytes = 0, tbytes = 0,
+ item = (_cups_sp_item_t *)cupsArrayFirst(stringpool);
+ item;
+ item = (_cups_sp_item_t *)cupsArrayNext(stringpool))
+ {
+ /*
+ * Count allocated memory, using a 64-bit aligned buffer as a basis.
+ */
+
+ count += item->ref_count;
+ len = (strlen(item->str) + 8) & ~7;
+ abytes += sizeof(_cups_sp_item_t) + len;
+ tbytes += item->ref_count * len;
+ }
+
+ _cupsMutexUnlock(&sp_mutex);
+
+ /*
+ * Return values...
+ */
+
+ if (alloc_bytes)
+ *alloc_bytes = abytes;
+
+ if (total_bytes)
+ *total_bytes = tbytes;
+
+ return (count);
+}
+
+
+/*
+ * '_cups_strcpy()' - Copy a string allowing for overlapping strings.
+ */
+
+void
+_cups_strcpy(char *dst, /* I - Destination string */
+ const char *src) /* I - Source string */
+{
+ while (*src)
+ *dst++ = *src++;
+
+ *dst = '\0';
+}
+
+
+/*
+ * '_cups_strdup()' - Duplicate a string.
+ */
+
+#ifndef HAVE_STRDUP
+char * /* O - New string pointer */
+_cups_strdup(const char *s) /* I - String to duplicate */
+{
+ char *t; /* New string pointer */
+
+
+ if (s == NULL)
+ return (NULL);
+
+ if ((t = malloc(strlen(s) + 1)) == NULL)
+ return (NULL);
+
+ return (strcpy(t, s));
+}
+#endif /* !HAVE_STRDUP */
+
+
+/*
+ * '_cups_strcasecmp()' - Do a case-insensitive comparison.
+ */
+
+int /* O - Result of comparison (-1, 0, or 1) */
+_cups_strcasecmp(const char *s, /* I - First string */
+ const char *t) /* I - Second string */
+{
+ while (*s != '\0' && *t != '\0')
+ {
+ if (_cups_tolower(*s) < _cups_tolower(*t))
+ return (-1);
+ else if (_cups_tolower(*s) > _cups_tolower(*t))
+ return (1);
+
+ s ++;
+ t ++;
+ }
+
+ if (*s == '\0' && *t == '\0')
+ return (0);
+ else if (*s != '\0')
+ return (1);
+ else
+ return (-1);
+}
+
+/*
+ * '_cups_strncasecmp()' - Do a case-insensitive comparison on up to N chars.
+ */
+
+int /* O - Result of comparison (-1, 0, or 1) */
+_cups_strncasecmp(const char *s, /* I - First string */
+ const char *t, /* I - Second string */
+ size_t n) /* I - Maximum number of characters to compare */
+{
+ while (*s != '\0' && *t != '\0' && n > 0)
+ {
+ if (_cups_tolower(*s) < _cups_tolower(*t))
+ return (-1);
+ else if (_cups_tolower(*s) > _cups_tolower(*t))
+ return (1);
+
+ s ++;
+ t ++;
+ n --;
+ }
+
+ if (n == 0)
+ return (0);
+ else if (*s == '\0' && *t == '\0')
+ return (0);
+ else if (*s != '\0')
+ return (1);
+ else
+ return (-1);
+}
+
+
+#ifndef HAVE_STRLCAT
+/*
+ * '_cups_strlcat()' - Safely concatenate two strings.
+ */
+
+size_t /* O - Length of string */
+_cups_strlcat(char *dst, /* O - Destination string */
+ const char *src, /* I - Source string */
+ size_t size) /* I - Size of destination string buffer */
+{
+ size_t srclen; /* Length of source string */
+ size_t dstlen; /* Length of destination string */
+
+
+ /*
+ * Figure out how much room is left...
+ */
+
+ dstlen = strlen(dst);
+ size -= dstlen + 1;
+
+ if (!size)
+ return (dstlen); /* No room, return immediately... */
+
+ /*
+ * Figure out how much room is needed...
+ */
+
+ srclen = strlen(src);
+
+ /*
+ * Copy the appropriate amount...
+ */
+
+ if (srclen > size)
+ srclen = size;
+
+ memcpy(dst + dstlen, src, srclen);
+ dst[dstlen + srclen] = '\0';
+
+ return (dstlen + srclen);
+}
+#endif /* !HAVE_STRLCAT */
+
+
+#ifndef HAVE_STRLCPY
+/*
+ * '_cups_strlcpy()' - Safely copy two strings.
+ */
+
+size_t /* O - Length of string */
+_cups_strlcpy(char *dst, /* O - Destination string */
+ const char *src, /* I - Source string */
+ size_t size) /* I - Size of destination string buffer */
+{
+ size_t srclen; /* Length of source string */
+
+
+ /*
+ * Figure out how much room is needed...
+ */
+
+ size --;
+
+ srclen = strlen(src);
+
+ /*
+ * Copy the appropriate amount...
+ */
+
+ if (srclen > size)
+ srclen = size;
+
+ memcpy(dst, src, srclen);
+ dst[srclen] = '\0';
+
+ return (srclen);
+}
+#endif /* !HAVE_STRLCPY */
+
+
+/*
+ * 'compare_sp_items()' - Compare two string pool items...
+ */
+
+static int /* O - Result of comparison */
+compare_sp_items(_cups_sp_item_t *a, /* I - First item */
+ _cups_sp_item_t *b) /* I - Second item */
+{
+ return (strcmp(a->str, b->str));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/tempfile.c b/cups/tempfile.c
new file mode 100644
index 000000000..0eec46471
--- /dev/null
+++ b/cups/tempfile.c
@@ -0,0 +1,233 @@
+/*
+ * "$Id$"
+ *
+ * Temp file utilities for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsTempFd() - Creates a temporary file.
+ * cupsTempFile() - Generates a temporary filename.
+ * cupsTempFile2() - Creates a temporary CUPS file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+#else
+# include <unistd.h>
+#endif /* WIN32 || __EMX__ */
+
+
+/*
+ * 'cupsTempFd()' - Creates a temporary file.
+ *
+ * The temporary filename is returned in the filename buffer.
+ * The temporary file is opened for reading and writing.
+ */
+
+int /* O - New file descriptor or -1 on error */
+cupsTempFd(char *filename, /* I - Pointer to buffer */
+ int len) /* I - Size of buffer */
+{
+ int fd; /* File descriptor for temp file */
+ int tries; /* Number of tries */
+ const char *tmpdir; /* TMPDIR environment var */
+#ifdef WIN32
+ char tmppath[1024]; /* Windows temporary directory */
+ DWORD curtime; /* Current time */
+#else
+ struct timeval curtime; /* Current time */
+#endif /* WIN32 */
+
+
+ /*
+ * See if TMPDIR is defined...
+ */
+
+#ifdef WIN32
+ if ((tmpdir = getenv("TEMP")) == NULL)
+ {
+ GetTempPath(sizeof(tmppath), tmppath);
+ tmpdir = tmppath;
+ }
+#else
+ /*
+ * Previously we put root temporary files in the default CUPS temporary
+ * directory under /var/spool/cups. However, since the scheduler cleans
+ * out temporary files there and runs independently of the user apps, we
+ * don't want to use it unless specifically told to by cupsd.
+ */
+
+ if ((tmpdir = getenv("TMPDIR")) == NULL)
+# ifdef __APPLE__
+ tmpdir = "/private/tmp"; /* /tmp is a symlink to /private/tmp */
+# else
+ tmpdir = "/tmp";
+# endif /* __APPLE__ */
+#endif /* WIN32 */
+
+ /*
+ * Make the temporary name using the specified directory...
+ */
+
+ tries = 0;
+
+ do
+ {
+#ifdef WIN32
+ /*
+ * Get the current time of day...
+ */
+
+ curtime = GetTickCount() + tries;
+
+ /*
+ * Format a string using the hex time values...
+ */
+
+ snprintf(filename, len - 1, "%s/%05lx%08lx", tmpdir,
+ GetCurrentProcessId(), curtime);
+#else
+ /*
+ * Get the current time of day...
+ */
+
+ gettimeofday(&curtime, NULL);
+
+ /*
+ * Format a string using the hex time values...
+ */
+
+ snprintf(filename, len - 1, "%s/%05x%08x", tmpdir, (unsigned)getpid(),
+ (unsigned)(curtime.tv_sec + curtime.tv_usec + tries));
+#endif /* WIN32 */
+
+ /*
+ * Open the file in "exclusive" mode, making sure that we don't
+ * stomp on an existing file or someone's symlink crack...
+ */
+
+#ifdef WIN32
+ fd = open(filename, _O_CREAT | _O_RDWR | _O_TRUNC | _O_BINARY,
+ _S_IREAD | _S_IWRITE);
+#elif defined(O_NOFOLLOW)
+ fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
+#else
+ fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+#endif /* WIN32 */
+
+ if (fd < 0 && errno != EEXIST)
+ break;
+
+ tries ++;
+ }
+ while (fd < 0 && tries < 1000);
+
+ /*
+ * Return the file descriptor...
+ */
+
+ return (fd);
+}
+
+
+/*
+ * 'cupsTempFile()' - Generates a temporary filename.
+ *
+ * The temporary filename is returned in the filename buffer.
+ * This function is deprecated - use @link cupsTempFd@ or
+ * @link cupsTempFile2@ instead.
+ *
+ * @deprecated@
+ */
+
+char * /* O - Filename or @code NULL@ on error */
+cupsTempFile(char *filename, /* I - Pointer to buffer */
+ int len) /* I - Size of buffer */
+{
+ int fd; /* File descriptor for temp file */
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ /*
+ * See if a filename was specified...
+ */
+
+ if (filename == NULL)
+ {
+ filename = cg->tempfile;
+ len = sizeof(cg->tempfile);
+ }
+
+ /*
+ * Create the temporary file...
+ */
+
+ if ((fd = cupsTempFd(filename, len)) < 0)
+ return (NULL);
+
+ /*
+ * Close the temp file - it'll be reopened later as needed...
+ */
+
+ close(fd);
+
+ /*
+ * Return the temp filename...
+ */
+
+ return (filename);
+}
+
+
+/*
+ * 'cupsTempFile2()' - Creates a temporary CUPS file.
+ *
+ * The temporary filename is returned in the filename buffer.
+ * The temporary file is opened for writing.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+cups_file_t * /* O - CUPS file or @code NULL@ on error */
+cupsTempFile2(char *filename, /* I - Pointer to buffer */
+ int len) /* I - Size of buffer */
+{
+ cups_file_t *file; /* CUPS file */
+ int fd; /* File descriptor */
+
+
+ if ((fd = cupsTempFd(filename, len)) < 0)
+ return (NULL);
+ else if ((file = cupsFileOpenFd(fd, "w")) == NULL)
+ {
+ close(fd);
+ unlink(filename);
+ return (NULL);
+ }
+ else
+ return (file);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/test.ppd b/cups/test.ppd
new file mode 100644
index 000000000..ed7fe1d1d
--- /dev/null
+++ b/cups/test.ppd
@@ -0,0 +1,262 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Test PPD file for CUPS.
+*%
+*% This file is used to test the CUPS PPD API functions and cannot be
+*% used with any known printers. Look on the CUPS web site for working PPD
+*% files.
+*%
+*% If you are a PPD file developer, consider using the PPD compiler (ppdc)
+*% to create your PPD files - not only will it save you time, it produces
+*% consistently high-quality files.
+*%
+*% Copyright 2007-2010 by Apple Inc.
+*% Copyright 2002-2006 by Easy Software Products.
+*%
+*% These coded instructions, statements, and computer programs are the
+*% property of Apple Inc. 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
+*% file is missing or damaged, see the license at "http://www.cups.org/".
+*FormatVersion: "4.3"
+*FileVersion: "1.3"
+*LanguageVersion: English
+*LanguageEncoding: ISOLatin1
+*PCFileName: "TEST.PPD"
+*Manufacturer: "ESP"
+*Product: "(Test)"
+*cupsVersion: 1.4
+*ModelName: "Test"
+*ShortNickName: "Test"
+*NickName: "Test for CUPS"
+*PSVersion: "(3010.000) 0"
+*LanguageLevel: "3"
+*ColorDevice: True
+*DefaultColorSpace: RGB
+*FileSystem: False
+*Throughput: "1"
+*LandscapeOrientation: Plus90
+*TTRasterizer: Type42
+*cupsFilter: "application/vnd.cups-raster 0 -"
+*RequiresPageRegion All: True
+
+*% These constraints are used to test ppdConflicts() and cupsResolveConflicts()
+*UIConstraints: *PageSize Letter *InputSlot Envelope
+*UIConstraints: *InputSlot Envelope *PageSize Letter
+*UIConstraints: *PageRegion Letter *InputSlot Envelope
+*UIConstraints: *InputSlot Envelope *PageRegion Letter
+
+*% These constraints are used to test ppdInstallableConflict()
+*UIConstraints: "*Duplex *InstalledDuplexer False"
+*UIConstraints: "*InstalledDuplexer False *Duplex"
+
+*% These attributes test ppdFindAttr/ppdFindNext...
+*cupsTest Foo/I Love Foo: ""
+*cupsTest Bar/I Love Bar: ""
+
+*% For PageSize, we have put all of the translations in-line...
+*OpenUI *PageSize/Page Size: PickOne
+*fr.Translation PageSize/French Page Size: ""
+*fr_CA.Translation PageSize/French Canadian Page Size: ""
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize Letter/US Letter: "PageSize=Letter"
+*fr.PageSize Letter/French US Letter: ""
+*fr_CA.PageSize Letter/French Canadian US Letter: ""
+*PageSize Letter.Banner/US Letter Banner: "PageSize=Letter.Banner"
+*fr.PageSize Letter.Banner/French US Letter Banner: ""
+*fr_CA.PageSize Letter.Banner/French Canadian US Letter Banner: ""
+*PageSize Letter.Fullbleed/US Letter Borderless: "PageSize=Letter.Fullbleed"
+*fr.PageSize Letter.Fullbleed/French US Letter Borderless: ""
+*fr_CA.PageSize Letter.Fullbleed/French Canadian US Letter Borderless: ""
+*PageSize A4/A4: "PageSize=A4"
+*fr.PageSize A4/French A4: ""
+*fr_CA.PageSize A4/French Canadian A4: ""
+*PageSize Env10/#10 Envelope: "PageSize=Env10"
+*fr.PageSize Env10/French #10 Envelope: ""
+*fr_CA.PageSize Env10/French Canadian #10 Envelope: ""
+*CloseUI: *PageSize
+
+*% For PageRegion, we have separated the translations...
+*OpenUI *PageRegion/Page Region: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter/US Letter: "PageRegion=Letter"
+*PageRegion Letter.Banner/US Letter Banner: "PageRegion=Letter.Fullbleed"
+*PageRegion Letter.Fullbleed/US Letter Borderless: "PageRegion=Letter.Fullbleed"
+*PageRegion A4/A4: "PageRegion=A4"
+*PageRegion Env10/#10 Envelope: "PageRegion=Env10"
+*CloseUI: *PageRegion
+
+*fr.Translation PageRegion/French Page Region: ""
+*fr.PageRegion Letter/French US Letter: ""
+*fr.PageRegion Letter.Banner/French US Letter Banner: ""
+*fr.PageRegion Letter.Fullbleed/French US Letter Borderless: ""
+*fr.PageRegion A4/French A4: ""
+*fr.PageRegion Env10/French #10 Envelope: ""
+
+*fr_CA.Translation PageRegion/French Canadian Page Region: ""
+*fr_CA.PageRegion Letter/French Canadian US Letter: ""
+*fr_CA.PageRegion Letter.Banner/French Canadian US Letter Banner: ""
+*fr_CA.PageRegion Letter.Fullbleed/French Canadian US Letter Borderless: ""
+*fr_CA.PageRegion A4/French Canadian A4: ""
+*fr_CA.PageRegion Env10/French Canadian #10 Envelope: ""
+
+*DefaultImageableArea: Letter
+*ImageableArea Letter: "18 36 594 756"
+*ImageableArea Letter.Banner: "18 0 594 792"
+*ImageableArea Letter.Fullbleed: "0 0 612 792"
+*ImageableArea A4: "18 36 577 806"
+*ImageableArea Env10: "18 36 279 648"
+
+*DefaultPaperDimension: Letter
+*PaperDimension Letter: "612 792"
+*PaperDimension Letter.Banner: "612 792"
+*PaperDimension Letter.Fullbleed: "612 792"
+*PaperDimension A4: "595 842"
+*PaperDimension Env10: "297 684"
+
+*% Custom page size support
+*HWMargins: 0 0 0 0
+*NonUIOrderDependency: 100 AnySetup *CustomPageSize True
+*CustomPageSize True/Custom Page Size: "PageSize=Custom"
+*ParamCustomPageSize Width: 1 points 36 1080
+*ParamCustomPageSize Height: 2 points 36 86400
+*ParamCustomPageSize WidthOffset/Width Offset: 3 points 0 0
+*ParamCustomPageSize HeightOffset/Height Offset: 4 points 0 0
+*ParamCustomPageSize Orientation: 5 int 0 0
+
+*OpenUI *InputSlot/Input Slot: PickOne
+*OrderDependency: 20 AnySetup *InputSlot
+*DefaultInputSlot: Tray
+*InputSlot Tray/Tray: "InputSlot=Tray"
+*InputSlot Manual/Manual Feed: "InputSlot=Manual"
+*InputSlot Envelope/Envelope Feed: "InputSlot=Envelope"
+*CloseUI: *InputSlot
+
+*OpenUI *MediaType/Media Type: PickOne
+*OrderDependency: 25 AnySetup *MediaType
+*DefaultMediaType: Plain
+*MediaType Plain/Plain Paper: "MediaType=Plain"
+*MediaType Matte/Matte Photo: "MediaType=Matte"
+*MediaType Glossy/Glossy Photo: "MediaType=Glossy"
+*MediaType Transparency/Transparency Film: "MediaType=Transparency"
+*CloseUI: *MediaType
+
+*OpenUI *Duplex/2-Sided Printing: PickOne
+*OrderDependency: 10 DocumentSetup *Duplex
+*DefaultDuplex: None
+*Duplex None/Off: "Duplex=None"
+*Duplex DuplexNoTumble/Long Edge: "Duplex=DuplexNoTumble"
+*Duplex DuplexTumble/Short Edge: "Duplex=DuplexTumble"
+*CloseUI: *Duplex
+
+*% Installable option...
+*OpenGroup: InstallableOptions/Installable Options
+*OpenUI InstalledDuplexer/Duplexer Installed: Boolean
+*DefaultInstalledDuplexer: False
+*InstalledDuplexer False: ""
+*InstalledDuplexer True: ""
+*CloseUI: *InstalledDuplexer
+*CloseGroup: InstallableOptions
+
+*% Custom options...
+*OpenGroup: Extended/Extended Options
+
+*OpenUI IntOption/Integer: PickOne
+*OrderDependency: 30 AnySetup *IntOption
+*DefaultIntOption: None
+*IntOption None: ""
+*IntOption 1: "IntOption=1"
+*IntOption 2: "IntOption=2"
+*IntOption 3: "IntOption=3"
+*CloseUI: *IntOption
+
+*CustomIntOption True/Custom Integer: "IntOption=Custom"
+*ParamCustomIntOption Integer: 1 int -100 100
+
+*OpenUI StringOption/String: PickOne
+*OrderDependency: 40 AnySetup *StringOption
+*DefaultStringOption: None
+*StringOption None: ""
+*StringOption foo: "StringOption=foo"
+*StringOption bar: "StringOption=bar"
+*CloseUI: *StringOption
+
+*CustomStringOption True/Custom String: "StringOption=Custom"
+*ParamCustomStringOption String1: 2 string 1 10
+*ParamCustomStringOption String2: 1 string 1 10
+
+*CloseGroup: Extended
+
+*% IPP reasons for ppdLocalizeIPPReason tests
+*cupsIPPReason foo/Foo Reason: "http://foo/bar.html
+help:anchor='foo'%20bookID=Vendor%20Help
+/help/foo/bar.html"
+*End
+*fr.cupsIPPReason foo/La Foo Reason: "text:La%20Long%20
+text:Foo%20Reason
+http://foo/fr/bar.html
+help:anchor='foo'%20bookID=Vendor%20Help
+/help/fr/foo/bar.html"
+*End
+*zh_TW.cupsIPPReason foo/Number 1 Foo Reason: "text:Number%201%20
+text:Foo%20Reason
+http://foo/zh_TW/bar.html
+help:anchor='foo'%20bookID=Vendor%20Help
+/help/zh_TW/foo/bar.html"
+*End
+*zh.cupsIPPReason foo/Number 2 Foo Reason: "text:Number%202%20
+text:Foo%20Reason
+http://foo/zh/bar.html
+help:anchor='foo'%20bookID=Vendor%20Help
+/help/zh/foo/bar.html"
+*End
+
+*% Marker names for ppdLocalizeMarkerName tests
+*cupsMarkerName cyan/Cyan Toner: ""
+*fr.cupsMarkerName cyan/La Toner Cyan: ""
+*zh_TW.cupsMarkerName cyan/Number 1 Cyan Toner: ""
+*zh.cupsMarkerName cyan/Number 2 Cyan Toner: ""
+
+*DefaultFont: Courier
+*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM
+*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM
+*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM
+*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM
+*Font Bookman-Demi: Standard "(001.004S)" Standard ROM
+*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM
+*Font Bookman-Light: Standard "(001.004S)" Standard ROM
+*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM
+*Font Courier: Standard "(002.004S)" Standard ROM
+*Font Courier-Bold: Standard "(002.004S)" Standard ROM
+*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM
+*Font Courier-Oblique: Standard "(002.004S)" Standard ROM
+*Font Helvetica: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM
+*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM
+*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM
+*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM
+*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM
+*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM
+*Font Palatino-Bold: Standard "(001.005S)" Standard ROM
+*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM
+*Font Palatino-Italic: Standard "(001.005S)" Standard ROM
+*Font Palatino-Roman: Standard "(001.005S)" Standard ROM
+*Font Symbol: Special "(001.007S)" Special ROM
+*Font Times-Bold: Standard "(001.007S)" Standard ROM
+*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM
+*Font Times-Italic: Standard "(001.007S)" Standard ROM
+*Font Times-Roman: Standard "(001.007S)" Standard ROM
+*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM
+*Font ZapfDingbats: Special "(001.004S)" Standard ROM
+*%
+*% End of "$Id$".
+*%
diff --git a/cups/test2.ppd b/cups/test2.ppd
new file mode 100644
index 000000000..78ff2f7f0
--- /dev/null
+++ b/cups/test2.ppd
@@ -0,0 +1,252 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Test PPD file #2 for CUPS.
+*%
+*% This file is used to test the CUPS PPD API functions and cannot be
+*% used with any known printers. Look on the CUPS web site for working PPD
+*% files.
+*%
+*% If you are a PPD file developer, consider using the PPD compiler (ppdc)
+*% to create your PPD files - not only will it save you time, it produces
+*% consistently high-quality files.
+*%
+*% Copyright 2007-2011 by Apple Inc.
+*% Copyright 2002-2006 by Easy Software Products.
+*%
+*% These coded instructions, statements, and computer programs are the
+*% property of Apple Inc. 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
+*% file is missing or damaged, see the license at "http://www.cups.org/".
+*FormatVersion: "4.3"
+*FileVersion: "1.3"
+*LanguageVersion: English
+*LanguageEncoding: ISOLatin1
+*PCFileName: "TEST.PPD"
+*Manufacturer: "ESP"
+*Product: "(Test2)"
+*cupsVersion: 1.4
+*ModelName: "Test2"
+*ShortNickName: "Test2"
+*NickName: "Test2 for CUPS"
+*PSVersion: "(3010.000) 0"
+*LanguageLevel: "3"
+*ColorDevice: True
+*DefaultColorSpace: RGB
+*FileSystem: False
+*Throughput: "1"
+*LandscapeOrientation: Plus90
+*TTRasterizer: Type42
+
+*% These constraints are used to test ppdConflicts() and cupsResolveConflicts()
+*cupsUIConstraints envelope: "*PageSize Letter *InputSlot Envelope"
+*cupsUIConstraints envelope: "*PageSize A4 *InputSlot Envelope"
+*cupsUIResolver envelope: "*InputSlot Manual *PageSize Env10"
+
+*cupsUIConstraints envphoto: "*PageSize Env10 *InputSlot Envelope *Quality Photo"
+*cupsUIResolver envphoto: "*Quality Normal"
+
+*% This constraint is used to test ppdInstallableConflict()
+*cupsUIConstraints: "*Duplex *InstalledDuplexer False"
+
+*% These constraints are used to test the loop detection code in cupsResolveConflicts()
+*cupsUIConstraints loop1: "*PageSize A4 *Quality Photo"
+*cupsUIResolver loop1: "*Quality Normal"
+*cupsUIConstraints loop2: "*PageSize A4 *Quality Normal"
+*cupsUIResolver loop2: "*Quality Photo"
+
+*% For PageSize, we have put all of the translations in-line...
+*OpenUI *PageSize/Page Size: PickOne
+*fr.Translation PageSize/French Page Size: ""
+*fr_CA.Translation PageSize/French Canadian Page Size: ""
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize Letter/US Letter: "PageSize=Letter"
+*fr.PageSize Letter/French US Letter: ""
+*fr_CA.PageSize Letter/French Canadian US Letter: ""
+*PageSize A4/A4: "PageSize=A4"
+*fr.PageSize A4/French A4: ""
+*fr_CA.PageSize A4/French Canadian A4: ""
+*PageSize Env10/#10 Envelope: "PageSize=Env10"
+*fr.PageSize Env10/French #10 Envelope: ""
+*fr_CA.PageSize Env10/French Canadian #10 Envelope: ""
+*CloseUI: *PageSize
+
+*% For PageRegion, we have separated the translations...
+*OpenUI *PageRegion/Page Region: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter/US Letter: "PageRegion=Letter"
+*PageRegion A4/A4: "PageRegion=A4"
+*PageRegion Env10/#10 Envelope: "PageRegion=Env10"
+*CloseUI: *PageRegion
+
+*fr.Translation PageRegion/French Page Region: ""
+*fr.PageRegion Letter/French US Letter: ""
+*fr.PageRegion A4/French A4: ""
+*fr.PageRegion Env10/French #10 Envelope: ""
+
+*fr_CA.Translation PageRegion/French Canadian Page Region: ""
+*fr_CA.PageRegion Letter/French Canadian US Letter: ""
+*fr_CA.PageRegion A4/French Canadian A4: ""
+*fr_CA.PageRegion Env10/French Canadian #10 Envelope: ""
+
+*DefaultImageableArea: Letter
+*ImageableArea Letter: "18 36 594 756"
+*ImageableArea A4: "18 36 577 806"
+*ImageableArea Env10: "18 36 279 648"
+
+*DefaultPaperDimension: Letter
+*PaperDimension Letter: "612 792"
+*PaperDimension A4: "595 842"
+*PaperDimension Env10: "297 684"
+
+*% Custom page size support
+*HWMargins: 0 0 0 0
+*NonUIOrderDependency: 100 AnySetup *CustomPageSize True
+*CustomPageSize True/Custom Page Size: "PageSize=Custom"
+*ParamCustomPageSize Width: 1 points 36 1080
+*ParamCustomPageSize Height: 2 points 36 86400
+*ParamCustomPageSize WidthOffset/Width Offset: 3 points 0 0
+*ParamCustomPageSize HeightOffset/Height Offset: 4 points 0 0
+*ParamCustomPageSize Orientation: 5 int 0 0
+
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+
+*OpenUI *InputSlot/Input Slot: PickOne
+*OrderDependency: 20 AnySetup *InputSlot
+*DefaultInputSlot: Tray
+*InputSlot Tray/Tray: "InputSlot=Tray"
+*InputSlot Manual/Manual Feed: "InputSlot=Manual"
+*InputSlot Envelope/Envelope Feed: "InputSlot=Envelope"
+*CloseUI: *InputSlot
+
+*OpenUI *Quality/Output Mode: PickOne
+*OrderDependency: 20 AnySetup *Quality
+*DefaultQuality: Normal
+*Quality Draft: "Quality=Draft"
+*Quality Normal: "Quality=Normal"
+*Quality Photo: "Quality=Photo"
+*CloseUI: *Quality
+
+*OpenUI *Duplex/2-Sided Printing: PickOne
+*OrderDependency: 10 DocumentSetup *Duplex
+*DefaultDuplex: None
+*Duplex None/Off: "Duplex=None"
+*Duplex DuplexNoTumble/Long Edge: "Duplex=DuplexNoTumble"
+*Duplex DuplexTumble/Short Edge: "Duplex=DuplexTumble"
+*CloseUI: *Duplex
+
+*% Installable option...
+*OpenGroup: InstallableOptions/Installable Options
+*OpenUI InstalledDuplexer/Duplexer Installed: Boolean
+*DefaultInstalledDuplexer: False
+*InstalledDuplexer False: ""
+*InstalledDuplexer True: ""
+*CloseUI: *InstalledDuplexer
+*CloseGroup: InstallableOptions
+
+*% Custom options...
+*OpenGroup: Extended/Extended Options
+
+*OpenUI IntOption/Integer: PickOne
+*OrderDependency: 30 AnySetup *IntOption
+*DefaultIntOption: None
+*IntOption None: ""
+*IntOption 1: "IntOption=1"
+*IntOption 2: "IntOption=2"
+*IntOption 3: "IntOption=3"
+*CloseUI: *IntOption
+
+*CustomIntOption True/Custom Integer: "IntOption=Custom"
+*ParamCustomIntOption Integer: 1 int -100 100
+
+*OpenUI StringOption/String: PickOne
+*OrderDependency: 40 AnySetup *StringOption
+*DefaultStringOption: None
+*StringOption None: ""
+*StringOption foo: "StringOption=foo"
+*StringOption bar: "StringOption=bar"
+*CloseUI: *StringOption
+
+*CustomStringOption True/Custom String: "StringOption=Custom"
+*ParamCustomStringOption String: 1 string 1 10
+
+*CloseGroup: Extended
+
+*% IPP reasons for ppdLocalizeIPPReason tests
+*cupsIPPReason foo/Foo Reason: "http://foo/bar.html
+help:anchor='foo'%20bookID=Vendor%20Help
+/help/foo/bar.html"
+*End
+*fr.cupsIPPReason foo/La Foo Reason: "text:La%20Long%20
+text:Foo%20Reason
+http://foo/fr/bar.html
+help:anchor='foo'%20bookID=Vendor%20Help
+/help/fr/foo/bar.html"
+*End
+*zh_TW.cupsIPPReason foo/Number 1 Foo Reason: "text:Number%201%20
+text:Foo%20Reason
+http://foo/zh_TW/bar.html
+help:anchor='foo'%20bookID=Vendor%20Help
+/help/zh_TW/foo/bar.html"
+*End
+*zh.cupsIPPReason foo/Number 2 Foo Reason: "text:Number%202%20
+text:Foo%20Reason
+http://foo/zh/bar.html
+help:anchor='foo'%20bookID=Vendor%20Help
+/help/zh/foo/bar.html"
+*End
+
+*% Marker names for ppdLocalizeMarkerName tests
+*cupsMarkerName cyan/Cyan Toner: ""
+*fr.cupsMarkerName cyan/La Toner Cyan: ""
+*zh_TW.cupsMarkerName cyan/Number 1 Cyan Toner: ""
+*zh.cupsMarkerName cyan/Number 2 Cyan Toner: ""
+
+*DefaultFont: Courier
+*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM
+*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM
+*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM
+*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM
+*Font Bookman-Demi: Standard "(001.004S)" Standard ROM
+*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM
+*Font Bookman-Light: Standard "(001.004S)" Standard ROM
+*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM
+*Font Courier: Standard "(002.004S)" Standard ROM
+*Font Courier-Bold: Standard "(002.004S)" Standard ROM
+*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM
+*Font Courier-Oblique: Standard "(002.004S)" Standard ROM
+*Font Helvetica: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM
+*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM
+*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM
+*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM
+*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM
+*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM
+*Font Palatino-Bold: Standard "(001.005S)" Standard ROM
+*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM
+*Font Palatino-Italic: Standard "(001.005S)" Standard ROM
+*Font Palatino-Roman: Standard "(001.005S)" Standard ROM
+*Font Symbol: Special "(001.007S)" Special ROM
+*Font Times-Bold: Standard "(001.007S)" Standard ROM
+*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM
+*Font Times-Italic: Standard "(001.007S)" Standard ROM
+*Font Times-Roman: Standard "(001.007S)" Standard ROM
+*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM
+*Font ZapfDingbats: Special "(001.004S)" Standard ROM
+*%
+*% End of "$Id$".
+*%
diff --git a/cups/testadmin.c b/cups/testadmin.c
new file mode 100644
index 000000000..84772ffed
--- /dev/null
+++ b/cups/testadmin.c
@@ -0,0 +1,120 @@
+/*
+ * "$Id$"
+ *
+ * Admin function test program for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry.
+ * show_settings() - Show settings in the array...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "adminutil.h"
+#include "string-private.h"
+
+
+/*
+ * Local functions...
+ */
+
+static void show_settings(int num_settings, cups_option_t *settings);
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i, /* Looping var */
+ num_settings; /* Number of settings */
+ cups_option_t *settings; /* Settings */
+ http_t *http; /* Connection to server */
+
+
+ /*
+ * Connect to the server using the defaults...
+ */
+
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ /*
+ * Set the current configuration if we have anything on the command-line...
+ */
+
+ if (argc > 1)
+ {
+ for (i = 1, num_settings = 0, settings = NULL; i < argc; i ++)
+ num_settings = cupsParseOptions(argv[i], num_settings, &settings);
+
+ if (cupsAdminSetServerSettings(http, num_settings, settings))
+ {
+ puts("New server settings:");
+ cupsFreeOptions(num_settings, settings);
+ }
+ else
+ {
+ printf("Server settings not changed: %s\n", cupsLastErrorString());
+ return (1);
+ }
+ }
+ else
+ puts("Current server settings:");
+
+ /*
+ * Get the current configuration...
+ */
+
+ if (cupsAdminGetServerSettings(http, &num_settings, &settings))
+ {
+ show_settings(num_settings, settings);
+ cupsFreeOptions(num_settings, settings);
+ return (0);
+ }
+ else
+ {
+ printf(" %s\n", cupsLastErrorString());
+ return (1);
+ }
+}
+
+
+/*
+ * 'show_settings()' - Show settings in the array...
+ */
+
+static void
+show_settings(
+ int num_settings, /* I - Number of settings */
+ cups_option_t *settings) /* I - Settings */
+{
+ while (num_settings > 0)
+ {
+ printf(" %s=%s\n", settings->name, settings->value);
+
+ settings ++;
+ num_settings --;
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/testarray.c b/cups/testarray.c
new file mode 100644
index 000000000..8371840fa
--- /dev/null
+++ b/cups/testarray.c
@@ -0,0 +1,480 @@
+/*
+ * "$Id$"
+ *
+ * Array test program for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry.
+ * get_seconds() - Get the current time in seconds...
+ * load_words() - Load words from a file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "string-private.h"
+#include "debug-private.h"
+#include "array.h"
+#include "dir.h"
+
+
+/*
+ * Local functions...
+ */
+
+static double get_seconds(void);
+static int load_words(const char *filename, cups_array_t *array);
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ cups_array_t *array, /* Test array */
+ *dup_array; /* Duplicate array */
+ int status; /* Exit status */
+ char *text; /* Text from array */
+ char word[256]; /* Word from file */
+ double start, /* Start time */
+ end; /* End time */
+ cups_dir_t *dir; /* Current directory */
+ cups_dentry_t *dent; /* Directory entry */
+ char *saved[32]; /* Saved entries */
+ void *data; /* User data for arrays */
+
+
+ /*
+ * No errors so far...
+ */
+
+ status = 0;
+
+ /*
+ * cupsArrayNew()
+ */
+
+ fputs("cupsArrayNew: ", stdout);
+
+ data = (void *)"testarray";
+ array = cupsArrayNew((cups_array_func_t)strcmp, data);
+
+ if (array)
+ puts("PASS");
+ else
+ {
+ puts("FAIL (returned NULL, expected pointer)");
+ status ++;
+ }
+
+ /*
+ * cupsArrayUserData()
+ */
+
+ fputs("cupsArrayUserData: ", stdout);
+ if (cupsArrayUserData(array) == data)
+ puts("PASS");
+ else
+ {
+ printf("FAIL (returned %p instead of %p!)\n", cupsArrayUserData(array),
+ data);
+ status ++;
+ }
+
+ /*
+ * cupsArrayAdd()
+ */
+
+ fputs("cupsArrayAdd: ", stdout);
+
+ if (!cupsArrayAdd(array, strdup("One Fish")))
+ {
+ puts("FAIL (\"One Fish\")");
+ status ++;
+ }
+ else
+ {
+ if (!cupsArrayAdd(array, strdup("Two Fish")))
+ {
+ puts("FAIL (\"Two Fish\")");
+ status ++;
+ }
+ else
+ {
+ if (!cupsArrayAdd(array, strdup("Red Fish")))
+ {
+ puts("FAIL (\"Red Fish\")");
+ status ++;
+ }
+ else
+ {
+ if (!cupsArrayAdd(array, strdup("Blue Fish")))
+ {
+ puts("FAIL (\"Blue Fish\")");
+ status ++;
+ }
+ else
+ puts("PASS");
+ }
+ }
+ }
+
+ /*
+ * cupsArrayCount()
+ */
+
+ fputs("cupsArrayCount: ", stdout);
+ if (cupsArrayCount(array) == 4)
+ puts("PASS");
+ else
+ {
+ printf("FAIL (returned %d, expected 4)\n", cupsArrayCount(array));
+ status ++;
+ }
+
+ /*
+ * cupsArrayFirst()
+ */
+
+ fputs("cupsArrayFirst: ", stdout);
+ if ((text = (char *)cupsArrayFirst(array)) != NULL &&
+ !strcmp(text, "Blue Fish"))
+ puts("PASS");
+ else
+ {
+ printf("FAIL (returned \"%s\", expected \"Blue Fish\")\n", text);
+ status ++;
+ }
+
+ /*
+ * cupsArrayNext()
+ */
+
+ fputs("cupsArrayNext: ", stdout);
+ if ((text = (char *)cupsArrayNext(array)) != NULL &&
+ !strcmp(text, "One Fish"))
+ puts("PASS");
+ else
+ {
+ printf("FAIL (returned \"%s\", expected \"One Fish\")\n", text);
+ status ++;
+ }
+
+ /*
+ * cupsArrayLast()
+ */
+
+ fputs("cupsArrayLast: ", stdout);
+ if ((text = (char *)cupsArrayLast(array)) != NULL &&
+ !strcmp(text, "Two Fish"))
+ puts("PASS");
+ else
+ {
+ printf("FAIL (returned \"%s\", expected \"Two Fish\")\n", text);
+ status ++;
+ }
+
+ /*
+ * cupsArrayPrev()
+ */
+
+ fputs("cupsArrayPrev: ", stdout);
+ if ((text = (char *)cupsArrayPrev(array)) != NULL &&
+ !strcmp(text, "Red Fish"))
+ puts("PASS");
+ else
+ {
+ printf("FAIL (returned \"%s\", expected \"Red Fish\")\n", text);
+ status ++;
+ }
+
+ /*
+ * cupsArrayFind()
+ */
+
+ fputs("cupsArrayFind: ", stdout);
+ if ((text = (char *)cupsArrayFind(array, (void *)"One Fish")) != NULL &&
+ !strcmp(text, "One Fish"))
+ puts("PASS");
+ else
+ {
+ printf("FAIL (returned \"%s\", expected \"One Fish\")\n", text);
+ status ++;
+ }
+
+ /*
+ * cupsArrayCurrent()
+ */
+
+ fputs("cupsArrayCurrent: ", stdout);
+ if ((text = (char *)cupsArrayCurrent(array)) != NULL &&
+ !strcmp(text, "One Fish"))
+ puts("PASS");
+ else
+ {
+ printf("FAIL (returned \"%s\", expected \"One Fish\")\n", text);
+ status ++;
+ }
+
+ /*
+ * cupsArrayDup()
+ */
+
+ fputs("cupsArrayDup: ", stdout);
+ if ((dup_array = cupsArrayDup(array)) != NULL &&
+ cupsArrayCount(dup_array) == 4)
+ puts("PASS");
+ else
+ {
+ printf("FAIL (returned %p with %d elements, expected pointer with 4 elements)\n",
+ dup_array, cupsArrayCount(dup_array));
+ status ++;
+ }
+
+ /*
+ * cupsArrayRemove()
+ */
+
+ fputs("cupsArrayRemove: ", stdout);
+ if (cupsArrayRemove(array, (void *)"One Fish") &&
+ cupsArrayCount(array) == 3)
+ puts("PASS");
+ else
+ {
+ printf("FAIL (returned 0 with %d elements, expected 1 with 4 elements)\n",
+ cupsArrayCount(array));
+ status ++;
+ }
+
+ /*
+ * cupsArrayClear()
+ */
+
+ fputs("cupsArrayClear: ", stdout);
+ cupsArrayClear(array);
+ if (cupsArrayCount(array) == 0)
+ puts("PASS");
+ else
+ {
+ printf("FAIL (%d elements, expected 0 elements)\n",
+ cupsArrayCount(array));
+ status ++;
+ }
+
+ /*
+ * Now load this source file and grab all of the unique words...
+ */
+
+ fputs("Load unique words: ", stdout);
+ fflush(stdout);
+
+ start = get_seconds();
+
+ if ((dir = cupsDirOpen(".")) == NULL)
+ {
+ puts("FAIL (cupsDirOpen failed)");
+ status ++;
+ }
+ else
+ {
+ while ((dent = cupsDirRead(dir)) != NULL)
+ {
+ i = strlen(dent->filename) - 2;
+
+ if (i > 0 && dent->filename[i] == '.' &&
+ (dent->filename[i + 1] == 'c' ||
+ dent->filename[i + 1] == 'h'))
+ load_words(dent->filename, array);
+ }
+
+ cupsDirClose(dir);
+
+ end = get_seconds();
+
+ printf("%d words in %.3f seconds (%.0f words/sec), ", cupsArrayCount(array),
+ end - start, cupsArrayCount(array) / (end - start));
+ fflush(stdout);
+
+ for (text = (char *)cupsArrayFirst(array); text;)
+ {
+ /*
+ * Copy this word to the word buffer (safe because we strdup'd from
+ * the same buffer in the first place... :)
+ */
+
+ strcpy(word, text);
+
+ /*
+ * Grab the next word and compare...
+ */
+
+ if ((text = (char *)cupsArrayNext(array)) == NULL)
+ break;
+
+ if (strcmp(word, text) >= 0)
+ break;
+ }
+
+ if (text)
+ {
+ printf("FAIL (\"%s\" >= \"%s\"!)\n", word, text);
+ status ++;
+ }
+ else
+ puts("PASS");
+ }
+
+ /*
+ * Test deleting with iteration...
+ */
+
+ fputs("Delete While Iterating: ", stdout);
+
+ text = (char *)cupsArrayFirst(array);
+ cupsArrayRemove(array, text);
+ free(text);
+
+ text = (char *)cupsArrayNext(array);
+ if (!text)
+ {
+ puts("FAIL (cupsArrayNext returned NULL!)");
+ status ++;
+ }
+ else
+ puts("PASS");
+
+ /*
+ * Test save/restore...
+ */
+
+ fputs("cupsArraySave: ", stdout);
+
+ for (i = 0, text = (char *)cupsArrayFirst(array);
+ i < 32;
+ i ++, text = (char *)cupsArrayNext(array))
+ {
+ saved[i] = text;
+
+ if (!cupsArraySave(array))
+ break;
+ }
+
+ if (i < 32)
+ printf("FAIL (depth = %d)\n", i);
+ else
+ puts("PASS");
+
+ fputs("cupsArrayRestore: ", stdout);
+
+ while (i > 0)
+ {
+ i --;
+
+ text = cupsArrayRestore(array);
+ if (text != saved[i])
+ break;
+ }
+
+ if (i)
+ printf("FAIL (depth = %d)\n", i);
+ else
+ puts("PASS");
+
+ /*
+ * Delete the arrays...
+ */
+
+ cupsArrayDelete(array);
+ cupsArrayDelete(dup_array);
+
+ /*
+ * Summarize the results and return...
+ */
+
+ if (!status)
+ puts("\nALL TESTS PASSED!");
+ else
+ printf("\n%d TEST(S) FAILED!\n", status);
+
+ return (status);
+}
+
+
+/*
+ * 'get_seconds()' - Get the current time in seconds...
+ */
+
+#ifdef WIN32
+# include <windows.h>
+
+
+static double
+get_seconds(void)
+{
+}
+#else
+# include <sys/time.h>
+
+
+static double
+get_seconds(void)
+{
+ struct timeval curtime; /* Current time */
+
+
+ gettimeofday(&curtime, NULL);
+ return (curtime.tv_sec + 0.000001 * curtime.tv_usec);
+}
+#endif /* WIN32 */
+
+
+/*
+ * 'load_words()' - Load words from a file.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+load_words(const char *filename, /* I - File to load */
+ cups_array_t *array) /* I - Array to add to */
+{
+ FILE *fp; /* Test file */
+ char word[256]; /* Word from file */
+
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ {
+ perror(filename);
+ return (0);
+ }
+
+ while (fscanf(fp, "%255s", word) == 1)
+ {
+ if (!cupsArrayFind(array, word))
+ cupsArrayAdd(array, strdup(word));
+ }
+
+ fclose(fp);
+
+ return (1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/testconflicts.c b/cups/testconflicts.c
new file mode 100644
index 000000000..6f55f0ff4
--- /dev/null
+++ b/cups/testconflicts.c
@@ -0,0 +1,127 @@
+/*
+ * "$Id$"
+ *
+ * PPD constraint test program for CUPS.
+ *
+ * Copyright 2008-2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups.h"
+#include "ppd.h"
+#include "string-private.h"
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ ppd_file_t *ppd; /* PPD file loaded from disk */
+ char line[256], /* Input buffer */
+ *ptr, /* Pointer into buffer */
+ *optr, /* Pointer to first option name */
+ *cptr; /* Pointer to first choice */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ char *option, /* Current option */
+ *choice; /* Current choice */
+
+
+ if (argc != 2)
+ {
+ puts("Usage: testconflicts filename.ppd");
+ return (1);
+ }
+
+ if ((ppd = ppdOpenFile(argv[1])) == NULL)
+ {
+ ppd_status_t err; /* Last error in file */
+ int linenum; /* Line number in file */
+
+ err = ppdLastError(&linenum);
+
+ printf("Unable to open PPD file \"%s\": %s on line %d\n", argv[1],
+ ppdErrorString(err), linenum);
+ return (1);
+ }
+
+ ppdMarkDefaults(ppd);
+
+ option = NULL;
+ choice = NULL;
+
+ for (;;)
+ {
+ num_options = 0;
+ options = NULL;
+
+ if (!cupsResolveConflicts(ppd, option, choice, &num_options, &options))
+ puts("Unable to resolve conflicts!");
+ else if ((!option && num_options > 0) || (option && num_options > 1))
+ {
+ fputs("Resolved conflicts with the following options:\n ", stdout);
+ for (i = 0; i < num_options; i ++)
+ if (!option || _cups_strcasecmp(option, options[i].name))
+ printf(" %s=%s", options[i].name, options[i].value);
+ putchar('\n');
+
+ cupsFreeOptions(num_options, options);
+ }
+
+ if (option)
+ {
+ free(option);
+ free(choice);
+ }
+
+ printf("\nNew Option(s): ");
+ fflush(stdout);
+ if (!fgets(line, sizeof(line), stdin) || line[0] == '\n')
+ break;
+
+ for (ptr = line; isspace(*ptr & 255); ptr ++);
+ for (optr = ptr; *ptr && *ptr != '='; ptr ++);
+ if (!*ptr)
+ break;
+ for (*ptr++ = '\0', cptr = ptr; *ptr && !isspace(*ptr & 255); ptr ++);
+ if (!*ptr)
+ break;
+ *ptr++ = '\0';
+
+ option = strdup(optr);
+ choice = strdup(cptr);
+ num_options = cupsParseOptions(ptr, 0, &options);
+
+ ppdMarkOption(ppd, option, choice);
+ if (cupsMarkOptions(ppd, num_options, options))
+ puts("Options Conflict!");
+ cupsFreeOptions(num_options, options);
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/testcups.c b/cups/testcups.c
new file mode 100644
index 000000000..74241666a
--- /dev/null
+++ b/cups/testcups.c
@@ -0,0 +1,416 @@
+/*
+ * "$Id$"
+ *
+ * CUPS API test program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry.
+ * dests_equal() - Determine whether two destinations are equal.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "string-private.h"
+#include "cups.h"
+#include "ppd.h"
+#include <stdlib.h>
+
+
+/*
+ * Local functions...
+ */
+
+static int dests_equal(cups_dest_t *a, cups_dest_t *b);
+static void show_diffs(cups_dest_t *a, cups_dest_t *b);
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int status = 0, /* Exit status */
+ i, /* Looping var */
+ num_dests; /* Number of destinations */
+ cups_dest_t *dests, /* Destinations */
+ *dest, /* Current destination */
+ *named_dest; /* Current named destination */
+ const char *ppdfile; /* PPD file */
+ ppd_file_t *ppd; /* PPD file data */
+ int num_jobs; /* Number of jobs for queue */
+ cups_job_t *jobs; /* Jobs for queue */
+
+
+ if (argc > 1)
+ {
+ /*
+ * ./testcups printer file interval
+ */
+
+ int interval, /* Interval between writes */
+ job_id; /* Job ID */
+ cups_file_t *fp; /* Print file */
+ char buffer[16384]; /* Read/write buffer */
+ ssize_t bytes; /* Bytes read/written */
+
+
+ if (argc != 4)
+ {
+ puts("Usage: ./testcups");
+ puts(" ./testcups printer file interval");
+ return (1);
+ }
+
+ if ((fp = cupsFileOpen(argv[2], "r")) == NULL)
+ {
+ printf("Unable to open \"%s\": %s\n", argv[2], strerror(errno));
+ return (1);
+ }
+
+ if ((job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, argv[1], "testcups", 0,
+ NULL)) <= 0)
+ {
+ printf("Unable to create print job on %s: %s\n", argv[1],
+ cupsLastErrorString());
+ return (1);
+ }
+
+ interval = atoi(argv[3]);
+
+ if (cupsStartDocument(CUPS_HTTP_DEFAULT, argv[1], job_id, argv[2],
+ CUPS_FORMAT_AUTO, 1) != HTTP_CONTINUE)
+ {
+ puts("Unable to start document!");
+ return (1);
+ }
+
+ while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0)
+ {
+ printf("Writing %d bytes...\n", (int)bytes);
+
+ if (cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer,
+ bytes) != HTTP_CONTINUE)
+ {
+ puts("Unable to write bytes!");
+ return (1);
+ }
+
+ sleep(interval);
+ }
+
+ cupsFileClose(fp);
+
+ if (cupsFinishDocument(CUPS_HTTP_DEFAULT, argv[1]) != HTTP_OK)
+ {
+ puts("Unable to finish document!");
+ return (1);
+ }
+
+ return (0);
+ }
+
+ /*
+ * cupsGetDests()
+ */
+
+ fputs("cupsGetDests: ", stdout);
+ fflush(stdout);
+
+ num_dests = cupsGetDests(&dests);
+
+ if (num_dests == 0)
+ {
+ puts("FAIL");
+ return (1);
+ }
+ else
+ {
+ printf("PASS (%d dests)\n", num_dests);
+
+ for (i = num_dests, dest = dests; i > 0; i --, dest ++)
+ {
+ printf(" %s", dest->name);
+
+ if (dest->instance)
+ printf(" /%s", dest->instance);
+
+ if (dest->is_default)
+ puts(" ***DEFAULT***");
+ else
+ putchar('\n');
+ }
+ }
+
+ /*
+ * cupsGetDest(NULL)
+ */
+
+ fputs("cupsGetDest(NULL): ", stdout);
+ fflush(stdout);
+
+ if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
+ {
+ for (i = num_dests, dest = dests; i > 0; i --, dest ++)
+ if (dest->is_default)
+ break;
+
+ if (i)
+ {
+ status = 1;
+ puts("FAIL");
+ }
+ else
+ puts("PASS (no default)");
+
+ dest = NULL;
+ }
+ else
+ printf("PASS (%s)\n", dest->name);
+
+ /*
+ * cupsGetNamedDest(NULL, NULL, NULL)
+ */
+
+ fputs("cupsGetNamedDest(NULL, NULL, NULL): ", stdout);
+ fflush(stdout);
+
+ if ((named_dest = cupsGetNamedDest(NULL, NULL, NULL)) == NULL ||
+ !dests_equal(dest, named_dest))
+ {
+ if (!dest)
+ puts("PASS (no default)");
+ else if (named_dest)
+ {
+ puts("FAIL (different values)");
+ show_diffs(dest, named_dest);
+ status = 1;
+ }
+ else
+ {
+ puts("FAIL (no default)");
+ status = 1;
+ }
+ }
+ else
+ printf("PASS (%s)\n", named_dest->name);
+
+ if (named_dest)
+ cupsFreeDests(1, named_dest);
+
+ /*
+ * cupsGetDest(printer)
+ */
+
+ printf("cupsGetDest(\"%s\"): ", dests[num_dests / 2].name);
+ fflush(stdout);
+
+ if ((dest = cupsGetDest(dests[num_dests / 2].name, NULL, num_dests,
+ dests)) == NULL)
+ {
+ puts("FAIL");
+ return (1);
+ }
+ else
+ puts("PASS");
+
+ /*
+ * cupsGetNamedDest(NULL, printer, instance)
+ */
+
+ printf("cupsGetNamedDest(NULL, \"%s\", \"%s\"): ", dest->name,
+ dest->instance ? dest->instance : "(null)");
+ fflush(stdout);
+
+ if ((named_dest = cupsGetNamedDest(NULL, dest->name,
+ dest->instance)) == NULL ||
+ !dests_equal(dest, named_dest))
+ {
+ if (named_dest)
+ {
+ puts("FAIL (different values)");
+ show_diffs(dest, named_dest);
+ }
+ else
+ puts("FAIL (no destination)");
+
+
+ status = 1;
+ }
+ else
+ puts("PASS");
+
+ if (named_dest)
+ cupsFreeDests(1, named_dest);
+
+ /*
+ * cupsPrintFile()
+ */
+
+ fputs("cupsPrintFile: ", stdout);
+ fflush(stdout);
+
+ if (cupsPrintFile(dest->name, "../data/testprint", "Test Page",
+ dest->num_options, dest->options) <= 0)
+ {
+ printf("FAIL (%s)\n", cupsLastErrorString());
+ return (1);
+ }
+ else
+ puts("PASS");
+
+ /*
+ * cupsGetPPD(printer)
+ */
+
+ fputs("cupsGetPPD(): ", stdout);
+ fflush(stdout);
+
+ if ((ppdfile = cupsGetPPD(dest->name)) == NULL)
+ {
+ puts("FAIL");
+ }
+ else
+ {
+ puts("PASS");
+
+ /*
+ * ppdOpenFile()
+ */
+
+ fputs("ppdOpenFile(): ", stdout);
+ fflush(stdout);
+
+ if ((ppd = ppdOpenFile(ppdfile)) == NULL)
+ {
+ puts("FAIL");
+ return (1);
+ }
+ else
+ puts("PASS");
+
+ ppdClose(ppd);
+ unlink(ppdfile);
+ }
+
+ /*
+ * cupsGetJobs()
+ */
+
+ fputs("cupsGetJobs: ", stdout);
+ fflush(stdout);
+
+ num_jobs = cupsGetJobs(&jobs, NULL, 0, -1);
+
+ if (num_jobs == 0)
+ {
+ puts("FAIL");
+ return (1);
+ }
+ else
+ puts("PASS");
+
+ cupsFreeJobs(num_jobs, jobs);
+ cupsFreeDests(num_dests, dests);
+
+ return (status);
+}
+
+
+/*
+ * 'dests_equal()' - Determine whether two destinations are equal.
+ */
+
+static int /* O - 1 if equal, 0 if not equal */
+dests_equal(cups_dest_t *a, /* I - First destination */
+ cups_dest_t *b) /* I - Second destination */
+{
+ int i; /* Looping var */
+ cups_option_t *aoption; /* Current option */
+ const char *bval; /* Option value */
+
+
+ if (a == b)
+ return (1);
+
+ if (!a || !b)
+ return (0);
+
+ if (_cups_strcasecmp(a->name, b->name) ||
+ (a->instance && !b->instance) ||
+ (!a->instance && b->instance) ||
+ (a->instance && _cups_strcasecmp(a->instance, b->instance)) ||
+ a->num_options != b->num_options)
+ return (0);
+
+ for (i = a->num_options, aoption = a->options; i > 0; i --, aoption ++)
+ if ((bval = cupsGetOption(aoption->name, b->num_options,
+ b->options)) == NULL ||
+ strcmp(aoption->value, bval))
+ return (0);
+
+ return (1);
+}
+
+
+/*
+ * 'show_diffs()' - Show differences between two destinations.
+ */
+
+static void
+show_diffs(cups_dest_t *a, /* I - First destination */
+ cups_dest_t *b) /* I - Second destination */
+{
+ int i; /* Looping var */
+ cups_option_t *aoption; /* Current option */
+ const char *bval; /* Option value */
+
+
+ if (!a || !b)
+ return;
+
+ puts(" Item cupsGetDest cupsGetNamedDest");
+ puts(" -------------------- -------------------- --------------------");
+
+ if (_cups_strcasecmp(a->name, b->name))
+ printf(" name %-20.20s %-20.20s\n", a->name, b->name);
+
+ if ((a->instance && !b->instance) ||
+ (!a->instance && b->instance) ||
+ (a->instance && _cups_strcasecmp(a->instance, b->instance)))
+ printf(" instance %-20.20s %-20.20s\n",
+ a->instance ? a->instance : "(null)",
+ b->instance ? b->instance : "(null)");
+
+ if (a->num_options != b->num_options)
+ printf(" num_options %-20d %-20d\n", a->num_options,
+ b->num_options);
+
+ for (i = a->num_options, aoption = a->options; i > 0; i --, aoption ++)
+ if ((bval = cupsGetOption(aoption->name, b->num_options,
+ b->options)) == NULL ||
+ strcmp(aoption->value, bval))
+ printf(" %-20.20s %-20.20s %-20.20s\n", aoption->name,
+ aoption->value, bval ? bval : "(null)");
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/testfile.c b/cups/testfile.c
new file mode 100644
index 000000000..0821b380b
--- /dev/null
+++ b/cups/testfile.c
@@ -0,0 +1,821 @@
+/*
+ * "$Id$"
+ *
+ * File test program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry.
+ * count_lines() - Count the number of lines in a file.
+ * random_tests() - Do random access tests.
+ * read_write_tests() - Perform read/write tests.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "string-private.h"
+#include "debug-private.h"
+#include "file.h"
+#include <stdlib.h>
+#include <time.h>
+#ifdef HAVE_LIBZ
+# include <zlib.h>
+#endif /* HAVE_LIBZ */
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+#endif /* WIN32 */
+#include <fcntl.h>
+
+
+/*
+ * Local functions...
+ */
+
+static int count_lines(cups_file_t *fp);
+static int random_tests(void);
+static int read_write_tests(int compression);
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int status; /* Exit status */
+ char filename[1024]; /* Filename buffer */
+ cups_file_t *fp; /* File pointer */
+#ifndef WIN32
+ int fds[2]; /* Open file descriptors */
+ cups_file_t *fdfile; /* File opened with cupsFileOpenFd() */
+#endif /* !WIN32 */
+ int count; /* Number of lines in file */
+
+
+ if (argc == 1)
+ {
+ /*
+ * Do uncompressed file tests...
+ */
+
+ status = read_write_tests(0);
+
+#ifdef HAVE_LIBZ
+ /*
+ * Do compressed file tests...
+ */
+
+ putchar('\n');
+
+ status += read_write_tests(1);
+#endif /* HAVE_LIBZ */
+
+ /*
+ * Do uncompressed random I/O tests...
+ */
+
+ status += random_tests();
+
+#ifndef WIN32
+ /*
+ * Test fdopen and close without reading...
+ */
+
+ pipe(fds);
+ close(fds[1]);
+
+ fputs("\ncupsFileOpenFd(fd, \"r\"): ", stdout);
+ fflush(stdout);
+
+ if ((fdfile = cupsFileOpenFd(fds[0], "r")) == NULL)
+ {
+ puts("FAIL");
+ status ++;
+ }
+ else
+ {
+ /*
+ * Able to open file, now close without reading. If we don't return
+ * before the alarm fires, that is a failure and we will crash on the
+ * alarm signal...
+ */
+
+ puts("PASS");
+ fputs("cupsFileClose(no read): ", stdout);
+ fflush(stdout);
+
+ alarm(5);
+ cupsFileClose(fdfile);
+ alarm(0);
+
+ puts("PASS");
+ }
+#endif /* !WIN32 */
+
+ /*
+ * Count lines in psglyphs, rewind, then count again.
+ */
+
+ fputs("\ncupsFileOpen(\"../data/psglyphs\", \"r\"): ", stdout);
+
+ if ((fp = cupsFileOpen("../data/psglyphs", "r")) == NULL)
+ {
+ puts("FAIL");
+ status ++;
+ }
+ else
+ {
+ puts("PASS");
+ fputs("cupsFileGets: ", stdout);
+
+ if ((count = count_lines(fp)) != 1051)
+ {
+ printf("FAIL (got %d lines, expected 1051)\n", count);
+ status ++;
+ }
+ else
+ {
+ puts("PASS");
+ fputs("cupsFileRewind: ", stdout);
+
+ if (cupsFileRewind(fp) != 0)
+ {
+ puts("FAIL");
+ status ++;
+ }
+ else
+ {
+ puts("PASS");
+ fputs("cupsFileGets: ", stdout);
+
+ if ((count = count_lines(fp)) != 1051)
+ {
+ printf("FAIL (got %d lines, expected 1051)\n", count);
+ status ++;
+ }
+ else
+ puts("PASS");
+ }
+ }
+
+ cupsFileClose(fp);
+ }
+
+ /*
+ * Test path functions...
+ */
+
+ fputs("\ncupsFileFind: ", stdout);
+#ifdef WIN32
+ if (cupsFileFind("notepad.exe", "C:/WINDOWS", 1, filename, sizeof(filename)) &&
+ cupsFileFind("notepad.exe", "C:/WINDOWS;C:/WINDOWS/SYSTEM32", 1, filename, sizeof(filename)))
+#else
+ if (cupsFileFind("cat", "/bin", 1, filename, sizeof(filename)) &&
+ cupsFileFind("cat", "/bin:/usr/bin", 1, filename, sizeof(filename)))
+#endif /* WIN32 */
+ printf("PASS (%s)\n", filename);
+ else
+ {
+ puts("FAIL");
+ status ++;
+ }
+
+ /*
+ * Summarize the results and return...
+ */
+
+ if (!status)
+ puts("\nALL TESTS PASSED!");
+ else
+ printf("\n%d TEST(S) FAILED!\n", status);
+ }
+ else
+ {
+ /*
+ * Cat the filename on the command-line...
+ */
+
+ char line[1024]; /* Line from file */
+
+ if ((fp = cupsFileOpen(argv[1], "r")) == NULL)
+ {
+ perror(argv[1]);
+ status = 1;
+ }
+ else
+ {
+ status = 0;
+
+ while (cupsFileGets(fp, line, sizeof(line)))
+ puts(line);
+
+ if (!cupsFileEOF(fp))
+ perror(argv[1]);
+
+ cupsFileClose(fp);
+ }
+ }
+
+ return (status);
+}
+
+
+/*
+ * 'count_lines()' - Count the number of lines in a file.
+ */
+
+static int /* O - Number of lines */
+count_lines(cups_file_t *fp) /* I - File to read from */
+{
+ int count; /* Number of lines */
+ char line[1024]; /* Line buffer */
+
+
+ for (count = 0; cupsFileGets(fp, line, sizeof(line)); count ++);
+
+ return (count);
+}
+
+
+/*
+ * 'random_tests()' - Do random access tests.
+ */
+
+static int /* O - Status */
+random_tests(void)
+{
+ int status, /* Status of tests */
+ pass, /* Current pass */
+ count, /* Number of records read */
+ record, /* Current record */
+ num_records; /* Number of records */
+ ssize_t pos, /* Position in file */
+ expected; /* Expected position in file */
+ cups_file_t *fp; /* File */
+ char buffer[512]; /* Data buffer */
+
+
+ /*
+ * Run 4 passes, each time appending to a data file and then reopening the
+ * file for reading to validate random records in the file.
+ */
+
+ for (status = 0, pass = 0; pass < 4; pass ++)
+ {
+ /*
+ * cupsFileOpen(append)
+ */
+
+ printf("\ncupsFileOpen(append %d): ", pass);
+
+ if ((fp = cupsFileOpen("testfile.dat", "a")) == NULL)
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ break;
+ }
+ else
+ puts("PASS");
+
+ /*
+ * cupsFileTell()
+ */
+
+ expected = 256 * sizeof(buffer) * pass;
+
+ fputs("cupsFileTell(): ", stdout);
+ if ((pos = cupsFileTell(fp)) != expected)
+ {
+ printf("FAIL (" CUPS_LLFMT " instead of " CUPS_LLFMT ")\n",
+ CUPS_LLCAST pos, CUPS_LLCAST expected);
+ status ++;
+ break;
+ }
+ else
+ puts("PASS");
+
+ /*
+ * cupsFileWrite()
+ */
+
+ fputs("cupsFileWrite(256 512-byte records): ", stdout);
+ for (record = 0; record < 256; record ++)
+ {
+ memset(buffer, record, sizeof(buffer));
+ if (cupsFileWrite(fp, buffer, sizeof(buffer)) < sizeof(buffer))
+ break;
+ }
+
+ if (record < 256)
+ {
+ printf("FAIL (%d: %s)\n", record, strerror(errno));
+ status ++;
+ break;
+ }
+ else
+ puts("PASS");
+
+ /*
+ * cupsFileTell()
+ */
+
+ expected += 256 * sizeof(buffer);
+
+ fputs("cupsFileTell(): ", stdout);
+ if ((pos = cupsFileTell(fp)) != expected)
+ {
+ printf("FAIL (" CUPS_LLFMT " instead of " CUPS_LLFMT ")\n",
+ CUPS_LLCAST pos, CUPS_LLCAST expected);
+ status ++;
+ break;
+ }
+ else
+ puts("PASS");
+
+ cupsFileClose(fp);
+
+ /*
+ * cupsFileOpen(read)
+ */
+
+ printf("\ncupsFileOpen(read %d): ", pass);
+
+ if ((fp = cupsFileOpen("testfile.dat", "r")) == NULL)
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ break;
+ }
+ else
+ puts("PASS");
+
+ /*
+ * cupsFileSeek, cupsFileRead
+ */
+
+ fputs("cupsFileSeek(), cupsFileRead(): ", stdout);
+
+ for (num_records = (pass + 1) * 256, count = (pass + 1) * 256,
+ record = CUPS_RAND() % num_records;
+ count > 0;
+ count --, record = (record + (CUPS_RAND() & 31) - 16 + num_records) %
+ num_records)
+ {
+ /*
+ * The last record is always the first...
+ */
+
+ if (count == 1)
+ record = 0;
+
+ /*
+ * Try reading the data for the specified record, and validate the
+ * contents...
+ */
+
+ expected = sizeof(buffer) * record;
+
+ if ((pos = cupsFileSeek(fp, expected)) != expected)
+ {
+ printf("FAIL (" CUPS_LLFMT " instead of " CUPS_LLFMT ")\n",
+ CUPS_LLCAST pos, CUPS_LLCAST expected);
+ status ++;
+ break;
+ }
+ else
+ {
+ if (cupsFileRead(fp, buffer, sizeof(buffer)) != sizeof(buffer))
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ break;
+ }
+ else if ((buffer[0] & 255) != (record & 255) ||
+ memcmp(buffer, buffer + 1, sizeof(buffer) - 1))
+ {
+ printf("FAIL (Bad Data - %d instead of %d)\n", buffer[0] & 255,
+ record & 255);
+ status ++;
+ break;
+ }
+ }
+ }
+
+ if (count == 0)
+ puts("PASS");
+
+ cupsFileClose(fp);
+ }
+
+ /*
+ * Remove the test file...
+ */
+
+ unlink("testfile.dat");
+
+ /*
+ * Return the test status...
+ */
+
+ return (status);
+}
+
+
+/*
+ * 'read_write_tests()' - Perform read/write tests.
+ */
+
+static int /* O - Status */
+read_write_tests(int compression) /* I - Use compression? */
+{
+ int i; /* Looping var */
+ cups_file_t *fp; /* File */
+ int status; /* Exit status */
+ char line[1024], /* Line from file */
+ *value; /* Directive value from line */
+ int linenum; /* Line number */
+ unsigned char readbuf[8192], /* Read buffer */
+ writebuf[8192]; /* Write buffer */
+ int byte; /* Byte from file */
+ off_t length; /* Length of file */
+ static const char *partial_line = "partial line";
+ /* Partial line */
+
+
+ /*
+ * No errors so far...
+ */
+
+ status = 0;
+
+ /*
+ * Initialize the write buffer with random data...
+ */
+
+ CUPS_SRAND((unsigned)time(NULL));
+
+ for (i = 0; i < (int)sizeof(writebuf); i ++)
+ writebuf[i] = CUPS_RAND();
+
+ /*
+ * cupsFileOpen(write)
+ */
+
+ printf("cupsFileOpen(write%s): ", compression ? " compressed" : "");
+
+ fp = cupsFileOpen(compression ? "testfile.dat.gz" : "testfile.dat",
+ compression ? "w9" : "w");
+ if (fp)
+ {
+ puts("PASS");
+
+ /*
+ * cupsFileCompression()
+ */
+
+ fputs("cupsFileCompression(): ", stdout);
+
+ if (cupsFileCompression(fp) == compression)
+ puts("PASS");
+ else
+ {
+ printf("FAIL (Got %d, expected %d)\n", cupsFileCompression(fp),
+ compression);
+ status ++;
+ }
+
+ /*
+ * cupsFilePuts()
+ */
+
+ fputs("cupsFilePuts(): ", stdout);
+
+ if (cupsFilePuts(fp, "# Hello, World\n") > 0)
+ puts("PASS");
+ else
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ }
+
+ /*
+ * cupsFilePrintf()
+ */
+
+ fputs("cupsFilePrintf(): ", stdout);
+
+ for (i = 0; i < 1000; i ++)
+ if (cupsFilePrintf(fp, "TestLine %03d\n", i) < 0)
+ break;
+
+ if (i >= 1000)
+ puts("PASS");
+ else
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ }
+
+ /*
+ * cupsFilePutChar()
+ */
+
+ fputs("cupsFilePutChar(): ", stdout);
+
+ for (i = 0; i < 256; i ++)
+ if (cupsFilePutChar(fp, i) < 0)
+ break;
+
+ if (i >= 256)
+ puts("PASS");
+ else
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ }
+
+ /*
+ * cupsFileWrite()
+ */
+
+ fputs("cupsFileWrite(): ", stdout);
+
+ for (i = 0; i < 10000; i ++)
+ if (cupsFileWrite(fp, (char *)writebuf, sizeof(writebuf)) < 0)
+ break;
+
+ if (i >= 10000)
+ puts("PASS");
+ else
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ }
+
+ /*
+ * cupsFilePuts() with partial line...
+ */
+
+ fputs("cupsFilePuts(\"partial line\"): ", stdout);
+
+ if (cupsFilePuts(fp, partial_line) > 0)
+ puts("PASS");
+ else
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ }
+
+ /*
+ * cupsFileTell()
+ */
+
+ fputs("cupsFileTell(): ", stdout);
+
+ if ((length = cupsFileTell(fp)) == 81933283)
+ puts("PASS");
+ else
+ {
+ printf("FAIL (" CUPS_LLFMT " instead of 81933283)\n", CUPS_LLCAST length);
+ status ++;
+ }
+
+ /*
+ * cupsFileClose()
+ */
+
+ fputs("cupsFileClose(): ", stdout);
+
+ if (!cupsFileClose(fp))
+ puts("PASS");
+ else
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ }
+ }
+ else
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ }
+
+ /*
+ * cupsFileOpen(read)
+ */
+
+ fputs("\ncupsFileOpen(read): ", stdout);
+
+ fp = cupsFileOpen(compression ? "testfile.dat.gz" : "testfile.dat", "r");
+ if (fp)
+ {
+ puts("PASS");
+
+ /*
+ * cupsFileGets()
+ */
+
+ fputs("cupsFileGets(): ", stdout);
+
+ if (cupsFileGets(fp, line, sizeof(line)))
+ {
+ if (line[0] == '#')
+ puts("PASS");
+ else
+ {
+ printf("FAIL (Got line \"%s\", expected comment line)\n", line);
+ status ++;
+ }
+ }
+ else
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ }
+
+ /*
+ * cupsFileCompression()
+ */
+
+ fputs("cupsFileCompression(): ", stdout);
+
+ if (cupsFileCompression(fp) == compression)
+ puts("PASS");
+ else
+ {
+ printf("FAIL (Got %d, expected %d)\n", cupsFileCompression(fp),
+ compression);
+ status ++;
+ }
+
+ /*
+ * cupsFileGetConf()
+ */
+
+ linenum = 1;
+
+ fputs("cupsFileGetConf(): ", stdout);
+
+ for (i = 0; i < 1000; i ++)
+ if (!cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ break;
+ else if (_cups_strcasecmp(line, "TestLine") || !value || atoi(value) != i ||
+ linenum != (i + 2))
+ break;
+
+ if (i >= 1000)
+ puts("PASS");
+ else if (line[0])
+ {
+ printf("FAIL (Line %d, directive \"%s\", value \"%s\")\n", linenum,
+ line, value ? value : "(null)");
+ status ++;
+ }
+ else
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ }
+
+ /*
+ * cupsFileGetChar()
+ */
+
+ fputs("cupsFileGetChar(): ", stdout);
+
+ for (i = 0; i < 256; i ++)
+ if ((byte = cupsFileGetChar(fp)) != i)
+ break;
+
+ if (i >= 256)
+ puts("PASS");
+ else if (byte >= 0)
+ {
+ printf("FAIL (Got %d, expected %d)\n", byte, i);
+ status ++;
+ }
+ else
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ }
+
+ /*
+ * cupsFileRead()
+ */
+
+ fputs("cupsFileRead(): ", stdout);
+
+ for (i = 0; i < 10000; i ++)
+ if ((byte = cupsFileRead(fp, (char *)readbuf, sizeof(readbuf))) < 0)
+ break;
+ else if (memcmp(readbuf, writebuf, sizeof(readbuf)))
+ break;
+
+ if (i >= 10000)
+ puts("PASS");
+ else if (byte > 0)
+ {
+ printf("FAIL (Pass %d, ", i);
+
+ for (i = 0; i < (int)sizeof(readbuf); i ++)
+ if (readbuf[i] != writebuf[i])
+ break;
+
+ printf("match failed at offset %d - got %02X, expected %02X)\n",
+ i, readbuf[i], writebuf[i]);
+ }
+ else
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ }
+
+ /*
+ * cupsFileGetChar() with partial line...
+ */
+
+ fputs("cupsFileGetChar(partial line): ", stdout);
+
+ for (i = 0; i < (int)strlen(partial_line); i ++)
+ if ((byte = cupsFileGetChar(fp)) < 0)
+ break;
+ else if (byte != partial_line[i])
+ break;
+
+ if (!partial_line[i])
+ puts("PASS");
+ else
+ {
+ printf("FAIL (got '%c', expected '%c')\n", byte, partial_line[i]);
+ status ++;
+ }
+
+ /*
+ * cupsFileTell()
+ */
+
+ fputs("cupsFileTell(): ", stdout);
+
+ if ((length = cupsFileTell(fp)) == 81933283)
+ puts("PASS");
+ else
+ {
+ printf("FAIL (" CUPS_LLFMT " instead of 81933283)\n", CUPS_LLCAST length);
+ status ++;
+ }
+
+ /*
+ * cupsFileClose()
+ */
+
+ fputs("cupsFileClose(): ", stdout);
+
+ if (!cupsFileClose(fp))
+ puts("PASS");
+ else
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ }
+ }
+ else
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ status ++;
+ }
+
+ /*
+ * Remove the test file...
+ */
+
+ unlink(compression ? "testfile.dat.gz" : "testfile.dat");
+
+ /*
+ * Return the test status...
+ */
+
+ return (status);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/testhttp.c b/cups/testhttp.c
new file mode 100644
index 000000000..3b752f4cd
--- /dev/null
+++ b/cups/testhttp.c
@@ -0,0 +1,594 @@
+/*
+ * "$Id$"
+ *
+ * HTTP test program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "string-private.h"
+#include "http-private.h"
+
+
+/*
+ * Types and structures...
+ */
+
+typedef struct uri_test_s /**** URI test cases ****/
+{
+ http_uri_status_t result; /* Expected return value */
+ const char *uri, /* URI */
+ *scheme, /* Scheme string */
+ *username, /* Username:password string */
+ *hostname, /* Hostname string */
+ *resource; /* Resource string */
+ int port, /* Port number */
+ assemble_port; /* Port number for httpAssembleURI() */
+} uri_test_t;
+
+
+/*
+ * Local globals...
+ */
+
+static uri_test_t uri_tests[] = /* URI test data */
+ {
+ /* Start with valid URIs */
+ { HTTP_URI_OK, "file:/filename",
+ "file", "", "", "/filename", 0, 0 },
+ { HTTP_URI_OK, "file:/filename%20with%20spaces",
+ "file", "", "", "/filename with spaces", 0, 0 },
+ { HTTP_URI_OK, "file:///filename",
+ "file", "", "", "/filename", 0, 0 },
+ { HTTP_URI_OK, "file:///filename%20with%20spaces",
+ "file", "", "", "/filename with spaces", 0, 0 },
+ { HTTP_URI_OK, "file://localhost/filename",
+ "file", "", "localhost", "/filename", 0, 0 },
+ { HTTP_URI_OK, "file://localhost/filename%20with%20spaces",
+ "file", "", "localhost", "/filename with spaces", 0, 0 },
+ { HTTP_URI_OK, "http://server/",
+ "http", "", "server", "/", 80, 0 },
+ { HTTP_URI_OK, "http://username@server/",
+ "http", "username", "server", "/", 80, 0 },
+ { HTTP_URI_OK, "http://username:passwor%64@server/",
+ "http", "username:password", "server", "/", 80, 0 },
+ { HTTP_URI_OK, "http://username:passwor%64@server:8080/",
+ "http", "username:password", "server", "/", 8080, 8080 },
+ { HTTP_URI_OK, "http://username:passwor%64@server:8080/directory/filename",
+ "http", "username:password", "server", "/directory/filename", 8080, 8080 },
+ { HTTP_URI_OK, "http://[2000::10:100]:631/ipp",
+ "http", "", "2000::10:100", "/ipp", 631, 631 },
+ { HTTP_URI_OK, "https://username:passwor%64@server/directory/filename",
+ "https", "username:password", "server", "/directory/filename", 443, 0 },
+ { HTTP_URI_OK, "ipp://username:passwor%64@[::1]/ipp",
+ "ipp", "username:password", "::1", "/ipp", 631, 0 },
+ { HTTP_URI_OK, "lpd://server/queue?reserve=yes",
+ "lpd", "", "server", "/queue?reserve=yes", 515, 0 },
+ { HTTP_URI_OK, "mailto:user@domain.com",
+ "mailto", "", "", "user@domain.com", 0, 0 },
+ { HTTP_URI_OK, "socket://server/",
+ "socket", "", "server", "/", 9100, 0 },
+ { HTTP_URI_OK, "socket://192.168.1.1:9101/",
+ "socket", "", "192.168.1.1", "/", 9101, 9101 },
+ { HTTP_URI_OK, "ipp://username:password@[v1.fe80::200:1234:5678:9abc+eth0]:999/ipp",
+ "ipp", "username:password", "fe80::200:1234:5678:9abc%eth0", "/ipp", 999, 999 },
+ { HTTP_URI_OK, "http://server/admin?DEVICE_URI=usb://HP/Photosmart%25202600%2520series?serial=MY53OK70V10400",
+ "http", "", "server", "/admin?DEVICE_URI=usb://HP/Photosmart%25202600%2520series?serial=MY53OK70V10400", 80, 0 },
+ { HTTP_URI_OK, "lpd://Acme%20Laser%20(01%3A23%3A45).local._tcp._printer/",
+ "lpd", "", "Acme Laser (01:23:45).local._tcp._printer", "/", 515, 0 },
+ { HTTP_URI_OK, "ipp://HP%20Officejet%204500%20G510n-z%20%40%20Will's%20MacBook%20Pro%2015%22._ipp._tcp.local./",
+ "ipp", "", "HP Officejet 4500 G510n-z @ Will's MacBook Pro 15\"._ipp._tcp.local.", "/", 631, 0 },
+
+ /* Missing scheme */
+ { HTTP_URI_MISSING_SCHEME, "/path/to/file/index.html",
+ "file", "", "", "/path/to/file/index.html", 0, 0 },
+ { HTTP_URI_MISSING_SCHEME, "//server/ipp",
+ "ipp", "", "server", "/ipp", 631, 0 },
+
+ /* Unknown scheme */
+ { HTTP_URI_UNKNOWN_SCHEME, "vendor://server/resource",
+ "vendor", "", "server", "/resource", 0, 0 },
+
+ /* Missing resource */
+ { HTTP_URI_MISSING_RESOURCE, "socket://[::192.168.2.1]",
+ "socket", "", "::192.168.2.1", "/", 9100, 0 },
+ { HTTP_URI_MISSING_RESOURCE, "socket://192.168.1.1:9101",
+ "socket", "", "192.168.1.1", "/", 9101 },
+
+ /* Bad URI */
+ { HTTP_URI_BAD_URI, "",
+ "", "", "", "", 0, 0 },
+
+ /* Bad scheme */
+ { HTTP_URI_BAD_SCHEME, "bad_scheme://server/resource",
+ "", "", "", "", 0, 0 },
+
+ /* Bad username */
+ { HTTP_URI_BAD_USERNAME, "http://username:passwor%6@server/resource",
+ "http", "", "", "", 80, 0 },
+
+ /* Bad hostname */
+ { HTTP_URI_BAD_HOSTNAME, "http://[/::1]/index.html",
+ "http", "", "", "", 80, 0 },
+ { HTTP_URI_BAD_HOSTNAME, "http://[",
+ "http", "", "", "", 80, 0 },
+ { HTTP_URI_BAD_HOSTNAME, "http://serve%7/index.html",
+ "http", "", "", "", 80, 0 },
+
+ /* Bad port number */
+ { HTTP_URI_BAD_PORT, "http://127.0.0.1:9999a/index.html",
+ "http", "", "127.0.0.1", "", 0, 0 },
+
+ /* Bad resource */
+ { HTTP_URI_BAD_RESOURCE, "http://server/index.html%",
+ "http", "", "server", "", 80, 0 }
+ };
+static const char * const base64_tests[][2] =
+ {
+ { "A", "QQ==" },
+ /* 010000 01 */
+ { "AB", "QUI=" },
+ /* 010000 010100 0010 */
+ { "ABC", "QUJD" },
+ /* 010000 010100 001001 000011 */
+ { "ABCD", "QUJDRA==" },
+ /* 010000 010100 001001 000011 010001 00 */
+ { "ABCDE", "QUJDREU=" },
+ /* 010000 010100 001001 000011 010001 000100 0101 */
+ { "ABCDEF", "QUJDREVG" },
+ /* 010000 010100 001001 000011 010001 000100 010101 000110 */
+ };
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i, j, k; /* Looping vars */
+ http_t *http; /* HTTP connection */
+ http_status_t status; /* Status of GET command */
+ int failures; /* Number of test failures */
+ char buffer[8192]; /* Input buffer */
+ long bytes; /* Number of bytes read */
+ FILE *out; /* Output file */
+ char encode[256], /* Base64-encoded string */
+ decode[256]; /* Base64-decoded string */
+ int decodelen; /* Length of decoded string */
+ char scheme[HTTP_MAX_URI], /* Scheme from URI */
+ hostname[HTTP_MAX_URI], /* Hostname from URI */
+ username[HTTP_MAX_URI], /* Username:password from URI */
+ resource[HTTP_MAX_URI]; /* Resource from URI */
+ int port; /* Port number from URI */
+ http_uri_status_t uri_status; /* Status of URI separation */
+ http_addrlist_t *addrlist, /* Address list */
+ *addr; /* Current address */
+ off_t length, total; /* Length and total bytes */
+ time_t start, current; /* Start and end time */
+ static const char * const uri_status_strings[] =
+ {
+ "HTTP_URI_OVERFLOW",
+ "HTTP_URI_BAD_ARGUMENTS",
+ "HTTP_URI_BAD_RESOURCE",
+ "HTTP_URI_BAD_PORT",
+ "HTTP_URI_BAD_HOSTNAME",
+ "HTTP_URI_BAD_USERNAME",
+ "HTTP_URI_BAD_SCHEME",
+ "HTTP_URI_BAD_URI",
+ "HTTP_URI_OK",
+ "HTTP_URI_MISSING_SCHEME",
+ "HTTP_URI_UNKNOWN_SCHEME",
+ "HTTP_URI_MISSING_RESOURCE"
+ };
+
+
+ /*
+ * Do API tests if we don't have a URL on the command-line...
+ */
+
+ if (argc == 1)
+ {
+ failures = 0;
+
+ /*
+ * httpGetDateString()/httpGetDateTime()
+ */
+
+ fputs("httpGetDateString()/httpGetDateTime(): ", stdout);
+
+ start = time(NULL);
+ strcpy(buffer, httpGetDateString(start));
+ current = httpGetDateTime(buffer);
+
+ i = (int)(current - start);
+ if (i < 0)
+ i = -i;
+
+ if (!i)
+ puts("PASS");
+ else
+ {
+ failures ++;
+ puts("FAIL");
+ printf(" Difference is %d seconds, %02d:%02d:%02d...\n", i, i / 3600,
+ (i / 60) % 60, i % 60);
+ printf(" httpGetDateString(%d) returned \"%s\"\n", (int)start, buffer);
+ printf(" httpGetDateTime(\"%s\") returned %d\n", buffer, (int)current);
+ printf(" httpGetDateString(%d) returned \"%s\"\n", (int)current,
+ httpGetDateString(current));
+ }
+
+ /*
+ * httpDecode64_2()/httpEncode64_2()
+ */
+
+ fputs("httpDecode64_2()/httpEncode64_2(): ", stdout);
+
+ for (i = 0, j = 0; i < (int)(sizeof(base64_tests) / sizeof(base64_tests[0])); i ++)
+ {
+ httpEncode64_2(encode, sizeof(encode), base64_tests[i][0],
+ (int)strlen(base64_tests[i][0]));
+ decodelen = (int)sizeof(decode);
+ httpDecode64_2(decode, &decodelen, base64_tests[i][1]);
+
+ if (strcmp(decode, base64_tests[i][0]))
+ {
+ failures ++;
+
+ if (j)
+ {
+ puts("FAIL");
+ j = 1;
+ }
+
+ printf(" httpDecode64_2() returned \"%s\", expected \"%s\"...\n",
+ decode, base64_tests[i][0]);
+ }
+
+ if (strcmp(encode, base64_tests[i][1]))
+ {
+ failures ++;
+
+ if (j)
+ {
+ puts("FAIL");
+ j = 1;
+ }
+
+ printf(" httpEncode64_2() returned \"%s\", expected \"%s\"...\n",
+ encode, base64_tests[i][1]);
+ }
+ }
+
+ if (!j)
+ puts("PASS");
+
+ /*
+ * httpGetHostname()
+ */
+
+ fputs("httpGetHostname(): ", stdout);
+
+ if (httpGetHostname(NULL, hostname, sizeof(hostname)))
+ printf("PASS (%s)\n", hostname);
+ else
+ {
+ failures ++;
+ puts("FAIL");
+ }
+
+ /*
+ * httpAddrGetList()
+ */
+
+ printf("httpAddrGetList(%s): ", hostname);
+
+ addrlist = httpAddrGetList(hostname, AF_UNSPEC, NULL);
+ if (addrlist)
+ {
+ for (i = 0, addr = addrlist; addr; i ++, addr = addr->next)
+ {
+ char numeric[1024]; /* Numeric IP address */
+
+
+ httpAddrString(&(addr->addr), numeric, sizeof(numeric));
+ if (!strcmp(numeric, "UNKNOWN"))
+ break;
+ }
+
+ if (addr)
+ printf("FAIL (bad address for %s)\n", hostname);
+ else
+ printf("PASS (%d address(es) for %s)\n", i, hostname);
+
+ httpAddrFreeList(addrlist);
+ }
+ else if (isdigit(hostname[0] & 255))
+ {
+ puts("FAIL (ignored because hostname is numeric)");
+ }
+ else
+ {
+ failures ++;
+ puts("FAIL");
+ }
+
+ /*
+ * Test httpSeparateURI()...
+ */
+
+ fputs("httpSeparateURI(): ", stdout);
+ for (i = 0, j = 0; i < (int)(sizeof(uri_tests) / sizeof(uri_tests[0])); i ++)
+ {
+ uri_status = httpSeparateURI(HTTP_URI_CODING_MOST,
+ uri_tests[i].uri, scheme, sizeof(scheme),
+ username, sizeof(username),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(resource));
+ if (uri_status != uri_tests[i].result ||
+ strcmp(scheme, uri_tests[i].scheme) ||
+ strcmp(username, uri_tests[i].username) ||
+ strcmp(hostname, uri_tests[i].hostname) ||
+ port != uri_tests[i].port ||
+ strcmp(resource, uri_tests[i].resource))
+ {
+ failures ++;
+
+ if (!j)
+ {
+ puts("FAIL");
+ j = 1;
+ }
+
+ printf(" \"%s\":\n", uri_tests[i].uri);
+
+ if (uri_status != uri_tests[i].result)
+ printf(" Returned %s instead of %s\n",
+ uri_status_strings[uri_status + 8],
+ uri_status_strings[uri_tests[i].result + 8]);
+
+ if (strcmp(scheme, uri_tests[i].scheme))
+ printf(" Scheme \"%s\" instead of \"%s\"\n",
+ scheme, uri_tests[i].scheme);
+
+ if (strcmp(username, uri_tests[i].username))
+ printf(" Username \"%s\" instead of \"%s\"\n",
+ username, uri_tests[i].username);
+
+ if (strcmp(hostname, uri_tests[i].hostname))
+ printf(" Hostname \"%s\" instead of \"%s\"\n",
+ hostname, uri_tests[i].hostname);
+
+ if (port != uri_tests[i].port)
+ printf(" Port %d instead of %d\n",
+ port, uri_tests[i].port);
+
+ if (strcmp(resource, uri_tests[i].resource))
+ printf(" Resource \"%s\" instead of \"%s\"\n",
+ resource, uri_tests[i].resource);
+ }
+ }
+
+ if (!j)
+ printf("PASS (%d URIs tested)\n",
+ (int)(sizeof(uri_tests) / sizeof(uri_tests[0])));
+
+ /*
+ * Test httpAssembleURI()...
+ */
+
+ fputs("httpAssembleURI(): ", stdout);
+ for (i = 0, j = 0, k = 0;
+ i < (int)(sizeof(uri_tests) / sizeof(uri_tests[0]));
+ i ++)
+ if (uri_tests[i].result == HTTP_URI_OK &&
+ !strstr(uri_tests[i].uri, "%64") &&
+ strstr(uri_tests[i].uri, "//"))
+ {
+ k ++;
+ uri_status = httpAssembleURI(HTTP_URI_CODING_MOST,
+ buffer, sizeof(buffer),
+ uri_tests[i].scheme,
+ uri_tests[i].username,
+ uri_tests[i].hostname,
+ uri_tests[i].assemble_port,
+ uri_tests[i].resource);
+
+ if (uri_status != HTTP_URI_OK)
+ {
+ failures ++;
+
+ if (!j)
+ {
+ puts("FAIL");
+ j = 1;
+ }
+
+ printf(" \"%s\": %s\n", uri_tests[i].uri,
+ uri_status_strings[uri_status + 8]);
+ }
+ else if (strcmp(buffer, uri_tests[i].uri))
+ {
+ failures ++;
+
+ if (!j)
+ {
+ puts("FAIL");
+ j = 1;
+ }
+
+ printf(" \"%s\": assembled = \"%s\"\n", uri_tests[i].uri,
+ buffer);
+ }
+ }
+
+ if (!j)
+ printf("PASS (%d URIs tested)\n", k);
+
+ /*
+ * Show a summary and return...
+ */
+
+ if (failures)
+ printf("\n%d TESTS FAILED!\n", failures);
+ else
+ puts("\nALL TESTS PASSED!");
+
+ return (failures);
+ }
+ else if (strstr(argv[1], "._tcp"))
+ {
+ /*
+ * Test resolving an mDNS name.
+ */
+
+ char resolved[1024]; /* Resolved URI */
+
+
+ printf("_httpResolveURI(%s, _HTTP_RESOLVE_DEFAULT): ", argv[1]);
+ fflush(stdout);
+
+ if (!_httpResolveURI(argv[1], resolved, sizeof(resolved),
+ _HTTP_RESOLVE_DEFAULT, NULL, NULL))
+ {
+ puts("FAIL");
+ return (1);
+ }
+ else
+ printf("PASS (%s)\n", resolved);
+
+ printf("_httpResolveURI(%s, _HTTP_RESOLVE_FQDN): ", argv[1]);
+ fflush(stdout);
+
+ if (!_httpResolveURI(argv[1], resolved, sizeof(resolved),
+ _HTTP_RESOLVE_FQDN, NULL, NULL))
+ {
+ puts("FAIL");
+ return (1);
+ }
+ else if (strstr(resolved, ".local:"))
+ {
+ printf("FAIL (%s)\n", resolved);
+ return (1);
+ }
+ else
+ {
+ printf("PASS (%s)\n", resolved);
+ return (0);
+ }
+ }
+ else if (!strcmp(argv[1], "-u") && argc == 3)
+ {
+ /*
+ * Test URI separation...
+ */
+
+ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, argv[2], scheme,
+ sizeof(scheme), username, sizeof(username),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(resource));
+ printf("uri_status = %s\n", uri_status_strings[uri_status + 8]);
+ printf("scheme = \"%s\"\n", scheme);
+ printf("username = \"%s\"\n", username);
+ printf("hostname = \"%s\"\n", hostname);
+ printf("port = %d\n", port);
+ printf("resource = \"%s\"\n", resource);
+
+ return (0);
+ }
+
+ /*
+ * Test HTTP GET requests...
+ */
+
+ http = NULL;
+ out = stdout;
+
+ for (i = 1; i < argc; i ++)
+ {
+ if (!strcmp(argv[i], "-o"))
+ {
+ i ++;
+ if (i >= argc)
+ break;
+
+ out = fopen(argv[i], "wb");
+ continue;
+ }
+
+ httpSeparateURI(HTTP_URI_CODING_MOST, argv[i], scheme, sizeof(scheme),
+ username, sizeof(username),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(resource));
+
+ http = httpConnectEncrypt(hostname, port, HTTP_ENCRYPT_IF_REQUESTED);
+ if (http == NULL)
+ {
+ perror(hostname);
+ continue;
+ }
+ printf("Requesting file \"%s\"...\n", resource);
+ httpClearFields(http);
+ httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en");
+ httpGet(http, resource);
+ while ((status = httpUpdate(http)) == HTTP_CONTINUE);
+
+ if (status == HTTP_OK)
+ puts("GET OK:");
+ else
+ printf("GET failed with status %d...\n", status);
+
+
+ start = time(NULL);
+ length = httpGetLength2(http);
+ total = 0;
+
+ while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
+ {
+ total += bytes;
+ fwrite(buffer, bytes, 1, out);
+ if (out != stdout)
+ {
+ current = time(NULL);
+ if (current == start) current ++;
+ printf("\r" CUPS_LLFMT "/" CUPS_LLFMT " bytes ("
+ CUPS_LLFMT " bytes/sec) ", CUPS_LLCAST total,
+ CUPS_LLCAST length, CUPS_LLCAST (total / (current - start)));
+ fflush(stdout);
+ }
+ }
+ }
+
+ puts("Closing connection to server...");
+ httpClose(http);
+
+ if (out != stdout)
+ fclose(out);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/testi18n.c b/cups/testi18n.c
new file mode 100644
index 000000000..2e626715f
--- /dev/null
+++ b/cups/testi18n.c
@@ -0,0 +1,619 @@
+/*
+ * "$Id$"
+ *
+ * Internationalization test for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry for internationalization test module.
+ * print_utf8() - Print UTF-8 string with (optional) message.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "string-private.h"
+#include "language-private.h"
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+
+/*
+ * Local globals...
+ */
+
+static const char * const lang_encodings[] =
+ { /* Encoding strings */
+ "us-ascii", "iso-8859-1",
+ "iso-8859-2", "iso-8859-3",
+ "iso-8859-4", "iso-8859-5",
+ "iso-8859-6", "iso-8859-7",
+ "iso-8859-8", "iso-8859-9",
+ "iso-8859-10", "utf-8",
+ "iso-8859-13", "iso-8859-14",
+ "iso-8859-15", "windows-874",
+ "windows-1250", "windows-1251",
+ "windows-1252", "windows-1253",
+ "windows-1254", "windows-1255",
+ "windows-1256", "windows-1257",
+ "windows-1258", "koi8-r",
+ "koi8-u", "iso-8859-11",
+ "iso-8859-16", "mac-roman",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "windows-932", "windows-936",
+ "windows-949", "windows-950",
+ "windows-1361", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "unknown", "unknown",
+ "euc-cn", "euc-jp",
+ "euc-kr", "euc-tw",
+ "jis-x0213"
+ };
+
+
+/*
+ * Local functions...
+ */
+
+static void print_utf8(const char *msg, const cups_utf8_t *src);
+
+
+/*
+ * 'main()' - Main entry for internationalization test module.
+ */
+
+int /* O - Exit code */
+main(int argc, /* I - Argument Count */
+ char *argv[]) /* I - Arguments */
+{
+ FILE *fp; /* File pointer */
+ int count; /* File line counter */
+ int status, /* Status of current test */
+ errors; /* Error count */
+ char line[1024]; /* File line source string */
+ int len; /* Length (count) of string */
+ char legsrc[1024], /* Legacy source string */
+ legdest[1024], /* Legacy destination string */
+ *legptr; /* Pointer into legacy string */
+ cups_utf8_t utf8latin[] = /* UTF-8 Latin-1 source */
+ { 0x41, 0x20, 0x21, 0x3D, 0x20, 0xC3, 0x84, 0x2E, 0x00 };
+ /* "A != <A WITH DIAERESIS>." - use ISO 8859-1 */
+ cups_utf8_t utf8repla[] = /* UTF-8 Latin-1 replacement */
+ { 0x41, 0x20, 0xE2, 0x89, 0xA2, 0x20, 0xC3, 0x84, 0x2E, 0x00 };
+ /* "A <NOT IDENTICAL TO> <A WITH DIAERESIS>." */
+ cups_utf8_t utf8greek[] = /* UTF-8 Greek source string */
+ { 0x41, 0x20, 0x21, 0x3D, 0x20, 0xCE, 0x91, 0x2E, 0x00 };
+ /* "A != <ALPHA>." - use ISO 8859-7 */
+ cups_utf8_t utf8japan[] = /* UTF-8 Japanese source */
+ { 0x41, 0x20, 0x21, 0x3D, 0x20, 0xEE, 0x9C, 0x80, 0x2E, 0x00 };
+ /* "A != <PRIVATE U+E700>." - use Windows 932 or EUC-JP */
+ cups_utf8_t utf8taiwan[] = /* UTF-8 Chinese source */
+ { 0x41, 0x20, 0x21, 0x3D, 0x20, 0xE4, 0xB9, 0x82, 0x2E, 0x00 };
+ /* "A != <CJK U+4E42>." - use Windows 950 (Big5) or EUC-TW */
+ cups_utf8_t utf8dest[1024]; /* UTF-8 destination string */
+ cups_utf32_t utf32dest[1024]; /* UTF-32 destination string */
+
+
+ if (argc > 1)
+ {
+ int i; /* Looping var */
+ cups_encoding_t encoding; /* Source encoding */
+
+
+ if (argc != 3)
+ {
+ puts("Usage: ./testi18n [filename charset]");
+ return (1);
+ }
+
+ if ((fp = fopen(argv[1], "rb")) == NULL)
+ {
+ perror(argv[1]);
+ return (1);
+ }
+
+ for (i = 0, encoding = CUPS_AUTO_ENCODING;
+ i < (int)(sizeof(lang_encodings) / sizeof(lang_encodings[0]));
+ i ++)
+ if (!_cups_strcasecmp(lang_encodings[i], argv[2]))
+ {
+ encoding = (cups_encoding_t)i;
+ break;
+ }
+
+ if (encoding == CUPS_AUTO_ENCODING)
+ {
+ fprintf(stderr, "%s: Unknown character set!\n", argv[2]);
+ return (1);
+ }
+
+ while (fgets(line, sizeof(line), fp))
+ {
+ if (cupsCharsetToUTF8(utf8dest, line, sizeof(utf8dest), encoding) < 0)
+ {
+ fprintf(stderr, "%s: Unable to convert line: %s", argv[1], line);
+ return (1);
+ }
+
+ fputs((char *)utf8dest, stdout);
+ }
+
+ fclose(fp);
+ return (0);
+ }
+
+ /*
+ * Start with some conversion tests from a UTF-8 test file.
+ */
+
+ errors = 0;
+
+ if ((fp = fopen("utf8demo.txt", "rb")) == NULL)
+ {
+ perror("utf8demo.txt");
+ return (1);
+ }
+
+ /*
+ * cupsUTF8ToUTF32
+ */
+
+ fputs("cupsUTF8ToUTF32 of utfdemo.txt: ", stdout);
+
+ for (count = 0, status = 0; fgets(line, sizeof(line), fp);)
+ {
+ count ++;
+
+ if (cupsUTF8ToUTF32(utf32dest, (cups_utf8_t *)line, 1024) < 0)
+ {
+ printf("FAIL (UTF-8 to UTF-32 on line %d)\n", count);
+ errors ++;
+ status = 1;
+ break;
+ }
+ }
+
+ if (!status)
+ puts("PASS");
+
+ /*
+ * cupsUTF8ToCharset(CUPS_EUC_JP)
+ */
+
+ fputs("cupsUTF8ToCharset(CUPS_EUC_JP) of utfdemo.txt: ", stdout);
+
+ rewind(fp);
+
+ for (count = 0, status = 0; fgets(line, sizeof(line), fp);)
+ {
+ count ++;
+
+ len = cupsUTF8ToCharset(legdest, (cups_utf8_t *)line, 1024, CUPS_EUC_JP);
+ if (len < 0)
+ {
+ printf("FAIL (UTF-8 to EUC-JP on line %d)\n", count);
+ errors ++;
+ status = 1;
+ break;
+ }
+ }
+
+ if (!status)
+ puts("PASS");
+
+ fclose(fp);
+
+ /*
+ * Test UTF-8 to legacy charset (ISO 8859-1)...
+ */
+
+ fputs("cupsUTF8ToCharset(CUPS_ISO8859_1): ", stdout);
+
+ legdest[0] = 0;
+
+ len = cupsUTF8ToCharset(legdest, utf8latin, 1024, CUPS_ISO8859_1);
+ if (len < 0)
+ {
+ printf("FAIL (len=%d)\n", len);
+ errors ++;
+ }
+ else
+ puts("PASS");
+
+ /*
+ * cupsCharsetToUTF8
+ */
+
+ fputs("cupsCharsetToUTF8(CUPS_ISO8859_1): ", stdout);
+
+ strcpy(legsrc, legdest);
+
+ len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_ISO8859_1);
+ if (len != strlen((char *)utf8latin))
+ {
+ printf("FAIL (len=%d, expected %d)\n", len, (int)strlen((char *)utf8latin));
+ print_utf8(" utf8latin", utf8latin);
+ print_utf8(" utf8dest", utf8dest);
+ errors ++;
+ }
+ else if (memcmp(utf8latin, utf8dest, len))
+ {
+ puts("FAIL (results do not match)");
+ print_utf8(" utf8latin", utf8latin);
+ print_utf8(" utf8dest", utf8dest);
+ errors ++;
+ }
+ else if (cupsUTF8ToCharset(legdest, utf8repla, 1024, CUPS_ISO8859_1) < 0)
+ {
+ puts("FAIL (replacement characters do not work!)");
+ errors ++;
+ }
+ else
+ puts("PASS");
+
+ /*
+ * Test UTF-8 to/from legacy charset (ISO 8859-7)...
+ */
+
+ fputs("cupsUTF8ToCharset(CUPS_ISO8859_7): ", stdout);
+
+ if (cupsUTF8ToCharset(legdest, utf8greek, 1024, CUPS_ISO8859_7) < 0)
+ {
+ puts("FAIL");
+ errors ++;
+ }
+ else
+ {
+ for (legptr = legdest; *legptr && *legptr != '?'; legptr ++);
+
+ if (*legptr)
+ {
+ puts("FAIL (unknown character)");
+ errors ++;
+ }
+ else
+ puts("PASS");
+ }
+
+ fputs("cupsCharsetToUTF8(CUPS_ISO8859_7): ", stdout);
+
+ strcpy(legsrc, legdest);
+
+ len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_ISO8859_7);
+ if (len != strlen((char *)utf8greek))
+ {
+ printf("FAIL (len=%d, expected %d)\n", len, (int)strlen((char *)utf8greek));
+ print_utf8(" utf8greek", utf8greek);
+ print_utf8(" utf8dest", utf8dest);
+ errors ++;
+ }
+ else if (memcmp(utf8greek, utf8dest, len))
+ {
+ puts("FAIL (results do not match)");
+ print_utf8(" utf8greek", utf8greek);
+ print_utf8(" utf8dest", utf8dest);
+ errors ++;
+ }
+ else
+ puts("PASS");
+
+ /*
+ * Test UTF-8 to/from legacy charset (Windows 932)...
+ */
+
+ fputs("cupsUTF8ToCharset(CUPS_WINDOWS_932): ", stdout);
+
+ if (cupsUTF8ToCharset(legdest, utf8japan, 1024, CUPS_WINDOWS_932) < 0)
+ {
+ puts("FAIL");
+ errors ++;
+ }
+ else
+ {
+ for (legptr = legdest; *legptr && *legptr != '?'; legptr ++);
+
+ if (*legptr)
+ {
+ puts("FAIL (unknown character)");
+ errors ++;
+ }
+ else
+ puts("PASS");
+ }
+
+ fputs("cupsCharsetToUTF8(CUPS_WINDOWS_932): ", stdout);
+
+ strcpy(legsrc, legdest);
+
+ len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_WINDOWS_932);
+ if (len != strlen((char *)utf8japan))
+ {
+ printf("FAIL (len=%d, expected %d)\n", len, (int)strlen((char *)utf8japan));
+ print_utf8(" utf8japan", utf8japan);
+ print_utf8(" utf8dest", utf8dest);
+ errors ++;
+ }
+ else if (memcmp(utf8japan, utf8dest, len))
+ {
+ puts("FAIL (results do not match)");
+ print_utf8(" utf8japan", utf8japan);
+ print_utf8(" utf8dest", utf8dest);
+ errors ++;
+ }
+ else
+ puts("PASS");
+
+ /*
+ * Test UTF-8 to/from legacy charset (EUC-JP)...
+ */
+
+ fputs("cupsUTF8ToCharset(CUPS_EUC_JP): ", stdout);
+
+ if (cupsUTF8ToCharset(legdest, utf8japan, 1024, CUPS_EUC_JP) < 0)
+ {
+ puts("FAIL");
+ errors ++;
+ }
+ else
+ {
+ for (legptr = legdest; *legptr && *legptr != '?'; legptr ++);
+
+ if (*legptr)
+ {
+ puts("FAIL (unknown character)");
+ errors ++;
+ }
+ else
+ puts("PASS");
+ }
+
+#ifndef __linux
+ fputs("cupsCharsetToUTF8(CUPS_EUC_JP): ", stdout);
+
+ strcpy(legsrc, legdest);
+
+ len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_EUC_JP);
+ if (len != strlen((char *)utf8japan))
+ {
+ printf("FAIL (len=%d, expected %d)\n", len, (int)strlen((char *)utf8japan));
+ print_utf8(" utf8japan", utf8japan);
+ print_utf8(" utf8dest", utf8dest);
+ errors ++;
+ }
+ else if (memcmp(utf8japan, utf8dest, len))
+ {
+ puts("FAIL (results do not match)");
+ print_utf8(" utf8japan", utf8japan);
+ print_utf8(" utf8dest", utf8dest);
+ errors ++;
+ }
+ else
+ puts("PASS");
+#endif /* !__linux */
+
+ /*
+ * Test UTF-8 to/from legacy charset (Windows 950)...
+ */
+
+ fputs("cupsUTF8ToCharset(CUPS_WINDOWS_950): ", stdout);
+
+ if (cupsUTF8ToCharset(legdest, utf8taiwan, 1024, CUPS_WINDOWS_950) < 0)
+ {
+ puts("FAIL");
+ errors ++;
+ }
+ else
+ {
+ for (legptr = legdest; *legptr && *legptr != '?'; legptr ++);
+
+ if (*legptr)
+ {
+ puts("FAIL (unknown character)");
+ errors ++;
+ }
+ else
+ puts("PASS");
+ }
+
+ fputs("cupsCharsetToUTF8(CUPS_WINDOWS_950): ", stdout);
+
+ strcpy(legsrc, legdest);
+
+ len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_WINDOWS_950);
+ if (len != strlen((char *)utf8taiwan))
+ {
+ printf("FAIL (len=%d, expected %d)\n", len, (int)strlen((char *)utf8taiwan));
+ print_utf8(" utf8taiwan", utf8taiwan);
+ print_utf8(" utf8dest", utf8dest);
+ errors ++;
+ }
+ else if (memcmp(utf8taiwan, utf8dest, len))
+ {
+ puts("FAIL (results do not match)");
+ print_utf8(" utf8taiwan", utf8taiwan);
+ print_utf8(" utf8dest", utf8dest);
+ errors ++;
+ }
+ else
+ puts("PASS");
+
+ /*
+ * Test UTF-8 to/from legacy charset (EUC-TW)...
+ */
+
+ fputs("cupsUTF8ToCharset(CUPS_EUC_TW): ", stdout);
+
+ if (cupsUTF8ToCharset(legdest, utf8taiwan, 1024, CUPS_EUC_TW) < 0)
+ {
+ puts("FAIL");
+ errors ++;
+ }
+ else
+ {
+ for (legptr = legdest; *legptr && *legptr != '?'; legptr ++);
+
+ if (*legptr)
+ {
+ puts("FAIL (unknown character)");
+ errors ++;
+ }
+ else
+ puts("PASS");
+ }
+
+ fputs("cupsCharsetToUTF8(CUPS_EUC_TW): ", stdout);
+
+ strcpy(legsrc, legdest);
+
+ len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_EUC_TW);
+ if (len != strlen((char *)utf8taiwan))
+ {
+ printf("FAIL (len=%d, expected %d)\n", len, (int)strlen((char *)utf8taiwan));
+ print_utf8(" utf8taiwan", utf8taiwan);
+ print_utf8(" utf8dest", utf8dest);
+ errors ++;
+ }
+ else if (memcmp(utf8taiwan, utf8dest, len))
+ {
+ puts("FAIL (results do not match)");
+ print_utf8(" utf8taiwan", utf8taiwan);
+ print_utf8(" utf8dest", utf8dest);
+ errors ++;
+ }
+ else
+ puts("PASS");
+
+#if 0
+ /*
+ * Test UTF-8 (16-bit) to UTF-32 (w/ BOM)...
+ */
+ if (verbose)
+ printf("\ntesti18n: Testing UTF-8 to UTF-32 (w/ BOM)...\n");
+ len = cupsUTF8ToUTF32(utf32dest, utf8good, 1024);
+ if (len < 0)
+ return (1);
+ if (verbose)
+ {
+ print_utf8(" utf8good ", utf8good);
+ print_utf32(" utf32dest", utf32dest);
+ }
+ memcpy (utf32src, utf32dest, (len + 1) * sizeof(cups_utf32_t));
+ len = cupsUTF32ToUTF8(utf8dest, utf32src, 1024);
+ if (len < 0)
+ return (1);
+ if (len != strlen ((char *) utf8good))
+ return (1);
+ if (memcmp(utf8good, utf8dest, len) != 0)
+ return (1);
+
+ /*
+ * Test invalid UTF-8 (16-bit) to UTF-32 (w/ BOM)...
+ */
+ if (verbose)
+ printf("\ntesti18n: Testing UTF-8 bad 16-bit source string...\n");
+ len = cupsUTF8ToUTF32(utf32dest, utf8bad, 1024);
+ if (len >= 0)
+ return (1);
+ if (verbose)
+ print_utf8(" utf8bad ", utf8bad);
+
+ /*
+ * Test _cupsCharmapFlush()...
+ */
+ if (verbose)
+ printf("\ntesti18n: Testing _cupsCharmapFlush()...\n");
+ _cupsCharmapFlush();
+ return (0);
+#endif /* 0 */
+
+ return (errors > 0);
+}
+
+
+/*
+ * 'print_utf8()' - Print UTF-8 string with (optional) message.
+ */
+
+static void
+print_utf8(const char *msg, /* I - Message String */
+ const cups_utf8_t *src) /* I - UTF-8 Source String */
+{
+ const char *prefix; /* Prefix string */
+
+
+ if (msg)
+ printf("%s:", msg);
+
+ for (prefix = " "; *src; src ++)
+ {
+ printf("%s%02x", prefix, *src);
+
+ if ((src[0] & 0x80) && (src[1] & 0x80))
+ prefix = "";
+ else
+ prefix = " ";
+ }
+
+ putchar('\n');
+}
+
+
+/*
+ * End of "$Id$"
+ */
diff --git a/cups/testipp.c b/cups/testipp.c
new file mode 100644
index 000000000..57211c1b4
--- /dev/null
+++ b/cups/testipp.c
@@ -0,0 +1,867 @@
+/*
+ * "$Id$"
+ *
+ * IPP test program for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry.
+ * hex_dump() - Produce a hex dump of a buffer.
+ * print_attributes() - Print the attributes in a request...
+ * read_cb() - Read data from a buffer.
+ * write_cb() - Write data into a buffer.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "file.h"
+#include "string-private.h"
+#include "ipp-private.h"
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+# include <fcntl.h>
+#endif /* WIN32 */
+
+
+/*
+ * Local globals...
+ */
+
+int rpos; /* Current position in buffer */
+ipp_uchar_t wbuffer[8192]; /* Write buffer */
+int wused; /* Number of bytes in buffer */
+ipp_uchar_t collection[] = /* Collection buffer */
+ {
+ 0x01, 0x01, /* IPP version */
+ 0x00, 0x02, /* Print-Job operation */
+ 0x00, 0x00, 0x00, 0x01, /* Request ID */
+
+ IPP_TAG_OPERATION,
+
+ IPP_TAG_CHARSET,
+ 0x00, 0x12, /* Name length + name */
+ 'a','t','t','r','i','b','u','t','e','s','-',
+ 'c','h','a','r','s','e','t',
+ 0x00, 0x05, /* Value length + value */
+ 'u','t','f','-','8',
+
+ IPP_TAG_LANGUAGE,
+ 0x00, 0x1b, /* Name length + name */
+ 'a','t','t','r','i','b','u','t','e','s','-',
+ 'n','a','t','u','r','a','l','-','l','a','n',
+ 'g','u','a','g','e',
+ 0x00, 0x02, /* Value length + value */
+ 'e','n',
+
+ IPP_TAG_URI,
+ 0x00, 0x0b, /* Name length + name */
+ 'p','r','i','n','t','e','r','-','u','r','i',
+ 0x00, 0x1c, /* Value length + value */
+ 'i','p','p',':','/','/','l','o','c','a','l',
+ 'h','o','s','t','/','p','r','i','n','t','e',
+ 'r','s','/','f','o','o',
+
+ IPP_TAG_JOB, /* job group tag */
+
+ IPP_TAG_BEGIN_COLLECTION, /* begCollection tag */
+ 0x00, 0x09, /* Name length + name */
+ 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l',
+ 0x00, 0x00, /* No value */
+ IPP_TAG_MEMBERNAME, /* memberAttrName tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x0a, /* Value length + value */
+ 'm', 'e', 'd', 'i', 'a', '-', 's', 'i', 'z', 'e',
+ IPP_TAG_BEGIN_COLLECTION, /* begCollection tag */
+ 0x00, 0x00, /* Name length + name */
+ 0x00, 0x00, /* No value */
+ IPP_TAG_MEMBERNAME, /* memberAttrName tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x0b, /* Value length + value */
+ 'x', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n',
+ IPP_TAG_INTEGER, /* integer tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x04, /* Value length + value */
+ 0x00, 0x00, 0x54, 0x56,
+ IPP_TAG_MEMBERNAME, /* memberAttrName tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x0b, /* Value length + value */
+ 'y', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n',
+ IPP_TAG_INTEGER, /* integer tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x04, /* Value length + value */
+ 0x00, 0x00, 0x6d, 0x24,
+ IPP_TAG_END_COLLECTION, /* endCollection tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x00, /* No value */
+ IPP_TAG_MEMBERNAME, /* memberAttrName tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x0b, /* Value length + value */
+ 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r',
+ IPP_TAG_KEYWORD, /* keyword tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x04, /* Value length + value */
+ 'b', 'l', 'u', 'e',
+
+ IPP_TAG_MEMBERNAME, /* memberAttrName tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x0a, /* Value length + value */
+ 'm', 'e', 'd', 'i', 'a', '-', 't', 'y', 'p', 'e',
+ IPP_TAG_KEYWORD, /* keyword tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x05, /* Value length + value */
+ 'p', 'l', 'a', 'i', 'n',
+ IPP_TAG_END_COLLECTION, /* endCollection tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x00, /* No value */
+
+ IPP_TAG_BEGIN_COLLECTION, /* begCollection tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x00, /* No value */
+ IPP_TAG_MEMBERNAME, /* memberAttrName tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x0a, /* Value length + value */
+ 'm', 'e', 'd', 'i', 'a', '-', 's', 'i', 'z', 'e',
+ IPP_TAG_BEGIN_COLLECTION, /* begCollection tag */
+ 0x00, 0x00, /* Name length + name */
+ 0x00, 0x00, /* No value */
+ IPP_TAG_MEMBERNAME, /* memberAttrName tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x0b, /* Value length + value */
+ 'x', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n',
+ IPP_TAG_INTEGER, /* integer tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x04, /* Value length + value */
+ 0x00, 0x00, 0x52, 0x08,
+ IPP_TAG_MEMBERNAME, /* memberAttrName tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x0b, /* Value length + value */
+ 'y', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n',
+ IPP_TAG_INTEGER, /* integer tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x04, /* Value length + value */
+ 0x00, 0x00, 0x74, 0x04,
+ IPP_TAG_END_COLLECTION, /* endCollection tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x00, /* No value */
+ IPP_TAG_MEMBERNAME, /* memberAttrName tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x0b, /* Value length + value */
+ 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r',
+ IPP_TAG_KEYWORD, /* keyword tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x05, /* Value length + value */
+ 'p', 'l', 'a', 'i', 'd',
+
+ IPP_TAG_MEMBERNAME, /* memberAttrName tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x0a, /* Value length + value */
+ 'm', 'e', 'd', 'i', 'a', '-', 't', 'y', 'p', 'e',
+ IPP_TAG_KEYWORD, /* keyword tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x06, /* Value length + value */
+ 'g', 'l', 'o', 's', 's', 'y',
+ IPP_TAG_END_COLLECTION, /* endCollection tag */
+ 0x00, 0x00, /* No name */
+ 0x00, 0x00, /* No value */
+
+ IPP_TAG_END /* end tag */
+ };
+
+
+/*
+ * Local functions...
+ */
+
+void hex_dump(const char *title, ipp_uchar_t *buffer, int bytes);
+void print_attributes(ipp_t *ipp, int indent);
+ssize_t read_cb(void *data, ipp_uchar_t *buffer, size_t bytes);
+ssize_t write_cb(void *data, ipp_uchar_t *buffer, size_t bytes);
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ ipp_t *cols[2], /* Collections */
+ *size; /* media-size collection */
+ ipp_t *request; /* Request */
+ ipp_attribute_t *media_col, /* media-col attribute */
+ *media_size, /* media-size attribute */
+ *attr; /* Other attribute */
+ ipp_state_t state; /* State */
+ int length; /* Length of data */
+ cups_file_t *fp; /* File pointer */
+ int i; /* Looping var */
+ int status; /* Status of tests (0 = success, 1 = fail) */
+
+
+ status = 0;
+
+ if (argc == 1)
+ {
+ /*
+ * Test request generation code...
+ */
+
+ printf("Create Sample Request: ");
+
+ request = ippNew();
+ request->request.op.version[0] = 0x01;
+ request->request.op.version[1] = 0x01;
+ 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, "utf-8");
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, "en");
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, "ipp://localhost/printers/foo");
+
+ cols[0] = ippNew();
+ size = ippNew();
+ ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "x-dimension", 21590);
+ ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "y-dimension", 27940);
+ ippAddCollection(cols[0], IPP_TAG_JOB, "media-size", size);
+ ippDelete(size);
+ ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL,
+ "blue");
+ ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL,
+ "plain");
+
+ cols[1] = ippNew();
+ size = ippNew();
+ ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "x-dimension", 21000);
+ ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "y-dimension", 29700);
+ ippAddCollection(cols[1], IPP_TAG_JOB, "media-size", size);
+ ippDelete(size);
+ ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL,
+ "plaid");
+ ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL,
+ "glossy");
+
+ ippAddCollections(request, IPP_TAG_JOB, "media-col", 2,
+ (const ipp_t **)cols);
+ ippDelete(cols[0]);
+ ippDelete(cols[1]);
+
+ length = ippLength(request);
+ if (length != sizeof(collection))
+ {
+ printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n",
+ length, (int)sizeof(collection));
+ status = 1;
+ }
+ else
+ puts("PASS");
+
+ /*
+ * Write test #1...
+ */
+
+ printf("Write Sample to Memory: ");
+
+ wused = 0;
+ while ((state = ippWriteIO(wbuffer, write_cb, 1, NULL,
+ request)) != IPP_DATA)
+ if (state == IPP_ERROR)
+ break;
+
+ if (state != IPP_DATA)
+ {
+ printf("FAIL - %d bytes written.\n", wused);
+ status = 1;
+ }
+ else if (wused != sizeof(collection))
+ {
+ printf("FAIL - wrote %d bytes, expected %d bytes!\n", wused,
+ (int)sizeof(collection));
+ hex_dump("Bytes Written", wbuffer, wused);
+ hex_dump("Baseline", collection, sizeof(collection));
+ status = 1;
+ }
+ else if (memcmp(wbuffer, collection, wused))
+ {
+ for (i = 0; i < wused; i ++)
+ if (wbuffer[i] != collection[i])
+ break;
+
+ printf("FAIL - output does not match baseline at 0x%04x!\n", i);
+ hex_dump("Bytes Written", wbuffer, wused);
+ hex_dump("Baseline", collection, sizeof(collection));
+ status = 1;
+ }
+ else
+ puts("PASS");
+
+ ippDelete(request);
+
+ /*
+ * Read the data back in and confirm...
+ */
+
+ printf("Read Sample from Memory: ");
+
+ request = ippNew();
+ rpos = 0;
+
+ while ((state = ippReadIO(wbuffer, read_cb, 1, NULL, request)) != IPP_DATA)
+ if (state == IPP_ERROR)
+ break;
+
+ length = ippLength(request);
+
+ if (state != IPP_DATA)
+ {
+ printf("FAIL - %d bytes read.\n", rpos);
+ status = 1;
+ }
+ else if (rpos != wused)
+ {
+ printf("FAIL - read %d bytes, expected %d bytes!\n", rpos, wused);
+ print_attributes(request, 8);
+ status = 1;
+ }
+ else if (length != sizeof(collection))
+ {
+ printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n",
+ length, (int)sizeof(collection));
+ print_attributes(request, 8);
+ status = 1;
+ }
+ else
+ puts("PASS");
+
+ fputs("ippFindAttribute(media-col): ", stdout);
+ if ((media_col = ippFindAttribute(request, "media-col",
+ IPP_TAG_BEGIN_COLLECTION)) == NULL)
+ {
+ if ((media_col = ippFindAttribute(request, "media-col",
+ IPP_TAG_ZERO)) == NULL)
+ puts("FAIL (not found)");
+ else
+ printf("FAIL (wrong type - %s)\n", ippTagString(media_col->value_tag));
+
+ status = 1;
+ }
+ else if (media_col->num_values != 2)
+ {
+ printf("FAIL (wrong count - %d)\n", media_col->num_values);
+ status = 1;
+ }
+ else
+ puts("PASS");
+
+ if (media_col)
+ {
+ fputs("ippFindAttribute(media-size 1): ", stdout);
+ if ((media_size = ippFindAttribute(media_col->values[0].collection,
+ "media-size",
+ IPP_TAG_BEGIN_COLLECTION)) == NULL)
+ {
+ if ((media_size = ippFindAttribute(media_col->values[0].collection,
+ "media-col",
+ IPP_TAG_ZERO)) == NULL)
+ puts("FAIL (not found)");
+ else
+ printf("FAIL (wrong type - %s)\n",
+ ippTagString(media_size->value_tag));
+
+ status = 1;
+ }
+ else
+ {
+ if ((attr = ippFindAttribute(media_size->values[0].collection,
+ "x-dimension", IPP_TAG_INTEGER)) == NULL)
+ {
+ if ((attr = ippFindAttribute(media_size->values[0].collection,
+ "x-dimension", IPP_TAG_ZERO)) == NULL)
+ puts("FAIL (missing x-dimension)");
+ else
+ printf("FAIL (wrong type for x-dimension - %s)\n",
+ ippTagString(attr->value_tag));
+
+ status = 1;
+ }
+ else if (attr->values[0].integer != 21590)
+ {
+ printf("FAIL (wrong value for x-dimension - %d)\n",
+ attr->values[0].integer);
+ status = 1;
+ }
+ else if ((attr = ippFindAttribute(media_size->values[0].collection,
+ "y-dimension",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ if ((attr = ippFindAttribute(media_size->values[0].collection,
+ "y-dimension", IPP_TAG_ZERO)) == NULL)
+ puts("FAIL (missing y-dimension)");
+ else
+ printf("FAIL (wrong type for y-dimension - %s)\n",
+ ippTagString(attr->value_tag));
+
+ status = 1;
+ }
+ else if (attr->values[0].integer != 27940)
+ {
+ printf("FAIL (wrong value for y-dimension - %d)\n",
+ attr->values[0].integer);
+ status = 1;
+ }
+ else
+ puts("PASS");
+ }
+
+ fputs("ippFindAttribute(media-size 2): ", stdout);
+ if ((media_size = ippFindAttribute(media_col->values[1].collection,
+ "media-size",
+ IPP_TAG_BEGIN_COLLECTION)) == NULL)
+ {
+ if ((media_size = ippFindAttribute(media_col->values[1].collection,
+ "media-col",
+ IPP_TAG_ZERO)) == NULL)
+ puts("FAIL (not found)");
+ else
+ printf("FAIL (wrong type - %s)\n",
+ ippTagString(media_size->value_tag));
+
+ status = 1;
+ }
+ else
+ {
+ if ((attr = ippFindAttribute(media_size->values[0].collection,
+ "x-dimension",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ if ((attr = ippFindAttribute(media_size->values[0].collection,
+ "x-dimension", IPP_TAG_ZERO)) == NULL)
+ puts("FAIL (missing x-dimension)");
+ else
+ printf("FAIL (wrong type for x-dimension - %s)\n",
+ ippTagString(attr->value_tag));
+
+ status = 1;
+ }
+ else if (attr->values[0].integer != 21000)
+ {
+ printf("FAIL (wrong value for x-dimension - %d)\n",
+ attr->values[0].integer);
+ status = 1;
+ }
+ else if ((attr = ippFindAttribute(media_size->values[0].collection,
+ "y-dimension",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ if ((attr = ippFindAttribute(media_size->values[0].collection,
+ "y-dimension", IPP_TAG_ZERO)) == NULL)
+ puts("FAIL (missing y-dimension)");
+ else
+ printf("FAIL (wrong type for y-dimension - %s)\n",
+ ippTagString(attr->value_tag));
+
+ status = 1;
+ }
+ else if (attr->values[0].integer != 29700)
+ {
+ printf("FAIL (wrong value for y-dimension - %d)\n",
+ attr->values[0].integer);
+ status = 1;
+ }
+ else
+ puts("PASS");
+ }
+ }
+
+ ippDelete(request);
+
+ /*
+ * Test _ippFindOption() private API...
+ */
+
+ fputs("_ippFindOption(printer-type): ", stdout);
+ if (_ippFindOption("printer-type"))
+ puts("PASS");
+ else
+ {
+ puts("FAIL");
+ status = 1;
+ }
+
+ /*
+ * Summarize...
+ */
+
+ putchar('\n');
+
+ if (status)
+ puts("Core IPP tests failed.");
+ else
+ puts("Core IPP tests passed.");
+ }
+ else
+ {
+ /*
+ * Read IPP files...
+ */
+
+ for (i = 1; i < argc; i ++)
+ {
+ if ((fp = cupsFileOpen(argv[i], "r")) == NULL)
+ {
+ printf("Unable to open \"%s\" - %s\n", argv[i], strerror(errno));
+ status = 1;
+ continue;
+ }
+
+ request = ippNew();
+ while ((state = ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL,
+ request)) == IPP_ATTRIBUTE);
+
+ if (state != IPP_DATA)
+ {
+ printf("Error reading IPP message from \"%s\"!\n", argv[i]);
+ status = 1;
+ }
+ else
+ {
+ printf("\n%s:\n", argv[i]);
+ print_attributes(request, 4);
+ }
+
+ ippDelete(request);
+ cupsFileClose(fp);
+ }
+ }
+
+ return (status);
+}
+
+
+/*
+ * 'hex_dump()' - Produce a hex dump of a buffer.
+ */
+
+void
+hex_dump(const char *title, /* I - Title */
+ ipp_uchar_t *buffer, /* I - Buffer to dump */
+ int bytes) /* I - Number of bytes */
+{
+ int i, j; /* Looping vars */
+ int ch; /* Current ASCII char */
+
+
+ /*
+ * Show lines of 16 bytes at a time...
+ */
+
+ printf(" %s:\n", title);
+
+ for (i = 0; i < bytes; i += 16)
+ {
+ /*
+ * Show the offset...
+ */
+
+ printf(" %04x ", i);
+
+ /*
+ * Then up to 16 bytes in hex...
+ */
+
+ for (j = 0; j < 16; j ++)
+ if ((i + j) < bytes)
+ printf(" %02x", buffer[i + j]);
+ else
+ printf(" ");
+
+ /*
+ * Then the ASCII representation of the bytes...
+ */
+
+ putchar(' ');
+ putchar(' ');
+
+ for (j = 0; j < 16 && (i + j) < bytes; j ++)
+ {
+ ch = buffer[i + j] & 127;
+
+ if (ch < ' ' || ch == 127)
+ putchar('.');
+ else
+ putchar(ch);
+ }
+
+ putchar('\n');
+ }
+}
+
+
+/*
+ * 'print_attributes()' - Print the attributes in a request...
+ */
+
+void
+print_attributes(ipp_t *ipp, /* I - IPP request */
+ int indent) /* I - Indentation */
+{
+ int i; /* Looping var */
+ ipp_tag_t group; /* Current group */
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_value_t *val; /* Current value */
+ static const char * const tags[] = /* Value/group tag strings */
+ {
+ "reserved-00",
+ "operation-attributes-tag",
+ "job-attributes-tag",
+ "end-of-attributes-tag",
+ "printer-attributes-tag",
+ "unsupported-attributes-tag",
+ "subscription-attributes-tag",
+ "event-attributes-tag",
+ "reserved-08",
+ "reserved-09",
+ "reserved-0A",
+ "reserved-0B",
+ "reserved-0C",
+ "reserved-0D",
+ "reserved-0E",
+ "reserved-0F",
+ "unsupported",
+ "default",
+ "unknown",
+ "no-value",
+ "reserved-14",
+ "not-settable",
+ "delete-attr",
+ "admin-define",
+ "reserved-18",
+ "reserved-19",
+ "reserved-1A",
+ "reserved-1B",
+ "reserved-1C",
+ "reserved-1D",
+ "reserved-1E",
+ "reserved-1F",
+ "reserved-20",
+ "integer",
+ "boolean",
+ "enum",
+ "reserved-24",
+ "reserved-25",
+ "reserved-26",
+ "reserved-27",
+ "reserved-28",
+ "reserved-29",
+ "reserved-2a",
+ "reserved-2b",
+ "reserved-2c",
+ "reserved-2d",
+ "reserved-2e",
+ "reserved-2f",
+ "octetString",
+ "dateTime",
+ "resolution",
+ "rangeOfInteger",
+ "begCollection",
+ "textWithLanguage",
+ "nameWithLanguage",
+ "endCollection",
+ "reserved-38",
+ "reserved-39",
+ "reserved-3a",
+ "reserved-3b",
+ "reserved-3c",
+ "reserved-3d",
+ "reserved-3e",
+ "reserved-3f",
+ "reserved-40",
+ "textWithoutLanguage",
+ "nameWithoutLanguage",
+ "reserved-43",
+ "keyword",
+ "uri",
+ "uriScheme",
+ "charset",
+ "naturalLanguage",
+ "mimeMediaType",
+ "memberName"
+ };
+
+
+ for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next)
+ {
+ if (!attr->name && indent == 4)
+ {
+ group = IPP_TAG_ZERO;
+ putchar('\n');
+ continue;
+ }
+
+ if (group != attr->group_tag)
+ {
+ group = attr->group_tag;
+
+ printf("\n%*s%s:\n\n", indent - 4, "", tags[group]);
+ }
+
+ printf("%*s%s (", indent, "", attr->name ? attr->name : "(null)");
+ if (attr->num_values > 1)
+ printf("1setOf ");
+ printf("%s):", tags[attr->value_tag]);
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_ENUM :
+ case IPP_TAG_INTEGER :
+ for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
+ printf(" %d", val->integer);
+ putchar('\n');
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
+ printf(" %s", val->boolean ? "true" : "false");
+ putchar('\n');
+ break;
+
+ case IPP_TAG_RANGE :
+ for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
+ printf(" %d-%d", val->range.lower, val->range.upper);
+ putchar('\n');
+ break;
+
+ case IPP_TAG_DATE :
+ {
+ time_t vtime; /* Date/Time value */
+ struct tm *vdate; /* Date info */
+ char vstring[256]; /* Formatted time */
+
+ for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
+ {
+ vtime = ippDateToTime(val->date);
+ vdate = localtime(&vtime);
+ strftime(vstring, sizeof(vstring), "%c", vdate);
+ printf(" (%s)", vstring);
+ }
+ }
+ putchar('\n');
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
+ printf(" %dx%d%s", val->resolution.xres, val->resolution.yres,
+ val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpc");
+ putchar('\n');
+ break;
+
+ case IPP_TAG_STRING :
+ 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_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
+ printf(" \"%s\"", val->string.text);
+ putchar('\n');
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ putchar('\n');
+
+ for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
+ {
+ if (i)
+ putchar('\n');
+ print_attributes(val->collection, indent + 4);
+ }
+ break;
+
+ default :
+ printf("UNKNOWN (%d values)\n", attr->num_values);
+ break;
+ }
+ }
+}
+
+
+/*
+ * 'read_cb()' - Read data from a buffer.
+ */
+
+ssize_t /* O - Number of bytes read */
+read_cb(void *data, /* I - Data */
+ ipp_uchar_t *buffer, /* O - Buffer to read */
+ size_t bytes) /* I - Number of bytes to read */
+{
+ int count; /* Number of bytes */
+
+
+ /*
+ * Copy bytes from the data buffer to the read buffer...
+ */
+
+ for (count = bytes; count > 0 && rpos < wused; count --, rpos ++)
+ *buffer++ = wbuffer[rpos];
+
+ /*
+ * Return the number of bytes read...
+ */
+
+ return (bytes - count);
+}
+
+
+/*
+ * 'write_cb()' - Write data into a buffer.
+ */
+
+ssize_t /* O - Number of bytes written */
+write_cb(void *data, /* I - Data */
+ ipp_uchar_t *buffer, /* I - Buffer to write */
+ size_t bytes) /* I - Number of bytes to write */
+{
+ int count; /* Number of bytes */
+
+
+ /*
+ * Loop until all bytes are written...
+ */
+
+ for (count = bytes; count > 0 && wused < sizeof(wbuffer); count --, wused ++)
+ wbuffer[wused] = *buffer++;
+
+ /*
+ * Return the number of bytes written...
+ */
+
+ return (bytes - count);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/testlang.c b/cups/testlang.c
new file mode 100644
index 000000000..701c14db4
--- /dev/null
+++ b/cups/testlang.c
@@ -0,0 +1,114 @@
+/*
+ * "$Id$"
+ *
+ * Localization test program for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Load the specified language and show the strings for yes and no.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+
+
+/*
+ * 'main()' - Load the specified language and show the strings for yes and no.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ int errors = 0; /* Number of errors */
+ cups_lang_t *language; /* Message catalog */
+ cups_lang_t *language2; /* Message catalog */
+ struct lconv *loc; /* Locale data */
+ char buffer[1024]; /* String buffer */
+ double number; /* Number */
+ static const char * const tests[] = /* Test strings */
+ {
+ "1",
+ "-1",
+ "3",
+ "5.125"
+ };
+
+
+ _cupsSetLocale(argv);
+
+ if (argc == 1)
+ {
+ language = cupsLangDefault();
+ language2 = cupsLangDefault();
+ }
+ else
+ {
+ language = cupsLangGet(argv[1]);
+ language2 = cupsLangGet(argv[1]);
+ }
+
+ if (language != language2)
+ {
+ errors ++;
+
+ puts("**** ERROR: Language cache did not work! ****");
+ puts("First result from cupsLangGet:");
+ }
+
+ printf("Language = \"%s\"\n", language->language);
+ printf("Encoding = \"%s\"\n", _cupsEncodingName(language->encoding));
+ printf("No = \"%s\"\n", _cupsLangString(language, "No"));
+ printf("Yes = \"%s\"\n", _cupsLangString(language, "Yes"));
+
+ if (language != language2)
+ {
+ puts("Second result from cupsLangGet:");
+
+ printf("Language = \"%s\"\n", language2->language);
+ printf("Encoding = \"%s\"\n", _cupsEncodingName(language2->encoding));
+ printf("No = \"%s\"\n", _cupsLangString(language2, "No"));
+ printf("Yes = \"%s\"\n", _cupsLangString(language2, "Yes"));
+ }
+
+ loc = localeconv();
+
+ for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i ++)
+ {
+ number = _cupsStrScand(tests[i], NULL, loc);
+
+ printf("_cupsStrScand(\"%s\") number=%f\n", tests[i], number);
+
+ _cupsStrFormatd(buffer, buffer + sizeof(buffer), number, loc);
+
+ printf("_cupsStrFormatd(%f) buffer=\"%s\"\n", number, buffer);
+
+ if (strcmp(buffer, tests[i]))
+ {
+ errors ++;
+ puts("**** ERROR: Bad formatted number! ****");
+ }
+ }
+
+ return (errors > 0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/testoptions.c b/cups/testoptions.c
new file mode 100644
index 000000000..1cd72794f
--- /dev/null
+++ b/cups/testoptions.c
@@ -0,0 +1,116 @@
+/*
+ * "$Id$"
+ *
+ * Option test program for CUPS.
+ *
+ * Copyright 2008-2010 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Test option processing functions.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+
+
+/*
+ * 'main()' - Test option processing functions.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int status = 0, /* Exit status */
+ num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ const char *value; /* Value of an option */
+
+
+ if (argc == 1)
+ {
+ /*
+ * cupsParseOptions()
+ */
+
+ fputs("cupsParseOptions: ", stdout);
+
+ num_options = cupsParseOptions("foo=1234 "
+ "bar=\"One Fish\",\"Two Fish\",\"Red Fish\","
+ "\"Blue Fish\" "
+ "baz={param1=1 param2=2} "
+ "foobar=FOO\\ BAR "
+ "barfoo=barfoo "
+ "barfoo=\"\'BAR FOO\'\"", 0, &options);
+
+ if (num_options != 5)
+ {
+ printf("FAIL (num_options=%d, expected 5)\n", num_options);
+ status ++;
+ }
+ else if ((value = cupsGetOption("foo", num_options, options)) == NULL ||
+ strcmp(value, "1234"))
+ {
+ printf("FAIL (foo=\"%s\", expected \"1234\")\n", value);
+ status ++;
+ }
+ else if ((value = cupsGetOption("bar", num_options, options)) == NULL ||
+ strcmp(value, "One Fish,Two Fish,Red Fish,Blue Fish"))
+ {
+ printf("FAIL (bar=\"%s\", expected \"One Fish,Two Fish,Red Fish,Blue "
+ "Fish\")\n", value);
+ status ++;
+ }
+ else if ((value = cupsGetOption("baz", num_options, options)) == NULL ||
+ strcmp(value, "{param1=1 param2=2}"))
+ {
+ printf("FAIL (baz=\"%s\", expected \"{param1=1 param2=2}\")\n", value);
+ status ++;
+ }
+ else if ((value = cupsGetOption("foobar", num_options, options)) == NULL ||
+ strcmp(value, "FOO BAR"))
+ {
+ printf("FAIL (foobar=\"%s\", expected \"FOO BAR\")\n", value);
+ status ++;
+ }
+ else if ((value = cupsGetOption("barfoo", num_options, options)) == NULL ||
+ strcmp(value, "\'BAR FOO\'"))
+ {
+ printf("FAIL (barfoo=\"%s\", expected \"\'BAR FOO\'\")\n", value);
+ status ++;
+ }
+ else
+ puts("PASS");
+ }
+ else
+ {
+ int i; /* Looping var */
+ cups_option_t *option; /* Current option */
+
+
+ num_options = cupsParseOptions(argv[1], 0, &options);
+
+ for (i = 0, option = options; i < num_options; i ++, option ++)
+ printf("options[%d].name=\"%s\", value=\"%s\"\n", i, option->name,
+ option->value);
+ }
+
+ exit (status);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/testppd.c b/cups/testppd.c
new file mode 100644
index 000000000..db8a38e44
--- /dev/null
+++ b/cups/testppd.c
@@ -0,0 +1,1082 @@
+/*
+ * "$Id$"
+ *
+ * PPD test program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include <sys/stat.h>
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+# include <fcntl.h>
+#endif /* WIN32 */
+
+
+/*
+ * Test data...
+ */
+
+static const char *default_code =
+ "[{\n"
+ "%%BeginFeature: *InstalledDuplexer False\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%BeginFeature: *PageRegion Letter\n"
+ "PageRegion=Letter\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%BeginFeature: *InputSlot Tray\n"
+ "InputSlot=Tray\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%BeginFeature: *MediaType Plain\n"
+ "MediaType=Plain\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%BeginFeature: *IntOption None\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%BeginFeature: *StringOption None\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n";
+
+static const char *custom_code =
+ "[{\n"
+ "%%BeginFeature: *InstalledDuplexer False\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%BeginFeature: *InputSlot Tray\n"
+ "InputSlot=Tray\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%BeginFeature: *MediaType Plain\n"
+ "MediaType=Plain\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%BeginFeature: *IntOption None\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%BeginFeature: *CustomStringOption True\n"
+ "(value\\0502\\051)\n"
+ "(value 1)\n"
+ "StringOption=Custom\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%BeginFeature: *CustomPageSize True\n"
+ "400\n"
+ "500\n"
+ "0\n"
+ "0\n"
+ "0\n"
+ "PageSize=Custom\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n";
+
+static const char *default2_code =
+ "[{\n"
+ "%%BeginFeature: *InstalledDuplexer False\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%BeginFeature: *InputSlot Tray\n"
+ "InputSlot=Tray\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%BeginFeature: *Quality Normal\n"
+ "Quality=Normal\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%BeginFeature: *IntOption None\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%BeginFeature: *StringOption None\n"
+ "%%EndFeature\n"
+ "} stopped cleartomark\n";
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ ppd_file_t *ppd; /* PPD file loaded from disk */
+ int status; /* Status of tests (0 = success, 1 = fail) */
+ int conflicts; /* Number of conflicts */
+ char *s; /* String */
+ char buffer[8192]; /* String buffer */
+ const char *text, /* Localized text */
+ *val; /* Option value */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ ppd_size_t minsize, /* Minimum size */
+ maxsize, /* Maximum size */
+ *size; /* Current size */
+ ppd_attr_t *attr; /* Current attribute */
+
+
+ status = 0;
+
+ if (argc == 1)
+ {
+ /*
+ * Setup directories for locale stuff...
+ */
+
+ if (access("locale", 0))
+ {
+ mkdir("locale", 0777);
+ mkdir("locale/fr", 0777);
+ symlink("../../../locale/cups_fr.po", "locale/fr/cups_fr.po");
+ mkdir("locale/zh_TW", 0777);
+ symlink("../../../locale/cups_zh_TW.po", "locale/zh_TW/cups_zh_TW.po");
+ }
+
+ putenv("LOCALEDIR=locale");
+ putenv("SOFTWARE=CUPS");
+
+ /*
+ * Do tests with test.ppd...
+ */
+
+ fputs("ppdOpenFile(test.ppd): ", stdout);
+
+ if ((ppd = ppdOpenFile("test.ppd")) != NULL)
+ puts("PASS");
+ else
+ {
+ ppd_status_t err; /* Last error in file */
+ int line; /* Line number in file */
+
+
+ status ++;
+ err = ppdLastError(&line);
+
+ printf("FAIL (%s on line %d)\n", ppdErrorString(err), line);
+ }
+
+ fputs("ppdFindAttr(wildcard): ", stdout);
+ if ((attr = ppdFindAttr(ppd, "cupsTest", NULL)) == NULL)
+ {
+ status ++;
+ puts("FAIL (not found)");
+ }
+ else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo"))
+ {
+ status ++;
+ printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
+ }
+ else
+ puts("PASS");
+
+ fputs("ppdFindNextAttr(wildcard): ", stdout);
+ if ((attr = ppdFindNextAttr(ppd, "cupsTest", NULL)) == NULL)
+ {
+ status ++;
+ puts("FAIL (not found)");
+ }
+ else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Bar"))
+ {
+ status ++;
+ printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
+ }
+ else
+ puts("PASS");
+
+ fputs("ppdFindAttr(Foo): ", stdout);
+ if ((attr = ppdFindAttr(ppd, "cupsTest", "Foo")) == NULL)
+ {
+ status ++;
+ puts("FAIL (not found)");
+ }
+ else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo"))
+ {
+ status ++;
+ printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
+ }
+ else
+ puts("PASS");
+
+ fputs("ppdFindNextAttr(Foo): ", stdout);
+ if ((attr = ppdFindNextAttr(ppd, "cupsTest", "Foo")) != NULL)
+ {
+ status ++;
+ printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
+ }
+ else
+ puts("PASS");
+
+ fputs("ppdMarkDefaults: ", stdout);
+ ppdMarkDefaults(ppd);
+
+ if ((conflicts = ppdConflicts(ppd)) == 0)
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (%d conflicts)\n", conflicts);
+ }
+
+ fputs("ppdEmitString (defaults): ", stdout);
+ if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
+ !strcmp(s, default_code))
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
+ (int)strlen(default_code));
+
+ if (s)
+ puts(s);
+ }
+
+ if (s)
+ free(s);
+
+ fputs("ppdEmitString (custom size and string): ", stdout);
+ ppdMarkOption(ppd, "PageSize", "Custom.400x500");
+ ppdMarkOption(ppd, "StringOption", "{String1=\"value 1\" String2=value(2)}");
+
+ if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
+ !strcmp(s, custom_code))
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
+ (int)strlen(custom_code));
+
+ if (s)
+ puts(s);
+ }
+
+ if (s)
+ free(s);
+
+ /*
+ * Test constraints...
+ */
+
+ fputs("cupsGetConflicts(InputSlot=Envelope): ", stdout);
+ ppdMarkOption(ppd, "PageSize", "Letter");
+
+ num_options = cupsGetConflicts(ppd, "InputSlot", "Envelope", &options);
+ if (num_options != 2 ||
+ (val = cupsGetOption("PageRegion", num_options, options)) == NULL ||
+ _cups_strcasecmp(val, "Letter") ||
+ (val = cupsGetOption("PageSize", num_options, options)) == NULL ||
+ _cups_strcasecmp(val, "Letter"))
+ {
+ printf("FAIL (%d options:", num_options);
+ for (i = 0; i < num_options; i ++)
+ printf(" %s=%s", options[i].name, options[i].value);
+ puts(")");
+ status ++;
+ }
+ else
+ puts("PASS");
+
+ fputs("ppdConflicts(): ", stdout);
+ ppdMarkOption(ppd, "InputSlot", "Envelope");
+
+ if ((conflicts = ppdConflicts(ppd)) == 2)
+ puts("PASS (2)");
+ else
+ {
+ printf("FAIL (%d)\n", conflicts);
+ status ++;
+ }
+
+ fputs("cupsResolveConflicts(InputSlot=Envelope): ", stdout);
+ num_options = 0;
+ options = NULL;
+ if (!cupsResolveConflicts(ppd, "InputSlot", "Envelope", &num_options,
+ &options))
+ {
+ puts("FAIL (Unable to resolve)");
+ status ++;
+ }
+ else if (num_options != 2 ||
+ !cupsGetOption("PageSize", num_options, options))
+ {
+ printf("FAIL (%d options:", num_options);
+ for (i = 0; i < num_options; i ++)
+ printf(" %s=%s", options[i].name, options[i].value);
+ puts(")");
+ status ++;
+ }
+ else
+ puts("PASS (Resolved by changing PageSize)");
+
+ cupsFreeOptions(num_options, options);
+
+ fputs("cupsResolveConflicts(No option/choice): ", stdout);
+ num_options = 0;
+ options = NULL;
+ if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) &&
+ num_options == 1 && !_cups_strcasecmp(options[0].name, "InputSlot") &&
+ !_cups_strcasecmp(options[0].value, "Tray"))
+ puts("PASS (Resolved by changing InputSlot)");
+ else if (num_options > 0)
+ {
+ printf("FAIL (%d options:", num_options);
+ for (i = 0; i < num_options; i ++)
+ printf(" %s=%s", options[i].name, options[i].value);
+ puts(")");
+ status ++;
+ }
+ else
+ {
+ puts("FAIL (Unable to resolve)");
+ status ++;
+ }
+ cupsFreeOptions(num_options, options);
+
+ fputs("ppdInstallableConflict(): ", stdout);
+ if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") &&
+ !ppdInstallableConflict(ppd, "Duplex", "None"))
+ puts("PASS");
+ else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble"))
+ {
+ puts("FAIL (Duplex=DuplexNoTumble did not conflict)");
+ status ++;
+ }
+ else
+ {
+ puts("FAIL (Duplex=None conflicted)");
+ status ++;
+ }
+
+ /*
+ * ppdPageSizeLimits
+ */
+
+ fputs("ppdPageSizeLimits: ", stdout);
+ if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+ {
+ if (minsize.width != 36 || minsize.length != 36 ||
+ maxsize.width != 1080 || maxsize.length != 86400)
+ {
+ printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+ "expected min=36x36, max=1080x86400)\n", minsize.width,
+ minsize.length, maxsize.width, maxsize.length);
+ status ++;
+ }
+ else
+ puts("PASS");
+ }
+ else
+ {
+ puts("FAIL (returned 0)");
+ status ++;
+ }
+
+ /*
+ * cupsMarkOptions with PWG and IPP size names.
+ */
+
+ fputs("cupsMarkOptions(media=iso-a4): ", stdout);
+ num_options = cupsAddOption("media", "iso-a4", 0, &options);
+ cupsMarkOptions(ppd, num_options, options);
+ cupsFreeOptions(num_options, options);
+
+ size = ppdPageSize(ppd, NULL);
+ if (!size || strcmp(size->name, "A4"))
+ {
+ printf("FAIL (%s)\n", size ? size->name : "unknown");
+ status ++;
+ }
+ else
+ puts("PASS");
+
+ fputs("cupsMarkOptions(media=na_letter_8.5x11in): ", stdout);
+ num_options = cupsAddOption("media", "na_letter_8.5x11in", 0, &options);
+ cupsMarkOptions(ppd, num_options, options);
+ cupsFreeOptions(num_options, options);
+
+ size = ppdPageSize(ppd, NULL);
+ if (!size || strcmp(size->name, "Letter"))
+ {
+ printf("FAIL (%s)\n", size ? size->name : "unknown");
+ status ++;
+ }
+ else
+ puts("PASS");
+
+ fputs("cupsMarkOptions(media=oe_letter-fullbleed_8.5x11in): ", stdout);
+ num_options = cupsAddOption("media", "oe_letter-fullbleed_8.5x11in", 0,
+ &options);
+ cupsMarkOptions(ppd, num_options, options);
+ cupsFreeOptions(num_options, options);
+
+ size = ppdPageSize(ppd, NULL);
+ if (!size || strcmp(size->name, "Letter.Fullbleed"))
+ {
+ printf("FAIL (%s)\n", size ? size->name : "unknown");
+ status ++;
+ }
+ else
+ puts("PASS");
+
+ fputs("cupsMarkOptions(media=A4): ", stdout);
+ num_options = cupsAddOption("media", "A4", 0, &options);
+ cupsMarkOptions(ppd, num_options, options);
+ cupsFreeOptions(num_options, options);
+
+ size = ppdPageSize(ppd, NULL);
+ if (!size || strcmp(size->name, "A4"))
+ {
+ printf("FAIL (%s)\n", size ? size->name : "unknown");
+ status ++;
+ }
+ else
+ puts("PASS");
+
+ /*
+ * Test localization...
+ */
+
+ fputs("ppdLocalizeIPPReason(text): ", stdout);
+ if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
+ !strcmp(buffer, "Foo Reason"))
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (\"%s\" instead of \"Foo Reason\")\n", buffer);
+ }
+
+ fputs("ppdLocalizeIPPReason(http): ", stdout);
+ if (ppdLocalizeIPPReason(ppd, "foo", "http", buffer, sizeof(buffer)) &&
+ !strcmp(buffer, "http://foo/bar.html"))
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (\"%s\" instead of \"http://foo/bar.html\")\n", buffer);
+ }
+
+ fputs("ppdLocalizeIPPReason(help): ", stdout);
+ if (ppdLocalizeIPPReason(ppd, "foo", "help", buffer, sizeof(buffer)) &&
+ !strcmp(buffer, "help:anchor='foo'%20bookID=Vendor%20Help"))
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (\"%s\" instead of \"help:anchor='foo'%%20bookID=Vendor%%20Help\")\n", buffer);
+ }
+
+ fputs("ppdLocalizeIPPReason(file): ", stdout);
+ if (ppdLocalizeIPPReason(ppd, "foo", "file", buffer, sizeof(buffer)) &&
+ !strcmp(buffer, "/help/foo/bar.html"))
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (\"%s\" instead of \"/help/foo/bar.html\")\n", buffer);
+ }
+
+ putenv("LANG=fr");
+ putenv("LC_ALL=fr");
+ putenv("LC_CTYPE=fr");
+ putenv("LC_MESSAGES=fr");
+
+ fputs("ppdLocalizeIPPReason(fr text): ", stdout);
+ if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
+ !strcmp(buffer, "La Long Foo Reason"))
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (\"%s\" instead of \"La Long Foo Reason\")\n", buffer);
+ }
+
+ putenv("LANG=zh_TW");
+ putenv("LC_ALL=zh_TW");
+ putenv("LC_CTYPE=zh_TW");
+ putenv("LC_MESSAGES=zh_TW");
+
+ fputs("ppdLocalizeIPPReason(zh_TW text): ", stdout);
+ if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
+ !strcmp(buffer, "Number 1 Foo Reason"))
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (\"%s\" instead of \"Number 1 Foo Reason\")\n", buffer);
+ }
+
+ /*
+ * cupsMarkerName localization...
+ */
+
+ putenv("LANG=en");
+ putenv("LC_ALL=en");
+ putenv("LC_CTYPE=en");
+ putenv("LC_MESSAGES=en");
+
+ fputs("ppdLocalizeMarkerName(bogus): ", stdout);
+
+ if ((text = ppdLocalizeMarkerName(ppd, "bogus")) != NULL)
+ {
+ status ++;
+ printf("FAIL (\"%s\" instead of NULL)\n", text);
+ }
+ else
+ puts("PASS");
+
+ fputs("ppdLocalizeMarkerName(cyan): ", stdout);
+
+ if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
+ !strcmp(text, "Cyan Toner"))
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (\"%s\" instead of \"Cyan Toner\")\n",
+ text ? text : "(null)");
+ }
+
+ putenv("LANG=fr");
+ putenv("LC_ALL=fr");
+ putenv("LC_CTYPE=fr");
+ putenv("LC_MESSAGES=fr");
+
+ fputs("ppdLocalizeMarkerName(fr cyan): ", stdout);
+ if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
+ !strcmp(text, "La Toner Cyan"))
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (\"%s\" instead of \"La Toner Cyan\")\n",
+ text ? text : "(null)");
+ }
+
+ putenv("LANG=zh_TW");
+ putenv("LC_ALL=zh_TW");
+ putenv("LC_CTYPE=zh_TW");
+ putenv("LC_MESSAGES=zh_TW");
+
+ fputs("ppdLocalizeMarkerName(zh_TW cyan): ", stdout);
+ if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
+ !strcmp(text, "Number 1 Cyan Toner"))
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (\"%s\" instead of \"Number 1 Cyan Toner\")\n",
+ text ? text : "(null)");
+ }
+
+ ppdClose(ppd);
+
+ /*
+ * Test new constraints...
+ */
+
+ fputs("ppdOpenFile(test2.ppd): ", stdout);
+
+ if ((ppd = ppdOpenFile("test2.ppd")) != NULL)
+ puts("PASS");
+ else
+ {
+ ppd_status_t err; /* Last error in file */
+ int line; /* Line number in file */
+
+
+ status ++;
+ err = ppdLastError(&line);
+
+ printf("FAIL (%s on line %d)\n", ppdErrorString(err), line);
+ }
+
+ fputs("ppdMarkDefaults: ", stdout);
+ ppdMarkDefaults(ppd);
+
+ if ((conflicts = ppdConflicts(ppd)) == 0)
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (%d conflicts)\n", conflicts);
+ }
+
+ fputs("ppdEmitString (defaults): ", stdout);
+ if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
+ !strcmp(s, default2_code))
+ puts("PASS");
+ else
+ {
+ status ++;
+ printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
+ (int)strlen(default2_code));
+
+ if (s)
+ puts(s);
+ }
+
+ if (s)
+ free(s);
+
+ fputs("ppdConflicts(): ", stdout);
+ ppdMarkOption(ppd, "PageSize", "Env10");
+ ppdMarkOption(ppd, "InputSlot", "Envelope");
+ ppdMarkOption(ppd, "Quality", "Photo");
+
+ if ((conflicts = ppdConflicts(ppd)) == 1)
+ puts("PASS (1)");
+ else
+ {
+ printf("FAIL (%d)\n", conflicts);
+ status ++;
+ }
+
+ fputs("cupsResolveConflicts(Quality=Photo): ", stdout);
+ num_options = 0;
+ options = NULL;
+ if (cupsResolveConflicts(ppd, "Quality", "Photo", &num_options,
+ &options))
+ {
+ printf("FAIL (%d options:", num_options);
+ for (i = 0; i < num_options; i ++)
+ printf(" %s=%s", options[i].name, options[i].value);
+ puts(")");
+ status ++;
+ }
+ else
+ puts("PASS (Unable to resolve)");
+ cupsFreeOptions(num_options, options);
+
+ fputs("cupsResolveConflicts(No option/choice): ", stdout);
+ num_options = 0;
+ options = NULL;
+ if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) &&
+ num_options == 1 && !_cups_strcasecmp(options->name, "Quality") &&
+ !_cups_strcasecmp(options->value, "Normal"))
+ puts("PASS");
+ else if (num_options > 0)
+ {
+ printf("FAIL (%d options:", num_options);
+ for (i = 0; i < num_options; i ++)
+ printf(" %s=%s", options[i].name, options[i].value);
+ puts(")");
+ status ++;
+ }
+ else
+ {
+ puts("FAIL (Unable to resolve!)");
+ status ++;
+ }
+ cupsFreeOptions(num_options, options);
+
+ fputs("cupsResolveConflicts(loop test): ", stdout);
+ ppdMarkOption(ppd, "PageSize", "A4");
+ ppdMarkOption(ppd, "InputSlot", "Tray");
+ ppdMarkOption(ppd, "Quality", "Photo");
+ num_options = 0;
+ options = NULL;
+ if (!cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options))
+ puts("PASS");
+ else if (num_options > 0)
+ {
+ printf("FAIL (%d options:", num_options);
+ for (i = 0; i < num_options; i ++)
+ printf(" %s=%s", options[i].name, options[i].value);
+ puts(")");
+ }
+ else
+ puts("FAIL (No conflicts!)");
+
+ fputs("ppdInstallableConflict(): ", stdout);
+ if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") &&
+ !ppdInstallableConflict(ppd, "Duplex", "None"))
+ puts("PASS");
+ else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble"))
+ {
+ puts("FAIL (Duplex=DuplexNoTumble did not conflict)");
+ status ++;
+ }
+ else
+ {
+ puts("FAIL (Duplex=None conflicted)");
+ status ++;
+ }
+
+ /*
+ * ppdPageSizeLimits
+ */
+
+ ppdMarkDefaults(ppd);
+
+ fputs("ppdPageSizeLimits(default): ", stdout);
+ if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+ {
+ if (minsize.width != 36 || minsize.length != 36 ||
+ maxsize.width != 1080 || maxsize.length != 86400)
+ {
+ printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+ "expected min=36x36, max=1080x86400)\n", minsize.width,
+ minsize.length, maxsize.width, maxsize.length);
+ status ++;
+ }
+ else
+ puts("PASS");
+ }
+ else
+ {
+ puts("FAIL (returned 0)");
+ status ++;
+ }
+
+ ppdMarkOption(ppd, "InputSlot", "Manual");
+
+ fputs("ppdPageSizeLimits(InputSlot=Manual): ", stdout);
+ if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+ {
+ if (minsize.width != 100 || minsize.length != 100 ||
+ maxsize.width != 1000 || maxsize.length != 1000)
+ {
+ printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+ "expected min=100x100, max=1000x1000)\n", minsize.width,
+ minsize.length, maxsize.width, maxsize.length);
+ status ++;
+ }
+ else
+ puts("PASS");
+ }
+ else
+ {
+ puts("FAIL (returned 0)");
+ status ++;
+ }
+
+ ppdMarkOption(ppd, "Quality", "Photo");
+
+ fputs("ppdPageSizeLimits(Quality=Photo): ", stdout);
+ if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+ {
+ if (minsize.width != 200 || minsize.length != 200 ||
+ maxsize.width != 1000 || maxsize.length != 1000)
+ {
+ printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+ "expected min=200x200, max=1000x1000)\n", minsize.width,
+ minsize.length, maxsize.width, maxsize.length);
+ status ++;
+ }
+ else
+ puts("PASS");
+ }
+ else
+ {
+ puts("FAIL (returned 0)");
+ status ++;
+ }
+
+ ppdMarkOption(ppd, "InputSlot", "Tray");
+
+ fputs("ppdPageSizeLimits(Quality=Photo): ", stdout);
+ if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+ {
+ if (minsize.width != 300 || minsize.length != 300 ||
+ maxsize.width != 1080 || maxsize.length != 86400)
+ {
+ printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+ "expected min=300x300, max=1080x86400)\n", minsize.width,
+ minsize.length, maxsize.width, maxsize.length);
+ status ++;
+ }
+ else
+ puts("PASS");
+ }
+ else
+ {
+ puts("FAIL (returned 0)");
+ status ++;
+ }
+ }
+ else
+ {
+ const char *filename; /* PPD filename */
+ struct stat fileinfo; /* File information */
+
+
+ if (!strncmp(argv[1], "-d", 2))
+ {
+ const char *printer; /* Printer name */
+
+ if (argv[1][2])
+ printer = argv[1] + 2;
+ else if (argv[2])
+ printer = argv[2];
+ else
+ {
+ puts("Usage: ./testppd -d printer");
+ return (1);
+ }
+
+ filename = cupsGetPPD(printer);
+
+ if (!filename)
+ {
+ printf("%s: %s\n", printer, cupsLastErrorString());
+ return (1);
+ }
+ }
+ else
+ filename = argv[1];
+
+ if (lstat(filename, &fileinfo))
+ {
+ printf("%s: %s\n", filename, strerror(errno));
+ return (1);
+ }
+
+ if (S_ISLNK(fileinfo.st_mode))
+ {
+ char realfile[1024]; /* Real file path */
+ ssize_t realsize; /* Size of real file path */
+
+
+ if ((realsize = readlink(filename, realfile, sizeof(realfile) - 1)) < 0)
+ strcpy(realfile, "Unknown");
+ else
+ realfile[realsize] = '\0';
+
+ if (stat(realfile, &fileinfo))
+ printf("%s: symlink to \"%s\", %s\n", filename, realfile,
+ strerror(errno));
+ else
+ printf("%s: symlink to \"%s\", %ld bytes\n", filename, realfile,
+ (long)fileinfo.st_size);
+ }
+ else
+ printf("%s: regular file, %ld bytes\n", filename, (long)fileinfo.st_size);
+
+ if ((ppd = ppdOpenFile(filename)) == NULL)
+ {
+ ppd_status_t err; /* Last error in file */
+ int line; /* Line number in file */
+
+
+ status ++;
+ err = ppdLastError(&line);
+
+ printf("%s: %s on line %d\n", argv[1], ppdErrorString(err), line);
+ }
+ else
+ {
+ int j, k; /* Looping vars */
+ ppd_group_t *group; /* Option group */
+ ppd_option_t *option; /* Option */
+ ppd_coption_t *coption; /* Custom option */
+ ppd_cparam_t *cparam; /* Custom parameter */
+ ppd_const_t *c; /* UIConstraints */
+ char lang[255], /* LANG environment variable */
+ lc_all[255], /* LC_ALL environment variable */
+ lc_ctype[255], /* LC_CTYPE environment variable */
+ lc_messages[255];/* LC_MESSAGES environment variable */
+
+
+ if (argc > 2)
+ {
+ snprintf(lang, sizeof(lang), "LANG=%s", argv[2]);
+ putenv(lang);
+ snprintf(lc_all, sizeof(lc_all), "LC_ALL=%s", argv[2]);
+ putenv(lc_all);
+ snprintf(lc_ctype, sizeof(lc_ctype), "LC_CTYPE=%s", argv[2]);
+ putenv(lc_ctype);
+ snprintf(lc_messages, sizeof(lc_messages), "LC_MESSAGES=%s", argv[2]);
+ putenv(lc_messages);
+ }
+
+ ppdLocalize(ppd);
+ ppdMarkDefaults(ppd);
+
+ if (argc > 3)
+ {
+ text = ppdLocalizeIPPReason(ppd, argv[3], NULL, buffer, sizeof(buffer));
+ printf("ppdLocalizeIPPReason(%s)=%s\n", argv[3],
+ text ? text : "(null)");
+ return (text == NULL);
+ }
+
+ for (i = ppd->num_groups, group = ppd->groups;
+ i > 0;
+ i --, group ++)
+ {
+ printf("%s (%s):\n", group->name, group->text);
+
+ for (j = group->num_options, option = group->options;
+ j > 0;
+ j --, option ++)
+ {
+ printf(" %s (%s):\n", option->keyword, option->text);
+
+ for (k = 0; k < option->num_choices; k ++)
+ printf(" - %s%s (%s)\n",
+ option->choices[k].marked ? "*" : "",
+ option->choices[k].choice, option->choices[k].text);
+
+ if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
+ {
+ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+ cparam;
+ cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
+ {
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_CURVE :
+ printf(" %s(%s): PPD_CUSTOM_CURVE (%g to %g)\n",
+ cparam->name, cparam->text,
+ cparam->minimum.custom_curve,
+ cparam->maximum.custom_curve);
+ break;
+
+ case PPD_CUSTOM_INT :
+ printf(" %s(%s): PPD_CUSTOM_INT (%d to %d)\n",
+ cparam->name, cparam->text,
+ cparam->minimum.custom_int,
+ cparam->maximum.custom_int);
+ break;
+
+ case PPD_CUSTOM_INVCURVE :
+ printf(" %s(%s): PPD_CUSTOM_INVCURVE (%g to %g)\n",
+ cparam->name, cparam->text,
+ cparam->minimum.custom_invcurve,
+ cparam->maximum.custom_invcurve);
+ break;
+
+ case PPD_CUSTOM_PASSCODE :
+ printf(" %s(%s): PPD_CUSTOM_PASSCODE (%d to %d)\n",
+ cparam->name, cparam->text,
+ cparam->minimum.custom_passcode,
+ cparam->maximum.custom_passcode);
+ break;
+
+ case PPD_CUSTOM_PASSWORD :
+ printf(" %s(%s): PPD_CUSTOM_PASSWORD (%d to %d)\n",
+ cparam->name, cparam->text,
+ cparam->minimum.custom_password,
+ cparam->maximum.custom_password);
+ break;
+
+ case PPD_CUSTOM_POINTS :
+ printf(" %s(%s): PPD_CUSTOM_POINTS (%g to %g)\n",
+ cparam->name, cparam->text,
+ cparam->minimum.custom_points,
+ cparam->maximum.custom_points);
+ break;
+
+ case PPD_CUSTOM_REAL :
+ printf(" %s(%s): PPD_CUSTOM_REAL (%g to %g)\n",
+ cparam->name, cparam->text,
+ cparam->minimum.custom_real,
+ cparam->maximum.custom_real);
+ break;
+
+ case PPD_CUSTOM_STRING :
+ printf(" %s(%s): PPD_CUSTOM_STRING (%d to %d)\n",
+ cparam->name, cparam->text,
+ cparam->minimum.custom_string,
+ cparam->maximum.custom_string);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ puts("\nSizes:");
+ for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
+ printf(" %s = %gx%g, [%g %g %g %g]\n", size->name, size->width,
+ size->length, size->left, size->bottom, size->right, size->top);
+
+ puts("\nConstraints:");
+
+ for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
+ printf(" *UIConstraints: *%s %s *%s %s\n", c->option1, c->choice1,
+ c->option2, c->choice2);
+ if (ppd->num_consts == 0)
+ puts(" NO CONSTRAINTS");
+
+ puts("\nFilters:");
+
+ for (i = 0; i < ppd->num_filters; i ++)
+ printf(" %s\n", ppd->filters[i]);
+
+ if (ppd->num_filters == 0)
+ puts(" NO FILTERS");
+
+ puts("\nAttributes:");
+
+ for (attr = (ppd_attr_t *)cupsArrayFirst(ppd->sorted_attrs);
+ attr;
+ attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs))
+ printf(" *%s %s/%s: \"%s\"\n", attr->name, attr->spec,
+ attr->text, attr->value ? attr->value : "");
+ }
+
+ if (!strncmp(argv[1], "-d", 2))
+ unlink(filename);
+ }
+
+#ifdef __APPLE__
+ if (getenv("MallocStackLogging") && getenv("MallocStackLoggingNoCompact"))
+ {
+ char command[1024]; /* malloc_history command */
+
+ snprintf(command, sizeof(command), "malloc_history %d -all_by_size",
+ getpid());
+ fflush(stdout);
+ system(command);
+ }
+#endif /* __APPLE__ */
+
+ ppdClose(ppd);
+
+ return (status);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/testpwg.c b/cups/testpwg.c
new file mode 100644
index 000000000..756baf0d8
--- /dev/null
+++ b/cups/testpwg.c
@@ -0,0 +1,497 @@
+/*
+ * "$Id$"
+ *
+ * PWG test program for CUPS.
+ *
+ * Copyright 2009-2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry.
+ * test_pagesize() - Test the PWG mapping functions.
+ * test_ppd_cache() - Test the PPD cache functions.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "ppd-private.h"
+#include "file-private.h"
+
+
+/*
+ * Local functions...
+ */
+
+static int test_pagesize(_ppd_cache_t *pc, ppd_file_t *ppd,
+ const char *ppdsize);
+static int test_ppd_cache(_ppd_cache_t *pc, ppd_file_t *ppd);
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int status; /* Status of tests (0 = success, 1 = fail) */
+ const char *ppdfile; /* PPD filename */
+ ppd_file_t *ppd; /* PPD file */
+ _ppd_cache_t *pc; /* PPD cache and PWG mapping data */
+ _pwg_media_t *pwgmedia; /* PWG media size */
+
+
+ status = 0;
+
+ if (argc < 2 || argc > 3)
+ {
+ puts("Usage: ./testpwg filename.ppd [jobfile]");
+ return (1);
+ }
+
+ ppdfile = argv[1];
+
+ printf("ppdOpenFile(%s): ", ppdfile);
+ if ((ppd = ppdOpenFile(ppdfile)) == NULL)
+ {
+ ppd_status_t err; /* Last error in file */
+ int line; /* Line number in file */
+
+
+ err = ppdLastError(&line);
+
+ printf("FAIL (%s on line %d)\n", ppdErrorString(err), line);
+
+ return (1);
+ }
+ else
+ puts("PASS");
+
+ fputs("_ppdCacheCreateWithPPD(ppd): ", stdout);
+ if ((pc = _ppdCacheCreateWithPPD(ppd)) == NULL)
+ {
+ puts("FAIL");
+ status ++;
+ }
+ else
+ {
+ puts("PASS");
+ status += test_ppd_cache(pc, ppd);
+
+ if (argc == 3)
+ {
+ /*
+ * Test PageSize mapping code.
+ */
+
+ int fd; /* Job file descriptor */
+ const char *pagesize; /* PageSize value */
+ ipp_t *job; /* Job attributes */
+ ipp_attribute_t *media; /* Media attribute */
+
+ if ((fd = open(argv[2], O_RDONLY)) >= 0)
+ {
+ job = ippNew();
+ ippReadFile(fd, job);
+ close(fd);
+
+ if ((media = ippFindAttribute(job, "media", IPP_TAG_ZERO)) != NULL &&
+ media->value_tag != IPP_TAG_NAME &&
+ media->value_tag != IPP_TAG_KEYWORD)
+ media = NULL;
+
+ if (media)
+ printf("_ppdCacheGetPageSize(media=%s): ",
+ media->values[0].string.text);
+ else
+ fputs("_ppdCacheGetPageSize(media-col): ", stdout);
+
+ fflush(stdout);
+
+ if ((pagesize = _ppdCacheGetPageSize(pc, job, NULL, NULL)) == NULL)
+ {
+ puts("FAIL (Not Found)");
+ status = 1;
+ }
+ else if (media && _cups_strcasecmp(pagesize, media->values[0].string.text))
+ {
+ printf("FAIL (Got \"%s\", Expected \"%s\")\n", pagesize,
+ media->values[0].string.text);
+ status = 1;
+ }
+ else
+ printf("PASS (%s)\n", pagesize);
+
+ ippDelete(job);
+ }
+ else
+ {
+ perror(argv[2]);
+ status = 1;
+ }
+ }
+
+ /*
+ * _ppdCacheDestroy should never fail...
+ */
+
+ fputs("_ppdCacheDestroy(pc): ", stdout);
+ _ppdCacheDestroy(pc);
+ puts("PASS");
+ }
+
+ fputs("_pwgMediaForPWG(\"iso_a4_210x297mm\"): ", stdout);
+ if ((pwgmedia = _pwgMediaForPWG("iso_a4_210x297mm")) == NULL)
+ {
+ puts("FAIL (not found)");
+ status ++;
+ }
+ else if (strcmp(pwgmedia->pwg, "iso_a4_210x297mm"))
+ {
+ printf("FAIL (%s)\n", pwgmedia->pwg);
+ status ++;
+ }
+ else if (pwgmedia->width != 21000 || pwgmedia->length != 29700)
+ {
+ printf("FAIL (%dx%d)\n", pwgmedia->width, pwgmedia->length);
+ status ++;
+ }
+ else
+ puts("PASS");
+
+ fputs("_pwgMediaForLegacy(\"na-letter\"): ", stdout);
+ if ((pwgmedia = _pwgMediaForLegacy("na-letter")) == NULL)
+ {
+ puts("FAIL (not found)");
+ status ++;
+ }
+ else if (strcmp(pwgmedia->pwg, "na_letter_8.5x11in"))
+ {
+ printf("FAIL (%s)\n", pwgmedia->pwg);
+ status ++;
+ }
+ else if (pwgmedia->width != 21590 || pwgmedia->length != 27940)
+ {
+ printf("FAIL (%dx%d)\n", pwgmedia->width, pwgmedia->length);
+ status ++;
+ }
+ else
+ puts("PASS");
+
+ fputs("_pwgMediaForPPD(\"4x6\"): ", stdout);
+ if ((pwgmedia = _pwgMediaForPPD("4x6")) == NULL)
+ {
+ puts("FAIL (not found)");
+ status ++;
+ }
+ else if (strcmp(pwgmedia->pwg, "na_index-4x6_4x6in"))
+ {
+ printf("FAIL (%s)\n", pwgmedia->pwg);
+ status ++;
+ }
+ else if (pwgmedia->width != 10160 || pwgmedia->length != 15240)
+ {
+ printf("FAIL (%dx%d)\n", pwgmedia->width, pwgmedia->length);
+ status ++;
+ }
+ else
+ puts("PASS");
+
+ fputs("_pwgMediaForPPD(\"10x15cm\"): ", stdout);
+ if ((pwgmedia = _pwgMediaForPPD("10x15cm")) == NULL)
+ {
+ puts("FAIL (not found)");
+ status ++;
+ }
+ else if (strcmp(pwgmedia->pwg, "om_100x150mm_100x150mm"))
+ {
+ printf("FAIL (%s)\n", pwgmedia->pwg);
+ status ++;
+ }
+ else if (pwgmedia->width != 10000 || pwgmedia->length != 15000)
+ {
+ printf("FAIL (%dx%d)\n", pwgmedia->width, pwgmedia->length);
+ status ++;
+ }
+ else
+ puts("PASS");
+
+ fputs("_pwgMediaForPPD(\"Custom.10x15cm\"): ", stdout);
+ if ((pwgmedia = _pwgMediaForPPD("Custom.10x15cm")) == NULL)
+ {
+ puts("FAIL (not found)");
+ status ++;
+ }
+ else if (strcmp(pwgmedia->pwg, "custom_10x15cm_100x150mm"))
+ {
+ printf("FAIL (%s)\n", pwgmedia->pwg);
+ status ++;
+ }
+ else if (pwgmedia->width != 10000 || pwgmedia->length != 15000)
+ {
+ printf("FAIL (%dx%d)\n", pwgmedia->width, pwgmedia->length);
+ status ++;
+ }
+ else
+ puts("PASS");
+
+ fputs("_pwgMediaForSize(29700, 42000): ", stdout);
+ if ((pwgmedia = _pwgMediaForSize(29700, 42000)) == NULL)
+ {
+ puts("FAIL (not found)");
+ status ++;
+ }
+ else if (strcmp(pwgmedia->pwg, "iso_a3_297x420mm"))
+ {
+ printf("FAIL (%s)\n", pwgmedia->pwg);
+ status ++;
+ }
+ else
+ puts("PASS");
+
+ return (status);
+}
+
+
+/*
+ * 'test_pagesize()' - Test the PWG mapping functions.
+ */
+
+static int /* O - 1 on failure, 0 on success */
+test_pagesize(_ppd_cache_t *pc, /* I - PWG mapping data */
+ ppd_file_t *ppd, /* I - PPD file */
+ const char *ppdsize) /* I - PPD page size */
+{
+ int status = 0; /* Return status */
+ ipp_t *job; /* Job attributes */
+ const char *pagesize; /* PageSize value */
+
+
+ if (ppdPageSize(ppd, ppdsize))
+ {
+ printf("_ppdCacheGetPageSize(keyword=%s): ", ppdsize);
+ fflush(stdout);
+
+ if ((pagesize = _ppdCacheGetPageSize(pc, NULL, ppdsize, NULL)) == NULL)
+ {
+ puts("FAIL (Not Found)");
+ status = 1;
+ }
+ else if (_cups_strcasecmp(pagesize, ppdsize))
+ {
+ printf("FAIL (Got \"%s\", Expected \"%s\")\n", pagesize, ppdsize);
+ status = 1;
+ }
+ else
+ puts("PASS");
+
+ job = ippNew();
+ ippAddString(job, IPP_TAG_JOB, IPP_TAG_KEYWORD, "media", NULL, ppdsize);
+
+ printf("_ppdCacheGetPageSize(media=%s): ", ppdsize);
+ fflush(stdout);
+
+ if ((pagesize = _ppdCacheGetPageSize(pc, job, NULL, NULL)) == NULL)
+ {
+ puts("FAIL (Not Found)");
+ status = 1;
+ }
+ else if (_cups_strcasecmp(pagesize, ppdsize))
+ {
+ printf("FAIL (Got \"%s\", Expected \"%s\")\n", pagesize, ppdsize);
+ status = 1;
+ }
+ else
+ puts("PASS");
+
+ ippDelete(job);
+ }
+
+ return (status);
+}
+
+
+/*
+ * 'test_ppd_cache()' - Test the PPD cache functions.
+ */
+
+static int /* O - 1 on failure, 0 on success */
+test_ppd_cache(_ppd_cache_t *pc, /* I - PWG mapping data */
+ ppd_file_t *ppd) /* I - PPD file */
+{
+ int i, /* Looping var */
+ status = 0; /* Return status */
+ _ppd_cache_t *pc2; /* Loaded data */
+ _pwg_size_t *size, /* Size from original */
+ *size2; /* Size from saved */
+ _pwg_map_t *map, /* Map from original */
+ *map2; /* Map from saved */
+
+
+ /*
+ * Verify that we can write and read back the same data...
+ */
+
+ fputs("_ppdCacheWriteFile(test.pwg): ", stdout);
+ if (!_ppdCacheWriteFile(pc, "test.pwg", NULL))
+ {
+ puts("FAIL");
+ status ++;
+ }
+ else
+ puts("PASS");
+
+ fputs("_ppdCacheCreateWithFile(test.pwg): ", stdout);
+ if ((pc2 = _ppdCacheCreateWithFile("test.pwg", NULL)) == NULL)
+ {
+ puts("FAIL");
+ status ++;
+ }
+ else
+ {
+ // TODO: FINISH ADDING ALL VALUES IN STRUCTURE
+ if (pc2->num_sizes != pc->num_sizes)
+ {
+ if (!status)
+ puts("FAIL");
+
+ printf(" SAVED num_sizes=%d, ORIG num_sizes=%d\n", pc2->num_sizes,
+ pc->num_sizes);
+
+ status ++;
+ }
+ else
+ {
+ for (i = pc->num_sizes, size = pc->sizes, size2 = pc2->sizes;
+ i > 0;
+ i --, size ++, size2 ++)
+ {
+ if (strcmp(size2->map.pwg, size->map.pwg) ||
+ strcmp(size2->map.ppd, size->map.ppd) ||
+ size2->width != size->width ||
+ size2->length != size->length ||
+ size2->left != size->left ||
+ size2->bottom != size->bottom ||
+ size2->right != size->right ||
+ size2->top != size->top)
+ {
+ if (!status)
+ puts("FAIL");
+
+ if (strcmp(size->map.pwg, size2->map.pwg))
+ printf(" SAVED size->map.pwg=\"%s\", ORIG "
+ "size->map.pwg=\"%s\"\n", size2->map.pwg, size->map.pwg);
+
+ if (strcmp(size2->map.ppd, size->map.ppd))
+ printf(" SAVED size->map.ppd=\"%s\", ORIG "
+ "size->map.ppd=\"%s\"\n", size2->map.ppd, size->map.ppd);
+
+ if (size2->width != size->width)
+ printf(" SAVED size->width=%d, ORIG size->width=%d\n",
+ size2->width, size->width);
+
+ if (size2->length != size->length)
+ printf(" SAVED size->length=%d, ORIG size->length=%d\n",
+ size2->length, size->length);
+
+ if (size2->left != size->left)
+ printf(" SAVED size->left=%d, ORIG size->left=%d\n",
+ size2->left, size->left);
+
+ if (size2->bottom != size->bottom)
+ printf(" SAVED size->bottom=%d, ORIG size->bottom=%d\n",
+ size2->bottom, size->bottom);
+
+ if (size2->right != size->right)
+ printf(" SAVED size->right=%d, ORIG size->right=%d\n",
+ size2->right, size->right);
+
+ if (size2->top != size->top)
+ printf(" SAVED size->top=%d, ORIG size->top=%d\n",
+ size2->top, size->top);
+
+ status ++;
+ break;
+ }
+ }
+
+ for (i = pc->num_sources, map = pc->sources, map2 = pc2->sources;
+ i > 0;
+ i --, map ++, map2 ++)
+ {
+ if (strcmp(map2->pwg, map->pwg) ||
+ strcmp(map2->ppd, map->ppd))
+ {
+ if (!status)
+ puts("FAIL");
+
+ if (strcmp(map->pwg, map2->pwg))
+ printf(" SAVED source->pwg=\"%s\", ORIG source->pwg=\"%s\"\n",
+ map2->pwg, map->pwg);
+
+ if (strcmp(map2->ppd, map->ppd))
+ printf(" SAVED source->ppd=\"%s\", ORIG source->ppd=\"%s\"\n",
+ map2->ppd, map->ppd);
+
+ status ++;
+ break;
+ }
+ }
+
+ for (i = pc->num_types, map = pc->types, map2 = pc2->types;
+ i > 0;
+ i --, map ++, map2 ++)
+ {
+ if (strcmp(map2->pwg, map->pwg) ||
+ strcmp(map2->ppd, map->ppd))
+ {
+ if (!status)
+ puts("FAIL");
+
+ if (strcmp(map->pwg, map2->pwg))
+ printf(" SAVED type->pwg=\"%s\", ORIG type->pwg=\"%s\"\n",
+ map2->pwg, map->pwg);
+
+ if (strcmp(map2->ppd, map->ppd))
+ printf(" SAVED type->ppd=\"%s\", ORIG type->ppd=\"%s\"\n",
+ map2->ppd, map->ppd);
+
+ status ++;
+ break;
+ }
+ }
+ }
+
+ if (!status)
+ puts("PASS");
+
+ _ppdCacheDestroy(pc2);
+ }
+
+ /*
+ * Test PageSize mapping code...
+ */
+
+ status += test_pagesize(pc, ppd, "Letter");
+ status += test_pagesize(pc, ppd, "na-letter");
+ status += test_pagesize(pc, ppd, "A4");
+ status += test_pagesize(pc, ppd, "iso-a4");
+
+ return (status);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/testsnmp.c b/cups/testsnmp.c
new file mode 100644
index 000000000..3a3eb9f70
--- /dev/null
+++ b/cups/testsnmp.c
@@ -0,0 +1,304 @@
+/*
+ * "$Id$"
+ *
+ * SNMP test program for CUPS.
+ *
+ * Copyright 2008-2010 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry.
+ * scan_oid() - Scan an OID value.
+ * show_oid() - Show the specified OID.
+ * usage() - Show program usage and exit.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include "snmp-private.h"
+
+
+/*
+ * Local functions...
+ */
+
+static void print_packet(cups_snmp_t *packet, void *data);
+static int show_oid(int fd, const char *community,
+ http_addr_t *addr, const char *s, int walk);
+static void usage(void);
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ int fd = -1; /* SNMP socket */
+ http_addrlist_t *host = NULL; /* Address of host */
+ int walk = 0; /* Walk OIDs? */
+ char *oid = NULL; /* Last OID shown */
+ const char *community; /* Community name */
+
+
+ fputs("_cupsSNMPDefaultCommunity: ", stdout);
+
+ if ((community = _cupsSNMPDefaultCommunity()) == NULL)
+ {
+ puts("FAIL (NULL community name)");
+ return (1);
+ }
+
+ printf("PASS (%s)\n", community);
+
+ /*
+ * Query OIDs from the command-line...
+ */
+
+ for (i = 1; i < argc; i ++)
+ if (!strcmp(argv[i], "-c"))
+ {
+ i ++;
+
+ if (i >= argc)
+ usage();
+ else
+ community = argv[i];
+ }
+ else if (!strcmp(argv[i], "-d"))
+ _cupsSNMPSetDebug(10);
+ else if (!strcmp(argv[i], "-w"))
+ walk = 1;
+ else if (!host)
+ {
+ if ((host = httpAddrGetList(argv[i], AF_UNSPEC, "161")) == NULL)
+ {
+ printf("testsnmp: Unable to find \"%s\"!\n", argv[1]);
+ return (1);
+ }
+
+ if (fd < 0)
+ {
+ fputs("_cupsSNMPOpen: ", stdout);
+
+ if ((fd = _cupsSNMPOpen(host->addr.addr.sa_family)) < 0)
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ return (1);
+ }
+
+ puts("PASS");
+ }
+ }
+ else if (!show_oid(fd, community, &(host->addr), argv[i], walk))
+ return (1);
+ else
+ oid = argv[i];
+
+ if (!host)
+ usage();
+
+ if (!oid)
+ {
+ if (!show_oid(fd, community, &(host->addr),
+ walk ? ".1.3.6.1.2.1.43" :
+ ".1.3.6.1.2.1.43.10.2.1.4.1.1", walk))
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'print_packet()' - Print the contents of the response packet.
+ */
+
+static void
+print_packet(cups_snmp_t *packet, /* I - SNMP response packet */
+ void *data) /* I - User data pointer (not used) */
+{
+ int i; /* Looping var */
+ char temp[1024]; /* Temporary OID string */
+
+
+ (void)data;
+
+ printf("%s = ", _cupsSNMPOIDToString(packet->object_name, temp, sizeof(temp)));
+
+ switch (packet->object_type)
+ {
+ case CUPS_ASN1_BOOLEAN :
+ printf("BOOLEAN %s\n",
+ packet->object_value.boolean ? "TRUE" : "FALSE");
+ break;
+
+ case CUPS_ASN1_INTEGER :
+ printf("INTEGER %d\n", packet->object_value.integer);
+ break;
+
+ case CUPS_ASN1_BIT_STRING :
+ printf("BIT-STRING \"%s\"\n",
+ (char *)packet->object_value.string.bytes);
+ break;
+
+ case CUPS_ASN1_OCTET_STRING :
+ printf("OCTET-STRING \"%s\"\n",
+ (char *)packet->object_value.string.bytes);
+ break;
+
+ case CUPS_ASN1_NULL_VALUE :
+ puts("NULL-VALUE");
+ break;
+
+ case CUPS_ASN1_OID :
+ printf("OID %s\n", _cupsSNMPOIDToString(packet->object_value.oid,
+ temp, sizeof(temp)));
+ break;
+
+ case CUPS_ASN1_HEX_STRING :
+ fputs("Hex-STRING", stdout);
+ for (i = 0; i < packet->object_value.string.num_bytes; i ++)
+ printf(" %02X", packet->object_value.string.bytes[i]);
+ putchar('\n');
+ break;
+
+ case CUPS_ASN1_COUNTER :
+ printf("Counter %d\n", packet->object_value.counter);
+ break;
+
+ case CUPS_ASN1_GAUGE :
+ printf("Gauge %u\n", packet->object_value.gauge);
+ break;
+
+ case CUPS_ASN1_TIMETICKS :
+ printf("Timeticks %u days, %u:%02u:%02u.%02u\n",
+ packet->object_value.timeticks / 8640000,
+ (packet->object_value.timeticks / 360000) % 24,
+ (packet->object_value.timeticks / 6000) % 60,
+ (packet->object_value.timeticks / 100) % 60,
+ packet->object_value.timeticks % 100);
+ break;
+
+ default :
+ printf("Unknown-%X\n", packet->object_type);
+ break;
+ }
+}
+
+
+/*
+ * 'show_oid()' - Show the specified OID.
+ */
+
+static int /* O - 1 on success, 0 on error */
+show_oid(int fd, /* I - SNMP socket */
+ const char *community, /* I - Community name */
+ http_addr_t *addr, /* I - Address to query */
+ const char *s, /* I - OID to query */
+ int walk) /* I - Walk OIDs? */
+{
+ int i; /* Looping var */
+ int oid[CUPS_SNMP_MAX_OID]; /* OID */
+ cups_snmp_t packet; /* SNMP packet */
+ char temp[1024]; /* Temporary OID string */
+
+
+ if (!_cupsSNMPStringToOID(s, oid, sizeof(oid) / sizeof(oid[0])))
+ {
+ puts("testsnmp: Bad OID");
+ return (0);
+ }
+
+ if (walk)
+ {
+ printf("_cupsSNMPWalk(%s): ", _cupsSNMPOIDToString(oid, temp, sizeof(temp)));
+
+ if (_cupsSNMPWalk(fd, addr, CUPS_SNMP_VERSION_1, community, oid, 5.0,
+ print_packet, NULL) < 0)
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ return (0);
+ }
+ }
+ else
+ {
+ printf("_cupsSNMPWrite(%s): ", _cupsSNMPOIDToString(oid, temp, sizeof(temp)));
+
+ if (!_cupsSNMPWrite(fd, addr, CUPS_SNMP_VERSION_1, community,
+ CUPS_ASN1_GET_REQUEST, 1, oid))
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ return (0);
+ }
+
+ puts("PASS");
+
+ fputs("_cupsSNMPRead(5.0): ", stdout);
+
+ if (!_cupsSNMPRead(fd, &packet, 5.0))
+ {
+ puts("FAIL (timeout)");
+ return (0);
+ }
+
+ if (!_cupsSNMPIsOID(&packet, oid))
+ {
+ printf("FAIL (bad OID %d", packet.object_name[0]);
+ for (i = 1; packet.object_name[i] >= 0; i ++)
+ printf(".%d", packet.object_name[i]);
+ puts(")");
+ return (0);
+ }
+
+ if (packet.error)
+ {
+ printf("FAIL (%s)\n", packet.error);
+ return (0);
+ }
+
+ puts("PASS");
+
+ print_packet(&packet, NULL);
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'usage()' - Show program usage and exit.
+ */
+
+static void
+usage(void)
+{
+ puts("Usage: testsnmp [options] host-or-ip [oid ...]");
+ puts("");
+ puts("Options:");
+ puts("");
+ puts(" -c community Set community name");
+ puts(" -d Enable debugging");
+ puts(" -w Walk all OIDs under the specified one");
+
+ exit (1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/thread-private.h b/cups/thread-private.h
new file mode 100644
index 000000000..48f8a39a6
--- /dev/null
+++ b/cups/thread-private.h
@@ -0,0 +1,97 @@
+/*
+ * "$Id$"
+ *
+ * Private threading definitions for CUPS.
+ *
+ * Copyright 2009-2010 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPS_THREAD_PRIVATE_H_
+# define _CUPS_THREAD_PRIVATE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include "config.h"
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+# ifdef HAVE_PTHREAD_H
+# include <pthread.h>
+typedef void *(*_cups_thread_func_t)(void *arg);
+typedef pthread_mutex_t _cups_mutex_t;
+typedef pthread_rwlock_t _cups_rwlock_t;
+typedef pthread_key_t _cups_threadkey_t;
+# define _CUPS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+# define _CUPS_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
+# define _CUPS_THREADKEY_INITIALIZER -1
+# define _cupsThreadGetData(k) pthread_getspecific(k)
+# define _cupsThreadSetData(k,p) pthread_setspecific(k,p)
+
+# elif defined(WIN32)
+# include <winsock2.h>
+# include <windows.h>
+typedef void *(__stdcall *_cups_thread_func_t)(void *arg);
+typedef struct _cups_mutex_s
+{
+ int m_init; /* Flag for on-demand initialization */
+ CRITICAL_SECTION m_criticalSection;
+ /* Win32 Critical Section */
+} _cups_mutex_t;
+typedef _cups_mutex_t _cups_rwlock_t; /* TODO: Implement Win32 reader/writer lock */
+typedef DWORD _cups_threadkey_t;
+# define _CUPS_MUTEX_INITIALIZER { 0, 0 }
+# define _CUPS_RWLOCK_INITIALIZER { 0, 0 }
+# define _CUPS_THREADKEY_INITIALIZER 0
+# define _cupsThreadGetData(k) TlsGetValue(k)
+# define _cupsThreadSetData(k,p) TlsSetValue(k,p)
+
+# else
+typedef char _cups_mutex_t;
+typedef char _cups_rwlock_t;
+typedef void *_cups_threadkey_t;
+# define _CUPS_MUTEX_INITIALIZER 0
+# define _CUPS_RWLOCK_INITIALIZER 0
+# define _CUPS_THREADKEY_INITIALIZER (void *)0
+# define _cupsThreadGetData(k) k
+# define _cupsThreadSetData(k,p) k=p
+# endif /* HAVE_PTHREAD_H */
+
+
+/*
+ * Functions...
+ */
+
+extern void _cupsMutexInit(_cups_mutex_t *mutex);
+extern void _cupsMutexLock(_cups_mutex_t *mutex);
+extern void _cupsMutexUnlock(_cups_mutex_t *mutex);
+extern void _cupsRWInit(_cups_rwlock_t *rwlock);
+extern void _cupsRWLockRead(_cups_rwlock_t *rwlock);
+extern void _cupsRWLockWrite(_cups_rwlock_t *rwlock);
+extern void _cupsRWUnlock(_cups_rwlock_t *rwlock);
+extern int _cupsThreadCreate(_cups_thread_func_t func, void *arg);
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_THREAD_PRIVATE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/thread.c b/cups/thread.c
new file mode 100644
index 000000000..7574298fa
--- /dev/null
+++ b/cups/thread.c
@@ -0,0 +1,317 @@
+/*
+ * "$Id$"
+ *
+ * Threading primitives for CUPS.
+ *
+ * Copyright 2009-2010 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * _cupsMutexInit() - Initialize a mutex.
+ * _cupsMutexLock() - Lock a mutex.
+ * _cupsMutexUnlock() - Unlock a mutex.
+ * _cupsRWInit() - Initialize a reader/writer lock.
+ * _cupsRWLockRead() - Acquire a reader/writer lock for reading.
+ * _cupsRWLockWrite() - Acquire a reader/writer lock for writing.
+ * _cupsRWUnlock() - Release a reader/writer lock.
+ * _cupsThreadCreate() - Create a thread.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include "thread-private.h"
+
+
+#if defined(HAVE_PTHREAD_H)
+/*
+ * '_cupsMutexInit()' - Initialize a mutex.
+ */
+
+void
+_cupsMutexInit(_cups_mutex_t *mutex) /* I - Mutex */
+{
+ pthread_mutex_init(mutex, NULL);
+}
+
+
+/*
+ * '_cupsMutexLock()' - Lock a mutex.
+ */
+
+void
+_cupsMutexLock(_cups_mutex_t *mutex) /* I - Mutex */
+{
+ pthread_mutex_lock(mutex);
+}
+
+
+/*
+ * '_cupsMutexUnlock()' - Unlock a mutex.
+ */
+
+void
+_cupsMutexUnlock(_cups_mutex_t *mutex) /* I - Mutex */
+{
+ pthread_mutex_unlock(mutex);
+}
+
+
+/*
+ * '_cupsRWInit()' - Initialize a reader/writer lock.
+ */
+
+void
+_cupsRWInit(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */
+{
+ pthread_rwlock_init(rwlock, NULL);
+}
+
+
+/*
+ * '_cupsRWLockRead()' - Acquire a reader/writer lock for reading.
+ */
+
+void
+_cupsRWLockRead(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */
+{
+ pthread_rwlock_rdlock(rwlock);
+}
+
+
+/*
+ * '_cupsRWLockWrite()' - Acquire a reader/writer lock for writing.
+ */
+
+void
+_cupsRWLockWrite(_cups_rwlock_t *rwlock)/* I - Reader/writer lock */
+{
+ pthread_rwlock_wrlock(rwlock);
+}
+
+
+/*
+ * '_cupsRWUnlock()' - Release a reader/writer lock.
+ */
+
+void
+_cupsRWUnlock(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */
+{
+ pthread_rwlock_unlock(rwlock);
+}
+
+
+/*
+ * '_cupsThreadCreate()' - Create a thread.
+ */
+
+int /* O - 0 on failure, 1 on success */
+_cupsThreadCreate(
+ _cups_thread_func_t func, /* I - Entry point */
+ void *arg) /* I - Entry point context */
+{
+ pthread_t thread;
+
+ return (pthread_create(&thread, NULL, (void *(*)(void *))func, arg) == 0);
+}
+
+
+#elif defined(WIN32)
+# include <process.h>
+
+
+/*
+ * '_cupsMutexInit()' - Initialize a mutex.
+ */
+
+void
+_cupsMutexInit(_cups_mutex_t *mutex) /* I - Mutex */
+{
+ InitializeCriticalSection(&mutex->m_criticalSection);
+ mutex->m_init = 1;
+}
+
+
+/*
+ * '_cupsMutexLock()' - Lock a mutex.
+ */
+
+void
+_cupsMutexLock(_cups_mutex_t *mutex) /* I - Mutex */
+{
+ if (!mutex->m_init)
+ {
+ _cupsGlobalLock();
+
+ if (!mutex->m_init)
+ {
+ InitializeCriticalSection(&mutex->m_criticalSection);
+ mutex->m_init = 1;
+ }
+
+ _cupsGlobalUnlock();
+ }
+
+ EnterCriticalSection(&mutex->m_criticalSection);
+}
+
+
+/*
+ * '_cupsMutexUnlock()' - Unlock a mutex.
+ */
+
+void
+_cupsMutexUnlock(_cups_mutex_t *mutex) /* I - Mutex */
+{
+ LeaveCriticalSection(&mutex->m_criticalSection);
+}
+
+
+/*
+ * '_cupsRWInit()' - Initialize a reader/writer lock.
+ */
+
+void
+_cupsRWInit(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */
+{
+ _cupsMutexInit((_cups_mutex_t *)rwlock);
+}
+
+
+/*
+ * '_cupsRWLockRead()' - Acquire a reader/writer lock for reading.
+ */
+
+void
+_cupsRWLockRead(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */
+{
+ _cupsMutexLock((_cups_mutex_t *)rwlock);
+}
+
+
+/*
+ * '_cupsRWLockWrite()' - Acquire a reader/writer lock for writing.
+ */
+
+void
+_cupsRWLockWrite(_cups_rwlock_t *rwlock)/* I - Reader/writer lock */
+{
+ _cupsMutexLock((_cups_mutex_t *)rwlock);
+}
+
+
+/*
+ * '_cupsRWUnlock()' - Release a reader/writer lock.
+ */
+
+void
+_cupsRWUnlock(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */
+{
+ _cupsMutexUnlock((_cups_mutex_t *)rwlock);
+}
+
+
+/*
+ * '_cupsThreadCreate()' - Create a thread.
+ */
+
+int /* O - 0 on failure, 1 on success */
+_cupsThreadCreate(
+ _cups_thread_func_t func, /* I - Entry point */
+ void *arg) /* I - Entry point context */
+{
+ return (_beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE) func, arg, 0, NULL)
+ != 0);
+}
+
+
+#else
+/*
+ * '_cupsMutexInit()' - Initialize a mutex.
+ */
+
+void
+_cupsMutexInit(_cups_mutex_t *mutex) /* I - Mutex */
+{
+ (void)mutex;
+}
+
+
+/*
+ * '_cupsMutexLock()' - Lock a mutex.
+ */
+
+void
+_cupsMutexLock(_cups_mutex_t *mutex) /* I - Mutex */
+{
+ (void)mutex;
+}
+
+
+/*
+ * '_cupsMutexUnlock()' - Unlock a mutex.
+ */
+
+void
+_cupsMutexUnlock(_cups_mutex_t *mutex) /* I - Mutex */
+{
+ (void)mutex;
+}
+
+
+/*
+ * '_cupsRWInit()' - Initialize a reader/writer lock.
+ */
+
+void
+_cupsRWInit(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */
+{
+ (void)rwlock;
+}
+
+
+/*
+ * '_cupsRWLockRead()' - Acquire a reader/writer lock for reading.
+ */
+
+void
+_cupsRWLockRead(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */
+{
+ (void)rwlock;
+}
+
+
+/*
+ * '_cupsRWLockWrite()' - Acquire a reader/writer lock for writing.
+ */
+
+void
+_cupsRWLockWrite(_cups_rwlock_t *rwlock)/* I - Reader/writer lock */
+{
+ (void)rwlock;
+}
+
+
+/*
+ * '_cupsRWUnlock()' - Release a reader/writer lock.
+ */
+
+void
+_cupsRWUnlock(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */
+{
+ (void)rwlock;
+}
+#endif /* HAVE_PTHREAD_H */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/transcode.c b/cups/transcode.c
new file mode 100644
index 000000000..35ab52f49
--- /dev/null
+++ b/cups/transcode.c
@@ -0,0 +1,717 @@
+/*
+ * "$Id$"
+ *
+ * Transcoding support for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsCharmapFlush() - Flush all character set maps out of cache.
+ * cupsCharsetToUTF8() - Convert legacy character set to UTF-8.
+ * cupsUTF8ToCharset() - Convert UTF-8 to legacy character set.
+ * cupsUTF8ToUTF32() - Convert UTF-8 to UTF-32.
+ * cupsUTF32ToUTF8() - Convert UTF-32 to UTF-8.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include <limits.h>
+#include <time.h>
+#ifdef HAVE_ICONV_H
+# include <iconv.h>
+#endif /* HAVE_ICONV_H */
+
+
+/*
+ * Local globals...
+ */
+
+#ifdef HAVE_ICONV_H
+static _cups_mutex_t map_mutex = _CUPS_MUTEX_INITIALIZER;
+ /* Mutex to control access to maps */
+static iconv_t map_from_utf8 = (iconv_t)-1;
+ /* Convert from UTF-8 to charset */
+static iconv_t map_to_utf8 = (iconv_t)-1;
+ /* Convert from charset to UTF-8 */
+static cups_encoding_t map_encoding = CUPS_AUTO_ENCODING;
+ /* Which charset is cached */
+#endif /* HAVE_ICONV_H */
+
+
+/*
+ * '_cupsCharmapFlush()' - Flush all character set maps out of cache.
+ */
+
+void
+_cupsCharmapFlush(void)
+{
+#ifdef HAVE_ICONV_H
+ if (map_from_utf8 != (iconv_t)-1)
+ {
+ iconv_close(map_from_utf8);
+ map_from_utf8 = (iconv_t)-1;
+ }
+
+ if (map_to_utf8 != (iconv_t)-1)
+ {
+ iconv_close(map_to_utf8);
+ map_to_utf8 = (iconv_t)-1;
+ }
+
+ map_encoding = CUPS_AUTO_ENCODING;
+#endif /* HAVE_ICONV_H */
+}
+
+
+/*
+ * 'cupsCharsetToUTF8()' - Convert legacy character set to UTF-8.
+ */
+
+int /* O - Count or -1 on error */
+cupsCharsetToUTF8(
+ cups_utf8_t *dest, /* O - Target string */
+ const char *src, /* I - Source string */
+ const int maxout, /* I - Max output */
+ const cups_encoding_t encoding) /* I - Encoding */
+{
+ cups_utf8_t *destptr; /* Pointer into UTF-8 buffer */
+#ifdef HAVE_ICONV_H
+ size_t srclen, /* Length of source string */
+ outBytesLeft; /* Bytes remaining in output buffer */
+#endif /* HAVE_ICONV_H */
+
+
+ /*
+ * Check for valid arguments...
+ */
+
+ DEBUG_printf(("2cupsCharsetToUTF8(dest=%p, src=\"%s\", maxout=%d, encoding=%d)",
+ dest, src, maxout, encoding));
+
+ if (!dest || !src || maxout < 1)
+ {
+ if (dest)
+ *dest = '\0';
+
+ DEBUG_puts("3cupsCharsetToUTF8: Bad arguments, returning -1");
+ return (-1);
+ }
+
+ /*
+ * Handle identity conversions...
+ */
+
+ if (encoding == CUPS_UTF8 || encoding <= CUPS_US_ASCII ||
+ encoding >= CUPS_ENCODING_VBCS_END)
+ {
+ strlcpy((char *)dest, src, maxout);
+ return ((int)strlen((char *)dest));
+ }
+
+ /*
+ * Handle ISO-8859-1 to UTF-8 directly...
+ */
+
+ destptr = dest;
+
+ if (encoding == CUPS_ISO8859_1)
+ {
+ int ch; /* Character from string */
+ cups_utf8_t *destend; /* End of UTF-8 buffer */
+
+
+ destend = dest + maxout - 2;
+
+ while (*src && destptr < destend)
+ {
+ ch = *src++ & 255;
+
+ if (ch & 128)
+ {
+ *destptr++ = 0xc0 | (ch >> 6);
+ *destptr++ = 0x80 | (ch & 0x3f);
+ }
+ else
+ *destptr++ = ch;
+ }
+
+ *destptr = '\0';
+
+ return ((int)(destptr - dest));
+ }
+
+ /*
+ * Convert input legacy charset to UTF-8...
+ */
+
+#ifdef HAVE_ICONV_H
+ _cupsMutexLock(&map_mutex);
+
+ if (map_encoding != encoding)
+ {
+ _cupsCharmapFlush();
+
+ map_from_utf8 = iconv_open(_cupsEncodingName(encoding), "UTF-8");
+ map_to_utf8 = iconv_open("UTF-8", _cupsEncodingName(encoding));
+ map_encoding = encoding;
+ }
+
+ if (map_to_utf8 != (iconv_t)-1)
+ {
+ srclen = strlen(src);
+ outBytesLeft = maxout - 1;
+
+ iconv(map_to_utf8, (char **)&src, &srclen, (char **)&destptr,
+ &outBytesLeft);
+ *destptr = '\0';
+
+ _cupsMutexUnlock(&map_mutex);
+
+ return ((int)(destptr - dest));
+ }
+
+ _cupsMutexUnlock(&map_mutex);
+#endif /* HAVE_ICONV_H */
+
+ /*
+ * No iconv() support, so error out...
+ */
+
+ *destptr = '\0';
+
+ return (-1);
+}
+
+
+/*
+ * 'cupsUTF8ToCharset()' - Convert UTF-8 to legacy character set.
+ */
+
+int /* O - Count or -1 on error */
+cupsUTF8ToCharset(
+ char *dest, /* O - Target string */
+ const cups_utf8_t *src, /* I - Source string */
+ const int maxout, /* I - Max output */
+ const cups_encoding_t encoding) /* I - Encoding */
+{
+ char *destptr; /* Pointer into destination */
+#ifdef HAVE_ICONV_H
+ size_t srclen, /* Length of source string */
+ outBytesLeft; /* Bytes remaining in output buffer */
+#endif /* HAVE_ICONV_H */
+
+
+ /*
+ * Check for valid arguments...
+ */
+
+ if (!dest || !src || maxout < 1)
+ {
+ if (dest)
+ *dest = '\0';
+
+ return (-1);
+ }
+
+ /*
+ * Handle identity conversions...
+ */
+
+ if (encoding == CUPS_UTF8 ||
+ encoding >= CUPS_ENCODING_VBCS_END)
+ {
+ strlcpy(dest, (char *)src, maxout);
+ return ((int)strlen(dest));
+ }
+
+ /*
+ * Handle UTF-8 to ISO-8859-1 directly...
+ */
+
+ destptr = dest;
+
+ if (encoding == CUPS_ISO8859_1 || encoding <= CUPS_US_ASCII)
+ {
+ int ch, /* Character from string */
+ maxch; /* Maximum character for charset */
+ char *destend; /* End of ISO-8859-1 buffer */
+
+ maxch = encoding == CUPS_ISO8859_1 ? 256 : 128;
+ destend = dest + maxout - 1;
+
+ while (*src && destptr < destend)
+ {
+ ch = *src++;
+
+ if ((ch & 0xe0) == 0xc0)
+ {
+ ch = ((ch & 0x1f) << 6) | (*src++ & 0x3f);
+
+ if (ch < maxch)
+ *destptr++ = ch;
+ else
+ *destptr++ = '?';
+ }
+ else if ((ch & 0xf0) == 0xe0 ||
+ (ch & 0xf8) == 0xf0)
+ *destptr++ = '?';
+ else if (!(ch & 0x80))
+ *destptr++ = ch;
+ }
+
+ *destptr = '\0';
+
+ return ((int)(destptr - dest));
+ }
+
+#ifdef HAVE_ICONV_H
+ /*
+ * Convert input UTF-8 to legacy charset...
+ */
+
+ _cupsMutexLock(&map_mutex);
+
+ if (map_encoding != encoding)
+ {
+ _cupsCharmapFlush();
+
+ map_from_utf8 = iconv_open(_cupsEncodingName(encoding), "UTF-8");
+ map_to_utf8 = iconv_open("UTF-8", _cupsEncodingName(encoding));
+ map_encoding = encoding;
+ }
+
+ if (map_from_utf8 != (iconv_t)-1)
+ {
+ srclen = strlen((char *)src);
+ outBytesLeft = maxout - 1;
+
+ iconv(map_from_utf8, (char **)&src, &srclen, &destptr, &outBytesLeft);
+ *destptr = '\0';
+
+ _cupsMutexUnlock(&map_mutex);
+
+ return ((int)(destptr - dest));
+ }
+
+ _cupsMutexUnlock(&map_mutex);
+#endif /* HAVE_ICONV_H */
+
+ /*
+ * No iconv() support, so error out...
+ */
+
+ *destptr = '\0';
+
+ return (-1);
+}
+
+
+/*
+ * 'cupsUTF8ToUTF32()' - Convert UTF-8 to UTF-32.
+ *
+ * 32-bit UTF-32 (actually 21-bit) maps to UTF-8 as follows...
+ *
+ * UTF-32 char UTF-8 char(s)
+ * --------------------------------------------------
+ * 0 to 127 = 0xxxxxxx (US-ASCII)
+ * 128 to 2047 = 110xxxxx 10yyyyyy
+ * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz
+ * > 65535 = 11110xxx 10yyyyyy 10zzzzzz 10xxxxxx
+ *
+ * UTF-32 prohibits chars beyond Plane 16 (> 0x10ffff) in UCS-4,
+ * which would convert to five- or six-octet UTF-8 sequences...
+ */
+
+int /* O - Count or -1 on error */
+cupsUTF8ToUTF32(
+ cups_utf32_t *dest, /* O - Target string */
+ const cups_utf8_t *src, /* I - Source string */
+ const int maxout) /* I - Max output */
+{
+ int i; /* Looping variable */
+ cups_utf8_t ch; /* Character value */
+ cups_utf8_t next; /* Next character value */
+ cups_utf32_t ch32; /* UTF-32 character value */
+
+
+ /*
+ * Check for valid arguments and clear output...
+ */
+
+ DEBUG_printf(("2cupsUTF8ToUTF32(dest=%p, src=\"%s\", maxout=%d)", dest,
+ src, maxout));
+
+ if (dest)
+ *dest = 0;
+
+ if (!dest || !src || maxout < 1 || maxout > CUPS_MAX_USTRING)
+ {
+ DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad arguments)");
+
+ return (-1);
+ }
+
+ /*
+ * Convert input UTF-8 to output UTF-32...
+ */
+
+ for (i = maxout - 1; *src && i > 0; i --)
+ {
+ ch = *src++;
+
+ /*
+ * Convert UTF-8 character(s) to UTF-32 character...
+ */
+
+ if (!(ch & 0x80))
+ {
+ /*
+ * One-octet UTF-8 <= 127 (US-ASCII)...
+ */
+
+ *dest++ = ch;
+
+ DEBUG_printf(("4cupsUTF8ToUTF32: %02x => %08X", src[-1], ch));
+ continue;
+ }
+ else if ((ch & 0xe0) == 0xc0)
+ {
+ /*
+ * Two-octet UTF-8 <= 2047 (Latin-x)...
+ */
+
+ next = *src++;
+ if ((next & 0xc0) != 0x80)
+ {
+ DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
+
+ return (-1);
+ }
+
+ ch32 = ((ch & 0x1f) << 6) | (next & 0x3f);
+
+ /*
+ * Check for non-shortest form (invalid UTF-8)...
+ */
+
+ if (ch32 < 0x80)
+ {
+ DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
+
+ return (-1);
+ }
+
+ *dest++ = ch32;
+
+ DEBUG_printf(("4cupsUTF8ToUTF32: %02x %02x => %08X",
+ src[-2], src[-1], (unsigned)ch32));
+ }
+ else if ((ch & 0xf0) == 0xe0)
+ {
+ /*
+ * Three-octet UTF-8 <= 65535 (Plane 0 - BMP)...
+ */
+
+ next = *src++;
+ if ((next & 0xc0) != 0x80)
+ {
+ DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
+
+ return (-1);
+ }
+
+ ch32 = ((ch & 0x0f) << 6) | (next & 0x3f);
+
+ next = *src++;
+ if ((next & 0xc0) != 0x80)
+ {
+ DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
+
+ return (-1);
+ }
+
+ ch32 = (ch32 << 6) | (next & 0x3f);
+
+ /*
+ * Check for non-shortest form (invalid UTF-8)...
+ */
+
+ if (ch32 < 0x800)
+ {
+ DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
+
+ return (-1);
+ }
+
+ *dest++ = ch32;
+
+ DEBUG_printf(("4cupsUTF8ToUTF32: %02x %02x %02x => %08X",
+ src[-3], src[-2], src[-1], (unsigned)ch32));
+ }
+ else if ((ch & 0xf8) == 0xf0)
+ {
+ /*
+ * Four-octet UTF-8...
+ */
+
+ next = *src++;
+ if ((next & 0xc0) != 0x80)
+ {
+ DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
+
+ return (-1);
+ }
+
+ ch32 = ((ch & 0x07) << 6) | (next & 0x3f);
+
+ next = *src++;
+ if ((next & 0xc0) != 0x80)
+ {
+ DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
+
+ return (-1);
+ }
+
+ ch32 = (ch32 << 6) | (next & 0x3f);
+
+ next = *src++;
+ if ((next & 0xc0) != 0x80)
+ {
+ DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
+
+ return (-1);
+ }
+
+ ch32 = (ch32 << 6) | (next & 0x3f);
+
+ /*
+ * Check for non-shortest form (invalid UTF-8)...
+ */
+
+ if (ch32 < 0x10000)
+ {
+ DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
+
+ return (-1);
+ }
+
+ *dest++ = ch32;
+
+ DEBUG_printf(("4cupsUTF8ToUTF32: %02x %02x %02x %02x => %08X",
+ src[-4], src[-3], src[-2], src[-1], (unsigned)ch32));
+ }
+ else
+ {
+ /*
+ * More than 4-octet (invalid UTF-8 sequence)...
+ */
+
+ DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)");
+
+ return (-1);
+ }
+
+ /*
+ * Check for UTF-16 surrogate (illegal UTF-8)...
+ */
+
+ if (ch32 >= 0xd800 && ch32 <= 0xdfff)
+ return (-1);
+ }
+
+ *dest = 0;
+
+ DEBUG_printf(("3cupsUTF8ToUTF32: Returning %d characters", maxout - 1 - i));
+
+ return (maxout - 1 - i);
+}
+
+
+/*
+ * 'cupsUTF32ToUTF8()' - Convert UTF-32 to UTF-8.
+ *
+ * 32-bit UTF-32 (actually 21-bit) maps to UTF-8 as follows...
+ *
+ * UTF-32 char UTF-8 char(s)
+ * --------------------------------------------------
+ * 0 to 127 = 0xxxxxxx (US-ASCII)
+ * 128 to 2047 = 110xxxxx 10yyyyyy
+ * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz
+ * > 65535 = 11110xxx 10yyyyyy 10zzzzzz 10xxxxxx
+ *
+ * UTF-32 prohibits chars beyond Plane 16 (> 0x10ffff) in UCS-4,
+ * which would convert to five- or six-octet UTF-8 sequences...
+ */
+
+int /* O - Count or -1 on error */
+cupsUTF32ToUTF8(
+ cups_utf8_t *dest, /* O - Target string */
+ const cups_utf32_t *src, /* I - Source string */
+ const int maxout) /* I - Max output */
+{
+ cups_utf8_t *start; /* Start of destination string */
+ int i; /* Looping variable */
+ int swap; /* Byte-swap input to output */
+ cups_utf32_t ch; /* Character value */
+
+
+ /*
+ * Check for valid arguments and clear output...
+ */
+
+ DEBUG_printf(("2cupsUTF32ToUTF8(dest=%p, src=%p, maxout=%d)", dest, src,
+ maxout));
+
+ if (dest)
+ *dest = '\0';
+
+ if (!dest || !src || maxout < 1)
+ {
+ DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (bad args)");
+
+ return (-1);
+ }
+
+ /*
+ * Check for leading BOM in UTF-32 and inverted BOM...
+ */
+
+ start = dest;
+ swap = *src == 0xfffe0000;
+
+ DEBUG_printf(("4cupsUTF32ToUTF8: swap=%d", swap));
+
+ if (*src == 0xfffe0000 || *src == 0xfeff)
+ src ++;
+
+ /*
+ * Convert input UTF-32 to output UTF-8...
+ */
+
+ for (i = maxout - 1; *src && i > 0;)
+ {
+ ch = *src++;
+
+ /*
+ * Byte swap input UTF-32, if necessary...
+ * (only byte-swapping 24 of 32 bits)
+ */
+
+ if (swap)
+ ch = ((ch >> 24) | ((ch >> 8) & 0xff00) | ((ch << 8) & 0xff0000));
+
+ /*
+ * Check for beyond Plane 16 (invalid UTF-32)...
+ */
+
+ if (ch > 0x10ffff)
+ {
+ DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (character out of range)");
+
+ return (-1);
+ }
+
+ /*
+ * Convert UTF-32 character to UTF-8 character(s)...
+ */
+
+ if (ch < 0x80)
+ {
+ /*
+ * One-octet UTF-8 <= 127 (US-ASCII)...
+ */
+
+ *dest++ = (cups_utf8_t)ch;
+ i --;
+
+ DEBUG_printf(("4cupsUTF32ToUTF8: %08x => %02x", (unsigned)ch, dest[-1]));
+ }
+ else if (ch < 0x800)
+ {
+ /*
+ * Two-octet UTF-8 <= 2047 (Latin-x)...
+ */
+
+ if (i < 2)
+ {
+ DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (too long 2)");
+
+ return (-1);
+ }
+
+ *dest++ = (cups_utf8_t)(0xc0 | ((ch >> 6) & 0x1f));
+ *dest++ = (cups_utf8_t)(0x80 | (ch & 0x3f));
+ i -= 2;
+
+ DEBUG_printf(("4cupsUTF32ToUTF8: %08x => %02x %02x", (unsigned)ch,
+ dest[-2], dest[-1]));
+ }
+ else if (ch < 0x10000)
+ {
+ /*
+ * Three-octet UTF-8 <= 65535 (Plane 0 - BMP)...
+ */
+
+ if (i < 3)
+ {
+ DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (too long 3)");
+
+ return (-1);
+ }
+
+ *dest++ = (cups_utf8_t)(0xe0 | ((ch >> 12) & 0x0f));
+ *dest++ = (cups_utf8_t)(0x80 | ((ch >> 6) & 0x3f));
+ *dest++ = (cups_utf8_t)(0x80 | (ch & 0x3f));
+ i -= 3;
+
+ DEBUG_printf(("4cupsUTF32ToUTF8: %08x => %02x %02x %02x", (unsigned)ch,
+ dest[-3], dest[-2], dest[-1]));
+ }
+ else
+ {
+ /*
+ * Four-octet UTF-8...
+ */
+
+ if (i < 4)
+ {
+ DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (too long 4)");
+
+ return (-1);
+ }
+
+ *dest++ = (cups_utf8_t)(0xf0 | ((ch >> 18) & 0x07));
+ *dest++ = (cups_utf8_t)(0x80 | ((ch >> 12) & 0x3f));
+ *dest++ = (cups_utf8_t)(0x80 | ((ch >> 6) & 0x3f));
+ *dest++ = (cups_utf8_t)(0x80 | (ch & 0x3f));
+ i -= 4;
+
+ DEBUG_printf(("4cupsUTF32ToUTF8: %08x => %02x %02x %02x %02x",
+ (unsigned)ch, dest[-4], dest[-3], dest[-2], dest[-1]));
+ }
+ }
+
+ *dest = '\0';
+
+ DEBUG_printf(("3cupsUTF32ToUTF8: Returning %d", (int)(dest - start)));
+
+ return ((int)(dest - start));
+}
+
+
+/*
+ * End of "$Id$"
+ */
diff --git a/cups/transcode.h b/cups/transcode.h
new file mode 100644
index 000000000..cafea33c5
--- /dev/null
+++ b/cups/transcode.h
@@ -0,0 +1,81 @@
+/*
+ * "$Id$"
+ *
+ * Transcoding definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_TRANSCODE_H_
+# define _CUPS_TRANSCODE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include "language.h"
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Constants...
+ */
+
+# define CUPS_MAX_USTRING 8192 /* Max size of Unicode string */
+
+
+/*
+ * Types...
+ */
+
+typedef unsigned char cups_utf8_t; /* UTF-8 Unicode/ISO-10646 unit */
+typedef unsigned long cups_utf32_t; /* UTF-32 Unicode/ISO-10646 unit */
+typedef unsigned short cups_ucs2_t; /* UCS-2 Unicode/ISO-10646 unit */
+typedef unsigned long cups_ucs4_t; /* UCS-4 Unicode/ISO-10646 unit */
+typedef unsigned char cups_sbcs_t; /* SBCS Legacy 8-bit unit */
+typedef unsigned short cups_dbcs_t; /* DBCS Legacy 16-bit unit */
+typedef unsigned long cups_vbcs_t; /* VBCS Legacy 32-bit unit */
+ /* EUC uses 8, 16, 24, 32-bit */
+
+
+/*
+ * Prototypes...
+ */
+
+extern int cupsCharsetToUTF8(cups_utf8_t *dest,
+ const char *src,
+ const int maxout,
+ const cups_encoding_t encoding) _CUPS_API_1_2;
+extern int cupsUTF8ToCharset(char *dest,
+ const cups_utf8_t *src,
+ const int maxout,
+ const cups_encoding_t encoding) _CUPS_API_1_2;
+extern int cupsUTF8ToUTF32(cups_utf32_t *dest,
+ const cups_utf8_t *src,
+ const int maxout) _CUPS_API_1_2;
+extern int cupsUTF32ToUTF8(cups_utf8_t *dest,
+ const cups_utf32_t *src,
+ const int maxout) _CUPS_API_1_2;
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_TRANSCODE_H_ */
+
+
+/*
+ * End of "$Id$"
+ */
diff --git a/cups/usersys.c b/cups/usersys.c
new file mode 100644
index 000000000..c2ba7fd3a
--- /dev/null
+++ b/cups/usersys.c
@@ -0,0 +1,802 @@
+/*
+ * "$Id$"
+ *
+ * User, system, and password routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsEncryption() - Get the current encryption settings.
+ * cupsGetPassword() - Get a password from the user.
+ * cupsGetPassword2() - Get a password from the user using the advanced
+ * password callback.
+ * cupsServer() - Return the hostname/address of the current
+ * server.
+ * cupsSetClientCertCB() - Set the client certificate callback.
+ * cupsSetEncryption() - Set the encryption preference.
+ * cupsSetPasswordCB() - Set the password callback for CUPS.
+ * cupsSetPasswordCB2() - Set the advanced password callback for CUPS.
+ * cupsSetServer() - Set the default server name and port.
+ * cupsSetServerCertCB() - Set the server certificate callback.
+ * cupsSetUser() - Set the default user name.
+ * cupsUser() - Return the current user's name.
+ * _cupsGetPassword() - Get a password from the user.
+ * _cupsGSSServiceName() - Get the GSS (Kerberos) service name.
+ * _cupsSetDefaults() - Set the default server, port, and encryption.
+ * cups_read_client_conf() - Read a client.conf file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include <stdlib.h>
+#include <sys/stat.h>
+#ifdef WIN32
+# include <windows.h>
+#else
+# include <pwd.h>
+#endif /* WIN32 */
+
+
+/*
+ * Local functions...
+ */
+
+static void cups_read_client_conf(cups_file_t *fp,
+ _cups_globals_t *cg,
+ const char *cups_encryption,
+ const char *cups_server,
+#ifdef HAVE_GSSAPI
+ const char *cups_gssservicename,
+#endif /* HAVE_GSSAPI */
+ const char *cups_anyroot,
+ const char *cups_expiredroot,
+ const char *cups_expiredcerts);
+
+
+/*
+ * 'cupsEncryption()' - Get the current encryption settings.
+ *
+ * The default encryption setting comes from the CUPS_ENCRYPTION
+ * environment variable, then the ~/.cups/client.conf file, and finally the
+ * /etc/cups/client.conf file. If not set, the default is
+ * @code HTTP_ENCRYPT_IF_REQUESTED@.
+ *
+ * Note: The current encryption setting is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the setting via the
+ * @link cupsSetEncryption@ function need to do so in each thread for the same
+ * setting to be used.
+ */
+
+http_encryption_t /* O - Encryption settings */
+cupsEncryption(void)
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ if (cg->encryption == (http_encryption_t)-1)
+ _cupsSetDefaults();
+
+ return (cg->encryption);
+}
+
+
+/*
+ * 'cupsGetPassword()' - Get a password from the user.
+ *
+ * Uses the current password callback function. Returns @code NULL@ if the
+ * user does not provide a password.
+ *
+ * Note: The current password callback function is tracked separately for each
+ * thread in a program. Multi-threaded programs that override the setting via
+ * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
+ * do so in each thread for the same function to be used.
+ */
+
+const char * /* O - Password */
+cupsGetPassword(const char *prompt) /* I - Prompt string */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ return ((cg->password_cb)(prompt, NULL, NULL, NULL, cg->password_data));
+}
+
+
+/*
+ * 'cupsGetPassword2()' - Get a password from the user using the advanced
+ * password callback.
+ *
+ * Uses the current password callback function. Returns @code NULL@ if the
+ * user does not provide a password.
+ *
+ * Note: The current password callback function is tracked separately for each
+ * thread in a program. Multi-threaded programs that override the setting via
+ * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
+ * do so in each thread for the same function to be used.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+const char * /* O - Password */
+cupsGetPassword2(const char *prompt, /* I - Prompt string */
+ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *method, /* I - Request method ("GET", "POST", "PUT") */
+ const char *resource) /* I - Resource path */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ if (!http)
+ http = _cupsConnect();
+
+ return ((cg->password_cb)(prompt, http, method, resource, cg->password_data));
+}
+
+
+/*
+ * 'cupsServer()' - Return the hostname/address of the current server.
+ *
+ * The default server comes from the CUPS_SERVER environment variable, then the
+ * ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not
+ * set, the default is the local system - either "localhost" or a domain socket
+ * path.
+ *
+ * The returned value can be a fully-qualified hostname, a numeric IPv4 or IPv6
+ * address, or a domain socket pathname.
+ *
+ * Note: The current server is tracked separately for each thread in a program.
+ * Multi-threaded programs that override the server via the
+ * @link cupsSetServer@ function need to do so in each thread for the same
+ * server to be used.
+ */
+
+const char * /* O - Server name */
+cupsServer(void)
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ if (!cg->server[0])
+ _cupsSetDefaults();
+
+ return (cg->server);
+}
+
+
+/*
+ * 'cupsSetClientCertCB()' - Set the client certificate callback.
+ *
+ * Pass @code NULL@ to restore the default callback.
+ *
+ * Note: The current certificate callback is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the callback need to do
+ * so in each thread for the same callback to be used.
+ *
+ * @since CUPS 1.5/Mac OS X 10.7@
+ */
+
+void
+cupsSetClientCertCB(
+ cups_client_cert_cb_t cb, /* I - Callback function */
+ void *user_data) /* I - User data pointer */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ cg->client_cert_cb = cb;
+ cg->client_cert_data = user_data;
+}
+
+
+/*
+ * 'cupsSetCredentials()' - Set the default credentials to be used for SSL/TLS
+ * connections.
+ *
+ * Note: The default credentials are tracked separately for each thread in a
+ * program. Multi-threaded programs that override the setting need to do so in
+ * each thread for the same setting to be used.
+ *
+ * @since CUPS 1.5/Mac OS X 10.7@
+ */
+
+int /* O - Status of call (0 = success) */
+cupsSetCredentials(
+ cups_array_t *credentials) /* I - Array of credentials */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ if (cupsArrayCount(credentials) < 1)
+ return (-1);
+
+ _httpFreeCredentials(cg->tls_credentials);
+ cg->tls_credentials = _httpConvertCredentials(credentials);
+
+ return (cg->tls_credentials ? 0 : -1);
+}
+
+
+/*
+ * 'cupsSetEncryption()' - Set the encryption preference.
+ *
+ * The default encryption setting comes from the CUPS_ENCRYPTION
+ * environment variable, then the ~/.cups/client.conf file, and finally the
+ * /etc/cups/client.conf file. If not set, the default is
+ * @code HTTP_ENCRYPT_IF_REQUESTED@.
+ *
+ * Note: The current encryption setting is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the setting need to do
+ * so in each thread for the same setting to be used.
+ */
+
+void
+cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ cg->encryption = e;
+
+ if (cg->http)
+ httpEncryption(cg->http, e);
+}
+
+
+/*
+ * 'cupsSetPasswordCB()' - Set the password callback for CUPS.
+ *
+ * Pass @code NULL@ to restore the default (console) password callback, which
+ * reads the password from the console. Programs should call either this
+ * function or @link cupsSetPasswordCB2@, as only one callback can be registered
+ * by a program per thread.
+ *
+ * Note: The current password callback is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the callback need to do
+ * so in each thread for the same callback to be used.
+ */
+
+void
+cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ if (cb == (cups_password_cb_t)0)
+ cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
+ else
+ cg->password_cb = (cups_password_cb2_t)cb;
+
+ cg->password_data = NULL;
+}
+
+
+/*
+ * 'cupsSetPasswordCB2()' - Set the advanced password callback for CUPS.
+ *
+ * Pass @code NULL@ to restore the default (console) password callback, which
+ * reads the password from the console. Programs should call either this
+ * function or @link cupsSetPasswordCB2@, as only one callback can be registered
+ * by a program per thread.
+ *
+ * Note: The current password callback is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the callback need to do
+ * so in each thread for the same callback to be used.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+void
+cupsSetPasswordCB2(
+ cups_password_cb2_t cb, /* I - Callback function */
+ void *user_data) /* I - User data pointer */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ if (cb == (cups_password_cb2_t)0)
+ cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
+ else
+ cg->password_cb = cb;
+
+ cg->password_data = user_data;
+}
+
+
+/*
+ * 'cupsSetServer()' - Set the default server name and port.
+ *
+ * The "server" string can be a fully-qualified hostname, a numeric
+ * IPv4 or IPv6 address, or a domain socket pathname. Hostnames and numeric IP
+ * addresses can be optionally followed by a colon and port number to override
+ * the default port 631, e.g. "hostname:8631". Pass @code NULL@ to restore the
+ * default server name and port.
+ *
+ * Note: The current server is tracked separately for each thread in a program.
+ * Multi-threaded programs that override the server need to do so in each
+ * thread for the same server to be used.
+ */
+
+void
+cupsSetServer(const char *server) /* I - Server name */
+{
+ char *port; /* Pointer to port */
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ if (server)
+ {
+ strlcpy(cg->server, server, sizeof(cg->server));
+
+ if (cg->server[0] != '/' && (port = strrchr(cg->server, ':')) != NULL &&
+ !strchr(port, ']') && isdigit(port[1] & 255))
+ {
+ *port++ = '\0';
+
+ cg->ipp_port = atoi(port);
+ }
+
+ if (cg->server[0] == '/')
+ strcpy(cg->servername, "localhost");
+ else
+ strlcpy(cg->servername, cg->server, sizeof(cg->servername));
+ }
+ else
+ {
+ cg->server[0] = '\0';
+ cg->servername[0] = '\0';
+ }
+
+ if (cg->http)
+ {
+ httpClose(cg->http);
+ cg->http = NULL;
+ }
+}
+
+
+/*
+ * 'cupsSetServerCertCB()' - Set the server certificate callback.
+ *
+ * Pass @code NULL@ to restore the default callback.
+ *
+ * Note: The current credentials callback is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the callback need to do
+ * so in each thread for the same callback to be used.
+ *
+ * @since CUPS 1.5/Mac OS X 10.7@
+ */
+
+void
+cupsSetServerCertCB(
+ cups_server_cert_cb_t cb, /* I - Callback function */
+ void *user_data) /* I - User data pointer */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ cg->server_cert_cb = cb;
+ cg->server_cert_data = user_data;
+}
+
+
+/*
+ * 'cupsSetUser()' - Set the default user name.
+ *
+ * Pass @code NULL@ to restore the default user name.
+ *
+ * Note: The current user name is tracked separately for each thread in a
+ * program. Multi-threaded programs that override the user name need to do so
+ * in each thread for the same user name to be used.
+ */
+
+void
+cupsSetUser(const char *user) /* I - User name */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ if (user)
+ strlcpy(cg->user, user, sizeof(cg->user));
+ else
+ cg->user[0] = '\0';
+}
+
+
+/*
+ * 'cupsUser()' - Return the current user's name.
+ *
+ * Note: The current user name is tracked separately for each thread in a
+ * program. Multi-threaded programs that override the user name with the
+ * @link cupsSetUser@ function need to do so in each thread for the same user
+ * name to be used.
+ */
+
+const char * /* O - User name */
+cupsUser(void)
+{
+ const char *user; /* USER environment variable */
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ if (!cg->user[0])
+ {
+#ifdef WIN32
+ /*
+ * Get the current user name from the OS...
+ */
+
+ DWORD size; /* Size of string */
+
+ size = sizeof(cg->user);
+ if (!GetUserName(cg->user, &size))
+#else
+ /*
+ * Get the user name corresponding to the current UID...
+ */
+
+ struct passwd *pwd; /* User/password entry */
+
+ setpwent();
+ if ((pwd = getpwuid(getuid())) != NULL)
+ {
+ /*
+ * Found a match!
+ */
+
+ strlcpy(cg->user, pwd->pw_name, sizeof(cg->user));
+ }
+ else
+#endif /* WIN32 */
+ if ((user = getenv("USER")) != NULL)
+ {
+ /*
+ * Use the username from the "USER" environment variable...
+ */
+ strlcpy(cg->user, user, sizeof(cg->user));
+ }
+ else
+ {
+ /*
+ * Use the default "unknown" user name...
+ */
+
+ strcpy(cg->user, "unknown");
+ }
+ }
+
+ return (cg->user);
+}
+
+
+/*
+ * '_cupsGetPassword()' - Get a password from the user.
+ */
+
+const char * /* O - Password */
+_cupsGetPassword(const char *prompt) /* I - Prompt string */
+{
+#ifdef WIN32
+ /*
+ * Currently no console password support is provided on Windows.
+ */
+
+ return (NULL);
+
+#else
+ /*
+ * Use the standard getpass function to get a password from the console. An
+ * empty password is treated as canceling the authentication request.
+ */
+
+ const char *password = getpass(prompt);
+ /* Password string */
+
+ if (!password || !password[0])
+ return (NULL);
+ else
+ return (password);
+#endif /* WIN32 */
+}
+
+
+#ifdef HAVE_GSSAPI
+/*
+ * '_cupsGSSServiceName()' - Get the GSS (Kerberos) service name.
+ */
+
+const char *
+_cupsGSSServiceName(void)
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Thread globals */
+
+
+ if (!cg->gss_service_name[0])
+ _cupsSetDefaults();
+
+ return (cg->gss_service_name);
+}
+#endif /* HAVE_GSSAPI */
+
+
+/*
+ * '_cupsSetDefaults()' - Set the default server, port, and encryption.
+ */
+
+void
+_cupsSetDefaults(void)
+{
+ cups_file_t *fp; /* File */
+ const char *home, /* Home directory of user */
+ *cups_encryption, /* CUPS_ENCRYPTION env var */
+ *cups_server, /* CUPS_SERVER env var */
+#ifdef HAVE_GSSAPI
+ *cups_gssservicename, /* CUPS_GSSSERVICENAME env var */
+#endif /* HAVE_GSSAPI */
+ *cups_anyroot, /* CUPS_ANYROOT env var */
+ *cups_expiredroot, /* CUPS_EXPIREDROOT env var */
+ *cups_expiredcerts; /* CUPS_EXPIREDCERTS env var */
+ char filename[1024]; /* Filename */
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ DEBUG_puts("_cupsSetDefaults()");
+
+ /*
+ * First collect environment variables...
+ */
+
+ cups_encryption = getenv("CUPS_ENCRYPTION");
+ cups_server = getenv("CUPS_SERVER");
+#ifdef HAVE_GSSAPI
+ cups_gssservicename = getenv("CUPS_GSSSERVICENAME");
+#endif /* HAVE_GSSAPI */
+ cups_anyroot = getenv("CUPS_ANYROOT");
+ cups_expiredroot = getenv("CUPS_EXPIREDROOT");
+ cups_expiredcerts = getenv("CUPS_EXPIREDCERTS");
+
+ /*
+ * Then, if needed, read the ~/.cups/client.conf or /etc/cups/client.conf
+ * files to get the default values...
+ */
+
+ if (cg->encryption == (http_encryption_t)-1 || !cg->server[0] ||
+ !cg->ipp_port)
+ {
+ if ((home = getenv("HOME")) != NULL)
+ {
+ /*
+ * Look for ~/.cups/client.conf...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/.cups/client.conf", home);
+ fp = cupsFileOpen(filename, "r");
+ }
+ else
+ fp = NULL;
+
+ if (!fp)
+ {
+ /*
+ * Look for CUPS_SERVERROOT/client.conf...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/client.conf",
+ cg->cups_serverroot);
+ fp = cupsFileOpen(filename, "r");
+ }
+
+ /*
+ * Read the configuration file and apply any environment variables; both
+ * functions handle NULL cups_file_t pointers...
+ */
+
+ cups_read_client_conf(fp, cg, cups_encryption, cups_server,
+#ifdef HAVE_GSSAPI
+ cups_gssservicename,
+#endif /* HAVE_GSSAPI */
+ cups_anyroot, cups_expiredroot,
+ cups_expiredcerts);
+ cupsFileClose(fp);
+ }
+}
+
+
+/*
+ * 'cups_read_client_conf()' - Read a client.conf file.
+ */
+
+static void
+cups_read_client_conf(
+ cups_file_t *fp, /* I - File to read */
+ _cups_globals_t *cg, /* I - Global data */
+ const char *cups_encryption, /* I - CUPS_ENCRYPTION env var */
+ const char *cups_server, /* I - CUPS_SERVER env var */
+#ifdef HAVE_GSSAPI
+ const char *cups_gssservicename,
+ /* I - CUPS_GSSSERVICENAME env var */
+#endif /* HAVE_GSSAPI */
+ const char *cups_anyroot, /* I - CUPS_ANYROOT env var */
+ const char *cups_expiredroot, /* I - CUPS_EXPIREDROOT env var */
+ const char *cups_expiredcerts) /* I - CUPS_EXPIREDCERTS env var */
+{
+ int linenum; /* Current line number */
+ char line[1024], /* Line from file */
+ *value, /* Pointer into line */
+ encryption[1024], /* Encryption value */
+ server_name[1024], /* ServerName value */
+ any_root[1024], /* AllowAnyRoot value */
+ expired_root[1024], /* AllowExpiredRoot value */
+ expired_certs[1024]; /* AllowExpiredCerts value */
+#ifdef HAVE_GSSAPI
+ char gss_service_name[32]; /* GSSServiceName value */
+#endif /* HAVE_GSSAPI */
+
+
+ /*
+ * Read from the file...
+ */
+
+ linenum = 0;
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ if (!cups_encryption && cg->encryption == (http_encryption_t)-1 &&
+ !_cups_strcasecmp(line, "Encryption") && value)
+ {
+ strlcpy(encryption, value, sizeof(encryption));
+ cups_encryption = encryption;
+ }
+ else if (!cups_server && (!cg->server[0] || !cg->ipp_port) &&
+ !_cups_strcasecmp(line, "ServerName") && value)
+ {
+ strlcpy(server_name, value, sizeof(server_name));
+ cups_server = server_name;
+ }
+ else if (!cups_anyroot && !_cups_strcasecmp(line, "AllowAnyRoot") && value)
+ {
+ strlcpy(any_root, value, sizeof(any_root));
+ cups_anyroot = any_root;
+ }
+ else if (!cups_expiredroot && !_cups_strcasecmp(line, "AllowExpiredRoot") &&
+ value)
+ {
+ strlcpy(expired_root, value, sizeof(expired_root));
+ cups_expiredroot = expired_root;
+ }
+ else if (!cups_expiredcerts && !_cups_strcasecmp(line, "AllowExpiredCerts") &&
+ value)
+ {
+ strlcpy(expired_certs, value, sizeof(expired_certs));
+ cups_expiredcerts = expired_certs;
+ }
+#ifdef HAVE_GSSAPI
+ else if (!cups_gssservicename && !_cups_strcasecmp(line, "GSSServiceName") &&
+ value)
+ {
+ strlcpy(gss_service_name, value, sizeof(gss_service_name));
+ cups_gssservicename = gss_service_name;
+ }
+#endif /* HAVE_GSSAPI */
+ }
+
+ /*
+ * Set values...
+ */
+
+ if (cg->encryption == (http_encryption_t)-1 && cups_encryption)
+ {
+ if (!_cups_strcasecmp(cups_encryption, "never"))
+ cg->encryption = HTTP_ENCRYPT_NEVER;
+ else if (!_cups_strcasecmp(cups_encryption, "always"))
+ cg->encryption = HTTP_ENCRYPT_ALWAYS;
+ else if (!_cups_strcasecmp(cups_encryption, "required"))
+ cg->encryption = HTTP_ENCRYPT_REQUIRED;
+ else
+ cg->encryption = HTTP_ENCRYPT_IF_REQUESTED;
+ }
+
+ if ((!cg->server[0] || !cg->ipp_port) && cups_server)
+ {
+ if (!cg->server[0])
+ {
+ /*
+ * Copy server name...
+ */
+
+ strlcpy(cg->server, cups_server, sizeof(cg->server));
+
+ if (cg->server[0] != '/' && (value = strrchr(cg->server, ':')) != NULL &&
+ !strchr(value, ']') && isdigit(value[1] & 255))
+ *value++ = '\0';
+ else
+ value = NULL;
+
+ if (cg->server[0] == '/')
+ strcpy(cg->servername, "localhost");
+ else
+ strlcpy(cg->servername, cg->server, sizeof(cg->servername));
+ }
+ else if (cups_server[0] != '/' &&
+ (value = strrchr(cups_server, ':')) != NULL &&
+ !strchr(value, ']') && isdigit(value[1] & 255))
+ value ++;
+ else
+ value = NULL;
+
+ if (!cg->ipp_port && value)
+ cg->ipp_port = atoi(value);
+ }
+
+ if (!cg->server[0])
+ {
+#ifdef CUPS_DEFAULT_DOMAINSOCKET
+ /*
+ * If we are compiled with domain socket support, only use the
+ * domain socket if it exists and has the right permissions...
+ */
+
+ struct stat sockinfo; /* Domain socket information */
+
+ if (!stat(CUPS_DEFAULT_DOMAINSOCKET, &sockinfo) &&
+ (sockinfo.st_mode & S_IRWXO) == S_IRWXO)
+ cups_server = CUPS_DEFAULT_DOMAINSOCKET;
+ else
+#endif /* CUPS_DEFAULT_DOMAINSOCKET */
+ cups_server = "localhost";
+
+ cupsSetServer(cups_server);
+ }
+
+ if (!cg->ipp_port)
+ {
+ const char *ipp_port; /* IPP_PORT environment variable */
+
+ if ((ipp_port = getenv("IPP_PORT")) != NULL)
+ {
+ if ((cg->ipp_port = atoi(ipp_port)) <= 0)
+ cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
+ }
+ else
+ cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
+ }
+
+#ifdef HAVE_GSSAPI
+ if (!cups_gssservicename)
+ cups_gssservicename = CUPS_DEFAULT_GSSSERVICENAME;
+
+ strlcpy(cg->gss_service_name, cups_gssservicename,
+ sizeof(cg->gss_service_name));
+#endif /* HAVE_GSSAPI */
+
+ if (cups_anyroot)
+ cg->any_root = !_cups_strcasecmp(cups_anyroot, "yes") ||
+ !_cups_strcasecmp(cups_anyroot, "on") ||
+ !_cups_strcasecmp(cups_anyroot, "true");
+
+ if (cups_expiredroot)
+ cg->expired_root = !_cups_strcasecmp(cups_expiredroot, "yes") ||
+ !_cups_strcasecmp(cups_expiredroot, "on") ||
+ !_cups_strcasecmp(cups_expiredroot, "true");
+
+ if (cups_expiredcerts)
+ cg->expired_certs = !_cups_strcasecmp(cups_expiredcerts, "yes") ||
+ !_cups_strcasecmp(cups_expiredcerts, "on") ||
+ !_cups_strcasecmp(cups_expiredcerts, "true");
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/utf8demo.txt b/cups/utf8demo.txt
new file mode 100644
index 000000000..03802e4d7
--- /dev/null
+++ b/cups/utf8demo.txt
@@ -0,0 +1,213 @@
+UTF-8 encoded sample plain-text file
+‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+
+Markus Kuhn [ˈmaʳkÊŠs kuËn] <mkuhn@acm.org> — 2002-07-25
+
+
+The ASCII compatible UTF-8 encoding used in this plain-text file
+is defined in Unicode, ISO 10646-1, and RFC 2279.
+
+
+Using Unicode/UTF-8, you can write in emails and source code things such as
+
+Mathematics and sciences:
+
+ ∮ Eâ‹…da = Q, n → ∞, ∑ f(i) = ∠g(i), ⎧⎡⎛┌─────â”⎞⎤⎫
+ ⎪⎢⎜│a²+b³ ⎟⎥⎪
+ ∀x∈â„: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β), ⎪⎢⎜│───── ⎟⎥⎪
+ ⎪⎢⎜⎷ c₈ ⎟⎥⎪
+ ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℠⊂ ℂ, ⎨⎢⎜ ⎟⎥⎬
+ ⎪⎢⎜ ∞ ⎟⎥⎪
+ ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (⟦A⟧ ⇔ ⟪B⟫), ⎪⎢⎜ ⎲ ⎟⎥⎪
+ ⎪⎢⎜ ⎳aâ±-bâ±âŽŸâŽ¥âŽª
+ 2Hâ‚‚ + Oâ‚‚ ⇌ 2Hâ‚‚O, R = 4.7 kΩ, ⌀ 200 mm ⎩⎣âŽi=1 ⎠⎦⎭
+
+Linguistics and dictionaries:
+
+ ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn
+ Y [ˈÊpsilÉ”n], Yen [jÉ›n], Yoga [ˈjoËgÉ‘]
+
+APL:
+
+ ((Vâ³V)=â³â´V)/Vâ†,V ⌷â†â³â†’â´âˆ†âˆ‡âŠƒâ€¾âŽâ•âŒˆ
+
+Nicer typography in plain text files:
+
+ â•”â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•—
+ â•‘ â•‘
+ ║ • ‘single’ and “double†quotes ║
+ â•‘ â•‘
+ ║ • Curly apostrophes: “We’ve been here†║
+ â•‘ â•‘
+ ║ • Latin-1 apostrophe and accents: '´` ║
+ â•‘ â•‘
+ ║ • ‚deutsche‘ „Anführungszeichen“ ║
+ â•‘ â•‘
+ ║ • †, ‡, ‰, •, 3–4, —, −5/+5, ™, … ║
+ â•‘ â•‘
+ ║ • ASCII safety test: 1lI|, 0OD, 8B ║
+ ║ ╭─────────╮ ║
+ ║ • the euro symbol: │ 14.95 € │ ║
+ ║ ╰─────────╯ ║
+ â•šâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
+
+Combining characters:
+
+ STARGΛ̊TE SG-1, a = v̇ = r̈, a⃑ ⊥ b⃑
+
+Greek (in Polytonic):
+
+ The Greek anthem:
+
+ Σὲ γνωÏίζω ἀπὸ τὴν κόψη
+ τοῦ σπαθιοῦ τὴν Ï„ÏομεÏá½µ,
+ σὲ γνωÏίζω ἀπὸ τὴν ὄψη
+ ποὺ μὲ βία μετÏάει Ï„á½´ γῆ.
+
+ ᾿Απ᾿ τὰ κόκκαλα βγαλμένη
+ τῶν ῾Ελλήνων Ï„á½° ἱεÏá½±
+ καὶ σὰν Ï€Ïῶτα ἀνδÏειωμένη
+ χαῖÏε, ὦ χαῖÏε, ᾿ΕλευθεÏιά!
+
+ From a speech of Demosthenes in the 4th century BC:
+
+ Οá½Ï‡á½¶ ταá½Ï„á½° παÏίσταταί μοι γιγνώσκειν, ὦ ἄνδÏες ᾿Αθηναῖοι,
+ ὅταν τ᾿ εἰς Ï„á½° Ï€Ïάγματα ἀποβλέψω καὶ ὅταν Ï€Ïὸς τοὺς
+ λόγους οὓς ἀκούω· τοὺς μὲν Î³á½°Ï Î»á½¹Î³Î¿Ï…Ï‚ πεÏὶ τοῦ
+ τιμωÏήσασθαι Φίλιππον á½Ïῶ γιγνομένους, Ï„á½° δὲ Ï€Ïάγματ᾿
+ εἰς τοῦτο Ï€Ïοήκοντα, ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αá½Ï„οὶ
+ Ï€ÏότεÏον κακῶς σκέψασθαι δέον. οá½Î´á½³Î½ οὖν ἄλλο μοι δοκοῦσιν
+ οἱ Ï„á½° τοιαῦτα λέγοντες á¼¢ τὴν ὑπόθεσιν, πεÏὶ ἧς βουλεύεσθαι,
+ οá½Ï‡á½¶ τὴν οὖσαν παÏιστάντες ὑμῖν á¼Î¼Î±Ïτάνειν. á¼Î³á½¼ δέ, ὅτι μέν
+ ποτ᾿ á¼Î¾á¿†Î½ τῇ πόλει καὶ Ï„á½° αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον
+ τιμωÏήσασθαι, καὶ μάλ᾿ ἀκÏιβῶς οἶδα· á¼Ï€á¾¿ á¼Î¼Î¿á¿¦ γάÏ, οὠπάλαι
+ γέγονεν ταῦτ᾿ ἀμφότεÏα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν
+ Ï€Ïολαβεῖν ἡμῖν εἶναι τὴν Ï€Ïώτην, ὅπως τοὺς συμμάχους
+ σώσομεν. á¼á½°Î½ Î³á½°Ï Ï„Î¿á¿¦Ï„Î¿ βεβαίως ὑπάÏξῃ, τότε καὶ πεÏὶ τοῦ
+ τίνα τιμωÏήσεταί τις καὶ ὃν Ï„Ïόπον á¼Î¾á½³ÏƒÏ„αι σκοπεῖν· Ï€Ïὶν δὲ
+ τὴν á¼€Ïχὴν á½€Ïθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι πεÏὶ τῆς
+ τελευτῆς á½Î½Ï„ινοῦν ποιεῖσθαι λόγον.
+
+ Δημοσθένους, Γ´ ᾿Ολυνθιακὸς
+
+Georgian:
+
+ From a Unicode conference invitation:
+
+ გთხáƒáƒ•áƒ— áƒáƒ®áƒšáƒáƒ•áƒ” გáƒáƒ˜áƒáƒ áƒáƒ— რეგისტრáƒáƒªáƒ˜áƒ Unicode-ის მეáƒáƒ—ე სáƒáƒ”რთáƒáƒ¨áƒáƒ áƒ˜áƒ¡áƒ
+ კáƒáƒœáƒ¤áƒ”რენციáƒáƒ–ე დáƒáƒ¡áƒáƒ¡áƒ¬áƒ áƒ”ბáƒáƒ“, რáƒáƒ›áƒ”ლიც გáƒáƒ˜áƒ›áƒáƒ áƒ—ებრ10-12 მáƒáƒ áƒ¢áƒ¡,
+ ქ. მáƒáƒ˜áƒœáƒªáƒ¨áƒ˜, გერმáƒáƒœáƒ˜áƒáƒ¨áƒ˜. კáƒáƒœáƒ¤áƒ”რენცირშეჰკრებს ერთáƒáƒ“ მსáƒáƒ¤áƒšáƒ˜áƒáƒ¡
+ ექსპერტებს ისეთ დáƒáƒ áƒ’ებში რáƒáƒ’áƒáƒ áƒ˜áƒªáƒáƒ ინტერნეტი დრUnicode-ი,
+ ინტერნáƒáƒªáƒ˜áƒáƒœáƒáƒšáƒ˜áƒ–áƒáƒªáƒ˜áƒ დრლáƒáƒ™áƒáƒšáƒ˜áƒ–áƒáƒªáƒ˜áƒ, Unicode-ის გáƒáƒ›áƒáƒ§áƒ”ნებáƒ
+ áƒáƒžáƒ”რáƒáƒªáƒ˜áƒ£áƒš სისტემებსáƒ, დრგáƒáƒ›áƒáƒ§áƒ”ნებით პრáƒáƒ’რáƒáƒ›áƒ”ბში, შრიფტებში,
+ ტექსტების დáƒáƒ›áƒ£áƒ¨áƒáƒ•áƒ”ბáƒáƒ¡áƒ დრმრáƒáƒ•áƒáƒšáƒ”ნáƒáƒ•áƒáƒœ კáƒáƒ›áƒžáƒ˜áƒ£áƒ¢áƒ”რულ სისტემებში.
+
+Russian:
+
+ From a Unicode conference invitation:
+
+ ЗарегиÑтрируйтеÑÑŒ ÑÐµÐ¹Ñ‡Ð°Ñ Ð½Ð° ДеÑÑтую Международную Конференцию по
+ Unicode, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÑоÑтоитÑÑ 10-12 марта 1997 года в Майнце в Германии.
+ ÐšÐ¾Ð½Ñ„ÐµÑ€ÐµÐ½Ñ†Ð¸Ñ Ñоберет широкий круг ÑкÑпертов по вопроÑам глобального
+ Интернета и Unicode, локализации и интернационализации, воплощению и
+ применению Unicode в различных операционных ÑиÑтемах и программных
+ приложениÑÑ…, шрифтах, верÑтке и многоÑзычных компьютерных ÑиÑтемах.
+
+Thai (UCS Level 2):
+
+ Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese
+ classic 'San Gua'):
+
+ [----------------------------|------------------------]
+ ๠à¹à¸œà¹ˆà¸™à¸”ินฮั่นเสื่อมโทรมà¹à¸ªà¸™à¸ªà¸±à¸‡à¹€à¸§à¸Š พระปà¸à¹€à¸à¸¨à¸à¸­à¸‡à¸šà¸¹à¹Šà¸à¸¹à¹‰à¸‚ึ้นใหม่
+ สิบสองà¸à¸©à¸±à¸•à¸£à¸´à¸¢à¹Œà¸à¹ˆà¸­à¸™à¸«à¸™à¹‰à¸²à¹à¸¥à¸–ัดไป สององค์ไซร้โง่เขลาเบาปัà¸à¸à¸²
+ ทรงนับถือขันทีเป็นที่พึ่ง บ้านเมืองจึงวิปริตเป็นนัà¸à¸«à¸™à¸²
+ โฮจิ๋นเรียà¸à¸—ัพทั่วหัวเมืองมา หมายจะฆ่ามดชั่วตัวสำคัà¸
+ เหมือนขับไสไล่เสือจาà¸à¹€à¸„หา รับหมาป่าเข้ามาเลยอาสัà¸
+ à¸à¹ˆà¸²à¸¢à¸­à¹‰à¸­à¸‡à¸­à¸¸à¹‰à¸™à¸¢à¸¸à¹à¸¢à¸à¹ƒà¸«à¹‰à¹à¸•à¸à¸à¸±à¸™ ใช้สาวนั้นเป็นชนวนชื่นชวนใจ
+ พลันลิฉุยà¸à¸¸à¸¢à¸à¸µà¸à¸¥à¸±à¸šà¸à¹ˆà¸­à¹€à¸«à¸•à¸¸ ช่างอาเพศจริงหนาฟ้าร้องไห้
+ ต้องรบราฆ่าฟันจนบรรลัย ฤๅหาใครค้ำชูà¸à¸¹à¹‰à¸šà¸£à¸£à¸¥à¸±à¸‡à¸à¹Œ ฯ
+
+ (The above is a two-column text. If combining characters are handled
+ correctly, the lines of the second column should be aligned with the
+ | character above.)
+
+Ethiopian:
+
+ Proverbs in the Amharic language:
+
+ ሰማይ አይታረስ ንጉሥ አይከሰስá¢
+ ብላ ካለአእንደአባቴ በቆመጠáŠá¢
+ ጌጥ ያለቤቱ á‰áˆáŒ¥áŠ“ áŠá‹á¢
+ ደሀ በሕáˆáˆ™ ቅቤ ባይጠጣ ንጣት በገደለá‹á¢
+ የአá ወለáˆá‰³ በቅቤ አይታሽáˆá¢
+ አይጥ በበላ ዳዋ ተመታá¢
+ ሲተረጉሙ ይደረáŒáˆ™á¢
+ ቀስ በቀስᥠዕንá‰áˆ‹áˆ በእáŒáˆ© ይሄዳáˆá¢
+ ድር ቢያብር አንበሳ ያስርá¢
+ ሰዠእንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርáˆá¢
+ እáŒá‹œáˆ­ የከáˆá‰°á‹áŠ• ጉሮሮ ሳይዘጋዠአይድርáˆá¢
+ የጎረቤት ሌባᥠቢያዩት ይስቅ ባያዩት ያጠáˆá‰…á¢
+ ሥራ ከመáታት áˆáŒ„ን ላá‹á‰³á‰µá¢
+ ዓባይ ማደሪያ የለá‹á¥ áŒáŠ•á‹µ á‹­á‹ž ይዞራáˆá¢
+ የእስላሠአገሩ መካ የአሞራ አገሩ ዋርካá¢
+ ተንጋሎ ቢተበተመáˆáˆ¶ ባá‰á¢
+ ወዳጅህ ማር ቢሆን ጨርስህ አትላሰá‹á¢
+ እáŒáˆ­áˆ…ን በáራሽህ áˆáŠ­ ዘርጋá¢
+
+Runes:
+
+ ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛠᚻᛖ ᛒᚢᛞᛖ áš©áš¾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ áš¹á›áš¦ ᚦᚪ ᚹᛖᛥᚫ
+
+ (Old English, which transcribed into Latin reads 'He cwaeth that he
+ bude thaem lande northweardum with tha Westsae.' and means 'He said
+ that he lived in the northern land near the Western Sea.')
+
+Braille:
+
+ â¡Œâ â §â ‘ â ¼â â ’ â¡â œâ ‡â ‘⠹⠰⠎ ⡣⠕⠌
+
+ â¡â œâ ‡â ‘â ¹ â ºâ â Ž ⠙⠑â â ™â ’ â žâ • ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ â Šâ Ž â â • ⠙⠳⠃⠞
+ â ±â â žâ ‘⠧⠻ â â ƒâ ³â ž â ¹â â žâ ² ⡹⠑ ⠗⠑⠛⠊⠌⠻ â •â ‹ ⠙⠊⠎ ⠃⠥⠗⠊â â ‡ â ºâ â Ž
+ â Žâ Šâ ›â â « ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹â â â â ‚ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ â ¥â â ™â »â žâ â …⠻⠂
+ â â â ™ ⠹⠑ â ¡â Šâ ‘â ‹ â â ³â —â â »â ² ⡎⠊⠗⠕⠕⠛⠑ â Žâ Šâ ›â â « â Šâ žâ ² â¡â â ™
+ ⡎⠊⠗⠕⠕⠛⠑⠰⠎ â â â â ‘ â ºâ â Ž ⠛⠕⠕⠙ â ¥â â •â  â °â¡¡â â â ›â ‘â ‚ â ‹â •â — â â â ¹â ¹â ”â › ⠙⠑
+ â ¡â •â Žâ ‘ â žâ • â â ¥â ž ⠙⠊⠎ â ™â â â ™ â žâ •â ²
+
+ ⡕⠇⠙ â¡â œâ ‡â ‘â ¹ â ºâ â Ž â â Ž ⠙⠑â â ™ â â Ž â  â ™â •â •â —â ¤â â â Šâ ‡â ²
+
+ â¡â ”⠙⠖ â¡Š ⠙⠕â â °â ž â â ‘â â  â žâ • â Žâ â ¹ â ¹â â ž â¡Š â …â â ªâ ‚ â •â ‹ â â ¹
+ â ªâ  â …â â ªâ ‡â «â ›â ‘â ‚ â ±â â ž ⠹⠻⠑ â Šâ Ž â â œâ žâ Šâ Šâ ¥â ‡â œâ ‡â ¹ ⠙⠑â â ™ â â ƒâ ³â ž
+ â  â ™â •â •â —â ¤â â â Šâ ‡â ² â¡Š â â Šâ £â ž â ™â â §â ‘ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ â â ¹â Žâ ‘⠇⠋⠂ â žâ •
+ ⠗⠑⠛⠜⠙ â  â Šâ •â ‹â ‹â ”â ¤â â â Šâ ‡ â â Ž ⠹⠑ ⠙⠑â â ™â ‘â Œ â â Šâ ‘â Šâ ‘ â •â ‹ â Šâ —â •â â â •â â ›â »â ¹
+ â ” ⠹⠑ â žâ —â â ™â ‘â ² ⡃⠥⠞ ⠹⠑ â ºâ Šâ Žâ ™â •â  â •â ‹ ⠳⠗ â â â Šâ ‘⠌⠕⠗⠎
+ â Šâ Ž â ” ⠹⠑ â Žâ Šâ â Šâ ‡â ‘â † â â â ™ â â ¹ â ¥â â ™â â ‡â ‡â ªâ « â ™â â â ™â Ž
+ â ©â â ‡â ‡ â â •â ž ⠙⠊⠌⠥⠗⠃ â Šâ žâ ‚ â •â — ⠹⠑ â¡Šâ ³â â žâ —⠹⠰⠎ ⠙⠕â â ‘ â ‹â •â —â ² ⡹⠳
+ ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ â â »â â Šâ ž â â ‘ â žâ • â —â ‘â â ‘â â žâ ‚ â ‘â â â ™â â žâ Šâ Šâ â ‡â ‡â ¹â ‚ â ¹â â ž
+ â¡â œâ ‡â ‘â ¹ â ºâ â Ž â â Ž ⠙⠑â â ™ â â Ž â  â ™â •â •â —â ¤â â â Šâ ‡â ²
+
+ (The first couple of paragraphs of "A Christmas Carol" by Dickens)
+
+Compact font selection example text:
+
+ ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789
+ abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ
+ –—‘“â€â€žâ€ â€¢â€¦â€°â„¢Å“ŠŸž€ ΑΒΓΔΩαβγδω ÐБВГДабвгд
+ ∀∂∈â„∧∪≡∞ ↑↗↨↻⇣ â”┼╔╘░►☺♀ ï¬?⑀₂ἠḂӥẄÉËâŽ×Ô±áƒ
+
+Greetings in various languages:
+
+ Hello world, ΚαλημέÏα κόσμε, コンニãƒãƒ
+
+Box drawing alignment tests: â–ˆ
+ â–‰
+ â•”â•â•â•¦â•â•â•— ┌──┬──┠╭──┬──╮ ╭──┬──╮ â”â”â”┳â”â”┓ ┎┒â”┑ â•· â•» â”┯┓ ┌┰┠▊ ╱╲╱╲╳╳╳
+ ║┌─╨─â”â•‘ │╔â•â•§â•â•—│ │╒â•â•ªâ•â••â”‚ │╓─â•â”€â•–│ ┃┌─╂─â”┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ â”╋┥ â–‹ ╲╱╲╱╳╳╳
+ ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ â•¿ │┃ â”╅╆┓ ╵ ╹ â”—â”·â”› └┸┘ â–Œ ╱╲╱╲╳╳╳
+ â• â•¡ ╳ â•žâ•£ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┠╎ â”┅┅┓ ┋ ■╲╱╲╱╳╳╳
+ ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╠┇ ┋ ▎
+ ║└─╥─┘║ │╚â•â•¤â•â•â”‚ │╘â•â•ªâ•â•›â”‚ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ â•Ž ╠┇ ┋ â–
+ â•šâ•â•â•©â•â•â• └──┴──┘ ╰──┴──╯ ╰──┴──╯ â”—â”â”â”»â”â”â”› ▗▄▖▛▀▜ └╌╌┘ â•Ž â”—â•â•â”› ┋ â–▂▃▄▅▆▇█
+ â–▀▘▙▄▟
+
+
diff --git a/cups/util.c b/cups/util.c
new file mode 100644
index 000000000..5fd3fe197
--- /dev/null
+++ b/cups/util.c
@@ -0,0 +1,1800 @@
+/*
+ * "$Id$"
+ *
+ * Printing utilities for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsCancelJob() - Cancel a print job on the default server.
+ * cupsCancelJob2() - Cancel or purge a print job.
+ * cupsCreateJob() - Create an empty job for streaming.
+ * cupsFinishDocument() - Finish sending a document.
+ * cupsFreeJobs() - Free memory used by job data.
+ * cupsGetClasses() - Get a list of printer classes from the default
+ * server.
+ * cupsGetDefault() - Get the default printer or class for the default
+ * server.
+ * cupsGetDefault2() - Get the default printer or class for the specified
+ * server.
+ * cupsGetJobs() - Get the jobs from the default server.
+ * cupsGetJobs2() - Get the jobs from the specified server.
+ * cupsGetPPD() - Get the PPD file for a printer on the default
+ * server.
+ * cupsGetPPD2() - Get the PPD file for a printer from the specified
+ * server.
+ * cupsGetPPD3() - Get the PPD file for a printer on the specified
+ * server if it has changed.
+ * cupsGetPrinters() - Get a list of printers from the default server.
+ * cupsGetServerPPD() - Get an available PPD file from the server.
+ * cupsPrintFile() - Print a file to a printer or class on the default
+ * server.
+ * cupsPrintFile2() - Print a file to a printer or class on the
+ * specified server.
+ * cupsPrintFiles() - Print one or more files to a printer or class on
+ * the default server.
+ * cupsPrintFiles2() - Print one or more files to a printer or class on
+ * the specified server.
+ * cupsStartDocument() - Add a document to a job created with
+ * cupsCreateJob().
+ * cups_get_printer_uri() - Get the printer-uri-supported attribute for the
+ * first printer in a class.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cups-private.h"
+#include <fcntl.h>
+#include <sys/stat.h>
+#if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+#else
+# include <unistd.h>
+#endif /* WIN32 || __EMX__ */
+
+
+/*
+ * Local functions...
+ */
+
+static int cups_get_printer_uri(http_t *http, const char *name,
+ char *host, int hostsize, int *port,
+ char *resource, int resourcesize,
+ int depth);
+
+
+/*
+ * 'cupsCancelJob()' - Cancel a print job on the default server.
+ *
+ * Pass @code CUPS_JOBID_ALL@ to cancel all jobs or @code CUPS_JOBID_CURRENT@
+ * to cancel the current job on the named destination.
+ *
+ * Use the @link cupsLastError@ and @link cupsLastErrorString@ functions to get
+ * the cause of any failure.
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsCancelJob(const char *name, /* I - Name of printer or class */
+ int job_id) /* I - Job ID, @code CUPS_JOBID_CURRENT@ for the current job, or @code CUPS_JOBID_ALL@ for all jobs */
+{
+ return (cupsCancelJob2(CUPS_HTTP_DEFAULT, name, job_id, 0)
+ < IPP_REDIRECTION_OTHER_SITE);
+}
+
+
+/*
+ * 'cupsCancelJob2()' - Cancel or purge a print job.
+ *
+ * Canceled jobs remain in the job history while purged jobs are removed
+ * from the job history.
+ *
+ * Pass @code CUPS_JOBID_ALL@ to cancel all jobs or @code CUPS_JOBID_CURRENT@
+ * to cancel the current job on the named destination.
+ *
+ * Use the @link cupsLastError@ and @link cupsLastErrorString@ functions to get
+ * the cause of any failure.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+ipp_status_t /* O - IPP status */
+cupsCancelJob2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *name, /* I - Name of printer or class */
+ int job_id, /* I - Job ID, @code CUPS_JOBID_CURRENT@ for the current job, or @code CUPS_JOBID_ALL@ for all jobs */
+ int purge) /* I - 1 to purge, 0 to cancel */
+{
+ char uri[HTTP_MAX_URI]; /* Job/printer URI */
+ ipp_t *request; /* IPP request */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (job_id < -1 || (!name && job_id == 0))
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
+ return (0);
+ }
+
+ /*
+ * Connect to the default server as needed...
+ */
+
+ if (!http)
+ if ((http = _cupsConnect()) == NULL)
+ return (IPP_SERVICE_UNAVAILABLE);
+
+ /*
+ * Build an IPP_CANCEL_JOB or IPP_PURGE_JOBS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * job-uri or printer-uri + job-id
+ * requesting-user-name
+ * [purge-job] or [purge-jobs]
+ */
+
+ request = ippNewRequest(job_id < 0 ? IPP_PURGE_JOBS : IPP_CANCEL_JOB);
+
+ if (name)
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", ippPort(), "/printers/%s", name);
+
+ 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 if (job_id > 0)
+ {
+ snprintf(uri, sizeof(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());
+
+ if (purge && job_id >= 0)
+ ippAddBoolean(request, IPP_TAG_OPERATION, "purge-job", 1);
+ else if (!purge && job_id < 0)
+ ippAddBoolean(request, IPP_TAG_OPERATION, "purge-jobs", 0);
+
+ /*
+ * Do the request...
+ */
+
+ ippDelete(cupsDoRequest(http, request, "/jobs/"));
+
+ return (cupsLastError());
+}
+
+
+/*
+ * 'cupsCreateJob()' - Create an empty job for streaming.
+ *
+ * Use this function when you want to stream print data using the
+ * @link cupsStartDocument@, @link cupsWriteRequestData@, and
+ * @link cupsFinishDocument@ functions. If you have one or more files to
+ * print, use the @link cupsPrintFile2@ or @link cupsPrintFiles2@ function
+ * instead.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+int /* O - Job ID or 0 on error */
+cupsCreateJob(
+ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *name, /* I - Destination name */
+ const char *title, /* I - Title of job */
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ char printer_uri[1024], /* Printer URI */
+ resource[1024]; /* Printer resource */
+ ipp_t *request, /* Create-Job request */
+ *response; /* Create-Job response */
+ ipp_attribute_t *attr; /* job-id attribute */
+ int job_id = 0; /* job-id value */
+
+
+ DEBUG_printf(("cupsCreateJob(http=%p, name=\"%s\", title=\"%s\", "
+ "num_options=%d, options=%p)",
+ http, name, title, num_options, options));
+
+ /*
+ * Range check input...
+ */
+
+ if (!name)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
+ return (0);
+ }
+
+ /*
+ * Build a Create-Job request...
+ */
+
+ if ((request = ippNewRequest(IPP_CREATE_JOB)) == NULL)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(ENOMEM), 0);
+ return (0);
+ }
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), "ipp",
+ NULL, "localhost", ippPort(), "/printers/%s", name);
+ snprintf(resource, sizeof(resource), "/printers/%s", name);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, printer_uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+ if (title)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
+ title);
+ cupsEncodeOptions(request, num_options, options);
+
+ /*
+ * Send the request and get the job-id...
+ */
+
+ response = cupsDoRequest(http, request, resource);
+
+ if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL)
+ job_id = attr->values[0].integer;
+
+ ippDelete(response);
+
+ /*
+ * Return it...
+ */
+
+ return (job_id);
+}
+
+
+/*
+ * 'cupsFinishDocument()' - Finish sending a document.
+ *
+ * The document must have been started using @link cupsStartDocument@.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+ipp_status_t /* O - Status of document submission */
+cupsFinishDocument(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *name) /* I - Destination name */
+{
+ char resource[1024]; /* Printer resource */
+
+
+ snprintf(resource, sizeof(resource), "/printers/%s", name);
+
+ ippDelete(cupsGetResponse(http, resource));
+
+ return (cupsLastError());
+}
+
+
+/*
+ * 'cupsFreeJobs()' - Free memory used by job data.
+ */
+
+void
+cupsFreeJobs(int num_jobs, /* I - Number of jobs */
+ cups_job_t *jobs) /* I - Jobs */
+{
+ int i; /* Looping var */
+ cups_job_t *job; /* Current job */
+
+
+ if (num_jobs <= 0 || !jobs)
+ return;
+
+ for (i = num_jobs, job = jobs; i > 0; i --, job ++)
+ {
+ _cupsStrFree(job->dest);
+ _cupsStrFree(job->user);
+ _cupsStrFree(job->format);
+ _cupsStrFree(job->title);
+ }
+
+ free(jobs);
+}
+
+
+/*
+ * 'cupsGetClasses()' - Get a list of printer classes from the default server.
+ *
+ * This function is deprecated - use @link cupsGetDests@ instead.
+ *
+ * @deprecated@
+ */
+
+int /* O - Number of classes */
+cupsGetClasses(char ***classes) /* O - Classes */
+{
+ int n; /* Number of classes */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ char **temp; /* Temporary pointer */
+ http_t *http; /* Connection to server */
+
+
+ if (!classes)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
+
+ return (0);
+ }
+
+ *classes = NULL;
+
+ if ((http = _cupsConnect()) == NULL)
+ return (0);
+
+ /*
+ * Build a CUPS_GET_CLASSES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ */
+
+ request = ippNewRequest(CUPS_GET_CLASSES);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "printer-name");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ n = 0;
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ for (attr = response->attrs; attr != NULL; attr = attr->next)
+ if (attr->name != NULL &&
+ _cups_strcasecmp(attr->name, "printer-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ {
+ if (n == 0)
+ temp = malloc(sizeof(char *));
+ else
+ temp = realloc(*classes, sizeof(char *) * (n + 1));
+
+ if (temp == NULL)
+ {
+ /*
+ * Ran out of memory!
+ */
+
+ while (n > 0)
+ {
+ n --;
+ free((*classes)[n]);
+ }
+
+ free(*classes);
+ ippDelete(response);
+ return (0);
+ }
+
+ *classes = temp;
+ temp[n] = strdup(attr->values[0].string.text);
+ n ++;
+ }
+
+ ippDelete(response);
+ }
+
+ return (n);
+}
+
+
+/*
+ * 'cupsGetDefault()' - Get the default printer or class for the default server.
+ *
+ * This function returns the default printer or class as defined by
+ * the LPDEST or PRINTER environment variables. If these environment
+ * variables are not set, the server default destination is returned.
+ * Applications should use the @link cupsGetDests@ and @link cupsGetDest@
+ * functions to get the user-defined default printer, as this function does
+ * not support the lpoptions-defined default printer.
+ */
+
+const char * /* O - Default printer or @code NULL@ */
+cupsGetDefault(void)
+{
+ /*
+ * Return the default printer...
+ */
+
+ return (cupsGetDefault2(CUPS_HTTP_DEFAULT));
+}
+
+
+/*
+ * 'cupsGetDefault2()' - Get the default printer or class for the specified server.
+ *
+ * This function returns the default printer or class as defined by
+ * the LPDEST or PRINTER environment variables. If these environment
+ * variables are not set, the server default destination is returned.
+ * Applications should use the @link cupsGetDests@ and @link cupsGetDest@
+ * functions to get the user-defined default printer, as this function does
+ * not support the lpoptions-defined default printer.
+ *
+ * @since CUPS 1.1.21/Mac OS X 10.4@
+ */
+
+const char * /* O - Default printer or @code NULL@ */
+cupsGetDefault2(http_t *http) /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ /*
+ * See if we have a user default printer set...
+ */
+
+ if (_cupsUserDefault(cg->def_printer, sizeof(cg->def_printer)))
+ return (cg->def_printer);
+
+ /*
+ * Connect to the server as needed...
+ */
+
+ if (!http)
+ if ((http = _cupsConnect()) == NULL)
+ return (NULL);
+
+ /*
+ * Build a CUPS_GET_DEFAULT request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ */
+
+ request = ippNewRequest(CUPS_GET_DEFAULT);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ if ((attr = ippFindAttribute(response, "printer-name",
+ IPP_TAG_NAME)) != NULL)
+ {
+ strlcpy(cg->def_printer, attr->values[0].string.text,
+ sizeof(cg->def_printer));
+ ippDelete(response);
+ return (cg->def_printer);
+ }
+
+ ippDelete(response);
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * 'cupsGetJobs()' - Get the jobs from the default server.
+ *
+ * A "whichjobs" value of @code CUPS_WHICHJOBS_ALL@ returns all jobs regardless
+ * of state, while @code CUPS_WHICHJOBS_ACTIVE@ returns jobs that are
+ * pending, processing, or held and @code CUPS_WHICHJOBS_COMPLETED@ returns
+ * jobs that are stopped, canceled, aborted, or completed.
+ */
+
+int /* O - Number of jobs */
+cupsGetJobs(cups_job_t **jobs, /* O - Job data */
+ const char *name, /* I - @code NULL@ = all destinations, otherwise show jobs for named destination */
+ int myjobs, /* I - 0 = all users, 1 = mine */
+ int whichjobs) /* I - @code CUPS_WHICHJOBS_ALL@, @code CUPS_WHICHJOBS_ACTIVE@, or @code CUPS_WHICHJOBS_COMPLETED@ */
+{
+ /*
+ * Return the jobs...
+ */
+
+ return (cupsGetJobs2(CUPS_HTTP_DEFAULT, jobs, name, myjobs, whichjobs));
+}
+
+
+
+/*
+ * 'cupsGetJobs2()' - Get the jobs from the specified server.
+ *
+ * A "whichjobs" value of @code CUPS_WHICHJOBS_ALL@ returns all jobs regardless
+ * of state, while @code CUPS_WHICHJOBS_ACTIVE@ returns jobs that are
+ * pending, processing, or held and @code CUPS_WHICHJOBS_COMPLETED@ returns
+ * jobs that are stopped, canceled, aborted, or completed.
+ *
+ * @since CUPS 1.1.21/Mac OS X 10.4@
+ */
+
+int /* O - Number of jobs */
+cupsGetJobs2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ cups_job_t **jobs, /* O - Job data */
+ const char *name, /* I - @code NULL@ = all destinations, otherwise show jobs for named destination */
+ int myjobs, /* I - 0 = all users, 1 = mine */
+ int whichjobs) /* I - @code CUPS_WHICHJOBS_ALL@, @code CUPS_WHICHJOBS_ACTIVE@, or @code CUPS_WHICHJOBS_COMPLETED@ */
+{
+ int n; /* Number of jobs */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_job_t *temp; /* Temporary pointer */
+ int id, /* job-id */
+ priority, /* job-priority */
+ size; /* job-k-octets */
+ ipp_jstate_t state; /* job-state */
+ time_t completed_time, /* time-at-completed */
+ creation_time, /* time-at-creation */
+ processing_time; /* time-at-processing */
+ const char *dest, /* job-printer-uri */
+ *format, /* document-format */
+ *title, /* job-name */
+ *user; /* job-originating-user-name */
+ char uri[HTTP_MAX_URI]; /* URI for jobs */
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+ static const char * const attrs[] = /* Requested attributes */
+ {
+ "document-format",
+ "job-id",
+ "job-k-octets",
+ "job-name",
+ "job-originating-user-name",
+ "job-printer-uri",
+ "job-priority",
+ "job-state",
+ "time-at-completed",
+ "time-at-creation",
+ "time-at-processing"
+ };
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!jobs)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
+
+ return (-1);
+ }
+
+ /*
+ * Get the right URI...
+ */
+
+ if (name)
+ {
+ if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/printers/%s", name) != HTTP_URI_OK)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Unable to create printer-uri"), 1);
+
+ return (-1);
+ }
+ }
+ else
+ strcpy(uri, "ipp://localhost/");
+
+ if (!http)
+ if ((http = _cupsConnect()) == NULL)
+ return (-1);
+
+ /*
+ * Build an IPP_GET_JOBS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ * which-jobs
+ * my-jobs
+ * requested-attributes
+ */
+
+ request = ippNewRequest(IPP_GET_JOBS);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, cupsUser());
+
+ if (myjobs)
+ ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
+
+ if (whichjobs == CUPS_WHICHJOBS_COMPLETED)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "which-jobs", NULL, "completed");
+ else if (whichjobs == CUPS_WHICHJOBS_ALL)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "which-jobs", NULL, "all");
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(attrs) / sizeof(attrs[0]),
+ NULL, attrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ n = 0;
+ *jobs = NULL;
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ for (attr = response->attrs; attr; attr = attr->next)
+ {
+ /*
+ * Skip leading attributes until we hit a job...
+ */
+
+ while (attr && attr->group_tag != IPP_TAG_JOB)
+ attr = attr->next;
+
+ if (!attr)
+ break;
+
+ /*
+ * Pull the needed attributes from this job...
+ */
+
+ id = 0;
+ size = 0;
+ priority = 50;
+ state = IPP_JOB_PENDING;
+ user = "unknown";
+ dest = NULL;
+ format = "application/octet-stream";
+ title = "untitled";
+ creation_time = 0;
+ completed_time = 0;
+ processing_time = 0;
+
+ while (attr && attr->group_tag == IPP_TAG_JOB)
+ {
+ if (!strcmp(attr->name, "job-id") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ id = attr->values[0].integer;
+ else if (!strcmp(attr->name, "job-state") &&
+ attr->value_tag == IPP_TAG_ENUM)
+ state = (ipp_jstate_t)attr->values[0].integer;
+ else if (!strcmp(attr->name, "job-priority") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ priority = attr->values[0].integer;
+ else if (!strcmp(attr->name, "job-k-octets") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ size = attr->values[0].integer;
+ else if (!strcmp(attr->name, "time-at-completed") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ completed_time = attr->values[0].integer;
+ else if (!strcmp(attr->name, "time-at-creation") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ creation_time = attr->values[0].integer;
+ else if (!strcmp(attr->name, "time-at-processing") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ processing_time = attr->values[0].integer;
+ else if (!strcmp(attr->name, "job-printer-uri") &&
+ attr->value_tag == IPP_TAG_URI)
+ {
+ if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL)
+ dest ++;
+ }
+ else if (!strcmp(attr->name, "job-originating-user-name") &&
+ attr->value_tag == IPP_TAG_NAME)
+ user = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "document-format") &&
+ attr->value_tag == IPP_TAG_MIMETYPE)
+ format = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "job-name") &&
+ (attr->value_tag == IPP_TAG_TEXT ||
+ attr->value_tag == IPP_TAG_NAME))
+ title = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (!dest || !id)
+ {
+ if (!attr)
+ break;
+ else
+ continue;
+ }
+
+ /*
+ * Allocate memory for the job...
+ */
+
+ if (n == 0)
+ temp = malloc(sizeof(cups_job_t));
+ else
+ temp = realloc(*jobs, sizeof(cups_job_t) * (n + 1));
+
+ if (!temp)
+ {
+ /*
+ * Ran out of memory!
+ */
+
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
+
+ cupsFreeJobs(n, *jobs);
+ *jobs = NULL;
+
+ ippDelete(response);
+
+ return (-1);
+ }
+
+ *jobs = temp;
+ temp += n;
+ n ++;
+
+ /*
+ * Copy the data over...
+ */
+
+ temp->dest = _cupsStrAlloc(dest);
+ temp->user = _cupsStrAlloc(user);
+ temp->format = _cupsStrAlloc(format);
+ temp->title = _cupsStrAlloc(title);
+ temp->id = id;
+ temp->priority = priority;
+ temp->state = state;
+ temp->size = size;
+ temp->completed_time = completed_time;
+ temp->creation_time = creation_time;
+ temp->processing_time = processing_time;
+
+ if (!attr)
+ break;
+ }
+
+ ippDelete(response);
+ }
+
+ if (n == 0 && cg->last_error >= IPP_BAD_REQUEST)
+ return (-1);
+ else
+ return (n);
+}
+
+
+/*
+ * 'cupsGetPPD()' - Get the PPD file for a printer on the default server.
+ *
+ * For classes, @code cupsGetPPD@ returns the PPD file for the first printer
+ * in the class.
+ *
+ * The returned filename is stored in a static buffer and is overwritten with
+ * each call to @code cupsGetPPD@ or @link cupsGetPPD2@. The caller "owns" the
+ * file that is created and must @code unlink@ the returned filename.
+ */
+
+const char * /* O - Filename for PPD file */
+cupsGetPPD(const char *name) /* I - Destination name */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+ time_t modtime = 0; /* Modification time */
+
+
+ /*
+ * Return the PPD file...
+ */
+
+ cg->ppd_filename[0] = '\0';
+
+ if (cupsGetPPD3(CUPS_HTTP_DEFAULT, name, &modtime, cg->ppd_filename,
+ sizeof(cg->ppd_filename)) == HTTP_OK)
+ return (cg->ppd_filename);
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'cupsGetPPD2()' - Get the PPD file for a printer from the specified server.
+ *
+ * For classes, @code cupsGetPPD2@ returns the PPD file for the first printer
+ * in the class.
+ *
+ * The returned filename is stored in a static buffer and is overwritten with
+ * each call to @link cupsGetPPD@ or @code cupsGetPPD2@. The caller "owns" the
+ * file that is created and must @code unlink@ the returned filename.
+ *
+ * @since CUPS 1.1.21/Mac OS X 10.4@
+ */
+
+const char * /* O - Filename for PPD file */
+cupsGetPPD2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *name) /* I - Destination name */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+ time_t modtime = 0; /* Modification time */
+
+
+ cg->ppd_filename[0] = '\0';
+
+ if (cupsGetPPD3(http, name, &modtime, cg->ppd_filename,
+ sizeof(cg->ppd_filename)) == HTTP_OK)
+ return (cg->ppd_filename);
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'cupsGetPPD3()' - Get the PPD file for a printer on the specified
+ * server if it has changed.
+ *
+ * The "modtime" parameter contains the modification time of any
+ * locally-cached content and is updated with the time from the PPD file on
+ * the server.
+ *
+ * The "buffer" parameter contains the local PPD filename. If it contains
+ * the empty string, a new temporary file is created, otherwise the existing
+ * file will be overwritten as needed. The caller "owns" the file that is
+ * created and must @code unlink@ the returned filename.
+ *
+ * On success, @code HTTP_OK@ is returned for a new PPD file and
+ * @code HTTP_NOT_MODIFIED@ if the existing PPD file is up-to-date. Any other
+ * status is an error.
+ *
+ * For classes, @code cupsGetPPD3@ returns the PPD file for the first printer
+ * in the class.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+http_status_t /* O - HTTP status */
+cupsGetPPD3(http_t *http, /* I - HTTP connection or @code CUPS_HTTP_DEFAULT@ */
+ const char *name, /* I - Destination name */
+ time_t *modtime, /* IO - Modification time */
+ char *buffer, /* I - Filename buffer */
+ size_t bufsize) /* I - Size of filename buffer */
+{
+ int http_port; /* Port number */
+ char http_hostname[HTTP_MAX_HOST];
+ /* Hostname associated with connection */
+ http_t *http2; /* Alternate HTTP connection */
+ int fd; /* PPD file */
+ char localhost[HTTP_MAX_URI],/* Local hostname */
+ hostname[HTTP_MAX_URI], /* Hostname */
+ resource[HTTP_MAX_URI]; /* Resource name */
+ int port; /* Port number */
+ http_status_t status; /* HTTP status from server */
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("cupsGetPPD3(http=%p, name=\"%s\", modtime=%p(%d), buffer=%p, "
+ "bufsize=%d)", http, name, modtime,
+ modtime ? (int)*modtime : 0, buffer, (int)bufsize));
+
+ if (!name)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, _("No printer name"), 1);
+ return (HTTP_NOT_ACCEPTABLE);
+ }
+
+ if (!modtime)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, _("No modification time"), 1);
+ return (HTTP_NOT_ACCEPTABLE);
+ }
+
+ if (!buffer || bufsize <= 1)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad filename buffer"), 1);
+ return (HTTP_NOT_ACCEPTABLE);
+ }
+
+#ifndef WIN32
+ /*
+ * See if the PPD file is available locally...
+ */
+
+ if (!cg->servername[0])
+ cupsServer();
+
+ if (!_cups_strcasecmp(cg->servername, "localhost"))
+ {
+ char ppdname[1024]; /* PPD filename */
+ struct stat ppdinfo; /* PPD file information */
+
+
+ snprintf(ppdname, sizeof(ppdname), "%s/ppd/%s.ppd", cg->cups_serverroot,
+ name);
+ if (!stat(ppdname, &ppdinfo))
+ {
+ /*
+ * OK, the file exists, use it!
+ */
+
+ if (buffer[0])
+ {
+ unlink(buffer);
+
+ if (symlink(ppdname, buffer) && errno != EEXIST)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
+
+ return (HTTP_SERVER_ERROR);
+ }
+ }
+ else
+ {
+ int tries; /* Number of tries */
+ const char *tmpdir; /* TMPDIR environment variable */
+ struct timeval curtime; /* Current time */
+
+ /*
+ * Previously we put root temporary files in the default CUPS temporary
+ * directory under /var/spool/cups. However, since the scheduler cleans
+ * out temporary files there and runs independently of the user apps, we
+ * don't want to use it unless specifically told to by cupsd.
+ */
+
+ if ((tmpdir = getenv("TMPDIR")) == NULL)
+# ifdef __APPLE__
+ tmpdir = "/private/tmp"; /* /tmp is a symlink to /private/tmp */
+# else
+ tmpdir = "/tmp";
+# endif /* __APPLE__ */
+
+ /*
+ * Make the temporary name using the specified directory...
+ */
+
+ tries = 0;
+
+ do
+ {
+ /*
+ * Get the current time of day...
+ */
+
+ gettimeofday(&curtime, NULL);
+
+ /*
+ * Format a string using the hex time values...
+ */
+
+ snprintf(buffer, bufsize, "%s/%08lx%05lx", tmpdir,
+ (unsigned long)curtime.tv_sec,
+ (unsigned long)curtime.tv_usec);
+
+ /*
+ * Try to make a symlink...
+ */
+
+ if (!symlink(ppdname, buffer))
+ break;
+
+ tries ++;
+ }
+ while (tries < 1000);
+
+ if (tries >= 1000)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
+
+ return (HTTP_SERVER_ERROR);
+ }
+ }
+
+ if (*modtime >= ppdinfo.st_mtime)
+ return (HTTP_NOT_MODIFIED);
+ else
+ {
+ *modtime = ppdinfo.st_mtime;
+ return (HTTP_OK);
+ }
+ }
+ }
+#endif /* !WIN32 */
+
+ /*
+ * Try finding a printer URI for this printer...
+ */
+
+ if (!http)
+ if ((http = _cupsConnect()) == NULL)
+ return (HTTP_SERVICE_UNAVAILABLE);
+
+ if (!cups_get_printer_uri(http, name, hostname, sizeof(hostname), &port,
+ resource, sizeof(resource), 0))
+ return (HTTP_NOT_FOUND);
+
+ DEBUG_printf(("2cupsGetPPD3: Printer hostname=\"%s\", port=%d", hostname,
+ port));
+
+ /*
+ * Remap local hostname to localhost...
+ */
+
+ httpGetHostname(NULL, localhost, sizeof(localhost));
+
+ DEBUG_printf(("2cupsGetPPD3: Local hostname=\"%s\"", localhost));
+
+ if (!_cups_strcasecmp(localhost, hostname))
+ strcpy(hostname, "localhost");
+
+ /*
+ * Get the hostname and port number we are connected to...
+ */
+
+ httpGetHostname(http, http_hostname, sizeof(http_hostname));
+ http_port = _httpAddrPort(http->hostaddr);
+
+ DEBUG_printf(("2cupsGetPPD3: Connection hostname=\"%s\", port=%d",
+ http_hostname, http_port));
+
+ /*
+ * Reconnect to the correct server as needed...
+ */
+
+ if (!_cups_strcasecmp(http_hostname, hostname) && port == http_port)
+ http2 = http;
+ else if ((http2 = httpConnectEncrypt(hostname, port,
+ cupsEncryption())) == NULL)
+ {
+ DEBUG_puts("1cupsGetPPD3: Unable to connect to server");
+
+ return (HTTP_SERVICE_UNAVAILABLE);
+ }
+
+ /*
+ * Get a temp file...
+ */
+
+ if (buffer[0])
+ fd = open(buffer, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+ else
+ fd = cupsTempFd(buffer, bufsize);
+
+ if (fd < 0)
+ {
+ /*
+ * Can't open file; close the server connection and return NULL...
+ */
+
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
+
+ if (http2 != http)
+ httpClose(http2);
+
+ return (HTTP_SERVER_ERROR);
+ }
+
+ /*
+ * And send a request to the HTTP server...
+ */
+
+ strlcat(resource, ".ppd", sizeof(resource));
+
+ if (*modtime > 0)
+ httpSetField(http2, HTTP_FIELD_IF_MODIFIED_SINCE,
+ httpGetDateString(*modtime));
+
+ status = cupsGetFd(http2, resource, fd);
+
+ close(fd);
+
+ /*
+ * See if we actually got the file or an error...
+ */
+
+ if (status == HTTP_OK)
+ *modtime = httpGetDateTime(httpGetField(http2, HTTP_FIELD_DATE));
+ else if (status != HTTP_NOT_MODIFIED)
+ {
+ _cupsSetHTTPError(status);
+
+ unlink(cg->ppd_filename);
+ }
+
+ if (http2 != http)
+ httpClose(http2);
+
+ /*
+ * Return the PPD file...
+ */
+
+ DEBUG_printf(("1cupsGetPPD3: Returning status %d", status));
+
+ return (status);
+}
+
+
+/*
+ * 'cupsGetPrinters()' - Get a list of printers from the default server.
+ *
+ * This function is deprecated - use @link cupsGetDests@ instead.
+ *
+ * @deprecated@
+ */
+
+int /* O - Number of printers */
+cupsGetPrinters(char ***printers) /* O - Printers */
+{
+ int n; /* Number of printers */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ char **temp; /* Temporary pointer */
+ http_t *http; /* Connection to server */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!printers)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
+
+ return (0);
+ }
+
+ *printers = NULL;
+
+ /*
+ * Try to connect to the server...
+ */
+
+ if ((http = _cupsConnect()) == NULL)
+ return (0);
+
+ /*
+ * Build a CUPS_GET_PRINTERS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ */
+
+ request = ippNewRequest(CUPS_GET_PRINTERS);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "printer-name");
+
+ 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);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ n = 0;
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ for (attr = response->attrs; attr != NULL; attr = attr->next)
+ if (attr->name != NULL &&
+ _cups_strcasecmp(attr->name, "printer-name") == 0 &&
+ attr->value_tag == IPP_TAG_NAME)
+ {
+ if (n == 0)
+ temp = malloc(sizeof(char *));
+ else
+ temp = realloc(*printers, sizeof(char *) * (n + 1));
+
+ if (temp == NULL)
+ {
+ /*
+ * Ran out of memory!
+ */
+
+ while (n > 0)
+ {
+ n --;
+ free((*printers)[n]);
+ }
+
+ free(*printers);
+ ippDelete(response);
+ return (0);
+ }
+
+ *printers = temp;
+ temp[n] = strdup(attr->values[0].string.text);
+ n ++;
+ }
+
+ ippDelete(response);
+ }
+
+ return (n);
+}
+
+
+/*
+ * 'cupsGetServerPPD()' - Get an available PPD file from the server.
+ *
+ * This function returns the named PPD file from the server. The
+ * list of available PPDs is provided by the IPP @code CUPS_GET_PPDS@
+ * operation.
+ *
+ * You must remove (unlink) the PPD file when you are finished with
+ * it. The PPD filename is stored in a static location that will be
+ * overwritten on the next call to @link cupsGetPPD@, @link cupsGetPPD2@,
+ * or @link cupsGetServerPPD@.
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+char * /* O - Name of PPD file or @code NULL@ on error */
+cupsGetServerPPD(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *name) /* I - Name of PPD file ("ppd-name") */
+{
+ int fd; /* PPD file descriptor */
+ ipp_t *request; /* IPP request */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Pointer to library globals */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!name)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, _("No PPD name"), 1);
+
+ return (NULL);
+ }
+
+ if (!http)
+ if ((http = _cupsConnect()) == NULL)
+ return (NULL);
+
+ /*
+ * Get a temp file...
+ */
+
+ if ((fd = cupsTempFd(cg->ppd_filename, sizeof(cg->ppd_filename))) < 0)
+ {
+ /*
+ * Can't open file; close the server connection and return NULL...
+ */
+
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
+
+ return (NULL);
+ }
+
+ /*
+ * Get the PPD file...
+ */
+
+ request = ippNewRequest(CUPS_GET_PPD);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", NULL,
+ name);
+
+ ippDelete(cupsDoIORequest(http, request, "/", -1, fd));
+
+ close(fd);
+
+ if (cupsLastError() != IPP_OK)
+ {
+ unlink(cg->ppd_filename);
+ return (NULL);
+ }
+ else
+ return (cg->ppd_filename);
+}
+
+
+/*
+ * 'cupsPrintFile()' - Print a file to a printer or class on the default server.
+ */
+
+int /* O - Job ID or 0 on error */
+cupsPrintFile(const char *name, /* I - Destination name */
+ const char *filename, /* I - File to print */
+ const char *title, /* I - Title of job */
+ int num_options,/* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ DEBUG_printf(("cupsPrintFile(name=\"%s\", filename=\"%s\", "
+ "title=\"%s\", num_options=%d, options=%p)",
+ name, filename, title, num_options, options));
+
+ return (cupsPrintFiles2(CUPS_HTTP_DEFAULT, name, 1, &filename, title,
+ num_options, options));
+}
+
+
+/*
+ * 'cupsPrintFile2()' - Print a file to a printer or class on the specified
+ * server.
+ *
+ * @since CUPS 1.1.21/Mac OS X 10.4@
+ */
+
+int /* O - Job ID or 0 on error */
+cupsPrintFile2(
+ http_t *http, /* I - Connection to server */
+ const char *name, /* I - Destination name */
+ const char *filename, /* I - File to print */
+ const char *title, /* I - Title of job */
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ DEBUG_printf(("cupsPrintFile2(http=%p, name=\"%s\", filename=\"%s\", "
+ "title=\"%s\", num_options=%d, options=%p)",
+ http, name, filename, title, num_options, options));
+
+ return (cupsPrintFiles2(http, name, 1, &filename, title, num_options,
+ options));
+}
+
+
+/*
+ * 'cupsPrintFiles()' - Print one or more files to a printer or class on the
+ * default server.
+ */
+
+int /* O - Job ID or 0 on error */
+cupsPrintFiles(
+ const char *name, /* I - Destination name */
+ int num_files, /* I - Number of files */
+ const char **files, /* I - File(s) to print */
+ const char *title, /* I - Title of job */
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ DEBUG_printf(("cupsPrintFiles(name=\"%s\", num_files=%d, "
+ "files=%p, title=\"%s\", num_options=%d, options=%p)",
+ name, num_files, files, title, num_options, options));
+
+ /*
+ * Print the file(s)...
+ */
+
+ return (cupsPrintFiles2(CUPS_HTTP_DEFAULT, name, num_files, files, title,
+ num_options, options));
+}
+
+
+/*
+ * 'cupsPrintFiles2()' - Print one or more files to a printer or class on the
+ * specified server.
+ *
+ * @since CUPS 1.1.21/Mac OS X 10.4@
+ */
+
+int /* O - Job ID or 0 on error */
+cupsPrintFiles2(
+ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *name, /* I - Destination name */
+ int num_files, /* I - Number of files */
+ const char **files, /* I - File(s) to print */
+ const char *title, /* I - Title of job */
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ int i; /* Looping var */
+ int job_id; /* New job ID */
+ const char *docname; /* Basename of current filename */
+ const char *format; /* Document format */
+ cups_file_t *fp; /* Current file */
+ char buffer[8192]; /* Copy buffer */
+ ssize_t bytes; /* Bytes in buffer */
+ http_status_t status; /* Status of write */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+ ipp_status_t cancel_status; /* Status code to preserve */
+ char *cancel_message; /* Error message to preserve */
+
+
+ DEBUG_printf(("cupsPrintFiles2(http=%p, name=\"%s\", num_files=%d, "
+ "files=%p, title=\"%s\", num_options=%d, options=%p)",
+ http, name, num_files, files, title, num_options, options));
+
+ /*
+ * Range check input...
+ */
+
+ if (!name || num_files < 1 || !files)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
+
+ return (0);
+ }
+
+ /*
+ * Create the print job...
+ */
+
+ if ((job_id = cupsCreateJob(http, name, title, num_options, options)) == 0)
+ return (0);
+
+ /*
+ * Send each of the files...
+ */
+
+ if (cupsGetOption("raw", num_options, options))
+ format = CUPS_FORMAT_RAW;
+ else if ((format = cupsGetOption("document-format", num_options,
+ options)) == NULL)
+ format = CUPS_FORMAT_AUTO;
+
+ for (i = 0; i < num_files; i ++)
+ {
+ /*
+ * Start the next file...
+ */
+
+ if ((docname = strrchr(files[i], '/')) != NULL)
+ docname ++;
+ else
+ docname = files[i];
+
+ if ((fp = cupsFileOpen(files[i], "rb")) == NULL)
+ {
+ /*
+ * Unable to open print file, cancel the job and return...
+ */
+
+ _cupsSetError(IPP_DOCUMENT_ACCESS_ERROR, NULL, 0);
+ goto cancel_job;
+ }
+
+ status = cupsStartDocument(http, name, job_id, docname, format,
+ i == (num_files - 1));
+
+ while (status == HTTP_CONTINUE &&
+ (bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0)
+ status = cupsWriteRequestData(http, buffer, bytes);
+
+ cupsFileClose(fp);
+
+ if (status != HTTP_CONTINUE || cupsFinishDocument(http, name) != IPP_OK)
+ {
+ /*
+ * Unable to queue, cancel the job and return...
+ */
+
+ goto cancel_job;
+ }
+ }
+
+ return (job_id);
+
+ /*
+ * If we get here, something happened while sending the print job so we need
+ * to cancel the job without setting the last error (since we need to preserve
+ * the current error...
+ */
+
+ cancel_job:
+
+ cancel_status = cg->last_error;
+ cancel_message = cg->last_status_message ?
+ _cupsStrRetain(cg->last_status_message) : NULL;
+
+ cupsCancelJob2(http, name, job_id, 0);
+
+ cg->last_error = cancel_status;
+ cg->last_status_message = cancel_message;
+
+ return (0);
+}
+
+
+/*
+ * 'cupsStartDocument()' - Add a document to a job created with cupsCreateJob().
+ *
+ * Use @link cupsWriteRequestData@ to write data for the document and
+ * @link cupsFinishDocument@ to finish the document and get the submission status.
+ *
+ * The MIME type constants @code CUPS_FORMAT_AUTO@, @code CUPS_FORMAT_PDF@,
+ * @code CUPS_FORMAT_POSTSCRIPT@, @code CUPS_FORMAT_RAW@, and
+ * @code CUPS_FORMAT_TEXT@ are provided for the "format" argument, although
+ * any supported MIME type string can be supplied.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+http_status_t /* O - HTTP status of request */
+cupsStartDocument(
+ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *name, /* I - Destination name */
+ int job_id, /* I - Job ID from @link cupsCreateJob@ */
+ const char *docname, /* I - Name of document */
+ const char *format, /* I - MIME type or @code CUPS_FORMAT_foo@ */
+ int last_document) /* I - 1 for last document in job, 0 otherwise */
+{
+ char resource[1024], /* Resource for destinatio */
+ printer_uri[1024]; /* Printer URI */
+ ipp_t *request; /* Send-Document request */
+ http_status_t status; /* HTTP status */
+
+
+ /*
+ * Create a Send-Document request...
+ */
+
+ if ((request = ippNewRequest(IPP_SEND_DOCUMENT)) == NULL)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(ENOMEM), 0);
+ return (0);
+ }
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), "ipp",
+ NULL, "localhost", ippPort(), "/printers/%s", name);
+ snprintf(resource, sizeof(resource), "/printers/%s", name);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, printer_uri);
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+ if (docname)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name",
+ NULL, docname);
+ if (format)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
+ "document-format", NULL, format);
+ ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", last_document);
+
+ /*
+ * Send and delete the request, then return the status...
+ */
+
+ status = cupsSendRequest(http, request, resource, CUPS_LENGTH_VARIABLE);
+
+ ippDelete(request);
+
+ return (status);
+}
+
+
+/*
+ * 'cups_get_printer_uri()' - Get the printer-uri-supported attribute for the
+ * first printer in a class.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+cups_get_printer_uri(
+ http_t *http, /* I - Connection to server */
+ const char *name, /* I - Name of printer or class */
+ char *host, /* I - Hostname buffer */
+ int hostsize, /* I - Size of hostname buffer */
+ int *port, /* O - Port number */
+ char *resource, /* I - Resource buffer */
+ int resourcesize, /* I - Size of resource buffer */
+ int depth) /* I - Depth of query */
+{
+ int i; /* Looping var */
+ int http_port; /* Port number */
+ http_t *http2; /* Alternate HTTP connection */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* Current attribute */
+ char uri[HTTP_MAX_URI], /* printer-uri attribute */
+ scheme[HTTP_MAX_URI], /* Scheme name */
+ username[HTTP_MAX_URI], /* Username:password */
+ classname[255], /* Temporary class name */
+ http_hostname[HTTP_MAX_HOST];
+ /* Hostname associated with connection */
+ static const char * const requested_attrs[] =
+ { /* Requested attributes */
+ "member-uris",
+ "printer-uri-supported",
+ "printer-type"
+ };
+
+
+ DEBUG_printf(("7cups_get_printer_uri(http=%p, name=\"%s\", host=%p, "
+ "hostsize=%d, resource=%p, resourcesize=%d, depth=%d)",
+ http, name, host, hostsize, resource, resourcesize, depth));
+
+ /*
+ * Setup the printer URI...
+ */
+
+ if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/printers/%s", name) != HTTP_URI_OK)
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Unable to create printer-uri"), 1);
+
+ *host = '\0';
+ *resource = '\0';
+
+ return (0);
+ }
+
+ DEBUG_printf(("9cups_get_printer_uri: printer-uri=\"%s\"", uri));
+
+ /*
+ * Get the hostname and port number we are connected to...
+ */
+
+ httpGetHostname(http, http_hostname, sizeof(http_hostname));
+ http_port = _httpAddrPort(http->hostaddr);
+
+ /*
+ * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requested-attributes
+ */
+
+ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requested-attributes",
+ sizeof(requested_attrs) / sizeof(requested_attrs[0]),
+ NULL, requested_attrs);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL)
+ {
+ /*
+ * Get the first actual printer name in the class...
+ */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text,
+ scheme, sizeof(scheme), username, sizeof(username),
+ host, hostsize, port, resource, resourcesize);
+ if (!strncmp(resource, "/printers/", 10))
+ {
+ /*
+ * Found a printer!
+ */
+
+ ippDelete(response);
+
+ return (1);
+ }
+ }
+
+ /*
+ * No printers in this class - try recursively looking for a printer,
+ * but not more than 3 levels deep...
+ */
+
+ if (depth < 3)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text,
+ scheme, sizeof(scheme), username, sizeof(username),
+ host, hostsize, port, resource, resourcesize);
+ if (!strncmp(resource, "/classes/", 9))
+ {
+ /*
+ * Found a class! Connect to the right server...
+ */
+
+ if (!_cups_strcasecmp(http_hostname, host) && *port == http_port)
+ http2 = http;
+ else if ((http2 = httpConnectEncrypt(host, *port,
+ cupsEncryption())) == NULL)
+ {
+ DEBUG_puts("8cups_get_printer_uri: Unable to connect to server");
+
+ continue;
+ }
+
+ /*
+ * Look up printers on that server...
+ */
+
+ strlcpy(classname, resource + 9, sizeof(classname));
+
+ cups_get_printer_uri(http2, classname, host, hostsize, port,
+ resource, resourcesize, depth + 1);
+
+ /*
+ * Close the connection as needed...
+ */
+
+ if (http2 != http)
+ httpClose(http2);
+
+ if (*host)
+ return (1);
+ }
+ }
+ }
+ }
+ else if ((attr = ippFindAttribute(response, "printer-uri-supported",
+ IPP_TAG_URI)) != NULL)
+ {
+ httpSeparateURI(HTTP_URI_CODING_ALL,
+ _httpResolveURI(attr->values[0].string.text, uri,
+ sizeof(uri), _HTTP_RESOLVE_DEFAULT,
+ NULL, NULL),
+ scheme, sizeof(scheme), username, sizeof(username),
+ host, hostsize, port, resource, resourcesize);
+ ippDelete(response);
+
+ if (!strncmp(resource, "/classes/", 9))
+ {
+ _cupsSetError(IPP_INTERNAL_ERROR,
+ _("No printer-uri found for class"), 1);
+
+ *host = '\0';
+ *resource = '\0';
+
+ return (0);
+ }
+
+ return (1);
+ }
+
+ ippDelete(response);
+ }
+
+ if (cupsLastError() != IPP_NOT_FOUND)
+ _cupsSetError(IPP_INTERNAL_ERROR, _("No printer-uri found"), 1);
+
+ *host = '\0';
+ *resource = '\0';
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/versioning.h b/cups/versioning.h
new file mode 100644
index 000000000..92a0a52eb
--- /dev/null
+++ b/cups/versioning.h
@@ -0,0 +1,85 @@
+/*
+ * "$Id$"
+ *
+ * API versioning definitions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_VERSIONING_H_
+# define _CUPS_VERSIONING_H_
+
+/*
+ * This header defines several constants - _CUPS_DEPRECATED,
+ * _CUPS_API_1_1, _CUPS_API_1_1_19, _CUPS_API_1_1_20, _CUPS_API_1_1_21,
+ * _CUPS_API_1_2, _CUPS_API_1_3, _CUPS_API_1_4, _CUPS_API_1_5 - which add
+ * compiler-specific attributes that flag functions that are deprecated or added
+ * in particular releases.
+ *
+ * On Mac OS X, the _CUPS_API_* constants are defined based on the values of
+ * the MAC_OS_X_VERSION_MIN_ALLOWED and MAC_OS_X_VERSION_MAX_ALLOWED constants
+ * provided by the compiler.
+ */
+
+# if defined(__APPLE__) && !defined(_CUPS_SOURCE)
+# include <AvailabilityMacros.h>
+# ifndef AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+# define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER __attribute__((unavailable))
+# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER */
+# ifndef AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+# define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER __attribute__((unavailable))
+# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER */
+# ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+# define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER __attribute__((unavailable))
+# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER */
+# ifndef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+# define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER __attribute__((unavailable))
+# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER */
+# ifndef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+# define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER __attribute__((unavailable))
+# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER */
+# define _CUPS_API_1_1_19 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+# define _CUPS_API_1_1_20 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+# define _CUPS_API_1_1_21 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+# define _CUPS_API_1_2 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+# define _CUPS_API_1_3 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+# define _CUPS_API_1_4 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+# define _CUPS_API_1_5 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+# else
+# define _CUPS_API_1_1_19
+# define _CUPS_API_1_1_20
+# define _CUPS_API_1_1_21
+# define _CUPS_API_1_2
+# define _CUPS_API_1_3
+# define _CUPS_API_1_4
+# define _CUPS_API_1_5
+# endif /* __APPLE__ && !_CUPS_SOURCE */
+
+/*
+ * With GCC 3.0 and higher, we can mark old APIs "deprecated" so you get
+ * a warning at compile-time.
+ */
+
+# if defined(__GNUC__) && __GNUC__ > 2
+# define _CUPS_DEPRECATED __attribute__ ((__deprecated__))
+# else
+# define _CUPS_DEPRECATED
+# endif /* __GNUC__ && __GNUC__ > 2 */
+
+# ifndef __GNUC__
+# define __attribute__(x)
+# endif /* !__GNUC__ */
+
+#endif /* !_CUPS_VERSIONING_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/data/Makefile b/data/Makefile
new file mode 100644
index 000000000..b9de21a55
--- /dev/null
+++ b/data/Makefile
@@ -0,0 +1,166 @@
+#
+# "$Id$"
+#
+# Datafile makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1993-2006 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+#
+# Data files...
+#
+
+BANNERS = \
+ classified \
+ confidential \
+ secret \
+ standard \
+ topsecret \
+ unclassified
+
+CHARSETS = \
+ utf-8
+
+DATAFILES = \
+ psglyphs \
+ testprint
+
+PPDCFILES = \
+ epson.h \
+ escp.h \
+ font.defs \
+ hp.h \
+ label.h \
+ media.defs \
+ pcl.h \
+ raster.defs
+
+
+#
+# Make everything...
+#
+
+all:
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Clean all config and object files...
+#
+
+clean:
+
+
+#
+# Dummy depend...
+#
+
+depend:
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+ $(INSTALL_DIR) -m 755 $(DATADIR)/banners
+ for file in $(BANNERS); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/banners; \
+ done
+ $(INSTALL_DIR) -m 755 $(DATADIR)/charsets
+ if test "x$(BANNERTOPS)" != x -o "x$(TEXTTOPS)" != x; then \
+ for file in $(CHARSETS); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/charsets; \
+ done; \
+ fi
+ $(INSTALL_DIR) -m 755 $(DATADIR)/data
+ for file in $(DATAFILES); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/data; \
+ done
+ $(INSTALL_DIR) -m 755 $(DATADIR)/model
+ $(INSTALL_DIR) -m 755 $(DATADIR)/ppdc
+ for file in $(PPDCFILES); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/ppdc; \
+ done
+ $(INSTALL_DIR) -m 755 $(DATADIR)/profiles
+
+
+#
+# Install programs...
+#
+
+install-exec:
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall files...
+#
+
+uninstall:
+ for file in $(BANNERS); do \
+ $(RM) $(DATADIR)/banners/$$file; \
+ done
+ for file in $(CHARSETS); do \
+ $(RM) $(DATADIR)/charsets/$$file; \
+ done
+ for file in $(DATAFILES); do \
+ $(RM) $(DATADIR)/data/$$file; \
+ done
+ for file in $(PPDCFILES); do \
+ $(RM) $(DATADIR)/ppdc/$$file; \
+ done
+ -$(RMDIR) $(DATADIR)/profiles
+ -$(RMDIR) $(DATADIR)/ppdc
+ -$(RMDIR) $(DATADIR)/model
+ -$(RMDIR) $(DATADIR)/data
+ -$(RMDIR) $(DATADIR)/charsets
+ -$(RMDIR) $(DATADIR)/banners
+ -$(RMDIR) $(DATADIR)
+
+
+#
+# End of "$Id$".
+#
diff --git a/data/classified b/data/classified
new file mode 100644
index 000000000..ca01a13b7
--- /dev/null
+++ b/data/classified
@@ -0,0 +1,6 @@
+#CUPS-BANNER
+Show job-id job-name job-originating-user-name job-originating-host-name job-billing
+Header Classified
+Footer Classified
+Image images/cups.png
+
diff --git a/data/confidential b/data/confidential
new file mode 100644
index 000000000..f1f0d854d
--- /dev/null
+++ b/data/confidential
@@ -0,0 +1,6 @@
+#CUPS-BANNER
+Show job-id job-name job-originating-user-name job-originating-host-name job-billing
+Header Confidential
+Footer Confidential
+Image images/cups.png
+
diff --git a/data/cups.irix b/data/cups.irix
new file mode 100644
index 000000000..476383acb
--- /dev/null
+++ b/data/cups.irix
@@ -0,0 +1,3 @@
+#%PAM-1.0
+auth required pam_unix.so shadow nodelay nullok
+account required pam_unix.so
diff --git a/data/cups.pam b/data/cups.pam
new file mode 100644
index 000000000..f38e70184
--- /dev/null
+++ b/data/cups.pam
@@ -0,0 +1,2 @@
+auth required /lib/security/pam_pwdb.so nullok shadow
+account required /lib/security/pam_pwdb.so
diff --git a/data/cups.suse b/data/cups.suse
new file mode 100644
index 000000000..a9369e161
--- /dev/null
+++ b/data/cups.suse
@@ -0,0 +1,2 @@
+auth required pam_unix2.so nullok shadow
+account required pam_unix2.so
diff --git a/data/epson.h b/data/epson.h
new file mode 100644
index 000000000..13cb1a346
--- /dev/null
+++ b/data/epson.h
@@ -0,0 +1,27 @@
+/*
+ * "$Id$"
+ *
+ * This file contains model number definitions for the CUPS sample
+ * ESC/P driver.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#define EPSON_9PIN 0 /* 9-pin dot matrix */
+#define EPSON_24PIN 1 /* 24-pin dot matrix */
+#define EPSON_COLOR 2 /* Epson Stylus Color with ESC . */
+#define EPSON_PHOTO 3 /* Epson Stylus Photo with ESC . */
+#define EPSON_ICOLOR 4 /* Epson Stylus Color with ESC i */
+#define EPSON_IPHOTO 5 /* Epson Stylus Photo with ESC i */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/data/escp.h b/data/escp.h
new file mode 100644
index 000000000..94389f3b9
--- /dev/null
+++ b/data/escp.h
@@ -0,0 +1,34 @@
+/*
+ * "$Id$"
+ *
+ * This file contains model number definitions for the CUPS unified
+ * ESC/P driver.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/* General ESC/P Support */
+#define ESCP_DOTMATRIX 0x1 /* Dot matrix printer? */
+#define ESCP_MICROWEAVE 0x2 /* Use microweave command? */
+#define ESCP_STAGGER 0x4 /* Are color jets staggered? */
+#define ESCP_ESCK 0x8 /* Use print mode command?*/
+#define ESCP_EXT_UNITS 0x10 /* Use extended unit commands? */
+#define ESCP_EXT_MARGINS 0x20 /* Use extended margin command */
+#define ESCP_USB 0x40 /* Send USB packet mode escape? */
+#define ESCP_PAGE_SIZE 0x80 /* Use page size command */
+#define ESCP_RASTER_ESCI 0x100 /* Use ESC i graphics command */
+
+/* Remote mode support */
+#define ESCP_REMOTE 0x1000 /* Use remote mode commands? */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/data/font.defs b/data/font.defs
new file mode 100644
index 000000000..ee4559e82
--- /dev/null
+++ b/data/font.defs
@@ -0,0 +1,55 @@
+/*
+ * "$Id: font.defs 343 2007-07-13 19:52:48Z mike $"
+ *
+ * Standard ESP Ghostscript font definitions for the CUPS PPD file
+ * compiler.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#font AvantGarde-Book Standard "(1.05)" Standard ROM
+#font AvantGarde-BookOblique Standard "(1.05)" Standard ROM
+#font AvantGarde-Demi Standard "(1.05)" Standard ROM
+#font AvantGarde-DemiOblique Standard "(1.05)" Standard ROM
+#font Bookman-Demi Standard "(1.05)" Standard ROM
+#font Bookman-DemiItalic Standard "(1.05)" Standard ROM
+#font Bookman-Light Standard "(1.05)" Standard ROM
+#font Bookman-LightItalic Standard "(1.05)" Standard ROM
+#font Courier Standard "(1.05)" Standard ROM
+#font Courier-Bold Standard "(1.05)" Standard ROM
+#font Courier-BoldOblique Standard "(1.05)" Standard ROM
+#font Courier-Oblique Standard "(1.05)" Standard ROM
+#font Helvetica Standard "(1.05)" Standard ROM
+#font Helvetica-Bold Standard "(1.05)" Standard ROM
+#font Helvetica-BoldOblique Standard "(1.05)" Standard ROM
+#font Helvetica-Narrow Standard "(1.05)" Standard ROM
+#font Helvetica-Narrow-Bold Standard "(1.05)" Standard ROM
+#font Helvetica-Narrow-BoldOblique Standard "(1.05)" Standard ROM
+#font Helvetica-Narrow-Oblique Standard "(1.05)" Standard ROM
+#font Helvetica-Oblique Standard "(1.05)" Standard ROM
+#font NewCenturySchlbk-Bold Standard "(1.05)" Standard ROM
+#font NewCenturySchlbk-BoldItalic Standard "(1.05)" Standard ROM
+#font NewCenturySchlbk-Italic Standard "(1.05)" Standard ROM
+#font NewCenturySchlbk-Roman Standard "(1.05)" Standard ROM
+#font Palatino-Bold Standard "(1.05)" Standard ROM
+#font Palatino-BoldItalic Standard "(1.05)" Standard ROM
+#font Palatino-Italic Standard "(1.05)" Standard ROM
+#font Palatino-Roman Standard "(1.05)" Standard ROM
+#font Symbol Special "(001.005)" Special ROM
+#font Times-Bold Standard "(1.05)" Standard ROM
+#font Times-BoldItalic Standard "(1.05)" Standard ROM
+#font Times-Italic Standard "(1.05)" Standard ROM
+#font Times-Roman Standard "(1.05)" Standard ROM
+#font ZapfChancery-MediumItalic Standard "(1.05)" Standard ROM
+#font ZapfDingbats Special "(001.005)" Special ROM
+
+/*
+ * End of "$Id: font.defs 343 2007-07-13 19:52:48Z mike $".
+ */
diff --git a/data/hp.h b/data/hp.h
new file mode 100644
index 000000000..c70034316
--- /dev/null
+++ b/data/hp.h
@@ -0,0 +1,24 @@
+/*
+ * "$Id$"
+ *
+ * This file contains model number definitions for the CUPS sample
+ * HP driver.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#define HP_LASERJET 0 /* HP LaserJet */
+#define HP_DESKJET 1 /* HP DeskJet with simple color */
+#define HP_DESKJET2 2 /* HP DeskJet with CRet color */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/data/label.h b/data/label.h
new file mode 100644
index 000000000..4b6fba64f
--- /dev/null
+++ b/data/label.h
@@ -0,0 +1,28 @@
+/*
+ * "$Id$"
+ *
+ * This file contains model number definitions for the CUPS sample
+ * label printer driver.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#define DYMO_3x0 0 /* Dymo Labelwriter 300/330/330 Turbo */
+
+#define ZEBRA_EPL_LINE 0x10 /* Zebra EPL line mode printers */
+#define ZEBRA_EPL_PAGE 0x11 /* Zebra EPL page mode printers */
+#define ZEBRA_ZPL 0x12 /* Zebra ZPL-based printers */
+#define ZEBRA_CPCL 0x13 /* Zebra CPCL-based printers */
+
+#define INTELLITECH_PCL 0x20 /* Intellitech PCL-based printers */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/data/media.defs b/data/media.defs
new file mode 100644
index 000000000..799e542d2
--- /dev/null
+++ b/data/media.defs
@@ -0,0 +1,205 @@
+/*
+ * "$Id: media.defs 343 2007-07-13 19:52:48Z mike $"
+ *
+ * Adobe standard media size definitions for the CUPS PPD file compiler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These codedinstructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * copyright law. Distribution and use rights are outlinedin the file
+ * "LICENSE.txt" which should have beenincluded with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#media "10x11/10 x 11\"" 720 792
+#media "10x13/10 x 13\"" 720 936
+#media "10x14/10 x 14\"" 720 1008
+#media "12x11/12 x 11\"" 864 792
+#media "15x11/15 x 11\"" 1080 792
+#media "7x9/7 x 9\"" 504 648
+#media "8x10/8 x 10\"" 576 720
+#media "9x11/9 x 11\"" 648 792
+#media "9x12/9 x 12\"" 648 864
+#media "A0/A0" 2384 3370
+#media "A0.Transverse/A0 Long Edge" 3370 2384
+#media "A1/A1" 1684 2384
+#media "A1.Transverse/A1 Long Edge" 2384 1684
+#media "A2/A2" 1191 1684
+#media "A2.Transverse/A2 Long Edge" 1684 1191
+#media "A3/A3" 842 1191
+#media "A3.Transverse/A3 Long Edge" 1191 842
+#media "A3Extra/A3 Oversize" 913 1262
+#media "A3Extra.Transverse/A3 Oversize Long Edge" 913 1262
+#media "A3Rotated/A3 Long Edge" 1191 842
+#media "A4/A4" 595 842
+#media "A4Extra/A4 Oversize" 667 914
+#media "A4Plus/A4 Oversize" 595 936
+#media "A4Rotated/A4 Long Edge" 842 595
+#media "A4Small/A4 Small" 595 842
+#media "A4.Transverse/A4 Long Edge" 842 595
+#media "A5/A5" 420 595
+#media "A5Extra/A5 Oversize" 492 668
+#media "A5Rotated/A5 Long Edge" 595 420
+#media "A5.Transverse/A5 Long Edge" 595 420
+#media "A6/A6" 297 420
+#media "A6Rotated/A6 Long Edge" 420 297
+#media "A7/A7" 210 297
+#media "A8/A8" 148 210
+#media "A9/A9" 105 148
+#media "A10/A10" 73 105
+#media "AnsiA/ANSI A" 612 792
+#media "AnsiB/ANSI B" 792 1224
+#media "AnsiC/ANSI C" 1224 1584
+#media "AnsiD/ANSI D" 1584 2448
+#media "AnsiE/ANSI E" 2448 3168
+#media "ARCHA/Letter Oversize" 648 864
+#media "ARCHA.Transverse/Letter Oversize Long Edge" 864 648
+#media "ARCHB/Tabloid Oversize" 864 1296
+#media "ARCHB.Transverse/Tabloid Oversize Long Edge" 1296 864
+#media "ARCHC/ARCH C" 1296 1728
+#media "ARCHC.Transverse/ARCH C Long Edge" 1728 1296
+#media "ARCHD/ARCH D" 1728 2592
+#media "ARCHD.Transverse/ARCH D Long Edge" 2592 1728
+#media "ARCHE/ARCH E" 2592 3456
+#media "ARCHE.Transverse/ARCH E Long Edge" 3456 2592
+#media "B0/JIS B0" 2920 4127
+#media "B10/JIS B10" 91 127
+#media "B1/JIS B1" 2064 2918
+#media "B1/JIS B1" 2064 2920
+#media "B2/JIS B2" 1460 2064
+#media "B3/JIS B3" 1032 1460
+#media "B4/JIS B4" 729 1032
+#media "B4Rotated/JIS B4 Long Edge" 1032 729
+#media "B5/JIS B5" 516 729
+#media "B5Rotated/JIS B5 Long Edge" 729 516
+#media "B5.Transverse/JIS B5 Long Edge" 516 729
+#media "B6/JIS B6" 363 516
+#media "B6Rotated/JIS B6 Long Edge" 516 363
+#media "B7/JIS B7" 258 363
+#media "B8/JIS B8" 181 258
+#media "B9/JIS B9" 127 181
+#media "C4/Envelope C4" 649 918
+#media "C5/Envelope C5" 459 649
+#media "C6/Envelope C6" 323 459
+#media "DL/Envelope DL" 312 624
+#media "DoublePostcard/Postcard Double " 567 420
+#media "DoublePostcardRotated/Postcard Double Long Edge" 420 567
+#media "Env10/Envelope #10 " 297 684
+#media "Env11/Envelope #11" 324 747
+#media "Env12/Envelope #12" 342 792
+#media "Env14/Envelope #14" 360 828
+#media "Env9/Envelope #9" 279 639
+#media "EnvC0/Envelope C0" 2599 3676
+#media "EnvC1/Envelope C1" 1837 2599
+#media "EnvC2/Envelope C2" 1298 1837
+#media "EnvC3/Envelope C3" 918 1296
+#media "EnvC4/Envelope C4" 649 918
+#media "EnvC5/Envelope C5" 459 649
+#media "EnvC65/Envelope C65" 324 648
+#media "EnvC6/Envelope C6" 323 459
+#media "EnvC7/Envelope C7" 230 323
+#media "EnvChou3/Envelope Choukei 3" 340 666
+#media "EnvChou3Rotated/Envelope Choukei 3 Long Edge" 666 340
+#media "EnvChou4/Envelope Choukei 4" 255 581
+#media "EnvChou4Rotated/Envelope Choukei 4 Long Edge" 581 255
+#media "EnvDL/Envelope DL" 312 624
+#media "EnvInvite/Envelope Invite" 624 624
+#media "EnvISOB4/Envelope B4" 708 1001
+#media "EnvISOB5/Envelope B5" 499 709
+#media "EnvISOB6/Envelope B6" 499 354
+#media "EnvItalian/Envelope Italian" 312 652
+#media "EnvKaku2/Envelope Kaku2" 680 941
+#media "EnvKaku2Rotated/Envelope Kaku2 Long Edge" 941 680
+#media "EnvKaku3/Envelope Kaku3" 612 785
+#media "EnvKaku3Rotated/Envelope Kaku3 Long Edge" 785 612
+#media "EnvMonarch/Envelope Monarch" 279 540
+#media "EnvPersonal/Envelope Personal" 261 468
+#media "EnvPRC1/Envelope PRC1 " 289 468
+#media "EnvPRC1Rotated/Envelope PRC1 Long Edge" 468 289
+#media "EnvPRC2/Envelope PRC2" 289 499
+#media "EnvPRC2Rotated/Envelope PRC2 Long Edge" 499 289
+#media "EnvPRC3/Envelope PRC3" 354 499
+#media "EnvPRC3Rotated/Envelope PRC3 Long Edge" 499 354
+#media "EnvPRC4/Envelope PRC4" 312 590
+#media "EnvPRC4Rotated/Envelope PRC4 Long Edge" 590 312
+#media "EnvPRC5/Envelope PRC5PRC5" 312 624
+#media "EnvPRC5Rotated/Envelope PRC5 Long Edge" 624 312
+#media "EnvPRC6/Envelope PRC6" 340 652
+#media "EnvPRC6Rotated/Envelope PRC6 Long Edge" 652 340
+#media "EnvPRC7/Envelope PRC7" 454 652
+#media "EnvPRC7Rotated/Envelope PRC7 Long Edge" 652 454
+#media "EnvPRC8/Envelope PRC8" 340 876
+#media "EnvPRC8Rotated/Envelope PRC8 Long Edge" 876 340
+#media "EnvPRC9/Envelope PRC9" 649 918
+#media "EnvPRC9Rotated/Envelope PRC9 Long Edge" 918 649
+#media "EnvPRC10/Envelope PRC10" 918 1298
+#media "EnvPRC10Rotated/Envelope PRC10 Long Edge" 1298 918
+#media "EnvYou4/Envelope You4" 298 666
+#media "EnvYou4Rotated/Envelope You4 Long Edge" 666 298
+#media "Executive/Executive" 522 756
+#media "FanFoldGerman/FanFold German" 612 864
+#media "FanFoldGermanLegal/FanFold Legal German" 612 936
+#media "FanFoldUS/Fanfold US" 1071 792
+#media "Folio/Folio" 595 935
+#media "ISOB0/B0" 2835 4008
+#media "ISOB1/B1" 2004 2835
+#media "ISOB2/B2" 1417 2004
+#media "ISOB3/B3" 1001 1417
+#media "ISOB4/B4" 709 1001
+#media "ISOB5/B5" 499 709
+#media "ISOB5Extra/B5 Oversize" 570 782
+#media "ISOB6/B6" 354 499
+#media "ISOB7/B7" 249 354
+#media "ISOB8/B8" 176 249
+#media "ISOB9/B9" 125 176
+#media "ISOB10/B10" 88 125
+#media "Ledger/US Ledger" 1224 792
+#media "Legal/US Legal" 612 1008
+#media "LegalExtra/US Legal Oversize" 684 1080
+#media "Letter/US Letter" 612 792
+#media "Letter.Transverse/US Letter Long Edge" 792 612
+#media "LetterExtra/US Letter Oversize" 684 864
+#media "LetterExtra.Transverse/US Letter Oversize Long Edge" 864 684
+#media "LetterPlus/US Letter Oversize" 612 914
+#media "LetterRotated/US Letter Long Edge" 792 612
+#media "LetterSmall/US Letter Small" 612 792
+#media "Monarch/Envelope Monarch" 279 540
+#media "Note/Note" 612 792
+#media "Postcard/Postcard" 284 419
+#media "PostcardRotated/Postcard Long Edge" 419 284
+#media "PRC16K/PRC16K" 414 610
+#media "PRC16KRotated/PRC16K Long Edge" 610 414
+#media "PRC32K/PRC32K" 275 428
+#media "PRC32KBig/PRC32K Oversize" 275 428
+#media "PRC32KBigRotated/PRC32K Oversize Long Edge" 428 275
+#media "PRC32KRotated/PRC32K Long Edge" 428 275
+#media "Quarto/Quarto" 610 780
+#media "Statement/Statement" 396 612
+#media "SuperA/Super A" 643 1009
+#media "SuperB/Super B" 864 1380
+#media "Tabloid/Tabloid" 792 1224
+#media "TabloidExtra/Tabloid Oversize" 864 1296
+
+/*
+ * Non-standard sizes...
+ */
+
+#media "Photo4x6/Photo" 288 432
+#media "PhotoLabel/Photo Labels" 288 468
+#media "w936h1368/Super B/A3" 936 1368
+#media "w81h252/Address" 81 252
+#media "w101h252/Large Address" 101 252
+#media "w54h144/Return Address" 54 144
+#media "w167h288/Shipping Address" 167 288
+#media "w162h540/Internet Postage 2-Part" 162 540
+#media "w162h504/Internet Postage 3-Part" 162 504
+#media "w41h248/File Folder" 41 248
+#media "w41h144/Hanging Folder" 41 144
+#media "w153h198/3.5\" Disk" 153 198
+
+
+/*
+ * End of "$Id: media.defs 343 2007-07-13 19:52:48Z mike $".
+ */
diff --git a/data/pcl.h b/data/pcl.h
new file mode 100644
index 000000000..0cb1effe5
--- /dev/null
+++ b/data/pcl.h
@@ -0,0 +1,38 @@
+/*
+ * "$Id$"
+ *
+ * This file contains model number definitions for the CUPS unified
+ * PCL driver.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/* General PCL Support */
+#define PCL_PAPER_SIZE 0x1 /* Use ESC&l#A */
+#define PCL_INKJET 0x2 /* Use inkjet commands */
+
+/* Raster Support */
+#define PCL_RASTER_END_COLOR 0x100 /* Use ESC*rC */
+#define PCL_RASTER_CID 0x200 /* Use ESC*v#W */
+#define PCL_RASTER_CRD 0x400 /* Use ESC*g#W */
+#define PCL_RASTER_SIMPLE 0x800 /* Use ESC*r#U */
+#define PCL_RASTER_RGB24 0x1000 /* Use 24-bit RGB mode */
+
+/* PJL Support */
+#define PCL_PJL 0x10000 /* Use PJL Commands */
+#define PCL_PJL_PAPERWIDTH 0x20000 /* Use PJL PAPERWIDTH/LENGTH */
+#define PCL_PJL_HPGL2 0x40000 /* Enter HPGL2 */
+#define PCL_PJL_PCL3GUI 0x80000 /* Enter PCL3GUI */
+#define PCL_PJL_RESOLUTION 0x100000 /* Use PJL SET RESOLUTION */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/data/psglyphs b/data/psglyphs
new file mode 100644
index 000000000..c4a902c66
--- /dev/null
+++ b/data/psglyphs
@@ -0,0 +1,1051 @@
+0020 space
+0021 exclam
+0022 quotedbl
+0023 numbersign
+0024 dollar
+0025 percent
+0026 ampersand
+0027 quotesingle
+0028 parenleft
+0029 parenright
+002a asterisk
+002b plus
+002c comma
+002d minus
+002e period
+002f slash
+0030 zero
+0031 one
+0032 two
+0033 three
+0034 four
+0035 five
+0036 six
+0037 seven
+0038 eight
+0039 nine
+003a colon
+003b semicolon
+003c less
+003d equal
+003e greater
+003f question
+0040 at
+0041 A
+0042 B
+0043 C
+0044 D
+0045 E
+0046 F
+0047 G
+0048 H
+0049 I
+004a J
+004b K
+004c L
+004d M
+004e N
+004f O
+0050 P
+0051 Q
+0052 R
+0053 S
+0054 T
+0055 U
+0056 V
+0057 W
+0058 X
+0059 Y
+005a Z
+005b bracketleft
+005c backslash
+005d bracketright
+005e asciicircum
+005f underscore
+0060 grave
+0061 a
+0062 b
+0063 c
+0064 d
+0065 e
+0066 f
+0067 g
+0068 h
+0069 i
+006a j
+006b k
+006c l
+006d m
+006e n
+006f o
+0070 p
+0071 q
+0072 r
+0073 s
+0074 t
+0075 u
+0076 v
+0077 w
+0078 x
+0079 y
+007a z
+007b braceleft
+007c bar
+007d braceright
+007e asciitilde
+00a0 space
+00a1 exclamdown
+00a2 cent
+00a3 sterling
+00a4 currency
+00a5 yen
+00a6 brokenbar
+00a7 section
+00a8 dieresis
+00a9 copyright
+00aa ordfeminine
+00ab guillemotleft
+00ac logicalnot
+00ad hyphen
+00ae registered
+00af macron
+00b0 degree
+00b1 plusminus
+00b2 twosuperior
+00b3 threesuperior
+00b4 acute
+00b5 mu
+00b6 paragraph
+00b7 periodcentered
+00b8 cedilla
+00b9 onesuperior
+00ba ordmasculine
+00bb guillemotright
+00bc onequarter
+00bd onehalf
+00be threequarters
+00bf questiondown
+00c0 Agrave
+00c1 Aacute
+00c2 Acircumflex
+00c3 Atilde
+00c4 Adieresis
+00c5 Aring
+00c6 AE
+00c7 Ccedilla
+00c8 Egrave
+00c9 Eacute
+00ca Ecircumflex
+00cb Edieresis
+00cc Igrave
+00cd Iacute
+00ce Icircumflex
+00cf Idieresis
+00d0 Eth
+00d1 Ntilde
+00d2 Ograve
+00d3 Oacute
+00d4 Ocircumflex
+00d5 Otilde
+00d6 Odieresis
+00d7 multiply
+00d8 Oslash
+00d9 Ugrave
+00da Uacute
+00db Ucircumflex
+00dc Udieresis
+00dd Yacute
+00de Thorn
+00df germandbls
+00e0 agrave
+00e1 aacute
+00e2 acircumflex
+00e3 atilde
+00e4 adieresis
+00e5 aring
+00e6 ae
+00e7 ccedilla
+00e8 egrave
+00e9 eacute
+00ea ecircumflex
+00eb edieresis
+00ec igrave
+00ed iacute
+00ee icircumflex
+00ef idieresis
+00f0 eth
+00f1 ntilde
+00f2 ograve
+00f3 oacute
+00f4 ocircumflex
+00f5 otilde
+00f6 odieresis
+00f7 divide
+00f8 oslash
+00f9 ugrave
+00fa uacute
+00fb ucircumflex
+00fc udieresis
+00fd yacute
+00fe thorn
+00ff ydieresis
+0100 Amacron
+0101 amacron
+0102 Abreve
+0103 abreve
+0104 Aogonek
+0105 aogonek
+0106 Cacute
+0107 cacute
+0108 Ccircumflex
+0109 ccircumflex
+010a Cdotaccent
+010b cdotaccent
+010c Ccaron
+010d ccaron
+010e Dcaron
+010f dcaron
+0110 Dcroat
+0111 dcroat
+0112 Emacron
+0113 emacron
+0114 Ebreve
+0115 ebreve
+0116 Edotaccent
+0117 edotaccent
+0118 Eogonek
+0119 eogonek
+011a Ecaron
+011b ecaron
+011c Gcircumflex
+011d gcircumflex
+011e Gbreve
+011f gbreve
+0120 Gdotaccent
+0121 gdotaccent
+0122 Gcommaaccent
+0123 gcommaaccent
+0124 Hcircumflex
+0125 hcircumflex
+0126 Hbar
+0127 hbar
+0128 Itilde
+0129 itilde
+012a Imacron
+012b imacron
+012c Ibreve
+012d ibreve
+012e Iogonek
+012f iogonek
+0130 Idotaccent
+0131 dotlessi
+0132 IJ
+0133 ij
+0134 Jcircumflex
+0135 jcircumflex
+0136 Kcommaaccent
+0137 kcommaaccent
+0138 kgreenlandic
+0139 Lacute
+013a lacute
+013b Lcommaaccent
+013c lcommaaccent
+013d Lcaron
+013e lcaron
+013f Ldot
+0140 ldot
+0141 Lslash
+0142 lslash
+0143 Nacute
+0144 nacute
+0145 Ncommaaccent
+0146 ncommaaccent
+0147 Ncaron
+0148 ncaron
+0149 napostrophe
+014a Eng
+014b eng
+014c Omacron
+014d omacron
+014e Obreve
+014f obreve
+0150 Ohungarumlaut
+0151 ohungarumlaut
+0152 OE
+0153 oe
+0154 Racute
+0155 racute
+0156 Rcommaaccent
+0157 rcommaaccent
+0158 Rcaron
+0159 rcaron
+015a Sacute
+015b sacute
+015c Scircumflex
+015d scircumflex
+015e Scedilla
+015f scedilla
+0160 Scaron
+0161 scaron
+0162 Tcommaaccent
+0163 tcommaaccent
+0164 Tcaron
+0165 tcaron
+0166 Tbar
+0167 tbar
+0168 Utilde
+0169 utilde
+016a Umacron
+016b umacron
+016c Ubreve
+016d ubreve
+016e Uring
+016f uring
+0170 Uhungarumlaut
+0171 uhungarumlaut
+0172 Uogonek
+0173 uogonek
+0174 Wcircumflex
+0175 wcircumflex
+0176 Ycircumflex
+0177 ycircumflex
+0178 Ydieresis
+0179 Zacute
+017a zacute
+017b Zdotaccent
+017c zdotaccent
+017d Zcaron
+017e zcaron
+017f longs
+0192 florin
+01a0 Ohorn
+01a1 ohorn
+01af Uhorn
+01b0 uhorn
+01e6 Gcaron
+01e7 gcaron
+01fa Aringacute
+01fb aringacute
+01fc AEacute
+01fd aeacute
+01fe Oslashacute
+01ff oslashacute
+0218 Scommaaccent
+0219 scommaaccent
+021a Tcommaaccent
+021b tcommaaccent
+02bc afii57929
+02bd afii64937
+02c6 circumflex
+02c7 caron
+02c9 macron
+02d8 breve
+02d9 dotaccent
+02da ring
+02db ogonek
+02dc tilde
+02dd hungarumlaut
+0300 gravecomb
+0301 acutecomb
+0303 tildecomb
+0309 hookabovecomb
+0323 dotbelowcomb
+0384 tonos
+0385 dieresistonos
+0386 Alphatonos
+0387 anoteleia
+0388 Epsilontonos
+0389 Etatonos
+038a Iotatonos
+038c Omicrontonos
+038e Upsilontonos
+038f Omegatonos
+0390 iotadieresistonos
+0391 Alpha
+0392 Beta
+0393 Gamma
+0394 Delta
+0395 Epsilon
+0396 Zeta
+0397 Eta
+0398 Theta
+0399 Iota
+039a Kappa
+039b Lambda
+039c Mu
+039d Nu
+039e Xi
+039f Omicron
+03a0 Pi
+03a1 Rho
+03a3 Sigma
+03a4 Tau
+03a5 Upsilon
+03a6 Phi
+03a7 Chi
+03a8 Psi
+03a9 Omega
+03aa Iotadieresis
+03ab Upsilondieresis
+03ac alphatonos
+03ad epsilontonos
+03ae etatonos
+03af iotatonos
+03b0 upsilondieresistonos
+03b1 alpha
+03b2 beta
+03b3 gamma
+03b4 delta
+03b5 epsilon
+03b6 zeta
+03b7 eta
+03b8 theta
+03b9 iota
+03ba kappa
+03bb lambda
+03bc mu
+03bd nu
+03be xi
+03bf omicron
+03c0 pi
+03c1 rho
+03c2 sigma1
+03c3 sigma
+03c4 tau
+03c5 upsilon
+03c6 phi
+03c7 chi
+03c8 psi
+03c9 omega
+03ca iotadieresis
+03cb upsilondieresis
+03cc omicrontonos
+03cd upsilontonos
+03ce omegatonos
+03d1 theta1
+03d2 Upsilon1
+03d5 phi1
+03d6 omega1
+0401 afii10023
+0402 afii10051
+0403 afii10052
+0404 afii10053
+0405 afii10054
+0406 afii10055
+0407 afii10056
+0408 afii10057
+0409 afii10058
+040a afii10059
+040b afii10060
+040c afii10061
+040e afii10062
+040f afii10145
+0410 afii10017
+0411 afii10018
+0412 afii10019
+0413 afii10020
+0414 afii10021
+0415 afii10022
+0416 afii10024
+0417 afii10025
+0418 afii10026
+0419 afii10027
+041a afii10028
+041b afii10029
+041c afii10030
+041d afii10031
+041e afii10032
+041f afii10033
+0420 afii10034
+0421 afii10035
+0422 afii10036
+0423 afii10037
+0424 afii10038
+0425 afii10039
+0426 afii10040
+0427 afii10041
+0428 afii10042
+0429 afii10043
+042a afii10044
+042b afii10045
+042c afii10046
+042d afii10047
+042e afii10048
+042f afii10049
+0430 afii10065
+0431 afii10066
+0432 afii10067
+0433 afii10068
+0434 afii10069
+0435 afii10070
+0436 afii10072
+0437 afii10073
+0438 afii10074
+0439 afii10075
+043a afii10076
+043b afii10077
+043c afii10078
+043d afii10079
+043e afii10080
+043f afii10081
+0440 afii10082
+0441 afii10083
+0442 afii10084
+0443 afii10085
+0444 afii10086
+0445 afii10087
+0446 afii10088
+0447 afii10089
+0448 afii10090
+0449 afii10091
+044a afii10092
+044b afii10093
+044c afii10094
+044d afii10095
+044e afii10096
+044f afii10097
+0451 afii10071
+0452 afii10099
+0453 afii10100
+0454 afii10101
+0455 afii10102
+0456 afii10103
+0457 afii10104
+0458 afii10105
+0459 afii10106
+045a afii10107
+045b afii10108
+045c afii10109
+045e afii10110
+045f afii10193
+0462 afii10146
+0463 afii10194
+0472 afii10147
+0473 afii10195
+0474 afii10148
+0475 afii10196
+0490 afii10050
+0491 afii10098
+04d9 afii10846
+05b0 afii57799
+05b1 afii57801
+05b2 afii57800
+05b3 afii57802
+05b4 afii57793
+05b5 afii57794
+05b6 afii57795
+05b7 afii57798
+05b8 afii57797
+05b9 afii57806
+05bb afii57796
+05bc afii57807
+05bd afii57839
+05be afii57645
+05bf afii57841
+05c0 afii57842
+05c1 afii57804
+05c2 afii57803
+05c3 afii57658
+05d0 afii57664
+05d1 afii57665
+05d2 afii57666
+05d3 afii57667
+05d4 afii57668
+05d5 afii57669
+05d6 afii57670
+05d7 afii57671
+05d8 afii57672
+05d9 afii57673
+05da afii57674
+05db afii57675
+05dc afii57676
+05dd afii57677
+05de afii57678
+05df afii57679
+05e0 afii57680
+05e1 afii57681
+05e2 afii57682
+05e3 afii57683
+05e4 afii57684
+05e5 afii57685
+05e6 afii57686
+05e7 afii57687
+05e8 afii57688
+05e9 afii57689
+05ea afii57690
+05f0 afii57716
+05f1 afii57717
+05f2 afii57718
+060c afii57388
+061b afii57403
+061f afii57407
+0621 afii57409
+0622 afii57410
+0623 afii57411
+0624 afii57412
+0625 afii57413
+0626 afii57414
+0627 afii57415
+0628 afii57416
+0629 afii57417
+062a afii57418
+062b afii57419
+062c afii57420
+062d afii57421
+062e afii57422
+062f afii57423
+0630 afii57424
+0631 afii57425
+0632 afii57426
+0633 afii57427
+0634 afii57428
+0635 afii57429
+0636 afii57430
+0637 afii57431
+0638 afii57432
+0639 afii57433
+063a afii57434
+0640 afii57440
+0641 afii57441
+0642 afii57442
+0643 afii57443
+0644 afii57444
+0645 afii57445
+0646 afii57446
+0647 afii57470
+0648 afii57448
+0649 afii57449
+064a afii57450
+064b afii57451
+064c afii57452
+064d afii57453
+064e afii57454
+064f afii57455
+0650 afii57456
+0651 afii57457
+0652 afii57458
+0660 afii57392
+0661 afii57393
+0662 afii57394
+0663 afii57395
+0664 afii57396
+0665 afii57397
+0666 afii57398
+0667 afii57399
+0668 afii57400
+0669 afii57401
+066a afii57381
+066d afii63167
+0679 afii57511
+067e afii57506
+0686 afii57507
+0688 afii57512
+0691 afii57513
+0698 afii57508
+06a4 afii57505
+06af afii57509
+06ba afii57514
+06d2 afii57519
+06d5 afii57534
+1e80 Wgrave
+1e81 wgrave
+1e82 Wacute
+1e83 wacute
+1e84 Wdieresis
+1e85 wdieresis
+1ef2 Ygrave
+1ef3 ygrave
+200c afii61664
+200d afii301
+200e afii299
+200f afii300
+2012 figuredash
+2013 endash
+2014 emdash
+2015 afii00208
+2017 underscoredbl
+2018 quoteleft
+2019 quoteright
+201a quotesinglbase
+201b quotereversed
+201c quotedblleft
+201d quotedblright
+201e quotedblbase
+2020 dagger
+2021 daggerdbl
+2022 bullet
+2024 onedotenleader
+2025 twodotenleader
+2026 ellipsis
+202c afii61573
+202d afii61574
+202e afii61575
+2030 perthousand
+2032 minute
+2033 second
+2039 guilsinglleft
+203a guilsinglright
+203c exclamdbl
+2044 fraction
+2070 zerosuperior
+2074 foursuperior
+2075 fivesuperior
+2076 sixsuperior
+2077 sevensuperior
+2078 eightsuperior
+2079 ninesuperior
+207d parenleftsuperior
+207e parenrightsuperior
+207f nsuperior
+2080 zeroinferior
+2081 oneinferior
+2082 twoinferior
+2083 threeinferior
+2084 fourinferior
+2085 fiveinferior
+2086 sixinferior
+2087 seveninferior
+2088 eightinferior
+2089 nineinferior
+208d parenleftinferior
+208e parenrightinferior
+20a1 colonmonetary
+20a3 franc
+20a4 lira
+20a7 peseta
+20aa afii57636
+20ab dong
+20ac Euro
+2105 afii61248
+2111 Ifraktur
+2113 afii61289
+2116 afii61352
+2118 weierstrass
+211c Rfraktur
+211e prescription
+2122 trademark
+2126 Omega
+212e estimated
+2135 aleph
+2153 onethird
+2154 twothirds
+215b oneeighth
+215c threeeighths
+215d fiveeighths
+215e seveneighths
+2190 arrowleft
+2191 arrowup
+2192 arrowright
+2193 arrowdown
+2194 arrowboth
+2195 arrowupdn
+21a8 arrowupdnbse
+21b5 carriagereturn
+21d0 arrowdblleft
+21d1 arrowdblup
+21d2 arrowdblright
+21d3 arrowdbldown
+21d4 arrowdblboth
+2200 universal
+2202 partialdiff
+2203 existential
+2205 emptyset
+2206 Delta
+2207 gradient
+2208 element
+2209 notelement
+220b suchthat
+220f product
+2211 summation
+2212 minus
+2215 fraction
+2217 asteriskmath
+2219 periodcentered
+221a radical
+221d proportional
+221e infinity
+221f orthogonal
+2220 angle
+2227 logicaland
+2228 logicalor
+2229 intersection
+222a union
+222b integral
+2234 therefore
+223c similar
+2245 congruent
+2248 approxequal
+2260 notequal
+2261 equivalence
+2264 lessequal
+2265 greaterequal
+2282 propersubset
+2283 propersuperset
+2284 notsubset
+2286 reflexsubset
+2287 reflexsuperset
+2295 circleplus
+2297 circlemultiply
+22a5 perpendicular
+22c5 dotmath
+2302 house
+2310 revlogicalnot
+2320 integraltp
+2321 integralbt
+2329 angleleft
+232a angleright
+2500 SF100000
+2502 SF110000
+250c SF010000
+2510 SF030000
+2514 SF020000
+2518 SF040000
+251c SF080000
+2524 SF090000
+252c SF060000
+2534 SF070000
+253c SF050000
+2550 SF430000
+2551 SF240000
+2552 SF510000
+2553 SF520000
+2554 SF390000
+2555 SF220000
+2556 SF210000
+2557 SF250000
+2558 SF500000
+2559 SF490000
+255a SF380000
+255b SF280000
+255c SF270000
+255d SF260000
+255e SF360000
+255f SF370000
+2560 SF420000
+2561 SF190000
+2562 SF200000
+2563 SF230000
+2564 SF470000
+2565 SF480000
+2566 SF410000
+2567 SF450000
+2568 SF460000
+2569 SF400000
+256a SF540000
+256b SF530000
+256c SF440000
+2580 upblock
+2584 dnblock
+2588 block
+258c lfblock
+2590 rtblock
+2591 ltshade
+2592 shade
+2593 dkshade
+25a0 filledbox
+25a1 H22073
+25aa H18543
+25ab H18551
+25ac filledrect
+25b2 triagup
+25ba triagrt
+25bc triagdn
+25c4 triaglf
+25ca lozenge
+25cb circle
+25cf H18533
+25d8 invbullet
+25d9 invcircle
+25e6 openbullet
+263a smileface
+263b invsmileface
+263c sun
+2640 female
+2642 male
+2660 spade
+2663 club
+2665 heart
+2666 diamond
+266a musicalnote
+266b musicalnotedbl
+f6be dotlessj
+f6bf LL
+f6c0 ll
+f6c1 Scedilla
+f6c2 scedilla
+f6c3 commaaccent
+f6c4 afii10063
+f6c5 afii10064
+f6c6 afii10192
+f6c7 afii10831
+f6c8 afii10832
+f6c9 Acute
+f6ca Caron
+f6cb Dieresis
+f6cc DieresisAcute
+f6cd DieresisGrave
+f6ce Grave
+f6cf Hungarumlaut
+f6d0 Macron
+f6d1 cyrBreve
+f6d2 cyrFlex
+f6d3 dblGrave
+f6d4 cyrbreve
+f6d5 cyrflex
+f6d6 dblgrave
+f6d7 dieresisacute
+f6d8 dieresisgrave
+f6d9 copyrightserif
+f6da registerserif
+f6db trademarkserif
+f6dc onefitted
+f6dd rupiah
+f6de threequartersemdash
+f6df centinferior
+f6e0 centsuperior
+f6e1 commainferior
+f6e2 commasuperior
+f6e3 dollarinferior
+f6e4 dollarsuperior
+f6e5 hypheninferior
+f6e6 hyphensuperior
+f6e7 periodinferior
+f6e8 periodsuperior
+f6e9 asuperior
+f6ea bsuperior
+f6eb dsuperior
+f6ec esuperior
+f6ed isuperior
+f6ee lsuperior
+f6ef msuperior
+f6f0 osuperior
+f6f1 rsuperior
+f6f2 ssuperior
+f6f3 tsuperior
+f6f4 Brevesmall
+f6f5 Caronsmall
+f6f6 Circumflexsmall
+f6f7 Dotaccentsmall
+f6f8 Hungarumlautsmall
+f6f9 Lslashsmall
+f6fa OEsmall
+f6fb Ogoneksmall
+f6fc Ringsmall
+f6fd Scaronsmall
+f6fe Tildesmall
+f6ff Zcaronsmall
+f721 exclamsmall
+f724 dollaroldstyle
+f726 ampersandsmall
+f730 zerooldstyle
+f731 oneoldstyle
+f732 twooldstyle
+f733 threeoldstyle
+f734 fouroldstyle
+f735 fiveoldstyle
+f736 sixoldstyle
+f737 sevenoldstyle
+f738 eightoldstyle
+f739 nineoldstyle
+f73f questionsmall
+f760 Gravesmall
+f761 Asmall
+f762 Bsmall
+f763 Csmall
+f764 Dsmall
+f765 Esmall
+f766 Fsmall
+f767 Gsmall
+f768 Hsmall
+f769 Ismall
+f76a Jsmall
+f76b Ksmall
+f76c Lsmall
+f76d Msmall
+f76e Nsmall
+f76f Osmall
+f770 Psmall
+f771 Qsmall
+f772 Rsmall
+f773 Ssmall
+f774 Tsmall
+f775 Usmall
+f776 Vsmall
+f777 Wsmall
+f778 Xsmall
+f779 Ysmall
+f77a Zsmall
+f7a1 exclamdownsmall
+f7a2 centoldstyle
+f7a8 Dieresissmall
+f7af Macronsmall
+f7b4 Acutesmall
+f7b8 Cedillasmall
+f7bf questiondownsmall
+f7e0 Agravesmall
+f7e1 Aacutesmall
+f7e2 Acircumflexsmall
+f7e3 Atildesmall
+f7e4 Adieresissmall
+f7e5 Aringsmall
+f7e6 AEsmall
+f7e7 Ccedillasmall
+f7e8 Egravesmall
+f7e9 Eacutesmall
+f7ea Ecircumflexsmall
+f7eb Edieresissmall
+f7ec Igravesmall
+f7ed Iacutesmall
+f7ee Icircumflexsmall
+f7ef Idieresissmall
+f7f0 Ethsmall
+f7f1 Ntildesmall
+f7f2 Ogravesmall
+f7f3 Oacutesmall
+f7f4 Ocircumflexsmall
+f7f5 Otildesmall
+f7f6 Odieresissmall
+f7f8 Oslashsmall
+f7f9 Ugravesmall
+f7fa Uacutesmall
+f7fb Ucircumflexsmall
+f7fc Udieresissmall
+f7fd Yacutesmall
+f7fe Thornsmall
+f7ff Ydieresissmall
+f8e5 radicalex
+f8e6 arrowvertex
+f8e7 arrowhorizex
+f8e8 registersans
+f8e9 copyrightsans
+f8ea trademarksans
+f8eb parenlefttp
+f8ec parenleftex
+f8ed parenleftbt
+f8ee bracketlefttp
+f8ef bracketleftex
+f8f0 bracketleftbt
+f8f1 bracelefttp
+f8f2 braceleftmid
+f8f3 braceleftbt
+f8f4 braceex
+f8f5 integralex
+f8f6 parenrighttp
+f8f7 parenrightex
+f8f8 parenrightbt
+f8f9 bracketrighttp
+f8fa bracketrightex
+f8fb bracketrightbt
+f8fc bracerighttp
+f8fd bracerightmid
+f8fe bracerightbt
+fb00 ff
+fb01 fi
+fb02 fl
+fb03 ffi
+fb04 ffl
+fb1f afii57705
+fb2a afii57694
+fb2b afii57695
+fb35 afii57723
+fb4b afii57700
diff --git a/data/raster.defs b/data/raster.defs
new file mode 100644
index 000000000..486165f01
--- /dev/null
+++ b/data/raster.defs
@@ -0,0 +1,94 @@
+/*
+ * "$Id: raster.defs 343 2007-07-13 19:52:48Z mike $"
+ *
+ * This file contains the standard definitions for enumerated attributes
+ * in the CUPS raster page device dictionary.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/* Jog values */
+#define CUPS_JOG_NONE 0 /* Never move pages */
+#define CUPS_JOG_FILE 1 /* Move pages after this file */
+#define CUPS_JOG_JOB 2 /* Move pages after this job */
+#define CUPS_JOG_SET 3 /* Move pages after this set */
+
+/* Orientation values */
+#define CUPS_ORIENT_0 0 /* Don't rotate the page */
+#define CUPS_ORIENT_90 1 /* Rotate the page counter-clockwise */
+#define CUPS_ORIENT_180 2 /* Turn the page upside down */
+#define CUPS_ORIENT_270 3 /* Rotate the page clockwise */
+
+/* CutMedia values */
+#define CUPS_CUT_NONE 0 /* Never cut the roll */
+#define CUPS_CUT_FILE 1 /* Cut the roll after this file */
+#define CUPS_CUT_JOB 2 /* Cut the roll after this job */
+#define CUPS_CUT_SET 3 /* Cut the roll after this set */
+#define CUPS_CUT_PAGE 4 /* Cut the roll after this page */
+
+/* AdvanceMedia values */
+#define CUPS_ADVANCE_NONE 0 /* Never advance the roll */
+#define CUPS_ADVANCE_FILE 1 /* Advance the roll after this file */
+#define CUPS_ADVANCE_JOB 2 /* Advance the roll after this job */
+#define CUPS_ADVANCE_SET 3 /* Advance the roll after this set */
+#define CUPS_ADVANCE_PAGE 4 /* Advance the roll after this page */
+
+/* LeadingEdge values */
+#define CUPS_EDGE_TOP 0 /* Leading edge is the top of the page */
+#define CUPS_EDGE_RIGHT 1 /* Leading edge is the right of the page */
+#define CUPS_EDGE_BOTTOM 2 /* Leading edge is the bottom of the page */
+#define CUPS_EDGE_LEFT 3 /* Leading edge is the left of the page */
+
+/* cupsColorOrder values */
+#define CUPS_ORDER_CHUNKED 0 /* CMYK CMYK CMYK ... */
+#define CUPS_ORDER_BANDED 1 /* CCC MMM YYY KKK ... */
+#define CUPS_ORDER_PLANAR 2 /* CCC ... MMM ... YYY ... KKK ... */
+
+/* cupsColorSpace values */
+#define CUPS_CSPACE_W 0 /* Luminance */
+#define CUPS_CSPACE_RGB 1 /* Red, green, blue */
+#define CUPS_CSPACE_RGBA 2 /* Red, green, blue, alpha */
+#define CUPS_CSPACE_K 3 /* Black */
+#define CUPS_CSPACE_CMY 4 /* Cyan, magenta, yellow */
+#define CUPS_CSPACE_YMC 5 /* Yellow, magenta, cyan */
+#define CUPS_CSPACE_CMYK 6 /* Cyan, magenta, yellow, black */
+#define CUPS_CSPACE_YMCK 7 /* Yellow, magenta, cyan, black */
+#define CUPS_CSPACE_KCMY 8 /* Black, cyan, magenta, yellow */
+#define CUPS_CSPACE_KCMYcm 9 /* Black, cyan, magenta, yellow, *
+ * light-cyan, light-magenta */
+#define CUPS_CSPACE_GMCK 10 /* Gold, magenta, yellow, black */
+#define CUPS_CSPACE_GMCS 11 /* Gold, magenta, yellow, silver */
+#define CUPS_CSPACE_WHITE 12 /* White ink (as black) */
+#define CUPS_CSPACE_GOLD 13 /* Gold foil */
+#define CUPS_CSPACE_SILVER 14 /* Silver foil */
+
+#define CUPS_CSPACE_CIEXYZ 15 /* CIE XYZ */
+#define CUPS_CSPACE_CIELab 16 /* CIE Lab */
+
+#define CUPS_CSPACE_ICC1 32 /* ICC-based, 1 color */
+#define CUPS_CSPACE_ICC2 33 /* ICC-based, 2 colors */
+#define CUPS_CSPACE_ICC3 34 /* ICC-based, 3 colors */
+#define CUPS_CSPACE_ICC4 35 /* ICC-based, 4 colors */
+#define CUPS_CSPACE_ICC5 36 /* ICC-based, 5 colors */
+#define CUPS_CSPACE_ICC6 37 /* ICC-based, 6 colors */
+#define CUPS_CSPACE_ICC7 38 /* ICC-based, 7 colors */
+#define CUPS_CSPACE_ICC8 39 /* ICC-based, 8 colors */
+#define CUPS_CSPACE_ICC9 40 /* ICC-based, 9 colors */
+#define CUPS_CSPACE_ICCA 41 /* ICC-based, 10 colors */
+#define CUPS_CSPACE_ICCB 42 /* ICC-based, 11 colors */
+#define CUPS_CSPACE_ICCC 43 /* ICC-based, 12 colors */
+#define CUPS_CSPACE_ICCD 44 /* ICC-based, 13 colors */
+#define CUPS_CSPACE_ICCE 45 /* ICC-based, 14 colors */
+#define CUPS_CSPACE_ICCF 46 /* ICC-based, 15 colors */
+
+
+/*
+ * End of "$Id: raster.defs 343 2007-07-13 19:52:48Z mike $".
+ */
diff --git a/data/secret b/data/secret
new file mode 100644
index 000000000..66a0e8a91
--- /dev/null
+++ b/data/secret
@@ -0,0 +1,6 @@
+#CUPS-BANNER
+Show job-id job-name job-originating-user-name job-originating-host-name job-billing
+Header Secret
+Footer Secret
+Image images/cups.png
+
diff --git a/data/smiley.ps b/data/smiley.ps
new file mode 100644
index 000000000..6ff31fdfb
--- /dev/null
+++ b/data/smiley.ps
@@ -0,0 +1,28 @@
+%!PS-Adobe-3.0
+%%BoundingBox: 36 36 576 756
+%%Pages: 1
+%%LanguageLevel: 2
+%%EndComments
+%%Page: (1) 1
+% Draw a black box around the page
+0 setgray
+1 setlinewidth
+36 36 540 720 rectstroke
+
+% Draw a two inch blue circle in the middle of the page
+0 0 1 setrgbcolor
+306 396 144 0 360 arc closepath fill
+
+% Draw two half inch yellow circles for eyes
+1 1 0 setrgbcolor
+252 432 36 0 360 arc closepath fill
+360 432 36 0 360 arc closepath fill
+
+% Draw the smile
+1 setlinecap
+18 setlinewidth
+306 396 99 200 340 arc stroke
+
+% Print it!
+showpage
+%%EOF
diff --git a/data/standard b/data/standard
new file mode 100644
index 000000000..31c68a08e
--- /dev/null
+++ b/data/standard
@@ -0,0 +1,6 @@
+#CUPS-BANNER
+Show job-id job-name job-originating-user-name job-originating-host-name job-billing
+Header Cover Page
+Footer Cover Page
+Image images/cups.png
+
diff --git a/data/testprint.in b/data/testprint.in
new file mode 100644
index 000000000..8cee3ab4f
--- /dev/null
+++ b/data/testprint.in
@@ -0,0 +1,7 @@
+#CUPS-BANNER
+Show printer-name printer-info printer-location printer-make-and-model printer-driver-name printer-driver-version paper-size imageable-area
+Header Printer Test Page
+Footer Printer Test Page
+Notice CUPS @CUPS_VERSION@.
+Image images/cups.png
+Image images/color-wheel.png
diff --git a/data/topsecret b/data/topsecret
new file mode 100644
index 000000000..d2b87fabb
--- /dev/null
+++ b/data/topsecret
@@ -0,0 +1,6 @@
+#CUPS-BANNER
+Show job-id job-name job-originating-user-name job-originating-host-name job-billing
+Header Top Secret
+Footer Top Secret
+Image images/cups.png
+
diff --git a/data/unclassified b/data/unclassified
new file mode 100644
index 000000000..2d1a7d0f9
--- /dev/null
+++ b/data/unclassified
@@ -0,0 +1,6 @@
+#CUPS-BANNER
+Show job-id job-name job-originating-user-name job-originating-host-name job-billing
+Header Unclassified
+Footer Unclassified
+Image images/cups.png
+
diff --git a/data/utf-8 b/data/utf-8
new file mode 100644
index 000000000..044691b46
--- /dev/null
+++ b/data/utf-8
@@ -0,0 +1,40 @@
+charset utf8
+
+#
+# This file defines the font mappings used for Unicode/UTF-8 text printing.
+#
+# Each line consists of:
+#
+# first last direction width normal bold italic bold-italic
+#
+# First and last are the first and last glyphs in the font mapping
+# that correspond to that font; a maximum of 256 characters can be
+# mapped within each group, with a maximum of 256 mappings (this is a
+# PostScript limitation.) The glyph values are hexadecimal.
+#
+# Direction is the string "ltor" or "rtol", indicating left-to-right or
+# right-to-left text.
+#
+# Width is the string "single" or "double"; double means that the glyphs
+# are twice as wide as ASCII characters in the Monospace typeface.
+#
+# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use
+# for each presentation. If characters are only available in a single
+# style then only one typeface should be listed, e.g.
+#
+# 1000 10ff ltor single Monospace
+#
+# Each font that is listed will be downloaded to the printer when used.
+#
+
+0000 00FF ltor single Monospace Monospace-Bold Monospace-Oblique Monospace-BoldOblique
+0100 01FF ltor single Monospace Monospace-Bold Monospace-Oblique Monospace-BoldOblique
+0200 02FF ltor single Monospace Monospace-Bold Monospace-Oblique Monospace-BoldOblique
+0300 03FF ltor single Monospace Monospace-Bold Monospace-Oblique Monospace-BoldOblique
+0400 04FF ltor single Monospace Monospace-Bold Monospace-Oblique Monospace-BoldOblique
+1E00 1EFF ltor single Monospace Monospace-Bold Monospace-Oblique Monospace-BoldOblique
+2000 20FF ltor single Monospace Monospace-Bold Monospace-Oblique Monospace-BoldOblique
+2300 23FF ltor single Monospace Monospace-Bold Monospace-Oblique Monospace-BoldOblique
+2400 24FF ltor single Monospace Monospace-Bold Monospace-Oblique Monospace-BoldOblique
+2500 25FF ltor single Monospace Monospace-Bold Monospace-Oblique Monospace-BoldOblique
+2600 26FF ltor single Monospace Monospace-Bold Monospace-Oblique Monospace-BoldOblique
diff --git a/desktop/Makefile b/desktop/Makefile
new file mode 100644
index 000000000..9d786f6f0
--- /dev/null
+++ b/desktop/Makefile
@@ -0,0 +1,135 @@
+#
+# "$Id$"
+#
+# Desktop makefile for CUPS.
+#
+# Copyright 2007-2009 by Apple Inc.
+# Copyright 1993-2006 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+
+#
+# Make everything...
+#
+
+all:
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Clean all config and object files...
+#
+
+clean:
+
+
+#
+# Dummy depend...
+#
+
+depend:
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+ if test "x$(DBUSDIR)" != x; then \
+ echo Installing cups.conf in $(DBUSDIR)...;\
+ $(INSTALL_DIR) -m 755 $(BUILDROOT)$(DBUSDIR)/system.d; \
+ $(INSTALL_DATA) cups.conf $(BUILDROOT)$(DBUSDIR)/system.d/cups.conf; \
+ fi
+ if test "x$(MENUDIR)" != x; then \
+ echo Installing desktop menu...; \
+ $(INSTALL_DIR) -m 755 $(BUILDROOT)$(MENUDIR); \
+ $(INSTALL_DATA) cups.desktop $(BUILDROOT)$(MENUDIR); \
+ fi
+ if test "x$(ICONDIR)" != x; then \
+ echo Installing desktop icons...; \
+ $(INSTALL_DIR) -m 755 $(BUILDROOT)$(ICONDIR)/hicolor/16x16/apps; \
+ $(INSTALL_DATA) cups-16.png $(BUILDROOT)$(ICONDIR)/hicolor/16x16/apps/cups.png; \
+ $(INSTALL_DIR) -m 755 $(BUILDROOT)$(ICONDIR)/hicolor/32x32/apps; \
+ $(INSTALL_DATA) cups-32.png $(BUILDROOT)$(ICONDIR)/hicolor/32x32/apps/cups.png; \
+ $(INSTALL_DIR) -m 755 $(BUILDROOT)$(ICONDIR)/hicolor/64x64/apps; \
+ $(INSTALL_DATA) cups-64.png $(BUILDROOT)$(ICONDIR)/hicolor/64x64/apps/cups.png; \
+ $(INSTALL_DIR) -m 755 $(BUILDROOT)$(ICONDIR)/hicolor/128x128/apps; \
+ $(INSTALL_DATA) cups-128.png $(BUILDROOT)$(ICONDIR)/hicolor/128x128/apps/cups.png; \
+ fi
+
+
+#
+# Install programs...
+#
+
+install-exec:
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall files...
+#
+
+uninstall:
+ if test "x$(DBUSDIR)" != x; then \
+ echo Uninstalling cups.conf in $(DBUSDIR)...;\
+ $(RM) $(BUILDROOT)$(DBUSDIR)/cups.conf; \
+ $(RMDIR) $(BUILDROOT)$(DBUSDIR); \
+ fi
+ if test "x$(MENUDIR)" != x; then \
+ echo Uninstalling desktop menu...; \
+ $(RM) $(BUILDROOT)$(MENUDIR)/cups.desktop; \
+ fi
+ if test "x$(ICONDIR)" != x; then \
+ echo Uninstalling desktop icons...; \
+ $(RM) $(BUILDROOT)$(ICONDIR)/hicolor/16x16/apps/cups.png; \
+ $(RM) $(BUILDROOT)$(ICONDIR)/hicolor/32x32/apps/cups.png; \
+ $(RM) $(BUILDROOT)$(ICONDIR)/hicolor/64x64/apps/cups.png; \
+ $(RM) $(BUILDROOT)$(ICONDIR)/hicolor/128x128/apps/cups.png; \
+ fi
+
+
+#
+# End of "$Id$".
+#
diff --git a/desktop/cups-128.png b/desktop/cups-128.png
new file mode 100644
index 000000000..5c0f6ff20
--- /dev/null
+++ b/desktop/cups-128.png
Binary files differ
diff --git a/desktop/cups-16.png b/desktop/cups-16.png
new file mode 100644
index 000000000..90614fed1
--- /dev/null
+++ b/desktop/cups-16.png
Binary files differ
diff --git a/desktop/cups-256.png b/desktop/cups-256.png
new file mode 100644
index 000000000..755dc2f37
--- /dev/null
+++ b/desktop/cups-256.png
Binary files differ
diff --git a/desktop/cups-32.png b/desktop/cups-32.png
new file mode 100644
index 000000000..823c6d4aa
--- /dev/null
+++ b/desktop/cups-32.png
Binary files differ
diff --git a/desktop/cups-512.png b/desktop/cups-512.png
new file mode 100644
index 000000000..54a1b3bdc
--- /dev/null
+++ b/desktop/cups-512.png
Binary files differ
diff --git a/desktop/cups-64.png b/desktop/cups-64.png
new file mode 100644
index 000000000..21d19cc28
--- /dev/null
+++ b/desktop/cups-64.png
Binary files differ
diff --git a/desktop/cups.conf b/desktop/cups.conf
new file mode 100644
index 000000000..537ac7765
--- /dev/null
+++ b/desktop/cups.conf
@@ -0,0 +1,13 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <!-- Only root can send this message -->
+ <policy user="root">
+ <allow send_interface="com.redhat.PrinterSpooler"/>
+ </policy>
+
+ <!-- Allow any connection to receive the message -->
+ <policy context="default">
+ <allow receive_interface="com.redhat.PrinterSpooler"/>
+ </policy>
+</busconfig>
diff --git a/desktop/cups.desktop.in b/desktop/cups.desktop.in
new file mode 100644
index 000000000..44bb115f8
--- /dev/null
+++ b/desktop/cups.desktop.in
@@ -0,0 +1,39 @@
+[Desktop Entry]
+Categories=System;Printing;HardwareSettings;X-Red-Hat-Base;
+Exec=@CUPS_HTMLVIEW@ http://localhost:631/
+Icon=cups
+StartupNotify=false
+Terminal=false
+Type=Application
+Name=Manage Printing
+Comment=CUPS Web Interface
+Name[de]=Druckerverwaltung
+Comment[de]=CUPS Webinterface
+Name[en_US]=Manage Printing
+Comment[en_US]=CUPS Web Interface
+Name[es]=Administrar impresión
+Comment[es]=Interfaz Web de CUPS
+Name[et]=Trükkimise haldur
+Comment[et]=CUPS-i veebiliides
+Name[eu]=Kudeatu inprimaketak
+Comment[eu]=CUPSen web interfazea
+Name[fr]=Gestionnaire d'impression
+Comment[fr]=Interface Web de CUPS
+Name[he]=נהל הדפסות
+Comment[he]=ממשק דפדפן של CUPS
+Name[id]=Manajemen Pencetakan
+Comment[id]=Antarmuka Web CUPS
+Name[it]=Gestione stampa
+Comment[it]=Interfaccia web di CUPS
+Name[ja]=å°åˆ·ã®ç®¡ç†
+Comment[ja]=CUPS Web インタフェース
+Name[pl]=ZarzÄ…dzanie drukowaniem
+Comment[pl]=Interfejs WWW CUPS
+Name[ru]=ÐаÑтройка печати
+Comment[ru]=ÐаÑтройка CUPS
+Name[sv]=Hantera skrivare
+Comment[sv]=CUPS webb-gränssnitt
+Name[zh]=打å°æœºç®¡ç†
+Comment[zh]=CUPS网页界é¢
+Name[zh_TW]=å°è¡¨ç®¡ç†
+Comment[zh_TW]=CUPS 網é ä»‹é¢
diff --git a/desktop/cups.icns b/desktop/cups.icns
new file mode 100644
index 000000000..0fd7a35d5
--- /dev/null
+++ b/desktop/cups.icns
Binary files differ
diff --git a/desktop/cups.svg b/desktop/cups.svg
new file mode 100644
index 000000000..8d19c358c
--- /dev/null
+++ b/desktop/cups.svg
@@ -0,0 +1,533 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="100"
+ height="100"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docbase="/home/mike/c/cups-trunk/desktop"
+ sodipodi:docname="cups.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/msweet/c/cups-trunk/desktop/cups-512.png"
+ inkscape:export-xdpi="460.79999"
+ inkscape:export-ydpi="460.79999">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3645">
+ <stop
+ id="stop3647"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3649"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3515">
+ <stop
+ style="stop-color:#ccff66;stop-opacity:1;"
+ offset="0"
+ id="stop3517" />
+ <stop
+ style="stop-color:#00cc00;stop-opacity:1;"
+ offset="1"
+ id="stop3519" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3377">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3379" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3381" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3280">
+ <stop
+ style="stop-color:#ffffbf;stop-opacity:1;"
+ offset="0"
+ id="stop3282" />
+ <stop
+ style="stop-color:#ffffbf;stop-opacity:0;"
+ offset="1"
+ id="stop3284" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3270">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop3272" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3274" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3251">
+ <stop
+ style="stop-color:#ccff66;stop-opacity:1;"
+ offset="0"
+ id="stop3253" />
+ <stop
+ style="stop-color:#007700;stop-opacity:1;"
+ offset="1"
+ id="stop3255" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3416">
+ <stop
+ style="stop-color:#7fff00;stop-opacity:1;"
+ offset="0"
+ id="stop3418" />
+ <stop
+ style="stop-color:#1f7f00;stop-opacity:1;"
+ offset="1"
+ id="stop3420" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3530">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.74901962;"
+ offset="0"
+ id="stop3532" />
+ <stop
+ style="stop-color:#333333;stop-opacity:0;"
+ offset="1"
+ id="stop3534" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3690">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop3692" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3694" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3680">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.49803922"
+ offset="0"
+ id="stop3682" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3684" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3658">
+ <stop
+ style="stop-color:#cccc99;stop-opacity:1;"
+ offset="0"
+ id="stop3660" />
+ <stop
+ style="stop-color:#cccc99;stop-opacity:0;"
+ offset="1"
+ id="stop3662" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 50 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="100 : 50 : 1"
+ inkscape:persp3d-origin="50 : 33.333333 : 1"
+ id="perspective2838" />
+ <linearGradient
+ id="linearGradient3269">
+ <stop
+ style="stop-color:#00ff00;stop-opacity:1;"
+ offset="0"
+ id="stop3271" />
+ <stop
+ style="stop-color:#007f00;stop-opacity:1;"
+ offset="1"
+ id="stop3273" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3226">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop3228" />
+ <stop
+ style="stop-color:#333333;stop-opacity:1;"
+ offset="1"
+ id="stop3230" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3214">
+ <stop
+ style="stop-color:#00ff00;stop-opacity:1;"
+ offset="0"
+ id="stop3216" />
+ <stop
+ style="stop-color:#007f00;stop-opacity:1;"
+ offset="1"
+ id="stop3218" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5228">
+ <stop
+ style="stop-color:#cccc99;stop-opacity:0"
+ offset="0"
+ id="stop5230" />
+ <stop
+ id="stop5236"
+ offset="0.89999998"
+ style="stop-color:#cccc99;stop-opacity:0;" />
+ <stop
+ style="stop-color:#cccc99;stop-opacity:1"
+ offset="1"
+ id="stop5232" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5198">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop5200" />
+ <stop
+ style="stop-color:#333333;stop-opacity:0.94117647;"
+ offset="1"
+ id="stop5202" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5177">
+ <stop
+ style="stop-color:#cccc99;stop-opacity:1;"
+ offset="0"
+ id="stop5179" />
+ <stop
+ style="stop-color:#cccc99;stop-opacity:0.49803922"
+ offset="1"
+ id="stop5181" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4768">
+ <stop
+ id="stop4770"
+ offset="0"
+ style="stop-color:#e8e8e8;stop-opacity:0.90980393;" />
+ <stop
+ id="stop4772"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3598">
+ <stop
+ id="stop3600"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ <stop
+ id="stop3602"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2165">
+ <stop
+ style="stop-color:#350000;stop-opacity:1;"
+ offset="0"
+ id="stop2167" />
+ <stop
+ style="stop-color:#ff3333;stop-opacity:1;"
+ offset="1"
+ id="stop2169" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3196">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3198" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3200" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3160">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3162" />
+ <stop
+ id="stop3192"
+ offset="0.75"
+ style="stop-color:#ffffff;stop-opacity:0.24705882;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3164" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3257">
+ <path
+ transform="matrix(1,0,0,0.9882639,0,5.8678726e-2)"
+ d="M 95 50.534397 A 45 45.534397 0 1 1 5,50.534397 A 45 45.534397 0 1 1 95 50.534397 z"
+ sodipodi:ry="45.534397"
+ sodipodi:rx="45"
+ sodipodi:cy="50.534397"
+ sodipodi:cx="50"
+ id="path3259"
+ style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:type="arc" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3704">
+ <path
+ sodipodi:type="arc"
+ style="opacity:1;fill:#000000;fill-opacity:0.49803922;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path3706"
+ sodipodi:cx="51.104416"
+ sodipodi:cy="48.192772"
+ sodipodi:rx="39.658634"
+ sodipodi:ry="43.574299"
+ d="M 90.76305,48.192772 A 39.658634,43.574299 0 1 1 11.445782,48.192772 A 39.658634,43.574299 0 1 1 90.76305,48.192772 z"
+ transform="matrix(1.003038,0,0,1.0232718,-1.4805538,0.2740483)" />
+ </clipPath>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3270"
+ id="linearGradient3276"
+ x1="50.200802"
+ y1="91.967865"
+ x2="50.200802"
+ y2="67.948906"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3280"
+ id="linearGradient3286"
+ x1="47.690762"
+ y1="6.6265068"
+ x2="47.690762"
+ y2="53.815262"
+ gradientUnits="userSpaceOnUse" />
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3295">
+ <path
+ transform="matrix(0.8148984,0,0,0.6256338,5.5549494,4.4908095)"
+ d="M 96.184742,26.706827 A 44.477913,23.293173 0 1 1 7.2289162,26.706827 A 44.477913,23.293173 0 1 1 96.184742,26.706827 z"
+ sodipodi:ry="23.293173"
+ sodipodi:rx="44.477913"
+ sodipodi:cy="26.706827"
+ sodipodi:cx="51.706829"
+ id="path3297"
+ style="opacity:1;fill:#ffffbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3371">
+ <path
+ sodipodi:type="arc"
+ style="opacity:1;fill:#ffffbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path3373"
+ sodipodi:cx="48.895584"
+ sodipodi:cy="47.188755"
+ sodipodi:rx="42.269077"
+ sodipodi:ry="41.767067"
+ d="M 91.164661,47.188755 A 42.269077,41.767067 0 1 1 6.6265068,47.188755 A 42.269077,41.767067 0 1 1 91.164661,47.188755 z"
+ transform="matrix(0.9784331,0,0,0.9984421,2.7613512,2.0815482)" />
+ </clipPath>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3515"
+ id="radialGradient3521"
+ cx="51.405624"
+ cy="71.446022"
+ fx="51.405624"
+ fy="71.446022"
+ r="41.566265"
+ gradientTransform="matrix(1,0,0,1.5633645,0,-39.484036)"
+ gradientUnits="userSpaceOnUse" />
+ <filter
+ inkscape:collect="always"
+ id="filter3587"
+ x="-0.12220446"
+ width="1.2444089"
+ y="-0.11793158"
+ height="1.2358632">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="4.2329858"
+ id="feGaussianBlur3589" />
+ </filter>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3591">
+ <path
+ transform="translate(2.9340892e-7,-2.3929013)"
+ d="M 92.971889,50.301205 A 41.566265,43.072289 0 1 1 9.8393593,50.301205 A 41.566265,43.072289 0 1 1 92.971889,50.301205 z"
+ sodipodi:ry="43.072289"
+ sodipodi:rx="41.566265"
+ sodipodi:cy="50.301205"
+ sodipodi:cx="51.405624"
+ id="path3593"
+ style="opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ </clipPath>
+ <filter
+ inkscape:collect="always"
+ id="filter3611">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="2.1711472"
+ id="feGaussianBlur3613" />
+ </filter>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3645"
+ id="radialGradient3695"
+ cx="-6.7269073"
+ cy="27.94368"
+ fx="-6.7269073"
+ fy="27.94368"
+ r="12.5502"
+ gradientTransform="matrix(-1.9906652,-2.2927541e-8,1.4386067e-8,-1.5156153,-20.117928,50.98641)"
+ gradientUnits="userSpaceOnUse" />
+ <filter
+ inkscape:collect="always"
+ id="filter3797"
+ x="-0.098526749"
+ width="1.1970535"
+ y="-0.15589675"
+ height="1.3117935">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="1.030442"
+ id="feGaussianBlur3799" />
+ </filter>
+ <filter
+ inkscape:collect="always"
+ id="filter3807">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.1030442"
+ id="feGaussianBlur3809" />
+ </filter>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3645"
+ id="radialGradient3815"
+ cx="-6.7269082"
+ cy="29.116467"
+ fx="-6.7269082"
+ fy="29.116467"
+ r="12.5502"
+ gradientTransform="matrix(-1,-6.831379e-8,3.8912925e-8,-0.6320001,-13.453817,27.036147)"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="1"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.98"
+ inkscape:cx="50"
+ inkscape:cy="50"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ width="100px"
+ height="100px"
+ showgrid="true"
+ inkscape:grid-points="true"
+ inkscape:window-width="872"
+ inkscape:window-height="713"
+ inkscape:window-x="2458"
+ inkscape:window-y="22"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:snap-global="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2840" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ <dc:title>CUPS Icon</dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Michael Sweet</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>Apple Inc.</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ id="g2882"
+ transform="matrix(1.1282649,0,0,1.1259993,-5.472226,-6.4135954)">
+ <path
+ id="text2870"
+ d="M 72.501767,34.960416 L 82.666767,34.960416 C 82.096028,30.894474 80.883363,27.327811 79.028767,24.260416 C 77.174033,21.121817 74.855702,18.518153 72.073767,16.449416 C 69.291708,14.380824 66.117378,12.811492 62.550767,11.741416 C 58.984052,10.671494 55.203389,10.136495 51.208767,10.136416 C 45.359398,10.136495 40.15207,11.206494 35.586767,13.346416 C 31.092746,15.415156 27.312083,18.268487 24.244767,21.906416 C 21.248756,25.544479 18.966092,29.824475 17.396767,34.746416 C 15.827428,39.597132 15.042762,44.80446 15.042767,50.368416 C 15.042762,55.932449 15.756095,61.139777 17.182767,65.990416 C 18.680758,70.841101 20.89209,75.049763 23.816767,78.616416 C 26.741417,82.183089 30.41508,85.000753 34.837767,87.069416 C 39.260405,89.066749 44.432066,90.065415 50.352767,90.065416 C 60.125384,90.065415 67.829376,87.390417 73.464767,82.040416 C 79.100031,76.690428 82.417028,69.200436 83.415767,59.570416 L 73.250767,59.570416 C 73.036704,62.709109 72.394705,65.633772 71.324767,68.344416 C 70.254707,71.0551 68.756708,73.409098 66.830767,75.406416 C 64.976046,77.332427 62.729048,78.866093 60.089767,80.007416 C 57.52172,81.077424 54.561389,81.612423 51.208767,81.612416 C 46.643397,81.612423 42.720068,80.756424 39.438767,79.044416 C 36.157408,77.332427 33.446744,75.049763 31.306767,72.196416 C 29.238081,69.271769 27.704416,65.883439 26.705767,62.031416 C 25.707085,58.108113 25.207752,53.970784 25.207767,49.619416 C 25.207752,45.624793 25.707085,41.772796 26.705767,38.063416 C 27.704416,34.354137 29.238081,31.072807 31.306767,28.219416 C 33.446744,25.294813 36.121741,22.976482 39.331767,21.264416 C 42.613068,19.552485 46.536397,18.696486 51.101767,18.696416 C 56.451721,18.696486 61.052716,20.051818 64.904767,22.762416 C 68.828042,25.473146 71.360372,29.539142 72.501767,34.960416"
+ style="font-size:107px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Helvetica Neue;-inkscape-font-specification:Helvetica Neue" />
+ <path
+ id="text2862"
+ d="M 40.964993,34.10077 L 40.964993,29.66077 L 39.394993,29.66077 L 39.394993,34.10077 C 39.394987,34.634105 39.288321,35.027438 39.074993,35.28077 C 38.861655,35.527438 38.474988,35.650771 37.914993,35.65077 C 37.594989,35.650771 37.338323,35.607438 37.144993,35.52077 C 36.958323,35.427438 36.811657,35.310771 36.704993,35.17077 C 36.598323,35.024105 36.528324,34.857438 36.494993,34.67077 C 36.461657,34.484105 36.44499,34.294106 36.444993,34.10077 L 36.444993,29.66077 L 34.874993,29.66077 L 34.874993,34.10077 C 34.874992,35.074105 35.138325,35.794104 35.664993,36.26077 C 36.198324,36.727437 36.948323,36.96077 37.914993,36.96077 C 38.868321,36.96077 39.614987,36.727437 40.154993,36.26077 C 40.694986,35.787437 40.964986,35.067438 40.964993,34.10077 M 42.326868,29.66077 L 42.326868,36.80077 L 43.796868,36.80077 L 43.796868,32.02077 L 43.816868,32.02077 L 46.786868,36.80077 L 48.356868,36.80077 L 48.356868,29.66077 L 46.886868,29.66077 L 46.886868,34.45077 L 46.866868,34.45077 L 43.886868,29.66077 L 42.326868,29.66077 M 49.729211,29.66077 L 49.729211,36.80077 L 51.299211,36.80077 L 51.299211,29.66077 L 49.729211,29.66077 M 54.408899,33.06077 L 51.918899,36.80077 L 53.678899,36.80077 L 55.268899,34.33077 L 56.828899,36.80077 L 58.698899,36.80077 L 56.208899,33.07077 L 58.498899,29.66077 L 56.778899,29.66077 L 55.328899,31.94077 L 53.928899,29.66077 L 52.108899,29.66077 L 54.408899,33.06077 M 36.474993,43.02077 L 36.474993,40.88077 L 37.694993,40.88077 C 37.874989,40.880776 38.048322,40.894109 38.214993,40.92077 C 38.381655,40.947442 38.528322,41.000776 38.654993,41.08077 C 38.781655,41.154109 38.881655,41.260775 38.954993,41.40077 C 39.034988,41.540775 39.074988,41.724108 39.074993,41.95077 C 39.074988,42.177441 39.034988,42.360774 38.954993,42.50077 C 38.881655,42.640774 38.781655,42.750774 38.654993,42.83077 C 38.528322,42.904107 38.381655,42.954107 38.214993,42.98077 C 38.048322,43.00744 37.874989,43.020774 37.694993,43.02077 L 36.474993,43.02077 M 34.904993,39.66077 L 34.904993,46.80077 L 36.474993,46.80077 L 36.474993,44.24077 L 38.124993,44.24077 C 38.571655,44.240772 38.951654,44.177439 39.264993,44.05077 C 39.57832,43.917439 39.831654,43.744106 40.024993,43.53077 C 40.224987,43.31744 40.36832,43.074107 40.454993,42.80077 C 40.54832,42.520774 40.594986,42.237441 40.594993,41.95077 C 40.594986,41.657442 40.54832,41.374109 40.454993,41.10077 C 40.36832,40.827442 40.224987,40.584109 40.024993,40.37077 C 39.831654,40.157443 39.57832,39.987443 39.264993,39.86077 C 38.951654,39.727444 38.571655,39.660777 38.124993,39.66077 L 34.904993,39.66077 M 43.135149,42.89077 L 43.135149,40.88077 L 44.855149,40.88077 C 45.215144,40.880776 45.485144,40.960776 45.665149,41.12077 C 45.845144,41.274109 45.935144,41.524108 45.935149,41.87077 C 45.935144,42.230774 45.845144,42.490774 45.665149,42.65077 C 45.485144,42.810774 45.215144,42.890774 44.855149,42.89077 L 43.135149,42.89077 M 41.565149,39.66077 L 41.565149,46.80077 L 43.135149,46.80077 L 43.135149,44.01077 L 44.705149,44.01077 C 45.098478,44.010773 45.381811,44.097439 45.555149,44.27077 C 45.728477,44.444105 45.84181,44.717439 45.895149,45.09077 C 45.935144,45.377438 45.965144,45.677438 45.985149,45.99077 C 46.005144,46.304104 46.058477,46.574103 46.145149,46.80077 L 47.715149,46.80077 C 47.641809,46.70077 47.585142,46.58077 47.545149,46.44077 C 47.511809,46.294104 47.485142,46.14077 47.465149,45.98077 C 47.451809,45.820771 47.441809,45.664104 47.435149,45.51077 C 47.428476,45.357438 47.421809,45.224105 47.415149,45.11077 C 47.401809,44.930772 47.375142,44.750772 47.335149,44.57077 C 47.301809,44.390772 47.245142,44.227439 47.165149,44.08077 C 47.085143,43.927439 46.981809,43.797439 46.855149,43.69077 C 46.728476,43.57744 46.568476,43.494106 46.375149,43.44077 L 46.375149,43.42077 C 46.775143,43.260773 47.061809,43.02744 47.235149,42.72077 C 47.415142,42.414108 47.505142,42.050775 47.505149,41.63077 C 47.505142,41.357442 47.455142,41.104109 47.355149,40.87077 C 47.261809,40.630776 47.121809,40.420776 46.935149,40.24077 C 46.755143,40.060777 46.535143,39.920777 46.275149,39.82077 C 46.02181,39.71411 45.735144,39.660777 45.415149,39.66077 L 41.565149,39.66077 M 48.77218,39.66077 L 48.77218,46.80077 L 50.34218,46.80077 L 50.34218,39.66077 L 48.77218,39.66077 M 51.701868,39.66077 L 51.701868,46.80077 L 53.171868,46.80077 L 53.171868,42.02077 L 53.191868,42.02077 L 56.161868,46.80077 L 57.731868,46.80077 L 57.731868,39.66077 L 56.261868,39.66077 L 56.261868,44.45077 L 56.241868,44.45077 L 53.261868,39.66077 L 51.701868,39.66077 M 60.684211,40.98077 L 60.684211,46.80077 L 62.254211,46.80077 L 62.254211,40.98077 L 64.394211,40.98077 L 64.394211,39.66077 L 58.544211,39.66077 L 58.544211,40.98077 L 60.684211,40.98077 M 65.237024,39.66077 L 65.237024,46.80077 L 66.807024,46.80077 L 66.807024,39.66077 L 65.237024,39.66077 M 68.166711,39.66077 L 68.166711,46.80077 L 69.636711,46.80077 L 69.636711,42.02077 L 69.656711,42.02077 L 72.626711,46.80077 L 74.196711,46.80077 L 74.196711,39.66077 L 72.726711,39.66077 L 72.726711,44.45077 L 72.706711,44.45077 L 69.726711,39.66077 L 68.166711,39.66077 M 80.729055,45.99077 L 80.889055,46.80077 L 81.889055,46.80077 L 81.889055,42.94077 L 78.889055,42.94077 L 78.889055,44.11077 L 80.469055,44.11077 C 80.422383,44.610772 80.255716,44.994105 79.969055,45.26077 C 79.68905,45.520771 79.289051,45.650771 78.769055,45.65077 C 78.415718,45.650771 78.115718,45.584104 77.869055,45.45077 C 77.622386,45.310771 77.422386,45.127438 77.269055,44.90077 C 77.115719,44.674105 77.002386,44.420772 76.929055,44.14077 C 76.862386,43.854106 76.829053,43.560773 76.829055,43.26077 C 76.829053,42.94744 76.862386,42.644107 76.929055,42.35077 C 77.002386,42.057441 77.115719,41.797441 77.269055,41.57077 C 77.422386,41.337442 77.622386,41.154109 77.869055,41.02077 C 78.115718,40.880776 78.415718,40.810776 78.769055,40.81077 C 79.149051,40.810776 79.472384,40.910776 79.739055,41.11077 C 80.005717,41.310775 80.185716,41.610775 80.279055,42.01077 L 81.779055,42.01077 C 81.739048,41.604108 81.629048,41.244109 81.449055,40.93077 C 81.269049,40.617443 81.039049,40.35411 80.759055,40.14077 C 80.485716,39.927443 80.175716,39.767444 79.829055,39.66077 C 79.48905,39.547444 79.135717,39.490777 78.769055,39.49077 C 78.222385,39.490777 77.729052,39.587444 77.289055,39.78077 C 76.85572,39.97411 76.489053,40.240776 76.189055,40.58077 C 75.889054,40.920776 75.659054,41.320775 75.499055,41.78077 C 75.339055,42.234108 75.259055,42.727441 75.259055,43.26077 C 75.259055,43.780773 75.339055,44.267439 75.499055,44.72077 C 75.659054,45.167438 75.889054,45.557438 76.189055,45.89077 C 76.489053,46.224104 76.85572,46.487437 77.289055,46.68077 C 77.729052,46.867436 78.222385,46.96077 78.769055,46.96077 C 79.115717,46.96077 79.45905,46.89077 79.799055,46.75077 C 80.13905,46.604103 80.449049,46.35077 80.729055,45.99077 M 35.974993,54.43077 L 34.454993,54.43077 C 34.448326,54.870772 34.528326,55.250771 34.694993,55.57077 C 34.861659,55.890771 35.084992,56.154104 35.364993,56.36077 C 35.651658,56.567437 35.978324,56.717437 36.344993,56.81077 C 36.718323,56.91077 37.101656,56.96077 37.494993,56.96077 C 37.981655,56.96077 38.408322,56.904103 38.774993,56.79077 C 39.148321,56.677437 39.458321,56.52077 39.704993,56.32077 C 39.95832,56.114104 40.14832,55.870771 40.274993,55.59077 C 40.401653,55.310771 40.464986,55.007438 40.464993,54.68077 C 40.464986,54.280772 40.37832,53.954106 40.204993,53.70077 C 40.03832,53.440773 39.83832,53.234107 39.604993,53.08077 C 39.371654,52.92744 39.134988,52.81744 38.894993,52.75077 C 38.661655,52.677441 38.478322,52.627441 38.344993,52.60077 C 37.898322,52.487441 37.534989,52.394108 37.254993,52.32077 C 36.981656,52.247441 36.76499,52.174108 36.604993,52.10077 C 36.451657,52.027441 36.348324,51.947441 36.294993,51.86077 C 36.241657,51.774108 36.214991,51.660775 36.214993,51.52077 C 36.214991,51.367442 36.248324,51.240775 36.314993,51.14077 C 36.381657,51.040776 36.46499,50.957442 36.564993,50.89077 C 36.671657,50.824109 36.788323,50.777442 36.914993,50.75077 C 37.041656,50.724109 37.168323,50.710776 37.294993,50.71077 C 37.488323,50.710776 37.664989,50.727443 37.824993,50.76077 C 37.991655,50.794109 38.138322,50.850776 38.264993,50.93077 C 38.391655,51.010776 38.491655,51.120775 38.564993,51.26077 C 38.644988,51.400775 38.691655,51.577442 38.704993,51.79077 L 40.224993,51.79077 C 40.224987,51.377442 40.144987,51.027442 39.984993,50.74077 C 39.831654,50.447443 39.621654,50.207443 39.354993,50.02077 C 39.088321,49.83411 38.781655,49.700777 38.434993,49.62077 C 38.094989,49.53411 37.738322,49.490777 37.364993,49.49077 C 37.04499,49.490777 36.72499,49.53411 36.404993,49.62077 C 36.084991,49.707444 35.798324,49.840777 35.544993,50.02077 C 35.291658,50.200776 35.084992,50.427443 34.924993,50.70077 C 34.771659,50.967442 34.694992,51.284109 34.694993,51.65077 C 34.694992,51.977441 34.754992,52.257441 34.874993,52.49077 C 35.001658,52.717441 35.164992,52.90744 35.364993,53.06077 C 35.564991,53.214107 35.791658,53.340773 36.044993,53.44077 C 36.298324,53.534106 36.558324,53.614106 36.824993,53.68077 C 37.08499,53.754106 37.341656,53.820773 37.594993,53.88077 C 37.848322,53.940773 38.074989,54.010773 38.274993,54.09077 C 38.474988,54.170772 38.634988,54.270772 38.754993,54.39077 C 38.881655,54.510772 38.944988,54.667439 38.944993,54.86077 C 38.944988,55.040772 38.898321,55.190771 38.804993,55.31077 C 38.711655,55.424105 38.594988,55.514104 38.454993,55.58077 C 38.314988,55.647438 38.164989,55.694104 38.004993,55.72077 C 37.844989,55.740771 37.694989,55.750771 37.554993,55.75077 C 37.348323,55.750771 37.148323,55.727438 36.954993,55.68077 C 36.761657,55.627438 36.591657,55.550771 36.444993,55.45077 C 36.30499,55.344105 36.191657,55.207438 36.104993,55.04077 C 36.018324,54.874105 35.974991,54.670772 35.974993,54.43077 M 43.239368,54.02077 L 43.239368,56.80077 L 44.809368,56.80077 L 44.809368,54.06077 L 47.459368,49.66077 L 45.709368,49.66077 L 44.049368,52.48077 L 42.379368,49.66077 L 40.619368,49.66077 L 43.239368,54.02077 M 49.119524,54.43077 L 47.599524,54.43077 C 47.592857,54.870772 47.672857,55.250771 47.839524,55.57077 C 48.00619,55.890771 48.229523,56.154104 48.509524,56.36077 C 48.796189,56.567437 49.122855,56.717437 49.489524,56.81077 C 49.862855,56.91077 50.246188,56.96077 50.639524,56.96077 C 51.126187,56.96077 51.552853,56.904103 51.919524,56.79077 C 52.292852,56.677437 52.602852,56.52077 52.849524,56.32077 C 53.102851,56.114104 53.292851,55.870771 53.419524,55.59077 C 53.546184,55.310771 53.609518,55.007438 53.609524,54.68077 C 53.609518,54.280772 53.522851,53.954106 53.349524,53.70077 C 53.182851,53.440773 52.982851,53.234107 52.749524,53.08077 C 52.516185,52.92744 52.279519,52.81744 52.039524,52.75077 C 51.806186,52.677441 51.622853,52.627441 51.489524,52.60077 C 51.042853,52.487441 50.67952,52.394108 50.399524,52.32077 C 50.126188,52.247441 49.909521,52.174108 49.749524,52.10077 C 49.596188,52.027441 49.492855,51.947441 49.439524,51.86077 C 49.386188,51.774108 49.359522,51.660775 49.359524,51.52077 C 49.359522,51.367442 49.392855,51.240775 49.459524,51.14077 C 49.526188,51.040776 49.609522,50.957442 49.709524,50.89077 C 49.816188,50.824109 49.932855,50.777442 50.059524,50.75077 C 50.186188,50.724109 50.312854,50.710776 50.439524,50.71077 C 50.632854,50.710776 50.80952,50.727443 50.969524,50.76077 C 51.136187,50.794109 51.282853,50.850776 51.409524,50.93077 C 51.536186,51.010776 51.636186,51.120775 51.709524,51.26077 C 51.789519,51.400775 51.836186,51.577442 51.849524,51.79077 L 53.369524,51.79077 C 53.369518,51.377442 53.289518,51.027442 53.129524,50.74077 C 52.976185,50.447443 52.766185,50.207443 52.499524,50.02077 C 52.232852,49.83411 51.926186,49.700777 51.579524,49.62077 C 51.23952,49.53411 50.882854,49.490777 50.509524,49.49077 C 50.189521,49.490777 49.869521,49.53411 49.549524,49.62077 C 49.229522,49.707444 48.942856,49.840777 48.689524,50.02077 C 48.436189,50.200776 48.229523,50.427443 48.069524,50.70077 C 47.91619,50.967442 47.839523,51.284109 47.839524,51.65077 C 47.839523,51.977441 47.899523,52.257441 48.019524,52.49077 C 48.14619,52.717441 48.309523,52.90744 48.509524,53.06077 C 48.709522,53.214107 48.936189,53.340773 49.189524,53.44077 C 49.442855,53.534106 49.702855,53.614106 49.969524,53.68077 C 50.229521,53.754106 50.486187,53.820773 50.739524,53.88077 C 50.992853,53.940773 51.21952,54.010773 51.419524,54.09077 C 51.61952,54.170772 51.779519,54.270772 51.899524,54.39077 C 52.026186,54.510772 52.089519,54.667439 52.089524,54.86077 C 52.089519,55.040772 52.042852,55.190771 51.949524,55.31077 C 51.856186,55.424105 51.739519,55.514104 51.599524,55.58077 C 51.45952,55.647438 51.30952,55.694104 51.149524,55.72077 C 50.98952,55.740771 50.83952,55.750771 50.699524,55.75077 C 50.492854,55.750771 50.292854,55.727438 50.099524,55.68077 C 49.906188,55.627438 49.736188,55.550771 49.589524,55.45077 C 49.449522,55.344105 49.336188,55.207438 49.249524,55.04077 C 49.162855,54.874105 49.119522,54.670772 49.119524,54.43077 M 56.113899,50.98077 L 56.113899,56.80077 L 57.683899,56.80077 L 57.683899,50.98077 L 59.823899,50.98077 L 59.823899,49.66077 L 53.973899,49.66077 L 53.973899,50.98077 L 56.113899,50.98077 M 60.666711,49.66077 L 60.666711,56.80077 L 66.086711,56.80077 L 66.086711,55.48077 L 62.236711,55.48077 L 62.236711,53.73077 L 65.696711,53.73077 L 65.696711,52.51077 L 62.236711,52.51077 L 62.236711,50.98077 L 66.006711,50.98077 L 66.006711,49.66077 L 60.666711,49.66077 M 67.131555,49.66077 L 67.131555,56.80077 L 68.601555,56.80077 L 68.601555,51.79077 L 68.621555,51.79077 L 70.371555,56.80077 L 71.581555,56.80077 L 73.331555,51.74077 L 73.351555,51.74077 L 73.351555,56.80077 L 74.821555,56.80077 L 74.821555,49.66077 L 72.611555,49.66077 L 71.031555,54.57077 L 71.011555,54.57077 L 69.341555,49.66077 L 67.131555,49.66077"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Helvetica Neue;-inkscape-font-specification:Helvetica Neue Bold" />
+ </g>
+ </g>
+</svg>
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 000000000..ec7414eb2
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,266 @@
+#
+# "$Id$"
+#
+# Documentation makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2007 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+#
+# Document files...
+#
+
+WEBPAGES = \
+ cups.css \
+ cups-printable.css \
+ index.html \
+ robots.txt
+WEBIMAGES = \
+ images/color-wheel.png \
+ images/cups.png \
+ images/cups-icon.png \
+ images/generic.png \
+ images/left.gif \
+ images/right.gif \
+ images/sel.gif \
+ images/unsel.gif \
+ images/wait.gif
+HELPIMAGES = \
+ images/cups-block-diagram.png \
+ images/cups-command-chain.png \
+ images/cups-postscript-chain.png \
+ images/cups-raster-chain.png \
+ images/raster.png \
+ images/raster-organization.png \
+ images/sample-image.png \
+ images/smiley.jpg
+HELPFILES = \
+ help/accounting.html \
+ help/api-array.html \
+ help/api-cgi.html \
+ help/api-cups.html \
+ help/api-driver.html \
+ help/api-filedir.html \
+ help/api-filter.html \
+ help/api-httpipp.html \
+ help/api-mime.html \
+ help/api-overview.html \
+ help/api-ppd.html \
+ help/api-ppdc.html \
+ help/api-raster.html \
+ help/cgi.html \
+ help/glossary.html \
+ help/kerberos.html \
+ help/license.html \
+ help/man-cupsaccept.html \
+ help/man-backend.html \
+ help/man-cancel.html \
+ help/man-cups-config.html \
+ help/man-cups-lpd.html \
+ help/man-cups-polld.html \
+ help/man-cupsaddsmb.html \
+ help/man-cupsd.html \
+ help/man-cupsenable.html \
+ help/man-cupstestdsc.html \
+ help/man-cupstestppd.html \
+ help/man-filter.html \
+ help/man-ipptool.html \
+ help/man-ipptoolfile.html \
+ help/man-lp.html \
+ help/man-lpadmin.html \
+ help/man-lpc.html \
+ help/man-lpinfo.html \
+ help/man-lpmove.html \
+ help/man-lpoptions.html \
+ help/man-lppasswd.html \
+ help/man-lpq.html \
+ help/man-lpr.html \
+ help/man-lprm.html \
+ help/man-lpstat.html \
+ help/man-mime.convs.html \
+ help/man-mime.types.html \
+ help/man-notifier.html \
+ help/man-ppdc.html \
+ help/man-ppdhtml.html \
+ help/man-ppdi.html \
+ help/man-ppdmerge.html \
+ help/man-ppdpo.html \
+ help/network.html \
+ help/options.html \
+ help/overview.html \
+ help/policies.html \
+ help/postscript-driver.html \
+ help/ppd-compiler.html \
+ help/raster-driver.html \
+ help/ref-access_log.html \
+ help/ref-classes-conf.html \
+ help/ref-client-conf.html \
+ help/ref-cupsd-conf.html \
+ help/ref-error_log.html \
+ help/ref-mailto-conf.html \
+ help/ref-page_log.html \
+ help/ref-ppdcfile.html \
+ help/ref-printers-conf.html \
+ help/ref-snmp-conf.html \
+ help/ref-subscriptions-conf.html \
+ help/security.html \
+ help/sharing.html \
+ help/spec-banner.html \
+ help/spec-browsing.html \
+ help/spec-cmp.html \
+ help/spec-command.html \
+ help/spec-design.html \
+ help/spec-ipp.html \
+ help/spec-pdf.html \
+ help/spec-postscript.html \
+ help/spec-ppd.html \
+ help/spec-raster.html \
+ help/spec-stp.html \
+ help/standard.html \
+ help/translation.html \
+ help/whatsnew.html
+
+
+#
+# Make all documents...
+#
+
+all:
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Remove all generated files...
+#
+
+clean:
+
+
+#
+# Dummy depend target...
+#
+
+depend:
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data: $(INSTALL_LANGUAGES)
+ $(INSTALL_DIR) -m 755 $(DOCDIR)
+ for file in $(WEBPAGES); do \
+ $(INSTALL_MAN) $$file $(DOCDIR); \
+ done
+ $(INSTALL_DIR) -m 755 $(DOCDIR)/help
+ for file in $(HELPFILES); do \
+ $(INSTALL_MAN) $$file $(DOCDIR)/help; \
+ done
+ $(INSTALL_DIR) -m 755 $(DOCDIR)/images
+ for file in $(WEBIMAGES) $(HELPIMAGES); do \
+ $(INSTALL_MAN) $$file $(DOCDIR)/images; \
+ done
+
+install-languages:
+ for lang in $(LANGUAGES); do \
+ if test -d $$lang; then \
+ $(INSTALL_DIR) -m 755 $(DOCDIR)/$$lang; \
+ $(INSTALL_DATA) $$lang/index.html $(DOCDIR)/$$lang; \
+ $(INSTALL_DATA) $$lang/cups.css $(DOCDIR)/$$lang >/dev/null 2>&1 || true; \
+ fi; \
+ done
+
+install-langbundle:
+
+
+#
+# Install programs...
+#
+
+install-exec:
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall all documentation files...
+#
+
+uninstall: $(UNINSTALL_LANGUAGES)
+ for file in $(WEBPAGES); do \
+ $(RM) $(DOCDIR)/$$file; \
+ done
+ for file in $(HELPFILES); do \
+ $(RM) $(DOCDIR)/$$file; \
+ done
+ for file in $(WEBIMAGES); do \
+ $(RM) $(DOCDIR)/$$file; \
+ done
+ -$(RMDIR) $(DOCDIR)/images
+ -$(RMDIR) $(DOCDIR)/help
+ -$(RMDIR) $(DOCDIR)
+
+uninstall-languages:
+ -for lang in $(LANGUAGES); do \
+ $(RM) $(DOCDIR)/$$lang/index.html; \
+ $(RM) $(DOCDIR)/$$lang/cups.css; \
+ $(RMDIR) $(DOCDIR)/$$lang; \
+ done
+
+install-langbundle:
+
+
+#
+# Install the docset bits locally...
+#
+
+docset:
+ cp $(HELPFILES) ../org.cups.docset/Contents/Resources/Documentation/help
+ cp cups-printable.css ../org.cups.docset/Contents/Resources/Documentation
+ cp $(HELPIMAGES) ../org.cups.docset/Contents/Resources/Documentation/images
+
+
+#
+# End of Makefile.
+#
diff --git a/doc/cups-printable.css b/doc/cups-printable.css
new file mode 100644
index 000000000..42ea2bee1
--- /dev/null
+++ b/doc/cups-printable.css
@@ -0,0 +1,329 @@
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
diff --git a/doc/cups.css b/doc/cups.css
new file mode 100644
index 000000000..815c193c3
--- /dev/null
+++ b/doc/cups.css
@@ -0,0 +1,462 @@
+BODY {
+ background: white;
+ color: black;
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ color: #006600;
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ background: #f0f0f0;
+ border: dotted thin #7f7f7f;
+ color: #7f0000;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: white;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+PRE.command EM, PRE.example EM {
+ color: #3f0000;
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ color: #7f0000;
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #f0f0f0;
+ border: inset 1px #eeeeee;
+ padding: 10px;
+ /* These are not implemented by all browsers, but that's OK */
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: inherit;
+ text-decoration: none;
+ color: #000099;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+ color: #990099;
+}
+
+TABLE.page {
+ border: none;
+ border-collapse: collapse;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ width: 100%;
+}
+
+TD.body {
+ height: 100%;
+ vertical-align: top;
+}
+
+TD.sel, TD.unsel {
+ border-left: thin solid #cccccc;
+ padding: 0px 5px;
+ text-align: center;
+ vertical-align: middle;
+ width: 14%;
+}
+
+TD.sel {
+ background: url(images/sel.gif);
+}
+
+TD.unsel {
+ background: url(images/unsel.gif);
+}
+
+TD.sel A, TD.sel A:hover, TD.unsel A:link:hover, TD.unsel A:visited:hover,
+TD.unsel A:active, TD.unsel A, TD.unsel A:visited {
+ color: #666666;
+ display: block;
+ font-weight: normal;
+ padding: 8px;
+ text-decoration: none;
+}
+
+TD.trailer {
+ background: #f0f0f0;
+ border: solid thin #e0e0e0;
+ color: #666666;
+ font-size: 80%;
+ padding: 5px;
+}
+
+TD.trailer A {
+ color: #666699;
+}
+
+FORM {
+ display: inline;
+}
+
+INPUT[TYPE="TEXT"], TEXTAREA {
+ font-family: monaco, courier, monospace;
+}
+
+INPUT[TYPE="IMAGE"] {
+ border: none;
+ padding: 2pt;
+ vertical-align: bottom;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ background: white;
+ border: solid thin #bbbbbb;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #f0f0f0;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+.conflict {
+ background: red;
+ color: white;
+}
+
+TH.conflict {
+ text-align: right;
+}
+
+H1.title {
+ display: none;
+}
+
+H2.title, H3.title {
+ border-bottom: solid 1pt #999999;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DIV.sidebar {
+ float: right;
+ min-width: 25%;
+ margin-left: 10px;
+ max-width: 33%;
+}
+
+DIV.sidebar P.l0 {
+ margin-bottom: 0;
+ margin-left: 0;
+ margin-right: 0;
+ margin-top: 12pt;
+}
+
+DIV.sidebar P.l1 {
+ margin-bottom: 0;
+ margin-left: 36pt;
+ margin-right: 0;
+ margin-top: 0;
+ text-indent: -18pt;
+}
+
+DIV.sidebar P.l2 {
+ font-style: italic;
+ margin-bottom: 0;
+ margin-left: 54pt;
+ margin-right: 0;
+ margin-top: 0;
+ text-indent: -18pt;
+}
+
+TABLE.inset {
+ background: #f0f0f0;
+ border: thin solid #e0e0e0;
+ margin-top: 1em;
+ padding: 0;
+ width: 100%;
+ /* These are not implemented by all browsers, but that's OK */
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+}
+
+TABLE.inset CAPTION {
+ caption-side: top;
+ color: #666666;
+ font-size: 80%;
+ margin-left: 10px;
+ margin-bottom: 2px;
+ text-align: left;
+}
+
+TABLE.inset TD {
+ padding: 2px;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ background: white;
+ border: solid thin #999999;
+ border-spacing: 0;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #f0f0f0;
+}
+
+DIV.tabs {
+ height: 480px;
+ overflow: hidden;
+}
+
+DIV.tab {
+ float: left;
+ height: 100%;
+ overflow-y: auto;
+ width: 100%;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
diff --git a/doc/de/index.html.in b/doc/de/index.html.in
new file mode 100644
index 000000000..a73d77179
--- /dev/null
+++ b/doc/de/index.html.in
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>Home - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="sel"><A HREF="/">&nbsp;&nbsp;Startseite&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/admin">&nbsp;&nbsp;Verwaltung&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/classes/">&nbsp;&nbsp;Klassen&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/help/">&nbsp;&nbsp;Online-&nbsp;Hilfe&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/jobs/">&nbsp;&nbsp;Auftr&auml;ge&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/printers/">&nbsp;&nbsp;Drucker&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Search Help"
+AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD STYLE="padding-right: 20px;">
+
+<H1>Common UNIX Printing System @CUPS_VERSION@</H1>
+
+<P>CUPS ist das auf Standards basierte, Opensource-Drucksystem, welches von
+<A HREF="http://www.apple.com/">Apple Inc.</A> f&uuml;r Mac OS<SUP>&reg;</SUP> X und
+andere UNIX<SUP>&reg;</SUP>-&auml;hnliche Betriebssysteme entwickelt wird.</P>
+
+</TD>
+<TD><A HREF="http://www.cups.org/"><IMG SRC="images/cups-icon.png" WIDTH="128"
+HEIGHT="128" ALT="CUPS"></A></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-right: 20px;">
+
+<H2>CUPS f&uuml;r Benutzer</H2>
+
+<P><A HREF="help/overview.html">CUPS.&Uuml;bersicht</A></P>
+
+<P><A HREF="help/options.html">Kommandozeilendruck und Einstellungen</A></P>
+
+<P><A HREF="help/whatsnew.html">Neues in CUPS 1.4</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.general">Benutzerforum</A></P>
+
+</TD><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-left: 20px; padding-right: 20px;">
+
+<H2>CUPS f&uuml;r Administratoren</H2>
+
+<P><A HREF="admin">Drucker und Klassen hinzuf&uuml;gen</A></P>
+
+<P><A HREF="help/policies.html">Betriebsrichtlinien verwalten</A></P>
+
+<P><A HREF="help/accounting.html">Basiswissen Druckabrechnung</A></P>
+
+<P><A HREF="help/security.html">Sicherheit des Servers</A></P>
+
+<P><A HREF="help/kerberos.html">Verwenden der Kerberos Authentifizierung</A></P>
+
+<P><A HREF="help/network.html">Benutzen von Netzwerkdruckern</A></P>
+
+<P><A HREF="help/ref-cupsd-conf.html">cupsd.conf Referenz</A></P>
+
+<P><A HREF="http://www.cups.org/ppd.php">Druckertreiber finden</A></P>
+
+</TD><TD VALIGN="top" STYLE="padding-left: 20px;">
+
+<H2>CUPS f&uuml;r Entwickler</H2>
+
+<P><A HREF="help/api-overview.html">Einf&uuml;hrung in die CUPS-Programmierung</A></P>
+
+<P><A HREF="help/api-cups.html">CUPS-API</A></P>
+
+<P><A HREF="help/api-filter.html">Filter- und Backend-Programmierung</A></P>
+
+<P><A HREF="help/api-httpipp.html">HTTP- und IPP-APIs</A></P>
+
+<P><A HREF="help/api-ppd.html">PPD-API</A></P>
+
+<P><A HREF="help/api-raster.html">Raster-API</A></P>
+
+<P><A HREF="help/ref-ppdcfile.html">PPD Compiler Driver Information File Reference</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.development">Entwicklerforum</A></P>
+
+</TD></TR>
+</TABLE>
+
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS und das CUPS Logo sind
+eingetragene Warenzeichen der <A HREF="http://www.apple.com">Apple Inc.</A>
+CUPS ist urheberrechtlich gesch&uuml;tzt 2007-2011 von Apple Inc, alle Rechte vorbehalten.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/doc/es/index.html.in b/doc/es/index.html.in
new file mode 100644
index 000000000..5afb0d0c0
--- /dev/null
+++ b/doc/es/index.html.in
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>Inicio - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="sel"><A HREF="/">&nbsp;&nbsp;Inicio&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/admin">&nbsp;&nbsp;Administraci&oacute;n&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/classes/">&nbsp;&nbsp;Clases&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/help/">&nbsp;&nbsp;Ayuda&nbsp;en&nbsp;l&iacute;nea&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/jobs/">&nbsp;&nbsp;Trabajos&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/printers/">&nbsp;&nbsp;Impresoras&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Search Help"
+AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD STYLE="padding-right: 20px;">
+
+<H1>CUPS @CUPS_VERSION@</H1>
+
+<P>CUPS es el sistema de impresi&oacute;n de c&oacute;digo abierto basado en
+est&aacute;ndares desarrollado por <A HREF="http://www.apple.com/">Apple Inc.</A> para Mac
+OS<SUP>&reg;</SUP> X y otros sistemas operativos tipo UNIX<SUP>&reg;</SUP>.</P>
+
+</TD>
+<TD><A HREF="http://www.cups.org/"><IMG SRC="images/cups-icon.png" WIDTH="128"
+HEIGHT="128" ALT="CUPS"></A></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-right: 20px;">
+
+<H2>CUPS para usuarios</H2>
+
+<P><A HREF="help/overview.html">Descripci&oacute;n de CUPS</A></P>
+
+<P><A HREF="help/options.html">Impresi&oacute;n desde la l&iacute;nea de comandos y opciones</A></P>
+
+<P><A HREF="help/whatsnew.html">Qu&eacute; hay de nuevo en CUPS 1.4</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.general">Foro de usuarios</A></P>
+
+</TD><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-left: 20px; padding-right: 20px;">
+
+<H2>CUPS para administradores</H2>
+
+<P><A HREF="admin">A&ntilde;adiendo impresoras y clases</A></P>
+
+<P><A HREF="help/policies.html">Gestionando pol&iacute;ticas de funcionamiento</A></P>
+
+<P><A HREF="help/accounting.html">Contabilidad b&aacute;sica de impresora</A></P>
+
+<P><A HREF="help/security.html">Seguridad del servidor</A></P>
+
+<P><A HREF="help/kerberos.html">Usando autentificaci&oacute;n Kerberos</A></P>
+
+<P><A HREF="help/network.html">Usando impresoras de red</A></P>
+
+<P><A HREF="help/ref-cupsd-conf.html">Referencia de cupsd.conf</A></P>
+
+<P><A HREF="http://www.cups.org/ppd.php">Encontrar controladores de impresora</A></P>
+
+</TD><TD VALIGN="top" STYLE="padding-left: 20px;">
+
+<H2>CUPS para desarrolladores</H2>
+
+<P><A HREF="help/api-overview.html">Introducci&oacute;n a la programación de CUPS</A></P>
+
+<P><A HREF="help/api-cups.html">La API de CUPS</A></P>
+
+<P><A HREF="help/api-filter.html">Programaci&oacute;n de filtros y programas de conexi&oacute;n</A></P>
+
+<P><A HREF="help/api-httpipp.html">Las APIs HTTP e IPP</A></P>
+
+<P><A HREF="help/api-ppd.html">La API PPD</A></P>
+
+<P><A HREF="help/api-raster.html">La API Raster</A></P>
+
+<P><A HREF="help/ref-ppdcfile.html">Referencia del archivo de informaci&oacute;n del compilador de controladores PPD</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.development">Foro de desarrollo</A></P>
+
+</TD></TR>
+</TABLE>
+
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS y el logo de CUPS son
+marcas registradas de <A HREF="http://www.apple.com">Apple Inc.</A> Los derechos
+de copia de CUPS 2007-2011 son de Apple Inc. Todos los derechos reservados.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/doc/eu/index.html.in b/doc/eu/index.html.in
new file mode 100644
index 000000000..5b79b6ae2
--- /dev/null
+++ b/doc/eu/index.html.in
@@ -0,0 +1,106 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>Hasiera - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="sel"><A HREF="/">&nbsp;&nbsp;Hasiera&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/admin">&nbsp;&nbsp;Administrazioa&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/classes/">&nbsp;&nbsp;Klaseak&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/help/">&nbsp;&nbsp;Lineako&nbsp;laguntza&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/jobs/">&nbsp;&nbsp;Lanak&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/printers/">&nbsp;&nbsp;Inprimagailuak&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Bilatu laguntzan"
+AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD STYLE="padding-right: 20px;">
+
+<H1>CUPS @CUPS_VERSION@</H1>
+
+<P><A HREF="http://www.apple.com/">Apple Inc.</A>-ek Mac OS<SUP>&reg;</SUP> X eta
+beste UNIX<SUP>&reg;</SUP> bezalako sistema eragileentzako iturburu irekiko
+inprimatzeko sisteman oinarrituta dago.</P>
+
+</TD>
+<TD><A HREF="http://www.cups.org/"><IMG SRC="images/cups-icon.png" WIDTH="128"
+HEIGHT="128" ALT="CUPS"></A></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-right: 20px;">
+
+<H2>CUPS erabiltzaileentzako</H2>
+
+<P><A HREF="help/overview.html">CUPSen gainbegiraketa</A></P>
+
+<P><A HREF="help/options.html">Komando-lerroaren bidez inprimatzea eta aukerak</A></P>
+
+<P><A HREF="help/whatsnew.html">CUPS 1.4 bertsioak dakartzan berrikuntza.</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.general">Erabiltzaileen foroa</A></P>
+
+</TD><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-left: 20px; padding-right: 20px;">
+
+<H2>CUPS administratzaileentzako</H2>
+
+<P><A HREF="admin">Inprimagailuak eta klaseak gehitzea</A></P>
+
+<P><A HREF="help/policies.html">Kudeaketako eragiketen politikak</A></P>
+
+<P><A HREF="help/accounting.html">Inprimagailuaren oinarrizko kontabilitatea</A></P>
+
+<P><A HREF="help/security.html">Zerbitzariaren segurtasuna</A></P>
+
+<P><A HREF="help/kerberos.html">Kerberos autentifikazioa erabiltzea</A></P>
+
+<P><A HREF="help/network.html">Sareko inprimagailuak erabiltzea</A></P>
+
+<P><A HREF="help/ref-cupsd-conf.html">cupsd.conf erreferentzia</A></P>
+
+<P><A HREF="http://www.cups.org/ppd.php">Bilatu inprimagailuaren kontrolatzaileak</A></P>
+
+</TD><TD VALIGN="top" STYLE="padding-left: 20px;">
+
+<H2>CUPS garatzaileentzako</H2>
+
+<P><A HREF="help/api-overview.html">Sarrera CUPSen programaziora</A></P>
+
+<P><A HREF="help/api-cups.html">CUPSen APIa</A></P>
+
+<P><A HREF="help/api-filter.html">Iragazkien eta atzeko planoan programatzeea</A></P>
+
+<P><A HREF="help/api-httpipp.html">HTTP eta IPP APIak</A></P>
+
+<P><A HREF="help/api-ppd.html">PPD APIa</A></P>
+
+<P><A HREF="help/api-raster.html">Bilbearen APIa</A></P>
+
+<P><A HREF="help/ref-ppdcfile.html">PPD kontrolatzaileen konpilatzailearen informazioaren fitxategiaren erreferentzia</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.development">Garatzaileen forua</A></P>
+
+</TD></TR>
+</TABLE>
+
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS eta CUPSen logotipoa <A HREF="http://www.apple.com">Apple Inc.</A> en marka erregistratuak dira.
+CUPSen copyright-a 2007-2011 Apple Inc. Eskubide guztiak gordeta.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/doc/help/accounting.html b/doc/help/accounting.html
new file mode 100644
index 000000000..66c34ec1f
--- /dev/null
+++ b/doc/help/accounting.html
@@ -0,0 +1,62 @@
+<HTML>
+<!-- SECTION: Getting Started -->
+<HEAD>
+ <TITLE>Printer Accounting Basics</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">Printer Accounting Basics</H1>
+
+<P>CUPS supports a variety of printer accounting schemes. Aside from the
+built-in <A HREF="#QUOTAS">quota</A> and <A HREF="#PAGELOG">page logging</A>
+support, there are several third-party solutions that can be found on
+<A HREF="http://www.cups.org/">www.cups.org</A>.</P>
+
+
+<H2 CLASS="title"><A NAME="QUOTAS">Quota Support</A></H2>
+
+<P>CUPS supports page and size-based quotas for each printer.
+The quotas are tracked individually for each user, but a single set of
+limits applies to all users for a particular printer. For example, you
+can limit every user to 5 pages per day on an expensive printer, but
+you cannot limit every user except Johnny.</P>
+
+<P>The <CODE>job-k-limit</CODE>, <CODE>job-page-limit</CODE>, and <CODE>job-quota-period</CODE>
+options determine whether and how quotas are enforced for a printer.
+The <CODE>job-quota-period</CODE> option determines the time interval for
+quota tracking. The interval is expressed in seconds, so a day is
+86,400, a week is 604,800, and a month is 2,592,000 seconds. The
+<CODE>job-k-limit</CODE> option specifies the job size limit in killobytes. The
+<CODE>job-page-limit</CODE> option specifies the number of pages limit.</P>
+
+<P>For quotas to be enforced, the period and at least one of the limits
+must be set to a non-zero value. The following options will enable
+weekly quotas with the given size and page count limits:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p <I>printer</I> -o job-quota-period=604800 \
+ -o job-k-limit=1024 ENTER</KBD>
+<KBD>/usr/sbin/lpadmin -p <I>printer</I> -o job-quota-period=604800 \
+ -o job-page-limit=100 ENTER</KBD>
+</PRE>
+
+<P>Or, you can combine all three options on the same line.</P>
+
+<P>While there is no way to query the current quota state for a particular
+user, any application can request a list of jobs for a user and printer that
+can be used to easily determine that information.</P>
+
+
+<H2 CLASS="title"><A NAME="PAGELOG">Page Logging</A></H2>
+
+<P>CUPS logs every page that is printed on a system to the
+<VAR><A HREF="ref-page_log.html">page_log</A></VAR> file. Page logging
+is only available for drivers that provide page accounting information,
+typically all PostScript and CUPS raster devices. Raw queues and queues
+using third-party solutions such as Foomatic generally do not have
+useful page accounting information available.</P>
+
+
+</BODY>
+</HTML>
diff --git a/doc/help/api-array.html b/doc/help/api-array.html
new file mode 100644
index 000000000..7f22251b8
--- /dev/null
+++ b/doc/help/api-array.html
@@ -0,0 +1,1062 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>Array API </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: api-array.html 9772 2011-05-12 05:46:30Z mike $"
+
+ Array API header for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Array API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/array.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcups</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#OVERVIEW">Overview</a><ul class="subcontents">
+ <li><a href="#MANAGING_ARRAYS">Managing Arrays</a></li>
+ <li><a href="#FINDING_AND_ENUMERATING">Finding and Enumerating Elements</a></li>
+</ul></li>
+<li><a href="#FUNCTIONS">Functions</a><ul class="code">
+ <li><a href="#cupsArrayAdd" title="Add an element to the array.">cupsArrayAdd</a></li>
+ <li><a href="#cupsArrayClear" title="Clear the array.">cupsArrayClear</a></li>
+ <li><a href="#cupsArrayCount" title="Get the number of elements in the array.">cupsArrayCount</a></li>
+ <li><a href="#cupsArrayCurrent" title="Return the current element in the array.">cupsArrayCurrent</a></li>
+ <li><a href="#cupsArrayDelete" title="Free all memory used by the array.">cupsArrayDelete</a></li>
+ <li><a href="#cupsArrayDup" title="Duplicate the array.">cupsArrayDup</a></li>
+ <li><a href="#cupsArrayFind" title="Find an element in the array.">cupsArrayFind</a></li>
+ <li><a href="#cupsArrayFirst" title="Get the first element in the array.">cupsArrayFirst</a></li>
+ <li><a href="#cupsArrayGetIndex" title="Get the index of the current element.">cupsArrayGetIndex</a></li>
+ <li><a href="#cupsArrayGetInsert" title="Get the index of the last inserted element.">cupsArrayGetInsert</a></li>
+ <li><a href="#cupsArrayIndex" title="Get the N-th element in the array.">cupsArrayIndex</a></li>
+ <li><a href="#cupsArrayInsert" title="Insert an element in the array.">cupsArrayInsert</a></li>
+ <li><a href="#cupsArrayLast" title="Get the last element in the array.">cupsArrayLast</a></li>
+ <li><a href="#cupsArrayNew" title="Create a new array.">cupsArrayNew</a></li>
+ <li><a href="#cupsArrayNew2" title="Create a new array with hash.">cupsArrayNew2</a></li>
+ <li><a href="#cupsArrayNew3" title="Create a new array with hash and/or free function.">cupsArrayNew3</a></li>
+ <li><a href="#cupsArrayNext" title="Get the next element in the array.">cupsArrayNext</a></li>
+ <li><a href="#cupsArrayPrev" title="Get the previous element in the array.">cupsArrayPrev</a></li>
+ <li><a href="#cupsArrayRemove" title="Remove an element from the array.">cupsArrayRemove</a></li>
+ <li><a href="#cupsArrayRestore" title="Reset the current element to the last cupsArraySave.">cupsArrayRestore</a></li>
+ <li><a href="#cupsArraySave" title="Mark the current element for a later cupsArrayRestore.">cupsArraySave</a></li>
+ <li><a href="#cupsArrayUserData" title="Return the user data for an array.">cupsArrayUserData</a></li>
+</ul></li>
+<li><a href="#TYPES">Data Types</a><ul class="code">
+ <li><a href="#cups_acopy_func_t" title="Array element copy function">cups_acopy_func_t</a></li>
+ <li><a href="#cups_afree_func_t" title="Array element free function">cups_afree_func_t</a></li>
+ <li><a href="#cups_ahash_func_t" title="Array hash function">cups_ahash_func_t</a></li>
+ <li><a href="#cups_array_func_t" title="Array comparison function">cups_array_func_t</a></li>
+ <li><a href="#cups_array_t" title="CUPS array type">cups_array_t</a></li>
+</ul></li>
+</ul>
+<!--
+ "$Id: api-array.html 9772 2011-05-12 05:46:30Z mike $"
+
+ Array API introduction for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>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.
+Sorted arrays use a binary search algorithm from the last found or inserted
+element to quickly find matching elements in the array. Arrays created with the
+optional hash function can often find elements with a single lookup. The
+<a href='#cups_array_t'><code>cups_array_t</code></a> type is used when
+referring to a CUPS array.</p>
+
+<p>The CUPS scheduler (<tt>cupsd</tt>) and many of the CUPS API
+functions use the array API to efficiently manage large lists of
+data.</p>
+
+<h3><a name='MANAGING_ARRAYS'>Managing Arrays</a></h3>
+
+<p>Arrays are created using either the
+<a href='#cupsArrayNew'><code>cupsArrayNew</code></a>,
+<a href='#cupsArrayNew2'><code>cupsArrayNew2</code></a>, or
+<a href='#cupsArrayNew2'><code>cupsArrayNew3</code></a> functions. The
+first function creates a new array with the specified callback function
+and user data pointer:</p>
+
+<pre class='example'>
+#include &lt;cups/array.h&gt;
+
+static int compare_func(void *first, void *second, void *user_data);
+
+void *user_data;
+<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>(compare_func, user_data);
+</pre>
+
+<p>The comparison function (type
+<a href="#cups_arrayfunc_t"><code>cups_arrayfunc_t</code></a>) is called
+whenever an element is added to the array and can be <code>NULL</code> to
+create an unsorted array. The function returns -1 if the first element should
+come before the second, 0 if the first and second elements should have the same
+ordering, and 1 if the first element should come after the second.</p>
+
+<p>The "user_data" pointer is passed to your comparison function. Pass
+<code>NULL</code> if you do not need to associate the elements in your array
+with additional information.</p>
+
+<p>The <a href='#cupsArrayNew2'><code>cupsArrayNew2</code></a> function adds
+two more arguments to support hashed lookups, which can potentially provide
+instantaneous ("O(1)") lookups in your array:</p>
+
+<pre class='example'>
+#include &lt;cups/array.h&gt;
+
+#define HASH_SIZE 512 /* Size of hash table */
+
+static int compare_func(void *first, void *second, void *user_data);
+static int hash_func(void *element, void *user_data);
+
+void *user_data;
+<a href='#cups_array_t'>cups_array_t</a> *hash_array = <a href='#cupsArrayNew2'>cupsArrayNew2</a>(compare_func, user_data, hash_func, HASH_SIZE);
+</pre>
+
+<p>The hash function (type
+<a href="#cups_ahash_func_t"><code>cups_ahash_func_t</code></a>) should return a
+number from 0 to (hash_size-1) that (hopefully) uniquely identifies the
+element and is called whenever you look up an element in the array with
+<a href='#cupsArrayFind'><code>cupsArrayFind</code></a>. The hash size is
+only limited by available memory, but generally should not be larger than
+16384 to realize any performance improvement.</p>
+
+<p>The <a href='#cupsArrayNew3'><code>cupsArrayNew3</code></a> function adds
+copy and free callbacks to support basic memory management of elements:</p>
+
+<pre class='example'>
+#include &lt;cups/array.h&gt;
+
+#define HASH_SIZE 512 /* Size of hash table */
+
+static int compare_func(void *first, void *second, void *user_data);
+static void *copy_func(void *element, void *user_data);
+static void free_func(void *element, void *user_data);
+static int hash_func(void *element, void *user_data);
+
+void *user_data;
+<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew3'>cupsArrayNew3</a>(compare_func, user_data, NULL, 0, copy_func, free_func);
+
+<a href='#cups_array_t'>cups_array_t</a> *hash_array = <a href='#cupsArrayNew3'>cupsArrayNew3</a>(compare_func, user_data, hash_func, HASH_SIZE, copy_func, free_func);
+</pre>
+
+<p>Once you have created the array, you add elements using the
+<a href='#cupsArrayAdd'><code>cupsArrayAdd</code></a>
+<a href='#cupsArrayInsert'><code>cupsArrayInsert</code></a> functions.
+The first function adds an element to the array, adding the new element
+after any elements that have the same order, while the second inserts the
+element before others with the same order. For unsorted arrays,
+<a href='#cupsArrayAdd'><code>cupsArrayAdd</code></a> appends the element to
+the end of the array while
+<a href='#cupsArrayInsert'><code>cupsArrayInsert</code></a> inserts the
+element at the beginning of the array. For example, the following code
+creates a sorted array of character strings:</p>
+
+<pre class='example'>
+#include &lt;cups/array.h&gt;
+
+/* Use strcmp() to compare strings - it will ignore the user_data pointer */
+<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>((<a href='#cups_array_func_t'>cups_array_func_t</a>)strcmp, NULL);
+
+/* Add four strings to the array */
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "One Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Two Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Red Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Blue Fish");
+</pre>
+
+<p>Elements are removed using the
+<a href='#cupsArrayRemove'><code>cupsArrayRemove</code></a> function, for
+example:</p>
+
+<pre class='example'>
+#include &lt;cups/array.h&gt;
+
+/* Use strcmp() to compare strings - it will ignore the user_data pointer */
+<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>((<a href='#cups_array_func_t'>cups_array_func_t</a>)strcmp, NULL);
+
+/* Add four strings to the array */
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "One Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Two Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Red Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Blue Fish");
+
+/* Remove "Red Fish" */
+<a href='#cupsArrayRemove'>cupsArrayRemove</a>(array, "Red Fish");
+</pre>
+
+<p>Finally, you free the memory used by the array using the
+<a href='#cupsArrayDelete'><code>cupsArrayDelete</code></a> function. All
+of the memory for the array and hash table (if any) is freed, however <em>CUPS
+does not free the elements unless you provide copy and free functions</em>.</p>
+
+<h3><a name='FINDING_AND_ENUMERATING'>Finding and Enumerating Elements</a></h3>
+
+<p>CUPS provides several functions to find and enumerate elements in an
+array. Each one sets or updates a "current index" into the array, such that
+future lookups will start where the last one left off:</p>
+
+<dl>
+ <dt><a href='#cupsArrayFind'><code>cupsArrayFind</code></a></dt>
+ <dd>Returns the first matching element.</dd>
+ <dt><a href='#cupsArrayFirst'><code>cupsArrayFirst</code></a></dt>
+ <dd>Returns the first element in the array.</dd>
+ <dt><a href='#cupsArrayIndex'><code>cupsArrayIndex</code></a></dt>
+ <dd>Returns the Nth element in the array, starting at 0.</dd>
+ <dt><a href='#cupsArrayLast'><code>cupsArrayLast</code></a></dt>
+ <dd>Returns the last element in the array.</dd>
+ <dt><a href='#cupsArrayNext'><code>cupsArrayNext</code></a></dt>
+ <dd>Returns the next element in the array.</dd>
+ <dt><a href='#cupsArrayPrev'><code>cupsArrayPrev</code></a></dt>
+ <dd>Returns the previous element in the array.</dd>
+</dl>
+
+<p>Each of these functions returns <code>NULL</code> when there is no
+corresponding element. For example, a simple <code>for</code> loop using the
+<a href='#cupsArrayFirst'><code>cupsArrayFirst</code></a> and
+<a href='#cupsArrayNext'><code>cupsArrayNext</code></a> functions will
+enumerate all of the strings in our previous example:</p>
+
+<pre class='example'>
+#include &lt;cups/array.h&gt;
+
+/* Use strcmp() to compare strings - it will ignore the user_data pointer */
+<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>((<a href='#cups_array_func_t'>cups_array_func_t</a>)strcmp, NULL);
+
+/* Add four strings to the array */
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "One Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Two Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Red Fish");
+<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Blue Fish");
+
+/* Show all of the strings in the array */
+char *s;
+for (s = (char *)<a href='#cupsArrayFirst'>cupsArrayFirst</a>(array); s != NULL; s = (char *)<a href='#cupsArrayNext'>cupsArrayNext</a>(array))
+ puts(s);
+</pre>
+<h2 class="title"><a name="FUNCTIONS">Functions</a></h2>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayAdd">cupsArrayAdd</a></h3>
+<p class="description">Add an element to the array.</p>
+<p class="code">
+int cupsArrayAdd (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *e<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+<dt>e</dt>
+<dd class="description">Element</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 on success, 0 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">When adding an element to a sorted array, non-unique elements are
+appended at the end of the run of identical elements. For unsorted arrays,
+the element is appended to the end of the array.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayClear">cupsArrayClear</a></h3>
+<p class="description">Clear the array.</p>
+<p class="code">
+void cupsArrayClear (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is equivalent to removing all elements in the array.
+The caller is responsible for freeing the memory used by the
+elements themselves.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayCount">cupsArrayCount</a></h3>
+<p class="description">Get the number of elements in the array.</p>
+<p class="code">
+int cupsArrayCount (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of elements</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayCurrent">cupsArrayCurrent</a></h3>
+<p class="description">Return the current element in the array.</p>
+<p class="code">
+void *cupsArrayCurrent (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Element</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The current element is undefined until you call <a href="#cupsArrayFind"><code>cupsArrayFind</code></a>,
+<a href="#cupsArrayFirst"><code>cupsArrayFirst</code></a>, or <a href="#cupsArrayIndex"><code>cupsArrayIndex</code></a>, or <a href="#cupsArrayLast"><code>cupsArrayLast</code></a>.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayDelete">cupsArrayDelete</a></h3>
+<p class="description">Free all memory used by the array.</p>
+<p class="code">
+void cupsArrayDelete (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The caller is responsible for freeing the memory used by the
+elements themselves.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayDup">cupsArrayDup</a></h3>
+<p class="description">Duplicate the array.</p>
+<p class="code">
+<a href="#cups_array_t">cups_array_t</a> *cupsArrayDup (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Duplicate array</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayFind">cupsArrayFind</a></h3>
+<p class="description">Find an element in the array.</p>
+<p class="code">
+void *cupsArrayFind (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *e<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+<dt>e</dt>
+<dd class="description">Element</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Element found or <code>NULL</code></p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayFirst">cupsArrayFirst</a></h3>
+<p class="description">Get the first element in the array.</p>
+<p class="code">
+void *cupsArrayFirst (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">First element or <code>NULL</code> if the array is empty</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="cupsArrayGetIndex">cupsArrayGetIndex</a></h3>
+<p class="description">Get the index of the current element.</p>
+<p class="code">
+int cupsArrayGetIndex (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Index of the current element, starting at 0</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The current element is undefined until you call <a href="#cupsArrayFind"><code>cupsArrayFind</code></a>,
+<a href="#cupsArrayFirst"><code>cupsArrayFirst</code></a>, or <a href="#cupsArrayIndex"><code>cupsArrayIndex</code></a>, or <a href="#cupsArrayLast"><code>cupsArrayLast</code></a>.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="cupsArrayGetInsert">cupsArrayGetInsert</a></h3>
+<p class="description">Get the index of the last inserted element.</p>
+<p class="code">
+int cupsArrayGetInsert (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Index of the last inserted element, starting at 0</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayIndex">cupsArrayIndex</a></h3>
+<p class="description">Get the N-th element in the array.</p>
+<p class="code">
+void *cupsArrayIndex (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int n<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+<dt>n</dt>
+<dd class="description">Index into array, starting at 0</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">N-th element or <code>NULL</code></p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayInsert">cupsArrayInsert</a></h3>
+<p class="description">Insert an element in the array.</p>
+<p class="code">
+int cupsArrayInsert (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *e<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+<dt>e</dt>
+<dd class="description">Element</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on failure, 1 on success</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">When inserting an element in a sorted array, non-unique elements are
+inserted at the beginning of the run of identical elements. For unsorted
+arrays, the element is inserted at the beginning of the array.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayLast">cupsArrayLast</a></h3>
+<p class="description">Get the last element in the array.</p>
+<p class="code">
+void *cupsArrayLast (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Last element or <code>NULL</code> if the array is empty</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayNew">cupsArrayNew</a></h3>
+<p class="description">Create a new array.</p>
+<p class="code">
+<a href="#cups_array_t">cups_array_t</a> *cupsArrayNew (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_func_t">cups_array_func_t</a> f,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *d<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>f</dt>
+<dd class="description">Comparison function or <code>NULL</code> for an unsorted array</dd>
+<dt>d</dt>
+<dd class="description">User data pointer or <code>NULL</code></dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Array</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The comparison function (&quot;f&quot;) is used to create a sorted array. The function
+receives pointers to two elements and the user data pointer (&quot;d&quot;) - the user
+data pointer argument can safely be omitted when not required so functions
+like <code>strcmp</code> can be used for sorted string arrays.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="cupsArrayNew2">cupsArrayNew2</a></h3>
+<p class="description">Create a new array with hash.</p>
+<p class="code">
+<a href="#cups_array_t">cups_array_t</a> *cupsArrayNew2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_func_t">cups_array_func_t</a> f,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *d,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_ahash_func_t">cups_ahash_func_t</a> h,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int hsize<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>f</dt>
+<dd class="description">Comparison function or <code>NULL</code> for an unsorted array</dd>
+<dt>d</dt>
+<dd class="description">User data or <code>NULL</code></dd>
+<dt>h</dt>
+<dd class="description">Hash function or <code>NULL</code> for unhashed lookups</dd>
+<dt>hsize</dt>
+<dd class="description">Hash size (&gt;= 0)</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Array</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The comparison function (&quot;f&quot;) is used to create a sorted array. The function
+receives pointers to two elements and the user data pointer (&quot;d&quot;) - the user
+data pointer argument can safely be omitted when not required so functions
+like <code>strcmp</code> can be used for sorted string arrays.<br>
+<br>
+The hash function (&quot;h&quot;) is used to implement cached lookups with the
+specified hash size (&quot;hsize&quot;).
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span><a name="cupsArrayNew3">cupsArrayNew3</a></h3>
+<p class="description">Create a new array with hash and/or free function.</p>
+<p class="code">
+<a href="#cups_array_t">cups_array_t</a> *cupsArrayNew3 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_func_t">cups_array_func_t</a> f,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *d,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_ahash_func_t">cups_ahash_func_t</a> h,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int hsize,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_acopy_func_t">cups_acopy_func_t</a> cf,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_afree_func_t">cups_afree_func_t</a> ff<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>f</dt>
+<dd class="description">Comparison function or <code>NULL</code> for an unsorted array</dd>
+<dt>d</dt>
+<dd class="description">User data or <code>NULL</code></dd>
+<dt>h</dt>
+<dd class="description">Hash function or <code>NULL</code> for unhashed lookups</dd>
+<dt>hsize</dt>
+<dd class="description">Hash size (&gt;= 0)</dd>
+<dt>cf</dt>
+<dd class="description">Copy function</dd>
+<dt>ff</dt>
+<dd class="description">Free function</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Array</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The comparison function (&quot;f&quot;) is used to create a sorted array. The function
+receives pointers to two elements and the user data pointer (&quot;d&quot;) - the user
+data pointer argument can safely be omitted when not required so functions
+like <code>strcmp</code> can be used for sorted string arrays.<br>
+<br>
+The hash function (&quot;h&quot;) is used to implement cached lookups with the
+specified hash size (&quot;hsize&quot;).<br>
+<br>
+The copy function (&quot;cf&quot;) is used to automatically copy/retain elements when
+added or the array is copied.<br>
+<br>
+The free function (&quot;cf&quot;) is used to automatically free/release elements when
+removed or the array is deleted.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayNext">cupsArrayNext</a></h3>
+<p class="description">Get the next element in the array.</p>
+<p class="code">
+void *cupsArrayNext (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Next element or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is equivalent to &quot;cupsArrayIndex(a, cupsArrayGetIndex(a) + 1)&quot;.<br>
+<br>
+The next element is undefined until you call <a href="#cupsArrayFind"><code>cupsArrayFind</code></a>,
+<a href="#cupsArrayFirst"><code>cupsArrayFirst</code></a>, or <a href="#cupsArrayIndex"><code>cupsArrayIndex</code></a>, or <a href="#cupsArrayLast"><code>cupsArrayLast</code></a>
+to set the current element.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayPrev">cupsArrayPrev</a></h3>
+<p class="description">Get the previous element in the array.</p>
+<p class="code">
+void *cupsArrayPrev (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Previous element or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is equivalent to &quot;cupsArrayIndex(a, cupsArrayGetIndex(a) - 1)&quot;.<br>
+<br>
+The previous element is undefined until you call <a href="#cupsArrayFind"><code>cupsArrayFind</code></a>,
+<a href="#cupsArrayFirst"><code>cupsArrayFirst</code></a>, or <a href="#cupsArrayIndex"><code>cupsArrayIndex</code></a>, or <a href="#cupsArrayLast"><code>cupsArrayLast</code></a>
+to set the current element.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayRemove">cupsArrayRemove</a></h3>
+<p class="description">Remove an element from the array.</p>
+<p class="code">
+int cupsArrayRemove (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *e<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+<dt>e</dt>
+<dd class="description">Element</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 on success, 0 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">If more than one element matches &quot;e&quot;, only the first matching element is
+removed.<br>
+<br>
+The caller is responsible for freeing the memory used by the
+removed element.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayRestore">cupsArrayRestore</a></h3>
+<p class="description">Reset the current element to the last <a href="#cupsArraySave"><code>cupsArraySave</code></a>.</p>
+<p class="code">
+void *cupsArrayRestore (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New current element</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArraySave">cupsArraySave</a></h3>
+<p class="description">Mark the current element for a later <a href="#cupsArrayRestore"><code>cupsArrayRestore</code></a>.</p>
+<p class="code">
+int cupsArraySave (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 on success, 0 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The current element is undefined until you call <a href="#cupsArrayFind"><code>cupsArrayFind</code></a>,
+<a href="#cupsArrayFirst"><code>cupsArrayFirst</code></a>, or <a href="#cupsArrayIndex"><code>cupsArrayIndex</code></a>, or <a href="#cupsArrayLast"><code>cupsArrayLast</code></a>
+to set the current element.<br>
+<br>
+The save/restore stack is guaranteed to be at least 32 elements deep.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayUserData">cupsArrayUserData</a></h3>
+<p class="description">Return the user data for an array.</p>
+<p class="code">
+void *cupsArrayUserData (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_t">cups_array_t</a> *a<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>a</dt>
+<dd class="description">Array</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">User data</p>
+<h2 class="title"><a name="TYPES">Data Types</a></h2>
+<h3 class="typedef"><a name="cups_acopy_func_t">cups_acopy_func_t</a></h3>
+<p class="description">Array element copy function</p>
+<p class="code">
+typedef void *(*cups_acopy_func_t)(void *element, void *data);
+</p>
+<h3 class="typedef"><a name="cups_afree_func_t">cups_afree_func_t</a></h3>
+<p class="description">Array element free function</p>
+<p class="code">
+typedef void (*cups_afree_func_t)(void *element, void *data);
+</p>
+<h3 class="typedef"><a name="cups_ahash_func_t">cups_ahash_func_t</a></h3>
+<p class="description">Array hash function</p>
+<p class="code">
+typedef int (*cups_ahash_func_t)(void *element, void *data);
+</p>
+<h3 class="typedef"><a name="cups_array_func_t">cups_array_func_t</a></h3>
+<p class="description">Array comparison function</p>
+<p class="code">
+typedef int (*cups_array_func_t)(void *first, void *second, void *data);
+</p>
+<h3 class="typedef"><a name="cups_array_t">cups_array_t</a></h3>
+<p class="description">CUPS array type</p>
+<p class="code">
+typedef struct _cups_array_s cups_array_t;
+</p>
+</div>
+</body>
+</html>
diff --git a/doc/help/api-cgi.html b/doc/help/api-cgi.html
new file mode 100644
index 000000000..5c07e58a3
--- /dev/null
+++ b/doc/help/api-cgi.html
@@ -0,0 +1,1126 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>CGI API </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: api-cgi.html 9740 2011-05-04 06:26:22Z mike $"
+
+ CGI API header for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>CGI API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/cgi.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcupscgi</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#OVERVIEW">Overview</a></li>
+<li><a href="#FUNCTIONS">Functions</a><ul class="code">
+ <li><a href="#cgiCheckVariables" title="Check for the presence of &quot;required&quot; variables.">cgiCheckVariables</a></li>
+ <li><a href="#cgiClearVariables" title="Clear all form variables.">cgiClearVariables</a></li>
+ <li><a href="#cgiCompileSearch" title="Compile a search string.">cgiCompileSearch</a></li>
+ <li><a href="#cgiCopyTemplateFile" title="Copy a template file and replace all the
+'{variable}' strings with the variable value.">cgiCopyTemplateFile</a></li>
+ <li><a href="#cgiCopyTemplateLang" title="Copy a template file using a language...">cgiCopyTemplateLang</a></li>
+ <li><a href="#cgiDoSearch" title="Do a search of some text.">cgiDoSearch</a></li>
+ <li><a href="#cgiEndHTML" title="End a HTML page.">cgiEndHTML</a></li>
+ <li><a href="#cgiEndMultipart" title="End the delivery of a multipart web page.">cgiEndMultipart</a></li>
+ <li><a href="#cgiFormEncode" title="Encode a string as a form variable.">cgiFormEncode</a></li>
+ <li><a href="#cgiFreeSearch" title="Free a compiled search context.">cgiFreeSearch</a></li>
+ <li><a href="#cgiGetArray" title="Get an element from a form array.">cgiGetArray</a></li>
+ <li><a href="#cgiGetAttributes" title="Get the list of attributes that are needed
+by the template file.">cgiGetAttributes</a></li>
+ <li><a href="#cgiGetCookie" title="Get a cookie value.">cgiGetCookie</a></li>
+ <li><a href="#cgiGetFile" title="Get the file (if any) that was submitted in the form.">cgiGetFile</a></li>
+ <li><a href="#cgiGetIPPObjects" title="Get the objects in an IPP response.">cgiGetIPPObjects</a></li>
+ <li><a href="#cgiGetSize" title="Get the size of a form array value.">cgiGetSize</a></li>
+ <li><a href="#cgiGetTemplateDir" title="Get the templates directory...">cgiGetTemplateDir</a></li>
+ <li><a href="#cgiGetVariable" title="Get a CGI variable from the database.">cgiGetVariable</a></li>
+ <li><a href="#cgiInitialize" title="Initialize the CGI variable &quot;database&quot;.">cgiInitialize</a></li>
+ <li><a href="#cgiIsPOST" title="Determine whether this page was POSTed.">cgiIsPOST</a></li>
+ <li><a href="#cgiMoveJobs" title="Move one or more jobs.">cgiMoveJobs</a></li>
+ <li><a href="#cgiPrintCommand" title="Print a CUPS command job.">cgiPrintCommand</a></li>
+ <li><a href="#cgiPrintTestPage" title="Print a test page.">cgiPrintTestPage</a></li>
+ <li><a href="#cgiRewriteURL" title="Rewrite a printer URI into a web browser URL...">cgiRewriteURL</a></li>
+ <li><a href="#cgiSetArray" title="Set array element N to the specified string.">cgiSetArray</a></li>
+ <li><a href="#cgiSetCookie" title="Set a cookie value.">cgiSetCookie</a></li>
+ <li><a href="#cgiSetIPPObjectVars" title="Set CGI variables from an IPP object.">cgiSetIPPObjectVars</a></li>
+ <li><a href="#cgiSetIPPVars" title="Set CGI variables from an IPP response.">cgiSetIPPVars</a></li>
+ <li><a href="#cgiSetServerVersion" title="Set the server name and CUPS version...">cgiSetServerVersion</a></li>
+ <li><a href="#cgiSetSize" title="Set the array size.">cgiSetSize</a></li>
+ <li><a href="#cgiSetVariable" title="Set a CGI variable in the database.">cgiSetVariable</a></li>
+ <li><a href="#cgiShowIPPError" title="Show the last IPP error message.">cgiShowIPPError</a></li>
+ <li><a href="#cgiShowJobs" title="Show print jobs.">cgiShowJobs</a></li>
+ <li><a href="#cgiStartHTML" title="Start a HTML page.">cgiStartHTML</a></li>
+ <li><a href="#cgiStartMultipart" title="Start a multipart delivery of a web page.">cgiStartMultipart</a></li>
+ <li><a href="#cgiSupportsMultipart" title="Does the browser support multi-part documents?">cgiSupportsMultipart</a></li>
+ <li><a href="#cgiText" title="Return localized text.">cgiText</a></li>
+ <li><a href="#helpDeleteIndex" title="Delete an index, freeing all memory used.">helpDeleteIndex</a></li>
+ <li><a href="#helpFindNode" title="Find a node in an index.">helpFindNode</a></li>
+ <li><a href="#helpLoadIndex" title="Load a help index from disk.">helpLoadIndex</a></li>
+ <li><a href="#helpSaveIndex" title="Save a help index to disk.">helpSaveIndex</a></li>
+ <li><a href="#helpSearchIndex" title="Search an index.">helpSearchIndex</a></li>
+</ul></li>
+<li><a href="#TYPES">Data Types</a><ul class="code">
+ <li><a href="#cgi_file_t" title="Uploaded file data">cgi_file_t</a></li>
+ <li><a href="#help_index_t" title="Help index structure">help_index_t</a></li>
+ <li><a href="#help_node_t" title="Help node structure...">help_node_t</a></li>
+ <li><a href="#help_word_t" title="Help word structure...">help_word_t</a></li>
+</ul></li>
+<li><a href="#STRUCTURES">Structures</a><ul class="code">
+ <li><a href="#cgi_file_s" title="Uploaded file data">cgi_file_s</a></li>
+ <li><a href="#help_index_s" title="Help index structure">help_index_s</a></li>
+ <li><a href="#help_node_s" title="Help node structure...">help_node_s</a></li>
+ <li><a href="#help_word_s" title="Help word structure...">help_word_s</a></li>
+</ul></li>
+</ul>
+<!--
+ "$Id: api-cgi.html 9740 2011-05-04 06:26:22Z mike $"
+
+ CGI API introduction for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>The CGI API provides Common Gateway Interface functions for CUPS.</p>
+<h2 class="title"><a name="FUNCTIONS">Functions</a></h2>
+<h3 class="function"><a name="cgiCheckVariables">cgiCheckVariables</a></h3>
+<p class="description">Check for the presence of &quot;required&quot; variables.</p>
+<p class="code">
+int cgiCheckVariables (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *names<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>names</dt>
+<dd class="description">Variables to look for</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if all variables present, 0 otherwise</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Names may be separated by spaces and/or commas.</p>
+<h3 class="function"><a name="cgiClearVariables">cgiClearVariables</a></h3>
+<p class="description">Clear all form variables.</p>
+<p class="code">
+void cgiClearVariables (void);</p>
+<h3 class="function"><a name="cgiCompileSearch">cgiCompileSearch</a></h3>
+<p class="description">Compile a search string.</p>
+<p class="code">
+void *cgiCompileSearch (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *query<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>query</dt>
+<dd class="description">Query string</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Search context</p>
+<h3 class="function"><a name="cgiCopyTemplateFile">cgiCopyTemplateFile</a></h3>
+<p class="description">Copy a template file and replace all the
+'{variable}' strings with the variable value.</p>
+<p class="code">
+void cgiCopyTemplateFile (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;FILE *out,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *tmpl<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>out</dt>
+<dd class="description">Output file</dd>
+<dt>tmpl</dt>
+<dd class="description">Template file to read</dd>
+</dl>
+<h3 class="function"><a name="cgiCopyTemplateLang">cgiCopyTemplateLang</a></h3>
+<p class="description">Copy a template file using a language...</p>
+<p class="code">
+void cgiCopyTemplateLang (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *tmpl<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>tmpl</dt>
+<dd class="description">Base filename</dd>
+</dl>
+<h3 class="function"><a name="cgiDoSearch">cgiDoSearch</a></h3>
+<p class="description">Do a search of some text.</p>
+<p class="code">
+int cgiDoSearch (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *search,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *text<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>search</dt>
+<dd class="description">Search context</dd>
+<dt>text</dt>
+<dd class="description">Text to search</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of matches</p>
+<h3 class="function"><a name="cgiEndHTML">cgiEndHTML</a></h3>
+<p class="description">End a HTML page.</p>
+<p class="code">
+void cgiEndHTML (void);</p>
+<h3 class="function"><a name="cgiEndMultipart">cgiEndMultipart</a></h3>
+<p class="description">End the delivery of a multipart web page.</p>
+<p class="code">
+void cgiEndMultipart (void);</p>
+<h3 class="function"><a name="cgiFormEncode">cgiFormEncode</a></h3>
+<p class="description">Encode a string as a form variable.</p>
+<p class="code">
+char *cgiFormEncode (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *dst,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *src,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t dstsize<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>dst</dt>
+<dd class="description">Destination string</dd>
+<dt>src</dt>
+<dd class="description">Source string</dd>
+<dt>dstsize</dt>
+<dd class="description">Size of destination string</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Destination string</p>
+<h3 class="function"><a name="cgiFreeSearch">cgiFreeSearch</a></h3>
+<p class="description">Free a compiled search context.</p>
+<p class="code">
+void cgiFreeSearch (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *search<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>search</dt>
+<dd class="description">Search context</dd>
+</dl>
+<h3 class="function"><a name="cgiGetArray">cgiGetArray</a></h3>
+<p class="description">Get an element from a form array.</p>
+<p class="code">
+const char *cgiGetArray (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int element<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Name of array variable</dd>
+<dt>element</dt>
+<dd class="description">Element number (0 to N)</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Element value or NULL</p>
+<h3 class="function"><a name="cgiGetAttributes">cgiGetAttributes</a></h3>
+<p class="description">Get the list of attributes that are needed
+by the template file.</p>
+<p class="code">
+void cgiGetAttributes (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;ipp_t *request,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *tmpl<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>request</dt>
+<dd class="description">IPP request</dd>
+<dt>tmpl</dt>
+<dd class="description">Base filename</dd>
+</dl>
+<h3 class="function"><a name="cgiGetCookie">cgiGetCookie</a></h3>
+<p class="description">Get a cookie value.</p>
+<p class="code">
+const char *cgiGetCookie (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Name of cookie</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Value or NULL</p>
+<h3 class="function"><a name="cgiGetFile">cgiGetFile</a></h3>
+<p class="description">Get the file (if any) that was submitted in the form.</p>
+<p class="code">
+const <a href="#cgi_file_t">cgi_file_t</a> *cgiGetFile (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Attached file or NULL</p>
+<h3 class="function"><a name="cgiGetIPPObjects">cgiGetIPPObjects</a></h3>
+<p class="description">Get the objects in an IPP response.</p>
+<p class="code">
+cups_array_t *cgiGetIPPObjects (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;ipp_t *response,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *search<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>response</dt>
+<dd class="description">IPP response</dd>
+<dt>search</dt>
+<dd class="description">Search filter</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Array of objects</p>
+<h3 class="function"><a name="cgiGetSize">cgiGetSize</a></h3>
+<p class="description">Get the size of a form array value.</p>
+<p class="code">
+int cgiGetSize (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Name of variable</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of elements</p>
+<h3 class="function"><a name="cgiGetTemplateDir">cgiGetTemplateDir</a></h3>
+<p class="description">Get the templates directory...</p>
+<p class="code">
+char *cgiGetTemplateDir (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Template directory</p>
+<h3 class="function"><a name="cgiGetVariable">cgiGetVariable</a></h3>
+<p class="description">Get a CGI variable from the database.</p>
+<p class="code">
+const char *cgiGetVariable (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Name of variable</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Value of variable</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Returns NULL if the variable doesn't exist. If the variable is an
+array of values, returns the last element.</p>
+<h3 class="function"><a name="cgiInitialize">cgiInitialize</a></h3>
+<p class="description">Initialize the CGI variable &quot;database&quot;.</p>
+<p class="code">
+int cgiInitialize (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Non-zero if there was form data</p>
+<h3 class="function"><a name="cgiIsPOST">cgiIsPOST</a></h3>
+<p class="description">Determine whether this page was POSTed.</p>
+<p class="code">
+int cgiIsPOST (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if POST, 0 if GET</p>
+<h3 class="function"><a name="cgiMoveJobs">cgiMoveJobs</a></h3>
+<p class="description">Move one or more jobs.</p>
+<p class="code">
+void cgiMoveJobs (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *dest,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int job_id<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>dest</dt>
+<dd class="description">Destination or NULL</dd>
+<dt>job_id</dt>
+<dd class="description">Job ID or 0 for all</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">At least one of dest or job_id must be non-zero/NULL.</p>
+<h3 class="function"><a name="cgiPrintCommand">cgiPrintCommand</a></h3>
+<p class="description">Print a CUPS command job.</p>
+<p class="code">
+void cgiPrintCommand (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *dest,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *command,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *title<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>dest</dt>
+<dd class="description">Destination printer</dd>
+<dt>command</dt>
+<dd class="description">Command to send</dd>
+<dt>title</dt>
+<dd class="description">Page/job title</dd>
+</dl>
+<h3 class="function"><a name="cgiPrintTestPage">cgiPrintTestPage</a></h3>
+<p class="description">Print a test page.</p>
+<p class="code">
+void cgiPrintTestPage (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *dest<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>dest</dt>
+<dd class="description">Destination printer/class</dd>
+</dl>
+<h3 class="function"><a name="cgiRewriteURL">cgiRewriteURL</a></h3>
+<p class="description">Rewrite a printer URI into a web browser URL...</p>
+<p class="code">
+char *cgiRewriteURL (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *uri,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *url,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int urlsize,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *newresource<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>uri</dt>
+<dd class="description">Current URI</dd>
+<dt>url</dt>
+<dd class="description">New URL</dd>
+<dt>urlsize</dt>
+<dd class="description">Size of URL buffer</dd>
+<dt>newresource</dt>
+<dd class="description">Replacement resource</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New URL</p>
+<h3 class="function"><a name="cgiSetArray">cgiSetArray</a></h3>
+<p class="description">Set array element N to the specified string.</p>
+<p class="code">
+void cgiSetArray (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int element,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *value<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Name of variable</dd>
+<dt>element</dt>
+<dd class="description">Element number (0 to N)</dd>
+<dt>value</dt>
+<dd class="description">Value of variable</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">If the variable array is smaller than (element + 1), the intervening
+elements are set to NULL.</p>
+<h3 class="function"><a name="cgiSetCookie">cgiSetCookie</a></h3>
+<p class="description">Set a cookie value.</p>
+<p class="code">
+void cgiSetCookie (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *value,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *path,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *domain,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;time_t expires,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int secure<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Name</dd>
+<dt>value</dt>
+<dd class="description">Value</dd>
+<dt>path</dt>
+<dd class="description">Path (typically &quot;/&quot;)</dd>
+<dt>domain</dt>
+<dd class="description">Domain name</dd>
+<dt>expires</dt>
+<dd class="description">Expiration date (0 for session)</dd>
+<dt>secure</dt>
+<dd class="description">Require SSL</dd>
+</dl>
+<h3 class="function"><a name="cgiSetIPPObjectVars">cgiSetIPPObjectVars</a></h3>
+<p class="description">Set CGI variables from an IPP object.</p>
+<p class="code">
+ipp_attribute_t *cgiSetIPPObjectVars (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;ipp_attribute_t *obj,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *prefix,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int element<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>obj</dt>
+<dd class="description">Response data to be copied...</dd>
+<dt>prefix</dt>
+<dd class="description">Prefix for name or NULL</dd>
+<dt>element</dt>
+<dd class="description">Parent element number</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Next object</p>
+<h3 class="function"><a name="cgiSetIPPVars">cgiSetIPPVars</a></h3>
+<p class="description">Set CGI variables from an IPP response.</p>
+<p class="code">
+int cgiSetIPPVars (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;ipp_t *response,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *filter_name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *filter_value,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *prefix,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int parent_el<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>response</dt>
+<dd class="description">Response data to be copied...</dd>
+<dt>filter_name</dt>
+<dd class="description">Filter name</dd>
+<dt>filter_value</dt>
+<dd class="description">Filter value</dd>
+<dt>prefix</dt>
+<dd class="description">Prefix for name or NULL</dd>
+<dt>parent_el</dt>
+<dd class="description">Parent element number</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Maximum number of elements</p>
+<h3 class="function"><a name="cgiSetServerVersion">cgiSetServerVersion</a></h3>
+<p class="description">Set the server name and CUPS version...</p>
+<p class="code">
+void cgiSetServerVersion (void);</p>
+<h3 class="function"><a name="cgiSetSize">cgiSetSize</a></h3>
+<p class="description">Set the array size.</p>
+<p class="code">
+void cgiSetSize (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int size<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Name of variable</dd>
+<dt>size</dt>
+<dd class="description">Number of elements (0 to N)</dd>
+</dl>
+<h3 class="function"><a name="cgiSetVariable">cgiSetVariable</a></h3>
+<p class="description">Set a CGI variable in the database.</p>
+<p class="code">
+void cgiSetVariable (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *value<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Name of variable</dd>
+<dt>value</dt>
+<dd class="description">Value of variable</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">If the variable is an array, this truncates the array to a single element.</p>
+<h3 class="function"><a name="cgiShowIPPError">cgiShowIPPError</a></h3>
+<p class="description">Show the last IPP error message.</p>
+<p class="code">
+void cgiShowIPPError (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *message<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>message</dt>
+<dd class="description">Contextual message</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The caller must still call cgiStartHTML() and cgiEndHTML().</p>
+<h3 class="function"><a name="cgiShowJobs">cgiShowJobs</a></h3>
+<p class="description">Show print jobs.</p>
+<p class="code">
+void cgiShowJobs (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *dest<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>dest</dt>
+<dd class="description">Destination name or NULL</dd>
+</dl>
+<h3 class="function"><a name="cgiStartHTML">cgiStartHTML</a></h3>
+<p class="description">Start a HTML page.</p>
+<p class="code">
+void cgiStartHTML (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *title<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>title</dt>
+<dd class="description">Title of page</dd>
+</dl>
+<h3 class="function"><a name="cgiStartMultipart">cgiStartMultipart</a></h3>
+<p class="description">Start a multipart delivery of a web page.</p>
+<p class="code">
+void cgiStartMultipart (void);</p>
+<h3 class="function"><a name="cgiSupportsMultipart">cgiSupportsMultipart</a></h3>
+<p class="description">Does the browser support multi-part documents?</p>
+<p class="code">
+int cgiSupportsMultipart (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if multi-part supported, 0 otherwise</p>
+<h3 class="function"><a name="cgiText">cgiText</a></h3>
+<p class="description">Return localized text.</p>
+<p class="code">
+const char *cgiText (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *message<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>message</dt>
+<dd class="description">Message</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Localized message</p>
+<h3 class="function"><a name="helpDeleteIndex">helpDeleteIndex</a></h3>
+<p class="description">Delete an index, freeing all memory used.</p>
+<p class="code">
+void helpDeleteIndex (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#help_index_t">help_index_t</a> *hi<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>hi</dt>
+<dd class="description">Help index</dd>
+</dl>
+<h3 class="function"><a name="helpFindNode">helpFindNode</a></h3>
+<p class="description">Find a node in an index.</p>
+<p class="code">
+<a href="#help_node_t">help_node_t</a> *helpFindNode (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#help_index_t">help_index_t</a> *hi,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *filename,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *anchor<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>hi</dt>
+<dd class="description">Index</dd>
+<dt>filename</dt>
+<dd class="description">Filename</dd>
+<dt>anchor</dt>
+<dd class="description">Anchor</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Node pointer or NULL</p>
+<h3 class="function"><a name="helpLoadIndex">helpLoadIndex</a></h3>
+<p class="description">Load a help index from disk.</p>
+<p class="code">
+<a href="#help_index_t">help_index_t</a> *helpLoadIndex (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *hifile,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *directory<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>hifile</dt>
+<dd class="description">Index filename</dd>
+<dt>directory</dt>
+<dd class="description">Directory that is indexed</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Index pointer or NULL</p>
+<h3 class="function"><a name="helpSaveIndex">helpSaveIndex</a></h3>
+<p class="description">Save a help index to disk.</p>
+<p class="code">
+int helpSaveIndex (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#help_index_t">help_index_t</a> *hi,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *hifile<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>hi</dt>
+<dd class="description">Index</dd>
+<dt>hifile</dt>
+<dd class="description">Index filename</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error</p>
+<h3 class="function"><a name="helpSearchIndex">helpSearchIndex</a></h3>
+<p class="description">Search an index.</p>
+<p class="code">
+<a href="#help_index_t">help_index_t</a> *helpSearchIndex (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#help_index_t">help_index_t</a> *hi,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *query,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *section,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *filename<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>hi</dt>
+<dd class="description">Index</dd>
+<dt>query</dt>
+<dd class="description">Query string</dd>
+<dt>section</dt>
+<dd class="description">Limit search to this section</dd>
+<dt>filename</dt>
+<dd class="description">Limit search to this file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Search index</p>
+<h2 class="title"><a name="TYPES">Data Types</a></h2>
+<h3 class="typedef"><a name="cgi_file_t">cgi_file_t</a></h3>
+<p class="description">Uploaded file data</p>
+<p class="code">
+typedef struct <a href="#cgi_file_s">cgi_file_s</a> cgi_file_t;
+</p>
+<h3 class="typedef"><a name="help_index_t">help_index_t</a></h3>
+<p class="description">Help index structure</p>
+<p class="code">
+typedef struct <a href="#help_index_s">help_index_s</a> help_index_t;
+</p>
+<h3 class="typedef"><a name="help_node_t">help_node_t</a></h3>
+<p class="description">Help node structure...</p>
+<p class="code">
+typedef struct <a href="#help_node_s">help_node_s</a> help_node_t;
+</p>
+<h3 class="typedef"><a name="help_word_t">help_word_t</a></h3>
+<p class="description">Help word structure...</p>
+<p class="code">
+typedef struct <a href="#help_word_s">help_word_s</a> help_word_t;
+</p>
+<h2 class="title"><a name="STRUCTURES">Structures</a></h2>
+<h3 class="struct"><a name="cgi_file_s">cgi_file_s</a></h3>
+<p class="description">Uploaded file data</p>
+<p class="code">struct cgi_file_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t filesize;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char tempfile[1024], *name, *filename, *mimetype;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>filesize </dt>
+<dd class="description">Size of uploaded file</dd>
+<dt>mimetype </dt>
+<dd class="description">MIME media type</dd>
+</dl>
+<h3 class="struct"><a name="help_index_s">help_index_s</a></h3>
+<p class="description">Help index structure</p>
+<p class="code">struct help_index_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_array_t *nodes;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int search;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_array_t *sorted;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>nodes </dt>
+<dd class="description">Nodes sorted by filename</dd>
+<dt>search </dt>
+<dd class="description">1 = search index, 0 = normal</dd>
+<dt>sorted </dt>
+<dd class="description">Nodes sorted by score + text</dd>
+</dl>
+<h3 class="struct"><a name="help_node_s">help_node_s</a></h3>
+<p class="description">Help node structure...</p>
+<p class="code">struct help_node_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *anchor;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *filename;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t length;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;time_t mtime;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;off_t offset;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int score;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *section;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *text;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_array_t *words;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>anchor </dt>
+<dd class="description">Anchor name (NULL if none)</dd>
+<dt>filename </dt>
+<dd class="description">Filename, relative to help dir</dd>
+<dt>length </dt>
+<dd class="description">Length in bytes</dd>
+<dt>mtime </dt>
+<dd class="description">Last modification time</dd>
+<dt>offset </dt>
+<dd class="description">Offset in file</dd>
+<dt>score </dt>
+<dd class="description">Search score</dd>
+<dt>section </dt>
+<dd class="description">Section name (NULL if none)</dd>
+<dt>text </dt>
+<dd class="description">Text in anchor</dd>
+<dt>words </dt>
+<dd class="description">Words after this node</dd>
+</dl>
+<h3 class="struct"><a name="help_word_s">help_word_s</a></h3>
+<p class="description">Help word structure...</p>
+<p class="code">struct help_word_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int count;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *text;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>count </dt>
+<dd class="description">Number of occurrences</dd>
+<dt>text </dt>
+<dd class="description">Word text</dd>
+</dl>
+</div>
+</body>
+</html>
diff --git a/doc/help/api-cups.html b/doc/help/api-cups.html
new file mode 100644
index 000000000..2dd408308
--- /dev/null
+++ b/doc/help/api-cups.html
@@ -0,0 +1,2521 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>CUPS API </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: api-cups.html 9772 2011-05-12 05:46:30Z mike $"
+
+ CUPS API header for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>CUPS API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/cups.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcups</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a><br>
+ Programming: <a href='api-array.html' target='_top'>Array API</a><br>
+ Programming: <a href='api-filedir.html' target='_top'>File and Directory APIs</a><br>
+ Programming: <a href='api-filter.html' target='_top'>Filter and Backend Programming</a><br>
+ Programming: <a href='api-httpipp.html' target='_top'>HTTP and IPP APIs</a><br>
+ Programming: <a href='api-ppd.html' target='_top'>PPD API</a><br>
+ Programming: <a href='api-raster.html' target='_top'>Raster API</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#OVERVIEW">Overview</a><ul class="subcontents">
+ <li><a href="#CLIENTS_AND_SERVERS">Clients and Servers</a></li>
+ <li><a href="#PRINTERS_AND_CLASSES">Printers and Classes</a></li>
+ <li><a href="#OPTIONS">Options</a></li>
+ <li><a href="#PRINT_JOBS">Print Jobs</a></li>
+ <li><a href="#ERROR_HANDLING">Error Handling</a></li>
+ <li><a href="#PASSWORDS_AND_AUTHENTICATION">Passwords and Authentication</a></li>
+</ul></li>
+<li><a href="#FUNCTIONS">Functions</a><ul class="code">
+ <li><a href="#appleGetPaperSize" title="Get the default paper size.">appleGetPaperSize</a></li>
+ <li><a href="#cupsAddDest" title="Add a destination to the list of destinations.">cupsAddDest</a></li>
+ <li><a href="#cupsAddOption" title="Add an option to an option array.">cupsAddOption</a></li>
+ <li><a href="#cupsAdminCreateWindowsPPD" title="Create the Windows PPD file for a printer.">cupsAdminCreateWindowsPPD</a></li>
+ <li><a href="#cupsAdminExportSamba" title="Export a printer to Samba.">cupsAdminExportSamba</a></li>
+ <li><a href="#cupsAdminGetServerSettings" title="Get settings from the server.">cupsAdminGetServerSettings</a></li>
+ <li><a href="#cupsAdminSetServerSettings" title="Set settings on the server.">cupsAdminSetServerSettings</a></li>
+ <li><a href="#cupsCancelJob" title="Cancel a print job on the default server.">cupsCancelJob</a></li>
+ <li><a href="#cupsCancelJob2" title="Cancel or purge a print job.">cupsCancelJob2</a></li>
+ <li><a href="#cupsCreateJob" title="Create an empty job for streaming.">cupsCreateJob</a></li>
+ <li><a href="#cupsEncryption" title="Get the current encryption settings.">cupsEncryption</a></li>
+ <li><a href="#cupsFinishDocument" title="Finish sending a document.">cupsFinishDocument</a></li>
+ <li><a href="#cupsFreeDests" title="Free the memory used by the list of destinations.">cupsFreeDests</a></li>
+ <li><a href="#cupsFreeJobs" title="Free memory used by job data.">cupsFreeJobs</a></li>
+ <li><a href="#cupsFreeOptions" title="Free all memory used by options.">cupsFreeOptions</a></li>
+ <li><a href="#cupsGetClasses" title="Get a list of printer classes from the default server.">cupsGetClasses</a></li>
+ <li><a href="#cupsGetDefault" title="Get the default printer or class for the default server.">cupsGetDefault</a></li>
+ <li><a href="#cupsGetDefault2" title="Get the default printer or class for the specified server.">cupsGetDefault2</a></li>
+ <li><a href="#cupsGetDest" title="Get the named destination from the list.">cupsGetDest</a></li>
+ <li><a href="#cupsGetDests" title="Get the list of destinations from the default server.">cupsGetDests</a></li>
+ <li><a href="#cupsGetDests2" title="Get the list of destinations from the specified server.">cupsGetDests2</a></li>
+ <li><a href="#cupsGetJobs" title="Get the jobs from the default server.">cupsGetJobs</a></li>
+ <li><a href="#cupsGetJobs2" title="Get the jobs from the specified server.">cupsGetJobs2</a></li>
+ <li><a href="#cupsGetNamedDest" title="Get options for the named destination.">cupsGetNamedDest</a></li>
+ <li><a href="#cupsGetOption" title="Get an option value.">cupsGetOption</a></li>
+ <li><a href="#cupsGetPPD" title="Get the PPD file for a printer on the default server.">cupsGetPPD</a></li>
+ <li><a href="#cupsGetPPD2" title="Get the PPD file for a printer from the specified server.">cupsGetPPD2</a></li>
+ <li><a href="#cupsGetPPD3" title="Get the PPD file for a printer on the specified
+server if it has changed.">cupsGetPPD3</a></li>
+ <li><a href="#cupsGetPassword" title="Get a password from the user.">cupsGetPassword</a></li>
+ <li><a href="#cupsGetPassword2" title="Get a password from the user using the advanced
+password callback.">cupsGetPassword2</a></li>
+ <li><a href="#cupsGetPrinters" title="Get a list of printers from the default server.">cupsGetPrinters</a></li>
+ <li><a href="#cupsGetServerPPD" title="Get an available PPD file from the server.">cupsGetServerPPD</a></li>
+ <li><a href="#cupsLangDefault" title="Return the default language.">cupsLangDefault</a></li>
+ <li><a href="#cupsLangEncoding" title="Return the character encoding (us-ascii, etc.)
+for the given language.">cupsLangEncoding</a></li>
+ <li><a href="#cupsLangFlush" title="Flush all language data out of the cache.">cupsLangFlush</a></li>
+ <li><a href="#cupsLangFree" title="Free language data.">cupsLangFree</a></li>
+ <li><a href="#cupsLangGet" title="Get a language.">cupsLangGet</a></li>
+ <li><a href="#cupsNotifySubject" title="Return the subject for the given notification message.">cupsNotifySubject</a></li>
+ <li><a href="#cupsNotifyText" title="Return the text for the given notification message.">cupsNotifyText</a></li>
+ <li><a href="#cupsParseOptions" title="Parse options from a command-line argument.">cupsParseOptions</a></li>
+ <li><a href="#cupsPrintFile" title="Print a file to a printer or class on the default server.">cupsPrintFile</a></li>
+ <li><a href="#cupsPrintFile2" title="Print a file to a printer or class on the specified
+server.">cupsPrintFile2</a></li>
+ <li><a href="#cupsPrintFiles" title="Print one or more files to a printer or class on the
+default server.">cupsPrintFiles</a></li>
+ <li><a href="#cupsPrintFiles2" title="Print one or more files to a printer or class on the
+specified server.">cupsPrintFiles2</a></li>
+ <li><a href="#cupsRemoveDest" title="Remove a destination from the destination list.">cupsRemoveDest</a></li>
+ <li><a href="#cupsRemoveOption" title="Remove an option from an option array.">cupsRemoveOption</a></li>
+ <li><a href="#cupsServer" title="Return the hostname/address of the current server.">cupsServer</a></li>
+ <li><a href="#cupsSetClientCertCB" title="Set the client certificate callback.">cupsSetClientCertCB</a></li>
+ <li><a href="#cupsSetCredentials" title="Set the default credentials to be used for SSL/TLS
+connections.">cupsSetCredentials</a></li>
+ <li><a href="#cupsSetDefaultDest" title="Set the default destination.">cupsSetDefaultDest</a></li>
+ <li><a href="#cupsSetDests" title="Save the list of destinations for the default server.">cupsSetDests</a></li>
+ <li><a href="#cupsSetDests2" title="Save the list of destinations for the specified server.">cupsSetDests2</a></li>
+ <li><a href="#cupsSetEncryption" title="Set the encryption preference.">cupsSetEncryption</a></li>
+ <li><a href="#cupsSetPasswordCB" title="Set the password callback for CUPS.">cupsSetPasswordCB</a></li>
+ <li><a href="#cupsSetPasswordCB2" title="Set the advanced password callback for CUPS.">cupsSetPasswordCB2</a></li>
+ <li><a href="#cupsSetServer" title="Set the default server name and port.">cupsSetServer</a></li>
+ <li><a href="#cupsSetServerCertCB" title="Set the server certificate callback.">cupsSetServerCertCB</a></li>
+ <li><a href="#cupsSetUser" title="Set the default user name.">cupsSetUser</a></li>
+ <li><a href="#cupsStartDocument" title="Add a document to a job created with cupsCreateJob().">cupsStartDocument</a></li>
+ <li><a href="#cupsTempFd" title="Creates a temporary file.">cupsTempFd</a></li>
+ <li><a href="#cupsTempFile" title="Generates a temporary filename.">cupsTempFile</a></li>
+ <li><a href="#cupsTempFile2" title="Creates a temporary CUPS file.">cupsTempFile2</a></li>
+ <li><a href="#cupsUser" title="Return the current user's name.">cupsUser</a></li>
+</ul></li>
+<li><a href="#TYPES">Data Types</a><ul class="code">
+ <li><a href="#cups_client_cert_cb_t" title="Client credentials callback ">cups_client_cert_cb_t</a></li>
+ <li><a href="#cups_dest_t" title="Destination">cups_dest_t</a></li>
+ <li><a href="#cups_device_cb_t" title="Device callback ">cups_device_cb_t</a></li>
+ <li><a href="#cups_job_t" title="Job">cups_job_t</a></li>
+ <li><a href="#cups_option_t" title="Printer Options">cups_option_t</a></li>
+ <li><a href="#cups_password_cb2_t" title="New password callback ">cups_password_cb2_t</a></li>
+ <li><a href="#cups_password_cb_t" title="Password callback">cups_password_cb_t</a></li>
+ <li><a href="#cups_ptype_t" title="Printer type/capability bits">cups_ptype_t</a></li>
+ <li><a href="#cups_server_cert_cb_t" title="Server credentials callback ">cups_server_cert_cb_t</a></li>
+</ul></li>
+<li><a href="#STRUCTURES">Structures</a><ul class="code">
+ <li><a href="#cups_dest_s" title="Destination">cups_dest_s</a></li>
+ <li><a href="#cups_job_s" title="Job">cups_job_s</a></li>
+ <li><a href="#cups_option_s" title="Printer Options">cups_option_s</a></li>
+</ul></li>
+<li><a href="#VARIABLES">Variables</a><ul class="code">
+ <li><a href="#CF_RETURNS_RETAINED" title="Get the Apple language identifier associated with a
+locale ID.">CF_RETURNS_RETAINED</a></li>
+</ul></li>
+<li><a href="#ENUMERATIONS">Constants</a><ul class="code">
+ <li><a href="#cups_ptype_e" title="Printer type/capability bit constants">cups_ptype_e</a></li>
+</ul></li>
+</ul>
+<!--
+ "$Id: api-cups.html 9772 2011-05-12 05:46:30Z mike $"
+
+ API introduction for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>The CUPS API provides the convenience functions needed to support
+applications, filters, printer drivers, and backends that need to interface
+with the CUPS scheduler.</p>
+
+<h3><a name='CLIENTS_AND_SERVERS'>Clients and Servers</a></h3>
+
+<p>CUPS is based on the Internet Printing Protocol ("IPP"), which allows
+clients (applications) to communicate with a server (the scheduler) to get a
+list of printers, send print jobs, and so forth. You identify which server
+you want to communicate with using a pointer to the opaque structure
+<code>http_t</code>. All of the examples in this document use the
+<code>CUPS_HTTP_DEFAULT</code> constant, referring to the default connection
+to the scheduler. The <a href='api-httpipp.html' target='_top'>HTTP and IPP
+APIs</a> document provides more information on server connections.</p>
+
+<h3><a name='PRINTERS_AND_CLASSES'>Printers and Classes</a></h3>
+
+<p>Printers and classes (collections of printers) are accessed through
+the <a href="#cups_dest_t"><code>cups_dest_t</code></a> structure which
+includes the name (<code>name</code>), instance (<code>instance</code> -
+a way of selecting certain saved options/settings), and the options and
+attributes associated with that destination (<code>num_options</code> and
+<code>options</code>). Destinations are created using the
+<a href="#cupsGetDests"><code>cupsGetDests</code></a> function and freed
+using the <a href='#cupsFreeDests'><code>cupsFreeDests</code></a> function.
+The <a href='#cupsGetDest'><code>cupsGetDest</code></a> function finds a
+specific destination for printing:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+<a href='#cups_dest_t'>cups_dest_t</a> *dests;
+int num_dests = <a href='#cupsGetDests'>cupsGetDests</a>(&amp;dests);
+<a href='#cups_dest_t'>cups_dest_t</a> *dest = <a href='#cupsGetDest'>cupsGetDest</a>("name", NULL, num_dests, dests);
+
+/* do something with dest */
+
+<a href='#cupsFreeDests'>cupsFreeDests</a>(num_dests, dests);
+</pre>
+
+<p>Passing <code>NULL</code> to
+<a href='#cupsGetDest'><code>cupsGetDest</code></a> for the destination name
+will return the default destination. Similarly, passing a <code>NULL</code>
+instance will return the default instance for that destination.</p>
+
+<div class='table'><table summary='Table 1: Printer Attributes' width='80%'>
+<caption>Table 1: <a name='TABLE1'>Printer Attributes</a></caption>
+<thead>
+<tr>
+ <th>Attribute Name</th>
+ <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>"auth-info-required"</td>
+ <td>The type of authentication required for printing to this
+ destination: "none", "username,password", "domain,username,password",
+ or "negotiate" (Kerberos)</td>
+</tr>
+<tr>
+ <td>"printer-info"</td>
+ <td>The human-readable description of the destination such as "My
+ Laser Printer".</td>
+</tr>
+<tr>
+ <td>"printer-is-accepting-jobs"</td>
+ <td>"true" if the destination is accepting new jobs, "false" if
+ not.</td>
+</tr>
+<tr>
+ <td>"printer-is-shared"</td>
+ <td>"true" if the destination is being shared with other computers,
+ "false" if not.</td>
+</tr>
+<tr>
+ <td>"printer-location"</td>
+ <td>The human-readable location of the destination such as "Lab 4".</td>
+</tr>
+<tr>
+ <td>"printer-make-and-model"</td>
+ <td>The human-readable make and model of the destination such as "HP
+ LaserJet 4000 Series".</td>
+</tr>
+<tr>
+ <td>"printer-state"</td>
+ <td>"3" if the destination is idle, "4" if the destination is printing
+ a job, and "5" if the destination is stopped.</td>
+</tr>
+<tr>
+ <td>"printer-state-change-time"</td>
+ <td>The UNIX time when the destination entered the current state.</td>
+</tr>
+<tr>
+ <td>"printer-state-reasons"</td>
+ <td>Additional comma-delimited state keywords for the destination
+ such as "media-tray-empty-error" and "toner-low-warning".</td>
+</tr>
+<tr>
+ <td>"printer-type"</td>
+ <td>The <a href='#cups_printer_t'><code>cups_printer_t</code></a>
+ value associated with the destination.</td>
+</tr>
+</tbody>
+</table></div>
+
+<h3><a name='OPTIONS'>Options</a></h3>
+
+<p>Options are stored in arrays of
+<a href='#cups_option_t'><code>cups_option_t</code></a> structures. Each
+option has a name (<code>name</code>) and value (<code>value</code>)
+associated with it. The <a href='#cups_dest_t'><code>cups_dest_t</code></a>
+<code>num_options</code> and <code>options</code> members contain the
+default options for a particular destination, along with several informational
+attributes about the destination as shown in <a href='#TABLE1'>Table 1</a>.
+The <a href='#cupsGetOption'><code>cupsGetOption</code></a> function gets
+the value for the named option. For example, the following code lists the
+available destinations and their human-readable descriptions:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+<a href='#cups_dest_t'>cups_dest_t</a> *dests;
+int num_dests = <a href='#cupsGetDests'>cupsGetDests</a>(&amp;dests);
+<a href='#cups_dest_t'>cups_dest_t</a> *dest;
+int i;
+const char *value;
+
+for (i = num_dests, dest = dests; i > 0; i --, dest ++)
+ if (dest->instance == NULL)
+ {
+ value = <a href='#cupsGetOption'>cupsGetOption</a>("printer-info", dest->num_options, dest->options);
+ printf("%s (%s)\n", dest->name, value ? value : "no description");
+ }
+
+<a href='#cupsFreeDests'>cupsFreeDests</a>(num_dests, dests);
+</pre>
+
+<p>You can create your own option arrays using the
+<a href='#cupsAddOption'><code>cupsAddOption</code></a> function, which
+adds a single named option to an array:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+int num_options = 0;
+<a href='#cups_option_t'>cups_option_t</a> *options = NULL;
+
+/* The returned num_options value is updated as needed */
+num_options = <a href='#cupsAddOption'>cupsAddOption</a>("first", "value", num_options, &amp;options);
+
+/* This adds a second option value */
+num_options = <a href='#cupsAddOption'>cupsAddOption</a>("second", "value", num_options, &amp;options);
+
+/* This replaces the first option we added */
+num_options = <a href='#cupsAddOption'>cupsAddOption</a>("first", "new value", num_options, &amp;options);
+</pre>
+
+<p>Use a <code>for</code> loop to copy the options from a destination:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+int i;
+int num_options = 0;
+<a href='#cups_option_t'>cups_option_t</a> *options = NULL;
+<a href='#cups_dest_t'>cups_dest_t</a> *dest;
+
+for (i = 0; i < dest->num_options; i ++)
+ num_options = <a href='#cupsAddOption'>cupsAddOption</a>(dest->options[i].name, dest->options[i].value,
+ num_options, &amp;options);
+</pre>
+
+<p>Use the <a href='#cupsFreeOptions'><code>cupsFreeOptions</code></a>
+function to free the options array when you are done using it:</p>
+
+<pre class='example'>
+<a href='#cupsFreeOptions'>cupsFreeOptions</a>(num_options, options);
+</pre>
+
+<h3><a name='PRINT_JOBS'>Print Jobs</a></h3>
+
+<p>Print jobs are identified by a locally-unique job ID number from 1 to
+2<sup>31</sup>-1 and have options and one or more files for printing to a
+single destination. The <a href='#cupsPrintFile'><code>cupsPrintFile</code></a>
+function creates a new job with one file. The following code prints the CUPS
+test page file:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+<a href='#cups_dest_t'>cups_dest_t</a> *dest;
+int num_options;
+<a href='#cups_option_t'>cups_option_t</a> *options;
+int job_id;
+
+/* Print a single file */
+job_id = <a href='#cupsPrintFile'>cupsPrintFile</a>(dest->name, "/usr/share/cups/data/testprint.ps",
+ "Test Print", num_options, options);
+</pre>
+
+<p>The <a href='#cupsPrintFiles'><code>cupsPrintFiles</code></a> function
+creates a job with multiple files. The files are provided in a
+<code>char *</code> array:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+<a href='#cups_dest_t'>cups_dest_t</a> *dest;
+int num_options;
+<a href='#cups_option_t'>cups_option_t</a> *options;
+int job_id;
+char *files[3] = { "file1.pdf", "file2.pdf", "file3.pdf" };
+
+/* Print three files */
+job_id = <a href='#cupsPrintFiles'>cupsPrintFiles</a>(dest->name, 3, files, "Test Print", num_options, options);
+</pre>
+
+<p>Finally, the <a href='#cupsCreateJob'><code>cupsCreateJob</code></a>
+function creates a new job with no files in it. Files are added using the
+<a href='#cupsStartDocument'><code>cupsStartDocument</code></a>,
+<a href='api-httpipp.html#cupsWriteRequestData'><code>cupsWriteRequestData</code></a>,
+and <a href='#cupsFinishDocument'><code>cupsFinishDocument</code></a> functions.
+The following example creates a job with 10 text files for printing:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+<a href='#cups_dest_t'>cups_dest_t</a> *dest;
+int num_options;
+<a href='#cups_option_t'>cups_option_t</a> *options;
+int job_id;
+int i;
+char buffer[1024];
+
+/* Create the job */
+job_id = <a href='#cupsCreateJob'>cupsCreateJob</a>(CUPS_HTTP_DEFAULT, dest->name, "10 Text Files",
+ num_options, options);
+
+/* If the job is created, add 10 files */
+if (job_id > 0)
+{
+ for (i = 1; i &lt;= 10; i ++)
+ {
+ snprintf(buffer, sizeof(buffer), "file%d.txt", i);
+
+ <a href='#cupsStartDocument'>cupsStartDocument</a>(CUPS_HTTP_DEFAULT, dest->name, job_id, buffer,
+ CUPS_FORMAT_TEXT, i == 10);
+
+ snprintf(buffer, sizeof(buffer),
+ "File %d\n"
+ "\n"
+ "One fish,\n"
+ "Two fish,\n
+ "Red fish,\n
+ "Blue fish\n", i);
+
+ /* cupsWriteRequestData can be called as many times as needed */
+ <a href='#cupsWriteRequestData'>cupsWriteRequestData</a>(CUPS_HTTP_DEFAULT, buffer, strlen(buffer));
+
+ <a href='#cupsFinishDocument'>cupsFinishDocument</a>(CUPS_HTTP_DEFAULT, dest->name);
+ }
+}
+</pre>
+
+<p>Once you have created a job, you can monitor its status using the
+<a href='#cupsGetJobs'><code>cupsGetJobs</code></a> function, which returns
+an array of <a href='#cups_job_t'><code>cups_job_t</code></a> structures.
+Each contains the job ID (<code>id</code>), destination name
+(<code>dest</code>), title (<code>title</code>), and other information
+associated with the job. The job array is freed using the
+<a href='#cupsFreeJobs'><code>cupsFreeJobs</code></a> function. The following
+example monitors a specific job ID, showing the current job state once every
+5 seconds until the job is completed:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+<a href='#cups_dest_t'>cups_dest_t</a> *dest;
+int job_id;
+int num_jobs;
+<a href='#cups_job_t'>cups_job_t</a> *jobs;
+int i;
+ipp_jstate_t job_state = IPP_JOB_PENDING;
+
+while (job_state &lt; IPP_JOB_STOPPED)
+{
+ /* Get my jobs (1) with any state (-1) */
+ num_jobs = <a href='#cupsGetJobs'>cupsGetJobs</a>(&amp;jobs, dest->name, 1, -1);
+
+ /* Loop to find my job */
+ job_state = IPP_JOB_COMPLETED;
+
+ for (i = 0; i &lt; num_jobs; i ++)
+ if (jobs[i].id == job_id)
+ {
+ job_state = jobs[i].state;
+ break;
+ }
+
+ /* Free the job array */
+ <a href='#cupsFreeJobs'>cupsFreeJobs</a>(num_jobs, jobs);
+
+ /* Show the current state */
+ switch (job_state)
+ {
+ case IPP_JOB_PENDING :
+ printf("Job %d is pending.\n", job_id);
+ break;
+ case IPP_JOB_HELD :
+ printf("Job %d is held.\n", job_id);
+ break;
+ case IPP_JOB_PROCESSING :
+ printf("Job %d is processing.\n", job_id);
+ break;
+ case IPP_JOB_STOPPED :
+ printf("Job %d is stopped.\n", job_id);
+ break;
+ case IPP_JOB_CANCELED :
+ printf("Job %d is canceled.\n", job_id);
+ break;
+ case IPP_JOB_ABORTED :
+ printf("Job %d is aborted.\n", job_id);
+ break;
+ case IPP_JOB_COMPLETED :
+ printf("Job %d is completed.\n", job_id);
+ break;
+ }
+
+ /* Sleep if the job is not finished */
+ if (job_state &lt; IPP_JOB_STOPPED)
+ sleep(5);
+}
+</pre>
+
+<p>To cancel a job, use the
+<a href='#cupsCancelJob'><code>cupsCancelJob</code></a> function with the
+job ID:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+<a href='#cups_dest_t'>cups_dest_t</a> *dest;
+int job_id;
+
+<a href='#cupsCancelJob'>cupsCancelJob</a>(dest->name, job_id);
+</pre>
+
+<h3><a name='ERROR_HANDLING'>Error Handling</a></h3>
+
+<p>If any of the CUPS API printing functions returns an error, the reason for
+that error can be found by calling the
+<a href='#cupsLastError'><code>cupsLastError</code></a> and
+<a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> functions.
+<a href='#cupsLastError'><code>cupsLastError</code></a> returns the last IPP
+error code
+(<a href='api-httpipp.html#ipp_status_t'><code>ipp_status_t</code></a>)
+that was encountered, while
+<a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> returns
+a (localized) human-readable string that can be shown to the user. For example,
+if any of the job creation functions returns a job ID of 0, you can use
+<a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> to show
+the reason why the job could not be created:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+int job_id;
+
+if (job_id == 0)
+ puts(cupsLastErrorString());
+</pre>
+
+<h3><a name='PASSWORDS_AND_AUTHENTICATION'>Passwords and Authentication</a></h3>
+
+<p>CUPS supports authentication of any request, including submission of print
+jobs. The default mechanism for getting the username and password is to use the
+login user and a password from the console.</p>
+
+<p>To support other types of applications, in particular Graphical User
+Interfaces ("GUIs"), the CUPS API provides functions to set the default
+username and to register a callback function that returns a password string.</p>
+
+<p>The <a href="#cupsSetPasswordCB"><code>cupsSetPasswordCB</code></a>
+function is used to set a password callback in your program. Only one
+function can be used at any time.</p>
+
+<p>The <a href="#cupsSetUser"><code>cupsSetUser</code></a> function sets the
+current username for authentication. This function can be called by your
+password callback function to change the current username as needed.</p>
+
+<p>The following example shows a simple password callback that gets a
+username and password from the user:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+const char *
+my_password_cb(const char *prompt)
+{
+ char user[65];
+
+
+ puts(prompt);
+
+ /* Get a username from the user */
+ printf("Username: ");
+ if (fgets(user, sizeof(user), stdin) == NULL)
+ return (NULL);
+
+ /* Strip the newline from the string and set the user */
+ user[strlen(user) - 1] = '\0';
+
+ <a href='#cupsSetUser'>cupsSetUser</a>(user);
+
+ /* Use getpass() to ask for the password... */
+ return (getpass("Password: "));
+}
+
+<a href='#cupsSetPasswordCB'>cupsSetPasswordCB</a>(my_password_cb);
+</pre>
+
+<p>Similarly, a GUI could display the prompt string in a window with input
+fields for the username and password. The username should default to the
+string returned by the <a href="#cupsUser"><code>cupsUser</code></a>
+function.</p>
+<h2 class="title"><a name="FUNCTIONS">Functions</a></h2>
+<h3 class="function"><a name="appleGetPaperSize">appleGetPaperSize</a></h3>
+<p class="description">Get the default paper size.</p>
+<p class="code">
+char *appleGetPaperSize (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int namesize<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Paper size name buffer</dd>
+<dt>namesize</dt>
+<dd class="description">Size of buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Default paper size</p>
+<h3 class="function"><a name="cupsAddDest">cupsAddDest</a></h3>
+<p class="description">Add a destination to the list of destinations.</p>
+<p class="code">
+int cupsAddDest (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *instance,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_dests,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_dest_t">cups_dest_t</a> **dests<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Destination name</dd>
+<dt>instance</dt>
+<dd class="description">Instance name or <code>NULL</code> for none/primary</dd>
+<dt>num_dests</dt>
+<dd class="description">Number of destinations</dd>
+<dt>dests</dt>
+<dd class="description">Destinations</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New number of destinations</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function cannot be used to add a new class or printer queue,
+it only adds a new container of saved options for the named
+destination or instance.<br>
+<br>
+If the named destination already exists, the destination list is
+returned unchanged. Adding a new instance of a destination creates
+a copy of that destination's options.<br>
+<br>
+Use the <a href="#cupsSaveDests"><code>cupsSaveDests</code></a> function to save the updated list of
+destinations to the user's lpoptions file.</p>
+<h3 class="function"><a name="cupsAddOption">cupsAddOption</a></h3>
+<p class="description">Add an option to an option array.</p>
+<p class="code">
+int cupsAddOption (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *value,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_option_t">cups_option_t</a> **options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Name of option</dd>
+<dt>value</dt>
+<dd class="description">Value of option</dd>
+<dt>num_options</dt>
+<dd class="description">Number of options</dd>
+<dt>options</dt>
+<dd class="description">Pointer to options</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of options</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">New option arrays can be initialized simply by passing 0 for the
+&quot;num_options&quot; parameter.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsAdminCreateWindowsPPD">cupsAdminCreateWindowsPPD</a></h3>
+<p class="description">Create the Windows PPD file for a printer.</p>
+<p class="code">
+char *cupsAdminCreateWindowsPPD (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *dest,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *buffer,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int bufsize<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>dest</dt>
+<dd class="description">Printer or class</dd>
+<dt>buffer</dt>
+<dd class="description">Filename buffer</dd>
+<dt>bufsize</dt>
+<dd class="description">Size of filename buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">PPD file or NULL</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsAdminExportSamba">cupsAdminExportSamba</a></h3>
+<p class="description">Export a printer to Samba.</p>
+<p class="code">
+int cupsAdminExportSamba (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *dest,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *samba_server,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *samba_user,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *samba_password,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;FILE *logfile<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>dest</dt>
+<dd class="description">Destination to export</dd>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>samba_server</dt>
+<dd class="description">Samba server</dd>
+<dt>samba_user</dt>
+<dd class="description">Samba username</dd>
+<dt>samba_password</dt>
+<dd class="description">Samba password</dd>
+<dt>logfile</dt>
+<dd class="description">Log file, if any</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 on success, 0 on failure</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="cupsAdminGetServerSettings">cupsAdminGetServerSettings</a></h3>
+<p class="description">Get settings from the server.</p>
+<p class="code">
+int cupsAdminGetServerSettings (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *num_settings,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_option_t">cups_option_t</a> **settings<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>num_settings</dt>
+<dd class="description">Number of settings</dd>
+<dt>settings</dt>
+<dd class="description">Settings</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 on success, 0 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The returned settings should be freed with cupsFreeOptions() when
+you are done with them.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="cupsAdminSetServerSettings">cupsAdminSetServerSettings</a></h3>
+<p class="description">Set settings on the server.</p>
+<p class="code">
+int cupsAdminSetServerSettings (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_settings,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_option_t">cups_option_t</a> *settings<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>num_settings</dt>
+<dd class="description">Number of settings</dd>
+<dt>settings</dt>
+<dd class="description">Settings</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 on success, 0 on failure</p>
+<h3 class="function"><a name="cupsCancelJob">cupsCancelJob</a></h3>
+<p class="description">Cancel a print job on the default server.</p>
+<p class="code">
+int cupsCancelJob (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int job_id<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Name of printer or class</dd>
+<dt>job_id</dt>
+<dd class="description">Job ID, <code>CUPS_JOBID_CURRENT</code> for the current job, or <code>CUPS_JOBID_ALL</code> for all jobs</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 on success, 0 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Pass <code>CUPS_JOBID_ALL</code> to cancel all jobs or <code>CUPS_JOBID_CURRENT</code>
+to cancel the current job on the named destination.<br>
+<br>
+Use the <a href="#cupsLastError"><code>cupsLastError</code></a> and <a href="#cupsLastErrorString"><code>cupsLastErrorString</code></a> functions to get
+the cause of any failure.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsCancelJob2">cupsCancelJob2</a></h3>
+<p class="description">Cancel or purge a print job.</p>
+<p class="code">
+ipp_status_t cupsCancelJob2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int job_id,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int purge<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>name</dt>
+<dd class="description">Name of printer or class</dd>
+<dt>job_id</dt>
+<dd class="description">Job ID, <code>CUPS_JOBID_CURRENT</code> for the current job, or <code>CUPS_JOBID_ALL</code> for all jobs</dd>
+<dt>purge</dt>
+<dd class="description">1 to purge, 0 to cancel</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">IPP status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Canceled jobs remain in the job history while purged jobs are removed
+from the job history.<br>
+<br>
+Pass <code>CUPS_JOBID_ALL</code> to cancel all jobs or <code>CUPS_JOBID_CURRENT</code>
+to cancel the current job on the named destination.<br>
+<br>
+Use the <a href="#cupsLastError"><code>cupsLastError</code></a> and <a href="#cupsLastErrorString"><code>cupsLastErrorString</code></a> functions to get
+the cause of any failure.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsCreateJob">cupsCreateJob</a></h3>
+<p class="description">Create an empty job for streaming.</p>
+<p class="code">
+int cupsCreateJob (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *title,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_option_t">cups_option_t</a> *options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>name</dt>
+<dd class="description">Destination name</dd>
+<dt>title</dt>
+<dd class="description">Title of job</dd>
+<dt>num_options</dt>
+<dd class="description">Number of options</dd>
+<dt>options</dt>
+<dd class="description">Options</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Job ID or 0 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Use this function when you want to stream print data using the
+<a href="#cupsStartDocument"><code>cupsStartDocument</code></a>, <a href="#cupsWriteRequestData"><code>cupsWriteRequestData</code></a>, and
+<a href="#cupsFinishDocument"><code>cupsFinishDocument</code></a> functions. If you have one or more files to
+print, use the <a href="#cupsPrintFile2"><code>cupsPrintFile2</code></a> or <a href="#cupsPrintFiles2"><code>cupsPrintFiles2</code></a> function
+instead.
+
+</p>
+<h3 class="function"><a name="cupsEncryption">cupsEncryption</a></h3>
+<p class="description">Get the current encryption settings.</p>
+<p class="code">
+http_encryption_t cupsEncryption (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Encryption settings</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The default encryption setting comes from the CUPS_ENCRYPTION
+environment variable, then the ~/.cups/client.conf file, and finally the
+/etc/cups/client.conf file. If not set, the default is
+<code>HTTP_ENCRYPT_IF_REQUESTED</code>.<br>
+<br>
+Note: The current encryption setting is tracked separately for each thread
+in a program. Multi-threaded programs that override the setting via the
+<a href="#cupsSetEncryption"><code>cupsSetEncryption</code></a> function need to do so in each thread for the same
+setting to be used.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsFinishDocument">cupsFinishDocument</a></h3>
+<p class="description">Finish sending a document.</p>
+<p class="code">
+ipp_status_t cupsFinishDocument (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>name</dt>
+<dd class="description">Destination name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of document submission</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The document must have been started using <a href="#cupsStartDocument"><code>cupsStartDocument</code></a>.
+
+</p>
+<h3 class="function"><a name="cupsFreeDests">cupsFreeDests</a></h3>
+<p class="description">Free the memory used by the list of destinations.</p>
+<p class="code">
+void cupsFreeDests (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_dests,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_dest_t">cups_dest_t</a> *dests<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>num_dests</dt>
+<dd class="description">Number of destinations</dd>
+<dt>dests</dt>
+<dd class="description">Destinations</dd>
+</dl>
+<h3 class="function"><a name="cupsFreeJobs">cupsFreeJobs</a></h3>
+<p class="description">Free memory used by job data.</p>
+<p class="code">
+void cupsFreeJobs (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_jobs,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_job_t">cups_job_t</a> *jobs<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>num_jobs</dt>
+<dd class="description">Number of jobs</dd>
+<dt>jobs</dt>
+<dd class="description">Jobs</dd>
+</dl>
+<h3 class="function"><a name="cupsFreeOptions">cupsFreeOptions</a></h3>
+<p class="description">Free all memory used by options.</p>
+<p class="code">
+void cupsFreeOptions (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_option_t">cups_option_t</a> *options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>num_options</dt>
+<dd class="description">Number of options</dd>
+<dt>options</dt>
+<dd class="description">Pointer to options</dd>
+</dl>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="cupsGetClasses">cupsGetClasses</a></h3>
+<p class="description">Get a list of printer classes from the default server.</p>
+<p class="code">
+int cupsGetClasses (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char ***classes<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>classes</dt>
+<dd class="description">Classes</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of classes</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is deprecated - use <a href="#cupsGetDests"><code>cupsGetDests</code></a> instead.
+
+</p>
+<h3 class="function"><a name="cupsGetDefault">cupsGetDefault</a></h3>
+<p class="description">Get the default printer or class for the default server.</p>
+<p class="code">
+const char *cupsGetDefault (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Default printer or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns the default printer or class as defined by
+the LPDEST or PRINTER environment variables. If these environment
+variables are not set, the server default destination is returned.
+Applications should use the <a href="#cupsGetDests"><code>cupsGetDests</code></a> and <a href="#cupsGetDest"><code>cupsGetDest</code></a>
+functions to get the user-defined default printer, as this function does
+not support the lpoptions-defined default printer.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.21/Mac OS X 10.4&nbsp;</span><a name="cupsGetDefault2">cupsGetDefault2</a></h3>
+<p class="description">Get the default printer or class for the specified server.</p>
+<p class="code">
+const char *cupsGetDefault2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Default printer or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns the default printer or class as defined by
+the LPDEST or PRINTER environment variables. If these environment
+variables are not set, the server default destination is returned.
+Applications should use the <a href="#cupsGetDests"><code>cupsGetDests</code></a> and <a href="#cupsGetDest"><code>cupsGetDest</code></a>
+functions to get the user-defined default printer, as this function does
+not support the lpoptions-defined default printer.
+
+</p>
+<h3 class="function"><a name="cupsGetDest">cupsGetDest</a></h3>
+<p class="description">Get the named destination from the list.</p>
+<p class="code">
+<a href="#cups_dest_t">cups_dest_t</a> *cupsGetDest (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *instance,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_dests,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_dest_t">cups_dest_t</a> *dests<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Destination name or <code>NULL</code> for the default destination</dd>
+<dt>instance</dt>
+<dd class="description">Instance name or <code>NULL</code></dd>
+<dt>num_dests</dt>
+<dd class="description">Number of destinations</dd>
+<dt>dests</dt>
+<dd class="description">Destinations</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Destination pointer or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Use the <a href="#cupsGetDests"><code>cupsGetDests</code></a> or <a href="#cupsGetDests2"><code>cupsGetDests2</code></a> functions to get a
+list of supported destinations for the current user.</p>
+<h3 class="function"><a name="cupsGetDests">cupsGetDests</a></h3>
+<p class="description">Get the list of destinations from the default server.</p>
+<p class="code">
+int cupsGetDests (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_dest_t">cups_dest_t</a> **dests<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>dests</dt>
+<dd class="description">Destinations</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of destinations</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Starting with CUPS 1.2, the returned list of destinations include the
+printer-info, printer-is-accepting-jobs, printer-is-shared,
+printer-make-and-model, printer-state, printer-state-change-time,
+printer-state-reasons, and printer-type attributes as options. CUPS 1.4
+adds the marker-change-time, marker-colors, marker-high-levels,
+marker-levels, marker-low-levels, marker-message, marker-names,
+marker-types, and printer-commands attributes as well.<br>
+<br>
+Use the <a href="#cupsFreeDests"><code>cupsFreeDests</code></a> function to free the destination list and
+the <a href="#cupsGetDest"><code>cupsGetDest</code></a> function to find a particular destination.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.21/Mac OS X 10.4&nbsp;</span><a name="cupsGetDests2">cupsGetDests2</a></h3>
+<p class="description">Get the list of destinations from the specified server.</p>
+<p class="code">
+int cupsGetDests2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_dest_t">cups_dest_t</a> **dests<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>dests</dt>
+<dd class="description">Destinations</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of destinations</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Starting with CUPS 1.2, the returned list of destinations include the
+printer-info, printer-is-accepting-jobs, printer-is-shared,
+printer-make-and-model, printer-state, printer-state-change-time,
+printer-state-reasons, and printer-type attributes as options. CUPS 1.4
+adds the marker-change-time, marker-colors, marker-high-levels,
+marker-levels, marker-low-levels, marker-message, marker-names,
+marker-types, and printer-commands attributes as well.<br>
+<br>
+Use the <a href="#cupsFreeDests"><code>cupsFreeDests</code></a> function to free the destination list and
+the <a href="#cupsGetDest"><code>cupsGetDest</code></a> function to find a particular destination.
+
+</p>
+<h3 class="function"><a name="cupsGetJobs">cupsGetJobs</a></h3>
+<p class="description">Get the jobs from the default server.</p>
+<p class="code">
+int cupsGetJobs (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_job_t">cups_job_t</a> **jobs,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int myjobs,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int whichjobs<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>jobs</dt>
+<dd class="description">Job data</dd>
+<dt>name</dt>
+<dd class="description"><code>NULL</code> = all destinations, otherwise show jobs for named destination</dd>
+<dt>myjobs</dt>
+<dd class="description">0 = all users, 1 = mine</dd>
+<dt>whichjobs</dt>
+<dd class="description"><code>CUPS_WHICHJOBS_ALL</code>, <code>CUPS_WHICHJOBS_ACTIVE</code>, or <code>CUPS_WHICHJOBS_COMPLETED</code></dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of jobs</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">A &quot;whichjobs&quot; value of <code>CUPS_WHICHJOBS_ALL</code> returns all jobs regardless
+of state, while <code>CUPS_WHICHJOBS_ACTIVE</code> returns jobs that are
+pending, processing, or held and <code>CUPS_WHICHJOBS_COMPLETED</code> returns
+jobs that are stopped, canceled, aborted, or completed.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.21/Mac OS X 10.4&nbsp;</span><a name="cupsGetJobs2">cupsGetJobs2</a></h3>
+<p class="description">Get the jobs from the specified server.</p>
+<p class="code">
+int cupsGetJobs2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_job_t">cups_job_t</a> **jobs,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int myjobs,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int whichjobs<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>jobs</dt>
+<dd class="description">Job data</dd>
+<dt>name</dt>
+<dd class="description"><code>NULL</code> = all destinations, otherwise show jobs for named destination</dd>
+<dt>myjobs</dt>
+<dd class="description">0 = all users, 1 = mine</dd>
+<dt>whichjobs</dt>
+<dd class="description"><code>CUPS_WHICHJOBS_ALL</code>, <code>CUPS_WHICHJOBS_ACTIVE</code>, or <code>CUPS_WHICHJOBS_COMPLETED</code></dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of jobs</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">A &quot;whichjobs&quot; value of <code>CUPS_WHICHJOBS_ALL</code> returns all jobs regardless
+of state, while <code>CUPS_WHICHJOBS_ACTIVE</code> returns jobs that are
+pending, processing, or held and <code>CUPS_WHICHJOBS_COMPLETED</code> returns
+jobs that are stopped, canceled, aborted, or completed.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsGetNamedDest">cupsGetNamedDest</a></h3>
+<p class="description">Get options for the named destination.</p>
+<p class="code">
+<a href="#cups_dest_t">cups_dest_t</a> *cupsGetNamedDest (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *instance<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>name</dt>
+<dd class="description">Destination name or <code>NULL</code> for the default destination</dd>
+<dt>instance</dt>
+<dd class="description">Instance name or <code>NULL</code></dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Destination or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is optimized for retrieving a single destination and should
+be used instead of <a href="#cupsGetDests"><code>cupsGetDests</code></a> and <a href="#cupsGetDest"><code>cupsGetDest</code></a> when you either
+know the name of the destination or want to print to the default destination.
+If <code>NULL</code> is returned, the destination does not exist or there is no
+default destination.<br>
+<br>
+If &quot;http&quot; is <code>CUPS_HTTP_DEFAULT</code>, the connection to the default print
+server will be used.<br>
+<br>
+If &quot;name&quot; is <code>NULL</code>, the default printer for the current user will be
+returned.<br>
+<br>
+The returned destination must be freed using <a href="#cupsFreeDests"><code>cupsFreeDests</code></a> with a
+&quot;num_dests&quot; value of 1.
+
+</p>
+<h3 class="function"><a name="cupsGetOption">cupsGetOption</a></h3>
+<p class="description">Get an option value.</p>
+<p class="code">
+const char *cupsGetOption (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_option_t">cups_option_t</a> *options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Name of option</dd>
+<dt>num_options</dt>
+<dd class="description">Number of options</dd>
+<dt>options</dt>
+<dd class="description">Options</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Option value or <code>NULL</code></p>
+<h3 class="function"><a name="cupsGetPPD">cupsGetPPD</a></h3>
+<p class="description">Get the PPD file for a printer on the default server.</p>
+<p class="code">
+const char *cupsGetPPD (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Destination name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Filename for PPD file</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">For classes, <code>cupsGetPPD</code> returns the PPD file for the first printer
+in the class.<br>
+<br>
+The returned filename is stored in a static buffer and is overwritten with
+each call to <code>cupsGetPPD</code> or <a href="#cupsGetPPD2"><code>cupsGetPPD2</code></a>. The caller &quot;owns&quot; the
+file that is created and must <code>unlink</code> the returned filename.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.21/Mac OS X 10.4&nbsp;</span><a name="cupsGetPPD2">cupsGetPPD2</a></h3>
+<p class="description">Get the PPD file for a printer from the specified server.</p>
+<p class="code">
+const char *cupsGetPPD2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>name</dt>
+<dd class="description">Destination name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Filename for PPD file</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">For classes, <code>cupsGetPPD2</code> returns the PPD file for the first printer
+in the class.<br>
+<br>
+The returned filename is stored in a static buffer and is overwritten with
+each call to <a href="#cupsGetPPD"><code>cupsGetPPD</code></a> or <code>cupsGetPPD2</code>. The caller &quot;owns&quot; the
+file that is created and must <code>unlink</code> the returned filename.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsGetPPD3">cupsGetPPD3</a></h3>
+<p class="description">Get the PPD file for a printer on the specified
+server if it has changed.</p>
+<p class="code">
+http_status_t cupsGetPPD3 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;time_t *modtime,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *buffer,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t bufsize<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">HTTP connection or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>name</dt>
+<dd class="description">Destination name</dd>
+<dt>modtime</dt>
+<dd class="description">Modification time</dd>
+<dt>buffer</dt>
+<dd class="description">Filename buffer</dd>
+<dt>bufsize</dt>
+<dd class="description">Size of filename buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">HTTP status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The &quot;modtime&quot; parameter contains the modification time of any
+locally-cached content and is updated with the time from the PPD file on
+the server.<br>
+<br>
+The &quot;buffer&quot; parameter contains the local PPD filename. If it contains
+the empty string, a new temporary file is created, otherwise the existing
+file will be overwritten as needed. The caller &quot;owns&quot; the file that is
+created and must <code>unlink</code> the returned filename.<br>
+<br>
+On success, <code>HTTP_OK</code> is returned for a new PPD file and
+<code>HTTP_NOT_MODIFIED</code> if the existing PPD file is up-to-date. Any other
+status is an error.<br>
+<br>
+For classes, <code>cupsGetPPD3</code> returns the PPD file for the first printer
+in the class.
+
+</p>
+<h3 class="function"><a name="cupsGetPassword">cupsGetPassword</a></h3>
+<p class="description">Get a password from the user.</p>
+<p class="code">
+const char *cupsGetPassword (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *prompt<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>prompt</dt>
+<dd class="description">Prompt string</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Password</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Uses the current password callback function. Returns <code>NULL</code> if the
+user does not provide a password.<br>
+<br>
+Note: The current password callback function is tracked separately for each
+thread in a program. Multi-threaded programs that override the setting via
+the <a href="#cupsSetPasswordCB"><code>cupsSetPasswordCB</code></a> or <a href="#cupsSetPasswordCB2"><code>cupsSetPasswordCB2</code></a> functions need to
+do so in each thread for the same function to be used.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsGetPassword2">cupsGetPassword2</a></h3>
+<p class="description">Get a password from the user using the advanced
+password callback.</p>
+<p class="code">
+const char *cupsGetPassword2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *prompt,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *method,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resource<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>prompt</dt>
+<dd class="description">Prompt string</dd>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>method</dt>
+<dd class="description">Request method (&quot;GET&quot;, &quot;POST&quot;, &quot;PUT&quot;)</dd>
+<dt>resource</dt>
+<dd class="description">Resource path</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Password</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Uses the current password callback function. Returns <code>NULL</code> if the
+user does not provide a password.<br>
+<br>
+Note: The current password callback function is tracked separately for each
+thread in a program. Multi-threaded programs that override the setting via
+the <a href="#cupsSetPasswordCB"><code>cupsSetPasswordCB</code></a> or <a href="#cupsSetPasswordCB2"><code>cupsSetPasswordCB2</code></a> functions need to
+do so in each thread for the same function to be used.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="cupsGetPrinters">cupsGetPrinters</a></h3>
+<p class="description">Get a list of printers from the default server.</p>
+<p class="code">
+int cupsGetPrinters (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char ***printers<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>printers</dt>
+<dd class="description">Printers</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of printers</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is deprecated - use <a href="#cupsGetDests"><code>cupsGetDests</code></a> instead.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="cupsGetServerPPD">cupsGetServerPPD</a></h3>
+<p class="description">Get an available PPD file from the server.</p>
+<p class="code">
+char *cupsGetServerPPD (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>name</dt>
+<dd class="description">Name of PPD file (&quot;ppd-name&quot;)</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Name of PPD file or <code>NULL</code> on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns the named PPD file from the server. The
+list of available PPDs is provided by the IPP <code>CUPS_GET_PPDS</code>
+operation.<br>
+<br>
+You must remove (unlink) the PPD file when you are finished with
+it. The PPD filename is stored in a static location that will be
+overwritten on the next call to <a href="#cupsGetPPD"><code>cupsGetPPD</code></a>, <a href="#cupsGetPPD2"><code>cupsGetPPD2</code></a>,
+or <a href="#cupsGetServerPPD"><code>cupsGetServerPPD</code></a>.
+
+</p>
+<h3 class="function"><a name="cupsLangDefault">cupsLangDefault</a></h3>
+<p class="description">Return the default language.</p>
+<p class="code">
+cups_lang_t *cupsLangDefault (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Language data</p>
+<h3 class="function"><a name="cupsLangEncoding">cupsLangEncoding</a></h3>
+<p class="description">Return the character encoding (us-ascii, etc.)
+for the given language.</p>
+<p class="code">
+const char *cupsLangEncoding (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_lang_t *lang<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>lang</dt>
+<dd class="description">Language data</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Character encoding</p>
+<h3 class="function"><a name="cupsLangFlush">cupsLangFlush</a></h3>
+<p class="description">Flush all language data out of the cache.</p>
+<p class="code">
+void cupsLangFlush (void);</p>
+<h3 class="function"><a name="cupsLangFree">cupsLangFree</a></h3>
+<p class="description">Free language data.</p>
+<p class="code">
+void cupsLangFree (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_lang_t *lang<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>lang</dt>
+<dd class="description">Language to free</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This does not actually free anything; use <a href="#cupsLangFlush"><code>cupsLangFlush</code></a> for that.</p>
+<h3 class="function"><a name="cupsLangGet">cupsLangGet</a></h3>
+<p class="description">Get a language.</p>
+<p class="code">
+cups_lang_t *cupsLangGet (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *language<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>language</dt>
+<dd class="description">Language or locale</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Language data</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsNotifySubject">cupsNotifySubject</a></h3>
+<p class="description">Return the subject for the given notification message.</p>
+<p class="code">
+char *cupsNotifySubject (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_lang_t *lang,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;ipp_t *event<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>lang</dt>
+<dd class="description">Language data</dd>
+<dt>event</dt>
+<dd class="description">Event data</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Subject string or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The returned string must be freed by the caller using <code>free</code>.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsNotifyText">cupsNotifyText</a></h3>
+<p class="description">Return the text for the given notification message.</p>
+<p class="code">
+char *cupsNotifyText (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_lang_t *lang,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;ipp_t *event<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>lang</dt>
+<dd class="description">Language data</dd>
+<dt>event</dt>
+<dd class="description">Event data</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Message text or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The returned string must be freed by the caller using <code>free</code>.
+
+</p>
+<h3 class="function"><a name="cupsParseOptions">cupsParseOptions</a></h3>
+<p class="description">Parse options from a command-line argument.</p>
+<p class="code">
+int cupsParseOptions (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *arg,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_option_t">cups_option_t</a> **options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>arg</dt>
+<dd class="description">Argument to parse</dd>
+<dt>num_options</dt>
+<dd class="description">Number of options</dd>
+<dt>options</dt>
+<dd class="description">Options found</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of options found</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function converts space-delimited name/value pairs according
+to the PAPI text option ABNF specification. Collection values
+(&quot;name={a=... b=... c=...}&quot;) are stored with the curley brackets
+intact - use <code>cupsParseOptions</code> on the value to extract the
+collection attributes.</p>
+<h3 class="function"><a name="cupsPrintFile">cupsPrintFile</a></h3>
+<p class="description">Print a file to a printer or class on the default server.</p>
+<p class="code">
+int cupsPrintFile (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *filename,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *title,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_option_t">cups_option_t</a> *options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Destination name</dd>
+<dt>filename</dt>
+<dd class="description">File to print</dd>
+<dt>title</dt>
+<dd class="description">Title of job</dd>
+<dt>num_options</dt>
+<dd class="description">Number of options</dd>
+<dt>options</dt>
+<dd class="description">Options</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Job ID or 0 on error</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.21/Mac OS X 10.4&nbsp;</span><a name="cupsPrintFile2">cupsPrintFile2</a></h3>
+<p class="description">Print a file to a printer or class on the specified
+server.</p>
+<p class="code">
+int cupsPrintFile2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *filename,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *title,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_option_t">cups_option_t</a> *options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>name</dt>
+<dd class="description">Destination name</dd>
+<dt>filename</dt>
+<dd class="description">File to print</dd>
+<dt>title</dt>
+<dd class="description">Title of job</dd>
+<dt>num_options</dt>
+<dd class="description">Number of options</dd>
+<dt>options</dt>
+<dd class="description">Options</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Job ID or 0 on error</p>
+<h3 class="function"><a name="cupsPrintFiles">cupsPrintFiles</a></h3>
+<p class="description">Print one or more files to a printer or class on the
+default server.</p>
+<p class="code">
+int cupsPrintFiles (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_files,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char **files,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *title,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_option_t">cups_option_t</a> *options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Destination name</dd>
+<dt>num_files</dt>
+<dd class="description">Number of files</dd>
+<dt>files</dt>
+<dd class="description">File(s) to print</dd>
+<dt>title</dt>
+<dd class="description">Title of job</dd>
+<dt>num_options</dt>
+<dd class="description">Number of options</dd>
+<dt>options</dt>
+<dd class="description">Options</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Job ID or 0 on error</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.21/Mac OS X 10.4&nbsp;</span><a name="cupsPrintFiles2">cupsPrintFiles2</a></h3>
+<p class="description">Print one or more files to a printer or class on the
+specified server.</p>
+<p class="code">
+int cupsPrintFiles2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_files,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char **files,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *title,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_option_t">cups_option_t</a> *options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>name</dt>
+<dd class="description">Destination name</dd>
+<dt>num_files</dt>
+<dd class="description">Number of files</dd>
+<dt>files</dt>
+<dd class="description">File(s) to print</dd>
+<dt>title</dt>
+<dd class="description">Title of job</dd>
+<dt>num_options</dt>
+<dd class="description">Number of options</dd>
+<dt>options</dt>
+<dd class="description">Options</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Job ID or 0 on error</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="cupsRemoveDest">cupsRemoveDest</a></h3>
+<p class="description">Remove a destination from the destination list.</p>
+<p class="code">
+int cupsRemoveDest (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *instance,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_dests,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_dest_t">cups_dest_t</a> **dests<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Destination name</dd>
+<dt>instance</dt>
+<dd class="description">Instance name or <code>NULL</code></dd>
+<dt>num_dests</dt>
+<dd class="description">Number of destinations</dd>
+<dt>dests</dt>
+<dd class="description">Destinations</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New number of destinations</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Removing a destination/instance does not delete the class or printer
+queue, merely the lpoptions for that destination/instance. Use the
+<a href="#cupsSetDests"><code>cupsSetDests</code></a> or <a href="#cupsSetDests2"><code>cupsSetDests2</code></a> functions to save the new
+options for the user.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsRemoveOption">cupsRemoveOption</a></h3>
+<p class="description">Remove an option from an option array.</p>
+<p class="code">
+int cupsRemoveOption (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_option_t">cups_option_t</a> **options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Option name</dd>
+<dt>num_options</dt>
+<dd class="description">Current number of options</dd>
+<dt>options</dt>
+<dd class="description">Options</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New number of options</p>
+<h3 class="function"><a name="cupsServer">cupsServer</a></h3>
+<p class="description">Return the hostname/address of the current server.</p>
+<p class="code">
+const char *cupsServer (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Server name</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The default server comes from the CUPS_SERVER environment variable, then the
+~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not
+set, the default is the local system - either &quot;localhost&quot; or a domain socket
+path.<br>
+<br>
+The returned value can be a fully-qualified hostname, a numeric IPv4 or IPv6
+address, or a domain socket pathname.<br>
+<br>
+Note: The current server is tracked separately for each thread in a program.
+Multi-threaded programs that override the server via the
+<a href="#cupsSetServer"><code>cupsSetServer</code></a> function need to do so in each thread for the same
+server to be used.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span><a name="cupsSetClientCertCB">cupsSetClientCertCB</a></h3>
+<p class="description">Set the client certificate callback.</p>
+<p class="code">
+void cupsSetClientCertCB (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_client_cert_cb_t">cups_client_cert_cb_t</a> cb,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *user_data<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cb</dt>
+<dd class="description">Callback function</dd>
+<dt>user_data</dt>
+<dd class="description">User data pointer</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Pass <code>NULL</code> to restore the default callback.<br>
+<br>
+Note: The current certificate callback is tracked separately for each thread
+in a program. Multi-threaded programs that override the callback need to do
+so in each thread for the same callback to be used.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span><a name="cupsSetCredentials">cupsSetCredentials</a></h3>
+<p class="description">Set the default credentials to be used for SSL/TLS
+connections.</p>
+<p class="code">
+int cupsSetCredentials (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_array_t *credentials<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>credentials</dt>
+<dd class="description">Array of credentials</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of call (0 = success)</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Note: The default credentials are tracked separately for each thread in a
+program. Multi-threaded programs that override the setting need to do so in
+each thread for the same setting to be used.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="cupsSetDefaultDest">cupsSetDefaultDest</a></h3>
+<p class="description">Set the default destination.</p>
+<p class="code">
+void cupsSetDefaultDest (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *instance,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_dests,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_dest_t">cups_dest_t</a> *dests<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Destination name</dd>
+<dt>instance</dt>
+<dd class="description">Instance name or <code>NULL</code></dd>
+<dt>num_dests</dt>
+<dd class="description">Number of destinations</dd>
+<dt>dests</dt>
+<dd class="description">Destinations</dd>
+</dl>
+<h3 class="function"><a name="cupsSetDests">cupsSetDests</a></h3>
+<p class="description">Save the list of destinations for the default server.</p>
+<p class="code">
+void cupsSetDests (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_dests,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_dest_t">cups_dest_t</a> *dests<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>num_dests</dt>
+<dd class="description">Number of destinations</dd>
+<dt>dests</dt>
+<dd class="description">Destinations</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function saves the destinations to /etc/cups/lpoptions when run
+as root and ~/.cups/lpoptions when run as a normal user.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.21/Mac OS X 10.4&nbsp;</span><a name="cupsSetDests2">cupsSetDests2</a></h3>
+<p class="description">Save the list of destinations for the specified server.</p>
+<p class="code">
+int cupsSetDests2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_dests,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_dest_t">cups_dest_t</a> *dests<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>num_dests</dt>
+<dd class="description">Number of destinations</dd>
+<dt>dests</dt>
+<dd class="description">Destinations</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function saves the destinations to /etc/cups/lpoptions when run
+as root and ~/.cups/lpoptions when run as a normal user.
+
+</p>
+<h3 class="function"><a name="cupsSetEncryption">cupsSetEncryption</a></h3>
+<p class="description">Set the encryption preference.</p>
+<p class="code">
+void cupsSetEncryption (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_encryption_t e<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>e</dt>
+<dd class="description">New encryption preference</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The default encryption setting comes from the CUPS_ENCRYPTION
+environment variable, then the ~/.cups/client.conf file, and finally the
+/etc/cups/client.conf file. If not set, the default is
+<code>HTTP_ENCRYPT_IF_REQUESTED</code>.<br>
+<br>
+Note: The current encryption setting is tracked separately for each thread
+in a program. Multi-threaded programs that override the setting need to do
+so in each thread for the same setting to be used.</p>
+<h3 class="function"><a name="cupsSetPasswordCB">cupsSetPasswordCB</a></h3>
+<p class="description">Set the password callback for CUPS.</p>
+<p class="code">
+void cupsSetPasswordCB (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_password_cb_t">cups_password_cb_t</a> cb<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cb</dt>
+<dd class="description">Callback function</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Pass <code>NULL</code> to restore the default (console) password callback, which
+reads the password from the console. Programs should call either this
+function or <a href="#cupsSetPasswordCB2"><code>cupsSetPasswordCB2</code></a>, as only one callback can be registered
+by a program per thread.<br>
+<br>
+Note: The current password callback is tracked separately for each thread
+in a program. Multi-threaded programs that override the callback need to do
+so in each thread for the same callback to be used.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsSetPasswordCB2">cupsSetPasswordCB2</a></h3>
+<p class="description">Set the advanced password callback for CUPS.</p>
+<p class="code">
+void cupsSetPasswordCB2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_password_cb2_t">cups_password_cb2_t</a> cb,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *user_data<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cb</dt>
+<dd class="description">Callback function</dd>
+<dt>user_data</dt>
+<dd class="description">User data pointer</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Pass <code>NULL</code> to restore the default (console) password callback, which
+reads the password from the console. Programs should call either this
+function or <a href="#cupsSetPasswordCB2"><code>cupsSetPasswordCB2</code></a>, as only one callback can be registered
+by a program per thread.<br>
+<br>
+Note: The current password callback is tracked separately for each thread
+in a program. Multi-threaded programs that override the callback need to do
+so in each thread for the same callback to be used.
+
+</p>
+<h3 class="function"><a name="cupsSetServer">cupsSetServer</a></h3>
+<p class="description">Set the default server name and port.</p>
+<p class="code">
+void cupsSetServer (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *server<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>server</dt>
+<dd class="description">Server name</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The &quot;server&quot; string can be a fully-qualified hostname, a numeric
+IPv4 or IPv6 address, or a domain socket pathname. Hostnames and numeric IP
+addresses can be optionally followed by a colon and port number to override
+the default port 631, e.g. &quot;hostname:8631&quot;. Pass <code>NULL</code> to restore the
+default server name and port.<br>
+<br>
+Note: The current server is tracked separately for each thread in a program.
+Multi-threaded programs that override the server need to do so in each
+thread for the same server to be used.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span><a name="cupsSetServerCertCB">cupsSetServerCertCB</a></h3>
+<p class="description">Set the server certificate callback.</p>
+<p class="code">
+void cupsSetServerCertCB (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_server_cert_cb_t">cups_server_cert_cb_t</a> cb,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *user_data<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cb</dt>
+<dd class="description">Callback function</dd>
+<dt>user_data</dt>
+<dd class="description">User data pointer</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Pass <code>NULL</code> to restore the default callback.<br>
+<br>
+Note: The current credentials callback is tracked separately for each thread
+in a program. Multi-threaded programs that override the callback need to do
+so in each thread for the same callback to be used.
+
+</p>
+<h3 class="function"><a name="cupsSetUser">cupsSetUser</a></h3>
+<p class="description">Set the default user name.</p>
+<p class="code">
+void cupsSetUser (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *user<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>user</dt>
+<dd class="description">User name</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Pass <code>NULL</code> to restore the default user name.<br>
+<br>
+Note: The current user name is tracked separately for each thread in a
+program. Multi-threaded programs that override the user name need to do so
+in each thread for the same user name to be used.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsStartDocument">cupsStartDocument</a></h3>
+<p class="description">Add a document to a job created with cupsCreateJob().</p>
+<p class="code">
+http_status_t cupsStartDocument (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;http_t *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int job_id,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *docname,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *format,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int last_document<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>name</dt>
+<dd class="description">Destination name</dd>
+<dt>job_id</dt>
+<dd class="description">Job ID from <a href="#cupsCreateJob"><code>cupsCreateJob</code></a></dd>
+<dt>docname</dt>
+<dd class="description">Name of document</dd>
+<dt>format</dt>
+<dd class="description">MIME type or <code>CUPS_FORMAT_foo</code></dd>
+<dt>last_document</dt>
+<dd class="description">1 for last document in job, 0 otherwise</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">HTTP status of request</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Use <a href="#cupsWriteRequestData"><code>cupsWriteRequestData</code></a> to write data for the document and
+<a href="#cupsFinishDocument"><code>cupsFinishDocument</code></a> to finish the document and get the submission status.<br>
+<br>
+The MIME type constants <code>CUPS_FORMAT_AUTO</code>, <code>CUPS_FORMAT_PDF</code>,
+<code>CUPS_FORMAT_POSTSCRIPT</code>, <code>CUPS_FORMAT_RAW</code>, and
+<code>CUPS_FORMAT_TEXT</code> are provided for the &quot;format&quot; argument, although
+any supported MIME type string can be supplied.
+
+</p>
+<h3 class="function"><a name="cupsTempFd">cupsTempFd</a></h3>
+<p class="description">Creates a temporary file.</p>
+<p class="code">
+int cupsTempFd (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *filename,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int len<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>filename</dt>
+<dd class="description">Pointer to buffer</dd>
+<dt>len</dt>
+<dd class="description">Size of buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New file descriptor or -1 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The temporary filename is returned in the filename buffer.
+The temporary file is opened for reading and writing.</p>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="cupsTempFile">cupsTempFile</a></h3>
+<p class="description">Generates a temporary filename.</p>
+<p class="code">
+char *cupsTempFile (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *filename,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int len<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>filename</dt>
+<dd class="description">Pointer to buffer</dd>
+<dt>len</dt>
+<dd class="description">Size of buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Filename or <code>NULL</code> on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The temporary filename is returned in the filename buffer.
+This function is deprecated - use <a href="#cupsTempFd"><code>cupsTempFd</code></a> or
+<a href="#cupsTempFile2"><code>cupsTempFile2</code></a> instead.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsTempFile2">cupsTempFile2</a></h3>
+<p class="description">Creates a temporary CUPS file.</p>
+<p class="code">
+cups_file_t *cupsTempFile2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *filename,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int len<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>filename</dt>
+<dd class="description">Pointer to buffer</dd>
+<dt>len</dt>
+<dd class="description">Size of buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">CUPS file or <code>NULL</code> on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The temporary filename is returned in the filename buffer.
+The temporary file is opened for writing.
+
+</p>
+<h3 class="function"><a name="cupsUser">cupsUser</a></h3>
+<p class="description">Return the current user's name.</p>
+<p class="code">
+const char *cupsUser (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">User name</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Note: The current user name is tracked separately for each thread in a
+program. Multi-threaded programs that override the user name with the
+<a href="#cupsSetUser"><code>cupsSetUser</code></a> function need to do so in each thread for the same user
+name to be used.</p>
+<h2 class="title"><a name="TYPES">Data Types</a></h2>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span><a name="cups_client_cert_cb_t">cups_client_cert_cb_t</a></h3>
+<p class="description">Client credentials callback </p>
+<p class="code">
+typedef int (*cups_client_cert_cb_t)(http_t *http, void *tls, cups_array_t *distinguished_names, void *user_data);
+</p>
+<h3 class="typedef"><a name="cups_dest_t">cups_dest_t</a></h3>
+<p class="description">Destination</p>
+<p class="code">
+typedef struct <a href="#cups_dest_s">cups_dest_s</a> cups_dest_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cups_device_cb_t">cups_device_cb_t</a></h3>
+<p class="description">Device callback </p>
+<p class="code">
+typedef void (*cups_device_cb_t)(const char *device_class, const char *device_id, const char *device_info, const char *device_make_and_model, const char *device_uri, const char *device_location, void *user_data);
+</p>
+<h3 class="typedef"><a name="cups_job_t">cups_job_t</a></h3>
+<p class="description">Job</p>
+<p class="code">
+typedef struct <a href="#cups_job_s">cups_job_s</a> cups_job_t;
+</p>
+<h3 class="typedef"><a name="cups_option_t">cups_option_t</a></h3>
+<p class="description">Printer Options</p>
+<p class="code">
+typedef struct <a href="#cups_option_s">cups_option_s</a> cups_option_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cups_password_cb2_t">cups_password_cb2_t</a></h3>
+<p class="description">New password callback </p>
+<p class="code">
+typedef const char *(*cups_password_cb2_t)(const char *prompt, http_t *http, const char *method, const char *resource, void *user_data);
+</p>
+<h3 class="typedef"><a name="cups_password_cb_t">cups_password_cb_t</a></h3>
+<p class="description">Password callback</p>
+<p class="code">
+typedef const char *(*cups_password_cb_t)(const char *prompt);
+</p>
+<h3 class="typedef"><a name="cups_ptype_t">cups_ptype_t</a></h3>
+<p class="description">Printer type/capability bits</p>
+<p class="code">
+typedef unsigned cups_ptype_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span><a name="cups_server_cert_cb_t">cups_server_cert_cb_t</a></h3>
+<p class="description">Server credentials callback </p>
+<p class="code">
+typedef int (*cups_server_cert_cb_t)(http_t *http, void *tls, cups_array_t *certs, void *user_data);
+</p>
+<h2 class="title"><a name="STRUCTURES">Structures</a></h2>
+<h3 class="struct"><a name="cups_dest_s">cups_dest_s</a></h3>
+<p class="description">Destination</p>
+<p class="code">struct cups_dest_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *name, *instance;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int is_default;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_option_t">cups_option_t</a> *options;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>instance </dt>
+<dd class="description">Local instance name or NULL</dd>
+<dt>is_default </dt>
+<dd class="description">Is this printer the default?</dd>
+<dt>num_options </dt>
+<dd class="description">Number of options</dd>
+<dt>options </dt>
+<dd class="description">Options</dd>
+</dl>
+<h3 class="struct"><a name="cups_job_s">cups_job_s</a></h3>
+<p class="description">Job</p>
+<p class="code">struct cups_job_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;time_t completed_time;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;time_t creation_time;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *dest;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *format;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int id;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int priority;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;time_t processing_time;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int size;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;ipp_jstate_t state;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *title;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *user;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>completed_time </dt>
+<dd class="description">Time the job was completed</dd>
+<dt>creation_time </dt>
+<dd class="description">Time the job was created</dd>
+<dt>dest </dt>
+<dd class="description">Printer or class name</dd>
+<dt>format </dt>
+<dd class="description">Document format</dd>
+<dt>id </dt>
+<dd class="description">The job ID</dd>
+<dt>priority </dt>
+<dd class="description">Priority (1-100)</dd>
+<dt>processing_time </dt>
+<dd class="description">Time the job was processed</dd>
+<dt>size </dt>
+<dd class="description">Size in kilobytes</dd>
+<dt>state </dt>
+<dd class="description">Job state</dd>
+<dt>title </dt>
+<dd class="description">Title/job name</dd>
+<dt>user </dt>
+<dd class="description">User the submitted the job</dd>
+</dl>
+<h3 class="struct"><a name="cups_option_s">cups_option_s</a></h3>
+<p class="description">Printer Options</p>
+<p class="code">struct cups_option_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *name;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *value;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>name </dt>
+<dd class="description">Name of option</dd>
+<dt>value </dt>
+<dd class="description">Value of option</dd>
+</dl>
+<h2 class="title"><a name="VARIABLES">Variables</a></h2>
+<h3 class="variable"><a name="CF_RETURNS_RETAINED">CF_RETURNS_RETAINED</a></h3>
+<p class="description">Get the Apple language identifier associated with a
+locale ID.</p>
+<p class="code">const char *locale) CF_RETURNS_RETAINED;</p>
+<h2 class="title"><a name="ENUMERATIONS">Constants</a></h2>
+<h3 class="enumeration"><a name="cups_ptype_e">cups_ptype_e</a></h3>
+<p class="description">Printer type/capability bit constants</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_PRINTER_AUTHENTICATED <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Printer requires authentication </dd>
+<dt>CUPS_PRINTER_BIND </dt>
+<dd class="description">Can bind output</dd>
+<dt>CUPS_PRINTER_BW </dt>
+<dd class="description">Can do B&amp;W printing</dd>
+<dt>CUPS_PRINTER_CLASS </dt>
+<dd class="description">Printer class</dd>
+<dt>CUPS_PRINTER_COLLATE </dt>
+<dd class="description">Can collage copies</dd>
+<dt>CUPS_PRINTER_COLOR </dt>
+<dd class="description">Can do color printing</dd>
+<dt>CUPS_PRINTER_COMMANDS <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Printer supports maintenance commands </dd>
+<dt>CUPS_PRINTER_COPIES </dt>
+<dd class="description">Can do copies</dd>
+<dt>CUPS_PRINTER_COVER </dt>
+<dd class="description">Can cover output</dd>
+<dt>CUPS_PRINTER_DEFAULT </dt>
+<dd class="description">Default printer on network</dd>
+<dt>CUPS_PRINTER_DELETE <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Delete printer </dd>
+<dt>CUPS_PRINTER_DISCOVERED <span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Printer was automatically discovered and added </dd>
+<dt>CUPS_PRINTER_DUPLEX </dt>
+<dd class="description">Can do duplexing</dd>
+<dt>CUPS_PRINTER_FAX </dt>
+<dd class="description">Fax queue</dd>
+<dt>CUPS_PRINTER_IMPLICIT </dt>
+<dd class="description">Implicit class</dd>
+<dt>CUPS_PRINTER_LARGE </dt>
+<dd class="description">Can do D/E/A1/A0</dd>
+<dt>CUPS_PRINTER_LOCAL </dt>
+<dd class="description">Local printer or class</dd>
+<dt>CUPS_PRINTER_MEDIUM </dt>
+<dd class="description">Can do Tabloid/B/C/A3/A2</dd>
+<dt>CUPS_PRINTER_MFP <span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span></dt>
+<dd class="description">Printer with scanning capabilities </dd>
+<dt>CUPS_PRINTER_NOT_SHARED <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Printer is not shared </dd>
+<dt>CUPS_PRINTER_PUNCH </dt>
+<dd class="description">Can punch output</dd>
+<dt>CUPS_PRINTER_REJECTING </dt>
+<dd class="description">Printer is rejecting jobs</dd>
+<dt>CUPS_PRINTER_REMOTE </dt>
+<dd class="description">Remote printer or class</dd>
+<dt>CUPS_PRINTER_SCANNER <span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span></dt>
+<dd class="description">Scanner-only device </dd>
+<dt>CUPS_PRINTER_SMALL </dt>
+<dd class="description">Can do Letter/Legal/A4</dd>
+<dt>CUPS_PRINTER_SORT </dt>
+<dd class="description">Can sort output</dd>
+<dt>CUPS_PRINTER_STAPLE </dt>
+<dd class="description">Can staple output</dd>
+<dt>CUPS_PRINTER_VARIABLE </dt>
+<dd class="description">Can do variable sizes</dd>
+</dl>
+</div>
+</body>
+</html>
diff --git a/doc/help/api-driver.html b/doc/help/api-driver.html
new file mode 100644
index 000000000..1a3ee3aed
--- /dev/null
+++ b/doc/help/api-driver.html
@@ -0,0 +1,1156 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>Printer Driver API </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: api-driver.html 9740 2011-05-04 06:26:22Z mike $"
+
+ Driver API header for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Driver API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/driver.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcupsdriver</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#OVERVIEW">Overview</a></li>
+<li><a href="#FUNCTIONS">Functions</a><ul class="code">
+ <li><a href="#cupsCMYKDelete" title="Delete a color separation.">cupsCMYKDelete</a></li>
+ <li><a href="#cupsCMYKDoBlack" title="Do a black separation...">cupsCMYKDoBlack</a></li>
+ <li><a href="#cupsCMYKDoCMYK" title="Do a CMYK separation...">cupsCMYKDoCMYK</a></li>
+ <li><a href="#cupsCMYKDoGray" title="Do a grayscale separation...">cupsCMYKDoGray</a></li>
+ <li><a href="#cupsCMYKDoRGB" title="Do an sRGB separation...">cupsCMYKDoRGB</a></li>
+ <li><a href="#cupsCMYKLoad" title="Load a CMYK color profile from PPD attributes.">cupsCMYKLoad</a></li>
+ <li><a href="#cupsCMYKNew" title="Create a new CMYK color separation.">cupsCMYKNew</a></li>
+ <li><a href="#cupsCMYKSetBlack" title="Set the transition range for CMY to black.">cupsCMYKSetBlack</a></li>
+ <li><a href="#cupsCMYKSetCurve" title="Set a color transform curve using points.">cupsCMYKSetCurve</a></li>
+ <li><a href="#cupsCMYKSetGamma" title="Set a color transform curve using gamma and density.">cupsCMYKSetGamma</a></li>
+ <li><a href="#cupsCMYKSetInkLimit" title="Set the limit on the amount of ink.">cupsCMYKSetInkLimit</a></li>
+ <li><a href="#cupsCMYKSetLtDk" title="Set light/dark ink transforms.">cupsCMYKSetLtDk</a></li>
+ <li><a href="#cupsCheckBytes" title="Check to see if all bytes are zero.">cupsCheckBytes</a></li>
+ <li><a href="#cupsCheckValue" title="Check to see if all bytes match the given value.">cupsCheckValue</a></li>
+ <li><a href="#cupsDitherDelete" title="Free a dithering buffer.">cupsDitherDelete</a></li>
+ <li><a href="#cupsDitherLine" title="Dither a line of pixels...">cupsDitherLine</a></li>
+ <li><a href="#cupsDitherNew" title="Create an error-diffusion dithering buffer.">cupsDitherNew</a></li>
+ <li><a href="#cupsFindAttr" title="Find a PPD attribute based on the colormodel,
+media, and resolution.">cupsFindAttr</a></li>
+ <li><a href="#cupsLutDelete" title="Free the memory used by a lookup table.">cupsLutDelete</a></li>
+ <li><a href="#cupsLutLoad" title="Load a LUT from a PPD file.">cupsLutLoad</a></li>
+ <li><a href="#cupsLutNew" title="Make a lookup table from a list of pixel values.">cupsLutNew</a></li>
+ <li><a href="#cupsPackHorizontal" title="Pack pixels horizontally...">cupsPackHorizontal</a></li>
+ <li><a href="#cupsPackHorizontal2" title="Pack 2-bit pixels horizontally...">cupsPackHorizontal2</a></li>
+ <li><a href="#cupsPackHorizontalBit" title="Pack pixels horizontally by bit...">cupsPackHorizontalBit</a></li>
+ <li><a href="#cupsPackVertical" title="Pack pixels vertically...">cupsPackVertical</a></li>
+ <li><a href="#cupsRGBDelete" title="Delete a color separation.">cupsRGBDelete</a></li>
+ <li><a href="#cupsRGBDoGray" title="Do a grayscale separation...">cupsRGBDoGray</a></li>
+ <li><a href="#cupsRGBDoRGB" title="Do a RGB separation...">cupsRGBDoRGB</a></li>
+ <li><a href="#cupsRGBLoad" title="Load a RGB color profile from a PPD file.">cupsRGBLoad</a></li>
+ <li><a href="#cupsRGBNew" title="Create a new RGB color separation.">cupsRGBNew</a></li>
+</ul></li>
+<li><a href="#TYPES">Data Types</a><ul class="code">
+ <li><a href="#cups_cmyk_t" title="Simple CMYK lookup table">cups_cmyk_t</a></li>
+ <li><a href="#cups_dither_t" title="Dithering State">cups_dither_t</a></li>
+ <li><a href="#cups_lut_t" title="Lookup Table for Dithering">cups_lut_t</a></li>
+ <li><a href="#cups_rgb_t" title="Color separation lookup table">cups_rgb_t</a></li>
+ <li><a href="#cups_sample_t" title="Color sample point">cups_sample_t</a></li>
+</ul></li>
+<li><a href="#STRUCTURES">Structures</a><ul class="code">
+ <li><a href="#cups_cmyk_s" title="Simple CMYK lookup table">cups_cmyk_s</a></li>
+ <li><a href="#cups_dither_s" title="Dithering State">cups_dither_s</a></li>
+ <li><a href="#cups_lut_s" title="Lookup Table for Dithering">cups_lut_s</a></li>
+ <li><a href="#cups_rgb_s" title="Color separation lookup table">cups_rgb_s</a></li>
+ <li><a href="#cups_sample_s" title="Color sample point">cups_sample_s</a></li>
+</ul></li>
+<li><a href="#VARIABLES">Variables</a><ul class="code">
+ <li><a href="#cups_scmy_lut[256]" title="sRGB gamma lookup table (inverted)">cups_scmy_lut[256]</a></li>
+ <li><a href="#cups_srgb_lut[256]" title="sRGB gamma lookup table">cups_srgb_lut[256]</a></li>
+</ul></li>
+</ul>
+<!--
+ "$Id: api-driver.html 9740 2011-05-04 06:26:22Z mike $"
+
+ Driver API introduction for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>The driver API provides common dithering, color conversion, and utility
+functions for CUPS drivers.</p>
+<h2 class="title"><a name="FUNCTIONS">Functions</a></h2>
+<h3 class="function"><a name="cupsCMYKDelete">cupsCMYKDelete</a></h3>
+<p class="description">Delete a color separation.</p>
+<p class="code">
+void cupsCMYKDelete (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_cmyk_t">cups_cmyk_t</a> *cmyk<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cmyk</dt>
+<dd class="description">Color separation</dd>
+</dl>
+<h3 class="function"><a name="cupsCMYKDoBlack">cupsCMYKDoBlack</a></h3>
+<p class="description">Do a black separation...</p>
+<p class="code">
+void cupsCMYKDoBlack (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#cups_cmyk_t">cups_cmyk_t</a> *cmyk,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char *input,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;short *output,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_pixels<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cmyk</dt>
+<dd class="description">Color separation</dd>
+<dt>input</dt>
+<dd class="description">Input grayscale pixels</dd>
+<dt>output</dt>
+<dd class="description">Output Device-N pixels</dd>
+<dt>num_pixels</dt>
+<dd class="description">Number of pixels</dd>
+</dl>
+<h3 class="function"><a name="cupsCMYKDoCMYK">cupsCMYKDoCMYK</a></h3>
+<p class="description">Do a CMYK separation...</p>
+<p class="code">
+void cupsCMYKDoCMYK (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#cups_cmyk_t">cups_cmyk_t</a> *cmyk,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char *input,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;short *output,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_pixels<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cmyk</dt>
+<dd class="description">Color separation</dd>
+<dt>input</dt>
+<dd class="description">Input grayscale pixels</dd>
+<dt>output</dt>
+<dd class="description">Output Device-N pixels</dd>
+<dt>num_pixels</dt>
+<dd class="description">Number of pixels</dd>
+</dl>
+<h3 class="function"><a name="cupsCMYKDoGray">cupsCMYKDoGray</a></h3>
+<p class="description">Do a grayscale separation...</p>
+<p class="code">
+void cupsCMYKDoGray (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#cups_cmyk_t">cups_cmyk_t</a> *cmyk,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char *input,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;short *output,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_pixels<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cmyk</dt>
+<dd class="description">Color separation</dd>
+<dt>input</dt>
+<dd class="description">Input grayscale pixels</dd>
+<dt>output</dt>
+<dd class="description">Output Device-N pixels</dd>
+<dt>num_pixels</dt>
+<dd class="description">Number of pixels</dd>
+</dl>
+<h3 class="function"><a name="cupsCMYKDoRGB">cupsCMYKDoRGB</a></h3>
+<p class="description">Do an sRGB separation...</p>
+<p class="code">
+void cupsCMYKDoRGB (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#cups_cmyk_t">cups_cmyk_t</a> *cmyk,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char *input,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;short *output,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_pixels<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cmyk</dt>
+<dd class="description">Color separation</dd>
+<dt>input</dt>
+<dd class="description">Input grayscale pixels</dd>
+<dt>output</dt>
+<dd class="description">Output Device-N pixels</dd>
+<dt>num_pixels</dt>
+<dd class="description">Number of pixels</dd>
+</dl>
+<h3 class="function"><a name="cupsCMYKLoad">cupsCMYKLoad</a></h3>
+<p class="description">Load a CMYK color profile from PPD attributes.</p>
+<p class="code">
+<a href="#cups_cmyk_t">cups_cmyk_t</a> *cupsCMYKLoad (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;ppd_file_t *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *colormodel,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *media,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resolution<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>colormodel</dt>
+<dd class="description">ColorModel value</dd>
+<dt>media</dt>
+<dd class="description">MediaType value</dd>
+<dt>resolution</dt>
+<dd class="description">Resolution value</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">CMYK color separation</p>
+<h3 class="function"><a name="cupsCMYKNew">cupsCMYKNew</a></h3>
+<p class="description">Create a new CMYK color separation.</p>
+<p class="code">
+<a href="#cups_cmyk_t">cups_cmyk_t</a> *cupsCMYKNew (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_channels<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>num_channels</dt>
+<dd class="description">Number of color components</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New CMYK separation or NULL</p>
+<h3 class="function"><a name="cupsCMYKSetBlack">cupsCMYKSetBlack</a></h3>
+<p class="description">Set the transition range for CMY to black.</p>
+<p class="code">
+void cupsCMYKSetBlack (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_cmyk_t">cups_cmyk_t</a> *cmyk,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float lower,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float upper<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cmyk</dt>
+<dd class="description">CMYK color separation</dd>
+<dt>lower</dt>
+<dd class="description">No black ink</dd>
+<dt>upper</dt>
+<dd class="description">Only black ink</dd>
+</dl>
+<h3 class="function"><a name="cupsCMYKSetCurve">cupsCMYKSetCurve</a></h3>
+<p class="description">Set a color transform curve using points.</p>
+<p class="code">
+void cupsCMYKSetCurve (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_cmyk_t">cups_cmyk_t</a> *cmyk,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int channel,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_xypoints,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const float *xypoints<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cmyk</dt>
+<dd class="description">CMYK color separation</dd>
+<dt>channel</dt>
+<dd class="description">Color channel</dd>
+<dt>num_xypoints</dt>
+<dd class="description">Number of X,Y points</dd>
+<dt>xypoints</dt>
+<dd class="description">X,Y points</dd>
+</dl>
+<h3 class="function"><a name="cupsCMYKSetGamma">cupsCMYKSetGamma</a></h3>
+<p class="description">Set a color transform curve using gamma and density.</p>
+<p class="code">
+void cupsCMYKSetGamma (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_cmyk_t">cups_cmyk_t</a> *cmyk,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int channel,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float gamval,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float density<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cmyk</dt>
+<dd class="description">CMYK color separation</dd>
+<dt>channel</dt>
+<dd class="description">Ink channel</dd>
+<dt>gamval</dt>
+<dd class="description">Gamma correction</dd>
+<dt>density</dt>
+<dd class="description">Maximum density</dd>
+</dl>
+<h3 class="function"><a name="cupsCMYKSetInkLimit">cupsCMYKSetInkLimit</a></h3>
+<p class="description">Set the limit on the amount of ink.</p>
+<p class="code">
+void cupsCMYKSetInkLimit (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_cmyk_t">cups_cmyk_t</a> *cmyk,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float limit<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cmyk</dt>
+<dd class="description">CMYK color separation</dd>
+<dt>limit</dt>
+<dd class="description">Limit of ink</dd>
+</dl>
+<h3 class="function"><a name="cupsCMYKSetLtDk">cupsCMYKSetLtDk</a></h3>
+<p class="description">Set light/dark ink transforms.</p>
+<p class="code">
+void cupsCMYKSetLtDk (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_cmyk_t">cups_cmyk_t</a> *cmyk,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int channel,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float light,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float dark<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cmyk</dt>
+<dd class="description">CMYK color separation</dd>
+<dt>channel</dt>
+<dd class="description">Dark ink channel (+1 for light)</dd>
+<dt>light</dt>
+<dd class="description">Light ink only level</dd>
+<dt>dark</dt>
+<dd class="description">Dark ink only level</dd>
+</dl>
+<h3 class="function"><a name="cupsCheckBytes">cupsCheckBytes</a></h3>
+<p class="description">Check to see if all bytes are zero.</p>
+<p class="code">
+int cupsCheckBytes (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char *bytes,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int length<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>bytes</dt>
+<dd class="description">Bytes to check</dd>
+<dt>length</dt>
+<dd class="description">Number of bytes to check</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if they match</p>
+<h3 class="function"><a name="cupsCheckValue">cupsCheckValue</a></h3>
+<p class="description">Check to see if all bytes match the given value.</p>
+<p class="code">
+int cupsCheckValue (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char *bytes,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int length,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char value<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>bytes</dt>
+<dd class="description">Bytes to check</dd>
+<dt>length</dt>
+<dd class="description">Number of bytes to check</dd>
+<dt>value</dt>
+<dd class="description">Value to check</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if they match</p>
+<h3 class="function"><a name="cupsDitherDelete">cupsDitherDelete</a></h3>
+<p class="description">Free a dithering buffer.</p>
+<p class="code">
+void cupsDitherDelete (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_dither_t">cups_dither_t</a> *d<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>d</dt>
+<dd class="description">Dithering buffer</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Returns 0 on success, -1 on failure.</p>
+<h3 class="function"><a name="cupsDitherLine">cupsDitherLine</a></h3>
+<p class="description">Dither a line of pixels...</p>
+<p class="code">
+void cupsDitherLine (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_dither_t">cups_dither_t</a> *d,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#cups_lut_t">cups_lut_t</a> *lut,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const short *data,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_channels,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char *p<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>d</dt>
+<dd class="description">Dither data</dd>
+<dt>lut</dt>
+<dd class="description">Lookup table</dd>
+<dt>data</dt>
+<dd class="description">Separation data</dd>
+<dt>num_channels</dt>
+<dd class="description">Number of components</dd>
+<dt>p</dt>
+<dd class="description">Pixels</dd>
+</dl>
+<h3 class="function"><a name="cupsDitherNew">cupsDitherNew</a></h3>
+<p class="description">Create an error-diffusion dithering buffer.</p>
+<p class="code">
+<a href="#cups_dither_t">cups_dither_t</a> *cupsDitherNew (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int width<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>width</dt>
+<dd class="description">Width of output in pixels</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New state array</p>
+<h3 class="function"><a name="cupsFindAttr">cupsFindAttr</a></h3>
+<p class="description">Find a PPD attribute based on the colormodel,
+media, and resolution.</p>
+<p class="code">
+ppd_attr_t *cupsFindAttr (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;ppd_file_t *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *colormodel,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *media,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resolution,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *spec,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int specsize<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>name</dt>
+<dd class="description">Attribute name</dd>
+<dt>colormodel</dt>
+<dd class="description">Color model</dd>
+<dt>media</dt>
+<dd class="description">Media type</dd>
+<dt>resolution</dt>
+<dd class="description">Resolution</dd>
+<dt>spec</dt>
+<dd class="description">Final selection string</dd>
+<dt>specsize</dt>
+<dd class="description">Size of string buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Matching attribute or NULL</p>
+<h3 class="function"><a name="cupsLutDelete">cupsLutDelete</a></h3>
+<p class="description">Free the memory used by a lookup table.</p>
+<p class="code">
+void cupsLutDelete (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_lut_t">cups_lut_t</a> *lut<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>lut</dt>
+<dd class="description">Lookup table to free</dd>
+</dl>
+<h3 class="function"><a name="cupsLutLoad">cupsLutLoad</a></h3>
+<p class="description">Load a LUT from a PPD file.</p>
+<p class="code">
+<a href="#cups_lut_t">cups_lut_t</a> *cupsLutLoad (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;ppd_file_t *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *colormodel,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *media,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resolution,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *ink<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>colormodel</dt>
+<dd class="description">Color model</dd>
+<dt>media</dt>
+<dd class="description">Media type</dd>
+<dt>resolution</dt>
+<dd class="description">Resolution</dd>
+<dt>ink</dt>
+<dd class="description">Ink name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New lookup table</p>
+<h3 class="function"><a name="cupsLutNew">cupsLutNew</a></h3>
+<p class="description">Make a lookup table from a list of pixel values.</p>
+<p class="code">
+<a href="#cups_lut_t">cups_lut_t</a> *cupsLutNew (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_values,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const float *values<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>num_values</dt>
+<dd class="description">Number of values</dd>
+<dt>values</dt>
+<dd class="description">Lookup table values</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New lookup table</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Returns a pointer to the lookup table on success, NULL on failure.</p>
+<h3 class="function"><a name="cupsPackHorizontal">cupsPackHorizontal</a></h3>
+<p class="description">Pack pixels horizontally...</p>
+<p class="code">
+void cupsPackHorizontal (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char *ipixels,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char *obytes,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int width,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char clearto,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const int step<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipixels</dt>
+<dd class="description">Input pixels</dd>
+<dt>obytes</dt>
+<dd class="description">Output bytes</dd>
+<dt>width</dt>
+<dd class="description">Number of pixels</dd>
+<dt>clearto</dt>
+<dd class="description">Initial value of bytes</dd>
+<dt>step</dt>
+<dd class="description">Step value between pixels</dd>
+</dl>
+<h3 class="function"><a name="cupsPackHorizontal2">cupsPackHorizontal2</a></h3>
+<p class="description">Pack 2-bit pixels horizontally...</p>
+<p class="code">
+void cupsPackHorizontal2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char *ipixels,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char *obytes,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int width,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const int step<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipixels</dt>
+<dd class="description">Input pixels</dd>
+<dt>obytes</dt>
+<dd class="description">Output bytes</dd>
+<dt>width</dt>
+<dd class="description">Number of pixels</dd>
+<dt>step</dt>
+<dd class="description">Stepping value</dd>
+</dl>
+<h3 class="function"><a name="cupsPackHorizontalBit">cupsPackHorizontalBit</a></h3>
+<p class="description">Pack pixels horizontally by bit...</p>
+<p class="code">
+void cupsPackHorizontalBit (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char *ipixels,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char *obytes,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int width,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char clearto,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char bit<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipixels</dt>
+<dd class="description">Input pixels</dd>
+<dt>obytes</dt>
+<dd class="description">Output bytes</dd>
+<dt>width</dt>
+<dd class="description">Number of pixels</dd>
+<dt>clearto</dt>
+<dd class="description">Initial value of bytes</dd>
+<dt>bit</dt>
+<dd class="description">Bit to check</dd>
+</dl>
+<h3 class="function"><a name="cupsPackVertical">cupsPackVertical</a></h3>
+<p class="description">Pack pixels vertically...</p>
+<p class="code">
+void cupsPackVertical (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char *ipixels,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char *obytes,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int width,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char bit,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const int step<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipixels</dt>
+<dd class="description">Input pixels</dd>
+<dt>obytes</dt>
+<dd class="description">Output bytes</dd>
+<dt>width</dt>
+<dd class="description">Number of input pixels</dd>
+<dt>bit</dt>
+<dd class="description">Output bit</dd>
+<dt>step</dt>
+<dd class="description">Number of bytes between columns</dd>
+</dl>
+<h3 class="function"><a name="cupsRGBDelete">cupsRGBDelete</a></h3>
+<p class="description">Delete a color separation.</p>
+<p class="code">
+void cupsRGBDelete (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_rgb_t">cups_rgb_t</a> *rgbptr<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>rgbptr</dt>
+<dd class="description">Color separation</dd>
+</dl>
+<h3 class="function"><a name="cupsRGBDoGray">cupsRGBDoGray</a></h3>
+<p class="description">Do a grayscale separation...</p>
+<p class="code">
+void cupsRGBDoGray (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_rgb_t">cups_rgb_t</a> *rgbptr,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char *input,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char *output,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_pixels<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>rgbptr</dt>
+<dd class="description">Color separation</dd>
+<dt>input</dt>
+<dd class="description">Input grayscale pixels</dd>
+<dt>output</dt>
+<dd class="description">Output Device-N pixels</dd>
+<dt>num_pixels</dt>
+<dd class="description">Number of pixels</dd>
+</dl>
+<h3 class="function"><a name="cupsRGBDoRGB">cupsRGBDoRGB</a></h3>
+<p class="description">Do a RGB separation...</p>
+<p class="code">
+void cupsRGBDoRGB (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_rgb_t">cups_rgb_t</a> *rgbptr,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char *input,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char *output,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_pixels<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>rgbptr</dt>
+<dd class="description">Color separation</dd>
+<dt>input</dt>
+<dd class="description">Input RGB pixels</dd>
+<dt>output</dt>
+<dd class="description">Output Device-N pixels</dd>
+<dt>num_pixels</dt>
+<dd class="description">Number of pixels</dd>
+</dl>
+<h3 class="function"><a name="cupsRGBLoad">cupsRGBLoad</a></h3>
+<p class="description">Load a RGB color profile from a PPD file.</p>
+<p class="code">
+<a href="#cups_rgb_t">cups_rgb_t</a> *cupsRGBLoad (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;ppd_file_t *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *colormodel,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *media,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resolution<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>colormodel</dt>
+<dd class="description">Color model</dd>
+<dt>media</dt>
+<dd class="description">Media type</dd>
+<dt>resolution</dt>
+<dd class="description">Resolution</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New color profile</p>
+<h3 class="function"><a name="cupsRGBNew">cupsRGBNew</a></h3>
+<p class="description">Create a new RGB color separation.</p>
+<p class="code">
+<a href="#cups_rgb_t">cups_rgb_t</a> *cupsRGBNew (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_samples,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_sample_t">cups_sample_t</a> *samples,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int cube_size,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_channels<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>num_samples</dt>
+<dd class="description">Number of samples</dd>
+<dt>samples</dt>
+<dd class="description">Samples</dd>
+<dt>cube_size</dt>
+<dd class="description">Size of LUT cube</dd>
+<dt>num_channels</dt>
+<dd class="description">Number of color components</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New color separation or NULL</p>
+<h2 class="title"><a name="TYPES">Data Types</a></h2>
+<h3 class="typedef"><a name="cups_cmyk_t">cups_cmyk_t</a></h3>
+<p class="description">Simple CMYK lookup table</p>
+<p class="code">
+typedef struct <a href="#cups_cmyk_s">cups_cmyk_s</a> cups_cmyk_t;
+</p>
+<h3 class="typedef"><a name="cups_dither_t">cups_dither_t</a></h3>
+<p class="description">Dithering State</p>
+<p class="code">
+typedef struct <a href="#cups_dither_s">cups_dither_s</a> cups_dither_t;
+</p>
+<h3 class="typedef"><a name="cups_lut_t">cups_lut_t</a></h3>
+<p class="description">Lookup Table for Dithering</p>
+<p class="code">
+typedef struct <a href="#cups_lut_s">cups_lut_s</a> cups_lut_t;
+</p>
+<h3 class="typedef"><a name="cups_rgb_t">cups_rgb_t</a></h3>
+<p class="description">Color separation lookup table</p>
+<p class="code">
+typedef struct <a href="#cups_rgb_s">cups_rgb_s</a> cups_rgb_t;
+</p>
+<h3 class="typedef"><a name="cups_sample_t">cups_sample_t</a></h3>
+<p class="description">Color sample point</p>
+<p class="code">
+typedef struct <a href="#cups_sample_s">cups_sample_s</a> cups_sample_t;
+</p>
+<h2 class="title"><a name="STRUCTURES">Structures</a></h2>
+<h3 class="struct"><a name="cups_cmyk_s">cups_cmyk_s</a></h3>
+<p class="description">Simple CMYK lookup table</p>
+<p class="code">struct cups_cmyk_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char black_lut[256];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;short *channels[CUPS_MAX_CHAN];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char color_lut[256];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int ink_limit;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_channels;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>black_lut[256] </dt>
+<dd class="description">Black generation LUT</dd>
+<dt>channels[CUPS_MAX_CHAN] </dt>
+<dd class="description">Lookup tables</dd>
+<dt>color_lut[256] </dt>
+<dd class="description">Color removal LUT</dd>
+<dt>ink_limit </dt>
+<dd class="description">Ink limit</dd>
+<dt>num_channels </dt>
+<dd class="description">Number of components</dd>
+</dl>
+<h3 class="struct"><a name="cups_dither_s">cups_dither_s</a></h3>
+<p class="description">Dithering State</p>
+<p class="code">struct cups_dither_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int errors[96];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int row;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int width;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>errors[96] </dt>
+<dd class="description">Error values</dd>
+<dt>row </dt>
+<dd class="description">Current row</dd>
+<dt>width </dt>
+<dd class="description">Width of buffer</dd>
+</dl>
+<h3 class="struct"><a name="cups_lut_s">cups_lut_s</a></h3>
+<p class="description">Lookup Table for Dithering</p>
+<p class="code">struct cups_lut_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int error;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;short intensity;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;short pixel;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>error </dt>
+<dd class="description">Error from desired value</dd>
+<dt>intensity </dt>
+<dd class="description">Adjusted intensity</dd>
+<dt>pixel </dt>
+<dd class="description">Output pixel value</dd>
+</dl>
+<h3 class="struct"><a name="cups_rgb_s">cups_rgb_s</a></h3>
+<p class="description">Color separation lookup table</p>
+<p class="code">struct cups_rgb_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char black[CUPS_MAX_RGB];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int cache_init;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char ****colors;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int cube_index[256];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int cube_mult[256];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int cube_size;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_channels;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char white[CUPS_MAX_RGB];<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>black[CUPS_MAX_RGB] </dt>
+<dd class="description">Cached black (sRGB = 0,0,0)</dd>
+<dt>cache_init </dt>
+<dd class="description">Are cached values initialized?</dd>
+<dt>colors </dt>
+<dd class="description">4-D array of sample values</dd>
+<dt>cube_index[256] </dt>
+<dd class="description">Index into cube for a given sRGB value</dd>
+<dt>cube_mult[256] </dt>
+<dd class="description">Multiplier value for a given sRGB value</dd>
+<dt>cube_size </dt>
+<dd class="description">Size of color cube (2-N) on a side</dd>
+<dt>num_channels </dt>
+<dd class="description">Number of colors per sample</dd>
+<dt>white[CUPS_MAX_RGB] </dt>
+<dd class="description">Cached white (sRGB = 255,255,255)</dd>
+</dl>
+<h3 class="struct"><a name="cups_sample_s">cups_sample_s</a></h3>
+<p class="description">Color sample point</p>
+<p class="code">struct cups_sample_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char colors[CUPS_MAX_RGB];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char rgb[3];<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>colors[CUPS_MAX_RGB] </dt>
+<dd class="description">Color values</dd>
+<dt>rgb[3] </dt>
+<dd class="description">sRGB values</dd>
+</dl>
+<h2 class="title"><a name="VARIABLES">Variables</a></h2>
+<h3 class="variable"><a name="cups_scmy_lut[256]">cups_scmy_lut[256]</a></h3>
+<p class="description">sRGB gamma lookup table (inverted)</p>
+<p class="code">extern const unsigned char cups_scmy_lut[256];</p>
+<h3 class="variable"><a name="cups_srgb_lut[256]">cups_srgb_lut[256]</a></h3>
+<p class="description">sRGB gamma lookup table</p>
+<p class="code">extern const unsigned char cups_srgb_lut[256];</p>
+</div>
+</body>
+</html>
diff --git a/doc/help/api-filedir.html b/doc/help/api-filedir.html
new file mode 100644
index 000000000..430494a75
--- /dev/null
+++ b/doc/help/api-filedir.html
@@ -0,0 +1,995 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>File and Directory APIs </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: api-filedir.html 9772 2011-05-12 05:46:30Z mike $"
+
+ File and Directory API header for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>File and Directory APIs</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Headers</th>
+ <th>cups/file.h<br>
+ cups/dir.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcups</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a><br>
+ Programming: <a href='api-cups.html' target='_top'>CUPS API</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#OVERVIEW">Overview</a></li>
+<li><a href="#FUNCTIONS">Functions</a><ul class="code">
+ <li><a href="#cupsDirClose" title="Close a directory.">cupsDirClose</a></li>
+ <li><a href="#cupsDirOpen" title="Open a directory.">cupsDirOpen</a></li>
+ <li><a href="#cupsDirRead" title="Read the next directory entry.">cupsDirRead</a></li>
+ <li><a href="#cupsDirRewind" title="Rewind to the start of the directory.">cupsDirRewind</a></li>
+ <li><a href="#cupsFileClose" title="Close a CUPS file.">cupsFileClose</a></li>
+ <li><a href="#cupsFileCompression" title="Return whether a file is compressed.">cupsFileCompression</a></li>
+ <li><a href="#cupsFileEOF" title="Return the end-of-file status.">cupsFileEOF</a></li>
+ <li><a href="#cupsFileFind" title="Find a file using the specified path.">cupsFileFind</a></li>
+ <li><a href="#cupsFileFlush" title="Flush pending output.">cupsFileFlush</a></li>
+ <li><a href="#cupsFileGetChar" title="Get a single character from a file.">cupsFileGetChar</a></li>
+ <li><a href="#cupsFileGetConf" title="Get a line from a configuration file.">cupsFileGetConf</a></li>
+ <li><a href="#cupsFileGetLine" title="Get a CR and/or LF-terminated line that may
+contain binary data.">cupsFileGetLine</a></li>
+ <li><a href="#cupsFileGets" title="Get a CR and/or LF-terminated line.">cupsFileGets</a></li>
+ <li><a href="#cupsFileLock" title="Temporarily lock access to a file.">cupsFileLock</a></li>
+ <li><a href="#cupsFileNumber" title="Return the file descriptor associated with a CUPS file.">cupsFileNumber</a></li>
+ <li><a href="#cupsFileOpen" title="Open a CUPS file.">cupsFileOpen</a></li>
+ <li><a href="#cupsFileOpenFd" title="Open a CUPS file using a file descriptor.">cupsFileOpenFd</a></li>
+ <li><a href="#cupsFilePeekChar" title="Peek at the next character from a file.">cupsFilePeekChar</a></li>
+ <li><a href="#cupsFilePrintf" title="Write a formatted string.">cupsFilePrintf</a></li>
+ <li><a href="#cupsFilePutChar" title="Write a character.">cupsFilePutChar</a></li>
+ <li><a href="#cupsFilePutConf" title="Write a configuration line.">cupsFilePutConf</a></li>
+ <li><a href="#cupsFilePuts" title="Write a string.">cupsFilePuts</a></li>
+ <li><a href="#cupsFileRead" title="Read from a file.">cupsFileRead</a></li>
+ <li><a href="#cupsFileRewind" title="Set the current file position to the beginning of the
+file.">cupsFileRewind</a></li>
+ <li><a href="#cupsFileSeek" title="Seek in a file.">cupsFileSeek</a></li>
+ <li><a href="#cupsFileStderr" title="Return a CUPS file associated with stderr.">cupsFileStderr</a></li>
+ <li><a href="#cupsFileStdin" title="Return a CUPS file associated with stdin.">cupsFileStdin</a></li>
+ <li><a href="#cupsFileStdout" title="Return a CUPS file associated with stdout.">cupsFileStdout</a></li>
+ <li><a href="#cupsFileTell" title="Return the current file position.">cupsFileTell</a></li>
+ <li><a href="#cupsFileUnlock" title="Unlock access to a file.">cupsFileUnlock</a></li>
+ <li><a href="#cupsFileWrite" title="Write to a file.">cupsFileWrite</a></li>
+</ul></li>
+<li><a href="#TYPES">Data Types</a><ul class="code">
+ <li><a href="#cups_dentry_t" title="Directory entry type">cups_dentry_t</a></li>
+ <li><a href="#cups_dir_t" title="Directory type">cups_dir_t</a></li>
+ <li><a href="#cups_file_t" title="CUPS file type">cups_file_t</a></li>
+</ul></li>
+<li><a href="#STRUCTURES">Structures</a><ul class="code">
+ <li><a href="#cups_dentry_s" title="Directory entry type">cups_dentry_s</a></li>
+</ul></li>
+</ul>
+<!--
+ "$Id: api-filedir.html 9772 2011-05-12 05:46:30Z mike $"
+
+ File and directory API introduction for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2005 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name="OVERVIEW">Overview</a></h2>
+
+<p>The CUPS file and directory APIs provide portable interfaces
+for manipulating files and listing files and directories. Unlike
+stdio <code>FILE</code> streams, the <code>cupsFile</code> 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
+<code>cupsFile</code> functions.</p>
+
+<p>The <code>cupsDir</code> 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.</p>
+<h2 class="title"><a name="FUNCTIONS">Functions</a></h2>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsDirClose">cupsDirClose</a></h3>
+<p class="description">Close a directory.</p>
+<p class="code">
+void cupsDirClose (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_dir_t">cups_dir_t</a> *dp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>dp</dt>
+<dd class="description">Directory pointer</dd>
+</dl>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsDirOpen">cupsDirOpen</a></h3>
+<p class="description">Open a directory.</p>
+<p class="code">
+<a href="#cups_dir_t">cups_dir_t</a> *cupsDirOpen (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *directory<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>directory</dt>
+<dd class="description">Directory name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Directory pointer or <code>NULL</code> if the directory could not be opened.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsDirRead">cupsDirRead</a></h3>
+<p class="description">Read the next directory entry.</p>
+<p class="code">
+<a href="#cups_dentry_t">cups_dentry_t</a> *cupsDirRead (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_dir_t">cups_dir_t</a> *dp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>dp</dt>
+<dd class="description">Directory pointer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Directory entry or <code>NULL</code> when there are no more</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsDirRewind">cupsDirRewind</a></h3>
+<p class="description">Rewind to the start of the directory.</p>
+<p class="code">
+void cupsDirRewind (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_dir_t">cups_dir_t</a> *dp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>dp</dt>
+<dd class="description">Directory pointer</dd>
+</dl>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileClose">cupsFileClose</a></h3>
+<p class="description">Close a CUPS file.</p>
+<p class="code">
+int cupsFileClose (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileCompression">cupsFileCompression</a></h3>
+<p class="description">Return whether a file is compressed.</p>
+<p class="code">
+int cupsFileCompression (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description"><code>CUPS_FILE_NONE</code> or <code>CUPS_FILE_GZIP</code></p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileEOF">cupsFileEOF</a></h3>
+<p class="description">Return the end-of-file status.</p>
+<p class="code">
+int cupsFileEOF (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 on end of file, 0 otherwise</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileFind">cupsFileFind</a></h3>
+<p class="description">Find a file using the specified path.</p>
+<p class="code">
+const char *cupsFileFind (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *filename,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *path,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int executable,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *buffer,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int bufsize<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>filename</dt>
+<dd class="description">File to find</dd>
+<dt>path</dt>
+<dd class="description">Colon/semicolon-separated path</dd>
+<dt>executable</dt>
+<dd class="description">1 = executable files, 0 = any file/dir</dd>
+<dt>buffer</dt>
+<dd class="description">Filename buffer</dd>
+<dt>bufsize</dt>
+<dd class="description">Size of filename buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Full path to file or <code>NULL</code> if not found</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function allows the paths in the path string to be separated by
+colons (UNIX standard) or semicolons (Windows standard) and stores the
+result in the buffer supplied. If the file cannot be found in any of
+the supplied paths, <code>NULL</code> is returned. A <code>NULL</code> path only
+matches the current directory.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileFlush">cupsFileFlush</a></h3>
+<p class="description">Flush pending output.</p>
+<p class="code">
+int cupsFileFlush (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileGetChar">cupsFileGetChar</a></h3>
+<p class="description">Get a single character from a file.</p>
+<p class="code">
+int cupsFileGetChar (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Character or -1 on end of file</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileGetConf">cupsFileGetConf</a></h3>
+<p class="description">Get a line from a configuration file.</p>
+<p class="code">
+char *cupsFileGetConf (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *buf,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t buflen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char **value,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *linenum<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+<dt>buf</dt>
+<dd class="description">String buffer</dd>
+<dt>buflen</dt>
+<dd class="description">Size of string buffer</dd>
+<dt>value</dt>
+<dd class="description">Pointer to value</dd>
+<dt>linenum</dt>
+<dd class="description">Current line number</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Line read or <code>NULL</code> on end of file or error</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileGetLine">cupsFileGetLine</a></h3>
+<p class="description">Get a CR and/or LF-terminated line that may
+contain binary data.</p>
+<p class="code">
+size_t cupsFileGetLine (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *buf,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t buflen<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read from</dd>
+<dt>buf</dt>
+<dd class="description">Buffer</dd>
+<dt>buflen</dt>
+<dd class="description">Size of buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of bytes on line or 0 on end of file</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function differs from <a href="#cupsFileGets"><code>cupsFileGets</code></a> in that the trailing CR
+and LF are preserved, as is any binary data on the line. The buffer is
+nul-terminated, however you should use the returned length to determine
+the number of bytes on the line.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileGets">cupsFileGets</a></h3>
+<p class="description">Get a CR and/or LF-terminated line.</p>
+<p class="code">
+char *cupsFileGets (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *buf,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t buflen<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+<dt>buf</dt>
+<dd class="description">String buffer</dd>
+<dt>buflen</dt>
+<dd class="description">Size of string buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Line read or <code>NULL</code> on end of file or error</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileLock">cupsFileLock</a></h3>
+<p class="description">Temporarily lock access to a file.</p>
+<p class="code">
+int cupsFileLock (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int block<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+<dt>block</dt>
+<dd class="description">1 to wait for the lock, 0 to fail right away</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileNumber">cupsFileNumber</a></h3>
+<p class="description">Return the file descriptor associated with a CUPS file.</p>
+<p class="code">
+int cupsFileNumber (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">File descriptor</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileOpen">cupsFileOpen</a></h3>
+<p class="description">Open a CUPS file.</p>
+<p class="code">
+<a href="#cups_file_t">cups_file_t</a> *cupsFileOpen (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *filename,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *mode<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>filename</dt>
+<dd class="description">Name of file</dd>
+<dt>mode</dt>
+<dd class="description">Open mode</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">CUPS file or <code>NULL</code> if the file or socket cannot be opened</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The &quot;mode&quot; parameter can be &quot;r&quot; to read, &quot;w&quot; to write, overwriting any
+existing file, &quot;a&quot; to append to an existing file or create a new file,
+or &quot;s&quot; to open a socket connection.<br>
+<br>
+When opening for writing (&quot;w&quot;), an optional number from 1 to 9 can be
+supplied which enables Flate compression of the file. Compression is
+not supported for the &quot;a&quot; (append) mode.<br>
+<br>
+When opening a socket connection, the filename is a string of the form
+&quot;address:port&quot; or &quot;hostname:port&quot;. The socket will make an IPv4 or IPv6
+connection as needed, generally preferring IPv6 connections when there is
+a choice.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileOpenFd">cupsFileOpenFd</a></h3>
+<p class="description">Open a CUPS file using a file descriptor.</p>
+<p class="code">
+<a href="#cups_file_t">cups_file_t</a> *cupsFileOpenFd (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int fd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *mode<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fd</dt>
+<dd class="description">File descriptor</dd>
+<dt>mode</dt>
+<dd class="description">Open mode</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">CUPS file or <code>NULL</code> if the file could not be opened</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The &quot;mode&quot; parameter can be &quot;r&quot; to read, &quot;w&quot; to write, &quot;a&quot; to append,
+or &quot;s&quot; to treat the file descriptor as a bidirectional socket connection.<br>
+<br>
+When opening for writing (&quot;w&quot;), an optional number from 1 to 9 can be
+supplied which enables Flate compression of the file. Compression is
+not supported for the &quot;a&quot; (append) mode.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFilePeekChar">cupsFilePeekChar</a></h3>
+<p class="description">Peek at the next character from a file.</p>
+<p class="code">
+int cupsFilePeekChar (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Character or -1 on end of file</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFilePrintf">cupsFilePrintf</a></h3>
+<p class="description">Write a formatted string.</p>
+<p class="code">
+int cupsFilePrintf (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *format,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;...<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+<dt>format</dt>
+<dd class="description">Printf-style format string</dd>
+<dt>...</dt>
+<dd class="description">Additional args as necessary</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of bytes written or -1 on error</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFilePutChar">cupsFilePutChar</a></h3>
+<p class="description">Write a character.</p>
+<p class="code">
+int cupsFilePutChar (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int c<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+<dt>c</dt>
+<dd class="description">Character to write</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsFilePutConf">cupsFilePutConf</a></h3>
+<p class="description">Write a configuration line.</p>
+<p class="code">
+ssize_t cupsFilePutConf (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *directive,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *value<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+<dt>directive</dt>
+<dd class="description">Directive</dd>
+<dt>value</dt>
+<dd class="description">Value</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of bytes written or -1 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function handles any comment escaping of the value.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFilePuts">cupsFilePuts</a></h3>
+<p class="description">Write a string.</p>
+<p class="code">
+int cupsFilePuts (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *s<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+<dt>s</dt>
+<dd class="description">String to write</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of bytes written or -1 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Like the <code>fputs</code> function, no newline is appended to the string.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileRead">cupsFileRead</a></h3>
+<p class="description">Read from a file.</p>
+<p class="code">
+ssize_t cupsFileRead (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *buf,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t bytes<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+<dt>buf</dt>
+<dd class="description">Buffer</dd>
+<dt>bytes</dt>
+<dd class="description">Number of bytes to read</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of bytes read or -1 on error</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileRewind">cupsFileRewind</a></h3>
+<p class="description">Set the current file position to the beginning of the
+file.</p>
+<p class="code">
+off_t cupsFileRewind (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New file position or -1 on error</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileSeek">cupsFileSeek</a></h3>
+<p class="description">Seek in a file.</p>
+<p class="code">
+off_t cupsFileSeek (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;off_t pos<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+<dt>pos</dt>
+<dd class="description">Position in file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New file position or -1 on error</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileStderr">cupsFileStderr</a></h3>
+<p class="description">Return a CUPS file associated with stderr.</p>
+<p class="code">
+<a href="#cups_file_t">cups_file_t</a> *cupsFileStderr (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">CUPS file</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileStdin">cupsFileStdin</a></h3>
+<p class="description">Return a CUPS file associated with stdin.</p>
+<p class="code">
+<a href="#cups_file_t">cups_file_t</a> *cupsFileStdin (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">CUPS file</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileStdout">cupsFileStdout</a></h3>
+<p class="description">Return a CUPS file associated with stdout.</p>
+<p class="code">
+<a href="#cups_file_t">cups_file_t</a> *cupsFileStdout (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">CUPS file</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileTell">cupsFileTell</a></h3>
+<p class="description">Return the current file position.</p>
+<p class="code">
+off_t cupsFileTell (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">File position</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileUnlock">cupsFileUnlock</a></h3>
+<p class="description">Unlock access to a file.</p>
+<p class="code">
+int cupsFileUnlock (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsFileWrite">cupsFileWrite</a></h3>
+<p class="description">Write to a file.</p>
+<p class="code">
+ssize_t cupsFileWrite (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_file_t">cups_file_t</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *buf,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t bytes<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">CUPS file</dd>
+<dt>buf</dt>
+<dd class="description">Buffer</dd>
+<dt>bytes</dt>
+<dd class="description">Number of bytes to write</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of bytes written or -1 on error</p>
+<h2 class="title"><a name="TYPES">Data Types</a></h2>
+<h3 class="typedef"><a name="cups_dentry_t">cups_dentry_t</a></h3>
+<p class="description">Directory entry type</p>
+<p class="code">
+typedef struct <a href="#cups_dentry_s">cups_dentry_s</a> cups_dentry_t;
+</p>
+<h3 class="typedef"><a name="cups_dir_t">cups_dir_t</a></h3>
+<p class="description">Directory type</p>
+<p class="code">
+typedef struct _cups_dir_s cups_dir_t;
+</p>
+<h3 class="typedef"><a name="cups_file_t">cups_file_t</a></h3>
+<p class="description">CUPS file type</p>
+<p class="code">
+typedef struct _cups_file_s cups_file_t;
+</p>
+<h2 class="title"><a name="STRUCTURES">Structures</a></h2>
+<h3 class="struct"><a name="cups_dentry_s">cups_dentry_s</a></h3>
+<p class="description">Directory entry type</p>
+<p class="code">struct cups_dentry_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;struct stat fileinfo;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char filename[260];<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>fileinfo </dt>
+<dd class="description">File information</dd>
+<dt>filename[260] </dt>
+<dd class="description">File name</dd>
+</dl>
+</div>
+</body>
+</html>
diff --git a/doc/help/api-filter.html b/doc/help/api-filter.html
new file mode 100644
index 000000000..3a9d1288e
--- /dev/null
+++ b/doc/help/api-filter.html
@@ -0,0 +1,1625 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>Filter and Backend Programming </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: api-filter.html 9799 2011-05-20 18:09:22Z mike $"
+
+ Filter and backend programming header for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Filter and Backend Programming</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Headers</th>
+ <th>cups/backend.h<br>
+ cups/sidechannel.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcups</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a><br>
+ Programming: <a href='api-cups.html' target='_top'>CUPS API</a><br>
+ Programming: <a href='api-ppd.html' target='_top'>PPD API</a><br>
+ Programming: <a href='api-raster.html' target='_top'>Raster API</a><br>
+ Programming: <a href='postscript-driver.html' target='_top'>Developing PostScript Printer Drivers</a><br>
+ Programming: <a href='raster-driver.html' target='_top'>Developing Raster Printer Drivers</a><br>
+ Specifications: <a href='spec-design.html' target='_top'>CUPS Design Description</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#OVERVIEW">Overview</a><ul class="subcontents">
+ <li><a href="#SECURITY">Security Considerations</a></li>
+ <li><a href="#SIGNALS">Canceled Jobs and Signal Handling</a></li>
+ <li><a href="#PERMISSIONS">File Permissions</a></li>
+ <li><a href="#TEMPFILES">Temporary Files</a></li>
+ <li><a href="#COPIES">Copy Generation</a></li>
+ <li><a href="#EXITCODES">Exit Codes</a></li>
+ <li><a href="#ENVIRONMENT">Environment Variables</a></li>
+ <li><a href="#MESSAGES">Communicating with the Scheduler</a></li>
+ <li><a href="#COMMUNICATING_BACKEND">Communicating with the Backend</a></li>
+ <li><a href="#COMMUNICATING_FILTER">Communicating with Filters</a></li>
+ <li><a href="#SNMP">Doing SNMP Queries with Network Printers</a></li>
+</ul></li>
+<li><a href="#FUNCTIONS">Functions</a><ul class="code">
+ <li><a href="#cupsBackChannelRead" title="Read data from the backchannel.">cupsBackChannelRead</a></li>
+ <li><a href="#cupsBackChannelWrite" title="Write data to the backchannel.">cupsBackChannelWrite</a></li>
+ <li><a href="#cupsBackendDeviceURI" title="Get the device URI for a backend.">cupsBackendDeviceURI</a></li>
+ <li><a href="#cupsBackendReport" title="Write a device line from a backend.">cupsBackendReport</a></li>
+ <li><a href="#cupsSideChannelDoRequest" title="Send a side-channel command to a backend and wait for a response.">cupsSideChannelDoRequest</a></li>
+ <li><a href="#cupsSideChannelRead" title="Read a side-channel message.">cupsSideChannelRead</a></li>
+ <li><a href="#cupsSideChannelSNMPGet" title="Query a SNMP OID's value.">cupsSideChannelSNMPGet</a></li>
+ <li><a href="#cupsSideChannelSNMPWalk" title="Query multiple SNMP OID values.">cupsSideChannelSNMPWalk</a></li>
+ <li><a href="#cupsSideChannelWrite" title="Write a side-channel message.">cupsSideChannelWrite</a></li>
+</ul></li>
+<li><a href="#TYPES">Data Types</a><ul class="code">
+ <li><a href="#cups_backend_t" title="Backend exit codes">cups_backend_t</a></li>
+ <li><a href="#cups_sc_bidi_t" title="Bidirectional capabilities">cups_sc_bidi_t</a></li>
+ <li><a href="#cups_sc_command_t" title="Request command codes">cups_sc_command_t</a></li>
+ <li><a href="#cups_sc_connected_t" title="Connectivity values">cups_sc_connected_t</a></li>
+ <li><a href="#cups_sc_state_t" title="Printer state bits">cups_sc_state_t</a></li>
+ <li><a href="#cups_sc_status_t" title="Response status codes">cups_sc_status_t</a></li>
+ <li><a href="#cups_sc_walk_func_t" title="SNMP walk callback">cups_sc_walk_func_t</a></li>
+</ul></li>
+<li><a href="#ENUMERATIONS">Constants</a><ul class="code">
+ <li><a href="#cups_backend_e" title="Backend exit codes">cups_backend_e</a></li>
+ <li><a href="#cups_sc_bidi_e" title="Bidirectional capability values">cups_sc_bidi_e</a></li>
+ <li><a href="#cups_sc_command_e" title="Request command codes">cups_sc_command_e</a></li>
+ <li><a href="#cups_sc_connected_e" title="Connectivity values">cups_sc_connected_e</a></li>
+ <li><a href="#cups_sc_state_e" title="Printer state bits">cups_sc_state_e</a></li>
+ <li><a href="#cups_sc_status_e" title="Response status codes">cups_sc_status_e</a></li>
+</ul></li>
+</ul>
+<!--
+ "$Id: api-filter.html 9799 2011-05-20 18:09:22Z mike $"
+
+ Filter and backend programming introduction for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name="OVERVIEW">Overview</a></h2>
+
+<p>Filters (which include printer drivers and port monitors) and backends
+are used to convert job files to a printable format and send that data to the
+printer itself. All of these programs use a common interface for processing
+print jobs and communicating status information to the scheduler. Each is run
+with a standard set of command-line arguments:<p>
+
+<dl class="code">
+
+ <dt>argv[1]</dt>
+ <dd>The job ID</dd>
+
+ <dt>argv[2]</dt>
+ <dd>The user printing the job</dd>
+
+ <dt>argv[3]</dt>
+ <dd>The job name/title</dd>
+
+ <dt>argv[4]</dt>
+ <dd>The number of copies to print</dd>
+
+ <dt>argv[5]</dt>
+ <dd>The options that were provided when the job was submitted</dd>
+
+ <dt>argv[6]</dt>
+ <dd>The file to print (first program only)</dd>
+</dl>
+
+<p>The scheduler runs one or more of these programs to print any given job. The
+first filter reads from the print file and writes to the standard output, while
+the remaining filters read from the standard input and write to the standard
+output. The backend is the last filter in the chain and writes to the
+device.</p>
+
+<p>Filters are always run as a non-privileged user, typically "lp", with no
+connection to the user's desktop. Backends are run either as a non-privileged
+user or as root if the file permissions do not allow user or group execution.
+The <a href="#PERMISSIONS">file permissions</a> section talks about this in
+more detail.</p>
+
+<h3><a name="SECURITY">Security Considerations</a></h3>
+
+<p>It is always important to use security programming practices. Filters and
+most backends are run as a non-privileged user, so the major security
+consideration is resource utilization - filters should not depend on unlimited
+amounts of CPU, memory, or disk space, and should protect against conditions
+that could lead to excess usage of any resource like infinite loops and
+unbounded recursion. In addition, filters must <em>never</em> allow the user to
+specify an arbitrary file path to a separator page, template, or other file
+used by the filter since that can lead to an unauthorized disclosure of
+information. <em>Always</em> treat input as suspect and validate it!</p>
+
+<p>If you are developing a backend that runs as root, make sure to check for
+potential buffer overflows, integer under/overflow conditions, and file
+accesses since these can lead to privilege escalations. When writing files,
+always validate the file path and <em>never</em> allow a user to determine
+where to store a file.</p>
+
+<blockquote><b>Note:</b>
+
+<p><em>Never</em> write files to a user's home directory. Aside from the
+security implications, CUPS is a network print service and as such the network
+user may not be the same as the local user and/or there may not be a local home
+directory to write to.</p>
+
+<p>In addition, some operating systems provide additional security mechanisms
+that further limit file system access, even for backends running as root. On
+Mac OS X, for example, no backend may write to a user's home directory.</p>
+</blockquote>
+
+<h3><a name="SIGNALS">Canceled Jobs and Signal Handling</a></h3>
+
+<p>The scheduler sends <code>SIGTERM</code> when a printing job is canceled or
+held. Filters, backends, and port monitors <em>must</em> catch
+<code>SIGTERM</code> and perform any cleanup necessary to produce a valid output
+file or return the printer to a known good state. The recommended behavior is to
+end the output on the current page, preferably on the current line or object
+being printed.</p>
+
+<p>Filters and backends may also receive <code>SIGPIPE</code> when an upstream or downstream filter/backend exits with a non-zero status. Developers should generally ignore <code>SIGPIPE</code> at the beginning of <code>main()</code> with the following function call:</p>
+
+<pre class="example">
+#include &lt;signal.h&gt;>
+
+...
+
+int
+main(int argc, char *argv[])
+{
+ signal(SIGPIPE, SIG_IGN);
+
+ ...
+}
+</pre>
+
+<h3><a name="PERMISSIONS">File Permissions</a></h3>
+
+<p>For security reasons, CUPS will only run filters and backends that are owned
+by root and do not have world or group write permissions. The recommended
+permissions for filters and backends are 0555 - read and execute but no write.
+Backends that must run as root should use permissions of 0500 - read and execute
+by root, no access for other users. Write permissions can be enabled for the
+root user only.</p>
+
+<p>To avoid a warning message, the directory containing your filter(s) must also
+be owned by root and have world and group write disabled - permissions of 0755
+or 0555 are strongly encouraged.</p>
+
+<h3><a name="TEMPFILES">Temporary Files</a></h3>
+
+<p>Temporary files should be created in the directory specified by the
+"TMPDIR" environment variable. The
+<a href="#cupsTempFile2"><code>cupsTempFile2</code></a> function can be
+used to safely create temporary files in this directory.</p>
+
+<h3><a name="COPIES">Copy Generation</a></h3>
+
+<p>The <code>argv[4]</code> argument specifies the number of copies to produce
+of the input file. In general, you should only generate copies if the
+<em>filename</em> argument is supplied. The only exception to this are
+filters that produce device-independent PostScript output, since the PostScript
+filter <var>pstops</var> is responsible for generating copies of PostScript
+files.</p>
+
+<h3><a name="EXITCODES">Exit Codes</a></h3>
+
+<p>Filters must exit with status 0 when they successfully generate print data
+or 1 when they encounter an error. Backends can return any of the
+<a href="#cups_backend_t"><code>cups_backend_t</code></a> constants.</p>
+
+<h3><a name="ENVIRONMENT">Environment Variables</a></h3>
+
+<p>The following environment variables are defined by the printing system
+when running print filters and backends:</p>
+
+<dl class="code">
+
+ <dt>APPLE_LANGUAGE</dt>
+ <dd>The Apple language identifier associated with the job
+ (Mac OS X only).</dd>
+
+ <dt>CHARSET</dt>
+ <dd>The job character set, typically "utf-8".</dd>
+
+ <dt>CLASS</dt>
+ <dd>When a job is submitted to a printer class, contains the name of
+ the destination printer class. Otherwise this environment
+ variable will not be set.</dd>
+
+ <dt>CONTENT_TYPE</dt>
+ <dd>The MIME type associated with the file (e.g.
+ application/postscript).</dd>
+
+ <dt>CUPS_CACHEDIR</dt>
+ <dd>The directory where cache files can be stored. Cache files can be
+ used to retain information between jobs or files in a job.</dd>
+
+ <dt>CUPS_DATADIR</dt>
+ <dd>The directory where (read-only) CUPS data files can be found.</dd>
+
+ <dt>CUPS_FILETYPE</dt>
+ <dd>The type of file being printed: "job-sheet" for a banner page and
+ "document" for a regular print file.</dd>
+
+ <dt>CUPS_SERVERROOT</dt>
+ <dd>The root directory of the server.</dd>
+
+ <dt>DEVICE_URI</dt>
+ <dd>The device-uri associated with the printer.</dd>
+
+ <dt>FINAL_CONTENT_TYPE</dt>
+ <dd>The MIME type associated with the printer (e.g.
+ application/vnd.cups-postscript).</dd>
+
+ <dt>LANG</dt>
+ <dd>The language locale associated with the job.</dd>
+
+ <dt>PPD</dt>
+ <dd>The full pathname of the PostScript Printer Description (PPD)
+ file for this printer.</dd>
+
+ <dt>PRINTER</dt>
+ <dd>The queue name of the class or printer.</dd>
+
+ <dt>RIP_CACHE</dt>
+ <dd>The recommended amount of memory to use for Raster Image
+ Processors (RIPs).</dd>
+
+ <dt>TMPDIR</dt>
+ <dd>The directory where temporary files should be created.</dd>
+
+</dl>
+
+<h3><a name="MESSAGES">Communicating with the Scheduler</a></h3>
+
+<p>Filters and backends communicate with the scheduler by writing messages
+to the standard error file. The scheduler reads messages from all filters in
+a job and processes the message based on its prefix. For example, the following
+code sets the current printer state message to "Printing page 5":</p>
+
+<pre class="example">
+int page = 5;
+
+fprintf(stderr, "INFO: Printing page %d\n", page);
+</pre>
+
+<p>Each message is a single line of text starting with one of the following
+prefix strings:</p>
+
+<dl class="code">
+
+ <dt>ALERT: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "alert" log level.</dd>
+
+ <dt>ATTR: attribute=value [attribute=value]</dt>
+ <dd>Sets the named printer or job attribute(s). Typically this is used
+ to set the <code>marker-colors</code>, <code>marker-high-levels</code>,
+ <code>marker-levels</code>, <code>marker-low-levels</code>,
+ <code>marker-message</code>, <code>marker-names</code>,
+ <code>marker-types</code>, <code>printer-alert</code>, and
+ <code>printer-alert-description</code> printer attributes. Standard
+ <code>marker-types</code> values are listed in <a href='#TABLE1'>Table
+ 1</a>.</dd>
+
+ <dt>CRIT: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "critical" log
+ level.</dd>
+
+ <dt>DEBUG: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "debug" log level.</dd>
+
+ <dt>DEBUG2: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "debug2" log level.</dd>
+
+ <dt>EMERG: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "emergency" log
+ level.</dd>
+
+ <dt>ERROR: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "error" log level.
+ Use "ERROR:" messages for non-persistent processing errors.</dd>
+
+ <dt>INFO: message</dt>
+ <dd>Sets the printer-state-message attribute. If the current log level
+ is set to "debug2", also adds the specified message to the current error
+ log file using the "info" log level.</dd>
+
+ <dt>NOTICE: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "notice" log level.</dd>
+
+ <dt>PAGE: page-number #-copies</dt>
+ <dt>PAGE: total #-pages</dt>
+ <dd>Adds an entry to the current page log file. The first form adds
+ #-copies to the job-media-sheets-completed attribute. The second
+ form sets the job-media-sheets-completed attribute to #-pages.</dd>
+
+ <dt>PPD: keyword=value [keyword=value ...]</dt>
+ <dd>Changes or adds keywords to the printer's PPD file. Typically
+ this is used to update installable options or default media settings
+ based on the printer configuration.</dd>
+
+ <dt>STATE: + printer-state-reason [printer-state-reason ...]</dt>
+ <dt>STATE: - printer-state-reason [printer-state-reason ...]</dt>
+ <dd>Sets or clears printer-state-reason keywords for the current queue.
+ Typically this is used to indicate persistent media, ink, toner, and
+ configuration conditions or errors on a printer.
+ <a href='#TABLE2'>Table 2</a> lists the standard state keywords -
+ use vendor-prefixed ("com.example.foo") keywords for custom states. See
+ <a href="#MANAGING_STATE">Managing Printer State in a Filter</a> for more
+ information.
+
+ <dt>WARNING: message</dt>
+ <dd>Sets the printer-state-message attribute and adds the specified
+ message to the current error log file using the "warning" log
+ level.</dd>
+
+</dl>
+
+<p>Messages without one of these prefixes are treated as if they began with
+the "DEBUG:" prefix string.</p>
+
+<div class='table'><table width='80%' summary='Table 1: Standard marker-types Values'>
+<caption>Table 1: <a name='TABLE1'>Standard marker-types Values</a></caption>
+<thead>
+<tr>
+ <th>marker-type</th>
+ <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>developer</td>
+ <td>Developer unit</td>
+</tr>
+<tr>
+ <td>fuser</td>
+ <td>Fuser unit</td>
+</tr>
+<tr>
+ <td>fuserCleaningPad</td>
+ <td>Fuser cleaning pad</td>
+</tr>
+<tr>
+ <td>fuserOil</td>
+ <td>Fuser oil</td>
+</tr>
+<tr>
+ <td>ink</td>
+ <td>Ink supply</td>
+</tr>
+<tr>
+ <td>opc</td>
+ <td>Photo conductor</td>
+</tr>
+<tr>
+ <td>solidWax</td>
+ <td>Wax supply</td>
+</tr>
+<tr>
+ <td>staples</td>
+ <td>Staple supply</td>
+</tr>
+<tr>
+ <td>toner</td>
+ <td>Toner supply</td>
+</tr>
+<tr>
+ <td>transferUnit</td>
+ <td>Transfer unit</td>
+</tr>
+<tr>
+ <td>wasteInk</td>
+ <td>Waste ink tank</td>
+</tr>
+<tr>
+ <td>wasteToner</td>
+ <td>Waste toner tank</td>
+</tr>
+<tr>
+ <td>wasteWax</td>
+ <td>Waste wax tank</td>
+</tr>
+</tbody>
+</table></div>
+
+<br>
+
+<div class='table'><table width='80%' summary='Table 2: Standard State Keywords'>
+<caption>Table 2: <a name='TABLE2'>Standard State Keywords</a></caption>
+<thead>
+<tr>
+ <th>Keyword</th>
+ <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>connecting-to-device</td>
+ <td>Connecting to printer but not printing yet.</td>
+</tr>
+<tr>
+ <td>cover-open</td>
+ <td>The printer's cover is open.</td>
+</tr>
+<tr>
+ <td>input-tray-missing</td>
+ <td>The paper tray is missing.</td>
+</tr>
+<tr>
+ <td>marker-supply-empty</td>
+ <td>The printer is out of ink.</td>
+</tr>
+<tr>
+ <td>marker-supply-low</td>
+ <td>The printer is almost out of ink.</td>
+</tr>
+<tr>
+ <td>marker-waste-almost-full</td>
+ <td>The printer's waste bin is almost full.</td>
+</tr>
+<tr>
+ <td>marker-waste-full</td>
+ <td>The printer's waste bin is full.</td>
+</tr>
+<tr>
+ <td>media-empty</td>
+ <td>The paper tray (any paper tray) is empty.</td>
+</tr>
+<tr>
+ <td>media-jam</td>
+ <td>There is a paper jam.</td>
+</tr>
+<tr>
+ <td>media-low</td>
+ <td>The paper tray (any paper tray) is almost empty.</td>
+</tr>
+<tr>
+ <td>media-needed</td>
+ <td>The paper tray needs to be filled (for a job that is printing).</td>
+</tr>
+<tr>
+ <td>paused</td>
+ <td>Stop the printer.</td>
+</tr>
+<tr>
+ <td>timed-out</td>
+ <td>Unable to connect to printer.</td>
+</tr>
+<tr>
+ <td>toner-empty</td>
+ <td>The printer is out of toner.</td>
+</tr>
+<tr>
+ <td>toner-low</td>
+ <td>The printer is low on toner.</td>
+</tr>
+</tbody>
+</table></div>
+
+<h4><a name="MANAGING_STATE">Managing Printer State in a Filter</a></h4>
+
+<p>Filters are responsible for managing the state keywords they set using
+"STATE:" messages. Typically you will update <em>all</em> of the keywords that
+are used by the filter at startup, for example:</p>
+
+<pre class="example">
+if (foo_condition != 0)
+ fputs("STATE: +com.example.foo\n", stderr);
+else
+ fputs("STATE: -com.example.foo\n", stderr);
+
+if (bar_condition != 0)
+ fputs("STATE: +com.example.bar\n", stderr);
+else
+ fputs("STATE: -com.example.bar\n", stderr);
+</pre>
+
+<p>Then as conditions change, your filter sends "STATE: +keyword" or "STATE:
+-keyword" messages as necessary to set or clear the corresponding keyword,
+respectively.</p>
+
+<p>State keywords are often used to notify the user of issues that span across
+jobs, for example "media-empty-warning" that indicates one or more paper trays
+are empty. These keywords should not be cleared unless the corresponding issue
+no longer exists.</p>
+
+<p>Filters should clear job-related keywords on startup and exit so that they
+do not remain set between jobs. For example, "connecting-to-device" is a job
+sub-state and not an issue that applies when a job is not printing.</p>
+
+<blockquote><b>Note:</b>
+
+<p>"STATE:" messages often provide visible alerts to the user. For example,
+on Mac OS X setting a printer-state-reason value with an "-error" or
+"-warning" suffix will cause the printer's dock item to bounce if the
+corresponding reason is localized with a cupsIPPReason keyword in the
+printer's PPD file.</p>
+
+<p>When providing a vendor-prefixed keyword, <em>always</em> provide the
+corresponding standard keyword (if any) to allow clients to respond to the
+condition correctly. For example, if you provide a vendor-prefixed keyword
+for a low cyan ink condition ("com.example.cyan-ink-low") you must also set the
+"marker-supply-low-warning" keyword. In such cases you should also refrain
+from localizing the vendor-prefixed keyword in the PPD file - otherwise both
+the generic and vendor-specific keyword will be shown in the user
+interface.</p>
+
+</blockquote></dd>
+
+<h4><a name="REPORTING_SUPPLIES">Reporting Supply Levels</a></h4>
+
+<p>CUPS tracks several "marker-*" attributes for ink/toner supply level
+reporting. These attributes allow applications to display the current supply
+levels for a printer without printer-specific software. <a href="#TABLE3">Table 3</a> lists the marker attributes and what they represent.</p>
+
+<p>Filters set marker attributes by sending "ATTR:" messages to stderr. For
+example, a filter supporting an inkjet printer with black and tri-color ink
+cartridges would use the following to initialize the supply attributes:</p>
+
+<pre class="example">
+fputs("ATTR: marker-colors=#000000,#00FFFF#FF00FF#FFFF00\n", stderr);
+fputs("ATTR: marker-low-levels=5,10\n", stderr);
+fputs("ATTR: marker-names=Black,Tri-Color\n", stderr);
+fputs("ATTR: marker-types=ink,ink\n", stderr);
+</pre>
+
+<p>Then periodically the filter queries the printer for its current supply
+levels and updates them with a separate "ATTR:" message:</p>
+
+<pre class="example">
+int black_level, tri_level;
+...
+fprintf(stderr, "ATTR: marker-levels=%d,%d\n", black_level, tri_level);
+</pre>
+
+<div class='table'><table width='80%' summary='Table 3: Supply Level Attributes'>
+<caption>Table 3: <a name='TABLE3'>Supply Level Attributes</a></caption>
+<thead>
+<tr>
+ <th>Attribute</th>
+ <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>marker-colors</td>
+ <td>A list of comma-separated colors; each color is either "none" or one or
+ more hex-encoded sRGB colors of the form "#RRGGBB".</td>
+</tr>
+<tr>
+ <td>marker-high-levels</td>
+ <td>A list of comma-separated "almost full" level values from 0 to 100; a
+ value of 100 should be used for supplies that are consumed/emptied like ink
+ cartridges.</td>
+</tr>
+<tr>
+ <td>marker-levels</td>
+ <td>A list of comma-separated level values for each supply. A value of -1
+ indicates the level is unavailable, -2 indicates unknown, and -3 indicates
+ the level is unknown but has not yet reached capacity. Values from 0 to 100
+ indicate the corresponding percentage.</td>
+</tr>
+<tr>
+ <td>marker-low-levels</td>
+ <td>A list of comma-separated "almost empty" level values from 0 to 100; a
+ value of 0 should be used for supplies that are filled like waste ink
+ tanks.</td>
+</tr>
+<tr>
+ <td>marker-message</td>
+ <td>A human-readable supply status message for the user like "12 pages of
+ ink remaining."</td>
+</tr>
+<tr>
+ <td>marker-names</td>
+ <td>A list of comma-separated supply names like "Cyan Ink", "Fuser",
+ etc.</td>
+</tr>
+<tr>
+ <td>marker-types</td>
+ <td>A list of comma-separated supply types; the types are listed in
+ <a href="#TABLE1">Table 1</a>.</td>
+</tr>
+</tbody>
+</table></div>
+
+<h3><a name="COMMUNICATING_BACKEND">Communicating with the Backend</a></h3>
+
+<p>Filters can communicate with the backend via the
+<a href="#cupsBackChannelRead"><code>cupsBackChannelRead</code></a> and
+<a href="#cupsSideChannelDoRequest"><code>cupsSideChannelDoRequest</code></a>
+functions. The
+<a href="#cupsBackChannelRead"><code>cupsBackChannelRead</code></a> function
+reads data that has been sent back from the device and is typically used to
+obtain status and configuration information. For example, the following code
+polls the backend for back-channel data:</p>
+
+<pre class="example">
+#include &lt;cups/cups.h&gt;
+
+char buffer[8192];
+ssize_t bytes;
+
+/* Use a timeout of 0.0 seconds to poll for back-channel data */
+bytes = cupsBackChannelRead(buffer, sizeof(buffer), 0.0);
+</pre>
+
+<p>Filters can also use <code>select()</code> or <code>poll()</code> on the
+back-channel file descriptor (3 or <code>CUPS_BC_FD</code>) to read data only
+when it is available.</p>
+
+<p>The
+<a href="#cupsSideChannelDoRequest"><code>cupsSideChannelDoRequest</code></a>
+function allows you to get out-of-band status information and do synchronization
+with the device. For example, the following code gets the current IEEE-1284
+device ID string from the backend:</p>
+
+<pre class="example">
+#include &lt;cups/sidechannel.h&gt;
+
+char data[2049];
+int datalen;
+<a href="#cups_sc_status_t">cups_sc_status_t</a> status;
+
+/* Tell cupsSideChannelDoRequest() how big our buffer is, less 1 byte for
+ nul-termination... */
+datalen = sizeof(data) - 1;
+
+/* Get the IEEE-1284 device ID, waiting for up to 1 second */
+status = <a href="#cupsSideChannelDoRequest">cupsSideChannelDoRequest</a>(CUPS_SC_CMD_GET_DEVICE_ID, data, &amp;datalen, 1.0);
+
+/* Use the returned value if OK was returned and the length is non-zero */
+if (status == CUPS_SC_STATUS_OK && datalen > 0)
+ data[datalen] = '\0';
+else
+ data[0] = '\0';
+</pre>
+
+<h4><a name="DRAIN_OUTPUT">Forcing All Output to a Printer</a></h4>
+
+<p>The
+<a href="#cupsSideChannelDoRequest"><code>cupsSideChannelDoRequest</code></a>
+function allows you to tell the backend to send all pending data to the printer.
+This is most often needed when sending query commands to the printer. For example:</p>
+
+<pre class="example">
+#include &lt;cups/cups.h&gt;
+#include &lt;cups/sidechannel.h&gt;
+
+char data[1024];
+int datalen = sizeof(data);
+<a href="#cups_sc_status_t">cups_sc_status_t</a> status;
+
+/* Flush pending output to stdout */
+fflush(stdout);
+
+/* Drain output to backend, waiting for up to 30 seconds */
+status = <a href="#cupsSideChannelDoRequest">cupsSideChannelDoRequest</a>(CUPS_SC_CMD_DRAIN_OUTPUT, data, &amp;datalen, 30.0);
+
+/* Read the response if the output was sent */
+if (status == CUPS_SC_STATUS_OK)
+{
+ ssize_t bytes;
+
+ /* Wait up to 10.0 seconds for back-channel data */
+ bytes = cupsBackChannelRead(data, sizeof(data), 10.0);
+ /* do something with the data from the printer */
+}
+</pre>
+
+<h3><a name="COMMUNICATING_FILTER">Communicating with Filters</a></h3>
+
+<p>Backends communicate with filters using the reciprocal functions
+<a href="#cupsBackChannelWrite"><code>cupsBackChannelWrite</code></a>,
+<a href="#cupsSideChannelRead"><code>cupsSideChannelRead</code></a>, and
+<a href="#cupsSideChannelWrite"><code>cupsSideChannelWrite</code></a>. We
+recommend writing back-channel data using a timeout of 1.0 seconds:</p>
+
+<pre class="example">
+#include &lt;cups/cups.h&gt;
+
+char buffer[8192];
+ssize_t bytes;
+
+/* Obtain data from printer/device */
+...
+
+/* Use a timeout of 1.0 seconds to give filters a chance to read */
+cupsBackChannelWrite(buffer, bytes, 1.0);
+</pre>
+
+<p>The <a href="#cupsSideChannelRead"><code>cupsSideChannelRead</code></a>
+function reads a side-channel command from a filter, driver, or port monitor.
+Backends can either poll for commands using a <code>timeout</code> of 0.0, wait
+indefinitely for commands using a <code>timeout</code> of -1.0 (probably in a
+separate thread for that purpose), or use <code>select</code> or
+<code>poll</code> on the <code>CUPS_SC_FD</code> file descriptor (4) to handle
+input and output on several file descriptors at the same time.</p>
+
+<p>Once a command is processed, the backend uses the
+<a href="#cupsSideChannelWrite"><code>cupsSideChannelWrite</code></a> function
+to send its response. For example, the following code shows how to poll for a
+side-channel command and respond to it:</p>
+
+<pre class="example">
+#include &lt;cups/sidechannel.h&gt;
+
+<a href="#cups_sc_command_t">cups_sc_command_t</a> command;
+<a href="#cups_sc_status_t">cups_sc_status_t</a> status;
+char data[2048];
+int datalen = sizeof(data);
+
+/* Poll for a command... */
+if (!<a href="#cupsSideChannelRead">cupsSideChannelRead</a>(&amp;command, &amp;status, data, &amp;datalen, 0.0))
+{
+ switch (command)
+ {
+ /* handle supported commands, fill data/datalen/status with values as needed */
+
+ default :
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ datalen = 0;
+ break;
+ }
+
+ /* Send a response... */
+ <a href="#cupsSideChannelWrite">cupsSideChannelWrite</a>(command, status, data, datalen, 1.0);
+}
+</pre>
+
+<h3><a name="SNMP">Doing SNMP Queries with Network Printers</a></h3>
+
+<p>The Simple Network Management Protocol (SNMP) allows you to get the current
+status, page counter, and supply levels from most network printers. Every
+piece of information is associated with an Object Identifier (OID), and
+every printer has a <em>community</em> name associated with it. OIDs can be
+queried directly or by "walking" over a range of OIDs with a common prefix.</p>
+
+<p>The two CUPS SNMP functions provide a simple API for querying network
+printers through the side-channel interface. Each accepts a string containing
+an OID like ".1.3.6.1.2.1.43.10.2.1.4.1.1" (the standard page counter OID)
+along with a timeout for the query.</p>
+
+<p>The <a href="#cupsSideChannelSNMPGet"><code>cupsSideChannelSNMPGet</code></a>
+function queries a single OID and returns the value as a string in a buffer
+you supply:</p>
+
+<pre class="example">
+#include &lt;cups/sidechannel.h&gt;
+
+char data[512];
+int datalen = sizeof(data);
+
+if (<a href="#cupsSideChannelSNMPGet">cupsSideChannelSNMPGet</a>(".1.3.6.1.2.1.43.10.2.1.4.1.1", data, &amp;datalen, 5.0)
+ == CUPS_SC_STATUS_OK)
+{
+ /* Do something with the value */
+ printf("Page counter is: %s\n", data);
+}
+</pre>
+
+<p>The
+<a href="#cupsSideChannelSNMPWalk"><code>cupsSideChannelSNMPWalk</code></a>
+function allows you to query a whole group of OIDs, calling a function of your
+choice for each OID that is found:</p>
+
+<pre class="example">
+#include &lt;cups/sidechannel.h&gt;
+
+void
+my_callback(const char *oid, const char *data, int datalen, void *context)
+{
+ /* Do something with the value */
+ printf("%s=%s\n", oid, data);
+}
+
+...
+
+void *my_data;
+
+<a href="#cupsSideChannelSNMPWalk">cupsSNMPSideChannelWalk</a>(".1.3.6.1.2.1.43", 5.0, my_callback, my_data);
+</pre>
+<h2 class="title"><a name="FUNCTIONS">Functions</a></h2>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsBackChannelRead">cupsBackChannelRead</a></h3>
+<p class="description">Read data from the backchannel.</p>
+<p class="code">
+ssize_t cupsBackChannelRead (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *buffer,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t bytes,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;double timeout<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>buffer</dt>
+<dd class="description">Buffer to read into</dd>
+<dt>bytes</dt>
+<dd class="description">Bytes to read</dd>
+<dt>timeout</dt>
+<dd class="description">Timeout in seconds, typically 0.0 to poll</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Bytes read or -1 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Reads up to &quot;bytes&quot; bytes from the backchannel/backend. The &quot;timeout&quot;
+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.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsBackChannelWrite">cupsBackChannelWrite</a></h3>
+<p class="description">Write data to the backchannel.</p>
+<p class="code">
+ssize_t cupsBackChannelWrite (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *buffer,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t bytes,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;double timeout<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>buffer</dt>
+<dd class="description">Buffer to write</dd>
+<dt>bytes</dt>
+<dd class="description">Bytes to write</dd>
+<dt>timeout</dt>
+<dd class="description">Timeout in seconds, typically 1.0</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Bytes written or -1 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Writes &quot;bytes&quot; bytes to the backchannel/filter. The &quot;timeout&quot; 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.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsBackendDeviceURI">cupsBackendDeviceURI</a></h3>
+<p class="description">Get the device URI for a backend.</p>
+<p class="code">
+const char *cupsBackendDeviceURI (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char **argv<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>argv</dt>
+<dd class="description">Command-line arguments</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Device URI or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The &quot;argv&quot; argument is the argv argument passed to main(). This
+function returns the device URI passed in the DEVICE_URI environment
+variable or the device URI passed in argv[0], whichever is found
+first.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsBackendReport">cupsBackendReport</a></h3>
+<p class="description">Write a device line from a backend.</p>
+<p class="code">
+void cupsBackendReport (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *device_scheme,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *device_uri,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *device_make_and_model,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *device_info,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *device_id,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *device_location<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>device_scheme</dt>
+<dd class="description">device-scheme string</dd>
+<dt>device_uri</dt>
+<dd class="description">device-uri string</dd>
+<dt>device_make_and_model</dt>
+<dd class="description">device-make-and-model string or <code>NULL</code></dd>
+<dt>device_info</dt>
+<dd class="description">device-info string or <code>NULL</code></dd>
+<dt>device_id</dt>
+<dd class="description">device-id string or <code>NULL</code></dd>
+<dt>device_location</dt>
+<dd class="description">device-location string or <code>NULL</code></dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function writes a single device line to stdout for a backend.
+It handles quoting of special characters in the device-make-and-model,
+device-info, device-id, and device-location strings.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="cupsSideChannelDoRequest">cupsSideChannelDoRequest</a></h3>
+<p class="description">Send a side-channel command to a backend and wait for a response.</p>
+<p class="code">
+<a href="#cups_sc_status_t">cups_sc_status_t</a> cupsSideChannelDoRequest (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_sc_command_t">cups_sc_command_t</a> command,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *data,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *datalen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;double timeout<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>command</dt>
+<dd class="description">Command to send</dd>
+<dt>data</dt>
+<dd class="description">Response data buffer pointer</dd>
+<dt>datalen</dt>
+<dd class="description">Size of data buffer on entry, number of bytes in buffer on return</dd>
+<dt>timeout</dt>
+<dd class="description">Timeout in seconds</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of command</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is normally only called by filters, drivers, or port
+monitors in order to communicate with the backend used by the current
+printer. Programs must be prepared to handle timeout or &quot;not
+implemented&quot; status codes, which indicate that the backend or device
+do not support the specified side-channel command.<br>
+<br>
+The &quot;datalen&quot; parameter must be initialized to the size of the buffer
+pointed to by the &quot;data&quot; parameter. cupsSideChannelDoRequest() will
+update the value to contain the number of data bytes in the buffer.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="cupsSideChannelRead">cupsSideChannelRead</a></h3>
+<p class="description">Read a side-channel message.</p>
+<p class="code">
+int cupsSideChannelRead (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_sc_command_t">cups_sc_command_t</a> *command,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_sc_status_t">cups_sc_status_t</a> *status,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *data,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *datalen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;double timeout<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>command</dt>
+<dd class="description">Command code</dd>
+<dt>status</dt>
+<dd class="description">Status code</dd>
+<dt>data</dt>
+<dd class="description">Data buffer pointer</dd>
+<dt>datalen</dt>
+<dd class="description">Size of data buffer on entry, number of bytes in buffer on return</dd>
+<dt>timeout</dt>
+<dd class="description">Timeout in seconds</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is normally only called by backend programs to read
+commands from a filter, driver, or port monitor program. The
+caller must be prepared to handle incomplete or invalid messages
+and return the corresponding status codes.<br>
+<br>
+The &quot;datalen&quot; parameter must be initialized to the size of the buffer
+pointed to by the &quot;data&quot; parameter. cupsSideChannelDoRequest() will
+update the value to contain the number of data bytes in the buffer.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsSideChannelSNMPGet">cupsSideChannelSNMPGet</a></h3>
+<p class="description">Query a SNMP OID's value.</p>
+<p class="code">
+<a href="#cups_sc_status_t">cups_sc_status_t</a> cupsSideChannelSNMPGet (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *oid,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *data,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *datalen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;double timeout<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>oid</dt>
+<dd class="description">OID to query</dd>
+<dt>data</dt>
+<dd class="description">Buffer for OID value</dd>
+<dt>datalen</dt>
+<dd class="description">Size of OID buffer on entry, size of value on return</dd>
+<dt>timeout</dt>
+<dd class="description">Timeout in seconds</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Query status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function asks the backend to do a SNMP OID query on behalf of the
+filter, port monitor, or backend using the default community name.<br>
+<br>
+&quot;oid&quot; contains a numeric OID consisting of integers separated by periods,
+for example &quot;.1.3.6.1.2.1.43&quot;. Symbolic names from SNMP MIBs are not
+supported and must be converted to their numeric forms.<br>
+<br>
+On input, &quot;data&quot; and &quot;datalen&quot; provide the location and size of the
+buffer to hold the OID value as a string. HEX-String (binary) values are
+converted to hexadecimal strings representing the binary data, while
+NULL-Value and unknown OID types are returned as the empty string.
+The returned &quot;datalen&quot; does not include the trailing nul.
+
+<code>CUPS_SC_STATUS_NOT_IMPLEMENTED</code> is returned by backends that do not
+support SNMP queries. <code>CUPS_SC_STATUS_NO_RESPONSE</code> is returned when
+the printer does not respond to the SNMP query.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsSideChannelSNMPWalk">cupsSideChannelSNMPWalk</a></h3>
+<p class="description">Query multiple SNMP OID values.</p>
+<p class="code">
+<a href="#cups_sc_status_t">cups_sc_status_t</a> cupsSideChannelSNMPWalk (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *oid,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;double timeout,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_sc_walk_func_t">cups_sc_walk_func_t</a> cb,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *context<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>oid</dt>
+<dd class="description">First numeric OID to query</dd>
+<dt>timeout</dt>
+<dd class="description">Timeout for each query in seconds</dd>
+<dt>cb</dt>
+<dd class="description">Function to call with each value</dd>
+<dt>context</dt>
+<dd class="description">Application-defined pointer to send to callback</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of first query of <code>CUPS_SC_STATUS_OK</code> on success</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function asks the backend to do multiple SNMP OID queries on behalf
+of the filter, port monitor, or backend using the default community name.
+All OIDs under the &quot;parent&quot; OID are queried and the results are sent to
+the callback function you provide.<br>
+<br>
+&quot;oid&quot; contains a numeric OID consisting of integers separated by periods,
+for example &quot;.1.3.6.1.2.1.43&quot;. Symbolic names from SNMP MIBs are not
+supported and must be converted to their numeric forms.<br>
+<br>
+&quot;timeout&quot; specifies the timeout for each OID query. The total amount of
+time will depend on the number of OID values found and the time required
+for each query.<br>
+<br>
+&quot;cb&quot; provides a function to call for every value that is found. &quot;context&quot;
+is an application-defined pointer that is sent to the callback function
+along with the OID and current data. The data passed to the callback is the
+same as returned by <a href="#cupsSideChannelSNMPGet"><code>cupsSideChannelSNMPGet</code></a>.
+
+<code>CUPS_SC_STATUS_NOT_IMPLEMENTED</code> is returned by backends that do not
+support SNMP queries. <code>CUPS_SC_STATUS_NO_RESPONSE</code> is returned when
+the printer does not respond to the first SNMP query.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="cupsSideChannelWrite">cupsSideChannelWrite</a></h3>
+<p class="description">Write a side-channel message.</p>
+<p class="code">
+int cupsSideChannelWrite (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_sc_command_t">cups_sc_command_t</a> command,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_sc_status_t">cups_sc_status_t</a> status,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *data,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int datalen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;double timeout<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>command</dt>
+<dd class="description">Command code</dd>
+<dt>status</dt>
+<dd class="description">Status code</dd>
+<dt>data</dt>
+<dd class="description">Data buffer pointer</dd>
+<dt>datalen</dt>
+<dd class="description">Number of bytes of data</dd>
+<dt>timeout</dt>
+<dd class="description">Timeout in seconds</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is normally only called by backend programs to send
+responses to a filter, driver, or port monitor program.
+
+</p>
+<h2 class="title"><a name="TYPES">Data Types</a></h2>
+<h3 class="typedef"><a name="cups_backend_t">cups_backend_t</a></h3>
+<p class="description">Backend exit codes</p>
+<p class="code">
+typedef enum <a href="#cups_backend_e">cups_backend_e</a> cups_backend_t;
+</p>
+<h3 class="typedef"><a name="cups_sc_bidi_t">cups_sc_bidi_t</a></h3>
+<p class="description">Bidirectional capabilities</p>
+<p class="code">
+typedef enum <a href="#cups_sc_bidi_e">cups_sc_bidi_e</a> cups_sc_bidi_t;
+</p>
+<h3 class="typedef"><a name="cups_sc_command_t">cups_sc_command_t</a></h3>
+<p class="description">Request command codes</p>
+<p class="code">
+typedef enum <a href="#cups_sc_command_e">cups_sc_command_e</a> cups_sc_command_t;
+</p>
+<h3 class="typedef"><a name="cups_sc_connected_t">cups_sc_connected_t</a></h3>
+<p class="description">Connectivity values</p>
+<p class="code">
+typedef enum <a href="#cups_sc_connected_e">cups_sc_connected_e</a> cups_sc_connected_t;
+</p>
+<h3 class="typedef"><a name="cups_sc_state_t">cups_sc_state_t</a></h3>
+<p class="description">Printer state bits</p>
+<p class="code">
+typedef enum <a href="#cups_sc_state_e">cups_sc_state_e</a> cups_sc_state_t;
+</p>
+<h3 class="typedef"><a name="cups_sc_status_t">cups_sc_status_t</a></h3>
+<p class="description">Response status codes</p>
+<p class="code">
+typedef enum <a href="#cups_sc_status_e">cups_sc_status_e</a> cups_sc_status_t;
+</p>
+<h3 class="typedef"><a name="cups_sc_walk_func_t">cups_sc_walk_func_t</a></h3>
+<p class="description">SNMP walk callback</p>
+<p class="code">
+typedef void (*cups_sc_walk_func_t)(const char *oid, const char *data, int datalen, void *context);
+</p>
+<h2 class="title"><a name="ENUMERATIONS">Constants</a></h2>
+<h3 class="enumeration"><a name="cups_backend_e">cups_backend_e</a></h3>
+<p class="description">Backend exit codes</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_BACKEND_AUTH_REQUIRED </dt>
+<dd class="description">Job failed, authentication required</dd>
+<dt>CUPS_BACKEND_CANCEL </dt>
+<dd class="description">Job failed, cancel job</dd>
+<dt>CUPS_BACKEND_FAILED </dt>
+<dd class="description">Job failed, use error-policy</dd>
+<dt>CUPS_BACKEND_HOLD </dt>
+<dd class="description">Job failed, hold job</dd>
+<dt>CUPS_BACKEND_OK </dt>
+<dd class="description">Job completed successfully</dd>
+<dt>CUPS_BACKEND_RETRY </dt>
+<dd class="description">Job failed, retry this job later</dd>
+<dt>CUPS_BACKEND_RETRY_CURRENT </dt>
+<dd class="description">Job failed, retry this job immediately</dd>
+<dt>CUPS_BACKEND_STOP </dt>
+<dd class="description">Job failed, stop queue</dd>
+</dl>
+<h3 class="enumeration"><a name="cups_sc_bidi_e">cups_sc_bidi_e</a></h3>
+<p class="description">Bidirectional capability values</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_SC_BIDI_NOT_SUPPORTED </dt>
+<dd class="description">Bidirectional I/O is not supported</dd>
+<dt>CUPS_SC_BIDI_SUPPORTED </dt>
+<dd class="description">Bidirectional I/O is supported</dd>
+</dl>
+<h3 class="enumeration"><a name="cups_sc_command_e">cups_sc_command_e</a></h3>
+<p class="description">Request command codes</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_SC_CMD_DRAIN_OUTPUT </dt>
+<dd class="description">Drain all pending output</dd>
+<dt>CUPS_SC_CMD_GET_BIDI </dt>
+<dd class="description">Return bidirectional capabilities</dd>
+<dt>CUPS_SC_CMD_GET_CONNECTED <span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span></dt>
+<dd class="description">Return whether the backend is &quot;connected&quot; to the printer </dd>
+<dt>CUPS_SC_CMD_GET_DEVICE_ID </dt>
+<dd class="description">Return the IEEE-1284 device ID</dd>
+<dt>CUPS_SC_CMD_GET_STATE </dt>
+<dd class="description">Return the device state</dd>
+<dt>CUPS_SC_CMD_SNMP_GET <span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span></dt>
+<dd class="description">Query an SNMP OID </dd>
+<dt>CUPS_SC_CMD_SNMP_GET_NEXT <span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span></dt>
+<dd class="description">Query the next SNMP OID </dd>
+<dt>CUPS_SC_CMD_SOFT_RESET </dt>
+<dd class="description">Do a soft reset</dd>
+</dl>
+<h3 class="enumeration"><a name="cups_sc_connected_e">cups_sc_connected_e</a></h3>
+<p class="description">Connectivity values</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_SC_CONNECTED </dt>
+<dd class="description">Backend is &quot;connected&quot; to printer</dd>
+<dt>CUPS_SC_NOT_CONNECTED </dt>
+<dd class="description">Backend is not &quot;connected&quot; to printer</dd>
+</dl>
+<h3 class="enumeration"><a name="cups_sc_state_e">cups_sc_state_e</a></h3>
+<p class="description">Printer state bits</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_SC_STATE_BUSY </dt>
+<dd class="description">Device is busy</dd>
+<dt>CUPS_SC_STATE_ERROR </dt>
+<dd class="description">Other error condition</dd>
+<dt>CUPS_SC_STATE_MARKER_EMPTY </dt>
+<dd class="description">Toner/ink out condition</dd>
+<dt>CUPS_SC_STATE_MARKER_LOW </dt>
+<dd class="description">Toner/ink low condition</dd>
+<dt>CUPS_SC_STATE_MEDIA_EMPTY </dt>
+<dd class="description">Paper out condition</dd>
+<dt>CUPS_SC_STATE_MEDIA_LOW </dt>
+<dd class="description">Paper low condition</dd>
+<dt>CUPS_SC_STATE_OFFLINE </dt>
+<dd class="description">Device is offline</dd>
+<dt>CUPS_SC_STATE_ONLINE </dt>
+<dd class="description">Device is online</dd>
+</dl>
+<h3 class="enumeration"><a name="cups_sc_status_e">cups_sc_status_e</a></h3>
+<p class="description">Response status codes</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_SC_STATUS_BAD_MESSAGE </dt>
+<dd class="description">The command/response message was invalid</dd>
+<dt>CUPS_SC_STATUS_IO_ERROR </dt>
+<dd class="description">An I/O error occurred</dd>
+<dt>CUPS_SC_STATUS_NONE </dt>
+<dd class="description">No status</dd>
+<dt>CUPS_SC_STATUS_NOT_IMPLEMENTED </dt>
+<dd class="description">Command not implemented</dd>
+<dt>CUPS_SC_STATUS_NO_RESPONSE </dt>
+<dd class="description">The device did not respond</dd>
+<dt>CUPS_SC_STATUS_OK </dt>
+<dd class="description">Operation succeeded</dd>
+<dt>CUPS_SC_STATUS_TIMEOUT </dt>
+<dd class="description">The backend did not respond</dd>
+<dt>CUPS_SC_STATUS_TOO_BIG </dt>
+<dd class="description">Response too big</dd>
+</dl>
+</div>
+</body>
+</html>
diff --git a/doc/help/api-httpipp.html b/doc/help/api-httpipp.html
new file mode 100644
index 000000000..38a3e3fc3
--- /dev/null
+++ b/doc/help/api-httpipp.html
@@ -0,0 +1,4377 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>HTTP and IPP APIs </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: api-httpipp.html 9801 2011-05-21 04:02:41Z mike $"
+
+ HTTP and IPP API header for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>HTTP and IPP APIs</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/cups.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcups</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html'>Introduction to CUPS Programming</a><br>
+ Programming: <a href='api-cups.html'>CUPS API</a><br>
+ References: <a href='spec-ipp.html'>CUPS Implementation of IPP</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#OVERVIEW">Overview</a><ul class="subcontents">
+ <li><a href="#CREATING_URI_STRINGS">Creating URI Strings</a></li>
+ <li><a href="#SENDING_REQUESTS_WITH_FILES">Sending Requests with Files</a></li>
+ <li><a href="#ASYNCHRONOUS_REQUEST_PROCESSING">Asynchronous Request Processing</a></li>
+</ul></li>
+<li><a href="#FUNCTIONS">Functions</a><ul class="code">
+ <li><a href="#cupsDoAuthentication" title="Authenticate a request.">cupsDoAuthentication</a></li>
+ <li><a href="#cupsDoFileRequest" title="Do an IPP request with a file.">cupsDoFileRequest</a></li>
+ <li><a href="#cupsDoIORequest" title="Do an IPP request with file descriptors.">cupsDoIORequest</a></li>
+ <li><a href="#cupsDoRequest" title="Do an IPP request.">cupsDoRequest</a></li>
+ <li><a href="#cupsEncodeOptions" title="Encode printer options into IPP attributes.">cupsEncodeOptions</a></li>
+ <li><a href="#cupsEncodeOptions2" title="Encode printer options into IPP attributes for a group.">cupsEncodeOptions2</a></li>
+ <li><a href="#cupsGetDevices" title="Get available printer devices.">cupsGetDevices</a></li>
+ <li><a href="#cupsGetFd" title="Get a file from the server.">cupsGetFd</a></li>
+ <li><a href="#cupsGetFile" title="Get a file from the server.">cupsGetFile</a></li>
+ <li><a href="#cupsGetResponse" title="Get a response to an IPP request.">cupsGetResponse</a></li>
+ <li><a href="#cupsLastError" title="Return the last IPP status code.">cupsLastError</a></li>
+ <li><a href="#cupsLastErrorString" title="Return the last IPP status-message.">cupsLastErrorString</a></li>
+ <li><a href="#cupsPutFd" title="Put a file on the server.">cupsPutFd</a></li>
+ <li><a href="#cupsPutFile" title="Put a file on the server.">cupsPutFile</a></li>
+ <li><a href="#cupsReadResponseData" title="Read additional data after the IPP response.">cupsReadResponseData</a></li>
+ <li><a href="#cupsSendRequest" title="Send an IPP request.">cupsSendRequest</a></li>
+ <li><a href="#cupsWriteRequestData" title="Write additional data after an IPP request.">cupsWriteRequestData</a></li>
+ <li><a href="#httpAddCredential" title="Allocates and adds a single credential to an array.">httpAddCredential</a></li>
+ <li><a href="#httpAddrAny" title="Check for the &quot;any&quot; address.">httpAddrAny</a></li>
+ <li><a href="#httpAddrEqual" title="Compare two addresses.">httpAddrEqual</a></li>
+ <li><a href="#httpAddrLength" title="Return the length of the address in bytes.">httpAddrLength</a></li>
+ <li><a href="#httpAddrLocalhost" title="Check for the local loopback address.">httpAddrLocalhost</a></li>
+ <li><a href="#httpAddrLookup" title="Lookup the hostname associated with the address.">httpAddrLookup</a></li>
+ <li><a href="#httpAddrString" title="Convert an address to a numeric string.">httpAddrString</a></li>
+ <li><a href="#httpAssembleURI" title="Assemble a uniform resource identifier from its
+components.">httpAssembleURI</a></li>
+ <li><a href="#httpAssembleURIf" title="Assemble a uniform resource identifier from its
+components with a formatted resource.">httpAssembleURIf</a></li>
+ <li><a href="#httpBlocking" title="Set blocking/non-blocking behavior on a connection.">httpBlocking</a></li>
+ <li><a href="#httpCheck" title="Check to see if there is a pending response from the server.">httpCheck</a></li>
+ <li><a href="#httpClearCookie" title="Clear the cookie value(s).">httpClearCookie</a></li>
+ <li><a href="#httpClearFields" title="Clear HTTP request fields.">httpClearFields</a></li>
+ <li><a href="#httpClose" title="Close an HTTP connection.">httpClose</a></li>
+ <li><a href="#httpConnect" title="Connect to a HTTP server.">httpConnect</a></li>
+ <li><a href="#httpConnectEncrypt" title="Connect to a HTTP server using encryption.">httpConnectEncrypt</a></li>
+ <li><a href="#httpCopyCredentials" title="Copy the credentials associated with an encrypted
+connection.">httpCopyCredentials</a></li>
+ <li><a href="#httpDecode64" title="Base64-decode a string.">httpDecode64</a></li>
+ <li><a href="#httpDecode64_2" title="Base64-decode a string.">httpDecode64_2</a></li>
+ <li><a href="#httpDelete" title="Send a DELETE request to the server.">httpDelete</a></li>
+ <li><a href="#httpEncode64" title="Base64-encode a string.">httpEncode64</a></li>
+ <li><a href="#httpEncode64_2" title="Base64-encode a string.">httpEncode64_2</a></li>
+ <li><a href="#httpEncryption" title="Set the required encryption on the link.">httpEncryption</a></li>
+ <li><a href="#httpError" title="Get the last error on a connection.">httpError</a></li>
+ <li><a href="#httpFlush" title="Flush data from a HTTP connection.">httpFlush</a></li>
+ <li><a href="#httpFlushWrite" title="Flush data in write buffer.">httpFlushWrite</a></li>
+ <li><a href="#httpFreeCredentials" title="Free an array of credentials.">httpFreeCredentials</a></li>
+ <li><a href="#httpGet" title="Send a GET request to the server.">httpGet</a></li>
+ <li><a href="#httpGetAuthString" title="Get the current authorization string.">httpGetAuthString</a></li>
+ <li><a href="#httpGetBlocking" title="Get the blocking/non-block state of a connection.">httpGetBlocking</a></li>
+ <li><a href="#httpGetCookie" title="Get any cookie data from the response.">httpGetCookie</a></li>
+ <li><a href="#httpGetDateString" title="Get a formatted date/time string from a time value.">httpGetDateString</a></li>
+ <li><a href="#httpGetDateString2" title="Get a formatted date/time string from a time value.">httpGetDateString2</a></li>
+ <li><a href="#httpGetDateTime" title="Get a time value from a formatted date/time string.">httpGetDateTime</a></li>
+ <li><a href="#httpGetFd" title="Get the file descriptor associated with a connection.">httpGetFd</a></li>
+ <li><a href="#httpGetField" title="Get a field value from a request/response.">httpGetField</a></li>
+ <li><a href="#httpGetHostByName" title="Lookup a hostname or IPv4 address, and return
+address records for the specified name.">httpGetHostByName</a></li>
+ <li><a href="#httpGetHostname" title="Get the FQDN for the connection or local system.">httpGetHostname</a></li>
+ <li><a href="#httpGetLength" title="Get the amount of data remaining from the
+content-length or transfer-encoding fields.">httpGetLength</a></li>
+ <li><a href="#httpGetLength2" title="Get the amount of data remaining from the
+content-length or transfer-encoding fields.">httpGetLength2</a></li>
+ <li><a href="#httpGetStatus" title="Get the status of the last HTTP request.">httpGetStatus</a></li>
+ <li><a href="#httpGetSubField" title="Get a sub-field value.">httpGetSubField</a></li>
+ <li><a href="#httpGetSubField2" title="Get a sub-field value.">httpGetSubField2</a></li>
+ <li><a href="#httpGets" title="Get a line of text from a HTTP connection.">httpGets</a></li>
+ <li><a href="#httpHead" title="Send a HEAD request to the server.">httpHead</a></li>
+ <li><a href="#httpInitialize" title="Initialize the HTTP interface library and set the
+default HTTP proxy (if any).">httpInitialize</a></li>
+ <li><a href="#httpMD5" title="Compute the MD5 sum of the username:group:password.">httpMD5</a></li>
+ <li><a href="#httpMD5Final" title="Combine the MD5 sum of the username, group, and password
+with the server-supplied nonce value, method, and
+request-uri.">httpMD5Final</a></li>
+ <li><a href="#httpMD5String" title="Convert an MD5 sum to a character string.">httpMD5String</a></li>
+ <li><a href="#httpOptions" title="Send an OPTIONS request to the server.">httpOptions</a></li>
+ <li><a href="#httpPost" title="Send a POST request to the server.">httpPost</a></li>
+ <li><a href="#httpPut" title="Send a PUT request to the server.">httpPut</a></li>
+ <li><a href="#httpRead" title="Read data from a HTTP connection.">httpRead</a></li>
+ <li><a href="#httpRead2" title="Read data from a HTTP connection.">httpRead2</a></li>
+ <li><a href="#httpReconnect" title="Reconnect to a HTTP server.">httpReconnect</a></li>
+ <li><a href="#httpSeparate" title="Separate a Universal Resource Identifier into its
+components.">httpSeparate</a></li>
+ <li><a href="#httpSeparate2" title="Separate a Universal Resource Identifier into its
+components.">httpSeparate2</a></li>
+ <li><a href="#httpSeparateURI" title="Separate a Universal Resource Identifier into its
+components.">httpSeparateURI</a></li>
+ <li><a href="#httpSetAuthString" title="Set the current authorization string.">httpSetAuthString</a></li>
+ <li><a href="#httpSetCookie" title="Set the cookie value(s).">httpSetCookie</a></li>
+ <li><a href="#httpSetCredentials" title="Set the credentials associated with an encrypted
+connection.">httpSetCredentials</a></li>
+ <li><a href="#httpSetExpect" title="Set the Expect: header in a request.">httpSetExpect</a></li>
+ <li><a href="#httpSetField" title="Set the value of an HTTP header.">httpSetField</a></li>
+ <li><a href="#httpSetLength" title="Set the content-length and content-encoding.">httpSetLength</a></li>
+ <li><a href="#httpSetTimeout" title="Set read/write timeouts and an optional callback.">httpSetTimeout</a></li>
+ <li><a href="#httpStatus" title="Return a short string describing a HTTP status code.">httpStatus</a></li>
+ <li><a href="#httpTrace" title="Send an TRACE request to the server.">httpTrace</a></li>
+ <li><a href="#httpUpdate" title="Update the current HTTP state for incoming data.">httpUpdate</a></li>
+ <li><a href="#httpWait" title="Wait for data available on a connection.">httpWait</a></li>
+ <li><a href="#httpWrite" title="Write data to a HTTP connection.">httpWrite</a></li>
+ <li><a href="#httpWrite2" title="Write data to a HTTP connection.">httpWrite2</a></li>
+ <li><a href="#ippAddBoolean" title="Add a boolean attribute to an IPP message.">ippAddBoolean</a></li>
+ <li><a href="#ippAddBooleans" title="Add an array of boolean values.">ippAddBooleans</a></li>
+ <li><a href="#ippAddCollection" title="Add a collection value.">ippAddCollection</a></li>
+ <li><a href="#ippAddCollections" title="Add an array of collection values.">ippAddCollections</a></li>
+ <li><a href="#ippAddDate" title="Add a date attribute to an IPP message.">ippAddDate</a></li>
+ <li><a href="#ippAddInteger" title="Add a integer attribute to an IPP message.">ippAddInteger</a></li>
+ <li><a href="#ippAddIntegers" title="Add an array of integer values.">ippAddIntegers</a></li>
+ <li><a href="#ippAddOctetString" title="Add an octetString value to an IPP message.">ippAddOctetString</a></li>
+ <li><a href="#ippAddRange" title="Add a range of values to an IPP message.">ippAddRange</a></li>
+ <li><a href="#ippAddRanges" title="Add ranges of values to an IPP message.">ippAddRanges</a></li>
+ <li><a href="#ippAddResolution" title="Add a resolution value to an IPP message.">ippAddResolution</a></li>
+ <li><a href="#ippAddResolutions" title="Add resolution values to an IPP message.">ippAddResolutions</a></li>
+ <li><a href="#ippAddSeparator" title="Add a group separator to an IPP message.">ippAddSeparator</a></li>
+ <li><a href="#ippAddString" title="Add a language-encoded string to an IPP message.">ippAddString</a></li>
+ <li><a href="#ippAddStrings" title="Add language-encoded strings to an IPP message.">ippAddStrings</a></li>
+ <li><a href="#ippDateToTime" title="Convert from RFC 1903 Date/Time format to UNIX time
+in seconds.">ippDateToTime</a></li>
+ <li><a href="#ippDelete" title="Delete an IPP message.">ippDelete</a></li>
+ <li><a href="#ippDeleteAttribute" title="Delete a single attribute in an IPP message.">ippDeleteAttribute</a></li>
+ <li><a href="#ippErrorString" title="Return a name for the given status code.">ippErrorString</a></li>
+ <li><a href="#ippErrorValue" title="Return a status code for the given name.">ippErrorValue</a></li>
+ <li><a href="#ippFindAttribute" title="Find a named attribute in a request...">ippFindAttribute</a></li>
+ <li><a href="#ippFindNextAttribute" title="Find the next named attribute in a request...">ippFindNextAttribute</a></li>
+ <li><a href="#ippLength" title="Compute the length of an IPP message.">ippLength</a></li>
+ <li><a href="#ippNew" title="Allocate a new IPP message.">ippNew</a></li>
+ <li><a href="#ippNewRequest" title="Allocate a new IPP request message.">ippNewRequest</a></li>
+ <li><a href="#ippOpString" title="Return a name for the given operation id.">ippOpString</a></li>
+ <li><a href="#ippOpValue" title="Return an operation id for the given name.">ippOpValue</a></li>
+ <li><a href="#ippPort" title="Return the default IPP port number.">ippPort</a></li>
+ <li><a href="#ippRead" title="Read data for an IPP message from a HTTP connection.">ippRead</a></li>
+ <li><a href="#ippReadFile" title="Read data for an IPP message from a file.">ippReadFile</a></li>
+ <li><a href="#ippReadIO" title="Read data for an IPP message.">ippReadIO</a></li>
+ <li><a href="#ippSetPort" title="Set the default port number.">ippSetPort</a></li>
+ <li><a href="#ippTagString" title="Return the tag name corresponding to a tag value.">ippTagString</a></li>
+ <li><a href="#ippTagValue" title="Return the tag value corresponding to a tag name.">ippTagValue</a></li>
+ <li><a href="#ippTimeToDate" title="Convert from UNIX time to RFC 1903 format.">ippTimeToDate</a></li>
+ <li><a href="#ippWrite" title="Write data for an IPP message to a HTTP connection.">ippWrite</a></li>
+ <li><a href="#ippWriteFile" title="Write data for an IPP message to a file.">ippWriteFile</a></li>
+ <li><a href="#ippWriteIO" title="Write data for an IPP message.">ippWriteIO</a></li>
+</ul></li>
+<li><a href="#TYPES">Data Types</a><ul class="code">
+ <li><a href="#gss_auth_identity_desc" title="Local functions...">gss_auth_identity_desc</a></li>
+ <li><a href="#http_addr_t" title="Socket address union, which
+makes using IPv6 and other
+address types easier and
+more portable. ">http_addr_t</a></li>
+ <li><a href="#http_addrlist_t" title="Socket address list, which is
+used to enumerate all of the
+addresses that are associated
+with a hostname. ">http_addrlist_t</a></li>
+ <li><a href="#http_auth_t" title="HTTP authentication types">http_auth_t</a></li>
+ <li><a href="#http_credential_t" title="HTTP credential data ">http_credential_t</a></li>
+ <li><a href="#http_encoding_t" title="HTTP transfer encoding values">http_encoding_t</a></li>
+ <li><a href="#http_encryption_t" title="HTTP encryption values">http_encryption_t</a></li>
+ <li><a href="#http_field_t" title="HTTP field names">http_field_t</a></li>
+ <li><a href="#http_keepalive_t" title="HTTP keep-alive values">http_keepalive_t</a></li>
+ <li><a href="#http_state_t" title="HTTP state values; states
+are server-oriented...">http_state_t</a></li>
+ <li><a href="#http_status_t" title="HTTP status codes">http_status_t</a></li>
+ <li><a href="#http_t" title="HTTP connection type">http_t</a></li>
+ <li><a href="#http_timeout_cb_t" title="HTTP timeout callback ">http_timeout_cb_t</a></li>
+ <li><a href="#http_uri_coding_t" title="URI en/decode flags">http_uri_coding_t</a></li>
+ <li><a href="#http_uri_status_t" title="URI separation status ">http_uri_status_t</a></li>
+ <li><a href="#http_version_t" title="HTTP version numbers">http_version_t</a></li>
+ <li><a href="#ipp_attribute_t" title="Attribute">ipp_attribute_t</a></li>
+ <li><a href="#ipp_finish_t" title="Finishings">ipp_finish_t</a></li>
+ <li><a href="#ipp_iocb_t" title="IPP IO Callback Function ">ipp_iocb_t</a></li>
+ <li><a href="#ipp_jstate_t" title="Job states">ipp_jstate_t</a></li>
+ <li><a href="#ipp_op_t" title="IPP operations">ipp_op_t</a></li>
+ <li><a href="#ipp_orient_t" title="Orientation values">ipp_orient_t</a></li>
+ <li><a href="#ipp_pstate_t" title="Printer states">ipp_pstate_t</a></li>
+ <li><a href="#ipp_quality_t" title="Qualities">ipp_quality_t</a></li>
+ <li><a href="#ipp_request_t" title="Request Header">ipp_request_t</a></li>
+ <li><a href="#ipp_res_t" title="Resolution units">ipp_res_t</a></li>
+ <li><a href="#ipp_state_t" title="IPP states">ipp_state_t</a></li>
+ <li><a href="#ipp_t" title="Attribute Value">ipp_t</a></li>
+ <li><a href="#ipp_uchar_t" title="IPP status codes">ipp_uchar_t</a></li>
+ <li><a href="#ipp_tag_t" title="Format tags for attributes">ipp_tag_t</a></li>
+ <li><a href="#ipp_value_t" title="Attribute Value">ipp_value_t</a></li>
+</ul></li>
+<li><a href="#STRUCTURES">Structures</a><ul class="code">
+ <li><a href="#gss_auth_identity" title="Local functions...">gss_auth_identity</a></li>
+ <li><a href="#http_addrlist_s" title="Socket address list, which is
+used to enumerate all of the
+addresses that are associated
+with a hostname. ">http_addrlist_s</a></li>
+ <li><a href="#http_credential_s" title="HTTP credential data ">http_credential_s</a></li>
+ <li><a href="#ipp_attribute_s" title="Attribute">ipp_attribute_s</a></li>
+ <li><a href="#ipp_s" title="IPP Request/Response/Notification">ipp_s</a></li>
+</ul></li>
+<li><a href="#UNIONS">Unions</a><ul class="code">
+ <li><a href="#ipp_request_u" title="Request Header">ipp_request_u</a></li>
+ <li><a href="#ipp_value_u" title="Attribute Value">ipp_value_u</a></li>
+</ul></li>
+<li><a href="#ENUMERATIONS">Constants</a><ul class="code">
+ <li><a href="#http_auth_e" title="HTTP authentication types">http_auth_e</a></li>
+ <li><a href="#http_encoding_e" title="HTTP transfer encoding values">http_encoding_e</a></li>
+ <li><a href="#http_encryption_e" title="HTTP encryption values">http_encryption_e</a></li>
+ <li><a href="#http_field_e" title="HTTP field names">http_field_e</a></li>
+ <li><a href="#http_keepalive_e" title="HTTP keep-alive values">http_keepalive_e</a></li>
+ <li><a href="#http_state_e" title="HTTP state values; states
+are server-oriented...">http_state_e</a></li>
+ <li><a href="#http_status_e" title="HTTP status codes">http_status_e</a></li>
+ <li><a href="#http_uri_coding_e" title="URI en/decode flags">http_uri_coding_e</a></li>
+ <li><a href="#http_uri_status_e" title="URI separation status ">http_uri_status_e</a></li>
+ <li><a href="#http_version_e" title="HTTP version numbers">http_version_e</a></li>
+ <li><a href="#ipp_finish_e" title="Finishings">ipp_finish_e</a></li>
+ <li><a href="#ipp_jstate_e" title="Job states">ipp_jstate_e</a></li>
+ <li><a href="#ipp_op_e" title="IPP operations">ipp_op_e</a></li>
+ <li><a href="#ipp_orient_e" title="Orientation values">ipp_orient_e</a></li>
+ <li><a href="#ipp_pstate_e" title="Printer states">ipp_pstate_e</a></li>
+ <li><a href="#ipp_quality_e" title="Qualities">ipp_quality_e</a></li>
+ <li><a href="#ipp_res_e" title="Resolution units">ipp_res_e</a></li>
+ <li><a href="#ipp_state_e" title="IPP states">ipp_state_e</a></li>
+ <li><a href="#ipp_status_e" title="IPP status codes">ipp_status_e</a></li>
+ <li><a href="#ipp_tag_e" title="Format tags for attributes">ipp_tag_e</a></li>
+</ul></li>
+</ul>
+<!--
+ "$Id: api-httpipp.html 9801 2011-05-21 04:02:41Z mike $"
+
+ HTTP and IPP API introduction for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>The CUPS HTTP and IPP APIs provide low-level access to the HTTP and IPP
+protocols and CUPS scheduler. They are typically used by monitoring and
+administration programs to perform specific functions not supported by the
+high-level CUPS API functions.</p>
+
+<p>The HTTP APIs use an opaque structure called
+<a href='#http_t'><code>http_t</code></a> to manage connections to
+a particular HTTP or IPP server. The
+<a href='#httpConnectEncrypt'><code>httpConnectEncrypt</code></a> function is
+used to create an instance of this structure for a particular server.
+The constant <code>CUPS_HTTP_DEFAULT</code> can be used with all of the
+<code>cups</code> functions to refer to the default CUPS server - the functions
+create a per-thread <a href='#http_t'><code>http_t</code></a> as needed.</p>
+
+<p>The IPP APIs use two structures for requests (messages sent to the CUPS
+scheduler) and responses (messages sent back to your application from the
+scheduler). The <a href='#ipp_t'><code>ipp_t</code></a> structure holds a
+complete request or response and is allocated using the
+<a href='#ippNew'><code>ippNew</code></a> or
+<a href='#ippNewRequest'><code>ippNewRequest</code></a> functions and
+freed using the <a href='#ippDelete'><code>ippDelete</code></a> function.</p>
+
+<p>The second structure is called
+<a href='#ipp_attribute_t'><code>ipp_attribute_t</code></a> and holds a
+single IPP attribute which consists of a group tag (<code>group_tag</code>), a
+value type tag (<code>value_tag</code>), the attribute name (<code>name</code>),
+and 1 or more values (<code>values[]</code>). Attributes are added to an
+<a href='#ipp_t'><code>ipp_t</code></a> structure using one of the
+<code>ippAdd</code> functions. For example, use
+<a href='#ippAddString'><code>ippAddString</code></a> to add a
+"requesting-user-name" string attribute to a request:</p>
+
+<pre class='example'>
+<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(IPP_GET_JOBS);
+
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+</pre>
+
+<p>Once you have created an IPP request, use the <code>cups</code>
+functions to send the request to and read the response from the server.
+For example, the <a href='#cupsDoRequest'><code>cupsDoRequest</code></a>
+function can be used for simple query operations that do not involve files:</p>
+
+<pre class='example'>
+#include &lt;cups/cups.h&gt;
+
+
+<a href='#ipp_t'>ipp_t</a> *<a name='get_jobs'>get_jobs</a>(void)
+{
+ <a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(IPP_GET_JOBS);
+
+ <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ return (<a href='#cupsDoRequest'>cupsDoRequest</a>(CUPS_HTTP_DEFAULT, request, "/"));
+}
+</pre>
+
+<p>The <a href='#cupsDoRequest'><code>cupsDoRequest</code></a> function frees
+the request structure and returns an IPP response structure or NULL pointer if
+the request could not be sent to the server. Once you have a response from
+the server, you can either use the
+<a href='#ippFindAttribute'><code>ippFindAttribute</code></a> and
+<a href='#ippFindNextAttribute'><code>ippFindNextAttribute</code></a> functions
+to find specific attributes, for example:</p>
+
+<pre class='example'>
+<a href='#ipp_t'>ipp_t</a> *response;
+<a href='#ipp_attribute_t'>ipp_attribute_t</a> *attr;
+
+attr = <a href='#ippFindAttribute'>ippFindAttribute</a>(response, "printer-state", IPP_TAG_ENUM);
+</pre>
+
+<p>You can also walk the list of attributes with a simple <code>for</code> loop
+like this:</p>
+
+<pre class='example'>
+<a href='#ipp_t'>ipp_t</a> *response;
+<a href='#ipp_attribute_t'>ipp_attribute_t</a> *attr;
+
+for (attr = response->attrs; attr != NULL; attr = attr->next)
+ if (attr->name == NULL)
+ puts("--SEPARATOR--");
+ else
+ puts(attr->name);
+</pre>
+
+<p>The <code>for</code> loop approach is normally used when collecting
+attributes for multiple objects (jobs, printers, etc.) in a response. Attributes
+with <code>NULL</code> names indicate a separator between the attributes of
+each object. For example, the following code will list the jobs returned from
+our previous <a href='#get_jobs'><code>get_jobs</code></a> example code:</p>
+
+<pre class='example'>
+<a href='#ipp_t'>ipp_t</a> *response = <a href='#get_jobs'>get_jobs</a>();
+
+if (response != NULL)
+{
+ <a href='#ipp_attribute_t'>ipp_attribute_t</a> *attr;
+ int job_id = 0;
+ char *job_name = NULL;
+ char *job_originating_user_name = NULL;
+
+ puts("Job ID Owner Title");
+ puts("------ ---------------- ---------------------------------");
+
+ for (attr = response->attrs; attr != NULL; attr = attr->next)
+ {
+ /* Attributes without names are separators between jobs */
+ if (attr->name == NULL)
+ {
+ if (job_id > 0 &amp;&amp; job_name != NULL &amp;&amp; job_originating_user_name != NULL)
+ printf("%5d %-16s %s\n", job_id, job_originating_user_name, job_name);
+
+ job_id = 0;
+ job_name = NULL;
+ job_originating_user_name = NULL;
+ continue;
+ }
+ else if (!strcmp(attr->name, "job-id") &amp;&amp; attr->value_tag == IPP_TAG_INTEGER)
+ job_id = attr->values[0].integer;
+ else if (!strcmp(attr->name, "job-name") &amp;&amp; attr->value_tag == IPP_TAG_NAME)
+ job_name = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "job-originating-user-name") &amp;&amp;
+ attr->value_tag == IPP_TAG_NAME)
+ job_originating_user_name = attr->values[0].string.text;
+ }
+
+ if (job_id > 0 &amp;&amp; job_name != NULL &amp;&amp; job_originating_user_name != NULL)
+ printf("%5d %-16s %s\n", job_id, job_originating_user_name, job_name);
+}
+</pre>
+
+<h3><a name='CREATING_URI_STRINGS'>Creating URI Strings</a></h3>
+
+<p>To ensure proper encoding, the
+<a href='#httpAssembleURIf'><code>httpAssembleURIf</code></a> function must be
+used to format a "printer-uri" string for all printer-based requests:</p>
+
+<pre class='example'>
+const char *name = "Foo";
+char uri[1024];
+<a href='#ipp_t'>ipp_t</a> *request;
+
+<a href='#httpAssembleURIf'>httpAssembleURIf</a>(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, cupsServer(),
+ ippPort(), "/printers/%s", name);
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
+</pre>
+
+<h3><a name='SENDING_REQUESTS_WITH_FILES'>Sending Requests with Files</a></h3>
+
+<p>The <a href='#cupsDoFileRequest'><code>cupsDoFileRequest</code></a> and
+<a href='#cupsDoIORequest'><code>cupsDoIORequest</code></a> functions are
+used for requests involving files. The
+<a href='#cupsDoFileRequest'><code>cupsDoFileRequest</code></a> function
+attaches the named file to a request and is typically used when sending a print
+file or changing a printer's PPD file:</p>
+
+<pre class='example'>
+const char *filename = "/usr/share/cups/data/testprint.ps";
+const char *name = "Foo";
+char uri[1024];
+char resource[1024];
+<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(IPP_PRINT_JOB);
+<a href='#ipp_t'>ipp_t</a> *response;
+
+/* Use httpAssembleURIf for the printer-uri string */
+<a href='#httpAssembleURIf'>httpAssembleURIf</a>(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, cupsServer(),
+ ippPort(), "/printers/%s", name);
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
+ NULL, "testprint.ps");
+
+/* Use snprintf for the resource path */
+snprintf(resource, sizeof(resource), "/printers/%s", name);
+
+response = <a href='#cupsDoFileRequest'>cupsDoFileRequest</a>(CUPS_HTTP_DEFAULT, request, resource, filename);
+</pre>
+
+<p>The <a href='#cupsDoIORequest'><code>cupsDoIORequest</code></a> function
+optionally attaches a file to the request and optionally saves a file in the
+response from the server. It is used when using a pipe for the request
+attachment or when using a request that returns a file, currently only
+<code>CUPS_GET_DOCUMENT</code> and <code>CUPS_GET_PPD</code>. For example,
+the following code will download the PPD file for the sample HP LaserJet
+printer driver:</p>
+
+<pre class='example'>
+char tempfile[1024];
+int tempfd;
+<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(CUPS_GET_PPD);
+<a href='#ipp_t'>ipp_t</a> *response;
+
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name",
+ NULL, "laserjet.ppd");
+
+tempfd = cupsTempFd(tempfile, sizeof(tempfile));
+
+response = <a href='#cupsDoIORequest'>cupsDoIORequest</a>(CUPS_HTTP_DEFAULT, request, "/", -1, tempfd);
+</pre>
+
+<p>The example passes <code>-1</code> for the input file descriptor to specify
+that no file is to be attached to the request. The PPD file attached to the
+response is written to the temporary file descriptor we created using the
+<code>cupsTempFd</code> function.</p>
+
+<h3><a name='ASYNCHRONOUS_REQUEST_PROCESSING'>Asynchronous Request Processing</a></h3>
+
+<p>The <a href='#cupsSendRequest'><code>cupsSendRequest</code></a> and
+<a href='#cupsGetResponse'><code>cupsGetResponse</code></a> support
+asynchronous communications with the server. Unlike the other request
+functions, the IPP request is not automatically freed, so remember to
+free your request with the <a href='#ippDelete'><code>ippDelete</code></a>
+function.</p>
+
+<p>File data is attached to the request using the
+<a href='#cupsWriteRequestData'><code>cupsWriteRequestData</code></a>
+function, while file data returned from the server is read using the
+<a href='#cupsReadResponseData'><code>cupsReadResponseData</code></a>
+function. We can rewrite the previous <code>CUPS_GET_PPD</code> example
+to use the asynchronous functions quite easily:</p>
+
+<pre class='example'>
+char tempfile[1024];
+int tempfd;
+<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(CUPS_GET_PPD);
+<a href='#ipp_t'>ipp_t</a> *response;
+
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name",
+ NULL, "laserjet.ppd");
+
+tempfd = cupsTempFd(tempfile, sizeof(tempfile));
+
+if (<a href='#cupsSendRequest'>cupsSendRequest</a>(CUPS_HTTP_DEFAULT, request, "/") == HTTP_CONTINUE)
+{
+ response = <a href='#cupsGetResponse'>cupsGetResponse</a>(CUPS_HTTP_DEFAULT, "/");
+
+ if (response != NULL)
+ {
+ ssize_t bytes;
+ char buffer[8192];
+
+ while ((bytes = <a href='#cupsReadResponseData'>cupsReadResponseData</a>(CUPS_HTTP_DEFAULT, buffer, sizeof(buffer))) > 0)
+ write(tempfd, buffer, bytes);
+ }
+}
+
+/* Free the request! */
+<a href='#ippDelete'>ippDelete</a>(request);
+</pre>
+
+<p>The <a href='#cupsSendRequest'><code>cupsSendRequest</code></a> function
+returns the initial HTTP request status, typically either
+<code>HTTP_CONTINUE</code> or <code>HTTP_UNAUTHORIZED</code>. The latter status
+is returned when the request requires authentication of some sort. The
+<a href='#cupsDoAuthentication'><code>cupsDoAuthentication</code></a> function
+must be called when your see <code>HTTP_UNAUTHORIZED</code> and the request
+re-sent. We can add authentication support to our example code by using a
+<code>do ... while</code> loop:</p>
+
+<pre class='example'>
+char tempfile[1024];
+int tempfd;
+<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(CUPS_GET_PPD);
+<a href='#ipp_t'>ipp_t</a> *response;
+http_status_t status;
+
+<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name",
+ NULL, "laserjet.ppd");
+
+tempfd = cupsTempFd(tempfile, sizeof(tempfile));
+
+/* Loop for authentication */
+do
+{
+ status = <a href='#cupsSendRequest'>cupsSendRequest</a>(CUPS_HTTP_DEFAULT, request, "/");
+
+ if (status == HTTP_UNAUTHORIZED)
+ {
+ /* Try to authenticate, break out of the loop if that fails */
+ if (<a href='#cupsDoAuthentication'>cupsDoAuthentication</a>(CUPS_HTTP_DEFAULT, "POST", "/"))
+ break;
+ }
+}
+while (status != HTTP_CONTINUE &amp;&amp; status != HTTP_UNAUTHORIZED);
+
+if (status == HTTP_CONTINUE)
+{
+ response = <a href='#cupsGetResponse'>cupsGetResponse</a>(CUPS_HTTP_DEFAULT, "/");
+
+ if (response != NULL)
+ {
+ ssize_t bytes;
+ char buffer[8192];
+
+ while ((bytes = <a href='#cupsReadResponseData'>cupsReadResponseData</a>(CUPS_HTTP_DEFAULT, buffer, sizeof(buffer))) > 0)
+ write(tempfd, buffer, bytes);
+ }
+}
+
+/* Free the request! */
+<a href='#ippDelete'>ippDelete</a>(request);
+</pre>
+<h2 class="title"><a name="FUNCTIONS">Functions</a></h2>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.20/Mac OS X 10.4&nbsp;</span><a name="cupsDoAuthentication">cupsDoAuthentication</a></h3>
+<p class="description">Authenticate a request.</p>
+<p class="code">
+int cupsDoAuthentication (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *method,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resource<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>method</dt>
+<dd class="description">Request method (&quot;GET&quot;, &quot;POST&quot;, &quot;PUT&quot;)</dd>
+<dt>resource</dt>
+<dd class="description">Resource path</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function should be called in response to a <code>HTTP_UNAUTHORIZED</code>
+status, prior to resubmitting your request.
+
+</p>
+<h3 class="function"><a name="cupsDoFileRequest">cupsDoFileRequest</a></h3>
+<p class="description">Do an IPP request with a file.</p>
+<p class="code">
+<a href="#ipp_t">ipp_t</a> *cupsDoFileRequest (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *request,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resource,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *filename<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>request</dt>
+<dd class="description">IPP request</dd>
+<dt>resource</dt>
+<dd class="description">HTTP resource for POST</dd>
+<dt>filename</dt>
+<dd class="description">File to send or <code>NULL</code> for none</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Response data</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function sends the IPP request to the specified server, retrying
+and authenticating as necessary. The request is freed with <a href="#ippDelete"><code>ippDelete</code></a>
+after receiving a valid IPP response.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="cupsDoIORequest">cupsDoIORequest</a></h3>
+<p class="description">Do an IPP request with file descriptors.</p>
+<p class="code">
+<a href="#ipp_t">ipp_t</a> *cupsDoIORequest (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *request,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resource,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int infile,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int outfile<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>request</dt>
+<dd class="description">IPP request</dd>
+<dt>resource</dt>
+<dd class="description">HTTP resource for POST</dd>
+<dt>infile</dt>
+<dd class="description">File to read from or -1 for none</dd>
+<dt>outfile</dt>
+<dd class="description">File to write to or -1 for none</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Response data</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function sends the IPP request to the specified server, retrying
+and authenticating as necessary. The request is freed with ippDelete()
+after receiving a valid IPP response.<br>
+<br>
+If &quot;infile&quot; is a valid file descriptor, cupsDoIORequest() copies
+all of the data from the file after the IPP request message.<br>
+<br>
+If &quot;outfile&quot; is a valid file descriptor, cupsDoIORequest() copies
+all of the data after the IPP response message to the file.
+
+</p>
+<h3 class="function"><a name="cupsDoRequest">cupsDoRequest</a></h3>
+<p class="description">Do an IPP request.</p>
+<p class="code">
+<a href="#ipp_t">ipp_t</a> *cupsDoRequest (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *request,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resource<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>request</dt>
+<dd class="description">IPP request</dd>
+<dt>resource</dt>
+<dd class="description">HTTP resource for POST</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Response data</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function sends the IPP request to the specified server, retrying
+and authenticating as necessary. The request is freed with ippDelete()
+after receiving a valid IPP response.</p>
+<h3 class="function"><a name="cupsEncodeOptions">cupsEncodeOptions</a></h3>
+<p class="description">Encode printer options into IPP attributes.</p>
+<p class="code">
+void cupsEncodeOptions (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_option_t *options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">Request to add to</dd>
+<dt>num_options</dt>
+<dd class="description">Number of options</dd>
+<dt>options</dt>
+<dd class="description">Options</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function adds operation, job, and then subscription attributes,
+in that order. Use the cupsEncodeOptions2() function to add attributes
+for a single group.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsEncodeOptions2">cupsEncodeOptions2</a></h3>
+<p class="description">Encode printer options into IPP attributes for a group.</p>
+<p class="code">
+void cupsEncodeOptions2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_option_t *options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group_tag<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">Request to add to</dd>
+<dt>num_options</dt>
+<dd class="description">Number of options</dd>
+<dt>options</dt>
+<dd class="description">Options</dd>
+<dt>group_tag</dt>
+<dd class="description">Group to encode</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function only adds attributes for a single group. Call this
+function multiple times for each group, or use cupsEncodeOptions()
+to add the standard groups.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsGetDevices">cupsGetDevices</a></h3>
+<p class="description">Get available printer devices.</p>
+<p class="code">
+ipp_status_t cupsGetDevices (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int timeout,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *include_schemes,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *exclude_schemes,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_device_cb_t callback,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *user_data<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>timeout</dt>
+<dd class="description">Timeout in seconds or <code>CUPS_TIMEOUT_DEFAULT</code></dd>
+<dt>include_schemes</dt>
+<dd class="description">Comma-separated URI schemes to include or <code>CUPS_INCLUDE_ALL</code></dd>
+<dt>exclude_schemes</dt>
+<dd class="description">Comma-separated URI schemes to exclude or <code>CUPS_EXCLUDE_NONE</code></dd>
+<dt>callback</dt>
+<dd class="description">Callback function</dd>
+<dt>user_data</dt>
+<dd class="description">User data pointer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Request status - <code>IPP_OK</code> on success.</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function sends a CUPS-Get-Devices request and streams the discovered
+devices to the specified callback function. The &quot;timeout&quot; parameter controls
+how long the request lasts, while the &quot;include_schemes&quot; and &quot;exclude_schemes&quot;
+parameters provide comma-delimited lists of backends to include or omit from
+the request respectively.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.20/Mac OS X 10.4&nbsp;</span><a name="cupsGetFd">cupsGetFd</a></h3>
+<p class="description">Get a file from the server.</p>
+<p class="code">
+<a href="#http_status_t">http_status_t</a> cupsGetFd (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resource,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int fd<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>resource</dt>
+<dd class="description">Resource name</dd>
+<dt>fd</dt>
+<dd class="description">File descriptor</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">HTTP status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns <code>HTTP_OK</code> when the file is successfully retrieved.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.20/Mac OS X 10.4&nbsp;</span><a name="cupsGetFile">cupsGetFile</a></h3>
+<p class="description">Get a file from the server.</p>
+<p class="code">
+<a href="#http_status_t">http_status_t</a> cupsGetFile (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resource,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *filename<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>resource</dt>
+<dd class="description">Resource name</dd>
+<dt>filename</dt>
+<dd class="description">Filename</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">HTTP status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns <code>HTTP_OK</code> when the file is successfully retrieved.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsGetResponse">cupsGetResponse</a></h3>
+<p class="description">Get a response to an IPP request.</p>
+<p class="code">
+<a href="#ipp_t">ipp_t</a> *cupsGetResponse (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resource<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>resource</dt>
+<dd class="description">HTTP resource for POST</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Response or <code>NULL</code> on HTTP error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Use this function to get the response for an IPP request sent using
+cupsSendDocument() or cupsSendRequest(). For requests that return
+additional data, use httpRead() after getting a successful response.
+
+</p>
+<h3 class="function"><a name="cupsLastError">cupsLastError</a></h3>
+<p class="description">Return the last IPP status code.</p>
+<p class="code">
+ipp_status_t cupsLastError (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">IPP status code from last request</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsLastErrorString">cupsLastErrorString</a></h3>
+<p class="description">Return the last IPP status-message.</p>
+<p class="code">
+const char *cupsLastErrorString (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">status-message text from last request</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.20/Mac OS X 10.4&nbsp;</span><a name="cupsPutFd">cupsPutFd</a></h3>
+<p class="description">Put a file on the server.</p>
+<p class="code">
+<a href="#http_status_t">http_status_t</a> cupsPutFd (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resource,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int fd<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>resource</dt>
+<dd class="description">Resource name</dd>
+<dt>fd</dt>
+<dd class="description">File descriptor</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">HTTP status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns <code>HTTP_CREATED</code> when the file is stored
+successfully.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.20/Mac OS X 10.4&nbsp;</span><a name="cupsPutFile">cupsPutFile</a></h3>
+<p class="description">Put a file on the server.</p>
+<p class="code">
+<a href="#http_status_t">http_status_t</a> cupsPutFile (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resource,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *filename<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>resource</dt>
+<dd class="description">Resource name</dd>
+<dt>filename</dt>
+<dd class="description">Filename</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">HTTP status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns <code>HTTP_CREATED</code> when the file is stored
+successfully.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsReadResponseData">cupsReadResponseData</a></h3>
+<p class="description">Read additional data after the IPP response.</p>
+<p class="code">
+ssize_t cupsReadResponseData (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *buffer,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t length<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>buffer</dt>
+<dd class="description">Buffer to use</dd>
+<dt>length</dt>
+<dd class="description">Number of bytes to read</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Bytes read, 0 on EOF, -1 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is used after cupsGetResponse() to read the PPD or document
+files for CUPS_GET_PPD and CUPS_GET_DOCUMENT requests, respectively.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsSendRequest">cupsSendRequest</a></h3>
+<p class="description">Send an IPP request.</p>
+<p class="code">
+<a href="#http_status_t">http_status_t</a> cupsSendRequest (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *request,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resource,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t length<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>request</dt>
+<dd class="description">IPP request</dd>
+<dt>resource</dt>
+<dd class="description">Resource path</dd>
+<dt>length</dt>
+<dd class="description">Length of data to follow or <code>CUPS_LENGTH_VARIABLE</code></dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Initial HTTP status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Use httpWrite() to write any additional data (document, PPD file, etc.)
+for the request, cupsGetResponse() to get the IPP response, and httpRead()
+to read any additional data following the response. Only one request can be
+sent/queued at a time.<br>
+<br>
+Unlike cupsDoFileRequest(), cupsDoIORequest(), and cupsDoRequest(), the
+request is not freed.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsWriteRequestData">cupsWriteRequestData</a></h3>
+<p class="description">Write additional data after an IPP request.</p>
+<p class="code">
+<a href="#http_status_t">http_status_t</a> cupsWriteRequestData (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *buffer,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t length<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>buffer</dt>
+<dd class="description">Bytes to write</dd>
+<dt>length</dt>
+<dd class="description">Number of bytes to write</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description"><code>HTTP_CONTINUE</code> if OK or HTTP status on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is used after <a href="#cupsSendRequest"><code>cupsSendRequest</code></a> to provide a PPD and
+after <a href="#cupsStartDocument"><code>cupsStartDocument</code></a> to provide a document file.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span><a name="httpAddCredential">httpAddCredential</a></h3>
+<p class="description">Allocates and adds a single credential to an array.</p>
+<p class="code">
+int httpAddCredential (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_array_t *credentials,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const void *data,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t datalen<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>credentials</dt>
+<dd class="description">Credentials array</dd>
+<dt>data</dt>
+<dd class="description">PEM-encoded X.509 data</dd>
+<dt>datalen</dt>
+<dd class="description">Length of data</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Use <code>cupsArrayNew(NULL, NULL)</code> to create a credentials array.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpAddrAny">httpAddrAny</a></h3>
+<p class="description">Check for the &quot;any&quot; address.</p>
+<p class="code">
+int httpAddrAny (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#http_addr_t">http_addr_t</a> *addr<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>addr</dt>
+<dd class="description">Address to check</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if &quot;any&quot;, 0 otherwise</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpAddrEqual">httpAddrEqual</a></h3>
+<p class="description">Compare two addresses.</p>
+<p class="code">
+int httpAddrEqual (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#http_addr_t">http_addr_t</a> *addr1,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#http_addr_t">http_addr_t</a> *addr2<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>addr1</dt>
+<dd class="description">First address</dd>
+<dt>addr2</dt>
+<dd class="description">Second address</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if equal, 0 if not</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpAddrLength">httpAddrLength</a></h3>
+<p class="description">Return the length of the address in bytes.</p>
+<p class="code">
+int httpAddrLength (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#http_addr_t">http_addr_t</a> *addr<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>addr</dt>
+<dd class="description">Address</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Length in bytes</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpAddrLocalhost">httpAddrLocalhost</a></h3>
+<p class="description">Check for the local loopback address.</p>
+<p class="code">
+int httpAddrLocalhost (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#http_addr_t">http_addr_t</a> *addr<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>addr</dt>
+<dd class="description">Address to check</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if local host, 0 otherwise</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpAddrLookup">httpAddrLookup</a></h3>
+<p class="description">Lookup the hostname associated with the address.</p>
+<p class="code">
+char *httpAddrLookup (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#http_addr_t">http_addr_t</a> *addr,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int namelen<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>addr</dt>
+<dd class="description">Address to lookup</dd>
+<dt>name</dt>
+<dd class="description">Host name buffer</dd>
+<dt>namelen</dt>
+<dd class="description">Size of name buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Host name</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpAddrString">httpAddrString</a></h3>
+<p class="description">Convert an address to a numeric string.</p>
+<p class="code">
+char *httpAddrString (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#http_addr_t">http_addr_t</a> *addr,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *s,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int slen<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>addr</dt>
+<dd class="description">Address to convert</dd>
+<dt>s</dt>
+<dd class="description">String buffer</dd>
+<dt>slen</dt>
+<dd class="description">Length of string</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Numeric address string</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpAssembleURI">httpAssembleURI</a></h3>
+<p class="description">Assemble a uniform resource identifier from its
+components.</p>
+<p class="code">
+<a href="#http_uri_status_t">http_uri_status_t</a> httpAssembleURI (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_uri_coding_t">http_uri_coding_t</a> encoding,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *uri,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int urilen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *scheme,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *username,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *host,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int port,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resource<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>encoding</dt>
+<dd class="description">Encoding flags</dd>
+<dt>uri</dt>
+<dd class="description">URI buffer</dd>
+<dt>urilen</dt>
+<dd class="description">Size of URI buffer</dd>
+<dt>scheme</dt>
+<dd class="description">Scheme name</dd>
+<dt>username</dt>
+<dd class="description">Username</dd>
+<dt>host</dt>
+<dd class="description">Hostname or address</dd>
+<dt>port</dt>
+<dd class="description">Port number</dd>
+<dt>resource</dt>
+<dd class="description">Resource</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">URI status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function escapes reserved characters in the URI depending on the
+value of the &quot;encoding&quot; argument. You should use this function in
+place of traditional string functions whenever you need to create a
+URI string.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpAssembleURIf">httpAssembleURIf</a></h3>
+<p class="description">Assemble a uniform resource identifier from its
+components with a formatted resource.</p>
+<p class="code">
+<a href="#http_uri_status_t">http_uri_status_t</a> httpAssembleURIf (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_uri_coding_t">http_uri_coding_t</a> encoding,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *uri,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int urilen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *scheme,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *username,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *host,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int port,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resourcef,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;...<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>encoding</dt>
+<dd class="description">Encoding flags</dd>
+<dt>uri</dt>
+<dd class="description">URI buffer</dd>
+<dt>urilen</dt>
+<dd class="description">Size of URI buffer</dd>
+<dt>scheme</dt>
+<dd class="description">Scheme name</dd>
+<dt>username</dt>
+<dd class="description">Username</dd>
+<dt>host</dt>
+<dd class="description">Hostname or address</dd>
+<dt>port</dt>
+<dd class="description">Port number</dd>
+<dt>resourcef</dt>
+<dd class="description">Printf-style resource</dd>
+<dt>...</dt>
+<dd class="description">Additional arguments as needed</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">URI status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function creates a formatted version of the resource string
+argument &quot;resourcef&quot; and escapes reserved characters in the URI
+depending on the value of the &quot;encoding&quot; argument. You should use
+this function in place of traditional string functions whenever
+you need to create a URI string.
+
+</p>
+<h3 class="function"><a name="httpBlocking">httpBlocking</a></h3>
+<p class="description">Set blocking/non-blocking behavior on a connection.</p>
+<p class="code">
+void httpBlocking (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int b<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>b</dt>
+<dd class="description">1 = blocking, 0 = non-blocking</dd>
+</dl>
+<h3 class="function"><a name="httpCheck">httpCheck</a></h3>
+<p class="description">Check to see if there is a pending response from the server.</p>
+<p class="code">
+int httpCheck (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 = no data, 1 = data available</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="httpClearCookie">httpClearCookie</a></h3>
+<p class="description">Clear the cookie value(s).</p>
+<p class="code">
+void httpClearCookie (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h3 class="function"><a name="httpClearFields">httpClearFields</a></h3>
+<p class="description">Clear HTTP request fields.</p>
+<p class="code">
+void httpClearFields (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h3 class="function"><a name="httpClose">httpClose</a></h3>
+<p class="description">Close an HTTP connection.</p>
+<p class="code">
+void httpClose (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="httpConnect">httpConnect</a></h3>
+<p class="description">Connect to a HTTP server.</p>
+<p class="code">
+<a href="#http_t">http_t</a> *httpConnect (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *host,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int port<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>host</dt>
+<dd class="description">Host to connect to</dd>
+<dt>port</dt>
+<dd class="description">Port number</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New HTTP connection</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is deprecated - use <a href="#httpConnectEncrypt"><code>httpConnectEncrypt</code></a> instead.
+
+</p>
+<h3 class="function"><a name="httpConnectEncrypt">httpConnectEncrypt</a></h3>
+<p class="description">Connect to a HTTP server using encryption.</p>
+<p class="code">
+<a href="#http_t">http_t</a> *httpConnectEncrypt (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *host,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int port,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_encryption_t">http_encryption_t</a> encryption<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>host</dt>
+<dd class="description">Host to connect to</dd>
+<dt>port</dt>
+<dd class="description">Port number</dd>
+<dt>encryption</dt>
+<dd class="description">Type of encryption to use</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New HTTP connection</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span><a name="httpCopyCredentials">httpCopyCredentials</a></h3>
+<p class="description">Copy the credentials associated with an encrypted
+connection.</p>
+<p class="code">
+int httpCopyCredentials (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_array_t **credentials<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>credentials</dt>
+<dd class="description">Array of credentials</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of call (0 = success)</p>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="httpDecode64">httpDecode64</a></h3>
+<p class="description">Base64-decode a string.</p>
+<p class="code">
+char *httpDecode64 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *out,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *in<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>out</dt>
+<dd class="description">String to write to</dd>
+<dt>in</dt>
+<dd class="description">String to read from</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Decoded string</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is deprecated. Use the httpDecode64_2() function instead
+which provides buffer length arguments.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.21/Mac OS X 10.4&nbsp;</span><a name="httpDecode64_2">httpDecode64_2</a></h3>
+<p class="description">Base64-decode a string.</p>
+<p class="code">
+char *httpDecode64_2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *out,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *outlen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *in<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>out</dt>
+<dd class="description">String to write to</dd>
+<dt>outlen</dt>
+<dd class="description">Size of output string</dd>
+<dt>in</dt>
+<dd class="description">String to read from</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Decoded string</p>
+<h3 class="function"><a name="httpDelete">httpDelete</a></h3>
+<p class="description">Send a DELETE request to the server.</p>
+<p class="code">
+int httpDelete (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *uri<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>uri</dt>
+<dd class="description">URI to delete</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of call (0 = success)</p>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="httpEncode64">httpEncode64</a></h3>
+<p class="description">Base64-encode a string.</p>
+<p class="code">
+char *httpEncode64 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *out,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *in<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>out</dt>
+<dd class="description">String to write to</dd>
+<dt>in</dt>
+<dd class="description">String to read from</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Encoded string</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is deprecated. Use the httpEncode64_2() function instead
+which provides buffer length arguments.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.21/Mac OS X 10.4&nbsp;</span><a name="httpEncode64_2">httpEncode64_2</a></h3>
+<p class="description">Base64-encode a string.</p>
+<p class="code">
+char *httpEncode64_2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *out,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int outlen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *in,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int inlen<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>out</dt>
+<dd class="description">String to write to</dd>
+<dt>outlen</dt>
+<dd class="description">Size of output string</dd>
+<dt>in</dt>
+<dd class="description">String to read from</dd>
+<dt>inlen</dt>
+<dd class="description">Size of input string</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Encoded string</p>
+<h3 class="function"><a name="httpEncryption">httpEncryption</a></h3>
+<p class="description">Set the required encryption on the link.</p>
+<p class="code">
+int httpEncryption (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_encryption_t">http_encryption_t</a> e<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>e</dt>
+<dd class="description">New encryption preference</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">-1 on error, 0 on success</p>
+<h3 class="function"><a name="httpError">httpError</a></h3>
+<p class="description">Get the last error on a connection.</p>
+<p class="code">
+int httpError (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Error code (errno) value</p>
+<h3 class="function"><a name="httpFlush">httpFlush</a></h3>
+<p class="description">Flush data from a HTTP connection.</p>
+<p class="code">
+void httpFlush (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpFlushWrite">httpFlushWrite</a></h3>
+<p class="description">Flush data in write buffer.</p>
+<p class="code">
+int httpFlushWrite (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Bytes written or -1 on error</p>
+<h3 class="function"><a name="httpFreeCredentials">httpFreeCredentials</a></h3>
+<p class="description">Free an array of credentials.</p>
+<p class="code">
+void httpFreeCredentials (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_array_t *credentials<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>credentials</dt>
+<dd class="description">Array of credentials</dd>
+</dl>
+<h3 class="function"><a name="httpGet">httpGet</a></h3>
+<p class="description">Send a GET request to the server.</p>
+<p class="code">
+int httpGet (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *uri<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>uri</dt>
+<dd class="description">URI to get</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of call (0 = success)</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="httpGetAuthString">httpGetAuthString</a></h3>
+<p class="description">Get the current authorization string.</p>
+<p class="code">
+char *httpGetAuthString (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Authorization string</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The authorization string is set by cupsDoAuthentication() and
+httpSetAuthString(). Use httpGetAuthString() to retrieve the
+string to use with httpSetField() for the HTTP_FIELD_AUTHORIZATION
+value.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpGetBlocking">httpGetBlocking</a></h3>
+<p class="description">Get the blocking/non-block state of a connection.</p>
+<p class="code">
+int httpGetBlocking (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if blocking, 0 if non-blocking</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="httpGetCookie">httpGetCookie</a></h3>
+<p class="description">Get any cookie data from the response.</p>
+<p class="code">
+const char *httpGetCookie (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">HTTP connecion</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Cookie data or NULL</p>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="httpGetDateString">httpGetDateString</a></h3>
+<p class="description">Get a formatted date/time string from a time value.</p>
+<p class="code">
+const char *httpGetDateString (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;time_t t<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>t</dt>
+<dd class="description">UNIX time</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Date/time string</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpGetDateString2">httpGetDateString2</a></h3>
+<p class="description">Get a formatted date/time string from a time value.</p>
+<p class="code">
+const char *httpGetDateString2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;time_t t,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *s,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int slen<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>t</dt>
+<dd class="description">UNIX time</dd>
+<dt>s</dt>
+<dd class="description">String buffer</dd>
+<dt>slen</dt>
+<dd class="description">Size of string buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Date/time string</p>
+<h3 class="function"><a name="httpGetDateTime">httpGetDateTime</a></h3>
+<p class="description">Get a time value from a formatted date/time string.</p>
+<p class="code">
+time_t httpGetDateTime (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *s<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>s</dt>
+<dd class="description">Date/time string</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">UNIX time</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpGetFd">httpGetFd</a></h3>
+<p class="description">Get the file descriptor associated with a connection.</p>
+<p class="code">
+int httpGetFd (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">File descriptor or -1 if none</p>
+<h3 class="function"><a name="httpGetField">httpGetField</a></h3>
+<p class="description">Get a field value from a request/response.</p>
+<p class="code">
+const char *httpGetField (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_field_t">http_field_t</a> field<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>field</dt>
+<dd class="description">Field to get</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Field value</p>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="httpGetHostByName">httpGetHostByName</a></h3>
+<p class="description">Lookup a hostname or IPv4 address, and return
+address records for the specified name.</p>
+<p class="code">
+struct hostent *httpGetHostByName (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Hostname or IP address</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Host entry</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpGetHostname">httpGetHostname</a></h3>
+<p class="description">Get the FQDN for the connection or local system.</p>
+<p class="code">
+const char *httpGetHostname (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *s,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int slen<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">HTTP connection or NULL</dd>
+<dt>s</dt>
+<dd class="description">String buffer for name</dd>
+<dt>slen</dt>
+<dd class="description">Size of buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">FQDN for connection or system</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">When &quot;http&quot; points to a connected socket, return the hostname or
+address that was used in the call to httpConnect() or httpConnectEncrypt().
+Otherwise, return the FQDN for the local system using both gethostname()
+and gethostbyname() to get the local hostname with domain.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="httpGetLength">httpGetLength</a></h3>
+<p class="description">Get the amount of data remaining from the
+content-length or transfer-encoding fields.</p>
+<p class="code">
+int httpGetLength (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Content length</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is deprecated and will not return lengths larger than
+2^31 - 1; use httpGetLength2() instead.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpGetLength2">httpGetLength2</a></h3>
+<p class="description">Get the amount of data remaining from the
+content-length or transfer-encoding fields.</p>
+<p class="code">
+off_t httpGetLength2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Content length</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns the complete content length, even for
+content larger than 2^31 - 1.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpGetStatus">httpGetStatus</a></h3>
+<p class="description">Get the status of the last HTTP request.</p>
+<p class="code">
+<a href="#http_status_t">http_status_t</a> httpGetStatus (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">HTTP status</p>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="httpGetSubField">httpGetSubField</a></h3>
+<p class="description">Get a sub-field value.</p>
+<p class="code">
+char *httpGetSubField (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_field_t">http_field_t</a> field,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *value<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>field</dt>
+<dd class="description">Field index</dd>
+<dt>name</dt>
+<dd class="description">Name of sub-field</dd>
+<dt>value</dt>
+<dd class="description">Value string</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Value or NULL</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpGetSubField2">httpGetSubField2</a></h3>
+<p class="description">Get a sub-field value.</p>
+<p class="code">
+char *httpGetSubField2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_field_t">http_field_t</a> field,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *value,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int valuelen<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>field</dt>
+<dd class="description">Field index</dd>
+<dt>name</dt>
+<dd class="description">Name of sub-field</dd>
+<dt>value</dt>
+<dd class="description">Value string</dd>
+<dt>valuelen</dt>
+<dd class="description">Size of value buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Value or NULL</p>
+<h3 class="function"><a name="httpGets">httpGets</a></h3>
+<p class="description">Get a line of text from a HTTP connection.</p>
+<p class="code">
+char *httpGets (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *line,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int length,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>line</dt>
+<dd class="description">Line to read into</dd>
+<dt>length</dt>
+<dd class="description">Max length of buffer</dd>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Line or NULL</p>
+<h3 class="function"><a name="httpHead">httpHead</a></h3>
+<p class="description">Send a HEAD request to the server.</p>
+<p class="code">
+int httpHead (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *uri<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>uri</dt>
+<dd class="description">URI for head</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of call (0 = success)</p>
+<h3 class="function"><a name="httpInitialize">httpInitialize</a></h3>
+<p class="description">Initialize the HTTP interface library and set the
+default HTTP proxy (if any).</p>
+<p class="code">
+void httpInitialize (void);</p>
+<h3 class="function"><a name="httpMD5">httpMD5</a></h3>
+<p class="description">Compute the MD5 sum of the username:group:password.</p>
+<p class="code">
+char *httpMD5 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *username,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *realm,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *passwd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char md5[33]<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>username</dt>
+<dd class="description">User name</dd>
+<dt>realm</dt>
+<dd class="description">Realm name</dd>
+<dt>passwd</dt>
+<dd class="description">Password string</dd>
+<dt>md5[33]</dt>
+<dd class="description">MD5 string</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">MD5 sum</p>
+<h3 class="function"><a name="httpMD5Final">httpMD5Final</a></h3>
+<p class="description">Combine the MD5 sum of the username, group, and password
+with the server-supplied nonce value, method, and
+request-uri.</p>
+<p class="code">
+char *httpMD5Final (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *nonce,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *method,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *resource,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char md5[33]<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>nonce</dt>
+<dd class="description">Server nonce value</dd>
+<dt>method</dt>
+<dd class="description">METHOD (GET, POST, etc.)</dd>
+<dt>resource</dt>
+<dd class="description">Resource path</dd>
+<dt>md5[33]</dt>
+<dd class="description">MD5 sum</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New sum</p>
+<h3 class="function"><a name="httpMD5String">httpMD5String</a></h3>
+<p class="description">Convert an MD5 sum to a character string.</p>
+<p class="code">
+char *httpMD5String (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const unsigned char *sum,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char md5[33]<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>sum</dt>
+<dd class="description">MD5 sum data</dd>
+<dt>md5[33]</dt>
+<dd class="description">MD5 sum in hex</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">MD5 sum in hex</p>
+<h3 class="function"><a name="httpOptions">httpOptions</a></h3>
+<p class="description">Send an OPTIONS request to the server.</p>
+<p class="code">
+int httpOptions (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *uri<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>uri</dt>
+<dd class="description">URI for options</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of call (0 = success)</p>
+<h3 class="function"><a name="httpPost">httpPost</a></h3>
+<p class="description">Send a POST request to the server.</p>
+<p class="code">
+int httpPost (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *uri<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>uri</dt>
+<dd class="description">URI for post</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of call (0 = success)</p>
+<h3 class="function"><a name="httpPut">httpPut</a></h3>
+<p class="description">Send a PUT request to the server.</p>
+<p class="code">
+int httpPut (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *uri<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>uri</dt>
+<dd class="description">URI to put</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of call (0 = success)</p>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="httpRead">httpRead</a></h3>
+<p class="description">Read data from a HTTP connection.</p>
+<p class="code">
+int httpRead (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *buffer,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int length<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>buffer</dt>
+<dd class="description">Buffer for data</dd>
+<dt>length</dt>
+<dd class="description">Maximum number of bytes</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of bytes read</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is deprecated. Use the httpRead2() function which can
+read more than 2GB of data.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpRead2">httpRead2</a></h3>
+<p class="description">Read data from a HTTP connection.</p>
+<p class="code">
+ssize_t httpRead2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *buffer,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t length<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>buffer</dt>
+<dd class="description">Buffer for data</dd>
+<dt>length</dt>
+<dd class="description">Maximum number of bytes</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of bytes read</p>
+<h3 class="function"><a name="httpReconnect">httpReconnect</a></h3>
+<p class="description">Reconnect to a HTTP server.</p>
+<p class="code">
+int httpReconnect (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, non-zero on failure</p>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="httpSeparate">httpSeparate</a></h3>
+<p class="description">Separate a Universal Resource Identifier into its
+components.</p>
+<p class="code">
+void httpSeparate (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *uri,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *scheme,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *username,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *host,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *port,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *resource<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>uri</dt>
+<dd class="description">Universal Resource Identifier</dd>
+<dt>scheme</dt>
+<dd class="description">Scheme [32] (http, https, etc.)</dd>
+<dt>username</dt>
+<dd class="description">Username [1024]</dd>
+<dt>host</dt>
+<dd class="description">Hostname [1024]</dd>
+<dt>port</dt>
+<dd class="description">Port number to use</dd>
+<dt>resource</dt>
+<dd class="description">Resource/filename [1024]</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is deprecated; use the httpSeparateURI() function instead.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.21/Mac OS X 10.4&nbsp;</span><a name="httpSeparate2">httpSeparate2</a></h3>
+<p class="description">Separate a Universal Resource Identifier into its
+components.</p>
+<p class="code">
+void httpSeparate2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *uri,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *scheme,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int schemelen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *username,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int usernamelen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *host,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int hostlen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *port,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *resource,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int resourcelen<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>uri</dt>
+<dd class="description">Universal Resource Identifier</dd>
+<dt>scheme</dt>
+<dd class="description">Scheme (http, https, etc.)</dd>
+<dt>schemelen</dt>
+<dd class="description">Size of scheme buffer</dd>
+<dt>username</dt>
+<dd class="description">Username</dd>
+<dt>usernamelen</dt>
+<dd class="description">Size of username buffer</dd>
+<dt>host</dt>
+<dd class="description">Hostname</dd>
+<dt>hostlen</dt>
+<dd class="description">Size of hostname buffer</dd>
+<dt>port</dt>
+<dd class="description">Port number to use</dd>
+<dt>resource</dt>
+<dd class="description">Resource/filename</dd>
+<dt>resourcelen</dt>
+<dd class="description">Size of resource buffer</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is deprecated; use the httpSeparateURI() function instead.
+
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpSeparateURI">httpSeparateURI</a></h3>
+<p class="description">Separate a Universal Resource Identifier into its
+components.</p>
+<p class="code">
+<a href="#http_uri_status_t">http_uri_status_t</a> httpSeparateURI (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_uri_coding_t">http_uri_coding_t</a> decoding,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *uri,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *scheme,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int schemelen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *username,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int usernamelen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *host,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int hostlen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *port,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *resource,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int resourcelen<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>decoding</dt>
+<dd class="description">Decoding flags</dd>
+<dt>uri</dt>
+<dd class="description">Universal Resource Identifier</dd>
+<dt>scheme</dt>
+<dd class="description">Scheme (http, https, etc.)</dd>
+<dt>schemelen</dt>
+<dd class="description">Size of scheme buffer</dd>
+<dt>username</dt>
+<dd class="description">Username</dd>
+<dt>usernamelen</dt>
+<dd class="description">Size of username buffer</dd>
+<dt>host</dt>
+<dd class="description">Hostname</dd>
+<dt>hostlen</dt>
+<dd class="description">Size of hostname buffer</dd>
+<dt>port</dt>
+<dd class="description">Port number to use</dd>
+<dt>resource</dt>
+<dd class="description">Resource/filename</dd>
+<dt>resourcelen</dt>
+<dd class="description">Size of resource buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Result of separation</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="httpSetAuthString">httpSetAuthString</a></h3>
+<p class="description">Set the current authorization string.</p>
+<p class="code">
+void httpSetAuthString (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *scheme,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *data<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>scheme</dt>
+<dd class="description">Auth scheme (NULL to clear it)</dd>
+<dt>data</dt>
+<dd class="description">Auth data (NULL for none)</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function just stores a copy of the current authorization string in
+the HTTP connection object. You must still call httpSetField() to set
+HTTP_FIELD_AUTHORIZATION prior to issuing a HTTP request using httpGet(),
+httpHead(), httpOptions(), httpPost, or httpPut().
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="httpSetCookie">httpSetCookie</a></h3>
+<p class="description">Set the cookie value(s).</p>
+<p class="code">
+void httpSetCookie (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *cookie<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection</dd>
+<dt>cookie</dt>
+<dd class="description">Cookie string</dd>
+</dl>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span><a name="httpSetCredentials">httpSetCredentials</a></h3>
+<p class="description">Set the credentials associated with an encrypted
+connection.</p>
+<p class="code">
+int httpSetCredentials (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_array_t *credentials<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>credentials</dt>
+<dd class="description">Array of credentials</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of call (0 = success)</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpSetExpect">httpSetExpect</a></h3>
+<p class="description">Set the Expect: header in a request.</p>
+<p class="code">
+void httpSetExpect (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_status_t">http_status_t</a> expect<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>expect</dt>
+<dd class="description">HTTP status to expect (HTTP_CONTINUE)</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Currently only HTTP_CONTINUE is supported for the &quot;expect&quot; argument.
+
+</p>
+<h3 class="function"><a name="httpSetField">httpSetField</a></h3>
+<p class="description">Set the value of an HTTP header.</p>
+<p class="code">
+void httpSetField (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_field_t">http_field_t</a> field,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *value<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>field</dt>
+<dd class="description">Field index</dd>
+<dt>value</dt>
+<dd class="description">Value</dd>
+</dl>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpSetLength">httpSetLength</a></h3>
+<p class="description">Set the content-length and content-encoding.</p>
+<p class="code">
+void httpSetLength (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t length<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>length</dt>
+<dd class="description">Length (0 for chunked)</dd>
+</dl>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span><a name="httpSetTimeout">httpSetTimeout</a></h3>
+<p class="description">Set read/write timeouts and an optional callback.</p>
+<p class="code">
+void httpSetTimeout (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;double timeout,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_timeout_cb_t">http_timeout_cb_t</a> cb,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *user_data<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>timeout</dt>
+<dd class="description">Number of seconds for timeout,
+must be greater than 0</dd>
+<dt>cb</dt>
+<dd class="description">Callback function or NULL</dd>
+<dt>user_data</dt>
+<dd class="description">User data pointer</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The optional timeout callback receives both the HTTP connection and a user
+data pointer and must return 1 to continue or 0 to error (time) out.
+
+</p>
+<h3 class="function"><a name="httpStatus">httpStatus</a></h3>
+<p class="description">Return a short string describing a HTTP status code.</p>
+<p class="code">
+const char *httpStatus (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_status_t">http_status_t</a> status<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>status</dt>
+<dd class="description">HTTP status code</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Localized status string</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The returned string is localized to the current POSIX locale and is based
+on the status strings defined in RFC 2616.</p>
+<h3 class="function"><a name="httpTrace">httpTrace</a></h3>
+<p class="description">Send an TRACE request to the server.</p>
+<p class="code">
+int httpTrace (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *uri<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>uri</dt>
+<dd class="description">URI for trace</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of call (0 = success)</p>
+<h3 class="function"><a name="httpUpdate">httpUpdate</a></h3>
+<p class="description">Update the current HTTP state for incoming data.</p>
+<p class="code">
+<a href="#http_status_t">http_status_t</a> httpUpdate (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">HTTP status</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="httpWait">httpWait</a></h3>
+<p class="description">Wait for data available on a connection.</p>
+<p class="code">
+int httpWait (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int msec<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>msec</dt>
+<dd class="description">Milliseconds to wait</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if data is available, 0 otherwise</p>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="httpWrite">httpWrite</a></h3>
+<p class="description">Write data to a HTTP connection.</p>
+<p class="code">
+int httpWrite (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *buffer,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int length<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>buffer</dt>
+<dd class="description">Buffer for data</dd>
+<dt>length</dt>
+<dd class="description">Number of bytes to write</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of bytes written</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is deprecated. Use the httpWrite2() function which can
+write more than 2GB of data.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpWrite2">httpWrite2</a></h3>
+<p class="description">Write data to a HTTP connection.</p>
+<p class="code">
+ssize_t httpWrite2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *buffer,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t length<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>buffer</dt>
+<dd class="description">Buffer for data</dd>
+<dt>length</dt>
+<dd class="description">Number of bytes to write</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of bytes written</p>
+<h3 class="function"><a name="ippAddBoolean">ippAddBoolean</a></h3>
+<p class="description">Add a boolean attribute to an IPP message.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddBoolean (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char value<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>group</dt>
+<dd class="description">IPP group</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>value</dt>
+<dd class="description">Value of attribute</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><a name="ippAddBooleans">ippAddBooleans</a></h3>
+<p class="description">Add an array of boolean values.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddBooleans (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_values,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *values<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>group</dt>
+<dd class="description">IPP group</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>num_values</dt>
+<dd class="description">Number of values</dd>
+<dt>values</dt>
+<dd class="description">Values</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ippAddCollection">ippAddCollection</a></h3>
+<p class="description">Add a collection value.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddCollection (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *value<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>group</dt>
+<dd class="description">IPP group</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>value</dt>
+<dd class="description">Value</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ippAddCollections">ippAddCollections</a></h3>
+<p class="description">Add an array of collection values.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddCollections (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_values,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#ipp_t">ipp_t</a> **values<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>group</dt>
+<dd class="description">IPP group</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>num_values</dt>
+<dd class="description">Number of values</dd>
+<dt>values</dt>
+<dd class="description">Values</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><a name="ippAddDate">ippAddDate</a></h3>
+<p class="description">Add a date attribute to an IPP message.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddDate (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#ipp_uchar_t">ipp_uchar_t</a> *value<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>group</dt>
+<dd class="description">IPP group</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>value</dt>
+<dd class="description">Value</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><a name="ippAddInteger">ippAddInteger</a></h3>
+<p class="description">Add a integer attribute to an IPP message.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddInteger (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> type,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int value<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>group</dt>
+<dd class="description">IPP group</dd>
+<dt>type</dt>
+<dd class="description">Type of attribute</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>value</dt>
+<dd class="description">Value of attribute</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><a name="ippAddIntegers">ippAddIntegers</a></h3>
+<p class="description">Add an array of integer values.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddIntegers (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> type,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_values,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const int *values<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>group</dt>
+<dd class="description">IPP group</dd>
+<dt>type</dt>
+<dd class="description">Type of attribute</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>num_values</dt>
+<dd class="description">Number of values</dd>
+<dt>values</dt>
+<dd class="description">Values</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ippAddOctetString">ippAddOctetString</a></h3>
+<p class="description">Add an octetString value to an IPP message.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddOctetString (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const void *data,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int datalen<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>group</dt>
+<dd class="description">IPP group</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>data</dt>
+<dd class="description">octetString data</dd>
+<dt>datalen</dt>
+<dd class="description">Length of data in bytes</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><a name="ippAddRange">ippAddRange</a></h3>
+<p class="description">Add a range of values to an IPP message.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddRange (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int lower,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int upper<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>group</dt>
+<dd class="description">IPP group</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>lower</dt>
+<dd class="description">Lower value</dd>
+<dt>upper</dt>
+<dd class="description">Upper value</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><a name="ippAddRanges">ippAddRanges</a></h3>
+<p class="description">Add ranges of values to an IPP message.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddRanges (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_values,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const int *lower,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const int *upper<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>group</dt>
+<dd class="description">IPP group</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>num_values</dt>
+<dd class="description">Number of values</dd>
+<dt>lower</dt>
+<dd class="description">Lower values</dd>
+<dt>upper</dt>
+<dd class="description">Upper values</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><a name="ippAddResolution">ippAddResolution</a></h3>
+<p class="description">Add a resolution value to an IPP message.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddResolution (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_res_t">ipp_res_t</a> units,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int xres,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int yres<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>group</dt>
+<dd class="description">IPP group</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>units</dt>
+<dd class="description">Units for resolution</dd>
+<dt>xres</dt>
+<dd class="description">X resolution</dd>
+<dt>yres</dt>
+<dd class="description">Y resolution</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><a name="ippAddResolutions">ippAddResolutions</a></h3>
+<p class="description">Add resolution values to an IPP message.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddResolutions (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_values,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_res_t">ipp_res_t</a> units,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const int *xres,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const int *yres<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>group</dt>
+<dd class="description">IPP group</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>num_values</dt>
+<dd class="description">Number of values</dd>
+<dt>units</dt>
+<dd class="description">Units for resolution</dd>
+<dt>xres</dt>
+<dd class="description">X resolutions</dd>
+<dt>yres</dt>
+<dd class="description">Y resolutions</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><a name="ippAddSeparator">ippAddSeparator</a></h3>
+<p class="description">Add a group separator to an IPP message.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddSeparator (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><a name="ippAddString">ippAddString</a></h3>
+<p class="description">Add a language-encoded string to an IPP message.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddString (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> type,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *charset,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *value<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>group</dt>
+<dd class="description">IPP group</dd>
+<dt>type</dt>
+<dd class="description">Type of attribute</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>charset</dt>
+<dd class="description">Character set</dd>
+<dt>value</dt>
+<dd class="description">Value</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><a name="ippAddStrings">ippAddStrings</a></h3>
+<p class="description">Add language-encoded strings to an IPP message.</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippAddStrings (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> type,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_values,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *charset,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *const *values<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>group</dt>
+<dd class="description">IPP group</dd>
+<dt>type</dt>
+<dd class="description">Type of attribute</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>num_values</dt>
+<dd class="description">Number of values</dd>
+<dt>charset</dt>
+<dd class="description">Character set</dd>
+<dt>values</dt>
+<dd class="description">Values</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New attribute</p>
+<h3 class="function"><a name="ippDateToTime">ippDateToTime</a></h3>
+<p class="description">Convert from RFC 1903 Date/Time format to UNIX time
+in seconds.</p>
+<p class="code">
+time_t ippDateToTime (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const <a href="#ipp_uchar_t">ipp_uchar_t</a> *date<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>date</dt>
+<dd class="description">RFC 1903 date info</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">UNIX time value</p>
+<h3 class="function"><a name="ippDelete">ippDelete</a></h3>
+<p class="description">Delete an IPP message.</p>
+<p class="code">
+void ippDelete (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+</dl>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ippDeleteAttribute">ippDeleteAttribute</a></h3>
+<p class="description">Delete a single attribute in an IPP message.</p>
+<p class="code">
+void ippDeleteAttribute (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_attribute_t">ipp_attribute_t</a> *attr<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>attr</dt>
+<dd class="description">Attribute to delete</dd>
+</dl>
+<h3 class="function"><a name="ippErrorString">ippErrorString</a></h3>
+<p class="description">Return a name for the given status code.</p>
+<p class="code">
+const char *ippErrorString (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;ipp_status_t error<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>error</dt>
+<dd class="description">Error status</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Text string</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ippErrorValue">ippErrorValue</a></h3>
+<p class="description">Return a status code for the given name.</p>
+<p class="code">
+ipp_status_t ippErrorValue (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">IPP status code</p>
+<h3 class="function"><a name="ippFindAttribute">ippFindAttribute</a></h3>
+<p class="description">Find a named attribute in a request...</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippFindAttribute (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> type<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>type</dt>
+<dd class="description">Type of attribute</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Matching attribute</p>
+<h3 class="function"><a name="ippFindNextAttribute">ippFindNextAttribute</a></h3>
+<p class="description">Find the next named attribute in a request...</p>
+<p class="code">
+<a href="#ipp_attribute_t">ipp_attribute_t</a> *ippFindNextAttribute (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> type<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+<dt>name</dt>
+<dd class="description">Name of attribute</dd>
+<dt>type</dt>
+<dd class="description">Type of attribute</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Matching attribute</p>
+<h3 class="function"><a name="ippLength">ippLength</a></h3>
+<p class="description">Compute the length of an IPP message.</p>
+<p class="code">
+size_t ippLength (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ipp</dt>
+<dd class="description">IPP message</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Size of IPP message</p>
+<h3 class="function"><a name="ippNew">ippNew</a></h3>
+<p class="description">Allocate a new IPP message.</p>
+<p class="code">
+<a href="#ipp_t">ipp_t</a> *ippNew (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New IPP message</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ippNewRequest">ippNewRequest</a></h3>
+<p class="description">Allocate a new IPP request message.</p>
+<p class="code">
+<a href="#ipp_t">ipp_t</a> *ippNewRequest (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_op_t">ipp_op_t</a> op<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>op</dt>
+<dd class="description">Operation code</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">IPP request message</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The new request message is initialized with the attributes-charset and
+attributes-natural-language attributes added. The
+attributes-natural-language value is derived from the current locale.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ippOpString">ippOpString</a></h3>
+<p class="description">Return a name for the given operation id.</p>
+<p class="code">
+const char *ippOpString (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_op_t">ipp_op_t</a> op<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>op</dt>
+<dd class="description">Operation ID</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Name</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ippOpValue">ippOpValue</a></h3>
+<p class="description">Return an operation id for the given name.</p>
+<p class="code">
+<a href="#ipp_op_t">ipp_op_t</a> ippOpValue (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Textual name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Operation ID</p>
+<h3 class="function"><a name="ippPort">ippPort</a></h3>
+<p class="description">Return the default IPP port number.</p>
+<p class="code">
+int ippPort (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Port number</p>
+<h3 class="function"><a name="ippRead">ippRead</a></h3>
+<p class="description">Read data for an IPP message from a HTTP connection.</p>
+<p class="code">
+<a href="#ipp_state_t">ipp_state_t</a> ippRead (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">HTTP connection</dd>
+<dt>ipp</dt>
+<dd class="description">IPP data</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Current state</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ippReadFile">ippReadFile</a></h3>
+<p class="description">Read data for an IPP message from a file.</p>
+<p class="code">
+<a href="#ipp_state_t">ipp_state_t</a> ippReadFile (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int fd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fd</dt>
+<dd class="description">HTTP data</dd>
+<dt>ipp</dt>
+<dd class="description">IPP data</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Current state</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ippReadIO">ippReadIO</a></h3>
+<p class="description">Read data for an IPP message.</p>
+<p class="code">
+<a href="#ipp_state_t">ipp_state_t</a> ippReadIO (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *src,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_iocb_t">ipp_iocb_t</a> cb,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int blocking,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *parent,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>src</dt>
+<dd class="description">Data source</dd>
+<dt>cb</dt>
+<dd class="description">Read callback function</dd>
+<dt>blocking</dt>
+<dd class="description">Use blocking IO?</dd>
+<dt>parent</dt>
+<dd class="description">Parent request, if any</dd>
+<dt>ipp</dt>
+<dd class="description">IPP data</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Current state</p>
+<h3 class="function"><a name="ippSetPort">ippSetPort</a></h3>
+<p class="description">Set the default port number.</p>
+<p class="code">
+void ippSetPort (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int p<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>p</dt>
+<dd class="description">Port number to use</dd>
+</dl>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="ippTagString">ippTagString</a></h3>
+<p class="description">Return the tag name corresponding to a tag value.</p>
+<p class="code">
+const char *ippTagString (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> tag<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>tag</dt>
+<dd class="description">Tag value</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Tag name</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The returned names are defined in RFC 2911 and 3382.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="ippTagValue">ippTagValue</a></h3>
+<p class="description">Return the tag value corresponding to a tag name.</p>
+<p class="code">
+<a href="#ipp_tag_t">ipp_tag_t</a> ippTagValue (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>name</dt>
+<dd class="description">Tag name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Tag value</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The tag names are defined in RFC 2911 and 3382.
+
+</p>
+<h3 class="function"><a name="ippTimeToDate">ippTimeToDate</a></h3>
+<p class="description">Convert from UNIX time to RFC 1903 format.</p>
+<p class="code">
+const <a href="#ipp_uchar_t">ipp_uchar_t</a> *ippTimeToDate (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;time_t t<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>t</dt>
+<dd class="description">UNIX time value</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">RFC-1903 date/time data</p>
+<h3 class="function"><a name="ippWrite">ippWrite</a></h3>
+<p class="description">Write data for an IPP message to a HTTP connection.</p>
+<p class="code">
+<a href="#ipp_state_t">ipp_state_t</a> ippWrite (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">HTTP connection</dd>
+<dt>ipp</dt>
+<dd class="description">IPP data</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Current state</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ippWriteFile">ippWriteFile</a></h3>
+<p class="description">Write data for an IPP message to a file.</p>
+<p class="code">
+<a href="#ipp_state_t">ipp_state_t</a> ippWriteFile (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int fd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fd</dt>
+<dd class="description">HTTP data</dd>
+<dt>ipp</dt>
+<dd class="description">IPP data</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Current state</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ippWriteIO">ippWriteIO</a></h3>
+<p class="description">Write data for an IPP message.</p>
+<p class="code">
+<a href="#ipp_state_t">ipp_state_t</a> ippWriteIO (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *dst,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_iocb_t">ipp_iocb_t</a> cb,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int blocking,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *parent,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *ipp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>dst</dt>
+<dd class="description">Destination</dd>
+<dt>cb</dt>
+<dd class="description">Write callback function</dd>
+<dt>blocking</dt>
+<dd class="description">Use blocking IO?</dd>
+<dt>parent</dt>
+<dd class="description">Parent IPP message</dd>
+<dt>ipp</dt>
+<dd class="description">IPP data</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Current state</p>
+<h2 class="title"><a name="TYPES">Data Types</a></h2>
+<h3 class="typedef"><a name="gss_auth_identity_desc">gss_auth_identity_desc</a></h3>
+<p class="description">Local functions...</p>
+<p class="code">
+typedef struct <a href="#gss_auth_identity">gss_auth_identity</a> gss_auth_identity_desc;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="http_addr_t">http_addr_t</a></h3>
+<p class="description">Socket address union, which
+makes using IPv6 and other
+address types easier and
+more portable. </p>
+<p class="code">
+typedef union _http_addr_u / http_addr_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="http_addrlist_t">http_addrlist_t</a></h3>
+<p class="description">Socket address list, which is
+used to enumerate all of the
+addresses that are associated
+with a hostname. </p>
+<p class="code">
+typedef struct <a href="#http_addrlist_s">http_addrlist_s</a> / http_addrlist_t;
+</p>
+<h3 class="typedef"><a name="http_auth_t">http_auth_t</a></h3>
+<p class="description">HTTP authentication types</p>
+<p class="code">
+typedef enum <a href="#http_auth_e">http_auth_e</a> http_auth_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span><a name="http_credential_t">http_credential_t</a></h3>
+<p class="description">HTTP credential data </p>
+<p class="code">
+typedef struct <a href="#http_credential_s">http_credential_s</a> http_credential_t;
+</p>
+<h3 class="typedef"><a name="http_encoding_t">http_encoding_t</a></h3>
+<p class="description">HTTP transfer encoding values</p>
+<p class="code">
+typedef enum <a href="#http_encoding_e">http_encoding_e</a> http_encoding_t;
+</p>
+<h3 class="typedef"><a name="http_encryption_t">http_encryption_t</a></h3>
+<p class="description">HTTP encryption values</p>
+<p class="code">
+typedef enum <a href="#http_encryption_e">http_encryption_e</a> http_encryption_t;
+</p>
+<h3 class="typedef"><a name="http_field_t">http_field_t</a></h3>
+<p class="description">HTTP field names</p>
+<p class="code">
+typedef enum <a href="#http_field_e">http_field_e</a> http_field_t;
+</p>
+<h3 class="typedef"><a name="http_keepalive_t">http_keepalive_t</a></h3>
+<p class="description">HTTP keep-alive values</p>
+<p class="code">
+typedef enum <a href="#http_keepalive_e">http_keepalive_e</a> http_keepalive_t;
+</p>
+<h3 class="typedef"><a name="http_state_t">http_state_t</a></h3>
+<p class="description">HTTP state values; states
+are server-oriented...</p>
+<p class="code">
+typedef enum <a href="#http_state_e">http_state_e</a> / http_state_t;
+</p>
+<h3 class="typedef"><a name="http_status_t">http_status_t</a></h3>
+<p class="description">HTTP status codes</p>
+<p class="code">
+typedef enum <a href="#http_status_e">http_status_e</a> http_status_t;
+</p>
+<h3 class="typedef"><a name="http_t">http_t</a></h3>
+<p class="description">HTTP connection type</p>
+<p class="code">
+typedef struct _http_s http_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span><a name="http_timeout_cb_t">http_timeout_cb_t</a></h3>
+<p class="description">HTTP timeout callback </p>
+<p class="code">
+typedef int (*http_timeout_cb_t)(<a href="#http_t">http_t</a> *http, void *user_data);
+</p>
+<h3 class="typedef"><a name="http_uri_coding_t">http_uri_coding_t</a></h3>
+<p class="description">URI en/decode flags</p>
+<p class="code">
+typedef enum <a href="#http_uri_coding_e">http_uri_coding_e</a> http_uri_coding_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.2&nbsp;</span><a name="http_uri_status_t">http_uri_status_t</a></h3>
+<p class="description">URI separation status </p>
+<p class="code">
+typedef enum <a href="#http_uri_status_e">http_uri_status_e</a> http_uri_status_t;
+</p>
+<h3 class="typedef"><a name="http_version_t">http_version_t</a></h3>
+<p class="description">HTTP version numbers</p>
+<p class="code">
+typedef enum <a href="#http_version_e">http_version_e</a> http_version_t;
+</p>
+<h3 class="typedef"><a name="ipp_attribute_t">ipp_attribute_t</a></h3>
+<p class="description">Attribute</p>
+<p class="code">
+typedef struct <a href="#ipp_attribute_s">ipp_attribute_s</a> ipp_attribute_t;
+</p>
+<h3 class="typedef"><a name="ipp_finish_t">ipp_finish_t</a></h3>
+<p class="description">Finishings</p>
+<p class="code">
+typedef enum <a href="#ipp_finish_e">ipp_finish_e</a> ipp_finish_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ipp_iocb_t">ipp_iocb_t</a></h3>
+<p class="description">IPP IO Callback Function </p>
+<p class="code">
+typedef ssize_t (*ipp_iocb_t)(void *, <a href="#ipp_uchar_t">ipp_uchar_t</a> *, size_t);
+</p>
+<h3 class="typedef"><a name="ipp_jstate_t">ipp_jstate_t</a></h3>
+<p class="description">Job states</p>
+<p class="code">
+typedef enum <a href="#ipp_jstate_e">ipp_jstate_e</a> ipp_jstate_t;
+</p>
+<h3 class="typedef"><a name="ipp_op_t">ipp_op_t</a></h3>
+<p class="description">IPP operations</p>
+<p class="code">
+typedef enum <a href="#ipp_op_e">ipp_op_e</a> ipp_op_t;
+</p>
+<h3 class="typedef"><a name="ipp_orient_t">ipp_orient_t</a></h3>
+<p class="description">Orientation values</p>
+<p class="code">
+typedef enum <a href="#ipp_orient_e">ipp_orient_e</a> ipp_orient_t;
+</p>
+<h3 class="typedef"><a name="ipp_pstate_t">ipp_pstate_t</a></h3>
+<p class="description">Printer states</p>
+<p class="code">
+typedef enum <a href="#ipp_pstate_e">ipp_pstate_e</a> ipp_pstate_t;
+</p>
+<h3 class="typedef"><a name="ipp_quality_t">ipp_quality_t</a></h3>
+<p class="description">Qualities</p>
+<p class="code">
+typedef enum <a href="#ipp_quality_e">ipp_quality_e</a> ipp_quality_t;
+</p>
+<h3 class="typedef"><a name="ipp_request_t">ipp_request_t</a></h3>
+<p class="description">Request Header</p>
+<p class="code">
+typedef union <a href="#ipp_request_u">ipp_request_u</a> ipp_request_t;
+</p>
+<h3 class="typedef"><a name="ipp_res_t">ipp_res_t</a></h3>
+<p class="description">Resolution units</p>
+<p class="code">
+typedef enum <a href="#ipp_res_e">ipp_res_e</a> ipp_res_t;
+</p>
+<h3 class="typedef"><a name="ipp_state_t">ipp_state_t</a></h3>
+<p class="description">IPP states</p>
+<p class="code">
+typedef enum <a href="#ipp_state_e">ipp_state_e</a> ipp_state_t;
+</p>
+<h3 class="typedef"><a name="ipp_t">ipp_t</a></h3>
+<p class="description">Attribute Value</p>
+<p class="code">
+typedef struct <a href="#ipp_s">ipp_s</a> ipp_t;
+</p>
+<h3 class="typedef"><a name="ipp_uchar_t">ipp_uchar_t</a></h3>
+<p class="description">IPP status codes</p>
+<p class="code">
+typedef typedef unsigned char ipp_uchar_t;
+</p>
+<h3 class="typedef"><a name="ipp_tag_t">ipp_tag_t</a></h3>
+<p class="description">Format tags for attributes</p>
+<p class="code">
+typedef enum <a href="#ipp_tag_e">ipp_tag_e</a> ipp_tag_t;
+</p>
+<h3 class="typedef"><a name="ipp_value_t">ipp_value_t</a></h3>
+<p class="description">Attribute Value</p>
+<p class="code">
+typedef union <a href="#ipp_value_u">ipp_value_u</a> ipp_value_t;
+</p>
+<h2 class="title"><a name="STRUCTURES">Structures</a></h2>
+<h3 class="struct"><a name="gss_auth_identity">gss_auth_identity</a></h3>
+<p class="description">Local functions...</p>
+<p class="code">struct gss_auth_identity {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;gss_buffer_t *credentialsRef;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;uint32_t flags;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *password;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *realm;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;uint32_t type;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *username;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>credentialsRef </dt>
+<dt>flags </dt>
+<dt>password </dt>
+<dt>realm </dt>
+<dt>type </dt>
+<dt>username </dt>
+</dl>
+<h3 class="struct"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="http_addrlist_s">http_addrlist_s</a></h3>
+<p class="description">Socket address list, which is
+used to enumerate all of the
+addresses that are associated
+with a hostname. </p>
+<p class="code">struct http_addrlist_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_addr_t">http_addr_t</a> addr;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;struct <a href="#http_addrlist_s">http_addrlist_s</a> *next;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>addr </dt>
+<dd class="description">Address</dd>
+<dt>next </dt>
+<dd class="description">Pointer to next address in list</dd>
+</dl>
+<h3 class="struct"><span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span><a name="http_credential_s">http_credential_s</a></h3>
+<p class="description">HTTP credential data </p>
+<p class="code">struct http_credential_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *data;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t datalen;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>data </dt>
+<dd class="description">Pointer to credential data</dd>
+<dt>datalen </dt>
+<dd class="description">Credential length</dd>
+</dl>
+<h3 class="struct"><a name="ipp_attribute_s">ipp_attribute_s</a></h3>
+<p class="description">Attribute</p>
+<p class="code">struct ipp_attribute_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *name;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;struct <a href="#ipp_attribute_s">ipp_attribute_s</a> *next;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_values;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> group_tag, value_tag;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_value_t">ipp_value_t</a> values[1];<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>name </dt>
+<dd class="description">Name of attribute</dd>
+<dt>next </dt>
+<dd class="description">Next attribute in list</dd>
+<dt>num_values </dt>
+<dd class="description">Number of values</dd>
+<dt>value_tag </dt>
+<dd class="description">What type of value is it?</dd>
+<dt>values[1] </dt>
+<dd class="description">Values</dd>
+</dl>
+<h3 class="struct"><a name="ipp_s">ipp_s</a></h3>
+<p class="description">IPP Request/Response/Notification</p>
+<p class="code">struct ipp_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_attribute_t">ipp_attribute_t</a> *attrs;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_attribute_t">ipp_attribute_t</a> *current;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_tag_t">ipp_tag_t</a> curtag;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_attribute_t">ipp_attribute_t</a> *last;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_attribute_t">ipp_attribute_t</a> *prev;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_request_t">ipp_request_t</a> request;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_state_t">ipp_state_t</a> state;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int use;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>attrs </dt>
+<dd class="description">Attributes</dd>
+<dt>current </dt>
+<dd class="description">Current attribute (for read/write)</dd>
+<dt>curtag </dt>
+<dd class="description">Current attribute group tag</dd>
+<dt>last </dt>
+<dd class="description">Last attribute in list</dd>
+<dt>prev <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Previous attribute (for read) </dd>
+<dt>request </dt>
+<dd class="description">Request header</dd>
+<dt>state </dt>
+<dd class="description">State of request</dd>
+<dt>use <span class="info">&nbsp;CUPS 1.4.4/Mac OS X 10.6.?&nbsp;</span></dt>
+<dd class="description">Use count </dd>
+</dl>
+<h2 class="title"><a name="UNIONS">Unions</a></h2>
+<h3 class="union"><a name="ipp_request_u">ipp_request_u</a></h3>
+<p class="description">Request Header</p>
+<p class="code">union ipp_request_u {<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+</dl>
+<h3 class="union"><a name="ipp_value_u">ipp_value_u</a></h3>
+<p class="description">Attribute Value</p>
+<p class="code">union ipp_value_u {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char boolean;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_t">ipp_t</a> *collection;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ipp_uchar_t">ipp_uchar_t</a> date[11];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int integer;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>boolean </dt>
+<dd class="description">Boolean value</dd>
+<dt>collection <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">Collection value </dd>
+<dt>date[11] </dt>
+<dd class="description">Date/time value</dd>
+<dt>integer </dt>
+<dd class="description">Integer/enumerated value</dd>
+</dl>
+<h2 class="title"><a name="ENUMERATIONS">Constants</a></h2>
+<h3 class="enumeration"><a name="http_auth_e">http_auth_e</a></h3>
+<p class="description">HTTP authentication types</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>HTTP_AUTH_BASIC </dt>
+<dd class="description">Basic authentication in use</dd>
+<dt>HTTP_AUTH_MD5 </dt>
+<dd class="description">Digest authentication in use</dd>
+<dt>HTTP_AUTH_MD5_INT </dt>
+<dd class="description">Digest authentication in use for body</dd>
+<dt>HTTP_AUTH_MD5_SESS </dt>
+<dd class="description">MD5-session authentication in use</dd>
+<dt>HTTP_AUTH_MD5_SESS_INT </dt>
+<dd class="description">MD5-session authentication in use for body</dd>
+<dt>HTTP_AUTH_NEGOTIATE <span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">GSSAPI authentication in use </dd>
+<dt>HTTP_AUTH_NONE </dt>
+<dd class="description">No authentication in use</dd>
+</dl>
+<h3 class="enumeration"><a name="http_encoding_e">http_encoding_e</a></h3>
+<p class="description">HTTP transfer encoding values</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>HTTP_ENCODE_CHUNKED </dt>
+<dd class="description">Data is chunked</dd>
+<dt>HTTP_ENCODE_FIELDS </dt>
+<dd class="description">Sending HTTP fields</dd>
+<dt>HTTP_ENCODE_LENGTH </dt>
+<dd class="description">Data is sent with Content-Length</dd>
+</dl>
+<h3 class="enumeration"><a name="http_encryption_e">http_encryption_e</a></h3>
+<p class="description">HTTP encryption values</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>HTTP_ENCRYPT_ALWAYS </dt>
+<dd class="description">Always encrypt (SSL)</dd>
+<dt>HTTP_ENCRYPT_IF_REQUESTED </dt>
+<dd class="description">Encrypt if requested (TLS upgrade)</dd>
+<dt>HTTP_ENCRYPT_NEVER </dt>
+<dd class="description">Never encrypt</dd>
+<dt>HTTP_ENCRYPT_REQUIRED </dt>
+<dd class="description">Encryption is required (TLS upgrade)</dd>
+</dl>
+<h3 class="enumeration"><a name="http_field_e">http_field_e</a></h3>
+<p class="description">HTTP field names</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>HTTP_FIELD_ACCEPT_LANGUAGE </dt>
+<dd class="description">Accept-Language field</dd>
+<dt>HTTP_FIELD_ACCEPT_RANGES </dt>
+<dd class="description">Accept-Ranges field</dd>
+<dt>HTTP_FIELD_AUTHORIZATION </dt>
+<dd class="description">Authorization field</dd>
+<dt>HTTP_FIELD_CONNECTION </dt>
+<dd class="description">Connection field</dd>
+<dt>HTTP_FIELD_CONTENT_ENCODING </dt>
+<dd class="description">Content-Encoding field</dd>
+<dt>HTTP_FIELD_CONTENT_LANGUAGE </dt>
+<dd class="description">Content-Language field</dd>
+<dt>HTTP_FIELD_CONTENT_LENGTH </dt>
+<dd class="description">Content-Length field</dd>
+<dt>HTTP_FIELD_CONTENT_LOCATION </dt>
+<dd class="description">Content-Location field</dd>
+<dt>HTTP_FIELD_CONTENT_MD5 </dt>
+<dd class="description">Content-MD5 field</dd>
+<dt>HTTP_FIELD_CONTENT_RANGE </dt>
+<dd class="description">Content-Range field</dd>
+<dt>HTTP_FIELD_CONTENT_TYPE </dt>
+<dd class="description">Content-Type field</dd>
+<dt>HTTP_FIELD_CONTENT_VERSION </dt>
+<dd class="description">Content-Version field</dd>
+<dt>HTTP_FIELD_DATE </dt>
+<dd class="description">Date field</dd>
+<dt>HTTP_FIELD_HOST </dt>
+<dd class="description">Host field</dd>
+<dt>HTTP_FIELD_IF_MODIFIED_SINCE </dt>
+<dd class="description">If-Modified-Since field</dd>
+<dt>HTTP_FIELD_IF_UNMODIFIED_SINCE </dt>
+<dd class="description">If-Unmodified-Since field</dd>
+<dt>HTTP_FIELD_KEEP_ALIVE </dt>
+<dd class="description">Keep-Alive field</dd>
+<dt>HTTP_FIELD_LAST_MODIFIED </dt>
+<dd class="description">Last-Modified field</dd>
+<dt>HTTP_FIELD_LINK </dt>
+<dd class="description">Link field</dd>
+<dt>HTTP_FIELD_LOCATION </dt>
+<dd class="description">Location field</dd>
+<dt>HTTP_FIELD_MAX </dt>
+<dd class="description">Maximum field index</dd>
+<dt>HTTP_FIELD_RANGE </dt>
+<dd class="description">Range field</dd>
+<dt>HTTP_FIELD_REFERER </dt>
+<dd class="description">Referer field</dd>
+<dt>HTTP_FIELD_RETRY_AFTER </dt>
+<dd class="description">Retry-After field</dd>
+<dt>HTTP_FIELD_TRANSFER_ENCODING </dt>
+<dd class="description">Transfer-Encoding field</dd>
+<dt>HTTP_FIELD_UNKNOWN </dt>
+<dd class="description">Unknown field</dd>
+<dt>HTTP_FIELD_UPGRADE </dt>
+<dd class="description">Upgrade field</dd>
+<dt>HTTP_FIELD_USER_AGENT </dt>
+<dd class="description">User-Agent field</dd>
+<dt>HTTP_FIELD_WWW_AUTHENTICATE </dt>
+<dd class="description">WWW-Authenticate field</dd>
+</dl>
+<h3 class="enumeration"><a name="http_keepalive_e">http_keepalive_e</a></h3>
+<p class="description">HTTP keep-alive values</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>HTTP_KEEPALIVE_OFF </dt>
+<dd class="description">No keep alive support</dd>
+<dt>HTTP_KEEPALIVE_ON </dt>
+<dd class="description">Use keep alive</dd>
+</dl>
+<h3 class="enumeration"><a name="http_state_e">http_state_e</a></h3>
+<p class="description">HTTP state values; states
+are server-oriented...</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>HTTP_CLOSE </dt>
+<dd class="description">CLOSE command, waiting for blank line</dd>
+<dt>HTTP_DELETE </dt>
+<dd class="description">DELETE command, waiting for blank line</dd>
+<dt>HTTP_GET </dt>
+<dd class="description">GET command, waiting for blank line</dd>
+<dt>HTTP_GET_SEND </dt>
+<dd class="description">GET command, sending data</dd>
+<dt>HTTP_HEAD </dt>
+<dd class="description">HEAD command, waiting for blank line</dd>
+<dt>HTTP_OPTIONS </dt>
+<dd class="description">OPTIONS command, waiting for blank line</dd>
+<dt>HTTP_POST </dt>
+<dd class="description">POST command, waiting for blank line</dd>
+<dt>HTTP_POST_RECV </dt>
+<dd class="description">POST command, receiving data</dd>
+<dt>HTTP_POST_SEND </dt>
+<dd class="description">POST command, sending data</dd>
+<dt>HTTP_PUT </dt>
+<dd class="description">PUT command, waiting for blank line</dd>
+<dt>HTTP_PUT_RECV </dt>
+<dd class="description">PUT command, receiving data</dd>
+<dt>HTTP_STATUS </dt>
+<dd class="description">Command complete, sending status</dd>
+<dt>HTTP_TRACE </dt>
+<dd class="description">TRACE command, waiting for blank line</dd>
+<dt>HTTP_WAITING </dt>
+<dd class="description">Waiting for command</dd>
+</dl>
+<h3 class="enumeration"><a name="http_status_e">http_status_e</a></h3>
+<p class="description">HTTP status codes</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>HTTP_ACCEPTED </dt>
+<dd class="description">DELETE command was successful</dd>
+<dt>HTTP_AUTHORIZATION_CANCELED <span class="info">&nbsp;CUPS 1.4&nbsp;</span></dt>
+<dd class="description">User canceled authorization </dd>
+<dt>HTTP_BAD_GATEWAY </dt>
+<dd class="description">Bad gateway</dd>
+<dt>HTTP_BAD_REQUEST </dt>
+<dd class="description">Bad request</dd>
+<dt>HTTP_CONFLICT </dt>
+<dd class="description">Request is self-conflicting</dd>
+<dt>HTTP_CONTINUE </dt>
+<dd class="description">Everything OK, keep going...</dd>
+<dt>HTTP_CREATED </dt>
+<dd class="description">PUT command was successful</dd>
+<dt>HTTP_ERROR </dt>
+<dd class="description">An error response from httpXxxx()</dd>
+<dt>HTTP_EXPECTATION_FAILED </dt>
+<dd class="description">The expectation given in an Expect header field was not met</dd>
+<dt>HTTP_FORBIDDEN </dt>
+<dd class="description">Forbidden to access this URI</dd>
+<dt>HTTP_GATEWAY_TIMEOUT </dt>
+<dd class="description">Gateway connection timed out</dd>
+<dt>HTTP_GONE </dt>
+<dd class="description">Server has gone away</dd>
+<dt>HTTP_LENGTH_REQUIRED </dt>
+<dd class="description">A content length or encoding is required</dd>
+<dt>HTTP_METHOD_NOT_ALLOWED </dt>
+<dd class="description">Method is not allowed</dd>
+<dt>HTTP_MOVED_PERMANENTLY </dt>
+<dd class="description">Document has moved permanently</dd>
+<dt>HTTP_MOVED_TEMPORARILY </dt>
+<dd class="description">Document has moved temporarily</dd>
+<dt>HTTP_MULTIPLE_CHOICES </dt>
+<dd class="description">Multiple files match request</dd>
+<dt>HTTP_NOT_ACCEPTABLE </dt>
+<dd class="description">Not Acceptable</dd>
+<dt>HTTP_NOT_AUTHORITATIVE </dt>
+<dd class="description">Information isn't authoritative</dd>
+<dt>HTTP_NOT_FOUND </dt>
+<dd class="description">URI was not found</dd>
+<dt>HTTP_NOT_IMPLEMENTED </dt>
+<dd class="description">Feature not implemented</dd>
+<dt>HTTP_NOT_MODIFIED </dt>
+<dd class="description">File not modified</dd>
+<dt>HTTP_NOT_SUPPORTED </dt>
+<dd class="description">HTTP version not supported</dd>
+<dt>HTTP_NO_CONTENT </dt>
+<dd class="description">Successful command, no new data</dd>
+<dt>HTTP_OK </dt>
+<dd class="description">OPTIONS/GET/HEAD/POST/TRACE command was successful</dd>
+<dt>HTTP_PARTIAL_CONTENT </dt>
+<dd class="description">Only a partial file was recieved/sent</dd>
+<dt>HTTP_PAYMENT_REQUIRED </dt>
+<dd class="description">Payment required</dd>
+<dt>HTTP_PKI_ERROR <span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span></dt>
+<dd class="description">Error negotiating a secure connection </dd>
+<dt>HTTP_PRECONDITION </dt>
+<dd class="description">Precondition failed</dd>
+<dt>HTTP_PROXY_AUTHENTICATION </dt>
+<dd class="description">Proxy Authentication is Required</dd>
+<dt>HTTP_REQUESTED_RANGE </dt>
+<dd class="description">The requested range is not satisfiable</dd>
+<dt>HTTP_REQUEST_TIMEOUT </dt>
+<dd class="description">Request timed out</dd>
+<dt>HTTP_REQUEST_TOO_LARGE </dt>
+<dd class="description">Request entity too large</dd>
+<dt>HTTP_RESET_CONTENT </dt>
+<dd class="description">Content was reset/recreated</dd>
+<dt>HTTP_SEE_OTHER </dt>
+<dd class="description">See this other link...</dd>
+<dt>HTTP_SERVER_ERROR </dt>
+<dd class="description">Internal server error</dd>
+<dt>HTTP_SERVICE_UNAVAILABLE </dt>
+<dd class="description">Service is unavailable</dd>
+<dt>HTTP_SWITCHING_PROTOCOLS </dt>
+<dd class="description">HTTP upgrade to TLS/SSL</dd>
+<dt>HTTP_UNAUTHORIZED </dt>
+<dd class="description">Unauthorized to access host</dd>
+<dt>HTTP_UNSUPPORTED_MEDIATYPE </dt>
+<dd class="description">The requested media type is unsupported</dd>
+<dt>HTTP_UPGRADE_REQUIRED </dt>
+<dd class="description">Upgrade to SSL/TLS required</dd>
+<dt>HTTP_URI_TOO_LONG </dt>
+<dd class="description">URI too long</dd>
+<dt>HTTP_USE_PROXY </dt>
+<dd class="description">Must use a proxy to access this URI</dd>
+</dl>
+<h3 class="enumeration"><a name="http_uri_coding_e">http_uri_coding_e</a></h3>
+<p class="description">URI en/decode flags</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>HTTP_URI_CODING_ALL </dt>
+<dd class="description">En/decode everything</dd>
+<dt>HTTP_URI_CODING_HOSTNAME </dt>
+<dd class="description">En/decode the hostname portion</dd>
+<dt>HTTP_URI_CODING_MOST </dt>
+<dd class="description">En/decode all but the query</dd>
+<dt>HTTP_URI_CODING_NONE </dt>
+<dd class="description">Don't en/decode anything</dd>
+<dt>HTTP_URI_CODING_QUERY </dt>
+<dd class="description">En/decode the query portion</dd>
+<dt>HTTP_URI_CODING_RESOURCE </dt>
+<dd class="description">En/decode the resource portion</dd>
+<dt>HTTP_URI_CODING_USERNAME </dt>
+<dd class="description">En/decode the username portion</dd>
+</dl>
+<h3 class="enumeration"><span class="info">&nbsp;CUPS 1.2&nbsp;</span><a name="http_uri_status_e">http_uri_status_e</a></h3>
+<p class="description">URI separation status </p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>HTTP_URI_BAD_ARGUMENTS </dt>
+<dd class="description">Bad arguments to function (error)</dd>
+<dt>HTTP_URI_BAD_HOSTNAME </dt>
+<dd class="description">Bad hostname in URI (error)</dd>
+<dt>HTTP_URI_BAD_PORT </dt>
+<dd class="description">Bad port number in URI (error)</dd>
+<dt>HTTP_URI_BAD_RESOURCE </dt>
+<dd class="description">Bad resource in URI (error)</dd>
+<dt>HTTP_URI_BAD_SCHEME </dt>
+<dd class="description">Bad scheme in URI (error)</dd>
+<dt>HTTP_URI_BAD_URI </dt>
+<dd class="description">Bad/empty URI (error)</dd>
+<dt>HTTP_URI_BAD_USERNAME </dt>
+<dd class="description">Bad username in URI (error)</dd>
+<dt>HTTP_URI_MISSING_RESOURCE </dt>
+<dd class="description">Missing resource in URI (warning)</dd>
+<dt>HTTP_URI_MISSING_SCHEME </dt>
+<dd class="description">Missing scheme in URI (warning)</dd>
+<dt>HTTP_URI_OK </dt>
+<dd class="description">URI decoded OK</dd>
+<dt>HTTP_URI_OVERFLOW </dt>
+<dd class="description">URI buffer for httpAssembleURI is too small</dd>
+<dt>HTTP_URI_UNKNOWN_SCHEME </dt>
+<dd class="description">Unknown scheme in URI (warning)</dd>
+</dl>
+<h3 class="enumeration"><a name="http_version_e">http_version_e</a></h3>
+<p class="description">HTTP version numbers</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>HTTP_0_9 </dt>
+<dd class="description">HTTP/0.9</dd>
+<dt>HTTP_1_0 </dt>
+<dd class="description">HTTP/1.0</dd>
+<dt>HTTP_1_1 </dt>
+<dd class="description">HTTP/1.1</dd>
+</dl>
+<h3 class="enumeration"><a name="ipp_finish_e">ipp_finish_e</a></h3>
+<p class="description">Finishings</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>IPP_FINISHINGS_BALE </dt>
+<dd class="description">Bale (any type)</dd>
+<dt>IPP_FINISHINGS_BIND </dt>
+<dd class="description">Bind</dd>
+<dt>IPP_FINISHINGS_BIND_BOTTOM </dt>
+<dd class="description">Bind on bottom</dd>
+<dt>IPP_FINISHINGS_BIND_LEFT </dt>
+<dd class="description">Bind on left</dd>
+<dt>IPP_FINISHINGS_BIND_RIGHT </dt>
+<dd class="description">Bind on right</dd>
+<dt>IPP_FINISHINGS_BIND_TOP </dt>
+<dd class="description">Bind on top</dd>
+<dt>IPP_FINISHINGS_BOOKLET_MAKER </dt>
+<dd class="description">Fold to make booklet</dd>
+<dt>IPP_FINISHINGS_COVER </dt>
+<dd class="description">Add cover</dd>
+<dt>IPP_FINISHINGS_EDGE_STITCH </dt>
+<dd class="description">Stitch along any side</dd>
+<dt>IPP_FINISHINGS_EDGE_STITCH_BOTTOM </dt>
+<dd class="description">Stitch along bottom edge</dd>
+<dt>IPP_FINISHINGS_EDGE_STITCH_LEFT </dt>
+<dd class="description">Stitch along left side</dd>
+<dt>IPP_FINISHINGS_EDGE_STITCH_RIGHT </dt>
+<dd class="description">Stitch along right side</dd>
+<dt>IPP_FINISHINGS_EDGE_STITCH_TOP </dt>
+<dd class="description">Stitch along top edge</dd>
+<dt>IPP_FINISHINGS_FOLD </dt>
+<dd class="description">Fold (any type)</dd>
+<dt>IPP_FINISHINGS_JOB_OFFSET </dt>
+<dd class="description">Offset for binding (any type)</dd>
+<dt>IPP_FINISHINGS_NONE </dt>
+<dd class="description">No finishing</dd>
+<dt>IPP_FINISHINGS_PUNCH </dt>
+<dd class="description">Punch (any location/count)</dd>
+<dt>IPP_FINISHINGS_SADDLE_STITCH </dt>
+<dd class="description">Staple interior</dd>
+<dt>IPP_FINISHINGS_STAPLE </dt>
+<dd class="description">Staple (any location)</dd>
+<dt>IPP_FINISHINGS_STAPLE_BOTTOM_LEFT </dt>
+<dd class="description">Staple bottom left corner</dd>
+<dt>IPP_FINISHINGS_STAPLE_BOTTOM_RIGHT </dt>
+<dd class="description">Staple bottom right corner</dd>
+<dt>IPP_FINISHINGS_STAPLE_DUAL_BOTTOM </dt>
+<dd class="description">Two staples on bottom</dd>
+<dt>IPP_FINISHINGS_STAPLE_DUAL_LEFT </dt>
+<dd class="description">Two staples on left</dd>
+<dt>IPP_FINISHINGS_STAPLE_DUAL_RIGHT </dt>
+<dd class="description">Two staples on right</dd>
+<dt>IPP_FINISHINGS_STAPLE_DUAL_TOP </dt>
+<dd class="description">Two staples on top</dd>
+<dt>IPP_FINISHINGS_STAPLE_TOP_LEFT </dt>
+<dd class="description">Staple top left corner</dd>
+<dt>IPP_FINISHINGS_STAPLE_TOP_RIGHT </dt>
+<dd class="description">Staple top right corner</dd>
+<dt>IPP_FINISHINGS_TRIM </dt>
+<dd class="description">Trim (any type)</dd>
+</dl>
+<h3 class="enumeration"><a name="ipp_jstate_e">ipp_jstate_e</a></h3>
+<p class="description">Job states</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>IPP_JOB_ABORTED </dt>
+<dd class="description">Job has aborted due to error</dd>
+<dt>IPP_JOB_CANCELED </dt>
+<dd class="description">Job has been canceled</dd>
+<dt>IPP_JOB_COMPLETED </dt>
+<dd class="description">Job has completed successfully</dd>
+<dt>IPP_JOB_HELD </dt>
+<dd class="description">Job is held for printing</dd>
+<dt>IPP_JOB_PENDING </dt>
+<dd class="description">Job is waiting to be printed</dd>
+<dt>IPP_JOB_PROCESSING </dt>
+<dd class="description">Job is currently printing</dd>
+<dt>IPP_JOB_STOPPED </dt>
+<dd class="description">Job has been stopped</dd>
+</dl>
+<h3 class="enumeration"><a name="ipp_op_e">ipp_op_e</a></h3>
+<p class="description">IPP operations</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_ACCEPT_JOBS </dt>
+<dd class="description">Accept new jobs on a printer</dd>
+<dt>CUPS_ADD_MODIFY_CLASS </dt>
+<dd class="description">Add or modify a class</dd>
+<dt>CUPS_ADD_MODIFY_PRINTER </dt>
+<dd class="description">Add or modify a printer</dd>
+<dt>CUPS_AUTHENTICATE_JOB <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Authenticate a job </dd>
+<dt>CUPS_DELETE_CLASS </dt>
+<dd class="description">Delete a class</dd>
+<dt>CUPS_DELETE_PRINTER </dt>
+<dd class="description">Delete a printer</dd>
+<dt>CUPS_GET_CLASSES <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Get a list of classes </dd>
+<dt>CUPS_GET_DEFAULT </dt>
+<dd class="description">Get the default printer</dd>
+<dt>CUPS_GET_DEVICES </dt>
+<dd class="description">Get a list of supported devices</dd>
+<dt>CUPS_GET_DOCUMENT <span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span></dt>
+<dd class="description">Get a document file </dd>
+<dt>CUPS_GET_PPD <span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Get a PPD file </dd>
+<dt>CUPS_GET_PPDS </dt>
+<dd class="description">Get a list of supported drivers</dd>
+<dt>CUPS_GET_PRINTERS </dt>
+<dd class="description">Get a list of printers and/or classes</dd>
+<dt>CUPS_MOVE_JOB </dt>
+<dd class="description">Move a job to a different printer</dd>
+<dt>CUPS_REJECT_JOBS </dt>
+<dd class="description">Reject new jobs on a printer</dd>
+<dt>CUPS_SET_DEFAULT </dt>
+<dd class="description">Set the default printer</dd>
+<dt>IPP_CANCEL_JOB </dt>
+<dd class="description">Cancel a job</dd>
+<dt>IPP_CANCEL_JOBS </dt>
+<dd class="description">Cancel-Jobs</dd>
+<dt>IPP_CANCEL_MY_JOBS </dt>
+<dd class="description">Cancel-My-Jobs</dd>
+<dt>IPP_CANCEL_SUBSCRIPTION <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Cancel a subscription </dd>
+<dt>IPP_CLOSE_JOB </dt>
+<dd class="description">Close-Job</dd>
+<dt>IPP_CREATE_JOB </dt>
+<dd class="description">Create an empty print job</dd>
+<dt>IPP_CREATE_JOB_SUBSCRIPTION <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Create a job subscription </dd>
+<dt>IPP_CREATE_PRINTER_SUBSCRIPTION <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Create a printer subscription </dd>
+<dt>IPP_DISABLE_PRINTER </dt>
+<dd class="description">Stop a printer</dd>
+<dt>IPP_ENABLE_PRINTER </dt>
+<dd class="description">Start a printer</dd>
+<dt>IPP_GET_JOBS </dt>
+<dd class="description">Get a list of jobs</dd>
+<dt>IPP_GET_JOB_ATTRIBUTES </dt>
+<dd class="description">Get job attributes</dd>
+<dt>IPP_GET_NOTIFICATIONS <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Get notification events </dd>
+<dt>IPP_GET_PRINTER_ATTRIBUTES </dt>
+<dd class="description">Get printer attributes</dd>
+<dt>IPP_GET_PRINTER_SUPPORTED_VALUES </dt>
+<dd class="description">Get supported attribute values</dd>
+<dt>IPP_GET_SUBSCRIPTIONS <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Get list of subscriptions </dd>
+<dt>IPP_GET_SUBSCRIPTION_ATTRIBUTES <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Get subscription attributes </dd>
+<dt>IPP_HOLD_JOB </dt>
+<dd class="description">Hold a job for printing</dd>
+<dt>IPP_PAUSE_PRINTER </dt>
+<dd class="description">Stop a printer</dd>
+<dt>IPP_PRINT_JOB </dt>
+<dd class="description">Print a single file</dd>
+<dt>IPP_PURGE_JOBS </dt>
+<dd class="description">Cancel all jobs</dd>
+<dt>IPP_RELEASE_JOB </dt>
+<dd class="description">Release a job for printing</dd>
+<dt>IPP_RENEW_SUBSCRIPTION <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Renew a printer subscription </dd>
+<dt>IPP_RESTART_JOB </dt>
+<dd class="description">Reprint a job</dd>
+<dt>IPP_RESUBMIT_JOB </dt>
+<dd class="description">Resubmit-Job</dd>
+<dt>IPP_RESUME_PRINTER </dt>
+<dd class="description">Start a printer</dd>
+<dt>IPP_SEND_DOCUMENT </dt>
+<dd class="description">Add a file to a job</dd>
+<dt>IPP_SET_JOB_ATTRIBUTES </dt>
+<dd class="description">Set job attributes</dd>
+<dt>IPP_VALIDATE_JOB </dt>
+<dd class="description">Validate job options</dd>
+</dl>
+<h3 class="enumeration"><a name="ipp_orient_e">ipp_orient_e</a></h3>
+<p class="description">Orientation values</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>IPP_LANDSCAPE </dt>
+<dd class="description">90 degrees counter-clockwise</dd>
+<dt>IPP_PORTRAIT </dt>
+<dd class="description">No rotation</dd>
+<dt>IPP_REVERSE_LANDSCAPE </dt>
+<dd class="description">90 degrees clockwise</dd>
+<dt>IPP_REVERSE_PORTRAIT </dt>
+<dd class="description">180 degrees</dd>
+</dl>
+<h3 class="enumeration"><a name="ipp_pstate_e">ipp_pstate_e</a></h3>
+<p class="description">Printer states</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>IPP_PRINTER_IDLE </dt>
+<dd class="description">Printer is idle</dd>
+<dt>IPP_PRINTER_PROCESSING </dt>
+<dd class="description">Printer is working</dd>
+<dt>IPP_PRINTER_STOPPED </dt>
+<dd class="description">Printer is stopped</dd>
+</dl>
+<h3 class="enumeration"><a name="ipp_quality_e">ipp_quality_e</a></h3>
+<p class="description">Qualities</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>IPP_QUALITY_DRAFT </dt>
+<dd class="description">Draft quality</dd>
+<dt>IPP_QUALITY_HIGH </dt>
+<dd class="description">High quality</dd>
+<dt>IPP_QUALITY_NORMAL </dt>
+<dd class="description">Normal quality</dd>
+</dl>
+<h3 class="enumeration"><a name="ipp_res_e">ipp_res_e</a></h3>
+<p class="description">Resolution units</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>IPP_RES_PER_CM </dt>
+<dd class="description">Pixels per centimeter</dd>
+<dt>IPP_RES_PER_INCH </dt>
+<dd class="description">Pixels per inch</dd>
+</dl>
+<h3 class="enumeration"><a name="ipp_state_e">ipp_state_e</a></h3>
+<p class="description">IPP states</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>IPP_ATTRIBUTE </dt>
+<dd class="description">One or more attributes need to be sent/received</dd>
+<dt>IPP_DATA </dt>
+<dd class="description">IPP request data needs to be sent/received</dd>
+<dt>IPP_ERROR </dt>
+<dd class="description">An error occurred</dd>
+<dt>IPP_HEADER </dt>
+<dd class="description">The request header needs to be sent/received</dd>
+<dt>IPP_IDLE </dt>
+<dd class="description">Nothing is happening/request completed</dd>
+</dl>
+<h3 class="enumeration"><a name="ipp_status_e">ipp_status_e</a></h3>
+<p class="description">IPP status codes</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_SEE_OTHER </dt>
+<dd class="description">cups-see-other</dd>
+<dt>IPP_ATTRIBUTES </dt>
+<dd class="description">client-error-attributes-or-values-not-supported</dd>
+<dt>IPP_ATTRIBUTES_NOT_SETTABLE </dt>
+<dd class="description">client-error-attributes-not-settable</dd>
+<dt>IPP_AUTHENTICATION_CANCELED <span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span></dt>
+<dd class="description">Authentication canceled by user </dd>
+<dt>IPP_BAD_REQUEST </dt>
+<dd class="description">client-error-bad-request</dd>
+<dt>IPP_CHARSET </dt>
+<dd class="description">client-error-charset-not-supported</dd>
+<dt>IPP_COMPRESSION_ERROR </dt>
+<dd class="description">client-error-compression-error</dd>
+<dt>IPP_COMPRESSION_NOT_SUPPORTED </dt>
+<dd class="description">client-error-compression-not-supported</dd>
+<dt>IPP_CONFLICT </dt>
+<dd class="description">client-error-conflicting-attributes</dd>
+<dt>IPP_DEVICE_ERROR </dt>
+<dd class="description">server-error-device-error</dd>
+<dt>IPP_DOCUMENT_ACCESS_ERROR </dt>
+<dd class="description">client-error-document-access-error</dd>
+<dt>IPP_DOCUMENT_FORMAT </dt>
+<dd class="description">client-error-document-format-not-supported</dd>
+<dt>IPP_DOCUMENT_FORMAT_ERROR </dt>
+<dd class="description">client-error-document-format-error</dd>
+<dt>IPP_ERROR_JOB_CANCELED </dt>
+<dd class="description">server-error-job-canceled</dd>
+<dt>IPP_FORBIDDEN </dt>
+<dd class="description">client-error-forbidden</dd>
+<dt>IPP_GONE </dt>
+<dd class="description">client-error-gone</dd>
+<dt>IPP_IGNORED_ALL_NOTIFICATIONS </dt>
+<dd class="description">client-error-ignored-all-notifications</dd>
+<dt>IPP_IGNORED_ALL_SUBSCRIPTIONS </dt>
+<dd class="description">client-error-ignored-all-subscriptions</dd>
+<dt>IPP_INTERNAL_ERROR </dt>
+<dd class="description">server-error-internal-error</dd>
+<dt>IPP_MULTIPLE_JOBS_NOT_SUPPORTED </dt>
+<dd class="description">server-error-multiple-document-jobs-not-supported</dd>
+<dt>IPP_NOT_ACCEPTING </dt>
+<dd class="description">server-error-not-accepting-jobs</dd>
+<dt>IPP_NOT_AUTHENTICATED </dt>
+<dd class="description">client-error-not-authenticated</dd>
+<dt>IPP_NOT_AUTHORIZED </dt>
+<dd class="description">client-error-not-authorized</dd>
+<dt>IPP_NOT_FOUND </dt>
+<dd class="description">client-error-not-found</dd>
+<dt>IPP_NOT_POSSIBLE </dt>
+<dd class="description">client-error-not-possible</dd>
+<dt>IPP_OK </dt>
+<dd class="description">successful-ok</dd>
+<dt>IPP_OK_BUT_CANCEL_SUBSCRIPTION </dt>
+<dd class="description">successful-ok-but-cancel-subscription</dd>
+<dt>IPP_OK_CONFLICT </dt>
+<dd class="description">successful-ok-conflicting-attributes</dd>
+<dt>IPP_OK_EVENTS_COMPLETE </dt>
+<dd class="description">successful-ok-events-complete</dd>
+<dt>IPP_OK_IGNORED_NOTIFICATIONS </dt>
+<dd class="description">successful-ok-ignored-notifications</dd>
+<dt>IPP_OK_IGNORED_SUBSCRIPTIONS </dt>
+<dd class="description">successful-ok-ignored-subscriptions</dd>
+<dt>IPP_OK_SUBST </dt>
+<dd class="description">successful-ok-ignored-or-substituted-attributes</dd>
+<dt>IPP_OK_TOO_MANY_EVENTS </dt>
+<dd class="description">successful-ok-too-many-events</dd>
+<dt>IPP_OPERATION_NOT_SUPPORTED </dt>
+<dd class="description">server-error-operation-not-supported</dd>
+<dt>IPP_PKI_ERROR <span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span></dt>
+<dd class="description">Error negotiating a secure connection </dd>
+<dt>IPP_PRINTER_BUSY </dt>
+<dd class="description">server-error-busy</dd>
+<dt>IPP_PRINTER_IS_DEACTIVATED </dt>
+<dd class="description">server-error-printer-is-deactivated</dd>
+<dt>IPP_PRINT_SUPPORT_FILE_NOT_FOUND </dt>
+<dd class="description">client-error-print-support-file-not-found</dd>
+<dt>IPP_REQUEST_ENTITY </dt>
+<dd class="description">client-error-request-entity-too-large</dd>
+<dt>IPP_REQUEST_VALUE </dt>
+<dd class="description">client-error-request-value-too-long</dd>
+<dt>IPP_SERVICE_UNAVAILABLE </dt>
+<dd class="description">server-error-service-unavailable</dd>
+<dt>IPP_TEMPORARY_ERROR </dt>
+<dd class="description">server-error-temporary-error</dd>
+<dt>IPP_TIMEOUT </dt>
+<dd class="description">client-error-timeout</dd>
+<dt>IPP_TOO_MANY_SUBSCRIPTIONS </dt>
+<dd class="description">client-error-too-many-subscriptions</dd>
+<dt>IPP_UPGRADE_REQUIRED </dt>
+<dd class="description">TLS upgrade required</dd>
+<dt>IPP_URI_SCHEME </dt>
+<dd class="description">client-error-uri-scheme-not-supported</dd>
+<dt>IPP_VERSION_NOT_SUPPORTED </dt>
+<dd class="description">server-error-version-not-supported</dd>
+</dl>
+<h3 class="enumeration"><a name="ipp_tag_e">ipp_tag_e</a></h3>
+<p class="description">Format tags for attributes</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>IPP_TAG_ADMINDEFINE </dt>
+<dd class="description">Admin-defined value</dd>
+<dt>IPP_TAG_BEGIN_COLLECTION </dt>
+<dd class="description">Beginning of collection value</dd>
+<dt>IPP_TAG_BOOLEAN </dt>
+<dd class="description">Boolean value</dd>
+<dt>IPP_TAG_CHARSET </dt>
+<dd class="description">Character set value</dd>
+<dt>IPP_TAG_COPY </dt>
+<dd class="description">Bitflag for copied attribute values</dd>
+<dt>IPP_TAG_DATE </dt>
+<dd class="description">Date/time value</dd>
+<dt>IPP_TAG_DEFAULT </dt>
+<dd class="description">Default value</dd>
+<dt>IPP_TAG_DELETEATTR </dt>
+<dd class="description">Delete-attribute value</dd>
+<dt>IPP_TAG_END </dt>
+<dd class="description">End-of-attributes</dd>
+<dt>IPP_TAG_END_COLLECTION </dt>
+<dd class="description">End of collection value</dd>
+<dt>IPP_TAG_ENUM </dt>
+<dd class="description">Enumeration value</dd>
+<dt>IPP_TAG_EVENT_NOTIFICATION </dt>
+<dd class="description">Event group</dd>
+<dt>IPP_TAG_INTEGER </dt>
+<dd class="description">Integer value</dd>
+<dt>IPP_TAG_JOB </dt>
+<dd class="description">Job group</dd>
+<dt>IPP_TAG_KEYWORD </dt>
+<dd class="description">Keyword value</dd>
+<dt>IPP_TAG_LANGUAGE </dt>
+<dd class="description">Language value</dd>
+<dt>IPP_TAG_MASK </dt>
+<dd class="description">Mask for copied attribute values</dd>
+<dt>IPP_TAG_MEMBERNAME </dt>
+<dd class="description">Collection member name value</dd>
+<dt>IPP_TAG_MIMETYPE </dt>
+<dd class="description">MIME media type value</dd>
+<dt>IPP_TAG_NAME </dt>
+<dd class="description">Name value</dd>
+<dt>IPP_TAG_NAMELANG </dt>
+<dd class="description">Name-with-language value</dd>
+<dt>IPP_TAG_NOTSETTABLE </dt>
+<dd class="description">Not-settable value</dd>
+<dt>IPP_TAG_NOVALUE </dt>
+<dd class="description">No-value value</dd>
+<dt>IPP_TAG_OPERATION </dt>
+<dd class="description">Operation group</dd>
+<dt>IPP_TAG_PRINTER </dt>
+<dd class="description">Printer group</dd>
+<dt>IPP_TAG_RANGE </dt>
+<dd class="description">Range value</dd>
+<dt>IPP_TAG_RESOLUTION </dt>
+<dd class="description">Resolution value</dd>
+<dt>IPP_TAG_STRING </dt>
+<dd class="description">Octet string value</dd>
+<dt>IPP_TAG_SUBSCRIPTION </dt>
+<dd class="description">Subscription group</dd>
+<dt>IPP_TAG_TEXT </dt>
+<dd class="description">Text value</dd>
+<dt>IPP_TAG_TEXTLANG </dt>
+<dd class="description">Text-with-language value</dd>
+<dt>IPP_TAG_UNKNOWN </dt>
+<dd class="description">Unknown value</dd>
+<dt>IPP_TAG_UNSUPPORTED_GROUP </dt>
+<dd class="description">Unsupported attributes group</dd>
+<dt>IPP_TAG_UNSUPPORTED_VALUE </dt>
+<dd class="description">Unsupported value</dd>
+<dt>IPP_TAG_URI </dt>
+<dd class="description">URI value</dd>
+<dt>IPP_TAG_URISCHEME </dt>
+<dd class="description">URI scheme value</dd>
+<dt>IPP_TAG_ZERO </dt>
+<dd class="description">Zero tag - used for separators</dd>
+</dl>
+</div>
+</body>
+</html>
diff --git a/doc/help/api-mime.html b/doc/help/api-mime.html
new file mode 100644
index 000000000..c27337640
--- /dev/null
+++ b/doc/help/api-mime.html
@@ -0,0 +1,833 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>MIME API </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: api-mime.html 9772 2011-05-12 05:46:30Z mike $"
+
+ MIME API header for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>MIME API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/mime.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcupsmime</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#OVERVIEW">Overview</a></li>
+<li><a href="#FUNCTIONS">Functions</a><ul class="code">
+ <li><a href="#mimeAddFilter" title="Add a filter to the current MIME database.">mimeAddFilter</a></li>
+ <li><a href="#mimeAddType" title="Add a MIME type to a database.">mimeAddType</a></li>
+ <li><a href="#mimeAddTypeRule" title="Add a detection rule for a file type.">mimeAddTypeRule</a></li>
+ <li><a href="#mimeDelete" title="Delete (free) a MIME database.">mimeDelete</a></li>
+ <li><a href="#mimeDeleteFilter" title="Delete a filter from the MIME database.">mimeDeleteFilter</a></li>
+ <li><a href="#mimeDeleteType" title="Delete a type from the MIME database.">mimeDeleteType</a></li>
+ <li><a href="#mimeFileType" title="Determine the type of a file.">mimeFileType</a></li>
+ <li><a href="#mimeFilter" title="Find the fastest way to convert from one type to another.">mimeFilter</a></li>
+ <li><a href="#mimeFilter2" title="Find the fastest way to convert from one type to another,
+including file size.">mimeFilter2</a></li>
+ <li><a href="#mimeFilterLookup" title="Lookup a filter.">mimeFilterLookup</a></li>
+ <li><a href="#mimeFirstFilter" title="Get the first filter in the MIME database.">mimeFirstFilter</a></li>
+ <li><a href="#mimeFirstType" title="Get the first type in the MIME database.">mimeFirstType</a></li>
+ <li><a href="#mimeLoad" title="Create a new MIME database from disk.">mimeLoad</a></li>
+ <li><a href="#mimeLoadFilters" title="Load filter definitions from disk.">mimeLoadFilters</a></li>
+ <li><a href="#mimeLoadTypes" title="Load type definitions from disk.">mimeLoadTypes</a></li>
+ <li><a href="#mimeNew" title="Create a new, empty MIME database.">mimeNew</a></li>
+ <li><a href="#mimeNextFilter" title="Get the next filter in the MIME database.">mimeNextFilter</a></li>
+ <li><a href="#mimeNextType" title="Get the next type in the MIME database.">mimeNextType</a></li>
+ <li><a href="#mimeNumFilters" title="Next type">mimeNumFilters</a></li>
+ <li><a href="#mimeNumTypes" title="MIME database">mimeNumTypes</a></li>
+ <li><a href="#mimeSetErrorCallback" title="Set the callback for error messages.">mimeSetErrorCallback</a></li>
+ <li><a href="#mimeType" title="Lookup a file type.">mimeType</a></li>
+</ul></li>
+<li><a href="#TYPES">Data Types</a><ul class="code">
+ <li><a href="#const" title="MIME Database">const</a></li>
+ <li><a href="#mime_filter_t" title="MIME Conversion Filter Data">mime_filter_t</a></li>
+ <li><a href="#mime_magic_t" title="MIME Magic Data">mime_magic_t</a></li>
+ <li><a href="#mime_op_t" title="Types/structures...">mime_op_t</a></li>
+ <li><a href="#mime_t" title="MIME Database">mime_t</a></li>
+ <li><a href="#mime_type_t" title="MIME Type Data">mime_type_t</a></li>
+</ul></li>
+</ul>
+<!--
+ "$Id: api-mime.html 9772 2011-05-12 05:46:30Z mike $"
+
+ MIME API introduction for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>The MIME API provides file typing and conversion services for CUPS.</p>
+<h2 class="title"><a name="FUNCTIONS">Functions</a></h2>
+<h3 class="function"><a name="mimeAddFilter">mimeAddFilter</a></h3>
+<p class="description">Add a filter to the current MIME database.</p>
+<p class="code">
+<a href="#mime_filter_t">mime_filter_t</a> *mimeAddFilter (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_type_t">mime_type_t</a> *src,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_type_t">mime_type_t</a> *dst,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int cost,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#const">const</a> char *filter<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+<dt>src</dt>
+<dd class="description">Source type</dd>
+<dt>dst</dt>
+<dd class="description">Destination type</dd>
+<dt>cost</dt>
+<dd class="description">Relative time/resource cost</dd>
+<dt>filter</dt>
+<dd class="description">Filter program to run</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New filter</p>
+<h3 class="function"><a name="mimeAddType">mimeAddType</a></h3>
+<p class="description">Add a MIME type to a database.</p>
+<p class="code">
+<a href="#mime_type_t">mime_type_t</a> *mimeAddType (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#const">const</a> char *super,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#const">const</a> char *type<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+<dt>super</dt>
+<dd class="description">Super-type name</dd>
+<dt>type</dt>
+<dd class="description">Type name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New (or existing) MIME type</p>
+<h3 class="function"><a name="mimeAddTypeRule">mimeAddTypeRule</a></h3>
+<p class="description">Add a detection rule for a file type.</p>
+<p class="code">
+int mimeAddTypeRule (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_type_t">mime_type_t</a> *mt,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#const">const</a> char *rule<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mt</dt>
+<dd class="description">Type to add to</dd>
+<dt>rule</dt>
+<dd class="description">Rule to add</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h3 class="function"><a name="mimeDelete">mimeDelete</a></h3>
+<p class="description">Delete (free) a MIME database.</p>
+<p class="code">
+void mimeDelete (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+</dl>
+<h3 class="function"><a name="mimeDeleteFilter">mimeDeleteFilter</a></h3>
+<p class="description">Delete a filter from the MIME database.</p>
+<p class="code">
+void mimeDeleteFilter (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_filter_t">mime_filter_t</a> *filter<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+<dt>filter</dt>
+<dd class="description">Filter</dd>
+</dl>
+<h3 class="function"><a name="mimeDeleteType">mimeDeleteType</a></h3>
+<p class="description">Delete a type from the MIME database.</p>
+<p class="code">
+void mimeDeleteType (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_type_t">mime_type_t</a> *mt<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+<dt>mt</dt>
+<dd class="description">Type</dd>
+</dl>
+<h3 class="function"><a name="mimeFileType">mimeFileType</a></h3>
+<p class="description">Determine the type of a file.</p>
+<p class="code">
+<a href="#mime_type_t">mime_type_t</a> *mimeFileType (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#const">const</a> char *pathname,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#const">const</a> char *filename,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *compression<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+<dt>pathname</dt>
+<dd class="description">Name of file to check on disk</dd>
+<dt>filename</dt>
+<dd class="description">Original filename or NULL</dd>
+<dt>compression</dt>
+<dd class="description">Is the file compressed?</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Type of file</p>
+<h3 class="function"><a name="mimeFilter">mimeFilter</a></h3>
+<p class="description">Find the fastest way to convert from one type to another.</p>
+<p class="code">
+cups_array_t *mimeFilter (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_type_t">mime_type_t</a> *src,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_type_t">mime_type_t</a> *dst,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *cost<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+<dt>src</dt>
+<dd class="description">Source file type</dd>
+<dt>dst</dt>
+<dd class="description">Destination file type</dd>
+<dt>cost</dt>
+<dd class="description">Cost of filters</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Array of filters to run</p>
+<h3 class="function"><a name="mimeFilter2">mimeFilter2</a></h3>
+<p class="description">Find the fastest way to convert from one type to another,
+including file size.</p>
+<p class="code">
+cups_array_t *mimeFilter2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_type_t">mime_type_t</a> *src,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t srcsize,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_type_t">mime_type_t</a> *dst,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *cost<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+<dt>src</dt>
+<dd class="description">Source file type</dd>
+<dt>srcsize</dt>
+<dd class="description">Size of source file</dd>
+<dt>dst</dt>
+<dd class="description">Destination file type</dd>
+<dt>cost</dt>
+<dd class="description">Cost of filters</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Array of filters to run</p>
+<h3 class="function"><a name="mimeFilterLookup">mimeFilterLookup</a></h3>
+<p class="description">Lookup a filter.</p>
+<p class="code">
+<a href="#mime_filter_t">mime_filter_t</a> *mimeFilterLookup (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_type_t">mime_type_t</a> *src,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_type_t">mime_type_t</a> *dst<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+<dt>src</dt>
+<dd class="description">Source type</dd>
+<dt>dst</dt>
+<dd class="description">Destination type</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Filter for src-&gt;dst</p>
+<h3 class="function"><a name="mimeFirstFilter">mimeFirstFilter</a></h3>
+<p class="description">Get the first filter in the MIME database.</p>
+<p class="code">
+<a href="#mime_filter_t">mime_filter_t</a> *mimeFirstFilter (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Filter or NULL</p>
+<h3 class="function"><a name="mimeFirstType">mimeFirstType</a></h3>
+<p class="description">Get the first type in the MIME database.</p>
+<p class="code">
+<a href="#mime_type_t">mime_type_t</a> *mimeFirstType (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Type or NULL</p>
+<h3 class="function"><a name="mimeLoad">mimeLoad</a></h3>
+<p class="description">Create a new MIME database from disk.</p>
+<p class="code">
+<a href="#mime_t">mime_t</a> *mimeLoad (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#const">const</a> char *pathname,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#const">const</a> char *filterpath<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>pathname</dt>
+<dd class="description">Directory to load</dd>
+<dt>filterpath</dt>
+<dd class="description">Directory to load</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New MIME database</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function uses <a href="#mimeLoadFilters"><code>mimeLoadFilters</code></a> and <a href="#mimeLoadTypes"><code>mimeLoadTypes</code></a> to
+create a MIME database from a single directory.</p>
+<h3 class="function"><a name="mimeLoadFilters">mimeLoadFilters</a></h3>
+<p class="description">Load filter definitions from disk.</p>
+<p class="code">
+<a href="#mime_t">mime_t</a> *mimeLoadFilters (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#const">const</a> char *pathname,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#const">const</a> char *filterpath<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+<dt>pathname</dt>
+<dd class="description">Directory to load from</dd>
+<dt>filterpath</dt>
+<dd class="description">Default filter program directory</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">MIME database</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function loads all of the .convs files from the specified directory.
+Use <a href="#mimeLoadTypes"><code>mimeLoadTypes</code></a> to load all types before you load the filters.</p>
+<h3 class="function"><a name="mimeLoadTypes">mimeLoadTypes</a></h3>
+<p class="description">Load type definitions from disk.</p>
+<p class="code">
+<a href="#mime_t">mime_t</a> *mimeLoadTypes (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#const">const</a> char *pathname<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database or <code>NULL</code> to create a new one</dd>
+<dt>pathname</dt>
+<dd class="description">Directory to load from</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">MIME database</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function loads all of the .types files from the specified directory.
+Use <a href="#mimeLoadFilters"><code>mimeLoadFilters</code></a> to load all filters after you load the types.</p>
+<h3 class="function"><a name="mimeNew">mimeNew</a></h3>
+<p class="description">Create a new, empty MIME database.</p>
+<p class="code">
+<a href="#mime_t">mime_t</a> *mimeNew (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">MIME database</p>
+<h3 class="function"><a name="mimeNextFilter">mimeNextFilter</a></h3>
+<p class="description">Get the next filter in the MIME database.</p>
+<p class="code">
+<a href="#mime_filter_t">mime_filter_t</a> *mimeNextFilter (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Filter or NULL</p>
+<h3 class="function"><a name="mimeNextType">mimeNextType</a></h3>
+<p class="description">Get the next type in the MIME database.</p>
+<p class="code">
+<a href="#mime_type_t">mime_type_t</a> *mimeNextType (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Type or NULL</p>
+<h3 class="function"><a name="mimeNumFilters">mimeNumFilters</a></h3>
+<p class="description">Next type</p>
+<p class="code">
+int mimeNumFilters (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Get the number of filters in a MIME database.</p>
+<h3 class="function"><a name="mimeNumTypes">mimeNumTypes</a></h3>
+<p class="description">MIME database</p>
+<p class="code">
+int mimeNumTypes (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Get the number of types in a MIME database.</p>
+<h3 class="function"><a name="mimeSetErrorCallback">mimeSetErrorCallback</a></h3>
+<p class="description">Set the callback for error messages.</p>
+<p class="code">
+void mimeSetErrorCallback (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;mime_error_cb_t cb,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *ctx<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+<dt>cb</dt>
+<dd class="description">Callback function</dd>
+<dt>ctx</dt>
+<dd class="description">Context pointer for callback</dd>
+</dl>
+<h3 class="function"><a name="mimeType">mimeType</a></h3>
+<p class="description">Lookup a file type.</p>
+<p class="code">
+<a href="#mime_type_t">mime_type_t</a> *mimeType (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#mime_t">mime_t</a> *mime,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#const">const</a> char *super,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#const">const</a> char *type<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>mime</dt>
+<dd class="description">MIME database</dd>
+<dt>super</dt>
+<dd class="description">Super-type name</dd>
+<dt>type</dt>
+<dd class="description">Type name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Matching file type definition</p>
+<h2 class="title"><a name="TYPES">Data Types</a></h2>
+<h3 class="typedef"><a name="const">const</a></h3>
+<p class="description">MIME Database</p>
+<p class="code">
+typedef void (*constmime_error_cb_t)(void *;
+</p>
+<h3 class="typedef"><a name="mime_filter_t">mime_filter_t</a></h3>
+<p class="description">MIME Conversion Filter Data</p>
+<p class="code">
+typedef struct _mime_filter_s mime_filter_t;
+</p>
+<h3 class="typedef"><a name="mime_magic_t">mime_magic_t</a></h3>
+<p class="description">MIME Magic Data</p>
+<p class="code">
+typedef struct _mime_magic_s mime_magic_t;
+</p>
+<h3 class="typedef"><a name="mime_op_t">mime_op_t</a></h3>
+<p class="description">Types/structures...</p>
+<p class="code">
+typedef enum mime_op_t;
+</p>
+<h3 class="typedef"><a name="mime_t">mime_t</a></h3>
+<p class="description">MIME Database</p>
+<p class="code">
+typedef struct _mime_s mime_t;
+</p>
+<h3 class="typedef"><a name="mime_type_t">mime_type_t</a></h3>
+<p class="description">MIME Type Data</p>
+<p class="code">
+typedef struct _mime_type_s mime_type_t;
+</p>
+</div>
+</body>
+</html>
diff --git a/doc/help/api-overview.html b/doc/help/api-overview.html
new file mode 100644
index 000000000..278df7ca1
--- /dev/null
+++ b/doc/help/api-overview.html
@@ -0,0 +1,501 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>Introduction to CUPS Programming </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: api-overview.html 9772 2011-05-12 05:46:30Z mike $"
+
+ Introduction to CUPS programming header for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Introduction to CUPS Programming</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Headers</th>
+ <th>cups/cups.h<br>
+ cups/array.h<br>
+ cups/backend.h<br>
+ cups/dir.h<br>
+ cups/file.h<br>
+ cups/ppd.h<br>
+ cups/raster.h<br>
+ cups/sidechannel.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Libraries</th>
+ <td>-lcups<br>
+ -lcupsimage</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='raster-driver.html' target='_top'>Developing Raster Printer Drivers</a><br>
+ Programming: <a href='postscript-driver.html' target='_top'>Developing PostScript Printer Drivers</a><br>
+ Programming: <a href='api-filter.html' target='_top'>Filter and Backend Programming</a><br>
+ Programming: <a href='ppd-compiler.html' target='_top'>Introduction to the PPD Compiler</a><br>
+ Programming: <a href='api-array.html' target='_top'>Array API</a><br>
+ Programming: <a href='api-cups.html' target='_top'>CUPS API</a><br>
+ Programming: <a href='api-filedir.html' target='_top'>File and Directory APIs</a><br>
+ Programming: <a href='api-httpipp.html' target='_top'>HTTP and IPP APIs</a><br>
+ Programming: <a href='api-ppd.html' target='_top'>PPD API</a><br>
+ Programming: <a href='api-raster.html' target='_top'>Raster API</a><br>
+ References: <a href='ref-ppdcfile.html' target='_top'>PPD Compiler Driver Information File Reference</a><br>
+ Specifications: <a href='spec-ppd.html' target='_top'>CUPS PPD Extensions</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#OVERVIEW">Overview</a></li>
+<li><a href="#COMPILING">Compiling Programs</a><ul class="subcontents">
+ <li><a href="#XCODE">Compiling with Xcode</a></li>
+ <li><a href="#COMMANDLINE">Compiling with GCC</a></li>
+</ul></li>
+<li><a href="#WHERETOGO">Where to Go Next</a></li>
+</ul>
+<!--
+ "$Id: api-overview.html 9772 2011-05-12 05:46:30Z mike $"
+
+ Introduction to CUPS programming content for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class="title"><a name="OVERVIEW">Overview</a></h2>
+
+<p>CUPS provides two libraries that interface with the different parts of the
+printing system. The "cups" library provides all of the common application and
+filter functions while the "cupsimage" library provides all of the imaging
+functions used in raster printer drivers. The "cups" library functions are
+accessed by including the <var>&lt;cups/cups.h&gt;</var> header, while
+"cupsimage" functions are found in the <var>&lt;cups/raster.h&gt;</var>
+header.</p>
+
+<h2 class="title"><a name="COMPILING">Compiling Programs</a></h2>
+
+<p>The CUPS libraries can be used from any C, C++, or Objective C program.
+The method of compiling against the libraries varies depending on the
+operating system and installation of CUPS. The following sections show how
+to compile a simple program (shown below) in two common environments.</p>
+
+<p>The following simple program lists the available printers on the system:</p>
+
+<pre class="example">
+#include &lt;stdio.h&gt;
+#include &lt;cups/cups.h&gt;
+
+int main(void)
+{
+ int i;
+ cups_dest_t *dests, *dest;
+ int num_dests = cupsGetDests(&amp;dests);
+
+ for (i = num_dests, dest = dests; i &gt; 0; i --, dest ++)
+ {
+ if (dest->instance)
+ printf("%s/%s\n", dest->name, dest->instance);
+ else
+ puts(dest->name);
+ }
+
+ return (0);
+}
+</pre>
+
+<h3><a name="XCODE">Compiling with Xcode</a></h3>
+
+<p>In Xcode, choose <var>New Project...</var> from the <var>File</var> menu,
+then select the <var>Standard Tool</var> project type under <var>Command Line
+Utility</var>. Click <var>Next</var> and choose a project directory. Click
+<var>Next</var> to create the project.</p>
+
+<p>In the project window, double-click on the <var>Targets</var> group and
+control-click on the simple target to show the context menu. Choose
+<var>Existing Framework...</var> from the <var>Add</var> submenu. When the file
+chooser sheet appears, press the <kbd>/</kbd> key and enter "/usr/lib". Scroll
+down the file list and select the <var>libcups.dylib</var> file. Click the
+<var>Add</var> button in the file chooser and attributes sheets.</p>
+
+<p>In the project window, double-click on the <var>main.c</var> source file.
+Replace the template source code with the listing above and save it. Click the
+<var>Build and Go</var> button to build the sample program and run it.</p>
+
+<h3><a name="COMMANDLINE">Compiling with GCC</a></h3>
+
+<p>From the command-line, create a file called <var>sample.c</var> using your
+favorite editor and then run the following command to compile it with GCC and
+run it:</p>
+
+<pre class="command">
+gcc -o simple `cups-config --cflags` simple.c `cups-config --libs`
+./simple
+</pre>
+
+<p>The <code>cups-config</code> command provides the compiler flags
+("cups-config --cflags") and libraries ("cups-config --libs") needed for the
+local system.</p>
+
+<h2 class="title"><a name="WHERETOGO">Where to Go Next</a></h2>
+
+<p>If you are developing a print filter, driver, or backend, see the
+<a href="api-filter.html" target="_top">Filter and Backend Programming</a>
+guide. Raster printer driver developers should also read the
+<a href="api-raster.html" target="_top">Raster API</a> reference.</p>
+</div>
+</body>
+</html>
diff --git a/doc/help/api-ppd.html b/doc/help/api-ppd.html
new file mode 100644
index 000000000..ae32165dd
--- /dev/null
+++ b/doc/help/api-ppd.html
@@ -0,0 +1,2189 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>PPD API </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: api-ppd.html 9772 2011-05-12 05:46:30Z mike $"
+
+ PPD API header for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>PPD API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/ppd.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcups</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a><br>
+ Programming: <a href='api-cups.html' target='_top'>CUPS API</a><br>
+ Specifications: <a href='spec-ppd.html' target='_top'>CUPS PPD Extensions</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#OVERVIEW">Overview</a><ul class="subcontents">
+ <li><a href="#LOADING">Loading a PPD File</a></li>
+ <li><a href="#OPTIONS_AND_GROUPS">Options and Groups</a></li>
+ <li><a href="#CONSTRAINTS">Constraints</a></li>
+ <li><a href="#PAGE_SIZES">Page Sizes</a></li>
+ <li><a href="#ATTRIBUTES">Attributes</a></li>
+</ul></li>
+<li><a href="#FUNCTIONS">Functions</a><ul class="code">
+ <li><a href="#cupsGetConflicts" title="Get a list of conflicting options in a marked PPD.">cupsGetConflicts</a></li>
+ <li><a href="#cupsMarkOptions" title="Mark command-line options in a PPD file.">cupsMarkOptions</a></li>
+ <li><a href="#cupsResolveConflicts" title="Resolve conflicts in a marked PPD.">cupsResolveConflicts</a></li>
+ <li><a href="#ppdClose" title="Free all memory used by the PPD file.">ppdClose</a></li>
+ <li><a href="#ppdCollect" title="Collect all marked options that reside in the specified
+section.">ppdCollect</a></li>
+ <li><a href="#ppdCollect2" title="Collect all marked options that reside in the
+specified section and minimum order.">ppdCollect2</a></li>
+ <li><a href="#ppdConflicts" title="Check to see if there are any conflicts among the
+marked option choices.">ppdConflicts</a></li>
+ <li><a href="#ppdEmit" title="Emit code for marked options to a file.">ppdEmit</a></li>
+ <li><a href="#ppdEmitAfterOrder" title="Emit a subset of the code for marked options to a file.">ppdEmitAfterOrder</a></li>
+ <li><a href="#ppdEmitFd" title="Emit code for marked options to a file.">ppdEmitFd</a></li>
+ <li><a href="#ppdEmitJCL" title="Emit code for JCL options to a file.">ppdEmitJCL</a></li>
+ <li><a href="#ppdEmitJCLEnd" title="Emit JCLEnd code to a file.">ppdEmitJCLEnd</a></li>
+ <li><a href="#ppdEmitString" title="Get a string containing the code for marked options.">ppdEmitString</a></li>
+ <li><a href="#ppdErrorString" title="Returns the text assocated with a status.">ppdErrorString</a></li>
+ <li><a href="#ppdFindAttr" title="Find the first matching attribute.">ppdFindAttr</a></li>
+ <li><a href="#ppdFindChoice" title="Return a pointer to an option choice.">ppdFindChoice</a></li>
+ <li><a href="#ppdFindCustomOption" title="Find a custom option.">ppdFindCustomOption</a></li>
+ <li><a href="#ppdFindCustomParam" title="Find a parameter for a custom option.">ppdFindCustomParam</a></li>
+ <li><a href="#ppdFindMarkedChoice" title="Return the marked choice for the specified option.">ppdFindMarkedChoice</a></li>
+ <li><a href="#ppdFindNextAttr" title="Find the next matching attribute.">ppdFindNextAttr</a></li>
+ <li><a href="#ppdFindOption" title="Return a pointer to the specified option.">ppdFindOption</a></li>
+ <li><a href="#ppdFirstCustomParam" title="Return the first parameter for a custom option.">ppdFirstCustomParam</a></li>
+ <li><a href="#ppdFirstOption" title="Return the first option in the PPD file.">ppdFirstOption</a></li>
+ <li><a href="#ppdInstallableConflict" title="Test whether an option choice conflicts with
+an installable option.">ppdInstallableConflict</a></li>
+ <li><a href="#ppdIsMarked" title="Check to see if an option is marked.">ppdIsMarked</a></li>
+ <li><a href="#ppdLastError" title="Return the status from the last ppdOpen*().">ppdLastError</a></li>
+ <li><a href="#ppdLocalize" title="Localize the PPD file to the current locale.">ppdLocalize</a></li>
+ <li><a href="#ppdLocalizeAttr" title="Localize an attribute.">ppdLocalizeAttr</a></li>
+ <li><a href="#ppdLocalizeIPPReason" title="Get the localized version of a cupsIPPReason
+attribute.">ppdLocalizeIPPReason</a></li>
+ <li><a href="#ppdLocalizeMarkerName" title="Get the localized version of a marker-names
+attribute value.">ppdLocalizeMarkerName</a></li>
+ <li><a href="#ppdMarkDefaults" title="Mark all default options in the PPD file.">ppdMarkDefaults</a></li>
+ <li><a href="#ppdMarkOption" title="Mark an option in a PPD file and return the number of
+conflicts.">ppdMarkOption</a></li>
+ <li><a href="#ppdNextCustomParam" title="Return the next parameter for a custom option.">ppdNextCustomParam</a></li>
+ <li><a href="#ppdNextOption" title="Return the next option in the PPD file.">ppdNextOption</a></li>
+ <li><a href="#ppdOpen" title="Read a PPD file into memory.">ppdOpen</a></li>
+ <li><a href="#ppdOpen2" title="Read a PPD file into memory.">ppdOpen2</a></li>
+ <li><a href="#ppdOpenFd" title="Read a PPD file into memory.">ppdOpenFd</a></li>
+ <li><a href="#ppdOpenFile" title="Read a PPD file into memory.">ppdOpenFile</a></li>
+ <li><a href="#ppdPageLength" title="Get the page length for the given size.">ppdPageLength</a></li>
+ <li><a href="#ppdPageSize" title="Get the page size record for the given size.">ppdPageSize</a></li>
+ <li><a href="#ppdPageSizeLimits" title="Return the custom page size limits.">ppdPageSizeLimits</a></li>
+ <li><a href="#ppdPageWidth" title="Get the page width for the given size.">ppdPageWidth</a></li>
+ <li><a href="#ppdSetConformance" title="Set the conformance level for PPD files.">ppdSetConformance</a></li>
+</ul></li>
+<li><a href="#TYPES">Data Types</a><ul class="code">
+ <li><a href="#ppd_attr_t" title="PPD Attribute Structure ">ppd_attr_t</a></li>
+ <li><a href="#ppd_choice_t" title="Option choices">ppd_choice_t</a></li>
+ <li><a href="#ppd_conform_t" title="Conformance Levels ">ppd_conform_t</a></li>
+ <li><a href="#ppd_const_t" title="Constraints">ppd_const_t</a></li>
+ <li><a href="#ppd_coption_t" title="Custom Option ">ppd_coption_t</a></li>
+ <li><a href="#ppd_cparam_t" title="Custom Parameter ">ppd_cparam_t</a></li>
+ <li><a href="#ppd_cplimit_t" title="Custom Parameter Limit ">ppd_cplimit_t</a></li>
+ <li><a href="#ppd_cptype_t" title="Custom Parameter Type ">ppd_cptype_t</a></li>
+ <li><a href="#ppd_cpvalue_t" title="Custom Parameter Value ">ppd_cpvalue_t</a></li>
+ <li><a href="#ppd_cs_t" title="Colorspaces">ppd_cs_t</a></li>
+ <li><a href="#ppd_emul_t" title="Emulators">ppd_emul_t</a></li>
+ <li><a href="#ppd_file_t" title="PPD File">ppd_file_t</a></li>
+ <li><a href="#ppd_group_t" title="Groups">ppd_group_t</a></li>
+ <li><a href="#ppd_option_t" title="Options">ppd_option_t</a></li>
+ <li><a href="#ppd_profile_t" title="sRGB Color Profiles">ppd_profile_t</a></li>
+ <li><a href="#ppd_section_t" title="Order dependency sections">ppd_section_t</a></li>
+ <li><a href="#ppd_size_t" title="Page Sizes">ppd_size_t</a></li>
+ <li><a href="#ppd_status_t" title="Status Codes ">ppd_status_t</a></li>
+ <li><a href="#ppd_ui_t" title="UI Types">ppd_ui_t</a></li>
+</ul></li>
+<li><a href="#STRUCTURES">Structures</a><ul class="code">
+ <li><a href="#ppd_attr_s" title="PPD Attribute Structure ">ppd_attr_s</a></li>
+ <li><a href="#ppd_choice_s" title="Option choices">ppd_choice_s</a></li>
+ <li><a href="#ppd_const_s" title="Constraints">ppd_const_s</a></li>
+ <li><a href="#ppd_coption_s" title="Custom Option ">ppd_coption_s</a></li>
+ <li><a href="#ppd_cparam_s" title="Custom Parameter ">ppd_cparam_s</a></li>
+ <li><a href="#ppd_emul_s" title="Emulators">ppd_emul_s</a></li>
+ <li><a href="#ppd_file_s" title="PPD File">ppd_file_s</a></li>
+ <li><a href="#ppd_group_s" title="Groups">ppd_group_s</a></li>
+ <li><a href="#ppd_option_s" title="Options">ppd_option_s</a></li>
+ <li><a href="#ppd_profile_s" title="sRGB Color Profiles">ppd_profile_s</a></li>
+ <li><a href="#ppd_size_s" title="Page Sizes">ppd_size_s</a></li>
+</ul></li>
+<li><a href="#UNIONS">Unions</a><ul class="code">
+ <li><a href="#ppd_cplimit_u" title="Custom Parameter Limit ">ppd_cplimit_u</a></li>
+ <li><a href="#ppd_cpvalue_u" title="Custom Parameter Value ">ppd_cpvalue_u</a></li>
+</ul></li>
+<li><a href="#ENUMERATIONS">Constants</a><ul class="code">
+ <li><a href="#ppd_conform_e" title="Conformance Levels ">ppd_conform_e</a></li>
+ <li><a href="#ppd_cs_e" title="Colorspaces">ppd_cs_e</a></li>
+ <li><a href="#ppd_section_e" title="Order dependency sections">ppd_section_e</a></li>
+ <li><a href="#ppd_status_e" title="Status Codes ">ppd_status_e</a></li>
+ <li><a href="#ppd_ui_e" title="UI Types">ppd_ui_e</a></li>
+</ul></li>
+</ul>
+<!--
+ "$Id: api-ppd.html 9772 2011-05-12 05:46:30Z mike $"
+
+ PPD API introduction for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>The CUPS PPD API provides read-only access the data in PostScript Printer
+Description ("PPD") files which are used for all printers with a driver. With
+it you can obtain the data necessary to display printer options to users, mark
+option choices and check for conflicting choices, and output marked choices in
+PostScript output. The <a href="#ppd_file_t"><code>ppd_file_t</code></a>
+structure contains all of the information in a PPD file.</p>
+
+<blockquote><b>Note:</b>
+
+<p>The CUPS PPD API uses the terms "option" and "choice" instead of the Adobe
+terms "MainKeyword" and "OptionKeyword" to refer to specific printer options and
+features. CUPS also treats option ("MainKeyword") and choice ("OptionKeyword")
+values as case-insensitive strings, so option "InputSlot" and choice "Upper"
+are equivalent to "inputslot" and "upper", respectively.</p>
+</blockquote>
+
+<h3><a name="LOADING">Loading a PPD File</a></h3>
+
+<p>The <a href="#ppdOpenFile"><code>ppdOpenFile</code></a> function "opens" a
+PPD file and loads it into memory. For example, the following code opens the
+current printer's PPD file in a CUPS filter:</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd = <a href="#ppdOpenFile">ppdOpenFile</a>(getenv("PPD"));
+</pre>
+
+<p>The return value is a pointer to a new
+<a href="#ppd_file_t"><code>ppd_file_t</code></a> structure or <code>NULL</code>
+if the PPD file does not exist or cannot be loaded. The
+<a href="#ppdClose"><code>ppdClose</code></a> function frees the memory used
+by the structure:</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd;
+
+<a href="#ppdClose">ppdClose</a>(ppd);
+</pre>
+
+<p>Once closed, pointers to the <a href="#ppd_file_t"><code>ppd_file_t</code></a>
+structure and any data in it will no longer be valid.</p>
+
+<h3><a name="OPTIONS_AND_GROUPS">Options and Groups</a></h3>
+
+<p>PPD files support multiple options, which are stored in arrays of
+<a href="#ppd_option_t"><code>ppd_option_t</code></a> and
+<a href="#ppd_choice_t"><code>ppd_choice_t</code></a> structures.</p>
+
+<p>Each option in turn is associated with a group stored in a
+<a href="#ppd_group_t"><code>ppd_group_t</code></a> structure. Groups can be
+specified in the PPD file; if an option is not associated with a group
+then it is put in an automatically-generated "General" group. Groups can also
+have sub-groups, however CUPS currently ignores sub-groups because of past
+abuses of this functionality.</p>
+
+<p>Option choices are selected by marking them using one of three functions. The
+first is <a href="#ppdMarkDefaults"><code>ppdMarkDefaults</code></a> which
+selects all of the default options in the PPD file:</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd;
+
+<a href="#ppdMarkDefaults">ppdMarkDefaults</a>(ppd);
+</pre>
+
+<p>The second is <a href="#ppdMarkOption"><code>ppdMarkOption</code></a>
+which selects a single option choice in the PPD file. For example, the following
+code selects the upper paper tray:</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd;
+
+<a href="#ppdMarkOption">ppdMarkOption</a>(ppd, "InputSlot", "Upper");
+</pre>
+
+<p>The last function is
+<a href="#cupsMarkOptions"><code>cupsMarkOptions</code></a> which selects
+multiple option choices in the PPD file from an array of CUPS options, mapping
+IPP attributes like "media" and "sides" to their corresponding PPD options. You
+typically use this function in a print filter with
+<code>cupsParseOptions</code> and
+<a href="#ppdMarkDefaults"><code>ppdMarkDefaults</code></a> to select all of
+the option choices needed for the job, for example:</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd = <a href="#ppdOpenFile">ppdOpenFile</a>(getenv("PPD"));
+cups_option_t *options = NULL;
+int num_options = cupsParseOptions(argv[5], 0, &amp;options);
+
+<a href="#ppdMarkDefaults">ppdMarkDefaults</a>(ppd);
+<a href="#cupsMarkOptions">cupsMarkOptions</a>(ppd, num_options, options);
+cupsFreeOptions(num_options, options);
+</pre>
+
+<h3><a name="CONSTRAINTS">Constraints</a></h3>
+
+<p>PPD files support specification of conflict conditions, called
+constraints, between different options. Constraints are stored in an array of
+<a href="#ppd_const_t"><code>ppd_const_t</code></a> structures which specify
+the options and choices that conflict with each other. The
+<a href="#ppdConflicts"><code>ppdConflicts</code></a> function tells you
+how many of the selected options are incompatible. Since constraints are
+normally specified in pairs, the returned value is typically an even number.</p>
+
+<h3><a name="PAGE_SIZES">Page Sizes</a></h3>
+
+<p>Page sizes are special options which have physical dimensions and margins
+associated with them. The size information is stored in
+<a href="#ppd_size_t"><code>ppd_size_t</code></a> structures and is available
+by looking up the named size with the
+<a href="#ppdPageSize"><code>ppdPageSize</code></a> function. The page size and
+margins are returned in units called points; there are 72 points per inch. If
+you pass <code>NULL</code> for the size, the currently selected size is
+returned:</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd;
+<a href="#ppd_size_t">ppd_size_t</a> *size = <a href="#ppdPageSize">ppdPageSize</a>(ppd, NULL);
+</pre>
+
+<p>Besides the standard page sizes listed in a PPD file, some printers
+support variable or custom page sizes. Custom page sizes are supported if the
+<code>variables_sizes</code> member of the
+<a href="#ppd_file_t"><code>ppd_file_t</code></a> structure is non-zero.
+The <code>custom_min</code>, <code>custom_max</code>, and
+<code>custom_margins</code> members of the
+<a href="#ppd_file_t"><code>ppd_file_t</code></a> structure define the limits
+of the printable area. To get the resulting media size, use a page size string
+of the form "Custom.<I>width</I>x<I>length</I>", where "width" and "length" are
+in points. Custom page size names can also be specified in inches
+("Custom.<i>width</i>x<i>height</i>in"), centimeters
+("Custom.<i>width</i>x<i>height</i>cm"), or millimeters
+("Custom.<i>width</i>x<i>height</i>mm"):</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd;
+
+/* Get an 576x720 point custom page size */
+<a href="#ppd_size_t">ppd_size_t</a> *size = <a href="#ppdPageSize">ppdPageSize</a>(ppd, "Custom.576x720");
+
+/* Get an 8x10 inch custom page size */
+<a href="#ppd_size_t">ppd_size_t</a> *size = <a href="#ppdPageSize">ppdPageSize</a>(ppd, "Custom.8x10in");
+
+/* Get a 100x200 millimeter custom page size */
+<a href="#ppd_size_t">ppd_size_t</a> *size = <a href="#ppdPageSize">ppdPageSize</a>(ppd, "Custom.100x200mm");
+
+/* Get a 12.7x34.5 centimeter custom page size */
+<a href="#ppd_size_t">ppd_size_t</a> *size = <a href="#ppdPageSize">ppdPageSize</a>(ppd, "Custom.12.7x34.5cm");
+</pre>
+
+<p>If the PPD does not support variable page sizes, the
+<a href="#ppdPageSize"><code>ppdPageSize</code></a> function will return
+<code>NULL</code>.</p>
+
+<h3><a name="ATTRIBUTES">Attributes</a></h3>
+
+<p>Every PPD file is composed of one or more attributes. Most of these
+attributes are used to define groups, options, choices, and page sizes,
+however several informational attributes may be present which you can access
+in your program or filter. Attributes normally look like one of the following
+examples in a PPD file:</p>
+
+<pre class="example">
+*name: "value"
+*name spec: "value"
+*name spec/text: "value"
+</pre>
+
+<p>The <a href="#ppdFindAttr"><code>ppdFindAttr</code></a> and
+<a href="#ppdFindNextAttr"><code>ppdFindNextAttr</code></a> functions find the
+first and next instances, respectively, of the named attribute with the given
+"spec" string and return a <a href="#ppd_attr_t"><code>ppd_attr_t</code></a>
+structure. If you provide a NULL specifier string, all attributes with the
+given name will be returned. For example, the following code lists all of the
+<code>Product</code> attributes in a PPD file:</p>
+
+<pre class="example">
+#include &lt;cups/ppd.h&gt;
+
+<a href="#ppd_file_t">ppd_file_t</a> *ppd;
+<a href="#ppd_attr_t">ppd_attr_t</a> *attr;
+
+for (attr = <a href="#ppdFindAttr">ppdFindAttr</a>(ppd, "Product", NULL);
+ attr != NULL;
+ attr = <a href="#ppdFindNextAttr">ppdFindNextAttr</a>(ppd, "Product", NULL))
+ puts(attr->value);
+</pre>
+<h2 class="title"><a name="FUNCTIONS">Functions</a></h2>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsGetConflicts">cupsGetConflicts</a></h3>
+<p class="description">Get a list of conflicting options in a marked PPD.</p>
+<p class="code">
+int cupsGetConflicts (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *option,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *choice,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_option_t **options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>option</dt>
+<dd class="description">Option to test</dd>
+<dt>choice</dt>
+<dd class="description">Choice to test</dd>
+<dt>options</dt>
+<dd class="description">Conflicting options</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of conflicting options</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function gets a list of options that would conflict if &quot;option&quot; and
+&quot;choice&quot; were marked in the PPD. You would typically call this function
+after marking the currently selected options in the PPD in order to
+determine whether a new option selection would cause a conflict.<br>
+<br>
+The number of conflicting options are returned with &quot;options&quot; pointing to
+the conflicting options. The returned option array must be freed using
+<a href="#cupsFreeOptions"><code>cupsFreeOptions</code></a>.
+
+</p>
+<h3 class="function"><a name="cupsMarkOptions">cupsMarkOptions</a></h3>
+<p class="description">Mark command-line options in a PPD file.</p>
+<p class="code">
+int cupsMarkOptions (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_option_t *options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>num_options</dt>
+<dd class="description">Number of options</dd>
+<dt>options</dt>
+<dd class="description">Options</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if conflicts exist, 0 otherwise</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function maps the IPP &quot;finishings&quot;, &quot;media&quot;, &quot;mirror&quot;,
+&quot;multiple-document-handling&quot;, &quot;output-bin&quot;, &quot;print-color-mode&quot;,
+&quot;print-quality&quot;, &quot;printer-resolution&quot;, and &quot;sides&quot; attributes to their
+corresponding PPD options and choices.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="cupsResolveConflicts">cupsResolveConflicts</a></h3>
+<p class="description">Resolve conflicts in a marked PPD.</p>
+<p class="code">
+int cupsResolveConflicts (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *option,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *choice,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_option_t **options<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>option</dt>
+<dd class="description">Newly selected option or <code>NULL</code> for none</dd>
+<dt>choice</dt>
+<dd class="description">Newly selected choice or <code>NULL</code> for none</dd>
+<dt>num_options</dt>
+<dd class="description">Number of additional selected options</dd>
+<dt>options</dt>
+<dd class="description">Additional selected options</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 on success, 0 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function attempts to resolve any conflicts in a marked PPD, returning
+a list of option changes that are required to resolve them. On input,
+&quot;num_options&quot; and &quot;options&quot; contain any pending option changes that have
+not yet been marked, while &quot;option&quot; and &quot;choice&quot; contain the most recent
+selection which may or may not be in &quot;num_options&quot; or &quot;options&quot;.<br>
+<br>
+On successful return, &quot;num_options&quot; and &quot;options&quot; are updated to contain
+&quot;option&quot; and &quot;choice&quot; along with any changes required to resolve conflicts
+specified in the PPD file and 1 is returned.<br>
+<br>
+If option conflicts cannot be resolved, &quot;num_options&quot; and &quot;options&quot; are not
+changed and 0 is returned.<br>
+<br>
+When resolving conflicts, <code>cupsResolveConflicts</code> does not consider
+changes to the current page size (<code>media</code>, <code>PageSize</code>, and
+<code>PageRegion</code>) or to the most recent option specified in &quot;option&quot;.
+Thus, if the only way to resolve a conflict is to change the page size
+or the option the user most recently changed, <code>cupsResolveConflicts</code>
+will return 0 to indicate it was unable to resolve the conflicts.<br>
+<br>
+The <code>cupsResolveConflicts</code> function uses one of two sources of option
+constraint information. The preferred constraint information is defined by
+<code>cupsUIConstraints</code> and <code>cupsUIResolver</code> attributes - in this
+case, the PPD file provides constraint resolution actions.<br>
+<br>
+The backup constraint information is defined by the
+<code>UIConstraints</code> and <code>NonUIConstraints</code> attributes. These
+constraints are resolved algorithmically by first selecting the default
+choice for the conflicting option, then iterating over all possible choices
+until a non-conflicting option choice is found.
+
+</p>
+<h3 class="function"><a name="ppdClose">ppdClose</a></h3>
+<p class="description">Free all memory used by the PPD file.</p>
+<p class="code">
+void ppdClose (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file record</dd>
+</dl>
+<h3 class="function"><a name="ppdCollect">ppdCollect</a></h3>
+<p class="description">Collect all marked options that reside in the specified
+section.</p>
+<p class="code">
+int ppdCollect (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_section_t">ppd_section_t</a> section,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_choice_t">ppd_choice_t</a> ***choices<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file data</dd>
+<dt>section</dt>
+<dd class="description">Section to collect</dd>
+<dt>choices</dt>
+<dd class="description">Pointers to choices</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of options marked</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The choices array should be freed using <code>free</code> when you are
+finished with it.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppdCollect2">ppdCollect2</a></h3>
+<p class="description">Collect all marked options that reside in the
+specified section and minimum order.</p>
+<p class="code">
+int ppdCollect2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_section_t">ppd_section_t</a> section,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float min_order,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_choice_t">ppd_choice_t</a> ***choices<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file data</dd>
+<dt>section</dt>
+<dd class="description">Section to collect</dd>
+<dt>min_order</dt>
+<dd class="description">Minimum OrderDependency value</dd>
+<dt>choices</dt>
+<dd class="description">Pointers to choices</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of options marked</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The choices array should be freed using <code>free</code> when you are
+finished with it.
+
+</p>
+<h3 class="function"><a name="ppdConflicts">ppdConflicts</a></h3>
+<p class="description">Check to see if there are any conflicts among the
+marked option choices.</p>
+<p class="code">
+int ppdConflicts (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD to check</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of conflicts found</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The returned value is the same as returned by <a href="#ppdMarkOption"><code>ppdMarkOption</code></a>.</p>
+<h3 class="function"><a name="ppdEmit">ppdEmit</a></h3>
+<p class="description">Emit code for marked options to a file.</p>
+<p class="code">
+int ppdEmit (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;FILE *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_section_t">ppd_section_t</a> section<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file record</dd>
+<dt>fp</dt>
+<dd class="description">File to write to</dd>
+<dt>section</dt>
+<dd class="description">Section to write</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppdEmitAfterOrder">ppdEmitAfterOrder</a></h3>
+<p class="description">Emit a subset of the code for marked options to a file.</p>
+<p class="code">
+int ppdEmitAfterOrder (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;FILE *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_section_t">ppd_section_t</a> section,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int limit,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float min_order<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file record</dd>
+<dt>fp</dt>
+<dd class="description">File to write to</dd>
+<dt>section</dt>
+<dd class="description">Section to write</dd>
+<dt>limit</dt>
+<dd class="description">Non-zero to use min_order</dd>
+<dt>min_order</dt>
+<dd class="description">Lowest OrderDependency</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">When &quot;limit&quot; is non-zero, this function only emits options whose
+OrderDependency value is greater than or equal to &quot;min_order&quot;.<br>
+<br>
+When &quot;limit&quot; is zero, this function is identical to ppdEmit().
+
+</p>
+<h3 class="function"><a name="ppdEmitFd">ppdEmitFd</a></h3>
+<p class="description">Emit code for marked options to a file.</p>
+<p class="code">
+int ppdEmitFd (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int fd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_section_t">ppd_section_t</a> section<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file record</dd>
+<dt>fd</dt>
+<dd class="description">File to write to</dd>
+<dt>section</dt>
+<dd class="description">Section to write</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h3 class="function"><a name="ppdEmitJCL">ppdEmitJCL</a></h3>
+<p class="description">Emit code for JCL options to a file.</p>
+<p class="code">
+int ppdEmitJCL (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;FILE *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int job_id,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *user,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *title<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file record</dd>
+<dt>fp</dt>
+<dd class="description">File to write to</dd>
+<dt>job_id</dt>
+<dd class="description">Job ID</dd>
+<dt>user</dt>
+<dd class="description">Username</dd>
+<dt>title</dt>
+<dd class="description">Title</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppdEmitJCLEnd">ppdEmitJCLEnd</a></h3>
+<p class="description">Emit JCLEnd code to a file.</p>
+<p class="code">
+int ppdEmitJCLEnd (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;FILE *fp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file record</dd>
+<dt>fp</dt>
+<dd class="description">File to write to</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppdEmitString">ppdEmitString</a></h3>
+<p class="description">Get a string containing the code for marked options.</p>
+<p class="code">
+char *ppdEmitString (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_section_t">ppd_section_t</a> section,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float min_order<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file record</dd>
+<dt>section</dt>
+<dd class="description">Section to write</dd>
+<dt>min_order</dt>
+<dd class="description">Lowest OrderDependency</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">String containing option code or <code>NULL</code> if there is no option code</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">When &quot;min_order&quot; is greater than zero, this function only includes options
+whose OrderDependency value is greater than or equal to &quot;min_order&quot;.
+Otherwise, all options in the specified section are included in the
+returned string.<br>
+<br>
+The return string is allocated on the heap and should be freed using
+<code>free</code> when you are done with it.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ppdErrorString">ppdErrorString</a></h3>
+<p class="description">Returns the text assocated with a status.</p>
+<p class="code">
+const char *ppdErrorString (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_status_t">ppd_status_t</a> status<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>status</dt>
+<dd class="description">PPD status</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status string</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ppdFindAttr">ppdFindAttr</a></h3>
+<p class="description">Find the first matching attribute.</p>
+<p class="code">
+<a href="#ppd_attr_t">ppd_attr_t</a> *ppdFindAttr (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *spec<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file data</dd>
+<dt>name</dt>
+<dd class="description">Attribute name</dd>
+<dt>spec</dt>
+<dd class="description">Specifier string or <code>NULL</code></dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Attribute or <code>NULL</code> if not found</p>
+<h3 class="function"><a name="ppdFindChoice">ppdFindChoice</a></h3>
+<p class="description">Return a pointer to an option choice.</p>
+<p class="code">
+<a href="#ppd_choice_t">ppd_choice_t</a> *ppdFindChoice (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_option_t">ppd_option_t</a> *o,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *choice<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>o</dt>
+<dd class="description">Pointer to option</dd>
+<dt>choice</dt>
+<dd class="description">Name of choice</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Choice pointer or <code>NULL</code></p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppdFindCustomOption">ppdFindCustomOption</a></h3>
+<p class="description">Find a custom option.</p>
+<p class="code">
+<a href="#ppd_coption_t">ppd_coption_t</a> *ppdFindCustomOption (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *keyword<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>keyword</dt>
+<dd class="description">Custom option name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Custom option or NULL</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppdFindCustomParam">ppdFindCustomParam</a></h3>
+<p class="description">Find a parameter for a custom option.</p>
+<p class="code">
+<a href="#ppd_cparam_t">ppd_cparam_t</a> *ppdFindCustomParam (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_coption_t">ppd_coption_t</a> *opt,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>opt</dt>
+<dd class="description">Custom option</dd>
+<dt>name</dt>
+<dd class="description">Parameter name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Custom parameter or NULL</p>
+<h3 class="function"><a name="ppdFindMarkedChoice">ppdFindMarkedChoice</a></h3>
+<p class="description">Return the marked choice for the specified option.</p>
+<p class="code">
+<a href="#ppd_choice_t">ppd_choice_t</a> *ppdFindMarkedChoice (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *option<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>option</dt>
+<dd class="description">Keyword/option name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Pointer to choice or <code>NULL</code></p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ppdFindNextAttr">ppdFindNextAttr</a></h3>
+<p class="description">Find the next matching attribute.</p>
+<p class="code">
+<a href="#ppd_attr_t">ppd_attr_t</a> *ppdFindNextAttr (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *spec<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file data</dd>
+<dt>name</dt>
+<dd class="description">Attribute name</dd>
+<dt>spec</dt>
+<dd class="description">Specifier string or <code>NULL</code></dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Attribute or <code>NULL</code> if not found</p>
+<h3 class="function"><a name="ppdFindOption">ppdFindOption</a></h3>
+<p class="description">Return a pointer to the specified option.</p>
+<p class="code">
+<a href="#ppd_option_t">ppd_option_t</a> *ppdFindOption (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *option<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file data</dd>
+<dt>option</dt>
+<dd class="description">Option/Keyword name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Pointer to option or <code>NULL</code></p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppdFirstCustomParam">ppdFirstCustomParam</a></h3>
+<p class="description">Return the first parameter for a custom option.</p>
+<p class="code">
+<a href="#ppd_cparam_t">ppd_cparam_t</a> *ppdFirstCustomParam (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_coption_t">ppd_coption_t</a> *opt<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>opt</dt>
+<dd class="description">Custom option</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Custom parameter or NULL</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppdFirstOption">ppdFirstOption</a></h3>
+<p class="description">Return the first option in the PPD file.</p>
+<p class="code">
+<a href="#ppd_option_t">ppd_option_t</a> *ppdFirstOption (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">First option or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Options are returned from all groups in ascending alphanumeric order.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="ppdInstallableConflict">ppdInstallableConflict</a></h3>
+<p class="description">Test whether an option choice conflicts with
+an installable option.</p>
+<p class="code">
+int ppdInstallableConflict (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *option,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *choice<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>option</dt>
+<dd class="description">Option</dd>
+<dt>choice</dt>
+<dd class="description">Choice</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if conflicting, 0 if not conflicting</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function tests whether a particular option choice is available based
+on constraints against options in the &quot;InstallableOptions&quot; group.
+
+</p>
+<h3 class="function"><a name="ppdIsMarked">ppdIsMarked</a></h3>
+<p class="description">Check to see if an option is marked.</p>
+<p class="code">
+int ppdIsMarked (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *option,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *choice<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file data</dd>
+<dt>option</dt>
+<dd class="description">Option/Keyword name</dd>
+<dt>choice</dt>
+<dd class="description">Choice name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Non-zero if option is marked</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ppdLastError">ppdLastError</a></h3>
+<p class="description">Return the status from the last ppdOpen*().</p>
+<p class="code">
+<a href="#ppd_status_t">ppd_status_t</a> ppdLastError (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *line<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>line</dt>
+<dd class="description">Line number</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status code</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppdLocalize">ppdLocalize</a></h3>
+<p class="description">Localize the PPD file to the current locale.</p>
+<p class="code">
+int ppdLocalize (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">All groups, options, and choices are localized, as are ICC profile
+descriptions, printer presets, and custom option parameters. Each
+localized string uses the UTF-8 character encoding.
+
+</p>
+<h3 class="function"><a name="ppdLocalizeAttr">ppdLocalizeAttr</a></h3>
+<p class="description">Localize an attribute.</p>
+<p class="code">
+<a href="#ppd_attr_t">ppd_attr_t</a> *ppdLocalizeAttr (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *keyword,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *spec<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>keyword</dt>
+<dd class="description">Main keyword</dd>
+<dt>spec</dt>
+<dd class="description">Option keyword or <code>NULL</code> for none</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Localized attribute or <code>NULL</code> if none exists</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function uses the current locale to find the localized attribute for
+the given main and option keywords. If no localized version of the
+attribute exists for the current locale, the unlocalized version is returned.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="ppdLocalizeIPPReason">ppdLocalizeIPPReason</a></h3>
+<p class="description">Get the localized version of a cupsIPPReason
+attribute.</p>
+<p class="code">
+const char *ppdLocalizeIPPReason (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *reason,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *scheme,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *buffer,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t bufsize<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>reason</dt>
+<dd class="description">IPP reason keyword to look up</dd>
+<dt>scheme</dt>
+<dd class="description">URI scheme or NULL for text</dd>
+<dt>buffer</dt>
+<dd class="description">Value buffer</dd>
+<dt>bufsize</dt>
+<dd class="description">Size of value buffer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Value or NULL if not found</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function uses the current locale to find the corresponding reason
+text or URI from the attribute value. If &quot;scheme&quot; is NULL or &quot;text&quot;,
+the returned value contains human-readable (UTF-8) text from the translation
+string or attribute value. Otherwise the corresponding URI is returned.<br>
+<br>
+If no value of the requested scheme can be found, NULL is returned.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="ppdLocalizeMarkerName">ppdLocalizeMarkerName</a></h3>
+<p class="description">Get the localized version of a marker-names
+attribute value.</p>
+<p class="code">
+const char *ppdLocalizeMarkerName (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>name</dt>
+<dd class="description">Marker name to look up</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Value or <code>NULL</code> if not found</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function uses the current locale to find the corresponding name
+text from the attribute value. If no localized text for the requested
+name can be found, <code>NULL</code> is returned.
+
+</p>
+<h3 class="function"><a name="ppdMarkDefaults">ppdMarkDefaults</a></h3>
+<p class="description">Mark all default options in the PPD file.</p>
+<p class="code">
+void ppdMarkDefaults (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file record</dd>
+</dl>
+<h3 class="function"><a name="ppdMarkOption">ppdMarkOption</a></h3>
+<p class="description">Mark an option in a PPD file and return the number of
+conflicts.</p>
+<p class="code">
+int ppdMarkOption (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *option,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *choice<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file record</dd>
+<dt>option</dt>
+<dd class="description">Keyword</dd>
+<dt>choice</dt>
+<dd class="description">Option name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of conflicts</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppdNextCustomParam">ppdNextCustomParam</a></h3>
+<p class="description">Return the next parameter for a custom option.</p>
+<p class="code">
+<a href="#ppd_cparam_t">ppd_cparam_t</a> *ppdNextCustomParam (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_coption_t">ppd_coption_t</a> *opt<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>opt</dt>
+<dd class="description">Custom option</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Custom parameter or NULL</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppdNextOption">ppdNextOption</a></h3>
+<p class="description">Return the next option in the PPD file.</p>
+<p class="code">
+<a href="#ppd_option_t">ppd_option_t</a> *ppdNextOption (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Next option or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Options are returned from all groups in ascending alphanumeric order.
+
+</p>
+<h3 class="function"><a name="ppdOpen">ppdOpen</a></h3>
+<p class="description">Read a PPD file into memory.</p>
+<p class="code">
+<a href="#ppd_file_t">ppd_file_t</a> *ppdOpen (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;FILE *fp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read from</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">PPD file record</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppdOpen2">ppdOpen2</a></h3>
+<p class="description">Read a PPD file into memory.</p>
+<p class="code">
+<a href="#ppd_file_t">ppd_file_t</a> *ppdOpen2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_file_t *fp<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read from</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">PPD file record or <code>NULL</code> if the PPD file could not be opened.</p>
+<h3 class="function"><a name="ppdOpenFd">ppdOpenFd</a></h3>
+<p class="description">Read a PPD file into memory.</p>
+<p class="code">
+<a href="#ppd_file_t">ppd_file_t</a> *ppdOpenFd (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int fd<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fd</dt>
+<dd class="description">File to read from</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">PPD file record or <code>NULL</code> if the PPD file could not be opened.</p>
+<h3 class="function"><a name="ppdOpenFile">ppdOpenFile</a></h3>
+<p class="description">Read a PPD file into memory.</p>
+<p class="code">
+<a href="#ppd_file_t">ppd_file_t</a> *ppdOpenFile (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *filename<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>filename</dt>
+<dd class="description">File to read from</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">PPD file record or <code>NULL</code> if the PPD file could not be opened.</p>
+<h3 class="function"><a name="ppdPageLength">ppdPageLength</a></h3>
+<p class="description">Get the page length for the given size.</p>
+<p class="code">
+float ppdPageLength (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>name</dt>
+<dd class="description">Size name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Length of page in points or 0.0</p>
+<h3 class="function"><a name="ppdPageSize">ppdPageSize</a></h3>
+<p class="description">Get the page size record for the given size.</p>
+<p class="code">
+<a href="#ppd_size_t">ppd_size_t</a> *ppdPageSize (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file record</dd>
+<dt>name</dt>
+<dd class="description">Size name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Size record for page or NULL</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4/Mac OS X 10.6&nbsp;</span><a name="ppdPageSizeLimits">ppdPageSizeLimits</a></h3>
+<p class="description">Return the custom page size limits.</p>
+<p class="code">
+int ppdPageSizeLimits (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_size_t">ppd_size_t</a> *minimum,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_size_t">ppd_size_t</a> *maximum<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file record</dd>
+<dt>minimum</dt>
+<dd class="description">Minimum custom size</dd>
+<dt>maximum</dt>
+<dd class="description">Maximum custom size</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if custom sizes are supported, 0 otherwise</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns the minimum and maximum custom page sizes and printable
+areas based on the currently-marked (selected) options.<br>
+<br>
+If the specified PPD file does not support custom page sizes, both
+&quot;minimum&quot; and &quot;maximum&quot; are filled with zeroes.
+
+</p>
+<h3 class="function"><a name="ppdPageWidth">ppdPageWidth</a></h3>
+<p class="description">Get the page width for the given size.</p>
+<p class="code">
+float ppdPageWidth (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file record</dd>
+<dt>name</dt>
+<dd class="description">Size name</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Width of page in points or 0.0</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.1.20/Mac OS X 10.4&nbsp;</span><a name="ppdSetConformance">ppdSetConformance</a></h3>
+<p class="description">Set the conformance level for PPD files.</p>
+<p class="code">
+void ppdSetConformance (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_conform_t">ppd_conform_t</a> c<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>c</dt>
+<dd class="description">Conformance level</dd>
+</dl>
+<h2 class="title"><a name="TYPES">Data Types</a></h2>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ppd_attr_t">ppd_attr_t</a></h3>
+<p class="description">PPD Attribute Structure </p>
+<p class="code">
+typedef struct <a href="#ppd_attr_s">ppd_attr_s</a> ppd_attr_t;
+</p>
+<h3 class="typedef"><a name="ppd_choice_t">ppd_choice_t</a></h3>
+<p class="description">Option choices</p>
+<p class="code">
+typedef struct <a href="#ppd_choice_s">ppd_choice_s</a> ppd_choice_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ppd_conform_t">ppd_conform_t</a></h3>
+<p class="description">Conformance Levels </p>
+<p class="code">
+typedef enum <a href="#ppd_conform_e">ppd_conform_e</a> ppd_conform_t;
+</p>
+<h3 class="typedef"><a name="ppd_const_t">ppd_const_t</a></h3>
+<p class="description">Constraints</p>
+<p class="code">
+typedef struct <a href="#ppd_const_s">ppd_const_s</a> ppd_const_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppd_coption_t">ppd_coption_t</a></h3>
+<p class="description">Custom Option </p>
+<p class="code">
+typedef struct <a href="#ppd_coption_s">ppd_coption_s</a> ppd_coption_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppd_cparam_t">ppd_cparam_t</a></h3>
+<p class="description">Custom Parameter </p>
+<p class="code">
+typedef struct <a href="#ppd_cparam_s">ppd_cparam_s</a> ppd_cparam_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppd_cplimit_t">ppd_cplimit_t</a></h3>
+<p class="description">Custom Parameter Limit </p>
+<p class="code">
+typedef union <a href="#ppd_cplimit_u">ppd_cplimit_u</a> ppd_cplimit_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppd_cptype_t">ppd_cptype_t</a></h3>
+<p class="description">Custom Parameter Type </p>
+<p class="code">
+typedef enum ppd_cptype_e ppd_cptype_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppd_cpvalue_t">ppd_cpvalue_t</a></h3>
+<p class="description">Custom Parameter Value </p>
+<p class="code">
+typedef union <a href="#ppd_cpvalue_u">ppd_cpvalue_u</a> ppd_cpvalue_t;
+</p>
+<h3 class="typedef"><a name="ppd_cs_t">ppd_cs_t</a></h3>
+<p class="description">Colorspaces</p>
+<p class="code">
+typedef enum <a href="#ppd_cs_e">ppd_cs_e</a> ppd_cs_t;
+</p>
+<h3 class="typedef"><a name="ppd_emul_t">ppd_emul_t</a></h3>
+<p class="description">Emulators</p>
+<p class="code">
+typedef struct <a href="#ppd_emul_s">ppd_emul_s</a> ppd_emul_t;
+</p>
+<h3 class="typedef"><a name="ppd_file_t">ppd_file_t</a></h3>
+<p class="description">PPD File</p>
+<p class="code">
+typedef struct <a href="#ppd_file_s">ppd_file_s</a> ppd_file_t;
+</p>
+<h3 class="typedef"><a name="ppd_group_t">ppd_group_t</a></h3>
+<p class="description">Groups</p>
+<p class="code">
+typedef struct <a href="#ppd_group_s">ppd_group_s</a> ppd_group_t;
+</p>
+<h3 class="typedef"><a name="ppd_option_t">ppd_option_t</a></h3>
+<p class="description">Options</p>
+<p class="code">
+typedef struct <a href="#ppd_option_s">ppd_option_s</a> ppd_option_t;
+</p>
+<h3 class="typedef"><a name="ppd_profile_t">ppd_profile_t</a></h3>
+<p class="description">sRGB Color Profiles</p>
+<p class="code">
+typedef struct <a href="#ppd_profile_s">ppd_profile_s</a> ppd_profile_t;
+</p>
+<h3 class="typedef"><a name="ppd_section_t">ppd_section_t</a></h3>
+<p class="description">Order dependency sections</p>
+<p class="code">
+typedef enum <a href="#ppd_section_e">ppd_section_e</a> ppd_section_t;
+</p>
+<h3 class="typedef"><a name="ppd_size_t">ppd_size_t</a></h3>
+<p class="description">Page Sizes</p>
+<p class="code">
+typedef struct <a href="#ppd_size_s">ppd_size_s</a> ppd_size_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ppd_status_t">ppd_status_t</a></h3>
+<p class="description">Status Codes </p>
+<p class="code">
+typedef enum <a href="#ppd_status_e">ppd_status_e</a> ppd_status_t;
+</p>
+<h3 class="typedef"><a name="ppd_ui_t">ppd_ui_t</a></h3>
+<p class="description">UI Types</p>
+<p class="code">
+typedef enum <a href="#ppd_ui_e">ppd_ui_e</a> ppd_ui_t;
+</p>
+<h2 class="title"><a name="STRUCTURES">Structures</a></h2>
+<h3 class="struct"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ppd_attr_s">ppd_attr_s</a></h3>
+<p class="description">PPD Attribute Structure </p>
+<p class="code">struct ppd_attr_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char name[PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char spec[PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char text[PPD_MAX_TEXT];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *value;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>name[PPD_MAX_NAME] </dt>
+<dd class="description">Name of attribute (cupsXYZ)</dd>
+<dt>spec[PPD_MAX_NAME] </dt>
+<dd class="description">Specifier string, if any</dd>
+<dt>text[PPD_MAX_TEXT] </dt>
+<dd class="description">Human-readable text, if any</dd>
+<dt>value </dt>
+<dd class="description">Value string</dd>
+</dl>
+<h3 class="struct"><a name="ppd_choice_s">ppd_choice_s</a></h3>
+<p class="description">Option choices</p>
+<p class="code">struct ppd_choice_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char choice[PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *code;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char marked;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_option_t">ppd_option_t</a> *option;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char text[PPD_MAX_TEXT];<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>choice[PPD_MAX_NAME] </dt>
+<dd class="description">Computer-readable option name</dd>
+<dt>code </dt>
+<dd class="description">Code to send for this option</dd>
+<dt>marked </dt>
+<dd class="description">0 if not selected, 1 otherwise</dd>
+<dt>option </dt>
+<dd class="description">Pointer to parent option structure</dd>
+<dt>text[PPD_MAX_TEXT] </dt>
+<dd class="description">Human-readable option name</dd>
+</dl>
+<h3 class="struct"><a name="ppd_const_s">ppd_const_s</a></h3>
+<p class="description">Constraints</p>
+<p class="code">struct ppd_const_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char choice1[PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char choice2[PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char option1[PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char option2[PPD_MAX_NAME];<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>choice1[PPD_MAX_NAME] </dt>
+<dd class="description">First option/choice (blank for all)</dd>
+<dt>choice2[PPD_MAX_NAME] </dt>
+<dd class="description">Second option/choice (blank for all)</dd>
+<dt>option1[PPD_MAX_NAME] </dt>
+<dd class="description">First keyword</dd>
+<dt>option2[PPD_MAX_NAME] </dt>
+<dd class="description">Second keyword</dd>
+</dl>
+<h3 class="struct"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppd_coption_s">ppd_coption_s</a></h3>
+<p class="description">Custom Option </p>
+<p class="code">struct ppd_coption_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char keyword[PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int marked;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_option_t">ppd_option_t</a> *option;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_array_t *params;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>keyword[PPD_MAX_NAME] </dt>
+<dd class="description">Name of option that is being extended...</dd>
+<dt>marked </dt>
+<dd class="description">Extended option is marked</dd>
+<dt>option </dt>
+<dd class="description">Option that is being extended...</dd>
+<dt>params </dt>
+<dd class="description">Parameters</dd>
+</dl>
+<h3 class="struct"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppd_cparam_s">ppd_cparam_s</a></h3>
+<p class="description">Custom Parameter </p>
+<p class="code">struct ppd_cparam_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_cpvalue_t">ppd_cpvalue_t</a> current;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_cplimit_t">ppd_cplimit_t</a> minimum, maximum;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char name[PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int order;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char text[PPD_MAX_TEXT];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_cptype_t">ppd_cptype_t</a> type;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>current </dt>
+<dd class="description">Current value</dd>
+<dt>maximum </dt>
+<dd class="description">Maximum value</dd>
+<dt>name[PPD_MAX_NAME] </dt>
+<dd class="description">Parameter name</dd>
+<dt>order </dt>
+<dd class="description">Order (0 to N)</dd>
+<dt>text[PPD_MAX_TEXT] </dt>
+<dd class="description">Human-readable text</dd>
+<dt>type </dt>
+<dd class="description">Parameter type</dd>
+</dl>
+<h3 class="struct"><a name="ppd_emul_s">ppd_emul_s</a></h3>
+<p class="description">Emulators</p>
+<p class="code">struct ppd_emul_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char name[PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *start;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *stop;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>name[PPD_MAX_NAME] </dt>
+<dd class="description">Emulator name</dd>
+<dt>start </dt>
+<dd class="description">Code to switch to this emulation</dd>
+<dt>stop </dt>
+<dd class="description">Code to stop this emulation</dd>
+</dl>
+<h3 class="struct"><a name="ppd_file_s">ppd_file_s</a></h3>
+<p class="description">PPD File</p>
+<p class="code">struct ppd_file_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int accurate_screens;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int color_device;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_cs_t">ppd_cs_t</a> colorspace;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_const_t">ppd_const_t</a> *consts;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int contone_only;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float custom_margins[4];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float custom_max[2];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float custom_min[2];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_emul_t">ppd_emul_t</a> *emulations;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char **filters;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int flip_duplex;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char **fonts;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_group_t">ppd_group_t</a> *groups;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *jcl_begin;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *jcl_end;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *jcl_ps;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int landscape;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *lang_encoding;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *lang_version;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int language_level;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int manual_copies;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *manufacturer;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int model_number;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *modelname;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *nickname;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_consts;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_emulations;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_filters;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_fonts;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_groups;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_profiles;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_sizes;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *patches;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *pcfilename;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *product;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_profile_t">ppd_profile_t</a> *profiles;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *protocols;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *shortnickname;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_size_t">ppd_size_t</a> *sizes;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int throughput;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *ttrasterizer;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int variable_sizes;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>accurate_screens </dt>
+<dd class="description">1 = supports accurate screens, 0 = not</dd>
+<dt>color_device </dt>
+<dd class="description">1 = color device, 0 = grayscale</dd>
+<dt>colorspace </dt>
+<dd class="description">Default colorspace</dd>
+<dt>consts </dt>
+<dd class="description">UI/Non-UI constraints</dd>
+<dt>contone_only </dt>
+<dd class="description">1 = continuous tone only, 0 = not</dd>
+<dt>custom_margins[4] </dt>
+<dd class="description">Margins around page</dd>
+<dt>custom_max[2] </dt>
+<dd class="description">Maximum variable page size</dd>
+<dt>custom_min[2] </dt>
+<dd class="description">Minimum variable page size</dd>
+<dt>emulations </dt>
+<dd class="description">Emulations and the code to invoke them</dd>
+<dt>filters </dt>
+<dd class="description">Filter strings...</dd>
+<dt>flip_duplex <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">1 = Flip page for back sides </dd>
+<dt>fonts </dt>
+<dd class="description">Pre-loaded fonts</dd>
+<dt>groups </dt>
+<dd class="description">UI groups</dd>
+<dt>jcl_begin </dt>
+<dd class="description">Start JCL commands</dd>
+<dt>jcl_end </dt>
+<dd class="description">End JCL commands</dd>
+<dt>jcl_ps </dt>
+<dd class="description">Enter PostScript interpreter</dd>
+<dt>landscape </dt>
+<dd class="description">-90 or 90</dd>
+<dt>lang_encoding </dt>
+<dd class="description">Language encoding</dd>
+<dt>lang_version </dt>
+<dd class="description">Language version (English, Spanish, etc.)</dd>
+<dt>language_level </dt>
+<dd class="description">Language level of device</dd>
+<dt>manual_copies </dt>
+<dd class="description">1 = Copies done manually, 0 = hardware</dd>
+<dt>manufacturer </dt>
+<dd class="description">Manufacturer name</dd>
+<dt>model_number </dt>
+<dd class="description">Device-specific model number</dd>
+<dt>modelname </dt>
+<dd class="description">Model name (general)</dd>
+<dt>nickname </dt>
+<dd class="description">Nickname (specific)</dd>
+<dt>num_consts </dt>
+<dd class="description">Number of UI/Non-UI constraints</dd>
+<dt>num_emulations </dt>
+<dd class="description">Number of emulations supported</dd>
+<dt>num_filters </dt>
+<dd class="description">Number of filters</dd>
+<dt>num_fonts </dt>
+<dd class="description">Number of pre-loaded fonts</dd>
+<dt>num_groups </dt>
+<dd class="description">Number of UI groups</dd>
+<dt>num_profiles <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Number of sRGB color profiles </dd>
+<dt>num_sizes </dt>
+<dd class="description">Number of page sizes</dd>
+<dt>patches </dt>
+<dd class="description">Patch commands to be sent to printer</dd>
+<dt>pcfilename <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">PCFileName string </dd>
+<dt>product </dt>
+<dd class="description">Product name (from PS RIP/interpreter)</dd>
+<dt>profiles <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">sRGB color profiles </dd>
+<dt>protocols <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">Protocols (BCP, TBCP) string </dd>
+<dt>shortnickname </dt>
+<dd class="description">Short version of nickname</dd>
+<dt>sizes </dt>
+<dd class="description">Page sizes</dd>
+<dt>throughput </dt>
+<dd class="description">Pages per minute</dd>
+<dt>ttrasterizer </dt>
+<dd class="description">Truetype rasterizer</dd>
+<dt>variable_sizes </dt>
+<dd class="description">1 = supports variable sizes, 0 = doesn't</dd>
+</dl>
+<h3 class="struct"><a name="ppd_group_s">ppd_group_s</a></h3>
+<p class="description">Groups</p>
+<p class="code">struct ppd_group_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char text[PPD_MAX_TEXT - PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char name[PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_subgroups;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_option_t">ppd_option_t</a> *options;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;struct <a href="#ppd_group_s">ppd_group_s</a> *subgroups;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>PPD_MAX_NAME] </dt>
+<dd class="description">Human-readable group name</dd>
+<dt>name[PPD_MAX_NAME] <span class="info">&nbsp;CUPS 1.1.18/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">Group name </dd>
+<dt>num_options </dt>
+<dd class="description">Number of options</dd>
+<dt>num_subgroups </dt>
+<dd class="description">Number of sub-groups</dd>
+<dt>options </dt>
+<dd class="description">Options</dd>
+<dt>subgroups </dt>
+<dd class="description">Sub-groups (max depth = 1)</dd>
+</dl>
+<h3 class="struct"><a name="ppd_option_s">ppd_option_s</a></h3>
+<p class="description">Options</p>
+<p class="code">struct ppd_option_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_choice_t">ppd_choice_t</a> *choices;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char conflicted;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char defchoice[PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char keyword[PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_choices;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float order;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_section_t">ppd_section_t</a> section;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char text[PPD_MAX_TEXT];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_ui_t">ppd_ui_t</a> ui;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>choices </dt>
+<dd class="description">Option choices</dd>
+<dt>conflicted </dt>
+<dd class="description">0 if no conflicts exist, 1 otherwise</dd>
+<dt>defchoice[PPD_MAX_NAME] </dt>
+<dd class="description">Default option choice</dd>
+<dt>keyword[PPD_MAX_NAME] </dt>
+<dd class="description">Option keyword name (&quot;PageSize&quot;, etc.)</dd>
+<dt>num_choices </dt>
+<dd class="description">Number of option choices</dd>
+<dt>order </dt>
+<dd class="description">Order number</dd>
+<dt>section </dt>
+<dd class="description">Section for command</dd>
+<dt>text[PPD_MAX_TEXT] </dt>
+<dd class="description">Human-readable text</dd>
+<dt>ui </dt>
+<dd class="description">Type of UI option</dd>
+</dl>
+<h3 class="struct"><a name="ppd_profile_s">ppd_profile_s</a></h3>
+<p class="description">sRGB Color Profiles</p>
+<p class="code">struct ppd_profile_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float density;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float gamma;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float matrix[3][3];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char media_type[PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char resolution[PPD_MAX_NAME];<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>density </dt>
+<dd class="description">Ink density to use</dd>
+<dt>gamma </dt>
+<dd class="description">Gamma correction to use</dd>
+<dt>matrix[3][3] </dt>
+<dd class="description">Transform matrix</dd>
+<dt>media_type[PPD_MAX_NAME] </dt>
+<dd class="description">Media type or &quot;-&quot;</dd>
+<dt>resolution[PPD_MAX_NAME] </dt>
+<dd class="description">Resolution or &quot;-&quot;</dd>
+</dl>
+<h3 class="struct"><a name="ppd_size_s">ppd_size_s</a></h3>
+<p class="description">Page Sizes</p>
+<p class="code">struct ppd_size_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float bottom;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float left;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float length;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int marked;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char name[PPD_MAX_NAME];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float right;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float top;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float width;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>bottom </dt>
+<dd class="description">Bottom printable margin in points</dd>
+<dt>left </dt>
+<dd class="description">Left printable margin in points</dd>
+<dt>length </dt>
+<dd class="description">Length of media in points</dd>
+<dt>marked </dt>
+<dd class="description">Page size selected?</dd>
+<dt>name[PPD_MAX_NAME] </dt>
+<dd class="description">Media size option</dd>
+<dt>right </dt>
+<dd class="description">Right printable margin in points</dd>
+<dt>top </dt>
+<dd class="description">Top printable margin in points</dd>
+<dt>width </dt>
+<dd class="description">Width of media in points</dd>
+</dl>
+<h2 class="title"><a name="UNIONS">Unions</a></h2>
+<h3 class="union"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppd_cplimit_u">ppd_cplimit_u</a></h3>
+<p class="description">Custom Parameter Limit </p>
+<p class="code">union ppd_cplimit_u {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float custom_curve;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int custom_int;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float custom_invcurve;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int custom_passcode;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int custom_password;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float custom_points;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float custom_real;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int custom_string;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>custom_curve </dt>
+<dd class="description">Gamma value</dd>
+<dt>custom_int </dt>
+<dd class="description">Integer value</dd>
+<dt>custom_invcurve </dt>
+<dd class="description">Gamma value</dd>
+<dt>custom_passcode </dt>
+<dd class="description">Passcode length</dd>
+<dt>custom_password </dt>
+<dd class="description">Password length</dd>
+<dt>custom_points </dt>
+<dd class="description">Measurement value</dd>
+<dt>custom_real </dt>
+<dd class="description">Real value</dd>
+<dt>custom_string </dt>
+<dd class="description">String length</dd>
+</dl>
+<h3 class="union"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="ppd_cpvalue_u">ppd_cpvalue_u</a></h3>
+<p class="description">Custom Parameter Value </p>
+<p class="code">union ppd_cpvalue_u {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float custom_curve;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int custom_int;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float custom_invcurve;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *custom_passcode;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *custom_password;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float custom_points;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float custom_real;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *custom_string;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>custom_curve </dt>
+<dd class="description">Gamma value</dd>
+<dt>custom_int </dt>
+<dd class="description">Integer value</dd>
+<dt>custom_invcurve </dt>
+<dd class="description">Gamma value</dd>
+<dt>custom_passcode </dt>
+<dd class="description">Passcode value</dd>
+<dt>custom_password </dt>
+<dd class="description">Password value</dd>
+<dt>custom_points </dt>
+<dd class="description">Measurement value</dd>
+<dt>custom_real </dt>
+<dd class="description">Real value</dd>
+<dt>custom_string </dt>
+<dd class="description">String value</dd>
+</dl>
+<h2 class="title"><a name="ENUMERATIONS">Constants</a></h2>
+<h3 class="enumeration"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ppd_conform_e">ppd_conform_e</a></h3>
+<p class="description">Conformance Levels </p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>PPD_CONFORM_RELAXED </dt>
+<dd class="description">Relax whitespace and control char</dd>
+<dt>PPD_CONFORM_STRICT </dt>
+<dd class="description">Require strict conformance</dd>
+</dl>
+<h3 class="enumeration"><a name="ppd_cs_e">ppd_cs_e</a></h3>
+<p class="description">Colorspaces</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>PPD_CS_CMY </dt>
+<dd class="description">CMY colorspace</dd>
+<dt>PPD_CS_CMYK </dt>
+<dd class="description">CMYK colorspace</dd>
+<dt>PPD_CS_GRAY </dt>
+<dd class="description">Grayscale colorspace</dd>
+<dt>PPD_CS_N </dt>
+<dd class="description">DeviceN colorspace</dd>
+<dt>PPD_CS_RGB </dt>
+<dd class="description">RGB colorspace</dd>
+<dt>PPD_CS_RGBK </dt>
+<dd class="description">RGBK (K = gray) colorspace</dd>
+</dl>
+<h3 class="enumeration"><a name="ppd_section_e">ppd_section_e</a></h3>
+<p class="description">Order dependency sections</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>PPD_ORDER_ANY </dt>
+<dd class="description">Option code can be anywhere in the file</dd>
+<dt>PPD_ORDER_DOCUMENT </dt>
+<dd class="description">... must be in the DocumentSetup section</dd>
+<dt>PPD_ORDER_EXIT </dt>
+<dd class="description">... must be sent prior to the document</dd>
+<dt>PPD_ORDER_JCL </dt>
+<dd class="description">... must be sent as a JCL command</dd>
+<dt>PPD_ORDER_PAGE </dt>
+<dd class="description">... must be in the PageSetup section</dd>
+<dt>PPD_ORDER_PROLOG </dt>
+<dd class="description">... must be in the Prolog section</dd>
+</dl>
+<h3 class="enumeration"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="ppd_status_e">ppd_status_e</a></h3>
+<p class="description">Status Codes </p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>PPD_ALLOC_ERROR </dt>
+<dd class="description">Memory allocation error</dd>
+<dt>PPD_BAD_CUSTOM_PARAM </dt>
+<dd class="description">Bad custom parameter</dd>
+<dt>PPD_BAD_OPEN_GROUP </dt>
+<dd class="description">Bad OpenGroup</dd>
+<dt>PPD_BAD_OPEN_UI </dt>
+<dd class="description">Bad OpenUI/JCLOpenUI</dd>
+<dt>PPD_BAD_ORDER_DEPENDENCY </dt>
+<dd class="description">Bad OrderDependency</dd>
+<dt>PPD_BAD_UI_CONSTRAINTS </dt>
+<dd class="description">Bad UIConstraints</dd>
+<dt>PPD_BAD_VALUE </dt>
+<dd class="description">Bad value string</dd>
+<dt>PPD_FILE_OPEN_ERROR </dt>
+<dd class="description">Unable to open PPD file</dd>
+<dt>PPD_ILLEGAL_CHARACTER </dt>
+<dd class="description">Illegal control character</dd>
+<dt>PPD_ILLEGAL_MAIN_KEYWORD </dt>
+<dd class="description">Illegal main keyword string</dd>
+<dt>PPD_ILLEGAL_OPTION_KEYWORD </dt>
+<dd class="description">Illegal option keyword string</dd>
+<dt>PPD_ILLEGAL_TRANSLATION </dt>
+<dd class="description">Illegal translation string</dd>
+<dt>PPD_ILLEGAL_WHITESPACE </dt>
+<dd class="description">Illegal whitespace character</dd>
+<dt>PPD_INTERNAL_ERROR </dt>
+<dd class="description">Internal error</dd>
+<dt>PPD_LINE_TOO_LONG </dt>
+<dd class="description">Line longer than 255 chars</dd>
+<dt>PPD_MISSING_ASTERISK </dt>
+<dd class="description">Missing asterisk in column 0</dd>
+<dt>PPD_MISSING_CLOSE_GROUP </dt>
+<dd class="description">Missing CloseGroup</dd>
+<dt>PPD_MISSING_OPTION_KEYWORD </dt>
+<dd class="description">Missing option keyword</dd>
+<dt>PPD_MISSING_PPDADOBE4 </dt>
+<dd class="description">Missing PPD-Adobe-4.x header</dd>
+<dt>PPD_MISSING_VALUE </dt>
+<dd class="description">Missing value string</dd>
+<dt>PPD_NESTED_OPEN_GROUP </dt>
+<dd class="description">OpenGroup without a CloseGroup first</dd>
+<dt>PPD_NESTED_OPEN_UI </dt>
+<dd class="description">OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first</dd>
+<dt>PPD_NULL_FILE </dt>
+<dd class="description">NULL PPD file pointer</dd>
+<dt>PPD_OK </dt>
+<dd class="description">OK</dd>
+</dl>
+<h3 class="enumeration"><a name="ppd_ui_e">ppd_ui_e</a></h3>
+<p class="description">UI Types</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>PPD_UI_BOOLEAN </dt>
+<dd class="description">True or False option</dd>
+<dt>PPD_UI_PICKMANY </dt>
+<dd class="description">Pick zero or more from a list</dd>
+<dt>PPD_UI_PICKONE </dt>
+<dd class="description">Pick one from a list</dd>
+</dl>
+</div>
+</body>
+</html>
diff --git a/doc/help/api-ppdc.html b/doc/help/api-ppdc.html
new file mode 100644
index 000000000..cb15f61e6
--- /dev/null
+++ b/doc/help/api-ppdc.html
@@ -0,0 +1,2197 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>PPD Compiler API </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: api-ppdc.html 9740 2011-05-04 06:26:22Z mike $"
+
+ PPD Compiler API header for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>PPD Compiler API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/ppdc.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcupsppdc</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#OVERVIEW">Overview</a></li>
+<li><a href="#CLASSES">Classes</a><ul class="code">
+ <li><a href="#ppdcArray" title="// Shared Array">ppdcArray</a></li>
+ <li><a href="#ppdcAttr" title="// Attribute">ppdcAttr</a></li>
+ <li><a href="#ppdcCatalog" title="// Translation catalog">ppdcCatalog</a></li>
+ <li><a href="#ppdcChoice" title="// Option Choice">ppdcChoice</a></li>
+ <li><a href="#ppdcConstraint" title="// Constraint">ppdcConstraint</a></li>
+ <li><a href="#ppdcDriver" title="// Printer Driver Data">ppdcDriver</a></li>
+ <li><a href="#ppdcFile" title="// File">ppdcFile</a></li>
+ <li><a href="#ppdcFilter" title="// Filter Program">ppdcFilter</a></li>
+ <li><a href="#ppdcFont" title="// Shared Font">ppdcFont</a></li>
+ <li><a href="#ppdcGroup" title="// Group of Options">ppdcGroup</a></li>
+ <li><a href="#ppdcInteger" title="// Shared integer">ppdcInteger</a></li>
+ <li><a href="#ppdcMediaSize" title="// Media Size">ppdcMediaSize</a></li>
+ <li><a href="#ppdcMessage" title="// Translation message">ppdcMessage</a></li>
+ <li><a href="#ppdcOption" title="// Option">ppdcOption</a></li>
+ <li><a href="#ppdcProfile" title="// Color Profile">ppdcProfile</a></li>
+ <li><a href="#ppdcShared" title="// Shared Data Value">ppdcShared</a></li>
+ <li><a href="#ppdcSource" title="// Source File">ppdcSource</a></li>
+ <li><a href="#ppdcString" title="// Shared String">ppdcString</a></li>
+ <li><a href="#ppdcVariable" title="// Variable Definition">ppdcVariable</a></li>
+</ul></li>
+<li><a href="#TYPES">Data Types</a><ul class="code">
+ <li><a href="#ppdc_cs_t" title="">ppdc_cs_t</a></li>
+</ul></li>
+<li><a href="#VARIABLES">Variables</a><ul class="code">
+ <li><a href="#ppdcSource" title="// Printer Driver Data">ppdcSource</a></li>
+</ul></li>
+<li><a href="#ENUMERATIONS">Constants</a><ul class="code">
+ <li><a href="#ppdcCondFlags" title="// Condition flags">ppdcCondFlags</a></li>
+ <li><a href="#ppdcDrvType" title="// Driver type">ppdcDrvType</a></li>
+ <li><a href="#ppdcFontStatus" title="// Load status of font">ppdcFontStatus</a></li>
+ <li><a href="#ppdcLineEnding" title="// Line endings">ppdcLineEnding</a></li>
+ <li><a href="#ppdcOptSection" title="// Option section">ppdcOptSection</a></li>
+ <li><a href="#ppdcOptType" title="// Option type">ppdcOptType</a></li>
+</ul></li>
+</ul>
+<!--
+ "$Id: api-ppdc.html 9740 2011-05-04 06:26:22Z mike $"
+
+ PPD Compiler API introduction for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>The PPD Compiler API provides access to CUPS driver information files and
+methods for generating and importing PPD files.</p>
+<h2 class="title"><a name="CLASSES">Classes</a></h2>
+<h3 class="class"><a name="ppdcArray">ppdcArray</a></h3>
+<p class="description">// Shared Array</p>
+<p class="code">class ppdcArray : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int count, alloc, current;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcShared">ppdcShared</a> **data;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>current </dt>
+<dd class="description">Current element</dd>
+<dt>data </dt>
+<dd class="description">Elements</dd>
+</dl>
+<h4 class="method"><a name="PPDC_NAME">PPDC_NAME</a></h4>
+<p class="description"></p>
+<p class="code">
+void PPDC_NAME (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void add(<a href="#ppdcShared">ppdcShared</a> *d<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>d</dt>
+</dl>
+<h4 class="method"><a name="add">add</a></h4>
+<p class="description"></p>
+<p class="code">
+void add (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcShared">ppdcShared</a> *d<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>d</dt>
+</dl>
+<h4 class="method"><a name="first">first</a></h4>
+<p class="description">Return the first element in the array.</p>
+<p class="code">
+<a href="#ppdcShared">ppdcShared</a> *first (void);</p>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description"></p>
+<h4 class="method"><a name="next">next</a></h4>
+<p class="description">Return the next element in the array.</p>
+<p class="code">
+<a href="#ppdcShared">ppdcShared</a> *next (void);</p>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description"></p>
+<h4 class="method"><a name="ppdcArray">ppdcArray</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcArray (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcArray">ppdcArray</a> *a<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>a</dt>
+</dl>
+<h4 class="method"><a name="remove">remove</a></h4>
+<p class="description"></p>
+<p class="code">
+void remove (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcShared">ppdcShared</a> *d<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>d</dt>
+<dd class="description">Data element</dd>
+</dl>
+<h4 class="method"><a name="~ppdcArray">~ppdcArray</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcArray (void);</p>
+<h3 class="class"><a name="ppdcAttr">ppdcAttr</a></h3>
+<p class="description">// Attribute</p>
+<p class="code">class ppdcAttr : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;bool localizable;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *name, *selector, *text, *value;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>localizable </dt>
+<dd class="description">Should this attribute be localized?</dd>
+<dt>value </dt>
+<dd class="description">Value string</dd>
+</dl>
+<h4 class="method"><a name="ppdcAttr">ppdcAttr</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcAttr (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *n,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *s,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *t,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *v,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;bool loc<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>n</dt>
+<dd class="description">Name</dd>
+<dt>s</dt>
+<dd class="description">Spec string</dd>
+<dt>t</dt>
+<dd class="description">Human-readable text</dd>
+<dt>v</dt>
+<dd class="description">Value</dd>
+<dt>loc</dt>
+<dd class="description">Localize this attribute?</dd>
+</dl>
+<h4 class="method"><a name="~ppdcAttr">~ppdcAttr</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcAttr (void);</p>
+<h3 class="class"><a name="ppdcCatalog">ppdcCatalog</a></h3>
+<p class="description">// Translation catalog</p>
+<p class="code">class ppdcCatalog : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *filename;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *locale;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcArray">ppdcArray</a> *messages;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>filename </dt>
+<dd class="description">Name of translation file</dd>
+<dt>locale </dt>
+<dd class="description">Name of locale</dd>
+<dt>messages </dt>
+<dd class="description">Array of translation messages</dd>
+</dl>
+<h4 class="method"><a name="PPDC_NAME">PPDC_NAME</a></h4>
+<p class="description"></p>
+<p class="code">
+void PPDC_NAME (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void add_message(const char *id,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *string = NULL<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>id</dt>
+<dt>string</dt>
+</dl>
+<h4 class="method"><a name="add_message">add_message</a></h4>
+<p class="description"></p>
+<p class="code">
+void add_message (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *id,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *string<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>id</dt>
+<dd class="description">Message ID to add</dd>
+<dt>string</dt>
+<dd class="description">Translation string</dd>
+</dl>
+<h4 class="method"><a name="find_message">find_message</a></h4>
+<p class="description"></p>
+<p class="code">
+const char *find_message (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *id<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>id</dt>
+<dd class="description">Message ID</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Message text</p>
+<h4 class="method"><a name="load_messages">load_messages</a></h4>
+<p class="description"></p>
+<p class="code">
+int load_messages (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *f<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>f</dt>
+<dd class="description">Message catalog file</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">0 on success, -1 on failure</p>
+<h4 class="method"><a name="ppdcCatalog">ppdcCatalog</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcCatalog (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *l,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *f<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>l</dt>
+<dd class="description">Locale</dd>
+<dt>f</dt>
+<dd class="description">Message catalog file</dd>
+</dl>
+<h4 class="method"><a name="save_messages">save_messages</a></h4>
+<p class="description"></p>
+<p class="code">
+int save_messages (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *f<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>f</dt>
+<dd class="description">File to save to</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">0 on success, -1 on error</p>
+<h4 class="method"><a name="~ppdcCatalog">~ppdcCatalog</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcCatalog (void);</p>
+<h3 class="class"><a name="ppdcChoice">ppdcChoice</a></h3>
+<p class="description">// Option Choice</p>
+<p class="code">class ppdcChoice : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *name, *text, *code;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>code </dt>
+<dd class="description">PS code of choice</dd>
+</dl>
+<h4 class="method"><a name="ppdcChoice">ppdcChoice</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcChoice (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *n,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *t,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *c<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>n</dt>
+<dd class="description">Name of choice</dd>
+<dt>t</dt>
+<dd class="description">Text of choice</dd>
+<dt>c</dt>
+<dd class="description">Code of choice</dd>
+</dl>
+<h4 class="method"><a name="~ppdcChoice">~ppdcChoice</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcChoice (void);</p>
+<h3 class="class"><a name="ppdcConstraint">ppdcConstraint</a></h3>
+<p class="description">// Constraint</p>
+<p class="code">class ppdcConstraint : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *option1, *choice1, *option2, *choice2;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>choice2 </dt>
+<dd class="description">Second choice</dd>
+</dl>
+<h4 class="method"><a name="ppdcConstraint">ppdcConstraint</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcConstraint (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *o1,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *c1,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *o2,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *c2<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>o1</dt>
+<dd class="description">First option</dd>
+<dt>c1</dt>
+<dd class="description">First choice</dd>
+<dt>o2</dt>
+<dd class="description">Second option</dd>
+<dt>c2</dt>
+<dd class="description">Second choice</dd>
+</dl>
+<h4 class="method"><a name="~ppdcConstraint">~ppdcConstraint</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcConstraint (void);</p>
+<h3 class="class"><a name="ppdcDriver">ppdcDriver</a></h3>
+<p class="description">// Printer Driver Data</p>
+<p class="code">class ppdcDriver : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcArray">ppdcArray</a> *copyright;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *custom_size_code;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *default_font, *default_size;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float left_margin, bottom_margin, right_margin, top_margin, max_width, max_length, min_width, min_length;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcArray">ppdcArray</a> *attrs, *constraints, *filters, *fonts, *groups, *profiles, *sizes;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int model_number, manual_copies, color_device, throughput;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcDrvType">ppdcDrvType</a> type;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int variable_paper_size;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *manufacturer, *model_name, *file_name, *pc_file_name, *version;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>copyright </dt>
+<dd class="description">Copyright strings</dd>
+<dt>custom_size_code </dt>
+<dd class="description">Custom page size code, if any</dd>
+<dt>default_size </dt>
+<dd class="description">Default size option</dd>
+<dt>min_length </dt>
+<dd class="description">Minimum length (points)</dd>
+<dt>sizes </dt>
+<dd class="description">Fixed sizes</dd>
+<dt>throughput </dt>
+<dd class="description">Throughput in pages per minute</dd>
+<dt>type </dt>
+<dd class="description">Driver type</dd>
+<dt>variable_paper_size </dt>
+<dd class="description">Support variable sizes?</dd>
+<dt>version </dt>
+<dd class="description">Version number</dd>
+</dl>
+<h4 class="method"><a name="PPDC_NAME">PPDC_NAME</a></h4>
+<p class="description"></p>
+<p class="code">
+void PPDC_NAME (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void add_attr(<a href="#ppdcAttr">ppdcAttr</a> *a<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>a</dt>
+</dl>
+<h4 class="method"><a name="add_constraint">add_constraint</a></h4>
+<p class="description"></p>
+<p class="code">
+void add_constraint (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcConstraint">ppdcConstraint</a> *c<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>c</dt>
+</dl>
+<h4 class="method"><a name="add_copyright">add_copyright</a></h4>
+<p class="description"></p>
+<p class="code">
+void add_copyright (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *c<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>c</dt>
+</dl>
+<h4 class="method"><a name="add_filter">add_filter</a></h4>
+<p class="description"></p>
+<p class="code">
+void add_filter (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFilter">ppdcFilter</a> *f<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>f</dt>
+</dl>
+<h4 class="method"><a name="add_font">add_font</a></h4>
+<p class="description"></p>
+<p class="code">
+void add_font (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFont">ppdcFont</a> *f<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>f</dt>
+</dl>
+<h4 class="method"><a name="add_group">add_group</a></h4>
+<p class="description"></p>
+<p class="code">
+void add_group (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcGroup">ppdcGroup</a> *g<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>g</dt>
+</dl>
+<h4 class="method"><a name="add_profile">add_profile</a></h4>
+<p class="description"></p>
+<p class="code">
+void add_profile (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcProfile">ppdcProfile</a> *p<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>p</dt>
+</dl>
+<h4 class="method"><a name="add_size">add_size</a></h4>
+<p class="description"></p>
+<p class="code">
+void add_size (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcMediaSize">ppdcMediaSize</a> *m<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>m</dt>
+</dl>
+<h4 class="method"><a name="find_attr">find_attr</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcAttr">ppdcAttr</a> *find_attr (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *k,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *s<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>k</dt>
+<dd class="description">Keyword string</dd>
+<dt>s</dt>
+<dd class="description">Spec string</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Attribute or NULL</p>
+<h4 class="method"><a name="find_group">find_group</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcGroup">ppdcGroup</a> *find_group (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *n<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>n</dt>
+<dd class="description">Group name</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Matching group or NULL</p>
+<h4 class="method"><a name="find_option">find_option</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcOption">ppdcOption</a> *find_option (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *n<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>n</dt>
+<dd class="description">Option name</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Matching option or NULL</p>
+<h4 class="method"><a name="find_option_group">find_option_group</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcOption">ppdcOption</a> *find_option_group (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *n,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcGroup">ppdcGroup</a> **mg<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>n</dt>
+<dd class="description">Option name</dd>
+<dt>mg</dt>
+<dd class="description">Matching group or NULL</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Matching option or NULL</p>
+<h4 class="method"><a name="ppdcDriver">ppdcDriver</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcDriver (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcDriver">ppdcDriver</a> *d<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>d</dt>
+<dd class="description">Printer driver template</dd>
+</dl>
+<h4 class="method"><a name="set_custom_size_code">set_custom_size_code</a></h4>
+<p class="description"></p>
+<p class="code">
+void set_custom_size_code (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *c<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>c</dt>
+<dd class="description">CustomPageSize code</dd>
+</dl>
+<h4 class="method"><a name="set_default_font">set_default_font</a></h4>
+<p class="description"></p>
+<p class="code">
+void set_default_font (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFont">ppdcFont</a> *f<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>f</dt>
+<dd class="description">Font</dd>
+</dl>
+<h4 class="method"><a name="set_default_size">set_default_size</a></h4>
+<p class="description"></p>
+<p class="code">
+void set_default_size (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcMediaSize">ppdcMediaSize</a> *m<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>m</dt>
+<dd class="description">Media size</dd>
+</dl>
+<h4 class="method"><a name="set_file_name">set_file_name</a></h4>
+<p class="description"></p>
+<p class="code">
+void set_file_name (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *f<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>f</dt>
+<dd class="description">Filename</dd>
+</dl>
+<h4 class="method"><a name="set_manufacturer">set_manufacturer</a></h4>
+<p class="description"></p>
+<p class="code">
+void set_manufacturer (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *m<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>m</dt>
+<dd class="description">Model name</dd>
+</dl>
+<h4 class="method"><a name="set_model_name">set_model_name</a></h4>
+<p class="description"></p>
+<p class="code">
+void set_model_name (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *m<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>m</dt>
+<dd class="description">Model name</dd>
+</dl>
+<h4 class="method"><a name="set_pc_file_name">set_pc_file_name</a></h4>
+<p class="description"></p>
+<p class="code">
+void set_pc_file_name (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *f<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>f</dt>
+<dd class="description">Filename</dd>
+</dl>
+<h4 class="method"><a name="set_version">set_version</a></h4>
+<p class="description"></p>
+<p class="code">
+void set_version (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *v<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>v</dt>
+<dd class="description">Version</dd>
+</dl>
+<h4 class="method"><a name="write_ppd_file">write_ppd_file</a></h4>
+<p class="description"></p>
+<p class="code">
+int write_ppd_file (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_file_t *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcCatalog">ppdcCatalog</a> *catalog,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcArray">ppdcArray</a> *locales,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcSource">ppdcSource</a> *src,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcLineEnding">ppdcLineEnding</a> le<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">PPD file</dd>
+<dt>catalog</dt>
+<dd class="description">Message catalog</dd>
+<dt>locales</dt>
+<dd class="description">Additional languages to add</dd>
+<dt>src</dt>
+<dd class="description">Driver source</dd>
+<dt>le</dt>
+<dd class="description">Line endings to use</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">0 on success, -1 on failure</p>
+<h4 class="method"><a name="~ppdcDriver">~ppdcDriver</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcDriver (void);</p>
+<h3 class="class"><a name="ppdcFile">ppdcFile</a></h3>
+<p class="description">// File</p>
+<p class="code">class ppdcFile {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *filename;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_file_t *fp;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int line;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>filename </dt>
+<dd class="description">Filename</dd>
+<dt>fp </dt>
+<dd class="description">File pointer</dd>
+<dt>line </dt>
+<dd class="description">Line in file</dd>
+</dl>
+<h4 class="method"><a name="get">get</a></h4>
+<p class="description">Get a character from a file.</p>
+<p class="code">
+int get (void);</p>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description"></p>
+<h4 class="method"><a name="peek">peek</a></h4>
+<p class="description"></p>
+<p class="code">
+int peek (void);</p>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Next character in file</p>
+<h4 class="method"><a name="ppdcFile">ppdcFile</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcFile (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *f,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_file_t *ffp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>f</dt>
+<dd class="description">File to open</dd>
+<dt>ffp</dt>
+<dd class="description">File pointer to use</dd>
+</dl>
+<h4 class="method"><a name="~ppdcFile">~ppdcFile</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcFile (void);</p>
+<h3 class="class"><a name="ppdcFilter">ppdcFilter</a></h3>
+<p class="description">// Filter Program</p>
+<p class="code">class ppdcFilter : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int cost;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *mime_type, *program;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>cost </dt>
+<dd class="description">Relative cost of filter</dd>
+<dt>program </dt>
+<dd class="description">Filter program</dd>
+</dl>
+<h4 class="method"><a name="ppdcFilter">ppdcFilter</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcFilter (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *t,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *p,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int c<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>t</dt>
+<dd class="description">MIME type</dd>
+<dt>p</dt>
+<dd class="description">Filter program</dd>
+<dt>c</dt>
+<dd class="description">Relative cost</dd>
+</dl>
+<h4 class="method"><a name="~ppdcFilter">~ppdcFilter</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcFilter (void);</p>
+<h3 class="class"><a name="ppdcFont">ppdcFont</a></h3>
+<p class="description">// Shared Font</p>
+<p class="code">class ppdcFont : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *name, *encoding, *version, *charset;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFontStatus">ppdcFontStatus</a> status;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>charset </dt>
+<dd class="description">Font charset</dd>
+<dt>status </dt>
+<dd class="description">Font status (ROM or Disk)</dd>
+</dl>
+<h4 class="method"><a name="ppdcFont">ppdcFont</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcFont (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *n,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *e,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *v,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *c,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFontStatus">ppdcFontStatus</a> s<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>n</dt>
+<dd class="description">Name of font</dd>
+<dt>e</dt>
+<dd class="description">Font encoding</dd>
+<dt>v</dt>
+<dd class="description">Font version</dd>
+<dt>c</dt>
+<dd class="description">Font charset</dd>
+<dt>s</dt>
+<dd class="description">Font status</dd>
+</dl>
+<h4 class="method"><a name="~ppdcFont">~ppdcFont</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcFont (void);</p>
+<h3 class="class"><a name="ppdcGroup">ppdcGroup</a></h3>
+<p class="description">// Group of Options</p>
+<p class="code">class ppdcGroup : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcArray">ppdcArray</a> *options;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *name, *text;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>options </dt>
+<dd class="description">Options</dd>
+<dt>text </dt>
+<dd class="description">Human-readable text of option</dd>
+</dl>
+<h4 class="method"><a name="PPDC_NAME">PPDC_NAME</a></h4>
+<p class="description"></p>
+<p class="code">
+void PPDC_NAME (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void add_option(<a href="#ppdcOption">ppdcOption</a> *o<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>o</dt>
+</dl>
+<h4 class="method"><a name="find_option">find_option</a></h4>
+<p class="description">Find an option in a group.</p>
+<p class="code">
+<a href="#ppdcOption">ppdcOption</a> *find_option (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *n<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>n</dt>
+<dd class="description">Name of option</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description"></p>
+<h4 class="method"><a name="ppdcGroup">ppdcGroup</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcGroup (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcGroup">ppdcGroup</a> *g<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>g</dt>
+<dd class="description">Group template</dd>
+</dl>
+<h4 class="method"><a name="~ppdcGroup">~ppdcGroup</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcGroup (void);</p>
+<h3 class="class"><a name="ppdcInteger">ppdcInteger</a></h3>
+<p class="description">// Shared integer</p>
+<p class="code">class ppdcInteger : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *value;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>value </dt>
+<dd class="description">Integer value</dd>
+</dl>
+<h4 class="method"><a name="ppdcInteger">ppdcInteger</a></h4>
+<p class="description">Integer value</p>
+<p class="code">
+void ppdcInteger (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *v<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>v</dt>
+</dl>
+<h3 class="class"><a name="ppdcMediaSize">ppdcMediaSize</a></h3>
+<p class="description">// Media Size</p>
+<p class="code">class ppdcMediaSize : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *size_code, *region_code;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *name, *text;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float width, length, left, bottom, right, top;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>region_code </dt>
+<dd class="description">PageRegion code, if any</dd>
+<dt>text </dt>
+<dd class="description">Human-readable text</dd>
+<dt>top </dt>
+<dd class="description">Top limit in points</dd>
+</dl>
+<h4 class="method"><a name="ppdcMediaSize">ppdcMediaSize</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcMediaSize (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *n,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *t,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float w,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float l,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float lm,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float bm,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float rm,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float tm,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *sc,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *rc<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>n</dt>
+<dd class="description">Name of media size</dd>
+<dt>t</dt>
+<dd class="description">Text of media size</dd>
+<dt>w</dt>
+<dd class="description">Width in points</dd>
+<dt>l</dt>
+<dd class="description">Length in points</dd>
+<dt>lm</dt>
+<dd class="description">Left margin in points</dd>
+<dt>bm</dt>
+<dd class="description">Bottom margin in points</dd>
+<dt>rm</dt>
+<dd class="description">Right margin in points</dd>
+<dt>tm</dt>
+<dd class="description">Top margin in points</dd>
+<dt>sc</dt>
+<dd class="description">PageSize code, if any</dd>
+<dt>rc</dt>
+<dd class="description">PageRegion code, if any</dd>
+</dl>
+<h4 class="method"><a name="~ppdcMediaSize">~ppdcMediaSize</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcMediaSize (void);</p>
+<h3 class="class"><a name="ppdcMessage">ppdcMessage</a></h3>
+<p class="description">// Translation message</p>
+<p class="code">class ppdcMessage : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *id, *string;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>string </dt>
+<dd class="description">Translation string</dd>
+</dl>
+<h4 class="method"><a name="ppdcMessage">ppdcMessage</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcMessage (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *i,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *s<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>i</dt>
+<dd class="description">ID</dd>
+<dt>s</dt>
+<dd class="description">Text</dd>
+</dl>
+<h4 class="method"><a name="~ppdcMessage">~ppdcMessage</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcMessage (void);</p>
+<h3 class="class"><a name="ppdcOption">ppdcOption</a></h3>
+<p class="description">// Option</p>
+<p class="code">class ppdcOption : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcArray">ppdcArray</a> *choices;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *defchoice;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float order;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcOptSection">ppdcOptSection</a> section;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *name, *text;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcOptType">ppdcOptType</a> type;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>choices </dt>
+<dd class="description">Choices</dd>
+<dt>defchoice </dt>
+<dd class="description">Default choice</dd>
+<dt>order </dt>
+<dd class="description">Order number</dd>
+<dt>section </dt>
+<dd class="description">Section for option code</dd>
+<dt>text </dt>
+<dd class="description">Human-readable text of option</dd>
+<dt>type </dt>
+<dd class="description">Type of option</dd>
+</dl>
+<h4 class="method"><a name="PPDC_NAME">PPDC_NAME</a></h4>
+<p class="description"></p>
+<p class="code">
+void PPDC_NAME (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void add_choice(<a href="#ppdcChoice">ppdcChoice</a> *c<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>c</dt>
+</dl>
+<h4 class="method"><a name="find_choice">find_choice</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcChoice">ppdcChoice</a> *find_choice (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *n<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>n</dt>
+<dd class="description">Name of choice</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Choice or NULL</p>
+<h4 class="method"><a name="ppdcOption">ppdcOption</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcOption (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcOption">ppdcOption</a> *o<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>o</dt>
+<dd class="description">Template option</dd>
+</dl>
+<h4 class="method"><a name="set_defchoice">set_defchoice</a></h4>
+<p class="description"></p>
+<p class="code">
+void set_defchoice (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcChoice">ppdcChoice</a> *c<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>c</dt>
+<dd class="description">Choice</dd>
+</dl>
+<h4 class="method"><a name="~ppdcOption">~ppdcOption</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcOption (void);</p>
+<h3 class="class"><a name="ppdcProfile">ppdcProfile</a></h3>
+<p class="description">// Color Profile</p>
+<p class="code">class ppdcProfile : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *resolution, *media_type;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float density, gamma, profile[9];<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>media_type </dt>
+<dd class="description">Media type name</dd>
+<dt>profile[9] </dt>
+<dd class="description">Color profile matrix</dd>
+</dl>
+<h4 class="method"><a name="ppdcProfile">ppdcProfile</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcProfile (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *r,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *m,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float d,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float g,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const float *p<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>r</dt>
+<dd class="description">Resolution name</dd>
+<dt>m</dt>
+<dd class="description">Media type name</dd>
+<dt>d</dt>
+<dd class="description">Density</dd>
+<dt>g</dt>
+<dd class="description">Gamma</dd>
+<dt>p</dt>
+<dd class="description">3x3 transform matrix</dd>
+</dl>
+<h4 class="method"><a name="~ppdcProfile">~ppdcProfile</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcProfile (void);</p>
+<h3 class="class"><a name="ppdcShared">ppdcShared</a></h3>
+<p class="description">// Shared Data Value</p>
+<p class="code">class ppdcShared {<br>
+&nbsp;&nbsp;private:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int use;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>use </dt>
+<dd class="description">Use count (delete when 0)</dd>
+</dl>
+<h4 class="method"><a name="class_name">class_name</a></h4>
+<p class="description"></p>
+<p class="code">
+virtual const char *class_name (void);</p>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description"></p>
+<h4 class="method"><a name="ppdcShared">ppdcShared</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcShared (void);</p>
+<h4 class="method"><a name="release">release</a></h4>
+<p class="description"></p>
+<p class="code">
+void release (void);</p>
+<h4 class="method"><a name="retain">retain</a></h4>
+<p class="description"></p>
+<p class="code">
+void retain (void);</p>
+<h4 class="method"><a name="~ppdcShared">~ppdcShared</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcShared (void);</p>
+<h3 class="class"><a name="ppdcSource">ppdcSource</a></h3>
+<p class="description">// Source File</p>
+<p class="code">class ppdcSource : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int cond_state, *cond_current, cond_stack[101];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;static const char *driver_types[];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *filename;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;static <a href="#ppdcArray">ppdcArray</a> *includes;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcArray">ppdcArray</a> *base_fonts, *drivers, *po_files, *sizes, *vars;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>cond_stack[101] </dt>
+<dd class="description">#if state stack</dd>
+<dt>driver_types[] </dt>
+<dd class="description">Driver types</dd>
+<dt>filename </dt>
+<dd class="description">Filename</dd>
+<dt>includes </dt>
+<dd class="description">Include directories</dd>
+<dt>vars </dt>
+<dd class="description">Defined variables</dd>
+</dl>
+<h4 class="method"><a name="PPDC_NAME">PPDC_NAME</a></h4>
+<p class="description"></p>
+<p class="code">
+void PPDC_NAME (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;static void add_include(const char *d<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>d</dt>
+</dl>
+<h4 class="method"><a name="add_include">add_include</a></h4>
+<p class="description"></p>
+<p class="code">
+void add_include (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *d<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>d</dt>
+<dd class="description">Include directory</dd>
+</dl>
+<h4 class="method"><a name="find_driver">find_driver</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcDriver">ppdcDriver</a> *find_driver (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *f<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>f</dt>
+<dd class="description">Driver file name</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Driver</p>
+<h4 class="method"><a name="find_include">find_include</a></h4>
+<p class="description"></p>
+<p class="code">
+char *find_include (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *f,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *base,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *n,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int nlen<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>f</dt>
+<dd class="description">Include filename</dd>
+<dt>base</dt>
+<dd class="description">Current directory</dd>
+<dt>n</dt>
+<dd class="description">Path buffer</dd>
+<dt>nlen</dt>
+<dd class="description">Path buffer length</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Found path or NULL</p>
+<h4 class="method"><a name="find_po">find_po</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcCatalog">ppdcCatalog</a> *find_po (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *l<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>l</dt>
+<dd class="description">Locale name</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Message catalog or NULL</p>
+<h4 class="method"><a name="find_size">find_size</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcMediaSize">ppdcMediaSize</a> *find_size (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *s<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>s</dt>
+<dd class="description">Size name</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Size</p>
+<h4 class="method"><a name="find_variable">find_variable</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcVariable">ppdcVariable</a> *find_variable (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *n<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>n</dt>
+<dd class="description">Variable name</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Variable</p>
+<h4 class="method"><a name="get_attr">get_attr</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcAttr">ppdcAttr</a> *get_attr (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;bool loc<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+<dt>loc</dt>
+<dd class="description">Localize this attribute?</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Attribute</p>
+<h4 class="method"><a name="get_boolean">get_boolean</a></h4>
+<p class="description"></p>
+<p class="code">
+int get_boolean (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Boolean value</p>
+<h4 class="method"><a name="get_choice">get_choice</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcChoice">ppdcChoice</a> *get_choice (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Choice data</p>
+<h4 class="method"><a name="get_color_model">get_color_model</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcChoice">ppdcChoice</a> *get_color_model (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Choice data</p>
+<h4 class="method"><a name="get_color_order">get_color_order</a></h4>
+<p class="description"></p>
+<p class="code">
+int get_color_order (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *co<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>co</dt>
+<dd class="description">Color order string</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Color order value</p>
+<h4 class="method"><a name="get_color_profile">get_color_profile</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcProfile">ppdcProfile</a> *get_color_profile (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Color profile</p>
+<h4 class="method"><a name="get_color_space">get_color_space</a></h4>
+<p class="description"></p>
+<p class="code">
+int get_color_space (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *cs<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>cs</dt>
+<dd class="description">Colorspace string</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Colorspace value</p>
+<h4 class="method"><a name="get_constraint">get_constraint</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcConstraint">ppdcConstraint</a> *get_constraint (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Constraint</p>
+<h4 class="method"><a name="get_custom_size">get_custom_size</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcMediaSize">ppdcMediaSize</a> *get_custom_size (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Media size</p>
+<h4 class="method"><a name="get_duplex">get_duplex</a></h4>
+<p class="description"></p>
+<p class="code">
+void get_duplex (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcDriver">ppdcDriver</a> *d<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read from</dd>
+<dt>d</dt>
+<dd class="description">Current driver</dd>
+</dl>
+<h4 class="method"><a name="get_filter">get_filter</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcFilter">ppdcFilter</a> *get_filter (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Filter</p>
+<h4 class="method"><a name="get_float">get_float</a></h4>
+<p class="description"></p>
+<p class="code">
+float get_float (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Number</p>
+<h4 class="method"><a name="get_font">get_font</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcFont">ppdcFont</a> *get_font (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Font data</p>
+<h4 class="method"><a name="get_generic">get_generic</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcChoice">ppdcChoice</a> *get_generic (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *keyword,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *tattr,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *nattr<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+<dt>keyword</dt>
+<dd class="description">Keyword name</dd>
+<dt>tattr</dt>
+<dd class="description">Text attribute</dd>
+<dt>nattr</dt>
+<dd class="description">Numeric attribute</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Choice data</p>
+<h4 class="method"><a name="get_group">get_group</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcGroup">ppdcGroup</a> *get_group (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcDriver">ppdcDriver</a> *d<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+<dt>d</dt>
+<dd class="description">Printer driver</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Group</p>
+<h4 class="method"><a name="get_installable">get_installable</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcOption">ppdcOption</a> *get_installable (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Option</p>
+<h4 class="method"><a name="get_integer">get_integer</a></h4>
+<p class="description"></p>
+<p class="code">
+int get_integer (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Integer value</p>
+<h4 class="method"><a name="get_measurement">get_measurement</a></h4>
+<p class="description"></p>
+<p class="code">
+float get_measurement (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Measurement value in points</p>
+<h4 class="method"><a name="get_option">get_option</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcOption">ppdcOption</a> *get_option (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcDriver">ppdcDriver</a> *d,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcGroup">ppdcGroup</a> *g<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+<dt>d</dt>
+<dd class="description">Printer driver</dd>
+<dt>g</dt>
+<dd class="description">Current group</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Option</p>
+<h4 class="method"><a name="get_po">get_po</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcCatalog">ppdcCatalog</a> *get_po (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Message catalog</p>
+<h4 class="method"><a name="get_resolution">get_resolution</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcChoice">ppdcChoice</a> *get_resolution (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Choice data</p>
+<h4 class="method"><a name="get_simple_profile">get_simple_profile</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcProfile">ppdcProfile</a> *get_simple_profile (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Color profile</p>
+<h4 class="method"><a name="get_size">get_size</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcMediaSize">ppdcMediaSize</a> *get_size (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Media size</p>
+<h4 class="method"><a name="get_token">get_token</a></h4>
+<p class="description"></p>
+<p class="code">
+char *get_token (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *buffer,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int buflen<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+<dt>buffer</dt>
+<dd class="description">Buffer</dd>
+<dt>buflen</dt>
+<dd class="description">Length of buffer</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Token string or NULL</p>
+<h4 class="method"><a name="get_variable">get_variable</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcVariable">ppdcVariable</a> *get_variable (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Variable</p>
+<h4 class="method"><a name="import_ppd">import_ppd</a></h4>
+<p class="description"></p>
+<p class="code">
+int import_ppd (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *f<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>f</dt>
+<dd class="description">Filename</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">1 on success, 0 on failure</p>
+<h4 class="method"><a name="ppdcSource">ppdcSource</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcSource (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *f,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_file_t *ffp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>f</dt>
+<dd class="description">File to read</dd>
+<dt>ffp</dt>
+<dd class="description">File pointer to use</dd>
+</dl>
+<h4 class="method"><a name="quotef">quotef</a></h4>
+<p class="description"></p>
+<p class="code">
+int quotef (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_file_t *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *format,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;...<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to write to</dd>
+<dt>format</dt>
+<dd class="description">Printf-style format string</dd>
+<dt>...</dt>
+<dd class="description">Additional args as needed</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Number bytes on success, -1 on failure</p>
+<h4 class="method"><a name="read_file">read_file</a></h4>
+<p class="description"></p>
+<p class="code">
+void read_file (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *f,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_file_t *ffp<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>f</dt>
+<dd class="description">File to read</dd>
+<dt>ffp</dt>
+<dd class="description">File pointer to use</dd>
+</dl>
+<h4 class="method"><a name="scan_file">scan_file</a></h4>
+<p class="description"></p>
+<p class="code">
+void scan_file (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcFile">ppdcFile</a> *fp,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcDriver">ppdcDriver</a> *td,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;bool inc<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>fp</dt>
+<dd class="description">File to read</dd>
+<dt>td</dt>
+<dd class="description">Driver template</dd>
+<dt>inc</dt>
+<dd class="description">Including?</dd>
+</dl>
+<h4 class="method"><a name="set_variable">set_variable</a></h4>
+<p class="description"></p>
+<p class="code">
+<a href="#ppdcVariable">ppdcVariable</a> *set_variable (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *name,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *value<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>name</dt>
+<dd class="description">Name</dd>
+<dt>value</dt>
+<dd class="description">Value</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">Variable</p>
+<h4 class="method"><a name="write_file">write_file</a></h4>
+<p class="description"></p>
+<p class="code">
+int write_file (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *f<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>f</dt>
+<dd class="description">File to write</dd>
+</dl>
+<h5 class="returnvalue">Return Value</h5>
+<p class="description">0 on success, -1 on error</p>
+<h4 class="method"><a name="~ppdcSource">~ppdcSource</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcSource (void);</p>
+<h3 class="class"><a name="ppdcString">ppdcString</a></h3>
+<p class="description">// Shared String</p>
+<p class="code">class ppdcString : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *value;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>value </dt>
+<dd class="description">String value</dd>
+</dl>
+<h4 class="method"><a name="ppdcString">ppdcString</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcString (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *v<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>v</dt>
+<dd class="description">String</dd>
+</dl>
+<h4 class="method"><a name="~ppdcString">~ppdcString</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcString (void);</p>
+<h3 class="class"><a name="ppdcVariable">ppdcVariable</a></h3>
+<p class="description">// Variable Definition</p>
+<p class="code">class ppdcVariable : public ppdcShared {<br>
+&nbsp;&nbsp;public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppdcString">ppdcString</a> *name, *value;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>value </dt>
+<dd class="description">Value of variable</dd>
+</dl>
+<h4 class="method"><a name="PPDC_NAME">PPDC_NAME</a></h4>
+<p class="description"></p>
+<p class="code">
+void PPDC_NAME (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void set_value(const char *v<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>v</dt>
+</dl>
+<h4 class="method"><a name="ppdcVariable">ppdcVariable</a></h4>
+<p class="description"></p>
+<p class="code">
+void ppdcVariable (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *n,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *v<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>n</dt>
+<dd class="description">Name of variable</dd>
+<dt>v</dt>
+<dd class="description">Value of variable</dd>
+</dl>
+<h4 class="method"><a name="set_value">set_value</a></h4>
+<p class="description"></p>
+<p class="code">
+void set_value (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *v<br>
+);</p>
+<h5 class="parameters">Parameters</h5>
+<dl>
+<dt>v</dt>
+</dl>
+<h4 class="method"><a name="~ppdcVariable">~ppdcVariable</a></h4>
+<p class="description"></p>
+<p class="code">
+void ~ppdcVariable (void);</p>
+<h2 class="title"><a name="TYPES">Data Types</a></h2>
+<h3 class="typedef"><a name="ppdc_cs_t">ppdc_cs_t</a></h3>
+<p class="description"></p>
+<p class="code">
+typedef enum ppdc_cs_t;
+</p>
+<h2 class="title"><a name="VARIABLES">Variables</a></h2>
+<h3 class="variable"><a name="ppdcSource">ppdcSource</a></h3>
+<p class="description">// Printer Driver Data</p>
+<p class="code">class ppdcSource;</p>
+<h2 class="title"><a name="ENUMERATIONS">Constants</a></h2>
+<h3 class="enumeration"><a name="ppdcCondFlags">ppdcCondFlags</a></h3>
+<p class="description">// Condition flags</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>PPDC_COND_NORMAL </dt>
+<dd class="description">Normal state</dd>
+<dt>PPDC_COND_SATISFIED </dt>
+<dd class="description">At least one condition satisfied</dd>
+<dt>PPDC_COND_SKIP </dt>
+<dd class="description">Skip state</dd>
+</dl>
+<h3 class="enumeration"><a name="ppdcDrvType">ppdcDrvType</a></h3>
+<p class="description">// Driver type</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>PPDC_DRIVER_CUSTOM </dt>
+<dd class="description">Custom driver</dd>
+<dt>PPDC_DRIVER_EPSON </dt>
+<dd class="description">rastertoepson driver</dd>
+<dt>PPDC_DRIVER_ESCP </dt>
+<dd class="description">rastertoescpx driver</dd>
+<dt>PPDC_DRIVER_HP </dt>
+<dd class="description">rastertohp driver</dd>
+<dt>PPDC_DRIVER_LABEL </dt>
+<dd class="description">rastertolabel/rastertodymo driver</dd>
+<dt>PPDC_DRIVER_MAX </dt>
+<dd class="description">Number of driver types defined</dd>
+<dt>PPDC_DRIVER_PCL </dt>
+<dd class="description">rastertopclx driver</dd>
+<dt>PPDC_DRIVER_PS </dt>
+<dd class="description">PostScript driver</dd>
+</dl>
+<h3 class="enumeration"><a name="ppdcFontStatus">ppdcFontStatus</a></h3>
+<p class="description">// Load status of font</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>PPDC_FONT_DISK </dt>
+<dd class="description">Font is on disk</dd>
+<dt>PPDC_FONT_ROM </dt>
+<dd class="description">Font is in ROM</dd>
+</dl>
+<h3 class="enumeration"><a name="ppdcLineEnding">ppdcLineEnding</a></h3>
+<p class="description">// Line endings</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>PPDC_CRLF </dt>
+<dd class="description">CR + LF</dd>
+<dt>PPDC_CRONLY </dt>
+<dd class="description">CR only</dd>
+<dt>PPDC_LFONLY </dt>
+<dd class="description">LF only</dd>
+</dl>
+<h3 class="enumeration"><a name="ppdcOptSection">ppdcOptSection</a></h3>
+<p class="description">// Option section</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>PPDC_SECTION_ANY </dt>
+<dd class="description">AnySetup</dd>
+<dt>PPDC_SECTION_DOCUMENT </dt>
+<dd class="description">DocumentSetup</dd>
+<dt>PPDC_SECTION_EXIT </dt>
+<dd class="description">ExitServer</dd>
+<dt>PPDC_SECTION_JCL </dt>
+<dd class="description">JCLSetup</dd>
+<dt>PPDC_SECTION_PAGE </dt>
+<dd class="description">PageSetup</dd>
+<dt>PPDC_SECTION_PROLOG </dt>
+<dd class="description">Prolog</dd>
+</dl>
+<h3 class="enumeration"><a name="ppdcOptType">ppdcOptType</a></h3>
+<p class="description">// Option type</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>PPDC_BOOLEAN </dt>
+<dd class="description">True/false option</dd>
+<dt>PPDC_PICKMANY </dt>
+<dd class="description">Multiple choices from list</dd>
+<dt>PPDC_PICKONE </dt>
+<dd class="description">Single choice from list</dd>
+</dl>
+</div>
+</body>
+</html>
diff --git a/doc/help/api-raster.html b/doc/help/api-raster.html
new file mode 100644
index 000000000..f193d07e2
--- /dev/null
+++ b/doc/help/api-raster.html
@@ -0,0 +1,1416 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>Raster API </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: api-raster.html 9772 2011-05-12 05:46:30Z mike $"
+
+ Raster API documentation for CUPS.
+
+ Copyright 2008-2010 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Raster API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/raster.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcupsimage</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html'>Introduction to CUPS Programming</a><br>
+ Programming: <a href='api-cups.html'>CUPS API</a><br>
+ Programming: <a href='api-cups.html'>PPD API</a><br>
+ References: <a href='spec-ppd.html'>CUPS PPD Specification</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#OVERVIEW">Overview</a></li>
+<li><a href="#TASKS">Functions by Task</a><ul class="subcontents">
+ <li><a href="#OPENCLOSE">Opening and Closing Raster Streams</a></li>
+ <li><a href="#READING">Reading Raster Streams</a></li>
+ <li><a href="#WRITING">Writing Raster Streams</a></li>
+</ul></li>
+<li><a href="#FUNCTIONS">Functions</a><ul class="code">
+ <li><a href="#cupsRasterClose" title="Close a raster stream.">cupsRasterClose</a></li>
+ <li><a href="#cupsRasterInterpretPPD" title="Interpret PPD commands to create a page header.">cupsRasterInterpretPPD</a></li>
+ <li><a href="#cupsRasterOpen" title="Open a raster stream using a file descriptor.">cupsRasterOpen</a></li>
+ <li><a href="#cupsRasterOpenIO" title="Open a raster stream using a callback function.">cupsRasterOpenIO</a></li>
+ <li><a href="#cupsRasterReadHeader" title="Read a raster page header and store it in a
+version 1 page header structure.">cupsRasterReadHeader</a></li>
+ <li><a href="#cupsRasterReadHeader2" title="Read a raster page header and store it in a
+version 2 page header structure.">cupsRasterReadHeader2</a></li>
+ <li><a href="#cupsRasterReadPixels" title="Read raster pixels.">cupsRasterReadPixels</a></li>
+ <li><a href="#cupsRasterWriteHeader" title="Write a raster page header from a version 1 page
+header structure.">cupsRasterWriteHeader</a></li>
+ <li><a href="#cupsRasterWriteHeader2" title="Write a raster page header from a version 2
+page header structure.">cupsRasterWriteHeader2</a></li>
+ <li><a href="#cupsRasterWritePixels" title="Write raster pixels.">cupsRasterWritePixels</a></li>
+</ul></li>
+<li><a href="#TYPES">Data Types</a><ul class="code">
+ <li><a href="#cups_adv_t" title="AdvanceMedia attribute values">cups_adv_t</a></li>
+ <li><a href="#cups_bool_t" title="Boolean type">cups_bool_t</a></li>
+ <li><a href="#cups_cspace_t" title="cupsColorSpace attribute values">cups_cspace_t</a></li>
+ <li><a href="#cups_cut_t" title="CutMedia attribute values">cups_cut_t</a></li>
+ <li><a href="#cups_edge_t" title="LeadingEdge attribute values">cups_edge_t</a></li>
+ <li><a href="#cups_interpret_cb_t" title="cupsRasterInterpretPPD callback function">cups_interpret_cb_t</a></li>
+ <li><a href="#cups_jog_t" title="Jog attribute values">cups_jog_t</a></li>
+ <li><a href="#cups_mode_t" title="cupsRasterOpen modes">cups_mode_t</a></li>
+ <li><a href="#cups_order_t" title="cupsColorOrder attribute values">cups_order_t</a></li>
+ <li><a href="#cups_orient_t" title="Orientation attribute values">cups_orient_t</a></li>
+ <li><a href="#cups_page_header2_t" title="Version 2 page header ">cups_page_header2_t</a></li>
+ <li><a href="#cups_page_header_t" title="Version 1 page header ">cups_page_header_t</a></li>
+ <li><a href="#cups_raster_iocb_t" title="cupsRasterOpenIO callback function">cups_raster_iocb_t</a></li>
+ <li><a href="#cups_raster_t" title="Raster stream data">cups_raster_t</a></li>
+</ul></li>
+<li><a href="#STRUCTURES">Structures</a><ul class="code">
+ <li><a href="#cups_page_header2_s" title="Version 2 page header ">cups_page_header2_s</a></li>
+ <li><a href="#cups_page_header_s" title="Version 1 page header ">cups_page_header_s</a></li>
+</ul></li>
+<li><a href="#ENUMERATIONS">Constants</a><ul class="code">
+ <li><a href="#cups_adv_e" title="AdvanceMedia attribute values">cups_adv_e</a></li>
+ <li><a href="#cups_bool_e" title="Boolean type">cups_bool_e</a></li>
+ <li><a href="#cups_cspace_e" title="cupsColorSpace attribute values">cups_cspace_e</a></li>
+ <li><a href="#cups_cut_e" title="CutMedia attribute values">cups_cut_e</a></li>
+ <li><a href="#cups_edge_e" title="LeadingEdge attribute values">cups_edge_e</a></li>
+ <li><a href="#cups_jog_e" title="Jog attribute values">cups_jog_e</a></li>
+ <li><a href="#cups_mode_e" title="cupsRasterOpen modes">cups_mode_e</a></li>
+ <li><a href="#cups_order_e" title="cupsColorOrder attribute values">cups_order_e</a></li>
+ <li><a href="#cups_orient_e" title="Orientation attribute values">cups_orient_e</a></li>
+</ul></li>
+</ul>
+<!--
+ "$Id: api-raster.html 9772 2011-05-12 05:46:30Z mike $"
+
+ Raster API introduction for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name="OVERVIEW">Overview</a></h2>
+
+<p>The CUPS raster API provides a standard interface for reading and writing
+CUPS raster streams which are used for printing to raster printers. Because the
+raster format is updated from time to time, it is important to use this API to
+avoid incompatibilities with newer versions of CUPS.</p>
+
+<p>Two kinds of CUPS filters use the CUPS raster API - raster image processor
+(RIP) filters such as <code>pstoraster</code> and <code>cgpdftoraster</code>
+(Mac OS X) that produce CUPS raster files and printer driver filters that
+convert CUPS raster files into a format usable by the printer. Printer
+driver filters are by far the most common.</p>
+
+<p>CUPS raster files (<code>application/vnd.cups-raster</code>) consists of
+a stream of raster page descriptions produced by one of the RIP filters such as
+<var>pstoraster</var>, <var>imagetoraster</var>, or
+<var>cgpdftoraster</var>. CUPS raster files are referred to using the
+<a href='#cups_raster_t'><code>cups_raster_t</code></a> type and are
+opened using the <a href='#cupsRasterOpen'><code>cupsRasterOpen</code></a>
+function. For example, to read raster data from the standard input, open
+file descriptor 0:</p>
+
+<pre class="example">
+#include &lt;cups/raster.h&gt;>
+
+<a href="#cups_raster_t">cups_raster_t</a> *ras = <a href="#cupsRasterOpen">cupsRasterOpen</a>(0, CUPS_RASTER_READ);
+</pre>
+
+<p>Each page of data begins with a page dictionary structure called
+<a href="#cups_page_header2_t"><code>cups_page_header2_t</code></a>. This
+structure contains the colorspace, bits per color, media size, media type,
+hardware resolution, and so forth used for the page.</p>
+
+<blockquote><b>Note:</b>
+
+ <p>Do not confuse the colorspace in the page header with the PPD
+ <tt>ColorModel</tt> keyword. <tt>ColorModel</tt> refers to the general type of
+ color used for a device (Gray, RGB, CMYK, DeviceN) and is often used to
+ select a particular colorspace for the page header along with the associate
+ color profile. The page header colorspace (<tt>cupsColorSpace</tt>) describes
+ both the type and organization of the color data, for example KCMY (black
+ first) instead of CMYK and RGBA (RGB + alpha) instead of RGB.</p>
+
+</blockquote>
+
+<p>You read the page header using the
+<a href="#cupsRasterReadHeader2"><code>cupsRasterReadHeader2</code></a>
+function:</p>
+
+<pre class="example">
+#include &lt;cups/raster.h&gt;>
+
+<a href="#cups_raster_t">cups_raster_t</a> *ras = <a href="#cupsRasterOpen">cupsRasterOpen</a>(0, CUPS_RASTER_READ);
+<a href="#cups_page_header2_t">cups_page_header2_t</a> header;
+
+while (<a href="#cupsRasterReadHeader2">cupsRasterReadHeader2</a>(ras, &amp;header))
+{
+ /* setup this page */
+
+ /* read raster data */
+
+ /* finish this page */
+}
+</pre>
+
+<p>After the page dictionary comes the page data which is a full-resolution,
+possibly compressed bitmap representing the page in the printer's output
+colorspace. You read uncompressed raster data using the
+<a href="#cupsRasterReadPixels"><code>cupsRasterReadPixels</code></a>
+function. A <code>for</code> loop is normally used to read the page one line
+at a time:</p>
+
+<pre class="example">
+#include &lt;cups/raster.h&gt;>
+
+<a href="#cups_raster_t">cups_raster_t</a> *ras = <a href="#cupsRasterOpen">cupsRasterOpen</a>(0, CUPS_RASTER_READ);
+<a href="#cups_page_header2_t">cups_page_header2_t</a> header;
+int page = 0;
+int y;
+char *buffer;
+
+while (<a href="#cupsRasterReadHeader2">cupsRasterReadHeader2</a>(ras, &amp;header))
+{
+ /* setup this page */
+ page ++;
+ fprintf(stderr, "PAGE: %d %d\n", page, header.NumCopies);
+
+ /* allocate memory for 1 line */
+ buffer = malloc(header.cupsBytesPerLine);
+
+ /* read raster data */
+ for (y = 0; y &lt; header.cupsHeight; y ++)
+ {
+ if (<a href="#cupsRasterReadPixels">cupsRasterReadPixels</a>(ras, buffer, header.cupsBytesPerLine) == 0)
+ break;
+
+ /* write raster data to printer on stdout */
+ }
+
+ /* finish this page */
+}
+</pre>
+
+<p>When you are done reading the raster data, call the
+<a href="#cupsRasterClose"><code>cupsRasterClose</code></a> function to free
+the memory used to read the raster file:</p>
+
+<pre class="example">
+<a href="#cups_raster_t">cups_raster_t</a> *ras;
+
+<a href="#cupsRasterClose">cupsRasterClose</a>(ras);
+</pre>
+
+
+<h2 class='title'><a name="TASKS">Functions by Task</a></h2>
+
+<h3><a name="OPENCLOSE">Opening and Closing Raster Streams</a></h3>
+
+<ul class="code">
+
+ <li><a href="#cupsRasterClose" title="Close a raster stream.">cupsRasterClose</a></li>
+ <li><a href="#cupsRasterOpen" title="Open a raster stream.">cupsRasterOpen</a></li>
+
+</ul>
+
+<h3><a name="READING">Reading Raster Streams</a></h3>
+
+<ul class="code">
+
+ <li><a href="#cupsRasterReadHeader" title="Read a raster page header and store it in a version 1 page header structure.">cupsRasterReadHeader</a> <span class="info">Deprecated in CUPS 1.2/Mac OS X 10.5</span></li>
+ <li><a href="#cupsRasterReadHeader2" title="Read a raster page header and store it in a version 2 page header structure.">cupsRasterReadHeader2</a></li>
+ <li><a href="#cupsRasterReadPixels" title="Read raster pixels.">cupsRasterReadPixels</a></li>
+
+</ul>
+
+<h3><a name="WRITING">Writing Raster Streams</a></h3>
+
+<ul class="code">
+
+ <li><a href="#cupsRasterInterpretPPD" title="Interpret PPD commands to create a page header.">cupsRasterInterpretPPD</a></li>
+ <li><a href="#cupsRasterWriteHeader" title="Write a raster page header from a version 1 page header structure.">cupsRasterWriteHeader</a> <span class="info">Deprecated in CUPS 1.2/Mac OS X 10.5</span></li>
+ <li><a href="#cupsRasterWriteHeader2" title="Write a raster page header from a version 2 page header structure.">cupsRasterWriteHeader2</a></li>
+ <li><a href="#cupsRasterWritePixels" title="Write raster pixels.">cupsRasterWritePixels</a></li>
+
+</ul>
+<h2 class="title"><a name="FUNCTIONS">Functions</a></h2>
+<h3 class="function"><a name="cupsRasterClose">cupsRasterClose</a></h3>
+<p class="description">Close a raster stream.</p>
+<p class="code">
+void cupsRasterClose (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_raster_t">cups_raster_t</a> *r<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>r</dt>
+<dd class="description">Stream to close</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The file descriptor associated with the raster stream must be closed
+separately as needed.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsRasterInterpretPPD">cupsRasterInterpretPPD</a></h3>
+<p class="description">Interpret PPD commands to create a page header.</p>
+<p class="code">
+int cupsRasterInterpretPPD (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_page_header2_t">cups_page_header2_t</a> *h,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;ppd_file_t *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int num_options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_option_t *options,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_interpret_cb_t">cups_interpret_cb_t</a> func<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>h</dt>
+<dd class="description">Page header to create</dd>
+<dt>ppd</dt>
+<dd class="description">PPD file</dd>
+<dt>num_options</dt>
+<dd class="description">Number of options</dd>
+<dt>options</dt>
+<dd class="description">Options</dd>
+<dt>func</dt>
+<dd class="description">Optional page header callback (<code>NULL</code> for none)</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is used by raster image processing (RIP) filters like
+cgpdftoraster and imagetoraster when writing CUPS raster data for a page.
+It is not used by raster printer driver filters which only read CUPS
+raster data.<br>
+<br>
+
+<code>cupsRasterInterpretPPD</code> does not mark the options in the PPD using
+the &quot;num_options&quot; and &quot;options&quot; arguments. Instead, mark the options with
+<code>cupsMarkOptions</code> and <code>ppdMarkOption</code> prior to calling it -
+this allows for per-page options without manipulating the options array.<br>
+<br>
+The &quot;func&quot; argument specifies an optional callback function that is
+called prior to the computation of the final raster data. The function
+can make changes to the <a href="#cups_page_header2_t"><code>cups_page_header2_t</code></a> data as needed to use a
+supported raster format and then returns 0 on success and -1 if the
+requested attributes cannot be supported.<br>
+<br>
+
+<code>cupsRasterInterpretPPD</code> supports a subset of the PostScript language.
+Currently only the <code>[</code>, <code>]</code>, <code><<</code>, <code>>></code>, <code>{</code>,
+<code>}</code>, <code>cleartomark</code>, <code>copy</code>, <code>dup</code>, <code>index</code>,
+<code>pop</code>, <code>roll</code>, <code>setpagedevice</code>, and <code>stopped</code> operators
+are supported.
+
+</p>
+<h3 class="function"><a name="cupsRasterOpen">cupsRasterOpen</a></h3>
+<p class="description">Open a raster stream using a file descriptor.</p>
+<p class="code">
+<a href="#cups_raster_t">cups_raster_t</a> *cupsRasterOpen (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int fd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_mode_t">cups_mode_t</a> mode<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>fd</dt>
+<dd class="description">File descriptor</dd>
+<dt>mode</dt>
+<dd class="description">Mode - <code>CUPS_RASTER_READ</code>,
+<code>CUPS_RASTER_WRITE</code>,
+<code>CUPS_RASTER_WRITE_COMPRESSED</code>,
+or <code>CUPS_RASTER_WRITE_PWG</code></dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New stream</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function associates a raster stream with the given file descriptor.
+For most printer driver filters, &quot;fd&quot; will be 0 (stdin). For most raster
+image processor (RIP) filters that generate raster data, &quot;fd&quot; will be 1
+(stdout).<br>
+<br>
+When writing raster data, the <code>CUPS_RASTER_WRITE</code>,
+<code>CUPS_RASTER_WRITE_COMPRESS</code>, or <code>CUPS_RASTER_WRITE_PWG</code> mode can
+be used - compressed and PWG output is generally 25-50% smaller but adds a
+100-300% execution time overhead.</p>
+<h3 class="function"><a name="cupsRasterOpenIO">cupsRasterOpenIO</a></h3>
+<p class="description">Open a raster stream using a callback function.</p>
+<p class="code">
+<a href="#cups_raster_t">cups_raster_t</a> *cupsRasterOpenIO (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_raster_iocb_t">cups_raster_iocb_t</a> iocb,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *ctx,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_mode_t">cups_mode_t</a> mode<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>iocb</dt>
+<dd class="description">Read/write callback</dd>
+<dt>ctx</dt>
+<dd class="description">Context pointer for callback</dd>
+<dt>mode</dt>
+<dd class="description">Mode - <code>CUPS_RASTER_READ</code>,
+<code>CUPS_RASTER_WRITE</code>,
+<code>CUPS_RASTER_WRITE_COMPRESSED</code>,
+or <code>CUPS_RASTER_WRITE_PWG</code></dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New stream</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function associates a raster stream with the given callback function and
+context pointer.<br>
+<br>
+When writing raster data, the <code>CUPS_RASTER_WRITE</code>,
+<code>CUPS_RASTER_WRITE_COMPRESS</code>, or <code>CUPS_RASTER_WRITE_PWG</code> mode can
+be used - compressed and PWG output is generally 25-50% smaller but adds a
+100-300% execution time overhead.</p>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="cupsRasterReadHeader">cupsRasterReadHeader</a></h3>
+<p class="description">Read a raster page header and store it in a
+version 1 page header structure.</p>
+<p class="code">
+unsigned cupsRasterReadHeader (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_raster_t">cups_raster_t</a> *r,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_page_header_t">cups_page_header_t</a> *h<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>r</dt>
+<dd class="description">Raster stream</dd>
+<dt>h</dt>
+<dd class="description">Pointer to header data</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 on success, 0 on failure/end-of-file</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is deprecated. Use <a href="#cupsRasterReadHeader2"><code>cupsRasterReadHeader2</code></a> instead.<br>
+<br>
+Version 1 page headers were used in CUPS 1.0 and 1.1 and contain a subset
+of the version 2 page header data. This function handles reading version 2
+page headers and copying only the version 1 data into the provided buffer.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsRasterReadHeader2">cupsRasterReadHeader2</a></h3>
+<p class="description">Read a raster page header and store it in a
+version 2 page header structure.</p>
+<p class="code">
+unsigned cupsRasterReadHeader2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_raster_t">cups_raster_t</a> *r,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_page_header2_t">cups_page_header2_t</a> *h<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>r</dt>
+<dd class="description">Raster stream</dd>
+<dt>h</dt>
+<dd class="description">Pointer to header data</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 on success, 0 on failure/end-of-file</p>
+<h3 class="function"><a name="cupsRasterReadPixels">cupsRasterReadPixels</a></h3>
+<p class="description">Read raster pixels.</p>
+<p class="code">
+unsigned cupsRasterReadPixels (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_raster_t">cups_raster_t</a> *r,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char *p,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned len<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>r</dt>
+<dd class="description">Raster stream</dd>
+<dt>p</dt>
+<dd class="description">Pointer to pixel buffer</dd>
+<dt>len</dt>
+<dd class="description">Number of bytes to read</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of bytes read</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">For best performance, filters should read one or more whole lines.
+The &quot;cupsBytesPerLine&quot; value from the page header can be used to allocate
+the line buffer and as the number of bytes to read.</p>
+<h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="cupsRasterWriteHeader">cupsRasterWriteHeader</a></h3>
+<p class="description">Write a raster page header from a version 1 page
+header structure.</p>
+<p class="code">
+unsigned cupsRasterWriteHeader (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_raster_t">cups_raster_t</a> *r,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_page_header_t">cups_page_header_t</a> *h<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>r</dt>
+<dd class="description">Raster stream</dd>
+<dt>h</dt>
+<dd class="description">Raster page header</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 on success, 0 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function is deprecated. Use <a href="#cupsRasterWriteHeader2"><code>cupsRasterWriteHeader2</code></a> instead.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsRasterWriteHeader2">cupsRasterWriteHeader2</a></h3>
+<p class="description">Write a raster page header from a version 2
+page header structure.</p>
+<p class="code">
+unsigned cupsRasterWriteHeader2 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_raster_t">cups_raster_t</a> *r,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_page_header2_t">cups_page_header2_t</a> *h<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>r</dt>
+<dd class="description">Raster stream</dd>
+<dt>h</dt>
+<dd class="description">Raster page header</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 on success, 0 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The page header can be initialized using <a href="#cupsRasterInterpretPPD"><code>cupsRasterInterpretPPD</code></a>.
+
+</p>
+<h3 class="function"><a name="cupsRasterWritePixels">cupsRasterWritePixels</a></h3>
+<p class="description">Write raster pixels.</p>
+<p class="code">
+unsigned cupsRasterWritePixels (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_raster_t">cups_raster_t</a> *r,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned char *p,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned len<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>r</dt>
+<dd class="description">Raster stream</dd>
+<dt>p</dt>
+<dd class="description">Bytes to write</dd>
+<dt>len</dt>
+<dd class="description">Number of bytes to write</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of bytes written</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">For best performance, filters should write one or more whole lines.
+The &quot;cupsBytesPerLine&quot; value from the page header can be used to allocate
+the line buffer and as the number of bytes to write.</p>
+<h2 class="title"><a name="TYPES">Data Types</a></h2>
+<h3 class="typedef"><a name="cups_adv_t">cups_adv_t</a></h3>
+<p class="description">AdvanceMedia attribute values</p>
+<p class="code">
+typedef enum <a href="#cups_adv_e">cups_adv_e</a> cups_adv_t;
+</p>
+<h3 class="typedef"><a name="cups_bool_t">cups_bool_t</a></h3>
+<p class="description">Boolean type</p>
+<p class="code">
+typedef enum <a href="#cups_bool_e">cups_bool_e</a> cups_bool_t;
+</p>
+<h3 class="typedef"><a name="cups_cspace_t">cups_cspace_t</a></h3>
+<p class="description">cupsColorSpace attribute values</p>
+<p class="code">
+typedef enum <a href="#cups_cspace_e">cups_cspace_e</a> cups_cspace_t;
+</p>
+<h3 class="typedef"><a name="cups_cut_t">cups_cut_t</a></h3>
+<p class="description">CutMedia attribute values</p>
+<p class="code">
+typedef enum <a href="#cups_cut_e">cups_cut_e</a> cups_cut_t;
+</p>
+<h3 class="typedef"><a name="cups_edge_t">cups_edge_t</a></h3>
+<p class="description">LeadingEdge attribute values</p>
+<p class="code">
+typedef enum <a href="#cups_edge_e">cups_edge_e</a> cups_edge_t;
+</p>
+<h3 class="typedef"><a name="cups_interpret_cb_t">cups_interpret_cb_t</a></h3>
+<p class="description">cupsRasterInterpretPPD callback function</p>
+<p class="code">
+typedef int (*cups_interpret_cb_t)(<a href="#cups_page_header2_t">cups_page_header2_t</a> *header, int preferred_bits);
+</p>
+<h3 class="typedef"><a name="cups_jog_t">cups_jog_t</a></h3>
+<p class="description">Jog attribute values</p>
+<p class="code">
+typedef enum <a href="#cups_jog_e">cups_jog_e</a> cups_jog_t;
+</p>
+<h3 class="typedef"><a name="cups_mode_t">cups_mode_t</a></h3>
+<p class="description">cupsRasterOpen modes</p>
+<p class="code">
+typedef enum <a href="#cups_mode_e">cups_mode_e</a> cups_mode_t;
+</p>
+<h3 class="typedef"><a name="cups_order_t">cups_order_t</a></h3>
+<p class="description">cupsColorOrder attribute values</p>
+<p class="code">
+typedef enum <a href="#cups_order_e">cups_order_e</a> cups_order_t;
+</p>
+<h3 class="typedef"><a name="cups_orient_t">cups_orient_t</a></h3>
+<p class="description">Orientation attribute values</p>
+<p class="code">
+typedef enum <a href="#cups_orient_e">cups_orient_e</a> cups_orient_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cups_page_header2_t">cups_page_header2_t</a></h3>
+<p class="description">Version 2 page header </p>
+<p class="code">
+typedef struct <a href="#cups_page_header2_s">cups_page_header2_s</a> cups_page_header2_t;
+</p>
+<h3 class="typedef"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="cups_page_header_t">cups_page_header_t</a></h3>
+<p class="description">Version 1 page header </p>
+<p class="code">
+typedef struct <a href="#cups_page_header_s">cups_page_header_s</a> cups_page_header_t;
+</p>
+<h3 class="typedef"><a name="cups_raster_iocb_t">cups_raster_iocb_t</a></h3>
+<p class="description">cupsRasterOpenIO callback function</p>
+<p class="code">
+typedef ssize_t (*cups_raster_iocb_t)(void *ctx, unsigned char *buffer, size_t length);
+</p>
+<h3 class="typedef"><a name="cups_raster_t">cups_raster_t</a></h3>
+<p class="description">Raster stream data</p>
+<p class="code">
+typedef struct _cups_raster_s cups_raster_t;
+</p>
+<h2 class="title"><a name="STRUCTURES">Structures</a></h2>
+<h3 class="struct"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cups_page_header2_s">cups_page_header2_s</a></h3>
+<p class="description">Version 2 page header </p>
+<p class="code">struct cups_page_header2_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned AdvanceDistance;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_adv_t">cups_adv_t</a> AdvanceMedia;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> Collate;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_cut_t">cups_cut_t</a> CutMedia;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> Duplex;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned HWResolution[2];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned ImagingBoundingBox[4];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> InsertSheet;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_jog_t">cups_jog_t</a> Jog;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_edge_t">cups_edge_t</a> LeadingEdge;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> ManualFeed;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned Margins[2];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char MediaClass[64];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char MediaColor[64];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned MediaPosition;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char MediaType[64];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned MediaWeight;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> MirrorPrint;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> NegativePrint;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned NumCopies;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_orient_t">cups_orient_t</a> Orientation;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> OutputFaceUp;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char OutputType[64];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned PageSize[2];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> Separations;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> TraySwitch;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> Tumble;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsBitsPerColor;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsBitsPerPixel;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float cupsBorderlessScalingFactor;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsBytesPerLine;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_order_t">cups_order_t</a> cupsColorOrder;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_cspace_t">cups_cspace_t</a> cupsColorSpace;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsCompression;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsHeight;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float cupsImagingBBox[4];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsInteger[16];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char cupsMarkerType[64];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsMediaType;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsNumColors;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char cupsPageSizeName[64];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float cupsPageSize[2];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;float cupsReal[16];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char cupsRenderingIntent[64];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsRowCount;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsRowFeed;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsRowStep;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char cupsString[16][64];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsWidth;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>AdvanceDistance </dt>
+<dd class="description">AdvanceDistance value in points</dd>
+<dt>AdvanceMedia </dt>
+<dd class="description">AdvanceMedia value (<a href="#cups_adv_t"><code>cups_adv_t</code></a>)</dd>
+<dt>Collate </dt>
+<dd class="description">Collated copies value</dd>
+<dt>CutMedia </dt>
+<dd class="description">CutMedia value (<a href="#cups_cut_t"><code>cups_cut_t</code></a>)</dd>
+<dt>Duplex </dt>
+<dd class="description">Duplexed (double-sided) value</dd>
+<dt>HWResolution[2] </dt>
+<dd class="description">Resolution in dots-per-inch</dd>
+<dt>ImagingBoundingBox[4] </dt>
+<dd class="description">Pixel region that is painted (points, left, bottom, right, top)</dd>
+<dt>InsertSheet </dt>
+<dd class="description">InsertSheet value</dd>
+<dt>Jog </dt>
+<dd class="description">Jog value (<a href="#cups_jog_t"><code>cups_jog_t</code></a>)</dd>
+<dt>LeadingEdge </dt>
+<dd class="description">LeadingEdge value (<a href="#cups_edge_t"><code>cups_edge_t</code></a>)</dd>
+<dt>ManualFeed </dt>
+<dd class="description">ManualFeed value</dd>
+<dt>Margins[2] </dt>
+<dd class="description">Lower-lefthand margins in points</dd>
+<dt>MediaClass[64] </dt>
+<dd class="description">MediaClass string</dd>
+<dt>MediaColor[64] </dt>
+<dd class="description">MediaColor string</dd>
+<dt>MediaPosition </dt>
+<dd class="description">MediaPosition value</dd>
+<dt>MediaType[64] </dt>
+<dd class="description">MediaType string</dd>
+<dt>MediaWeight </dt>
+<dd class="description">MediaWeight value in grams/m^2</dd>
+<dt>MirrorPrint </dt>
+<dd class="description">MirrorPrint value</dd>
+<dt>NegativePrint </dt>
+<dd class="description">NegativePrint value</dd>
+<dt>NumCopies </dt>
+<dd class="description">Number of copies to produce</dd>
+<dt>Orientation </dt>
+<dd class="description">Orientation value (<a href="#cups_orient_t"><code>cups_orient_t</code></a>)</dd>
+<dt>OutputFaceUp </dt>
+<dd class="description">OutputFaceUp value</dd>
+<dt>OutputType[64] </dt>
+<dd class="description">OutputType string</dd>
+<dt>PageSize[2] </dt>
+<dd class="description">Width and length of page in points</dd>
+<dt>Separations </dt>
+<dd class="description">Separations value</dd>
+<dt>TraySwitch </dt>
+<dd class="description">TraySwitch value</dd>
+<dt>Tumble </dt>
+<dd class="description">Tumble value</dd>
+<dt>cupsBitsPerColor </dt>
+<dd class="description">Number of bits for each color</dd>
+<dt>cupsBitsPerPixel </dt>
+<dd class="description">Number of bits for each pixel</dd>
+<dt>cupsBorderlessScalingFactor <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Scaling that was applied to page data </dd>
+<dt>cupsBytesPerLine </dt>
+<dd class="description">Number of bytes per line</dd>
+<dt>cupsColorOrder </dt>
+<dd class="description">Order of colors</dd>
+<dt>cupsColorSpace </dt>
+<dd class="description">True colorspace</dd>
+<dt>cupsCompression </dt>
+<dd class="description">Device compression to use</dd>
+<dt>cupsHeight </dt>
+<dd class="description">Height of page image in pixels</dd>
+<dt>cupsImagingBBox[4] <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Floating point ImagingBoundingBox
+(scaling factor not applied, left,
+bottom, right, top) </dd>
+<dt>cupsInteger[16] <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">User-defined integer values </dd>
+<dt>cupsMarkerType[64] <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Ink/toner type </dd>
+<dt>cupsMediaType </dt>
+<dd class="description">Media type code</dd>
+<dt>cupsNumColors <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Number of color compoents </dd>
+<dt>cupsPageSizeName[64] <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">PageSize name </dd>
+<dt>cupsPageSize[2] <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Floating point PageSize (scaling *
+factor not applied) </dd>
+<dt>cupsReal[16] <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">User-defined floating-point values </dd>
+<dt>cupsRenderingIntent[64] <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Color rendering intent </dd>
+<dt>cupsRowCount </dt>
+<dd class="description">Rows per band</dd>
+<dt>cupsRowFeed </dt>
+<dd class="description">Feed between bands</dd>
+<dt>cupsRowStep </dt>
+<dd class="description">Spacing between lines</dd>
+<dt>cupsString[16][64] <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">User-defined string values </dd>
+<dt>cupsWidth </dt>
+<dd class="description">Width of page image in pixels</dd>
+</dl>
+<h3 class="struct"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="cups_page_header_s">cups_page_header_s</a></h3>
+<p class="description">Version 1 page header </p>
+<p class="code">struct cups_page_header_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned AdvanceDistance;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_adv_t">cups_adv_t</a> AdvanceMedia;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> Collate;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_cut_t">cups_cut_t</a> CutMedia;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> Duplex;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned HWResolution[2];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned ImagingBoundingBox[4];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> InsertSheet;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_jog_t">cups_jog_t</a> Jog;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_edge_t">cups_edge_t</a> LeadingEdge;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> ManualFeed;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned Margins[2];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char MediaClass[64];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char MediaColor[64];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned MediaPosition;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char MediaType[64];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned MediaWeight;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> MirrorPrint;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> NegativePrint;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned NumCopies;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_orient_t">cups_orient_t</a> Orientation;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> OutputFaceUp;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char OutputType[64];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned PageSize[2];<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> Separations;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> TraySwitch;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_bool_t">cups_bool_t</a> Tumble;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsBitsPerColor;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsBitsPerPixel;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsBytesPerLine;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_order_t">cups_order_t</a> cupsColorOrder;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_cspace_t">cups_cspace_t</a> cupsColorSpace;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsCompression;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsHeight;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsMediaType;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsRowCount;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsRowFeed;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsRowStep;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;unsigned cupsWidth;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>AdvanceDistance </dt>
+<dd class="description">AdvanceDistance value in points</dd>
+<dt>AdvanceMedia </dt>
+<dd class="description">AdvanceMedia value (<a href="#cups_adv_t"><code>cups_adv_t</code></a>)</dd>
+<dt>Collate </dt>
+<dd class="description">Collated copies value</dd>
+<dt>CutMedia </dt>
+<dd class="description">CutMedia value (<a href="#cups_cut_t"><code>cups_cut_t</code></a>)</dd>
+<dt>Duplex </dt>
+<dd class="description">Duplexed (double-sided) value</dd>
+<dt>HWResolution[2] </dt>
+<dd class="description">Resolution in dots-per-inch</dd>
+<dt>ImagingBoundingBox[4] </dt>
+<dd class="description">Pixel region that is painted (points, left, bottom, right, top)</dd>
+<dt>InsertSheet </dt>
+<dd class="description">InsertSheet value</dd>
+<dt>Jog </dt>
+<dd class="description">Jog value (<a href="#cups_jog_t"><code>cups_jog_t</code></a>)</dd>
+<dt>LeadingEdge </dt>
+<dd class="description">LeadingEdge value (<a href="#cups_edge_t"><code>cups_edge_t</code></a>)</dd>
+<dt>ManualFeed </dt>
+<dd class="description">ManualFeed value</dd>
+<dt>Margins[2] </dt>
+<dd class="description">Lower-lefthand margins in points</dd>
+<dt>MediaClass[64] </dt>
+<dd class="description">MediaClass string</dd>
+<dt>MediaColor[64] </dt>
+<dd class="description">MediaColor string</dd>
+<dt>MediaPosition </dt>
+<dd class="description">MediaPosition value</dd>
+<dt>MediaType[64] </dt>
+<dd class="description">MediaType string</dd>
+<dt>MediaWeight </dt>
+<dd class="description">MediaWeight value in grams/m^2</dd>
+<dt>MirrorPrint </dt>
+<dd class="description">MirrorPrint value</dd>
+<dt>NegativePrint </dt>
+<dd class="description">NegativePrint value</dd>
+<dt>NumCopies </dt>
+<dd class="description">Number of copies to produce</dd>
+<dt>Orientation </dt>
+<dd class="description">Orientation value (<a href="#cups_orient_t"><code>cups_orient_t</code></a>)</dd>
+<dt>OutputFaceUp </dt>
+<dd class="description">OutputFaceUp value</dd>
+<dt>OutputType[64] </dt>
+<dd class="description">OutputType string</dd>
+<dt>PageSize[2] </dt>
+<dd class="description">Width and length of page in points</dd>
+<dt>Separations </dt>
+<dd class="description">Separations value</dd>
+<dt>TraySwitch </dt>
+<dd class="description">TraySwitch value</dd>
+<dt>Tumble </dt>
+<dd class="description">Tumble value</dd>
+<dt>cupsBitsPerColor </dt>
+<dd class="description">Number of bits for each color</dd>
+<dt>cupsBitsPerPixel </dt>
+<dd class="description">Number of bits for each pixel</dd>
+<dt>cupsBytesPerLine </dt>
+<dd class="description">Number of bytes per line</dd>
+<dt>cupsColorOrder </dt>
+<dd class="description">Order of colors</dd>
+<dt>cupsColorSpace </dt>
+<dd class="description">True colorspace</dd>
+<dt>cupsCompression </dt>
+<dd class="description">Device compression to use</dd>
+<dt>cupsHeight </dt>
+<dd class="description">Height of page image in pixels</dd>
+<dt>cupsMediaType </dt>
+<dd class="description">Media type code</dd>
+<dt>cupsRowCount </dt>
+<dd class="description">Rows per band</dd>
+<dt>cupsRowFeed </dt>
+<dd class="description">Feed between bands</dd>
+<dt>cupsRowStep </dt>
+<dd class="description">Spacing between lines</dd>
+<dt>cupsWidth </dt>
+<dd class="description">Width of page image in pixels</dd>
+</dl>
+<h2 class="title"><a name="ENUMERATIONS">Constants</a></h2>
+<h3 class="enumeration"><a name="cups_adv_e">cups_adv_e</a></h3>
+<p class="description">AdvanceMedia attribute values</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_ADVANCE_FILE </dt>
+<dd class="description">Advance the roll after this file</dd>
+<dt>CUPS_ADVANCE_JOB </dt>
+<dd class="description">Advance the roll after this job</dd>
+<dt>CUPS_ADVANCE_NONE </dt>
+<dd class="description">Never advance the roll</dd>
+<dt>CUPS_ADVANCE_PAGE </dt>
+<dd class="description">Advance the roll after this page</dd>
+<dt>CUPS_ADVANCE_SET </dt>
+<dd class="description">Advance the roll after this set</dd>
+</dl>
+<h3 class="enumeration"><a name="cups_bool_e">cups_bool_e</a></h3>
+<p class="description">Boolean type</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_FALSE </dt>
+<dd class="description">Logical false</dd>
+<dt>CUPS_TRUE </dt>
+<dd class="description">Logical true</dd>
+</dl>
+<h3 class="enumeration"><a name="cups_cspace_e">cups_cspace_e</a></h3>
+<p class="description">cupsColorSpace attribute values</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_CSPACE_ADOBERGB <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">Red, green, blue (Adobe RGB) </dd>
+<dt>CUPS_CSPACE_CIELab <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">CIE Lab </dd>
+<dt>CUPS_CSPACE_CIEXYZ <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">CIE XYZ </dd>
+<dt>CUPS_CSPACE_CMY </dt>
+<dd class="description">Cyan, magenta, yellow (DeviceCMY)</dd>
+<dt>CUPS_CSPACE_CMYK </dt>
+<dd class="description">Cyan, magenta, yellow, black (DeviceCMYK)</dd>
+<dt>CUPS_CSPACE_DEVICE1 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 1 color </dd>
+<dt>CUPS_CSPACE_DEVICE2 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 2 colors </dd>
+<dt>CUPS_CSPACE_DEVICE3 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 3 colors </dd>
+<dt>CUPS_CSPACE_DEVICE4 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 4 colors </dd>
+<dt>CUPS_CSPACE_DEVICE5 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 5 colors </dd>
+<dt>CUPS_CSPACE_DEVICE6 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 6 colors </dd>
+<dt>CUPS_CSPACE_DEVICE7 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 7 colors </dd>
+<dt>CUPS_CSPACE_DEVICE8 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 8 colors </dd>
+<dt>CUPS_CSPACE_DEVICE9 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 9 colors </dd>
+<dt>CUPS_CSPACE_DEVICEA <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 10 colors </dd>
+<dt>CUPS_CSPACE_DEVICEB <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 11 colors </dd>
+<dt>CUPS_CSPACE_DEVICEC <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 12 colors </dd>
+<dt>CUPS_CSPACE_DEVICED <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 13 colors </dd>
+<dt>CUPS_CSPACE_DEVICEE <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 14 colors </dd>
+<dt>CUPS_CSPACE_DEVICEF <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 15 colors </dd>
+<dt>CUPS_CSPACE_GMCK <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Gold, magenta, yellow, black </dd>
+<dt>CUPS_CSPACE_GMCS <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Gold, magenta, yellow, silver </dd>
+<dt>CUPS_CSPACE_GOLD <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Gold foil </dd>
+<dt>CUPS_CSPACE_ICC1 <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 1 color </dd>
+<dt>CUPS_CSPACE_ICC2 <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 2 colors </dd>
+<dt>CUPS_CSPACE_ICC3 <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 3 colors </dd>
+<dt>CUPS_CSPACE_ICC4 <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 4 colors </dd>
+<dt>CUPS_CSPACE_ICC5 <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 5 colors </dd>
+<dt>CUPS_CSPACE_ICC6 <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 6 colors </dd>
+<dt>CUPS_CSPACE_ICC7 <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 7 colors </dd>
+<dt>CUPS_CSPACE_ICC8 <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 8 colors </dd>
+<dt>CUPS_CSPACE_ICC9 <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 9 colors </dd>
+<dt>CUPS_CSPACE_ICCA <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 10 colors </dd>
+<dt>CUPS_CSPACE_ICCB <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 11 colors </dd>
+<dt>CUPS_CSPACE_ICCC <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 12 colors </dd>
+<dt>CUPS_CSPACE_ICCD <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 13 colors </dd>
+<dt>CUPS_CSPACE_ICCE <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 14 colors </dd>
+<dt>CUPS_CSPACE_ICCF <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
+<dd class="description">ICC-based, 15 colors </dd>
+<dt>CUPS_CSPACE_K </dt>
+<dd class="description">Black (DeviceK)</dd>
+<dt>CUPS_CSPACE_KCMY <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Black, cyan, magenta, yellow </dd>
+<dt>CUPS_CSPACE_KCMYcm <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Black, cyan, magenta, yellow, light-cyan, light-magenta </dd>
+<dt>CUPS_CSPACE_RGB </dt>
+<dd class="description">Red, green, blue (DeviceRGB, sRGB by default)</dd>
+<dt>CUPS_CSPACE_RGBA </dt>
+<dd class="description">Red, green, blue, alpha (DeviceRGB, sRGB by default)</dd>
+<dt>CUPS_CSPACE_RGBW <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Red, green, blue, white (DeviceRGB, sRGB by default) </dd>
+<dt>CUPS_CSPACE_SILVER <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Silver foil </dd>
+<dt>CUPS_CSPACE_SRGB <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">Red, green, blue (sRGB) </dd>
+<dt>CUPS_CSPACE_SW <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">Luminance (gamma 2.2) </dd>
+<dt>CUPS_CSPACE_W </dt>
+<dd class="description">Luminance (DeviceGray, gamma 2.2 by default)</dd>
+<dt>CUPS_CSPACE_WHITE <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">White ink (as black) </dd>
+<dt>CUPS_CSPACE_YMC <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Yellow, magenta, cyan </dd>
+<dt>CUPS_CSPACE_YMCK <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Yellow, magenta, cyan, black </dd>
+</dl>
+<h3 class="enumeration"><a name="cups_cut_e">cups_cut_e</a></h3>
+<p class="description">CutMedia attribute values</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_CUT_FILE </dt>
+<dd class="description">Cut the roll after this file</dd>
+<dt>CUPS_CUT_JOB </dt>
+<dd class="description">Cut the roll after this job</dd>
+<dt>CUPS_CUT_NONE </dt>
+<dd class="description">Never cut the roll</dd>
+<dt>CUPS_CUT_PAGE </dt>
+<dd class="description">Cut the roll after this page</dd>
+<dt>CUPS_CUT_SET </dt>
+<dd class="description">Cut the roll after this set</dd>
+</dl>
+<h3 class="enumeration"><a name="cups_edge_e">cups_edge_e</a></h3>
+<p class="description">LeadingEdge attribute values</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_EDGE_BOTTOM </dt>
+<dd class="description">Leading edge is the bottom of the page</dd>
+<dt>CUPS_EDGE_LEFT </dt>
+<dd class="description">Leading edge is the left of the page</dd>
+<dt>CUPS_EDGE_RIGHT </dt>
+<dd class="description">Leading edge is the right of the page</dd>
+<dt>CUPS_EDGE_TOP </dt>
+<dd class="description">Leading edge is the top of the page</dd>
+</dl>
+<h3 class="enumeration"><a name="cups_jog_e">cups_jog_e</a></h3>
+<p class="description">Jog attribute values</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_JOG_FILE </dt>
+<dd class="description">Move pages after this file</dd>
+<dt>CUPS_JOG_JOB </dt>
+<dd class="description">Move pages after this job</dd>
+<dt>CUPS_JOG_NONE </dt>
+<dd class="description">Never move pages</dd>
+<dt>CUPS_JOG_SET </dt>
+<dd class="description">Move pages after this set</dd>
+</dl>
+<h3 class="enumeration"><a name="cups_mode_e">cups_mode_e</a></h3>
+<p class="description">cupsRasterOpen modes</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_RASTER_READ </dt>
+<dd class="description">Open stream for reading</dd>
+<dt>CUPS_RASTER_WRITE </dt>
+<dd class="description">Open stream for writing</dd>
+<dt>CUPS_RASTER_WRITE_COMPRESSED <span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span></dt>
+<dd class="description">Open stream for compressed writing </dd>
+<dt>CUPS_RASTER_WRITE_PWG <span class="info">&nbsp;CUPS 1.5/Mac OS X 10.7&nbsp;</span></dt>
+<dd class="description">Open stream for compressed writing in PWG mode </dd>
+</dl>
+<h3 class="enumeration"><a name="cups_order_e">cups_order_e</a></h3>
+<p class="description">cupsColorOrder attribute values</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_ORDER_BANDED </dt>
+<dd class="description">CCC MMM YYY KKK ...</dd>
+<dt>CUPS_ORDER_CHUNKED </dt>
+<dd class="description">CMYK CMYK CMYK ...</dd>
+<dt>CUPS_ORDER_PLANAR </dt>
+<dd class="description">CCC ... MMM ... YYY ... KKK ...</dd>
+</dl>
+<h3 class="enumeration"><a name="cups_orient_e">cups_orient_e</a></h3>
+<p class="description">Orientation attribute values</p>
+<h4 class="constants">Constants</h4>
+<dl>
+<dt>CUPS_ORIENT_0 </dt>
+<dd class="description">Don't rotate the page</dd>
+<dt>CUPS_ORIENT_180 </dt>
+<dd class="description">Turn the page upside down</dd>
+<dt>CUPS_ORIENT_270 </dt>
+<dd class="description">Rotate the page clockwise</dd>
+<dt>CUPS_ORIENT_90 </dt>
+<dd class="description">Rotate the page counter-clockwise</dd>
+</dl>
+</div>
+</body>
+</html>
diff --git a/doc/help/cgi.html b/doc/help/cgi.html
new file mode 100644
index 000000000..c50a2a501
--- /dev/null
+++ b/doc/help/cgi.html
@@ -0,0 +1,86 @@
+<HTML>
+<!-- SECTION: Getting Started -->
+<HEAD>
+ <TITLE>Using CGI Programs</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">Using CGI Programs</H1>
+
+<P>CUPS provides a dynamic web interface through dedicated CGI programs that
+are executed when users open special directories on the CUPS server. Each CGI
+performs administration, class, help, 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.</P>
+
+<P>CUPS also supports CGI programs and specific scripting languages (Java, Perl,
+PHP, and Python) for pages you want to provide. The interpreters for these
+languages are currently configured at compile time and are associated with
+MIME media types. <a href="#TABLE1">Table 1</a> shows the MIME media types that
+are reserved for each type of page and are the same as those used by the Apache
+web server.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="CGI MIME Media Types">
+<CAPTION><A NAME="TABLE1">Table 1</A>: CGI MIME Media Types</CAPTION>
+<TR>
+ <TH>MIME Media Type</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>application/x-httpd-cgi</TD>
+ <TD>CGI script/program</TD>
+</TR>
+<TR>
+ <TD>application/x-httpd-java</TD>
+ <TD>Java program</TD>
+</TR>
+<TR>
+ <TD>application/x-httpd-perl</TD>
+ <TD>Perl script</TD>
+</TR>
+<TR>
+ <TD>application/x-httpd-php</TD>
+ <TD>PHP script</TD>
+</TR>
+<TR>
+ <TD>application/x-httpd-python</TD>
+ <TD>Python script</TD>
+</TR>
+</TABLE></DIV>
+
+<H2><A NAME="CONFIG">Configuring the Server</A></H2>
+
+<P>In order to enable the corresponding type, you must create a
+new <VAR>/etc/cups/cgi.types</VAR> file which maps the filename
+extensions to the appropriate MIME types, for example:</P>
+
+<PRE CLASS="command">
+application/x-httpd-cgi cgi
+application/x-httpd-java class
+application/x-httpd-perl pl
+application/x-httpd-php php
+application/x-httpd-python py
+</PRE>
+
+<P>CGI scripts/programs (application/x-httpd-cgi) also must have execution
+permissions to be treated as a CGI script or program.</P>
+
+<H2><A NAME="LIMITS">Limitations</A></H2>
+
+<P>CUPS implements most of the CGI/1.1 specification, with the
+following exceptions:</P>
+
+<UL>
+
+ <LI>No PATH_INFO or PATH_TRANSLATED support</LI>
+
+ <LI>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</LI>
+
+</UL>
+
+</BODY>
+</HTML>
diff --git a/doc/help/glossary.html b/doc/help/glossary.html
new file mode 100644
index 000000000..c6898dc7d
--- /dev/null
+++ b/doc/help/glossary.html
@@ -0,0 +1,219 @@
+<HTML>
+<!-- SECTION: Getting Started -->
+<HEAD>
+ <TITLE>Glossary</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">Glossary</H1>
+
+<H2><A NAME="A">A</A></H2>
+
+<DL>
+
+ <DT>ASCII
+ <DD>American Standard Code for Information Interchange
+
+</DL>
+
+
+<H2><A NAME="C">C</A></H2>
+
+<DL>
+
+ <DT>C
+ <DD>A computer language
+
+ <DT>Character Set
+ <DD>The association of numbers with specific printed or
+ displayed characters or symbols
+
+</DL>
+
+
+<H2><A NAME="E">E</A></H2>
+
+<DL>
+
+ <DT>ESC/P
+ <DD>EPSON Standard Code for Printers
+
+</DL>
+
+
+<H2><A NAME="F">F</A></H2>
+
+<DL>
+
+ <DT>FTP
+ <DD>File Transfer Protocol
+
+</DL>
+
+
+<H2><A NAME="G">G</A></H2>
+
+<DL>
+
+ <DT>GIF
+ <DD>Graphics Interchange Format
+
+</DL>
+
+
+<H2><A NAME="H">H</A></H2>
+
+<DL>
+
+ <DT>HP-GL
+ <DD>Hewlett-Packard Graphics Language
+
+ <DT>HP-PCL
+ <DD>Hewlett-Packard Page Control Language
+
+ <DT>HP-PJL
+ <DD>Hewlett-Packard Printer Job Language
+
+</DL>
+
+
+<H2><A NAME="I">I</A></H2>
+
+<DL>
+
+ <DT>IETF
+ <DD>Internet Engineering Task Force
+
+ <DT>IP
+ <DD>Internet Protocol
+
+ <DT>IPv4
+ <DD>Internet Protocol, version 4; IPv4 addresses are 32-bits in
+ length and often look like "nnn.nnn.nnn.nnn" and "127.0.0.1"
+
+ <DT>IPv6
+ <DD>Internet Protocol, version 6: IPv6 addresses are 128-bits in
+ length and look like "xxxx::xxxx:xxxx:xxxx:xxxx" and "::1"
+
+ <DT>IPP
+ <DD>Internet Printing Protocol
+
+ <DT>ISO
+ <DD>International Standards Organization
+
+</DL>
+
+
+<H2><A NAME="J">J</A></H2>
+
+<DL>
+
+ <DT>JFIF
+ <DD>JPEG File Interchange Format
+
+ <DT>JPEG
+ <DD>Joint Photographic Experts Group
+
+</DL>
+
+
+<H2><A NAME="L">L</A></H2>
+
+<DL>
+
+ <DT>LPD
+ <DD>Line Printer Daemon
+
+</DL>
+
+
+<H2><A NAME="M">M</A></H2>
+
+<DL>
+
+ <DT>MIME
+ <DD>Multimedia Internet Mail Exchange
+
+</DL>
+
+
+<H2><A NAME="P">P</A></H2>
+
+<DL>
+
+ <DT>parallel
+ <DD>Sending or receiving data more than 1 bit at a time
+
+ <DT>PDF
+ <DD>Portable Document Format
+
+ <DT>pipe
+ <DD>A one-way communications channel between two programs
+
+ <DT>PNG
+ <DD>Portable Network Graphics
+
+ <DT>PostScript
+ <DD>A page description language that is most often used
+ for printing
+
+ <DT>PPD
+ <DD>PostScript Printer Description
+
+</DL>
+
+
+<H2><A NAME="S">S</A></H2>
+
+<DL>
+
+ <DT>SCSI
+ <DD>Small Computer Systems Interface
+
+ <DT>serial
+ <DD>Sending or receiving data 1 bit at a time
+
+ <DT>SMB
+ <DD>Server Message Block
+
+ <DT>socket
+ <DD>A two-way network communications channel
+
+</DL>
+
+
+<H2><A NAME="T">T</A></H2>
+
+<DL>
+
+ <DT>TCP
+ <DD>Transmission Control Protocol
+
+ <DT>TFTP
+ <DD>Trivial File Transfer Protocol
+
+ <DT>TIFF
+ <DD>Tagged Image File Format
+
+</DL>
+
+
+<H2><A NAME="U">U</A></H2>
+
+<DL>
+
+ <DT>UDP
+ <DD>Unicast Datagram Protocol
+
+ <DT>Unicode
+ <DD>A universal character set for all languages of the
+ world
+
+ <DT>UTF-8
+ <DD>Unicode Transfer Format 8-Bit
+
+</DL>
+
+</BODY>
+</HTML>
diff --git a/doc/help/kerberos.html b/doc/help/kerberos.html
new file mode 100644
index 000000000..82c9b5ffe
--- /dev/null
+++ b/doc/help/kerberos.html
@@ -0,0 +1,122 @@
+<HTML>
+<!-- SECTION: Getting Started -->
+<HEAD>
+ <TITLE>Using Kerberos Authentication</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">Using Kerberos Authentication</H1>
+
+<P>CUPS allows you to use a Key Distribution Center (KDC) for authentication
+on your local CUPS server and when printing to a remote authenticated queue.
+This document describes how to configure CUPS to use Kerberos authentication
+and provides links to the MIT help pages for configuring Kerberos on your
+systems and network.</P>
+
+
+<H2 CLASS="title"><A NAME="REQUIREMENTS">System Requirements</A></H2>
+
+<p>The following are required to use Kerberos with CUPS:</p>
+
+<ol>
+
+ <li>Heimdal Kerberos (any version) or MIT Kerberos (1.6.3 or newer)</li>
+
+ <li>Properly configured Domain Name System (DNS)
+ infrastructure:<ol type='a'>
+ <li>DNS server(s) with static IP addresses for all CUPS clients
+ and servers or configured to allow DHCP updates to the host
+ addresses</li>
+ <li>All CUPS clients and servers configured to use the same
+ DNS server(s)</li>
+ </ol></li>
+
+ <li>Properly configured Kerberos infrastructure:<ol type='a'>
+ <li>KDC configured to allow CUPS clients and servers to obtain
+ Service Granting Tickets (SGTs) for the "ipp" service</li>
+ <li>LDAP-based user accounts - both OpenDirectory and
+ ActiveDirectory provide this with the KDC</li>
+ <li>CUPS clients and servers bound to the KDC and LDAP
+ server(s)</li>
+ </ol></li>
+
+ <li>An "ipp" Service Granting Ticket (SGT) for every CUPS client and
+ server</li>
+
+</ol>
+
+
+<H2 CLASS="title"><A NAME="KRB5">Configuring Kerberos on Your System</A></H2>
+
+<P>Before you can use Kerberos with CUPS, you will need to configure
+Kerberos on your system and setup a system as a KDC. Because this
+configuration is highly system and site-specific, please consult
+the following on-line resources provided by the creators of Kerberos
+at the Massachusetts Institute of Technology (MIT):</P>
+
+<UL>
+
+ <LI><A HREF="http://web.mit.edu/kerberos/">Kerberos: The Network
+ Authentication Protocol</A></LI>
+
+ <LI><A HREF="http://web.mit.edu/macdev/KfM/Common/Documentation/faq-osx.html">Kerberos
+ on Mac OS X Frequently Asked Questions</A></LI>
+
+</UL>
+
+<P>The Linux Documentation Project also has a HOWTO on Kerberos:</P>
+
+<UL>
+
+ <LI><A HREF="http://tldp.org/HOWTO/html_single/Kerberos-Infrastructure-HOWTO/">Kerberos
+ Infrastructure HOWTO</A></LI>
+
+</UL>
+
+
+<H2 CLASS="title"><A NAME="CUPS">Configuring CUPS to Use Kerberos</A></H2>
+
+<P>Once you have configured Kerberos on your system(s), you can then
+enable Kerberos authentication by selecting the <tt>Negotiate</tt>
+authentication type. The simplest way to do this is using the
+<tt>cupsctl(8)</tt> command:</P>
+
+<PRE CLASS="command">
+<KBD>cupsctl DefaultAuthType=Negotiate</KBD>
+</PRE>
+
+<P>You can also enable Kerberos from the web interface by checking the
+<VAR>Use Kerberos Authentication</VAR> box and clicking <VAR>Change
+Settings</VAR>:</P>
+
+<PRE CLASS="command">
+http://localhost:631/admin
+</PRE>
+
+<P>After you have enabled Kerberos authentication, use the built-in
+"authenticated" policy or your own custom policies with the printers you
+will be sharing. See <a href="policies.html">Managing Operation Policies</a>
+for more information.</P>
+
+
+<H2 CLASS="title"><A NAME="IMPLEMENT">Implementation Information</A></H2>
+
+<P>CUPS implements Kerberos over HTTP using GSSAPI and the service name
+"host". Because of limitations in the HTTP GSSAPI protocol extension, only
+a single domain/KDC is supported for authentication.</P>
+
+<P>When doing printing tasks that require authentication, CUPS requests a
+single-use "ticket" from your login session to authenticate who you are.
+This ticket gives CUPS a username of the form "user@REALM", which is then
+converted to just "user" for purposes of user and group checks.</P>
+
+<P>In order to support printing to a shared printer, CUPS has to ask the KDC
+for a copy of your credentials (this is called delegation) that can be sent to
+the remote server for authentication. Delegation only works when the system
+has a stable hostname which maps to the current address of the system, which
+is why you need a static IP address or DHCP that updates the DNS entry for your
+system.</P>
+
+</BODY>
+</HTML>
diff --git a/doc/help/license.html b/doc/help/license.html
new file mode 100644
index 000000000..2b7c2460f
--- /dev/null
+++ b/doc/help/license.html
@@ -0,0 +1,1076 @@
+<HTML>
+<!-- SECTION: Getting Started -->
+<HEAD>
+ <TITLE>Software License Agreement</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">Software License Agreement</H1>
+
+<P ALIGN="CENTER">Copyright 2007-2011 by Apple Inc.<BR>
+1 Infinite Loop<BR>
+Cupertino, CA 95014 USA<BR>
+<BR>
+WWW: <A HREF="http://www.cups.org/">http://www.cups.org/</A>
+
+<H2 CLASS="title"><A NAME="INTRO">Introduction</A></H2>
+
+<P>CUPS<SUP>TM</SUP> 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.</P>
+
+<P>The GNU LGPL applies to the CUPS and CUPS Imaging libraries located in the
+"cups" and "filter" subdirectories of the CUPS source distribution and the files
+in the "test" subdirectory. The GNU GPL applies to the remainder of the CUPS
+distribution.</P>
+
+<P>For those not familiar with the GNU GPL, the license basically
+allows you to:</P>
+
+<UL>
+
+ <LI>Use the CUPS software at no charge.</LI>
+
+ <LI>Distribute verbatim copies of the software in source
+ or binary form.</LI>
+
+ <LI>Sell verbatim copies of the software for a media
+ fee, or sell support for the software.</LI>
+
+</UL>
+
+<P>What this license <EM>does not</EM> 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
+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.</P>
+
+<P>The GNU LGPL relaxes the "link-to" restriction, allowing you
+to develop applications that use the CUPS and CUPS Imaging
+libraries under other licenses and/or conditions as appropriate
+for your application, driver, or filter.</P>
+
+
+<H2 CLASS="title"><A NAME="EXCEPTIONS">License Exceptions</A></H2>
+
+<P>In addition, as the copyright holder of CUPS, Apple Inc. grants
+the following special exceptions:</P>
+
+<OL>
+
+ <LI><B>Apple Operating System Development License
+ Exception</B>;
+
+ <OL TYPE="a">
+
+ <LI>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.</LI>
+
+ <LI>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.</LI>
+
+ <LI>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.</LI>
+
+ <LI>All CUPS software that falls under this
+ license exception have the following text at the
+ top of each source file:
+
+ <BLOCKQUOTE>This file is subject to the Apple
+ OS-Developed Software
+ exception.</BLOCKQUOTE></LI>
+
+ </OL>
+
+ <LI><B>OpenSSL Toolkit License Exception</B>;
+
+ <OL TYPE="a">
+
+ <LI>Apple Inc. explicitly allows the
+ compilation and distribution of the CUPS
+ software with the OpenSSL Toolkit.</LI>
+
+ </OL>
+
+</OL>
+
+<P>No developer is required to provide these exceptions in a
+derived work.</P>
+
+
+<H2 CLASS="title"><A NAME="KERBEROS">Kerberos Support Code</A></H2>
+
+<P>The Kerberos support code ("KSC") is copyright 2006 by Jelmer
+Vernooij and is provided 'as-is', without any express or implied
+warranty. In no event will the author or Apple Inc. be held liable
+for any damages arising from the use of the KSC.</P>
+
+<P>Sources files containing KSC have the following text at the top
+of each source file:</P>
+
+<BLOCKQUOTE>This file contains Kerberos support code, copyright
+2006 by Jelmer Vernooij.</BLOCKQUOTE>
+
+<P>The KSC copyright and license apply <EM>only</EM> to
+Kerberos-related feature code in CUPS. Such code is typically
+conditionally compiled based on the present of the
+<TT>HAVE_GSSAPI</TT> preprocessor definition.</P>
+
+<P>Permission is granted to anyone to use the KSC for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following
+restrictions:</P>
+
+<OL>
+
+ <LI>The origin of the KSC must not be misrepresented; you
+ must not claim that you wrote the original software. If
+ you use the KSC in a product, an acknowledgment in the
+ product documentation would be appreciated but is not
+ required.</LI>
+
+ <LI>Altered source versions must be plainly marked as
+ such, and must not be misrepresented as being the
+ original software.</LI>
+
+ <LI>This notice may not be removed or altered from any
+ source distribution.</LI>
+
+</OL>
+
+
+<H2 CLASS="title"><A NAME="TRADEMARKS">Trademarks</A></H2>
+
+<P>CUPS and the CUPS logo (the "CUPS Marks") are trademarks of Apple Inc. Apple
+grants you a non-exclusive and non-transferable right to use the CUPS Marks in
+any direct port or binary distribution incorporating CUPS software and in any
+promotional material therefor. You agree that your products will meet the
+highest levels of quality and integrity for similar goods, not be unlawful, and
+be developed, manufactured, and distributed in compliance with this license.
+You will not interfere with Apple's rights in the CUPS Marks, and all use of the
+CUPS Marks shall inure to the benefit of Apple. This license does not apply to
+use of the CUPS Marks in a derivative products, which requires prior written
+permission from Apple Inc.</P>
+
+
+<H2 CLASS="title"><A NAME="GPL">GNU GENERAL PUBLIC LICENSE</A></H2>
+
+<P>Version 2, June 1991
+
+<PRE>
+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.
+</PRE>
+
+<H3>Preamble</H3>
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>The precise terms and conditions for copying, distribution and
+modification follow.
+
+<H3>GNU GENERAL PUBLIC LICENSE<BR>
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</H3>
+
+<OL START="0">
+
+<LI>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".
+
+<P>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.
+
+<LI>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.
+
+<P>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.
+
+<LI>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:
+
+<OL TYPE="a">
+
+<LI>You must cause the modified files to carry prominent notices
+stating that you changed the files and the date of any change.
+
+<LI>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.
+
+<LI>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.)
+
+</OL>
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<LI>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:
+
+<OL TYPE="a">
+
+<LI>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,
+
+<LI>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,
+
+<LI>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.)
+
+</OL>
+
+<P>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.
+
+<P>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.
+
+<LI>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.
+
+<LI>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.
+
+<LI>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.
+
+<LI>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.
+
+<P>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.
+
+<P>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.
+
+<P>This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+<LI>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.
+
+<LI>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.
+
+<P>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.
+
+<LI>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.
+
+</OL>
+
+<H3>NO WARRANTY</H3>
+
+<OL START="11">
+
+<LI>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.
+
+<LI>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.
+
+</OL>
+
+<H3>END OF TERMS AND CONDITIONS</H3>
+
+<H3>How to Apply These Terms to Your New Programs</H3>
+
+<P>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.
+
+<P>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.
+
+<PRE>
+<VAR>one line to give the program's name and an idea of what it does.</VAR>
+Copyright (C) <VAR>yyyy</VAR> <VAR>name of author</VAR>
+
+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.
+</PRE>
+
+<P>Also add information on how to contact you by electronic and paper mail.
+
+<P>If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+<PRE>
+Gnomovision version 69, Copyright (C) <VAR>year</VAR> <VAR>name of author</VAR>
+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.
+</PRE>
+
+<P>The hypothetical commands <SAMP>`show w'</SAMP> and <SAMP>`show c'</SAMP> should show
+the appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than <SAMP>`show w'</SAMP> and
+<SAMP>`show c'</SAMP>; they could even be mouse-clicks or menu items--whatever
+suits your program.
+
+<P>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:
+
+<PRE>
+Yoyodyne, Inc., hereby disclaims all copyright
+interest in the program `Gnomovision'
+(which makes passes at compilers) written
+by James Hacker.
+
+<VAR>signature of Ty Coon</VAR>, 1 April 1989
+Ty Coon, President of Vice
+</PRE>
+
+<H2 CLASS="title"><A NAME="LGPL">GNU LIBRARY GENERAL PUBLIC LICENSE</A></H2>
+
+<P>Version 2, June 1991
+
+<PRE>
+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.]
+</PRE>
+
+<H3>Preamble</H3>
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P>Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+<H3>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</H3>
+
+<P><STRONG>0.</STRONG>
+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".
+
+<P>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.
+
+<P>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".)
+
+<P>"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.
+
+<P>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.
+
+<P><STRONG>1.</STRONG>
+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.
+
+<P>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.
+
+<P><STRONG>2.</STRONG>
+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:
+
+<OL TYPE="a">
+
+ <LI>The modified work must itself be a software library.
+
+ <P>
+ <LI>You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ <P>
+ <LI>You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ <P>
+ <LI>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.
+
+ <P>(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.)
+
+</OL>
+
+<P>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.
+
+<P>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.
+
+<P>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.
+
+<P><STRONG>3.</STRONG>
+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.
+
+<P>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.
+
+<P>This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+<P><STRONG>4.</STRONG>
+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.
+
+<P>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.
+
+<P><STRONG>5.</STRONG>
+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.
+
+<P>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.
+
+<P>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.
+
+<P>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.)
+
+<P>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.
+
+<P><STRONG>6.</STRONG>
+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.
+
+<P>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:
+
+<OL TYPE="a">
+
+ <LI>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.)
+
+ <P>
+ <LI>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.
+
+ <P>
+ <LI>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.
+
+ <P>
+ <LI>Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+</OL>
+
+<P>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.
+
+<P>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.
+
+<P><STRONG>7.</STRONG>
+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:
+
+<OL TYPE="a">
+
+ <LI>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.
+
+ <P>
+ <LI>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.
+
+</OL>
+
+<P><STRONG>8.</STRONG>
+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.
+
+<P><STRONG>9.</STRONG>
+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.
+
+<P><STRONG>10.</STRONG>
+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.
+
+<P><STRONG>11.</STRONG>
+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.
+
+<P>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.
+
+<P>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.
+
+<P>This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+<P><STRONG>12.</STRONG>
+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.
+
+<P><STRONG>13.</STRONG>
+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.
+
+<P>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.
+
+<P><STRONG>14.</STRONG>
+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.
+
+<P><STRONG>NO WARRANTY</STRONG>
+
+<P><STRONG>15.</STRONG>
+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.
+
+<P><STRONG>16.</STRONG>
+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.
+
+<H3>END OF TERMS AND CONDITIONS</H3>
+
+<H3>How to Apply These Terms to Your New Libraries</H3>
+
+<P>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).
+
+<P>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.
+
+<PRE>
+<VAR>one line to give the library's name and an idea of what it does.</VAR>
+Copyright (C) <VAR>year</VAR> <VAR>name of author</VAR>
+
+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
+</PRE>
+
+<P>Also add information on how to contact you by electronic and paper mail.
+
+<P>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:
+
+<PRE>
+Yoyodyne, Inc., hereby disclaims all copyright interest in
+the library `Frob' (a library for tweaking knobs) written
+by James Random Hacker.
+
+<VAR>signature of Ty Coon</VAR>, 1 April 1990
+Ty Coon, President of Vice
+</PRE>
+
+<P>That's all there is to it!
+
+</BODY>
+</HTML>
diff --git a/doc/help/network.html b/doc/help/network.html
new file mode 100644
index 000000000..d02d4f403
--- /dev/null
+++ b/doc/help/network.html
@@ -0,0 +1,684 @@
+<HTML>
+<!-- SECTION: Getting Started -->
+<HEAD>
+ <TITLE>Using Network Printers</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">Using Network Printers</H1>
+
+<P>This help document describes how to discover, configure, and use TCP/IP network printers with CUPS.</P>
+
+<H2 CLASS="title"><A NAME="ADDRESS">Getting the IP Address</A></H2>
+
+<P>Every network printer or print server has a unique Internet Protocol (IP) address associated with it. This address is either configured manually or set using an automatic network protocol such as the <A HREF="#BOOTP">Boot Protocol (BOOTP)</A>, <A HREF="#DHCP">Dynamic Host Control Protocol (DHCP)</A>, Reverse Address Resolution Protocol (RARP), or ZeroConf.</P>
+
+<P>You can normally find the IP address of a printer on the printer's control panel or by printing the configuration or status page. The <A HREF="#SNMP">Simple Network Management Protocol (SNMP)</A> can also be used to get the IP address remotely, which happens automatically when you visit the CUPS administration web page or choose an available CUPS device when adding a printer.</P>
+
+
+<H2 CLASS="title"><A NAME="CONFIG">Configuring the IP Address</A></H2>
+
+<P>When you first install a network printer or print server on your LAN, you need to set the Internet Protocol ("IP") address. Most higher-end "workgroup" printers allow you to set the address through the printer control panel. However, if you have many printers you will want to assign the addresses remotely - this makes administration a bit easier and avoids assigning duplicate addresses accidentally.</P>
+
+<P>To setup your printer or print server for remote address assignment, you'll need the Ethernet Media Access Control ("MAC") address, also sometimes called a node address, and the IP address you want to use for the device. The Ethernet MAC address can often be found on the printer test page or bottom of the print server.</P>
+
+<H3><A NAME="DHCP">Configuring the IP Address Using DHCP</A></H3>
+
+<P>The DHCP protocol is the usual way of setting the IP address of a printer on a managed network. Using the standard <TT>dhcpd(8)</TT> program supplied with UNIX you simply need to add a line to the <VAR>/etc/dhcpd.conf</VAR> file:</P>
+
+<PRE CLASS="command">
+host <I>hostname</I> {
+ hardware ethernet <I>mac-address</I>;
+ fixed-address <I>ip-address</I>;
+}
+</PRE>
+
+<P>Make sure that the hostname you use is also listed in the <VAR>/etc/hosts</VAR> file or is registered with your DNS server.</P>
+
+<H3><A NAME="BOOTP">Configuring the IP Address Using BOOTP</A></H3>
+
+<P>The BOOTP protocol is used when you need to provide additional information such as the location of a configuration file to the network interface. Using the standard <TT>bootpd(8)</TT> program supplied with UNIX you simply need to add a line to the <VAR>/etc/bootptab</VAR> file; for IRIX:</P>
+
+<PRE CLASS="command">
+myprinter 08:00:69:00:12:34 192.0.2.2 <VAR>myprinter.boot</VAR>
+</PRE>
+
+<P>Newer versions of <TT>bootpd</TT> use a different format:</P>
+
+<PRE CLASS="command">
+myprinter:ha=080069001234:ip=192.0.2.2:<VAR>t144=myprinter.boot</VAR>
+</PRE>
+
+<P>The <VAR>myprinter.boot</VAR> file resides in the <VAR>/usr/local/boot</VAR> directory by default. If you do not need to provide a boot file you may leave the last part of the line blank.</P>
+
+<BLOCKQUOTE><B>Note:</B> Some versions of UNIX do not enable the BOOTP service by default. The <VAR>/etc/inetd.conf</VAR> or <VAR>/etc/xinetd.d/bootp</VAR> file usually contains a line for the BOOTP service that can be uncommented if needed.</BLOCKQUOTE>
+
+
+<H2 CLASS="title"><A NAME="VERIFY">Verifying the Printer Connection</A></H2>
+
+<P>To test that the IP address has been successfully assigned and
+that the printer is properly connected to your LAN, type:</P>
+
+<PRE CLASS="command">
+<KBD>ping ip-address</KBD>
+</PRE>
+
+<P>If the connection is working properly you will see something
+like:</P>
+
+<PRE CLASS="command">
+<KBD>ping myprinter</KBD>
+PING myprinter (192.0.2.2): 56 data bytes
+64 bytes from 192.0.2.2: icmp_seq=0 ttl=15 time=5 ms
+64 bytes from 192.0.2.2: icmp_seq=1 ttl=15 time=3 ms
+64 bytes from 192.0.2.2: icmp_seq=2 ttl=15 time=3 ms
+64 bytes from 192.0.2.2: icmp_seq=3 ttl=15 time=3 ms
+</PRE>
+
+<P>If not, verify that the printer or print server is connected
+to the LAN, it is powered on, the LAN cabling is good, and the IP
+address is set correctly. You can usually see the current IP
+address and network status by printing a configuration or test
+page on the device.</P>
+
+
+<H2 CLASS="title"><A NAME="PROTOCOLS">Network Protocols Supported by CUPS</H2>
+
+<P>CUPS supports most network printers using one of three TCP/IP-based protocols. Printer discovery is currently accomplished using the SNMP protocol, however future versions of CUPS will also include support for multicast DNS service discovery as well.</P>
+
+<H3><A NAME="SOCKET">AppSocket Protocol</A></H3>
+
+<P>The AppSocket protocol (sometimes also called the JetDirect protocol, owing to its origins with the HP JetDirect network interfaces) is the simplest, fastest, and generally the most reliable network protocol used for printers. AppSocket printing normally happens over port 9100 and uses the <tt>socket</tt> URI scheme:</P>
+
+<PRE>
+socket://<i>ip-address-or-hostname</i>
+socket://<i>ip-address-or-hostname</i>/?waiteof=false
+socket://<i>ip-address-or-hostname</i>:<i>port-number</i>
+socket://<i>ip-address-or-hostname</i>:<i>port-number</i>/?waiteof=false
+</PRE>
+
+<P>The "waiteof" option controls whether the <tt>socket</tt> backend waits for the printer to complete the printing of the job. The default is to wait.</P>
+
+<H3><A NAME="IPP">Internet Printing Protocol (IPP)</A></H3>
+
+<P>IPP is the only protocol that CUPS supports natively and is supported by some network printers and print servers. However, since many printers do not implement IPP properly, only use IPP when the vendor actually documents official support for it. IPP printing normally happens over port 631 and uses the <tt>http</tt> and <tt>ipp</tt> URI schemes:</P>
+
+<PRE>
+http://<i>ip-address-or-hostname</i>:<i>port-number</i>/<i>resource</i>
+http://<i>ip-address-or-hostname</i>:<i>port-number</i>/<i>resource</i>?<i>option=value</i>
+http://<i>ip-address-or-hostname</i>:<i>port-number</i>/<i>resource</i>?<i>option=value&option=value</i>
+ipp://<i>ip-address-or-hostname</i>/<i>resource</i>
+ipp://<i>ip-address-or-hostname</i>/<i>resource</i>?<i>option=value</i>
+ipp://<i>ip-address-or-hostname</i>/<i>resource</i>?<i>option=value&option=value</i>
+ipp://<i>ip-address-or-hostname</i>:<i>port-number</i>/<i>resource</i>
+ipp://<i>ip-address-or-hostname</i>:<i>port-number</i>/<i>resource</i>?<i>option=value</i>
+ipp://<i>ip-address-or-hostname</i>:<i>port-number</i>/<i>resource</i>?<i>option=value&option=value</i>
+</PRE>
+
+<P>The <tt>ipp</tt> backend supports many options, which are summarized in <A HREF="#TABLE2">Table 2</A>.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="IPP URI Options">
+<CAPTION>Table 2: <A NAME="TABLE2">IPP URI Options</A></CAPTION>
+<THEAD>
+<TR>
+ <TH>Option</TH>
+ <TH>Description</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD><TT>compression=gzip</TT></TD>
+ <TD>Specifies that print data should be compressed before sending.</TD>
+</TR>
+<TR>
+ <TD><TT>encryption=always</TT></TD>
+ <TD>Specifies that the connection to the IPP server should be encrypted using SSL.</TD>
+</TR>
+<TR>
+ <TD><TT>encryption=ifrequested</TT></TD>
+ <TD>Specifies that the connection to the IPP server should only be encrypted if the server requests it.</TD>
+</TR>
+<TR>
+ <TD><TT>encryption=never</TT></TD>
+ <TD>Specifies that the connection to the IPP server should not be encrypted.</TD>
+</TR>
+<TR>
+ <TD><TT>encryption=required</TT></TD>
+ <TD>Specifies that the connection to the IPP server should be encrypted using TLS.</TD>
+</TR>
+<TR>
+ <TD><TT>version=1.0</TT></TD>
+ <TD>Specifies that version 1.0 of the IPP protocol should be used instead of the default version 1.1.</TD>
+</TR>
+<TR>
+ <TD><TT>version=2.0</TT></TD>
+ <TD>Specifies that version 2.0 of the IPP protocol should be used instead of the default version 1.1.</TD>
+</TR>
+<TR>
+ <TD><TT>version=2.1</TT></TD>
+ <TD>Specifies that version 2.1 of the IPP protocol should be used instead of the default version 1.1.</TD>
+</TR>
+<TR>
+ <TD><TT>waitjob=false</TT></TD>
+ <TD>Specifies that the IPP backend should not wait for the job to complete.</TD>
+</TR>
+<TR>
+ <TD><TT>waitprinter=false</TT></TD>
+ <TD>Specifies that the IPP backend should not wait for the printer to become idle before sending the print job.</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+<H3><A NAME="LPD">Line Printer Daemon (LPD) Protocol</A></H3>
+
+<P>LPD is the original network printing protocol and is supported by many network printers. Due to limitations in the LPD protocol, we do not recommend using it if the printer or server supports one of the other protocols. LPD printing normally happens over port 515 and uses the <tt>lpd</tt> URI scheme:</P>
+
+<PRE>
+lpd://<i>ip-address-or-hostname</i>/<i>queue</i>
+lpd://<i>username@ip-address-or-hostname</i>/<i>queue</i>
+lpd://<i>ip-address-or-hostname</i>/<i>queue</i>?<i>option=value</i>
+lpd://<i>username@ip-address-or-hostname</i>/<i>queue</i>?<i>option=value</i>
+lpd://<i>ip-address-or-hostname</i>/<i>queue</i>?<i>option=value&option=value</i>
+lpd://<i>username@ip-address-or-hostname</i>/<i>queue</i>?<i>option=value&option=value</i>
+</PRE>
+
+<P><A HREF="#TABLE3">Table 3</A> summarizes the options supported by the <tt>lpd</tt> backend.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="LPD URI Options">
+<CAPTION>Table 3: <A NAME="TABLE3">LPD URI Options</A></CAPTION>
+<THEAD>
+<TR>
+ <TH>Option</TH>
+ <TH>Description</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD><TT>banner=on</TT></TD>
+ <TD>Specifies that a banner page should be printed by the server.</TD>
+</TR>
+<TR>
+ <TD><TT>contimeout=<I>seconds</I></TT></TD>
+ <TD>Specifies the number of seconds to wait for the connection to the server to complete.</TD>
+</TR>
+<TR>
+ <TD><TT>format=c</TT></TD>
+ <TD>Specifies that the print data is a CIF file.</TD>
+</TR>
+<TR>
+ <TD><TT>format=d</TT></TD>
+ <TD>Specifies that the print data is a DVI file.</TD>
+</TR>
+<TR>
+ <TD><TT>format=f</TT></TD>
+ <TD>Specifies that the print data is a plain text file.</TD>
+</TR>
+<TR>
+ <TD><TT>format=g</TT></TD>
+ <TD>Specifies that the print data is a Berkeley plot file.</TD>
+</TR>
+<TR>
+ <TD><TT>format=l</TT></TD>
+ <TD>Specifies that the print data is a raw (preformatted) print file.</TD>
+</TR>
+<TR>
+ <TD><TT>format=n</TT></TD>
+ <TD>Specifies that the print data is a ditroff file.</TD>
+</TR>
+<TR>
+ <TD><TT>format=o</TT></TD>
+ <TD>Specifies that the print data is a PostScript file.</TD>
+</TR>
+<TR>
+ <TD><TT>format=p</TT></TD>
+ <TD>Specifies that the print data is a plain text file that should be "pretty" printed with a header and footer.</TD>
+</TR>
+<TR>
+ <TD><TT>format=r</TT></TD>
+ <TD>Specifies that the print data is a FORTRAN carriage control file.</TD>
+</TR>
+<TR>
+ <TD><TT>format=t</TT></TD>
+ <TD>Specifies that the print data is a troff Graphic Systems C/A/T phototypesetter file.</TD>
+</TR>
+<TR>
+ <TD><TT>format=v</TT></TD>
+ <TD>Specifies that the print data is a Sun raster file.</TD>
+</TR>
+<TR>
+ <TD><TT>order=data,control</TT></TD>
+ <TD>Specifies that the print data files should be sent before the control file.</TD>
+</TR>
+<TR>
+ <TD><TT>reserve=none</TT></TD>
+ <TD>Specifies that the backend should not reserve a source port.</TD>
+</TR>
+<TR>
+ <TD><TT>reserve=rfc1179</TT></TD>
+ <TD>Specifies that the backend should reserve a source port from 721 to 731 as required by RFC 1179.</TD>
+</TR>
+<TR>
+ <TD><TT>sanitize_title=no</TT></TD>
+ <TD>Specifies that the job title string should not be restricted to ASCII characters.</TD>
+</TR>
+<TR>
+ <TD><TT>sanitize_title=yes</TT></TD>
+ <TD>Specifies that the job title string should be restricted to ASCII characters.</TD>
+</TR>
+<TR>
+ <TD><TT>timeout=<I>seconds</I></TT></TD>
+ <TD>Specifies the number of seconds to wait for LPD commands to complete.</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+
+<H3><A NAME="URI">Common Network Printer URIs</A></H3>
+
+<P>Once you have set the IP address you can access the printer or print server using the <TT>ipp</TT>, <TT>lpd</TT>, or <TT>socket</TT> backends. <A HREF="#TABLE1">Table 1</A> shows a list of common network interfaces and printer servers and the settings you should use with CUPS:</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="Common Device URIs">
+<CAPTION>Table 1: <A NAME="TABLE1">Common Device URIs</A></CAPTION>
+<THEAD>
+<TR>
+ <TH>Model/Manufacturer</TH>
+ <TH>Device URI(s)</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD>Apple LaserWriter</TD>
+ <TD>lpd://<I>address</I>/PASSTHRU</TD>
+</TR>
+<TR>
+ <TD>Axis w/o IPP<BR>
+ Axis OfficeBasic<BR>
+ <A HREF="#AXIS">(see directions)</A></TD>
+ <TD>socket://<I>address</I>:9100<BR>
+ socket://<I>address</I>:9101<BR>
+ socket://<I>address</I>:9102</TD>
+</TR>
+<TR>
+ <TD>Axis w/IPP</TD>
+ <TD>ipp://<I>address</I>/LPT1<BR>
+ ipp://<I>address</I>/LPT2<BR>
+ ipp://<I>address</I>/COM1</TD>
+</TR>
+<TR>
+ <TD>Castelle LANpress<SUP>TM</SUP></TD>
+ <TD>lpd://<I>address</I>/pr1<BR>
+ lpd://<I>address</I>/pr2<BR>
+ lpd://<I>address</I>/pr3</TD>
+</TR>
+<TR>
+ <TD>DPI NETPrint</TD>
+ <TD>lpd://<I>address</I>/pr1<BR>
+ lpd://<I>address</I>/pr2<BR>
+ lpd://<I>address</I>/pr3</TD>
+</TR>
+<TR>
+ <TD>DLink DP-301P+</TD>
+ <TD>socket://<I>address</I></TD>
+</TR>
+<TR>
+ <TD>EFI&reg; Fiery&reg; RIP</TD>
+ <TD>lpd://<I>address</I>/print</TD>
+</TR>
+<TR>
+ <TD>EPSON&reg; Multiprotocol Ethernet Interface Board</TD>
+ <TD>socket://<I>address</I></TD>
+</TR>
+<TR>
+ <TD>Extended System ExtendNET</TD>
+ <TD>lpd://<I>address</I>/pr1<BR>
+ lpd://<I>address</I>/pr2<BR>
+ lpd://<I>address</I>/pr3</TD>
+</TR>
+<TR>
+ <TD>Hewlett Packard JetDirect</TD>
+ <TD>socket://<I>address</I>:9100<BR>
+ socket://<I>address</I>:9101<BR>
+ socket://<I>address</I>:9102</TD>
+</TR>
+<TR>
+ <TD>Intel&reg; NetportExpress XL, PRO/100</TD>
+ <TD>lpd://<I>address</I>/LPT1_PASSTHRU<BR>
+ lpd://<I>address</I>/LPT2_PASSTHRU<BR>
+ lpd://<I>address</I>/COM1_PASSTHRU</TD>
+</TR>
+<TR>
+ <TD>Lexmark<SUP>TM</SUP> MarkNet</TD>
+ <TD>lpd://<I>address</I>/ps</TD>
+</TR>
+<TR>
+ <TD>Linksys EtherFast&reg;<BR>
+ <A HREF="#LINKSYS">(see directions)</A></TD>
+ <TD>socket://<I>address</I>:4010<BR>
+ socket://<I>address</I>:4020<BR>
+ socket://<I>address</I>:4030</TD>
+</TR>
+<TR>
+ <TD>Linksys PSUS4</TD>
+ <TD>lpd://<I>address</I>/lp</TD>
+</TR>
+<TR>
+ <TD>Kodak&reg;</TD>
+ <TD>lpd://<I>address</I>/ps</TD>
+</TR>
+<TR>
+ <TD>Netgear WGPS606</TD>
+ <TD>lpd://<I>address</I>/L1<BR>
+ lpd://<I>address</I>/L2</TD>
+</TR>
+<TR>
+ <TD>QMS&reg; CrownNet<SUP>TM</SUP></TD>
+ <TD>lpd://<I>address</I>/ps</TD>
+</TR>
+<TR>
+ <TD>Tektronix&reg; PhaserShare<SUP>TM</SUP></TD>
+ <TD>socket://<I>address</I>:9100</TD>
+</TR>
+<TR>
+ <TD>XEROX&reg; 4512 NIC</TD>
+ <TD>lpd://<I>address</I>/PORT1</TD>
+</TR>
+<TR>
+ <TD>XEROX&reg; XNIC</TD>
+ <TD>lpd://<I>address</I>/PASSTHRU</TD>
+</TR>
+<TR>
+ <TD>XEROX&reg; (most others)</TD>
+ <TD>socket://<I>address</I>:5503</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+
+<H2 CLASS="title"><A NAME="SNMP">Troubleshooting SNMP Discovery Problems</A></H2>
+
+<P>Whenever you view the administration web page or a list of supported device URIs, the <tt>snmp</tt> backend will probe the local network(s) using Simple Network Management Protocol (SNMP) broadcasts. Printers that respond to these broadcasts are then interrogated for the make and model and supported protocols, yielding a device URI that can be used to add the printer.</P>
+
+<P>That said, the SNMP requests sometimes expose problems in vendor SNMP or IPP implementations. If you are experiencing long delays in loading the CUPS web interface administration page, or if you don't see your printer listed, the following instructions will help you to diagnose those problems and/or provide important feedback to the CUPS developers so that we can correct problems and improve the SNMP backend in future releases.</P>
+
+<H3>Quick Fixes</H3>
+
+<P>If you don't use "public" as your community name, create a text file called <VAR>/etc/cups/snmp.conf</VAR> and put the following line in it:</P>
+
+<PRE CLASS="command">
+Community <I>your community name</I>
+</PRE>
+
+<P>If you have more than one community name, list them all on separate lines.</P>
+
+<P>If you don't support SNMP v1 on your network, you are currently "out of luck". That said, we will be adding v2, v2c, and v3 support in future CUPS releases once we have a handle on the actual requirements people have for such things. Please file or update an <A HREF="http://www.cups.org/str.php">SNMP enhancement request</A> with <em>specific</em> requirements you have - what you need supported, why you need it supported, and how you would like to see the functionality provided/exposed - so that we can do it "right" the first time.</P>
+
+<H3>Basic Debugging</H3>
+
+<P>The SNMP backend supports a debugging mode that is activated by running it from a shell prompt. If you are using Bash (/bin/bash), Bourne shell (/bin/sh), Korn shell (/bin/ksh), or Z shell (/bin/zsh), you can run the following command to get a verbose log of the SNMP backend:</P>
+
+<PRE CLASS="command">
+CUPS_DEBUG_LEVEL=2 /usr/lib/cups/backend/snmp 2>&amp;1 | tee snmp.log
+</PRE>
+
+<P>For C shell (/bin/csh) and TCsh (/bin/tcsh), use the following command instead:</P>
+
+<PRE CLASS="command">
+(setenv CUPS_DEBUG_LEVEL 2; /usr/lib/cups/backend/snmp) |& tee snmp.log
+</PRE>
+
+<P>On MacOS X you'll find the SNMP backend in /usr/libexec/cups/backend instead:</P>
+
+<PRE CLASS="command">
+CUPS_DEBUG_LEVEL=2 /usr/libexec/cups/backend/snmp 2>&amp;1 | tee snmp.log
+</PRE>
+
+<P>The output will look something like this:</P>
+
+<PRE STYLE="margin-left: 36pt">
+ 1 INFO: Using default SNMP Address @LOCAL
+ 2 INFO: Using default SNMP Community public
+ 3 DEBUG: Scanning for devices in "public" via "@LOCAL"...
+ 4 DEBUG: 0.000 Sending 46 bytes to 192.168.2.255...
+ 5 DEBUG: SEQUENCE 44 bytes
+ 6 DEBUG: INTEGER 1 bytes 0
+ 7 DEBUG: OCTET STRING 6 bytes "public"
+ 8 DEBUG: Get-Request-PDU 31 bytes
+ 9 DEBUG: INTEGER 4 bytes 1149539174
+10 DEBUG: INTEGER 1 bytes 0
+11 DEBUG: INTEGER 1 bytes 0
+12 DEBUG: SEQUENCE 17 bytes
+13 DEBUG: SEQUENCE 15 bytes
+14 DEBUG: OID 11 bytes .1.3.6.1.2.1.25.3.2.1.2.1
+15 DEBUG: NULL VALUE 0 bytes
+16 DEBUG: 0.001 Received 55 bytes from 192.168.2.229...
+17 DEBUG: community="public"
+18 DEBUG: request-id=1149539174
+19 DEBUG: error-status=0
+20 DEBUG: SEQUENCE 53 bytes
+21 DEBUG: INTEGER 1 bytes 0
+22 DEBUG: OCTET STRING 6 bytes "public"
+23 DEBUG: Get-Response-PDU 40 bytes
+24 DEBUG: INTEGER 4 bytes 1149539174
+25 DEBUG: INTEGER 1 bytes 0
+26 DEBUG: INTEGER 1 bytes 0
+27 DEBUG: SEQUENCE 26 bytes
+28 DEBUG: SEQUENCE 24 bytes
+29 DEBUG: OID 11 bytes .1.3.6.1.2.1.25.3.2.1.2.1
+30 DEBUG: OID 9 bytes .1.3.6.1.2.1.25.3.1.5
+31 DEBUG: add_cache(addr=0xbfffe170, addrname="192.168.2.229",
+ uri="(null)", id="(null)", make_and_model="(null)")
+32 DEBUG: 0.002 Sending 46 bytes to 192.168.2.229...
+33 DEBUG: SEQUENCE 44 bytes
+34 DEBUG: INTEGER 1 bytes 0
+35 DEBUG: OCTET STRING 6 bytes "public"
+36 DEBUG: Get-Request-PDU 31 bytes
+37 DEBUG: INTEGER 4 bytes 1149539175
+38 DEBUG: INTEGER 1 bytes 0
+39 DEBUG: INTEGER 1 bytes 0
+40 DEBUG: SEQUENCE 17 bytes
+41 DEBUG: SEQUENCE 15 bytes
+42 DEBUG: OID 11 bytes .1.3.6.1.2.1.25.3.2.1.3.1
+43 DEBUG: NULL VALUE 0 bytes
+44 DEBUG: 0.003 Received 69 bytes from 192.168.2.229...
+45 DEBUG: community="public"
+46 DEBUG: request-id=1149539175
+47 DEBUG: error-status=0
+48 DEBUG: SEQUENCE 67 bytes
+49 DEBUG: INTEGER 1 bytes 0
+50 DEBUG: OCTET STRING 6 bytes "public"
+51 DEBUG: Get-Response-PDU 54 bytes
+52 DEBUG: INTEGER 4 bytes 1149539175
+53 DEBUG: INTEGER 1 bytes 0
+54 DEBUG: INTEGER 1 bytes 0
+55 DEBUG: SEQUENCE 40 bytes
+56 DEBUG: SEQUENCE 38 bytes
+57 DEBUG: OID 11 bytes .1.3.6.1.2.1.25.3.2.1.3.1
+58 DEBUG: OCTET STRING 23 bytes "HP LaserJet 4000
+ Series"
+59 DEBUG: 1.001 Probing 192.168.2.229...
+60 DEBUG: 1.001 Trying socket://192.168.2.229:9100...
+61 DEBUG: 192.168.2.229 supports AppSocket!
+62 DEBUG: 1.002 Scan complete!
+63 network socket://192.168.2.229 "HP LaserJet 4000 Series"
+ "HP LaserJet 4000 Series 192.168.2.229" ""
+</PRE>
+
+<H3>Dissecting the Output</H3>
+
+<P>The first two lines are just informational and let you know that the default community name and address are being used. Lines 3-15 contain the initial SNMP query for the device type OID (.1.3.6.1.2.1.25.3.2.1.2.1) from the Host MIB.</P>
+
+<P>Lines 16-31 show the response we got from an HP LaserJet 4000 network printer. At this point we discover that it is a printer device and then send another SNMP query (lines 32-43) for the device description OID (.1.3.6.1.2.1.25.3.2.1.3.1) from the Host MIB as well.</P>
+
+<P>Lines 44-58 show the response to the device description query, which tells us that this is an HP LaserJet 4000 Series printer.</P>
+
+<P>On line 59 we start our active connection probe and discover that this print server supports the AppSocket (JetDirect) protocol on port 9100.</P>
+
+<P>Finally, line 63 shows the device information line for the print server that is sent to CUPS.</P>
+
+<H3>Reporting Problems</H3>
+
+If you don't see your printer listed, or the wrong information is listed, then you need to gather more information on the printer. The easiest way to do this is to run the snmpwalk command:
+
+<PRE CLASS="command">
+snmpwalk -Cc -v 1 -c public <I>ip-address</I> | tee snmpwalk.log
+</PRE>
+
+<P>where "ip-address" is the IP address of the printer or print server. You should see a <em>lot</em> of values stream by - the ones you want to see are:</P>
+
+<PRE STYLE="margin-left: 36pt">
+HOST-RESOURCES-MIB::hrDeviceType.1 = OID: HOST-RESOURCES-TYPES::hrDevicePrinter
+HOST-RESOURCES-MIB::hrDeviceDescr.1 = STRING: HP LaserJet 4000 Series
+</PRE>
+
+<P>The hrDeviceType line should show hrDevicePrinter; if not, then your printer or print server doesn't identify itself as a printer. The hrDeviceDescr line should provide a human-readable string for the make and model of the printer, although in some cases you'll just see something less useful like "Axis OfficeBASIC Parallel Print Server".</P>
+
+<P>Once you have collected the snmpwalk output, you should go to the <A HREF="http://www.cups.org/str.php">CUPS Bugs &amp; Features page</A> to submit a feature request to support your printer or print server. Be sure to attach those two log files you created - they will help us to identify the SNMP values we need to look for.</P>
+
+
+<H2 CLASS="title"><A NAME="SERVERS">Configuring Print Servers</A></H2>
+
+<H3><A NAME="AXIS">Configuring Axis Print Servers</A></H3>
+
+<P>The Axis print servers can be configured using BOOTP or DHCP. However, on models that do not provide IPP support an additional step must be performed to configure the TCP/IP portion of the print server for use with CUPS.</P>
+
+<P>Each print server contains a configuration file named <VAR>config</VAR> that contains a list of network parameters used by the server. To modify this file you must first download it from the print server using the <TT>ftp(1)</TT> program:</P>
+
+<PRE CLASS="command">
+<KBD>ftp ip-address</KBD>
+Connected to ip-address.
+220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
+ftp> <KBD>user root</KBD>
+331 User name ok, need password
+Password: <KBD>pass</KBD> <I>(this is not echoed)</I>
+230 User logged in
+ftp> <KBD>get config</KBD>
+local: config remote: config
+200 PORT command successful.
+150 Opening data connection for config (192,0,2,2),
+(mode ascii).
+226 Transfer complete.
+##### bytes received in #.## seconds (##### Kbytes/s)
+ftp> <KBD>quit</KBD>
+221 Goodbye.
+</PRE>
+
+<P>Next, edit the file with your favorite text editor and locate the lines beginning with:</P>
+
+<PRE CLASS="command">
+RTN_OPT. : YES
+RTEL_PR1. : 0
+RTEL_PR2. : 0
+RTEL_PR3. : 0
+RTEL_PR4. : 0
+RTEL_PR5. : 0
+RTEL_PR6. : 0
+RTEL_PR7. : 0
+RTEL_PR8. : 0
+</PRE>
+
+<P>Change the <TT>RTN_OPT</TT> line to read:</P>
+
+<PRE CLASS="command">
+RTN_OPT. : <KBD>NO</KBD>
+</PRE>
+
+<P>This disables the Reverse TELNET protocol and enables the standard TELNET protocol on the print server. Next, assign a port number for each parallel and serial port on the server as follows:</P>
+
+<PRE CLASS="command">
+RTEL_PR1. : <KBD>9100</KBD>
+RTEL_PR2. : <KBD>9101</KBD>
+RTEL_PR3. : <KBD>9102</KBD>
+RTEL_PR4. : <KBD>9103</KBD>
+RTEL_PR5. : <KBD>9104</KBD>
+RTEL_PR6. : <KBD>9105</KBD>
+RTEL_PR7. : <KBD>9106</KBD>
+RTEL_PR8. : <KBD>9107</KBD>
+</PRE>
+
+<P>This essentially makes the Axis print server look like a Hewlett Packard JetDirect EX print server. Save the file and then upload the new <VAR>config</VAR> file using the <TT>ftp</TT> command:</P>
+
+<PRE CLASS="command">
+<KBD>ftp ip-address</KBD>
+Connected to ip-address.
+220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
+ftp> <KBD>user root</KBD>
+331 User name ok, need password
+Password: <KBD>pass</KBD> <I>(this is not echoed)</I>
+230 User logged in
+ftp> <KBD>put config CONFIG</KBD>
+local: config remote: CONFIG
+200 PORT command successful.
+150 Opening data connection for config (192,0,2,2), (mode ascii).
+226 Transfer complete.
+##### bytes received in #.## seconds (##### Kbytes/s)
+ftp> <KBD>get hardreset</KBD>
+local: hardreset remote: hardreset
+200 PORT command successful.
+421 Axis NPS ### hard reset, closing connection.
+ftp> <KBD>quit</KBD>
+221 Goodbye.
+</PRE>
+
+<P>Your Axis print server is now ready for use!</P>
+
+<H3><A NAME="LINKSYS">Configuring Linksys Print Servers</A></H3>
+
+<P>The Linksys print servers can be configured using BOOTP or DHCP. Like older Axis print servers, an additional step must be performed to configure the TCP/IP portion of the print server for use with CUPS.</P>
+
+<P>Each print server contains a configuration file named <VAR>CONFIG</VAR> that contains a list of network parameters used by the server. To modify this file you must first download it from the print server using the <TT>ftp(1)</TT> program:</P>
+
+<PRE CLASS="command">
+<KBD>ftp -n ip-address</KBD>
+Connected to ip-address.
+220 Print Server Ready.
+Remote system type is Print.
+ftp> <KBD>get CONFIG</KBD>
+local: CONFIG remote: CONFIG
+200 Command OK.
+150 Open ASCII Mode Connection.
+WARNING! 68 bare linefeeds received in ASCII mode
+File may not have transferred correctly.
+226 Transfer complete.
+##### bytes received in #.## seconds (##### Kbytes/s)
+ftp> <KBD>quit</KBD>
+221 Goodbye.
+</PRE>
+
+<P>Next, edit the file with your favorite text editor and locate the lines beginning with:</P>
+
+<PRE CLASS="command">
+0100 L1_PROUT:P1
+0120 L2_PROUT:P1
+0140 L3_PROUT:P1
+</PRE>
+
+<P>Change the port number for each parallel and serial port on the server as follows:</P>
+
+<PRE CLASS="command">
+0100 L1_PROUT:<KBD>P1</KBD>
+0120 L2_PROUT:<KBD>P2</KBD>
+0140 L3_PROUT:<KBD>P3</KBD>
+</PRE>
+
+<P>This maps each virtual printer with a physical port. Save the file and then upload the new <VAR>CONFIG</VAR> file using the <TT>ftp</TT> command:</P>
+
+<PRE CLASS="command">
+<KBD>ftp -n ip-address</KBD>
+Connected to ip-address.
+220 Print Server Ready.
+Remote system type is Print.
+ftp> <KBD>put CONFIG</KBD>
+local: CONFIG remote: CONFIG
+200 Command OK.
+150 Open ASCII Mode Connection.
+226 Transfer complete.
+##### bytes received in #.## seconds (##### Kbytes/s)
+ftp> <KBD>quit</KBD>
+221 Goodbye.
+</PRE>
+
+<P>Your Linksys print server is now ready for use!</P>
+
+</BODY>
+</HTML>
diff --git a/doc/help/options.html b/doc/help/options.html
new file mode 100644
index 000000000..0cfa74135
--- /dev/null
+++ b/doc/help/options.html
@@ -0,0 +1,778 @@
+<HTML>
+<!-- SECTION: Getting Started -->
+<HEAD>
+ <TITLE>Command-Line Printing and Options</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">Command-Line Printing and Options</H1>
+
+<P>CUPS provides both the System V (<A
+HREF="man-lp.html">lp(1)</A>) and Berkeley (<A
+HREF="man-lpr.html">lpr(1)</A>) printing commands for printing
+files. In addition, it supported a large number of standard and
+printer-specific options that allow you to control how and where
+files are printed.</P>
+
+
+<H2 CLASS="title"><A NAME="BASICS">Printing Files</A></H2>
+
+<P>CUPS understands many different types of files directly,
+including text, PostScript, PDF, and image files. This allows you
+to print from inside your applications or at the command-line,
+whichever is most convenient! Type either of the following
+commands to print a file to the default (or only) printer on the
+system:</P>
+
+<PRE CLASS="command">
+lp filename
+lpr filename
+</PRE>
+
+<H3><A NAME="PRINTER">Choosing a Printer</A></H3>
+
+<P>Many systems will have more than one printer available to the
+user. These printers can be attached to the local system via a
+parallel, serial, or USB port, or available over the network. Use
+the <A HREF="man-lpstat.html">lpstat(1)</A> command to see a list
+of available printers:</P>
+
+<PRE CLASS="command">
+lpstat -p -d
+</PRE>
+
+<P>The <CODE>-p</CODE> option specifies that you want to see a
+list of printers, and the <CODE>-d</CODE> option reports the
+current default printer or class.</P>
+
+<P>Use the <CODE>-d</CODE> option with the <B>lp</B> command to
+print to a specific printer:</P>
+
+<PRE CLASS="command">
+lp -d printer filename
+</PRE>
+
+<P>or the <CODE>-P</CODE> option with the <B>lpr</B> command:</P>
+
+<PRE CLASS="command">
+lpr -P printer filename
+</PRE>
+
+<H3><A NAME="DEFAULT">Setting the Default Printer</A></H3>
+
+<P>If you normally use a particular printer, you can tell CUPS to
+use it by default using the <A
+HREF="man-lpoptions.html">lpoptions(1)</A> command:</P>
+
+<PRE CLASS="command">
+lpoptions -d printer
+</PRE>
+
+<H3><A NAME="PIPE">Printing the Output of a Program</A></H3>
+
+<P>Both the <B>lp</B> and <B>lpr</B> commands support printing
+from the standard input:</P>
+
+<PRE CLASS="command">
+program | lp
+program | lp -d printer
+program | lpr
+program | lpr -P printer
+</PRE>
+
+<P>If the program does not provide any output, then nothing will
+be queued for printing.</P>
+
+<H3><A NAME="WITHOPTIONS">Specifying Printer Options</A></H3>
+
+<P>For many types of files, the default printer options may be
+sufficient for your needs. However, there may be times when you
+need to change the options for a particular file you are
+printing.</P>
+
+<P>The <B>lp</B> and <B>lpr</B> commands allow you to pass
+printer options using the <CODE>-o</CODE> option:</P>
+
+<PRE CLASS="command">
+lp -o landscape -o scaling=75 -o media=A4 filename.jpg
+lpr -o landscape -o scaling=75 -o media=A4 filename.jpg
+</PRE>
+
+<P>The available printer options vary depending on the printer.
+The standard options are described in the "<A
+HREF="#OPTIONS">Standard Printing Options</A>" section
+below. Printer-specific options are also available and can be
+listed using the <B>lpoptions</B> command:</P>
+
+<PRE CLASS="command">
+lpoptions -p printer -l
+</PRE>
+
+<H3><A NAME="INSTANCES">Creating Saved Options</A></H3>
+
+<P>Saved options are supported in CUPS through <em>printer
+instances</em>. Printer instances are, as their name implies, copies
+of a printer that have certain options associated with them. Use the
+<B>lpoptions</B> command to create a printer instance:</P>
+
+<PRE CLASS="command">
+lpoptions -p printer/instance -o name=value ...
+</PRE>
+
+<P>The <CODE>-p printer/instance</CODE> option provides the name of
+the instance, which is always the printer name, a slash, and the
+instance name which can contain any printable characters except
+space and slash. The remaining options are then associated with the
+instance instead of the main queue. For example, the following
+command creates a duplex instance of the LaserJet queue:</P>
+
+<PRE CLASS="command">
+lpoptions -p LaserJet/duplex -o sides=two-sided-long-edge
+</PRE>
+
+<P>Instances <em>do not</em> inherit lpoptions from the main
+queue.</P>
+
+<H3><A NAME="COPIES">Printing Multiple Copies</A></H3>
+
+<P>Both the <B>lp</B> and <B>lpr</B> commands have options for
+printing more than one copy of a file:</P>
+
+<PRE CLASS="command">
+lp -n <EM>num-copies</EM> filename
+lpr -#<EM>num-copies</EM> filename
+</PRE>
+
+<P>Copies are normally <EM>not</EM> collated for you. Use the
+<CODE>-o Collate=True</CODE> option to get collated copies:</P>
+
+<PRE CLASS="command">
+lp -n <EM>num-copies</EM> -o Collate=True filename
+lpr -#<EM>num-copies</EM> -o Collate=True filename
+</PRE>
+
+
+<H2 CLASS="title"><A NAME="CANCEL">Canceling a Print Job</A></H2>
+
+<P>The <A HREF="man-cancel.html">cancel(1)</A> and <A
+HREF="man-lprm.html">lprm(1)</A> commands cancel a print job:</P>
+
+<PRE CLASS="command">
+cancel <EM>job-id</EM>
+lprm <EM>job-id</EM>
+</PRE>
+
+<P>The <EM>job-id</EM> is the number that was reported to you by
+the <B>lp</B> command. You can also get the job ID using the <A
+HREF="man-lpq.html">lpq(1)</A> or <A
+HREF="man-lpstat.html">lpstat</A> commands:</P>
+
+<PRE CLASS="command">
+lpq
+lpstat
+</PRE>
+
+
+<H2 CLASS="title"><A NAME="LPMOVE">Moving a Print Job</A></H2>
+
+<P>The <A HREF="man-lpmove.html">lpmove(8)</A> command moves a print
+job to a new printer or class:</P>
+
+<PRE CLASS="command">
+lpmove <EM>job-id</EM> <i>destination</i>
+</PRE>
+
+<P>The <EM>job-id</EM> is the number that was reported to you by
+the <B>lp</B> or <B>lpstat</B> commands. <i>Destination</i> is the
+name of a printer or class that you want to actually print the job.
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>The <B>lpmove</B> command is located in the system command
+directory (typically <VAR>/usr/sbin</VAR> or <VAR>/usr/local/sbin</VAR>),
+and so may not be in your command path. Specify the full path to the
+command if you get a "command not found" error, for example:
+
+<PRE CLASS="command">
+/usr/sbin/lpmove foo-123 bar
+</PRE>
+
+</BLOCKQUOTE>
+
+
+<H2 CLASS="title"><A NAME="OPTIONS">Standard Printing Options</A></H2>
+
+<P>The following options apply when printing all types of
+files.</P>
+
+<H3><A NAME="MEDIA">Selecting the Media Size, Type, and Source</A></H3>
+
+<P>The <CODE>-o media=xyz</CODE> option sets the media size,
+type, and/or source:</P>
+
+<PRE CLASS="command">
+lp -o media=Letter filename
+lp -o media=Letter,MultiPurpose filename
+lpr -o media=Letter,Transparency filename
+lpr -o media=Letter,MultiPurpose,Transparency filename
+</PRE>
+
+<P>The available media sizes, types, and sources depend on the
+printer, but most support the following options (case is not
+significant):</P>
+
+<UL>
+
+ <LI><CODE>Letter</CODE> - US Letter (8.5x11 inches, or 216x279mm)
+
+ <LI><CODE>Legal</CODE> - US Legal (8.5x14 inches, or 216x356mm)
+
+ <LI><CODE>A4</CODE> - ISO A4 (8.27x11.69 inches, or 210x297mm)
+
+ <LI><CODE>COM10</CODE> - US #10 Envelope (9.5x4.125 inches, or
+ 241x105mm)
+
+ <LI><CODE>DL</CODE> - ISO DL Envelope (8.66x4.33 inches, or 220x110mm)
+
+ <LI><CODE>Transparency</CODE> - Transparency media type or source
+
+ <LI><CODE>Upper</CODE> - Upper paper tray
+
+ <LI><CODE>Lower</CODE> - Lower paper tray
+
+ <LI><CODE>MultiPurpose</CODE> - Multi-purpose paper tray
+
+ <LI><CODE>LargeCapacity</CODE> - Large capacity paper tray
+
+</UL>
+
+<P>The actual options supported are defined in the printer's PPD
+file in the <CODE>PageSize</CODE>, <CODE>InputSlot</CODE>, and
+<CODE>MediaType</CODE> options. You can list them using the
+<B>lpoptions(1)</B> command:</P>
+
+<PRE CLASS="command">
+lpoptions -p printer -l
+</PRE>
+
+<P>When <CODE>Custom</CODE> is listed for the <CODE>PageSize</CODE> option, you can specify custom media sizes using one of the following forms:</P>
+
+<PRE CLASS="command">
+lp -o media=Custom.<EM>WIDTH</EM>x<EM>LENGTH</EM> filename
+lp -o media=Custom.<EM>WIDTH</EM>x<EM>LENGTH</EM>in filename
+lp -o media=Custom.<EM>WIDTH</EM>x<EM>LENGTH</EM>cm filename
+lp -o media=Custom.<EM>WIDTH</EM>x<EM>LENGTH</EM>mm filename
+</PRE>
+
+<P>where "WIDTH" and "LENGTH" are the width and length of the media in points, inches, centimeters, or millimeters, respectively.</P>
+
+
+<H3><A NAME="ORIENTATION">Setting the Orientation</A></H3>
+
+<P>The <CODE>-o landscape</CODE> option will rotate the page 90
+degrees to print in landscape orientation:</P>
+
+<PRE CLASS="command">
+lp -o landscape filename
+lpr -o landscape filename
+</PRE>
+
+<P>The <CODE>-o orientation-requested=N</CODE> option rotates the
+page depending on the value of N:</P>
+
+<UL>
+
+ <LI><CODE>-o orientation-requested=3</CODE> - portrait
+ orientation (no rotation)</LI>
+
+ <LI><CODE>-o orientation-requested=4</CODE> - landscape
+ orientation (90 degrees)</LI>
+
+ <LI><CODE>-o orientation-requested=5</CODE> - reverse
+ landscape or seascape orientation (270 degrees)</LI>
+
+ <LI><CODE>-o orientation-requested=6</CODE> - reverse
+ portrait or upside-down orientation (180 degrees)</LI>
+
+</UL>
+
+
+<H3><A NAME="SIDES">Printing On Both Sides of the Paper</A></H3>
+
+<P>The <CODE>-o sides=two-sided-short-edge</CODE> and <CODE>-o
+sides=two-sided-long-edge</CODE> options will enable two-sided
+printing on the printer if the printer supports it. The <CODE>-o
+sides=two-sided-short-edge</CODE> option is suitable for
+landscape pages, while the <CODE>-o
+sides=two-sided-long-edge</CODE> option is suitable for portrait
+pages:</P>
+
+<PRE CLASS="command">
+lp -o sides=two-sided-short-edge filename
+lp -o sides=two-sided-long-edge filename
+lpr -o sides=two-sided-long-edge filename
+</PRE>
+
+<P>The default is to print single-sided:</P>
+
+<PRE CLASS="command">
+lp -o sides=one-sided filename
+lpr -o sides=one-sided filename
+</PRE>
+
+
+<H3><A NAME="JOBSHEETS">Selecting the Banner Page(s)</A></H3>
+
+<P>The <CODE>-o job-sheets=start,end</CODE> option sets the banner
+page(s) to use for a job:</P>
+
+<PRE CLASS="command">
+lp -o job-sheets=none filename
+lp -o job-sheets=standard filename
+lpr -o job-sheets=classified,classified filename
+</PRE>
+
+<P>If only one banner file is specified, it will be printed
+before the files in the job. If a second banner file is
+specified, it is printed after the files in the job.</P>
+
+<P>The available banner pages depend on the local system
+configuration; CUPS includes the following banner files:</P>
+
+<UL>
+
+ <LI><CODE>none</CODE> - Do not produce a banner page.
+
+ <LI><CODE>classified</CODE> - A banner page with a "classified"
+ label at the top and bottom.
+
+ <LI><CODE>confidential</CODE> - A banner page with a
+ "confidential" label at the top and bottom.
+
+ <LI><CODE>secret</CODE> - A banner page with a "secret" label
+ at the top and bottom.
+
+ <LI><CODE>standard</CODE> - A banner page with no label at the
+ top and bottom.
+
+ <LI><CODE>topsecret</CODE> - A banner page with a "top secret"
+ label at the top and bottom.
+
+ <LI><CODE>unclassified</CODE> - A banner page with an
+ "unclassified" label at the top and bottom.
+
+</UL>
+
+
+<H3><A NAME="JOBHOLDUNTIL">Holding Jobs for Later Printing</A></H3>
+
+<P>The <CODE>-o job-hold-until=when</CODE> option tells CUPS to
+delay printing until the "when" time, which can be one of the
+following:</P>
+
+<UL>
+
+ <LI><CODE>-o job-hold-until=indefinite</CODE>; print only
+ after released by the user or an administrator</LI>
+
+ <LI><CODE>-o job-hold-until=day-time</CODE>; print from
+ 6am to 6pm local time</LI>
+
+ <LI><CODE>-o job-hold-until=night</CODE>; print from
+ 6pm to 6am local time</LI>
+
+ <LI><CODE>-o job-hold-until=second-shift</CODE>; print from
+ 4pm to 12am local time</LI>
+
+ <LI><CODE>-o job-hold-until=third-shift</CODE>; print from
+ 12am to 8am local time</LI>
+
+ <LI><CODE>-o job-hold-until=weekend</CODE>; print on Saturday
+ or Sunday</LI>
+
+ <LI><CODE>-o job-hold-until=HH:MM</CODE>; print at the specified
+ UTC time</LI>
+
+</UL>
+
+<H3><A NAME="RELEASEJOB">Releasing Held Jobs</A></H3>
+
+<P>Aside from the web interface, you can use the <B>lp</B> command
+to release a held job:</P>
+
+<PRE CLASS="command">
+lp -i <em>job-id</em> -H resume
+</PRE>
+
+<P>where "job-id" is the job ID reported by the <B>lpstat</B>
+command.</P>
+
+
+<H3><A NAME="JOBPRIORITY">Setting the Job Priority</A></H3>
+
+<P>The <CODE>-o job-priority=NNN</CODE> option tells CUPS to
+assign a priority to your job from 1 (lowest) to 100 (highest),
+which influences where the job appears in the print queue. Higher
+priority jobs are printed before lower priority jobs, however
+submitting a new job with a high priority will not interrupt an
+already printing job.</P>
+
+
+<H3><A NAME="OUTPUTORDER">Specifying the Output Order</A></H3>
+
+<P>The <CODE>-o outputorder=normal</CODE> and <CODE>-o outputorder=reverse</CODE> options specify the order of the pages. Normal order prints page 1 first, page 2 second, and so forth. Reverse order prints page 1 last.</P>
+
+
+<H3><A NAME="PAGERANGES">Selecting a Range of Pages</A></H3>
+
+<P>The <CODE>-o page-ranges=pages</CODE> option selects a range
+of pages for printing:</P>
+
+<PRE CLASS="command">
+lp -o page-ranges=1 filename
+lp -o page-ranges=1-4 filename
+lp -o page-ranges=1-4,7,9-12 filename
+lpr -o page-ranges=1-4,7,9-12 filename
+</PRE>
+
+<P>As shown above, the <CODE>pages</CODE> value can be a single page, a
+range of pages, or a collection of page numbers and ranges separated by
+commas. The pages will always be printed in ascending order, regardless
+of the order of the pages in the <CODE>page-ranges</CODE> option.
+
+<P>The default is to print all pages.
+
+<blockquote><b>Note:</b>
+
+<p>The page numbers used by <code>page-ranges</code> refer to the output
+pages and not the document's page numbers. Options like <code>number-up</code>
+can make the output page numbering not match the document page numbers.</p>
+
+</blockquote>
+
+
+<H3><A NAME="PAGESET">Selecting Even or Odd Pages</A></H3>
+
+<P>Use the <CODE>-o page-set=set</CODE> option to select the even or odd pages:</P>
+
+<PRE CLASS="command">
+lp -o page-set=odd filename
+lp -o page-set=even filename
+lpr -o page-set=even filename
+</PRE>
+
+<P>The default is to print all pages.
+
+<H3><A NAME="NUMBERUP">N-Up Printing</A></H3>
+
+<P>The <CODE>-o number-up=value</CODE> option selects N-Up
+printing. N-Up printing places multiple document pages on a
+single printed page. CUPS supports 1, 2, 4, 6, 9, and 16-Up
+formats; the default format is 1-Up:</P>
+
+<PRE CLASS="command">
+lp -o number-up=1 filename
+lp -o number-up=2 filename
+lp -o number-up=4 filename
+lpr -o number-up=16 filename
+</PRE>
+
+<P>The <CODE>-o page-border=value</CODE> option chooses the
+border to draw around each page:</P>
+
+<UL>
+ <LI><CODE>-o page-border=double</CODE>; draw two hairline borders around each page</LI>
+ <LI><CODE>-o page-border=double-thick</CODE>; draw two 1pt borders around each page</LI>
+ <LI><CODE>-o page-border=none</CODE>; do not draw a border (default)</LI>
+ <LI><CODE>-o page-border=single</CODE>; draw one hairline border around each page</LI>
+ <LI><CODE>-o page-border=single-thick</CODE>; draw one 1pt border around each page</LI>
+</UL>
+
+<P>The <CODE>-o number-up-layout=value</CODE> option chooses the
+layout of the pages on each output page:</P>
+
+<UL>
+ <LI><CODE>-o number-up-layout=btlr</CODE>; Bottom to top, left to right</LI>
+ <LI><CODE>-o number-up-layout=btrl</CODE>; Bottom to top, right to left</LI>
+ <LI><CODE>-o number-up-layout=lrbt</CODE>; Left to right, bottom to top</LI>
+ <LI><CODE>-o number-up-layout=lrtb</CODE>; Left to right, top to bottom (default)</LI>
+ <LI><CODE>-o number-up-layout=rlbt</CODE>; Right to left, bottom to top</LI>
+ <LI><CODE>-o number-up-layout=rltb</CODE>; Right to left, top to bottom</LI>
+ <LI><CODE>-o number-up-layout=tblr</CODE>; Top to bottom, left to right</LI>
+ <LI><CODE>-o number-up-layout=tbrl</CODE>; Top to bottom, right to left</LI>
+</UL>
+
+<H3><A NAME="FIT_TO_PAGE">Scaling to Fit</A></H3>
+
+<P>The <CODE>-o fit-to-page</CODE> option specifies that the document
+should be scaled to fit on the page:</P>
+
+<PRE CLASS="command">
+lp -o fit-to-page filename
+lpr -o fit-to-page filename
+</PRE>
+
+<P>The default is to use the size specified in the file.</P>
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>This feature depends upon an accurate size in
+the print file. If no size is given in the file, the page may be
+scaled incorrectly!
+
+</BLOCKQUOTE>
+
+<H3><A NAME="OUTPUTORDER">Printing in Reverse Order</A></H3>
+
+<P>The <CODE>-o outputorder=reverse</CODE> option will print the
+pages in reverse order:</P>
+
+<PRE CLASS="command">
+lp -o outputorder=reverse filename
+lpr -o outputorder=reverse filename
+</PRE>
+
+<P>Similarly, the <CODE>-o outputorder=normal</CODE> option will
+print starting with page 1:</P>
+
+<PRE CLASS="command">
+lp -o outputorder=normal filename
+lpr -o outputorder=normal filename
+</PRE>
+
+<P>The default is <CODE>-o outputorder=normal</CODE> for
+printers that print face down and <CODE>-o outputorder=reverse</CODE>
+for printers that print face up.
+
+<H3><A NAME="MIRROR">Printing Mirrored Pages</A></H3>
+
+<P>The <CODE>-o mirror</CODE> option flips each page along the
+vertical axis to produce a mirrored image:</P>
+
+<PRE CLASS="command">
+lp -o mirror filename
+lpr -o mirror filename
+</PRE>
+
+<P>This is typically used when printing on T-shirt transfer
+media or sometimes on transparencies.</P>
+
+<H3><A NAME="RAW">Raw or Unfiltered Output</A></H3>
+
+<P>The <CODE>-o raw</CODE> option allows you to send files
+directly to a printer without filtering. This is sometimes
+required when printing from applications that provide their own
+"printer drivers" for your printer:</P>
+
+<PRE CLASS="command">
+lp -o raw filename
+lpr -o raw filename
+</PRE>
+
+<P>The <CODE>-l</CODE> option can also be used with the
+<B>lpr</B> command to send files directly to a printer:</P>
+
+<PRE CLASS="command">
+lpr -l filename
+</PRE>
+
+
+<H2 CLASS="title"><A NAME="TEXTOPTIONS">Text Options</A></H2>
+
+<P>CUPS supports several options that are only used when printing
+plain text files. These options have absolutely no effect on
+PostScript, PDF, HP-GL/2, or image files.</P>
+
+<H3><A NAME="CPI">Setting the Number of Characters Per Inch</A></H3>
+
+<P>The <CODE>-o cpi=value</CODE> option sets the number of
+characters per inch:</P>
+
+<PRE CLASS="command">
+lp -o cpi=10 filename
+lp -o cpi=12 filename
+lpr -o cpi=17 filename
+</PRE>
+
+<P>The default characters per inch is 10.</P>
+
+<H3><A NAME="LPI">Setting the Number of Lines Per Inch</A></H3>
+
+<P>The <CODE>-o lpi=value</CODE> option sets the number of lines
+per inch:</P>
+
+<PRE CLASS="command">
+lp -o lpi=6 filename
+lpr -o lpi=8 filename
+</PRE>
+
+<P>The default lines per inch is 6.</P>
+
+<H3><A NAME="COLUMNS">Setting the Number of Columns</A></H3>
+
+<P>The <CODE>-o columns=value</CODE> option sets the number of
+text columns:</P>
+
+<PRE CLASS="command">
+lp -o columns=2 filename
+lpr -o columns=3 filename
+</PRE>
+
+<P>The default number of columns is 1.</P>
+
+<H3><A NAME="MARGINS">Setting the Page Margins</A></H3>
+
+<P>Normally the page margins are set to the hard limits of the
+printer. Use the <CODE>-o page-left=value</CODE>, <CODE>-o
+page-right=value</CODE>, <CODE>-o page-top=value</CODE>, and
+<CODE>-o page-bottom=value</CODE> options to adjust the page
+margins:</P>
+
+<PRE CLASS="command">
+lp -o page-left=<EM>value</EM> filename
+lp -o page-right=<EM>value</EM> filename
+lp -o page-top=<EM>value</EM> filename
+lp -o page-bottom=<EM>value</EM> filename
+lpr -o page-left=<EM>value</EM> -o page-right=<EM>value</EM> -o page-top=<EM>value</EM> -o page-bottom=<EM>value</EM> filename
+</PRE>
+
+<P>The <CODE>value</CODE> argument is the margin in points; each
+point is 1/72 inch or 0.35mm.</P>
+
+<H3><A NAME="PRETTYPRINT">Pretty Printing</A></H3>
+
+<P>The <CODE>-o prettyprint</CODE> option puts a header at the
+top of each page with the page number, job title (usually the
+filename), and the date. Also, C and C++ keywords are
+highlighted, and comment lines are italicized:</P>
+
+<PRE CLASS="command">
+lp -o prettyprint filename
+lpr -o prettyprint filename
+</PRE>
+
+<H3><A NAME="WRAP">Turning Off Text Wrapping</A></H3>
+
+<P>The <CODE>-o nowrap</CODE> option disables wrapping of long lines:</P>
+
+<PRE CLASS="command">
+lp -o nowrap filename
+lpr -o nowrap filename
+</PRE>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">Not Supported on Mac OS X</SPAN><A NAME="IMAGEOPTIONS">Image Options</A></H2>
+
+<P>CUPS supports several options that are only used when printing
+image files. These options have absolutely no effect on PostScript, PDF,
+HP-GL/2, or text files.</P>
+
+<H3><A NAME="position">Positioning Images</A></H3>
+
+<P>The <CODE>-o position=name</CODE> option specifies the position of the
+image on the page:
+
+<UL>
+
+ <LI><CODE>center</CODE> - Center the image on the page (default)
+
+ <LI><CODE>top</CODE> - Print the image centered at the top of the page
+
+ <LI><CODE>left</CODE> - Print the image centered on the left of page
+
+ <LI><CODE>right</CODE> - Print the image centered on the right of the page
+
+ <LI><CODE>top-left</CODE> - Print the image at the top left corner of
+ the page
+
+ <LI><CODE>top-right</CODE> - Print the image at the top right corner of
+ the page
+
+ <LI><CODE>bottom</CODE> - Print the image centered at the bottom of
+ the page
+
+ <LI><CODE>bottom-left</CODE> - Print the image at the bottom left
+ corner of the page
+
+ <LI><CODE>bottom-right</CODE> - Print the image at the bottom right
+ corner of the page
+
+</UL>
+
+<H3><A NAME="scaling">Scaling Images</A></H3>
+
+<P>The <CODE>-o scaling=percent</CODE>, <CODE>-o
+ppi=value</CODE>, and <CODE>-o natural-scaling=percent</CODE>
+options change the size of a printed image:
+
+<PRE CLASS="command">
+lp -o scaling=<EM>percent</EM> filename
+lp -o ppi=<EM>value</EM> filename
+lpr -o natural-scaling=<EM>percent</EM> filename
+</PRE>
+
+<P>The <CODE>scaling=percent</CODE> value is a number from 1 to 800
+specifying the size in relation to the page (<EM>not</EM> the image.) A
+scaling of 100 percent will fill the page as completely as the image
+aspect ratio allows. A scaling of 200 percent will print on up to 4
+pages.
+
+<P>The <CODE>ppi=value</CODE> value is a number from 1 to 1200 specifying the
+resolution of the image in pixels per inch. An image that is 3000x2400
+pixels will print 10x8 inches at 300 pixels per inch, for example. If
+the specified resolution makes the image larger than the page, multiple
+pages will be printed to satisfy the request.
+
+<P>The <CODE>natural-scaling=percent</CODE> value is a number
+from 1 to 800 specifying the size in relation to the natural
+image size. A scaling of 100 percent will print the image at its
+natural size, while a scaling of 50 percent will print the image
+at half its natural size. If the specified scaling makes the
+image larger than the page, multiple pages will be printed to
+satisfy the request.
+
+
+<H2 CLASS="title"><A NAME="HPGL2OPTIONS">HP-GL/2 Options</A></H2>
+
+<P>CUPS supports several options that are only used when printing
+HP-GL/2 files. These options have absolutely no effect on PostScript, PDF,
+image, or text files.</P>
+
+<H3><A NAME="blackplot">Printing in Black</A></H3>
+
+<P>The <CODE>-o blackplot</CODE> option specifies that all pens should
+plot in black:</P>
+
+<PRE CLASS="command">
+lp -o blackplot filename
+lpr -o blackplot filename
+</PRE>
+
+<P>The default is to use the colors defined in the plot file or the
+standard pen colors defined in the HP-GL/2 reference manual from
+Hewlett Packard.
+
+<H3><A NAME="penwidth">Setting the Default Pen Width</A></H3>
+
+<P>The <CODE>-o penwidth=value</CODE> option specifies the default pen
+width for HP-GL/2 files:</P>
+
+<PRE CLASS="command">
+lp -o penwidth=<EM>value</EM> filename
+lpr -o penwidth=<EM>value</EM> filename
+</PRE>
+
+<P>The pen width <CODE>value</CODE> specifies the pen width in micrometers.
+The default value of 1000 produces lines that are 1 millimeter in width.
+Specifying a pen width of 0 produces lines that are exactly 1 pixel wide.</P>
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>This option is ignored when the pen widths are set in the plot
+file.
+
+</BLOCKQUOTE>
+
+</BODY>
+</HTML>
diff --git a/doc/help/overview.html b/doc/help/overview.html
new file mode 100644
index 000000000..59a2ac067
--- /dev/null
+++ b/doc/help/overview.html
@@ -0,0 +1,70 @@
+<HTML>
+<!-- SECTION: Getting Started -->
+<HEAD>
+ <TITLE>Overview of CUPS</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">Overview of CUPS</H1>
+
+<P>CUPS is the software you use to print from applications like the web browser
+you are using to read this page. It converts the <em>page descriptions</em>
+produced by your application (put a paragraph here, draw a line there, and so
+forth) into something your printer can understand and then sends the information
+to the printer for printing.</P>
+
+<P>Now, since every printer manufacturer does things differently, printing can
+be very complicated. CUPS does its best to hide this from you and your
+application so that you can concentrate on printing and less on <em>how</em> to
+print. Generally, the only time you need to know anything about your printer is
+when you use it for the first time, and even then CUPS can often figure things
+out on its own.</P>
+
+<H2 CLASS="title"><A NAME="WORK">How Does It Work?</A></H2>
+
+<P>The first time you print to a printer, CUPS creates a <em>queue</em> to keep
+track of the current status of the printer (everything OK, out of paper, etc.)
+and any pages you have printed. Most of the time the queue points to a printer
+connected directly to your computer via a USB or parallel port, however it can
+also point to a printer on your network, a printer on the Internet, or multiple
+printers depending on the configuration. Regardless of <em>where</em> the queue
+points, it will look like any other printer to you and your applications.</P>
+
+<P>Every time you print something, CUPS creates a <em>job</em> which contains
+the queue you are sending the print to, the name of the document you are
+printing, and the page descriptions. Job are numbered (queue-1, queue-2, and so
+forth) so you can monitor the job as it is printed or cancel it if you see a
+mistake. When CUPS gets a job for printing, it determines the best programs
+(<em>filters</em>, <em>printer drivers</em>, <em>port monitors</em>, and
+<em>backends</em>) to convert the pages into a printable format and then runs
+them to actually print the job.</P>
+
+<P>When the print job is completely printed, CUPS removes the job from the queue
+and moves on to any other jobs you have submitted. You can also be notified when
+the job is finished, or if there are any errors during printing, in several
+different ways.</P>
+
+<H2 CLASS="title"><A NAME="BEGIN">Where Do I Begin?</A></H2>
+
+<P>Click on the <A HREF="http://localhost:631/admin">Administration</A> tab at
+the top of this page. Click on the <VAR>Add Printer</VAR> button and follow the
+prompts.</P>
+
+<BLOCKQUOTE>When you are asked for a username and password, enter your login
+username and password or the "root" username and password. On MacOS X, the login
+username (or "short name") is typically your first and last name in
+lowercase.</BLOCKQUOTE>
+
+<P>After the printer is added, CUPS will ask you to set the default printer
+options (paper size, output mode, etc.) for the printer. Make any changes as
+needed and then click on the <VAR>Set Default Options</VAR> button to save
+them. Some printers also support auto-configuration - click on the <VAR>Query
+Printer for Default Options</VAR> button to update the options automatically.</P>
+
+<P>Once you have added the printer, you can print to it from any application.
+You can also choose <VAR>Print Test Page</VAR> from the maintenance menu to print
+a simple test page and verify that everything is working properly.</P>
+
+</BODY>
+</HTML>
diff --git a/doc/help/policies.html b/doc/help/policies.html
new file mode 100644
index 000000000..14a5b4b87
--- /dev/null
+++ b/doc/help/policies.html
@@ -0,0 +1,601 @@
+<HTML>
+<!-- SECTION: Getting Started -->
+<HEAD>
+ <TITLE>Managing Operation Policies</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">Managing Operation Policies</H1>
+
+<P>Operation policies are the rules used for each IPP operation in CUPS. These rules include things like "user must provide a password", "user must be in the system group", "allow only from the local system", and so forth. Until CUPS 1.2, these rules were largely hardcoded and could only be customized at a very basic level.</P>
+
+<P>CUPS 1.2 and later provides a fine-grained policy layer which allows you to completely redefine the rules for each operation and/or printer. Each policy is named and defines access control rules for each IPP operation. This document describes how to manage policies and their rules.</P>
+
+<H2 CLASS="title"><A NAME="BASICS">The Basics</A></H2>
+
+<P>Operation policies are used for all IPP requests sent to the scheduler and are evaluated <em>after</em> the <A HREF="ref-cupsd-conf.html#Location"><TT>Location</TT></A> based access control rules. This means that operation policies can only add additional security restrictions to a request, never relax them. Use <TT>Location</TT> based access control rules for server-wide limits and operation policies for limits on individual printers, tasks, or services.</P>
+
+<P>Policies are stored in the <VAR>cupsd.conf</VAR> file in <A HREF="ref-cupsd-conf.html#Policy"><TT>Policy</TT></A> sections. Each policy has an alphanumeric name that is used to select it. Inside the policy section are one or more <A
+HREF="ref-cupsd-conf.html#LimitIPP"><TT>Limit</TT></A> subsections which list the operations that are affected by the rules inside it. <A HREF="#LISTING01">Listing 1</A> shows the default operation policy, appropriately called "default", that is shipped with CUPS.</P>
+
+<P>The easiest way to add a policy to the <VAR>cupsd.conf</VAR> file is to use the web interface. Click on the <VAR>Administration</VAR> tab and then the <VAR>Edit Configuration File</VAR> button to edit the current <VAR>cupsd.conf</VAR> file. Click on the <VAR>Save Changes</VAR> button to save the changes and restart the scheduler. If you edit the <VAR>cupsd.conf</VAR> file from the console, make sure to <A HREF="ref-cupsd-conf.html">restart the cupsd process</A> before trying to use the new policy.</P>
+
+<PRE CLASS="example">
+<EM>Listing 1: <A NAME="LISTING01">Default Operation Policy</A></EM>
+
+ 1 &lt;Policy default>
+ 2 # Job-related operations must be done by the owner or an
+ administrator...
+ 3 &lt;Limit Send-Document Send-URI Hold-Job Release-Job
+ Restart-Job Purge-Jobs Set-Job-Attributes
+ Create-Job-Subscription Renew-Subscription
+ Cancel-Subscription Get-Notifications Reprocess-Job
+ Cancel-Current-Job Suspend-Current-Job Resume-Job
+ CUPS-Move-Job CUPS-Get-Document>
+ 4 Require user @OWNER @SYSTEM
+ 5 Order deny,allow
+ 6 &lt;/Limit>
+ 7
+ 8 # All administration operations require an administrator
+ to authenticate...
+ 9 &lt;Limit CUPS-Add-Printer CUPS-Delete-Printer CUPS-Add-Class
+ CUPS-Delete-Class CUPS-Set-Default>
+10 AuthType Default
+11 Require user @SYSTEM
+12 Order deny,allow
+13 &lt;/Limit>
+14
+15 # All printer operations require a printer operator
+ to authenticate...
+16 &lt;Limit Pause-Printer Resume-Printer
+ Set-Printer-Attributes Enable-Printer Disable-Printer
+ Pause-Printer-After-Current-Job Hold-New-Jobs
+ Release-Held-New-Jobs Deactivate-Printer Activate-Printer
+ Restart-Printer Shutdown-Printer Startup-Printer
+ Promote-Job Schedule-Job-After CUPS-Accept-Jobs
+ CUPS-Reject-Jobs>
+17 AuthType Default
+18 Require user <em>varies by OS</em>
+19 Order deny,allow
+20 &lt;/Limit>
+21
+22 # Only the owner or an administrator can cancel or
+ authenticate a job...
+23 &lt;Limit Cancel-Job CUPS-Authenticate-Job>
+24 Require user @OWNER @SYSTEM
+25 Order deny,allow
+26 &lt;/Limit>
+27
+28 &lt;Limit All>
+29 Order deny,allow
+30 &lt;/Limit>
+31 &lt;/Policy>
+</PRE>
+
+<H3>The Default CUPS Operation Policy</H3>
+
+<P>The policy definition starts with an opening <TT>Policy</TT> directive:</P>
+
+<PRE CLASS="example">
+ 1 &lt;Policy default>
+</PRE>
+
+<P>The first <TT>Limit</TT> subsection defines the rules for IPP job operations:</P>
+
+<PRE CLASS="example">
+ 3 &lt;Limit Send-Document Send-URI Hold-Job Release-Job
+ Restart-Job Purge-Jobs Set-Job-Attributes
+ Create-Job-Subscription Renew-Subscription
+ Cancel-Subscription Get-Notifications Reprocess-Job
+ Cancel-Current-Job Suspend-Current-Job Resume-Job
+ CUPS-Move-Job CUPS-Get-Document>
+ 4 Require user @OWNER @SYSTEM
+ 5 Order deny,allow
+ 6 &lt;/Limit>
+</PRE>
+
+<P>The operation names are listed on a single line with spaces separating them. Each name corresponds to the IPP operation described in any of the IETF or PWG standards documents for the Internet Printing Protocol. <A HREF="#TABLE01">Table 1</A> lists all of the operations that have been defined along with their usage in CUPS.</P>
+
+<P>The access control rules are listed after the <TT>Limit</TT> line and are the same as those used for <A HREF="ref-cupsd-conf.html#Location"><TT>Location</TT></A> sections. In this case, we require the owner of the job ("@OWNER") or a member of the <A HREF="ref-cupsd-conf.html#SystemGroup"><TT>SystemGroup</TT></A> ("@SYSTEM") to do the operation. Because we do not include an <A HREF="ref-cupsd-conf.html#AuthType"><TT>AuthType</TT></A> directive here, the user information can come from the IPP request itself or the authenticated username from the HTTP request. The administrative operations starting on line 9, however, <em>do</em> use the <TT>AuthType</TT> directive, and so administrative operations need to be authenticated:</P>
+
+<PRE CLASS="example">
+ 9 &lt;Limit CUPS-Add-Printer CUPS-Delete-Printer CUPS-Add-Class
+ CUPS-Delete-Class CUPS-Set-Default>
+10 AuthType Default
+11 Require user @SYSTEM
+12 Order deny,allow
+13 &lt;/Limit>
+14
+15 # All printer operations require a printer operator
+ to authenticate...
+16 &lt;Limit Pause-Printer Resume-Printer
+ Set-Printer-Attributes Enable-Printer Disable-Printer
+ Pause-Printer-After-Current-Job Hold-New-Jobs
+ Release-Held-New-Jobs Deactivate-Printer Activate-Printer
+ Restart-Printer Shutdown-Printer Startup-Printer
+ Promote-Job Schedule-Job-After CUPS-Accept-Jobs
+ CUPS-Reject-Jobs>
+17 AuthType Default
+18 Require user <em>varies by OS</em>
+19 Order deny,allow
+20 &lt;/Limit>
+</PRE>
+
+<P>The "Order deny,allow" line at the end of both <TT>Limit</TT> subsections allows the request to come from any system allowed by the <TT>Location</TT> sections elsewhere in the <VAR>cupsd.conf</VAR> file.</P>
+
+<P>The <TT>Cancel-Job</TT> and <TT>CUPS-Authenticate-Job</TT> operations are listed separately to allow the web interface to more easily edit their policy without disturbing the rest. Like the rest of the job operations, we want the job's owner ("@OWNER") or an administrator ("@SYSTEM") to do it:</P>
+
+<PRE CLASS="example">
+16 &lt;Limit Cancel-Job CUPS-Authenticate-Job>
+17 Require user @OWNER @SYSTEM
+18 Order deny,allow
+19 &lt;/Limit>
+</PRE>
+
+<P>The last <TT>Limit</TT> subsection in any policy uses the special operation name <TT>All</TT>. CUPS will use the rules in this subsection for any operation you don't list specifically in the policy. In this case, all other operations are allowed without a username or authentication:</P>
+
+<PRE CLASS="example">
+21 &lt;Limit All>
+22 Order deny,allow
+23 &lt;/Limit>
+24 &lt;/Policy>
+</PRE>
+
+
+<DIV CLASS="table"><TABLE WIDTH="80%" SUMMARY="IPP Operation Names">
+<CAPTION>Table 1: <A NAME="TABLE01">IPP Operation Names</A></CAPTION>
+<THEAD>
+<TR>
+ <TH>Name</TH>
+ <TH>Used by CUPS?</TH>
+ <TH>Description</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD NOWRAP><TT>Print-Job</TT></TD>
+ <TD>Yes</TD>
+ <TD>Creates a print job with a single file.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Print-URI</TT></TD>
+ <TD>No</TD>
+ <TD>Create a print job with a single URI.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Validate-Job</TT></TD>
+ <TD>Yes</TD>
+ <TD>Validates a print request before printing.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Create-Job</TT></TD>
+ <TD>Yes</TD>
+ <TD>Creates a print job with no files or URIs.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Send-Document</TT></TD>
+ <TD>Yes</TD>
+ <TD>Adds a file to a print job.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Send-URI</TT></TD>
+ <TD>No</TD>
+ <TD>Adds a URI to a print job.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Cancel-Job</TT></TD>
+ <TD>Yes</TD>
+ <TD>Cancels a print job.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Get-Job-Attributes</TT></TD>
+ <TD>Yes</TD>
+ <TD>Gets information and options associated with a job.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Get-Jobs</TT></TD>
+ <TD>Yes</TD>
+ <TD>Gets a list of jobs.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Get-Printer-Attributes</TT></TD>
+ <TD>Yes</TD>
+ <TD>Gets information and options associated with a printer or class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Hold-Job</TT></TD>
+ <TD>Yes</TD>
+ <TD>Holds a print job for printing.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Release-Job</TT></TD>
+ <TD>Yes</TD>
+ <TD>Releases a print job for printing.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Restart-Job</TT></TD>
+ <TD>Yes</TD>
+ <TD>Reprints a print job.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Pause-Printer</TT></TD>
+ <TD>Yes</TD>
+ <TD>Stops a printer or class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Resume-Printer</TT></TD>
+ <TD>Yes</TD>
+ <TD>Starts a printer or class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Purge-Jobs</TT></TD>
+ <TD>Yes</TD>
+ <TD>Cancels all jobs on the server or a printer or class
+ and removes the job history information.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Set-Printer-Attributes</TT></TD>
+ <TD>No</TD>
+ <TD>Sets printer or class information; CUPS uses
+ CUPS-Add-Modify-Printer and CUPS-Add-Modify-Class
+ instead.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Set-Job-Attributes</TT></TD>
+ <TD>Yes</TD>
+ <TD>Changes job options.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Get-Printer-Supported-Values</TT></TD>
+ <TD>No</TD>
+ <TD>Gets -supported attributes for a printer based on job
+ options.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Create-Printer-Subscription</TT></TD>
+ <TD>Yes</TD>
+ <TD>Creates an event subscription for a printer or the server.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Create-Job-Subscription</TT></TD>
+ <TD>Yes</TD>
+ <TD>Creates an event subscription for a job.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Get-Subscription-Attributes</TT></TD>
+ <TD>Yes</TD>
+ <TD>Gets information for an event subscription.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Get-Subscriptions</TT></TD>
+ <TD>Yes</TD>
+ <TD>Gets a list of event subscriptions.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Renew-Subscription</TT></TD>
+ <TD>Yes</TD>
+ <TD>Renews an event subscription that is about to expire.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Cancel-Subscription</TT></TD>
+ <TD>Yes</TD>
+ <TD>Cancels an event subscription.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Get-Notifications</TT></TD>
+ <TD>Yes</TD>
+ <TD>Gets (pending) events for an event subscription.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Send-Notifications</TT></TD>
+ <TD>No</TD>
+ <TD>Sends events for an event subscription.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Get-Printer-Support-Files</TT></TD>
+ <TD>No</TD>
+ <TD>Gets printer driver files for a Novell client.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Enable-Printer</TT></TD>
+ <TD>Yes</TD>
+ <TD>Starts a printer or class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Disable-Printer</TT></TD>
+ <TD>Yes</TD>
+ <TD>Stops a printer or class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Pause-Printer-After-Current-Job</TT></TD>
+ <TD>No</TD>
+ <TD>Stops a printer or class after the current job is finished.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Hold-New-Jobs</TT></TD>
+ <TD>No</TD>
+ <TD>Holds new jobs submitted to a printer or class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Release-Held-New-Jobs</TT></TD>
+ <TD>No</TD>
+ <TD>Releases jobs that were held because of the
+ Hold-New-Jobs operation.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Deactivate-Printer</TT></TD>
+ <TD>No</TD>
+ <TD>Deactivates a printer or class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Activate-Printer</TT></TD>
+ <TD>No</TD>
+ <TD>Activates a printer or class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Restart-Printer</TT></TD>
+ <TD>No</TD>
+ <TD>Restarts a printer or class, resuming print jobs as needed.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Shutdown-Printer</TT></TD>
+ <TD>No</TD>
+ <TD>Powers a printer or class off.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Startup-Printer</TT></TD>
+ <TD>No</TD>
+ <TD>Powers a printer or class on.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Reprocess-Job</TT></TD>
+ <TD>No</TD>
+ <TD>Reprints a job on a different printer or class; CUPS has the
+ CUPS-Move-Job operation instead.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Cancel-Current-Job</TT></TD>
+ <TD>No</TD>
+ <TD>Cancels the current job on a printer or class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Suspend-Current-Job</TT></TD>
+ <TD>No</TD>
+ <TD>Stops the current job on a printer or class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Resume-Job</TT></TD>
+ <TD>No</TD>
+ <TD>Resumes printing of a stopped job.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Promote-Job</TT></TD>
+ <TD>No</TD>
+ <TD>Prints a job before others.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>Schedule-Job-After</TT></TD>
+ <TD>No</TD>
+ <TD>Prints a job after others.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Get-Default</TT></TD>
+ <TD>Yes</TD>
+ <TD>Gets the server/network default printer or class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Get-Printers</TT></TD>
+ <TD>Yes</TD>
+ <TD>Gets a list of printers and/or classes.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Add-Modify-Printer</TT></TD>
+ <TD>Yes</TD>
+ <TD>Adds or modifies a printer.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Delete-Printer</TT></TD>
+ <TD>Yes</TD>
+ <TD>Removes a printer.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Get-Classes</TT></TD>
+ <TD>Yes</TD>
+ <TD>Gets a list of classes.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Add-Modify-Class</TT></TD>
+ <TD>Yes</TD>
+ <TD>Adds or modifies a class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Delete-Class</TT></TD>
+ <TD>Yes</TD>
+ <TD>Removes a class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Accept-Jobs</TT></TD>
+ <TD>Yes</TD>
+ <TD>Sets a printer's or class' printer-is-accepting-jobs
+ attribute to true.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Reject-Jobs</TT></TD>
+ <TD>Yes</TD>
+ <TD>Sets a printer's or class' printer-is-accepting-jobs
+ attribute to false.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Set-Default</TT></TD>
+ <TD>Yes</TD>
+ <TD>Sets the server/network default printer or class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Get-Devices</TT></TD>
+ <TD>Yes</TD>
+ <TD>Gets a list of printer devices.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Get-PPDs</TT></TD>
+ <TD>Yes</TD>
+ <TD>Gets a list of printer drivers or manufacturers.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Move-Job</TT></TD>
+ <TD>Yes</TD>
+ <TD>Moves a job to a different printer or class.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Authenticate-Job</TT></TD>
+ <TD>Yes</TD>
+ <TD>Authenticates a job for printing.</TD>
+</TR>
+<TR>
+ <TD NOWRAP><TT>CUPS-Get-Document</TT></TD>
+ <TD>Yes</TD>
+ <TD>Retrieves a document file from a job.</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+
+<H2 CLASS="title"><A NAME="CREATING">Creating Your Own Policies</A></H2>
+
+<P>The easiest way to create a new policy is to start with the default policy and then make changes to the copy. The first change you'll make is to give the policy a new name. Policy names can use the same characters as a printer name, specifically all printable characters except space, slash (/), and pound (#):</P>
+
+<PRE CLASS="example">
+&lt;Policy mypolicy>
+</PRE>
+
+<P>Then you need to decide exactly what limits you want for the policy. For example, if you want to allow any user to cancel any other users' jobs, you can change the <TT>Cancel-Job</TT> limits to:</P>
+
+<PRE CLASS="example">
+&lt;Limit Cancel-Job>
+ Order deny,allow
+&lt;/Limit>
+</PRE>
+
+<P>The directives inside the <TT>Limit</TT> subsection can use any of the normal limiting directives: <A HREF="ref-cupsd-conf.html#Allow"><TT>Allow</TT></A>, <A HREF="ref-cupsd-conf.html#AuthType"><TT>AuthType</TT></A>, <A HREF="ref-cupsd-conf.html#Deny"><TT>Deny</TT></A>, <A HREF="ref-cupsd-conf.html#Encryption"><TT>Encryption</TT></A>, <A HREF="ref-cupsd-conf.html#Require"><TT>Require</TT></A>, and <A HREF="ref-cupsd-conf.html#Satisfy"><TT>Satisfy</TT></A>. <A HREF="#TABLE02">Table 2</A> lists some basic "recipes" for different access control rules.</P>
+
+<DIV CLASS="table"><TABLE WIDTH="80%" SUMMARY="Access Control Recipes">
+<CAPTION>Table 2: <A NAME="TABLE02">Access Control Recipes</A></CAPTION>
+<THEAD>
+<TR>
+ <TH>Access Level</TH>
+ <TH>Directives to Use</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD>Allow Everyone</TD>
+ <TD><PRE>Order deny,allow
+Allow from all</PRE></TD>
+</TR>
+<TR>
+ <TD>Allow Everyone on the Local Network</TD>
+ <TD><PRE>Order deny,allow
+Allow from @LOCAL</PRE></TD>
+</TR>
+<TR>
+ <TD>Deny Everyone/Disable Operation(s)</TD>
+ <TD><PRE>Order deny,allow</PRE></TD>
+</TR>
+<TR>
+ <TD>Require Login (System) Password</TD>
+ <TD><PRE>AuthType Basic</PRE></TD>
+</TR>
+<TR>
+ <TD>Require CUPS (lppasswd) Password</TD>
+ <TD><PRE>AuthType BasicDigest</PRE></TD>
+</TR>
+<TR>
+ <TD>Require Kerberos</TD>
+ <TD><PRE>AuthType Negotiate</PRE></TD>
+</TR>
+<TR>
+ <TD>Require the Owner of a Job or Subscription</TD>
+ <TD><PRE>Require user @OWNER</PRE></TD>
+</TR>
+<TR>
+ <TD>Require an Administrative User</TD>
+ <TD><PRE>Require user @SYSTEM</PRE></TD>
+</TR>
+<TR>
+ <TD>Require Member of Group "foogroup"</TD>
+ <TD><PRE>Require user @foogroup</PRE></TD>
+</TR>
+<TR>
+ <TD>Require "john" or "mary"</TD>
+ <TD><PRE>Require user john mary</PRE></TD>
+</TR>
+<TR>
+ <TD>Require Encryption</TD>
+ <TD><PRE>Encryption Required</PRE></TD>
+</TR>
+</TABLE></DIV>
+
+
+<H3>Creating a Policy for a Computer Lab</H3>
+
+<P>One common operating scenario is a computer lab. The lab is managed by one or more technicians that assist the users of the lab and handle the basic administration tasks. <A HREF="#LISTING02">Listing 2</A> shows an operation policy that only allows access from the lab's subnet, 10.0.2.x, and allows the lab technicians, who are members of a special UNIX group for that lab called "lab999", to do job, printer, and subscription management operations.</P>
+
+<PRE CLASS="example">
+<EM>Listing 2: <A NAME="LISTING02">Operation Policy for a Lab</A></EM>
+
+ 1 &lt;Policy lab999>
+ 2 # Job- and subscription-related operations must be done
+ by the owner, a lab technician, or an administrator...
+ 3 &lt;Limit Send-Document Send-URI Hold-Job Release-Job
+ Restart-Job Purge-Jobs Set-Job-Attributes
+ Create-Job-Subscription Renew-Subscription
+ Cancel-Subscription Get-Notifications Reprocess-Job
+ Cancel-Current-Job Suspend-Current-Job Resume-Job
+ CUPS-Move-Job Cancel-Job CUPS-Authenticate-Job CUPS-Get-Document>
+ 4 Require user @OWNER @lab999 @SYSTEM
+ 5 Order allow,deny
+ 6 Allow from 10.0.2.0/24
+ 7 &lt;/Limit>
+ 8
+ 9 # All administration operations require a lab technician
+ or an administrator to authenticate...
+10 &lt;Limit Pause-Printer Resume-Printer
+ Set-Printer-Attributes Enable-Printer Disable-Printer
+ Pause-Printer-After-Current-Job Hold-New-Jobs
+ Release-Held-New-Jobs Deactivate-Printer Activate-Printer
+ Restart-Printer Shutdown-Printer Startup-Printer
+ Promote-Job Schedule-Job-After CUPS-Accept-Jobs
+ CUPS-Reject-Jobs CUPS-Set-Default>
+11 AuthType Default
+12 Require user @lab999 @SYSTEM
+13 Order allow,deny
+14 Allow from 10.0.2.0/24
+15 &lt;/Limit>
+16
+17 # All other operations are allowed from the lab network...
+18 &lt;Limit All>
+19 Order allow,deny
+20 Allow from 10.0.2.0/24
+21 &lt;/Limit>
+22 &lt;/Policy>
+</PRE>
+
+
+<H2 CLASS="title"><A NAME="SELECT">Using Policies</A></H2>
+
+<P>Once you have created a policy, you can use it in two ways. The first way is to assign it as the default policy for the system using the <A HREF="ref-cupsd-conf.html#DefaultPolicy"><TT>DefaultPolicy</TT></A> directive in the <VAR>cupsd.conf</VAR> file. For example, add the following line to the <VAR>cupsd.conf</VAR> file to use the "lab999" policy from the previous section:</P>
+
+<PRE CLASS="example">
+DefaultPolicy lab999
+</PRE>
+
+<P>To associate the policy with one or more printers, use either the <A HREF="man-lpadmin.html">lpadmin(8)</A> command or the web interface to change the operation policy for each printer. When using the <B>lpadmin</B> command, the <TT>-o printer-op-policy=name</TT> option sets the operation policy for a printer. For example, enter the following command to use the "lab999" policy from the previous section with a printer named "LaserJet4000":</P>
+
+<PRE CLASS="command">
+lpadmin -p LaserJet4000 -o printer-op-policy=lab999
+</PRE>
+
+<P>To make the same change in the web interface, go to the printer's web page, for example "http://localhost:631/printers/LaserJet4000", and choose <VAR>Set Default Options</VAR> from the <VAR>Administration</VAR> menu button. Click on the <VAR>Policies</VAR> link and choose the desired policy from the pull-down list. Click on <VAR>Set Default Options</VAR> to change the policy for the printer.</P>
+
+</BODY>
+</HTML>
diff --git a/doc/help/postscript-driver.html b/doc/help/postscript-driver.html
new file mode 100644
index 000000000..501043c78
--- /dev/null
+++ b/doc/help/postscript-driver.html
@@ -0,0 +1,663 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>Developing PostScript Printer Drivers </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: postscript-driver.html 9740 2011-05-04 06:26:22Z mike $"
+
+ PostScript printer driver documentation for CUPS.
+
+ Copyright 2007-2010 by Apple Inc.
+ Copyright 1997-2007 by Easy Software Products.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Developing PostScript Printer Drivers</h1>
+
+<p>This document describes how to develop printer drivers for PostScript printers. Topics include: <a href='#BASICS'>printer driver basics</a>, <a href='#CREATE'>creating new PPD files</a>, <a href='#IMPORT'>importing existing PPD files</a>, <a href='#FILTERS'>using custom filters</a>, <a href='#COLOR'>implementing color management</a>, and <a href='#MACOSX'>adding Mac OS X features</a>.</p>
+
+<div class='summary'><table summary='General Information'>
+<tbody>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='raster-driver.html'>Developing Raster Printer Drivers</a><br>
+ Programming: <a href='api-filter.html'>Filter and Backend Programming</a><br>
+ Programming: <a href='ppd-compiler.html'>Introduction to the PPD Compiler</a><br>
+ Programming: <a href='api-raster.html'>Raster API</a><br>
+ References: <a href='ref-ppdcfile.html'>PPD Compiler Driver Information File Reference</a><br>
+ Specifications: <a href='spec-ppd.html'>CUPS PPD Extensions</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#BASICS">Printer Driver Basics</a></li>
+<li><a href="#CREATING">Creating New PPD Files</a><ul class="subcontents">
+ <li><a href="#IMPORT">Importing Existing PPD Files</a></li>
+</ul></li>
+<li><a href="#FILTERS">Using Custom Filters</a></li>
+<li><a href="#COLOR">Implementing Color Management</a></li>
+<li><a href="#MACOSX">Adding Mac OS X Features</a></li>
+</ul>
+<h2 class='title'><a name='BASICS'>Printer Driver Basics</a></h2>
+
+<p>A CUPS PostScript printer driver consists of a PostScript Printer Description (PPD) file that describes the features and capabilities of the device, zero or more <em>filter</em> programs that prepare print data for the device, and zero or more support files for color management, online help, and so forth. The PPD file includes references to all of the filters and support files used by the driver.</p>
+
+<p>Every time a user prints something the scheduler program, <a href='man-cupsd.html'>cupsd(8)</a>, determines the format of the print job and the programs required to convert that job into something the printer understands. CUPS includes filter programs for many common formats, for example to convert Portable Document Format (PDF) files into device-independent PostScript, and then from device-independent PostScript to device-dependent PostScript. <a href='#FIGURE_1'>Figure 1</a> shows the data flow of a typical print job.</p>
+
+<div class='figure'><table summary='PostScript Filter Chain'>
+<caption>Figure 1: <a name='FIGURE_1'>PostScript Filter Chain</a></caption>
+<tr><td><img src='../images/cups-postscript-chain.png' width='700' height='150' alt='PostScript Filter Chain'></td></tr>
+</table></div>
+
+<p>The optional PostScript filter can be provided to add printer-specific commands to the PostScript output that cannot be represented in the PPD file or to reorganize the output for special printer features. Typically this is used to support advanced job management or finishing functions on the printer. CUPS includes a generic PostScript filter that handles all PPD-defined commands.</p>
+
+<p>The optional port monitor handles interface-specific protocol or encoding issues. For example, many PostScript printers support the Binary Communications Protocol (BCP) and Tagged Binary Communications Protocol (TBCP) to allow applications to print 8-bit ("binary") PostScript jobs. CUPS includes port monitors for BCP and TBCP, and you can supply your own port monitors as needed.</p>
+
+<p>The backend handles communications with the printer, sending print data from the last filter to the printer and relaying back-channel data from the printer to the upstream filters. CUPS includes backend programs for common direct-connect interfaces and network protocols, and you can provide your own backend to support custom interfaces and protocols.</p>
+
+<p>The scheduler also supports a special "command" file format for sending maintenance commands and status queries to a printer or printer driver. Command print jobs typically use a single command filter program defined in the PPD file to generate the appropriate printer commands and handle any responses from the printer. <a href='#FIGURE_2'>Figure 2</a> shows the data flow of a typical command job.</p>
+
+<div class='figure'><table summary='Command Filter Chain'>
+<caption>Figure 2: <a name='FIGURE_2'>Command Filter Chain</a></caption>
+<tr><td><img src='../images/cups-command-chain.png' width='575' height='150' alt='Command Filter Chain'></td></tr>
+</table></div>
+
+<p>PostScript printer drivers typically do not require their own command filter since CUPS includes a generic PostScript command filter that supports all of the standard functions using PPD-defined commands.</p>
+
+
+<h2 class='title'><a name='CREATING'>Creating New PPD Files</a></h2>
+
+<p>We recommend using the CUPS PPD compiler, <a href='man-ppdc.html'>ppdc(1)</a>, to create new PPD files since it manages many of the tedious (and error-prone!) details of paper sizes and localization for you. It also allows you to easily support multiple devices from a single source file. For more information see the "<a href='ppd-compiler.html'>Introduction to the PPD Compiler</a>" document. <a href='#LISTING_1'>Listing 1</a> shows a driver information file for a black-and-white PostScript printer.</p>
+
+<p class='example'>Listing 1: <a name='LISTING_1'>"examples/postscript.drv"</a></p>
+
+<pre class='example'>
+// Include standard font and media definitions
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+
+// Specify this is a PostScript printer driver
+<a href='ref-ppdcfile.html#DriverType'>DriverType</a> ps
+
+// List the fonts that are supported, in this case all standard fonts
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+
+// Manufacturer, model name, and version
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "Foo"
+<a href='ref-ppdcfile.html#ModelName'>ModelName</a> "Foo LaserProofer 2000"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+
+// PostScript printer attributes
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> DefaultColorSpace "" Gray
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> LandscapeOrientation "" Minus90
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> LanguageLevel "" "3"
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> Product "" "(Foo LaserProofer 2000)"
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> PSVersion "" "(3010) 0"
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> TTRasterizer "" Type42
+
+// Supported page sizes
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Legal
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+
+// Query command for page size
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> "?PageSize" "" "
+ save
+ currentpagedevice /PageSize get aload pop
+ 2 copy gt {exch} if (Unknown)
+ 23 dict
+ dup [612 792] (Letter) put
+ dup [612 1008] (Legal) put
+ dup [595 842] (A4) put
+ {exch aload pop 4 index sub abs 5 le exch
+ 5 index sub abs 5 le and
+ {exch pop exit} {pop} ifelse
+ } bind forall = flush pop pop
+ restore"
+
+// Specify the name of the PPD file we want to generate
+<a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "fooproof.ppd"
+</pre>
+
+<h3>Required Attributes</h3>
+
+<p>PostScript drivers require the attributes listed in <a href='#TABLE_1'>Table 1</a>. If not specified, the defaults for CUPS drivers are used. A typical PostScript driver information file would include the following attributes:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> DefaultColorSpace "" Gray
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> LandscapeOrientation "" Minus90
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> LanguageLevel "" "3"
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> Product "" "(Foo LaserProofer 2000)"
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> PSVersion "" "(3010) 0"
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> TTRasterizer "" Type42
+</pre>
+
+<div class='table'><table summary='Required PostScript Printer Driver Attributes'>
+<caption>Table 1: <a name='TABLE_1'>Required PostScript Printer Driver Attributes</a></caption>
+<thead>
+<tr>
+ <th>Attribute</th>
+ <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td><tt>DefaultColorSpace</tt></td>
+ <td>The default colorspace:
+ <tt>Gray</tt>, <tt>RGB</tt>, <tt>CMY</tt>, or
+ <tt>CMYK</tt>. If not specified, then <tt>RGB</tt> is
+ assumed.</td>
+</tr>
+<tr>
+ <td><tt>LandscapeOrientation</tt></td>
+ <td>The preferred landscape
+ orientation: <tt>Plus90</tt>, <tt>Minus90</tt>, or
+ <tt>Any</tt>. If not specified, <tt>Plus90</tt> is
+ assumed.</td>
+</tr>
+<tr>
+ <td><tt>LanguageLevel</tt></td>
+ <td>The PostScript language
+ level supported by the device: 1, 2, or 3. If not
+ specified, 2 is assumed.</td>
+</tr>
+<tr>
+ <td><tt>Product</tt></td>
+ <td>The string returned by
+ the PostScript <tt>product</tt> operator, which
+ <i>must</i> include parenthesis to conform with
+ PostScript syntax rules for strings. Multiple
+ <tt>Product</tt> attributes may be specified to support
+ multiple products with the same PPD file. If not
+ specified, "(ESP Ghostscript)" and "(GNU Ghostscript)"
+ are assumed.</td>
+</tr>
+<tr>
+ <td><tt>PSVersion</tt></td>
+ <td>The PostScript
+ interpreter version numbers as returned by the
+ <tt>version</tt> and <tt>revision</tt> operators. The
+ required format is "(version) revision". Multiple
+ <tt>PSVersion</tt> attributes may be specified to
+ support multiple interpreter version numbers. If not
+ specified, "(3010) 705" and "(3010) 707" are
+ assumed.</td>
+</tr>
+<tr>
+ <td><tt>TTRasterizer</tt></td>
+ <td>The type of TrueType
+ font rasterizer supported by the device, if any. The
+ supported values are <tt>None</tt>, <tt>Accept68k</tt>,
+ <tt>Type42</tt>, and <tt>TrueImage</tt>. If not
+ specified, <tt>None</tt> is assumed.</td>
+</tr>
+</table></div>
+
+<h3>Query Commands</h3>
+
+<p>Most PostScript printer PPD files include query commands (<tt>?PageSize</tt>, etc.) that allow applications to query the printer for its current settings and configuration. Query commands are included in driver information files as attributes. For example, the example in <a href='#LISTING_1'>Listing 1</a> uses the following definition for the <tt>PageSize</tt> query command:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> "?PageSize" "" "
+ save
+ currentpagedevice /PageSize get aload pop
+ 2 copy gt {exch} if (Unknown)
+ 23 dict
+ dup [612 792] (Letter) put
+ dup [612 1008] (Legal) put
+ dup [595 842] (A4) put
+ {exch aload pop 4 index sub abs 5 le exch
+ 5 index sub abs 5 le and
+ {exch pop exit} {pop} ifelse
+ } bind forall = flush pop pop
+ restore"
+</pre>
+
+<p>Query commands can span multiple lines, however no single line may contain more than 255 characters.</p>
+
+<h3><a name='IMPORT'>Importing Existing PPD Files</a></h3>
+
+<P>CUPS includes a utility called <a href='man-ppdi.html'>ppdi(1)</a>
+which allows you to import existing PPD files into the driver information file
+format used by the PPD compiler <a href='man-ppdc.html'>ppdc(1)</a>. Once
+imported, you can modify, localize, and regenerate the PPD files easily. Type
+the following command to import the PPD file <VAR>mydevice.ppd</VAR> into the
+driver information file <VAR>mydevice.drv</VAR>:</P>
+
+<pre class='command'>
+ppdi -o mydevice.drv mydevice.ppd
+</pre>
+
+<P>If you have a whole directory of PPD files that you would like to import,
+you can list multiple filenames or use shell wildcards to import more than one
+PPD file on the command-line:</P>
+
+<pre class='command'>
+ppdi -o mydevice.drv mydevice1.ppd mydevice2.ppd
+ppdi -o mydevice.drv *.ppd
+</pre>
+
+<P>If the driver information file already exists, the new PPD
+file entries are appended to the end of the file. Each PPD file
+is placed in its own group of curly braces within the driver
+information file.</P>
+
+
+<h2 class='title'><a name='FILTERS'>Using Custom Filters</a></h2>
+
+<p>Normally a PostScript printer driver will not utilize any additional print filters. For drivers that provide additional filters such as a CUPS command file filter for doing printer maintenance, you must also list the following <tt>Filter</tt> directive to handle printing PostScript files:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-postscript 0 -
+</pre>
+
+<h3>Custom Command Filters</h3>
+
+<p>The <tt>application/vnd.cups-command</tt> file type is used for CUPS command files. Use the following <tt>Filter</tt> directive to handle CUPS command files:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-command 100 /path/to/command/filter
+</pre>
+
+<p>To use the standard PostScript command filter, specify <var>commandtops</var> as the path to the command filter.</p>
+
+<h3>Custom PDF Filters</h3>
+
+<p>The <tt>application/pdf</tt> file type is used for unfiltered PDF files while the <tt>application/vnd.cups-pdf</tt> file type is used for filtered PDF files. Use the following <tt>Filter</tt> directive to handle filtered PDF files:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-pdf 100 /path/to/pdf/filter
+</pre>
+
+<p>For unfiltered PDF files, use:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/pdf 100 /path/to/pdf/filter
+</pre>
+
+<p>Custom PDF filters that accept filtered data do not need to perform number-up processing and other types of page imposition, while those that accept unfiltered data MUST do the number-up processing themselves.</p>
+
+<h3>Custom PostScript Filters</h3>
+
+<p>The <tt>application/vnd.cups-postscript</tt> file type is used for filtered PostScript files. Use the following <tt>Filter</tt> directive to handle PostScript files:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-postscript 100 /path/to/postscript/filter
+</pre>
+
+
+<h2 class='title'><a name='COLOR'>Implementing Color Management</a></h2>
+
+<p>CUPS uses ICC color profiles to provide more accurate color reproduction. The <a href='spec-ppd.html#cupsICCProfile'><tt>cupsICCProfile</tt></a> attribute defines the color profiles that are available for a given printer, for example:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsICCProfile "ColorModel.MediaType.Resolution/Description" /path/to/ICC/profile
+</pre>
+
+<p>where "ColorModel.MediaType.Resolution" defines a selector based on the corresponding option selections. A simple driver might only define profiles for the color models that are supported, for example a printer supporting Gray and RGB might use:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsICCProfile "Gray../Grayscale Profile" /path/to/ICC/gray-profile
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsICCProfile "RGB../Full Color Profile" /path/to/ICC/rgb-profile
+</pre>
+
+<p>The options used for profile selection can be customized using the <tt>cupsICCQualifier2</tt> and <tt>cupsICCQualifier3</tt> attributes.</p>
+
+
+<h2 class='title'><a name='MACOSX'>Adding Mac OS X Features</a></h2>
+
+<p>Mac OS X printer drivers can provide <a href='spec-ppd.html#MACOSX'>additional attributes</a> to specify additional option panes in the print dialog, an image of the printer, a help book, and option presets for the driver software:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APDialogExtension "" /Library/Printers/Vendor/filename.plugin
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APHelpBook "" /Library/Printers/Vendor/filename.bundle
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APPrinterIconPath "" /Library/Printers/Vendor/filename.icns
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APPrinterPreset "name/text" "*option choice ..."
+</pre>
+</div>
+</body>
+</html>
diff --git a/doc/help/ppd-compiler.html b/doc/help/ppd-compiler.html
new file mode 100644
index 000000000..db891f17d
--- /dev/null
+++ b/doc/help/ppd-compiler.html
@@ -0,0 +1,1279 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>Introduction to the PPD Compiler </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: ppd-compiler.html 9740 2011-05-04 06:26:22Z mike $"
+
+ PPD compiler documentation for CUPS.
+
+ Copyright 2007-2010 by Apple Inc.
+ Copyright 1997-2007 by Easy Software Products.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Introduction to the PPD Compiler</h1>
+
+<P>This document describes how to use the CUPS PostScript Printer Description
+(PPD) file compiler. The PPD compiler generates PPD files from simple text files
+that describe the features and capabilities of one or more printers.</P>
+
+<div class='summary'><table summary='General Information'>
+<tbody>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='raster-driver.html'>Developing Raster Printer Drivers</a><br>
+ Programming: <a href='postscript-driver.html'>Developing PostScript Printer Drivers</a><br>
+ Programming: <a href='api-filter.html'>Filter and Backend Programming</a><br>
+ Programming: <a href='api-raster.html'>Raster API</a><br>
+ References: <a href='ref-ppdcfile.html'>PPD Compiler Driver Information File Reference</a><br>
+ Specifications: <a href='spec-ppd.html'>CUPS PPD Extensions</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#BASICS">The Basics</a></li>
+<li><a href="#DRV">Driver Information Files</a><ul class="subcontents">
+ <li><a href="#SIMPLE">A Simple Example</a></li>
+ <li><a href="#GROUPING">Grouping and Inheritance</a></li>
+ <li><a href="#COLOR">Color Support</a></li>
+ <li><a href="#OPTIONS">Defining Custom Options and Option Groups</a></li>
+ <li><a href="#DEFINE">Defining Constants</a></li>
+ <li><a href="#CONDITIONAL">Conditional Statements</a></li>
+ <li><a href="#CONSTRAINTS">Defining Constraints</a></li>
+</ul></li>
+<li><a href="#LOCALIZATION">Localization</a><ul class="subcontents">
+ <li><a href="#PPDPO">The ppdpo Utility</a></li>
+ <li><a href="#PPDC_CATALOG">Using Message Catalogs with the PPD Compiler</a></li>
+</ul></li>
+</ul>
+<h2 class='title'><a name='BASICS'>The Basics</a></h2>
+
+<P>The PPD compiler, <a href='man-ppdc.html'><code>ppdc(1)</code></a>, is a
+simple command-line tool that takes a single <I>driver information file</I>,
+which by convention uses the extension <VAR>.drv</VAR>, and produces one or more
+PPD files that may be distributed with your printer drivers for use with CUPS.
+For example, you would run the following command to create the English language
+PPD files defined by the driver information file <VAR>mydrivers.drv</VAR>:</P>
+
+<pre class='command'>
+ppdc mydrivers.drv
+</pre>
+
+<P>The PPD files are placed in a subdirectory called
+<VAR>ppd</VAR>. The <TT>-d</TT> option is used to put the PPD
+files in a different location, for example:</p>
+
+<pre class='command'>
+ppdc -d myppds mydrivers.drv
+</pre>
+
+<P>places the PPD files in a subdirectory named
+<VAR>myppds</VAR>. Finally, use the <TT>-l</TT> option to
+specify the language localization for the PPD files that are
+created, for example:</P>
+
+<pre class='command'>
+ppdc -d myppds/de -l de mydrivers.drv
+ppdc -d myppds/en -l en mydrivers.drv
+ppdc -d myppds/es -l es mydrivers.drv
+ppdc -d myppds/fr -l fr mydrivers.drv
+ppdc -d myppds/it -l it mydrivers.drv
+</pre>
+
+<P>creates PPD files in German (de), English (en), Spanish (es),
+French (fr), and Italian (it) in the corresponding
+subdirectories. Specify multiple languages (separated by commas) to produce
+"globalized" PPD files:</p>
+
+<pre class='command'>
+ppdc -d myppds -l de,en,es,fr,it mydrivers.drv
+</pre>
+
+
+<h2 class='title'><a name='DRV'>Driver Information Files</a></h2>
+
+<P>The driver information files accepted by the PPD compiler are
+plain text files that define the various attributes and options
+that are included in the PPD files that are generated. A driver
+information file can define the information for one or more printers and
+their corresponding PPD files.</P>
+
+<p class='example'><a name="LISTING1">Listing 1: "examples/minimum.drv"</a></p>
+
+<pre class='example'>
+<I>// Include standard font and media definitions</I>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+
+<I>// List the fonts that are supported, in this case all standard fonts...</I>
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+
+<I>// Manufacturer, model name, and version</I>
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "Foo"
+<a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+
+<I>// Each filter provided by the driver...</I>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-raster 100 rastertofoo
+
+<I>// Supported page sizes</I>
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+
+<I>// Supported resolutions</I>
+*<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "600dpi/600 DPI"
+
+<I>// Specify the name of the PPD file we want to generate...</I>
+<a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojet2k.ppd"
+</pre>
+
+
+<h3><a name='SIMPLE'>A Simple Example</a></h3>
+
+<P>The example in <A HREF="#LISTING1">Listing 1</A> shows a driver information
+file which defines the minimum required attributes to provide a valid PPD file.
+The first part of the file includes standard definition files for fonts and
+media sizes:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+</pre>
+
+<P>The <TT>#include</TT> directive works just like the C/C++ include directive;
+files included using the angle brackets (<TT>&lt;filename&gt;</TT>) are found
+in any of the standard include directories and files included using quotes
+(<TT>"filename"</TT>) are found in the same directory as the source or include
+file. The <TT>&lt;font.defs&gt;</TT> include file defines the standard fonts
+which are included with GPL Ghostscript and the Apple PDF RIP, while the
+<TT>&lt;media.defs&gt;</TT> include file defines the standard media sizes
+listed in Appendix B of the Adobe PostScript Printer Description File Format
+Specification.</P>
+
+<P>CUPS provides several other standard include files:</P>
+
+<UL>
+
+ <LI><TT>&lt;epson.h&gt;</TT> - Defines all of the rastertoepson driver
+ constants.</LI>
+
+ <LI><TT>&lt;escp.h&gt;</TT> - Defines all of the rastertoescpx driver
+ constants.</LI>
+
+ <LI><TT>&lt;hp.h&gt;</TT> - Defines all of the rastertohp driver
+ constants.</LI>
+
+ <LI><TT>&lt;label.h&gt;</TT> - Defines all of the rastertolabel driver
+ constants.</LI>
+
+ <LI><TT>&lt;pcl.h&gt;</TT> - Defines all of the rastertopclx driver
+ constants.</LI>
+
+ <LI><TT>&lt;raster.defs&gt;</TT> - Defines all of the CUPS raster format
+ constants.</LI>
+
+</UL>
+
+<P>Next we list all of the fonts that are available in the driver; for CUPS
+raster drivers, the following line is all that is usually supplied:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+</pre>
+
+<P>The <TT>Font</TT> directive specifies the name of a single font or the
+asterisk to specify all fonts. For example, you would use the following line to
+define an additional bar code font that you are supplying with your printer
+driver:</P>
+
+<pre class='example'>
+<I>// name encoding version charset status</I>
+<a href='ref-ppdcfile.html#Font'>Font</a> Barcode-Foo Special "(1.0)" Special ROM
+</pre>
+
+<P>The name of the font is <TT>Barcode-Foo</TT>. Since it is not a standard
+text font, the encoding and charset name <TT>Special</TT> is used. The version
+number is <TT>1.0</TT> and the status (where the font is located) is
+<TT>ROM</TT> to indicate that the font does not need to be embedded in
+documents that use the font for this printer.</P>
+
+<P>Third comes the manufacturer, model name, and version number information
+strings:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "Foo"
+<a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+</pre>
+
+<P>These strings are used when the user (or auto-configuration program) selects
+the printer driver for a newly connected device.</p>
+
+<P>The list of filters comes after the information strings; for the example in
+<A HREF="#LISTING1">Listing 1</A>, we have a single filter that takes CUPS
+raster data:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-raster 100 rastertofoo
+</pre>
+
+<P>Each filter specified in the driver information file is the equivalent of a
+printer driver for that format; if a user submits a print job in a different
+format, CUPS figures out the sequence of commands that will produce a supported
+format for the least relative cost.</P>
+
+<P>Once we have defined the driver information we specify the supported options.
+For the example driver we support a single resolution of 600 dots per inch and
+two media sizes, A4 and Letter:</P>
+
+<pre class='example'>
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+
+*<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "600dpi/600 DPI"
+</pre>
+
+<P>The asterisk in front of the <TT>MediaSize</TT> and <TT>Resolution</TT>
+directives specify that those option choices are the default. The
+<TT>MediaSize</TT> directive is followed by a media size name which is normally
+defined in the <TT>&lt;media.defs&gt;</TT> file and corresponds to a standard
+Adobe media size name. If the default media size is <TT>Letter</TT>, the PPD
+compiler will override it to be <TT>A4</TT> for non-English localizations for
+you automatically.</P>
+
+<P>The <TT>Resolution</TT> directive accepts several values after it as
+follows:</P>
+
+<OL>
+
+ <LI>Colorspace for this resolution, if any. In the example file, the
+ colorspace <TT>k</TT> is used which corresponds to black. For printer
+ drivers that support color printing, this field is usually specified as
+ "-" for "no change".</LI>
+
+ <LI>Bits per color. In the example file, we define 8 bits per color, for
+ a continuous-tone grayscale output. All versions of CUPS support 1 and
+ 8 bits per color. CUPS 1.2 and higher (Mac OS X 10.5 and higher) also
+ supports 16 bits per color.</LI>
+
+ <LI>Rows per band. In the example file, we define 0 rows per band to
+ indicate that our printer driver does not process the page in
+ bands.</LI>
+
+ <LI>Row feed. In the example, we define the feed value to be 0 to
+ indicate that our printer driver does not interleave the output.</LI>
+
+ <LI>Row step. In the example, we define the step value to be 0 to
+ indicate that our printer driver does not interleave the output. This
+ value normally indicates the spacing between the nozzles of an inkjet
+ printer - when combined with the previous two values, it informs the
+ driver how to stagger the output on the page to produce interleaved
+ lines on the page for higher-resolution output.</LI>
+
+ <LI>Choice name and text. In the example, we define the choice name and
+ text to be <TT>"600dpi/600 DPI"</TT>. The name and text are separated by
+ slash (<TT>/</TT>) character; if no text is specified, then the name is
+ used as the text. The PPD compiler parses the name to determine the
+ actual resolution; the name can be of the form
+ <TT><I>RESOLUTION</I>dpi</TT> for resolutions that are equal
+ horizontally and vertically or <TT><I>HRES</I>x<I>VRES</I>dpi</TT> for
+ isometric resolutions. Only integer resolution values are supported, so
+ a resolution name of <TT>300dpi</TT> is valid while <TT>300.1dpi</TT> is
+ not.</LI>
+
+</OL>
+
+<P>Finally, the <TT>PCFileName</TT> directive specifies that the named PPD file
+should be written for the current driver definitions:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojet2k.ppd"
+</pre>
+
+<P>The filename follows the directive and <I>must</I> conform to the Adobe
+filename requirements in the Adobe Postscript Printer Description File Format
+Specification. Specifically, the filename may not exceed 8 characters followed
+by the extension <VAR>.ppd</VAR>. The <TT>FileName</TT> directive can be used to
+specify longer filenames:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#FileName'>FileName</a> "FooJet 2000"
+</pre>
+
+
+<h3><a name='GROUPING'>Grouping and Inheritance</a></h3>
+
+<P>The previous example created a single PPD file. Driver information files can
+also define multiple printers by using the PPD compiler grouping functionality.
+Directives are grouped using the curly braces (<TT>{</TT> and <TT>}</TT>) and
+every group that uses the <TT>PCFileName</TT> or <TT>FileName</TT> directives
+produces a PPD file with that name. <A HREF="#LISTING2">Listing 2</A> shows a
+variation of the original example that uses two groups to define two printers
+that share the same printer driver filter but provide two different resolution
+options.</P>
+
+<p class='example'><a name="LISTING2">Listing 2: "examples/grouping.drv"</a></p>
+
+<pre class='example'>
+
+<I>// Include standard font and media definitions</I>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+
+<I>// List the fonts that are supported, in this case all standard fonts...</I>
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+
+<I>// Manufacturer and version</I>
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "Foo"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+
+<I>// Each filter provided by the driver...</I>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-raster 100 rastertofoo
+
+<I>// Supported page sizes</I>
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+
+{
+ <I>// Supported resolutions</I>
+ *<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "600dpi/600 DPI"
+
+ <I>// Specify the model name and filename...</I>
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojet2k.ppd"
+}
+
+{
+ <I>// Supported resolutions</I>
+ *<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "1200dpi/1200 DPI"
+
+ <I>// Specify the model name and filename...</I>
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2001"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojt2k1.ppd"
+}
+</pre>
+
+<P>The second example is essentially the same as the first, except that each
+printer model is defined inside of a pair of curly braces. For example, the
+first printer is defined using:</P>
+
+<pre class='example'>
+{
+ // Supported resolutions
+ *<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "600dpi/600 DPI"
+
+ // Specify the model name and filename...
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojet2k.ppd"
+}
+</pre>
+
+<P>The printer <I>inherits</I> all of the definitions from the parent group (the
+top part of the file) and adds the additional definitions inside the curly
+braces for that printer driver. When we define the second group, it also
+inherits the same definitions from the parent group but <I>none</I> of the
+definitions from the first driver. Groups can be nested to any number of levels
+to support variations of similar models without duplication of information.</P>
+
+
+<h3><a name='COLOR'>Color Support</a></h3>
+
+<P>For printer drivers that support color printing, the
+<TT>ColorDevice</TT> and <TT>ColorModel</TT> directives should be
+used to tell the printing system that color output is desired
+and in what formats. <A HREF="#LISTING3">Listing 3</A> shows a
+variation of the previous example which includes a color printer
+that supports printing at 300 and 600 DPI.</P>
+
+<P>The key changes are the addition of the <TT>ColorDevice</TT>
+directive:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#ColorDevice'>ColorDevice</a> true
+</pre>
+
+<P>which tells the printing system that the printer supports
+color printing, and the <TT>ColorModel</TT> directives:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#ColorModel'>ColorModel</a> Gray/Grayscale w chunky 0
+*<a href='ref-ppdcfile.html#ColorModel'>ColorModel</a> RGB/Color rgb chunky 0
+</pre>
+
+<P>which tell the printing system which colorspaces are supported by the printer
+driver for color printing. Each of the <TT>ColorModel</TT> directives is
+followed by the option name and text (<TT>Gray/Grayscale</TT> and
+<TT>RGB/Color</TT>), the colorspace name (<TT>w</TT> and <TT>rgb</TT>), the
+color organization (<TT>chunky</TT>), and the compression mode number
+(<TT>0</TT>) to be passed to the driver. The option name can be any of the
+standard Adobe <TT>ColorModel</TT> names:</P>
+
+<UL>
+
+ <LI><TT>Gray</TT> - Grayscale output.
+
+ <LI><TT>RGB</TT> - Color output, typically using the RGB
+ colorspace, but without a separate black channel.
+
+ <LI><TT>CMYK</TT> - Color output with a separate black
+ channel.
+
+</UL>
+
+<P>Custom names can be used, however it is recommended that you use your vendor
+prefix for any custom names, for example "fooName".</P>
+
+<P>The colorspace name can be any of the following universally supported
+colorspaces:</P>
+
+<UL>
+ <LI><TT>w</TT> - Luminance</LI>
+
+ <LI><TT>rgb</TT> - Red, green, blue</LI>
+
+ <LI><TT>k</TT> - Black</LI>
+
+ <LI><TT>cmy</TT> - Cyan, magenta, yellow</LI>
+
+ <LI><TT>cmyk</TT> - Cyan, magenta, yellow, black</LI>
+
+</UL>
+
+<P>The color organization can be any of the following values:</P>
+
+<UL>
+
+ <LI><TT>chunky</TT> - Color values are passed together on a line
+ as RGB RGB RGB RGB</LI>
+
+ <LI><TT>banded</TT> - Color values are passed separately
+ on a line as RRRR GGGG BBBB; not supported by the Apple
+ RIP filters</LI>
+
+ <LI><TT>planar</TT> - Color values are passed separately
+ on a page as RRRR RRRR RRRR ... GGGG GGGG GGGG ... BBBB
+ BBBB BBBB; not supported by the Apple RIP filters</LI>
+
+</UL>
+
+<P>The compression mode value is passed to the driver in the
+<TT>cupsCompression</TT> attribute. It is traditionally used to select an
+appropriate compression mode for the color model but can be used for any
+purpose, such as specifying a photo mode vs. standard mode.</P>
+
+<p class='example'><a name="LISTING3">Listing 3: "examples/color.drv"</a></p>
+
+<pre class='example'>
+
+<I>// Include standard font and media definitions</I>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+
+<I>// List the fonts that are supported, in this case all standard fonts...</I>
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+
+<I>// Manufacturer and version</I>
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "Foo"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+
+<I>// Each filter provided by the driver...</I>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-raster 100 rastertofoo
+
+<I>// Supported page sizes</I>
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+
+{
+ <I>// Supported resolutions</I>
+ *<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "600dpi/600 DPI"
+
+ <I>// Specify the model name and filename...</I>
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojet2k.ppd"
+}
+
+{
+ <I>// Supports color printing</I>
+ <a href='ref-ppdcfile.html#ColorDevice'>ColorDevice</a> true
+
+ <I>// Supported colorspaces</I>
+ <a href='ref-ppdcfile.html#ColorModel'>ColorModel</a> Gray/Grayscale w chunky 0
+ *<a href='ref-ppdcfile.html#ColorModel'>ColorModel</a> RGB/Color rgb chunky 0
+
+ <I>// Supported resolutions</I>
+ *<a href='ref-ppdcfile.html#Resolution'>Resolution</a> - 8 0 0 0 "300dpi/300 DPI"
+ <a href='ref-ppdcfile.html#Resolution'>Resolution</a> - 8 0 0 0 "600dpi/600 DPI"
+
+ <I>// Specify the model name and filename...</I>
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet Color"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojetco.ppd"
+}
+</pre>
+
+
+<h3><a name='OPTIONS'>Defining Custom Options and Option Groups</a></h3>
+
+<P>The <TT>Group</TT>, <TT>Option</TT>, and <TT>Choice</TT>
+directives are used to define or select a group, option, or
+choice. <A HREF="#LISTING4">Listing 4</A> shows a variation of
+the first example that provides two custom options in a group
+named "Footasm".</P>
+
+<p class='example'><a name="LISTING4">Listing 4: "examples/custom.drv"</a></p>
+
+<pre class='example'>
+
+<I>// Include standard font and media definitions</I>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+
+<I>// List the fonts that are supported, in this case all standard fonts...</I>
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+
+<I>// Manufacturer, model name, and version</I>
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "Foo"
+<a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+
+<I>// Each filter provided by the driver...</I>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-raster 100 rastertofoo
+
+<I>// Supported page sizes</I>
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+
+<I>// Supported resolutions</I>
+*<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "600dpi/600 DPI"
+
+<I>// Option Group</I>
+<a href='ref-ppdcfile.html#Group'>Group</a> "Footasm"
+
+ <I>// Boolean option</I>
+ <a href='ref-ppdcfile.html#Option'>Option</a> "fooEnhance/Resolution Enhancement" Boolean AnySetup 10
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> True/Yes "&lt;&lt;/cupsCompression 1&gt;&gt;setpagedevice"
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> False/No "&lt;&lt;/cupsCompression 0&gt;&gt;setpagedevice"
+
+ <I>// Multiple choice option</I>
+ <a href='ref-ppdcfile.html#Option'>Option</a> "fooOutputType/Output Quality" PickOne AnySetup 10
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> "Auto/Automatic Selection"
+ "&lt;&lt;/OutputType(Auto)&gt;&gt;setpagedevice""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "Text/Optimize for Text"
+ "&lt;&lt;/OutputType(Text)&gt;&gt;setpagedevice""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "Graph/Optimize for Graphics"
+ "&lt;&lt;/OutputType(Graph)&gt;&gt;setpagedevice""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "Photo/Optimize for Photos"
+ "&lt;&lt;/OutputType(Photo)&gt;&gt;setpagedevice""
+
+<I>// Specify the name of the PPD file we want to generate...</I>
+<a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojet2k.ppd"
+</pre>
+
+<P>The custom group is introduced by the <TT>Group</TT>
+directive which is followed by the name and optionally text for
+the user:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Group'>Group</a> "Footasm/Footastic Options"
+</pre>
+
+<P>The group name must conform to the PPD specification and
+cannot exceed 40 characters in length. If you specify user text,
+it cannot exceed 80 characters in length. The groups
+<TT>General</TT>, <TT>Extra</TT>, and
+<TT>InstallableOptions</TT> are predefined by CUPS; the general
+and extra groups are filled by the UI options defined by the PPD
+specification. The <TT>InstallableOptions</TT> group is reserved
+for options that define whether accessories for the printer
+(duplexer unit, finisher, stapler, etc.) are installed.</P>
+
+<P>Once the group is specified, the <TT>Option</TT> directive is
+used to introduce a new option:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Option'>Option</a> "fooEnhance/Resolution Enhancement" Boolean AnySetup 10
+</pre>
+
+<P>The directive is followed by the name of the option and any
+optional user text, the option type, the PostScript document group, and
+the sort order number. The option name must conform to the PPD specification
+and cannot exceed 40 characters in length. If you specify user text, it
+cannot exceed 80 characters in length.</P>
+
+<P>The option type can be <TT>Boolean</TT> for true/false
+selections, <TT>PickOne</TT> for picking one of many choices, or
+<TT>PickMany</TT> for picking zero or more choices. Boolean
+options can have at most two choices with the names
+<TT>False</TT> and <TT>True</TT>. Pick options can have any
+number of choices, although for Windows compatibility reasons
+the number of choices should not exceed 255.</P>
+
+<P>The PostScript document group is typically <TT>AnySetup</TT>,
+meaning that the option can be introduced at any point in the
+PostScript document. Other values include <TT>PageSetup</TT> to
+include the option before each page and <TT>DocumentSetup</TT>
+to include the option once at the beginning of the document.</P>
+
+<P>The sort order number is used to sort the printer commands
+associated with each option choice within the PostScript
+document. This allows you to setup certain options before others
+as required by the printer. For most CUPS raster printer
+drivers, the value <TT>10</TT> can be used for all options.</P>
+
+<P>Once the option is specified, each option choice can be
+listed using the <TT>Choice</TT> directive:</P>
+
+<pre class='example'>
+*<a href='ref-ppdcfile.html#Choice'>Choice</a> True/Yes "&lt;&lt;/cupsCompression 1&gt;&gt;setpagedevice"
+<a href='ref-ppdcfile.html#Choice'>Choice</a> False/No "&lt;&lt;/cupsCompression 0&gt;&gt;setpagedevice"
+</pre>
+
+<P>The directive is followed by the choice name and optionally
+user text, and the PostScript commands that should be inserted
+when printing a file to this printer. The option name must
+conform to the PPD specification and cannot exceed 40 characters
+in length. If you specify user text, it cannot exceed 80
+characters in length.</P>
+
+<P>The PostScript commands are also interpreted by any RIP
+filters, so these commands typically must be present for all
+option choices. Most commands take the form:</P>
+
+<pre class='example'>
+&lt;&lt;/name value&gt;&gt;setpagedevice
+</pre>
+
+<P>where <TT>name</TT> is the name of the PostScript page device
+attribute and <TT>value</TT> is the numeric or string value for
+that attribute.</P>
+
+
+<h3><a name='DEFINE'>Defining Constants</a></h3>
+
+<P>Sometimes you will want to define constants for your drivers
+so that you can share values in different groups within the same
+driver information file, or to share values between different
+driver information files using the <TT>#include</TT> directive.
+The <TT>#define</TT> directive is used to define constants for
+use in your printer definitions:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#_define'>#define</a> NAME value
+</pre>
+
+<P>The <TT>NAME</TT> is any sequence of letters, numbers, and
+the underscore. The <TT>value</TT> is a number or string; if the
+value contains spaces you must put double quotes around it, for
+example:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#_define'>#define</a> FOO "My String Value"
+</pre>
+
+<P>Constants can also be defined on the command-line using the <tt>-D</tt>
+option:</P>
+
+<pre class='command'>
+ppdc -DNAME="value" filename.drv
+</pre>
+
+<P>Once defined, you use the notation <TT>$NAME</TT> to substitute the value of
+the constant in the file, for example:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#_define'>#define</a> MANUFACTURER "Foo"
+<a href='ref-ppdcfile.html#_define'>#define</a> FOO_600 0
+<a href='ref-ppdcfile.html#_define'>#define</a> FOO_1200 1
+
+{
+ <a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "$MANUFACTURER"
+ <a href='ref-ppdcfile.html#ModelNumber'>ModelNumber</a> $FOO_600
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+ ...
+}
+
+{
+ <a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "$MANUFACTURER"
+ <a href='ref-ppdcfile.html#ModelNumber'>ModelNumber</a> $FOO_1200
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2001"
+ ...
+}
+</pre>
+
+<P>Numeric constants can be bitwise OR'd together by placing the constants
+inside parenthesis, for example:</P>
+
+<pre class='example'>
+<I>// ModelNumber capability bits</I>
+<a href='ref-ppdcfile.html#_define'>#define</a> DUPLEX 1
+<a href='ref-ppdcfile.html#_define'>#define</a> COLOR 2
+
+...
+
+{
+ <I>// Define a model number specifying the capabilities of the printer...</I>
+ <a href='ref-ppdcfile.html#ModelNumber'>ModelNumber</a> ($DUPLEX $COLOR)
+ ...
+}
+</pre>
+
+
+<h3><a name='CONDITIONAL'>Conditional Statements</a></h3>
+
+<p>The PPD compiler supports conditional compilation using the <tt>#if</tt>,
+<tt>#elif</tt>, <tt>#else</tt>, and <tt>#endif</tt> directives. The <tt>#if</tt>
+and <tt>#elif</tt> directives are followed by a constant name or an expression.
+For example, to include a group of options when "ADVANCED" is defined:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#_if'>#if</a> ADVANCED
+<a href='ref-ppdcfile.html#Group'>Group</a> "Advanced/Advanced Options"
+ <a href='ref-ppdcfile.html#Option'>Option</a> "fooCyanAdjust/Cyan Adjustment"
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus10/+10%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus5/+5%" ""
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> "none/No Adjustment" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus5/-5%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus10/-10%" ""
+ <a href='ref-ppdcfile.html#Option'>Option</a> "fooMagentaAdjust/Magenta Adjustment"
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus10/+10%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus5/+5%" ""
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> "none/No Adjustment" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus5/-5%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus10/-10%" ""
+ <a href='ref-ppdcfile.html#Option'>Option</a> "fooYellowAdjust/Yellow Adjustment"
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus10/+10%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus5/+5%" ""
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> "none/No Adjustment" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus5/-5%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus10/-10%" ""
+ <a href='ref-ppdcfile.html#Option'>Option</a> "fooBlackAdjust/Black Adjustment"
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus10/+10%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus5/+5%" ""
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> "none/No Adjustment" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus5/-5%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus10/-10%" ""
+<a href='ref-ppdcfile.html#_endif'>#endif</a>
+</pre>
+
+
+<h3><a name='CONSTRAINTS'>Defining Constraints</a></h3>
+
+<P>Constraints are strings that are used to specify that one or more option
+choices are incompatible, for example two-sided printing on transparency media.
+Constraints are also used to prevent the use of uninstalled features such as the
+duplexer unit, additional media trays, and so forth.</P>
+
+<P>The <TT>UIConstraints</TT> directive is used to specify a constraint that is
+placed in the PPD file. The directive is followed by a string using one of the
+following formats:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*Option1 *Option2"
+<a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*Option1 Choice1 *Option2"
+<a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*Option1 *Option2 Choice2"
+<a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*Option1 Choice1 *Option2 Choice2"
+</pre>
+
+<P>Each option name is preceded by the asterisk (<TT>*</TT>). If no choice is
+given for an option, then all choices <I>except</I> <TT>False</TT> and
+<TT>None</TT> will conflict with the other option and choice(s). Since the PPD
+compiler automatically adds reciprocal constraints (option A conflicts with
+option B, so therefore option B conflicts with option A), you need only specify
+the constraint once.</P>
+
+<p class='example'><a name="LISTING5">Listing 5: "examples/constraint.drv"</a></p>
+
+<pre class='example'>
+
+<I>// Include standard font and media definitions</I>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+
+<I>// List the fonts that are supported, in this case all standard fonts...</I>
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+
+<I>// Manufacturer, model name, and version</I>
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "Foo"
+<a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+
+<I>// Each filter provided by the driver...</I>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-raster 100 rastertofoo
+
+<I>// Supported page sizes</I>
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+
+<I>// Supported resolutions</I>
+*<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "600dpi/600 DPI"
+
+<I>// Installable Option Group</I>
+<a href='ref-ppdcfile.html#Group'>Group</a> "InstallableOptions/Options Installed"
+
+ <I>// Duplexing unit option</I>
+ <a href='ref-ppdcfile.html#Option'>Option</a> "OptionDuplexer/Duplexing Unit" Boolean AnySetup 10
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> True/Installed ""
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> "False/Not Installed" ""
+
+<I>// General Option Group</I>
+<a href='ref-ppdcfile.html#Group'>Group</a> General
+
+ <I>// Duplexing option</I>
+ <a href='ref-ppdcfile.html#Option'>Option</a> "Duplex/Two-Sided Printing" PickOne AnySetup 10
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> "None/No" "&lt;&lt;/Duplex false&gt;&gt;setpagedevice""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "DuplexNoTumble/Long Edge Binding"
+ "&lt;&lt;/Duplex true/Tumble false&gt;&gt;setpagedevice""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "DuplexTumble/Short Edge Binding"
+ "&lt;&lt;/Duplex true/Tumble true&gt;&gt;setpagedevice""
+
+<I>// Only allow duplexing if the duplexer is installed</I>
+<a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*Duplex *OptionDuplexer False"
+
+<I>// Specify the name of the PPD file we want to generate...</I>
+<a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojet2k.ppd"
+</pre>
+
+<P><A HREF="#LISTING5">Listing 5</A> shows a variation of the first example with
+an added <TT>Duplex</TT> option and installable option for the duplexer,
+<TT>OptionDuplex</TT>. A constraint is added at the end to specify that any
+choice of the <TT>Duplex</TT> option that is not <TT>None</TT> is incompatible
+with the "Duplexer Installed" option set to "Not Installed"
+(<TT>False</TT>):</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*Duplex *OptionDuplexer False"
+</pre>
+
+<h4>Enhanced Constraints</h4>
+
+<p>CUPS 1.4 supports constraints between 2 or more options using the
+<TT>Attribute</TT> directive. <TT>cupsUIConstraints</TT> attributes define
+the constraints, while <TT>cupsUIResolver</TT> attributes define option changes
+to resolve constraints. For example, we can specify the previous duplex
+constraint with a resolver that turns off duplexing with the following two
+lines:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsUIConstraints DuplexOff "*Duplex *OptionDuplexer False"
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsUIResolver DuplexOff "*Duplex None"
+</pre>
+
+<h2 class='title'><a name='LOCALIZATION'>Localization</a></h2>
+
+<p>The PPD compiler provides localization of PPD files in different languages
+through <i>message catalog</i> files in the GNU gettext or Apple .strings
+formats. Each user text string and several key PPD attribute values such as
+<tt>LanguageVersion</tt> and <tt>LanguageEncoding</tt> are looked up in the
+corresponding message catalog and the translated text is substituted in the
+generated PPD files. One message catalog file can be used by multiple driver
+information files, and each file contains a single language translation.</p>
+
+<h3><a name='PPDPO'>The ppdpo Utility</a></h3>
+
+<p>While CUPS includes localizations of all standard media sizes and options in
+several languages, your driver information files may provide their own media
+sizes and options that need to be localized. CUPS provides a utility program to
+aid in the localization of drivers called <a
+href='man-ppdpo.html'><tt>ppdpo(1)</tt></a>. The <tt>ppdpo</tt> program creates
+or updates a message catalog file based upon one or more driver information
+files. New messages are added with the word "TRANSLATE" added to the front of
+the translation string to make locating new strings for translation easier. The
+program accepts the message catalog filename and one or more driver information
+files.</p>
+
+<p>For example, run the following command to create a new German message catalog
+called <var>de.po</var> for all of the driver information files in the current
+directory:</p>
+
+<pre class='command'>
+ppdpo -o de.po *.drv
+</pre>
+
+<p>If the file <var>de.po</var> already exists, <tt>ppdpo</tt> will update the
+contents of the file with any new messages that need to be translated. To create
+an Apple .strings file instead, specify the output filename with a .strings
+extension, for example:</p>
+
+<pre class='command'>
+ppdpo -o de.strings *.drv
+</pre>
+
+<h3><a name='PPDC_CATALOG'>Using Message Catalogs with the PPD Compiler</a></h3>
+
+<p>Once you have created a message catalog, use the <a
+href='ref-ppdcfile.html#_po'><tt>#po</tt></a> directive to declare it in each
+driver information file. For example, to declare the German message catalog for
+a driver use:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#_po'>#po</a> de "de.po" // German
+</pre>
+
+<p>In fact, you can use the <tt>#po</tt> directive as many times as needed:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#_po'>#po</a> de "de.po" // German
+<a href='ref-ppdcfile.html#_po'>#po</a> es "es.po" // Spanish
+<a href='ref-ppdcfile.html#_po'>#po</a> fr "fr.po" // French
+<a href='ref-ppdcfile.html#_po'>#po</a> it "it.po" // Italian
+<a href='ref-ppdcfile.html#_po'>#po</a> ja "ja.po" // Japanese
+</pre>
+
+<p>The filename ("de.po", etc.) can be relative to the location of the driver
+information file or an absolute path. Once defined, the PPD compiler will
+automatically generate a globalized PPD for every language declared in your
+driver information file. To generate a single-language PPD file, simply use the
+<tt>-l</tt> option to list the corresponding locale, for example:</p>
+
+<pre class='command'>
+ppdc -l de -d ppd/de mydrivers.drv
+</pre>
+
+<p>to generate German PPD files.</p>
+</div>
+</body>
+</html>
diff --git a/doc/help/raster-driver.html b/doc/help/raster-driver.html
new file mode 100644
index 000000000..2ec3f4e5a
--- /dev/null
+++ b/doc/help/raster-driver.html
@@ -0,0 +1,579 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Programming -->
+<head>
+ <title>Developing Raster Printer Drivers </title>
+ <meta name="keywords" content="Programming">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: raster-driver.html 9740 2011-05-04 06:26:22Z mike $"
+
+ Raster printer driver documentation for CUPS.
+
+ Copyright 2007-2010 by Apple Inc.
+ Copyright 1997-2007 by Easy Software Products.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Developing Raster Printer Drivers</h1>
+
+<p>This document describes how to develop printer drivers for raster printers. Topics include: <a href='#BASICS'>printer driver basics</a>, <a href='#CREATE'>creating new PPD files</a>, <a href='#FILTERS'>using filters</a>, <a href='#COLOR'>implementing color management</a>, and <a href='#MACOSX'>adding Mac OS X features</a>.</p>
+
+<div class='summary'><table summary='General Information'>
+<tbody>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='postscript-driver.html'>Developing PostScript Printer Drivers</a><br>
+ Programming: <a href='api-filter.html'>Filter and Backend Programming</a><br>
+ Programming: <a href='ppd-compiler.html'>Introduction to the PPD Compiler</a><br>
+ Programming: <a href='api-raster.html'>Raster API</a><br>
+ References: <a href='ref-ppdcfile.html'>PPD Compiler Driver Information File Reference</a><br>
+ Specifications: <a href='spec-ppd.html'>CUPS PPD Extensions</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#BASICS">Printer Driver Basics</a></li>
+<li><a href="#CREATING">Creating New PPD Files</a></li>
+<li><a href="#FILTERS">Using Filters</a></li>
+<li><a href="#COLOR">Implementing Color Management</a></li>
+<li><a href="#MACOSX">Adding Mac OS X Features</a></li>
+</ul>
+<h2 class='title'><a name='BASICS'>Printer Driver Basics</a></h2>
+
+<p>A CUPS raster printer driver consists of a PostScript Printer Description (PPD) file that describes the features and capabilities of the device, one or more <em>filter</em> programs that prepare print data for the device, and zero or more support files for color management, online help, and so forth. The PPD file includes references to all of the filters and support files used by the driver.</p>
+
+<p>Every time a user prints something the scheduler program, <a href='man-cupsd.html'>cupsd(8)</a>, determines the format of the print job and the programs required to convert that job into something the printer understands. CUPS includes filter programs for many common formats, for example to convert Portable Document Format (PDF) files into CUPS raster data. <a href='#FIGURE_1'>Figure 1</a> shows the data flow of a typical print job.</p>
+
+<div class='figure'><table summary='Raster Filter Chain'>
+<caption>Figure 1: <a name='FIGURE_1'>Raster Filter Chain</a></caption>
+<tr><td><img src='../images/cups-raster-chain.png' width='700' height='150' alt='Raster Filter Chain'></td></tr>
+</table></div>
+
+<p>The raster filter converts CUPS raster data into a format the printer understands, for example HP-PCL. CUPS includes several sample raster filters supporting standard page description languages (PDLs). <a href='#TABLE_1'>Table 1</a> shows the raster filters that are bundled with CUPS and the languages they support.</p>
+
+<div class='table'><table summary='Standard CUPS Raster Filters'>
+<caption>Table 1: <a name='TABLE_1'>Standard CUPS Raster Filters</a></caption>
+<thead>
+<tr><th>Filter</th><th>PDLs</th><th>ppdc DriverType</th><th>ppdc #include file</th></tr>
+</thead>
+<tbody>
+<tr><td>rastertoepson</td><td>ESC/P, ESC/P2</td><td>epson</td><td>epson.h</td></tr>
+<tr><td>rastertoescpx</td><td>ESC/P, ESC/P2, EPSON Remote Mode</td><td>escp</td><td>escp.h</td></tr>
+<tr><td>rastertohp</td><td>HP-PCL3, HP-PCL5</td><td>hp</td><td>hp.h</td></tr>
+<tr><td>rastertolabel</td><td>CPCL, Dymo, EPL1, EPL2, Intellitech PCL, ZPL</td><td>label</td><td>label.h</td></tr>
+<tr><td>rastertopclx</td><td>HP-RTL, HP-PCL3, HP-PCL3GUI, HP-PCL5, HP-PCL5c, HP-PCL5e</td><td>pcl</td><td>pcl.h</td></tr>
+</tbody>
+</table></div>
+
+<p>The optional port monitor handles interface-specific protocol or encoding issues. For example, some raster printers use the 1284.4 communications protocol.</p>
+
+<p>The backend handles communications with the printer, sending print data from the last filter to the printer and relaying back-channel data from the printer to the upstream filters. CUPS includes backend programs for common direct-connect interfaces and network protocols, and you can provide your own backend to support custom interfaces and protocols.</p>
+
+<p>The scheduler also supports a special "command" file format for sending maintenance commands and status queries to a printer or printer driver. Command print jobs typically use a single command filter program defined in the PPD file to generate the appropriate printer commands and handle any responses from the printer. <a href='#FIGURE_2'>Figure 2</a> shows the data flow of a typical command job.</p>
+
+<div class='figure'><table summary='Command Filter Chain'>
+<caption>Figure 2: <a name='FIGURE_2'>Command Filter Chain</a></caption>
+<tr><td><img src='../images/cups-command-chain.png' width='575' height='150' alt='Command Filter Chain'></td></tr>
+</table></div>
+
+<p>Raster printer drivers must provide their own command filter.</p>
+
+
+<h2 class='title'><a name='CREATING'>Creating New PPD Files</a></h2>
+
+<p>We recommend using the CUPS PPD compiler, <a href='man-ppdc.html'>ppdc(1)</a>, to create new PPD files since it manages many of the tedious (and error-prone!) details of paper sizes and localization for you. It also allows you to easily support multiple devices from a single source file. For more information see the "<a href='ppd-compiler.html'>Introduction to the PPD Compiler</a>" document. <a href='#LISTING_1'>Listing 1</a> shows a driver information file for several similar black-and-white HP-PCL5 laser printers.</p>
+
+<p class='example'>Listing 1: <a name='LISTING_1'>"examples/laserjet-basic.drv"</a></p>
+
+<pre class='example'>
+<I>// Include standard font and media definitions</I>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+
+<I>// Include HP-PCL driver definitions</I>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;pcl.h&gt;
+
+<I>// Specify that this driver uses the HP-PCL driver...</I>
+<a href='ref-ppdcfile.html#DriverType'>DriverType</a> pcl
+
+<I>// Specify the driver options via the model number...</I>
+<a href='ref-ppdcfile.html#ModelNumber'>ModelNumber</a> ($PCL_PAPER_SIZE $PCL_PJL $PCL_PJL_RESOLUTION)
+
+<I>// List the fonts that are supported, in this case all standard fonts...</I>
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+
+<I>// Manufacturer and driver version</I>
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "HP"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+
+<I>// Supported page sizes and their margins</I>
+<a href='ref-ppdcfile.html#HWMargins'>HWMargins</a> 18 12 18 12
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Legal
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Executive
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Monarch
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Statement
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> FanFoldGermanLegal
+
+<a href='ref-ppdcfile.html#HWMargins'>HWMargins</a> 18 12.72 18 12.72
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Env10
+
+<a href='ref-ppdcfile.html#HWMargins'>HWMargins</a> 9.72 12 9.72 12
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A5
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> B5
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> EnvC5
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> EnvDL
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> EnvISOB5
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Postcard
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> DoublePostcard
+
+<I>// Only black-and-white output with mode 3 compression...</I>
+<a href='ref-ppdcfile.html#ColorModel'>ColorModel</a> Gray k chunky 3
+
+<I>// Supported resolutions</I>
+<a href='ref-ppdcfile.html#Resolution'>Resolution</a> - 1 0 0 0 "300dpi/300 DPI"
+*<a href='ref-ppdcfile.html#Resolution'>Resolution</a> - 8 0 0 0 "600dpi/600 DPI"
+
+<I>// Supported input slots</I>
+*<a href='ref-ppdcfile.html#InputSlot'>InputSlot</a> 7 "Auto/Automatic Selection"
+<a href='ref-ppdcfile.html#InputSlot'>InputSlot</a> 2 "Manual/Tray 1 - Manual Feed"
+<a href='ref-ppdcfile.html#InputSlot'>InputSlot</a> 4 "Upper/Tray 1"
+<a href='ref-ppdcfile.html#InputSlot'>InputSlot</a> 1 "Lower/Tray 2"
+<a href='ref-ppdcfile.html#InputSlot'>InputSlot</a> 5 "LargeCapacity/Tray 3"
+
+<I>// Tray 3 is an option...</I>
+<a href='ref-ppdcfile.html#Installable'>Installable</a> "OptionLargeCapacity/Tray 3 Installed"
+<a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*OptionLargeCapacity False *InputSlot LargeCapacity"
+
+{
+ <I>// HP LaserJet 2100 Series</I>
+ <a href='ref-ppdcfile.html#Throughput'>Throughput</a> 10
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "LaserJet 2100 Series"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "hpljt211.ppd"
+}
+
+{
+ <I>// LaserJet 2200 and 2300 series have duplexer option...</I>
+ <a href='ref-ppdcfile.html#Duplex'>Duplex</a> normal
+ <a href='ref-ppdcfile.html#Installable'>Installable</a> "OptionDuplex/Duplexer Installed"
+ <a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*OptionDuplex False *Duplex"
+
+ {
+ <I>// HP LaserJet 2200 Series</I>
+ <a href='ref-ppdcfile.html#Throughput'>Throughput</a> 19
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "LaserJet 2200 Series"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "hpljt221.ppd"
+ }
+
+ {
+ <I>// HP LaserJet 2300 Series</I>
+ <a href='ref-ppdcfile.html#Throughput'>Throughput</a> 25
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "LaserJet 2300 Series"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "hpljt231.ppd"
+ }
+}
+</pre>
+
+
+<h2 class='title'><a name='FILTERS'>Using Filters</a></h2>
+
+<p>The standard CUPS raster filters can be specified using the
+<a href='ref-ppdcfile.html#DriverType'><tt>DriverType</tt></a> directive, for example:</p>
+
+<pre class='example'>
+<I>// Specify that this driver uses the HP-PCL driver...</I>
+<a href='ref-ppdcfile.html#DriverType'>DriverType</a> pcl
+</pre>
+
+<p><a href='#TABLE_1'>Table 1</a> shows the driver types for each of the standard CUPS raster filters. For drivers that do not use the standard raster filters, the "custom" type is used with <a href='ref-ppdcfile.html#Filter'><tt>Filter</tt></a> directives:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#DriverType'>DriverType</a> custom
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-raster 100 /path/to/raster/filter
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-command 100 /path/to/command/filter
+</pre>
+
+
+<h2 class='title'><a name='COLOR'>Implementing Color Management</a></h2>
+
+<p>CUPS uses ICC color profiles to provide more accurate color reproduction. The <a href='spec-ppd.html#cupsICCProfile'><tt>cupsICCProfile</tt></a> attribute defines the color profiles that are available for a given printer, for example:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsICCProfile "ColorModel.MediaType.Resolution/Description" /path/to/ICC/profile
+</pre>
+
+<p>where "ColorModel.MediaType.Resolution" defines a selector based on the corresponding option selections. A simple driver might only define profiles for the color models that are supported, for example a printer supporting Gray and RGB might use:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsICCProfile "Gray../Grayscale Profile" /path/to/ICC/gray-profile
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsICCProfile "RGB../Full Color Profile" /path/to/ICC/rgb-profile
+</pre>
+
+<p>The options used for profile selection can be customized using the <tt>cupsICCQualifier2</tt> and <tt>cupsICCQualifier3</tt> attributes.</p>
+
+<h3><span class='info'>Since Mac OS X 10.5</span>Custom Color Matching Support</h3>
+
+<p>Mac OS X printer drivers that are based on an existing standard RGB colorspace can tell the system to use the corresponding colorspace instead of an arbitrary ICC color profile when doing color management. The <a href='#APCustom'><tt>APSupportsCustomColorMatching</tt></a> and <tt>APDefaultCustomColorMatchingProfile</tt> attributes can be used to enable this mode:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APSupportsCustomColorMatching "" true
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APDefaultCustomColorMatchingProfile "" sRGB
+</pre>
+
+
+<h2 class='title'><a name='MACOSX'>Adding Mac OS X Features</a></h2>
+
+<p>Mac OS X printer drivers can provide <a href='spec-ppd.html#MACOSX'>additional attributes</a> to specify additional option panes in the print dialog, an image of the printer, a help book, and option presets for the driver software:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APDialogExtension "" /Library/Printers/Vendor/filename.plugin
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APHelpBook "" /Library/Printers/Vendor/filename.bundle
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APPrinterIconPath "" /Library/Printers/Vendor/filename.icns
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APPrinterPreset "name/text" "*option choice ..."
+</pre>
+</div>
+</body>
+</html>
diff --git a/doc/help/ref-access_log.html b/doc/help/ref-access_log.html
new file mode 100644
index 000000000..015ea17bd
--- /dev/null
+++ b/doc/help/ref-access_log.html
@@ -0,0 +1,140 @@
+<HTML>
+<!-- SECTION: References -->
+<HEAD>
+ <TITLE>access_log</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">access_log</H1>
+
+<P>The <VAR>access_log</VAR> file lists each HTTP resource that
+is accessed by a web browser or client. Each line is in an
+extended version of the so-called "Common Log Format" used by
+many web servers and web reporting tools:</P>
+
+<P CLASS="command">
+
+host group user date-time \"method resource version\" status
+bytes ipp-operation ipp-status<BR>
+
+<BR>
+
+10.0.1.2 - - [01/Dec/2005:21:50:28 +0000] "POST / HTTP/1.1" 200
+317 CUPS-Get-Printers
+successful-ok-ignored-or-substituted-attributes<BR>
+
+localhost - - [01/Dec/2005:21:50:32 +0000] "GET /admin HTTP/1.1"
+200 0 - -<BR>
+
+localhost - - [01/Dec/2005:21:50:32 +0000] "POST / HTTP/1.1" 200
+157 CUPS-Get-Printers
+successful-ok-ignored-or-substituted-attributes<BR>
+
+localhost - - [01/Dec/2005:21:50:32 +0000] "POST / HTTP/1.1" 200
+1411 CUPS-Get-Devices -<BR>
+
+localhost - - [01/Dec/2005:21:50:32 +0000] "GET /admin HTTP/1.1"
+200 6667 - -<BR>
+
+</P>
+
+<P>The <I>host</I> field will normally only be an IP address
+unless you have enabled the <A
+HREF="ref-cupsd-conf.html#HostNameLookups"><CODE>HostNameLookups</CODE></A>
+directive in the <VAR>cupsd.conf</VAR> file or if the IP address
+corresponds to your local machine.</P>
+
+<P>The <I>group</I> field always contains "-".</P>
+
+<P>The <I>user</I> field is the authenticated username of the
+requesting user. If no username and password is supplied for the
+request then this field contains "-".</P>
+
+<P>The <I>date-time</I> field is the date and time of the request
+in local time and is in the format:</P>
+
+<P CLASS="command">
+[DD/MON/YYYY:HH:MM:SS +ZZZZ]
+</P>
+
+<P>The <I>method</I> field is the HTTP method used: "GET",
+"OPTIONS", "PUT", or "POST". "GET" requests are used to get files
+from the server, both for the web interface and to get
+configuration and log files. "OPTIONS" requests are used to
+upgrade connections to TLS encryption. "PUT" requests are used to
+upload configuration files. "POST" requests are used for web
+interface forms and IPP requests.</P>
+
+<P>The <I>resource</I> field is the filename of the requested
+resource.</P>
+
+<P>The <I>version</I> field is the HTTP specification version used by the
+client. For CUPS clients this will always be "HTTP/1.1".</P>
+
+<P>The <I>status</I> field contains the HTTP result status of the
+request, as follows:</P>
+
+<UL>
+
+ <LI><CODE>200</CODE> - Successful operation.</LI>
+
+ <LI><CODE>201</CODE> - File created/modified successfully.</LI>
+
+ <LI><CODE>304</CODE> - The requested file has not changed.</LI>
+
+ <LI><CODE>400</CODE> - Bad HTTP request; typically this
+ means that you have a malicious program trying to access
+ your server.</LI>
+
+ <LI><CODE>401</CODE> - Unauthorized, authentication
+ (username + password) is required.</LI>
+
+ <LI><CODE>403</CODE> - Access is forbidden; typically
+ this means that a client tried to access a file or
+ resource they do not have permission to access.</LI>
+
+ <LI><CODE>404</CODE> - The file or resource does not
+ exist.</LI>
+
+ <LI><CODE>405</CODE> - URL access method is not allowed;
+ typically this means you have a web browser using your
+ server as a proxy.</LI>
+
+ <LI><CODE>413</CODE> - Request too large; typically this
+ means that a client tried to print a file larger than the
+ <A
+ HREF="ref-cupsd-conf.html#MaxRequestSize"><CODE>MaxRequestSize</CODE></A>
+ allows.</LI>
+
+ <LI><CODE>426</CODE> - Upgrading to TLS-encrypted
+ connection.</LI>
+
+ <LI><CODE>500</CODE> - Server error; typically this
+ happens when the server is unable to open/create a file -
+ consult the <VAR>error_log</VAR> file for details.</LI>
+
+ <LI><CODE>501</CODE> - The client requested encryption
+ but encryption support is not enabled/compiled in.</LI>
+
+ <LI><CODE>505</CODE> - HTTP version number not supported;
+ typically this means that you have a malicious program
+ trying to access your server.</LI>
+
+</UL>
+
+<P>The <I>bytes</I> field contains the number of bytes in the
+request. For POST requests the <I>bytes</I> field contains the
+number of bytes of non-IPP data that is received from the
+client.</P>
+
+<P>The <I>ipp-operation</I> field contains either "-" for non-IPP
+requests or the IPP operation name for POST requests containing
+an IPP request.</P>
+
+<P>The <I>ipp-status</I> field contains either "-" for non-IPP
+requests or the IPP status code name for POST requests containing
+an IPP response.</P>
+
+</BODY>
+</HTML>
diff --git a/doc/help/ref-classes-conf.html b/doc/help/ref-classes-conf.html
new file mode 100644
index 000000000..40bc3d5e2
--- /dev/null
+++ b/doc/help/ref-classes-conf.html
@@ -0,0 +1,566 @@
+<HTML>
+<!-- SECTION: References -->
+<HEAD>
+ <TITLE>classes.conf</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">classes.conf</H1>
+
+<P>The CUPS scheduler (cupsd) uses the
+<VAR>/etc/cups/classes.conf</VAR> file to store the list of
+available classes. This file contains only locally defined
+classes, not remote classes that are created automatically via
+browsing. Each directive is listed on a line by itself followed
+by its value. Comments are introduced using the number sign ("#")
+character at the beginning of a line.</P>
+
+<P>While the class configuration file consists of plain text and
+can be modified using your favorite text editor, you should
+normally use the <A HREF="man-lpadmin.html">lpadmin(8)</A>
+command, web interface, or any of the available GUIs to manage
+your classes instead. If you do choose to edit this file
+manually, you will need to stop the scheduler first, make your
+changes, and then start the scheduler to make them active.</P>
+
+
+<H2 CLASS="title"><A NAME="Accepting">Accepting</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ Accepting yes
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Accepting</CODE> directive defines the initial state
+of the <VAR>printer-is-accepting-jobs</VAR> attribute. This state
+is also set by the <CODE>accept(8)</CODE> and
+<CODE>reject(8)</CODE> commands:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/accept classname
+/usr/sbin/reject classname</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="AllowUser">AllowUser</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ AllowUser foo_user
+ AllowUser @bar_group
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>AllowUser</CODE> directive adds a username or group
+name to the <VAR>requesting-user-name-allowed</VAR> attribute
+which can be set by the <CODE>lpadmin(8)</CODE> command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p classname -u allow:foo_user,@bar_group</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A> directive.
+This directive cannot be used with <A
+HREF="#DenyUser"><CODE>DenyUser</CODE></A>.</P>
+
+
+<H2 CLASS="title"><A NAME="Class">Class</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Class</CODE> directive begins a class definition.
+Classes are added using the <CODE>lpadmin(8)</CODE> command:
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -c classname</KBD>
+</PRE>
+
+
+<H2 CLASS="title"><A NAME="DefaultClass">DefaultClass</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;DefaultClass name&gt;
+ ...
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DefaultClass</CODE> directive begins a class
+definition as the default server destination. The default server
+destination can be set using the <CODE>lpadmin(8)</CODE>
+command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -d classname</KBD>
+</PRE>
+
+<P>Note that the server default destination settings can be
+overridden by the user's default destination settings which are
+normally set using the <CODE>lpoptions(1)</CODE> command.</P>
+
+
+<H2 CLASS="title"><A NAME="DenyUser">DenyUser</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ DenyUser foo_user
+ DenyUser @bar_group
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DenyUser</CODE> directive adds a username or group
+name to the <VAR>requesting-user-name-denied</VAR> attribute
+which can be set by the <CODE>lpadmin(8)</CODE> command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p classname -u deny:foo_user,@bar_group</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A> directive.
+This directive cannot be used with <A
+HREF="#AllowUser"><CODE>AllowUser</CODE></A></P>
+
+
+<H2 CLASS="title"><A NAME="Info">Info</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ Info My Class
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Info</CODE> directive defines the string for the
+<VAR>printer-info</VAR> attribute. It is normally set using the
+<CODE>lpadmin(8)</CODE> command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p classname -D "My Class"</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="JobSheets">JobSheets</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ JobSheets none,standard
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>JobSheets</CODE> directive specifies the default
+banner pages to print before and after a print job. In the above
+example, only a <VAR>standard</VAR> banner will print after each
+job. The <CODE>lpadmin(8)</CODE> command is normally used to set
+the default banners:
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p classname -o job-sheets-default=none,standard</KBD>
+</PRE>
+
+<P>If only one banner file is specified, it will be printed
+before the files in the job. If a second banner file is
+specified, it is printed after the files in the job.</P>
+
+<P>The available banner pages depend on the local system
+configuration; CUPS includes the following standard banner
+files:</P>
+
+<UL>
+
+ <LI><CODE>none</CODE> - Do not produce a banner
+ page.</LI>
+
+ <LI><CODE>classified</CODE> - A banner page with a
+ &quot;classified&quot; label at the top and bottom.</LI>
+
+ <LI><CODE>confidential</CODE> - A banner page with a
+ &quot;confidential&quot; label at the top and bottom.</LI>
+
+ <LI><CODE>secret</CODE> - A banner page with a
+ &quot;secret&quot; label at the top and bottom.</LI>
+
+ <LI><CODE>standard</CODE> - A banner page with no label
+ at the top and bottom.</LI>
+
+ <LI><CODE>topsecret</CODE> - A banner page with a
+ &quot;top secret&quot; label at the top and bottom.</LI>
+
+ <LI><CODE>unclassified</CODE> - A banner page with an
+ &quot;unclassified&quot; label at the top and bottom.</LI>
+
+</UL>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="KLimit">KLimit</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ KLimit 1234
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>KLimit</CODE> directive defines the value of the
+<VAR>job-k-limit</VAR> attribute. It is normally set using the
+<CODE>lpadmin(8)</CODE> command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p classname -o job-k-limit=1234</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="Location">Location</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ Location Building 3321
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Location</CODE> directive defines the string for the
+<VAR>printer-location</VAR> attribute. It is normally set using the
+<CODE>lpadmin(8)</CODE> command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p classname -L "Building 3321"</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2</SPAN><A NAME="OpPolicy">OpPolicy</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ OpPolicy default
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>OpPolicy</CODE> directive sets the operation policy
+that is used for the printer. The <CODE>lpadmin(8)</CODE> command
+sets the current operation policy:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p classname -o printer-op-policy=default</KBD>
+</PRE>
+
+<P>The default policy is named "default". All policies correspond
+to those defined using the <VAR>cupsd.conf</VAR> <A
+HREF="ref-cupsd-conf.html#Policy"><CODE>Policy</CODE></A>
+section.</P>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2</SPAN><A NAME="Option">Option</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ Option name value
+ Option scaling 100
+ Option page-left 72
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Option</CODE> directive specifies a default job
+template attribute value. It is mapped to
+<CODE>name-default</CODE> in the printer attributes and applied
+to jobs as <CODE>name</CODE>.</P>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="PageLimit">PageLimit</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ PageLimit 1234
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>PageLimit</CODE> directive defines the value of the
+<VAR>job-page-limit</VAR> attribute. It can be set using the
+<CODE>lpadmin(8)</CODE> command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p classname -o job-page-limit=1234</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="Printer">Printer</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ Printer foo
+ Printer bar
+ Printer bleep
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Printer</CODE> directive adds a printer to a class.
+Printers are added to a class using the <CODE>lpadmin(8)</CODE>
+command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -c classname</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="QuotaPeriod">QuotaPeriod</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ QuotaPeriod 604800
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>QuotaPeriod</CODE> directive defines the value of
+the <VAR>job-quota-period</VAR> attribute. Typical values are
+86400 (1 day), 604800 (1 week), 2592000 (1 month), and 31536000
+(1 year). It is set using the <CODE>lpadmin(8)</CODE>
+command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p classname -o job-quota-period=604800</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2</SPAN><A NAME="Shared">Shared</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ Shared yes
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Shared</CODE> directive defines the initial value of
+the <VAR>printer-is-shared</VAR> attribute. The strings
+<VAR>yes</VAR> and <VAR>no</VAR> correspond to the true and false
+values, respectively. The <CODE>lpadmin(8)</CODE> command sets
+the current state:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p classname -o printer-is-shared=true</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="State">State</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ State idle
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>State</CODE> directive defines the initial value of
+the <VAR>printer-state</VAR> attribute. The strings
+<VAR>idle</VAR> and <VAR>stopped</VAR> correspond to the IPP
+enumeration values 3 and 5, respectively. The
+<CODE>cupsenable(8)</CODE> and <CODE>cupsdisable(8)</CODE>
+commands set the current state:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/cupsenable classname</KBD>
+<KBD>/usr/sbin/cupsdisable classname</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="StateMessage">StateMessage</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ StateMessage Ready to print.
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>StateMessage</CODE> directive defines the initial
+string for the <VAR>printer-state-message</VAR> attribute. The
+following are some example messages:</P>
+
+<PRE CLASS="command">
+StateMessage Connected to host_name...
+StateMessage Connecting to printer_queue on port port_number...
+StateMessage Network host host_name is busy; will retry in 30 seconds...
+StateMessage Class busy; will retry in 10 seconds...
+StateMessage Class is busy; retrying print job...
+StateMessage Print file accepted - job ID id_number.
+StateMessage Ready to print.
+StateMessage Waiting for job to complete
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2</SPAN><A NAME="StateTime">StateTime</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Class name&gt;
+ ...
+ StateTime 1133542425
+&lt;/Class&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>StateTime</CODE> directive defines the UNIX time
+(seconds since Jan 1, 1970) for the last state change of the
+queue. It is mapped to the <VAR>printer-state-change-time</VAR>
+attribute.</P>
+
+<P>This directive must appear inside a <A
+HREF="#Class"><CODE>Class</CODE></A> or <A
+HREF="#DefaultClass"><CODE>DefaultClass</CODE></A>
+section.</P>
+
+
+</BODY>
+</HTML>
diff --git a/doc/help/ref-client-conf.html b/doc/help/ref-client-conf.html
new file mode 100644
index 000000000..0229b0040
--- /dev/null
+++ b/doc/help/ref-client-conf.html
@@ -0,0 +1,56 @@
+<HTML>
+<!-- SECTION: References -->
+<HEAD>
+ <TITLE>client.conf</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">client.conf</H1>
+
+<P>The <VAR>/etc/cups/client.conf</VAR> and
+<VAR>~/.cups/client.conf</VAR> files contain up to two directives
+that determine how the client behaves. Each directive is listed
+on a line by itself followed by its value. Comments are
+introduced using the number sign ("#") character at the beginning
+of a line.</P>
+
+<H2 CLASS="title"><A NAME="Encryption">Encryption</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+Encryption Never
+Encryption IfRequested
+Encryption Required
+Encryption Always
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Encryption</CODE> directive specifies the default
+encryption settings for the client.</P>
+
+<P>The default setting is <VAR>IfRequested</VAR>.</P>
+
+
+<H2 CLASS="title"><A NAME="ServerName">ServerName</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ServerName foo.bar.com
+ServerName 11.22.33.44
+ServerName foo.bar.com:8631
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ServerName</CODE> directive specifies sets the remote server that is to be used for all client operations. That is, it redirects all client requests to the remote server.</P>
+
+<P>The default port number is 631 but can be overridden by adding a colon followed by the desired port number to the value.</P>
+
+<P>The default is to use the local server ("<VAR>localhost</VAR>") or domain socket, if so configured.</P>
+
+</BODY>
+</HTML>
diff --git a/doc/help/ref-cupsd-conf.html.in b/doc/help/ref-cupsd-conf.html.in
new file mode 100644
index 000000000..736a0b3b5
--- /dev/null
+++ b/doc/help/ref-cupsd-conf.html.in
@@ -0,0 +1,3198 @@
+<HTML>
+<!-- SECTION: References -->
+<HEAD>
+ <TITLE>cupsd.conf</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">cupsd.conf</H1>
+
+<P>The <VAR>/etc/cups/cupsd.conf</VAR> file contains
+configuration <I>directives</I> that control how the server
+functions. Each directive is listed on a line by itself followed
+by its value. Comments are introduced using the number sign ("#")
+character at the beginning of a line.</P>
+
+<P>Since the server configuration file consists of plain text,
+you can use your favorite text editor to make changes to it.
+After making any changes, restart the <CODE>cupsd(8)</CODE>
+process using the startup script for your operating system:</P>
+
+<UL>
+
+ <LI>AIX, IRIX, Linux, Solaris:
+ <PRE CLASS="command">
+/etc/init.d/cups restart
+ </PRE></LI>
+
+ <LI>HP-UX:
+ <PRE CLASS="command">
+/sbin/init.d/cups restart
+ </PRE></LI>
+
+ <LI>MacOS X:
+ <PRE CLASS="command">
+sudo launchctl unload /System/Library/LaunchDaemons/org.cups.cupsd.plist
+sudo launchctl load /System/Library/LaunchDaemons/org.cups.cupsd.plist
+ </PRE></LI>
+
+</UL>
+
+<P>You can also edit this file from the CUPS web interface, which
+automatically handles restarting the scheduler.</P>
+
+
+<H2 CLASS="title"><A NAME="AccessLog">AccessLog</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+AccessLog /var/log/cups/access_log
+AccessLog /var/log/cups/access_log-%s
+AccessLog syslog
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>AccessLog</CODE> directive sets the name of the
+access log file. If the filename is not absolute then it is
+assumed to be relative to the <A
+HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
+access log file is stored in "common log format" and can be used
+by any web access reporting tool to generate a report on CUPS
+server activity.</P>
+
+<P>The server name can be included in the filename by using
+<CODE>%s</CODE> in the name.</P>
+
+<P>The special name "syslog" can be used to send the access
+information to the system log instead of a plain file.</P>
+
+<P>The default access log file is
+<VAR>@CUPS_LOGDIR@/access_log</VAR>.</P>
+
+
+<H2 CLASS="title"><A NAME="AccessLogLevel">AccessLogLevel</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+AccessLogLevel config
+AccessLogLevel actions
+AccessLogLevel all
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>AccessLogLevel</CODE> directive controls which requests are logged
+to the access log file. The following levels are defined:</P>
+
+<UL>
+
+ <LI><CODE>config</CODE>; Log when printers and classes are added,
+ deleted, or modified and when configuration files are accessed or
+ updated.</LI>
+
+ <LI><CODE>actions</CODE>; Log when print jobs are submitted,
+ held, released, modified, or canceled, and any of the conditions
+ for <CODE>config</CODE>.</LI>
+
+ <LI><CODE>all</CODE>; Log all requests.</LI>
+
+</UL>
+
+<P>The default access log level is <CODE>@CUPS_ACCESS_LOG_LEVEL@</CODE>.</P>
+
+
+<H2 CLASS="title"><A NAME="Allow">Allow</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Location /path&gt;
+ ...
+ Allow from All
+ Allow from None
+ Allow from *.example.com
+ Allow from .example.com
+ Allow from host.example.com
+ Allow from nnn.*
+ Allow from nnn.nnn.*
+ Allow from nnn.nnn.nnn.*
+ Allow from nnn.nnn.nnn.nnn
+ Allow from nnn.nnn.nnn.nnn/mm
+ Allow from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
+ Allow from [xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]
+ Allow from [xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]/mmm
+ Allow from @LOCAL
+ Allow from @IF(name)
+&lt;/Location&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Allow</CODE> directive specifies a hostname, IP
+address, or network that is allowed access to the server.
+<CODE>Allow</CODE> directives are cumulative, so multiple
+<CODE>Allow</CODE> directives can be used to allow access for
+multiple hosts or networks.</P>
+
+<P>Host and domain name matching require that you enable the <A
+HREF="#HostNameLookups"><CODE>HostNameLookups</CODE></A>
+directive.</P>
+
+<P>The <CODE>/mm</CODE> notation specifies a CIDR netmask, as shown in
+<A HREF="#TABLE1">Table 1</A>.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="CIDR Netmasks">
+<CAPTION>Table 1: <A NAME="TABLE1">CIDR Netmasks</A></CAPTION>
+<TR>
+ <TH WIDTH="10%">mm</TH>
+ <TH WIDTH="20%">netmask</TH>
+ <TH WIDTH="10%">mm</TH>
+ <TH WIDTH="20%">netmask</TH>
+</TR>
+<TR>
+ <TD ALIGN="CENTER">0</TD>
+ <TD ALIGN="CENTER">0.0.0.0</TD>
+ <TD ALIGN="CENTER">8</TD>
+ <TD ALIGN="CENTER">255.0.0.0</TD>
+</TR>
+<TR>
+ <TD ALIGN="CENTER">1</TD>
+ <TD ALIGN="CENTER">128.0.0.0</TD>
+ <TD ALIGN="CENTER">16</TD>
+ <TD ALIGN="CENTER">255.255.0.0</TD>
+</TR>
+<TR>
+ <TD ALIGN="CENTER">2</TD>
+ <TD ALIGN="CENTER">192.0.0.0</TD>
+ <TD ALIGN="CENTER">24</TD>
+ <TD ALIGN="CENTER">255.255.255.0</TD>
+</TR>
+<TR>
+ <TD ALIGN="CENTER">...</TD>
+ <TD ALIGN="CENTER">...</TD>
+ <TD ALIGN="CENTER">32</TD>
+ <TD ALIGN="CENTER">255.255.255.255</TD>
+</TR>
+</TABLE></DIV>
+
+<P>The <CODE>@LOCAL</CODE> name will allow access from all local
+interfaces. The <CODE>@IF(name)</CODE> name will allow access
+from the named interface. In both cases, CUPS only allows access
+from the network that the interface(s) are configured for -
+requests arriving on the interface from a foreign network will
+<em>not</em> be accepted.</P>
+
+<P>The <CODE>Allow</CODE> directive must appear inside a <A
+HREF="#Location"><CODE>Location</CODE></A> or <A
+HREF="#Limit"><CODE>Limit</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">Deprecated</SPAN><A NAME="AuthClass">AuthClass</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Location /path&gt;
+ ...
+ AuthClass Anonymous
+ AuthClass User
+ AuthClass System
+ AuthClass Group
+&lt;/Location&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>AuthClass</CODE> directive defines what level of
+authentication is required:</P>
+
+<UL>
+
+ <LI><CODE>Anonymous</CODE> - No authentication should be
+ performed (default)</LI>
+
+ <LI><CODE>User</CODE> - A valid username and password is
+ required</LI>
+
+ <LI><CODE>System</CODE> - A valid username and password
+ is required, and the username must belong to the "sys"
+ group; this can be changed using the <A
+ HREF="#SystemGroup"><CODE>SystemGroup</CODE></A>
+ directive</LI>
+
+ <LI><CODE>Group</CODE> - A valid username and password is
+ required, and the username must belong to the group named
+ by the <A
+ HREF="#AuthGroupName"><CODE>AuthGroupName</CODE></A>
+ directive</LI>
+
+</UL>
+
+<P>The <CODE>AuthClass</CODE> directive must appear inside a <A
+HREF="#Location"><CODE>Location</CODE></A> or <A
+HREF="#Limit"><CODE>Limit</CODE></A> section.</P>
+
+<P><B>This directive is deprecated and will be removed from a
+future release of CUPS.</B> Consider using the more flexible <A
+HREF="#Require"><CODE>Require</CODE></A> directive instead.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">Deprecated</SPAN><A NAME="AuthGroupName">AuthGroupName</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Location /path&gt;
+ ...
+ AuthGroupName mygroup
+ AuthGroupName lp
+&lt;/Location&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>AuthGroupName</CODE> directive sets the group to use
+for <CODE>Group</CODE> authentication.</P>
+
+<P>The <CODE>AuthGroupName</CODE> directive must appear inside a
+<A HREF="#Location"><CODE>Location</CODE></A> or <A
+HREF="#Limit"><CODE>Limit</CODE></A> section.</P>
+
+<P><B>This directive is deprecated and will be removed from a
+future release of CUPS.</B> Consider using the more flexible <A
+HREF="#Require"><CODE>Require</CODE></A> directive instead.</P>
+
+
+<H2 CLASS="title"><A NAME="AuthType">AuthType</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Location /path&gt;
+ ...
+ AuthType None
+ AuthType Basic
+ AuthType Digest
+ AuthType BasicDigest
+ AuthType Negotiate
+&lt;/Location&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>AuthType</CODE> directive defines the type of
+authentication to perform:</P>
+
+<UL>
+
+ <LI><CODE>None</CODE> - No authentication should be
+ performed (default)</LI>
+
+ <LI><CODE>Basic</CODE> - Basic authentication should be
+ performed using the UNIX password and group files</LI>
+
+ <LI><CODE>Digest</CODE> - Digest authentication should be
+ performed using the <VAR>/etc/cups/passwd.md5</VAR>
+ file</LI>
+
+ <LI><CODE>BasicDigest</CODE> - Basic authentication
+ should be performed using the
+ <VAR>/etc/cups/passwd.md5</VAR> file</LI>
+
+ <LI><CODE>Negotiate</CODE> - Kerberos authentication
+ should be performed</LI>
+
+</UL>
+
+<P>When using <CODE>Basic</CODE>, <CODE>Digest</CODE>,
+<CODE>BasicDigest</CODE>, or <CODE>Negotiate</CODE> authentication,
+clients connecting through the <CODE>localhost</CODE> interface can
+also authenticate using certificates.</P>
+
+<P>The <CODE>AuthType</CODE> directive must appear inside a <A
+HREF="#Location"><CODE>Location</CODE></A> or <A
+HREF="#Limit"><CODE>Limit</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="AutoPurgeJobs">AutoPurgeJobs</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+AutoPurgeJobs Yes
+AutoPurgeJobs No
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>AutoPurgeJobs</CODE> directive specifies whether or
+not to purge completed jobs once they are no longer required for
+quotas. This option has no effect if quotas are not enabled. The
+default setting is <CODE>No</CODE>.</P>
+
+
+<H2 CLASS="title"><A NAME="BrowseAddress">BrowseAddress</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseAddress 255.255.255.255:631
+BrowseAddress 192.0.2.255:631
+BrowseAddress host.example.com:631
+BrowseAddress @LOCAL
+BrowseAddress @IF(name)
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseAddress</CODE> directive specifies an address
+to send browsing information to. Multiple
+<CODE>BrowseAddress</CODE> directives can be specified to send
+browsing information to different networks or systems.</P>
+
+<P>The <CODE>@LOCAL</CODE> name will broadcast printer
+information to all local interfaces. The <CODE>@IF(name)</CODE>
+name will broadcast to the named interface.</P>
+
+<P>There is no default browse address.</P>
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>If you are using HP-UX 10.20 and a subnet that is not 24,
+16, or 8 bits, printer browsing (and in fact all broadcast
+reception) will not work. This problem appears to be fixed in
+HP-UX 11.0.</P>
+
+</BLOCKQUOTE>
+
+
+<H2 CLASS="title"><A NAME="BrowseAllow">BrowseAllow</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseAllow from all
+BrowseAllow from none
+BrowseAllow from 192.0.2
+BrowseAllow from 192.0.2.0/24
+BrowseAllow from 192.0.2.0/255.255.255.0
+BrowseAllow from *.example.com
+BrowseAllow from @LOCAL
+BrowseAllow from @IF(name)
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseAllow</CODE> directive specifies a system or
+network to accept browse packets from. The default is to accept
+browse packets from all hosts.</P>
+
+<P>Host and domain name matching require that you enable the <A
+HREF="#HostNameLookups"><CODE>HostNameLookups</CODE></A>
+directive.</P>
+
+<P>IP address matching supports exact matches, partial addresses that match
+networks using netmasks of 255.0.0.0, 255.255.0.0, and 255.255.255.0, or network
+addresses using the specified netmask or bit count. The <CODE>/mm</CODE>
+notation specifies a CIDR netmask, a shown in <A HREF="TABLE1">Table 1</A>.</P>
+
+<P>The <CODE>@LOCAL</CODE> name will allow browse data from all
+local interfaces. The <CODE>@IF(name)</CODE> name will allow
+browse data from the named interface. In both cases, CUPS only
+allows data from the network that the interface(s) are configured
+for - data arriving on the interface from a foreign network will
+<em>not</em> be allowed.</P>
+
+
+<H2 CLASS="title"><A NAME="BrowseDeny">BrowseDeny</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseDeny from all
+BrowseDeny from none
+BrowseDeny from 192.0.2
+BrowseDeny from 192.0.2.0/24
+BrowseDeny from 192.0.2.0/255.255.255.0
+BrowseDeny from *.example.com
+BrowseDeny from @LOCAL
+BrowseDeny from @IF(name)
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseDeny</CODE> directive specifies a system or
+network to reject browse packets from. The default is to not deny
+browse packets from any hosts.</P>
+
+<P>Host and domain name matching require that you enable the <A
+HREF="#HostNameLookups"><CODE>HostNameLookups</CODE></A>
+directive.</P>
+
+<P>IP address matching supports exact matches, partial addresses that match
+networks using netmasks of 255.0.0.0, 255.255.0.0, and 255.255.255.0, or network
+addresses using the specified netmask or bit count. The <CODE>/mm</CODE>
+notation specifies a CIDR netmask, a shown in <A HREF="TABLE1">Table 1</A>.</P>
+
+<P>The <CODE>@LOCAL</CODE> name will block browse data from all
+local interfaces. The <CODE>@IF(name)</CODE> name will block
+browse data from the named interface. In both cases, CUPS only
+blocks data from the network that the interface(s) are configured
+for - data arriving on the interface from a foreign network will
+<em>not</em> be blocked.</P>
+
+
+<H2 CLASS="title"><A NAME="BrowseInterval">BrowseInterval</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseInterval 0
+BrowseInterval 30
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseInterval</CODE> directive specifies the
+maximum amount of time between browsing updates. Specifying a
+value of 0 seconds disables outgoing browse updates but allows a
+server to receive printer information from other hosts.</P>
+
+<P>The <CODE>BrowseInterval</CODE> value should always be less
+than the <A HREF="#BrowseTimeout"><CODE>BrowseTimeout</CODE></A>
+value. Otherwise printers and classes will disappear from client
+systems between updates.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="BrowseLDAPBindDN">BrowseLDAPBindDN</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseLDAPBindDN foo
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseLDAPBindDN</CODE> directive specifies the LDAP
+domain name to use when listening for printer registrations. The
+default is undefined.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.4/Mac OS X 10.6</SPAN><A NAME="BrowseLDAPCACertFile">BrowseLDAPCACertFile</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseLDAPCACertFile /etc/cups/ssl/certs
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseLDAPCACertFile</CODE> directive specifies the SSL certificate
+authority file to use for LDAP + SSL. The default is undefined.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="BrowseLDAPDN">BrowseLDAPDN</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseLDAPDN bar
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseLDAPDN</CODE> directive specifies the LDAP
+domain name to use when registering local shared printers. The
+default is undefined.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="BrowseLDAPPassword">BrowseLDAPPassword</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseLDAPPassword foo123
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseLDAPPassword</CODE> directive specifies the
+access password to use when connecting to the LDAP server. The
+default is undefined.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="BrowseLDAPServer">BrowseLDAPServer</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseLDAPServer localhost
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseLDAPServer</CODE> directive specifies the name
+of the LDAP server to connect to. The default is undefined.</P>
+
+
+<H2 CLASS="title"><A NAME="BrowseLocalOptions">BrowseLocalOptions</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseLocalOptions compression=yes
+BrowseLocalOptions encryption=required
+BrowseLocalOptions compression=yes&amp;encryption=required
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseLocalOptions</CODE> directive specifies
+additional IPP backend options to advertise with local shared
+printers. The default is to not include any options.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="BrowseLocalProtocols">BrowseLocalProtocols</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseLocalProtocols all
+BrowseLocalProtocols none
+BrowseLocalProtocols cups
+BrowseLocalProtocols dnssd
+BrowseLocalProtocols ldap
+BrowseLocalProtocols lpd
+BrowseLocalProtocols slp
+BrowseLocalProtocols smb
+BrowseLocalProtocols cups dnssd
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseLocalProtocols</CODE> directive specifies the
+protocols to use when advertising local shared printers on the
+network. Multiple protocols can be specified by separating them
+with spaces. The default is "<CODE>@CUPS_BROWSE_LOCAL_PROTOCOLS@</CODE>".</P>
+
+
+<H2 CLASS="title"><A NAME="BrowseOrder">BrowseOrder</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseOrder allow,deny
+BrowseOrder deny,allow
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseOrder</CODE> directive specifies the order of
+allow/deny processing. The default order is
+<CODE>deny,allow</CODE>:</P>
+
+<UL>
+
+ <LI><CODE>allow,deny</CODE> - Deny browse packets by
+ default, then check <CODE>BrowseAllow</CODE> lines
+ followed by <CODE>BrowseDeny</CODE> lines.</LI>
+
+ <LI><CODE>deny,allow</CODE> - Allow browse packets by
+ default, then check <CODE>BrowseDeny</CODE> lines
+ followed by <CODE>BrowseAllow</CODE> lines.</LI>
+
+</UL>
+
+
+<H2 CLASS="title"><A NAME="BrowsePoll">BrowsePoll</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowsePoll 192.0.2.2:631
+BrowsePoll host.example.com:631
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowsePoll</CODE> directive polls a server for
+available printers once every <A
+HREF="#BrowseInterval"><CODE>BrowseInterval</CODE></A> seconds.
+Multiple <CODE>BrowsePoll</CODE> directives can be specified to
+poll multiple servers.</P>
+
+<P>If <CODE>BrowseInterval</CODE> is set to 0 then the server is
+polled once every 30 seconds.</P>
+
+
+<H2 CLASS="title"><A NAME="BrowsePort">BrowsePort</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowsePort 631
+BrowsePort 9999
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowsePort</CODE> directive specifies the UDP port number
+used for browse packets. The default port number is 631.</P>
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>You must set the <CODE>BrowsePort</CODE> to the same value
+on all of the systems that you want to see.
+
+</BLOCKQUOTE>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.10</SPAN><A NAME="BrowseProtocols">BrowseProtocols</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseProtocols all
+BrowseProtocols none
+BrowseProtocols cups
+BrowseProtocols dnssd
+BrowseProtocols ldap
+BrowseProtocols lpd
+BrowseProtocols slp
+BrowseProtocols smb
+BrowseProtocols cups dnssd
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseProtocols</CODE> directive specifies the
+protocols to use when showing and advertising shared printers on
+the local network. Multiple protocols can be specified by
+separating them with spaces. The default protocol is
+"<CODE>@CUPS_BROWSE_LOCAL_PROTOCOLS@</CODE>" for
+<A HREF="#BrowseLocalProtocols"><CODE>BrowseLocalProtocols</CODE></A> and
+"<CODE>@CUPS_BROWSE_REMOTE_PROTOCOLS@</CODE>" for
+<A HREF="#BrowseRemoteProtocols"><CODE>BrowseRemoteProtocols</CODE></A>.</P>
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>When using the <CODE>SLP</CODE> protocol, you must have at least
+one Directory Agent (DA) server on your network. Otherwise the
+CUPS scheduler (<CODE>cupsd</CODE>) will not respond to client
+requests for several seconds while polling the network.</P>
+
+</BLOCKQUOTE>
+
+
+<H2 CLASS="title"><A NAME="BrowseRelay">BrowseRelay</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseRelay 193.0.2.1 192.0.2.255
+BrowseRelay 193.0.2.0/255.255.255.0 192.0.2.255
+BrowseRelay 193.0.2.0/24 192.0.2.255
+BrowseRelay *.example.com 192.0.2.255
+BrowseRelay host.example.com 192.0.2.255
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseRelay</CODE> directive specifies source and
+destination addresses for relaying browsing information from one
+host or network to another. Multiple <CODE>BrowseRelay</CODE>
+directives can be specified as needed.</P>
+
+<P><CODE>BrowseRelay</CODE> is typically used on systems that
+bridge multiple subnets using one or more network interfaces. It
+can also be used to relay printer information from polled servers
+with the line:</P>
+
+<PRE CLASS="command">
+BrowseRelay 127.0.0.1 192.0.2.255
+</PRE>
+
+<P>This effectively provides access to printers on a WAN for all
+clients on the LAN. Use multiple <CODE>BrowseRelay</CODE> lines to
+relay information to multiple subnets.</P>
+
+
+<H2 CLASS="title"><A NAME="BrowseRemoteOptions">BrowseRemoteOptions</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseRemoteOptions compression=yes
+BrowseRemoteOptions encryption=required
+BrowseRemoteOptions ?compression=yes&amp;encryption=required
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseRemoteOptions</CODE> directive specifies
+additional IPP backend options to include with remote shared
+printers. If the options string begins with a question mark (?),
+the options replace any options specified by the remote server.
+The default is to not include any options.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="BrowseRemoteProtocols">BrowseRemoteProtocols</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseRemoteProtocols all
+BrowseRemoteProtocols none
+BrowseRemoteProtocols cups
+BrowseRemoteProtocols ldap
+BrowseRemoteProtocols slp
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseRemoteProtocols</CODE> directive specifies the
+protocols to use when finding remote shared printers on the
+network. Multiple protocols can be specified by separating them
+with spaces. The default is "<CODE>@CUPS_BROWSE_REMOTE_PROTOCOLS@</CODE>".</P>
+
+
+<H2 CLASS="title"><A NAME="BrowseShortNames">BrowseShortNames</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseShortNames Yes
+BrowseShortNames No
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseShortNames</CODE> directive specifies whether
+or not short names are used for remote printers when possible.
+Short names are just the remote printer name, without the server
+("printer"). If more than one remote printer is detected with the
+same name, the printers will have long names ("printer@server1",
+"printer@server2".)</P>
+
+<P>The default value for this option is <CODE>@CUPS_BROWSE_SHORT_NAMES@</CODE>.</P>
+
+
+<H2 CLASS="title"><A NAME="BrowseTimeout">BrowseTimeout</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseTimeout 300
+BrowseTimeout 60
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseTimeout</CODE> directive sets the timeout for
+printer or class information that is received in browse packets.
+Once a printer or class times out it is removed from the list of
+available destinations.</P>
+
+<P>The <CODE>BrowseTimeout</CODE> value should always be greater
+than the <A
+HREF="#BrowseInterval"><CODE>BrowseInterval</CODE></A> value.
+Otherwise printers and classes will disappear from client systems
+between updates.</P>
+
+
+<H2 CLASS="title"><A NAME="BrowseWebIF">BrowseWebIF</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseWebIF On
+BrowseWebIF Off
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseWebIF</CODE> directive controls whether the CUPS web
+interface is advertised via DNS-SD. The default setting is
+<CODE>Off</CODE>.</P>
+
+
+<H2 CLASS="title"><A NAME="Browsing">Browsing</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+Browsing On
+Browsing Off
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Browsing</CODE> directive controls whether or not
+network printer browsing is enabled. The default setting is
+<CODE>@CUPS_BROWSING@</CODE>.</P>
+
+<P>This directive does not enable sharing of local printers by
+itself; you must also use the <A
+HREF="#BrowseAddress"><CODE>BrowseAddress</CODE></A> or <A
+HREF="#BrowseProtocols"><CODE>BrowseProtocols</CODE></A>
+directives to advertise local printers to other systems.</P>
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>If you are using HP-UX 10.20 and a subnet that is not 24,
+16, or 8 bits, printer browsing (and in fact all broadcast
+reception) will not work. This problem appears to be fixed in
+HP-UX 11.0.</P>
+
+</BLOCKQUOTE>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.7</SPAN><A NAME="Classification">Classification</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+Classification
+Classification classified
+Classification confidential
+Classification secret
+Classification topsecret
+Classification unclassified
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Classification</CODE> directive sets the
+classification level on the server. When this option is set, at
+least one of the banner pages is forced to the classification
+level, and the classification is placed on each page of output.
+The default is no classification level.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.10</SPAN><A NAME="ClassifyOverride">ClassifyOverride</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ClassifyOverride Yes
+ClassifyOverride No
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ClassifyOverride</CODE> directive specifies whether
+users can override the default classification level on the
+server. When the server classification is set, users can change
+the classification using the <CODE>job-sheets</CODE> option and
+can choose to only print one security banner before or after the
+job. If the <CODE>job-sheets</CODE> option is set to
+<CODE>none</CODE> then the server default classification is
+used.</P>
+
+<P>The default is to not allow classification overrides.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.15</SPAN><A NAME="ConfigFilePerm">ConfigFilePerm</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ConfigFilePerm 0644
+ConfigFilePerm 0640
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ConfigFilePerm</CODE> directive specifies the
+permissions to use when writing configuration files. The default
+is @CUPS_CONFIG_FILE_PERM@.</P>
+
+
+<H2 CLASS="title"><A NAME="DataDir">DataDir</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+DataDir /usr/share/cups
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DataDir</CODE> directive sets the directory to use
+for data files.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="DefaultAuthType">DefaultAuthType</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+DefaultAuthType Basic
+DefaultAuthType BasicDigest
+DefaultAuthType Digest
+DefaultAuthType Negotiate
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DefaultAuthType</CODE> directive specifies the type
+of authentication to use for IPP operations that require a
+username. The default is <CODE>Basic</CODE>.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="DefaultEncryption">DefaultEncryption</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+DefaultEncryption Never
+DefaultEncryption IfRequested
+DefaultEncryption Required
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DefaultEncryption</CODE> directive specifies the
+type of encryption to use when performing authentication. The
+default is <CODE>Required</CODE>.</P>
+
+
+<H2 CLASS="title"><A NAME="DefaultLanguage">DefaultLanguage</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+DefaultLanguage de
+DefaultLanguage en
+DefaultLanguage es
+DefaultLanguage fr
+DefaultLanguage it
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DefaultLanguage</CODE> directive specifies the
+default language to use for client connections. Setting the
+default language also sets the default character set if a
+language localization file exists for it. The default language
+is "en" for English.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.4/Mac OS X 10.6</SPAN><A NAME="DefaultPaperSize">DefaultPaperSize</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+DefaultPaperSize Letter
+DefaultPaperSize A4
+DefaultPaperSize Auto
+DefaultPaperSize None
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DefaultPaperSize</CODE> directive specifies the default paper
+size to use when creating new printers. The default is <CODE>Auto</CODE>
+which uses a paper size appropriate for the system default locale. A value
+of <CODE>None</CODE> tells the scheduler to not set the default paper
+size.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="DefaultPolicy">DefaultPolicy</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+DefaultPolicy default
+DefaultPolicy authenticated
+DefaultPolicy foo
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DefaultPolicy</CODE> directive specifies the default
+policy to use for IPP operation. The default is
+<CODE>default</CODE>. CUPS also includes a policy called
+<CODE>authenticated</CODE> that requires a username and password for printing
+and other job operations.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="DefaultShared">DefaultShared</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+DefaultShared yes
+DefaultShared no
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DefaultShared</CODE> directive specifies whether
+printers are shared (published) by default. The default is
+<CODE>@CUPS_DEFAULT_SHARED@</CODE>.</P>
+
+
+<H2 CLASS="title"><A NAME="Deny">Deny</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Location /path&gt;
+ ..
+ Deny from All
+ Deny from None
+ Deny from *.example.com
+ Deny from .example.com
+ Deny from host.example.com
+ Deny from nnn.*
+ Deny from nnn.nnn.*
+ Deny from nnn.nnn.nnn.*
+ Deny from nnn.nnn.nnn.nnn
+ Deny from nnn.nnn.nnn.nnn/mm
+ Deny from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
+ Deny from [xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]
+ Deny from [xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]/mmm
+ Deny from @LOCAL
+ Deny from @IF(name)
+&lt;/Location&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Deny</CODE> directive specifies a hostname, IP
+address, or network that is denied access to the server.
+<CODE>Deny</CODE> directives are cumulative, so multiple
+<CODE>Deny</CODE> directives can be used to deny access for
+multiple hosts or networks.</P>
+
+<P>Host and domain name matching require that you enable the <A
+HREF="#HostNameLookups"><CODE>HostNameLookups</CODE></A>
+directive.</P>
+
+<P>The <CODE>/mm</CODE> notation specifies a CIDR netmask, a shown in
+<A HREF="TABLE1">Table 1</A>.</P>
+
+<P>The <CODE>@LOCAL</CODE> name will deny access from all local
+interfaces. The <CODE>@IF(name)</CODE> name will deny access from
+the named interface. In both cases, CUPS only denies access from
+the network that the interface(s) are configured for - requests
+arriving on the interface from a foreign network will
+<em>not</em> be denied.</P>
+
+<P>The <CODE>Deny</CODE> directive must appear inside a <A
+HREF="#Location"><CODE>Location</CODE></A> or <A
+HREF="#Limit"><CODE>Limit</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.4/Mac OS X 10.6</SPAN><A NAME="DirtyCleanInterval">DirtyCleanInterval</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+DirtyCleanInterval 30
+DirtyCleanInterval 0
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DirtyCleanInterval</CODE> directive specifies the number of
+seconds to wait before updating configuration and state files for printers,
+classes, subscriptions, and jobs. The default is 30 seconds. A value of 0
+causes the update to occur as soon as possible, typically within a few
+milliseconds.</P>
+
+
+<H2 CLASS="title"><A NAME="DocumentRoot">DocumentRoot</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+DocumentRoot /usr/share/doc/cups
+DocumentRoot /foo/bar/doc/cups
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DocumentRoot</CODE> directive specifies the location
+of web content for the HTTP server in CUPS. If an absolute path
+is not specified then it is assumed to be relative to the <A
+HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
+default directory is <VAR>@CUPS_DOCROOT@</VAR>.</P>
+
+<P>Documents are first looked up in a sub-directory for the
+primary language requested by the client (e.g.
+<VAR>@CUPS_DOCROOT@/fr/...</VAR>) and then directly under
+the <CODE>DocumentRoot</CODE> directory (e.g.
+<VAR>@CUPS_DOCROOT@/...</VAR>), so it is possible to
+localize the web content by providing subdirectories for each
+language needed.</P>
+
+
+<H2 CLASS="title"><A NAME="Encryption">Encryption</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Location /path&gt;
+ ...
+ Encryption Never
+ Encryption IfRequested
+ Encryption Required
+&lt;/Location&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Encryption</CODE> directive must appear instead a <A
+HREF="#Location"><CODE>Location</CODE></A> or <A
+HREF="#Limit"><CODE>Limit</CODE></A> section and specifies the
+encryption settings for that location. The default setting is
+<CODE>IfRequested</CODE> for all locations.</P>
+
+
+<H2 CLASS="title"><A NAME="ErrorLog">ErrorLog</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ErrorLog /var/log/cups/error_log
+ErrorLog /var/log/cups/error_log-%s
+ErrorLog syslog
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ErrorLog</CODE> directive sets the name of the error
+log file. If the filename is not absolute then it is assumed to
+be relative to the <A
+HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
+default error log file is <VAR>@CUPS_LOGDIR@/error_log</VAR>.</P>
+
+<P>The server name can be included in the filename by using
+<CODE>%s</CODE> in the name.</P>
+
+<P>The special name "syslog" can be used to send the error
+information to the system log instead of a plain file.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.3/Mac OS X 10.5</SPAN><A NAME="ErrorPolicy">ErrorPolicy</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ErrorPolicy abort-job
+ErrorPolicy retry-job
+ErrorPolicy stop-printer
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ErrorPolicy</CODE> directive defines the default policy that
+is used when a backend is unable to send a print job to the
+printer.</P>
+
+<P>The following values are supported:</P>
+
+<UL>
+
+ <LI><CODE>abort-job</CODE> - Abort the job and proceed
+ with the next job in the queue</LI>
+
+ <LI><CODE>retry-job</CODE> - Retry the job after waiting
+ for N seconds; the <VAR>cupsd.conf</VAR> <A
+ HREF="#JobRetryInterval"><CODE>JobRetryInterval</CODE></A>
+ directive controls the value of N</LI>
+
+ <LI><CODE>retry-this-job</CODE> - Retry the current job immediately
+ and indefinitely.</LI>
+
+ <LI><CODE>stop-printer</CODE> - Stop the printer and keep
+ the job for future printing; this is the default
+ value</LI>
+
+</UL>
+
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.4/Mac OS X 10.6</SPAN><A NAME="FatalErrors">FatalErrors</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+FatalErrors none
+FatalErrors all
+FatalErrors browse
+FatalErrors config
+FatalErrors listen
+FatalErrors log
+FatalErrors permissions
+FatalErrors all -permissions
+FatalErrors config permissions log
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>FatalErrors</CODE> directive determines whether certain kinds of
+errors are fatal. The following kinds of errors are currently recognized:</P>
+
+<UL>
+
+ <LI><CODE>none</CODE> - No errors are fatal</LI>
+
+ <LI><CODE>all</CODE> - All of the errors below are fatal</LI>
+
+ <LI><CODE>browse</CODE> - Browsing initialization errors are fatal,
+ for example failed binding to the CUPS browse port or failed connections
+ to LDAP servers</LI>
+
+ <LI><CODE>config</CODE> - Configuration file syntax errors are
+ fatal</LI>
+
+ <LI><CODE>listen</CODE> - Listen or Port errors are fatal, except for
+ IPv6 failures on the loopback or "any" addresses</LI>
+
+ <LI><CODE>log</CODE> - Log file creation or write errors are fatal</LI>
+
+ <LI><CODE>permissions</CODE> - Bad startup file permissions are
+ fatal, for example shared SSL certificate and key files with world-
+ read permissions</LI>
+
+</UL>
+
+<P>Multiple errors can be listed, and the form "-kind" can be used with
+<CODE>all</CODE> to remove specific kinds of errors. The default setting is
+<CODE>@CUPS_FATAL_ERRORS@</CODE>.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.18</SPAN><A NAME="FileDevice">FileDevice</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+FileDevice Yes
+FileDevice No
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>FileDevice</CODE> directive determines whether the
+scheduler allows new printers to be added using device URIs of
+the form <CODE>file:/filename</CODE>. File devices are most often
+used to test new printer drivers and do not support raw file
+printing.</P>
+
+<P>The default setting is <CODE>No</CODE>.</P>
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>File devices are managed by the scheduler. Since the
+scheduler normally runs as the root user, file devices
+can be used to overwrite system files and potentially
+gain unauthorized access to the system. If you must
+create printers using file devices, we recommend that
+you set the <CODE>FileDevice</CODE> directive to
+<CODE>Yes</CODE> for only as long as you need to add the
+printers to the system, and then reset the directive to
+<CODE>No</CODE>.</P>
+
+</BLOCKQUOTE>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.3</SPAN><A NAME="FilterLimit">FilterLimit</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+FilterLimit 0
+FilterLimit 200
+FilterLimit 1000
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>FilterLimit</CODE> directive sets the maximum cost
+of all running job filters. It can be used to limit the number of
+filter programs that are run on a server to minimize disk,
+memory, and CPU resource problems. A limit of 0 disables filter
+limiting.</P>
+
+<P>An average print to a non-PostScript printer needs a filter
+limit of about 200. A PostScript printer needs about half that
+(100). Setting the limit below these thresholds will effectively
+limit the scheduler to printing a single job at any time.</P>
+
+<P>The default limit is 0.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.16</SPAN><A NAME="FilterNice">FilterNice</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+FilterNice 0
+FilterNice 10
+FilterNice 19
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>FilterNice</CODE> directive sets the <B>nice(1)</B>
+value to assign to filter processes. The nice value ranges from
+0, the highest priority, to 19, the lowest priority. The default
+is 0.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.3</SPAN><A NAME="FontPath">FontPath</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+FontPath /foo/bar/fonts
+FontPath /usr/share/cups/fonts:/foo/bar/fonts
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>FontPath</CODE> directive specifies the font path to
+use when searching for fonts. The default font path is
+<CODE>/usr/share/cups/fonts</CODE>.</P>
+
+
+<H2 CLASS="title"><A NAME="Group">Group</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+Group lp
+Group nobody
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Group</CODE> directive specifies the UNIX group that
+filter and CGI programs run as. The default group is
+system-specific but is usually <CODE>lp</CODE> or
+<CODE>nobody</CODE>.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.10</SPAN><A NAME="HideImplicitMembers">HideImplicitMembers</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+HideImplicitMembers Yes
+HideImplicitMembers No
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>HideImplicitMembers</CODE> directive controls
+whether the individual printers in an implicit class are hidden
+from the user. The default is <CODE>Yes</CODE>.</P>
+
+<P><A HREF="#ImplicitClasses"><CODE>ImplicitClasses</CODE></A>
+must be enabled for this directive to have any effect.</P>
+
+
+<H2 CLASS="title"><A NAME="HostNameLookups">HostNameLookups</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+HostNameLookups On
+HostNameLookups Off
+HostNameLookups Double
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>HostNameLookups</CODE> directive controls whether or
+not CUPS looks up the hostname for connecting clients. The
+<CODE>Double</CODE> setting causes CUPS to verify that the
+hostname resolved from the address matches one of the addresses
+returned for that hostname. <CODE>Double</CODE> lookups also
+prevent clients with unregistered addresses from connecting to
+your server.</P>
+
+<P>The default is <CODE>Off</CODE> to avoid the potential server
+performance problems with hostname lookups. Set this option to
+<CODE>On</CODE> or <CODE>Double</CODE> only if absolutely
+required.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.10</SPAN><A NAME="ImplicitAnyClasses">ImplicitAnyClasses</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ImplicitAnyClasses On
+ImplicitAnyClasses Off
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ImplicitAnyClasses</CODE> directive controls
+whether implicit classes for local and remote printers are
+created with the name <CODE>AnyPrinter</CODE>. The default
+setting is <CODE>Off</CODE>.</P>
+
+<P><A HREF="#ImplicitClasses"><CODE>ImplicitClasses</CODE></A>
+must be enabled for this directive to have any effect.</P>
+
+
+<H2 CLASS="title"><A NAME="ImplicitClasses">ImplicitClasses</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ImplicitClasses On
+ImplicitClasses Off
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ImplicitClasses</CODE> directive controls whether
+implicit classes are created based upon the available network
+printers and classes. The default setting is
+<CODE>@CUPS_IMPLICIT_CLASSES@</CODE> but is automatically turned
+<CODE>Off</CODE> if <A HREF="#Browsing"><CODE>Browsing</CODE></A> is turned
+<CODE>Off</CODE>.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.9</SPAN><A NAME="Include">Include</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+Include filename
+Include /foo/bar/filename
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Include</CODE> directive includes the named file in
+the <CODE>cupsd.conf</CODE> file. If no leading path is provided,
+the file is assumed to be relative to the <A
+HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.5</SPAN><A NAME="JobPrivateAccess">JobPrivateAccess</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+JobPrivateAccess all
+JobPrivateAccess default
+JobPrivateAccess {user|@group|@ACL|@OWNER|@SYSTEM}+
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>JobPrivateAccess</CODE> directive specifies the access list for a
+job's private values. The "default" access list is "@OWNER @SYSTEM". "@ACL" maps
+to the printer's requesting-user-name-allowed or requesting-user-name-denied
+values.</P>
+
+<P>The <CODE>JobPrivateAccess</CODE> directive must appear inside a <A
+HREF="#Policy"><CODE>Policy</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.5</SPAN><A NAME="JobPrivateValues">JobPrivateValues</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+JobPrivateValues all
+JobPrivateValues default
+JobPrivateValues none
+JobPrivateValues attribute-name-1 [ ... attribute-name-N ]
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>JobPrivateValues</CODE> directive specifies the list of job values
+to make private. The "default" values are "job-name",
+"job-originating-host-name", and "job-originating-user-name".</P>
+
+<P>The <CODE>JobPrivateValues</CODE> directive must appear inside a <A
+HREF="#Policy"><CODE>Policy</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="JobRetryInterval">JobRetryInterval</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+JobRetryInterval 30
+JobRetryInterval 120
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>JobRetryInterval</CODE> directive specifies the
+number of seconds to wait before retrying a job. This is
+typically used for fax queues but can also be used with normal
+print queues whose error policy is <CODE>retry-job</CODE>. The
+default is 30 seconds.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.4/Mac OS X 10.6</SPAN><A NAME="JobKillDelay">JobKillDelay</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+JobKillDelay 30
+JobKillDelay 120
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>JobKillDelay</CODE> directive specifies the number of seconds to
+wait before killing the filters and backend associated with a canceled or held
+job. The default is 30 seconds.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="JobRetryLimit">JobRetryLimit</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+JobRetryLimit 5
+JobRetryLimit 50
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>JobRetryLimit</CODE> directive specifies the maximum
+number of times the scheduler will try to print a job. This is
+typically used for fax queues but can also be used with normal
+print queues whose error policy is <CODE>retry-job</CODE>. The
+default is 5 times.</P>
+
+
+<H2 CLASS="title"><A NAME="KeepAlive">KeepAlive</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+KeepAlive On
+KeepAlive Off
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>KeepAlive</CODE> directive controls whether or not
+to support persistent HTTP connections. The default is
+<CODE>On</CODE>.</P>
+
+<P>HTTP/1.1 clients automatically support persistent connections,
+while HTTP/1.0 clients must specifically request them using the
+<CODE>Keep-Alive</CODE> attribute in the <CODE>Connection:</CODE>
+field of each request.</P>
+
+
+<H2 CLASS="title"><A NAME="KeepAliveTimeout">KeepAliveTimeout</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+KeepAliveTimeout 60
+KeepAliveTimeout 30
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>KeepAliveTimeout</CODE> directive controls how long
+a persistent HTTP connection will remain open after the last
+request. The default is 30 seconds.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.7</SPAN><A NAME="Limit">Limit (Location)</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Location /path&gt;
+ &lt;Limit GET POST&gt;
+ ...
+ &lt;/Limit&gt;
+
+ &lt;Limit ALL&gt;
+ ...
+ &lt;/Limit&gt;
+&lt;/Location&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Limit</CODE> directive groups access control
+directives for specific types of HTTP requests and must appear
+inside a <A HREF="#Location"><CODE>Location</CODE></A> section.
+Access can be limited for individual request types
+(<CODE>DELETE</CODE>, <CODE>GET</CODE>, <CODE>HEAD</CODE>,
+<CODE>OPTIONS</CODE>, <CODE>POST</CODE>, <CODE>PUT</CODE>, and
+<CODE>TRACE</CODE>) or for all request types (<CODE>ALL</CODE>).
+The request type names are case-sensitive for compatibility with
+Apache.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="LimitIPP">Limit (Policy)</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Policy name&gt;
+ &lt;Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer&gt;
+ ...
+ &lt;/Limit&gt;
+
+ &lt;Limit All&gt;
+ ...
+ &lt;/Limit&gt;
+&lt;/Policy&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>When included in <A HREF="#Policy"><CODE>Policy</CODE></A>
+sections, the <CODE>Limit</CODE> directive groups access control
+directives for specific IPP operations. Multiple operations can
+be listed, separated by spaces. Table 2 lists the supported
+operations.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="Supported IPP Operations">
+<CAPTION>Table 2: <A NAME="TABLE2">Supported IPP Operations</A></CAPTION>
+<THEAD>
+<TR>
+ <TH>Operation Name</TH>
+ <TH>Description</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD>All</TD>
+ <TD>All operations - used as the default limit for
+ operations that are not listed</TD>
+</TR>
+<TR>
+ <TD>Cancel-Job</TD>
+ <TD>Cancel a job</TD>
+</TR>
+<TR>
+ <TD>Cancel-Subscription</TD>
+ <TD>Cancel a subscription</TD>
+</TR>
+<TR>
+ <TD>Create-Job</TD>
+ <TD>Create a new, empty job</TD>
+</TR>
+<TR>
+ <TD>Create-Job-Subscription</TD>
+ <TD>Creates a notification subscription on a job</TD>
+</TR>
+<TR>
+ <TD>Create-Printer-Subscription</TD>
+ <TD>Creates a notification subscription on a printer</TD>
+</TR>
+<TR>
+ <TD>CUPS-Accept-Jobs</TD>
+ <TD>Sets the printer-is-accepting-jobs value for a printer to true</TD>
+</TR>
+<TR>
+ <TD>CUPS-Add-Modify-Class</TD>
+ <TD>Adds or modifies a class</TD>
+</TR>
+<TR>
+ <TD>CUPS-Add-Modify-Printer</TD>
+ <TD>Adds or modifies a printer</TD>
+</TR>
+<TR>
+ <TD>CUPS-Authenticate-Job</TD>
+ <TD>Authenticates a job for printing</TD>
+</TR>
+<TR>
+ <TD>CUPS-Delete-Class</TD>
+ <TD>Deletes a class</TD>
+</TR>
+<TR>
+ <TD>CUPS-Delete-Printer</TD>
+ <TD>Deletes a printer</TD>
+</TR>
+<TR>
+ <TD>CUPS-Get-Classes</TD>
+ <TD>Gets a list of classes</TD>
+</TR>
+<TR>
+ <TD>CUPS-Get-Default</TD>
+ <TD>Gets the (network/server) default printer or class</TD>
+</TR>
+<TR>
+ <TD>CUPS-Get-Devices</TD>
+ <TD>Gets a list of available devices</TD>
+</TR>
+<TR>
+ <TD>CUPS-Get-PPDs</TD>
+ <TD>Gets a list of available manufacturers or drivers</TD>
+</TR>
+<TR>
+ <TD>CUPS-Get-Printers</TD>
+ <TD>Gets a list of printers and/or classes</TD>
+</TR>
+<TR>
+ <TD>CUPS-Move-Job</TD>
+ <TD>Moves a job to a new destination</TD>
+</TR>
+<TR>
+ <TD>CUPS-Reject-Jobs</TD>
+ <TD>Sets the printer-is-accepting-jobs value for a printer to false</TD>
+</TR>
+<TR>
+ <TD>CUPS-Set-Default</TD>
+ <TD>Sets the network/server default printer or class</TD>
+</TR>
+<TR>
+ <TD>Disable-Printer</TD>
+ <TD>Sets the printer-state value for a printer to stopped</TD>
+</TR>
+<TR>
+ <TD>Enable-Printer</TD>
+ <TD>Sets the printer-state value for a printer to idle/processing</TD>
+</TR>
+<TR>
+ <TD>Get-Job-Attributes</TD>
+ <TD>Gets information about a job</TD>
+</TR>
+<TR>
+ <TD>Get-Jobs</TD>
+ <TD>Gets a list of jobs</TD>
+</TR>
+<TR>
+ <TD>Get-Notifications</TD>
+ <TD>Gets a list of events</TD>
+</TR>
+<TR>
+ <TD>Get-Printer-Attributes</TD>
+ <TD>Gets information about a printer or class</TD>
+</TR>
+<TR>
+ <TD>Get-Subscription-Attributes</TD>
+ <TD>Gets information about a notification subscription</TD>
+</TR>
+<TR>
+ <TD>Get-Subscriptions</TD>
+ <TD>Gets a list of notification subscriptions</TD>
+</TR>
+<TR>
+ <TD>Hold-Job</TD>
+ <TD>Holds a job for printing</TD>
+</TR>
+<TR>
+ <TD>Pause-Printer</TD>
+ <TD>Sets the printer-state value for a printer to stopped</TD>
+</TR>
+<TR>
+ <TD>Print-Job</TD>
+ <TD>Creates a job with a single file for printing</TD>
+</TR>
+<TR>
+ <TD>Purge-Jobs</TD>
+ <TD>Removes all jobs from a printer</TD>
+</TR>
+<TR>
+ <TD>Release-Job</TD>
+ <TD>Releases a previously held job for printing</TD>
+</TR>
+<TR>
+ <TD>Renew-Subscription</TD>
+ <TD>Renews a notification subscription</TD>
+</TR>
+<TR>
+ <TD>Restart-Job</TD>
+ <TD>Reprints a job</TD>
+</TR>
+<TR>
+ <TD>Resume-Printer</TD>
+ <TD>Sets the printer-state value for a printer to idle/processing</TD>
+</TR>
+<TR>
+ <TD>Send-Document</TD>
+ <TD>Adds a file to an job created with Create-Job</TD>
+</TR>
+<TR>
+ <TD>Set-Job-Attributes</TD>
+ <TD>Changes job options</TD>
+</TR>
+<TR>
+ <TD>Validate-Job</TD>
+ <TD>Validates job options prior to printing</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.7</SPAN><A NAME="LimitExcept">LimitExcept</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Location /path&gt;
+ &lt;LimitExcept GET POST&gt;
+ ...
+ &lt;/LimitExcept&gt;
+&lt;/Location&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>LimitExcept</CODE> directive groups access control
+directives for specific types of HTTP requests and must appear
+inside a <A HREF="#Location"><CODE>Location</CODE></A> section.
+Unlike the <A HREF="#Limit"><CODE>Limit</CODE></A> directive,
+<CODE>LimitExcept</CODE> restricts access for all requests
+<I>except</I> those listed on the <CODE>LimitExcept</CODE>
+line.</P>
+
+
+<H2 CLASS="title"><A NAME="LimitRequestBody">LimitRequestBody</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+LimitRequestBody 10485760
+LimitRequestBody 10m
+LimitRequestBody 0
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>LimitRequestBody</CODE> directive controls the
+maximum size of print files, IPP requests, and HTML form data in
+HTTP POST requests. The default limit is 0 which disables the
+limit check.</P>
+
+
+<H2 CLASS="title"><A NAME="Listen">Listen</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+Listen 127.0.0.1:631
+Listen 192.0.2.1:631
+Listen [::1]:631
+Listen *:631
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Listen</CODE> directive specifies a network address
+and port to listen for connections. Multiple <CODE>Listen</CODE>
+directives can be provided to listen on multiple addresses.</P>
+
+<P>The <CODE>Listen</CODE> directive is similar to the <A
+HREF="#Port"><CODE>Port</CODE></A> directive but allows you to
+restrict access to specific interfaces or networks.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.7</SPAN><A NAME="ListenBackLog">ListenBackLog</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ListenBackLog 5
+ListenBackLog 10
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ListenBackLog</CODE> directive sets the maximum
+number of pending connections the scheduler will allow. This
+normally only affects very busy servers that have reached the <A
+HREF="#MaxClients"><CODE>MaxClients</CODE></A> limit, but can
+also be triggered by large numbers of simultaneous connections.
+When the limit is reached, the operating system will refuse
+additional connections until the scheduler can accept the pending
+ones. The default is the OS-defined default limit, typically
+either 5 for older operating systems or 128 for newer operating
+systems.</P>
+
+
+<H2 CLASS="title"><A NAME="Location">Location</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Location /&gt;
+...
+&lt;/Location&gt;
+
+&lt;Location /admin&gt;
+...
+&lt;/Location&gt;
+
+&lt;Location /admin/conf&gt;
+...
+&lt;/Location&gt;
+
+&lt;Location /admin/log&gt;
+...
+&lt;/Location&gt;
+
+&lt;Location /classes&gt;
+...
+&lt;/Location&gt;
+
+&lt;Location /classes/name&gt;
+...
+&lt;/Location&gt;
+
+&lt;Location /jobs&gt;
+...
+&lt;/Location&gt;
+
+&lt;Location /printers&gt;
+...
+&lt;/Location&gt;
+
+&lt;Location /printers/name&gt;
+...
+&lt;/Location&gt;
+
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Location</CODE> directive specifies access control
+and authentication options for the specified HTTP resource or
+path. The <A HREF="#Allow"><CODE>Allow</CODE></A>, <A
+HREF="#AuthType"><CODE>AuthType</CODE></A>, <A
+HREF="#Deny"><CODE>Deny</CODE></A>, <A
+HREF="#Encryption"><CODE>Encryption</CODE></A>, <A
+HREF="#Limit"><CODE>Limit</CODE></A>, <A
+HREF="#LimitExcept"><CODE>LimitExcept</CODE></A>, <A
+HREF="#Order"><CODE>Order</CODE></A>, <A
+HREF="#Require"><CODE>Require</CODE></A>, and <A
+HREF="#Satisfy"><CODE>Satisfy</CODE></A> directives may all
+appear inside a location.</P>
+
+<P>Note that more specific resources override the less specific
+ones. So the directives inside the <CODE>/printers/name</CODE>
+location will override ones from <CODE>/printers</CODE>.
+Directives inside <CODE>/printers</CODE> will override ones from
+<CODE>/</CODE>. None of the directives are inherited.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="Common Locations on the Server">
+<CAPTION>Table 3: <A NAME="TABLE3">Common Locations on the Server</A></CAPTION>
+<THEAD>
+<TR><TH>Location</TH><TH>Description</TH></TR>
+</THEAD>
+<TBODY>
+<TR><TD><CODE>/</CODE></TD><TD>The path for all get operations (get-printers, get-jobs, etc.)</TD></TR>
+<TR><TD><CODE>/admin</CODE></TD><TD>The path for all administration operations (add-printer, delete-printer, start-printer, etc.)</TD></TR>
+<TR><TD><CODE>/admin/conf</CODE></TD><TD>The path for access to the CUPS configuration files (cupsd.conf, client.conf, etc.)</TD></TR>
+<TR><TD><CODE>/admin/log</CODE></TD><TD>The path for access to the CUPS log files (access_log, error_log, page_log)</TD></TR>
+<TR><TD><CODE>/classes</CODE></TD><TD>The path for all classes</TD></TR>
+<TR><TD><CODE>/classes/name</CODE></TD><TD>The resource for class <CODE>name</CODE></TD></TR>
+<TR><TD><CODE>/jobs</CODE></TD><TD>The path for all jobs (hold-job, release-job, etc.)</TD></TR>
+<TR><TD><CODE>/jobs/id</CODE></TD><TD>The resource for job <CODE>id</CODE></TD></TR>
+<TR><TD><CODE>/printers</CODE></TD><TD>The path for all printers</TD></TR>
+<TR><TD><CODE>/printers/name</CODE></TD><TD>The path for printer <CODE>name</CODE></TD></TR>
+<TR><TD><CODE>/printers/name.ppd</CODE></TD><TD>The PPD file path for printer <CODE>name</CODE></TD></TR>
+</TBODY>
+</TABLE></DIV>
+
+
+<H2 CLASS="title"><A NAME="LogDebugHistory">LogDebugHistory</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+LogDebugHistory 0
+LogDebugHistory 200
+</PRE>
+
+<H3>Description</H3>
+
+<P>When <A HREF="#LogLevel"><CODE>LogLevel</CODE></A> is not set to
+<CODE>debug</CODE> or <CODE>debug2</CODE>, the <CODE>LogDebugHistory</CODE>
+directive specifies the number of debugging messages that are logged when an
+error occurs during printing. The default is 200 messages. A value of 0
+disables debugging history entirely and is not recommended.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.15</SPAN><A NAME="LogFilePerm">LogFilePerm</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+LogFilePerm 0644
+LogFilePerm 0600
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>LogFilePerm</CODE> directive specifies the
+permissions to use when writing configuration files. The default
+is @CUPS_LOG_FILE_PERM@.</P>
+
+
+<H2 CLASS="title"><A NAME="LogLevel">LogLevel</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+LogLevel none
+LogLevel emerg
+LogLevel alert
+LogLevel crit
+LogLevel error
+LogLevel warn
+LogLevel notice
+LogLevel info
+LogLevel debug
+LogLevel debug2
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>LogLevel</CODE> directive specifies the level of
+logging for the <A HREF="#ErrorLog"><CODE>ErrorLog</CODE></A>
+file. The following values are recognized (each level logs
+everything under the preceding levels):</P>
+
+<UL>
+
+ <LI><CODE>none</CODE> - Log nothing</LI>
+
+ <LI><CODE>emerg</CODE> - Log emergency conditions that
+ prevent the server from running</LI>
+
+ <LI><CODE>alert</CODE> - Log alerts that must be handled
+ immediately</LI>
+
+ <LI><CODE>crit</CODE> - Log critical errors that don't
+ prevent the server from running</LI>
+
+ <LI><CODE>error</CODE> - Log general errors</LI>
+
+ <LI><CODE>warn</CODE> - Log errors and warnings</LI>
+
+ <LI><CODE>notice</CODE> - Log temporary error conditions</LI>
+
+ <LI><CODE>info</CODE> - Log all requests and state
+ changes</LI>
+
+ <LI><CODE>debug</CODE> - Log basic debugging
+ information</LI>
+
+ <LI><CODE>debug2</CODE> - Log all debugging
+ information</LI>
+
+</UL>
+
+<p>The default <code>LogLevel</code> is <code>@CUPS_LOG_LEVEL@</code>.</p>
+
+
+<H2 CLASS="title"><A NAME="LogTimeFormat">LogTimeFormat</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+LogTimeFormat standard
+LogTimeFormat usecs
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>LogTimeFormat</CODE> directive specifies the format used for the
+date and time in the log files. <CODE>Standard</CODE> uses the standard Apache
+Common Log Format date and time while <CODE>usecs</CODE> adds microseconds.
+The default is <CODE>standard</CODE>.</P>
+
+
+<H2 CLASS="title"><A NAME="MaxClients">MaxClients</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+MaxClients 100
+MaxClients 1024
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>MaxClients</CODE> directive controls the maximum
+number of simultaneous clients that will be allowed by the
+server. The default is 100 clients.</P>
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>Since each print job requires a file descriptor for the status
+pipe, the scheduler internally limits the <CODE>MaxClients</CODE>
+value to 1/3 of the available file descriptors to avoid possible
+problems when printing large numbers of jobs.</P>
+
+</BLOCKQUOTE>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.18</SPAN><A NAME="MaxClientsPerHost">MaxClientsPerHost</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+MaxClientsPerHost 10
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>MaxClientsPerHost</CODE> directive controls the
+maximum number of simultaneous clients that will be allowed from
+a single host by the server. The default is the
+<CODE>MaxClients</CODE> value.</P>
+
+<P>This directive provides a small measure of protection against
+Denial of Service attacks from a single host.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.16</SPAN><A NAME="MaxCopies">MaxCopies</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+MaxCopies 100
+MaxCopies 65535
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>MaxCopies</CODE> directive controls the maximum
+number of copies that a user can print of a job. The default is
+@CUPS_MAX_COPIES@ copies.</P>
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>Most HP PCL laser printers internally limit the number of
+copies to 100.</P>
+
+</BLOCKQUOTE>
+
+
+
+<H2 CLASS="title"><A NAME="MaxJobs">MaxJobs</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+MaxJobs 100
+MaxJobs 9999
+MaxJobs 0
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>MaxJobs</CODE> directive controls the maximum number
+of jobs that are kept in memory. Once the number of jobs reaches
+the limit, the oldest completed job is automatically purged from
+the system to make room for the new one. If all of the known jobs
+are still pending or active then the new job will be
+rejected.</P>
+
+<P>Setting the maximum size to 0 disables this functionality. The
+default setting is 500.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.7</SPAN><A NAME="MaxJobsPerPrinter">MaxJobsPerPrinter</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+MaxJobsPerPrinter 100
+MaxJobsPerPrinter 9999
+MaxJobsPerPrinter 0
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>MaxJobsPerPrinter</CODE> directive controls the
+maximum number of active jobs that are allowed for each printer
+or class. Once a printer or class reaches the limit, new jobs
+will be rejected until one of the active jobs is completed,
+stopped, aborted, or canceled.</P>
+
+<P>Setting the maximum to 0 disables this functionality. The
+default setting is 0.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.7</SPAN><A NAME="MaxJobsPerUser">MaxJobsPerUser</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+MaxJobsPerUser 100
+MaxJobsPerUser 9999
+MaxJobsPerUser 0
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>MaxJobsPerUser</CODE> directive controls the maximum
+number of active jobs that are allowed for each user. Once a user
+reaches the limit, new jobs will be rejected until one of the
+active jobs is completed, stopped, aborted, or canceled.</P>
+
+<P>Setting the maximum to 0 disables this functionality. The
+default setting is 0.</P>
+
+
+<H2 CLASS="title"><A NAME="MaxLogSize">MaxLogSize</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+MaxLogSize 1048576
+MaxLogSize 1m
+MaxLogSize 0
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>MaxLogSize</CODE> directive controls the maximum
+size of each log file. Once a log file reaches or exceeds the
+maximum size it is closed and renamed to <VAR>filename.O</VAR>.
+This allows you to rotate the logs automatically. The default
+size is 1048576 bytes (1MB).</P>
+
+<P>Setting the maximum size to 0 disables log rotation.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">Deprecated</SPAN><A NAME="MaxRequestSize">MaxRequestSize</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+MaxRequestSize 10485760
+MaxRequestSize 10m
+MaxRequestSize 0
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>MaxRequestSize</CODE> directive controls the maximum
+size of print files, IPP requests, and HTML form data in HTTP
+POST requests. The default limit is 0 which disables the limit
+check.</P>
+
+<P><B>This directive is deprecated and will be removed in a
+future CUPS release.</B> Use the <A
+HREF="#LimitRequestBody"><CODE>LimitRequestBody</CODE></A>
+directive instead.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.4/Mac OS X 10.6</SPAN><A NAME="MultipleOperationTimeout">MultipleOperationTimeout</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+MultipleOperationTimeout 60
+MultipleOperationTimeout 300
+MultipleOperationTimeout 86400
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>MultipleOperationTimeout</CODE> directive sets the maximum amount
+of time between files in a multi-file print job. The default is 300 seconds.</P>
+
+
+<H2 CLASS="title"><A NAME="Order">Order</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Location /path&gt;
+ ...
+ Order Allow,Deny
+ Order Deny,Allow
+&lt;/Location&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Order</CODE> directive defines the default access
+control. The following values are supported:</P>
+
+<UL>
+
+ <LI><CODE>allow,deny</CODE> - Deny requests by default,
+ then check the <A HREF="#Allow"><CODE>Allow</CODE></A>
+ lines followed by the <A
+ HREF="#Deny"><CODE>Deny</CODE></A> lines</LI>
+
+ <LI><CODE>deny,allow</CODE> - Allow requests by default,
+ then check the <A HREF="#Deny"><CODE>Deny</CODE></A>
+ lines followed by the <A
+ HREF="#Allow"><CODE>Allow</CODE></A> lines</LI>
+
+</UL>
+
+<P>The <CODE>Order</CODE> directive must appear inside a <A
+HREF="#Location"><CODE>Location</CODE></A> or <A
+HREF="#Limit"><CODE>Limit</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="PageLog">PageLog</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+PageLog /var/log/cups/page_log
+PageLog /var/log/cups/page_log-%s
+PageLog syslog
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>PageLog</CODE> directive sets the name of the page
+log file. If the filename is not absolute then it is assumed to
+be relative to the <A
+HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
+default page log file is <VAR>@CUPS_LOGDIR@/page_log</VAR>.</P>
+
+<P>The server name can be included in the filename by using
+<CODE>%s</CODE> in the name.</P>
+
+<P>The special name "syslog" can be used to send the page
+information to the system log instead of a plain file.</P>
+
+
+<H2 CLASS="title"><A NAME="PageLogFormat">PageLogFormat</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+PageLogFormat %p %u %j %T %P %C %{job-billing} %{job-originating-host-name} %{job-name} %{media} %{sides}
+PageLogFormat PAGE %p %u %j %P %C %{job-billing} %{job-originating-host-name}
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>PageLogFormat</CODE> directive sets the format of lines
+that are logged to the page log file. Sequences beginning with percent (%)
+characters are replaced with the corresponding information, while all other
+characters are copied literally. The following percent sequences are
+recognized:</P>
+
+<UL>
+
+ <LI><CODE>%%</CODE>: Inserts a single percent character.</LI>
+
+ <LI><CODE>%{name}</CODE>: Inserts the value of the specified IPP
+ attribute.</LI>
+
+ <LI><CODE>%C</CODE>: Inserts the number of copies for the current page.</LI>
+
+ <LI><CODE>%P</CODE>: Inserts the current page number.</LI>
+
+ <LI><CODE>%T</CODE>: Inserts the current date and time in common log
+ format.</LI>
+
+ <LI><CODE>%j</CODE>: Inserts the job ID.</LI>
+
+ <LI><CODE>%p</CODE>: Inserts the printer name.</LI>
+
+ <LI><CODE>%u</CODE>: Inserts the username.</LI>
+
+</UL>
+
+<P>The default is "%p %u %j %T %P %C %{job-billing} %{job-originating-host-name} %{job-name} %{media} %{sides}".</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="PassEnv">PassEnv</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+PassEnv MY_ENV_VARIABLE
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>PassEnv</CODE> directive specifies an environment
+variable that should be passed to child processes. Normally, the
+scheduler only passes the <CODE>DYLD_LIBRARY_PATH</CODE>,
+<CODE>LD_ASSUME_KERNEL</CODE>, <CODE>LD_LIBRARY_PATH</CODE>,
+<CODE>LD_PRELOAD</CODE>, <CODE>NLSPATH</CODE>,
+<CODE>SHLIB_PATH</CODE>, <CODE>TZ</CODE>, and <CODE>VGARGS</CODE>
+environment variables to child processes.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="Policy">Policy</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Policy name&gt;
+ &lt;Limit operation ... operation&gt;
+ ...
+ &lt;/Limit&gt;
+ &lt;Limit operation ... operation&gt;
+ ...
+ &lt;/Limit&gt;
+ &lt;Limit All&gt;
+ ...
+ &lt;/Limit&gt;
+&lt;/Policy&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Policy</CODE> directive specifies IPP operation
+access control limits. Each policy contains 1 or more <A
+HREF="#LimitIPP"><CODE>Limit</CODE></A> sections to set the
+access control limits for specific operations - user limits,
+authentication, encryption, and allowed/denied addresses,
+domains, or hosts. The <CODE>&lt;Limit All&gt;</CODE> section
+specifies the default access control limits for operations that
+are not listed.</P>
+
+<P>Policies are named and associated with printers via the
+printer's operation policy setting
+(<CODE>printer-op-policy</CODE>). The default policy for the
+scheduler is specified using the <A
+HREF="#DefaultPolicy"><CODE>DefaultPolicy</CODE></A>
+directive.</P>
+
+
+<H2 CLASS="title"><A NAME="Port">Port</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+Port 631
+Port 80
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Port</CODE> directive specifies a port to listen on.
+Multiple <CODE>Port</CODE> lines can be specified to listen on
+multiple ports. The <CODE>Port</CODE> directive is equivalent to
+"<CODE>Listen *:nnn</CODE>". The default port is 631.</P>
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>On systems that support IPv6, this directive will bind to both
+the IPv4 and IPv6 wildcard address.</P>
+
+</BLOCKQUOTE>
+
+
+<H2 CLASS="title"><A NAME="PreserveJobHistory">PreserveJobHistory</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+PreserveJobHistory On
+PreserveJobHistory Off
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>PreserveJobHistory</CODE> directive controls whether
+the history of completed, canceled, or aborted print jobs is
+stored on disk.</P>
+
+<P>A value of <CODE>On</CODE> (the default) preserves job
+information until the administrator purges it with the
+<CODE>cancel</CODE> command.</P>
+
+<P>A value of <CODE>Off</CODE> removes the job information as
+soon as each job is completed, canceled, or aborted.</P>
+
+
+<H2 CLASS="title"><A NAME="PreserveJobFiles">PreserveJobFiles</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+PreserveJobFiles On
+PreserveJobFiles Off
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>PreserveJobFiles</CODE> directive controls whether
+the document files of completed, canceled, or aborted print jobs
+are stored on disk.</P>
+
+<P>A value of <CODE>On</CODE> preserves job files until the
+administrator purges them with the <CODE>cancel</CODE> command.
+Jobs can be restarted (and reprinted) as desired until they are
+purged.</P>
+
+<P>A value of <CODE>Off</CODE> (the default) removes the job
+files as soon as each job is completed, canceled, or aborted.</P>
+
+
+<H2 CLASS="title"><A NAME="Printcap">Printcap</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+Printcap
+Printcap /etc/printcap
+Printcap /etc/printers.conf
+Printcap /Library/Preferences/org.cups.printers.plist
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Printcap</CODE> directive controls whether or not a
+printcap file is automatically generated and updated with a list
+of available printers. If specified with no value, then no
+printcap file will be generated. The default is to generate a
+file named <VAR>@CUPS_DEFAUL_PRINTCAP@</VAR>.</P>
+
+<P>When a filename is specified (e.g. <VAR>@CUPS_DEFAULT_PRINTCAP@</VAR>),
+the printcap file is written whenever a printer is added or
+removed. The printcap file can then be used by applications that
+are hardcoded to look at the printcap file for the available
+printers.</P>
+
+
+<H2 CLASS="title"><A NAME="PrintcapFormat">PrintcapFormat</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+PrintcapFormat BSD
+PrintcapFormat Solaris
+PrintcapFormat plist
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>PrintcapFormat</CODE> directive controls the output format of the
+printcap file. The default is to generate the plist format on Mac OS X, the
+Solaris format on Solaris, and the BSD format on other operating systems.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.13</SPAN><A NAME="PrintcapGUI">PrintcapGUI</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+PrintGUI /usr/bin/glpoptions
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>PrintcapGUI</CODE> directive sets the program to
+associate with the IRIX printer GUI interface script which is
+used by IRIX applications to display printer-specific options.
+There is no default program.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.21</SPAN><A NAME="ReloadTimeout">ReloadTimeout</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ReloadTimeout 0
+ReloadTimeout 30
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ReloadTimeout</CODE> directive specifies the number
+of seconds the scheduler will wait for active jobs to complete
+before doing a restart. The default is 30 seconds.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.3</SPAN><A NAME="RemoteRoot">RemoteRoot</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+RemoteRoot remroot
+RemoteRoot root
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>RemoteRoot</CODE> directive sets the username for
+unauthenticated root requests from remote hosts. The default
+username is <VAR>remroot</VAR>. Setting <CODE>RemoteRoot</CODE>
+to <VAR>root</VAR> effectively disables this security
+mechanism.</P>
+
+
+<H2 CLASS="title"><A NAME="RequestRoot">RequestRoot</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+RequestRoot /var/spool/cups
+RequestRoot /foo/bar/spool/cups
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>RequestRoot</CODE> directive sets the directory for
+incoming IPP requests and HTML forms. If an absolute path is not
+provided then it is assumed to be relative to the <A
+HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
+default request directory is <VAR>@CUPS_REQUESTS@</VAR>.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.7</SPAN><A NAME="Require">Require</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Location /path&gt;
+ ...
+ Require group foo bar
+ Require user john mary
+ Require valid-user
+ Require user @groupname
+ Require user @SYSTEM
+ Require user @OWNER
+&lt;/Location&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Require</CODE> directive specifies that
+authentication is required for the resource. The
+<CODE>group</CODE> keyword specifies that the authenticated user
+must be a member of one or more of the named groups that
+follow.</P>
+
+<P>The <CODE>user</CODE> keyword specifies that the
+authenticated user must be one of the named users or groups that
+follow. Group names are specified using the "@" prefix.</P>
+
+<P>The <CODE>valid-user</CODE> keyword specifies that any
+authenticated user may access the resource.</P>
+
+<P>The default is to do no authentication. This directive must
+appear inside a <A HREF="#Location"><CODE>Location</CODE></A> or
+<A HREF="#Limit"><CODE>Limit</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="RIPCache">RIPCache</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+RIPCache 128m
+RIPCache 1g
+RIPCache 2048k
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>RIPCache</CODE> directive sets the size of the
+memory cache used by Raster Image Processor ("RIP") filters such
+as <CODE>imagetoraster</CODE> and <CODE>pstoraster</CODE>. The
+size can be suffixed with a "k" for kilobytes, "m" for megabytes,
+or "g" for gigabytes. The default cache size is "128m", or 128
+megabytes.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.16</SPAN><A NAME="RootCertDuration">RootCertDuration</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+RootCertDuration 0
+RootCertDuration 300
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>RootCertDuration</CODE> directive specifies the
+number of seconds the <EM>root certificate</EM> remains valid.
+The scheduler will generate a new certificate as needed when the
+number of seconds has expired. If set to 0, the root certificate
+is generated only once on startup or on a restart. The default is
+300 seconds.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.7</SPAN><A NAME="Satisfy">Satisfy</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Location /path&gt;
+ ...
+ Satisfy all
+ Satisfy any
+&lt;/Location&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Satisfy</CODE> directive specifies whether all
+conditions must be satisfied to allow access to the resource. If
+set to <CODE>all</CODE>, then all authentication and access
+control conditions must be satisfied to allow access.</P>
+
+<P>Setting <CODE>Satisfy</CODE> to <CODE>any</CODE> allows a user
+to gain access if the authentication or access control
+requirements are satisfied. For example, you might require
+authentication for remote access, but allow local access without
+authentication.</P>
+
+<P>The default is <CODE>all</CODE>. This directive must appear
+inside a <A HREF="#Location"><CODE>Location</CODE></A> or <A
+HREF="#Limit"><CODE>Limit</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="ServerAdmin">ServerAdmin</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ServerAdmin user@host
+ServerAdmin root@foo.bar.com
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ServerAdmin</CODE> directive identifies the email
+address for the administrator on the system. By default the
+administrator email address is <CODE>root@server</CODE>, where
+<CODE>server</CODE> is the <A
+HREF="#ServerName"><CODE>ServerName</CODE></A>.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.3.10</SPAN><A NAME="ServerAlias">ServerAlias</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ServerAlias althost
+ServerAlias foo.example.com
+ServerAlias bar.example.com
+ServerAlias one.example.com two.example.com
+ServerAlias *
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ServerAlias</CODE> directive specifies alternate names that the server is known by. By default it contains a list of all aliases associated with the <A HREF="#ServerName"><CODE>ServerName</CODE></A>. The special name "*" can be used to allow any hostname when accessing CUPS via an external network interfaces.</P>
+
+<BLOCKQUOTE><B>Note</B>
+
+<P>The <CODE>ServerAlias</CODE> directive is used for HTTP Host header
+validation when clients connect to the scheduler from external interfaces.
+Using the special name "*" can expose your system to known browser-based
+DNS rebinding attacks, even when accessing sites through a firewall. If the
+auto-discovery of alternate names does not work, we recommend listing each
+alternate name with a ServerAlias directive instead of using "*".</P>
+
+</BLOCKQUOTE>
+
+
+<H2 CLASS="title"><A NAME="ServerBin">ServerBin</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ServerBin /usr/lib/cups
+ServerBin /foo/bar/lib/cups
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ServerBin</CODE> directive sets the directory for
+server-run executables. If an absolute path is not provided then
+it is assumed to be relative to the <A
+HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
+default executable directory is <VAR>/usr/lib/cups</VAR>,
+<VAR>/usr/lib32/cups</VAR>, or <VAR>/usr/libexec/cups</VAR>
+depending on the operating system.</P>
+
+
+<H2 CLASS="title"><A NAME="ServerCertificate">ServerCertificate</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ServerCertificate /etc/cups/ssl/server.crt
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ServerCertificate</CODE> directive specifies the
+location of the SSL certificate file used by the server when
+negotiating encrypted connections. The certificate must not be
+encrypted (password protected) since the scheduler normally runs
+in the background and will be unable to ask for a password.</P>
+
+<P>The default certificate file is
+<VAR>/etc/cups/ssl/server.crt</VAR>.</P>
+
+
+<H2 CLASS="title"><A NAME="ServerKey">ServerKey</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ServerKey /etc/cups/ssl/server.key
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ServerKey</CODE> directive specifies the location of
+the SSL private key file used by the server when negotiating
+encrypted connections.</P>
+
+<P>The default key file is
+<VAR>/etc/cups/ssl/server.crt</VAR>.</P>
+
+
+<H2 CLASS="title"><A NAME="ServerName">ServerName</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ServerName foo.example.com
+ServerName myserver.example.com
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ServerName</CODE> directive specifies the hostname
+that is reported to clients. By default the server name is the
+hostname.</P>
+
+
+<H2 CLASS="title"><A NAME="ServerRoot">ServerRoot</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ServerRoot /etc/cups
+ServerRoot /foo/bar/cups
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ServerRoot</CODE> directive specifies the absolute
+path to the server configuration and state files. It is also used
+to resolve relative paths in the <VAR>cupsd.conf</VAR> file. The
+default server directory is <VAR>/etc/cups</VAR>.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.21</SPAN><A NAME="ServerTokens">ServerTokens</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ServerTokens None
+ServerTokens ProductOnly
+ServerTokens Major
+ServerTokens Minor
+ServerTokens Minimal
+ServerTokens OS
+ServerTokens Full
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ServerTokens</CODE> directive specifies the
+information that is included in the <CODE>Server:</CODE> header
+of all HTTP responses. Table 4 lists the token name along with
+the text that is returned. The default is
+<CODE>Minimal</CODE>.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="ServerToken Names and Values">
+<CAPTION>Table 4: <A NAME="TABLE4">ServerToken Names and Values</A></CAPTION>
+<THEAD>
+<TR>
+ <TH>Name</TH>
+ <TH>Value</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD>None</TD>
+ <TD>No <CODE>Server:</CODE> header is returned</TD>
+</TR>
+<TR>
+ <TD>ProductOnly</TD>
+ <TD>"CUPS"</TD>
+</TR>
+<TR>
+ <TD>Major</TD>
+ <TD>"CUPS 1"</TD>
+</TR>
+<TR>
+ <TD>Minor</TD>
+ <TD>"CUPS 1.2"</TD>
+</TR>
+<TR>
+ <TD>Minimal</TD>
+ <TD>"CUPS 1.2.N" where N is the patch release</TD>
+</TR>
+<TR>
+ <TD>OS</TD>
+ <TD>"CUPS 1.2.N (UNAME)" where N is the patch release and
+ UNAME is the output of the <B>uname(1)</B> command</TD>
+</TR>
+<TR>
+ <TD>Full</TD>
+ <TD>"CUPS 1.2.N (UNAME) IPP/1.1" where N is the patch
+ release and UNAME is the output of the <B>uname(1)</B>
+ command</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="SetEnv">SetEnv</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+SetEnv PATH /usr/lib/cups/filter:/bin:/usr/bin:/usr/local/bin
+SetEnv MY_ENV_VAR foo
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>SetEnv</CODE> directive specifies an environment
+variable that should be passed to child processes.</P>
+
+
+<H2 CLASS="title"><A NAME="SSLListen">SSLListen</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+SSLListen 127.0.0.1:443
+SSLListen 192.0.2.1:443
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>SSLListen</CODE> directive specifies a network
+address and port to listen for secure connections. Multiple
+<CODE>SSLListen</CODE> directives can be provided to listen on
+multiple addresses.</P>
+
+<P>The <CODE>SSLListen</CODE> directive is similar to the <A
+HREF="#SSLPort"><CODE>SSLPort</CODE></A> directive but allows you
+to restrict access to specific interfaces or networks.</P>
+
+
+<H2 CLASS="title"><A NAME="SSLOptions">SSLOptions</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+SSLOptions None
+SSLOptions NoEmptyFragments
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>SSLOptions</CODE> directive specifies additional SSL/TLS
+protocol options to use for encrypted connected. Currently only two
+options are supported - <code>None</code> (the default) for the most
+secure mode and <code>NoEmptyFragments</code> to allow CUPS to work with
+Microsoft Windows with the FIPS conformance mode enabled.</p>
+
+
+<H2 CLASS="title"><A NAME="SSLPort">SSLPort</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+SSLPort 443
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>SSLPort</CODE> directive specifies a port to listen
+on for secure connections. Multiple <CODE>SSLPort</CODE> lines
+can be specified to listen on multiple ports.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.5</SPAN><A NAME="SubscriptionPrivateAccess">SubscriptionPrivateAccess</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+SubscriptionPrivateAccess all
+SubscriptionPrivateAccess default
+SubscriptionPrivateAccess {user|@group|@ACL|@OWNER|@SYSTEM}+
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>SubscriptionPrivateAccess</CODE> directive specifies the access list for a
+subscription's private values. The "default" access list is "@OWNER @SYSTEM".
+"@ACL" maps to the printer's requesting-user-name-allowed or
+requesting-user-name-denied values.</P>
+
+<P>The <CODE>SubscriptionPrivateAccess</CODE> directive must appear inside a <A
+HREF="#Policy"><CODE>Policy</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.5</SPAN><A NAME="SubscriptionPrivateValues">SubscriptionPrivateValues</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+SubscriptionPrivateValues all
+SubscriptionPrivateValues default
+SubscriptionPrivateValues none
+SubscriptionPrivateValues attribute-name-1 [ ... attribute-name-N ]
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>SubscriptionPrivateValues</CODE> directive specifies the list of
+subscription values to make private. The "default" values are "notify-events",
+"notify-pull-method", "notify-recipient-uri", "notify-subscriber-user-name", and
+"notify-user-data".</P>
+
+<P>The <CODE>SubscriptionPrivateValues</CODE> directive must appear inside a <A
+HREF="#Policy"><CODE>Policy</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="SystemGroup">SystemGroup</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+SystemGroup lpadmin
+SystemGroup sys
+SystemGroup system
+SystemGroup root
+SystemGroup root lpadmin
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>SystemGroup</CODE> directive specifies the system
+administration group for <CODE>System</CODE> authentication.
+Multiple groups can be listed, separated with spaces. The default
+group list is <CODE>@CUPS_SYSTEM_GROUPS@</CODE>.</P>
+
+
+<H2 CLASS="title"><A NAME="TempDir">TempDir</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+TempDir /var/tmp
+TempDir /foo/bar/tmp
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>TempDir</CODE> directive specifies an absolute path
+for the directory to use for temporary files. The default
+directory is <VAR>@CUPS_REQUESTS@/tmp</VAR>.</P>
+
+<P>Temporary directories must be world-writable and should have
+the "sticky" permission bit enabled so that other users cannot
+delete filter temporary files. The following commands will create
+an appropriate temporary directory called
+<VAR>/foo/bar/tmp</VAR>:</P>
+
+<PRE CLASS="command">
+<KBD>mkdir /foo/bar/tmp</KBD>
+<KBD>chmod a+rwxt /foo/bar/tmp</KBD>
+</PRE>
+
+
+<H2 CLASS="title"><A NAME="Timeout">Timeout</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+Timeout 300
+Timeout 90
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Timeout</CODE> directive controls the amount of time
+to wait before an active HTTP or IPP request times out. The
+default timeout is 300 seconds.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="UseNetworkDefault">UseNetworkDefault</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+UseNetworkDefault yes
+UseNetworkDefault no
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>UseNetworkDefault</CODE> directive controls whether
+the client will use a network/remote printer as a default
+printer. If enabled, the default printer of a server is used as
+the default printer on a client. When multiple servers are
+advertising a default printer, the client's default printer is
+set to the first discovered printer, or to the implicit class for
+the same printer available from multiple servers.</P>
+
+<P>The default is <CODE>@CUPS_USE_NETWORK_DEFAULT@</CODE>.</P>
+
+
+<H2 CLASS="title"><A NAME="User">User</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+User lp
+User guest
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>User</CODE> directive specifies the UNIX user that
+filter and CGI programs run as. The default user is
+<CODE>@CUPS_USER@</CODE>.</P>
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>You may not use user <CODE>root</CODE>, as that would expose
+the system to unacceptable security risks. The scheduler will
+automatically choose user <CODE>nobody</CODE> if you specify a
+user whose ID is 0.</P>
+
+</BLOCKQUOTE>
+
+
+<H2 CLASS="title"><SPAN CLASS="INFO">CUPS 1.5</SPAN><A NAME="WebInterface">WebInterface</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+WebInterface yes
+WebInterface no
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>WebInterface</CODE> directive specifies whether the web interface is enabled. The default value is <CODE>@CUPS_WEBIF@</CODE>.</P>
+
+</BODY>
+</HTML>
diff --git a/doc/help/ref-error_log.html b/doc/help/ref-error_log.html
new file mode 100644
index 000000000..010927802
--- /dev/null
+++ b/doc/help/ref-error_log.html
@@ -0,0 +1,55 @@
+<HTML>
+<!-- SECTION: References -->
+<HEAD>
+ <TITLE>error_log</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">error_log</H1>
+
+<P>The <VAR>error_log</VAR> file lists messages from the
+scheduler - errors, warnings, etc. The <A
+HREF="ref-cupsd-conf.html#LogLevel"><CODE>LogLevel</CODE></A>
+directive controls which messages are logged:</P>
+
+<P CLASS="command">
+
+level date-time message<BR>
+
+<BR>
+
+I [20/May/1999:19:18:28 +0000] Job 1 queued on 'DeskJet' by 'mike'.<BR>
+
+I [20/May/1999:19:21:02 +0000] Job 2 queued on 'DeskJet' by 'mike'.<BR>
+
+I [20/May/1999:19:22:24 +0000] Job 2 was cancelled by 'mike'.<BR>
+
+</P>
+
+<P>The <I>level</I> field contains the type of message:</P>
+
+<UL>
+
+ <LI><CODE>A</CODE> - Alert message (LogLevel alert)
+ <LI><CODE>C</CODE> - Critical error message (LogLevel crit)
+ <LI><CODE>D</CODE> - Debugging message (LogLevel debug)
+ <LI><CODE>d</CODE> - Detailed debugging message (LogLevel debug2)
+ <LI><CODE>E</CODE> - Normal error message (LogLevel error)
+ <LI><CODE>I</CODE> - Informational message (LogLevel info)
+ <LI><CODE>N</CODE> - Notice message (LogLevel notice)
+ <LI><CODE>W</CODE> - Warning message (LogLevel warn)
+ <LI><CODE>X</CODE> - Emergency error message (LogLevel emerg)
+
+</UL>
+
+<P>The <I>date-time</I> field contains the date and time of when
+the page started printing. The format of this field is identical
+to the <I>data-time</I> field in the <VAR>access_log</VAR> file.</P>
+
+<P>The <I>message</I> fields contains a free-form textual
+message. Messages from job filters are prefixed with "<CODE>[Job
+NNN]</CODE>".</P>
+
+</BODY>
+</HTML>
diff --git a/doc/help/ref-mailto-conf.html b/doc/help/ref-mailto-conf.html
new file mode 100644
index 000000000..0b9513220
--- /dev/null
+++ b/doc/help/ref-mailto-conf.html
@@ -0,0 +1,108 @@
+<HTML>
+<!-- SECTION: References -->
+<HEAD>
+ <TITLE>mailto.conf</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">mailto.conf</H1>
+
+<P>The <VAR>/etc/cups/mailto.conf</VAR> file contains several
+directives that defines the local mail server and email
+notification preferences for CUPS. Each directive is listed on a
+line by itself followed by its value. Comments are introduced
+using the number sign ("#") character at the beginning of a
+line.</P>
+
+
+<H2 CLASS="title"><A NAME="Cc">Cc</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+Cc bigbrother@example.com
+Cc John Doe &lt;jd@example.com>
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Cc</CODE> directive specifies an additional
+recipient ("carbon copy") for all email notifications. The
+default is to not send a copy to anyone but the subscriber.</P>
+
+
+<H2 CLASS="title"><A NAME="From">From</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+From printserver@example.com
+From Your Happy Printer &lt;printserver@example.com>
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>From</CODE> directive specifies the sender of email
+notifications. The default is the <A
+HREF="ref-cupsd-conf.html#ServerAdmin"><TT>ServerAdmin</TT><A>
+address defined in the <VAR>cupsd.conf</VAR> file.</P>
+
+
+<H2 CLASS="title"><A NAME="Sendmail">Sendmail</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+Sendmail /usr/sbin/sendmail
+Sendmail /usr/lib/sendmail -bm -i
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Sendmail</CODE> directive specifies the command to
+run to deliver an email locally. This directive cannot be used
+with the <TT>SMTPServer</TT> directive, and if both
+<TT>Sendmail</TT> and <TT>SMTPServer</TT> lines appear in the
+<VAR>mailto.conf</VAR> file, only the last line is used. The
+default is <TT>/usr/sbin/sendmail</TT>.</P>
+
+
+<H2 CLASS="title"><A NAME="SMTPServer">SMTPServer</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+SMTPServer mail.example.com
+SMTPServer 192.168.2.1
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>SMTPServer</CODE> directive specifies a hostname or
+IP address of a (possibly remote) SMTP mail server. This
+directive cannot be used with the <TT>Sendmail</TT> directive,
+and if both <TT>Sendmail</TT> and <TT>SMTPServer</TT> lines
+appear in the <VAR>mailto.conf</VAR> file, only the last line is
+used. The default is to use the <TT>Sendmail</TT> command
+instead.</P>
+
+
+<H2 CLASS="title"><A NAME="Subject">Subject</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+Subject [CUPS]
+Subject URGENT EMAIL NOTIFICATION
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Subject</CODE> directive specifies a prefix string to
+add to the subject of each email notification. The default is to
+not add a prefix string.</P>
+
+
+</BODY>
+</HTML>
diff --git a/doc/help/ref-page_log.html b/doc/help/ref-page_log.html
new file mode 100644
index 000000000..076cc4b9c
--- /dev/null
+++ b/doc/help/ref-page_log.html
@@ -0,0 +1,77 @@
+<HTML>
+<!-- SECTION: References -->
+<HEAD>
+ <TITLE>page_log</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">page_log</H1>
+
+<P>The <VAR>page_log</VAR> file lists each page that is sent to a
+printer. By default, each line contains the following information:</P>
+
+<P CLASS="command">
+
+printer user job-id date-time page-number num-copies job-billing job-originating-host-name job-name media sides<BR>
+
+<BR>
+
+DeskJet root 2 [20/May/1999:19:21:05 +0000] 1 1 acme-123 localhost myjob letter one-sided<BR>
+
+DeskJet root 2 [20/May/1999:19:21:05 +0000] 2 1 acme-123 localhost myjob letter one-sided<BR>
+
+</P>
+
+<p>The <a href="ref-cupsd_conf.html#PageLogFormat"><code>PageLogFormat</code></a>
+directive can be used to change this information.</p>
+
+<P>The <I>printer</I> field contains the name of the printer that
+printed the page. If you send a job to a printer class, this
+field will contain the name of the printer that was assigned the
+job.</P>
+
+<P>The <I>user</I> field contains the name of the user (the IPP
+<CODE>requesting-user-name</CODE> attribute) that submitted this
+file for printing.</P>
+
+<P>The <I>job-id</I> field contains the job number of the page
+being printed. Job numbers are reset to 1 whenever the spool
+directory (<VAR>/var/spool/cups</VAR>) is cleared, so don't
+depend on this number being unique!</P>
+
+<P>The <I>date-time</I> field contains the date and time of when
+the page started printing. The format of this field is identical
+to the <I>data-time</I> field in the <VAR>access_log</VAR>
+file.</P>
+
+<P>The <I>page-number</I> and <I>num-copies</I> fields contain the
+page number and number of copies being printed of that page. For
+printers that cannot produce copies on their own, the
+<I>num-copies</I> field will always be 1.</P>
+
+<P>The <I>job-billing</I> field contains a copy of the
+<CODE>job-billing</CODE> attribute provided with the IPP
+<CODE>Create-Job</CODE> or <CODE>Print-Job</CODE> requests or "-"
+if none was provided.
+
+<P>The <I>job-originating-host-name</I> field contains the hostname or IP
+address of the client that printed the job.</P>
+
+<P>The <I>job-name</I> field contains a copy of the
+<CODE>job-name</CODE> attribute provided with the IPP
+<CODE>Create-Job</CODE> or <CODE>Print-Job</CODE> requests or "-"
+if none was provided.
+
+<P>The <I>media</I> field contains a copy of the
+<CODE>media</CODE> attribute provided with the IPP
+<CODE>Create-Job</CODE> or <CODE>Print-Job</CODE> requests or "-"
+if none was provided.
+
+<P>The <I>sides</I> field contains a copy of the
+<CODE>sides</CODE> attribute provided with the IPP
+<CODE>Create-Job</CODE> or <CODE>Print-Job</CODE> requests or "-"
+if none was provided.
+
+</BODY>
+</HTML>
diff --git a/doc/help/ref-ppdcfile.html b/doc/help/ref-ppdcfile.html
new file mode 100644
index 000000000..c3967f1c2
--- /dev/null
+++ b/doc/help/ref-ppdcfile.html
@@ -0,0 +1,2449 @@
+<HTML>
+<!-- SECTION: References -->
+<HEAD>
+ <TITLE>PPD Compiler Driver Information File Reference</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">PPD Compiler Driver Information File Reference</H1>
+
+<p>The CUPS PPD compiler reads meta files that contain descriptions
+of one or more PPD files to be generated by
+<a href="man-ppdc.html">ppdc(1)</a> or the corresponding driver interface
+program <a href="man-drv.html">drv(1)</a>. The source file format is plain
+ASCII text that can be edited using your favorite text editor.</p>
+
+<p>Directives may be placed anywhere on a line and are followed by
+zero or more values.</p>
+
+<p>Comments are supported using the C (/* ... */) and C++ (// ...) comment
+mechanisms.</p>
+
+<p>Directives that accept expressions look for sequences of the form:</p>
+
+<dl>
+
+ <dt>NAME</dt>
+ <dd>Evaluates to 1 if NAME is defined, otherwise 0.</dd>
+
+ <dt>number</dt>
+
+ <dd>Evaluates to the specified integer; the number can be preceded by
+ a leading sign (+/-) followed by a decimal number (1234), octal number
+ (01234), or hexadecimal number (0x1234) using the same rules as C and
+ C++.</dd>
+
+ <dt>(NAME NAME ... number number ...)</dt>
+ <dd>Evaluates to the bitwise OR of each named #define constant or
+ number.</dd>
+
+ <dt>(NAME == OTHERNAME)</dt>
+ <dt>(NAME == number)</dt>
+ <dd>Evaluates to 1 if NAME is equal to the other named constant or
+ number, otherwise 0.</dd>
+
+ <dt>(NAME != OTHERNAME)</dt>
+ <dt>(NAME != number)</dt>
+ <dd>Evaluates to 1 if NAME is not equal to the other named constant or
+ number, otherwise 0.</dd>
+
+ <dt>(NAME &lt; OTHERNAME)</dt>
+ <dt>(NAME &lt; number)</dt>
+ <dd>Evaluates to 1 if NAME is less than to the other named constant or
+ number, otherwise 0.</dd>
+
+ <dt>(NAME &lt;= OTHERNAME)</dt>
+ <dt>(NAME &lt;= number)</dt>
+ <dd>Evaluates to 1 if NAME is less than or equal to the other named
+ constant or number, otherwise 0.</dd>
+
+ <dt>(NAME &gt; OTHERNAME)</dt>
+ <dt>(NAME &gt; number)</dt>
+ <dd>Evaluates to 1 if NAME is greater than to the other named constant
+ or number, otherwise 0.</dd>
+
+ <dt>(NAME &gt;= OTHERNAME)</dt>
+ <dt>(NAME &gt;= number)</dt>
+ <dd>Evaluates to 1 if NAME is greater than or equal to the other named
+ constant or number, otherwise 0.</dd>
+
+</dl>
+
+<p>Printer driver information can be grouped and shared using
+curly braces ({ ... }); PPD files are written when a close
+brace or end-of-file is seen and a <a href="#PCFileName">PCFileName</a>
+directive has been defined.</p>
+
+
+<h2 class="title"><a name='_define'>#define</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+#define <i>name expression</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+#define FOO 100
+#define BAR "Bar, Inc."
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>#define</code> directive assigns a value to a name
+which can be later referenced using <code>$name</code>. The name is
+case-insensitive and can be any sequence of letters, numbers,
+and the underscore. The value can be any valid expression.</p>
+
+<h3>Predefined Names</h3>
+
+<p>The following <code>#define</code> names are set by the PPD compiler:</p>
+
+<ul>
+
+ <li><code>CUPS_VERSION</code> - The full CUPS version string, e.g.
+ "1.4.0"</li>
+
+ <li><code>CUPS_VERSION_MAJOR</code> - The major version number, e.g.
+ "1"</li>
+
+ <li><code>CUPS_VERSION_MINOR</code> - The minor version number, e.g.
+ "4"</li>
+
+ <li><code>CUPS_VERSION_PATCH</code> - The patch version number, e.g.
+ "0"</li>
+
+ <li><code>PLATFORM_NAME</code> - The operating system name used by the
+ current system as reported by "uname" ("Windows" on Microsoft
+ Windows)</li>
+
+ <li><code>PLATFORM_ARCH</code> - The processor architecture used by the
+ current system as reported by "uname -m" ("X86" or "X64" on Microsoft
+ Windows)</li>
+
+</ul>
+
+<h3>See Also</h3>
+
+<p><a href='#_include'><code>#include</code></a></p>
+
+
+<h2 class="title"><a name='_elif'>#elif</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+#elif <i>expression</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+#if HAVE_FOO
+...
+#elif (HAVE_BAR &gt;= 999)
+...
+#else
+...
+#endif
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>#elif</code> directive allows portions of a driver information file
+to be used conditionally. <code>#elif</code> directives must appear after a
+corresponding <a href="#_if"><code>#if</code></a> directive.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#_else'><code>#else</code></a>,
+<a href='#_endif'><code>#endif</code></a>,
+<a href='#_if'><code>#if</code></a></p>
+
+
+<h2 class="title"><a name='_else'>#else</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+#else
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+#if HAVE_FOO
+...
+#elif (HAVE_BAR &gt;= 999)
+...
+#else
+...
+#endif
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>#else</code> directive allows portions of a driver information file
+to be used conditionally when the corresponding
+<a href="#_if"><code>#if</code></a> and <a href="#_elif"><code>#elif</code></a>
+expressions are non-zero.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#_elif'><code>#elif</code></a>,
+<a href='#_endif'><code>#endif</code></a>,
+<a href='#_if'><code>#if</code></a></p>
+
+
+<h2 class="title"><a name='_endif'>#endif</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+#endif
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+#if HAVE_FOO
+...
+#elif (HAVE_BAR &gt;= 999)
+...
+#else
+...
+#endif
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>#endif</code> directive ends a conditional block of a driver
+information file. It must appear after all of the
+<a href="#_if"><code>#if</code></a>, <a href="#_elif"><code>#elif</code></a>,
+and <a href="#_else"><code>#else</code></a> directives for the current
+conditional block.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#_elif'><code>#elif</code></a>,
+<a href='#_else'><code>#else</code></a>,
+<a href='#_if'><code>#if</code></a></p>
+
+
+<h2 class="title"><a name='_font'>#font</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+#font <i>name encoding "version" charset status</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+#font Courier Standard "(1.05)" Standard ROM
+#font Symbol Special "(001.005)" Special ROM
+#font Barcode-Foo Special "(1.0)" Special Disk
+#font Unicode-Foo Expert "(2.0)" Adobe-Identity ROM
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>#font</code> directive defines a "base font" for all
+printer drivers. The name is the PostScript font name.</p>
+
+<p>The encoding is the default encoding of the font, usually
+<code>Standard</code>, <code>Expert</code>, or <code>Special</code>, as
+defined in the Adobe PPD file specification.</p>
+
+<p>The version is the PostScript string definition that
+corresponds to the font version number.</p>
+
+<p>The charset defines the available characters in the font,
+usually <code>Standard</code> or <code>Special</code>, as defined in the
+Adobe PPD file specification.</p>
+
+<p>The status is the installation status of the font and must be
+either the word <code>ROM</code> or <code>Disk</code>.
+
+<p>Base fonts differ from fonts defined using the <a
+href='#Font'><code>Font</code></a> directive in that they are not
+automatically associated with all drivers - you must use the
+special <code>Font *</code> directive to include them in a
+driver.</p>
+
+<p>Currently the <code>#font</code> directive is used mainly for
+defining the standard raster fonts in the
+<code>&lt;font.defs&gt;</code> include file.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#_include'><code>#include</code></a>,
+<a href='#Font'><code>Font</code></a></p>
+
+
+<h2 class="title"><a name='_if'>#if</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+#if <i>name or expression</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+#if HAVE_FOO
+...
+#elif (HAVE_BAR &gt;= 999)
+...
+#else
+...
+#endif
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>#if</code> directive allows portions of a driver information file
+to be used conditionally. When followed by a name, the data that follows is
+used only when the name is defined, otherwise the data is ignored.
+<code>#if</code> directives can be nested up to 100 times.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#_elif'><code>#elif</code></a>,
+<a href='#_else'><code>#else</code></a>,
+<a href='#_endif'><code>#endif</code></a></p>
+
+
+<h2 class="title"><a name='_include'>#include</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+#include &lt;<i>filename</i>&gt;
+#include "<i>filename</i>"
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+#include &lt;font.defs&gt;
+#include "myfile.h"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>#include</code> directive reads the named driver
+information file. If the filename is included inside angle
+brackets (<code>&lt;filename&gt;</code>), then the PPD compiler will
+look for the file in all of the include directories it knows
+about. Otherwise, the file is opened in the current directory
+relative to the current driver information file, and if that
+fails then it looks in the include directories for the file.</p>
+
+<p>The <code>#include</code> directive can be nested to as many
+files as are allowed by the host operating system, typically at
+least 100 files.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#_define'><code>#define</code></a>,
+<a href='#_font'><code>#font</code></a>,
+<a href='#_media'><code>#media</code></a></p>
+
+
+<h2 class="title"><a name='_media'>#media</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+#media <i>name width length</i>
+#media <i>"name/text" width length</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+#media "Letter/Letter - 8.5x11in" 8.5in 11in
+#media "A4/A4 - 210x297mm" 210mm 297mm
+#media "w936h1368/Super B/A3 - 13x19in" 936 1368
+#media Photo 4in 6in
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>#media</code> directive defines a named media size for
+inclusion in a driver. The name with optional user text defines
+the name for the media size and is used with the <a
+href='#MediaSize'><code>MediaSize</code></a> directive to associate
+the media size with the driver. The name may contain up to 40 ASCII
+characters within the range of decimal 33 to decimal 126 inclusive,
+except for the characters comma (44), slash (47) and colon (58).
+The user text, if supplied, may not exceed 80 bytes in length.</p>
+
+<p>The width and length define the dimensions of the media. Each
+number is optionally followed by one of the following unit
+suffixes:</p>
+
+<ul>
+
+ <li><code>cm</code> - centimeters</li>
+
+ <li><code>ft</code> - feet</li>
+
+ <li><code>in</code> - inches</li>
+
+ <li><code>m</code> - meters</li>
+
+ <li><code>mm</code> - millimeters</li>
+
+ <li><code>pt</code> - points (72 points = 1 inch)</li>
+
+</ul>
+
+<p>Points are assumed if no units are specified.
+
+<h3>See Also</h3>
+
+<p><a href='#_include'><code>#include</code></a>,
+<a href='#CustomMedia'><code>CustomMedia</code></a>,
+<a href='#MediaSize'><code>MediaSize</code></a></p>
+
+
+<h2 class="title"><a name='_po'>#po</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+#po <i>locale filename</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+#po es "es.po"
+#po fr_CA "mydriver-fr_CA.po"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>#po</code> directive defines a message catalog to use for the
+given POSIX language abbreviation. Multiple <code>#po</code> directives can be
+specified to list multiple catalogs. The filename can be an absolute path or
+relative to the driver information file. GNU gettext and Mac OS X .strings
+files are supported.</p>
+
+
+<h2 class="title"><a name='Attribute'>Attribute</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Attribute <i>name "" value</i>
+Attribute <i>name keyword value</i>
+Attribute <i>name "keyword/text" value</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Attribute cupsInkChannels "" 1
+Attribute cupsAllDither 600dpi "1.0"
+Attribute fooProfile "Photo/Photographic Profile" "photopro.icc"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Attribute</code> directive creates a PPD attribute. The
+name may contain up to 40 ASCII characters within the range of decimal
+33 to decimal 126 inclusive, except for the characters comma (44),
+slash (47) and colon (58).</p>
+
+<p>The selector can be the empty string (<code>""</code>) or text of up
+to 80 bytes.</p>
+
+<p>The value is any string or number; the string may contain multiple
+lines, however no one line may exceed 255 bytes.</p>
+
+<h3>See Also</h3>
+
+<p><a href="#LocAttribute"><code>LocAttribute</code></a></p>
+
+
+<h2 class="title"><a name='Choice'>Choice</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Choice <i>name "code"</i>
+Choice <i>"name/text" "code"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Choice None "&lt;&lt;/MediaType (None)&gt;&gt;setpagedevice"
+Choice "False/No" "&lt;&lt;/cupsCompression 0&gt;&gt;setpagedevice"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Choice</code> directive adds a single choice to the
+current option. The name may contain up to 40 ASCII characters within
+the range of decimal 33 to decimal 126 inclusive, except for the
+characters comma (44), slash (47) and colon (58).</p>
+
+<p>If provided, the text can be any string up to 80 bytes
+in length. If no text is provided, the name is used.</p>
+
+<p>The code is any string and may contain multiple lines,
+however no one line may exceed 255 bytes.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#ColorModel'><code>ColorModel</code></a>,
+<a href='#Cutter'><code>Cutter</code></a>,
+<a href='#Darkness'><code>Darkness</code></a>,
+<a href='#Duplex'><code>Duplex</code></a>,
+<a href='#Finishing'><code>Finishing</code></a>,
+<a href='#Group'><code>Group</code></a>,
+<a href='#InputSlot'><code>InputSlot</code></a>,
+<a href='#Installable'><code>Installable</code></a>,
+<a href='#MediaType'><code>MediaType</code></a>,
+<a href='#Option'><code>Option</code></a>,
+<a href='#Resolution'><code>Resolution</code></a>,
+<a href='#UIConstraints'><code>UIConstraints</code></a></p>
+
+
+<h2 class="title"><a name='ColorDevice'>ColorDevice</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+ColorDevice <i>boolean-value</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+ColorDevice no
+ColorDevice yes
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>ColorDevice</code> directive tells the application if
+the printer supports color. It is typically used in conjunction
+with the <a href='#ColorModel'><code>ColorModel</code></a> directive
+to provide color printing support.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#ColorModel'><code>ColorModel</code></a></p>
+
+
+<h2 class="title"><span class="info">Deprecated</span><a name='ColorModel'>ColorModel</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+ColorModel <i>name colorspace colororder compression</i>
+ColorModel <i>"name/text" colorspace colororder compression</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+ColorModel Gray/Grayscale w chunky 0
+ColorModel RGB/Color rgb chunky 0
+ColorModel CMYK cmyk chunky 0
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>ColorModel</code> directive is a convenience directive
+which creates a ColorModel option and choice for the current
+printer driver. The name may contain up to 40 ASCII characters within
+the range of decimal 33 to decimal 126 inclusive, except for the
+characters comma (44), slash (47) and colon (58).</p>
+
+<p>If provided, the text can be any string up to 80 bytes in length.
+If no text is provided, the name is used.</p>
+
+<p>The colorspace argument is one of the standard colorspace
+keywords defined later in this appendix in the section titled,
+"<a href='#REF_COLOR_SPACE'>Colorspace Keywords</a>".</p>
+
+<P>The colororder argument is one of the standard color order
+keywords defined later in this appendix in the section titled,
+"<a href='#REF_COLOR_ORDER'>Color Order Keywords</a>".</p>
+
+<p>The compression argument is any number and is assigned to the
+<code>cupsCompression</code> attribute in the PostScript page device
+dictionary.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#Choice'><code>Choice</code></a>,
+<a href='#ColorDevice'><code>ColorDevice</code></a>,
+<a href='#Cutter'><code>Cutter</code></a>,
+<a href='#Darkness'><code>Darkness</code></a>,
+<a href='#Duplex'><code>Duplex</code></a>,
+<a href='#Finishing'><code>Finishing</code></a>,
+<a href='#Group'><code>Group</code></a>,
+<a href='#InputSlot'><code>InputSlot</code></a>,
+<a href='#Installable'><code>Installable</code></a>,
+<a href='#MediaType'><code>MediaType</code></a>,
+<a href='#Option'><code>Option</code></a>,
+<a href='#Resolution'><code>Resolution</code></a>,
+<a href='#UIConstraints'><code>UIConstraints</code></a></p>
+
+
+<h2 class="title"><span class="info">Deprecated</span><a name='ColorProfile'>ColorProfile</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+ColorProfile <i>resolution/mediatype gamma density matrix</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+ColorProfile -/- 1.7 1.0
+ 1.0 0.0 0.0
+ 0.0 1.0 0.0
+ 0.0 0.0 1.0
+
+ColorProfile 360dpi/- 1.6 1.0
+ 1.0 -0.05 -0.3
+ -0.35 1.0 -0.15
+ -0.095 -0.238 0.95
+
+ColorProfile 720dpi/Special 1.5 1.0
+ 1.0 0.0 -0.38
+ -0.4 1.0 0.0
+ 0.0 -0.38 0.9
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>ColorProfile</code> directive defines a CMY
+transform-based color profile. The resolution and mediatype
+arguments specify the <code>Resolution</code> and <code>MediaType</code>
+choices which use the profile; the hyphen (<code>-</code>) is used to
+specify that any resolution or mediatype can be used with the
+profile.</p>
+
+<p>The gamma argument specifies the gamma correction to apply to
+the color values (P = p<sup>g</sup>) and is a real number
+greater than 0. Values larger than 1 cause a general lightening
+of the print while values smaller than 1 cause a general
+darkening of the print. A value of 1 disables gamma
+correction.</p>
+
+<p>The density argument specifies the linear density correction
+to apply to the color values (P = d * p<sup>g</sup>) and is a
+real number greater than 0 and less than or equal to 1. A value
+1 of disables density correction while lower values produce
+proportionately lighter output.</p>
+
+<p>The matrix argument specifies a 3x3 linear transformation
+matrix in row-major order. The matrix is applied only to the CMY
+component of a RGB to CMYK transformation and is not used when
+printing in grayscale or CMYK mode unless the printer only
+supports printing with 3 colors.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#SimpleColorProfile'><code>SimpleColorProfile</code></a></p>
+
+
+<h2 class="title"><a name='Copyright'>Copyright</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Copyright <i>"text"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Copyright "Copyright 2008 by Foo Enterprises"
+
+Copyright
+"This software 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 software 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 software; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+MA 02111 USA"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Copyright</code> directive adds text comments to the
+top of a PPD file, typically for use in copyright notices. The
+text argument can contain multiple lines of text, but no line
+may exceed 255 bytes.</p>
+
+
+<h2 class="title"><a name='CustomMedia'>CustomMedia</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+CustomMedia <i>name width length left bottom right top
+ "size-code" "region-code"</i>
+
+CustomMedia <i>"name/text" width length left bottom right top
+ "size-code" "region-code"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+CustomMedia Letter 8.5in 11in 0.25in 0.46in 0.25in 0.04in
+ "&lt;&lt;/PageSize[612 792]/ImagingBBox null/ManualFeed false&gt;&gt;
+ setpagedevice"
+ "&lt;&lt;/PageSize[612 792]/ImagingBBox null/ManualFeed true&gt;&gt;
+ setpagedevice"
+
+CustomMedia "A4/A4 - 210x297mm" 210mm 297mm 12 12 12 12
+ "&lt;&lt;/PageSize[595 842]/ImagingBBox null&gt;&gt;setpagedevice"
+ "&lt;&lt;/PageSize[595 842]/ImagingBBox null&gt;&gt;setpagedevice"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>CustomMedia</code> directive adds a custom media size to
+the driver. The name may contain up to 40 ASCII characters within the
+range of decimal 33 to decimal 126 inclusive, except for the characters
+comma (44), slash (47) and colon (58).</p>
+
+<p>If provided, the text can be any string up to 80 bytes in length.
+If no text is provided, the name is used.</p>
+
+<p>The width and length arguments specify the dimensions of the
+media as defined for the <a href="#_media"><code>#media</code></a>
+directive.</p>
+
+<p>The left, bottom, right, and top arguments specify the
+printable margins of the media.</p>
+
+<p>The size-code and region-code arguments specify the
+PostScript commands to run for the <code>PageSize</code> and
+<code>PageRegion</code> options, respectively. The commands can
+contain multiple lines, however no line may be more than 255
+bytes in length.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#_media'><code>#media</code></a>,
+<a href='#MediaSize'><code>MediaSize</code></a></p>
+
+
+<h2 class="title"><a name='Cutter'>Cutter</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Cutter <i>boolean-value</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Cutter yes
+Cutter no
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Cutter</code> directive specifies whether the printer
+has a built-in media cutter. When a cutter is present, the
+printer's PPD file will contain a <code>CutMedia</code> option that
+allows the user to control whether the media is cut at the end
+of the job.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#Choice'><code>Choice</code></a>,
+<a href='#ColorModel'><code>ColorModel</code></a>,
+<a href='#Darkness'><code>Darkness</code></a>,
+<a href='#Duplex'><code>Duplex</code></a>,
+<a href='#Finishing'><code>Finishing</code></a>,
+<a href='#Group'><code>Group</code></a>,
+<a href='#InputSlot'><code>InputSlot</code></a>,
+<a href='#Installable'><code>Installable</code></a>,
+<a href='#MediaType'><code>MediaType</code></a>,
+<a href='#Option'><code>Option</code></a>,
+<a href='#Resolution'><code>Resolution</code></a>,
+<a href='#UIConstraints'><code>UIConstraints</code></a></p>
+
+
+<h2 class="title"><span class="info">Deprecated</span><a name='Darkness'>Darkness</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Darkness <i>temperature name</i>
+Darkness <i>temperature "name/text"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Darkness 0 Light
+Darkness 2 "Normal/Standard"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Darkness</code> directive defines a choice for the
+<code>cupsDarkness</code> option which sets the
+<code>cupsCompression</code> attribute in the PostScript page device
+dictionary. It is used with the CUPS <VAR>rastertolabel</VAR>
+sample driver to control the print head temperature and
+therefore the darkness of the print.</p>
+
+<p>The temperature argument specifies a temperature value for
+the Dymo driver from 0 (lowest) to 3 (highest), with 2
+representing the normal setting.</p>
+
+<p>The name may contain up to 40 ASCII characters within the range of
+decimal 33 to decimal 126 inclusive, except for the characters comma
+(44), slash (47) and colon (58).</p>
+
+<p>If provided, the text can be any string up to 80 bytes in length.
+If no text is provided, the name is used.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#Choice'><code>Choice</code></a>,
+<a href='#ColorModel'><code>ColorModel</code></a>,
+<a href='#Cutter'><code>Cutter</code></a>,
+<a href='#Duplex'><code>Duplex</code></a>,
+<a href='#Finishing'><code>Finishing</code></a>,
+<a href='#Group'><code>Group</code></a>,
+<a href='#InputSlot'><code>InputSlot</code></a>,
+<a href='#Installable'><code>Installable</code></a>,
+<a href='#MediaType'><code>MediaType</code></a>,
+<a href='#Option'><code>Option</code></a>,
+<a href='#Resolution'><code>Resolution</code></a>,
+<a href='#UIConstraints'><code>UIConstraints</code></a></p>
+
+
+<h2 class="title"><a name='DriverType'>DriverType</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+DriverType <i>type</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+DriverType custom
+DriverType escp
+DriverType pcl
+DriverType ps
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>DriverType</code> directive tells the PPD compiler
+which DDK filters to include in the PPD file. The following
+types are supported:</p>
+
+<ul>
+
+ <li><code>custom</code> - Use only those filters that are
+ defined in the driver information file</li>
+
+ <li><code>epson</code> - Use the CUPS sample Epson driver filter
+ <var>rastertoepson</var></li>
+
+ <li><code>escp</code> - Use the ESC/P DDK driver filters
+ <var>commandtoescpx</var> and
+ <var>rastertoescpx</var></li>
+
+ <li><code>hp</code> - Use the CUPS sample HP driver filter
+ <var>rastertohp</var></li>
+
+ <li><code>label</code> - Use the CUPS sample label driver filter <var>rastertolabel</var></li>
+
+ <li><code>pcl</code> - Use the HP-PCL DDK driver filters
+ <var>commandtopclx</var> and
+ <var>rastertopclx</var></li>
+
+ <li><code>ps</code> - Use no filters; this driver is for a
+ standard PostScript device</li>
+
+</ul>
+
+<h3>See Also</h3>
+
+<p><a href='#Filter'><code>Filter</code></a>,
+<a href='#ModelNumber'><code>ModelNumber</code></a></p>
+
+
+<h2 class="title"><a name='Duplex'>Duplex</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Duplex <i>type</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Duplex none
+Duplex normal
+Duplex flip
+Duplex rotated
+Duplex manualtumble
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Duplex</code> directive determines whether double-sided printing
+is supported in the current driver. The type argument specifies the type
+of duplexing that is supported:</p>
+
+<ul>
+
+ <li><code>none</code> - double-sided printing is not
+ supported</li>
+
+ <li><code>normal</code> - double-sided printing is
+ supported</li>
+
+ <li><code>flip</code> - double-sided printing is supported,
+ but the back side image needs to be flipped vertically
+ (used primarily with inkjet printers)</li>
+
+ <li><code>rotated</code> - double-sided printing is supported,
+ but the back side image needs to be rotated 180 degrees for
+ DuplexNoTumble</li>
+
+ <li><code>manualtumble</code> - double-sided printing is supported,
+ but the back side image needs to be rotated 180 degrees for
+ DuplexTumble</li>
+
+</ul>
+
+<h3>See Also</h3>
+
+<p><a href='#Choice'><code>Choice</code></a>,
+<a href='#ColorModel'><code>ColorModel</code></a>,
+<a href='#Cutter'><code>Cutter</code></a>,
+<a href='#Darkness'><code>Darkness</code></a>,
+<a href='#Finishing'><code>Finishing</code></a>,
+<a href='#Group'><code>Group</code></a>,
+<a href='#InputSlot'><code>InputSlot</code></a>,
+<a href='#Installable'><code>Installable</code></a>,
+<a href='#MediaType'><code>MediaType</code></a>,
+<a href='#Option'><code>Option</code></a>,
+<a href='#Resolution'><code>Resolution</code></a>,
+<a href='#UIConstraints'><code>UIConstraints</code></a></p>
+
+
+<h2 class="title"><a name='FileName'>FileName</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+FileName <i>"filename"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+FileName "Acme Laser Printer 2000"
+FileName "Acme Ink Waster 1000"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>FileName</code> attribute specifies the "long" name of the
+PPD file for the current driver.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#Manufacturer'><code>Manufacturer</code></a>,
+<a href='#ModelName'><code>ModelName</code></a>,
+<a href="#PCFileName"><code>PCFileName</code></a>,
+<a href='#Version'><code>Version</code></a></p>
+
+
+<h2 class="title"><a name='Filter'>Filter</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Filter <i>mime-type cost program</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Filter application/vnd.cups-raster 50 rastertofoo
+Filter application/vnd.hp-HPGL 25 /usr/foo/filter/hpgltofoo
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Filter</code> directive adds a filter for the current
+driver. The mime-type argument is a valid MIME media type name
+as defined in a CUPS <var>mime.types</var> file.</p>
+
+<p>The cost argument specifies the relative cost of the filter.
+In general, use a number representing the average percentage of
+CPU time that is used when printing the specified MIME media
+type.</p>
+
+<p>The program argument specifies the program to run; if the
+program is not an absolute filename, then CUPS will look for the
+program in the CUPS filter directory.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#DriverType'><code>DriverType</code></a></p>
+
+
+<h2 class="title"><span class="info">Deprecated</span><a name='Finishing'>Finishing</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Finishing <i>name</i>
+Finishing <i>"name/text"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Finishing None
+Finishing "Glossy/Photo Overcoat"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Finishing</code> directive adds a choice to the
+<code>cupsFinishing</code> option. The name may contain up to 40 ASCII
+characters within the range of decimal 33 to decimal 126 inclusive,
+except for the characters comma (44), slash (47) and colon (58).</p>
+
+<p>If provided, the text can be any string up to 80 bytes in length.
+If no text is provided, the name is used.</p>
+
+<p>The name is stored in the <code>OutputType</code> attribute in the
+PostScript page device dictionary.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#Choice'><code>Choice</code></a>,
+<a href='#ColorModel'><code>ColorModel</code></a>,
+<a href='#Cutter'><code>Cutter</code></a>,
+<a href='#Darkness'><code>Darkness</code></a>,
+<a href='#Duplex'><code>Duplex</code></a>,
+<a href='#Group'><code>Group</code></a>,
+<a href='#InputSlot'><code>InputSlot</code></a>,
+<a href='#Installable'><code>Installable</code></a>,
+<a href='#MediaType'><code>MediaType</code></a>,
+<a href='#Option'><code>Option</code></a>,
+<a href='#Resolution'><code>Resolution</code></a>,
+<a href='#UIConstraints'><code>UIConstraints</code></a></p>
+
+
+<h2 class="title"><a name='Font'>Font</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Font <i>name encoding "version" charset status</i>
+Font *
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Font *
+Font Courier Standard "(1.05)" Standard ROM
+Font Symbol Special "(001.005)" Special ROM
+Font Barcode-Foo Special "(1.0)" Special Disk
+Font Unicode-Foo Expert "(2.0)" Adobe-Identity ROM
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Font</code> directive defines a "device font" for the
+current printer driver. The name is the PostScript font name.</p>
+
+<p>The encoding is the default encoding of the font, usually
+<code>Standard</code>, <code>Expert</code>, or <code>Special</code>, as
+defined in the Adobe PPD file specification.</p>
+
+<p>The version is the PostScript string definition that
+corresponds to the font version number.</p>
+
+<p>The charset defines the available characters in the font,
+usually <code>Standard</code> or <code>Special</code>, as defined in the
+Adobe PPD file specification.</p>
+
+<p>The status is the installation status of the font and must be
+either the word <code>ROM</code> or <code>Disk</code>.</p>
+
+<p>Device fonts differ from fonts defined using the <a
+href='#_font'><code>#font</code></a> directive in that they are
+automatically associated with the current driver. Fonts defined
+using <code>#font</code> may be imported into the current driver
+using the <code>Font *</code> form of this directive.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#_font'><code>#font</code></a></p>
+
+
+<h2 class="title"><a name='Group'>Group</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Group <i>name</i>
+Group <i>"name/text"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Group General
+Group "InstallableOptions/Options Installed"
+Group "Special/Vendor Options"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Group</code> directive specifies the group for new
+<code>Option</code> directives. The name may contain up to 40 ASCII
+characters within the range of decimal 33 to decimal 126 inclusive,
+except for the characters comma (44), slash (47) and colon (58).</p>
+
+<p>If provided, the text can be any string up to 40 bytes in length.
+If no text is provided, the name is used.</p>
+
+<p>The names <code>General</code> and <code>InstallableOptions</code>
+are predefined for the standard Adobe UI keywords and for installable
+options, respectively.</p>
+
+<center><table width='80%' border='1' bgcolor='#cccccc' cellpadding='5' cellspacing='0'>
+<tr>
+ <td align='justify'><b>Note:</b>
+
+ <p>Because of certain API binary compatibility issues,
+ CUPS limits the length of PPD group translation strings
+ (text) to 40 bytes, while the PPD specification
+ allows for up to 80 bytes.</p>
+
+ </td>
+</tr>
+</table></center>
+
+<h3>See Also</h3>
+
+<p><a href='#Choice'><code>Choice</code></a>,
+<a href='#ColorModel'><code>ColorModel</code></a>,
+<a href='#Cutter'><code>Cutter</code></a>,
+<a href='#Darkness'><code>Darkness</code></a>,
+<a href='#Duplex'><code>Duplex</code></a>,
+<a href='#Finishing'><code>Finishing</code></a>,
+<a href='#InputSlot'><code>InputSlot</code></a>,
+<a href='#Installable'><code>Installable</code></a>,
+<a href='#MediaType'><code>MediaType</code></a>,
+<a href='#Option'><code>Option</code></a>,
+<a href='#Resolution'><code>Resolution</code></a>,
+<a href='#UIConstraints'><code>UIConstraints</code></a></p>
+
+
+<h2 class="title"><a name='HWMargins'>HWMargins</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+HWMargins <i>left bottom right top</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+HWMargins 18 36 18 36
+HWMargins 0.25in 0.5in 0.25in 0.5in
+HWMargins 0.6cm 1.2cm 0.6cm 1.2cm
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>HWMargins</code> directive specifies the current
+margins for <a href='#MediaSize'><code>MediaSize</code></a> that
+follow. The left, bottom, right, and top margin values specify
+the printable margins.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#MediaSize'><code>MediaSize</code></a></p>
+
+
+<h2 class="title"><a name='InputSlot'>InputSlot</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+InputSlot <i>position name</i>
+InputSlot <i>position "name/text"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+InputSlot 0 Auto
+InputSlot 1 "Upper/Tray 1"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>InputSlot</code> directive adds a new choice to the
+<code>InputSlot</code> option. The position argument is a number
+from 0 to 2<sup>32</sup>-1 specifying the value that is placed
+in the <code>MediaPosition</code> attribute in the PostScript page
+device dictionary.</p>
+
+<p>The name may contain up to 40 ASCII characters within the range of
+decimal 33 to decimal 126 inclusive, except for the characters comma
+(44), slash (47) and colon (58).</p>
+
+<p>If provided, the text can be any string up to 80 bytes in length.
+If no text is provided, the name is used.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#Choice'><code>Choice</code></a>,
+<a href='#ColorModel'><code>ColorModel</code></a>,
+<a href='#Cutter'><code>Cutter</code></a>,
+<a href='#Darkness'><code>Darkness</code></a>,
+<a href='#Duplex'><code>Duplex</code></a>,
+<a href='#Finishing'><code>Finishing</code></a>,
+<a href='#Group'><code>Group</code></a>,
+<a href='#Installable'><code>Installable</code></a>,
+<a href='#MediaType'><code>MediaType</code></a>,
+<a href='#Option'><code>Option</code></a>,
+<a href='#Resolution'><code>Resolution</code></a>,
+<a href='#UIConstraints'><code>UIConstraints</code></a></p>
+
+
+<h2 class="title"><a name='Installable'>Installable</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Installable <i>name</i>
+Installable <i>"name/text"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Installable EnvTray
+Installable "Option1/Duplexer Installed"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Installable</code> directive adds a new boolean option
+to the <code>InstallableOptions</code> group with a default value of
+<code>False</code>. The name may contain up to 40 ASCII characters
+within the range of decimal 33 to decimal 126 inclusive, except for
+the characters comma (44), slash (47) and colon (58).</p>
+
+<p>If provided, the text can be any string up to 80 bytes in length.
+If no text is provided, the name is used.</p>
+
+
+<h2 class="title"><a name='LocAttribute'>LocAttribute</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+LocAttribute <i>name "keyword/text" value</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+LocAttribute fooProfile "Photo/Photographic Profile" "photopro.icc"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>LocAttribute</code> directive creates a localized PPD
+attribute. The name may contain up to 40 ASCII characters within the
+range of decimal 33 to decimal 126 inclusive, except for the characters
+comma (44), slash (47) and colon (58).</p>
+
+<p>The selector can be the empty string (<code>""</code>) or text of up
+to 80 bytes.</p>
+
+<p>The value is any string or number; the string may contain multiple
+lines, however no one line may exceed 255 bytes.</p>
+
+<h3>See Also</h3>
+
+<p><a href="#Attribute"><code>Attribute</code></a></p>
+
+
+<h2 class="title"><a name='ManualCopies'>ManualCopies</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+ManualCopies <i>boolean-value</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+ManualCopies no
+ManualCopies yes
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>ManualCopies</code> directive specifies whether copies
+need to be produced by the RIP filters. The default is
+<code>no</code>.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#Choice'><code>Choice</code></a>,
+<a href='#ColorModel'><code>ColorModel</code></a>,
+<a href='#Cutter'><code>Cutter</code></a>,
+<a href='#Darkness'><code>Darkness</code></a>,
+<a href='#Duplex'><code>Duplex</code></a>,
+<a href='#Finishing'><code>Finishing</code></a>,
+<a href='#Group'><code>Group</code></a>,
+<a href='#InputSlot'><code>InputSlot</code></a>,
+<a href='#MediaType'><code>MediaType</code></a>,
+<a href='#Option'><code>Option</code></a>,
+<a href='#Resolution'><code>Resolution</code></a>,
+<a href='#UIConstraints'><code>UIConstraints</code></a></p>
+
+
+<h2 class="title"><a name='Manufacturer'>Manufacturer</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Manufacturer <i>"name"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Manufacturer "Foo"
+Manufacturer "HP"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Manufacturer</code> directive specifies the
+manufacturer name for the current driver. The name argument must
+conform to the manufacturer name requirements in the Adobe PPD
+file specification.</p>
+
+<h3>See Also</h3>
+
+<p><a href="#FileName"><code>FileName</code></a>,
+<a href='#ModelName'><code>ModelName</code></a>,
+<a href='#PCFileName'><code>PCFileName</code></a>,
+<a href='#Version'><code>Version</code></a></p>
+
+
+<h2 class="title"><a name='MaxSize'>MaxSize</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+MaxSize <i>width length</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+MaxSize 36in 100ft
+MaxSize 300cm 30m
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>MaxSize</code> directive specifies the maximum width
+and length that is supported for custom page sizes.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#MinSize'><code>MinSize</code></a>,
+<a href='#VariablePaperSize'><code>VariablePaperSize</code></a></p>
+
+
+<h2 class="title"><a name='MediaSize'>MediaSize</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+MediaSize <i>name</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+MediaSize Letter
+MediaSize A4
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>MediaSize</code> directive adds the named size to the
+current printer driver using the current margins defined with
+the <a href="#HWMargins"><code>HWMargins</code></a> directive. The
+name argument must match a media size defined using the <a
+href="#_media"><code>#media</code></a> directive.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#_media'><code>#media</code></a>,
+<a href='#HWMargins'><code>HWMargins</code></a></p>
+
+
+<h2 class="title"><a name='MediaType'>MediaType</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+MediaType <i>type name</i>
+MediaType <i>type "name/text"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+MediaType 0 Auto
+MediaType 1 "Plain/Plain Paper"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>MediaType</code> directive adds a new choice to the
+<code>MediaType</code> option. The type argument is a number
+from 0 to 2<sup>32</sup>-1 specifying the value that is placed
+in the <code>cupsMediaType</code> attribute in the PostScript page
+device dictionary.</p>
+
+<p>The name may contain up to 40 ASCII characters within the range of
+decimal 33 to decimal 126 inclusive, except for the characters comma
+(44), slash (47) and colon (58).</p>
+
+<p>If provided, the text can be any string up to 80 bytes in length.
+If no text is provided, the name is used.</p>
+
+<p>The name is placed in the <code>MediaType</code> attribute in the
+PostScript page device dictionary.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#Choice'><code>Choice</code></a>,
+<a href='#ColorModel'><code>ColorModel</code></a>,
+<a href='#Cutter'><code>Cutter</code></a>,
+<a href='#Darkness'><code>Darkness</code></a>,
+<a href='#Duplex'><code>Duplex</code></a>,
+<a href='#Finishing'><code>Finishing</code></a>,
+<a href='#Group'><code>Group</code></a>,
+<a href='#InputSlot'><code>InputSlot</code></a>,
+<a href='#Installable'><code>Installable</code></a>,
+<a href='#Option'><code>Option</code></a>,
+<a href='#Resolution'><code>Resolution</code></a>,
+<a href='#UIConstraints'><code>UIConstraints</code></a></p>
+
+
+<h2 class="title"><a name='MinSize'>MinSize</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+MinSize <i>width length</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+MinSize 4in 8in
+MinSize 10cm 20cm
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>MinSize</code> directive specifies the minimum width
+and length that is supported for custom page sizes.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#MaxSize'><code>MaxSize</code></a>,
+<a href='#VariablePaperSize'><code>VariablePaperSize</code></a></p>
+
+
+<h2 class="title"><a name='ModelName'>ModelName</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+ModelName <i>"name"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+ModelName "Foo Laser Printer 2000"
+ModelName "Colorific 123"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>ModelName</code> directive sets the printer name for
+the <code>ModelName</code>, <code>NickName</code>, and
+<code>ShortNickName</code> attributes for the printer driver. The
+name is any string of letters, numbers, spaces, and the
+characters ".", "/", "-", and "+" and should not begin with the
+manufacturer name since the PPD compiler will add this
+automatically for you. The maximum length of the name string is
+31 bytes to conform to the Adobe limits on the length of
+<code>ShortNickName</code>.</p>
+
+<h3>See Also</h3>
+
+<p><a href="#FileName"><code>FileName</code></a>,
+<a href='#Manufacturer'><code>Manufacturer</code></a>,
+<a href='#PCFileName'><code>PCFileName</code></a>,
+<a href='#Version'><code>Version</code></a></p>
+
+
+<h2 class="title"><a name='ModelNumber'>ModelNumber</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+ModelNumber <i>expression</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+ModelNumber 123
+ModelNumber ($PCL_PAPER_SIZE $PCL_PJL)
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>ModelNumber</code> directive sets the
+<code>cupsModelNumber</code> attribute for the printer driver, which
+is often used by the printer driver filter to tailor its output
+for the current device. The number is any integer or bitwise OR
+of integers and constants that is appropriate for the printer
+driver filters.<p>
+
+<p>A complete list of printer driver model number constants is
+available later in this appendix in the section titled, "<a
+href='#REF_MODEL_NUMBER'>Printer Driver ModelNumber
+Constants</a>".</p>
+
+<h3>See Also</h3>
+
+<p><a href='#DriverType'><code>DriverType</code></a>,
+<a href='#Filter'><code>Filter</code></a></p>
+
+
+<h2 class="title"><a name='Option'>Option</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Option <i>name type section order</i>
+Option <i>"name/text" type section order</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Option Punch Boolean AnySetup 10
+Option "fooFinish/Finishing Option" PickOne DocumentSetup 10
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Option</code> directive creates a new option in the
+current group, by default the <code>General</code> group. The name
+may contain up to 40 ASCII characters within the range of decimal 33
+to decimal 126 inclusive, except for the characters comma (44), slash
+(47) and colon (58).</p>
+
+<p>If provided, the text can be any string up to 80 bytes in length.
+If no text is provided, the name is used.</p>
+
+<p>The type argument is one of the following keywords:</p>
+
+<ul>
+
+ <li><code>Boolean</code> - a true/false option</li>
+
+ <li><code>PickOne</code> - allows the user to pick one
+ choice from a list</li>
+
+ <li><code>PickMany</code> - allows the user to pick zero or
+ more choices from a list</li>
+
+</ul>
+
+<p>The section argument is one of the following keywords:</p>
+
+<ul>
+
+ <li><code>AnySetup</code> - The option can be placed in
+ either the DocumentSetup or PageSetup sections of the
+ PostScript document</li>
+
+ <li><code>DocumentSetup</code> - The option must be placed
+ in the DocumentSetup section of the PostScript document;
+ this does not allow the option to be overridden on
+ individual pages</li>
+
+ <li><code>ExitServer</code> - The option must be placed in a
+ separate initialization job prior to the document (not
+ used for raster printer drivers)</li>
+
+ <li><code>JCLSetup</code> - The option contains job control
+ language commands and must be sent prior to the document
+ using the <code>JCLBegin</code> and
+ <code>JCLToPSInterpreter</code> attributes (not used for
+ raster printer drivers)</li>
+
+ <li><code>PageSetup</code> - The option must be placed at the
+ beginning of each page in the PostScript document</li>
+
+ <li><code>Prolog</code> - The option must be placed in the
+ prolog section of the PostScript document; this is
+ typically used to add special comments for high-end
+ typesetters, but can also be used to add CUPS PostScript
+ job ticket comments.</li>
+
+</ul>
+
+<p>The order argument is a real number greater than or equal to
+0.0 and is used to sort the printer commands from many options
+before sending them to the printer or RIP filter.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#Choice'><code>Choice</code></a>,
+<a href='#ColorModel'><code>ColorModel</code></a>,
+<a href='#Cutter'><code>Cutter</code></a>,
+<a href='#Darkness'><code>Darkness</code></a>,
+<a href='#Duplex'><code>Duplex</code></a>,
+<a href='#Finishing'><code>Finishing</code></a>,
+<a href='#Group'><code>Group</code></a>,
+<a href='#InputSlot'><code>InputSlot</code></a>,
+<a href='#Installable'><code>Installable</code></a>,
+<a href='#MediaType'><code>MediaType</code></a>,
+<a href='#Resolution'><code>Resolution</code></a>,
+<a href='#UIConstraints'><code>UIConstraints</code></a></p>
+
+
+<h2 class="title"><a name='PCFileName'>PCFileName</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+PCFileName <i>"filename.ppd"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+PCFileName "foljt2k1.ppd"
+PCFileName "deskjet.ppd"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>PCFileName</code> attribute specifies the name of the
+PPD file for the current driver. The filename argument must
+conform to the Adobe PPD file specification and can be no more
+than 8 filename characters plus the extension ".ppd".</p>
+
+<h3>See Also</h3>
+
+<p><a href="#FileName"><code>FileName</code></a>,
+<a href='#Manufacturer'><code>Manufacturer</code></a>,
+<a href='#ModelName'><code>ModelName</code></a>,
+<a href='#Version'><code>Version</code></a></p>
+
+
+<h2 class="title"><span class="info">Deprecated</span><a name='Resolution'>Resolution</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Resolution <i>colorspace bits-per-color row-count row-feed row-step name</i>
+Resolution <i>colorspace bits-per-color row-count row-feed row-step "name/text"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Resolution - 8 0 0 0 300dpi
+Resolution k 8 0 0 0 "600x300dpi/600 DPI Grayscale"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Resolution</code> directive creates a new
+<code>Resolution</code> option choice which sets the
+<code>HWResolution</code>, <code>cupsBitsPerColor</code>,
+<code>cupsRowCount</code>, <code>cupsRowFeed</code>,
+<code>cupsRowStep</code>, and optionally the <code>cupsColorSpace</code>
+page device dictionary attributes. The colorspace argument
+specifies a colorspace to use for the specified resolution and
+can be the hyphen (<code>-</code>) character to make no change to
+the selected color model or any keyword listed in the section
+titled, "<a href='#REF_COLOR_SPACE'>Colorspace Keywords</a>", to
+force the named colorspace.</p>
+
+<p>The bits-per-color argument specifies the number of bits per
+color to generate when RIP'ing a job. The values 1, 2, 4, and 8
+are currently supported by CUPS.</p>
+
+<p>The row-count, row-feed, and row-step argument specify the
+driver-dependent values for the <code>cupsRowCount</code>,
+<code>cupsRowFeed</code>, and <code>cupsRowStep</code> attributes,
+respectively. Most drivers leave these attributes set to 0, but
+any number from 0 to 2<sup>32</sup>-1 is allowed.</p>
+
+<p>The name argument must conform to the resolution naming
+conventions in the Adobe PPD file specification, either
+<code>HHHdpi</code> for symmetric resolutions or <code>HHHxVVVdpi</code>
+for asymmetric resolutions. The <code>HHH</code> and <code>VVV</code> in
+the examples represent the horizontal and vertical resolutions
+which must be positive integer values.</p>
+
+<p>If provided, the text can be any string up to 80 bytes in length.
+If no text is provided, the name is used.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#Choice'><code>Choice</code></a>,
+<a href='#ColorModel'><code>ColorModel</code></a>,
+<a href='#Cutter'><code>Cutter</code></a>,
+<a href='#Darkness'><code>Darkness</code></a>,
+<a href='#Duplex'><code>Duplex</code></a>,
+<a href='#Finishing'><code>Finishing</code></a>,
+<a href='#Group'><code>Group</code></a>,
+<a href='#InputSlot'><code>InputSlot</code></a>,
+<a href='#Installable'><code>Installable</code></a>,
+<a href='#MediaType'><code>MediaType</code></a>,
+<a href='#Option'><code>Option</code></a>,
+<a href='#UIConstraints'><code>UIConstraints</code></a></p>
+
+
+<h2 class="title"><span class="info">Deprecated</span><a name='SimpleColorProfile'>SimpleColorProfile</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+SimpleColorProfile <i>resolution/mediatype density
+ yellow-density red-density gamma
+ red-adjust green-adjust blue-adjust</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+SimpleColorProfile -/- 100 100 200 1.0 0 0 0
+
+SimpleColorProfile 360dpi/- 100 95 150 1.2 5 10 15
+
+SimpleColorProfile 720dpi/Glossy 100 90 120 1.5 -5 5 10
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>SimpleColorProfile</code> directive creates a
+matrix-based <a href="#ColorProfile"><code>ColorProfile</code></a>.
+The resolution and mediatype arguments specify the
+<code>Resolution</code> and <code>MediaType</code> choices which use the
+profile; the hyphen (<code>-</code>) is used to specify that any
+resolution or mediatype can be used with the profile.</p>
+
+<p>The density argument specifies the linear density correction
+to apply to the color values (P = d * 0.01 * p<sup>g</sup>) and
+is an integer greater than 0 and less than or equal to 100. A
+value 100 of disables density correction while lower values
+produce proportionately lighter output. The density value
+adjusts all color channels equally in all color modes.</p>
+
+<p>The yellow-density argument specifies the density of the
+yellow channel when printing in grayscale or RGB mode and is an
+integer greater than 0 and less then or equal to 100. A value of
+100 disables yellow density correction while lower values
+produce proportionately lighter output.</p>
+
+<P>The red-density argument specifies the two-color density
+limit (e.g. C + M, C + Y, M + Y) when printing in grayscale or
+RGB mode and is an integer greater than 0 and less then or equal
+to 200. A value of 200 disables two-color density correction
+while lower values produce proportionately lighter output.</p>
+
+<p>The gamma argument specifies the gamma correction to apply to
+the color values (P = p<sup>g</sup>) and is a real number
+greater than 0. Values larger than 1 cause a general lightening
+of the print while values smaller than 1 cause a general
+darkening of the print. A value of 1 disables gamma
+correction.</p>
+
+<p>The red-adjust, green-adjust, blue-adjust arguments specify
+the percentage of color to add or remove. Positive red-adjust
+values add magenta and negative values add yellow. Positive
+green-adjust values add cyan and negative values add yellow.
+Positive blue-adjust values add cyan and negative values add
+magenta. Values of 0 disable color adjustments.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#ColorProfile'><code>ColorProfile</code></a></p>
+
+
+<h2 class="title"><a name='Throughput'>Throughput</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Throughput <i>pages-per-minute</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Throughput 1
+Throughput 10
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Throughput</code> directive sets the <code>Throughput</code>
+attribute for the current printer driver. The pages-per-minute
+argument is a positive integer representing the peak number of
+pages per minute that the printer is capable of producing. Use a
+value of 1 for printers that produce less than 1 page per
+minute.</p>
+
+
+<h2 class="title"><a name='UIConstraints'>UIConstraints</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+UIConstraints <i>"*Option1 *Option2"</i>
+UIConstraints <i>"*Option1 Choice1 *Option2"</i>
+UIConstraints <i>"*Option1 *Option2 Choice2"</i>
+UIConstraints <i>"*Option1 Choice1 *Option2 Choice2"</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+UIConstraints "*Finishing *MediaType"
+UIConstraints "*Option1 False *Duplex"
+UIConstraints "*Duplex *MediaType Transparency"
+UIConstraints "*Resolution 600dpi *ColorModel RGB"
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>UIConstraints</code> directive adds a constraint
+between two options. Constraints inform the application when a
+user has chosen incompatible options. Each option name is
+preceded by the asterisk (<code>*</code>). If no choice is given for
+an option, then all choices <i>except</i> <code>False</code> and
+<code>None</code> will conflict with the other option and choice(s).
+Since the PPD compiler automatically adds reciprocal constraints
+(option A conflicts with option B, so therefore option B
+conflicts with option A), you need only specify the constraint
+once.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#Choice'><code>Choice</code></a>,
+<a href='#ColorModel'><code>ColorModel</code></a>,
+<a href='#Cutter'><code>Cutter</code></a>,
+<a href='#Darkness'><code>Darkness</code></a>,
+<a href='#Duplex'><code>Duplex</code></a>,
+<a href='#Finishing'><code>Finishing</code></a>,
+<a href='#Group'><code>Group</code></a>,
+<a href='#InputSlot'><code>InputSlot</code></a>,
+<a href='#Installable'><code>Installable</code></a>,
+<a href='#MediaType'><code>MediaType</code></a>,
+<a href='#Option'><code>Option</code></a>,
+<a href='#Resolution'><code>Resolution</code></a></p>
+
+
+<h2 class="title"><a name='VariablePaperSize'>VariablePaperSize</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+VariablePaperSize <i>boolean-value</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+VariablePaperSize yes
+VariablePaperSize no
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>VariablePaperSize</code> directive specifies whether
+the current printer supports variable (custom) page sizes. When
+<code>yes</code> is specified, the PPD compiler will include the
+standard PPD attributes required to support custom page
+sizes.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#MaxSize'><code>MaxSize</code></a>,
+<a href='#MinSize'><code>MinSize</code></a></p>
+
+
+<h2 class="title"><a name='Version'>Version</a></h2>
+
+<h3>Syntax</h3>
+
+<pre>
+Version <i>number</i>
+</pre>
+
+<h3>Examples</h3>
+
+<pre>
+Version 1.0
+Version 3.7
+</pre>
+
+<h3>Description</h3>
+
+<p>The <code>Version</code> directive sets the <code>FileVersion</code>
+attribute in the PPD file and is also used for the
+<code>NickName</code> attribute. The number argument is a positive
+real number.</p>
+
+<h3>See Also</h3>
+
+<p><a href='#Manufacturer'><code>Manufacturer</code></a>,
+<a href='#ModelName'><code>ModelName</code></a>,
+<a href='#PCFileName'><code>PCFileName</code></a></p>
+
+
+<h2 class="title"><a name='REF_INCLUDE'>Standard Include Files</h2>
+
+<p><a href='#TABLEB-1'>Table B-1</a> shows the standard include
+files which are provided with the DDK.</p>
+
+<center><table border='1' cellpadding='5' cellspacing='0' width='80%'>
+<caption align='bottom'><a name='TABLEB-1'><i>Table B-1,
+Standard Include Files</i></a></caption>
+<tr bgcolor='#cccccc'>
+ <th>Include File</th>
+ <th>Description</th>
+</tr>
+<tr>
+ <td valign='top'><code>&lt;font.defs&gt;</code></td>
+ <td align='justify' valign='top'>Defines all of the
+ standard fonts which are included with ESP Ghostscript
+ and the Apple PDF RIP.</td>
+</tr>
+<tr>
+ <td valign='top'><code>&lt;epson.h&gt;</code></td>
+ <td align='justify' valign='top'>Defines all of the
+ CUPS ESC/P sample driver constants.</td>
+</tr>
+<tr>
+ <td valign='top'><code>&lt;escp.h&gt;</code></td>
+ <td align='justify' valign='top'>Defines all of the
+ DDK ESC/P driver constants.</td>
+</tr>
+<tr>
+ <td valign='top'><code>&lt;hp.h&gt;</code></td>
+ <td align='justify' valign='top'>Defines all of the
+ CUPS HP-PCL sample driver constants.</td>
+</tr>
+<tr>
+ <td valign='top'><code>&lt;label.h&gt;</code></td>
+ <td align='justify' valign='top'>Defines all of the
+ CUPS label sample driver constants.</td>
+</tr>
+<tr>
+ <td valign='top'><code>&lt;media.defs&gt;</code></td>
+ <td align='justify' valign='top'>Defines all of the
+ standard media sizes listed in Appendix B of the Adobe
+ PostScript Printer Description File Format
+ Specification.</td>
+</tr>
+<tr>
+ <td valign='top'><code>&lt;pcl.h&gt;</code></td>
+ <td align='justify' valign='top'>Defines all of the
+ DDK HP-PCL driver constants.</td>
+</tr>
+<tr>
+ <td valign='top'><code>&lt;raster.defs&gt;</code></td>
+ <td align='justify' valign='top'>Defines all of the CUPS
+ raster format constants.</td>
+</tr>
+</table></center>
+
+<h2 class="title"><a name='REF_MODEL_NUMBER'>Printer Driver ModelNumber Constants</a></h2>
+
+<p>The CUPS DDK and sample drivers use the
+<code>cupsModelNumber</code> attribute in the PPD file to tailor
+their output to the printer. The following sections describe the
+constants for each driver.</p>
+
+<h3><a name='REF_MODEL_EPSON'>The CUPS ESC/P Sample Driver (epson)</a></h3>
+
+<p>The <code>epson</code> driver supports Epson and Okidata
+dot-matrix, Epson Stylus Color, and Epson Stylus Photo printers.
+<a href='#TABLEB-2'>Table B-2</a> lists the constants for the <a
+href='#ModelNumber'><code>ModelNumber</code></a> directive.
+<code>ModelNumber</code> values should be inserted by referencing
+only one of these constants.</p>
+
+<!-- NEED 20 -->
+<center><table border='1' cellpadding='5' cellspacing='0' width='80%'>
+<caption align='bottom'><a name='TABLEB-2'><i>Table B-2, <code>epson</code> driver
+constants</i></a></caption>
+<tr bgcolor='#cccccc'>
+ <th>Constant</th>
+ <th>Description</th>
+</tr>
+<tr>
+ <td valign='top'><code>EPSON_9PIN</code></td>
+ <td align='justify' valign='top'>Epson and Okidata 9-pin
+ dot-matrix printers</td>
+</tr>
+<tr>
+ <td valign='top'><code>EPSON_24PIN</code></td>
+ <td align='justify' valign='top'>Epson and Okidata 24-pin
+ dot-matrix printers</td>
+</tr>
+<tr>
+ <td valign='top'><code>EPSON_COLOR</code></td>
+ <td align='justify' valign='top'>Older Epson Stylus Color
+ printers that use the <code>ESC .</code> graphics command</td>
+</tr>
+<tr>
+ <td valign='top'><code>EPSON_PHOTO</code></td>
+ <td align='justify' valign='top'>Older Epson Stylus Photo
+ printers that use the <code>ESC .</code> graphics command</td>
+</tr>
+<tr>
+ <td valign='top'><code>EPSON_ICOLOR</code></td>
+ <td align='justify' valign='top'>Newer Epson Stylus Color
+ printers that use the <code>ESC i</code> graphics command</td>
+</tr>
+<tr>
+ <td valign='top'><code>EPSON_IPHOTO</code></td>
+ <td align='justify' valign='top'>Newer Epson Stylus Photo
+ printers that use the <code>ESC i</code> graphics command</td>
+</tr>
+</table></center>
+
+<h3><a name='REF_MODEL_HP'>The CUPS HP-PCL Sample Driver (hp)</a></h3>
+
+<p>The <code>hp</code> driver supports HP LaserJet and DeskJet
+printers. <a href='#TABLEB-3'>Table B-3</a> lists the constants
+for the <a href='#ModelNumber'><code>ModelNumber</code></a>
+directive. <code>ModelNumber</code> values should be inserted by
+referencing only one of these constants.</p>
+
+<center><table border='1' cellpadding='5' cellspacing='0' width='80%'>
+<caption align='bottom'><a name='TABLEB-3'><i>Table B-3, <code>hp</code> driver
+constants</i></a></caption>
+<tr bgcolor='#cccccc'>
+ <th>Constant</th>
+ <th>Description</th>
+</tr>
+<tr>
+ <td valign='top'><code>HP_LASERJET</code></td>
+ <td align='justify' valign='top'>HP LaserJet printers supporting
+ PCL 3, 4, or 5</td>
+</tr>
+<tr>
+ <td valign='top'><code>HP_DESKJET</code></td>
+ <td align='justify' valign='top'>HP DeskJet printers
+ supporting PCL 3 and using the simple color graphics
+ command (<code>ESC * r # U</code>)</td>
+</tr>
+<tr>
+ <td valign='top'><code>HP_DESKJET2</code></td>
+ <td align='justify' valign='top'>HP DeskJet printers
+ supporting PCL3GUI and using the configure raster graphics
+ command (<code>ESC * g # W</code>)</td>
+</tr>
+</table></center>
+
+<h3><a name='REF_MODEL_LABEL'>The CUPS Label Sample Driver (label)</a></h3>
+
+<p>The <code>label</code> driver supports the Dymo Labelwriter, Zebra CPCL, Zebra EPL, and Zebra ZPL, and Intellitech PCL label printers. <a href='#TABLEB-4'>Table B-4</a>
+lists the constants for the <a
+href='#ModelNumber'><code>ModelNumber</code></a> directive.
+<code>ModelNumber</code> values should be inserted by referencing
+only one of these constants.</p>
+
+<center><table border='1' cellpadding='5' cellspacing='0' width='80%'>
+<caption align='bottom'><a name='TABLEB-4'><i>Table B-4, <code>label</code> driver
+constants</i></a></caption>
+<tr bgcolor='#cccccc'>
+ <th>Constant</th>
+ <th>Description</th>
+</tr>
+<tr>
+ <td valign='top'><code>DYMO_3x0</code></td>
+ <td align='justify' valign='top'>Format output for the
+ Dymo Labelwriter 300, 330, or 330 Turbo.</td>
+</tr>
+<tr>
+ <td valign='top'><code>INTELLITECH_PCL</code></td>
+ <td align='justify' valign='top'>Format output for the Intellitech PCL printers.</td>
+</tr>
+<tr>
+ <td valign='top'><code>ZEBRA_CPCL</code></td>
+ <td align='justify' valign='top'>Format output for the Zebra CPCL printers.</td>
+</tr>
+<tr>
+ <td valign='top'><code>ZEBRA_EPL_LINE</code></td>
+ <td align='justify' valign='top'>Format output for the Zebra EPL line mode (EPL 1) printers.</td>
+</tr>
+<tr>
+ <td valign='top'><code>ZEBRA_EPL_PAGE</code></td>
+ <td align='justify' valign='top'>Format output for the Zebra EPL page mode (EPL 2) printers.</td>
+</tr>
+<tr>
+ <td valign='top'><code>ZEBRA_ZPL</code></td>
+ <td align='justify' valign='top'>Format output for the Zebra ZPL printers.</td>
+</tr>
+</table></center>
+
+<h3><a name='REF_MODEL_ESCP'>The DDK ESC/P Driver (escp)</a></h3>
+
+<p>The <code>escp</code> driver supports all Epson inkjet printers.
+<a href='#TABLEB-6'>Table B-6</a> lists the constants for the <a
+href='#ModelNumber'><code>ModelNumber</code></a> directive.
+<code>ModelNumber</code> values should be specified as the bitwise
+OR of one or more of these constants.</p>
+
+<center><table border='1' cellpadding='5' cellspacing='0' width='80%'>
+<caption align='bottom'><a name='TABLEB-6'><i>Table B-6, <code>escp</code> driver
+constants</i></a></caption>
+<tr bgcolor='#cccccc'>
+ <th>Constant</th>
+ <th>Description</th>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_MICROWEAVE</code></td>
+ <td align='justify' valign='top'>Use microweave command?</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_STAGGER</code></td>
+ <td align='justify' valign='top'>Are color jets staggered?</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_ESCK</code></td>
+ <td align='justify' valign='top'>Use print mode command?</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_EXT_UNITS</code></td>
+ <td align='justify' valign='top'>Use extended unit commands?</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_EXT_MARGINS</code></td>
+ <td align='justify' valign='top'>Use extended margin command?</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_USB</code></td>
+ <td align='justify' valign='top'>Send USB packet mode escape</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_PAGE_SIZE</code></td>
+ <td align='justify' valign='top'>Use page size command</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_RASTER_ESCI</code></td>
+ <td align='justify' valign='top'>Use <code>ESC i</code> graphics command</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_REMOTE</code></td>
+ <td align='justify' valign='top'>Use remote mode commands</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_REMOTE_AC</code></td>
+ <td align='justify' valign='top'>Use auto-cutter command</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_REMOTE_CO</code></td>
+ <td align='justify' valign='top'>Use cutter-operation command</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_REMOTE_EX</code></td>
+ <td align='justify' valign='top'>Use media-position command</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_REMOTE_MS</code></td>
+ <td align='justify' valign='top'>Use media-size command</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_REMOTE_MT</code></td>
+ <td align='justify' valign='top'>Use media-type command</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_REMOTE_PC</code></td>
+ <td align='justify' valign='top'>Use paper-check command</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_REMOTE_PH</code></td>
+ <td align='justify' valign='top'>Use paper-thickness command</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_REMOTE_PP</code></td>
+ <td align='justify' valign='top'>Use paper-path command</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_REMOTE_SN0</code></td>
+ <td align='justify' valign='top'>Use feed-sequence-0 command</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_REMOTE_SN1</code></td>
+ <td align='justify' valign='top'>Use platten-gap command</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_REMOTE_SN2</code></td>
+ <td align='justify' valign='top'>Use feed-sequence-2 command</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_REMOTE_SN6</code></td>
+ <td align='justify' valign='top'>Use eject-delay command</td>
+</tr>
+<tr>
+ <td valign='top'><code>ESCP_REMOTE_FP</code></td>
+ <td align='justify' valign='top'>Use print-position command</td>
+</tr>
+</table></center>
+
+<h3><a name='REF_MODEL_PCL'>The DDK HP-PCL Driver (pcl)</a></h3>
+
+<p>The <code>pcl</code> driver supports all HP LaserJet, DeskJet,
+and DesignJet printers. <a href='#TABLEB-5'>Table B-5</a> lists
+the constants for the <a
+href='#ModelNumber'><code>ModelNumber</code></a> directive.
+<code>ModelNumber</code> values should be specified as the bitwise
+OR of one or more of these constants.</p>
+
+<center><table border='1' cellpadding='5' cellspacing='0' width='80%'>
+<caption align='bottom'><a name='TABLEB-5'><i>Table B-5, <code>pcl</code> driver
+constants</i></a></caption>
+<tr bgcolor='#cccccc'>
+ <th>Constant</th>
+ <th>Description</th>
+</tr>
+<tr>
+ <td valign='top'><code>PCL_PAPER_SIZE</code></td>
+ <td align='justify' valign='top'>Use paper size command (<code>ESC &amp; l # A</code>)</td>
+</tr>
+<tr>
+ <td valign='top'><code>PCL_INKJET</code></td>
+ <td align='justify' valign='top'>Use inkjet commands</td>
+</tr>
+<tr>
+ <td valign='top'><code>PCL_RASTER_END_COLOR</code></td>
+ <td align='justify' valign='top'>Use new end-raster command (<code>ESC * r C</code>)</td>
+</tr>
+<tr>
+ <td valign='top'><code>PCL_RASTER_CID</code></td>
+ <td align='justify' valign='top'>Use configure-image-data command (<code>ESC * v # W</code>)</td>
+</tr>
+<tr>
+ <td valign='top'><code>PCL_RASTER_CRD</code></td>
+ <td align='justify' valign='top'>Use configure-raster-data command (<code>ESC * g # W</code>)</td>
+</tr>
+<tr>
+ <td valign='top'><code>PCL_RASTER_SIMPLE</code></td>
+ <td align='justify' valign='top'>Use simple-raster-color command (<code>ESC * r # U</code>)</td>
+</tr>
+<tr>
+ <td valign='top'><code>PCL_RASTER_RGB24</code></td>
+ <td align='justify' valign='top'>Use 24-bit RGB mode</td>
+</tr>
+<tr>
+ <td valign='top'><code>PCL_PJL</code></td>
+ <td align='justify' valign='top'>Use PJL commands</td>
+</tr>
+<tr>
+ <td valign='top'><code>PCL_PJL_PAPERWIDTH</code></td>
+ <td align='justify' valign='top'>Use PJL PAPERWIDTH/LENGTH commands</td>
+</tr>
+<tr>
+ <td valign='top'><code>PCL_PJL_HPGL2</code></td>
+ <td align='justify' valign='top'>Use PJL ENTER HPGL2 command</td>
+</tr>
+<tr>
+ <td valign='top'><code>PCL_PJL_PCL3GUI</code></td>
+ <td align='justify' valign='top'>Use PJL ENTER PCL3GUI command</td>
+</tr>
+<tr>
+ <td valign='top'><code>PCL_PJL_RESOLUTION</code></td>
+ <td align='justify' valign='top'>Use PJL SET RESOLUTION command</td>
+</tr>
+</table></center>
+
+<H2><A NAME="REF_COLOR">Color Keywords</A></H2>
+
+<p>The PPD compiler defines two types of color keywords:
+colorspace and color order. The following sections list the
+supported keywords for each type.</p>
+
+<H3><A NAME="REF_COLOR_SPACE">Colorspace Keywords</A></H3>
+
+<P>The following colorspace keywords are recognized:</P>
+
+<UL>
+
+ <LI><TT>cielab</TT> - CIE Lab <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>ciexyz</TT> - CIE XYZ <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>cmy</TT> - Cyan, magenta, yellow</LI>
+
+ <LI><TT>cmyk</TT> - Cyan, magenta, yellow, black</LI>
+
+ <LI><TT>gmck</TT> - Gold, magenta, yellow, black <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>gmcs</TT> - Gold, magenta, yellow, silver <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>gold</TT> - Gold foil <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>icc1</TT> - ICC-based, 1 color <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>icc2</TT> - ICC-based, 2 colors <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>icc3</TT> - ICC-based, 3 colors <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>icc4</TT> - ICC-based, 4 colors <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>icc5</TT> - ICC-based, 5 colors <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>icc6</TT> - ICC-based, 6 colors <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>icc7</TT> - ICC-based, 7 colors <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>icc8</TT> - ICC-based, 8 colors <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>icc9</TT> - ICC-based, 9 colors <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>icca</TT> - ICC-based, 10 colors <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>iccb</TT> - ICC-based, 11 colors <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>iccc</TT> - ICC-based, 12 colors <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>iccd</TT> - ICC-based, 13 colors <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>icce</TT> - ICC-based, 14 colors <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>iccf</TT> - ICC-based, 15 colors <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>k</TT> - Black</LI>
+
+ <LI><TT>kcmy</TT> - Black, cyan, magenta, yellow <A HREF="#REF_COLOR_APPLE">*</A></LI>
+
+ <LI><TT>kcmycm</TT> - Black, cyan, magenta, yellow, light-cyan, light-magenta <A HREF="#REF_COLOR_APPLE">*</A></LI>
+
+ <LI><TT>rgb</TT> - Red, green, blue</LI>
+
+ <LI><TT>rgba</TT> - Red, green, blue, alpha</LI>
+
+ <LI><TT>rgbw</TT> - Red, green, blue, luminance <A HREF="#REF_COLOR_APPLE">*</A></LI>
+
+ <LI><TT>silver</TT> - Silver foil <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>w</TT> - Luminance</LI>
+
+ <LI><TT>white</TT> - White ink (as black) <A HREF="#REF_COLOR_APPLE2">**</A></LI>
+
+ <LI><TT>ymc</TT> - Yellow, magenta, cyan <A HREF="#REF_COLOR_APPLE">*</A></LI>
+
+ <LI><TT>ymck</TT> - Yellow, magenta, cyan, black <A HREF="#REF_COLOR_APPLE">*</A>
+
+ <BR>&nbsp;
+
+ <BR><A NAME="REF_COLOR_APPLE">*</A> = This colorspace is not supported on Mac OS X prior to 10.4.
+ <BR><A NAME="REF_COLOR_APPLE2">**</A> = This colorspace is not supported on Mac OS X.</LI>
+
+</UL>
+
+<H3><A NAME="REF_COLOR_ORDER">Color Order Keywords</A></H3>
+
+<P>The following color order keywords are recognized:</P>
+
+<UL>
+
+ <LI><TT>chunked</TT> or <TT>chunky</TT> - Color values
+ are passed together on a line as RGB RGB RGB RGB</LI>
+
+ <LI><TT>banded</TT> - Color values are passed separately
+ on a line as RRRR GGGG BBBB <A
+ HREF="#REF_COLOR_APPLE2">*</A></LI>
+
+ <LI><TT>planar</TT> - Color values are passed separately
+ on a page as RRRR RRRR RRRR ... GGGG GGGG GGGG ... BBBB
+ BBBB BBBB <A HREF="#REF_COLOR_APPLE2">*</A>
+
+ <BR>&nbsp;
+
+ <BR><A NAME="REF_COLOR_APPLE2">*</A> = This color order
+ is not supported by the current Apple RIP filters and
+ should not be used when developing printer drivers for
+ Mac OS X.</LI>
+
+</UL>
+
+</BODY>
+</HTML>
diff --git a/doc/help/ref-printers-conf.html b/doc/help/ref-printers-conf.html
new file mode 100644
index 000000000..9568fc7c8
--- /dev/null
+++ b/doc/help/ref-printers-conf.html
@@ -0,0 +1,720 @@
+<HTML>
+<!-- SECTION: References -->
+<HEAD>
+ <TITLE>printers.conf</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">printers.conf</H1>
+
+<P>The CUPS scheduler (cupsd) uses the
+<VAR>/etc/cups/printers.conf</VAR> file to store the list of
+available printers. This file contains only locally defined
+printers, not remote printers that are created automatically via
+browsing. Each directive is listed on a line by itself followed
+by its value. Comments are introduced using the number sign ("#")
+character at the beginning of a line.</P>
+
+<P>While the printer configuration file consists of plain text
+and can be modified using your favorite text editor, you should
+normally use the <A HREF="man-lpadmin.html">lpadmin(8)</A>
+command, web interface, or any of the available GUIs to manage
+your printers instead. If you do choose to edit this file
+manually, you will need to stop the scheduler first, make your
+changes, and then start the scheduler to make them active.</P>
+
+
+<H2 CLASS="title"><A NAME="Accepting">Accepting</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ Accepting yes
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Accepting</CODE> directive defines the initial state
+of the <VAR>printer-is-accepting-jobs</VAR> attribute. This state
+is also set by the <CODE>cupsaccept(8)</CODE> and
+<CODE>cupsreject(8)</CODE> commands:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/cupsaccept printername
+/usr/sbin/cupsreject printername</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="AllowUser">AllowUser</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ AllowUser foo_user
+ AllowUser @bar_group
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>AllowUser</CODE> directive adds a username or group
+name to the <VAR>requesting-user-name-allowed</VAR> attribute
+which can be set by the <CODE>lpadmin(8)</CODE> command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -u allow:foo_user,@bar_group</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A> directive.
+This directive cannot be used with <A
+HREF="#DenyUser"><CODE>DenyUser</CODE></A>.</P>
+
+
+<H2 CLASS="title"><A NAME="DefaultPrinter">DefaultPrinter</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;DefaultPrinter name&gt;
+ ...
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DefaultPrinter</CODE> directive begins a printer
+definition as the default server destination. The default server
+destination can be set using the <CODE>lpadmin(8)</CODE>
+command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -d printername</KBD>
+</PRE>
+
+<P>Note that the server default destination settings can be
+overridden by the user's default destination settings which are
+normally set using the <CODE>lpoptions(1)</CODE> command.</P>
+
+
+<H2 CLASS="title"><A NAME="DenyUser">DenyUser</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ DenyUser foo_user
+ DenyUser @bar_group
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DenyUser</CODE> directive adds a username or group
+name to the <VAR>requesting-user-name-denied</VAR> attribute
+which can be set by the <CODE>lpadmin(8)</CODE> command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -u deny:foo_user,@bar_group</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A> directive.
+This directive cannot be used with <A
+HREF="#AllowUser"><CODE>AllowUser</CODE></A></P>
+
+
+<H2 CLASS="title"><A NAME="DeviceURI">DeviceURI</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ DeviceURI socket://foo.bar.com:9100
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DeviceURI</CODE> directive defines the value of the
+<VAR>device-uri-attribute</VAR> attribute. It is normally set
+using the <CODE>lpadmin(8)</CODE> command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -v device-uri</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2</SPAN><A NAME="ErrorPolicy">ErrorPolicy</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ ErrorPolicy abort-job
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ErrorPolicy</CODE> directive defines the policy that
+is used when a backend is unable to send a print job to the
+printer. The <CODE>lpadmin(8)</CODE> command sets the current
+error policy:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -o printer-error-policy=stop-printer</KBD>
+</PRE>
+
+<P>The following values are supported:</P>
+
+<UL>
+
+ <LI><CODE>abort-job</CODE> - Abort the job and proceed
+ with the next job in the queue</LI>
+
+ <LI><CODE>retry-current-job</CODE> - Retry the current job
+ immediately</LI>
+
+ <LI><CODE>retry-job</CODE> - Retry the job after waiting
+ for N seconds; the <VAR>cupsd.conf</VAR> <A
+ HREF="ref-cupsd-conf.html#JobRetryInterval"><CODE>JobRetryInterval</CODE></A>
+ directive controls the value of N</LI>
+
+ <LI><CODE>stop-printer</CODE> - Stop the printer and keep
+ the job for future printing; this is the default
+ value</LI>
+
+</UL>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.4</SPAN><A NAME="Filter">Filter</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ Filter mime/type 100 program
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Filter</CODE> directive lists a single filter program as defined
+in the printer's PPD file.</P>
+
+<P>This directive must appear inside a
+<A HREF="#Printer"><CODE>Printer</CODE></A> or
+<A HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="Info">Info</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ Info My Printer
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Info</CODE> directive defines the string for the
+<VAR>printer-info</VAR> attribute. It is normally set using the
+<CODE>lpadmin(8)</CODE> command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -D "My Printer"</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="JobSheets">JobSheets</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ JobSheets none,standard
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>JobSheets</CODE> directive specifies the default
+banner pages to print before and after a print job. In the above
+example, only a <VAR>standard</VAR> banner will print after each
+job. The <CODE>lpadmin(8)</CODE> command is normally used to set
+the default banners:
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -o job-sheets-default=none,standard</KBD>
+</PRE>
+
+<P>If only one banner file is specified, it will be printed
+before the files in the job. If a second banner file is
+specified, it is printed after the files in the job.</P>
+
+<P>The available banner pages depend on the local system
+configuration; CUPS includes the following standard banner
+files:</P>
+
+<UL>
+
+ <LI><CODE>none</CODE> - Do not produce a banner
+ page.</LI>
+
+ <LI><CODE>classified</CODE> - A banner page with a
+ &quot;classified&quot; label at the top and bottom.</LI>
+
+ <LI><CODE>confidential</CODE> - A banner page with a
+ &quot;confidential&quot; label at the top and bottom.</LI>
+
+ <LI><CODE>secret</CODE> - A banner page with a
+ &quot;secret&quot; label at the top and bottom.</LI>
+
+ <LI><CODE>standard</CODE> - A banner page with no label
+ at the top and bottom.</LI>
+
+ <LI><CODE>topsecret</CODE> - A banner page with a
+ &quot;top secret&quot; label at the top and bottom.</LI>
+
+ <LI><CODE>unclassified</CODE> - A banner page with an
+ &quot;unclassified&quot; label at the top and bottom.</LI>
+
+</UL>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="KLimit">KLimit</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ KLimit 1234
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>KLimit</CODE> directive defines the value of the
+<VAR>job-k-limit</VAR> attribute. It is normally set using the
+<CODE>lpadmin(8)</CODE> command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -o job-k-limit=1234</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="Location">Location</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ Location Building 3321
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Location</CODE> directive defines the string for the
+<VAR>printer-location</VAR> attribute. It is normally set using the
+<CODE>lpadmin(8)</CODE> command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -L "Building 3321"</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2</SPAN><A NAME="OpPolicy">OpPolicy</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ OpPolicy default
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>OpPolicy</CODE> directive sets the operation policy
+that is used for the printer. The <CODE>lpadmin(8)</CODE> command
+sets the current operation policy:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -o printer-op-policy=default</KBD>
+</PRE>
+
+<P>The default policy is named "default". All policies correspond
+to those defined using the <VAR>cupsd.conf</VAR> <A
+HREF="ref-cupsd-conf.html#Policy"><CODE>Policy</CODE></A>
+section.</P>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2</SPAN><A NAME="Option">Option</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ Option name value
+ Option scaling 100
+ Option page-left 72
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Option</CODE> directive specifies a default job
+template attribute value. It is mapped to
+<CODE>name-default</CODE> in the printer attributes and applied
+to jobs as <CODE>name</CODE>.</P>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="PageLimit">PageLimit</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ PageLimit 1234
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>PageLimit</CODE> directive defines the value of the
+<VAR>job-page-limit</VAR> attribute. It can be set using the
+<CODE>lpadmin(8)</CODE> command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -o job-page-limit=1234</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2</SPAN><A NAME="PortMonitor">PortMonitor</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ PortMonitor bcp
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>PortMonitor</CODE> directive sets the filter program that
+is used for every print job, typically to encode or package the print
+data in a format acceptable for a particular printer interface. It is
+set using the <CODE>lpadmin(8)</CODE> command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -o port-monitor=tbcp</KBD>
+</PRE>
+
+<P>The following standard port monitors are included with CUPS:</P>
+
+<UL>
+
+ <LI><CODE>bcp</CODE> - Encode PostScript print data using
+ the Adobe Binary Control Protocol (BCP)</LI>
+
+ <LI><CODE>none</CODE> - Do not use a port monitor</LI>
+
+ <LI><CODE>tbcp</CODE> - Encode PostScript print data
+ using the Adobe Tagged Binary Control Protocol
+ (TBCP)</LI>
+
+</UL>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.4</SPAN><A NAME="PreFilter">PreFilter</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ PreFilter mime/type 100 program
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>PreFilter</CODE> directive lists a single pre-filter program as
+defined in the printer's PPD file.</P>
+
+<P>This directive must appear inside a
+<A HREF="#Printer"><CODE>Printer</CODE></A> or
+<A HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="Printer">Printer</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Printer</CODE> directive begins a printer
+definition. Printers are added using the <CODE>lpadmin(8)</CODE>
+command:
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername ...</KBD>
+</PRE>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.4</SPAN><A NAME="Product">Product</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ Product Acme PaperWriter
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Product</CODE> directive defines the main product string from the
+printer's PPD file and is used when advertising the queue via DNS-SD.</P>
+
+<P>This directive must appear inside a
+<A HREF="#Printer"><CODE>Printer</CODE></A> or
+<A HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="QuotaPeriod">QuotaPeriod</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ QuotaPeriod 604800
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>QuotaPeriod</CODE> directive defines the value of
+the <VAR>job-quota-period</VAR> attribute. Typical values are
+86400 (1 day), 604800 (1 week), 2592000 (1 month), and 31536000
+(1 year). It is set using the <CODE>lpadmin(8)</CODE>
+command:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -o job-quota-period=604800</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2</SPAN><A NAME="Shared">Shared</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ Shared yes
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Shared</CODE> directive defines the initial value of
+the <VAR>printer-is-shared</VAR> attribute. The strings
+<VAR>yes</VAR> and <VAR>no</VAR> correspond to the true and false
+values, respectively. The <CODE>lpadmin(8)</CODE> command sets
+the current state:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/lpadmin -p printername -o printer-is-shared=true</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="State">State</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ State idle
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>State</CODE> directive defines the initial value of
+the <VAR>printer-state</VAR> attribute. The strings
+<VAR>idle</VAR> and <VAR>stopped</VAR> correspond to the IPP
+enumeration values 3 and 5, respectively. The
+<CODE>cupsenable(8)</CODE> and <CODE>cupsdisable(8)</CODE>
+commands set the current state:</P>
+
+<PRE CLASS="command">
+<KBD>/usr/sbin/cupsenable printername</KBD>
+<KBD>/usr/sbin/cupsdisable printername</KBD>
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="StateMessage">StateMessage</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ StateMessage Ready to print.
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>StateMessage</CODE> directive defines the initial
+string for the <VAR>printer-state-message</VAR> attribute. The
+following are some example messages:</P>
+
+<PRE CLASS="command">
+StateMessage Connected to host_name...
+StateMessage Connecting to printer_queue on port port_number...
+StateMessage Network host host_name is busy; will retry in 30 seconds...
+StateMessage Printer busy; will retry in 10 seconds...
+StateMessage Printer is busy; retrying print job...
+StateMessage Print file accepted - job ID id_number.
+StateMessage Ready to print.
+StateMessage Waiting for job to complete
+</PRE>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2</SPAN><A NAME="StateTime">StateTime</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Printer name&gt;
+ ...
+ StateTime 1133542425
+&lt;/Printer&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>StateTime</CODE> directive defines the UNIX time
+(seconds since Jan 1, 1970) for the last state change of the
+queue. It is mapped to the <VAR>printer-state-change-time</VAR>
+attribute.</P>
+
+<P>This directive must appear inside a <A
+HREF="#Printer"><CODE>Printer</CODE></A> or <A
+HREF="#DefaultPrinter"><CODE>DefaultPrinter</CODE></A>
+section.</P>
+
+
+</BODY>
+</HTML>
diff --git a/doc/help/ref-snmp-conf.html b/doc/help/ref-snmp-conf.html
new file mode 100644
index 000000000..db4aacee5
--- /dev/null
+++ b/doc/help/ref-snmp-conf.html
@@ -0,0 +1,146 @@
+<HTML>
+<!-- SECTION: References -->
+<HEAD>
+ <TITLE>snmp.conf</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">snmp.conf</H1>
+
+<P>The <VAR>/etc/cups/snmp.conf</VAR> file contains several
+directives that determine how the SNMP printer discovery backend
+behaves. Each directive is listed on a line by itself followed
+by its value. Comments are introduced using the number sign ("#")
+character at the beginning of a line.</P>
+
+<P>The SNMP backend uses the SNMPv1 protocol to discover network
+printers, collecting information from the Host MIB along with
+intelligent port probes to determine the correct device URI and
+make and model for each printer. Future versions of CUPS will
+likely support the new Port Monitor MIB as well.</P>
+
+<H2 CLASS="title"><A NAME="Address">Address</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+Address @LOCAL
+Address @IF(name)
+Address 255.255.255.255
+Address 192.168.2.255
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Address</CODE> directive specifies a broadcast
+address to use when discovering printers. Multiple
+<CODE>Address</CODE> lines can be provided to scan different
+subnets.</P>
+
+<P>The default address is <VAR>@LOCAL</VAR>, which broadcasts to
+all LANs.</P>
+
+
+<H2 CLASS="title"><A NAME="Community">Community</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+Community public
+Community easysw
+Community BigCorp
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Community</CODE> directive specifies a community
+name to use when discovering printers. Multiple
+<CODE>Community</CODE> lines can be provided to scan different
+SNMP communities.</P>
+
+<P>The default community is "public".</P>
+
+
+<H2 CLASS="title"><A NAME="DebugLevel">DebugLevel</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+DebugLevel 0
+DebugLevel 1
+DebugLevel 2
+DebugLevel 3
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DebugLevel</CODE> directive specifies the debugging
+level to use when searching for network printers. Level 0
+produces no debugging information. Level 1 produces basic
+debugging information. Level 2 adds printing of the SNMP
+messages. Level 3 adds a hex dump of the network data.</P>
+
+<P>The default setting is <VAR>0</VAR>.</P>
+
+<H2 CLASS="title"><A NAME="DeviceURI">DeviceURI</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+DeviceURI "HP.*JetDirect.*" socket://%s:9100 socket://%s:9101 socket://%s:9102
+DeviceURI "HP.*" socket://%s
+DeviceURI "Acme.*Laser.*" lpd://%s/print
+DeviceURI "Xerox.*"
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DeviceURI</CODE> directive specifies a regular expression
+(enclosed in double quotes) that is matched against the SNMP device
+description OID returned by a printer. If the description matches the
+regular expression, each device URI that follows the regular expression
+is listed by the backend, with any occurrences of <CODE>%s</CODE>
+replaced by the device's hostname or IP address. If no URIs are listed,
+the device is ignored.</P>
+
+<P>The <CODE>DeviceURI</CODE> directives are processed serially in
+the order specified in the <VAR>snmp.conf</VAR> file until a match
+is found.</P>
+
+
+<H2 CLASS="title"><A NAME="HostNameLookups">HostNameLookups</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+HostNameLookups on
+HostNameLookups off
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>HostNameLookups</CODE> directive specifies whether printer
+addresses are converted to hostnames or left as numeric IP addresses.</P>
+
+<P>The default setting is <VAR>off</VAR>.</P>
+
+<H2 CLASS="title"><A NAME="MaxRunTime">MaxRunTime</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+MaxRunTime 10
+MaxRunTime 300
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>MaxRunTime</CODE> directive specifies the maximum
+number of seconds that the SNMP backend will spend looking for
+printer devices on the network.</P>
+
+<P>The default setting is <VAR>10</VAR>.</P>
+
+</BODY>
+</HTML>
diff --git a/doc/help/ref-subscriptions-conf.html b/doc/help/ref-subscriptions-conf.html
new file mode 100644
index 000000000..d4f4defc3
--- /dev/null
+++ b/doc/help/ref-subscriptions-conf.html
@@ -0,0 +1,354 @@
+<HTML>
+<!-- SECTION: References -->
+<HEAD>
+ <TITLE>subscriptions.conf</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">subscriptions.conf</H1>
+
+<P>The CUPS scheduler (cupsd) uses the
+<VAR>/etc/cups/subscriptions.conf</VAR> file to store the list
+of active subscriptions. Each directive is listed on a line by
+itself followed by its value. Comments are introduced using the
+number sign ("#") character at the beginning of a line.
+
+<P>While the subscriptions configuration file consists of plain
+text and can be modified using your favorite text editor, you
+should normally use the command-line programs (<A
+HREF="man-lp.html">lp(1)</A> and <A
+HREF="man-lpr.html">lpr(1)</A>) or specific applications via IPP
+requests to manage your subscriptions.</P>
+
+<H2 CLASS="title"><A NAME="Events">Events</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Subscription NNN&gt;
+ ...
+ Events job-completed
+&lt;/Subscription&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Events</CODE> directive lists the events, separated
+by spaces, that the subscriber is interested in. Table 1 lists
+the supported event names.</P>
+
+<P>The <CODE>Events</CODE> directive must appear inside a <A
+HREF="#Subscription"><CODE>Subscription</CODE></A> section.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="Event Names">
+<CAPTION>Table 1: <A NAME="TABLE1">Event Names</A></CAPTION>
+<THEAD>
+<TR>
+ <TH>Name</TH>
+ <TH>Description</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD>all</TD>
+ <TD>All events</TD>
+</TR>
+<TR>
+ <TD>job-completed</TD>
+ <TD>Send notification when the job is completed</TD>
+</TR>
+<TR>
+ <TD>job-config-changed</TD>
+ <TD>Send notification when the job is changed</TD>
+</TR>
+<TR>
+ <TD>job-created</TD>
+ <TD>Send notification when a job is created</TD>
+</TR>
+<TR>
+ <TD>job-progress</TD>
+ <TD>Send notification for job progress</TD>
+</TR>
+<TR>
+ <TD>job-state-changed</TD>
+ <TD>Send notification when the job-state changes</TD>
+</TR>
+<TR>
+ <TD>job-stopped</TD>
+ <TD>Send notification when the job is stopped</TD>
+</TR>
+<TR>
+ <TD>printer-added</TD>
+ <TD>Send notification when a printer is added</TD>
+</TR>
+<TR>
+ <TD>printer-changed</TD>
+ <TD>Send notification when a printer is changed</TD>
+</TR>
+<TR>
+ <TD>printer-config-changed</TD>
+ <TD>Send notification when a printer's configuration is changed</TD>
+</TR>
+<TR>
+ <TD>printer-deleted</TD>
+ <TD>Send notification when a printer is deleted</TD>
+</TR>
+<TR>
+ <TD>printer-modified</TD>
+ <TD>Send notification when a printer is modified</TD>
+</TR>
+<TR>
+ <TD>printer-state-changed</TD>
+ <TD>Send notification when the printer-state changes</TD>
+</TR>
+<TR>
+ <TD>printer-stopped</TD>
+ <TD>Send notification when a printer is stopped</TD>
+</TR>
+<TR>
+ <TD>server-audit</TD>
+ <TD>Send notification when a bad request, security error, or
+ authentication error occurs</TD>
+</TR>
+<TR>
+ <TD>server-restarted</TD>
+ <TD>Send notification when the server is restarted</TD>
+</TR>
+<TR>
+ <TD>server-started</TD>
+ <TD>Send notification when the server is initially started</TD>
+</TR>
+<TR>
+ <TD>server-stopped</TD>
+ <TD>Send notification when the server is shutdown</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+
+<H2 CLASS="title"><A NAME="ExpirationTime">ExpirationTime</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Subscription NNN&gt;
+ ...
+ ExpirationTime 1012563145
+&lt;/Subscription&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ExpirationTime</CODE> directive specifies the
+expiration time of the subscription as a UNIX time value. It is 0
+for subscriptions with no predefined expiration time.</P>
+
+<P>The <CODE>ExpirationTime</CODE> directive must appear inside a
+<A HREF="#Subscription"><CODE>Subscription</CODE></A>
+section.</P>
+
+
+<H2 CLASS="title"><A NAME="Interval">Interval</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Subscription NNN&gt;
+ ...
+ Interval 30
+&lt;/Subscription&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Interval</CODE> directive specifies the preferred
+time interval for event notifications in seconds.</P>
+
+<P>The <CODE>Interval</CODE> directive must appear inside a <A
+HREF="#Subscription"><CODE>Subscription</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="JobId">JobId</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Subscription NNN&gt;
+ ...
+ JobId 123
+&lt;/Subscription&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>JobId</CODE> directive specifies the
+<CODE>job-id</CODE> for job subscriptions.</P>
+
+<P>The <CODE>JobId</CODE> directive must appear inside a <A
+HREF="#Subscription"><CODE>Subscription</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="LeaseDuration">LeaseDuration</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Subscription NNN&gt;
+ ...
+ LeaseDuration
+&lt;/Subscription&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>LeaseDuration</CODE> directive specifies the number
+of seconds that the subscription is valid. A value of 0 means
+that the subscription will last forever or the life of the print
+job the subscription is attached to.</P>
+
+<P>The <CODE>LeaseDuration</CODE> directive must appear inside a <A
+HREF="#Subscription"><CODE>Subscription</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="NextEventId">NextEventId</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Subscription NNN&gt;
+ ...
+ NextEventId 999
+&lt;/Subscription&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>NextEventId</CODE> directive specifies the
+<CODE>notify-sequence-number</CODE> value for the next
+notification event. It starts at 1 and increases for every event
+that is delivered for the subscription.</P>
+
+<P>The <CODE>NextEventId</CODE> directive must appear inside a <A
+HREF="#Subscription"><CODE>Subscription</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="NextSubscriptionId">NextSubscriptionId</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+NextSubscriptionId 999
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>NextSubscriptionId</CODE> directive specifies the
+next subscription ID to use. It defaults to 1 more than the
+highest subscription number seen.</P>
+
+
+<H2 CLASS="title"><A NAME="Owner">Owner</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Subscription NNN&gt;
+ ...
+ Owner username
+&lt;/Subscription&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Owner</CODE> directive specifies the user that owns
+this subscription.</P>
+
+<P>The <CODE>Owner</CODE> directive must appear inside a <A
+HREF="#Subscription"><CODE>Subscription</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="PrinterName">PrinterName</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Subscription NNN&gt;
+ ...
+ PrinterName name
+&lt;/Subscription&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>PrinterName</CODE> directive specifies the name of
+the printer or class that is associated with this
+subscription.</P>
+
+<P>The <CODE>PrinterName</CODE> directive must appear inside a <A
+HREF="#Subscription"><CODE>Subscription</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="Recipient">Recipient</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Subscription NNN&gt;
+ ...
+ Recipient mailto:foo@domain.com
+&lt;/Subscription&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Recipient</CODE> directive specifies the
+<CODE>notify-recipient-uri</CODE> value for push-type
+notifications. The URI scheme name determines which notifier
+program is used to send the event(s).</P>
+
+<P>The <CODE>Recipient</CODE> directive must appear inside a <A
+HREF="#Subscription"><CODE>Subscription</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><A NAME="Subscription">Subscription</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Subscription NNN&gt;
+ ...
+&lt;/Subscription&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>Subscription</CODE> section defines a single
+subscription in the system. Each subscription is assigned a
+unique (to the server) number starting at 1.</P>
+
+
+<H2 CLASS="title"><A NAME="UserData">UserData</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+&lt;Subscription NNN&gt;
+ ...
+ UserData mailto:bar<40>domain.com
+&lt;/Subscription&gt;
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>UserData</CODE> directive specifies the
+<CODE>notify-user-data</CODE> value, which is normally the "from"
+address used in <CODE>mailto</CODE> notifications. Binary values
+are introduced by encoding the bytes as hexadecimal values inside
+angle brackets, e.g. "<1234>".</P>
+
+<P>The <CODE>UserData</CODE> directive must appear inside a <A
+HREF="#Subscription"><CODE>Subscription</CODE></A> section.</P>
+
+</BODY>
+</HTML>
diff --git a/doc/help/security.html b/doc/help/security.html
new file mode 100644
index 000000000..c86151d17
--- /dev/null
+++ b/doc/help/security.html
@@ -0,0 +1,172 @@
+<HTML>
+<!-- SECTION: Getting Started -->
+<HEAD>
+ <TITLE>Server Security</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">Server Security</H1>
+
+<P>In the default "standalone" configuration, there are few
+potential security risks - the CUPS server does not accept remote
+connections, and only accepts shared printer information from the
+local subnet. When you share printers and/or enable remote
+administration, you expose your system to potential unauthorized
+access. This help page provides an analysis of possible CUPS
+security concerns and describes how to better secure your
+server.</P>
+
+<H2 CLASS="title"><A NAME="AUTHENTICATION">Authentication Issues</A></H2>
+
+<P>When you enable remote administration, the server will use
+Basic authentication for administration tasks. The current CUPS
+server supports Basic, Digest, Kerberos, and local certificate
+authentication:</P>
+
+<OL>
+
+ <LI>Basic authentication essentially places the clear
+ text of the username and password on the network.
+
+ <P>Since CUPS uses the system username and password
+ account information, the authentication information could
+ be used to gain access to possibly privileged accounts on
+ the server.</P>
+
+ <P><B>Recommendation:</B> Enable encryption to hide the
+ username and password information - this is the default on
+ MacOS X and systems with GNU TLS or OpenSSL installed.</P></LI>
+
+ <LI>Digest authentication uses an MD5 checksum of the
+ username, password, and domain ("CUPS"), so the original
+ username and password is not sent over the network.
+
+ <P>The current implementation does not authenticate the
+ entire message and uses the client's IP address for the
+ nonce value, making it possible to launch "man in the
+ middle" and replay attacks from the same client.</P>
+
+ <P><B>Recommendation:</B> Enable encryption to hide the
+ username and password information.</P></LI></LI>
+
+ <LI>Local certificate authentication passes 128-bit
+ "certificates" that identify an authenticated user.
+ Certificates are created on-the-fly from random data and
+ stored in files under <VAR>/var/run/cups/certs</VAR>.
+ They have restricted read permissions: root +
+ system-group(s) for the root certificate, and lp + lp
+ for CGI certificates.
+
+ <P>Because certificates are only available on the local
+ system, the CUPS server does not accept local
+ authentication unless the client is connected to the
+ loopback interface (127.0.0.1 or ::1) or domain
+ socket.</P>
+
+ <P><B>Recommendation:</B> Ensure that unauthorized users
+ are not added to the system group(s).</P></LI></LI>
+
+</OL>
+
+<H2 CLASS="title"><A NAME="DOS">Denial of Service Attacks</A></H2>
+
+<P>When printer sharing or remote administration is enabled, the
+CUPS server, like all Internet services, is vulnerable to a
+variety of denial of service attacks:</P>
+
+<OL>
+
+ <LI>Establishing multiple connections to the server until
+ the server will accept no more.
+
+ <P>This cannot be protected against by any known
+ software. The <CODE>MaxClientsPerHost</CODE> directive
+ can be used to configure CUPS to limit the number of
+ connections allowed from a single host, however that does
+ not prevent a distributed attack.</P>
+
+ <P><B>Recommendation:</B> Limit access to trusted systems
+ and networks.</P></LI>
+
+ <LI>Repeatedly opening and closing connections to the
+ server as fast as possible.
+
+ <P>There is no easy way of protecting against this in the
+ CUPS software. If the attack is coming from outside the
+ local network, it may be possible to filter such an
+ attack. However, once the connection request has been
+ received by the server it must at least accept the
+ connection to find out who is connecting.</P>
+
+ <P><B>Recommendation:</B> None.</P></LI>
+
+ <LI>Flooding the network with broadcast packets on port
+ 631.
+
+ <P>It might be possible to disable browsing if this
+ condition is detected by the CUPS software, however if
+ there are large numbers of printers available on the
+ network such an algorithm might think that an attack was
+ occurring when instead a valid update was being
+ received.</P>
+
+ <P><B>Recommendation:</B> Block browse packets from
+ foreign or untrusted networks using a router or
+ firewall.</P></LI>
+
+ <LI>Sending partial IPP requests; specifically, sending
+ part of an attribute value and then stopping
+ transmission.
+
+ <P>The current code will wait up to 1 second before
+ timing out the partial value and closing the connection.
+ This will slow the server responses to valid requests and
+ may lead to dropped browsing packets, but will otherwise
+ not affect the operation of the server.</P>
+
+ <P><B>Recommendation:</B> Block IPP packets from foreign
+ or untrusted networks using a router or
+ firewall.</P></LI>
+
+ <LI>Sending large/long print jobs to printers, preventing
+ other users from printing.
+
+ <P>There are limited facilities for protecting against
+ large print jobs (the <CODE>MaxRequestSize</CODE>
+ attribute), however this will not protect printers from
+ malicious users and print files that generate hundreds or
+ thousands of pages.</P>
+
+ <P><B>Recommendation:</B> Restrict printer access to
+ known hosts or networks, and add user-level access
+ controls as needed for expensive printers.</P></LI>
+
+</OL>
+
+<H2 CLASS="title"><A NAME="ENCRYPTION">Encryption Issues</A></H2>
+
+<P>CUPS supports 128-bit SSL 3.0 and TLS 1.0 encryption of
+network connections via the OpenSSL, GNU TLS, and CDSA encryption
+libraries. In additional to the potential security issues posed
+by the SSL and TLS protocols, CUPS currently has the following
+additional issue:</P>
+
+<OL>
+
+ <LI>Certification validation/revocation; currently CUPS
+ does not validate or revoke server or client certificates
+ when establishing a secure connection. This can
+ potentially lead to "man in the middle" and
+ impersonation/spoofing attacks over unsecured networks.
+ Future versions of CUPS will support both validation and
+ revocation of server certificates.
+
+ <P><B>Recommendation:</B> Do not depend on encryption for
+ security when connecting to servers over the Internet or
+ untrusted WAN links.</P></LI>
+
+</OL>
+
+</BODY>
+</HTML>
diff --git a/doc/help/sharing.html b/doc/help/sharing.html
new file mode 100644
index 000000000..00ccb6fe8
--- /dev/null
+++ b/doc/help/sharing.html
@@ -0,0 +1,184 @@
+<html>
+<!-- SECTION: Getting Started -->
+<head>
+ <title>Printer Sharing</title>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">Printer Sharing</H1>
+
+<p>This document discusses several ways to configure printer sharing.</p>
+
+<h2><a name="BASICS">The Basics</h2>
+
+<p>A "server" is any machine that communicates directly to a printer. A "client"
+is any machine that sends print jobs to a server for final printing. Clients can
+also be servers if they communicate directly with any printers of their own.</p>
+
+<p>By default, CUPS uses the Internet Printing Protocol (IPP) to send jobs from
+a client to a server. When printing to legacy print servers you may also use the
+Line Printer Daemon (LPD) when printing to older UNIX-based servers or Server
+Message Block (SMB) when printing to Windows<sup>&reg;</sup> servers.</p>
+
+<p>Clients can automatically discover and access shared printers via CUPS
+browsing, IPP, Service Location Protocol (SLP), and Lightweight Directory Access
+Protocol (LDAP). DNS Service Discovery (DNS-SD a.k.a. Bonjour<sup>&reg;</sup>)
+and SMB browsing can also be used to manually discover and access shared
+printers.</p>
+
+
+<h2><a name="SERVER_CONFIG">Configuring the Server</a></h2>
+
+<p>You must enable printer sharing on the server before clients can print
+through it. The simplest way to do this is to use the
+<a href="man-cupsctl.html">cupsctl(8)</a> command on the server:</p>
+
+<pre class="command">
+cupsctl --share-printers
+</pre>
+
+<p>By default, the above command will allow printing from other clients on the
+same subnet as your server. To allow printing from any subnet, use the following
+command instead:</p>
+
+<pre class="command">
+cupsctl --share-printers --remote-any
+</pre>
+
+<p>Next, you need to choose which protocols to use for printer sharing. The
+default is CUPS browsing and DNS-SD on Mac OS X and CUPS browsing alone on
+other platforms. To set the sharing protocols, run the <b>cupsctl</b> command
+to set the
+<a href="ref-cupsd-conf.html#BrowseLocalProtocols">BrowseLocalProtocols</a>
+value. For example, run the following command to allow shared printing via
+CUPS, DNS-SD, LPD, and SMB:</p>
+
+<pre class="command">
+cupsctl 'BrowseLocalProtocols="cups dnssd lpd smb"'
+</pre>
+
+
+<h2><a name="AUTO_CUPS">Automatic Configuration using CUPS Browsing</a></h2>
+
+<p>CUPS browsing works by periodically broadcasting information about printers
+that are being shared to client systems on the same subnet. Each client
+maintains its own list of shared printers, and when more than one server shares
+the same printer (or the same kind of printer) the client uses all of the
+servers and printers to provide high-availability and failsafe printing.</p>
+
+<p>To configure printers on the same subnet, <em>do nothing</em>. Each client
+should see the available printers within 30 seconds automatically. The printer
+and class lists are updated automatically as printers and servers are added or
+removed.</p>
+
+<blockquote><b>Note:</b>
+
+<p>Due to user interface changes in Mac OS X 10.5, CUPS shared printers will not
+automatically appear in the print dialog. Instead, you must first run the
+following command to enable CUPS browsing on your system:</p>
+
+<pre class="command">
+cupsctl BrowseRemoteProtocols=cups
+</pre>
+
+<p>Then choose each of the CUPS shared printers you want to see in the print
+dialog by adding them, either from the <var>Add Printer...</var> item in the
+print dialog or from the <var>Print &amp; Fax</var> preference pane in the
+<var>System Preferences</var> window.</p>
+
+</blockquote>
+
+<h3><a name="BROWSE_POLL">Seeing Printers on Other Subnets</a></h3>
+
+<p>You can automatically access printers on other subnets by adding
+<a href="ref-cupsd-conf.html#BrowsePoll"><code>BrowsePoll</code></a> lines
+to the <var>cupsd.conf</var> file on your local system. For a single
+server you can use the <b>cupsctl</b> command:</p>
+
+<pre class="command">
+cupsctl BrowsePoll=server:port
+</pre>
+
+<p>For multiple servers, use the CUPS web interface (http://localhost:631/admin)
+to edit the configuration file instead. Enter one <code>BrowsePoll</code> line
+per server at the bottom of the file, as follows:</p>
+
+<pre class="example">
+BrowsePoll server1:port
+BrowsePoll server2:port
+BrowsePoll server3:port
+</pre>
+
+<p>If you have more than one client on your subnet that wants to see the
+printers on those servers, add a
+<a href="ref-cupsd-conf.html#BrowseRelay"><code>BrowseRely</code></a> line
+to the <var>cupsd.conf</var> file on your local system using the <b>cupsctl</b>
+command:</p>
+
+<pre class="command">
+cupsctl 'BrowseRelay="127.0.0.1 @LOCAL"'
+</pre>
+
+<p>or CUPS web interface (again, at the bottom of the file):</p>
+
+<pre class="example">
+BrowseRelay 127.0.0.1 @LOCAL
+</pre>
+
+
+<h2><a name="AUTO_IPP">Automatic Configuration using IPP</a></h2>
+
+<p>CUPS can be configured to run without a local spooler and send all jobs to a
+single server. However, if that server goes down then all printing will be
+disabled. Use this configuration only as absolutely necessary.</p>
+
+<p>The default server is normally the local system ("localhost"). To override
+the default server create a file named <var>/etc/cups/client.conf</var> with a
+line as follows:</p>
+
+<pre class='example'>
+ServerName <em>server</em>
+</pre>
+
+<p>The <var>server</var> name can be the hostname or IP address of the default
+server. If the server is not using the default IPP port (631), you can add the
+port number at the end like this:</p>
+
+<pre class='example'>
+ServerName <em>server:port</em>
+</pre>
+
+<p>The default server can also be customized on a per-user basis. To set a
+user-specific server create a file named <var>~/.cups/client.conf</var> instead.
+The user <var>client.conf</var> file takes precedence over the system one.</p>
+
+<p>Finally, you can set the <code>CUPS_SERVER</code> environment variable to
+override the default server for a single process, for example:</p>
+
+<pre class='command'>
+CUPS_SERVER=server:port firefox http://www.cups.org
+</pre>
+
+<p>will run the Firefox web browser pointed to the specified server and
+port. The environment variable overrides both the user and system
+<var>client.conf</var> files, if any.</p>
+
+
+<h2><a name="MANUAL">Manual Configuration of Print Queues</a></h2>
+
+<p>The most tedious method of configuring client machines is to configure
+each remote queue by hand using the <a href="man-lpadmin.html">lpadmin(8)</a>
+command:</p>
+
+<pre class='command'>
+lpadmin -p <em>printer</em> -E -v ipp://<em>server</em>/printers/<em>printer</em>
+</pre>
+
+<p>The <var>printer</var> name is the name of the printer on the server machine.
+The <var>server</var> name is the hostname or IP address of the server machine.
+Repeat the <b>lpadmin</b> command for each remote printer you wish to use.</p>
+
+
+</body>
+</html>
diff --git a/doc/help/spec-banner.html b/doc/help/spec-banner.html
new file mode 100644
index 000000000..2d22d9e8e
--- /dev/null
+++ b/doc/help/spec-banner.html
@@ -0,0 +1,156 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Specifications -->
+<head>
+ <title>CUPS Banner File Format</title>
+ <meta name='keywords' content='job-sheets'>
+ <link rel='stylesheet' type='text/css' href='../cups-printable.css'>
+</head>
+<body>
+<!--
+ "$Id: spec-banner.html 9727 2011-04-28 21:20:12Z mike $"
+
+ Banner file format specification for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<H1 CLASS="title">CUPS Banner File Format</H1>
+
+<h2 class='title'><a name='INTRODUCTION'>Introduction</a></h2>
+
+<p>This specification describes the CUPS banner file format
+(application/vnd.cups-banner) which is used to generate print job cover pages
+and the CUPS test page. The format itself consists of a header followed by
+lines of UTF-8 text containing comments or keywords and values:</p>
+
+<pre class='command'>
+#CUPS-BANNER
+
+# What to show on the cover page
+Show job-id job-name job-originating-user-name time-at-creation
+
+# The header and footer text
+Header Cover Page
+Footer Cover Page
+
+# Arbitrary "notice" text
+Notice All work and no play makes Johnny a dull boy.
+Notice All work and no play makes Johnny a dull boy.
+Notice All work and no play makes Johnny a dull boy.
+Notice All work and no play makes Johnny a dull boy.
+
+# Images to place below the rest
+Image /usr/share/doc/cups/images/cups-icon.png
+Image /usr/share/doc/cups/images/smiley.jpg
+</pre>
+
+
+<h2 class='title'><a name='KEYWORDS'>Standard Keywords</a></h2>
+
+<h3><a name='Footer'>Footer</a></h3>
+
+<p class='summary'>
+Footer text for footer
+</p>
+
+<p>The <code>Footer</code> key defines the text that is centered at the bottom
+of the page. Only one <code>Footer</code> key can be specified.</p>
+
+
+<h3><a name='Header'>Header</a></h3>
+
+<p class='summary'>
+Header text for Header
+</p>
+
+<p>The <code>Header</code> key defines the text that is centered at the top
+of the page. Only one <code>Header</code> key can be specified.</p>
+
+
+<h3><a name='Image'>Image</a></h3>
+
+<p class='summary'>
+Image /path/to/image/filename<br>
+Image relative/path/in/DocumentRoot/filename
+</p>
+
+<p>The <code>Image</code> key defines images that are centered above the footer
+text. Multiple images are centered as a group from left to right. Images are
+scaled as needed to fit on the page with a nominal size of 1"/25cm.</p>
+
+
+<h3><a name='Notice'>Notice</a></h3>
+
+<p class='summary'>
+Notice Text to display below the job information.<br>
+Notice More text to display below the job information.
+</p>
+
+<p>The <code>Notice</code> key defines lines of text that are centered below
+the job information.</p>
+
+
+<h3><a name='Show'>Show</a></h3>
+
+<p class='summary'>
+Show <em>value value ... value</em>
+</p>
+
+<p>The <code>Show</code> key lists the job information that is shown. The
+following values are supported:</p>
+
+<ul>
+
+ <li><code>imageable-area</code>: The imageable area of the current
+ page size</li>
+
+ <li><code>job-billing</code>: Billing information for the job</li>
+
+ <li><code>job-id</code>: The job ID</li>
+
+ <li><code>job-name</code>: The title of the job</li>
+
+ <li><code>job-originating-host-name</code>: The computer that printed
+ the job</li>
+
+ <li><code>job-originating-user-name</code>: The user that printed the
+ job</li>
+
+ <li><code>job-uuid</code>: The job UUID</li>
+
+ <li><code>options</code>: The options that were provided with the
+ job</li>
+
+ <li><code>paper-name</code>: The name of the paper size used</li>
+
+ <li><code>paper-size</code>: The dimensions of the paper size used.</li>
+
+ <li><code>printer-driver-name</code>: The printer driver used</li>
+
+ <li><code>printer-driver-version</code>: The driver version</li>
+
+ <li><code>printer-info</code>: The printer description</li>
+
+ <li><code>printer-location</code>: The location of the printer</li>
+
+ <li><code>printer-make-and-model</code>: The make and model strings
+ reported by the printer driver</li>
+
+ <li><code>printer-name</code>: The printer used</li>
+
+ <li><code>time-at-creation</code>: When the job was submitted</li>
+
+ <li><code>time-at-processing</code>: The current date and time</li>
+
+</ul>
+
+
+</body>
+</html>
diff --git a/doc/help/spec-browsing.html b/doc/help/spec-browsing.html
new file mode 100644
index 000000000..4583731d4
--- /dev/null
+++ b/doc/help/spec-browsing.html
@@ -0,0 +1,118 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Specifications -->
+<head>
+ <title>CUPS Browse Protocol</title>
+ <meta name='keywords' content='Programming'>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</head>
+<body>
+<!--
+ "$Id: spec-browsing.html 9727 2011-04-28 21:20:12Z mike $"
+
+ CUPS Browse Protocol specification for CUPS.
+
+ Copyright 2008-2011 by Apple Inc.
+ Copyright 1997-2005 by Easy Software Products.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>The CUPS Browse Protocol is deprecated and will no longer be used in a future release of CUPS.</P>
+
+</BLOCKQUOTE>
+
+<H1 CLASS="title">CUPS Browse Protocol</H1>
+
+<h2><a name='INTRO'>Introduction</a></h2>
+
+<p>This specification describes the CUPS browsing protocol which is used for
+printer sharing. The protocol is a UDP/IP-based broadcast service that
+operates on IP service port 631 by default. Each broadcast packet describes
+a single printer or class being shared.</p>
+
+<p>For simple networks with a single subnet, a CUPS system sharing a printer
+(the <em>server</em>) will periodically broadcast that printer's availability
+and status information to the subnet. Every other CUPS system on the subnet
+(the <em>clients</em>) will receive the broadcast and make that printer
+available to local users. If a client stops receiving broadcasts from the
+server, or if the server sends a special "deleted" broadcast message, the
+client will remove its copy of the printer.</p>
+
+<p>For larger networks with multiple subnets, a relay configuration can be used
+where one or more client systems poll the server and then broadcast the
+availability and status information for the server's shared printers to the
+clients' local subnets.</p>
+
+<p>A key feature of CUPS printer sharing is support for <em>implicit
+classes</em>, which are automatically-created classes for printers that are
+shared by multiple servers. These implicit classes provide automatic load
+balancing and fail-safe printing functionality transparently to the user.</p>
+
+
+<h2><a name='SECURITY'>Security Considerations</a></h2>
+
+<p>Like most discovery protocols, CUPS browse packets are not encrypted or
+signed, so it is possible for malicious systems on a network to advertise
+or remove printers on that network to cause denial of service or information
+disclosure. In order to combat this, CUPS logs incoming browse packets and
+provides access controls to limit browse packet reception to known hosts.</p>
+
+
+<h2><a name='FORMAT'>Browse Packet Format</a></h2>
+
+<p>Each broadcast packet is an ASCII text string of up to 1450 bytes ending
+with a line feed (0x0a). The general format is:</p>
+
+<p class='summary'>
+printer-type printer-state printer-uri "printer-location" "printer-info"
+"printer-make-and-model" name=value name2=value2 ...
+</p>
+
+<p>Each of the fields contains the value of the corresponding IPP attribute.
+The trailing "name=value" information is used to convey default job template
+attribute values (job-sheets-default, media-default, etc.), authentication
+requirements (auth-info-required), and additional IPP URI options that are
+requested by the server (ipp-options).</p>
+
+<h3>ABNF Definition</h3>
+
+<p>The following ABNF definition [RFC4234, RFC3986] defines the format of each
+browse packet:</p>
+
+<pre class='command'>
+PACKET = TYPE WSP STATE WSP URI WSP LOCATION WSP INFO WSP
+ MAKE-AND-MODEL WSP *[ WSP ATTR-NAME "=" ATTR-VALUE ] LF
+
+TYPE = 1*HEXDIG
+
+STATE = "3" / "4" / "5"
+
+URI = "ipp://" ( 1*NAMECHAR / IP-literal / IPv4address )
+ [ ":" 1*DIGIT ] ( "/printers/" / "/classes/" ) 1*NAMECHAR
+NAMECHAR = %x21.22.24.26-2E.30-7E / %x25 HEXDIG HEXDIG
+IP-literal = See RFC 3986
+IPv4address = See RFC 3986
+
+LOCATION = QUOTED-STRING
+INFO = QUOTED-STRING
+MAKE-AND-MODEL = QUOTED-STRING
+
+ATTR-NAME = 1*( ALPHA / DIGIT / "-" / "." )
+ATTR-VALUE = QUOTED-STRING / 1*UNQUOTE-CHAR
+
+QUOTED-STRING = DQUOTE *QUOTED-CHAR DQUOTE
+QUOTED-CHAR = %x20.21.23-5B.5D-7E / UTF8-CHAR / %x5C %x5C / %x5C %x22
+UNQUOTE-CHAR = %x21.23-26.28-5B.5D-7E / UTF8-CHAR
+UTF8-CHAR = %xC0.DF %x80.BF / %xE0.EF %x80.BF %x80.BF /
+ %xF0.F7 %x80.BF %x80.BF %x80.BF
+</pre>
+
+</body>
+</html>
diff --git a/doc/help/spec-cmp.html b/doc/help/spec-cmp.html
new file mode 100644
index 000000000..47f56d31d
--- /dev/null
+++ b/doc/help/spec-cmp.html
@@ -0,0 +1,1218 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<!-- SECTION: Specifications -->
+<HEAD>
+ <TITLE>CUPS Developer Guide</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">CUPS Developer Guide</H1>
+
+<P>This developer guide documents the guidelines and processes we use when developing and maintaining CUPS and related software. Our goal is to provide reliable and efficient software and documentation that addresses the needs of our users.</P>
+
+<H2 CLASS="title"><A NAME="COMMUNICATION">Communication</A></H2>
+
+<H3><A NAME="CONTACT">How to Contact the Developers</A></H3>
+
+<P>The <A HREF="http://www.cups.org/newsgroups.php">CUPS
+Forums</A> are the primary means of asking questions and
+informally discussing issues and feature requests with the CUPS
+developers. Table 1 shows the available forums and their
+focus:</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="CUPS Forums">
+<CAPTION>Table 1: CUPS Forums</CAPTION>
+<TR>
+ <TH>Forum</TH>
+ <TH>Focus/Purpose</TH>
+</TR>
+<TR>
+ <TD>cups.bugs</TD>
+ <TD>Discussion of bugs and issues in the CUPS
+ software</TD>
+</TR>
+<TR>
+ <TD>cups.commit</TD>
+ <TD>Report of all commits to the Subversion repository
+ (read-only)</TD>
+</TR>
+<TR>
+ <TD>cups.ddk</TD>
+ <TD>Usage and development questions for the CUPS Driver
+ Development Kit</TD>
+</TR>
+<TR>
+ <TD>cups.development</TD>
+ <TD>Development questions and discussion of new features
+ in the CUPS software</TD>
+</TR>
+<TR>
+ <TD>cups.general</TD>
+ <TD>Usage questions for the CUPS software</TD>
+</TR>
+</TABLE></DIV>
+
+<H3><A NAME="SUBMIT">How to Submit a Bug Report or Feature Request</A></H3>
+
+<P>The CUPS "<A HREF="http://www.cups.org/str.php">Bugs &amp;
+Features</A>" page provides access to the CUPS <em>software
+trouble report</em> database and is the formal way to submit a
+bug report or feature request to the CUPS developers. Please
+note, however, that we <em>do not</em> provide answers to usage
+questions or resolve problems in third-party software on this
+page - use the CUPS Forums for that instead.</P>
+
+<P>Unlike discussions that occur on the CUPS Forums, formal bug
+reports and feature requests must be acted on by the CUPS
+developers. This does not mean that every bug report is resolved
+or every feature request is implemented, but we do respond and
+keep track of them all for posterity.</P>
+
+<BLOCKQUOTE>Please use the search feature of the Bugs &amp;
+Features page before submitting a new bug report or feature
+request. If you see an existing report that matches your issue,
+please post a message to that report ("I have this issue as
+well", "I would also like to see", etc.) rather than submitting a
+new report. This helps speed the resolution of your issue by
+reducing the CUPS developers' work load.</BLOCKQUOTE>
+
+<H3><A NAME="PATCH">How to Prepare a Patch</A></H3>
+
+<P>When submitting a bug report or feature request, you can
+include patch files that resolve the bug or implement the feature
+to speed the inclusion of that bug fix or feature in a new CUPS
+release. For changes to existing files, we prefer a unified diff
+against the current Subversion <VAR>trunk</VAR> branch, which can
+be generated easily using the following Subversion command:</P>
+
+<PRE CLASS="command">
+svn diff >filename.patch
+</PRE>
+
+<P>If you produce a patch using a released source archive, use
+one of the following commands instead:</P>
+
+<PRE CLASS="command">
+diff -u oldfilename filename >filename.patch
+
+diff -urN olddirectory directory >filename.patch
+</PRE>
+
+<P>New files and files with significant changes can be submitted
+in their entirety, however that may delay the adoption of your
+changes.</P>
+
+<BLOCKQUOTE>Patches and files must conform to the standards outlined in the
+"<A HREF="#CODING">Coding Guidelines</A>" and "<A HREF="#MAKEFILES">Makefile
+Guidelines</A>" sections in this document. In addition, since Apple Inc.
+provides CUPS under multiple licenses, we require that you assign the copyright
+for your changes and files to us for inclusion in CUPS.</BLOCKQUOTE>
+
+
+<H2 CLASS="title"><A NAME="PRACTICES">Software Development Practices</A></H2>
+
+<H3><A NAME="VERSIONS">Version Numbering</A></H3>
+
+<P>CUPS uses a three-part version number separated by periods to
+represent the major, minor, and patch release numbers. Major
+release numbers indicate large design changes or
+backwards-incompatible changes to the CUPS API or CUPS Imaging
+API. Minor release numbers indicate new features and other
+smaller changes which are backwards-compatible with previous CUPS
+releases. Patch numbers indicate bug fixes to the previous
+release.</P>
+
+<BLOCKQUOTE>When we talk about compatibility, we are talking
+about binary compatibility for public APIs and output format
+compatibility for program interfaces. Changes to configuration
+file formats or the default behavior of programs are not
+generally considered incompatible as the upgrade process can
+normally address such changes gracefully.</BLOCKQUOTE>
+
+<P>Production releases use the plain version numbers:</P>
+
+<PRE CLASS="command">
+MAJOR.MINOR.PATCH
+1.0.0
+1.0.1
+1.0.2
+...
+1.1.0
+...
+1.1.23
+1.2.0
+1.2.1
+...
+1.3.0
+...
+2.0.0
+</PRE>
+
+<P>The first production release in a MAJOR.MINOR series (MAJOR.MINOR.0) is
+called a feature release. Feature releases are the only releases that may
+contain new features. Subsequent production releases in a MAJOR.MINOR series may
+only contain bug fixes.</P>
+
+<BLOCKQUOTE>We did not hold to this limitation in the CUPS 1.1 series for a
+variety of reasons. Starting with CUPS 1.2, the "no new features in a patch
+release" policy has been strictly enforced. The policy has also resulted in
+fewer new features (and interactions!) to validate/test in the subsequence
+feature releases.</BLOCKQUOTE>
+
+<P>Beta-test releases are identified by appending the letter B to the major and
+minor version numbers followed by the beta release number:</P>
+
+<PRE CLASS="command">
+MAJOR.MINORbNUMBER
+1.2b1
+</PRE>
+
+<P>Release candidates are identified by appending the letters RC to the major
+and minor version numbers followed by the release candidate number:</P>
+
+<PRE CLASS="command">
+MAJOR.MINORrcNUMBER
+1.2rc1
+</PRE>
+
+<P>Developer snapshots are identified by appending the letters SVN-R to the
+major and minor version numbers followed by the revision number:</P>
+
+<PRE CLASS="command">
+MAJOR.MINORsvn-rREV
+1.2svn-r1234
+</PRE>
+
+<P>Beta-test releases, release candidates, and developer snapshots are only
+created for new minor releases. Once a production release has been made
+(MAJOR.MINOR.0), subsequent patch releases are issues without preliminary beta
+or release testing.</P>
+
+<H3>Version Control (Subversion)</H3>
+
+<P>The CUPS source files are managed by the Subversion ("SVN")
+software, available at:</P>
+
+<PRE CLASS="command">
+<A HREF="http://subversion.tigris.org/" TARGET="_blank">subversion.tigris.org</A>
+</PRE>
+
+<P>Source files are "checked in" with each change so that
+modifications can be tracked, and each checkin must reference any
+applicable STRs. The following format <em>must</em> be used for
+commit log messages:</P>
+
+<PRE CLASS="command">
+Summary of the change on one line followed by bug number (STR #NNNN)
+
+Detailed list of changes.
+</PRE>
+
+<P>Primary development occurs on the <var>trunk</var> branch,
+with changes merged back to release branches as needed. Table 2
+shows the URLs developers use for the various CUPS sub-projects
+and branches:</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="CUPS Subversion URLs">
+<CAPTION>Table 2: CUPS Subversion URLs</CAPTION>
+<TR>
+ <TH>URL</TH>
+ <TH>Purpose</TH>
+</TR>
+<TR>
+ <TD><A HREF="http://svn.easysw.com/public/cups/trunk/">https://svn.easysw.com/public/cups/trunk/</A></TD>
+ <TD>Primary CUPS development branch</TD>
+</TR>
+<TR>
+ <TD><A HREF="http://svn.easysw.com/public/cups/branches/">https://svn.easysw.com/public/cups/branches/</A></TD>
+ <TD>CUPS maintenance branches (merge-only)</TD>
+</TR>
+<TR>
+ <TD><A HREF="http://svn.easysw.com/public/cups/tags/">https://svn.easysw.com/public/cups/tags/</A></TD>
+ <TD>CUPS release tags (read-only)</TD>
+</TR>
+<TR>
+ <TD><A HREF="http://svn.easysw.com/public/windows/trunk/">https://svn.easysw.com/public/windows/trunk/</A></TD>
+ <TD>Primary CUPS Windows Driver development branch</TD>
+</TR>
+<TR>
+ <TD><A HREF="http://svn.easysw.com/public/windows/branches/">https://svn.easysw.com/public/windows/branches/</A></TD>
+ <TD>CUPS Windows Driver maintenance branches (merge-only)</TD>
+</TR>
+<TR>
+ <TD><A HREF="http://svn.easysw.com/public/windows/tags/">https://svn.easysw.com/public/windows/tags/</A></TD>
+ <TD>CUPS Windows Driver release tags (read-only)</TD>
+</TR>
+</TABLE></DIV>
+
+<P>The branch for a MAJOR.MINOR release are created when the
+first production release (MAJOR.MINOR.0) is made using the name
+"branch-MAJOR.MINOR". Release tags are created for every beta,
+candidate, and production release using the name
+"release-MAJOR.MINOR.PATCHbNUMBER",
+"release-MAJOR.MINOR.PATCHrcNUMBER", or
+"release-MAJOR.MINOR.PATCH", respectively. No release tags are
+created for developer snapshots.</P>
+
+
+<H3>Files and Directories</H3>
+
+<P>File and directory names may not exceed 16 characters in
+length to ensure compatibility with older UNIX filesystems. In
+addition, to avoid problems with case-insensitive filesystems,
+you may not use names which differ only by case, for example
+"ReadMe" and "README" are not allowed in the same directory.</P>
+
+<P>Source files must be documented and formatted as described in
+"<A HREF="#CODING">Coding Requirements</A>". Make files must
+follow the guidelines in "<A HREF="#MAKEFILE">Makefile
+Guidelines</A>".</P>
+
+
+<H3>Build System</H3>
+
+<P>The CUPS build system uses <A
+HREF="http://www.gnu.org/software/autoconf/">GNU autoconf</A> to
+tailor the library to the local operating system. Project files
+for major IDEs are also provided for Microsoft
+Windows<SUP>&reg;</SUP>. To improve portability, makefiles must
+not make use of the unique features offered by <A
+HREF="http://www.gnu.org/software/make/">GNU make</A>. See the <A
+HREF="#MAKEFILES">Makefile Guidelines</A> section for a
+description of the allowed make features and makefile
+guidelines.</P>
+
+<P>Additional GNU build programs such as <A
+HREF="http://www.gnu.org/software/automake">GNU automake</A> and
+<A HREF="http://www.gnu.org/software/libtool">GNU libtool</A>
+must not be used. GNU automake produces non-portable makefiles
+which depend on GNU-specific extensions, and GNU libtool is not
+portable or reliable enough for CUPS.</P>
+
+
+<H3><A NAME="PACKAGING">Packaging</A></H3>
+
+<P>Source packages are created using the
+<VAR>tools/makesrcdist</VAR> script in the Subversion repository.
+The script optionally uses a version number argument:</P>
+
+<PRE CLASS="command">
+tools/makesrcdist
+tools/makesrcdist <I>version</I>
+</PRE>
+
+<P>When run with no arguments, the script creates a snapshot of
+the current working copy and names it using the highest revision
+number in the WC, for example
+"/tmp/cups-1.3svn-r1234-source.tar.bz2" and
+"/tmp/cups-1.3svn-r1234-source.tar.gz". When run with two
+arguments, the script creates a release tag in the repository and
+exports that tag, creating the files
+"/tmp/cups-<I>version</I>-source.tar.bz2" and
+"/tmp/cups-<I>version</I>-source.tar.gz".</P>
+
+<P>Binary packages are not generally distributed by the CUPS
+team, however the <VAR>packaging/cups.spec</VAR> and
+<VAR>packaging/cups.list</VAR> files may be used to create binary
+packages on Linux, Mac OS X, and UNIX. The
+<VAR>packaging/cups.spec</VAR> file produces a binary package
+using the <CODE>rpmbuild(8)</CODE> software:</P>
+
+<PRE CLASS="command">
+rpmbuild -ta cups-<I>version</I>-source.tar.gz
+</PRE>
+
+<P>The <VAR>cups.list</VAR> file is generated by the
+<VAR>configure</VAR> script and produces binary packages for many
+platforms using the <A HREF="http://www.easysw.com/epm/"
+TARGET="_blank">EPM</A> software. Table 3 shows the targets that
+are available for each type of binary package:</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="Binary Package Targets">
+<CAPTION>Table 3: Binary Package Targets</CAPTION>
+<TR>
+ <TH>Target</TH>
+ <TH>Type of Package</TH>
+</TR>
+<TR>
+ <TD>aix</TD>
+ <TD>AIX installp</TD>
+</TR>
+<TR>
+ <TD>bsd</TD>
+ <TD>*BSD pkg_install</TD>
+</TR>
+<TR>
+ <TD>deb</TD>
+ <TD>Debian dpkg</TD>
+</TR>
+<TR>
+ <TD>depot</TD>
+ <TD>HP-UX swinstall</TD>
+</TR>
+<TR>
+ <TD>epm</TD>
+ <TD>Portable tarball with install script</TD>
+</TR>
+<TR>
+ <TD>inst</TD>
+ <TD>IRIX inst/tardist</TD>
+</TR>
+<TR>
+ <TD>osx</TD>
+ <TD>Mac OS X Install</TD>
+</TR>
+<TR>
+ <TD>pkg</TD>
+ <TD>Solaris pkgadd</TD>
+</TR>
+<TR>
+ <TD>rpm</TD>
+ <TD>RPM binary</TD>
+</TR>
+<TR>
+ <TD>setld</TD>
+ <TD>Tru64 UNIX setld</TD>
+</TR>
+<TR>
+ <TD>slackware</TD>
+ <TD>Slackware install</TD>
+</TR>
+<TR>
+ <TD>swinstall</TD>
+ <TD>HP-UX swinstall</TD>
+</TR>
+<TR>
+ <TD>tardist</TD>
+ <TD>IRIX inst/tardist</TD>
+</TR>
+</TABLE></DIV>
+
+<P>Finally, the <VAR>tools/testrpm</VAR> and
+<VAR>tools/testosx</VAR> scripts can be used to create binary
+packages from the current working copy for testing on Linux and
+Mac OS X, respectively:</P>
+
+<PRE CLASS="command">
+tools/testrpm
+sudo rpm -U /usr/src/redhat/RPMS/i386/cups*.rpm
+
+sudo tools/testosx
+open cups.pkg
+</PRE>
+
+
+<H3><A NAME="TESTING">Testing</A></H3>
+
+<P>Software testing is conducted according to the <A
+HREF="spec-stp.html">CUPS Software Test Plan</A>. This testing is
+automated via the top-level makefile <VAR>test</VAR> target:</P>
+
+<PRE CLASS="command">
+make test
+</PRE>
+
+<P>The test environment allows for both short-term automated
+testing and long-term testing and development without the
+automated test script.</P>
+
+
+<H2 CLASS="title"><A NAME="STR">Trouble Report Processing</A></H2>
+
+<P>A Software Trouble Report ("STR") must be submitted every time
+a user or vendor experiences a problem with the CUPS software.
+Trouble reports are maintained on the <A
+HREF="http://www.cups.org/str.php" TARGET="_blank">Bugs &amp;
+Features</A> page with one of the following states:</P>
+
+<OL>
+
+ <LI>STR is closed with complete resolution</LI>
+
+ <LI>STR is closed without resolution</LI>
+
+ <LI>STR is active, waiting on information from submitter</LI>
+
+ <LI>STR is pending with additional information from submitter</LI>
+
+ <LI>STR is newly submitted</LI>
+
+</OL>
+
+<P>Trouble reports are processed using the following steps.</P>
+
+<OL>
+
+<LI>Classification
+
+<P>When a trouble report is received it must be classified at one
+of the following priority levels:</P>
+
+<OL>
+
+ <LI>Request for enhancement, e.g. asking for a
+ feature
+
+ <LI>Low, e.g. a documentation error or undocumented
+ side-effect
+
+ <LI>Moderate, e.g. unable to print a file or unable to
+ compile the software
+
+ <LI>High, e.g. unable to print to a printer or key
+ functionality not working
+
+ <LI>Critical, e.g. unable to print at all
+
+</OL>
+
+<P>Level 4 and 5 trouble reports must be resolved in the next
+software release. Level 2 and 3 trouble reports are scheduled for
+resolution in a specific release at the discretion of the release
+coordinator. Level 1 trouble reports are scheduled for resolution
+in a future feature release.</P>
+
+<P>The scope of the problem is also determined as:</P>
+
+<OL>
+
+ <LI>Specific to a machine or printer
+
+ <LI>Specific to an operating system
+
+ <LI>Applies to all machines, printers, and operating systems
+
+</OL>
+
+<LI>Identification
+
+<P>Once the level and scope of the trouble report is determined
+the software sub-system(s) involved with the problem are
+determined. This may involve additional communication with the
+user or vendor to isolate the problem to a specific cause.</P>
+
+<P>When the sub-system(s) involved have been identified, an
+engineer will then determine the change(s) needed and estimate
+the time required for the change(s).</P>
+
+<LI>Correction
+
+<P>Corrections are scheduled based upon the severity and
+complexity of the problem. Once all changes have been made,
+documented, and tested successfully a new software release
+snapshot is generated. Additional tests are added as necessary
+for proper testing of the changes.</P>
+
+<LI>Notification
+
+<P>The user or vendor is notified when the fix is available or if
+the problem was caused by user error.</P>
+
+</OL>
+
+
+<H2 CLASS="title"><A NAME="RELEASES">Release Management</A></H2>
+
+<P>When testing has been completed successfully, a new source
+package is created using the <VAR>tools/makesrcdist</VAR> script.
+Three types of releases, beta, candidate, and production, are
+created and released to the public using the basic schedule in
+Table 4. At least one beta and one release candidate must be
+created prior to a production release, and there must be at least
+two weeks between the last beta and first candidate and last
+candidate and first production release.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="CUPS Basic Release Schedule">
+<CAPTION>Table: CUPS Basic Release Schedule</CAPTION>
+<TR>
+ <TH>Week</TH>
+ <TH>Version</TH>
+ <TH>Description</TH>
+</TR>
+<TR>
+ <TD>T-6 weeks</TD>
+ <TD>1.2b1</TD>
+ <TD>First beta release</TD>
+</TR>
+<TR>
+ <TD>T-5 weeks</TD>
+ <TD>1.2b2</TD>
+ <TD>Second beta release</TD>
+</TR>
+<TR>
+ <TD>T-3 weeks</TD>
+ <TD>1.2rc1</TD>
+ <TD>First release candidate</TD>
+</TR>
+<TR>
+ <TD>T-2 weeks</TD>
+ <TD>1.2rc2</TD>
+ <TD>Second release candidate</TD>
+</TR>
+<TR>
+ <TD>T-0 weeks</TD>
+ <TD>1.2.0</TD>
+ <TD>Production (feature) release</TD>
+</TR>
+</TABLE></DIV>
+
+
+<H2 CLASS="title"><A NAME="CODING">Coding Guidelines</A></H2>
+
+<P>These coding guidelines provide detailed information on source
+file formatting and documentation content and must be applied to
+all C and C++ source files provided with CUPS. Source code for
+other languages should conform to these guidelines as allowed by
+the language.</P>
+
+<H3>Source Files</H3>
+
+<P>All source files names shall be 16 characters or less in
+length to ensure compatibility with older UNIX filesystems.
+Source files containing functions shall have an extension of ".c"
+for ANSI C and ".cxx" for C++ source files. All other "include"
+files shall have an extension of ".h".</P>
+
+<P>The top of each source file shall contain a header giving the
+name of the file, the purpose or nature of the source file, the
+copyright and licensing notice, and the functions contained in
+the file. The file name and revision information is provided by
+the Subversion "&#36;Id$" tag:</P>
+
+<PRE CLASS="command">
+/*
+ * "&#36;Id$"
+ *
+ * Description of file contents.
+ *
+ * Copyright 2010 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * function1() - Description 1.
+ * function2() - Description 2.
+ * function3() - Description 3.
+ */
+</PRE>
+
+<P>For source files that are subject to the Apple OS-Developed
+Software exception, the following additional comment should
+appear after the contact information:</P>
+
+<PRE CLASS="command">
+ * This file is subject to the Apple OS-Developed Software exception.
+</PRE>
+
+<P>The bottom of each source file shall contain a trailer giving
+the name of the file using the Subversion "&#36;Id$" tag. The
+primary purpose of this is to mark the end of a source file; if
+the trailer is missing it is possible that code has been lost
+near the end of the file:</P>
+
+<PRE CLASS="command">
+/*
+ * End of "&#36;Id$".
+ */
+</PRE>
+
+<H3>Functions</H3>
+
+<P>Functions with a global scope shall have a lowercase prefix
+followed by capitalized words ("cupsDoThis", "cupsDoThat",
+"cupsDoSomethingElse", etc.) Private global functions shall begin
+with a leading underscore ("_cupsDoThis", "_cupsDoThat",
+etc.)</P>
+
+<P>Functions with a local scope shall be declared "static" and be
+lowercase with underscores between words ("do_this", "do_that",
+"do_something_else", etc.)</P>
+
+<P>Each function shall begin with a comment header describing
+what the function does, the possible input limits (if any), and
+the possible output values (if any), and any special information
+needed:</P>
+
+<PRE CLASS="command">
+/*
+ * 'do_this()' - Compute y = this(x).
+ *
+ * Notes: none.
+ */
+
+static float /* O - Inverse power value, 0.0 &lt;= y &lt;= 1.1 */
+do_this(float x) /* I - Power value (0.0 &lt;= x &lt;= 1.1) */
+{
+ ...
+ return (y);
+}
+</PRE>
+
+<P>Return/output values are indicated using an "O" prefix, input
+values are indicated using the "I" prefix, and values that are
+both input and output use the "IO" prefix for the corresponding
+in-line comment.</P>
+
+<P>The Mini-XML documentation generator also understands the following
+special text in the function description comment:</P>
+
+<UL>
+
+ <LI><CODE>@deprecated@</CODE> - Marks the function as
+ deprecated (not recommended for new development and
+ scheduled for removal)</LI>
+
+ <LI><CODE>@since CUPS <I>version</I>@</CODE> - Marks the
+ function as new in the specified version of CUPS.</LI>
+
+ <LI><CODE>@private@</CODE> - Marks the function as private.</LI>
+
+</UL>
+
+<H3>Variables</H3>
+
+<P>Variables with a global scope shall be capitalized
+("ThisVariable", "ThatVariable", "ThisStateVariable", etc.) The
+only exception to this rule shall be the CUPS interface library
+global variables which must begin with the prefix "cups"
+("cupsThisVariable", "cupsThatVariable", etc.) Global variables
+shall be replaced by function arguments whenever possible.</P>
+
+<P>Variables with a local scope shall be lowercase with
+underscores between words ("this_variable", "that_variable",
+etc.) Any local variables shared by functions within a source
+file shall be declared "static".</P>
+
+<P>Each variable shall be declared on a separate line and shall
+be immediately followed by a comment block describing the
+variable:</P>
+
+<PRE CLASS="command">
+int this_variable; /* The current state of this */
+int that_variable; /* The current state of that */
+</PRE>
+
+<H3>Types</H3>
+
+<P>All type names shall be lowercase with underscores between
+words and "_t" appended to the end of the name
+("cups_this_type_t", "cups_that_type_t", etc.) Type names must
+start with a prefix, typically "cups" or the name of the program,
+to avoid conflicts with system types. Private type names must
+start with an underscore ("_cups_this_t", "_cups_that_t",
+etc.)</P>
+
+<P>Each type shall have a comment block immediately after the
+typedef:</P>
+
+<PRE CLASS="command">
+typedef int cups_this_type_t; /* This type is for CUPS foobar options. */
+</PRE>
+
+<H3>Structures</H3>
+
+<P>All structure names shall be lowercase with underscores
+between words and "_s" appended to the end of the name
+("cups_this_s", "cups_that_s", etc.) Structure names must start
+with a prefix, typically "cups" or the name of the program, to
+avoid conflicts with system types. Private structure names must
+start with an underscore ("_cups_this_s", "_cups_that_s",
+etc.)</P>
+
+<P>Each structure shall have a comment block immediately after
+the struct and each member shall be documented in accordance with
+the variable naming policy above:</P>
+
+<PRE CLASS="command">
+struct cups_this_struct_s /* This structure is for CUPS foobar options. */
+{
+ int this_member; /* Current state for this */
+ int that_member; /* Current state for that */
+};
+</PRE>
+
+<H3>Constants</H3>
+
+<P>All constant names shall be uppercase with underscored between
+words ("CUPS_THIS_CONSTANT", "CUPS_THAT_CONSTANT", etc.)
+Constants must begin with an uppercase prefix, typically "CUPS"
+or the program name.</P>
+
+<P>Typed enumerations shall be used whenever possible to allow
+for type checking by the compiler.</P>
+
+<P>Comment blocks shall immediately follow each constant:</P>
+
+<PRE CLASS="command">
+enum
+{
+ CUPS_THIS_TRAY, /* This tray */
+ CUPS_THAT_TRAY /* That tray */
+};
+</PRE>
+
+<H3>Code</H3>
+
+<P>All source code shall utilize block comments within functions
+to describe the operations being performed by a group of
+statements; avoid putting a comment per line unless absolutely
+necessary, and then consider refactoring the code so that it is
+not necessary:</P>
+
+<PRE CLASS="command">
+/*
+ * Clear the state array before we begin...
+ */
+
+for (i = 0; i &lt; (sizeof(array) / sizeof(sizeof(array[0])); i ++)
+ array[i] = STATE_IDLE;
+
+/*
+ * Wait for state changes...
+ */
+
+do
+{
+ for (i = 0; i &lt; (sizeof(array) / sizeof(sizeof(array[0])); i ++)
+ if (array[i] != STATE_IDLE)
+ break;
+
+ if (i == (sizeof(array) / sizeof(array[0])))
+ sleep(1);
+} while (i == (sizeof(array) / sizeof(array[0])));
+</PRE>
+
+<H3>Indentation</H3>
+
+<P>All code blocks enclosed by brackets shall begin with the
+opening brace on a new line. The code then follows starting on a
+new line after the brace and is indented 2 spaces. The closing
+brace is then placed on a new line following the code at the
+original indentation:</P>
+
+<PRE CLASS="command">
+{
+ int i; /* Looping var */
+
+ /*
+ * Process foobar values from 0 to 999...
+ */
+
+ for (i = 0; i &lt; 1000; i ++)
+ {
+ do_this(i);
+ do_that(i);
+ }
+}
+</PRE>
+
+<P>Single-line statements following "do", "else", "for", "if",
+and "while" shall be indented 2 spaces as well. Blocks of code
+in a "switch" block shall be indented 4 spaces after each "case"
+and "default" case:</P>
+
+<PRE CLASS="command">
+switch (array[i])
+{
+ case STATE_IDLE :
+ do_this(i);
+ do_that(i);
+ break;
+ default :
+ do_nothing(i);
+ break;
+}
+</PRE>
+
+<H3>Spacing</H3>
+
+<P>A space shall follow each reserved word ("if", "while", etc.)
+Spaces shall not be inserted between a function name and the
+arguments in parenthesis.</P>
+
+<H3>Return Values</H3>
+
+<P>Parenthesis shall surround values returned from a function
+using "return":</P>
+
+<PRE CLASS="command">
+return (CUPS_STATE_IDLE);
+</PRE>
+
+<H3>Loops</H3>
+
+<P>Whenever convenient loops should count downward to zero to
+improve program performance:</P>
+
+<PRE CLASS="command">
+for (i = sizeof(array) / sizeof(array[0]) - 1; i >= 0; i --)
+ array[i] = CUPS_STATE_IDLE;
+</PRE>
+
+<H2 CLASS="title"><A NAME="MAKEFILES">Makefile Guidelines</A></H2>
+
+<P>The following is a guide to the makefile-based build system
+used by CUPS. These standards have been developed over the years
+to allow CUPS to be built on as many systems and environments as
+possible.</P>
+
+<H3>General Organization</H3>
+
+<P>The CUPS source code is organized functionally into a
+top-level makefile, include file, and subdirectories each with
+their own makefile and dependencies files. The ".in" files are
+template files for the <CODE>autoconf</CODE> software and are
+used to generate a static version of the corresponding file.</P>
+
+<H3>Makefile Documentation</H3>
+
+<P>Each make file must start with the standard CUPS header
+containing the Subversion "&#36;Id$" keyword, description of the
+file, and CUPS copyright and license notice:</P>
+
+<PRE CLASS="command">
+#
+# "&#36;Id$"
+#
+# Makefile for ...
+#
+# Copyright 2007 by Apple Inc.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+</PRE>
+
+<P>The end of each makefile must have a comment saying:</P>
+
+<PRE CLASS="command">
+#
+# End of "&#36;Id$".
+#
+</PRE>
+
+<P>The purpose of the trailer is to indicate the end of the
+makefile so that truncations are immediately obvious.</P>
+
+<H3>Portable Makefile Construction</H3>
+
+<P>CUPS uses a common subset of make program syntax to ensure
+that the software can be compiled "out of the box" on as many
+systems as possible. The following is a list of assumptions we
+follow when constructing makefiles:</P>
+
+<UL>
+
+ <LI><b>Targets</b>; we assume that the make program
+ supports the notion of simple targets of the form
+ "name:" that perform tab-indented commands that follow
+ the target, e.g.:
+ <PRE CLASS="command">
+target:
+&rarr; target commands</PRE></LI>
+
+ <LI><b>Dependencies</b>; we assume that the make program
+ supports recursive dependencies on targets, e.g.:
+ <PRE CLASS="command">
+target: foo bar
+&rarr; target commands
+
+foo: bla
+&rarr; foo commands
+
+bar:
+&rarr; bar commands
+
+bla:
+&rarr; bla commands</PRE></LI>
+
+ <LI><b>Variable Definition</b>; we assume that the make program
+ supports variable definition on the command-line or in the makefile
+ using the following form:
+ <PRE CLASS="command">
+name=value</PRE>
+
+ <LI><b>Variable Substitution</b>; we assume that the make program
+ supports variable substitution using the following forms:
+ <UL>
+ <LI><CODE>$(name)</CODE>; substitutes the value of "name",</LI>
+ <LI><CODE>($name:.old=.new)</CODE>; substitutes the value of "name"
+ with the filename extensions ".old" changed to ".new",</LI>
+ <LI><CODE>$(MAKEFLAGS)</CODE>; substitutes the
+ command-line options passed to the program
+ without the leading hyphen (-),</LI>
+ <LI><CODE>$$</CODE>; substitutes a single <CODE>$</CODE> character,</LI>
+ <LI><CODE>$&lt;</CODE>; substitutes the current source file or dependency, and</LI>
+ <LI><CODE>$@</CODE>; substitutes the current target name.</LI>
+ </UL></LI>
+
+ <LI><b>Suffixes</b>; we assume that the make program
+ supports filename suffixes with assumed dependencies, e.g.:
+ <PRE CLASS="command">
+.SUFFIXES: .c .o
+.c.o:
+&rarr; $(CC) $(CFLAGS) -o $@ -c $&lt;</PRE></LI>
+
+ <LI><b>Include Files</b>; we assume that the make program
+ supports the <CODE>include</CODE> directive, e.g.:
+ <PRE CLASS="command">
+include ../Makedefs
+include Dependencies</PRE></LI>
+
+ <LI><b>Comments</b>; we assume that comments begin with
+ a <CODE>#</CODE> character and proceed to the end of the
+ current line.</LI>
+
+ <LI><b>Line Length</b>; we assume that there is no
+ practical limit to the length of lines.</LI>
+
+ <LI><b>Continuation of long lines</b>; we assume that
+ the <CODE>\</CODE> character may be placed at the end of a
+ line to concatenate two or more lines in a
+ makefile to form a single long line.</LI>
+
+ <LI><b>Shell</b>; we assume a POSIX-compatible shell is
+ present on the build system.</LI>
+
+</UL>
+
+<H3>Standard Variables</H3>
+
+<P>The following variables are defined in the "Makedefs" file
+generated by the <CODE>autoconf</CODE> software:</P>
+
+<UL>
+
+ <LI><CODE>AR</CODE>; the library archiver command,</LI>
+
+ <LI><CODE>ARFLAGS</CODE>; options for the library archiver command,</LI>
+
+ <LI><CODE>BUILDROOT</CODE>; optional installation prefix,</LI>
+
+ <LI><CODE>MAN1EXT</CODE>; extension for man pages in section 1,</LI>
+
+ <LI><CODE>MAN3EXT</CODE>; extension for man pages in section 3,</LI>
+
+ <LI><CODE>MAN5EXT</CODE>; extension for man pages in section 5,</LI>
+
+ <LI><CODE>MAN7EXT</CODE>; extension for man pages in section 7,</LI>
+
+ <LI><CODE>MAN8DIR</CODE>; subdirectory for man pages in section 8,</LI>
+
+ <LI><CODE>MAN8EXT</CODE>; extension for man pages in section 8,</LI>
+
+ <LI><CODE>CC</CODE>; the C compiler command,</LI>
+
+ <LI><CODE>CFLAGS</CODE>; options for the C compiler command,</LI>
+
+ <LI><CODE>CXX</CODE>; the C++ compiler command,</LI>
+
+ <LI><CODE>CXXFLAGS</CODE>; options for the C++ compiler command,</LI>
+
+ <LI><CODE>DSOCOMMAND</CODE>; the shared library building command,</LI>
+
+ <LI><CODE>DSOFLAGS</CODE>; options for the shared library building command,</LI>
+
+ <LI><CODE>INSTALL</CODE>; the <CODE>install</CODE> command,</LI>
+
+ <LI><CODE>INSTALL_BIN</CODE>; the program installation command,</LI>
+
+ <LI><CODE>INSTALL_DATA</CODE>; the data file installation command,</LI>
+
+ <LI><CODE>INSTALL_DIR</CODE>; the directory installation command,</LI>
+
+ <LI><CODE>INSTALL_LIB</CODE>; the library installation command,</LI>
+
+ <LI><CODE>INSTALL_MAN</CODE>; the documentation installation command,</LI>
+
+ <LI><CODE>INSTALL_SCRIPT</CODE>; the shell script installation command,</LI>
+
+ <LI><CODE>LDFLAGS</CODE>; options for the linker,</LI>
+
+ <LI><CODE>LIBS</CODE>; libraries for all programs,</LI>
+
+ <LI><CODE>LN</CODE>; the <CODE>ln</CODE> command,</LI>
+
+ <LI><CODE>OPTIM</CODE>; common compiler optimization options,</LI>
+
+ <LI><CODE>RM</CODE>; the <CODE>rm</CODE> command,</LI>
+
+ <LI><CODE>SHELL</CODE>; the <CODE>sh</CODE> (POSIX shell) command,</LI>
+
+ <LI><CODE>STRIP</CODE>; the <CODE>strip</CODE> command,</LI>
+
+ <LI><CODE>bindir</CODE>; the binary installation directory,</LI>
+
+ <LI><CODE>datadir</CODE>; the data file installation directory,</LI>
+
+ <LI><CODE>exec_prefix</CODE>; the installation prefix for executable files,</LI>
+
+ <LI><CODE>libdir</CODE>; the library installation directory,</LI>
+
+ <LI><CODE>mandir</CODE>; the man page installation directory,</LI>
+
+ <LI><CODE>prefix</CODE>; the installation prefix for non-executable files, and</LI>
+
+ <LI><CODE>srcdir</CODE>; the source directory.</LI>
+
+</UL>
+
+<H3>Standard Targets</H3>
+
+<P>The following standard targets must be defined in each
+makefile:</P>
+
+<UL>
+
+ <LI><CODE>all</CODE>; creates all target programs,
+ libraries, and documentation files,</LI>
+
+ <LI><CODE>clean</CODE>; removes all target programs,
+ libraries, documentation files, and object files,</LI>
+
+ <LI><CODE>depend</CODE>; generates automatic dependencies
+ for any C or C++ source files (also see <A
+ HREF="#DEPEND_TARGET">"Dependencies"</A>),</LI>
+
+ <LI><CODE>distclean</CODE>; removes autoconf-generated files
+ in addition to those removed by the "clean" target,</LI>
+
+ <LI><CODE>install</CODE>; installs all distribution files in
+ their corresponding locations (also see <A
+ HREF="#INSTALL_TARGET">"Install/Uninstall Support"</A>), </LI>
+
+ <LI><CODE>uninstall</CODE>; removes all distribution files from
+ their corresponding locations (also see <A
+ HREF="#INSTALL_TARGET">"Install/Uninstall Support"</A>), and</LI>
+
+</UL>
+
+
+<H3>Object Files</H3>
+
+<P>Object files (the result of compiling a C or C++ source file)
+have the extension ".o".</P>
+
+<H3>Programs</H3>
+
+<P>Program files are the result of linking object files and
+libraries together to form an executable file. A typical
+program target looks like:</P>
+
+<PRE CLASS="command">
+program: $(OBJS)
+&rarr; echo Linking $@...
+&rarr; $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
+</PRE>
+
+<H3>Static Libraries</H3>
+
+<P>Static libraries have a prefix of "lib" and the extension
+".a". A typical static library target looks like:</P>
+
+<PRE CLASS="command">
+libname.a: $(OBJECTS)
+&rarr; echo Creating $@...
+&rarr; $(RM) $@
+&rarr; $(AR) $(ARFLAGS) $@ $(OBJECTS)
+&rarr; $(RANLIB) $@
+</PRE>
+
+<H3>Shared Libraries</H3>
+
+<P>Shared libraries have a prefix of "lib" and the extension
+".dylib", ".sl", ".so", or "_s.a" depending on the operating
+system. A typical shared library is composed of several targets
+that look like:</P>
+
+<PRE CLASS="command">
+libname.so: $(OBJECTS)
+&rarr; echo $(DSOCOMMAND) libname.so.$(DSOVERSION) ...
+&rarr; $(DSOCOMMAND) libname.so.$(DSOVERSION) $(OBJECTS)
+&rarr; $(RM) libname.so libname.so.$(DSOMAJOR)
+&rarr; $(LN) libname.so.$(DSOVERSION) libname.so.$(DSOMAJOR)
+&rarr; $(LN) libname.so.$(DSOVERSION) libname.so
+
+libname.sl: $(OBJECTS)
+&rarr; echo $(DSOCOMMAND) libname.sl.$(DSOVERSION) ...
+&rarr; $(DSOCOMMAND) libname.sl.$(DSOVERSION) $(OBJECTS)
+&rarr; $(RM) libname.sl libname.sl.$(DSOMAJOR)
+&rarr; $(LN) libname.sl.$(DSOVERSION) libname.sl.$(DSOMAJOR)
+&rarr; $(LN) libname.sl.$(DSOVERSION) libname.sl
+
+libname.dylib: $(OBJECTS)
+&rarr; echo $(DSOCOMMAND) libname.$(DSOVERSION).dylib ...
+&rarr; $(DSOCOMMAND) libname.$(DSOVERSION).dylib \
+&rarr; &rarr; -install_name $(libdir)/libname.$(DSOMAJOR).dylib \
+&rarr; &rarr; -current_version libname.$(DSOVERSION).dylib \
+&rarr; &rarr; -compatibility_version $(DSOMAJOR).0 \
+&rarr; &rarr; $(OBJECTS) $(LIBS)
+&rarr; $(RM) libname.dylib
+&rarr; $(RM) libname.$(DSOMAJOR).dylib
+&rarr; $(LN) libname.$(DSOVERSION).dylib libname.$(DSOMAJOR).dylib
+&rarr; $(LN) libname.$(DSOVERSION).dylib libname.dylib
+
+libname_s.a: $(OBJECTS)
+&rarr; echo $(DSOCOMMAND) libname_s.o ...
+&rarr; $(DSOCOMMAND) libname_s.o $(OBJECTS) $(LIBS)
+&rarr; echo $(LIBCOMMAND) libname_s.a libname_s.o
+&rarr; $(RM) $@
+&rarr; $(LIBCOMMAND) libname_s.a libname_s.o
+&rarr; $(CHMOD) +x libname_s.a
+</PRE>
+
+
+<H3>Dependencies</H3>
+
+<P>Static dependencies are expressed in each makefile following the
+target, for example:</P>
+
+<PRE CLASS="command">
+foo: bar
+</PRE>
+
+<P>Static dependencies shall only be used when it is not
+possible to automatically generate them. Automatic dependencies
+are stored in a file named "Dependencies" and included at the
+end of the makefile. The following "depend" target rule shall be
+used to create the automatic dependencies:
+
+<PRE CLASS="command">
+depend:
+&rarr; $(MAKEDEPEND) -Y -I.. -f Dependencies $(OBJS:.o=.c)
+</PRE>
+
+<P>We only regenerate the automatic dependencies on a Linux
+system and express any non-Linux dependencies statically in the
+makefile.</P>
+
+<H3><A NAME="TARGET_INSTALL">Install/Uninstall Support</A></H3>
+
+<P>All makefiles must contain install and uninstall rules which
+install or remove the corresponding software. These rules must
+use the <CODE>$(BUILDROOT)</CODE> variable as a prefix to any
+installation directory so that CUPS can be installed in a
+temporary location for packaging by programs like
+<CODE>rpmbuild</CODE>.</P>
+
+<P>The <CODE>$(INSTALL_BIN)</CODE>, <CODE>$(INSTALL_DATA)</CODE>,
+<CODE>$(INSTALL_DIR)</CODE>, <CODE>$(INSTALL_LIB)</CODE>,
+<CODE>$(INSTALL_MAN)</CODE>, and <CODE>$(INSTALL_SCRIPT)</CODE>
+variables must be used when installing files so that the proper
+ownership and permissions are set on the installed files.</P>
+
+<P>The <CODE>$(RANLIB)</CODE> command must be run on any static
+libraries after installation since the symbol table is
+invalidated when the library is copied on some platforms.</P>
+
+</BODY>
+</HTML>
diff --git a/doc/help/spec-command.html b/doc/help/spec-command.html
new file mode 100644
index 000000000..af201cb55
--- /dev/null
+++ b/doc/help/spec-command.html
@@ -0,0 +1,218 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Specifications -->
+<head>
+ <title>CUPS Command File Format</title>
+ <meta name='keywords' content='Programming, CUPS Command File Format'>
+ <link rel='stylesheet' type='text/css' href='../cups-printable.css'>
+</head>
+<body>
+<!--
+ "$Id: spec-command.html 9727 2011-04-28 21:20:12Z mike $"
+
+ CUPS command file format specification for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<H1 CLASS="title">CUPS Command File Format</H1>
+
+<h2 class='title'><a name='INTRODUCTION'>Introduction</a></h2>
+
+<p>This specification describes the CUPS command file format
+(application/vnd.cups-command) which is used to send printer
+maintenance commands to a printer in a device-independent way.
+The current specification supports basic maintenance functions
+such as head cleaning and self-test pages and query functions
+such as auto-configure, report supply levels, and report status.</p>
+
+<p>Printer drivers advertise support for the CUPS command file
+format by providing a filter for the
+<var>application/vnd.cups-command</var> file type. Applications
+can determine if a printer supports printing of CUPS command
+files by checking the <code>printer-type</code> attribute for the
+<code>CUPS_PRINTER_COMMANDS</code> capability bit.</p>
+
+<p>In addition, the PPD file for a printer can contain a
+<code>cupsCommands</code> keyword that provides a list of supported
+commands separated by spaces, for example:</p>
+
+<pre class='command'>
+*cupsCommand: "AutoConfigure Clean PrintSelfTestPage ReportLevels ReportStatus"
+</pre>
+
+<p>If no <code>cupsCommands</code> keyword is provided, the command filter
+must support <a href='#AutoConfigure'><code>AutoConfigure</code></a>,
+<a href='#Clean'><code>Clean</code></a>,
+<a href='#PrintSelfTestPage'><code>PrintSelfTestPage</code></a>,
+and <a href='#ReportLevels'><code>ReportLevels</code></a>. The scheduler also
+provides the <code>printer-commands</code> attribute containing the list of
+supported commands.</p>
+
+
+<h2 class='title'><a name='SYNTAX'>File Syntax</a></h2>
+
+<p>CUPS command files are ASCII text files. The first line of a
+CUPS command file MUST contain:</p>
+
+<pre class='command'>
+#CUPS-COMMAND
+</pre>
+
+<p>After that, each line is either a command or a comment.
+Comments begin with the # character, e.g.:</p>
+
+<pre class='command'>
+# This is a comment
+</pre>
+
+<p>Commands are any sequence of letters, numbers, and punctuation characters
+optionally followed by parameters separated by whitespace, e.g.:</p>
+
+<pre class='command'>
+Clean all
+PrintSelfTestPage
+</pre>
+
+<p>Command names are case-insensitive, so "PRINTSELFTESTPAGE",
+"printselftestpage", and "PrintSelfTestPage" are equivalent. Vendor-specific
+commands should use a domain name prefix, e.g.:</p>
+
+<pre class='command'>
+com.vendor.foo
+com.vendor.bar param param2 ... paramN
+</pre>
+
+
+<h2 class='title'><a name='COMMANDS'>Standard Commands</a></h2>
+
+<p>The following are the standard commands supported by the format. The only
+required command is
+<a href='#PrintSelfTestPage'><code>PrintSelfTestPage</code></a>.</p>
+
+
+<h3><a name='AutoConfigure'>AutoConfigure</a></h3>
+
+<p class='summary'>AutoConfigure</p>
+
+<p>The <code>AutoConfigure</code> command updates the printer's PPD file
+and driver state information to reflect the current configuration of the
+printer. There are no arguments for this command.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+#CUPS-COMMAND
+AutoConfigure
+</pre>
+
+
+<h3><a name='Clean'>Clean</a></h3>
+
+<p class='summary'>Clean <i>colorname</i></p>
+
+<p>The <code>Clean</code> command performs a standard print head cleaning. The
+"colorname" parameter specifies which color or head to clean. If a printer does
+not support cleaning of individual colors or cartridges, then all colors are
+cleaned. Command filters MUST support the "all" colorname. Other standard color
+names include "black", "color", "photo", "cyan", "magenta", "yellow",
+"light-cyan", "light-magenta", "light-black", "light-gray", and "dark-gray".</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+#CUPS-COMMAND
+Clean all
+</pre>
+
+
+<h3><a name='PrintAlignmentPage'>PrintAlignmentPage</a></h3>
+
+<p class='summary'>PrintAlignmentPage pass</p>
+
+<p>The <code>PrintAlignmentPage</code> command prints a head alignment page on
+the printer. The "pass" parameter provides a pass number from 1 to N. The number
+of passes is device-dependent.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+#CUPS-COMMAND
+PrintAlignmentPage 1
+</pre>
+
+
+<h3><a name='PrintSelfTestPage'>PrintSelfTestPage</a></h3>
+
+<p class='summary'>PrintSelfTestPage</p>
+
+<p>The <code>PrintSelfTestPage</code> command prints a self-test page on the
+printer. Typically this page shows whether all jets on a print head are
+functioning and that the print feed mechanisms are working properly.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+#CUPS-COMMAND
+PrintSelfTestPage
+</pre>
+
+
+<h3><a name='ReportLevels'>ReportLevels</a></h3>
+
+<p class='summary'>ReportLevels</p>
+
+<p>The <code>ReportLevels</code> command queries the supply levels on a printer
+and reports "marker-colors", "marker-levels", "marker-names", and
+"marker-types" attributes using "ATTR:" messages sent to the scheduler. This
+command should also report the current printer status using "STATE:" messages
+like the <a href='#ReportStatus'><code>ReportStatus</code></a> command.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+#CUPS-COMMAND
+ReportLevels
+</pre>
+
+
+<h3><a name='ReportStatus'>ReportStatus</a></h3>
+
+<p class='summary'>ReportStatus</p>
+
+<p>The <code>ReportStatus</code> command queries the printer for its current
+status and reports it using "STATE:" messages sent to the scheduler.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+#CUPS-COMMAND
+ReportLevels
+</pre>
+
+
+<h3><a name='SetAlignment'>SetAlignment</a></h3>
+
+<p class='summary'>SetAlignment pass value ... valueN</p>
+
+<p>The <code>SetAlignment</code> command sets print head alignment values. The
+"pass" parameter is a number from 1 to N. All parameters are
+device-dependent.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+#CUPS-COMMAND
+SetAlignment 1 14
+</pre>
+
+
+</body>
+</html>
diff --git a/doc/help/spec-design.html b/doc/help/spec-design.html
new file mode 100644
index 000000000..28a14eb31
--- /dev/null
+++ b/doc/help/spec-design.html
@@ -0,0 +1,184 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<!-- SECTION: Specifications -->
+<HEAD>
+ <TITLE>CUPS Design Description</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">CUPS Design Description</H1>
+
+<P>This design description documents the overall organization of CUPS. The purpose is not to provide a line-by-line description of the CUPS source code, but rather to describe the overall architecture and location of key pieces so that developers can more easily understand the underlying operation of CUPS.</P>
+
+<H2 CLASS="title"><A NAME="INTRO">Introduction</A></H2>
+
+<P>Like most printing systems, CUPS is designed around a central print scheduling process that dispatches print jobs, processes administrative commands, provides printer status information to local and remote programs, and informs users as needed. <A HREF="#FIGURE1">Figure 1</A> shows the basic organization of CUPS.</P>
+
+<H3>Scheduler</H3>
+
+<P>The scheduler is a HTTP/1.1 and IPP/2.1 server application that manages HTTP and IPP requests, printers, classes, jobs, subscriptions, and notifications on the system. HTTP is used for normal web browser services as well as IPP operation messages passed via HTTP POST requests with the <CODE>application/ipp</CODE> content type. The scheduler uses a series of helper applications based on the Common Gateway Interface ("CGI") to provide dynamic web interfaces and can be configured to run additional site-specific programs or scripts for the web interface.</P>
+
+<P>The scheduler is designed as a traditional single-threaded server process which runs external processes to do longer-term operations such as printing, notification, device/driver enumeration, and remote printer monitoring. External processes are normally run as a non-privileged account ("lp") and, on some platforms, with additional restrictions that limit what the processes are allowed to do.</P>
+
+<P>The maximum number of simultaneous clients and print jobs that can be supported is primarily limited by the available server memory, file descriptors, and CPU - the scheduler itself imposes no hard limits.</P>
+
+<DIV CLASS="figure"><TABLE SUMMARY="CUPS Block Diagram">
+<CAPTION>Figure 1: <A NAME="FIGURE1">CUPS Block Diagram</A></CAPTION>
+<TR><TD ALIGN="CENTER"><IMG SRC="../images/cups-block-diagram.png"
+WIDTH="768" HEIGHT="768" ALT="CUPS Block Diagram"></TD></TR>
+</TABLE></DIV>
+
+<H4>Config Files</H4>
+
+<P>The scheduler uses several configuration files to store the server settings (<A HREF="ref-cupsd-conf.html">cupsd.conf</A>), available classes (<A HREF="ref-classes-conf.html">classes.conf</A>), available printers (<A HREF="ref-printers-conf.html">printers.conf</A>), current notification subscriptions (<A HREF="ref-subscriptions-conf.html">subscriptions.conf</A>), and supported file types and filters (<A HREF="man-mime.types.html">mime.types</A>, <A HREF="man-mime.convs.html">mime.convs</A>). In addition, PostScript Printer Description ("PPD") files or interface scripts are associated with each printer, and the scheduler has cache files for remote printers, PPD files, and current jobs to optimize the scheduler's startup speed and availability.</P>
+
+<H4>Job Files</H4>
+
+<P>The scheduler stores job files in a <EM>spool directory</EM>, typically <VAR>/var/spool/cups</VAR>. Two types of files will be found in the spool directory: <EM>control files</EM> starting with the letter "c" ("c00001", "c99999", "c100000", etc.) and <EM>data files</EM> starting with the letter "d" ("d00001-001", "d99999-001", "d100000-001", etc.) Control files are IPP messages based on the original IPP Print-Job or Create-Job messages, while data files are the original print files that were submitted for printing. There is one control file for every job known to the system and 0 or more data files for each job.
+
+<p>Control files are normally cleaned out after the 500th job is submitted, while data files are removed immediately after a job has successfully printed. Both behaviors can be configured.</P>
+
+<H4>Log Files</H4>
+
+<P>The scheduler keeps three kinds of log files which are normally stored in the <VAR>/var/log/cups</VAR> directory. The <A HREF="ref-access_log.html">access_log</A> file lists every HTTP and IPP request that is processed by the scheduler. The <A HREF="ref-error_log.html">error_log</A> file contains messages from the scheduler and its helper applications that can be used
+to track down problems. The <A HREF="ref-page_log.html">page_log</A> file lists every page that is printed, allowing for simple print accounting.</P>
+
+<P>Log files are rotated automatically by the scheduler when they reach the configured size limit, by default 1MB. If the limit is set to 0 then no rotation is performed in the scheduler - this mode is often used by Linux distributions so they can use the <B>logrotated(8)</B> program to rotate them instead.</P>
+
+<H3>Berkeley Commands</H3>
+
+<P>CUPS provides the Berkeley <A HREF="man-lpc.html">lpc(8)</A>, <A HREF="man-lpq.html">lpq(1)</A>, <A HREF="man-lpr.html">lpr(1)</A>, and <A HREF="man-lprm.html">lprm(1)</A> commands. In general, they function identically to the original Berkeley commands with the following exceptions:</P>
+
+<OL>
+
+ <LI>The <B>lpc</B> command currently only supports the "status" sub-command.</LI>
+
+ <LI>The <B>lpr</B> command does not support the format modifier options "1" (TROFF font set 1), "2" (TROFF font set 2), "3" (TROFF font set 3), "4" (TROFF font set 4), "c" (CIFPLOT), "d" (DVI), "f" (FORTRAN), "g" (GNU plot), "i" (indentation), "n" (Ditroff), "r" (Sun raster), "t" (Troff), or "w" (width), as they do not map to the IPP MIME media type based document formats.</LI>
+
+</OL>
+
+<H3>System V Commands</H3>
+
+<P>CUPS provides the System V <A HREF="man-cancel.html">cancel(1)</A>, <A HREF="man-lp.html">lp(1)</A>, <A HREF="man-lpadmin.html">lpadmin(8)</A>, <A HREF="man-lpmove.html">lpmove(8)</A>, and <A HREF="man-lpstat.html">lpstat(1)</A> commands. In general, they function identically to the original System V commands with the following exceptions:</P>
+
+<OL>
+
+ <LI>All commands may ask for a password; the System V print spooler requires root access to perform administration tasks, while CUPS allows for more flexible configurations.</LI>
+
+ <LI>The <B>lpadmin</B> command does not implement the Solaris "-A" (alert), "-F" (fault recovery), "-M" (mount form/wheel), "-P" (paper list), "-S" (print wheels), "-T" (type list), "-U" (dialer info), "-W" (wait), "-f" (form name), "-l" (content-type list), "-s" (remote printer), or "-t" (number of trays) options.</LI>
+
+</OL>
+
+<H3>CUPS Commands</H3>
+
+<P>CUPS provides the <A HREF="man-cupsaccept.html">cupsaccept(8)</A>, <A HREF="man-cupsaddsmb.html">cupsaddsmb(8)</A>, <A HREF="man-cupsenable.html">cupsdisable(8)</A>, <A HREF="man-cupsenable.html">cupsenable(8)</A>, <A HREF="man-cupsaccept.html">cupsreject(8)</A>, <A HREF="man-cupstestppd.html">cupstestppd(1)</A>, <A HREF="man-lpinfo.html">lpinfo(8)</A>, and <A HREF="man-lppasswd.html">lppasswd(1)</A> commands. The <B>cupsaccept</B>, <B>cupsdisable</B>, <B>cupsenable</B>, and <B>cupsreject</B> commands correspond to the System V <B>accept</B>, <B>disable</B>, <B>enable</B>, and <B>reject</B> commands but have been renamed to avoid confusion and conflicts with the <B>bash(1)</B> internal <B>enable</B> command of the same name.</P>
+
+<H3>LPD Support</H3>
+
+<P>LPD client support is provided via the <A HREF="man-cups-lpd.html">cups-lpd(8)</A> program. Incoming LPD requests are accepted on TCP port 515 by the local <B>inetd(8)</B>, <B>launchd(8)</B>, or <B>xinetd(8)</B> process and forwarded to the <B>cups-lpd</B> program for conversion to the corresponding IPP request(s).</P>
+
+<P>The <B>cups-lpd</B> program conforms, for the most part, to RFC 1179: Line Printer Daemon Protocol, but does not enforce the privileged source port restriction specified in that document. In addition, the banner page and output format options are usually overridden via command-line options to the <B>cups-lpd</B> program when it is invoked by the corresponding super-daemon program.</P>
+
+<H3>Web Interface</H3>
+
+<P>The web interface is supported by five CGI programs. <A HREF="#TABLE1">Table 1</A> describes the purpose of each of the programs.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="CGI Programs">
+<CAPTION>Table 1: <A NAME="TABLE1">CGI Programs</A></CAPTION>
+<THEAD>
+<TR>
+ <TH>Program</TH>
+ <TH>Location</TH>
+ <TH>Description</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD>admin.cgi</TD>
+ <TD>/admin</TD>
+ <TD>Provides all of the administrative functions</TD>
+</TR>
+<TR>
+ <TD>classes.cgi</TD>
+ <TD>/classes</TD>
+ <TD>Lists classes and provides class management functions</TD>
+</TR>
+<TR>
+ <TD>help.cgi</TD>
+ <TD>/help</TD>
+ <TD>Provides access to online help documents</TD>
+</TR>
+<TR>
+ <TD>jobs.cgi</TD>
+ <TD>/jobs</TD>
+ <TD>Lists jobs and provides job management functions</TD>
+</TR>
+<TR>
+ <TD>printers.cgi</TD>
+ <TD>/printers</TD>
+ <TD>Lists printers and provides printer management functions</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+<H3>Notifiers</H3>
+
+<P>Notifiers (<A HREF="man-notifier.html">notifier(7)</A>) provide the means for sending asynchronous event notifications from the scheduler. Notifiers are executed with the recipient information on the command-line and the event data on the standard input. For example:</P>
+
+<PRE CLASS="command">
+CUPS_SERVERBIN/notifier/foo recipient user-data
+</PRE>
+
+<P>CUPS includes two notifiers: <B>mailto</B> to provide SMTP-based email notifications and <B>rss</B> to provide Really Simple Syndication ("RSS") notifications from the scheduler. Additional notifiers can be installed in the <VAR>notifier</VAR> directory as needed to support other methods.</P>
+
+<H3>Filters</H3>
+
+<P>Filters (<A HREF="man-filter.html">filter(7)</A>) convert job files into a printable format. Multiple filters are run, as needed, to convert from the job file format to the printable format. A filter program reads from the standard input or from a file if a filename is supplied. All filters must support a common set of options including printer name, job ID, username, job title, number of copies, and job options. All output is sent to the standard output.</P>
+
+<P>CUPS provides filters for printing text, PostScript, PDF, HP-GL/2, and many types of image files. CUPS also provides printer driver filters for HP-PCL, ESC/P, and several types of label printers. Additional filters can be registered with CUPS via mime.convs and PPD files.</P>
+
+<H3>Port Monitors</H3>
+
+<P>Port monitors handle the device- and channel-specific data formatting for a printer. Port monitors use the same interface as filters.</P>
+
+<P>CUPS includes two port monitors: the <B>bcp</B> port monitor which supports the PostScript Binary Communications Protocol ("BCP") and the <b>tbcp</b> port monitor which supports the PostScript Tagged Binary Communications Protocol ("TBCP"). Additional port monitors can be registered in PPD files.</P>
+
+<H3>Backends</H3>
+
+<P>Backends (<A HREF="man-backend.html">backend(7)</A>) send print data to the printer and enumerate available printers/devices as needed. Backends use the same interface as filters.</P>
+
+<P>CUPS includes backends for AppSocket (JetDirect), IPP, LPD, parallel, SCSI, serial, and USB connections. Additional backends can be added as needed without additional configuration.</P>
+
+
+<H2 CLASS="title"><A NAME="PROGRAMMING">Programming Interfaces</A></H2>
+
+<P>CUPS makes use of several general-purpose libraries to provide its printing services. Unlike the rest of CUPS, the libraries are provided under the terms of the GNU LGPL so they may be used by non-GPL applications.</P>
+
+<H3>CUPS Library (libcups)</H3>
+
+<P>The CUPS library contains all of the core HTTP and IPP communications code as well as convenience functions for queuing print jobs, getting printer information, accessing resources via HTTP and IPP, and manipulating PPD files. The scheduler and all commands, filters, and backends use this library.</P>
+
+<H3>CUPS CGI Library (libcupscgi)</H3>
+
+<P>The CUPS CGI library provides all of the web interface support functions. It is used by the CGI programs to provide the CUPS web interface.</P>
+
+<H3>CUPS Driver Library (libcupsdriver)</H3>
+
+<P>The CUPS driver library provides access to the dithering, color conversion, and helper functions used by the CUPS sample printer drivers.</P>
+
+<H3>CUPS Imaging Library (libcupsimage)</H3>
+
+<P>The CUPS imaging library provides functions for managing large images, doing colorspace conversion and color management, scaling images for printing, and managing raster page streams. It is used by the CUPS image file filters, the PostScript RIP, and all raster printers drivers.</P>
+
+<H3>CUPS MIME Library (libcupsmime)</H3>
+
+<P>The CUPS MIME library provides file typing and conversion functions and is used by the scheduler and <A HREF="man-cupsfilter.html">cupsfilter(8)</A> command to auto-type and convert print files to a printable format.</P>
+
+<H3>CUPS PPD Compiler Library (libcupsppdc)</H3>
+
+<P>The CUPS PPD compiler library provides access to driver information files and is used by the PPD compiler tools as well as the <A HREF="man-cups-driverd.html">cups-driverd(8)</A> helper program to generate PPD files and message catalogs for localization.</P>
+
+
+</BODY>
+</HTML>
diff --git a/doc/help/spec-ipp.html b/doc/help/spec-ipp.html
new file mode 100644
index 000000000..98bc05748
--- /dev/null
+++ b/doc/help/spec-ipp.html
@@ -0,0 +1,2879 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Specifications -->
+<head>
+ <title>CUPS Implementation of IPP</title>
+ <meta name='keywords' content='Programming, Internet Printing Protocol'>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</head>
+<body>
+<!--
+ "$Id: spec-ipp.html 9727 2011-04-28 21:20:12Z mike $"
+
+ CUPS IPP specification for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2007 by Easy Software Products.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<H1 CLASS="title">CUPS Implementation of IPP</H1>
+
+<h2 class='title'><a name='INTRODUCTION'>Introduction</a></h2>
+
+<p>CUPS implements IPP/2.1 and the operations and attributes
+defined in the "IPP: Job and Printer Set Operations", "IPP/1.1:
+Output-bin Attribute Extension", and "IPP/1.1: finishings
+'fold',' trim', and 'bale' attribute values extension"
+specifications.</p>
+
+<p>CUPS also provides 16 new operations and many new attributes
+to support multiple IPP printers and printer classes on a single
+host.</p>
+
+<h3 class='title'><a name='IPP_URIS'>IPP URIs</a></h3>
+
+<p>CUPS supports the "http", "https", and "ipp" schemes. The
+following resource names are used:</p>
+
+<dl>
+
+ <dt><tt>scheme://hostname:port/</tt></dt>
+
+ <dd>Can be used for all "get" operations and for server
+ subscriptions.</dd>
+
+ <dt><tt>scheme://hostname:port/admin/</tt></dt>
+
+ <dd>Used for all administrative operations.</dd>
+
+ <dt><tt>scheme://hostname:port/classes/name</tt></dt>
+
+ <dd>Specifies a printer class.</dd>
+
+ <dt><tt>scheme://hostname:port/jobs/id</tt></dt>
+
+ <dd>Specifies a job.</dd>
+
+ <dt><tt>scheme://hostname:port/printers/name</tt></dt>
+
+ <dd>Specifies a printer.</dd>
+
+</dl>
+
+<p>So a typical printer URI would be
+"ipp://foo.bar.com/printers/LaserJet". In addition, the CUPS
+server also supports normal browser access via
+"http://hostname:port/" and "https://hostname:port/".</p>
+
+<h3 class='title'><a name='IPP_OPERATIONS'>CUPS IPP Operations</a></h3>
+
+<p>CUPS provides 16 extension operations in addition to most of the
+standard IPP and registered extension operations:
+
+<div class='table'><table align='center' border='1' width='80%'
+summary='Supported Operations'>
+<thead>
+<tr>
+ <TH VALIGN="TOP">Operation Name</th>
+ <TH VALIGN="TOP">CUPS</th>
+ <TH VALIGN="TOP">Code</th>
+ <TH VALIGN="TOP">Brief Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td><a href='#PRINT_JOB'>Print-Job</a></td>
+ <td>1.0</td>
+ <td>0x0002</td>
+ <td>Print a file.</td>
+</tr>
+<tr>
+ <td>Validate-Job</td>
+ <td>1.0</td>
+ <td>0x0004</td>
+ <td>Validate job attributes.</td>
+</tr>
+<tr>
+ <td><a href='#CREATE_JOB'>Create-Job</a></td>
+ <td>1.1</td>
+ <td>0x0005</td>
+ <td>Create a print job.</td>
+</tr>
+<tr>
+ <td>Send-Document</td>
+ <td>1.1</td>
+ <td>0x0006</td>
+ <td>Send a file for a print job.</td>
+</tr>
+<tr>
+ <td><a href='#CANCEL_JOB'>Cancel-Job</a></td>
+ <td>1.0</td>
+ <td>0x0008</td>
+ <td>Cancel a print job.</td>
+</tr>
+<tr>
+ <td>Get-Job-Attributes</td>
+ <td>1.0</td>
+ <td>0x0009</td>
+ <td>Get job attributes.</td>
+</tr>
+<tr>
+ <td>Get-Jobs</td>
+ <td>1.0</td>
+ <td>0x000A</td>
+ <td>Get all jobs.</td>
+</tr>
+<tr>
+ <td>Get-Printer-Attributes</td>
+ <td>1.0</td>
+ <td>0x000B</td>
+ <td>Get printer attributes.</td>
+</tr>
+<tr>
+ <td>Hold-Job</td>
+ <td>1.1</td>
+ <td>0x000C</td>
+ <td>Hold a job for printing.</td>
+</tr>
+<tr>
+ <td>Release-Job</td>
+ <td>1.1</td>
+ <td>0x000D</td>
+ <td>Release a job for printing.</td>
+</tr>
+<tr>
+ <td>Restart-Job</td>
+ <td>1.1</td>
+ <td>0x000E</td>
+ <td>Restarts a print job.</td>
+</tr>
+<tr>
+ <td>Pause-Printer</td>
+ <td>1.0</td>
+ <td>0x0010</td>
+ <td>Pause printing on a printer.</td>
+</tr>
+<tr>
+ <td>Resume-Printer</td>
+ <td>1.0</td>
+ <td>0x0011</td>
+ <td>Resume printing on a printer.</td>
+</tr>
+<tr>
+ <td><a href='#PURGE_JOBS'>Purge-Jobs</a></td>
+ <td>1.0</td>
+ <td>0x0012</td>
+ <td>Purge all jobs.</td>
+</tr>
+<tr>
+ <td><a href='#SET_JOB_ATTRIBUTES'>Set-Job-Attributes</a></td>
+ <td>1.1</td>
+ <td>0x0014</td>
+ <td>Set attributes for a pending or held job.</td>
+</tr>
+<tr>
+ <td><a href='#CREATE_PRINTER_SUBSCRIPTION'>Create-Printer-Subscription</a></td>
+ <td>1.2</td>
+ <td>0x0016</td>
+ <td>Creates a subscription associated with a printer or the server.</td>
+</tr>
+<tr>
+ <td>Create-Job-Subscription</td>
+ <td>1.2</td>
+ <td>0x0017</td>
+ <td>Creates a subscription associated with a job.</td>
+</tr>
+<tr>
+ <td>Get-Subscription-Attributes</td>
+ <td>1.2</td>
+ <td>0x0018</td>
+ <td>Gets the attributes for a subscription.</td>
+</tr>
+<tr>
+ <td>Get-Subscriptions</td>
+ <td>1.2</td>
+ <td>0x0019</td>
+ <td>Gets the attributes for zero or more subscriptions.</td>
+</tr>
+<tr>
+ <td>Renew-Subscription</td>
+ <td>1.2</td>
+ <td>0x001A</td>
+ <td>Renews a subscription.</td>
+</tr>
+<tr>
+ <td>Cancel-Subscription</td>
+ <td>1.2</td>
+ <td>0x001B</td>
+ <td>Cancels a subscription.</td>
+</tr>
+<tr>
+ <td>Get-Notifications</td>
+ <td>1.2</td>
+ <td>0x001C</td>
+ <td>Get notification events for <tt>ippget</tt> subscriptions.</td>
+</tr>
+<tr>
+ <td>Enable-Printer</td>
+ <td>1.2</td>
+ <td>0x0022</td>
+ <td>Accepts jobs on a printer.</td>
+</tr>
+<tr>
+ <td>Disable-Printer</td>
+ <td>1.2</td>
+ <td>0x0023</td>
+ <td>Rejects jobs on a printer.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_GET_DEFAULT'>CUPS-Get-Default</a></td>
+ <td>1.0</td>
+ <td>0x4001</td>
+ <td>Get the default destination.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_GET_PRINTERS'>CUPS-Get-Printers</a></td>
+ <td>1.0</td>
+ <td>0x4002</td>
+ <td>Get all of the available printers.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_ADD_MODIFY_PRINTER'>CUPS-Add-Modify-Printer</a></td>
+ <td>1.0</td>
+ <td>0x4003</td>
+ <td>Add or modify a printer.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_DELETE_PRINTER'>CUPS-Delete-Printer</a></td>
+ <td>1.0</td>
+ <td>0x4004</td>
+ <td>Delete a printer.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_GET_CLASSES'>CUPS-Get-Classes</a></td>
+ <td>1.0</td>
+ <td>0x4005</td>
+ <td>Get all of the available printer classes.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_ADD_MODIFY_CLASS'>CUPS-Add-Modify-Class</a></td>
+ <td>1.0</td>
+ <td>0x4006</td>
+ <td>Add or modify a printer class.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_DELETE_CLASS'>CUPS-Delete-Class</a></td>
+ <td>1.0</td>
+ <td>0x4007</td>
+ <td>Delete a printer class.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_ACCEPT_JOBS'>CUPS-Accept-Jobs</a></td>
+ <td>1.0</td>
+ <td>0x4008</td>
+ <td>Accept jobs on a printer or printer class.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_REJECT_JOBS'>CUPS-Reject-Jobs</a></td>
+ <td>1.0</td>
+ <td>0x4009</td>
+ <td>Reject jobs on a printer or printer class.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_SET_DEFAULT'>CUPS-Set-Default</a></td>
+ <td>1.0</td>
+ <td>0x400A</td>
+ <td>Set the default destination.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_GET_DEVICES'>CUPS-Get-Devices</a></td>
+ <td>1.1</td>
+ <td>0x400B</td>
+ <td>Get all of the available devices.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_GET_PPDS'>CUPS-Get-PPDs</a></td>
+ <td>1.1</td>
+ <td>0x400C</td>
+ <td>Get all of the available PPDs.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_MOVE_JOB'>CUPS-Move-Job</a></td>
+ <td>1.1</td>
+ <td>0x400D</td>
+ <td>Move a job to a different printer.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_AUTHENTICATE_JOB'>CUPS-Authenticate-Job</a></td>
+ <td>1.2</td>
+ <td>0x400E</td>
+ <td>Authenticate a job for printing.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_GET_PPD'>CUPS-Get-PPD</a></td>
+ <td>1.3</td>
+ <td>0x400F</td>
+ <td>Get a PPD file.</td>
+</tr>
+<tr>
+ <td><a href='#CUPS_GET_DOCUMENT'>CUPS-Get-Document</a></td>
+ <td>1.4</td>
+ <td>0x4027</td>
+ <td>Get a document file from a job.</td>
+</tr>
+</tbody>
+</table></div>
+
+<h2 class='title'><a name='OPERATIONS'>Operations</a></h2>
+
+<p>The following sections describe the operations supported by CUPS.
+In the interest of brevity, operations which use only the standard
+IPP attributes are not described.
+
+<h3 class='title'><a name='PRINT_JOB'>Print-Job Operation</a></h3>
+
+<p>The Print-Job operation (0x0002) prints a file.
+
+<h4>Print-Job Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+Print-Job request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri):
+
+ <dd>The client MUST supply a URI for the specified printer.
+
+</dl>
+
+<p>Group 2: Job Template Attributes
+
+<dl>
+
+ <dt>"auth-info" (1setOf text(MAX)):<span class='info'>CUPS 1.3/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies one or more authentication values as specified by the "auth-info-required" attribute.
+
+ <dt>"job-billing" (text(MAX)):<span class='info'>CUPS 1.1</span>
+
+ <dd>The client OPTIONALLY supplies a billing string that is logged
+ with the page accounting information.
+
+ <dt>"job-sheets" (1setof type3 keyword | name(MAX)):<span class='info'>CUPS 1.1</span>
+
+ <dd>The client OPTIONALLY supplies one or two banner pages that
+ are printed before and after any files in the print job. The
+ name of "none" is reserved to indicate that no banner page
+ should be printed. If the client does not specify this
+ attribute then the value of the "job-sheets-default" printer
+ object attribute is used.
+
+ <blockquote><b>Note:</b> Standard IPP only allows
+ specification of a single job-sheets attribute
+ value.</blockquote>
+
+ <dt>"media" (1setof type3 keyword | name(MAX)):
+
+ <dd>The client OPTIONALLY supplies one or more media attributes
+ specifying the size, type, source, and color of the output
+ media. If the client does not specify this attribute then the
+ value of the "media-default" printer object attribute is used.
+
+ <blockquote><b>Note:</b> Standard IPP only allows
+ specification of a single media attribute
+ value.</blockquote>
+
+ <dt>Other Job Template Attributes
+
+</dl>
+
+<p>The Print-Job request is followed by a file to be printed.
+
+<h4>Print-Job Response</h4>
+
+<p>The following groups of attributes are send as part of the Print-Job
+Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<p>Group 2: Job Attributes
+
+<dl>
+
+ <dt>Standard Job Attributes
+
+</dl>
+
+<p>Group 3: Unsupported Attributes (status=client-eror-attributes-or-values-not-supported)
+
+<dl>
+
+ <dt>auth-info-required (1setOf Type2 keyword)
+
+ <dd>The required authentication information.
+
+</dl>
+
+<h3 class='title'><span class='info'>CUPS 1.1</span><a name='CREATE_JOB'>Create-Job Operation</a></h3>
+
+<p>The Create-Job operation (0x0005) creates a new, empty print job.
+
+<h4>Create-Job Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+Create-Job request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri):
+
+ <dd>The client MUST supply a URI for the specified printer.
+
+</dl>
+
+<p>Group 2: Job Template Attributes
+
+<dl>
+
+ <dt>"auth-info" (1setOf text(MAX)):<span class='info'>CUPS 1.3/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies one or more authentication values as specified by the "auth-info-required" attribute.
+
+ <dt>"job-billing" (text(MAX)):<span class='info'>CUPS 1.1</span>
+
+ <dd>The client OPTIONALLY supplies a billing string that is logged
+ with the page accounting information.
+
+ <dt>"job-sheets" (1setof type3 keyword | name(MAX)):<span class='info'>CUPS 1.1</span>
+
+ <dd>The client OPTIONALLY supplies one or two banner pages that
+ are printed before and after any files in the print job. The
+ name of "none" is reserved to indicate that no banner page
+ should be printed. If the client does not specify this
+ attribute then the value of the "job-sheets-default" printer
+ object attribute is used.
+
+ <blockquote><b>Note:</b> Standard IPP only allows
+ specification of a single job-sheets attribute
+ value.</blockquote>
+
+ <dt>"media" (1setof type3 keyword | name(MAX)):
+
+ <dd>The client OPTIONALLY supplies one or more media attributes
+ specifying the size, type, source, and color of the output
+ media. If the client does not specify this attribute then the
+ value of the "media-default" printer object attribute is used.
+
+ <blockquote><b>Note:</b> Standard IPP only allows
+ specification of a single media attribute
+ value.</blockquote>
+
+ <dt>Standard Job Template Attributes
+
+</dl>
+
+<h4>Create-Job Response</h4>
+
+<p>The following groups of attributes are send as part of the
+Create-Job Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<p>Group 2: Job Attributes
+
+<dl>
+
+ <dt>Standard Job Attributes
+
+</dl>
+
+<p>Group 3: Unsupported Attributes (status=client-eror-attributes-or-values-not-supported)
+
+<dl>
+
+ <dt>auth-info-required (1setOf Type2 keyword)
+
+ <dd>The required authentication information.
+
+</dl>
+
+<h3 class='title'><a name='CANCEL_JOB'>Cancel Job Operation</a></h3>
+
+<p>The Cancel-Job operation (0x0008) cancels the specified job. CUPS 1.4 adds
+a new <tt>purge-job (boolean)</tt> attribute that allows you to purge both
+active and completed jobs, removing all history and document files for the
+job as well.
+
+<h4>Cancel-Job Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+Cancel-Job request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri) and "job-id" (integer)
+ <br><i>OR</i>
+ <br>"job-uri":
+
+ <dd>The client MUST supply a URI for the specified printer and
+ a job ID number, or the job URI.
+
+ <dt><span class="info">CUPS 1.4/Mac OS X 10.6</span>"purge-job" (boolean):
+
+ <dd>The client OPTIONALLY supplies this attribute. When true,
+ all job files (history and document) are purged. The default
+ is false, leading to the standard IPP behavior.
+
+</dl>
+
+<h4>Cancel-Job Response</h4>
+
+<p>The following groups of attributes are send as part of the Cancel-Job
+Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<h3 class='title'><a name='PURGE_JOBS'>Purge-Jobs Operation</a></h3>
+
+<p>The Purge-Jobs operation (0x0012) cancels all of the jobs on a
+given destination and optionally removes all history and document
+files for the jobs as well.
+
+<h4>Purge-Jobs Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+Purge-Jobs request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri):
+
+ <dd>The client MUST supply a URI for the specified printer or
+ "ipp://.../printers" for all printers and classes.
+
+ <dt><span class="info">CUPS 1.2/Mac OS X 10.5</span>"requesting-user-name" (name(MAX)):
+
+ <dd>The client OPTIONALLY supplies this attribute to specify whose jobs
+ jobs are purged or canceled.
+
+ <dt><span class="info">CUPS 1.2/Mac OS X 10.5</span>"my-jobs" (boolean):
+
+ <dd>The client OPTIONALLY supplies this attribute to specify that only
+ the jobs owned by the requesting user are purged or canceled. The
+ default is false.
+
+ <dt><span class="info">CUPS 1.2/Mac OS X 10.5</span>"purge-jobs" (boolean):
+
+ <dd>The client OPTIONALLY supplies this attribute to specify
+ whether the jobs are purged (true) or just canceled (false).
+ The default is true.
+
+</dl>
+
+<h4>Purge-Jobs Response</h4>
+
+<p>The following groups of attributes are send as part of the Purge-Jobs
+Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<h3 class='title'><span class='info'>CUPS 1.1</span><a name='SET_JOB_ATTRIBUTES'>Set-Job-Attributes Operation</a></h3>
+
+<p>The Set-Job-Attributes operation (0x0014) changes the attributes of
+an active (not completed) job.
+
+<h4>Set-Job-Attributes Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+Set-Job-Attributes request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri) and "job-id" (integer)
+ <br><i>OR</i>
+ <br>"job-uri":
+
+ <dd>The client MUST supply a URI for the specified printer and
+ a job ID number, or the job URI.
+
+</dl>
+
+<p>Group 2: Job Template Attributes
+
+<dl>
+
+ <dt>"job-sheets" (1setof type3 keyword | name(MAX)):<span class='info'>CUPS 1.1</span>
+
+ <dd>The client OPTIONALLY supplies one or two banner pages that
+ are printed before and after any files in the print job. The
+ name of "none" is reserved to indicate that no banner page
+ should be printed. If the client does not specify this
+ attribute then the value of the "job-sheets-default" printer
+ object attribute is used.
+
+ <blockquote><b>Note:</b> Standard IPP only allows
+ specification of a single job-sheets attribute
+ value.</blockquote>
+
+ <dt>"media" (1setof type3 keyword | name(MAX)):
+
+ <dd>The client OPTIONALLY supplies one or more media attributes
+ specifying the size, type, source, and color of the output
+ media. If the client does not specify this attribute then the
+ value of the "media-default" printer object attribute is used.
+
+ <blockquote><b>Note:</b> Standard IPP only allows
+ specification of a single media attribute
+ value.</blockquote>
+
+ <dt>Other Job Template Attributes
+
+</dl>
+
+<h4>Set-Job-Attributes Response</h4>
+
+<p>The following groups of attributes are send as part of the Set-Job-Attributes
+Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<h3 class='title'><span class='info'>CUPS 1.2/Mac OS X 10.5</span><a
+name='CREATE_PRINTER_SUBSCRIPTION'>Create-Printer-Subscription</a></h3>
+
+<p>The Create-Printer-Subscription operation (0x0016) creates a
+subscription for printer or server event notifications. CUPS
+provides several additional events in addition to the standard
+events in the IPP notifications specification.</p>
+
+<h4>Create-Printer-Subscription Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+request:</p>
+
+<p>Group 1: Operation Attributes</p>
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri):
+
+ <dd>The printer
+ (<tt>ipp://server/printers/printername</tt>), class
+ (<tt>ipp://server/classes/classname</tt>), or server
+ (<tt>ipp://server/</tt>) URI for event notifications.
+
+ <dt>"notify-events" (1setOf keyword):
+
+ <dd>The events to monitor. In addition to the standard
+ events, CUPS adds the following keywords:
+ <ul>
+
+ <li><tt>printer-added</tt> - Get notified
+ whenever a printer or class is added</li>
+
+ <li><tt>printer-deleted</tt> - Get notified
+ whenever a printer or class is deleted</li>
+
+ <li><tt>printer-modified</tt> - Get notified
+ whenever a printer or class is modified</li>
+
+ <li><tt>server-audit</tt> - Get notified when a
+ security condition occurs</li>
+
+ <li><tt>server-restarted</tt> - Get notified when
+ the server is restarted</li>
+
+ <li><tt>server-started</tt> - Get notified when
+ the server is started</li>
+
+ <li><tt>server-stopped</tt> - Get notified when
+ the server is stopped</li>
+
+ </ul>
+
+</dl>
+
+<h4>Create-Printer-Subscription Response</h4>
+
+<p>The following groups of attributes are send as part of the
+response:</p>
+
+<p>Group 1: Operation Attributes</p>
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<p>Group 2: Subscription Object Attributes</p>
+
+<dl>
+
+ <dt>"subscription-id" (integer):
+
+ <dd>The subscription number.
+
+</dl>
+
+<h3 class='title'><a name='CUPS_GET_DEFAULT'>CUPS-Get-Default Operation</a></h3>
+
+<p>The CUPS-Get-Default operation (0x4001) returns the default printer
+URI and attributes.
+
+<h4>CUPS-Get-Default Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+CUPS-Get-Default request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"requested-attributes" (1setOf keyword) :
+
+ <dd>The client OPTIONALLY supplies a set of attribute names
+ and/or attribute group names in whose values the requester is
+ interested. If the client omits this attribute, the server
+ responds as if this attribute had been supplied with a value of
+ 'all'.
+
+</dl>
+
+<h4>CUPS-Get-Default Response</h4>
+
+<p>The following groups of attributes are send as part of the
+CUPS-Get-Default Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<p>Group 2: Printer Object Attributes
+
+<dl>
+
+ <dt>The set of requested attributes and their current values.
+
+</dl>
+
+<h3 class='title'><a name='CUPS_GET_PRINTERS'>CUPS-Get-Printers Operation</a></h3>
+
+<p>The CUPS-Get-Printers operation (0x4002) returns the printer
+attributes for every printer known to the system. This may include
+printers that are not served directly by the server.
+
+<h4>CUPS-Get-Printers Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+CUPS-Get-Printers request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"first-printer-name" (name(127)):<span class='info'>CUPS 1.2/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies this attribute to
+ select the first printer that is returned.
+
+ <dt>"limit" (integer (1:MAX)):
+
+ <dd>The client OPTIONALLY supplies this attribute limiting the
+ number of printers that are returned.
+
+ <dt>"printer-location" (text(127)): <span class='info'>CUPS 1.1.7</span>
+
+ <dd>The client OPTIONALLY supplies this attribute to
+ select which printers are returned.
+
+ <dt>"printer-type" (type2 enum): <span class='info'>CUPS 1.1.7</span>
+
+ <dd>The client OPTIONALLY supplies a printer type enumeration to
+ select which printers are returned.
+
+ <dt>"printer-type-mask" (type2 enum): <span class='info'>CUPS 1.1.7</span>
+
+ <dd>The client OPTIONALLY supplies a printer type mask
+ enumeration to select which bits are used in the "printer-type"
+ attribute.
+
+ <dt>"requested-attributes" (1setOf keyword) :
+
+ <dd>The client OPTIONALLY supplies a set of attribute names
+ and/or attribute group names in whose values the requester is
+ interested. If the client omits this attribute, the server
+ responds as if this attribute had been supplied with a value of
+ 'all'.
+
+ <dt>"requested-user-name" (name(127)) : <span class='info'>CUPS 1.2/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies a user name that is used to filter
+ the returned printers.
+
+</dl>
+
+<h4>CUPS-Get-Printers Response</h4>
+
+<p>The following groups of attributes are send as part of the
+CUPS-Get-Printers Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<p>Group 2: Printer Object Attributes
+
+<dl>
+
+ <dt>The set of requested attributes and their current values for
+ each printer.
+
+</dl>
+
+<h3 class='title'><a name='CUPS_ADD_MODIFY_PRINTER'>CUPS-Add-Modify-Printer Operation</a></h3>
+
+<p>The CUPS-Add-Modify-Printer operation (0x4003) adds a new printer or
+modifies an existing printer on the system.
+
+<h4>CUPS-Add-Modify-Printer Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+CUPS-Add-Modify-Printer request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri):
+
+ <dd>The client MUST supply a URI for the specified printer.
+
+</dl>
+
+<p>Group 2: Printer Object Attributes
+
+<dl>
+
+ <dt>"auth-info-required" (1setOf type2 keyword):<span class='info'>CUPS 1.3/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies one or more authentication keywords that are required to communicate with the printer/remote queue.
+
+ <dt>"job-sheets-default" (1setOf name(127)): <span
+ class='info'>CUPS 1.1.7</span>
+
+ <dd>The client OPTIONALLY supplies one or two banner page
+ names that are printed before and after files in a job.
+ The reserved name "none" is used to specify that no
+ banner page should be printed.
+
+ <dt>"device-uri" (uri):
+
+ <dd>The client OPTIONALLY supplies a device URI for the
+ specified printer.
+
+ <dt>"port-monitor" (name(127)):
+
+ <dd>The client OPTIONALLY supplies a port monitor name for the
+ specified printer.
+
+ <dt>"ppd-name" (name(127)):
+
+ <dd>The client OPTIONALLY supplies a PPD name for the specified
+ printer.
+
+ <dt>"printer-is-accepting-jobs" (boolean):
+
+ <dd>The client OPTIONALLY supplies this boolean attribute
+ indicating whether or not the printer object should accept new jobs.
+
+ <dt>"printer-info" (text(127)):
+
+ <dd>The client OPTIONALLY supplies this attribute indicating the
+ printer information string.
+
+ <dt>"printer-location" (text(127)):
+
+ <dd>The client OPTIONALLY supplies this attribute indicating a
+ textual location of the printer.
+
+ <dt>"printer-more-info" (uri):
+
+ <dd>The client OPTIONALLY supplies this attribute indicating a
+ URI for additional printer information.
+
+ <dt>"printer-state" (type2 enum):
+
+ <dd>The client OPTIONALLY supplies this attribute indicating the
+ initial/current state of the printer. Only the "idle" and "stopped"
+ enumerations are recognized.
+
+ <dt>"printer-state-message" (text(MAX)):
+
+ <dd>The client OPTIONALLY supplies this attribute indicating a
+ textual reason for the current printer state.
+
+ <dt>"requesting-user-name-allowed" (1setof name(127) | delete)
+ <br><i>OR</i>
+ <br>"requesting-user-name-denied" (1setof name(127) | delete):
+
+ <dd>The client OPTIONALLY supplies one of these attributes to
+ specify an access control list for incoming print jobs. To allow
+ all users access to a printer, use the delete tag for the
+ attribute value.
+
+</dl>
+
+<p>The CUPS-Add-Modify-Printer request can optionally be followed by a PPD
+file or System V interface script to be used for the printer. The
+"ppd-name" attribute overrides any file that is attached to the end of
+the request with a local CUPS PPD file.
+
+<h4>CUPS-Add-Modify-Printer Response</h4>
+
+<p>The following groups of attributes are send as part of the
+CUPS-Add-Modify-Printer Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<h3 class='title'><a name='CUPS_DELETE_PRINTER'>CUPS-Delete-Printer Operation</a></h3>
+
+<p>The CUPS-Delete-Printer operation (0x4004) removes an existing
+printer from the system.
+
+<h4>CUPS-Delete-Printer Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+CUPS-Delete-Printer request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri):
+
+ <dd>The client MUST supply a URI for the specified printer.
+
+</dl>
+
+<h4>CUPS-Delete-Printer Response</h4>
+
+<p>The following groups of attributes are send as part of the
+CUPS-Delete-Printer Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<h3 class='title'><a name='CUPS_GET_CLASSES'>CUPS-Get-Classes Operation</a></h3>
+
+<p>The CUPS-Get-Classes operation (0x4005) returns the printer
+attributes for every printer class known to the system. This may
+include printer classes that are not served directly by the server.
+
+<h4>CUPS-Get-Classes Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+CUPS-Get-Classes request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"first-printer-name" (name(127)):<span class='info'>CUPS 1.2/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies this attribute to
+ select the first printer that is returned.
+
+ <dt>"limit" (integer (1:MAX)):
+
+ <dd>The client OPTIONALLY supplies this attribute limiting the
+ number of printer classes that are returned.
+
+ <dt>"printer-location" (text(127)): <span class='info'>CUPS 1.1.7</span>
+ <dd>The client OPTIONALLY supplies this attribute to
+ select which printer classes are returned.
+
+ <dt>"printer-type" (type2 enum): <span class='info'>CUPS 1.1.7</span>
+ <dd>The client OPTIONALLY supplies a printer type enumeration to
+ select which printer classes are returned.
+
+ <dt>"printer-type-mask" (type2 enum): <span class='info'>CUPS 1.1.7</span>
+ <dd>The client OPTIONALLY supplies a printer type mask
+ enumeration to select which bits are used in the "printer-type"
+ attribute.
+
+ <dt>"requested-attributes" (1setOf keyword) :
+
+ <dd>The client OPTIONALLY supplies a set of attribute names
+ and/or attribute group names in whose values the requester is
+ interested. If the client omits this attribute, the server responds as
+ if this attribute had been supplied with a value of 'all'.
+
+ <dt>"requested-user-name" (name(127)) : <span class='info'>CUPS 1.2/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies a user name that is used to filter
+ the returned printers.
+
+</dl>
+
+<h4>CUPS-Get-Classes Response</h4>
+
+<p>The following groups of attributes are send as part of the
+CUPS-Get-Classes Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<p>Group 2: Printer Class Object Attributes
+
+<dl>
+
+ <dt>The set of requested attributes and their current values for
+ each printer class.
+
+</dl>
+
+<h3 class='title'><a name='CUPS_ADD_MODIFY_CLASS'>CUPS-Add-Modify-Class Operation</a></h3>
+
+<p>The CUPS-Add-Modify-Class operation (0x4006) adds a new printer class or
+modifies and existing printer class on the system.
+
+<h4>CUPS-Add-Modify-Class Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+CUPS-Add-Modify-Class request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri):
+
+ <dd>The client MUST supply a URI for the specified printer class.
+
+</dl>
+
+<p>Group 2: Printer Object Attributes
+
+<dl>
+
+ <dt>"auth-info-required" (1setOf type2 keyword):<span class='info'>CUPS 1.3/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies one or more authentication keywords that are required to communicate with the printer/remote queue.
+
+ <dt>"member-uris" (1setof uri):
+
+ <dd>The client OPTIONALLY supplies the "member-uris" set
+ specifying the printers and printer classes that are part of the class.
+
+ <dt>"printer-is-accepting-jobs" (boolean):
+
+ <dd>The client OPTIONALLY supplies this boolean attribute
+ indicating whether or not the class object should accept new jobs.
+
+ <dt>"printer-info" (text(127)):
+
+ <dd>The client OPTIONALLY supplies this attribute indicating the
+ printer information string.
+
+ <dt>"printer-location" (text(127)):
+
+ <dd>The client OPTIONALLY supplies this attribute indicating a
+ textual location of the class.
+
+ <dt>"printer-more-info" (uri):
+
+ <dd>The client OPTIONALLY supplies this attribute indicating a
+ URI for additional class information.
+
+ <dt>"printer-state" (type2 enum):
+
+ <dd>The client OPTIONALLY supplies this attribute indicating the
+ initial/current state of the class. Only the "idle" and "stopped"
+ enumerations are recognized.
+
+ <dt>"printer-state-message" (text(MAX)):
+
+ <dd>The client OPTIONALLY supplies this attribute indicating a
+ textual reason for the current class state.
+
+ <dt>"requesting-user-name-allowed" (1setof name(127))
+ <br><i>OR</i>
+ <br>"requesting-user-name-denied" (1setof name(127)):
+
+ <dd>The client OPTIONALLY supplies one of these attributes to
+ specify an access control list for incoming print jobs. To allow
+ all users access to a class, use the delete tag for the
+ attribute value.
+
+</dl>
+
+<h4>CUPS-Add-Modify-Class Response</h4>
+
+<p>The following groups of attributes are send as part of the CUPS-Add-Modify-Class Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<h3 class='title'><a name='CUPS_DELETE_CLASS'>CUPS-Delete-Class Operation</a></h3>
+
+<p>The CUPS-Delete-Class operation (0x4007) removes an existing printer
+class from the system.
+
+<h4>CUPS-Delete-Class Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+CUPS-Delete-Class request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri):
+
+ <dd>The client MUST supply a URI for the specified printer class.
+
+</dl>
+
+<h4>CUPS-Delete-Class Response</h4>
+
+<p>The following groups of attributes are send as part of the
+CUPS-Delete-Class Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<h3 class='title'><a name='CUPS_ACCEPT_JOBS'>CUPS-Accept-Jobs Operation</a></h3>
+
+<p>The CUPS-Accept-Jobs operation (0x4008) sets the
+"printer-is-accepting-jobs" attribute to true for the specified printer
+or printer class.
+
+<h4>CUPS-Accept-Jobs Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+CUPS-Accept-Jobs request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri):
+
+ <dd>The client MUST supply a URI for the specified printer or printer class.
+
+</dl>
+
+<h4>CUPS-Accept-Jobs Response</h4>
+
+<p>The following groups of attributes are send as part of the
+CUPS-Accept-Jobs Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<h3 class='title'><a name='CUPS_REJECT_JOBS'>CUPS-Reject-Jobs Operation</a></h3>
+
+<p>The CUPS-Reject-Jobs operation (0x4009) sets
+the"printer-is-accepting-jobs" attribute to false for the specified
+printer or printer class.
+
+<h4>CUPS-Reject-Jobs Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+CUPS-Reject-Jobs request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri):
+
+ <dd>The client MUST supply a URI for the specified printer or printer class.
+
+</dl>
+
+<p>Group 2: Printer Object Attributes
+
+<dl>
+
+ <dt>"printer-state-message" (text(MAX)):
+
+ <dd>The client OPTIONALLY supplies this attribute indicating a
+ textual reason for the current printer state.
+
+</dl>
+
+<h4>CUPS-Reject-Jobs Response</h4>
+
+<p>The following groups of attributes are send as part of the
+CUPS-Reject-Jobs Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<h3 class='title'><a name='CUPS_SET_DEFAULT'>CUPS-Set-Default Operation</a></h3>
+
+<p>The CUPS-Set-Default operation (0x400A) sets the default printer
+destination for all clients when a resource name of "/printers" is
+specified.
+
+<h4>CUPS-Set-Default Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+CUPS-Set-Default request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri):
+
+ <dd>The client MUST supply a URI for the specified printer or
+ printer class.
+
+</dl>
+
+<h4>CUPS-Set-Default Response</h4>
+
+<p>The following groups of attributes are send as part of the
+CUPS-Set-Default Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<h3 class='title'><span class='info'>CUPS 1.1</span><a name='CUPS_GET_DEVICES'>CUPS-Get-Devices Operation</a></h3>
+
+<p>The CUPS-Get-Devices operation (0x400B) returns all of the
+supported device-uri's for the server.</p>
+
+<h4>CUPS-Get-Devices Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+CUPS-Get-Devices request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"device-class" (type1 keyword):
+
+ <dd>The client OPTIONALLY supplies a device class keyword to select
+ which devices are returned.
+
+ <dt>"exclude-schemes" (1setOf name) :<span class='info'>CUPS 1.4/Mac OS X 10.6</span>
+
+ <dd>The client OPTIONALLY supplies a set of scheme names that the
+ requestor does not want to discover. If the client omits this attribute,
+ the server responds with devices of all schemes specified by
+ the "include-schemes" attribute.
+
+ <dt>"include-schemes" (1setOf name) :<span class='info'>CUPS 1.4/Mac OS X 10.6</span>
+
+ <dd>The client OPTIONALLY supplies a set of scheme names that the
+ requestor wants to discover. If the client omits this attribute,
+ the server responds with devices of all schemes except those specified
+ by the "exclude-schemes" attribute.
+
+ <dt>"limit" (integer (1:MAX)):
+
+ <dd>The client OPTIONALLY supplies this attribute limiting the number of
+ devices that are returned.
+
+ <dt>"requested-attributes" (1setOf keyword) :
+
+ <dd>The client OPTIONALLY supplies a set of attribute names and/or
+ attribute group names in whose values the requester is interested. If
+ the client omits this attribute, the server responds as if this
+ attribute had been supplied with a value of 'all'.
+
+ <dt>"timeout" (integer (1:MAX)) :<span class='info'>CUPS 1.4/Mac OS X 10.6</span>
+
+ <dd>The client OPTIONALLY supplies this attribute to limit the duration
+ of the lookup. The default timeout is 15 seconds.
+
+</dl>
+
+<h4>CUPS-Get-Devices Response</h4>
+
+<p>The following groups of attributes are send as part of the
+CUPS-Get-Devices Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<p>Group 2: Device Object Attributes
+
+<dl>
+
+ <dt>The set of requested attributes and their current values for
+ each device.
+
+</dl>
+
+<h3 class='title'><span class='info'>CUPS 1.1</span><a name='CUPS_GET_PPDS'>CUPS-Get-PPDs Operation</a></h3>
+
+<p>The CUPS-Get-PPDs operation (0x400C) returns all of the
+locally available PPD files on the system.</p>
+
+<h4>CUPS-Get-PPDs Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+CUPS-Get-PPDs request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"exclude-schemes" (1setOf name) :<span class='info'>CUPS 1.4/Mac OS X 10.6</span>
+
+ <dd>The client OPTIONALLY supplies a set of scheme names that the
+ requestor does not want to list. If the client omits this attribute,
+ the server responds with PPDs of all schemes specified by the
+ "include-schemes" attribute.
+
+ <dt>"include-schemes" (1setOf name) :<span class='info'>CUPS 1.4/Mac OS X 10.6</span>
+
+ <dd>The client OPTIONALLY supplies a set of scheme names that the
+ requestor wants to list. If the client omits this attribute, the server
+ responds with PPDs of all schemes except those specified by the
+ "exclude-schemes" attribute.
+
+ <dt>"limit" (integer (1:MAX)):
+
+ <dd>The client OPTIONALLY supplies this attribute limiting the number of PPDs that are returned.
+
+ <dt>"ppd-make" (text(127)):
+
+ <dd>The client OPTIONALLY supplies a printer manufacturer to select which PPDs are returned.
+
+ <dt>"ppd-make-and-model" (text(127)):<span class='info'>CUPS 1.3/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies a make and model to select which PPDs are returned.
+
+ <dt>"ppd-model-number" (integer):<span class='info'>CUPS 1.3/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies a model number to select which PPDs are returned.
+
+ <dt>"ppd-natural-language" (naturalLanguage):<span class='info'>CUPS 1.3/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies a language to select which PPDs are returned.
+
+ <dt>"ppd-product" (text(127)):<span class='info'>CUPS 1.3/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies a PostScript product string to select which PPDs are returned.
+
+ <dt>"ppd-psversion" (text(127)):<span class='info'>CUPS 1.3/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies a PostScript version string to select which PPDs are returned.
+
+ <dt>"ppd-type" (type1 keyword):<span class='info'>CUPS 1.3/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies a driver type to select which PPDs are returned.
+
+ <dt>"requested-attributes" (1setOf keyword) :
+
+ <dd>The client OPTIONALLY supplies a set of attribute names and/or attribute group names in whose values the requester is interested. If the client omits this attribute, the server responds as if this attribute had been supplied with a value of 'all'. Specify "ppd-make" to get a list of manufacturers.
+
+</dl>
+
+<h4>CUPS-Get-PPDs Response</h4>
+
+<p>The following groups of attributes are send as part of the
+CUPS-Get-PPDs Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<p>Group 2: PPD Attributes
+
+<dl>
+
+ <dt>The set of requested attributes and their current values for each
+ PPD file.
+
+</dl>
+
+<h3 class='title'><span class='info'>CUPS 1.1</span><a name='CUPS_MOVE_JOB'>CUPS-Move-Job Operation</a></h3>
+
+<p>The CUPS-Move-Job operation (0x400D) moves an active print job or all print
+jobs for a printer to a different printer.</p>
+
+<h4>CUPS-Move-Job Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+CUPS-Move-Job request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri)
+ <br><i>OR</i>
+ <dt>"printer-uri" (uri) and "job-id" (integer)
+ <br><i>OR</i>
+ <br>"job-uri":
+
+ <dd>The client MUST supply a URI for the specified printer, the URI for
+ the specified printer and a job ID number, or the job URI.
+
+</dl>
+
+<p>Group 2: Job Template Attributes
+
+<dl>
+
+ <dt>"job-printer-uri" (uri)
+
+ <dd>The client MUST supply a URI for a printer on the same server.
+
+</dl>
+
+<h4>CUPS-Move-Job Response</h4>
+
+<p>The following groups of attributes are send as part of the
+CUPS-Move-Job Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<h3 class='title'><span class='info'>CUPS 1.2/Mac OS X 10.5</span><a name='CUPS_AUTHENTICATE_JOB'>CUPS-Authenticate-Job Operation</a></h3>
+
+<p>The CUPS-Authenticate-Job operation (0x400E) authenticates a print job for
+printing, releasing the job if it is held. Typically this is used when printing
+to a remote server. The authentication information is passed in the HTTP
+request; the HTTP connection is normally encrypted for this type of request.</p>
+
+<h4>CUPS-Authenticate-Job Request</h4>
+
+<p>The following groups of attributes are supplied as part of the
+CUPS-Authenticate-Job request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri) and "job-id" (integer)
+ <br><i>OR</i>
+ <br>"job-uri":
+
+ <dd>The client MUST supply a URI for the specified printer and
+ a job ID number, or the job URI.
+
+</dl>
+
+<p>Group 2: Job Attributes
+
+<dl>
+
+ <dt>"auth-info" (1setOf text(MAX)):<span class='info'>CUPS 1.3/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies one or more authentication values as specified by the "auth-info-required" attribute.
+
+ <dt>"job-hold-until" (keyword | name(MAX)):<span class='info'>CUPS 1.3/Mac OS X 10.5</span>
+
+ <dd>The client OPTIONALLY supplies a new job-hold-until value for the
+ job. If specified and not the "no-hold" value, the job is held instead
+ of released for printing.
+
+</dl>
+
+<h4>CUPS-Authenticate-Job Response</h4>
+
+<p>The following groups of attributes are send as part of the
+CUPS-Authenticate-Job Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+</dl>
+
+<p>Group 2: Unsupported Attributes (status=client-eror-attributes-or-values-not-supported)
+
+<dl>
+
+ <dt>auth-info-required (1setOf Type2 keyword)
+
+ <dd>The required authentication information.
+
+</dl>
+
+<h3 class='title'><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='CUPS_GET_PPD'>CUPS-Get-PPD Operation</a></h3>
+
+<p>The CUPS-Get-PPD operation (0x400F) gets a PPD file from the
+server. The PPD file can be specified using a <tt>ppd-name</tt>
+returned by <a href='#CUPS_GET_PPDS'><tt>CUPS-Get-PPDs</tt></a>
+or using the <tt>printer-uri</tt> for a queue.</p>
+
+<p>If the PPD file is found, <tt>successful-ok</tt> is returned with
+the PPD file following the response data.</p>
+
+<p>If the PPD file cannot be served by the local server because
+the <tt>printer-uri</tt> attribute points to an external printer,
+a <tt>cups-see-other</tt> status is returned with the correct
+URI to use.</p>
+
+<p>If the PPD file does not exist, <tt>client-error-not-found</tt> is
+returned.</p>
+
+<h4>CUPS-Get-PPD Request</h4>
+
+<p>The following group of attributes is supplied as part of the
+CUPS-Get-PPD request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri)
+ <br><i>OR</i>
+ <br>"ppd-name" (name(255)):
+
+ <dd>The client MUST supply a printer URI or PPD name.
+
+</dl>
+
+<h4>CUPS-Get-PPD Response</h4>
+
+<p>The following group of attributes is sent as part of the
+CUPS-Get-PPD Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri):
+
+ <dd>The printer that provides the actual PPD file when
+ the status code is cups-see-other (0x280)
+
+</dl>
+
+<p>If the status code is <tt>successful-ok</tt>, the PPD file follows
+the end of the IPP response.</p>
+
+<h3 class='title'><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='CUPS_GET_DOCUMENT'>CUPS-Get-Document Operation</a></h3>
+
+<p>The CUPS-Get-Document operation (0x4027) gets a document file from a
+job on the server. The document file is specified using the
+<tt>document-number</tt> and either the <tt>job-uri</tt> or <tt>printer-uri</tt>
+and <tt>job-id</tt> identifying the job.</p>
+
+<p>If the document file is found, <tt>successful-ok</tt> is returned with
+the document file following the response data.</p>
+
+<p>If the document file does not exist, <tt>client-error-not-found</tt> is
+returned.</p>
+
+<p>If the requesting user does not have access to the document file,
+<tt>client-error-not-authorized</tt> is returned.
+
+<h4>CUPS-Get-Document Request</h4>
+
+<p>The following group of attributes is supplied as part of the
+CUPS-Get-Document request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+ <dt>"printer-uri" (uri) and "job-id" (integer)
+ <br><i>OR</i>
+ <br>"job-uri" (uri):
+
+ <dd>The client MUST supply a printer URI and job ID or job URI.
+
+ <dt>"document-number" (integer(1:MAX)):
+
+ <dd>The client MUST supply a document number to retrieve. The
+ <tt>document-count</tt> attribute for the job defines the maximum
+ document number that can be specified. In the case of jobs with
+ banners (<tt>job-sheets</tt> is not "none"), document number 1
+ will typically contain the start banner and document number N
+ will typically contain the end banner.
+
+</dl>
+
+<h4>CUPS-Get-Document Response</h4>
+
+<p>The following group of attributes is sent as part of the
+CUPS-Get-Document Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+ <dt>Status Message:
+
+ <dd>The standard response status message.
+
+ <dt>Natural Language and Character Set:
+
+ <dd>The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+ <dt>"document-format" (mimeType):
+
+ <dd>The format of the document file.
+
+ <dt>"document-number" (integer(1:MAX)):
+
+ <dd>The requested document number.
+
+ <dt>"document-name" (name(MAX)):
+
+ <dd>The name that was supplied with the document, if any.
+
+</dl>
+
+<p>If the status code is <tt>successful-ok</tt>, the document file follows
+the end of the IPP response.</p>
+
+
+<h2 class='title'><a name='ATTRIBUTES'>Attributes</a></h2>
+
+<p>CUPS provides many extension attributes to support multiple
+devices, PPD files, standard job filters, printers, and printer
+classes.</p>
+
+<h3 class='title'><a name='DEVICE_ATTRIBUTES'>Device Attributes</a></h3>
+
+<p>Device attributes are returned by the CUPS-Get-Devices
+operation and enumerate all of the available hardware devices and
+network protocols that are supported by the server.</p>
+
+<h4><a name="device-class">device-class (type2 keyword)</a></h4>
+
+<p>The device-class attribute specifies the class of device and can be
+one of the following:
+
+<ul>
+
+ <li>"file" - a disk file.
+
+ <li>"direct" - a parallel or fixed-rate serial data port,
+ currently used for Centronics, IEEE-1284, and USB printer
+ ports.
+
+ <li>"serial" - a variable-rate serial port.
+
+ <li>"network" - a network connection, typically via AppSocket,
+ HTTP, IPP, LPD, or SMB/CIFS protocols.
+
+</ul>
+
+<h4><a name="device-id">device-id (text(127))</a><span class="info">CUPS 1.2/Mac OS X 10.5</span></h4>
+
+<p>The device-id attribute specifies the IEEE-1284 device ID
+string for the device.</p>
+
+<h4><a name="device-info">device-info (text(127))</a></h4>
+
+<p>The device-info attribute specifies a human-readable string describing
+the device, e.g. "Parallel Port #1".
+
+<h4><a name="device-location">device-location (text(127))</a><span class="info">CUPS 1.4/Mac OS X 10.6</span></h4>
+
+<p>The device-location attribute specifies the physical location of the
+printer.
+
+<h4><a name="device-make-and-model">device-make-and-model (text(127))</a></h4>
+
+<p>The device-make-and-model attribute specifies a device
+identification string provided by the printer connected to the device.
+If the device or printer does not support identification then this
+attribute contains the string "unknown".
+
+<h4><a name="device-uri">device-uri (uri)</a></h4>
+
+<p>The device-uri attribute specifies a unique identifier for the
+device. The actual format of the device-uri string depends on the value
+of the device-class attribute:
+
+<ul>
+
+ <li>"file" - The device-uri will be of the form
+ "file:///path/to/filename".
+
+ <li>"direct" - The device-uri will be of the form
+ "scheme:/dev/filename" or "scheme://vendor/identifier",
+ where scheme may be "parallel" or "usb" in the current
+ implementation.
+
+ <li>"serial" - The device-uri will be of the form
+ "serial:/dev/filename?baud=value+parity=value+flow=value".
+ The baud value is the data rate in bits per second; the
+ supported values depend on the underlying hardware.
+ The parity value can be one of "none", "even", or "odd".
+ The flow value can be one of "none", "soft" (XON/XOFF
+ handshaking), "hard" or "rts/cts" (RTS/CTS handshaking),
+ or "dtrdsr" (DTR/DSR handshaking).
+
+ <p>The URI returned by CUPS-Get-Devices will contain the
+ maximum baud rate supported by the device and the best
+ type of flow control available ("soft" or "hard").
+
+ <li>"network" - The device-uri will be of the form
+ "scheme://[username:password@]hostname[:port]/[resource]",
+ where scheme may be "http", "https", "ipp", "lpd", "smb", or
+ "socket" in the current implementation.
+
+ <p>The URI returned by CUPS-Get-Devices will only contain
+ the scheme name ("scheme"). It is up to the client
+ application to add the appropriate host and other
+ information when adding a new printer.
+
+ <p>The URI returned by Get-Printer-Attributes and
+ CUPS-Get-Printers has any username and password information
+ stripped; the information is still stored and used by the
+ server internally to perform any needed authentication.
+
+</ul>
+
+<h3 class='title'><a name='JOB_TEMPLATE_ATTRIBUTES'>Job Template Attributes</a></h3>
+
+<h4><a name="auth-info">auth-info (1setOf text(MAX))</a><span class="info">CUPS 1.3/Mac OS X 10.5</span></h4>
+
+<p>The auth-info attribute specifies the authentication information to use when printing to a remote device. The order and content of each text value is specifed by the <a href="#auth-info-required">auth-info-required</a> printer attribute.
+
+<h4><a name="blackplot">blackplot (boolean)</a></h4>
+
+<p>The blackplot attribute specifies whether HP-GL/2 plot files should be
+rendered entirely in black ink (blackplot=true) or using the colors and shades
+specified in the file (blackplot=false). The default value is false.
+
+<h4><a name="brightness">brightness (integer(0:200))</a><span class="info">Deprecated</span></h4>
+
+<p>The brightness attribute specifies the overall brightness of the printed
+output in percent. A brightness of 100 is normal, while 200 is twice as
+bright and 50 is half as bright. The default value is 100.
+
+<p>Brightness is applied to the Cyan, Magenta, Yellow, and Black values using
+the function "f(x) = brightness / 100 * x".
+
+<blockquote><b>Note:</b>
+
+<p>This attribute is deprecated and will be removed from a future CUPS
+release.</p>
+
+</blockquote>
+
+<h4><a name="columns">columns (integer(1:4))</a> <span class='info'>Deprecated</span></h4>
+
+<p>The columns attribute specifies the number of columns to generate when
+printing text files. The default value is 1.
+
+<h4><a name="cpi">cpi (type2 enum)</a></h4>
+
+<p>The cpi attribute specifies the number of characters per inch when
+printing text files. Only the values 10, 12, and 17 are currently
+supported. The default value is 10.
+
+<h4><a name="document-count">document-count (integer(1:MAX))</a></h4>
+
+<p>The document-count attribute specifies the number of documents that
+are present in the job.
+
+<h4><a name="fit-to-page">fit-to-page (boolean)</a><span class="info">CUPS 1.4/Mac OS X 10.6</span></h4>
+
+<p>The fit-to-page attribute specifies whether to scale documents to fit on the
+selected media (fit-to-page=true) or use the physical size specified in the
+document (fit-to-page=false). The default value is false.
+
+<h4><a name="fitplot">fitplot (boolean)</a><span class="info">Deprecated</span></h4>
+
+<p>The fitplot attribute specifies whether to scale HP-GL/2 plot files to
+fit on the selected media (fitplot=true) or use the physical scale specified
+in the plot file (fitplot=false). The default value is false.
+
+<h4><a name="gamma">gamma (integer(1:10000))</a><span class="info">Deprecated</span></h4>
+
+<p>The gamma attribute specifies the luminance correction for the output.
+A value of 1000 specifies no correction, while values of 2000 and 500 will
+generate lighter and darker output, respectively. The default value is
+1000.
+
+<p>Gamma is applied to the Red, Green, and Blue values (or luminance for
+grayscale output) using the function "f(x) = x<sup>(1000/gamma)</sup>".
+
+<blockquote><b>Note:</b>
+
+<p>This attribute is deprecated and will be removed from a future CUPS
+release.</p>
+
+</blockquote>
+
+<h4><a name="hue">hue (integer(-180:180))</a><span class="info">Deprecated</span></h4>
+
+<p>The hue attribute specifies a color hue rotation when printing image
+files. The default value is 0.
+
+<blockquote><b>Note:</b>
+
+<p>This attribute is deprecated and will be removed from a future CUPS
+release.</p>
+
+</blockquote>
+
+<h4><a name="job-billing">job-billing (text(MAX))</a><span class='info'>CUPS 1.1</span></h4>
+
+<p>The job-billing attribute provides a text value to associate with a job
+for billing purposes.
+
+<h4><a name="job-hold-until">job-hold-until (keyword | name(MAX))</a><span class='info'>CUPS 1.1</span></h4>
+
+<p>The job-hold-until attribute specifies a hold time. In addition to the
+standard IPP/1.1 keyword names, CUPS supports name values of the form
+"HH:MM" and "HH:MM:SS" that specify a hold time. The hold time is in
+Universal Coordinated Time (UTC) and <i>not</i> in the local time zone. If the
+specified time is less than the current time, the job is held until the
+next day.
+
+<h4><a name="job-media-progress">job-media-progress (integer(0:100))</a><span class='info'>CUPS 1.4/Mac OS X 10.6</span></h4>
+
+<p>The job-media-progress attribute specifies the percentage of completion of
+the current page. It is only valid when the job-state attribute has the
+"processing" value (5).</p>
+
+<h4><a name="job-printer-state-message">job-printer-state-message (text(MAX))</a><span class='info'>CUPS 1.3/Mac OS X 10.5</span></h4>
+
+<p>The job-printer-state-message attribute provides the last known value of the printer-state-message attribute for the printer that processed (or is processing) the job.</p>
+
+<h4><a name="job-printer-state-reasons">job-printer-state-reasons (1setOf type2 keyword)</a><span class='info'>CUPS 1.3/Mac OS X 10.5</span></h4>
+
+<p>The job-printer-state-reasons attribute provides the last known value of the printer-state-reasons attribute for the printer that processed (or is processing) the job.</p>
+
+<h4><a name="job-sheets">job-sheets (1setof type3 keyword | name(MAX))</a><span class='info'>CUPS 1.1</span></h4>
+
+<p>The job-sheets attribute specifies one or two banner files that are printed
+before and after a job. The reserved value of "none" disables banner printing.
+The default value is stored in the job-sheets-default attribute.
+
+<p>If only one value is supplied, the banner file is printed before the job.
+If two values are supplied, the first value is used as the starting banner
+file and the second as the ending banner file.
+
+<h4><a name="job-originating-host-name">job-originating-host-name (name(MAX))</a></h4>
+
+<p><i>(CUPS 1.1.5 and higher)</i>
+
+<p>The job-originating-host-name attribute specifies the host
+from which the job was queued. The value will be the hostname or
+IP address of the client depending on whether hostname
+resolution is enabled. The localhost address (127.0.0.1) is
+<b>always</b> resolved to the name "localhost".
+
+<p>This attribute is read-only.
+
+<h4><a name="lpi">lpi (type2 enum)</a></h4>
+
+<p>The lpi attribute specifies the number of lines per inch when
+printing text files. Only the values 6 and 8 are currently supported.
+The default value is 6.
+
+<h4><a name="mirror">mirror (boolean)</a></h4>
+
+<p>The mirror attribute specifies whether pages are mirrored on
+their X axis, which is useful for printing transfer images on
+special media. The default value is false.
+
+<h4><a name="natural-scaling">natural-scaling (integer(1:1000))</a><span class='info'>CUPS 1.1.9</span></h4>
+<p>The natural-scaling attribute specifies the scaling of image files with
+respect to the natural image size. A value of 100 specifies that the image
+file should exactly the natural size, while 50 is half the natural size
+and 200 is twice the natural size. The default value is 100.
+
+<p>The ppi option can be used to override the natural resolution of the
+image, which controls the natural size.
+
+<h4><a name="number-up-layout">number-up-layout (type2 keyword)</a><span class='info'>CUPS 1.1.15</span></h4>
+<p>The number-up-layout attribute specifies the order each input
+page is placed on each output page. The following keywords are
+presently defined:
+
+<ul>
+
+ <li><CODE>btlr</CODE> - Bottom to top, left to right</li>
+
+ <li><CODE>btrl</CODE> - Bottom to top, right to left</li>
+
+ <li><CODE>lrbt</CODE> - Left to right, bottom to top</li>
+
+ <li><CODE>lrtb</CODE> - Left to right, top to bottom (default)</li>
+
+ <li><CODE>rlbt</CODE> - Right to left, bottom to top</li>
+
+ <li><CODE>rltb</CODE> - Right to left, top to bottom</li>
+
+ <li><CODE>tblr</CODE> - Top to bottom, left to right</li>
+
+ <li><CODE>tbrl</CODE> - Top to bottom, right to left</li>
+
+</ul>
+
+<h4><a name="page-border">page-border (type2 keyword)</a><span class='info'>CUPS 1.1.15</span></h4>
+<p>The page-border attribute specifies whether a border is
+draw around each page. The following keywords are presently
+defined:
+
+<ul>
+
+ <li><CODE>double</CODE> - Two hairline borders are drawn</li>
+
+ <li><CODE>double-thick</CODE> - Two 1pt borders are drawn</li>
+
+ <li><CODE>none</CODE> - No border is drawn (default)</li>
+
+ <li><CODE>single</CODE> - A single hairline border is drawn</li>
+
+ <li><CODE>single-thick</CODE> - A single 1pt border is drawn</li>
+
+</ul>
+
+<h4><a name="page-bottom">page-bottom (integer(0:MAX))</a></h4>
+
+<p>The page-bottom attribute specifies the bottom margin in points (72 points
+equals 1 inch). The default value is the device physical margin.
+
+<h4><a name="page-label">page-label (text(MAX))</a><span class='info'>CUPS 1.1.7</span></h4>
+<p>The page-label attribute provides a text value to place in
+the header and footer on each page. If a classification level is
+set on the server, then this classification is printed before
+the page label.
+
+<h4><a name="page-left">page-left (integer(0:MAX))</a></h4>
+
+<p>The page-left attribute specifies the left margin in points (72 points
+equals 1 inch). The default value is the device physical margin.
+
+<h4><a name="page-right">page-right (integer(0:MAX))</a></h4>
+
+<p>The page-right attribute specifies the right margin in points (72 points
+equals 1 inch). The default value is the device physical margin.
+
+<h4><a name="page-set">page-set (type2 keyword)</a></h4>
+
+<p>The page-set attribute specifies which pages to print in a file. The
+supported keywords are "all", "even", and "odd". The default value is
+"all".
+
+<h4><a name="page-top">page-top (integer(0:MAX))</a></h4>
+
+<p>The page-top attribute specifies the top margin in points (72 points
+equals 1 inch). The default value is the device physical margin.
+
+<h4><a name="penwidth">penwidth (integer(0:MAX))</a></h4>
+
+<p>The penwidth attribute specifies the default pen width in micrometers
+when printing HP-GL/2 plot files. The default value is 1000 (1 millimeter).
+
+<h4><a name="position">position (type2 keyword)</a></h4>
+
+<p>The position attribute specifies the location of image files on the
+media. The following keyword values are recognized:
+
+<ul>
+
+ <li><CODE>center</CODE> - Center the image on the page (default)
+
+ <li><CODE>top</CODE> - Print the image centered at the top of the page
+
+ <li><CODE>left</CODE> - Print the image centered on the left of page
+
+ <li><CODE>right</CODE> - Print the image centered on the right of the page
+
+ <li><CODE>top-left</CODE> - Print the image at the top left corner of
+ the page
+
+ <li><CODE>top-right</CODE> - Print the image at the top right corner of
+ the page
+
+ <li><CODE>bottom</CODE> - Print the image centered at the bottom of
+ the page
+
+ <li><CODE>bottom-left</CODE> - Print the image at the bottom left
+ corner of the page
+
+ <li><CODE>bottom-right</CODE> - Print the image at the bottom right
+ corner of the page
+
+</ul>
+
+<h4><a name="ppi">ppi (integer(1:MAX))</a></h4>
+
+<p>The ppi attribute specifies the resolution of an image file in pixels
+per inch. The default value is the resolution included with the file or
+128 if no resolution information is available.
+
+<h4><a name="prettyprint">prettyprint (boolean)</a></h4>
+
+<p>The prettyprint attribute specifies whether text files should be printed
+with a shaded header and keyword highlighting (prettyprint=true) or without
+additional formatting (prettyprint=false). The default value is false.
+
+<h4><a name="saturation">saturation (integer(0:200))</a><span class="info">Deprecated</span></h4>
+
+<p>The saturation attribute specifies the color saturation when
+printing image files. A saturation of 100 is normal, while values of 50
+and 200 will be half and twice as colorful, respectively. The default
+value is 100.
+
+<blockquote><b>Note:</b>
+
+<p>This attribute is deprecated and will be removed from a future CUPS
+release.</p>
+
+</blockquote>
+
+<h4><a name="scaling">scaling (integer(1:1000))</a></h4>
+
+<p>The scaling attribute specifies the scaling of image files with
+respect to the selected media. A value of 100 specifies that the image
+file should fit 100% of the page, or as much as possible given the
+image dimensions. The default value is unspecified.
+
+<p>The scaling attribute overrides the ppi attribute if specified.
+
+<h4><a name="wrap">wrap (boolean)</a></h4>
+
+<p>The wrap attribute specifies whether long lines should be wrapped
+(wrap=true) or not (wrap=false) when printing text files. The default
+value is true.
+
+<h3 class='title'><a name='PPD_ATTRIBUTES'>PPD Attributes</a></h3>
+
+<h4><a name="ppd-device-id">ppd-device-id (text(127))</a></h4>
+
+<p>The ppd-device-id attribute specifies the IEEE-1284 device ID
+string for the device described by the PPD file.</p>
+
+<h4><a name="ppd-make">ppd-make (text(127))</a></h4>
+
+<p>The ppd-make attribute specifies the manufacturer of the printer
+(the Manufacturer attribute in the PPD file). If the manufacturer
+is not specified in the PPD file then an educated guess is made using
+the NickName attribute in the PPD file.
+
+<h4><a name="ppd-make-and-model">ppd-make-and-model (text(127))</a></h4>
+
+<p>The ppd-make-and-model attribute specifies the manufacturer and model
+name of the PPD file (the NickName attribute in the PPD file). If the
+make and model is not specified in the PPD file then the ModelName or
+ShortNickName attributes are used instead.
+
+<h4><a name="ppd-model-number">ppd-model-number (integer)</a><span class="info">CUPS 1.3/Mac OS X 10.5</span></h4>
+
+<p>The ppd-model-number attribute provides the <tt>cupsModelNumber</tt> value from the PPD file.
+
+<h4><a name="ppd-name">ppd-name (name(255))</a></h4>
+
+<p>The ppd-name attribute specifies either the PPD filename on the server relative to the model directory or a URI that maps to a specific driver interface in the driver directory. The forward slash (/) is used to delineate directories.
+
+<h4><a name="ppd-natural-language">ppd-natural-language (1setOf naturalLanguage)</a></h4>
+
+<p>The ppd-natural-language attribute specifies the language encoding
+of the PPD file (the LanguageVersion attribute in the PPD file). If the
+language is unknown or undefined then "en" (English) is assumed.
+
+<h4><a name="ppd-product">ppd-product (1setOf text(127))</a></h4>
+
+<p>The ppd-product attribute specifies the Product attribute values in the PPD file.
+
+<h4><a name="ppd-psversion">ppd-psversion (1setOf text(127))</a><span class="info">CUPS 1.3/Mac OS X 10.5</span></h4>
+
+<p>The ppd-product attribute specifies the PSVersion attribute values in the PPD file.
+
+<h4><a name="ppd-type">ppd-type (type1 keyword)</a><span class="info">CUPS 1.3/Mac OS X 10.5</span></h4>
+
+<p>The ppd-type attribute specifies the type of driver described by the PPD file:</p>
+
+<ul>
+
+ <li><tt>fax</tt> - A facsimile or multi-function device</li>
+
+ <li><tt>pdf</tt> - A PDF printer</li>
+
+ <li><tt>postscript</tt> - A PostScript printer (no filters)</li>
+
+ <li><tt>raster</tt> - A CUPS raster driver</li>
+
+ <li><tt>unknown</tt> - An unknown or hybrid driver</li>
+
+</ul>
+
+
+<h3 class='title'><a name='PRINTER_ATTRIBUTES'>Printer Attributes</a></h3>
+
+<h4><a name="auth-info-required">auth-info-required (1setOf type2 keyword)</a><span class="info">CUPS 1.3/Mac OS X 10.5</span></h4>
+
+<p>The auth-info-required attribute specifies the authentication information that is required for printing a job. The following keywords are recognized:</p>
+
+<ul>
+
+ <li><tt>domain</tt> - A domain name is required.</li>
+
+ <li><tt>none</tt> - No authentication is required - this keyword can only appear by itself.</li>
+
+ <li><tt>password</tt> - A password is required.</li>
+
+ <li><tt>username</tt> - A username is required.</li>
+
+</ul>
+
+<h4><a name="job-k-limit">job-k-limit (integer)</a><span class='info'>CUPS 1.1</span></h4>
+
+<p>The job-k-limit attribute specifies the maximum number of kilobytes that
+may be printed by a user, including banner files. The default value of 0
+specifies that there is no limit.
+
+<h4><a name="job-page-limit">job-page-limit (integer)</a><span class='info'>CUPS 1.1</span></h4>
+
+<p>The job-page-limit attribute specifies the maximum number of pages that
+may be printed by a user, including banner files. The default value of 0
+specifies that there is no limit.
+
+<h4><a name="job-quota-period">job-quota-period (integer)</a><span class='info'>CUPS 1.1</span></h4>
+
+<p>The job-quota-period attribute specifies the time period used for quota
+calculations, in seconds. The default value of 0 specifies that the limits
+apply to all jobs that have been printed by a user that are still known to
+the system.
+
+<h4><a name="job-sheets-supported">job-sheets-supported (1setof type3 keyword | name(MAX))</a><span class='info'>CUPS 1.1</span></h4>
+
+<p>The job-sheets-supported attribute specifies the available banner files.
+There will always be at least one banner file available called "none".
+
+<h4><a name="marker-change-time">marker-change-time (integer)</a><span class='info'>CUPS 1.3/Mac OS X 10.5</span></h4>
+
+<p>The marker-change-time attribute specifies the printer-up-time value when
+the last change to the marker-colors, marker-levels, marker-message,
+marker-names, or marker-types attributes was made.</p>
+
+<h4><a name="marker-colors">marker-colors (1setof name(MAX))</a><span class='info'>CUPS 1.3/Mac OS X 10.5</span></h4>
+
+<p>The marker-colors attribute specifies the color(s) for each supply in the
+printer. It is only available when the driver provides supply levels. The
+color is either "none" or one or more hex-encoded sRGB colors of the form
+"#RRGGBB".</p>
+
+<h4><a name="marker-high-levels">marker-high-levels (1setof integer(0:100))</a><span class='info'>CUPS 1.4/Mac OS X 10.6</span></h4>
+
+<p>The marker-high-levels attribute specifies the supply levels that indicate
+a near-full condition. A value of 100 should be used for supplies that are
+consumed/emptied, e.g. ink cartridges.</p>
+
+<h4><a name="marker-levels">marker-levels (1setof integer(-3:100))</a><span class='info'>CUPS 1.3/Mac OS X 10.5</span></h4>
+
+<p>The marker-levels attribute specifies the current supply levels for the
+printer. It is only available when the driver provides supply levels. A
+value of -1 indicates the level is unavailable, -2 indicates unknown, and -3
+indicates the level is unknown but has not yet reached capacity. Values from 0
+to 100 indicate the corresponding percentage.</p>
+
+<h4><a name="marker-low-levels">marker-low-levels (1setof integer(0:100))</a><span class='info'>CUPS 1.4/Mac OS X 10.6</span></h4>
+
+<p>The marker-low-levels attribute specifies the supply levels that indicate
+a near-empty condition. A value of 0 should be used for supplies that are
+filled, e.g. waste ink tanks.</p>
+
+<h4><a name="marker-message">marker-message (text(MAX))</a><span class='info'>CUPS 1.4/Mac OS X 10.6</span></h4>
+
+<p>The marker-message attribute provides a human-readable status message
+for the current supply levels, e.g. "12 pages of ink remaining." It is only
+available when the driver provides supply levels.</p>
+
+<h4><a name="marker-names">marker-names (1setof name(MAX))</a><span class='info'>CUPS 1.3/Mac OS X 10.5</span></h4>
+
+<p>The marker-names attribute specifies the name(s) for each supply in the
+printer. It is only available when the driver provides supply levels.</p>
+
+<h4><a name="marker-types">marker-types (1setof type3 keyword)</a><span class='info'>CUPS 1.3/Mac OS X 10.5</span></h4>
+
+<p>The marker-types attribute specifies the type(s) of each supply in the
+printer. It is only available when the driver provides supply levels. The
+following (RFC 3805) types are currently supported:</p>
+
+<ul>
+
+ <li><tt>toner</tt></li>
+
+ <li><tt>wasteToner</tt></li>
+
+ <li><tt>ink</tt></li>
+
+ <li><tt>inkCartridge</tt></li>
+
+ <li><tt>inkRibbon</tt></li>
+
+ <li><tt>wasteInk</tt></li>
+
+ <li><tt>opc</tt></li>
+
+ <li><tt>developer</tt></li>
+
+ <li><tt>fuserOil</tt></li>
+
+ <li><tt>solidWax</tt></li>
+
+ <li><tt>ribbonWax</tt></li>
+
+ <li><tt>wasteWax</tt></li>
+
+ <li><tt>fuser</tt></li>
+
+ <li><tt>coronaWire</tt></li>
+
+ <li><tt>fuserOilWick</tt></li>
+
+ <li><tt>cleanerUnit</tt></li>
+
+ <li><tt>fuserCleaningPad</tt></li>
+
+ <li><tt>transferUnit</tt></li>
+
+ <li><tt>tonerCartridge</tt></li>
+
+ <li><tt>fuserOiler</tt></li>
+
+ <li><tt>water</tt></li>
+
+ <li><tt>wasteWater</tt></li>
+
+ <li><tt>bindingSupply</tt></li>
+
+ <li><tt>bandingSupply</tt></li>
+
+ <li><tt>stichingWire</tt></li>
+
+ <li><tt>shrinkWrap</tt></li>
+
+ <li><tt>paperWrap</tt></li>
+
+ <li><tt>staples</tt></li>
+
+ <li><tt>inserts</tt></li>
+
+ <li><tt>covers</tt></li>
+
+</ul>
+
+<h4><a name="port-monitor">port-monitor" (name(127))</a></h4>
+
+<p>The port-monitor attribute specifies the port monitor to use when printing
+to this printer. The default port monitor is "none".
+
+<h4><a name="port-monitor-supported">port-monitor-supported" (1setOf name(127))</a></h4>
+
+<p>The port-monitor-supported attribute specifies the available port monitors.
+
+<h4><a name="printer-commands">printer-commands (1setOf Type3 keyword)</a><span class='info'>CUPS 1.4/Mac OS X 10.6</span></h4>
+
+<p>The printer-commands attribute specifies the commands that are supported
+by the CUPS command file filter. The keyword "none" indicates that no commands
+are supported.</p>
+
+<h4><a name="printer-dns-sd-name">printer-dns-sd-name (name(MAX) | noValue)</a><span class='info'>CUPS 1.4/Mac OS X 10.6</span></h4>
+
+<p>The printer-dns-sd-name attribute specifies the registered DNS-SD service
+name for the printer. If the printer is not being shared using this protocol,
+printer-dns-sd-name will have the noValue value.</p>
+
+<h4><a name="printer-state-reasons">printer-state-reasons (1setOf type2 keyword)</a></h4>
+
+<p>The printer-state-reasons attribute provides additional persistent state
+information for a printer. In addition to the keywords defined in RFC 2911,
+CUPS supports vendor-specific keywords with a domain prefix ("com.vendor.foo")
+and the following CUPS-specific keywords:</p>
+
+<ul>
+
+ <li><tt>cups-insecure-filter-warning</tt> - a filter or backend (or the
+ directory containing the filter or backend) has insecure file
+ permissions. CUPS will not execute programs with world write permissions
+ or setuid programs. When run as root (the default), CUPS also does not
+ execute programs that are not owned by root.
+ <span class='info'>CUPS 1.4/Mac OS X 10.6</span></li>
+
+ <li><tt>cups-missing-filter-warning</tt> - a filter or backend is not
+ installed. <span class='info'>CUPS 1.4/Mac OS X 10.6</span></li>
+
+</ul>
+
+<h4><a name="printer-type">printer-type (type2 enum)</a></h4>
+
+<p>The printer-type attribute specifies printer type and
+capability bits for the printer or class. The default value is
+computed from internal state information and the PPD file for the
+printer. The following bits are defined:</p>
+
+<div class='table'><table align='center' border='1' width='80%'
+summary='Printer Type Bits'>
+<thead>
+<tr>
+ <th>Bit</th>
+ <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>0x00000001</td>
+ <td>Is a printer class.</td>
+</tr>
+<tr>
+ <td>0x00000002</td>
+ <td>Is a remote destination.</td>
+</tr>
+<tr>
+ <td>0x00000004</td>
+ <td>Can print in black.</td>
+</tr>
+<tr>
+ <td>0x00000008</td>
+ <td>Can print in color.</td>
+</tr>
+<tr>
+ <td>0x00000010</td>
+ <td>Can print on both sides of the page in hardware.</td>
+</tr>
+<tr>
+ <td>0x00000020</td>
+ <td>Can staple output.</td>
+</tr>
+<tr>
+ <td>0x00000040</td>
+ <td>Can do fast copies in hardware.</td>
+</tr>
+<tr>
+ <td>0x00000080</td>
+ <td>Can do fast copy collation in hardware.</td>
+</tr>
+<tr>
+ <td>0x00000100</td>
+ <td>Can punch output.</td>
+</tr>
+<tr>
+ <td>0x00000200</td>
+ <td>Can cover output.</td>
+</tr>
+<tr>
+ <td>0x00000400</td>
+ <td>Can bind output.</td>
+</tr>
+<tr>
+ <td>0x00000800</td>
+ <td>Can sort output.</td>
+</tr>
+<tr>
+ <td>0x00001000</td>
+ <td>Can handle media up to US-Legal/A4.</td>
+</tr>
+<tr>
+ <td>0x00002000</td>
+ <td>Can handle media from US-Legal/A4 to ISO-C/A2.</td>
+</tr>
+<tr>
+ <td>0x00004000</td>
+ <td>Can handle media larger than ISO-C/A2.</td>
+</tr>
+<tr>
+ <td>0x00008000</td>
+ <td>Can handle user-defined media sizes.</td>
+</tr>
+<tr>
+ <td>0x00010000</td>
+ <td>Is an implicit (server-generated) class.</td>
+</tr>
+<tr>
+ <td>0x00020000</td>
+ <td>Is the a default printer on the network.</td>
+</tr>
+<tr>
+ <td>0x00040000</td>
+ <td>Is a facsimile device.</td>
+</tr>
+<tr>
+ <td>0x00080000</td>
+ <td>Is rejecting jobs.</td>
+</tr>
+<tr>
+ <td>0x00100000</td>
+ <td>Delete this queue.</td>
+</tr>
+<tr>
+ <td>0x00200000</td>
+ <td>Queue is not shared.</td>
+</tr>
+<tr>
+ <td>0x00400000</td>
+ <td>Queue requires authentication.</td>
+</tr>
+<tr>
+ <td>0x00800000</td>
+ <td>Queue supports CUPS command files.</td>
+</tr>
+<tr>
+ <td>0x01000000</td>
+ <td>Queue was automatically discovered and added.</td>
+</tr>
+<tr>
+ <td>0x02000000</td>
+ <td>Queue is a scanner with no printing capabilities.</td>
+</tr>
+<tr>
+ <td>0x04000000</td>
+ <td>Queue is a printer with scanning capabilities.</td>
+</tr>
+</tbody>
+</table></div>
+
+<h4>printer-type-mask (type2 enum)<span class='info'>CUPS 1.1</span></h4>
+
+<p>The printer-type-mask attribute is used to choose printers or classes with
+the CUPS-Get-Printers and CUPS-Get-Classes operations. The bits are defined
+identically to the printer-type attribute and default to all 1's.
+
+<h4>requesting-user-name-allowed (1setof name(127))<span class='info'>CUPS 1.1</span></h4>
+
+<p>The requesting-user-name-allowed attribute lists all of the users that are
+allowed to access a printer or class. Either this attribute or the
+requesting-user-name-denied attribute will be defined, but not both.
+
+<h4>requesting-user-name-denied (1setof name(127))<span class='info'>CUPS 1.1</span></h4>
+
+<p>The requesting-user-name-denied attribute lists all of the users that are
+not allowed to access a printer or class. Either this attribute or the
+requesting-user-name-allowed attribute will be defined, but not both.
+
+<h3 class='title'><a name='CLASS_ATTRIBUTES'>Printer Class Attributes</a></h3>
+
+<h4>member-names (1setof name(127))</h4>
+
+<p>The member-names attribute specifies each of the printer-name attributes of
+the member printers and classes. Each name corresponds to the same element of
+the member-uris attribute.
+
+<h4>member-uris (1setof uri)</h4>
+
+<p>The member-uris attribute specifies each of the printer-uri attributes of
+the member printers and classes. Each URI corresponds to the same element of
+the member-names attribute.
+
+</body>
+</html>
diff --git a/doc/help/spec-pdf.html b/doc/help/spec-pdf.html
new file mode 100644
index 000000000..407f47887
--- /dev/null
+++ b/doc/help/spec-pdf.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<!-- SECTION: Specifications -->
+<HEAD>
+ <TITLE>CUPS PDF Format</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">CUPS PDF Format</H1>
+
+<P>CUPS PDF files (application/vnd.cups-pdf) are device-dependent
+PDF/A files that contain a job ticket information. These files
+are typically produced by the CUPS <CODE>pdftopdf</CODE> filter
+which handles job ticket generation, imposition, page labeling,
+scaling, and other formatting options requested by the user. CUPS
+PDF files are intended for direct consumption by a PDF-capable
+printer, PDF RIP, or the <CODE>pdftops</CODE> filter.</P>
+
+<P>More information will be posted here as the PDF workflow
+filters are added to CUPS.</P>
+
+</BODY>
+</HTML>
diff --git a/doc/help/spec-postscript.html b/doc/help/spec-postscript.html
new file mode 100644
index 000000000..3aa99c412
--- /dev/null
+++ b/doc/help/spec-postscript.html
@@ -0,0 +1,148 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Specifications -->
+<head>
+ <title>Generating PostScript for CUPS</title>
+ <meta name='keywords' content='Programming, PostScript, Document Structuring Conventions'>
+ <link rel='stylesheet' type='text/css' href='../cups-printable.css'>
+</head>
+<body>
+<!--
+ "$Id: spec-postscript.html 9727 2011-04-28 21:20:12Z mike $"
+
+ CUPS PostScript file specification for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 2006 by Easy Software Products.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<H1 CLASS="title">Generating PostScript for CUPS</H1>
+
+<h2 class='title'><a name='INTRODUCTION'>Introduction</a></h2>
+
+<p>This document describes how to generate PostScript output for
+CUPS and is largely based on the <a
+href="http://partners.adobe.com/public/developer/en/ps/5001.DSC_Spec.pdf">
+Adobe TechNote #5001: PostScript Language Document Structuring
+Conventions Specification Version 3.0</a>. While CUPS can
+generally print any PostScript file, following the rules in the
+Adobe TechNote and this document will ensure that your PostScript
+output will work reliably.</p>
+
+<blockquote><b>Note:</b> While PostScript is currently the
+de-facto standard print job file format/language for UNIX-based
+applications, it is slowly being phased out in favor of Adobe's
+Portable Document Format ("PDF") which offers many advantages
+over PostScript. Mac OS X uses PDF as the primary print job file
+format and Linux is making the transition. Both PostScript and
+PDF are complex formats, and we highly recommend using high-level
+toolkits whenever possible to create your print jobs.</blockquote>
+
+<h3>Anatomy of a PostScript File</h3>
+
+<p>PostScript files are ASCII text files starting with a header
+line (<tt>%!PS-Adobe-3.0</tt>) followed by a combination of
+comment lines starting with the percent sign (<tt>%</tt>) and
+PostScript code lines. The lines themselves should not exceed 255
+characters to conform to the DSC. The following short PostScript
+file produces a box with a smiley face in it:</p>
+
+<pre class="command">
+%!PS-Adobe-3.0
+%%BoundingBox: 36 36 576 756
+%%Pages: 1
+%%LanguageLevel: 2
+%%EndComments
+%%BeginSetup
+% this is where fonts would be embedded
+%%EndSetup
+%%Page: (1) 1
+%%BeginPageSetup
+% this is where page-specific features would be specified
+%%EndPageSetup
+% Draw a black box around the page
+0 setgray
+1 setlinewidth
+36 36 540 720 rectstroke
+
+% Draw a two inch blue circle in the middle of the page
+0 0 1 setrgbcolor
+306 396 144 0 360 arc closepath fill
+
+% Draw two half inch yellow circles for eyes
+1 1 0 setrgbcolor
+252 432 36 0 360 arc closepath fill
+360 432 36 0 360 arc closepath fill
+
+% Draw the smile
+1 setlinecap
+18 setlinewidth
+306 396 99 200 340 arc stroke
+
+% Print it!
+showpage
+%%EOF
+</pre>
+
+<div class="figure"><table summary="Sample PostScript File Output">
+<caption>Figure 1: <a name="FIGURE_1">Sample PostScript File Output</a></caption>
+<tr><td align="center"><img src="../images/smiley.jpg"
+width="445" height="570" alt="Sample PostScript File Output"></td></tr>
+</table></div>
+
+
+<h2><a name='OPTIONS'>Embedding Printer Options</a></h2>
+
+<p>There are two main strategies for embedding printer options in PostScript
+files. The first is to list CUPS options using the <code>%cupsJobTicket</code>
+comment:</p>
+
+<pre>
+%!PS-Adobe-3.0
+%cupsJobTicket: media=A4 sides=two-sided-long-edge
+%cupsJobTicket: PrinterOption=foo PrinterOption2=bar
+...
+%%EndComments
+</pre>
+
+<p>CUPS options apply to the entire job. To apply options to individual pages,
+use the <code>%%IncludeFeature</code> comment instead:</p>
+
+<pre>
+%%Page: label 123
+%%BeginPageSetup
+%%IncludeFeature: *PageSize A4
+%%IncludeFeature: *PrinterOption Foo
+%%IncludeFeature: *PrinterOption2 Bar
+%%EndPageSetup
+...
+</pre>
+
+
+<h2><a name='FONTS'>Embedding Fonts and Text</a></h2>
+
+<p>Always embed the fonts used by your print job, and for best performance
+embed the fonts and character encodings in the setup section of the PostScript
+file. Type 1 and Type 3 fonts are supported by all PostScript printers, while
+Type 42 (TrueType) and CID fonts are supported by most level 2 and all level 3
+PostScript printers. Binary font files should always be converted to the
+corresponding ASCII (hex) encoding to avoid problems when printing over
+interfaces that do not support binary PostScript.</p>
+
+
+<h2><a name='IMAGES'>Embedding Images</a></h2>
+
+<p>The <code>image</code> operator should be used to embed images in PostScript
+files. Always use ASCII hex or Base-85 encoding for the image data to avoid
+problems when printing over interfaces that do not support binary PostScript.
+In most cases, the Base-85 encoding and compression filters can be used to
+embed images with very little, if any, increase in data size.</p>
+
+</body>
+</html>
diff --git a/doc/help/spec-ppd.html b/doc/help/spec-ppd.html
new file mode 100644
index 000000000..c94d8b3a0
--- /dev/null
+++ b/doc/help/spec-ppd.html
@@ -0,0 +1,2342 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- SECTION: Specifications -->
+<head>
+ <title>CUPS PPD Extensions </title>
+ <meta name="keywords" content="Specifications">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="creator" content="Mini-XML v2.7">
+<style type="text/css"><!--
+BODY {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+ font-family: monaco, courier, monospace;
+ font-weight: bold;
+}
+
+PRE {
+ font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+ border: dotted thin #7f7f7f;
+ margin-left: 36pt;
+ padding: 10px;
+}
+
+P.compact {
+ margin: 0;
+}
+
+P.example {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+PRE.example {
+ background: #eeeeee;
+ border: dotted thin #999999;
+ margin-left: 36pt;
+ padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+ font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+ font-family: monaco, courier, monospace;
+ margin-left: 36pt;
+}
+
+P.formula {
+ font-style: italic;
+ margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+ background: #eeeeee;
+ border: solid thin #999999;
+ padding: 10pt;
+}
+
+A IMG {
+ border: none;
+}
+
+A:link:hover IMG {
+ background: #f0f0f0;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+ font-weight: normal;
+ text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+ text-decoration: underline;
+}
+
+SUB, SUP {
+ font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+ margin-top: 10pt;
+ padding: 5pt;
+ border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+ border-bottom: solid 1pt #999999;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+}
+
+DIV.table TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table CAPTION {
+ caption-side: top;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.table TABLE TD {
+ border: solid thin #cccccc;
+ padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+ background: #cccccc;
+ border: none;
+ border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+DIV.figure CAPTION {
+ caption-side: bottom;
+ font-size: 120%;
+ font-style: italic;
+ font-weight: bold;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+TH.label {
+ text-align: right;
+ vertical-align: top;
+}
+
+TH.sublabel {
+ text-align: right;
+ font-weight: normal;
+}
+
+HR {
+ border: solid thin;
+}
+
+SPAN.info {
+ background: black;
+ border: thin solid black;
+ color: white;
+ font-size: 80%;
+ font-style: italic;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+ float: right;
+ font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+ border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+ margin-top: 2em;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.indent {
+ border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+ padding: 0;
+}
+
+TABLE.list {
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+
+TABLE.list TH {
+ background: white;
+ border-bottom: solid thin #cccccc;
+ color: #444444;
+ padding-top: 10pt;
+ padding-left: 5pt;
+ text-align: left;
+ vertical-align: bottom;
+ white-space: nowrap;
+}
+
+TABLE.list TH A {
+ color: #4444cc;
+}
+
+TABLE.list TD {
+ border-bottom: solid thin #eeeeee;
+ padding-top: 5pt;
+ padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+ background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+ background: #f4f4f4;
+}
+
+DT {
+ margin-left: 36pt;
+ margin-top: 12pt;
+}
+
+DD {
+ margin-left: 54pt;
+}
+
+DL.category DT {
+ font-weight: bold;
+}
+
+P.summary {
+ margin-left: 36pt;
+ font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+ border: solid thin #999999;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+ border: solid thin #999999;
+ padding: 5px;
+ text-align: left;
+ vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+ background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+ margin: 0;
+}
+div.body h2 {
+ margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+ margin-bottom: 0.5em;
+ margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+ border-bottom: solid thin #999999;
+ margin-bottom: 0;
+ margin-top: 2em;
+}
+.description {
+ margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+ font-family: monaco, courier, monospace;
+ font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+ list-style-type: none;
+ margin: 0;
+ padding-left: 0;
+}
+ul.code li {
+ margin: 0;
+}
+ul.contents > li {
+ margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+ padding-left: 2em;
+}
+div.body dl {
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dt {
+ font-style: italic;
+ margin-left: 0;
+ margin-top: 0;
+}
+div.body dd {
+ margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+ background: #e8e8e8;
+ border: solid thin black;
+ padding: 10px;
+}
+div.contents h1 {
+ font-size: 110%;
+}
+div.contents h2 {
+ font-size: 100%;
+}
+div.contents ul.contents {
+ font-size: 80%;
+}
+div.contents ul.subcontents li {
+ margin-left: 1em;
+ text-indent: -1em;
+}
+--></style>
+</head>
+<body>
+<div class='body'>
+<!--
+ "$Id: spec-ppd.html 9740 2011-05-04 06:26:22Z mike $"
+
+ PPD extension documentation for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2007 by Easy Software Products.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<H1 CLASS="title">CUPS PPD Extensions</H1>
+
+<p>This specification describes the attributes and extensions that CUPS adds to <a href="http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf" target="_blank">Adobe TechNote #5003: PostScript Printer Description File Format Specification Version 4.3</a>. PostScript Printer Description ("PPD") files describe the capabilities of each printer and are used by CUPS to support printer-specific features and intelligent filtering.</p>
+
+<div class='summary'><table summary='General Information'>
+<tbody>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='postscript-driver.html'>Developing PostScript Printer Drivers</a><br>
+ Programming: <a href='raster-driver.html'>Developing Raster Printer Drivers</a><br>
+ Programming: <a href='api-filter.html'>Filter and Backend Programming</a><br>
+ Programming: <a href='ppd-compiler.html'>Introduction to the PPD Compiler</a><br>
+ Programming: <a href='api-raster.html'>Raster API</a><br>
+ References: <a href='ref-ppdcfile.html'>PPD Compiler Driver Information File Reference</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#SYNTAX">PPD File Syntax</a></li>
+<li><a href="#AUTOCONFIG">Auto-Configuration</a><ul class="subcontents">
+ <li><a href="#APAutoSetupTool">APAutoSetupTool</a></li>
+ <li><a href="#QUERYKEYWORD">?MainKeyword</a></li>
+ <li><a href="#OID">OIDMainKeyword</a></li>
+</ul></li>
+<li><a href="#PROFILES">Color Profiles</a><ul class="subcontents">
+ <li><a href="#cupsColorProfile">cupsColorProfile</a></li>
+ <li><a href="#cupsICCProfile">cupsICCProfile</a></li>
+ <li><a href="#APCustom">Custom Color Matching Support</a></li>
+</ul></li>
+<li><a href="#CONSTRAINTS">Constraints</a><ul class="subcontents">
+ <li><a href="#cupsUIConstraints">cupsUIConstraints</a></li>
+ <li><a href="#cupsUIResolver">cupsUIResolver</a></li>
+</ul></li>
+<li><a href="#I18N">Globalized PPD Support</a></li>
+<li><a href="#OPTIONS">CUPS 1.3/Mac OS X 10.6Custom Options</a></li>
+<li><a href="#RASTERPS">Writing PostScript Option Commands for Raster Drivers</a></li>
+<li><a href="#MEDIA">Media Keywords</a><ul class="subcontents">
+ <li><a href="#cupsMediaQualifier2">cupsMediaQualifier2</a></li>
+ <li><a href="#cupsMediaQualifier3">cupsMediaQualifier3</a></li>
+ <li><a href="#cupsMinSize">cupsMinSize</a></li>
+ <li><a href="#cupsMaxSize">cupsMaxSize</a></li>
+</ul></li>
+<li><a href="#ATTRIBUTES">General Attributes</a><ul class="subcontents">
+ <li><a href="#cupsBackSide">cupsBackSide</a></li>
+ <li><a href="#cupsCommands">cupsCommands</a></li>
+ <li><a href="#cupsEvenDuplex">cupsEvenDuplex</a></li>
+ <li><a href="#cupsFax">cupsFax</a></li>
+ <li><a href="#cupsFilter">cupsFilter</a></li>
+ <li><a href="#cupsFilter2">cupsFilter2</a></li>
+ <li><a href="#cupsFlipDuplex">cupsFlipDuplex</a></li>
+ <li><a href="#cupsIPPFinishings">cupsIPPFinishings</a></li>
+ <li><a href="#cupsIPPReason">cupsIPPReason</a></li>
+ <li><a href="#cupsIPPSupplies">cupsIPPSupplies</a></li>
+ <li><a href="#cupsLanguages">cupsLanguages</a></li>
+ <li><a href="#cupsManualCopies">cupsManualCopies</a></li>
+ <li><a href="#cupsMarkerName">cupsMarkerName</a></li>
+ <li><a href="#cupsMarkerNotice">cupsMarkerNotice</a></li>
+ <li><a href="#cupsModelNumber">cupsModelNumber</a></li>
+ <li><a href="#cupsPJLCharset">cupsPJLCharset</a></li>
+ <li><a href="#cupsPJLDisplay">cupsPJLDisplay</a></li>
+ <li><a href="#cupsPortMonitor">cupsPortMonitor</a></li>
+ <li><a href="#cupsPreFilter">cupsPreFilter</a></li>
+ <li><a href="#cupsPrintQuality">cupsPrintQuality</a></li>
+ <li><a href="#cupsSingleFile">cupsSingleFile</a></li>
+ <li><a href="#cupsSNMPSupplies">cupsSNMPSupplies</a></li>
+ <li><a href="#cupsVersion">cupsVersion</a></li>
+</ul></li>
+<li><a href="#MACOSX">Mac OS X Attributes</a><ul class="subcontents">
+ <li><a href="#APDialogExtension">APDialogExtension</a></li>
+ <li><a href="#APDuplexRequiresFlippedMargin">APDuplexRequiresFlippedMargin</a></li>
+ <li><a href="#APHelpBook">APHelpBook</a></li>
+ <li><a href="#APICADriver">APICADriver</a></li>
+ <li><a href="#APPrinterIconPath">APPrinterIconPath</a></li>
+ <li><a href="#APPrinterLowInkTool">APPrinterLowInkTool</a></li>
+ <li><a href="#APPrinterPreset">APPrinterPreset</a></li>
+ <li><a href="#APPrinterUtilityPath">APPrinterUtilityPath</a></li>
+ <li><a href="#APScannerOnly">APScannerOnly</a></li>
+ <li><a href="#APScanAppBundleID">APScanAppBundleID</a></li>
+</ul></li>
+<li><a href="#HISTORY">Change History</a></li>
+</ul>
+<h2 class='title'><a name='SYNTAX'>PPD File Syntax</a></h2>
+
+<p>The PPD format is text-based and uses lines of up to 255 characters terminated by a carriage return, linefeed, or combination of carriage return and line feed. The following ABNF definition [<a href="http://tools.ietf.org/html/rfc5234" target="_blank">RFC5234</a>] defines the general format of lines in a PPD file:</p>
+
+<pre class='command'>
+PPD-FILE = HEADER +(DATA / COMMENT / LINE-END)
+
+HEADER = "*PPD-Adobe:" *WSP DQUOTE VERSION DQUOTE LINE-END
+
+VERSION = "4.0" / "4.1" / "4.2" / "4.3"
+
+COMMENT = "*%" *TCHAR LINE-END
+
+DATA = "*" 1*KCHAR [ WSP 1*KCHAR [ "/" 1*TCHAR ] ] ":"
+ 1*(*WSP VALUE) LINE-END
+
+VALUE = 1*TCHAR / DQUOTE 1*SCHAR DQUOTE
+
+KCHAR = ALPHA / DIGIT / "_" / "." / "-"
+
+SCHAR = LINE-END / WSP / %x21.23-7E.A0-FF
+
+TCHAR = %x20-7E.A0-FF
+
+LINE-END = CR / LF / CR LF
+</pre>
+
+
+<h2 class='title'><a name='AUTOCONFIG'>Auto-Configuration</a></h2>
+
+<p>CUPS supports several methods of auto-configuration via PPD keywords.</p>
+
+<h3><span class='info'>Mac OS X 10.5</span><a name='APAutoSetupTool'>APAutoSetupTool</a></h3>
+
+<p class='summary'>*APAutoSetupTool: "/LibraryPrinters/vendor/filename"</p>
+
+<p>This Mac OS X keyword defines a program that sets the default option choices. It is run when a printer is added from the <var>Add Printer</var> window or the <var>Nearby Printers</var> list in the <var>Print</var> dialog.</p>
+
+<p>The program is provided with two arguments: the printer's device URI and the PPD file to be used for the printer. The program must write an updated PPD file to stdout.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Use our setup tool when adding a printer
+*APAutoSetupTool: "/Library/Printers/vendor/Tools/autosetuptool"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.2/CUPS 1.4</span><a name='QUERYKEYWORD'>?MainKeyword</a></h3>
+
+<p class='summary'>*?<i>MainKeyword</i>: "<br>
+ PostScript query code that writes a message using the = operator...<br>
+"<br>
+*End</p>
+
+<p>The <tt>?<i>MainKeyword</i></tt> keyword defines PostScript code that determines the currently selected/enabled option keyword (choice) for the main keyword (option). It is typically used when communicating with USB, serial, Appletalk, and AppSocket (port 9100) printers.</p>
+
+<p>The PostScript code typically sends its response back using the <tt>=</tt> operator.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+*OpenUI OptionDuplex/Duplexer Installed: Boolean
+*DuplexOptionDuplex: False
+*OptionDuplex False/Not Installed: ""
+*OptionDuplex True/Installed: ""
+
+<em>*% Query the printer for the presence of the duplexer option...</em>
+*?OptionDuplex: "
+ currentpagedevice /Duplex known
+ {(True)} {(False)} ifelse
+ = flush
+"
+*End
+*CloseUI: OptionDuplex
+</pre>
+
+<h3><span class='info'>Mac OS X 10.4/CUPS 1.5</span><a name='OID'>OIDMainKeyword</a></h3>
+
+<p class='summary'>*?OID<i>MainKeyword</i>: ".n.n.n..."<br>
+*OID<i>MainKeyword</i> <i>OptionKeyword1</i>: "value"<br>
+...<br>
+*OID<i>MainKeyword</i> <i>OptionKeywordN</i>: "value"</p>
+
+<p>The <tt>OID<i>MainKeyword</i></tt> keyword is used to define SNMP OIDs that map to installable options. The first (query) line defines the OID to lookup on the network device. The second and subsequent keywords define a mapping from OID value to option keyword. Since SNMP is an IP-based network protocol, this method is typically only used to configure AppSocket, IPP, and LPD network printers.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Get the installed memory on the printer...
+*?OIDInstalledMemory: ".1.3.6.1.2.1.25.2.2.0"
+*OIDInstalledMemory 16MB: "16384 KBytes"
+*OIDInstalledMemory 32MB: "32768 KBytes"
+*OIDInstalledMemory 48MB: "49152 KBytes"
+*OIDInstalledMemory 72MB: "73728 KBytes"
+</pre>
+
+
+<h2 class='title'><a name='PROFILES'>Color Profiles</a></h2>
+
+<p>CUPS supports three types of color profiles. The first type is based on sRGB and is used by the standard CUPS raster filters and GPL Ghostscript. The second type is based on ICC profiles and is used by the Quartz-based filters on MacOS X. The final type is based on well-known colorspaces such as sRGB and Adobe RGB.</p>
+
+<blockquote><b>Note:</b>
+
+<p>At this time, none of the CUPS raster filters support ICC profiles. This will be addressed as time and resources permit.</p>
+
+</blockquote>
+
+<h3><span class='info'>Deprecated</span><a name='cupsColorProfile'>cupsColorProfile</a></h3>
+
+<p class='summary'>*cupsColorProfile Resolution/MediaType: "density gamma m00 m01 m02 m10 m11 m12 m20 m21 m22"</p>
+
+<p>This string keyword specifies an sRGB-based color profile consisting of gamma and density controls and a 3x3 CMY color transform matrix. <em>This keyword is not supported on Mac OS X.</em></p>
+
+<p>The <i>Resolution</i> and <i>MediaType</i> values may be "-" to act as a wildcard. Otherwise they must match one of the <tt>Resolution</tt> or <tt>MediaType</tt> option keywords defined in the PPD file.</p>
+
+<p>The <i>density</i> and <i>gamma</i> values define gamma and
+density adjustment function such that:</p>
+
+<pre class='command'>
+f(x) = density * x <sup style='font-size: 100%'>gamma</sup>
+</pre>
+
+<p>The <i>m00</i> through <i>m22</i> values define a 3x3 transformation matrix for the CMY color values. The density function is applied <i>after</i> the CMY transformation:</p>
+
+<pre class='command'>
+| m00 m01 m02 |
+| m10 m11 m12 |
+| m20 m21 m22 |
+</pre>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify a profile for printing at 360dpi on all media types</em>
+*cupsColorProfile 360dpi/-: "1.0 1.5 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
+
+<em>*% Specify a profile for printing at 720dpi on Glossy media</em>
+*cupsColorProfile 720dpi/Glossy: "1.0 2.5 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
+
+<em>*% Specify a default profile for printing at all other resolutions and media types</em>
+*cupsColorProfile -/-: "0.9 2.0 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
+</pre>
+
+
+<h3><span class='info'>Mac OS X 10.3/CUPS 1.2</span><a name='cupsICCProfile'>cupsICCProfile</a></h3>
+
+<p class='summary'>*cupsICCProfile ColorModel.MediaType.Resolution/Description: "filename"</p>
+
+<p>This keyword specifies an ICC color profile that is used to convert the document colors to the device colorspace. The <tt>ColorModel</tt>, <tt>MediaType</tt>, and <tt>Resolution</tt> option keywords specify a selector for color profiles. If omitted, the color profile will match any option keyword for the corresponding main keyword.</p>
+
+<p>The <tt>Description</tt> specifies human-readable text that is associated with the color profile. The <tt>filename</tt> portion specifies the ICC color profile to use; if the filename is not absolute, it is loaded relative to the <var>/usr/share/cups/profiles</var> directory.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify a profile for CMYK printing at 360dpi on all media types</em>
+*cupsICCProfile CMYK..360dpi/360dpi CMYK: "/Library/Printers/vendor/Profiles/foo-360-cmyk.icc"
+
+<em>*% Specify a profile for RGB printing at 720dpi on Glossy media</em>
+*cupsColorProfile RGB.Glossy.720dpi/720dpi Glossy: "/Library/Printers/vendor/Profiles/foo-720-glossy-rgb.icc"
+
+<em>*% Specify a default profile for printing at all other resolutions and media types</em>
+*cupsICCProfile ../Default: "/Library/Printers/vendor/Profiles/foo-default.icc"
+</pre>
+
+<h4>Customizing the Profile Selection Keywords</h4>
+
+<p>The <tt>MediaType</tt> and <tt>Resolution</tt> main keywords can be reassigned to different main keywords, allowing drivers to do color profile selection based on different parameters. The <tt>cupsICCQualifier2</tt> and <tt>cupsICCQualifier3</tt> keywords define the mapping from selector to main keyword:</p>
+
+<pre class='command'>
+*cupsICCQualifier2: MainKeyword2
+*cupsICCQualifier3: MainKeyword3
+</pre>
+
+<p>The default mapping is as follows:</p>
+
+<pre class='command'>
+*cupsICCQualifier2: MediaType
+*cupsICCQualifier3: Resolution
+</pre>
+
+<h3><span class='info'>Mac OS X 10.4</span><a name='APCustom'>Custom Color Matching Support</a></h3>
+
+<p class='summary'>*<a href='#APSupportsCustomColorMatching'>APSupportsCustomColorMatching</a>: true<br>
+*<a href='#APCustomColorMatchingName'>APCustomColorMatchingName</a> name/text: ""<br>
+*<a href='#APCustomColorMatchingProfile'>APCustomColorMatchingProfile</a>: profile<br>
+*<a href='#APDefaultCustomColorMatchingProfile'>APDefaultCustomColorMatchingProfile</a>: profile</p>
+
+<p>These keywords tell the Mac OS X raster filters that the printer driver provides its own custom color matching and that generic color profiles should be used when generating 1-, 3-, and 4-component raster data as requested by the driver. The <tt>APCustomColorMatchingProfile</tt> and <tt>APDefaultColorMatchingProfile</tt> keywords specify alternate color profiles (sRGB or AdobeRGB) to use for 3-color (RGB) raster data.</p>
+
+<blockquote><b>Note:</b>
+
+<p>Prior to Mac OS X 10.6, the default RGB color space was Apple's "GenericRGB". The new default in Mac OS X 10.6 and later is "sRGB". For more information, see <a href="http://support.apple.com/kb/HT3712">"Mac OS X v10.6: About gamma 2.2"</a> on Apple's support site.</p>
+
+</blockquote>
+
+<h4><span class='info'>Mac OS X 10.5</span><a name='APCustomColorMatchingName'>APCustomColorMatchingName</a></h4>
+
+<p class='summary'>*APCustomColorMatchingName name/text: ""</p>
+
+<p>This keyword defines an alternate name for the color matching provided by a driver in the <var>Color Matching</var> print panel. The default is to use the name "Vendor Matching" or its localized equivalent.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Define the names for our color matching...
+*APCustomColorMatchingName name/AcmeColor(tm): ""
+*fr.APCustomColorMatchingName name/La AcmeColor(tm): ""
+</pre>
+
+<h4><span class='info'>Mac OS X 10.5</span><a name='APCustomColorMatchingProfile'>APCustomColorMatchingProfile</a></h4>
+
+<p class='summary'>*APCustomColorMatchingProfile: name</p>
+
+<p>This keyword defines a supported RGB color profile that can be used when doing custom color matching. Currently only <tt>sRGB</tt>, <tt>AdobeRGB</tt>, and <tt>GenericRGB</tt> are supported. If not specified, RGB data will use the GenericRGB colorspace.</p>
+
+<blockquote><b>Note:</b>
+
+<p>If you provide multiple <tt>APCustomColorMatchingProfile</tt> keywords, you are responsible for providing the necessary user interface controls to select the profile in a <a href='#APDialogExtension'>print dialog pane</a>. Add the named profile to the print settings using the key <tt>kPMCustomColorMatchingProfileKey</tt>.</p>
+
+</blockquote>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Use sRGB for RGB color by default, but support both sRGB and AdobeRGB
+*APSupportsCustomColorMatching: true
+*APDefaultCustomColorMatchingProfile: sRGB
+*APCustomColorMatchingProfile: sRGB
+*APCustomColorMatchingProfile: AdobeRGB
+</pre>
+
+<h4><span class='info'>Mac OS X 10.5</span><a name='APDefaultCustomColorMatchingProfile'>APDefaultCustomColorMatchingProfile</a></h4>
+
+<p class='summary'>*APDefaultCustomColorMatchingProfile: name</p>
+
+<p>This keyword defines the default RGB color profile that will be used when doing custom color matching. Currently only <tt>sRGB</tt>, <tt>AdobeRGB</tt>, and <tt>GenericRGB</tt> are supported.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Use sRGB for RGB color by default
+*APSupportsCustomColorMatching: true
+*APDefaultCustomColorMatchingProfile: sRGB
+</pre>
+
+<h4><span class='info'>Mac OS X 10.4</span><a name='APSupportsCustomColorMatching'>APSupportsCustomColorMatching</a></h4>
+
+<p class='summary'>*APSupportsCustomColorMatching: boolean</p>
+
+<p>This keyword specifies that the driver provides its own custom color matching. When <tt>true</tt>, the default hand-off colorspace will be GenericGray, GenericRGB, or GenericCMYK depending on the number of components the driver requests. The <a href='#APDefaultCustomColorMatchingProfile'><tt>APDefaultCustomColorMatchingProfile</tt></a> keyword can be used to override the default 3-component (RGB) colorspace.</p>
+
+<p>The default for <tt>APSupportsCustomColorMatching</tt> is <tt>false</tt>.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APSupportsCustomColorMatching: true
+*APDefaultCustomColorMatchingProfile: sRGB
+</pre>
+
+
+<h2 class='title'><a name='CONSTRAINTS'>Constraints</a></h2>
+
+<p>Constraints are option choices that are not allowed by the driver or device, for example printing 2-sided transparencies. All versions of CUPS support constraints defined by the legacy Adobe <tt>UIConstraints</tt> and <tt>NonUIConstraints</tt> keywords which support conflicts between any two option choices, for example:</p>
+
+<pre class='command'>
+*% Do not allow 2-sided printing on transparency media
+*UIConstraints: "*Duplex *MediaType Transparency"
+*UIConstraints: "*MediaType Transparency *Duplex"
+</pre>
+
+<p>While nearly all constraints can be expressed using these keywords, there are valid scenarios requiring constraints between more than two option choices. In addition, resolution of constraints is problematic since users and software have to guess how a particular constraint is best resolved.</p>
+
+<p>CUPS 1.4 and higher define two new keywords for constraints, <tt>cupsUIConstraints</tt> and <tt>cupsUIResolver</tt>. Each <tt>cupsUIConstraints</tt> keyword points to a <tt>cupsUIResolver</tt> keyword which specifies alternate options that resolve the conflict condition. The same <tt>cupsUIResolver</tt> can be used by multiple <tt>cupsUIConstraints</tt>.</p>
+
+<blockquote><b>Note:</b>
+
+<p>When developing PPD files that contain constraints, it is very important to use the <a href="man-cupstestppd.html">cupstestppd(1)</a> program to verify that your constraints are accurate and cannot result in unresolvable option selections.</p>
+
+</blockquote>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsUIConstraints'>cupsUIConstraints</a></h3>
+
+<p class='summary'>*cupsUIConstraints resolver: "*Keyword1 *Keyword2 ..."<br>
+*cupsUIConstraints resolver: "*Keyword1 OptionKeyword1 *Keyword2 ..."<br>
+*cupsUIConstraints resolver: "*Keyword1 *Keyword2 OptionKeyword2 ..."<br>
+*cupsUIConstraints resolver: "*Keyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."<br>
+*cupsUIConstraints: "*InstallableKeyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."</p>
+
+<p>Lists two or more options which conflict. The "resolver" string is a (possibly unique) keyword which specifies which options to change when the constraint exists. When no resolver is provided, CUPS first tries the default choice followed by testing each option choice to resolve the conflict.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify that 2-sided printing cannot happen on transparencies</em>
+*cupsUIConstraints transparency: "*Duplex *MediaType Transparency"
+
+<em>*% Specify that envelope printing cannot happen from the paper trays</em>
+*cupsUIConstraints envelope: "*PageSize Env10 *InputSlot Tray1"
+*cupsUIConstraints envelope: "*PageSize Env10 *InputSlot Tray1"
+*cupsUIConstraints envelope: "*PageSize EnvDL *InputSlot Tray2"
+*cupsUIConstraints envelope: "*PageSize EnvDL *InputSlot Tray2"
+
+<em>*% Specify an installable option constraint for the envelope feeder</em>
+*cupsUIConstraints: "*InputSlot EnvFeeder *InstalledEnvFeeder"
+
+<em>*% Specify that photo printing cannot happen on plain paper or transparencies at 1200dpi</em>
+*cupsUIConstraints photo: "*OutputMode Photo *MediaType Plain *Resolution 1200dpi"
+*cupsUIConstraints photo: "*OutputMode Photo *MediaType Transparency *Resolution 1200dpi"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsUIResolver'>cupsUIResolver</a></h3>
+
+<p class='summary'>*cupsUIResolver resolver: "*Keyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."</p>
+
+<p>Specifies two or more options to mark/select to resolve a constraint. The "resolver" string identifies a particular action to take for one or more <a href='#cupsUIConstraints'><tt>cupsUIConstraints</tt></a>. The same action can be used for multiple constraints. The option keyword pairs are treated as an ordered list of option selections to try - only the first N selections will be used, where N is the minimum number of selections required. Because <a href="api-ppd.html#cupsResolveConflicts"><code>cupsResolveConflicts()</code></a> will not change the most recent option selection passed to it, at least two options from the constraints must be listed to avoid situations where conflicts cannot be resolved.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify the options to change for the 2-sided transparency constraint</em>
+*cupsUIResolver transparency: "*Duplex None *MediaType Plain"
+
+<em>*% Specify the options to change for the envelope printing constraints. Notice
+*% that we try to change the InputSlot to either the envelope feeder or the
+*% manual feed first, then we change the page size...</em>
+*cupsUIResolver envelope: "*InputSlot EnvFeeder *InputSlot ManualFeed *PageSize Letter"
+
+<em>*% Specify the options to change for the photo printing constraints</em>
+*cupsUIResolver photo: "*OutputMode Best *Resolution 600dpi"
+</pre>
+
+
+<h2 class='title'><a name='I18N'>Globalized PPD Support</a></h2>
+
+<p>CUPS 1.2 and higher adds support for PPD files containing multiple languages by following the following additional rules:</p>
+
+<ol>
+
+ <li>The <tt>LanguageVersion</tt> MUST be <tt>English</tt></li>
+
+ <li>The <tt>LanguageEncoding</tt> MUST be <tt>ISOLatin1</tt></li>
+
+ <li>The <tt>cupsLanguages</tt> keyword MUST be provided and list each of the supported locales in the PPD file</li>
+
+ <li>Main and option keywords MUST NOT exceed 34 (instead of 40) characters to allow room for the locale prefixes in translation keywords</li>
+
+ <li>The main keyword "Translation" MUST NOT be used</li>
+
+ <li>Translation strings included with the main and option keywords MUST NOT contain characters outside the ASCII subset of ISOLatin1 and UTF-8; developers wishing to use characters outside ASCII MUST provide a separate set of English localization keywords for the affected keywords.</li>
+
+ <li>Localizations are specified using a locale prefix of the form "ll" or "ll_CC." where "ll" is the 2-letter ISO language code and "CC" is the 2-letter ISO country code<ul>
+ <li>A generic language translation ("ll") SHOULD be provided with country-specific differences ("ll_CC") provided only as needed</li>
+ <li>For historical reasons, the "zh" and "zh_CN" locales map to Simplified Chinese while the "zh_TW" locale maps to Traditional Chinese</li>
+ </ul></li>
+
+ <li>Locale-specific translation strings MUST be encoded using UTF-8.</li>
+
+ <li>Main keywords MUST be localized using one of the following forms:
+ <p><tt>*ll.Translation MainKeyword/translation text: ""</tt><br />
+ <tt>*ll_CC.Translation MainKeyword/translation text: ""</tt></p></li>
+
+ <li>Option keywords MUST be localized using one of the following forms:
+ <p><tt>*ll.MainKeyword OptionKeyword/translation text: ""</tt><br>
+ <tt>*ll_CC.MainKeyword OptionKeyword/translation text: ""</tt></p></li>
+
+ <li>Localization keywords MAY appear anywhere after the first line of the PPD file</li>
+
+</ol>
+
+<blockquote><b>Note:</b>
+
+<p>We use a <tt>LanguageEncoding</tt> value of <tt>ISOLatin1</tt> and limit the allowed base translation strings to ASCII to avoid character coding issues that would otherwise occur. In addition, requiring the base translation strings to be in English allows for easier fallback translation when no localization is provided in the PPD file for a given locale.</p>
+
+</blockquote>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*LanguageVersion: English
+*LanguageEncoding: ISOLatin1
+*cupsLanguages: "de fr_CA"
+*ModelName: "Foobar Laser 9999"
+
+<em>*% Localize ModelName for French and German</em>
+*fr_CA.Translation ModelName/La Foobar Laser 9999: ""
+*de.Translation ModelName/Foobar LaserDrucken 9999: ""
+
+*cupsIPPReason com.vendor-error/A serious error occurred: "/help/com.vendor/error.html"
+<em>*% Localize printer-state-reason for French and German</em>
+*fr_CA.cupsIPPReason com.vendor-error/Une erreur s&egrave;rieuse s'est produite: "/help/com.vendor/error.html"
+*de.cupsIPPReason com.vendor-error/Eine ernste St&ouml;rung trat: "/help/com.vendor/error.html"
+
+...
+
+*OpenUI *InputSlot/Paper Source: PickOne
+*OrderDependency: 10 AnySetup *InputSlot
+*DefaultInputSlot: Auto
+<em>*% Localize InputSlot for French and German</em>
+*fr_CA.Translation InputSlot/Papier source: ""
+*de.Translation InputSlot/Papiereinzug: ""
+*InputSlot Auto/Default: "&lt;&lt;/ManualFeed false&gt;&gt;setpagedevice"
+<em>*% Localize InputSlot=Auto for French and German</em>
+*fr_CA.InputSlot Auto/Par Defaut: ""
+*de.InputSlot Auto/Standard: ""
+*InputSlot Manual/Manual Feed: "&lt;&lt;/ManualFeed true&gt;&gt;setpagedevice"
+<em>*% Localize InputSlot=Manual for French and German</em>
+*fr_CA.InputSlot Manual/Manuel mecanisme de alimentation: ""
+*de.InputSlot Manual/Manueller Einzug: ""
+*CloseUI: *InputSlot
+</pre>
+
+
+<h2 class='title'><a name='OPTIONS'><span class="info">CUPS 1.3/Mac OS X 10.6</span>Custom Options</a></h2>
+
+<p>CUPS supports custom options using an extension of the <tt>CustomPageSize</tt> and <tt>ParamCustomPageSize</tt> syntax:</p>
+
+<pre class='command'>
+*CustomFoo True: "command"
+*ParamCustomFoo Name1/Text 1: order type minimum maximum
+*ParamCustomFoo Name2/Text 2: order type minimum maximum
+...
+*ParamCustomFoo NameN/Text N: order type minimum maximum
+</pre>
+
+<p>When the base option is part of the <tt>JCLSetup</tt> section, the "command" string contains JCL commands with "\order" placeholders for each numbered parameter. The CUPS API handles any necessary value quoting for HP-PJL commands. For example, if the JCL command string is "@PJL SET PASSCODE=\1" and the first
+option value is "1234" then CUPS will output the string "@PJL SET PASSCODE=1234".</p>
+
+<p>For non-<tt>JCLSetup</tt> options, the "order" value is a number from 1 to N and specifies the order of values as they are placed on the stack before the command. For example, if the PostScript command string is "&lt;&lt;/cupsReal1 2 1 roll&gt;&gt;setpagedevice" and the option value is "2.0" then CUPS will output the string "2.0 &lt;&lt;/cupsReal1 2 1 roll&gt;&gt;setpagedevice".</p>
+
+<p>The "type" is one of the following keywords:</p>
+
+<ul>
+
+ <li><tt>curve</tt> - a real value from "minimum" to "maximum" representing a gamma correction curve using the function: f(x) = x <sup>value</sup></li>
+
+ <li><tt>int</tt> - an integer value from "minimum" to "maximum"</li>
+
+ <li><tt>invcurve</tt> - a real value from "minimum" to "maximum" representing a gamma correction curve using the function: f(x) = x <sup>1 / value</sup></li>
+
+ <li><tt>passcode</tt> - a string of numbers value with a minimum of "minimum" numbers and a maximum of "maximum" numbers ("minimum" and "maximum" are numbers and passcode strings are not displayed in the user interface)</li>
+
+ <li><tt>password</tt> - a string value with a minimum of "minimum" characters and a maximum of "maximum" characters ("minimum" and "maximum" are numbers and password strings are not displayed in the user interface)</li>
+
+ <li><tt>points</tt> - a measurement value in points from "minimum" to "maximum"</li>
+
+ <li><tt>real</tt> - a real value from "minimum" to "maximum"</li>
+
+ <li><tt>string</tt> - a string value with a minimum of "minimum" characters and a maximum of "maximum" characters ("minimum" and "maximum" are numbers)</li>
+
+</ul>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Base JCL key code option</em>
+*JCLOpenUI JCLPasscode/Key Code: PickOne
+*OrderDependency: 10 JCLSetup *JCLPasscode
+*DefaultJCLPasscode: None
+*JCLPasscode None/No Code: ""
+*JCLPasscode 1111: "@PJL SET PASSCODE = 1111&lt;0A&gt;"
+*JCLPasscode 2222: "@PJL SET PASSCODE = 2222&lt;0A&gt;"
+*JCLPasscode 3333: "@PJL SET PASSCODE = 3333&lt;0A&gt;"
+*JCLCloseUI: *JCLPasscode
+
+<em>*% Custom JCL key code option</em>
+*CustomJCLPasscode True: "@PJL SET PASSCODE = \1&lt;0A&gt;"
+*ParamCustomJCLPasscode Code/Key Code: 1 passcode 4 4
+
+
+<em>*% Base PostScript watermark option</em>
+*OpenUI WatermarkText/Watermark Text: PickOne
+*OrderDependency: 10 AnySetup *WatermarkText
+*DefaultWatermarkText: None
+*WatermarkText None: ""
+*WatermarkText Draft: "&lt;&lt;/cupsString1(Draft)&gt;&gt;setpagedevice"
+*CloseUI: *WatermarkText
+
+<em>*% Custom PostScript watermark option</em>
+*CustomWatermarkText True: "&lt;&lt;/cupsString1 3 -1 roll&gt;&gt;setpagedevice"
+*ParamCustomWatermarkText Text: 1 string 0 32
+
+
+<em>*% Base PostScript gamma/density option</em>
+*OpenUI GammaDensity/Gamma and Density: PickOne
+*OrderDependency: 10 AnySetup *GammaDensity
+*DefaultGammaDensity: Normal
+*GammaDensity Normal/Normal: "&lt;&lt;/cupsReal1 1.0/cupsReal2 1.0&gt;&gt;setpagedevice"
+*GammaDensity Light/Lighter: "&lt;&lt;/cupsReal1 0.9/cupsReal2 0.67&gt;&gt;setpagedevice"
+*GammaDensity Dark/Darker: "&lt;&lt;/cupsReal1 1.1/cupsReal2 1.5&gt;&gt;setpagedevice"
+*CloseUI: *GammaDensity
+
+<em>*% Custom PostScript gamma/density option</em>
+*CustomGammaDensity True: "&lt;&lt;/cupsReal1 3 -1 roll/cupsReal2 5 -1&gt;&gt;setpagedevice"
+*ParamCustomGammaDensity Gamma: 1 curve 0.1 10
+*ParamCustomGammaDensity Density: 2 real 0 2
+</pre>
+
+
+<h2 class='title'><a name='RASTERPS'>Writing PostScript Option Commands for Raster Drivers</a></h2>
+
+<p>PPD files are used for both PostScript and non-PostScript printers. For CUPS raster drivers, you use a subset of the PostScript language to set page device keywords such as page size, resolution, and so forth. For example, the following code sets the page size to A4 size:</p>
+
+<pre class='command'>
+*PageSize A4: "&lt;&lt;/PageSize[595 842]&gt;&gt;setpagedevice"
+</pre>
+
+<p>Custom options typically use other operators to organize the values into a key/value dictionary for <tt>setpagedevice</tt>. For example, our previous <tt>CustomWatermarkText</tt> option code uses the <tt>roll</tt> operator to move the custom string value into the dictionary for <tt>setpagedevice</tt>:</p>
+
+<pre class='command'>
+*CustomWatermarkText True: "&lt;&lt;/cupsString1 3 -1 roll&gt;&gt;setpagedevice"
+</pre>
+
+<p>For a custom string value of "My Watermark", CUPS will produce the following PostScript code for the option:</p>
+
+<pre class='command'>
+(My Watermark)
+&lt;&lt;/cupsString1 3 -1 roll&gt;&gt;setpagedevice
+</pre>
+
+<p>The code moves the string value ("My Watermark") from the bottom of the stack to the top, creating a dictionary that looks like:</p>
+
+<pre class='command'>
+&lt;&lt;/cupsString1(My Watermark)&gt;&gt;setpagedevice
+</pre>
+
+<p>The resulting dictionary sets the page device attributes that are sent to your raster driver in the page header.</p>
+
+<h3>Custom Page Size Code</a></h3>
+
+<p>There are many possible implementations of the <tt>CustomPageSize</tt> code. For CUPS raster drivers, the following code is recommended:</p>
+
+<pre class='command'>
+*ParamCustomPageSize Width: 1 points <i>min-width max-width</i>
+*ParamCustomPageSize Height: 2 points <i>min-height max-height</i>
+*ParamCustomPageSize WidthOffset: 3 points 0 0
+*ParamCustomPageSize HeightOffset: 4 points 0 0
+*ParamCustomPageSize Orientation: 5 int 0 0
+*CustomPageSize True: "pop pop pop &lt;&lt;/PageSize[5 -2 roll]/ImagingBBox null&gt;&gt;setpagedevice"
+</pre>
+
+<h3>Supported PostScript Operators</a></h3>
+
+<p>CUPS supports the following PostScript operators in addition to the usual PostScript number, string (literal and hex-encoded), boolean, null, and name values:</p>
+
+<ul>
+
+ <li><tt>&lt;&lt;</tt> - Start a dictionary.</li>
+
+ <li><tt>&gt;&gt;</tt> - End a dictionary.</li>
+
+ <li><tt>[</tt> - Start an array.</li>
+
+ <li><tt>]</tt> - End an array.</li>
+
+ <li><tt>copy</tt> - Copy the top N objects on the stack.</li>
+
+ <li><tt>dup</tt> - Copy the top object on the stack.</li>
+
+ <li><tt>index</tt> - Copy the Nth from the top object on the stack.</li>
+
+ <li><tt>pop</tt> - Pop the top object on the stack.</li>
+
+ <li><tt>roll</tt> - Shift the top N objects on the stack.</li>
+
+ <li><tt>setpagedevice</tt> - Set the page header values according to the key/value dictionary on the stack.</li>
+
+</ul>
+
+<blockquote><b>Note:</b>
+
+<p><em>Never</em> use the unsupported <tt>dict</tt> or <tt>put</tt>
+operators in your option code. These operators are typically used in
+option code dating back to Level 1 PostScript printers, which did not
+support the simpler <tt>&lt;&lt;</tt> or <tt>&gt;&gt;</tt> operators.
+If you have old option code using <tt>dict</tt> or <tt>put</tt>, you can
+rewrite it very easily to use the newer <tt>&lt;&lt;</tt> and
+<tt>&gt;&gt;</tt> operators instead. For example, the following code
+to set the page size:</p>
+
+<style type='text/css'><!--
+PRE B {
+ background: #000000;
+ color: #ffffff;
+ padding: 2px 5px;
+}
+--></style>
+
+<pre class='command'>
+<b>1 dict dup</b> /PageSize [612 792] <b>put</b> setpagedevice
+</pre>
+
+<p>can be rewritten as:</p>
+
+<pre class='command'>
+<b>&lt;&lt;</b> /PageSize [612 792] <b>&gt;&gt;</b> setpagedevice
+</pre>
+
+</blockquote>
+
+<h3>Supported Page Device Attributes</a></h3>
+
+<p>Table 2 shows the supported page device attributes along with PostScript code examples.</p>
+
+<div class='table'>
+<table summary='Supported Page Device Attributes'>
+<caption>Table 2: <a name='TABLE_2'>Supported Page Device Attributes</a></caption>
+<thead>
+<tr>
+ <th>Name(s)</th>
+ <th>Type</th>
+ <th>Description</th>
+ <th>Example(s)</th>
+</tr>
+</thead>
+<tbody>
+<tr valign='top'>
+ <td><tt>AdvanceDistance</tt></td>
+ <td>Integer</td>
+ <td>Specifies the number of points to advance roll media after printing.</td>
+ <td><tt>&lt;&lt;/AdvanceDistance 18&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>AdvanceMedia</tt></td>
+ <td>Integer</td>
+ <td>Specifies when to advance the media: 0 = never, 1 = after the file, 2 = after the job, 3 = after the set, and 4 = after the page.</td>
+ <td><tt>&lt;&lt;/AdvanceMedia 4&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>Collate</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether collated copies are required.</td>
+ <td><tt>&lt;&lt;/Collate true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>CutMedia</tt></td>
+ <td>Integer</td>
+ <td>Specifies when to cut the media: 0 = never, 1 = after the file, 2 = after the job, 3 = after the set, and 4 = after the page.</td>
+ <td><tt>&lt;&lt;/CutMedia 1&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>Duplex</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether 2-sided printing is required.</td>
+ <td><tt>&lt;&lt;/Duplex true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>HWResolution</tt></td>
+ <td>Integer Array</td>
+ <td>Specifies the resolution of the page image in pixels per inch.</td>
+ <td><tt>&lt;&lt;/HWResolution[1200 1200]&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>InsertSheet</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether to insert a blank sheet before the job.</td>
+ <td><tt>&lt;&lt;/InsertSheet true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>Jog</tt></td>
+ <td>Integer</td>
+ <td>Specifies when to shift the media in the output bin: 0 = never, 1 = after the file, 2 = after the job, 3 = after the set, and 4 = after the page.</td>
+ <td><tt>&lt;&lt;/Jog 2&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>LeadingEdge</tt></td>
+ <td>Integer</td>
+ <td>Specifies the leading edge of the media: 0 = top, 1 = right, 2 = bottom, 3 = left.</td>
+ <td><tt>&lt;&lt;/LeadingEdge 0&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>ManualFeed</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether media should be drawn from the manual feed tray. Note: The <tt>MediaPosition</tt> attribute is preferred over the <tt>ManualFeed</tt> attribute.</td>
+ <td><tt>&lt;&lt;/ManualFeed true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>MediaClass</tt></td>
+ <td>String</td>
+ <td>Specifies a named media.</td>
+ <td><tt>&lt;&lt;/MediaClass (Invoices)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>MediaColor</tt></td>
+ <td>String</td>
+ <td>Specifies the color of the media.</td>
+ <td><tt>&lt;&lt;/MediaColor &gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>MediaPosition</tt></td>
+ <td>Integer</td>
+ <td>Specifies the tray or source of the media.</td>
+ <td><tt>&lt;&lt;/MediaPosition 12&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>MediaType</tt></td>
+ <td>String</td>
+ <td>Specifies the general media type.</td>
+ <td><tt>&lt;&lt;/MediaType (Glossy)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>MediaWeight</tt></td>
+ <td>Integer</td>
+ <td>Specifies the media weight in grams per meter<sup>2</sup>.</td>
+ <td><tt>&lt;&lt;/MediaWeight 100&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>MirrorPrint</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether to flip the output image horizontally.</td>
+ <td><tt>&lt;&lt;/MirrorPrint true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>NegativePrint</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether to invert the output image.</td>
+ <td><tt>&lt;&lt;/NegativePrint true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>NumCopies</tt></td>
+ <td>Integer</td>
+ <td>Specifies the number of copies to produce of each page.</td>
+ <td><tt>&lt;&lt;/NumCopies 100&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>Orientation</tt></td>
+ <td>Integer</td>
+ <td>Specifies the orientation of the output: 0 = portrait, 1 = landscape rotated counter-clockwise, 2 = upside-down, 3 = landscape rotated clockwise.</td>
+ <td><tt>&lt;&lt;/Orientation 3&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>OutputFaceUp</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether to place the media face-up in the output bin/tray.</td>
+ <td><tt>&lt;&lt;/OutputFaceUp true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>OutputType</tt></td>
+ <td>String</td>
+ <td>Specifies the output type name.</td>
+ <td><tt>&lt;&lt;/OutputType (Photo)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>PageSize</tt></td>
+ <td>Integer/Real Array</td>
+ <td>Specifies the width and length/height of the page in points.</td>
+ <td><tt>&lt;&lt;/PageSize[595 842]&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>Separations</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether to produce color separations.</td>
+ <td><tt>&lt;&lt;/Separations true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>TraySwitch</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether to switch trays automatically.</td>
+ <td><tt>&lt;&lt;/TraySwitch true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>Tumble</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether the back sides of pages are rotated 180 degrees.</td>
+ <td><tt>&lt;&lt;/Tumble true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsBorderlessScalingFactor</tt></td>
+ <td>Real</td>
+ <td>Specifies the amount to scale the page image dimensions.</td>
+ <td><tt>&lt;&lt;/cupsBorderlessScalingFactor 1.01&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsColorOrder</tt></td>
+ <td>Integer</td>
+ <td>Specifies the order of colors: 0 = chunked, 1 = banded, 2 = planar.</td>
+ <td><tt>&lt;&lt;/cupsColorOrder 0&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsColorSpace</tt></td>
+ <td>Integer</td>
+ <td>Specifies the page image colorspace: 0 = W, 1 = RGB, 2 = RGBA, 3 = K, 4 = CMY, 5 = YMC, 6 = CMYK, 7 = YMCK, 8 = KCMY, 9 = KCMYcm, 10 = GMCK, 11 = GMCS, 12 = White, 13 = Gold, 14 = Silver, 15 = CIE XYZ, 16 = CIE Lab, 17 = RGBW, 32 to 46 = CIE Lab (1 to 15 inks)</td>
+ <td><tt>&lt;&lt;/cupsColorSpace 1 &gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsCompression</tt></td>
+ <td>Integer</td>
+ <td>Specifies a driver compression type/mode.</td>
+ <td><tt>&lt;&lt;/cupsCompression 2&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsInteger0<br>
+ ...<br>
+ cupsInteger15</tt></td>
+ <td>Integer</td>
+ <td>Specifies driver integer values.</td>
+ <td><tt>&lt;&lt;/cupsInteger11 1234&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsMarkerType</tt></td>
+ <td>String</td>
+ <td>Specifies the type of ink/toner to use.</td>
+ <td><tt>&lt;&lt;/cupsMarkerType (Black+Color)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsMediaType</tt></td>
+ <td>Integer</td>
+ <td>Specifies a numeric media type.</td>
+ <td><tt>&lt;&lt;/cupsMediaType 999&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsPageSizeName</tt></td>
+ <td>String</td>
+ <td>Specifies the name of the page size.</td>
+ <td><tt>&lt;&lt;/cupsPageSizeName (A4.Full)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsPreferredBitsPerColor</tt></td>
+ <td>Integer</td>
+ <td>Specifies the preferred number of bits per color, typically 8 or 16.</td>
+ <td><tt>&lt;&lt;/cupsPreferredBitsPerColor 16&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsReal0<br>
+ ...<br>
+ cupsReal15</tt></td>
+ <td>Real</td>
+ <td>Specifies driver real number values.</td>
+ <td><tt>&lt;&lt;/cupsReal15 1.234&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsRenderingIntent</tt></td>
+ <td>String</td>
+ <td>Specifies the color rendering intent.</td>
+ <td><tt>&lt;&lt;/cupsRenderingIntent (AbsoluteColorimetric)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsRowCount</tt></td>
+ <td>Integer</td>
+ <td>Specifies the number of rows of raster data to print on each line for some drivers.</td>
+ <td><tt>&lt;&lt;/cupsRowCount 24&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsRowFeed</tt></td>
+ <td>Integer</td>
+ <td>Specifies the number of rows to feed between passes for some drivers.</td>
+ <td><tt>&lt;&lt;/cupsRowFeed 17&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsRowStep</tt></td>
+ <td>Integer</td>
+ <td>Specifies the number of lines between columns/rows on the print head for some drivers.</td>
+ <td><tt>&lt;&lt;/cupsRowStep 2&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsString0<br>
+ ...<br>
+ cupsString15</tt></td>
+ <td>String</td>
+ <td>Specifies driver string values.</td>
+ <td><tt>&lt;&lt;/cupsString0(String Value)&gt;&gt;setpagedevice</tt></td>
+</tr>
+</tbody>
+</table></div>
+
+
+<h2 class='title'><a name='MEDIA'>Media Keywords</a></h2>
+
+<p>The CUPS media keywords allow drivers to specify alternate custom page
+size limits based on up to two options.</p>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMediaQualifier2'>cupsMediaQualifier2</a></h3>
+
+<p class='summary'>*cupsMediaQualifier2: MainKeyword</p>
+
+<p>This keyword specifies the second option to use for overriding the
+custom page size limits.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMediaQualifier3'>cupsMediaQualifier3</a></h3>
+
+<p class='summary'>*cupsMediaQualifier3: MainKeyword</p>
+
+<p>This keyword specifies the third option to use for overriding the
+custom page size limits.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMinSize'>cupsMinSize</a></h3>
+
+<p class='summary'>*cupsMinSize .Qualifier2.Qualifier3: "width length"<br>
+*cupsMinSize .Qualifier2.: "width length"<br>
+*cupsMinSize ..Qualifier3: "width length"</p>
+
+<p>This keyword specifies alternate minimum custom page sizes in points.
+The <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a> and
+<a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a> keywords
+are used to identify options to use for matching.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMaxSize'>cupsMaxSize</a></h3>
+
+<p class='summary'>*cupsMaxSize .Qualifier2.Qualifier3: "width length"<br>
+*cupsMaxSize .Qualifier2.: "width length"<br>
+*cupsMaxSize ..Qualifier3: "width length"</p>
+
+<p>This keyword specifies alternate maximum custom page sizes in points.
+The <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a> and
+<a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a> keywords
+are used to identify options to use for matching.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+
+<h2 class='title'><a name='ATTRIBUTES'>General Attributes</a></h2>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsBackSide'>cupsBackSide</a></h3>
+
+<p class='summary'>*cupsBackSide: keyword</p>
+
+<p>This keyword requests special handling of the back side of pages
+when doing duplexed (2-sided) output. <a href='#TABLE_1'>Table 1</a>
+shows the supported keyword values for this keyword and their effect
+on the raster data sent to your driver. For example, when <tt>cupsBackSide</tt>
+is <code>Rotated</code> and <tt>Tumble</tt> is <tt>false</tt>, your driver
+will receive print data starting at the bottom right corner of the page, with
+each line going right-to-left instead of left-to-right. The default value is
+<code>Normal</code>.</p>
+
+<blockquote><b>Note:</b>
+
+<p><tt>cupsBackSide</tt> replaces the older <tt>cupsFlipDuplex</tt>
+keyword - if <tt>cupsBackSide</tt> is specified, <tt>cupsFlipDuplex</tt>
+will be ignored.</p>
+
+</blockquote>
+
+<div class='table'>
+<table width='80%' summary='Back Side Raster Coordinate System'>
+<caption>Table 1: <a name='TABLE_1'>Back Side Raster Coordinate System</a></caption>
+<thead>
+<tr>
+ <th>cupsBackSide</th>
+ <th>Tumble Value</th>
+ <th>Image Presentation</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td><code>Normal</code></td>
+ <td><code>false</code></td>
+ <td>Left-to-right, top-to-bottom</td>
+</tr>
+<tr>
+ <td><code>Normal</code></td>
+ <td><code>true</code></td>
+ <td>Left-to-right, top-to-bottom</td>
+</tr>
+<tr>
+ <td><code>ManualTumble</code></td>
+ <td><code>false</code></td>
+ <td>Left-to-right, top-to-bottom</td>
+</tr>
+<tr>
+ <td><code>ManualTumble</code></td>
+ <td><code>true</code></td>
+ <td>Right-to-left, bottom-to-top</td>
+</tr>
+<tr>
+ <td><code>Rotated</code></td>
+ <td><code>false</code></td>
+ <td>Right-to-left, bottom-to-top</td>
+</tr>
+<tr>
+ <td><code>Rotated</code></td>
+ <td><code>true</code></td>
+ <td>Right-to-left, top-to-bottom</td>
+</tr>
+<tr>
+ <td><code>Flipped</code> *</td>
+ <td><code>false</code></td>
+ <td>Left-to-right, bottom-to-top</td>
+</tr>
+<tr>
+ <td><code>Flipped</code> *</td>
+ <td><code>true</code></td>
+ <td>Right-to-left, top-to-bottom</td>
+</tr>
+</tbody>
+</table>
+</div>
+
+<p><em>* - Not supported in Mac OS X 10.5.x and earlier</em></p>
+
+<div class='figure'><table summary='Back side images'>
+<caption>Figure 1: Back side images</caption>
+<tr><td><img src='../images/raster.png' width='624' height='448' alt='Back side images'></td></tr>
+</table></div>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Flip the page image for the back side of duplexed output</em>
+*cupsBackSide: Flipped
+
+<em>*% Rotate the page image for the back side of duplexed output</em>
+*cupsBackSide: Rotated
+</pre>
+
+<p>Also see the related <a href='#APDuplexRequiresFlippedMargin'><tt>APDuplexRequiresFlippedMargin</tt></a>
+keyword.</p>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsCommands'>cupsCommands</a></h3>
+
+<p class='summary'>*cupsCommands: "name name2 ... nameN"</p>
+
+<p>This string keyword specifies the commands that are supported by the
+CUPS command file filter for this device. The command names are separated
+by whitespace.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify the list of commands we support</em>
+*cupsCommands: "AutoConfigure Clean PrintSelfTestPage ReportLevels com.vendor.foo"
+</pre>
+
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsEvenDuplex'>cupsEvenDuplex</a></h3>
+
+<p class='summary'>*cupsEvenDuplex: boolean</p>
+
+<p>This boolean keyword notifies the RIP filters that the
+destination printer requires an even number of pages when 2-sided
+printing is selected. The default value is <code>false</code>.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Always send an even number of pages when duplexing</em>
+*cupsEvenDuplex: true
+</pre>
+
+<h3><a name='cupsFax'>cupsFax</a></h3>
+
+<p class='summary'>*cupsFax: boolean</p>
+
+<p>This boolean keyword specifies whether the PPD defines a facsimile device. The default is <tt>false</tt>.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*cupsFax: true
+</pre>
+
+<h3><a name='cupsFilter'>cupsFilter</a></h3>
+
+<p class='summary'>*cupsFilter: "source/type cost program"</p>
+
+<p>This string keyword provides a conversion rule from the
+given source type to the printer's native format using the
+filter "program". If a printer supports the source type directly,
+the special filter program "-" may be specified.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Standard raster printer driver filter</em>
+*cupsFilter: "application/vnd.cups-raster 100 rastertofoo"
+
+<em>*% Plain text filter</em>
+*cupsFilter: "text/plain 10 texttofoo"
+
+<em>*% Pass-through filter for PostScript printers</em>
+*cupsFilter: "application/vnd.cups-postscript 0 -"
+</pre>
+
+<h3><span class='info'>CUPS 1.5</span><a name='cupsFilter2'>cupsFilter2</a></h3>
+
+<p class='summary'>*cupsFilter2: "source/type destination/type cost program"</p>
+
+<p>This string keyword provides a conversion rule from the given source type to the printer's native format using the filter "program". If a printer supports the source type directly, the special filter program "-" may be specified. The destination type is automatically created as needed and is passed to the filters and backend as the FINAL_CONTENT_TYPE value.</p>
+
+<blockquote><b>Note:</b>
+
+<p>The presence of a single <code>cupsFilter2</code> keyword in the PPD file will hide any <code>cupsFilter</code> keywords from the CUPS scheduler. When using <code>cupsFilter2</code> to provide filters specific for CUPS 1.5 and later, provide a <code>cupsFilter2</code> line for every filter and a <code>cupsFilter</code> line for each filter that is compatible with older versions of CUPS.</p>
+
+</blockquote>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Standard raster printer driver filter</em>
+*cupsFilter2: "application/vnd.cups-raster application/vnd.foo 100 rastertofoo"
+
+<em>*% Plain text filter</em>
+*cupsFilter2: "text/plain application/vnd.foo 10 texttofoo"
+
+<em>*% Pass-through filter for PostScript printers</em>
+*cupsFilter2: "application/vnd.cups-postscript application/postscript 0 -"
+</pre>
+
+<h3><span class='info'>Deprecated</span><a name='cupsFlipDuplex'>cupsFlipDuplex</a></h3>
+
+<p class='summary'>*cupsFlipDuplex: boolean</p>
+
+<p>Due to implementation differences between Mac OS X and Ghostscript,
+the <tt>cupsFlipDuplex</tt> keyword is deprecated. Instead, use
+the <a href='#cupsBackSide'><tt>cupsBackSide</tt></a> keyword to specify
+the coordinate system (pixel layout) of the page data on the back side of
+duplex pages.</p>
+
+<p>The value <code>true</code> maps to a <tt>cupsBackSide</tt> value
+of <code>Rotated</code> on Mac OS X and <code>Flipped</code> with
+Ghostscript.</p>
+
+<p>The default value is <code>false</code>.</p>
+
+<blockquote><b>Note:</b>
+
+<p>Mac OS X drivers that previously used
+<tt>cupsFlipDuplex</tt> may wish to provide both the old and
+new keywords for maximum compatibility, for example:</p>
+
+<pre class='command'>
+*cupsBackSide: Rotated
+*cupsFlipDuplex: true
+</pre>
+
+<p>Similarly, drivers written for other operating systems using
+Ghostscript can use:</p>
+
+<pre class='command'>
+*cupsBackSide: Flipped
+*cupsFlipDuplex: true
+</pre></blockquote>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsIPPFinishings'>cupsIPPFinishings</a></h3>
+
+<p class='summary'>*cupsIPPFinishings number/text: "*Option Choice ..."</p>
+
+<p>This keyword defines a mapping from IPP <code>finishings</code>
+values to PPD options and choices.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*cupsIPPFinishings 4/staple: "*StapleLocation SinglePortrait"
+*cupsIPPFinishings 5/punch: "*PunchMedia Yes *PunchLocation LeftSide"
+*cupsIPPFinishings 20/staple-top-left: "*StapleLocation SinglePortrait"
+*cupsIPPFinishings 21/staple-bottom-left: "*StapleLocation SingleLandscape"
+</pre>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsIPPReason'>cupsIPPReason</a></h3>
+
+<p class='summary'>*cupsIPPReason reason/Reason Text: "optional URIs"</p>
+
+<p>This optional keyword maps custom
+<code>printer-state-reasons</code> keywords that are generated by
+the driver to human readable text. The optional URIs string
+contains zero or more URIs separated by a newline. Each URI can
+be a CUPS server absolute path to a help file under the
+scheduler's <code>DocumentRoot</code> directory, a full HTTP URL
+("http://www.domain.com/path/to/help/page.html"), or any other
+valid URI which directs the user at additional information
+concerning the condition that is being reported.</p>
+
+<p>Since the reason text is limited to 80 characters by the PPD specification,
+longer text strings can be included by URI-encoding the text with the "text"
+scheme, for example "text:some%20text". Multiple <code>text</code> URIs are
+combined (with spaces between each URI) by the <tt>ppdLocalizeIPPReason</tt>
+into a single string that can be displayed to the user.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Map com.vendor-error to text but no page</em>
+*cupsIPPReason com.vendor-error/A serious error occurred: ""
+
+<em>*% Map com.vendor-error to more than 80 characters of text but no page</em>
+*cupsIPPReason com.vendor-error/A serious error occurred: "text:Now%20is%20the%20time
+text:for%20all%20good%20men%20to%20come%20to%20the%20aid%20of%20their%20country."
+
+<em>*% Map com.vendor-error to text and a local page</em>
+*cupsIPPReason com.vendor-error/A serious error occurred: "/help/com.vendor/error.html"
+
+<em>*% Map com.vendor-error to text and a remote page</em>
+*cupsIPPReason com.vendor-error/A serious error occurred: "http://www.vendor.com/help"
+
+<em>*% Map com.vendor-error to text and a local, Apple help book, and remote page</em>
+*APHelpBook: "file:///Library/Printers/vendor/Help.bundle"
+*cupsIPPReason com.vendor-error/A serious error occurred: "/help/com.vendor/error.html
+help:anchor='com.vendor-error'%20bookID=Vendor%20Help
+http://www.vendor.com/help"
+*End
+</pre>
+
+<h3><span class='info'>CUPS 1.5</span><a name='cupsIPPSupplies'>cupsIPPSupplies</a></h3>
+
+<p class='summary'>*cupsIPPSupplies: boolean</p>
+
+<p>This keyword tells the IPP backend whether it should report the current marker-xxx supply attribute values. The default value is <code>True</code>.
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Do not use IPP marker-xxx attributes to report supply levels</em>
+*cupsIPPSupplies: False
+</pre>
+
+<h3><span class='info'>CUPS 1.2/Mac OS X 10.5</span><a name='cupsLanguages'>cupsLanguages</a></h3>
+
+<p class='summary'>*cupsLanguages: "locale list"</p>
+
+<p>This keyword describes which language localizations are
+included in the PPD. The "locale list" string is a space-delimited
+list of locale names ("en", "en_US", "fr_CA", etc.)</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify Canadian, UK, and US English, and Canadian and French French</em>
+*cupsLanguages: "en_CA en_UK en_US fr_CA fr_FR"
+</pre>
+
+<h3><a name='cupsManualCopies'>cupsManualCopies</a></h3>
+
+<p class='summary'>*cupsManualCopies: boolean</p>
+
+<p>This boolean keyword notifies the RIP filters that the
+destination printer does not support copy generation in
+hardware. The default value is <code>false</code>.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Tell the RIP filters to generate the copies for us</em>
+*cupsManualCopies: true
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMarkerName'>cupsMarkerName</a></h3>
+
+<p class='summary'>*cupsMarkerName/Name Text: ""</p>
+
+<p>This optional keyword maps <code>marker-names</code> strings that are
+generated by the driver to human readable text.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Map cyanToner to "Cyan Toner"</em>
+*cupsMarkerName cyanToner/Cyan Toner: ""
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMarkerNotice'>cupsMarkerNotice</a></h3>
+
+<p class='summary'>*cupsMarkerNotice: "disclaimer text"</p>
+
+<p>This optional keyword provides disclaimer text for the supply level
+information provided by the driver, typically something like "supply levels
+are approximate".</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*cupsMarkerNotice: "Supply levels are approximate."
+</pre>
+
+<h3><a name='cupsModelNumber'>cupsModelNumber</a></h3>
+
+<p class='summary'>*cupsModelNumber: number</p>
+
+<p>This integer keyword specifies a printer-specific model
+number. This number can be used by a filter program to adjust
+the output for a specific model of printer.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify an integer for a driver-specific model number</em>
+*cupsModelNumber: 1234
+</pre>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsPJLCharset'>cupsPJLCharset</a></h3>
+
+<p class='summary'>*cupsPJLCharset: "ISO character set name"</p>
+
+<p>This string keyword specifies the character set that is used
+for strings in PJL commands. If not specified, US-ASCII is
+assumed.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify UTF-8 is used in PJL strings</em>
+*cupsPJLCharset: "UTF-8"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsPJLDisplay'>cupsPJLDisplay</a></h3>
+
+<p class='summary'>*cupsPJLDisplay: "what"</p>
+
+<p>This optional keyword specifies which command is used to display the
+job ID, name, and user on the printer's control panel. "What" is either "none"
+to disable this functionality, "job" to use "@PJL JOB DISPLAY", or "rdymsg"
+to use "@PJL RDYMSG DISPLAY". The default is "job".</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Display job information using @PJL SET RDYMSG DISPLAY="foo"</em>
+*cupsPJLDisplay: "rdymsg"
+
+<em>*% Display job information display</em>
+*cupsPJLDisplay: "none"
+</pre>
+
+<h3><span class='info'>CUPS 1.2/Mac OS X 10.5</span><a name='cupsPortMonitor'>cupsPortMonitor</a></h3>
+
+<p class='summary'>*cupsPortMonitor urischeme/Descriptive Text: "port monitor"</p>
+
+<p>This string keyword specifies printer-specific "port
+monitor" filters that may be used with the printer. The CUPS
+scheduler also looks for the <tt>Protocols</tt> keyword to see
+if the <tt>BCP</tt> or <tt>TBCP</tt> protocols are supported. If
+so, the corresponding port monitor ("bcp" and "tbcp",
+respectively) is listed in the printer's
+<tt>port-monitor-supported</tt> keyword.</p>
+
+<p>The "urischeme" portion of the keyword specifies the URI scheme
+that this port monitor should be used for. Typically this is used to
+pre-select a particular port monitor for each type of connection that
+is supported by the printer. The "port monitor" string can be "none"
+to disable the port monitor for the given URI scheme.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify a PostScript printer that supports the TBCP protocol</em>
+*Protocols: TBCP PJL
+
+<em>*% Specify that TBCP should be used for socket connections but not USB</em>
+*cupsPortMonitor socket/AppSocket Printing: "tbcp"
+*cupsPortMonitor usb/USB Printing: "none"
+
+<em>*% Specify a printer-specific port monitor for an Epson USB printer</em>
+*cupsPortMonitor usb/USB Status Monitor: "epson-usb"
+</pre>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsPreFilter'>cupsPreFilter</a></h3>
+
+<p class='summary'>*cupsPreFilter: "source/type cost program"</p>
+
+<p>This string keyword provides a pre-filter rule. The pre-filter
+program will be inserted in the conversion chain immediately
+before the filter that accepts the given MIME type.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% PDF pre-filter</em>
+*cupsPreFilter: "application/pdf 100 mypdfprefilter"
+
+<em>*% PNG pre-filter</em>
+*cupsPreFilter: "image/png 0 mypngprefilter"
+</pre>
+
+
+<h3><span class='info'>CUPS 1.5</span><a name='cupsPrintQuality'>cupsPrintQuality</a></h3>
+
+<p class='summary'>*cupsPrintQuality keyword/text: "code"</p>
+
+<p>This UI keyword defines standard print qualities that directly map from the IPP "print-quality" job template keyword. Standard keyword values are "Draft", "Normal", and "High" which are mapped from the IPP "print-quality" values 3, 4, and 5 respectively. Each <code>cupsPrintQuality</code> option typically sets output mode and resolution parameters in the page device dictionary, eliminating the need for separate (and sometimes confusing) output mode and resolution options.</p>
+
+<blockquote><b>Note:</b>
+
+<p>Unlike all of the other keywords defined in this document, <code>cupsPrintQuality</code> is a UI keyword that MUST be enclosed inside the PPD <code>OpenUI</code> and <code>CloseUI</code> keywords.</p>
+
+</blockquote>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*OpenUI *cupsPrintQuality/Print Quality: PickOne
+*OrderDependency: 10 AnySetup *cupsPrintQuality
+*DefaultcupsPrintQuality: Normal
+*cupsPrintQuality Draft/Draft: "code"
+*cupsPrintQuality Normal/Normal: "code"
+*cupsPrintQuality High/Photo: "code"
+*CloseUI: *cupsPrintQuality
+</pre>
+
+<h3><span class='info'>CUPS 1.5</span><a name='cupsSingleFile'>cupsSingleFile</a></h3>
+
+<p class='summary'>*cupsSingleFile: Boolean</p>
+
+<p>This boolean keyword tells the scheduler whether to print multiple files in a job together or singly. The default is "False" which uses a single instance of the backend for all files in the print job. Setting this keyword to "True" will result in separate instances of the backend for each file in the print job.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Send all print data to a single backend</em>
+*cupsSingleFile: False
+
+<em>*% Send each file using a separate backend</em>
+*cupsSingleFile: True
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsSNMPSupplies'>cupsSNMPSupplies</a></h3>
+
+<p class='summary'>*cupsSNMPSupplies: boolean</p>
+
+<p>This keyword tells the standard network backends whether they should query
+the standard SNMP Printer MIB OIDs for supply levels. The default value is
+<code>True</code>.
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Do not use SNMP queries to report supply levels</em>
+*cupsSNMPSupplies: False
+</pre>
+
+<h3><a name='cupsVersion'>cupsVersion</a></h3>
+
+<p class='summary'>*cupsVersion: major.minor</p>
+
+<p>This required keyword describes which version of the CUPS
+PPD file extensions was used. Currently it must be the string
+"1.0", "1.1", "1.2", or "1.3".</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify a CUPS 1.2 driver</em>
+*cupsVersion: "1.2"
+</pre>
+
+
+<h2 class='title'><a name='MACOSX'>Mac OS X Attributes</a></h2>
+
+<h3><span class='info'>Mac OS X 10.3</span><a name='APDialogExtension'>APDialogExtension</a></h3>
+
+<p class='summary'>*APDialogExtension: "/Library/Printers/vendor/filename.plugin"</p>
+
+<p>This keyword defines additional option panes that are displayed in the
+print dialog. Each keyword adds one or more option panes. See the "OutputBinsPDE"
+example and <a href='http://developer.apple.com/qa/qa2004/qa1352.html'>Apple
+Technical Q&amp;A QA1352</a> for information on writing your own print dialog
+plug-ins.</p>
+
+<blockquote><b>Note:</b>
+
+<p>Starting with Mac OS X 10.5, each plug-in must be compiled "4-way fat"
+(32-bit and 64-bit for both PowerPC and Intel) with garbage collection enabled
+in order to be usable with all applications.</p>
+
+</blockquote>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Add two panes for finishing and driver options
+*APDialogExtension: "/Library/Printers/vendor/finishing.plugin"
+*APDialogExtension: "/Library/Printers/vendor/options.plugin"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.4</span><a name='APDuplexRequiresFlippedMargin'>APDuplexRequiresFlippedMargin</a></h3>
+
+<p class='summary'>*APDuplexRequiresFlippedMargin: boolean</p>
+
+<p>This boolean keyword notifies the RIP filters that the
+destination printer requires the top and bottom margins of the
+<tt>ImageableArea</tt> to be swapped for the back page. The
+default is <tt>true</tt> when <tt>cupsBackSide</tt> is <tt>Flipped</tt>
+and <tt>false</tt> otherwise. <a href='#TABLE_2'>Table 2</a> shows how
+<tt>APDuplexRequiresFlippedMargin</tt> interacts with <tt>cupsBackSide</tt>
+and the <tt>Tumble</tt> page attribute.</p>
+
+<div class='table'>
+<table width='80%' summary='Margin Flipping Modes'>
+<caption>Table 2: <a name='TABLE_2'>Margin Flipping Modes</a></caption>
+<thead>
+<tr>
+ <th>APDuplexRequiresFlippedMargin</th>
+ <th>cupsBackSide</th>
+ <th>Tumble Value</th>
+ <th>Margins</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>false</td>
+ <td>any</td>
+ <td>any</td>
+ <td>Normal</td>
+</tr>
+<tr>
+ <td>any</td>
+ <td>Normal</td>
+ <td>any</td>
+ <td>Normal</td>
+</tr>
+<tr>
+ <td>true</td>
+ <td>ManualDuplex</td>
+ <td>false</td>
+ <td>Normal</td>
+</tr>
+<tr>
+ <td>true</td>
+ <td>ManualDuplex</td>
+ <td>true</td>
+ <td>Flipped</td>
+</tr>
+<tr>
+ <td>true</td>
+ <td>Rotated</td>
+ <td>false</td>
+ <td>Flipped</td>
+</tr>
+<tr>
+ <td>true</td>
+ <td>Rotated</td>
+ <td>true</td>
+ <td>Normal</td>
+</tr>
+<tr>
+ <td>true or unspecified</td>
+ <td>Flipped</td>
+ <td>any</td>
+ <td>Flipped</td>
+</tr>
+</tbody>
+</table></div>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Rotate the back side images</em>
+*cupsBackSide: Rotated
+
+<em>*% Don't swap the top and bottom margins for the back side</em>
+*APDuplexRequiresFlippedMargin: false
+</pre>
+
+<p>Also see the related <a href='#cupsBackSide'><tt>cupsBackSide</tt></a>
+keyword.</p>
+
+<h3><a name='APHelpBook'>APHelpBook</a></h3>
+
+<p class='summary'>*APHelpBook: "bundle URL"</p>
+
+<p>This string keyword specifies the Apple help book bundle to use when
+looking up IPP reason codes for this printer driver. The
+<a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> keyword maps
+"help" URIs to this file.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+*APHelpBook: "file:///Library/Printers/vendor/Help.bundle"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.6</span><a name='APICADriver'>APICADriver</a></h3>
+
+<p class='summary'>*APICADriver: boolean</p>
+
+<p>This keyword specifies whether the device has a matching Image Capture
+Architecture (ICA) driver for scanning. The default is <tt>False</tt>.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APICADriver: True
+*APScanAppBundleID: "com.apple.ImageCaptureApp"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.3</span><a name='APPrinterIconPath'>APPrinterIconPath</a></h3>
+
+<p class='summary'>*APPrinterIconPath: "/Library/Printers/vendor/filename.icns"</p>
+
+<p>This keyword defines the location of a printer icon file to use when
+displaying the printer. The file must be in the Apple icon format.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Apple icon file
+*APPrinterIconPath: "/Library/Printers/vendor/Icons/filename.icns"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.4</span><a name='APPrinterLowInkTool'>APPrinterLowInkTool</a></h3>
+
+<p class='summary'>*APPrinterLowInkTool: "/Library/Printers/vendor/program"</p>
+
+<p>This keyword defines an program that checks the ink/toner/marker levels
+on a printer, returning an XML document with those levels. See the "InkTool"
+example and
+<a href='http://developer.apple.com/technotes/tn2005/tn2144.html'>Apple
+Technical Note TN2144</a> for more information.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Use a vendor monitoring program
+*APPrinterLowInkTool: "/Library/Printers/vendor/Tools/lowinktool"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.5</span><a name='APPrinterPreset'>APPrinterPreset</a></h3>
+
+<p class='summary'>*APPrinterPreset name/text: "*Option Choice ..."</p>
+
+<p>This keyword defines presets for multiple options that show up
+in the print dialog of applications (such as iPhoto) that set the job
+style hint to <tt>NSPrintPhotoJobStyleHint</tt>. Each preset maps to one or
+more pairs of PPD options and choices as well as providing key/value data for
+the application. The following standard preset names are currently defined:</p>
+
+<ul>
+
+ <li><code>General_with_Paper_Auto-Detect</code>; Normal quality general printing with auto-detected media.</li>
+
+ <li><code>General_with_Paper_Auto-Detect_-_Draft</code>; Draft quality general printing with auto-detected media.</li>
+
+ <li><code>General_on_Plain_Paper</code>; Normal quality general printing on plain paper.</li>
+
+ <li><code>General_on_Plain_Paper_-_Draft</code>; Draft quality general printing on plain paper.</li>
+
+ <li><code>Photo_with_Paper_Auto-Detect</code>; Normal quality photo printing with auto-detected media.</li>
+
+ <li><code>Photo_with_Paper_Auto-Detect_-_Fine</code>; High quality photo printing with auto-detected media.</li>
+
+ <li><code>Photo_on_Plain_Paper</code>; Normal quality photo printing on plain paper.</li>
+
+ <li><code>Photo_on_Plain_Paper_-_Fine</code>; High quality photo printing on plain paper.</li>
+
+ <li><code>Photo_on_Photo_Paper</code>; Normal quality photo printing on glossy photo paper.</li>
+
+ <li><code>Photo_on_Photo_Paper_-_Fine</code>; High quality photo printing on glossy photo paper.</li>
+
+ <li><code>Photo_on_Matte_Paper</code>; Normal quality photo printing on matte paper.</li>
+
+ <li><code>Photo_on_Matte_Paper_-_Fine</code>; High quality photo printing on matte paper.</li>
+
+</ul>
+
+<p>The value string consists of pairs of keywords, either an option name and
+choice (*MainKeyword OptionKeyword) or a preset identifier and value
+(com.apple.print.preset.foo value). The following preset identifiers are currently used:</p>
+
+<ul>
+
+ <li><code>com.apple.print.preset.graphicsType</code>; specifies the type of printing used for this printing - "General" for general purpose printing and "Photo" for photo printing.</li>
+
+ <li><code>com.apple.print.preset.media-front-coating</code>; specifies the media type selected by this preset - "none" (plain paper), "glossy", "high-gloss", "semi-gloss", "satin", "matte", and "autodetect".</li>
+
+ <li><code>com.apple.print.preset.output-mode</code>; specifies the output mode for this preset - "color" (default for color printers) or "monochrome" (grayscale, default for B&amp;W printers).</li>
+
+ <li><code>com.apple.print.preset.quality</code>; specifies the overall print quality selected by this preset - "low" (draft), "mid" (normal), or "high".</li>
+
+</ul>
+
+<p>Presets, like options, can also be localized in multiple languages.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APPrinterPreset Photo_on_Photo_Paper/Photo on Photo Paper: "
+ *MediaType Glossy
+ *ColorModel RGB
+ *Resolution 300dpi
+ com.apple.print.preset.graphicsType Photo
+ com.apple.print.preset.quality mid
+ com.apple.print.preset.media-front-coating glossy"
+*End
+*fr.APPrinterPreset Photo_on_Photo_Paper/Photo sur papier photographique: ""
+</pre>
+
+<h3><span class='info'>Mac OS X 10.3</span><a name='APPrinterUtilityPath'>APPrinterUtilityPath</a></h3>
+
+<p class='summary'>*APPrinterPrinterUtilityPath: "/Library/Printers/vendor/filename.app"</p>
+
+<p>This keyword defines a GUI application that can be used to do printer
+maintenance functions such as cleaning the print head(s). See ... for more
+information.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Define the printer utility application
+*APPrinterPrinterUtilityPath: "/Library/Printers/vendor/Tools/utility.app"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.6</span><a name='APScannerOnly'>APScannerOnly</a></h3>
+
+<p class='summary'>*APScannerOnly: boolean</p>
+
+<p>This keyword specifies whether the device has scanning but no printing
+capabilities. The default is <tt>False</tt>.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APICADriver: True
+*APScannerOnly: True
+</pre>
+
+<h3><span class='info'>Mac OS X 10.3</span><a name='APScanAppBundleID'>APScanAppBundleID</a></h3>
+
+<p class='summary'>*APScanAppBundleID: "bundle ID"</p>
+
+<p>This keyword defines the application to use when scanning pages from
+the device.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APICADriver: True
+*APScanAppBundleID: "com.apple.ImageCaptureApp"
+</pre>
+
+
+<h2 class='title'><a name='HISTORY'>Change History</a></h2>
+
+<h3>Changes in CUPS 1.5</h3>
+
+<ul>
+
+ <li>Changes all instances of PPD attributes to PPD keywords, to be consistent with the parent specification from Adobe.</li>
+
+</ul>
+
+
+<h3>Changes in CUPS 1.4.5</h3>
+
+<ul>
+
+ <li>Added <a href='#cupsPrintQuality'><tt>cupsPrintQuality</tt></a> UI keyword.</li>
+
+ <li>Added new properties and values for the <a href='#APPrinterPreset'><tt>APPrinterPreset</tt></a> keyword.</li>
+
+</ul>
+
+
+<h3>Changes in CUPS 1.4</h3>
+
+<ul>
+
+ <li>Added <a href='#APICADriver'><tt>APICADriver</tt></a>
+ keyword.</li>
+
+ <li>Added <a href='#cupsCommands'><tt>cupsCommands</tt></a>
+ keyword.</li>
+
+ <li>Added <a href='#cupsMarkerName'><tt>cupsMarkerName</tt></a>
+ keyword.</li>
+
+ <li>Added <a href='#cupsMarkerNotice'><tt>cupsMarkerNotice</tt></a>
+ keyword.</li>
+
+ <li>Added <a href='#cupsPJLDisplay'><tt>cupsPJLDisplay</tt></a>
+ keyword.</li>
+
+ <li>Added <a href='#cupsSNMPSupplies'><tt>cupsSNMPSupplies</tt></a>
+ keyword.</li>
+
+ <li>Added <a href='#cupsUIResolver'><tt>cupsUIResolver</tt></a> and
+ <a href='#cupsUIConstraints'><tt>cupsUIConstraints</tt></a>
+ keywords.</li>
+
+ <li>Added
+ <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a>,
+ <a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a>,
+ <a href='#cupsMinSize'><tt>cupsMinSize</tt></a>, and
+ <a href='#cupsMaxSize'><tt>cupsMaxSize</tt></a> keywords.</li>
+
+</ul>
+
+
+<h3>Changes in CUPS 1.3.1</h3>
+
+<ul>
+
+ <li>Added missing Mac OS X <tt>AP</tt> keywords.</li>
+
+ <li>Added section on auto-configuration including the
+ <tt>OID<i>MainKeyword</i></tt> and <tt>?<i>MainKeyword</i></tt>
+ keywords.</li>
+
+ <li>Minor reorganization.</li>
+
+</ul>
+
+
+<h3>Changes in CUPS 1.3</h3>
+
+<ul>
+
+ <li>Added <a href='#cupsBackSide'><tt>cupsBackSide</tt></a> and
+ deprecated <a href='#cupsFlipDuplex'><tt>cupsFlipDuplex</tt></a>.</li>
+
+ <li>Added text URI information to
+ <a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> documentation.</li>
+
+ <li>Added <a href='#APPrinterPreset'><tt>APPrinterPreset</tt></a>,
+ <a href='#cupsIPPFinishings'><tt>cupsIPPFinishings</tt></a>, and
+ <a href='#cupsPreFilter'><tt>cupsPreFilter</tt></a> keywords.</li>
+
+ <li>Added discussion of custom option code, sample
+ <tt>CustomPageSize</tt> code, and "do not use dict and put" note.</li>
+
+</ul>
+
+<h3>Changes in CUPS 1.2.8</h3>
+
+<ul>
+
+ <li>Added section on supported PostScript commands for raster
+ drivers</li>
+
+</ul>
+
+<h3>Changes in CUPS 1.2</h3>
+
+<ul>
+
+ <li>Added globalization support keywords</li>
+
+ <li>Added custom option values support</li>
+
+ <li>Added <a href='#APHelpBook'><tt>APHelpBook</tt></a> keyword</li>
+
+ <li>Added <a href='#APDuplexRequiresFlippedMargin'><tt>APDuplexRequiresFlippedMargin</tt></a>
+ keyword</li>
+
+ <li>Added <a href='#cupsICCProfile'><tt>cupsICCProfile</tt></a> keyword</li>
+
+ <li>Added <a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> keyword</li>
+
+ <li>Added <a href='#cupsLanguages'><tt>cupsLanguages</tt></a> keyword</li>
+
+ <li>Added <a href='#cupsPortMonitor'><tt>cupsPortMonitor</tt></a> keyword</li>
+
+ <li>Removed <tt>cupsProtocol</tt> keyword</li>
+
+</ul>
+
+<h3>Changes in CUPS 1.1</h3>
+
+<ul>
+
+ <li>Added <a href='#cupsFlipDuplex'><tt>cupsFlipDuplex</tt></a> keyword</li>
+
+ <li>Added <tt>cupsProtocol</tt> keyword</li>
+
+</ul>
+</div>
+</body>
+</html>
diff --git a/doc/help/spec-raster.html b/doc/help/spec-raster.html
new file mode 100644
index 000000000..50fca220a
--- /dev/null
+++ b/doc/help/spec-raster.html
@@ -0,0 +1,720 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<!-- SECTION: Specifications -->
+<HEAD>
+ <TITLE>CUPS Raster Format</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">CUPS Raster Format</H1>
+
+<P>CUPS Raster files are device-dependent raster image files that contain a PostScript page device dictionary and device-dependent raster imagery for each page in the document. These files are used to transfer raster data from the PostScript and image file RIPs to device-dependent filters that convert the raster data to a printable format.</P>
+
+<P>CUPS 1.0 and 1.1 used version 1 of the raster format. CUPS 1.2 and later use version 2 (compressed) and version 3 (uncompressed) that are a superset of the version 1 raster format. All three versions of CUPS Raster are streamable formats, and applications using the CUPS Imaging API (the cupsRaster* functions) can read all formats without code changes.</P>
+
+<P>The registered MIME media type for CUPS Raster files is <CODE>application/vnd.cups-raster</CODE>.</P>
+
+
+<H2 CLASS="title"><A NAME="ORGANIZATION">Organization of a CUPS Raster File</A></H2>
+
+<P><A HREF="FILEFORMAT">Figure 1, "Raster Organization"</A>, shows the general organization of all CUPS Raster files. Each file begins with a 32-bit synchronization word followed by zero or more pages. Each page consists of a header (the PostScript page device dictionary and raster-specific values) followed by the bitmap image for the page.</P>
+
+<DIV CLASS="figure"><TABLE SUMMARY="Raster Organization">
+<CAPTION><A NAME="FILEFORMAT">Figure 1: Raster Organization</A></CAPTION>
+<TR><TD><IMG SRC="../images/raster-organization.png" WIDTH="446" HEIGHT="1056" ALT="Raster Organization"></TD></TR>
+</TABLE></DIV>
+
+<P>Each page bitmap is stored as described by the <CODE>cupsBitsPerColor</CODE>, <CODE>cupsBytesPerLine</CODE>, <CODE>cupsColorOrder</CODE>, <CODE>cupsColorSpace</CODE>, <CODE>cupsHeight</CODE>, and <CODE>cupsWidth</CODE> values in the page header. Pixels for the front side of a sheet are always stored left-to-right, top-to-bottom. When doing duplex printing, pixels for the back side of a sheet may be stored differently depending on the value of the <CODE>cupsBackSide</CODE> keyword ("Normal", "ManualTumble", "Rotated", or "Flipped") in the PPD file and the <CODE>Tumble</CODE> value ("true" or "false") in the page header. <A HREF="#PAGEBITMAPS">Figure 2, "Page Bitmaps"</A>, shows the pixel order for each combination.</P>
+
+<DIV CLASS="figure"><TABLE SUMMARY="Page Bitmaps">
+<CAPTION><A NAME="PAGEBITMAPS">Figure 2: Page Bitmaps</A></CAPTION>
+<TR><TD><IMG SRC="../images/raster.png" WIDTH="624" HEIGHT="448" ALT="Page Bitmaps"></TD></TR>
+</TABLE></DIV>
+
+
+<H2 CLASS="title"><A NAME="V1">Version 1 Raster File Format</A></H2>
+
+<P>A version 1 raster file begins with a 32-bit synchronization word: 0x52615374 ("RaSt") for big-endian architectures or 0x74536152 ("tSaR") for little-endian architectures. The writer of the raster file will use the native word order, and the reader is responsible for detecting a reversed word order file and swapping bytes as needed. The CUPS Imaging API raster functions perform this function automatically.</P>
+
+<P>Following the synchronization word are a series of raster pages. Each page starts with a page device dictionary header and is followed immediately by the (uncompressed/raw) raster data for that page.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="CUPS Version 1 Raster Page Device Dictionary">
+<CAPTION><A NAME="TABLE1">Table 1: CUPS Version 1 Raster Page Device Dictionary</A></CAPTION>
+<THEAD>
+<TR>
+ <TH>Bytes</TH>
+ <TH>Type</TH>
+ <TH>Description</TH>
+ <TH>Values</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD>0-63</TD>
+ <TD>C String</TD>
+ <TD>MediaClass</TD>
+ <TD>Media class string</TD>
+</TR>
+<TR>
+ <TD>64-127</TD>
+ <TD>C String</TD>
+ <TD>MediaColor</TD>
+ <TD>Media color string</TD>
+</TR>
+<TR>
+ <TD>128-191</TD>
+ <TD>C String</TD>
+ <TD>MediaType</TD>
+ <TD>Media type string</TD>
+</TR>
+<TR>
+ <TD>192-255</TD>
+ <TD>C String</TD>
+ <TD>OutputType</TD>
+ <TD>Output type string</TD>
+</TR>
+<TR>
+ <TD>256-259</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>AdvanceDistance</TD>
+ <TD>0 to 2<SUP>32</SUP> - 1 points</TD>
+</TR>
+<TR>
+ <TD>260-263</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>AdvanceMedia</TD>
+ <TD>0 = Never advance roll<BR>
+ 1 = Advance roll after file<BR>
+ 2 = Advance roll after job<BR>
+ 3 = Advance roll after set<BR>
+ 4 = Advance roll after page</TD>
+</TR>
+<TR>
+ <TD>264-267</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>Collate</TD>
+ <TD>0 = do not collate copies<BR>
+ 1 = collate copies</TD>
+</TR>
+<TR>
+ <TD>268-271</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>CutMedia</TD>
+ <TD>0 = Never cut media<BR>
+ 1 = Cut roll after file<BR>
+ 2 = Cut roll after job<BR>
+ 3 = Cut roll after set<BR>
+ 4 = Cut roll after page</TD>
+</TR>
+<TR>
+ <TD>272-275</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>Duplex</TD>
+ <TD>0 = Print single-sided<BR>
+ 1 = Print double-sided</TD>
+</TR>
+<TR>
+ <TD>276-283</TD>
+ <TD>Unsigned Integers (2)</TD>
+ <TD>HWResolution</TD>
+ <TD>Horizontal and vertical resolution in dots-per-inch.</TD>
+</TR>
+<TR>
+ <TD>284-299</TD>
+ <TD>Unsigned Integers (4)</TD>
+ <TD>ImagingBoundingBox</TD>
+ <TD>Four integers giving the left, bottom, right, and top positions
+ of the page bounding box in points</TD>
+</TR>
+<TR>
+ <TD>300-303</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>InsertSheet</TD>
+ <TD>0 = Do not insert separator sheets<BR>
+ 1 = Insert separator sheets</TD>
+</TR>
+<TR>
+ <TD>304-307</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>Jog</TD>
+ <TD>0 = Do no jog pages<BR>
+ 1 = Jog pages after file<BR>
+ 2 = Jog pages after job<BR>
+ 3 = Jog pages after set</TD>
+</TR>
+<TR>
+ <TD>308-311</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>LeadingEdge</TD>
+ <TD>0 = Top edge is first<BR>
+ 1 = Right edge is first<BR>
+ 2 = Bottom edge is first<BR>
+ 3 = Left edge is first</TD>
+</TR>
+<TR>
+ <TD>312-319</TD>
+ <TD>Unsigned Integers (2)</TD>
+ <TD>Margins</TD>
+ <TD>Left and bottom origin of image in points</TD>
+</TR>
+<TR>
+ <TD>320-323</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>ManualFeed</TD>
+ <TD>0 = Do not manually feed media<BR>
+ 1 = Manually feed media</TD>
+</TR>
+<TR>
+ <TD>324-327</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>MediaPosition</TD>
+ <TD>Input slot position from 0 to N</TD>
+</TR>
+<TR>
+ <TD>328-331</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>MediaWeight</TD>
+ <TD>Media weight in grams per meter squared, 0 = printer default</TD>
+</TR>
+<TR>
+ <TD>332-335</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>MirrorPrint</TD>
+ <TD>0 = Do not mirror prints<BR>
+ 1 = Mirror prints</TD>
+</TR>
+<TR>
+ <TD>336-339</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>NegativePrint</TD>
+ <TD>0 = Do not invert prints<BR>
+ 1 = Invert prints</TD>
+</TR>
+<TR>
+ <TD>340-343</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>NumCopies</TD>
+ <TD>0 to 2<SUP>32</SUP> - 1, 0 = printer default</TD>
+</TR>
+<TR>
+ <TD>344-347</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>Orientation</TD>
+ <TD>0 = Do not rotate page<BR>
+ 1 = Rotate page counter-clockwise<BR>
+ 2 = Turn page upside down<BR>
+ 3 = Rotate page clockwise</TD>
+</TR>
+<TR>
+ <TD>348-351</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>OutputFaceUp</TD>
+ <TD>0 = Output face down<BR>
+ 1 = Output face up</TD>
+</TR>
+<TR>
+ <TD>352-359</TD>
+ <TD>Unsigned Integers (2)</TD>
+ <TD>PageSize</TD>
+ <TD>Width and length in points</TD>
+</TR>
+<TR>
+ <TD>360-363</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>Separations</TD>
+ <TD>0 = Print composite image<BR>
+ 1 = Print color separations</TD>
+</TR>
+<TR>
+ <TD>364-367</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>TraySwitch</TD>
+ <TD>0 = Do not change trays if selected tray is empty<BR>
+ 1 = Change trays if selected tray is empty</TD>
+</TR>
+<TR>
+ <TD>368-371</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>Tumble</TD>
+ <TD>0 = Do not rotate even pages when duplexing<BR>
+ 1 = Rotate even pages when duplexing</TD>
+</TR>
+<TR>
+ <TD>372-375</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>cupsWidth</TD>
+ <TD>Width of page image in pixels</TD>
+</TR>
+<TR>
+ <TD>376-379</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>cupsHeight</TD>
+ <TD>Height of page image in pixels</TD>
+</TR>
+<TR>
+ <TD>380-383</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>cupsMediaType</TD>
+ <TD>Driver-specific 0 to 2<SUP>32</SUP> - 1</TD>
+</TR>
+<TR>
+ <TD>384-387</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>cupsBitsPerColor</TD>
+ <TD>1, 2, 4, 8 bits for version 1 raster files<BR>
+ 1, 2, 4, 8, and 16 bits for version 2/3 raster files</TD>
+</TR>
+<TR>
+ <TD>388-391</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>cupsBitsPerPixel</TD>
+ <TD>1 to 32 bits for version 1 raster files<BR>
+ 1 to 240 bits for version 2/3 raster files</TD>
+</TR>
+<TR>
+ <TD>392-395</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>cupsBytesPerLine</TD>
+ <TD>1 to 2<SUP>32</SUP> - 1 bytes</TD>
+</TR>
+<TR>
+ <TD>396-399</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>cupsColorOrder</TD>
+ <TD>0 = chunky pixels (CMYK CMYK CMYK)<BR>
+ 1 = banded pixels (CCC MMM YYY KKK)<BR>
+ 2 = planar pixels (CCC... MMM... YYY... KKK...)</TD>
+</TR>
+<TR>
+ <TD>400-403</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>cupsColorSpace</TD>
+ <TD>0 = gray (device, typically sRGB-based)<BR>
+ 1 = RGB (device, typically sRGB)<BR>
+ 2 = RGBA (device, typically sRGB)<BR>
+ 3 = black<BR>
+ 4 = CMY<BR>
+ 5 = YMC<BR>
+ 6 = CMYK<BR>
+ 7 = YMCK<BR>
+ 8 = KCMY<BR>
+ 9 = KCMYcm<BR>
+ 10 = GMCK<BR>
+ 11 = GMCS<BR>
+ 12 = WHITE<BR>
+ 13 = GOLD<BR>
+ 14 = SILVER<BR>
+ 15 = CIE XYZ<BR>
+ 16 = CIE Lab<BR>
+ 17 = RGBW (sRGB)<BR>
+ 18 = sGray (gray using sRGB gamma/white point)<BR>
+ 19 = sRGB<BR>
+ 20 = AdobeRGB<BR>
+ 32 = ICC1 (CIE Lab with hint for 1 color)<BR>
+ 33 = ICC2 (CIE Lab with hint for 2 colors)<BR>
+ 34 = ICC3 (CIE Lab with hint for 3 colors)<BR>
+ 35 = ICC4 (CIE Lab with hint for 4 colors)<BR>
+ 36 = ICC5 (CIE Lab with hint for 5 colors)<BR>
+ 37 = ICC6 (CIE Lab with hint for 6 colors)<BR>
+ 38 = ICC7 (CIE Lab with hint for 7 colors)<BR>
+ 39 = ICC8 (CIE Lab with hint for 8 colors)<BR>
+ 40 = ICC9 (CIE Lab with hint for 9 colors)<BR>
+ 41 = ICCA (CIE Lab with hint for 10 colors)<BR>
+ 42 = ICCB (CIE Lab with hint for 11 colors)<BR>
+ 43 = ICCC (CIE Lab with hint for 12 colors)<BR>
+ 44 = ICCD (CIE Lab with hint for 13 colors)<BR>
+ 45 = ICCE (CIE Lab with hint for 14 colors)<BR>
+ 46 = ICCF (CIE Lab with hint for 15 colors)<BR>
+ 48 = Device1 (DeviceN for 1 color)<BR>
+ 49 = Device2 (DeviceN for 2 colors)<BR>
+ 50 = Device3 (DeviceN for 3 colors)<BR>
+ 51 = Device4 (DeviceN for 4 colors)<BR>
+ 52 = Device5 (DeviceN for 5 colors)<BR>
+ 53 = Device6 (DeviceN for 6 colors)<BR>
+ 54 = Device7 (DeviceN for 7 colors)<BR>
+ 55 = Device8 (DeviceN for 8 colors)<BR>
+ 56 = Device9 (DeviceN for 9 colors)<BR>
+ 57 = DeviceA (DeviceN for 10 colors)<BR>
+ 58 = DeviceB (DeviceN for 11 colors)<BR>
+ 59 = DeviceC (DeviceN for 12 colors)<BR>
+ 60 = DeviceD (DeviceN for 13 colors)<BR>
+ 61 = DeviceE (DeviceN for 14 colors)<BR>
+ 62 = DeviceF (DeviceN for 15 colors)
+ </TD>
+</TR>
+<TR>
+ <TD>404-407</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>cupsCompression</TD>
+ <TD>Driver-specific 0 to 2<SUP>32</SUP> - 1</TD>
+</TR>
+<TR>
+ <TD>408-411</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>cupsRowCount</TD>
+ <TD>Driver-specific 0 to 2<SUP>32</SUP> - 1</TD>
+</TR>
+<TR>
+ <TD>412-415</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>cupsRowFeed</TD>
+ <TD>Driver-specific 0 to 2<SUP>32</SUP> - 1</TD>
+</TR>
+<TR>
+ <TD>416-419</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>cupsRowStep</TD>
+ <TD>Driver-specific 0 to 2<SUP>32</SUP> - 1</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+
+<H2 CLASS="title"><A NAME="V2">Version 2 Raster File Format</A></H2>
+
+<P>A version 2 raster file begins with a 32-bit synchronization word: 0x52615332 ("RaS2") for big-endian architectures or 0x32536152 ("2SaR") for little-endian architectures. The writer of the raster file will use the native word order, and the reader is responsible for detecting a reversed word order file and swapping bytes as needed. The CUPS Imaging API raster functions perform this function automatically.</P>
+
+<P>Following the synchronization word are a series of raster pages. Each page starts with a version 2 page device dictionary header and is followed immediately by the compressed raster data for that page.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="CUPS Version 2 Raster Page Device Dictionary">
+<CAPTION><A NAME="TABLE2">Table 2: CUPS Version 2 Raster Page Device Dictionary</A></CAPTION>
+<THEAD>
+<TR>
+ <TH>Bytes</TH>
+ <TH>Type</TH>
+ <TH>Description</TH>
+ <TH>Values</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD>0-419</TD>
+ <TD>Version 1 header data</TD>
+ <TD>See Table 1</TD>
+</TR>
+<TR>
+ <TD>420-423</TD>
+ <TD>Unsigned Integer</TD>
+ <TD>cupsNumColors</TD>
+ <TD>1 to 15 colors</TD>
+</TR>
+<TR>
+ <TD>424-427</TD>
+ <TD>IEEE Single Precision</TD>
+ <TD>cupsBorderlessScalingFactor</TD>
+ <TD>0.0 or 1.0 or greater</TD>
+</TR>
+<TR>
+ <TD>428-435</TD>
+ <TD>IEEE Single Precision (2)</TD>
+ <TD>cupsPageSize</TD>
+ <TD>Width and length in points</TD>
+</TR>
+<TR>
+ <TD>436-451</TD>
+ <TD>IEEE Single Precision (4)</TD>
+ <TD>cupsImagingBBox</TD>
+ <TD>Four floating point numbers giving the left, bottom, right, and top positions of the page bounding box in points</TD>
+</TR>
+<TR>
+ <TD>452-515</TD>
+ <TD>Unsigned Integers (16)</TD>
+ <TD>cupsInteger</TD>
+ <TD>16 driver-defined integer values</TD>
+</TR>
+<TR>
+ <TD>516-579</TD>
+ <TD>IEEE Single Precision (16)</TD>
+ <TD>cupsReal</TD>
+ <TD>16 driver-defined floating point values</TD>
+</TR>
+<TR>
+ <TD>580-1603</TD>
+ <TD>C Strings (16x64)</TD>
+ <TD>cupsString</TD>
+ <TD>16 driver-defined strings</TD>
+</TR>
+<TR>
+ <TD>1604-1667</TD>
+ <TD>C String</TD>
+ <TD>cupsMarkerType</TD>
+ <TD>Ink/toner type string</TD>
+</TR>
+<TR>
+ <TD>1668-1731</TD>
+ <TD>C String</TD>
+ <TD>cupsRenderingIntent</TD>
+ <TD>Color rendering intent string</TD>
+</TR>
+<TR>
+ <TD>1732-1795</TD>
+ <TD>C String</TD>
+ <TD>cupsPageSizeName</TD>
+ <TD>Page size name/keyword string from PPD</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+<H3><A NAME="COMPRESSION">Compressed Raster Data Format</A></H3>
+
+<P>The version 2 raster data is compressed using a PackBits-like algorithm. Lines are grouped into an integral number of color values based upon the <CODE>cupsColorOrder</CODE> setting:</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="Color Value Sizes">
+<CAPTION><A NAME="TABLE3">Table 3: Color Value Sizes</A></CAPTION>
+<TR>
+ <TH>cupsColorOrder</TH>
+ <TH>Bytes per color value</TH>
+</TR>
+<TR>
+ <TD>0 (chunky)</TD>
+ <TD>(<CODE>cupsBitsPerPixel</CODE> + 7) / 8</TD>
+</TR>
+<TR>
+ <TD>1 (banded)</TD>
+ <TD>(<CODE>cupsBitsPerColor</CODE> + 7) / 8</TD>
+</TR>
+<TR>
+ <TD>2 (planar)</TD>
+ <TD>(<CODE>cupsBitsPerColor</CODE> + 7) / 8</TD>
+</TR>
+</TABLE></DIV>
+
+<P>Each line of raster data begins with a repetition count from 1 to 256 that is encoded using a single byte of "count - 1".</P>
+
+<P>After the repetition count, whole color values for that line are run-length encoded using a PackBits-like run-length encoding algorithm: 1 to 128 repeated colors are encoded using an initial byte of "count - 1" followed by the color value byte(s) while 2 to 128 non-repeating colors are encoded using an initial byte of "257 - count" followed by the color value bytes.</P>
+
+<P>For example, the 8x8 24-bit sRGB image shown in <a href="#SAMPLEIMAGE">Figure 3, "Sample Image"</a>, would be encoded as the following 89 octets:</p>
+
+<PRE CLASS="example">
+%x00 %x00.FF.FF.FF %x02.FF.FF.00 %x03.FF.FF.FF
+%x00 %xFE.FF.FF.00.00.00.FF.FF.FF.00 %x02.FF.FF.FF %x00.00.FF.00 %x00.FF.FF.FF
+%x00 %x01.FF.FF.00 %x02.FF.FF.FF %x02.00.FF.00
+%x00 %x02.FF.FF.00 %x02.FF.FF.FF %x00.00.FF.00 %x00.FF.FF.FF
+%x00 %x00.FF.FF.FF %x02.FF.FF.00 %x03.FF.FF.FF
+%x00 %x07.FF.FF.FF
+%x01 %x07.FF.00.00
+</PRE>
+
+<P>The first line (%x00) contains 1 white pixel (%x00.FF.FF.FF), 3 yellow pixels (%x02.FF.FF.00), and 4 white pixels (%x03.FF.FF.FF).</P>
+
+<P>The second line (%x00) contains a sequence of yellow + blue + yellow pixels (%xFE.FF.FF.00.00.00.FF.FF.FF.00), 3 white pixels (%x02.FF.FF.FF), 1 green pixel (%x00.00.FF.00), and 1 white pixel (%x00.FF.FF.FF).</P>
+
+<P>The third line (%x00) contains 2 yellow pixels (%x01.FF.FF.00), 3 white pixels (%x02.FF.FF.FF), and 3 green pixels (%x02.00.FF.00)</P>
+
+<P>The fourth line (%x00) contains 3 yellow pixels (%x02.FF.FF.00), 3 white pixels (%x02.FF.FF.FF), 1 green pixel (%x00.00.FF.00), and 1 white pixel (%x00.FF.FF.FF).</P>
+
+<P>The fifth line (%x00) contains 1 white pixel (%x00.FF.FF.FF), 3 yellow pixels (%x02.FF.FF.00), and 4 white pixels (%x03.FF.FF.FF).</P>
+
+<P>The sixth line (%x00) contains 8 white pixels (%x07.FF.FF.FF).</P>
+
+<P>The seventh and eighth lines (%x01) contain 8 red pixels (%x07.FF.00.00).</P>
+
+<DIV CLASS="figure"><TABLE SUMMARY="Sample Image">
+<CAPTION><A NAME="SAMPLEIMAGE">Figure 3: Sample Image</A></CAPTION>
+<TR><TD><IMG SRC="../images/sample-image.png" WIDTH="257" HEIGHT="257" ALT="Sample Image"></TD></TR>
+</TABLE></DIV>
+
+
+<H2 CLASS="title"><A NAME="V3">Version 3 Raster File Format</A></H2>
+
+<P>A version 3 raster file begins with a 32-bit synchronization word: 0x52615333 ("RaS3") for big-endian architectures and 0x33536152 ("3SaR") for little-endian architectures. The writer of the raster file will use the native word order, and the reader is responsible for detecting a reversed word order file and swapping bytes as needed. The CUPS Imaging API raster functions perform this function automatically.</P>
+
+<P>Following the synchronization word are a series of raster pages. Each page starts with a version 2 page device dictionary header and is followed immediately by the uncompressed/raw raster data for that page.</P>
+
+
+<H2 CLASS="title"><A NAME="ENCODING">Pixel Value Coding</A></H2>
+
+<P>The following sections describe the encoding and decoding of the color values in a CUPS Raster file. In general, colors are packed into the minimum number of bytes, with special consideration provided for efficiency of encoding and access. Multi-byte values are stored in the native byte order and automatically swapped as needed when reading them using the CUPS imaging API.</P>
+
+<H3>CUPS_ORDER_CHUNKED</H3>
+
+<P>The chunked order provides the pixel value packed in a single place. Pixel values with 8 or more bits per color are stored as an array of colors in order, e.g. for <CODE>CUPS_CSPACE_RGB</CODE> you will see 8/16-bits of red, then blue, then green, then red, green, blue, etc. Pixel values with less than 8 bits per color are packed together as shown in Table 4. <I>Multi-byte pixel values are stored in the native word order, just as for 16-bit color values.</I></P>
+
+<DIV CLASS="table"><TABLE SUMMARY="Chunked Color Values">
+<CAPTION><A NAME="TABLE4">Table 4: Chunked Color Values</A></CAPTION>
+<THEAD>
+<TR>
+ <TH>Bits</TH>
+ <TH>1-color</TH>
+ <TH>3-color</TH>
+ <TH>4-color</TH>
+ <TH>6-color</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD>1</TD>
+ <TD>W/W/W/W/W/W/W/W</TD>
+ <TD>0RGB/0RGB</TD>
+ <TD>CMYK/CMYK</TD>
+ <TD>00KCMYcm</TD>
+</TR>
+<TR>
+ <TD>2</TD>
+ <TD>WW/WW/WW/WW</TD>
+ <TD>00RRGGBB</TD>
+ <TD>CCMMYYKK</TD>
+ <TD>N/A</TD>
+</TR>
+<TR>
+ <TD>4</TD>
+ <TD>WWWW/WWWW</TD>
+ <TD>0000RRRRGGGGBBBB<BR>
+ <I>(multi-byte)</I></TD>
+ <TD>CCCCMMMMYYYYKKKK<BR>
+ <I>(multi-byte)</I></TD>
+ <TD>N/A</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+<H3>CUPS_ORDER_BANDED</H3>
+
+<P>The banded order provides each color as a separate line of data. Each color plane for a line is written in sequence, e.g. for the <CODE>CUPS_CSPACE_CMYK</CODE> color space you would see all of the cyan pixels for a line followed by the magenta, yellow, and black pixels for that line. This is repeated for all of the lines on the page. Color values are packed starting with the most-significant bit (MSB) first.</P>
+
+<H3>CUPS_ORDER_PLANAR</H3>
+
+<P>The planar order provides each color as a separate page of data using a shared page header. Each color plane for a page is written in sequence, e.g. for the <CODE>CUPS_CSPACE_CMYK</CODE> color space you would see all of the cyan pixels for a page followed by the magenta, yellow, and black pixels for that page. Color values are packed starting with the most-significant bit (MSB) first. Each line starts on an 8-bit boundary.</P>
+
+<H3>CUPS_CSPACE_RGBW</H3>
+
+<P>This color space provides a dedicated black text channel and uses the sRGB color space definition and white point for the RGB color channels. The white channel is 0 for text (or "true") black, otherwise it must contain the maximum color value: 1 for 1-bit, 3 for 2-bit, 15 for 4-bit, 255 for 8-bit, or 65535 for 16-bit.</P>
+
+<H3>CUPS_CSPACE_KCMYcm</H3>
+
+<P>When <CODE>cupsBitsPerColor</CODE> is 1, 6 color planes are provided - black, cyan, magenta, yellow, light cyan, and light magenta. When <CODE>cupsBitsPerColor</CODE> is greater than 1, 4 color planes are provided using the <CODE>CUPS_CSPACE_KCMY</CODE> color space instead.</P>
+
+<P>When <CODE>cupsColorOrder</CODE> is <CODE>CUPS_ORDER_CHUNKED</CODE>, bit 5 corresponds to black and bit 0 corresponds to light magenta. For <CODE>CUPS_ORDER_BANDED</CODE> and <CODE>CUPS_ORDER_PLANAR</CODE>, each color plane is encoded separately.</P>
+
+<H3>CUPS_CSPACE_CIELab and CUPS_CSPACE_ICCn</H3>
+
+<P>These color spaces map a CIE Lab color value with a D65 white point to either a 8- or 16-bit per color chunked (<CODE>CUPS_ORDER_CHUNKED</CODE>) format; the banded (<CODE>CUPS_ORDER_BANDED</CODE>) and planar (<CODE>CUPS_ORDER_PLANAR</CODE>) color orders are not supported.</P>
+
+<P>The values are encoded and decoded using the following formulas:</P>
+
+<UL>
+
+ <LI>8-bit Encoding:<BR>
+ <I>L8 = 2.55 * L + 0.5<BR>
+ a8 = a + 128.5<BR>
+ b8 = b + 128.5<BR>
+ &nbsp;</I></LI>
+
+ <LI>8-bit Decoding:<BR>
+ <I>L = L8 / 2.55<BR>
+ a = a8 - 128<BR>
+ b = b8 - 128<BR>
+ &nbsp;</I></LI>
+
+ <LI>16-bit Encoding:<BR>
+ <I>L16 = 655.35 * L + 0.5<BR>
+ a16 = 256 * (a + 128) + 0.5<BR>
+ b16 = 256 * (b + 128) + 0.5<BR>
+ &nbsp;</I></LI>
+
+ <LI>16-bit Decoding:<BR>
+ <I>L = L16 / 655.35<BR>
+ a = a16 / 256 - 128<BR>
+ b = b16 / 256 - 128<BR>
+ &nbsp;</I></LI>
+
+</UL>
+
+<H3>CUPS_CSPACE_CIEXYZ</H3>
+
+<P>These color spaces map a CIE XYZ color value with a D65 white point to either a 8- or 16-bit per color chunked (<CODE>CUPS_ORDER_CHUNKED</CODE>) format; the banded (<CODE>CUPS_ORDER_BANDED</CODE>) and planar (<CODE>CUPS_ORDER_PLANAR</CODE>) color orders are not supported.</P>
+
+<P>The values are encoded and decoded using the following formulas:</P>
+
+<UL>
+
+ <LI>8-bit Encoding:<BR>
+ <I>X8 = 231.8181 * X + 0.5<BR>
+ Y8 = 231.8181 * Y + 0.5<BR>
+ Z8 = 231.8181 * Z + 0.5<BR>
+ &nbsp;</I></LI>
+
+ <LI>8-bit Decoding:<BR>
+ <I>X = X8 / 231.8181<BR>
+ Y = Y8 / 231.8181<BR>
+ Z = Z8 / 231.8181<BR>
+ &nbsp;</I></LI>
+
+ <LI>16-bit Encoding:<BR>
+ <I>X16 = 59577.2727 * X + 0.5<BR>
+ Y16 = 59577.2727 * Y + 0.5<BR>
+ Z16 = 59577.2727 * Z + 0.5<BR>
+ &nbsp;</I></LI>
+
+ <LI>16-bit Decoding:<BR>
+ <I>X = X16 / 59577.2727<BR>
+ Y = Y16 / 59577.2727<BR>
+ Z = Z16 / 59577.2727<BR>
+ &nbsp;</I></LI>
+
+</UL>
+
+<P>The scaling factor for XYZ values is 1/1.1, or 231.8181 for 8-bit values and 59577.2727 for 16-bit values. This allows for a slight overflow of XYZ values when converting from RGB, improving accuracy.</P>
+
+
+<H2 CLASS="title"><A NAME="HISTORY">Change History</A></H2>
+
+<H3>Changes in CUPS 1.4.7</H3>
+
+<ul>
+
+ <li>Greatly improved the detail and now include an example of the bitmap compression.</li>
+ <li>Added all missing cupsColorSpace values and a separate description of CUPS_CSPACE_RGBW.</li>
+
+</ul>
+
+
+<H3>Changes in CUPS 1.2.2</H3>
+
+<ul>
+
+ <li>Added version 3 (uncompressed) format.</li>
+
+</ul>
+
+
+<H3>Changes in CUPS 1.2.1</H3>
+
+<ul>
+
+ <li>Added new sections on coding pixel values.</li>
+
+ <li>Clarified definitions of color spaces.</li>
+
+</ul>
+
+
+<H3>Changes in CUPS 1.2</H3>
+
+<ul>
+
+ <li>Bumped raster version to 2</li>
+
+ <li>Added RGBW color space</li>
+
+ <li>Added 16 bit per color support</li>
+
+ <li>Added cupsNumColors, cupsBorderlessScalingFactor, cupsPageSize, cupsImagingBBox, cupsInteger, cupsReal, cupsString, cupsMarkerType, cupsRenderingIntent, and cupsPageSizeName attributes to the page device dictionary</li>
+
+ <li>Added raster data compression</li>
+
+ <li>Added data type column to device dictionary documentation.</li>
+
+</ul>
+
+<h3>Changes in CUPS 1.1.19</h3>
+
+<ul>
+
+ <li>Added ICC and CIE color spaces.</li>
+
+</ul>
+
+</BODY>
+</HTML>
diff --git a/doc/help/spec-stp.html b/doc/help/spec-stp.html
new file mode 100644
index 000000000..06c099b55
--- /dev/null
+++ b/doc/help/spec-stp.html
@@ -0,0 +1,133 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<!-- SECTION: Specifications -->
+<HEAD>
+ <TITLE>CUPS Software Test Plan</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">CUPS Software Test Plan</H1>
+
+<P>This software test plan provides detailed tests that are used
+to evaluate the stability and compliance of CUPS.</P>
+
+
+<H2 CLASS="title"><A NAME="PROCEDURE">Test Procedure</A></H2>
+
+<P>The test software and data files are located in the
+<VAR>test</VAR> subdirectory of the source distribution. A script
+is provided to compile the <CODE>ipptool</CODE> program and run
+all of the tests that follow, producing a success/fail
+report.</P>
+
+<P>The <CODE>test</CODE> target of the top-level makefile can be
+used to run this script:</P>
+
+<PRE CLASS="command">
+make test
+</PRE>
+
+<P>or you can run the test script directly:</P>
+
+<PRE CLASS="command">
+cd test
+./run-stp-tests
+</PRE>
+
+<P>A Software Test Report is stored in a HTML file in the
+<VAR>test</VAR> subdirectory at the conclusion of the test.</P>
+
+
+<H2 CLASS="title"><A NAME="IPP">IPP Compliance Tests</A></H2>
+
+<P>This section describes the tests used to validate the IPP
+standards compliance of the CUPS server.</P>
+
+<H3>Request Tests</H3>
+
+<P>These tests verify that the CUPS scheduler only accepts valid
+IPP requests that start with the <CODE>attributes-charset</CODE>
+and <CODE>attributes-natural-language</CODE> attributes and also
+contain a <CODE>printer-uri</CODE> or <CODE>job-uri</CODE>
+attribute.</P>
+
+<P>It also verifies that the CUPS scheduler always responds with
+<CODE>attributes-charset</CODE> and
+<CODE>attributes-natural-language</CODE> attributes, using
+default values if they are not provided by the client.</P>
+
+<H3>CUPS Printer Operation Tests</H3>
+
+<P>These tests verify that the CUPS printer operations are
+supported and function properly. Two printers called
+<CODE>Test1</CODE> and <CODE>Test2</CODE> are created, one as a
+PostScript printer and one as a raster printer.</P>
+
+<H3>Job Operation Tests</H3>
+
+<P>These test verify that the CUPS scheduler accepts print jobs
+for all supported file formats and that the
+<CODE>cancel-job</CODE>, <CODE>hold-job</CODE>, and
+<CODE>resume-job</CODE> operations work.</P>
+
+<H3>Subscription Operation Tests</H3>
+
+<P>These test verify that the CUPS scheduler accepts
+subscriptions with print jobs and that all subscription
+operations work as required by the IPP notification and mailto
+specifications.</P>
+
+
+<H2 CLASS="title"><A NAME="COMMAND">Command Tests</A></H2>
+
+<P>This section describes the tests used to validate the Berkeley
+and System V commands included with CUPS.</P>
+
+<H3>lpadmin</H3>
+
+<P>This test verifies that printers can be added, modified, and
+defaulted using the <CODE>lpadmin</CODE> command.</P>
+
+<H3>lpc</H3>
+
+<P>This test verifies that the <CODE>lpc</CODE> command can show
+the current status of all print queues.</P>
+
+<H3>lpq</H3>
+
+<P>This test verifies that the <CODE>lpq</CODE> command lists
+any jobs in the queue.</P>
+
+<H3>lpstat</H3>
+
+<P>This test verifies that the <CODE>lpstat</CODE> command works
+with all reports using the "<CODE>-t</CODE>" option.</P>
+
+<H3>lp</H3>
+
+<P>This test verifies that the <CODE>lp</CODE> command works with
+both the default destination and a specific destination.</P>
+
+<H3>lpr</H3>
+
+<P>This test verifies that the <CODE>lpr</CODE> command works
+with both the default destination and a specific destination.</P>
+
+<H3>lprm</H3>
+
+<P>This test verifies that the <CODE>lprm</CODE> command can
+properly cancel a job.</P>
+
+<H3>cancel</H3>
+
+<P>This test verifies that the <CODE>cancel</CODE> command can
+properly cancel a job or all jobs.</P>
+
+<H3>lpinfo</H3>
+
+<P>This test verifies that the <CODE>lpinfo</CODE> command
+returns a list of available printer drivers and devices.</P>
+
+</BODY>
+</HTML>
diff --git a/doc/help/standard.html.in b/doc/help/standard.html.in
new file mode 100644
index 000000000..f957fe249
--- /dev/null
+++ b/doc/help/standard.html.in
@@ -0,0 +1,181 @@
+<HTML>
+<!-- SECTION: Getting Started -->
+<HEAD>
+ <TITLE>Standard Configuration</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">Standard Configuration</H1>
+
+<P>This document describes the standard configuration for this CUPS
+server.</P>
+
+<BLOCKQUOTE><B>Note:</B>
+
+<!-- Packagers: Change the following statement and the following sections
+ if you make any changes to the standard CUPS distribution that are
+ not automatically updated by the configure script. -->
+<P>This file reflects the standard CUPS configuration as distributed
+by Apple Inc, the developer of CUPS.</P>
+
+</BLOCKQUOTE>
+
+
+<H2 CLASS="title"><A NAME="CUPSD">cupsd Configuration</A></H2>
+
+<P><CODE>cupsd(8)</CODE> is configured by default to show
+printers shared by other systems and only allow local access to
+the system and its printers. Administration operations require
+Basic authentication with membership in the group
+"@CUPS_GROUP@".</P>
+
+<P>Connections are accepted via domain socket
+(<VAR>@CUPS_DEFAULT_DOMAINSOCKET@</VAR>) or "localhost"
+(127.0.0.1).</P>
+
+<H3><A NAME="SETTINGS">Settings</A></H3>
+
+<DIV CLASS="table"><TABLE SUMMARY="Default Values">
+<CAPTION>Table 1: Default Values</CAPTION>
+<TR>
+ <TH>Directive</TH>
+ <TH>Value</TH>
+</TR>
+<TR>
+ <TD><CODE><A HREF="ref-cupsd-conf.html#Browsing">Browsing</A></CODE></TD>
+ <TD><CODE>@CUPS_BROWSING@</CODE></TD>
+</TR>
+<TR>
+ <TD><CODE><A HREF="ref-cupsd-conf.html#BrowseLocalProtocols">BrowseLocalProtocols</A></CODE></TD>
+ <TD><CODE>@CUPS_BROWSE_LOCAL_PROTOCOLS@</CODE></TD>
+</TR>
+<TR>
+ <TD><CODE><A HREF="ref-cupsd-conf.html#BrowseRemoteProtocols">BrowseRemoteProtocols</A></CODE></TD>
+ <TD><CODE>@CUPS_BROWSE_REMOTE_PROTOCOLS@</CODE></TD>
+</TR>
+<TR>
+ <TD><CODE><A HREF="ref-cupsd-conf.html#BrowseShortNames">BrowseShortNames</A></CODE></TD>
+ <TD><CODE>@CUPS_BROWSE_SHORT_NAMES@</CODE></TD>
+</TR>
+<TR>
+ <TD><CODE><A HREF="ref-cupsd-conf.html#ConfigFilePerm">ConfigFilePerm</A></CODE></TD>
+ <TD><CODE>@CUPS_CONFIG_FILE_PERM@</CODE></TD>
+</TR>
+<TR>
+ <TD><CODE><A HREF="ref-cupsd-conf.html#DefaultShared">DefaultShared</A></CODE></TD>
+ <TD><CODE>@CUPS_DEFAULT_SHARED@</CODE></TD>
+</TR>
+<TR>
+ <TD><CODE><A HREF="ref-cupsd-conf.html#ImplicitClasses">ImplicitClasses</A></CODE></TD>
+ <TD><CODE>@CUPS_IMPLICIT_CLASSES@</CODE></TD>
+</TR>
+<TR>
+ <TD><CODE><A HREF="ref-cupsd-conf.html#LogFilePerm">LogFilePerm</A></CODE></TD>
+ <TD><CODE>@CUPS_LOG_FILE_PERM@</CODE></TD>
+</TR>
+<TR>
+ <TD><CODE><A HREF="ref-cupsd-conf.html#MaxCopies">MaxCopies</A></CODE></TD>
+ <TD><CODE>@CUPS_MAX_COPIES@</CODE></TD>
+</TR>
+<TR>
+ <TD><CODE><A HREF="ref-cupsd-conf.html#UseNetworkDefault">UseNetworkDefault</A></CODE></TD>
+ <TD><CODE>@CUPS_USE_NETWORK_DEFAULT@</CODE></TD>
+</TR>
+</TABLE></DIV>
+
+
+<H2 CLASS="title"><A NAME="DIRECTORIES">Directories</A></H2>
+
+<DIV CLASS="table"><TABLE SUMMARY="Directories">
+<CAPTION>Table 2: Directories</CAPTION>
+<TR>
+ <TH>Directory</TH>
+ <TH>Purpose</TH>
+</TR>
+<TR>
+ <TD><VAR>@CUPS_SERVERROOT@</VAR></TD>
+ <TD>The location of configuration files such as
+ <VAR>printers.conf</VAR>. Overridden by the <A
+ HREF="ref-cupsd-conf.html#ServerRoot"><CODE>ServerRoot</CODE></A>
+ directive in <VAR>cupsd.conf</VAR>.</TD>
+</TR>
+<TR>
+ <TD><VAR>@bindir@</VAR></TD>
+ <TD>The location of user programs.</TD>
+</TR>
+<TR>
+ <TD><VAR>@includedir@</VAR></TD>
+ <TD>The location of CUPS include files.</TD>
+</TR>
+<TR>
+ <TD><VAR>@libdir@</VAR></TD>
+ <TD>The location of CUPS library files.</TD>
+</TR>
+<TR>
+ <TD><VAR>@CUPS_SERVERBIN@</VAR></TD>
+ <TD>The location of server programs such as backends and
+ filters. Overridden by the <A
+ HREF="ref-cupsd-conf.html#ServerBin"><CODE>ServerBin</CODE></A>
+ directive in <VAR>cupsd.conf</VAR>.</TD>
+</TR>
+<TR>
+ <TD><VAR>@sbindir@</VAR></TD>
+ <TD>The location of administrator programs.</TD>
+</TR>
+<TR>
+ <TD><VAR>@CUPS_DATADIR@</VAR></TD>
+ <TD>The location of data files such as fonts. Overridden
+ by the <A
+ HREF="ref-cupsd-conf.html#DataDir"><CODE>DataDir</CODE></A>
+ directive in <VAR>cupsd.conf</VAR>.</TD>
+</TR>
+<TR>
+ <TD><VAR>@CUPS_DOCROOT@</VAR></TD>
+ <TD>The location of documentation files. Overridden by
+ the <A
+ HREF="ref-cupsd-conf.html#DocumentRoot"><CODE>DocumentRoot</CODE></A>
+ directive in <VAR>cupsd.conf</VAR>.</TD>
+</TR>
+<TR>
+ <TD><VAR>@CUPS_LOCALEDIR@</VAR></TD>
+ <TD>The location of localization files.</TD>
+</TR>
+<TR>
+ <TD><VAR>@CUPS_CACHEDIR@</VAR></TD>
+ <TD>The location of cache files such as
+ <VAR>ppds.dat</VAR> and <VAR>remote.cache</VAR>.
+ Overridden by the <A
+ HREF="ref-cupsd-conf.html#CacheDir"><CODE>CacheDir</CODE></A>
+ directive in <VAR>cupsd.conf</VAR>.</TD>
+</TR>
+<TR>
+ <TD><VAR>@CUPS_LOGDIR@</VAR></TD>
+ <TD>The location of the <VAR>access_log</VAR>,
+ <VAR>error_log</VAR>, and <VAR>page_log</VAR> files.
+ Overridden by the <A
+ HREF="ref-cupsd-conf.html#AccessLog"><CODE>AccessLog</CODE></A>,
+ <A
+ HREF="ref-cupsd-conf.html#ErrorLog"><CODE>ErrorLog</CODE></A>,
+ <A
+ HREF="ref-cupsd-conf.html#PageLog"><CODE>PageLog</CODE></A>,
+ directive in <VAR>cupsd.conf</VAR>.</TD>
+</TR>
+<TR>
+ <TD><VAR>@CUPS_STATEDIR@</VAR></TD>
+ <TD>The location of the domain socket file and state data
+ such as authentication certificates. Overridden by the <A
+ HREF="ref-cupsd-conf.html#StateDir"><CODE>StateDir</CODE></A>
+ directive in <VAR>cupsd.conf</VAR>.</TD>
+</TR>
+<TR>
+ <TD><VAR>@CUPS_REQUESTS@</VAR></TD>
+ <TD>The location of spooled print jobs. Overridden by the
+ <A
+ HREF="ref-cupsd-conf.html#RequestRoot"><CODE>RequestRoot</CODE></A>
+ directive in <VAR>cupsd.conf</VAR>.</TD>
+</TR>
+</TABLE></DIV>
+
+</BODY>
+</HTML>
diff --git a/doc/help/translation.html b/doc/help/translation.html
new file mode 100644
index 000000000..a4ada4a70
--- /dev/null
+++ b/doc/help/translation.html
@@ -0,0 +1,852 @@
+<HTML>
+<!-- SECTION: Getting Started -->
+<HEAD>
+ <TITLE>Translating and Customizing CUPS</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">Translating and Customizing CUPS</H1>
+
+<P>Thanks to its extensive use of templates, images, and message
+catalogs, CUPS can be easily translated (or customized!) to suit
+your needs. This help file will guide you through the CUPS
+localization files so you can get the most out of it.</P>
+
+
+<H2 CLASS="title"><A NAME="INTRO">Getting Started</A></H2>
+
+<P>Start by downloading the CUPS source code from <A
+HREF="http://www.cups.org/software.php"
+TARGET="_blank">www.cups.org</A>. After you extract the files
+from the source archive, you will want to copy the following
+files and directories:</P>
+
+<UL>
+
+ <LI><VAR>desktop/cups.desktop</VAR> - the GNOME/KDE
+ desktop file pointing to the CUPS web interface</LI>
+
+ <LI><VAR>doc/index.html</VAR> - the web interface home
+ page</LI>
+
+ <LI><VAR>locale/cups.pot</VAR> - the message catalog</LI>
+
+ <LI><VAR>templates/*.tmpl</VAR> - the web interface
+ template files</LI>
+
+</UL>
+
+<P>With the exception of the message catalogs and desktop file,
+localization files are placed in subdirectories under the
+<VAR>doc</VAR> and <VAR>templates</VAR> using the locale name.
+Locale names are either <VAR>ll</VAR> or <VAR>ll_CC</VAR>, where
+"ll" is the 2-letter language code and "CC" is the 2-letter
+country code. <em>CUPS does not currently use or support the newer
+<VAR>ll-region</VAR> syntax for locale names.</em></P>
+
+<P>All non-image files must be encoded using the UTF-8 character
+set.</P>
+
+
+<H2 CLASS="title"><A NAME="SUBMIT">Submitting a Translation for CUPS</A></H2>
+
+<P>To submit a translation for inclusion in CUPS, translate the
+desktop file, all of the template files, the <VAR>index.html.in</VAR>
+file, and the message catalog. Place these files in the correct
+subdirectories in the CUPS source code archive and run the following
+command to create an archive with your files:</P>
+
+<PRE CLASS="command">
+tar cvf <I>ll_CC</I>.tar.gz desktop/cups.desktop doc/<I>ll_CC</I> \
+ locale/cups_<I>ll_CC</I>.po templates/<I>ll_CC</I>
+</PRE>
+
+<P>Replace "ll_CC" with the locale name for your translation.
+Once you have created the archive, go to the <A
+HREF="http://www.cups.org/str.php" TARGET="_blank">CUPS Bugs
+&amp; Features</A> page and submit a bug report, attaching the
+translation to the report.</P>
+
+
+<H2 CLASS="title"><A NAME="DESKTOP">The Desktop File</A></H2>
+
+<P>The <VAR>desktop/cups.desktop</VAR> file provides a link to
+the CUPS web interface from desktop environments such as
+GNOME and KDE. To translate this file, add two lines to the
+bottom with the <tt>Name</tt> and <tt>Comment</tt> keys:</P>
+
+<PRE CLASS="command">
+Name[<I>ll_CC</I>]=<I>Translation of "Manage Printing"</I>
+Comment[<I>ll_CC</I>]=<I>Translation of "CUPS Web Interface"</I>
+</PRE>
+
+
+<H2 CLASS="title"><A NAME="HOMEPAGE">The Home Page</A></H2>
+
+<P>The <VAR>index.html</VAR> file is a complete HTML file that is
+displayed when the user visits "http://localhost:631/". Edit the
+existing <VAR>doc/index.html</VAR> and save it in the
+<VAR>doc/ll_CC</VAR> subdirectory so that the makefile can
+install it. Run "make install" in the <VAR>doc</VAR> subdirectory
+to test the new home page.</P>
+
+
+<H2 CLASS="title"><A NAME="CATALOGS">Message Catalogs</A></H2>
+
+<P>CUPS message catalogs are GNU gettext ".po" text files that
+provide a list of localized message strings for the CUPS
+software. Message catalogs are named <VAR>cups_ll.po</VAR> or
+<VAR>cups_ll_CC.po</VAR>, where "ll" is the standard 2-letter
+abbreviation for the language and "CC" is the standard 2-letter
+abbreviation for the country.</P>
+
+<P>When translating a new message catalog, copy the
+<VAR>cups.pot</VAR> message catalog file in the <VAR>locale</VAR>
+subdirectory of the CUPS source code. For example, to start
+translating the message catalog to Canadian French, you would
+type the following commands:</P>
+
+<PRE CLASS="command">
+cd locale
+cp cups.pot cups_fr_CA.po
+</PRE>
+
+<P>Alternatively, you can copy the existing <VAR>cups_fr.po</VAR>
+message catalog and then make any necessary changes.</P>
+
+<P>Once you have make your copy of the file, edit it using your
+favorite text editor or translation program to translate the text
+to the desired language.</P>
+
+<P>Then validate your translation using the <VAR>locale/checkpo</VAR> utility:</P>
+
+<PRE CLASS="command">
+cd locale
+./checkpo cups_ll_CC.po
+</PRE>
+
+<P>After fixing any errors in your translation, add your locale to the <CODE>LANGUAGES</CODE>
+variable in the <VAR>Makedefs</VAR> file and run the "make
+install" command in the <VAR>locale</VAR> subdirectory to test
+the translation.</P>
+
+
+<H2 CLASS="title"><A NAME="TEMPLATES">Template Files</A></H2>
+
+<P>The CUPS scheduler provides a web interface that can be used
+to do many common printing and administration tasks. The built-in
+web server supports localization of web pages through the use of
+subdirectories for each locale, e.g. "fr" for French, "de" for
+German, "fr_ca" for French in Canada, and so forth.</P>
+
+<P>Template files are HTML files with special formatting
+characters in them that allow substitution of variables and arrays.
+The CUPS CGI programs (<CODE>admin.cgi</CODE>,
+<CODE>classes.cgi</CODE>, <CODE>help.cgi</CODE>,
+<CODE>jobs.cgi</CODE>, and <CODE>printers.cgi</CODE>) use these
+template file to provide dynamic content for the web interface.
+Template files are installed in the
+<VAR>/usr/share/cups/templates</VAR> directory by default. Table
+2 lists the various template files and their purpose.</P>
+
+<P>Translated versions of the template files should be saved in
+the <VAR>templates/ll_CC</VAR> subdirectory. For example,
+Canadian French template files should be saved in the
+<VAR>templates/fr_CA</VAR> subdirectory. After you have
+translated all of the templates, add the locale to the
+<CODE>LANGUAGES</CODE> variable in the
+<VAR>Makedefs</VAR> file and run "make install" in the
+<VAR>templates</VAR> subdirectory to test the translation.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="Web Interface Template Files">
+<CAPTION>Table 2: Web Interface Template Files</CAPTION>
+<THEAD>
+<TR>
+ <TH>Filename</TH>
+ <TH>Purpose</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD>add-class.tmpl</TD>
+ <TD>This is the initial form that is shown to add a new
+ printer class.</TD>
+</TR>
+<TR>
+ <TD>add-printer.tmpl</TD>
+ <TD>This is the initial form that is shown to add a new
+ printer.</TD>
+</TR>
+<TR>
+ <TD>add-rss-subscription.tmpl</TD>
+ <TD>This is the form that is shown to add a new RSS subscription.</TD>
+</TR>
+<TR>
+ <TD>admin.tmpl</TD>
+ <TD>This is the main administration page.</TD>
+</TR>
+<TR>
+ <TD>choose-device.tmpl</TD>
+ <TD>This is the form that shows the list of available
+ devices.</TD>
+</TR>
+<TR>
+ <TD>choose-make.tmpl</TD>
+ <TD>This is the form that shows the list of available
+ manufacturers.</TD>
+</TR>
+<TR>
+ <TD>choose-model.tmpl</TD>
+ <TD>This is the form that shows the list of available
+ printer models/drivers.</TD>
+</TR>
+<TR>
+ <TD>choose-serial.tmpl</TD>
+ <TD>This is the form that allows the user to choose
+ a serial port and any options.</TD>
+</TR>
+<TR>
+ <TD>choose-uri.tmpl</TD>
+ <TD>This is the form that allows the user to enter
+ a device URI for network printers.</TD>
+</TR>
+<TR>
+ <TD>class-added.tmpl</TD>
+ <TD>This template shows the "class added" message.</TD>
+</TR>
+<TR>
+ <TD>class-confirm.tmpl</TD>
+ <TD>This is the template used to confirm the
+ deletion of a class.</TD>
+</TR>
+<TR>
+ <TD>class-deleted.tmpl</TD>
+ <TD>This template shows the "class deleted" message.</TD>
+</TR>
+<TR>
+ <TD>class-jobs-header.tmpl</TD>
+ <TD>This template shows the "jobs" header for jobs in a
+ class.</TD>
+</TR>
+<TR>
+ <TD>class-modified.tmpl</TD>
+ <TD>This template shows the "class modified" message.</TD>
+</TR>
+<TR>
+ <TD>classes.tmpl</TD>
+ <TD>This template shows one or more printer classes.</TD>
+</TR>
+<TR>
+ <TD>classes-header.tmpl</TD>
+ <TD>This template shows the "showing N of M classes" header in
+ the class list.</TD>
+</TR>
+<TR>
+ <TD>edit-config.tmpl</TD>
+ <TD>This is the cupsd.conf editor page.</TD>
+</TR>
+<TR>
+ <TD>error.tmpl</TD>
+ <TD>This template displays a generic error message.</TD>
+</TR>
+<TR>
+ <TD>error-op.tmpl</TD>
+ <TD>This is the "unknown operation" error page.</TD>
+</TR>
+<TR>
+ <TD>header.tmpl</TD>
+ <TD>This template is used as the standard header on all dynamic
+ content.</TD>
+</TR>
+<TR>
+ <TD>help-header.tmpl</TD>
+ <TD>This is the top part of the help page.</TD>
+</TR>
+<TR>
+ <TD>help-printable.tmpl</TD>
+ <TD>This is the standard page header for the printable
+ version of help files.</TD>
+</TR>
+<TR>
+ <TD>job-cancel.tmpl</TD>
+ <TD>This template shows "job canceled".</TD>
+</TR>
+<TR>
+ <TD>job-hold.tmpl</TD>
+ <TD>This template shows "job held".</TD>
+</TR>
+<TR>
+ <TD>job-move.tmpl</TD>
+ <TD>This template shows the move-job form.</TD>
+</TR>
+<TR>
+ <TD>job-moved.tmpl</TD>
+ <TD>This template shows "job moved".</TD>
+</TR>
+<TR>
+ <TD>job-release.tmpl</TD>
+ <TD>This template shows "job released".</TD>
+</TR>
+<TR>
+ <TD>job-restart.tmpl</TD>
+ <TD>This template shows "job reprinted".</TD>
+</TR>
+<TR>
+ <TD>jobs.tmpl</TD>
+ <TD>This template is used to list the print jobs on a server,
+ class, or printer.</TD>
+</TR>
+<TR>
+ <TD>jobs-header.tmpl</TD>
+ <TD>This template shows the "showing N or M jobs" header in the
+ jobs list.</TD>
+</TR>
+<TR>
+ <TD>list-available-printers.tmpl</TD>
+ <TD>This template shows a list of new printers that have been found.</TD>
+</TR>
+<TR>
+ <TD>maintenance.tmpl</TD>
+ <TD>This template shows "maintenance commands sent".</TD>
+</TR>
+<TR>
+ <TD>modify-class.tmpl</TD>
+ <TD>This template is used as the first form when modifying a
+ class.</TD>
+</TR>
+<TR>
+ <TD>modify-printer.tmpl</TD>
+ <TD>This template is used as the first form when modifying a
+ printer.</TD>
+</TR>
+<TR>
+ <TD>norestart.tmpl</TD>
+ <TD>This template shows "server not restarted because no
+ changes were made to the configuration".</TD>
+</TR>
+<TR>
+ <TD>option-boolean.tmpl</TD>
+ <TD>This template is used to select a boolean PPD option.</TD>
+</TR>
+<TR>
+ <TD>option-conflict.tmpl</TD>
+ <TD>This template shows the conflicting options.</TD>
+</TR>
+<TR>
+ <TD>option-header.tmpl</TD>
+ <TD>This template is used to start a PPD option group.</TD>
+</TR>
+<TR>
+ <TD>option-pickmany.tmpl</TD>
+ <TD>This template is used to select a multi-valued PPD option.</TD>
+</TR>
+<TR>
+ <TD>option-pickone.tmpl</TD>
+ <TD>This template is used to select a single-valued PPD option.</TD>
+</TR>
+<TR>
+ <TD>option-trailer.tmpl</TD>
+ <TD>This template is used to end a PPD option group.</TD>
+</TR>
+<TR>
+ <TD>pager.tmpl</TD>
+ <TD>This template shows the previous/next pager bar.</TD>
+</TR>
+<TR>
+ <TD>printer-accept.tmpl</TD>
+ <TD>This template shows "printer now accepting jobs".</TD>
+</TR>
+<TR>
+ <TD>printer-added.tmpl</TD>
+ <TD>This template shows "printer added".</TD>
+</TR>
+<TR>
+ <TD>printer-configured.tmpl</TD>
+ <TD>This template shows "printer configured".</TD>
+</TR>
+<TR>
+ <TD>printer-confirm.tmpl</TD>
+ <TD>This template asks the user to confirm the deletion
+ of a printer.</TD>
+</TR>
+<TR>
+ <TD>printer-default.tmpl</TD>
+ <TD>This template shows "default printer set".</TD>
+</TR>
+<TR>
+ <TD>printer-deleted.tmpl</TD>
+ <TD>This template shows "printer deleted".</TD>
+</TR>
+<TR>
+ <TD>printer-jobs-header.tmpl</TD>
+ <TD>This templates shows the "jobs" header for jobs on a
+ printer.</TD>
+</TR>
+<TR>
+ <TD>printer-modified.tmpl</TD>
+ <TD>This template shows "printer modified".</TD>
+</TR>
+<TR>
+ <TD>printer-purge.tmpl</TD>
+ <TD>This template shows "printer has been purged of all jobs".</TD>
+</TR>
+<TR>
+ <TD>printer-reject.tmpl</TD>
+ <TD>This template shows "printer now rejecting jobs".</TD>
+</TR>
+<TR>
+ <TD>printer-start.tmpl</TD>
+ <TD>This template shows "printer started".</TD>
+</TR>
+<TR>
+ <TD>printer-stop.tmpl</TD>
+ <TD>This template shows "printer stopped".</TD>
+</TR>
+<TR>
+ <TD>printers.tmpl</TD>
+ <TD>This template is used to list information on one or more
+ printers.</TD>
+</TR>
+<TR>
+ <TD>printers-header.tmpl</TD>
+ <TD>This template shows the "showing printer N of M" header in
+ the printers list.</TD>
+</TR>
+<TR>
+ <TD>restart.tmpl</TD>
+ <TD>This template shows "server restarting".</TD>
+</TR>
+<TR>
+ <TD>samba-export.tmpl</TD>
+ <TD>This template shows the export printers to Samba form.</TD>
+</TR>
+<TR>
+ <TD>samba-exported.tmpl</TD>
+ <TD>This template shows "printers exported to Samba".</TD>
+</TR>
+<TR>
+ <TD>search.tmpl</TD>
+ <TD>This template shows the search form.</TD>
+</TR>
+<TR>
+ <TD>set-printer-options-header.tmpl</TD>
+ <TD>This template shows the first part of the set printer options
+ form.</TD>
+</TR>
+<TR>
+ <TD>set-printer-options-trailer.tmpl</TD>
+ <TD>This template shows the last part of the set printer options
+ form.</TD>
+</TR>
+<TR>
+ <TD>subscription-added.tmpl</TD>
+ <TD>This template shows "subscription ... added".</TD>
+</TR>
+<TR>
+ <TD>subscription-canceled.tmpl</TD>
+ <TD>This template shows "subscription #NNN canceled".</TD>
+</TR>
+<TR>
+ <TD>test-page.tmpl</TD>
+ <TD>This template shows "test page printed".</TD>
+</TR>
+<TR>
+ <TD>trailer.tmpl</TD>
+ <TD>This template is used as the standard trailer on all dynamic
+ content.</TD>
+</TR>
+<TR>
+ <TD>users.tmpl</TD>
+ <TD>This template shows the set allowed users form.</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+<H3><A NAME="VARIABLE">Inserting Attributes and Values</A></H3>
+
+<P>Template files consist of HTML with variable substitutions for
+named inside curly braces "{name}". Variable names are generally
+the IPP attribute names with the hyphen ("-") replaced by the
+underscore ("_") character. For example, the
+<TT>job-printer-uri</TT> attribute is renamed to
+<TT>job_printer_uri</TT>.</P>
+
+<P>Curley braces ("{" and "}") to indicate substitutions, and the
+backslash ("\") character for quoting. To insert any of these
+special characters as-is you need to use the HTML
+<CODE>&amp;name;</CODE> mechanism or prefix each special
+character with the backslash ("\".)</P>
+
+<P>You substitute the value of a variable using
+<CODE>{NAME}</CODE> in your template file. If the variable is
+undefined then the <CODE>{NAME}</CODE> string is output
+as-is.</P>
+
+<P>To substitute an empty string if the variable is undefined,
+use <CODE>{?NAME}</CODE> instead.</P>
+
+<H3>Array Substitutions</H3>
+
+<P>The number of array elements can be inserted using
+<CODE>{#NAME}</CODE>. If the array is undefined then 0 is output.
+The current array element (starting at 1) is inserted with
+<CODE>{#}</CODE>.</P>
+
+<P>Arrays are handled using <CODE>{[NAME]</CODE> at the beginning
+of a section and <CODE>}</CODE> at the end. The information
+between the closing bracket ("]") and closing brace ("}") is
+repeated for as many elements as are in the named array. For
+example, the following template will display a list of each job
+in the <CODE>job_id</CODE> array:</P>
+
+<PRE CLASS="command">
+&lt;TABLE&gt;
+&lt;TR&gt;
+ &lt;TH&gt;Job ID&lt;/TH&gt;
+ &lt;TH&gt;Destination&lt;/TH&gt;
+ &lt;TH&gt;Title&lt;/TH&gt;
+&lt;/TR&gt;
+
+{[job_id]
+&lt;TR&gt;
+ &lt;TD&gt;{?job_id}&lt;/TD&gt;
+ &lt;TD&gt;{?job_printer_name}&lt;/TD&gt;
+ &lt;TD&gt;{?job_name}&lt;/TD&gt;
+&lt;/TR&gt;
+}
+&lt;/TABLE&gt;
+</PRE>
+
+<P>Arrays can be nested, however all elements within the curly
+braces ("{" and "}") are indexed using the innermost array.</P>
+
+<H3>Conditional Tests</H3>
+
+<P>Templates can also test variables against specific values and
+conditionally include text in the template. The format is:</P>
+
+<PRE CLASS="command">
+{<I>variable</I>?<I>true</I>:<I>false</I>}
+{<I>variable</I>=<I>value</I>?<I>true</I>:<I>false</I>}
+{<I>variable</I>!<I>value</I>?<I>true</I>:<I>false</I>}
+{<I>variable</I>&lt;<I>value</I>?<I>true</I>:<I>false</I>}
+{<I>variable</I>><I>value</I>?<I>true</I>:<I>false</I>}
+</PRE>
+
+<P>where <VAR>true</VAR> is the text that is included if the
+condition is true and <VAR>false</VAR> is the text that is
+included if the condition is false. A value of <CODE>#</CODE> is
+replaced with the current element number (starting at 1.) The
+character after the variable name specifies the condition to
+test. Table 3 shows the available test conditions.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="Template Substitution Conditions">
+<CAPTION>Table 3: Template Substitution Conditions</CAPTION>
+<TR>
+ <TH>Char</TH>
+ <TH>Condition</TH>
+</TR>
+<TR>
+ <TD>?</TD>
+ <TD>True if <VAR>variable</VAR> exists.</TD>
+</TR>
+<TR>
+ <TD>=</TD>
+ <TD>True if <VAR>variable</VAR> is equal to <VAR>value</VAR>.</TD>
+</TR>
+<TR>
+ <TD>!</TD>
+ <TD>True if <VAR>variable</VAR> is not equal to <VAR>value</VAR>.</TD>
+</TR>
+<TR>
+ <TD>&lt;</TD>
+ <TD>True if <VAR>variable</VAR> is less than <VAR>value</VAR>.</TD>
+</TR>
+<TR>
+ <TD>></TD>
+ <TD>True if <VAR>variable</VAR> is greater than <VAR>value</VAR>.</TD>
+</TR>
+</TABLE></DIV>
+
+<H3><A NAME="CGI">CGI Programs</A></H3>
+
+<P>CUPS uses five CGI programs to manage the dynamic web
+interfaces:</P>
+
+<UL>
+
+ <LI><CODE>admin.cgi</CODE></LI>
+ <LI><CODE>classes.cgi</CODE></LI>
+ <LI><CODE>help.cgi</CODE></LI>
+ <LI><CODE>jobs.cgi</CODE></LI>
+ <LI><CODE>printers.cgi</CODE></LI>
+
+</UL>
+
+<P>Each CGI program accepts standard form variables such as
+<CODE>OP</CODE> for the operation to perform,
+<CODE>PRINTER_NAME</CODE> for the printer or class name to
+operate on, <CODE>QUERY</CODE> for any search words,
+<CODE>FIRST</CODE> for the first class, job, or printer to
+display, and <CODE>ORDER</CODE> to control the order that
+classes, jobs, or printers are displayed.</P>
+
+<P>In addition, the <CODE>classes.cgi</CODE>,
+<CODE>jobs.cgi</CODE>, and <CODE>printers.cgi</CODE> programs
+support a <CODE>WHICH_JOBS</CODE> variable to control which jobs
+are displayed. Table 4 lists the supported values.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="WHICH_JOBS Values">
+<CAPTION>Table 4: WHICH_JOBS Values</CAPTION>
+<THEAD>
+<TR>
+ <TH>WHICH_JOBS Value</TH>
+ <TH>Description</TH>
+</TR>
+</THEAD>
+<TR>
+ <TD>all</TD>
+ <TD>Show all jobs</TD>
+</TR>
+<TR>
+ <TD>completed</TD>
+ <TD>Show completed jobs</TD>
+</TR>
+<TR>
+ <TD>not-completed</TD>
+ <TD>Show active jobs</TD>
+</TR>
+</TABLE></DIV>
+
+<H4><A NAME="admin.cgi">admin.cgi</A></H4>
+
+<P>The <CODE>admin.cgi</CODE> program handles all of the printer
+and class administration functions and is run for all direct
+accesses to the <VAR>/admin</VAR> resource. For most operations
+it uses the <CODE>PRINTER_NAME</CODE> and <CODE>OP</CODE> form
+variables to specify the action requested. Table 5 shows the
+supported <CODE>OP</CODE> values.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="admin.cgi OP Values">
+<CAPTION>Table 5: admin.cgi OP Values</CAPTION>
+<THEAD>
+<TR>
+ <TH>OP Value</TH>
+ <TH>Description</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD>accept-jobs</TD>
+ <TD>Accepts jobs on the named destination.</TD>
+</TR>
+<TR>
+ <TD>add-class</TD>
+ <TD>Adds a new printer class.</TD>
+</TR>
+<TR>
+ <TD>add-printer</TD>
+ <TD>Adds a new printer.</TD>
+</TR>
+<TR>
+ <TD>config-server</TD>
+ <TD>Configures the server.</TD>
+</TR>
+<TR>
+ <TD>delete-class</TD>
+ <TD>Deletes a printer class. The form variable <CODE>CONFIRM</CODE>
+ may be set to any value to bypass the confirmation page.</TD>
+</TR>
+<TR>
+ <TD>delete-printer</TD>
+ <TD>Deletes a printer. The form variable <CODE>CONFIRM</CODE>
+ may be set to any value to bypass the confirmation page.</TD>
+</TR>
+<TR>
+ <TD>export-samba</TD>
+ <TD>Exports printers to Samba.</TD>
+</TR>
+<TR>
+ <TD>find-new-printers</TD>
+ <TD>Find new printers that have not yet been added.</TD>
+</TR>
+<TR>
+ <TD>modify-class</TD>
+ <TD>Modifies a printer class.</TD>
+</TR>
+<TR>
+ <TD>modify-printer</TD>
+ <TD>Modifies a printer.</TD>
+</TR>
+<TR>
+ <TD>purge-jobs</TD>
+ <TD>Purges all jobs on the named destination.</TD>
+</TR>
+<TR>
+ <TD>redirect</TD>
+ <TD>Redirects the web browser to the location referenced by
+ the URL form variable.</TD>
+</TR>
+<TR>
+ <TD>reject-jobs</TD>
+ <TD>Rejects new jobs on the named destination.</TD>
+</TR>
+<TR>
+ <TD>set-allowed-users</TD>
+ <TD>Sets the allowed users for a destination.</TD>
+</TR>
+<TR>
+ <TD>set-as-default</TD>
+ <TD>Sets the default destination.</TD>
+</TR>
+<TR>
+ <TD>set-printer-options</TD>
+ <TD>Sets the default options for a printer.</TD>
+</TR>
+<TR>
+ <TD>set-sharing</TD>
+ <TD>Sets the printer-is-shared attribute for a destination.</TD>
+</TR>
+<TR>
+ <TD>start-class</TD>
+ <TD>Starts the named class.</TD>
+</TR>
+<TR>
+ <TD>start-printer</TD>
+ <TD>Starts the named printer.</TD>
+</TR>
+<TR>
+ <TD>stop-class</TD>
+ <TD>Stops the named class.</TD>
+</TR>
+<TR>
+ <TD>stop-printer</TD>
+ <TD>Stops the named printer.</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+<H4><A NAME="classes.cgi">classes.cgi</A></H4>
+
+<P>The <CODE>classes.cgi</CODE> program is responsible for
+listing class information, including jobs destined for that
+class. It is for all direct accesses to the <VAR>/classes</VAR>
+resource and supports the optional form variables <CODE>OP</CODE>
+and <CODE>WHICH_JOBS</CODE>. If no form variables are supplied
+then the CGI lists all or a specific class and the active jobs on
+each class. Table 6 shows the supported <CODE>OP</CODE>
+values.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="classes.cgi OP Values">
+<CAPTION>Table 6: classes.cgi OP Values</CAPTION>
+<THEAD>
+<TR>
+ <TH>OP Value</TH>
+ <TH>Description</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD>move-jobs</TD>
+ <TD>Moves the jobs on this class to another destination.</TD>
+</TR>
+<TR>
+ <TD>print-test-page</TD>
+ <TD>Prints the standard PostScript test page.</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+
+<H4><A NAME="help.cgi">help.cgi</A></H4>
+
+<P>The <CODE>help.cgi</CODE> program handles all of the on-line
+help functions and is run for all direct accesses to the
+<VAR>/help</VAR> resource.</P>
+
+
+<H4><A NAME="jobs.cgi">jobs.cgi</A></H4>
+
+<P>The <CODE>jobs.cgi</CODE> program handles all of the job
+functions and is run for all direct accesses to the
+<VAR>/jobs</VAR> resource. For most operations it uses the
+<CODE>JOB_ID</CODE>, <CODE>OP</CODE>, and <CODE>WHICH_JOBS</CODE>
+form variables to specify the action requested. Table 7 shows the
+supported <CODE>OP</CODE> values.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="jobs.cgi OP Values">
+<CAPTION>Table 7: jobs.cgi OP Values</CAPTION>
+<THEAD>
+<TR>
+ <TH>OP Value</TH>
+ <TH>Description</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD>cancel-job</TD>
+ <TD>Cancels a job.</TD>
+</TR>
+<TR>
+ <TD>hold-job</TD>
+ <TD>Holds a job indefinitely.</TD>
+</TR>
+<TR>
+ <TD>move-job</TD>
+ <TD>Moves a job to another destination.</TD>
+</TR>
+<TR>
+ <TD>release-job</TD>
+ <TD>Releases a job for printing.</TD>
+</TR>
+<TR>
+ <TD>restart-job</TD>
+ <TD>Restarts/reprints a stopped, canceled, completed, or aborted
+ print job.</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+
+<H4><A NAME="printers.cgi">printers.cgi</A></H4>
+
+<P>The <CODE>printers.cgi</CODE> program is responsible for
+listing printer information, including jobs destined for that
+printer. It is for all direct accesses to the
+<VAR>/printers</VAR> resource and supports the optional form
+variables <CODE>OP</CODE> and <CODE>WHICH_JOBS</CODE>. If no form
+variables are supplied then the CGI lists all printers or a
+specific printer and the active jobs on that printer. Table 8
+shows the supported <CODE>OP</CODE> values.</P>
+
+<DIV CLASS="table"><TABLE SUMMARY="printers.cgi OP Values">
+<CAPTION>Table 8: printers.cgi OP Values</CAPTION>
+<THEAD>
+<TR>
+ <TH>OP Value</TH>
+ <TH>Description</TH>
+</TR>
+</THEAD>
+<TBODY>
+<TR>
+ <TD>clean-print-heads</TD>
+ <TD>Clean the print heads.</TD>
+</TR>
+<TR>
+ <TD>move-jobs</TD>
+ <TD>Move all jobs to a different destination.</TD>
+</TR>
+<TR>
+ <TD>print-self-test-page</TD>
+ <TD>Print a printer self-test page.</TD>
+</TR>
+<TR>
+ <TD>print-test-page</TD>
+ <TD>Print a PostScript test page.</TD>
+</TR>
+</TBODY>
+</TABLE></DIV>
+
+</BODY>
+</HTML>
diff --git a/doc/help/whatsnew.html b/doc/help/whatsnew.html
new file mode 100644
index 000000000..856f30a94
--- /dev/null
+++ b/doc/help/whatsnew.html
@@ -0,0 +1,61 @@
+<HTML>
+<!-- SECTION: Getting Started -->
+<HEAD>
+ <TITLE>What's New in CUPS 1.5</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="../cups-printable.css">
+</HEAD>
+<BODY>
+
+<H1 CLASS="title">What's New in CUPS 1.5</H1>
+
+<P>CUPS 1.5 many changes and new features to CUPS 1.4.x. This page provides a high-level outline of these changes. If you have never used CUPS before, read the <A HREF="overview.html">"Overview of CUPS"</A> document instead.</P>
+
+<H2 CLASS="title"><A NAME="COMMANDS">Commands</A></H2>
+
+<OL START="1">
+
+ <LI><EM>User defaults;</EM> Starting in CUPS 1.2, user defaults were stored in the ~/.cups directory, and the old ~/.cupsrc and ~/.lpoptions files were deprecated. Support for ~/.cupsrc and ~/.lpoptions have been removed in CUPS 1.5.</LI>
+
+ <LI><EM>IPP test tool;</EM> The <code>ipptool</code> IPP test tool is now a first-class user program.</LI>
+
+ <LI><EM>lpadmin;</EM> The <code>lpadmin</code> command now supports setting the cupsIPPSupplies and cupsSNMPSupplies keywords in PPDs and deleting options.</LI>
+</OL>
+
+<H2 CLASS="title"><A NAME="SCHEDULER">Scheduler</A></H2>
+
+<OL START="4">
+
+ <LI><EM>Filter security;</EM> Filters and backends must now have group write permissions disabled.</LI>
+
+</OL>
+
+
+<H2 CLASS="title"><A NAME="FILTERS">Print Filters</A></H2>
+
+<OL START="5">
+
+ <LI><EM>HP-GL/2 filter;</EM> The HP-GL/2 filter is no longer provided with CUPS.</LI>
+
+ <LI><EM>PDF filter;</EM> The PDF filter now supports new Poppler and Ghostscript options.</LI>
+
+ <LI><EM>PWG Raster driver;</EM> Added a new PWG Raster printer driver filter.</LI>
+
+ <LI><EM>SCSI backend;</EM> The SCSI backend is no longer provided with CUPS.</LI>
+
+</OL>
+
+
+<H2 CLASS="title"><A NAME="CUPSAPI">CUPS API</A></H2>
+
+<OL START="9">
+
+ <LI><EM>CUPS headers;</EM> Changes to the main CUPS header may require code changes to applications and toolkits. Users of PPD functions must now include the &lt;cups/ppd.h&gt; header file explicitly since the &lt;cups/cups.h&gt; header no longer does so.</LI>
+
+ <LI><EM>HTTP support:</EM> Applications can now set a per-connection timeout interval and callback for HTTP operations as well as query and set SSL/TLS X.509 certificates.</LI>
+
+ <LI><EM>Raster support;</EM> The CUPS raster functions now support the creation of PWG Raster files and streams, and a new callback-based context function allows reading and writing from objects other than file descriptors.</LI>
+
+</OL>
+
+</BODY>
+</HTML>
diff --git a/doc/id/index.html.in b/doc/id/index.html.in
new file mode 100644
index 000000000..93b4621e7
--- /dev/null
+++ b/doc/id/index.html.in
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>Beranda - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="sel"><A HREF="/">&nbsp;&nbsp;Beranda&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/admin">&nbsp;&nbsp;Administrasi&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/classes/">&nbsp;&nbsp;Kelas&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/help/">&nbsp;&nbsp;Bantuan&nbsp;Langsung&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/jobs/">&nbsp;&nbsp;Tugas&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/printers/">&nbsp;&nbsp;Pencetak&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Search Help"
+AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD STYLE="padding-right: 20px;">
+
+<H1>CUPS @CUPS_VERSION@</H1>
+
+<P>CUPS adalah sistem pencetakan berstandar dan berkode sumber terbuka, dikembangkan oleh
+<A HREF="http://www.apple.com/">Apple Inc.</A> untuk Mac OS<SUP>&reg;</SUP> X dan sistem
+operasi serupa UNIX<SUP>&reg;</SUP> lainnya.</P>
+
+</TD>
+<TD><A HREF="http://www.cups.org/"><IMG SRC="images/cups-icon.png" WIDTH="128"
+HEIGHT="128" ALT="CUPS"></A></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-right: 20px;">
+
+<H2>CUPS bagi Pengguna</H2>
+
+<P><A HREF="help/overview.html">Ikhtisar CUPS</A></P>
+
+<P><A HREF="help/options.html">Opsi dan Pencetakan dari Baris Perintah</A></P>
+
+<P><A HREF="help/whatsnew.html">Apa yang Baru di CUPS 1.4</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.general">Forum Pengguna</A></P>
+
+</TD><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-left: 20px; padding-right: 20px;">
+
+<H2>CUPS bagi Administrator</H2>
+
+<P><A HREF="admin">Menambah Pencetak dan Kelas</A></P>
+
+<P><A HREF="help/policies.html">Mengatur Kebijakan Operasi</A></P>
+
+<P><A HREF="help/accounting.html">Dasar Akunting Pencetak</A></P>
+
+<P><A HREF="help/security.html">Keamanan Server</A></P>
+
+<P><A HREF="help/kerberos.html">Menggunakan Otentikasi Kerberos</A></P>
+
+<P><A HREF="help/network.html">Menggunakan Pencetak di Jaringan</A></P>
+
+<P><A HREF="help/ref-cupsd-conf.html">Referensi cupsd.conf</A></P>
+
+<P><A HREF="http://www.cups.org/ppd.php">Mencari Penggerak Pencetak</A></P>
+
+</TD><TD VALIGN="top" STYLE="padding-left: 20px;">
+
+<H2>CUPS bagi Pengembang</H2>
+
+<P><A HREF="help/api-overview.html">Pengenalan untuk Pemrograman CUPS</A></P>
+
+<P><A HREF="help/api-cups.html">API di CUPS</A></P>
+
+<P><A HREF="help/api-filter.html">Penyaring dan Pemrograman Balik (<I>Backend Programming</I>)</A></P>
+
+<P><A HREF="help/api-httpipp.html">API di HTTP dan IPP</A></P>
+
+<P><A HREF="help/api-ppd.html">API di PPD</A></P>
+
+<P><A HREF="help/api-raster.html">API di Raster</A></P>
+
+<P><A HREF="help/ref-ppdcfile.html">Referensi Kompiler Berkas Penggerak PPD</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.development">Forum Pengembang</A></P>
+
+</TD></TR>
+</TABLE>
+
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS dan logo CUPS logo adalah merek dagang dari
+<A HREF="http://www.apple.com">Apple Inc.</A> Hak cipta CUPS pada 2007-2011 Apple
+Inc. Semua hak terpelihara.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/doc/images/color-wheel.png b/doc/images/color-wheel.png
new file mode 100644
index 000000000..301e3fd59
--- /dev/null
+++ b/doc/images/color-wheel.png
Binary files differ
diff --git a/doc/images/cups-block-diagram.png b/doc/images/cups-block-diagram.png
new file mode 100644
index 000000000..d47052e25
--- /dev/null
+++ b/doc/images/cups-block-diagram.png
Binary files differ
diff --git a/doc/images/cups-block-diagram.svg b/doc/images/cups-block-diagram.svg
new file mode 100644
index 000000000..3638f8526
--- /dev/null
+++ b/doc/images/cups-block-diagram.svg
@@ -0,0 +1,841 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="6in"
+ height="6in"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docbase="/home/mike/c/printpro/cups/doc/images"
+ sodipodi:docname="cups-block-diagram.svg"
+ inkscape:export-filename="/Users/msweet/c/cups-trunk/doc/images/cups-block-diagram.png"
+ inkscape:export-xdpi="128"
+ inkscape:export-ydpi="128"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="TriangleInS"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleInS"
+ style="overflow:visible">
+ <path
+ id="path8672"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(-0.2)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutS"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleOutS"
+ style="overflow:visible">
+ <path
+ id="path8681"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.2)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutM"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleOutM"
+ style="overflow:visible">
+ <path
+ id="path8678"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.4)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lend"
+ style="overflow:visible;">
+ <path
+ id="path8553"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(1,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 270 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="540 : 270 : 1"
+ inkscape:persp3d-origin="270 : 180 : 1"
+ id="perspective2734" />
+ <marker
+ inkscape:stockid="Arrow1Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Lend"
+ style="overflow:visible;">
+ <path
+ id="path2919"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.8) rotate(180)" />
+ </marker>
+ <inkscape:perspective
+ id="perspective4394"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.1185185"
+ inkscape:cx="260.28777"
+ inkscape:cy="357.41007"
+ inkscape:document-units="in"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ gridtolerance="0.05in"
+ guidetolerance="0.005in"
+ inkscape:window-width="1198"
+ inkscape:window-height="771"
+ inkscape:window-x="47"
+ inkscape:window-y="22"
+ inkscape:grid-points="false">
+ <inkscape:grid
+ id="GridFromPre046Settings"
+ type="xygrid"
+ originx="0px"
+ originy="0in"
+ spacingx="0.1in"
+ spacingy="0.1in"
+ color="#0000ff"
+ empcolor="#0000ff"
+ opacity="0.2"
+ empopacity="0.4"
+ empspacing="5" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ style="fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInS);marker-mid:none;marker-end:url(#TriangleOutS)"
+ d="M 347.58275,443.70324 L 347.58275,432 L 170.00583,432 L 169.76302,443.20144"
+ id="path2929"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:4.79963589;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 257.66929,431.36712 L 257.66929,444.03066 L 257.66929,444.03066 L 257.66929,444.03066"
+ id="path2931" />
+ <path
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:2.11245656;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 323.05915,156.91535 C 419.71541,156.91535 418.25858,156.91535 418.25858,156.91535 L 418.25858,156.91535 L 323.05915,156.91535 z"
+ id="path2745"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 207,243 L 288,162"
+ id="path2743" />
+ <path
+ style="fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 316.36931,337.79604 C 449.70265,337.79604 449.70265,337.79604 449.70265,337.79604 L 449.70265,337.79604 L 316.36931,337.79604 z "
+ id="path2629" />
+ <rect
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.19518334000000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2627"
+ width="90"
+ height="51.328693"
+ x="613.72308"
+ y="371.13135"
+ transform="matrix(1,0,-0.526022,0.850471,0,0)"
+ ry="7.4584665" />
+ <path
+ style="fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 207,252 L 288,333 L 207,252 z "
+ id="path2621" />
+ <path
+ style="fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 202.40096,225 L 203.37218,67.081834 L 202.40096,225 z"
+ id="path2564"
+ sodipodi:nodetypes="ccc" />
+ <path
+ style="fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 96.75,248.08465 C 456.75,248.08465 456.75,248.08465 456.75,248.08465 L 456.75,248.08465 L 96.75,248.08465 z "
+ id="path2534" />
+ <path
+ style="fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:none;marker-mid:none;marker-end:url(#Arrow1Lend)"
+ d="M 88.8022,468.00005 C 448.8022,468.00005 448.8022,468.00005 448.8022,468.00005 L 448.8022,468.00005 L 88.8022,468.00005 z "
+ id="path1567" />
+ <rect
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.18000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ id="rect2206"
+ width="180"
+ height="45"
+ x="45"
+ y="225" />
+ <flowRoot
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"
+ id="flowRoot1325"
+ transform="translate(-174.31055,58.156198)"><flowRegion
+ id="flowRegion1327"><rect
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ id="rect1329"
+ width="182"
+ height="37"
+ x="218"
+ y="182" /></flowRegion><flowPara
+ id="flowPara1331">Scheduler (cupsd)</flowPara></flowRoot> <rect
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.17000352;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3134"
+ width="62.997257"
+ height="36.002312"
+ x="45.000458"
+ y="450.00046" />
+ <rect
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.18000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3136"
+ width="90"
+ height="45"
+ x="270"
+ y="225" />
+ <rect
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.17000352;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1561"
+ width="62.99725"
+ height="36.002312"
+ x="135.00046"
+ y="450.00046" />
+ <rect
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.1699964;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1563"
+ width="62.982178"
+ height="36.007904"
+ x="225.00041"
+ y="449.9971" />
+ <rect
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.17025572;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1565"
+ width="63.185108"
+ height="36.001846"
+ x="314.81396"
+ y="450.00092" />
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="75.47715"
+ y="471.5834"
+ id="text2442"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2444"
+ x="75.47715"
+ y="471.5834">Filter</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="165.96277"
+ y="471.35364"
+ id="text2446"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2448"
+ x="165.96277"
+ y="471.35364">PPD Filter</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="345.22427"
+ y="471.43503"
+ id="text2450"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2452"
+ x="345.22427"
+ y="471.43503">Backend</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="256.90625"
+ y="464.43979"
+ id="text2454"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2456"
+ x="256.90625"
+ y="464.43979">Port</tspan><tspan
+ sodipodi:role="line"
+ x="256.90625"
+ y="479.43979"
+ id="tspan2458">Monitor</tspan></text>
+ <g
+ id="g2478"
+ transform="translate(0,-2.9587768)"
+ style="fill:#e8e8e8;fill-opacity:1">
+ <rect
+ y="324"
+ x="45"
+ height="36"
+ width="45"
+ id="rect2462"
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.18000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ transform="matrix(0.968754,0,0,1,1.651751,5.380985e-2)"
+ d="M 91.192055,323.6424 A 23.245033,8.9403973 0 1 1 44.701988,323.6424 A 23.245033,8.9403973 0 1 1 91.192055,323.6424 z"
+ sodipodi:ry="8.9403973"
+ sodipodi:rx="23.245033"
+ sodipodi:cy="323.6424"
+ sodipodi:cx="67.947021"
+ id="path2460"
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.18287981;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:open="true"
+ sodipodi:end="6.2747868"
+ sodipodi:start="0"
+ transform="matrix(0.967546,0,0,1.049207,1.764766,20.43299)"
+ d="M 91.192055,323.6424 A 23.245033,8.9403973 0 1 1 91.191235,323.56731"
+ sodipodi:ry="8.9403973"
+ sodipodi:rx="23.245033"
+ sodipodi:cy="323.6424"
+ sodipodi:cx="67.947021"
+ id="path2474"
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.17865127;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <rect
+ y="349.08267"
+ x="45.469322"
+ height="10.9234"
+ width="44.070267"
+ id="rect2476"
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="67.512787"
+ y="341.48492"
+ id="text2488"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2490"
+ x="67.512787"
+ y="341.48492">Job</tspan><tspan
+ sodipodi:role="line"
+ x="67.512787"
+ y="356.48492"
+ id="tspan2492">Files</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="315.43127"
+ y="245.89345"
+ id="text2536"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2538"
+ x="315.43127"
+ y="245.89345">Web Interface</tspan><tspan
+ sodipodi:role="line"
+ x="315.43127"
+ y="260.89346"
+ id="tspan2949">(CGI)</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000000000000;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 108.88889,67.91535 C 411.11111,67.91535 411.11111,67.91535 411.11111,67.91535 L 411.11111,67.91535 L 108.88889,67.91535 z "
+ id="path2562" />
+ <rect
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.18000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3140"
+ width="90"
+ height="45"
+ x="90"
+ y="45" />
+ <rect
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.18000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2540"
+ width="90"
+ height="45"
+ x="225"
+ y="45" />
+ <rect
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.18000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2542"
+ width="90"
+ height="45"
+ x="360"
+ y="45" />
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="134.09766"
+ y="63"
+ id="text2544"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2546"
+ x="134.09766"
+ y="63">Berkeley</tspan><tspan
+ sodipodi:role="line"
+ x="134.09766"
+ y="78"
+ id="tspan2548">Commands</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="268.03125"
+ y="63"
+ id="text2550"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2552"
+ x="268.03125"
+ y="63">CUPS</tspan><tspan
+ sodipodi:role="line"
+ x="268.03125"
+ y="78"
+ id="tspan2554">Commands</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="404.38281"
+ y="63"
+ id="text2556"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2558"
+ x="404.38281"
+ y="63">System V</tspan><tspan
+ sodipodi:role="line"
+ x="404.38281"
+ y="78"
+ id="tspan2560">Commands</tspan></text>
+ <g
+ id="g2581"
+ transform="translate(135,-3.176317)"
+ style="fill:#e8e8e8;fill-opacity:1">
+ <rect
+ y="324"
+ x="45"
+ height="36"
+ width="45"
+ id="rect2583"
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.18000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ transform="matrix(0.968754,0,0,1,1.651751,5.380985e-2)"
+ d="M 91.192055,323.6424 A 23.245033,8.9403973 0 1 1 44.701988,323.6424 A 23.245033,8.9403973 0 1 1 91.192055,323.6424 z"
+ sodipodi:ry="8.9403973"
+ sodipodi:rx="23.245033"
+ sodipodi:cy="323.6424"
+ sodipodi:cx="67.947021"
+ id="path2585"
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.18287981;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:open="true"
+ sodipodi:end="6.2747868"
+ sodipodi:start="0"
+ transform="matrix(0.967546,0,0,1.049207,1.764766,20.43299)"
+ d="M 91.192055,323.6424 A 23.245033,8.9403973 0 1 1 91.191235,323.56731"
+ sodipodi:ry="8.9403973"
+ sodipodi:rx="23.245033"
+ sodipodi:cy="323.6424"
+ sodipodi:cx="67.947021"
+ id="path2587"
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.17865127;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <rect
+ y="349.08267"
+ x="45.469322"
+ height="10.9234"
+ width="44.070267"
+ id="rect2589"
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="201.93938"
+ y="340.97122"
+ id="text2591"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2593"
+ x="201.93938"
+ y="340.97122">Config</tspan><tspan
+ sodipodi:role="line"
+ x="201.93938"
+ y="355.97122"
+ id="tspan2595">Files</tspan></text>
+ <g
+ id="g2597"
+ transform="translate(67.64483,-3.341036)"
+ style="fill:#86fcfe;fill-opacity:1">
+ <rect
+ y="324"
+ x="45"
+ height="36"
+ width="45"
+ id="rect2599"
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.17999999999999999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ transform="matrix(0.968754,0,0,1,1.651751,5.380985e-2)"
+ d="M 91.192055 323.6424 A 23.245033 8.9403973 0 1 1 44.701988,323.6424 A 23.245033 8.9403973 0 1 1 91.192055 323.6424 z"
+ sodipodi:ry="8.9403973"
+ sodipodi:rx="23.245033"
+ sodipodi:cy="323.6424"
+ sodipodi:cx="67.947021"
+ id="path2601"
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.18287981000000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:open="true"
+ sodipodi:end="6.2747868"
+ sodipodi:start="0"
+ transform="matrix(0.967546,0,0,1.049207,1.764766,20.43299)"
+ d="M 91.192055,323.6424 A 23.245033,8.9403973 0 1 1 91.191235,323.56731"
+ sodipodi:ry="8.9403973"
+ sodipodi:rx="23.245033"
+ sodipodi:cy="323.6424"
+ sodipodi:cx="67.947021"
+ id="path2603"
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.17865127000000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <rect
+ y="349.08267"
+ x="45.469322"
+ height="10.9234"
+ width="44.070267"
+ id="rect2605"
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998000000003;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;writing-mode:lr;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans;font-stretch:normal;font-variant:normal"
+ x="134.23688"
+ y="342"
+ id="text2607"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2609"
+ x="134.23688"
+ y="342">Log</tspan><tspan
+ sodipodi:role="line"
+ x="134.23688"
+ y="357"
+ id="tspan2611">Files</tspan></text>
+ <rect
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.18000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2615"
+ width="90"
+ height="45"
+ x="270"
+ y="315" />
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="315.24219"
+ y="342"
+ id="text2617"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2619"
+ x="315.24219"
+ y="342">Notifiers</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="448.03891"
+ y="333"
+ id="text2623"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2625"
+ x="448.03891"
+ y="333"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr;text-anchor:middle;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">Email</tspan><tspan
+ sodipodi:role="line"
+ x="448.03891"
+ y="351.75"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr;text-anchor:middle;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ id="tspan4400">RSS</tspan></text>
+ <g
+ id="g1359"
+ transform="matrix(0.132379,0,0,0.132379,405.1231,87.87966)"
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#666666;stroke-opacity:1">
+ <path
+ d="M 417.9632,334.5033 C 476.16835,321.96076 588.92602,287.75479 640.93956,281.47067 C 512.95701,264.29571 405.24092,241.40451 277.25839,224.22955 C 263.70364,223.98781 125.52678,243.58521 102.45701,245.36704 C 217.21731,273.28909 303.20291,306.58124 417.9632,334.5033 z "
+ id="path4182"
+ sodipodi:nodetypes="ccccc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:8.50060749000000015;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="M 107.07868,644.01625 L 417.77533,829.57064 L 436.38702,326.56632 L 103.95193,246.2678 L 107.07868,644.01625 z "
+ id="path1061"
+ sodipodi:nodetypes="ccccc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:8.50060749000000015;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="M 621.34583,303.5924 C 621.34583,303.5924 620.10477,731.45364 632.48702,735.52624 C 641.98953,746.48994 633.91274,299.26757 633.91274,299.26757 L 621.34583,303.5924 z "
+ id="path7930"
+ sodipodi:nodetypes="cccc"
+ style="fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:0.25000000000000000pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ d="M 382.7467,784.68144 C 422.53161,754.86324 593.606,710.47204 633.91554,713.09464 C 639.34806,712.22014 669.25382,712.65274 670.70568,714.52834 C 675.47993,719.34724 676.63707,751.65134 670.38287,761.62634 C 658.76725,770.05774 458.10527,857.55324 402.03899,829.12304 C 374.07804,817.58304 377.34537,820.07094 382.7467,784.68144 z "
+ id="path2869"
+ sodipodi:nodetypes="cccccc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:8.50060749000000015;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="M 639.2477,715.85454 C 611.50195,724.90444 516.97162,762.71464 423.5077,786.95474 C 425.93718,801.95534 445.97921,802.53554 455.85601,800.57084 C 526.81816,784.45754 648.02894,742.62314 670.59823,728.14214 C 671.66684,710.75284 650.54305,717.22304 639.2477,715.85454 z "
+ id="path2871"
+ sodipodi:nodetypes="ccccc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:0.25000000000000000pt;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="M 629.30506,719.60834 C 629.44296,588.52692 620.69798,434.00079 620.83588,302.91943 C 627.43228,315.2828 645.79308,319.14474 663.41418,314.68193 C 663.27628,441.96326 661.78078,588.83712 661.64288,716.11844"
+ id="path2873"
+ sodipodi:nodetypes="cccc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:8.50060749000000015;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="M 427.62277,328.34273 L 438.63597,778.18344 L 634.25396,716.15164 L 635.97224,281.31264 L 427.62277,328.34273 z "
+ id="path4181"
+ sodipodi:nodetypes="ccccc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:8.50060749000000015;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="M 547.36961,555.08059 L 547.36961,740.26374"
+ id="path7924"
+ sodipodi:nodetypes="cc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:7.55513000000000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block" />
+ <g
+ id="g3639"
+ transform="matrix(1.072727,5.73852e-2,0,1.176989,-15.07636,-184.9701)"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#666666;stroke-opacity:1">
+ <rect
+ height="11.974187"
+ id="rect2875"
+ rx="41.725475"
+ ry="38.425697"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:nonzero;stroke:#666666;stroke-width:2.49999951999999981;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ transform="matrix(0.955244,-0.295818,0,1,0,0)"
+ width="148.65286"
+ x="470.03616"
+ y="694.40729" />
+ <rect
+ height="11.974187"
+ id="rect3635"
+ rx="41.72546"
+ ry="38.425697"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:nonzero;stroke:#666666;stroke-width:2.49999951999999981;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ transform="matrix(0.955244,-0.295818,0,1,0,0)"
+ width="148.65282"
+ x="468.98917"
+ y="714.09766" />
+ <rect
+ height="11.974187"
+ id="rect3637"
+ rx="41.72546"
+ ry="38.425697"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:nonzero;stroke:#666666;stroke-width:2.49999951999999981;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ transform="matrix(0.955244,-0.295818,0,1,0,0)"
+ width="148.65282"
+ x="466.89545"
+ y="734.47827" />
+ </g>
+ <path
+ d="M 636.61105,527.7906 L 428.72348,588.30571"
+ id="path5914"
+ sodipodi:nodetypes="cc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:7.55513000000000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block" />
+ <path
+ d="M 399.40557,782.62584 C 399.54347,636.11304 399.28377,481.25078 399.42167,334.73804 C 406.01807,348.55688 424.37887,352.87346 441.99997,347.88527 C 441.86207,490.15062 440.36657,638.94396 440.22867,781.20934"
+ id="rect4813"
+ sodipodi:nodetypes="cccc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:8.50060749000000015;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="M 646.18257,718.01154 L 657.83722,716.83994 L 657.88967,320.47598 L 647.623,326.47598 L 646.18257,718.01154 z "
+ id="path4406"
+ sodipodi:nodetypes="ccccc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:nonzero;stroke:#666666;stroke-width:2.49999951999999981;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="M 275.59425,231.08961 L 593.41113,289.56174 L 609.68616,281.13168 L 275.59425,231.08961 z "
+ id="path8207"
+ sodipodi:nodetypes="cccc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:nonzero;stroke:#666666;stroke-width:2.49999951999999981;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="M 391.84792,317.6227 C 431.75855,318.76516 588.95775,295.62572 629.97485,279.85418 C 635.43405,279.73251 665.30763,284.28765 666.69463,286.35575 C 671.30163,291.81323 674.61122,312.75026 668.02022,321.82155 C 662.01772,332.4314 503.16982,367.83022 458.7787,375.15681 C 379.07159,376.97996 391.60528,368.03358 391.84792,317.6227 z "
+ id="rect4190"
+ sodipodi:nodetypes="cccccc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:8.50060749000000015;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="M 631.33874,284.39099 C 605.30027,292.07712 485.819,320.11288 406.58219,321.36324 C 401.3263,332.21553 411.88343,343.27296 446.84984,343.0618 C 518.32062,336.80142 661.47272,301.40021 664.52311,290.09151 L 631.33874,284.39099 z "
+ id="path9173"
+ sodipodi:nodetypes="ccccc"
+ style="fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:0.25000000000000000pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g5916"
+ transform="matrix(3.236925,0.134526,-0.141899,3.068732,-730.8271,-1186.692)"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#666666;stroke-opacity:1">
+ <path
+ d="M 426.17674,486.6755 L 427.92029,504.37026 L 433.84729,506.57724 L 441.7756,503.44055 L 438.15666,495.20714 L 438.06514,485.96117 L 434.79529,483.95977 L 426.17674,486.6755 z "
+ id="path2844"
+ sodipodi:nodetypes="cccccccc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:0.25000000000000000pt;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="M 431.1253,488.44205 L 431.81201,496.7507 L 434.46658,504.62081 L 439.9392,502.5562 L 436.93429,495.64077 L 436.62822,486.63527 L 431.1253,488.44205 z "
+ id="path2846"
+ sodipodi:nodetypes="ccccccc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:0.25000000000000000pt;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ <path
+ d="M 434.98217,398.8078 L 422.73953,787.46524 L 436.29587,783.51554 L 434.98217,398.8078 z "
+ id="path3644"
+ sodipodi:nodetypes="cccc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:nonzero;stroke:#666666;stroke-width:2.49999951999999981;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ d="M 132.82575,392.29308 L 132.82575,542.19972 C 146.96789,532.30023 163.93845,465.83218 132.82575,392.29308 z "
+ id="path7447"
+ sodipodi:nodetypes="ccc"
+ style="color:#000000;fill:#e8e8e8;fill-opacity:1;fill-rule:evenodd;stroke:#666666;stroke-width:0.25000000000000000pt;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ <path
+ d="M 380.85948,154.09657 L 380.85948,154.09657 z "
+ id="path16683"
+ style="color:#000000;fill:#000000;fill-opacity:0.08695649;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;opacity:0.66666667" />
+ <rect
+ style="opacity:1;fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.18000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2735"
+ width="90"
+ height="45"
+ x="270"
+ y="135" />
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="315.08038"
+ y="155.42715"
+ id="text2737"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2739"
+ x="315.08038"
+ y="155.42715"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">LPD Support</tspan><tspan
+ sodipodi:role="line"
+ x="315.08038"
+ y="170.42715"
+ id="tspan2741"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">(cups-lpd)</tspan></text>
+ <g
+ transform="matrix(0.5,0,0,0.5,200.47501,348.975)"
+ id="g3893"
+ style="stroke:#000000;stroke-opacity:1">
+ <rect
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.38684496000000002;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect3887"
+ width="90"
+ height="51.961464"
+ x="611.20306"
+ y="207.32623"
+ transform="matrix(1,0,-0.4999983,0.8660264,0,0)" />
+ <rect
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.36000000999999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect3885"
+ width="135"
+ height="67.5"
+ x="472.04999"
+ y="202.05"
+ rx="10"
+ ry="10" />
+ <text
+ xml:space="preserve"
+ style="font-size:32px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="481.96405"
+ y="246.4836"
+ id="text3889"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3891"
+ x="481.96405"
+ y="246.4836">Printer</tspan></text>
+ </g>
+ <image
+ y="209.8"
+ x="401"
+ id="image4396"
+ height="78.199997"
+ width="103"
+ sodipodi:absref="/Users/msweet/c/cups-trunk/doc/images/webinterface.png"
+ xlink:href="webinterface.png" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:0;stroke-dasharray:none;stroke-opacity:1"
+ d="M 107.90106,468 L 127.86948,468"
+ id="path6467"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:0;stroke-dasharray:none;stroke-opacity:1"
+ d="M 198,468 L 217.96842,468"
+ id="path16701"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:0;stroke-dasharray:none;stroke-opacity:1"
+ d="M 288,468 L 308.21122,468"
+ id="path16703"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#TriangleInS);marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:0;stroke-dasharray:none;stroke-opacity:1"
+ d="M 384.7832,468 L 429.71163,468"
+ id="path16705"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 135,270 L 135,304.45479"
+ id="path33961"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path33963"
+ d="M 202.47401,311.4402 L 202.47401,276.98541"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path33965"
+ d="M 67.834287,270 L 67.834287,304.45479"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path33967"
+ d="M 67.474011,366.47616 L 67.302321,443.16659"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+</svg>
diff --git a/doc/images/cups-command-chain.png b/doc/images/cups-command-chain.png
new file mode 100644
index 000000000..a7218e5ce
--- /dev/null
+++ b/doc/images/cups-command-chain.png
Binary files differ
diff --git a/doc/images/cups-command-chain.svg b/doc/images/cups-command-chain.svg
new file mode 100644
index 000000000..7eb361742
--- /dev/null
+++ b/doc/images/cups-command-chain.svg
@@ -0,0 +1,439 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="517.5"
+ height="135"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="cups-command-chain.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/msweet/c/cups-trunk/doc/images/cups-command-chain.png"
+ inkscape:export-xdpi="100"
+ inkscape:export-ydpi="100">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="TriangleInS"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleInS"
+ style="overflow:visible">
+ <path
+ id="path4263"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(-0.2)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutS"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleOutS"
+ style="overflow:visible">
+ <path
+ id="path4272"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.2)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutM"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleOutM"
+ style="overflow:visible">
+ <path
+ id="path4269"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.4)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Mend"
+ style="overflow:visible;">
+ <path
+ id="path4132"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.4) rotate(180) translate(10,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Sstart"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Sstart"
+ style="overflow:visible">
+ <path
+ id="path4135"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.2) translate(6,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lstart"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lstart"
+ style="overflow:visible">
+ <path
+ id="path4141"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) translate(1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Lstart"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Lstart"
+ style="overflow:visible">
+ <path
+ id="path4123"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.8) translate(12.5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mstart"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mstart"
+ style="overflow:visible">
+ <path
+ id="path4147"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) translate(0,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="-490.8657 : 919.3427 : 1"
+ inkscape:vp_y="9.6977444e-14 : 1482.3941 : 0"
+ inkscape:vp_z="687.60276 : 919.3427 : 1"
+ inkscape:persp3d-origin="98.368532 : 659.34009 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.810628"
+ inkscape:cx="258.75"
+ inkscape:cy="67.5"
+ inkscape:document-units="in"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ units="in"
+ inkscape:snap-bbox="true"
+ inkscape:object-paths="true"
+ inkscape:object-nodes="true"
+ inkscape:bbox-paths="true"
+ inkscape:bbox-nodes="true"
+ inkscape:snap-intersection-line-segments="true"
+ inkscape:window-width="1073"
+ inkscape:window-height="701"
+ inkscape:window-x="747"
+ inkscape:window-y="9">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2383"
+ visible="true"
+ enabled="true"
+ units="in"
+ spacingx="0.125in"
+ spacingy="0.125in"
+ dotted="false"
+ empspacing="8" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 135,56.25 L 135,78.75"
+ id="path10785" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:8.12441158;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 55.812205,101.25 L 89.77536,101.25"
+ id="path4118" />
+ <path
+ id="path10220"
+ d="M 403.15192,101.25 L 429.50524,101.25"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:7.40767479;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#TriangleInS);marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:7.32613468;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#TriangleInS);marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 290.97054,101.25 L 316.53195,101.25"
+ id="path10781" />
+ <path
+ id="path10783"
+ d="M 178.34513,101.80229 L 203.90654,101.80229"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:7.32613468;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#TriangleInS);marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <g
+ id="g3596"
+ transform="matrix(0.5,0,0,0.5,67.958488,-33.525)">
+ <rect
+ y="100.83127"
+ x="90"
+ height="67.22084"
+ width="90"
+ id="rect3582"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25 A 45,11.25 0 1 1 180,101.25 z"
+ sodipodi:ry="11.25"
+ sodipodi:rx="45"
+ sodipodi:cy="101.25"
+ sodipodi:cx="135"
+ id="path3580"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:end="3.1415927"
+ sodipodi:start="0"
+ transform="matrix(1,0,0,1.0799999,0,58.500006)"
+ sodipodi:type="arc"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path3584"
+ sodipodi:cx="135"
+ sodipodi:cy="101.25"
+ sodipodi:rx="45"
+ sodipodi:ry="11.25"
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25 L 135,101.25 z" />
+ <path
+ sodipodi:open="true"
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25"
+ sodipodi:ry="11.25"
+ sodipodi:rx="45"
+ sodipodi:cy="101.25"
+ sodipodi:cx="135"
+ id="path3586"
+ style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc"
+ transform="translate(-0.45,67.05)"
+ sodipodi:start="0"
+ sodipodi:end="3.1415927" />
+ <path
+ id="path3588"
+ d="M 90,99.9365 L 89.583023,168.73466"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 180,100.94936 L 179.58302,169.74752"
+ id="path3590" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3592"
+ y="149.58008"
+ x="134.30273"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="149.58008"
+ x="134.30273"
+ id="tspan3594"
+ sodipodi:role="line">PPD</tspan></text>
+ </g>
+ <g
+ id="g4096"
+ transform="translate(0.2249985,-11.025002)">
+ <rect
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.44999999;stroke-miterlimit:4;stroke-dasharray:0.45, 0.45;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect3608"
+ width="67.5"
+ height="45"
+ x="101.025"
+ y="89.775002" />
+ <flowRoot
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ id="flowRoot3610"
+ transform="matrix(0.5,0,0,0.5,134.70508,106.84766)"><flowRegion
+ id="flowRegion3612" /><flowPara
+ id="flowPara3616">Optional</flowPara><flowPara
+ id="flowPara3620">Command</flowPara><flowPara
+ id="flowPara3618">Filter</flowPara></flowRoot> </g>
+ <g
+ id="g3724"
+ transform="matrix(0.5,0,0,0.5,-33.291512,33.75)">
+ <g
+ id="g3744">
+ <rect
+ y="100.83127"
+ x="90"
+ height="67.22084"
+ width="90"
+ id="rect3726"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25 A 45,11.25 0 1 1 180,101.25 z"
+ sodipodi:ry="11.25"
+ sodipodi:rx="45"
+ sodipodi:cy="101.25"
+ sodipodi:cx="135"
+ id="path3728"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:end="3.1415927"
+ sodipodi:start="0"
+ transform="matrix(1,0,0,1.0799999,0,58.500006)"
+ sodipodi:type="arc"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path3730"
+ sodipodi:cx="135"
+ sodipodi:cy="101.25"
+ sodipodi:rx="45"
+ sodipodi:ry="11.25"
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25 L 135,101.25 z" />
+ <path
+ sodipodi:open="true"
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25"
+ sodipodi:ry="11.25"
+ sodipodi:rx="45"
+ sodipodi:cy="101.25"
+ sodipodi:cx="135"
+ id="path3732"
+ style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc"
+ transform="translate(-0.45,67.05)"
+ sodipodi:start="0"
+ sodipodi:end="3.1415927" />
+ <path
+ id="path3734"
+ d="M 90,99.9365 L 89.583023,168.73466"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 180,100.94936 L 179.58302,169.74752"
+ id="path3736" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text3738"
+ y="139.58008"
+ x="134.30273"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="139.58008"
+ x="134.30273"
+ id="tspan3740"
+ sodipodi:role="line">Command</tspan><tspan
+ id="tspan3742"
+ y="155.58008"
+ x="134.30273"
+ sodipodi:role="line">File</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="matrix(0.5,0,0,0.5,202.63501,-10.934996)"
+ id="g3893">
+ <rect
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#747474;stroke-width:0.38684496;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect3887"
+ width="90"
+ height="51.961464"
+ x="611.20306"
+ y="207.32623"
+ transform="matrix(1,0,-0.4999983,0.8660264,0,0)" />
+ <rect
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#747474;stroke-width:0.36000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect3885"
+ width="135"
+ height="67.5"
+ x="472.04999"
+ y="202.05"
+ rx="10"
+ ry="10" />
+ <text
+ xml:space="preserve"
+ style="font-size:32px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="481.96405"
+ y="246.4836"
+ id="text3889"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3891"
+ x="481.96405"
+ y="246.4836">Printer</tspan></text>
+ </g>
+ <g
+ id="g3853"
+ transform="matrix(0.5,0,0,0.5,191.7,-1.5199184e-6)">
+ <g
+ id="g4104">
+ <rect
+ y="157.5"
+ x="44.099995"
+ height="90"
+ width="135"
+ id="rect3855"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:0.9, 0.9;stroke-dashoffset:0;stroke-opacity:1" />
+ <flowRoot
+ transform="translate(111.78164,191.19532)"
+ id="flowRoot3857"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3859" /><flowPara
+ id="flowPara3863">Optional</flowPara><flowPara
+ id="flowPara3865">Port</flowPara><flowPara
+ id="flowPara3867">Monitor</flowPara></flowRoot> </g>
+ </g>
+ <g
+ id="g4083"
+ transform="translate(22.725,-0.225)">
+ <g
+ id="g4112"
+ transform="translate(-0.45,-10.8)">
+ <rect
+ y="90"
+ x="303.75"
+ height="45"
+ width="67.5"
+ id="rect3814"
+ style="fill:#7fff00;fill-opacity:1;stroke:#000000;stroke-width:0.44999999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <flowRoot
+ transform="matrix(0.5,0,0,0.5,338.14944,116.67659)"
+ id="flowRoot3816"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3818" /><flowPara
+ id="flowPara3822">Backend</flowPara></flowRoot> </g>
+ </g>
+ </g>
+</svg>
diff --git a/doc/images/cups-icon.png b/doc/images/cups-icon.png
new file mode 100644
index 000000000..5c0f6ff20
--- /dev/null
+++ b/doc/images/cups-icon.png
Binary files differ
diff --git a/doc/images/cups-postscript-chain.png b/doc/images/cups-postscript-chain.png
new file mode 100644
index 000000000..41f8bced8
--- /dev/null
+++ b/doc/images/cups-postscript-chain.png
Binary files differ
diff --git a/doc/images/cups-postscript-chain.svg b/doc/images/cups-postscript-chain.svg
new file mode 100644
index 000000000..d1e2d3e84
--- /dev/null
+++ b/doc/images/cups-postscript-chain.svg
@@ -0,0 +1,531 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="630"
+ height="135"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="cups-postscript-chain.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/msweet/c/cups-trunk/doc/images/cups-postscript-chain.png"
+ inkscape:export-xdpi="100"
+ inkscape:export-ydpi="100">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="TriangleInS"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInS"
+ style="overflow:visible">
+ <path
+ id="path4263"
+ d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="scale(-0.2,-0.2)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutS"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutS"
+ style="overflow:visible">
+ <path
+ id="path4272"
+ d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="scale(0.2,0.2)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutM"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutM"
+ style="overflow:visible">
+ <path
+ id="path4269"
+ d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="scale(0.4,0.4)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Mend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Mend"
+ style="overflow:visible">
+ <path
+ id="path4132"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.4,0,0,-0.4,-4,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Sstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Sstart"
+ style="overflow:visible">
+ <path
+ id="path4135"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.2,0,0,0.2,1.2,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lstart"
+ style="overflow:visible">
+ <path
+ id="path4141"
+ style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z"
+ transform="matrix(1.1,0,0,1.1,1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Lstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Lstart"
+ style="overflow:visible">
+ <path
+ id="path4123"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.8,0,0,0.8,10,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Mstart"
+ style="overflow:visible">
+ <path
+ id="path4147"
+ style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z"
+ transform="scale(0.6,0.6)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="-490.8657 : 919.3427 : 1"
+ inkscape:vp_y="9.6977444e-14 : 1482.3941 : 0"
+ inkscape:vp_z="687.60276 : 919.3427 : 1"
+ inkscape:persp3d-origin="98.368532 : 659.34009 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.5492063"
+ inkscape:cx="315"
+ inkscape:cy="8.9209734"
+ inkscape:document-units="in"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ units="in"
+ inkscape:snap-bbox="true"
+ inkscape:object-paths="true"
+ inkscape:object-nodes="true"
+ inkscape:bbox-paths="true"
+ inkscape:bbox-nodes="true"
+ inkscape:snap-intersection-line-segments="true"
+ inkscape:window-width="1073"
+ inkscape:window-height="701"
+ inkscape:window-x="747"
+ inkscape:window-y="9">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2383"
+ visible="true"
+ enabled="true"
+ units="in"
+ spacingx="0.125in"
+ spacingy="0.125in"
+ dotted="false"
+ empspacing="8" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 230.6911,54.143596 L 135,78.75"
+ id="path11557" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 247.95,56.25 L 247.95,78.75"
+ id="path10785" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:8.12441158;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 55.812205,101.25 L 89.77536,101.25"
+ id="path4118" />
+ <path
+ id="path10220"
+ d="M 516.10192,101.25 L 542.45524,101.25"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:7.40767479;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#TriangleInS);marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:7.32613468;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#TriangleInS);marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 403.92054,101.25 L 429.48195,101.25"
+ id="path10781" />
+ <path
+ id="path10783"
+ d="M 291.29513,101.80229 L 316.85654,101.80229"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:7.32613468;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#TriangleInS);marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <g
+ id="g3596"
+ transform="matrix(0.5,0,0,0.5,180.90849,-33.525)">
+ <rect
+ y="100.83127"
+ x="90"
+ height="67.22084"
+ width="90"
+ id="rect3582"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25 A 45,11.25 0 1 1 180,101.25 z"
+ sodipodi:ry="11.25"
+ sodipodi:rx="45"
+ sodipodi:cy="101.25"
+ sodipodi:cx="135"
+ id="path3580"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:end="3.1415927"
+ sodipodi:start="0"
+ transform="matrix(1,0,0,1.0799999,0,58.500006)"
+ sodipodi:type="arc"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path3584"
+ sodipodi:cx="135"
+ sodipodi:cy="101.25"
+ sodipodi:rx="45"
+ sodipodi:ry="11.25"
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25 L 135,101.25 z" />
+ <path
+ sodipodi:open="true"
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25"
+ sodipodi:ry="11.25"
+ sodipodi:rx="45"
+ sodipodi:cy="101.25"
+ sodipodi:cx="135"
+ id="path3586"
+ style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc"
+ transform="translate(-0.45,67.05)"
+ sodipodi:start="0"
+ sodipodi:end="3.1415927" />
+ <path
+ id="path3588"
+ d="M 90,99.9365 L 89.583023,168.73466"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 180,100.94936 L 179.58302,169.74752"
+ id="path3590" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3592"
+ y="149.58008"
+ x="134.30273"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="149.58008"
+ x="134.30273"
+ id="tspan3594"
+ sodipodi:role="line">PPD</tspan></text>
+ </g>
+ <g
+ transform="matrix(0.5,0,0,0.5,315.58501,-10.934996)"
+ id="g3893">
+ <rect
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#747474;stroke-width:0.38684496;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect3887"
+ width="90"
+ height="51.961464"
+ x="611.20306"
+ y="207.32623"
+ transform="matrix(1,0,-0.4999983,0.8660264,0,0)" />
+ <rect
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#747474;stroke-width:0.36000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect3885"
+ width="135"
+ height="67.5"
+ x="472.04999"
+ y="202.05"
+ rx="10"
+ ry="10" />
+ <text
+ xml:space="preserve"
+ style="font-size:32px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="481.96405"
+ y="246.4836"
+ id="text3889"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3891"
+ x="481.96405"
+ y="246.4836">Printer</tspan></text>
+ </g>
+ <g
+ id="g3853"
+ transform="matrix(0.5,0,0,0.5,304.65,-1.5258789e-6)">
+ <g
+ id="g4104">
+ <rect
+ y="157.5"
+ x="44.099995"
+ height="90"
+ width="135"
+ id="rect3855"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:0.9, 0.9;stroke-dashoffset:0;stroke-opacity:1" />
+ <flowRoot
+ transform="translate(111.78164,191.19532)"
+ id="flowRoot3857"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3859" /><flowPara
+ id="flowPara3863">Optional</flowPara><flowPara
+ id="flowPara3865">Port</flowPara><flowPara
+ id="flowPara3867">Monitor</flowPara></flowRoot> </g>
+ </g>
+ <g
+ id="g4083"
+ transform="translate(135.675,-0.225)">
+ <g
+ id="g4112"
+ transform="translate(-0.45,-10.8)">
+ <rect
+ y="90"
+ x="303.75"
+ height="45"
+ width="67.5"
+ id="rect3814"
+ style="fill:#7fff00;fill-opacity:1;stroke:#000000;stroke-width:0.44999999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <flowRoot
+ transform="matrix(0.5,0,0,0.5,338.14944,116.67659)"
+ id="flowRoot3816"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3818" /><flowPara
+ id="flowPara3822">Backend</flowPara></flowRoot> </g>
+ </g>
+ <g
+ id="g11327"
+ transform="translate(0,-10.8)">
+ <g
+ id="g3564"
+ transform="matrix(0.5,0,0,0.5,191.475,-0.225)">
+ <flowRoot
+ transform="translate(-0.7816377,17.247326)"
+ id="flowRoot3568"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3570"><use
+ height="630"
+ width="630"
+ id="use3572"
+ xlink:href="#rect2768"
+ y="0"
+ x="0" /></flowRegion><flowPara
+ id="flowPara3574">Optional</flowPara><flowPara
+ id="flowPara3578">PostScript</flowPara><flowPara
+ id="flowPara3576">Filter</flowPara></flowRoot> <g
+ id="g11354">
+ <rect
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:0.89999998, 1.79999995;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect3566"
+ width="135"
+ height="90"
+ x="45"
+ y="180" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text11346"
+ y="213.24532"
+ x="112.47734"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="213.24532"
+ x="112.47734"
+ id="tspan11348"
+ sodipodi:role="line">Optional</tspan><tspan
+ id="tspan11350"
+ y="233.24532"
+ x="112.47734"
+ sodipodi:role="line">PostScript</tspan><tspan
+ id="tspan11352"
+ y="253.24532"
+ x="112.47734"
+ sodipodi:role="line">Filter</tspan></text>
+ </g>
+ </g>
+ </g>
+ <g
+ id="g3693"
+ transform="matrix(0.5,0,0,0.5,191.84368,-23.741102)">
+ <g
+ id="g11542"
+ transform="translate(-450.27038,115.4322)">
+ <rect
+ y="100.83127"
+ x="90"
+ height="67.22084"
+ width="90"
+ id="rect3646"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25 A 45,11.25 0 1 1 180,101.25 z"
+ sodipodi:ry="11.25"
+ sodipodi:rx="45"
+ sodipodi:cy="101.25"
+ sodipodi:cx="135"
+ id="path3648"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:end="3.1415927"
+ sodipodi:start="0"
+ transform="matrix(1,0,0,1.0799999,0,58.500006)"
+ sodipodi:type="arc"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path3650"
+ sodipodi:cx="135"
+ sodipodi:cy="101.25"
+ sodipodi:rx="45"
+ sodipodi:ry="11.25"
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25 L 135,101.25 z" />
+ <path
+ sodipodi:open="true"
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25"
+ sodipodi:ry="11.25"
+ sodipodi:rx="45"
+ sodipodi:cy="101.25"
+ sodipodi:cx="135"
+ id="path3652"
+ style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc"
+ transform="translate(-0.45,67.05)"
+ sodipodi:start="0"
+ sodipodi:end="3.1415927" />
+ <path
+ id="path3654"
+ d="M 90,99.9365 L 89.583023,168.73466"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 180,100.94936 L 179.58302,169.74752"
+ id="path3656" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3658"
+ y="139.58008"
+ x="134.30273"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="139.58008"
+ x="134.30273"
+ id="tspan3660"
+ sodipodi:role="line">Print</tspan><tspan
+ id="tspan3662"
+ y="164.58008"
+ x="134.30273"
+ sodipodi:role="line">File</tspan></text>
+ </g>
+ <g
+ id="g11399"
+ transform="translate(-450.27038,114.0822)">
+ <g
+ id="g3622"
+ transform="translate(392.34954,180.45)">
+ <g
+ id="g3636">
+ <g
+ transform="translate(-167.81652,-270)"
+ id="g3786">
+ <rect
+ y="180"
+ x="45"
+ height="90"
+ width="135"
+ id="rect3624"
+ style="fill:#7fff00;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <flowRoot
+ transform="translate(-2.7816377,25.247326)"
+ id="flowRoot3626"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3628"><use
+ height="630"
+ width="630"
+ id="use3630"
+ xlink:href="#rect2768"
+ y="0"
+ x="0" /></flowRegion><flowPara
+ id="flowPara3632">CUPS</flowPara><flowPara
+ id="flowPara3634">Filters</flowPara></flowRoot> </g>
+ </g>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="336.27359"
+ y="130.69901"
+ id="text11380"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan11382"
+ x="336.27359"
+ y="130.69901">CUPS</tspan><tspan
+ sodipodi:role="line"
+ x="336.27359"
+ y="155.69901"
+ id="tspan11384">Filters</tspan></text>
+ </g>
+ </g>
+ <path
+ id="path11553"
+ d="M 168.75,101.25 L 202.71316,101.25"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:8.12441158;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+</svg>
diff --git a/doc/images/cups-raster-chain.png b/doc/images/cups-raster-chain.png
new file mode 100644
index 000000000..5349bd9f5
--- /dev/null
+++ b/doc/images/cups-raster-chain.png
Binary files differ
diff --git a/doc/images/cups-raster-chain.svg b/doc/images/cups-raster-chain.svg
new file mode 100644
index 000000000..5130c8191
--- /dev/null
+++ b/doc/images/cups-raster-chain.svg
@@ -0,0 +1,534 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="630"
+ height="135"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="cups-raster-chain.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/msweet/c/cups-trunk/doc/images/cups-raster-chain.png"
+ inkscape:export-xdpi="100"
+ inkscape:export-ydpi="100">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="TriangleInS"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInS"
+ style="overflow:visible">
+ <path
+ id="path4263"
+ d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="scale(-0.2,-0.2)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutS"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutS"
+ style="overflow:visible">
+ <path
+ id="path4272"
+ d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="scale(0.2,0.2)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutM"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutM"
+ style="overflow:visible">
+ <path
+ id="path4269"
+ d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="scale(0.4,0.4)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Mend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Mend"
+ style="overflow:visible">
+ <path
+ id="path4132"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.4,0,0,-0.4,-4,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Sstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Sstart"
+ style="overflow:visible">
+ <path
+ id="path4135"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.2,0,0,0.2,1.2,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lstart"
+ style="overflow:visible">
+ <path
+ id="path4141"
+ style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z"
+ transform="matrix(1.1,0,0,1.1,1.1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Lstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Lstart"
+ style="overflow:visible">
+ <path
+ id="path4123"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.8,0,0,0.8,10,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Mstart"
+ style="overflow:visible">
+ <path
+ id="path4147"
+ style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z"
+ transform="scale(0.6,0.6)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="-490.8657 : 919.3427 : 1"
+ inkscape:vp_y="9.6977444e-14 : 1482.3941 : 0"
+ inkscape:vp_z="687.60276 : 919.3427 : 1"
+ inkscape:persp3d-origin="98.368532 : 659.34009 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.5492063"
+ inkscape:cx="315"
+ inkscape:cy="8.9209734"
+ inkscape:document-units="in"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ units="in"
+ inkscape:snap-bbox="true"
+ inkscape:object-paths="true"
+ inkscape:object-nodes="true"
+ inkscape:bbox-paths="true"
+ inkscape:bbox-nodes="true"
+ inkscape:snap-intersection-line-segments="true"
+ inkscape:window-width="1073"
+ inkscape:window-height="701"
+ inkscape:window-x="747"
+ inkscape:window-y="9">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2383"
+ visible="true"
+ enabled="true"
+ units="in"
+ spacingx="0.125in"
+ spacingy="0.125in"
+ dotted="false"
+ empspacing="8" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 230.6911,54.143596 L 135,78.75"
+ id="path11557" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 247.95,56.25 L 247.95,78.75"
+ id="path10785" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:8.12441158;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 55.812205,101.25 L 89.77536,101.25"
+ id="path4118" />
+ <path
+ id="path10220"
+ d="M 516.10192,101.25 L 542.45524,101.25"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:7.40767479;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#TriangleInS);marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:7.32613468;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#TriangleInS);marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 403.92054,101.25 L 429.48195,101.25"
+ id="path10781" />
+ <path
+ id="path10783"
+ d="M 291.29513,101.80229 L 316.85654,101.80229"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:7.32613468;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#TriangleInS);marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <g
+ id="g3596"
+ transform="matrix(0.5,0,0,0.5,180.90849,-33.525)">
+ <rect
+ y="100.83127"
+ x="90"
+ height="67.22084"
+ width="90"
+ id="rect3582"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25 A 45,11.25 0 1 1 180,101.25 z"
+ sodipodi:ry="11.25"
+ sodipodi:rx="45"
+ sodipodi:cy="101.25"
+ sodipodi:cx="135"
+ id="path3580"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:end="3.1415927"
+ sodipodi:start="0"
+ transform="matrix(1,0,0,1.0799999,0,58.500006)"
+ sodipodi:type="arc"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path3584"
+ sodipodi:cx="135"
+ sodipodi:cy="101.25"
+ sodipodi:rx="45"
+ sodipodi:ry="11.25"
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25 L 135,101.25 z" />
+ <path
+ sodipodi:open="true"
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25"
+ sodipodi:ry="11.25"
+ sodipodi:rx="45"
+ sodipodi:cy="101.25"
+ sodipodi:cx="135"
+ id="path3586"
+ style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc"
+ transform="translate(-0.45,67.05)"
+ sodipodi:start="0"
+ sodipodi:end="3.1415927" />
+ <path
+ id="path3588"
+ d="M 90,99.9365 L 89.583023,168.73466"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 180,100.94936 L 179.58302,169.74752"
+ id="path3590" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3592"
+ y="149.58008"
+ x="134.30273"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="149.58008"
+ x="134.30273"
+ id="tspan3594"
+ sodipodi:role="line">PPD</tspan></text>
+ </g>
+ <g
+ transform="matrix(0.5,0,0,0.5,315.58501,-10.934996)"
+ id="g3893">
+ <rect
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#747474;stroke-width:0.38684496;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect3887"
+ width="90"
+ height="51.961464"
+ x="611.20306"
+ y="207.32623"
+ transform="matrix(1,0,-0.4999983,0.8660264,0,0)" />
+ <rect
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#747474;stroke-width:0.36000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect3885"
+ width="135"
+ height="67.5"
+ x="472.04999"
+ y="202.05"
+ rx="10"
+ ry="10" />
+ <text
+ xml:space="preserve"
+ style="font-size:32px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="481.96405"
+ y="246.4836"
+ id="text3889"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3891"
+ x="481.96405"
+ y="246.4836">Printer</tspan></text>
+ </g>
+ <g
+ id="g3853"
+ transform="matrix(0.5,0,0,0.5,304.65,-1.5258789e-6)">
+ <g
+ id="g4104">
+ <rect
+ y="157.5"
+ x="44.099995"
+ height="90"
+ width="135"
+ id="rect3855"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:0.9, 0.9;stroke-dashoffset:0;stroke-opacity:1" />
+ <flowRoot
+ transform="translate(111.78164,191.19532)"
+ id="flowRoot3857"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3859" /><flowPara
+ id="flowPara3863">Optional</flowPara><flowPara
+ id="flowPara3865">Port</flowPara><flowPara
+ id="flowPara3867">Monitor</flowPara></flowRoot> </g>
+ </g>
+ <g
+ id="g4083"
+ transform="translate(135.675,-0.225)">
+ <g
+ id="g4112"
+ transform="translate(-0.45,-10.8)">
+ <rect
+ y="90"
+ x="303.75"
+ height="45"
+ width="67.5"
+ id="rect3814"
+ style="fill:#7fff00;fill-opacity:1;stroke:#000000;stroke-width:0.44999999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <flowRoot
+ transform="matrix(0.5,0,0,0.5,338.14944,116.67659)"
+ id="flowRoot3816"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3818" /><flowPara
+ id="flowPara3822">Backend</flowPara></flowRoot> </g>
+ </g>
+ <g
+ id="g11327"
+ transform="translate(0,-10.8)">
+ <g
+ id="g3564"
+ transform="matrix(0.5,0,0,0.5,191.475,-0.225)">
+ <flowRoot
+ transform="translate(-0.7816377,17.247326)"
+ id="flowRoot3568"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3570"><use
+ height="630"
+ width="630"
+ id="use3572"
+ xlink:href="#rect2768"
+ y="0"
+ x="0" /></flowRegion><flowPara
+ id="flowPara3574">Optional</flowPara><flowPara
+ id="flowPara3578">PostScript</flowPara><flowPara
+ id="flowPara3576">Filter</flowPara></flowRoot> <g
+ id="g11354">
+ <g
+ id="g11692">
+ <rect
+ y="180"
+ x="45"
+ height="90"
+ width="135"
+ id="rect3566"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="112.47734"
+ y="213.24532"
+ id="text11346"
+ sodipodi:linespacing="100%"><tspan
+ sodipodi:role="line"
+ x="112.47734"
+ y="213.24532"
+ id="tspan11350">Required</tspan><tspan
+ id="tspan11690"
+ sodipodi:role="line"
+ x="112.47734"
+ y="233.24532">Raster</tspan><tspan
+ sodipodi:role="line"
+ x="112.47734"
+ y="253.24532"
+ id="tspan11352">Filter</tspan></text>
+ </g>
+ </g>
+ </g>
+ </g>
+ <g
+ id="g3693"
+ transform="matrix(0.5,0,0,0.5,191.84368,-23.741102)">
+ <g
+ id="g11542"
+ transform="translate(-450.27038,115.4322)">
+ <rect
+ y="100.83127"
+ x="90"
+ height="67.22084"
+ width="90"
+ id="rect3646"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25 A 45,11.25 0 1 1 180,101.25 z"
+ sodipodi:ry="11.25"
+ sodipodi:rx="45"
+ sodipodi:cy="101.25"
+ sodipodi:cx="135"
+ id="path3648"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:end="3.1415927"
+ sodipodi:start="0"
+ transform="matrix(1,0,0,1.0799999,0,58.500006)"
+ sodipodi:type="arc"
+ style="fill:#e8e8e8;fill-opacity:1;stroke:none;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path3650"
+ sodipodi:cx="135"
+ sodipodi:cy="101.25"
+ sodipodi:rx="45"
+ sodipodi:ry="11.25"
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25 L 135,101.25 z" />
+ <path
+ sodipodi:open="true"
+ d="M 180,101.25 A 45,11.25 0 1 1 90,101.25"
+ sodipodi:ry="11.25"
+ sodipodi:rx="45"
+ sodipodi:cy="101.25"
+ sodipodi:cx="135"
+ id="path3652"
+ style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc"
+ transform="translate(-0.45,67.05)"
+ sodipodi:start="0"
+ sodipodi:end="3.1415927" />
+ <path
+ id="path3654"
+ d="M 90,99.9365 L 89.583023,168.73466"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 180,100.94936 L 179.58302,169.74752"
+ id="path3656" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3658"
+ y="139.58008"
+ x="134.30273"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="139.58008"
+ x="134.30273"
+ id="tspan3660"
+ sodipodi:role="line">Print</tspan><tspan
+ id="tspan3662"
+ y="164.58008"
+ x="134.30273"
+ sodipodi:role="line">File</tspan></text>
+ </g>
+ <g
+ id="g11399"
+ transform="translate(-450.27038,114.0822)">
+ <g
+ id="g3622"
+ transform="translate(392.34954,180.45)">
+ <g
+ id="g3636">
+ <g
+ transform="translate(-167.81652,-270)"
+ id="g3786">
+ <rect
+ y="180"
+ x="45"
+ height="90"
+ width="135"
+ id="rect3624"
+ style="fill:#7fff00;fill-opacity:1;stroke:#000000;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <flowRoot
+ transform="translate(-2.7816377,25.247326)"
+ id="flowRoot3626"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:100%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3628"><use
+ height="630"
+ width="630"
+ id="use3630"
+ xlink:href="#rect2768"
+ y="0"
+ x="0" /></flowRegion><flowPara
+ id="flowPara3632">CUPS</flowPara><flowPara
+ id="flowPara3634">Filters</flowPara></flowRoot> </g>
+ </g>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="336.27359"
+ y="130.69901"
+ id="text11380"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan11382"
+ x="336.27359"
+ y="130.69901">CUPS</tspan><tspan
+ sodipodi:role="line"
+ x="336.27359"
+ y="155.69901"
+ id="tspan11384">Filters</tspan></text>
+ </g>
+ </g>
+ <path
+ id="path11553"
+ d="M 168.75,101.25 L 202.71316,101.25"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:8.12441158;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-mid:none;marker-end:url(#TriangleOutS);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+</svg>
diff --git a/doc/images/cups.png b/doc/images/cups.png
new file mode 100644
index 000000000..5c0f6ff20
--- /dev/null
+++ b/doc/images/cups.png
Binary files differ
diff --git a/doc/images/cups.svg b/doc/images/cups.svg
new file mode 100644
index 000000000..8d19c358c
--- /dev/null
+++ b/doc/images/cups.svg
@@ -0,0 +1,533 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="100"
+ height="100"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docbase="/home/mike/c/cups-trunk/desktop"
+ sodipodi:docname="cups.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/msweet/c/cups-trunk/desktop/cups-512.png"
+ inkscape:export-xdpi="460.79999"
+ inkscape:export-ydpi="460.79999">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3645">
+ <stop
+ id="stop3647"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3649"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3515">
+ <stop
+ style="stop-color:#ccff66;stop-opacity:1;"
+ offset="0"
+ id="stop3517" />
+ <stop
+ style="stop-color:#00cc00;stop-opacity:1;"
+ offset="1"
+ id="stop3519" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3377">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3379" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3381" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3280">
+ <stop
+ style="stop-color:#ffffbf;stop-opacity:1;"
+ offset="0"
+ id="stop3282" />
+ <stop
+ style="stop-color:#ffffbf;stop-opacity:0;"
+ offset="1"
+ id="stop3284" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3270">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop3272" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3274" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3251">
+ <stop
+ style="stop-color:#ccff66;stop-opacity:1;"
+ offset="0"
+ id="stop3253" />
+ <stop
+ style="stop-color:#007700;stop-opacity:1;"
+ offset="1"
+ id="stop3255" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3416">
+ <stop
+ style="stop-color:#7fff00;stop-opacity:1;"
+ offset="0"
+ id="stop3418" />
+ <stop
+ style="stop-color:#1f7f00;stop-opacity:1;"
+ offset="1"
+ id="stop3420" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3530">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.74901962;"
+ offset="0"
+ id="stop3532" />
+ <stop
+ style="stop-color:#333333;stop-opacity:0;"
+ offset="1"
+ id="stop3534" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3690">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.49803922;"
+ offset="0"
+ id="stop3692" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3694" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3680">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.49803922"
+ offset="0"
+ id="stop3682" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3684" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3658">
+ <stop
+ style="stop-color:#cccc99;stop-opacity:1;"
+ offset="0"
+ id="stop3660" />
+ <stop
+ style="stop-color:#cccc99;stop-opacity:0;"
+ offset="1"
+ id="stop3662" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 50 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="100 : 50 : 1"
+ inkscape:persp3d-origin="50 : 33.333333 : 1"
+ id="perspective2838" />
+ <linearGradient
+ id="linearGradient3269">
+ <stop
+ style="stop-color:#00ff00;stop-opacity:1;"
+ offset="0"
+ id="stop3271" />
+ <stop
+ style="stop-color:#007f00;stop-opacity:1;"
+ offset="1"
+ id="stop3273" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3226">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop3228" />
+ <stop
+ style="stop-color:#333333;stop-opacity:1;"
+ offset="1"
+ id="stop3230" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3214">
+ <stop
+ style="stop-color:#00ff00;stop-opacity:1;"
+ offset="0"
+ id="stop3216" />
+ <stop
+ style="stop-color:#007f00;stop-opacity:1;"
+ offset="1"
+ id="stop3218" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5228">
+ <stop
+ style="stop-color:#cccc99;stop-opacity:0"
+ offset="0"
+ id="stop5230" />
+ <stop
+ id="stop5236"
+ offset="0.89999998"
+ style="stop-color:#cccc99;stop-opacity:0;" />
+ <stop
+ style="stop-color:#cccc99;stop-opacity:1"
+ offset="1"
+ id="stop5232" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5198">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop5200" />
+ <stop
+ style="stop-color:#333333;stop-opacity:0.94117647;"
+ offset="1"
+ id="stop5202" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5177">
+ <stop
+ style="stop-color:#cccc99;stop-opacity:1;"
+ offset="0"
+ id="stop5179" />
+ <stop
+ style="stop-color:#cccc99;stop-opacity:0.49803922"
+ offset="1"
+ id="stop5181" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4768">
+ <stop
+ id="stop4770"
+ offset="0"
+ style="stop-color:#e8e8e8;stop-opacity:0.90980393;" />
+ <stop
+ id="stop4772"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3598">
+ <stop
+ id="stop3600"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ <stop
+ id="stop3602"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2165">
+ <stop
+ style="stop-color:#350000;stop-opacity:1;"
+ offset="0"
+ id="stop2167" />
+ <stop
+ style="stop-color:#ff3333;stop-opacity:1;"
+ offset="1"
+ id="stop2169" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3196">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3198" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3200" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3160">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3162" />
+ <stop
+ id="stop3192"
+ offset="0.75"
+ style="stop-color:#ffffff;stop-opacity:0.24705882;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop3164" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3257">
+ <path
+ transform="matrix(1,0,0,0.9882639,0,5.8678726e-2)"
+ d="M 95 50.534397 A 45 45.534397 0 1 1 5,50.534397 A 45 45.534397 0 1 1 95 50.534397 z"
+ sodipodi:ry="45.534397"
+ sodipodi:rx="45"
+ sodipodi:cy="50.534397"
+ sodipodi:cx="50"
+ id="path3259"
+ style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:type="arc" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3704">
+ <path
+ sodipodi:type="arc"
+ style="opacity:1;fill:#000000;fill-opacity:0.49803922;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path3706"
+ sodipodi:cx="51.104416"
+ sodipodi:cy="48.192772"
+ sodipodi:rx="39.658634"
+ sodipodi:ry="43.574299"
+ d="M 90.76305,48.192772 A 39.658634,43.574299 0 1 1 11.445782,48.192772 A 39.658634,43.574299 0 1 1 90.76305,48.192772 z"
+ transform="matrix(1.003038,0,0,1.0232718,-1.4805538,0.2740483)" />
+ </clipPath>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3270"
+ id="linearGradient3276"
+ x1="50.200802"
+ y1="91.967865"
+ x2="50.200802"
+ y2="67.948906"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3280"
+ id="linearGradient3286"
+ x1="47.690762"
+ y1="6.6265068"
+ x2="47.690762"
+ y2="53.815262"
+ gradientUnits="userSpaceOnUse" />
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3295">
+ <path
+ transform="matrix(0.8148984,0,0,0.6256338,5.5549494,4.4908095)"
+ d="M 96.184742,26.706827 A 44.477913,23.293173 0 1 1 7.2289162,26.706827 A 44.477913,23.293173 0 1 1 96.184742,26.706827 z"
+ sodipodi:ry="23.293173"
+ sodipodi:rx="44.477913"
+ sodipodi:cy="26.706827"
+ sodipodi:cx="51.706829"
+ id="path3297"
+ style="opacity:1;fill:#ffffbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3371">
+ <path
+ sodipodi:type="arc"
+ style="opacity:1;fill:#ffffbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path3373"
+ sodipodi:cx="48.895584"
+ sodipodi:cy="47.188755"
+ sodipodi:rx="42.269077"
+ sodipodi:ry="41.767067"
+ d="M 91.164661,47.188755 A 42.269077,41.767067 0 1 1 6.6265068,47.188755 A 42.269077,41.767067 0 1 1 91.164661,47.188755 z"
+ transform="matrix(0.9784331,0,0,0.9984421,2.7613512,2.0815482)" />
+ </clipPath>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3515"
+ id="radialGradient3521"
+ cx="51.405624"
+ cy="71.446022"
+ fx="51.405624"
+ fy="71.446022"
+ r="41.566265"
+ gradientTransform="matrix(1,0,0,1.5633645,0,-39.484036)"
+ gradientUnits="userSpaceOnUse" />
+ <filter
+ inkscape:collect="always"
+ id="filter3587"
+ x="-0.12220446"
+ width="1.2444089"
+ y="-0.11793158"
+ height="1.2358632">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="4.2329858"
+ id="feGaussianBlur3589" />
+ </filter>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3591">
+ <path
+ transform="translate(2.9340892e-7,-2.3929013)"
+ d="M 92.971889,50.301205 A 41.566265,43.072289 0 1 1 9.8393593,50.301205 A 41.566265,43.072289 0 1 1 92.971889,50.301205 z"
+ sodipodi:ry="43.072289"
+ sodipodi:rx="41.566265"
+ sodipodi:cy="50.301205"
+ sodipodi:cx="51.405624"
+ id="path3593"
+ style="opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ </clipPath>
+ <filter
+ inkscape:collect="always"
+ id="filter3611">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="2.1711472"
+ id="feGaussianBlur3613" />
+ </filter>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3645"
+ id="radialGradient3695"
+ cx="-6.7269073"
+ cy="27.94368"
+ fx="-6.7269073"
+ fy="27.94368"
+ r="12.5502"
+ gradientTransform="matrix(-1.9906652,-2.2927541e-8,1.4386067e-8,-1.5156153,-20.117928,50.98641)"
+ gradientUnits="userSpaceOnUse" />
+ <filter
+ inkscape:collect="always"
+ id="filter3797"
+ x="-0.098526749"
+ width="1.1970535"
+ y="-0.15589675"
+ height="1.3117935">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="1.030442"
+ id="feGaussianBlur3799" />
+ </filter>
+ <filter
+ inkscape:collect="always"
+ id="filter3807">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.1030442"
+ id="feGaussianBlur3809" />
+ </filter>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3645"
+ id="radialGradient3815"
+ cx="-6.7269082"
+ cy="29.116467"
+ fx="-6.7269082"
+ fy="29.116467"
+ r="12.5502"
+ gradientTransform="matrix(-1,-6.831379e-8,3.8912925e-8,-0.6320001,-13.453817,27.036147)"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="1"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.98"
+ inkscape:cx="50"
+ inkscape:cy="50"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ width="100px"
+ height="100px"
+ showgrid="true"
+ inkscape:grid-points="true"
+ inkscape:window-width="872"
+ inkscape:window-height="713"
+ inkscape:window-x="2458"
+ inkscape:window-y="22"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:snap-global="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2840" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ <dc:title>CUPS Icon</dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Michael Sweet</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>Apple Inc.</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ id="g2882"
+ transform="matrix(1.1282649,0,0,1.1259993,-5.472226,-6.4135954)">
+ <path
+ id="text2870"
+ d="M 72.501767,34.960416 L 82.666767,34.960416 C 82.096028,30.894474 80.883363,27.327811 79.028767,24.260416 C 77.174033,21.121817 74.855702,18.518153 72.073767,16.449416 C 69.291708,14.380824 66.117378,12.811492 62.550767,11.741416 C 58.984052,10.671494 55.203389,10.136495 51.208767,10.136416 C 45.359398,10.136495 40.15207,11.206494 35.586767,13.346416 C 31.092746,15.415156 27.312083,18.268487 24.244767,21.906416 C 21.248756,25.544479 18.966092,29.824475 17.396767,34.746416 C 15.827428,39.597132 15.042762,44.80446 15.042767,50.368416 C 15.042762,55.932449 15.756095,61.139777 17.182767,65.990416 C 18.680758,70.841101 20.89209,75.049763 23.816767,78.616416 C 26.741417,82.183089 30.41508,85.000753 34.837767,87.069416 C 39.260405,89.066749 44.432066,90.065415 50.352767,90.065416 C 60.125384,90.065415 67.829376,87.390417 73.464767,82.040416 C 79.100031,76.690428 82.417028,69.200436 83.415767,59.570416 L 73.250767,59.570416 C 73.036704,62.709109 72.394705,65.633772 71.324767,68.344416 C 70.254707,71.0551 68.756708,73.409098 66.830767,75.406416 C 64.976046,77.332427 62.729048,78.866093 60.089767,80.007416 C 57.52172,81.077424 54.561389,81.612423 51.208767,81.612416 C 46.643397,81.612423 42.720068,80.756424 39.438767,79.044416 C 36.157408,77.332427 33.446744,75.049763 31.306767,72.196416 C 29.238081,69.271769 27.704416,65.883439 26.705767,62.031416 C 25.707085,58.108113 25.207752,53.970784 25.207767,49.619416 C 25.207752,45.624793 25.707085,41.772796 26.705767,38.063416 C 27.704416,34.354137 29.238081,31.072807 31.306767,28.219416 C 33.446744,25.294813 36.121741,22.976482 39.331767,21.264416 C 42.613068,19.552485 46.536397,18.696486 51.101767,18.696416 C 56.451721,18.696486 61.052716,20.051818 64.904767,22.762416 C 68.828042,25.473146 71.360372,29.539142 72.501767,34.960416"
+ style="font-size:107px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Helvetica Neue;-inkscape-font-specification:Helvetica Neue" />
+ <path
+ id="text2862"
+ d="M 40.964993,34.10077 L 40.964993,29.66077 L 39.394993,29.66077 L 39.394993,34.10077 C 39.394987,34.634105 39.288321,35.027438 39.074993,35.28077 C 38.861655,35.527438 38.474988,35.650771 37.914993,35.65077 C 37.594989,35.650771 37.338323,35.607438 37.144993,35.52077 C 36.958323,35.427438 36.811657,35.310771 36.704993,35.17077 C 36.598323,35.024105 36.528324,34.857438 36.494993,34.67077 C 36.461657,34.484105 36.44499,34.294106 36.444993,34.10077 L 36.444993,29.66077 L 34.874993,29.66077 L 34.874993,34.10077 C 34.874992,35.074105 35.138325,35.794104 35.664993,36.26077 C 36.198324,36.727437 36.948323,36.96077 37.914993,36.96077 C 38.868321,36.96077 39.614987,36.727437 40.154993,36.26077 C 40.694986,35.787437 40.964986,35.067438 40.964993,34.10077 M 42.326868,29.66077 L 42.326868,36.80077 L 43.796868,36.80077 L 43.796868,32.02077 L 43.816868,32.02077 L 46.786868,36.80077 L 48.356868,36.80077 L 48.356868,29.66077 L 46.886868,29.66077 L 46.886868,34.45077 L 46.866868,34.45077 L 43.886868,29.66077 L 42.326868,29.66077 M 49.729211,29.66077 L 49.729211,36.80077 L 51.299211,36.80077 L 51.299211,29.66077 L 49.729211,29.66077 M 54.408899,33.06077 L 51.918899,36.80077 L 53.678899,36.80077 L 55.268899,34.33077 L 56.828899,36.80077 L 58.698899,36.80077 L 56.208899,33.07077 L 58.498899,29.66077 L 56.778899,29.66077 L 55.328899,31.94077 L 53.928899,29.66077 L 52.108899,29.66077 L 54.408899,33.06077 M 36.474993,43.02077 L 36.474993,40.88077 L 37.694993,40.88077 C 37.874989,40.880776 38.048322,40.894109 38.214993,40.92077 C 38.381655,40.947442 38.528322,41.000776 38.654993,41.08077 C 38.781655,41.154109 38.881655,41.260775 38.954993,41.40077 C 39.034988,41.540775 39.074988,41.724108 39.074993,41.95077 C 39.074988,42.177441 39.034988,42.360774 38.954993,42.50077 C 38.881655,42.640774 38.781655,42.750774 38.654993,42.83077 C 38.528322,42.904107 38.381655,42.954107 38.214993,42.98077 C 38.048322,43.00744 37.874989,43.020774 37.694993,43.02077 L 36.474993,43.02077 M 34.904993,39.66077 L 34.904993,46.80077 L 36.474993,46.80077 L 36.474993,44.24077 L 38.124993,44.24077 C 38.571655,44.240772 38.951654,44.177439 39.264993,44.05077 C 39.57832,43.917439 39.831654,43.744106 40.024993,43.53077 C 40.224987,43.31744 40.36832,43.074107 40.454993,42.80077 C 40.54832,42.520774 40.594986,42.237441 40.594993,41.95077 C 40.594986,41.657442 40.54832,41.374109 40.454993,41.10077 C 40.36832,40.827442 40.224987,40.584109 40.024993,40.37077 C 39.831654,40.157443 39.57832,39.987443 39.264993,39.86077 C 38.951654,39.727444 38.571655,39.660777 38.124993,39.66077 L 34.904993,39.66077 M 43.135149,42.89077 L 43.135149,40.88077 L 44.855149,40.88077 C 45.215144,40.880776 45.485144,40.960776 45.665149,41.12077 C 45.845144,41.274109 45.935144,41.524108 45.935149,41.87077 C 45.935144,42.230774 45.845144,42.490774 45.665149,42.65077 C 45.485144,42.810774 45.215144,42.890774 44.855149,42.89077 L 43.135149,42.89077 M 41.565149,39.66077 L 41.565149,46.80077 L 43.135149,46.80077 L 43.135149,44.01077 L 44.705149,44.01077 C 45.098478,44.010773 45.381811,44.097439 45.555149,44.27077 C 45.728477,44.444105 45.84181,44.717439 45.895149,45.09077 C 45.935144,45.377438 45.965144,45.677438 45.985149,45.99077 C 46.005144,46.304104 46.058477,46.574103 46.145149,46.80077 L 47.715149,46.80077 C 47.641809,46.70077 47.585142,46.58077 47.545149,46.44077 C 47.511809,46.294104 47.485142,46.14077 47.465149,45.98077 C 47.451809,45.820771 47.441809,45.664104 47.435149,45.51077 C 47.428476,45.357438 47.421809,45.224105 47.415149,45.11077 C 47.401809,44.930772 47.375142,44.750772 47.335149,44.57077 C 47.301809,44.390772 47.245142,44.227439 47.165149,44.08077 C 47.085143,43.927439 46.981809,43.797439 46.855149,43.69077 C 46.728476,43.57744 46.568476,43.494106 46.375149,43.44077 L 46.375149,43.42077 C 46.775143,43.260773 47.061809,43.02744 47.235149,42.72077 C 47.415142,42.414108 47.505142,42.050775 47.505149,41.63077 C 47.505142,41.357442 47.455142,41.104109 47.355149,40.87077 C 47.261809,40.630776 47.121809,40.420776 46.935149,40.24077 C 46.755143,40.060777 46.535143,39.920777 46.275149,39.82077 C 46.02181,39.71411 45.735144,39.660777 45.415149,39.66077 L 41.565149,39.66077 M 48.77218,39.66077 L 48.77218,46.80077 L 50.34218,46.80077 L 50.34218,39.66077 L 48.77218,39.66077 M 51.701868,39.66077 L 51.701868,46.80077 L 53.171868,46.80077 L 53.171868,42.02077 L 53.191868,42.02077 L 56.161868,46.80077 L 57.731868,46.80077 L 57.731868,39.66077 L 56.261868,39.66077 L 56.261868,44.45077 L 56.241868,44.45077 L 53.261868,39.66077 L 51.701868,39.66077 M 60.684211,40.98077 L 60.684211,46.80077 L 62.254211,46.80077 L 62.254211,40.98077 L 64.394211,40.98077 L 64.394211,39.66077 L 58.544211,39.66077 L 58.544211,40.98077 L 60.684211,40.98077 M 65.237024,39.66077 L 65.237024,46.80077 L 66.807024,46.80077 L 66.807024,39.66077 L 65.237024,39.66077 M 68.166711,39.66077 L 68.166711,46.80077 L 69.636711,46.80077 L 69.636711,42.02077 L 69.656711,42.02077 L 72.626711,46.80077 L 74.196711,46.80077 L 74.196711,39.66077 L 72.726711,39.66077 L 72.726711,44.45077 L 72.706711,44.45077 L 69.726711,39.66077 L 68.166711,39.66077 M 80.729055,45.99077 L 80.889055,46.80077 L 81.889055,46.80077 L 81.889055,42.94077 L 78.889055,42.94077 L 78.889055,44.11077 L 80.469055,44.11077 C 80.422383,44.610772 80.255716,44.994105 79.969055,45.26077 C 79.68905,45.520771 79.289051,45.650771 78.769055,45.65077 C 78.415718,45.650771 78.115718,45.584104 77.869055,45.45077 C 77.622386,45.310771 77.422386,45.127438 77.269055,44.90077 C 77.115719,44.674105 77.002386,44.420772 76.929055,44.14077 C 76.862386,43.854106 76.829053,43.560773 76.829055,43.26077 C 76.829053,42.94744 76.862386,42.644107 76.929055,42.35077 C 77.002386,42.057441 77.115719,41.797441 77.269055,41.57077 C 77.422386,41.337442 77.622386,41.154109 77.869055,41.02077 C 78.115718,40.880776 78.415718,40.810776 78.769055,40.81077 C 79.149051,40.810776 79.472384,40.910776 79.739055,41.11077 C 80.005717,41.310775 80.185716,41.610775 80.279055,42.01077 L 81.779055,42.01077 C 81.739048,41.604108 81.629048,41.244109 81.449055,40.93077 C 81.269049,40.617443 81.039049,40.35411 80.759055,40.14077 C 80.485716,39.927443 80.175716,39.767444 79.829055,39.66077 C 79.48905,39.547444 79.135717,39.490777 78.769055,39.49077 C 78.222385,39.490777 77.729052,39.587444 77.289055,39.78077 C 76.85572,39.97411 76.489053,40.240776 76.189055,40.58077 C 75.889054,40.920776 75.659054,41.320775 75.499055,41.78077 C 75.339055,42.234108 75.259055,42.727441 75.259055,43.26077 C 75.259055,43.780773 75.339055,44.267439 75.499055,44.72077 C 75.659054,45.167438 75.889054,45.557438 76.189055,45.89077 C 76.489053,46.224104 76.85572,46.487437 77.289055,46.68077 C 77.729052,46.867436 78.222385,46.96077 78.769055,46.96077 C 79.115717,46.96077 79.45905,46.89077 79.799055,46.75077 C 80.13905,46.604103 80.449049,46.35077 80.729055,45.99077 M 35.974993,54.43077 L 34.454993,54.43077 C 34.448326,54.870772 34.528326,55.250771 34.694993,55.57077 C 34.861659,55.890771 35.084992,56.154104 35.364993,56.36077 C 35.651658,56.567437 35.978324,56.717437 36.344993,56.81077 C 36.718323,56.91077 37.101656,56.96077 37.494993,56.96077 C 37.981655,56.96077 38.408322,56.904103 38.774993,56.79077 C 39.148321,56.677437 39.458321,56.52077 39.704993,56.32077 C 39.95832,56.114104 40.14832,55.870771 40.274993,55.59077 C 40.401653,55.310771 40.464986,55.007438 40.464993,54.68077 C 40.464986,54.280772 40.37832,53.954106 40.204993,53.70077 C 40.03832,53.440773 39.83832,53.234107 39.604993,53.08077 C 39.371654,52.92744 39.134988,52.81744 38.894993,52.75077 C 38.661655,52.677441 38.478322,52.627441 38.344993,52.60077 C 37.898322,52.487441 37.534989,52.394108 37.254993,52.32077 C 36.981656,52.247441 36.76499,52.174108 36.604993,52.10077 C 36.451657,52.027441 36.348324,51.947441 36.294993,51.86077 C 36.241657,51.774108 36.214991,51.660775 36.214993,51.52077 C 36.214991,51.367442 36.248324,51.240775 36.314993,51.14077 C 36.381657,51.040776 36.46499,50.957442 36.564993,50.89077 C 36.671657,50.824109 36.788323,50.777442 36.914993,50.75077 C 37.041656,50.724109 37.168323,50.710776 37.294993,50.71077 C 37.488323,50.710776 37.664989,50.727443 37.824993,50.76077 C 37.991655,50.794109 38.138322,50.850776 38.264993,50.93077 C 38.391655,51.010776 38.491655,51.120775 38.564993,51.26077 C 38.644988,51.400775 38.691655,51.577442 38.704993,51.79077 L 40.224993,51.79077 C 40.224987,51.377442 40.144987,51.027442 39.984993,50.74077 C 39.831654,50.447443 39.621654,50.207443 39.354993,50.02077 C 39.088321,49.83411 38.781655,49.700777 38.434993,49.62077 C 38.094989,49.53411 37.738322,49.490777 37.364993,49.49077 C 37.04499,49.490777 36.72499,49.53411 36.404993,49.62077 C 36.084991,49.707444 35.798324,49.840777 35.544993,50.02077 C 35.291658,50.200776 35.084992,50.427443 34.924993,50.70077 C 34.771659,50.967442 34.694992,51.284109 34.694993,51.65077 C 34.694992,51.977441 34.754992,52.257441 34.874993,52.49077 C 35.001658,52.717441 35.164992,52.90744 35.364993,53.06077 C 35.564991,53.214107 35.791658,53.340773 36.044993,53.44077 C 36.298324,53.534106 36.558324,53.614106 36.824993,53.68077 C 37.08499,53.754106 37.341656,53.820773 37.594993,53.88077 C 37.848322,53.940773 38.074989,54.010773 38.274993,54.09077 C 38.474988,54.170772 38.634988,54.270772 38.754993,54.39077 C 38.881655,54.510772 38.944988,54.667439 38.944993,54.86077 C 38.944988,55.040772 38.898321,55.190771 38.804993,55.31077 C 38.711655,55.424105 38.594988,55.514104 38.454993,55.58077 C 38.314988,55.647438 38.164989,55.694104 38.004993,55.72077 C 37.844989,55.740771 37.694989,55.750771 37.554993,55.75077 C 37.348323,55.750771 37.148323,55.727438 36.954993,55.68077 C 36.761657,55.627438 36.591657,55.550771 36.444993,55.45077 C 36.30499,55.344105 36.191657,55.207438 36.104993,55.04077 C 36.018324,54.874105 35.974991,54.670772 35.974993,54.43077 M 43.239368,54.02077 L 43.239368,56.80077 L 44.809368,56.80077 L 44.809368,54.06077 L 47.459368,49.66077 L 45.709368,49.66077 L 44.049368,52.48077 L 42.379368,49.66077 L 40.619368,49.66077 L 43.239368,54.02077 M 49.119524,54.43077 L 47.599524,54.43077 C 47.592857,54.870772 47.672857,55.250771 47.839524,55.57077 C 48.00619,55.890771 48.229523,56.154104 48.509524,56.36077 C 48.796189,56.567437 49.122855,56.717437 49.489524,56.81077 C 49.862855,56.91077 50.246188,56.96077 50.639524,56.96077 C 51.126187,56.96077 51.552853,56.904103 51.919524,56.79077 C 52.292852,56.677437 52.602852,56.52077 52.849524,56.32077 C 53.102851,56.114104 53.292851,55.870771 53.419524,55.59077 C 53.546184,55.310771 53.609518,55.007438 53.609524,54.68077 C 53.609518,54.280772 53.522851,53.954106 53.349524,53.70077 C 53.182851,53.440773 52.982851,53.234107 52.749524,53.08077 C 52.516185,52.92744 52.279519,52.81744 52.039524,52.75077 C 51.806186,52.677441 51.622853,52.627441 51.489524,52.60077 C 51.042853,52.487441 50.67952,52.394108 50.399524,52.32077 C 50.126188,52.247441 49.909521,52.174108 49.749524,52.10077 C 49.596188,52.027441 49.492855,51.947441 49.439524,51.86077 C 49.386188,51.774108 49.359522,51.660775 49.359524,51.52077 C 49.359522,51.367442 49.392855,51.240775 49.459524,51.14077 C 49.526188,51.040776 49.609522,50.957442 49.709524,50.89077 C 49.816188,50.824109 49.932855,50.777442 50.059524,50.75077 C 50.186188,50.724109 50.312854,50.710776 50.439524,50.71077 C 50.632854,50.710776 50.80952,50.727443 50.969524,50.76077 C 51.136187,50.794109 51.282853,50.850776 51.409524,50.93077 C 51.536186,51.010776 51.636186,51.120775 51.709524,51.26077 C 51.789519,51.400775 51.836186,51.577442 51.849524,51.79077 L 53.369524,51.79077 C 53.369518,51.377442 53.289518,51.027442 53.129524,50.74077 C 52.976185,50.447443 52.766185,50.207443 52.499524,50.02077 C 52.232852,49.83411 51.926186,49.700777 51.579524,49.62077 C 51.23952,49.53411 50.882854,49.490777 50.509524,49.49077 C 50.189521,49.490777 49.869521,49.53411 49.549524,49.62077 C 49.229522,49.707444 48.942856,49.840777 48.689524,50.02077 C 48.436189,50.200776 48.229523,50.427443 48.069524,50.70077 C 47.91619,50.967442 47.839523,51.284109 47.839524,51.65077 C 47.839523,51.977441 47.899523,52.257441 48.019524,52.49077 C 48.14619,52.717441 48.309523,52.90744 48.509524,53.06077 C 48.709522,53.214107 48.936189,53.340773 49.189524,53.44077 C 49.442855,53.534106 49.702855,53.614106 49.969524,53.68077 C 50.229521,53.754106 50.486187,53.820773 50.739524,53.88077 C 50.992853,53.940773 51.21952,54.010773 51.419524,54.09077 C 51.61952,54.170772 51.779519,54.270772 51.899524,54.39077 C 52.026186,54.510772 52.089519,54.667439 52.089524,54.86077 C 52.089519,55.040772 52.042852,55.190771 51.949524,55.31077 C 51.856186,55.424105 51.739519,55.514104 51.599524,55.58077 C 51.45952,55.647438 51.30952,55.694104 51.149524,55.72077 C 50.98952,55.740771 50.83952,55.750771 50.699524,55.75077 C 50.492854,55.750771 50.292854,55.727438 50.099524,55.68077 C 49.906188,55.627438 49.736188,55.550771 49.589524,55.45077 C 49.449522,55.344105 49.336188,55.207438 49.249524,55.04077 C 49.162855,54.874105 49.119522,54.670772 49.119524,54.43077 M 56.113899,50.98077 L 56.113899,56.80077 L 57.683899,56.80077 L 57.683899,50.98077 L 59.823899,50.98077 L 59.823899,49.66077 L 53.973899,49.66077 L 53.973899,50.98077 L 56.113899,50.98077 M 60.666711,49.66077 L 60.666711,56.80077 L 66.086711,56.80077 L 66.086711,55.48077 L 62.236711,55.48077 L 62.236711,53.73077 L 65.696711,53.73077 L 65.696711,52.51077 L 62.236711,52.51077 L 62.236711,50.98077 L 66.006711,50.98077 L 66.006711,49.66077 L 60.666711,49.66077 M 67.131555,49.66077 L 67.131555,56.80077 L 68.601555,56.80077 L 68.601555,51.79077 L 68.621555,51.79077 L 70.371555,56.80077 L 71.581555,56.80077 L 73.331555,51.74077 L 73.351555,51.74077 L 73.351555,56.80077 L 74.821555,56.80077 L 74.821555,49.66077 L 72.611555,49.66077 L 71.031555,54.57077 L 71.011555,54.57077 L 69.341555,49.66077 L 67.131555,49.66077"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Helvetica Neue;-inkscape-font-specification:Helvetica Neue Bold" />
+ </g>
+ </g>
+</svg>
diff --git a/doc/images/generic.png b/doc/images/generic.png
new file mode 100644
index 000000000..2abe9de9e
--- /dev/null
+++ b/doc/images/generic.png
Binary files differ
diff --git a/doc/images/left.gif b/doc/images/left.gif
new file mode 100644
index 000000000..e82004257
--- /dev/null
+++ b/doc/images/left.gif
Binary files differ
diff --git a/doc/images/left.xcf.gz b/doc/images/left.xcf.gz
new file mode 100644
index 000000000..d403e78e5
--- /dev/null
+++ b/doc/images/left.xcf.gz
Binary files differ
diff --git a/doc/images/raster-organization.png b/doc/images/raster-organization.png
new file mode 100644
index 000000000..c390f4144
--- /dev/null
+++ b/doc/images/raster-organization.png
Binary files differ
diff --git a/doc/images/raster-organization.svg b/doc/images/raster-organization.svg
new file mode 100644
index 000000000..442032f2e
--- /dev/null
+++ b/doc/images/raster-organization.svg
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="744.09448819"
+ height="1052.3622047"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.0 r9654"
+ sodipodi:docname="raster-organization.svg"
+ inkscape:export-filename="/Users/mike/c/cups-trunk/doc/images/raster-organization.png"
+ inkscape:export-xdpi="100.04211"
+ inkscape:export-ydpi="100.04211">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.80227655"
+ inkscape:cx="414.35236"
+ inkscape:cy="794.80623"
+ inkscape:document-units="px"
+ inkscape:current-layer="g4208"
+ showgrid="true"
+ inkscape:window-width="1089"
+ inkscape:window-height="815"
+ inkscape:window-x="308"
+ inkscape:window-y="0"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3979" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <rect
+ style="fill:none;stroke:#000000;stroke-width:0.98624134px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985"
+ width="359.01376"
+ height="39.01376"
+ x="180.49312"
+ y="52.855301" />
+ <flowRoot
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+ id="flowRoot4112"
+ transform="translate(70.681641,5.4232931)"><flowRegion
+ id="flowRegion4114"><use
+ x="0"
+ y="0"
+ xlink:href="#rect2985"
+ id="use4116"
+ width="744.09448"
+ height="1052.3622" /></flowRegion><flowPara
+ id="flowPara4118">Synchronization Word</flowPara></flowRoot> <g
+ id="g4196">
+ <rect
+ style="fill:none;stroke:#000000;stroke-width:1.71552336px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect3981"
+ width="358.28448"
+ height="118.28448"
+ x="180.85776"
+ y="133.21994" />
+ <rect
+ y="253.5766"
+ x="181.21442"
+ height="237.57117"
+ width="357.57117"
+ id="rect3983"
+ style="fill:none;stroke:#000000;stroke-width:2.42882872px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <flowRoot
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+ id="flowRoot4120"
+ transform="translate(106.53711,125.42329)"><flowRegion
+ id="flowRegion4122"><use
+ x="0"
+ y="0"
+ xlink:href="#rect2985"
+ id="use4124"
+ width="744.09448"
+ height="1052.3622" /></flowRegion><flowPara
+ id="flowPara4126">Page Header 1</flowPara></flowRoot> <flowRoot
+ transform="translate(106.53711,295.42329)"
+ id="flowRoot4128"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+ xml:space="preserve"><flowRegion
+ id="flowRegion4130"><use
+ height="1052.3622"
+ width="744.09448"
+ id="use4132"
+ xlink:href="#rect2985"
+ y="0"
+ x="0" /></flowRegion><flowPara
+ id="flowPara4134">Page Bitmap 1</flowPara></flowRoot> </g>
+ <g
+ id="g4208"
+ transform="translate(4.1127203e-6,510)">
+ <rect
+ y="133.21994"
+ x="180.85776"
+ height="118.28448"
+ width="358.28448"
+ id="rect4210"
+ style="fill:none;stroke:#000000;stroke-width:1.71552336px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <rect
+ style="fill:none;stroke:#000000;stroke-width:2.42882872px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect4212"
+ width="357.57117"
+ height="237.57117"
+ x="181.21442"
+ y="253.5766" />
+ <flowRoot
+ transform="translate(106.53711,125.42329)"
+ id="flowRoot4214"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+ xml:space="preserve"><flowRegion
+ id="flowRegion4216"><use
+ height="1052.3622"
+ width="744.09448"
+ id="use4218"
+ xlink:href="#rect2985"
+ y="0"
+ x="0" /></flowRegion><flowPara
+ id="flowPara4220">Page Header N</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+ id="flowRoot4222"
+ transform="translate(106.53711,295.42329)"><flowRegion
+ id="flowRegion4224"><use
+ x="0"
+ y="0"
+ xlink:href="#rect2985"
+ id="use4226"
+ width="744.09448"
+ height="1052.3622" /></flowRegion><flowPara
+ id="flowPara4228">Page Bitmap N</flowPara></flowRoot> <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:1,2;stroke-dashoffset:0"
+ d="m 180,92.362183 0,39.999997"
+ id="path4230"
+ inkscape:connector-curvature="0"
+ transform="translate(-4.1127203e-6,-510)" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4232"
+ d="m 540,-417.63782 0,40"
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 2;stroke-dashoffset:0" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:1,2;stroke-dashoffset:0"
+ d="m 180,492.36218 0,60 -20,10 40,10 -20,10 0,60"
+ id="path4236"
+ inkscape:connector-curvature="0"
+ transform="translate(-4.1127203e-6,-510)"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ sodipodi:nodetypes="cccccc"
+ inkscape:connector-curvature="0"
+ id="path4238"
+ d="m 540,-17.637817 0,60 -20,10 40,10 -20,10 0,59.999997"
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 2;stroke-dashoffset:0" />
+ </g>
+ </g>
+</svg>
diff --git a/doc/images/raster.png b/doc/images/raster.png
new file mode 100644
index 000000000..17ba3b230
--- /dev/null
+++ b/doc/images/raster.png
Binary files differ
diff --git a/doc/images/raster.svg b/doc/images/raster.svg
new file mode 100644
index 000000000..58277e70c
--- /dev/null
+++ b/doc/images/raster.svg
@@ -0,0 +1,386 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="438.75"
+ height="315"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.45.1"
+ version="1.0"
+ sodipodi:docbase="/home/mike/c/cups-trunk/doc/images"
+ sodipodi:docname="raster.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/home/mike/c/cups-trunk/doc/images/raster.png"
+ inkscape:export-xdpi="128"
+ inkscape:export-ydpi="128">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.90444444"
+ inkscape:cx="225"
+ inkscape:cy="177.5167"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ width="351pt"
+ height="252pt"
+ units="pt"
+ showgrid="true"
+ gridspacingx="9pt"
+ gridspacingy="9pt"
+ gridanglex="24pt"
+ gridanglez="24pt"
+ grid_units="pt"
+ inkscape:object-bbox="true"
+ inkscape:object-points="true"
+ inkscape:object-nodes="true"
+ inkscape:grid-points="true"
+ inkscape:guide-points="true"
+ inkscape:window-width="872"
+ inkscape:window-height="622"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ id="g3338"
+ transform="translate(0.5,-1.3515625)">
+ <rect
+ y="11.25"
+ x="11.25"
+ height="90"
+ width="67.5"
+ id="rect3336"
+ style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <flowRoot
+ transform="translate(11.34082,17.328046)"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ id="flowRoot2357"
+ xml:space="preserve"><flowRegion
+ id="flowRegion2359"><rect
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ y="12.162162"
+ x="9.95086"
+ height="128.25552"
+ width="86.240784"
+ id="rect2361" /></flowRegion><flowPara
+ id="flowPara2363">Back</flowPara><flowPara
+ id="flowPara2365">Side</flowPara></flowRoot> </g>
+ <g
+ id="g3346"
+ transform="translate(113,-1.3515625)">
+ <rect
+ y="11.25"
+ x="11.25"
+ height="90"
+ width="67.5"
+ id="rect3348"
+ style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <flowRoot
+ transform="translate(11.34082,17.328046)"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ id="flowRoot3350"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3352"><rect
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ y="12.162162"
+ x="9.95086"
+ height="128.25552"
+ width="86.240784"
+ id="rect3354" /></flowRegion><flowPara
+ id="flowPara3356">Back</flowPara><flowPara
+ id="flowPara3358">Side</flowPara></flowRoot> </g>
+ <g
+ id="g3360"
+ transform="translate(226,-1.8515625)">
+ <rect
+ y="11.25"
+ x="11.25"
+ height="90"
+ width="67.5"
+ id="rect3362"
+ style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <flowRoot
+ transform="translate(11.34082,17.328046)"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ id="flowRoot3364"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3366"><rect
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ y="12.162162"
+ x="9.95086"
+ height="128.25552"
+ width="86.240784"
+ id="rect3368" /></flowRegion><flowPara
+ id="flowPara3370">Back</flowPara><flowPara
+ id="flowPara3372">Side</flowPara></flowRoot> </g>
+ <g
+ id="g3374"
+ transform="matrix(-1,0,0,-1,428,111.14844)">
+ <rect
+ y="11.25"
+ x="11.25"
+ height="90"
+ width="67.5"
+ id="rect3376"
+ style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <flowRoot
+ transform="translate(11.34082,17.328046)"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ id="flowRoot3378"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3380"><rect
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ y="12.162162"
+ x="9.95086"
+ height="128.25552"
+ width="86.240784"
+ id="rect3382" /></flowRegion><flowPara
+ id="flowPara3384">Back</flowPara><flowPara
+ id="flowPara3386">Side</flowPara></flowRoot> </g>
+ <g
+ id="g3388"
+ transform="matrix(-1,0,0,-1,90.5,279.89844)">
+ <rect
+ y="11.25"
+ x="11.25"
+ height="90"
+ width="67.5"
+ id="rect3390"
+ style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <flowRoot
+ transform="translate(11.34082,17.328046)"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ id="flowRoot3392"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3394"><rect
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ y="12.162162"
+ x="9.95086"
+ height="128.25552"
+ width="86.240784"
+ id="rect3396" /></flowRegion><flowPara
+ id="flowPara3398">Back</flowPara><flowPara
+ id="flowPara3400">Side</flowPara></flowRoot> </g>
+ <g
+ id="g3402"
+ transform="translate(113,167.39844)">
+ <rect
+ y="11.25"
+ x="11.25"
+ height="90"
+ width="67.5"
+ id="rect3404"
+ style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <flowRoot
+ transform="translate(11.34082,17.328046)"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ id="flowRoot3406"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3408"><rect
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ y="12.162162"
+ x="9.95086"
+ height="128.25552"
+ width="86.240784"
+ id="rect3410" /></flowRegion><flowPara
+ id="flowPara3412">Back</flowPara><flowPara
+ id="flowPara3414">Side</flowPara></flowRoot> </g>
+ <g
+ id="g3416"
+ transform="matrix(1,0,0,-1,226,279.39844)">
+ <rect
+ y="11.25"
+ x="11.25"
+ height="90"
+ width="67.5"
+ id="rect3418"
+ style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <flowRoot
+ transform="translate(11.34082,17.328046)"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ id="flowRoot3420"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3422"><rect
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ y="12.162162"
+ x="9.95086"
+ height="128.25552"
+ width="86.240784"
+ id="rect3424" /></flowRegion><flowPara
+ id="flowPara3426">Back</flowPara><flowPara
+ id="flowPara3428">Side</flowPara></flowRoot> </g>
+ <g
+ id="g3430"
+ transform="matrix(-1,0,0,1,428,167.39844)">
+ <rect
+ y="11.25"
+ x="11.25"
+ height="90"
+ width="67.5"
+ id="rect3432"
+ style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <flowRoot
+ transform="translate(11.34082,17.328046)"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ id="flowRoot3434"
+ xml:space="preserve"><flowRegion
+ id="flowRegion3436"><rect
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Monospace"
+ y="12.162162"
+ x="9.95086"
+ height="128.25552"
+ width="86.240784"
+ id="rect3438" /></flowRegion><flowPara
+ id="flowPara3440">Back</flowPara><flowPara
+ id="flowPara3442">Side</flowPara></flowRoot> </g>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Monospace"
+ x="47.503906"
+ y="119.83008"
+ id="text3444"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3446"
+ x="47.503906"
+ y="119.83008">Normal</tspan><tspan
+ sodipodi:role="line"
+ x="47.503906"
+ y="134.83008"
+ id="tspan3448">false</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Monospace"
+ x="160.00391"
+ y="119.83008"
+ id="text3450"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3452"
+ x="160.00391"
+ y="119.83008">Normal</tspan><tspan
+ sodipodi:role="line"
+ x="160.00391"
+ y="134.83008"
+ id="tspan3454">true</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Monospace"
+ x="273.00391"
+ y="119.83008"
+ id="text3456"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3458"
+ x="273.00391"
+ y="119.83008">ManualTumble</tspan><tspan
+ sodipodi:role="line"
+ x="273.00391"
+ y="134.83008"
+ id="tspan3460">false</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Monospace"
+ x="385.39062"
+ y="119.83008"
+ id="text3462"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3464"
+ x="385.39062"
+ y="119.83008">ManualTumble</tspan><tspan
+ sodipodi:role="line"
+ x="385.39062"
+ y="134.83008"
+ id="tspan3466">true</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Monospace"
+ x="43.847656"
+ y="288.51562"
+ id="text3468"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3470"
+ x="43.847656"
+ y="288.51562">Rotated</tspan><tspan
+ sodipodi:role="line"
+ x="43.847656"
+ y="303.51562"
+ id="tspan3472">false</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Monospace"
+ x="156.84766"
+ y="288.51562"
+ id="text3474"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3476"
+ x="156.84766"
+ y="288.51562">Rotated</tspan><tspan
+ sodipodi:role="line"
+ x="156.84766"
+ y="303.51562"
+ id="tspan3478">true</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Monospace"
+ x="269.34766"
+ y="288.58008"
+ id="text3480"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3482"
+ x="269.34766"
+ y="288.58008">Flipped</tspan><tspan
+ sodipodi:role="line"
+ x="269.34766"
+ y="303.58008"
+ id="tspan3484">false</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Monospace"
+ x="381.84766"
+ y="288.58008"
+ id="text3486"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3488"
+ x="381.84766"
+ y="288.58008">Flipped</tspan><tspan
+ sodipodi:role="line"
+ x="381.84766"
+ y="303.58008"
+ id="tspan3490">true</tspan></text>
+ </g>
+</svg>
diff --git a/doc/images/right.gif b/doc/images/right.gif
new file mode 100644
index 000000000..9ebe46433
--- /dev/null
+++ b/doc/images/right.gif
Binary files differ
diff --git a/doc/images/sample-image.png b/doc/images/sample-image.png
new file mode 100644
index 000000000..f78760e07
--- /dev/null
+++ b/doc/images/sample-image.png
Binary files differ
diff --git a/doc/images/sel.gif b/doc/images/sel.gif
new file mode 100644
index 000000000..36b16bf69
--- /dev/null
+++ b/doc/images/sel.gif
Binary files differ
diff --git a/doc/images/smiley.jpg b/doc/images/smiley.jpg
new file mode 100644
index 000000000..0076fae2d
--- /dev/null
+++ b/doc/images/smiley.jpg
Binary files differ
diff --git a/doc/images/unsel.gif b/doc/images/unsel.gif
new file mode 100644
index 000000000..10477fe55
--- /dev/null
+++ b/doc/images/unsel.gif
Binary files differ
diff --git a/doc/images/wait.gif b/doc/images/wait.gif
new file mode 100644
index 000000000..c18f421ee
--- /dev/null
+++ b/doc/images/wait.gif
Binary files differ
diff --git a/doc/images/webinterface.png b/doc/images/webinterface.png
new file mode 100644
index 000000000..feca5d66a
--- /dev/null
+++ b/doc/images/webinterface.png
Binary files differ
diff --git a/doc/index.html.in b/doc/index.html.in
new file mode 100644
index 000000000..26f8de13b
--- /dev/null
+++ b/doc/index.html.in
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>Home - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="sel"><A HREF="/">&nbsp;&nbsp;Home&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/admin">&nbsp;&nbsp;Administration&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/classes/">&nbsp;&nbsp;Classes&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/help/">&nbsp;&nbsp;Online&nbsp;Help&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/jobs/">&nbsp;&nbsp;Jobs&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/printers/">&nbsp;&nbsp;Printers&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Search Help"
+AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD STYLE="padding-right: 20px;">
+
+<H1>CUPS @CUPS_VERSION@</H1>
+
+<P>CUPS is the standards-based, open source printing system developed by
+<A HREF="http://www.apple.com/">Apple Inc.</A> for Mac OS<SUP>&reg;</SUP> X and
+other UNIX<SUP>&reg;</SUP>-like operating systems.</P>
+
+</TD>
+<TD><A HREF="http://www.cups.org/"><IMG SRC="images/cups-icon.png" WIDTH="128"
+HEIGHT="128" ALT="CUPS"></A></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-right: 20px;">
+
+<H2>CUPS for Users</H2>
+
+<P><A HREF="help/overview.html">Overview of CUPS</A></P>
+
+<P><A HREF="help/options.html">Command-Line Printing and Options</A></P>
+
+<P><A HREF="help/whatsnew.html">What's New in CUPS 1.4</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.general">User Forum</A></P>
+
+</TD><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-left: 20px; padding-right: 20px;">
+
+<H2>CUPS for Administrators</H2>
+
+<P><A HREF="admin">Adding Printers and Classes</A></P>
+
+<P><A HREF="help/policies.html">Managing Operation Policies</A></P>
+
+<P><A HREF="help/accounting.html">Printer Accounting Basics</A></P>
+
+<P><A HREF="help/security.html">Server Security</A></P>
+
+<P><A HREF="help/kerberos.html">Using Kerberos Authentication</A></P>
+
+<P><A HREF="help/network.html">Using Network Printers</A></P>
+
+<P><A HREF="help/ref-cupsd-conf.html">cupsd.conf Reference</A></P>
+
+<P><A HREF="http://www.cups.org/ppd.php">Find Printer Drivers</A></P>
+
+</TD><TD VALIGN="top" STYLE="padding-left: 20px;">
+
+<H2>CUPS for Developers</H2>
+
+<P><A HREF="help/api-overview.html">Introduction to CUPS Programming</A></P>
+
+<P><A HREF="help/api-cups.html">CUPS API</A></P>
+
+<P><A HREF="help/api-filter.html">Filter and Backend Programming</A></P>
+
+<P><A HREF="help/api-httpipp.html">HTTP and IPP APIs</A></P>
+
+<P><A HREF="help/api-ppd.html">PPD API</A></P>
+
+<P><A HREF="help/api-raster.html">Raster API</A></P>
+
+<P><A HREF="help/ref-ppdcfile.html">PPD Compiler Driver Information File Reference</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.development">Developer Forum</A></P>
+
+</TD></TR>
+</TABLE>
+
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS and the CUPS logo are trademarks of
+<A HREF="http://www.apple.com">Apple Inc.</A> CUPS is copyright 2007-2011 Apple
+Inc. All rights reserved.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/doc/it/index.html.in b/doc/it/index.html.in
new file mode 100644
index 000000000..f65954f03
--- /dev/null
+++ b/doc/it/index.html.in
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>Home - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="sel"><A HREF="/">&nbsp;&nbsp;Home&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/admin">&nbsp;&nbsp;Amministrazione&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/classes/">&nbsp;&nbsp;Classi&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/help/">&nbsp;&nbsp;Guida&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/jobs/">&nbsp;&nbsp;Stampe&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/printers/">&nbsp;&nbsp;Stampanti&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Aiuto alla ricerca"
+AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD STYLE="padding-right: 20px;">
+
+<H1>CUPS @CUPS_VERSION@</H1>
+
+<P>CUPS è un sistema di stampa basato su standard, open source sviluppato da
+<A HREF="http://www.apple.com/">Apple Inc.</A> per Mac OS<SUP>&reg;</SUP> X e
+altri sistemi UNIX<SUP>&reg;</SUP> e derivati.</P>
+
+</TD>
+<TD><A HREF="http://www.cups.org/"><IMG SRC="images/cups-icon.png" WIDTH="128"
+HEIGHT="128" ALT="CUPS"></A></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-right: 20px;">
+
+<H2>CUPS per utenti</H2>
+
+<P><A HREF="help/overview.html">Panoramica di CUPS</A></P>
+
+<P><A HREF="help/options.html">Stampa e opzioni da riga di comando</A></P>
+
+<P><A HREF="help/whatsnew.html">Cosa c'è di nuovo in CUPS 1.4</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.general">Forum degli utenti</A></P>
+
+</TD><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-left: 20px; padding-right: 20px;">
+
+<H2>CUPS per amministratori</H2>
+
+<P><A HREF="admin">Aggiungere stampanti e classi</A></P>
+
+<P><A HREF="help/policies.html">Gestire i criteri di funzionamento</A></P>
+
+<P><A HREF="help/accounting.html">Basi di controllo di accesso alle stampanti</A></P>
+
+<P><A HREF="help/security.html">Sicurezza del server</A></P>
+
+<P><A HREF="help/kerberos.html">Utilizzare l'autenticazione Kerberos</A></P>
+
+<P><A HREF="help/network.html">Utilizzare stampanti di rete</A></P>
+
+<P><A HREF="help/ref-cupsd-conf.html">Riferimenti al cupsd.conf</A></P>
+
+<P><A HREF="http://www.cups.org/ppd.php">Trovare driver per le stampanti</A></P>
+
+</TD><TD VALIGN="top" STYLE="padding-left: 20px;">
+
+<H2>CUPS per sviluppatori</H2>
+
+<P><A HREF="help/api-overview.html">Introduzione alla programmazione di CUPS</A></P>
+
+<P><A HREF="help/api-cups.html">API di CUPS</A></P>
+
+<P><A HREF="help/api-filter.html">Programmazione di filtri e motori</A></P>
+
+<P><A HREF="help/api-httpipp.html">API HTTP e IPP</A></P>
+
+<P><A HREF="help/api-ppd.html">API PPD</A></P>
+
+<P><A HREF="help/api-raster.html">API Raster</A></P>
+
+<P><A HREF="help/ref-ppdcfile.html">Riferimenti al file del compilatore di driver PPD</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.development">Forum degli sviluppatori</A></P>
+
+</TD></TR>
+</TABLE>
+
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS e il logo CUPS sono marchi di
+<A HREF="http://www.apple.com">Apple Inc.</A> CUPS è un copyright 2007-2011 di Apple
+Inc. Tutti i diritti sono riservati.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/doc/ja/index.html.in b/doc/ja/index.html.in
new file mode 100644
index 000000000..4271c7adf
--- /dev/null
+++ b/doc/ja/index.html.in
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>ホーム - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="sel" NOWRAP><A HREF="/">&nbsp;&nbsp;ホーム&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" NOWRAP><A HREF="/admin">&nbsp;&nbsp;管ç†&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" NOWRAP><A HREF="/classes/">&nbsp;&nbsp;クラス&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" NOWRAP><A HREF="/help/">&nbsp;&nbsp;ヘルプ&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" NOWRAP><A HREF="/jobs/">&nbsp;&nbsp;ジョブ&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" NOWRAP><A HREF="/printers/">&nbsp;プリンター&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Search Help"
+AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD STYLE="padding-right: 20px;">
+
+<H1>CUPS @CUPS_VERSION@</H1>
+
+<P>CUPS ã¯ã€Mac OS<SUP>&reg;</SUP> X ãŠã‚ˆã³ãã®ä»–ã® UNIX ç³» OS ã®ãŸã‚ã«ã€
+<A HREF="http://www.apple.com/">Apple Inc.</A>
+ã«ã‚ˆã£ã¦é–‹ç™ºã•ã‚ŒãŸæ¨™æº–ベースã®ã‚ªãƒ¼ãƒ—ンソースå°åˆ·ã‚·ã‚¹ãƒ†ãƒ ã§ã™ã€‚</P>
+
+</TD>
+<TD><A HREF="http://www.cups.org/"><IMG SRC="images/cups-icon.png" WIDTH="128"
+HEIGHT="128" ALT="CUPS"></A></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-right: 20px;">
+
+<H2>ユーザーå‘ã‘</H2>
+
+<P><A HREF="help/overview.html">CUPS ã®æ¦‚è¦</A></P>
+
+<P><A HREF="help/options.html">コマンドラインã‹ã‚‰ã®å°åˆ·ã¨ã‚ªãƒ—ション</A></P>
+
+<P><A HREF="help/whatsnew.html">CUPS 1.4 ã®æ–°æ©Ÿèƒ½</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.general">ユーザーフォーラム</A></P>
+
+</TD><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-left: 20px; padding-right: 20px;">
+
+<H2>管ç†è€…å‘ã‘</H2>
+
+<P><A HREF="admin">プリンターã¨ã‚¯ãƒ©ã‚¹ã®è¿½åŠ </A></P>
+
+<P><A HREF="help/policies.html">æ“作ãƒãƒªã‚·ãƒ¼ã®ç®¡ç†ã«ã¤ã„ã¦</A></P>
+
+<P><A HREF="help/accounting.html">プリンターアカウンティングã®åŸºæœ¬</A></P>
+
+<P><A HREF="help/security.html">サーãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãƒ¼</A></P>
+
+<P><A HREF="help/kerberos.html">Kerberos èªè¨¼ã®ä½¿ã„æ–¹</A></P>
+
+<P><A HREF="help/network.html">ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ—リンターã®ä½¿ã„æ–¹</A></P>
+
+<P><A HREF="help/ref-cupsd-conf.html">cupsd.conf リファレンス</A></P>
+
+<P><A HREF="http://www.cups.org/ppd.php">プリンタードライãƒãƒ¼ã®æ¤œç´¢</A></P>
+
+</TD><TD VALIGN="top" STYLE="padding-left: 20px;">
+
+<H2>開発者å‘ã‘</H2>
+
+<P><A HREF="help/api-overview.html">イントロダクション</A></P>
+
+<P><A HREF="help/api-cups.html">CUPS API</A></P>
+
+<P><A HREF="help/api-filter.html">フィルタã¨ãƒãƒƒã‚¯ã‚¨ãƒ³ãƒ‰ã®ãƒ—ログラミング</A></P>
+
+<P><A HREF="help/api-httpipp.html">HTTP 㨠IPP 㮠API</A></P>
+
+<P><A HREF="help/api-ppd.html">PPD API</A></P>
+
+<P><A HREF="help/api-raster.html">ラスター API</A></P>
+
+<P><A HREF="help/ref-ppdcfile.html">PPD コンパイラー用ドライãƒãƒ¼æƒ…報ファイル リファレンス</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.development">開発者フォーラム</A></P>
+
+</TD></TR>
+</TABLE>
+
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS and the CUPS logo are trademarks of
+<A HREF="http://www.apple.com">Apple Inc.</A> CUPS is copyright 2007-2011 Apple
+Inc. All rights reserved.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/doc/pl/index.html.in b/doc/pl/index.html.in
new file mode 100644
index 000000000..943cb9e96
--- /dev/null
+++ b/doc/pl/index.html.in
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>Strona domowa - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="sel"><A HREF="/">&nbsp;&nbsp;Strona domowa&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/admin">&nbsp;&nbsp;Administracja&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/classes/">&nbsp;&nbsp;Klasy&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/help/">&nbsp;&nbsp;Pomoc&nbsp;online&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/jobs/">&nbsp;&nbsp;Zadania&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/printers/">&nbsp;&nbsp;Drukowanie&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Search Help"
+AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD STYLE="padding-right: 20px;">
+
+<H1>CUPS @CUPS_VERSION@</H1>
+
+<P>CUPS jest opartym na standardach systemem drukowania na licencji open source, tworzonym przez
+<A HREF="http://www.apple.com/">Apple Inc.</A> dla Mac OS<SUP>&reg;</SUP> X i
+innych systemów operacyjnych podobnych do Uniksa<SUP>&reg;</SUP>.</P>
+
+</TD>
+<TD><A HREF="http://www.cups.org/"><IMG SRC="images/cups-icon.png" WIDTH="128"
+HEIGHT="128" ALT="CUPS"></A></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-right: 20px;">
+
+<H2>CUPS dla użytkowników</H2>
+
+<P><A HREF="help/overview.html">PrzeglÄ…d CUPS</A></P>
+
+<P><A HREF="help/options.html">Drukowanie i opcje w wierszu poleceń</A></P>
+
+<P><A HREF="help/whatsnew.html">Co nowego w CUPS 1.4</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.general">Forum użytkowników</A></P>
+
+</TD><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-left: 20px; padding-right: 20px;">
+
+<H2>CUPS dla administratorów</H2>
+
+<P><A HREF="admin">Dodawanie drukarek i klas</A></P>
+
+<P><A HREF="help/policies.html">ZarzÄ…dzanie politykami operacji</A></P>
+
+<P><A HREF="help/accounting.html">Podstawy kont drukowania</A></P>
+
+<P><A HREF="help/security.html">Bezpieczeństwo systemu</A></P>
+
+<P><A HREF="help/kerberos.html">Używanie uwierzytelniania Kerberosa</A></P>
+
+<P><A HREF="help/network.html">Używanie drukarek sieciowych</A></P>
+
+<P><A HREF="help/ref-cupsd-conf.html">Informacje o cupsd.conf</A></P>
+
+<P><A HREF="http://www.cups.org/ppd.php">Wyszukiwanie sterowników drukarek</A></P>
+
+</TD><TD VALIGN="top" STYLE="padding-left: 20px;">
+
+<H2>CUPS dla programistów</H2>
+
+<P><A HREF="help/api-overview.html">Wprowadzenie do programowania CUPS</A></P>
+
+<P><A HREF="help/api-cups.html">API CUPS</A></P>
+
+<P><A HREF="help/api-filter.html">Programowanie filtrów i modułów przetwarzających</A></P>
+
+<P><A HREF="help/api-httpipp.html">API HTTP i IPP</A></P>
+
+<P><A HREF="help/api-ppd.html">API PPD</A></P>
+
+<P><A HREF="help/api-raster.html">API rastrowe</A></P>
+
+<P><A HREF="help/ref-ppdcfile.html">Informacje o kompilatorze plików informacji o sterownikach PPD</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.development">Forum programistów</A></P>
+
+</TD></TR>
+</TABLE>
+
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS i logo CUPS
+sÄ… znakami handlowymi <A HREF="http://www.apple.com">Apple Inc.</A> CUPS
+copyright 2007-2011 Apple Inc. Wszystkie prawa zastrzeżone.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/doc/robots.txt b/doc/robots.txt
new file mode 100644
index 000000000..45dcdc221
--- /dev/null
+++ b/doc/robots.txt
@@ -0,0 +1,31 @@
+#
+# "$Id: robots.txt 3494 2003-03-19 15:37:44Z mike $"
+#
+# This file tells search engines not to index your CUPS server.
+#
+# Copyright 1993-2003 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Easy Software Products and are protected by Federal
+# copyright law. Distribution and use rights are outlined in the file
+# "LICENSE.txt" which should have been included with this file. If this
+# file is missing or damaged please contact Easy Software Products
+# at:
+#
+# Attn: CUPS Licensing Information
+# Easy Software Products
+# 44141 Airport View Drive, Suite 204
+# Hollywood, Maryland 20636-3111 USA
+#
+# Voice: (301) 373-9600
+# EMail: cups-info@cups.org
+# WWW: http://www.cups.org
+#
+
+User-agent: *
+Disallow: /
+
+#
+# End of "$Id: robots.txt 3494 2003-03-19 15:37:44Z mike $".
+#
+
diff --git a/doc/ru/index.html.in b/doc/ru/index.html.in
new file mode 100644
index 000000000..7b2b745a2
--- /dev/null
+++ b/doc/ru/index.html.in
@@ -0,0 +1,103 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>Ðачало — CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="sel"><A HREF="/">&nbsp;&nbsp;Ðачало&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/admin">&nbsp;&nbsp;ÐдминиÑтрирование&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/classes/">&nbsp;&nbsp;Группы&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/help/">&nbsp;&nbsp;Справка&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/jobs/">&nbsp;&nbsp;ЗаданиÑ&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel"><A HREF="/printers/">&nbsp;&nbsp;Принтеры&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="ПоиÑк по Ñправке"
+AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD STYLE="padding-right: 20px;">
+
+<H1>CUPS @CUPS_VERSION@</H1>
+
+<P>CUPS — Ð¿Ð¾Ð´Ð´ÐµÑ€Ð¶Ð¸Ð²Ð°ÑŽÑ‰Ð°Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ð½Ñтво Ñтандартов, ÑÐ²Ð¾Ð±Ð¾Ð´Ð½Ð°Ñ Ð¿Ð¾Ð´ÑиÑтема печати, Ñ€Ð°Ð·Ñ€Ð°Ð±Ð°Ñ‚Ñ‹Ð²Ð°ÐµÐ¼Ð°Ñ ÐºÐ¾Ð¼Ð¿Ð°Ð½Ð¸ÐµÐ¹ <A HREF="http://www.apple.com/">Apple Inc.</A> Ð´Ð»Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð¾Ð¹ ÑиÑтемы Mac OS<SUP>&reg;</SUP> X и других UNIX<SUP>&reg;</SUP>-подобных операционных ÑиÑтем.</P>
+
+</TD>
+<TD><A HREF="http://www.cups.org/"><IMG SRC="images/cups-icon.png" WIDTH="128"
+HEIGHT="128" ALT="CUPS"></A></TD>
+</TR>
+</TABLE>
+
+<TABLE CLASS="indent" SUMMARY="">
+<TR><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-right: 20px;">
+
+<H2>CUPS for Users</H2>
+
+<P><A HREF="help/overview.html">Введение в CUPS</A></P>
+
+<P><A HREF="help/options.html">Печать из командной Ñтроки</A></P>
+
+<P><A HREF="help/whatsnew.html">Что нового в CUPS 1.4</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.general">Форум пользователей</A></P>
+
+</TD><TD VALIGN="top" STYLE="border-right: dotted thin #cccccc; padding-left: 20px; padding-right: 20px;">
+
+<H2>CUPS Ð´Ð»Ñ Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñтраторов</H2>
+
+<P><A HREF="admin">Добавление принтеров и групп</A></P>
+
+<P><A HREF="help/policies.html">Управление доÑтупом</A></P>
+
+<P><A HREF="help/accounting.html">ИÑпользование реÑурÑов</A></P>
+
+<P><A HREF="help/security.html">БезопаÑноÑÑ‚ÑŒ ÑиÑтемы</A></P>
+
+<P><A HREF="help/kerberos.html">ИÑпользование аутентификации Kerberos</A></P>
+
+<P><A HREF="help/network.html">ИÑпользование Ñетевых принтеров</A></P>
+
+<P><A HREF="help/ref-cupsd-conf.html">Справочник по cupsd.conf</A></P>
+
+<P><A HREF="http://www.cups.org/ppd.php">ПоиÑк драйверов принтера</A></P>
+
+</TD><TD VALIGN="top" STYLE="padding-left: 20px;">
+
+<H2>CUPS Ð´Ð»Ñ Ñ€Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚Ñ‡Ð¸ÐºÐ¾Ð²</H2>
+
+<P><A HREF="help/api-overview.html">Введение в разработку CUPS</A></P>
+
+<P><A HREF="help/api-cups.html">CUPS API</A></P>
+
+<P><A HREF="help/api-filter.html">Разработка фильтров и модулей</A></P>
+
+<P><A HREF="help/api-httpipp.html">API доÑтупа по HTTP и IPP</A></P>
+
+<P><A HREF="help/api-ppd.html">PPD API</A></P>
+
+<P><A HREF="help/api-raster.html">Raster API</A></P>
+
+<P><A HREF="help/ref-ppdcfile.html">Справочник по компилÑтору PPD</A></P>
+
+<P><A HREF="http://www.cups.org/newsgroups.php?gcups.development">Форум разработчиков</A></P>
+
+</TD></TR>
+</TABLE>
+
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS а также логотип CUPS ÑвлÑÑŽÑ‚ÑÑ Ð·Ð°Ñ€ÐµÐ³Ð¸Ñтрированными торговыми марками <A HREF="http://www.apple.com">Apple Inc.</A> ÐвторÑкие права на CUPS принадлежат (2007-2011) компании Apple Inc. Ð’Ñе права защищены.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/driver/Dependencies b/driver/Dependencies
new file mode 100644
index 000000000..6730f13f5
--- /dev/null
+++ b/driver/Dependencies
@@ -0,0 +1,75 @@
+# DO NOT DELETE
+
+commandtoescpx.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+commandtoescpx.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+commandtoescpx.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+commandtoescpx.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+commandtoescpx.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+commandtoescpx.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+commandtoescpx.o: ../cups/ipp-private.h ../cups/ipp.h
+commandtoescpx.o: ../cups/language-private.h ../cups/transcode.h
+commandtoescpx.o: ../cups/thread-private.h driver.h ../cups/raster.h
+commandtoescpx.o: ../cups/ppd.h ../data/escp.h
+commandtopclx.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+commandtopclx.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+commandtopclx.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+commandtopclx.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+commandtopclx.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+commandtopclx.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+commandtopclx.o: ../cups/ipp-private.h ../cups/ipp.h
+commandtopclx.o: ../cups/language-private.h ../cups/transcode.h
+commandtopclx.o: ../cups/thread-private.h driver.h ../cups/raster.h
+commandtopclx.o: ../cups/ppd.h ../data/pcl.h
+rastertoescpx.o: driver.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+rastertoescpx.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+rastertoescpx.o: ../cups/language.h ../cups/raster.h ../cups/cups.h
+rastertoescpx.o: ../cups/ppd.h ../cups/language-private.h ../cups/transcode.h
+rastertoescpx.o: ../cups/string-private.h ../config.h ../data/escp.h
+rastertopclx.o: driver.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+rastertopclx.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+rastertopclx.o: ../cups/language.h ../cups/raster.h ../cups/cups.h
+rastertopclx.o: ../cups/ppd.h ../cups/language-private.h ../cups/transcode.h
+rastertopclx.o: ../cups/string-private.h ../config.h pcl-common.h
+rastertopclx.o: ../data/pcl.h
+pcl-common.o: driver.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+pcl-common.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+pcl-common.o: ../cups/raster.h ../cups/cups.h ../cups/ppd.h pcl-common.h
+pcl-common.o: ../cups/string-private.h ../config.h ../data/pcl.h
+testcmyk.o: ../cups/string-private.h ../config.h driver.h ../cups/cups.h
+testcmyk.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+testcmyk.o: ../cups/array.h ../cups/language.h ../cups/raster.h
+testcmyk.o: ../cups/cups.h ../cups/ppd.h
+testdither.o: driver.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+testdither.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+testdither.o: ../cups/raster.h ../cups/cups.h ../cups/ppd.h
+testdither.o: ../cups/string-private.h ../config.h
+testrgb.o: ../cups/string-private.h ../config.h driver.h ../cups/cups.h
+testrgb.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+testrgb.o: ../cups/array.h ../cups/language.h ../cups/raster.h ../cups/cups.h
+testrgb.o: ../cups/ppd.h
+attr.o: driver.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+attr.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+attr.o: ../cups/raster.h ../cups/cups.h ../cups/ppd.h
+attr.o: ../cups/string-private.h ../config.h
+check.o: driver.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+check.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+check.o: ../cups/raster.h ../cups/cups.h ../cups/ppd.h
+cmyk.o: driver.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+cmyk.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+cmyk.o: ../cups/raster.h ../cups/cups.h ../cups/ppd.h
+cmyk.o: ../cups/string-private.h ../config.h
+dither.o: driver.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+dither.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+dither.o: ../cups/raster.h ../cups/cups.h ../cups/ppd.h ../config.h
+lut.o: driver.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+lut.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+lut.o: ../cups/raster.h ../cups/cups.h ../cups/ppd.h
+pack.o: driver.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+pack.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+pack.o: ../cups/raster.h ../cups/cups.h ../cups/ppd.h
+rgb.o: driver.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+rgb.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+rgb.o: ../cups/raster.h ../cups/cups.h ../cups/ppd.h
+srgb.o: driver.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+srgb.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+srgb.o: ../cups/raster.h ../cups/cups.h ../cups/ppd.h
diff --git a/driver/Makefile b/driver/Makefile
new file mode 100644
index 000000000..21fdfe29c
--- /dev/null
+++ b/driver/Makefile
@@ -0,0 +1,382 @@
+#
+# "$Id$"
+#
+# Makefile for the CUPS base drivers.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 2002-2005 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+#
+# Include standard definitions...
+#
+
+include ../Makedefs
+
+
+#
+# Object files...
+#
+
+LIBOBJS = \
+ attr.o \
+ check.o \
+ cmyk.o \
+ dither.o \
+ lut.o \
+ pack.o \
+ rgb.o \
+ srgb.o
+OBJS = \
+ commandtoescpx.o \
+ commandtopclx.o \
+ rastertoescpx.o \
+ rastertopclx.o \
+ pcl-common.o \
+ testcmyk.o \
+ testdither.o \
+ testrgb.o \
+ $(LIBOBJS)
+
+LIBTARGETS = \
+ $(LIBCUPSDRIVER) \
+ libcupsdriver.a
+UNITTARGETS = \
+ testcmyk \
+ testdither \
+ testrgb
+FILTERS = \
+ commandtoescpx \
+ commandtopclx \
+ rastertoescpx \
+ rastertopclx
+TARGETS = \
+ $(LIBTARGETS) \
+ $(FILTERS)
+
+
+#
+# Make everything...
+#
+
+all: $(TARGETS)
+
+
+#
+# Make library targets...
+#
+
+libs: $(LIBTARGETS)
+
+
+#
+# Make unit tests...
+#
+
+unittests: $(UNITTARGETS)
+
+
+#
+# Clean everything...
+#
+
+clean:
+ $(RM) $(OBJS) core
+ $(RM) *.bck core.*
+ $(RM) $(TARGETS) $(UNITTARGETS)
+ $(RM) -r test
+ $(RM) libcupsdriver.so libcupsdriver.sl libcupsdriver.dylib
+
+
+#
+# Update dependencies...
+#
+
+depend:
+ makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+
+
+#
+# Install programs...
+#
+
+install-exec:
+ $(INSTALL_DIR) $(SERVERBIN)/filter
+ for file in $(FILTERS); do \
+ $(INSTALL_BIN) $$file $(SERVERBIN)/filter; \
+ done
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ for file in $(FILTERS); do \
+ cp $$file $(SYMROOT); \
+ done \
+ fi
+
+
+#
+# Install headers...
+#
+
+install-headers:
+ echo Installing header files in $(INCLUDEDIR)/cups...
+ $(INSTALL_DIR) -m 755 $(INCLUDEDIR)/cups
+ $(INSTALL_DATA) driver.h $(INCLUDEDIR)/cups
+
+
+#
+# Install libraries...
+#
+
+install-libs: $(INSTALLSTATIC)
+ echo Installing libraries in $(LIBDIR)...
+ $(INSTALL_DIR) -m 755 $(LIBDIR)
+ $(INSTALL_LIB) $(LIBCUPSDRIVER) $(LIBDIR)
+ if test $(LIBCUPSDRIVER) = "libcupsdriver.so.1" -o $(LIBCUPSDRIVER) = "libcupsdriver.sl.1"; then \
+ $(RM) $(LIBDIR)/`basename $(LIBCUPSDRIVER) .1`; \
+ $(LN) $(LIBCUPSDRIVER) $(LIBDIR)/`basename $(LIBCUPSDRIVER) .1`; \
+ fi
+ if test $(LIBCUPSDRIVER) = "libcupsdriver.1.dylib"; then \
+ $(RM) $(LIBDIR)/libcupsdriver.dylib; \
+ $(LN) $(LIBCUPSDRIVER) $(LIBDIR)/libcupsdriver.dylib; \
+ fi
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ cp $(LIBCUPSDRIVER) $(SYMROOT); \
+ fi
+
+installstatic:
+ $(INSTALL_DIR) -m 755 $(LIBDIR)
+ $(INSTALL_LIB) -m 755 libcupsdriver.a $(LIBDIR)
+ $(RANLIB) $(LIBDIR)/libcupsdriver.a
+ $(CHMOD) 555 $(LIBDIR)/libcupsdriver.a
+
+
+#
+# Uninstall...
+#
+
+uninstall:
+ for file in commandtoescpx commandtopclx rastertoescpx rastertopclx; do \
+ $(RM) $(SERVERBIN)/filter/$$file; \
+ done
+ $(RM) $(LIBDIR)/libcupsdriver.1.dylib
+ $(RM) $(LIBDIR)/libcupsdriver.a
+ $(RM) $(LIBDIR)/libcupsdriver.dylib
+ $(RM) $(LIBDIR)/libcupsdriver_s.a
+ $(RM) $(LIBDIR)/libcupsdriver.sl
+ $(RM) $(LIBDIR)/libcupsdriver.sl.1
+ $(RM) $(LIBDIR)/libcupsdriver.so
+ $(RM) $(LIBDIR)/libcupsdriver.so.1
+ -$(RMDIR) $(LIBDIR)
+ $(RM) $(INCLUDEDIR)/cups/driver.h
+ -$(RMDIR) $(INCLUDEDIR)/cups
+
+
+#
+# Automatic API help files...
+#
+
+apihelp:
+ mxmldoc --section "Programming" \
+ --title "Printer Driver API" \
+ --css ../doc/cups-printable.css \
+ --header api-driver.header --intro api-driver.shtml \
+ api-driver.xml \
+ driver.h $(LIBOBJS:.o=.c) >../doc/help/api-driver.html
+ mxmldoc --tokens help/api-driver.html >../doc/help/api-driver.tokens
+ $(RM) api-driver.xml
+
+framedhelp:
+ mxmldoc --framed api-driver \
+ --section "Programming" \
+ --title "Printer Driver API" \
+ --css ../doc/cups-printable.css \
+ --header api-driver.header --intro api-driver.shtml \
+ driver.h $(LIBOBJS:.o=.c)
+
+
+#
+# commandtopclx, the PCL command printer driver.
+#
+
+commandtopclx: commandtopclx.o $(LIBCUPSDRIVER) ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ commandtopclx.o -L. -lcupsdriver $(LIBS)
+
+
+#
+# commandtoescpx, the ESC/P command printer driver.
+#
+
+commandtoescpx: commandtoescpx.o $(LIBCUPSDRIVER) ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ commandtoescpx.o -L. -lcupsdriver $(LIBS)
+
+
+#
+# rastertoescpx, the ESC/P raster printer driver.
+#
+
+rastertoescpx: rastertoescpx.o $(LIBCUPSDRIVER) ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ rastertoescpx.o -L. -lcupsdriver \
+ $(LINKCUPSIMAGE) $(LIBS)
+
+
+#
+# rastertopclx, the ESC/P raster printer driver.
+#
+
+rastertopclx: rastertopclx.o pcl-common.o $(LIBCUPSDRIVER) \
+ ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ rastertopclx.o pcl-common.o -L. -lcupsdriver \
+ $(LINKCUPSIMAGE) $(LIBS)
+
+
+#
+# test, make a common test subdirectory for the other test programs.
+#
+
+test:
+ if test ! -d test; then \
+ rm -rf test; \
+ mkdir test; \
+ fi
+
+
+#
+# testcmyk, test cmyk separation functions.
+#
+
+testcmyk: test testcmyk.o libcupsdriver.a ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testcmyk.o libcupsdriver.a \
+ ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ $(COMMONLIBS) $(LIBZ)
+ echo Running CMYK API tests...
+ ./testcmyk > test/testcmyk.log
+
+
+#
+# testdither, test dithering functions.
+#
+
+testdither: test testdither.o libcupsdriver.a ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testdither.o libcupsdriver.a \
+ ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ $(COMMONLIBS) $(LIBZ)
+ echo Running dither API tests...
+ ./testdither > test/0-255.pgm 2>test/0-255.log
+ ./testdither 0 127 255 > test/0-127-255.pgm 2>test/0-127-255.log
+ ./testdither 0 85 170 255 > test/0-85-170-255.pgm 2>test/0-85-170-255.log
+ ./testdither 0 63 127 170 198 227 255 > test/0-63-127-170-198-227-255.pgm 2>test/0-63-127-170-198-227-255.log
+ ./testdither 0 210 383 > test/0-210-383.pgm 2>test/0-210-383.log
+ ./testdither 0 82 255 > test/0-82-255.pgm 2>test/0-82-255.log
+ ./testdither 0 510 > test/0-510.pgm 2>test/0-510.log
+ ./testdither 0 1020 > test/0-1020.pgm 2>test/0-1020.log
+
+
+#
+# testrgb, test RGB separation functions.
+#
+
+testrgb: test testrgb.o libcupsdriver.a ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testrgb.o libcupsdriver.a \
+ ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ $(COMMONLIBS) $(LIBZ)
+ echo Running RGB API tests...
+ ./testrgb > test/testrgb.log 2>&1 || echo "RGB tests failed!"
+
+
+#
+# libcupsdriver.so.1, libcupsdriver.sl.1
+#
+
+libcupsdriver.so.1 libcupsdriver.sl.1: $(LIBOBJS)
+ echo Linking $@...
+ $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS) $(LIBS)
+ $(RM) `basename $@ .1`
+ $(LN) $@ `basename $@ .1`
+
+
+#
+# libcupsdriver.1.dylib
+#
+
+libcupsdriver.1.dylib: $(LIBOBJS) libcupsdriver.exp
+ echo Linking $@...
+ $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ \
+ -install_name $(libdir)/$@ \
+ -current_version 1.0.0 \
+ -compatibility_version 1.0.0 \
+ -exported_symbols_list libcupsdriver.exp \
+ $(LIBOBJS) $(LIBS)
+ $(RM) libcupsdriver.dylib
+ $(LN) $@ libcupsdriver.dylib
+
+
+#
+# libcupsdriver_s.a
+#
+
+libcupsdriver_s.a: $(LIBOBJS)
+ echo Creating $@...
+ $(DSO) $(DSOFLAGS) -o libcupsdriver_s.o $(LIBOBJS) $(LIBS)
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ libcupsdriver_s.o
+
+
+#
+# libcupsdriver.la
+#
+
+libcupsdriver.la: $(LIBOBJS)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS:.o=.lo) -rpath $(LIBDIR) \
+ -version-info 1:0 $(LIBS)
+
+
+#
+# libcupsdriver.a
+#
+
+libcupsdriver.a: $(LIBOBJS)
+ echo Archiving $@...
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ $(LIBOBJS)
+ $(RANLIB) $@
+
+
+#
+# Include dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id$".
+#
diff --git a/driver/api-driver.header b/driver/api-driver.header
new file mode 100644
index 000000000..0f3937bc1
--- /dev/null
+++ b/driver/api-driver.header
@@ -0,0 +1,34 @@
+<!--
+ "$Id: api-array.header 8087 2008-10-27 21:37:05Z mike $"
+
+ Driver API header for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Driver API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/driver.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcupsdriver</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/driver/api-driver.shtml b/driver/api-driver.shtml
new file mode 100644
index 000000000..0e8bcff27
--- /dev/null
+++ b/driver/api-driver.shtml
@@ -0,0 +1,18 @@
+<!--
+ "$Id: api-array.shtml 7616 2008-05-28 00:34:13Z mike $"
+
+ Driver API introduction for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>The driver API provides common dithering, color conversion, and utility
+functions for CUPS drivers.</p>
diff --git a/driver/attr.c b/driver/attr.c
new file mode 100644
index 000000000..4eba32417
--- /dev/null
+++ b/driver/attr.c
@@ -0,0 +1,109 @@
+/*
+ * "$Id$"
+ *
+ * PPD attribute lookup routine for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsFindAttr() - Find a PPD attribute based on the colormodel,
+ * media, and resolution.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "driver.h"
+#include <cups/string-private.h>
+
+
+/*
+ * 'cupsFindAttr()' - Find a PPD attribute based on the colormodel,
+ * media, and resolution.
+ */
+
+ppd_attr_t * /* O - Matching attribute or NULL */
+cupsFindAttr(ppd_file_t *ppd, /* I - PPD file */
+ const char *name, /* I - Attribute name */
+ const char *colormodel, /* I - Color model */
+ const char *media, /* I - Media type */
+ const char *resolution, /* I - Resolution */
+ char *spec, /* O - Final selection string */
+ int specsize) /* I - Size of string buffer */
+{
+ ppd_attr_t *attr; /* Attribute */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !name || !colormodel || !media || !resolution || !spec ||
+ specsize < PPD_MAX_NAME)
+ return (NULL);
+
+ /*
+ * Look for the attribute with the following keywords:
+ *
+ * ColorModel.MediaType.Resolution
+ * ColorModel.Resolution
+ * ColorModel
+ * MediaType.Resolution
+ * MediaType
+ * Resolution
+ * ""
+ */
+
+ snprintf(spec, specsize, "%s.%s.%s", colormodel, media, resolution);
+ fprintf(stderr, "DEBUG2: Looking for \"*%s %s\"...\n", name, spec);
+ if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+ return (attr);
+
+ snprintf(spec, specsize, "%s.%s", colormodel, resolution);
+ fprintf(stderr, "DEBUG2: Looking for \"*%s %s\"...\n", name, spec);
+ if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+ return (attr);
+
+ strlcpy(spec, colormodel, specsize);
+ fprintf(stderr, "DEBUG2: Looking for \"*%s %s\"...\n", name, spec);
+ if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+ return (attr);
+
+ snprintf(spec, specsize, "%s.%s", media, resolution);
+ fprintf(stderr, "DEBUG2: Looking for \"*%s %s\"...\n", name, spec);
+ if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+ return (attr);
+
+ strlcpy(spec, media, specsize);
+ fprintf(stderr, "DEBUG2: Looking for \"*%s %s\"...\n", name, spec);
+ if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+ return (attr);
+
+ strlcpy(spec, resolution, specsize);
+ fprintf(stderr, "DEBUG2: Looking for \"*%s %s\"...\n", name, spec);
+ if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+ return (attr);
+
+ spec[0] = '\0';
+ fprintf(stderr, "DEBUG2: Looking for \"*%s\"...\n", name);
+ if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+ return (attr);
+
+ fprintf(stderr, "DEBUG2: No instance of \"*%s\" found...\n", name);
+
+ return (NULL);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/check.c b/driver/check.c
new file mode 100644
index 000000000..d7ceb3d44
--- /dev/null
+++ b/driver/check.c
@@ -0,0 +1,111 @@
+/*
+ * "$Id$"
+ *
+ * Byte checking routines for CUPS.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsCheckBytes() - Check to see if all bytes are zero.
+ * cupsCheckValue() - Check to see if all bytes match the given value.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "driver.h"
+
+
+/*
+ * 'cupsCheckBytes()' - Check to see if all bytes are zero.
+ */
+
+int /* O - 1 if they match */
+cupsCheckBytes(const unsigned char *bytes, /* I - Bytes to check */
+ int length) /* I - Number of bytes to check */
+{
+ while (length > 7)
+ {
+ if (*bytes++)
+ return (0);
+ if (*bytes++)
+ return (0);
+ if (*bytes++)
+ return (0);
+ if (*bytes++)
+ return (0);
+ if (*bytes++)
+ return (0);
+ if (*bytes++)
+ return (0);
+ if (*bytes++)
+ return (0);
+ if (*bytes++)
+ return (0);
+
+ length -= 8;
+ }
+
+ while (length > 0)
+ if (*bytes++)
+ return (0);
+ else
+ length --;
+
+ return (1);
+}
+
+
+/*
+ * 'cupsCheckValue()' - Check to see if all bytes match the given value.
+ */
+
+int /* O - 1 if they match */
+cupsCheckValue(const unsigned char *bytes, /* I - Bytes to check */
+ int length, /* I - Number of bytes to check */
+ const unsigned char value) /* I - Value to check */
+{
+ while (length > 7)
+ {
+ if (*bytes++ != value)
+ return (0);
+ if (*bytes++ != value)
+ return (0);
+ if (*bytes++ != value)
+ return (0);
+ if (*bytes++ != value)
+ return (0);
+ if (*bytes++ != value)
+ return (0);
+ if (*bytes++ != value)
+ return (0);
+ if (*bytes++ != value)
+ return (0);
+ if (*bytes++ != value)
+ return (0);
+
+ length -= 8;
+ }
+
+ while (length > 0)
+ if (*bytes++ != value)
+ return (0);
+ else
+ length --;
+
+ return (1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/cmyk.c b/driver/cmyk.c
new file mode 100644
index 000000000..c6c350c24
--- /dev/null
+++ b/driver/cmyk.c
@@ -0,0 +1,1955 @@
+/*
+ * "$Id$"
+ *
+ * CMYK color separation code for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsCMYKDelete() - Delete a color separation.
+ * cupsCMYKDoBlack() - Do a black separation...
+ * cupsCMYKDoCMYK() - Do a CMYK separation...
+ * cupsCMYKDoGray() - Do a grayscale separation...
+ * cupsCMYKDoRGB() - Do an sRGB separation...
+ * cupsCMYKLoad() - Load a CMYK color profile from PPD attributes.
+ * cupsCMYKNew() - Create a new CMYK color separation.
+ * cupsCMYKSetBlack() - Set the transition range for CMY to black.
+ * cupsCMYKSetCurve() - Set a color transform curve using points.
+ * cupsCMYKSetGamma() - Set a color transform curve using gamma and
+ * density.
+ * cupsCMYKSetInkLimit() - Set the limit on the amount of ink.
+ * cupsCMYKSetLtDk() - Set light/dark ink transforms.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "driver.h"
+#include <cups/string-private.h>
+
+
+/*
+ * 'cupsCMYKDelete()' - Delete a color separation.
+ */
+
+void
+cupsCMYKDelete(cups_cmyk_t *cmyk) /* I - Color separation */
+{
+ /*
+ * Range check input...
+ */
+
+ if (cmyk == NULL)
+ return;
+
+ /*
+ * Free memory used...
+ */
+
+ free(cmyk->channels[0]);
+ free(cmyk);
+}
+
+
+/*
+ * 'cupsCMYKDoBlack()' - Do a black separation...
+ */
+
+void
+cupsCMYKDoBlack(const cups_cmyk_t *cmyk,
+ /* I - Color separation */
+ const unsigned char *input,
+ /* I - Input grayscale pixels */
+ short *output,
+ /* O - Output Device-N pixels */
+ int num_pixels)
+ /* I - Number of pixels */
+{
+ int k; /* Current black value */
+ const short **channels; /* Copy of channel LUTs */
+ int ink, /* Amount of ink */
+ ink_limit; /* Ink limit from separation */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0)
+ return;
+
+ /*
+ * Loop through it all...
+ */
+
+ channels = (const short **)cmyk->channels;
+ ink_limit = cmyk->ink_limit;
+
+ switch (cmyk->num_channels)
+ {
+ case 1 : /* Black */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ k = *input++;
+ *output++ = channels[0][k];
+
+ num_pixels --;
+ }
+ break;
+
+ case 2 : /* Black, light black */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ k = *input++;
+ output[0] = channels[0][k];
+ output[1] = channels[1][k];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ }
+ }
+
+ output += 2;
+ num_pixels --;
+ }
+ break;
+
+ case 3 : /* CMY */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ k = *input++;
+ output[0] = channels[0][k];
+ output[1] = channels[1][k];
+ output[2] = channels[2][k];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1] + output[2];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ output[2] = ink_limit * output[2] / ink;
+ }
+ }
+
+ output += 3;
+ num_pixels --;
+ }
+ break;
+
+ case 4 : /* CMYK */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ k = *input++;
+ *output++ = 0;
+ *output++ = 0;
+ *output++ = 0;
+ *output++ = channels[3][k];
+
+ num_pixels --;
+ }
+ break;
+
+ case 6 : /* CcMmYK */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ k = *input++;
+ *output++ = 0;
+ *output++ = 0;
+ *output++ = 0;
+ *output++ = 0;
+ *output++ = 0;
+ *output++ = channels[5][k];
+
+ num_pixels --;
+ }
+ break;
+
+ case 7 : /* CcMmYKk */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ k = *input++;
+ output[0] = 0;
+ output[1] = 0;
+ output[2] = 0;
+ output[3] = 0;
+ output[4] = 0;
+ output[5] = channels[5][k];
+ output[6] = channels[6][k];
+
+ if (ink_limit)
+ {
+ ink = output[5] + output[6];
+
+ if (ink > ink_limit)
+ {
+ output[5] = ink_limit * output[5] / ink;
+ output[6] = ink_limit * output[6] / ink;
+ }
+ }
+
+ output += 7;
+ num_pixels --;
+ }
+ break;
+ }
+}
+
+
+/*
+ * 'cupsCMYKDoCMYK()' - Do a CMYK separation...
+ */
+
+void
+cupsCMYKDoCMYK(const cups_cmyk_t *cmyk,
+ /* I - Color separation */
+ const unsigned char *input,
+ /* I - Input grayscale pixels */
+ short *output,
+ /* O - Output Device-N pixels */
+ int num_pixels)
+ /* I - Number of pixels */
+{
+ int c, /* Current cyan value */
+ m, /* Current magenta value */
+ y, /* Current yellow value */
+ k; /* Current black value */
+ const short **channels; /* Copy of channel LUTs */
+ int ink, /* Amount of ink */
+ ink_limit; /* Ink limit from separation */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0)
+ return;
+
+ /*
+ * Loop through it all...
+ */
+
+ channels = (const short **)cmyk->channels;
+ ink_limit = cmyk->ink_limit;
+
+ switch (cmyk->num_channels)
+ {
+ case 1 : /* Black */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ c = *input++;
+ m = *input++;
+ y = *input++;
+ k = *input++ + (c * 31 + m * 61 + y * 8) / 100;
+
+ if (k < 255)
+ *output++ = channels[0][k];
+ else
+ *output++ = channels[0][255];
+
+ num_pixels --;
+ }
+ break;
+
+ case 2 : /* Black, light black */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ c = *input++;
+ m = *input++;
+ y = *input++;
+ k = *input++ + (c * 31 + m * 61 + y * 8) / 100;
+
+ if (k < 255)
+ {
+ output[0] = channels[0][k];
+ output[1] = channels[1][k];
+ }
+ else
+ {
+ output[0] = channels[0][255];
+ output[1] = channels[1][255];
+ }
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ }
+ }
+
+ output += 2;
+ num_pixels --;
+ }
+ break;
+
+ case 3 : /* CMY */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ c = *input++;
+ m = *input++;
+ y = *input++;
+ k = *input++;
+ c += k;
+ m += k;
+ y += k;
+
+ if (c < 255)
+ output[0] = channels[0][c];
+ else
+ output[0] = channels[0][255];
+
+ if (m < 255)
+ output[1] = channels[1][m];
+ else
+ output[1] = channels[1][255];
+
+ if (y < 255)
+ output[2] = channels[2][y];
+ else
+ output[2] = channels[2][255];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1] + output[2];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ output[2] = ink_limit * output[2] / ink;
+ }
+ }
+
+ output += 3;
+ num_pixels --;
+ }
+ break;
+
+ case 4 : /* CMYK */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ c = *input++;
+ m = *input++;
+ y = *input++;
+ k = *input++;
+
+ output[0] = channels[0][c];
+ output[1] = channels[1][m];
+ output[2] = channels[2][y];
+ output[3] = channels[3][k];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1] + output[2] + output[3];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ output[2] = ink_limit * output[2] / ink;
+ output[3] = ink_limit * output[3] / ink;
+ }
+ }
+
+ output += 4;
+ num_pixels --;
+ }
+ break;
+
+ case 6 : /* CcMmYK */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ c = *input++;
+ m = *input++;
+ y = *input++;
+ k = *input++;
+
+ output[0] = channels[0][c];
+ output[1] = channels[1][c];
+ output[2] = channels[2][m];
+ output[3] = channels[3][m];
+ output[4] = channels[4][y];
+ output[5] = channels[5][k];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1] + output[2] + output[3] +
+ output[4] + output[5];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ output[2] = ink_limit * output[2] / ink;
+ output[3] = ink_limit * output[3] / ink;
+ output[4] = ink_limit * output[4] / ink;
+ output[5] = ink_limit * output[5] / ink;
+ }
+ }
+
+ output += 6;
+ num_pixels --;
+ }
+ break;
+
+ case 7 : /* CcMmYKk */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ c = *input++;
+ m = *input++;
+ y = *input++;
+ k = *input++;
+
+ output[0] = channels[0][c];
+ output[1] = channels[1][c];
+ output[2] = channels[2][m];
+ output[3] = channels[3][m];
+ output[4] = channels[4][y];
+ output[5] = channels[5][k];
+ output[6] = channels[6][k];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1] + output[2] + output[3] +
+ output[4] + output[5] + output[6];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ output[2] = ink_limit * output[2] / ink;
+ output[3] = ink_limit * output[3] / ink;
+ output[4] = ink_limit * output[4] / ink;
+ output[5] = ink_limit * output[5] / ink;
+ output[6] = ink_limit * output[6] / ink;
+ }
+ }
+
+ output += 7;
+ num_pixels --;
+ }
+ break;
+ }
+}
+
+
+/*
+ * 'cupsCMYKDoGray()' - Do a grayscale separation...
+ */
+
+void
+cupsCMYKDoGray(const cups_cmyk_t *cmyk,
+ /* I - Color separation */
+ const unsigned char *input,
+ /* I - Input grayscale pixels */
+ short *output,
+ /* O - Output Device-N pixels */
+ int num_pixels)
+ /* I - Number of pixels */
+{
+ int k, /* Current black value */
+ kc; /* Current black color value */
+ const short **channels; /* Copy of channel LUTs */
+ int ink, /* Amount of ink */
+ ink_limit; /* Ink limit from separation */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0)
+ return;
+
+ /*
+ * Loop through it all...
+ */
+
+ channels = (const short **)cmyk->channels;
+ ink_limit = cmyk->ink_limit;
+
+ switch (cmyk->num_channels)
+ {
+ case 1 : /* Black */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ k = cups_scmy_lut[*input++];
+ *output++ = channels[0][k];
+
+ num_pixels --;
+ }
+ break;
+
+ case 2 : /* Black, light black */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ k = cups_scmy_lut[*input++];
+ output[0] = channels[0][k];
+ output[1] = channels[1][k];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ }
+ }
+
+ output += 2;
+ num_pixels --;
+ }
+ break;
+
+ case 3 : /* CMY */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ k = cups_scmy_lut[*input++];
+ output[0] = channels[0][k];
+ output[1] = channels[1][k];
+ output[2] = channels[2][k];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1] + output[2];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ output[2] = ink_limit * output[2] / ink;
+ }
+ }
+
+ output += 3;
+ num_pixels --;
+ }
+ break;
+
+ case 4 : /* CMYK */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ k = cups_scmy_lut[*input++];
+ kc = cmyk->color_lut[k];
+ k = cmyk->black_lut[k];
+ output[0] = channels[0][kc];
+ output[1] = channels[1][kc];
+ output[2] = channels[2][kc];
+ output[3] = channels[3][k];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1] + output[2] + output[3];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ output[2] = ink_limit * output[2] / ink;
+ output[3] = ink_limit * output[3] / ink;
+ }
+ }
+
+ output += 4;
+ num_pixels --;
+ }
+ break;
+
+ case 6 : /* CcMmYK */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ k = cups_scmy_lut[*input++];
+ kc = cmyk->color_lut[k];
+ k = cmyk->black_lut[k];
+ output[0] = channels[0][kc];
+ output[1] = channels[1][kc];
+ output[2] = channels[2][kc];
+ output[3] = channels[3][kc];
+ output[4] = channels[4][kc];
+ output[5] = channels[5][k];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1] + output[2] + output[3] +
+ output[4] + output[5];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ output[2] = ink_limit * output[2] / ink;
+ output[3] = ink_limit * output[3] / ink;
+ output[4] = ink_limit * output[4] / ink;
+ output[5] = ink_limit * output[5] / ink;
+ }
+ }
+
+ output += 6;
+ num_pixels --;
+ }
+ break;
+
+ case 7 : /* CcMmYKk */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ k = cups_scmy_lut[*input++];
+ kc = cmyk->color_lut[k];
+ k = cmyk->black_lut[k];
+ output[0] = channels[0][kc];
+ output[1] = channels[1][kc];
+ output[2] = channels[2][kc];
+ output[3] = channels[3][kc];
+ output[4] = channels[4][kc];
+ output[5] = channels[5][k];
+ output[6] = channels[6][k];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1] + output[2] + output[3] +
+ output[4] + output[5] + output[6];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ output[2] = ink_limit * output[2] / ink;
+ output[3] = ink_limit * output[3] / ink;
+ output[4] = ink_limit * output[4] / ink;
+ output[5] = ink_limit * output[5] / ink;
+ output[6] = ink_limit * output[6] / ink;
+ }
+ }
+
+ output += 7;
+ num_pixels --;
+ }
+ break;
+ }
+}
+
+
+/*
+ * 'cupsCMYKDoRGB()' - Do an sRGB separation...
+ */
+
+void
+cupsCMYKDoRGB(const cups_cmyk_t *cmyk,
+ /* I - Color separation */
+ const unsigned char *input,
+ /* I - Input grayscale pixels */
+ short *output,
+ /* O - Output Device-N pixels */
+ int num_pixels)
+ /* I - Number of pixels */
+{
+ int c, /* Current cyan value */
+ m, /* Current magenta value */
+ y, /* Current yellow value */
+ k, /* Current black value */
+ kc, /* Current black color value */
+ km; /* Maximum black value */
+ const short **channels; /* Copy of channel LUTs */
+ int ink, /* Amount of ink */
+ ink_limit; /* Ink limit from separation */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0)
+ return;
+
+ /*
+ * Loop through it all...
+ */
+
+ channels = (const short **)cmyk->channels;
+ ink_limit = cmyk->ink_limit;
+
+ switch (cmyk->num_channels)
+ {
+ case 1 : /* Black */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ c = cups_scmy_lut[*input++];
+ m = cups_scmy_lut[*input++];
+ y = cups_scmy_lut[*input++];
+ k = (c * 31 + m * 61 + y * 8) / 100;
+
+ *output++ = channels[0][k];
+
+ num_pixels --;
+ }
+ break;
+
+ case 2 : /* Black, light black */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ c = cups_scmy_lut[*input++];
+ m = cups_scmy_lut[*input++];
+ y = cups_scmy_lut[*input++];
+ k = (c * 31 + m * 61 + y * 8) / 100;
+
+ output[0] = channels[0][k];
+ output[1] = channels[1][k];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ }
+ }
+
+ output += 2;
+ num_pixels --;
+ }
+ break;
+
+ case 3 : /* CMY */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ c = cups_scmy_lut[*input++];
+ m = cups_scmy_lut[*input++];
+ y = cups_scmy_lut[*input++];
+
+ output[0] = channels[0][c];
+ output[1] = channels[1][m];
+ output[2] = channels[2][y];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1] + output[2];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ output[2] = ink_limit * output[2] / ink;
+ }
+ }
+
+ output += 3;
+ num_pixels --;
+ }
+ break;
+
+ case 4 : /* CMYK */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ c = cups_scmy_lut[*input++];
+ m = cups_scmy_lut[*input++];
+ y = cups_scmy_lut[*input++];
+ k = min(c, min(m, y));
+
+ if ((km = max(c, max(m, y))) > k)
+ k = k * k * k / (km * km);
+
+ kc = cmyk->color_lut[k] - k;
+ k = cmyk->black_lut[k];
+ c += kc;
+ m += kc;
+ y += kc;
+
+ output[0] = channels[0][c];
+ output[1] = channels[1][m];
+ output[2] = channels[2][y];
+ output[3] = channels[3][k];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1] + output[2] + output[3];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ output[2] = ink_limit * output[2] / ink;
+ output[3] = ink_limit * output[3] / ink;
+ }
+ }
+
+ output += 4;
+ num_pixels --;
+ }
+ break;
+
+ case 6 : /* CcMmYK */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ c = cups_scmy_lut[*input++];
+ m = cups_scmy_lut[*input++];
+ y = cups_scmy_lut[*input++];
+ k = min(c, min(m, y));
+
+ if ((km = max(c, max(m, y))) > k)
+ k = k * k * k / (km * km);
+
+ kc = cmyk->color_lut[k] - k;
+ k = cmyk->black_lut[k];
+ c += kc;
+ m += kc;
+ y += kc;
+
+ output[0] = channels[0][c];
+ output[1] = channels[1][c];
+ output[2] = channels[2][m];
+ output[3] = channels[3][m];
+ output[4] = channels[4][y];
+ output[5] = channels[5][k];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1] + output[2] + output[3] +
+ output[4] + output[5];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ output[2] = ink_limit * output[2] / ink;
+ output[3] = ink_limit * output[3] / ink;
+ output[4] = ink_limit * output[4] / ink;
+ output[5] = ink_limit * output[5] / ink;
+ }
+ }
+
+ output += 6;
+ num_pixels --;
+ }
+ break;
+
+ case 7 : /* CcMmYKk */
+ while (num_pixels > 0)
+ {
+ /*
+ * Get the input black value and then set the corresponding color
+ * channel values...
+ */
+
+ c = cups_scmy_lut[*input++];
+ m = cups_scmy_lut[*input++];
+ y = cups_scmy_lut[*input++];
+ k = min(c, min(m, y));
+
+ if ((km = max(c, max(m, y))) > k)
+ k = k * k * k / (km * km);
+
+ kc = cmyk->color_lut[k] - k;
+ k = cmyk->black_lut[k];
+ c += kc;
+ m += kc;
+ y += kc;
+
+ output[0] = channels[0][c];
+ output[1] = channels[1][c];
+ output[2] = channels[2][m];
+ output[3] = channels[3][m];
+ output[4] = channels[4][y];
+ output[5] = channels[5][k];
+ output[6] = channels[6][k];
+
+ if (ink_limit)
+ {
+ ink = output[0] + output[1] + output[2] + output[3] +
+ output[4] + output[5] + output[6];
+
+ if (ink > ink_limit)
+ {
+ output[0] = ink_limit * output[0] / ink;
+ output[1] = ink_limit * output[1] / ink;
+ output[2] = ink_limit * output[2] / ink;
+ output[3] = ink_limit * output[3] / ink;
+ output[4] = ink_limit * output[4] / ink;
+ output[5] = ink_limit * output[5] / ink;
+ output[6] = ink_limit * output[6] / ink;
+ }
+ }
+
+ output += 7;
+ num_pixels --;
+ }
+ break;
+ }
+}
+
+
+/*
+ * 'cupsCMYKLoad()' - Load a CMYK color profile from PPD attributes.
+ */
+
+cups_cmyk_t * /* O - CMYK color separation */
+cupsCMYKLoad(ppd_file_t *ppd, /* I - PPD file */
+ const char *colormodel, /* I - ColorModel value */
+ const char *media, /* I - MediaType value */
+ const char *resolution) /* I - Resolution value */
+{
+ cups_cmyk_t *cmyk; /* CMYK color separation */
+ char spec[PPD_MAX_NAME]; /* Profile name */
+ ppd_attr_t *attr; /* Attribute from PPD file */
+ int num_channels; /* Number of color components */
+ float gamval, /* Gamma correction value */
+ density, /* Density value */
+ light, /* Light ink limit */
+ dark, /* Light ink cut-off */
+ lower, /* Start of black ink */
+ upper; /* End of color ink */
+ int num_xypoints; /* Number of X,Y points */
+ float xypoints[100 * 2], /* X,Y points */
+ *xyptr; /* Current X,Y point */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (ppd == NULL || colormodel == NULL || resolution == NULL || media == NULL)
+ return (NULL);
+
+ /*
+ * Find the following attributes:
+ *
+ * cupsAllGamma - Set default curve using gamma + density
+ * cupsAllXY - Set default curve using XY points
+ * cupsBlackGamma - Set black curve using gamma + density
+ * cupsBlackGeneration - Set black generation
+ * cupsBlackLightDark - Set black light/dark transition
+ * cupsBlackXY - Set black curve using XY points
+ * cupsCyanGamma - Set cyan curve using gamma + density
+ * cupsCyanLightDark - Set cyan light/dark transition
+ * cupsCyanXY - Set cyan curve using XY points
+ * cupsInkChannels - Set number of color channels
+ * cupsInkLimit - Set total ink limit
+ * cupsLightBlackGamma - Set light black curve using gamma + density
+ * cupsLightBlackXY - Set light black curve using XY points
+ * cupsLightCyanGamma - Set light cyan curve using gamma + density
+ * cupsLightCyanXY - Set light cyan curve using XY points
+ * cupsLightMagentaGamma - Set light magenta curve using gamma + density
+ * cupsLightMagentaXY - Set light magenta curve using XY points
+ * cupsMagentaGamma - Set magenta curve using gamma + density
+ * cupsMagentaLightDark - Set magenta light/dark transition
+ * cupsMagentaXY - Set magenta curve using XY points
+ * cupsYellowGamma - Set yellow curve using gamma + density
+ * cupsYellowXY - Set yellow curve using XY points
+ *
+ * The only required attribute is cupsInkChannels.
+ *
+ * The *XY attributes have precedence over the *Gamma attributes, and
+ * the *Light* attributes have precedence over the corresponding
+ * *LightDark* attributes.
+ */
+
+ /*
+ * Get the required cupsInkChannels attribute...
+ */
+
+ if ((attr = cupsFindAttr(ppd, "cupsInkChannels", colormodel, media,
+ resolution, spec, sizeof(spec))) == NULL)
+ return (NULL);
+
+ num_channels = atoi(attr->value);
+
+ if (num_channels < 1 || num_channels > 7 || num_channels == 5)
+ return (NULL);
+
+ if ((cmyk = cupsCMYKNew(num_channels)) == NULL)
+ return (NULL);
+
+ /*
+ * Get the optional cupsInkLimit attribute...
+ */
+
+ if ((attr = cupsFindAttr(ppd, "cupsInkLimit", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ cupsCMYKSetInkLimit(cmyk, atof(attr->value));
+
+ /*
+ * Get the optional cupsBlackGeneration attribute...
+ */
+
+ if ((attr = cupsFindAttr(ppd, "cupsBlackGeneration", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &lower, &upper) == 2)
+ cupsCMYKSetBlack(cmyk, lower, upper);
+ }
+
+ /*
+ * Get the optional cupsBlackXY or cupsBlackGamma attributes...
+ */
+
+ if (num_channels != 3)
+ {
+ if ((attr = cupsFindAttr(ppd, "cupsBlackXY", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsBlackXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ switch (num_channels)
+ {
+ case 1 :
+ case 2 :
+ cupsCMYKSetCurve(cmyk, 0, num_xypoints, xypoints);
+ break;
+ case 4 :
+ cupsCMYKSetCurve(cmyk, 3, num_xypoints, xypoints);
+ break;
+ case 6 :
+ case 7 :
+ cupsCMYKSetCurve(cmyk, 5, num_xypoints, xypoints);
+ break;
+ }
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsBlackGamma", colormodel,
+ media, resolution, spec,
+ sizeof(spec))) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ switch (num_channels)
+ {
+ case 1 :
+ case 2 :
+ cupsCMYKSetGamma(cmyk, 0, gamval, density);
+ break;
+ case 4 :
+ cupsCMYKSetGamma(cmyk, 3, gamval, density);
+ break;
+ case 6 :
+ case 7 :
+ cupsCMYKSetGamma(cmyk, 5, gamval, density);
+ break;
+ }
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsAllXY", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ switch (num_channels)
+ {
+ case 1 :
+ case 2 :
+ cupsCMYKSetCurve(cmyk, 0, num_xypoints, xypoints);
+ break;
+ case 4 :
+ cupsCMYKSetCurve(cmyk, 3, num_xypoints, xypoints);
+ break;
+ case 6 :
+ case 7 :
+ cupsCMYKSetCurve(cmyk, 5, num_xypoints, xypoints);
+ break;
+ }
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsAllGamma", colormodel,
+ media, resolution, spec,
+ sizeof(spec))) != NULL &&
+ num_channels != 3)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ switch (num_channels)
+ {
+ case 1 :
+ case 2 :
+ cupsCMYKSetGamma(cmyk, 0, gamval, density);
+ break;
+ case 4 :
+ cupsCMYKSetGamma(cmyk, 3, gamval, density);
+ break;
+ case 6 :
+ case 7 :
+ cupsCMYKSetGamma(cmyk, 5, gamval, density);
+ break;
+ }
+ }
+ }
+
+ if (num_channels > 2)
+ {
+ /*
+ * Get the optional cupsCyanXY or cupsCyanGamma attributes...
+ */
+
+ if ((attr = cupsFindAttr(ppd, "cupsCyanXY", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsCyanXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ cupsCMYKSetCurve(cmyk, 0, num_xypoints, xypoints);
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsCyanGamma", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ cupsCMYKSetGamma(cmyk, 0, gamval, density);
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsAllXY", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ cupsCMYKSetCurve(cmyk, 0, num_xypoints, xypoints);
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsAllGamma", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ cupsCMYKSetGamma(cmyk, 0, gamval, density);
+ }
+
+ /*
+ * Get the optional cupsMagentaXY or cupsMagentaGamma attributes...
+ */
+
+ if ((attr = cupsFindAttr(ppd, "cupsMagentaXY", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsMagentaXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cupsCMYKSetCurve(cmyk, 1, num_xypoints, xypoints);
+ break;
+ case 6 :
+ case 7 :
+ cupsCMYKSetCurve(cmyk, 2, num_xypoints, xypoints);
+ break;
+ }
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsMagentaGamma", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cupsCMYKSetGamma(cmyk, 1, gamval, density);
+ break;
+ case 6 :
+ case 7 :
+ cupsCMYKSetGamma(cmyk, 2, gamval, density);
+ break;
+ }
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsAllXY", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cupsCMYKSetCurve(cmyk, 1, num_xypoints, xypoints);
+ break;
+ case 6 :
+ case 7 :
+ cupsCMYKSetCurve(cmyk, 2, num_xypoints, xypoints);
+ break;
+ }
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsAllGamma", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cupsCMYKSetGamma(cmyk, 1, gamval, density);
+ break;
+ case 6 :
+ case 7 :
+ cupsCMYKSetGamma(cmyk, 2, gamval, density);
+ break;
+ }
+ }
+
+ /*
+ * Get the optional cupsYellowXY or cupsYellowGamma attributes...
+ */
+
+ if ((attr = cupsFindAttr(ppd, "cupsYellowXY", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsYellowXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cupsCMYKSetCurve(cmyk, 2, num_xypoints, xypoints);
+ break;
+ case 6 :
+ case 7 :
+ cupsCMYKSetCurve(cmyk, 4, num_xypoints, xypoints);
+ break;
+ }
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsYellowGamma", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cupsCMYKSetGamma(cmyk, 2, gamval, density);
+ break;
+ case 6 :
+ case 7 :
+ cupsCMYKSetGamma(cmyk, 4, gamval, density);
+ break;
+ }
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsAllXY", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cupsCMYKSetCurve(cmyk, 2, num_xypoints, xypoints);
+ break;
+ case 6 :
+ case 7 :
+ cupsCMYKSetCurve(cmyk, 4, num_xypoints, xypoints);
+ break;
+ }
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsAllGamma", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cupsCMYKSetGamma(cmyk, 2, gamval, density);
+ break;
+ case 6 :
+ case 7 :
+ cupsCMYKSetGamma(cmyk, 4, gamval, density);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Get the optional cupsLightBlackXY, cupsLightBlackGamma, or
+ * cupsBlackLtDk attributes...
+ */
+
+ if (num_channels == 2 || num_channels == 7)
+ {
+ if ((attr = cupsFindAttr(ppd, "cupsLightBlackXY", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsLightBlackXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ switch (num_channels)
+ {
+ case 2 :
+ cupsCMYKSetCurve(cmyk, 1, num_xypoints, xypoints);
+ break;
+ case 7 :
+ cupsCMYKSetCurve(cmyk, 6, num_xypoints, xypoints);
+ break;
+ }
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsLightBlackGamma", colormodel,
+ media, resolution, spec,
+ sizeof(spec))) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ switch (num_channels)
+ {
+ case 2 :
+ cupsCMYKSetGamma(cmyk, 1, gamval, density);
+ break;
+ case 7 :
+ cupsCMYKSetGamma(cmyk, 6, gamval, density);
+ break;
+ }
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsBlackLtDk", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
+ switch (num_channels)
+ {
+ case 2 :
+ cupsCMYKSetLtDk(cmyk, 0, light, dark);
+ break;
+ case 7 :
+ cupsCMYKSetLtDk(cmyk, 5, light, dark);
+ break;
+ }
+ else
+ fprintf(stderr, "ERROR: Bad cupsBlackLtDk value \"%s\"!\n",
+ attr->value);
+ }
+ else
+ fprintf(stderr, "WARNING: No light black attribute found for %s!\n",
+ spec);
+ }
+
+ if (num_channels >= 6)
+ {
+ /*
+ * Get the optional cupsLightCyanXY, cupsLightCyanGamma, or
+ * cupsCyanLtDk attributes...
+ */
+
+ if ((attr = cupsFindAttr(ppd, "cupsLightCyanXY", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsLightCyanXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ cupsCMYKSetCurve(cmyk, 1, num_xypoints, xypoints);
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsLightCyanGamma", colormodel,
+ media, resolution, spec,
+ sizeof(spec))) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ cupsCMYKSetGamma(cmyk, 1, gamval, density);
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsCyanLtDk", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
+ cupsCMYKSetLtDk(cmyk, 0, light, dark);
+ else
+ fprintf(stderr, "ERROR: Bad cupsCyanLtDk value \"%s\"!\n",
+ attr->value);
+ }
+ else
+ fprintf(stderr, "WARNING: No light cyan attribute found for %s!\n",
+ spec);
+
+ /*
+ * Get the optional cupsLightMagentaXY, cupsLightMagentaGamma, or
+ * cupsMagentaLtDk attributes...
+ */
+
+ if ((attr = cupsFindAttr(ppd, "cupsLightMagentaXY", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsLightMagentaXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ cupsCMYKSetCurve(cmyk, 3, num_xypoints, xypoints);
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsLightMagentaGamma", colormodel,
+ media, resolution, spec,
+ sizeof(spec))) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ cupsCMYKSetGamma(cmyk, 3, gamval, density);
+ }
+ else if ((attr = cupsFindAttr(ppd, "cupsMagentaLtDk", colormodel, media,
+ resolution, spec, sizeof(spec))) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
+ cupsCMYKSetLtDk(cmyk, 2, light, dark);
+ else
+ fprintf(stderr, "ERROR: Bad cupsMagentaLtDk value \"%s\"!\n",
+ attr->value);
+ }
+ else
+ fprintf(stderr, "WARNING: No light magenta attribute found for %s!\n",
+ spec);
+ }
+
+ /*
+ * Return the new profile...
+ */
+
+ return (cmyk);
+}
+
+
+/*
+ * 'cupsCMYKNew()' - Create a new CMYK color separation.
+ */
+
+cups_cmyk_t * /* O - New CMYK separation or NULL */
+cupsCMYKNew(int num_channels) /* I - Number of color components */
+{
+ cups_cmyk_t *cmyk; /* New color separation */
+ int i; /* Looping var */
+
+
+ /*
+ * Range-check the input...
+ */
+
+ if (num_channels < 1)
+ return (NULL);
+
+ /*
+ * Allocate memory for the separation...
+ */
+
+ if ((cmyk = calloc(1, sizeof(cups_cmyk_t))) == NULL)
+ return (NULL);
+
+ /*
+ * Allocate memory for the LUTs...
+ */
+
+ cmyk->num_channels = num_channels;
+
+ if ((cmyk->channels[0] = calloc(num_channels * 256, sizeof(short))) == NULL)
+ {
+ free(cmyk);
+ return (NULL);
+ }
+
+ for (i = 1; i < num_channels; i ++)
+ cmyk->channels[i] = cmyk->channels[0] + i * 256;
+
+ /*
+ * Fill in the LUTs with unity transitions...
+ */
+
+ for (i = 0; i < 256; i ++)
+ cmyk->black_lut[i] = i;
+
+ switch (num_channels)
+ {
+ case 1 : /* K */
+ case 2 : /* Kk */
+ for (i = 0; i < 256; i ++)
+ {
+ cmyk->channels[0][i] = CUPS_MAX_LUT * i / 255;
+ }
+ break;
+ case 3 : /* CMY */
+ for (i = 0; i < 256; i ++)
+ {
+ cmyk->channels[0][i] = CUPS_MAX_LUT * i / 255;
+ cmyk->channels[1][i] = CUPS_MAX_LUT * i / 255;
+ cmyk->channels[2][i] = CUPS_MAX_LUT * i / 255;
+ }
+ break;
+ case 4 : /* CMYK */
+ for (i = 0; i < 256; i ++)
+ {
+ cmyk->channels[0][i] = CUPS_MAX_LUT * i / 255;
+ cmyk->channels[1][i] = CUPS_MAX_LUT * i / 255;
+ cmyk->channels[2][i] = CUPS_MAX_LUT * i / 255;
+ cmyk->channels[3][i] = CUPS_MAX_LUT * i / 255;
+ }
+ break;
+ case 6 : /* CcMmYK */
+ case 7 : /* CcMmYKk */
+ for (i = 0; i < 256; i ++)
+ {
+ cmyk->channels[0][i] = CUPS_MAX_LUT * i / 255;
+ cmyk->channels[2][i] = CUPS_MAX_LUT * i / 255;
+ cmyk->channels[4][i] = CUPS_MAX_LUT * i / 255;
+ cmyk->channels[5][i] = CUPS_MAX_LUT * i / 255;
+ }
+ break;
+ }
+
+ /*
+ * Return the separation...
+ */
+
+ return (cmyk);
+}
+
+
+/*
+ * 'cupsCMYKSetBlack()' - Set the transition range for CMY to black.
+ */
+
+void
+cupsCMYKSetBlack(cups_cmyk_t *cmyk, /* I - CMYK color separation */
+ float lower, /* I - No black ink */
+ float upper) /* I - Only black ink */
+{
+ int i, /* Looping var */
+ delta, /* Difference between lower and upper */
+ ilower, /* Lower level from 0 to 255 */
+ iupper; /* Upper level from 0 to 255 */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (cmyk == NULL || lower < 0.0 || lower > 1.0 || upper < 0.0 || upper > 1.0 ||
+ lower > upper)
+ return;
+
+ /*
+ * Convert lower and upper to integers from 0 to 255...
+ */
+
+ ilower = (int)(255.0 * lower + 0.5);
+ iupper = (int)(255.0 * upper + 0.5);
+ delta = iupper - ilower;
+
+ /*
+ * Generate the CMY-only data...
+ */
+
+ for (i = 0; i < ilower; i ++)
+ {
+ cmyk->black_lut[i] = 0;
+ cmyk->color_lut[i] = i;
+ }
+
+ /*
+ * Then the transition data...
+ */
+
+ for (; i < iupper; i ++)
+ {
+ cmyk->black_lut[i] = iupper * (i - ilower) / delta;
+ cmyk->color_lut[i] = ilower - ilower * (i - ilower) / delta;
+ }
+
+ /*
+ * Then the K-only data...
+ */
+
+ for (; i < 256; i ++)
+ {
+ cmyk->black_lut[i] = i;
+ cmyk->color_lut[i] = 0;
+ }
+
+ fprintf(stderr, "DEBUG: cupsCMYKSetBlack(cmyk, lower=%.3f, upper=%.3f)\n", lower, upper);
+
+ for (i = 0; i < 256; i += 17)
+ fprintf(stderr, "DEBUG: %3d = %3dk + %3dc\n", i,
+ cmyk->black_lut[i], cmyk->color_lut[i]);
+}
+
+
+/*
+ * 'cupsCMYKSetCurve()' - Set a color transform curve using points.
+ */
+
+void
+cupsCMYKSetCurve(cups_cmyk_t *cmyk, /* I - CMYK color separation */
+ int channel, /* I - Color channel */
+ int num_xypoints,
+ /* I - Number of X,Y points */
+ const float *xypoints) /* I - X,Y points */
+{
+ int i; /* Looping var */
+ int xstart; /* Start position */
+ int xend; /* End position */
+ int xdelta; /* Difference in position */
+ int ystart; /* Start value */
+ int yend; /* End value */
+ int ydelta; /* Difference in value */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (cmyk == NULL || channel < 0 || channel >= cmyk->num_channels ||
+ num_xypoints < 1 || xypoints == NULL)
+ return;
+
+ /*
+ * Initialize the lookup table for the specified channel...
+ */
+
+ for (xstart = xend = 0, ystart = yend = 0;
+ num_xypoints > 0;
+ num_xypoints --, xypoints += 2, xstart = xend, ystart = yend)
+ {
+ xend = (int)(255.0 * xypoints[1] + 0.5);
+ yend = (int)(CUPS_MAX_LUT * xypoints[0] + 0.5);
+ xdelta = xend - xstart;
+ ydelta = yend - ystart;
+
+ for (i = xstart; i < xend; i ++)
+ cmyk->channels[channel][i] = ystart + ydelta * (i - xstart) / xdelta;
+ }
+
+ /*
+ * Initialize any trailing values to the maximum of the last data point...
+ */
+
+ for (i = xend; i < 256; i ++)
+ cmyk->channels[channel][i] = yend;
+
+ fprintf(stderr, "DEBUG: cupsCMYKSetXY(cmyk, channel=%d, num_xypoints=%d, "
+ "xypoints=[%.3f %.3f %.3f %.3f ...])\n", channel,
+ num_xypoints, xypoints[0], xypoints[1], xypoints[2], xypoints[3]);
+
+ for (i = 0; i < 256; i += 17)
+ fprintf(stderr, "DEBUG: %3d = %4d\n", i,
+ cmyk->channels[channel + 0][i]);
+}
+
+
+/*
+ * 'cupsCMYKSetGamma()' - Set a color transform curve using gamma and density.
+ */
+
+void
+cupsCMYKSetGamma(cups_cmyk_t *cmyk, /* I - CMYK color separation */
+ int channel, /* I - Ink channel */
+ float gamval, /* I - Gamma correction */
+ float density) /* I - Maximum density */
+{
+ int i; /* Looping var */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (cmyk == NULL || channel < 0 || channel >= cmyk->num_channels ||
+ gamval <= 0.0 || density <= 0.0 || density > 1.0)
+ return;
+
+ /*
+ * Initialize the lookup table for the specified channel...
+ */
+
+ for (i = 0; i < 256; i ++)
+ cmyk->channels[channel][i] = (int)(density * CUPS_MAX_LUT *
+ pow((float)i / 255.0, gamval) + 0.5);
+
+ fprintf(stderr, "DEBUG: cupsCMYKSetGamma(cmyk, channel=%d, gamval=%.3f, "
+ "density=%.3f)\n", channel, gamval, density);
+
+ for (i = 0; i < 256; i += 17)
+ fprintf(stderr, "DEBUG: %3d = %4d\n", i,
+ cmyk->channels[channel + 0][i]);
+}
+
+
+/*
+ * 'cupsCMYKSetInkLimit()' - Set the limit on the amount of ink.
+ */
+
+void
+cupsCMYKSetInkLimit(cups_cmyk_t *cmyk, /* I - CMYK color separation */
+ float limit) /* I - Limit of ink */
+{
+ if (!cmyk || limit < 0.0)
+ return;
+
+ cmyk->ink_limit = limit * CUPS_MAX_LUT;
+}
+
+
+/*
+ * 'cupsCMYKSetLtDk()' - Set light/dark ink transforms.
+ */
+
+void
+cupsCMYKSetLtDk(cups_cmyk_t *cmyk, /* I - CMYK color separation */
+ int channel, /* I - Dark ink channel (+1 for light) */
+ float light, /* I - Light ink only level */
+ float dark) /* I - Dark ink only level */
+{
+ int i, /* Looping var */
+ delta, /* Difference between lower and upper */
+ ilight, /* Light level from 0 to 255 */
+ idark; /* Dark level from 0 to 255 */
+ short lut[256]; /* Original LUT data */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (cmyk == NULL || light < 0.0 || light > 1.0 || dark < 0.0 || dark > 1.0 ||
+ light > dark || channel < 0 || channel > (cmyk->num_channels - 2))
+ return;
+
+ /*
+ * Convert lower and upper to integers from 0 to 255...
+ */
+
+ ilight = (int)(255.0 * light + 0.5);
+ idark = (int)(255.0 * dark + 0.5);
+ delta = idark - ilight;
+
+ /*
+ * Copy the dark ink LUT...
+ */
+
+ memcpy(lut, cmyk->channels[channel], sizeof(lut));
+
+ /*
+ * Generate the light-only data...
+ */
+
+ for (i = 0; i < ilight; i ++)
+ {
+ cmyk->channels[channel + 0][i] = 0;
+ cmyk->channels[channel + 1][i] = CUPS_MAX_LUT * i / ilight;
+ }
+
+ /*
+ * Then the transition data...
+ */
+
+ for (; i < idark; i ++)
+ {
+ cmyk->channels[channel + 0][i] = CUPS_MAX_LUT * idark * (i - ilight) /
+ delta / 255;
+ cmyk->channels[channel + 1][i] = CUPS_MAX_LUT - CUPS_MAX_LUT *
+ (i - ilight) / delta;
+ }
+
+ /*
+ * Then the K-only data...
+ */
+
+ for (; i < 256; i ++)
+ {
+ cmyk->channels[channel + 0][i] = CUPS_MAX_LUT * i / 255;
+ cmyk->channels[channel + 1][i] = 0;
+ }
+
+ fprintf(stderr, "DEBUG: cupsCMYKSetLtDk(cmyk, channel=%d, light=%.3f, "
+ "dark=%.3f)\n", channel, light, dark);
+
+ for (i = 0; i < 256; i += 17)
+ fprintf(stderr, "DEBUG: %3d = %4dlt + %4ddk\n", i,
+ cmyk->channels[channel + 0][i], cmyk->channels[channel + 1][i]);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/commandtoescpx.c b/driver/commandtoescpx.c
new file mode 100644
index 000000000..d11bd9bd4
--- /dev/null
+++ b/driver/commandtoescpx.c
@@ -0,0 +1,245 @@
+/*
+ * "$Id$"
+ *
+ * Advanced EPSON ESC/P command filter for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ *
+ * Contents:
+ *
+ * main() - Main entry and command processing.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include "driver.h"
+#include "data/escp.h"
+
+
+/*
+ * 'main()' - Main entry and processing of driver.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ FILE *fp; /* Command file */
+ char line[1024], /* Line from file */
+ *lineptr; /* Pointer into line */
+ int feedpage; /* Feed the page */
+ ppd_file_t *ppd; /* PPD file */
+
+
+ /*
+ * Check for valid arguments...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ /*
+ * We don't have the correct number of arguments; write an error message
+ * and return.
+ */
+
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options [file]"),
+ argv[0]);
+ return (1);
+ }
+
+ /*
+ * Open the PPD file...
+ */
+
+ if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL)
+ {
+ fputs("ERROR: Unable to open PPD file!\n", stderr);
+ return (1);
+ }
+
+ /*
+ * Open the command file as needed...
+ */
+
+ if (argc == 7)
+ {
+ if ((fp = fopen(argv[6], "r")) == NULL)
+ {
+ perror("ERROR: Unable to open command file - ");
+ return (1);
+ }
+ }
+ else
+ fp = stdin;
+
+ /*
+ * Some EPSON printers need an additional command issued at the
+ * beginning of each job to exit from USB "packet" mode...
+ */
+
+ if (ppd->model_number & ESCP_USB)
+ cupsWritePrintData("\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@", 29);
+
+ /*
+ * Reset the printer...
+ */
+
+ cupsWritePrintData("\033@", 2);
+
+ /*
+ * Enter remote mode...
+ */
+
+ cupsWritePrintData("\033(R\010\000\000REMOTE1", 13);
+ feedpage = 0;
+
+ /*
+ * Read the commands from the file and send the appropriate commands...
+ */
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Drop trailing newline...
+ */
+
+ lineptr = line + strlen(line) - 1;
+ if (*lineptr == '\n')
+ *lineptr = '\0';
+
+ /*
+ * Skip leading whitespace...
+ */
+
+ for (lineptr = line; isspace(*lineptr); lineptr ++);
+
+ /*
+ * Skip comments and blank lines...
+ */
+
+ if (*lineptr == '#' || !*lineptr)
+ continue;
+
+ /*
+ * Parse the command...
+ */
+
+ if (_cups_strncasecmp(lineptr, "Clean", 5) == 0)
+ {
+ /*
+ * Clean heads...
+ */
+
+ cupsWritePrintData("CH\002\000\000\000", 6);
+ }
+ else if (_cups_strncasecmp(lineptr, "PrintAlignmentPage", 18) == 0)
+ {
+ /*
+ * Print alignment page...
+ */
+
+ int phase;
+
+ phase = atoi(lineptr + 18);
+
+ cupsWritePrintData("DT\003\000\000", 5);
+ putchar(phase & 255);
+ putchar(phase >> 8);
+ feedpage = 1;
+ }
+ else if (_cups_strncasecmp(lineptr, "PrintSelfTestPage", 17) == 0)
+ {
+ /*
+ * Print version info and nozzle check...
+ */
+
+ cupsWritePrintData("VI\002\000\000\000", 6);
+ cupsWritePrintData("NC\002\000\000\000", 6);
+ feedpage = 1;
+ }
+ else if (_cups_strncasecmp(lineptr, "ReportLevels", 12) == 0)
+ {
+ /*
+ * Report ink levels...
+ */
+
+ cupsWritePrintData("IQ\001\000\001", 5);
+ }
+ else if (_cups_strncasecmp(lineptr, "SetAlignment", 12) == 0)
+ {
+ /*
+ * Set head alignment...
+ */
+
+ int phase, x;
+
+ if (sscanf(lineptr + 12, "%d%d", &phase, &x) != 2)
+ {
+ fprintf(stderr, "ERROR: Invalid printer command \"%s\"!\n", lineptr);
+ continue;
+ }
+
+ cupsWritePrintData("DA\004\000", 4);
+ putchar(0);
+ putchar(phase);
+ putchar(0);
+ putchar(x);
+ cupsWritePrintData("SV\000\000", 4);
+ }
+ else
+ fprintf(stderr, "ERROR: Invalid printer command \"%s\"!\n", lineptr);
+ }
+
+ /*
+ * Exit remote mode...
+ */
+
+ cupsWritePrintData("\033\000\000\000", 4);
+
+ /*
+ * Eject the page as needed...
+ */
+
+ if (feedpage)
+ {
+ fputs("PAGE: 1 1\n", stderr);
+
+ putchar(13);
+ putchar(10);
+ putchar(12);
+ }
+
+ /*
+ * Reset the printer...
+ */
+
+ cupsWritePrintData("\033@", 2);
+
+ /*
+ * Close the command file and return...
+ */
+
+ ppdClose(ppd);
+
+ if (fp != stdin)
+ fclose(fp);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/commandtopclx.c b/driver/commandtopclx.c
new file mode 100644
index 000000000..1ef53aab4
--- /dev/null
+++ b/driver/commandtopclx.c
@@ -0,0 +1,172 @@
+/*
+ * "$Id$"
+ *
+ * Advanced PCL command filter for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ *
+ * Contents:
+ *
+ * main() - Main entry and command processing.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include "driver.h"
+#include "data/pcl.h"
+
+
+/*
+ * 'main()' - Main entry and processing of driver.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ FILE *fp; /* Command file */
+ char line[1024], /* Line from file */
+ *lineptr; /* Pointer into line */
+ int feedpage; /* Feed the page */
+ ppd_file_t *ppd; /* PPD file */
+
+
+ /*
+ * Check for valid arguments...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ /*
+ * We don't have the correct number of arguments; write an error message
+ * and return.
+ */
+
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options [file]"),
+ argv[0]);
+ return (1);
+ }
+
+ /*
+ * Open the PPD file...
+ */
+
+ if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL)
+ {
+ fputs("ERROR: Unable to open PPD file!\n", stderr);
+ return (1);
+ }
+
+ /*
+ * Open the command file as needed...
+ */
+
+ if (argc == 7)
+ {
+ if ((fp = fopen(argv[6], "r")) == NULL)
+ {
+ perror("ERROR: Unable to open command file - ");
+ return (1);
+ }
+ }
+ else
+ fp = stdin;
+
+ /*
+ * Reset the printer...
+ */
+
+ cupsWritePrintData("\033E", 2);
+
+ /*
+ * Read the commands from the file and send the appropriate commands...
+ */
+
+ feedpage = 0;
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Drop trailing newline...
+ */
+
+ lineptr = line + strlen(line) - 1;
+ if (*lineptr == '\n')
+ *lineptr = '\0';
+
+ /*
+ * Skip leading whitespace...
+ */
+
+ for (lineptr = line; isspace(*lineptr); lineptr ++);
+
+ /*
+ * Skip comments and blank lines...
+ */
+
+ if (*lineptr == '#' || !*lineptr)
+ continue;
+
+ /*
+ * Parse the command...
+ */
+
+ if (_cups_strncasecmp(lineptr, "Clean", 5) == 0 &&
+ (ppd->model_number & PCL_INKJET))
+ {
+ /*
+ * Clean heads...
+ */
+
+ cupsWritePrintData("\033&b16WPML \004\000\006\001\004\001\005\001"
+ "\001\004\001\144", 22);
+ }
+ else
+ fprintf(stderr, "ERROR: Invalid printer command \"%s\"!\n", lineptr);
+ }
+
+ /*
+ * Eject the page as needed...
+ */
+
+ if (feedpage)
+ {
+ fputs("PAGE: 1 1\n", stderr);
+
+ putchar(12);
+ }
+
+ /*
+ * Reset the printer...
+ */
+
+ cupsWritePrintData("\033E", 2);
+
+ /*
+ * Close the command file and return...
+ */
+
+ ppdClose(ppd);
+
+ if (fp != stdin)
+ fclose(fp);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/dither.c b/driver/dither.c
new file mode 100644
index 000000000..dfefed7c1
--- /dev/null
+++ b/driver/dither.c
@@ -0,0 +1,306 @@
+/*
+ * "$Id$"
+ *
+ * Dithering routines for CUPS.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsDitherDelete() - Free a dithering buffer.
+ * cupsDitherLine() - Dither a line of pixels...
+ * cupsDitherNew() - Create a dithering buffer.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "driver.h"
+#include <config.h>
+
+
+/*
+ * 'cupsDitherDelete()' - Free a dithering buffer.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+
+void
+cupsDitherDelete(cups_dither_t *d) /* I - Dithering buffer */
+{
+ if (d != NULL)
+ free(d);
+}
+
+
+/*
+ * 'cupsDitherLine()' - Dither a line of pixels...
+ */
+
+void
+cupsDitherLine(cups_dither_t *d, /* I - Dither data */
+ const cups_lut_t *lut, /* I - Lookup table */
+ const short *data, /* I - Separation data */
+ int num_channels,
+ /* I - Number of components */
+ unsigned char *p) /* O - Pixels */
+{
+ register int x, /* Horizontal position in line... */
+ pixel, /* Current adjusted pixel... */
+ e, /* Current error */
+ e0,e1,e2; /* Error values */
+ register int errval0, /* First half of error value */
+ errval1, /* Second half of error value */
+ errbase, /* Base multiplier */
+ errbase0, /* Base multiplier for large values */
+ errbase1, /* Base multiplier for small values */
+ errrange; /* Range of random multiplier */
+ register int *p0, /* Error buffer pointers... */
+ *p1;
+ static char logtable[16384]; /* Error magnitude for randomness */
+ static char loginit = 0; /* Has the table been initialized? */
+
+
+ if (!loginit)
+ {
+ /*
+ * Initialize a logarithmic table for the magnitude of randomness
+ * that is introduced.
+ */
+
+ loginit = 1;
+
+ logtable[0] = 0;
+ for (x = 1; x < 2049; x ++)
+ logtable[x] = (int)(log(x / 16.0) / log(2.0) + 1.0);
+ for (; x < 16384; x ++)
+ logtable[x] = logtable[2049];
+ }
+
+ if (d->row == 0)
+ {
+ /*
+ * Dither from left to right:
+ *
+ * e0 == p0[0]
+ * e1 e2 == p1[-1] p1[0]
+ */
+
+ p0 = d->errors + 2;
+ p1 = d->errors + 2 + d->width + 4;
+ e0 = p0[0];
+ e1 = 0;
+ e2 = 0;
+
+ /*
+ * Error diffuse each output pixel...
+ */
+
+ for (x = d->width;
+ x > 0;
+ x --, p0 ++, p1 ++, p ++, data += num_channels)
+ {
+ /*
+ * Skip blank pixels...
+ */
+
+ if (*data == 0)
+ {
+ *p = 0;
+ e0 = p0[1];
+ p1[-1] = e1;
+ e1 = e2;
+ e2 = 0;
+ continue;
+ }
+
+ /*
+ * Compute the net pixel brightness and brightness error. Set a dot
+ * if necessary...
+ */
+
+ pixel = lut[*data].intensity + e0 / 128;
+
+ if (pixel > CUPS_MAX_LUT)
+ pixel = CUPS_MAX_LUT;
+ else if (pixel < 0)
+ pixel = 0;
+
+ *p = lut[pixel].pixel;
+ e = lut[pixel].error;
+
+ /*
+ * Set the randomness factor...
+ */
+
+ if (e > 0)
+ errrange = logtable[e];
+ else
+ errrange = logtable[-e];
+
+ errbase = 8 - errrange;
+ errrange = errrange * 2 + 1;
+
+ /*
+ * Randomize the error value.
+ */
+
+ if (errrange > 1)
+ {
+ errbase0 = errbase + (CUPS_RAND() % errrange);
+ errbase1 = errbase + (CUPS_RAND() % errrange);
+ }
+ else
+ errbase0 = errbase1 = errbase;
+
+ /*
+ * X 7/16 = X e0
+ * 3/16 5/16 1/16 = e1 e2
+ */
+
+ errval0 = errbase0 * e;
+ errval1 = (16 - errbase0) * e;
+ e0 = p0[1] + 7 * errval0;
+ e1 = e2 + 5 * errval1;
+
+ errval0 = errbase1 * e;
+ errval1 = (16 - errbase1) * e;
+ e2 = errval0;
+ p1[-1] = e1 + 3 * errval1;
+ }
+ }
+ else
+ {
+ /*
+ * Dither from right to left:
+ *
+ * e0 == p0[0]
+ * e2 e1 == p1[0] p1[1]
+ */
+
+ p0 = d->errors + d->width + 1 + d->width + 4;
+ p1 = d->errors + d->width + 1;
+ p += d->width - 1;
+ data += num_channels * (d->width - 1);
+ e0 = p0[0];
+ e1 = 0;
+ e2 = 0;
+
+ /*
+ * Error diffuse each output pixel...
+ */
+
+ for (x = d->width;
+ x > 0;
+ x --, p0 --, p1 --, p --, data -= num_channels)
+ {
+ /*
+ * Skip blank pixels...
+ */
+
+ if (*data == 0)
+ {
+ *p = 0;
+ e0 = p0[-1];
+ p1[1] = e1;
+ e1 = e2;
+ e2 = 0;
+ continue;
+ }
+
+ /*
+ * Compute the net pixel brightness and brightness error. Set a dot
+ * if necessary...
+ */
+
+ pixel = lut[*data].intensity + e0 / 128;
+
+ if (pixel > CUPS_MAX_LUT)
+ pixel = CUPS_MAX_LUT;
+ else if (pixel < 0)
+ pixel = 0;
+
+ *p = lut[pixel].pixel;
+ e = lut[pixel].error;
+
+ /*
+ * Set the randomness factor...
+ */
+
+ if (e > 0)
+ errrange = logtable[e];
+ else
+ errrange = logtable[-e];
+
+ errbase = 8 - errrange;
+ errrange = errrange * 2 + 1;
+
+ /*
+ * Randomize the error value.
+ */
+
+ if (errrange > 1)
+ {
+ errbase0 = errbase + (CUPS_RAND() % errrange);
+ errbase1 = errbase + (CUPS_RAND() % errrange);
+ }
+ else
+ errbase0 = errbase1 = errbase;
+
+ /*
+ * X 7/16 = X e0
+ * 3/16 5/16 1/16 = e1 e2
+ */
+
+ errval0 = errbase0 * e;
+ errval1 = (16 - errbase0) * e;
+ e0 = p0[-1] + 7 * errval0;
+ e1 = e2 + 5 * errval1;
+
+ errval0 = errbase1 * e;
+ errval1 = (16 - errbase1) * e;
+ e2 = errval0;
+ p1[1] = e1 + 3 * errval1;
+ }
+ }
+
+ /*
+ * Update to the next row...
+ */
+
+ d->row = 1 - d->row;
+}
+
+
+/*
+ * 'cupsDitherNew()' - Create an error-diffusion dithering buffer.
+ */
+
+cups_dither_t * /* O - New state array */
+cupsDitherNew(int width) /* I - Width of output in pixels */
+{
+ cups_dither_t *d; /* New dithering buffer */
+
+
+ if ((d = (cups_dither_t *)calloc(1, sizeof(cups_dither_t) +
+ 2 * (width + 4) *
+ sizeof(int))) == NULL)
+ return (NULL);
+
+ d->width = width;
+
+ return (d);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/driver.h b/driver/driver.h
new file mode 100644
index 000000000..ed4eab96d
--- /dev/null
+++ b/driver/driver.h
@@ -0,0 +1,249 @@
+/*
+ * "$Id$"
+ *
+ * Printer driver utilities header file for CUPS.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPS_DRIVER_H_
+# define _CUPS_DRIVER_H_
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+/*
+ * Include necessary headers...
+ */
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <time.h>
+# include <math.h>
+
+# if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+# else
+# include <unistd.h>
+# include <fcntl.h>
+# endif /* WIN32 || __EMX__ */
+
+# include <cups/cups.h>
+# include <cups/raster.h>
+
+
+/*
+ * Common macros...
+ */
+
+# ifndef min
+# define min(a,b) ((a) < (b) ? (a) : (b))
+# define max(a,b) ((a) > (b) ? (a) : (b))
+# endif /* !min */
+
+
+/*
+ * Constants...
+ */
+
+#define CUPS_MAX_CHAN 15 /* Maximum number of color components */
+#define CUPS_MAX_LUT 4095 /* Maximum LUT value */
+#define CUPS_MAX_RGB 4 /* Maximum number of sRGB components */
+
+
+/*
+ * Types/structures for the various routines.
+ */
+
+typedef struct cups_lut_s /**** Lookup Table for Dithering ****/
+{
+ short intensity; /* Adjusted intensity */
+ short pixel; /* Output pixel value */
+ int error; /* Error from desired value */
+} cups_lut_t;
+
+typedef struct cups_dither_s /**** Dithering State ****/
+{
+ int width; /* Width of buffer */
+ int row; /* Current row */
+ int errors[96]; /* Error values */
+} cups_dither_t;
+
+typedef struct cups_sample_s /**** Color sample point ****/
+{
+ unsigned char rgb[3]; /* sRGB values */
+ unsigned char colors[CUPS_MAX_RGB]; /* Color values */
+} cups_sample_t;
+
+typedef struct cups_rgb_s /**** Color separation lookup table ****/
+{
+ int cube_size; /* Size of color cube (2-N) on a side */
+ int num_channels; /* Number of colors per sample */
+ unsigned char ****colors; /* 4-D array of sample values */
+ int cube_index[256]; /* Index into cube for a given sRGB value */
+ int cube_mult[256]; /* Multiplier value for a given sRGB value */
+ int cache_init; /* Are cached values initialized? */
+ unsigned char black[CUPS_MAX_RGB]; /* Cached black (sRGB = 0,0,0) */
+ unsigned char white[CUPS_MAX_RGB]; /* Cached white (sRGB = 255,255,255) */
+} cups_rgb_t;
+
+typedef struct cups_cmyk_s /**** Simple CMYK lookup table ****/
+{
+ unsigned char black_lut[256]; /* Black generation LUT */
+ unsigned char color_lut[256]; /* Color removal LUT */
+ int ink_limit; /* Ink limit */
+ int num_channels; /* Number of components */
+ short *channels[CUPS_MAX_CHAN];
+ /* Lookup tables */
+} cups_cmyk_t;
+
+
+/*
+ * Globals...
+ */
+
+extern const unsigned char
+ cups_srgb_lut[256];
+ /* sRGB gamma lookup table */
+extern const unsigned char
+ cups_scmy_lut[256];
+ /* sRGB gamma lookup table (inverted) */
+
+
+/*
+ * Prototypes...
+ */
+
+/*
+ * Attribute function...
+ */
+
+extern ppd_attr_t *cupsFindAttr(ppd_file_t *ppd, const char *name,
+ const char *colormodel,
+ const char *media,
+ const char *resolution,
+ char *spec, int specsize);
+
+/*
+ * Byte checking functions...
+ */
+
+extern int cupsCheckBytes(const unsigned char *, int);
+extern int cupsCheckValue(const unsigned char *, int,
+ const unsigned char);
+
+/*
+ * Dithering functions...
+ */
+
+extern void cupsDitherLine(cups_dither_t *d, const cups_lut_t *lut,
+ const short *data, int num_channels,
+ unsigned char *p);
+extern cups_dither_t *cupsDitherNew(int width);
+extern void cupsDitherDelete(cups_dither_t *);
+
+/*
+ * Lookup table functions for dithering...
+ */
+
+extern cups_lut_t *cupsLutNew(int num_vals, const float *vals);
+extern void cupsLutDelete(cups_lut_t *lut);
+extern cups_lut_t *cupsLutLoad(ppd_file_t *ppd,
+ const char *colormodel,
+ const char *media,
+ const char *resolution,
+ const char *ink);
+
+
+/*
+ * Bit packing functions...
+ */
+
+extern void cupsPackHorizontal(const unsigned char *,
+ unsigned char *, int,
+ const unsigned char, const int);
+extern void cupsPackHorizontal2(const unsigned char *,
+ unsigned char *, int, const int);
+extern void cupsPackHorizontalBit(const unsigned char *,
+ unsigned char *, int,
+ const unsigned char,
+ const unsigned char);
+extern void cupsPackVertical(const unsigned char *, unsigned char *,
+ int, const unsigned char, const int);
+
+/*
+ * Color separation functions...
+ */
+
+extern void cupsRGBDelete(cups_rgb_t *rgb);
+extern void cupsRGBDoGray(cups_rgb_t *rgb,
+ const unsigned char *input,
+ unsigned char *output, int num_pixels);
+extern void cupsRGBDoRGB(cups_rgb_t *rgb,
+ const unsigned char *input,
+ unsigned char *output, int num_pixels);
+extern cups_rgb_t *cupsRGBLoad(ppd_file_t *ppd,
+ const char *colormodel,
+ const char *media,
+ const char *resolution);
+extern cups_rgb_t *cupsRGBNew(int num_samples, cups_sample_t *samples,
+ int cube_size, int num_channels);
+
+/*
+ * CMYK separation functions...
+ */
+
+extern cups_cmyk_t *cupsCMYKNew(int num_channels);
+extern void cupsCMYKDelete(cups_cmyk_t *cmyk);
+extern void cupsCMYKDoBlack(const cups_cmyk_t *cmyk,
+ const unsigned char *input,
+ short *output, int num_pixels);
+extern void cupsCMYKDoCMYK(const cups_cmyk_t *cmyk,
+ const unsigned char *input,
+ short *output, int num_pixels);
+extern void cupsCMYKDoGray(const cups_cmyk_t *cmyk,
+ const unsigned char *input,
+ short *output, int num_pixels);
+extern void cupsCMYKDoRGB(const cups_cmyk_t *cmyk,
+ const unsigned char *input,
+ short *output, int num_pixels);
+extern cups_cmyk_t *cupsCMYKLoad(ppd_file_t *ppd,
+ const char *colormodel,
+ const char *media,
+ const char *resolution);
+extern void cupsCMYKSetBlack(cups_cmyk_t *cmyk,
+ float lower, float upper);
+extern void cupsCMYKSetCurve(cups_cmyk_t *cmyk, int channel,
+ int num_xypoints,
+ const float *xypoints);
+extern void cupsCMYKSetGamma(cups_cmyk_t *cmyk, int channel,
+ float gamval, float density);
+extern void cupsCMYKSetInkLimit(cups_cmyk_t *cmyk, float limit);
+extern void cupsCMYKSetLtDk(cups_cmyk_t *cmyk, int channel,
+ float light, float dark);
+
+
+/*
+ * Convenience macro for writing print data...
+ */
+
+# define cupsWritePrintData(s,n) fwrite((s), 1, (n), stdout)
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_DRIVER_H_ */
+
+/*
+ * End of "$Id$".
+ */
+
diff --git a/driver/image.pgm b/driver/image.pgm
new file mode 100644
index 000000000..c0b7a22f7
--- /dev/null
+++ b/driver/image.pgm
Binary files differ
diff --git a/driver/image.ppm b/driver/image.ppm
new file mode 100644
index 000000000..3823fe48b
--- /dev/null
+++ b/driver/image.ppm
Binary files differ
diff --git a/driver/libcupsdriver.exp b/driver/libcupsdriver.exp
new file mode 100644
index 000000000..fff6506fe
--- /dev/null
+++ b/driver/libcupsdriver.exp
@@ -0,0 +1,30 @@
+_cupsCMYKDelete
+_cupsCMYKDoBlack
+_cupsCMYKDoCMYK
+_cupsCMYKDoGray
+_cupsCMYKDoRGB
+_cupsCMYKLoad
+_cupsCMYKNew
+_cupsCMYKSetBlack
+_cupsCMYKSetCurve
+_cupsCMYKSetGamma
+_cupsCMYKSetInkLimit
+_cupsCMYKSetLtDk
+_cupsCheckBytes
+_cupsCheckValue
+_cupsDitherDelete
+_cupsDitherLine
+_cupsDitherNew
+_cupsFindAttr
+_cupsLutDelete
+_cupsLutLoad
+_cupsLutNew
+_cupsPackHorizontal
+_cupsPackHorizontal2
+_cupsPackHorizontalBit
+_cupsPackVertical
+_cupsRGBDelete
+_cupsRGBDoGray
+_cupsRGBDoRGB
+_cupsRGBLoad
+_cupsRGBNew
diff --git a/driver/lut.c b/driver/lut.c
new file mode 100644
index 000000000..7ca7e4350
--- /dev/null
+++ b/driver/lut.c
@@ -0,0 +1,202 @@
+/*
+ * "$Id$"
+ *
+ * Lookup table routines for CUPS.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsLutDelete() - Free the memory used by a lookup table.
+ * cupsLutLoad() - Load a LUT from a PPD file.
+ * cupsLutNew() - Make a lookup table from a list of pixel values.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "driver.h"
+#include <math.h>
+
+
+/*
+ * 'cupsLutDelete()' - Free the memory used by a lookup table.
+ */
+
+void
+cupsLutDelete(cups_lut_t *lut) /* I - Lookup table to free */
+{
+ if (lut != NULL)
+ free(lut);
+}
+
+
+/*
+ * 'cupsLutLoad()' - Load a LUT from a PPD file.
+ */
+
+cups_lut_t * /* O - New lookup table */
+cupsLutLoad(ppd_file_t *ppd, /* I - PPD file */
+ const char *colormodel, /* I - Color model */
+ const char *media, /* I - Media type */
+ const char *resolution, /* I - Resolution */
+ const char *ink) /* I - Ink name */
+{
+ char name[PPD_MAX_NAME], /* Attribute name */
+ spec[PPD_MAX_NAME]; /* Attribute spec */
+ ppd_attr_t *attr; /* Attribute */
+ int nvals; /* Number of values */
+ float vals[4]; /* Values */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !colormodel || !media || !resolution || !ink)
+ return (NULL);
+
+ /*
+ * Try to find the LUT values...
+ */
+
+ snprintf(name, sizeof(name), "cups%sDither", ink);
+
+ if ((attr = cupsFindAttr(ppd, name, colormodel, media, resolution, spec,
+ sizeof(spec))) == NULL)
+ attr = cupsFindAttr(ppd, "cupsAllDither", colormodel, media,
+ resolution, spec, sizeof(spec));
+
+ if (!attr)
+ return (NULL);
+
+ vals[0] = 0.0;
+ vals[1] = 0.0;
+ vals[2] = 0.0;
+ vals[3] = 0.0;
+ nvals = sscanf(attr->value, "%f%f%f", vals + 1, vals + 2, vals + 3) + 1;
+
+ fprintf(stderr, "DEBUG: Loaded LUT %s from PPD with values [%.3f %.3f %.3f %.3f]\n",
+ name, vals[0], vals[1], vals[2], vals[3]);
+
+ return (cupsLutNew(nvals, vals));
+}
+
+
+/*
+ * 'cupsLutNew()' - Make a lookup table from a list of pixel values.
+ *
+ * Returns a pointer to the lookup table on success, NULL on failure.
+ */
+
+cups_lut_t * /* O - New lookup table */
+cupsLutNew(int num_values, /* I - Number of values */
+ const float *values) /* I - Lookup table values */
+{
+ int pixel; /* Pixel value */
+ cups_lut_t *lut; /* Lookup table */
+ int start, /* Start value */
+ end, /* End value */
+ maxval; /* Maximum value */
+
+
+ /*
+ * Range check...
+ */
+
+ if (!num_values || !values)
+ return (NULL);
+
+ /*
+ * Allocate memory for the lookup table...
+ */
+
+ if ((lut = (cups_lut_t *)calloc((CUPS_MAX_LUT + 1),
+ sizeof(cups_lut_t))) == NULL)
+ return (NULL);
+
+ /*
+ * Generate the dither lookup table. The pixel values are roughly
+ * defined by a piecewise linear curve that has an intensity value
+ * at each output pixel. This isn't perfectly accurate, but it's
+ * close enough for jazz.
+ */
+
+ maxval = CUPS_MAX_LUT / values[num_values - 1];
+
+ for (start = 0; start <= CUPS_MAX_LUT; start ++)
+ lut[start].intensity = start * maxval / CUPS_MAX_LUT;
+
+ for (pixel = 0; pixel < num_values; pixel ++)
+ {
+ /*
+ * Select start and end values for this pixel...
+ */
+
+ if (pixel == 0)
+ start = 0;
+ else
+ start = (int)(0.5 * maxval * (values[pixel - 1] +
+ values[pixel])) + 1;
+
+ if (start < 0)
+ start = 0;
+ else if (start > CUPS_MAX_LUT)
+ start = CUPS_MAX_LUT;
+
+ if (pixel == (num_values - 1))
+ end = CUPS_MAX_LUT;
+ else
+ end = (int)(0.5 * maxval * (values[pixel] + values[pixel + 1]));
+
+ if (end < 0)
+ end = 0;
+ else if (end > CUPS_MAX_LUT)
+ end = CUPS_MAX_LUT;
+
+ if (start == end)
+ break;
+
+ /*
+ * Generate lookup values and errors for each pixel.
+ */
+
+ while (start <= end)
+ {
+ lut[start].pixel = pixel;
+ if (start == 0)
+ lut[0].error = 0;
+ else
+ lut[start].error = start - maxval * values[pixel];
+
+ start ++;
+ }
+ }
+
+ /*
+ * Show the lookup table...
+ */
+
+ for (start = 0; start <= CUPS_MAX_LUT; start += CUPS_MAX_LUT / 15)
+ fprintf(stderr, "DEBUG: %d = %d/%d/%d\n", start, lut[start].intensity,
+ lut[start].pixel, lut[start].error);
+
+ /*
+ * Return the lookup table...
+ */
+
+ return (lut);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/pack.c b/driver/pack.c
new file mode 100644
index 000000000..d9d01d16b
--- /dev/null
+++ b/driver/pack.c
@@ -0,0 +1,307 @@
+/*
+ * "$Id$"
+ *
+ * Bit packing routines for CUPS.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsPackHorizontal() - Pack pixels horizontally...
+ * cupsPackHorizontal2() - Pack 2-bit pixels horizontally...
+ * cupsPackHorizontalBit() - Pack pixels horizontally by bit...
+ * cupsPackVertical() - Pack pixels vertically...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "driver.h"
+
+
+/*
+ * 'cupsPackHorizontal()' - Pack pixels horizontally...
+ */
+
+void
+cupsPackHorizontal(const unsigned char *ipixels,/* I - Input pixels */
+ unsigned char *obytes, /* O - Output bytes */
+ int width, /* I - Number of pixels */
+ const unsigned char clearto, /* I - Initial value of bytes */
+ const int step) /* I - Step value between pixels */
+{
+ register unsigned char b; /* Current byte */
+
+
+ /*
+ * Do whole bytes first...
+ */
+
+ while (width > 7)
+ {
+ b = clearto;
+
+ if (*ipixels)
+ b ^= 0x80;
+ ipixels += step;
+ if (*ipixels)
+ b ^= 0x40;
+ ipixels += step;
+ if (*ipixels)
+ b ^= 0x20;
+ ipixels += step;
+ if (*ipixels)
+ b ^= 0x10;
+ ipixels += step;
+ if (*ipixels)
+ b ^= 0x08;
+ ipixels += step;
+ if (*ipixels)
+ b ^= 0x04;
+ ipixels += step;
+ if (*ipixels)
+ b ^= 0x02;
+ ipixels += step;
+ if (*ipixels)
+ b ^= 0x01;
+ ipixels += step;
+
+ *obytes++ = b;
+
+ width -= 8;
+ }
+
+ /*
+ * Then do the last N bytes (N < 8)...
+ */
+
+ b = clearto;
+
+ switch (width)
+ {
+ case 7 :
+ if (ipixels[6 * step])
+ b ^= 0x02;
+ case 6 :
+ if (ipixels[5 * step])
+ b ^= 0x04;
+ case 5 :
+ if (ipixels[4 * step])
+ b ^= 0x08;
+ case 4 :
+ if (ipixels[3 * step])
+ b ^= 0x10;
+ case 3 :
+ if (ipixels[2 * step])
+ b ^= 0x20;
+ case 2 :
+ if (ipixels[1 * step])
+ b ^= 0x40;
+ case 1 :
+ if (ipixels[0])
+ b ^= 0x80;
+ *obytes = b;
+ break;
+ }
+}
+
+
+/*
+ * 'cupsPackHorizontal2()' - Pack 2-bit pixels horizontally...
+ */
+
+void
+cupsPackHorizontal2(const unsigned char *ipixels, /* I - Input pixels */
+ unsigned char *obytes, /* O - Output bytes */
+ int width, /* I - Number of pixels */
+ const int step) /* I - Stepping value */
+{
+ register unsigned char b; /* Current byte */
+
+
+ /*
+ * Do whole bytes first...
+ */
+
+ while (width > 3)
+ {
+ b = *ipixels;
+ ipixels += step;
+ b = (b << 2) | *ipixels;
+ ipixels += step;
+ b = (b << 2) | *ipixels;
+ ipixels += step;
+ b = (b << 2) | *ipixels;
+ ipixels += step;
+
+ *obytes++ = b;
+
+ width -= 4;
+ }
+
+ /*
+ * Then do the last N bytes (N < 4)...
+ */
+
+ b = 0;
+
+ switch (width)
+ {
+ case 3 :
+ b = ipixels[2 * step];
+ case 2 :
+ b = (b << 2) | ipixels[step];
+ case 1 :
+ b = (b << 2) | ipixels[0];
+ *obytes = b << (8 - 2 * width);
+ break;
+ }
+}
+
+
+/*
+ * 'cupsPackHorizontalBit()' - Pack pixels horizontally by bit...
+ */
+
+void
+cupsPackHorizontalBit(const unsigned char *ipixels, /* I - Input pixels */
+ unsigned char *obytes, /* O - Output bytes */
+ int width, /* I - Number of pixels */
+ const unsigned char clearto, /* I - Initial value of bytes */
+ const unsigned char bit) /* I - Bit to check */
+{
+ register unsigned char b; /* Current byte */
+
+
+ /*
+ * Do whole bytes first...
+ */
+
+ while (width > 7)
+ {
+ b = clearto;
+
+ if (*ipixels++ & bit)
+ b ^= 0x80;
+ if (*ipixels++ & bit)
+ b ^= 0x40;
+ if (*ipixels++ & bit)
+ b ^= 0x20;
+ if (*ipixels++ & bit)
+ b ^= 0x10;
+ if (*ipixels++ & bit)
+ b ^= 0x08;
+ if (*ipixels++ & bit)
+ b ^= 0x04;
+ if (*ipixels++ & bit)
+ b ^= 0x02;
+ if (*ipixels++ & bit)
+ b ^= 0x01;
+
+ *obytes++ = b;
+
+ width -= 8;
+ }
+
+ /*
+ * Then do the last N bytes (N < 8)...
+ */
+
+ b = clearto;
+
+ switch (width)
+ {
+ case 7 :
+ if (ipixels[6] & bit)
+ b ^= 0x02;
+ case 6 :
+ if (ipixels[5] & bit)
+ b ^= 0x04;
+ case 5 :
+ if (ipixels[4] & bit)
+ b ^= 0x08;
+ case 4 :
+ if (ipixels[3] & bit)
+ b ^= 0x10;
+ case 3 :
+ if (ipixels[2] & bit)
+ b ^= 0x20;
+ case 2 :
+ if (ipixels[1] & bit)
+ b ^= 0x40;
+ case 1 :
+ if (ipixels[0] & bit)
+ b ^= 0x80;
+ *obytes = b;
+ break;
+ }
+}
+
+
+/*
+ * 'cupsPackVertical()' - Pack pixels vertically...
+ */
+
+void
+cupsPackVertical(const unsigned char *ipixels, /* I - Input pixels */
+ unsigned char *obytes, /* O - Output bytes */
+ int width, /* I - Number of input pixels */
+ const unsigned char bit, /* I - Output bit */
+ const int step) /* I - Number of bytes between columns */
+{
+ /*
+ * Loop through the entire array...
+ */
+
+ while (width > 7)
+ {
+ if (*ipixels++)
+ *obytes ^= bit;
+ obytes += step;
+ if (*ipixels++)
+ *obytes ^= bit;
+ obytes += step;
+ if (*ipixels++)
+ *obytes ^= bit;
+ obytes += step;
+ if (*ipixels++)
+ *obytes ^= bit;
+ obytes += step;
+ if (*ipixels++)
+ *obytes ^= bit;
+ obytes += step;
+ if (*ipixels++)
+ *obytes ^= bit;
+ obytes += step;
+ if (*ipixels++)
+ *obytes ^= bit;
+ obytes += step;
+ if (*ipixels++)
+ *obytes ^= bit;
+ obytes += step;
+
+ width -= 8;
+ }
+
+ while (width > 0)
+ {
+ if (*ipixels++)
+ *obytes ^= bit;
+
+ obytes += step;
+ width --;
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/pcl-common.c b/driver/pcl-common.c
new file mode 100644
index 000000000..427879338
--- /dev/null
+++ b/driver/pcl-common.c
@@ -0,0 +1,272 @@
+/*
+ * "$Id$"
+ *
+ * Common PCL functions for CUPS.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * pcl_set_media_size() - Set media size using the page size command.
+ * pjl_write() - Write a PJL command string, performing
+ * substitutions as needed.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "driver.h"
+#include "pcl-common.h"
+#include <math.h>
+
+
+/*
+ * 'pcl_set_media_size()' - Set media size using the page size command.
+ */
+
+void
+pcl_set_media_size(ppd_file_t *ppd, /* I - PPD file */
+ float width, /* I - Width of page */
+ float length) /* I - Length of page */
+{
+ (void)width;
+
+ printf("\033&l0O"); /* Set portrait orientation */
+
+ if (ppd->model_number & PCL_PAPER_SIZE)
+ switch ((int)(length + 0.5f))
+ {
+ case 419 : /* Postcard */
+ printf("\033&l71A"); /* Set page size */
+ break;
+
+ case 540 : /* Monarch Envelope */
+ printf("\033&l80A"); /* Set page size */
+ break;
+
+ case 567 : /* Double Postcard */
+ printf("\033&l72A"); /* Set page size */
+ break;
+
+ case 595 : /* A5 */
+ printf("\033&l25A"); /* Set page size */
+ break;
+
+ case 612 : /* Statement */
+ printf("\033&l5A"); /* Set page size */
+ break;
+
+ case 624 : /* DL Envelope */
+ printf("\033&l90A"); /* Set page size */
+ break;
+
+ case 649 : /* C5 Envelope */
+ printf("\033&l91A"); /* Set page size */
+ break;
+
+ case 684 : /* COM-10 Envelope */
+ printf("\033&l81A"); /* Set page size */
+ break;
+
+ case 709 : /* B5 Envelope */
+ printf("\033&l100A"); /* Set page size */
+ break;
+
+ case 729 : /* B5 */
+ printf("\033&l45A"); /* Set page size */
+ break;
+
+ case 756 : /* Executive */
+ printf("\033&l1A"); /* Set page size */
+ break;
+
+ case 792 : /* Letter */
+ printf("\033&l2A"); /* Set page size */
+ break;
+
+ case 842 : /* A4 */
+ printf("\033&l26A"); /* Set page size */
+ break;
+
+ case 936 : /* Foolscap */
+ printf("\033&l23A"); /* Set page size */
+ break;
+
+ case 1008 : /* Legal */
+ printf("\033&l3A"); /* Set page size */
+ break;
+
+ case 1032 : /* B4 */
+ printf("\033&l46A"); /* Set page size */
+ break;
+
+ case 1191 : /* A3 */
+ printf("\033&l27A"); /* Set page size */
+ break;
+
+ case 1224 : /* Tabloid */
+ printf("\033&l6A"); /* Set page size */
+ break;
+
+ default :
+ printf("\033&l101A"); /* Set page size */
+ printf("\033&l6D\033&k12H"); /* Set 6 LPI, 10 CPI */
+ printf("\033&l%.2fP", length / 12.0);
+ /* Set page length */
+ printf("\033&l%.0fF", length / 12.0);
+ /* Set text length to page */
+ break;
+ }
+ else
+ {
+ printf("\033&l6D\033&k12H"); /* Set 6 LPI, 10 CPI */
+ printf("\033&l%.2fP", length / 12.0);
+ /* Set page length */
+ printf("\033&l%.0fF", length / 12.0);
+ /* Set text length to page */
+ }
+
+ printf("\033&l0L"); /* Turn off perforation skip */
+ printf("\033&l0E"); /* Reset top margin to 0 */
+}
+
+
+/*
+ * 'pjl_write()' - Write a PJL command string, performing substitutions as needed.
+ */
+
+void
+pjl_write(ppd_file_t *ppd, /* I - PPD file */
+ const char *format, /* I - Format string */
+ const char *value, /* I - Value for %s */
+ int job_id, /* I - Job ID */
+ const char *user, /* I - Username */
+ const char *title, /* I - Title */
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ const char *optval; /* Option value */
+ char match[255], /* Match string */
+ *mptr; /* Pointer into match string */
+
+
+ if (!format)
+ return;
+
+ while (*format)
+ {
+ if (*format == '%')
+ {
+ /*
+ * Perform substitution...
+ */
+
+ format ++;
+ switch (*format)
+ {
+ case 'b' : /* job-billing */
+ if ((optval = cupsGetOption("job-billing", num_options,
+ options)) != NULL)
+ fputs(optval, stdout);
+ break;
+
+ case 'h' : /* job-originating-host-name */
+ if ((optval = cupsGetOption("job-originating-host-name",
+ num_options, options)) != NULL)
+ fputs(optval, stdout);
+ break;
+
+ case 'j' : /* job-id */
+ printf("%d", job_id);
+ break;
+
+ case 'n' : /* CR + LF */
+ putchar('\r');
+ putchar('\n');
+ break;
+
+ case 'q' : /* double quote (") */
+ putchar('\"');
+ break;
+
+ case 's' : /* "value" */
+ if (value)
+ fputs(value, stdout);
+ break;
+
+ case 't' : /* job-name */
+ fputs(title, stdout);
+ break;
+
+ case 'u' : /* job-originating-user-name */
+ fputs(user, stdout);
+ break;
+
+ case '?' : /* ?value:string; */
+ /*
+ * Get the match value...
+ */
+
+ for (format ++, mptr = match; *format && *format != ':'; format ++)
+ if (mptr < (match + sizeof(match) - 1))
+ *mptr++ = *format;
+
+ if (!*format)
+ return;
+
+ /*
+ * See if we have a match...
+ */
+
+ format ++;
+ *mptr = '\0';
+
+ if (!value || strcmp(match, value))
+ {
+ /*
+ * Value doesn't match; skip the string that follows...
+ */
+
+ while (*format && *format != ';')
+ format ++;
+ }
+ else
+ {
+ /*
+ * Value matches; copy the string that follows...
+ */
+
+ while (*format && *format != ';')
+ putchar(*format++);
+ }
+
+ if (!*format)
+ return;
+ break;
+
+ default : /* Anything else */
+ putchar('%');
+ case '%' : /* %% = single % */
+ putchar(*format);
+ break;
+ }
+ }
+ else
+ putchar(*format);
+
+ format ++;
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/pcl-common.h b/driver/pcl-common.h
new file mode 100644
index 000000000..7cab21cb9
--- /dev/null
+++ b/driver/pcl-common.h
@@ -0,0 +1,71 @@
+/*
+ * "$Id$"
+ *
+ * Common HP-PCL definitions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products, All Rights Reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/string-private.h>
+#include "data/pcl.h"
+
+
+/*
+ * Functions/macros...
+ */
+
+#define pcl_reset()\
+ printf("\033E")
+#define pcl_set_copies(copies)\
+ printf("\033&l%dX", (copies))
+#define pcl_set_pcl_mode(m)\
+ printf("\033%%%dA", (m))
+#define pcl_set_hpgl_mode(m)\
+ printf("\033%%%dB", (m))
+#define pcl_set_negative_motion()\
+ printf("\033&a1N")
+#define pcl_set_media_source(source)\
+ printf("\033&l%dH", source)
+#define pcl_set_media_type(type)\
+ printf("\033&l%dM", type)
+#define pcl_set_duplex(duplex,landscape)\
+ if (duplex) printf("\033&l%dS", (duplex) + (landscape))
+#define pcl_set_simple_black()\
+ printf("\033*r-1U")
+#define pcl_set_simple_color()\
+ printf("\033*r3U")
+#define pcl_set_simple_cmy()\
+ printf("\033*r-3U")
+#define pcl_set_simple_kcmy()\
+ printf("\033*r-4U")
+#define pcl_set_simple_resolution(r)\
+ printf("\033*t%dR", (r))
+
+#define pjl_escape()\
+ printf("\033%%-12345X@PJL\r\n")
+#define pjl_set_job(job_id,user,title)\
+ printf("@PJL JOB NAME = \"%s\" DISPLAY = \"%d %s %s\"\r\n", \
+ (title), (job_id), (user), (title))
+#define pjl_enter_language(lang)\
+ printf("@PJL ENTER LANGUAGE=%s\r\n", (lang))
+
+extern void pcl_set_media_size(ppd_file_t *ppd, float width, float length);
+extern void pjl_write(ppd_file_t *ppd, const char *format,
+ const char *value, int job_id,
+ const char *user, const char *title,
+ int num_options, cups_option_t *options);
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/rastertoescpx.c b/driver/rastertoescpx.c
new file mode 100644
index 000000000..0bcc0a92c
--- /dev/null
+++ b/driver/rastertoescpx.c
@@ -0,0 +1,1931 @@
+/*
+ * "$Id$"
+ *
+ * Advanced EPSON ESC/P raster driver for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * Setup() - Prepare the printer for graphics output.
+ * StartPage() - Start a page of graphics.
+ * EndPage() - Finish a page of graphics.
+ * Shutdown() - Shutdown a printer.
+ * CancelJob() - Cancel the current job...
+ * CompressData() - Compress a line of graphics.
+ * OutputBand() - Output a band of graphics.
+ * ProcessLine() - Read graphics from the page stream and output
+ * as needed.
+ * main() - Main entry and processing of driver.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "driver.h"
+#include <cups/language-private.h>
+#include <cups/string-private.h>
+#include "data/escp.h"
+#include <signal.h>
+
+
+/*
+ * Softweave data...
+ */
+
+typedef struct cups_weave_str
+{
+ struct cups_weave_str *prev, /* Previous band */
+ *next; /* Next band */
+ int x, y, /* Column/Line on the page */
+ plane, /* Color plane */
+ dirty, /* Is this buffer dirty? */
+ row, /* Row in the buffer */
+ count; /* Max rows this pass */
+ unsigned char *buffer; /* Data buffer */
+} cups_weave_t;
+
+
+/*
+ * Globals...
+ */
+
+cups_rgb_t *RGB; /* RGB color separation data */
+cups_cmyk_t *CMYK; /* CMYK color separation data */
+unsigned char *PixelBuffer, /* Pixel buffer */
+ *CMYKBuffer, /* CMYK buffer */
+ *OutputBuffers[7], /* Output buffers */
+ *DotBuffers[7], /* Dot buffers */
+ *CompBuffer; /* Compression buffer */
+short *InputBuffer; /* Color separation buffer */
+cups_weave_t *DotAvailList, /* Available buffers */
+ *DotUsedList, /* Used buffers */
+ *DotBands[128][7]; /* Buffers in use */
+int DotBufferSize, /* Size of dot buffers */
+ DotRowMax, /* Maximum row number in buffer */
+ DotColStep, /* Step for each output column */
+ DotRowStep, /* Step for each output line */
+ DotRowFeed, /* Amount to feed for interleave */
+ DotRowCount, /* Number of rows to output */
+ DotRowOffset[7], /* Offset for each color on print head */
+ DotRowCurrent, /* Current row */
+ DotSize; /* Dot size (Pro 5000 only) */
+int PrinterPlanes, /* # of color planes */
+ BitPlanes, /* # of bit planes per color */
+ PrinterTop, /* Top of page */
+ PrinterLength; /* Length of page */
+cups_lut_t *DitherLuts[7]; /* Lookup tables for dithering */
+cups_dither_t *DitherStates[7]; /* Dither state tables */
+int OutputFeed; /* Number of lines to skip */
+int Canceled; /* Is the job canceled? */
+
+
+/*
+ * Prototypes...
+ */
+
+void Setup(ppd_file_t *);
+void StartPage(ppd_file_t *, cups_page_header2_t *);
+void EndPage(ppd_file_t *, cups_page_header2_t *);
+void Shutdown(ppd_file_t *);
+
+void AddBand(cups_weave_t *band);
+void CancelJob(int sig);
+void CompressData(ppd_file_t *, const unsigned char *, const int,
+ int, int, const int, const int, const int,
+ const int);
+void OutputBand(ppd_file_t *, cups_page_header2_t *,
+ cups_weave_t *band);
+void ProcessLine(ppd_file_t *, cups_raster_t *,
+ cups_page_header2_t *, const int y);
+
+
+/*
+ * 'Setup()' - Prepare a printer for graphics output.
+ */
+
+void
+Setup(ppd_file_t *ppd) /* I - PPD file */
+{
+ /*
+ * Some EPSON printers need an additional command issued at the
+ * beginning of each job to exit from USB "packet" mode...
+ */
+
+ if (ppd->model_number & ESCP_USB)
+ cupsWritePrintData("\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@", 29);
+}
+
+
+/*
+ * 'StartPage()' - Start a page of graphics.
+ */
+
+void
+StartPage(ppd_file_t *ppd, /* I - PPD file */
+ cups_page_header2_t *header) /* I - Page header */
+{
+ int i, y; /* Looping vars */
+ int subrow, /* Current subrow */
+ modrow, /* Subrow modulus */
+ plane; /* Current color plane */
+ unsigned char *ptr; /* Pointer into dot buffer */
+ int bands; /* Number of bands to allocate */
+ int units; /* Units for resolution */
+ cups_weave_t *band; /* Current band */
+ const char *colormodel; /* Color model string */
+ char resolution[PPD_MAX_NAME],
+ /* Resolution string */
+ spec[PPD_MAX_NAME]; /* PPD attribute name */
+ ppd_attr_t *attr; /* Attribute from PPD file */
+ const float default_lut[2] = /* Default dithering lookup table */
+ {
+ 0.0,
+ 1.0
+ };
+
+
+ fprintf(stderr, "DEBUG: StartPage...\n");
+ fprintf(stderr, "DEBUG: MediaClass = \"%s\"\n", header->MediaClass);
+ fprintf(stderr, "DEBUG: MediaColor = \"%s\"\n", header->MediaColor);
+ fprintf(stderr, "DEBUG: MediaType = \"%s\"\n", header->MediaType);
+ fprintf(stderr, "DEBUG: OutputType = \"%s\"\n", header->OutputType);
+
+ fprintf(stderr, "DEBUG: AdvanceDistance = %d\n", header->AdvanceDistance);
+ fprintf(stderr, "DEBUG: AdvanceMedia = %d\n", header->AdvanceMedia);
+ fprintf(stderr, "DEBUG: Collate = %d\n", header->Collate);
+ fprintf(stderr, "DEBUG: CutMedia = %d\n", header->CutMedia);
+ fprintf(stderr, "DEBUG: Duplex = %d\n", header->Duplex);
+ fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", header->HWResolution[0],
+ header->HWResolution[1]);
+ fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
+ header->ImagingBoundingBox[0], header->ImagingBoundingBox[1],
+ header->ImagingBoundingBox[2], header->ImagingBoundingBox[3]);
+ fprintf(stderr, "DEBUG: InsertSheet = %d\n", header->InsertSheet);
+ fprintf(stderr, "DEBUG: Jog = %d\n", header->Jog);
+ fprintf(stderr, "DEBUG: LeadingEdge = %d\n", header->LeadingEdge);
+ fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", header->Margins[0],
+ header->Margins[1]);
+ fprintf(stderr, "DEBUG: ManualFeed = %d\n", header->ManualFeed);
+ fprintf(stderr, "DEBUG: MediaPosition = %d\n", header->MediaPosition);
+ fprintf(stderr, "DEBUG: MediaWeight = %d\n", header->MediaWeight);
+ fprintf(stderr, "DEBUG: MirrorPrint = %d\n", header->MirrorPrint);
+ fprintf(stderr, "DEBUG: NegativePrint = %d\n", header->NegativePrint);
+ fprintf(stderr, "DEBUG: NumCopies = %d\n", header->NumCopies);
+ fprintf(stderr, "DEBUG: Orientation = %d\n", header->Orientation);
+ fprintf(stderr, "DEBUG: OutputFaceUp = %d\n", header->OutputFaceUp);
+ fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", header->PageSize[0],
+ header->PageSize[1]);
+ fprintf(stderr, "DEBUG: Separations = %d\n", header->Separations);
+ fprintf(stderr, "DEBUG: TraySwitch = %d\n", header->TraySwitch);
+ fprintf(stderr, "DEBUG: Tumble = %d\n", header->Tumble);
+ fprintf(stderr, "DEBUG: cupsWidth = %d\n", header->cupsWidth);
+ fprintf(stderr, "DEBUG: cupsHeight = %d\n", header->cupsHeight);
+ fprintf(stderr, "DEBUG: cupsMediaType = %d\n", header->cupsMediaType);
+ fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header->cupsBitsPerColor);
+ fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header->cupsBitsPerPixel);
+ fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header->cupsBytesPerLine);
+ fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header->cupsColorOrder);
+ fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header->cupsColorSpace);
+ fprintf(stderr, "DEBUG: cupsCompression = %d\n", header->cupsCompression);
+ fprintf(stderr, "DEBUG: cupsRowCount = %d\n", header->cupsRowCount);
+ fprintf(stderr, "DEBUG: cupsRowFeed = %d\n", header->cupsRowFeed);
+ fprintf(stderr, "DEBUG: cupsRowStep = %d\n", header->cupsRowStep);
+
+ /*
+ * Figure out the color model and spec strings...
+ */
+
+ switch (header->cupsColorSpace)
+ {
+ case CUPS_CSPACE_K :
+ colormodel = "Black";
+ break;
+ case CUPS_CSPACE_W :
+ colormodel = "Gray";
+ break;
+ default :
+ case CUPS_CSPACE_RGB :
+ colormodel = "RGB";
+ break;
+ case CUPS_CSPACE_CMYK :
+ colormodel = "CMYK";
+ break;
+ }
+
+ if (header->HWResolution[0] != header->HWResolution[1])
+ snprintf(resolution, sizeof(resolution), "%dx%ddpi",
+ header->HWResolution[0], header->HWResolution[1]);
+ else
+ snprintf(resolution, sizeof(resolution), "%ddpi",
+ header->HWResolution[0]);
+
+ if (!header->MediaType[0])
+ strcpy(header->MediaType, "Plain");
+
+ /*
+ * Load the appropriate color profiles...
+ */
+
+ RGB = NULL;
+ CMYK = NULL;
+
+ fputs("DEBUG: Attempting to load color profiles using the following values:\n", stderr);
+ fprintf(stderr, "DEBUG: ColorModel = %s\n", colormodel);
+ fprintf(stderr, "DEBUG: MediaType = %s\n", header->MediaType);
+ fprintf(stderr, "DEBUG: Resolution = %s\n", resolution);
+
+ if (header->cupsColorSpace == CUPS_CSPACE_RGB ||
+ header->cupsColorSpace == CUPS_CSPACE_W)
+ RGB = cupsRGBLoad(ppd, colormodel, header->MediaType, resolution);
+ else
+ RGB = NULL;
+
+ CMYK = cupsCMYKLoad(ppd, colormodel, header->MediaType, resolution);
+
+ if (RGB)
+ fputs("DEBUG: Loaded RGB separation from PPD.\n", stderr);
+
+ if (CMYK)
+ fputs("DEBUG: Loaded CMYK separation from PPD.\n", stderr);
+ else
+ {
+ fputs("DEBUG: Loading default CMYK separation.\n", stderr);
+ CMYK = cupsCMYKNew(4);
+ }
+
+ PrinterPlanes = CMYK->num_channels;
+
+ fprintf(stderr, "DEBUG: PrinterPlanes = %d\n", PrinterPlanes);
+
+ /*
+ * Get the dithering parameters...
+ */
+
+ switch (PrinterPlanes)
+ {
+ case 1 : /* K */
+ DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Black");
+ break;
+
+ case 2 : /* Kk */
+ DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Black");
+ DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "LightBlack");
+ break;
+
+ case 3 : /* CMY */
+ DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Cyan");
+ DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Magenta");
+ DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Yellow");
+ break;
+
+ case 4 : /* CMYK */
+ DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Cyan");
+ DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Magenta");
+ DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Yellow");
+ DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Black");
+ break;
+
+ case 6 : /* CcMmYK */
+ DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Cyan");
+ DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "LightCyan");
+ DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Magenta");
+ DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "LightMagenta");
+ DitherLuts[4] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Yellow");
+ DitherLuts[5] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Black");
+ break;
+
+ case 7 : /* CcMmYKk */
+ DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Cyan");
+ DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "LightCyan");
+ DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Magenta");
+ DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "LightMagenta");
+ DitherLuts[4] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Yellow");
+ DitherLuts[5] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Black");
+ DitherLuts[6] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "LightBlack");
+ break;
+ }
+
+ for (plane = 0; plane < PrinterPlanes; plane ++)
+ {
+ DitherStates[plane] = cupsDitherNew(header->cupsWidth);
+
+ if (!DitherLuts[plane])
+ DitherLuts[plane] = cupsLutNew(2, default_lut);
+ }
+
+ if (DitherLuts[0][4095].pixel > 1)
+ BitPlanes = 2;
+ else
+ BitPlanes = 1;
+
+ /*
+ * Initialize the printer...
+ */
+
+ printf("\033@");
+
+ if (ppd->model_number & ESCP_REMOTE)
+ {
+ /*
+ * Go into remote mode...
+ */
+
+ cupsWritePrintData("\033(R\010\000\000REMOTE1", 13);
+
+ /*
+ * Disable status reporting...
+ */
+
+ cupsWritePrintData("ST\002\000\000\000", 6);
+
+ /*
+ * Enable borderless printing...
+ */
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPFP", NULL)) != NULL && attr->value)
+ {
+ /*
+ * Set horizontal offset...
+ */
+
+ i = atoi(attr->value);
+
+ cupsWritePrintData("FP\003\000\000", 5);
+ putchar(i & 255);
+ putchar(i >> 8);
+ }
+
+ /*
+ * Set media type...
+ */
+
+ if (header->cupsMediaType)
+ {
+ sprintf(spec, "%d", header->cupsMediaType);
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPSN0", spec)) != NULL && attr->value)
+ {
+ /*
+ * Set feed sequence...
+ */
+
+ cupsWritePrintData("SN\003\000\000\000", 6);
+ putchar(atoi(attr->value));
+ }
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPSN1", spec)) != NULL && attr->value)
+ {
+ /*
+ * Set platten gap...
+ */
+
+ cupsWritePrintData("SN\003\000\000\001", 6);
+ putchar(atoi(attr->value));
+ }
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPSN2", spec)) != NULL && attr->value)
+ {
+ /*
+ * Paper feeding/ejecting sequence...
+ */
+
+ cupsWritePrintData("SN\003\000\000\002", 6);
+ putchar(atoi(attr->value));
+ }
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPSN6", spec)) != NULL && attr->value)
+ {
+ /*
+ * Eject delay...
+ */
+
+ cupsWritePrintData("SN\003\000\000\006", 6);
+ putchar(atoi(attr->value));
+ }
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPMT", spec)) != NULL && attr->value)
+ {
+ /*
+ * Set media type.
+ */
+
+ cupsWritePrintData("MT\003\000\000\000", 6);
+ putchar(atoi(attr->value));
+ }
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPPH", spec)) != NULL && attr->value)
+ {
+ /*
+ * Set paper thickness.
+ */
+
+ cupsWritePrintData("PH\002\000\000", 5);
+ putchar(atoi(attr->value));
+ }
+ }
+
+ sprintf(spec, "%d", header->MediaPosition);
+
+ if (header->MediaPosition)
+ {
+ if ((attr = ppdFindAttr(ppd, "cupsESCPPC", spec)) != NULL && attr->value)
+ {
+ /*
+ * Paper check.
+ */
+
+ cupsWritePrintData("PC\002\000\000", 5);
+ putchar(atoi(attr->value));
+ }
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPPP", spec)) != NULL && attr->value)
+ {
+ /*
+ * Paper path.
+ */
+
+ int a, b;
+
+ a = b = 0;
+ sscanf(attr->value, "%d%d", &a, &b);
+
+ cupsWritePrintData("PP\003\000\000", 5);
+ putchar(a);
+ putchar(b);
+ }
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPEX", spec)) != NULL && attr->value)
+ {
+ /*
+ * Set media position.
+ */
+
+ cupsWritePrintData("EX\006\000\000\000\000\000\005", 9);
+ putchar(atoi(attr->value));
+ }
+ }
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPMS", spec)) != NULL && attr->value)
+ {
+ /*
+ * Set media size...
+ */
+
+ cupsWritePrintData("MS\010\000\000", 5);
+ putchar(atoi(attr->value));
+
+ switch (header->PageSize[1])
+ {
+ case 1191 : /* A3 */
+ putchar(0x01);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ break;
+ case 1032 : /* B4 */
+ putchar(0x02);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ break;
+ case 842 : /* A4 */
+ putchar(0x03);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ break;
+ case 595 : /* A4.Transverse */
+ putchar(0x03);
+ putchar(0x01);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ break;
+ case 729 : /* B5 */
+ putchar(0x04);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ break;
+ case 516 : /* B5.Transverse */
+ putchar(0x04);
+ putchar(0x01);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ break;
+ case 1369 : /* Super A3/B */
+ putchar(0x20);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ break;
+ case 792 : /* Letter */
+ putchar(0x08);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ break;
+ case 612 : /* Letter.Transverse */
+ putchar(0x08);
+ putchar(0x01);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ break;
+ case 1004 : /* Legal */
+ putchar(0x0a);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ break;
+ case 1224 : /* Tabloid */
+ putchar(0x2d);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ putchar(0x00);
+ break;
+ default : /* Custom size */
+ putchar(0xff);
+ putchar(0xff);
+ i = 360 * header->PageSize[0] / 72;
+ putchar(i);
+ putchar(i >> 8);
+ i = 360 * header->PageSize[1] / 72;
+ putchar(i);
+ putchar(i >> 8);
+ break;
+ }
+ }
+
+ sprintf(spec, "%d", header->CutMedia);
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPAC", spec)) != NULL && attr->value)
+ {
+ /*
+ * Enable/disable cutter.
+ */
+
+ cupsWritePrintData("AC\002\000\000", 5);
+ putchar(atoi(attr->value));
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPSN80", header->MediaType)) != NULL && attr->value)
+ {
+ /*
+ * Cutting method...
+ */
+
+ cupsWritePrintData("SN\003\000\000\200", 6);
+ putchar(atoi(attr->value));
+ }
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPSN81", header->MediaType)) != NULL && attr->value)
+ {
+ /*
+ * Cutting pressure...
+ */
+
+ cupsWritePrintData("SN\003\000\000\201", 6);
+ putchar(atoi(attr->value));
+ }
+ }
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPCO", spec)) != NULL && attr->value)
+ {
+ /*
+ * Enable/disable cutter.
+ */
+
+ cupsWritePrintData("CO\010\000\000\000", 6);
+ putchar(atoi(attr->value));
+ cupsWritePrintData("\000\000\000\000\000", 5);
+ }
+
+ /*
+ * Exit remote mode...
+ */
+
+ cupsWritePrintData("\033\000\000\000", 4);
+ }
+
+ /*
+ * Enter graphics mode...
+ */
+
+ cupsWritePrintData("\033(G\001\000\001", 6);
+
+ /*
+ * Set the line feed increment...
+ */
+
+ /* TODO: get this from the PPD file... */
+ for (units = 1440; units < header->HWResolution[0]; units *= 2);
+
+ if (ppd->model_number & ESCP_EXT_UNITS)
+ {
+ cupsWritePrintData("\033(U\005\000", 5);
+ putchar(units / header->HWResolution[1]);
+ putchar(units / header->HWResolution[1]);
+ putchar(units / header->HWResolution[0]);
+ putchar(units);
+ putchar(units >> 8);
+ }
+ else
+ {
+ cupsWritePrintData("\033(U\001\000", 5);
+ putchar(3600 / header->HWResolution[1]);
+ }
+
+ /*
+ * Set the page length...
+ */
+
+ PrinterLength = header->PageSize[1] * header->HWResolution[1] / 72;
+
+ if (ppd->model_number & ESCP_PAGE_SIZE)
+ {
+ /*
+ * Set page size (expands bottom margin)...
+ */
+
+ cupsWritePrintData("\033(S\010\000", 5);
+
+ i = header->PageSize[0] * header->HWResolution[1] / 72;
+ putchar(i);
+ putchar(i >> 8);
+ putchar(i >> 16);
+ putchar(i >> 24);
+
+ i = header->PageSize[1] * header->HWResolution[1] / 72;
+ putchar(i);
+ putchar(i >> 8);
+ putchar(i >> 16);
+ putchar(i >> 24);
+ }
+ else
+ {
+ cupsWritePrintData("\033(C\002\000", 5);
+ putchar(PrinterLength & 255);
+ putchar(PrinterLength >> 8);
+ }
+
+ /*
+ * Set the top and bottom margins...
+ */
+
+ PrinterTop = (int)((ppd->sizes[1].length - ppd->sizes[1].top) *
+ header->HWResolution[1] / 72.0);
+
+ if (ppd->model_number & ESCP_EXT_MARGINS)
+ {
+ cupsWritePrintData("\033(c\010\000", 5);
+
+ putchar(PrinterTop);
+ putchar(PrinterTop >> 8);
+ putchar(PrinterTop >> 16);
+ putchar(PrinterTop >> 24);
+
+ putchar(PrinterLength);
+ putchar(PrinterLength >> 8);
+ putchar(PrinterLength >> 16);
+ putchar(PrinterLength >> 24);
+ }
+ else
+ {
+ cupsWritePrintData("\033(c\004\000", 5);
+
+ putchar(PrinterTop & 255);
+ putchar(PrinterTop >> 8);
+
+ putchar(PrinterLength & 255);
+ putchar(PrinterLength >> 8);
+ }
+
+ /*
+ * Set the top position...
+ */
+
+ cupsWritePrintData("\033(V\002\000\000\000", 7);
+
+ /*
+ * Enable unidirectional printing depending on the mode...
+ */
+
+ if ((attr = cupsFindAttr(ppd, "cupsESCPDirection", colormodel,
+ header->MediaType, resolution, spec,
+ sizeof(spec))) != NULL)
+ printf("\033U%c", atoi(attr->value));
+
+ /*
+ * Enable/disable microweaving as needed...
+ */
+
+ if ((attr = cupsFindAttr(ppd, "cupsESCPMicroWeave", colormodel,
+ header->MediaType, resolution, spec,
+ sizeof(spec))) != NULL)
+ printf("\033(i\001%c%c", 0, atoi(attr->value));
+
+ /*
+ * Set the dot size and print speed as needed...
+ */
+
+ if ((attr = cupsFindAttr(ppd, "cupsESCPDotSize", colormodel,
+ header->MediaType, resolution, spec,
+ sizeof(spec))) != NULL)
+ printf("\033(e\002%c%c%c", 0, 0, atoi(attr->value));
+
+ if (ppd->model_number & ESCP_ESCK)
+ {
+ /*
+ * Set the print mode...
+ */
+
+ if (PrinterPlanes == 1)
+ {
+ /*
+ * Fast black printing.
+ */
+
+ cupsWritePrintData("\033(K\002\000\000\001", 7);
+ }
+ else
+ {
+ /*
+ * Color printing.
+ */
+
+ cupsWritePrintData("\033(K\002\000\000\002", 7);
+ }
+ }
+
+ /*
+ * Get softweave settings from header...
+ */
+
+ if (header->cupsRowCount <= 1)
+ {
+ DotRowCount = 1;
+ DotColStep = 1;
+ DotRowStep = 1;
+ DotRowFeed = 1;
+ }
+ else
+ {
+ DotRowCount = header->cupsRowCount;
+ DotRowFeed = header->cupsRowFeed;
+ DotRowStep = header->cupsRowStep % 100;
+ DotColStep = header->cupsRowStep / 100;
+
+ if (DotColStep == 0)
+ DotColStep ++;
+ }
+
+ /*
+ * Setup softweave parameters...
+ */
+
+ DotRowCurrent = 0;
+ DotRowMax = DotRowCount * DotRowStep;
+ DotBufferSize = (header->cupsWidth / DotColStep * BitPlanes + 7) / 8;
+
+ fprintf(stderr, "DEBUG: DotBufferSize = %d\n", DotBufferSize);
+ fprintf(stderr, "DEBUG: DotColStep = %d\n", DotColStep);
+ fprintf(stderr, "DEBUG: DotRowMax = %d\n", DotRowMax);
+ fprintf(stderr, "DEBUG: DotRowStep = %d\n", DotRowStep);
+ fprintf(stderr, "DEBUG: DotRowFeed = %d\n", DotRowFeed);
+ fprintf(stderr, "DEBUG: DotRowCount = %d\n", DotRowCount);
+
+ DotAvailList = NULL;
+ DotUsedList = NULL;
+ DotBuffers[0] = NULL;
+
+ fprintf(stderr, "DEBUG: model_number = %x\n", ppd->model_number);
+
+ if (DotRowMax > 1)
+ {
+ /*
+ * Compute offsets for the color jets on the print head...
+ */
+
+ bands = DotRowStep * DotColStep * PrinterPlanes * 4;
+
+ memset(DotRowOffset, 0, sizeof(DotRowOffset));
+
+ if (PrinterPlanes == 1)
+ {
+ /*
+ * Use full height of print head...
+ */
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPBlack", resolution)) != NULL &&
+ attr->value)
+ {
+ /*
+ * Use custom black head data...
+ */
+
+ sscanf(attr->value, "%d%d", &DotRowCount, &DotRowStep);
+ }
+ }
+ else if (ppd->model_number & ESCP_STAGGER)
+ {
+ /*
+ * Use staggered print head...
+ */
+
+ fputs("DEBUG: Offset head detected...\n", stderr);
+
+ if ((attr = ppdFindAttr(ppd, "cupsESCPOffsets", resolution)) != NULL &&
+ attr->value)
+ {
+ /*
+ * Use only 1/3 of the print head when printing color...
+ */
+
+ sscanf(attr->value, "%d%d%d%d", DotRowOffset + 0,
+ DotRowOffset + 1, DotRowOffset + 2, DotRowOffset + 3);
+ }
+ }
+
+ for (i = 0; i < PrinterPlanes; i ++)
+ fprintf(stderr, "DEBUG: DotRowOffset[%d] = %d\n", i, DotRowOffset[i]);
+
+ /*
+ * Allocate bands...
+ */
+
+ for (i = 0; i < bands; i ++)
+ {
+ band = (cups_weave_t *)calloc(1, sizeof(cups_weave_t));
+ band->next = DotAvailList;
+ DotAvailList = band;
+
+ band->buffer = calloc(DotRowCount, DotBufferSize);
+ }
+
+ if (!DotAvailList)
+ {
+ fputs("ERROR: Unable to allocate band list\n", stderr);
+ exit(1);
+ }
+
+ fputs("DEBUG: Pointer list at start of page...\n", stderr);
+
+ for (band = DotAvailList; band != NULL; band = band->next)
+ fprintf(stderr, "DEBUG: %p\n", band);
+
+ fputs("DEBUG: ----END----\n", stderr);
+
+ /*
+ * Fill the initial bands...
+ */
+
+ modrow = DotColStep * DotRowStep;
+
+ if (DotRowFeed == 0)
+ {
+ /*
+ * Automatically compute the optimal feed value...
+ */
+
+ DotRowFeed = DotRowCount / DotColStep - DotRowStep;
+
+ while ((((DotRowFeed % 2) == 0) == ((DotRowCount % 2) == 0) ||
+ ((DotRowFeed % 3) == 0) == ((DotRowCount % 3) == 0) ||
+ ((DotRowFeed % 5) == 0) == ((DotRowCount % 5) == 0)) &&
+ DotRowFeed > 1)
+ DotRowFeed --;
+
+ if (DotRowFeed < 1)
+ DotRowFeed = 1;
+
+ fprintf(stderr, "DEBUG: Auto DotRowFeed = %d, modrow=%d...\n",
+ DotRowFeed, modrow);
+ }
+
+ memset(DotBands, 0, sizeof(DotBands));
+
+ for (i = modrow, subrow = modrow - 1, y = DotRowFeed;
+ i > 0;
+ i --, y += DotRowFeed)
+ {
+ while (DotBands[subrow][0])
+ {
+ /*
+ * This subrow is already used, move to another one...
+ */
+
+ subrow = (subrow + 1) % modrow;
+ }
+
+ for (plane = 0; plane < PrinterPlanes; plane ++)
+ {
+ /*
+ * Pull the next available band from the list...
+ */
+
+ band = DotAvailList;
+ DotAvailList = DotAvailList->next;
+ DotBands[subrow][plane] = band;
+
+ /*
+ * Start the band in the first few passes, with the number of rows
+ * varying to allow for a nice interleaved pattern...
+ */
+
+ band->x = subrow / DotRowStep;
+ band->y = (subrow % DotRowStep) + DotRowOffset[plane];
+ band->plane = plane;
+ band->row = 0;
+ band->count = DotRowCount - y / DotRowStep;
+
+ if (band->count < 1)
+ band->count = 1;
+ else if (band->count > DotRowCount)
+ band->count = DotRowCount;
+
+ fprintf(stderr, "DEBUG: DotBands[%d][%d] = %p, x = %d, y = %d, plane = %d, count = %d\n",
+ subrow, plane, band, band->x, band->y, band->plane, band->count);
+ }
+
+ subrow = (subrow + DotRowFeed) % modrow;
+ }
+ }
+ else
+ {
+ /*
+ * Allocate memory for a single line of graphics...
+ */
+
+ ptr = calloc(PrinterPlanes, DotBufferSize);
+
+ for (plane = 0; plane < PrinterPlanes; plane ++, ptr += DotBufferSize)
+ DotBuffers[plane] = ptr;
+ }
+
+ /*
+ * Set the output resolution...
+ */
+
+ cupsWritePrintData("\033(D\004\000", 5);
+ putchar(units);
+ putchar(units >> 8);
+ putchar(units * DotRowStep / header->HWResolution[1]);
+ putchar(units * DotColStep / header->HWResolution[0]);
+
+ /*
+ * Set the top of form...
+ */
+
+ OutputFeed = 0;
+
+ /*
+ * Allocate buffers as needed...
+ */
+
+ PixelBuffer = malloc(header->cupsBytesPerLine);
+ InputBuffer = malloc(header->cupsWidth * PrinterPlanes * 2);
+ OutputBuffers[0] = malloc(PrinterPlanes * header->cupsWidth);
+
+ for (i = 1; i < PrinterPlanes; i ++)
+ OutputBuffers[i] = OutputBuffers[0] + i * header->cupsWidth;
+
+ if (RGB)
+ CMYKBuffer = malloc(header->cupsWidth * PrinterPlanes);
+
+ CompBuffer = malloc(10 * DotBufferSize * DotRowMax);
+}
+
+
+/*
+ * 'EndPage()' - Finish a page of graphics.
+ */
+
+void
+EndPage(ppd_file_t *ppd, /* I - PPD file */
+ cups_page_header2_t *header) /* I - Page header */
+{
+ int i; /* Looping var */
+ cups_weave_t *band, /* Current band */
+ *next; /* Next band in list */
+ int plane; /* Current plane */
+ int subrow; /* Current subrow */
+ int subrows; /* Number of subrows */
+
+
+ /*
+ * Output the last bands of print data as necessary...
+ */
+
+ if (DotRowMax > 1)
+ {
+ /*
+ * Move the remaining bands to the used or avail lists...
+ */
+
+ subrows = DotRowStep * DotColStep;
+
+ for (subrow = 0; subrow < subrows; subrow ++)
+ for (plane = 0; plane < PrinterPlanes; plane ++)
+ {
+ if (DotBands[subrow][plane]->dirty)
+ {
+ /*
+ * Insert into the used list...
+ */
+
+ DotBands[subrow][plane]->count = DotBands[subrow][plane]->row;
+
+ AddBand(DotBands[subrow][plane]);
+ }
+ else
+ {
+ /*
+ * Nothing here, so move it to the available list...
+ */
+
+ DotBands[subrow][plane]->next = DotAvailList;
+ DotAvailList = DotBands[subrow][plane];
+ }
+
+ DotBands[subrow][plane] = NULL;
+ }
+
+ /*
+ * Loop until all bands are written...
+ */
+
+ fputs("DEBUG: Pointer list at end of page...\n", stderr);
+
+ for (band = DotUsedList; band != NULL; band = band->next)
+ fprintf(stderr, "DEBUG: %p (used)\n", band);
+ for (band = DotAvailList; band != NULL; band = band->next)
+ fprintf(stderr, "DEBUG: %p (avail)\n", band);
+
+ fputs("DEBUG: ----END----\n", stderr);
+
+ for (band = DotUsedList; band != NULL; band = next)
+ {
+ next = band->next;
+
+ OutputBand(ppd, header, band);
+
+ fprintf(stderr, "DEBUG: freeing used band %p, prev = %p, next = %p\n",
+ band, band->prev, band->next);
+
+ free(band->buffer);
+ free(band);
+ }
+
+ /*
+ * Free memory for the available bands, if any...
+ */
+
+ for (band = DotAvailList; band != NULL; band = next)
+ {
+ next = band->next;
+
+ fprintf(stderr, "DEBUG: freeing avail band %p, prev = %p, next = %p\n",
+ band, band->prev, band->next);
+
+ free(band->buffer);
+ free(band);
+ }
+ }
+ else
+ free(DotBuffers[0]);
+
+ /*
+ * Output a page eject sequence...
+ */
+
+ putchar(12);
+
+ /*
+ * Free memory for the page...
+ */
+
+ for (i = 0; i < PrinterPlanes; i ++)
+ {
+ cupsDitherDelete(DitherStates[i]);
+ cupsLutDelete(DitherLuts[i]);
+ }
+
+ free(OutputBuffers[0]);
+
+ free(PixelBuffer);
+ free(InputBuffer);
+ free(CompBuffer);
+
+ cupsCMYKDelete(CMYK);
+
+ if (RGB)
+ {
+ cupsRGBDelete(RGB);
+ free(CMYKBuffer);
+ }
+}
+
+
+/*
+ * 'Shutdown()' - Shutdown a printer.
+ */
+
+void
+Shutdown(ppd_file_t *ppd) /* I - PPD file */
+{
+ /*
+ * Reset the printer...
+ */
+
+ printf("\033@");
+
+ if (ppd->model_number & ESCP_REMOTE)
+ {
+ /*
+ * Go into remote mode...
+ */
+
+ cupsWritePrintData("\033(R\010\000\000REMOTE1", 13);
+
+ /*
+ * Load defaults...
+ */
+
+ cupsWritePrintData("LD\000\000", 4);
+
+ /*
+ * Exit remote mode...
+ */
+
+ cupsWritePrintData("\033\000\000\000", 4);
+ }
+}
+
+
+/*
+ * 'AddBand()' - Add a band of data to the used list.
+ */
+
+void
+AddBand(cups_weave_t *band) /* I - Band to add */
+{
+ cups_weave_t *current, /* Current band */
+ *prev; /* Previous band */
+
+
+ if (band->count < 1)
+ return;
+
+ for (current = DotUsedList, prev = NULL;
+ current != NULL;
+ prev = current, current = current->next)
+ if (band->y < current->y ||
+ (band->y == current->y && band->x < current->x) ||
+ (band->y == current->y && band->x == current->x &&
+ band->plane < current->plane))
+ break;
+
+ if (current != NULL)
+ {
+ /*
+ * Insert the band...
+ */
+
+ band->next = current;
+ band->prev = prev;
+ current->prev = band;
+
+ if (prev != NULL)
+ prev->next = band;
+ else
+ DotUsedList = band;
+ }
+ else if (prev != NULL)
+ {
+ /*
+ * Append the band to the end...
+ */
+
+ band->prev = prev;
+ prev->next = band;
+ band->next = NULL;
+ }
+ else
+ {
+ /*
+ * First band in list...
+ */
+
+ DotUsedList = band;
+ band->prev = NULL;
+ band->next = NULL;
+ }
+}
+
+
+/*
+ * 'CancelJob()' - Cancel the current job...
+ */
+
+void
+CancelJob(int sig) /* I - Signal */
+{
+ (void)sig;
+
+ Canceled = 1;
+}
+
+
+/*
+ * 'CompressData()' - Compress a line of graphics.
+ */
+
+void
+CompressData(ppd_file_t *ppd, /* I - PPD file information */
+ const unsigned char *line, /* I - Data to compress */
+ const int length,/* I - Number of bytes */
+ int plane, /* I - Color plane */
+ int type, /* I - Type of compression */
+ const int rows, /* I - Number of lines to write */
+ const int xstep, /* I - Spacing between columns */
+ const int ystep, /* I - Spacing between lines */
+ const int offset)/* I - Head offset */
+{
+ register const unsigned char *line_ptr,
+ /* Current byte pointer */
+ *line_end, /* End-of-line byte pointer */
+ *start; /* Start of compression sequence */
+ register unsigned char *comp_ptr; /* Pointer into compression buffer */
+ register int count; /* Count of bytes for output */
+ register int bytes; /* Number of bytes per row */
+ static int ctable[7][7] = /* Colors */
+ {
+ { 0, 0, 0, 0, 0, 0, 0 }, /* K */
+ { 0, 16, 0, 0, 0, 0, 0 }, /* Kk */
+ { 2, 1, 4, 0, 0, 0, 0 }, /* CMY */
+ { 2, 1, 4, 0, 0, 0, 0 }, /* CMYK */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 2, 18, 1, 17, 4, 0, 0 }, /* CcMmYK */
+ { 2, 18, 1, 17, 4, 0, 16 }, /* CcMmYKk */
+ };
+
+
+ switch (type)
+ {
+ case 0 :
+ /*
+ * Do no compression...
+ */
+
+ line_ptr = (const unsigned char *)line;
+ line_end = (const unsigned char *)line + length;
+ break;
+
+ default :
+ /*
+ * Do TIFF pack-bits encoding...
+ */
+
+ line_ptr = (const unsigned char *)line;
+ line_end = (const unsigned char *)line + length;
+ comp_ptr = CompBuffer;
+
+ while (line_ptr < line_end && (comp_ptr - CompBuffer) < length)
+ {
+ if ((line_ptr + 1) >= line_end)
+ {
+ /*
+ * Single byte on the end...
+ */
+
+ *comp_ptr++ = 0x00;
+ *comp_ptr++ = *line_ptr++;
+ }
+ else if (line_ptr[0] == line_ptr[1])
+ {
+ /*
+ * Repeated sequence...
+ */
+
+ line_ptr ++;
+ count = 2;
+
+ while (line_ptr < (line_end - 1) &&
+ line_ptr[0] == line_ptr[1] &&
+ count < 127)
+ {
+ line_ptr ++;
+ count ++;
+ }
+
+ *comp_ptr++ = 257 - count;
+ *comp_ptr++ = *line_ptr++;
+ }
+ else
+ {
+ /*
+ * Non-repeated sequence...
+ */
+
+ start = line_ptr;
+ line_ptr ++;
+ count = 1;
+
+ while (line_ptr < (line_end - 1) &&
+ line_ptr[0] != line_ptr[1] &&
+ count < 127)
+ {
+ line_ptr ++;
+ count ++;
+ }
+
+ *comp_ptr++ = count - 1;
+
+ memcpy(comp_ptr, start, count);
+ comp_ptr += count;
+ }
+ }
+
+ if ((comp_ptr - CompBuffer) < length)
+ {
+ line_ptr = (const unsigned char *)CompBuffer;
+ line_end = (const unsigned char *)comp_ptr;
+ }
+ else
+ {
+ type = 0;
+ line_ptr = (const unsigned char *)line;
+ line_end = (const unsigned char *)line + length;
+ }
+ break;
+ }
+
+ /*
+ * Position the print head...
+ */
+
+ putchar(0x0d);
+
+ if (offset)
+ {
+ if (BitPlanes == 1)
+ cupsWritePrintData("\033(\\\004\000\240\005", 7);
+ else
+ printf("\033\\");
+
+ putchar(offset);
+ putchar(offset >> 8);
+ }
+
+ /*
+ * Send the graphics...
+ */
+
+ bytes = length / rows;
+
+ if (ppd->model_number & ESCP_RASTER_ESCI)
+ {
+ /*
+ * Send graphics with ESC i command.
+ */
+
+ printf("\033i");
+ putchar(ctable[PrinterPlanes - 1][plane]);
+ putchar(type != 0);
+ putchar(BitPlanes);
+ putchar(bytes & 255);
+ putchar(bytes >> 8);
+ putchar(rows & 255);
+ putchar(rows >> 8);
+ }
+ else
+ {
+ /*
+ * Set the color if necessary...
+ */
+
+ if (PrinterPlanes > 1)
+ {
+ plane = ctable[PrinterPlanes - 1][plane];
+
+ if (plane & 0x10)
+ printf("\033(r%c%c%c%c", 2, 0, 1, plane & 0x0f);
+ else
+ printf("\033r%c", plane);
+ }
+
+ /*
+ * Send graphics with ESC . command.
+ */
+
+ bytes *= 8;
+
+ printf("\033.");
+ putchar(type != 0);
+ putchar(ystep);
+ putchar(xstep);
+ putchar(rows);
+ putchar(bytes & 255);
+ putchar(bytes >> 8);
+ }
+
+ cupsWritePrintData(line_ptr, line_end - line_ptr);
+}
+
+
+/*
+ * 'OutputBand()' - Output a band of graphics.
+ */
+
+void
+OutputBand(ppd_file_t *ppd, /* I - PPD file */
+ cups_page_header2_t *header, /* I - Page header */
+ cups_weave_t *band) /* I - Current band */
+{
+ int xstep, /* Spacing between columns */
+ ystep; /* Spacing between rows */
+
+
+ /*
+ * Interleaved ESC/P2 graphics...
+ */
+
+ OutputFeed = band->y - DotRowCurrent;
+ DotRowCurrent = band->y;
+
+ fprintf(stderr, "DEBUG: Printing band %p, x = %d, y = %d, plane = %d, count = %d, OutputFeed = %d\n",
+ band, band->x, band->y, band->plane, band->count, OutputFeed);
+
+ /*
+ * Compute step values...
+ */
+
+ xstep = 3600 * DotColStep / header->HWResolution[0];
+ ystep = 3600 * DotRowStep / header->HWResolution[1];
+
+ /*
+ * Output the band...
+ */
+
+ if (OutputFeed > 0)
+ {
+ cupsWritePrintData("\033(v\002\000", 5);
+ putchar(OutputFeed & 255);
+ putchar(OutputFeed >> 8);
+
+ OutputFeed = 0;
+ }
+
+ CompressData(ppd, band->buffer, band->count * DotBufferSize, band->plane,
+ header->cupsCompression, band->count, xstep, ystep, band->x);
+
+ /*
+ * Clear the band...
+ */
+
+ memset(band->buffer, 0, band->count * DotBufferSize);
+ band->dirty = 0;
+
+ /*
+ * Flush the output buffers...
+ */
+
+ fflush(stdout);
+}
+
+
+/*
+ * 'ProcessLine()' - Read graphics from the page stream and output as needed.
+ */
+
+void
+ProcessLine(ppd_file_t *ppd, /* I - PPD file */
+ cups_raster_t *ras, /* I - Raster stream */
+ cups_page_header2_t *header, /* I - Page header */
+ const int y) /* I - Current scanline */
+{
+ int plane, /* Current color plane */
+ width, /* Width of line */
+ subwidth, /* Width of interleaved row */
+ subrow, /* Subrow for interleaved output */
+ offset, /* Offset to current line */
+ pass, /* Pass number */
+ xstep, /* X step value */
+ ystep; /* Y step value */
+ cups_weave_t *band; /* Current band */
+
+
+ /*
+ * Read a row of graphics...
+ */
+
+ if (!cupsRasterReadPixels(ras, PixelBuffer, header->cupsBytesPerLine))
+ return;
+
+ /*
+ * Perform the color separation...
+ */
+
+ width = header->cupsWidth;
+ subwidth = header->cupsWidth / DotColStep;
+ xstep = 3600 / header->HWResolution[0];
+ ystep = 3600 / header->HWResolution[1];
+
+ switch (header->cupsColorSpace)
+ {
+ case CUPS_CSPACE_W :
+ if (RGB)
+ {
+ cupsRGBDoGray(RGB, PixelBuffer, CMYKBuffer, width);
+ cupsCMYKDoCMYK(CMYK, CMYKBuffer, InputBuffer, width);
+ }
+ else
+ cupsCMYKDoGray(CMYK, PixelBuffer, InputBuffer, width);
+ break;
+
+ case CUPS_CSPACE_K :
+ cupsCMYKDoBlack(CMYK, PixelBuffer, InputBuffer, width);
+ break;
+
+ default :
+ case CUPS_CSPACE_RGB :
+ if (RGB)
+ {
+ cupsRGBDoRGB(RGB, PixelBuffer, CMYKBuffer, width);
+ cupsCMYKDoCMYK(CMYK, CMYKBuffer, InputBuffer, width);
+ }
+ else
+ cupsCMYKDoRGB(CMYK, PixelBuffer, InputBuffer, width);
+ break;
+
+ case CUPS_CSPACE_CMYK :
+ cupsCMYKDoCMYK(CMYK, PixelBuffer, InputBuffer, width);
+ break;
+ }
+
+ /*
+ * Dither the pixels...
+ */
+
+ for (plane = 0; plane < PrinterPlanes; plane ++)
+ {
+ cupsDitherLine(DitherStates[plane], DitherLuts[plane], InputBuffer + plane,
+ PrinterPlanes, OutputBuffers[plane]);
+
+ if (DotRowMax == 1)
+ {
+ /*
+ * Handle microweaved output...
+ */
+
+ if (cupsCheckBytes(OutputBuffers[plane], width))
+ continue;
+
+ if (BitPlanes == 1)
+ cupsPackHorizontal(OutputBuffers[plane], DotBuffers[plane],
+ width, 0, 1);
+ else
+ cupsPackHorizontal2(OutputBuffers[plane], DotBuffers[plane],
+ width, 1);
+
+ if (OutputFeed > 0)
+ {
+ cupsWritePrintData("\033(v\002\000", 5);
+ putchar(OutputFeed & 255);
+ putchar(OutputFeed >> 8);
+ OutputFeed = 0;
+ }
+
+ CompressData(ppd, DotBuffers[plane], DotBufferSize, plane, 1, 1,
+ xstep, ystep, 0);
+ fflush(stdout);
+ }
+ else
+ {
+ /*
+ * Handle softweaved output...
+ */
+
+ for (pass = 0, subrow = y % DotRowStep;
+ pass < DotColStep;
+ pass ++, subrow += DotRowStep)
+ {
+ /*
+ * See if we need to output the band...
+ */
+
+ band = DotBands[subrow][plane];
+ offset = band->row * DotBufferSize;
+
+ if (BitPlanes == 1)
+ cupsPackHorizontal(OutputBuffers[plane] + pass,
+ band->buffer + offset, subwidth, 0, DotColStep);
+ else
+ cupsPackHorizontal2(OutputBuffers[plane] + pass,
+ band->buffer + offset, subwidth, DotColStep);
+
+ band->row ++;
+ band->dirty |= !cupsCheckBytes(band->buffer + offset, DotBufferSize);
+ if (band->row >= band->count)
+ {
+ if (band->dirty)
+ {
+ /*
+ * Dirty band needs to be added to the used list...
+ */
+
+ AddBand(band);
+
+ /*
+ * Then find a new band...
+ */
+
+ if (DotAvailList == NULL)
+ {
+ OutputBand(ppd, header, DotUsedList);
+
+ DotBands[subrow][plane] = DotUsedList;
+ DotUsedList->x = band->x;
+ DotUsedList->y = band->y + band->count * DotRowStep;
+ DotUsedList->plane = band->plane;
+ DotUsedList->row = 0;
+ DotUsedList->count = DotRowCount;
+ DotUsedList = DotUsedList->next;
+ }
+ else
+ {
+ DotBands[subrow][plane] = DotAvailList;
+ DotAvailList->x = band->x;
+ DotAvailList->y = band->y + band->count * DotRowStep;
+ DotAvailList->plane = band->plane;
+ DotAvailList->row = 0;
+ DotAvailList->count = DotRowCount;
+ DotAvailList = DotAvailList->next;
+ }
+ }
+ else
+ {
+ /*
+ * This band isn't dirty, so reuse it...
+ */
+
+ fprintf(stderr, "DEBUG: Blank band %p, x = %d, y = %d, plane = %d, count = %d\n",
+ band, band->x, band->y, band->plane, band->count);
+
+ band->y += band->count * DotRowStep;
+ band->row = 0;
+ band->count = DotRowCount;
+ }
+ }
+ }
+ }
+ }
+
+ if (DotRowMax == 1)
+ OutputFeed ++;
+}
+
+
+/*
+ * 'main()' - Main entry and processing of driver.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int fd; /* File descriptor */
+ cups_raster_t *ras; /* Raster stream for printing */
+ cups_page_header2_t header; /* Page header from file */
+ int page; /* Current page */
+ int y; /* Current line */
+ ppd_file_t *ppd; /* PPD file */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("%s job-id user title copies options [file]"),
+ "rastertoescpx");
+ return (1);
+ }
+
+ num_options = cupsParseOptions(argv[5], 0, &options);
+
+ /*
+ * Open the PPD file...
+ */
+
+ ppd = ppdOpenFile(getenv("PPD"));
+
+ if (!ppd)
+ {
+ ppd_status_t status; /* PPD error */
+ int linenum; /* Line number */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The PPD file could not be opened."));
+
+ status = ppdLastError(&linenum);
+
+ fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
+
+ return (1);
+ }
+
+ ppdMarkDefaults(ppd);
+ cupsMarkOptions(ppd, num_options, options);
+
+ /*
+ * Open the page stream...
+ */
+
+ if (argc == 7)
+ {
+ if ((fd = open(argv[6], O_RDONLY)) == -1)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open raster file"));
+ return (1);
+ }
+ }
+ else
+ fd = 0;
+
+ ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
+
+ /*
+ * Register a signal handler to eject the current page if the
+ * job is cancelled.
+ */
+
+ Canceled = 0;
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, CancelJob);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = CancelJob;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, CancelJob);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Initialize the print device...
+ */
+
+ Setup(ppd);
+
+ /*
+ * Process pages as needed...
+ */
+
+ page = 0;
+
+ while (cupsRasterReadHeader2(ras, &header))
+ {
+ /*
+ * Write a status message with the page number and number of copies.
+ */
+
+ if (Canceled)
+ break;
+
+ page ++;
+
+ fprintf(stderr, "PAGE: %d 1\n", page);
+ _cupsLangPrintFilter(stderr, "INFO", _("Starting page %d."), page);
+
+ StartPage(ppd, &header);
+
+ for (y = 0; y < header.cupsHeight; y ++)
+ {
+ /*
+ * Let the user know how far we have progressed...
+ */
+
+ if (Canceled)
+ break;
+
+ if ((y & 127) == 0)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printing page %d, %d%% complete."),
+ page, 100 * y / header.cupsHeight);
+ fprintf(stderr, "ATTR: job-media-progress=%d\n",
+ 100 * y / header.cupsHeight);
+ }
+
+ /*
+ * Read and write a line of graphics or whitespace...
+ */
+
+ ProcessLine(ppd, ras, &header, y);
+ }
+
+ /*
+ * Eject the page...
+ */
+
+ _cupsLangPrintFilter(stderr, "INFO", _("Finished page %d."), page);
+
+ EndPage(ppd, &header);
+
+ if (Canceled)
+ break;
+ }
+
+ Shutdown(ppd);
+
+ cupsFreeOptions(num_options, options);
+
+ cupsRasterClose(ras);
+
+ if (fd != 0)
+ close(fd);
+
+ if (page == 0)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("No pages were found."));
+ return (1);
+ }
+ else
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("Ready to print."));
+ return (0);
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/rastertopclx.c b/driver/rastertopclx.c
new file mode 100644
index 000000000..42f008220
--- /dev/null
+++ b/driver/rastertopclx.c
@@ -0,0 +1,1956 @@
+/*
+ * "$Id$"
+ *
+ * Advanced HP Page Control Language and Raster Transfer Language
+ * filter for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * StartPage() - Start a page of graphics.
+ * EndPage() - Finish a page of graphics.
+ * Shutdown() - Shutdown a printer.
+ * CancelJob() - Cancel the current job...
+ * CompressData() - Compress a line of graphics.
+ * OutputLine() - Output the specified number of lines of graphics.
+ * ReadLine() - Read graphics from the page stream.
+ * main() - Main entry and processing of driver.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "driver.h"
+#include <cups/language-private.h>
+#include <cups/string-private.h>
+#include "pcl-common.h"
+#include <signal.h>
+
+
+/*
+ * Output modes...
+ */
+
+typedef enum
+{
+ OUTPUT_BITMAP, /* Output bitmap data from RIP */
+ OUTPUT_INVERBIT, /* Output inverted bitmap data */
+ OUTPUT_RGB, /* Output 24-bit RGB data from RIP */
+ OUTPUT_DITHERED /* Output dithered data */
+} pcl_output_t;
+
+
+/*
+ * Globals...
+ */
+
+cups_rgb_t *RGB; /* RGB color separation data */
+cups_cmyk_t *CMYK; /* CMYK color separation data */
+unsigned char *PixelBuffer, /* Pixel buffer */
+ *CMYKBuffer, /* CMYK buffer */
+ *OutputBuffers[6], /* Output buffers */
+ *DotBuffers[6], /* Bit buffers */
+ *CompBuffer, /* Compression buffer */
+ *SeedBuffer, /* Mode 3 seed buffers */
+ BlankValue; /* The blank value */
+short *InputBuffer; /* Color separation buffer */
+cups_lut_t *DitherLuts[6]; /* Lookup tables for dithering */
+cups_dither_t *DitherStates[6]; /* Dither state tables */
+int PrinterPlanes, /* Number of color planes */
+ SeedInvalid, /* Contents of seed buffer invalid? */
+ DotBits[6], /* Number of bits per color */
+ DotBufferSizes[6], /* Size of one row of color dots */
+ DotBufferSize, /* Size of complete line */
+ OutputFeed, /* Number of lines to skip */
+ Page; /* Current page number */
+pcl_output_t OutputMode; /* Output mode - see OUTPUT_ consts */
+const int ColorOrders[7][7] = /* Order of color planes */
+ {
+ { 0, 0, 0, 0, 0, 0, 0 }, /* Black */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 1, 2, 0, 0, 0, 0 }, /* CMY */
+ { 3, 0, 1, 2, 0, 0, 0 }, /* KCMY */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 5, 0, 1, 2, 3, 4, 0 }, /* KCMYcm */
+ { 5, 0, 1, 2, 3, 4, 6 } /* KCMYcmk */
+ };
+int Canceled; /* Is the job canceled? */
+
+
+/*
+ * Prototypes...
+ */
+
+void StartPage(ppd_file_t *ppd, cups_page_header2_t *header, int job_id,
+ const char *user, const char *title, int num_options,
+ cups_option_t *options);
+void EndPage(ppd_file_t *ppd, cups_page_header2_t *header);
+void Shutdown(ppd_file_t *ppd, int job_id, const char *user,
+ const char *title, int num_options, cups_option_t *options);
+
+void CancelJob(int sig);
+void CompressData(unsigned char *line, int length, int plane, int pend,
+ int type);
+void OutputLine(ppd_file_t *ppd, cups_page_header2_t *header);
+int ReadLine(cups_raster_t *ras, cups_page_header2_t *header);
+
+
+/*
+ * 'StartPage()' - Start a page of graphics.
+ */
+
+void
+StartPage(ppd_file_t *ppd, /* I - PPD file */
+ cups_page_header2_t *header, /* I - Page header */
+ int job_id, /* I - Job ID */
+ const char *user, /* I - User printing job */
+ const char *title, /* I - Title of job */
+ int num_options,
+ /* I - Number of command-line options */
+ cups_option_t *options) /* I - Command-line options */
+{
+ int i; /* Temporary/looping var */
+ int plane; /* Current plane */
+ char s[255]; /* Temporary value */
+ const char *colormodel; /* Color model string */
+ char resolution[PPD_MAX_NAME],
+ /* Resolution string */
+ spec[PPD_MAX_NAME]; /* PPD attribute name */
+ ppd_attr_t *attr; /* Attribute from PPD file */
+ ppd_choice_t *choice; /* Selected option */
+ const int *order; /* Order to use */
+ int xorigin, /* X origin of page */
+ yorigin; /* Y origin of page */
+ static const float default_lut[2] = /* Default dithering lookup table */
+ {
+ 0.0,
+ 1.0
+ };
+
+
+ /*
+ * Debug info...
+ */
+
+ fprintf(stderr, "DEBUG: StartPage...\n");
+ fprintf(stderr, "DEBUG: MediaClass = \"%s\"\n", header->MediaClass);
+ fprintf(stderr, "DEBUG: MediaColor = \"%s\"\n", header->MediaColor);
+ fprintf(stderr, "DEBUG: MediaType = \"%s\"\n", header->MediaType);
+ fprintf(stderr, "DEBUG: OutputType = \"%s\"\n", header->OutputType);
+
+ fprintf(stderr, "DEBUG: AdvanceDistance = %d\n", header->AdvanceDistance);
+ fprintf(stderr, "DEBUG: AdvanceMedia = %d\n", header->AdvanceMedia);
+ fprintf(stderr, "DEBUG: Collate = %d\n", header->Collate);
+ fprintf(stderr, "DEBUG: CutMedia = %d\n", header->CutMedia);
+ fprintf(stderr, "DEBUG: Duplex = %d\n", header->Duplex);
+ fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", header->HWResolution[0],
+ header->HWResolution[1]);
+ fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
+ header->ImagingBoundingBox[0], header->ImagingBoundingBox[1],
+ header->ImagingBoundingBox[2], header->ImagingBoundingBox[3]);
+ fprintf(stderr, "DEBUG: InsertSheet = %d\n", header->InsertSheet);
+ fprintf(stderr, "DEBUG: Jog = %d\n", header->Jog);
+ fprintf(stderr, "DEBUG: LeadingEdge = %d\n", header->LeadingEdge);
+ fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", header->Margins[0],
+ header->Margins[1]);
+ fprintf(stderr, "DEBUG: ManualFeed = %d\n", header->ManualFeed);
+ fprintf(stderr, "DEBUG: MediaPosition = %d\n", header->MediaPosition);
+ fprintf(stderr, "DEBUG: MediaWeight = %d\n", header->MediaWeight);
+ fprintf(stderr, "DEBUG: MirrorPrint = %d\n", header->MirrorPrint);
+ fprintf(stderr, "DEBUG: NegativePrint = %d\n", header->NegativePrint);
+ fprintf(stderr, "DEBUG: NumCopies = %d\n", header->NumCopies);
+ fprintf(stderr, "DEBUG: Orientation = %d\n", header->Orientation);
+ fprintf(stderr, "DEBUG: OutputFaceUp = %d\n", header->OutputFaceUp);
+ fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", header->PageSize[0],
+ header->PageSize[1]);
+ fprintf(stderr, "DEBUG: Separations = %d\n", header->Separations);
+ fprintf(stderr, "DEBUG: TraySwitch = %d\n", header->TraySwitch);
+ fprintf(stderr, "DEBUG: Tumble = %d\n", header->Tumble);
+ fprintf(stderr, "DEBUG: cupsWidth = %d\n", header->cupsWidth);
+ fprintf(stderr, "DEBUG: cupsHeight = %d\n", header->cupsHeight);
+ fprintf(stderr, "DEBUG: cupsMediaType = %d\n", header->cupsMediaType);
+ fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header->cupsBitsPerColor);
+ fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header->cupsBitsPerPixel);
+ fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header->cupsBytesPerLine);
+ fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header->cupsColorOrder);
+ fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header->cupsColorSpace);
+ fprintf(stderr, "DEBUG: cupsCompression = %d\n", header->cupsCompression);
+
+#ifdef __APPLE__
+ /*
+ * MacOS X 10.2.x doesn't set most of the page device attributes, so check
+ * the options and set them accordingly...
+ */
+
+ if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble"))
+ {
+ header->Duplex = CUPS_TRUE;
+ header->Tumble = CUPS_FALSE;
+ }
+ else if (ppdIsMarked(ppd, "Duplex", "DuplexTumble"))
+ {
+ header->Duplex = CUPS_TRUE;
+ header->Tumble = CUPS_TRUE;
+ }
+
+ fprintf(stderr, "DEBUG: num_options=%d\n", num_options);
+
+ for (i = 0; i < num_options; i ++)
+ fprintf(stderr, "DEBUG: options[%d]=[\"%s\" \"%s\"]\n", i,
+ options[i].name, options[i].value);
+#endif /* __APPLE__ */
+
+ /*
+ * Figure out the color model and spec strings...
+ */
+
+ switch (header->cupsColorSpace)
+ {
+ case CUPS_CSPACE_K :
+ colormodel = "Black";
+ break;
+ case CUPS_CSPACE_W :
+ colormodel = "Gray";
+ break;
+ default :
+ case CUPS_CSPACE_RGB :
+ colormodel = "RGB";
+ break;
+ case CUPS_CSPACE_CMY :
+ colormodel = "CMY";
+ break;
+ case CUPS_CSPACE_CMYK :
+ colormodel = "CMYK";
+ break;
+ }
+
+ if (header->HWResolution[0] != header->HWResolution[1])
+ snprintf(resolution, sizeof(resolution), "%dx%ddpi",
+ header->HWResolution[0], header->HWResolution[1]);
+ else
+ snprintf(resolution, sizeof(resolution), "%ddpi",
+ header->HWResolution[0]);
+
+ if (!header->MediaType[0])
+ strcpy(header->MediaType, "PLAIN");
+
+ /*
+ * Get the dithering parameters...
+ */
+
+ BlankValue = 0x00;
+
+ if (header->cupsBitsPerColor == 1)
+ {
+ /*
+ * Use raw bitmap mode...
+ */
+
+ switch (header->cupsColorSpace)
+ {
+ case CUPS_CSPACE_K :
+ OutputMode = OUTPUT_BITMAP;
+ PrinterPlanes = 1;
+ break;
+ case CUPS_CSPACE_W :
+ OutputMode = OUTPUT_INVERBIT;
+ PrinterPlanes = 1;
+ break;
+ default :
+ case CUPS_CSPACE_RGB :
+ OutputMode = OUTPUT_INVERBIT;
+ PrinterPlanes = 3;
+ break;
+ case CUPS_CSPACE_CMY :
+ OutputMode = OUTPUT_BITMAP;
+ PrinterPlanes = 3;
+ break;
+ case CUPS_CSPACE_CMYK :
+ OutputMode = OUTPUT_BITMAP;
+ PrinterPlanes = 4;
+ break;
+ }
+
+ if (OutputMode == OUTPUT_INVERBIT)
+ BlankValue = 0xff;
+
+ DotBufferSize = header->cupsBytesPerLine;
+
+ memset(DitherLuts, 0, sizeof(DitherLuts));
+ memset(DitherStates, 0, sizeof(DitherStates));
+ }
+ else if (header->cupsColorSpace == CUPS_CSPACE_RGB &&
+ (ppd->model_number & PCL_RASTER_RGB24))
+ {
+ /*
+ * Use 24-bit RGB output mode...
+ */
+
+ OutputMode = OUTPUT_RGB;
+ PrinterPlanes = 3;
+ DotBufferSize = header->cupsBytesPerLine;
+
+ if (header->cupsCompression == 10)
+ BlankValue = 0xff;
+
+ memset(DitherLuts, 0, sizeof(DitherLuts));
+ memset(DitherStates, 0, sizeof(DitherStates));
+ }
+ else if ((header->cupsColorSpace == CUPS_CSPACE_K ||
+ header->cupsColorSpace == CUPS_CSPACE_W) &&
+ (ppd->model_number & PCL_RASTER_RGB24) &&
+ header->cupsCompression == 10)
+ {
+ /*
+ * Use 24-bit RGB output mode for grayscale/black output...
+ */
+
+ OutputMode = OUTPUT_RGB;
+ PrinterPlanes = 1;
+ DotBufferSize = header->cupsBytesPerLine;
+
+ if (header->cupsColorSpace == CUPS_CSPACE_W)
+ BlankValue = 0xff;
+
+ memset(DitherLuts, 0, sizeof(DitherLuts));
+ memset(DitherStates, 0, sizeof(DitherStates));
+ }
+ else
+ {
+ /*
+ * Use dithered output mode...
+ */
+
+ OutputMode = OUTPUT_DITHERED;
+
+ /*
+ * Load the appropriate color profiles...
+ */
+
+ RGB = NULL;
+ CMYK = NULL;
+
+ fputs("DEBUG: Attempting to load color profiles using the following values:\n", stderr);
+ fprintf(stderr, "DEBUG: ColorModel = %s\n", colormodel);
+ fprintf(stderr, "DEBUG: MediaType = %s\n", header->MediaType);
+ fprintf(stderr, "DEBUG: Resolution = %s\n", resolution);
+
+ if (header->cupsColorSpace == CUPS_CSPACE_RGB ||
+ header->cupsColorSpace == CUPS_CSPACE_W)
+ RGB = cupsRGBLoad(ppd, colormodel, header->MediaType, resolution);
+
+ CMYK = cupsCMYKLoad(ppd, colormodel, header->MediaType, resolution);
+
+ if (RGB)
+ fputs("DEBUG: Loaded RGB separation from PPD.\n", stderr);
+
+ if (CMYK)
+ fputs("DEBUG: Loaded CMYK separation from PPD.\n", stderr);
+ else
+ {
+ fputs("DEBUG: Loading default K separation.\n", stderr);
+ CMYK = cupsCMYKNew(1);
+ }
+
+ PrinterPlanes = CMYK->num_channels;
+
+ /*
+ * Use dithered mode...
+ */
+
+ switch (PrinterPlanes)
+ {
+ case 1 : /* K */
+ DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Black");
+ break;
+
+ case 3 : /* CMY */
+ DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Cyan");
+ DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Magenta");
+ DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Yellow");
+ break;
+
+ case 4 : /* CMYK */
+ DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Cyan");
+ DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Magenta");
+ DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Yellow");
+ DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Black");
+ break;
+
+ case 6 : /* CcMmYK */
+ DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Cyan");
+ DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "LightCyan");
+ DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Magenta");
+ DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "LightMagenta");
+ DitherLuts[4] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Yellow");
+ DitherLuts[5] = cupsLutLoad(ppd, colormodel, header->MediaType,
+ resolution, "Black");
+ break;
+ }
+
+ for (plane = 0; plane < PrinterPlanes; plane ++)
+ {
+ if (!DitherLuts[plane])
+ DitherLuts[plane] = cupsLutNew(2, default_lut);
+
+ if (DitherLuts[plane][4095].pixel > 1)
+ DotBits[plane] = 2;
+ else
+ DotBits[plane] = 1;
+
+ DitherStates[plane] = cupsDitherNew(header->cupsWidth);
+
+ if (!DitherLuts[plane])
+ DitherLuts[plane] = cupsLutNew(2, default_lut);
+ }
+ }
+
+ fprintf(stderr, "DEBUG: PrinterPlanes = %d\n", PrinterPlanes);
+
+ /*
+ * Initialize the printer...
+ */
+
+ if ((attr = ppdFindAttr(ppd, "cupsInitialNulls", NULL)) != NULL)
+ for (i = atoi(attr->value); i > 0; i --)
+ putchar(0);
+
+ if (Page == 1 && (ppd->model_number & PCL_PJL))
+ {
+ pjl_escape();
+
+ /*
+ * PJL job setup...
+ */
+
+ pjl_set_job(job_id, user, title);
+
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", "StartJob")) != NULL)
+ pjl_write(ppd, attr->value, NULL, job_id, user, title, num_options,
+ options);
+
+ snprintf(spec, sizeof(spec), "RENDERMODE.%s", colormodel);
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", spec)) != NULL)
+ printf("@PJL SET RENDERMODE=%s\r\n", attr->value);
+
+ snprintf(spec, sizeof(spec), "COLORSPACE.%s", colormodel);
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", spec)) != NULL)
+ printf("@PJL SET COLORSPACE=%s\r\n", attr->value);
+
+ snprintf(spec, sizeof(spec), "RENDERINTENT.%s", colormodel);
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", spec)) != NULL)
+ printf("@PJL SET RENDERINTENT=%s\r\n", attr->value);
+
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", "Duplex")) != NULL)
+ {
+ sprintf(s, "%d", header->Duplex);
+ pjl_write(ppd, attr->value, s, job_id, user, title, num_options, options);
+ }
+
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", "Tumble")) != NULL)
+ {
+ sprintf(s, "%d", header->Tumble);
+ pjl_write(ppd, attr->value, s, job_id, user, title, num_options, options);
+ }
+
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", "MediaClass")) != NULL)
+ pjl_write(ppd, attr->value, header->MediaClass, job_id, user, title,
+ num_options, options);
+
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", "MediaColor")) != NULL)
+ pjl_write(ppd, attr->value, header->MediaColor, job_id, user, title,
+ num_options, options);
+
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", "MediaType")) != NULL)
+ pjl_write(ppd, attr->value, header->MediaType, job_id, user, title,
+ num_options, options);
+
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", "OutputType")) != NULL)
+ pjl_write(ppd, attr->value, header->OutputType, job_id, user, title,
+ num_options, options);
+
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsBooklet")) != NULL &&
+ (choice = ppdFindMarkedChoice(ppd, "cupsBooklet")) != NULL)
+ pjl_write(ppd, attr->value, choice->choice, job_id, user, title,
+ num_options, options);
+
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", "Jog")) != NULL)
+ {
+ sprintf(s, "%d", header->Jog);
+ pjl_write(ppd, attr->value, s, job_id, user, title, num_options, options);
+ }
+
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsPunch")) != NULL &&
+ (choice = ppdFindMarkedChoice(ppd, "cupsPunch")) != NULL)
+ pjl_write(ppd, attr->value, choice->choice, job_id, user, title,
+ num_options, options);
+
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsStaple")) != NULL &&
+ (choice = ppdFindMarkedChoice(ppd, "cupsStaple")) != NULL)
+ pjl_write(ppd, attr->value, choice->choice, job_id, user, title,
+ num_options, options);
+
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsRET")) != NULL &&
+ (choice = ppdFindMarkedChoice(ppd, "cupsRET")) != NULL)
+ pjl_write(ppd, attr->value, choice->choice, job_id, user, title,
+ num_options, options);
+
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", "cupsTonerSave")) != NULL &&
+ (choice = ppdFindMarkedChoice(ppd, "cupsTonerSave")) != NULL)
+ pjl_write(ppd, attr->value, choice->choice, job_id, user, title,
+ num_options, options);
+
+ if (ppd->model_number & PCL_PJL_PAPERWIDTH)
+ {
+ printf("@PJL SET PAPERLENGTH=%d\r\n", header->PageSize[1] * 10);
+ printf("@PJL SET PAPERWIDTH=%d\r\n", header->PageSize[0] * 10);
+ }
+
+ if (ppd->model_number & PCL_PJL_RESOLUTION)
+ printf("@PJL SET RESOLUTION=%d\r\n", header->HWResolution[0]);
+
+ if (ppd->model_number & PCL_PJL_HPGL2)
+ pjl_enter_language("HPGL2");
+ else if (ppd->model_number & PCL_PJL_PCL3GUI)
+ pjl_enter_language("PCL3GUI");
+ else
+ pjl_enter_language("PCL");
+ }
+
+ if (Page == 1)
+ {
+ pcl_reset();
+ }
+
+ if (ppd->model_number & PCL_PJL_HPGL2)
+ {
+ if (Page == 1)
+ {
+ /*
+ * HP-GL/2 initialization...
+ */
+
+ printf("IN;");
+ printf("MG\"%d %s %s\";", job_id, user, title);
+ }
+
+ /*
+ * Set media size, position, type, etc...
+ */
+
+ printf("BP5,0;");
+ printf("PS%.0f,%.0f;",
+ header->cupsHeight * 1016.0 / header->HWResolution[1],
+ header->cupsWidth * 1016.0 / header->HWResolution[0]);
+ printf("PU;");
+ printf("PA0,0");
+
+ printf("MT%d;", header->cupsMediaType);
+
+ if (header->CutMedia == CUPS_CUT_PAGE)
+ printf("EC;");
+ else
+ printf("EC0;");
+
+ /*
+ * Set graphics mode...
+ */
+
+ pcl_set_pcl_mode(0);
+ pcl_set_negative_motion();
+ }
+ else
+ {
+ /*
+ * Set media size, position, type, etc...
+ */
+
+ if (!header->Duplex || (Page & 1))
+ {
+ pcl_set_media_size(ppd, header->PageSize[0], header->PageSize[1]);
+
+ if (header->MediaPosition)
+ pcl_set_media_source(header->MediaPosition);
+
+ pcl_set_media_type(header->cupsMediaType);
+
+ if (ppdFindAttr(ppd, "cupsPJL", "Duplex") == NULL)
+ pcl_set_duplex(header->Duplex, header->Tumble);
+
+ /*
+ * Set the number of copies...
+ */
+
+ if (!ppd->manual_copies)
+ pcl_set_copies(header->NumCopies);
+
+ /*
+ * Set the output order/bin...
+ */
+
+ if (ppdFindAttr(ppd, "cupsPJL", "Jog") == NULL && header->Jog)
+ printf("\033&l%dG", header->Jog);
+ }
+ else
+ {
+ /*
+ * Print on the back side...
+ */
+
+ printf("\033&a2G");
+ }
+
+ if (header->Duplex && (ppd->model_number & PCL_RASTER_CRD))
+ {
+ /*
+ * Reload the media...
+ */
+
+ pcl_set_media_source(-2);
+ }
+
+ /*
+ * Set the units for cursor positioning and go to the top of the form.
+ */
+
+ printf("\033&u%dD", header->HWResolution[0]);
+ printf("\033*p0Y\033*p0X");
+ }
+
+ if ((attr = cupsFindAttr(ppd, "cupsPCLQuality", colormodel,
+ header->MediaType, resolution, spec,
+ sizeof(spec))) != NULL)
+ {
+ /*
+ * Set the print quality...
+ */
+
+ if (ppd->model_number & PCL_PJL_HPGL2)
+ printf("QM%d", atoi(attr->value));
+ else
+ printf("\033*o%dM", atoi(attr->value));
+ }
+
+ /*
+ * Enter graphics mode...
+ */
+
+ if (ppd->model_number & PCL_RASTER_CRD)
+ {
+ /*
+ * Use configure raster data command...
+ */
+
+ if (OutputMode == OUTPUT_RGB)
+ {
+ /*
+ * Send 12-byte configure raster data command with horizontal and
+ * vertical resolutions as well as a color count...
+ */
+
+ if ((attr = cupsFindAttr(ppd, "cupsPCLCRDMode", colormodel,
+ header->MediaType, resolution, spec,
+ sizeof(spec))) != NULL)
+ i = atoi(attr->value);
+ else
+ i = 31;
+
+ printf("\033*g12W");
+ putchar(6); /* Format 6 */
+ putchar(i); /* Set pen mode */
+ putchar(0x00); /* Number components */
+ putchar(0x01); /* (1 for RGB) */
+
+ putchar(header->HWResolution[0] >> 8);
+ putchar(header->HWResolution[0]);
+ putchar(header->HWResolution[1] >> 8);
+ putchar(header->HWResolution[1]);
+
+ putchar(header->cupsCompression); /* Compression mode 3 or 10 */
+ putchar(0x01); /* Portrait orientation */
+ putchar(0x20); /* Bits per pixel (32 = RGB) */
+ putchar(0x01); /* Planes per pixel (1 = chunky RGB) */
+ }
+ else
+ {
+ /*
+ * Send the configure raster data command with horizontal and
+ * vertical resolutions as well as a color count...
+ */
+
+ printf("\033*g%dW", PrinterPlanes * 6 + 2);
+ putchar(2); /* Format 2 */
+ putchar(PrinterPlanes); /* Output planes */
+
+ order = ColorOrders[PrinterPlanes - 1];
+
+ for (i = 0; i < PrinterPlanes; i ++)
+ {
+ plane = order[i];
+
+ putchar(header->HWResolution[0] >> 8);
+ putchar(header->HWResolution[0]);
+ putchar(header->HWResolution[1] >> 8);
+ putchar(header->HWResolution[1]);
+ putchar(0);
+ putchar(1 << DotBits[plane]);
+ }
+ }
+ }
+ else if ((ppd->model_number & PCL_RASTER_CID) && OutputMode == OUTPUT_RGB)
+ {
+ /*
+ * Use configure image data command...
+ */
+
+ pcl_set_simple_resolution(header->HWResolution[0]);
+ /* Set output resolution */
+
+ cupsWritePrintData("\033*v6W\0\3\0\10\10\10", 11);
+ /* 24-bit RGB */
+ }
+ else
+ {
+ /*
+ * Use simple raster commands...
+ */
+
+ pcl_set_simple_resolution(header->HWResolution[0]);
+ /* Set output resolution */
+
+ if (PrinterPlanes == 3)
+ pcl_set_simple_cmy();
+ else if (PrinterPlanes == 4)
+ pcl_set_simple_kcmy();
+ }
+
+ if ((attr = ppdFindAttr(ppd, "cupsPCLOrigin", "X")) != NULL)
+ xorigin = atoi(attr->value);
+ else
+ xorigin = 0;
+
+ if ((attr = ppdFindAttr(ppd, "cupsPCLOrigin", "Y")) != NULL)
+ yorigin = atoi(attr->value);
+ else
+ yorigin = 120;
+
+ printf("\033&a%dH\033&a%dV", xorigin, yorigin);
+ printf("\033*r%dS", header->cupsWidth);
+ printf("\033*r%dT", header->cupsHeight);
+ printf("\033*r1A");
+
+ if (header->cupsCompression && header->cupsCompression != 10)
+ printf("\033*b%dM", header->cupsCompression);
+
+ OutputFeed = 0;
+
+ /*
+ * Allocate memory for the page...
+ */
+
+ PixelBuffer = malloc(header->cupsBytesPerLine);
+
+ if (OutputMode == OUTPUT_DITHERED)
+ {
+ InputBuffer = malloc(header->cupsWidth * PrinterPlanes * 2);
+ OutputBuffers[0] = malloc(PrinterPlanes * header->cupsWidth);
+
+ for (i = 1; i < PrinterPlanes; i ++)
+ OutputBuffers[i] = OutputBuffers[0] + i * header->cupsWidth;
+
+ if (RGB)
+ CMYKBuffer = malloc(header->cupsWidth * PrinterPlanes);
+
+ for (plane = 0, DotBufferSize = 0; plane < PrinterPlanes; plane ++)
+ {
+ DotBufferSizes[plane] = (header->cupsWidth + 7) / 8 * DotBits[plane];
+ DotBufferSize += DotBufferSizes[plane];
+ }
+
+ DotBuffers[0] = malloc(DotBufferSize);
+ for (plane = 1; plane < PrinterPlanes; plane ++)
+ DotBuffers[plane] = DotBuffers[plane - 1] + DotBufferSizes[plane - 1];
+ }
+
+ if (header->cupsCompression)
+ CompBuffer = malloc(DotBufferSize * 4);
+
+ if (header->cupsCompression >= 3)
+ SeedBuffer = malloc(DotBufferSize);
+
+ SeedInvalid = 1;
+
+ fprintf(stderr, "BlankValue=%d\n", BlankValue);
+}
+
+
+/*
+ * 'EndPage()' - Finish a page of graphics.
+ */
+
+void
+EndPage(ppd_file_t *ppd, /* I - PPD file */
+ cups_page_header2_t *header) /* I - Page header */
+{
+ int plane; /* Current plane */
+
+
+ /*
+ * End graphics mode...
+ */
+
+ if (ppd->model_number & PCL_RASTER_END_COLOR)
+ printf("\033*rC"); /* End color GFX */
+ else
+ printf("\033*r0B"); /* End B&W GFX */
+
+ /*
+ * Output a page eject sequence...
+ */
+
+ if (ppd->model_number & PCL_PJL_HPGL2)
+ {
+ pcl_set_hpgl_mode(0); /* Back to HP-GL/2 mode */
+ printf("PG;"); /* Eject the current page */
+ }
+ else if (!(header->Duplex && (Page & 1)))
+ printf("\014"); /* Eject current page */
+
+ /*
+ * Free memory for the page...
+ */
+
+ free(PixelBuffer);
+
+ if (OutputMode == OUTPUT_DITHERED)
+ {
+ for (plane = 0; plane < PrinterPlanes; plane ++)
+ {
+ cupsDitherDelete(DitherStates[plane]);
+ cupsLutDelete(DitherLuts[plane]);
+ }
+
+ free(DotBuffers[0]);
+ free(InputBuffer);
+ free(OutputBuffers[0]);
+
+ cupsCMYKDelete(CMYK);
+
+ if (RGB)
+ {
+ cupsRGBDelete(RGB);
+ free(CMYKBuffer);
+ }
+ }
+
+ if (header->cupsCompression)
+ free(CompBuffer);
+
+ if (header->cupsCompression >= 3)
+ free(SeedBuffer);
+}
+
+
+/*
+ * 'Shutdown()' - Shutdown a printer.
+ */
+
+void
+Shutdown(ppd_file_t *ppd, /* I - PPD file */
+ int job_id, /* I - Job ID */
+ const char *user, /* I - User printing job */
+ const char *title, /* I - Title of job */
+ int num_options,/* I - Number of command-line options */
+ cups_option_t *options) /* I - Command-line options */
+{
+ ppd_attr_t *attr; /* Attribute from PPD file */
+
+
+ if ((attr = ppdFindAttr(ppd, "cupsPCL", "EndJob")) != NULL)
+ {
+ /*
+ * Tell the printer how many pages were in the job...
+ */
+
+ putchar(0x1b);
+ printf(attr->value, Page);
+ }
+ else
+ {
+ /*
+ * Return the printer to the default state...
+ */
+
+ pcl_reset();
+ }
+
+ if (ppd->model_number & PCL_PJL)
+ {
+ pjl_escape();
+
+ if ((attr = ppdFindAttr(ppd, "cupsPJL", "EndJob")) != NULL)
+ pjl_write(ppd, attr->value, NULL, job_id, user, title, num_options,
+ options);
+ else
+ printf("@PJL EOJ\r\n");
+
+ pjl_escape();
+ }
+}
+
+
+/*
+ * 'CancelJob()' - Cancel the current job...
+ */
+
+void
+CancelJob(int sig) /* I - Signal */
+{
+ (void)sig;
+
+ Canceled = 1;
+}
+
+
+/*
+ * 'CompressData()' - Compress a line of graphics.
+ */
+
+void
+CompressData(unsigned char *line, /* I - Data to compress */
+ int length, /* I - Number of bytes */
+ int plane, /* I - Color plane */
+ int pend, /* I - End character for data */
+ int type) /* I - Type of compression */
+{
+ unsigned char *line_ptr, /* Current byte pointer */
+ *line_end, /* End-of-line byte pointer */
+ *comp_ptr, /* Pointer into compression buffer */
+ *start, /* Start of compression sequence */
+ *seed; /* Seed buffer pointer */
+ int count, /* Count of bytes for output */
+ offset, /* Offset of bytes for output */
+ temp; /* Temporary count */
+ int r, g, b; /* RGB deltas for mode 10 compression */
+
+
+ switch (type)
+ {
+ default :
+ /*
+ * Do no compression; with a mode-0 only printer, we can compress blank
+ * lines...
+ */
+
+ line_ptr = line;
+
+ if (cupsCheckBytes(line, length))
+ line_end = line; /* Blank line */
+ else
+ line_end = line + length; /* Non-blank line */
+ break;
+
+ case 1 :
+ /*
+ * Do run-length encoding...
+ */
+
+ line_end = line + length;
+ for (line_ptr = line, comp_ptr = CompBuffer;
+ line_ptr < line_end;
+ comp_ptr += 2, line_ptr += count)
+ {
+ for (count = 1;
+ (line_ptr + count) < line_end &&
+ line_ptr[0] == line_ptr[count] &&
+ count < 256;
+ count ++);
+
+ comp_ptr[0] = count - 1;
+ comp_ptr[1] = line_ptr[0];
+ }
+
+ line_ptr = CompBuffer;
+ line_end = comp_ptr;
+ break;
+
+ case 2 :
+ /*
+ * Do TIFF pack-bits encoding...
+ */
+
+ line_ptr = line;
+ line_end = line + length;
+ comp_ptr = CompBuffer;
+
+ while (line_ptr < line_end)
+ {
+ if ((line_ptr + 1) >= line_end)
+ {
+ /*
+ * Single byte on the end...
+ */
+
+ *comp_ptr++ = 0x00;
+ *comp_ptr++ = *line_ptr++;
+ }
+ else if (line_ptr[0] == line_ptr[1])
+ {
+ /*
+ * Repeated sequence...
+ */
+
+ line_ptr ++;
+ count = 2;
+
+ while (line_ptr < (line_end - 1) &&
+ line_ptr[0] == line_ptr[1] &&
+ count < 127)
+ {
+ line_ptr ++;
+ count ++;
+ }
+
+ *comp_ptr++ = 257 - count;
+ *comp_ptr++ = *line_ptr++;
+ }
+ else
+ {
+ /*
+ * Non-repeated sequence...
+ */
+
+ start = line_ptr;
+ line_ptr ++;
+ count = 1;
+
+ while (line_ptr < (line_end - 1) &&
+ line_ptr[0] != line_ptr[1] &&
+ count < 127)
+ {
+ line_ptr ++;
+ count ++;
+ }
+
+ *comp_ptr++ = count - 1;
+
+ memcpy(comp_ptr, start, count);
+ comp_ptr += count;
+ }
+ }
+
+ line_ptr = CompBuffer;
+ line_end = comp_ptr;
+ break;
+
+ case 3 :
+ /*
+ * Do delta-row compression...
+ */
+
+ line_ptr = line;
+ line_end = line + length;
+
+ comp_ptr = CompBuffer;
+ seed = SeedBuffer + plane * length;
+
+ while (line_ptr < line_end)
+ {
+ /*
+ * Find the next non-matching sequence...
+ */
+
+ start = line_ptr;
+
+ if (SeedInvalid)
+ {
+ /*
+ * The seed buffer is invalid, so do the next 8 bytes, max...
+ */
+
+ offset = 0;
+
+ if ((count = line_end - line_ptr) > 8)
+ count = 8;
+
+ line_ptr += count;
+ }
+ else
+ {
+ /*
+ * The seed buffer is valid, so compare against it...
+ */
+
+ while (*line_ptr == *seed &&
+ line_ptr < line_end)
+ {
+ line_ptr ++;
+ seed ++;
+ }
+
+ if (line_ptr == line_end)
+ break;
+
+ offset = line_ptr - start;
+
+ /*
+ * Find up to 8 non-matching bytes...
+ */
+
+ start = line_ptr;
+ count = 0;
+ while (*line_ptr != *seed &&
+ line_ptr < line_end &&
+ count < 8)
+ {
+ line_ptr ++;
+ seed ++;
+ count ++;
+ }
+ }
+
+ /*
+ * Place mode 3 compression data in the buffer; see HP manuals
+ * for details...
+ */
+
+ if (offset >= 31)
+ {
+ /*
+ * Output multi-byte offset...
+ */
+
+ *comp_ptr++ = ((count - 1) << 5) | 31;
+
+ offset -= 31;
+ while (offset >= 255)
+ {
+ *comp_ptr++ = 255;
+ offset -= 255;
+ }
+
+ *comp_ptr++ = offset;
+ }
+ else
+ {
+ /*
+ * Output single-byte offset...
+ */
+
+ *comp_ptr++ = ((count - 1) << 5) | offset;
+ }
+
+ memcpy(comp_ptr, start, count);
+ comp_ptr += count;
+ }
+
+ line_ptr = CompBuffer;
+ line_end = comp_ptr;
+
+ memcpy(SeedBuffer + plane * length, line, length);
+ break;
+
+ case 10 :
+ /*
+ * Mode 10 "near lossless" RGB compression...
+ */
+
+ line_ptr = line;
+ line_end = line + length;
+
+ comp_ptr = CompBuffer;
+ seed = SeedBuffer;
+
+ if (PrinterPlanes == 1)
+ {
+ /*
+ * Do grayscale compression to RGB...
+ */
+
+ while (line_ptr < line_end)
+ {
+ /*
+ * Find the next non-matching sequence...
+ */
+
+ start = line_ptr;
+ while (line_ptr < line_end &&
+ *line_ptr == *seed)
+ {
+ line_ptr ++;
+ seed ++;
+ }
+
+ if (line_ptr == line_end)
+ break;
+
+ offset = line_ptr - start;
+
+ /*
+ * Find non-matching grayscale pixels...
+ */
+
+ start = line_ptr;
+ while (line_ptr < line_end &&
+ *line_ptr != *seed)
+ {
+ line_ptr ++;
+ seed ++;
+ }
+
+ count = line_ptr - start;
+
+#if 0
+ fprintf(stderr, "DEBUG: offset=%d, count=%d, comp_ptr=%p(%d of %d)...\n",
+ offset, count, comp_ptr, comp_ptr - CompBuffer,
+ BytesPerLine * 5);
+#endif /* 0 */
+
+ /*
+ * Place mode 10 compression data in the buffer; each sequence
+ * starts with a command byte that looks like:
+ *
+ * CMD SRC SRC OFF OFF CNT CNT CNT
+ *
+ * For the purpose of this driver, CMD and SRC are always 0.
+ *
+ * If the offset >= 3 then additional offset bytes follow the
+ * first command byte, each byte == 255 until the last one.
+ *
+ * If the count >= 7, then additional count bytes follow each
+ * group of pixels, each byte == 255 until the last one.
+ *
+ * The offset and count are in RGB tuples (not bytes, as for
+ * Mode 3 and 9)...
+ */
+
+ if (offset >= 3)
+ {
+ /*
+ * Output multi-byte offset...
+ */
+
+ if (count > 7)
+ *comp_ptr++ = 0x1f;
+ else
+ *comp_ptr++ = 0x18 | (count - 1);
+
+ offset -= 3;
+ while (offset >= 255)
+ {
+ *comp_ptr++ = 255;
+ offset -= 255;
+ }
+
+ *comp_ptr++ = offset;
+ }
+ else
+ {
+ /*
+ * Output single-byte offset...
+ */
+
+ if (count > 7)
+ *comp_ptr++ = (offset << 3) | 0x07;
+ else
+ *comp_ptr++ = (offset << 3) | (count - 1);
+ }
+
+ temp = count - 8;
+ seed -= count;
+
+ while (count > 0)
+ {
+ if (count <= temp)
+ {
+ /*
+ * This is exceedingly lame... The replacement counts
+ * are intermingled with the data...
+ */
+
+ if (temp >= 255)
+ *comp_ptr++ = 255;
+ else
+ *comp_ptr++ = temp;
+
+ temp -= 255;
+ }
+
+ /*
+ * Get difference between current and see pixels...
+ */
+
+ r = *start - *seed;
+ g = r;
+ b = ((*start & 0xfe) - (*seed & 0xfe)) / 2;
+
+ if (r < -16 || r > 15 || g < -16 || g > 15 || b < -16 || b > 15)
+ {
+ /*
+ * Pack 24-bit RGB into 23 bits... Lame...
+ */
+
+ g = *start;
+
+ *comp_ptr++ = g >> 1;
+
+ if (g & 1)
+ *comp_ptr++ = 0x80 | (g >> 1);
+ else
+ *comp_ptr++ = g >> 1;
+
+ if (g & 1)
+ *comp_ptr++ = 0x80 | (g >> 1);
+ else
+ *comp_ptr++ = g >> 1;
+ }
+ else
+ {
+ /*
+ * Pack 15-bit RGB difference...
+ */
+
+ *comp_ptr++ = 0x80 | ((r << 2) & 0x7c) | ((g >> 3) & 0x03);
+ *comp_ptr++ = ((g << 5) & 0xe0) | (b & 0x1f);
+ }
+
+ count --;
+ start ++;
+ seed ++;
+ }
+
+ /*
+ * Make sure we have the ending count if the replacement count
+ * was exactly 8 + 255n...
+ */
+
+ if (temp == 0)
+ *comp_ptr++ = 0;
+ }
+ }
+ else
+ {
+ /*
+ * Do RGB compression...
+ */
+
+ while (line_ptr < line_end)
+ {
+ /*
+ * Find the next non-matching sequence...
+ */
+
+ start = line_ptr;
+ while (line_ptr[0] == seed[0] &&
+ line_ptr[1] == seed[1] &&
+ line_ptr[2] == seed[2] &&
+ (line_ptr + 2) < line_end)
+ {
+ line_ptr += 3;
+ seed += 3;
+ }
+
+ if (line_ptr == line_end)
+ break;
+
+ offset = (line_ptr - start) / 3;
+
+ /*
+ * Find non-matching RGB tuples...
+ */
+
+ start = line_ptr;
+ while ((line_ptr[0] != seed[0] ||
+ line_ptr[1] != seed[1] ||
+ line_ptr[2] != seed[2]) &&
+ (line_ptr + 2) < line_end)
+ {
+ line_ptr += 3;
+ seed += 3;
+ }
+
+ count = (line_ptr - start) / 3;
+
+ /*
+ * Place mode 10 compression data in the buffer; each sequence
+ * starts with a command byte that looks like:
+ *
+ * CMD SRC SRC OFF OFF CNT CNT CNT
+ *
+ * For the purpose of this driver, CMD and SRC are always 0.
+ *
+ * If the offset >= 3 then additional offset bytes follow the
+ * first command byte, each byte == 255 until the last one.
+ *
+ * If the count >= 7, then additional count bytes follow each
+ * group of pixels, each byte == 255 until the last one.
+ *
+ * The offset and count are in RGB tuples (not bytes, as for
+ * Mode 3 and 9)...
+ */
+
+ if (offset >= 3)
+ {
+ /*
+ * Output multi-byte offset...
+ */
+
+ if (count > 7)
+ *comp_ptr++ = 0x1f;
+ else
+ *comp_ptr++ = 0x18 | (count - 1);
+
+ offset -= 3;
+ while (offset >= 255)
+ {
+ *comp_ptr++ = 255;
+ offset -= 255;
+ }
+
+ *comp_ptr++ = offset;
+ }
+ else
+ {
+ /*
+ * Output single-byte offset...
+ */
+
+ if (count > 7)
+ *comp_ptr++ = (offset << 3) | 0x07;
+ else
+ *comp_ptr++ = (offset << 3) | (count - 1);
+ }
+
+ temp = count - 8;
+ seed -= count * 3;
+
+ while (count > 0)
+ {
+ if (count <= temp)
+ {
+ /*
+ * This is exceedingly lame... The replacement counts
+ * are intermingled with the data...
+ */
+
+ if (temp >= 255)
+ *comp_ptr++ = 255;
+ else
+ *comp_ptr++ = temp;
+
+ temp -= 255;
+ }
+
+ /*
+ * Get difference between current and see pixels...
+ */
+
+ r = start[0] - seed[0];
+ g = start[1] - seed[1];
+ b = ((start[2] & 0xfe) - (seed[2] & 0xfe)) / 2;
+
+ if (r < -16 || r > 15 || g < -16 || g > 15 || b < -16 || b > 15)
+ {
+ /*
+ * Pack 24-bit RGB into 23 bits... Lame...
+ */
+
+ *comp_ptr++ = start[0] >> 1;
+
+ if (start[0] & 1)
+ *comp_ptr++ = 0x80 | (start[1] >> 1);
+ else
+ *comp_ptr++ = start[1] >> 1;
+
+ if (start[1] & 1)
+ *comp_ptr++ = 0x80 | (start[2] >> 1);
+ else
+ *comp_ptr++ = start[2] >> 1;
+ }
+ else
+ {
+ /*
+ * Pack 15-bit RGB difference...
+ */
+
+ *comp_ptr++ = 0x80 | ((r << 2) & 0x7c) | ((g >> 3) & 0x03);
+ *comp_ptr++ = ((g << 5) & 0xe0) | (b & 0x1f);
+ }
+
+ count --;
+ start += 3;
+ seed += 3;
+ }
+
+ /*
+ * Make sure we have the ending count if the replacement count
+ * was exactly 8 + 255n...
+ */
+
+ if (temp == 0)
+ *comp_ptr++ = 0;
+ }
+ }
+
+ line_ptr = CompBuffer;
+ line_end = comp_ptr;
+
+ memcpy(SeedBuffer, line, length);
+ break;
+ }
+
+ /*
+ * Set the length of the data and write a raster plane...
+ */
+
+ printf("\033*b%d%c", (int)(line_end - line_ptr), pend);
+ cupsWritePrintData(line_ptr, line_end - line_ptr);
+}
+
+
+/*
+ * 'OutputLine()' - Output the specified number of lines of graphics.
+ */
+
+void
+OutputLine(ppd_file_t *ppd, /* I - PPD file */
+ cups_page_header2_t *header) /* I - Page header */
+{
+ int i, j; /* Looping vars */
+ int plane; /* Current plane */
+ unsigned char bit; /* Current bit */
+ int bytes; /* Number of bytes/plane */
+ int width; /* Width of line in pixels */
+ const int *order; /* Order to use */
+ unsigned char *ptr; /* Pointer into buffer */
+
+
+ /*
+ * Output whitespace as needed...
+ */
+
+ if (OutputFeed > 0)
+ {
+ if (header->cupsCompression < 3)
+ {
+ /*
+ * Send blank raster lines...
+ */
+
+ while (OutputFeed > 0)
+ {
+ printf("\033*b0W");
+ OutputFeed --;
+ }
+ }
+ else
+ {
+ /*
+ * Send Y offset command and invalidate the seed buffer...
+ */
+
+ printf("\033*b%dY", OutputFeed);
+ OutputFeed = 0;
+ SeedInvalid = 1;
+ }
+ }
+
+ /*
+ * Write bitmap data as needed...
+ */
+
+ switch (OutputMode)
+ {
+ case OUTPUT_BITMAP : /* Send 1-bit bitmap data... */
+ order = ColorOrders[PrinterPlanes - 1];
+ bytes = header->cupsBytesPerLine / PrinterPlanes;
+
+ for (i = 0; i < PrinterPlanes; i ++)
+ {
+ plane = order[i];
+
+ CompressData(PixelBuffer + i * bytes, bytes, plane,
+ (i < (PrinterPlanes - 1)) ? 'V' : 'W',
+ header->cupsCompression);
+ }
+ break;
+
+ case OUTPUT_INVERBIT : /* Send inverted 1-bit bitmap data... */
+ order = ColorOrders[PrinterPlanes - 1];
+ bytes = header->cupsBytesPerLine / PrinterPlanes;
+
+ for (i = header->cupsBytesPerLine, ptr = PixelBuffer;
+ i > 0;
+ i --, ptr ++)
+ *ptr = ~*ptr;
+
+ for (i = 0; i < PrinterPlanes; i ++)
+ {
+ plane = order[i];
+
+ CompressData(PixelBuffer + i * bytes, bytes, plane,
+ (i < (PrinterPlanes - 1)) ? 'V' : 'W',
+ header->cupsCompression);
+ }
+ break;
+
+ case OUTPUT_RGB : /* Send 24-bit RGB data... */
+ if (PrinterPlanes == 1 && !BlankValue)
+ {
+ /*
+ * Invert black to grayscale...
+ */
+
+ for (i = header->cupsBytesPerLine, ptr = PixelBuffer;
+ i > 0;
+ i --, ptr ++)
+ *ptr = ~*ptr;
+ }
+
+ /*
+ * Compress the output...
+ */
+
+ CompressData(PixelBuffer, header->cupsBytesPerLine, 0, 'W',
+ header->cupsCompression);
+ break;
+
+ default :
+ order = ColorOrders[PrinterPlanes - 1];
+ width = header->cupsWidth;
+
+ for (i = 0, j = 0; i < PrinterPlanes; i ++)
+ {
+ plane = order[i];
+ bytes = DotBufferSizes[plane] / DotBits[plane];
+
+ for (bit = 1, ptr = DotBuffers[plane];
+ bit <= DotBits[plane];
+ bit <<= 1, ptr += bytes, j ++)
+ {
+ cupsPackHorizontalBit(OutputBuffers[plane], DotBuffers[plane],
+ width, 0, bit);
+ CompressData(ptr, bytes, j,
+ i == (PrinterPlanes - 1) &&
+ bit == DotBits[plane] ? 'W' : 'V',
+ header->cupsCompression);
+ }
+ }
+ break;
+ }
+
+ /*
+ * The seed buffer, if any, now should contain valid data...
+ */
+
+ SeedInvalid = 0;
+}
+
+
+/*
+ * 'ReadLine()' - Read graphics from the page stream.
+ */
+
+int /* O - Number of lines (0 if blank) */
+ReadLine(cups_raster_t *ras, /* I - Raster stream */
+ cups_page_header2_t *header) /* I - Page header */
+{
+ int plane, /* Current color plane */
+ width; /* Width of line */
+
+
+ /*
+ * Read raster data...
+ */
+
+ cupsRasterReadPixels(ras, PixelBuffer, header->cupsBytesPerLine);
+
+ /*
+ * See if it is blank; if so, return right away...
+ */
+
+ if (cupsCheckValue(PixelBuffer, header->cupsBytesPerLine, BlankValue))
+ return (0);
+
+ /*
+ * If we aren't dithering, return immediately...
+ */
+
+ if (OutputMode != OUTPUT_DITHERED)
+ return (1);
+
+ /*
+ * Perform the color separation...
+ */
+
+ width = header->cupsWidth;
+
+ switch (header->cupsColorSpace)
+ {
+ case CUPS_CSPACE_W :
+ if (RGB)
+ {
+ cupsRGBDoGray(RGB, PixelBuffer, CMYKBuffer, width);
+
+ if (RGB->num_channels == 1)
+ cupsCMYKDoBlack(CMYK, CMYKBuffer, InputBuffer, width);
+ else
+ cupsCMYKDoCMYK(CMYK, CMYKBuffer, InputBuffer, width);
+ }
+ else
+ cupsCMYKDoGray(CMYK, PixelBuffer, InputBuffer, width);
+ break;
+
+ case CUPS_CSPACE_K :
+ cupsCMYKDoBlack(CMYK, PixelBuffer, InputBuffer, width);
+ break;
+
+ default :
+ case CUPS_CSPACE_RGB :
+ if (RGB)
+ {
+ cupsRGBDoRGB(RGB, PixelBuffer, CMYKBuffer, width);
+
+ if (RGB->num_channels == 1)
+ cupsCMYKDoBlack(CMYK, CMYKBuffer, InputBuffer, width);
+ else
+ cupsCMYKDoCMYK(CMYK, CMYKBuffer, InputBuffer, width);
+ }
+ else
+ cupsCMYKDoRGB(CMYK, PixelBuffer, InputBuffer, width);
+ break;
+
+ case CUPS_CSPACE_CMYK :
+ cupsCMYKDoCMYK(CMYK, PixelBuffer, InputBuffer, width);
+ break;
+ }
+
+ /*
+ * Dither the pixels...
+ */
+
+ for (plane = 0; plane < PrinterPlanes; plane ++)
+ cupsDitherLine(DitherStates[plane], DitherLuts[plane], InputBuffer + plane,
+ PrinterPlanes, OutputBuffers[plane]);
+
+ /*
+ * Return 1 to indicate that we have non-blank output...
+ */
+
+ return (1);
+}
+
+
+/*
+ * 'main()' - Main entry and processing of driver.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int fd; /* File descriptor */
+ cups_raster_t *ras; /* Raster stream for printing */
+ cups_page_header2_t header; /* Page header from file */
+ int y; /* Current line */
+ ppd_file_t *ppd; /* PPD file */
+ int job_id; /* Job ID */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("%s job-id user title copies options [file]"),
+ "rastertopclx");
+ return (1);
+ }
+
+ num_options = cupsParseOptions(argv[5], 0, &options);
+
+ /*
+ * Open the PPD file...
+ */
+
+ ppd = ppdOpenFile(getenv("PPD"));
+
+ if (!ppd)
+ {
+ ppd_status_t status; /* PPD error */
+ int linenum; /* Line number */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The PPD file could not be opened."));
+
+ status = ppdLastError(&linenum);
+
+ fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
+
+ return (1);
+ }
+
+ ppdMarkDefaults(ppd);
+ cupsMarkOptions(ppd, num_options, options);
+
+ /*
+ * Open the page stream...
+ */
+
+ if (argc == 7)
+ {
+ if ((fd = open(argv[6], O_RDONLY)) == -1)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open raster file"));
+ return (1);
+ }
+ }
+ else
+ fd = 0;
+
+ ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
+
+ /*
+ * Register a signal handler to eject the current page if the
+ * job is cancelled.
+ */
+
+ Canceled = 0;
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, CancelJob);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = CancelJob;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, CancelJob);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Process pages as needed...
+ */
+
+ job_id = atoi(argv[1]);
+
+ Page = 0;
+
+ while (cupsRasterReadHeader2(ras, &header))
+ {
+ /*
+ * Write a status message with the page number and number of copies.
+ */
+
+ if (Canceled)
+ break;
+
+ Page ++;
+
+ fprintf(stderr, "PAGE: %d %d\n", Page, header.NumCopies);
+ _cupsLangPrintFilter(stderr, "INFO", _("Starting page %d."), Page);
+
+ StartPage(ppd, &header, atoi(argv[1]), argv[2], argv[3],
+ num_options, options);
+
+ for (y = 0; y < (int)header.cupsHeight; y ++)
+ {
+ /*
+ * Let the user know how far we have progressed...
+ */
+
+ if (Canceled)
+ break;
+
+ if ((y & 127) == 0)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printing page %d, %d%% complete."),
+ Page, 100 * y / header.cupsHeight);
+ fprintf(stderr, "ATTR: job-media-progress=%d\n",
+ 100 * y / header.cupsHeight);
+ }
+
+ /*
+ * Read and write a line of graphics or whitespace...
+ */
+
+ if (ReadLine(ras, &header))
+ OutputLine(ppd, &header);
+ else
+ OutputFeed ++;
+ }
+
+ /*
+ * Eject the page...
+ */
+
+ _cupsLangPrintFilter(stderr, "INFO", _("Finished page %d."), Page);
+
+ EndPage(ppd, &header);
+
+ if (Canceled)
+ break;
+ }
+
+ Shutdown(ppd, job_id, argv[2], argv[3], num_options, options);
+
+ cupsFreeOptions(num_options, options);
+
+ cupsRasterClose(ras);
+
+ if (fd != 0)
+ close(fd);
+
+ if (Page == 0)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("No pages were found."));
+ return (1);
+ }
+ else
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("Ready to print."));
+ return (0);
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/rgb.c b/driver/rgb.c
new file mode 100644
index 000000000..fd0b117a5
--- /dev/null
+++ b/driver/rgb.c
@@ -0,0 +1,558 @@
+/*
+ * "$Id$"
+ *
+ * RGB color separation code for CUPS.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsRGBDelete() - Delete a color separation.
+ * cupsRGBDoGray() - Do a grayscale separation...
+ * cupsRGBDoRGB() - Do a RGB separation...
+ * cupsRGBLoad() - Load a RGB color profile from a PPD file.
+ * cupsRGBNew() - Create a new RGB color separation.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "driver.h"
+
+
+/*
+ * 'cupsRGBDelete()' - Delete a color separation.
+ */
+
+void
+cupsRGBDelete(cups_rgb_t *rgbptr) /* I - Color separation */
+{
+ if (rgbptr == NULL)
+ return;
+
+ free(rgbptr->colors[0][0][0]);
+ free(rgbptr->colors[0][0]);
+ free(rgbptr->colors[0]);
+ free(rgbptr->colors);
+ free(rgbptr);
+}
+
+
+/*
+ * 'cupsRGBDoGray()' - Do a grayscale separation...
+ */
+
+void
+cupsRGBDoGray(cups_rgb_t *rgbptr,
+ /* I - Color separation */
+ const unsigned char *input,
+ /* I - Input grayscale pixels */
+ unsigned char *output,
+ /* O - Output Device-N pixels */
+ int num_pixels)
+ /* I - Number of pixels */
+{
+ int i; /* Looping var */
+ int lastgray; /* Previous grayscale */
+ int xs, ys, zs, /* Current RGB row offsets */
+ g, gi, gm0, gm1;/* Current gray index and multipliers ... */
+ const unsigned char *color; /* Current color data */
+ int tempg; /* Current separation color */
+ int rgbsize; /* Separation data size */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!rgbptr || !input || !output || num_pixels <= 0)
+ return;
+
+ /*
+ * Initialize variables used for the duration of the separation...
+ */
+
+ lastgray = -1;
+ rgbsize = rgbptr->num_channels;
+ xs = rgbptr->cube_size * rgbptr->cube_size * rgbptr->num_channels;
+ ys = rgbptr->cube_size * rgbptr->num_channels;
+ zs = rgbptr->num_channels;
+
+ /*
+ * Loop through it all...
+ */
+
+ while (num_pixels > 0)
+ {
+ /*
+ * See if the next pixel is a cached value...
+ */
+
+ num_pixels --;
+
+ g = cups_srgb_lut[*input++];
+
+ if (g == lastgray)
+ {
+ /*
+ * Copy previous color and continue...
+ */
+
+ memcpy(output, output - rgbptr->num_channels, rgbsize);
+
+ output += rgbptr->num_channels;
+ continue;
+ }
+ else if (g == 0x00 && rgbptr->cache_init)
+ {
+ /*
+ * Copy black color and continue...
+ */
+
+ memcpy(output, rgbptr->black, rgbsize);
+
+ output += rgbptr->num_channels;
+ continue;
+ }
+ else if (g == 0xff && rgbptr->cache_init)
+ {
+ /*
+ * Copy white color and continue...
+ */
+
+ memcpy(output, rgbptr->white, rgbsize);
+
+ output += rgbptr->num_channels;
+ continue;
+ }
+
+ /*
+ * Nope, figure this one out on our own...
+ */
+
+ gi = rgbptr->cube_index[g];
+ gm0 = rgbptr->cube_mult[g];
+ gm1 = 256 - gm0;
+
+ color = rgbptr->colors[gi][gi][gi];
+
+ for (i = 0; i < rgbptr->num_channels; i ++, color ++)
+ {
+ tempg = (color[0] * gm0 + color[xs + ys + zs] * gm1) / 256;
+
+ if (tempg > 255)
+ *output++ = 255;
+ else if (tempg < 0)
+ *output++ = 0;
+ else
+ *output++ = tempg;
+ }
+ }
+}
+
+
+/*
+ * 'cupsRGBDoRGB()' - Do a RGB separation...
+ */
+
+void
+cupsRGBDoRGB(cups_rgb_t *rgbptr,
+ /* I - Color separation */
+ const unsigned char *input,
+ /* I - Input RGB pixels */
+ unsigned char *output,
+ /* O - Output Device-N pixels */
+ int num_pixels)
+ /* I - Number of pixels */
+{
+ int i; /* Looping var */
+ int rgb, /* Current RGB color */
+ lastrgb; /* Previous RGB color */
+ int r, ri, rm0, rm1, rs,
+ /* Current red index, multipliexs, and row offset */
+ g, gi, gm0, gm1, gs,
+ /* Current green ... */
+ b, bi, bm0, bm1, bs;
+ /* Current blue ... */
+ const unsigned char *color; /* Current color data */
+ int tempr, /* Current separation colors */
+ tempg, /* ... */
+ tempb ; /* ... */
+ int rgbsize; /* Separation data size */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!rgbptr || !input || !output || num_pixels <= 0)
+ return;
+
+ /*
+ * Initialize variables used for the duration of the separation...
+ */
+
+ lastrgb = -1;
+ rgbsize = rgbptr->num_channels;
+ rs = rgbptr->cube_size * rgbptr->cube_size * rgbptr->num_channels;
+ gs = rgbptr->cube_size * rgbptr->num_channels;
+ bs = rgbptr->num_channels;
+
+ /*
+ * Loop through it all...
+ */
+
+ while (num_pixels > 0)
+ {
+ /*
+ * See if the next pixel is a cached value...
+ */
+
+ num_pixels --;
+
+ r = cups_srgb_lut[*input++];
+ g = cups_srgb_lut[*input++];
+ b = cups_srgb_lut[*input++];
+ rgb = (((r << 8) | g) << 8) | b;
+
+ if (rgb == lastrgb)
+ {
+ /*
+ * Copy previous color and continue...
+ */
+
+ memcpy(output, output - rgbptr->num_channels, rgbsize);
+
+ output += rgbptr->num_channels;
+ continue;
+ }
+ else if (rgb == 0x000000 && rgbptr->cache_init)
+ {
+ /*
+ * Copy black color and continue...
+ */
+
+ memcpy(output, rgbptr->black, rgbsize);
+
+ output += rgbptr->num_channels;
+ continue;
+ }
+ else if (rgb == 0xffffff && rgbptr->cache_init)
+ {
+ /*
+ * Copy white color and continue...
+ */
+
+ memcpy(output, rgbptr->white, rgbsize);
+
+ output += rgbptr->num_channels;
+ continue;
+ }
+
+ /*
+ * Nope, figure this one out on our own...
+ */
+
+ ri = rgbptr->cube_index[r];
+ rm0 = rgbptr->cube_mult[r];
+ rm1 = 256 - rm0;
+
+ gi = rgbptr->cube_index[g];
+ gm0 = rgbptr->cube_mult[g];
+ gm1 = 256 - gm0;
+
+ bi = rgbptr->cube_index[b];
+ bm0 = rgbptr->cube_mult[b];
+ bm1 = 256 - bm0;
+
+ color = rgbptr->colors[ri][gi][bi];
+
+ for (i = rgbptr->num_channels; i > 0; i --, color ++)
+ {
+ tempb = (color[0] * bm0 + color[bs] * bm1) / 256;
+ tempg = tempb * gm0;
+ tempb = (color[gs] * gm0 + color[gs + bs] * bm1) / 256;
+ tempg = (tempg + tempb * gm1) / 256;
+
+ tempr = tempg * rm0;
+
+ tempb = (color[rs] * bm0 + color[rs + bs] * bm1) / 256;
+ tempg = tempb * gm0;
+ tempb = (color[rs + gs] * bm0 + color[rs + gs + bs] * bm1) / 256;
+ tempg = (tempg + tempb * gm1) / 256;
+
+ tempr = (tempr + tempg * rm1) / 256;
+
+ if (tempr > 255)
+ *output++ = 255;
+ else if (tempr < 0)
+ *output++ = 0;
+ else
+ *output++ = tempr;
+ }
+ }
+}
+
+
+/*
+ * 'cupsRGBLoad()' - Load a RGB color profile from a PPD file.
+ */
+
+cups_rgb_t * /* O - New color profile */
+cupsRGBLoad(ppd_file_t *ppd, /* I - PPD file */
+ const char *colormodel, /* I - Color model */
+ const char *media, /* I - Media type */
+ const char *resolution) /* I - Resolution */
+{
+ int i, /* Looping var */
+ cube_size, /* Size of color lookup cube */
+ num_channels, /* Number of color channels */
+ num_samples; /* Number of color samples */
+ cups_sample_t *samples; /* Color samples */
+ float values[7]; /* Color sample values */
+ char spec[PPD_MAX_NAME]; /* Profile name */
+ ppd_attr_t *attr; /* Attribute from PPD file */
+ cups_rgb_t *rgbptr; /* RGB color profile */
+
+
+ /*
+ * Find the following attributes:
+ *
+ * cupsRGBProfile - Specifies the cube size, number of channels, and
+ * number of samples
+ * cupsRGBSample - Specifies an RGB to CMYK color sample
+ */
+
+ if ((attr = cupsFindAttr(ppd, "cupsRGBProfile", colormodel, media,
+ resolution, spec, sizeof(spec))) == NULL)
+ {
+ fputs("DEBUG2: No cupsRGBProfile attribute found for the current settings!\n", stderr);
+ return (NULL);
+ }
+
+ if (!attr->value || sscanf(attr->value, "%d%d%d", &cube_size, &num_channels,
+ &num_samples) != 3)
+ {
+ fprintf(stderr, "ERROR: Bad cupsRGBProfile attribute \'%s\'!\n",
+ attr->value ? attr->value : "(null)");
+ return (NULL);
+ }
+
+ if (cube_size < 2 || cube_size > 16 ||
+ num_channels < 1 || num_channels > CUPS_MAX_RGB ||
+ num_samples != (cube_size * cube_size * cube_size))
+ {
+ fprintf(stderr, "ERROR: Bad cupsRGBProfile attribute \'%s\'!\n",
+ attr->value);
+ return (NULL);
+ }
+
+ /*
+ * Allocate memory for the samples and read them...
+ */
+
+ if ((samples = calloc(num_samples, sizeof(cups_sample_t))) == NULL)
+ {
+ fputs("ERROR: Unable to allocate memory for RGB profile!\n", stderr);
+ return (NULL);
+ }
+
+ /*
+ * Read all of the samples...
+ */
+
+ for (i = 0; i < num_samples; i ++)
+ if ((attr = ppdFindNextAttr(ppd, "cupsRGBSample", spec)) == NULL)
+ break;
+ else if (!attr->value)
+ {
+ fputs("ERROR: Bad cupsRGBSample value!\n", stderr);
+ break;
+ }
+ else if (sscanf(attr->value, "%f%f%f%f%f%f%f", values + 0,
+ values + 1, values + 2, values + 3, values + 4, values + 5,
+ values + 6) != (3 + num_channels))
+ {
+ fputs("ERROR: Bad cupsRGBSample value!\n", stderr);
+ break;
+ }
+ else
+ {
+ samples[i].rgb[0] = (int)(255.0 * values[0] + 0.5);
+ samples[i].rgb[1] = (int)(255.0 * values[1] + 0.5);
+ samples[i].rgb[2] = (int)(255.0 * values[2] + 0.5);
+ samples[i].colors[0] = (int)(255.0 * values[3] + 0.5);
+ if (num_channels > 1)
+ samples[i].colors[1] = (int)(255.0 * values[4] + 0.5);
+ if (num_channels > 2)
+ samples[i].colors[2] = (int)(255.0 * values[5] + 0.5);
+ if (num_channels > 3)
+ samples[i].colors[3] = (int)(255.0 * values[6] + 0.5);
+ }
+
+ /*
+ * If everything went OK, create the color profile...
+ */
+
+ if (i == num_samples)
+ rgbptr = cupsRGBNew(num_samples, samples, cube_size, num_channels);
+ else
+ rgbptr = NULL;
+
+ /*
+ * Free the temporary sample array and return...
+ */
+
+ free(samples);
+
+ return (rgbptr);
+}
+
+
+/*
+ * 'cupsRGBNew()' - Create a new RGB color separation.
+ */
+
+cups_rgb_t * /* O - New color separation or NULL */
+cupsRGBNew(int num_samples, /* I - Number of samples */
+ cups_sample_t *samples, /* I - Samples */
+ int cube_size, /* I - Size of LUT cube */
+ int num_channels) /* I - Number of color components */
+{
+ cups_rgb_t *rgbptr; /* New color separation */
+ int i; /* Looping var */
+ int r, g, b; /* Current RGB */
+ int tempsize; /* Sibe of main arrays */
+ unsigned char *tempc; /* Pointer for C arrays */
+ unsigned char **tempb ; /* Pointer for Z arrays */
+ unsigned char ***tempg; /* Pointer for Y arrays */
+ unsigned char ****tempr; /* Pointer for X array */
+ unsigned char rgb[3]; /* Temporary RGB value */
+
+
+ /*
+ * Range-check the input...
+ */
+
+ if (!samples || num_samples != (cube_size * cube_size * cube_size) ||
+ num_channels <= 0 || num_channels > CUPS_MAX_RGB)
+ return (NULL);
+
+ /*
+ * Allocate memory for the separation...
+ */
+
+ if ((rgbptr = calloc(1, sizeof(cups_rgb_t))) == NULL)
+ return (NULL);
+
+ /*
+ * Allocate memory for the samples and the LUT cube...
+ */
+
+ tempsize = cube_size * cube_size * cube_size; /* FUTURE: num_samples < cs^3 */
+
+ tempc = calloc(tempsize, num_channels);
+ tempb = calloc(tempsize, sizeof(unsigned char *));
+ tempg = calloc(cube_size * cube_size, sizeof(unsigned char **));
+ tempr = calloc(cube_size, sizeof(unsigned char ***));
+
+ if (tempc == NULL || tempb == NULL || tempg == NULL || tempr == NULL)
+ {
+ free(rgbptr);
+
+ if (tempc)
+ free(tempc);
+
+ if (tempb)
+ free(tempb);
+
+ if (tempg)
+ free(tempg);
+
+ if (tempr)
+ free(tempr);
+
+ return (NULL);
+ }
+
+ /*
+ * Fill in the arrays...
+ */
+
+ for (i = 0, r = 0; r < cube_size; r ++)
+ {
+ tempr[r] = tempg + r * cube_size;
+
+ for (g = 0; g < cube_size; g ++)
+ {
+ tempr[r][g] = tempb + i;
+
+ for (b = 0; b < cube_size; b ++, i ++)
+ tempr[r][g][b] = tempc + i * num_channels;
+ }
+ }
+
+ for (i = 0; i < num_samples; i ++)
+ {
+ r = samples[i].rgb[0] * (cube_size - 1) / 255;
+ g = samples[i].rgb[1] * (cube_size - 1) / 255;
+ b = samples[i].rgb[2] * (cube_size - 1) / 255;
+
+ memcpy(tempr[r][g][b], samples[i].colors, num_channels);
+ }
+
+ rgbptr->cube_size = cube_size;
+ rgbptr->num_channels = num_channels;
+ rgbptr->colors = tempr;
+
+ /*
+ * Generate the lookup tables for the cube indices and multipliers...
+ */
+
+ for (i = 0; i < 256; i ++)
+ {
+ rgbptr->cube_index[i] = i * (cube_size - 1) / 256;
+
+ if (i == 0)
+ rgbptr->cube_mult[i] = 256;
+ else
+ rgbptr->cube_mult[i] = 255 - ((i * (cube_size - 1)) & 255);
+ }
+
+ /*
+ * Generate the black and white cache values for the separation...
+ */
+
+ rgb[0] = 0;
+ rgb[1] = 0;
+ rgb[2] = 0;
+
+ cupsRGBDoRGB(rgbptr, rgb, rgbptr->black, 1);
+
+ rgb[0] = 255;
+ rgb[1] = 255;
+ rgb[2] = 255;
+
+ cupsRGBDoRGB(rgbptr, rgb, rgbptr->white, 1);
+
+ rgbptr->cache_init = 1;
+
+ /*
+ * Return the separation...
+ */
+
+ return (rgbptr);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/srgb.c b/driver/srgb.c
new file mode 100644
index 000000000..0354f23e5
--- /dev/null
+++ b/driver/srgb.c
@@ -0,0 +1,79 @@
+/*
+ * "$Id$"
+ *
+ * sRGB lookup tables for CUPS.
+ *
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "driver.h"
+
+
+/*
+ * sRGB gamma lookup table.
+ */
+
+const unsigned char cups_srgb_lut[256] =
+{
+ 0, 20, 28, 33, 38, 42, 46, 49, 52, 55, 58, 61, 63, 65, 68,
+ 70, 72, 74, 76, 78, 80, 81, 83, 85, 87, 88, 90, 91, 93, 94,
+ 96, 97, 99, 100, 102, 103, 104, 106, 107, 108, 109, 111, 112, 113, 114,
+ 115, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128, 129, 130, 131,
+ 132, 133, 134, 135, 136, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145,
+ 146, 147, 147, 148, 149, 150, 151, 152, 153, 153, 154, 155, 156, 157, 158,
+ 158, 159, 160, 161, 162, 162, 163, 164, 165, 165, 166, 167, 168, 168, 169,
+ 170, 171, 171, 172, 173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 180,
+ 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190,
+ 190, 191, 192, 192, 193, 194, 194, 195, 196, 196, 197, 197, 198, 199, 199,
+ 200, 200, 201, 202, 202, 203, 203, 204, 205, 205, 206, 206, 207, 208, 208,
+ 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 214, 215, 216, 216, 217,
+ 217, 218, 218, 219, 219, 220, 220, 221, 222, 222, 223, 223, 224, 224, 225,
+ 225, 226, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232,
+ 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 239, 240,
+ 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247,
+ 248, 248, 249, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254,
+ 255
+};
+
+
+/*
+ * sRGB gamma lookup table (inverted output to map to CMYK...)
+ */
+
+const unsigned char cups_scmy_lut[256] =
+{
+ 255, 235, 227, 222, 217, 213, 209, 206, 203, 200, 197, 194, 192, 190, 187,
+ 185, 183, 181, 179, 177, 175, 174, 172, 170, 168, 167, 165, 164, 162, 161,
+ 159, 158, 156, 155, 153, 152, 151, 149, 148, 147, 146, 144, 143, 142, 141,
+ 140, 138, 137, 136, 135, 134, 133, 132, 131, 130, 129, 127, 126, 125, 124,
+ 123, 122, 121, 120, 119, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110,
+ 109, 108, 108, 107, 106, 105, 104, 103, 102, 102, 101, 100, 99, 98, 97,
+ 97, 96, 95, 94, 93, 93, 92, 91, 90, 90, 89, 88, 87, 87, 86,
+ 85, 84, 84, 83, 82, 81, 81, 80, 79, 79, 78, 77, 77, 76, 75,
+ 74, 74, 73, 72, 72, 71, 70, 70, 69, 68, 68, 67, 66, 66, 65,
+ 65, 64, 63, 63, 62, 61, 61, 60, 59, 59, 58, 58, 57, 56, 56,
+ 55, 55, 54, 53, 53, 52, 52, 51, 50, 50, 49, 49, 48, 47, 47,
+ 46, 46, 45, 45, 44, 43, 43, 42, 42, 41, 41, 40, 39, 39, 38,
+ 38, 37, 37, 36, 36, 35, 35, 34, 33, 33, 32, 32, 31, 31, 30,
+ 30, 29, 29, 28, 28, 27, 27, 26, 26, 25, 25, 24, 24, 23, 23,
+ 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16, 16, 15,
+ 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8,
+ 7, 7, 6, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1,
+ 0
+};
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/testcmyk.c b/driver/testcmyk.c
new file mode 100644
index 000000000..97bac6f47
--- /dev/null
+++ b/driver/testcmyk.c
@@ -0,0 +1,437 @@
+/*
+ * "$Id$"
+ *
+ * Test the CMYK color separation code for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2006 by Easy Software Products, All Rights Reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * test_gray() - Test grayscale separations...
+ * test_rgb() - Test color separations...
+ * main() - Do color separation tests.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <cups/string-private.h>
+#include "driver.h"
+#include <sys/stat.h>
+
+
+void test_gray(int num_comps, const char *basename);
+void test_rgb(int num_comps, const char *basename);
+
+
+/*
+ * 'main()' - Do color separation tests.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ /*
+ * Make the test directory...
+ */
+
+ mkdir("test", 0755);
+
+ /*
+ * Run tests for K, Kk, CMY, CMYK, CcMmYK, and CcMmYKk separations...
+ */
+
+ test_rgb(1, "test/K-rgb");
+ test_rgb(2, "test/Kk-rgb");
+ test_rgb(3, "test/CMY-rgb");
+ test_rgb(4, "test/CMYK-rgb");
+ test_rgb(6, "test/CcMmYK-rgb");
+ test_rgb(7, "test/CcMmYKk-rgb");
+
+ test_gray(1, "test/K-gray");
+ test_gray(2, "test/Kk-gray");
+ test_gray(3, "test/CMY-gray");
+ test_gray(4, "test/CMYK-gray");
+ test_gray(6, "test/CcMmYK-gray");
+ test_gray(7, "test/CcMmYKk-gray");
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'test_gray()' - Test grayscale separations...
+ */
+
+void
+test_gray(int num_comps, /* I - Number of components */
+ const char *basename) /* I - Base filename of output */
+{
+ int i; /* Looping var */
+ char filename[255]; /* Output filename */
+ char line[255]; /* Line from PGM file */
+ int width, height; /* Width and height of test image */
+ int x, y; /* Current coordinate in image */
+ int r, g, b; /* Current RGB color */
+ unsigned char input[7000]; /* Line to separate */
+ short output[48000], /* Output separation data */
+ *outptr; /* Pointer in output */
+ FILE *in; /* Input PPM file */
+ FILE *out[CUPS_MAX_CHAN];
+ /* Output PGM files */
+ FILE *comp; /* Composite output */
+ cups_cmyk_t *cmyk; /* Color separation */
+
+
+ /*
+ * Open the test image...
+ */
+
+ in = fopen("image.pgm", "rb");
+ while (fgets(line, sizeof(line), in) != NULL)
+ if (isdigit(line[0]))
+ break;
+
+ sscanf(line, "%d%d", &width, &height);
+
+ fgets(line, sizeof(line), in);
+
+ /*
+ * Create the color separation...
+ */
+
+ cmyk = cupsCMYKNew(num_comps);
+
+ switch (num_comps)
+ {
+ case 2 : /* Kk */
+ cupsCMYKSetLtDk(cmyk, 0, 0.5, 1.0);
+ break;
+
+ case 4 :
+ cupsCMYKSetGamma(cmyk, 2, 1.0, 0.9);
+ cupsCMYKSetBlack(cmyk, 0.5, 1.0);
+ break;
+
+ case 6 : /* CcMmYK */
+ cupsCMYKSetLtDk(cmyk, 0, 0.5, 1.0);
+ cupsCMYKSetLtDk(cmyk, 2, 0.5, 1.0);
+ cupsCMYKSetGamma(cmyk, 4, 1.0, 0.9);
+ cupsCMYKSetBlack(cmyk, 0.5, 1.0);
+ break;
+
+ case 7 : /* CcMmYKk */
+ cupsCMYKSetLtDk(cmyk, 0, 0.5, 1.0);
+ cupsCMYKSetLtDk(cmyk, 2, 0.5, 1.0);
+ cupsCMYKSetGamma(cmyk, 4, 1.0, 0.9);
+ cupsCMYKSetLtDk(cmyk, 5, 0.5, 1.0);
+ break;
+ }
+
+ /*
+ * Open the color separation files...
+ */
+
+ for (i = 0; i < num_comps; i ++)
+ {
+ sprintf(filename, "%s%d.pgm", basename, i);
+ out[i] = fopen(filename, "wb");
+
+ fprintf(out[i], "P5\n%d %d 255\n", width, height);
+ }
+
+ sprintf(filename, "%s.ppm", basename);
+ comp = fopen(filename, "wb");
+
+ fprintf(comp, "P6\n%d %d 255\n", width, height);
+
+ /*
+ * Read the image and do the separations...
+ */
+
+ for (y = 0; y < height; y ++)
+ {
+ fread(input, width, 1, in);
+
+ cupsCMYKDoGray(cmyk, input, output, width);
+
+ for (x = 0, outptr = output; x < width; x ++, outptr += num_comps)
+ {
+ for (i = 0; i < num_comps; i ++)
+ putc(255 - 255 * outptr[i] / 4095, out[i]);
+
+ r = 4095;
+ g = 4095;
+ b = 4095;
+
+ switch (num_comps)
+ {
+ case 1 :
+ r -= outptr[0];
+ g -= outptr[0];
+ b -= outptr[0];
+ break;
+ case 2 :
+ r -= outptr[0];
+ g -= outptr[0];
+ b -= outptr[0];
+
+ r -= outptr[1] / 2;
+ g -= outptr[1] / 2;
+ b -= outptr[1] / 2;
+ break;
+ case 3 :
+ r -= outptr[0];
+ g -= outptr[1];
+ b -= outptr[2];
+ break;
+ case 4 :
+ r -= outptr[0];
+ g -= outptr[1];
+ b -= outptr[2];
+
+ r -= outptr[3];
+ g -= outptr[3];
+ b -= outptr[3];
+ break;
+ case 6 :
+ r -= outptr[0] + outptr[1] / 2;
+ g -= outptr[2] + outptr[3] / 3;
+ b -= outptr[4];
+
+ r -= outptr[5];
+ g -= outptr[5];
+ b -= outptr[5];
+ break;
+ case 7 :
+ r -= outptr[0] + outptr[1] / 2;
+ g -= outptr[2] + outptr[3] / 3;
+ b -= outptr[4];
+
+ r -= outptr[5] + outptr[6] / 2;
+ g -= outptr[5] + outptr[6] / 2;
+ b -= outptr[5] + outptr[6] / 2;
+ break;
+ }
+
+ if (r < 0)
+ putc(0, comp);
+ else
+ putc(255 * r / 4095, comp);
+
+ if (g < 0)
+ putc(0, comp);
+ else
+ putc(255 * g / 4095, comp);
+
+ if (b < 0)
+ putc(0, comp);
+ else
+ putc(255 * b / 4095, comp);
+ }
+ }
+
+ for (i = 0; i < num_comps; i ++)
+ fclose(out[i]);
+
+ fclose(comp);
+ fclose(in);
+
+ cupsCMYKDelete(cmyk);
+}
+
+
+/*
+ * 'test_rgb()' - Test color separations...
+ */
+
+void
+test_rgb(int num_comps, /* I - Number of components */
+ const char *basename) /* I - Base filename of output */
+{
+ int i; /* Looping var */
+ char filename[255]; /* Output filename */
+ char line[255]; /* Line from PPM file */
+ int width, height; /* Width and height of test image */
+ int x, y; /* Current coordinate in image */
+ int r, g, b; /* Current RGB color */
+ unsigned char input[7000]; /* Line to separate */
+ short output[48000], /* Output separation data */
+ *outptr; /* Pointer in output */
+ FILE *in; /* Input PPM file */
+ FILE *out[CUPS_MAX_CHAN];
+ /* Output PGM files */
+ FILE *comp; /* Composite output */
+ cups_cmyk_t *cmyk; /* Color separation */
+
+
+ /*
+ * Open the test image...
+ */
+
+ in = fopen("image.ppm", "rb");
+ while (fgets(line, sizeof(line), in) != NULL)
+ if (isdigit(line[0]))
+ break;
+
+ sscanf(line, "%d%d", &width, &height);
+
+ fgets(line, sizeof(line), in);
+
+ /*
+ * Create the color separation...
+ */
+
+ cmyk = cupsCMYKNew(num_comps);
+
+ cupsCMYKSetBlack(cmyk, 0.5, 1.0);
+
+ switch (num_comps)
+ {
+ case 2 : /* Kk */
+ cupsCMYKSetLtDk(cmyk, 0, 0.5, 1.0);
+ break;
+ case 6 : /* CcMmYK */
+ cupsCMYKSetGamma(cmyk, 0, 1.0, 0.8);
+ cupsCMYKSetLtDk(cmyk, 0, 0.5, 1.0);
+ cupsCMYKSetGamma(cmyk, 2, 1.0, 0.8);
+ cupsCMYKSetLtDk(cmyk, 2, 0.5, 1.0);
+ break;
+ case 7 : /* CcMmYKk */
+ cupsCMYKSetGamma(cmyk, 0, 1.0, 0.8);
+ cupsCMYKSetLtDk(cmyk, 0, 0.5, 1.0);
+ cupsCMYKSetGamma(cmyk, 2, 1.0, 0.8);
+ cupsCMYKSetLtDk(cmyk, 2, 0.5, 1.0);
+ cupsCMYKSetLtDk(cmyk, 5, 0.5, 1.0);
+ break;
+ }
+
+ /*
+ * Open the color separation files...
+ */
+
+ for (i = 0; i < num_comps; i ++)
+ {
+ sprintf(filename, "%s%d.pgm", basename, i);
+ out[i] = fopen(filename, "wb");
+
+ fprintf(out[i], "P5\n%d %d 255\n", width, height);
+ }
+
+ sprintf(filename, "%s.ppm", basename);
+ comp = fopen(filename, "wb");
+
+ fprintf(comp, "P6\n%d %d 255\n", width, height);
+
+ /*
+ * Read the image and do the separations...
+ */
+
+ for (y = 0; y < height; y ++)
+ {
+ fread(input, width, 3, in);
+
+ cupsCMYKDoRGB(cmyk, input, output, width);
+
+ for (x = 0, outptr = output; x < width; x ++, outptr += num_comps)
+ {
+ for (i = 0; i < num_comps; i ++)
+ putc(255 - 255 * outptr[i] / 4095, out[i]);
+
+ r = 4095;
+ g = 4095;
+ b = 4095;
+
+ switch (num_comps)
+ {
+ case 1 :
+ r -= outptr[0];
+ g -= outptr[0];
+ b -= outptr[0];
+ break;
+ case 2 :
+ r -= outptr[0];
+ g -= outptr[0];
+ b -= outptr[0];
+
+ r -= outptr[1] / 2;
+ g -= outptr[1] / 2;
+ b -= outptr[1] / 2;
+ break;
+ case 3 :
+ r -= outptr[0];
+ g -= outptr[1];
+ b -= outptr[2];
+ break;
+ case 4 :
+ r -= outptr[0];
+ g -= outptr[1];
+ b -= outptr[2];
+
+ r -= outptr[3];
+ g -= outptr[3];
+ b -= outptr[3];
+ break;
+ case 6 :
+ r -= outptr[0] + outptr[1] / 2;
+ g -= outptr[2] + outptr[3] / 3;
+ b -= outptr[4];
+
+ r -= outptr[5];
+ g -= outptr[5];
+ b -= outptr[5];
+ break;
+ case 7 :
+ r -= outptr[0] + outptr[1] / 2;
+ g -= outptr[2] + outptr[3] / 3;
+ b -= outptr[4];
+
+ r -= outptr[5] + outptr[6] / 2;
+ g -= outptr[5] + outptr[6] / 2;
+ b -= outptr[5] + outptr[6] / 2;
+ break;
+ }
+
+ if (r < 0)
+ putc(0, comp);
+ else
+ putc(255 * r / 4095, comp);
+
+ if (g < 0)
+ putc(0, comp);
+ else
+ putc(255 * g / 4095, comp);
+
+ if (b < 0)
+ putc(0, comp);
+ else
+ putc(255 * b / 4095, comp);
+ }
+ }
+
+ for (i = 0; i < num_comps; i ++)
+ fclose(out[i]);
+
+ fclose(comp);
+ fclose(in);
+
+ cupsCMYKDelete(cmyk);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/testdither.c b/driver/testdither.c
new file mode 100644
index 000000000..547e47d05
--- /dev/null
+++ b/driver/testdither.c
@@ -0,0 +1,191 @@
+/*
+ * "$Id$"
+ *
+ * Dither test program for CUPS.
+ *
+ * Try the following:
+ *
+ * testdither 0 255 > filename.ppm
+ * testdither 0 127 255 > filename.ppm
+ * testdither 0 85 170 255 > filename.ppm
+ * testdither 0 63 127 170 198 227 255 > filename.ppm
+ * testdither 0 210 383 > filename.ppm
+ * testdither 0 82 255 > filename.ppm
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Test dithering and output a PPM file.
+ * usage() - Show program usage...
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include "driver.h"
+#include <cups/string-private.h>
+
+
+/*
+ * Local functions...
+ */
+
+void usage(void);
+
+
+/*
+ * 'main()' - Test dithering and output a PPM file.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int x, y; /* Current coordinate in image */
+ short line[512]; /* Line to dither */
+ unsigned char pixels[512], /* Dither pixels */
+ *pixptr; /* Pointer in line */
+ int output; /* Output pixel */
+ cups_lut_t *lut; /* Dither lookup table */
+ cups_dither_t *dither; /* Dither state */
+ int nlutvals; /* Number of lookup values */
+ float lutvals[16]; /* Lookup values */
+ int pixvals[16]; /* Pixel values */
+
+
+ /*
+ * See if we have lookup table values on the command-line...
+ */
+
+ if (argc > 1)
+ {
+ /*
+ * Yes, collect them...
+ */
+
+ nlutvals = 0;
+
+ for (x = 1; x < argc; x ++)
+ if (isdigit(argv[x][0]) && nlutvals < 16)
+ {
+ pixvals[nlutvals] = atoi(argv[x]);
+ lutvals[nlutvals] = atof(argv[x]) / 255.0;
+ nlutvals ++;
+ }
+ else
+ usage();
+
+ /*
+ * See if we have at least 2 values...
+ */
+
+ if (nlutvals < 2)
+ usage();
+ }
+ else
+ {
+ /*
+ * Otherwise use the default 2-entry LUT with values of 0 and 255...
+ */
+
+ nlutvals = 2;
+ lutvals[0] = 0.0;
+ lutvals[1] = 1.0;
+ pixvals[0] = 0;
+ pixvals[1] = 255;
+ }
+
+ /*
+ * Create the lookup table and dither state...
+ */
+
+ lut = cupsLutNew(nlutvals, lutvals);
+ dither = cupsDitherNew(512);
+
+ /*
+ * Put out the PGM header for a raw 256x256x8-bit grayscale file...
+ */
+
+ puts("P5\n512\n512\n255");
+
+ /*
+ * Dither 512 lines, which are written out in 256 image lines...
+ */
+
+ for (y = 0; y < 512; y ++)
+ {
+ /*
+ * Create the grayscale data for the current line...
+ */
+
+ for (x = 0; x < 512; x ++)
+ line[x] = 4095 * ((y / 32) * 16 + x / 32) / 255;
+
+ /*
+ * Dither the line...
+ */
+
+ cupsDitherLine(dither, lut, line, 1, pixels);
+
+ if (y == 0)
+ {
+ fputs("DEBUG: pixels =", stderr);
+ for (x = 0; x < 512; x ++)
+ fprintf(stderr, " %d", pixels[x]);
+ fputs("\n", stderr);
+ }
+
+ /*
+ * Add or set the output pixel values...
+ */
+
+ for (x = 0, pixptr = pixels; x < 512; x ++, pixptr ++)
+ {
+ output = 255 - pixvals[*pixptr];
+
+ if (output < 0)
+ putchar(0);
+ else
+ putchar(output);
+ }
+ }
+
+ /*
+ * Free the dither state and lookup table...
+ */
+
+ cupsDitherDelete(dither);
+ cupsLutDelete(lut);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'usage()' - Show program usage...
+ */
+
+void
+usage(void)
+{
+ puts("Usage: testdither [val1 val2 [... val16]] >filename.ppm");
+ exit(1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/testdriver.c b/driver/testdriver.c
new file mode 100644
index 000000000..faba416d9
--- /dev/null
+++ b/driver/testdriver.c
@@ -0,0 +1,176 @@
+/*
+ * "$Id$"
+ *
+ * Sample/test driver interface program for CUPS.
+ *
+ * This program handles listing and installing both static PPD files
+ * in CUPS_DATADIR/model and dynamically generated PPD files using
+ * the driver helper programs in CUPS_SERVERBIN/driver.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Enumerate or display PPD files.
+ * cat_ppd() - Display a PPD file.
+ * list_ppds() - List PPDs.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/string-private.h>
+#include <cups/cups.h>
+
+
+/*
+ * Local functions...
+ */
+
+static int cat_ppd(const char *uri);
+static int list_ppds(const char *name);
+
+
+/*
+ * Sample data...
+ */
+
+static const char *models[][2] =
+ {
+ { "foojet.ppd", "Foo Printer" },
+ { "barjet.ppd", "Bar Printer" },
+ { "foobar.ppd", "Foo/Bar Multifunction Printer" }
+ };
+
+
+/*
+ * 'main()' - Enumerate or display PPD files.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ if (argc == 2 && !strcmp(argv[1], "list"))
+ return (list_ppds(argv[0]));
+ else if (argc == 3 && !strcmp(argv[1], "cat"))
+ return (cat_ppd(argv[2]));
+
+ fprintf(stderr, "ERROR: Usage: %s cat URI\n", argv[0]);
+ fprintf(stderr, "ERROR: Usage: %s list\n", argv[0]);
+ return (1);
+}
+
+
+/*
+ * 'cat_ppd()' - Display a PPD file.
+ */
+
+static int /* O - Exit status */
+cat_ppd(const char *uri) /* I - PPD URI */
+{
+ int i; /* Looping var */
+ char scheme[255], /* URI scheme */
+ userpass[255], /* Username/password (unused) */
+ hostname[255], /* Hostname (unused) */
+ resource[1024]; /* Resource name */
+ int port; /* Port (unused) */
+ const char *name; /* Pointer to name in URI */
+
+
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
+ userpass, sizeof(userpass), hostname, sizeof(hostname),
+ &port, resource, sizeof(resource)) < HTTP_URI_OK)
+ {
+ fprintf(stderr, "ERROR: Bad URI \"%s\"!\n", uri);
+ return (1);
+ }
+
+ name = resource + 1;
+
+ for (i = 0 ; i < (int)(sizeof(models) / sizeof(models[0])); i ++)
+ if (!strcmp(name, models[i][0]))
+ {
+ /*
+ * Actually display the PPD file...
+ */
+ puts("*PPD-Adobe: \"4.3\"");
+
+ puts("*LanguageEncoding: ISOLatin1");
+ puts("*LanguageVersion: English");
+ puts("*Manufacturer: \"Test\"");
+ puts("*FileVersion: \"1.0\"");
+ puts("*FormatVersion: \"4.3\"");
+ puts("*PSVersion: \"(3010) 1\"");
+ printf("*PCFileName: \"%s\"\n", models[i][0]);
+
+ printf("*Product: \"(%s)\"\n", models[i][1]);
+ printf("*ModelName: \"Test %s\"\n", models[i][1]);
+ printf("*NickName: \"Test %s\"\n", models[i][1]);
+ printf("*ShortNickName: \"Test %s\"\n", models[i][1]);
+
+ puts("*OpenUI PageSize: PickOne");
+ puts("*OrderDependency: 10 AnySetup *PageSetup");
+ puts("*DefaultPageSize: Letter");
+ puts("*PageSize Letter: \"<</PageSize[612 792]>>setpagedevice\"");
+ puts("*PageSize A4: \"<</PageSize[585 842]>>setpagedevice\"");
+ puts("*CloseUI: *PageSize");
+
+ puts("*OpenUI PageRegion: PickOne");
+ puts("*OrderDependency: 10 AnySetup *PageRegion");
+ puts("*DefaultPageRegion: Letter");
+ puts("*PageRegion Letter: \"<</PageRegion[612 792]>>setpagedevice\"");
+ puts("*PageRegion A4: \"<</PageRegion[585 842]>>setpagedevice\"");
+ puts("*CloseUI: *PageRegion");
+
+ puts("*DefaultImageableArea: Letter");
+ puts("*ImageableArea Letter: \"0 0 612 792\"");
+ puts("*ImageableArea A4: \"0 0 595 842\"");
+
+ puts("*DefaultPaperDimension: Letter");
+ puts("*PaperDimension Letter: \"612 792\"");
+ puts("*PaperDimension A4: \"595 842\"");
+
+ return (0);
+ }
+
+ fprintf(stderr, "ERROR: Unknown URI \"%s\"!\n", uri);
+ return (1);
+}
+
+
+/*
+ * 'list_ppds()' - List PPDs.
+ */
+
+static int /* O - Exit status */
+list_ppds(const char *name) /* I - Program name */
+{
+ int i; /* Looping var */
+ const char *base; /* Base name of program */
+
+
+ if ((base = strrchr(name, '/')) != NULL)
+ base ++;
+ else
+ base = name;
+
+ for (i = 0; i < (int)(sizeof(models) / sizeof(models[0])); i ++)
+ printf("\"%s:///%s\" en \"Test\" \"Test %s\" \"1284 device id\"\n",
+ base, models[i][0], models[i][1]);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/driver/testrgb.c b/driver/testrgb.c
new file mode 100644
index 000000000..b2bd27031
--- /dev/null
+++ b/driver/testrgb.c
@@ -0,0 +1,348 @@
+/*
+ * "$Id$"
+ *
+ * Test the new RGB color separation code for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2006 by Easy Software Products, All Rights Reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Do color rgb tests.
+ * test_gray() - Test grayscale rgbs...
+ * test_rgb() - Test color rgbs...
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <cups/string-private.h>
+#include "driver.h"
+#include <sys/stat.h>
+
+#ifdef HAVE_LIBLCMS
+# include <lcms/lcms.h>
+#endif /* HAVE_LIBLCMS */
+
+
+void test_gray(cups_sample_t *samples, int num_samples,
+ int cube_size, int num_comps, const char *basename);
+void test_rgb(cups_sample_t *samples, int num_samples,
+ int cube_size, int num_comps,
+ const char *basename);
+
+
+/*
+ * 'main()' - Do color rgb tests.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ static cups_sample_t CMYK[] = /* Basic 4-color sep */
+ {
+ /*{ r, g, b }, { C, M, Y, K }*/
+ { { 0, 0, 0 }, { 0, 0, 0, 255 } },
+ { { 255, 0, 0 }, { 0, 255, 240, 0 } },
+ { { 0, 255, 0 }, { 200, 0, 200, 0 } },
+ { { 255, 255, 0 }, { 0, 0, 240, 0 } },
+ { { 0, 0, 255 }, { 200, 200, 0, 0 } },
+ { { 255, 0, 255 }, { 0, 200, 0, 0 } },
+ { { 0, 255, 255 }, { 200, 0, 0, 0 } },
+ { { 255, 255, 255 }, { 0, 0, 0, 0 } }
+ };
+
+
+ /*
+ * Make the test directory...
+ */
+
+ mkdir("test", 0755);
+
+ /*
+ * Run tests for CMYK and CMYK separations...
+ */
+
+ test_rgb(CMYK, 8, 2, 4, "test/rgb-cmyk");
+
+ test_gray(CMYK, 8, 2, 4, "test/gray-cmyk");
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'test_gray()' - Test grayscale rgbs...
+ */
+
+void
+test_gray(cups_sample_t *samples, /* I - Sample values */
+ int num_samples, /* I - Number of samples */
+ int cube_size, /* I - Cube size */
+ int num_comps, /* I - Number of components */
+ const char *basename) /* I - Base filename of output */
+{
+ int i; /* Looping var */
+ char filename[255]; /* Output filename */
+ char line[255]; /* Line from PPM file */
+ int width, height; /* Width and height of test image */
+ int x, y; /* Current coordinate in image */
+ int r, g, b; /* Current RGB color */
+ unsigned char input[7000]; /* Line to rgbarate */
+ unsigned char output[48000], /* Output rgb data */
+ *outptr; /* Pointer in output */
+ FILE *in; /* Input PPM file */
+ FILE *out[CUPS_MAX_CHAN];
+ /* Output PGM files */
+ FILE *comp; /* Composite output */
+ cups_rgb_t *rgb; /* Color separation */
+
+
+ /*
+ * Open the test image...
+ */
+
+ in = fopen("image.pgm", "rb");
+ while (fgets(line, sizeof(line), in) != NULL)
+ if (isdigit(line[0]))
+ break;
+
+ sscanf(line, "%d%d", &width, &height);
+
+ fgets(line, sizeof(line), in);
+
+ /*
+ * Create the color rgb...
+ */
+
+ rgb = cupsRGBNew(num_samples, samples, cube_size, num_comps);
+
+ /*
+ * Open the color rgb files...
+ */
+
+ for (i = 0; i < num_comps; i ++)
+ {
+ sprintf(filename, "%s%d.pgm", basename, i);
+ out[i] = fopen(filename, "wb");
+
+ fprintf(out[i], "P5\n%d %d 255\n", width, height);
+ }
+
+ sprintf(filename, "%s.ppm", basename);
+ comp = fopen(filename, "wb");
+
+ fprintf(comp, "P6\n%d %d 255\n", width, height);
+
+ /*
+ * Read the image and do the rgbs...
+ */
+
+ for (y = 0; y < height; y ++)
+ {
+ fread(input, width, 1, in);
+
+ cupsRGBDoGray(rgb, input, output, width);
+
+ for (x = 0, outptr = output; x < width; x ++, outptr += num_comps)
+ {
+ for (i = 0; i < num_comps; i ++)
+ putc(255 - outptr[i], out[i]);
+
+ r = 255;
+ g = 255;
+ b = 255;
+
+ r -= outptr[0];
+ g -= outptr[1];
+ b -= outptr[2];
+
+ r -= outptr[3];
+ g -= outptr[3];
+ b -= outptr[3];
+
+ if (num_comps > 4)
+ {
+ r -= outptr[4] / 2;
+ g -= outptr[5] / 2;
+ }
+
+ if (num_comps > 6)
+ {
+ r -= outptr[6] / 2;
+ g -= outptr[6] / 2;
+ b -= outptr[6] / 2;
+ }
+
+ if (r < 0)
+ putc(0, comp);
+ else
+ putc(r, comp);
+
+ if (g < 0)
+ putc(0, comp);
+ else
+ putc(g, comp);
+
+ if (b < 0)
+ putc(0, comp);
+ else
+ putc(b, comp);
+ }
+ }
+
+ for (i = 0; i < num_comps; i ++)
+ fclose(out[i]);
+
+ fclose(comp);
+ fclose(in);
+
+ cupsRGBDelete(rgb);
+}
+
+
+/*
+ * 'test_rgb()' - Test color rgbs...
+ */
+
+void
+test_rgb(cups_sample_t *samples, /* I - Sample values */
+ int num_samples, /* I - Number of samples */
+ int cube_size, /* I - Cube size */
+ int num_comps, /* I - Number of components */
+ const char *basename) /* I - Base filename of output */
+{
+ int i; /* Looping var */
+ char filename[255]; /* Output filename */
+ char line[255]; /* Line from PPM file */
+ int width, height; /* Width and height of test image */
+ int x, y; /* Current coordinate in image */
+ int r, g, b; /* Current RGB color */
+ unsigned char input[7000]; /* Line to rgbarate */
+ unsigned char output[48000], /* Output rgb data */
+ *outptr; /* Pointer in output */
+ FILE *in; /* Input PPM file */
+ FILE *out[CUPS_MAX_CHAN];
+ /* Output PGM files */
+ FILE *comp; /* Composite output */
+ cups_rgb_t *rgb; /* Color separation */
+
+
+ /*
+ * Open the test image...
+ */
+
+ in = fopen("image.ppm", "rb");
+ while (fgets(line, sizeof(line), in) != NULL)
+ if (isdigit(line[0]))
+ break;
+
+ sscanf(line, "%d%d", &width, &height);
+
+ fgets(line, sizeof(line), in);
+
+ /*
+ * Create the color rgb...
+ */
+
+ rgb = cupsRGBNew(num_samples, samples, cube_size, num_comps);
+
+ /*
+ * Open the color rgb files...
+ */
+
+ for (i = 0; i < num_comps; i ++)
+ {
+ sprintf(filename, "%s%d.pgm", basename, i);
+ out[i] = fopen(filename, "wb");
+
+ fprintf(out[i], "P5\n%d %d 255\n", width, height);
+ }
+
+ sprintf(filename, "%s.ppm", basename);
+ comp = fopen(filename, "wb");
+
+ fprintf(comp, "P6\n%d %d 255\n", width, height);
+
+ /*
+ * Read the image and do the rgbs...
+ */
+
+ for (y = 0; y < height; y ++)
+ {
+ fread(input, width, 3, in);
+
+ cupsRGBDoRGB(rgb, input, output, width);
+
+ for (x = 0, outptr = output; x < width; x ++, outptr += num_comps)
+ {
+ for (i = 0; i < num_comps; i ++)
+ putc(255 - outptr[i], out[i]);
+
+ r = 255;
+ g = 255;
+ b = 255;
+
+ r -= outptr[0];
+ g -= outptr[1];
+ b -= outptr[2];
+
+ r -= outptr[3];
+ g -= outptr[3];
+ b -= outptr[3];
+
+ if (num_comps > 4)
+ {
+ r -= outptr[4] / 2;
+ g -= outptr[5] / 2;
+ }
+
+ if (num_comps > 6)
+ {
+ r -= outptr[6] / 2;
+ g -= outptr[6] / 2;
+ b -= outptr[6] / 2;
+ }
+
+ if (r < 0)
+ putc(0, comp);
+ else
+ putc(r, comp);
+
+ if (g < 0)
+ putc(0, comp);
+ else
+ putc(g, comp);
+
+ if (b < 0)
+ putc(0, comp);
+ else
+ putc(b, comp);
+ }
+ }
+
+ for (i = 0; i < num_comps; i ++)
+ fclose(out[i]);
+
+ fclose(comp);
+ fclose(in);
+
+ cupsRGBDelete(rgb);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/examples/Makefile b/examples/Makefile
new file mode 100644
index 000000000..da08298b3
--- /dev/null
+++ b/examples/Makefile
@@ -0,0 +1,128 @@
+#
+# "$Id$"
+#
+# PPD compiler example makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 2002-2005 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+#
+# Include standard definitions...
+#
+
+include ../Makedefs
+
+
+#
+# Examples...
+#
+
+EXAMPLES = \
+ color.drv \
+ constraint.drv \
+ custom.drv \
+ grouping.drv \
+ laserjet-basic.drv \
+ laserjet-pjl.drv \
+ minimum.drv \
+ postscript.drv \
+ r300-basic.drv \
+ r300-colorman.drv \
+ r300-remote.drv
+
+
+#
+# Make everything...
+#
+
+all:
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Clean everything...
+#
+
+clean:
+
+
+#
+# Dummy depend...
+#
+
+depend:
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+ $(INSTALL_DIR) $(DATADIR)/examples
+ for file in $(EXAMPLES); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/examples; \
+ done
+
+
+#
+# Install programs...
+#
+
+install-exec:
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall files...
+#
+
+uninstall:
+ for file in $(EXAMPLES); do \
+ $(RM) $(DATADIR)/examples/$$file; \
+ done
+ -$(RMDIR) $(DATADIR)/examples
+
+
+#
+# End of "$Id$".
+#
diff --git a/examples/color.drv b/examples/color.drv
new file mode 100644
index 000000000..69984c4b9
--- /dev/null
+++ b/examples/color.drv
@@ -0,0 +1,44 @@
+// Include standard font and media definitions
+#include <font.defs>
+#include <media.defs>
+
+// List the fonts that are supported, in this case all standard
+// fonts...
+Font *
+
+// Manufacturer and version
+Manufacturer "Foo"
+Version 1.0
+
+// Each filter provided by the driver...
+Filter application/vnd.cups-raster 100 rastertofoo
+
+// Supported page sizes
+*MediaSize Letter
+MediaSize A4
+
+{
+ // Supported resolutions
+ *Resolution k 8 0 0 0 "600dpi/600 DPI"
+
+ // Specify the model name and filename...
+ ModelName "FooJet 2000"
+ PCFileName "foojet2k.ppd"
+}
+
+{
+ // Supports color printing
+ ColorDevice true
+
+ // Supported colorspaces
+ ColorModel Gray/Grayscale w chunky 0
+ *ColorModel RGB/Color rgb chunky 0
+
+ // Supported resolutions
+ *Resolution - 8 0 0 0 "300dpi/300 DPI"
+ Resolution - 8 0 0 0 "600dpi/600 DPI"
+
+ // Specify the model name and filename...
+ ModelName "FooJet Color"
+ PCFileName "foojetco.ppd"
+}
diff --git a/examples/constraint.drv b/examples/constraint.drv
new file mode 100644
index 000000000..6acb7f106
--- /dev/null
+++ b/examples/constraint.drv
@@ -0,0 +1,48 @@
+// Include standard font and media definitions
+#include <font.defs>
+#include <media.defs>
+
+// List the fonts that are supported, in this case all standard
+// fonts...
+Font *
+
+// Manufacturer, model name, and version
+Manufacturer "Foo"
+ModelName "FooJet 2000"
+Version 1.0
+
+// Each filter provided by the driver...
+Filter application/vnd.cups-raster 100 rastertofoo
+
+// Supported page sizes
+*MediaSize Letter
+MediaSize A4
+
+// Supported resolutions
+*Resolution k 8 0 0 0 "600dpi/600 DPI"
+
+// Installable Option Group
+Group "InstallableOptions/Options Installed"
+
+ // Duplexing unit option
+ Option "Option1/Duplexing Unit" Boolean AnySetup 10
+ Choice True/Installed ""
+ *Choice "False/Not Installed" ""
+
+// General Option Group
+Group General
+
+ // Duplexing option
+ Option "Duplex/Two-Sided Printing" PickOne AnySetup 10
+ *Choice "None/No" "<</Duplex false>>setpagedevice"
+ Choice "DuplexNoTumble/Long Edge Binding"
+ "<</Duplex true/Tumble false>>setpagedevice"
+ Choice "DuplexTumble/Short Edge Binding"
+ "<</Duplex true/Tumble true>>setpagedevice"
+
+// Only allow duplexing if the duplexer is installed
+UIConstraints "*Duplex *Option1 False"
+
+// Specify the name of the PPD file we want to generate...
+PCFileName "foojet2k.ppd"
+
diff --git a/examples/custom.drv b/examples/custom.drv
new file mode 100644
index 000000000..1001c4fc1
--- /dev/null
+++ b/examples/custom.drv
@@ -0,0 +1,41 @@
+// Include standard font and media definitions
+#include <font.defs>
+#include <media.defs>
+
+// List the fonts that are supported, in this case all standard
+// fonts...
+Font *
+
+// Manufacturer, model name, and version
+Manufacturer "Foo"
+ModelName "FooJet 2000"
+Version 1.0
+
+// Each filter provided by the driver...
+Filter application/vnd.cups-raster 100 rastertofoo
+
+// Supported page sizes
+*MediaSize Letter
+MediaSize A4
+
+// Supported resolutions
+*Resolution k 8 0 0 0 "600dpi/600 DPI"
+
+// Option Group
+Group "Footasm"
+
+ // Boolean option
+ Option "fooEnhance/Resolution Enhancement" Boolean AnySetup 10
+ *Choice True/Yes "<</cupsCompression 1>>setpagedevice"
+ Choice False/No "<</cupsCompression 0>>setpagedevice"
+
+ // Multiple choice option
+ Option "fooOutputType/Output Quality" PickOne AnySetup 10
+ *Choice "Auto/Automatic Selection" "<</OutputType(Auto)>>setpagedevice"
+ Choice "Text/Optimize for Text" "<</OutputType(Text)>>setpagedevice"
+ Choice "Graph/Optimize for Graphics" "<</OutputType(Graph)>>setpagedevice"
+ Choice "Photo/Optimize for Photos" "<</OutputType(Photo)>>setpagedevice"
+
+// Specify the name of the PPD file we want to generate...
+PCFileName "foojet2k.ppd"
+
diff --git a/examples/grouping.drv b/examples/grouping.drv
new file mode 100644
index 000000000..da66d74fc
--- /dev/null
+++ b/examples/grouping.drv
@@ -0,0 +1,36 @@
+// Include standard font and media definitions
+#include <font.defs>
+#include <media.defs>
+
+// List the fonts that are supported, in this case all standard
+// fonts...
+Font *
+
+// Manufacturer and version
+Manufacturer "Foo"
+Version 1.0
+
+// Each filter provided by the driver...
+Filter application/vnd.cups-raster 100 rastertofoo
+
+// Supported page sizes
+*MediaSize Letter
+MediaSize A4
+
+{
+ // Supported resolutions
+ *Resolution k 8 0 0 0 "600dpi/600 DPI"
+
+ // Specify the model name and filename...
+ ModelName "FooJet 2000"
+ PCFileName "foojet2k.ppd"
+}
+
+{
+ // Supported resolutions
+ *Resolution k 8 0 0 0 "1200dpi/1200 DPI"
+
+ // Specify the model name and filename...
+ ModelName "FooJet 2001"
+ PCFileName "foojt2k1.ppd"
+}
diff --git a/examples/laserjet-basic.drv b/examples/laserjet-basic.drv
new file mode 100644
index 000000000..6924ed7b8
--- /dev/null
+++ b/examples/laserjet-basic.drv
@@ -0,0 +1,88 @@
+// Include standard font and media definitions
+#include <font.defs>
+#include <media.defs>
+
+// Include HP-PCL driver definitions
+#include <pcl.h>
+
+// Specify that this driver uses the HP-PCL driver...
+DriverType pcl
+
+// Specify the driver options via the model number...
+ModelNumber ($PCL_PAPER_SIZE $PCL_PJL $PCL_PJL_RESOLUTION)
+
+// List the fonts that are supported, in this case all standard
+// fonts...
+Font *
+
+// Manufacturer and driver version
+Manufacturer "HP"
+Version 1.0
+
+// Supported page sizes and their margins
+HWMargins 18 12 18 12
+*MediaSize Letter
+MediaSize Legal
+MediaSize Executive
+MediaSize Monarch
+MediaSize Statement
+MediaSize FanFoldGermanLegal
+
+HWMargins 18 12.72 18 12.72
+MediaSize Env10
+
+HWMargins 9.72 12 9.72 12
+MediaSize A4
+MediaSize A5
+MediaSize B5
+MediaSize EnvC5
+MediaSize EnvDL
+MediaSize EnvISOB5
+MediaSize Postcard
+MediaSize DoublePostcard
+
+// Only black-and-white output with mode 3 compression...
+ColorModel Gray k chunky 3
+
+// Supported resolutions
+Resolution - 1 0 0 0 "300dpi/300 DPI"
+*Resolution - 8 0 0 0 "600dpi/600 DPI"
+
+// Supported input slots
+*InputSlot 7 "Auto/Automatic Selection"
+InputSlot 2 "Manual/Tray 1 - Manual Feed"
+InputSlot 4 "Upper/Tray 1"
+InputSlot 1 "Lower/Tray 2"
+InputSlot 5 "LargeCapacity/Tray 3"
+
+// Tray 3 is an option...
+Installable "OptionLargeCapacity/Tray 3 Installed"
+UIConstraints "*OptionLargeCapacity False *InputSlot LargeCapacity"
+
+{
+ // HP LaserJet 2100 Series
+ Throughput 10
+ ModelName "LaserJet 2100 Series"
+ PCFileName "hpljt211.ppd"
+}
+
+{
+ // LaserJet 2200 and 2300 series have duplexer option...
+ Duplex normal
+ Installable "OptionDuplex/Duplexer Installed"
+ UIConstraints "*OptionDuplex False *Duplex"
+
+ {
+ // HP LaserJet 2200 Series
+ Throughput 19
+ ModelName "LaserJet 2200 Series"
+ PCFileName "hpljt221.ppd"
+ }
+
+ {
+ // HP LaserJet 2300 Series
+ Throughput 25
+ ModelName "LaserJet 2300 Series"
+ PCFileName "hpljt231.ppd"
+ }
+}
diff --git a/examples/laserjet-pjl.drv b/examples/laserjet-pjl.drv
new file mode 100644
index 000000000..32a0bc4f0
--- /dev/null
+++ b/examples/laserjet-pjl.drv
@@ -0,0 +1,101 @@
+// Include standard font and media definitions
+#include <font.defs>
+#include <media.defs>
+
+// Include HP-PCL driver definitions
+#include <pcl.h>
+
+// Specify that this driver uses the HP-PCL driver...
+DriverType pcl
+
+// Specify the driver options via the model number...
+ModelNumber ($PCL_PAPER_SIZE $PCL_PJL $PCL_PJL_RESOLUTION)
+
+// List the fonts that are supported, in this case all standard
+// fonts...
+Font *
+
+// Manufacturer and driver version
+Manufacturer "HP"
+Version 2.0
+
+// Supported page sizes and their margins
+HWMargins 18 12 18 12
+*MediaSize Letter
+MediaSize Legal
+MediaSize Executive
+MediaSize Monarch
+MediaSize Statement
+MediaSize FanFoldGermanLegal
+
+HWMargins 18 12.72 18 12.72
+MediaSize Env10
+
+HWMargins 9.72 12 9.72 12
+MediaSize A4
+MediaSize A5
+MediaSize B5
+MediaSize EnvC5
+MediaSize EnvDL
+MediaSize EnvISOB5
+MediaSize Postcard
+MediaSize DoublePostcard
+
+// Only black-and-white output with mode 3 compression...
+ColorModel Gray k chunky 3
+
+// Supported resolutions
+Resolution - 1 0 0 0 "300dpi/300 DPI"
+*Resolution - 8 0 0 0 "600dpi/600 DPI"
+
+// Supported input slots
+*InputSlot 7 "Auto/Automatic Selection"
+InputSlot 2 "Manual/Tray 1 - Manual Feed"
+InputSlot 4 "Upper/Tray 1"
+InputSlot 1 "Lower/Tray 2"
+InputSlot 5 "LargeCapacity/Tray 3"
+
+// Tray 3 is an option...
+Installable "OptionLargeCapacity/Tray 3 Installed"
+UIConstraints "*OptionLargeCapacity False *InputSlot LargeCapacity"
+
+// PJL options
+Attribute cupsPJL cupsRET "@PJL SET SMOOTHING=%?False:OFF;%?True:ON;%n"
+
+Option "cupsRET/Smoothing" Boolean DocumentSetup 10
+ Choice "False/Off" ""
+ *Choice "True/On" ""
+
+Attribute cupsPJL cupsTonerSave "@PJL SET ECONOMODE=%?False:OFF;%?True:ON;%n"
+
+Option "cupsTonerSave/Save Toner" Boolean DocumentSetup 10
+ *Choice "False/No" ""
+ Choice "True/Yes" ""
+
+{
+ // HP LaserJet 2100 Series
+ Throughput 10
+ ModelName "LaserJet 2100 Series PJL"
+ PCFileName "hpljt212.ppd"
+}
+
+{
+ // LaserJet 2200 and 2300 series have duplexer option...
+ Duplex normal
+ Installable "OptionDuplex/Duplexer Installed"
+ UIConstraints "*OptionDuplex False *Duplex"
+
+ {
+ // HP LaserJet 2200 Series
+ Throughput 19
+ ModelName "LaserJet 2200 Series PJL"
+ PCFileName "hpljt222.ppd"
+ }
+
+ {
+ // HP LaserJet 2300 Series
+ Throughput 25
+ ModelName "LaserJet 2300 Series PJL"
+ PCFileName "hpljt232.ppd"
+ }
+}
diff --git a/examples/minimum.drv b/examples/minimum.drv
new file mode 100644
index 000000000..ac6e38db0
--- /dev/null
+++ b/examples/minimum.drv
@@ -0,0 +1,26 @@
+// Include standard font and media definitions
+#include <font.defs>
+#include <media.defs>
+
+// List the fonts that are supported, in this case all standard
+// fonts...
+Font *
+
+// Manufacturer, model name, and version
+Manufacturer "Foo"
+ModelName "FooJet 2000"
+Version 1.0
+
+// Each filter provided by the driver...
+Filter application/vnd.cups-raster 100 rastertofoo
+
+// Supported page sizes
+*MediaSize Letter
+MediaSize A4
+
+// Supported resolutions
+*Resolution k 8 0 0 0 "600dpi/600 DPI"
+
+// Specify the name of the PPD file we want to generate...
+PCFileName "foojet2k.ppd"
+
diff --git a/examples/postscript.drv b/examples/postscript.drv
new file mode 100644
index 000000000..ebb02f8a0
--- /dev/null
+++ b/examples/postscript.drv
@@ -0,0 +1,46 @@
+// Include standard font and media definitions
+#include <font.defs>
+#include <media.defs>
+
+// Specify this is a PostScript printer driver
+DriverType ps
+
+// List the fonts that are supported, in this case all standard fonts
+Font *
+
+// Manufacturer, model name, and version
+Manufacturer "Foo"
+ModelName "Foo LaserProofer 2000"
+Version 1.0
+
+// PostScript printer attributes
+Attribute DefaultColorSpace "" Gray
+Attribute LandscapeOrientation "" Minus90
+Attribute LanguageLevel "" "3"
+Attribute Product "" "(Foo LaserProofer 2000)"
+Attribute PSVersion "" "(3010) 0"
+Attribute TTRasterizer "" Type42
+
+// Supported page sizes
+*MediaSize Letter
+MediaSize Legal
+MediaSize A4
+
+// Query command for page size
+Attribute "?PageSize" "" "
+ save
+ currentpagedevice /PageSize get aload pop
+ 2 copy gt {exch} if (Unknown)
+ 23 dict
+ dup [612 792] (Letter) put
+ dup [612 1008] (Legal) put
+ dup [595 842] (A4) put
+ {exch aload pop 4 index sub abs 5 le exch
+ 5 index sub abs 5 le and
+ {exch pop exit} {pop} ifelse
+ } bind forall = flush pop pop
+ restore"
+
+// Specify the name of the PPD file we want to generate
+PCFileName "fooproof.ppd"
+
diff --git a/examples/r300-basic.drv b/examples/r300-basic.drv
new file mode 100644
index 000000000..e203d511d
--- /dev/null
+++ b/examples/r300-basic.drv
@@ -0,0 +1,75 @@
+// Include standard font and media definitions
+#include <font.defs>
+#include <media.defs>
+
+// Include ESC/P driver definitions
+#include <escp.h>
+
+// Specify that this driver uses the ESC/P driver...
+DriverType escp
+
+// Specify the driver options via the model number...
+ModelNumber ($ESCP_ESCK $ESCP_EXT_UNITS $ESCP_EXT_MARGINS $ESCP_USB
+ $ESCP_PAGE_SIZE $ESCP_RASTER_ESCI)
+
+// List the fonts that are supported, in this case all standard
+// fonts...
+Font *
+
+// Manufacturer and driver version
+Manufacturer "Epson"
+Version 1.0
+
+// Supported page sizes and their margins
+HWMargins 8.4 0 8.4 0
+*MediaSize Letter
+MediaSize Legal
+MediaSize Executive
+MediaSize Statement
+MediaSize A4
+MediaSize A5
+MediaSize A6
+MediaSize B5
+MediaSize Env10
+MediaSize EnvC5
+MediaSize EnvDL
+MediaSize EnvISOB5
+MediaSize Postcard
+MediaSize DoublePostcard
+
+VariablePaperSize Yes
+MinSize 1in 4in
+MaxSize 8.5in 44in
+
+// Four color modes are supported...
+ColorModel Gray/Grayscale w chunky 1
+ColorModel Black k chunky 1
+*ColorModel RGB/Color rgb chunky 1
+ColorModel CMYK cmyk chunky 1
+
+// Supported resolutions
+Resolution - 8 90 0 103 "360dpi/360 DPI"
+*Resolution - 8 90 0 206 "720dpi/720 DPI"
+Resolution - 8 90 0 412 "1440dpi/1440 DPI"
+
+// Very basic dithering settings
+Attribute cupsInkChannels "" 6
+Attribute cupsInkLimit "" 2.0
+
+Attribute cupsCyanLtDk "" "0.5 1.0"
+Attribute cupsMagentaLtDk "" "0.5 1.0"
+
+Attribute cupsAllDither 360dpi "0.5 0.75 1.0"
+Attribute cupsAllDither 720dpi "0.6 0.9 1.2"
+Attribute cupsAllDither 1440dpi "0.9 1.35"
+
+Attribute cupsESCPDotSize 360dpi 16
+Attribute cupsESCPDotSize 720dpi 17
+Attribute cupsESCPDotSize 1440dpi 18
+
+{
+ // EPSON Stylus Photo R300 Series
+ Throughput 1
+ ModelName "Stylus Photo R300"
+ PCFileName "epspr301.ppd"
+}
diff --git a/examples/r300-colorman.drv b/examples/r300-colorman.drv
new file mode 100644
index 000000000..ddaf58ec7
--- /dev/null
+++ b/examples/r300-colorman.drv
@@ -0,0 +1,85 @@
+// Include standard font and media definitions
+#include <font.defs>
+#include <media.defs>
+
+// Include ESC/P driver definitions
+#include <escp.h>
+
+// Specify that this driver uses the ESC/P driver...
+DriverType escp
+
+// Specify the driver options via the model number...
+ModelNumber ($ESCP_ESCK $ESCP_EXT_UNITS $ESCP_EXT_MARGINS $ESCP_USB
+ $ESCP_PAGE_SIZE $ESCP_RASTER_ESCI $ESCP_REMOTE)
+
+// List the fonts that are supported, in this case all standard
+// fonts...
+Font *
+
+// Manufacturer and driver version
+Manufacturer "Epson"
+Version 3.0
+
+// Supported page sizes and their margins
+HWMargins 0 0 0 0
+*MediaSize Letter
+MediaSize Legal
+MediaSize Executive
+MediaSize Statement
+MediaSize A4
+MediaSize A5
+MediaSize A6
+MediaSize B5
+MediaSize Env10
+MediaSize EnvC5
+MediaSize EnvDL
+MediaSize EnvISOB5
+MediaSize Postcard
+MediaSize DoublePostcard
+
+VariablePaperSize Yes
+MinSize 1in 4in
+MaxSize 8.5in 44in
+
+// Borderless printing offset...
+Attribute cupsESCPFP "" 0
+
+// Four color modes are supported...
+ColorModel Gray/Grayscale w chunky 1
+ColorModel Black k chunky 1
+*ColorModel RGB/Color rgb chunky 1
+ColorModel CMYK cmyk chunky 1
+
+// Supported resolutions
+Resolution - 8 90 0 103 "360dpi/360 DPI"
+*Resolution - 8 90 0 206 "720dpi/720 DPI"
+Resolution - 8 90 0 412 "1440dpi/1440 DPI"
+
+// Paper trays...
+*InputSlot 0 "Auto/Auto Select"
+InputSlot 1 "Manual/Manual Feed"
+
+Attribute cupsESCPPP 0 "1 255"
+Attribute cupsESCPPP 1 "2 1"
+
+// Very basic dithering settings
+Attribute cupsInkChannels "" 6
+Attribute cupsInkLimit "" 3.0
+
+Attribute cupsCyanLtDk "" "0.5 1.0"
+Attribute cupsMagentaLtDk "" "0.5 1.0"
+
+Attribute cupsAllDither 360dpi "0.5 0.75 1.0"
+Attribute cupsAllDither 720dpi "0.6 0.9 1.2"
+Attribute cupsAllDither 1440dpi "0.9 1.35"
+
+Attribute cupsESCPDotSize 360dpi 16
+Attribute cupsESCPDotSize 720dpi 17
+Attribute cupsESCPDotSize 1440dpi 18
+
+{
+ // EPSON Stylus Photo R300 Series
+ Throughput 1
+ ModelName "Epson Stylus Photo R300"
+ PCFileName "epspr303.ppd"
+}
diff --git a/examples/r300-remote.drv b/examples/r300-remote.drv
new file mode 100644
index 000000000..c3065d00c
--- /dev/null
+++ b/examples/r300-remote.drv
@@ -0,0 +1,85 @@
+// Include standard font and media definitions
+#include <font.defs>
+#include <media.defs>
+
+// Include ESC/P driver definitions
+#include <escp.h>
+
+// Specify that this driver uses the ESC/P driver...
+DriverType escp
+
+// Specify the driver options via the model number...
+ModelNumber ($ESCP_ESCK $ESCP_EXT_UNITS $ESCP_EXT_MARGINS $ESCP_USB
+ $ESCP_PAGE_SIZE $ESCP_RASTER_ESCI $ESCP_REMOTE)
+
+// List the fonts that are supported, in this case all standard
+// fonts...
+Font *
+
+// Manufacturer and driver version
+Manufacturer "Epson"
+Version 2.0
+
+// Supported page sizes and their margins
+HWMargins 0 0 0 0
+*MediaSize Letter
+MediaSize Legal
+MediaSize Executive
+MediaSize Statement
+MediaSize A4
+MediaSize A5
+MediaSize A6
+MediaSize B5
+MediaSize Env10
+MediaSize EnvC5
+MediaSize EnvDL
+MediaSize EnvISOB5
+MediaSize Postcard
+MediaSize DoublePostcard
+
+VariablePaperSize Yes
+MinSize 1in 4in
+MaxSize 8.5in 44in
+
+// Borderless printing offset...
+Attribute cupsESCPFP "" -80
+
+// Four color modes are supported...
+ColorModel Gray/Grayscale w chunky 1
+ColorModel Black k chunky 1
+*ColorModel RGB/Color rgb chunky 1
+ColorModel CMYK cmyk chunky 1
+
+// Supported resolutions
+Resolution - 8 90 0 103 "360dpi/360 DPI"
+*Resolution - 8 90 0 206 "720dpi/720 DPI"
+Resolution - 8 90 0 412 "1440dpi/1440 DPI"
+
+// Paper trays...
+*InputSlot 0 "Auto/Auto Select"
+InputSlot 1 "Manual/Manual Feed"
+
+Attribute cupsESCPPP 0 "1 255"
+Attribute cupsESCPPP 1 "2 1"
+
+// Very basic dithering settings
+Attribute cupsInkChannels "" 6
+Attribute cupsInkLimit "" 2.0
+
+Attribute cupsCyanLtDk "" "0.5 1.0"
+Attribute cupsMagentaLtDk "" "0.5 1.0"
+
+Attribute cupsAllDither 360dpi "0.5 0.75 1.0"
+Attribute cupsAllDither 720dpi "0.6 0.9 1.2"
+Attribute cupsAllDither 1440dpi "0.9 1.35"
+
+Attribute cupsESCPDotSize 360dpi 16
+Attribute cupsESCPDotSize 720dpi 17
+Attribute cupsESCPDotSize 1440dpi 18
+
+{
+ // EPSON Stylus Photo R300 Series
+ Throughput 1
+ ModelName "Epson Stylus Photo R300"
+ PCFileName "epspr302.ppd"
+}
diff --git a/filter/Dependencies b/filter/Dependencies
new file mode 100644
index 000000000..f4a4c5b89
--- /dev/null
+++ b/filter/Dependencies
@@ -0,0 +1,486 @@
+# DO NOT DELETE
+
+image-bmp.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-bmp.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-bmp.o: ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-bmp.o: ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-colorspace.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-colorspace.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-colorspace.o: ../cups/http.h ../cups/array.h ../cups/language.h
+image-colorspace.o: ../cups/ppd.h ../cups/cups.h ../cups/debug-private.h
+image-colorspace.o: ../cups/string-private.h ../config.h
+image-gif.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-gif.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-gif.o: ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-gif.o: ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-jpeg.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-jpeg.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-jpeg.o: ../cups/http.h ../cups/array.h ../cups/language.h ../cups/ppd.h
+image-jpeg.o: ../cups/cups.h ../cups/debug-private.h ../cups/string-private.h
+image-jpeg.o: ../config.h
+image-photocd.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-photocd.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-photocd.o: ../cups/http.h ../cups/array.h ../cups/language.h
+image-photocd.o: ../cups/ppd.h ../cups/cups.h ../cups/debug-private.h
+image-photocd.o: ../cups/string-private.h ../config.h
+image-pix.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-pix.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-pix.o: ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-pix.o: ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-png.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-png.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-png.o: ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-png.o: ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-pnm.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-pnm.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-pnm.o: ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-pnm.o: ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-sgi.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-sgi.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-sgi.o: ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-sgi.o: ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-sgi.o: image-sgi.h
+image-sgilib.o: image-sgi.h
+image-sun.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-sun.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-sun.o: ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-sun.o: ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-tiff.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-tiff.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-tiff.o: ../cups/http.h ../cups/array.h ../cups/language.h ../cups/ppd.h
+image-tiff.o: ../cups/cups.h ../cups/debug-private.h ../cups/string-private.h
+image-tiff.o: ../config.h
+image-zoom.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-zoom.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-zoom.o: ../cups/http.h ../cups/array.h ../cups/language.h ../cups/ppd.h
+image-zoom.o: ../cups/cups.h ../cups/debug-private.h ../cups/string-private.h
+image-zoom.o: ../config.h
+image.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+image.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image.o: ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image.o: ../cups/debug-private.h ../cups/string-private.h ../config.h
+error.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+error.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+error.o: ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+error.o: ../cups/debug-private.h ../cups/string-private.h ../config.h
+interpret.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+interpret.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+interpret.o: ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+interpret.o: ../cups/debug-private.h ../cups/string-private.h ../config.h
+raster.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+raster.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+raster.o: ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+raster.o: ../cups/debug-private.h ../cups/string-private.h ../config.h
+bannertops.o: pstext.h common.h ../cups/string-private.h ../config.h
+bannertops.o: ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+bannertops.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+bannertops.o: ../cups/array.h ../cups/language.h ../cups/transcode.h image.h
+bannertops.o: ../cups/raster.h ../cups/ppd.h ../cups/language-private.h
+commandtops.o: ../cups/cups-private.h ../cups/cups.h ../cups/string-private.h
+commandtops.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+commandtops.o: ../cups/ppd.h ../cups/cups.h ../cups/file.h
+commandtops.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+commandtops.o: ../cups/array.h ../cups/language.h ../cups/pwg-private.h
+commandtops.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+commandtops.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+commandtops.o: ../cups/transcode.h ../cups/thread-private.h
+commandtops.o: ../cups/sidechannel.h
+gziptoany.o: ../cups/cups-private.h ../cups/cups.h ../cups/string-private.h
+gziptoany.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+gziptoany.o: ../cups/ppd.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+gziptoany.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+gziptoany.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+gziptoany.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+gziptoany.o: ../cups/language-private.h ../cups/transcode.h
+gziptoany.o: ../cups/thread-private.h
+imagetops.o: common.h ../cups/string-private.h ../config.h ../cups/cups.h
+imagetops.o: ../cups/ppd.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+imagetops.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+imagetops.o: image.h ../cups/raster.h ../cups/ppd.h
+imagetops.o: ../cups/language-private.h ../cups/transcode.h
+imagetoraster.o: common.h ../cups/string-private.h ../config.h ../cups/cups.h
+imagetoraster.o: ../cups/ppd.h ../cups/cups.h ../cups/file.h
+imagetoraster.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+imagetoraster.o: ../cups/array.h ../cups/language.h image-private.h image.h
+imagetoraster.o: ../cups/raster.h ../cups/ppd.h ../cups/debug-private.h
+imagetoraster.o: ../cups/language-private.h ../cups/transcode.h
+common.o: common.h ../cups/string-private.h ../config.h ../cups/cups.h
+common.o: ../cups/ppd.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+common.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+pdftops.o: ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+pdftops.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+pdftops.o: ../cups/language.h ../cups/string-private.h ../config.h
+pdftops.o: ../cups/language-private.h ../cups/transcode.h
+pstext.o: pstext.h common.h ../cups/string-private.h ../config.h
+pstext.o: ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+pstext.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+pstext.o: ../cups/language.h ../cups/transcode.h ../cups/language-private.h
+pstops.o: common.h ../cups/string-private.h ../config.h ../cups/cups.h
+pstops.o: ../cups/ppd.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+pstops.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+pstops.o: ../cups/file.h ../cups/array.h ../cups/language-private.h
+pstops.o: ../cups/transcode.h
+rasterbench.o: ../config.h ../cups/raster.h ../cups/cups.h ../cups/file.h
+rasterbench.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+rasterbench.o: ../cups/array.h ../cups/language.h ../cups/ppd.h
+rastertoepson.o: ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+rastertoepson.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+rastertoepson.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+rastertoepson.o: ../config.h ../cups/language-private.h ../cups/transcode.h
+rastertoepson.o: ../cups/raster.h ../cups/ppd.h
+rastertohp.o: ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+rastertohp.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+rastertohp.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+rastertohp.o: ../config.h ../cups/language-private.h ../cups/transcode.h
+rastertohp.o: ../cups/raster.h ../cups/ppd.h
+rastertolabel.o: ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+rastertolabel.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+rastertolabel.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+rastertolabel.o: ../config.h ../cups/language-private.h ../cups/transcode.h
+rastertolabel.o: ../cups/raster.h ../cups/ppd.h
+rastertopwg.o: ../cups/cups.h ../cups/language-private.h ../cups/transcode.h
+rastertopwg.o: ../cups/language.h ../cups/array.h ../cups/versioning.h
+rastertopwg.o: ../cups/raster.h ../cups/cups.h ../cups/file.h ../cups/ipp.h
+rastertopwg.o: ../cups/http.h ../cups/ppd.h ../cups/string-private.h
+rastertopwg.o: ../config.h
+testimage.o: image.h ../cups/raster.h ../cups/cups.h ../cups/file.h
+testimage.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+testimage.o: ../cups/array.h ../cups/language.h ../cups/ppd.h
+testraster.o: image-private.h image.h ../cups/raster.h ../cups/cups.h
+testraster.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+testraster.o: ../cups/http.h ../cups/array.h ../cups/language.h ../cups/ppd.h
+testraster.o: ../cups/cups.h ../cups/debug-private.h ../cups/string-private.h
+testraster.o: ../config.h
+textcommon.o: textcommon.h common.h ../cups/string-private.h ../config.h
+textcommon.o: ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+textcommon.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+textcommon.o: ../cups/array.h ../cups/language.h ../cups/language-private.h
+textcommon.o: ../cups/transcode.h
+texttops.o: textcommon.h common.h ../cups/string-private.h ../config.h
+texttops.o: ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+texttops.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+texttops.o: ../cups/language.h ../cups/language-private.h ../cups/transcode.h
+# DO NOT DELETE
+
+image-bmp.32.o: image-bmp.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-bmp.32.o: image-bmp.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-bmp.32.o: image-bmp.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-bmp.32.o: image-bmp.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-colorspace.32.o: image-colorspace.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-colorspace.32.o: image-colorspace.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-colorspace.32.o: image-colorspace.c ../cups/http.h ../cups/array.h ../cups/language.h
+image-colorspace.32.o: image-colorspace.c ../cups/ppd.h ../cups/cups.h ../cups/debug-private.h
+image-colorspace.32.o: image-colorspace.c ../cups/string-private.h ../config.h
+image-gif.32.o: image-gif.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-gif.32.o: image-gif.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-gif.32.o: image-gif.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-gif.32.o: image-gif.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-jpeg.32.o: image-jpeg.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-jpeg.32.o: image-jpeg.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-jpeg.32.o: image-jpeg.c ../cups/http.h ../cups/array.h ../cups/language.h ../cups/ppd.h
+image-jpeg.32.o: image-jpeg.c ../cups/cups.h ../cups/debug-private.h ../cups/string-private.h
+image-jpeg.32.o: image-jpeg.c ../config.h
+image-photocd.32.o: image-photocd.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-photocd.32.o: image-photocd.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-photocd.32.o: image-photocd.c ../cups/http.h ../cups/array.h ../cups/language.h
+image-photocd.32.o: image-photocd.c ../cups/ppd.h ../cups/cups.h ../cups/debug-private.h
+image-photocd.32.o: image-photocd.c ../cups/string-private.h ../config.h
+image-pix.32.o: image-pix.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-pix.32.o: image-pix.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-pix.32.o: image-pix.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-pix.32.o: image-pix.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-png.32.o: image-png.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-png.32.o: image-png.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-png.32.o: image-png.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-png.32.o: image-png.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-pnm.32.o: image-pnm.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-pnm.32.o: image-pnm.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-pnm.32.o: image-pnm.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-pnm.32.o: image-pnm.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-sgi.32.o: image-sgi.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-sgi.32.o: image-sgi.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-sgi.32.o: image-sgi.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-sgi.32.o: image-sgi.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-sgi.32.o: image-sgi.c image-sgi.h
+image-sgilib.32.o: image-sgilib.c image-sgi.h
+image-sun.32.o: image-sun.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-sun.32.o: image-sun.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-sun.32.o: image-sun.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-sun.32.o: image-sun.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-tiff.32.o: image-tiff.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-tiff.32.o: image-tiff.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-tiff.32.o: image-tiff.c ../cups/http.h ../cups/array.h ../cups/language.h ../cups/ppd.h
+image-tiff.32.o: image-tiff.c ../cups/cups.h ../cups/debug-private.h ../cups/string-private.h
+image-tiff.32.o: image-tiff.c ../config.h
+image-zoom.32.o: image-zoom.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-zoom.32.o: image-zoom.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-zoom.32.o: image-zoom.c ../cups/http.h ../cups/array.h ../cups/language.h ../cups/ppd.h
+image-zoom.32.o: image-zoom.c ../cups/cups.h ../cups/debug-private.h ../cups/string-private.h
+image-zoom.32.o: image-zoom.c ../config.h
+image.32.o: image.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image.32.o: image.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image.32.o: image.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image.32.o: image.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+error.32.o: error.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+error.32.o: error.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+error.32.o: error.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+error.32.o: error.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+interpret.32.o: interpret.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+interpret.32.o: interpret.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+interpret.32.o: interpret.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+interpret.32.o: interpret.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+raster.32.o: raster.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+raster.32.o: raster.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+raster.32.o: raster.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+raster.32.o: raster.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+bannertops.32.o: bannertops.c pstext.h common.h ../cups/string-private.h ../config.h
+bannertops.32.o: bannertops.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+bannertops.32.o: bannertops.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+bannertops.32.o: bannertops.c ../cups/array.h ../cups/language.h ../cups/transcode.h image.h
+bannertops.32.o: bannertops.c ../cups/raster.h ../cups/ppd.h ../cups/language-private.h
+commandtops.32.o: commandtops.c ../cups/cups-private.h ../cups/cups.h ../cups/string-private.h
+commandtops.32.o: commandtops.c ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+commandtops.32.o: commandtops.c ../cups/ppd.h ../cups/cups.h ../cups/file.h
+commandtops.32.o: commandtops.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+commandtops.32.o: commandtops.c ../cups/array.h ../cups/language.h ../cups/pwg-private.h
+commandtops.32.o: commandtops.c ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+commandtops.32.o: commandtops.c ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+commandtops.32.o: commandtops.c ../cups/transcode.h ../cups/thread-private.h
+commandtops.32.o: commandtops.c ../cups/sidechannel.h
+gziptoany.32.o: gziptoany.c ../cups/cups-private.h ../cups/cups.h ../cups/string-private.h
+gziptoany.32.o: gziptoany.c ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+gziptoany.32.o: gziptoany.c ../cups/ppd.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+gziptoany.32.o: gziptoany.c ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+gziptoany.32.o: gziptoany.c ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+gziptoany.32.o: gziptoany.c ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+gziptoany.32.o: gziptoany.c ../cups/language-private.h ../cups/transcode.h
+gziptoany.32.o: gziptoany.c ../cups/thread-private.h
+imagetops.32.o: imagetops.c common.h ../cups/string-private.h ../config.h ../cups/cups.h
+imagetops.32.o: imagetops.c ../cups/ppd.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+imagetops.32.o: imagetops.c ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+imagetops.32.o: imagetops.c image.h ../cups/raster.h ../cups/ppd.h
+imagetops.32.o: imagetops.c ../cups/language-private.h ../cups/transcode.h
+imagetoraster.32.o: imagetoraster.c common.h ../cups/string-private.h ../config.h ../cups/cups.h
+imagetoraster.32.o: imagetoraster.c ../cups/ppd.h ../cups/cups.h ../cups/file.h
+imagetoraster.32.o: imagetoraster.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+imagetoraster.32.o: imagetoraster.c ../cups/array.h ../cups/language.h image-private.h image.h
+imagetoraster.32.o: imagetoraster.c ../cups/raster.h ../cups/ppd.h ../cups/debug-private.h
+imagetoraster.32.o: imagetoraster.c ../cups/language-private.h ../cups/transcode.h
+common.32.o: common.c common.h ../cups/string-private.h ../config.h ../cups/cups.h
+common.32.o: common.c ../cups/ppd.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+common.32.o: common.c ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+pdftops.32.o: pdftops.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+pdftops.32.o: pdftops.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+pdftops.32.o: pdftops.c ../cups/language.h ../cups/string-private.h ../config.h
+pdftops.32.o: pdftops.c ../cups/language-private.h ../cups/transcode.h
+pstext.32.o: pstext.c pstext.h common.h ../cups/string-private.h ../config.h
+pstext.32.o: pstext.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+pstext.32.o: pstext.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+pstext.32.o: pstext.c ../cups/language.h ../cups/transcode.h ../cups/language-private.h
+pstops.32.o: pstops.c common.h ../cups/string-private.h ../config.h ../cups/cups.h
+pstops.32.o: pstops.c ../cups/ppd.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+pstops.32.o: pstops.c ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+pstops.32.o: pstops.c ../cups/file.h ../cups/array.h ../cups/language-private.h
+pstops.32.o: pstops.c ../cups/transcode.h
+rasterbench.32.o: rasterbench.c ../config.h ../cups/raster.h ../cups/cups.h ../cups/file.h
+rasterbench.32.o: rasterbench.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+rasterbench.32.o: rasterbench.c ../cups/array.h ../cups/language.h ../cups/ppd.h
+rastertoepson.32.o: rastertoepson.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+rastertoepson.32.o: rastertoepson.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+rastertoepson.32.o: rastertoepson.c ../cups/array.h ../cups/language.h ../cups/string-private.h
+rastertoepson.32.o: rastertoepson.c ../config.h ../cups/language-private.h ../cups/transcode.h
+rastertoepson.32.o: rastertoepson.c ../cups/raster.h ../cups/ppd.h
+rastertohp.32.o: rastertohp.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+rastertohp.32.o: rastertohp.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+rastertohp.32.o: rastertohp.c ../cups/array.h ../cups/language.h ../cups/string-private.h
+rastertohp.32.o: rastertohp.c ../config.h ../cups/language-private.h ../cups/transcode.h
+rastertohp.32.o: rastertohp.c ../cups/raster.h ../cups/ppd.h
+rastertolabel.32.o: rastertolabel.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+rastertolabel.32.o: rastertolabel.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+rastertolabel.32.o: rastertolabel.c ../cups/array.h ../cups/language.h ../cups/string-private.h
+rastertolabel.32.o: rastertolabel.c ../config.h ../cups/language-private.h ../cups/transcode.h
+rastertolabel.32.o: rastertolabel.c ../cups/raster.h ../cups/ppd.h
+rastertopwg.32.o: rastertopwg.c ../cups/cups.h ../cups/language-private.h ../cups/transcode.h
+rastertopwg.32.o: rastertopwg.c ../cups/language.h ../cups/array.h ../cups/versioning.h
+rastertopwg.32.o: rastertopwg.c ../cups/raster.h ../cups/cups.h ../cups/file.h ../cups/ipp.h
+rastertopwg.32.o: rastertopwg.c ../cups/http.h ../cups/ppd.h ../cups/string-private.h
+rastertopwg.32.o: rastertopwg.c ../config.h
+testimage.32.o: testimage.c image.h ../cups/raster.h ../cups/cups.h ../cups/file.h
+testimage.32.o: testimage.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+testimage.32.o: testimage.c ../cups/array.h ../cups/language.h ../cups/ppd.h
+testraster.32.o: testraster.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+testraster.32.o: testraster.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+testraster.32.o: testraster.c ../cups/http.h ../cups/array.h ../cups/language.h ../cups/ppd.h
+testraster.32.o: testraster.c ../cups/cups.h ../cups/debug-private.h ../cups/string-private.h
+testraster.32.o: testraster.c ../config.h
+textcommon.32.o: textcommon.c textcommon.h common.h ../cups/string-private.h ../config.h
+textcommon.32.o: textcommon.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+textcommon.32.o: textcommon.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+textcommon.32.o: textcommon.c ../cups/array.h ../cups/language.h ../cups/language-private.h
+textcommon.32.o: textcommon.c ../cups/transcode.h
+texttops.32.o: texttops.c textcommon.h common.h ../cups/string-private.h ../config.h
+texttops.32.o: texttops.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+texttops.32.o: texttops.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+texttops.32.o: texttops.c ../cups/language.h ../cups/language-private.h ../cups/transcode.h
+# DO NOT DELETE
+
+image-bmp.64.o: image-bmp.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-bmp.64.o: image-bmp.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-bmp.64.o: image-bmp.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-bmp.64.o: image-bmp.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-colorspace.64.o: image-colorspace.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-colorspace.64.o: image-colorspace.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-colorspace.64.o: image-colorspace.c ../cups/http.h ../cups/array.h ../cups/language.h
+image-colorspace.64.o: image-colorspace.c ../cups/ppd.h ../cups/cups.h ../cups/debug-private.h
+image-colorspace.64.o: image-colorspace.c ../cups/string-private.h ../config.h
+image-gif.64.o: image-gif.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-gif.64.o: image-gif.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-gif.64.o: image-gif.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-gif.64.o: image-gif.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-jpeg.64.o: image-jpeg.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-jpeg.64.o: image-jpeg.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-jpeg.64.o: image-jpeg.c ../cups/http.h ../cups/array.h ../cups/language.h ../cups/ppd.h
+image-jpeg.64.o: image-jpeg.c ../cups/cups.h ../cups/debug-private.h ../cups/string-private.h
+image-jpeg.64.o: image-jpeg.c ../config.h
+image-photocd.64.o: image-photocd.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-photocd.64.o: image-photocd.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-photocd.64.o: image-photocd.c ../cups/http.h ../cups/array.h ../cups/language.h
+image-photocd.64.o: image-photocd.c ../cups/ppd.h ../cups/cups.h ../cups/debug-private.h
+image-photocd.64.o: image-photocd.c ../cups/string-private.h ../config.h
+image-pix.64.o: image-pix.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-pix.64.o: image-pix.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-pix.64.o: image-pix.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-pix.64.o: image-pix.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-png.64.o: image-png.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-png.64.o: image-png.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-png.64.o: image-png.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-png.64.o: image-png.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-pnm.64.o: image-pnm.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-pnm.64.o: image-pnm.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-pnm.64.o: image-pnm.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-pnm.64.o: image-pnm.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-sgi.64.o: image-sgi.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-sgi.64.o: image-sgi.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-sgi.64.o: image-sgi.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-sgi.64.o: image-sgi.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-sgi.64.o: image-sgi.c image-sgi.h
+image-sgilib.64.o: image-sgilib.c image-sgi.h
+image-sun.64.o: image-sun.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-sun.64.o: image-sun.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image-sun.64.o: image-sun.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image-sun.64.o: image-sun.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+image-tiff.64.o: image-tiff.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-tiff.64.o: image-tiff.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-tiff.64.o: image-tiff.c ../cups/http.h ../cups/array.h ../cups/language.h ../cups/ppd.h
+image-tiff.64.o: image-tiff.c ../cups/cups.h ../cups/debug-private.h ../cups/string-private.h
+image-tiff.64.o: image-tiff.c ../config.h
+image-zoom.64.o: image-zoom.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image-zoom.64.o: image-zoom.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+image-zoom.64.o: image-zoom.c ../cups/http.h ../cups/array.h ../cups/language.h ../cups/ppd.h
+image-zoom.64.o: image-zoom.c ../cups/cups.h ../cups/debug-private.h ../cups/string-private.h
+image-zoom.64.o: image-zoom.c ../config.h
+image.64.o: image.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+image.64.o: image.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+image.64.o: image.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+image.64.o: image.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+error.64.o: error.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+error.64.o: error.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+error.64.o: error.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+error.64.o: error.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+interpret.64.o: interpret.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+interpret.64.o: interpret.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+interpret.64.o: interpret.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+interpret.64.o: interpret.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+raster.64.o: raster.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+raster.64.o: raster.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+raster.64.o: raster.c ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/cups.h
+raster.64.o: raster.c ../cups/debug-private.h ../cups/string-private.h ../config.h
+bannertops.64.o: bannertops.c pstext.h common.h ../cups/string-private.h ../config.h
+bannertops.64.o: bannertops.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+bannertops.64.o: bannertops.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+bannertops.64.o: bannertops.c ../cups/array.h ../cups/language.h ../cups/transcode.h image.h
+bannertops.64.o: bannertops.c ../cups/raster.h ../cups/ppd.h ../cups/language-private.h
+commandtops.64.o: commandtops.c ../cups/cups-private.h ../cups/cups.h ../cups/string-private.h
+commandtops.64.o: commandtops.c ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+commandtops.64.o: commandtops.c ../cups/ppd.h ../cups/cups.h ../cups/file.h
+commandtops.64.o: commandtops.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+commandtops.64.o: commandtops.c ../cups/array.h ../cups/language.h ../cups/pwg-private.h
+commandtops.64.o: commandtops.c ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+commandtops.64.o: commandtops.c ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+commandtops.64.o: commandtops.c ../cups/transcode.h ../cups/thread-private.h
+commandtops.64.o: commandtops.c ../cups/sidechannel.h
+gziptoany.64.o: gziptoany.c ../cups/cups-private.h ../cups/cups.h ../cups/string-private.h
+gziptoany.64.o: gziptoany.c ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+gziptoany.64.o: gziptoany.c ../cups/ppd.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+gziptoany.64.o: gziptoany.c ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+gziptoany.64.o: gziptoany.c ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+gziptoany.64.o: gziptoany.c ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+gziptoany.64.o: gziptoany.c ../cups/language-private.h ../cups/transcode.h
+gziptoany.64.o: gziptoany.c ../cups/thread-private.h
+imagetops.64.o: imagetops.c common.h ../cups/string-private.h ../config.h ../cups/cups.h
+imagetops.64.o: imagetops.c ../cups/ppd.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+imagetops.64.o: imagetops.c ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+imagetops.64.o: imagetops.c image.h ../cups/raster.h ../cups/ppd.h
+imagetops.64.o: imagetops.c ../cups/language-private.h ../cups/transcode.h
+imagetoraster.64.o: imagetoraster.c common.h ../cups/string-private.h ../config.h ../cups/cups.h
+imagetoraster.64.o: imagetoraster.c ../cups/ppd.h ../cups/cups.h ../cups/file.h
+imagetoraster.64.o: imagetoraster.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+imagetoraster.64.o: imagetoraster.c ../cups/array.h ../cups/language.h image-private.h image.h
+imagetoraster.64.o: imagetoraster.c ../cups/raster.h ../cups/ppd.h ../cups/debug-private.h
+imagetoraster.64.o: imagetoraster.c ../cups/language-private.h ../cups/transcode.h
+common.64.o: common.c common.h ../cups/string-private.h ../config.h ../cups/cups.h
+common.64.o: common.c ../cups/ppd.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+common.64.o: common.c ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+pdftops.64.o: pdftops.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+pdftops.64.o: pdftops.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+pdftops.64.o: pdftops.c ../cups/language.h ../cups/string-private.h ../config.h
+pdftops.64.o: pdftops.c ../cups/language-private.h ../cups/transcode.h
+pstext.64.o: pstext.c pstext.h common.h ../cups/string-private.h ../config.h
+pstext.64.o: pstext.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+pstext.64.o: pstext.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+pstext.64.o: pstext.c ../cups/language.h ../cups/transcode.h ../cups/language-private.h
+pstops.64.o: pstops.c common.h ../cups/string-private.h ../config.h ../cups/cups.h
+pstops.64.o: pstops.c ../cups/ppd.h ../cups/cups.h ../cups/file.h ../cups/versioning.h
+pstops.64.o: pstops.c ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+pstops.64.o: pstops.c ../cups/file.h ../cups/array.h ../cups/language-private.h
+pstops.64.o: pstops.c ../cups/transcode.h
+rasterbench.64.o: rasterbench.c ../config.h ../cups/raster.h ../cups/cups.h ../cups/file.h
+rasterbench.64.o: rasterbench.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+rasterbench.64.o: rasterbench.c ../cups/array.h ../cups/language.h ../cups/ppd.h
+rastertoepson.64.o: rastertoepson.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+rastertoepson.64.o: rastertoepson.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+rastertoepson.64.o: rastertoepson.c ../cups/array.h ../cups/language.h ../cups/string-private.h
+rastertoepson.64.o: rastertoepson.c ../config.h ../cups/language-private.h ../cups/transcode.h
+rastertoepson.64.o: rastertoepson.c ../cups/raster.h ../cups/ppd.h
+rastertohp.64.o: rastertohp.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+rastertohp.64.o: rastertohp.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+rastertohp.64.o: rastertohp.c ../cups/array.h ../cups/language.h ../cups/string-private.h
+rastertohp.64.o: rastertohp.c ../config.h ../cups/language-private.h ../cups/transcode.h
+rastertohp.64.o: rastertohp.c ../cups/raster.h ../cups/ppd.h
+rastertolabel.64.o: rastertolabel.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+rastertolabel.64.o: rastertolabel.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+rastertolabel.64.o: rastertolabel.c ../cups/array.h ../cups/language.h ../cups/string-private.h
+rastertolabel.64.o: rastertolabel.c ../config.h ../cups/language-private.h ../cups/transcode.h
+rastertolabel.64.o: rastertolabel.c ../cups/raster.h ../cups/ppd.h
+rastertopwg.64.o: rastertopwg.c ../cups/cups.h ../cups/language-private.h ../cups/transcode.h
+rastertopwg.64.o: rastertopwg.c ../cups/language.h ../cups/array.h ../cups/versioning.h
+rastertopwg.64.o: rastertopwg.c ../cups/raster.h ../cups/cups.h ../cups/file.h ../cups/ipp.h
+rastertopwg.64.o: rastertopwg.c ../cups/http.h ../cups/ppd.h ../cups/string-private.h
+rastertopwg.64.o: rastertopwg.c ../config.h
+testimage.64.o: testimage.c image.h ../cups/raster.h ../cups/cups.h ../cups/file.h
+testimage.64.o: testimage.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+testimage.64.o: testimage.c ../cups/array.h ../cups/language.h ../cups/ppd.h
+testraster.64.o: testraster.c image-private.h image.h ../cups/raster.h ../cups/cups.h
+testraster.64.o: testraster.c ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+testraster.64.o: testraster.c ../cups/http.h ../cups/array.h ../cups/language.h ../cups/ppd.h
+testraster.64.o: testraster.c ../cups/cups.h ../cups/debug-private.h ../cups/string-private.h
+testraster.64.o: testraster.c ../config.h
+textcommon.64.o: textcommon.c textcommon.h common.h ../cups/string-private.h ../config.h
+textcommon.64.o: textcommon.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+textcommon.64.o: textcommon.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+textcommon.64.o: textcommon.c ../cups/array.h ../cups/language.h ../cups/language-private.h
+textcommon.64.o: textcommon.c ../cups/transcode.h
+texttops.64.o: texttops.c textcommon.h common.h ../cups/string-private.h ../config.h
+texttops.64.o: texttops.c ../cups/cups.h ../cups/ppd.h ../cups/cups.h ../cups/file.h
+texttops.64.o: texttops.c ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+texttops.64.o: texttops.c ../cups/language.h ../cups/language-private.h ../cups/transcode.h
diff --git a/filter/Makefile b/filter/Makefile
new file mode 100644
index 000000000..80d992248
--- /dev/null
+++ b/filter/Makefile
@@ -0,0 +1,527 @@
+#
+# "$Id$"
+#
+# Filter makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2006 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# This file is subject to the Apple OS-Developed Software exception.
+#
+
+include ../Makedefs
+
+
+FILTERS = \
+ $(BANNERTOPS) \
+ commandtops \
+ gziptoany \
+ $(TEXTTOPS) \
+ pstops \
+ $(IMGFILTERS) \
+ $(PDFTOPS) \
+ rastertoepson \
+ rastertohp \
+ rastertolabel \
+ rastertopwg
+LIBTARGETS = \
+ $(LIBCUPSIMAGE) \
+ libcupsimage.a \
+ $(LIB32CUPSIMAGE) \
+ $(LIB64CUPSIMAGE)
+UNITTARGETS = \
+ rasterbench \
+ testimage \
+ testraster
+TARGETS = \
+ $(LIBTARGETS) \
+ $(FILTERS)
+
+IMAGEOBJS = image-bmp.o image-colorspace.o image-gif.o image-jpeg.o \
+ image-photocd.o image-pix.o image-png.o image-pnm.o \
+ image-sgi.o image-sgilib.o image-sun.o image-tiff.o \
+ image-zoom.o image.o error.o interpret.o raster.o
+IMAGE32OBJS = $(IMAGEOBJS:.o=.32.o)
+IMAGE64OBJS = $(IMAGEOBJS:.o=.64.o)
+OBJS = $(IMAGEOBJS) \
+ bannertops.o commandtops.o gziptoany.o imagetops.o \
+ imagetoraster.o common.o pdftops.o pstext.o pstops.o \
+ rasterbench.o rastertoepson.o rastertohp.o rastertolabel.o \
+ rastertopwg.o testimage.o testraster.o textcommon.o texttops.o
+
+
+#
+# Make all targets...
+#
+
+all: $(TARGETS)
+
+
+#
+# Make library targets...
+#
+
+libs: $(LIBTARGETS)
+
+
+#
+# Make unit tests...
+#
+
+unittests: $(UNITTARGETS)
+
+
+#
+# Clean all object files...
+#
+
+clean:
+ $(RM) $(OBJS) $(TARGETS) $(UNITTARGETS)
+ $(RM) libcupsimage.so libcupsimage.sl libcupsimage.dylib
+ $(RM) -r 32bit 64bit
+
+
+#
+# Update dependencies (without system header dependencies...)
+#
+
+depend:
+ touch Dependencies.tmp
+ makedepend -Y -I.. -fDependencies.tmp $(OBJS:.o=.c) >/dev/null 2>&1
+ $(RM) Dependencies
+ cp Dependencies.tmp Dependencies
+ sed -E -e '1,$$s/^([^.]+)\.o:/\1\.32.o: \1\.c /' Dependencies.tmp >>Dependencies
+ sed -E -e '1,$$s/^([^.]+)\.o:/\1\.64.o: \1\.c /' Dependencies.tmp >>Dependencies
+ $(RM) Dependencies.tmp
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+
+
+#
+# Install programs...
+#
+
+install-exec:
+ $(INSTALL_DIR) -m 755 $(SERVERBIN)/filter
+ for file in $(FILTERS); do \
+ $(INSTALL_BIN) $$file $(SERVERBIN)/filter; \
+ done
+ $(RM) $(SERVERBIN)/filter/rastertodymo
+ $(LN) rastertolabel $(SERVERBIN)/filter/rastertodymo
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ for file in $(FILTERS); do \
+ cp $$file $(SYMROOT); \
+ done \
+ fi
+
+
+#
+# Install headers...
+#
+
+install-headers:
+ $(INSTALL_DIR) -m 755 $(INCLUDEDIR)/cups
+ $(INSTALL_DATA) image.h $(INCLUDEDIR)/cups
+
+
+#
+# Install libraries...
+#
+
+install-libs: $(INSTALLSTATIC) $(INSTALL32) $(INSTALL64)
+ $(INSTALL_DIR) -m 755 $(LIBDIR)
+ $(INSTALL_LIB) $(LIBCUPSIMAGE) $(LIBDIR)
+ -if test $(LIBCUPSIMAGE) = "libcupsimage.so.2" -o $(LIBCUPSIMAGE) = "libcupsimage.sl.2"; then \
+ $(RM) $(LIBDIR)/`basename $(LIBCUPSIMAGE) .2`; \
+ $(LN) $(LIBCUPSIMAGE) $(LIBDIR)/`basename $(LIBCUPSIMAGE) .2`; \
+ fi
+ -if test $(LIBCUPSIMAGE) = "libcupsimage.2.dylib"; then \
+ $(RM) $(LIBDIR)/libcupsimage.dylib; \
+ $(LN) $(LIBCUPSIMAGE) $(LIBDIR)/libcupsimage.dylib; \
+ fi
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ cp $(LIBCUPSIMAGE) $(SYMROOT); \
+ fi
+
+installstatic:
+ $(INSTALL_DIR) -m 755 $(LIBDIR)
+ $(INSTALL_LIB) -m 755 libcupsimage.a $(LIBDIR)
+ $(RANLIB) $(LIBDIR)/libcupsimage.a
+ $(CHMOD) 555 $(LIBDIR)/libcupsimage.a
+
+install32bit:
+ $(INSTALL_DIR) -m 755 $(LIB32DIR)
+ $(INSTALL_LIB) 32bit/libcupsimage.so.2 $(LIB32DIR)/libcupsimage.so.2
+ $(LN) libcupsimage.so.2 $(LIB32DIR)/libcupsimage.so
+
+install64bit:
+ $(INSTALL_DIR) -m 755 $(LIB64DIR)
+ $(INSTALL_LIB) 64bit/libcupsimage.so.2 $(LIB64DIR)/libcupsimage.so.2
+ $(LN) libcupsimage.so.2 $(LIB64DIR)/libcupsimage.so
+
+
+#
+# Uninstall all targets...
+#
+
+uninstall: $(UNINSTALL32) $(UNINSTALL64)
+ for file in $(FILTERS); do \
+ $(RM) $(SERVERBIN)/filter/$$file; \
+ done
+ $(RM) $(SERVERBIN)/filter/rastertodymo
+ -$(RMDIR) $(SERVERBIN)/filter
+ -$(RMDIR) $(SERVERBIN)
+ $(RM) $(LIBDIR)/libcupsimage.2.dylib
+ $(RM) $(LIBDIR)/libcupsimage.a
+ $(RM) $(LIBDIR)/libcupsimage.dylib
+ $(RM) $(LIBDIR)/libcupsimage_s.a
+ $(RM) $(LIBDIR)/libcupsimage.sl
+ $(RM) $(LIBDIR)/libcupsimage.sl.2
+ $(RM) $(LIBDIR)/libcupsimage.so
+ $(RM) $(LIBDIR)/libcupsimage.so.2
+ -$(RMDIR) $(LIBDIR)
+ $(RM) $(INCLUDEDIR)/cups/image.h
+ -$(RMDIR) $(INCLUDEDIR)/cups
+
+uninstall32bit:
+ $(RM) $(LIB32DIR)/libcupsimage.so
+ $(RM) $(LIB32DIR)/libcupsimage.so.2
+ -$(RMDIR) $(LIB32DIR)
+
+uninstall64bit:
+ $(RM) $(LIB64DIR)/libcupsimage.so
+ $(RM) $(LIB64DIR)/libcupsimage.so.2
+ -$(RMDIR) $(LIB64DIR)
+
+
+#
+# Automatic API help files...
+#
+
+apihelp:
+ echo Generating CUPS API help files...
+ mxmldoc --section "Programming" --title "Raster API" \
+ --css ../doc/cups-printable.css \
+ --header api-raster.header --intro api-raster.shtml \
+ api-raster.xml \
+ ../cups/raster.h interpret.c raster.c \
+ >../doc/help/api-raster.html
+ mxmldoc --tokens help/api-raster.html api-raster.xml >../doc/help/api-raster.tokens
+ $(RM) api-raster.xml
+ mxmldoc --section "Programming" \
+ --title "Developing PostScript Printer Drivers" \
+ --css ../doc/cups-printable.css \
+ --header postscript-driver.header \
+ --intro postscript-driver.shtml \
+ >../doc/help/postscript-driver.html
+ mxmldoc --section "Programming" \
+ --title "Introduction to the PPD Compiler" \
+ --css ../doc/cups-printable.css \
+ --header ppd-compiler.header \
+ --intro ppd-compiler.shtml \
+ >../doc/help/ppd-compiler.html
+ mxmldoc --section "Programming" \
+ --title "Developing Raster Printer Drivers" \
+ --css ../doc/cups-printable.css \
+ --header raster-driver.header \
+ --intro raster-driver.shtml \
+ >../doc/help/raster-driver.html
+ mxmldoc --section "Specifications" \
+ --title "CUPS PPD Extensions" \
+ --css ../doc/cups-printable.css \
+ --header spec-ppd.header \
+ --intro spec-ppd.shtml \
+ >../doc/help/spec-ppd.html
+
+framedhelp:
+ echo Generating CUPS API help files...
+ mxmldoc --section "Programming" --title "Raster API" \
+ --framed ../cups/api-raster \
+ --css ../doc/cups-printable.css \
+ --header api-raster.header --intro api-raster.shtml \
+ ../cups/raster.h interpret.c raster.c
+ mxmldoc --section "Programming" \
+ --title "Developing PostScript Printer Drivers" \
+ --framed ../cups/postscript-driver \
+ --css ../doc/cups-printable.css \
+ --header postscript-driver.header \
+ --intro postscript-driver.shtml
+ mxmldoc --section "Programming" \
+ --title "Introduction to the PPD Compiler" \
+ --framed ../cups/ppd-compiler \
+ --css ../doc/cups-printable.css \
+ --header ppd-compiler.header \
+ --intro ppd-compiler.shtml
+ mxmldoc --section "Programming" \
+ --title "Developing Raster Printer Drivers" \
+ --framed ../cups/raster-driver \
+ --css ../doc/cups-printable.css \
+ --header raster-driver.header \
+ --intro raster-driver.shtml
+ mxmldoc --section "Specifications" \
+ --title "CUPS PPD Extensions" \
+ --framed ../cups/spec-ppd \
+ --css ../doc/cups-printable.css \
+ --header spec-ppd.header \
+ --intro spec-ppd.shtml \
+
+
+#
+# bannertops
+#
+
+bannertops: bannertops.o pstext.o common.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ bannertops.o pstext.o common.o $(LINKCUPSIMAGE) \
+ $(IMGLIBS) $(LIBS)
+
+
+#
+# commandtops
+#
+
+commandtops: commandtops.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ commandtops.o $(LIBS)
+
+
+#
+# gziptoany
+#
+
+gziptoany: gziptoany.o ../Makedefs ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ gziptoany.o $(LIBZ) $(LIBS)
+
+
+#
+# libcupsimage.so.2, libcupsimage.sl.2
+#
+
+libcupsimage.so.2 libcupsimage.sl.2: $(IMAGEOBJS)
+ echo Linking $@...
+ $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(IMAGEOBJS) $(DSOLIBS) \
+ -L../cups $(LINKCUPS) -lm
+ $(RM) `basename $@ .2`
+ $(LN) $@ `basename $@ .2`
+
+
+#
+# 32bit/libcupsimage.so.2
+#
+
+32bit/libcupsimage.so.2: $(IMAGE32OBJS)
+ echo Linking 32-bit $@...
+ -mkdir 32bit
+ $(DSO) $(ARCH32FLAGS) $(DSO32FLAGS) -o $@ $(IMAGE32OBJS) $(DSOLIBS) \
+ -L../cups/32bit $(LINKCUPS) -lm
+
+
+#
+# 64bit/libcupsimage.so.2
+#
+
+64bit/libcupsimage.so.2: $(IMAGE64OBJS)
+ echo Linking 64-bit $@...
+ -mkdir 64bit
+ $(DSO) $(ARCH64FLAGS) $(DSO64FLAGS) -o $@ $(IMAGE64OBJS) $(DSOLIBS) \
+ -L../cups/64bit $(LINKCUPS) -lm
+
+
+#
+# libcupsimage.2.dylib
+#
+
+libcupsimage.2.dylib: $(IMAGEOBJS) $(LIBCUPSIMAGEORDER)
+ echo Linking $@...
+ $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ \
+ -install_name $(libdir)/$@ \
+ -current_version 2.3.0 \
+ -compatibility_version 2.0.0 \
+ $(IMAGEOBJS) $(DSOLIBS) -L../cups $(LINKCUPS) -lm
+ $(RM) libcupsimage.dylib
+ $(LN) $@ libcupsimage.dylib
+
+
+#
+# libcupsimage_s.a
+#
+
+libcupsimage_s.a: $(IMAGEOBJS) libcupsimage_s.exp
+ echo Linking $@...
+ $(DSO) $(DSOFLAGS) -Wl,-berok,-bexport:libcupsimage_s.exp \
+ -o libcupsimage_s.o $(IMAGEOBJS) $(DSOLIBS) -lm
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ libcupsimage_s.o
+
+
+#
+# libcupsimage.la
+#
+
+libcupsimage.la: $(IMAGEOBJS)
+ echo Linking $@...
+ $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(IMAGEOBJS:.o=.lo) $(DSOLIBS) \
+ -L../cups $(LINKCUPS) \
+ -rpath $(LIBDIR) -version-info 2:3
+
+
+#
+# libcupsimage.a
+#
+
+libcupsimage.a: $(IMAGEOBJS)
+ echo Archiving $@...
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ $(IMAGEOBJS)
+ $(RANLIB) $@
+
+
+#
+# testimage
+#
+
+testimage: testimage.o libcupsimage.a ../Makedefs
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ testimage.o libcupsimage.a \
+ $(IMGLIBS) $(DSOLIBS) $(LIBS)
+
+
+#
+# imagetops
+#
+
+imagetops: imagetops.o common.o $(LIBCUPSIMAGE) \
+ ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ imagetops.o common.o $(LINKCUPSIMAGE) \
+ $(IMGLIBS) $(LIBS)
+
+
+#
+# imagetoraster
+#
+
+imagetoraster: imagetoraster.o common.o $(LIBCUPSIMAGE) \
+ ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ imagetoraster.o common.o $(LINKCUPSIMAGE) \
+ $(IMGLIBS) $(LIBS)
+
+
+#
+# pstops
+#
+
+pstops: pstops.o common.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ pstops.o common.o $(LIBS) -lm
+
+
+#
+# pdftops
+#
+
+pdftops: pdftops.o common.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ pdftops.o common.o $(LIBS)
+
+
+#
+# rastertoepson
+#
+
+rastertoepson: rastertoepson.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ rastertoepson.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS)
+
+
+#
+# rastertohp
+#
+
+rastertohp: rastertohp.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ rastertohp.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS)
+
+
+#
+# rastertolabel
+#
+
+rastertolabel: rastertolabel.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ rastertolabel.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS)
+
+
+#
+# rastertopwg
+#
+
+rastertopwg: rastertopwg.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ rastertopwg.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS)
+
+
+#
+# testraster
+#
+
+testraster: testraster.o ../cups/$(LIBCUPSSTATIC) libcupsimage.a
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testraster.o libcupsimage.a \
+ ../cups/$(LIBCUPSSTATIC) $(IMGLIBS) $(DSOLIBS) $(COMMONLIBS) \
+ $(SSLLIBS) $(DNSSDLIBS) $(LIBGSSAPI)
+ echo Running raster API tests...
+ ./testraster
+
+
+#
+# rasterbench
+#
+
+rasterbench: rasterbench.o libcupsimage.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ rasterbench.o libcupsimage.a $(LIBS)
+
+
+#
+# texttops
+#
+
+texttops: texttops.o textcommon.o common.o \
+ ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ texttops.o textcommon.o common.o $(LIBS)
+
+
+#
+# Dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id$".
+#
diff --git a/filter/api-raster.header b/filter/api-raster.header
new file mode 100644
index 000000000..201c799d3
--- /dev/null
+++ b/filter/api-raster.header
@@ -0,0 +1,37 @@
+<!--
+ "$Id: api-raster.header 9344 2010-10-26 23:45:18Z mike $"
+
+ Raster API documentation for CUPS.
+
+ Copyright 2008-2010 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Raster API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/raster.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcupsimage</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html'>Introduction to CUPS Programming</a><br>
+ Programming: <a href='api-cups.html'>CUPS API</a><br>
+ Programming: <a href='api-cups.html'>PPD API</a><br>
+ References: <a href='spec-ppd.html'>CUPS PPD Specification</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/filter/api-raster.shtml b/filter/api-raster.shtml
new file mode 100644
index 000000000..a309022ea
--- /dev/null
+++ b/filter/api-raster.shtml
@@ -0,0 +1,160 @@
+<!--
+ "$Id$"
+
+ Raster API introduction for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2006 by Easy Software Products, all rights reserved.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name="OVERVIEW">Overview</a></h2>
+
+<p>The CUPS raster API provides a standard interface for reading and writing
+CUPS raster streams which are used for printing to raster printers. Because the
+raster format is updated from time to time, it is important to use this API to
+avoid incompatibilities with newer versions of CUPS.</p>
+
+<p>Two kinds of CUPS filters use the CUPS raster API - raster image processor
+(RIP) filters such as <code>pstoraster</code> and <code>cgpdftoraster</code>
+(Mac OS X) that produce CUPS raster files and printer driver filters that
+convert CUPS raster files into a format usable by the printer. Printer
+driver filters are by far the most common.</p>
+
+<p>CUPS raster files (<code>application/vnd.cups-raster</code>) consists of
+a stream of raster page descriptions produced by one of the RIP filters such as
+<var>pstoraster</var>, <var>imagetoraster</var>, or
+<var>cgpdftoraster</var>. CUPS raster files are referred to using the
+<a href='#cups_raster_t'><code>cups_raster_t</code></a> type and are
+opened using the <a href='#cupsRasterOpen'><code>cupsRasterOpen</code></a>
+function. For example, to read raster data from the standard input, open
+file descriptor 0:</p>
+
+<pre class="example">
+#include &lt;cups/raster.h&gt;>
+
+<a href="#cups_raster_t">cups_raster_t</a> *ras = <a href="#cupsRasterOpen">cupsRasterOpen</a>(0, CUPS_RASTER_READ);
+</pre>
+
+<p>Each page of data begins with a page dictionary structure called
+<a href="#cups_page_header2_t"><code>cups_page_header2_t</code></a>. This
+structure contains the colorspace, bits per color, media size, media type,
+hardware resolution, and so forth used for the page.</p>
+
+<blockquote><b>Note:</b>
+
+ <p>Do not confuse the colorspace in the page header with the PPD
+ <tt>ColorModel</tt> keyword. <tt>ColorModel</tt> refers to the general type of
+ color used for a device (Gray, RGB, CMYK, DeviceN) and is often used to
+ select a particular colorspace for the page header along with the associate
+ color profile. The page header colorspace (<tt>cupsColorSpace</tt>) describes
+ both the type and organization of the color data, for example KCMY (black
+ first) instead of CMYK and RGBA (RGB + alpha) instead of RGB.</p>
+
+</blockquote>
+
+<p>You read the page header using the
+<a href="#cupsRasterReadHeader2"><code>cupsRasterReadHeader2</code></a>
+function:</p>
+
+<pre class="example">
+#include &lt;cups/raster.h&gt;>
+
+<a href="#cups_raster_t">cups_raster_t</a> *ras = <a href="#cupsRasterOpen">cupsRasterOpen</a>(0, CUPS_RASTER_READ);
+<a href="#cups_page_header2_t">cups_page_header2_t</a> header;
+
+while (<a href="#cupsRasterReadHeader2">cupsRasterReadHeader2</a>(ras, &amp;header))
+{
+ /* setup this page */
+
+ /* read raster data */
+
+ /* finish this page */
+}
+</pre>
+
+<p>After the page dictionary comes the page data which is a full-resolution,
+possibly compressed bitmap representing the page in the printer's output
+colorspace. You read uncompressed raster data using the
+<a href="#cupsRasterReadPixels"><code>cupsRasterReadPixels</code></a>
+function. A <code>for</code> loop is normally used to read the page one line
+at a time:</p>
+
+<pre class="example">
+#include &lt;cups/raster.h&gt;>
+
+<a href="#cups_raster_t">cups_raster_t</a> *ras = <a href="#cupsRasterOpen">cupsRasterOpen</a>(0, CUPS_RASTER_READ);
+<a href="#cups_page_header2_t">cups_page_header2_t</a> header;
+int page = 0;
+int y;
+char *buffer;
+
+while (<a href="#cupsRasterReadHeader2">cupsRasterReadHeader2</a>(ras, &amp;header))
+{
+ /* setup this page */
+ page ++;
+ fprintf(stderr, "PAGE: %d %d\n", page, header.NumCopies);
+
+ /* allocate memory for 1 line */
+ buffer = malloc(header.cupsBytesPerLine);
+
+ /* read raster data */
+ for (y = 0; y &lt; header.cupsHeight; y ++)
+ {
+ if (<a href="#cupsRasterReadPixels">cupsRasterReadPixels</a>(ras, buffer, header.cupsBytesPerLine) == 0)
+ break;
+
+ /* write raster data to printer on stdout */
+ }
+
+ /* finish this page */
+}
+</pre>
+
+<p>When you are done reading the raster data, call the
+<a href="#cupsRasterClose"><code>cupsRasterClose</code></a> function to free
+the memory used to read the raster file:</p>
+
+<pre class="example">
+<a href="#cups_raster_t">cups_raster_t</a> *ras;
+
+<a href="#cupsRasterClose">cupsRasterClose</a>(ras);
+</pre>
+
+
+<h2 class='title'><a name="TASKS">Functions by Task</a></h2>
+
+<h3><a name="OPENCLOSE">Opening and Closing Raster Streams</a></h3>
+
+<ul class="code">
+
+ <li><a href="#cupsRasterClose" title="Close a raster stream.">cupsRasterClose</a></li>
+ <li><a href="#cupsRasterOpen" title="Open a raster stream.">cupsRasterOpen</a></li>
+
+</ul>
+
+<h3><a name="READING">Reading Raster Streams</a></h3>
+
+<ul class="code">
+
+ <li><a href="#cupsRasterReadHeader" title="Read a raster page header and store it in a version 1 page header structure.">cupsRasterReadHeader</a> <span class="info">Deprecated in CUPS 1.2/Mac OS X 10.5</span></li>
+ <li><a href="#cupsRasterReadHeader2" title="Read a raster page header and store it in a version 2 page header structure.">cupsRasterReadHeader2</a></li>
+ <li><a href="#cupsRasterReadPixels" title="Read raster pixels.">cupsRasterReadPixels</a></li>
+
+</ul>
+
+<h3><a name="WRITING">Writing Raster Streams</a></h3>
+
+<ul class="code">
+
+ <li><a href="#cupsRasterInterpretPPD" title="Interpret PPD commands to create a page header.">cupsRasterInterpretPPD</a></li>
+ <li><a href="#cupsRasterWriteHeader" title="Write a raster page header from a version 1 page header structure.">cupsRasterWriteHeader</a> <span class="info">Deprecated in CUPS 1.2/Mac OS X 10.5</span></li>
+ <li><a href="#cupsRasterWriteHeader2" title="Write a raster page header from a version 2 page header structure.">cupsRasterWriteHeader2</a></li>
+ <li><a href="#cupsRasterWritePixels" title="Write raster pixels.">cupsRasterWritePixels</a></li>
+
+</ul>
diff --git a/filter/bannertops.c b/filter/bannertops.c
new file mode 100644
index 000000000..467980e99
--- /dev/null
+++ b/filter/bannertops.c
@@ -0,0 +1,1094 @@
+/*
+ * "$Id$"
+ *
+ * Banner to PostScript filter for CUPS.
+ *
+ * Copyright 2008-2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Generate PostScript cover pages.
+ * load_banner() - Load the banner file.
+ * ps_ascii85() - Print binary data as a series of base-85 numbers.
+ * write_banner() - Write a banner page...
+ * write_epilogue() - Write the PostScript file epilogue.
+ * write_prolog() - Write the PostScript file prolog with options.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "pstext.h"
+#include "image.h"
+#include <cups/language-private.h>
+
+
+/*
+ * Constants...
+ */
+
+#define SHOW_IMAGEABLE_AREA 1 /* Show imageable area */
+#define SHOW_JOB_BILLING 2 /* Show billing string */
+#define SHOW_JOB_ID 4 /* Show job ID */
+#define SHOW_JOB_NAME 8 /* Show job title */
+#define SHOW_JOB_ORIGINATING_USER_NAME 16 /* Show owner of job */
+#define SHOW_JOB_ORIGINATING_HOST_NAME 32 /* Show submitting system */
+#define SHOW_JOB_UUID 64 /* Show job UUID */
+#define SHOW_OPTIONS 128 /* Show print options */
+#define SHOW_PAPER_NAME 256 /* Show paper size name */
+#define SHOW_PAPER_SIZE 512 /* Show paper dimensions */
+#define SHOW_PRINTER_DRIVER_NAME 1024 /* Show printer driver name */
+#define SHOW_PRINTER_DRIVER_VERSION 2048 /* Show printer driver version */
+#define SHOW_PRINTER_INFO 4096 /* Show printer description */
+#define SHOW_PRINTER_LOCATION 8192 /* Show printer location */
+#define SHOW_PRINTER_MAKE_AND_MODEL 16384 /* Show printer make and model */
+#define SHOW_PRINTER_NAME 32768 /* Show printer queue ID */
+#define SHOW_TIME_AT_CREATION 65536 /* Show date/time when submitted */
+#define SHOW_TIME_AT_PROCESSING 131072 /* Show date/time when printed */
+
+
+/*
+ * Structures...
+ */
+
+typedef struct banner_file_s /**** Banner file data ****/
+{
+ int show; /* What to show */
+ char *header, /* Header text */
+ *footer; /* Footer text */
+ cups_array_t *notices, /* Notices to show */
+ *images; /* Images to show */
+} banner_file_t;
+
+
+/*
+ * Local functions...
+ */
+
+static banner_file_t *load_banner(const char *filename);
+static int write_banner(banner_file_t *banner, ppd_file_t *ppd,
+ ps_text_t *fonts, int job_id,
+ const char *title, const char *username,
+ int num_options, cups_option_t *options);
+static void write_epilogue(int num_pages);
+static ps_text_t *write_prolog(const char *title, const char *user);
+
+
+/*
+ * 'main()' - Generate PostScript cover pages.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ banner_file_t *banner; /* Banner file data */
+ int num_options; /* Number of print options */
+ cups_option_t *options; /* Print options */
+ ppd_file_t *ppd; /* PPD file */
+ ps_text_t *fonts; /* Fonts for output */
+ int job_id; /* Job ID from command-line */
+ const char *title, /* Title from command-line */
+ *username; /* Username from command-line */
+ int num_pages; /* Number of pages printed */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options file"),
+ argv[0]);
+ return (1);
+ }
+
+ /*
+ * Get stuff from command-line...
+ */
+
+ job_id = atoi(argv[1]);
+ username = argv[2];
+ title = argv[3];
+ options = NULL;
+ num_options = cupsParseOptions(argv[5], 0, &options);
+ banner = load_banner(argv[6]);
+
+ /*
+ * Set standard options and get the PPD file for this printer...
+ */
+
+ ppd = SetCommonOptions(num_options, options, 1);
+
+ /*
+ * Write a PostScript banner document and return...
+ */
+
+ fonts = write_prolog(title, username);
+ num_pages = write_banner(banner, ppd, fonts, job_id, title, username,
+ num_options, options);
+
+ write_epilogue(num_pages);
+
+ return (0);
+}
+
+
+/*
+ * 'load_banner()' - Load the banner file.
+ */
+
+static banner_file_t * /* O - Banner file data */
+load_banner(const char *filename) /* I - Filename or NULL for stdin */
+{
+ cups_file_t *fp; /* File */
+ char line[2048], /* Line buffer */
+ *ptr; /* Pointer into line */
+ int linenum; /* Current line number */
+ banner_file_t *banner; /* Banner file data */
+ const char *cups_docroot; /* CUPS_DOCROOT environment variable */
+
+
+ fprintf(stderr, "DEBUG: load_banner(filename=\"%s\")\n",
+ filename ? filename : "(stdin)");
+
+ /*
+ * Open the banner file...
+ */
+
+ if (filename)
+ fp = cupsFileOpen(filename, "r");
+ else
+ fp = cupsFileStdin();
+
+ if (!fp)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ exit(1);
+ }
+
+ /*
+ * Read the banner file...
+ */
+
+ if ((cups_docroot = getenv("CUPS_DOCROOT")) == NULL)
+ cups_docroot = CUPS_DOCROOT;
+
+ banner = calloc(1, sizeof(banner_file_t));
+ linenum = 0;
+
+ while (cupsFileGets(fp, line, sizeof(line)))
+ {
+ /*
+ * Skip blank and comment lines...
+ */
+
+ linenum ++;
+
+ fprintf(stderr, "DEBUG: %4d %s\n", linenum, line);
+
+ if (line[0] == '#' || !line[0])
+ continue;
+
+ /*
+ * Break the line into keyword and value parts...
+ */
+
+ for (ptr = line; *ptr && !isspace(*ptr & 255); ptr ++);
+
+ while (isspace(*ptr & 255))
+ *ptr++ = '\0';
+
+ if (!*ptr)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Missing value on line %d of banner file."),
+ linenum);
+ continue;
+ }
+
+ /*
+ * Save keyword values in the appropriate places...
+ */
+
+ if (!_cups_strcasecmp(line, "Footer"))
+ {
+ if (banner->footer)
+ fprintf(stderr, "DEBUG: Extra \"Footer\" on line %d of banner file\n",
+ linenum);
+ else
+ banner->footer = strdup(ptr);
+ }
+ else if (!_cups_strcasecmp(line, "Header"))
+ {
+ if (banner->header)
+ fprintf(stderr, "DEBUG: Extra \"Header\" on line %d of banner file\n",
+ linenum);
+ else
+ banner->header = strdup(ptr);
+ }
+ else if (!_cups_strcasecmp(line, "Image"))
+ {
+ char imagefile[1024]; /* Image filename */
+
+
+ if (ptr[0] == '/')
+ strlcpy(imagefile, ptr, sizeof(imagefile));
+ else
+ snprintf(imagefile, sizeof(imagefile), "%s/%s", cups_docroot, ptr);
+
+ if (access(imagefile, R_OK))
+ {
+ fprintf(stderr, "DEBUG: Image \"%s\" on line %d of banner file: %s\n",
+ ptr, linenum, strerror(errno));
+ }
+ else
+ {
+ if (!banner->images)
+ banner->images = cupsArrayNew(NULL, NULL);
+
+ cupsArrayAdd(banner->images, strdup(imagefile));
+ }
+ }
+ else if (!_cups_strcasecmp(line, "Notice"))
+ {
+ if (!banner->notices)
+ banner->notices = cupsArrayNew(NULL, NULL);
+
+ cupsArrayAdd(banner->notices, strdup(ptr));
+ }
+ else if (!_cups_strcasecmp(line, "Show"))
+ {
+ char *value; /* Current value */
+
+
+ for (value = ptr; *value; value = ptr)
+ {
+ /*
+ * Find the end of the current value
+ */
+
+ while (*ptr && !isspace(*ptr & 255))
+ ptr ++;
+
+ while (*ptr && isspace(*ptr & 255))
+ *ptr++ = '\0';
+
+ /*
+ * Add the value to the show flags...
+ */
+ if (!_cups_strcasecmp(value, "imageable-area"))
+ banner->show |= SHOW_IMAGEABLE_AREA;
+ else if (!_cups_strcasecmp(value, "job-billing"))
+ banner->show |= SHOW_JOB_BILLING;
+ else if (!_cups_strcasecmp(value, "job-id"))
+ banner->show |= SHOW_JOB_ID;
+ else if (!_cups_strcasecmp(value, "job-name"))
+ banner->show |= SHOW_JOB_NAME;
+ else if (!_cups_strcasecmp(value, "job-originating-host-name"))
+ banner->show |= SHOW_JOB_ORIGINATING_HOST_NAME;
+ else if (!_cups_strcasecmp(value, "job-originating-user-name"))
+ banner->show |= SHOW_JOB_ORIGINATING_USER_NAME;
+ else if (!_cups_strcasecmp(value, "job-uuid"))
+ banner->show |= SHOW_JOB_UUID;
+ else if (!_cups_strcasecmp(value, "options"))
+ banner->show |= SHOW_OPTIONS;
+ else if (!_cups_strcasecmp(value, "paper-name"))
+ banner->show |= SHOW_PAPER_NAME;
+ else if (!_cups_strcasecmp(value, "paper-size"))
+ banner->show |= SHOW_PAPER_SIZE;
+ else if (!_cups_strcasecmp(value, "printer-driver-name"))
+ banner->show |= SHOW_PRINTER_DRIVER_NAME;
+ else if (!_cups_strcasecmp(value, "printer-driver-version"))
+ banner->show |= SHOW_PRINTER_DRIVER_VERSION;
+ else if (!_cups_strcasecmp(value, "printer-info"))
+ banner->show |= SHOW_PRINTER_INFO;
+ else if (!_cups_strcasecmp(value, "printer-location"))
+ banner->show |= SHOW_PRINTER_LOCATION;
+ else if (!_cups_strcasecmp(value, "printer-make-and-model"))
+ banner->show |= SHOW_PRINTER_MAKE_AND_MODEL;
+ else if (!_cups_strcasecmp(value, "printer-name"))
+ banner->show |= SHOW_PRINTER_NAME;
+ else if (!_cups_strcasecmp(value, "time-at-creation"))
+ banner->show |= SHOW_TIME_AT_CREATION;
+ else if (!_cups_strcasecmp(value, "time-at-processing"))
+ banner->show |= SHOW_TIME_AT_PROCESSING;
+ else
+ {
+ fprintf(stderr,
+ "DEBUG: Unknown \"Show\" value \"%s\" on line %d of banner "
+ "file\n", value, linenum);
+ }
+ }
+ }
+ else
+ fprintf(stderr, "DEBUG: Unknown key \"%s\" on line %d of banner file\n",
+ line, linenum);
+ }
+
+ if (filename)
+ cupsFileClose(fp);
+
+ return (banner);
+}
+
+
+/*
+ * 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
+ */
+
+static void
+ps_ascii85(cups_ib_t *data, /* I - Data to print */
+ int length, /* I - Number of bytes to print */
+ int last_line) /* I - Last line of raster data? */
+{
+ unsigned b; /* Binary data word */
+ unsigned char c[5]; /* ASCII85 encoded chars */
+ static int col = 0; /* Current column */
+
+
+ while (length > 3)
+ {
+ b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
+
+ if (b == 0)
+ {
+ putchar('z');
+ col ++;
+ }
+ else
+ {
+ c[4] = (b % 85) + '!';
+ b /= 85;
+ c[3] = (b % 85) + '!';
+ b /= 85;
+ c[2] = (b % 85) + '!';
+ b /= 85;
+ c[1] = (b % 85) + '!';
+ b /= 85;
+ c[0] = b + '!';
+
+ fwrite(c, 5, 1, stdout);
+ col += 5;
+ }
+
+ data += 4;
+ length -= 4;
+
+ if (col >= 75)
+ {
+ putchar('\n');
+ col = 0;
+ }
+ }
+
+ if (last_line)
+ {
+ if (length > 0)
+ {
+ memset(data + length, 0, 4 - length);
+ b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
+
+ c[4] = (b % 85) + '!';
+ b /= 85;
+ c[3] = (b % 85) + '!';
+ b /= 85;
+ c[2] = (b % 85) + '!';
+ b /= 85;
+ c[1] = (b % 85) + '!';
+ b /= 85;
+ c[0] = b + '!';
+
+ fwrite(c, length + 1, 1, stdout);
+ }
+
+ puts("~>");
+ col = 0;
+ }
+}
+
+
+/*
+ * 'write_banner()' - Write a banner page...
+ */
+
+static int /* O - Number of pages */
+write_banner(banner_file_t *banner, /* I - Banner file */
+ ppd_file_t *ppd, /* I - PPD file */
+ ps_text_t *fonts, /* I - Fonts */
+ int job_id, /* I - Job ID */
+ const char *title, /* I - Title of job */
+ const char *username, /* I - Owner of job */
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ char *notice; /* Current notice */
+ char *imagefile; /* Current image file */
+ cups_array_t *images; /* Images */
+ cups_image_t *image; /* Current image */
+ const char *option; /* Option value */
+ int i, j; /* Looping vars */
+ float x, /* Current X position */
+ y; /* Current Y position */
+ cups_lang_t *language; /* Default language */
+ int showlines; /* Number of lines to show */
+ float fontsize; /* Font size to use */
+ int num_pages; /* Number of pages */
+ float print_width, /* Printable width of page */
+ print_height, /* Printable height of page */
+ info_top, /* Top of info fields */
+ info_height, /* Height of info fields */
+ line_height, /* Height of info lines */
+ notices_height, /* Height of all notices */
+ images_width, /* Width of all images */
+ images_height, /* Height of all images */
+ total_height; /* Height of all content */
+ char text[1024]; /* Formatted field text */
+
+
+ /*
+ * Figure out how many lines of text will be shown...
+ */
+
+ showlines = 0;
+ if (banner->show & SHOW_IMAGEABLE_AREA)
+ showlines += 2;
+ if (banner->show & SHOW_JOB_BILLING)
+ showlines ++;
+ if (banner->show & SHOW_JOB_ID)
+ showlines ++;
+ if (banner->show & SHOW_JOB_NAME)
+ showlines ++;
+ if (banner->show & SHOW_JOB_ORIGINATING_USER_NAME)
+ showlines ++;
+ if (banner->show & SHOW_JOB_ORIGINATING_HOST_NAME)
+ showlines ++;
+ if (banner->show & SHOW_JOB_UUID)
+ showlines ++;
+ if (banner->show & SHOW_OPTIONS)
+ {
+ for (j = 0; j < num_options; j ++)
+ {
+ if (_cups_strcasecmp("media", options[j].name) &&
+ _cups_strcasecmp("PageSize", options[j].name) &&
+ _cups_strcasecmp("PageRegion", options[j].name) &&
+ _cups_strcasecmp("InputSlot", options[j].name) &&
+ _cups_strcasecmp("MediaType", options[j].name) &&
+ _cups_strcasecmp("finishings", options[j].name) &&
+ _cups_strcasecmp("sides", options[j].name) &&
+ _cups_strcasecmp("Duplex", options[j].name) &&
+ _cups_strcasecmp("orientation-requested", options[j].name) &&
+ _cups_strcasecmp("landscape", options[j].name) &&
+ _cups_strcasecmp("number-up", options[j].name) &&
+ _cups_strcasecmp("OutputOrder", options[j].name))
+ continue;
+
+ showlines ++;
+ }
+ }
+ if (banner->show & SHOW_PAPER_NAME)
+ showlines ++;
+ if (banner->show & SHOW_PAPER_SIZE)
+ showlines += 2;
+ if (banner->show & SHOW_PRINTER_DRIVER_NAME)
+ showlines ++;
+ if (banner->show & SHOW_PRINTER_DRIVER_VERSION)
+ showlines ++;
+ if (banner->show & SHOW_PRINTER_INFO)
+ showlines ++;
+ if (banner->show & SHOW_PRINTER_LOCATION)
+ showlines ++;
+ if (banner->show & SHOW_PRINTER_MAKE_AND_MODEL)
+ showlines ++;
+ if (banner->show & SHOW_PRINTER_NAME)
+ showlines ++;
+ if (banner->show & SHOW_TIME_AT_CREATION)
+ showlines ++;
+ if (banner->show & SHOW_TIME_AT_PROCESSING)
+ showlines ++;
+
+ /*
+ * Figure out the dimensions and positions of everything...
+ */
+
+ print_width = PageRight - PageLeft;
+ print_height = PageTop - PageBottom;
+ fontsize = print_height / 60; /* Nominally 12pts */
+ line_height = 1.2 * fontsize;
+ info_height = showlines * line_height;
+ notices_height = cupsArrayCount(banner->notices) * line_height;
+
+ if (cupsArrayCount(banner->images))
+ {
+ images = cupsArrayNew(NULL, NULL);
+ images_height = print_height / 10; /* Nominally 1" */
+
+ for (imagefile = (char *)cupsArrayFirst(banner->images), images_width = 0.0;
+ imagefile;
+ imagefile = (char *)cupsArrayNext(banner->images))
+ {
+ if ((image = cupsImageOpen(imagefile, ColorDevice ? CUPS_IMAGE_RGB_CMYK :
+ CUPS_IMAGE_WHITE,
+ CUPS_IMAGE_WHITE, 100, 0, NULL)) == NULL)
+ {
+ fprintf(stderr, "DEBUG: Unable to open image file \"%s\"\n",
+ imagefile);
+ continue;
+ }
+
+ images_width += cupsImageGetWidth(image) * images_height /
+ cupsImageGetHeight(image);
+ cupsArrayAdd(images, image);
+ }
+ }
+ else
+ {
+ images = NULL;
+ images_height = 0;
+ images_width = 0;
+ }
+
+ total_height = info_height + notices_height + images_height;
+ if (cupsArrayCount(banner->notices) && showlines)
+ total_height += 2 * line_height;
+ if (cupsArrayCount(banner->images) &&
+ (showlines || cupsArrayCount(banner->notices)))
+ total_height += 2 * line_height;
+
+ info_top = 0.5 * (print_height + total_height);
+
+ /*
+ * Write the page(s)...
+ */
+
+ language = cupsLangDefault();
+ num_pages = Duplex ? 2 : 1;
+
+ for (i = 1; i <= num_pages; i ++)
+ {
+ /*
+ * Start the page...
+ */
+
+ printf("%%%%Page: %s %d\n", i == 1 ? "coverpage" : "coverback", i);
+ puts("gsave");
+ if (i == 1)
+ printf("%.1f %.1f translate\n", PageLeft, PageBottom);
+ else
+ printf("%.1f %.1f translate\n", PageWidth - PageRight,
+ PageLength - PageTop);
+ puts("0 setgray");
+
+ y = info_top;
+
+ /*
+ * Information...
+ */
+
+ if (banner->show)
+ {
+ x = 0.33 * print_width;
+
+ if (banner->show & SHOW_PRINTER_NAME)
+ {
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Printer Name: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, getenv("PRINTER"));
+ }
+ if (banner->show & SHOW_JOB_ID)
+ {
+ snprintf(text, sizeof(text), "%s-%d", getenv("PRINTER"), job_id);
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Job ID: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+ }
+ if (banner->show & SHOW_JOB_UUID)
+ {
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Job UUID: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+ cupsGetOption("job-uuid", num_options, options));
+ }
+ if (banner->show & SHOW_JOB_NAME)
+ {
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Title: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, title);
+ }
+ if (banner->show & SHOW_JOB_ORIGINATING_USER_NAME)
+ {
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Printed For: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, username);
+ }
+ if (banner->show & SHOW_JOB_ORIGINATING_HOST_NAME)
+ {
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Printed From: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+ cupsGetOption("job-originating-host-name", num_options,
+ options));
+ }
+ if (banner->show & SHOW_JOB_BILLING)
+ {
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Billing Information: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+ cupsGetOption("job-billing", num_options, options));
+ }
+ if (banner->show & SHOW_OPTIONS)
+ {
+ printf("%.1f %.1f moveto", x, y);
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Options: ")));
+
+ for (j = 0; j < num_options; j ++)
+ {
+ if (_cups_strcasecmp("media", options[j].name) &&
+ _cups_strcasecmp("PageSize", options[j].name) &&
+ _cups_strcasecmp("PageRegion", options[j].name) &&
+ _cups_strcasecmp("InputSlot", options[j].name) &&
+ _cups_strcasecmp("MediaType", options[j].name) &&
+ _cups_strcasecmp("finishings", options[j].name) &&
+ _cups_strcasecmp("sides", options[j].name) &&
+ _cups_strcasecmp("Duplex", options[j].name) &&
+ _cups_strcasecmp("orientation-requested", options[j].name) &&
+ _cups_strcasecmp("landscape", options[j].name) &&
+ _cups_strcasecmp("number-up", options[j].name) &&
+ _cups_strcasecmp("OutputOrder", options[j].name))
+ continue;
+
+ if (!_cups_strcasecmp("landscape", options[j].name))
+ strlcpy(text, "orientation-requested=landscape", sizeof(text));
+ else if (!_cups_strcasecmp("orientation-requested", options[j].name))
+ {
+ switch (atoi(options[j].value))
+ {
+ default :
+ case IPP_PORTRAIT :
+ strlcpy(text, "orientation-requested=portrait",
+ sizeof(text));
+ break;
+
+ case IPP_LANDSCAPE :
+ strlcpy(text, "orientation-requested=landscape",
+ sizeof(text));
+ break;
+
+ case IPP_REVERSE_PORTRAIT :
+ strlcpy(text, "orientation-requested=reverse-portrait",
+ sizeof(text));
+ break;
+
+ case IPP_REVERSE_LANDSCAPE :
+ strlcpy(text, "orientation-requested=reverse-landscape",
+ sizeof(text));
+ break;
+ }
+ }
+ else
+ snprintf(text, sizeof(text), "%s=%s", options[j].name,
+ options[j].value);
+
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+ }
+ }
+
+ if (banner->show & SHOW_PRINTER_INFO)
+ {
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Description: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+ getenv("PRINTER_INFO"));
+ }
+ if (banner->show & SHOW_PRINTER_LOCATION)
+ {
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Location: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+ getenv("PRINTER_LOCATION"));
+ }
+ if (banner->show & SHOW_PRINTER_MAKE_AND_MODEL)
+ {
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Make and Model: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+ ppd ? ppd->nickname : NULL);
+ }
+
+ if (banner->show & SHOW_PAPER_NAME)
+ {
+ if ((option = cupsGetOption("media", num_options, options)) == NULL)
+ if ((option = cupsGetOption("PageSize", num_options, options)) == NULL)
+ if ((option = cupsGetOption("PageRegion", num_options,
+ options)) == NULL)
+ option = "Default";
+
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Media Name: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, option);
+ }
+ if (banner->show & SHOW_PAPER_SIZE)
+ {
+ snprintf(text, sizeof(text),
+ _cupsLangString(language, _("%.2f x %.2f inches")),
+ PageWidth / 72.0, PageLength / 72.0);
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Media Dimensions: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+
+ snprintf(text, sizeof(text),
+ _cupsLangString(language, _("%.0f x %.0f millimeters")),
+ PageWidth * 25.4 / 72.0, PageLength * 25.4 / 72.0);
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+ }
+ if (banner->show & SHOW_IMAGEABLE_AREA)
+ {
+ snprintf(text, sizeof(text),
+ _cupsLangString(language,
+ _("%.2f x %.2f to %.2f x %.2f inches")),
+ PageLeft / 72.0, PageBottom / 72.0,
+ PageRight / 72.0, PageTop / 72.0);
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Media Limits: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+
+ snprintf(text, sizeof(text),
+ _cupsLangString(language,
+ _("%.0f x %.0f to %.0f x %.0f millimeters")),
+ PageLeft * 25.4 / 72.0, PageBottom * 25.4 / 72.0,
+ PageRight * 25.4 / 72.0, PageTop * 25.4 / 72.0);
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+
+ printf("gsave 2 setlinewidth 1 1 %.1f %.1f rectstroke grestore\n",
+ print_width - 2.0, print_height - 2.0);
+ }
+ if (banner->show & SHOW_PRINTER_DRIVER_NAME)
+ {
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Driver Name: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+ ppd ? ppd->pcfilename : NULL);
+ }
+ if (banner->show & SHOW_PRINTER_DRIVER_VERSION)
+ {
+ ppd_attr_t *file_version = ppdFindAttr(ppd, "FileVersion", NULL);
+
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Driver Version: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT,
+ file_version ? file_version->value : NULL);
+ }
+ if (banner->show & SHOW_TIME_AT_CREATION)
+ {
+ if ((option = cupsGetOption("time-at-creation", num_options,
+ options)) != NULL)
+ {
+ time_t curtime; /* Current time */
+ struct tm *curdate; /* Current date */
+
+ curtime = (time_t)atoi(option);
+ curdate = localtime(&curtime);
+
+ strftime(text, sizeof(text), "%c", curdate);
+ }
+ else
+ strlcpy(text, "?", sizeof(text));
+
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Created On: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+ }
+ if (banner->show & SHOW_TIME_AT_PROCESSING)
+ {
+ if ((option = cupsGetOption("time-at-processing", num_options,
+ options)) != NULL)
+ {
+ time_t curtime; /* Current time */
+ struct tm *curdate; /* Current date */
+
+ curtime = (time_t)atoi(option);
+ curdate = localtime(&curtime);
+
+ strftime(text, sizeof(text), "%c", curdate);
+ }
+ else
+ strlcpy(text, "?", sizeof(text));
+
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_BOLD, PS_RIGHT,
+ _cupsLangString(language, _("Printed On: ")));
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_LEFT, text);
+ }
+ }
+
+ /*
+ * Notices...
+ */
+
+ if (cupsArrayCount(banner->notices))
+ {
+ if (banner->show)
+ y -= 2 * line_height;
+
+ x = 0.5 * print_width;
+
+ for (notice = (char *)cupsArrayFirst(banner->notices);
+ notice;
+ notice = (char *)cupsArrayNext(banner->notices))
+ {
+ printf("%.1f %.1f moveto", x, y);
+ y -= line_height;
+ psTextUTF8(fonts, fontsize, PS_NORMAL, PS_CENTER, notice);
+ }
+ }
+
+ /*
+ * Images...
+ */
+
+ if (cupsArrayCount(images))
+ {
+ if (banner->show || cupsArrayCount(banner->notices))
+ y -= 2 * line_height;
+
+ x = 0.5 * (print_width - images_width);
+
+ for (image = (cups_image_t *)cupsArrayFirst(images);
+ image;
+ image = (cups_image_t *)cupsArrayNext(images))
+ {
+ float temp_width; /* Width of this image */
+ int depth, /* Bytes per pixel */
+ num_cols, /* Number of columns */
+ row, /* Current row */
+ num_rows, /* Number of rows */
+ out_length, /* Length of data to write */
+ out_offset; /* Offset in line buffer */
+ unsigned char *line; /* Data for current row */
+
+
+ depth = cupsImageGetDepth(image);
+ num_cols = cupsImageGetWidth(image);
+ num_rows = cupsImageGetHeight(image);
+ line = malloc(depth * num_cols + 3);
+ temp_width = num_cols * images_height / num_rows;
+
+ printf("gsave %.1f %.1f translate %.3f %.3f scale\n", x, y,
+ temp_width / num_cols, images_height / num_rows);
+ x += temp_width;
+
+ switch (cupsImageGetColorSpace(image))
+ {
+ default :
+ case CUPS_IMAGE_WHITE :
+ printf("/DeviceGray setcolorspace"
+ "<<"
+ "/ImageType 1"
+ "/Width %d"
+ "/Height %d"
+ "/BitsPerComponent 8"
+ "/Decode[0 1]\n",
+ num_cols, num_rows);
+ break;
+
+ case CUPS_IMAGE_RGB :
+ printf("/DeviceRGB setcolorspace"
+ "<<"
+ "/ImageType 1"
+ "/Width %d"
+ "/Height %d"
+ "/BitsPerComponent 8"
+ "/Decode[0 1 0 1 0 1]\n",
+ num_cols, num_rows);
+ break;
+
+ case CUPS_IMAGE_CMYK :
+ printf("/DeviceCMYK setcolorspace"
+ "<<"
+ "/ImageType 1"
+ "/Width %d"
+ "/Height %d"
+ "/BitsPerComponent 8"
+ "/Decode[0 1 0 1 0 1 0 1]\n",
+ num_cols, num_rows);
+ break;
+ }
+
+ puts("/DataSource currentfile"
+ "/ASCII85Decode filter"
+ "/ImageMatrix[1 0 0 -1 0 1]>>image");
+
+ for (row = 0, out_offset = 0; row < num_rows; row ++)
+ {
+ cupsImageGetRow(image, 0, row, num_cols, line + out_offset);
+
+ out_length = num_cols * depth + out_offset;
+ out_offset = out_length & 3;
+
+ ps_ascii85(line, out_length, row == (num_rows - 1));
+
+ if (out_offset > 0)
+ memcpy(line, line + out_length - out_offset, out_offset);
+ }
+
+ puts("grestore");
+
+ if (i == num_pages)
+ cupsImageClose(image);
+
+ free(line);
+ }
+ }
+
+ /*
+ * Header and footer...
+ */
+
+ x = 0.5 * print_width;
+
+ if (banner->header)
+ {
+ printf("%.1f %.1f moveto", x, print_height - 2 * fontsize);
+ psTextUTF8(fonts, 2 * fontsize, PS_BOLD, PS_CENTER, banner->header);
+ }
+
+ if (banner->footer)
+ {
+ printf("%.1f %.1f moveto", x, fontsize);
+ psTextUTF8(fonts, 2 * fontsize, PS_BOLD, PS_CENTER, banner->footer);
+ }
+
+ /*
+ * Show the page...
+ */
+
+ puts("grestore");
+ puts("showpage");
+ }
+
+ return (num_pages);
+}
+
+
+/*
+ * 'write_epilogue()' - Write the PostScript file epilogue.
+ */
+
+static void
+write_epilogue(int num_pages) /* I - Number of pages */
+{
+ puts("%%Trailer");
+ printf("%%%%Pages: %d\n", num_pages);
+ puts("%%EOF");
+}
+
+
+/*
+ * 'write_prolog()' - Write the PostScript file prolog with options.
+ */
+
+ps_text_t * /* O - Fonts */
+write_prolog(const char *title, /* I - Title of job */
+ const char *username) /* I - Username */
+{
+ time_t curtime; /* Current time */
+ struct tm *curtm; /* Current date */
+ char curdate[255]; /* Current date (text format) */
+ ps_text_t *fonts; /* Fonts */
+
+
+ /*
+ * Get the fonts we'll need...
+ */
+
+ fonts = psTextInitialize();
+
+ /*
+ * Output the DSC header...
+ */
+
+ curtime = time(NULL);
+ curtm = localtime(&curtime);
+ strftime(curdate, sizeof(curdate), "%c", curtm);
+
+ puts("%!PS-Adobe-3.0");
+ printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom,
+ PageRight, PageTop);
+ printf("%%cupsRotation: %d\n", (Orientation & 3) * 90);
+ puts("%%Creator: bannertops/" CUPS_SVERSION);
+ printf("%%%%CreationDate: %s\n", curdate);
+ puts("%%LanguageLevel: 2");
+ puts("%%DocumentData: Clean7Bit");
+ WriteTextComment("Title", title);
+ WriteTextComment("For", username);
+ printf("%%%%Pages: %d\n", Duplex ? 2 : 1);
+ psTextListFonts(fonts);
+ puts("%%EndComments");
+ puts("%%BeginProlog");
+ psTextEmbedFonts(fonts);
+ puts("%%EndProlog");
+
+ return (fonts);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/commandtops.c b/filter/commandtops.c
new file mode 100644
index 000000000..467d3d092
--- /dev/null
+++ b/filter/commandtops.c
@@ -0,0 +1,371 @@
+/*
+ * "$Id$"
+ *
+ * PostScript command filter for CUPS.
+ *
+ * Copyright 2008-2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ *
+ * Contents:
+ *
+ * main() - Process a CUPS command file.
+ * auto_configure() - Automatically configure the printer using
+ * PostScript query commands and/or SNMP lookups.
+ * begin_ps() - Send the standard PostScript prolog.
+ * end_ps() - Send the standard PostScript trailer.
+ * print_self_test_page() - Print a self-test page.
+ * report_levels() - Report supply levels.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include <cups/ppd.h>
+#include <cups/sidechannel.h>
+
+
+/*
+ * Local functions...
+ */
+
+static void auto_configure(ppd_file_t *ppd, const char *user);
+static void begin_ps(ppd_file_t *ppd, const char *user);
+static void end_ps(ppd_file_t *ppd);
+static void print_self_test_page(ppd_file_t *ppd, const char *user);
+static void report_levels(ppd_file_t *ppd, const char *user);
+
+
+/*
+ * 'main()' - Process a CUPS command file.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ cups_file_t *fp; /* Command file */
+ char line[1024], /* Line from file */
+ *value; /* Value on line */
+ int linenum; /* Line number in file */
+ ppd_file_t *ppd; /* PPD file */
+
+
+ /*
+ * Check for valid arguments...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ /*
+ * We don't have the correct number of arguments; write an error message
+ * and return.
+ */
+
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options file"),
+ argv[0]);
+ return (1);
+ }
+
+ /*
+ * Open the PPD file...
+ */
+
+ if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL)
+ {
+ fputs("ERROR: Unable to open PPD file!\n", stderr);
+ return (1);
+ }
+
+ /*
+ * Open the command file as needed...
+ */
+
+ if (argc == 7)
+ {
+ if ((fp = cupsFileOpen(argv[6], "r")) == NULL)
+ {
+ perror("ERROR: Unable to open command file - ");
+ return (1);
+ }
+ }
+ else
+ fp = cupsFileStdin();
+
+ /*
+ * Read the commands from the file and send the appropriate commands...
+ */
+
+ linenum = 0;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ /*
+ * Parse the command...
+ */
+
+ if (!_cups_strcasecmp(line, "AutoConfigure"))
+ auto_configure(ppd, argv[2]);
+ else if (!_cups_strcasecmp(line, "PrintSelfTestPage"))
+ print_self_test_page(ppd, argv[2]);
+ else if (!_cups_strcasecmp(line, "ReportLevels"))
+ report_levels(ppd, argv[2]);
+ else
+ fprintf(stderr, "ERROR: Invalid printer command \"%s\"!\n", line);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'auto_configure()' - Automatically configure the printer using PostScript
+ * query commands and/or SNMP lookups.
+ */
+
+static void
+auto_configure(ppd_file_t *ppd, /* I - PPD file */
+ const char *user) /* I - Printing user */
+{
+ ppd_option_t *option; /* Current option in PPD */
+ ppd_attr_t *attr; /* Query command attribute */
+ char buffer[1024], /* String buffer */
+ *bufptr; /* Pointer into buffer */
+ ssize_t bytes; /* Number of bytes read */
+ int datalen; /* Side-channel data length */
+
+
+ /*
+ * See if the backend supports bidirectional I/O...
+ */
+
+ datalen = 1;
+ if (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_BIDI, buffer, &datalen,
+ 30.0) != CUPS_SC_STATUS_OK ||
+ buffer[0] != CUPS_SC_BIDI_SUPPORTED)
+ {
+ fputs("DEBUG: Unable to auto-configure PostScript Printer - no "
+ "bidirectional I/O available!\n", stderr);
+ return;
+ }
+
+ /*
+ * Put the printer in PostScript mode...
+ */
+
+ begin_ps(ppd, user);
+ fflush(stdout);
+
+ /*
+ * Wait for the printer to become connected...
+ */
+
+ do
+ {
+ sleep(1);
+ datalen = 1;
+ }
+ while (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_CONNECTED, buffer, &datalen,
+ 5.0) == CUPS_SC_STATUS_OK && !buffer[0]);
+
+ /*
+ * Then loop through every option in the PPD file and ask for the current
+ * value...
+ */
+
+ fputs("DEBUG: Auto-configuring PostScript printer...\n", stderr);
+
+ for (option = ppdFirstOption(ppd); option; option = ppdNextOption(ppd))
+ {
+ /*
+ * See if we have a query command for this option...
+ */
+
+ snprintf(buffer, sizeof(buffer), "?%s", option->keyword);
+
+ if ((attr = ppdFindAttr(ppd, buffer, NULL)) == NULL || !attr->value)
+ {
+ fprintf(stderr, "DEBUG: Skipping %s option...\n", option->keyword);
+ continue;
+ }
+
+ /*
+ * Send the query code to the printer...
+ */
+
+ fprintf(stderr, "DEBUG: Querying %s...\n", option->keyword);
+ fputs(attr->value, stdout);
+ fflush(stdout);
+
+ datalen = 0;
+ cupsSideChannelDoRequest(CUPS_SC_CMD_DRAIN_OUTPUT, buffer, &datalen, 5.0);
+
+ /*
+ * Read the response data...
+ */
+
+ while ((bytes = cupsBackChannelRead(buffer, sizeof(buffer) - 1, 90.0)) > 0)
+ {
+ /*
+ * Trim whitespace from both ends...
+ */
+
+ buffer[bytes] = '\0';
+
+ for (bufptr = buffer + bytes - 1; bufptr >= buffer; bufptr --)
+ if (isspace(*bufptr & 255))
+ *bufptr = '\0';
+ else
+ break;
+
+ for (bufptr = buffer; isspace(*bufptr & 255); bufptr ++);
+
+ fprintf(stderr, "DEBUG: Got \"%s\" (%d bytes)\n", bufptr, (int)bytes);
+
+ /*
+ * Skip blank lines...
+ */
+
+ if (!*bufptr)
+ continue;
+
+ /*
+ * Verify the result is a valid option choice...
+ */
+
+ if (!ppdFindChoice(option, bufptr))
+ continue;
+
+ /*
+ * Write out the result and move on to the next option...
+ */
+
+ fprintf(stderr, "DEBUG: Default%s=%s\n", option->keyword, bufptr);
+ fprintf(stderr, "PPD: Default%s=%s\n", option->keyword, bufptr);
+ break;
+ }
+ }
+
+ /*
+ * Finish the job...
+ */
+
+ end_ps(ppd);
+}
+
+
+/*
+ * 'begin_ps()' - Send the standard PostScript prolog.
+ */
+
+static void
+begin_ps(ppd_file_t *ppd, /* I - PPD file */
+ const char *user) /* I - Username */
+{
+ (void)user;
+
+ if (ppd->jcl_begin)
+ {
+ fputs(ppd->jcl_begin, stdout);
+ fputs(ppd->jcl_ps, stdout);
+ }
+
+ puts("%!");
+ puts("userdict dup(\\004)cvn{}put (\\004\\004)cvn{}put\n");
+ fflush(stdout);
+}
+
+
+/*
+ * 'end_ps()' - Send the standard PostScript trailer.
+ */
+
+static void
+end_ps(ppd_file_t *ppd) /* I - PPD file */
+{
+ if (ppd->jcl_end)
+ fputs(ppd->jcl_end, stdout);
+ else
+ putchar(0x04);
+
+ fflush(stdout);
+}
+
+
+/*
+ * 'print_self_test_page()' - Print a self-test page.
+ */
+
+static void
+print_self_test_page(ppd_file_t *ppd, /* I - PPD file */
+ const char *user) /* I - Printing user */
+{
+ /*
+ * Put the printer in PostScript mode...
+ */
+
+ begin_ps(ppd, user);
+
+ /*
+ * Send a simple file the draws a box around the imageable area and shows
+ * the product/interpreter information...
+ */
+
+ puts("% You are using the wrong driver for your printer!\n"
+ "0 setgray\n"
+ "2 setlinewidth\n"
+ "initclip newpath clippath gsave stroke grestore pathbbox\n"
+ "exch pop exch pop exch 9 add exch 9 sub moveto\n"
+ "/Courier findfont 12 scalefont setfont\n"
+ "0 -12 rmoveto gsave product show grestore\n"
+ "0 -12 rmoveto gsave version show ( ) show revision 20 string cvs show "
+ "grestore\n"
+ "0 -12 rmoveto gsave serialnumber 20 string cvs show grestore\n"
+ "showpage");
+
+ /*
+ * Finish the job...
+ */
+
+ end_ps(ppd);
+}
+
+
+/*
+ * 'report_levels()' - Report supply levels.
+ */
+
+static void
+report_levels(ppd_file_t *ppd, /* I - PPD file */
+ const char *user) /* I - Printing user */
+{
+ /*
+ * Put the printer in PostScript mode...
+ */
+
+ begin_ps(ppd, user);
+
+ /*
+ * Don't bother sending any additional PostScript commands, since we just
+ * want the backend to have enough time to collect the supply info.
+ */
+
+ /*
+ * Finish the job...
+ */
+
+ end_ps(ppd);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/common.c b/filter/common.c
new file mode 100644
index 000000000..b80f4d5b5
--- /dev/null
+++ b/filter/common.c
@@ -0,0 +1,535 @@
+/*
+ * "$Id$"
+ *
+ * Common filter routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * SetCommonOptions() - Set common filter options for media size,
+ * etc.
+ * UpdatePageVars() - Update the page variables for the orientation.
+ * WriteComment() - Write a DSC comment.
+ * WriteCommon() - Write common procedures...
+ * WriteLabelProlog() - Write the prolog with the classification
+ * and page label.
+ * WriteLabels() - Write the actual page labels.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "common.h"
+#include <locale.h>
+
+
+/*
+ * Globals...
+ */
+
+int Orientation = 0, /* 0 = portrait, 1 = landscape, etc. */
+ Duplex = 0, /* Duplexed? */
+ LanguageLevel = 1, /* Language level of printer */
+ ColorDevice = 1; /* Do color text? */
+float PageLeft = 18.0f, /* Left margin */
+ PageRight = 594.0f, /* Right margin */
+ PageBottom = 36.0f, /* Bottom margin */
+ PageTop = 756.0f, /* Top margin */
+ PageWidth = 612.0f, /* Total page width */
+ PageLength = 792.0f; /* Total page length */
+
+
+/*
+ * 'SetCommonOptions()' - Set common filter options for media size, etc.
+ */
+
+ppd_file_t * /* O - PPD file */
+SetCommonOptions(
+ int num_options, /* I - Number of options */
+ cups_option_t *options, /* I - Options */
+ int change_size) /* I - Change page size? */
+{
+ ppd_file_t *ppd; /* PPD file */
+ ppd_size_t *pagesize; /* Current page size */
+ const char *val; /* Option value */
+
+
+#ifdef LC_TIME
+ setlocale(LC_TIME, "");
+#endif /* LC_TIME */
+
+ ppd = ppdOpenFile(getenv("PPD"));
+
+ ppdMarkDefaults(ppd);
+ cupsMarkOptions(ppd, num_options, options);
+
+ if ((pagesize = ppdPageSize(ppd, NULL)) != NULL)
+ {
+ PageWidth = pagesize->width;
+ PageLength = pagesize->length;
+ PageTop = pagesize->top;
+ PageBottom = pagesize->bottom;
+ PageLeft = pagesize->left;
+ PageRight = pagesize->right;
+
+ fprintf(stderr, "DEBUG: Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f\n",
+ PageWidth, PageLength, PageLeft, PageBottom, PageRight, PageTop);
+ }
+
+ if (ppd != NULL)
+ {
+ ColorDevice = ppd->color_device;
+ LanguageLevel = ppd->language_level;
+ }
+
+ if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
+ {
+ if (_cups_strcasecmp(val, "no") != 0 && _cups_strcasecmp(val, "off") != 0 &&
+ _cups_strcasecmp(val, "false") != 0)
+ {
+ if (ppd && ppd->landscape > 0)
+ Orientation = 1;
+ else
+ Orientation = 3;
+ }
+ }
+ else if ((val = cupsGetOption("orientation-requested", num_options, options)) != NULL)
+ {
+ /*
+ * Map IPP orientation values to 0 to 3:
+ *
+ * 3 = 0 degrees = 0
+ * 4 = 90 degrees = 1
+ * 5 = -90 degrees = 3
+ * 6 = 180 degrees = 2
+ */
+
+ Orientation = atoi(val) - 3;
+ if (Orientation >= 2)
+ Orientation ^= 1;
+ }
+
+ if ((val = cupsGetOption("page-left", num_options, options)) != NULL)
+ {
+ switch (Orientation & 3)
+ {
+ case 0 :
+ PageLeft = (float)atof(val);
+ break;
+ case 1 :
+ PageBottom = (float)atof(val);
+ break;
+ case 2 :
+ PageRight = PageWidth - (float)atof(val);
+ break;
+ case 3 :
+ PageTop = PageLength - (float)atof(val);
+ break;
+ }
+ }
+
+ if ((val = cupsGetOption("page-right", num_options, options)) != NULL)
+ {
+ switch (Orientation & 3)
+ {
+ case 0 :
+ PageRight = PageWidth - (float)atof(val);
+ break;
+ case 1 :
+ PageTop = PageLength - (float)atof(val);
+ break;
+ case 2 :
+ PageLeft = (float)atof(val);
+ break;
+ case 3 :
+ PageBottom = (float)atof(val);
+ break;
+ }
+ }
+
+ if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL)
+ {
+ switch (Orientation & 3)
+ {
+ case 0 :
+ PageBottom = (float)atof(val);
+ break;
+ case 1 :
+ PageLeft = (float)atof(val);
+ break;
+ case 2 :
+ PageTop = PageLength - (float)atof(val);
+ break;
+ case 3 :
+ PageRight = PageWidth - (float)atof(val);
+ break;
+ }
+ }
+
+ if ((val = cupsGetOption("page-top", num_options, options)) != NULL)
+ {
+ switch (Orientation & 3)
+ {
+ case 0 :
+ PageTop = PageLength - (float)atof(val);
+ break;
+ case 1 :
+ PageRight = PageWidth - (float)atof(val);
+ break;
+ case 2 :
+ PageBottom = (float)atof(val);
+ break;
+ case 3 :
+ PageLeft = (float)atof(val);
+ break;
+ }
+ }
+
+ if (change_size)
+ UpdatePageVars();
+
+ if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") ||
+ ppdIsMarked(ppd, "Duplex", "DuplexTumble") ||
+ ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") ||
+ ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") ||
+ ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") ||
+ ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") ||
+ ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") ||
+ ppdIsMarked(ppd, "KD03Duplex", "DuplexTumble"))
+ Duplex = 1;
+
+ return (ppd);
+}
+
+
+/*
+ * 'UpdatePageVars()' - Update the page variables for the orientation.
+ */
+
+void
+UpdatePageVars(void)
+{
+ float temp; /* Swapping variable */
+
+
+ switch (Orientation & 3)
+ {
+ case 0 : /* Portait */
+ break;
+
+ case 1 : /* Landscape */
+ temp = PageLeft;
+ PageLeft = PageBottom;
+ PageBottom = temp;
+
+ temp = PageRight;
+ PageRight = PageTop;
+ PageTop = temp;
+
+ temp = PageWidth;
+ PageWidth = PageLength;
+ PageLength = temp;
+ break;
+
+ case 2 : /* Reverse Portrait */
+ temp = PageWidth - PageLeft;
+ PageLeft = PageWidth - PageRight;
+ PageRight = temp;
+
+ temp = PageLength - PageBottom;
+ PageBottom = PageLength - PageTop;
+ PageTop = temp;
+ break;
+
+ case 3 : /* Reverse Landscape */
+ temp = PageWidth - PageLeft;
+ PageLeft = PageWidth - PageRight;
+ PageRight = temp;
+
+ temp = PageLength - PageBottom;
+ PageBottom = PageLength - PageTop;
+ PageTop = temp;
+
+ temp = PageLeft;
+ PageLeft = PageBottom;
+ PageBottom = temp;
+
+ temp = PageRight;
+ PageRight = PageTop;
+ PageTop = temp;
+
+ temp = PageWidth;
+ PageWidth = PageLength;
+ PageLength = temp;
+ break;
+ }
+}
+
+
+/*
+ * 'WriteCommon()' - Write common procedures...
+ */
+
+void
+WriteCommon(void)
+{
+ puts("% x y w h ESPrc - Clip to a rectangle.\n"
+ "userdict/ESPrc/rectclip where{pop/rectclip load}\n"
+ "{{newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
+ "neg 0 rlineto closepath clip newpath}bind}ifelse put");
+ puts("% x y w h ESPrf - Fill a rectangle.\n"
+ "userdict/ESPrf/rectfill where{pop/rectfill load}\n"
+ "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
+ "neg 0 rlineto closepath fill grestore}bind}ifelse put");
+ puts("% x y w h ESPrs - Stroke a rectangle.\n"
+ "userdict/ESPrs/rectstroke where{pop/rectstroke load}\n"
+ "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
+ "neg 0 rlineto closepath stroke grestore}bind}ifelse put");
+}
+
+
+/*
+ * 'WriteLabelProlog()' - Write the prolog with the classification
+ * and page label.
+ */
+
+void
+WriteLabelProlog(const char *label, /* I - Page label */
+ float bottom, /* I - Bottom position in points */
+ float top, /* I - Top position in points */
+ float width) /* I - Width in points */
+{
+ const char *classification; /* CLASSIFICATION environment variable */
+ const char *ptr; /* Temporary string pointer */
+
+
+ /*
+ * First get the current classification...
+ */
+
+ if ((classification = getenv("CLASSIFICATION")) == NULL)
+ classification = "";
+ if (strcmp(classification, "none") == 0)
+ classification = "";
+
+ /*
+ * If there is nothing to show, bind an empty 'write labels' procedure
+ * and return...
+ */
+
+ if (!classification[0] && (label == NULL || !label[0]))
+ {
+ puts("userdict/ESPwl{}bind put");
+ return;
+ }
+
+ /*
+ * Set the classification + page label string...
+ */
+
+ printf("userdict");
+ if (strcmp(classification, "confidential") == 0)
+ printf("/ESPpl(CONFIDENTIAL");
+ else if (strcmp(classification, "classified") == 0)
+ printf("/ESPpl(CLASSIFIED");
+ else if (strcmp(classification, "secret") == 0)
+ printf("/ESPpl(SECRET");
+ else if (strcmp(classification, "topsecret") == 0)
+ printf("/ESPpl(TOP SECRET");
+ else if (strcmp(classification, "unclassified") == 0)
+ printf("/ESPpl(UNCLASSIFIED");
+ else
+ {
+ printf("/ESPpl(");
+
+ for (ptr = classification; *ptr; ptr ++)
+ if (*ptr < 32 || *ptr > 126)
+ printf("\\%03o", *ptr);
+ else if (*ptr == '_')
+ putchar(' ');
+ else
+ {
+ if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
+ putchar('\\');
+
+ putchar(*ptr);
+ }
+ }
+
+ if (label)
+ {
+ if (classification[0])
+ printf(" - ");
+
+ /*
+ * Quote the label string as needed...
+ */
+
+ for (ptr = label; *ptr; ptr ++)
+ if (*ptr < 32 || *ptr > 126)
+ printf("\\%03o", *ptr);
+ else
+ {
+ if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
+ putchar('\\');
+
+ putchar(*ptr);
+ }
+ }
+
+ puts(")put");
+
+ /*
+ * Then get a 14 point Helvetica-Bold font...
+ */
+
+ puts("userdict/ESPpf /Helvetica-Bold findfont 14 scalefont put");
+
+ /*
+ * Finally, the procedure to write the labels on the page...
+ */
+
+ puts("userdict/ESPwl{");
+ puts(" ESPpf setfont");
+ printf(" ESPpl stringwidth pop dup 12 add exch -0.5 mul %.0f add\n",
+ width * 0.5f);
+ puts(" 1 setgray");
+ printf(" dup 6 sub %.0f 3 index 20 ESPrf\n", bottom - 2.0);
+ printf(" dup 6 sub %.0f 3 index 20 ESPrf\n", top - 18.0);
+ puts(" 0 setgray");
+ printf(" dup 6 sub %.0f 3 index 20 ESPrs\n", bottom - 2.0);
+ printf(" dup 6 sub %.0f 3 index 20 ESPrs\n", top - 18.0);
+ printf(" dup %.0f moveto ESPpl show\n", bottom + 2.0);
+ printf(" %.0f moveto ESPpl show\n", top - 14.0);
+ puts("pop");
+ puts("}bind put");
+}
+
+
+/*
+ * 'WriteLabels()' - Write the actual page labels.
+ */
+
+void
+WriteLabels(int orient) /* I - Orientation of the page */
+{
+ float width, /* Width of page */
+ length; /* Length of page */
+
+
+ puts("gsave");
+
+ if ((orient ^ Orientation) & 1)
+ {
+ width = PageLength;
+ length = PageWidth;
+ }
+ else
+ {
+ width = PageWidth;
+ length = PageLength;
+ }
+
+ switch (orient & 3)
+ {
+ case 1 : /* Landscape */
+ printf("%.1f 0.0 translate 90 rotate\n", length);
+ break;
+ case 2 : /* Reverse Portrait */
+ printf("%.1f %.1f translate 180 rotate\n", width, length);
+ break;
+ case 3 : /* Reverse Landscape */
+ printf("0.0 %.1f translate -90 rotate\n", width);
+ break;
+ }
+
+ puts("ESPwl");
+ puts("grestore");
+}
+
+
+/*
+ * 'WriteTextComment()' - Write a DSC text comment.
+ */
+
+void
+WriteTextComment(const char *name, /* I - Comment name ("Title", etc.) */
+ const char *value) /* I - Comment value */
+{
+ int len; /* Current line length */
+
+
+ /*
+ * DSC comments are of the form:
+ *
+ * %%name: value
+ *
+ * The name and value must be limited to 7-bit ASCII for most printers,
+ * so we escape all non-ASCII and ASCII control characters as described
+ * in the Adobe Document Structuring Conventions specification.
+ */
+
+ printf("%%%%%s: (", name);
+ len = 5 + strlen(name);
+
+ while (*value)
+ {
+ if (*value < ' ' || *value >= 127)
+ {
+ /*
+ * Escape this character value...
+ */
+
+ if (len >= 251) /* Keep line < 254 chars */
+ break;
+
+ printf("\\%03o", *value & 255);
+ len += 4;
+ }
+ else if (*value == '\\')
+ {
+ /*
+ * Escape the backslash...
+ */
+
+ if (len >= 253) /* Keep line < 254 chars */
+ break;
+
+ putchar('\\');
+ putchar('\\');
+ len += 2;
+ }
+ else
+ {
+ /*
+ * Put this character literally...
+ */
+
+ if (len >= 254) /* Keep line < 254 chars */
+ break;
+
+ putchar(*value);
+ len ++;
+ }
+
+ value ++;
+ }
+
+ puts(")");
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/common.h b/filter/common.h
new file mode 100644
index 000000000..bbaf99eed
--- /dev/null
+++ b/filter/common.h
@@ -0,0 +1,78 @@
+/*
+ * "$Id$"
+ *
+ * Common filter definitions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/string-private.h>
+#include <cups/cups.h>
+#include <cups/ppd.h>
+#include <time.h>
+
+
+/*
+ * C++ magic...
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/*
+ * Globals...
+ */
+
+extern int Orientation, /* 0 = portrait, 1 = landscape, etc. */
+ Duplex, /* Duplexed? */
+ LanguageLevel, /* Language level of printer */
+ ColorDevice; /* Do color text? */
+extern float PageLeft, /* Left margin */
+ PageRight, /* Right margin */
+ PageBottom, /* Bottom margin */
+ PageTop, /* Top margin */
+ PageWidth, /* Total page width */
+ PageLength; /* Total page length */
+
+
+/*
+ * Prototypes...
+ */
+
+extern ppd_file_t *SetCommonOptions(int num_options, cups_option_t *options,
+ int change_size);
+extern void UpdatePageVars(void);
+extern void WriteCommon(void);
+extern void WriteLabelProlog(const char *label, float bottom,
+ float top, float width);
+extern void WriteLabels(int orient);
+extern void WriteTextComment(const char *name, const char *value);
+
+
+/*
+ * C++ magic...
+ */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/error.c b/filter/error.c
new file mode 100644
index 000000000..76adc2da6
--- /dev/null
+++ b/filter/error.c
@@ -0,0 +1,287 @@
+/*
+ * "$Id$"
+ *
+ * Raster error handling for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsRasterAddError() - Add an error message to the error buffer.
+ * _cupsRasterClearError() - Clear the error buffer.
+ * cupsRasterErrorString() - Return the last error from a raster function.
+ * get_error_buffer() - Return a pointer to thread local storage.
+ * raster_init() - Initialize error buffer once.
+ * raster_destructor() - Free memory allocated by get_error_buffer().
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+#include <stdarg.h>
+
+
+/*
+ * Local structures...
+ */
+
+typedef struct _cups_raster_error_s /**** Error buffer structure ****/
+{
+ char *start, /* Start of buffer */
+ *current, /* Current position in buffer */
+ *end; /* End of buffer */
+} _cups_raster_error_t;
+
+
+/*
+ * Local functions...
+ */
+
+static _cups_raster_error_t *get_error_buffer(void);
+
+
+/*
+ * '_cupsRasterAddError()' - Add an error message to the error buffer.
+ */
+
+void
+_cupsRasterAddError(const char *f, /* I - Printf-style error message */
+ ...) /* I - Additional arguments as needed */
+{
+ _cups_raster_error_t *buf = get_error_buffer();
+ /* Error buffer */
+ va_list ap; /* Pointer to additional arguments */
+ char s[2048]; /* Message string */
+ size_t bytes; /* Bytes in message string */
+
+
+ va_start(ap, f);
+ bytes = vsnprintf(s, sizeof(s), f, ap);
+ va_end(ap);
+
+ if (bytes <= 0)
+ return;
+
+ bytes ++;
+
+ if (bytes >= sizeof(s))
+ return;
+
+ if (bytes > (size_t)(buf->end - buf->current))
+ {
+ /*
+ * Allocate more memory...
+ */
+
+ char *temp; /* New buffer */
+ size_t size; /* Size of buffer */
+
+
+ size = buf->end - buf->start + 2 * bytes + 1024;
+
+ if (buf->start)
+ temp = realloc(buf->start, size);
+ else
+ temp = malloc(size);
+
+ if (!temp)
+ return;
+
+ /*
+ * Update pointers...
+ */
+
+ buf->end = temp + size;
+ buf->current = temp + (buf->current - buf->start);
+ buf->start = temp;
+ }
+
+ /*
+ * Append the message to the end of the current string...
+ */
+
+ memcpy(buf->current, s, bytes);
+ buf->current += bytes - 1;
+}
+
+
+/*
+ * '_cupsRasterClearError()' - Clear the error buffer.
+ */
+
+void
+_cupsRasterClearError(void)
+{
+ _cups_raster_error_t *buf = get_error_buffer();
+ /* Error buffer */
+
+
+ buf->current = buf->start;
+
+ if (buf->start)
+ *(buf->start) = '\0';
+}
+
+
+/*
+ * 'cupsRasterErrorString()' - Return the last error from a raster function.
+ *
+ * If there are no recent errors, NULL is returned.
+ *
+ * @since CUPS 1.3/Mac OS X 10.5@
+ */
+
+const char * /* O - Last error */
+cupsRasterErrorString(void)
+{
+ _cups_raster_error_t *buf = get_error_buffer();
+ /* Error buffer */
+
+
+ if (buf->current == buf->start)
+ return (NULL);
+ else
+ return (buf->start);
+}
+
+
+#ifdef HAVE_PTHREAD_H
+/*
+ * Implement per-thread globals...
+ */
+
+# include <pthread.h>
+
+
+/*
+ * Local globals...
+ */
+
+static pthread_key_t raster_key = -1;
+ /* Thread local storage key */
+static pthread_once_t raster_key_once = PTHREAD_ONCE_INIT;
+ /* One-time initialization object */
+
+
+/*
+ * Local functions...
+ */
+
+static void raster_init(void);
+static void raster_destructor(void *value);
+
+
+/*
+ * 'get_error_buffer()' - Return a pointer to thread local storage.
+ */
+
+_cups_raster_error_t * /* O - Pointer to error buffer */
+get_error_buffer(void)
+{
+ _cups_raster_error_t *buf; /* Pointer to error buffer */
+
+
+ /*
+ * Initialize the global data exactly once...
+ */
+
+ DEBUG_puts("get_error_buffer()");
+
+ pthread_once(&raster_key_once, raster_init);
+
+ /*
+ * See if we have allocated the data yet...
+ */
+
+ if ((buf = (_cups_raster_error_t *)pthread_getspecific(raster_key))
+ == NULL)
+ {
+ DEBUG_puts("get_error_buffer: allocating memory for thread...");
+
+ /*
+ * No, allocate memory as set the pointer for the key...
+ */
+
+ buf = calloc(1, sizeof(_cups_raster_error_t));
+ pthread_setspecific(raster_key, buf);
+
+ DEBUG_printf((" buf=%p\n", buf));
+ }
+
+ /*
+ * Return the pointer to the data...
+ */
+
+ return (buf);
+}
+
+
+/*
+ * 'raster_init()' - Initialize error buffer once.
+ */
+
+static void
+raster_init(void)
+{
+ pthread_key_create(&raster_key, raster_destructor);
+
+ DEBUG_printf(("raster_init(): raster_key=%x(%u)\n", (unsigned)raster_key,
+ (unsigned)raster_key));
+}
+
+
+/*
+ * 'raster_destructor()' - Free memory allocated by get_error_buffer().
+ */
+
+static void
+raster_destructor(void *value) /* I - Data to free */
+{
+ _cups_raster_error_t *buf = (_cups_raster_error_t *)value;
+ /* Error buffer */
+
+
+ DEBUG_printf(("raster_destructor(value=%p)\n", value));
+
+ if (buf->start)
+ free(buf->start);
+
+ free(value);
+}
+
+
+#else
+/*
+ * Implement static globals...
+ */
+
+/*
+ * 'get_error_buffer()' - Return a pointer to thread local storage.
+ */
+
+_cups_raster_error_t * /* O - Pointer to error buffer */
+get_error_buffer(void)
+{
+ static _cups_raster_error_t buf = { 0, 0, 0 };
+ /* Error buffer */
+
+
+ return (&buf);
+}
+#endif /* HAVE_PTHREAD_H */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/gziptoany.c b/filter/gziptoany.c
new file mode 100644
index 000000000..bde1c81a6
--- /dev/null
+++ b/filter/gziptoany.c
@@ -0,0 +1,112 @@
+/*
+ * "$Id$"
+ *
+ * GZIP/raw pre-filter for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Copy (and uncompress) files to stdout.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * 'main()' - Copy (and uncompress) files to stdout.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ cups_file_t *fp; /* File */
+ char buffer[8192]; /* Data buffer */
+ int bytes; /* Number of bytes read/written */
+ int copies; /* Number of copies */
+
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc != 7)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options file"),
+ argv[0]);
+ return (1);
+ }
+
+ /*
+ * Get the copy count; if we have no final content type, this is a
+ * raw queue or raw print file, so we need to make copies...
+ */
+
+ if (!getenv("FINAL_CONTENT_TYPE"))
+ copies = atoi(argv[4]);
+ else
+ copies = 1;
+
+ /*
+ * Open the file...
+ */
+
+ if ((fp = cupsFileOpen(argv[6], "r")) == NULL)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ return (1);
+ }
+
+ /*
+ * Copy the file to stdout...
+ */
+
+ while (copies > 0)
+ {
+ if (!getenv("FINAL_CONTENT_TYPE"))
+ fputs("PAGE: 1 1\n", stderr);
+
+ cupsFileRewind(fp);
+
+ while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0)
+ if (write(1, buffer, bytes) < bytes)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to write uncompressed print data: %s"),
+ strerror(errno));
+ cupsFileClose(fp);
+
+ return (1);
+ }
+
+ copies --;
+ }
+
+ /*
+ * Close the file and return...
+ */
+
+ cupsFileClose(fp);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-bmp.c b/filter/image-bmp.c
new file mode 100644
index 000000000..3f8b56ffc
--- /dev/null
+++ b/filter/image-bmp.c
@@ -0,0 +1,545 @@
+/*
+ * "$Id$"
+ *
+ * BMP image routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsImageReadBMP() - Read a BMP image file.
+ * read_word() - Read a 16-bit unsigned integer.
+ * read_dword() - Read a 32-bit unsigned integer.
+ * read_long() - Read a 32-bit signed integer.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+
+
+/*
+ * Constants for the bitmap compression...
+ */
+
+# define BI_RGB 0 /* No compression - straight BGR data */
+# define BI_RLE8 1 /* 8-bit run-length compression */
+# define BI_RLE4 2 /* 4-bit run-length compression */
+# define BI_BITFIELDS 3 /* RGB bitmap with RGB masks */
+
+
+/*
+ * Local functions...
+ */
+
+static unsigned short read_word(FILE *fp);
+static unsigned int read_dword(FILE *fp);
+static int read_long(FILE *fp);
+
+
+/*
+ * '_cupsImageReadBMP()' - Read a BMP image file.
+ */
+
+int /* O - Read status */
+_cupsImageReadBMP(
+ cups_image_t *img, /* IO - cupsImage */
+ FILE *fp, /* I - cupsImage file */
+ cups_icspace_t primary, /* I - Primary choice for colorspace */
+ cups_icspace_t secondary, /* I - Secondary choice for colorspace */
+ int saturation, /* I - Color saturation (%) */
+ int hue, /* I - Color hue (degrees) */
+ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */
+{
+ int offset, /* Offset to bitmap data */
+ info_size, /* Size of info header */
+ planes, /* Number of planes (always 1) */
+ depth, /* Depth of image (bits) */
+ compression, /* Type of compression */
+ image_size, /* Size of image in bytes */
+ colors_used, /* Number of colors used */
+ colors_important, /* Number of important colors */
+ bpp, /* Bytes per pixel */
+ x, y, /* Looping vars */
+ color, /* Color of RLE pixel */
+ count, /* Number of times to repeat */
+ temp, /* Temporary color */
+ align; /* Alignment bytes */
+ cups_ib_t bit, /* Bit in image */
+ byte; /* Byte in image */
+ cups_ib_t *in, /* Input pixels */
+ *out, /* Output pixels */
+ *ptr; /* Pointer into pixels */
+ cups_ib_t colormap[256][4]; /* Colormap */
+
+
+ (void)secondary;
+
+ /*
+ * Get the header...
+ */
+
+ getc(fp); /* Skip "BM" sync chars */
+ getc(fp);
+ read_dword(fp); /* Skip size */
+ read_word(fp); /* Skip reserved stuff */
+ read_word(fp);
+ offset = read_dword(fp);
+
+ fprintf(stderr, "DEBUG: offset = %d\n", offset);
+
+ if (offset < 0)
+ {
+ fprintf(stderr, "DEBUG: Bad BMP offset %d\n", offset);
+ fclose(fp);
+ return (1);
+ }
+
+ /*
+ * Then the bitmap information...
+ */
+
+ info_size = read_dword(fp);
+ img->xsize = read_long(fp);
+ img->ysize = read_long(fp);
+ planes = read_word(fp);
+ depth = read_word(fp);
+ compression = read_dword(fp);
+ image_size = read_dword(fp);
+ img->xppi = read_long(fp) * 0.0254 + 0.5;
+ img->yppi = read_long(fp) * 0.0254 + 0.5;
+ colors_used = read_dword(fp);
+ colors_important = read_dword(fp);
+
+ if (img->xsize == 0 || img->xsize > CUPS_IMAGE_MAX_WIDTH ||
+ img->ysize == 0 || img->ysize > CUPS_IMAGE_MAX_HEIGHT ||
+ (depth != 1 && depth != 4 && depth != 8 && depth != 24))
+ {
+ fprintf(stderr, "DEBUG: Bad BMP dimensions %ux%ux%d\n",
+ img->xsize, img->ysize, depth);
+ fclose(fp);
+ return (1);
+ }
+
+ if (colors_used < 0 || colors_used > 256)
+ {
+ fprintf(stderr, "DEBUG: Bad BMP colormap size %d\n", colors_used);
+ fclose(fp);
+ return (1);
+ }
+
+ if (img->xppi == 0 || img->yppi == 0)
+ {
+ fprintf(stderr, "DEBUG: Bad BMP resolution %dx%d PPI.\n",
+ img->xppi, img->yppi);
+ img->xppi = img->yppi = 128;
+ }
+
+ /*
+ * Make sure the resolution info is valid...
+ */
+
+ fprintf(stderr, "info_size = %d, xsize = %d, ysize = %d, planes = %d, depth = %d\n",
+ info_size, img->xsize, img->ysize, planes, depth);
+ fprintf(stderr, "compression = %d, image_size = %d, xppi = %d, yppi = %d\n",
+ compression, image_size, img->xppi, img->yppi);
+ fprintf(stderr, "colors_used = %d, colors_important = %d\n", colors_used,
+ colors_important);
+
+ if (info_size > 40)
+ for (info_size -= 40; info_size > 0; info_size --)
+ getc(fp);
+
+ /*
+ * Get colormap...
+ */
+
+ if (colors_used == 0 && depth <= 8)
+ colors_used = 1 << depth;
+
+ if (colors_used > 0)
+ fread(colormap, colors_used, 4, fp);
+ else
+ memset(colormap, 0, sizeof(colormap));
+
+ /*
+ * Setup image and buffers...
+ */
+
+ img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary;
+
+ cupsImageSetMaxTiles(img, 0);
+
+ bpp = cupsImageGetDepth(img);
+
+ if ((in = malloc(img->xsize * 3)) == NULL)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ fclose(fp);
+ return (1);
+ }
+
+ if ((out = malloc(img->xsize * bpp)) == NULL)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ free(in);
+ fclose(fp);
+ return (1);
+ }
+
+ /*
+ * Read the image data...
+ */
+
+ color = 0;
+ count = 0;
+ align = 0;
+
+ for (y = img->ysize - 1; y >= 0; y --)
+ {
+ ptr = in;
+
+ switch (depth)
+ {
+ case 1 : /* Bitmap */
+ for (x = img->xsize, bit = 128, byte = 0; x > 0; x --)
+ {
+ if (bit == 128)
+ byte = getc(fp);
+
+ if (byte & bit)
+ {
+ *ptr++ = colormap[1][2];
+ *ptr++ = colormap[1][1];
+ *ptr++ = colormap[1][0];
+ }
+ else
+ {
+ *ptr++ = colormap[0][2];
+ *ptr++ = colormap[0][1];
+ *ptr++ = colormap[0][0];
+ }
+
+ if (bit > 1)
+ bit >>= 1;
+ else
+ bit = 128;
+ }
+
+ /*
+ * Read remaining bytes to align to 32 bits...
+ */
+
+ for (temp = (img->xsize + 7) / 8; temp & 3; temp ++)
+ getc(fp);
+ break;
+
+ case 4 : /* 16-color */
+ for (x = img->xsize, bit = 0xf0, temp = 0; x > 0; x --)
+ {
+ /*
+ * Get a new count as needed...
+ */
+
+ if (compression != BI_RLE4 && count == 0)
+ {
+ count = 2;
+ color = -1;
+ }
+
+ if (count == 0)
+ {
+ while (align > 0)
+ {
+ align --;
+ getc(fp);
+ }
+
+ if ((count = getc(fp)) == 0)
+ {
+ if ((count = getc(fp)) == 0)
+ {
+ /*
+ * End of line...
+ */
+
+ x ++;
+ continue;
+ }
+ else if (count == 1)
+ {
+ /*
+ * End of image...
+ */
+
+ break;
+ }
+ else if (count == 2)
+ {
+ /*
+ * Delta...
+ */
+
+ count = getc(fp) * getc(fp) * img->xsize;
+ color = 0;
+ }
+ else
+ {
+ /*
+ * Absolute...
+ */
+
+ color = -1;
+ align = ((4 - (count & 3)) / 2) & 1;
+ }
+ }
+ else
+ color = getc(fp);
+ }
+
+ /*
+ * Get a new color as needed...
+ */
+
+ count --;
+
+ if (bit == 0xf0)
+ {
+ if (color < 0)
+ temp = getc(fp);
+ else
+ temp = color;
+
+ /*
+ * Copy the color value...
+ */
+
+ *ptr++ = colormap[temp >> 4][2];
+ *ptr++ = colormap[temp >> 4][1];
+ *ptr++ = colormap[temp >> 4][0];
+ bit = 0x0f;
+ }
+ else
+ {
+ /*
+ * Copy the color value...
+ */
+
+ *ptr++ = colormap[temp & 15][2];
+ *ptr++ = colormap[temp & 15][1];
+ *ptr++ = colormap[temp & 15][0];
+ bit = 0xf0;
+ }
+ }
+ break;
+
+ case 8 : /* 256-color */
+ for (x = img->xsize; x > 0; x --)
+ {
+ /*
+ * Get a new count as needed...
+ */
+
+ if (compression != BI_RLE8)
+ {
+ count = 1;
+ color = -1;
+ }
+
+ if (count == 0)
+ {
+ while (align > 0)
+ {
+ align --;
+ getc(fp);
+ }
+
+ if ((count = getc(fp)) == 0)
+ {
+ if ((count = getc(fp)) == 0)
+ {
+ /*
+ * End of line...
+ */
+
+ x ++;
+ continue;
+ }
+ else if (count == 1)
+ {
+ /*
+ * End of image...
+ */
+
+ break;
+ }
+ else if (count == 2)
+ {
+ /*
+ * Delta...
+ */
+
+ count = getc(fp) * getc(fp) * img->xsize;
+ color = 0;
+ }
+ else
+ {
+ /*
+ * Absolute...
+ */
+
+ color = -1;
+ align = (2 - (count & 1)) & 1;
+ }
+ }
+ else
+ color = getc(fp);
+ }
+
+ /*
+ * Get a new color as needed...
+ */
+
+ if (color < 0)
+ temp = getc(fp);
+ else
+ temp = color;
+
+ count --;
+
+ /*
+ * Copy the color value...
+ */
+
+ *ptr++ = colormap[temp][2];
+ *ptr++ = colormap[temp][1];
+ *ptr++ = colormap[temp][0];
+ }
+ break;
+
+ case 24 : /* 24-bit RGB */
+ for (x = img->xsize; x > 0; x --, ptr += 3)
+ {
+ ptr[2] = getc(fp);
+ ptr[1] = getc(fp);
+ ptr[0] = getc(fp);
+ }
+
+ /*
+ * Read remaining bytes to align to 32 bits...
+ */
+
+ for (temp = img->xsize * 3; temp & 3; temp ++)
+ getc(fp);
+ break;
+ }
+
+ if (saturation != 100 || hue != 0)
+ cupsImageRGBAdjust(in, img->xsize, saturation, hue);
+
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_WHITE :
+ cupsImageRGBToWhite(in, out, img->xsize);
+ break;
+
+ case CUPS_IMAGE_RGB :
+ cupsImageRGBToRGB(in, out, img->xsize);
+ break;
+
+ case CUPS_IMAGE_BLACK :
+ cupsImageRGBToBlack(in, out, img->xsize);
+ break;
+
+ case CUPS_IMAGE_CMY :
+ cupsImageRGBToCMY(in, out, img->xsize);
+ break;
+
+ case CUPS_IMAGE_CMYK :
+ cupsImageRGBToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * bpp, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, out);
+ }
+
+ fclose(fp);
+ free(in);
+ free(out);
+
+ return (0);
+}
+
+
+/*
+ * 'read_word()' - Read a 16-bit unsigned integer.
+ */
+
+static unsigned short /* O - 16-bit unsigned integer */
+read_word(FILE *fp) /* I - File to read from */
+{
+ unsigned char b0, b1; /* Bytes from file */
+
+ b0 = getc(fp);
+ b1 = getc(fp);
+
+ return ((b1 << 8) | b0);
+}
+
+
+/*
+ * 'read_dword()' - Read a 32-bit unsigned integer.
+ */
+
+static unsigned int /* O - 32-bit unsigned integer */
+read_dword(FILE *fp) /* I - File to read from */
+{
+ unsigned char b0, b1, b2, b3; /* Bytes from file */
+
+ b0 = getc(fp);
+ b1 = getc(fp);
+ b2 = getc(fp);
+ b3 = getc(fp);
+
+ return ((((((b3 << 8) | b2) << 8) | b1) << 8) | b0);
+}
+
+
+/*
+ * 'read_long()' - Read a 32-bit signed integer.
+ */
+
+static int /* O - 32-bit signed integer */
+read_long(FILE *fp) /* I - File to read from */
+{
+ unsigned char b0, b1, b2, b3; /* Bytes from file */
+
+ b0 = getc(fp);
+ b1 = getc(fp);
+ b2 = getc(fp);
+ b3 = getc(fp);
+
+ return ((int)(((((b3 << 8) | b2) << 8) | b1) << 8) | b0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-colorspace.c b/filter/image-colorspace.c
new file mode 100644
index 000000000..28aead265
--- /dev/null
+++ b/filter/image-colorspace.c
@@ -0,0 +1,1567 @@
+/*
+ * "$Id$"
+ *
+ * Colorspace conversions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2006 by Easy Software Products.
+ *
+ * The color saturation/hue matrix stuff is provided thanks to Mr. Paul
+ * Haeberli at "http://www.sgi.com/grafica/matrix/index.html".
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsImageCMYKToBlack() - Convert CMYK data to black.
+ * cupsImageCMYKToCMY() - Convert CMYK colors to CMY.
+ * cupsImageCMYKToCMYK() - Convert CMYK colors to CMYK.
+ * cupsImageCMYKToRGB() - Convert CMYK colors to device-dependent
+ * RGB.
+ * cupsImageCMYKToWhite() - Convert CMYK colors to luminance.
+ * cupsImageLut() - Adjust all pixel values with the given
+ * LUT.
+ * cupsImageRGBAdjust() - Adjust the hue and saturation of the
+ * given RGB colors.
+ * cupsImageRGBToBlack() - Convert RGB data to black.
+ * cupsImageRGBToCMY() - Convert RGB colors to CMY.
+ * cupsImageRGBToCMYK() - Convert RGB colors to CMYK.
+ * cupsImageRGBToRGB() - Convert RGB colors to device-dependent
+ * RGB.
+ * cupsImageRGBToWhite() - Convert RGB colors to luminance.
+ * cupsImageSetProfile() - Set the device color profile.
+ * cupsImageSetRasterColorSpace() - Set the destination colorspace.
+ * cupsImageWhiteToBlack() - Convert luminance colors to black.
+ * cupsImageWhiteToCMY() - Convert luminance colors to CMY.
+ * cupsImageWhiteToCMYK() - Convert luminance colors to CMYK.
+ * cupsImageWhiteToRGB() - Convert luminance data to RGB.
+ * cupsImageWhiteToWhite() - Convert luminance colors to device-
+ * dependent luminance.
+ * cielab() - Map CIE Lab transformation...
+ * huerotate() - Rotate the hue, maintaining luminance.
+ * ident() - Make an identity matrix.
+ * mult() - Multiply two matrices.
+ * rgb_to_lab() - Convert an RGB color to CIE Lab.
+ * rgb_to_xyz() - Convert an RGB color to CIE XYZ.
+ * saturate() - Make a saturation matrix.
+ * xform() - Transform a 3D point using a matrix...
+ * xrotate() - Rotate about the x (red) axis...
+ * yrotate() - Rotate about the y (green) axis...
+ * zrotate() - Rotate about the z (blue) axis...
+ * zshear() - Shear z using x and y...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+
+
+/*
+ * Define some math constants that are required...
+ */
+
+#ifndef M_PI
+# define M_PI 3.14159265358979323846
+#endif /* !M_PI */
+
+#ifndef M_SQRT2
+# define M_SQRT2 1.41421356237309504880
+#endif /* !M_SQRT2 */
+
+#ifndef M_SQRT1_2
+# define M_SQRT1_2 0.70710678118654752440
+#endif /* !M_SQRT1_2 */
+
+/*
+ * CIE XYZ whitepoint...
+ */
+
+#define D65_X (0.412453 + 0.357580 + 0.180423)
+#define D65_Y (0.212671 + 0.715160 + 0.072169)
+#define D65_Z (0.019334 + 0.119193 + 0.950227)
+
+
+/*
+ * Lookup table structure...
+ */
+
+typedef int cups_clut_t[3][256];
+
+
+/*
+ * Local globals...
+ */
+
+static int cupsImageHaveProfile = 0;
+ /* Do we have a color profile? */
+static int *cupsImageDensity;
+ /* Ink/marker density LUT */
+static cups_clut_t *cupsImageMatrix;
+ /* Color transform matrix LUT */
+static cups_cspace_t cupsImageColorSpace = CUPS_CSPACE_RGB;
+ /* Destination colorspace */
+
+
+/*
+ * Local functions...
+ */
+
+static float cielab(float x, float xn);
+static void huerotate(float [3][3], float);
+static void ident(float [3][3]);
+static void mult(float [3][3], float [3][3], float [3][3]);
+static void rgb_to_lab(cups_ib_t *val);
+static void rgb_to_xyz(cups_ib_t *val);
+static void saturate(float [3][3], float);
+static void xform(float [3][3], float, float, float, float *, float *, float *);
+static void xrotate(float [3][3], float, float);
+static void yrotate(float [3][3], float, float);
+static void zrotate(float [3][3], float, float);
+static void zshear(float [3][3], float, float);
+
+
+/*
+ * 'cupsImageCMYKToBlack()' - Convert CMYK data to black.
+ */
+
+void
+cupsImageCMYKToBlack(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ int k; /* Black value */
+
+
+ if (cupsImageHaveProfile)
+ while (count > 0)
+ {
+ k = (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 + in[3];
+
+ if (k < 255)
+ *out++ = cupsImageDensity[k];
+ else
+ *out++ = cupsImageDensity[255];
+
+ in += 4;
+ count --;
+ }
+ else
+ while (count > 0)
+ {
+ k = (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 + in[3];
+
+ if (k < 255)
+ *out++ = k;
+ else
+ *out++ = 255;
+
+ in += 4;
+ count --;
+ }
+}
+
+
+/*
+ * 'cupsImageCMYKToCMY()' - Convert CMYK colors to CMY.
+ */
+
+void
+cupsImageCMYKToCMY(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ int c, m, y, k; /* CMYK values */
+ int cc, cm, cy; /* Calibrated CMY values */
+
+
+ if (cupsImageHaveProfile)
+ while (count > 0)
+ {
+ c = *in++;
+ m = *in++;
+ y = *in++;
+ k = *in++;
+
+ cc = cupsImageMatrix[0][0][c] +
+ cupsImageMatrix[0][1][m] +
+ cupsImageMatrix[0][2][y] + k;
+ cm = cupsImageMatrix[1][0][c] +
+ cupsImageMatrix[1][1][m] +
+ cupsImageMatrix[1][2][y] + k;
+ cy = cupsImageMatrix[2][0][c] +
+ cupsImageMatrix[2][1][m] +
+ cupsImageMatrix[2][2][y] + k;
+
+ if (cc < 0)
+ *out++ = 0;
+ else if (cc > 255)
+ *out++ = cupsImageDensity[255];
+ else
+ *out++ = cupsImageDensity[cc];
+
+ if (cm < 0)
+ *out++ = 0;
+ else if (cm > 255)
+ *out++ = cupsImageDensity[255];
+ else
+ *out++ = cupsImageDensity[cm];
+
+ if (cy < 0)
+ *out++ = 0;
+ else if (cy > 255)
+ *out++ = cupsImageDensity[255];
+ else
+ *out++ = cupsImageDensity[cy];
+
+ count --;
+ }
+ else
+ while (count > 0)
+ {
+ c = *in++;
+ m = *in++;
+ y = *in++;
+ k = *in++;
+
+ c += k;
+ m += k;
+ y += k;
+
+ if (c < 255)
+ *out++ = c;
+ else
+ *out++ = 255;
+
+ if (m < 255)
+ *out++ = y;
+ else
+ *out++ = 255;
+
+ if (y < 255)
+ *out++ = y;
+ else
+ *out++ = 255;
+
+ count --;
+ }
+}
+
+
+/*
+ * 'cupsImageCMYKToCMYK()' - Convert CMYK colors to CMYK.
+ */
+
+void
+cupsImageCMYKToCMYK(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ int c, m, y, k; /* CMYK values */
+ int cc, cm, cy; /* Calibrated CMY values */
+
+
+ if (cupsImageHaveProfile)
+ while (count > 0)
+ {
+ c = *in++;
+ m = *in++;
+ y = *in++;
+ k = *in++;
+
+ cc = (cupsImageMatrix[0][0][c] +
+ cupsImageMatrix[0][1][m] +
+ cupsImageMatrix[0][2][y]);
+ cm = (cupsImageMatrix[1][0][c] +
+ cupsImageMatrix[1][1][m] +
+ cupsImageMatrix[1][2][y]);
+ cy = (cupsImageMatrix[2][0][c] +
+ cupsImageMatrix[2][1][m] +
+ cupsImageMatrix[2][2][y]);
+
+ if (cc < 0)
+ *out++ = 0;
+ else if (cc > 255)
+ *out++ = cupsImageDensity[255];
+ else
+ *out++ = cupsImageDensity[cc];
+
+ if (cm < 0)
+ *out++ = 0;
+ else if (cm > 255)
+ *out++ = cupsImageDensity[255];
+ else
+ *out++ = cupsImageDensity[cm];
+
+ if (cy < 0)
+ *out++ = 0;
+ else if (cy > 255)
+ *out++ = cupsImageDensity[255];
+ else
+ *out++ = cupsImageDensity[cy];
+
+ *out++ = cupsImageDensity[k];
+
+ count --;
+ }
+ else if (in != out)
+ {
+ while (count > 0)
+ {
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = *in++;
+
+ count --;
+ }
+ }
+}
+
+
+/*
+ * 'cupsImageCMYKToRGB()' - Convert CMYK colors to device-dependent RGB.
+ */
+
+void
+cupsImageCMYKToRGB(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ int c, m, y, k; /* CMYK values */
+ int cr, cg, cb; /* Calibrated RGB values */
+
+
+ if (cupsImageHaveProfile)
+ {
+ while (count > 0)
+ {
+ c = *in++;
+ m = *in++;
+ y = *in++;
+ k = *in++;
+
+ cr = cupsImageMatrix[0][0][c] +
+ cupsImageMatrix[0][1][m] +
+ cupsImageMatrix[0][2][y] + k;
+ cg = cupsImageMatrix[1][0][c] +
+ cupsImageMatrix[1][1][m] +
+ cupsImageMatrix[1][2][y] + k;
+ cb = cupsImageMatrix[2][0][c] +
+ cupsImageMatrix[2][1][m] +
+ cupsImageMatrix[2][2][y] + k;
+
+ if (cr < 0)
+ *out++ = 255;
+ else if (cr > 255)
+ *out++ = 255 - cupsImageDensity[255];
+ else
+ *out++ = 255 - cupsImageDensity[cr];
+
+ if (cg < 0)
+ *out++ = 255;
+ else if (cg > 255)
+ *out++ = 255 - cupsImageDensity[255];
+ else
+ *out++ = 255 - cupsImageDensity[cg];
+
+ if (cb < 0)
+ *out++ = 255;
+ else if (cb > 255)
+ *out++ = 255 - cupsImageDensity[255];
+ else
+ *out++ = 255 - cupsImageDensity[cb];
+
+ count --;
+ }
+ }
+ else
+ {
+ while (count > 0)
+ {
+ c = 255 - *in++;
+ m = 255 - *in++;
+ y = 255 - *in++;
+ k = *in++;
+
+ c -= k;
+ m -= k;
+ y -= k;
+
+ if (c > 0)
+ *out++ = c;
+ else
+ *out++ = 0;
+
+ if (m > 0)
+ *out++ = m;
+ else
+ *out++ = 0;
+
+ if (y > 0)
+ *out++ = y;
+ else
+ *out++ = 0;
+
+ if (cupsImageColorSpace == CUPS_CSPACE_CIELab ||
+ cupsImageColorSpace >= CUPS_CSPACE_ICC1)
+ rgb_to_lab(out - 3);
+ else if (cupsImageColorSpace == CUPS_CSPACE_CIEXYZ)
+ rgb_to_xyz(out - 3);
+
+ count --;
+ }
+ }
+}
+
+
+/*
+ * 'cupsImageCMYKToWhite()' - Convert CMYK colors to luminance.
+ */
+
+void
+cupsImageCMYKToWhite(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ int w; /* White value */
+
+
+ if (cupsImageHaveProfile)
+ {
+ while (count > 0)
+ {
+ w = 255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 - in[3];
+
+ if (w > 0)
+ *out++ = cupsImageDensity[w];
+ else
+ *out++ = cupsImageDensity[0];
+
+ in += 4;
+ count --;
+ }
+ }
+ else
+ {
+ while (count > 0)
+ {
+ w = 255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 - in[3];
+
+ if (w > 0)
+ *out++ = w;
+ else
+ *out++ = 0;
+
+ in += 4;
+ count --;
+ }
+ }
+}
+
+
+/*
+ * 'cupsImageLut()' - Adjust all pixel values with the given LUT.
+ */
+
+void
+cupsImageLut(cups_ib_t *pixels, /* IO - Input/output pixels */
+ int count, /* I - Number of pixels/bytes to adjust */
+ const cups_ib_t *lut) /* I - Lookup table */
+{
+ while (count > 0)
+ {
+ *pixels = lut[*pixels];
+ pixels ++;
+ count --;
+ }
+}
+
+
+/*
+ * 'cupsImageRGBAdjust()' - Adjust the hue and saturation of the given RGB colors.
+ */
+
+void
+cupsImageRGBAdjust(cups_ib_t *pixels, /* IO - Input/output pixels */
+ int count, /* I - Number of pixels to adjust */
+ int saturation,/* I - Color saturation (%) */
+ int hue) /* I - Color hue (degrees) */
+{
+ int i, j, k; /* Looping vars */
+ float mat[3][3]; /* Color adjustment matrix */
+ static int last_sat = 100, /* Last saturation used */
+ last_hue = 0; /* Last hue used */
+ static cups_clut_t *lut = NULL; /* Lookup table for matrix */
+
+
+ if (saturation != last_sat || hue != last_hue || !lut)
+ {
+ /*
+ * Build the color adjustment matrix...
+ */
+
+ ident(mat);
+ saturate(mat, saturation * 0.01);
+ huerotate(mat, (float)hue);
+
+ /*
+ * Allocate memory for the lookup table...
+ */
+
+ if (lut == NULL)
+ lut = calloc(3, sizeof(cups_clut_t));
+
+ if (lut == NULL)
+ return;
+
+ /*
+ * Convert the matrix into a 3x3 array of lookup tables...
+ */
+
+ for (i = 0; i < 3; i ++)
+ for (j = 0; j < 3; j ++)
+ for (k = 0; k < 256; k ++)
+ lut[i][j][k] = mat[i][j] * k + 0.5;
+
+ /*
+ * Save the saturation and hue to compare later...
+ */
+
+ last_sat = saturation;
+ last_hue = hue;
+ }
+
+ /*
+ * Adjust each pixel in the given buffer.
+ */
+
+ while (count > 0)
+ {
+ i = lut[0][0][pixels[0]] +
+ lut[1][0][pixels[1]] +
+ lut[2][0][pixels[2]];
+ if (i < 0)
+ pixels[0] = 0;
+ else if (i > 255)
+ pixels[0] = 255;
+ else
+ pixels[0] = i;
+
+ i = lut[0][1][pixels[0]] +
+ lut[1][1][pixels[1]] +
+ lut[2][1][pixels[2]];
+ if (i < 0)
+ pixels[1] = 0;
+ else if (i > 255)
+ pixels[1] = 255;
+ else
+ pixels[1] = i;
+
+ i = lut[0][2][pixels[0]] +
+ lut[1][2][pixels[1]] +
+ lut[2][2][pixels[2]];
+ if (i < 0)
+ pixels[2] = 0;
+ else if (i > 255)
+ pixels[2] = 255;
+ else
+ pixels[2] = i;
+
+ count --;
+ pixels += 3;
+ }
+}
+
+
+/*
+ * 'cupsImageRGBToBlack()' - Convert RGB data to black.
+ */
+
+void
+cupsImageRGBToBlack(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ if (cupsImageHaveProfile)
+ while (count > 0)
+ {
+ *out++ = cupsImageDensity[255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100];
+ in += 3;
+ count --;
+ }
+ else
+ while (count > 0)
+ {
+ *out++ = 255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100;
+ in += 3;
+ count --;
+ }
+}
+
+
+/*
+ * 'cupsImageRGBToCMY()' - Convert RGB colors to CMY.
+ */
+
+void
+cupsImageRGBToCMY(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ int c, m, y, k; /* CMYK values */
+ int cc, cm, cy; /* Calibrated CMY values */
+
+
+ if (cupsImageHaveProfile)
+ while (count > 0)
+ {
+ c = 255 - *in++;
+ m = 255 - *in++;
+ y = 255 - *in++;
+ k = min(c, min(m, y));
+ c -= k;
+ m -= k;
+ y -= k;
+
+ cc = cupsImageMatrix[0][0][c] +
+ cupsImageMatrix[0][1][m] +
+ cupsImageMatrix[0][2][y] + k;
+ cm = cupsImageMatrix[1][0][c] +
+ cupsImageMatrix[1][1][m] +
+ cupsImageMatrix[1][2][y] + k;
+ cy = cupsImageMatrix[2][0][c] +
+ cupsImageMatrix[2][1][m] +
+ cupsImageMatrix[2][2][y] + k;
+
+ if (cc < 0)
+ *out++ = 0;
+ else if (cc > 255)
+ *out++ = cupsImageDensity[255];
+ else
+ *out++ = cupsImageDensity[cc];
+
+ if (cm < 0)
+ *out++ = 0;
+ else if (cm > 255)
+ *out++ = cupsImageDensity[255];
+ else
+ *out++ = cupsImageDensity[cm];
+
+ if (cy < 0)
+ *out++ = 0;
+ else if (cy > 255)
+ *out++ = cupsImageDensity[255];
+ else
+ *out++ = cupsImageDensity[cy];
+
+ count --;
+ }
+ else
+ while (count > 0)
+ {
+ c = 255 - in[0];
+ m = 255 - in[1];
+ y = 255 - in[2];
+ k = min(c, min(m, y));
+
+ *out++ = (255 - in[1] / 4) * (c - k) / 255 + k;
+ *out++ = (255 - in[2] / 4) * (m - k) / 255 + k;
+ *out++ = (255 - in[0] / 4) * (y - k) / 255 + k;
+ in += 3;
+ count --;
+ }
+}
+
+
+/*
+ * 'cupsImageRGBToCMYK()' - Convert RGB colors to CMYK.
+ */
+
+void
+cupsImageRGBToCMYK(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ int c, m, y, k, /* CMYK values */
+ km; /* Maximum K value */
+ int cc, cm, cy; /* Calibrated CMY values */
+
+
+ if (cupsImageHaveProfile)
+ while (count > 0)
+ {
+ c = 255 - *in++;
+ m = 255 - *in++;
+ y = 255 - *in++;
+ k = min(c, min(m, y));
+
+ if ((km = max(c, max(m, y))) > k)
+ k = k * k * k / (km * km);
+
+ c -= k;
+ m -= k;
+ y -= k;
+
+ cc = (cupsImageMatrix[0][0][c] +
+ cupsImageMatrix[0][1][m] +
+ cupsImageMatrix[0][2][y]);
+ cm = (cupsImageMatrix[1][0][c] +
+ cupsImageMatrix[1][1][m] +
+ cupsImageMatrix[1][2][y]);
+ cy = (cupsImageMatrix[2][0][c] +
+ cupsImageMatrix[2][1][m] +
+ cupsImageMatrix[2][2][y]);
+
+ if (cc < 0)
+ *out++ = 0;
+ else if (cc > 255)
+ *out++ = cupsImageDensity[255];
+ else
+ *out++ = cupsImageDensity[cc];
+
+ if (cm < 0)
+ *out++ = 0;
+ else if (cm > 255)
+ *out++ = cupsImageDensity[255];
+ else
+ *out++ = cupsImageDensity[cm];
+
+ if (cy < 0)
+ *out++ = 0;
+ else if (cy > 255)
+ *out++ = cupsImageDensity[255];
+ else
+ *out++ = cupsImageDensity[cy];
+
+ *out++ = cupsImageDensity[k];
+
+ count --;
+ }
+ else
+ while (count > 0)
+ {
+ c = 255 - *in++;
+ m = 255 - *in++;
+ y = 255 - *in++;
+ k = min(c, min(m, y));
+
+ if ((km = max(c, max(m, y))) > k)
+ k = k * k * k / (km * km);
+
+ c -= k;
+ m -= k;
+ y -= k;
+
+ *out++ = c;
+ *out++ = m;
+ *out++ = y;
+ *out++ = k;
+
+ count --;
+ }
+}
+
+
+/*
+ * 'cupsImageRGBToRGB()' - Convert RGB colors to device-dependent RGB.
+ */
+
+void
+cupsImageRGBToRGB(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ int c, m, y, k; /* CMYK values */
+ int cr, cg, cb; /* Calibrated RGB values */
+
+
+ if (cupsImageHaveProfile)
+ {
+ while (count > 0)
+ {
+ c = 255 - *in++;
+ m = 255 - *in++;
+ y = 255 - *in++;
+ k = min(c, min(m, y));
+ c -= k;
+ m -= k;
+ y -= k;
+
+ cr = cupsImageMatrix[0][0][c] +
+ cupsImageMatrix[0][1][m] +
+ cupsImageMatrix[0][2][y] + k;
+ cg = cupsImageMatrix[1][0][c] +
+ cupsImageMatrix[1][1][m] +
+ cupsImageMatrix[1][2][y] + k;
+ cb = cupsImageMatrix[2][0][c] +
+ cupsImageMatrix[2][1][m] +
+ cupsImageMatrix[2][2][y] + k;
+
+ if (cr < 0)
+ *out++ = 255;
+ else if (cr > 255)
+ *out++ = 255 - cupsImageDensity[255];
+ else
+ *out++ = 255 - cupsImageDensity[cr];
+
+ if (cg < 0)
+ *out++ = 255;
+ else if (cg > 255)
+ *out++ = 255 - cupsImageDensity[255];
+ else
+ *out++ = 255 - cupsImageDensity[cg];
+
+ if (cb < 0)
+ *out++ = 255;
+ else if (cb > 255)
+ *out++ = 255 - cupsImageDensity[255];
+ else
+ *out++ = 255 - cupsImageDensity[cb];
+
+ count --;
+ }
+ }
+ else
+ {
+ if (in != out)
+ memcpy(out, in, count * 3);
+
+ if (cupsImageColorSpace == CUPS_CSPACE_CIELab ||
+ cupsImageColorSpace >= CUPS_CSPACE_ICC1)
+ {
+ while (count > 0)
+ {
+ rgb_to_lab(out);
+
+ out += 3;
+ count --;
+ }
+ }
+ else if (cupsImageColorSpace == CUPS_CSPACE_CIEXYZ)
+ {
+ while (count > 0)
+ {
+ rgb_to_xyz(out);
+
+ out += 3;
+ count --;
+ }
+ }
+ }
+}
+
+
+/*
+ * 'cupsImageRGBToWhite()' - Convert RGB colors to luminance.
+ */
+
+void
+cupsImageRGBToWhite(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ if (cupsImageHaveProfile)
+ {
+ while (count > 0)
+ {
+ *out++ = 255 - cupsImageDensity[255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100];
+ in += 3;
+ count --;
+ }
+ }
+ else
+ {
+ while (count > 0)
+ {
+ *out++ = (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100;
+ in += 3;
+ count --;
+ }
+ }
+}
+
+
+/*
+ * 'cupsImageSetProfile()' - Set the device color profile.
+ */
+
+void
+cupsImageSetProfile(float d, /* I - Ink/marker density */
+ float g, /* I - Ink/marker gamma */
+ float matrix[3][3]) /* I - Color transform matrix */
+{
+ int i, j, k; /* Looping vars */
+ float m; /* Current matrix value */
+ int *im; /* Pointer into cupsImageMatrix */
+
+
+ /*
+ * Allocate memory for the profile data...
+ */
+
+ if (cupsImageMatrix == NULL)
+ cupsImageMatrix = calloc(3, sizeof(cups_clut_t));
+
+ if (cupsImageMatrix == NULL)
+ return;
+
+ if (cupsImageDensity == NULL)
+ cupsImageDensity = calloc(256, sizeof(int));
+
+ if (cupsImageDensity == NULL)
+ return;
+
+ /*
+ * Populate the profile lookup tables...
+ */
+
+ cupsImageHaveProfile = 1;
+
+ for (i = 0, im = cupsImageMatrix[0][0]; i < 3; i ++)
+ for (j = 0; j < 3; j ++)
+ for (k = 0, m = matrix[i][j]; k < 256; k ++)
+ *im++ = (int)(k * m + 0.5);
+
+ for (k = 0, im = cupsImageDensity; k < 256; k ++)
+ *im++ = 255.0 * d * pow((float)k / 255.0, g) + 0.5;
+}
+
+
+/*
+ * 'cupsImageSetRasterColorSpace()' - Set the destination colorspace.
+ */
+
+void
+cupsImageSetRasterColorSpace(
+ cups_cspace_t cs) /* I - Destination colorspace */
+{
+ /*
+ * Set the destination colorspace...
+ */
+
+ cupsImageColorSpace = cs;
+
+ /*
+ * Don't use color profiles in colorimetric colorspaces...
+ */
+
+ if (cs == CUPS_CSPACE_CIEXYZ ||
+ cs == CUPS_CSPACE_CIELab ||
+ cs >= CUPS_CSPACE_ICC1)
+ cupsImageHaveProfile = 0;
+}
+
+
+/*
+ * 'cupsImageWhiteToBlack()' - Convert luminance colors to black.
+ */
+
+void
+cupsImageWhiteToBlack(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ if (cupsImageHaveProfile)
+ while (count > 0)
+ {
+ *out++ = cupsImageDensity[255 - *in++];
+ count --;
+ }
+ else
+ while (count > 0)
+ {
+ *out++ = 255 - *in++;
+ count --;
+ }
+}
+
+
+/*
+ * 'cupsImageWhiteToCMY()' - Convert luminance colors to CMY.
+ */
+
+void
+cupsImageWhiteToCMY(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ if (cupsImageHaveProfile)
+ while (count > 0)
+ {
+ out[0] = cupsImageDensity[255 - *in++];
+ out[1] = out[0];
+ out[2] = out[0];
+ out += 3;
+ count --;
+ }
+ else
+ while (count > 0)
+ {
+ *out++ = 255 - *in;
+ *out++ = 255 - *in;
+ *out++ = 255 - *in++;
+ count --;
+ }
+}
+
+
+/*
+ * 'cupsImageWhiteToCMYK()' - Convert luminance colors to CMYK.
+ */
+
+void
+cupsImageWhiteToCMYK(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ if (cupsImageHaveProfile)
+ while (count > 0)
+ {
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = cupsImageDensity[255 - *in++];
+ count --;
+ }
+ else
+ while (count > 0)
+ {
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 255 - *in++;
+ count --;
+ }
+}
+
+
+/*
+ * 'cupsImageWhiteToRGB()' - Convert luminance data to RGB.
+ */
+
+void
+cupsImageWhiteToRGB(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ if (cupsImageHaveProfile)
+ {
+ while (count > 0)
+ {
+ out[0] = 255 - cupsImageDensity[255 - *in++];
+ out[1] = out[0];
+ out[2] = out[0];
+ out += 3;
+ count --;
+ }
+ }
+ else
+ {
+ while (count > 0)
+ {
+ *out++ = *in;
+ *out++ = *in;
+ *out++ = *in++;
+
+ if (cupsImageColorSpace == CUPS_CSPACE_CIELab ||
+ cupsImageColorSpace >= CUPS_CSPACE_ICC1)
+ rgb_to_lab(out - 3);
+ else if (cupsImageColorSpace == CUPS_CSPACE_CIEXYZ)
+ rgb_to_xyz(out - 3);
+
+ count --;
+ }
+ }
+}
+
+
+/*
+ * 'cupsImageWhiteToWhite()' - Convert luminance colors to device-dependent
+ * luminance.
+ */
+
+void
+cupsImageWhiteToWhite(
+ const cups_ib_t *in, /* I - Input pixels */
+ cups_ib_t *out, /* I - Output pixels */
+ int count) /* I - Number of pixels */
+{
+ if (cupsImageHaveProfile)
+ while (count > 0)
+ {
+ *out++ = 255 - cupsImageDensity[255 - *in++];
+ count --;
+ }
+ else if (in != out)
+ memcpy(out, in, count);
+}
+
+
+/*
+ * 'cielab()' - Map CIE Lab transformation...
+ */
+
+static float /* O - Adjusted color value */
+cielab(float x, /* I - Raw color value */
+ float xn) /* I - Whitepoint color value */
+{
+ float x_xn; /* Fraction of whitepoint */
+
+
+ x_xn = x / xn;
+
+ if (x_xn > 0.008856)
+ return (cbrt(x_xn));
+ else
+ return (7.787 * x_xn + 16.0 / 116.0);
+}
+
+
+/*
+ * 'huerotate()' - Rotate the hue, maintaining luminance.
+ */
+
+static void
+huerotate(float mat[3][3], /* I - Matrix to append to */
+ float rot) /* I - Hue rotation in degrees */
+{
+ float hmat[3][3]; /* Hue matrix */
+ float lx, ly, lz; /* Luminance vector */
+ float xrs, xrc; /* X rotation sine/cosine */
+ float yrs, yrc; /* Y rotation sine/cosine */
+ float zrs, zrc; /* Z rotation sine/cosine */
+ float zsx, zsy; /* Z shear x/y */
+
+
+ /*
+ * Load the identity matrix...
+ */
+
+ ident(hmat);
+
+ /*
+ * Rotate the grey vector into positive Z...
+ */
+
+ xrs = M_SQRT1_2;
+ xrc = M_SQRT1_2;
+ xrotate(hmat,xrs,xrc);
+
+ yrs = -1.0 / sqrt(3.0);
+ yrc = -M_SQRT2 * yrs;
+ yrotate(hmat,yrs,yrc);
+
+ /*
+ * Shear the space to make the luminance plane horizontal...
+ */
+
+ xform(hmat, 0.3086, 0.6094, 0.0820, &lx, &ly, &lz);
+ zsx = lx / lz;
+ zsy = ly / lz;
+ zshear(hmat, zsx, zsy);
+
+ /*
+ * Rotate the hue...
+ */
+
+ zrs = sin(rot * M_PI / 180.0);
+ zrc = cos(rot * M_PI / 180.0);
+
+ zrotate(hmat, zrs, zrc);
+
+ /*
+ * Unshear the space to put the luminance plane back...
+ */
+
+ zshear(hmat, -zsx, -zsy);
+
+ /*
+ * Rotate the grey vector back into place...
+ */
+
+ yrotate(hmat, -yrs, yrc);
+ xrotate(hmat, -xrs, xrc);
+
+ /*
+ * Append it to the current matrix...
+ */
+
+ mult(hmat, mat, mat);
+}
+
+
+/*
+ * 'ident()' - Make an identity matrix.
+ */
+
+static void
+ident(float mat[3][3]) /* I - Matrix to identify */
+{
+ mat[0][0] = 1.0;
+ mat[0][1] = 0.0;
+ mat[0][2] = 0.0;
+ mat[1][0] = 0.0;
+ mat[1][1] = 1.0;
+ mat[1][2] = 0.0;
+ mat[2][0] = 0.0;
+ mat[2][1] = 0.0;
+ mat[2][2] = 1.0;
+}
+
+
+/*
+ * 'mult()' - Multiply two matrices.
+ */
+
+static void
+mult(float a[3][3], /* I - First matrix */
+ float b[3][3], /* I - Second matrix */
+ float c[3][3]) /* I - Destination matrix */
+{
+ int x, y; /* Looping vars */
+ float temp[3][3]; /* Temporary matrix */
+
+
+ /*
+ * Multiply a and b, putting the result in temp...
+ */
+
+ for (y = 0; y < 3; y ++)
+ for (x = 0; x < 3; x ++)
+ temp[y][x] = b[y][0] * a[0][x] +
+ b[y][1] * a[1][x] +
+ b[y][2] * a[2][x];
+
+ /*
+ * Copy temp to c (that way c can be a pointer to a or b).
+ */
+
+ memcpy(c, temp, sizeof(temp));
+}
+
+
+/*
+ * 'rgb_to_lab()' - Convert an RGB color to CIE Lab.
+ */
+
+static void
+rgb_to_lab(cups_ib_t *val) /* IO - Color value */
+{
+ float r, /* Red value */
+ g, /* Green value */
+ b, /* Blue value */
+ ciex, /* CIE X value */
+ ciey, /* CIE Y value */
+ ciez, /* CIE Z value */
+ ciey_yn, /* Normalized luminance */
+ ciel, /* CIE L value */
+ ciea, /* CIE a value */
+ cieb; /* CIE b value */
+
+
+ /*
+ * Convert sRGB to linear RGB...
+ */
+
+ r = pow((val[0] / 255.0 + 0.055) / 1.055, 2.4);
+ g = pow((val[1] / 255.0 + 0.055) / 1.055, 2.4);
+ b = pow((val[2] / 255.0 + 0.055) / 1.055, 2.4);
+
+ /*
+ * Convert to CIE XYZ...
+ */
+
+ ciex = 0.412453 * r + 0.357580 * g + 0.180423 * b;
+ ciey = 0.212671 * r + 0.715160 * g + 0.072169 * b;
+ ciez = 0.019334 * r + 0.119193 * g + 0.950227 * b;
+
+ /*
+ * Normalize and convert to CIE Lab...
+ */
+
+ ciey_yn = ciey / D65_Y;
+
+ if (ciey_yn > 0.008856)
+ ciel = 116 * cbrt(ciey_yn) - 16;
+ else
+ ciel = 903.3 * ciey_yn;
+
+/*ciel = ciel;*/
+ ciea = 500 * (cielab(ciex, D65_X) - cielab(ciey, D65_Y));
+ cieb = 200 * (cielab(ciey, D65_Y) - cielab(ciez, D65_Z));
+
+ /*
+ * Scale the L value and bias the a and b values by 128 so that all
+ * numbers are from 0 to 255.
+ */
+
+ ciel = ciel * 2.55 + 0.5;
+ ciea += 128.5;
+ cieb += 128.5;
+
+ /*
+ * Output 8-bit values...
+ */
+
+ if (ciel < 0.0)
+ val[0] = 0;
+ else if (ciel < 255.0)
+ val[0] = (int)ciel;
+ else
+ val[0] = 255;
+
+ if (ciea < 0.0)
+ val[1] = 0;
+ else if (ciea < 255.0)
+ val[1] = (int)ciea;
+ else
+ val[1] = 255;
+
+ if (cieb < 0.0)
+ val[2] = 0;
+ else if (cieb < 255.0)
+ val[2] = (int)cieb;
+ else
+ val[2] = 255;
+}
+
+
+/*
+ * 'rgb_to_xyz()' - Convert an RGB color to CIE XYZ.
+ */
+
+static void
+rgb_to_xyz(cups_ib_t *val) /* IO - Color value */
+{
+ float r, /* Red value */
+ g, /* Green value */
+ b, /* Blue value */
+ ciex, /* CIE X value */
+ ciey, /* CIE Y value */
+ ciez; /* CIE Z value */
+
+
+ /*
+ * Convert sRGB to linear RGB...
+ */
+
+ r = pow((val[0] / 255.0 + 0.055) / 1.055, 2.4);
+ g = pow((val[1] / 255.0 + 0.055) / 1.055, 2.4);
+ b = pow((val[2] / 255.0 + 0.055) / 1.055, 2.4);
+
+ /*
+ * Convert to CIE XYZ...
+ */
+
+ ciex = 0.412453 * r + 0.357580 * g + 0.180423 * b;
+ ciey = 0.212671 * r + 0.715160 * g + 0.072169 * b;
+ ciez = 0.019334 * r + 0.119193 * g + 0.950227 * b;
+
+ /*
+ * Encode as 8-bit XYZ...
+ */
+
+ if (ciex < 0.0f)
+ val[0] = 0;
+ else if (ciex < 1.1f)
+ val[0] = (int)(231.8181f * ciex + 0.5);
+ else
+ val[0] = 255;
+
+ if (ciey < 0.0f)
+ val[1] = 0;
+ else if (ciey < 1.1f)
+ val[1] = (int)(231.8181f * ciey + 0.5);
+ else
+ val[1] = 255;
+
+ if (ciez < 0.0f)
+ val[2] = 0;
+ else if (ciez < 1.1f)
+ val[2] = (int)(231.8181f * ciez + 0.5);
+ else
+ val[2] = 255;
+}
+
+
+/*
+ * 'saturate()' - Make a saturation matrix.
+ */
+
+static void
+saturate(float mat[3][3], /* I - Matrix to append to */
+ float sat) /* I - Desired color saturation */
+{
+ float smat[3][3]; /* Saturation matrix */
+
+
+ smat[0][0] = (1.0 - sat) * 0.3086 + sat;
+ smat[0][1] = (1.0 - sat) * 0.3086;
+ smat[0][2] = (1.0 - sat) * 0.3086;
+ smat[1][0] = (1.0 - sat) * 0.6094;
+ smat[1][1] = (1.0 - sat) * 0.6094 + sat;
+ smat[1][2] = (1.0 - sat) * 0.6094;
+ smat[2][0] = (1.0 - sat) * 0.0820;
+ smat[2][1] = (1.0 - sat) * 0.0820;
+ smat[2][2] = (1.0 - sat) * 0.0820 + sat;
+
+ mult(smat, mat, mat);
+}
+
+
+/*
+ * 'xform()' - Transform a 3D point using a matrix...
+ */
+
+static void
+xform(float mat[3][3], /* I - Matrix */
+ float x, /* I - Input X coordinate */
+ float y, /* I - Input Y coordinate */
+ float z, /* I - Input Z coordinate */
+ float *tx, /* O - Output X coordinate */
+ float *ty, /* O - Output Y coordinate */
+ float *tz) /* O - Output Z coordinate */
+{
+ *tx = x * mat[0][0] + y * mat[1][0] + z * mat[2][0];
+ *ty = x * mat[0][1] + y * mat[1][1] + z * mat[2][1];
+ *tz = x * mat[0][2] + y * mat[1][2] + z * mat[2][2];
+}
+
+
+/*
+ * 'xrotate()' - Rotate about the x (red) axis...
+ */
+
+static void
+xrotate(float mat[3][3], /* I - Matrix */
+ float rs, /* I - Rotation angle sine */
+ float rc) /* I - Rotation angle cosine */
+{
+ float rmat[3][3]; /* I - Rotation matrix */
+
+
+ rmat[0][0] = 1.0;
+ rmat[0][1] = 0.0;
+ rmat[0][2] = 0.0;
+
+ rmat[1][0] = 0.0;
+ rmat[1][1] = rc;
+ rmat[1][2] = rs;
+
+ rmat[2][0] = 0.0;
+ rmat[2][1] = -rs;
+ rmat[2][2] = rc;
+
+ mult(rmat, mat, mat);
+}
+
+
+/*
+ * 'yrotate()' - Rotate about the y (green) axis...
+ */
+
+static void
+yrotate(float mat[3][3], /* I - Matrix */
+ float rs, /* I - Rotation angle sine */
+ float rc) /* I - Rotation angle cosine */
+{
+ float rmat[3][3]; /* I - Rotation matrix */
+
+
+ rmat[0][0] = rc;
+ rmat[0][1] = 0.0;
+ rmat[0][2] = -rs;
+
+ rmat[1][0] = 0.0;
+ rmat[1][1] = 1.0;
+ rmat[1][2] = 0.0;
+
+ rmat[2][0] = rs;
+ rmat[2][1] = 0.0;
+ rmat[2][2] = rc;
+
+ mult(rmat,mat,mat);
+}
+
+
+/*
+ * 'zrotate()' - Rotate about the z (blue) axis...
+ */
+
+static void
+zrotate(float mat[3][3], /* I - Matrix */
+ float rs, /* I - Rotation angle sine */
+ float rc) /* I - Rotation angle cosine */
+{
+ float rmat[3][3]; /* I - Rotation matrix */
+
+
+ rmat[0][0] = rc;
+ rmat[0][1] = rs;
+ rmat[0][2] = 0.0;
+
+ rmat[1][0] = -rs;
+ rmat[1][1] = rc;
+ rmat[1][2] = 0.0;
+
+ rmat[2][0] = 0.0;
+ rmat[2][1] = 0.0;
+ rmat[2][2] = 1.0;
+
+ mult(rmat,mat,mat);
+}
+
+
+/*
+ * 'zshear()' - Shear z using x and y...
+ */
+
+static void
+zshear(float mat[3][3], /* I - Matrix */
+ float dx, /* I - X shear */
+ float dy) /* I - Y shear */
+{
+ float smat[3][3]; /* Shear matrix */
+
+
+ smat[0][0] = 1.0;
+ smat[0][1] = 0.0;
+ smat[0][2] = dx;
+
+ smat[1][0] = 0.0;
+ smat[1][1] = 1.0;
+ smat[1][2] = dy;
+
+ smat[2][0] = 0.0;
+ smat[2][1] = 0.0;
+ smat[2][2] = 1.0;
+
+ mult(smat, mat, mat);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-gif.c b/filter/image-gif.c
new file mode 100644
index 000000000..3e8d9723e
--- /dev/null
+++ b/filter/image-gif.c
@@ -0,0 +1,698 @@
+/*
+ * "$Id$"
+ *
+ * GIF image routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsImageReadGIF() - Read a GIF image file.
+ * gif_get_block() - Read a GIF data block...
+ * gif_get_code() - Get a LZW code from the file...
+ * gif_read_cmap() - Read the colormap from a GIF file...
+ * gif_read_image() - Read a GIF image stream...
+ * gif_read_lzw() - Read a byte from the LZW stream...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+
+
+/*
+ * GIF definitions...
+ */
+
+#define GIF_INTERLACE 0x40
+#define GIF_COLORMAP 0x80
+#define GIF_MAX_BITS 12
+
+typedef cups_ib_t gif_cmap_t[256][4];
+typedef short gif_table_t[4096];
+
+
+/*
+ * Local globals...
+ */
+
+static int gif_eof = 0; /* Did we hit EOF? */
+
+
+/*
+ * Local functions...
+ */
+
+static int gif_get_block(FILE *fp, unsigned char *buffer);
+static int gif_get_code (FILE *fp, int code_size, int first_time);
+static int gif_read_cmap(FILE *fp, int ncolors, gif_cmap_t cmap,
+ int *gray);
+static int gif_read_image(FILE *fp, cups_image_t *img, gif_cmap_t cmap,
+ int interlace);
+static int gif_read_lzw(FILE *fp, int first_time, int input_code_size);
+
+
+/*
+ * '_cupsImageReadGIF()' - Read a GIF image file.
+ */
+
+int /* O - Read status */
+_cupsImageReadGIF(
+ cups_image_t *img, /* IO - cupsImage */
+ FILE *fp, /* I - cupsImage file */
+ cups_icspace_t primary, /* I - Primary choice for colorspace */
+ cups_icspace_t secondary, /* I - Secondary choice for colorspace */
+ int saturation, /* I - Color saturation (%) */
+ int hue, /* I - Color hue (degrees) */
+ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */
+{
+ unsigned char buf[1024]; /* Input buffer */
+ gif_cmap_t cmap; /* Colormap */
+ int i, /* Looping var */
+ bpp, /* Bytes per pixel */
+ gray, /* Grayscale image? */
+ ncolors, /* Bits per pixel */
+ transparent; /* Transparent color index */
+
+
+ /*
+ * GIF files are either grayscale or RGB - no CMYK...
+ */
+
+ if (primary == CUPS_IMAGE_RGB_CMYK)
+ primary = CUPS_IMAGE_RGB;
+
+ /*
+ * Read the header; we already know it is a GIF file...
+ */
+
+ fread(buf, 13, 1, fp);
+
+ img->xsize = (buf[7] << 8) | buf[6];
+ img->ysize = (buf[9] << 8) | buf[8];
+ ncolors = 2 << (buf[10] & 0x07);
+ gray = primary == CUPS_IMAGE_BLACK || primary == CUPS_IMAGE_WHITE;
+
+ if (buf[10] & GIF_COLORMAP)
+ if (gif_read_cmap(fp, ncolors, cmap, &gray))
+ {
+ fclose(fp);
+ return (-1);
+ }
+
+ transparent = -1;
+
+ for (;;)
+ {
+ switch (getc(fp))
+ {
+ case ';' : /* End of image */
+ fclose(fp);
+ return (-1); /* Early end of file */
+
+ case '!' : /* Extension record */
+ buf[0] = getc(fp);
+ if (buf[0] == 0xf9) /* Graphic Control Extension */
+ {
+ gif_get_block(fp, buf);
+ if (buf[0] & 1) /* Get transparent color index */
+ transparent = buf[3];
+ }
+
+ while (gif_get_block(fp, buf) != 0);
+ break;
+
+ case ',' : /* cupsImage data */
+ fread(buf, 9, 1, fp);
+
+ if (buf[8] & GIF_COLORMAP)
+ {
+ ncolors = 2 << (buf[8] & 0x07);
+ gray = primary == CUPS_IMAGE_BLACK || primary == CUPS_IMAGE_WHITE;
+
+ if (gif_read_cmap(fp, ncolors, cmap, &gray))
+ {
+ fclose(fp);
+ return (-1);
+ }
+ }
+
+ if (transparent >= 0)
+ {
+ /*
+ * Make transparent color white...
+ */
+
+ cmap[transparent][0] = 255;
+ cmap[transparent][1] = 255;
+ cmap[transparent][2] = 255;
+ }
+
+ if (gray)
+ {
+ switch (secondary)
+ {
+ case CUPS_IMAGE_CMYK :
+ for (i = ncolors - 1; i >= 0; i --)
+ cupsImageWhiteToCMYK(cmap[i], cmap[i], 1);
+ break;
+ case CUPS_IMAGE_CMY :
+ for (i = ncolors - 1; i >= 0; i --)
+ cupsImageWhiteToCMY(cmap[i], cmap[i], 1);
+ break;
+ case CUPS_IMAGE_BLACK :
+ for (i = ncolors - 1; i >= 0; i --)
+ cupsImageWhiteToBlack(cmap[i], cmap[i], 1);
+ break;
+ case CUPS_IMAGE_WHITE :
+ break;
+ case CUPS_IMAGE_RGB :
+ case CUPS_IMAGE_RGB_CMYK :
+ for (i = ncolors - 1; i >= 0; i --)
+ cupsImageWhiteToRGB(cmap[i], cmap[i], 1);
+ break;
+ }
+
+ img->colorspace = secondary;
+ }
+ else
+ {
+ if (hue != 0 || saturation != 100)
+ for (i = ncolors - 1; i >= 0; i --)
+ cupsImageRGBAdjust(cmap[i], 1, saturation, hue);
+
+ switch (primary)
+ {
+ case CUPS_IMAGE_CMYK :
+ for (i = ncolors - 1; i >= 0; i --)
+ cupsImageRGBToCMYK(cmap[i], cmap[i], 1);
+ break;
+ case CUPS_IMAGE_CMY :
+ for (i = ncolors - 1; i >= 0; i --)
+ cupsImageRGBToCMY(cmap[i], cmap[i], 1);
+ break;
+ case CUPS_IMAGE_BLACK :
+ for (i = ncolors - 1; i >= 0; i --)
+ cupsImageRGBToBlack(cmap[i], cmap[i], 1);
+ break;
+ case CUPS_IMAGE_WHITE :
+ for (i = ncolors - 1; i >= 0; i --)
+ cupsImageRGBToWhite(cmap[i], cmap[i], 1);
+ break;
+ case CUPS_IMAGE_RGB :
+ case CUPS_IMAGE_RGB_CMYK :
+ for (i = ncolors - 1; i >= 0; i --)
+ cupsImageRGBToRGB(cmap[i], cmap[i], 1);
+ break;
+ }
+
+ img->colorspace = primary;
+ }
+
+ if (lut)
+ {
+ bpp = cupsImageGetDepth(img);
+
+ for (i = ncolors - 1; i >= 0; i --)
+ cupsImageLut(cmap[i], bpp, lut);
+ }
+
+ img->xsize = (buf[5] << 8) | buf[4];
+ img->ysize = (buf[7] << 8) | buf[6];
+
+ /*
+ * Check the dimensions of the image; since the dimensions are
+ * a 16-bit integer we just need to check for 0...
+ */
+
+ if (img->xsize == 0 || img->ysize == 0)
+ {
+ fprintf(stderr, "DEBUG: Bad GIF image dimensions: %dx%d\n",
+ img->xsize, img->ysize);
+ fclose(fp);
+ return (1);
+ }
+
+ i = gif_read_image(fp, img, cmap, buf[8] & GIF_INTERLACE);
+ fclose(fp);
+ return (i);
+ }
+ }
+}
+
+
+/*
+ * 'gif_get_block()' - Read a GIF data block...
+ */
+
+static int /* O - Number characters read */
+gif_get_block(FILE *fp, /* I - File to read from */
+ unsigned char *buf) /* I - Input buffer */
+{
+ int count; /* Number of character to read */
+
+
+ /*
+ * Read the count byte followed by the data from the file...
+ */
+
+ if ((count = getc(fp)) == EOF)
+ {
+ gif_eof = 1;
+ return (-1);
+ }
+ else if (count == 0)
+ gif_eof = 1;
+ else if (fread(buf, 1, count, fp) < count)
+ {
+ gif_eof = 1;
+ return (-1);
+ }
+ else
+ gif_eof = 0;
+
+ return (count);
+}
+
+
+/*
+ * 'gif_get_code()' - Get a LZW code from the file...
+ */
+
+static int /* O - LZW code */
+gif_get_code(FILE *fp, /* I - File to read from */
+ int code_size, /* I - Size of code in bits */
+ int first_time) /* I - 1 = first time, 0 = not first time */
+{
+ unsigned i, j, /* Looping vars */
+ ret; /* Return value */
+ int count; /* Number of bytes read */
+ static unsigned char buf[280]; /* Input buffer */
+ static unsigned curbit, /* Current bit */
+ lastbit, /* Last bit in buffer */
+ done, /* Done with this buffer? */
+ last_byte; /* Last byte in buffer */
+ static const unsigned char bits[8] = /* Bit masks for codes */
+ {
+ 0x01, 0x02, 0x04, 0x08,
+ 0x10, 0x20, 0x40, 0x80
+ };
+
+
+ if (first_time)
+ {
+ /*
+ * Just initialize the input buffer...
+ */
+
+ curbit = 0;
+ lastbit = 0;
+ last_byte = 0;
+ done = 0;
+
+ return (0);
+ }
+
+ if ((curbit + code_size) >= lastbit)
+ {
+ /*
+ * Don't have enough bits to hold the code...
+ */
+
+ if (done)
+ return (-1); /* Sorry, no more... */
+
+ /*
+ * Move last two bytes to front of buffer...
+ */
+
+ if (last_byte > 1)
+ {
+ buf[0] = buf[last_byte - 2];
+ buf[1] = buf[last_byte - 1];
+ last_byte = 2;
+ }
+ else if (last_byte == 1)
+ {
+ buf[0] = buf[last_byte - 1];
+ last_byte = 1;
+ }
+
+ /*
+ * Read in another buffer...
+ */
+
+ if ((count = gif_get_block (fp, buf + last_byte)) <= 0)
+ {
+ /*
+ * Whoops, no more data!
+ */
+
+ done = 1;
+ return (-1);
+ }
+
+ /*
+ * Update buffer state...
+ */
+
+ curbit = (curbit - lastbit) + 8 * last_byte;
+ last_byte += count;
+ lastbit = last_byte * 8;
+ }
+
+ for (ret = 0, i = curbit + code_size - 1, j = code_size;
+ j > 0;
+ i --, j --)
+ ret = (ret << 1) | ((buf[i / 8] & bits[i & 7]) != 0);
+
+ curbit += code_size;
+
+ return ret;
+}
+
+
+/*
+ * 'gif_read_cmap()' - Read the colormap from a GIF file...
+ */
+
+static int /* O - -1 on error, 0 on success */
+gif_read_cmap(FILE *fp, /* I - File to read from */
+ int ncolors, /* I - Number of colors in file */
+ gif_cmap_t cmap, /* O - Colormap information */
+ int *gray) /* IO - Is the image grayscale? */
+{
+ int i; /* Looping var */
+
+
+ /*
+ * Read the colormap...
+ */
+
+ for (i = 0; i < ncolors; i ++)
+ if (fread(cmap[i], 3, 1, fp) < 1)
+ return (-1);
+
+ /*
+ * Check to see if the colormap is a grayscale ramp...
+ */
+
+ for (i = 0; i < ncolors; i ++)
+ if (cmap[i][0] != cmap[i][1] || cmap[i][1] != cmap[i][2])
+ break;
+
+ if (i == ncolors)
+ {
+ *gray = 1;
+ return (0);
+ }
+
+ /*
+ * If this needs to be a grayscale image, convert the RGB values to
+ * luminance values...
+ */
+
+ if (*gray)
+ for (i = 0; i < ncolors; i ++)
+ cmap[i][0] = (cmap[i][0] * 31 + cmap[i][1] * 61 + cmap[i][2] * 8) / 100;
+
+ return (0);
+}
+
+
+/*
+ * 'gif_read_image()' - Read a GIF image stream...
+ */
+
+static int /* I - 0 = success, -1 = failure */
+gif_read_image(FILE *fp, /* I - Input file */
+ cups_image_t *img, /* I - cupsImage pointer */
+ gif_cmap_t cmap, /* I - Colormap */
+ int interlace) /* I - Non-zero = interlaced image */
+{
+ unsigned char code_size; /* Code size */
+ cups_ib_t *pixels, /* Pixel buffer */
+ *temp; /* Current pixel */
+ int xpos, /* Current X position */
+ ypos, /* Current Y position */
+ pass; /* Current pass */
+ int pixel; /* Current pixel */
+ int bpp; /* Bytes per pixel */
+ static const int xpasses[4] = /* X interleaving */
+ { 8, 8, 4, 2 },
+ ypasses[5] = /* Y interleaving */
+ { 0, 4, 2, 1, 999999 };
+
+
+ bpp = cupsImageGetDepth(img);
+ pixels = calloc(bpp, img->xsize);
+ xpos = 0;
+ ypos = 0;
+ pass = 0;
+ code_size = getc(fp);
+
+ if (!pixels)
+ return (-1);
+
+ if (code_size > GIF_MAX_BITS || gif_read_lzw(fp, 1, code_size) < 0)
+ {
+ free(pixels);
+ return (-1);
+ }
+
+ temp = pixels;
+ while ((pixel = gif_read_lzw(fp, 0, code_size)) >= 0)
+ {
+ switch (bpp)
+ {
+ case 4 :
+ temp[3] = cmap[pixel][3];
+ case 3 :
+ temp[2] = cmap[pixel][2];
+ case 2 :
+ temp[1] = cmap[pixel][1];
+ default :
+ temp[0] = cmap[pixel][0];
+ }
+
+ xpos ++;
+ temp += bpp;
+ if (xpos == img->xsize)
+ {
+ _cupsImagePutRow(img, 0, ypos, img->xsize, pixels);
+
+ xpos = 0;
+ temp = pixels;
+
+ if (interlace)
+ {
+ ypos += xpasses[pass];
+
+ if (ypos >= img->ysize)
+ {
+ pass ++;
+
+ ypos = ypasses[pass];
+ }
+ }
+ else
+ ypos ++;
+ }
+
+ if (ypos >= img->ysize)
+ break;
+ }
+
+ free(pixels);
+
+ return (0);
+}
+
+
+/*
+ * 'gif_read_lzw()' - Read a byte from the LZW stream...
+ */
+
+static int /* I - Byte from stream */
+gif_read_lzw(FILE *fp, /* I - File to read from */
+ int first_time, /* I - 1 = first time, 0 = not first time */
+ int input_code_size) /* I - Code size in bits */
+{
+ int i, /* Looping var */
+ code, /* Current code */
+ incode; /* Input code */
+ static short fresh = 0, /* 1 = empty buffers */
+ code_size, /* Current code size */
+ set_code_size, /* Initial code size set */
+ max_code, /* Maximum code used */
+ max_code_size, /* Maximum code size */
+ firstcode, /* First code read */
+ oldcode, /* Last code read */
+ clear_code, /* Clear code for LZW input */
+ end_code, /* End code for LZW input */
+ *stack = NULL, /* Output stack */
+ *sp; /* Current stack pointer */
+ static gif_table_t *table = NULL; /* String table */
+
+
+ if (first_time)
+ {
+ /*
+ * Setup LZW state...
+ */
+
+ set_code_size = input_code_size;
+ code_size = set_code_size + 1;
+ clear_code = 1 << set_code_size;
+ end_code = clear_code + 1;
+ max_code_size = 2 * clear_code;
+ max_code = clear_code + 2;
+
+ /*
+ * Allocate memory for buffers...
+ */
+
+ if (table == NULL)
+ table = calloc(2, sizeof(gif_table_t));
+
+ if (table == NULL)
+ return (-1);
+
+ if (stack == NULL)
+ stack = calloc(8192, sizeof(short));
+
+ if (stack == NULL)
+ return (-1);
+
+ /*
+ * Initialize input buffers...
+ */
+
+ gif_get_code(fp, 0, 1);
+
+ /*
+ * Wipe the decompressor table...
+ */
+
+ fresh = 1;
+
+ for (i = 0; i < clear_code; i ++)
+ {
+ table[0][i] = 0;
+ table[1][i] = i;
+ }
+
+ for (; i < 4096; i ++)
+ table[0][i] = table[1][0] = 0;
+
+ sp = stack;
+
+ return (0);
+ }
+ else if (fresh)
+ {
+ fresh = 0;
+
+ do
+ firstcode = oldcode = gif_get_code(fp, code_size, 0);
+ while (firstcode == clear_code);
+
+ return (firstcode);
+ }
+ else if (!table)
+ return (0);
+
+ if (sp > stack)
+ return (*--sp);
+
+ while ((code = gif_get_code (fp, code_size, 0)) >= 0)
+ {
+ if (code == clear_code)
+ {
+ for (i = 0; i < clear_code; i ++)
+ {
+ table[0][i] = 0;
+ table[1][i] = i;
+ }
+
+ for (; i < 4096; i ++)
+ table[0][i] = table[1][i] = 0;
+
+ code_size = set_code_size + 1;
+ max_code_size = 2 * clear_code;
+ max_code = clear_code + 2;
+
+ sp = stack;
+
+ firstcode = oldcode = gif_get_code(fp, code_size, 0);
+
+ return (firstcode);
+ }
+ else if (code == end_code)
+ {
+ unsigned char buf[260];
+
+
+ if (!gif_eof)
+ while (gif_get_block(fp, buf) > 0);
+
+ return (-2);
+ }
+
+ incode = code;
+
+ if (code >= max_code)
+ {
+ *sp++ = firstcode;
+ code = oldcode;
+ }
+
+ while (code >= clear_code)
+ {
+ *sp++ = table[1][code];
+ if (code == table[0][code])
+ return (255);
+
+ code = table[0][code];
+ }
+
+ *sp++ = firstcode = table[1][code];
+ code = max_code;
+
+ if (code < 4096)
+ {
+ table[0][code] = oldcode;
+ table[1][code] = firstcode;
+ max_code ++;
+
+ if (max_code >= max_code_size && max_code_size < 4096)
+ {
+ max_code_size *= 2;
+ code_size ++;
+ }
+ }
+
+ oldcode = incode;
+
+ if (sp > stack)
+ return (*--sp);
+ }
+
+ return (code);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-jpeg.c b/filter/image-jpeg.c
new file mode 100644
index 000000000..3c9ebcc3d
--- /dev/null
+++ b/filter/image-jpeg.c
@@ -0,0 +1,322 @@
+/*
+ * "$Id$"
+ *
+ * JPEG image routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsImageReadJPEG() - Read a JPEG image file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+
+#ifdef HAVE_LIBJPEG
+# include <jpeglib.h> /* JPEG/JFIF image definitions */
+
+
+/*
+ * '_cupsImageReadJPEG()' - Read a JPEG image file.
+ */
+
+int /* O - Read status */
+_cupsImageReadJPEG(
+ cups_image_t *img, /* IO - cupsImage */
+ FILE *fp, /* I - cupsImage file */
+ cups_icspace_t primary, /* I - Primary choice for colorspace */
+ cups_icspace_t secondary, /* I - Secondary choice for colorspace */
+ int saturation, /* I - Color saturation (%) */
+ int hue, /* I - Color hue (degrees) */
+ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */
+{
+ struct jpeg_decompress_struct cinfo; /* Decompressor info */
+ struct jpeg_error_mgr jerr; /* Error handler info */
+ cups_ib_t *in, /* Input pixels */
+ *out; /* Output pixels */
+ jpeg_saved_marker_ptr marker; /* Pointer to marker data */
+ int psjpeg = 0; /* Non-zero if Photoshop CMYK JPEG */
+ static const char *cspaces[] =
+ { /* JPEG colorspaces... */
+ "JCS_UNKNOWN",
+ "JCS_GRAYSCALE",
+ "JCS_RGB",
+ "JCS_YCbCr",
+ "JCS_CMYK",
+ "JCS_YCCK"
+ };
+
+
+ /*
+ * Read the JPEG header...
+ */
+
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
+ jpeg_save_markers(&cinfo, JPEG_APP0 + 14, 0xffff); /* Adobe JPEG */
+ jpeg_stdio_src(&cinfo, fp);
+ jpeg_read_header(&cinfo, 1);
+
+ /*
+ * Parse any Adobe APPE data embedded in the JPEG file. Since Adobe doesn't
+ * bother following standards, we have to invert the CMYK JPEG data written by
+ * Adobe apps...
+ */
+
+ for (marker = cinfo.marker_list; marker; marker = marker->next)
+ if (marker->marker == (JPEG_APP0 + 14) && marker->data_length >= 12 &&
+ !memcmp(marker->data, "Adobe", 5) && marker->data[11] == 2)
+ {
+ fputs("DEBUG: Adobe CMYK JPEG detected (inverting color values)\n",
+ stderr);
+ psjpeg = 1;
+ }
+
+ cinfo.quantize_colors = 0;
+
+ fprintf(stderr, "DEBUG: num_components = %d\n", cinfo.num_components);
+ fprintf(stderr, "DEBUG: jpeg_color_space = %s\n",
+ cspaces[cinfo.jpeg_color_space]);
+
+ if (cinfo.num_components == 1)
+ {
+ fputs("DEBUG: Converting image to grayscale...\n", stderr);
+
+ cinfo.out_color_space = JCS_GRAYSCALE;
+ cinfo.out_color_components = 1;
+ cinfo.output_components = 1;
+
+ img->colorspace = secondary;
+ }
+ else if (cinfo.num_components == 4)
+ {
+ fputs("DEBUG: Converting image to CMYK...\n", stderr);
+
+ cinfo.out_color_space = JCS_CMYK;
+ cinfo.out_color_components = 4;
+ cinfo.output_components = 4;
+
+ img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_CMYK : primary;
+ }
+ else
+ {
+ fputs("DEBUG: Converting image to RGB...\n", stderr);
+
+ cinfo.out_color_space = JCS_RGB;
+ cinfo.out_color_components = 3;
+ cinfo.output_components = 3;
+
+ img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary;
+ }
+
+ jpeg_calc_output_dimensions(&cinfo);
+
+ if (cinfo.output_width <= 0 || cinfo.output_width > CUPS_IMAGE_MAX_WIDTH ||
+ cinfo.output_height <= 0 || cinfo.output_height > CUPS_IMAGE_MAX_HEIGHT)
+ {
+ fprintf(stderr, "DEBUG: Bad JPEG dimensions %dx%d!\n",
+ cinfo.output_width, cinfo.output_height);
+
+ jpeg_destroy_decompress(&cinfo);
+
+ fclose(fp);
+ return (1);
+ }
+
+ img->xsize = cinfo.output_width;
+ img->ysize = cinfo.output_height;
+
+ if (cinfo.X_density > 0 && cinfo.Y_density > 0 && cinfo.density_unit > 0)
+ {
+ if (cinfo.density_unit == 1)
+ {
+ img->xppi = cinfo.X_density;
+ img->yppi = cinfo.Y_density;
+ }
+ else
+ {
+ img->xppi = (int)((float)cinfo.X_density * 2.54);
+ img->yppi = (int)((float)cinfo.Y_density * 2.54);
+ }
+
+ if (img->xppi == 0 || img->yppi == 0)
+ {
+ fprintf(stderr, "DEBUG: Bad JPEG image resolution %dx%d PPI.\n",
+ img->xppi, img->yppi);
+ img->xppi = img->yppi = 128;
+ }
+ }
+
+ fprintf(stderr, "DEBUG: JPEG image %dx%dx%d, %dx%d PPI\n",
+ img->xsize, img->ysize, cinfo.output_components,
+ img->xppi, img->yppi);
+
+ cupsImageSetMaxTiles(img, 0);
+
+ in = malloc(img->xsize * cinfo.output_components);
+ out = malloc(img->xsize * cupsImageGetDepth(img));
+
+ jpeg_start_decompress(&cinfo);
+
+ while (cinfo.output_scanline < cinfo.output_height)
+ {
+ jpeg_read_scanlines(&cinfo, (JSAMPROW *)&in, (JDIMENSION)1);
+
+ if (psjpeg && cinfo.output_components == 4)
+ {
+ /*
+ * Invert CMYK data from Photoshop...
+ */
+
+ cups_ib_t *ptr; /* Pointer into buffer */
+ int i; /* Looping var */
+
+
+ for (ptr = in, i = img->xsize * 4; i > 0; i --, ptr ++)
+ *ptr = 255 - *ptr;
+ }
+
+ if ((saturation != 100 || hue != 0) && cinfo.output_components == 3)
+ cupsImageRGBAdjust(in, img->xsize, saturation, hue);
+
+ if ((img->colorspace == CUPS_IMAGE_WHITE && cinfo.out_color_space == JCS_GRAYSCALE) ||
+ (img->colorspace == CUPS_IMAGE_CMYK && cinfo.out_color_space == JCS_CMYK))
+ {
+#ifdef DEBUG
+ int i, j;
+ cups_ib_t *ptr;
+
+
+ fputs("DEBUG: Direct Data...\n", stderr);
+
+ fputs("DEBUG:", stderr);
+
+ for (i = 0, ptr = in; i < img->xsize; i ++)
+ {
+ putc(' ', stderr);
+ for (j = 0; j < cinfo.output_components; j ++, ptr ++)
+ fprintf(stderr, "%02X", *ptr & 255);
+ }
+
+ putc('\n', stderr);
+#endif /* DEBUG */
+
+ if (lut)
+ cupsImageLut(in, img->xsize * cupsImageGetDepth(img), lut);
+
+ _cupsImagePutRow(img, 0, cinfo.output_scanline - 1, img->xsize, in);
+ }
+ else if (cinfo.out_color_space == JCS_GRAYSCALE)
+ {
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_BLACK :
+ cupsImageWhiteToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_RGB :
+ cupsImageWhiteToRGB(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageWhiteToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageWhiteToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * cupsImageGetDepth(img), lut);
+
+ _cupsImagePutRow(img, 0, cinfo.output_scanline - 1, img->xsize, out);
+ }
+ else if (cinfo.out_color_space == JCS_RGB)
+ {
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_RGB :
+ cupsImageRGBToRGB(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_WHITE :
+ cupsImageRGBToWhite(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageRGBToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageRGBToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageRGBToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * cupsImageGetDepth(img), lut);
+
+ _cupsImagePutRow(img, 0, cinfo.output_scanline - 1, img->xsize, out);
+ }
+ else /* JCS_CMYK */
+ {
+ fputs("DEBUG: JCS_CMYK\n", stderr);
+
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_WHITE :
+ cupsImageCMYKToWhite(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageCMYKToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageCMYKToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_RGB :
+ cupsImageCMYKToRGB(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * cupsImageGetDepth(img), lut);
+
+ _cupsImagePutRow(img, 0, cinfo.output_scanline - 1, img->xsize, out);
+ }
+ }
+
+ free(in);
+ free(out);
+
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+
+ fclose(fp);
+
+ return (0);
+}
+#endif /* HAVE_LIBJPEG */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-photocd.c b/filter/image-photocd.c
new file mode 100644
index 000000000..7a4de6c09
--- /dev/null
+++ b/filter/image-photocd.c
@@ -0,0 +1,333 @@
+/*
+ * "$Id$"
+ *
+ * PhotoCD routines for CUPS.
+ *
+ * PhotoCD support is currently limited to the 768x512 base image, which
+ * is only YCC encoded. Support for the higher resolution images will
+ * require a lot of extra code...
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsImageReadPhotoCD() - Read a PhotoCD image file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+
+
+/*
+ * '_cupsImageReadPhotoCD()' - Read a PhotoCD image file.
+ */
+
+int /* O - Read status */
+_cupsImageReadPhotoCD(
+ cups_image_t *img, /* IO - cupsImage */
+ FILE *fp, /* I - cupsImage file */
+ cups_icspace_t primary, /* I - Primary choice for colorspace */
+ cups_icspace_t secondary, /* I - Secondary choice for colorspace */
+ int saturation, /* I - Color saturation (%) */
+ int hue, /* I - Color hue (degrees) */
+ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */
+{
+ int x, y; /* Looping vars */
+ int xdir, /* X direction */
+ xstart; /* X starting point */
+ int bpp; /* Bytes per pixel */
+ int pass; /* Pass number */
+ int rotation; /* 0 for 768x512, 1 for 512x768 */
+ int temp, /* Adjusted luminance */
+ temp2, /* Red, green, and blue values */
+ cb, cr; /* Adjusted chroma values */
+ cups_ib_t *in, /* Input (YCC) pixels */
+ *iy, /* Luminance */
+ *icb, /* Blue chroma */
+ *icr, /* Red chroma */
+ *rgb, /* RGB */
+ *rgbptr, /* Pointer into RGB data */
+ *out; /* Output pixels */
+
+
+ (void)secondary;
+
+ /*
+ * Get the image orientation...
+ */
+
+ fseek(fp, 72, SEEK_SET);
+ rotation = (getc(fp) & 63) != 8;
+
+ /*
+ * Seek to the start of the base image...
+ */
+
+ fseek(fp, 0x30000, SEEK_SET);
+
+ /*
+ * Allocate and initialize...
+ */
+
+ img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary;
+ img->xppi = 128;
+ img->yppi = 128;
+
+ if (rotation)
+ {
+ img->xsize = 512;
+ img->ysize = 768;
+ }
+ else
+ {
+ img->xsize = 768;
+ img->ysize = 512;
+ }
+
+ cupsImageSetMaxTiles(img, 0);
+
+ bpp = cupsImageGetDepth(img);
+
+ if ((in = malloc(768 * 3)) == NULL)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ fclose(fp);
+ return (1);
+ }
+
+ if ((out = malloc(768 * bpp)) == NULL)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ fclose(fp);
+ free(in);
+ return (1);
+ }
+
+ if (bpp > 1)
+ {
+ if ((rgb = malloc(768 * 3)) == NULL)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ fclose(fp);
+ free(in);
+ free(out);
+ return (1);
+ }
+ }
+ else
+ rgb = NULL;
+
+ if (rotation)
+ {
+ xstart = 767 * bpp;
+ xdir = -2 * bpp;
+ }
+ else
+ {
+ xstart = 0;
+ xdir = 0;
+ }
+
+ /*
+ * Read the image file...
+ */
+
+ for (y = 0; y < 512; y += 2)
+ {
+ /*
+ * Grab the next two scanlines:
+ *
+ * YYYYYYYYYYYYYYY...
+ * YYYYYYYYYYYYYYY...
+ * CbCbCb...CrCrCr...
+ */
+
+ if (fread(in, 1, 768 * 3, fp) < (768 * 3))
+ {
+ /*
+ * Couldn't read a row of data - return an error!
+ */
+
+ free(in);
+ free(out);
+
+ if (bpp > 1)
+ free(rgb);
+
+ return (-1);
+ }
+
+ /*
+ * Process the two scanlines...
+ */
+
+ for (pass = 0, iy = in; pass < 2; pass ++)
+ {
+ if (bpp == 1)
+ {
+ /*
+ * Just extract the luminance channel from the line and put it
+ * in the image...
+ */
+
+ if (primary == CUPS_IMAGE_BLACK)
+ {
+ if (rotation)
+ {
+ for (rgbptr = out + xstart, x = 0; x < 768; x ++)
+ *rgbptr-- = 255 - *iy++;
+
+ if (lut)
+ cupsImageLut(out, 768, lut);
+
+ _cupsImagePutCol(img, 511 - y - pass, 0, 768, out);
+ }
+ else
+ {
+ cupsImageWhiteToBlack(iy, out, 768);
+
+ if (lut)
+ cupsImageLut(out, 768, lut);
+
+ _cupsImagePutRow(img, 0, y + pass, 768, out);
+ iy += 768;
+ }
+ }
+ else if (rotation)
+ {
+ for (rgbptr = out + xstart, x = 0; x < 768; x ++)
+ *rgbptr-- = 255 - *iy++;
+
+ if (lut)
+ cupsImageLut(out, 768, lut);
+
+ _cupsImagePutCol(img, 511 - y - pass, 0, 768, out);
+ }
+ else
+ {
+ if (lut)
+ cupsImageLut(iy, 768, lut);
+
+ _cupsImagePutRow(img, 0, y + pass, 768, iy);
+ iy += 768;
+ }
+ }
+ else
+ {
+ /*
+ * Convert YCbCr to RGB... While every pixel gets a luminance
+ * value, adjacent pixels share chroma information.
+ */
+
+ cb = cr = 0.0f;
+
+ for (x = 0, rgbptr = rgb + xstart, icb = in + 1536, icr = in + 1920;
+ x < 768;
+ x ++, iy ++, rgbptr += xdir)
+ {
+ if (!(x & 1))
+ {
+ cb = (float)(*icb - 156);
+ cr = (float)(*icr - 137);
+ }
+
+ temp = 92241 * (*iy);
+
+ temp2 = (temp + 86706 * cr) / 65536;
+ if (temp2 < 0)
+ *rgbptr++ = 0;
+ else if (temp2 > 255)
+ *rgbptr++ = 255;
+ else
+ *rgbptr++ = temp2;
+
+ temp2 = (temp - 25914 * cb - 44166 * cr) / 65536;
+ if (temp2 < 0)
+ *rgbptr++ = 0;
+ else if (temp2 > 255)
+ *rgbptr++ = 255;
+ else
+ *rgbptr++ = temp2;
+
+ temp2 = (temp + 133434 * cb) / 65536;
+ if (temp2 < 0)
+ *rgbptr++ = 0;
+ else if (temp2 > 255)
+ *rgbptr++ = 255;
+ else
+ *rgbptr++ = temp2;
+
+ if (x & 1)
+ {
+ icb ++;
+ icr ++;
+ }
+ }
+
+ /*
+ * Adjust the hue and saturation if needed...
+ */
+
+ if (saturation != 100 || hue != 0)
+ cupsImageRGBAdjust(rgb, 768, saturation, hue);
+
+ /*
+ * Then convert the RGB data to the appropriate colorspace and
+ * put it in the image...
+ */
+
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_RGB :
+ cupsImageRGBToRGB(rgb, out, 768);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageRGBToCMY(rgb, out, 768);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageRGBToCMYK(rgb, out, 768);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, 768 * bpp, lut);
+
+ if (rotation)
+ _cupsImagePutCol(img, 511 - y - pass, 0, 768, out);
+ else
+ _cupsImagePutRow(img, 0, y + pass, 768, out);
+ }
+ }
+ }
+
+ /*
+ * Free memory and return...
+ */
+
+ free(in);
+ free(out);
+ if (bpp > 1)
+ free(rgb);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-pix.c b/filter/image-pix.c
new file mode 100644
index 000000000..f8b2ae6ed
--- /dev/null
+++ b/filter/image-pix.c
@@ -0,0 +1,240 @@
+/*
+ * "$Id$"
+ *
+ * Alias PIX image routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsImageReadPIX() - Read a PIX image file.
+ * read_short() - Read a 16-bit integer.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+
+
+/*
+ * Local functions...
+ */
+
+static short read_short(FILE *fp);
+
+
+/*
+ * '_cupsImageReadPIX()' - Read a PIX image file.
+ */
+
+int /* O - Read status */
+_cupsImageReadPIX(
+ cups_image_t *img, /* IO - cupsImage */
+ FILE *fp, /* I - cupsImage file */
+ cups_icspace_t primary, /* I - Primary choice for colorspace */
+ cups_icspace_t secondary, /* I - Secondary choice for colorspace */
+ int saturation, /* I - Color saturation (%) */
+ int hue, /* I - Color hue (degrees) */
+ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */
+{
+ short width, /* Width of image */
+ height, /* Height of image */
+ depth; /* Depth of image (bits) */
+ int count, /* Repetition count */
+ bpp, /* Bytes per pixel */
+ x, y; /* Looping vars */
+ cups_ib_t r, g, b; /* Red, green/gray, blue values */
+ cups_ib_t *in, /* Input pixels */
+ *out, /* Output pixels */
+ *ptr; /* Pointer into pixels */
+
+
+ /*
+ * Get the image dimensions and setup the image...
+ */
+
+ width = read_short(fp);
+ height = read_short(fp);
+ read_short(fp);
+ read_short(fp);
+ depth = read_short(fp);
+
+ /*
+ * Check the dimensions of the image. Since the short values used for the
+ * width and height cannot exceed CUPS_IMAGE_MAX_WIDTH or
+ * CUPS_IMAGE_MAX_HEIGHT, we just need to verify they are positive integers.
+ */
+
+ if (width <= 0 || height <= 0 ||
+ (depth != 8 && depth != 24))
+ {
+ fprintf(stderr, "DEBUG: Bad PIX image dimensions %dx%dx%d\n",
+ width, height, depth);
+ fclose(fp);
+ return (1);
+ }
+
+ if (depth == 8)
+ img->colorspace = secondary;
+ else
+ img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary;
+
+ img->xsize = width;
+ img->ysize = height;
+
+ cupsImageSetMaxTiles(img, 0);
+
+ bpp = cupsImageGetDepth(img);
+
+ if ((in = malloc(img->xsize * (depth / 8))) == NULL)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ fclose(fp);
+ return (1);
+ }
+
+ if ((out = malloc(img->xsize * bpp)) == NULL)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ fclose(fp);
+ free(in);
+ return (1);
+ }
+
+ /*
+ * Read the image data...
+ */
+
+ if (depth == 8)
+ {
+ for (count = 0, y = 0, g = 0; y < img->ysize; y ++)
+ {
+ if (img->colorspace == CUPS_IMAGE_WHITE)
+ ptr = out;
+ else
+ ptr = in;
+
+ for (x = img->xsize; x > 0; x --, count --)
+ {
+ if (count == 0)
+ {
+ count = getc(fp);
+ g = getc(fp);
+ }
+
+ *ptr++ = g;
+ }
+
+ if (img->colorspace != CUPS_IMAGE_WHITE)
+ switch (img->colorspace)
+ {
+ default :
+ cupsImageWhiteToRGB(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageWhiteToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageWhiteToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageWhiteToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * bpp, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, out);
+ }
+ }
+ else
+ {
+ for (count = 0, y = 0, r = 0, g = 0, b = 0; y < img->ysize; y ++)
+ {
+ ptr = in;
+
+ for (x = img->xsize; x > 0; x --, count --)
+ {
+ if (count == 0)
+ {
+ count = getc(fp);
+ b = getc(fp);
+ g = getc(fp);
+ r = getc(fp);
+ }
+
+ *ptr++ = r;
+ *ptr++ = g;
+ *ptr++ = b;
+ }
+
+ if (saturation != 100 || hue != 0)
+ cupsImageRGBAdjust(in, img->xsize, saturation, hue);
+
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_WHITE :
+ cupsImageRGBToWhite(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_RGB :
+ cupsImageRGBToWhite(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageRGBToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageRGBToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageRGBToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * bpp, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, out);
+ }
+ }
+
+ fclose(fp);
+ free(in);
+ free(out);
+
+ return (0);
+}
+
+
+/*
+ * 'read_short()' - Read a 16-bit integer.
+ */
+
+static short /* O - Value from file */
+read_short(FILE *fp) /* I - File to read from */
+{
+ int ch; /* Character from file */
+
+
+ ch = getc(fp);
+ return ((ch << 8) | getc(fp));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-png.c b/filter/image-png.c
new file mode 100644
index 000000000..4f24f6b03
--- /dev/null
+++ b/filter/image-png.c
@@ -0,0 +1,315 @@
+/*
+ * "$Id$"
+ *
+ * PNG image routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsImageReadPNG() - Read a PNG image file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+
+#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
+# include <png.h> /* Portable Network Graphics (PNG) definitions */
+
+
+/*
+ * '_cupsImageReadPNG()' - Read a PNG image file.
+ */
+
+int /* O - Read status */
+_cupsImageReadPNG(
+ cups_image_t *img, /* IO - cupsImage */
+ FILE *fp, /* I - cupsImage file */
+ cups_icspace_t primary, /* I - Primary choice for colorspace */
+ cups_icspace_t secondary, /* I - Secondary choice for colorspace */
+ int saturation, /* I - Color saturation (%) */
+ int hue, /* I - Color hue (degrees) */
+ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */
+{
+ int y; /* Looping var */
+ png_structp pp; /* PNG read pointer */
+ png_infop info; /* PNG info pointers */
+ png_uint_32 width, /* Width of image */
+ height; /* Height of image */
+ int bit_depth, /* Bit depth */
+ color_type, /* Color type */
+ interlace_type, /* Interlace type */
+ compression_type, /* Compression type */
+ filter_type; /* Filter type */
+ png_uint_32 xppm, /* X pixels per meter */
+ yppm; /* Y pixels per meter */
+ int bpp; /* Bytes per pixel */
+ int pass, /* Current pass */
+ passes; /* Number of passes required */
+ cups_ib_t *in, /* Input pixels */
+ *inptr, /* Pointer into pixels */
+ *out; /* Output pixels */
+ png_color_16 bg; /* Background color */
+
+
+ /*
+ * Setup the PNG data structures...
+ */
+
+ pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ info = png_create_info_struct(pp);
+
+ /*
+ * Initialize the PNG read "engine"...
+ */
+
+ png_init_io(pp, fp);
+
+ /*
+ * Get the image dimensions and load the output image...
+ */
+
+ png_read_info(pp, info);
+
+ png_get_IHDR(pp, info, &width, &height, &bit_depth, &color_type,
+ &interlace_type, &compression_type, &filter_type);
+
+ fprintf(stderr, "DEBUG: PNG image: %dx%dx%d, color_type=%x (%s%s%s)\n",
+ (int)width, (int)height, bit_depth, color_type,
+ (color_type & PNG_COLOR_MASK_COLOR) ? "RGB" : "GRAYSCALE",
+ (color_type & PNG_COLOR_MASK_ALPHA) ? "+ALPHA" : "",
+ (color_type & PNG_COLOR_MASK_PALETTE) ? "+PALETTE" : "");
+
+ if (color_type & PNG_COLOR_MASK_PALETTE)
+ png_set_expand(pp);
+ else if (bit_depth < 8)
+ {
+ png_set_packing(pp);
+ png_set_expand(pp);
+ }
+ else if (bit_depth == 16)
+ png_set_strip_16(pp);
+
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB :
+ primary;
+ else
+ img->colorspace = secondary;
+
+ if (width == 0 || width > CUPS_IMAGE_MAX_WIDTH ||
+ height == 0 || height > CUPS_IMAGE_MAX_HEIGHT)
+ {
+ fprintf(stderr, "DEBUG: PNG image has invalid dimensions %ux%u!\n",
+ (unsigned)width, (unsigned)height);
+ fclose(fp);
+ return (1);
+ }
+
+ img->xsize = width;
+ img->ysize = height;
+
+ if ((xppm = png_get_x_pixels_per_meter(pp, info)) != 0 &&
+ (yppm = png_get_y_pixels_per_meter(pp, info)) != 0)
+ {
+ img->xppi = (int)((float)xppm * 0.0254);
+ img->yppi = (int)((float)yppm * 0.0254);
+
+ if (img->xppi == 0 || img->yppi == 0)
+ {
+ fprintf(stderr, "DEBUG: PNG image has invalid resolution %dx%d PPI\n",
+ img->xppi, img->yppi);
+
+ img->xppi = img->yppi = 128;
+ }
+ }
+
+ cupsImageSetMaxTiles(img, 0);
+
+ passes = png_set_interlace_handling(pp);
+
+ /*
+ * Handle transparency...
+ */
+
+ if (png_get_valid(pp, info, PNG_INFO_tRNS))
+ png_set_tRNS_to_alpha(pp);
+
+ bg.red = 65535;
+ bg.green = 65535;
+ bg.blue = 65535;
+
+ png_set_background(pp, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+
+ if (passes == 1)
+ {
+ /*
+ * Load one row at a time...
+ */
+
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ in = malloc(img->xsize);
+ else
+ in = malloc(img->xsize * 3);
+ }
+ else
+ {
+ /*
+ * Interlaced images must be loaded all at once...
+ */
+
+ size_t bufsize; /* Size of buffer */
+
+
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ bufsize = img->xsize * img->ysize;
+
+ if ((bufsize / img->xsize) != img->ysize)
+ {
+ fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n",
+ (unsigned)width, (unsigned)height);
+ fclose(fp);
+ return (1);
+ }
+ }
+ else
+ {
+ bufsize = img->xsize * img->ysize * 3;
+
+ if ((bufsize / (img->xsize * 3)) != img->ysize)
+ {
+ fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n",
+ (unsigned)width, (unsigned)height);
+ fclose(fp);
+ return (1);
+ }
+ }
+
+ in = malloc(bufsize);
+ }
+
+ bpp = cupsImageGetDepth(img);
+ out = malloc(img->xsize * bpp);
+
+ if (!in || !out)
+ {
+ fputs("DEBUG: Unable to allocate memory for PNG image!\n", stderr);
+
+ if (in)
+ free(in);
+
+ if (out)
+ free(out);
+
+ fclose(fp);
+
+ return (1);
+ }
+
+ /*
+ * Read the image, interlacing as needed...
+ */
+
+ for (pass = 1; pass <= passes; pass ++)
+ for (inptr = in, y = 0; y < img->ysize; y ++)
+ {
+ png_read_row(pp, (png_bytep)inptr, NULL);
+
+ if (pass == passes)
+ {
+ /*
+ * Output this row...
+ */
+
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ if ((saturation != 100 || hue != 0) && bpp > 1)
+ cupsImageRGBAdjust(inptr, img->xsize, saturation, hue);
+
+ switch (img->colorspace)
+ {
+ case CUPS_IMAGE_WHITE :
+ cupsImageRGBToWhite(inptr, out, img->xsize);
+ break;
+ case CUPS_IMAGE_RGB :
+ case CUPS_IMAGE_RGB_CMYK :
+ cupsImageRGBToRGB(inptr, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageRGBToBlack(inptr, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageRGBToCMY(inptr, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageRGBToCMYK(inptr, out, img->xsize);
+ break;
+ }
+ }
+ else
+ {
+ switch (img->colorspace)
+ {
+ case CUPS_IMAGE_WHITE :
+ memcpy(out, inptr, img->xsize);
+ break;
+ case CUPS_IMAGE_RGB :
+ case CUPS_IMAGE_RGB_CMYK :
+ cupsImageWhiteToRGB(inptr, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageWhiteToBlack(inptr, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageWhiteToCMY(inptr, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageWhiteToCMYK(inptr, out, img->xsize);
+ break;
+ }
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * bpp, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, out);
+ }
+
+ if (passes > 1)
+ {
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ inptr += img->xsize * 3;
+ else
+ inptr += img->xsize;
+ }
+ }
+
+ png_read_end(pp, info);
+ png_destroy_read_struct(&pp, &info, NULL);
+
+ fclose(fp);
+ free(in);
+ free(out);
+
+ return (0);
+}
+#endif /* HAVE_LIBPNG && HAVE_LIBZ */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-pnm.c b/filter/image-pnm.c
new file mode 100644
index 000000000..f1949d5d6
--- /dev/null
+++ b/filter/image-pnm.c
@@ -0,0 +1,320 @@
+/*
+ * "$Id$"
+ *
+ * Portable Any Map file routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsImageReadPNM() - Read a PNM image file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+
+
+/*
+ * '_cupsImageReadPNM()' - Read a PNM image file.
+ */
+
+int /* O - Read status */
+_cupsImageReadPNM(
+ cups_image_t *img, /* IO - cupsImage */
+ FILE *fp, /* I - cupsImage file */
+ cups_icspace_t primary, /* I - Primary choice for colorspace */
+ cups_icspace_t secondary, /* I - Secondary choice for colorspace */
+ int saturation, /* I - Color saturation (%) */
+ int hue, /* I - Color hue (degrees) */
+ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */
+{
+ int x, y; /* Looping vars */
+ int bpp; /* Bytes per pixel */
+ cups_ib_t *in, /* Input pixels */
+ *inptr, /* Current input pixel */
+ *out, /* Output pixels */
+ *outptr, /* Current output pixel */
+ bit; /* Bit in input line */
+ char line[255], /* Input line */
+ *lineptr; /* Pointer in line */
+ int format, /* Format of PNM file */
+ val, /* Pixel value */
+ maxval; /* Maximum pixel value */
+
+
+ /*
+ * Read the file header in the format:
+ *
+ * Pformat
+ * # comment1
+ * # comment2
+ * ...
+ * # commentN
+ * width
+ * height
+ * max sample
+ */
+
+ if ((lineptr = fgets(line, sizeof(line), fp)) == NULL)
+ {
+ fputs("DEBUG: Bad PNM header!\n", stderr);
+ fclose(fp);
+ return (1);
+ }
+
+ lineptr ++;
+
+ format = atoi(lineptr);
+ while (isdigit(*lineptr & 255))
+ lineptr ++;
+
+ while (lineptr != NULL && img->xsize == 0)
+ {
+ if (*lineptr == '\0' || *lineptr == '#')
+ lineptr = fgets(line, sizeof(line), fp);
+ else if (isdigit(*lineptr & 255))
+ {
+ img->xsize = atoi(lineptr);
+ while (isdigit(*lineptr & 255))
+ lineptr ++;
+ }
+ else
+ lineptr ++;
+ }
+
+ while (lineptr != NULL && img->ysize == 0)
+ {
+ if (*lineptr == '\0' || *lineptr == '#')
+ lineptr = fgets(line, sizeof(line), fp);
+ else if (isdigit(*lineptr & 255))
+ {
+ img->ysize = atoi(lineptr);
+ while (isdigit(*lineptr & 255))
+ lineptr ++;
+ }
+ else
+ lineptr ++;
+ }
+
+ if (format != 1 && format != 4)
+ {
+ maxval = 0;
+
+ while (lineptr != NULL && maxval == 0)
+ {
+ if (*lineptr == '\0' || *lineptr == '#')
+ lineptr = fgets(line, sizeof(line), fp);
+ else if (isdigit(*lineptr & 255))
+ {
+ maxval = atoi(lineptr);
+ while (isdigit(*lineptr & 255))
+ lineptr ++;
+ }
+ else
+ lineptr ++;
+ }
+ }
+ else
+ maxval = 1;
+
+ if (img->xsize == 0 || img->xsize > CUPS_IMAGE_MAX_WIDTH ||
+ img->ysize == 0 || img->ysize > CUPS_IMAGE_MAX_HEIGHT)
+ {
+ fprintf(stderr, "DEBUG: Bad PNM dimensions %dx%d!\n",
+ img->xsize, img->ysize);
+ fclose(fp);
+ return (1);
+ }
+
+ if (maxval == 0)
+ {
+ fprintf(stderr, "DEBUG: Bad PNM max value %d!\n", maxval);
+ fclose(fp);
+ return (1);
+ }
+
+ if (format == 1 || format == 2 || format == 4 || format == 5)
+ img->colorspace = secondary;
+ else
+ img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary;
+
+ cupsImageSetMaxTiles(img, 0);
+
+ bpp = cupsImageGetDepth(img);
+
+ if ((in = malloc(img->xsize * 3)) == NULL)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ fclose(fp);
+ return (1);
+ }
+
+ if ((out = malloc(img->xsize * bpp)) == NULL)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ fclose(fp);
+ free(in);
+ return (1);
+ }
+
+ /*
+ * Read the image file...
+ */
+
+ for (y = 0; y < img->ysize; y ++)
+ {
+ switch (format)
+ {
+ case 1 :
+ for (x = img->xsize, inptr = in; x > 0; x --, inptr ++)
+ if (fscanf(fp, "%d", &val) == 1)
+ *inptr = val ? 0 : 255;
+ break;
+
+ case 2 :
+ for (x = img->xsize, inptr = in; x > 0; x --, inptr ++)
+ if (fscanf(fp, "%d", &val) == 1)
+ *inptr = 255 * val / maxval;
+ break;
+
+ case 3 :
+ for (x = img->xsize, inptr = in; x > 0; x --, inptr += 3)
+ {
+ if (fscanf(fp, "%d", &val) == 1)
+ inptr[0] = 255 * val / maxval;
+ if (fscanf(fp, "%d", &val) == 1)
+ inptr[1] = 255 * val / maxval;
+ if (fscanf(fp, "%d", &val) == 1)
+ inptr[2] = 255 * val / maxval;
+ }
+ break;
+
+ case 4 :
+ fread(out, (img->xsize + 7) / 8, 1, fp);
+ for (x = img->xsize, inptr = in, outptr = out, bit = 128;
+ x > 0;
+ x --, inptr ++)
+ {
+ if (*outptr & bit)
+ *inptr = 0;
+ else
+ *inptr = 255;
+
+ if (bit > 1)
+ bit >>= 1;
+ else
+ {
+ bit = 128;
+ outptr ++;
+ }
+ }
+ break;
+
+ case 5 :
+ fread(in, img->xsize, 1, fp);
+ break;
+
+ case 6 :
+ fread(in, img->xsize, 3, fp);
+ break;
+ }
+
+ switch (format)
+ {
+ case 1 :
+ case 2 :
+ case 4 :
+ case 5 :
+ if (img->colorspace == CUPS_IMAGE_WHITE)
+ {
+ if (lut)
+ cupsImageLut(in, img->xsize, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, in);
+ }
+ else
+ {
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_RGB :
+ cupsImageWhiteToRGB(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageWhiteToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageWhiteToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageWhiteToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * bpp, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, out);
+ }
+ break;
+
+ default :
+ if ((saturation != 100 || hue != 0) && bpp > 1)
+ cupsImageRGBAdjust(in, img->xsize, saturation, hue);
+
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_WHITE :
+ cupsImageRGBToWhite(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_RGB :
+ cupsImageRGBToRGB(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageRGBToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageRGBToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageRGBToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * bpp, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, out);
+ break;
+ }
+ }
+
+ free(in);
+ free(out);
+
+ fclose(fp);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-private.h b/filter/image-private.h
new file mode 100644
index 000000000..f96e50ed0
--- /dev/null
+++ b/filter/image-private.h
@@ -0,0 +1,220 @@
+/*
+ * "$Id$"
+ *
+ * Private image library definitions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_IMAGE_PRIVATE_H_
+# define _CUPS_IMAGE_PRIVATE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include "image.h"
+# include <cups/cups.h>
+# include <cups/debug-private.h>
+# include <cups/string-private.h>
+# include <stdlib.h>
+# include <string.h>
+# ifdef WIN32
+# include <io.h>
+# else
+# include <unistd.h>
+# endif /* WIN32 */
+# include <errno.h>
+# include <math.h>
+
+
+/*
+ * Constants...
+ */
+
+# define CUPS_IMAGE_MAX_WIDTH 0x07ffffff
+ /* 2^27-1 to allow for 15-channel data */
+# define CUPS_IMAGE_MAX_HEIGHT 0x3fffffff
+ /* 2^30-1 */
+
+# define CUPS_TILE_SIZE 256 /* 256x256 pixel tiles */
+# define CUPS_TILE_MINIMUM 10 /* Minimum number of tiles */
+
+
+/*
+ * min/max/abs macros...
+ */
+
+# ifndef max
+# define max(a,b) ((a) > (b) ? (a) : (b))
+# endif /* !max */
+# ifndef min
+# define min(a,b) ((a) < (b) ? (a) : (b))
+# endif /* !min */
+# ifndef abs
+# define abs(a) ((a) < 0 ? -(a) : (a))
+# endif /* !abs */
+
+
+/*
+ * Types and structures...
+ */
+
+typedef enum cups_iztype_e /**** Image zoom type ****/
+{
+ CUPS_IZOOM_FAST, /* Use nearest-neighbor sampling */
+ CUPS_IZOOM_NORMAL, /* Use bilinear interpolation */
+ CUPS_IZOOM_BEST /* Use bicubic interpolation */
+} cups_iztype_t;
+
+struct cups_ic_s;
+
+typedef struct cups_itile_s /**** Image tile ****/
+{
+ int dirty; /* True if tile is dirty */
+ off_t pos; /* Position of tile on disk (-1 if not written) */
+ struct cups_ic_s *ic; /* Pixel data */
+} cups_itile_t;
+
+typedef struct cups_ic_s /**** Image tile cache ****/
+{
+ struct cups_ic_s *prev, /* Previous tile in cache */
+ *next; /* Next tile in cache */
+ cups_itile_t *tile; /* Tile this is attached to */
+ cups_ib_t *pixels; /* Pixel data */
+} cups_ic_t;
+
+struct cups_image_s /**** Image file data ****/
+{
+ cups_icspace_t colorspace; /* Colorspace of image */
+ unsigned xsize, /* Width of image in pixels */
+ ysize, /* Height of image in pixels */
+ xppi, /* X resolution in pixels-per-inch */
+ yppi, /* Y resolution in pixels-per-inch */
+ num_ics, /* Number of cached tiles */
+ max_ics; /* Maximum number of cached tiles */
+ cups_itile_t **tiles; /* Tiles in image */
+ cups_ic_t *first, /* First cached tile in image */
+ *last; /* Last cached tile in image */
+ int cachefile; /* Tile cache file */
+ char cachename[256]; /* Tile cache filename */
+};
+
+struct cups_izoom_s /**** Image zoom data ****/
+{
+ cups_image_t *img; /* Image to zoom */
+ cups_iztype_t type; /* Type of zooming */
+ unsigned xorig, /* X origin */
+ yorig, /* Y origin */
+ width, /* Width of input area */
+ height, /* Height of input area */
+ depth, /* Number of bytes per pixel */
+ rotated, /* Non-zero if image needs to be rotated */
+ xsize, /* Width of output image */
+ ysize, /* Height of output image */
+ xmax, /* Maximum input image X position */
+ ymax, /* Maximum input image Y position */
+ xmod, /* Threshold for Bresenheim rounding */
+ ymod; /* ... */
+ int xstep, /* Amount to step for each pixel along X */
+ xincr,
+ instep, /* Amount to step pixel pointer along X */
+ inincr,
+ ystep, /* Amount to step for each pixel along Y */
+ yincr,
+ row; /* Current row */
+ cups_ib_t *rows[2], /* Horizontally scaled pixel data */
+ *in; /* Unscaled input pixel data */
+};
+
+
+/*
+ * Prototypes...
+ */
+
+extern int _cupsImagePutCol(cups_image_t *img, int x, int y,
+ int height, const cups_ib_t *pixels);
+extern int _cupsImagePutRow(cups_image_t *img, int x, int y,
+ int width, const cups_ib_t *pixels);
+extern int _cupsImageReadBMP(cups_image_t *img, FILE *fp,
+ cups_icspace_t primary,
+ cups_icspace_t secondary,
+ int saturation, int hue,
+ const cups_ib_t *lut);
+extern int _cupsImageReadFPX(cups_image_t *img, FILE *fp,
+ cups_icspace_t primary,
+ cups_icspace_t secondary,
+ int saturation, int hue,
+ const cups_ib_t *lut);
+extern int _cupsImageReadGIF(cups_image_t *img, FILE *fp,
+ cups_icspace_t primary,
+ cups_icspace_t secondary,
+ int saturation, int hue,
+ const cups_ib_t *lut);
+extern int _cupsImageReadJPEG(cups_image_t *img, FILE *fp,
+ cups_icspace_t primary,
+ cups_icspace_t secondary,
+ int saturation, int hue,
+ const cups_ib_t *lut);
+extern int _cupsImageReadPIX(cups_image_t *img, FILE *fp,
+ cups_icspace_t primary,
+ cups_icspace_t secondary,
+ int saturation, int hue,
+ const cups_ib_t *lut);
+extern int _cupsImageReadPNG(cups_image_t *img, FILE *fp,
+ cups_icspace_t primary,
+ cups_icspace_t secondary,
+ int saturation, int hue,
+ const cups_ib_t *lut);
+extern int _cupsImageReadPNM(cups_image_t *img, FILE *fp,
+ cups_icspace_t primary,
+ cups_icspace_t secondary,
+ int saturation, int hue,
+ const cups_ib_t *lut);
+extern int _cupsImageReadPhotoCD(cups_image_t *img, FILE *fp,
+ cups_icspace_t primary,
+ cups_icspace_t secondary,
+ int saturation, int hue,
+ const cups_ib_t *lut);
+extern int _cupsImageReadSGI(cups_image_t *img, FILE *fp,
+ cups_icspace_t primary,
+ cups_icspace_t secondary,
+ int saturation, int hue,
+ const cups_ib_t *lut);
+extern int _cupsImageReadSunRaster(cups_image_t *img, FILE *fp,
+ cups_icspace_t primary,
+ cups_icspace_t secondary,
+ int saturation, int hue,
+ const cups_ib_t *lut);
+extern int _cupsImageReadTIFF(cups_image_t *img, FILE *fp,
+ cups_icspace_t primary,
+ cups_icspace_t secondary,
+ int saturation, int hue,
+ const cups_ib_t *lut);
+extern void _cupsImageZoomDelete(cups_izoom_t *z);
+extern void _cupsImageZoomFill(cups_izoom_t *z, int iy);
+extern cups_izoom_t *_cupsImageZoomNew(cups_image_t *img, int xc0, int yc0,
+ int xc1, int yc1, int xsize,
+ int ysize, int rotated,
+ cups_iztype_t type);
+
+extern int _cupsRasterExecPS(cups_page_header2_t *h,
+ int *preferred_bits,
+ const char *code);
+extern void _cupsRasterAddError(const char *f, ...);
+extern void _cupsRasterClearError(void);
+
+#endif /* !_CUPS_IMAGE_PRIVATE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-sgi.c b/filter/image-sgi.c
new file mode 100644
index 000000000..a1b16dfd7
--- /dev/null
+++ b/filter/image-sgi.c
@@ -0,0 +1,295 @@
+/*
+ * "$Id$"
+ *
+ * SGI image file routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsImageReadSGI() - Read a SGI image file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+#include "image-sgi.h"
+
+
+/*
+ * '_cupsImageReadSGI()' - Read a SGI image file.
+ */
+
+int /* O - Read status */
+_cupsImageReadSGI(
+ cups_image_t *img, /* IO - cupsImage */
+ FILE *fp, /* I - cupsImage file */
+ cups_icspace_t primary, /* I - Primary choice for colorspace */
+ cups_icspace_t secondary, /* I - Secondary choice for colorspace */
+ int saturation, /* I - Color saturation (%) */
+ int hue, /* I - Color hue (degrees) */
+ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */
+{
+ int i, y; /* Looping vars */
+ int bpp; /* Bytes per pixel */
+ sgi_t *sgip; /* SGI image file */
+ cups_ib_t *in, /* Input pixels */
+ *inptr, /* Current input pixel */
+ *out; /* Output pixels */
+ unsigned short *rows[4], /* Row pointers for image data */
+ *red,
+ *green,
+ *blue,
+ *gray,
+ *alpha;
+
+
+ /*
+ * Setup the SGI file...
+ */
+
+ sgip = sgiOpenFile(fp, SGI_READ, 0, 0, 0, 0, 0);
+
+ /*
+ * Get the image dimensions and load the output image...
+ */
+
+ /*
+ * Check the image dimensions; since xsize and ysize are unsigned shorts,
+ * just check if they are 0 since they can't exceed CUPS_IMAGE_MAX_WIDTH or
+ * CUPS_IMAGE_MAX_HEIGHT...
+ */
+
+ if (sgip->xsize == 0 || sgip->ysize == 0 ||
+ sgip->zsize == 0 || sgip->zsize > 4)
+ {
+ fprintf(stderr, "DEBUG: Bad SGI image dimensions %ux%ux%u!\n",
+ sgip->xsize, sgip->ysize, sgip->zsize);
+ sgiClose(sgip);
+ return (1);
+ }
+
+ if (sgip->zsize < 3)
+ img->colorspace = secondary;
+ else
+ img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary;
+
+ img->xsize = sgip->xsize;
+ img->ysize = sgip->ysize;
+
+ cupsImageSetMaxTiles(img, 0);
+
+ bpp = cupsImageGetDepth(img);
+
+ if ((in = malloc(img->xsize * sgip->zsize)) == NULL)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ sgiClose(sgip);
+ return (1);
+ }
+
+ if ((out = malloc(img->xsize * bpp)) == NULL)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ sgiClose(sgip);
+ free(in);
+ return (1);
+ }
+
+ if ((rows[0] = calloc(img->xsize * sgip->zsize,
+ sizeof(unsigned short))) == NULL)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ sgiClose(sgip);
+ free(in);
+ free(out);
+ return (1);
+ }
+
+ for (i = 1; i < sgip->zsize; i ++)
+ rows[i] = rows[0] + i * img->xsize;
+
+ /*
+ * Read the SGI image file...
+ */
+
+ for (y = 0; y < img->ysize; y ++)
+ {
+ for (i = 0; i < sgip->zsize; i ++)
+ sgiGetRow(sgip, rows[i], img->ysize - 1 - y, i);
+
+ switch (sgip->zsize)
+ {
+ case 1 :
+ if (sgip->bpp == 1)
+ for (i = img->xsize - 1, gray = rows[0], inptr = in;
+ i >= 0;
+ i --)
+ {
+ *inptr++ = *gray++;
+ }
+ else
+ for (i = img->xsize - 1, gray = rows[0], inptr = in;
+ i >= 0;
+ i --)
+ {
+ *inptr++ = (*gray++) / 256 + 128;
+ }
+ break;
+ case 2 :
+ if (sgip->bpp == 1)
+ for (i = img->xsize - 1, gray = rows[0], alpha = rows[1], inptr = in;
+ i >= 0;
+ i --)
+ {
+ *inptr++ = (*gray++) * (*alpha++) / 255;
+ }
+ else
+ for (i = img->xsize - 1, gray = rows[0], alpha = rows[1], inptr = in;
+ i >= 0;
+ i --)
+ {
+ *inptr++ = ((*gray++) / 256 + 128) * (*alpha++) / 32767;
+ }
+ break;
+ case 3 :
+ if (sgip->bpp == 1)
+ for (i = img->xsize - 1, red = rows[0], green = rows[1],
+ blue = rows[2], inptr = in;
+ i >= 0;
+ i --)
+ {
+ *inptr++ = *red++;
+ *inptr++ = *green++;
+ *inptr++ = *blue++;
+ }
+ else
+ for (i = img->xsize - 1, red = rows[0], green = rows[1],
+ blue = rows[2], inptr = in;
+ i >= 0;
+ i --)
+ {
+ *inptr++ = (*red++) / 256 + 128;
+ *inptr++ = (*green++) / 256 + 128;
+ *inptr++ = (*blue++) / 256 + 128;
+ }
+ break;
+ case 4 :
+ if (sgip->bpp == 1)
+ for (i = img->xsize - 1, red = rows[0], green = rows[1],
+ blue = rows[2], alpha = rows[3], inptr = in;
+ i >= 0;
+ i --)
+ {
+ *inptr++ = (*red++) * (*alpha) / 255;
+ *inptr++ = (*green++) * (*alpha) / 255;
+ *inptr++ = (*blue++) * (*alpha++) / 255;
+ }
+ else
+ for (i = img->xsize - 1, red = rows[0], green = rows[1],
+ blue = rows[2], alpha = rows[3], inptr = in;
+ i >= 0;
+ i --)
+ {
+ *inptr++ = ((*red++) / 256 + 128) * (*alpha) / 32767;
+ *inptr++ = ((*green++) / 256 + 128) * (*alpha) / 32767;
+ *inptr++ = ((*blue++) / 256 + 128) * (*alpha++) / 32767;
+ }
+ break;
+ }
+
+ if (sgip->zsize < 3)
+ {
+ if (img->colorspace == CUPS_IMAGE_WHITE)
+ {
+ if (lut)
+ cupsImageLut(in, img->xsize, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, in);
+ }
+ else
+ {
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_RGB :
+ case CUPS_IMAGE_RGB_CMYK :
+ cupsImageWhiteToRGB(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageWhiteToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageWhiteToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageWhiteToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * bpp, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, out);
+ }
+ }
+ else
+ {
+ if ((saturation != 100 || hue != 0) && bpp > 1)
+ cupsImageRGBAdjust(in, img->xsize, saturation, hue);
+
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_WHITE :
+ cupsImageRGBToWhite(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_RGB :
+ cupsImageRGBToRGB(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageRGBToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageRGBToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageRGBToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * bpp, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, out);
+ }
+ }
+
+ free(in);
+ free(out);
+ free(rows[0]);
+
+ sgiClose(sgip);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-sgi.h b/filter/image-sgi.h
new file mode 100644
index 000000000..16226ee15
--- /dev/null
+++ b/filter/image-sgi.h
@@ -0,0 +1,86 @@
+/*
+ * "$Id$"
+ *
+ * SGI image file format library definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _SGI_H_
+# define _SGI_H_
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+
+/*
+ * Constants...
+ */
+
+# define SGI_MAGIC 474 /* Magic number in image file */
+
+# define SGI_READ 0 /* Read from an SGI image file */
+# define SGI_WRITE 1 /* Write to an SGI image file */
+
+# define SGI_COMP_NONE 0 /* No compression */
+# define SGI_COMP_RLE 1 /* Run-length encoding */
+# define SGI_COMP_ARLE 2 /* Agressive run-length encoding */
+
+
+/*
+ * Image structure...
+ */
+
+typedef struct
+{
+ FILE *file; /* Image file */
+ int mode, /* File open mode */
+ bpp, /* Bytes per pixel/channel */
+ comp; /* Compression */
+ unsigned short xsize, /* Width in pixels */
+ ysize, /* Height in pixels */
+ zsize; /* Number of channels */
+ long firstrow, /* File offset for first row */
+ nextrow, /* File offset for next row */
+ **table, /* Offset table for compression */
+ **length; /* Length table for compression */
+ unsigned short *arle_row; /* Advanced RLE compression buffer */
+ long arle_offset, /* Advanced RLE buffer offset */
+ arle_length; /* Advanced RLE buffer length */
+} sgi_t;
+
+
+/*
+ * Prototypes...
+ */
+
+extern int sgiClose(sgi_t *sgip);
+extern int sgiGetRow(sgi_t *sgip, unsigned short *row, int y, int z);
+extern sgi_t *sgiOpen(const char *filename, int mode, int comp, int bpp,
+ int xsize, int ysize, int zsize);
+extern sgi_t *sgiOpenFile(FILE *file, int mode, int comp, int bpp,
+ int xsize, int ysize, int zsize);
+extern int sgiPutRow(sgi_t *sgip, unsigned short *row, int y, int z);
+
+# ifdef __cplusplus
+}
+# endif
+#endif /* !_SGI_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-sgilib.c b/filter/image-sgilib.c
new file mode 100644
index 000000000..f72d1b4a2
--- /dev/null
+++ b/filter/image-sgilib.c
@@ -0,0 +1,890 @@
+/*
+ * "$Id$"
+ *
+ * SGI image file format library routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * sgiClose() - Close an SGI image file.
+ * sgiGetRow() - Get a row of image data from a file.
+ * sgiOpen() - Open an SGI image file for reading or writing.
+ * sgiOpenFile() - Open an SGI image file for reading or writing.
+ * sgiPutRow() - Put a row of image data to a file.
+ * getlong() - Get a 32-bit big-endian integer.
+ * getshort() - Get a 16-bit big-endian integer.
+ * putlong() - Put a 32-bit big-endian integer.
+ * putshort() - Put a 16-bit big-endian integer.
+ * read_rle8() - Read 8-bit RLE data.
+ * read_rle16() - Read 16-bit RLE data.
+ * write_rle8() - Write 8-bit RLE data.
+ * write_rle16() - Write 16-bit RLE data.
+ */
+
+#include "image-sgi.h"
+
+
+/*
+ * Local functions...
+ */
+
+static int getlong(FILE *);
+static int getshort(FILE *);
+static int putlong(long, FILE *);
+static int putshort(unsigned short, FILE *);
+static int read_rle8(FILE *, unsigned short *, int);
+static int read_rle16(FILE *, unsigned short *, int);
+static int write_rle8(FILE *, unsigned short *, int);
+static int write_rle16(FILE *, unsigned short *, int);
+
+
+/*
+ * 'sgiClose()' - Close an SGI image file.
+ */
+
+int /* O - 0 on success, -1 on error */
+sgiClose(sgi_t *sgip) /* I - SGI image */
+{
+ int i; /* Return status */
+ long *offset; /* Looping var for offset table */
+
+
+ if (sgip == NULL)
+ return (-1);
+
+ if (sgip->mode == SGI_WRITE && sgip->comp != SGI_COMP_NONE)
+ {
+ /*
+ * Write the scanline offset table to the file...
+ */
+
+ fseek(sgip->file, 512, SEEK_SET);
+
+ for (i = sgip->ysize * sgip->zsize, offset = sgip->table[0];
+ i > 0;
+ i --, offset ++)
+ if (putlong(offset[0], sgip->file) < 0)
+ return (-1);
+
+ for (i = sgip->ysize * sgip->zsize, offset = sgip->length[0];
+ i > 0;
+ i --, offset ++)
+ if (putlong(offset[0], sgip->file) < 0)
+ return (-1);
+ }
+
+ if (sgip->table != NULL)
+ {
+ free(sgip->table[0]);
+ free(sgip->table);
+ }
+
+ if (sgip->length != NULL)
+ {
+ free(sgip->length[0]);
+ free(sgip->length);
+ }
+
+ if (sgip->comp == SGI_COMP_ARLE)
+ free(sgip->arle_row);
+
+ i = fclose(sgip->file);
+ free(sgip);
+
+ return (i);
+}
+
+
+/*
+ * 'sgiGetRow()' - Get a row of image data from a file.
+ */
+
+int /* O - 0 on success, -1 on error */
+sgiGetRow(sgi_t *sgip, /* I - SGI image */
+ unsigned short *row, /* O - Row to read */
+ int y, /* I - Line to read */
+ int z) /* I - Channel to read */
+{
+ int x; /* X coordinate */
+ long offset; /* File offset */
+
+
+ if (sgip == NULL ||
+ row == NULL ||
+ y < 0 || y >= sgip->ysize ||
+ z < 0 || z >= sgip->zsize)
+ return (-1);
+
+ switch (sgip->comp)
+ {
+ case SGI_COMP_NONE :
+ /*
+ * Seek to the image row - optimize buffering by only seeking if
+ * necessary...
+ */
+
+ offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp;
+ if (offset != ftell(sgip->file))
+ fseek(sgip->file, offset, SEEK_SET);
+
+ if (sgip->bpp == 1)
+ {
+ for (x = sgip->xsize; x > 0; x --, row ++)
+ *row = getc(sgip->file);
+ }
+ else
+ {
+ for (x = sgip->xsize; x > 0; x --, row ++)
+ *row = getshort(sgip->file);
+ }
+ break;
+
+ case SGI_COMP_RLE :
+ offset = sgip->table[z][y];
+ if (offset != ftell(sgip->file))
+ fseek(sgip->file, offset, SEEK_SET);
+
+ if (sgip->bpp == 1)
+ return (read_rle8(sgip->file, row, sgip->xsize));
+ else
+ return (read_rle16(sgip->file, row, sgip->xsize));
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'sgiOpen()' - Open an SGI image file for reading or writing.
+ */
+
+sgi_t * /* O - New image */
+sgiOpen(const char *filename, /* I - File to open */
+ int mode, /* I - Open mode (SGI_READ or SGI_WRITE) */
+ int comp, /* I - Type of compression */
+ int bpp, /* I - Bytes per pixel */
+ int xsize, /* I - Width of image in pixels */
+ int ysize, /* I - Height of image in pixels */
+ int zsize) /* I - Number of channels */
+{
+ sgi_t *sgip; /* New SGI image file */
+ FILE *file; /* Image file pointer */
+
+
+ if (mode == SGI_READ)
+ file = fopen(filename, "rb");
+ else
+ file = fopen(filename, "wb+");
+
+ if (file == NULL)
+ return (NULL);
+
+ if ((sgip = sgiOpenFile(file, mode, comp, bpp, xsize, ysize, zsize)) == NULL)
+ fclose(file);
+
+ return (sgip);
+}
+
+
+/*
+ * 'sgiOpenFile()' - Open an SGI image file for reading or writing.
+ */
+
+sgi_t * /* O - New image */
+sgiOpenFile(FILE *file, /* I - File to open */
+ int mode, /* I - Open mode (SGI_READ or SGI_WRITE) */
+ int comp, /* I - Type of compression */
+ int bpp, /* I - Bytes per pixel */
+ int xsize, /* I - Width of image in pixels */
+ int ysize, /* I - Height of image in pixels */
+ int zsize) /* I - Number of channels */
+{
+ int i, j; /* Looping var */
+ char name[80]; /* Name of file in image header */
+ short magic; /* Magic number */
+ sgi_t *sgip; /* New image pointer */
+
+
+ if ((sgip = calloc(sizeof(sgi_t), 1)) == NULL)
+ return (NULL);
+
+ sgip->file = file;
+
+ switch (mode)
+ {
+ case SGI_READ :
+ sgip->mode = SGI_READ;
+
+ magic = getshort(sgip->file);
+ if (magic != SGI_MAGIC)
+ {
+ free(sgip);
+ return (NULL);
+ }
+
+ sgip->comp = getc(sgip->file);
+ sgip->bpp = getc(sgip->file);
+ getshort(sgip->file); /* Dimensions */
+ sgip->xsize = getshort(sgip->file);
+ sgip->ysize = getshort(sgip->file);
+ sgip->zsize = getshort(sgip->file);
+ getlong(sgip->file); /* Minimum pixel */
+ getlong(sgip->file); /* Maximum pixel */
+
+ if (sgip->comp)
+ {
+ /*
+ * This file is compressed; read the scanline tables...
+ */
+
+ fseek(sgip->file, 512, SEEK_SET);
+
+ if ((sgip->table = calloc(sgip->zsize, sizeof(long *))) == NULL)
+ {
+ free(sgip);
+ return (NULL);
+ }
+
+ if ((sgip->table[0] = calloc(sgip->ysize * sgip->zsize,
+ sizeof(long))) == NULL)
+ {
+ free(sgip->table);
+ free(sgip);
+ return (NULL);
+ }
+
+ for (i = 1; i < sgip->zsize; i ++)
+ sgip->table[i] = sgip->table[0] + i * sgip->ysize;
+
+ for (i = 0; i < sgip->zsize; i ++)
+ for (j = 0; j < sgip->ysize; j ++)
+ sgip->table[i][j] = getlong(sgip->file);
+ }
+ break;
+
+ case SGI_WRITE :
+ if (xsize < 1 ||
+ ysize < 1 ||
+ zsize < 1 ||
+ bpp < 1 || bpp > 2 ||
+ comp < SGI_COMP_NONE || comp > SGI_COMP_ARLE)
+ {
+ free(sgip);
+ return (NULL);
+ }
+
+ sgip->mode = SGI_WRITE;
+
+ putshort(SGI_MAGIC, sgip->file);
+ putc((sgip->comp = comp) != 0, sgip->file);
+ putc(sgip->bpp = bpp, sgip->file);
+ putshort(3, sgip->file); /* Dimensions */
+ putshort(sgip->xsize = xsize, sgip->file);
+ putshort(sgip->ysize = ysize, sgip->file);
+ putshort(sgip->zsize = zsize, sgip->file);
+ if (bpp == 1)
+ {
+ putlong(0, sgip->file); /* Minimum pixel */
+ putlong(255, sgip->file); /* Maximum pixel */
+ }
+ else
+ {
+ putlong(-32768, sgip->file); /* Minimum pixel */
+ putlong(32767, sgip->file); /* Maximum pixel */
+ }
+ putlong(0, sgip->file); /* Reserved */
+
+ memset(name, 0, sizeof(name));
+ fwrite(name, sizeof(name), 1, sgip->file);
+
+ for (i = 0; i < 102; i ++)
+ putlong(0, sgip->file);
+
+ switch (comp)
+ {
+ case SGI_COMP_NONE : /* No compression */
+ /*
+ * This file is uncompressed. To avoid problems with sparse files,
+ * we need to write blank pixels for the entire image...
+ */
+
+ if (bpp == 1)
+ {
+ for (i = xsize * ysize * zsize; i > 0; i --)
+ putc(0, sgip->file);
+ }
+ else
+ {
+ for (i = xsize * ysize * zsize; i > 0; i --)
+ putshort(0, sgip->file);
+ }
+ break;
+
+ case SGI_COMP_ARLE : /* Aggressive RLE */
+ sgip->arle_row = calloc(xsize, sizeof(unsigned short));
+ sgip->arle_offset = 0;
+
+ case SGI_COMP_RLE : /* Run-Length Encoding */
+ /*
+ * This file is compressed; write the (blank) scanline tables...
+ */
+
+ for (i = 2 * ysize * zsize; i > 0; i --)
+ putlong(0, sgip->file);
+
+ sgip->firstrow = ftell(sgip->file);
+ sgip->nextrow = ftell(sgip->file);
+ if ((sgip->table = calloc(sgip->zsize, sizeof(long *))) == NULL)
+ {
+ free(sgip);
+ return (NULL);
+ }
+
+ if ((sgip->table[0] = calloc(sgip->ysize * sgip->zsize,
+ sizeof(long))) == NULL)
+ {
+ free(sgip->table);
+ free(sgip);
+ return (NULL);
+ }
+
+ for (i = 1; i < sgip->zsize; i ++)
+ sgip->table[i] = sgip->table[0] + i * sgip->ysize;
+
+ if ((sgip->length = calloc(sgip->zsize, sizeof(long *))) == NULL)
+ {
+ free(sgip->table);
+ free(sgip);
+ return (NULL);
+ }
+
+ if ((sgip->length[0] = calloc(sgip->ysize * sgip->zsize,
+ sizeof(long))) == NULL)
+ {
+ free(sgip->length);
+ free(sgip->table);
+ free(sgip);
+ return (NULL);
+ }
+
+ for (i = 1; i < sgip->zsize; i ++)
+ sgip->length[i] = sgip->length[0] + i * sgip->ysize;
+ break;
+ }
+ break;
+
+ default :
+ free(sgip);
+ return (NULL);
+ }
+
+ return (sgip);
+}
+
+
+/*
+ * 'sgiPutRow()' - Put a row of image data to a file.
+ */
+
+int /* O - 0 on success, -1 on error */
+sgiPutRow(sgi_t *sgip, /* I - SGI image */
+ unsigned short *row, /* I - Row to write */
+ int y, /* I - Line to write */
+ int z) /* I - Channel to write */
+{
+ int x; /* X coordinate */
+ long offset; /* File offset */
+
+
+ if (sgip == NULL ||
+ row == NULL ||
+ y < 0 || y >= sgip->ysize ||
+ z < 0 || z >= sgip->zsize)
+ return (-1);
+
+ switch (sgip->comp)
+ {
+ case SGI_COMP_NONE :
+ /*
+ * Seek to the image row - optimize buffering by only seeking if
+ * necessary...
+ */
+
+ offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp;
+ if (offset != ftell(sgip->file))
+ fseek(sgip->file, offset, SEEK_SET);
+
+ if (sgip->bpp == 1)
+ {
+ for (x = sgip->xsize; x > 0; x --, row ++)
+ putc(*row, sgip->file);
+ }
+ else
+ {
+ for (x = sgip->xsize; x > 0; x --, row ++)
+ putshort(*row, sgip->file);
+ }
+ break;
+
+ case SGI_COMP_ARLE :
+ if (sgip->table[z][y] != 0)
+ return (-1);
+
+ /*
+ * First check the last row written...
+ */
+
+ if (sgip->arle_offset > 0)
+ {
+ for (x = 0; x < sgip->xsize; x ++)
+ if (row[x] != sgip->arle_row[x])
+ break;
+
+ if (x == sgip->xsize)
+ {
+ sgip->table[z][y] = sgip->arle_offset;
+ sgip->length[z][y] = sgip->arle_length;
+ return (0);
+ }
+ }
+
+ /*
+ * If that didn't match, search all the previous rows...
+ */
+
+ fseek(sgip->file, sgip->firstrow, SEEK_SET);
+
+ if (sgip->bpp == 1)
+ {
+ for (;;)
+ {
+ sgip->arle_offset = ftell(sgip->file);
+ if ((sgip->arle_length = read_rle8(sgip->file, sgip->arle_row, sgip->xsize)) < 0)
+ {
+ x = 0;
+ break;
+ }
+
+ if (memcmp(row, sgip->arle_row, sgip->xsize * sizeof(unsigned short)) == 0)
+ {
+ x = sgip->xsize;
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ sgip->arle_offset = ftell(sgip->file);
+ if ((sgip->arle_length = read_rle16(sgip->file, sgip->arle_row, sgip->xsize)) < 0)
+ {
+ x = 0;
+ break;
+ }
+
+ if (memcmp(row, sgip->arle_row, sgip->xsize * sizeof(unsigned short)) == 0)
+ {
+ x = sgip->xsize;
+ break;
+ }
+ }
+ }
+
+ if (x == sgip->xsize)
+ {
+ sgip->table[z][y] = sgip->arle_offset;
+ sgip->length[z][y] = sgip->arle_length;
+ return (0);
+ }
+ else
+ fseek(sgip->file, 0, SEEK_END); /* Clear EOF */
+
+ case SGI_COMP_RLE :
+ if (sgip->table[z][y] != 0)
+ return (-1);
+
+ offset = sgip->table[z][y] = sgip->nextrow;
+
+ if (offset != ftell(sgip->file))
+ fseek(sgip->file, offset, SEEK_SET);
+
+ if (sgip->bpp == 1)
+ x = write_rle8(sgip->file, row, sgip->xsize);
+ else
+ x = write_rle16(sgip->file, row, sgip->xsize);
+
+ if (sgip->comp == SGI_COMP_ARLE)
+ {
+ sgip->arle_offset = offset;
+ sgip->arle_length = x;
+ memcpy(sgip->arle_row, row, sgip->xsize * sizeof(unsigned short));
+ }
+
+ sgip->nextrow = ftell(sgip->file);
+ sgip->length[z][y] = x;
+
+ return (x);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'getlong()' - Get a 32-bit big-endian integer.
+ */
+
+static int /* O - Long value */
+getlong(FILE *fp) /* I - File to read from */
+{
+ unsigned char b[4]; /* Bytes from file */
+
+
+ fread(b, 4, 1, fp);
+ return ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
+}
+
+
+/*
+ * 'getshort()' - Get a 16-bit big-endian integer.
+ */
+
+static int /* O - Short value */
+getshort(FILE *fp) /* I - File to read from */
+{
+ unsigned char b[2]; /* Bytes from file */
+
+
+ fread(b, 2, 1, fp);
+ return ((b[0] << 8) | b[1]);
+}
+
+
+/*
+ * 'putlong()' - Put a 32-bit big-endian integer.
+ */
+
+static int /* O - 0 on success, -1 on error */
+putlong(long n, /* I - Long to write */
+ FILE *fp) /* I - File to write to */
+{
+ if (putc(n >> 24, fp) == EOF)
+ return (EOF);
+ if (putc(n >> 16, fp) == EOF)
+ return (EOF);
+ if (putc(n >> 8, fp) == EOF)
+ return (EOF);
+ if (putc(n, fp) == EOF)
+ return (EOF);
+ else
+ return (0);
+}
+
+
+/*
+ * 'putshort()' - Put a 16-bit big-endian integer.
+ */
+
+static int /* O - 0 on success, -1 on error */
+putshort(unsigned short n, /* I - Short to write */
+ FILE *fp) /* I - File to write to */
+{
+ if (putc(n >> 8, fp) == EOF)
+ return (EOF);
+ if (putc(n, fp) == EOF)
+ return (EOF);
+ else
+ return (0);
+}
+
+
+/*
+ * 'read_rle8()' - Read 8-bit RLE data.
+ */
+
+static int /* O - Value on success, -1 on error */
+read_rle8(FILE *fp, /* I - File to read from */
+ unsigned short *row, /* O - Data */
+ int xsize) /* I - Width of data in pixels */
+{
+ int i, /* Looping var */
+ ch, /* Current character */
+ count, /* RLE count */
+ length; /* Number of bytes read... */
+
+
+ length = 0;
+
+ while (xsize > 0)
+ {
+ if ((ch = getc(fp)) == EOF)
+ return (-1);
+ length ++;
+
+ count = ch & 127;
+ if (count == 0)
+ break;
+
+ if (ch & 128)
+ {
+ for (i = 0; i < count; i ++, row ++, xsize --, length ++)
+ if (xsize > 0)
+ *row = getc(fp);
+ }
+ else
+ {
+ ch = getc(fp);
+ length ++;
+ for (i = 0; i < count && xsize > 0; i ++, row ++, xsize --)
+ *row = ch;
+ }
+ }
+
+ return (xsize > 0 ? -1 : length);
+}
+
+
+/*
+ * 'read_rle16()' - Read 16-bit RLE data.
+ */
+
+static int /* O - Value on success, -1 on error */
+read_rle16(FILE *fp, /* I - File to read from */
+ unsigned short *row, /* O - Data */
+ int xsize) /* I - Width of data in pixels */
+{
+ int i, /* Looping var */
+ ch, /* Current character */
+ count, /* RLE count */
+ length; /* Number of bytes read... */
+
+
+ length = 0;
+
+ while (xsize > 0)
+ {
+ if ((ch = getshort(fp)) == EOF)
+ return (-1);
+ length ++;
+
+ count = ch & 127;
+ if (count == 0)
+ break;
+
+ if (ch & 128)
+ {
+ for (i = 0; i < count; i ++, row ++, xsize --, length ++)
+ if (xsize > 0)
+ *row = getshort(fp);
+ }
+ else
+ {
+ ch = getshort(fp);
+ length ++;
+ for (i = 0; i < count && xsize > 0; i ++, row ++, xsize --)
+ *row = ch;
+ }
+ }
+
+ return (xsize > 0 ? -1 : length * 2);
+}
+
+
+/*
+ * 'write_rle8()' - Write 8-bit RLE data.
+ */
+
+static int /* O - Length on success, -1 on error */
+write_rle8(FILE *fp, /* I - File to write to */
+ unsigned short *row, /* I - Data */
+ int xsize) /* I - Width of data in pixels */
+{
+ int length, /* Length in bytes */
+ count, /* Number of repeating pixels */
+ i, /* Looping var */
+ x; /* Current column */
+ unsigned short *start, /* Start of current sequence */
+ repeat; /* Repeated pixel */
+
+
+ for (x = xsize, length = 0; x > 0;)
+ {
+ start = row;
+ row += 2;
+ x -= 2;
+
+ while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
+ {
+ row ++;
+ x --;
+ }
+
+ row -= 2;
+ x += 2;
+
+ count = row - start;
+ while (count > 0)
+ {
+ i = count > 126 ? 126 : count;
+ count -= i;
+
+ if (putc(128 | i, fp) == EOF)
+ return (-1);
+ length ++;
+
+ while (i > 0)
+ {
+ if (putc(*start, fp) == EOF)
+ return (-1);
+ start ++;
+ i --;
+ length ++;
+ }
+ }
+
+ if (x <= 0)
+ break;
+
+ start = row;
+ repeat = row[0];
+
+ row ++;
+ x --;
+
+ while (x > 0 && *row == repeat)
+ {
+ row ++;
+ x --;
+ }
+
+ count = row - start;
+ while (count > 0)
+ {
+ i = count > 126 ? 126 : count;
+ count -= i;
+
+ if (putc(i, fp) == EOF)
+ return (-1);
+ length ++;
+
+ if (putc(repeat, fp) == EOF)
+ return (-1);
+ length ++;
+ }
+ }
+
+ length ++;
+
+ if (putc(0, fp) == EOF)
+ return (-1);
+ else
+ return (length);
+}
+
+
+/*
+ * 'write_rle16()' - Write 16-bit RLE data.
+ */
+
+static int /* O - Length in words */
+write_rle16(FILE *fp, /* I - File to write to */
+ unsigned short *row, /* I - Data */
+ int xsize) /* I - Width of data in pixels */
+{
+ int length, /* Length in words */
+ count, /* Number of repeating pixels */
+ i, /* Looping var */
+ x; /* Current column */
+ unsigned short *start, /* Start of current sequence */
+ repeat; /* Repeated pixel */
+
+
+ for (x = xsize, length = 0; x > 0;)
+ {
+ start = row;
+ row += 2;
+ x -= 2;
+
+ while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
+ {
+ row ++;
+ x --;
+ }
+
+ row -= 2;
+ x += 2;
+
+ count = row - start;
+ while (count > 0)
+ {
+ i = count > 126 ? 126 : count;
+ count -= i;
+
+ if (putshort(128 | i, fp) == EOF)
+ return (-1);
+ length ++;
+
+ while (i > 0)
+ {
+ if (putshort(*start, fp) == EOF)
+ return (-1);
+ start ++;
+ i --;
+ length ++;
+ }
+ }
+
+ if (x <= 0)
+ break;
+
+ start = row;
+ repeat = row[0];
+
+ row ++;
+ x --;
+
+ while (x > 0 && *row == repeat)
+ {
+ row ++;
+ x --;
+ }
+
+ count = row - start;
+ while (count > 0)
+ {
+ i = count > 126 ? 126 : count;
+ count -= i;
+
+ if (putshort(i, fp) == EOF)
+ return (-1);
+ length ++;
+
+ if (putshort(repeat, fp) == EOF)
+ return (-1);
+ length ++;
+ }
+ }
+
+ length ++;
+
+ if (putshort(0, fp) == EOF)
+ return (-1);
+ else
+ return (2 * length);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-sun.c b/filter/image-sun.c
new file mode 100644
index 000000000..9c4ca6a20
--- /dev/null
+++ b/filter/image-sun.c
@@ -0,0 +1,407 @@
+/*
+ * "$Id$"
+ *
+ * Sun Raster image file routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsImageReadSunRaster() - Read a SunRaster image file.
+ * read_unsigned() - Read a 32-bit unsigned integer.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+
+
+#define RAS_MAGIC 0x59a66a95
+
+ /* Sun supported ras_type's */
+#define RT_OLD 0 /* Raw pixrect image in 68000 byte order */
+#define RT_STANDARD 1 /* Raw pixrect image in 68000 byte order */
+#define RT_BYTE_ENCODED 2 /* Run-length compression of bytes */
+#define RT_FORMAT_RGB 3 /* XRGB or RGB instead of XBGR or BGR */
+#define RT_EXPERIMENTAL 0xffff /* Reserved for testing */
+
+ /* Sun registered ras_maptype's */
+#define RMT_RAW 2
+ /* Sun supported ras_maptype's */
+#define RMT_NONE 0 /* ras_maplength is expected to be 0 */
+#define RMT_EQUAL_RGB 1 /* red[ras_maplength/3],green[],blue[] */
+
+#define RAS_RLE 0x80
+
+/*
+ * NOTES:
+ * Each line of the image is rounded out to a multiple of 16 bits.
+ * This corresponds to the rounding convention used by the memory pixrect
+ * package (/usr/include/pixrect/memvar.h) of the SunWindows system.
+ * The ras_encoding field (always set to 0 by Sun's supported software)
+ * was renamed to ras_length in release 2.0. As a result, rasterfiles
+ * of type 0 generated by the old software claim to have 0 length; for
+ * compatibility, code reading rasterfiles must be prepared to compute the
+ * true length from the width, height, and depth fields.
+ */
+
+/*
+ * Local functions...
+ */
+
+static unsigned read_unsigned(FILE *fp);
+
+
+/*
+ * '_cupsImageReadSunRaster()' - Read a SunRaster image file.
+ */
+
+int /* O - Read status */
+_cupsImageReadSunRaster(
+ cups_image_t *img, /* IO - cupsImage */
+ FILE *fp, /* I - cupsImage file */
+ cups_icspace_t primary, /* I - Primary choice for colorspace */
+ cups_icspace_t secondary, /* I - Secondary choice for colorspace */
+ int saturation, /* I - Color saturation (%) */
+ int hue, /* I - Color hue (degrees) */
+ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */
+{
+ int i, x, y,
+ bpp, /* Bytes per pixel */
+ scanwidth,
+ run_count,
+ run_value;
+ cups_ib_t *in,
+ *out,
+ *scanline,
+ *scanptr,
+ *p,
+ bit;
+ unsigned ras_depth, /* depth (1, 8, or 24 bits) of pixel */
+ ras_type, /* type of file; see RT_* below */
+ ras_maplength; /* length (bytes) of following map */
+ unsigned char cmap[3][256]; /* colormap */
+
+
+ /*
+ * Read the header; we already know that this is a raster file (cupsImageOpen
+ * checks this) so we don't need to check the magic number again.
+ */
+
+ fputs("DEBUG: Reading Sun Raster image...\n", stderr);
+
+ read_unsigned(fp); /* Skip magic */
+ img->xsize = read_unsigned(fp);
+ img->ysize = read_unsigned(fp);
+ ras_depth = read_unsigned(fp);
+ /* ras_length */read_unsigned(fp);
+ ras_type = read_unsigned(fp);
+ /* ras_maptype*/read_unsigned(fp);
+ ras_maplength = read_unsigned(fp);
+
+ fprintf(stderr, "DEBUG: ras_width=%d, ras_height=%d, ras_depth=%d, ras_type=%d, ras_maplength=%d\n",
+ img->xsize, img->ysize, ras_depth, ras_type, ras_maplength);
+
+ if (ras_maplength > 768 ||
+ img->xsize == 0 || img->xsize > CUPS_IMAGE_MAX_WIDTH ||
+ img->ysize == 0 || img->ysize > CUPS_IMAGE_MAX_HEIGHT ||
+ ras_depth == 0 || ras_depth > 32)
+ {
+ fputs("DEBUG: Raster image cannot be loaded!\n", stderr);
+ return (1);
+ }
+
+ if (ras_maplength > 0)
+ {
+ memset(cmap[0], 255, sizeof(cmap[0]));
+ memset(cmap[1], 0, sizeof(cmap[1]));
+ memset(cmap[2], 0, sizeof(cmap[2]));
+
+ fread(cmap[0], 1, ras_maplength / 3, fp);
+ fread(cmap[1], 1, ras_maplength / 3, fp);
+ fread(cmap[2], 1, ras_maplength / 3, fp);
+ }
+
+ /*
+ * Compute the width of each line and allocate memory as needed...
+ */
+
+ scanwidth = (img->xsize * ras_depth + 7) / 8;
+ if (scanwidth & 1)
+ scanwidth ++;
+
+ if (ras_depth < 24 && ras_maplength == 0)
+ {
+ img->colorspace = secondary;
+ in = malloc(img->xsize + 1);
+ }
+ else
+ {
+ img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary;
+ in = malloc(img->xsize * 3 + 1);
+ }
+
+ if (!in)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ fclose(fp);
+ return (1);
+ }
+
+ bpp = cupsImageGetDepth(img);
+
+ if ((out = malloc(img->xsize * bpp)) == NULL)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ fclose(fp);
+ free(in);
+ return (1);
+ }
+
+ if ((scanline = malloc(scanwidth)) == NULL)
+ {
+ fputs("DEBUG: Unable to allocate memory!\n", stderr);
+ fclose(fp);
+ free(in);
+ free(out);
+ return (1);
+ }
+
+ run_count = 0;
+ run_value = 0;
+
+ fprintf(stderr, "DEBUG: bpp=%d, scanwidth=%d\n", bpp, scanwidth);
+
+ for (y = 0; y < img->ysize; y ++)
+ {
+ if ((ras_depth != 8 && ras_depth != 24) || ras_maplength > 0)
+ p = scanline;
+ else
+ p = in;
+
+ if (ras_type != RT_BYTE_ENCODED)
+ fread(p, scanwidth, 1, fp);
+ else
+ {
+ for (i = scanwidth; i > 0; i --, p ++)
+ {
+ if (run_count > 0)
+ {
+ *p = run_value;
+ run_count --;
+ }
+ else
+ {
+ run_value = getc(fp);
+
+ if (run_value == RAS_RLE)
+ {
+ run_count = getc(fp);
+ if (run_count == 0)
+ *p = RAS_RLE;
+ else
+ run_value = *p = getc(fp);
+ }
+ else
+ *p = run_value;
+ }
+ }
+ }
+
+ if (ras_depth == 1 && ras_maplength == 0)
+ {
+ /*
+ * 1-bit B&W image...
+ */
+
+ for (x = img->xsize, bit = 128, scanptr = scanline, p = in;
+ x > 0;
+ x --, p ++)
+ {
+ if (*scanptr & bit)
+ *p = 255;
+ else
+ *p = 0;
+
+ if (bit > 1)
+ bit >>= 1;
+ else
+ {
+ bit = 128;
+ scanptr ++;
+ }
+ }
+ }
+ else if (ras_depth == 1)
+ {
+ /*
+ * 1-bit colormapped image...
+ */
+
+ for (x = img->xsize, bit = 128, scanptr = scanline, p = in;
+ x > 0;
+ x --)
+ {
+ if (*scanptr & bit)
+ {
+ *p++ = cmap[0][1];
+ *p++ = cmap[1][1];
+ *p++ = cmap[2][1];
+ }
+ else
+ {
+ *p++ = cmap[0][0];
+ *p++ = cmap[1][0];
+ *p++ = cmap[2][0];
+ }
+
+ if (bit > 1)
+ bit >>= 1;
+ else
+ {
+ bit = 128;
+ scanptr ++;
+ }
+ }
+ }
+ else if (ras_depth == 8 && ras_maplength > 0)
+ {
+ /*
+ * 8-bit colormapped image.
+ */
+
+ for (x = img->xsize, scanptr = scanline, p = in;
+ x > 0;
+ x --)
+ {
+ *p++ = cmap[0][*scanptr];
+ *p++ = cmap[1][*scanptr];
+ *p++ = cmap[2][*scanptr++];
+ }
+ }
+ else if (ras_depth == 24 && ras_type != RT_FORMAT_RGB)
+ {
+ /*
+ * Convert BGR to RGB...
+ */
+
+ for (x = img->xsize, scanptr = scanline, p = in;
+ x > 0;
+ x --, scanptr += 3)
+ {
+ *p++ = scanptr[2];
+ *p++ = scanptr[1];
+ *p++ = scanptr[0];
+ }
+ }
+
+ if (ras_depth <= 8 && ras_maplength == 0)
+ {
+ if (img->colorspace == CUPS_IMAGE_WHITE)
+ {
+ if (lut)
+ cupsImageLut(in, img->xsize, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, in);
+ }
+ else
+ {
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_RGB :
+ cupsImageWhiteToRGB(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageWhiteToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageWhiteToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageWhiteToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * bpp, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, out);
+ }
+ }
+ else
+ {
+ if ((saturation != 100 || hue != 0) && bpp > 1)
+ cupsImageRGBAdjust(in, img->xsize, saturation, hue);
+
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_WHITE :
+ cupsImageRGBToWhite(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageRGBToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageRGBToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageRGBToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * bpp, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, out);
+ }
+ }
+
+ free(scanline);
+ free(in);
+ free(out);
+
+ fclose(fp);
+
+ return (0);
+}
+
+
+/*
+ * 'read_unsigned()' - Read a 32-bit unsigned integer.
+ */
+
+static unsigned /* O - Integer from file */
+read_unsigned(FILE *fp) /* I - File to read from */
+{
+ unsigned v; /* Integer from file */
+
+
+ v = getc(fp);
+ v = (v << 8) | getc(fp);
+ v = (v << 8) | getc(fp);
+ v = (v << 8) | getc(fp);
+
+ return (v);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-tiff.c b/filter/image-tiff.c
new file mode 100644
index 000000000..3c5c5dd18
--- /dev/null
+++ b/filter/image-tiff.c
@@ -0,0 +1,1715 @@
+/*
+ * "$Id$"
+ *
+ * TIFF file routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsImageReadTIFF() - Read a TIFF image file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+
+#ifdef HAVE_LIBTIFF
+# include <tiff.h> /* TIFF image definitions */
+# include <tiffio.h>
+# include <unistd.h>
+
+
+/*
+ * '_cupsImageReadTIFF()' - Read a TIFF image file.
+ */
+
+int /* O - Read status */
+_cupsImageReadTIFF(
+ cups_image_t *img, /* IO - cupsImage */
+ FILE *fp, /* I - cupsImage file */
+ cups_icspace_t primary, /* I - Primary choice for colorspace */
+ cups_icspace_t secondary, /* I - Secondary choice for colorspace */
+ int saturation, /* I - Color saturation (%) */
+ int hue, /* I - Color hue (degrees) */
+ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */
+{
+ TIFF *tif; /* TIFF file */
+ uint32 width, height; /* Size of image */
+ uint16 photometric, /* Colorspace */
+ compression, /* Type of compression */
+ orientation, /* Orientation */
+ resunit, /* Units for resolution */
+ samples, /* Number of samples/pixel */
+ bits, /* Number of bits/pixel */
+ inkset, /* Ink set for color separations */
+ numinks; /* Number of inks in set */
+ float xres, /* Horizontal resolution */
+ yres; /* Vertical resolution */
+ uint16 *redcmap, /* Red colormap information */
+ *greencmap, /* Green colormap information */
+ *bluecmap; /* Blue colormap information */
+ int c, /* Color index */
+ num_colors, /* Number of colors */
+ bpp, /* Bytes per pixel */
+ x, y, /* Current x & y */
+ row, /* Current row in image */
+ xstart, ystart, /* Starting x & y */
+ xdir, ydir, /* X & y direction */
+ xcount, ycount, /* X & Y counters */
+ pstep, /* Pixel step (= bpp or -2 * bpp) */
+ scanwidth, /* Width of scanline */
+ r, g, b, k, /* Red, green, blue, and black values */
+ alpha; /* cupsImage includes alpha? */
+ cups_ib_t *in, /* Input buffer */
+ *out, /* Output buffer */
+ *p, /* Pointer into buffer */
+ *scanline, /* Scanline buffer */
+ *scanptr, /* Pointer into scanline buffer */
+ bit, /* Current bit */
+ pixel, /* Current pixel */
+ zero, /* Zero value (bitmaps) */
+ one; /* One value (bitmaps) */
+
+
+ /*
+ * Open the TIFF file and get the required parameters...
+ */
+
+ lseek(fileno(fp), 0, SEEK_SET); /* Work around "feature" in some stdio's */
+
+ if ((tif = TIFFFdOpen(fileno(fp), "", "r")) == NULL)
+ {
+ fputs("DEBUG: TIFFFdOpen() failed!\n", stderr);
+ fclose(fp);
+ return (-1);
+ }
+
+ if (!TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width))
+ {
+ fputs("DEBUG: No image width tag in the file!\n", stderr);
+ TIFFClose(tif);
+ fclose(fp);
+ return (-1);
+ }
+
+ if (!TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))
+ {
+ fputs("DEBUG: No image height tag in the file!\n", stderr);
+ TIFFClose(tif);
+ fclose(fp);
+ return (-1);
+ }
+
+ if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric))
+ {
+ fputs("DEBUG: No photometric tag in the file!\n", stderr);
+ TIFFClose(tif);
+ fclose(fp);
+ return (-1);
+ }
+
+ if (!TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression))
+ {
+ fputs("DEBUG: No compression tag in the file!\n", stderr);
+ TIFFClose(tif);
+ fclose(fp);
+ return (-1);
+ }
+
+ if (!TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samples))
+ samples = 1;
+
+ if (!TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bits))
+ bits = 1;
+
+ /*
+ * Get the image orientation...
+ */
+
+ if (!TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation))
+ orientation = 0;
+
+ /*
+ * Get the image resolution...
+ */
+
+ if (TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres) &&
+ TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres) &&
+ TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resunit))
+ {
+ if (resunit == RESUNIT_INCH)
+ {
+ img->xppi = xres;
+ img->yppi = yres;
+ }
+ else if (resunit == RESUNIT_CENTIMETER)
+ {
+ img->xppi = xres * 2.54;
+ img->yppi = yres * 2.54;
+ }
+ else
+ {
+ img->xppi = 128;
+ img->yppi = 128;
+ }
+
+ if (img->xppi == 0 || img->yppi == 0)
+ {
+ fputs("DEBUG: Bad TIFF resolution.\n", stderr);
+ img->xppi = img->yppi = 128;
+ }
+
+ fprintf(stderr, "DEBUG: TIFF resolution = %fx%f, units=%d\n",
+ xres, yres, resunit);
+ fprintf(stderr, "DEBUG: Stored resolution = %dx%d PPI\n",
+ img->xppi, img->yppi);
+ }
+
+ /*
+ * See if the image has an alpha channel...
+ */
+
+ if (samples == 2 || (samples == 4 && photometric == PHOTOMETRIC_RGB))
+ alpha = 1;
+ else
+ alpha = 0;
+
+ /*
+ * Check the size of the image...
+ */
+
+ if (width == 0 || width > CUPS_IMAGE_MAX_WIDTH ||
+ height == 0 || height > CUPS_IMAGE_MAX_HEIGHT ||
+ (bits != 1 && bits != 2 && bits != 4 && bits != 8) ||
+ samples < 1 || samples > 4)
+ {
+ fprintf(stderr, "DEBUG: Bad TIFF dimensions %ux%ux%ux%u!\n",
+ (unsigned)width, (unsigned)height, (unsigned)bits,
+ (unsigned)samples);
+ TIFFClose(tif);
+ fclose(fp);
+ return (1);
+ }
+
+ /*
+ * Setup the image size and colorspace...
+ */
+
+ img->xsize = width;
+ img->ysize = height;
+ if (photometric == PHOTOMETRIC_MINISBLACK ||
+ photometric == PHOTOMETRIC_MINISWHITE)
+ img->colorspace = secondary;
+ else if (photometric == PHOTOMETRIC_SEPARATED && primary == CUPS_IMAGE_RGB_CMYK)
+ img->colorspace = CUPS_IMAGE_CMYK;
+ else if (primary == CUPS_IMAGE_RGB_CMYK)
+ img->colorspace = CUPS_IMAGE_RGB;
+ else
+ img->colorspace = primary;
+
+ fprintf(stderr, "DEBUG: img->colorspace = %d\n", img->colorspace);
+
+ bpp = cupsImageGetDepth(img);
+
+ cupsImageSetMaxTiles(img, 0);
+
+ /*
+ * Set the X & Y start and direction according to the image orientation...
+ */
+
+ switch (orientation)
+ {
+ case ORIENTATION_TOPRIGHT :
+ fputs("DEBUG: orientation = top-right\n", stderr);
+ break;
+ case ORIENTATION_RIGHTTOP :
+ fputs("DEBUG: orientation = right-top\n", stderr);
+ break;
+ default :
+ case ORIENTATION_TOPLEFT :
+ fputs("DEBUG: orientation = top-left\n", stderr);
+ break;
+ case ORIENTATION_LEFTTOP :
+ fputs("DEBUG: orientation = left-top\n", stderr);
+ break;
+ case ORIENTATION_BOTLEFT :
+ fputs("DEBUG: orientation = bottom-left\n", stderr);
+ break;
+ case ORIENTATION_LEFTBOT :
+ fputs("DEBUG: orientation = left-bottom\n", stderr);
+ break;
+ case ORIENTATION_BOTRIGHT :
+ fputs("DEBUG: orientation = bottom-right\n", stderr);
+ break;
+ case ORIENTATION_RIGHTBOT :
+ fputs("DEBUG: orientation = right-bottom\n", stderr);
+ break;
+ }
+
+ switch (orientation)
+ {
+ case ORIENTATION_TOPRIGHT :
+ case ORIENTATION_RIGHTTOP :
+ xstart = img->xsize - 1;
+ xdir = -1;
+ ystart = 0;
+ ydir = 1;
+ break;
+ default :
+ case ORIENTATION_TOPLEFT :
+ case ORIENTATION_LEFTTOP :
+ xstart = 0;
+ xdir = 1;
+ ystart = 0;
+ ydir = 1;
+ break;
+ case ORIENTATION_BOTLEFT :
+ case ORIENTATION_LEFTBOT :
+ xstart = 0;
+ xdir = 1;
+ ystart = img->ysize - 1;
+ ydir = -1;
+ break;
+ case ORIENTATION_BOTRIGHT :
+ case ORIENTATION_RIGHTBOT :
+ xstart = img->xsize - 1;
+ xdir = -1;
+ ystart = img->ysize - 1;
+ ydir = -1;
+ break;
+ }
+
+ /*
+ * Allocate a scanline buffer...
+ */
+
+ scanwidth = TIFFScanlineSize(tif);
+ scanline = _TIFFmalloc(scanwidth);
+
+ /*
+ * Allocate input and output buffers...
+ */
+
+ if (orientation < ORIENTATION_LEFTTOP)
+ {
+ if (samples > 1 || photometric == PHOTOMETRIC_PALETTE)
+ pstep = xdir * 3;
+ else
+ pstep = xdir;
+
+ in = malloc(img->xsize * 3 + 3);
+ out = malloc(img->xsize * bpp);
+ }
+ else
+ {
+ if (samples > 1 || photometric == PHOTOMETRIC_PALETTE)
+ pstep = ydir * 3;
+ else
+ pstep = ydir;
+
+ in = malloc(img->ysize * 3 + 3);
+ out = malloc(img->ysize * bpp);
+ }
+
+ /*
+ * Read the image. This is greatly complicated by the fact that TIFF
+ * supports literally hundreds of different colorspaces and orientations,
+ * each which must be handled separately...
+ */
+
+ fprintf(stderr, "DEBUG: photometric = %d\n", photometric);
+ fprintf(stderr, "DEBUG: compression = %d\n", compression);
+
+ switch (photometric)
+ {
+ case PHOTOMETRIC_MINISWHITE :
+ case PHOTOMETRIC_MINISBLACK :
+ if (photometric == PHOTOMETRIC_MINISWHITE)
+ {
+ zero = 255;
+ one = 0;
+ }
+ else
+ {
+ zero = 0;
+ one = 255;
+ }
+
+ if (orientation < ORIENTATION_LEFTTOP)
+ {
+ /*
+ * Row major order...
+ */
+
+ for (y = ystart, ycount = img->ysize, row = 0;
+ ycount > 0;
+ ycount --, y += ydir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (xcount = img->xsize, scanptr = scanline, p = in + xstart, bit = 128;
+ xcount > 0;
+ xcount --, p += pstep)
+ {
+ if (*scanptr & bit)
+ *p = one;
+ else
+ *p = zero;
+
+ if (bit > 1)
+ bit >>= 1;
+ else
+ {
+ bit = 128;
+ scanptr ++;
+ }
+ }
+ }
+ else if (bits == 2)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (xcount = img->xsize, scanptr = scanline, p = in + xstart, bit = 0xc0;
+ xcount > 0;
+ xcount --, p += pstep)
+ {
+ pixel = *scanptr & bit;
+ while (pixel > 3)
+ pixel >>= 2;
+ *p = (255 * pixel / 3) ^ zero;
+
+ if (bit > 3)
+ bit >>= 2;
+ else
+ {
+ bit = 0xc0;
+ scanptr ++;
+ }
+ }
+ }
+ else if (bits == 4)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (xcount = img->xsize, scanptr = scanline, p = in + xstart, bit = 0xf0;
+ xcount > 0;
+ xcount --, p += pstep)
+ {
+ if (bit == 0xf0)
+ {
+ *p = (255 * ((*scanptr & 0xf0) >> 4) / 15) ^ zero;
+ bit = 0x0f;
+ }
+ else
+ {
+ *p = (255 * (*scanptr & 0x0f) / 15) ^ zero;
+ bit = 0xf0;
+ scanptr ++;
+ }
+ }
+ }
+ else if (xdir < 0 || zero || alpha)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+
+ if (alpha)
+ {
+ if (zero)
+ {
+ for (xcount = img->xsize, p = in + xstart, scanptr = scanline;
+ xcount > 0;
+ xcount --, p += pstep, scanptr += 2)
+ *p = (scanptr[1] * (255 - scanptr[0]) +
+ (255 - scanptr[1]) * 255) / 255;
+ }
+ else
+ {
+ for (xcount = img->xsize, p = in + xstart, scanptr = scanline;
+ xcount > 0;
+ xcount --, p += pstep, scanptr += 2)
+ *p = (scanptr[1] * scanptr[0] +
+ (255 - scanptr[1]) * 255) / 255;
+ }
+ }
+ else
+ {
+ if (zero)
+ {
+ for (xcount = img->xsize, p = in + xstart, scanptr = scanline;
+ xcount > 0;
+ xcount --, p += pstep, scanptr ++)
+ *p = 255 - *scanptr;
+ }
+ else
+ {
+ for (xcount = img->xsize, p = in + xstart, scanptr = scanline;
+ xcount > 0;
+ xcount --, p += pstep, scanptr ++)
+ *p = *scanptr;
+ }
+ }
+ }
+ else
+ TIFFReadScanline(tif, in, row, 0);
+
+ if (img->colorspace == CUPS_IMAGE_WHITE)
+ {
+ if (lut)
+ cupsImageLut(in, img->xsize, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, in);
+ }
+ else
+ {
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_RGB :
+ cupsImageWhiteToRGB(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageWhiteToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageWhiteToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageWhiteToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * bpp, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, out);
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Column major order...
+ */
+
+ for (x = xstart, xcount = img->xsize, row = 0;
+ xcount > 0;
+ xcount --, x += xdir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (ycount = img->ysize, scanptr = scanline, p = in + ystart, bit = 128;
+ ycount > 0;
+ ycount --, p += ydir)
+ {
+ if (*scanptr & bit)
+ *p = one;
+ else
+ *p = zero;
+
+ if (bit > 1)
+ bit >>= 1;
+ else
+ {
+ bit = 128;
+ scanptr ++;
+ }
+ }
+ }
+ else if (bits == 2)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (ycount = img->ysize, scanptr = scanline, p = in + ystart, bit = 0xc0;
+ ycount > 0;
+ ycount --, p += ydir)
+ {
+ pixel = *scanptr & 0xc0;
+ while (pixel > 3)
+ pixel >>= 2;
+
+ *p = (255 * pixel / 3) ^ zero;
+
+ if (bit > 3)
+ bit >>= 2;
+ else
+ {
+ bit = 0xc0;
+ scanptr ++;
+ }
+ }
+ }
+ else if (bits == 4)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (ycount = img->ysize, scanptr = scanline, p = in + ystart, bit = 0xf0;
+ ycount > 0;
+ ycount --, p += ydir)
+ {
+ if (bit == 0xf0)
+ {
+ *p = (255 * ((*scanptr & 0xf0) >> 4) / 15) ^ zero;
+ bit = 0x0f;
+ }
+ else
+ {
+ *p = (255 * (*scanptr & 0x0f) / 15) ^ zero;
+ bit = 0xf0;
+ scanptr ++;
+ }
+ }
+ }
+ else if (ydir < 0 || zero || alpha)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+
+ if (alpha)
+ {
+ if (zero)
+ {
+ for (ycount = img->ysize, p = in + ystart, scanptr = scanline;
+ ycount > 0;
+ ycount --, p += ydir, scanptr += 2)
+ *p = (scanptr[1] * (255 - scanptr[0]) +
+ (255 - scanptr[1]) * 255) / 255;
+ }
+ else
+ {
+ for (ycount = img->ysize, p = in + ystart, scanptr = scanline;
+ ycount > 0;
+ ycount --, p += ydir, scanptr += 2)
+ *p = (scanptr[1] * scanptr[0] +
+ (255 - scanptr[1]) * 255) / 255;
+ }
+ }
+ else
+ {
+ if (zero)
+ {
+ for (ycount = img->ysize, p = in + ystart, scanptr = scanline;
+ ycount > 0;
+ ycount --, p += ydir, scanptr ++)
+ *p = 255 - *scanptr;
+ }
+ else
+ {
+ for (ycount = img->ysize, p = in + ystart, scanptr = scanline;
+ ycount > 0;
+ ycount --, p += ydir, scanptr ++)
+ *p = *scanptr;
+ }
+ }
+ }
+ else
+ TIFFReadScanline(tif, in, row, 0);
+
+ if (img->colorspace == CUPS_IMAGE_WHITE)
+ {
+ if (lut)
+ cupsImageLut(in, img->ysize, lut);
+
+ _cupsImagePutCol(img, x, 0, img->ysize, in);
+ }
+ else
+ {
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_RGB :
+ cupsImageWhiteToRGB(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageWhiteToBlack(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageWhiteToCMY(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageWhiteToCMYK(in, out, img->ysize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->ysize * bpp, lut);
+
+ _cupsImagePutCol(img, x, 0, img->ysize, out);
+ }
+ }
+ }
+ break;
+
+ case PHOTOMETRIC_PALETTE :
+ if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &redcmap, &greencmap, &bluecmap))
+ {
+ fputs("DEBUG: No colormap tag in the file!\n", stderr);
+ fclose(fp);
+ return (-1);
+ }
+
+ num_colors = 1 << bits;
+
+ for (c = 0; c < num_colors; c ++)
+ {
+ redcmap[c] >>= 8;
+ greencmap[c] >>= 8;
+ bluecmap[c] >>= 8;
+ }
+
+ if (orientation < ORIENTATION_LEFTTOP)
+ {
+ /*
+ * Row major order...
+ */
+
+ for (y = ystart, ycount = img->ysize, row = 0;
+ ycount > 0;
+ ycount --, y += ydir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (xcount = img->xsize, scanptr = scanline,
+ p = in + xstart * 3, bit = 128;
+ xcount > 0;
+ xcount --, p += pstep)
+ {
+ if (*scanptr & bit)
+ {
+ p[0] = redcmap[1];
+ p[1] = greencmap[1];
+ p[2] = bluecmap[1];
+ }
+ else
+ {
+ p[0] = redcmap[0];
+ p[1] = greencmap[0];
+ p[2] = bluecmap[0];
+ }
+
+ if (bit > 1)
+ bit >>= 1;
+ else
+ {
+ bit = 128;
+ scanptr ++;
+ }
+ }
+ }
+ else if (bits == 2)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (xcount = img->xsize, scanptr = scanline,
+ p = in + xstart * 3, bit = 0xc0;
+ xcount > 0;
+ xcount --, p += pstep)
+ {
+ pixel = *scanptr & bit;
+ while (pixel > 3)
+ pixel >>= 2;
+
+ p[0] = redcmap[pixel];
+ p[1] = greencmap[pixel];
+ p[2] = bluecmap[pixel];
+
+ if (bit > 3)
+ bit >>= 2;
+ else
+ {
+ bit = 0xc0;
+ scanptr ++;
+ }
+ }
+ }
+ else if (bits == 4)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (xcount = img->xsize, scanptr = scanline,
+ p = in + 3 * xstart, bit = 0xf0;
+ xcount > 0;
+ xcount --, p += pstep)
+ {
+ if (bit == 0xf0)
+ {
+ pixel = (*scanptr & 0xf0) >> 4;
+ p[0] = redcmap[pixel];
+ p[1] = greencmap[pixel];
+ p[2] = bluecmap[pixel];
+ bit = 0x0f;
+ }
+ else
+ {
+ pixel = *scanptr++ & 0x0f;
+ p[0] = redcmap[pixel];
+ p[1] = greencmap[pixel];
+ p[2] = bluecmap[pixel];
+ bit = 0xf0;
+ }
+ }
+ }
+ else
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+
+ for (xcount = img->xsize, p = in + 3 * xstart, scanptr = scanline;
+ xcount > 0;
+ xcount --, p += pstep)
+ {
+ p[0] = redcmap[*scanptr];
+ p[1] = greencmap[*scanptr];
+ p[2] = bluecmap[*scanptr++];
+ }
+ }
+
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_WHITE :
+ cupsImageRGBToWhite(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_RGB :
+ cupsImageRGBToRGB(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageRGBToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageRGBToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageRGBToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * bpp, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, out);
+ }
+ }
+ else
+ {
+ /*
+ * Column major order...
+ */
+
+ for (x = xstart, xcount = img->xsize, row = 0;
+ xcount > 0;
+ xcount --, x += xdir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (ycount = img->ysize, scanptr = scanline,
+ p = in + 3 * ystart, bit = 128;
+ ycount > 0;
+ ycount --, p += ydir)
+ {
+ if (*scanptr & bit)
+ {
+ p[0] = redcmap[1];
+ p[1] = greencmap[1];
+ p[2] = bluecmap[1];
+ }
+ else
+ {
+ p[0] = redcmap[0];
+ p[1] = greencmap[0];
+ p[2] = bluecmap[0];
+ }
+
+ if (bit > 1)
+ bit >>= 1;
+ else
+ {
+ bit = 128;
+ scanptr ++;
+ }
+ }
+ }
+ else if (bits == 2)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (ycount = img->ysize, scanptr = scanline,
+ p = in + 3 * ystart, bit = 0xc0;
+ ycount > 0;
+ ycount --, p += ydir)
+ {
+ pixel = *scanptr & 0xc0;
+ while (pixel > 3)
+ pixel >>= 2;
+
+ p[0] = redcmap[pixel];
+ p[1] = greencmap[pixel];
+ p[2] = bluecmap[pixel];
+
+ if (bit > 3)
+ bit >>= 2;
+ else
+ {
+ bit = 0xc0;
+ scanptr ++;
+ }
+ }
+ }
+ else if (bits == 4)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (ycount = img->ysize, scanptr = scanline,
+ p = in + 3 * ystart, bit = 0xf0;
+ ycount > 0;
+ ycount --, p += ydir)
+ {
+ if (bit == 0xf0)
+ {
+ pixel = (*scanptr & 0xf0) >> 4;
+ p[0] = redcmap[pixel];
+ p[1] = greencmap[pixel];
+ p[2] = bluecmap[pixel];
+ bit = 0x0f;
+ }
+ else
+ {
+ pixel = *scanptr++ & 0x0f;
+ p[0] = redcmap[pixel];
+ p[1] = greencmap[pixel];
+ p[2] = bluecmap[pixel];
+ bit = 0xf0;
+ }
+ }
+ }
+ else
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+
+ for (ycount = img->ysize, p = in + 3 * ystart, scanptr = scanline;
+ ycount > 0;
+ ycount --, p += ydir)
+ {
+ p[0] = redcmap[*scanptr];
+ p[1] = greencmap[*scanptr];
+ p[2] = bluecmap[*scanptr++];
+ }
+ }
+
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_WHITE :
+ cupsImageRGBToWhite(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_RGB :
+ cupsImageRGBToRGB(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageRGBToBlack(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageRGBToCMY(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageRGBToCMYK(in, out, img->ysize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->ysize * bpp, lut);
+
+ _cupsImagePutCol(img, x, 0, img->ysize, out);
+ }
+ }
+ break;
+
+ case PHOTOMETRIC_RGB :
+ if (orientation < ORIENTATION_LEFTTOP)
+ {
+ /*
+ * Row major order...
+ */
+
+ for (y = ystart, ycount = img->ysize, row = 0;
+ ycount > 0;
+ ycount --, y += ydir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (xcount = img->xsize, scanptr = scanline, p = in + xstart * 3, bit = 0xf0;
+ xcount > 0;
+ xcount --, p += pstep)
+ {
+ if (*scanptr & bit & 0x88)
+ p[0] = 255;
+ else
+ p[0] = 0;
+
+ if (*scanptr & bit & 0x44)
+ p[1] = 255;
+ else
+ p[1] = 0;
+
+ if (*scanptr & bit & 0x22)
+ p[2] = 255;
+ else
+ p[2] = 0;
+
+ if (bit == 0xf0)
+ bit = 0x0f;
+ else
+ {
+ bit = 0xf0;
+ scanptr ++;
+ }
+ }
+ }
+ else if (bits == 2)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (xcount = img->xsize, scanptr = scanline, p = in + xstart * 3;
+ xcount > 0;
+ xcount --, p += pstep, scanptr ++)
+ {
+ pixel = *scanptr >> 2;
+ p[0] = 255 * (pixel & 3) / 3;
+ pixel >>= 2;
+ p[1] = 255 * (pixel & 3) / 3;
+ pixel >>= 2;
+ p[2] = 255 * (pixel & 3) / 3;
+ }
+ }
+ else if (bits == 4)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (xcount = img->xsize, scanptr = scanline, p = in + xstart * 3;
+ xcount > 0;
+ xcount -= 2, p += 2 * pstep, scanptr += 3)
+ {
+ pixel = scanptr[0];
+ p[1] = 255 * (pixel & 15) / 15;
+ pixel >>= 4;
+ p[0] = 255 * (pixel & 15) / 15;
+ pixel = scanptr[1];
+ p[2] = 255 * ((pixel >> 4) & 15) / 15;
+
+ if (xcount > 1)
+ {
+ p[pstep + 0] = 255 * (pixel & 15) / 15;
+ pixel = scanptr[2];
+ p[pstep + 2] = 255 * (pixel & 15) / 15;
+ pixel >>= 4;
+ p[pstep + 1] = 255 * (pixel & 15) / 15;
+ }
+ }
+ }
+ else if (xdir < 0 || alpha)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+
+ if (alpha)
+ {
+ for (xcount = img->xsize, p = in + xstart * 3, scanptr = scanline;
+ xcount > 0;
+ xcount --, p += pstep, scanptr += 4)
+ {
+ p[0] = (scanptr[0] * scanptr[3] + 255 * (255 - scanptr[3])) / 255;
+ p[1] = (scanptr[1] * scanptr[3] + 255 * (255 - scanptr[3])) / 255;
+ p[2] = (scanptr[2] * scanptr[3] + 255 * (255 - scanptr[3])) / 255;
+ }
+ }
+ else
+ {
+ for (xcount = img->xsize, p = in + xstart * 3, scanptr = scanline;
+ xcount > 0;
+ xcount --, p += pstep, scanptr += 3)
+ {
+ p[0] = scanptr[0];
+ p[1] = scanptr[1];
+ p[2] = scanptr[2];
+ }
+ }
+ }
+ else
+ TIFFReadScanline(tif, in, row, 0);
+
+ if ((saturation != 100 || hue != 0) && bpp > 1)
+ cupsImageRGBAdjust(in, img->xsize, saturation, hue);
+
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_WHITE :
+ cupsImageRGBToWhite(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_RGB :
+ cupsImageRGBToRGB(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageRGBToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageRGBToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageRGBToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * bpp, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, out);
+ }
+ }
+ else
+ {
+ /*
+ * Column major order...
+ */
+
+ for (x = xstart, xcount = img->xsize, row = 0;
+ xcount > 0;
+ xcount --, x += xdir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (ycount = img->ysize, scanptr = scanline, p = in + ystart * 3, bit = 0xf0;
+ ycount > 0;
+ ycount --, p += pstep)
+ {
+ if (*scanptr & bit & 0x88)
+ p[0] = 255;
+ else
+ p[0] = 0;
+
+ if (*scanptr & bit & 0x44)
+ p[1] = 255;
+ else
+ p[1] = 0;
+
+ if (*scanptr & bit & 0x22)
+ p[2] = 255;
+ else
+ p[2] = 0;
+
+ if (bit == 0xf0)
+ bit = 0x0f;
+ else
+ {
+ bit = 0xf0;
+ scanptr ++;
+ }
+ }
+ }
+ else if (bits == 2)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (ycount = img->ysize, scanptr = scanline, p = in + ystart * 3;
+ ycount > 0;
+ ycount --, p += pstep, scanptr ++)
+ {
+ pixel = *scanptr >> 2;
+ p[0] = 255 * (pixel & 3) / 3;
+ pixel >>= 2;
+ p[1] = 255 * (pixel & 3) / 3;
+ pixel >>= 2;
+ p[2] = 255 * (pixel & 3) / 3;
+ }
+ }
+ else if (bits == 4)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (ycount = img->ysize, scanptr = scanline, p = in + ystart * 3;
+ ycount > 0;
+ ycount -= 2, p += 2 * pstep, scanptr += 3)
+ {
+ pixel = scanptr[0];
+ p[1] = 255 * (pixel & 15) / 15;
+ pixel >>= 4;
+ p[0] = 255 * (pixel & 15) / 15;
+ pixel = scanptr[1];
+ p[2] = 255 * ((pixel >> 4) & 15) / 15;
+
+ if (ycount > 1)
+ {
+ p[pstep + 0] = 255 * (pixel & 15) / 15;
+ pixel = scanptr[2];
+ p[pstep + 2] = 255 * (pixel & 15) / 15;
+ pixel >>= 4;
+ p[pstep + 1] = 255 * (pixel & 15) / 15;
+ }
+ }
+ }
+ else if (ydir < 0 || alpha)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+
+ if (alpha)
+ {
+ for (ycount = img->ysize, p = in + ystart * 3, scanptr = scanline;
+ ycount > 0;
+ ycount --, p += pstep, scanptr += 4)
+ {
+ p[0] = (scanptr[0] * scanptr[3] + 255 * (255 - scanptr[3])) / 255;
+ p[1] = (scanptr[1] * scanptr[3] + 255 * (255 - scanptr[3])) / 255;
+ p[2] = (scanptr[2] * scanptr[3] + 255 * (255 - scanptr[3])) / 255;
+ }
+ }
+ else
+ {
+ for (ycount = img->ysize, p = in + ystart * 3, scanptr = scanline;
+ ycount > 0;
+ ycount --, p += pstep, scanptr += 3)
+ {
+ p[0] = scanptr[0];
+ p[1] = scanptr[1];
+ p[2] = scanptr[2];
+ }
+ }
+ }
+ else
+ TIFFReadScanline(tif, in, row, 0);
+
+ if ((saturation != 100 || hue != 0) && bpp > 1)
+ cupsImageRGBAdjust(in, img->ysize, saturation, hue);
+
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_WHITE :
+ cupsImageRGBToWhite(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_RGB :
+ cupsImageRGBToRGB(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageRGBToBlack(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageRGBToCMY(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageRGBToCMYK(in, out, img->ysize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->ysize * bpp, lut);
+
+ _cupsImagePutCol(img, x, 0, img->ysize, out);
+ }
+ }
+ break;
+
+ case PHOTOMETRIC_SEPARATED :
+ inkset = INKSET_CMYK;
+ numinks = 4;
+
+#ifdef TIFFTAG_NUMBEROFINKS
+ if (!TIFFGetField(tif, TIFFTAG_INKSET, &inkset) &&
+ !TIFFGetField(tif, TIFFTAG_NUMBEROFINKS, &numinks))
+#else
+ if (!TIFFGetField(tif, TIFFTAG_INKSET, &inkset))
+#endif /* TIFFTAG_NUMBEROFINKS */
+ {
+ fputs("WARNING: No inkset or number-of-inks tag in the file!\n", stderr);
+ }
+
+ if (inkset == INKSET_CMYK || numinks == 4)
+ {
+ if (orientation < ORIENTATION_LEFTTOP)
+ {
+ /*
+ * Row major order...
+ */
+
+ for (y = ystart, ycount = img->ysize, row = 0;
+ ycount > 0;
+ ycount --, y += ydir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (xcount = img->xsize, scanptr = scanline, p = in + xstart * 3, bit = 0xf0;
+ xcount > 0;
+ xcount --, p += pstep)
+ {
+ if (*scanptr & bit & 0x11)
+ {
+ p[0] = 0;
+ p[1] = 0;
+ p[2] = 0;
+ }
+ else
+ {
+ if (*scanptr & bit & 0x88)
+ p[0] = 0;
+ else
+ p[0] = 255;
+
+ if (*scanptr & bit & 0x44)
+ p[1] = 0;
+ else
+ p[1] = 255;
+
+ if (*scanptr & bit & 0x22)
+ p[2] = 0;
+ else
+ p[2] = 255;
+ }
+
+ if (bit == 0xf0)
+ bit = 0x0f;
+ else
+ {
+ bit = 0xf0;
+ scanptr ++;
+ }
+ }
+ }
+ else if (bits == 2)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (xcount = img->xsize, scanptr = scanline, p = in + xstart * 3;
+ xcount > 0;
+ xcount --, p += pstep, scanptr ++)
+ {
+ pixel = *scanptr;
+ k = 255 * (pixel & 3) / 3;
+ if (k == 255)
+ {
+ p[0] = 0;
+ p[1] = 0;
+ p[2] = 0;
+ }
+ else
+ {
+ pixel >>= 2;
+ b = 255 - 255 * (pixel & 3) / 3 - k;
+ if (b < 0)
+ p[2] = 0;
+ else if (b < 256)
+ p[2] = b;
+ else
+ p[2] = 255;
+
+ pixel >>= 2;
+ g = 255 - 255 * (pixel & 3) / 3 - k;
+ if (g < 0)
+ p[1] = 0;
+ else if (g < 256)
+ p[1] = g;
+ else
+ p[1] = 255;
+
+ pixel >>= 2;
+ r = 255 - 255 * (pixel & 3) / 3 - k;
+ if (r < 0)
+ p[0] = 0;
+ else if (r < 256)
+ p[0] = r;
+ else
+ p[0] = 255;
+ }
+ }
+ }
+ else if (bits == 4)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (xcount = img->xsize, scanptr = scanline, p = in + xstart * 3;
+ xcount > 0;
+ xcount --, p += pstep, scanptr += 2)
+ {
+ pixel = scanptr[1];
+ k = 255 * (pixel & 15) / 15;
+ if (k == 255)
+ {
+ p[0] = 0;
+ p[1] = 0;
+ p[2] = 0;
+ }
+ else
+ {
+ pixel >>= 4;
+ b = 255 - 255 * (pixel & 15) / 15 - k;
+ if (b < 0)
+ p[2] = 0;
+ else if (b < 256)
+ p[2] = b;
+ else
+ p[2] = 255;
+
+ pixel = scanptr[0];
+ g = 255 - 255 * (pixel & 15) / 15 - k;
+ if (g < 0)
+ p[1] = 0;
+ else if (g < 256)
+ p[1] = g;
+ else
+ p[1] = 255;
+
+ pixel >>= 4;
+ r = 255 - 255 * (pixel & 15) / 15 - k;
+ if (r < 0)
+ p[0] = 0;
+ else if (r < 256)
+ p[0] = r;
+ else
+ p[0] = 255;
+ }
+ }
+ }
+ else if (img->colorspace == CUPS_IMAGE_CMYK)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ _cupsImagePutRow(img, 0, y, img->xsize, scanline);
+ }
+ else
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+
+ for (xcount = img->xsize, p = in + xstart * 3, scanptr = scanline;
+ xcount > 0;
+ xcount --, p += pstep, scanptr += 4)
+ {
+ k = scanptr[3];
+ if (k == 255)
+ {
+ p[0] = 0;
+ p[1] = 0;
+ p[2] = 0;
+ }
+ else
+ {
+ r = 255 - scanptr[0] - k;
+ if (r < 0)
+ p[0] = 0;
+ else if (r < 256)
+ p[0] = r;
+ else
+ p[0] = 255;
+
+ g = 255 - scanptr[1] - k;
+ if (g < 0)
+ p[1] = 0;
+ else if (g < 256)
+ p[1] = g;
+ else
+ p[1] = 255;
+
+ b = 255 - scanptr[2] - k;
+ if (b < 0)
+ p[2] = 0;
+ else if (b < 256)
+ p[2] = b;
+ else
+ p[2] = 255;
+ }
+ }
+ }
+
+ if ((saturation != 100 || hue != 0) && bpp > 1)
+ cupsImageRGBAdjust(in, img->xsize, saturation, hue);
+
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_WHITE :
+ cupsImageRGBToWhite(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_RGB :
+ cupsImageRGBToRGB(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageRGBToBlack(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageRGBToCMY(in, out, img->xsize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageRGBToCMYK(in, out, img->xsize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->xsize * 3, lut);
+
+ _cupsImagePutRow(img, 0, y, img->xsize, out);
+ }
+ }
+ else
+ {
+ /*
+ * Column major order...
+ */
+
+ for (x = xstart, xcount = img->xsize, row = 0;
+ xcount > 0;
+ xcount --, x += xdir, row ++)
+ {
+ if (bits == 1)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (ycount = img->ysize, scanptr = scanline, p = in + xstart * 3, bit = 0xf0;
+ ycount > 0;
+ ycount --, p += pstep)
+ {
+ if (*scanptr & bit & 0x11)
+ {
+ p[0] = 0;
+ p[1] = 0;
+ p[2] = 0;
+ }
+ else
+ {
+ if (*scanptr & bit & 0x88)
+ p[0] = 0;
+ else
+ p[0] = 255;
+
+ if (*scanptr & bit & 0x44)
+ p[1] = 0;
+ else
+ p[1] = 255;
+
+ if (*scanptr & bit & 0x22)
+ p[2] = 0;
+ else
+ p[2] = 255;
+ }
+
+ if (bit == 0xf0)
+ bit = 0x0f;
+ else
+ {
+ bit = 0xf0;
+ scanptr ++;
+ }
+ }
+ }
+ else if (bits == 2)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (ycount = img->ysize, scanptr = scanline, p = in + xstart * 3;
+ ycount > 0;
+ ycount --, p += pstep, scanptr ++)
+ {
+ pixel = *scanptr;
+ k = 255 * (pixel & 3) / 3;
+ if (k == 255)
+ {
+ p[0] = 0;
+ p[1] = 0;
+ p[2] = 0;
+ }
+ else
+ {
+ pixel >>= 2;
+ b = 255 - 255 * (pixel & 3) / 3 - k;
+ if (b < 0)
+ p[2] = 0;
+ else if (b < 256)
+ p[2] = b;
+ else
+ p[2] = 255;
+
+ pixel >>= 2;
+ g = 255 - 255 * (pixel & 3) / 3 - k;
+ if (g < 0)
+ p[1] = 0;
+ else if (g < 256)
+ p[1] = g;
+ else
+ p[1] = 255;
+
+ pixel >>= 2;
+ r = 255 - 255 * (pixel & 3) / 3 - k;
+ if (r < 0)
+ p[0] = 0;
+ else if (r < 256)
+ p[0] = r;
+ else
+ p[0] = 255;
+ }
+ }
+ }
+ else if (bits == 4)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ for (ycount = img->ysize, scanptr = scanline, p = in + xstart * 3;
+ ycount > 0;
+ ycount --, p += pstep, scanptr += 2)
+ {
+ pixel = scanptr[1];
+ k = 255 * (pixel & 15) / 15;
+ if (k == 255)
+ {
+ p[0] = 0;
+ p[1] = 0;
+ p[2] = 0;
+ }
+ else
+ {
+ pixel >>= 4;
+ b = 255 - 255 * (pixel & 15) / 15 - k;
+ if (b < 0)
+ p[2] = 0;
+ else if (b < 256)
+ p[2] = b;
+ else
+ p[2] = 255;
+
+ pixel = scanptr[0];
+ g = 255 - 255 * (pixel & 15) / 15 - k;
+ if (g < 0)
+ p[1] = 0;
+ else if (g < 256)
+ p[1] = g;
+ else
+ p[1] = 255;
+
+ pixel >>= 4;
+ r = 255 - 255 * (pixel & 15) / 15 - k;
+ if (r < 0)
+ p[0] = 0;
+ else if (r < 256)
+ p[0] = r;
+ else
+ p[0] = 255;
+ }
+ }
+ }
+ else if (img->colorspace == CUPS_IMAGE_CMYK)
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+ _cupsImagePutCol(img, x, 0, img->ysize, scanline);
+ }
+ else
+ {
+ TIFFReadScanline(tif, scanline, row, 0);
+
+ for (ycount = img->ysize, p = in + xstart * 3, scanptr = scanline;
+ ycount > 0;
+ ycount --, p += pstep, scanptr += 4)
+ {
+ k = scanptr[3];
+ if (k == 255)
+ {
+ p[0] = 0;
+ p[1] = 0;
+ p[2] = 0;
+ }
+ else
+ {
+ r = 255 - scanptr[0] - k;
+ if (r < 0)
+ p[0] = 0;
+ else if (r < 256)
+ p[0] = r;
+ else
+ p[0] = 255;
+
+ g = 255 - scanptr[1] - k;
+ if (g < 0)
+ p[1] = 0;
+ else if (g < 256)
+ p[1] = g;
+ else
+ p[1] = 255;
+
+ b = 255 - scanptr[2] - k;
+ if (b < 0)
+ p[2] = 0;
+ else if (b < 256)
+ p[2] = b;
+ else
+ p[2] = 255;
+ }
+ }
+ }
+
+ if ((saturation != 100 || hue != 0) && bpp > 1)
+ cupsImageRGBAdjust(in, img->ysize, saturation, hue);
+
+ switch (img->colorspace)
+ {
+ default :
+ break;
+
+ case CUPS_IMAGE_WHITE :
+ cupsImageRGBToWhite(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_RGB :
+ cupsImageRGBToRGB(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_BLACK :
+ cupsImageRGBToBlack(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_CMY :
+ cupsImageRGBToCMY(in, out, img->ysize);
+ break;
+ case CUPS_IMAGE_CMYK :
+ cupsImageRGBToCMYK(in, out, img->ysize);
+ break;
+ }
+
+ if (lut)
+ cupsImageLut(out, img->ysize * bpp, lut);
+
+ _cupsImagePutCol(img, x, 0, img->ysize, out);
+ }
+ }
+
+ break;
+ }
+
+ default :
+ _TIFFfree(scanline);
+ free(in);
+ free(out);
+
+ TIFFClose(tif);
+ fputs("DEBUG: Unknown TIFF photometric value!\n", stderr);
+ return (-1);
+ }
+
+ /*
+ * Free temporary buffers, close the TIFF file, and return.
+ */
+
+ _TIFFfree(scanline);
+ free(in);
+ free(out);
+
+ TIFFClose(tif);
+ return (0);
+}
+#endif /* HAVE_LIBTIFF */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image-zoom.c b/filter/image-zoom.c
new file mode 100644
index 000000000..154ea34c2
--- /dev/null
+++ b/filter/image-zoom.c
@@ -0,0 +1,361 @@
+/*
+ * "$Id$"
+ *
+ * cupsImage zoom routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cupsImageZoomDelete() - Free a zoom record...
+ * _cupsImageZoomFill() - Fill a zoom record...
+ * _cupsImageZoomNew() - Allocate a pixel zoom record...
+ * zoom_bilinear() - Fill a zoom record with image data utilizing
+ * bilinear interpolation.
+ * zoom_nearest() - Fill a zoom record quickly using nearest-neighbor
+ * sampling.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+
+
+/*
+ * Local functions...
+ */
+
+static void zoom_bilinear(cups_izoom_t *z, int iy);
+static void zoom_nearest(cups_izoom_t *z, int iy);
+
+
+/*
+ * '_cupsImageZoomDelete()' - Free a zoom record...
+ */
+
+void
+_cupsImageZoomDelete(cups_izoom_t *z) /* I - Zoom record to free */
+{
+ free(z->rows[0]);
+ free(z->rows[1]);
+ free(z->in);
+ free(z);
+}
+
+
+/*
+ * '_cupsImageZoomFill()' - Fill a zoom record with image data utilizing bilinear
+ * interpolation.
+ */
+
+void
+_cupsImageZoomFill(cups_izoom_t *z, /* I - Zoom record to fill */
+ int iy) /* I - Zoom image row */
+{
+ switch (z->type)
+ {
+ case CUPS_IZOOM_FAST :
+ zoom_nearest(z, iy);
+ break;
+
+ default :
+ zoom_bilinear(z, iy);
+ break;
+ }
+}
+
+
+/*
+ * '_cupsImageZoomNew()' - Allocate a pixel zoom record...
+ */
+
+cups_izoom_t *
+_cupsImageZoomNew(
+ cups_image_t *img, /* I - cupsImage to zoom */
+ int xc0, /* I - Upper-lefthand corner */
+ int yc0, /* I - ... */
+ int xc1, /* I - Lower-righthand corner */
+ int yc1, /* I - ... */
+ int xsize, /* I - Final width of image */
+ int ysize, /* I - Final height of image */
+ int rotated, /* I - Non-zero if image is rotated 90 degs */
+ cups_iztype_t type) /* I - Zoom type */
+{
+ cups_izoom_t *z; /* New zoom record */
+ int flip; /* Flip on X axis? */
+
+
+ if (xsize > CUPS_IMAGE_MAX_WIDTH ||
+ ysize > CUPS_IMAGE_MAX_HEIGHT ||
+ (xc1 - xc0) > CUPS_IMAGE_MAX_WIDTH ||
+ (yc1 - yc0) > CUPS_IMAGE_MAX_HEIGHT)
+ return (NULL); /* Protect against integer overflow */
+
+ if ((z = (cups_izoom_t *)calloc(1, sizeof(cups_izoom_t))) == NULL)
+ return (NULL);
+
+ z->img = img;
+ z->row = 0;
+ z->depth = cupsImageGetDepth(img);
+ z->rotated = rotated;
+ z->type = type;
+
+ if (xsize < 0)
+ {
+ flip = 1;
+ xsize = -xsize;
+ }
+ else
+ {
+ flip = 0;
+ }
+
+ if (rotated)
+ {
+ z->xorig = xc1;
+ z->yorig = yc0;
+ z->width = yc1 - yc0 + 1;
+ z->height = xc1 - xc0 + 1;
+ z->xsize = xsize;
+ z->ysize = ysize;
+ z->xmod = z->width % z->xsize;
+ z->xstep = z->width / z->xsize;
+ z->xincr = 1;
+ z->ymod = z->height % z->ysize;
+ z->ystep = z->height / z->ysize;
+ z->yincr = 1;
+ z->instep = z->xstep * z->depth;
+ z->inincr = /* z->xincr * */ z->depth; /* z->xincr is always 1 */
+
+ if (z->width < img->ysize)
+ z->xmax = z->width;
+ else
+ z->xmax = z->width - 1;
+
+ if (z->height < img->xsize)
+ z->ymax = z->height;
+ else
+ z->ymax = z->height - 1;
+ }
+ else
+ {
+ z->xorig = xc0;
+ z->yorig = yc0;
+ z->width = xc1 - xc0 + 1;
+ z->height = yc1 - yc0 + 1;
+ z->xsize = xsize;
+ z->ysize = ysize;
+ z->xmod = z->width % z->xsize;
+ z->xstep = z->width / z->xsize;
+ z->xincr = 1;
+ z->ymod = z->height % z->ysize;
+ z->ystep = z->height / z->ysize;
+ z->yincr = 1;
+ z->instep = z->xstep * z->depth;
+ z->inincr = /* z->xincr * */ z->depth; /* z->xincr is always 1 */
+
+ if (z->width < img->xsize)
+ z->xmax = z->width;
+ else
+ z->xmax = z->width - 1;
+
+ if (z->height < img->ysize)
+ z->ymax = z->height;
+ else
+ z->ymax = z->height - 1;
+ }
+
+ if (flip)
+ {
+ z->instep = -z->instep;
+ z->inincr = -z->inincr;
+ }
+
+ if ((z->rows[0] = (cups_ib_t *)malloc(z->xsize * z->depth)) == NULL)
+ {
+ free(z);
+ return (NULL);
+ }
+
+ if ((z->rows[1] = (cups_ib_t *)malloc(z->xsize * z->depth)) == NULL)
+ {
+ free(z->rows[0]);
+ free(z);
+ return (NULL);
+ }
+
+ if ((z->in = (cups_ib_t *)malloc(z->width * z->depth)) == NULL)
+ {
+ free(z->rows[0]);
+ free(z->rows[1]);
+ free(z);
+ return (NULL);
+ }
+
+ return (z);
+}
+
+
+/*
+ * 'zoom_bilinear()' - Fill a zoom record with image data utilizing bilinear
+ * interpolation.
+ */
+
+static void
+zoom_bilinear(cups_izoom_t *z, /* I - Zoom record to fill */
+ int iy) /* I - Zoom image row */
+{
+ cups_ib_t *r, /* Row pointer */
+ *inptr; /* Pixel pointer */
+ int xerr0, /* X error counter */
+ xerr1; /* ... */
+ int ix,
+ x,
+ count,
+ z_depth,
+ z_xstep,
+ z_xincr,
+ z_instep,
+ z_inincr,
+ z_xmax,
+ z_xmod,
+ z_xsize;
+
+
+ if (iy > z->ymax)
+ iy = z->ymax;
+
+ z->row ^= 1;
+
+ z_depth = z->depth;
+ z_xsize = z->xsize;
+ z_xmax = z->xmax;
+ z_xmod = z->xmod;
+ z_xstep = z->xstep;
+ z_xincr = z->xincr;
+ z_instep = z->instep;
+ z_inincr = z->inincr;
+
+ if (z->rotated)
+ cupsImageGetCol(z->img, z->xorig - iy, z->yorig, z->width, z->in);
+ else
+ cupsImageGetRow(z->img, z->xorig, z->yorig + iy, z->width, z->in);
+
+ if (z_inincr < 0)
+ inptr = z->in + (z->width - 1) * z_depth;
+ else
+ inptr = z->in;
+
+ for (x = z_xsize, xerr0 = z_xsize, xerr1 = 0, ix = 0, r = z->rows[z->row];
+ x > 0;
+ x --)
+ {
+ if (ix < z_xmax)
+ {
+ for (count = 0; count < z_depth; count ++)
+ *r++ = (inptr[count] * xerr0 + inptr[z_depth + count] * xerr1) / z_xsize;
+ }
+ else
+ {
+ for (count = 0; count < z_depth; count ++)
+ *r++ = inptr[count];
+ }
+
+ ix += z_xstep;
+ inptr += z_instep;
+ xerr0 -= z_xmod;
+ xerr1 += z_xmod;
+
+ if (xerr0 <= 0)
+ {
+ xerr0 += z_xsize;
+ xerr1 -= z_xsize;
+ ix += z_xincr;
+ inptr += z_inincr;
+ }
+ }
+}
+
+
+/*
+ * 'zoom_nearest()' - Fill a zoom record quickly using nearest-neighbor
+ * sampling.
+ */
+
+static void
+zoom_nearest(cups_izoom_t *z, /* I - Zoom record to fill */
+ int iy) /* I - Zoom image row */
+{
+ cups_ib_t *r, /* Row pointer */
+ *inptr; /* Pixel pointer */
+ int xerr0; /* X error counter */
+ int ix,
+ x,
+ count,
+ z_depth,
+ z_xstep,
+ z_xincr,
+ z_instep,
+ z_inincr,
+ z_xmod,
+ z_xsize;
+
+
+ if (iy > z->ymax)
+ iy = z->ymax;
+
+ z->row ^= 1;
+
+ z_depth = z->depth;
+ z_xsize = z->xsize;
+ z_xmod = z->xmod;
+ z_xstep = z->xstep;
+ z_xincr = z->xincr;
+ z_instep = z->instep;
+ z_inincr = z->inincr;
+
+ if (z->rotated)
+ cupsImageGetCol(z->img, z->xorig - iy, z->yorig, z->width, z->in);
+ else
+ cupsImageGetRow(z->img, z->xorig, z->yorig + iy, z->width, z->in);
+
+ if (z_inincr < 0)
+ inptr = z->in + (z->width - 1) * z_depth;
+ else
+ inptr = z->in;
+
+ for (x = z_xsize, xerr0 = z_xsize, ix = 0, r = z->rows[z->row];
+ x > 0;
+ x --)
+ {
+ for (count = 0; count < z_depth; count ++)
+ *r++ = inptr[count];
+
+ ix += z_xstep;
+ inptr += z_instep;
+ xerr0 -= z_xmod;
+
+ if (xerr0 <= 0)
+ {
+ xerr0 += z_xsize;
+ ix += z_xincr;
+ inptr += z_inincr;
+ }
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image.c b/filter/image.c
new file mode 100644
index 000000000..f3f76afb4
--- /dev/null
+++ b/filter/image.c
@@ -0,0 +1,812 @@
+/*
+ * "$Id$"
+ *
+ * Base image support for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsImageClose() - Close an image file.
+ * cupsImageGetCol() - Get a column of pixels from an image.
+ * cupsImageGetColorSpace() - Get the image colorspace.
+ * cupsImageGetDepth() - Get the number of bytes per pixel.
+ * cupsImageGetHeight() - Get the height of an image.
+ * cupsImageGetRow() - Get a row of pixels from an image.
+ * cupsImageGetWidth() - Get the width of an image.
+ * cupsImageGetXPPI() - Get the horizontal resolution of an image.
+ * cupsImageGetYPPI() - Get the vertical resolution of an image.
+ * cupsImageOpen() - Open an image file and read it into memory.
+ * _cupsImagePutCol() - Put a column of pixels to an image.
+ * _cupsImagePutRow() - Put a row of pixels to an image.
+ * cupsImageSetMaxTiles() - Set the maximum number of tiles to cache.
+ * flush_tile() - Flush the least-recently-used tile in the cache.
+ * get_tile() - Get a cached tile.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+
+
+/*
+ * Local functions...
+ */
+
+static void flush_tile(cups_image_t *img);
+static cups_ib_t *get_tile(cups_image_t *img, int x, int y);
+
+
+/*
+ * 'cupsImageClose()' - Close an image file.
+ */
+
+void
+cupsImageClose(cups_image_t *img) /* I - Image to close */
+{
+ cups_ic_t *current, /* Current cached tile */
+ *next; /* Next cached tile */
+
+
+ /*
+ * Wipe the tile cache file (if any)...
+ */
+
+ if (img->cachefile >= 0)
+ {
+ DEBUG_printf(("Closing/removing swap file \"%s\"...\n", img->cachename));
+
+ close(img->cachefile);
+ unlink(img->cachename);
+ }
+
+ /*
+ * Free the image cache...
+ */
+
+ DEBUG_puts("Freeing memory...");
+
+ for (current = img->first, next = NULL; current != NULL; current = next)
+ {
+ DEBUG_printf(("Freeing cache (%p, next = %p)...\n", current, next));
+
+ next = current->next;
+ free(current);
+ }
+
+ /*
+ * Free the rest of memory...
+ */
+
+ if (img->tiles != NULL)
+ {
+ DEBUG_printf(("Freeing tiles (%p)...\n", img->tiles[0]));
+
+ free(img->tiles[0]);
+
+ DEBUG_printf(("Freeing tile pointers (%p)...\n", img->tiles));
+
+ free(img->tiles);
+ }
+
+ free(img);
+}
+
+
+/*
+ * 'cupsImageGetCol()' - Get a column of pixels from an image.
+ */
+
+int /* O - -1 on error, 0 on success */
+cupsImageGetCol(cups_image_t *img, /* I - Image */
+ int x, /* I - Column */
+ int y, /* I - Start row */
+ int height, /* I - Column height */
+ cups_ib_t *pixels) /* O - Pixel data */
+{
+ int bpp, /* Bytes per pixel */
+ twidth, /* Tile width */
+ count; /* Number of pixels to get */
+ const cups_ib_t *ib; /* Pointer into tile */
+
+
+ if (img == NULL || x < 0 || x >= img->xsize || y >= img->ysize)
+ return (-1);
+
+ if (y < 0)
+ {
+ height += y;
+ y = 0;
+ }
+
+ if ((y + height) > img->ysize)
+ height = img->ysize - y;
+
+ if (height < 1)
+ return (-1);
+
+ bpp = cupsImageGetDepth(img);
+ twidth = bpp * (CUPS_TILE_SIZE - 1);
+
+ while (height > 0)
+ {
+ ib = get_tile(img, x, y);
+
+ if (ib == NULL)
+ return (-1);
+
+ count = CUPS_TILE_SIZE - (y & (CUPS_TILE_SIZE - 1));
+ if (count > height)
+ count = height;
+
+ y += count;
+ height -= count;
+
+ for (; count > 0; count --, ib += twidth)
+ switch (bpp)
+ {
+ case 4 :
+ *pixels++ = *ib++;
+ case 3 :
+ *pixels++ = *ib++;
+ *pixels++ = *ib++;
+ case 1 :
+ *pixels++ = *ib++;
+ break;
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'cupsImageGetColorSpace()' - Get the image colorspace.
+ */
+
+cups_icspace_t /* O - Colorspace */
+cupsImageGetColorSpace(
+ cups_image_t *img) /* I - Image */
+{
+ return (img->colorspace);
+}
+
+
+/*
+ * 'cupsImageGetDepth()' - Get the number of bytes per pixel.
+ */
+
+int /* O - Bytes per pixel */
+cupsImageGetDepth(cups_image_t *img) /* I - Image */
+{
+ return (abs(img->colorspace));
+}
+
+
+/*
+ * 'cupsImageGetHeight()' - Get the height of an image.
+ */
+
+unsigned /* O - Height in pixels */
+cupsImageGetHeight(cups_image_t *img) /* I - Image */
+{
+ return (img->ysize);
+}
+
+
+/*
+ * 'cupsImageGetRow()' - Get a row of pixels from an image.
+ */
+
+int /* O - -1 on error, 0 on success */
+cupsImageGetRow(cups_image_t *img, /* I - Image */
+ int x, /* I - Start column */
+ int y, /* I - Row */
+ int width, /* I - Width of row */
+ cups_ib_t *pixels) /* O - Pixel data */
+{
+ int bpp, /* Bytes per pixel */
+ count; /* Number of pixels to get */
+ const cups_ib_t *ib; /* Pointer to pixels */
+
+
+ if (img == NULL || y < 0 || y >= img->ysize || x >= img->xsize)
+ return (-1);
+
+ if (x < 0)
+ {
+ width += x;
+ x = 0;
+ }
+
+ if ((x + width) > img->xsize)
+ width = img->xsize - x;
+
+ if (width < 1)
+ return (-1);
+
+ bpp = img->colorspace < 0 ? -img->colorspace : img->colorspace;
+
+ while (width > 0)
+ {
+ ib = get_tile(img, x, y);
+
+ if (ib == NULL)
+ return (-1);
+
+ count = CUPS_TILE_SIZE - (x & (CUPS_TILE_SIZE - 1));
+ if (count > width)
+ count = width;
+ memcpy(pixels, ib, count * bpp);
+ pixels += count * bpp;
+ x += count;
+ width -= count;
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'cupsImageGetWidth()' - Get the width of an image.
+ */
+
+unsigned /* O - Width in pixels */
+cupsImageGetWidth(cups_image_t *img) /* I - Image */
+{
+ return (img->xsize);
+}
+
+
+/*
+ * 'cupsImageGetXPPI()' - Get the horizontal resolution of an image.
+ */
+
+unsigned /* O - Horizontal PPI */
+cupsImageGetXPPI(cups_image_t *img) /* I - Image */
+{
+ return (img->xppi);
+}
+
+
+/*
+ * 'cupsImageGetYPPI()' - Get the vertical resolution of an image.
+ */
+
+unsigned /* O - Vertical PPI */
+cupsImageGetYPPI(cups_image_t *img) /* I - Image */
+{
+ return (img->yppi);
+}
+
+
+/*
+ * 'cupsImageOpen()' - Open an image file and read it into memory.
+ */
+
+cups_image_t * /* O - New image */
+cupsImageOpen(
+ const char *filename, /* I - Filename of image */
+ cups_icspace_t primary, /* I - Primary colorspace needed */
+ cups_icspace_t secondary, /* I - Secondary colorspace if primary no good */
+ int saturation, /* I - Color saturation level */
+ int hue, /* I - Color hue adjustment */
+ const cups_ib_t *lut) /* I - RGB gamma/brightness LUT */
+{
+ FILE *fp; /* File pointer */
+ unsigned char header[16], /* First 16 bytes of file */
+ header2[16]; /* Bytes 2048-2064 (PhotoCD) */
+ cups_image_t *img; /* New image buffer */
+ int status; /* Status of load... */
+
+
+ DEBUG_printf(("cupsImageOpen(\"%s\", %d, %d, %d, %d, %p)\n",
+ filename ? filename : "(null)", primary, secondary,
+ saturation, hue, lut));
+
+ /*
+ * Figure out the file type...
+ */
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ return (NULL);
+
+ if (fread(header, 1, sizeof(header), fp) == 0)
+ {
+ fclose(fp);
+ return (NULL);
+ }
+
+ fseek(fp, 2048, SEEK_SET);
+ memset(header2, 0, sizeof(header2));
+ fread(header2, 1, sizeof(header2), fp);
+ fseek(fp, 0, SEEK_SET);
+
+ /*
+ * Allocate memory...
+ */
+
+ img = calloc(sizeof(cups_image_t), 1);
+
+ if (img == NULL)
+ {
+ fclose(fp);
+ return (NULL);
+ }
+
+ /*
+ * Load the image as appropriate...
+ */
+
+ img->max_ics = CUPS_TILE_MINIMUM;
+ img->xppi = 128;
+ img->yppi = 128;
+
+ if (!memcmp(header, "GIF87a", 6) || !memcmp(header, "GIF89a", 6))
+ status = _cupsImageReadGIF(img, fp, primary, secondary, saturation, hue,
+ lut);
+ else if (!memcmp(header, "BM", 2))
+ status = _cupsImageReadBMP(img, fp, primary, secondary, saturation, hue,
+ lut);
+ else if (header[0] == 0x01 && header[1] == 0xda)
+ status = _cupsImageReadSGI(img, fp, primary, secondary, saturation, hue,
+ lut);
+ else if (header[0] == 0x59 && header[1] == 0xa6 &&
+ header[2] == 0x6a && header[3] == 0x95)
+ status = _cupsImageReadSunRaster(img, fp, primary, secondary, saturation,
+ hue, lut);
+ else if (header[0] == 'P' && header[1] >= '1' && header[1] <= '6')
+ status = _cupsImageReadPNM(img, fp, primary, secondary, saturation, hue,
+ lut);
+ else if (!memcmp(header2, "PCD_IPI", 7))
+ status = _cupsImageReadPhotoCD(img, fp, primary, secondary, saturation,
+ hue, lut);
+ else if (!memcmp(header + 8, "\000\010", 2) ||
+ !memcmp(header + 8, "\000\030", 2))
+ status = _cupsImageReadPIX(img, fp, primary, secondary, saturation, hue,
+ lut);
+#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
+ else if (!memcmp(header, "\211PNG", 4))
+ status = _cupsImageReadPNG(img, fp, primary, secondary, saturation, hue,
+ lut);
+#endif /* HAVE_LIBPNG && HAVE_LIBZ */
+#ifdef HAVE_LIBJPEG
+ else if (!memcmp(header, "\377\330\377", 3) && /* Start-of-Image */
+ header[3] >= 0xe0 && header[3] <= 0xef) /* APPn */
+ status = _cupsImageReadJPEG(img, fp, primary, secondary, saturation, hue,
+ lut);
+#endif /* HAVE_LIBJPEG */
+#ifdef HAVE_LIBTIFF
+ else if (!memcmp(header, "MM\000\052", 4) ||
+ !memcmp(header, "II\052\000", 4))
+ status = _cupsImageReadTIFF(img, fp, primary, secondary, saturation, hue,
+ lut);
+#endif /* HAVE_LIBTIFF */
+ else
+ {
+ fclose(fp);
+ status = -1;
+ }
+
+ if (status)
+ {
+ free(img);
+ return (NULL);
+ }
+ else
+ return (img);
+}
+
+
+/*
+ * '_cupsImagePutCol()' - Put a column of pixels to an image.
+ */
+
+int /* O - -1 on error, 0 on success */
+_cupsImagePutCol(
+ cups_image_t *img, /* I - Image */
+ int x, /* I - Column */
+ int y, /* I - Start row */
+ int height, /* I - Column height */
+ const cups_ib_t *pixels) /* I - Pixels to put */
+{
+ int bpp, /* Bytes per pixel */
+ twidth, /* Width of tile */
+ count; /* Number of pixels to put */
+ int tilex, /* Column within tile */
+ tiley; /* Row within tile */
+ cups_ib_t *ib; /* Pointer to pixels in tile */
+
+
+ if (img == NULL || x < 0 || x >= img->xsize || y >= img->ysize)
+ return (-1);
+
+ if (y < 0)
+ {
+ height += y;
+ y = 0;
+ }
+
+ if ((y + height) > img->ysize)
+ height = img->ysize - y;
+
+ if (height < 1)
+ return (-1);
+
+ bpp = cupsImageGetDepth(img);
+ twidth = bpp * (CUPS_TILE_SIZE - 1);
+ tilex = x / CUPS_TILE_SIZE;
+ tiley = y / CUPS_TILE_SIZE;
+
+ while (height > 0)
+ {
+ ib = get_tile(img, x, y);
+
+ if (ib == NULL)
+ return (-1);
+
+ img->tiles[tiley][tilex].dirty = 1;
+ tiley ++;
+
+ count = CUPS_TILE_SIZE - (y & (CUPS_TILE_SIZE - 1));
+ if (count > height)
+ count = height;
+
+ y += count;
+ height -= count;
+
+ for (; count > 0; count --, ib += twidth)
+ switch (bpp)
+ {
+ case 4 :
+ *ib++ = *pixels++;
+ case 3 :
+ *ib++ = *pixels++;
+ *ib++ = *pixels++;
+ case 1 :
+ *ib++ = *pixels++;
+ break;
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * '_cupsImagePutRow()' - Put a row of pixels to an image.
+ */
+
+int /* O - -1 on error, 0 on success */
+_cupsImagePutRow(
+ cups_image_t *img, /* I - Image */
+ int x, /* I - Start column */
+ int y, /* I - Row */
+ int width, /* I - Row width */
+ const cups_ib_t *pixels) /* I - Pixel data */
+{
+ int bpp, /* Bytes per pixel */
+ count; /* Number of pixels to put */
+ int tilex, /* Column within tile */
+ tiley; /* Row within tile */
+ cups_ib_t *ib; /* Pointer to pixels in tile */
+
+
+ if (img == NULL || y < 0 || y >= img->ysize || x >= img->xsize)
+ return (-1);
+
+ if (x < 0)
+ {
+ width += x;
+ x = 0;
+ }
+
+ if ((x + width) > img->xsize)
+ width = img->xsize - x;
+
+ if (width < 1)
+ return (-1);
+
+ bpp = img->colorspace < 0 ? -img->colorspace : img->colorspace;
+ tilex = x / CUPS_TILE_SIZE;
+ tiley = y / CUPS_TILE_SIZE;
+
+ while (width > 0)
+ {
+ ib = get_tile(img, x, y);
+
+ if (ib == NULL)
+ return (-1);
+
+ img->tiles[tiley][tilex].dirty = 1;
+
+ count = CUPS_TILE_SIZE - (x & (CUPS_TILE_SIZE - 1));
+ if (count > width)
+ count = width;
+ memcpy(ib, pixels, count * bpp);
+ pixels += count * bpp;
+ x += count;
+ width -= count;
+ tilex ++;
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'cupsImageSetMaxTiles()' - Set the maximum number of tiles to cache.
+ *
+ * If the "max_tiles" argument is 0 then the maximum number of tiles is
+ * computed from the image size or the RIP_CACHE environment variable.
+ */
+
+void
+cupsImageSetMaxTiles(
+ cups_image_t *img, /* I - Image to set */
+ int max_tiles) /* I - Number of tiles to cache */
+{
+ int cache_size, /* Size of tile cache in bytes */
+ min_tiles, /* Minimum number of tiles to cache */
+ max_size; /* Maximum cache size in bytes */
+ char *cache_env, /* Cache size environment variable */
+ cache_units[255]; /* Cache size units */
+
+
+ min_tiles = max(CUPS_TILE_MINIMUM,
+ 1 + max((img->xsize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE,
+ (img->ysize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE));
+
+ if (max_tiles == 0)
+ max_tiles = ((img->xsize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE) *
+ ((img->ysize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE);
+
+ cache_size = max_tiles * CUPS_TILE_SIZE * CUPS_TILE_SIZE *
+ cupsImageGetDepth(img);
+
+ if ((cache_env = getenv("RIP_MAX_CACHE")) != NULL)
+ {
+ switch (sscanf(cache_env, "%d%254s", &max_size, cache_units))
+ {
+ case 0 :
+ max_size = 32 * 1024 * 1024;
+ break;
+ case 1 :
+ max_size *= 4 * CUPS_TILE_SIZE * CUPS_TILE_SIZE;
+ break;
+ case 2 :
+ if (tolower(cache_units[0] & 255) == 'g')
+ max_size *= 1024 * 1024 * 1024;
+ else if (tolower(cache_units[0] & 255) == 'm')
+ max_size *= 1024 * 1024;
+ else if (tolower(cache_units[0] & 255) == 'k')
+ max_size *= 1024;
+ else if (tolower(cache_units[0] & 255) == 't')
+ max_size *= 4 * CUPS_TILE_SIZE * CUPS_TILE_SIZE;
+ break;
+ }
+ }
+ else
+ max_size = 32 * 1024 * 1024;
+
+ if (cache_size > max_size)
+ max_tiles = max_size / CUPS_TILE_SIZE / CUPS_TILE_SIZE /
+ cupsImageGetDepth(img);
+
+ if (max_tiles < min_tiles)
+ max_tiles = min_tiles;
+
+ img->max_ics = max_tiles;
+
+ DEBUG_printf(("max_ics=%d...\n", img->max_ics));
+}
+
+
+/*
+ * 'flush_tile()' - Flush the least-recently-used tile in the cache.
+ */
+
+static void
+flush_tile(cups_image_t *img) /* I - Image */
+{
+ int bpp; /* Bytes per pixel */
+ cups_itile_t *tile; /* Pointer to tile */
+
+
+ bpp = cupsImageGetDepth(img);
+ tile = img->first->tile;
+
+ if (!tile->dirty)
+ {
+ tile->ic = NULL;
+ return;
+ }
+
+ if (img->cachefile < 0)
+ {
+ if ((img->cachefile = cupsTempFd(img->cachename,
+ sizeof(img->cachename))) < 0)
+ {
+ tile->ic = NULL;
+ tile->dirty = 0;
+ return;
+ }
+
+ DEBUG_printf(("Created swap file \"%s\"...\n", img->cachename));
+ }
+
+ if (tile->pos >= 0)
+ {
+ if (lseek(img->cachefile, tile->pos, SEEK_SET) != tile->pos)
+ {
+ tile->ic = NULL;
+ tile->dirty = 0;
+ return;
+ }
+ }
+ else
+ {
+ if ((tile->pos = lseek(img->cachefile, 0, SEEK_END)) < 0)
+ {
+ tile->ic = NULL;
+ tile->dirty = 0;
+ return;
+ }
+ }
+
+ write(img->cachefile, tile->ic->pixels, bpp * CUPS_TILE_SIZE * CUPS_TILE_SIZE);
+
+ tile->ic = NULL;
+ tile->dirty = 0;
+}
+
+
+/*
+ * 'get_tile()' - Get a cached tile.
+ */
+
+static cups_ib_t * /* O - Pointer to tile or NULL */
+get_tile(cups_image_t *img, /* I - Image */
+ int x, /* I - Column in image */
+ int y) /* I - Row in image */
+{
+ int bpp, /* Bytes per pixel */
+ tilex, /* Column within tile */
+ tiley, /* Row within tile */
+ xtiles, /* Number of tiles horizontally */
+ ytiles; /* Number of tiles vertically */
+ cups_ic_t *ic; /* Cache pointer */
+ cups_itile_t *tile; /* Tile pointer */
+
+
+ if (img->tiles == NULL)
+ {
+ xtiles = (img->xsize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE;
+ ytiles = (img->ysize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE;
+
+ DEBUG_printf(("Creating tile array (%dx%d)\n", xtiles, ytiles));
+
+ if ((img->tiles = calloc(sizeof(cups_itile_t *), ytiles)) == NULL)
+ return (NULL);
+
+ if ((tile = calloc(xtiles * sizeof(cups_itile_t), ytiles)) == NULL)
+ return (NULL);
+
+ for (tiley = 0; tiley < ytiles; tiley ++)
+ {
+ img->tiles[tiley] = tile;
+ for (tilex = xtiles; tilex > 0; tilex --, tile ++)
+ tile->pos = -1;
+ }
+ }
+
+ bpp = cupsImageGetDepth(img);
+ tilex = x / CUPS_TILE_SIZE;
+ tiley = y / CUPS_TILE_SIZE;
+ tile = img->tiles[tiley] + tilex;
+ x &= (CUPS_TILE_SIZE - 1);
+ y &= (CUPS_TILE_SIZE - 1);
+
+ if ((ic = tile->ic) == NULL)
+ {
+ if (img->num_ics < img->max_ics)
+ {
+ if ((ic = calloc(sizeof(cups_ic_t) +
+ bpp * CUPS_TILE_SIZE * CUPS_TILE_SIZE, 1)) == NULL)
+ {
+ if (img->num_ics == 0)
+ return (NULL);
+
+ flush_tile(img);
+ ic = img->first;
+ }
+ else
+ {
+ ic->pixels = ((cups_ib_t *)ic) + sizeof(cups_ic_t);
+
+ img->num_ics ++;
+
+ DEBUG_printf(("Allocated cache tile %d (%p)...\n", img->num_ics, ic));
+ }
+ }
+ else
+ {
+ DEBUG_printf(("Flushing old cache tile (%p)...\n", img->first));
+
+ flush_tile(img);
+ ic = img->first;
+ }
+
+ ic->tile = tile;
+ tile->ic = ic;
+
+ if (tile->pos >= 0)
+ {
+ DEBUG_printf(("Loading cache tile from file position " CUPS_LLFMT "...\n",
+ CUPS_LLCAST tile->pos));
+
+ lseek(img->cachefile, tile->pos, SEEK_SET);
+ read(img->cachefile, ic->pixels, bpp * CUPS_TILE_SIZE * CUPS_TILE_SIZE);
+ }
+ else
+ {
+ DEBUG_puts("Clearing cache tile...");
+
+ memset(ic->pixels, 0, bpp * CUPS_TILE_SIZE * CUPS_TILE_SIZE);
+ }
+ }
+
+ if (ic == img->first)
+ {
+ if (ic->next != NULL)
+ ic->next->prev = NULL;
+
+ img->first = ic->next;
+ ic->next = NULL;
+ ic->prev = NULL;
+ }
+ else if (img->first == NULL)
+ img->first = ic;
+
+ if (ic != img->last)
+ {
+ /*
+ * Remove the cache entry from the list...
+ */
+
+ if (ic->prev != NULL)
+ ic->prev->next = ic->next;
+ if (ic->next != NULL)
+ ic->next->prev = ic->prev;
+
+ /*
+ * And add it to the end...
+ */
+
+ if (img->last != NULL)
+ img->last->next = ic;
+
+ ic->prev = img->last;
+ img->last = ic;
+ }
+
+ ic->next = NULL;
+
+ return (ic->pixels + bpp * (y * CUPS_TILE_SIZE + x));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/image.h b/filter/image.h
new file mode 100644
index 000000000..7174b5e0d
--- /dev/null
+++ b/filter/image.h
@@ -0,0 +1,130 @@
+/*
+ * "$Id$"
+ *
+ * Image library definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_IMAGE_H_
+# define _CUPS_IMAGE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include <stdio.h>
+# include <cups/raster.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+/*
+ * Constants...
+ */
+
+typedef enum cups_icspace_e /**** Image colorspaces ****/
+{
+ CUPS_IMAGE_CMYK = -4, /* Cyan, magenta, yellow, and black */
+ CUPS_IMAGE_CMY = -3, /* Cyan, magenta, and yellow */
+ CUPS_IMAGE_BLACK = -1, /* Black */
+ CUPS_IMAGE_WHITE = 1, /* White (luminance) */
+ CUPS_IMAGE_RGB = 3, /* Red, green, and blue */
+ CUPS_IMAGE_RGB_CMYK = 4 /* Use RGB or CMYK */
+} cups_icspace_t;
+
+
+/*
+ * Types and structures...
+ */
+
+typedef unsigned char cups_ib_t; /**** Image byte ****/
+
+struct cups_image_s;
+typedef struct cups_image_s cups_image_t;
+ /**** Image file data ****/
+
+struct cups_izoom_s;
+typedef struct cups_izoom_s cups_izoom_t;
+ /**** Image zoom data ****/
+
+
+/*
+ * Prototypes...
+ */
+
+extern void cupsImageClose(cups_image_t *img) _CUPS_API_1_2;
+extern void cupsImageCMYKToBlack(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+extern void cupsImageCMYKToCMY(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+extern void cupsImageCMYKToCMYK(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+extern void cupsImageCMYKToRGB(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+extern void cupsImageCMYKToWhite(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+extern int cupsImageGetCol(cups_image_t *img, int x, int y,
+ int height, cups_ib_t *pixels) _CUPS_API_1_2;
+extern cups_icspace_t cupsImageGetColorSpace(cups_image_t *img) _CUPS_API_1_2;
+extern int cupsImageGetDepth(cups_image_t *img) _CUPS_API_1_2;
+extern unsigned cupsImageGetHeight(cups_image_t *img) _CUPS_API_1_2;
+extern int cupsImageGetRow(cups_image_t *img, int x, int y,
+ int width, cups_ib_t *pixels) _CUPS_API_1_2;
+extern unsigned cupsImageGetWidth(cups_image_t *img) _CUPS_API_1_2;
+extern unsigned cupsImageGetXPPI(cups_image_t *img) _CUPS_API_1_2;
+extern unsigned cupsImageGetYPPI(cups_image_t *img) _CUPS_API_1_2;
+extern void cupsImageLut(cups_ib_t *pixels, int count,
+ const cups_ib_t *lut) _CUPS_API_1_2;
+extern cups_image_t *cupsImageOpen(const char *filename,
+ cups_icspace_t primary,
+ cups_icspace_t secondary,
+ int saturation, int hue,
+ const cups_ib_t *lut) _CUPS_API_1_2;
+extern void cupsImageRGBAdjust(cups_ib_t *pixels, int count,
+ int saturation, int hue) _CUPS_API_1_2;
+extern void cupsImageRGBToBlack(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+extern void cupsImageRGBToCMY(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+extern void cupsImageRGBToCMYK(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+extern void cupsImageRGBToRGB(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+extern void cupsImageRGBToWhite(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+extern void cupsImageSetMaxTiles(cups_image_t *img, int max_tiles) _CUPS_API_1_2;
+extern void cupsImageSetProfile(float d, float g,
+ float matrix[3][3]) _CUPS_API_1_2;
+extern void cupsImageSetRasterColorSpace(cups_cspace_t cs) _CUPS_API_1_2;
+extern void cupsImageWhiteToBlack(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+extern void cupsImageWhiteToCMY(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+extern void cupsImageWhiteToCMYK(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+extern void cupsImageWhiteToRGB(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+extern void cupsImageWhiteToWhite(const cups_ib_t *in,
+ cups_ib_t *out, int count) _CUPS_API_1_2;
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_IMAGE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/imagetops.c b/filter/imagetops.c
new file mode 100644
index 000000000..3662fdb32
--- /dev/null
+++ b/filter/imagetops.c
@@ -0,0 +1,1078 @@
+/*
+ * "$Id$"
+ *
+ * Image file to PostScript filter for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry...
+ * ps_hex() - Print binary data as a series of hexadecimal numbers.
+ * ps_ascii85() - Print binary data as a series of base-85 numbers.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "common.h"
+#include "image.h"
+#include <math.h>
+#include <cups/language-private.h>
+#include <signal.h>
+
+
+/*
+ * Globals...
+ */
+
+int Flip = 0, /* Flip/mirror pages */
+ XPosition = 0, /* Horizontal position on page */
+ YPosition = 0, /* Vertical position on page */
+ Collate = 0, /* Collate copies? */
+ Copies = 1; /* Number of copies */
+
+
+/*
+ * Local functions...
+ */
+
+static void ps_hex(cups_ib_t *, int, int);
+static void ps_ascii85(cups_ib_t *, int, int);
+
+
+/*
+ * 'main()' - Main entry...
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ cups_image_t *img; /* Image to print */
+ float xprint, /* Printable area */
+ yprint,
+ xinches, /* Total size in inches */
+ yinches;
+ float xsize, /* Total size in points */
+ ysize,
+ xsize2,
+ ysize2;
+ float aspect; /* Aspect ratio */
+ int xpages, /* # x pages */
+ ypages, /* # y pages */
+ xpage, /* Current x page */
+ ypage, /* Current y page */
+ page; /* Current page number */
+ int xc0, yc0, /* Corners of the page in image coords */
+ xc1, yc1;
+ cups_ib_t *row; /* Current row */
+ int y; /* Current Y coordinate in image */
+ int colorspace; /* Output colorspace */
+ int out_offset, /* Offset into output buffer */
+ out_length; /* Length of output buffer */
+ ppd_file_t *ppd; /* PPD file */
+ ppd_choice_t *choice; /* PPD option choice */
+ int num_options; /* Number of print options */
+ cups_option_t *options; /* Print options */
+ const char *val; /* Option value */
+ int slowcollate; /* Collate copies the slow way */
+ float g; /* Gamma correction value */
+ float b; /* Brightness factor */
+ float zoom; /* Zoom facter */
+ int xppi, yppi; /* Pixels-per-inch */
+ int hue, sat; /* Hue and saturation adjustment */
+ int realcopies, /* Real copies being printed */
+ emit_jcl; /* Emit JCL? */
+ float left, top; /* Left and top of image */
+ char filename[1024]; /* Name of file to print */
+ time_t curtime; /* Current time */
+ struct tm *curtm; /* Current date */
+ char curdate[255]; /* Current date string */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Ignore broken pipe signals...
+ */
+
+ signal(SIGPIPE, SIG_IGN);
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options file"),
+ argv[0]);
+ return (1);
+ }
+
+ /*
+ * Copy stdin as needed...
+ */
+
+ if (argc == 6)
+ {
+ int fd; /* File to write to */
+ char buffer[8192]; /* Buffer to read into */
+ int bytes; /* # of bytes to read */
+
+
+ if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to copy print file"));
+ return (1);
+ }
+
+ fprintf(stderr, "DEBUG: imagetops - copying to temp print file \"%s\".\n",
+ filename);
+
+ while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
+ write(fd, buffer, bytes);
+
+ close(fd);
+ }
+ else
+ strlcpy(filename, argv[6], sizeof(filename));
+
+ /*
+ * Process command-line options and write the prolog...
+ */
+
+ zoom = 0.0;
+ xppi = 0;
+ yppi = 0;
+ hue = 0;
+ sat = 100;
+ g = 1.0;
+ b = 1.0;
+
+ Copies = atoi(argv[4]);
+
+ options = NULL;
+ num_options = cupsParseOptions(argv[5], 0, &options);
+
+ ppd = SetCommonOptions(num_options, options, 0);
+
+ if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
+ {
+ /*
+ * This IPP attribute is unnecessarily complicated...
+ *
+ * single-document, separate-documents-collated-copies, and
+ * single-document-new-sheet all require collated copies.
+ *
+ * separate-documents-uncollated-copies allows for uncollated copies.
+ */
+
+ Collate = _cups_strcasecmp(val, "separate-documents-uncollated-copies") != 0;
+ }
+
+ if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
+ _cups_strcasecmp(val, "True") == 0)
+ Collate = 1;
+
+ if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
+ {
+ /*
+ * Get gamma value from 1 to 10000...
+ */
+
+ g = atoi(val) * 0.001f;
+
+ if (g < 0.001f)
+ g = 0.001f;
+ else if (g > 10.0f)
+ g = 10.0f;
+ }
+
+ if ((val = cupsGetOption("brightness", num_options, options)) != NULL)
+ {
+ /*
+ * Get brightness value from 10 to 1000.
+ */
+
+ b = atoi(val) * 0.01f;
+
+ if (b < 0.1f)
+ b = 0.1f;
+ else if (b > 10.0f)
+ b = 10.0f;
+ }
+
+ if ((val = cupsGetOption("scaling", num_options, options)) != NULL)
+ zoom = atoi(val) * 0.01;
+ else if ((val = cupsGetOption("fitplot", num_options, options)) != NULL &&
+ !_cups_strcasecmp(val, "true"))
+ zoom = 1.0;
+ else if ((val = cupsGetOption("fit-to-page", num_options, options)) != NULL &&
+ !_cups_strcasecmp(val, "true"))
+ zoom = 1.0;
+
+ if ((val = cupsGetOption("ppi", num_options, options)) != NULL)
+ if (sscanf(val, "%dx%d", &xppi, &yppi) < 2)
+ yppi = xppi;
+
+ if ((val = cupsGetOption("position", num_options, options)) != NULL)
+ {
+ if (_cups_strcasecmp(val, "center") == 0)
+ {
+ XPosition = 0;
+ YPosition = 0;
+ }
+ else if (_cups_strcasecmp(val, "top") == 0)
+ {
+ XPosition = 0;
+ YPosition = 1;
+ }
+ else if (_cups_strcasecmp(val, "left") == 0)
+ {
+ XPosition = -1;
+ YPosition = 0;
+ }
+ else if (_cups_strcasecmp(val, "right") == 0)
+ {
+ XPosition = 1;
+ YPosition = 0;
+ }
+ else if (_cups_strcasecmp(val, "top-left") == 0)
+ {
+ XPosition = -1;
+ YPosition = 1;
+ }
+ else if (_cups_strcasecmp(val, "top-right") == 0)
+ {
+ XPosition = 1;
+ YPosition = 1;
+ }
+ else if (_cups_strcasecmp(val, "bottom") == 0)
+ {
+ XPosition = 0;
+ YPosition = -1;
+ }
+ else if (_cups_strcasecmp(val, "bottom-left") == 0)
+ {
+ XPosition = -1;
+ YPosition = -1;
+ }
+ else if (_cups_strcasecmp(val, "bottom-right") == 0)
+ {
+ XPosition = 1;
+ YPosition = -1;
+ }
+ }
+
+ if ((val = cupsGetOption("saturation", num_options, options)) != NULL)
+ sat = atoi(val);
+
+ if ((val = cupsGetOption("hue", num_options, options)) != NULL)
+ hue = atoi(val);
+
+ if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL)
+ {
+ val = choice->choice;
+ choice->marked = 0;
+ }
+ else
+ val = cupsGetOption("mirror", num_options, options);
+
+ if (val && (!_cups_strcasecmp(val, "true") || !_cups_strcasecmp(val, "on") ||
+ !_cups_strcasecmp(val, "yes")))
+ Flip = 1;
+
+ if ((val = cupsGetOption("emit-jcl", num_options, options)) != NULL &&
+ (!_cups_strcasecmp(val, "false") || !_cups_strcasecmp(val, "off") ||
+ !_cups_strcasecmp(val, "no") || !strcmp(val, "0")))
+ emit_jcl = 0;
+ else
+ emit_jcl = 1;
+
+ /*
+ * Open the input image to print...
+ */
+
+ colorspace = ColorDevice ? CUPS_IMAGE_RGB_CMYK : CUPS_IMAGE_WHITE;
+
+ img = cupsImageOpen(filename, colorspace, CUPS_IMAGE_WHITE, sat, hue, NULL);
+
+ if (argc == 6)
+ unlink(filename);
+
+ if (img == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The print file could not be opened."));
+ ppdClose(ppd);
+ return (1);
+ }
+
+ colorspace = cupsImageGetColorSpace(img);
+
+ /*
+ * Scale as necessary...
+ */
+
+ if (zoom == 0.0 && xppi == 0)
+ {
+ xppi = cupsImageGetXPPI(img);
+ yppi = cupsImageGetYPPI(img);
+ }
+
+ if (yppi == 0)
+ yppi = xppi;
+
+ fprintf(stderr, "DEBUG: Before scaling: xppi=%d, yppi=%d, zoom=%.2f\n",
+ xppi, yppi, zoom);
+
+ if (xppi > 0)
+ {
+ /*
+ * Scale the image as neccesary to match the desired pixels-per-inch.
+ */
+
+ if (Orientation & 1)
+ {
+ xprint = (PageTop - PageBottom) / 72.0;
+ yprint = (PageRight - PageLeft) / 72.0;
+ }
+ else
+ {
+ xprint = (PageRight - PageLeft) / 72.0;
+ yprint = (PageTop - PageBottom) / 72.0;
+ }
+
+ fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n",
+ xprint, yprint);
+
+ xinches = (float)cupsImageGetWidth(img) / (float)xppi;
+ yinches = (float)cupsImageGetHeight(img) / (float)yppi;
+
+ fprintf(stderr, "DEBUG: Image size is %.1f x %.1f inches...\n",
+ xinches, yinches);
+
+ if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL)
+ {
+ xinches = xinches * atoi(val) / 100;
+ yinches = yinches * atoi(val) / 100;
+ }
+
+ if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
+ cupsGetOption("landscape", num_options, options) == NULL)
+ {
+ /*
+ * Rotate the image if it will fit landscape but not portrait...
+ */
+
+ fputs("DEBUG: Auto orientation...\n", stderr);
+
+ if ((xinches > xprint || yinches > yprint) &&
+ xinches <= yprint && yinches <= xprint)
+ {
+ /*
+ * Rotate the image as needed...
+ */
+
+ fputs("DEBUG: Using landscape orientation...\n", stderr);
+
+ Orientation = (Orientation + 1) & 3;
+ xsize = yprint;
+ yprint = xprint;
+ xprint = xsize;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Scale percentage of page size...
+ */
+
+ xprint = (PageRight - PageLeft) / 72.0;
+ yprint = (PageTop - PageBottom) / 72.0;
+ aspect = (float)cupsImageGetYPPI(img) / (float)cupsImageGetXPPI(img);
+
+ fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n",
+ xprint, yprint);
+
+ fprintf(stderr, "DEBUG: cupsImageGetXPPI(img) = %d, cupsImageGetYPPI(img) = %d, aspect = %f\n",
+ cupsImageGetXPPI(img), cupsImageGetYPPI(img), aspect);
+
+ xsize = xprint * zoom;
+ ysize = xsize * cupsImageGetHeight(img) / cupsImageGetWidth(img) / aspect;
+
+ if (ysize > (yprint * zoom))
+ {
+ ysize = yprint * zoom;
+ xsize = ysize * cupsImageGetWidth(img) * aspect / cupsImageGetHeight(img);
+ }
+
+ xsize2 = yprint * zoom;
+ ysize2 = xsize2 * cupsImageGetHeight(img) / cupsImageGetWidth(img) / aspect;
+
+ if (ysize2 > (xprint * zoom))
+ {
+ ysize2 = xprint * zoom;
+ xsize2 = ysize2 * cupsImageGetWidth(img) * aspect / cupsImageGetHeight(img);
+ }
+
+ fprintf(stderr, "DEBUG: Portrait size is %.2f x %.2f inches\n", xsize, ysize);
+ fprintf(stderr, "DEBUG: Landscape size is %.2f x %.2f inches\n", xsize2, ysize2);
+
+ if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
+ cupsGetOption("landscape", num_options, options) == NULL)
+ {
+ /*
+ * Choose the rotation with the largest area, but prefer
+ * portrait if they are equal...
+ */
+
+ fputs("DEBUG: Auto orientation...\n", stderr);
+
+ if ((xsize * ysize) < (xsize2 * xsize2))
+ {
+ /*
+ * Do landscape orientation...
+ */
+
+ fputs("DEBUG: Using landscape orientation...\n", stderr);
+
+ Orientation = 1;
+ xinches = xsize2;
+ yinches = ysize2;
+ xprint = (PageTop - PageBottom) / 72.0;
+ yprint = (PageRight - PageLeft) / 72.0;
+ }
+ else
+ {
+ /*
+ * Do portrait orientation...
+ */
+
+ fputs("DEBUG: Using portrait orientation...\n", stderr);
+
+ Orientation = 0;
+ xinches = xsize;
+ yinches = ysize;
+ }
+ }
+ else if (Orientation & 1)
+ {
+ fputs("DEBUG: Using landscape orientation...\n", stderr);
+
+ xinches = xsize2;
+ yinches = ysize2;
+ xprint = (PageTop - PageBottom) / 72.0;
+ yprint = (PageRight - PageLeft) / 72.0;
+ }
+ else
+ {
+ fputs("DEBUG: Using portrait orientation...\n", stderr);
+
+ xinches = xsize;
+ yinches = ysize;
+ xprint = (PageRight - PageLeft) / 72.0;
+ yprint = (PageTop - PageBottom) / 72.0;
+ }
+ }
+
+ /*
+ * Compute the number of pages to print and the size of the image on each
+ * page...
+ */
+
+ xpages = ceil(xinches / xprint);
+ ypages = ceil(yinches / yprint);
+
+ xprint = xinches / xpages;
+ yprint = yinches / ypages;
+
+ fprintf(stderr, "DEBUG: xpages = %dx%.2fin, ypages = %dx%.2fin\n",
+ xpages, xprint, ypages, yprint);
+
+ /*
+ * Update the page size for custom sizes...
+ */
+
+ if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL &&
+ _cups_strcasecmp(choice->choice, "Custom") == 0)
+ {
+ float width, /* New width in points */
+ length; /* New length in points */
+ char s[255]; /* New custom page size... */
+
+
+ /*
+ * Use the correct width and length for the current orientation...
+ */
+
+ if (Orientation & 1)
+ {
+ width = yprint * 72.0;
+ length = xprint * 72.0;
+ }
+ else
+ {
+ width = xprint * 72.0;
+ length = yprint * 72.0;
+ }
+
+ /*
+ * Add margins to page size...
+ */
+
+ width += ppd->custom_margins[0] + ppd->custom_margins[2];
+ length += ppd->custom_margins[1] + ppd->custom_margins[3];
+
+ /*
+ * Enforce minimums...
+ */
+
+ if (width < ppd->custom_min[0])
+ width = ppd->custom_min[0];
+
+ if (length < ppd->custom_min[1])
+ length = ppd->custom_min[1];
+
+ fprintf(stderr, "DEBUG: Updated custom page size to %.2f x %.2f inches...\n",
+ width / 72.0, length / 72.0);
+
+ /*
+ * Set the new custom size...
+ */
+
+ sprintf(s, "Custom.%.0fx%.0f", width, length);
+ ppdMarkOption(ppd, "PageSize", s);
+
+ /*
+ * Update page variables...
+ */
+
+ PageWidth = width;
+ PageLength = length;
+ PageLeft = ppd->custom_margins[0];
+ PageRight = width - ppd->custom_margins[2];
+ PageBottom = ppd->custom_margins[1];
+ PageTop = length - ppd->custom_margins[3];
+ }
+
+ /*
+ * See if we need to collate, and if so how we need to do it...
+ */
+
+ if (xpages == 1 && ypages == 1)
+ Collate = 0;
+
+ slowcollate = Collate && ppdFindOption(ppd, "Collate") == NULL;
+
+ if (Copies > 1 && !slowcollate)
+ {
+ realcopies = Copies;
+ Copies = 1;
+ }
+ else
+ realcopies = 1;
+
+ /*
+ * Write any "exit server" options that have been selected...
+ */
+
+ ppdEmit(ppd, stdout, PPD_ORDER_EXIT);
+
+ /*
+ * Write any JCL commands that are needed to print PostScript code...
+ */
+
+ if (emit_jcl)
+ ppdEmitJCL(ppd, stdout, atoi(argv[1]), argv[2], argv[3]);
+
+ /*
+ * Start sending the document with any commands needed...
+ */
+
+ curtime = time(NULL);
+ curtm = localtime(&curtime);
+
+ puts("%!PS-Adobe-3.0");
+ printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom,
+ PageRight, PageTop);
+ printf("%%%%LanguageLevel: %d\n", LanguageLevel);
+ printf("%%%%Pages: %d\n", xpages * ypages * Copies);
+ puts("%%DocumentData: Clean7Bit");
+ puts("%%DocumentNeededResources: font Helvetica-Bold");
+ puts("%%Creator: imagetops/" CUPS_SVERSION);
+ strftime(curdate, sizeof(curdate), "%c", curtm);
+ printf("%%%%CreationDate: %s\n", curdate);
+ WriteTextComment("Title", argv[3]);
+ WriteTextComment("For", argv[2]);
+ if (Orientation & 1)
+ puts("%%Orientation: Landscape");
+ else
+ puts("%%Orientation: Portrait");
+ puts("%%EndComments");
+ puts("%%BeginProlog");
+
+ if (ppd != NULL && ppd->patches != NULL)
+ puts(ppd->patches);
+
+ ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT);
+ ppdEmit(ppd, stdout, PPD_ORDER_ANY);
+ ppdEmit(ppd, stdout, PPD_ORDER_PROLOG);
+
+ if (g != 1.0 || b != 1.0)
+ printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
+ "ifelse %.3f mul } bind settransfer\n", g, b);
+
+ WriteCommon();
+ switch (Orientation)
+ {
+ case 0 :
+ WriteLabelProlog(cupsGetOption("page-label", num_options, options),
+ PageBottom, PageTop, PageWidth);
+ break;
+
+ case 1 :
+ WriteLabelProlog(cupsGetOption("page-label", num_options, options),
+ PageLeft, PageRight, PageLength);
+ break;
+
+ case 2 :
+ WriteLabelProlog(cupsGetOption("page-label", num_options, options),
+ PageLength - PageTop, PageLength - PageBottom,
+ PageWidth);
+ break;
+
+ case 3 :
+ WriteLabelProlog(cupsGetOption("page-label", num_options, options),
+ PageWidth - PageRight, PageWidth - PageLeft,
+ PageLength);
+ break;
+ }
+
+ if (realcopies > 1)
+ {
+ if (ppd == NULL || ppd->language_level == 1)
+ printf("/#copies %d def\n", realcopies);
+ else
+ printf("<</NumCopies %d>>setpagedevice\n", realcopies);
+ }
+
+ puts("%%EndProlog");
+
+ /*
+ * Output the pages...
+ */
+
+ row = malloc(cupsImageGetWidth(img) * abs(colorspace) + 3);
+
+ fprintf(stderr, "DEBUG: XPosition=%d, YPosition=%d, Orientation=%d\n",
+ XPosition, YPosition, Orientation);
+ fprintf(stderr, "DEBUG: xprint=%.0f, yprint=%.0f\n", xprint, yprint);
+ fprintf(stderr, "DEBUG: PageLeft=%.0f, PageRight=%.0f, PageWidth=%.0f\n",
+ PageLeft, PageRight, PageWidth);
+ fprintf(stderr, "DEBUG: PageBottom=%.0f, PageTop=%.0f, PageLength=%.0f\n",
+ PageBottom, PageTop, PageLength);
+
+ switch (Orientation)
+ {
+ default :
+ switch (XPosition)
+ {
+ case -1 :
+ left = PageLeft;
+ break;
+ default :
+ left = (PageRight + PageLeft - xprint * 72) / 2;
+ break;
+ case 1 :
+ left = PageRight - xprint * 72;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case -1 :
+ top = PageBottom + yprint * 72;
+ break;
+ default :
+ top = (PageTop + PageBottom + yprint * 72) / 2;
+ break;
+ case 1 :
+ top = PageTop;
+ break;
+ }
+ break;
+
+ case 1 :
+ switch (XPosition)
+ {
+ case -1 :
+ left = PageBottom;
+ break;
+ default :
+ left = (PageTop + PageBottom - xprint * 72) / 2;
+ break;
+ case 1 :
+ left = PageTop - xprint * 72;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case -1 :
+ top = PageLeft + yprint * 72;
+ break;
+ default :
+ top = (PageRight + PageLeft + yprint * 72) / 2;
+ break;
+ case 1 :
+ top = PageRight;
+ break;
+ }
+ break;
+
+ case 2 :
+ switch (XPosition)
+ {
+ case 1 :
+ left = PageLeft;
+ break;
+ default :
+ left = (PageRight + PageLeft - xprint * 72) / 2;
+ break;
+ case -1 :
+ left = PageRight - xprint * 72;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case 1 :
+ top = PageBottom + yprint * 72;
+ break;
+ default :
+ top = (PageTop + PageBottom + yprint * 72) / 2;
+ break;
+ case -1 :
+ top = PageTop;
+ break;
+ }
+ break;
+
+ case 3 :
+ switch (XPosition)
+ {
+ case 1 :
+ left = PageBottom;
+ break;
+ default :
+ left = (PageTop + PageBottom - xprint * 72) / 2;
+ break;
+ case -1 :
+ left = PageTop - xprint * 72;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case 1 :
+ top = PageLeft + yprint * 72;
+ break;
+ default :
+ top = (PageRight + PageLeft + yprint * 72) / 2;
+ break;
+ case -1 :
+ top = PageRight;
+ break;
+ }
+ break;
+ }
+
+ fprintf(stderr, "DEBUG: left=%.2f, top=%.2f\n", left, top);
+
+ for (page = 1; Copies > 0; Copies --)
+ for (xpage = 0; xpage < xpages; xpage ++)
+ for (ypage = 0; ypage < ypages; ypage ++, page ++)
+ {
+ if (ppd && ppd->num_filters == 0)
+ fprintf(stderr, "PAGE: %d %d\n", page, realcopies);
+
+ _cupsLangPrintFilter(stderr, "INFO", _("Printing page %d."), page);
+
+ printf("%%%%Page: %d %d\n", page, page);
+
+ ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
+
+ puts("gsave");
+
+ if (Flip)
+ printf("%.0f 0 translate -1 1 scale\n", PageWidth);
+
+ switch (Orientation)
+ {
+ case 1 : /* Landscape */
+ printf("%.0f 0 translate 90 rotate\n", PageWidth);
+ break;
+ case 2 : /* Reverse Portrait */
+ printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength);
+ break;
+ case 3 : /* Reverse Landscape */
+ printf("0 %.0f translate -90 rotate\n", PageLength);
+ break;
+ }
+
+ puts("gsave");
+
+ xc0 = cupsImageGetWidth(img) * xpage / xpages;
+ xc1 = cupsImageGetWidth(img) * (xpage + 1) / xpages - 1;
+ yc0 = cupsImageGetHeight(img) * ypage / ypages;
+ yc1 = cupsImageGetHeight(img) * (ypage + 1) / ypages - 1;
+
+ printf("%.1f %.1f translate\n", left, top);
+
+ printf("%.3f %.3f scale\n\n",
+ xprint * 72.0 / (xc1 - xc0 + 1),
+ yprint * 72.0 / (yc1 - yc0 + 1));
+
+ if (LanguageLevel == 1)
+ {
+ printf("/picture %d string def\n", (xc1 - xc0 + 1) * abs(colorspace));
+ printf("%d %d 8[1 0 0 -1 0 1]", (xc1 - xc0 + 1), (yc1 - yc0 + 1));
+
+ if (colorspace == CUPS_IMAGE_WHITE)
+ puts("{currentfile picture readhexstring pop} image");
+ else
+ printf("{currentfile picture readhexstring pop} false %d colorimage\n",
+ abs(colorspace));
+
+ for (y = yc0; y <= yc1; y ++)
+ {
+ cupsImageGetRow(img, xc0, y, xc1 - xc0 + 1, row);
+ ps_hex(row, (xc1 - xc0 + 1) * abs(colorspace), y == yc1);
+ }
+ }
+ else
+ {
+ switch (colorspace)
+ {
+ case CUPS_IMAGE_WHITE :
+ puts("/DeviceGray setcolorspace");
+ break;
+ case CUPS_IMAGE_RGB :
+ puts("/DeviceRGB setcolorspace");
+ break;
+ case CUPS_IMAGE_CMYK :
+ puts("/DeviceCMYK setcolorspace");
+ break;
+ }
+
+ printf("<<"
+ "/ImageType 1"
+ "/Width %d"
+ "/Height %d"
+ "/BitsPerComponent 8",
+ xc1 - xc0 + 1, yc1 - yc0 + 1);
+
+ switch (colorspace)
+ {
+ case CUPS_IMAGE_WHITE :
+ fputs("/Decode[0 1]", stdout);
+ break;
+ case CUPS_IMAGE_RGB :
+ fputs("/Decode[0 1 0 1 0 1]", stdout);
+ break;
+ case CUPS_IMAGE_CMYK :
+ fputs("/Decode[0 1 0 1 0 1 0 1]", stdout);
+ break;
+ }
+
+ fputs("\n/DataSource currentfile/ASCII85Decode filter", stdout);
+
+ if (((xc1 - xc0 + 1) / xprint) < 100.0)
+ fputs("/Interpolate true", stdout);
+
+ puts("/ImageMatrix[1 0 0 -1 0 1]>>image");
+
+ for (y = yc0, out_offset = 0; y <= yc1; y ++)
+ {
+ cupsImageGetRow(img, xc0, y, xc1 - xc0 + 1, row + out_offset);
+
+ out_length = (xc1 - xc0 + 1) * abs(colorspace) + out_offset;
+ out_offset = out_length & 3;
+
+ ps_ascii85(row, out_length, y == yc1);
+
+ if (out_offset > 0)
+ memcpy(row, row + out_length - out_offset, out_offset);
+ }
+ }
+
+ puts("grestore");
+ WriteLabels(0);
+ puts("grestore");
+ puts("showpage");
+ }
+
+ puts("%%EOF");
+
+ /*
+ * End the job with the appropriate JCL command or CTRL-D otherwise.
+ */
+
+ if (emit_jcl)
+ {
+ if (ppd && ppd->jcl_end)
+ ppdEmitJCLEnd(ppd, stdout);
+ else
+ putchar(0x04);
+ }
+
+ /*
+ * Close files...
+ */
+
+ cupsImageClose(img);
+ ppdClose(ppd);
+
+ return (0);
+}
+
+
+/*
+ * 'ps_hex()' - Print binary data as a series of hexadecimal numbers.
+ */
+
+static void
+ps_hex(cups_ib_t *data, /* I - Data to print */
+ int length, /* I - Number of bytes to print */
+ int last_line) /* I - Last line of raster data? */
+{
+ static int col = 0; /* Current column */
+ static char *hex = "0123456789ABCDEF";
+ /* Hex digits */
+
+
+ while (length > 0)
+ {
+ /*
+ * Put the hex chars out to the file; note that we don't use printf()
+ * for speed reasons...
+ */
+
+ putchar(hex[*data >> 4]);
+ putchar(hex[*data & 15]);
+
+ data ++;
+ length --;
+
+ col += 2;
+ if (col > 78)
+ {
+ putchar('\n');
+ col = 0;
+ }
+ }
+
+ if (last_line && col)
+ {
+ putchar('\n');
+ col = 0;
+ }
+}
+
+
+/*
+ * 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
+ */
+
+static void
+ps_ascii85(cups_ib_t *data, /* I - Data to print */
+ int length, /* I - Number of bytes to print */
+ int last_line) /* I - Last line of raster data? */
+{
+ unsigned b; /* Binary data word */
+ unsigned char c[5]; /* ASCII85 encoded chars */
+ static int col = 0; /* Current column */
+
+
+ while (length > 3)
+ {
+ b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
+
+ if (b == 0)
+ {
+ putchar('z');
+ col ++;
+ }
+ else
+ {
+ c[4] = (b % 85) + '!';
+ b /= 85;
+ c[3] = (b % 85) + '!';
+ b /= 85;
+ c[2] = (b % 85) + '!';
+ b /= 85;
+ c[1] = (b % 85) + '!';
+ b /= 85;
+ c[0] = b + '!';
+
+ fwrite(c, 5, 1, stdout);
+ col += 5;
+ }
+
+ data += 4;
+ length -= 4;
+
+ if (col >= 75)
+ {
+ putchar('\n');
+ col = 0;
+ }
+ }
+
+ if (last_line)
+ {
+ if (length > 0)
+ {
+ memset(data + length, 0, 4 - length);
+ b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
+
+ c[4] = (b % 85) + '!';
+ b /= 85;
+ c[3] = (b % 85) + '!';
+ b /= 85;
+ c[2] = (b % 85) + '!';
+ b /= 85;
+ c[1] = (b % 85) + '!';
+ b /= 85;
+ c[0] = b + '!';
+
+ fwrite(c, length + 1, 1, stdout);
+ }
+
+ puts("~>");
+ col = 0;
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/imagetoraster.c b/filter/imagetoraster.c
new file mode 100644
index 000000000..90ffd7fa4
--- /dev/null
+++ b/filter/imagetoraster.c
@@ -0,0 +1,4367 @@
+/*
+ * "$Id$"
+ *
+ * Image file to raster filter for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry...
+ * blank_line() - Clear a line buffer to the blank value...
+ * format_CMY() - Convert image data to CMY.
+ * format_CMYK() - Convert image data to CMYK.
+ * format_K() - Convert image data to black.
+ * format_KCMY() - Convert image data to KCMY.
+ * format_KCMYcm() - Convert image data to KCMYcm.
+ * format_RGBA() - Convert image data to RGBA/RGBW.
+ * format_W() - Convert image data to luminance.
+ * format_YMC() - Convert image data to YMC.
+ * format_YMCK() - Convert image data to YMCK.
+ * make_lut() - Make a lookup table given gamma and brightness values.
+ * raster_cb() - Validate the page header.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "common.h"
+#include "image-private.h"
+#include <unistd.h>
+#include <math.h>
+#include <cups/language-private.h>
+#include <signal.h>
+
+
+/*
+ * Globals...
+ */
+
+int Flip = 0, /* Flip/mirror pages */
+ XPosition = 0, /* Horizontal position on page */
+ YPosition = 0, /* Vertical position on page */
+ Collate = 0, /* Collate copies? */
+ Copies = 1; /* Number of copies */
+int Floyd16x16[16][16] = /* Traditional Floyd ordered dither */
+ {
+ { 0, 128, 32, 160, 8, 136, 40, 168,
+ 2, 130, 34, 162, 10, 138, 42, 170 },
+ { 192, 64, 224, 96, 200, 72, 232, 104,
+ 194, 66, 226, 98, 202, 74, 234, 106 },
+ { 48, 176, 16, 144, 56, 184, 24, 152,
+ 50, 178, 18, 146, 58, 186, 26, 154 },
+ { 240, 112, 208, 80, 248, 120, 216, 88,
+ 242, 114, 210, 82, 250, 122, 218, 90 },
+ { 12, 140, 44, 172, 4, 132, 36, 164,
+ 14, 142, 46, 174, 6, 134, 38, 166 },
+ { 204, 76, 236, 108, 196, 68, 228, 100,
+ 206, 78, 238, 110, 198, 70, 230, 102 },
+ { 60, 188, 28, 156, 52, 180, 20, 148,
+ 62, 190, 30, 158, 54, 182, 22, 150 },
+ { 252, 124, 220, 92, 244, 116, 212, 84,
+ 254, 126, 222, 94, 246, 118, 214, 86 },
+ { 3, 131, 35, 163, 11, 139, 43, 171,
+ 1, 129, 33, 161, 9, 137, 41, 169 },
+ { 195, 67, 227, 99, 203, 75, 235, 107,
+ 193, 65, 225, 97, 201, 73, 233, 105 },
+ { 51, 179, 19, 147, 59, 187, 27, 155,
+ 49, 177, 17, 145, 57, 185, 25, 153 },
+ { 243, 115, 211, 83, 251, 123, 219, 91,
+ 241, 113, 209, 81, 249, 121, 217, 89 },
+ { 15, 143, 47, 175, 7, 135, 39, 167,
+ 13, 141, 45, 173, 5, 133, 37, 165 },
+ { 207, 79, 239, 111, 199, 71, 231, 103,
+ 205, 77, 237, 109, 197, 69, 229, 101 },
+ { 63, 191, 31, 159, 55, 183, 23, 151,
+ 61, 189, 29, 157, 53, 181, 21, 149 },
+ { 254, 127, 223, 95, 247, 119, 215, 87,
+ 253, 125, 221, 93, 245, 117, 213, 85 }
+ };
+int Floyd8x8[8][8] =
+ {
+ { 0, 32, 8, 40, 2, 34, 10, 42 },
+ { 48, 16, 56, 24, 50, 18, 58, 26 },
+ { 12, 44, 4, 36, 14, 46, 6, 38 },
+ { 60, 28, 52, 20, 62, 30, 54, 22 },
+ { 3, 35, 11, 43, 1, 33, 9, 41 },
+ { 51, 19, 59, 27, 49, 17, 57, 25 },
+ { 15, 47, 7, 39, 13, 45, 5, 37 },
+ { 63, 31, 55, 23, 61, 29, 53, 21 }
+ };
+int Floyd4x4[4][4] =
+ {
+ { 0, 8, 2, 10 },
+ { 12, 4, 14, 6 },
+ { 3, 11, 1, 9 },
+ { 15, 7, 13, 5 }
+ };
+
+cups_ib_t OnPixels[256], /* On-pixel LUT */
+ OffPixels[256]; /* Off-pixel LUT */
+
+
+/*
+ * Local functions...
+ */
+
+static void blank_line(cups_page_header2_t *header, unsigned char *row);
+static void format_CMY(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1);
+static void format_CMYK(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1);
+static void format_K(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1);
+static void format_KCMYcm(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1);
+static void format_KCMY(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1);
+#define format_RGB format_CMY
+static void format_RGBA(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1);
+static void format_W(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1);
+static void format_YMC(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1);
+static void format_YMCK(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1);
+static void make_lut(cups_ib_t *, int, float, float);
+static int raster_cb(cups_page_header2_t *header, int preferred_bits);
+
+
+/*
+ * 'main()' - Main entry...
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ cups_image_t *img; /* Image to print */
+ float xprint, /* Printable area */
+ yprint,
+ xinches, /* Total size in inches */
+ yinches;
+ float xsize, /* Total size in points */
+ ysize,
+ xsize2,
+ ysize2;
+ float aspect; /* Aspect ratio */
+ int xpages, /* # x pages */
+ ypages, /* # y pages */
+ xpage, /* Current x page */
+ ypage, /* Current y page */
+ xtemp, /* Bitmap width in pixels */
+ ytemp, /* Bitmap height in pixels */
+ page; /* Current page number */
+ int xc0, yc0, /* Corners of the page in image coords */
+ xc1, yc1;
+ ppd_file_t *ppd; /* PPD file */
+ ppd_choice_t *choice; /* PPD option choice */
+ char *resolution, /* Output resolution */
+ *media_type; /* Media type */
+ ppd_profile_t *profile; /* Color profile */
+ ppd_profile_t userprofile; /* User-specified profile */
+ cups_raster_t *ras; /* Raster stream */
+ cups_page_header2_t header; /* Page header */
+ int num_options; /* Number of print options */
+ cups_option_t *options; /* Print options */
+ const char *val; /* Option value */
+ int slowcollate, /* Collate copies the slow way */
+ slowcopies; /* Make copies the "slow" way? */
+ float g; /* Gamma correction value */
+ float b; /* Brightness factor */
+ float zoom; /* Zoom facter */
+ int xppi, yppi; /* Pixels-per-inch */
+ int hue, sat; /* Hue and saturation adjustment */
+ cups_izoom_t *z; /* Image zoom buffer */
+ cups_iztype_t zoom_type; /* Image zoom type */
+ int primary, /* Primary image colorspace */
+ secondary; /* Secondary image colorspace */
+ cups_ib_t *row, /* Current row */
+ *r0, /* Top row */
+ *r1; /* Bottom row */
+ int y, /* Current Y coordinate on page */
+ iy, /* Current Y coordinate in image */
+ last_iy, /* Previous Y coordinate in image */
+ yerr0, /* Top Y error value */
+ yerr1; /* Bottom Y error value */
+ cups_ib_t lut[256]; /* Gamma/brightness LUT */
+ int plane, /* Current color plane */
+ num_planes; /* Number of color planes */
+ char filename[1024]; /* Name of file to print */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Ignore broken pipe signals...
+ */
+
+ signal(SIGPIPE, SIG_IGN);
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options file"),
+ argv[0]);
+ return (1);
+ }
+
+ /*
+ * See if we need to use the imagetops and pstoraster filters instead...
+ */
+
+ options = NULL;
+ num_options = cupsParseOptions(argv[5], 0, &options);
+
+ if (getenv("CLASSIFICATION") ||
+ cupsGetOption("page-label", num_options, options))
+ {
+ /*
+ * Yes, fork a copy of pstoraster and then transfer control to imagetops...
+ */
+
+ int mypipes[2]; /* New pipes for imagetops | pstoraster */
+ int pid; /* PID of pstoraster */
+
+
+ cupsFreeOptions(num_options, options);
+
+ if (pipe(mypipes))
+ {
+ _cupsLangPrintError("ERROR", _("Unable to create pipes for filters"));
+ return (errno);
+ }
+
+ if ((pid = fork()) == 0)
+ {
+ /*
+ * Child process for pstoraster... Assign new pipe input to pstoraster...
+ */
+
+ dup2(mypipes[0], 0);
+ close(mypipes[0]);
+ close(mypipes[1]);
+
+ execlp("pstoraster", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
+ NULL);
+ return (errno);
+ }
+ else if (pid < 0)
+ {
+ /*
+ * Error!
+ */
+
+ _cupsLangPrintError("ERROR", _("Unable to fork filter"));
+ return (errno);
+ }
+
+ /*
+ * Update stdout so it points at the new pstoraster...
+ */
+
+ dup2(mypipes[1], 1);
+ close(mypipes[0]);
+ close(mypipes[1]);
+
+ /*
+ * Run imagetops to get the classification or page labeling that was
+ * requested...
+ */
+
+ execlp("imagetops", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
+ argv[6], NULL);
+ return (errno);
+ }
+
+ /*
+ * Copy stdin as needed...
+ */
+
+ if (argc == 6)
+ {
+ int fd; /* File to write to */
+ char buffer[8192]; /* Buffer to read into */
+ int bytes; /* # of bytes to read */
+
+
+ if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to copy print file"));
+ return (1);
+ }
+
+ fprintf(stderr,
+ "DEBUG: imagetoraster - copying to temp print file \"%s\".\n",
+ filename);
+
+ while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
+ write(fd, buffer, bytes);
+
+ close(fd);
+ }
+ else
+ strlcpy(filename, argv[6], sizeof(filename));
+
+ /*
+ * Process command-line options and write the prolog...
+ */
+
+ zoom = 0.0;
+ xppi = 0;
+ yppi = 0;
+ hue = 0;
+ sat = 100;
+ g = 1.0;
+ b = 1.0;
+
+ Copies = atoi(argv[4]);
+
+ ppd = SetCommonOptions(num_options, options, 0);
+
+ if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
+ {
+ /*
+ * This IPP attribute is unnecessarily complicated...
+ *
+ * single-document, separate-documents-collated-copies, and
+ * single-document-new-sheet all require collated copies.
+ *
+ * separate-documents-collated-copies allows for uncollated copies.
+ */
+
+ Collate = _cups_strcasecmp(val, "separate-documents-collated-copies") != 0;
+ }
+
+ if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
+ _cups_strcasecmp(val, "True") == 0)
+ Collate = 1;
+
+ if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
+ {
+ /*
+ * Get gamma value from 1 to 10000...
+ */
+
+ g = atoi(val) * 0.001f;
+
+ if (g < 0.001f)
+ g = 0.001f;
+ else if (g > 10.0f)
+ g = 10.0f;
+ }
+
+ if ((val = cupsGetOption("brightness", num_options, options)) != NULL)
+ {
+ /*
+ * Get brightness value from 10 to 1000.
+ */
+
+ b = atoi(val) * 0.01f;
+
+ if (b < 0.1f)
+ b = 0.1f;
+ else if (b > 10.0f)
+ b = 10.0f;
+ }
+
+ if ((val = cupsGetOption("scaling", num_options, options)) != NULL)
+ zoom = atoi(val) * 0.01;
+ else if ((val = cupsGetOption("fitplot", num_options, options)) != NULL &&
+ !_cups_strcasecmp(val, "true"))
+ zoom = 1.0;
+ else if ((val = cupsGetOption("fit-to-page", num_options, options)) != NULL &&
+ !_cups_strcasecmp(val, "true"))
+ zoom = 1.0;
+
+ if ((val = cupsGetOption("ppi", num_options, options)) != NULL)
+ if (sscanf(val, "%dx%d", &xppi, &yppi) < 2)
+ yppi = xppi;
+
+ if ((val = cupsGetOption("position", num_options, options)) != NULL)
+ {
+ if (_cups_strcasecmp(val, "center") == 0)
+ {
+ XPosition = 0;
+ YPosition = 0;
+ }
+ else if (_cups_strcasecmp(val, "top") == 0)
+ {
+ XPosition = 0;
+ YPosition = 1;
+ }
+ else if (_cups_strcasecmp(val, "left") == 0)
+ {
+ XPosition = -1;
+ YPosition = 0;
+ }
+ else if (_cups_strcasecmp(val, "right") == 0)
+ {
+ XPosition = 1;
+ YPosition = 0;
+ }
+ else if (_cups_strcasecmp(val, "top-left") == 0)
+ {
+ XPosition = -1;
+ YPosition = 1;
+ }
+ else if (_cups_strcasecmp(val, "top-right") == 0)
+ {
+ XPosition = 1;
+ YPosition = 1;
+ }
+ else if (_cups_strcasecmp(val, "bottom") == 0)
+ {
+ XPosition = 0;
+ YPosition = -1;
+ }
+ else if (_cups_strcasecmp(val, "bottom-left") == 0)
+ {
+ XPosition = -1;
+ YPosition = -1;
+ }
+ else if (_cups_strcasecmp(val, "bottom-right") == 0)
+ {
+ XPosition = 1;
+ YPosition = -1;
+ }
+ }
+
+ if ((val = cupsGetOption("saturation", num_options, options)) != NULL)
+ sat = atoi(val);
+
+ if ((val = cupsGetOption("hue", num_options, options)) != NULL)
+ hue = atoi(val);
+
+ if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL)
+ {
+ val = choice->choice;
+ choice->marked = 0;
+ }
+ else
+ val = cupsGetOption("mirror", num_options, options);
+
+ if (val && (!_cups_strcasecmp(val, "true") || !_cups_strcasecmp(val, "on") ||
+ !_cups_strcasecmp(val, "yes")))
+ Flip = 1;
+
+ /*
+ * Set the needed options in the page header...
+ */
+
+ if (cupsRasterInterpretPPD(&header, ppd, num_options, options, raster_cb))
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The page setup information was not valid."));
+ fprintf(stderr, "DEBUG: %s\n", cupsRasterErrorString());
+ return (1);
+ }
+
+ /*
+ * Get the media type and resolution that have been chosen...
+ */
+
+ if ((choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL)
+ media_type = choice->choice;
+ else
+ media_type = "";
+
+ if ((choice = ppdFindMarkedChoice(ppd, "Resolution")) != NULL)
+ resolution = choice->choice;
+ else
+ resolution = "";
+
+ /*
+ * Choose the appropriate colorspace...
+ */
+
+ switch (header.cupsColorSpace)
+ {
+ case CUPS_CSPACE_W :
+ case CUPS_CSPACE_SW :
+ if (header.cupsBitsPerColor >= 8)
+ {
+ primary = CUPS_IMAGE_WHITE;
+ secondary = CUPS_IMAGE_WHITE;
+ }
+ else
+ {
+ primary = CUPS_IMAGE_BLACK;
+ secondary = CUPS_IMAGE_BLACK;
+ }
+ break;
+
+ case CUPS_CSPACE_RGB :
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_RGBW :
+ case CUPS_CSPACE_SRGB :
+ case CUPS_CSPACE_ADOBERGB :
+ if (header.cupsBitsPerColor >= 8)
+ {
+ primary = CUPS_IMAGE_RGB;
+ secondary = CUPS_IMAGE_RGB;
+ }
+ else
+ {
+ primary = CUPS_IMAGE_CMY;
+ secondary = CUPS_IMAGE_CMY;
+ }
+ break;
+
+ case CUPS_CSPACE_K :
+ case CUPS_CSPACE_WHITE :
+ case CUPS_CSPACE_GOLD :
+ case CUPS_CSPACE_SILVER :
+ primary = CUPS_IMAGE_BLACK;
+ secondary = CUPS_IMAGE_BLACK;
+ break;
+
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_KCMYcm :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ if (header.cupsBitsPerColor == 1)
+ {
+ primary = CUPS_IMAGE_CMY;
+ secondary = CUPS_IMAGE_CMY;
+ }
+ else
+ {
+ primary = CUPS_IMAGE_CMYK;
+ secondary = CUPS_IMAGE_CMYK;
+ }
+ break;
+
+ case CUPS_CSPACE_CMY :
+ case CUPS_CSPACE_YMC :
+ primary = CUPS_IMAGE_CMY;
+ secondary = CUPS_IMAGE_CMY;
+ break;
+
+ case CUPS_CSPACE_CIEXYZ :
+ case CUPS_CSPACE_CIELab :
+ case CUPS_CSPACE_ICC1 :
+ case CUPS_CSPACE_ICC2 :
+ case CUPS_CSPACE_ICC3 :
+ case CUPS_CSPACE_ICC4 :
+ case CUPS_CSPACE_ICC5 :
+ case CUPS_CSPACE_ICC6 :
+ case CUPS_CSPACE_ICC7 :
+ case CUPS_CSPACE_ICC8 :
+ case CUPS_CSPACE_ICC9 :
+ case CUPS_CSPACE_ICCA :
+ case CUPS_CSPACE_ICCB :
+ case CUPS_CSPACE_ICCC :
+ case CUPS_CSPACE_ICCD :
+ case CUPS_CSPACE_ICCE :
+ case CUPS_CSPACE_ICCF :
+ case CUPS_CSPACE_DEVICE1 :
+ case CUPS_CSPACE_DEVICE2 :
+ case CUPS_CSPACE_DEVICE3 :
+ case CUPS_CSPACE_DEVICE4 :
+ case CUPS_CSPACE_DEVICE5 :
+ case CUPS_CSPACE_DEVICE6 :
+ case CUPS_CSPACE_DEVICE7 :
+ case CUPS_CSPACE_DEVICE8 :
+ case CUPS_CSPACE_DEVICE9 :
+ case CUPS_CSPACE_DEVICEA :
+ case CUPS_CSPACE_DEVICEB :
+ case CUPS_CSPACE_DEVICEC :
+ case CUPS_CSPACE_DEVICED :
+ case CUPS_CSPACE_DEVICEE :
+ case CUPS_CSPACE_DEVICEF :
+ fprintf(stderr, "DEBUG: Colorspace %d not supported.\n",
+ header.cupsColorSpace);
+ exit(1);
+ break;
+ }
+
+ /*
+ * Find a color profile matching the current options...
+ */
+
+ if ((val = cupsGetOption("profile", num_options, options)) != NULL)
+ {
+ profile = &userprofile;
+ sscanf(val, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f",
+ &(userprofile.density), &(userprofile.gamma),
+ userprofile.matrix[0] + 0, userprofile.matrix[0] + 1,
+ userprofile.matrix[0] + 2,
+ userprofile.matrix[1] + 0, userprofile.matrix[1] + 1,
+ userprofile.matrix[1] + 2,
+ userprofile.matrix[2] + 0, userprofile.matrix[2] + 1,
+ userprofile.matrix[2] + 2);
+
+ userprofile.density *= 0.001f;
+ userprofile.gamma *= 0.001f;
+ userprofile.matrix[0][0] *= 0.001f;
+ userprofile.matrix[0][1] *= 0.001f;
+ userprofile.matrix[0][2] *= 0.001f;
+ userprofile.matrix[1][0] *= 0.001f;
+ userprofile.matrix[1][1] *= 0.001f;
+ userprofile.matrix[1][2] *= 0.001f;
+ userprofile.matrix[2][0] *= 0.001f;
+ userprofile.matrix[2][1] *= 0.001f;
+ userprofile.matrix[2][2] *= 0.001f;
+ }
+ else if (ppd != NULL)
+ {
+ fprintf(stderr, "DEBUG: Searching for profile \"%s/%s\"...\n",
+ resolution, media_type);
+
+ for (i = 0, profile = ppd->profiles; i < ppd->num_profiles; i ++, profile ++)
+ {
+ fprintf(stderr, "DEBUG: \"%s/%s\" = ", profile->resolution,
+ profile->media_type);
+
+ if ((strcmp(profile->resolution, resolution) == 0 ||
+ profile->resolution[0] == '-') &&
+ (strcmp(profile->media_type, media_type) == 0 ||
+ profile->media_type[0] == '-'))
+ {
+ fputs("MATCH\n", stderr);
+ break;
+ }
+ else
+ fputs("no.\n", stderr);
+ }
+
+ /*
+ * If we found a color profile, use it!
+ */
+
+ if (i >= ppd->num_profiles)
+ profile = NULL;
+ }
+ else
+ profile = NULL;
+
+ if (profile)
+ cupsImageSetProfile(profile->density, profile->gamma, profile->matrix);
+
+ cupsImageSetRasterColorSpace(header.cupsColorSpace);
+
+ /*
+ * Create a gamma/brightness LUT...
+ */
+
+ make_lut(lut, primary, g, b);
+
+ /*
+ * Open the input image to print...
+ */
+
+ _cupsLangPrintFilter(stderr, "INFO", _("Loading print file."));
+
+ if (header.cupsColorSpace == CUPS_CSPACE_CIEXYZ ||
+ header.cupsColorSpace == CUPS_CSPACE_CIELab ||
+ header.cupsColorSpace >= CUPS_CSPACE_ICC1)
+ img = cupsImageOpen(filename, primary, secondary, sat, hue, NULL);
+ else
+ img = cupsImageOpen(filename, primary, secondary, sat, hue, lut);
+
+ if (argc == 6)
+ unlink(filename);
+
+ if (img == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The print file could not be opened."));
+ ppdClose(ppd);
+ return (1);
+ }
+
+ /*
+ * Scale as necessary...
+ */
+
+ if (zoom == 0.0 && xppi == 0)
+ {
+ xppi = img->xppi;
+ yppi = img->yppi;
+ }
+
+ if (yppi == 0)
+ yppi = xppi;
+
+ fprintf(stderr, "DEBUG: Before scaling: xppi=%d, yppi=%d, zoom=%.2f\n",
+ xppi, yppi, zoom);
+
+ if (xppi > 0)
+ {
+ /*
+ * Scale the image as neccesary to match the desired pixels-per-inch.
+ */
+
+ if (Orientation & 1)
+ {
+ xprint = (PageTop - PageBottom) / 72.0;
+ yprint = (PageRight - PageLeft) / 72.0;
+ }
+ else
+ {
+ xprint = (PageRight - PageLeft) / 72.0;
+ yprint = (PageTop - PageBottom) / 72.0;
+ }
+
+ fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n",
+ xprint, yprint);
+
+ xinches = (float)img->xsize / (float)xppi;
+ yinches = (float)img->ysize / (float)yppi;
+
+ fprintf(stderr, "DEBUG: Image size is %.1f x %.1f inches...\n",
+ xinches, yinches);
+
+ if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL)
+ {
+ xinches = xinches * atoi(val) / 100;
+ yinches = yinches * atoi(val) / 100;
+ }
+
+ if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
+ cupsGetOption("landscape", num_options, options) == NULL)
+ {
+ /*
+ * Rotate the image if it will fit landscape but not portrait...
+ */
+
+ fputs("DEBUG: Auto orientation...\n", stderr);
+
+ if ((xinches > xprint || yinches > yprint) &&
+ xinches <= yprint && yinches <= xprint)
+ {
+ /*
+ * Rotate the image as needed...
+ */
+
+ fputs("DEBUG: Using landscape orientation...\n", stderr);
+
+ Orientation = (Orientation + 1) & 3;
+ xsize = yprint;
+ yprint = xprint;
+ xprint = xsize;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Scale percentage of page size...
+ */
+
+ xprint = (PageRight - PageLeft) / 72.0;
+ yprint = (PageTop - PageBottom) / 72.0;
+ aspect = (float)img->yppi / (float)img->xppi;
+
+ fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n",
+ xprint, yprint);
+
+ fprintf(stderr, "DEBUG: img->xppi = %d, img->yppi = %d, aspect = %f\n",
+ img->xppi, img->yppi, aspect);
+
+ xsize = xprint * zoom;
+ ysize = xsize * img->ysize / img->xsize / aspect;
+
+ if (ysize > (yprint * zoom))
+ {
+ ysize = yprint * zoom;
+ xsize = ysize * img->xsize * aspect / img->ysize;
+ }
+
+ xsize2 = yprint * zoom;
+ ysize2 = xsize2 * img->ysize / img->xsize / aspect;
+
+ if (ysize2 > (xprint * zoom))
+ {
+ ysize2 = xprint * zoom;
+ xsize2 = ysize2 * img->xsize * aspect / img->ysize;
+ }
+
+ fprintf(stderr, "DEBUG: Portrait size is %.2f x %.2f inches\n", xsize, ysize);
+ fprintf(stderr, "DEBUG: Landscape size is %.2f x %.2f inches\n", xsize2, ysize2);
+
+ if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
+ cupsGetOption("landscape", num_options, options) == NULL)
+ {
+ /*
+ * Choose the rotation with the largest area, but prefer
+ * portrait if they are equal...
+ */
+
+ fputs("DEBUG: Auto orientation...\n", stderr);
+
+ if ((xsize * ysize) < (xsize2 * xsize2))
+ {
+ /*
+ * Do landscape orientation...
+ */
+
+ fputs("DEBUG: Using landscape orientation...\n", stderr);
+
+ Orientation = 1;
+ xinches = xsize2;
+ yinches = ysize2;
+ xprint = (PageTop - PageBottom) / 72.0;
+ yprint = (PageRight - PageLeft) / 72.0;
+ }
+ else
+ {
+ /*
+ * Do portrait orientation...
+ */
+
+ fputs("DEBUG: Using portrait orientation...\n", stderr);
+
+ Orientation = 0;
+ xinches = xsize;
+ yinches = ysize;
+ }
+ }
+ else if (Orientation & 1)
+ {
+ fputs("DEBUG: Using landscape orientation...\n", stderr);
+
+ xinches = xsize2;
+ yinches = ysize2;
+ xprint = (PageTop - PageBottom) / 72.0;
+ yprint = (PageRight - PageLeft) / 72.0;
+ }
+ else
+ {
+ fputs("DEBUG: Using portrait orientation...\n", stderr);
+
+ xinches = xsize;
+ yinches = ysize;
+ xprint = (PageRight - PageLeft) / 72.0;
+ yprint = (PageTop - PageBottom) / 72.0;
+ }
+ }
+
+ /*
+ * Compute the number of pages to print and the size of the image on each
+ * page...
+ */
+
+ xpages = ceil(xinches / xprint);
+ ypages = ceil(yinches / yprint);
+
+ xprint = xinches / xpages;
+ yprint = yinches / ypages;
+
+ fprintf(stderr, "DEBUG: xpages = %dx%.2fin, ypages = %dx%.2fin\n",
+ xpages, xprint, ypages, yprint);
+
+ /*
+ * Compute the bitmap size...
+ */
+
+ if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL &&
+ _cups_strcasecmp(choice->choice, "Custom") == 0)
+ {
+ float width, /* New width in points */
+ length; /* New length in points */
+
+
+ /*
+ * Use the correct width and length for the current orientation...
+ */
+
+ if (Orientation & 1)
+ {
+ width = yprint * 72.0;
+ length = xprint * 72.0;
+ }
+ else
+ {
+ width = xprint * 72.0;
+ length = yprint * 72.0;
+ }
+
+ /*
+ * Add margins to page size...
+ */
+
+ width += ppd->custom_margins[0] + ppd->custom_margins[2];
+ length += ppd->custom_margins[1] + ppd->custom_margins[3];
+
+ /*
+ * Enforce minimums...
+ */
+
+ if (width < ppd->custom_min[0])
+ width = ppd->custom_min[0];
+
+ if (length < ppd->custom_min[1])
+ length = ppd->custom_min[1];
+
+ fprintf(stderr, "DEBUG: Updated custom page size to %.2f x %.2f inches...\n",
+ width / 72.0, length / 72.0);
+
+ /*
+ * Set the new custom size...
+ */
+
+ strcpy(header.cupsPageSizeName, "Custom");
+
+ header.cupsPageSize[0] = width + 0.5;
+ header.cupsPageSize[1] = length + 0.5;
+ header.PageSize[0] = width + 0.5;
+ header.PageSize[1] = length + 0.5;
+
+ /*
+ * Update page variables...
+ */
+
+ PageWidth = width;
+ PageLength = length;
+ PageLeft = ppd->custom_margins[0];
+ PageRight = width - ppd->custom_margins[2];
+ PageBottom = ppd->custom_margins[1];
+ PageTop = length - ppd->custom_margins[3];
+
+ /*
+ * Remove margins from page size...
+ */
+
+ width -= ppd->custom_margins[0] + ppd->custom_margins[2];
+ length -= ppd->custom_margins[1] + ppd->custom_margins[3];
+
+ /*
+ * Set the bitmap size...
+ */
+
+ header.cupsWidth = width * header.HWResolution[0] / 72.0;
+ header.cupsHeight = length * header.HWResolution[1] / 72.0;
+
+ header.cupsBytesPerLine = (header.cupsBitsPerPixel *
+ header.cupsWidth + 7) / 8;
+
+ if (header.cupsColorOrder == CUPS_ORDER_BANDED)
+ header.cupsBytesPerLine *= header.cupsNumColors;
+ }
+
+ header.Margins[0] = PageLeft;
+ header.Margins[1] = PageBottom;
+
+ fprintf(stderr, "DEBUG: PageSize = [%d %d]\n", header.PageSize[0],
+ header.PageSize[1]);
+
+ switch (Orientation)
+ {
+ default :
+ switch (XPosition)
+ {
+ case -1 :
+ header.cupsImagingBBox[0] = PageLeft;
+ header.cupsImagingBBox[2] = PageLeft + xprint * 72;
+ break;
+ default :
+ header.cupsImagingBBox[0] = (PageRight + PageLeft - xprint * 72) / 2;
+ header.cupsImagingBBox[2] = (PageRight + PageLeft + xprint * 72) / 2;
+ break;
+ case 1 :
+ header.cupsImagingBBox[0] = PageRight - xprint * 72;
+ header.cupsImagingBBox[2] = PageRight;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case -1 :
+ header.cupsImagingBBox[1] = PageBottom;
+ header.cupsImagingBBox[3] = PageBottom + yprint * 72;
+ break;
+ default :
+ header.cupsImagingBBox[1] = (PageTop + PageBottom - yprint * 72) / 2;
+ header.cupsImagingBBox[3] = (PageTop + PageBottom + yprint * 72) / 2;
+ break;
+ case 1 :
+ header.cupsImagingBBox[1] = PageTop - yprint * 72;
+ header.cupsImagingBBox[3] = PageTop;
+ break;
+ }
+ break;
+
+ case 1 :
+ switch (XPosition)
+ {
+ case -1 :
+ header.cupsImagingBBox[0] = PageBottom;
+ header.cupsImagingBBox[2] = PageBottom + yprint * 72;
+ break;
+ default :
+ header.cupsImagingBBox[0] = (PageTop + PageBottom - yprint * 72) / 2;
+ header.cupsImagingBBox[2] = (PageTop + PageBottom + yprint * 72) / 2;
+ break;
+ case 1 :
+ header.cupsImagingBBox[0] = PageTop - yprint * 72;
+ header.cupsImagingBBox[2] = PageTop;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case -1 :
+ header.cupsImagingBBox[1] = PageLeft;
+ header.cupsImagingBBox[3] = PageLeft + xprint * 72;
+ break;
+ default :
+ header.cupsImagingBBox[1] = (PageRight + PageLeft - xprint * 72) / 2;
+ header.cupsImagingBBox[3] = (PageRight + PageLeft + xprint * 72) / 2;
+ break;
+ case 1 :
+ header.cupsImagingBBox[1] = PageRight - xprint * 72;
+ header.cupsImagingBBox[3] = PageRight;
+ break;
+ }
+ break;
+
+ case 2 :
+ switch (XPosition)
+ {
+ case 1 :
+ header.cupsImagingBBox[0] = PageLeft;
+ header.cupsImagingBBox[2] = PageLeft + xprint * 72;
+ break;
+ default :
+ header.cupsImagingBBox[0] = (PageRight + PageLeft - xprint * 72) / 2;
+ header.cupsImagingBBox[2] = (PageRight + PageLeft + xprint * 72) / 2;
+ break;
+ case -1 :
+ header.cupsImagingBBox[0] = PageRight - xprint * 72;
+ header.cupsImagingBBox[2] = PageRight;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case 1 :
+ header.cupsImagingBBox[1] = PageBottom;
+ header.cupsImagingBBox[3] = PageBottom + yprint * 72;
+ break;
+ default :
+ header.cupsImagingBBox[1] = (PageTop + PageBottom - yprint * 72) / 2;
+ header.cupsImagingBBox[3] = (PageTop + PageBottom + yprint * 72) / 2;
+ break;
+ case -1 :
+ header.cupsImagingBBox[1] = PageTop - yprint * 72;
+ header.cupsImagingBBox[3] = PageTop;
+ break;
+ }
+ break;
+
+ case 3 :
+ switch (XPosition)
+ {
+ case 1 :
+ header.cupsImagingBBox[0] = PageBottom;
+ header.cupsImagingBBox[2] = PageBottom + yprint * 72;
+ break;
+ default :
+ header.cupsImagingBBox[0] = (PageTop + PageBottom - yprint * 72) / 2;
+ header.cupsImagingBBox[2] = (PageTop + PageBottom + yprint * 72) / 2;
+ break;
+ case -1 :
+ header.cupsImagingBBox[0] = PageTop - yprint * 72;
+ header.cupsImagingBBox[2] = PageTop;
+ break;
+ }
+
+ switch (YPosition)
+ {
+ case 1 :
+ header.cupsImagingBBox[1] = PageLeft;
+ header.cupsImagingBBox[3] = PageLeft + xprint * 72;
+ break;
+ default :
+ header.cupsImagingBBox[1] = (PageRight + PageLeft - xprint * 72) / 2;
+ header.cupsImagingBBox[3] = (PageRight + PageLeft + xprint * 72) / 2;
+ break;
+ case -1 :
+ header.cupsImagingBBox[1] = PageRight - xprint * 72;
+ header.cupsImagingBBox[3] = PageRight;
+ break;
+ }
+ break;
+ }
+
+ header.ImagingBoundingBox[0] = header.cupsImagingBBox[0];
+ header.ImagingBoundingBox[1] = header.cupsImagingBBox[1];
+ header.ImagingBoundingBox[2] = header.cupsImagingBBox[2];
+ header.ImagingBoundingBox[3] = header.cupsImagingBBox[3];
+
+ if (header.cupsColorOrder == CUPS_ORDER_PLANAR)
+ num_planes = header.cupsNumColors;
+ else
+ num_planes = 1;
+
+ if (header.cupsBitsPerColor >= 8)
+ zoom_type = CUPS_IZOOM_NORMAL;
+ else
+ zoom_type = CUPS_IZOOM_FAST;
+
+ /*
+ * See if we need to collate, and if so how we need to do it...
+ */
+
+ if (xpages == 1 && ypages == 1)
+ Collate = 0;
+
+ slowcollate = Collate && ppdFindOption(ppd, "Collate") == NULL;
+ if (ppd != NULL)
+ slowcopies = ppd->manual_copies;
+ else
+ slowcopies = 1;
+
+ if (Copies > 1 && !slowcollate && !slowcopies)
+ {
+ header.Collate = (cups_bool_t)Collate;
+ header.NumCopies = Copies;
+
+ Copies = 1;
+ }
+ else
+ header.NumCopies = 1;
+
+ /*
+ * Create the dithering lookup tables...
+ */
+
+ OnPixels[0] = 0x00;
+ OnPixels[255] = 0xff;
+ OffPixels[0] = 0x00;
+ OffPixels[255] = 0xff;
+
+ switch (header.cupsBitsPerColor)
+ {
+ case 2 :
+ for (i = 1; i < 255; i ++)
+ {
+ OnPixels[i] = 0x55 * (i / 85 + 1);
+ OffPixels[i] = 0x55 * (i / 64);
+ }
+ break;
+ case 4 :
+ for (i = 1; i < 255; i ++)
+ {
+ OnPixels[i] = 17 * (i / 17 + 1);
+ OffPixels[i] = 17 * (i / 16);
+ }
+ break;
+ }
+
+ /*
+ * Output the pages...
+ */
+
+ fprintf(stderr, "DEBUG: cupsWidth = %d\n", header.cupsWidth);
+ fprintf(stderr, "DEBUG: cupsHeight = %d\n", header.cupsHeight);
+ fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header.cupsBitsPerColor);
+ fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header.cupsBitsPerPixel);
+ fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header.cupsBytesPerLine);
+ fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header.cupsColorOrder);
+ fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header.cupsColorSpace);
+ fprintf(stderr, "DEBUG: img->colorspace = %d\n", img->colorspace);
+
+ row = malloc(2 * header.cupsBytesPerLine);
+ ras = cupsRasterOpen(1, CUPS_RASTER_WRITE);
+
+ for (i = 0, page = 1; i < Copies; i ++)
+ for (xpage = 0; xpage < xpages; xpage ++)
+ for (ypage = 0; ypage < ypages; ypage ++, page ++)
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("Formatting page %d."), page);
+
+ if (Orientation & 1)
+ {
+ xc0 = img->xsize * ypage / ypages;
+ xc1 = img->xsize * (ypage + 1) / ypages - 1;
+ yc0 = img->ysize * xpage / xpages;
+ yc1 = img->ysize * (xpage + 1) / xpages - 1;
+
+ xtemp = header.HWResolution[0] * yprint;
+ ytemp = header.HWResolution[1] * xprint;
+ }
+ else
+ {
+ xc0 = img->xsize * xpage / xpages;
+ xc1 = img->xsize * (xpage + 1) / xpages - 1;
+ yc0 = img->ysize * ypage / ypages;
+ yc1 = img->ysize * (ypage + 1) / ypages - 1;
+
+ xtemp = header.HWResolution[0] * xprint;
+ ytemp = header.HWResolution[1] * yprint;
+ }
+
+ cupsRasterWriteHeader2(ras, &header);
+
+ for (plane = 0; plane < num_planes; plane ++)
+ {
+ /*
+ * Initialize the image "zoom" engine...
+ */
+
+ if (Flip)
+ z = _cupsImageZoomNew(img, xc0, yc0, xc1, yc1, -xtemp, ytemp,
+ Orientation & 1, zoom_type);
+ else
+ z = _cupsImageZoomNew(img, xc0, yc0, xc1, yc1, xtemp, ytemp,
+ Orientation & 1, zoom_type);
+
+ /*
+ * Write leading blank space as needed...
+ */
+
+ if (header.cupsHeight > z->ysize && YPosition <= 0)
+ {
+ blank_line(&header, row);
+
+ y = header.cupsHeight - z->ysize;
+ if (YPosition == 0)
+ y /= 2;
+
+ fprintf(stderr, "DEBUG: Writing %d leading blank lines...\n", y);
+
+ for (; y > 0; y --)
+ {
+ if (cupsRasterWritePixels(ras, row, header.cupsBytesPerLine) <
+ header.cupsBytesPerLine)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to send raster data to the "
+ "driver."));
+ cupsImageClose(img);
+ exit(1);
+ }
+ }
+ }
+
+ /*
+ * Then write image data...
+ */
+
+ for (y = z->ysize, yerr0 = 0, yerr1 = z->ysize, iy = 0, last_iy = -2;
+ y > 0;
+ y --)
+ {
+ if (iy != last_iy)
+ {
+ if (zoom_type != CUPS_IZOOM_FAST && (iy - last_iy) > 1)
+ _cupsImageZoomFill(z, iy);
+
+ _cupsImageZoomFill(z, iy + z->yincr);
+
+ last_iy = iy;
+ }
+
+ /*
+ * Format this line of raster data for the printer...
+ */
+
+ blank_line(&header, row);
+
+ r0 = z->rows[z->row];
+ r1 = z->rows[1 - z->row];
+
+ switch (header.cupsColorSpace)
+ {
+ case CUPS_CSPACE_W :
+ format_W(&header, row, y, plane, z->xsize, z->ysize,
+ yerr0, yerr1, r0, r1);
+ break;
+ default :
+ case CUPS_CSPACE_RGB :
+ format_RGB(&header, row, y, plane, z->xsize, z->ysize,
+ yerr0, yerr1, r0, r1);
+ break;
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_RGBW :
+ format_RGBA(&header, row, y, plane, z->xsize, z->ysize,
+ yerr0, yerr1, r0, r1);
+ break;
+ case CUPS_CSPACE_K :
+ case CUPS_CSPACE_WHITE :
+ case CUPS_CSPACE_GOLD :
+ case CUPS_CSPACE_SILVER :
+ format_K(&header, row, y, plane, z->xsize, z->ysize,
+ yerr0, yerr1, r0, r1);
+ break;
+ case CUPS_CSPACE_CMY :
+ format_CMY(&header, row, y, plane, z->xsize, z->ysize,
+ yerr0, yerr1, r0, r1);
+ break;
+ case CUPS_CSPACE_YMC :
+ format_YMC(&header, row, y, plane, z->xsize, z->ysize,
+ yerr0, yerr1, r0, r1);
+ break;
+ case CUPS_CSPACE_CMYK :
+ format_CMYK(&header, row, y, plane, z->xsize, z->ysize,
+ yerr0, yerr1, r0, r1);
+ break;
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ format_YMCK(&header, row, y, plane, z->xsize, z->ysize,
+ yerr0, yerr1, r0, r1);
+ break;
+ case CUPS_CSPACE_KCMYcm :
+ if (header.cupsBitsPerColor == 1)
+ {
+ format_KCMYcm(&header, row, y, plane, z->xsize, z->ysize,
+ yerr0, yerr1, r0, r1);
+ break;
+ }
+ case CUPS_CSPACE_KCMY :
+ format_KCMY(&header, row, y, plane, z->xsize, z->ysize,
+ yerr0, yerr1, r0, r1);
+ break;
+ }
+
+ /*
+ * Write the raster data to the driver...
+ */
+
+ if (cupsRasterWritePixels(ras, row, header.cupsBytesPerLine) <
+ header.cupsBytesPerLine)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to send raster data to the "
+ "driver."));
+ cupsImageClose(img);
+ exit(1);
+ }
+
+ /*
+ * Compute the next scanline in the image...
+ */
+
+ iy += z->ystep;
+ yerr0 += z->ymod;
+ yerr1 -= z->ymod;
+ if (yerr1 <= 0)
+ {
+ yerr0 -= z->ysize;
+ yerr1 += z->ysize;
+ iy += z->yincr;
+ }
+ }
+
+ /*
+ * Write trailing blank space as needed...
+ */
+
+ if (header.cupsHeight > z->ysize && YPosition >= 0)
+ {
+ blank_line(&header, row);
+
+ y = header.cupsHeight - z->ysize;
+ if (YPosition == 0)
+ y = y - y / 2;
+
+ fprintf(stderr, "DEBUG: Writing %d trailing blank lines...\n", y);
+
+ for (; y > 0; y --)
+ {
+ if (cupsRasterWritePixels(ras, row, header.cupsBytesPerLine) <
+ header.cupsBytesPerLine)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to send raster data to the "
+ "driver."));
+ cupsImageClose(img);
+ exit(1);
+ }
+ }
+ }
+
+ /*
+ * Free memory used for the "zoom" engine...
+ */
+
+ _cupsImageZoomDelete(z);
+ }
+ }
+
+ /*
+ * Close files...
+ */
+
+ free(row);
+ cupsRasterClose(ras);
+ cupsImageClose(img);
+ ppdClose(ppd);
+
+ return (0);
+}
+
+
+/*
+ * 'blank_line()' - Clear a line buffer to the blank value...
+ */
+
+static void
+blank_line(cups_page_header2_t *header, /* I - Page header */
+ unsigned char *row) /* I - Row buffer */
+{
+ int count; /* Remaining bytes */
+
+
+ count = header->cupsBytesPerLine;
+
+ switch (header->cupsColorSpace)
+ {
+ case CUPS_CSPACE_CIEXYZ :
+ while (count > 2)
+ {
+ *row++ = 242;
+ *row++ = 255;
+ *row++ = 255;
+ count -= 3;
+ }
+ break;
+
+ case CUPS_CSPACE_CIELab :
+ case CUPS_CSPACE_ICC1 :
+ case CUPS_CSPACE_ICC2 :
+ case CUPS_CSPACE_ICC3 :
+ case CUPS_CSPACE_ICC4 :
+ case CUPS_CSPACE_ICC5 :
+ case CUPS_CSPACE_ICC6 :
+ case CUPS_CSPACE_ICC7 :
+ case CUPS_CSPACE_ICC8 :
+ case CUPS_CSPACE_ICC9 :
+ case CUPS_CSPACE_ICCA :
+ case CUPS_CSPACE_ICCB :
+ case CUPS_CSPACE_ICCC :
+ case CUPS_CSPACE_ICCD :
+ case CUPS_CSPACE_ICCE :
+ case CUPS_CSPACE_ICCF :
+ while (count > 2)
+ {
+ *row++ = 255;
+ *row++ = 128;
+ *row++ = 128;
+ count -= 3;
+ }
+ break;
+
+ case CUPS_CSPACE_K :
+ case CUPS_CSPACE_CMY :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMC :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_KCMYcm :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ case CUPS_CSPACE_WHITE :
+ case CUPS_CSPACE_GOLD :
+ case CUPS_CSPACE_SILVER :
+ memset(row, 0, count);
+ break;
+
+ default :
+ memset(row, 255, count);
+ break;
+ }
+}
+
+
+/*
+ * 'format_CMY()' - Convert image data to CMY.
+ */
+
+static void
+format_CMY(cups_page_header2_t *header, /* I - Page header */
+ unsigned char *row, /* IO - Bitmap data for device */
+ int y, /* I - Current row */
+ int z, /* I - Current plane */
+ int xsize, /* I - Width of image data */
+ int ysize, /* I - Height of image data */
+ int yerr0, /* I - Top Y error */
+ int yerr1, /* I - Bottom Y error */
+ cups_ib_t *r0, /* I - Primary image data */
+ cups_ib_t *r1) /* I - Image data for interpolation */
+{
+ cups_ib_t *ptr, /* Pointer into row */
+ *cptr, /* Pointer into cyan */
+ *mptr, /* Pointer into magenta */
+ *yptr, /* Pointer into yellow */
+ bitmask; /* Current mask for pixel */
+ int bitoffset; /* Current offset in line */
+ int bandwidth; /* Width of a color band */
+ int x, /* Current X coordinate on page */
+ *dither; /* Pointer into dither array */
+
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ ptr = row + bitoffset / 8;
+ bandwidth = header->cupsBytesPerLine / 3;
+
+ switch (header->cupsColorOrder)
+ {
+ case CUPS_ORDER_CHUNKED :
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 64 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize ; x > 0; x --)
+ {
+ if (*r0++ > dither[x & 15])
+ *ptr ^= bitmask;
+ bitmask >>= 1;
+
+ if (*r0++ > dither[x & 15])
+ *ptr ^= bitmask;
+ bitmask >>= 1;
+
+ if (*r0++ > dither[x & 15])
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 64;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ dither = Floyd8x8[y & 7];
+
+ for (x = xsize ; x > 0; x --, r0 += 3)
+ {
+ if ((r0[0] & 63) > dither[x & 7])
+ *ptr ^= (0x30 & OnPixels[r0[0]]);
+ else
+ *ptr ^= (0x30 & OffPixels[r0[0]]);
+
+ if ((r0[1] & 63) > dither[x & 7])
+ *ptr ^= (0x0c & OnPixels[r0[1]]);
+ else
+ *ptr ^= (0x0c & OffPixels[r0[1]]);
+
+ if ((r0[2] & 63) > dither[x & 7])
+ *ptr++ ^= (0x03 & OnPixels[r0[2]]);
+ else
+ *ptr++ ^= (0x03 & OffPixels[r0[2]]);
+ }
+ break;
+
+ case 4 :
+ dither = Floyd4x4[y & 3];
+
+ for (x = xsize ; x > 0; x --, r0 += 3)
+ {
+ if ((r0[0] & 15) > dither[x & 3])
+ *ptr++ ^= (0x0f & OnPixels[r0[0]]);
+ else
+ *ptr++ ^= (0x0f & OffPixels[r0[0]]);
+
+ if ((r0[1] & 15) > dither[x & 3])
+ *ptr ^= (0xf0 & OnPixels[r0[1]]);
+ else
+ *ptr ^= (0xf0 & OffPixels[r0[1]]);
+
+ if ((r0[2] & 15) > dither[x & 3])
+ *ptr++ ^= (0x0f & OnPixels[r0[2]]);
+ else
+ *ptr++ ^= (0x0f & OffPixels[r0[2]]);
+ }
+ break;
+
+ case 8 :
+ for (x = xsize * 3; x > 0; x --, r0 ++, r1 ++)
+ if (*r0 == *r1)
+ *ptr++ = *r0;
+ else
+ *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize;
+ break;
+ }
+ break;
+
+ case CUPS_ORDER_BANDED :
+ cptr = ptr;
+ mptr = ptr + bandwidth;
+ yptr = ptr + 2 * bandwidth;
+
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if (*r0++ > dither[x & 15])
+ *cptr ^= bitmask;
+ if (*r0++ > dither[x & 15])
+ *mptr ^= bitmask;
+ if (*r0++ > dither[x & 15])
+ *yptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ bitmask = 0xc0 >> (bitoffset & 7);
+ dither = Floyd8x8[y & 7];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 63) > dither[x & 7])
+ *cptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *cptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *mptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *mptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *yptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *yptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask > 3)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 0xc0;
+
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ }
+ }
+ break;
+
+ case 4 :
+ bitmask = 0xf0 >> (bitoffset & 7);
+ dither = Floyd4x4[y & 3];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 15) > dither[x & 3])
+ *cptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *cptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *mptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *mptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *yptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *yptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask == 0xf0)
+ bitmask = 0x0f;
+ else
+ {
+ bitmask = 0xf0;
+
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ }
+ }
+ break;
+
+ case 8 :
+ for (x = xsize; x > 0; x --, r0 += 3, r1 += 3)
+ {
+ if (r0[0] == r1[0])
+ *cptr++ = r0[0];
+ else
+ *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize;
+
+ if (r0[1] == r1[1])
+ *mptr++ = r0[1];
+ else
+ *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize;
+
+ if (r0[2] == r1[2])
+ *yptr++ = r0[2];
+ else
+ *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+
+ case CUPS_ORDER_PLANAR :
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ switch (z)
+ {
+ case 0 :
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if (r0[0] > dither[x & 15])
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 1 :
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if (r0[1] > dither[x & 15])
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if (r0[2] > dither[x & 15])
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+ }
+ break;
+
+ case 2 :
+ bitmask = 0xc0 >> (bitoffset & 7);
+ dither = Floyd8x8[y & 7];
+ r0 += z;
+
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if ((*r0 & 63) > dither[x & 7])
+ *ptr ^= (bitmask & OnPixels[*r0]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0]);
+
+ if (bitmask > 3)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 0xc0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 4 :
+ bitmask = 0xf0 >> (bitoffset & 7);
+ dither = Floyd4x4[y & 3];
+ r0 += z;
+
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if ((*r0 & 15) > dither[x & 3])
+ *ptr ^= (bitmask & OnPixels[*r0]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0]);
+
+ if (bitmask == 0xf0)
+ bitmask = 0x0f;
+ else
+ {
+ bitmask = 0xf0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 8 :
+ r0 += z;
+ r1 += z;
+
+ for (x = xsize; x > 0; x --, r0 += 3, r1 += 3)
+ {
+ if (*r0 == *r1)
+ *ptr++ = *r0;
+ else
+ *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+ }
+}
+
+
+/*
+ * 'format_CMYK()' - Convert image data to CMYK.
+ */
+
+static void
+format_CMYK(cups_page_header2_t *header,/* I - Page header */
+ unsigned char *row, /* IO - Bitmap data for device */
+ int y, /* I - Current row */
+ int z, /* I - Current plane */
+ int xsize, /* I - Width of image data */
+ int ysize, /* I - Height of image data */
+ int yerr0, /* I - Top Y error */
+ int yerr1, /* I - Bottom Y error */
+ cups_ib_t *r0, /* I - Primary image data */
+ cups_ib_t *r1) /* I - Image data for interpolation */
+{
+ cups_ib_t *ptr, /* Pointer into row */
+ *cptr, /* Pointer into cyan */
+ *mptr, /* Pointer into magenta */
+ *yptr, /* Pointer into yellow */
+ *kptr, /* Pointer into black */
+ bitmask; /* Current mask for pixel */
+ int bitoffset; /* Current offset in line */
+ int bandwidth; /* Width of a color band */
+ int x, /* Current X coordinate on page */
+ *dither; /* Pointer into dither array */
+ int pc, pm, py; /* CMY pixels */
+
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ ptr = row + bitoffset / 8;
+ bandwidth = header->cupsBytesPerLine / 4;
+
+ switch (header->cupsColorOrder)
+ {
+ case CUPS_ORDER_CHUNKED :
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 128 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize ; x > 0; x --)
+ {
+ pc = *r0++ > dither[x & 15];
+ pm = *r0++ > dither[x & 15];
+ py = *r0++ > dither[x & 15];
+
+ if (pc && pm && py)
+ {
+ bitmask >>= 3;
+ *ptr ^= bitmask;
+ }
+ else
+ {
+ if (pc)
+ *ptr ^= bitmask;
+ bitmask >>= 1;
+
+ if (pm)
+ *ptr ^= bitmask;
+ bitmask >>= 1;
+
+ if (py)
+ *ptr ^= bitmask;
+ bitmask >>= 1;
+ }
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 128;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ dither = Floyd8x8[y & 7];
+
+ for (x = xsize ; x > 0; x --, r0 += 4)
+ {
+ if ((r0[0] & 63) > dither[x & 7])
+ *ptr ^= (0xc0 & OnPixels[r0[0]]);
+ else
+ *ptr ^= (0xc0 & OffPixels[r0[0]]);
+
+ if ((r0[1] & 63) > dither[x & 7])
+ *ptr ^= (0x30 & OnPixels[r0[1]]);
+ else
+ *ptr ^= (0x30 & OffPixels[r0[1]]);
+
+ if ((r0[2] & 63) > dither[x & 7])
+ *ptr ^= (0x0c & OnPixels[r0[2]]);
+ else
+ *ptr ^= (0x0c & OffPixels[r0[2]]);
+
+ if ((r0[3] & 63) > dither[x & 7])
+ *ptr++ ^= (0x03 & OnPixels[r0[3]]);
+ else
+ *ptr++ ^= (0x03 & OffPixels[r0[3]]);
+ }
+ break;
+
+ case 4 :
+ dither = Floyd4x4[y & 3];
+
+ for (x = xsize ; x > 0; x --, r0 += 4)
+ {
+ if ((r0[0] & 15) > dither[x & 3])
+ *ptr ^= (0xf0 & OnPixels[r0[0]]);
+ else
+ *ptr ^= (0xf0 & OffPixels[r0[0]]);
+
+ if ((r0[1] & 15) > dither[x & 3])
+ *ptr++ ^= (0x0f & OnPixels[r0[1]]);
+ else
+ *ptr++ ^= (0x0f & OffPixels[r0[1]]);
+
+ if ((r0[2] & 15) > dither[x & 3])
+ *ptr ^= (0xf0 & OnPixels[r0[2]]);
+ else
+ *ptr ^= (0xf0 & OffPixels[r0[2]]);
+
+ if ((r0[3] & 15) > dither[x & 3])
+ *ptr++ ^= (0x0f & OnPixels[r0[3]]);
+ else
+ *ptr++ ^= (0x0f & OffPixels[r0[3]]);
+ }
+ break;
+
+ case 8 :
+ for (x = xsize * 4; x > 0; x --, r0 ++, r1 ++)
+ if (*r0 == *r1)
+ *ptr++ = *r0;
+ else
+ *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize;
+ break;
+ }
+ break;
+
+ case CUPS_ORDER_BANDED :
+ cptr = ptr;
+ mptr = ptr + bandwidth;
+ yptr = ptr + 2 * bandwidth;
+ kptr = ptr + 3 * bandwidth;
+
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize; x > 0; x --)
+ {
+ pc = *r0++ > dither[x & 15];
+ pm = *r0++ > dither[x & 15];
+ py = *r0++ > dither[x & 15];
+
+ if (pc && pm && py)
+ *kptr ^= bitmask;
+ else
+ {
+ if (pc)
+ *cptr ^= bitmask;
+ if (pm)
+ *mptr ^= bitmask;
+ if (py)
+ *yptr ^= bitmask;
+ }
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ bitmask = 0xc0 >> (bitoffset & 7);
+ dither = Floyd8x8[y & 7];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 63) > dither[x & 7])
+ *cptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *cptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *mptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *mptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *yptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *yptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *kptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *kptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask > 3)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 0xc0;
+
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ }
+ }
+ break;
+
+ case 4 :
+ bitmask = 0xf0 >> (bitoffset & 7);
+ dither = Floyd4x4[y & 3];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 15) > dither[x & 3])
+ *cptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *cptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *mptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *mptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *yptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *yptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *kptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *kptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask == 0xf0)
+ bitmask = 0x0f;
+ else
+ {
+ bitmask = 0xf0;
+
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ }
+ }
+ break;
+
+ case 8 :
+ for (x = xsize; x > 0; x --, r0 += 4, r1 += 4)
+ {
+ if (r0[0] == r1[0])
+ *cptr++ = r0[0];
+ else
+ *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize;
+
+ if (r0[1] == r1[1])
+ *mptr++ = r0[1];
+ else
+ *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize;
+
+ if (r0[2] == r1[2])
+ *yptr++ = r0[2];
+ else
+ *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize;
+
+ if (r0[3] == r1[3])
+ *kptr++ = r0[3];
+ else
+ *kptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+
+ case CUPS_ORDER_PLANAR :
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize; x > 0; x --)
+ {
+ pc = *r0++ > dither[x & 15];
+ pm = *r0++ > dither[x & 15];
+ py = *r0++ > dither[x & 15];
+
+ if ((pc && pm && py && z == 3) ||
+ (pc && z == 0) || (pm && z == 1) || (py && z == 2))
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ bitmask = 0xc0 >> (bitoffset & 7);
+ dither = Floyd8x8[y & 7];
+ r0 += z;
+
+ for (x = xsize; x > 0; x --, r0 += 4)
+ {
+ if ((*r0 & 63) > dither[x & 7])
+ *ptr ^= (bitmask & OnPixels[*r0]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0]);
+
+ if (bitmask > 3)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 0xc0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 4 :
+ bitmask = 0xf0 >> (bitoffset & 7);
+ dither = Floyd4x4[y & 3];
+ r0 += z;
+
+ for (x = xsize; x > 0; x --, r0 += 4)
+ {
+ if ((*r0 & 15) > dither[x & 3])
+ *ptr ^= (bitmask & OnPixels[*r0]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0]);
+
+ if (bitmask == 0xf0)
+ bitmask = 0x0f;
+ else
+ {
+ bitmask = 0xf0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 8 :
+ r0 += z;
+ r1 += z;
+
+ for (x = xsize; x > 0; x --, r0 += 4, r1 += 4)
+ {
+ if (*r0 == *r1)
+ *ptr++ = *r0;
+ else
+ *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+ }
+}
+
+
+/*
+ * 'format_K()' - Convert image data to black.
+ */
+
+static void
+format_K(cups_page_header2_t *header, /* I - Page header */
+ unsigned char *row, /* IO - Bitmap data for device */
+ int y, /* I - Current row */
+ int z, /* I - Current plane */
+ int xsize, /* I - Width of image data */
+ int ysize, /* I - Height of image data */
+ int yerr0, /* I - Top Y error */
+ int yerr1, /* I - Bottom Y error */
+ cups_ib_t *r0, /* I - Primary image data */
+ cups_ib_t *r1) /* I - Image data for interpolation */
+{
+ cups_ib_t *ptr, /* Pointer into row */
+ bitmask; /* Current mask for pixel */
+ int bitoffset; /* Current offset in line */
+ int x, /* Current X coordinate on page */
+ *dither; /* Pointer into dither array */
+
+
+ (void)z;
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ ptr = row + bitoffset / 8;
+
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if (*r0++ > dither[x & 15])
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ bitmask = 0xc0 >> (bitoffset & 7);
+ dither = Floyd8x8[y & 7];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 63) > dither[x & 7])
+ *ptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask > 3)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 0xc0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 4 :
+ bitmask = 0xf0 >> (bitoffset & 7);
+ dither = Floyd4x4[y & 3];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 15) > dither[x & 3])
+ *ptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask == 0xf0)
+ bitmask = 0x0f;
+ else
+ {
+ bitmask = 0xf0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 8 :
+ for (x = xsize; x > 0; x --, r0 ++, r1 ++)
+ {
+ if (*r0 == *r1)
+ *ptr++ = *r0;
+ else
+ *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize;
+ }
+ break;
+ }
+}
+
+
+/*
+ * 'format_KCMY()' - Convert image data to KCMY.
+ */
+
+static void
+format_KCMY(cups_page_header2_t *header,/* I - Page header */
+ unsigned char *row, /* IO - Bitmap data for device */
+ int y, /* I - Current row */
+ int z, /* I - Current plane */
+ int xsize, /* I - Width of image data */
+ int ysize, /* I - Height of image data */
+ int yerr0, /* I - Top Y error */
+ int yerr1, /* I - Bottom Y error */
+ cups_ib_t *r0, /* I - Primary image data */
+ cups_ib_t *r1) /* I - Image data for interpolation */
+{
+ cups_ib_t *ptr, /* Pointer into row */
+ *cptr, /* Pointer into cyan */
+ *mptr, /* Pointer into magenta */
+ *yptr, /* Pointer into yellow */
+ *kptr, /* Pointer into black */
+ bitmask; /* Current mask for pixel */
+ int bitoffset; /* Current offset in line */
+ int bandwidth; /* Width of a color band */
+ int x, /* Current X coordinate on page */
+ *dither; /* Pointer into dither array */
+ int pc, pm, py; /* CMY pixels */
+
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ ptr = row + bitoffset / 8;
+ bandwidth = header->cupsBytesPerLine / 4;
+
+ switch (header->cupsColorOrder)
+ {
+ case CUPS_ORDER_CHUNKED :
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 128 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize ; x > 0; x --)
+ {
+ pc = *r0++ > dither[x & 15];
+ pm = *r0++ > dither[x & 15];
+ py = *r0++ > dither[x & 15];
+
+ if (pc && pm && py)
+ {
+ *ptr ^= bitmask;
+ bitmask >>= 3;
+ }
+ else
+ {
+ bitmask >>= 1;
+ if (pc)
+ *ptr ^= bitmask;
+
+ bitmask >>= 1;
+ if (pm)
+ *ptr ^= bitmask;
+
+ bitmask >>= 1;
+ if (py)
+ *ptr ^= bitmask;
+ }
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 128;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ dither = Floyd8x8[y & 7];
+
+ for (x = xsize ; x > 0; x --, r0 += 4)
+ {
+ if ((r0[3] & 63) > dither[x & 7])
+ *ptr ^= (0xc0 & OnPixels[r0[3]]);
+ else
+ *ptr ^= (0xc0 & OffPixels[r0[3]]);
+
+ if ((r0[0] & 63) > dither[x & 7])
+ *ptr ^= (0x30 & OnPixels[r0[0]]);
+ else
+ *ptr ^= (0x30 & OffPixels[r0[0]]);
+
+ if ((r0[1] & 63) > dither[x & 7])
+ *ptr ^= (0x0c & OnPixels[r0[1]]);
+ else
+ *ptr ^= (0x0c & OffPixels[r0[1]]);
+
+ if ((r0[2] & 63) > dither[x & 7])
+ *ptr++ ^= (0x03 & OnPixels[r0[2]]);
+ else
+ *ptr++ ^= (0x03 & OffPixels[r0[2]]);
+ }
+ break;
+
+ case 4 :
+ dither = Floyd4x4[y & 3];
+
+ for (x = xsize ; x > 0; x --, r0 += 4)
+ {
+ if ((r0[3] & 15) > dither[x & 3])
+ *ptr ^= (0xf0 & OnPixels[r0[3]]);
+ else
+ *ptr ^= (0xf0 & OffPixels[r0[3]]);
+
+ if ((r0[0] & 15) > dither[x & 3])
+ *ptr++ ^= (0x0f & OnPixels[r0[0]]);
+ else
+ *ptr++ ^= (0x0f & OffPixels[r0[0]]);
+
+ if ((r0[1] & 15) > dither[x & 3])
+ *ptr ^= (0xf0 & OnPixels[r0[1]]);
+ else
+ *ptr ^= (0xf0 & OffPixels[r0[1]]);
+
+ if ((r0[2] & 15) > dither[x & 3])
+ *ptr++ ^= (0x0f & OnPixels[r0[2]]);
+ else
+ *ptr++ ^= (0x0f & OffPixels[r0[2]]);
+ }
+ break;
+
+ case 8 :
+ for (x = xsize; x > 0; x --, r0 += 4, r1 += 4)
+ {
+ if (r0[3] == r1[3])
+ *ptr++ = r0[3];
+ else
+ *ptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize;
+
+ if (r0[0] == r1[0])
+ *ptr++ = r0[0];
+ else
+ *ptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize;
+
+ if (r0[1] == r1[1])
+ *ptr++ = r0[1];
+ else
+ *ptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize;
+
+ if (r0[2] == r1[2])
+ *ptr++ = r0[2];
+ else
+ *ptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+
+ case CUPS_ORDER_BANDED :
+ kptr = ptr;
+ cptr = ptr + bandwidth;
+ mptr = ptr + 2 * bandwidth;
+ yptr = ptr + 3 * bandwidth;
+
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize; x > 0; x --)
+ {
+ pc = *r0++ > dither[x & 15];
+ pm = *r0++ > dither[x & 15];
+ py = *r0++ > dither[x & 15];
+
+ if (pc && pm && py)
+ *kptr ^= bitmask;
+ else
+ {
+ if (pc)
+ *cptr ^= bitmask;
+ if (pm)
+ *mptr ^= bitmask;
+ if (py)
+ *yptr ^= bitmask;
+ }
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ bitmask = 0xc0 >> (bitoffset & 7);
+ dither = Floyd8x8[y & 7];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 63) > dither[x & 7])
+ *cptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *cptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *mptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *mptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *yptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *yptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *kptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *kptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask > 3)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 0xc0;
+
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ }
+ }
+ break;
+
+ case 4 :
+ bitmask = 0xf0 >> (bitoffset & 7);
+ dither = Floyd4x4[y & 3];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 15) > dither[x & 3])
+ *cptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *cptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *mptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *mptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *yptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *yptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *kptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *kptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask == 0xf0)
+ bitmask = 0x0f;
+ else
+ {
+ bitmask = 0xf0;
+
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ }
+ }
+ break;
+
+ case 8 :
+ for (x = xsize; x > 0; x --, r0 += 4, r1 += 4)
+ {
+ if (r0[0] == r1[0])
+ *cptr++ = r0[0];
+ else
+ *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize;
+
+ if (r0[1] == r1[1])
+ *mptr++ = r0[1];
+ else
+ *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize;
+
+ if (r0[2] == r1[2])
+ *yptr++ = r0[2];
+ else
+ *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize;
+
+ if (r0[3] == r1[3])
+ *kptr++ = r0[3];
+ else
+ *kptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+
+ case CUPS_ORDER_PLANAR :
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize; x > 0; x --)
+ {
+ pc = *r0++ > dither[x & 15];
+ pm = *r0++ > dither[x & 15];
+ py = *r0++ > dither[x & 15];
+
+ if ((pc && pm && py && z == 0) ||
+ (pc && z == 1) || (pm && z == 2) || (py && z == 3))
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ bitmask = 0xc0 >> (bitoffset & 7);
+ dither = Floyd8x8[y & 7];
+ if (z == 0)
+ r0 += 3;
+ else
+ r0 += z - 1;
+
+ for (x = xsize; x > 0; x --, r0 += 4)
+ {
+ if ((*r0 & 63) > dither[x & 7])
+ *ptr ^= (bitmask & OnPixels[*r0]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0]);
+
+ if (bitmask > 3)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 0xc0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 4 :
+ bitmask = 0xf0 >> (bitoffset & 7);
+ dither = Floyd4x4[y & 3];
+ if (z == 0)
+ r0 += 3;
+ else
+ r0 += z - 1;
+
+ for (x = xsize; x > 0; x --, r0 += 4)
+ {
+ if ((*r0 & 15) > dither[x & 3])
+ *ptr ^= (bitmask & OnPixels[*r0]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0]);
+
+ if (bitmask == 0xf0)
+ bitmask = 0x0f;
+ else
+ {
+ bitmask = 0xf0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 8 :
+ if (z == 0)
+ {
+ r0 += 3;
+ r1 += 3;
+ }
+ else
+ {
+ r0 += z - 1;
+ r1 += z - 1;
+ }
+
+ for (x = xsize; x > 0; x --, r0 += 4, r1 += 4)
+ {
+ if (*r0 == *r1)
+ *ptr++ = *r0;
+ else
+ *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+ }
+}
+
+
+/*
+ * 'format_KCMYcm()' - Convert image data to KCMYcm.
+ */
+
+static void
+format_KCMYcm(
+ cups_page_header2_t *header, /* I - Page header */
+ unsigned char *row, /* IO - Bitmap data for device */
+ int y, /* I - Current row */
+ int z, /* I - Current plane */
+ int xsize, /* I - Width of image data */
+ int ysize, /* I - Height of image data */
+ int yerr0, /* I - Top Y error */
+ int yerr1, /* I - Bottom Y error */
+ cups_ib_t *r0, /* I - Primary image data */
+ cups_ib_t *r1) /* I - Image data for interpolation */
+{
+ int pc, pm, py, pk; /* Cyan, magenta, yellow, and black values */
+ cups_ib_t *ptr, /* Pointer into row */
+ *cptr, /* Pointer into cyan */
+ *mptr, /* Pointer into magenta */
+ *yptr, /* Pointer into yellow */
+ *kptr, /* Pointer into black */
+ *lcptr, /* Pointer into light cyan */
+ *lmptr, /* Pointer into light magenta */
+ bitmask; /* Current mask for pixel */
+ int bitoffset; /* Current offset in line */
+ int bandwidth; /* Width of a color band */
+ int x, /* Current X coordinate on page */
+ *dither; /* Pointer into dither array */
+
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ ptr = row + bitoffset / 8;
+ bandwidth = header->cupsBytesPerLine / 6;
+
+ switch (header->cupsColorOrder)
+ {
+ case CUPS_ORDER_CHUNKED :
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize ; x > 0; x --)
+ {
+ pc = *r0++ > dither[x & 15];
+ pm = *r0++ > dither[x & 15];
+ py = *r0++ > dither[x & 15];
+ pk = pc && pm && py;
+
+ if (pk)
+ *ptr++ ^= 32; /* Black */
+ else if (pc && pm)
+ *ptr++ ^= 17; /* Blue (cyan + light magenta) */
+ else if (pc && py)
+ *ptr++ ^= 6; /* Green (light cyan + yellow) */
+ else if (pm && py)
+ *ptr++ ^= 12; /* Red (magenta + yellow) */
+ else if (pc)
+ *ptr++ ^= 16;
+ else if (pm)
+ *ptr++ ^= 8;
+ else if (py)
+ *ptr++ ^= 4;
+ else
+ ptr ++;
+ }
+ break;
+
+ case CUPS_ORDER_BANDED :
+ kptr = ptr;
+ cptr = ptr + bandwidth;
+ mptr = ptr + 2 * bandwidth;
+ yptr = ptr + 3 * bandwidth;
+ lcptr = ptr + 4 * bandwidth;
+ lmptr = ptr + 5 * bandwidth;
+
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize; x > 0; x --)
+ {
+ pc = *r0++ > dither[x & 15];
+ pm = *r0++ > dither[x & 15];
+ py = *r0++ > dither[x & 15];
+ pk = pc && pm && py;
+
+ if (pk)
+ *kptr ^= bitmask; /* Black */
+ else if (pc && pm)
+ {
+ *cptr ^= bitmask; /* Blue (cyan + light magenta) */
+ *lmptr ^= bitmask;
+ }
+ else if (pc && py)
+ {
+ *lcptr ^= bitmask; /* Green (light cyan + yellow) */
+ *yptr ^= bitmask;
+ }
+ else if (pm && py)
+ {
+ *mptr ^= bitmask; /* Red (magenta + yellow) */
+ *yptr ^= bitmask;
+ }
+ else if (pc)
+ *cptr ^= bitmask;
+ else if (pm)
+ *mptr ^= bitmask;
+ else if (py)
+ *yptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ lcptr ++;
+ lmptr ++;
+ }
+ }
+ break;
+
+ case CUPS_ORDER_PLANAR :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize; x > 0; x --)
+ {
+ pc = *r0++ > dither[x & 15];
+ pm = *r0++ > dither[x & 15];
+ py = *r0++ > dither[x & 15];
+ pk = pc && pm && py;
+
+ if (pk && z == 0)
+ *ptr ^= bitmask;
+ else if (pc && pm && (z == 1 || z == 5))
+ *ptr ^= bitmask; /* Blue (cyan + light magenta) */
+ else if (pc && py && (z == 3 || z == 4))
+ *ptr ^= bitmask; /* Green (light cyan + yellow) */
+ else if (pm && py && (z == 2 || z == 3))
+ *ptr ^= bitmask; /* Red (magenta + yellow) */
+ else if (pc && z == 1)
+ *ptr ^= bitmask;
+ else if (pm && z == 2)
+ *ptr ^= bitmask;
+ else if (py && z == 3)
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+ }
+}
+
+
+/*
+ * 'format_RGBA()' - Convert image data to RGBA/RGBW.
+ */
+
+static void
+format_RGBA(cups_page_header2_t *header,/* I - Page header */
+ unsigned char *row, /* IO - Bitmap data for device */
+ int y, /* I - Current row */
+ int z, /* I - Current plane */
+ int xsize, /* I - Width of image data */
+ int ysize, /* I - Height of image data */
+ int yerr0, /* I - Top Y error */
+ int yerr1, /* I - Bottom Y error */
+ cups_ib_t *r0, /* I - Primary image data */
+ cups_ib_t *r1) /* I - Image data for interpolation */
+{
+ cups_ib_t *ptr, /* Pointer into row */
+ *cptr, /* Pointer into cyan */
+ *mptr, /* Pointer into magenta */
+ *yptr, /* Pointer into yellow */
+ bitmask; /* Current mask for pixel */
+ int bitoffset; /* Current offset in line */
+ int bandwidth; /* Width of a color band */
+ int x, /* Current X coordinate on page */
+ *dither; /* Pointer into dither array */
+
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ ptr = row + bitoffset / 8;
+ bandwidth = header->cupsBytesPerLine / 4;
+
+ switch (header->cupsColorOrder)
+ {
+ case CUPS_ORDER_CHUNKED :
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 128 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize ; x > 0; x --)
+ {
+ if (*r0++ > dither[x & 15])
+ *ptr ^= bitmask;
+ bitmask >>= 1;
+
+ if (*r0++ > dither[x & 15])
+ *ptr ^= bitmask;
+ bitmask >>= 1;
+
+ if (*r0++ > dither[x & 15])
+ *ptr ^= bitmask;
+
+ if (bitmask > 2)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 128;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ dither = Floyd8x8[y & 7];
+
+ for (x = xsize ; x > 0; x --, r0 += 3)
+ {
+ if ((r0[0] & 63) > dither[x & 7])
+ *ptr ^= (0xc0 & OnPixels[r0[0]]);
+ else
+ *ptr ^= (0xc0 & OffPixels[r0[0]]);
+
+ if ((r0[1] & 63) > dither[x & 7])
+ *ptr ^= (0x30 & OnPixels[r0[1]]);
+ else
+ *ptr ^= (0x30 & OffPixels[r0[1]]);
+
+ if ((r0[2] & 63) > dither[x & 7])
+ *ptr ^= (0x0c & OnPixels[r0[2]]);
+ else
+ *ptr ^= (0x0c & OffPixels[r0[2]]);
+
+ ptr ++;
+ }
+ break;
+
+ case 4 :
+ dither = Floyd4x4[y & 3];
+
+ for (x = xsize ; x > 0; x --, r0 += 3)
+ {
+ if ((r0[0] & 15) > dither[x & 3])
+ *ptr ^= (0xf0 & OnPixels[r0[0]]);
+ else
+ *ptr ^= (0xf0 & OffPixels[r0[0]]);
+
+ if ((r0[1] & 15) > dither[x & 3])
+ *ptr++ ^= (0x0f & OnPixels[r0[1]]);
+ else
+ *ptr++ ^= (0x0f & OffPixels[r0[1]]);
+
+ if ((r0[2] & 15) > dither[x & 3])
+ *ptr ^= (0xf0 & OnPixels[r0[2]]);
+ else
+ *ptr ^= (0xf0 & OffPixels[r0[2]]);
+
+ ptr ++;
+ }
+ break;
+
+ case 8 :
+ for (x = xsize; x > 0; x --, r0 += 3, r1 += 3)
+ {
+ if (r0[0] == r1[0])
+ *ptr++ = r0[0];
+ else
+ *ptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize;
+
+ if (r0[1] == r1[1])
+ *ptr++ = r0[1];
+ else
+ *ptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize;
+
+ if (r0[2] == r1[2])
+ *ptr++ = r0[2];
+ else
+ *ptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize;
+
+ ptr ++;
+ }
+ break;
+ }
+ break;
+
+ case CUPS_ORDER_BANDED :
+ cptr = ptr;
+ mptr = ptr + bandwidth;
+ yptr = ptr + 2 * bandwidth;
+
+ memset(ptr + 3 * bandwidth, 255, bandwidth);
+
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if (*r0++ > dither[x & 15])
+ *cptr ^= bitmask;
+ if (*r0++ > dither[x & 15])
+ *mptr ^= bitmask;
+ if (*r0++ > dither[x & 15])
+ *yptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ bitmask = 0xc0 >> (bitoffset & 7);
+ dither = Floyd8x8[y & 7];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 63) > dither[x & 7])
+ *cptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *cptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *mptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *mptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *yptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *yptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask > 3)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 0xc0;
+
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ }
+ }
+ break;
+
+ case 4 :
+ bitmask = 0xf0 >> (bitoffset & 7);
+ dither = Floyd4x4[y & 3];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 15) > dither[x & 3])
+ *cptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *cptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *mptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *mptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *yptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *yptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask == 0xf0)
+ bitmask = 0x0f;
+ else
+ {
+ bitmask = 0xf0;
+
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ }
+ }
+ break;
+
+ case 8 :
+ for (x = xsize; x > 0; x --, r0 += 3, r1 += 3)
+ {
+ if (r0[0] == r1[0])
+ *cptr++ = r0[0];
+ else
+ *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize;
+
+ if (r0[1] == r1[1])
+ *mptr++ = r0[1];
+ else
+ *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize;
+
+ if (r0[2] == r1[2])
+ *yptr++ = r0[2];
+ else
+ *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+
+ case CUPS_ORDER_PLANAR :
+ if (z == 3)
+ {
+ memset(row, 255, header->cupsBytesPerLine);
+ break;
+ }
+
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ switch (z)
+ {
+ case 0 :
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if (r0[0] > dither[x & 15])
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 1 :
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if (r0[1] > dither[x & 15])
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if (r0[2] > dither[x & 15])
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+ }
+ break;
+
+ case 2 :
+ bitmask = 0xc0 >> (bitoffset & 7);
+ dither = Floyd8x8[y & 7];
+ r0 += z;
+
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if ((*r0 & 63) > dither[x & 7])
+ *ptr ^= (bitmask & OnPixels[*r0]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0]);
+
+ if (bitmask > 3)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 0xc0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 4 :
+ bitmask = 0xf0 >> (bitoffset & 7);
+ dither = Floyd4x4[y & 3];
+ r0 += z;
+
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if ((*r0 & 15) > dither[x & 3])
+ *ptr ^= (bitmask & OnPixels[*r0]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0]);
+
+ if (bitmask == 0xf0)
+ bitmask = 0x0f;
+ else
+ {
+ bitmask = 0xf0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 8 :
+ r0 += z;
+ r1 += z;
+
+ for (x = xsize; x > 0; x --, r0 += 3, r1 += 3)
+ {
+ if (*r0 == *r1)
+ *ptr++ = *r0;
+ else
+ *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+ }
+}
+
+
+/*
+ * 'format_W()' - Convert image data to luminance.
+ */
+
+static void
+format_W(cups_page_header2_t *header, /* I - Page header */
+ unsigned char *row, /* IO - Bitmap data for device */
+ int y, /* I - Current row */
+ int z, /* I - Current plane */
+ int xsize, /* I - Width of image data */
+ int ysize, /* I - Height of image data */
+ int yerr0, /* I - Top Y error */
+ int yerr1, /* I - Bottom Y error */
+ cups_ib_t *r0, /* I - Primary image data */
+ cups_ib_t *r1) /* I - Image data for interpolation */
+{
+ cups_ib_t *ptr, /* Pointer into row */
+ bitmask; /* Current mask for pixel */
+ int bitoffset; /* Current offset in line */
+ int x, /* Current X coordinate on page */
+ *dither; /* Pointer into dither array */
+
+
+ (void)z;
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ ptr = row + bitoffset / 8;
+
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if (*r0++ > dither[x & 15])
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ bitmask = 0xc0 >> (bitoffset & 7);
+ dither = Floyd8x8[y & 7];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 63) > dither[x & 7])
+ *ptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask > 3)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 0xc0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 4 :
+ bitmask = 0xf0 >> (bitoffset & 7);
+ dither = Floyd4x4[y & 3];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 15) > dither[x & 3])
+ *ptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask == 0xf0)
+ bitmask = 0x0f;
+ else
+ {
+ bitmask = 0xf0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 8 :
+ for (x = xsize; x > 0; x --, r0 ++, r1 ++)
+ {
+ if (*r0 == *r1)
+ *ptr++ = *r0;
+ else
+ *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize;
+ }
+ break;
+ }
+}
+
+
+/*
+ * 'format_YMC()' - Convert image data to YMC.
+ */
+
+static void
+format_YMC(cups_page_header2_t *header, /* I - Page header */
+ unsigned char *row, /* IO - Bitmap data for device */
+ int y, /* I - Current row */
+ int z, /* I - Current plane */
+ int xsize, /* I - Width of image data */
+ int ysize, /* I - Height of image data */
+ int yerr0, /* I - Top Y error */
+ int yerr1, /* I - Bottom Y error */
+ cups_ib_t *r0, /* I - Primary image data */
+ cups_ib_t *r1) /* I - Image data for interpolation */
+{
+ cups_ib_t *ptr, /* Pointer into row */
+ *cptr, /* Pointer into cyan */
+ *mptr, /* Pointer into magenta */
+ *yptr, /* Pointer into yellow */
+ bitmask; /* Current mask for pixel */
+ int bitoffset; /* Current offset in line */
+ int bandwidth; /* Width of a color band */
+ int x, /* Current X coordinate on page */
+ *dither; /* Pointer into dither array */
+
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ ptr = row + bitoffset / 8;
+ bandwidth = header->cupsBytesPerLine / 3;
+
+ switch (header->cupsColorOrder)
+ {
+ case CUPS_ORDER_CHUNKED :
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 64 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize ; x > 0; x --, r0 += 3)
+ {
+ if (r0[2] > dither[x & 15])
+ *ptr ^= bitmask;
+ bitmask >>= 1;
+
+ if (r0[1] > dither[x & 15])
+ *ptr ^= bitmask;
+ bitmask >>= 1;
+
+ if (r0[0] > dither[x & 15])
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 64;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ dither = Floyd8x8[y & 7];
+
+ for (x = xsize ; x > 0; x --, r0 += 3)
+ {
+ if ((r0[2] & 63) > dither[x & 7])
+ *ptr ^= (0x30 & OnPixels[r0[2]]);
+ else
+ *ptr ^= (0x30 & OffPixels[r0[2]]);
+
+ if ((r0[1] & 63) > dither[x & 7])
+ *ptr ^= (0x0c & OnPixels[r0[1]]);
+ else
+ *ptr ^= (0x0c & OffPixels[r0[1]]);
+
+ if ((r0[0] & 63) > dither[x & 7])
+ *ptr++ ^= (0x03 & OnPixels[r0[0]]);
+ else
+ *ptr++ ^= (0x03 & OffPixels[r0[0]]);
+ }
+ break;
+
+ case 4 :
+ dither = Floyd4x4[y & 3];
+
+ for (x = xsize ; x > 0; x --, r0 += 3)
+ {
+ if ((r0[2] & 15) > dither[x & 3])
+ *ptr++ ^= (0x0f & OnPixels[r0[2]]);
+ else
+ *ptr++ ^= (0x0f & OffPixels[r0[2]]);
+
+ if ((r0[1] & 15) > dither[x & 3])
+ *ptr ^= (0xf0 & OnPixels[r0[1]]);
+ else
+ *ptr ^= (0xf0 & OffPixels[r0[1]]);
+
+ if ((r0[0] & 15) > dither[x & 3])
+ *ptr++ ^= (0x0f & OnPixels[r0[0]]);
+ else
+ *ptr++ ^= (0x0f & OffPixels[r0[0]]);
+ }
+ break;
+
+ case 8 :
+ for (x = xsize; x > 0; x --, r0 += 3, r1 += 3)
+ {
+ if (r0[2] == r1[2])
+ *ptr++ = r0[2];
+ else
+ *ptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize;
+
+ if (r0[1] == r1[1])
+ *ptr++ = r0[1];
+ else
+ *ptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize;
+
+ if (r0[0] == r1[0])
+ *ptr++ = r0[0];
+ else
+ *ptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+
+ case CUPS_ORDER_BANDED :
+ yptr = ptr;
+ mptr = ptr + bandwidth;
+ cptr = ptr + 2 * bandwidth;
+
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if (*r0++ > dither[x & 15])
+ *cptr ^= bitmask;
+ if (*r0++ > dither[x & 15])
+ *mptr ^= bitmask;
+ if (*r0++ > dither[x & 15])
+ *yptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ bitmask = 0xc0 >> (bitoffset & 7);
+ dither = Floyd8x8[y & 7];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 63) > dither[x & 7])
+ *cptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *cptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *mptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *mptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *yptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *yptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask > 3)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 0xc0;
+
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ }
+ }
+ break;
+
+ case 4 :
+ bitmask = 0xf0 >> (bitoffset & 7);
+ dither = Floyd4x4[y & 3];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 15) > dither[x & 3])
+ *cptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *cptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *mptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *mptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *yptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *yptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask == 0xf0)
+ bitmask = 0x0f;
+ else
+ {
+ bitmask = 0xf0;
+
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ }
+ }
+ break;
+
+ case 8 :
+ for (x = xsize; x > 0; x --, r0 += 3, r1 += 3)
+ {
+ if (r0[0] == r1[0])
+ *cptr++ = r0[0];
+ else
+ *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize;
+
+ if (r0[1] == r1[1])
+ *mptr++ = r0[1];
+ else
+ *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize;
+
+ if (r0[2] == r1[2])
+ *yptr++ = r0[2];
+ else
+ *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+
+ case CUPS_ORDER_PLANAR :
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ switch (z)
+ {
+ case 2 :
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if (r0[0] > dither[x & 15])
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 1 :
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if (r0[1] > dither[x & 15])
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 0 :
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if (r0[2] > dither[x & 15])
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+ }
+ break;
+
+ case 2 :
+ bitmask = 0xc0 >> (bitoffset & 7);
+ dither = Floyd8x8[y & 7];
+ z = 2 - z;
+ r0 += z;
+
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if ((*r0 & 63) > dither[x & 7])
+ *ptr ^= (bitmask & OnPixels[*r0]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0]);
+
+ if (bitmask > 3)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 0xc0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 4 :
+ bitmask = 0xf0 >> (bitoffset & 7);
+ dither = Floyd4x4[y & 3];
+ z = 2 - z;
+ r0 += z;
+
+ for (x = xsize; x > 0; x --, r0 += 3)
+ {
+ if ((*r0 & 15) > dither[x & 3])
+ *ptr ^= (bitmask & OnPixels[*r0]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0]);
+
+ if (bitmask == 0xf0)
+ bitmask = 0x0f;
+ else
+ {
+ bitmask = 0xf0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 8 :
+ z = 2 - z;
+ r0 += z;
+ r1 += z;
+
+ for (x = xsize; x > 0; x --, r0 += 3, r1 += 3)
+ {
+ if (*r0 == *r1)
+ *ptr++ = *r0;
+ else
+ *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+ }
+}
+
+
+/*
+ * 'format_YMCK()' - Convert image data to YMCK.
+ */
+
+static void
+format_YMCK(cups_page_header2_t *header,/* I - Page header */
+ unsigned char *row, /* IO - Bitmap data for device */
+ int y, /* I - Current row */
+ int z, /* I - Current plane */
+ int xsize, /* I - Width of image data */
+ int ysize, /* I - Height of image data */
+ int yerr0, /* I - Top Y error */
+ int yerr1, /* I - Bottom Y error */
+ cups_ib_t *r0, /* I - Primary image data */
+ cups_ib_t *r1) /* I - Image data for interpolation */
+{
+ cups_ib_t *ptr, /* Pointer into row */
+ *cptr, /* Pointer into cyan */
+ *mptr, /* Pointer into magenta */
+ *yptr, /* Pointer into yellow */
+ *kptr, /* Pointer into black */
+ bitmask; /* Current mask for pixel */
+ int bitoffset; /* Current offset in line */
+ int bandwidth; /* Width of a color band */
+ int x, /* Current X coordinate on page */
+ *dither; /* Pointer into dither array */
+ int pc, pm, py; /* CMY pixels */
+
+
+ switch (XPosition)
+ {
+ case -1 :
+ bitoffset = 0;
+ break;
+ default :
+ bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2);
+ break;
+ case 1 :
+ bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize);
+ break;
+ }
+
+ ptr = row + bitoffset / 8;
+ bandwidth = header->cupsBytesPerLine / 4;
+
+ switch (header->cupsColorOrder)
+ {
+ case CUPS_ORDER_CHUNKED :
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 128 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize ; x > 0; x --)
+ {
+ pc = *r0++ > dither[x & 15];
+ pm = *r0++ > dither[x & 15];
+ py = *r0++ > dither[x & 15];
+
+ if (pc && pm && py)
+ {
+ bitmask >>= 3;
+ *ptr ^= bitmask;
+ }
+ else
+ {
+ if (py)
+ *ptr ^= bitmask;
+ bitmask >>= 1;
+
+ if (pm)
+ *ptr ^= bitmask;
+ bitmask >>= 1;
+
+ if (pc)
+ *ptr ^= bitmask;
+ bitmask >>= 1;
+ }
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 128;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ dither = Floyd8x8[y & 7];
+
+ for (x = xsize ; x > 0; x --, r0 += 4)
+ {
+ if ((r0[2] & 63) > dither[x & 7])
+ *ptr ^= (0xc0 & OnPixels[r0[2]]);
+ else
+ *ptr ^= (0xc0 & OffPixels[r0[2]]);
+
+ if ((r0[1] & 63) > dither[x & 7])
+ *ptr ^= (0x30 & OnPixels[r0[1]]);
+ else
+ *ptr ^= (0x30 & OffPixels[r0[1]]);
+
+ if ((r0[0] & 63) > dither[x & 7])
+ *ptr ^= (0x0c & OnPixels[r0[0]]);
+ else
+ *ptr ^= (0x0c & OffPixels[r0[0]]);
+
+ if ((r0[3] & 63) > dither[x & 7])
+ *ptr++ ^= (0x03 & OnPixels[r0[3]]);
+ else
+ *ptr++ ^= (0x03 & OffPixels[r0[3]]);
+ }
+ break;
+
+ case 4 :
+ dither = Floyd4x4[y & 3];
+
+ for (x = xsize ; x > 0; x --, r0 += 4)
+ {
+ if ((r0[2] & 15) > dither[x & 3])
+ *ptr ^= (0xf0 & OnPixels[r0[2]]);
+ else
+ *ptr ^= (0xf0 & OffPixels[r0[2]]);
+
+ if ((r0[1] & 15) > dither[x & 3])
+ *ptr++ ^= (0x0f & OnPixels[r0[1]]);
+ else
+ *ptr++ ^= (0x0f & OffPixels[r0[1]]);
+
+ if ((r0[0] & 15) > dither[x & 3])
+ *ptr ^= (0xf0 & OnPixels[r0[0]]);
+ else
+ *ptr ^= (0xf0 & OffPixels[r0[0]]);
+
+ if ((r0[3] & 15) > dither[x & 3])
+ *ptr++ ^= (0x0f & OnPixels[r0[3]]);
+ else
+ *ptr++ ^= (0x0f & OffPixels[r0[3]]);
+ }
+ break;
+
+ case 8 :
+ for (x = xsize; x > 0; x --, r0 += 4, r1 += 4)
+ {
+ if (r0[2] == r1[2])
+ *ptr++ = r0[2];
+ else
+ *ptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize;
+
+ if (r0[1] == r1[1])
+ *ptr++ = r0[1];
+ else
+ *ptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize;
+
+ if (r0[0] == r1[0])
+ *ptr++ = r0[0];
+ else
+ *ptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize;
+
+ if (r0[3] == r1[3])
+ *ptr++ = r0[3];
+ else
+ *ptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+
+ case CUPS_ORDER_BANDED :
+ yptr = ptr;
+ mptr = ptr + bandwidth;
+ cptr = ptr + 2 * bandwidth;
+ kptr = ptr + 3 * bandwidth;
+
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize; x > 0; x --)
+ {
+ pc = *r0++ > dither[x & 15];
+ pm = *r0++ > dither[x & 15];
+ py = *r0++ > dither[x & 15];
+
+ if (pc && pm && py)
+ *kptr ^= bitmask;
+ else
+ {
+ if (pc)
+ *cptr ^= bitmask;
+ if (pm)
+ *mptr ^= bitmask;
+ if (py)
+ *yptr ^= bitmask;
+ }
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ bitmask = 0xc0 >> (bitoffset & 7);
+ dither = Floyd8x8[y & 7];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 63) > dither[x & 7])
+ *cptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *cptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *mptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *mptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *yptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *yptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 63) > dither[x & 7])
+ *kptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *kptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask > 3)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 0xc0;
+
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ }
+ }
+ break;
+
+ case 4 :
+ bitmask = 0xf0 >> (bitoffset & 7);
+ dither = Floyd4x4[y & 3];
+
+ for (x = xsize; x > 0; x --)
+ {
+ if ((*r0 & 15) > dither[x & 3])
+ *cptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *cptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *mptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *mptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *yptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *yptr ^= (bitmask & OffPixels[*r0++]);
+
+ if ((*r0 & 15) > dither[x & 3])
+ *kptr ^= (bitmask & OnPixels[*r0++]);
+ else
+ *kptr ^= (bitmask & OffPixels[*r0++]);
+
+ if (bitmask == 0xf0)
+ bitmask = 0x0f;
+ else
+ {
+ bitmask = 0xf0;
+
+ cptr ++;
+ mptr ++;
+ yptr ++;
+ kptr ++;
+ }
+ }
+ break;
+
+ case 8 :
+ for (x = xsize; x > 0; x --, r0 += 4, r1 += 4)
+ {
+ if (r0[0] == r1[0])
+ *cptr++ = r0[0];
+ else
+ *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize;
+
+ if (r0[1] == r1[1])
+ *mptr++ = r0[1];
+ else
+ *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize;
+
+ if (r0[2] == r1[2])
+ *yptr++ = r0[2];
+ else
+ *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize;
+
+ if (r0[3] == r1[3])
+ *kptr++ = r0[3];
+ else
+ *kptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+
+ case CUPS_ORDER_PLANAR :
+ switch (header->cupsBitsPerColor)
+ {
+ case 1 :
+ bitmask = 0x80 >> (bitoffset & 7);
+ dither = Floyd16x16[y & 15];
+
+ for (x = xsize; x > 0; x --)
+ {
+ pc = *r0++ > dither[x & 15];
+ pm = *r0++ > dither[x & 15];
+ py = *r0++ > dither[x & 15];
+
+ if ((pc && pm && py && z == 3) ||
+ (pc && z == 2) || (pm && z == 1) || (py && z == 0))
+ *ptr ^= bitmask;
+
+ if (bitmask > 1)
+ bitmask >>= 1;
+ else
+ {
+ bitmask = 0x80;
+ ptr ++;
+ }
+ }
+ break;
+
+ case 2 :
+ bitmask = 0xc0 >> (bitoffset & 7);
+ dither = Floyd8x8[y & 7];
+ if (z == 3)
+ r0 += 3;
+ else
+ r0 += 2 - z;
+
+ for (x = xsize; x > 0; x --, r0 += 4)
+ {
+ if ((*r0 & 63) > dither[x & 7])
+ *ptr ^= (bitmask & OnPixels[*r0]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0]);
+
+ if (bitmask > 3)
+ bitmask >>= 2;
+ else
+ {
+ bitmask = 0xc0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 4 :
+ bitmask = 0xf0 >> (bitoffset & 7);
+ dither = Floyd4x4[y & 3];
+ if (z == 3)
+ r0 += 3;
+ else
+ r0 += 2 - z;
+
+ for (x = xsize; x > 0; x --, r0 += 4)
+ {
+ if ((*r0 & 15) > dither[x & 3])
+ *ptr ^= (bitmask & OnPixels[*r0]);
+ else
+ *ptr ^= (bitmask & OffPixels[*r0]);
+
+ if (bitmask == 0xf0)
+ bitmask = 0x0f;
+ else
+ {
+ bitmask = 0xf0;
+
+ ptr ++;
+ }
+ }
+ break;
+
+ case 8 :
+ if (z == 3)
+ {
+ r0 += 3;
+ r1 += 3;
+ }
+ else
+ {
+ r0 += 2 - z;
+ r1 += 2 - z;
+ }
+
+ for (x = xsize; x > 0; x --, r0 += 4, r1 += 4)
+ {
+ if (*r0 == *r1)
+ *ptr++ = *r0;
+ else
+ *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize;
+ }
+ break;
+ }
+ break;
+ }
+}
+
+
+/*
+ * 'make_lut()' - Make a lookup table given gamma and brightness values.
+ */
+
+static void
+make_lut(cups_ib_t *lut, /* I - Lookup table */
+ int colorspace, /* I - Colorspace */
+ float g, /* I - Image gamma */
+ float b) /* I - Image brightness */
+{
+ int i; /* Looping var */
+ int v; /* Current value */
+
+
+ g = 1.0 / g;
+ b = 1.0 / b;
+
+ for (i = 0; i < 256; i ++)
+ {
+ if (colorspace < 0)
+ v = 255.0 * b * (1.0 - pow(1.0 - (float)i / 255.0, g)) + 0.5;
+ else
+ v = 255.0 * (1.0 - b * (1.0 - pow((float)i / 255.0, g))) + 0.5;
+
+ if (v < 0)
+ *lut++ = 0;
+ else if (v > 255)
+ *lut++ = 255;
+ else
+ *lut++ = v;
+ }
+}
+
+
+/*
+ * 'raster_cb()' - Validate the page header.
+ */
+
+static int /* O - 0 if OK, -1 if not */
+raster_cb(
+ cups_page_header2_t *header, /* IO - Raster header */
+ int preferred_bits) /* I - Preferred bits per color */
+{
+ /*
+ * Ensure that colorimetric colorspaces use at least 8 bits per
+ * component...
+ */
+
+ if ((header->cupsColorSpace == CUPS_CSPACE_CIEXYZ ||
+ header->cupsColorSpace == CUPS_CSPACE_CIELab ||
+ header->cupsColorSpace >= CUPS_CSPACE_ICC1) &&
+ header->cupsBitsPerColor < 8)
+ header->cupsBitsPerColor = 8;
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/interpret.c b/filter/interpret.c
new file mode 100644
index 000000000..eb7e43810
--- /dev/null
+++ b/filter/interpret.c
@@ -0,0 +1,1688 @@
+/*
+ * "$Id$"
+ *
+ * PPD command interpreter for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsRasterInterpretPPD() - Interpret PPD commands to create a page header.
+ * _cupsRasterExecPS() - Execute PostScript code to initialize a page
+ * header.
+ * cleartomark_stack() - Clear to the last mark ([) on the stack.
+ * copy_stack() - Copy the top N stack objects.
+ * delete_stack() - Free memory used by a stack.
+ * error_object() - Add an object's value to the current error
+ * message.
+ * error_stack() - Add a stack to the current error message.
+ * index_stack() - Copy the Nth value on the stack.
+ * new_stack() - Create a new stack.
+ * pop_stock() - Pop the top object off the stack.
+ * push_stack() - Push an object on the stack.
+ * roll_stack() - Rotate stack objects.
+ * scan_ps() - Scan a string for the next PS object.
+ * setpagedevice() - Simulate the PostScript setpagedevice operator.
+ * DEBUG_object() - Print an object value.
+ * DEBUG_stack() - Print a stack.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+
+
+/*
+ * Stack values for the PostScript mini-interpreter...
+ */
+
+typedef enum
+{
+ CUPS_PS_NAME,
+ CUPS_PS_NUMBER,
+ CUPS_PS_STRING,
+ CUPS_PS_BOOLEAN,
+ CUPS_PS_NULL,
+ CUPS_PS_START_ARRAY,
+ CUPS_PS_END_ARRAY,
+ CUPS_PS_START_DICT,
+ CUPS_PS_END_DICT,
+ CUPS_PS_START_PROC,
+ CUPS_PS_END_PROC,
+ CUPS_PS_CLEARTOMARK,
+ CUPS_PS_COPY,
+ CUPS_PS_DUP,
+ CUPS_PS_INDEX,
+ CUPS_PS_POP,
+ CUPS_PS_ROLL,
+ CUPS_PS_SETPAGEDEVICE,
+ CUPS_PS_STOPPED,
+ CUPS_PS_OTHER
+} _cups_ps_type_t;
+
+typedef struct
+{
+ _cups_ps_type_t type; /* Object type */
+ union
+ {
+ int boolean; /* Boolean value */
+ char name[64]; /* Name value */
+ double number; /* Number value */
+ char other[64]; /* Other operator */
+ char string[64]; /* Sring value */
+ } value; /* Value */
+} _cups_ps_obj_t;
+
+typedef struct
+{
+ int num_objs, /* Number of objects on stack */
+ alloc_objs; /* Number of allocated objects */
+ _cups_ps_obj_t *objs; /* Objects in stack */
+} _cups_ps_stack_t;
+
+
+/*
+ * Local functions...
+ */
+
+static int cleartomark_stack(_cups_ps_stack_t *st);
+static int copy_stack(_cups_ps_stack_t *st, int count);
+static void delete_stack(_cups_ps_stack_t *st);
+static void error_object(_cups_ps_obj_t *obj);
+static void error_stack(_cups_ps_stack_t *st, const char *title);
+static _cups_ps_obj_t *index_stack(_cups_ps_stack_t *st, int n);
+static _cups_ps_stack_t *new_stack(void);
+static _cups_ps_obj_t *pop_stack(_cups_ps_stack_t *st);
+static _cups_ps_obj_t *push_stack(_cups_ps_stack_t *st,
+ _cups_ps_obj_t *obj);
+static int roll_stack(_cups_ps_stack_t *st, int c, int s);
+static _cups_ps_obj_t *scan_ps(_cups_ps_stack_t *st, char **ptr);
+static int setpagedevice(_cups_ps_stack_t *st,
+ cups_page_header2_t *h,
+ int *preferred_bits);
+#ifdef DEBUG
+static void DEBUG_object(_cups_ps_obj_t *obj);
+static void DEBUG_stack(_cups_ps_stack_t *st);
+#endif /* DEBUG */
+
+
+/*
+ * 'cupsRasterInterpretPPD()' - Interpret PPD commands to create a page header.
+ *
+ * This function is used by raster image processing (RIP) filters like
+ * cgpdftoraster and imagetoraster when writing CUPS raster data for a page.
+ * It is not used by raster printer driver filters which only read CUPS
+ * raster data.
+ *
+ *
+ * @code cupsRasterInterpretPPD@ does not mark the options in the PPD using
+ * the "num_options" and "options" arguments. Instead, mark the options with
+ * @code cupsMarkOptions@ and @code ppdMarkOption@ prior to calling it -
+ * this allows for per-page options without manipulating the options array.
+ *
+ * The "func" argument specifies an optional callback function that is
+ * called prior to the computation of the final raster data. The function
+ * can make changes to the @link cups_page_header2_t@ data as needed to use a
+ * supported raster format and then returns 0 on success and -1 if the
+ * requested attributes cannot be supported.
+ *
+ *
+ * @code cupsRasterInterpretPPD@ supports a subset of the PostScript language.
+ * Currently only the @code [@, @code ]@, @code <<@, @code >>@, @code {@,
+ * @code }@, @code cleartomark@, @code copy@, @code dup@, @code index@,
+ * @code pop@, @code roll@, @code setpagedevice@, and @code stopped@ operators
+ * are supported.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+int /* O - 0 on success, -1 on failure */
+cupsRasterInterpretPPD(
+ cups_page_header2_t *h, /* O - Page header to create */
+ ppd_file_t *ppd, /* I - PPD file */
+ int num_options, /* I - Number of options */
+ cups_option_t *options, /* I - Options */
+ cups_interpret_cb_t func) /* I - Optional page header callback (@code NULL@ for none) */
+{
+ int status; /* Cummulative status */
+ char *code; /* Code to run */
+ const char *val; /* Option value */
+ ppd_size_t *size; /* Current size */
+ float left, /* Left position */
+ bottom, /* Bottom position */
+ right, /* Right position */
+ top; /* Top position */
+ int preferred_bits; /* Preferred bits per color */
+
+
+ /*
+ * Range check input...
+ */
+
+ _cupsRasterClearError();
+
+ if (!h)
+ {
+ _cupsRasterAddError("Page header cannot be NULL!\n");
+ return (-1);
+ }
+
+ /*
+ * Reset the page header to the defaults...
+ */
+
+ memset(h, 0, sizeof(cups_page_header2_t));
+
+ h->NumCopies = 1;
+ h->PageSize[0] = 612;
+ h->PageSize[1] = 792;
+ h->HWResolution[0] = 100;
+ h->HWResolution[1] = 100;
+ h->cupsBitsPerColor = 1;
+ h->cupsColorOrder = CUPS_ORDER_CHUNKED;
+ h->cupsColorSpace = CUPS_CSPACE_K;
+ h->cupsBorderlessScalingFactor = 1.0f;
+ h->cupsPageSize[0] = 612.0f;
+ h->cupsPageSize[1] = 792.0f;
+ h->cupsImagingBBox[0] = 0.0f;
+ h->cupsImagingBBox[1] = 0.0f;
+ h->cupsImagingBBox[2] = 612.0f;
+ h->cupsImagingBBox[3] = 792.0f;
+
+ strcpy(h->cupsPageSizeName, "Letter");
+
+#ifdef __APPLE__
+ /*
+ * cupsInteger0 is also used for the total page count on Mac OS X; set an
+ * uncommon default value so we can tell if the driver is using cupsInteger0.
+ */
+
+ h->cupsInteger[0] = 0x80000000;
+#endif /* __APPLE__ */
+
+ /*
+ * Apply patches and options to the page header...
+ */
+
+ status = 0;
+ preferred_bits = 0;
+
+ if (ppd)
+ {
+ /*
+ * Apply any patch code (used to override the defaults...)
+ */
+
+ if (ppd->patches)
+ status |= _cupsRasterExecPS(h, &preferred_bits, ppd->patches);
+
+ /*
+ * Then apply printer options in the proper order...
+ */
+
+ if ((code = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, 0.0)) != NULL)
+ {
+ status |= _cupsRasterExecPS(h, &preferred_bits, code);
+ free(code);
+ }
+
+ if ((code = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL)
+ {
+ status |= _cupsRasterExecPS(h, &preferred_bits, code);
+ free(code);
+ }
+
+ if ((code = ppdEmitString(ppd, PPD_ORDER_PROLOG, 0.0)) != NULL)
+ {
+ status |= _cupsRasterExecPS(h, &preferred_bits, code);
+ free(code);
+ }
+
+ if ((code = ppdEmitString(ppd, PPD_ORDER_PAGE, 0.0)) != NULL)
+ {
+ status |= _cupsRasterExecPS(h, &preferred_bits, code);
+ free(code);
+ }
+ }
+
+ /*
+ * Allow option override for page scaling...
+ */
+
+ if ((val = cupsGetOption("cupsBorderlessScalingFactor", num_options,
+ options)) != NULL)
+ {
+ double sc = atof(val); /* Scale factor */
+
+ if (sc >= 0.1 && sc <= 2.0)
+ h->cupsBorderlessScalingFactor = (float)sc;
+ }
+
+ /*
+ * Get the margins for the current size...
+ */
+
+ if ((size = ppdPageSize(ppd, NULL)) != NULL)
+ {
+ /*
+ * Use the margins from the PPD file...
+ */
+
+ left = size->left;
+ bottom = size->bottom;
+ right = size->right;
+ top = size->top;
+
+ strlcpy(h->cupsPageSizeName, size->name, sizeof(h->cupsPageSizeName));
+
+ h->cupsPageSize[0] = size->width;
+ h->cupsPageSize[1] = size->length;
+ }
+ else
+ {
+ /*
+ * Use the default margins...
+ */
+
+ left = 0.0f;
+ bottom = 0.0f;
+ right = 612.0f;
+ top = 792.0f;
+ }
+
+ h->PageSize[0] = (unsigned)(h->cupsPageSize[0] *
+ h->cupsBorderlessScalingFactor);
+ h->PageSize[1] = (unsigned)(h->cupsPageSize[1] *
+ h->cupsBorderlessScalingFactor);
+ h->Margins[0] = (unsigned)(left *
+ h->cupsBorderlessScalingFactor);
+ h->Margins[1] = (unsigned)(bottom *
+ h->cupsBorderlessScalingFactor);
+ h->ImagingBoundingBox[0] = (unsigned)(left *
+ h->cupsBorderlessScalingFactor);
+ h->ImagingBoundingBox[1] = (unsigned)(bottom *
+ h->cupsBorderlessScalingFactor);
+ h->ImagingBoundingBox[2] = (unsigned)(right *
+ h->cupsBorderlessScalingFactor);
+ h->ImagingBoundingBox[3] = (unsigned)(top *
+ h->cupsBorderlessScalingFactor);
+ h->cupsImagingBBox[0] = (float)left;
+ h->cupsImagingBBox[1] = (float)bottom;
+ h->cupsImagingBBox[2] = (float)right;
+ h->cupsImagingBBox[3] = (float)top;
+
+ /*
+ * Use the callback to validate the page header...
+ */
+
+ if (func && (*func)(h, preferred_bits))
+ {
+ _cupsRasterAddError("Page header callback returned error.\n");
+ return (-1);
+ }
+
+ /*
+ * Check parameters...
+ */
+
+ if (!h->HWResolution[0] || !h->HWResolution[1] ||
+ !h->PageSize[0] || !h->PageSize[1] ||
+ (h->cupsBitsPerColor != 1 && h->cupsBitsPerColor != 2 &&
+ h->cupsBitsPerColor != 4 && h->cupsBitsPerColor != 8 &&
+ h->cupsBitsPerColor != 16) ||
+ h->cupsBorderlessScalingFactor < 0.1 ||
+ h->cupsBorderlessScalingFactor > 2.0)
+ {
+ _cupsRasterAddError("Page header uses unsupported values.\n");
+ return (-1);
+ }
+
+ /*
+ * Compute the bitmap parameters...
+ */
+
+ h->cupsWidth = (int)((right - left) * h->cupsBorderlessScalingFactor *
+ h->HWResolution[0] / 72.0f + 0.5f);
+ h->cupsHeight = (int)((top - bottom) * h->cupsBorderlessScalingFactor *
+ h->HWResolution[1] / 72.0f + 0.5f);
+
+ switch (h->cupsColorSpace)
+ {
+ case CUPS_CSPACE_W :
+ case CUPS_CSPACE_K :
+ case CUPS_CSPACE_WHITE :
+ case CUPS_CSPACE_GOLD :
+ case CUPS_CSPACE_SILVER :
+ case CUPS_CSPACE_SW :
+ h->cupsNumColors = 1;
+ h->cupsBitsPerPixel = h->cupsBitsPerColor;
+ break;
+
+ default :
+ /*
+ * Ensure that colorimetric colorspaces use at least 8 bits per
+ * component...
+ */
+
+ if (h->cupsColorSpace >= CUPS_CSPACE_CIEXYZ &&
+ h->cupsBitsPerColor < 8)
+ h->cupsBitsPerColor = 8;
+
+ /*
+ * Figure out the number of bits per pixel...
+ */
+
+ if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
+ {
+ if (h->cupsBitsPerColor >= 8)
+ h->cupsBitsPerPixel = h->cupsBitsPerColor * 3;
+ else
+ h->cupsBitsPerPixel = h->cupsBitsPerColor * 4;
+ }
+ else
+ h->cupsBitsPerPixel = h->cupsBitsPerColor;
+
+ h->cupsNumColors = 3;
+ break;
+
+ case CUPS_CSPACE_KCMYcm :
+ if (h->cupsBitsPerColor == 1)
+ {
+ if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
+ h->cupsBitsPerPixel = 8;
+ else
+ h->cupsBitsPerPixel = 1;
+
+ h->cupsNumColors = 6;
+ break;
+ }
+
+ /*
+ * Fall through to CMYK code...
+ */
+
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_RGBW :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
+ h->cupsBitsPerPixel = h->cupsBitsPerColor * 4;
+ else
+ h->cupsBitsPerPixel = h->cupsBitsPerColor;
+
+ h->cupsNumColors = 4;
+ break;
+
+ case CUPS_CSPACE_DEVICE1 :
+ case CUPS_CSPACE_DEVICE2 :
+ case CUPS_CSPACE_DEVICE3 :
+ case CUPS_CSPACE_DEVICE4 :
+ case CUPS_CSPACE_DEVICE5 :
+ case CUPS_CSPACE_DEVICE6 :
+ case CUPS_CSPACE_DEVICE7 :
+ case CUPS_CSPACE_DEVICE8 :
+ case CUPS_CSPACE_DEVICE9 :
+ case CUPS_CSPACE_DEVICEA :
+ case CUPS_CSPACE_DEVICEB :
+ case CUPS_CSPACE_DEVICEC :
+ case CUPS_CSPACE_DEVICED :
+ case CUPS_CSPACE_DEVICEE :
+ case CUPS_CSPACE_DEVICEF :
+ h->cupsNumColors = h->cupsColorSpace - CUPS_CSPACE_DEVICE1 + 1;
+
+ if (h->cupsColorOrder == CUPS_ORDER_CHUNKED)
+ h->cupsBitsPerPixel = h->cupsBitsPerColor * h->cupsNumColors;
+ else
+ h->cupsBitsPerPixel = h->cupsBitsPerColor;
+ break;
+ }
+
+ h->cupsBytesPerLine = (h->cupsBitsPerPixel * h->cupsWidth + 7) / 8;
+
+ if (h->cupsColorOrder == CUPS_ORDER_BANDED)
+ h->cupsBytesPerLine *= h->cupsNumColors;
+
+ return (status);
+}
+
+
+/*
+ * '_cupsRasterExecPS()' - Execute PostScript code to initialize a page header.
+ */
+
+int /* O - 0 on success, -1 on error */
+_cupsRasterExecPS(
+ cups_page_header2_t *h, /* O - Page header */
+ int *preferred_bits,/* O - Preferred bits per color */
+ const char *code) /* I - PS code to execute */
+{
+ _cups_ps_stack_t *st; /* PostScript value stack */
+ _cups_ps_obj_t *obj; /* Object from top of stack */
+ char *codecopy, /* Copy of code */
+ *codeptr; /* Pointer into copy of code */
+
+
+ DEBUG_printf(("_cupsRasterExecPS(h=%p, preferred_bits=%p, code=\"%s\")\n",
+ h, preferred_bits, code ? code : "(null)"));
+
+ /*
+ * Copy the PostScript code and create a stack...
+ */
+
+ if ((codecopy = strdup(code)) == NULL)
+ {
+ _cupsRasterAddError("Unable to duplicate code string.\n");
+ return (-1);
+ }
+
+ if ((st = new_stack()) == NULL)
+ {
+ _cupsRasterAddError("Unable to create stack.\n");
+ free(codecopy);
+ return (-1);
+ }
+
+ /*
+ * Parse the PS string until we run out of data...
+ */
+
+ codeptr = codecopy;
+
+ while ((obj = scan_ps(st, &codeptr)) != NULL)
+ {
+#ifdef DEBUG
+ DEBUG_printf(("_cupsRasterExecPS: Stack (%d objects)\n", st->num_objs));
+ DEBUG_object(obj);
+#endif /* DEBUG */
+
+ switch (obj->type)
+ {
+ default :
+ /* Do nothing for regular values */
+ break;
+
+ case CUPS_PS_CLEARTOMARK :
+ pop_stack(st);
+
+ if (cleartomark_stack(st))
+ _cupsRasterAddError("cleartomark: Stack underflow!\n");
+
+#ifdef DEBUG
+ DEBUG_puts(" dup: ");
+ DEBUG_stack(st);
+#endif /* DEBUG */
+ break;
+
+ case CUPS_PS_COPY :
+ pop_stack(st);
+ if ((obj = pop_stack(st)) != NULL)
+ {
+ copy_stack(st, (int)obj->value.number);
+
+#ifdef DEBUG
+ DEBUG_puts("_cupsRasterExecPS: copy");
+ DEBUG_stack(st);
+#endif /* DEBUG */
+ }
+ break;
+
+ case CUPS_PS_DUP :
+ pop_stack(st);
+ copy_stack(st, 1);
+
+#ifdef DEBUG
+ DEBUG_puts("_cupsRasterExecPS: dup");
+ DEBUG_stack(st);
+#endif /* DEBUG */
+ break;
+
+ case CUPS_PS_INDEX :
+ pop_stack(st);
+ if ((obj = pop_stack(st)) != NULL)
+ {
+ index_stack(st, (int)obj->value.number);
+
+#ifdef DEBUG
+ DEBUG_puts("_cupsRasterExecPS: index");
+ DEBUG_stack(st);
+#endif /* DEBUG */
+ }
+ break;
+
+ case CUPS_PS_POP :
+ pop_stack(st);
+ pop_stack(st);
+
+#ifdef DEBUG
+ DEBUG_puts("_cupsRasterExecPS: pop");
+ DEBUG_stack(st);
+#endif /* DEBUG */
+ break;
+
+ case CUPS_PS_ROLL :
+ pop_stack(st);
+ if ((obj = pop_stack(st)) != NULL)
+ {
+ int c; /* Count */
+
+
+ c = (int)obj->value.number;
+
+ if ((obj = pop_stack(st)) != NULL)
+ {
+ roll_stack(st, (int)obj->value.number, c);
+
+#ifdef DEBUG
+ DEBUG_puts("_cupsRasterExecPS: roll");
+ DEBUG_stack(st);
+#endif /* DEBUG */
+ }
+ }
+ break;
+
+ case CUPS_PS_SETPAGEDEVICE :
+ pop_stack(st);
+ setpagedevice(st, h, preferred_bits);
+
+#ifdef DEBUG
+ DEBUG_puts("_cupsRasterExecPS: setpagedevice");
+ DEBUG_stack(st);
+#endif /* DEBUG */
+ break;
+
+ case CUPS_PS_START_PROC :
+ case CUPS_PS_END_PROC :
+ case CUPS_PS_STOPPED :
+ pop_stack(st);
+ break;
+
+ case CUPS_PS_OTHER :
+ _cupsRasterAddError("Unknown operator \"%s\"!\n", obj->value.other);
+ DEBUG_printf(("_cupsRasterExecPS: Unknown operator \"%s\"!\n",
+ obj->value.other));
+ break;
+ }
+
+ if (obj && obj->type == CUPS_PS_OTHER)
+ break;
+ }
+
+ /*
+ * Cleanup...
+ */
+
+ free(codecopy);
+
+ if (st->num_objs > 0)
+ {
+ error_stack(st, "Stack not empty:");
+
+#ifdef DEBUG
+ DEBUG_puts("_cupsRasterExecPS: Stack not empty:");
+ DEBUG_stack(st);
+#endif /* DEBUG */
+
+ delete_stack(st);
+
+ return (-1);
+ }
+
+ delete_stack(st);
+
+ /*
+ * Return success...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'cleartomark_stack()' - Clear to the last mark ([) on the stack.
+ */
+
+static int /* O - 0 on success, -1 on error */
+cleartomark_stack(_cups_ps_stack_t *st) /* I - Stack */
+{
+ _cups_ps_obj_t *obj; /* Current object on stack */
+
+
+ while ((obj = pop_stack(st)) != NULL)
+ if (obj->type == CUPS_PS_START_ARRAY)
+ break;
+
+ return (obj ? 0 : -1);
+}
+
+
+/*
+ * 'copy_stack()' - Copy the top N stack objects.
+ */
+
+static int /* O - 0 on success, -1 on error */
+copy_stack(_cups_ps_stack_t *st, /* I - Stack */
+ int c) /* I - Number of objects to copy */
+{
+ int n; /* Index */
+
+
+ if (c < 0)
+ return (-1);
+ else if (c == 0)
+ return (0);
+
+ if ((n = st->num_objs - c) < 0)
+ return (-1);
+
+ while (c > 0)
+ {
+ if (!push_stack(st, st->objs + n))
+ return (-1);
+
+ n ++;
+ c --;
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'delete_stack()' - Free memory used by a stack.
+ */
+
+static void
+delete_stack(_cups_ps_stack_t *st) /* I - Stack */
+{
+ free(st->objs);
+ free(st);
+}
+
+
+/*
+ * 'error_object()' - Add an object's value to the current error message.
+ */
+
+static void
+error_object(_cups_ps_obj_t *obj) /* I - Object to add */
+{
+ switch (obj->type)
+ {
+ case CUPS_PS_NAME :
+ _cupsRasterAddError(" /%s", obj->value.name);
+ break;
+
+ case CUPS_PS_NUMBER :
+ _cupsRasterAddError(" %g", obj->value.number);
+ break;
+
+ case CUPS_PS_STRING :
+ _cupsRasterAddError(" (%s)", obj->value.string);
+ break;
+
+ case CUPS_PS_BOOLEAN :
+ if (obj->value.boolean)
+ _cupsRasterAddError(" true");
+ else
+ _cupsRasterAddError(" false");
+ break;
+
+ case CUPS_PS_NULL :
+ _cupsRasterAddError(" null");
+ break;
+
+ case CUPS_PS_START_ARRAY :
+ _cupsRasterAddError(" [");
+ break;
+
+ case CUPS_PS_END_ARRAY :
+ _cupsRasterAddError(" ]");
+ break;
+
+ case CUPS_PS_START_DICT :
+ _cupsRasterAddError(" <<");
+ break;
+
+ case CUPS_PS_END_DICT :
+ _cupsRasterAddError(" >>");
+ break;
+
+ case CUPS_PS_START_PROC :
+ _cupsRasterAddError(" {");
+ break;
+
+ case CUPS_PS_END_PROC :
+ _cupsRasterAddError(" }");
+ break;
+
+ case CUPS_PS_COPY :
+ _cupsRasterAddError(" --copy--");
+ break;
+
+ case CUPS_PS_CLEARTOMARK :
+ _cupsRasterAddError(" --cleartomark--");
+ break;
+
+ case CUPS_PS_DUP :
+ _cupsRasterAddError(" --dup--");
+ break;
+
+ case CUPS_PS_INDEX :
+ _cupsRasterAddError(" --index--");
+ break;
+
+ case CUPS_PS_POP :
+ _cupsRasterAddError(" --pop--");
+ break;
+
+ case CUPS_PS_ROLL :
+ _cupsRasterAddError(" --roll--");
+ break;
+
+ case CUPS_PS_SETPAGEDEVICE :
+ _cupsRasterAddError(" --setpagedevice--");
+ break;
+
+ case CUPS_PS_STOPPED :
+ _cupsRasterAddError(" --stopped--");
+ break;
+
+ case CUPS_PS_OTHER :
+ _cupsRasterAddError(" --%s--", obj->value.other);
+ break;
+ }
+}
+
+
+/*
+ * 'error_stack()' - Add a stack to the current error message...
+ */
+
+static void
+error_stack(_cups_ps_stack_t *st, /* I - Stack */
+ const char *title) /* I - Title string */
+{
+ int c; /* Looping var */
+ _cups_ps_obj_t *obj; /* Current object on stack */
+
+
+ _cupsRasterAddError(title);
+
+ for (obj = st->objs, c = st->num_objs; c > 0; c --, obj ++)
+ error_object(obj);
+
+ _cupsRasterAddError("\n");
+}
+
+
+/*
+ * 'index_stack()' - Copy the Nth value on the stack.
+ */
+
+static _cups_ps_obj_t * /* O - New object */
+index_stack(_cups_ps_stack_t *st, /* I - Stack */
+ int n) /* I - Object index */
+{
+ if (n < 0 || (n = st->num_objs - n - 1) < 0)
+ return (NULL);
+
+ return (push_stack(st, st->objs + n));
+}
+
+
+/*
+ * 'new_stack()' - Create a new stack.
+ */
+
+static _cups_ps_stack_t * /* O - New stack */
+new_stack(void)
+{
+ _cups_ps_stack_t *st; /* New stack */
+
+
+ if ((st = calloc(1, sizeof(_cups_ps_stack_t))) == NULL)
+ return (NULL);
+
+ st->alloc_objs = 32;
+
+ if ((st->objs = calloc(32, sizeof(_cups_ps_obj_t))) == NULL)
+ {
+ free(st);
+ return (NULL);
+ }
+ else
+ return (st);
+}
+
+
+/*
+ * 'pop_stock()' - Pop the top object off the stack.
+ */
+
+static _cups_ps_obj_t * /* O - Object */
+pop_stack(_cups_ps_stack_t *st) /* I - Stack */
+{
+ if (st->num_objs > 0)
+ {
+ st->num_objs --;
+
+ return (st->objs + st->num_objs);
+ }
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'push_stack()' - Push an object on the stack.
+ */
+
+static _cups_ps_obj_t * /* O - New object */
+push_stack(_cups_ps_stack_t *st, /* I - Stack */
+ _cups_ps_obj_t *obj) /* I - Object */
+{
+ _cups_ps_obj_t *temp; /* New object */
+
+
+ if (st->num_objs >= st->alloc_objs)
+ {
+
+
+ st->alloc_objs += 32;
+
+ if ((temp = realloc(st->objs, st->alloc_objs *
+ sizeof(_cups_ps_obj_t))) == NULL)
+ return (NULL);
+
+ st->objs = temp;
+ memset(temp + st->num_objs, 0, 32 * sizeof(_cups_ps_obj_t));
+ }
+
+ temp = st->objs + st->num_objs;
+ st->num_objs ++;
+
+ memcpy(temp, obj, sizeof(_cups_ps_obj_t));
+
+ return (temp);
+}
+
+
+/*
+ * 'roll_stack()' - Rotate stack objects.
+ */
+
+static int /* O - 0 on success, -1 on error */
+roll_stack(_cups_ps_stack_t *st, /* I - Stack */
+ int c, /* I - Number of objects */
+ int s) /* I - Amount to shift */
+{
+ _cups_ps_obj_t *temp; /* Temporary array of objects */
+ int n; /* Index into array */
+
+
+ DEBUG_printf((" roll_stack(st=%p, s=%d, c=%d)\n", st, s, c));
+
+ /*
+ * Range check input...
+ */
+
+ if (c < 0)
+ return (-1);
+ else if (c == 0)
+ return (0);
+
+ if ((n = st->num_objs - c) < 0)
+ return (-1);
+
+ s %= c;
+
+ if (s == 0)
+ return (0);
+
+ /*
+ * Copy N objects and move things around...
+ */
+
+ if (s < 0)
+ {
+ /*
+ * Shift down...
+ */
+
+ s = -s;
+
+ if ((temp = calloc(s, sizeof(_cups_ps_obj_t))) == NULL)
+ return (-1);
+
+ memcpy(temp, st->objs + n, s * sizeof(_cups_ps_obj_t));
+ memmove(st->objs + n, st->objs + n + s, (c - s) * sizeof(_cups_ps_obj_t));
+ memcpy(st->objs + n + c - s, temp, s * sizeof(_cups_ps_obj_t));
+ }
+ else
+ {
+ /*
+ * Shift up...
+ */
+
+ if ((temp = calloc(s, sizeof(_cups_ps_obj_t))) == NULL)
+ return (-1);
+
+ memcpy(temp, st->objs + n + c - s, s * sizeof(_cups_ps_obj_t));
+ memmove(st->objs + n + s, st->objs + n,
+ (c - s) * sizeof(_cups_ps_obj_t));
+ memcpy(st->objs + n, temp, s * sizeof(_cups_ps_obj_t));
+ }
+
+ free(temp);
+
+ return (0);
+}
+
+
+/*
+ * 'scan_ps()' - Scan a string for the next PS object.
+ */
+
+static _cups_ps_obj_t * /* O - New object or NULL on EOF */
+scan_ps(_cups_ps_stack_t *st, /* I - Stack */
+ char **ptr) /* IO - String pointer */
+{
+ _cups_ps_obj_t obj; /* Current object */
+ char *start, /* Start of object */
+ *cur, /* Current position */
+ *valptr, /* Pointer into value string */
+ *valend; /* End of value string */
+ int parens; /* Parenthesis nesting level */
+
+
+ /*
+ * Skip leading whitespace...
+ */
+
+ for (cur = *ptr; *cur; cur ++)
+ {
+ if (*cur == '%')
+ {
+ /*
+ * Comment, skip to end of line...
+ */
+
+ for (cur ++; *cur && *cur != '\n' && *cur != '\r'; cur ++);
+
+ if (!*cur)
+ cur --;
+ }
+ else if (!isspace(*cur & 255))
+ break;
+ }
+
+ if (!*cur)
+ {
+ *ptr = NULL;
+
+ return (NULL);
+ }
+
+ /*
+ * See what we have...
+ */
+
+ memset(&obj, 0, sizeof(obj));
+
+ switch (*cur)
+ {
+ case '(' : /* (string) */
+ obj.type = CUPS_PS_STRING;
+ start = cur;
+
+ for (cur ++, parens = 1, valptr = obj.value.string,
+ valend = obj.value.string + sizeof(obj.value.string) - 1;
+ *cur;
+ cur ++)
+ {
+ if (*cur == ')' && parens == 1)
+ break;
+
+ if (*cur == '(')
+ parens ++;
+ else if (*cur == ')')
+ parens --;
+
+ if (valptr >= valend)
+ {
+ *ptr = start;
+
+ return (NULL);
+ }
+
+ if (*cur == '\\')
+ {
+ /*
+ * Decode escaped character...
+ */
+
+ cur ++;
+
+ if (*cur == 'b')
+ *valptr++ = '\b';
+ else if (*cur == 'f')
+ *valptr++ = '\f';
+ else if (*cur == 'n')
+ *valptr++ = '\n';
+ else if (*cur == 'r')
+ *valptr++ = '\r';
+ else if (*cur == 't')
+ *valptr++ = '\t';
+ else if (*cur >= '0' && *cur <= '7')
+ {
+ int ch = *cur - '0';
+
+ if (cur[1] >= '0' && cur[1] <= '7')
+ {
+ cur ++;
+ ch = (ch << 3) + *cur - '0';
+ }
+
+ if (cur[1] >= '0' && cur[1] <= '7')
+ {
+ cur ++;
+ ch = (ch << 3) + *cur - '0';
+ }
+
+ *valptr++ = ch;
+ }
+ else if (*cur == '\r')
+ {
+ if (cur[1] == '\n')
+ cur ++;
+ }
+ else if (*cur != '\n')
+ *valptr++ = *cur;
+ }
+ else
+ *valptr++ = *cur;
+ }
+
+ if (*cur != ')')
+ {
+ *ptr = start;
+
+ return (NULL);
+ }
+
+ cur ++;
+ break;
+
+ case '[' : /* Start array */
+ obj.type = CUPS_PS_START_ARRAY;
+ cur ++;
+ break;
+
+ case ']' : /* End array */
+ obj.type = CUPS_PS_END_ARRAY;
+ cur ++;
+ break;
+
+ case '<' : /* Start dictionary or hex string */
+ if (cur[1] == '<')
+ {
+ obj.type = CUPS_PS_START_DICT;
+ cur += 2;
+ }
+ else
+ {
+ obj.type = CUPS_PS_STRING;
+ start = cur;
+
+ for (cur ++, valptr = obj.value.string,
+ valend = obj.value.string + sizeof(obj.value.string) - 1;
+ *cur;
+ cur ++)
+ {
+ int ch; /* Current character */
+
+
+
+ if (*cur == '>')
+ break;
+ else if (valptr >= valend || !isxdigit(*cur & 255))
+ {
+ *ptr = start;
+ return (NULL);
+ }
+
+ if (*cur >= '0' && *cur <= '9')
+ ch = (*cur - '0') << 4;
+ else
+ ch = (tolower(*cur) - 'a' + 10) << 4;
+
+ if (isxdigit(cur[1] & 255))
+ {
+ cur ++;
+
+ if (*cur >= '0' && *cur <= '9')
+ ch |= *cur - '0';
+ else
+ ch |= tolower(*cur) - 'a' + 10;
+ }
+
+ *valptr++ = ch;
+ }
+
+ if (*cur != '>')
+ {
+ *ptr = start;
+ return (NULL);
+ }
+
+ cur ++;
+ }
+ break;
+
+ case '>' : /* End dictionary? */
+ if (cur[1] == '>')
+ {
+ obj.type = CUPS_PS_END_DICT;
+ cur += 2;
+ }
+ else
+ {
+ obj.type = CUPS_PS_OTHER;
+ obj.value.other[0] = *cur;
+
+ cur ++;
+ }
+ break;
+
+ case '{' : /* Start procedure */
+ obj.type = CUPS_PS_START_PROC;
+ cur ++;
+ break;
+
+ case '}' : /* End procedure */
+ obj.type = CUPS_PS_END_PROC;
+ cur ++;
+ break;
+
+ case '-' : /* Possible number */
+ case '+' :
+ if (!isdigit(cur[1] & 255) && cur[1] != '.')
+ {
+ obj.type = CUPS_PS_OTHER;
+ obj.value.other[0] = *cur;
+
+ cur ++;
+ break;
+ }
+
+ case '0' : /* Number */
+ case '1' :
+ case '2' :
+ case '3' :
+ case '4' :
+ case '5' :
+ case '6' :
+ case '7' :
+ case '8' :
+ case '9' :
+ case '.' :
+ obj.type = CUPS_PS_NUMBER;
+
+ start = cur;
+ for (cur ++; *cur; cur ++)
+ if (!isdigit(*cur & 255))
+ break;
+
+ if (*cur == '#')
+ {
+ /*
+ * Integer with radix...
+ */
+
+ obj.value.number = strtol(cur + 1, &cur, atoi(start));
+ break;
+ }
+ else if (strchr(".Ee()<>[]{}/%", *cur) || isspace(*cur & 255))
+ {
+ /*
+ * Integer or real number...
+ */
+
+ obj.value.number = _cupsStrScand(start, &cur, localeconv());
+ break;
+ }
+ else
+ cur = start;
+
+ default : /* Operator/variable name */
+ start = cur;
+
+ if (*cur == '/')
+ {
+ obj.type = CUPS_PS_NAME;
+ valptr = obj.value.name;
+ valend = obj.value.name + sizeof(obj.value.name) - 1;
+ cur ++;
+ }
+ else
+ {
+ obj.type = CUPS_PS_OTHER;
+ valptr = obj.value.other;
+ valend = obj.value.other + sizeof(obj.value.other) - 1;
+ }
+
+ while (*cur)
+ {
+ if (strchr("()<>[]{}/%", *cur) || isspace(*cur & 255))
+ break;
+ else if (valptr < valend)
+ *valptr++ = *cur++;
+ else
+ {
+ *ptr = start;
+ return (NULL);
+ }
+ }
+
+ if (obj.type == CUPS_PS_OTHER)
+ {
+ if (!strcmp(obj.value.other, "true"))
+ {
+ obj.type = CUPS_PS_BOOLEAN;
+ obj.value.boolean = 1;
+ }
+ else if (!strcmp(obj.value.other, "false"))
+ {
+ obj.type = CUPS_PS_BOOLEAN;
+ obj.value.boolean = 0;
+ }
+ else if (!strcmp(obj.value.other, "null"))
+ obj.type = CUPS_PS_NULL;
+ else if (!strcmp(obj.value.other, "cleartomark"))
+ obj.type = CUPS_PS_CLEARTOMARK;
+ else if (!strcmp(obj.value.other, "copy"))
+ obj.type = CUPS_PS_COPY;
+ else if (!strcmp(obj.value.other, "dup"))
+ obj.type = CUPS_PS_DUP;
+ else if (!strcmp(obj.value.other, "index"))
+ obj.type = CUPS_PS_INDEX;
+ else if (!strcmp(obj.value.other, "pop"))
+ obj.type = CUPS_PS_POP;
+ else if (!strcmp(obj.value.other, "roll"))
+ obj.type = CUPS_PS_ROLL;
+ else if (!strcmp(obj.value.other, "setpagedevice"))
+ obj.type = CUPS_PS_SETPAGEDEVICE;
+ else if (!strcmp(obj.value.other, "stopped"))
+ obj.type = CUPS_PS_STOPPED;
+ }
+ break;
+ }
+
+ /*
+ * Save the current position in the string and return the new object...
+ */
+
+ *ptr = cur;
+
+ return (push_stack(st, &obj));
+}
+
+
+/*
+ * 'setpagedevice()' - Simulate the PostScript setpagedevice operator.
+ */
+
+static int /* O - 0 on success, -1 on error */
+setpagedevice(
+ _cups_ps_stack_t *st, /* I - Stack */
+ cups_page_header2_t *h, /* O - Page header */
+ int *preferred_bits)/* O - Preferred bits per color */
+{
+ int i; /* Index into array */
+ _cups_ps_obj_t *obj, /* Current object */
+ *end; /* End of dictionary */
+ const char *name; /* Attribute name */
+
+
+ /*
+ * Make sure we have a dictionary on the stack...
+ */
+
+ if (st->num_objs == 0)
+ return (-1);
+
+ obj = end = st->objs + st->num_objs - 1;
+
+ if (obj->type != CUPS_PS_END_DICT)
+ return (-1);
+
+ obj --;
+
+ while (obj > st->objs)
+ {
+ if (obj->type == CUPS_PS_START_DICT)
+ break;
+
+ obj --;
+ }
+
+ if (obj < st->objs)
+ return (-1);
+
+ /*
+ * Found the start of the dictionary, empty the stack to this point...
+ */
+
+ st->num_objs = obj - st->objs;
+
+ /*
+ * Now pull /name and value pairs from the dictionary...
+ */
+
+ DEBUG_puts("setpagedevice: Dictionary:");
+
+ for (obj ++; obj < end; obj ++)
+ {
+ /*
+ * Grab the name...
+ */
+
+ if (obj->type != CUPS_PS_NAME)
+ return (-1);
+
+ name = obj->value.name;
+ obj ++;
+
+#ifdef DEBUG
+ DEBUG_printf(("setpagedevice: /%s ", name));
+ DEBUG_object(obj);
+#endif /* DEBUG */
+
+ /*
+ * Then grab the value...
+ */
+
+ if (!strcmp(name, "MediaClass") && obj->type == CUPS_PS_STRING)
+ strlcpy(h->MediaClass, obj->value.string, sizeof(h->MediaClass));
+ else if (!strcmp(name, "MediaColor") && obj->type == CUPS_PS_STRING)
+ strlcpy(h->MediaColor, obj->value.string, sizeof(h->MediaColor));
+ else if (!strcmp(name, "MediaType") && obj->type == CUPS_PS_STRING)
+ strlcpy(h->MediaType, obj->value.string, sizeof(h->MediaType));
+ else if (!strcmp(name, "OutputType") && obj->type == CUPS_PS_STRING)
+ strlcpy(h->OutputType, obj->value.string, sizeof(h->OutputType));
+ else if (!strcmp(name, "AdvanceDistance") && obj->type == CUPS_PS_NUMBER)
+ h->AdvanceDistance = (unsigned)obj->value.number;
+ else if (!strcmp(name, "AdvanceMedia") && obj->type == CUPS_PS_NUMBER)
+ h->AdvanceMedia = (unsigned)obj->value.number;
+ else if (!strcmp(name, "Collate") && obj->type == CUPS_PS_BOOLEAN)
+ h->Collate = (unsigned)obj->value.boolean;
+ else if (!strcmp(name, "CutMedia") && obj->type == CUPS_PS_NUMBER)
+ h->CutMedia = (cups_cut_t)(unsigned)obj->value.number;
+ else if (!strcmp(name, "Duplex") && obj->type == CUPS_PS_BOOLEAN)
+ h->Duplex = (unsigned)obj->value.boolean;
+ else if (!strcmp(name, "HWResolution") && obj->type == CUPS_PS_START_ARRAY)
+ {
+ if (obj[1].type == CUPS_PS_NUMBER && obj[2].type == CUPS_PS_NUMBER &&
+ obj[3].type == CUPS_PS_END_ARRAY)
+ {
+ h->HWResolution[0] = (unsigned)obj[1].value.number;
+ h->HWResolution[1] = (unsigned)obj[2].value.number;
+ obj += 3;
+ }
+ else
+ return (-1);
+ }
+ else if (!strcmp(name, "InsertSheet") && obj->type == CUPS_PS_BOOLEAN)
+ h->InsertSheet = (unsigned)obj->value.boolean;
+ else if (!strcmp(name, "Jog") && obj->type == CUPS_PS_NUMBER)
+ h->Jog = (unsigned)obj->value.number;
+ else if (!strcmp(name, "LeadingEdge") && obj->type == CUPS_PS_NUMBER)
+ h->LeadingEdge = (unsigned)obj->value.number;
+ else if (!strcmp(name, "ManualFeed") && obj->type == CUPS_PS_BOOLEAN)
+ h->ManualFeed = (unsigned)obj->value.boolean;
+ else if ((!strcmp(name, "cupsMediaPosition") ||
+ !strcmp(name, "MediaPosition")) && obj->type == CUPS_PS_NUMBER)
+ {
+ /*
+ * cupsMediaPosition is supported for backwards compatibility only.
+ * We added it back in the Ghostscript 5.50 days to work around a
+ * bug in Ghostscript WRT handling of MediaPosition and setpagedevice.
+ *
+ * All new development should set MediaPosition...
+ */
+
+ h->MediaPosition = (unsigned)obj->value.number;
+ }
+ else if (!strcmp(name, "MediaWeight") && obj->type == CUPS_PS_NUMBER)
+ h->MediaWeight = (unsigned)obj->value.number;
+ else if (!strcmp(name, "MirrorPrint") && obj->type == CUPS_PS_BOOLEAN)
+ h->MirrorPrint = (unsigned)obj->value.boolean;
+ else if (!strcmp(name, "NegativePrint") && obj->type == CUPS_PS_BOOLEAN)
+ h->NegativePrint = (unsigned)obj->value.boolean;
+ else if (!strcmp(name, "NumCopies") && obj->type == CUPS_PS_NUMBER)
+ h->NumCopies = (unsigned)obj->value.number;
+ else if (!strcmp(name, "Orientation") && obj->type == CUPS_PS_NUMBER)
+ h->Orientation = (unsigned)obj->value.number;
+ else if (!strcmp(name, "OutputFaceUp") && obj->type == CUPS_PS_BOOLEAN)
+ h->OutputFaceUp = (unsigned)obj->value.boolean;
+ else if (!strcmp(name, "PageSize") && obj->type == CUPS_PS_START_ARRAY)
+ {
+ if (obj[1].type == CUPS_PS_NUMBER && obj[2].type == CUPS_PS_NUMBER &&
+ obj[3].type == CUPS_PS_END_ARRAY)
+ {
+ h->cupsPageSize[0] = (float)obj[1].value.number;
+ h->cupsPageSize[1] = (float)obj[2].value.number;
+
+ h->PageSize[0] = (unsigned)obj[1].value.number;
+ h->PageSize[1] = (unsigned)obj[2].value.number;
+
+ obj += 3;
+ }
+ else
+ return (-1);
+ }
+ else if (!strcmp(name, "Separations") && obj->type == CUPS_PS_BOOLEAN)
+ h->Separations = (unsigned)obj->value.boolean;
+ else if (!strcmp(name, "TraySwitch") && obj->type == CUPS_PS_BOOLEAN)
+ h->TraySwitch = (unsigned)obj->value.boolean;
+ else if (!strcmp(name, "Tumble") && obj->type == CUPS_PS_BOOLEAN)
+ h->Tumble = (unsigned)obj->value.boolean;
+ else if (!strcmp(name, "cupsMediaType") && obj->type == CUPS_PS_NUMBER)
+ h->cupsMediaType = (unsigned)obj->value.number;
+ else if (!strcmp(name, "cupsBitsPerColor") && obj->type == CUPS_PS_NUMBER)
+ h->cupsBitsPerColor = (unsigned)obj->value.number;
+ else if (!strcmp(name, "cupsPreferredBitsPerColor") &&
+ obj->type == CUPS_PS_NUMBER)
+ *preferred_bits = (int)obj->value.number;
+ else if (!strcmp(name, "cupsColorOrder") && obj->type == CUPS_PS_NUMBER)
+ h->cupsColorOrder = (cups_order_t)(unsigned)obj->value.number;
+ else if (!strcmp(name, "cupsColorSpace") && obj->type == CUPS_PS_NUMBER)
+ h->cupsColorSpace = (cups_cspace_t)(unsigned)obj->value.number;
+ else if (!strcmp(name, "cupsCompression") && obj->type == CUPS_PS_NUMBER)
+ h->cupsCompression = (unsigned)obj->value.number;
+ else if (!strcmp(name, "cupsRowCount") && obj->type == CUPS_PS_NUMBER)
+ h->cupsRowCount = (unsigned)obj->value.number;
+ else if (!strcmp(name, "cupsRowFeed") && obj->type == CUPS_PS_NUMBER)
+ h->cupsRowFeed = (unsigned)obj->value.number;
+ else if (!strcmp(name, "cupsRowStep") && obj->type == CUPS_PS_NUMBER)
+ h->cupsRowStep = (unsigned)obj->value.number;
+ else if (!strcmp(name, "cupsBorderlessScalingFactor") &&
+ obj->type == CUPS_PS_NUMBER)
+ h->cupsBorderlessScalingFactor = (float)obj->value.number;
+ else if (!strncmp(name, "cupsInteger", 11) && obj->type == CUPS_PS_NUMBER)
+ {
+ if ((i = atoi(name + 11)) < 0 || i > 15)
+ return (-1);
+
+ h->cupsInteger[i] = (unsigned)obj->value.number;
+ }
+ else if (!strncmp(name, "cupsReal", 8) && obj->type == CUPS_PS_NUMBER)
+ {
+ if ((i = atoi(name + 8)) < 0 || i > 15)
+ return (-1);
+
+ h->cupsReal[i] = (float)obj->value.number;
+ }
+ else if (!strncmp(name, "cupsString", 10) && obj->type == CUPS_PS_STRING)
+ {
+ if ((i = atoi(name + 10)) < 0 || i > 15)
+ return (-1);
+
+ strlcpy(h->cupsString[i], obj->value.string, sizeof(h->cupsString[i]));
+ }
+ else if (!strcmp(name, "cupsMarkerType") && obj->type == CUPS_PS_STRING)
+ strlcpy(h->cupsMarkerType, obj->value.string, sizeof(h->cupsMarkerType));
+ else if (!strcmp(name, "cupsPageSizeName") && obj->type == CUPS_PS_STRING)
+ strlcpy(h->cupsPageSizeName, obj->value.string,
+ sizeof(h->cupsPageSizeName));
+ else if (!strcmp(name, "cupsRenderingIntent") &&
+ obj->type == CUPS_PS_STRING)
+ strlcpy(h->cupsRenderingIntent, obj->value.string,
+ sizeof(h->cupsRenderingIntent));
+ else
+ {
+ /*
+ * Ignore unknown name+value...
+ */
+
+ DEBUG_printf((" Unknown name (\"%s\") or value...\n", name));
+
+ while (obj[1].type != CUPS_PS_NAME && obj < end)
+ obj ++;
+ }
+ }
+
+ return (0);
+}
+
+
+#ifdef DEBUG
+/*
+ * 'DEBUG_object()' - Print an object's value...
+ */
+
+static void
+DEBUG_object(_cups_ps_obj_t *obj) /* I - Object to print */
+{
+ switch (obj->type)
+ {
+ case CUPS_PS_NAME :
+ DEBUG_printf(("/%s\n", obj->value.name));
+ break;
+
+ case CUPS_PS_NUMBER :
+ DEBUG_printf(("%g\n", obj->value.number));
+ break;
+
+ case CUPS_PS_STRING :
+ DEBUG_printf(("(%s)\n", obj->value.string));
+ break;
+
+ case CUPS_PS_BOOLEAN :
+ if (obj->value.boolean)
+ DEBUG_puts("true");
+ else
+ DEBUG_puts("false");
+ break;
+
+ case CUPS_PS_NULL :
+ DEBUG_puts("null");
+ break;
+
+ case CUPS_PS_START_ARRAY :
+ DEBUG_puts("[");
+ break;
+
+ case CUPS_PS_END_ARRAY :
+ DEBUG_puts("]");
+ break;
+
+ case CUPS_PS_START_DICT :
+ DEBUG_puts("<<");
+ break;
+
+ case CUPS_PS_END_DICT :
+ DEBUG_puts(">>");
+ break;
+
+ case CUPS_PS_START_PROC :
+ DEBUG_puts("{");
+ break;
+
+ case CUPS_PS_END_PROC :
+ DEBUG_puts("}");
+ break;
+
+ case CUPS_PS_CLEARTOMARK :
+ DEBUG_puts("--cleartomark--");
+ break;
+
+ case CUPS_PS_COPY :
+ DEBUG_puts("--copy--");
+ break;
+
+ case CUPS_PS_DUP :
+ DEBUG_puts("--dup--");
+ break;
+
+ case CUPS_PS_INDEX :
+ DEBUG_puts("--index--");
+ break;
+
+ case CUPS_PS_POP :
+ DEBUG_puts("--pop--");
+ break;
+
+ case CUPS_PS_ROLL :
+ DEBUG_puts("--roll--");
+ break;
+
+ case CUPS_PS_SETPAGEDEVICE :
+ DEBUG_puts("--setpagedevice--");
+ break;
+
+ case CUPS_PS_STOPPED :
+ DEBUG_puts("--stopped--");
+ break;
+
+ case CUPS_PS_OTHER :
+ DEBUG_printf(("--%s--\n", obj->value.other));
+ break;
+ }
+}
+
+
+/*
+ * 'DEBUG_stack()' - Print a stack...
+ */
+
+static void
+DEBUG_stack(_cups_ps_stack_t *st) /* I - Stack */
+{
+ int c; /* Looping var */
+ _cups_ps_obj_t *obj; /* Current object on stack */
+
+
+ for (obj = st->objs, c = st->num_objs; c > 0; c --, obj ++)
+ DEBUG_object(obj);
+}
+#endif /* DEBUG */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/libcupsimage2.def b/filter/libcupsimage2.def
new file mode 100644
index 000000000..3c20284f5
--- /dev/null
+++ b/filter/libcupsimage2.def
@@ -0,0 +1,14 @@
+LIBRARY libcupsimage2
+VERSION 2.3
+EXPORTS
+cupsRasterClose
+cupsRasterErrorString
+cupsRasterInterpretPPD
+cupsRasterOpen
+cupsRasterOpenIO
+cupsRasterReadHeader
+cupsRasterReadHeader2
+cupsRasterReadPixels
+cupsRasterWriteHeader
+cupsRasterWriteHeader2
+cupsRasterWritePixels
diff --git a/filter/libcupsimage_s.exp b/filter/libcupsimage_s.exp
new file mode 100644
index 000000000..57f4259f9
--- /dev/null
+++ b/filter/libcupsimage_s.exp
@@ -0,0 +1,16 @@
+_cupsImagePutCol
+_cupsImagePutRow
+_cupsImageReadBMP
+_cupsImageReadGIF
+_cupsImageReadJPEG
+_cupsImageReadPIX
+_cupsImageReadPNG
+_cupsImageReadPNM
+_cupsImageReadPhotoCD
+_cupsImageReadSGI
+_cupsImageReadSunRaster
+_cupsImageReadTIFF
+_cupsImageZoomDelete
+_cupsImageZoomFill
+_cupsImageZoomNew
+_cupsRasterExecPS
diff --git a/filter/pdftops.c b/filter/pdftops.c
new file mode 100644
index 000000000..76da65dba
--- /dev/null
+++ b/filter/pdftops.c
@@ -0,0 +1,621 @@
+/*
+ * "$Id$"
+ *
+ * PDF to PostScript filter front-end for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Main entry for filter...
+ * cancel_job() - Flag the job as canceled.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <cups/ppd.h>
+#include <cups/string-private.h>
+#include <cups/language-private.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+
+/*
+ * Local functions...
+ */
+
+static void cancel_job(int sig);
+
+
+/*
+ * Local globals...
+ */
+
+static int job_canceled = 0;
+
+
+/*
+ * 'main()' - Main entry for filter...
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int fd; /* Copy file descriptor */
+ char *filename, /* PDF file to convert */
+ tempfile[1024]; /* Temporary file */
+ char buffer[8192]; /* Copy buffer */
+ int bytes; /* Bytes copied */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ const char *val; /* Option value */
+ int orientation, /* Output orientation */
+ fit; /* Fit output to default page size? */
+ ppd_file_t *ppd; /* PPD file */
+ ppd_size_t *size; /* Current page size */
+ int pdf_pid, /* Process ID for pdftops */
+ pdf_argc, /* Number of args for pdftops */
+ pstops_pid, /* Process ID of pstops filter */
+ pstops_pipe[2], /* Pipe to pstops filter */
+ wait_children, /* Number of child processes left */
+ wait_pid, /* Process ID from wait() */
+ wait_status, /* Status from child */
+ exit_status = 0; /* Exit status */
+ char *pdf_argv[100], /* Arguments for pdftops/gs */
+ pdf_width[255], /* Paper width */
+ pdf_height[255], /* Paper height */
+ pstops_path[1024], /* Path to pstops program */
+ *pstops_argv[7], /* Arguments for pstops filter */
+ *pstops_options, /* Options for pstops filter */
+ *pstops_start, /* Start of pstops filter option */
+ *pstops_end; /* End of pstops filter option */
+ const char *cups_serverbin; /* CUPS_SERVERBIN environment variable */
+#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 broken pipe signals...
+ */
+
+ signal(SIGPIPE, SIG_IGN);
+
+ /*
+ * Make sure we have the right number of arguments for CUPS!
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job user title copies options [filename]"),
+ argv[0]);
+ return (1);
+ }
+
+ /*
+ * Register a signal handler to cleanly cancel a job.
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, cancel_job);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = cancel_job;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, cancel_job);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Copy stdin if needed...
+ */
+
+ if (argc == 6)
+ {
+ /*
+ * Copy stdin to a temp file...
+ */
+
+ if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
+ {
+ perror("DEBUG: Unable to copy PDF file");
+ return (1);
+ }
+
+ fprintf(stderr, "DEBUG: pdftops - copying to temp print file \"%s\"\n",
+ tempfile);
+
+ while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
+ write(fd, buffer, bytes);
+
+ close(fd);
+
+ filename = tempfile;
+ }
+ else
+ {
+ /*
+ * Use the filename on the command-line...
+ */
+
+ filename = argv[6];
+ tempfile[0] = '\0';
+ }
+
+ /*
+ * Load the PPD file and mark options...
+ */
+
+ ppd = ppdOpenFile(getenv("PPD"));
+ num_options = cupsParseOptions(argv[5], 0, &options);
+
+ ppdMarkDefaults(ppd);
+ cupsMarkOptions(ppd, num_options, options);
+
+ /*
+ * Build the pstops command-line...
+ */
+
+ if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
+ cups_serverbin = CUPS_SERVERBIN;
+
+ snprintf(pstops_path, sizeof(pstops_path), "%s/filter/pstops",
+ cups_serverbin);
+
+ pstops_options = strdup(argv[5]);
+
+ if ((pstops_start = strstr(pstops_options, "fitplot")) != NULL &&
+ (!pstops_start[7] || isspace(pstops_start[7] & 255)))
+ {
+ /*
+ * Strip [no]fitplot option...
+ */
+
+ pstops_end = pstops_start + 7;
+
+ if ((pstops_start - pstops_options) >= 2 &&
+ !strncmp(pstops_start - 2, "no", 2))
+ pstops_start -= 2;
+
+ while (*pstops_end && isspace(*pstops_end & 255))
+ pstops_end ++;
+
+ _cups_strcpy(pstops_start, pstops_end);
+ }
+
+ if ((pstops_start = strstr(pstops_options, "fit-to-page")) != NULL &&
+ (!pstops_start[11] || isspace(pstops_start[11] & 255)))
+ {
+ /*
+ * Strip [no]fit-to-page option...
+ */
+
+ pstops_end = pstops_start + 11;
+
+ if ((pstops_start - pstops_options) >= 2 &&
+ !strncmp(pstops_start - 2, "no", 2))
+ pstops_start -= 2;
+
+ while (*pstops_end && isspace(*pstops_end & 255))
+ pstops_end ++;
+
+ _cups_strcpy(pstops_start, pstops_end);
+ }
+
+ if ((pstops_start = strstr(pstops_options, "landscape")) != NULL &&
+ (!pstops_start[9] || isspace(pstops_start[9] & 255)))
+ {
+ /*
+ * Strip [no]landscape option...
+ */
+
+ pstops_end = pstops_start + 9;
+
+ if ((pstops_start - pstops_options) >= 2 &&
+ !strncmp(pstops_start - 2, "no", 2))
+ pstops_start -= 2;
+
+ while (*pstops_end && isspace(*pstops_end & 255))
+ pstops_end ++;
+
+ _cups_strcpy(pstops_start, pstops_end);
+ }
+
+ if ((pstops_start = strstr(pstops_options, "orientation-requested=")) != NULL)
+ {
+ /*
+ * Strip [no]fitplot option...
+ */
+
+ pstops_end = pstops_start + 22;
+ while (*pstops_end && !isspace(*pstops_end & 255))
+ pstops_end ++;
+
+ _cups_strcpy(pstops_start, pstops_end);
+ }
+
+ pstops_argv[0] = argv[0]; /* Printer */
+ pstops_argv[1] = argv[1]; /* Job */
+ pstops_argv[2] = argv[2]; /* User */
+ pstops_argv[3] = argv[3]; /* Title */
+ pstops_argv[4] = argv[4]; /* Copies */
+ pstops_argv[5] = pstops_options; /* Options */
+ pstops_argv[6] = NULL;
+
+ /*
+ * Build the command-line for the pdftops or gs filter...
+ */
+
+#ifdef HAVE_PDFTOPS
+ pdf_argv[0] = (char *)"pdftops";
+ pdf_argc = 1;
+#else
+ pdf_argv[0] = (char *)"gs";
+ pdf_argv[1] = (char *)"-q";
+ pdf_argv[2] = (char *)"-dNOPAUSE";
+ pdf_argv[3] = (char *)"-dBATCH";
+ pdf_argv[4] = (char *)"-dSAFER";
+# ifdef HAVE_GHOSTSCRIPT_PS2WRITE
+ pdf_argv[5] = (char *)"-sDEVICE=ps2write";
+# else
+ pdf_argv[5] = (char *)"-sDEVICE=pswrite";
+# endif /* HAVE_GHOSTSCRIPT_PS2WRITE */
+ pdf_argv[6] = (char *)"-sOUTPUTFILE=%stdout";
+ pdf_argc = 7;
+#endif /* HAVE_PDFTOPS */
+
+ if (ppd)
+ {
+ /*
+ * Set language level and TrueType font handling...
+ */
+
+ if (ppd->language_level == 1)
+ {
+#ifdef HAVE_PDFTOPS
+ pdf_argv[pdf_argc++] = (char *)"-level1";
+ pdf_argv[pdf_argc++] = (char *)"-noembtt";
+#else
+ pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=1";
+#endif /* HAVE_PDFTOPS */
+ }
+ else if (ppd->language_level == 2)
+ {
+#ifdef HAVE_PDFTOPS
+ pdf_argv[pdf_argc++] = (char *)"-level2";
+ if (!ppd->ttrasterizer)
+ pdf_argv[pdf_argc++] = (char *)"-noembtt";
+#else
+ pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=2";
+#endif /* HAVE_PDFTOPS */
+ }
+ else
+#ifdef HAVE_PDFTOPS
+ pdf_argv[pdf_argc++] = (char *)"-level3";
+#else
+ pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=3";
+#endif /* HAVE_PDFTOPS */
+
+ if ((val = cupsGetOption("fitplot", num_options, options)) == NULL)
+ val = cupsGetOption("fit-to-page", num_options, options);
+
+ if (val && _cups_strcasecmp(val, "no") && _cups_strcasecmp(val, "off") &&
+ _cups_strcasecmp(val, "false"))
+ fit = 1;
+ else
+ fit = 0;
+
+ /*
+ * Set output page size...
+ */
+
+ size = ppdPageSize(ppd, NULL);
+ if (size && fit)
+ {
+ /*
+ * Got the size, now get the orientation...
+ */
+
+ orientation = 0;
+
+ if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
+ {
+ if (_cups_strcasecmp(val, "no") != 0 && _cups_strcasecmp(val, "off") != 0 &&
+ _cups_strcasecmp(val, "false") != 0)
+ orientation = 1;
+ }
+ else if ((val = cupsGetOption("orientation-requested", num_options,
+ options)) != NULL)
+ {
+ /*
+ * Map IPP orientation values to 0 to 3:
+ *
+ * 3 = 0 degrees = 0
+ * 4 = 90 degrees = 1
+ * 5 = -90 degrees = 3
+ * 6 = 180 degrees = 2
+ */
+
+ orientation = atoi(val) - 3;
+ if (orientation >= 2)
+ orientation ^= 1;
+ }
+
+#ifdef HAVE_PDFTOPS
+ if (orientation & 1)
+ {
+ snprintf(pdf_width, sizeof(pdf_width), "%.0f", size->length);
+ snprintf(pdf_height, sizeof(pdf_height), "%.0f", size->width);
+ }
+ else
+ {
+ snprintf(pdf_width, sizeof(pdf_width), "%.0f", size->width);
+ snprintf(pdf_height, sizeof(pdf_height), "%.0f", size->length);
+ }
+
+ pdf_argv[pdf_argc++] = (char *)"-paperw";
+ pdf_argv[pdf_argc++] = pdf_width;
+ pdf_argv[pdf_argc++] = (char *)"-paperh";
+ pdf_argv[pdf_argc++] = pdf_height;
+ pdf_argv[pdf_argc++] = (char *)"-expand";
+
+#else
+ if (orientation & 1)
+ {
+ snprintf(pdf_width, sizeof(pdf_width), "-dDEVICEWIDTHPOINTS=%.0f",
+ size->length);
+ snprintf(pdf_height, sizeof(pdf_height), "-dDEVICEHEIGHTPOINTS=%.0f",
+ size->width);
+ }
+ else
+ {
+ snprintf(pdf_width, sizeof(pdf_width), "-dDEVICEWIDTHPOINTS=%.0f",
+ size->width);
+ snprintf(pdf_height, sizeof(pdf_height), "-dDEVICEHEIGHTPOINTS=%.0f",
+ size->length);
+ }
+
+ pdf_argv[pdf_argc++] = pdf_width;
+ pdf_argv[pdf_argc++] = pdf_height;
+#endif /* HAVE_PDFTOPS */
+ }
+#if defined(HAVE_PDFTOPS) && defined(HAVE_PDFTOPS_WITH_ORIGPAGESIZES)
+ else
+ {
+ /*
+ * Use the page sizes of the original PDF document, this way documents
+ * which contain pages of different sizes can be printed correctly
+ */
+
+ pdf_argv[pdf_argc++] = (char *)"-origpagesizes";
+ }
+#endif /* HAVE_PDFTOPS && HAVE_PDFTOPS_WITH_ORIGPAGESIZES */
+ }
+
+#ifdef HAVE_PDFTOPS
+ pdf_argv[pdf_argc++] = filename;
+ pdf_argv[pdf_argc++] = (char *)"-";
+#else
+ pdf_argv[pdf_argc++] = (char *)"-c";
+ pdf_argv[pdf_argc++] = (char *)"save pop";
+ pdf_argv[pdf_argc++] = (char *)"-f";
+ pdf_argv[pdf_argc++] = filename;
+#endif /* HAVE_PDFTOPS */
+
+ pdf_argv[pdf_argc] = NULL;
+
+ /*
+ * Execute "pdftops/gs | pstops"...
+ */
+
+ if (pipe(pstops_pipe))
+ {
+ perror("DEBUG: Unable to create pipe");
+
+ exit_status = 1;
+ goto error;
+ }
+
+ if ((pdf_pid = fork()) == 0)
+ {
+ /*
+ * Child comes here...
+ */
+
+ dup2(pstops_pipe[1], 1);
+ close(pstops_pipe[0]);
+ close(pstops_pipe[1]);
+
+#ifdef HAVE_PDFTOPS
+ execv(CUPS_PDFTOPS, pdf_argv);
+ perror("DEBUG: Unable to execute pdftops program");
+#else
+ execv(CUPS_GHOSTSCRIPT, pdf_argv);
+ perror("DEBUG: Unable to execute gs program");
+#endif /* HAVE_PDFTOPS */
+
+ exit(1);
+ }
+ else if (pdf_pid < 0)
+ {
+ /*
+ * Unable to fork!
+ */
+
+#ifdef HAVE_PDFTOPS
+ perror("DEBUG: Unable to execute pdftops program");
+#else
+ perror("DEBUG: Unable to execute gs program");
+#endif /* HAVE_PDFTOPS */
+
+ exit_status = 1;
+ goto error;
+ }
+
+ fprintf(stderr, "DEBUG: Started filter %s (PID %d)\n", pdf_argv[0], pdf_pid);
+
+ if ((pstops_pid = fork()) == 0)
+ {
+ /*
+ * Child comes here...
+ */
+
+ dup2(pstops_pipe[0], 0);
+ close(pstops_pipe[0]);
+ close(pstops_pipe[1]);
+
+ execv(pstops_path, pstops_argv);
+ perror("DEBUG: Unable to execute pstops program");
+
+ exit(1);
+ }
+ else if (pstops_pid < 0)
+ {
+ /*
+ * Unable to fork!
+ */
+
+ perror("DEBUG: Unable to execute pstops program");
+
+ exit_status = 1;
+ goto error;
+ }
+
+ fprintf(stderr, "DEBUG: Started filter pstops (PID %d)\n", pstops_pid);
+
+ close(pstops_pipe[0]);
+ close(pstops_pipe[1]);
+
+ /*
+ * Wait for the child processes to exit...
+ */
+
+ wait_children = 2;
+
+ while (wait_children > 0)
+ {
+ /*
+ * Wait until we get a valid process ID or the job is canceled...
+ */
+
+ while ((wait_pid = wait(&wait_status)) < 0 && errno == EINTR)
+ {
+ if (job_canceled)
+ {
+ kill(pdf_pid, SIGTERM);
+ kill(pstops_pid, SIGTERM);
+
+ job_canceled = 0;
+ }
+ }
+
+ if (wait_pid < 0)
+ break;
+
+ wait_children --;
+
+ /*
+ * Report child status...
+ */
+
+ if (wait_status)
+ {
+ if (WIFEXITED(wait_status))
+ {
+ exit_status = WEXITSTATUS(wait_status);
+
+ fprintf(stderr, "DEBUG: PID %d (%s) stopped with status %d!\n",
+ wait_pid,
+#ifdef HAVE_PDFTOPS
+ wait_pid == pdf_pid ? "pdftops" : "pstops",
+#else
+ wait_pid == pdf_pid ? "gs" : "pstops",
+#endif /* HAVE_PDFTOPS */
+ exit_status);
+ }
+ else if (WTERMSIG(wait_status) == SIGTERM)
+ {
+ fprintf(stderr,
+ "DEBUG: PID %d (%s) was terminated normally with signal %d!\n",
+ wait_pid,
+#ifdef HAVE_PDFTOPS
+ wait_pid == pdf_pid ? "pdftops" : "pstops",
+#else
+ wait_pid == pdf_pid ? "gs" : "pstops",
+#endif /* HAVE_PDFTOPS */
+ exit_status);
+ }
+ else
+ {
+ exit_status = WTERMSIG(wait_status);
+
+ fprintf(stderr, "DEBUG: PID %d (%s) crashed on signal %d!\n", wait_pid,
+#ifdef HAVE_PDFTOPS
+ wait_pid == pdf_pid ? "pdftops" : "pstops",
+#else
+ wait_pid == pdf_pid ? "gs" : "pstops",
+#endif /* HAVE_PDFTOPS */
+ exit_status);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "DEBUG: PID %d (%s) exited with no errors.\n", wait_pid,
+#ifdef HAVE_PDFTOPS
+ wait_pid == pdf_pid ? "pdftops" : "pstops");
+#else
+ wait_pid == pdf_pid ? "gs" : "pstops");
+#endif /* HAVE_PDFTOPS */
+ }
+ }
+
+ /*
+ * Cleanup and exit...
+ */
+
+ error:
+
+ if (tempfile[0])
+ unlink(tempfile);
+
+ return (exit_status);
+}
+
+
+/*
+ * 'cancel_job()' - Flag the job as canceled.
+ */
+
+static void
+cancel_job(int sig) /* I - Signal number (unused) */
+{
+ (void)sig;
+
+ job_canceled = 1;
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/postscript-driver.header b/filter/postscript-driver.header
new file mode 100644
index 000000000..a0fedcf64
--- /dev/null
+++ b/filter/postscript-driver.header
@@ -0,0 +1,32 @@
+<!--
+ "$Id: postscript-driver.header 9344 2010-10-26 23:45:18Z mike $"
+
+ PostScript printer driver documentation for CUPS.
+
+ Copyright 2007-2010 by Apple Inc.
+ Copyright 1997-2007 by Easy Software Products.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Developing PostScript Printer Drivers</h1>
+
+<p>This document describes how to develop printer drivers for PostScript printers. Topics include: <a href='#BASICS'>printer driver basics</a>, <a href='#CREATE'>creating new PPD files</a>, <a href='#IMPORT'>importing existing PPD files</a>, <a href='#FILTERS'>using custom filters</a>, <a href='#COLOR'>implementing color management</a>, and <a href='#MACOSX'>adding Mac OS X features</a>.</p>
+
+<div class='summary'><table summary='General Information'>
+<tbody>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='raster-driver.html'>Developing Raster Printer Drivers</a><br>
+ Programming: <a href='api-filter.html'>Filter and Backend Programming</a><br>
+ Programming: <a href='ppd-compiler.html'>Introduction to the PPD Compiler</a><br>
+ Programming: <a href='api-raster.html'>Raster API</a><br>
+ References: <a href='ref-ppdcfile.html'>PPD Compiler Driver Information File Reference</a><br>
+ Specifications: <a href='spec-ppd.html'>CUPS PPD Extensions</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/filter/postscript-driver.shtml b/filter/postscript-driver.shtml
new file mode 100644
index 000000000..439744f0f
--- /dev/null
+++ b/filter/postscript-driver.shtml
@@ -0,0 +1,276 @@
+<h2 class='title'><a name='BASICS'>Printer Driver Basics</a></h2>
+
+<p>A CUPS PostScript printer driver consists of a PostScript Printer Description (PPD) file that describes the features and capabilities of the device, zero or more <em>filter</em> programs that prepare print data for the device, and zero or more support files for color management, online help, and so forth. The PPD file includes references to all of the filters and support files used by the driver.</p>
+
+<p>Every time a user prints something the scheduler program, <a href='man-cupsd.html'>cupsd(8)</a>, determines the format of the print job and the programs required to convert that job into something the printer understands. CUPS includes filter programs for many common formats, for example to convert Portable Document Format (PDF) files into device-independent PostScript, and then from device-independent PostScript to device-dependent PostScript. <a href='#FIGURE_1'>Figure 1</a> shows the data flow of a typical print job.</p>
+
+<div class='figure'><table summary='PostScript Filter Chain'>
+<caption>Figure 1: <a name='FIGURE_1'>PostScript Filter Chain</a></caption>
+<tr><td><img src='../images/cups-postscript-chain.png' width='700' height='150' alt='PostScript Filter Chain'></td></tr>
+</table></div>
+
+<p>The optional PostScript filter can be provided to add printer-specific commands to the PostScript output that cannot be represented in the PPD file or to reorganize the output for special printer features. Typically this is used to support advanced job management or finishing functions on the printer. CUPS includes a generic PostScript filter that handles all PPD-defined commands.</p>
+
+<p>The optional port monitor handles interface-specific protocol or encoding issues. For example, many PostScript printers support the Binary Communications Protocol (BCP) and Tagged Binary Communications Protocol (TBCP) to allow applications to print 8-bit ("binary") PostScript jobs. CUPS includes port monitors for BCP and TBCP, and you can supply your own port monitors as needed.</p>
+
+<p>The backend handles communications with the printer, sending print data from the last filter to the printer and relaying back-channel data from the printer to the upstream filters. CUPS includes backend programs for common direct-connect interfaces and network protocols, and you can provide your own backend to support custom interfaces and protocols.</p>
+
+<p>The scheduler also supports a special "command" file format for sending maintenance commands and status queries to a printer or printer driver. Command print jobs typically use a single command filter program defined in the PPD file to generate the appropriate printer commands and handle any responses from the printer. <a href='#FIGURE_2'>Figure 2</a> shows the data flow of a typical command job.</p>
+
+<div class='figure'><table summary='Command Filter Chain'>
+<caption>Figure 2: <a name='FIGURE_2'>Command Filter Chain</a></caption>
+<tr><td><img src='../images/cups-command-chain.png' width='575' height='150' alt='Command Filter Chain'></td></tr>
+</table></div>
+
+<p>PostScript printer drivers typically do not require their own command filter since CUPS includes a generic PostScript command filter that supports all of the standard functions using PPD-defined commands.</p>
+
+
+<h2 class='title'><a name='CREATING'>Creating New PPD Files</a></h2>
+
+<p>We recommend using the CUPS PPD compiler, <a href='man-ppdc.html'>ppdc(1)</a>, to create new PPD files since it manages many of the tedious (and error-prone!) details of paper sizes and localization for you. It also allows you to easily support multiple devices from a single source file. For more information see the "<a href='ppd-compiler.html'>Introduction to the PPD Compiler</a>" document. <a href='#LISTING_1'>Listing 1</a> shows a driver information file for a black-and-white PostScript printer.</p>
+
+<p class='example'>Listing 1: <a name='LISTING_1'>"examples/postscript.drv"</a></p>
+
+<pre class='example'>
+// Include standard font and media definitions
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+
+// Specify this is a PostScript printer driver
+<a href='ref-ppdcfile.html#DriverType'>DriverType</a> ps
+
+// List the fonts that are supported, in this case all standard fonts
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+
+// Manufacturer, model name, and version
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "Foo"
+<a href='ref-ppdcfile.html#ModelName'>ModelName</a> "Foo LaserProofer 2000"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+
+// PostScript printer attributes
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> DefaultColorSpace "" Gray
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> LandscapeOrientation "" Minus90
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> LanguageLevel "" "3"
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> Product "" "(Foo LaserProofer 2000)"
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> PSVersion "" "(3010) 0"
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> TTRasterizer "" Type42
+
+// Supported page sizes
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Legal
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+
+// Query command for page size
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> "?PageSize" "" "
+ save
+ currentpagedevice /PageSize get aload pop
+ 2 copy gt {exch} if (Unknown)
+ 23 dict
+ dup [612 792] (Letter) put
+ dup [612 1008] (Legal) put
+ dup [595 842] (A4) put
+ {exch aload pop 4 index sub abs 5 le exch
+ 5 index sub abs 5 le and
+ {exch pop exit} {pop} ifelse
+ } bind forall = flush pop pop
+ restore"
+
+// Specify the name of the PPD file we want to generate
+<a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "fooproof.ppd"
+</pre>
+
+<h3>Required Attributes</h3>
+
+<p>PostScript drivers require the attributes listed in <a href='#TABLE_1'>Table 1</a>. If not specified, the defaults for CUPS drivers are used. A typical PostScript driver information file would include the following attributes:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> DefaultColorSpace "" Gray
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> LandscapeOrientation "" Minus90
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> LanguageLevel "" "3"
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> Product "" "(Foo LaserProofer 2000)"
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> PSVersion "" "(3010) 0"
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> TTRasterizer "" Type42
+</pre>
+
+<div class='table'><table summary='Required PostScript Printer Driver Attributes'>
+<caption>Table 1: <a name='TABLE_1'>Required PostScript Printer Driver Attributes</a></caption>
+<thead>
+<tr>
+ <th>Attribute</th>
+ <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td><tt>DefaultColorSpace</tt></td>
+ <td>The default colorspace:
+ <tt>Gray</tt>, <tt>RGB</tt>, <tt>CMY</tt>, or
+ <tt>CMYK</tt>. If not specified, then <tt>RGB</tt> is
+ assumed.</td>
+</tr>
+<tr>
+ <td><tt>LandscapeOrientation</tt></td>
+ <td>The preferred landscape
+ orientation: <tt>Plus90</tt>, <tt>Minus90</tt>, or
+ <tt>Any</tt>. If not specified, <tt>Plus90</tt> is
+ assumed.</td>
+</tr>
+<tr>
+ <td><tt>LanguageLevel</tt></td>
+ <td>The PostScript language
+ level supported by the device: 1, 2, or 3. If not
+ specified, 2 is assumed.</td>
+</tr>
+<tr>
+ <td><tt>Product</tt></td>
+ <td>The string returned by
+ the PostScript <tt>product</tt> operator, which
+ <i>must</i> include parenthesis to conform with
+ PostScript syntax rules for strings. Multiple
+ <tt>Product</tt> attributes may be specified to support
+ multiple products with the same PPD file. If not
+ specified, "(ESP Ghostscript)" and "(GNU Ghostscript)"
+ are assumed.</td>
+</tr>
+<tr>
+ <td><tt>PSVersion</tt></td>
+ <td>The PostScript
+ interpreter version numbers as returned by the
+ <tt>version</tt> and <tt>revision</tt> operators. The
+ required format is "(version) revision". Multiple
+ <tt>PSVersion</tt> attributes may be specified to
+ support multiple interpreter version numbers. If not
+ specified, "(3010) 705" and "(3010) 707" are
+ assumed.</td>
+</tr>
+<tr>
+ <td><tt>TTRasterizer</tt></td>
+ <td>The type of TrueType
+ font rasterizer supported by the device, if any. The
+ supported values are <tt>None</tt>, <tt>Accept68k</tt>,
+ <tt>Type42</tt>, and <tt>TrueImage</tt>. If not
+ specified, <tt>None</tt> is assumed.</td>
+</tr>
+</table></div>
+
+<h3>Query Commands</h3>
+
+<p>Most PostScript printer PPD files include query commands (<tt>?PageSize</tt>, etc.) that allow applications to query the printer for its current settings and configuration. Query commands are included in driver information files as attributes. For example, the example in <a href='#LISTING_1'>Listing 1</a> uses the following definition for the <tt>PageSize</tt> query command:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> "?PageSize" "" "
+ save
+ currentpagedevice /PageSize get aload pop
+ 2 copy gt {exch} if (Unknown)
+ 23 dict
+ dup [612 792] (Letter) put
+ dup [612 1008] (Legal) put
+ dup [595 842] (A4) put
+ {exch aload pop 4 index sub abs 5 le exch
+ 5 index sub abs 5 le and
+ {exch pop exit} {pop} ifelse
+ } bind forall = flush pop pop
+ restore"
+</pre>
+
+<p>Query commands can span multiple lines, however no single line may contain more than 255 characters.</p>
+
+<h3><a name='IMPORT'>Importing Existing PPD Files</a></h3>
+
+<P>CUPS includes a utility called <a href='man-ppdi.html'>ppdi(1)</a>
+which allows you to import existing PPD files into the driver information file
+format used by the PPD compiler <a href='man-ppdc.html'>ppdc(1)</a>. Once
+imported, you can modify, localize, and regenerate the PPD files easily. Type
+the following command to import the PPD file <VAR>mydevice.ppd</VAR> into the
+driver information file <VAR>mydevice.drv</VAR>:</P>
+
+<pre class='command'>
+ppdi -o mydevice.drv mydevice.ppd
+</pre>
+
+<P>If you have a whole directory of PPD files that you would like to import,
+you can list multiple filenames or use shell wildcards to import more than one
+PPD file on the command-line:</P>
+
+<pre class='command'>
+ppdi -o mydevice.drv mydevice1.ppd mydevice2.ppd
+ppdi -o mydevice.drv *.ppd
+</pre>
+
+<P>If the driver information file already exists, the new PPD
+file entries are appended to the end of the file. Each PPD file
+is placed in its own group of curly braces within the driver
+information file.</P>
+
+
+<h2 class='title'><a name='FILTERS'>Using Custom Filters</a></h2>
+
+<p>Normally a PostScript printer driver will not utilize any additional print filters. For drivers that provide additional filters such as a CUPS command file filter for doing printer maintenance, you must also list the following <tt>Filter</tt> directive to handle printing PostScript files:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-postscript 0 -
+</pre>
+
+<h3>Custom Command Filters</h3>
+
+<p>The <tt>application/vnd.cups-command</tt> file type is used for CUPS command files. Use the following <tt>Filter</tt> directive to handle CUPS command files:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-command 100 /path/to/command/filter
+</pre>
+
+<p>To use the standard PostScript command filter, specify <var>commandtops</var> as the path to the command filter.</p>
+
+<h3>Custom PDF Filters</h3>
+
+<p>The <tt>application/pdf</tt> file type is used for unfiltered PDF files while the <tt>application/vnd.cups-pdf</tt> file type is used for filtered PDF files. Use the following <tt>Filter</tt> directive to handle filtered PDF files:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-pdf 100 /path/to/pdf/filter
+</pre>
+
+<p>For unfiltered PDF files, use:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/pdf 100 /path/to/pdf/filter
+</pre>
+
+<p>Custom PDF filters that accept filtered data do not need to perform number-up processing and other types of page imposition, while those that accept unfiltered data MUST do the number-up processing themselves.</p>
+
+<h3>Custom PostScript Filters</h3>
+
+<p>The <tt>application/vnd.cups-postscript</tt> file type is used for filtered PostScript files. Use the following <tt>Filter</tt> directive to handle PostScript files:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-postscript 100 /path/to/postscript/filter
+</pre>
+
+
+<h2 class='title'><a name='COLOR'>Implementing Color Management</a></h2>
+
+<p>CUPS uses ICC color profiles to provide more accurate color reproduction. The <a href='spec-ppd.html#cupsICCProfile'><tt>cupsICCProfile</tt></a> attribute defines the color profiles that are available for a given printer, for example:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsICCProfile "ColorModel.MediaType.Resolution/Description" /path/to/ICC/profile
+</pre>
+
+<p>where "ColorModel.MediaType.Resolution" defines a selector based on the corresponding option selections. A simple driver might only define profiles for the color models that are supported, for example a printer supporting Gray and RGB might use:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsICCProfile "Gray../Grayscale Profile" /path/to/ICC/gray-profile
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsICCProfile "RGB../Full Color Profile" /path/to/ICC/rgb-profile
+</pre>
+
+<p>The options used for profile selection can be customized using the <tt>cupsICCQualifier2</tt> and <tt>cupsICCQualifier3</tt> attributes.</p>
+
+
+<h2 class='title'><a name='MACOSX'>Adding Mac OS X Features</a></h2>
+
+<p>Mac OS X printer drivers can provide <a href='spec-ppd.html#MACOSX'>additional attributes</a> to specify additional option panes in the print dialog, an image of the printer, a help book, and option presets for the driver software:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APDialogExtension "" /Library/Printers/Vendor/filename.plugin
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APHelpBook "" /Library/Printers/Vendor/filename.bundle
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APPrinterIconPath "" /Library/Printers/Vendor/filename.icns
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APPrinterPreset "name/text" "*option choice ..."
+</pre>
diff --git a/filter/ppd-compiler.header b/filter/ppd-compiler.header
new file mode 100644
index 000000000..5a36477f9
--- /dev/null
+++ b/filter/ppd-compiler.header
@@ -0,0 +1,34 @@
+<!--
+ "$Id: ppd-compiler.header 9344 2010-10-26 23:45:18Z mike $"
+
+ PPD compiler documentation for CUPS.
+
+ Copyright 2007-2010 by Apple Inc.
+ Copyright 1997-2007 by Easy Software Products.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Introduction to the PPD Compiler</h1>
+
+<P>This document describes how to use the CUPS PostScript Printer Description
+(PPD) file compiler. The PPD compiler generates PPD files from simple text files
+that describe the features and capabilities of one or more printers.</P>
+
+<div class='summary'><table summary='General Information'>
+<tbody>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='raster-driver.html'>Developing Raster Printer Drivers</a><br>
+ Programming: <a href='postscript-driver.html'>Developing PostScript Printer Drivers</a><br>
+ Programming: <a href='api-filter.html'>Filter and Backend Programming</a><br>
+ Programming: <a href='api-raster.html'>Raster API</a><br>
+ References: <a href='ref-ppdcfile.html'>PPD Compiler Driver Information File Reference</a><br>
+ Specifications: <a href='spec-ppd.html'>CUPS PPD Extensions</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/filter/ppd-compiler.shtml b/filter/ppd-compiler.shtml
new file mode 100644
index 000000000..c98b95cee
--- /dev/null
+++ b/filter/ppd-compiler.shtml
@@ -0,0 +1,883 @@
+<h2 class='title'><a name='BASICS'>The Basics</a></h2>
+
+<P>The PPD compiler, <a href='man-ppdc.html'><code>ppdc(1)</code></a>, is a
+simple command-line tool that takes a single <I>driver information file</I>,
+which by convention uses the extension <VAR>.drv</VAR>, and produces one or more
+PPD files that may be distributed with your printer drivers for use with CUPS.
+For example, you would run the following command to create the English language
+PPD files defined by the driver information file <VAR>mydrivers.drv</VAR>:</P>
+
+<pre class='command'>
+ppdc mydrivers.drv
+</pre>
+
+<P>The PPD files are placed in a subdirectory called
+<VAR>ppd</VAR>. The <TT>-d</TT> option is used to put the PPD
+files in a different location, for example:</p>
+
+<pre class='command'>
+ppdc -d myppds mydrivers.drv
+</pre>
+
+<P>places the PPD files in a subdirectory named
+<VAR>myppds</VAR>. Finally, use the <TT>-l</TT> option to
+specify the language localization for the PPD files that are
+created, for example:</P>
+
+<pre class='command'>
+ppdc -d myppds/de -l de mydrivers.drv
+ppdc -d myppds/en -l en mydrivers.drv
+ppdc -d myppds/es -l es mydrivers.drv
+ppdc -d myppds/fr -l fr mydrivers.drv
+ppdc -d myppds/it -l it mydrivers.drv
+</pre>
+
+<P>creates PPD files in German (de), English (en), Spanish (es),
+French (fr), and Italian (it) in the corresponding
+subdirectories. Specify multiple languages (separated by commas) to produce
+"globalized" PPD files:</p>
+
+<pre class='command'>
+ppdc -d myppds -l de,en,es,fr,it mydrivers.drv
+</pre>
+
+
+<h2 class='title'><a name='DRV'>Driver Information Files</a></h2>
+
+<P>The driver information files accepted by the PPD compiler are
+plain text files that define the various attributes and options
+that are included in the PPD files that are generated. A driver
+information file can define the information for one or more printers and
+their corresponding PPD files.</P>
+
+<p class='example'><a name="LISTING1">Listing 1: "examples/minimum.drv"</a></p>
+
+<pre class='example'>
+<I>// Include standard font and media definitions</I>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+
+<I>// List the fonts that are supported, in this case all standard fonts...</I>
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+
+<I>// Manufacturer, model name, and version</I>
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "Foo"
+<a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+
+<I>// Each filter provided by the driver...</I>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-raster 100 rastertofoo
+
+<I>// Supported page sizes</I>
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+
+<I>// Supported resolutions</I>
+*<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "600dpi/600 DPI"
+
+<I>// Specify the name of the PPD file we want to generate...</I>
+<a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojet2k.ppd"
+</pre>
+
+
+<h3><a name='SIMPLE'>A Simple Example</a></h3>
+
+<P>The example in <A HREF="#LISTING1">Listing 1</A> shows a driver information
+file which defines the minimum required attributes to provide a valid PPD file.
+The first part of the file includes standard definition files for fonts and
+media sizes:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+</pre>
+
+<P>The <TT>#include</TT> directive works just like the C/C++ include directive;
+files included using the angle brackets (<TT>&lt;filename&gt;</TT>) are found
+in any of the standard include directories and files included using quotes
+(<TT>"filename"</TT>) are found in the same directory as the source or include
+file. The <TT>&lt;font.defs&gt;</TT> include file defines the standard fonts
+which are included with GPL Ghostscript and the Apple PDF RIP, while the
+<TT>&lt;media.defs&gt;</TT> include file defines the standard media sizes
+listed in Appendix B of the Adobe PostScript Printer Description File Format
+Specification.</P>
+
+<P>CUPS provides several other standard include files:</P>
+
+<UL>
+
+ <LI><TT>&lt;epson.h&gt;</TT> - Defines all of the rastertoepson driver
+ constants.</LI>
+
+ <LI><TT>&lt;escp.h&gt;</TT> - Defines all of the rastertoescpx driver
+ constants.</LI>
+
+ <LI><TT>&lt;hp.h&gt;</TT> - Defines all of the rastertohp driver
+ constants.</LI>
+
+ <LI><TT>&lt;label.h&gt;</TT> - Defines all of the rastertolabel driver
+ constants.</LI>
+
+ <LI><TT>&lt;pcl.h&gt;</TT> - Defines all of the rastertopclx driver
+ constants.</LI>
+
+ <LI><TT>&lt;raster.defs&gt;</TT> - Defines all of the CUPS raster format
+ constants.</LI>
+
+</UL>
+
+<P>Next we list all of the fonts that are available in the driver; for CUPS
+raster drivers, the following line is all that is usually supplied:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+</pre>
+
+<P>The <TT>Font</TT> directive specifies the name of a single font or the
+asterisk to specify all fonts. For example, you would use the following line to
+define an additional bar code font that you are supplying with your printer
+driver:</P>
+
+<pre class='example'>
+<I>// name encoding version charset status</I>
+<a href='ref-ppdcfile.html#Font'>Font</a> Barcode-Foo Special "(1.0)" Special ROM
+</pre>
+
+<P>The name of the font is <TT>Barcode-Foo</TT>. Since it is not a standard
+text font, the encoding and charset name <TT>Special</TT> is used. The version
+number is <TT>1.0</TT> and the status (where the font is located) is
+<TT>ROM</TT> to indicate that the font does not need to be embedded in
+documents that use the font for this printer.</P>
+
+<P>Third comes the manufacturer, model name, and version number information
+strings:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "Foo"
+<a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+</pre>
+
+<P>These strings are used when the user (or auto-configuration program) selects
+the printer driver for a newly connected device.</p>
+
+<P>The list of filters comes after the information strings; for the example in
+<A HREF="#LISTING1">Listing 1</A>, we have a single filter that takes CUPS
+raster data:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-raster 100 rastertofoo
+</pre>
+
+<P>Each filter specified in the driver information file is the equivalent of a
+printer driver for that format; if a user submits a print job in a different
+format, CUPS figures out the sequence of commands that will produce a supported
+format for the least relative cost.</P>
+
+<P>Once we have defined the driver information we specify the supported options.
+For the example driver we support a single resolution of 600 dots per inch and
+two media sizes, A4 and Letter:</P>
+
+<pre class='example'>
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+
+*<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "600dpi/600 DPI"
+</pre>
+
+<P>The asterisk in front of the <TT>MediaSize</TT> and <TT>Resolution</TT>
+directives specify that those option choices are the default. The
+<TT>MediaSize</TT> directive is followed by a media size name which is normally
+defined in the <TT>&lt;media.defs&gt;</TT> file and corresponds to a standard
+Adobe media size name. If the default media size is <TT>Letter</TT>, the PPD
+compiler will override it to be <TT>A4</TT> for non-English localizations for
+you automatically.</P>
+
+<P>The <TT>Resolution</TT> directive accepts several values after it as
+follows:</P>
+
+<OL>
+
+ <LI>Colorspace for this resolution, if any. In the example file, the
+ colorspace <TT>k</TT> is used which corresponds to black. For printer
+ drivers that support color printing, this field is usually specified as
+ "-" for "no change".</LI>
+
+ <LI>Bits per color. In the example file, we define 8 bits per color, for
+ a continuous-tone grayscale output. All versions of CUPS support 1 and
+ 8 bits per color. CUPS 1.2 and higher (Mac OS X 10.5 and higher) also
+ supports 16 bits per color.</LI>
+
+ <LI>Rows per band. In the example file, we define 0 rows per band to
+ indicate that our printer driver does not process the page in
+ bands.</LI>
+
+ <LI>Row feed. In the example, we define the feed value to be 0 to
+ indicate that our printer driver does not interleave the output.</LI>
+
+ <LI>Row step. In the example, we define the step value to be 0 to
+ indicate that our printer driver does not interleave the output. This
+ value normally indicates the spacing between the nozzles of an inkjet
+ printer - when combined with the previous two values, it informs the
+ driver how to stagger the output on the page to produce interleaved
+ lines on the page for higher-resolution output.</LI>
+
+ <LI>Choice name and text. In the example, we define the choice name and
+ text to be <TT>"600dpi/600 DPI"</TT>. The name and text are separated by
+ slash (<TT>/</TT>) character; if no text is specified, then the name is
+ used as the text. The PPD compiler parses the name to determine the
+ actual resolution; the name can be of the form
+ <TT><I>RESOLUTION</I>dpi</TT> for resolutions that are equal
+ horizontally and vertically or <TT><I>HRES</I>x<I>VRES</I>dpi</TT> for
+ isometric resolutions. Only integer resolution values are supported, so
+ a resolution name of <TT>300dpi</TT> is valid while <TT>300.1dpi</TT> is
+ not.</LI>
+
+</OL>
+
+<P>Finally, the <TT>PCFileName</TT> directive specifies that the named PPD file
+should be written for the current driver definitions:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojet2k.ppd"
+</pre>
+
+<P>The filename follows the directive and <I>must</I> conform to the Adobe
+filename requirements in the Adobe Postscript Printer Description File Format
+Specification. Specifically, the filename may not exceed 8 characters followed
+by the extension <VAR>.ppd</VAR>. The <TT>FileName</TT> directive can be used to
+specify longer filenames:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#FileName'>FileName</a> "FooJet 2000"
+</pre>
+
+
+<h3><a name='GROUPING'>Grouping and Inheritance</a></h3>
+
+<P>The previous example created a single PPD file. Driver information files can
+also define multiple printers by using the PPD compiler grouping functionality.
+Directives are grouped using the curly braces (<TT>{</TT> and <TT>}</TT>) and
+every group that uses the <TT>PCFileName</TT> or <TT>FileName</TT> directives
+produces a PPD file with that name. <A HREF="#LISTING2">Listing 2</A> shows a
+variation of the original example that uses two groups to define two printers
+that share the same printer driver filter but provide two different resolution
+options.</P>
+
+<p class='example'><a name="LISTING2">Listing 2: "examples/grouping.drv"</a></p>
+
+<pre class='example'>
+
+<I>// Include standard font and media definitions</I>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+
+<I>// List the fonts that are supported, in this case all standard fonts...</I>
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+
+<I>// Manufacturer and version</I>
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "Foo"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+
+<I>// Each filter provided by the driver...</I>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-raster 100 rastertofoo
+
+<I>// Supported page sizes</I>
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+
+{
+ <I>// Supported resolutions</I>
+ *<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "600dpi/600 DPI"
+
+ <I>// Specify the model name and filename...</I>
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojet2k.ppd"
+}
+
+{
+ <I>// Supported resolutions</I>
+ *<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "1200dpi/1200 DPI"
+
+ <I>// Specify the model name and filename...</I>
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2001"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojt2k1.ppd"
+}
+</pre>
+
+<P>The second example is essentially the same as the first, except that each
+printer model is defined inside of a pair of curly braces. For example, the
+first printer is defined using:</P>
+
+<pre class='example'>
+{
+ // Supported resolutions
+ *<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "600dpi/600 DPI"
+
+ // Specify the model name and filename...
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojet2k.ppd"
+}
+</pre>
+
+<P>The printer <I>inherits</I> all of the definitions from the parent group (the
+top part of the file) and adds the additional definitions inside the curly
+braces for that printer driver. When we define the second group, it also
+inherits the same definitions from the parent group but <I>none</I> of the
+definitions from the first driver. Groups can be nested to any number of levels
+to support variations of similar models without duplication of information.</P>
+
+
+<h3><a name='COLOR'>Color Support</a></h3>
+
+<P>For printer drivers that support color printing, the
+<TT>ColorDevice</TT> and <TT>ColorModel</TT> directives should be
+used to tell the printing system that color output is desired
+and in what formats. <A HREF="#LISTING3">Listing 3</A> shows a
+variation of the previous example which includes a color printer
+that supports printing at 300 and 600 DPI.</P>
+
+<P>The key changes are the addition of the <TT>ColorDevice</TT>
+directive:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#ColorDevice'>ColorDevice</a> true
+</pre>
+
+<P>which tells the printing system that the printer supports
+color printing, and the <TT>ColorModel</TT> directives:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#ColorModel'>ColorModel</a> Gray/Grayscale w chunky 0
+*<a href='ref-ppdcfile.html#ColorModel'>ColorModel</a> RGB/Color rgb chunky 0
+</pre>
+
+<P>which tell the printing system which colorspaces are supported by the printer
+driver for color printing. Each of the <TT>ColorModel</TT> directives is
+followed by the option name and text (<TT>Gray/Grayscale</TT> and
+<TT>RGB/Color</TT>), the colorspace name (<TT>w</TT> and <TT>rgb</TT>), the
+color organization (<TT>chunky</TT>), and the compression mode number
+(<TT>0</TT>) to be passed to the driver. The option name can be any of the
+standard Adobe <TT>ColorModel</TT> names:</P>
+
+<UL>
+
+ <LI><TT>Gray</TT> - Grayscale output.
+
+ <LI><TT>RGB</TT> - Color output, typically using the RGB
+ colorspace, but without a separate black channel.
+
+ <LI><TT>CMYK</TT> - Color output with a separate black
+ channel.
+
+</UL>
+
+<P>Custom names can be used, however it is recommended that you use your vendor
+prefix for any custom names, for example "fooName".</P>
+
+<P>The colorspace name can be any of the following universally supported
+colorspaces:</P>
+
+<UL>
+ <LI><TT>w</TT> - Luminance</LI>
+
+ <LI><TT>rgb</TT> - Red, green, blue</LI>
+
+ <LI><TT>k</TT> - Black</LI>
+
+ <LI><TT>cmy</TT> - Cyan, magenta, yellow</LI>
+
+ <LI><TT>cmyk</TT> - Cyan, magenta, yellow, black</LI>
+
+</UL>
+
+<P>The color organization can be any of the following values:</P>
+
+<UL>
+
+ <LI><TT>chunky</TT> - Color values are passed together on a line
+ as RGB RGB RGB RGB</LI>
+
+ <LI><TT>banded</TT> - Color values are passed separately
+ on a line as RRRR GGGG BBBB; not supported by the Apple
+ RIP filters</LI>
+
+ <LI><TT>planar</TT> - Color values are passed separately
+ on a page as RRRR RRRR RRRR ... GGGG GGGG GGGG ... BBBB
+ BBBB BBBB; not supported by the Apple RIP filters</LI>
+
+</UL>
+
+<P>The compression mode value is passed to the driver in the
+<TT>cupsCompression</TT> attribute. It is traditionally used to select an
+appropriate compression mode for the color model but can be used for any
+purpose, such as specifying a photo mode vs. standard mode.</P>
+
+<p class='example'><a name="LISTING3">Listing 3: "examples/color.drv"</a></p>
+
+<pre class='example'>
+
+<I>// Include standard font and media definitions</I>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+
+<I>// List the fonts that are supported, in this case all standard fonts...</I>
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+
+<I>// Manufacturer and version</I>
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "Foo"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+
+<I>// Each filter provided by the driver...</I>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-raster 100 rastertofoo
+
+<I>// Supported page sizes</I>
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+
+{
+ <I>// Supported resolutions</I>
+ *<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "600dpi/600 DPI"
+
+ <I>// Specify the model name and filename...</I>
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojet2k.ppd"
+}
+
+{
+ <I>// Supports color printing</I>
+ <a href='ref-ppdcfile.html#ColorDevice'>ColorDevice</a> true
+
+ <I>// Supported colorspaces</I>
+ <a href='ref-ppdcfile.html#ColorModel'>ColorModel</a> Gray/Grayscale w chunky 0
+ *<a href='ref-ppdcfile.html#ColorModel'>ColorModel</a> RGB/Color rgb chunky 0
+
+ <I>// Supported resolutions</I>
+ *<a href='ref-ppdcfile.html#Resolution'>Resolution</a> - 8 0 0 0 "300dpi/300 DPI"
+ <a href='ref-ppdcfile.html#Resolution'>Resolution</a> - 8 0 0 0 "600dpi/600 DPI"
+
+ <I>// Specify the model name and filename...</I>
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet Color"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojetco.ppd"
+}
+</pre>
+
+
+<h3><a name='OPTIONS'>Defining Custom Options and Option Groups</a></h3>
+
+<P>The <TT>Group</TT>, <TT>Option</TT>, and <TT>Choice</TT>
+directives are used to define or select a group, option, or
+choice. <A HREF="#LISTING4">Listing 4</A> shows a variation of
+the first example that provides two custom options in a group
+named "Footasm".</P>
+
+<p class='example'><a name="LISTING4">Listing 4: "examples/custom.drv"</a></p>
+
+<pre class='example'>
+
+<I>// Include standard font and media definitions</I>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+
+<I>// List the fonts that are supported, in this case all standard fonts...</I>
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+
+<I>// Manufacturer, model name, and version</I>
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "Foo"
+<a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+
+<I>// Each filter provided by the driver...</I>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-raster 100 rastertofoo
+
+<I>// Supported page sizes</I>
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+
+<I>// Supported resolutions</I>
+*<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "600dpi/600 DPI"
+
+<I>// Option Group</I>
+<a href='ref-ppdcfile.html#Group'>Group</a> "Footasm"
+
+ <I>// Boolean option</I>
+ <a href='ref-ppdcfile.html#Option'>Option</a> "fooEnhance/Resolution Enhancement" Boolean AnySetup 10
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> True/Yes "&lt;&lt;/cupsCompression 1&gt;&gt;setpagedevice"
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> False/No "&lt;&lt;/cupsCompression 0&gt;&gt;setpagedevice"
+
+ <I>// Multiple choice option</I>
+ <a href='ref-ppdcfile.html#Option'>Option</a> "fooOutputType/Output Quality" PickOne AnySetup 10
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> "Auto/Automatic Selection"
+ "&lt;&lt;/OutputType(Auto)&gt;&gt;setpagedevice""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "Text/Optimize for Text"
+ "&lt;&lt;/OutputType(Text)&gt;&gt;setpagedevice""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "Graph/Optimize for Graphics"
+ "&lt;&lt;/OutputType(Graph)&gt;&gt;setpagedevice""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "Photo/Optimize for Photos"
+ "&lt;&lt;/OutputType(Photo)&gt;&gt;setpagedevice""
+
+<I>// Specify the name of the PPD file we want to generate...</I>
+<a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojet2k.ppd"
+</pre>
+
+<P>The custom group is introduced by the <TT>Group</TT>
+directive which is followed by the name and optionally text for
+the user:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Group'>Group</a> "Footasm/Footastic Options"
+</pre>
+
+<P>The group name must conform to the PPD specification and
+cannot exceed 40 characters in length. If you specify user text,
+it cannot exceed 80 characters in length. The groups
+<TT>General</TT>, <TT>Extra</TT>, and
+<TT>InstallableOptions</TT> are predefined by CUPS; the general
+and extra groups are filled by the UI options defined by the PPD
+specification. The <TT>InstallableOptions</TT> group is reserved
+for options that define whether accessories for the printer
+(duplexer unit, finisher, stapler, etc.) are installed.</P>
+
+<P>Once the group is specified, the <TT>Option</TT> directive is
+used to introduce a new option:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Option'>Option</a> "fooEnhance/Resolution Enhancement" Boolean AnySetup 10
+</pre>
+
+<P>The directive is followed by the name of the option and any
+optional user text, the option type, the PostScript document group, and
+the sort order number. The option name must conform to the PPD specification
+and cannot exceed 40 characters in length. If you specify user text, it
+cannot exceed 80 characters in length.</P>
+
+<P>The option type can be <TT>Boolean</TT> for true/false
+selections, <TT>PickOne</TT> for picking one of many choices, or
+<TT>PickMany</TT> for picking zero or more choices. Boolean
+options can have at most two choices with the names
+<TT>False</TT> and <TT>True</TT>. Pick options can have any
+number of choices, although for Windows compatibility reasons
+the number of choices should not exceed 255.</P>
+
+<P>The PostScript document group is typically <TT>AnySetup</TT>,
+meaning that the option can be introduced at any point in the
+PostScript document. Other values include <TT>PageSetup</TT> to
+include the option before each page and <TT>DocumentSetup</TT>
+to include the option once at the beginning of the document.</P>
+
+<P>The sort order number is used to sort the printer commands
+associated with each option choice within the PostScript
+document. This allows you to setup certain options before others
+as required by the printer. For most CUPS raster printer
+drivers, the value <TT>10</TT> can be used for all options.</P>
+
+<P>Once the option is specified, each option choice can be
+listed using the <TT>Choice</TT> directive:</P>
+
+<pre class='example'>
+*<a href='ref-ppdcfile.html#Choice'>Choice</a> True/Yes "&lt;&lt;/cupsCompression 1&gt;&gt;setpagedevice"
+<a href='ref-ppdcfile.html#Choice'>Choice</a> False/No "&lt;&lt;/cupsCompression 0&gt;&gt;setpagedevice"
+</pre>
+
+<P>The directive is followed by the choice name and optionally
+user text, and the PostScript commands that should be inserted
+when printing a file to this printer. The option name must
+conform to the PPD specification and cannot exceed 40 characters
+in length. If you specify user text, it cannot exceed 80
+characters in length.</P>
+
+<P>The PostScript commands are also interpreted by any RIP
+filters, so these commands typically must be present for all
+option choices. Most commands take the form:</P>
+
+<pre class='example'>
+&lt;&lt;/name value&gt;&gt;setpagedevice
+</pre>
+
+<P>where <TT>name</TT> is the name of the PostScript page device
+attribute and <TT>value</TT> is the numeric or string value for
+that attribute.</P>
+
+
+<h3><a name='DEFINE'>Defining Constants</a></h3>
+
+<P>Sometimes you will want to define constants for your drivers
+so that you can share values in different groups within the same
+driver information file, or to share values between different
+driver information files using the <TT>#include</TT> directive.
+The <TT>#define</TT> directive is used to define constants for
+use in your printer definitions:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#_define'>#define</a> NAME value
+</pre>
+
+<P>The <TT>NAME</TT> is any sequence of letters, numbers, and
+the underscore. The <TT>value</TT> is a number or string; if the
+value contains spaces you must put double quotes around it, for
+example:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#_define'>#define</a> FOO "My String Value"
+</pre>
+
+<P>Constants can also be defined on the command-line using the <tt>-D</tt>
+option:</P>
+
+<pre class='command'>
+ppdc -DNAME="value" filename.drv
+</pre>
+
+<P>Once defined, you use the notation <TT>$NAME</TT> to substitute the value of
+the constant in the file, for example:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#_define'>#define</a> MANUFACTURER "Foo"
+<a href='ref-ppdcfile.html#_define'>#define</a> FOO_600 0
+<a href='ref-ppdcfile.html#_define'>#define</a> FOO_1200 1
+
+{
+ <a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "$MANUFACTURER"
+ <a href='ref-ppdcfile.html#ModelNumber'>ModelNumber</a> $FOO_600
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+ ...
+}
+
+{
+ <a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "$MANUFACTURER"
+ <a href='ref-ppdcfile.html#ModelNumber'>ModelNumber</a> $FOO_1200
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2001"
+ ...
+}
+</pre>
+
+<P>Numeric constants can be bitwise OR'd together by placing the constants
+inside parenthesis, for example:</P>
+
+<pre class='example'>
+<I>// ModelNumber capability bits</I>
+<a href='ref-ppdcfile.html#_define'>#define</a> DUPLEX 1
+<a href='ref-ppdcfile.html#_define'>#define</a> COLOR 2
+
+...
+
+{
+ <I>// Define a model number specifying the capabilities of the printer...</I>
+ <a href='ref-ppdcfile.html#ModelNumber'>ModelNumber</a> ($DUPLEX $COLOR)
+ ...
+}
+</pre>
+
+
+<h3><a name='CONDITIONAL'>Conditional Statements</a></h3>
+
+<p>The PPD compiler supports conditional compilation using the <tt>#if</tt>,
+<tt>#elif</tt>, <tt>#else</tt>, and <tt>#endif</tt> directives. The <tt>#if</tt>
+and <tt>#elif</tt> directives are followed by a constant name or an expression.
+For example, to include a group of options when "ADVANCED" is defined:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#_if'>#if</a> ADVANCED
+<a href='ref-ppdcfile.html#Group'>Group</a> "Advanced/Advanced Options"
+ <a href='ref-ppdcfile.html#Option'>Option</a> "fooCyanAdjust/Cyan Adjustment"
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus10/+10%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus5/+5%" ""
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> "none/No Adjustment" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus5/-5%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus10/-10%" ""
+ <a href='ref-ppdcfile.html#Option'>Option</a> "fooMagentaAdjust/Magenta Adjustment"
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus10/+10%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus5/+5%" ""
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> "none/No Adjustment" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus5/-5%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus10/-10%" ""
+ <a href='ref-ppdcfile.html#Option'>Option</a> "fooYellowAdjust/Yellow Adjustment"
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus10/+10%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus5/+5%" ""
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> "none/No Adjustment" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus5/-5%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus10/-10%" ""
+ <a href='ref-ppdcfile.html#Option'>Option</a> "fooBlackAdjust/Black Adjustment"
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus10/+10%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "plus5/+5%" ""
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> "none/No Adjustment" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus5/-5%" ""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "minus10/-10%" ""
+<a href='ref-ppdcfile.html#_endif'>#endif</a>
+</pre>
+
+
+<h3><a name='CONSTRAINTS'>Defining Constraints</a></h3>
+
+<P>Constraints are strings that are used to specify that one or more option
+choices are incompatible, for example two-sided printing on transparency media.
+Constraints are also used to prevent the use of uninstalled features such as the
+duplexer unit, additional media trays, and so forth.</P>
+
+<P>The <TT>UIConstraints</TT> directive is used to specify a constraint that is
+placed in the PPD file. The directive is followed by a string using one of the
+following formats:</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*Option1 *Option2"
+<a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*Option1 Choice1 *Option2"
+<a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*Option1 *Option2 Choice2"
+<a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*Option1 Choice1 *Option2 Choice2"
+</pre>
+
+<P>Each option name is preceded by the asterisk (<TT>*</TT>). If no choice is
+given for an option, then all choices <I>except</I> <TT>False</TT> and
+<TT>None</TT> will conflict with the other option and choice(s). Since the PPD
+compiler automatically adds reciprocal constraints (option A conflicts with
+option B, so therefore option B conflicts with option A), you need only specify
+the constraint once.</P>
+
+<p class='example'><a name="LISTING5">Listing 5: "examples/constraint.drv"</a></p>
+
+<pre class='example'>
+
+<I>// Include standard font and media definitions</I>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+
+<I>// List the fonts that are supported, in this case all standard fonts...</I>
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+
+<I>// Manufacturer, model name, and version</I>
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "Foo"
+<a href='ref-ppdcfile.html#ModelName'>ModelName</a> "FooJet 2000"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+
+<I>// Each filter provided by the driver...</I>
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-raster 100 rastertofoo
+
+<I>// Supported page sizes</I>
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+
+<I>// Supported resolutions</I>
+*<a href='ref-ppdcfile.html#Resolution'>Resolution</a> k 8 0 0 0 "600dpi/600 DPI"
+
+<I>// Installable Option Group</I>
+<a href='ref-ppdcfile.html#Group'>Group</a> "InstallableOptions/Options Installed"
+
+ <I>// Duplexing unit option</I>
+ <a href='ref-ppdcfile.html#Option'>Option</a> "OptionDuplexer/Duplexing Unit" Boolean AnySetup 10
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> True/Installed ""
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> "False/Not Installed" ""
+
+<I>// General Option Group</I>
+<a href='ref-ppdcfile.html#Group'>Group</a> General
+
+ <I>// Duplexing option</I>
+ <a href='ref-ppdcfile.html#Option'>Option</a> "Duplex/Two-Sided Printing" PickOne AnySetup 10
+ *<a href='ref-ppdcfile.html#Choice'>Choice</a> "None/No" "&lt;&lt;/Duplex false&gt;&gt;setpagedevice""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "DuplexNoTumble/Long Edge Binding"
+ "&lt;&lt;/Duplex true/Tumble false&gt;&gt;setpagedevice""
+ <a href='ref-ppdcfile.html#Choice'>Choice</a> "DuplexTumble/Short Edge Binding"
+ "&lt;&lt;/Duplex true/Tumble true&gt;&gt;setpagedevice""
+
+<I>// Only allow duplexing if the duplexer is installed</I>
+<a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*Duplex *OptionDuplexer False"
+
+<I>// Specify the name of the PPD file we want to generate...</I>
+<a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "foojet2k.ppd"
+</pre>
+
+<P><A HREF="#LISTING5">Listing 5</A> shows a variation of the first example with
+an added <TT>Duplex</TT> option and installable option for the duplexer,
+<TT>OptionDuplex</TT>. A constraint is added at the end to specify that any
+choice of the <TT>Duplex</TT> option that is not <TT>None</TT> is incompatible
+with the "Duplexer Installed" option set to "Not Installed"
+(<TT>False</TT>):</P>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*Duplex *OptionDuplexer False"
+</pre>
+
+<h4>Enhanced Constraints</h4>
+
+<p>CUPS 1.4 supports constraints between 2 or more options using the
+<TT>Attribute</TT> directive. <TT>cupsUIConstraints</TT> attributes define
+the constraints, while <TT>cupsUIResolver</TT> attributes define option changes
+to resolve constraints. For example, we can specify the previous duplex
+constraint with a resolver that turns off duplexing with the following two
+lines:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsUIConstraints DuplexOff "*Duplex *OptionDuplexer False"
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsUIResolver DuplexOff "*Duplex None"
+</pre>
+
+<h2 class='title'><a name='LOCALIZATION'>Localization</a></h2>
+
+<p>The PPD compiler provides localization of PPD files in different languages
+through <i>message catalog</i> files in the GNU gettext or Apple .strings
+formats. Each user text string and several key PPD attribute values such as
+<tt>LanguageVersion</tt> and <tt>LanguageEncoding</tt> are looked up in the
+corresponding message catalog and the translated text is substituted in the
+generated PPD files. One message catalog file can be used by multiple driver
+information files, and each file contains a single language translation.</p>
+
+<h3><a name='PPDPO'>The ppdpo Utility</a></h3>
+
+<p>While CUPS includes localizations of all standard media sizes and options in
+several languages, your driver information files may provide their own media
+sizes and options that need to be localized. CUPS provides a utility program to
+aid in the localization of drivers called <a
+href='man-ppdpo.html'><tt>ppdpo(1)</tt></a>. The <tt>ppdpo</tt> program creates
+or updates a message catalog file based upon one or more driver information
+files. New messages are added with the word "TRANSLATE" added to the front of
+the translation string to make locating new strings for translation easier. The
+program accepts the message catalog filename and one or more driver information
+files.</p>
+
+<p>For example, run the following command to create a new German message catalog
+called <var>de.po</var> for all of the driver information files in the current
+directory:</p>
+
+<pre class='command'>
+ppdpo -o de.po *.drv
+</pre>
+
+<p>If the file <var>de.po</var> already exists, <tt>ppdpo</tt> will update the
+contents of the file with any new messages that need to be translated. To create
+an Apple .strings file instead, specify the output filename with a .strings
+extension, for example:</p>
+
+<pre class='command'>
+ppdpo -o de.strings *.drv
+</pre>
+
+<h3><a name='PPDC_CATALOG'>Using Message Catalogs with the PPD Compiler</a></h3>
+
+<p>Once you have created a message catalog, use the <a
+href='ref-ppdcfile.html#_po'><tt>#po</tt></a> directive to declare it in each
+driver information file. For example, to declare the German message catalog for
+a driver use:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#_po'>#po</a> de "de.po" // German
+</pre>
+
+<p>In fact, you can use the <tt>#po</tt> directive as many times as needed:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#_po'>#po</a> de "de.po" // German
+<a href='ref-ppdcfile.html#_po'>#po</a> es "es.po" // Spanish
+<a href='ref-ppdcfile.html#_po'>#po</a> fr "fr.po" // French
+<a href='ref-ppdcfile.html#_po'>#po</a> it "it.po" // Italian
+<a href='ref-ppdcfile.html#_po'>#po</a> ja "ja.po" // Japanese
+</pre>
+
+<p>The filename ("de.po", etc.) can be relative to the location of the driver
+information file or an absolute path. Once defined, the PPD compiler will
+automatically generate a globalized PPD for every language declared in your
+driver information file. To generate a single-language PPD file, simply use the
+<tt>-l</tt> option to list the corresponding locale, for example:</p>
+
+<pre class='command'>
+ppdc -l de -d ppd/de mydrivers.drv
+</pre>
+
+<p>to generate German PPD files.</p>
diff --git a/filter/pstext.c b/filter/pstext.c
new file mode 100644
index 000000000..cfd8f08bb
--- /dev/null
+++ b/filter/pstext.c
@@ -0,0 +1,511 @@
+/*
+ * "$Id$"
+ *
+ * Common PostScript text code for CUPS.
+ *
+ * Copyright 2008-2010 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * psTextEmbedFonts() - Embed PostScript fonts.
+ * psTextListFonts() - List PostScript fonts.
+ * psTextInitialize() - Load and embed font data for UTF-8 text.
+ * psTextUTF8() - Output UTF-8 text at the current position.
+ * psTextUTF32() - Output UTF-32 text at the current position.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "pstext.h"
+#include <cups/language-private.h>
+
+
+/*
+ * Composite font names...
+ */
+
+static const char * const ps_font_names[] =
+{
+ "cupsNormal",
+ "cupsBold",
+ "cupsItalic",
+ "cupsBoldItalic"
+};
+
+
+/*
+ * 'psTextEmbedFonts()'- Embed PostScript fonts.
+ */
+
+void
+psTextEmbedFonts(ps_text_t *fonts) /* I - Font data */
+{
+ int i, j; /* Looping vars */
+ const char *cups_datadir; /* CUPS_DATADIR environment variable */
+ char *font; /* Current font */
+ char filename[1024]; /* Current filename */
+ FILE *fp; /* Current file */
+ char line[1024]; /* Line from file */
+ int ch; /* Character value */
+
+
+ /*
+ * Get the data directory...
+ */
+
+ if ((cups_datadir = getenv("CUPS_DATADIR")) == NULL)
+ cups_datadir = CUPS_DATADIR;
+
+ /*
+ * Embed each font...
+ */
+
+ for (font = (char *)cupsArrayFirst(fonts->unique);
+ font;
+ font = (char *)cupsArrayNext(fonts->unique))
+ {
+ printf("%%%%BeginResource: font %s\n", font);
+
+ snprintf(filename, sizeof(filename), "%s/fonts/%s", cups_datadir, font);
+ if ((fp = fopen(filename, "rb")) != NULL)
+ {
+ while ((j = fread(line, 1, sizeof(line), fp)) > 0)
+ fwrite(line, 1, j, stdout);
+
+ fclose(fp);
+ }
+ else
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ fprintf(stderr, "DEBUG: Unable to open \"%s\".\n", filename);
+ }
+
+ puts("\n%%EndResource");
+ }
+
+ /*
+ * Write the encoding arrays...
+ */
+
+ puts("% Character encodings");
+
+ for (i = 0; i < fonts->num_fonts; i ++)
+ {
+ printf("/cupsEncoding%02x [\n", i);
+
+ for (ch = 0; ch < 256; ch ++)
+ {
+ if (fonts->glyphs[fonts->codes[i * 256 + ch]])
+ printf("/%s", fonts->glyphs[fonts->codes[i * 256 + ch]]);
+ else if (fonts->codes[i * 256 + ch] > 255)
+ printf("/uni%04X", fonts->codes[i * 256 + ch]);
+ else
+ printf("/.notdef");
+
+ if ((ch & 7) == 7)
+ putchar('\n');
+ }
+
+ puts("] def");
+ }
+
+ /*
+ * Construct composite fonts... Start by reencoding the base fonts...
+ */
+
+ puts("% Reencode base fonts");
+
+ for (i = 0; i < 4; i ++)
+ for (j = 0; j < fonts->num_fonts; j ++)
+ {
+ printf("/%s findfont\n", fonts->fonts[j][i]);
+ printf("dup length 1 add dict begin\n"
+ " { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
+ " /Encoding cupsEncoding%02x def\n"
+ " currentdict\n"
+ "end\n", j);
+ printf("/%s%02x exch definefont /%s%02x exch def\n", ps_font_names[i], j,
+ ps_font_names[i], j);
+ }
+
+ /*
+ * Then merge them into composite fonts...
+ */
+
+ puts("% Create composite fonts");
+
+ for (i = 0; i < 4; i ++)
+ {
+ puts("8 dict begin");
+ puts("/FontType 0 def/FontMatrix[1.0 0 0 1.0 0 0]def/FMapType 2 def"
+ "/Encoding[");
+ for (j = 0; j < fonts->num_fonts; j ++)
+ if (j == (fonts->num_fonts - 1))
+ printf("%d", j);
+ else if ((j & 15) == 15)
+ printf("%d\n", j);
+ else
+ printf("%d ", j);
+ puts("]def/FDepVector[");
+ for (j = 0; j < fonts->num_fonts; j ++)
+ if (j == (fonts->num_fonts - 1))
+ printf("%s%02x", ps_font_names[i], j);
+ else if ((j & 3) == 3)
+ printf("%s%02x\n", ps_font_names[i], j);
+ else
+ printf("%s%02x ", ps_font_names[i], j);
+ puts("]def currentdict end");
+ printf("/%s exch definefont pop\n", ps_font_names[i]);
+ }
+
+ /*
+ * Procedures...
+ */
+
+ puts("% Procedures to justify text...\n"
+ "/showcenter{dup stringwidth pop -0.5 mul 0 rmoveto show}bind def\n"
+ "/showleft{show}bind def\n"
+ "/showright{dup stringwidth pop neg 0 rmoveto show}bind def");
+}
+
+
+/*
+ * 'psTextListFonts()' - List PostScript fonts.
+ */
+
+void
+psTextListFonts(ps_text_t *fonts) /* I - Font data */
+{
+ char *font; /* Current font */
+
+
+ font = (char *)cupsArrayFirst(fonts->unique);
+ printf("%%%%DocumentSuppliedResources: font %s\n", font);
+ while ((font = (char *)cupsArrayNext(fonts->unique)) != NULL)
+ printf("%%%%+ font %s\n", font);
+}
+
+
+/*
+ * 'psTextInitialize()' - Load and embed font data for UTF-8 text.
+ */
+
+ps_text_t * /* O - Font data */
+psTextInitialize(void)
+{
+ ps_text_t *fonts; /* Font data */
+ int i, j; /* Looping vars */
+ char filename[1024]; /* Current filename */
+ FILE *fp; /* Current file */
+ const char *cups_datadir; /* CUPS_DATADIR environment variable */
+ char line[1024], /* Line from file */
+ *lineptr, /* Pointer into line */
+ *valptr; /* Pointer to value in line */
+ int unicode; /* Character value */
+ int start, end; /* Start and end values for range */
+ char glyph[64]; /* Glyph name */
+
+
+ /*
+ * Get the data directory...
+ */
+
+ if ((cups_datadir = getenv("CUPS_DATADIR")) == NULL)
+ cups_datadir = CUPS_DATADIR;
+
+ /*
+ * Initialize the PostScript text data...
+ */
+
+ fonts = (ps_text_t *)calloc(1, sizeof(ps_text_t));
+ fonts->size = -1.0;
+ fonts->style = -1;
+
+ /*
+ * Load the PostScript glyph names...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/data/psglyphs", cups_datadir);
+
+ if ((fp = fopen(filename, "r")) != NULL)
+ {
+ while (fscanf(fp, "%x%63s", &unicode, glyph) == 2)
+ fonts->glyphs[unicode] = _cupsStrAlloc(glyph);
+
+ fclose(fp);
+ }
+ else
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ fprintf(stderr, "DEBUG: Unable to open \"%s\".\n", filename);
+ exit(1);
+ }
+
+ /*
+ * Open the UTF-8 character set definition...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/charsets/utf-8", cups_datadir);
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ {
+ /*
+ * Can't open charset file!
+ */
+
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ fprintf(stderr, "DEBUG: Unable to open \"%s\".\n", filename);
+ exit(1);
+ }
+
+ if (!fgets(line, sizeof(line), fp) || strncmp(line, "charset utf8", 12))
+ {
+ /*
+ * Bad/empty charset file!
+ */
+
+ fclose(fp);
+ _cupsLangPrintFilter(stderr, "ERROR", _("Bad charset file \"%s\"."),
+ filename);
+ exit(1);
+ }
+
+ /*
+ * Read the font descriptions...
+ */
+
+ fonts->unique = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Skip comment and blank lines...
+ */
+
+ if (line[0] == '#' || line[0] == '\n')
+ continue;
+
+ /*
+ * Read the font descriptions that should look like:
+ *
+ * start end direction width normal [bold italic bold-italic]
+ */
+
+ lineptr = line;
+
+ start = strtol(lineptr, &lineptr, 16);
+ end = strtol(lineptr, &lineptr, 16);
+
+ while (isspace(*lineptr & 255))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+
+ if (!*lineptr)
+ {
+ /*
+ * Can't have a font without all required values...
+ */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Bad font description line \"%s\"."), valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ *lineptr++ = '\0';
+
+ if (!strcmp(valptr, "ltor"))
+ fonts->directions[fonts->num_fonts] = 1;
+ else if (!strcmp(valptr, "rtol"))
+ fonts->directions[fonts->num_fonts] = -1;
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("Bad text direction \"%s\"."),
+ valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ /*
+ * Got the direction, now get the width...
+ */
+
+ while (isspace(*lineptr & 255))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+
+ if (!*lineptr)
+ {
+ /*
+ * Can't have a font without all required values...
+ */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Bad font description line \"%s\"."), valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ *lineptr++ = '\0';
+
+ if (!strcmp(valptr, "single"))
+ fonts->widths[fonts->num_fonts] = 1;
+ else if (!strcmp(valptr, "double"))
+ fonts->widths[fonts->num_fonts] = 2;
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("Bad text width \"%s\"."),
+ valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ /*
+ * Get the fonts...
+ */
+
+ for (i = 0; *lineptr && i < 4; i ++)
+ {
+ while (isspace(*lineptr & 255))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+
+ if (*lineptr)
+ *lineptr++ = '\0';
+
+ if (lineptr > valptr)
+ {
+ if (!cupsArrayFind(fonts->unique, valptr))
+ cupsArrayAdd(fonts->unique, _cupsStrAlloc(valptr));
+
+ fonts->fonts[fonts->num_fonts][i] = _cupsStrAlloc(valptr);
+ }
+ }
+
+ /*
+ * Fill in remaining fonts as needed...
+ */
+
+ for (j = i; j < 4; j ++)
+ fonts->fonts[fonts->num_fonts][j] =
+ _cupsStrAlloc(fonts->fonts[fonts->num_fonts][0]);
+
+ /*
+ * Define the character mappings...
+ */
+
+ for (i = start, j = fonts->num_fonts * 256; i <= end; i ++, j ++)
+ {
+ fonts->chars[i] = j;
+ fonts->codes[j] = i;
+ }
+
+ /*
+ * Move to the next font, stopping if needed...
+ */
+
+ fonts->num_fonts ++;
+ if (fonts->num_fonts >= 256)
+ break;
+ }
+
+ fclose(fp);
+
+ if (cupsArrayCount(fonts->unique) == 0)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("No fonts in charset file."));
+ exit(1);
+ }
+
+ return (fonts);
+}
+
+
+/*
+ * 'psTextUTF8()' - Output UTF-8 text at the current position.
+ */
+
+void
+psTextUTF8(ps_text_t *fonts, /* I - Font data */
+ float size, /* I - Size in points */
+ int style, /* I - Style */
+ int align, /* I - Alignment */
+ const char *text) /* I - UTF-8 text */
+{
+ cups_utf32_t utf32[2048]; /* Temporary buffer */
+ int utf32len; /* Number of characters */
+
+
+ if (!text)
+ {
+ puts("");
+ return;
+ }
+
+ if ((utf32len = cupsUTF8ToUTF32(utf32, (cups_utf8_t *)text,
+ (int)(sizeof(utf32) / sizeof(utf32[0])))) > 0)
+ psTextUTF32(fonts, size, style, align, utf32, utf32len);
+}
+
+
+/*
+ * 'psTextUTF32()' - Output UTF-32 text at the current position.
+ */
+
+void
+psTextUTF32(ps_text_t *fonts, /* I - Font data */
+ float size, /* I - Size in points */
+ int style, /* I - Font style */
+ int align, /* I - Alignment */
+ const cups_utf32_t *text, /* I - UTF-32 text */
+ int textlen) /* I - Length of text */
+{
+ if (size != fonts->size || style != fonts->style)
+ {
+ printf("/%s findfont %g scalefont setfont\n", ps_font_names[style], size);
+ fonts->size = size;
+ fonts->style = style;
+ }
+
+ putchar('<');
+ while (textlen > 0)
+ {
+ printf("%04x", fonts->chars[*text]);
+ text ++;
+ textlen --;
+ }
+
+ if (align == PS_CENTER)
+ puts(">showcenter");
+ else if (align == PS_RIGHT)
+ puts(">showright");
+ else
+ puts(">showleft");
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/pstext.h b/filter/pstext.h
new file mode 100644
index 000000000..41cbee433
--- /dev/null
+++ b/filter/pstext.h
@@ -0,0 +1,74 @@
+/*
+ * "$Id$"
+ *
+ * Common PostScript text definitions for CUPS.
+ *
+ * Copyright 2008-2010 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "common.h"
+#include <cups/transcode.h>
+
+
+/*
+ * Constants...
+ */
+
+#define PS_NORMAL 0 /* Normal text */
+#define PS_BOLD 1 /* Bold text */
+#define PS_ITALIC 2 /* Italic text */
+#define PS_BOLDITALIC 3 /* Bold italic text */
+
+#define PS_LEFT 1 /* Left-justified text */
+#define PS_CENTER 0 /* Center-justified text */
+#define PS_RIGHT -1 /* Right-justified text */
+
+
+/*
+ * Structures...
+ */
+
+typedef struct ps_text_s /**** PostScript font data ****/
+{
+ char *glyphs[65536]; /* PostScript glyphs for Unicode */
+ int num_fonts; /* Number of fonts to use */
+ char *fonts[256][4]; /* Fonts to use */
+ cups_array_t *unique; /* Unique fonts */
+ unsigned short chars[65536], /* 0xffcc (ff = font, cc = char) */
+ codes[65536]; /* Unicode glyph mapping to fonts */
+ int widths[256], /* Widths of each font */
+ directions[256];/* Text directions for each font */
+ float size; /* Current text size */
+ int style; /* Current text style */
+} ps_text_t;
+
+
+/*
+ * Functions...
+ */
+
+extern void psTextEmbedFonts(ps_text_t *fonts);
+extern void psTextListFonts(ps_text_t *fonts);
+extern ps_text_t *psTextInitialize(void);
+extern void psTextUTF8(ps_text_t *fonts, float size, int style,
+ int align, const char *text);
+extern void psTextUTF32(ps_text_t *fonts, float size, int style,
+ int align, const cups_utf32_t *text,
+ int textlen);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/pstops.c b/filter/pstops.c
new file mode 100644
index 000000000..b00373440
--- /dev/null
+++ b/filter/pstops.c
@@ -0,0 +1,3489 @@
+/*
+ * "$Id$"
+ *
+ * PostScript filter for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry.
+ * add_page() - Add a page to the pages array.
+ * cancel_job() - Flag the job as canceled.
+ * check_range() - Check to see if the current page is selected for
+ * printing.
+ * copy_bytes() - Copy bytes from the input file to stdout.
+ * copy_comments() - Copy all of the comments section.
+ * copy_dsc() - Copy a DSC-conforming document.
+ * copy_non_dsc() - Copy a document that does not conform to the DSC.
+ * copy_page() - Copy a page description.
+ * copy_prolog() - Copy the document prolog section.
+ * copy_setup() - Copy the document setup section.
+ * copy_trailer() - Copy the document trailer.
+ * do_prolog() - Send the necessary document prolog commands.
+ * do_setup() - Send the necessary document setup commands.
+ * doc_printf() - Send a formatted string to stdout and/or the temp
+ * file.
+ * doc_puts() - Send a nul-terminated string to stdout and/or the
+ * temp file.
+ * doc_write() - Send data to stdout and/or the temp file.
+ * end_nup() - End processing for N-up printing.
+ * include_feature() - Include a printer option/feature command.
+ * parse_text() - Parse a text value in a comment.
+ * set_pstops_options() - Set pstops options.
+ * skip_page() - Skip past a page that won't be printed.
+ * start_nup() - Start processing for N-up printing.
+ * write_label_prolog() - Write the prolog with the classification and page
+ * label.
+ * write_labels() - Write the actual page labels.
+ * write_options() - Write options provided via %%IncludeFeature.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "common.h"
+#include <limits.h>
+#include <math.h>
+#include <cups/file.h>
+#include <cups/array.h>
+#include <cups/language-private.h>
+#include <signal.h>
+
+
+/*
+ * Constants...
+ */
+
+#define PSTOPS_BORDERNONE 0 /* No border or hairline border */
+#define PSTOPS_BORDERTHICK 1 /* Think border */
+#define PSTOPS_BORDERSINGLE 2 /* Single-line hairline border */
+#define PSTOPS_BORDERSINGLE2 3 /* Single-line thick border */
+#define PSTOPS_BORDERDOUBLE 4 /* Double-line hairline border */
+#define PSTOPS_BORDERDOUBLE2 5 /* Double-line thick border */
+
+#define PSTOPS_LAYOUT_LRBT 0 /* Left to right, bottom to top */
+#define PSTOPS_LAYOUT_LRTB 1 /* Left to right, top to bottom */
+#define PSTOPS_LAYOUT_RLBT 2 /* Right to left, bottom to top */
+#define PSTOPS_LAYOUT_RLTB 3 /* Right to left, top to bottom */
+#define PSTOPS_LAYOUT_BTLR 4 /* Bottom to top, left to right */
+#define PSTOPS_LAYOUT_TBLR 5 /* Top to bottom, left to right */
+#define PSTOPS_LAYOUT_BTRL 6 /* Bottom to top, right to left */
+#define PSTOPS_LAYOUT_TBRL 7 /* Top to bottom, right to left */
+
+#define PSTOPS_LAYOUT_NEGATEY 1 /* The bits for the layout */
+#define PSTOPS_LAYOUT_NEGATEX 2 /* definitions above... */
+#define PSTOPS_LAYOUT_VERTICAL 4
+
+
+/*
+ * Types...
+ */
+
+typedef struct /**** Page information ****/
+{
+ char *label; /* Page label */
+ int bounding_box[4]; /* PageBoundingBox */
+ off_t offset; /* Offset to start of page */
+ ssize_t length; /* Number of bytes for page */
+ int num_options; /* Number of options for this page */
+ cups_option_t *options; /* Options for this page */
+} pstops_page_t;
+
+typedef struct /**** Document information ****/
+{
+ int page; /* Current page */
+ int bounding_box[4]; /* BoundingBox from header */
+ int new_bounding_box[4]; /* New composite bounding box */
+ int num_options; /* Number of document-wide options */
+ cups_option_t *options; /* Document-wide options */
+ int normal_landscape, /* Normal rotation for landscape? */
+ saw_eof, /* Saw the %%EOF comment? */
+ slow_collate, /* Collate copies by hand? */
+ slow_duplex, /* Duplex pages slowly? */
+ slow_order, /* Reverse pages slowly? */
+ use_ESPshowpage; /* Use ESPshowpage? */
+ cups_array_t *pages; /* Pages in document */
+ cups_file_t *temp; /* Temporary file, if any */
+ char tempfile[1024]; /* Temporary filename */
+ int job_id; /* Job ID */
+ const char *user, /* User name */
+ *title; /* Job name */
+ int copies; /* Number of copies */
+ const char *ap_input_slot, /* AP_FIRSTPAGE_InputSlot value */
+ *ap_manual_feed, /* AP_FIRSTPAGE_ManualFeed value */
+ *ap_media_color, /* AP_FIRSTPAGE_MediaColor value */
+ *ap_media_type, /* AP_FIRSTPAGE_MediaType value */
+ *ap_page_region, /* AP_FIRSTPAGE_PageRegion value */
+ *ap_page_size; /* AP_FIRSTPAGE_PageSize value */
+ float brightness; /* brightness value */
+ int collate, /* Collate copies? */
+ emit_jcl, /* Emit JCL commands? */
+ fitplot; /* Fit pages to media */
+ float gamma; /* gamma value */
+ const char *input_slot, /* InputSlot value */
+ *manual_feed, /* ManualFeed value */
+ *media_color, /* MediaColor value */
+ *media_type, /* MediaType value */
+ *page_region, /* PageRegion value */
+ *page_size; /* PageSize value */
+ int mirror, /* doc->mirror/mirror pages */
+ number_up, /* Number of pages on each sheet */
+ number_up_layout, /* doc->number_up_layout of N-up pages */
+ output_order, /* Requested reverse output order? */
+ page_border; /* doc->page_border around pages */
+ const char *page_label, /* page-label option, if any */
+ *page_ranges, /* page-ranges option, if any */
+ *page_set; /* page-set option, if any */
+} pstops_doc_t;
+
+
+/*
+ * Convenience macros...
+ */
+
+#define is_first_page(p) (doc->number_up == 1 || \
+ ((p) % doc->number_up) == 1)
+#define is_last_page(p) (doc->number_up == 1 || \
+ ((p) % doc->number_up) == 0)
+#define is_not_last_page(p) (doc->number_up > 1 && \
+ ((p) % doc->number_up) != 0)
+
+
+/*
+ * Local globals...
+ */
+
+static int JobCanceled = 0;/* Set to 1 on SIGTERM */
+
+
+/*
+ * Local functions...
+ */
+
+static pstops_page_t *add_page(pstops_doc_t *doc, const char *label);
+static void cancel_job(int sig);
+static int check_range(pstops_doc_t *doc, int page);
+static void copy_bytes(cups_file_t *fp, off_t offset,
+ size_t length);
+static ssize_t copy_comments(cups_file_t *fp, pstops_doc_t *doc,
+ ppd_file_t *ppd, char *line,
+ ssize_t linelen, size_t linesize);
+static void copy_dsc(cups_file_t *fp, pstops_doc_t *doc,
+ ppd_file_t *ppd, char *line, ssize_t linelen,
+ size_t linesize);
+static void copy_non_dsc(cups_file_t *fp, pstops_doc_t *doc,
+ ppd_file_t *ppd, char *line,
+ ssize_t linelen, size_t linesize);
+static ssize_t copy_page(cups_file_t *fp, pstops_doc_t *doc,
+ ppd_file_t *ppd, int number, char *line,
+ ssize_t linelen, size_t linesize);
+static ssize_t copy_prolog(cups_file_t *fp, pstops_doc_t *doc,
+ ppd_file_t *ppd, char *line,
+ ssize_t linelen, size_t linesize);
+static ssize_t copy_setup(cups_file_t *fp, pstops_doc_t *doc,
+ ppd_file_t *ppd, char *line,
+ ssize_t linelen, size_t linesize);
+static ssize_t copy_trailer(cups_file_t *fp, pstops_doc_t *doc,
+ ppd_file_t *ppd, int number, char *line,
+ ssize_t linelen, size_t linesize);
+static void do_prolog(pstops_doc_t *doc, ppd_file_t *ppd);
+static void do_setup(pstops_doc_t *doc, ppd_file_t *ppd);
+static void doc_printf(pstops_doc_t *doc, const char *format, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+#endif /* __GNUC__ */
+;
+static void doc_puts(pstops_doc_t *doc, const char *s);
+static void doc_write(pstops_doc_t *doc, const char *s, size_t len);
+static void end_nup(pstops_doc_t *doc, int number);
+static int include_feature(ppd_file_t *ppd, const char *line,
+ int num_options,
+ cups_option_t **options);
+static char *parse_text(const char *start, char **end, char *buffer,
+ size_t bufsize);
+static void set_pstops_options(pstops_doc_t *doc, ppd_file_t *ppd,
+ char *argv[], int num_options,
+ cups_option_t *options);
+static ssize_t skip_page(cups_file_t *fp, char *line, ssize_t linelen,
+ size_t linesize);
+static void start_nup(pstops_doc_t *doc, int number,
+ int show_border, const int *bounding_box);
+static void write_label_prolog(pstops_doc_t *doc, const char *label,
+ float bottom, float top,
+ float width);
+static void write_labels(pstops_doc_t *doc, int orient);
+static void write_options(pstops_doc_t *doc, ppd_file_t *ppd,
+ int num_options, cups_option_t *options);
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ pstops_doc_t doc; /* Document information */
+ cups_file_t *fp; /* Print file */
+ ppd_file_t *ppd; /* PPD file */
+ int num_options; /* Number of print options */
+ cups_option_t *options; /* Print options */
+ char line[8192]; /* Line buffer */
+ size_t len; /* Length of line 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);
+
+ /*
+ * Ignore broken pipe signals...
+ */
+
+ signal(SIGPIPE, SIG_IGN);
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options file"),
+ argv[0]);
+ return (1);
+ }
+
+ /*
+ * Register a signal handler to cleanly cancel a job.
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, cancel_job);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = cancel_job;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, cancel_job);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * If we have 7 arguments, print the file named on the command-line.
+ * Otherwise, send stdin instead...
+ */
+
+ if (argc == 6)
+ fp = cupsFileStdin();
+ else
+ {
+ /*
+ * Try to open the print file...
+ */
+
+ if ((fp = cupsFileOpen(argv[6], "r")) == NULL)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ return (1);
+ }
+ }
+
+ /*
+ * Read the first line to see if we have DSC comments...
+ */
+
+ if ((len = cupsFileGetLine(fp, line, sizeof(line))) == 0)
+ {
+ fputs("DEBUG: The print file is empty.\n", stderr);
+ return (1);
+ }
+
+ /*
+ * Process command-line options...
+ */
+
+ options = NULL;
+ num_options = cupsParseOptions(argv[5], 0, &options);
+ ppd = SetCommonOptions(num_options, options, 1);
+
+ set_pstops_options(&doc, ppd, argv, num_options, options);
+
+ /*
+ * Write any "exit server" options that have been selected...
+ */
+
+ ppdEmit(ppd, stdout, PPD_ORDER_EXIT);
+
+ /*
+ * Write any JCL commands that are needed to print PostScript code...
+ */
+
+ if (doc.emit_jcl)
+ ppdEmitJCL(ppd, stdout, doc.job_id, doc.user, doc.title);
+
+ /*
+ * Start with a DSC header...
+ */
+
+ puts("%!PS-Adobe-3.0");
+
+ /*
+ * Skip leading PJL in the document...
+ */
+
+ while (!strncmp(line, "\033%-12345X", 9) || !strncmp(line, "@PJL ", 5))
+ {
+ /*
+ * Yup, we have leading PJL fun, so skip it until we hit the line
+ * with "ENTER LANGUAGE"...
+ */
+
+ fputs("DEBUG: Skipping PJL header...\n", stderr);
+
+ while (strstr(line, "ENTER LANGUAGE") == NULL && strncmp(line, "%!", 2))
+ if ((len = cupsFileGetLine(fp, line, sizeof(line))) == 0)
+ break;
+
+ if (!strncmp(line, "%!", 2))
+ break;
+
+ if ((len = cupsFileGetLine(fp, line, sizeof(line))) == 0)
+ break;
+ }
+
+ /*
+ * Now see if the document conforms to the Adobe Document Structuring
+ * Conventions...
+ */
+
+ if (!strncmp(line, "%!PS-Adobe-", 11))
+ {
+ /*
+ * Yes, filter the document...
+ */
+
+ copy_dsc(fp, &doc, ppd, line, len, sizeof(line));
+ }
+ else
+ {
+ /*
+ * No, display an error message and treat the file as if it contains
+ * a single page...
+ */
+
+ copy_non_dsc(fp, &doc, ppd, line, len, sizeof(line));
+ }
+
+ /*
+ * Send %%EOF as needed...
+ */
+
+ if (!doc.saw_eof)
+ puts("%%EOF");
+
+ /*
+ * End the job with the appropriate JCL command or CTRL-D...
+ */
+
+ if (doc.emit_jcl)
+ {
+ if (ppd && ppd->jcl_end)
+ ppdEmitJCLEnd(ppd, stdout);
+ else
+ putchar(0x04);
+ }
+
+ /*
+ * Close files and remove the temporary file if needed...
+ */
+
+ if (doc.temp)
+ {
+ cupsFileClose(doc.temp);
+ unlink(doc.tempfile);
+ }
+
+ ppdClose(ppd);
+ cupsFreeOptions(num_options, options);
+
+ cupsFileClose(fp);
+
+ return (0);
+}
+
+
+/*
+ * 'add_page()' - Add a page to the pages array.
+ */
+
+static pstops_page_t * /* O - New page info object */
+add_page(pstops_doc_t *doc, /* I - Document information */
+ const char *label) /* I - Page label */
+{
+ pstops_page_t *pageinfo; /* New page info object */
+
+
+ if (!doc->pages)
+ doc->pages = cupsArrayNew(NULL, NULL);
+
+ if (!doc->pages)
+ {
+ _cupsLangPrintError("EMERG", _("Unable to allocate memory for pages array"));
+ exit(1);
+ }
+
+ if ((pageinfo = calloc(1, sizeof(pstops_page_t))) == NULL)
+ {
+ _cupsLangPrintError("EMERG", _("Unable to allocate memory for page info"));
+ exit(1);
+ }
+
+ pageinfo->label = strdup(label);
+ pageinfo->offset = cupsFileTell(doc->temp);
+
+ cupsArrayAdd(doc->pages, pageinfo);
+
+ doc->page ++;
+
+ return (pageinfo);
+}
+
+
+/*
+ * 'cancel_job()' - Flag the job as canceled.
+ */
+
+static void
+cancel_job(int sig) /* I - Signal number (unused) */
+{
+ (void)sig;
+
+ JobCanceled = 1;
+}
+
+
+/*
+ * 'check_range()' - Check to see if the current page is selected for
+ * printing.
+ */
+
+static int /* O - 1 if selected, 0 otherwise */
+check_range(pstops_doc_t *doc, /* I - Document information */
+ int page) /* I - Page number */
+{
+ const char *range; /* Pointer into range string */
+ int lower, upper; /* Lower and upper page numbers */
+
+
+ if (doc->page_set)
+ {
+ /*
+ * See if we only print even or odd pages...
+ */
+
+ if (!_cups_strcasecmp(doc->page_set, "even") && (page & 1))
+ return (0);
+
+ if (!_cups_strcasecmp(doc->page_set, "odd") && !(page & 1))
+ return (0);
+ }
+
+ if (!doc->page_ranges)
+ return (1); /* No range, print all pages... */
+
+ for (range = doc->page_ranges; *range != '\0';)
+ {
+ if (*range == '-')
+ {
+ lower = 1;
+ range ++;
+ upper = strtol(range, (char **)&range, 10);
+ }
+ else
+ {
+ lower = strtol(range, (char **)&range, 10);
+
+ if (*range == '-')
+ {
+ range ++;
+ if (!isdigit(*range & 255))
+ upper = 65535;
+ else
+ upper = strtol(range, (char **)&range, 10);
+ }
+ else
+ upper = lower;
+ }
+
+ if (page >= lower && page <= upper)
+ return (1);
+
+ if (*range == ',')
+ range ++;
+ else
+ break;
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'copy_bytes()' - Copy bytes from the input file to stdout.
+ */
+
+static void
+copy_bytes(cups_file_t *fp, /* I - File to read from */
+ off_t offset, /* I - Offset to page data */
+ size_t length) /* I - Length of page data */
+{
+ char buffer[8192]; /* Data buffer */
+ ssize_t nbytes; /* Number of bytes read */
+ size_t nleft; /* Number of bytes left/remaining */
+
+
+ nleft = length;
+
+ if (cupsFileSeek(fp, offset) < 0)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to see in file"));
+ return;
+ }
+
+ while (nleft > 0 || length == 0)
+ {
+ if (nleft > sizeof(buffer) || length == 0)
+ nbytes = sizeof(buffer);
+ else
+ nbytes = nleft;
+
+ if ((nbytes = cupsFileRead(fp, buffer, nbytes)) < 1)
+ return;
+
+ nleft -= nbytes;
+
+ fwrite(buffer, 1, nbytes, stdout);
+ }
+}
+
+
+/*
+ * 'copy_comments()' - Copy all of the comments section.
+ *
+ * This function expects "line" to be filled with a comment line.
+ * On return, "line" will contain the next line in the file, if any.
+ */
+
+static ssize_t /* O - Length of next line */
+copy_comments(cups_file_t *fp, /* I - File to read from */
+ pstops_doc_t *doc, /* I - Document info */
+ ppd_file_t *ppd, /* I - PPD file */
+ char *line, /* I - Line buffer */
+ ssize_t linelen, /* I - Length of initial line */
+ size_t linesize) /* I - Size of line buffer */
+{
+ int saw_bounding_box, /* Saw %%BoundingBox: comment? */
+ saw_for, /* Saw %%For: comment? */
+ saw_pages, /* Saw %%Pages: comment? */
+ saw_title; /* Saw %%Title: comment? */
+
+
+ /*
+ * Loop until we see %%EndComments or a non-comment line...
+ */
+
+ saw_bounding_box = 0;
+ saw_for = 0;
+ saw_pages = 0;
+ saw_title = 0;
+
+ while (line[0] == '%')
+ {
+ /*
+ * Strip trailing whitespace...
+ */
+
+ while (linelen > 0)
+ {
+ linelen --;
+
+ if (!isspace(line[linelen] & 255))
+ break;
+ else
+ line[linelen] = '\0';
+ }
+
+ /*
+ * Log the header...
+ */
+
+ fprintf(stderr, "DEBUG: %s\n", line);
+
+ /*
+ * Pull the headers out...
+ */
+
+ if (!strncmp(line, "%%Pages:", 8))
+ {
+ int pages; /* Number of pages */
+
+ if (saw_pages)
+ fputs("DEBUG: A duplicate %%Pages: comment was seen.\n", stderr);
+
+ saw_pages = 1;
+
+ if (Duplex && (pages = atoi(line + 8)) > 0 && pages <= doc->number_up)
+ {
+ /*
+ * Since we will only be printing on a single page, disable duplexing.
+ */
+
+ Duplex = 0;
+ doc->slow_duplex = 0;
+
+ if (cupsGetOption("sides", doc->num_options, doc->options))
+ doc->num_options = cupsAddOption("sides", "one-sided",
+ doc->num_options, &(doc->options));
+
+ if (cupsGetOption("Duplex", doc->num_options, doc->options))
+ doc->num_options = cupsAddOption("Duplex", "None",
+ doc->num_options, &(doc->options));
+
+ if (cupsGetOption("EFDuplex", doc->num_options, doc->options))
+ doc->num_options = cupsAddOption("EFDuplex", "None",
+ doc->num_options, &(doc->options));
+
+ if (cupsGetOption("EFDuplexing", doc->num_options, doc->options))
+ doc->num_options = cupsAddOption("EFDuplexing", "False",
+ doc->num_options, &(doc->options));
+
+ if (cupsGetOption("KD03Duplex", doc->num_options, doc->options))
+ doc->num_options = cupsAddOption("KD03Duplex", "None",
+ doc->num_options, &(doc->options));
+
+ if (cupsGetOption("JCLDuplex", doc->num_options, doc->options))
+ doc->num_options = cupsAddOption("JCLDuplex", "None",
+ doc->num_options, &(doc->options));
+
+ ppdMarkOption(ppd, "Duplex", "None");
+ ppdMarkOption(ppd, "EFDuplex", "None");
+ ppdMarkOption(ppd, "EFDuplexing", "False");
+ ppdMarkOption(ppd, "KD03Duplex", "None");
+ ppdMarkOption(ppd, "JCLDuplex", "None");
+ }
+ }
+ else if (!strncmp(line, "%%BoundingBox:", 14))
+ {
+ if (saw_bounding_box)
+ fputs("DEBUG: A duplicate %%BoundingBox: comment was seen.\n", stderr);
+ else if (strstr(line + 14, "(atend)"))
+ {
+ /*
+ * Do nothing for now but use the default imageable area...
+ */
+ }
+ else if (sscanf(line + 14, "%d%d%d%d", doc->bounding_box + 0,
+ doc->bounding_box + 1, doc->bounding_box + 2,
+ doc->bounding_box + 3) != 4)
+ {
+ fputs("DEBUG: A bad %%BoundingBox: comment was seen.\n", stderr);
+
+ doc->bounding_box[0] = (int)PageLeft;
+ doc->bounding_box[1] = (int)PageBottom;
+ doc->bounding_box[2] = (int)PageRight;
+ doc->bounding_box[3] = (int)PageTop;
+ }
+
+ saw_bounding_box = 1;
+ }
+ else if (!strncmp(line, "%%For:", 6))
+ {
+ saw_for = 1;
+ doc_printf(doc, "%s\n", line);
+ }
+ else if (!strncmp(line, "%%Title:", 8))
+ {
+ saw_title = 1;
+ doc_printf(doc, "%s\n", line);
+ }
+ else if (!strncmp(line, "%cupsRotation:", 14))
+ {
+ /*
+ * Reset orientation of document?
+ */
+
+ int orient = (atoi(line + 14) / 90) & 3;
+
+ if (orient != Orientation)
+ {
+ /*
+ * Yes, update things so that the pages come out right...
+ */
+
+ Orientation = (4 - Orientation + orient) & 3;
+ UpdatePageVars();
+ Orientation = orient;
+ }
+ }
+ else if (!strcmp(line, "%%EndComments"))
+ {
+ linelen = cupsFileGetLine(fp, line, linesize);
+ break;
+ }
+ else if (strncmp(line, "%!", 2) && strncmp(line, "%cups", 5))
+ doc_printf(doc, "%s\n", line);
+
+ if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0)
+ break;
+ }
+
+ if (!saw_bounding_box)
+ fputs("DEBUG: There wasn't a %%BoundingBox: comment in the header.\n",
+ stderr);
+
+ if (!saw_pages)
+ fputs("DEBUG: There wasn't a %%Pages: comment in the header.\n", stderr);
+
+ if (!saw_for)
+ WriteTextComment("For", doc->user);
+
+ if (!saw_title)
+ WriteTextComment("Title", doc->title);
+
+ if (doc->copies != 1 && (!doc->collate || !doc->slow_collate))
+ {
+ /*
+ * Tell the document processor the copy and duplex options
+ * that are required...
+ */
+
+ doc_printf(doc, "%%%%Requirements: numcopies(%d)%s%s\n", doc->copies,
+ doc->collate ? " collate" : "",
+ Duplex ? " duplex" : "");
+
+ /*
+ * Apple uses RBI comments for various non-PPD options...
+ */
+
+ doc_printf(doc, "%%RBINumCopies: %d\n", doc->copies);
+ }
+ else
+ {
+ /*
+ * Tell the document processor the duplex option that is required...
+ */
+
+ if (Duplex)
+ doc_puts(doc, "%%Requirements: duplex\n");
+
+ /*
+ * Apple uses RBI comments for various non-PPD options...
+ */
+
+ doc_puts(doc, "%RBINumCopies: 1\n");
+ }
+
+ doc_puts(doc, "%%Pages: (atend)\n");
+ doc_puts(doc, "%%BoundingBox: (atend)\n");
+ doc_puts(doc, "%%EndComments\n");
+
+ return (linelen);
+}
+
+
+/*
+ * 'copy_dsc()' - Copy a DSC-conforming document.
+ *
+ * This function expects "line" to be filled with the %!PS-Adobe comment line.
+ */
+
+static void
+copy_dsc(cups_file_t *fp, /* I - File to read from */
+ pstops_doc_t *doc, /* I - Document info */
+ ppd_file_t *ppd, /* I - PPD file */
+ char *line, /* I - Line buffer */
+ ssize_t linelen, /* I - Length of initial line */
+ size_t linesize) /* I - Size of line buffer */
+{
+ int number; /* Page number */
+ pstops_page_t *pageinfo; /* Page information */
+
+
+ /*
+ * Make sure we use ESPshowpage for EPS files...
+ */
+
+ if (strstr(line, "EPSF"))
+ {
+ doc->use_ESPshowpage = 1;
+ doc->number_up = 1;
+ }
+
+ /*
+ * Start sending the document with any commands needed...
+ */
+
+ fprintf(stderr, "DEBUG: Before copy_comments - %s", line);
+ linelen = copy_comments(fp, doc, ppd, line, linelen, linesize);
+
+ /*
+ * Now find the prolog section, if any...
+ */
+
+ fprintf(stderr, "DEBUG: Before copy_prolog - %s", line);
+ linelen = copy_prolog(fp, doc, ppd, line, linelen, linesize);
+
+ /*
+ * Then the document setup section...
+ */
+
+ fprintf(stderr, "DEBUG: Before copy_setup - %s", line);
+ linelen = copy_setup(fp, doc, ppd, line, linelen, linesize);
+
+ /*
+ * Copy until we see %%Page:...
+ */
+
+ while (strncmp(line, "%%Page:", 7) && strncmp(line, "%%Trailer", 9))
+ {
+ doc_write(doc, line, linelen);
+
+ if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0)
+ break;
+ }
+
+ /*
+ * Then process pages until we have no more...
+ */
+
+ number = 0;
+
+ fprintf(stderr, "DEBUG: Before page loop - %s", line);
+ while (!strncmp(line, "%%Page:", 7))
+ {
+ if (JobCanceled)
+ break;
+
+ number ++;
+
+ if (check_range(doc, (number - 1) / doc->number_up + 1))
+ {
+ fprintf(stderr, "DEBUG: Copying page %d...\n", number);
+ linelen = copy_page(fp, doc, ppd, number, line, linelen, linesize);
+ }
+ else
+ {
+ fprintf(stderr, "DEBUG: Skipping page %d...\n", number);
+ linelen = skip_page(fp, line, linelen, linesize);
+ }
+ }
+
+ /*
+ * Finish up the last page(s)...
+ */
+
+ if (number && is_not_last_page(number) && cupsArrayLast(doc->pages) &&
+ check_range(doc, (number - 1) / doc->number_up + 1))
+ {
+ pageinfo = (pstops_page_t *)cupsArrayLast(doc->pages);
+
+ start_nup(doc, doc->number_up, 0, doc->bounding_box);
+ doc_puts(doc, "showpage\n");
+ end_nup(doc, doc->number_up);
+
+ pageinfo->length = cupsFileTell(doc->temp) - pageinfo->offset;
+ }
+
+ if (doc->slow_duplex && (doc->page & 1))
+ {
+ /*
+ * Make sure we have an even number of pages...
+ */
+
+ pageinfo = add_page(doc, "(filler)");
+
+ if (!doc->slow_order)
+ {
+ if (!ppd || !ppd->num_filters)
+ fprintf(stderr, "PAGE: %d %d\n", doc->page,
+ doc->slow_collate ? 1 : doc->copies);
+
+ printf("%%%%Page: (filler) %d\n", doc->page);
+ }
+
+ start_nup(doc, doc->number_up, 0, doc->bounding_box);
+ doc_puts(doc, "showpage\n");
+ end_nup(doc, doc->number_up);
+
+ pageinfo->length = cupsFileTell(doc->temp) - pageinfo->offset;
+ }
+
+ /*
+ * Make additional copies as necessary...
+ */
+
+ number = doc->slow_order ? 0 : doc->page;
+
+ if (doc->temp && !JobCanceled && cupsArrayCount(doc->pages) > 0)
+ {
+ int copy; /* Current copy */
+
+
+ /*
+ * Reopen the temporary file for reading...
+ */
+
+ cupsFileClose(doc->temp);
+
+ doc->temp = cupsFileOpen(doc->tempfile, "r");
+
+ /*
+ * Make the copies...
+ */
+
+ if (doc->slow_collate)
+ copy = !doc->slow_order;
+ else
+ copy = doc->copies - 1;
+
+ for (; copy < doc->copies; copy ++)
+ {
+ if (JobCanceled)
+ break;
+
+ /*
+ * Send end-of-job stuff followed by any start-of-job stuff required
+ * for the JCL options...
+ */
+
+ if (number && doc->emit_jcl && ppd && ppd->jcl_end)
+ {
+ /*
+ * Send the trailer...
+ */
+
+ puts("%%Trailer");
+ printf("%%%%Pages: %d\n", cupsArrayCount(doc->pages));
+ if (doc->number_up > 1 || doc->fitplot)
+ printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
+ PageLeft, PageBottom, PageRight, PageTop);
+ else
+ printf("%%%%BoundingBox: %d %d %d %d\n",
+ doc->new_bounding_box[0], doc->new_bounding_box[1],
+ doc->new_bounding_box[2], doc->new_bounding_box[3]);
+ puts("%%EOF");
+
+ /*
+ * Start a new document...
+ */
+
+ ppdEmitJCLEnd(ppd, stdout);
+ ppdEmitJCL(ppd, stdout, doc->job_id, doc->user, doc->title);
+
+ puts("%!PS-Adobe-3.0");
+
+ number = 0;
+ }
+
+ /*
+ * Copy the prolog as needed...
+ */
+
+ if (!number)
+ {
+ pageinfo = (pstops_page_t *)cupsArrayFirst(doc->pages);
+ copy_bytes(doc->temp, 0, pageinfo->offset);
+ }
+
+ /*
+ * Then copy all of the pages...
+ */
+
+ pageinfo = doc->slow_order ? (pstops_page_t *)cupsArrayLast(doc->pages) :
+ (pstops_page_t *)cupsArrayFirst(doc->pages);
+
+ while (pageinfo)
+ {
+ if (JobCanceled)
+ break;
+
+ number ++;
+
+ if (!ppd || !ppd->num_filters)
+ fprintf(stderr, "PAGE: %d %d\n", number,
+ doc->slow_collate ? 1 : doc->copies);
+
+ if (doc->number_up > 1)
+ {
+ printf("%%%%Page: (%d) %d\n", number, number);
+ printf("%%%%PageBoundingBox: %.0f %.0f %.0f %.0f\n",
+ PageLeft, PageBottom, PageRight, PageTop);
+ }
+ else
+ {
+ printf("%%%%Page: %s %d\n", pageinfo->label, number);
+ printf("%%%%PageBoundingBox: %d %d %d %d\n",
+ pageinfo->bounding_box[0], pageinfo->bounding_box[1],
+ pageinfo->bounding_box[2], pageinfo->bounding_box[3]);
+ }
+
+ copy_bytes(doc->temp, pageinfo->offset, pageinfo->length);
+
+ pageinfo = doc->slow_order ? (pstops_page_t *)cupsArrayPrev(doc->pages) :
+ (pstops_page_t *)cupsArrayNext(doc->pages);
+ }
+ }
+ }
+
+ /*
+ * Restore the old showpage operator as needed...
+ */
+
+ if (doc->use_ESPshowpage)
+ puts("userdict/showpage/ESPshowpage load put\n");
+
+ /*
+ * Write/copy the trailer...
+ */
+
+ if (!JobCanceled)
+ copy_trailer(fp, doc, ppd, number, line, linelen, linesize);
+}
+
+
+/*
+ * 'copy_non_dsc()' - Copy a document that does not conform to the DSC.
+ *
+ * This function expects "line" to be filled with the %! comment line.
+ */
+
+static void
+copy_non_dsc(cups_file_t *fp, /* I - File to read from */
+ pstops_doc_t *doc, /* I - Document info */
+ ppd_file_t *ppd, /* I - PPD file */
+ char *line, /* I - Line buffer */
+ ssize_t linelen, /* I - Length of initial line */
+ size_t linesize) /* I - Size of line buffer */
+{
+ int copy; /* Current copy */
+ char buffer[8192]; /* Copy buffer */
+ int bytes; /* Number of bytes copied */
+
+
+ /*
+ * First let the user know that they are attempting to print a file
+ * that may not print correctly...
+ */
+
+ fputs("DEBUG: This document does not conform to the Adobe Document "
+ "Structuring Conventions and may not print correctly.\n", stderr);
+
+ /*
+ * Then write a standard DSC comment section...
+ */
+
+ printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom,
+ PageRight, PageTop);
+
+ if (doc->slow_collate && doc->copies > 1)
+ printf("%%%%Pages: %d\n", doc->copies);
+ else
+ puts("%%Pages: 1");
+
+ WriteTextComment("For", doc->user);
+ WriteTextComment("Title", doc->title);
+
+ if (doc->copies != 1 && (!doc->collate || !doc->slow_collate))
+ {
+ /*
+ * Tell the document processor the copy and duplex options
+ * that are required...
+ */
+
+ printf("%%%%Requirements: numcopies(%d)%s%s\n", doc->copies,
+ doc->collate ? " collate" : "",
+ Duplex ? " duplex" : "");
+
+ /*
+ * Apple uses RBI comments for various non-PPD options...
+ */
+
+ printf("%%RBINumCopies: %d\n", doc->copies);
+ }
+ else
+ {
+ /*
+ * Tell the document processor the duplex option that is required...
+ */
+
+ if (Duplex)
+ puts("%%Requirements: duplex");
+
+ /*
+ * Apple uses RBI comments for various non-PPD options...
+ */
+
+ puts("%RBINumCopies: 1");
+ }
+
+ puts("%%EndComments");
+
+ /*
+ * Then the prolog...
+ */
+
+ puts("%%BeginProlog");
+
+ do_prolog(doc, ppd);
+
+ puts("%%EndProlog");
+
+ /*
+ * Then the setup section...
+ */
+
+ puts("%%BeginSetup");
+
+ do_setup(doc, ppd);
+
+ puts("%%EndSetup");
+
+ /*
+ * Finally, embed a copy of the file inside a %%Page...
+ */
+
+ if (!ppd || !ppd->num_filters)
+ fprintf(stderr, "PAGE: 1 %d\n", doc->temp ? 1 : doc->copies);
+
+ puts("%%Page: 1 1");
+ puts("%%BeginPageSetup");
+ ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
+ puts("%%EndPageSetup");
+ puts("%%BeginDocument: nondsc");
+
+ fwrite(line, linelen, 1, stdout);
+
+ if (doc->temp)
+ cupsFileWrite(doc->temp, line, linelen);
+
+ while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0)
+ {
+ fwrite(buffer, 1, bytes, stdout);
+
+ if (doc->temp)
+ cupsFileWrite(doc->temp, buffer, bytes);
+ }
+
+ puts("%%EndDocument");
+
+ if (doc->use_ESPshowpage)
+ {
+ WriteLabels(Orientation);
+ puts("ESPshowpage");
+ }
+
+ if (doc->temp && !JobCanceled)
+ {
+ /*
+ * Reopen the temporary file for reading...
+ */
+
+ cupsFileClose(doc->temp);
+
+ doc->temp = cupsFileOpen(doc->tempfile, "r");
+
+ /*
+ * Make the additional copies as needed...
+ */
+
+ for (copy = 1; copy < doc->copies; copy ++)
+ {
+ if (JobCanceled)
+ break;
+
+ if (!ppd || !ppd->num_filters)
+ fputs("PAGE: 1 1\n", stderr);
+
+ printf("%%%%Page: %d %d\n", copy + 1, copy + 1);
+ puts("%%BeginPageSetup");
+ ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
+ puts("%%EndPageSetup");
+ puts("%%BeginDocument: nondsc");
+
+ copy_bytes(doc->temp, 0, 0);
+
+ puts("%%EndDocument");
+
+ if (doc->use_ESPshowpage)
+ {
+ WriteLabels(Orientation);
+ puts("ESPshowpage");
+ }
+ }
+ }
+
+ /*
+ * Restore the old showpage operator as needed...
+ */
+
+ if (doc->use_ESPshowpage)
+ puts("userdict/showpage/ESPshowpage load put\n");
+}
+
+
+/*
+ * 'copy_page()' - Copy a page description.
+ *
+ * This function expects "line" to be filled with a %%Page comment line.
+ * On return, "line" will contain the next line in the file, if any.
+ */
+
+static ssize_t /* O - Length of next line */
+copy_page(cups_file_t *fp, /* I - File to read from */
+ pstops_doc_t *doc, /* I - Document info */
+ ppd_file_t *ppd, /* I - PPD file */
+ int number, /* I - Current page number */
+ char *line, /* I - Line buffer */
+ ssize_t linelen, /* I - Length of initial line */
+ size_t linesize) /* I - Size of line buffer */
+{
+ char label[256], /* Page label string */
+ *ptr; /* Pointer into line */
+ int level; /* Embedded document level */
+ pstops_page_t *pageinfo; /* Page information */
+ int first_page; /* First page on N-up output? */
+ int has_page_setup = 0; /* Does the page have %%Begin/EndPageSetup? */
+ int bounding_box[4]; /* PageBoundingBox */
+
+
+ /*
+ * Get the page label for this page...
+ */
+
+ first_page = is_first_page(number);
+
+ if (!parse_text(line + 7, &ptr, label, sizeof(label)))
+ {
+ fputs("DEBUG: There was a bad %%Page: comment in the file.\n", stderr);
+ label[0] = '\0';
+ number = doc->page;
+ }
+ else if (strtol(ptr, &ptr, 10) == LONG_MAX || !isspace(*ptr & 255))
+ {
+ fputs("DEBUG: There was a bad %%Page: comment in the file.\n", stderr);
+ number = doc->page;
+ }
+
+ /*
+ * Create or update the current output page...
+ */
+
+ if (first_page)
+ pageinfo = add_page(doc, label);
+ else
+ pageinfo = (pstops_page_t *)cupsArrayLast(doc->pages);
+
+ /*
+ * Handle first page override...
+ */
+
+ if (doc->ap_input_slot || doc->ap_manual_feed)
+ {
+ if (doc->page == 1)
+ {
+ /*
+ * First page/sheet gets AP_FIRSTPAGE_* options...
+ */
+
+ pageinfo->num_options = cupsAddOption("InputSlot", doc->ap_input_slot,
+ pageinfo->num_options,
+ &(pageinfo->options));
+ pageinfo->num_options = cupsAddOption("ManualFeed",
+ doc->ap_input_slot ? "False" :
+ doc->ap_manual_feed,
+ pageinfo->num_options,
+ &(pageinfo->options));
+ pageinfo->num_options = cupsAddOption("MediaColor", doc->ap_media_color,
+ pageinfo->num_options,
+ &(pageinfo->options));
+ pageinfo->num_options = cupsAddOption("MediaType", doc->ap_media_type,
+ pageinfo->num_options,
+ &(pageinfo->options));
+ pageinfo->num_options = cupsAddOption("PageRegion", doc->ap_page_region,
+ pageinfo->num_options,
+ &(pageinfo->options));
+ pageinfo->num_options = cupsAddOption("PageSize", doc->ap_page_size,
+ pageinfo->num_options,
+ &(pageinfo->options));
+ }
+ else if (doc->page == (Duplex + 2))
+ {
+ /*
+ * Second page/sheet gets default options...
+ */
+
+ pageinfo->num_options = cupsAddOption("InputSlot", doc->input_slot,
+ pageinfo->num_options,
+ &(pageinfo->options));
+ pageinfo->num_options = cupsAddOption("ManualFeed",
+ doc->input_slot ? "False" :
+ doc->manual_feed,
+ pageinfo->num_options,
+ &(pageinfo->options));
+ pageinfo->num_options = cupsAddOption("MediaColor", doc->media_color,
+ pageinfo->num_options,
+ &(pageinfo->options));
+ pageinfo->num_options = cupsAddOption("MediaType", doc->media_type,
+ pageinfo->num_options,
+ &(pageinfo->options));
+ pageinfo->num_options = cupsAddOption("PageRegion", doc->page_region,
+ pageinfo->num_options,
+ &(pageinfo->options));
+ pageinfo->num_options = cupsAddOption("PageSize", doc->page_size,
+ pageinfo->num_options,
+ &(pageinfo->options));
+ }
+ }
+
+ /*
+ * Scan comments until we see something other than %%Page*: or
+ * %%Include*...
+ */
+
+ memcpy(bounding_box, doc->bounding_box, sizeof(bounding_box));
+
+ while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0)
+ {
+ if (!strncmp(line, "%%PageBoundingBox:", 18))
+ {
+ /*
+ * %%PageBoundingBox: llx lly urx ury
+ */
+
+ if (sscanf(line + 18, "%d%d%d%d", bounding_box + 0,
+ bounding_box + 1, bounding_box + 2,
+ bounding_box + 3) != 4)
+ {
+ fputs("DEBUG: There was a bad %%PageBoundingBox: comment in the file.\n", stderr);
+ memcpy(bounding_box, doc->bounding_box,
+ sizeof(bounding_box));
+ }
+ else if (doc->number_up == 1 && !doc->fitplot && Orientation)
+ {
+ int temp_bbox[4]; /* Temporary bounding box */
+
+
+ memcpy(temp_bbox, bounding_box, sizeof(temp_bbox));
+
+ fprintf(stderr, "DEBUG: Orientation = %d\n", Orientation);
+ fprintf(stderr, "DEBUG: original bounding_box = [ %d %d %d %d ]\n",
+ bounding_box[0], bounding_box[1],
+ bounding_box[2], bounding_box[3]);
+ fprintf(stderr, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n",
+ PageWidth, PageLength);
+
+ switch (Orientation)
+ {
+ case 1 : /* Landscape */
+ bounding_box[0] = PageLength - temp_bbox[3];
+ bounding_box[1] = temp_bbox[0];
+ bounding_box[2] = PageLength - temp_bbox[1];
+ bounding_box[3] = temp_bbox[2];
+ break;
+
+ case 2 : /* Reverse Portrait */
+ bounding_box[0] = PageWidth - temp_bbox[2];
+ bounding_box[1] = PageLength - temp_bbox[3];
+ bounding_box[2] = PageWidth - temp_bbox[0];
+ bounding_box[3] = PageLength - temp_bbox[1];
+ break;
+
+ case 3 : /* Reverse Landscape */
+ bounding_box[0] = temp_bbox[1];
+ bounding_box[1] = PageWidth - temp_bbox[2];
+ bounding_box[2] = temp_bbox[3];
+ bounding_box[3] = PageWidth - temp_bbox[0];
+ break;
+ }
+
+ fprintf(stderr, "DEBUG: updated bounding_box = [ %d %d %d %d ]\n",
+ bounding_box[0], bounding_box[1],
+ bounding_box[2], bounding_box[3]);
+ }
+ }
+#if 0
+ else if (!strncmp(line, "%%PageCustomColors:", 19) ||
+ !strncmp(line, "%%PageMedia:", 12) ||
+ !strncmp(line, "%%PageOrientation:", 18) ||
+ !strncmp(line, "%%PageProcessColors:", 20) ||
+ !strncmp(line, "%%PageRequirements:", 18) ||
+ !strncmp(line, "%%PageResources:", 16))
+ {
+ /*
+ * Copy literal...
+ */
+ }
+#endif /* 0 */
+ else if (!strncmp(line, "%%PageCustomColors:", 19))
+ {
+ /*
+ * %%PageCustomColors: ...
+ */
+ }
+ else if (!strncmp(line, "%%PageMedia:", 12))
+ {
+ /*
+ * %%PageMedia: ...
+ */
+ }
+ else if (!strncmp(line, "%%PageOrientation:", 18))
+ {
+ /*
+ * %%PageOrientation: ...
+ */
+ }
+ else if (!strncmp(line, "%%PageProcessColors:", 20))
+ {
+ /*
+ * %%PageProcessColors: ...
+ */
+ }
+ else if (!strncmp(line, "%%PageRequirements:", 18))
+ {
+ /*
+ * %%PageRequirements: ...
+ */
+ }
+ else if (!strncmp(line, "%%PageResources:", 16))
+ {
+ /*
+ * %%PageResources: ...
+ */
+ }
+ else if (!strncmp(line, "%%IncludeFeature:", 17))
+ {
+ /*
+ * %%IncludeFeature: *MainKeyword OptionKeyword
+ */
+
+ if (doc->number_up == 1 &&!doc->fitplot)
+ pageinfo->num_options = include_feature(ppd, line,
+ pageinfo->num_options,
+ &(pageinfo->options));
+ }
+ else if (!strncmp(line, "%%BeginPageSetup", 16))
+ {
+ has_page_setup = 1;
+ break;
+ }
+ else
+ break;
+ }
+
+ if (doc->number_up == 1)
+ {
+ /*
+ * Update the document's composite and page bounding box...
+ */
+
+ memcpy(pageinfo->bounding_box, bounding_box,
+ sizeof(pageinfo->bounding_box));
+
+ if (bounding_box[0] < doc->new_bounding_box[0])
+ doc->new_bounding_box[0] = bounding_box[0];
+ if (bounding_box[1] < doc->new_bounding_box[1])
+ doc->new_bounding_box[1] = bounding_box[1];
+ if (bounding_box[2] > doc->new_bounding_box[2])
+ doc->new_bounding_box[2] = bounding_box[2];
+ if (bounding_box[3] > doc->new_bounding_box[3])
+ doc->new_bounding_box[3] = bounding_box[3];
+ }
+
+ /*
+ * Output the page header as needed...
+ */
+
+ if (!doc->slow_order && first_page)
+ {
+ if (!ppd || !ppd->num_filters)
+ fprintf(stderr, "PAGE: %d %d\n", doc->page,
+ doc->slow_collate ? 1 : doc->copies);
+
+ if (doc->number_up > 1)
+ {
+ printf("%%%%Page: (%d) %d\n", doc->page, doc->page);
+ printf("%%%%PageBoundingBox: %.0f %.0f %.0f %.0f\n",
+ PageLeft, PageBottom, PageRight, PageTop);
+ }
+ else
+ {
+ printf("%%%%Page: %s %d\n", pageinfo->label, doc->page);
+ printf("%%%%PageBoundingBox: %d %d %d %d\n",
+ pageinfo->bounding_box[0], pageinfo->bounding_box[1],
+ pageinfo->bounding_box[2], pageinfo->bounding_box[3]);
+ }
+ }
+
+ /*
+ * Copy any page setup commands...
+ */
+
+ if (first_page)
+ doc_puts(doc, "%%BeginPageSetup\n");
+
+ if (has_page_setup)
+ {
+ int feature = 0; /* In a Begin/EndFeature block? */
+
+ while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0)
+ {
+ if (!strncmp(line, "%%EndPageSetup", 14))
+ break;
+ else if (!strncmp(line, "%%BeginFeature:", 15))
+ {
+ feature = 1;
+
+ if (doc->number_up > 1 || doc->fitplot)
+ continue;
+ }
+ else if (!strncmp(line, "%%EndFeature", 12))
+ {
+ feature = 0;
+
+ if (doc->number_up > 1 || doc->fitplot)
+ continue;
+ }
+ else if (!strncmp(line, "%%IncludeFeature:", 17))
+ {
+ pageinfo->num_options = include_feature(ppd, line,
+ pageinfo->num_options,
+ &(pageinfo->options));
+ continue;
+ }
+ else if (!strncmp(line, "%%Include", 9))
+ continue;
+
+ if (line[0] != '%' && !feature)
+ break;
+
+ if (!feature || (doc->number_up == 1 && !doc->fitplot))
+ doc_write(doc, line, linelen);
+ }
+
+ /*
+ * Skip %%EndPageSetup...
+ */
+
+ if (linelen > 0 && !strncmp(line, "%%EndPageSetup", 14))
+ {
+ linelen = cupsFileGetLine(fp, line, linesize);
+ has_page_setup = 0;
+ }
+ }
+
+ if (first_page)
+ {
+ char *page_setup; /* PageSetup commands to send */
+
+
+ if (pageinfo->num_options > 0)
+ write_options(doc, ppd, pageinfo->num_options, pageinfo->options);
+
+ /*
+ * Output commands for the current page...
+ */
+
+ page_setup = ppdEmitString(ppd, PPD_ORDER_PAGE, 0);
+
+ if (page_setup)
+ {
+ doc_puts(doc, page_setup);
+ free(page_setup);
+ }
+ }
+
+ /*
+ * Prep for the start of the page description...
+ */
+
+ start_nup(doc, number, 1, bounding_box);
+
+ if (first_page)
+ doc_puts(doc, "%%EndPageSetup\n");
+
+ /*
+ * Read the rest of the page description...
+ */
+
+ level = 0;
+
+ do
+ {
+ if (level == 0 &&
+ (!strncmp(line, "%%Page:", 7) ||
+ !strncmp(line, "%%Trailer", 9) ||
+ !strncmp(line, "%%EOF", 5)))
+ break;
+ else if (!strncmp(line, "%%BeginDocument", 15) ||
+ !strncmp(line, "%ADO_BeginApplication", 21))
+ {
+ doc_write(doc, line, linelen);
+
+ level ++;
+ }
+ else if ((!strncmp(line, "%%EndDocument", 13) ||
+ !strncmp(line, "%ADO_EndApplication", 19)) && level > 0)
+ {
+ doc_write(doc, line, linelen);
+
+ level --;
+ }
+ else if (!strncmp(line, "%%BeginBinary:", 14) ||
+ (!strncmp(line, "%%BeginData:", 12) &&
+ !strstr(line, "ASCII") && !strstr(line, "Hex")))
+ {
+ /*
+ * Copy binary data...
+ */
+
+ int bytes; /* Bytes of data */
+
+
+ doc_write(doc, line, linelen);
+
+ bytes = atoi(strchr(line, ':') + 1);
+
+ while (bytes > 0)
+ {
+ if (bytes > linesize)
+ linelen = cupsFileRead(fp, line, linesize);
+ else
+ linelen = cupsFileRead(fp, line, bytes);
+
+ if (linelen < 1)
+ {
+ line[0] = '\0';
+ perror("ERROR: Early end-of-file while reading binary data");
+ return (0);
+ }
+
+ doc_write(doc, line, linelen);
+
+ bytes -= linelen;
+ }
+ }
+ else
+ doc_write(doc, line, linelen);
+ }
+ while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0);
+
+ /*
+ * Finish up this page and return...
+ */
+
+ end_nup(doc, number);
+
+ pageinfo->length = cupsFileTell(doc->temp) - pageinfo->offset;
+
+ return (linelen);
+}
+
+
+/*
+ * 'copy_prolog()' - Copy the document prolog section.
+ *
+ * This function expects "line" to be filled with a %%BeginProlog comment line.
+ * On return, "line" will contain the next line in the file, if any.
+ */
+
+static ssize_t /* O - Length of next line */
+copy_prolog(cups_file_t *fp, /* I - File to read from */
+ pstops_doc_t *doc, /* I - Document info */
+ ppd_file_t *ppd, /* I - PPD file */
+ char *line, /* I - Line buffer */
+ ssize_t linelen, /* I - Length of initial line */
+ size_t linesize) /* I - Size of line buffer */
+{
+ while (strncmp(line, "%%BeginProlog", 13))
+ {
+ if (!strncmp(line, "%%BeginSetup", 12) || !strncmp(line, "%%Page:", 7))
+ break;
+
+ doc_write(doc, line, linelen);
+
+ if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0)
+ break;
+ }
+
+ doc_puts(doc, "%%BeginProlog\n");
+
+ do_prolog(doc, ppd);
+
+ if (!strncmp(line, "%%BeginProlog", 13))
+ {
+ while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0)
+ {
+ if (!strncmp(line, "%%EndProlog", 11) ||
+ !strncmp(line, "%%BeginSetup", 12) ||
+ !strncmp(line, "%%Page:", 7))
+ break;
+
+ doc_write(doc, line, linelen);
+ }
+
+ if (!strncmp(line, "%%EndProlog", 11))
+ linelen = cupsFileGetLine(fp, line, linesize);
+ else
+ fputs("DEBUG: The %%EndProlog comment is missing.\n", stderr);
+ }
+
+ doc_puts(doc, "%%EndProlog\n");
+
+ return (linelen);
+}
+
+
+/*
+ * 'copy_setup()' - Copy the document setup section.
+ *
+ * This function expects "line" to be filled with a %%BeginSetup comment line.
+ * On return, "line" will contain the next line in the file, if any.
+ */
+
+static ssize_t /* O - Length of next line */
+copy_setup(cups_file_t *fp, /* I - File to read from */
+ pstops_doc_t *doc, /* I - Document info */
+ ppd_file_t *ppd, /* I - PPD file */
+ char *line, /* I - Line buffer */
+ ssize_t linelen, /* I - Length of initial line */
+ size_t linesize) /* I - Size of line buffer */
+{
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+
+
+ while (strncmp(line, "%%BeginSetup", 12))
+ {
+ if (!strncmp(line, "%%Page:", 7))
+ break;
+
+ doc_write(doc, line, linelen);
+
+ if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0)
+ break;
+ }
+
+ doc_puts(doc, "%%BeginSetup\n");
+
+ do_setup(doc, ppd);
+
+ num_options = 0;
+ options = NULL;
+
+ if (!strncmp(line, "%%BeginSetup", 12))
+ {
+ while (strncmp(line, "%%EndSetup", 10))
+ {
+ if (!strncmp(line, "%%Page:", 7))
+ break;
+ else if (!strncmp(line, "%%IncludeFeature:", 17))
+ {
+ /*
+ * %%IncludeFeature: *MainKeyword OptionKeyword
+ */
+
+ if (doc->number_up == 1 && !doc->fitplot)
+ num_options = include_feature(ppd, line, num_options, &options);
+ }
+ else if (strncmp(line, "%%BeginSetup", 12))
+ doc_write(doc, line, linelen);
+
+ if ((linelen = cupsFileGetLine(fp, line, linesize)) == 0)
+ break;
+ }
+
+ if (!strncmp(line, "%%EndSetup", 10))
+ linelen = cupsFileGetLine(fp, line, linesize);
+ else
+ fputs("DEBUG: The %%EndSetup comment is missing.\n", stderr);
+ }
+
+ if (num_options > 0)
+ {
+ write_options(doc, ppd, num_options, options);
+ cupsFreeOptions(num_options, options);
+ }
+
+ doc_puts(doc, "%%EndSetup\n");
+
+ return (linelen);
+}
+
+
+/*
+ * 'copy_trailer()' - Copy the document trailer.
+ *
+ * This function expects "line" to be filled with a %%Trailer comment line.
+ * On return, "line" will contain the next line in the file, if any.
+ */
+
+static ssize_t /* O - Length of next line */
+copy_trailer(cups_file_t *fp, /* I - File to read from */
+ pstops_doc_t *doc, /* I - Document info */
+ ppd_file_t *ppd, /* I - PPD file */
+ int number, /* I - Number of pages */
+ char *line, /* I - Line buffer */
+ ssize_t linelen, /* I - Length of initial line */
+ size_t linesize) /* I - Size of line buffer */
+{
+ /*
+ * Write the trailer comments...
+ */
+
+ puts("%%Trailer");
+
+ while (linelen > 0)
+ {
+ if (!strncmp(line, "%%EOF", 5))
+ break;
+ else if (strncmp(line, "%%Trailer", 9) &&
+ strncmp(line, "%%Pages:", 8) &&
+ strncmp(line, "%%BoundingBox:", 14))
+ fwrite(line, 1, linelen, stdout);
+
+ linelen = cupsFileGetLine(fp, line, linesize);
+ }
+
+ fprintf(stderr, "DEBUG: Wrote %d pages...\n", number);
+
+ printf("%%%%Pages: %d\n", number);
+ if (doc->number_up > 1 || doc->fitplot)
+ printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
+ PageLeft, PageBottom, PageRight, PageTop);
+ else
+ printf("%%%%BoundingBox: %d %d %d %d\n",
+ doc->new_bounding_box[0], doc->new_bounding_box[1],
+ doc->new_bounding_box[2], doc->new_bounding_box[3]);
+
+ return (linelen);
+}
+
+
+/*
+ * 'do_prolog()' - Send the necessary document prolog commands.
+ */
+
+static void
+do_prolog(pstops_doc_t *doc, /* I - Document information */
+ ppd_file_t *ppd) /* I - PPD file */
+{
+ char *ps; /* PS commands */
+
+
+ /*
+ * Send the document prolog commands...
+ */
+
+ if (ppd && ppd->patches)
+ {
+ doc_puts(doc, "%%BeginFeature: *JobPatchFile 1\n");
+ doc_puts(doc, ppd->patches);
+ doc_puts(doc, "\n%%EndFeature\n");
+ }
+
+ if ((ps = ppdEmitString(ppd, PPD_ORDER_PROLOG, 0.0)) != NULL)
+ {
+ doc_puts(doc, ps);
+ free(ps);
+ }
+
+ /*
+ * Define ESPshowpage here so that applications that define their
+ * own procedure to do a showpage pick it up...
+ */
+
+ if (doc->use_ESPshowpage)
+ doc_puts(doc, "userdict/ESPshowpage/showpage load put\n"
+ "userdict/showpage{}put\n");
+}
+
+
+/*
+ * 'do_setup()' - Send the necessary document setup commands.
+ */
+
+static void
+do_setup(pstops_doc_t *doc, /* I - Document information */
+ ppd_file_t *ppd) /* I - PPD file */
+{
+ char *ps; /* PS commands */
+
+
+ /*
+ * Disable CTRL-D so that embedded files don't cause printing
+ * errors...
+ */
+
+ doc_puts(doc, "% Disable CTRL-D as an end-of-file marker...\n");
+ doc_puts(doc, "userdict dup(\\004)cvn{}put (\\004\\004)cvn{}put\n");
+
+ /*
+ * Mark job options...
+ */
+
+ cupsMarkOptions(ppd, doc->num_options, doc->options);
+
+ /*
+ * Send all the printer-specific setup commands...
+ */
+
+ if ((ps = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, 0.0)) != NULL)
+ {
+ doc_puts(doc, ps);
+ free(ps);
+ }
+
+ if ((ps = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL)
+ {
+ doc_puts(doc, ps);
+ free(ps);
+ }
+
+ /*
+ * Set the number of copies for the job...
+ */
+
+ if (doc->copies != 1 && (!doc->collate || !doc->slow_collate))
+ {
+ doc_printf(doc, "%%RBIBeginNonPPDFeature: *NumCopies %d\n", doc->copies);
+ doc_printf(doc,
+ "%d/languagelevel where{pop languagelevel 2 ge}{false}ifelse\n"
+ "{1 dict begin/NumCopies exch def currentdict end "
+ "setpagedevice}\n"
+ "{userdict/#copies 3 -1 roll put}ifelse\n", doc->copies);
+ doc_puts(doc, "%RBIEndNonPPDFeature\n");
+ }
+
+ /*
+ * If we are doing N-up printing, disable setpagedevice...
+ */
+
+ if (doc->number_up > 1)
+ {
+ doc_puts(doc, "userdict/CUPSsetpagedevice/setpagedevice load put\n");
+ doc_puts(doc, "userdict/setpagedevice{pop}bind put\n");
+ }
+
+ /*
+ * Changes to the transfer function must be made AFTER any
+ * setpagedevice code...
+ */
+
+ if (doc->gamma != 1.0f || doc->brightness != 1.0f)
+ doc_printf(doc, "{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
+ "ifelse %.3f mul } bind settransfer\n",
+ doc->gamma, doc->brightness);
+
+ /*
+ * Make sure we have rectclip and rectstroke procedures of some sort...
+ */
+
+ doc_puts(doc,
+ "% x y w h ESPrc - Clip to a rectangle.\n"
+ "userdict/ESPrc/rectclip where{pop/rectclip load}\n"
+ "{{newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
+ "neg 0 rlineto closepath clip newpath}bind}ifelse put\n");
+
+ doc_puts(doc,
+ "% x y w h ESPrf - Fill a rectangle.\n"
+ "userdict/ESPrf/rectfill where{pop/rectfill load}\n"
+ "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
+ "neg 0 rlineto closepath fill grestore}bind}ifelse put\n");
+
+ doc_puts(doc,
+ "% x y w h ESPrs - Stroke a rectangle.\n"
+ "userdict/ESPrs/rectstroke where{pop/rectstroke load}\n"
+ "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n"
+ "neg 0 rlineto closepath stroke grestore}bind}ifelse put\n");
+
+ /*
+ * Write the page and label prologs...
+ */
+
+ if (doc->number_up == 2 || doc->number_up == 6)
+ {
+ /*
+ * For 2- and 6-up output, rotate the labels to match the orientation
+ * of the pages...
+ */
+
+ if (Orientation & 1)
+ write_label_prolog(doc, doc->page_label, PageBottom,
+ PageWidth - PageLength + PageTop, PageLength);
+ else
+ write_label_prolog(doc, doc->page_label, PageLeft, PageRight,
+ PageLength);
+ }
+ else
+ write_label_prolog(doc, doc->page_label, PageBottom, PageTop, PageWidth);
+}
+
+
+/*
+ * 'doc_printf()' - Send a formatted string to stdout and/or the temp file.
+ *
+ * This function should be used for all page-level output that is affected
+ * by ordering, collation, etc.
+ */
+
+static void
+doc_printf(pstops_doc_t *doc, /* I - Document information */
+ const char *format, /* I - Printf-style format string */
+ ...) /* I - Additional arguments as needed */
+{
+ va_list ap; /* Pointer to arguments */
+ char buffer[1024]; /* Output buffer */
+ size_t bytes; /* Number of bytes to write */
+
+
+ va_start(ap, format);
+ bytes = vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+
+ if (bytes > sizeof(buffer))
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Buffer overflow detected, aborting."));
+ exit(1);
+ }
+
+ doc_write(doc, buffer, bytes);
+}
+
+
+/*
+ * 'doc_puts()' - Send a nul-terminated string to stdout and/or the temp file.
+ *
+ * This function should be used for all page-level output that is affected
+ * by ordering, collation, etc.
+ */
+
+static void
+doc_puts(pstops_doc_t *doc, /* I - Document information */
+ const char *s) /* I - String to send */
+{
+ doc_write(doc, s, strlen(s));
+}
+
+
+/*
+ * 'doc_write()' - Send data to stdout and/or the temp file.
+ */
+
+static void
+doc_write(pstops_doc_t *doc, /* I - Document information */
+ const char *s, /* I - Data to send */
+ size_t len) /* I - Number of bytes to send */
+{
+ if (!doc->slow_order)
+ fwrite(s, 1, len, stdout);
+
+ if (doc->temp)
+ cupsFileWrite(doc->temp, s, len);
+}
+
+
+/*
+ * 'end_nup()' - End processing for N-up printing.
+ */
+
+static void
+end_nup(pstops_doc_t *doc, /* I - Document information */
+ int number) /* I - Page number */
+{
+ if (doc->number_up > 1)
+ doc_puts(doc, "userdict/ESPsave get restore\n");
+
+ switch (doc->number_up)
+ {
+ case 1 :
+ if (doc->use_ESPshowpage)
+ {
+ write_labels(doc, Orientation);
+ doc_puts(doc, "ESPshowpage\n");
+ }
+ break;
+
+ case 2 :
+ case 6 :
+ if (is_last_page(number) && doc->use_ESPshowpage)
+ {
+ if (Orientation & 1)
+ {
+ /*
+ * Rotate the labels back to portrait...
+ */
+
+ write_labels(doc, Orientation - 1);
+ }
+ else if (Orientation == 0)
+ {
+ /*
+ * Rotate the labels to landscape...
+ */
+
+ write_labels(doc, doc->normal_landscape ? 1 : 3);
+ }
+ else
+ {
+ /*
+ * Rotate the labels to landscape...
+ */
+
+ write_labels(doc, doc->normal_landscape ? 3 : 1);
+ }
+
+ doc_puts(doc, "ESPshowpage\n");
+ }
+ break;
+
+ default :
+ if (is_last_page(number) && doc->use_ESPshowpage)
+ {
+ write_labels(doc, Orientation);
+ doc_puts(doc, "ESPshowpage\n");
+ }
+ break;
+ }
+
+ fflush(stdout);
+}
+
+
+/*
+ * 'include_feature()' - Include a printer option/feature command.
+ */
+
+static int /* O - New number of options */
+include_feature(
+ ppd_file_t *ppd, /* I - PPD file */
+ const char *line, /* I - DSC line */
+ int num_options, /* I - Number of options */
+ cups_option_t **options) /* IO - Options */
+{
+ char name[255], /* Option name */
+ value[255]; /* Option value */
+ ppd_option_t *option; /* Option in file */
+
+
+ /*
+ * Get the "%%IncludeFeature: *Keyword OptionKeyword" values...
+ */
+
+ if (sscanf(line + 17, "%254s%254s", name, value) != 2)
+ {
+ fputs("DEBUG: The %%IncludeFeature: comment is not valid.\n", stderr);
+ return (num_options);
+ }
+
+ /*
+ * Find the option and choice...
+ */
+
+ if ((option = ppdFindOption(ppd, name + 1)) == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "WARNING", _("Unknown option \"%s\"."),
+ name + 1);
+ return (num_options);
+ }
+
+ if (option->section == PPD_ORDER_EXIT ||
+ option->section == PPD_ORDER_JCL)
+ {
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("Option \"%s\" cannot be included via "
+ "%%%%IncludeFeature."), name + 1);
+ return (num_options);
+ }
+
+ if (!ppdFindChoice(option, value))
+ {
+ _cupsLangPrintFilter(stderr, "WARNING",
+ _("Unknown choice \"%s\" for option \"%s\"."),
+ value, name + 1);
+ return (num_options);
+ }
+
+ /*
+ * Add the option to the option array and return...
+ */
+
+ return (cupsAddOption(name + 1, value, num_options, options));
+}
+
+
+/*
+ * 'parse_text()' - Parse a text value in a comment.
+ *
+ * This function parses a DSC text value as defined on page 36 of the
+ * DSC specification. Text values are either surrounded by parenthesis
+ * or whitespace-delimited.
+ *
+ * The value returned is the literal characters for the entire text
+ * string, including any parenthesis and escape characters.
+ */
+
+static char * /* O - Value or NULL on error */
+parse_text(const char *start, /* I - Start of text value */
+ char **end, /* O - End of text value */
+ char *buffer, /* I - Buffer */
+ size_t bufsize) /* I - Size of buffer */
+{
+ char *bufptr, /* Pointer in buffer */
+ *bufend; /* End of buffer */
+ int level; /* Parenthesis level */
+
+
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (isspace(*start & 255))
+ start ++;
+
+ /*
+ * Then copy the value...
+ */
+
+ level = 0;
+ bufptr = buffer;
+ bufend = buffer + bufsize - 1;
+
+ while (bufptr < bufend)
+ {
+ if (isspace(*start & 255) && !level)
+ break;
+
+ *bufptr++ = *start;
+
+ if (*start == '(')
+ level ++;
+ else if (*start == ')')
+ {
+ if (!level)
+ {
+ start ++;
+ break;
+ }
+ else
+ level --;
+ }
+ else if (*start == '\\')
+ {
+ /*
+ * Copy escaped character...
+ */
+
+ int i; /* Looping var */
+
+
+ for (i = 1;
+ i <= 3 && isdigit(start[i] & 255) && bufptr < bufend;
+ *bufptr++ = start[i], i ++);
+ }
+
+ start ++;
+ }
+
+ *bufptr = '\0';
+
+ /*
+ * Return the value and new pointer into the line...
+ */
+
+ if (end)
+ *end = (char *)start;
+
+ if (bufptr == bufend)
+ return (NULL);
+ else
+ return (buffer);
+}
+
+
+/*
+ * 'set_pstops_options()' - Set pstops options.
+ */
+
+static void
+set_pstops_options(
+ pstops_doc_t *doc, /* I - Document information */
+ ppd_file_t *ppd, /* I - PPD file */
+ char *argv[], /* I - Command-line arguments */
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ const char *val; /* Option value */
+ int intval; /* Integer option value */
+ ppd_attr_t *attr; /* PPD attribute */
+ ppd_option_t *option; /* PPD option */
+ ppd_choice_t *choice; /* PPD choice */
+ const char *content_type; /* Original content type */
+
+
+ /*
+ * Initialize document information structure...
+ */
+
+ memset(doc, 0, sizeof(pstops_doc_t));
+
+ doc->job_id = atoi(argv[1]);
+ doc->user = argv[2];
+ doc->title = argv[3];
+ doc->copies = atoi(argv[4]);
+
+ if (ppd && ppd->landscape > 0)
+ doc->normal_landscape = 1;
+
+ doc->bounding_box[0] = (int)PageLeft;
+ doc->bounding_box[1] = (int)PageBottom;
+ doc->bounding_box[2] = (int)PageRight;
+ doc->bounding_box[3] = (int)PageTop;
+
+ doc->new_bounding_box[0] = INT_MAX;
+ doc->new_bounding_box[1] = INT_MAX;
+ doc->new_bounding_box[2] = INT_MIN;
+ doc->new_bounding_box[3] = INT_MIN;
+
+ /*
+ * AP_FIRSTPAGE_* and the corresponding non-first-page options.
+ */
+
+ doc->ap_input_slot = cupsGetOption("AP_FIRSTPAGE_InputSlot", num_options,
+ options);
+ doc->ap_manual_feed = cupsGetOption("AP_FIRSTPAGE_ManualFeed", num_options,
+ options);
+ doc->ap_media_color = cupsGetOption("AP_FIRSTPAGE_MediaColor", num_options,
+ options);
+ doc->ap_media_type = cupsGetOption("AP_FIRSTPAGE_MediaType", num_options,
+ options);
+ doc->ap_page_region = cupsGetOption("AP_FIRSTPAGE_PageRegion", num_options,
+ options);
+ doc->ap_page_size = cupsGetOption("AP_FIRSTPAGE_PageSize", num_options,
+ options);
+
+ if ((choice = ppdFindMarkedChoice(ppd, "InputSlot")) != NULL)
+ doc->input_slot = choice->choice;
+ if ((choice = ppdFindMarkedChoice(ppd, "ManualFeed")) != NULL)
+ doc->manual_feed = choice->choice;
+ if ((choice = ppdFindMarkedChoice(ppd, "MediaColor")) != NULL)
+ doc->media_color = choice->choice;
+ if ((choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL)
+ doc->media_type = choice->choice;
+ if ((choice = ppdFindMarkedChoice(ppd, "PageRegion")) != NULL)
+ doc->page_region = choice->choice;
+ if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL)
+ doc->page_size = choice->choice;
+
+ /*
+ * brightness
+ */
+
+ if ((val = cupsGetOption("brightness", num_options, options)) != NULL)
+ {
+ /*
+ * Get brightness value from 10 to 1000.
+ */
+
+ intval = atoi(val);
+
+ if (intval < 10 || intval > 1000)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unsupported brightness value %s, using "
+ "brightness=100."), val);
+ doc->brightness = 1.0f;
+ }
+ else
+ doc->brightness = intval * 0.01f;
+ }
+ else
+ doc->brightness = 1.0f;
+
+ /*
+ * collate, multiple-document-handling
+ */
+
+ if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
+ {
+ /*
+ * This IPP attribute is unnecessarily complicated...
+ *
+ * single-document, separate-documents-collated-copies, and
+ * single-document-new-sheet all require collated copies.
+ *
+ * separate-documents-uncollated-copies allows for uncollated copies.
+ */
+
+ doc->collate = _cups_strcasecmp(val, "separate-documents-uncollated-copies") != 0;
+ }
+
+ if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
+ (!_cups_strcasecmp(val, "true") ||!_cups_strcasecmp(val, "on") ||
+ !_cups_strcasecmp(val, "yes")))
+ doc->collate = 1;
+
+ /*
+ * emit-jcl
+ */
+
+ if ((val = cupsGetOption("emit-jcl", num_options, options)) != NULL &&
+ (!_cups_strcasecmp(val, "false") || !_cups_strcasecmp(val, "off") ||
+ !_cups_strcasecmp(val, "no") || !strcmp(val, "0")))
+ doc->emit_jcl = 0;
+ else
+ doc->emit_jcl = 1;
+
+ /*
+ * fitplot/fit-to-page/ipp-attribute-fidelity
+ *
+ * (Only for original PostScript content)
+ */
+
+ if ((content_type = getenv("CONTENT_TYPE")) == NULL)
+ content_type = "application/postscript";
+
+ if (!_cups_strcasecmp(content_type, "application/postscript"))
+ {
+ if ((val = cupsGetOption("fitplot", num_options, options)) != NULL &&
+ !_cups_strcasecmp(val, "true"))
+ doc->fitplot = 1;
+ else if ((val = cupsGetOption("fit-to-page", num_options, options)) != NULL &&
+ !_cups_strcasecmp(val, "true"))
+ doc->fitplot = 1;
+ else if ((val = cupsGetOption("ipp-attribute-fidelity", num_options,
+ options)) != NULL &&
+ !_cups_strcasecmp(val, "true"))
+ doc->fitplot = 1;
+ }
+
+ /*
+ * gamma
+ */
+
+ if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
+ {
+ /*
+ * Get gamma value from 1 to 10000...
+ */
+
+ intval = atoi(val);
+
+ if (intval < 1 || intval > 10000)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unsupported gamma value %s, using gamma=1000."),
+ val);
+ doc->gamma = 1.0f;
+ }
+ else
+ doc->gamma = intval * 0.001f;
+ }
+ else
+ doc->gamma = 1.0f;
+
+ /*
+ * mirror/MirrorPrint
+ */
+
+ if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL)
+ {
+ val = choice->choice;
+ choice->marked = 0;
+ }
+ else
+ val = cupsGetOption("mirror", num_options, options);
+
+ if (val && (!_cups_strcasecmp(val, "true") || !_cups_strcasecmp(val, "on") ||
+ !_cups_strcasecmp(val, "yes")))
+ doc->mirror = 1;
+
+ /*
+ * number-up
+ */
+
+ if ((val = cupsGetOption("number-up", num_options, options)) != NULL)
+ {
+ switch (intval = atoi(val))
+ {
+ case 1 :
+ case 2 :
+ case 4 :
+ case 6 :
+ case 9 :
+ case 16 :
+ doc->number_up = intval;
+ break;
+ default :
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unsupported number-up value %d, using "
+ "number-up=1."), intval);
+ doc->number_up = 1;
+ break;
+ }
+ }
+ else
+ doc->number_up = 1;
+
+ /*
+ * number-up-layout
+ */
+
+ if ((val = cupsGetOption("number-up-layout", num_options, options)) != NULL)
+ {
+ if (!_cups_strcasecmp(val, "lrtb"))
+ doc->number_up_layout = PSTOPS_LAYOUT_LRTB;
+ else if (!_cups_strcasecmp(val, "lrbt"))
+ doc->number_up_layout = PSTOPS_LAYOUT_LRBT;
+ else if (!_cups_strcasecmp(val, "rltb"))
+ doc->number_up_layout = PSTOPS_LAYOUT_RLTB;
+ else if (!_cups_strcasecmp(val, "rlbt"))
+ doc->number_up_layout = PSTOPS_LAYOUT_RLBT;
+ else if (!_cups_strcasecmp(val, "tblr"))
+ doc->number_up_layout = PSTOPS_LAYOUT_TBLR;
+ else if (!_cups_strcasecmp(val, "tbrl"))
+ doc->number_up_layout = PSTOPS_LAYOUT_TBRL;
+ else if (!_cups_strcasecmp(val, "btlr"))
+ doc->number_up_layout = PSTOPS_LAYOUT_BTLR;
+ else if (!_cups_strcasecmp(val, "btrl"))
+ doc->number_up_layout = PSTOPS_LAYOUT_BTRL;
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unsupported number-up-layout value %s, using "
+ "number-up-layout=lrtb."), val);
+ doc->number_up_layout = PSTOPS_LAYOUT_LRTB;
+ }
+ }
+ else
+ doc->number_up_layout = PSTOPS_LAYOUT_LRTB;
+
+ /*
+ * OutputOrder
+ */
+
+ if ((val = cupsGetOption("OutputOrder", num_options, options)) != NULL)
+ {
+ if (!_cups_strcasecmp(val, "Reverse"))
+ doc->output_order = 1;
+ }
+ else if (ppd)
+ {
+ /*
+ * Figure out the right default output order from the PPD file...
+ */
+
+ if ((choice = ppdFindMarkedChoice(ppd, "OutputBin")) != NULL &&
+ (attr = ppdFindAttr(ppd, "PageStackOrder", choice->choice)) != NULL &&
+ attr->value)
+ doc->output_order = !_cups_strcasecmp(attr->value, "Reverse");
+ else if ((attr = ppdFindAttr(ppd, "DefaultOutputOrder", NULL)) != NULL &&
+ attr->value)
+ doc->output_order = !_cups_strcasecmp(attr->value, "Reverse");
+ }
+
+ /*
+ * page-border
+ */
+
+ if ((val = cupsGetOption("page-border", num_options, options)) != NULL)
+ {
+ if (!_cups_strcasecmp(val, "none"))
+ doc->page_border = PSTOPS_BORDERNONE;
+ else if (!_cups_strcasecmp(val, "single"))
+ doc->page_border = PSTOPS_BORDERSINGLE;
+ else if (!_cups_strcasecmp(val, "single-thick"))
+ doc->page_border = PSTOPS_BORDERSINGLE2;
+ else if (!_cups_strcasecmp(val, "double"))
+ doc->page_border = PSTOPS_BORDERDOUBLE;
+ else if (!_cups_strcasecmp(val, "double-thick"))
+ doc->page_border = PSTOPS_BORDERDOUBLE2;
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unsupported page-border value %s, using "
+ "page-border=none."), val);
+ doc->page_border = PSTOPS_BORDERNONE;
+ }
+ }
+ else
+ doc->page_border = PSTOPS_BORDERNONE;
+
+ /*
+ * page-label
+ */
+
+ doc->page_label = cupsGetOption("page-label", num_options, options);
+
+ /*
+ * page-ranges
+ */
+
+ doc->page_ranges = cupsGetOption("page-ranges", num_options, options);
+
+ /*
+ * page-set
+ */
+
+ doc->page_set = cupsGetOption("page-set", num_options, options);
+
+ /*
+ * Now figure out if we have to force collated copies, etc.
+ */
+
+ if (ppd && ppd->manual_copies && Duplex && doc->copies > 1)
+ {
+ /*
+ * Force collated copies when printing a duplexed document to
+ * a non-PS printer that doesn't do hardware copy generation.
+ * Otherwise the copies will end up on the front/back side of
+ * each page.
+ */
+
+ doc->collate = 1;
+ }
+
+ /*
+ * See if we have to filter the fast or slow way...
+ */
+
+ if (doc->collate && doc->copies > 1)
+ {
+ /*
+ * See if we need to manually collate the pages...
+ */
+
+ doc->slow_collate = 1;
+
+ if ((choice = ppdFindMarkedChoice(ppd, "Collate")) != NULL &&
+ !_cups_strcasecmp(choice->choice, "True"))
+ {
+ /*
+ * Hardware collate option is selected, see if the option is
+ * conflicting - if not, collate in hardware. Otherwise,
+ * turn the hardware collate option off...
+ */
+
+ if ((option = ppdFindOption(ppd, "Collate")) != NULL &&
+ !option->conflicted)
+ doc->slow_collate = 0;
+ else
+ ppdMarkOption(ppd, "Collate", "False");
+ }
+ }
+ else
+ doc->slow_collate = 0;
+
+ if (!ppdFindOption(ppd, "OutputOrder") && doc->output_order)
+ doc->slow_order = 1;
+ else
+ doc->slow_order = 0;
+
+ if (Duplex &&
+ (doc->slow_collate || doc->slow_order ||
+ ((attr = ppdFindAttr(ppd, "cupsEvenDuplex", NULL)) != NULL &&
+ attr->value && !_cups_strcasecmp(attr->value, "true"))))
+ doc->slow_duplex = 1;
+ else
+ doc->slow_duplex = 0;
+
+ /*
+ * Create a temporary file for page data if we need to filter slowly...
+ */
+
+ if (doc->slow_order || doc->slow_collate)
+ {
+ if ((doc->temp = cupsTempFile2(doc->tempfile,
+ sizeof(doc->tempfile))) == NULL)
+ {
+ perror("DEBUG: Unable to create temporary file");
+ exit(1);
+ }
+ }
+
+ /*
+ * Figure out if we should use ESPshowpage or not...
+ */
+
+ if (doc->page_label || getenv("CLASSIFICATION") || doc->number_up > 1 ||
+ doc->page_border)
+ {
+ /*
+ * Yes, use ESPshowpage...
+ */
+
+ doc->use_ESPshowpage = 1;
+ }
+
+ fprintf(stderr, "DEBUG: slow_collate=%d, slow_duplex=%d, slow_order=%d\n",
+ doc->slow_collate, doc->slow_duplex, doc->slow_order);
+}
+
+
+/*
+ * 'skip_page()' - Skip past a page that won't be printed.
+ */
+
+static ssize_t /* O - Length of next line */
+skip_page(cups_file_t *fp, /* I - File to read from */
+ char *line, /* I - Line buffer */
+ ssize_t linelen, /* I - Length of initial line */
+ size_t linesize) /* I - Size of line buffer */
+{
+ int level; /* Embedded document level */
+
+
+ level = 0;
+
+ while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0)
+ {
+ if (level == 0 &&
+ (!strncmp(line, "%%Page:", 7) || !strncmp(line, "%%Trailer", 9)))
+ break;
+ else if (!strncmp(line, "%%BeginDocument", 15) ||
+ !strncmp(line, "%ADO_BeginApplication", 21))
+ level ++;
+ else if ((!strncmp(line, "%%EndDocument", 13) ||
+ !strncmp(line, "%ADO_EndApplication", 19)) && level > 0)
+ level --;
+ else if (!strncmp(line, "%%BeginBinary:", 14) ||
+ (!strncmp(line, "%%BeginData:", 12) &&
+ !strstr(line, "ASCII") && !strstr(line, "Hex")))
+ {
+ /*
+ * Skip binary data...
+ */
+
+ int bytes; /* Bytes of data */
+
+
+ bytes = atoi(strchr(line, ':') + 1);
+
+ while (bytes > 0)
+ {
+ if (bytes > linesize)
+ linelen = cupsFileRead(fp, line, linesize);
+ else
+ linelen = cupsFileRead(fp, line, bytes);
+
+ if (linelen < 1)
+ {
+ line[0] = '\0';
+ perror("ERROR: Early end-of-file while reading binary data");
+ return (0);
+ }
+
+ bytes -= linelen;
+ }
+ }
+ }
+
+ return (linelen);
+}
+
+
+/*
+ * 'start_nup()' - Start processing for N-up printing.
+ */
+
+static void
+start_nup(pstops_doc_t *doc, /* I - Document information */
+ int number, /* I - Page number */
+ int show_border, /* I - Show the border? */
+ const int *bounding_box) /* I - BoundingBox value */
+{
+ int pos; /* Position on page */
+ int x, y; /* Relative position of subpage */
+ float w, l, /* Width and length of subpage */
+ tx, ty; /* Translation values for subpage */
+ float pagew, /* Printable width of page */
+ pagel; /* Printable height of page */
+ int bboxx, /* BoundingBox X origin */
+ bboxy, /* BoundingBox Y origin */
+ bboxw, /* BoundingBox width */
+ bboxl; /* BoundingBox height */
+ float margin = 0; /* Current margin for border */
+
+
+ if (doc->number_up > 1)
+ doc_puts(doc, "userdict/ESPsave save put\n");
+
+ pos = (number - 1) % doc->number_up;
+ pagew = PageRight - PageLeft;
+ pagel = PageTop - PageBottom;
+
+ if (doc->fitplot)
+ {
+ bboxx = bounding_box[0];
+ bboxy = bounding_box[1];
+ bboxw = bounding_box[2] - bounding_box[0];
+ bboxl = bounding_box[3] - bounding_box[1];
+ }
+ else
+ {
+ bboxx = 0;
+ bboxy = 0;
+ bboxw = PageWidth;
+ bboxl = PageLength;
+ }
+
+ fprintf(stderr, "DEBUG: pagew = %.1f, pagel = %.1f\n", pagew, pagel);
+ fprintf(stderr, "DEBUG: bboxx = %d, bboxy = %d, bboxw = %d, bboxl = %d\n",
+ bboxx, bboxy, bboxw, bboxl);
+ fprintf(stderr, "DEBUG: PageLeft = %.1f, PageRight = %.1f\n",
+ PageLeft, PageRight);
+ fprintf(stderr, "DEBUG: PageTop = %.1f, PageBottom = %.1f\n",
+ PageTop, PageBottom);
+ fprintf(stderr, "DEBUG: PageWidth = %.1f, PageLength = %.1f\n",
+ PageWidth, PageLength);
+
+ switch (Orientation)
+ {
+ case 1 : /* Landscape */
+ doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", PageLength);
+ break;
+ case 2 : /* Reverse Portrait */
+ doc_printf(doc, "%.1f %.1f translate 180 rotate\n", PageWidth,
+ PageLength);
+ break;
+ case 3 : /* Reverse Landscape */
+ doc_printf(doc, "0.0 %.1f translate -90 rotate\n", PageWidth);
+ break;
+ }
+
+ if (Duplex && doc->number_up > 1 && ((number / doc->number_up) & 1))
+ doc_printf(doc, "%.1f %.1f translate\n", PageWidth - PageRight, PageBottom);
+ else if (doc->number_up > 1 || doc->fitplot)
+ doc_printf(doc, "%.1f %.1f translate\n", PageLeft, PageBottom);
+
+ switch (doc->number_up)
+ {
+ default :
+ if (doc->fitplot)
+ {
+ w = pagew;
+ l = w * bboxl / bboxw;
+
+ if (l > pagel)
+ {
+ l = pagel;
+ w = l * bboxw / bboxl;
+ }
+
+ tx = 0.5 * (pagew - w);
+ ty = 0.5 * (pagel - l);
+
+ doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n", tx, ty,
+ w / bboxw, l / bboxl);
+ }
+ else
+ w = PageWidth;
+ break;
+
+ case 2 :
+ if (Orientation & 1)
+ {
+ x = pos & 1;
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
+ x = 1 - x;
+
+ w = pagel;
+ l = w * bboxl / bboxw;
+
+ if (l > (pagew * 0.5))
+ {
+ l = pagew * 0.5;
+ w = l * bboxw / bboxl;
+ }
+
+ tx = 0.5 * (pagew * 0.5 - l);
+ ty = 0.5 * (pagel - w);
+
+ if (doc->normal_landscape)
+ doc_printf(doc, "0.0 %.1f translate -90 rotate\n", pagel);
+ else
+ doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", pagew);
+
+ doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
+ ty, tx + pagew * 0.5 * x, w / bboxw, l / bboxl);
+ }
+ else
+ {
+ x = pos & 1;
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
+ x = 1 - x;
+
+ l = pagew;
+ w = l * bboxw / bboxl;
+
+ if (w > (pagel * 0.5))
+ {
+ w = pagel * 0.5;
+ l = w * bboxl / bboxw;
+ }
+
+ tx = 0.5 * (pagel * 0.5 - w);
+ ty = 0.5 * (pagew - l);
+
+ if (doc->normal_landscape)
+ doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", pagew);
+ else
+ doc_printf(doc, "0.0 %.1f translate -90 rotate\n", pagel);
+
+ doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
+ tx + pagel * 0.5 * x, ty, w / bboxw, l / bboxl);
+ }
+ break;
+
+ case 4 :
+ if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
+ {
+ x = (pos / 2) & 1;
+ y = pos & 1;
+ }
+ else
+ {
+ x = pos & 1;
+ y = (pos / 2) & 1;
+ }
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
+ x = 1 - x;
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
+ y = 1 - y;
+
+ w = pagew * 0.5;
+ l = w * bboxl / bboxw;
+
+ if (l > (pagel * 0.5))
+ {
+ l = pagel * 0.5;
+ w = l * bboxw / bboxl;
+ }
+
+ tx = 0.5 * (pagew * 0.5 - w);
+ ty = 0.5 * (pagel * 0.5 - l);
+
+ doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
+ tx + x * pagew * 0.5, ty + y * pagel * 0.5,
+ w / bboxw, l / bboxl);
+ break;
+
+ case 6 :
+ if (Orientation & 1)
+ {
+ if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
+ {
+ x = pos / 3;
+ y = pos % 3;
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
+ x = 1 - x;
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
+ y = 2 - y;
+ }
+ else
+ {
+ x = pos & 1;
+ y = pos / 2;
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
+ x = 1 - x;
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
+ y = 2 - y;
+ }
+
+ w = pagel * 0.5;
+ l = w * bboxl / bboxw;
+
+ if (l > (pagew * 0.333))
+ {
+ l = pagew * 0.333;
+ w = l * bboxw / bboxl;
+ }
+
+ tx = 0.5 * (pagel - 2 * w);
+ ty = 0.5 * (pagew - 3 * l);
+
+ if (doc->normal_landscape)
+ doc_printf(doc, "0 %.1f translate -90 rotate\n", pagel);
+ else
+ doc_printf(doc, "%.1f 0 translate 90 rotate\n", pagew);
+
+ doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
+ tx + x * w, ty + y * l, l / bboxl, w / bboxw);
+ }
+ else
+ {
+ if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
+ {
+ x = pos / 2;
+ y = pos & 1;
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
+ x = 2 - x;
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
+ y = 1 - y;
+ }
+ else
+ {
+ x = pos % 3;
+ y = pos / 3;
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
+ x = 2 - x;
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
+ y = 1 - y;
+ }
+
+ l = pagew * 0.5;
+ w = l * bboxw / bboxl;
+
+ if (w > (pagel * 0.333))
+ {
+ w = pagel * 0.333;
+ l = w * bboxl / bboxw;
+ }
+
+ tx = 0.5 * (pagel - 3 * w);
+ ty = 0.5 * (pagew - 2 * l);
+
+ if (doc->normal_landscape)
+ doc_printf(doc, "%.1f 0 translate 90 rotate\n", pagew);
+ else
+ doc_printf(doc, "0 %.1f translate -90 rotate\n", pagel);
+
+ doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
+ tx + w * x, ty + l * y, w / bboxw, l / bboxl);
+
+ }
+ break;
+
+ case 9 :
+ if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
+ {
+ x = (pos / 3) % 3;
+ y = pos % 3;
+ }
+ else
+ {
+ x = pos % 3;
+ y = (pos / 3) % 3;
+ }
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
+ x = 2 - x;
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
+ y = 2 - y;
+
+ w = pagew * 0.333;
+ l = w * bboxl / bboxw;
+
+ if (l > (pagel * 0.333))
+ {
+ l = pagel * 0.333;
+ w = l * bboxw / bboxl;
+ }
+
+ tx = 0.5 * (pagew * 0.333 - w);
+ ty = 0.5 * (pagel * 0.333 - l);
+
+ doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
+ tx + x * pagew * 0.333, ty + y * pagel * 0.333,
+ w / bboxw, l / bboxl);
+ break;
+
+ case 16 :
+ if (doc->number_up_layout & PSTOPS_LAYOUT_VERTICAL)
+ {
+ x = (pos / 4) & 3;
+ y = pos & 3;
+ }
+ else
+ {
+ x = pos & 3;
+ y = (pos / 4) & 3;
+ }
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEX)
+ x = 3 - x;
+
+ if (doc->number_up_layout & PSTOPS_LAYOUT_NEGATEY)
+ y = 3 - y;
+
+ w = pagew * 0.25;
+ l = w * bboxl / bboxw;
+
+ if (l > (pagel * 0.25))
+ {
+ l = pagel * 0.25;
+ w = l * bboxw / bboxl;
+ }
+
+ tx = 0.5 * (pagew * 0.25 - w);
+ ty = 0.5 * (pagel * 0.25 - l);
+
+ doc_printf(doc, "%.1f %.1f translate %.3f %.3f scale\n",
+ tx + x * pagew * 0.25, ty + y * pagel * 0.25,
+ w / bboxw, l / bboxl);
+ break;
+ }
+
+ /*
+ * Draw borders as necessary...
+ */
+
+ if (doc->page_border && show_border)
+ {
+ int rects; /* Number of border rectangles */
+ float fscale; /* Scaling value for points */
+
+
+ rects = (doc->page_border & PSTOPS_BORDERDOUBLE) ? 2 : 1;
+ fscale = PageWidth / w;
+ margin = 2.25 * fscale;
+
+ /*
+ * Set the line width and color...
+ */
+
+ doc_puts(doc, "gsave\n");
+ doc_printf(doc, "%.3f setlinewidth 0 setgray newpath\n",
+ (doc->page_border & PSTOPS_BORDERTHICK) ? 0.5 * fscale :
+ 0.24 * fscale);
+
+ /*
+ * Draw border boxes...
+ */
+
+ for (; rects > 0; rects --, margin += 2 * fscale)
+ if (doc->number_up > 1)
+ doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrs\n",
+ margin,
+ margin,
+ bboxw - 2 * margin,
+ bboxl - 2 * margin);
+ else
+ doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrs\n",
+ PageLeft + margin,
+ PageBottom + margin,
+ PageRight - PageLeft - 2 * margin,
+ PageTop - PageBottom - 2 * margin);
+
+ /*
+ * Restore pen settings...
+ */
+
+ doc_puts(doc, "grestore\n");
+ }
+
+ if (doc->fitplot)
+ {
+ /*
+ * Offset the page by its bounding box...
+ */
+
+ doc_printf(doc, "%d %d translate\n", -bounding_box[0],
+ -bounding_box[1]);
+ }
+
+ if (doc->fitplot || doc->number_up > 1)
+ {
+ /*
+ * Clip the page to the page's bounding box...
+ */
+
+ doc_printf(doc, "%.1f %.1f %.1f %.1f ESPrc\n",
+ bboxx + margin, bboxy + margin,
+ bboxw - 2 * margin, bboxl - 2 * margin);
+ }
+
+ /*
+ * Mirror the page as needed...
+ */
+
+ if (doc->mirror)
+ doc_printf(doc, "%.1f 0.0 translate -1 1 scale\n", PageWidth);
+}
+
+
+/*
+ * 'write_label_prolog()' - Write the prolog with the classification
+ * and page label.
+ */
+
+static void
+write_label_prolog(pstops_doc_t *doc, /* I - Document info */
+ const char *label, /* I - Page label */
+ float bottom, /* I - Bottom position in points */
+ float top, /* I - Top position in points */
+ float width) /* I - Width in points */
+{
+ const char *classification; /* CLASSIFICATION environment variable */
+ const char *ptr; /* Temporary string pointer */
+
+
+ /*
+ * First get the current classification...
+ */
+
+ if ((classification = getenv("CLASSIFICATION")) == NULL)
+ classification = "";
+ if (strcmp(classification, "none") == 0)
+ classification = "";
+
+ /*
+ * If there is nothing to show, bind an empty 'write labels' procedure
+ * and return...
+ */
+
+ if (!classification[0] && (label == NULL || !label[0]))
+ {
+ doc_puts(doc, "userdict/ESPwl{}bind put\n");
+ return;
+ }
+
+ /*
+ * Set the classification + page label string...
+ */
+
+ doc_puts(doc, "userdict");
+ if (!strcmp(classification, "confidential"))
+ doc_puts(doc, "/ESPpl(CONFIDENTIAL");
+ else if (!strcmp(classification, "classified"))
+ doc_puts(doc, "/ESPpl(CLASSIFIED");
+ else if (!strcmp(classification, "secret"))
+ doc_puts(doc, "/ESPpl(SECRET");
+ else if (!strcmp(classification, "topsecret"))
+ doc_puts(doc, "/ESPpl(TOP SECRET");
+ else if (!strcmp(classification, "unclassified"))
+ doc_puts(doc, "/ESPpl(UNCLASSIFIED");
+ else
+ {
+ doc_puts(doc, "/ESPpl(");
+
+ for (ptr = classification; *ptr; ptr ++)
+ {
+ if (*ptr < 32 || *ptr > 126)
+ doc_printf(doc, "\\%03o", *ptr);
+ else if (*ptr == '_')
+ doc_puts(doc, " ");
+ else if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
+ doc_printf(doc, "\\%c", *ptr);
+ else
+ doc_printf(doc, "%c", *ptr);
+ }
+ }
+
+ if (label)
+ {
+ if (classification[0])
+ doc_puts(doc, " - ");
+
+ /*
+ * Quote the label string as needed...
+ */
+
+ for (ptr = label; *ptr; ptr ++)
+ {
+ if (*ptr < 32 || *ptr > 126)
+ doc_printf(doc, "\\%03o", *ptr);
+ else if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
+ doc_printf(doc, "\\%c", *ptr);
+ else
+ doc_printf(doc, "%c", *ptr);
+ }
+ }
+
+ doc_puts(doc, ")put\n");
+
+ /*
+ * Then get a 14 point Helvetica-Bold font...
+ */
+
+ doc_puts(doc, "userdict/ESPpf /Helvetica-Bold findfont 14 scalefont put\n");
+
+ /*
+ * Finally, the procedure to write the labels on the page...
+ */
+
+ doc_puts(doc, "userdict/ESPwl{\n");
+ doc_puts(doc, " ESPpf setfont\n");
+ doc_printf(doc, " ESPpl stringwidth pop dup 12 add exch -0.5 mul %.0f add\n",
+ width * 0.5f);
+ doc_puts(doc, " 1 setgray\n");
+ doc_printf(doc, " dup 6 sub %.0f 3 index 20 ESPrf\n", bottom - 2.0);
+ doc_printf(doc, " dup 6 sub %.0f 3 index 20 ESPrf\n", top - 18.0);
+ doc_puts(doc, " 0 setgray\n");
+ doc_printf(doc, " dup 6 sub %.0f 3 index 20 ESPrs\n", bottom - 2.0);
+ doc_printf(doc, " dup 6 sub %.0f 3 index 20 ESPrs\n", top - 18.0);
+ doc_printf(doc, " dup %.0f moveto ESPpl show\n", bottom + 2.0);
+ doc_printf(doc, " %.0f moveto ESPpl show\n", top - 14.0);
+ doc_puts(doc, "pop\n");
+ doc_puts(doc, "}bind put\n");
+}
+
+
+/*
+ * 'write_labels()' - Write the actual page labels.
+ *
+ * This function is a copy of the one in common.c since we need to
+ * use doc_puts/doc_printf instead of puts/printf...
+ */
+
+static void
+write_labels(pstops_doc_t *doc, /* I - Document information */
+ int orient) /* I - Orientation of the page */
+{
+ float width, /* Width of page */
+ length; /* Length of page */
+
+
+ doc_puts(doc, "gsave\n");
+
+ if ((orient ^ Orientation) & 1)
+ {
+ width = PageLength;
+ length = PageWidth;
+ }
+ else
+ {
+ width = PageWidth;
+ length = PageLength;
+ }
+
+ switch (orient & 3)
+ {
+ case 1 : /* Landscape */
+ doc_printf(doc, "%.1f 0.0 translate 90 rotate\n", length);
+ break;
+ case 2 : /* Reverse Portrait */
+ doc_printf(doc, "%.1f %.1f translate 180 rotate\n", width, length);
+ break;
+ case 3 : /* Reverse Landscape */
+ doc_printf(doc, "0.0 %.1f translate -90 rotate\n", width);
+ break;
+ }
+
+ doc_puts(doc, "ESPwl\n");
+ doc_puts(doc, "grestore\n");
+}
+
+
+/*
+ * 'write_options()' - Write options provided via %%IncludeFeature.
+ */
+
+static void
+write_options(
+ pstops_doc_t *doc, /* I - Document */
+ ppd_file_t *ppd, /* I - PPD file */
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ int i; /* Looping var */
+ ppd_option_t *option; /* PPD option */
+ int min_order; /* Minimum OrderDependency value */
+ char *doc_setup, /* DocumentSetup commands to send */
+ *any_setup; /* AnySetup commands to send */
+
+
+ /*
+ * Figure out the minimum OrderDependency value...
+ */
+
+ if ((option = ppdFindOption(ppd, "PageRegion")) != NULL)
+ min_order = option->order;
+ else
+ min_order = 999.0f;
+
+ for (i = 0; i < num_options; i ++)
+ if ((option = ppdFindOption(ppd, options[i].name)) != NULL &&
+ option->order < min_order)
+ min_order = option->order;
+
+ /*
+ * Mark and extract them...
+ */
+
+ cupsMarkOptions(ppd, num_options, options);
+
+ doc_setup = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, min_order);
+ any_setup = ppdEmitString(ppd, PPD_ORDER_ANY, min_order);
+
+ /*
+ * Then send them out...
+ */
+
+ if (doc->number_up > 1)
+ {
+ /*
+ * Temporarily restore setpagedevice so we can set the options...
+ */
+
+ doc_puts(doc, "userdict/setpagedevice/CUPSsetpagedevice load put\n");
+ }
+
+ if (doc_setup)
+ {
+ doc_puts(doc, doc_setup);
+ free(doc_setup);
+ }
+
+ if (any_setup)
+ {
+ doc_puts(doc, any_setup);
+ free(any_setup);
+ }
+
+ if (doc->number_up > 1)
+ {
+ /*
+ * Disable setpagedevice again...
+ */
+
+ doc_puts(doc, "userdict/setpagedevice{pop}bind put\n");
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/raster-driver.header b/filter/raster-driver.header
new file mode 100644
index 000000000..e85c2a99a
--- /dev/null
+++ b/filter/raster-driver.header
@@ -0,0 +1,32 @@
+<!--
+ "$Id: raster-driver.header 9344 2010-10-26 23:45:18Z mike $"
+
+ Raster printer driver documentation for CUPS.
+
+ Copyright 2007-2010 by Apple Inc.
+ Copyright 1997-2007 by Easy Software Products.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>Developing Raster Printer Drivers</h1>
+
+<p>This document describes how to develop printer drivers for raster printers. Topics include: <a href='#BASICS'>printer driver basics</a>, <a href='#CREATE'>creating new PPD files</a>, <a href='#FILTERS'>using filters</a>, <a href='#COLOR'>implementing color management</a>, and <a href='#MACOSX'>adding Mac OS X features</a>.</p>
+
+<div class='summary'><table summary='General Information'>
+<tbody>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='postscript-driver.html'>Developing PostScript Printer Drivers</a><br>
+ Programming: <a href='api-filter.html'>Filter and Backend Programming</a><br>
+ Programming: <a href='ppd-compiler.html'>Introduction to the PPD Compiler</a><br>
+ Programming: <a href='api-raster.html'>Raster API</a><br>
+ References: <a href='ref-ppdcfile.html'>PPD Compiler Driver Information File Reference</a><br>
+ Specifications: <a href='spec-ppd.html'>CUPS PPD Extensions</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/filter/raster-driver.shtml b/filter/raster-driver.shtml
new file mode 100644
index 000000000..1c0c32a9d
--- /dev/null
+++ b/filter/raster-driver.shtml
@@ -0,0 +1,194 @@
+<h2 class='title'><a name='BASICS'>Printer Driver Basics</a></h2>
+
+<p>A CUPS raster printer driver consists of a PostScript Printer Description (PPD) file that describes the features and capabilities of the device, one or more <em>filter</em> programs that prepare print data for the device, and zero or more support files for color management, online help, and so forth. The PPD file includes references to all of the filters and support files used by the driver.</p>
+
+<p>Every time a user prints something the scheduler program, <a href='man-cupsd.html'>cupsd(8)</a>, determines the format of the print job and the programs required to convert that job into something the printer understands. CUPS includes filter programs for many common formats, for example to convert Portable Document Format (PDF) files into CUPS raster data. <a href='#FIGURE_1'>Figure 1</a> shows the data flow of a typical print job.</p>
+
+<div class='figure'><table summary='Raster Filter Chain'>
+<caption>Figure 1: <a name='FIGURE_1'>Raster Filter Chain</a></caption>
+<tr><td><img src='../images/cups-raster-chain.png' width='700' height='150' alt='Raster Filter Chain'></td></tr>
+</table></div>
+
+<p>The raster filter converts CUPS raster data into a format the printer understands, for example HP-PCL. CUPS includes several sample raster filters supporting standard page description languages (PDLs). <a href='#TABLE_1'>Table 1</a> shows the raster filters that are bundled with CUPS and the languages they support.</p>
+
+<div class='table'><table summary='Standard CUPS Raster Filters'>
+<caption>Table 1: <a name='TABLE_1'>Standard CUPS Raster Filters</a></caption>
+<thead>
+<tr><th>Filter</th><th>PDLs</th><th>ppdc DriverType</th><th>ppdc #include file</th></tr>
+</thead>
+<tbody>
+<tr><td>rastertoepson</td><td>ESC/P, ESC/P2</td><td>epson</td><td>epson.h</td></tr>
+<tr><td>rastertoescpx</td><td>ESC/P, ESC/P2, EPSON Remote Mode</td><td>escp</td><td>escp.h</td></tr>
+<tr><td>rastertohp</td><td>HP-PCL3, HP-PCL5</td><td>hp</td><td>hp.h</td></tr>
+<tr><td>rastertolabel</td><td>CPCL, Dymo, EPL1, EPL2, Intellitech PCL, ZPL</td><td>label</td><td>label.h</td></tr>
+<tr><td>rastertopclx</td><td>HP-RTL, HP-PCL3, HP-PCL3GUI, HP-PCL5, HP-PCL5c, HP-PCL5e</td><td>pcl</td><td>pcl.h</td></tr>
+</tbody>
+</table></div>
+
+<p>The optional port monitor handles interface-specific protocol or encoding issues. For example, some raster printers use the 1284.4 communications protocol.</p>
+
+<p>The backend handles communications with the printer, sending print data from the last filter to the printer and relaying back-channel data from the printer to the upstream filters. CUPS includes backend programs for common direct-connect interfaces and network protocols, and you can provide your own backend to support custom interfaces and protocols.</p>
+
+<p>The scheduler also supports a special "command" file format for sending maintenance commands and status queries to a printer or printer driver. Command print jobs typically use a single command filter program defined in the PPD file to generate the appropriate printer commands and handle any responses from the printer. <a href='#FIGURE_2'>Figure 2</a> shows the data flow of a typical command job.</p>
+
+<div class='figure'><table summary='Command Filter Chain'>
+<caption>Figure 2: <a name='FIGURE_2'>Command Filter Chain</a></caption>
+<tr><td><img src='../images/cups-command-chain.png' width='575' height='150' alt='Command Filter Chain'></td></tr>
+</table></div>
+
+<p>Raster printer drivers must provide their own command filter.</p>
+
+
+<h2 class='title'><a name='CREATING'>Creating New PPD Files</a></h2>
+
+<p>We recommend using the CUPS PPD compiler, <a href='man-ppdc.html'>ppdc(1)</a>, to create new PPD files since it manages many of the tedious (and error-prone!) details of paper sizes and localization for you. It also allows you to easily support multiple devices from a single source file. For more information see the "<a href='ppd-compiler.html'>Introduction to the PPD Compiler</a>" document. <a href='#LISTING_1'>Listing 1</a> shows a driver information file for several similar black-and-white HP-PCL5 laser printers.</p>
+
+<p class='example'>Listing 1: <a name='LISTING_1'>"examples/laserjet-basic.drv"</a></p>
+
+<pre class='example'>
+<I>// Include standard font and media definitions</I>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;font.defs&gt;
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;media.defs&gt;
+
+<I>// Include HP-PCL driver definitions</I>
+<a href='ref-ppdcfile.html#_include'>#include</a> &lt;pcl.h&gt;
+
+<I>// Specify that this driver uses the HP-PCL driver...</I>
+<a href='ref-ppdcfile.html#DriverType'>DriverType</a> pcl
+
+<I>// Specify the driver options via the model number...</I>
+<a href='ref-ppdcfile.html#ModelNumber'>ModelNumber</a> ($PCL_PAPER_SIZE $PCL_PJL $PCL_PJL_RESOLUTION)
+
+<I>// List the fonts that are supported, in this case all standard fonts...</I>
+<a href='ref-ppdcfile.html#Font'>Font</a> *
+
+<I>// Manufacturer and driver version</I>
+<a href='ref-ppdcfile.html#Manufacturer'>Manufacturer</a> "HP"
+<a href='ref-ppdcfile.html#Version'>Version</a> 1.0
+
+<I>// Supported page sizes and their margins</I>
+<a href='ref-ppdcfile.html#HWMargins'>HWMargins</a> 18 12 18 12
+*<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Letter
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Legal
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Executive
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Monarch
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Statement
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> FanFoldGermanLegal
+
+<a href='ref-ppdcfile.html#HWMargins'>HWMargins</a> 18 12.72 18 12.72
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Env10
+
+<a href='ref-ppdcfile.html#HWMargins'>HWMargins</a> 9.72 12 9.72 12
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A4
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> A5
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> B5
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> EnvC5
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> EnvDL
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> EnvISOB5
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> Postcard
+<a href='ref-ppdcfile.html#MediaSize'>MediaSize</a> DoublePostcard
+
+<I>// Only black-and-white output with mode 3 compression...</I>
+<a href='ref-ppdcfile.html#ColorModel'>ColorModel</a> Gray k chunky 3
+
+<I>// Supported resolutions</I>
+<a href='ref-ppdcfile.html#Resolution'>Resolution</a> - 1 0 0 0 "300dpi/300 DPI"
+*<a href='ref-ppdcfile.html#Resolution'>Resolution</a> - 8 0 0 0 "600dpi/600 DPI"
+
+<I>// Supported input slots</I>
+*<a href='ref-ppdcfile.html#InputSlot'>InputSlot</a> 7 "Auto/Automatic Selection"
+<a href='ref-ppdcfile.html#InputSlot'>InputSlot</a> 2 "Manual/Tray 1 - Manual Feed"
+<a href='ref-ppdcfile.html#InputSlot'>InputSlot</a> 4 "Upper/Tray 1"
+<a href='ref-ppdcfile.html#InputSlot'>InputSlot</a> 1 "Lower/Tray 2"
+<a href='ref-ppdcfile.html#InputSlot'>InputSlot</a> 5 "LargeCapacity/Tray 3"
+
+<I>// Tray 3 is an option...</I>
+<a href='ref-ppdcfile.html#Installable'>Installable</a> "OptionLargeCapacity/Tray 3 Installed"
+<a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*OptionLargeCapacity False *InputSlot LargeCapacity"
+
+{
+ <I>// HP LaserJet 2100 Series</I>
+ <a href='ref-ppdcfile.html#Throughput'>Throughput</a> 10
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "LaserJet 2100 Series"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "hpljt211.ppd"
+}
+
+{
+ <I>// LaserJet 2200 and 2300 series have duplexer option...</I>
+ <a href='ref-ppdcfile.html#Duplex'>Duplex</a> normal
+ <a href='ref-ppdcfile.html#Installable'>Installable</a> "OptionDuplex/Duplexer Installed"
+ <a href='ref-ppdcfile.html#UIConstraints'>UIConstraints</a> "*OptionDuplex False *Duplex"
+
+ {
+ <I>// HP LaserJet 2200 Series</I>
+ <a href='ref-ppdcfile.html#Throughput'>Throughput</a> 19
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "LaserJet 2200 Series"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "hpljt221.ppd"
+ }
+
+ {
+ <I>// HP LaserJet 2300 Series</I>
+ <a href='ref-ppdcfile.html#Throughput'>Throughput</a> 25
+ <a href='ref-ppdcfile.html#ModelName'>ModelName</a> "LaserJet 2300 Series"
+ <a href='ref-ppdcfile.html#PCFileName'>PCFileName</a> "hpljt231.ppd"
+ }
+}
+</pre>
+
+
+<h2 class='title'><a name='FILTERS'>Using Filters</a></h2>
+
+<p>The standard CUPS raster filters can be specified using the
+<a href='ref-ppdcfile.html#DriverType'><tt>DriverType</tt></a> directive, for example:</p>
+
+<pre class='example'>
+<I>// Specify that this driver uses the HP-PCL driver...</I>
+<a href='ref-ppdcfile.html#DriverType'>DriverType</a> pcl
+</pre>
+
+<p><a href='#TABLE_1'>Table 1</a> shows the driver types for each of the standard CUPS raster filters. For drivers that do not use the standard raster filters, the "custom" type is used with <a href='ref-ppdcfile.html#Filter'><tt>Filter</tt></a> directives:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#DriverType'>DriverType</a> custom
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-raster 100 /path/to/raster/filter
+<a href='ref-ppdcfile.html#Filter'>Filter</a> application/vnd.cups-command 100 /path/to/command/filter
+</pre>
+
+
+<h2 class='title'><a name='COLOR'>Implementing Color Management</a></h2>
+
+<p>CUPS uses ICC color profiles to provide more accurate color reproduction. The <a href='spec-ppd.html#cupsICCProfile'><tt>cupsICCProfile</tt></a> attribute defines the color profiles that are available for a given printer, for example:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsICCProfile "ColorModel.MediaType.Resolution/Description" /path/to/ICC/profile
+</pre>
+
+<p>where "ColorModel.MediaType.Resolution" defines a selector based on the corresponding option selections. A simple driver might only define profiles for the color models that are supported, for example a printer supporting Gray and RGB might use:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsICCProfile "Gray../Grayscale Profile" /path/to/ICC/gray-profile
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> cupsICCProfile "RGB../Full Color Profile" /path/to/ICC/rgb-profile
+</pre>
+
+<p>The options used for profile selection can be customized using the <tt>cupsICCQualifier2</tt> and <tt>cupsICCQualifier3</tt> attributes.</p>
+
+<h3><span class='info'>Since Mac OS X 10.5</span>Custom Color Matching Support</h3>
+
+<p>Mac OS X printer drivers that are based on an existing standard RGB colorspace can tell the system to use the corresponding colorspace instead of an arbitrary ICC color profile when doing color management. The <a href='#APCustom'><tt>APSupportsCustomColorMatching</tt></a> and <tt>APDefaultCustomColorMatchingProfile</tt> attributes can be used to enable this mode:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APSupportsCustomColorMatching "" true
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APDefaultCustomColorMatchingProfile "" sRGB
+</pre>
+
+
+<h2 class='title'><a name='MACOSX'>Adding Mac OS X Features</a></h2>
+
+<p>Mac OS X printer drivers can provide <a href='spec-ppd.html#MACOSX'>additional attributes</a> to specify additional option panes in the print dialog, an image of the printer, a help book, and option presets for the driver software:</p>
+
+<pre class='example'>
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APDialogExtension "" /Library/Printers/Vendor/filename.plugin
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APHelpBook "" /Library/Printers/Vendor/filename.bundle
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APPrinterIconPath "" /Library/Printers/Vendor/filename.icns
+<a href='ref-ppdcfile.html#Attribute'>Attribute</a> APPrinterPreset "name/text" "*option choice ..."
+</pre>
diff --git a/filter/raster.c b/filter/raster.c
new file mode 100644
index 000000000..b47f9e2de
--- /dev/null
+++ b/filter/raster.c
@@ -0,0 +1,1376 @@
+/*
+ * "$Id$"
+ *
+ * Raster file routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * This file is part of the CUPS Imaging library.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * cupsRasterClose() - Close a raster stream.
+ * cupsRasterOpen() - Open a raster stream using a file descriptor.
+ * cupsRasterOpenIO() - Open a raster stream using a callback function.
+ * cupsRasterReadHeader() - Read a raster page header and store it in a
+ * version 1 page header structure.
+ * cupsRasterReadHeader2() - Read a raster page header and store it in a
+ * version 2 page header structure.
+ * cupsRasterReadPixels() - Read raster pixels.
+ * cupsRasterWriteHeader() - Write a raster page header from a version 1
+ * page header structure.
+ * cupsRasterWriteHeader2() - Write a raster page header from a version 2
+ * page header structure.
+ * cupsRasterWritePixels() - Write raster pixels.
+ * cups_raster_read_header() - Read a raster page header.
+ * cups_raster_read() - Read through the raster buffer.
+ * cups_raster_update() - Update the raster header and row count for the
+ * current page.
+ * cups_raster_write() - Write a row of compressed raster data...
+ * cups_read_fd() - Read bytes from a file.
+ * cups_swap() - Swap bytes in raster data...
+ * cups_write_fd() - Write bytes to a file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+#if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+# include <winsock2.h> /* for htonl() definition */
+#else
+# include <unistd.h>
+#endif /* WIN32 || __EMX__ */
+
+
+/*
+ * Private structures...
+ */
+
+struct _cups_raster_s /**** Raster stream data ****/
+{
+ unsigned sync; /* Sync word from start of stream */
+ void *ctx; /* File descriptor */
+ cups_raster_iocb_t iocb; /* IO callback */
+ cups_mode_t mode; /* Read/write mode */
+ cups_page_header2_t header; /* Raster header for current page */
+ int count, /* Current row run-length count */
+ remaining, /* Remaining rows in page image */
+ bpp; /* Bytes per pixel/color */
+ unsigned char *pixels, /* Pixels for current row */
+ *pend, /* End of pixel buffer */
+ *pcurrent; /* Current byte in pixel buffer */
+ int compressed, /* Non-zero if data is compressed */
+ swapped; /* Non-zero if data is byte-swapped */
+ unsigned char *buffer, /* Read/write buffer */
+ *bufptr, /* Current (read) position in buffer */
+ *bufend; /* End of current (read) buffer */
+ size_t bufsize; /* Buffer size */
+};
+
+
+/*
+ * Local functions...
+ */
+
+static int cups_raster_io(cups_raster_t *r, unsigned char *buf, int bytes);
+static unsigned cups_raster_read_header(cups_raster_t *r);
+static int cups_raster_read(cups_raster_t *r, unsigned char *buf,
+ int bytes);
+static void cups_raster_update(cups_raster_t *r);
+static int cups_raster_write(cups_raster_t *r,
+ const unsigned char *pixels);
+static ssize_t cups_read_fd(void *ctx, unsigned char *buf, size_t bytes);
+static void cups_swap(unsigned char *buf, int bytes);
+static ssize_t cups_write_fd(void *ctx, unsigned char *buf, size_t bytes);
+
+
+/*
+ * 'cupsRasterClose()' - Close a raster stream.
+ *
+ * The file descriptor associated with the raster stream must be closed
+ * separately as needed.
+ */
+
+void
+cupsRasterClose(cups_raster_t *r) /* I - Stream to close */
+{
+ if (r != NULL)
+ {
+ if (r->buffer)
+ free(r->buffer);
+
+ if (r->pixels)
+ free(r->pixels);
+
+ free(r);
+ }
+}
+
+
+/*
+ * 'cupsRasterOpen()' - Open a raster stream using a file descriptor.
+ *
+ * This function associates a raster stream with the given file descriptor.
+ * For most printer driver filters, "fd" will be 0 (stdin). For most raster
+ * image processor (RIP) filters that generate raster data, "fd" will be 1
+ * (stdout).
+ *
+ * When writing raster data, the @code CUPS_RASTER_WRITE@,
+ * @code CUPS_RASTER_WRITE_COMPRESS@, or @code CUPS_RASTER_WRITE_PWG@ mode can
+ * be used - compressed and PWG output is generally 25-50% smaller but adds a
+ * 100-300% execution time overhead.
+ */
+
+cups_raster_t * /* O - New stream */
+cupsRasterOpen(int fd, /* I - File descriptor */
+ cups_mode_t mode) /* I - Mode - @code CUPS_RASTER_READ@,
+ @code CUPS_RASTER_WRITE@,
+ @code CUPS_RASTER_WRITE_COMPRESSED@,
+ or @code CUPS_RASTER_WRITE_PWG@ */
+{
+ if (mode == CUPS_RASTER_READ)
+ return (cupsRasterOpenIO(cups_read_fd, (void *)((intptr_t)fd), mode));
+ else
+ return (cupsRasterOpenIO(cups_write_fd, (void *)((intptr_t)fd), mode));
+}
+
+
+/*
+ * 'cupsRasterOpenIO()' - Open a raster stream using a callback function.
+ *
+ * This function associates a raster stream with the given callback function and
+ * context pointer.
+ *
+ * When writing raster data, the @code CUPS_RASTER_WRITE@,
+ * @code CUPS_RASTER_WRITE_COMPRESS@, or @code CUPS_RASTER_WRITE_PWG@ mode can
+ * be used - compressed and PWG output is generally 25-50% smaller but adds a
+ * 100-300% execution time overhead.
+ */
+
+cups_raster_t * /* O - New stream */
+cupsRasterOpenIO(
+ cups_raster_iocb_t iocb, /* I - Read/write callback */
+ void *ctx, /* I - Context pointer for callback */
+ cups_mode_t mode) /* I - Mode - @code CUPS_RASTER_READ@,
+ @code CUPS_RASTER_WRITE@,
+ @code CUPS_RASTER_WRITE_COMPRESSED@,
+ or @code CUPS_RASTER_WRITE_PWG@ */
+{
+ cups_raster_t *r; /* New stream */
+
+
+ _cupsRasterClearError();
+
+ if ((r = calloc(sizeof(cups_raster_t), 1)) == NULL)
+ {
+ _cupsRasterAddError("Unable to allocate memory for raster stream: %s\n",
+ strerror(errno));
+ return (NULL);
+ }
+
+ r->ctx = ctx;
+ r->iocb = iocb;
+ r->mode = mode;
+
+ if (mode == CUPS_RASTER_READ)
+ {
+ /*
+ * Open for read - get sync word...
+ */
+
+ if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync)) !=
+ sizeof(r->sync))
+ {
+ _cupsRasterAddError("Unable to read header from raster stream: %s\n",
+ strerror(errno));
+ free(r);
+ return (NULL);
+ }
+
+ if (r->sync != CUPS_RASTER_SYNC &&
+ r->sync != CUPS_RASTER_REVSYNC &&
+ r->sync != CUPS_RASTER_SYNCv1 &&
+ r->sync != CUPS_RASTER_REVSYNCv1 &&
+ r->sync != CUPS_RASTER_SYNCv2 &&
+ r->sync != CUPS_RASTER_REVSYNCv2)
+ {
+ _cupsRasterAddError("Unknown raster format %08x!\n", r->sync);
+ free(r);
+ return (NULL);
+ }
+
+ if (r->sync == CUPS_RASTER_SYNCv2 ||
+ r->sync == CUPS_RASTER_REVSYNCv2)
+ r->compressed = 1;
+
+ if (r->sync == CUPS_RASTER_REVSYNC ||
+ r->sync == CUPS_RASTER_REVSYNCv1 ||
+ r->sync == CUPS_RASTER_REVSYNCv2)
+ r->swapped = 1;
+
+ DEBUG_printf(("r->swapped=%d, r->sync=%08x\n", r->swapped, r->sync));
+ }
+ else
+ {
+ /*
+ * Open for write - put sync word...
+ */
+
+ switch (mode)
+ {
+ default :
+ case CUPS_RASTER_WRITE :
+ r->sync = CUPS_RASTER_SYNC;
+ break;
+
+ case CUPS_RASTER_WRITE_COMPRESSED :
+ r->compressed = 1;
+ r->sync = CUPS_RASTER_SYNCv2;
+ break;
+
+ case CUPS_RASTER_WRITE_PWG :
+ r->compressed = 1;
+ r->sync = htonl(CUPS_RASTER_SYNC_PWG);
+ r->swapped = r->sync != CUPS_RASTER_SYNC_PWG;
+ break;
+ }
+
+ if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync))
+ < sizeof(r->sync))
+ {
+ _cupsRasterAddError("Unable to write raster stream header: %s\n",
+ strerror(errno));
+ free(r);
+ return (NULL);
+ }
+ }
+
+ return (r);
+}
+
+
+/*
+ * 'cupsRasterReadHeader()' - Read a raster page header and store it in a
+ * version 1 page header structure.
+ *
+ * This function is deprecated. Use @link cupsRasterReadHeader2@ instead.
+ *
+ * Version 1 page headers were used in CUPS 1.0 and 1.1 and contain a subset
+ * of the version 2 page header data. This function handles reading version 2
+ * page headers and copying only the version 1 data into the provided buffer.
+ *
+ * @deprecated@
+ */
+
+unsigned /* O - 1 on success, 0 on failure/end-of-file */
+cupsRasterReadHeader(
+ cups_raster_t *r, /* I - Raster stream */
+ cups_page_header_t *h) /* I - Pointer to header data */
+{
+ /*
+ * Get the raster header...
+ */
+
+ if (!cups_raster_read_header(r))
+ return (0);
+
+ /*
+ * Copy the header to the user-supplied buffer...
+ */
+
+ memcpy(h, &(r->header), sizeof(cups_page_header_t));
+
+ return (1);
+}
+
+
+/*
+ * 'cupsRasterReadHeader2()' - Read a raster page header and store it in a
+ * version 2 page header structure.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+unsigned /* O - 1 on success, 0 on failure/end-of-file */
+cupsRasterReadHeader2(
+ cups_raster_t *r, /* I - Raster stream */
+ cups_page_header2_t *h) /* I - Pointer to header data */
+{
+ /*
+ * Get the raster header...
+ */
+
+ if (!cups_raster_read_header(r))
+ return (0);
+
+ /*
+ * Copy the header to the user-supplied buffer...
+ */
+
+ memcpy(h, &(r->header), sizeof(cups_page_header2_t));
+
+ return (1);
+}
+
+
+/*
+ * 'cupsRasterReadPixels()' - Read raster pixels.
+ *
+ * For best performance, filters should read one or more whole lines.
+ * The "cupsBytesPerLine" value from the page header can be used to allocate
+ * the line buffer and as the number of bytes to read.
+ */
+
+unsigned /* O - Number of bytes read */
+cupsRasterReadPixels(cups_raster_t *r, /* I - Raster stream */
+ unsigned char *p, /* I - Pointer to pixel buffer */
+ unsigned len) /* I - Number of bytes to read */
+{
+ int bytes; /* Bytes read */
+ unsigned cupsBytesPerLine; /* cupsBytesPerLine value */
+ unsigned remaining; /* Bytes remaining */
+ unsigned char *ptr, /* Pointer to read buffer */
+ byte, /* Byte from file */
+ *temp; /* Pointer into buffer */
+ int count; /* Repetition count */
+
+
+ if (r == NULL || r->mode != CUPS_RASTER_READ || r->remaining == 0)
+ return (0);
+
+ if (!r->compressed)
+ {
+ /*
+ * Read without compression...
+ */
+
+ r->remaining -= len / r->header.cupsBytesPerLine;
+
+ if (cups_raster_io(r, p, len) < (ssize_t)len)
+ return (0);
+
+ /*
+ * Swap bytes as needed...
+ */
+
+ if (r->swapped &&
+ (r->header.cupsBitsPerColor == 16 ||
+ r->header.cupsBitsPerPixel == 12 ||
+ r->header.cupsBitsPerPixel == 16))
+ cups_swap(p, len);
+
+ /*
+ * Return...
+ */
+
+ return (len);
+ }
+
+ /*
+ * Read compressed data...
+ */
+
+ remaining = len;
+ cupsBytesPerLine = r->header.cupsBytesPerLine;
+
+ while (remaining > 0 && r->remaining > 0)
+ {
+ if (r->count == 0)
+ {
+ /*
+ * Need to read a new row...
+ */
+
+ if (remaining == cupsBytesPerLine)
+ ptr = p;
+ else
+ ptr = r->pixels;
+
+ /*
+ * Read using a modified PackBits compression...
+ */
+
+ if (!cups_raster_read(r, &byte, 1))
+ return (0);
+
+ r->count = byte + 1;
+
+ if (r->count > 1)
+ ptr = r->pixels;
+
+ temp = ptr;
+ bytes = cupsBytesPerLine;
+
+ while (bytes > 0)
+ {
+ /*
+ * Get a new repeat count...
+ */
+
+ if (!cups_raster_read(r, &byte, 1))
+ return (0);
+
+ if (byte & 128)
+ {
+ /*
+ * Copy N literal pixels...
+ */
+
+ count = (257 - byte) * r->bpp;
+
+ if (count > bytes)
+ count = bytes;
+
+ if (!cups_raster_read(r, temp, count))
+ return (0);
+
+ temp += count;
+ bytes -= count;
+ }
+ else
+ {
+ /*
+ * Repeat the next N bytes...
+ */
+
+ count = (byte + 1) * r->bpp;
+ if (count > bytes)
+ count = bytes;
+
+ if (count < r->bpp)
+ break;
+
+ bytes -= count;
+
+ if (!cups_raster_read(r, temp, r->bpp))
+ return (0);
+
+ temp += r->bpp;
+ count -= r->bpp;
+
+ while (count > 0)
+ {
+ memcpy(temp, temp - r->bpp, r->bpp);
+ temp += r->bpp;
+ count -= r->bpp;
+ }
+ }
+ }
+
+ /*
+ * Swap bytes as needed...
+ */
+
+ if ((r->header.cupsBitsPerColor == 16 ||
+ r->header.cupsBitsPerPixel == 12 ||
+ r->header.cupsBitsPerPixel == 16) &&
+ r->swapped)
+ cups_swap(ptr, bytes);
+
+ /*
+ * Update pointers...
+ */
+
+ if (remaining >= cupsBytesPerLine)
+ {
+ bytes = cupsBytesPerLine;
+ r->pcurrent = r->pixels;
+ r->count --;
+ r->remaining --;
+ }
+ else
+ {
+ bytes = remaining;
+ r->pcurrent = r->pixels + bytes;
+ }
+
+ /*
+ * Copy data as needed...
+ */
+
+ if (ptr != p)
+ memcpy(p, ptr, bytes);
+ }
+ else
+ {
+ /*
+ * Copy fragment from buffer...
+ */
+
+ if ((unsigned)(bytes = r->pend - r->pcurrent) > remaining)
+ bytes = remaining;
+
+ memcpy(p, r->pcurrent, bytes);
+ r->pcurrent += bytes;
+
+ if (r->pcurrent >= r->pend)
+ {
+ r->pcurrent = r->pixels;
+ r->count --;
+ r->remaining --;
+ }
+ }
+
+ remaining -= bytes;
+ p += bytes;
+ }
+
+ return (len);
+}
+
+
+/*
+ * 'cupsRasterWriteHeader()' - Write a raster page header from a version 1 page
+ * header structure.
+ *
+ * This function is deprecated. Use @link cupsRasterWriteHeader2@ instead.
+ *
+ * @deprecated@
+ */
+
+unsigned /* O - 1 on success, 0 on failure */
+cupsRasterWriteHeader(
+ cups_raster_t *r, /* I - Raster stream */
+ cups_page_header_t *h) /* I - Raster page header */
+{
+ if (r == NULL || r->mode == CUPS_RASTER_READ)
+ return (0);
+
+ /*
+ * Make a copy of the header, and compute the number of raster
+ * lines in the page image...
+ */
+
+ memset(&(r->header), 0, sizeof(r->header));
+ memcpy(&(r->header), h, sizeof(cups_page_header_t));
+
+ cups_raster_update(r);
+
+ /*
+ * Write the raster header...
+ */
+
+ if (r->mode == CUPS_RASTER_WRITE_PWG)
+ {
+ /*
+ * PWG raster data is always network byte order with most of the page header
+ * zeroed.
+ */
+
+ cups_page_header2_t fh; /* File page header */
+
+ memset(&fh, 0, sizeof(fh));
+ fh.HWResolution[0] = htonl(r->header.HWResolution[0]);
+ fh.HWResolution[1] = htonl(r->header.HWResolution[1]);
+ fh.cupsWidth = htonl(r->header.cupsWidth);
+ fh.cupsHeight = htonl(r->header.cupsHeight);
+ fh.cupsBitsPerColor = htonl(r->header.cupsBitsPerColor);
+ fh.cupsBitsPerPixel = htonl(r->header.cupsBitsPerPixel);
+ fh.cupsBytesPerLine = htonl(r->header.cupsBytesPerLine);
+ fh.cupsColorOrder = htonl(r->header.cupsColorOrder);
+ fh.cupsColorSpace = htonl(r->header.cupsColorSpace);
+
+ return (cups_raster_io(r, (unsigned char *)&fh, sizeof(fh)) == sizeof(fh));
+ }
+ else
+ return (cups_raster_io(r, (unsigned char *)&(r->header), sizeof(r->header))
+ == sizeof(r->header));
+}
+
+
+/*
+ * 'cupsRasterWriteHeader2()' - Write a raster page header from a version 2
+ * page header structure.
+ *
+ * The page header can be initialized using @link cupsRasterInterpretPPD@.
+ *
+ * @since CUPS 1.2/Mac OS X 10.5@
+ */
+
+unsigned /* O - 1 on success, 0 on failure */
+cupsRasterWriteHeader2(
+ cups_raster_t *r, /* I - Raster stream */
+ cups_page_header2_t *h) /* I - Raster page header */
+{
+ if (r == NULL || r->mode == CUPS_RASTER_READ)
+ return (0);
+
+ /*
+ * Make a copy of the header, and compute the number of raster
+ * lines in the page image...
+ */
+
+ memcpy(&(r->header), h, sizeof(cups_page_header2_t));
+
+ cups_raster_update(r);
+
+ /*
+ * Write the raster header...
+ */
+
+ if (r->mode == CUPS_RASTER_WRITE_PWG)
+ {
+ /*
+ * PWG raster data is always network byte order with most of the page header
+ * zeroed.
+ */
+
+ cups_page_header2_t fh; /* File page header */
+
+ memset(&fh, 0, sizeof(fh));
+ fh.HWResolution[0] = htonl(r->header.HWResolution[0]);
+ fh.HWResolution[1] = htonl(r->header.HWResolution[1]);
+ fh.cupsWidth = htonl(r->header.cupsWidth);
+ fh.cupsHeight = htonl(r->header.cupsHeight);
+ fh.cupsBitsPerColor = htonl(r->header.cupsBitsPerColor);
+ fh.cupsBitsPerPixel = htonl(r->header.cupsBitsPerPixel);
+ fh.cupsBytesPerLine = htonl(r->header.cupsBytesPerLine);
+ fh.cupsColorOrder = htonl(r->header.cupsColorOrder);
+ fh.cupsColorSpace = htonl(r->header.cupsColorSpace);
+ fh.cupsNumColors = htonl(r->header.cupsNumColors);
+
+ return (cups_raster_io(r, (unsigned char *)&fh, sizeof(fh)) == sizeof(fh));
+ }
+ else
+ return (cups_raster_io(r, (unsigned char *)&(r->header), sizeof(r->header))
+ == sizeof(r->header));
+}
+
+
+/*
+ * 'cupsRasterWritePixels()' - Write raster pixels.
+ *
+ * For best performance, filters should write one or more whole lines.
+ * The "cupsBytesPerLine" value from the page header can be used to allocate
+ * the line buffer and as the number of bytes to write.
+ */
+
+unsigned /* O - Number of bytes written */
+cupsRasterWritePixels(cups_raster_t *r, /* I - Raster stream */
+ unsigned char *p, /* I - Bytes to write */
+ unsigned len)/* I - Number of bytes to write */
+{
+ int bytes; /* Bytes read */
+ unsigned remaining; /* Bytes remaining */
+
+
+ DEBUG_printf(("cupsRasterWritePixels(r=%p, p=%p, len=%u), remaining=%u\n",
+ r, p, len, r->remaining));
+
+ if (r == NULL || r->mode == CUPS_RASTER_READ || r->remaining == 0)
+ return (0);
+
+ if (!r->compressed)
+ {
+ /*
+ * Without compression, just write the raster data raw unless the data needs
+ * to be swapped...
+ */
+
+ r->remaining -= len / r->header.cupsBytesPerLine;
+
+ if (r->swapped &&
+ (r->header.cupsBitsPerColor == 16 ||
+ r->header.cupsBitsPerPixel == 12 ||
+ r->header.cupsBitsPerPixel == 16))
+ {
+ unsigned char *bufptr; /* Pointer into write buffer */
+ unsigned count; /* Remaining count */
+
+ /*
+ * Allocate a write buffer as needed...
+ */
+
+ if ((size_t)len > r->bufsize)
+ {
+ if (r->buffer)
+ bufptr = realloc(r->buffer, len);
+ else
+ bufptr = malloc(len);
+
+ if (!bufptr)
+ return (0);
+
+ r->buffer = bufptr;
+ r->bufsize = len;
+ }
+
+ /*
+ * Byte swap the pixels...
+ */
+
+ for (bufptr = r->buffer, count = len; count > 1; count -= 2, bufptr += 2)
+ {
+ bufptr[1] = *p++;
+ bufptr[0] = *p++;
+ }
+
+ if (count) /* This should never happen... */
+ *bufptr = *p;
+
+ /*
+ * Write the byte-swapped buffer...
+ */
+
+ return (cups_raster_io(r, r->buffer, len));
+ }
+ else
+ return (cups_raster_io(r, p, len));
+ }
+
+ /*
+ * Otherwise, compress each line...
+ */
+
+ for (remaining = len; remaining > 0; remaining -= bytes, p += bytes)
+ {
+ /*
+ * Figure out the number of remaining bytes on the current line...
+ */
+
+ if ((bytes = remaining) > (r->pend - r->pcurrent))
+ bytes = r->pend - r->pcurrent;
+
+ if (r->count > 0)
+ {
+ /*
+ * Check to see if this line is the same as the previous line...
+ */
+
+ if (memcmp(p, r->pcurrent, bytes))
+ {
+ if (!cups_raster_write(r, r->pixels))
+ return (0);
+
+ r->count = 0;
+ }
+ else
+ {
+ /*
+ * Mark more bytes as the same...
+ */
+
+ r->pcurrent += bytes;
+
+ if (r->pcurrent >= r->pend)
+ {
+ /*
+ * Increase the repeat count...
+ */
+
+ r->count ++;
+ r->pcurrent = r->pixels;
+
+ /*
+ * Flush out this line if it is the last one...
+ */
+
+ r->remaining --;
+
+ if (r->remaining == 0)
+ return (cups_raster_write(r, r->pixels));
+ else if (r->count == 256)
+ {
+ if (cups_raster_write(r, r->pixels) == 0)
+ return (0);
+
+ r->count = 0;
+ }
+ }
+
+ continue;
+ }
+ }
+
+ if (r->count == 0)
+ {
+ /*
+ * Copy the raster data to the buffer...
+ */
+
+ memcpy(r->pcurrent, p, bytes);
+
+ r->pcurrent += bytes;
+
+ if (r->pcurrent >= r->pend)
+ {
+ /*
+ * Increase the repeat count...
+ */
+
+ r->count ++;
+ r->pcurrent = r->pixels;
+
+ /*
+ * Flush out this line if it is the last one...
+ */
+
+ r->remaining --;
+
+ if (r->remaining == 0)
+ return (cups_raster_write(r, r->pixels));
+ }
+ }
+ }
+
+ return (len);
+}
+
+
+/*
+ * 'cups_raster_read_header()' - Read a raster page header.
+ */
+
+static unsigned /* O - 1 on success, 0 on fail */
+cups_raster_read_header(
+ cups_raster_t *r) /* I - Raster stream */
+{
+ int len; /* Length for read/swap */
+
+
+ if (r == NULL || r->mode != CUPS_RASTER_READ)
+ return (0);
+
+ /*
+ * Get the length of the raster header...
+ */
+
+ if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1)
+ len = sizeof(cups_page_header_t);
+ else
+ len = sizeof(cups_page_header2_t);
+
+ /*
+ * Read the header...
+ */
+
+ memset(&(r->header), 0, sizeof(r->header));
+
+ if (cups_raster_read(r, (unsigned char *)&(r->header), len) < len)
+ return (0);
+
+ /*
+ * Swap bytes as needed...
+ */
+
+ if (r->swapped)
+ {
+ unsigned *s, /* Current word */
+ temp; /* Temporary copy */
+
+
+ DEBUG_puts("Swapping header bytes...");
+
+ for (len = 81, s = &(r->header.AdvanceDistance);
+ len > 0;
+ len --, s ++)
+ {
+ DEBUG_printf(("%08x =>", *s));
+
+ temp = *s;
+ *s = ((temp & 0xff) << 24) |
+ ((temp & 0xff00) << 8) |
+ ((temp & 0xff0000) >> 8) |
+ ((temp & 0xff000000) >> 24);
+
+ DEBUG_printf((" %08x\n", *s));
+ }
+ }
+
+ /*
+ * Update the header and row count...
+ */
+
+ cups_raster_update(r);
+
+ return (1);
+}
+
+
+/*
+ * 'cups_raster_io()' - Read/write bytes from a context, handling interruptions.
+ */
+
+static int /* O - Bytes read or -1 */
+cups_raster_io(cups_raster_t *r, /* I - Raster stream */
+ unsigned char *buf, /* I - Buffer for read/write */
+ int bytes) /* I - Number of bytes to read/write */
+{
+ ssize_t count; /* Number of bytes read/written */
+ size_t total; /* Total bytes read/written */
+
+
+ DEBUG_printf(("4cups_raster_io(r=%p, buf=%p, bytes=%d)", r, buf, bytes));
+
+ for (total = 0; total < bytes; total += count, buf += count)
+ {
+ count = (*r->iocb)(r->ctx, buf, bytes - total);
+
+ DEBUG_printf(("5cups_raster_io: count=%d, total=%d", (int)count,
+ (int)total));
+ if (count == 0)
+ return (0);
+ else if (count < 0)
+ return (-1);
+ }
+
+ return ((int)total);
+}
+
+
+/*
+ * 'cups_raster_read()' - Read through the raster buffer.
+ */
+
+static int /* O - Number of bytes read */
+cups_raster_read(cups_raster_t *r, /* I - Raster stream */
+ unsigned char *buf, /* I - Buffer */
+ int bytes) /* I - Number of bytes to read */
+{
+ int count, /* Number of bytes read */
+ remaining, /* Remaining bytes in buffer */
+ total; /* Total bytes read */
+
+
+ DEBUG_printf(("cups_raster_read(r=%p, buf=%p, bytes=%d)\n", r, buf, bytes));
+
+ if (!r->compressed)
+ return (cups_raster_io(r, buf, bytes));
+
+ /*
+ * Allocate a read buffer as needed...
+ */
+
+ count = 2 * r->header.cupsBytesPerLine;
+
+ if ((size_t)count > r->bufsize)
+ {
+ int offset = r->bufptr - r->buffer; /* Offset to current start of buffer */
+ int end = r->bufend - r->buffer; /* Offset to current end of buffer */
+ unsigned char *rptr; /* Pointer in read buffer */
+
+ if (r->buffer)
+ rptr = realloc(r->buffer, count);
+ else
+ rptr = malloc(count);
+
+ if (!rptr)
+ return (0);
+
+ r->buffer = rptr;
+ r->bufptr = rptr + offset;
+ r->bufend = rptr + end;
+ r->bufsize = count;
+ }
+
+ /*
+ * Loop until we have read everything...
+ */
+
+ for (total = 0, remaining = r->bufend - r->bufptr;
+ total < bytes;
+ total += count, buf += count)
+ {
+ count = bytes - total;
+
+ DEBUG_printf(("count=%d, remaining=%d, buf=%p, bufptr=%p, bufend=%p...\n",
+ count, remaining, buf, r->bufptr, r->bufend));
+
+ if (remaining == 0)
+ {
+ if (count < 16)
+ {
+ /*
+ * Read into the raster buffer and then copy...
+ */
+
+ remaining = (*r->iocb)(r->ctx, r->buffer, r->bufsize);
+ if (remaining <= 0)
+ return (0);
+
+ r->bufptr = r->buffer;
+ r->bufend = r->buffer + remaining;
+ }
+ else
+ {
+ /*
+ * Read directly into "buf"...
+ */
+
+ count = (*r->iocb)(r->ctx, buf, count);
+
+ if (count <= 0)
+ return (0);
+
+ continue;
+ }
+ }
+
+ /*
+ * Copy bytes from raster buffer to "buf"...
+ */
+
+ if (count > remaining)
+ count = remaining;
+
+ if (count == 1)
+ {
+ /*
+ * Copy 1 byte...
+ */
+
+ *buf = *(r->bufptr)++;
+ remaining --;
+ }
+ else if (count < 128)
+ {
+ /*
+ * Copy up to 127 bytes without using memcpy(); this is
+ * faster because it avoids an extra function call and is
+ * often further optimized by the compiler...
+ */
+
+ unsigned char *bufptr; /* Temporary buffer pointer */
+
+ remaining -= count;
+
+ for (bufptr = r->bufptr; count > 0; count --, total ++)
+ *buf++ = *bufptr++;
+
+ r->bufptr = bufptr;
+ }
+ else
+ {
+ /*
+ * Use memcpy() for a large read...
+ */
+
+ memcpy(buf, r->bufptr, count);
+ r->bufptr += count;
+ remaining -= count;
+ }
+ }
+
+ return (total);
+}
+
+
+/*
+ * 'cups_raster_update()' - Update the raster header and row count for the
+ * current page.
+ */
+
+static void
+cups_raster_update(cups_raster_t *r) /* I - Raster stream */
+{
+ if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1 ||
+ r->header.cupsNumColors == 0)
+ {
+ /*
+ * Set the "cupsNumColors" field according to the colorspace...
+ */
+
+ switch (r->header.cupsColorSpace)
+ {
+ case CUPS_CSPACE_W :
+ case CUPS_CSPACE_K :
+ case CUPS_CSPACE_WHITE :
+ case CUPS_CSPACE_GOLD :
+ case CUPS_CSPACE_SILVER :
+ case CUPS_CSPACE_SW :
+ r->header.cupsNumColors = 1;
+ break;
+
+ case CUPS_CSPACE_RGB :
+ case CUPS_CSPACE_CMY :
+ case CUPS_CSPACE_YMC :
+ case CUPS_CSPACE_CIEXYZ :
+ case CUPS_CSPACE_CIELab :
+ case CUPS_CSPACE_SRGB :
+ case CUPS_CSPACE_ADOBERGB :
+ case CUPS_CSPACE_ICC1 :
+ case CUPS_CSPACE_ICC2 :
+ case CUPS_CSPACE_ICC3 :
+ case CUPS_CSPACE_ICC4 :
+ case CUPS_CSPACE_ICC5 :
+ case CUPS_CSPACE_ICC6 :
+ case CUPS_CSPACE_ICC7 :
+ case CUPS_CSPACE_ICC8 :
+ case CUPS_CSPACE_ICC9 :
+ case CUPS_CSPACE_ICCA :
+ case CUPS_CSPACE_ICCB :
+ case CUPS_CSPACE_ICCC :
+ case CUPS_CSPACE_ICCD :
+ case CUPS_CSPACE_ICCE :
+ case CUPS_CSPACE_ICCF :
+ r->header.cupsNumColors = 3;
+ break;
+
+ case CUPS_CSPACE_RGBA :
+ case CUPS_CSPACE_RGBW :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_YMCK :
+ case CUPS_CSPACE_KCMY :
+ case CUPS_CSPACE_GMCK :
+ case CUPS_CSPACE_GMCS :
+ r->header.cupsNumColors = 4;
+ break;
+
+ case CUPS_CSPACE_KCMYcm :
+ if (r->header.cupsBitsPerPixel < 8)
+ r->header.cupsNumColors = 6;
+ else
+ r->header.cupsNumColors = 4;
+ break;
+
+ case CUPS_CSPACE_DEVICE1 :
+ case CUPS_CSPACE_DEVICE2 :
+ case CUPS_CSPACE_DEVICE3 :
+ case CUPS_CSPACE_DEVICE4 :
+ case CUPS_CSPACE_DEVICE5 :
+ case CUPS_CSPACE_DEVICE6 :
+ case CUPS_CSPACE_DEVICE7 :
+ case CUPS_CSPACE_DEVICE8 :
+ case CUPS_CSPACE_DEVICE9 :
+ case CUPS_CSPACE_DEVICEA :
+ case CUPS_CSPACE_DEVICEB :
+ case CUPS_CSPACE_DEVICEC :
+ case CUPS_CSPACE_DEVICED :
+ case CUPS_CSPACE_DEVICEE :
+ case CUPS_CSPACE_DEVICEF :
+ r->header.cupsNumColors = r->header.cupsColorSpace -
+ CUPS_CSPACE_DEVICE1 + 1;
+ break;
+ }
+ }
+
+ /*
+ * Set the number of bytes per pixel/color...
+ */
+
+ if (r->header.cupsColorOrder == CUPS_ORDER_CHUNKED)
+ r->bpp = (r->header.cupsBitsPerPixel + 7) / 8;
+ else
+ r->bpp = (r->header.cupsBitsPerColor + 7) / 8;
+
+ /*
+ * Set the number of remaining rows...
+ */
+
+ if (r->header.cupsColorOrder == CUPS_ORDER_PLANAR)
+ r->remaining = r->header.cupsHeight * r->header.cupsNumColors;
+ else
+ r->remaining = r->header.cupsHeight;
+
+ /*
+ * Allocate the compression buffer...
+ */
+
+ if (r->compressed)
+ {
+ if (r->pixels != NULL)
+ free(r->pixels);
+
+ r->pixels = calloc(r->header.cupsBytesPerLine, 1);
+ r->pcurrent = r->pixels;
+ r->pend = r->pixels + r->header.cupsBytesPerLine;
+ r->count = 0;
+ }
+}
+
+
+/*
+ * 'cups_raster_write()' - Write a row of compressed raster data...
+ */
+
+static int /* O - Number of bytes written */
+cups_raster_write(
+ cups_raster_t *r, /* I - Raster stream */
+ const unsigned char *pixels) /* I - Pixel data to write */
+{
+ const unsigned char *start, /* Start of sequence */
+ *ptr, /* Current pointer in sequence */
+ *pend, /* End of raster buffer */
+ *plast; /* Pointer to last pixel */
+ unsigned char *wptr; /* Pointer into write buffer */
+ int bpp, /* Bytes per pixel */
+ count; /* Count */
+
+
+ DEBUG_printf(("cups_raster_write(r=%p, pixels=%p)\n", r, pixels));
+
+ /*
+ * Allocate a write buffer as needed...
+ */
+
+ count = r->header.cupsBytesPerLine * 2;
+ if ((size_t)count > r->bufsize)
+ {
+ if (r->buffer)
+ wptr = realloc(r->buffer, count);
+ else
+ wptr = malloc(count);
+
+ if (!wptr)
+ return (-1);
+
+ r->buffer = wptr;
+ r->bufsize = count;
+ }
+
+ /*
+ * Write the row repeat count...
+ */
+
+ bpp = r->bpp;
+ pend = pixels + r->header.cupsBytesPerLine;
+ plast = pend - bpp;
+ wptr = r->buffer;
+ *wptr++ = r->count - 1;
+
+ /*
+ * Write using a modified PackBits compression...
+ */
+
+ for (ptr = pixels; ptr < pend;)
+ {
+ start = ptr;
+ ptr += bpp;
+
+ if (ptr == pend)
+ {
+ /*
+ * Encode a single pixel at the end...
+ */
+
+ *wptr++ = 0;
+ for (count = bpp; count > 0; count --)
+ *wptr++ = *start++;
+ }
+ else if (!memcmp(start, ptr, bpp))
+ {
+ /*
+ * Encode a sequence of repeating pixels...
+ */
+
+ for (count = 2; count < 128 && ptr < plast; count ++, ptr += bpp)
+ if (memcmp(ptr, ptr + bpp, bpp))
+ break;
+
+ *wptr++ = count - 1;
+ for (count = bpp; count > 0; count --)
+ *wptr++ = *ptr++;
+ }
+ else
+ {
+ /*
+ * Encode a sequence of non-repeating pixels...
+ */
+
+ for (count = 1; count < 128 && ptr < plast; count ++, ptr += bpp)
+ if (!memcmp(ptr, ptr + bpp, bpp))
+ break;
+
+ if (ptr >= plast && count < 128)
+ {
+ count ++;
+ ptr += bpp;
+ }
+
+ *wptr++ = 257 - count;
+
+ count *= bpp;
+ memcpy(wptr, start, count);
+ wptr += count;
+ }
+ }
+
+ return (cups_raster_io(r, r->buffer, wptr - r->buffer));
+}
+
+
+/*
+ * 'cups_read_fd()' - Read bytes from a file.
+ */
+
+static ssize_t /* O - Bytes read or -1 */
+cups_read_fd(void *ctx, /* I - File descriptor as pointer */
+ unsigned char *buf, /* I - Buffer for read */
+ size_t bytes) /* I - Maximum number of bytes to read */
+{
+ int fd = (int)((intptr_t)ctx);
+ /* File descriptor */
+ ssize_t count; /* Number of bytes read */
+
+
+ while ((count = read(fd, buf, bytes)) < 0)
+ if (errno != EINTR && errno != EAGAIN)
+ return (-1);
+
+ return (count);
+}
+
+
+/*
+ * 'cups_swap()' - Swap bytes in raster data...
+ */
+
+static void
+cups_swap(unsigned char *buf, /* I - Buffer to swap */
+ int bytes) /* I - Number of bytes to swap */
+{
+ unsigned char even, odd; /* Temporary variables */
+
+
+ bytes /= 2;
+
+ while (bytes > 0)
+ {
+ even = buf[0];
+ odd = buf[1];
+ buf[0] = odd;
+ buf[1] = even;
+
+ buf += 2;
+ bytes --;
+ }
+}
+
+
+/*
+ * 'cups_write_fd()' - Write bytes to a file.
+ */
+
+static ssize_t /* O - Bytes written or -1 */
+cups_write_fd(void *ctx, /* I - File descriptor pointer */
+ unsigned char *buf, /* I - Bytes to write */
+ size_t bytes) /* I - Number of bytes to write */
+{
+ int fd = (int)((intptr_t)ctx);
+ /* File descriptor */
+ ssize_t count; /* Number of bytes written */
+
+
+ while ((count = write(fd, buf, bytes)) < 0)
+ if (errno != EINTR && errno != EAGAIN)
+ return (-1);
+
+ return (count);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/rasterbench.c b/filter/rasterbench.c
new file mode 100644
index 000000000..69e139d37
--- /dev/null
+++ b/filter/rasterbench.c
@@ -0,0 +1,355 @@
+/*
+ * "$Id$"
+ *
+ * Raster benchmark program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Benchmark the raster read/write functions.
+ * compute_median() - Compute the median time for a test.
+ * read_test() - Benchmark the raster read functions.
+ * write_test() - Benchmark the raster write functions.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <config.h>
+#include <cups/raster.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+/*
+ * Constants...
+ */
+
+#define TEST_WIDTH 1024
+#define TEST_HEIGHT 1024
+#define TEST_PAGES 16
+#define TEST_PASSES 20
+
+
+/*
+ * Local functions...
+ */
+
+static double compute_median(double *secs);
+static double get_time(void);
+static void read_test(int fd);
+static int run_read_test(void);
+static void write_test(int fd, cups_mode_t mode);
+
+
+/*
+ * 'main()' - Benchmark the raster read/write functions.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ int ras_fd, /* File descriptor for read process */
+ status; /* Exit status of read process */
+ double start_secs, /* Start time */
+ write_secs, /* Write time */
+ read_secs, /* Read time */
+ pass_secs[TEST_PASSES]; /* Total test times */
+ cups_mode_t mode; /* Write mode */
+
+
+ /*
+ * See if we have anything on the command-line...
+ */
+
+ if (argc > 2 || (argc == 2 && strcmp(argv[1], "-z")))
+ {
+ puts("Usage: rasterbench [-z]");
+ return (1);
+ }
+
+ mode = argc > 1 ? CUPS_RASTER_WRITE_COMPRESSED : CUPS_RASTER_WRITE;
+
+ /*
+ * Ignore SIGPIPE...
+ */
+
+ signal(SIGPIPE, SIG_IGN);
+
+ /*
+ * Run the tests several times to get a good average...
+ */
+
+ printf("Test read/write speed of %d pages, %dx%d pixels...\n\n",
+ TEST_PAGES, TEST_WIDTH, TEST_HEIGHT);
+ for (i = 0; i < TEST_PASSES; i ++)
+ {
+ printf("PASS %2d: ", i + 1);
+ fflush(stdout);
+
+ ras_fd = run_read_test();
+ start_secs = get_time();
+
+ write_test(ras_fd, mode);
+
+ write_secs = get_time();
+ printf(" %.3f write,", write_secs - start_secs);
+ fflush(stdout);
+
+ close(ras_fd);
+ wait(&status);
+
+ read_secs = get_time();
+ pass_secs[i] = read_secs - start_secs;
+ printf(" %.3f read, %.3f total\n", read_secs - write_secs, pass_secs[i]);
+ }
+
+ printf("\nMedian Total Time: %.3f seconds per document\n",
+ compute_median(pass_secs));
+
+ return (0);
+}
+
+
+/*
+ * 'compute_median()' - Compute the median time for a test.
+ */
+
+static double /* O - Median time in seconds */
+compute_median(double *secs) /* I - Array of time samples */
+{
+ int i, j; /* Looping vars */
+ double temp; /* Swap variable */
+
+
+ /*
+ * Sort the array into ascending order using a quicky bubble sort...
+ */
+
+ for (i = 0; i < (TEST_PASSES - 1); i ++)
+ for (j = i + 1; j < TEST_PASSES; j ++)
+ if (secs[i] > secs[j])
+ {
+ temp = secs[i];
+ secs[i] = secs[j];
+ secs[j] = temp;
+ }
+
+ /*
+ * Return the average of the middle two samples...
+ */
+
+ return (0.5 * (secs[TEST_PASSES / 2 - 1] + secs[TEST_PASSES / 2]));
+}
+
+
+/*
+ * 'get_time()' - Get the current time in seconds.
+ */
+
+static double /* O - Time in seconds */
+get_time(void)
+{
+ struct timeval curtime; /* Current time */
+
+
+ gettimeofday(&curtime, NULL);
+ return (curtime.tv_sec + 0.000001 * curtime.tv_usec);
+}
+
+
+/*
+ * 'read_test()' - Benchmark the raster read functions.
+ */
+
+static void
+read_test(int fd) /* I - File descriptor to read from */
+{
+ int y; /* Looping var */
+ cups_raster_t *r; /* Raster stream */
+ cups_page_header2_t header; /* Page header */
+ unsigned char buffer[8 * TEST_WIDTH];
+ /* Read buffer */
+
+
+ /*
+ * Test read speed...
+ */
+
+ if ((r = cupsRasterOpen(fd, CUPS_RASTER_READ)) == NULL)
+ {
+ perror("Unable to create raster input stream");
+ return;
+ }
+
+ while (cupsRasterReadHeader2(r, &header))
+ {
+ for (y = 0; y < header.cupsHeight; y ++)
+ cupsRasterReadPixels(r, buffer, header.cupsBytesPerLine);
+ }
+
+ cupsRasterClose(r);
+}
+
+
+/*
+ * 'run_read_test()' - Run the read test as a child process via pipes.
+ */
+
+static int /* O - Standard input of child */
+run_read_test(void)
+{
+ int ras_pipes[2]; /* Raster data pipes */
+ int pid; /* Child process ID */
+
+
+ if (pipe(ras_pipes))
+ return (-1);
+
+ if ((pid = fork()) < 0)
+ {
+ /*
+ * Fork error - return -1 on error...
+ */
+
+ close(ras_pipes[0]);
+ close(ras_pipes[1]);
+
+ return (-1);
+ }
+ else if (pid == 0)
+ {
+ /*
+ * Child comes here - read data from the input pipe...
+ */
+
+ close(ras_pipes[1]);
+ read_test(ras_pipes[0]);
+ exit(0);
+ }
+ else
+ {
+ /*
+ * Parent comes here - return the output pipe...
+ */
+
+ close(ras_pipes[0]);
+ return (ras_pipes[1]);
+ }
+}
+
+
+/*
+ * 'write_test()' - Benchmark the raster write functions.
+ */
+
+static void
+write_test(int fd, /* I - File descriptor to write to */
+ cups_mode_t mode) /* I - Write mode */
+{
+ int page, x, y; /* Looping vars */
+ int count; /* Number of bytes to set */
+ cups_raster_t *r; /* Raster stream */
+ cups_page_header2_t header; /* Page header */
+ unsigned char data[32][8 * TEST_WIDTH];
+ /* Raster data to write */
+
+
+ /*
+ * Create a combination of random data and repeated data to simulate
+ * text with some whitespace.
+ */
+
+ CUPS_SRAND(time(NULL));
+
+ memset(data, 0, sizeof(data));
+
+ for (y = 0; y < 28; y ++)
+ {
+ for (x = CUPS_RAND() & 127, count = (CUPS_RAND() & 15) + 1;
+ x < sizeof(data[0]);
+ x ++, count --)
+ {
+ if (count <= 0)
+ {
+ x += (CUPS_RAND() & 15) + 1;
+ count = (CUPS_RAND() & 15) + 1;
+
+ if (x >= sizeof(data[0]))
+ break;
+ }
+
+ data[y][x] = CUPS_RAND();
+ }
+ }
+
+ /*
+ * Test write speed...
+ */
+
+ if ((r = cupsRasterOpen(fd, mode)) == NULL)
+ {
+ perror("Unable to create raster output stream");
+ return;
+ }
+
+ for (page = 0; page < TEST_PAGES; page ++)
+ {
+ memset(&header, 0, sizeof(header));
+ header.cupsWidth = TEST_WIDTH;
+ header.cupsHeight = TEST_HEIGHT;
+ header.cupsBytesPerLine = TEST_WIDTH;
+
+ if (page & 1)
+ {
+ header.cupsBytesPerLine *= 4;
+ header.cupsColorSpace = CUPS_CSPACE_CMYK;
+ header.cupsColorOrder = CUPS_ORDER_CHUNKED;
+ }
+ else
+ {
+ header.cupsColorSpace = CUPS_CSPACE_K;
+ header.cupsColorOrder = CUPS_ORDER_BANDED;
+ }
+
+ if (page & 2)
+ {
+ header.cupsBytesPerLine *= 2;
+ header.cupsBitsPerColor = 16;
+ header.cupsBitsPerPixel = (page & 1) ? 64 : 16;
+ }
+ else
+ {
+ header.cupsBitsPerColor = 8;
+ header.cupsBitsPerPixel = (page & 1) ? 32 : 8;
+ }
+
+ cupsRasterWriteHeader2(r, &header);
+
+ for (y = 0; y < TEST_HEIGHT; y ++)
+ cupsRasterWritePixels(r, data[y & 31], header.cupsBytesPerLine);
+ }
+
+ cupsRasterClose(r);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/rastertoepson.c b/filter/rastertoepson.c
new file mode 100644
index 000000000..6045e9add
--- /dev/null
+++ b/filter/rastertoepson.c
@@ -0,0 +1,1160 @@
+/*
+ * "$Id$"
+ *
+ * EPSON ESC/P and ESC/P2 filter for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * Setup() - Prepare the printer for printing.
+ * StartPage() - Start a page of graphics.
+ * EndPage() - Finish a page of graphics.
+ * Shutdown() - Shutdown the printer.
+ * CompressData() - Compress a line of graphics.
+ * OutputLine() - Output a line of graphics.
+ * main() - Main entry and processing of driver.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <cups/ppd.h>
+#include <cups/string-private.h>
+#include <cups/language-private.h>
+#include <cups/raster.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+
+
+/*
+ * Model numbers...
+ */
+
+#define EPSON_9PIN 0
+#define EPSON_24PIN 1
+#define EPSON_COLOR 2
+#define EPSON_PHOTO 3
+#define EPSON_ICOLOR 4
+#define EPSON_IPHOTO 5
+
+
+/*
+ * Macros...
+ */
+
+#define pwrite(s,n) fwrite((s), 1, (n), stdout)
+
+
+/*
+ * Globals...
+ */
+
+unsigned char *Planes[6], /* Output buffers */
+ *CompBuffer, /* Compression buffer */
+ *LineBuffers[2]; /* Line bitmap buffers */
+int Model, /* Model number */
+ NumPlanes, /* Number of color planes */
+ Feed, /* Number of lines to skip */
+ EjectPage; /* Eject the page when done? */
+int DotBit, /* Bit in buffers */
+ DotBytes, /* # bytes in a dot column */
+ DotColumns, /* # columns in 1/60 inch */
+ LineCount, /* # of lines processed */
+ EvenOffset, /* Offset into 'even' buffers */
+ OddOffset, /* Offset into 'odd' buffers */
+ Shingling, /* Shingle output? */
+ Canceled; /* Has the current job been canceled? */
+
+
+/*
+ * Prototypes...
+ */
+
+void Setup(void);
+void StartPage(const ppd_file_t *ppd, const cups_page_header2_t *header);
+void EndPage(const cups_page_header2_t *header);
+void Shutdown(void);
+
+void CancelJob(int sig);
+void CompressData(const unsigned char *line, int length, int plane,
+ int type, int xstep, int ystep);
+void OutputLine(const cups_page_header2_t *header);
+void OutputRows(const cups_page_header2_t *header, int row);
+
+
+/*
+ * 'Setup()' - Prepare the printer for printing.
+ */
+
+void
+Setup(void)
+{
+ const char *device_uri; /* The device for the printer... */
+
+
+ /*
+ * EPSON USB printers need an additional command issued at the
+ * beginning of each job to exit from "packet" mode...
+ */
+
+ if ((device_uri = getenv("DEVICE_URI")) != NULL &&
+ strncmp(device_uri, "usb:", 4) == 0 && Model >= EPSON_ICOLOR)
+ pwrite("\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@", 29);
+}
+
+
+/*
+ * 'StartPage()' - Start a page of graphics.
+ */
+
+void
+StartPage(
+ const ppd_file_t *ppd, /* I - PPD file */
+ const cups_page_header2_t *header) /* I - Page header */
+{
+ int n, t; /* Numbers */
+ int plane; /* Looping var */
+
+
+ /*
+ * Send a reset sequence.
+ */
+
+ if (ppd && ppd->nickname && strstr(ppd->nickname, "OKIDATA") != NULL)
+ printf("\033{A"); /* Set EPSON emulation mode */
+
+ printf("\033@");
+
+ /*
+ * See which type of printer we are using...
+ */
+
+ switch (Model)
+ {
+ case EPSON_9PIN :
+ case EPSON_24PIN :
+ printf("\033P\022"); /* Set 10 CPI */
+
+ if (header->HWResolution[0] == 360 || header->HWResolution[0] == 240)
+ {
+ printf("\033x1"); /* LQ printing */
+ printf("\033U1"); /* Unidirectional */
+ }
+ else
+ {
+ printf("\033x0"); /* Draft printing */
+ printf("\033U0"); /* Bidirectional */
+ }
+
+ printf("\033l%c\033Q%c", 0, /* Side margins */
+ (int)(10.0 * header->PageSize[0] / 72.0 + 0.5));
+ printf("\033\062\033C%c", /* Page length in 1/6th inches */
+ (int)(header->PageSize[1] / 12.0 + 0.5));
+ printf("\033N%c", 0); /* Bottom margin */
+ printf("\033O"); /* No perforation skip */
+
+ /*
+ * Setup various buffer limits...
+ */
+
+ DotBytes = header->cupsRowCount / 8;
+ DotColumns = header->HWResolution[0] / 60;
+ Shingling = 0;
+
+ if (Model == EPSON_9PIN)
+ printf("\033\063\030"); /* Set line feed */
+ else
+ switch (header->HWResolution[0])
+ {
+ case 60:
+ case 120 :
+ case 240 :
+ printf("\033\063\030"); /* Set line feed */
+ break;
+
+ case 180 :
+ case 360 :
+ Shingling = 1;
+
+ if (header->HWResolution[1] == 180)
+ printf("\033\063\010");/* Set line feed */
+ else
+ printf("\033+\010"); /* Set line feed */
+ break;
+ }
+ break;
+
+ default :
+ /*
+ * Set graphics mode...
+ */
+
+ pwrite("\033(G\001\000\001", 6); /* Graphics mode */
+
+ /*
+ * Set the media size...
+ */
+
+ if (Model < EPSON_ICOLOR)
+ {
+ pwrite("\033(U\001\000", 5); /* Resolution/units */
+ putchar(3600 / header->HWResolution[1]);
+ }
+ else
+ {
+ pwrite("\033(U\005\000", 5);
+ putchar(1440 / header->HWResolution[1]);
+ putchar(1440 / header->HWResolution[1]);
+ putchar(1440 / header->HWResolution[0]);
+ putchar(0xa0); /* n/1440ths... */
+ putchar(0x05);
+ }
+
+ n = header->PageSize[1] * header->HWResolution[1] / 72.0;
+
+ pwrite("\033(C\002\000", 5); /* Page length */
+ putchar(n);
+ putchar(n >> 8);
+
+ if (ppd)
+ t = (ppd->sizes[1].length - ppd->sizes[1].top) *
+ header->HWResolution[1] / 72.0;
+ else
+ t = 0;
+
+ pwrite("\033(c\004\000", 5); /* Top & bottom margins */
+ putchar(t);
+ putchar(t >> 8);
+ putchar(n);
+ putchar(n >> 8);
+
+ if (header->HWResolution[1] == 720)
+ {
+ pwrite("\033(i\001\000\001", 6); /* Microweave */
+ pwrite("\033(e\002\000\000\001", 7); /* Small dots */
+ }
+
+ pwrite("\033(V\002\000\000\000", 7); /* Set absolute position 0 */
+
+ DotBytes = 0;
+ DotColumns = 0;
+ Shingling = 0;
+ break;
+ }
+
+ /*
+ * Set other stuff...
+ */
+
+ if (header->cupsColorSpace == CUPS_CSPACE_CMY)
+ NumPlanes = 3;
+ else if (header->cupsColorSpace == CUPS_CSPACE_KCMY)
+ NumPlanes = 4;
+ else if (header->cupsColorSpace == CUPS_CSPACE_KCMYcm)
+ NumPlanes = 6;
+ else
+ NumPlanes = 1;
+
+ Feed = 0; /* No blank lines yet */
+
+ /*
+ * Allocate memory for a line/row of graphics...
+ */
+
+ if ((Planes[0] = malloc(header->cupsBytesPerLine)) == NULL)
+ {
+ fputs("ERROR: Unable to allocate memory\n", stderr);
+ exit(1);
+ }
+
+ for (plane = 1; plane < NumPlanes; plane ++)
+ Planes[plane] = Planes[0] + plane * header->cupsBytesPerLine / NumPlanes;
+
+ if (header->cupsCompression || DotBytes)
+ {
+ if ((CompBuffer = calloc(2, header->cupsWidth)) == NULL)
+ {
+ fputs("ERROR: Unable to allocate memory\n", stderr);
+ exit(1);
+ }
+ }
+ else
+ CompBuffer = NULL;
+
+ if (DotBytes)
+ {
+ if ((LineBuffers[0] = calloc(DotBytes,
+ header->cupsWidth * (Shingling + 1))) == NULL)
+ {
+ fputs("ERROR: Unable to allocate memory\n", stderr);
+ exit(1);
+ }
+
+ LineBuffers[1] = LineBuffers[0] + DotBytes * header->cupsWidth;
+ DotBit = 128;
+ LineCount = 0;
+ EvenOffset = 0;
+ OddOffset = 0;
+ }
+}
+
+
+/*
+ * 'EndPage()' - Finish a page of graphics.
+ */
+
+void
+EndPage(
+ const cups_page_header2_t *header) /* I - Page header */
+{
+ if (DotBytes && header)
+ {
+ /*
+ * Flush remaining graphics as needed...
+ */
+
+ if (!Shingling)
+ {
+ if (DotBit < 128 || EvenOffset)
+ OutputRows(header, 0);
+ }
+ else if (OddOffset > EvenOffset)
+ {
+ OutputRows(header, 1);
+ OutputRows(header, 0);
+ }
+ else
+ {
+ OutputRows(header, 0);
+ OutputRows(header, 1);
+ }
+ }
+
+ /*
+ * Eject the current page...
+ */
+
+ putchar(12); /* Form feed */
+ fflush(stdout);
+
+ /*
+ * Free memory...
+ */
+
+ free(Planes[0]);
+
+ if (CompBuffer)
+ free(CompBuffer);
+
+ if (DotBytes)
+ free(LineBuffers[0]);
+}
+
+
+/*
+ * 'Shutdown()' - Shutdown the printer.
+ */
+
+void
+Shutdown(void)
+{
+ /*
+ * Send a reset sequence.
+ */
+
+ printf("\033@");
+}
+
+
+/*
+ * 'CancelJob()' - Cancel the current job...
+ */
+
+void
+CancelJob(int sig) /* I - Signal */
+{
+ (void)sig;
+
+ Canceled = 1;
+}
+
+
+/*
+ * 'CompressData()' - Compress a line of graphics.
+ */
+
+void
+CompressData(const unsigned char *line, /* I - Data to compress */
+ int length,/* I - Number of bytes */
+ int plane, /* I - Color plane */
+ int type, /* I - Type of compression */
+ int xstep, /* I - X resolution */
+ int ystep) /* I - Y resolution */
+{
+ const unsigned char *line_ptr, /* Current byte pointer */
+ *line_end, /* End-of-line byte pointer */
+ *start; /* Start of compression sequence */
+ unsigned char *comp_ptr, /* Pointer into compression buffer */
+ temp; /* Current byte */
+ int count; /* Count of bytes for output */
+ static int ctable[6] = { 0, 2, 1, 4, 18, 17 };
+ /* KCMYcm color values */
+
+
+ /*
+ * Setup pointers...
+ */
+
+ line_ptr = line;
+ line_end = line + length;
+
+ /*
+ * Do depletion for 720 DPI printing...
+ */
+
+ if (ystep == 5)
+ {
+ for (comp_ptr = (unsigned char *)line; comp_ptr < line_end;)
+ {
+ /*
+ * Grab the current byte...
+ */
+
+ temp = *comp_ptr;
+
+ /*
+ * Check adjacent bits...
+ */
+
+ if ((temp & 0xc0) == 0xc0)
+ temp &= 0xbf;
+ if ((temp & 0x60) == 0x60)
+ temp &= 0xdf;
+ if ((temp & 0x30) == 0x30)
+ temp &= 0xef;
+ if ((temp & 0x18) == 0x18)
+ temp &= 0xf7;
+ if ((temp & 0x0c) == 0x0c)
+ temp &= 0xfb;
+ if ((temp & 0x06) == 0x06)
+ temp &= 0xfd;
+ if ((temp & 0x03) == 0x03)
+ temp &= 0xfe;
+
+ *comp_ptr++ = temp;
+
+ /*
+ * Check the last bit in the current byte and the first bit in the
+ * next byte...
+ */
+
+ if ((temp & 0x01) && comp_ptr < line_end && *comp_ptr & 0x80)
+ *comp_ptr &= 0x7f;
+ }
+ }
+
+ switch (type)
+ {
+ case 0 :
+ /*
+ * Do no compression...
+ */
+ break;
+
+ case 1 :
+ /*
+ * Do TIFF pack-bits encoding...
+ */
+
+ comp_ptr = CompBuffer;
+
+ while (line_ptr < line_end)
+ {
+ if ((line_ptr + 1) >= line_end)
+ {
+ /*
+ * Single byte on the end...
+ */
+
+ *comp_ptr++ = 0x00;
+ *comp_ptr++ = *line_ptr++;
+ }
+ else if (line_ptr[0] == line_ptr[1])
+ {
+ /*
+ * Repeated sequence...
+ */
+
+ line_ptr ++;
+ count = 2;
+
+ while (line_ptr < (line_end - 1) &&
+ line_ptr[0] == line_ptr[1] &&
+ count < 127)
+ {
+ line_ptr ++;
+ count ++;
+ }
+
+ *comp_ptr++ = 257 - count;
+ *comp_ptr++ = *line_ptr++;
+ }
+ else
+ {
+ /*
+ * Non-repeated sequence...
+ */
+
+ start = line_ptr;
+ line_ptr ++;
+ count = 1;
+
+ while (line_ptr < (line_end - 1) &&
+ line_ptr[0] != line_ptr[1] &&
+ count < 127)
+ {
+ line_ptr ++;
+ count ++;
+ }
+
+ *comp_ptr++ = count - 1;
+
+ memcpy(comp_ptr, start, count);
+ comp_ptr += count;
+ }
+ }
+
+ line_ptr = CompBuffer;
+ line_end = comp_ptr;
+ break;
+ }
+
+ putchar(0x0d); /* Move print head to left margin */
+
+ if (Model < EPSON_ICOLOR)
+ {
+ /*
+ * Do graphics the "old" way...
+ */
+
+ if (NumPlanes > 1)
+ {
+ /*
+ * Set the color...
+ */
+
+ if (plane > 3)
+ printf("\033(r%c%c%c%c", 2, 0, 1, ctable[plane] & 15);
+ /* Set extended color */
+ else if (NumPlanes == 3)
+ printf("\033r%c", ctable[plane + 1]);
+ /* Set color */
+ else
+ printf("\033r%c", ctable[plane]); /* Set color */
+ }
+
+ /*
+ * Send a raster plane...
+ */
+
+ length *= 8;
+ printf("\033."); /* Raster graphics */
+ putchar(type);
+ putchar(ystep);
+ putchar(xstep);
+ putchar(1);
+ putchar(length);
+ putchar(length >> 8);
+ }
+ else
+ {
+ /*
+ * Do graphics the "new" way...
+ */
+
+ printf("\033i");
+ putchar(ctable[plane]);
+ putchar(type);
+ putchar(1);
+ putchar(length & 255);
+ putchar(length >> 8);
+ putchar(1);
+ putchar(0);
+ }
+
+ pwrite(line_ptr, line_end - line_ptr);
+ fflush(stdout);
+}
+
+
+/*
+ * 'OutputLine()' - Output a line of graphics.
+ */
+
+void
+OutputLine(
+ const cups_page_header2_t *header) /* I - Page header */
+{
+ if (header->cupsRowCount)
+ {
+ int width;
+ unsigned char *tempptr,
+ *evenptr,
+ *oddptr;
+ register int x;
+ unsigned char bit;
+ const unsigned char *pixel;
+ unsigned char *temp;
+
+
+ /*
+ * Collect bitmap data in the line buffers and write after each buffer.
+ */
+
+ for (x = header->cupsWidth, bit = 128, pixel = Planes[0],
+ temp = CompBuffer;
+ x > 0;
+ x --, temp ++)
+ {
+ if (*pixel & bit)
+ *temp |= DotBit;
+
+ if (bit > 1)
+ bit >>= 1;
+ else
+ {
+ bit = 128;
+ pixel ++;
+ }
+ }
+
+ if (DotBit > 1)
+ DotBit >>= 1;
+ else
+ {
+ /*
+ * Copy the holding buffer to the output buffer, shingling as necessary...
+ */
+
+ if (Shingling && LineCount != 0)
+ {
+ /*
+ * Shingle the output...
+ */
+
+ if (LineCount & 1)
+ {
+ evenptr = LineBuffers[1] + OddOffset;
+ oddptr = LineBuffers[0] + EvenOffset + DotBytes;
+ }
+ else
+ {
+ evenptr = LineBuffers[0] + EvenOffset;
+ oddptr = LineBuffers[1] + OddOffset + DotBytes;
+ }
+
+ for (width = header->cupsWidth, tempptr = CompBuffer;
+ width > 0;
+ width -= 2, tempptr += 2, oddptr += DotBytes * 2,
+ evenptr += DotBytes * 2)
+ {
+ evenptr[0] = tempptr[0];
+ oddptr[0] = tempptr[1];
+ }
+ }
+ else
+ {
+ /*
+ * Don't shingle the output...
+ */
+
+ for (width = header->cupsWidth, tempptr = CompBuffer,
+ evenptr = LineBuffers[0] + EvenOffset;
+ width > 0;
+ width --, tempptr ++, evenptr += DotBytes)
+ *evenptr = tempptr[0];
+ }
+
+ if (Shingling && LineCount != 0)
+ {
+ EvenOffset ++;
+ OddOffset ++;
+
+ if (EvenOffset == DotBytes)
+ {
+ EvenOffset = 0;
+ OutputRows(header, 0);
+ }
+
+ if (OddOffset == DotBytes)
+ {
+ OddOffset = 0;
+ OutputRows(header, 1);
+ }
+ }
+ else
+ {
+ EvenOffset ++;
+
+ if (EvenOffset == DotBytes)
+ {
+ EvenOffset = 0;
+ OutputRows(header, 0);
+ }
+ }
+
+ DotBit = 128;
+ LineCount ++;
+
+ memset(CompBuffer, 0, header->cupsWidth);
+ }
+ }
+ else
+ {
+ int plane; /* Current plane */
+ int bytes; /* Bytes per plane */
+ int xstep, ystep; /* X & Y resolutions */
+
+
+ /*
+ * Write a single line of bitmap data as needed...
+ */
+
+ xstep = 3600 / header->HWResolution[0];
+ ystep = 3600 / header->HWResolution[1];
+ bytes = header->cupsBytesPerLine / NumPlanes;
+
+ for (plane = 0; plane < NumPlanes; plane ++)
+ {
+ /*
+ * Skip blank data...
+ */
+
+ if (!Planes[plane][0] &&
+ memcmp(Planes[plane], Planes[plane] + 1, bytes - 1) == 0)
+ continue;
+
+ /*
+ * Output whitespace as needed...
+ */
+
+ if (Feed > 0)
+ {
+ pwrite("\033(v\002\000", 5); /* Relative vertical position */
+ putchar(Feed);
+ putchar(Feed >> 8);
+
+ Feed = 0;
+ }
+
+ CompressData(Planes[plane], bytes, plane, header->cupsCompression, xstep,
+ ystep);
+ }
+
+ Feed ++;
+ }
+}
+
+
+/*
+ * 'OutputRows()' - Output 8, 24, or 48 rows.
+ */
+
+void
+OutputRows(
+ const cups_page_header2_t *header, /* I - Page image header */
+ int row) /* I - Row number (0 or 1) */
+{
+ unsigned i, n; /* Looping vars */
+ int dot_count, /* Number of bytes to print */
+ dot_min; /* Minimum number of bytes */
+ unsigned char *dot_ptr, /* Pointer to print data */
+ *ptr; /* Current data */
+
+
+ dot_min = DotBytes * DotColumns;
+
+ if (LineBuffers[row][0] != 0 ||
+ memcmp(LineBuffers[row], LineBuffers[row] + 1,
+ header->cupsWidth * DotBytes - 1))
+ {
+ /*
+ * Skip leading space...
+ */
+
+ i = 0;
+ dot_count = header->cupsWidth * DotBytes;
+ dot_ptr = LineBuffers[row];
+
+ while (dot_count >= dot_min && dot_ptr[0] == 0 &&
+ memcmp(dot_ptr, dot_ptr + 1, dot_min - 1) == 0)
+ {
+ i ++;
+ dot_ptr += dot_min;
+ dot_count -= dot_min;
+ }
+
+ /*
+ * Skip trailing space...
+ */
+
+ while (dot_count >= dot_min && dot_ptr[dot_count - dot_min] == 0 &&
+ memcmp(dot_ptr + dot_count - dot_min,
+ dot_ptr + dot_count - dot_min + 1, dot_min - 1) == 0)
+ dot_count -= dot_min;
+
+ /*
+ * Position print head for printing...
+ */
+
+ if (i == 0)
+ putchar('\r');
+ else
+ {
+ putchar(0x1b);
+ putchar('$');
+ putchar(i & 255);
+ putchar(i >> 8);
+ }
+
+ /*
+ * Start bitmap graphics for this line...
+ */
+
+ printf("\033*"); /* Select bit image */
+ switch (header->HWResolution[0])
+ {
+ case 60 : /* 60x60/72 DPI gfx */
+ putchar(0);
+ break;
+ case 120 : /* 120x60/72 DPI gfx */
+ putchar(1);
+ break;
+ case 180 : /* 180 DPI gfx */
+ putchar(39);
+ break;
+ case 240 : /* 240x72 DPI gfx */
+ putchar(3);
+ break;
+ case 360 : /* 360x180/360 DPI gfx */
+ if (header->HWResolution[1] == 180)
+ {
+ if (Shingling && LineCount != 0)
+ putchar(40); /* 360x180 fast */
+ else
+ putchar(41); /* 360x180 slow */
+ }
+ else
+ {
+ if (Shingling && LineCount != 0)
+ putchar(72); /* 360x360 fast */
+ else
+ putchar(73); /* 360x360 slow */
+ }
+ break;
+ }
+
+ n = (unsigned)dot_count / DotBytes;
+ putchar(n & 255);
+ putchar(n / 256);
+
+ /*
+ * Write the graphics data...
+ */
+
+ if (header->HWResolution[0] == 120 ||
+ header->HWResolution[0] == 240)
+ {
+ /*
+ * Need to interleave the dots to avoid hosing the print head...
+ */
+
+ for (n = dot_count / 2, ptr = dot_ptr; n > 0; n --, ptr += 2)
+ {
+ putchar(*ptr);
+ putchar(0);
+ }
+
+ /*
+ * Move the head back and print the odd bytes...
+ */
+
+ if (i == 0)
+ putchar('\r');
+ else
+ {
+ putchar(0x1b);
+ putchar('$');
+ putchar(i & 255);
+ putchar(i >> 8);
+ }
+
+ if (header->HWResolution[0] == 120)
+ printf("\033*\001"); /* Select bit image */
+ else
+ printf("\033*\003"); /* Select bit image */
+
+ n = (unsigned)dot_count / DotBytes;
+ putchar(n & 255);
+ putchar(n / 256);
+
+ for (n = dot_count / 2, ptr = dot_ptr + 1; n > 0; n --, ptr += 2)
+ {
+ putchar(0);
+ putchar(*ptr);
+ }
+ }
+ else
+ pwrite(dot_ptr, dot_count);
+ }
+
+ /*
+ * Feed the paper...
+ */
+
+ putchar('\n');
+
+ if (Shingling && row == 1)
+ {
+ if (header->HWResolution[1] == 360)
+ printf("\n\n\n\n");
+ else
+ printf("\n");
+ }
+
+ fflush(stdout);
+
+ /*
+ * Clear the buffer...
+ */
+
+ memset(LineBuffers[row], 0, header->cupsWidth * DotBytes);
+}
+
+
+/*
+ * 'main()' - Main entry and processing of driver.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int fd; /* File descriptor */
+ cups_raster_t *ras; /* Raster stream for printing */
+ cups_page_header2_t header; /* Page header from file */
+ ppd_file_t *ppd; /* PPD file */
+ int page; /* Current page */
+ int y; /* Current line */
+#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 < 6 || argc > 7)
+ {
+ /*
+ * We don't have the correct number of arguments; write an error message
+ * and return.
+ */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("%s job-id user title copies options [file]"),
+ "rastertoepson");
+ return (1);
+ }
+
+ /*
+ * Open the page stream...
+ */
+
+ if (argc == 7)
+ {
+ if ((fd = open(argv[6], O_RDONLY)) == -1)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open raster file"));
+ sleep(1);
+ return (1);
+ }
+ }
+ else
+ fd = 0;
+
+ ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
+
+ /*
+ * Register a signal handler to eject the current page if the
+ * job is cancelled.
+ */
+
+ Canceled = 0;
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, CancelJob);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = CancelJob;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, CancelJob);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Initialize the print device...
+ */
+
+ ppd = ppdOpenFile(getenv("PPD"));
+ if (!ppd)
+ {
+ ppd_status_t status; /* PPD error */
+ int linenum; /* Line number */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The PPD file could not be opened."));
+
+ status = ppdLastError(&linenum);
+
+ fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
+
+ return (1);
+ }
+
+ Model = ppd->model_number;
+
+ Setup();
+
+ /*
+ * Process pages as needed...
+ */
+
+ page = 0;
+
+ while (cupsRasterReadHeader2(ras, &header))
+ {
+ /*
+ * Write a status message with the page number and number of copies.
+ */
+
+ if (Canceled)
+ break;
+
+ page ++;
+
+ fprintf(stderr, "PAGE: %d %d\n", page, header.NumCopies);
+ _cupsLangPrintFilter(stderr, "INFO", _("Starting page %d."), page);
+
+ /*
+ * Start the page...
+ */
+
+ StartPage(ppd, &header);
+
+ /*
+ * Loop for each line on the page...
+ */
+
+ for (y = 0; y < header.cupsHeight; y ++)
+ {
+ /*
+ * Let the user know how far we have progressed...
+ */
+
+ if (Canceled)
+ break;
+
+ if ((y & 127) == 0)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printing page %d, %d%% complete."),
+ page, 100 * y / header.cupsHeight);
+ fprintf(stderr, "ATTR: job-media-progress=%d\n",
+ 100 * y / header.cupsHeight);
+ }
+
+ /*
+ * Read a line of graphics...
+ */
+
+ if (cupsRasterReadPixels(ras, Planes[0], header.cupsBytesPerLine) < 1)
+ break;
+
+ /*
+ * Write it to the printer...
+ */
+
+ OutputLine(&header);
+ }
+
+ /*
+ * Eject the page...
+ */
+
+ _cupsLangPrintFilter(stderr, "INFO", _("Finished page %d."), page);
+
+ EndPage(&header);
+
+ if (Canceled)
+ break;
+ }
+
+ /*
+ * Shutdown the printer...
+ */
+
+ Shutdown();
+
+ ppdClose(ppd);
+
+ /*
+ * Close the raster stream...
+ */
+
+ cupsRasterClose(ras);
+ if (fd != 0)
+ close(fd);
+
+ /*
+ * If no pages were printed, send an error message...
+ */
+
+ if (page == 0)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("No pages were found."));
+ return (1);
+ }
+ else
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("Ready to print."));
+ return (0);
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/rastertohp.c b/filter/rastertohp.c
new file mode 100644
index 000000000..5684c1542
--- /dev/null
+++ b/filter/rastertohp.c
@@ -0,0 +1,889 @@
+/*
+ * "$Id$"
+ *
+ * Hewlett-Packard Page Control Language filter for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * Setup() - Prepare the printer for printing.
+ * StartPage() - Start a page of graphics.
+ * EndPage() - Finish a page of graphics.
+ * Shutdown() - Shutdown the printer.
+ * CancelJob() - Cancel the current job...
+ * CompressData() - Compress a line of graphics.
+ * OutputLine() - Output a line of graphics.
+ * main() - Main entry and processing of driver.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <cups/ppd.h>
+#include <cups/string-private.h>
+#include <cups/language-private.h>
+#include <cups/raster.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+
+
+/*
+ * Globals...
+ */
+
+unsigned char *Planes[4], /* Output buffers */
+ *CompBuffer, /* Compression buffer */
+ *BitBuffer; /* Buffer for output bits */
+int NumPlanes, /* Number of color planes */
+ ColorBits, /* Number of bits per color */
+ Feed, /* Number of lines to skip */
+ Duplex, /* Current duplex mode */
+ Page, /* Current page number */
+ Canceled; /* Has the current job been canceled? */
+
+
+/*
+ * Prototypes...
+ */
+
+void Setup(void);
+void StartPage(ppd_file_t *ppd, cups_page_header2_t *header);
+void EndPage(void);
+void Shutdown(void);
+
+void CancelJob(int sig);
+void CompressData(unsigned char *line, int length, int plane, int type);
+void OutputLine(cups_page_header2_t *header);
+
+
+/*
+ * 'Setup()' - Prepare the printer for printing.
+ */
+
+void
+Setup(void)
+{
+ /*
+ * Send a PCL reset sequence.
+ */
+
+ putchar(0x1b);
+ putchar('E');
+}
+
+
+/*
+ * 'StartPage()' - Start a page of graphics.
+ */
+
+void
+StartPage(ppd_file_t *ppd, /* I - PPD file */
+ cups_page_header2_t *header) /* I - Page header */
+{
+ int plane; /* Looping var */
+
+
+ /*
+ * Show page device dictionary...
+ */
+
+ fprintf(stderr, "DEBUG: StartPage...\n");
+ fprintf(stderr, "DEBUG: MediaClass = \"%s\"\n", header->MediaClass);
+ fprintf(stderr, "DEBUG: MediaColor = \"%s\"\n", header->MediaColor);
+ fprintf(stderr, "DEBUG: MediaType = \"%s\"\n", header->MediaType);
+ fprintf(stderr, "DEBUG: OutputType = \"%s\"\n", header->OutputType);
+
+ fprintf(stderr, "DEBUG: AdvanceDistance = %d\n", header->AdvanceDistance);
+ fprintf(stderr, "DEBUG: AdvanceMedia = %d\n", header->AdvanceMedia);
+ fprintf(stderr, "DEBUG: Collate = %d\n", header->Collate);
+ fprintf(stderr, "DEBUG: CutMedia = %d\n", header->CutMedia);
+ fprintf(stderr, "DEBUG: Duplex = %d\n", header->Duplex);
+ fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", header->HWResolution[0],
+ header->HWResolution[1]);
+ fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
+ header->ImagingBoundingBox[0], header->ImagingBoundingBox[1],
+ header->ImagingBoundingBox[2], header->ImagingBoundingBox[3]);
+ fprintf(stderr, "DEBUG: InsertSheet = %d\n", header->InsertSheet);
+ fprintf(stderr, "DEBUG: Jog = %d\n", header->Jog);
+ fprintf(stderr, "DEBUG: LeadingEdge = %d\n", header->LeadingEdge);
+ fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", header->Margins[0],
+ header->Margins[1]);
+ fprintf(stderr, "DEBUG: ManualFeed = %d\n", header->ManualFeed);
+ fprintf(stderr, "DEBUG: MediaPosition = %d\n", header->MediaPosition);
+ fprintf(stderr, "DEBUG: MediaWeight = %d\n", header->MediaWeight);
+ fprintf(stderr, "DEBUG: MirrorPrint = %d\n", header->MirrorPrint);
+ fprintf(stderr, "DEBUG: NegativePrint = %d\n", header->NegativePrint);
+ fprintf(stderr, "DEBUG: NumCopies = %d\n", header->NumCopies);
+ fprintf(stderr, "DEBUG: Orientation = %d\n", header->Orientation);
+ fprintf(stderr, "DEBUG: OutputFaceUp = %d\n", header->OutputFaceUp);
+ fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", header->PageSize[0],
+ header->PageSize[1]);
+ fprintf(stderr, "DEBUG: Separations = %d\n", header->Separations);
+ fprintf(stderr, "DEBUG: TraySwitch = %d\n", header->TraySwitch);
+ fprintf(stderr, "DEBUG: Tumble = %d\n", header->Tumble);
+ fprintf(stderr, "DEBUG: cupsWidth = %d\n", header->cupsWidth);
+ fprintf(stderr, "DEBUG: cupsHeight = %d\n", header->cupsHeight);
+ fprintf(stderr, "DEBUG: cupsMediaType = %d\n", header->cupsMediaType);
+ fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header->cupsBitsPerColor);
+ fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header->cupsBitsPerPixel);
+ fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header->cupsBytesPerLine);
+ fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header->cupsColorOrder);
+ fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header->cupsColorSpace);
+ fprintf(stderr, "DEBUG: cupsCompression = %d\n", header->cupsCompression);
+
+ /*
+ * Setup printer/job attributes...
+ */
+
+ Duplex = header->Duplex;
+ ColorBits = header->cupsBitsPerColor;
+
+ if ((!Duplex || (Page & 1)) && header->MediaPosition)
+ printf("\033&l%dH", /* Set media position */
+ header->MediaPosition);
+
+ if (Duplex && ppd && ppd->model_number == 2)
+ {
+ /*
+ * Handle duplexing on new DeskJet printers...
+ */
+
+ printf("\033&l-2H"); /* Load media */
+
+ if (Page & 1)
+ printf("\033&l2S"); /* Set duplex mode */
+ }
+
+ if (!Duplex || (Page & 1) || (ppd && ppd->model_number == 2))
+ {
+ /*
+ * Set the media size...
+ */
+
+ printf("\033&l6D\033&k12H"); /* Set 6 LPI, 10 CPI */
+ printf("\033&l0O"); /* Set portrait orientation */
+
+ switch (header->PageSize[1])
+ {
+ case 540 : /* Monarch Envelope */
+ printf("\033&l80A"); /* Set page size */
+ break;
+
+ case 595 : /* A5 */
+ printf("\033&l25A"); /* Set page size */
+ break;
+
+ case 624 : /* DL Envelope */
+ printf("\033&l90A"); /* Set page size */
+ break;
+
+ case 649 : /* C5 Envelope */
+ printf("\033&l91A"); /* Set page size */
+ break;
+
+ case 684 : /* COM-10 Envelope */
+ printf("\033&l81A"); /* Set page size */
+ break;
+
+ case 709 : /* B5 Envelope */
+ printf("\033&l100A"); /* Set page size */
+ break;
+
+ case 756 : /* Executive */
+ printf("\033&l1A"); /* Set page size */
+ break;
+
+ case 792 : /* Letter */
+ printf("\033&l2A"); /* Set page size */
+ break;
+
+ case 842 : /* A4 */
+ printf("\033&l26A"); /* Set page size */
+ break;
+
+ case 1008 : /* Legal */
+ printf("\033&l3A"); /* Set page size */
+ break;
+
+ case 1191 : /* A3 */
+ printf("\033&l27A"); /* Set page size */
+ break;
+
+ case 1224 : /* Tabloid */
+ printf("\033&l6A"); /* Set page size */
+ break;
+ }
+
+ printf("\033&l%dP", /* Set page length */
+ header->PageSize[1] / 12);
+ printf("\033&l0E"); /* Set top margin to 0 */
+ }
+
+ if (!Duplex || (Page & 1))
+ {
+ /*
+ * Set other job options...
+ */
+
+ printf("\033&l%dX", header->NumCopies); /* Set number copies */
+
+ if (header->cupsMediaType &&
+ (!ppd || ppd->model_number != 2 || header->HWResolution[0] == 600))
+ printf("\033&l%dM", /* Set media type */
+ header->cupsMediaType);
+
+ if (!ppd || ppd->model_number != 2)
+ {
+ int mode = Duplex ? 1 + header->Tumble != 0 : 0;
+
+ printf("\033&l%dS", mode); /* Set duplex mode */
+ printf("\033&l0L"); /* Turn off perforation skip */
+ }
+ }
+ else if (!ppd || ppd->model_number != 2)
+ printf("\033&a2G"); /* Set back side */
+
+ /*
+ * Set graphics mode...
+ */
+
+ if (ppd && ppd->model_number == 2)
+ {
+ /*
+ * Figure out the number of color planes...
+ */
+
+ if (header->cupsColorSpace == CUPS_CSPACE_KCMY)
+ NumPlanes = 4;
+ else
+ NumPlanes = 1;
+
+ /*
+ * Set the resolution and top-of-form...
+ */
+
+ printf("\033&u%dD", header->HWResolution[0]);
+ /* Resolution */
+ printf("\033&l0e0L"); /* Reset top and don't skip */
+ printf("\033*p0Y\033*p0X"); /* Set top of form */
+
+ /*
+ * Send 26-byte configure image data command with horizontal and
+ * vertical resolutions as well as a color count...
+ */
+
+ printf("\033*g26W");
+ putchar(2); /* Format 2 */
+ putchar(NumPlanes); /* Output planes */
+
+ putchar(header->HWResolution[0] >> 8); /* Black resolution */
+ putchar(header->HWResolution[0]);
+ putchar(header->HWResolution[1] >> 8);
+ putchar(header->HWResolution[1]);
+ putchar(0);
+ putchar(1 << ColorBits); /* # of black levels */
+
+ putchar(header->HWResolution[0] >> 8); /* Cyan resolution */
+ putchar(header->HWResolution[0]);
+ putchar(header->HWResolution[1] >> 8);
+ putchar(header->HWResolution[1]);
+ putchar(0);
+ putchar(1 << ColorBits); /* # of cyan levels */
+
+ putchar(header->HWResolution[0] >> 8); /* Magenta resolution */
+ putchar(header->HWResolution[0]);
+ putchar(header->HWResolution[1] >> 8);
+ putchar(header->HWResolution[1]);
+ putchar(0);
+ putchar(1 << ColorBits); /* # of magenta levels */
+
+ putchar(header->HWResolution[0] >> 8); /* Yellow resolution */
+ putchar(header->HWResolution[0]);
+ putchar(header->HWResolution[1] >> 8);
+ putchar(header->HWResolution[1]);
+ putchar(0);
+ putchar(1 << ColorBits); /* # of yellow levels */
+
+ printf("\033&l0H"); /* Set media position */
+ }
+ else
+ {
+ printf("\033*t%dR", header->HWResolution[0]);
+ /* Set resolution */
+
+ if (header->cupsColorSpace == CUPS_CSPACE_KCMY)
+ {
+ NumPlanes = 4;
+ printf("\033*r-4U"); /* Set KCMY graphics */
+ }
+ else if (header->cupsColorSpace == CUPS_CSPACE_CMY)
+ {
+ NumPlanes = 3;
+ printf("\033*r-3U"); /* Set CMY graphics */
+ }
+ else
+ NumPlanes = 1; /* Black&white graphics */
+
+ /*
+ * Set size and position of graphics...
+ */
+
+ printf("\033*r%dS", header->cupsWidth); /* Set width */
+ printf("\033*r%dT", header->cupsHeight); /* Set height */
+
+ printf("\033&a0H"); /* Set horizontal position */
+
+ if (ppd)
+ printf("\033&a%.0fV", /* Set vertical position */
+ 10.0 * (ppd->sizes[0].length - ppd->sizes[0].top));
+ else
+ printf("\033&a0V"); /* Set top-of-page */
+ }
+
+ printf("\033*r1A"); /* Start graphics */
+
+ if (header->cupsCompression)
+ printf("\033*b%dM", /* Set compression */
+ header->cupsCompression);
+
+ Feed = 0; /* No blank lines yet */
+
+ /*
+ * Allocate memory for a line of graphics...
+ */
+
+ if ((Planes[0] = malloc(header->cupsBytesPerLine)) == NULL)
+ {
+ fputs("ERROR: Unable to allocate memory\n", stderr);
+ exit(1);
+ }
+
+ for (plane = 1; plane < NumPlanes; plane ++)
+ Planes[plane] = Planes[0] + plane * header->cupsBytesPerLine / NumPlanes;
+
+ if (ColorBits > 1)
+ BitBuffer = malloc(ColorBits * ((header->cupsWidth + 7) / 8));
+ else
+ BitBuffer = NULL;
+
+ if (header->cupsCompression)
+ CompBuffer = malloc(header->cupsBytesPerLine * 2);
+ else
+ CompBuffer = NULL;
+}
+
+
+/*
+ * 'EndPage()' - Finish a page of graphics.
+ */
+
+void
+EndPage(void)
+{
+ /*
+ * Eject the current page...
+ */
+
+ if (NumPlanes > 1)
+ {
+ printf("\033*rC"); /* End color GFX */
+
+ if (!(Duplex && (Page & 1)))
+ printf("\033&l0H"); /* Eject current page */
+ }
+ else
+ {
+ printf("\033*r0B"); /* End GFX */
+
+ if (!(Duplex && (Page & 1)))
+ printf("\014"); /* Eject current page */
+ }
+
+ fflush(stdout);
+
+ /*
+ * Free memory...
+ */
+
+ free(Planes[0]);
+
+ if (BitBuffer)
+ free(BitBuffer);
+
+ if (CompBuffer)
+ free(CompBuffer);
+}
+
+
+/*
+ * 'Shutdown()' - Shutdown the printer.
+ */
+
+void
+Shutdown(void)
+{
+ /*
+ * Send a PCL reset sequence.
+ */
+
+ putchar(0x1b);
+ putchar('E');
+}
+
+
+/*
+ * 'CancelJob()' - Cancel the current job...
+ */
+
+void
+CancelJob(int sig) /* I - Signal */
+{
+ (void)sig;
+
+ Canceled = 1;
+}
+
+
+/*
+ * 'CompressData()' - Compress a line of graphics.
+ */
+
+void
+CompressData(unsigned char *line, /* I - Data to compress */
+ int length, /* I - Number of bytes */
+ int plane, /* I - Color plane */
+ int type) /* I - Type of compression */
+{
+ unsigned char *line_ptr, /* Current byte pointer */
+ *line_end, /* End-of-line byte pointer */
+ *comp_ptr, /* Pointer into compression buffer */
+ *start; /* Start of compression sequence */
+ int count; /* Count of bytes for output */
+
+
+ switch (type)
+ {
+ default :
+ /*
+ * Do no compression...
+ */
+
+ line_ptr = line;
+ line_end = line + length;
+ break;
+
+ case 1 :
+ /*
+ * Do run-length encoding...
+ */
+
+ line_end = line + length;
+ for (line_ptr = line, comp_ptr = CompBuffer;
+ line_ptr < line_end;
+ comp_ptr += 2, line_ptr += count)
+ {
+ for (count = 1;
+ (line_ptr + count) < line_end &&
+ line_ptr[0] == line_ptr[count] &&
+ count < 256;
+ count ++);
+
+ comp_ptr[0] = count - 1;
+ comp_ptr[1] = line_ptr[0];
+ }
+
+ line_ptr = CompBuffer;
+ line_end = comp_ptr;
+ break;
+
+ case 2 :
+ /*
+ * Do TIFF pack-bits encoding...
+ */
+
+ line_ptr = line;
+ line_end = line + length;
+ comp_ptr = CompBuffer;
+
+ while (line_ptr < line_end)
+ {
+ if ((line_ptr + 1) >= line_end)
+ {
+ /*
+ * Single byte on the end...
+ */
+
+ *comp_ptr++ = 0x00;
+ *comp_ptr++ = *line_ptr++;
+ }
+ else if (line_ptr[0] == line_ptr[1])
+ {
+ /*
+ * Repeated sequence...
+ */
+
+ line_ptr ++;
+ count = 2;
+
+ while (line_ptr < (line_end - 1) &&
+ line_ptr[0] == line_ptr[1] &&
+ count < 127)
+ {
+ line_ptr ++;
+ count ++;
+ }
+
+ *comp_ptr++ = 257 - count;
+ *comp_ptr++ = *line_ptr++;
+ }
+ else
+ {
+ /*
+ * Non-repeated sequence...
+ */
+
+ start = line_ptr;
+ line_ptr ++;
+ count = 1;
+
+ while (line_ptr < (line_end - 1) &&
+ line_ptr[0] != line_ptr[1] &&
+ count < 127)
+ {
+ line_ptr ++;
+ count ++;
+ }
+
+ *comp_ptr++ = count - 1;
+
+ memcpy(comp_ptr, start, count);
+ comp_ptr += count;
+ }
+ }
+
+ line_ptr = CompBuffer;
+ line_end = comp_ptr;
+ break;
+ }
+
+ /*
+ * Set the length of the data and write a raster plane...
+ */
+
+ printf("\033*b%d%c", (int)(line_end - line_ptr), plane);
+ fwrite(line_ptr, line_end - line_ptr, 1, stdout);
+}
+
+
+/*
+ * 'OutputLine()' - Output a line of graphics.
+ */
+
+void
+OutputLine(cups_page_header2_t *header) /* I - Page header */
+{
+ int plane, /* Current plane */
+ bytes, /* Bytes to write */
+ count; /* Bytes to convert */
+ unsigned char bit, /* Current plane data */
+ bit0, /* Current low bit data */
+ bit1, /* Current high bit data */
+ *plane_ptr, /* Pointer into Planes */
+ *bit_ptr; /* Pointer into BitBuffer */
+
+
+ /*
+ * Output whitespace as needed...
+ */
+
+ if (Feed > 0)
+ {
+ printf("\033*b%dY", Feed);
+ Feed = 0;
+ }
+
+ /*
+ * Write bitmap data as needed...
+ */
+
+ bytes = (header->cupsWidth + 7) / 8;
+
+ for (plane = 0; plane < NumPlanes; plane ++)
+ if (ColorBits == 1)
+ {
+ /*
+ * Send bits as-is...
+ */
+
+ CompressData(Planes[plane], bytes, plane < (NumPlanes - 1) ? 'V' : 'W',
+ header->cupsCompression);
+ }
+ else
+ {
+ /*
+ * Separate low and high bit data into separate buffers.
+ */
+
+ for (count = header->cupsBytesPerLine / NumPlanes,
+ plane_ptr = Planes[plane], bit_ptr = BitBuffer;
+ count > 0;
+ count -= 2, plane_ptr += 2, bit_ptr ++)
+ {
+ bit = plane_ptr[0];
+
+ bit0 = ((bit & 64) << 1) | ((bit & 16) << 2) | ((bit & 4) << 3) | ((bit & 1) << 4);
+ bit1 = (bit & 128) | ((bit & 32) << 1) | ((bit & 8) << 2) | ((bit & 2) << 3);
+
+ if (count > 1)
+ {
+ bit = plane_ptr[1];
+
+ bit0 |= (bit & 1) | ((bit & 4) >> 1) | ((bit & 16) >> 2) | ((bit & 64) >> 3);
+ bit1 |= ((bit & 2) >> 1) | ((bit & 8) >> 2) | ((bit & 32) >> 3) | ((bit & 128) >> 4);
+ }
+
+ bit_ptr[0] = bit0;
+ bit_ptr[bytes] = bit1;
+ }
+
+ /*
+ * Send low and high bits...
+ */
+
+ CompressData(BitBuffer, bytes, 'V', header->cupsCompression);
+ CompressData(BitBuffer + bytes, bytes, plane < (NumPlanes - 1) ? 'V' : 'W',
+ header->cupsCompression);
+ }
+
+ fflush(stdout);
+}
+
+
+/*
+ * 'main()' - Main entry and processing of driver.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int fd; /* File descriptor */
+ cups_raster_t *ras; /* Raster stream for printing */
+ cups_page_header2_t header; /* Page header from file */
+ int y; /* Current line */
+ ppd_file_t *ppd; /* PPD file */
+#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 < 6 || argc > 7)
+ {
+ /*
+ * We don't have the correct number of arguments; write an error message
+ * and return.
+ */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("%s job-id user title copies options [file]"),
+ "rastertohp");
+ return (1);
+ }
+
+ /*
+ * Open the page stream...
+ */
+
+ if (argc == 7)
+ {
+ if ((fd = open(argv[6], O_RDONLY)) == -1)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open raster file"));
+ sleep(1);
+ return (1);
+ }
+ }
+ else
+ fd = 0;
+
+ ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
+
+ /*
+ * Register a signal handler to eject the current page if the
+ * job is cancelled.
+ */
+
+ Canceled = 0;
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, CancelJob);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = CancelJob;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, CancelJob);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Initialize the print device...
+ */
+
+ ppd = ppdOpenFile(getenv("PPD"));
+ if (!ppd)
+ {
+ ppd_status_t status; /* PPD error */
+ int linenum; /* Line number */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The PPD file could not be opened."));
+
+ status = ppdLastError(&linenum);
+
+ fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
+
+ return (1);
+ }
+
+ Setup();
+
+ /*
+ * Process pages as needed...
+ */
+
+ Page = 0;
+
+ while (cupsRasterReadHeader2(ras, &header))
+ {
+ /*
+ * Write a status message with the page number and number of copies.
+ */
+
+ if (Canceled)
+ break;
+
+ Page ++;
+
+ fprintf(stderr, "PAGE: %d %d\n", Page, header.NumCopies);
+ _cupsLangPrintFilter(stderr, "INFO", _("Starting page %d."), Page);
+
+ /*
+ * Start the page...
+ */
+
+ StartPage(ppd, &header);
+
+ /*
+ * Loop for each line on the page...
+ */
+
+ for (y = 0; y < header.cupsHeight; y ++)
+ {
+ /*
+ * Let the user know how far we have progressed...
+ */
+
+ if (Canceled)
+ break;
+
+ if ((y & 127) == 0)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printing page %d, %d%% complete."),
+ Page, 100 * y / header.cupsHeight);
+ fprintf(stderr, "ATTR: job-media-progress=%d\n",
+ 100 * y / header.cupsHeight);
+ }
+
+ /*
+ * Read a line of graphics...
+ */
+
+ if (cupsRasterReadPixels(ras, Planes[0], header.cupsBytesPerLine) < 1)
+ break;
+
+ /*
+ * See if the line is blank; if not, write it to the printer...
+ */
+
+ if (Planes[0][0] ||
+ memcmp(Planes[0], Planes[0] + 1, header.cupsBytesPerLine - 1))
+ OutputLine(&header);
+ else
+ Feed ++;
+ }
+
+ /*
+ * Eject the page...
+ */
+
+ _cupsLangPrintFilter(stderr, "INFO", _("Finished page %d."), Page);
+
+ EndPage();
+
+ if (Canceled)
+ break;
+ }
+
+ /*
+ * Shutdown the printer...
+ */
+
+ Shutdown();
+
+ if (ppd)
+ ppdClose(ppd);
+
+ /*
+ * Close the raster stream...
+ */
+
+ cupsRasterClose(ras);
+ if (fd != 0)
+ close(fd);
+
+ /*
+ * If no pages were printed, send an error message...
+ */
+
+ if (Page == 0)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("No pages were found."));
+ return (1);
+ }
+ else
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("Ready to print."));
+ return (0);
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/rastertolabel.c b/filter/rastertolabel.c
new file mode 100644
index 000000000..aa45a2b11
--- /dev/null
+++ b/filter/rastertolabel.c
@@ -0,0 +1,1315 @@
+/*
+ * "$Id$"
+ *
+ * Label printer filter for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2001-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * Setup() - Prepare the printer for printing.
+ * StartPage() - Start a page of graphics.
+ * EndPage() - Finish a page of graphics.
+ * CancelJob() - Cancel the current job...
+ * OutputLine() - Output a line of graphics.
+ * PCLCompress() - Output a PCL (mode 3) compressed line.
+ * ZPLCompress() - Output a run-length compression sequence.
+ * main() - Main entry and processing of driver.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <cups/ppd.h>
+#include <cups/string-private.h>
+#include <cups/language-private.h>
+#include <cups/raster.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+
+
+/*
+ * This driver filter currently supports Dymo, Intellitech, and Zebra
+ * label printers.
+ *
+ * The Dymo portion of the driver has been tested with the 300, 330,
+ * and 330 Turbo label printers; it may also work with other models.
+ * The Dymo printers support printing at 136, 203, and 300 DPI.
+ *
+ * The Intellitech portion of the driver has been tested with the
+ * Intellibar 408, 412, and 808 and supports their PCL variant.
+ *
+ * The Zebra portion of the driver has been tested with the LP-2844,
+ * LP-2844Z, QL-320, and QL-420 label printers; it may also work with
+ * other models. The driver supports EPL line mode, EPL page mode,
+ * ZPL, and CPCL as defined in Zebra's online developer documentation.
+ */
+
+/*
+ * Model number constants...
+ */
+
+#define DYMO_3x0 0 /* Dymo Labelwriter 300/330/330 Turbo */
+
+#define ZEBRA_EPL_LINE 0x10 /* Zebra EPL line mode printers */
+#define ZEBRA_EPL_PAGE 0x11 /* Zebra EPL page mode printers */
+#define ZEBRA_ZPL 0x12 /* Zebra ZPL-based printers */
+#define ZEBRA_CPCL 0x13 /* Zebra CPCL-based printers */
+
+#define INTELLITECH_PCL 0x20 /* Intellitech PCL-based printers */
+
+
+/*
+ * Globals...
+ */
+
+unsigned char *Buffer; /* Output buffer */
+unsigned char *CompBuffer; /* Compression buffer */
+unsigned char *LastBuffer; /* Last buffer */
+int LastSet; /* Number of repeat characters */
+int ModelNumber, /* cupsModelNumber attribute */
+ Page, /* Current page */
+ Feed, /* Number of lines to skip */
+ Canceled; /* Non-zero if job is canceled */
+
+
+/*
+ * Prototypes...
+ */
+
+void Setup(ppd_file_t *ppd);
+void StartPage(ppd_file_t *ppd, cups_page_header2_t *header);
+void EndPage(ppd_file_t *ppd, cups_page_header2_t *header);
+void CancelJob(int sig);
+void OutputLine(ppd_file_t *ppd, cups_page_header2_t *header, int y);
+void PCLCompress(unsigned char *line, int length);
+void ZPLCompress(char repeat_char, int repeat_count);
+
+
+/*
+ * 'Setup()' - Prepare the printer for printing.
+ */
+
+void
+Setup(ppd_file_t *ppd) /* I - PPD file */
+{
+ int i; /* Looping var */
+
+
+ /*
+ * Get the model number from the PPD file...
+ */
+
+ if (ppd)
+ ModelNumber = ppd->model_number;
+
+ /*
+ * Initialize based on the model number...
+ */
+
+ switch (ModelNumber)
+ {
+ case DYMO_3x0 :
+ /*
+ * Clear any remaining data...
+ */
+
+ for (i = 0; i < 100; i ++)
+ putchar(0x1b);
+
+ /*
+ * Reset the printer...
+ */
+
+ fputs("\033@", stdout);
+ break;
+
+ case ZEBRA_EPL_LINE :
+ break;
+
+ case ZEBRA_EPL_PAGE :
+ break;
+
+ case ZEBRA_ZPL :
+ break;
+
+ case ZEBRA_CPCL :
+ break;
+
+ case INTELLITECH_PCL :
+ /*
+ * Send a PCL reset sequence.
+ */
+
+ putchar(0x1b);
+ putchar('E');
+ break;
+ }
+}
+
+
+/*
+ * 'StartPage()' - Start a page of graphics.
+ */
+
+void
+StartPage(ppd_file_t *ppd, /* I - PPD file */
+ cups_page_header2_t *header) /* I - Page header */
+{
+ ppd_choice_t *choice; /* Marked choice */
+ int length; /* Actual label length */
+
+
+ /*
+ * Show page device dictionary...
+ */
+
+ fprintf(stderr, "DEBUG: StartPage...\n");
+ fprintf(stderr, "DEBUG: MediaClass = \"%s\"\n", header->MediaClass);
+ fprintf(stderr, "DEBUG: MediaColor = \"%s\"\n", header->MediaColor);
+ fprintf(stderr, "DEBUG: MediaType = \"%s\"\n", header->MediaType);
+ fprintf(stderr, "DEBUG: OutputType = \"%s\"\n", header->OutputType);
+
+ fprintf(stderr, "DEBUG: AdvanceDistance = %d\n", header->AdvanceDistance);
+ fprintf(stderr, "DEBUG: AdvanceMedia = %d\n", header->AdvanceMedia);
+ fprintf(stderr, "DEBUG: Collate = %d\n", header->Collate);
+ fprintf(stderr, "DEBUG: CutMedia = %d\n", header->CutMedia);
+ fprintf(stderr, "DEBUG: Duplex = %d\n", header->Duplex);
+ fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", header->HWResolution[0],
+ header->HWResolution[1]);
+ fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
+ header->ImagingBoundingBox[0], header->ImagingBoundingBox[1],
+ header->ImagingBoundingBox[2], header->ImagingBoundingBox[3]);
+ fprintf(stderr, "DEBUG: InsertSheet = %d\n", header->InsertSheet);
+ fprintf(stderr, "DEBUG: Jog = %d\n", header->Jog);
+ fprintf(stderr, "DEBUG: LeadingEdge = %d\n", header->LeadingEdge);
+ fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", header->Margins[0],
+ header->Margins[1]);
+ fprintf(stderr, "DEBUG: ManualFeed = %d\n", header->ManualFeed);
+ fprintf(stderr, "DEBUG: MediaPosition = %d\n", header->MediaPosition);
+ fprintf(stderr, "DEBUG: MediaWeight = %d\n", header->MediaWeight);
+ fprintf(stderr, "DEBUG: MirrorPrint = %d\n", header->MirrorPrint);
+ fprintf(stderr, "DEBUG: NegativePrint = %d\n", header->NegativePrint);
+ fprintf(stderr, "DEBUG: NumCopies = %d\n", header->NumCopies);
+ fprintf(stderr, "DEBUG: Orientation = %d\n", header->Orientation);
+ fprintf(stderr, "DEBUG: OutputFaceUp = %d\n", header->OutputFaceUp);
+ fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", header->PageSize[0],
+ header->PageSize[1]);
+ fprintf(stderr, "DEBUG: Separations = %d\n", header->Separations);
+ fprintf(stderr, "DEBUG: TraySwitch = %d\n", header->TraySwitch);
+ fprintf(stderr, "DEBUG: Tumble = %d\n", header->Tumble);
+ fprintf(stderr, "DEBUG: cupsWidth = %d\n", header->cupsWidth);
+ fprintf(stderr, "DEBUG: cupsHeight = %d\n", header->cupsHeight);
+ fprintf(stderr, "DEBUG: cupsMediaType = %d\n", header->cupsMediaType);
+ fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header->cupsBitsPerColor);
+ fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header->cupsBitsPerPixel);
+ fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header->cupsBytesPerLine);
+ fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header->cupsColorOrder);
+ fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header->cupsColorSpace);
+ fprintf(stderr, "DEBUG: cupsCompression = %d\n", header->cupsCompression);
+ fprintf(stderr, "DEBUG: cupsRowCount = %d\n", header->cupsRowCount);
+ fprintf(stderr, "DEBUG: cupsRowFeed = %d\n", header->cupsRowFeed);
+ fprintf(stderr, "DEBUG: cupsRowStep = %d\n", header->cupsRowStep);
+
+ switch (ModelNumber)
+ {
+ case DYMO_3x0 :
+ /*
+ * Setup printer/job attributes...
+ */
+
+ length = header->PageSize[1] * header->HWResolution[1] / 72;
+
+ printf("\033L%c%c", length >> 8, length);
+ printf("\033D%c", header->cupsBytesPerLine);
+
+ printf("\033%c", header->cupsCompression + 'c'); /* Darkness */
+ break;
+
+ case ZEBRA_EPL_LINE :
+ /*
+ * Set print rate...
+ */
+
+ if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL &&
+ strcmp(choice->choice, "Default"))
+ printf("\033S%.0f", atof(choice->choice) * 2.0 - 2.0);
+
+ /*
+ * Set darkness...
+ */
+
+ if (header->cupsCompression > 0 && header->cupsCompression <= 100)
+ printf("\033D%d", 7 * header->cupsCompression / 100);
+
+ /*
+ * Set left margin to 0...
+ */
+
+ fputs("\033M01", stdout);
+
+ /*
+ * Start buffered output...
+ */
+
+ fputs("\033B", stdout);
+ break;
+
+ case ZEBRA_EPL_PAGE :
+ /*
+ * Start a new label...
+ */
+
+ puts("");
+ puts("N");
+
+ /*
+ * Set hardware options...
+ */
+
+ if (!strcmp(header->MediaType, "Direct"))
+ puts("OD");
+
+ /*
+ * Set print rate...
+ */
+
+ if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL &&
+ strcmp(choice->choice, "Default"))
+ {
+ float val = atof(choice->choice);
+
+ if (val >= 3.0)
+ printf("S%.0f\n", val);
+ else
+ printf("S%.0f\n", val * 2.0 - 2.0);
+ }
+
+ /*
+ * Set darkness...
+ */
+
+ if (header->cupsCompression > 0 && header->cupsCompression <= 100)
+ printf("D%d\n", 15 * header->cupsCompression / 100);
+
+ /*
+ * Set label size...
+ */
+
+ printf("q%d\n", (header->cupsWidth + 7) & ~7);
+ break;
+
+ case ZEBRA_ZPL :
+ /*
+ * Set darkness...
+ */
+
+ if (header->cupsCompression > 0 && header->cupsCompression <= 100)
+ printf("~SD%02d\n", 30 * header->cupsCompression / 100);
+
+ /*
+ * Start bitmap graphics...
+ */
+
+ printf("~DGR:CUPS.GRF,%d,%d,\n",
+ header->cupsHeight * header->cupsBytesPerLine,
+ header->cupsBytesPerLine);
+
+ /*
+ * Allocate compression buffers...
+ */
+
+ CompBuffer = malloc(2 * header->cupsBytesPerLine + 1);
+ LastBuffer = malloc(header->cupsBytesPerLine);
+ LastSet = 0;
+ break;
+
+ case ZEBRA_CPCL :
+ /*
+ * Start label...
+ */
+
+ printf("! 0 %u %u %u %u\r\n", header->HWResolution[0],
+ header->HWResolution[1], header->cupsHeight,
+ header->NumCopies);
+ printf("PAGE-WIDTH %d\r\n", header->cupsWidth);
+ printf("PAGE-HEIGHT %d\r\n", header->cupsWidth);
+ break;
+
+ case INTELLITECH_PCL :
+ /*
+ * Set the media size...
+ */
+
+ printf("\033&l6D\033&k12H"); /* Set 6 LPI, 10 CPI */
+ printf("\033&l0O"); /* Set portrait orientation */
+
+ switch (header->PageSize[1])
+ {
+ case 540 : /* Monarch Envelope */
+ printf("\033&l80A"); /* Set page size */
+ break;
+
+ case 624 : /* DL Envelope */
+ printf("\033&l90A"); /* Set page size */
+ break;
+
+ case 649 : /* C5 Envelope */
+ printf("\033&l91A"); /* Set page size */
+ break;
+
+ case 684 : /* COM-10 Envelope */
+ printf("\033&l81A"); /* Set page size */
+ break;
+
+ case 756 : /* Executive */
+ printf("\033&l1A"); /* Set page size */
+ break;
+
+ case 792 : /* Letter */
+ printf("\033&l2A"); /* Set page size */
+ break;
+
+ case 842 : /* A4 */
+ printf("\033&l26A"); /* Set page size */
+ break;
+
+ case 1008 : /* Legal */
+ printf("\033&l3A"); /* Set page size */
+ break;
+
+ default : /* Custom size */
+ printf("\033!f%dZ", header->PageSize[1] * 300 / 72);
+ break;
+ }
+
+ printf("\033&l%dP", /* Set page length */
+ header->PageSize[1] / 12);
+ printf("\033&l0E"); /* Set top margin to 0 */
+ printf("\033&l%dX", header->NumCopies);
+ /* Set number copies */
+ printf("\033&l0L"); /* Turn off perforation skip */
+
+ /*
+ * Print settings...
+ */
+
+ if (Page == 1)
+ {
+ if (header->cupsRowFeed) /* inPrintRate */
+ printf("\033!p%dS", header->cupsRowFeed);
+
+ if (header->cupsCompression != ~0)
+ /* inPrintDensity */
+ printf("\033&d%dA", 30 * header->cupsCompression / 100 - 15);
+
+ if ((choice = ppdFindMarkedChoice(ppd, "inPrintMode")) != NULL)
+ {
+ if (!strcmp(choice->choice, "Standard"))
+ fputs("\033!p0M", stdout);
+ else if (!strcmp(choice->choice, "Tear"))
+ {
+ fputs("\033!p1M", stdout);
+
+ if (header->cupsRowCount) /* inTearInterval */
+ printf("\033!n%dT", header->cupsRowCount);
+ }
+ else
+ {
+ fputs("\033!p2M", stdout);
+
+ if (header->cupsRowStep) /* inCutInterval */
+ printf("\033!n%dC", header->cupsRowStep);
+ }
+ }
+ }
+
+ /*
+ * Setup graphics...
+ */
+
+ printf("\033*t%dR", header->HWResolution[0]);
+ /* Set resolution */
+
+ printf("\033*r%dS", header->cupsWidth);
+ /* Set width */
+ printf("\033*r%dT", header->cupsHeight);
+ /* Set height */
+
+ printf("\033&a0H"); /* Set horizontal position */
+ printf("\033&a0V"); /* Set vertical position */
+ printf("\033*r1A"); /* Start graphics */
+ printf("\033*b3M"); /* Set compression */
+
+ /*
+ * Allocate compression buffers...
+ */
+
+ CompBuffer = malloc(2 * header->cupsBytesPerLine + 1);
+ LastBuffer = malloc(header->cupsBytesPerLine);
+ LastSet = 0;
+ break;
+ }
+
+ /*
+ * Allocate memory for a line of graphics...
+ */
+
+ Buffer = malloc(header->cupsBytesPerLine);
+ Feed = 0;
+}
+
+
+/*
+ * 'EndPage()' - Finish a page of graphics.
+ */
+
+void
+EndPage(ppd_file_t *ppd, /* I - PPD file */
+ cups_page_header2_t *header) /* I - Page header */
+{
+ int val; /* Option value */
+ ppd_choice_t *choice; /* Marked choice */
+
+
+ switch (ModelNumber)
+ {
+ case DYMO_3x0 :
+ /*
+ * Eject the current page...
+ */
+
+ fputs("\033E", stdout);
+ break;
+
+ case ZEBRA_EPL_LINE :
+ /*
+ * End buffered output, eject the label...
+ */
+
+ fputs("\033E\014", stdout);
+ break;
+
+ case ZEBRA_EPL_PAGE :
+ /*
+ * Print the label...
+ */
+
+ puts("P1");
+ break;
+
+ case ZEBRA_ZPL :
+ if (Canceled)
+ {
+ /*
+ * Cancel bitmap download...
+ */
+
+ puts("~DN");
+ break;
+ }
+
+ /*
+ * Start label...
+ */
+
+ puts("^XA");
+
+ /*
+ * Set print rate...
+ */
+
+ if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL &&
+ strcmp(choice->choice, "Default"))
+ {
+ val = atoi(choice->choice);
+ printf("^PR%d,%d,%d\n", val, val, val);
+ }
+
+ /*
+ * Put label home in default position (0,0)...
+ */
+
+ printf("^LH0,0\n");
+
+ /*
+ * Set media tracking...
+ */
+
+ if (ppdIsMarked(ppd, "zeMediaTracking", "Continuous"))
+ {
+ /*
+ * Add label length command for continuous...
+ */
+
+ printf("^LL%d\n", header->cupsHeight);
+ printf("^MNN\n");
+ }
+ else if (ppdIsMarked(ppd, "zeMediaTracking", "Web"))
+ printf("^MNY\n");
+ else if (ppdIsMarked(ppd, "zeMediaTracking", "Mark"))
+ printf("^MNM\n");
+
+ /*
+ * Set label top
+ */
+
+ if (header->cupsRowStep != 200)
+ printf("^LT%u\n", header->cupsRowStep);
+
+ /*
+ * Set media type...
+ */
+
+ if (!strcmp(header->MediaType, "Thermal"))
+ printf("^MTT\n");
+ else if (!strcmp(header->MediaType, "Direct"))
+ printf("^MTD\n");
+
+ /*
+ * Set print mode...
+ */
+
+ if ((choice = ppdFindMarkedChoice(ppd, "zePrintMode")) != NULL &&
+ strcmp(choice->choice, "Saved"))
+ {
+ printf("^MM");
+
+ if (!strcmp(choice->choice, "Tear"))
+ printf("T,Y\n");
+ else if (!strcmp(choice->choice, "Peel"))
+ printf("P,Y\n");
+ else if (!strcmp(choice->choice, "Rewind"))
+ printf("R,Y\n");
+ else if (!strcmp(choice->choice, "Applicator"))
+ printf("A,Y\n");
+ else
+ printf("C,Y\n");
+ }
+
+ /*
+ * Set tear-off adjust position...
+ */
+
+ if (header->AdvanceDistance != 1000)
+ {
+ if ((int)header->AdvanceDistance < 0)
+ printf("~TA%04d\n", (int)header->AdvanceDistance);
+ else
+ printf("~TA%03d\n", (int)header->AdvanceDistance);
+ }
+
+ /*
+ * Allow for reprinting after an error...
+ */
+
+ if (ppdIsMarked(ppd, "zeErrorReprint", "Always"))
+ printf("^JZY\n");
+ else if (ppdIsMarked(ppd, "zeErrorReprint", "Never"))
+ printf("^JZN\n");
+
+ /*
+ * Print multiple copies
+ */
+
+ if (header->NumCopies > 1)
+ printf("^PQ%d, 0, 0, N\n", header->NumCopies);
+
+ /*
+ * Display the label image...
+ */
+
+ puts("^FO0,0^XGR:CUPS.GRF,1,1^FS");
+
+ /*
+ * End the label and eject...
+ */
+
+ puts("^IDR:CUPS.GRF^FS");
+ puts("^XZ");
+
+ /*
+ * Free compression buffers...
+ */
+
+ free(CompBuffer);
+ free(LastBuffer);
+ break;
+
+ case ZEBRA_CPCL :
+ /*
+ * Set tear-off adjust position...
+ */
+
+ if (header->AdvanceDistance != 1000)
+ printf("PRESENT-AT %d 1\r\n", (int)header->AdvanceDistance);
+
+ /*
+ * Allow for reprinting after an error...
+ */
+
+ if (ppdIsMarked(ppd, "zeErrorReprint", "Always"))
+ puts("ON-OUT-OF-PAPER WAIT\r");
+ else if (ppdIsMarked(ppd, "zeErrorReprint", "Never"))
+ puts("ON-OUT-OF-PAPER PURGE\r");
+
+ /*
+ * Cut label?
+ */
+
+ if (header->CutMedia)
+ puts("CUT\r");
+
+ /*
+ * Set darkness...
+ */
+
+ if (header->cupsCompression > 0)
+ printf("TONE %u\r\n", 2 * header->cupsCompression);
+
+ /*
+ * Set print rate...
+ */
+
+ if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL &&
+ strcmp(choice->choice, "Default"))
+ {
+ val = atoi(choice->choice);
+ printf("SPEED %d\r\n", val);
+ }
+
+ /*
+ * Print the label...
+ */
+
+ if ((choice = ppdFindMarkedChoice(ppd, "zeMediaTracking")) == NULL ||
+ strcmp(choice->choice, "Continuous"))
+ puts("FORM\r");
+
+ puts("PRINT\r");
+ break;
+
+ case INTELLITECH_PCL :
+ printf("\033*rB"); /* End GFX */
+ printf("\014"); /* Eject current page */
+ break;
+ }
+
+ fflush(stdout);
+
+ /*
+ * Free memory...
+ */
+
+ free(Buffer);
+}
+
+
+/*
+ * 'CancelJob()' - Cancel the current job...
+ */
+
+void
+CancelJob(int sig) /* I - Signal */
+{
+ /*
+ * Tell the main loop to stop...
+ */
+
+ (void)sig;
+
+ Canceled = 1;
+}
+
+
+/*
+ * 'OutputLine()' - Output a line of graphics...
+ */
+
+void
+OutputLine(ppd_file_t *ppd, /* I - PPD file */
+ cups_page_header2_t *header, /* I - Page header */
+ int y) /* I - Line number */
+{
+ int i; /* Looping var */
+ unsigned char *ptr; /* Pointer into buffer */
+ unsigned char *compptr; /* Pointer into compression buffer */
+ char repeat_char; /* Repeated character */
+ int repeat_count; /* Number of repeated characters */
+ static const char *hex = "0123456789ABCDEF";
+ /* Hex digits */
+
+
+ switch (ModelNumber)
+ {
+ case DYMO_3x0 :
+ /*
+ * See if the line is blank; if not, write it to the printer...
+ */
+
+ if (Buffer[0] ||
+ memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine - 1))
+ {
+ if (Feed)
+ {
+ while (Feed > 255)
+ {
+ printf("\033f\001%c", 255);
+ Feed -= 255;
+ }
+
+ printf("\033f\001%c", Feed);
+ Feed = 0;
+ }
+
+ putchar(0x16);
+ fwrite(Buffer, header->cupsBytesPerLine, 1, stdout);
+ fflush(stdout);
+
+#ifdef __sgi
+ /*
+ * This hack works around a bug in the IRIX serial port driver when
+ * run at high baud rates (e.g. 115200 baud)... This results in
+ * slightly slower label printing, but at least the labels come
+ * out properly.
+ */
+
+ sginap(1);
+#endif /* __sgi */
+ }
+ else
+ Feed ++;
+ break;
+
+ case ZEBRA_EPL_LINE :
+ printf("\033g%03d", header->cupsBytesPerLine);
+ fwrite(Buffer, 1, header->cupsBytesPerLine, stdout);
+ fflush(stdout);
+ break;
+
+ case ZEBRA_EPL_PAGE :
+ if (Buffer[0] || memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine))
+ {
+ printf("GW0,%d,%d,1\n", y, header->cupsBytesPerLine);
+ for (i = header->cupsBytesPerLine, ptr = Buffer; i > 0; i --, ptr ++)
+ putchar(~*ptr);
+ putchar('\n');
+ fflush(stdout);
+ }
+ break;
+
+ case ZEBRA_ZPL :
+ /*
+ * Determine if this row is the same as the previous line.
+ * If so, output a ':' and return...
+ */
+
+ if (LastSet)
+ {
+ if (!memcmp(Buffer, LastBuffer, header->cupsBytesPerLine))
+ {
+ putchar(':');
+ return;
+ }
+ }
+
+ /*
+ * Convert the line to hex digits...
+ */
+
+ for (ptr = Buffer, compptr = CompBuffer, i = header->cupsBytesPerLine;
+ i > 0;
+ i --, ptr ++)
+ {
+ *compptr++ = hex[*ptr >> 4];
+ *compptr++ = hex[*ptr & 15];
+ }
+
+ *compptr = '\0';
+
+ /*
+ * Run-length compress the graphics...
+ */
+
+ for (compptr = CompBuffer + 1, repeat_char = CompBuffer[0], repeat_count = 1;
+ *compptr;
+ compptr ++)
+ if (*compptr == repeat_char)
+ repeat_count ++;
+ else
+ {
+ ZPLCompress(repeat_char, repeat_count);
+ repeat_char = *compptr;
+ repeat_count = 1;
+ }
+
+ if (repeat_char == '0')
+ {
+ /*
+ * Handle 0's on the end of the line...
+ */
+
+ if (repeat_count & 1)
+ {
+ repeat_count --;
+ putchar('0');
+ }
+
+ if (repeat_count > 0)
+ putchar(',');
+ }
+ else
+ ZPLCompress(repeat_char, repeat_count);
+
+ fflush(stdout);
+
+ /*
+ * Save this line for the next round...
+ */
+
+ memcpy(LastBuffer, Buffer, header->cupsBytesPerLine);
+ LastSet = 1;
+ break;
+
+ case ZEBRA_CPCL :
+ if (Buffer[0] || memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine))
+ {
+ printf("CG %u 1 0 %d ", header->cupsBytesPerLine, y);
+ fwrite(Buffer, 1, header->cupsBytesPerLine, stdout);
+ puts("\r");
+ fflush(stdout);
+ }
+ break;
+
+ case INTELLITECH_PCL :
+ if (Buffer[0] ||
+ memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine - 1))
+ {
+ if (Feed)
+ {
+ printf("\033*b%dY", Feed);
+ Feed = 0;
+ LastSet = 0;
+ }
+
+ PCLCompress(Buffer, header->cupsBytesPerLine);
+ }
+ else
+ Feed ++;
+ break;
+ }
+}
+
+
+/*
+ * 'PCLCompress()' - Output a PCL (mode 3) compressed line.
+ */
+
+void
+PCLCompress(unsigned char *line, /* I - Line to compress */
+ int length) /* I - Length of line */
+{
+ unsigned char *line_ptr, /* Current byte pointer */
+ *line_end, /* End-of-line byte pointer */
+ *comp_ptr, /* Pointer into compression buffer */
+ *start, /* Start of compression sequence */
+ *seed; /* Seed buffer pointer */
+ int count, /* Count of bytes for output */
+ offset; /* Offset of bytes for output */
+
+
+ /*
+ * Do delta-row compression...
+ */
+
+ line_ptr = line;
+ line_end = line + length;
+
+ comp_ptr = CompBuffer;
+ seed = LastBuffer;
+
+ while (line_ptr < line_end)
+ {
+ /*
+ * Find the next non-matching sequence...
+ */
+
+ start = line_ptr;
+
+ if (!LastSet)
+ {
+ /*
+ * The seed buffer is invalid, so do the next 8 bytes, max...
+ */
+
+ offset = 0;
+
+ if ((count = line_end - line_ptr) > 8)
+ count = 8;
+
+ line_ptr += count;
+ }
+ else
+ {
+ /*
+ * The seed buffer is valid, so compare against it...
+ */
+
+ while (*line_ptr == *seed &&
+ line_ptr < line_end)
+ {
+ line_ptr ++;
+ seed ++;
+ }
+
+ if (line_ptr == line_end)
+ break;
+
+ offset = line_ptr - start;
+
+ /*
+ * Find up to 8 non-matching bytes...
+ */
+
+ start = line_ptr;
+ count = 0;
+ while (*line_ptr != *seed &&
+ line_ptr < line_end &&
+ count < 8)
+ {
+ line_ptr ++;
+ seed ++;
+ count ++;
+ }
+ }
+
+ /*
+ * Place mode 3 compression data in the buffer; see HP manuals
+ * for details...
+ */
+
+ if (offset >= 31)
+ {
+ /*
+ * Output multi-byte offset...
+ */
+
+ *comp_ptr++ = ((count - 1) << 5) | 31;
+
+ offset -= 31;
+ while (offset >= 255)
+ {
+ *comp_ptr++ = 255;
+ offset -= 255;
+ }
+
+ *comp_ptr++ = offset;
+ }
+ else
+ {
+ /*
+ * Output single-byte offset...
+ */
+
+ *comp_ptr++ = ((count - 1) << 5) | offset;
+ }
+
+ memcpy(comp_ptr, start, count);
+ comp_ptr += count;
+ }
+
+ /*
+ * Set the length of the data and write it...
+ */
+
+ printf("\033*b%dW", (int)(comp_ptr - CompBuffer));
+ fwrite(CompBuffer, comp_ptr - CompBuffer, 1, stdout);
+
+ /*
+ * Save this line as a "seed" buffer for the next...
+ */
+
+ memcpy(LastBuffer, line, length);
+ LastSet = 1;
+}
+
+
+/*
+ * 'ZPLCompress()' - Output a run-length compression sequence.
+ */
+
+void
+ZPLCompress(char repeat_char, /* I - Character to repeat */
+ int repeat_count) /* I - Number of repeated characters */
+{
+ if (repeat_count > 1)
+ {
+ /*
+ * Print as many z's as possible - they are the largest denomination
+ * representing 400 characters (zC stands for 400 adjacent C's)
+ */
+
+ while (repeat_count >= 400)
+ {
+ putchar('z');
+ repeat_count -= 400;
+ }
+
+ /*
+ * Then print 'g' through 'y' as multiples of 20 characters...
+ */
+
+ if (repeat_count >= 20)
+ {
+ putchar('f' + repeat_count / 20);
+ repeat_count %= 20;
+ }
+
+ /*
+ * Finally, print 'G' through 'Y' as 1 through 19 characters...
+ */
+
+ if (repeat_count > 0)
+ putchar('F' + repeat_count);
+ }
+
+ /*
+ * Then the character to be repeated...
+ */
+
+ putchar(repeat_char);
+}
+
+
+/*
+ * 'main()' - Main entry and processing of driver.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int fd; /* File descriptor */
+ cups_raster_t *ras; /* Raster stream for printing */
+ cups_page_header2_t header; /* Page header from file */
+ int y; /* Current line */
+ ppd_file_t *ppd; /* PPD file */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ /*
+ * We don't have the correct number of arguments; write an error message
+ * and return.
+ */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("%s job-id user title copies options [file]"),
+ "rastertolabel");
+ return (1);
+ }
+
+ /*
+ * Open the page stream...
+ */
+
+ if (argc == 7)
+ {
+ if ((fd = open(argv[6], O_RDONLY)) == -1)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open raster file"));
+ sleep(1);
+ return (1);
+ }
+ }
+ else
+ fd = 0;
+
+ ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
+
+ /*
+ * Register a signal handler to eject the current page if the
+ * job is cancelled.
+ */
+
+ Canceled = 0;
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGTERM, CancelJob);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = CancelJob;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, CancelJob);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Open the PPD file and apply options...
+ */
+
+ num_options = cupsParseOptions(argv[5], 0, &options);
+
+ ppd = ppdOpenFile(getenv("PPD"));
+ if (!ppd)
+ {
+ ppd_status_t status; /* PPD error */
+ int linenum; /* Line number */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("The PPD file could not be opened."));
+
+ status = ppdLastError(&linenum);
+
+ fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
+
+ return (1);
+ }
+
+ ppdMarkDefaults(ppd);
+ cupsMarkOptions(ppd, num_options, options);
+
+ /*
+ * Initialize the print device...
+ */
+
+ Setup(ppd);
+
+ /*
+ * Process pages as needed...
+ */
+
+ Page = 0;
+
+ while (cupsRasterReadHeader2(ras, &header))
+ {
+ /*
+ * Write a status message with the page number and number of copies.
+ */
+
+ if (Canceled)
+ break;
+
+ Page ++;
+
+ fprintf(stderr, "PAGE: %d 1\n", Page);
+ _cupsLangPrintFilter(stderr, "INFO", _("Starting page %d."), Page);
+
+ /*
+ * Start the page...
+ */
+
+ StartPage(ppd, &header);
+
+ /*
+ * Loop for each line on the page...
+ */
+
+ for (y = 0; y < header.cupsHeight && !Canceled; y ++)
+ {
+ /*
+ * Let the user know how far we have progressed...
+ */
+
+ if (Canceled)
+ break;
+
+ if ((y & 15) == 0)
+ {
+ _cupsLangPrintFilter(stderr, "INFO",
+ _("Printing page %d, %d%% complete."),
+ Page, 100 * y / header.cupsHeight);
+ fprintf(stderr, "ATTR: job-media-progress=%d\n",
+ 100 * y / header.cupsHeight);
+ }
+
+ /*
+ * Read a line of graphics...
+ */
+
+ if (cupsRasterReadPixels(ras, Buffer, header.cupsBytesPerLine) < 1)
+ break;
+
+ /*
+ * Write it to the printer...
+ */
+
+ OutputLine(ppd, &header, y);
+ }
+
+ /*
+ * Eject the page...
+ */
+
+ _cupsLangPrintFilter(stderr, "INFO", _("Finished page %d."), Page);
+
+ EndPage(ppd, &header);
+
+ if (Canceled)
+ break;
+ }
+
+ /*
+ * Close the raster stream...
+ */
+
+ cupsRasterClose(ras);
+ if (fd != 0)
+ close(fd);
+
+ /*
+ * Close the PPD file and free the options...
+ */
+
+ ppdClose(ppd);
+ cupsFreeOptions(num_options, options);
+
+ /*
+ * If no pages were printed, send an error message...
+ */
+
+ if (Page == 0)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("No pages were found."));
+ return (1);
+ }
+ else
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("Ready to print."));
+ return (0);
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/rastertopwg.c b/filter/rastertopwg.c
new file mode 100644
index 000000000..6f6497c09
--- /dev/null
+++ b/filter/rastertopwg.c
@@ -0,0 +1,218 @@
+/*
+ * "$Id$"
+ *
+ * CUPS raster to PWG raster format filter for CUPS.
+ *
+ * Copyright 2011 Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry for filter.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <cups/language-private.h>
+#include <cups/raster.h>
+#include <cups/string-private.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+
+/*
+ * 'main()' - Main entry for filter.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int fd; /* Raster file */
+ cups_raster_t *inras, /* Input raster stream */
+ *outras; /* Output raster stream */
+ cups_page_header2_t inheader, /* Input raster page header */
+ outheader; /* Output raster page header */
+ int y; /* Current line */
+ unsigned char *line; /* Line buffer */
+ int page = 0, /* Current page */
+ page_width, /* Actual page width */
+ page_height, /* Actual page height */
+ page_top, /* Top margin */
+ page_bottom, /* Bottom margin */
+ page_left, /* Left margin */
+ linesize, /* Bytes per line */
+ lineoffset; /* Offset into line */
+ unsigned char white; /* White pixel */
+
+
+ if (argc < 6 || argc > 7)
+ {
+ puts("Usage: rastertopwg job user title copies options [filename]");
+ return (1);
+ }
+ else if (argc == 7)
+ {
+ if ((fd = open(argv[6], O_RDONLY)) < 0)
+ {
+ perror("ERROR: Unable to open print file");
+ return (1);
+ }
+ }
+ else
+ fd = 0;
+
+ inras = cupsRasterOpen(fd, CUPS_RASTER_READ);
+ outras = cupsRasterOpen(1, CUPS_RASTER_WRITE_PWG);
+
+ while (cupsRasterReadHeader2(inras, &inheader))
+ {
+ /*
+ * Compute the real raster size...
+ */
+
+ page ++;
+
+ fprintf(stderr, "PAGE: %d %d\n", page, inheader.NumCopies);
+
+ page_width = (int)(inheader.cupsPageSize[0] * inheader.HWResolution[0] /
+ 72.0);
+ page_height = (int)(inheader.cupsPageSize[1] * inheader.HWResolution[1] /
+ 72.0);
+ page_left = (int)(inheader.cupsImagingBBox[0] *
+ inheader.HWResolution[0] / 72.0);
+ page_bottom = (int)(inheader.cupsImagingBBox[1] *
+ inheader.HWResolution[1] / 72.0);
+ page_top = page_height - page_bottom - inheader.cupsHeight;
+ linesize = (page_width * inheader.cupsBitsPerPixel + 7) / 8;
+ lineoffset = page_left * inheader.cupsBitsPerPixel / 8; /* Round down */
+
+ switch (inheader.cupsColorSpace)
+ {
+ case CUPS_CSPACE_W :
+ case CUPS_CSPACE_RGB :
+ case CUPS_CSPACE_SW :
+ case CUPS_CSPACE_SRGB :
+ case CUPS_CSPACE_ADOBERGB :
+ white = 255;
+ break;
+
+ case CUPS_CSPACE_K :
+ case CUPS_CSPACE_CMYK :
+ case CUPS_CSPACE_DEVICE1 :
+ case CUPS_CSPACE_DEVICE2 :
+ case CUPS_CSPACE_DEVICE3 :
+ case CUPS_CSPACE_DEVICE4 :
+ case CUPS_CSPACE_DEVICE5 :
+ case CUPS_CSPACE_DEVICE6 :
+ case CUPS_CSPACE_DEVICE7 :
+ case CUPS_CSPACE_DEVICE8 :
+ case CUPS_CSPACE_DEVICE9 :
+ case CUPS_CSPACE_DEVICEA :
+ case CUPS_CSPACE_DEVICEB :
+ case CUPS_CSPACE_DEVICEC :
+ case CUPS_CSPACE_DEVICED :
+ case CUPS_CSPACE_DEVICEE :
+ case CUPS_CSPACE_DEVICEF :
+ white = 0;
+ break;
+ default :
+ _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
+ fprintf(stderr, "DEBUG: Unsupported cupsColorSpace %d on page %d.\n",
+ inheader.cupsColorSpace, page);
+ return (1);
+ }
+
+ if (inheader.cupsColorOrder != CUPS_ORDER_CHUNKED)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
+ fprintf(stderr, "DEBUG: Unsupported cupsColorOrder %d on page %d.\n",
+ inheader.cupsColorOrder, page);
+ return (1);
+ }
+
+ if (inheader.cupsBitsPerPixel != 1 &&
+ inheader.cupsBitsPerColor != 8 && inheader.cupsBitsPerColor != 16)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
+ fprintf(stderr, "DEBUG: Unsupported cupsBitsPerColor %d on page %d.\n",
+ inheader.cupsBitsPerColor, page);
+ return (1);
+ }
+
+ memcpy(&outheader, &inheader, sizeof(outheader));
+ outheader.cupsWidth = page_width;
+ outheader.cupsHeight = page_height;
+ outheader.cupsBytesPerLine = linesize;
+
+ if (!cupsRasterWriteHeader2(outras, &outheader))
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
+ fprintf(stderr, "DEBUG: Unable to write header for page %d.\n", page);
+ return (1);
+ }
+
+ /*
+ * Copy raster data...
+ */
+
+ line = malloc(linesize);
+
+ memset(line, white, linesize);
+ for (y = page_top; y > 0; y --)
+ if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
+ fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n",
+ page_top - y + 1, page);
+ return (1);
+ }
+
+ for (y = inheader.cupsHeight; y > 0; y --)
+ {
+ cupsRasterReadPixels(inras, line + lineoffset, inheader.cupsBytesPerLine);
+ if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
+ fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n",
+ inheader.cupsHeight - y + page_top + 1, page);
+ return (1);
+ }
+ }
+
+ memset(line, white, linesize);
+ for (y = page_top; y > 0; y --)
+ if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
+ fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n",
+ page_bottom - y + page_top + inheader.cupsHeight + 1, page);
+ return (1);
+ }
+
+ free(line);
+ }
+
+ cupsRasterClose(inras);
+ if (fd)
+ close(fd);
+
+ cupsRasterClose(outras);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/spec-ppd.header b/filter/spec-ppd.header
new file mode 100644
index 000000000..c8793d378
--- /dev/null
+++ b/filter/spec-ppd.header
@@ -0,0 +1,32 @@
+<!--
+ "$Id: spec-ppd.header 9680 2011-04-13 15:45:24Z mike $"
+
+ PPD extension documentation for CUPS.
+
+ Copyright 2007-2011 by Apple Inc.
+ Copyright 1997-2007 by Easy Software Products.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<H1 CLASS="title">CUPS PPD Extensions</H1>
+
+<p>This specification describes the attributes and extensions that CUPS adds to <a href="http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf" target="_blank">Adobe TechNote #5003: PostScript Printer Description File Format Specification Version 4.3</a>. PostScript Printer Description ("PPD") files describe the capabilities of each printer and are used by CUPS to support printer-specific features and intelligent filtering.</p>
+
+<div class='summary'><table summary='General Information'>
+<tbody>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='postscript-driver.html'>Developing PostScript Printer Drivers</a><br>
+ Programming: <a href='raster-driver.html'>Developing Raster Printer Drivers</a><br>
+ Programming: <a href='api-filter.html'>Filter and Backend Programming</a><br>
+ Programming: <a href='ppd-compiler.html'>Introduction to the PPD Compiler</a><br>
+ Programming: <a href='api-raster.html'>Raster API</a><br>
+ References: <a href='ref-ppdcfile.html'>PPD Compiler Driver Information File Reference</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/filter/spec-ppd.shtml b/filter/spec-ppd.shtml
new file mode 100644
index 000000000..a1809636b
--- /dev/null
+++ b/filter/spec-ppd.shtml
@@ -0,0 +1,1900 @@
+<h2 class='title'><a name='SYNTAX'>PPD File Syntax</a></h2>
+
+<p>The PPD format is text-based and uses lines of up to 255 characters terminated by a carriage return, linefeed, or combination of carriage return and line feed. The following ABNF definition [<a href="http://tools.ietf.org/html/rfc5234" target="_blank">RFC5234</a>] defines the general format of lines in a PPD file:</p>
+
+<pre class='command'>
+PPD-FILE = HEADER +(DATA / COMMENT / LINE-END)
+
+HEADER = "*PPD-Adobe:" *WSP DQUOTE VERSION DQUOTE LINE-END
+
+VERSION = "4.0" / "4.1" / "4.2" / "4.3"
+
+COMMENT = "*%" *TCHAR LINE-END
+
+DATA = "*" 1*KCHAR [ WSP 1*KCHAR [ "/" 1*TCHAR ] ] ":"
+ 1*(*WSP VALUE) LINE-END
+
+VALUE = 1*TCHAR / DQUOTE 1*SCHAR DQUOTE
+
+KCHAR = ALPHA / DIGIT / "_" / "." / "-"
+
+SCHAR = LINE-END / WSP / %x21.23-7E.A0-FF
+
+TCHAR = %x20-7E.A0-FF
+
+LINE-END = CR / LF / CR LF
+</pre>
+
+
+<h2 class='title'><a name='AUTOCONFIG'>Auto-Configuration</a></h2>
+
+<p>CUPS supports several methods of auto-configuration via PPD keywords.</p>
+
+<h3><span class='info'>Mac OS X 10.5</span><a name='APAutoSetupTool'>APAutoSetupTool</a></h3>
+
+<p class='summary'>*APAutoSetupTool: "/LibraryPrinters/vendor/filename"</p>
+
+<p>This Mac OS X keyword defines a program that sets the default option choices. It is run when a printer is added from the <var>Add Printer</var> window or the <var>Nearby Printers</var> list in the <var>Print</var> dialog.</p>
+
+<p>The program is provided with two arguments: the printer's device URI and the PPD file to be used for the printer. The program must write an updated PPD file to stdout.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Use our setup tool when adding a printer
+*APAutoSetupTool: "/Library/Printers/vendor/Tools/autosetuptool"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.2/CUPS 1.4</span><a name='QUERYKEYWORD'>?MainKeyword</a></h3>
+
+<p class='summary'>*?<i>MainKeyword</i>: "<br>
+ PostScript query code that writes a message using the = operator...<br>
+"<br>
+*End</p>
+
+<p>The <tt>?<i>MainKeyword</i></tt> keyword defines PostScript code that determines the currently selected/enabled option keyword (choice) for the main keyword (option). It is typically used when communicating with USB, serial, Appletalk, and AppSocket (port 9100) printers.</p>
+
+<p>The PostScript code typically sends its response back using the <tt>=</tt> operator.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+*OpenUI OptionDuplex/Duplexer Installed: Boolean
+*DuplexOptionDuplex: False
+*OptionDuplex False/Not Installed: ""
+*OptionDuplex True/Installed: ""
+
+<em>*% Query the printer for the presence of the duplexer option...</em>
+*?OptionDuplex: "
+ currentpagedevice /Duplex known
+ {(True)} {(False)} ifelse
+ = flush
+"
+*End
+*CloseUI: OptionDuplex
+</pre>
+
+<h3><span class='info'>Mac OS X 10.4/CUPS 1.5</span><a name='OID'>OIDMainKeyword</a></h3>
+
+<p class='summary'>*?OID<i>MainKeyword</i>: ".n.n.n..."<br>
+*OID<i>MainKeyword</i> <i>OptionKeyword1</i>: "value"<br>
+...<br>
+*OID<i>MainKeyword</i> <i>OptionKeywordN</i>: "value"</p>
+
+<p>The <tt>OID<i>MainKeyword</i></tt> keyword is used to define SNMP OIDs that map to installable options. The first (query) line defines the OID to lookup on the network device. The second and subsequent keywords define a mapping from OID value to option keyword. Since SNMP is an IP-based network protocol, this method is typically only used to configure AppSocket, IPP, and LPD network printers.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Get the installed memory on the printer...
+*?OIDInstalledMemory: ".1.3.6.1.2.1.25.2.2.0"
+*OIDInstalledMemory 16MB: "16384 KBytes"
+*OIDInstalledMemory 32MB: "32768 KBytes"
+*OIDInstalledMemory 48MB: "49152 KBytes"
+*OIDInstalledMemory 72MB: "73728 KBytes"
+</pre>
+
+
+<h2 class='title'><a name='PROFILES'>Color Profiles</a></h2>
+
+<p>CUPS supports three types of color profiles. The first type is based on sRGB and is used by the standard CUPS raster filters and GPL Ghostscript. The second type is based on ICC profiles and is used by the Quartz-based filters on MacOS X. The final type is based on well-known colorspaces such as sRGB and Adobe RGB.</p>
+
+<blockquote><b>Note:</b>
+
+<p>At this time, none of the CUPS raster filters support ICC profiles. This will be addressed as time and resources permit.</p>
+
+</blockquote>
+
+<h3><span class='info'>Deprecated</span><a name='cupsColorProfile'>cupsColorProfile</a></h3>
+
+<p class='summary'>*cupsColorProfile Resolution/MediaType: "density gamma m00 m01 m02 m10 m11 m12 m20 m21 m22"</p>
+
+<p>This string keyword specifies an sRGB-based color profile consisting of gamma and density controls and a 3x3 CMY color transform matrix. <em>This keyword is not supported on Mac OS X.</em></p>
+
+<p>The <i>Resolution</i> and <i>MediaType</i> values may be "-" to act as a wildcard. Otherwise they must match one of the <tt>Resolution</tt> or <tt>MediaType</tt> option keywords defined in the PPD file.</p>
+
+<p>The <i>density</i> and <i>gamma</i> values define gamma and
+density adjustment function such that:</p>
+
+<pre class='command'>
+f(x) = density * x <sup style='font-size: 100%'>gamma</sup>
+</pre>
+
+<p>The <i>m00</i> through <i>m22</i> values define a 3x3 transformation matrix for the CMY color values. The density function is applied <i>after</i> the CMY transformation:</p>
+
+<pre class='command'>
+| m00 m01 m02 |
+| m10 m11 m12 |
+| m20 m21 m22 |
+</pre>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify a profile for printing at 360dpi on all media types</em>
+*cupsColorProfile 360dpi/-: "1.0 1.5 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
+
+<em>*% Specify a profile for printing at 720dpi on Glossy media</em>
+*cupsColorProfile 720dpi/Glossy: "1.0 2.5 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
+
+<em>*% Specify a default profile for printing at all other resolutions and media types</em>
+*cupsColorProfile -/-: "0.9 2.0 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
+</pre>
+
+
+<h3><span class='info'>Mac OS X 10.3/CUPS 1.2</span><a name='cupsICCProfile'>cupsICCProfile</a></h3>
+
+<p class='summary'>*cupsICCProfile ColorModel.MediaType.Resolution/Description: "filename"</p>
+
+<p>This keyword specifies an ICC color profile that is used to convert the document colors to the device colorspace. The <tt>ColorModel</tt>, <tt>MediaType</tt>, and <tt>Resolution</tt> option keywords specify a selector for color profiles. If omitted, the color profile will match any option keyword for the corresponding main keyword.</p>
+
+<p>The <tt>Description</tt> specifies human-readable text that is associated with the color profile. The <tt>filename</tt> portion specifies the ICC color profile to use; if the filename is not absolute, it is loaded relative to the <var>/usr/share/cups/profiles</var> directory.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify a profile for CMYK printing at 360dpi on all media types</em>
+*cupsICCProfile CMYK..360dpi/360dpi CMYK: "/Library/Printers/vendor/Profiles/foo-360-cmyk.icc"
+
+<em>*% Specify a profile for RGB printing at 720dpi on Glossy media</em>
+*cupsColorProfile RGB.Glossy.720dpi/720dpi Glossy: "/Library/Printers/vendor/Profiles/foo-720-glossy-rgb.icc"
+
+<em>*% Specify a default profile for printing at all other resolutions and media types</em>
+*cupsICCProfile ../Default: "/Library/Printers/vendor/Profiles/foo-default.icc"
+</pre>
+
+<h4>Customizing the Profile Selection Keywords</h4>
+
+<p>The <tt>MediaType</tt> and <tt>Resolution</tt> main keywords can be reassigned to different main keywords, allowing drivers to do color profile selection based on different parameters. The <tt>cupsICCQualifier2</tt> and <tt>cupsICCQualifier3</tt> keywords define the mapping from selector to main keyword:</p>
+
+<pre class='command'>
+*cupsICCQualifier2: MainKeyword2
+*cupsICCQualifier3: MainKeyword3
+</pre>
+
+<p>The default mapping is as follows:</p>
+
+<pre class='command'>
+*cupsICCQualifier2: MediaType
+*cupsICCQualifier3: Resolution
+</pre>
+
+<h3><span class='info'>Mac OS X 10.4</span><a name='APCustom'>Custom Color Matching Support</a></h3>
+
+<p class='summary'>*<a href='#APSupportsCustomColorMatching'>APSupportsCustomColorMatching</a>: true<br>
+*<a href='#APCustomColorMatchingName'>APCustomColorMatchingName</a> name/text: ""<br>
+*<a href='#APCustomColorMatchingProfile'>APCustomColorMatchingProfile</a>: profile<br>
+*<a href='#APDefaultCustomColorMatchingProfile'>APDefaultCustomColorMatchingProfile</a>: profile</p>
+
+<p>These keywords tell the Mac OS X raster filters that the printer driver provides its own custom color matching and that generic color profiles should be used when generating 1-, 3-, and 4-component raster data as requested by the driver. The <tt>APCustomColorMatchingProfile</tt> and <tt>APDefaultColorMatchingProfile</tt> keywords specify alternate color profiles (sRGB or AdobeRGB) to use for 3-color (RGB) raster data.</p>
+
+<blockquote><b>Note:</b>
+
+<p>Prior to Mac OS X 10.6, the default RGB color space was Apple's "GenericRGB". The new default in Mac OS X 10.6 and later is "sRGB". For more information, see <a href="http://support.apple.com/kb/HT3712">"Mac OS X v10.6: About gamma 2.2"</a> on Apple's support site.</p>
+
+</blockquote>
+
+<h4><span class='info'>Mac OS X 10.5</span><a name='APCustomColorMatchingName'>APCustomColorMatchingName</a></h4>
+
+<p class='summary'>*APCustomColorMatchingName name/text: ""</p>
+
+<p>This keyword defines an alternate name for the color matching provided by a driver in the <var>Color Matching</var> print panel. The default is to use the name "Vendor Matching" or its localized equivalent.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Define the names for our color matching...
+*APCustomColorMatchingName name/AcmeColor(tm): ""
+*fr.APCustomColorMatchingName name/La AcmeColor(tm): ""
+</pre>
+
+<h4><span class='info'>Mac OS X 10.5</span><a name='APCustomColorMatchingProfile'>APCustomColorMatchingProfile</a></h4>
+
+<p class='summary'>*APCustomColorMatchingProfile: name</p>
+
+<p>This keyword defines a supported RGB color profile that can be used when doing custom color matching. Currently only <tt>sRGB</tt>, <tt>AdobeRGB</tt>, and <tt>GenericRGB</tt> are supported. If not specified, RGB data will use the GenericRGB colorspace.</p>
+
+<blockquote><b>Note:</b>
+
+<p>If you provide multiple <tt>APCustomColorMatchingProfile</tt> keywords, you are responsible for providing the necessary user interface controls to select the profile in a <a href='#APDialogExtension'>print dialog pane</a>. Add the named profile to the print settings using the key <tt>kPMCustomColorMatchingProfileKey</tt>.</p>
+
+</blockquote>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Use sRGB for RGB color by default, but support both sRGB and AdobeRGB
+*APSupportsCustomColorMatching: true
+*APDefaultCustomColorMatchingProfile: sRGB
+*APCustomColorMatchingProfile: sRGB
+*APCustomColorMatchingProfile: AdobeRGB
+</pre>
+
+<h4><span class='info'>Mac OS X 10.5</span><a name='APDefaultCustomColorMatchingProfile'>APDefaultCustomColorMatchingProfile</a></h4>
+
+<p class='summary'>*APDefaultCustomColorMatchingProfile: name</p>
+
+<p>This keyword defines the default RGB color profile that will be used when doing custom color matching. Currently only <tt>sRGB</tt>, <tt>AdobeRGB</tt>, and <tt>GenericRGB</tt> are supported.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Use sRGB for RGB color by default
+*APSupportsCustomColorMatching: true
+*APDefaultCustomColorMatchingProfile: sRGB
+</pre>
+
+<h4><span class='info'>Mac OS X 10.4</span><a name='APSupportsCustomColorMatching'>APSupportsCustomColorMatching</a></h4>
+
+<p class='summary'>*APSupportsCustomColorMatching: boolean</p>
+
+<p>This keyword specifies that the driver provides its own custom color matching. When <tt>true</tt>, the default hand-off colorspace will be GenericGray, GenericRGB, or GenericCMYK depending on the number of components the driver requests. The <a href='#APDefaultCustomColorMatchingProfile'><tt>APDefaultCustomColorMatchingProfile</tt></a> keyword can be used to override the default 3-component (RGB) colorspace.</p>
+
+<p>The default for <tt>APSupportsCustomColorMatching</tt> is <tt>false</tt>.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APSupportsCustomColorMatching: true
+*APDefaultCustomColorMatchingProfile: sRGB
+</pre>
+
+
+<h2 class='title'><a name='CONSTRAINTS'>Constraints</a></h2>
+
+<p>Constraints are option choices that are not allowed by the driver or device, for example printing 2-sided transparencies. All versions of CUPS support constraints defined by the legacy Adobe <tt>UIConstraints</tt> and <tt>NonUIConstraints</tt> keywords which support conflicts between any two option choices, for example:</p>
+
+<pre class='command'>
+*% Do not allow 2-sided printing on transparency media
+*UIConstraints: "*Duplex *MediaType Transparency"
+*UIConstraints: "*MediaType Transparency *Duplex"
+</pre>
+
+<p>While nearly all constraints can be expressed using these keywords, there are valid scenarios requiring constraints between more than two option choices. In addition, resolution of constraints is problematic since users and software have to guess how a particular constraint is best resolved.</p>
+
+<p>CUPS 1.4 and higher define two new keywords for constraints, <tt>cupsUIConstraints</tt> and <tt>cupsUIResolver</tt>. Each <tt>cupsUIConstraints</tt> keyword points to a <tt>cupsUIResolver</tt> keyword which specifies alternate options that resolve the conflict condition. The same <tt>cupsUIResolver</tt> can be used by multiple <tt>cupsUIConstraints</tt>.</p>
+
+<blockquote><b>Note:</b>
+
+<p>When developing PPD files that contain constraints, it is very important to use the <a href="man-cupstestppd.html">cupstestppd(1)</a> program to verify that your constraints are accurate and cannot result in unresolvable option selections.</p>
+
+</blockquote>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsUIConstraints'>cupsUIConstraints</a></h3>
+
+<p class='summary'>*cupsUIConstraints resolver: "*Keyword1 *Keyword2 ..."<br>
+*cupsUIConstraints resolver: "*Keyword1 OptionKeyword1 *Keyword2 ..."<br>
+*cupsUIConstraints resolver: "*Keyword1 *Keyword2 OptionKeyword2 ..."<br>
+*cupsUIConstraints resolver: "*Keyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."<br>
+*cupsUIConstraints: "*InstallableKeyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."</p>
+
+<p>Lists two or more options which conflict. The "resolver" string is a (possibly unique) keyword which specifies which options to change when the constraint exists. When no resolver is provided, CUPS first tries the default choice followed by testing each option choice to resolve the conflict.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify that 2-sided printing cannot happen on transparencies</em>
+*cupsUIConstraints transparency: "*Duplex *MediaType Transparency"
+
+<em>*% Specify that envelope printing cannot happen from the paper trays</em>
+*cupsUIConstraints envelope: "*PageSize Env10 *InputSlot Tray1"
+*cupsUIConstraints envelope: "*PageSize Env10 *InputSlot Tray1"
+*cupsUIConstraints envelope: "*PageSize EnvDL *InputSlot Tray2"
+*cupsUIConstraints envelope: "*PageSize EnvDL *InputSlot Tray2"
+
+<em>*% Specify an installable option constraint for the envelope feeder</em>
+*cupsUIConstraints: "*InputSlot EnvFeeder *InstalledEnvFeeder"
+
+<em>*% Specify that photo printing cannot happen on plain paper or transparencies at 1200dpi</em>
+*cupsUIConstraints photo: "*OutputMode Photo *MediaType Plain *Resolution 1200dpi"
+*cupsUIConstraints photo: "*OutputMode Photo *MediaType Transparency *Resolution 1200dpi"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsUIResolver'>cupsUIResolver</a></h3>
+
+<p class='summary'>*cupsUIResolver resolver: "*Keyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."</p>
+
+<p>Specifies two or more options to mark/select to resolve a constraint. The "resolver" string identifies a particular action to take for one or more <a href='#cupsUIConstraints'><tt>cupsUIConstraints</tt></a>. The same action can be used for multiple constraints. The option keyword pairs are treated as an ordered list of option selections to try - only the first N selections will be used, where N is the minimum number of selections required. Because <a href="api-ppd.html#cupsResolveConflicts"><code>cupsResolveConflicts()</code></a> will not change the most recent option selection passed to it, at least two options from the constraints must be listed to avoid situations where conflicts cannot be resolved.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify the options to change for the 2-sided transparency constraint</em>
+*cupsUIResolver transparency: "*Duplex None *MediaType Plain"
+
+<em>*% Specify the options to change for the envelope printing constraints. Notice
+*% that we try to change the InputSlot to either the envelope feeder or the
+*% manual feed first, then we change the page size...</em>
+*cupsUIResolver envelope: "*InputSlot EnvFeeder *InputSlot ManualFeed *PageSize Letter"
+
+<em>*% Specify the options to change for the photo printing constraints</em>
+*cupsUIResolver photo: "*OutputMode Best *Resolution 600dpi"
+</pre>
+
+
+<h2 class='title'><a name='I18N'>Globalized PPD Support</a></h2>
+
+<p>CUPS 1.2 and higher adds support for PPD files containing multiple languages by following the following additional rules:</p>
+
+<ol>
+
+ <li>The <tt>LanguageVersion</tt> MUST be <tt>English</tt></li>
+
+ <li>The <tt>LanguageEncoding</tt> MUST be <tt>ISOLatin1</tt></li>
+
+ <li>The <tt>cupsLanguages</tt> keyword MUST be provided and list each of the supported locales in the PPD file</li>
+
+ <li>Main and option keywords MUST NOT exceed 34 (instead of 40) characters to allow room for the locale prefixes in translation keywords</li>
+
+ <li>The main keyword "Translation" MUST NOT be used</li>
+
+ <li>Translation strings included with the main and option keywords MUST NOT contain characters outside the ASCII subset of ISOLatin1 and UTF-8; developers wishing to use characters outside ASCII MUST provide a separate set of English localization keywords for the affected keywords.</li>
+
+ <li>Localizations are specified using a locale prefix of the form "ll" or "ll_CC." where "ll" is the 2-letter ISO language code and "CC" is the 2-letter ISO country code<ul>
+ <li>A generic language translation ("ll") SHOULD be provided with country-specific differences ("ll_CC") provided only as needed</li>
+ <li>For historical reasons, the "zh" and "zh_CN" locales map to Simplified Chinese while the "zh_TW" locale maps to Traditional Chinese</li>
+ </ul></li>
+
+ <li>Locale-specific translation strings MUST be encoded using UTF-8.</li>
+
+ <li>Main keywords MUST be localized using one of the following forms:
+ <p><tt>*ll.Translation MainKeyword/translation text: ""</tt><br />
+ <tt>*ll_CC.Translation MainKeyword/translation text: ""</tt></p></li>
+
+ <li>Option keywords MUST be localized using one of the following forms:
+ <p><tt>*ll.MainKeyword OptionKeyword/translation text: ""</tt><br>
+ <tt>*ll_CC.MainKeyword OptionKeyword/translation text: ""</tt></p></li>
+
+ <li>Localization keywords MAY appear anywhere after the first line of the PPD file</li>
+
+</ol>
+
+<blockquote><b>Note:</b>
+
+<p>We use a <tt>LanguageEncoding</tt> value of <tt>ISOLatin1</tt> and limit the allowed base translation strings to ASCII to avoid character coding issues that would otherwise occur. In addition, requiring the base translation strings to be in English allows for easier fallback translation when no localization is provided in the PPD file for a given locale.</p>
+
+</blockquote>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*LanguageVersion: English
+*LanguageEncoding: ISOLatin1
+*cupsLanguages: "de fr_CA"
+*ModelName: "Foobar Laser 9999"
+
+<em>*% Localize ModelName for French and German</em>
+*fr_CA.Translation ModelName/La Foobar Laser 9999: ""
+*de.Translation ModelName/Foobar LaserDrucken 9999: ""
+
+*cupsIPPReason com.vendor-error/A serious error occurred: "/help/com.vendor/error.html"
+<em>*% Localize printer-state-reason for French and German</em>
+*fr_CA.cupsIPPReason com.vendor-error/Une erreur s&egrave;rieuse s'est produite: "/help/com.vendor/error.html"
+*de.cupsIPPReason com.vendor-error/Eine ernste St&ouml;rung trat: "/help/com.vendor/error.html"
+
+...
+
+*OpenUI *InputSlot/Paper Source: PickOne
+*OrderDependency: 10 AnySetup *InputSlot
+*DefaultInputSlot: Auto
+<em>*% Localize InputSlot for French and German</em>
+*fr_CA.Translation InputSlot/Papier source: ""
+*de.Translation InputSlot/Papiereinzug: ""
+*InputSlot Auto/Default: "&lt;&lt;/ManualFeed false&gt;&gt;setpagedevice"
+<em>*% Localize InputSlot=Auto for French and German</em>
+*fr_CA.InputSlot Auto/Par Defaut: ""
+*de.InputSlot Auto/Standard: ""
+*InputSlot Manual/Manual Feed: "&lt;&lt;/ManualFeed true&gt;&gt;setpagedevice"
+<em>*% Localize InputSlot=Manual for French and German</em>
+*fr_CA.InputSlot Manual/Manuel mecanisme de alimentation: ""
+*de.InputSlot Manual/Manueller Einzug: ""
+*CloseUI: *InputSlot
+</pre>
+
+
+<h2 class='title'><a name='OPTIONS'><span class="info">CUPS 1.3/Mac OS X 10.6</span>Custom Options</a></h2>
+
+<p>CUPS supports custom options using an extension of the <tt>CustomPageSize</tt> and <tt>ParamCustomPageSize</tt> syntax:</p>
+
+<pre class='command'>
+*CustomFoo True: "command"
+*ParamCustomFoo Name1/Text 1: order type minimum maximum
+*ParamCustomFoo Name2/Text 2: order type minimum maximum
+...
+*ParamCustomFoo NameN/Text N: order type minimum maximum
+</pre>
+
+<p>When the base option is part of the <tt>JCLSetup</tt> section, the "command" string contains JCL commands with "\order" placeholders for each numbered parameter. The CUPS API handles any necessary value quoting for HP-PJL commands. For example, if the JCL command string is "@PJL SET PASSCODE=\1" and the first
+option value is "1234" then CUPS will output the string "@PJL SET PASSCODE=1234".</p>
+
+<p>For non-<tt>JCLSetup</tt> options, the "order" value is a number from 1 to N and specifies the order of values as they are placed on the stack before the command. For example, if the PostScript command string is "&lt;&lt;/cupsReal1 2 1 roll&gt;&gt;setpagedevice" and the option value is "2.0" then CUPS will output the string "2.0 &lt;&lt;/cupsReal1 2 1 roll&gt;&gt;setpagedevice".</p>
+
+<p>The "type" is one of the following keywords:</p>
+
+<ul>
+
+ <li><tt>curve</tt> - a real value from "minimum" to "maximum" representing a gamma correction curve using the function: f(x) = x <sup>value</sup></li>
+
+ <li><tt>int</tt> - an integer value from "minimum" to "maximum"</li>
+
+ <li><tt>invcurve</tt> - a real value from "minimum" to "maximum" representing a gamma correction curve using the function: f(x) = x <sup>1 / value</sup></li>
+
+ <li><tt>passcode</tt> - a string of numbers value with a minimum of "minimum" numbers and a maximum of "maximum" numbers ("minimum" and "maximum" are numbers and passcode strings are not displayed in the user interface)</li>
+
+ <li><tt>password</tt> - a string value with a minimum of "minimum" characters and a maximum of "maximum" characters ("minimum" and "maximum" are numbers and password strings are not displayed in the user interface)</li>
+
+ <li><tt>points</tt> - a measurement value in points from "minimum" to "maximum"</li>
+
+ <li><tt>real</tt> - a real value from "minimum" to "maximum"</li>
+
+ <li><tt>string</tt> - a string value with a minimum of "minimum" characters and a maximum of "maximum" characters ("minimum" and "maximum" are numbers)</li>
+
+</ul>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Base JCL key code option</em>
+*JCLOpenUI JCLPasscode/Key Code: PickOne
+*OrderDependency: 10 JCLSetup *JCLPasscode
+*DefaultJCLPasscode: None
+*JCLPasscode None/No Code: ""
+*JCLPasscode 1111: "@PJL SET PASSCODE = 1111&lt;0A&gt;"
+*JCLPasscode 2222: "@PJL SET PASSCODE = 2222&lt;0A&gt;"
+*JCLPasscode 3333: "@PJL SET PASSCODE = 3333&lt;0A&gt;"
+*JCLCloseUI: *JCLPasscode
+
+<em>*% Custom JCL key code option</em>
+*CustomJCLPasscode True: "@PJL SET PASSCODE = \1&lt;0A&gt;"
+*ParamCustomJCLPasscode Code/Key Code: 1 passcode 4 4
+
+
+<em>*% Base PostScript watermark option</em>
+*OpenUI WatermarkText/Watermark Text: PickOne
+*OrderDependency: 10 AnySetup *WatermarkText
+*DefaultWatermarkText: None
+*WatermarkText None: ""
+*WatermarkText Draft: "&lt;&lt;/cupsString1(Draft)&gt;&gt;setpagedevice"
+*CloseUI: *WatermarkText
+
+<em>*% Custom PostScript watermark option</em>
+*CustomWatermarkText True: "&lt;&lt;/cupsString1 3 -1 roll&gt;&gt;setpagedevice"
+*ParamCustomWatermarkText Text: 1 string 0 32
+
+
+<em>*% Base PostScript gamma/density option</em>
+*OpenUI GammaDensity/Gamma and Density: PickOne
+*OrderDependency: 10 AnySetup *GammaDensity
+*DefaultGammaDensity: Normal
+*GammaDensity Normal/Normal: "&lt;&lt;/cupsReal1 1.0/cupsReal2 1.0&gt;&gt;setpagedevice"
+*GammaDensity Light/Lighter: "&lt;&lt;/cupsReal1 0.9/cupsReal2 0.67&gt;&gt;setpagedevice"
+*GammaDensity Dark/Darker: "&lt;&lt;/cupsReal1 1.1/cupsReal2 1.5&gt;&gt;setpagedevice"
+*CloseUI: *GammaDensity
+
+<em>*% Custom PostScript gamma/density option</em>
+*CustomGammaDensity True: "&lt;&lt;/cupsReal1 3 -1 roll/cupsReal2 5 -1&gt;&gt;setpagedevice"
+*ParamCustomGammaDensity Gamma: 1 curve 0.1 10
+*ParamCustomGammaDensity Density: 2 real 0 2
+</pre>
+
+
+<h2 class='title'><a name='RASTERPS'>Writing PostScript Option Commands for Raster Drivers</a></h2>
+
+<p>PPD files are used for both PostScript and non-PostScript printers. For CUPS raster drivers, you use a subset of the PostScript language to set page device keywords such as page size, resolution, and so forth. For example, the following code sets the page size to A4 size:</p>
+
+<pre class='command'>
+*PageSize A4: "&lt;&lt;/PageSize[595 842]&gt;&gt;setpagedevice"
+</pre>
+
+<p>Custom options typically use other operators to organize the values into a key/value dictionary for <tt>setpagedevice</tt>. For example, our previous <tt>CustomWatermarkText</tt> option code uses the <tt>roll</tt> operator to move the custom string value into the dictionary for <tt>setpagedevice</tt>:</p>
+
+<pre class='command'>
+*CustomWatermarkText True: "&lt;&lt;/cupsString1 3 -1 roll&gt;&gt;setpagedevice"
+</pre>
+
+<p>For a custom string value of "My Watermark", CUPS will produce the following PostScript code for the option:</p>
+
+<pre class='command'>
+(My Watermark)
+&lt;&lt;/cupsString1 3 -1 roll&gt;&gt;setpagedevice
+</pre>
+
+<p>The code moves the string value ("My Watermark") from the bottom of the stack to the top, creating a dictionary that looks like:</p>
+
+<pre class='command'>
+&lt;&lt;/cupsString1(My Watermark)&gt;&gt;setpagedevice
+</pre>
+
+<p>The resulting dictionary sets the page device attributes that are sent to your raster driver in the page header.</p>
+
+<h3>Custom Page Size Code</a></h3>
+
+<p>There are many possible implementations of the <tt>CustomPageSize</tt> code. For CUPS raster drivers, the following code is recommended:</p>
+
+<pre class='command'>
+*ParamCustomPageSize Width: 1 points <i>min-width max-width</i>
+*ParamCustomPageSize Height: 2 points <i>min-height max-height</i>
+*ParamCustomPageSize WidthOffset: 3 points 0 0
+*ParamCustomPageSize HeightOffset: 4 points 0 0
+*ParamCustomPageSize Orientation: 5 int 0 0
+*CustomPageSize True: "pop pop pop &lt;&lt;/PageSize[5 -2 roll]/ImagingBBox null&gt;&gt;setpagedevice"
+</pre>
+
+<h3>Supported PostScript Operators</a></h3>
+
+<p>CUPS supports the following PostScript operators in addition to the usual PostScript number, string (literal and hex-encoded), boolean, null, and name values:</p>
+
+<ul>
+
+ <li><tt>&lt;&lt;</tt> - Start a dictionary.</li>
+
+ <li><tt>&gt;&gt;</tt> - End a dictionary.</li>
+
+ <li><tt>[</tt> - Start an array.</li>
+
+ <li><tt>]</tt> - End an array.</li>
+
+ <li><tt>copy</tt> - Copy the top N objects on the stack.</li>
+
+ <li><tt>dup</tt> - Copy the top object on the stack.</li>
+
+ <li><tt>index</tt> - Copy the Nth from the top object on the stack.</li>
+
+ <li><tt>pop</tt> - Pop the top object on the stack.</li>
+
+ <li><tt>roll</tt> - Shift the top N objects on the stack.</li>
+
+ <li><tt>setpagedevice</tt> - Set the page header values according to the key/value dictionary on the stack.</li>
+
+</ul>
+
+<blockquote><b>Note:</b>
+
+<p><em>Never</em> use the unsupported <tt>dict</tt> or <tt>put</tt>
+operators in your option code. These operators are typically used in
+option code dating back to Level 1 PostScript printers, which did not
+support the simpler <tt>&lt;&lt;</tt> or <tt>&gt;&gt;</tt> operators.
+If you have old option code using <tt>dict</tt> or <tt>put</tt>, you can
+rewrite it very easily to use the newer <tt>&lt;&lt;</tt> and
+<tt>&gt;&gt;</tt> operators instead. For example, the following code
+to set the page size:</p>
+
+<style type='text/css'><!--
+PRE B {
+ background: #000000;
+ color: #ffffff;
+ padding: 2px 5px;
+}
+--></style>
+
+<pre class='command'>
+<b>1 dict dup</b> /PageSize [612 792] <b>put</b> setpagedevice
+</pre>
+
+<p>can be rewritten as:</p>
+
+<pre class='command'>
+<b>&lt;&lt;</b> /PageSize [612 792] <b>&gt;&gt;</b> setpagedevice
+</pre>
+
+</blockquote>
+
+<h3>Supported Page Device Attributes</a></h3>
+
+<p>Table 2 shows the supported page device attributes along with PostScript code examples.</p>
+
+<div class='table'>
+<table summary='Supported Page Device Attributes'>
+<caption>Table 2: <a name='TABLE_2'>Supported Page Device Attributes</a></caption>
+<thead>
+<tr>
+ <th>Name(s)</th>
+ <th>Type</th>
+ <th>Description</th>
+ <th>Example(s)</th>
+</tr>
+</thead>
+<tbody>
+<tr valign='top'>
+ <td><tt>AdvanceDistance</tt></td>
+ <td>Integer</td>
+ <td>Specifies the number of points to advance roll media after printing.</td>
+ <td><tt>&lt;&lt;/AdvanceDistance 18&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>AdvanceMedia</tt></td>
+ <td>Integer</td>
+ <td>Specifies when to advance the media: 0 = never, 1 = after the file, 2 = after the job, 3 = after the set, and 4 = after the page.</td>
+ <td><tt>&lt;&lt;/AdvanceMedia 4&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>Collate</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether collated copies are required.</td>
+ <td><tt>&lt;&lt;/Collate true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>CutMedia</tt></td>
+ <td>Integer</td>
+ <td>Specifies when to cut the media: 0 = never, 1 = after the file, 2 = after the job, 3 = after the set, and 4 = after the page.</td>
+ <td><tt>&lt;&lt;/CutMedia 1&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>Duplex</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether 2-sided printing is required.</td>
+ <td><tt>&lt;&lt;/Duplex true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>HWResolution</tt></td>
+ <td>Integer Array</td>
+ <td>Specifies the resolution of the page image in pixels per inch.</td>
+ <td><tt>&lt;&lt;/HWResolution[1200 1200]&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>InsertSheet</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether to insert a blank sheet before the job.</td>
+ <td><tt>&lt;&lt;/InsertSheet true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>Jog</tt></td>
+ <td>Integer</td>
+ <td>Specifies when to shift the media in the output bin: 0 = never, 1 = after the file, 2 = after the job, 3 = after the set, and 4 = after the page.</td>
+ <td><tt>&lt;&lt;/Jog 2&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>LeadingEdge</tt></td>
+ <td>Integer</td>
+ <td>Specifies the leading edge of the media: 0 = top, 1 = right, 2 = bottom, 3 = left.</td>
+ <td><tt>&lt;&lt;/LeadingEdge 0&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>ManualFeed</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether media should be drawn from the manual feed tray. Note: The <tt>MediaPosition</tt> attribute is preferred over the <tt>ManualFeed</tt> attribute.</td>
+ <td><tt>&lt;&lt;/ManualFeed true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>MediaClass</tt></td>
+ <td>String</td>
+ <td>Specifies a named media.</td>
+ <td><tt>&lt;&lt;/MediaClass (Invoices)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>MediaColor</tt></td>
+ <td>String</td>
+ <td>Specifies the color of the media.</td>
+ <td><tt>&lt;&lt;/MediaColor &gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>MediaPosition</tt></td>
+ <td>Integer</td>
+ <td>Specifies the tray or source of the media.</td>
+ <td><tt>&lt;&lt;/MediaPosition 12&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>MediaType</tt></td>
+ <td>String</td>
+ <td>Specifies the general media type.</td>
+ <td><tt>&lt;&lt;/MediaType (Glossy)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>MediaWeight</tt></td>
+ <td>Integer</td>
+ <td>Specifies the media weight in grams per meter<sup>2</sup>.</td>
+ <td><tt>&lt;&lt;/MediaWeight 100&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>MirrorPrint</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether to flip the output image horizontally.</td>
+ <td><tt>&lt;&lt;/MirrorPrint true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>NegativePrint</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether to invert the output image.</td>
+ <td><tt>&lt;&lt;/NegativePrint true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>NumCopies</tt></td>
+ <td>Integer</td>
+ <td>Specifies the number of copies to produce of each page.</td>
+ <td><tt>&lt;&lt;/NumCopies 100&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>Orientation</tt></td>
+ <td>Integer</td>
+ <td>Specifies the orientation of the output: 0 = portrait, 1 = landscape rotated counter-clockwise, 2 = upside-down, 3 = landscape rotated clockwise.</td>
+ <td><tt>&lt;&lt;/Orientation 3&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>OutputFaceUp</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether to place the media face-up in the output bin/tray.</td>
+ <td><tt>&lt;&lt;/OutputFaceUp true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>OutputType</tt></td>
+ <td>String</td>
+ <td>Specifies the output type name.</td>
+ <td><tt>&lt;&lt;/OutputType (Photo)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>PageSize</tt></td>
+ <td>Integer/Real Array</td>
+ <td>Specifies the width and length/height of the page in points.</td>
+ <td><tt>&lt;&lt;/PageSize[595 842]&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>Separations</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether to produce color separations.</td>
+ <td><tt>&lt;&lt;/Separations true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>TraySwitch</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether to switch trays automatically.</td>
+ <td><tt>&lt;&lt;/TraySwitch true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>Tumble</tt></td>
+ <td>Boolean</td>
+ <td>Specifies whether the back sides of pages are rotated 180 degrees.</td>
+ <td><tt>&lt;&lt;/Tumble true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsBorderlessScalingFactor</tt></td>
+ <td>Real</td>
+ <td>Specifies the amount to scale the page image dimensions.</td>
+ <td><tt>&lt;&lt;/cupsBorderlessScalingFactor 1.01&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsColorOrder</tt></td>
+ <td>Integer</td>
+ <td>Specifies the order of colors: 0 = chunked, 1 = banded, 2 = planar.</td>
+ <td><tt>&lt;&lt;/cupsColorOrder 0&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsColorSpace</tt></td>
+ <td>Integer</td>
+ <td>Specifies the page image colorspace: 0 = W, 1 = RGB, 2 = RGBA, 3 = K, 4 = CMY, 5 = YMC, 6 = CMYK, 7 = YMCK, 8 = KCMY, 9 = KCMYcm, 10 = GMCK, 11 = GMCS, 12 = White, 13 = Gold, 14 = Silver, 15 = CIE XYZ, 16 = CIE Lab, 17 = RGBW, 32 to 46 = CIE Lab (1 to 15 inks)</td>
+ <td><tt>&lt;&lt;/cupsColorSpace 1 &gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsCompression</tt></td>
+ <td>Integer</td>
+ <td>Specifies a driver compression type/mode.</td>
+ <td><tt>&lt;&lt;/cupsCompression 2&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsInteger0<br>
+ ...<br>
+ cupsInteger15</tt></td>
+ <td>Integer</td>
+ <td>Specifies driver integer values.</td>
+ <td><tt>&lt;&lt;/cupsInteger11 1234&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsMarkerType</tt></td>
+ <td>String</td>
+ <td>Specifies the type of ink/toner to use.</td>
+ <td><tt>&lt;&lt;/cupsMarkerType (Black+Color)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsMediaType</tt></td>
+ <td>Integer</td>
+ <td>Specifies a numeric media type.</td>
+ <td><tt>&lt;&lt;/cupsMediaType 999&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsPageSizeName</tt></td>
+ <td>String</td>
+ <td>Specifies the name of the page size.</td>
+ <td><tt>&lt;&lt;/cupsPageSizeName (A4.Full)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsPreferredBitsPerColor</tt></td>
+ <td>Integer</td>
+ <td>Specifies the preferred number of bits per color, typically 8 or 16.</td>
+ <td><tt>&lt;&lt;/cupsPreferredBitsPerColor 16&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsReal0<br>
+ ...<br>
+ cupsReal15</tt></td>
+ <td>Real</td>
+ <td>Specifies driver real number values.</td>
+ <td><tt>&lt;&lt;/cupsReal15 1.234&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsRenderingIntent</tt></td>
+ <td>String</td>
+ <td>Specifies the color rendering intent.</td>
+ <td><tt>&lt;&lt;/cupsRenderingIntent (AbsoluteColorimetric)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsRowCount</tt></td>
+ <td>Integer</td>
+ <td>Specifies the number of rows of raster data to print on each line for some drivers.</td>
+ <td><tt>&lt;&lt;/cupsRowCount 24&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsRowFeed</tt></td>
+ <td>Integer</td>
+ <td>Specifies the number of rows to feed between passes for some drivers.</td>
+ <td><tt>&lt;&lt;/cupsRowFeed 17&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsRowStep</tt></td>
+ <td>Integer</td>
+ <td>Specifies the number of lines between columns/rows on the print head for some drivers.</td>
+ <td><tt>&lt;&lt;/cupsRowStep 2&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+ <td><tt>cupsString0<br>
+ ...<br>
+ cupsString15</tt></td>
+ <td>String</td>
+ <td>Specifies driver string values.</td>
+ <td><tt>&lt;&lt;/cupsString0(String Value)&gt;&gt;setpagedevice</tt></td>
+</tr>
+</tbody>
+</table></div>
+
+
+<h2 class='title'><a name='MEDIA'>Media Keywords</a></h2>
+
+<p>The CUPS media keywords allow drivers to specify alternate custom page
+size limits based on up to two options.</p>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMediaQualifier2'>cupsMediaQualifier2</a></h3>
+
+<p class='summary'>*cupsMediaQualifier2: MainKeyword</p>
+
+<p>This keyword specifies the second option to use for overriding the
+custom page size limits.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMediaQualifier3'>cupsMediaQualifier3</a></h3>
+
+<p class='summary'>*cupsMediaQualifier3: MainKeyword</p>
+
+<p>This keyword specifies the third option to use for overriding the
+custom page size limits.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMinSize'>cupsMinSize</a></h3>
+
+<p class='summary'>*cupsMinSize .Qualifier2.Qualifier3: "width length"<br>
+*cupsMinSize .Qualifier2.: "width length"<br>
+*cupsMinSize ..Qualifier3: "width length"</p>
+
+<p>This keyword specifies alternate minimum custom page sizes in points.
+The <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a> and
+<a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a> keywords
+are used to identify options to use for matching.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMaxSize'>cupsMaxSize</a></h3>
+
+<p class='summary'>*cupsMaxSize .Qualifier2.Qualifier3: "width length"<br>
+*cupsMaxSize .Qualifier2.: "width length"<br>
+*cupsMaxSize ..Qualifier3: "width length"</p>
+
+<p>This keyword specifies alternate maximum custom page sizes in points.
+The <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a> and
+<a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a> keywords
+are used to identify options to use for matching.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+
+<h2 class='title'><a name='ATTRIBUTES'>General Attributes</a></h2>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsBackSide'>cupsBackSide</a></h3>
+
+<p class='summary'>*cupsBackSide: keyword</p>
+
+<p>This keyword requests special handling of the back side of pages
+when doing duplexed (2-sided) output. <a href='#TABLE_1'>Table 1</a>
+shows the supported keyword values for this keyword and their effect
+on the raster data sent to your driver. For example, when <tt>cupsBackSide</tt>
+is <code>Rotated</code> and <tt>Tumble</tt> is <tt>false</tt>, your driver
+will receive print data starting at the bottom right corner of the page, with
+each line going right-to-left instead of left-to-right. The default value is
+<code>Normal</code>.</p>
+
+<blockquote><b>Note:</b>
+
+<p><tt>cupsBackSide</tt> replaces the older <tt>cupsFlipDuplex</tt>
+keyword - if <tt>cupsBackSide</tt> is specified, <tt>cupsFlipDuplex</tt>
+will be ignored.</p>
+
+</blockquote>
+
+<div class='table'>
+<table width='80%' summary='Back Side Raster Coordinate System'>
+<caption>Table 1: <a name='TABLE_1'>Back Side Raster Coordinate System</a></caption>
+<thead>
+<tr>
+ <th>cupsBackSide</th>
+ <th>Tumble Value</th>
+ <th>Image Presentation</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td><code>Normal</code></td>
+ <td><code>false</code></td>
+ <td>Left-to-right, top-to-bottom</td>
+</tr>
+<tr>
+ <td><code>Normal</code></td>
+ <td><code>true</code></td>
+ <td>Left-to-right, top-to-bottom</td>
+</tr>
+<tr>
+ <td><code>ManualTumble</code></td>
+ <td><code>false</code></td>
+ <td>Left-to-right, top-to-bottom</td>
+</tr>
+<tr>
+ <td><code>ManualTumble</code></td>
+ <td><code>true</code></td>
+ <td>Right-to-left, bottom-to-top</td>
+</tr>
+<tr>
+ <td><code>Rotated</code></td>
+ <td><code>false</code></td>
+ <td>Right-to-left, bottom-to-top</td>
+</tr>
+<tr>
+ <td><code>Rotated</code></td>
+ <td><code>true</code></td>
+ <td>Right-to-left, top-to-bottom</td>
+</tr>
+<tr>
+ <td><code>Flipped</code> *</td>
+ <td><code>false</code></td>
+ <td>Left-to-right, bottom-to-top</td>
+</tr>
+<tr>
+ <td><code>Flipped</code> *</td>
+ <td><code>true</code></td>
+ <td>Right-to-left, top-to-bottom</td>
+</tr>
+</tbody>
+</table>
+</div>
+
+<p><em>* - Not supported in Mac OS X 10.5.x and earlier</em></p>
+
+<div class='figure'><table summary='Back side images'>
+<caption>Figure 1: Back side images</caption>
+<tr><td><img src='../images/raster.png' width='624' height='448' alt='Back side images'></td></tr>
+</table></div>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Flip the page image for the back side of duplexed output</em>
+*cupsBackSide: Flipped
+
+<em>*% Rotate the page image for the back side of duplexed output</em>
+*cupsBackSide: Rotated
+</pre>
+
+<p>Also see the related <a href='#APDuplexRequiresFlippedMargin'><tt>APDuplexRequiresFlippedMargin</tt></a>
+keyword.</p>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsCommands'>cupsCommands</a></h3>
+
+<p class='summary'>*cupsCommands: "name name2 ... nameN"</p>
+
+<p>This string keyword specifies the commands that are supported by the
+CUPS command file filter for this device. The command names are separated
+by whitespace.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify the list of commands we support</em>
+*cupsCommands: "AutoConfigure Clean PrintSelfTestPage ReportLevels com.vendor.foo"
+</pre>
+
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsEvenDuplex'>cupsEvenDuplex</a></h3>
+
+<p class='summary'>*cupsEvenDuplex: boolean</p>
+
+<p>This boolean keyword notifies the RIP filters that the
+destination printer requires an even number of pages when 2-sided
+printing is selected. The default value is <code>false</code>.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Always send an even number of pages when duplexing</em>
+*cupsEvenDuplex: true
+</pre>
+
+<h3><a name='cupsFax'>cupsFax</a></h3>
+
+<p class='summary'>*cupsFax: boolean</p>
+
+<p>This boolean keyword specifies whether the PPD defines a facsimile device. The default is <tt>false</tt>.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*cupsFax: true
+</pre>
+
+<h3><a name='cupsFilter'>cupsFilter</a></h3>
+
+<p class='summary'>*cupsFilter: "source/type cost program"</p>
+
+<p>This string keyword provides a conversion rule from the
+given source type to the printer's native format using the
+filter "program". If a printer supports the source type directly,
+the special filter program "-" may be specified.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Standard raster printer driver filter</em>
+*cupsFilter: "application/vnd.cups-raster 100 rastertofoo"
+
+<em>*% Plain text filter</em>
+*cupsFilter: "text/plain 10 texttofoo"
+
+<em>*% Pass-through filter for PostScript printers</em>
+*cupsFilter: "application/vnd.cups-postscript 0 -"
+</pre>
+
+<h3><span class='info'>CUPS 1.5</span><a name='cupsFilter2'>cupsFilter2</a></h3>
+
+<p class='summary'>*cupsFilter2: "source/type destination/type cost program"</p>
+
+<p>This string keyword provides a conversion rule from the given source type to the printer's native format using the filter "program". If a printer supports the source type directly, the special filter program "-" may be specified. The destination type is automatically created as needed and is passed to the filters and backend as the FINAL_CONTENT_TYPE value.</p>
+
+<blockquote><b>Note:</b>
+
+<p>The presence of a single <code>cupsFilter2</code> keyword in the PPD file will hide any <code>cupsFilter</code> keywords from the CUPS scheduler. When using <code>cupsFilter2</code> to provide filters specific for CUPS 1.5 and later, provide a <code>cupsFilter2</code> line for every filter and a <code>cupsFilter</code> line for each filter that is compatible with older versions of CUPS.</p>
+
+</blockquote>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Standard raster printer driver filter</em>
+*cupsFilter2: "application/vnd.cups-raster application/vnd.foo 100 rastertofoo"
+
+<em>*% Plain text filter</em>
+*cupsFilter2: "text/plain application/vnd.foo 10 texttofoo"
+
+<em>*% Pass-through filter for PostScript printers</em>
+*cupsFilter2: "application/vnd.cups-postscript application/postscript 0 -"
+</pre>
+
+<h3><span class='info'>Deprecated</span><a name='cupsFlipDuplex'>cupsFlipDuplex</a></h3>
+
+<p class='summary'>*cupsFlipDuplex: boolean</p>
+
+<p>Due to implementation differences between Mac OS X and Ghostscript,
+the <tt>cupsFlipDuplex</tt> keyword is deprecated. Instead, use
+the <a href='#cupsBackSide'><tt>cupsBackSide</tt></a> keyword to specify
+the coordinate system (pixel layout) of the page data on the back side of
+duplex pages.</p>
+
+<p>The value <code>true</code> maps to a <tt>cupsBackSide</tt> value
+of <code>Rotated</code> on Mac OS X and <code>Flipped</code> with
+Ghostscript.</p>
+
+<p>The default value is <code>false</code>.</p>
+
+<blockquote><b>Note:</b>
+
+<p>Mac OS X drivers that previously used
+<tt>cupsFlipDuplex</tt> may wish to provide both the old and
+new keywords for maximum compatibility, for example:</p>
+
+<pre class='command'>
+*cupsBackSide: Rotated
+*cupsFlipDuplex: true
+</pre>
+
+<p>Similarly, drivers written for other operating systems using
+Ghostscript can use:</p>
+
+<pre class='command'>
+*cupsBackSide: Flipped
+*cupsFlipDuplex: true
+</pre></blockquote>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsIPPFinishings'>cupsIPPFinishings</a></h3>
+
+<p class='summary'>*cupsIPPFinishings number/text: "*Option Choice ..."</p>
+
+<p>This keyword defines a mapping from IPP <code>finishings</code>
+values to PPD options and choices.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*cupsIPPFinishings 4/staple: "*StapleLocation SinglePortrait"
+*cupsIPPFinishings 5/punch: "*PunchMedia Yes *PunchLocation LeftSide"
+*cupsIPPFinishings 20/staple-top-left: "*StapleLocation SinglePortrait"
+*cupsIPPFinishings 21/staple-bottom-left: "*StapleLocation SingleLandscape"
+</pre>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsIPPReason'>cupsIPPReason</a></h3>
+
+<p class='summary'>*cupsIPPReason reason/Reason Text: "optional URIs"</p>
+
+<p>This optional keyword maps custom
+<code>printer-state-reasons</code> keywords that are generated by
+the driver to human readable text. The optional URIs string
+contains zero or more URIs separated by a newline. Each URI can
+be a CUPS server absolute path to a help file under the
+scheduler's <code>DocumentRoot</code> directory, a full HTTP URL
+("http://www.domain.com/path/to/help/page.html"), or any other
+valid URI which directs the user at additional information
+concerning the condition that is being reported.</p>
+
+<p>Since the reason text is limited to 80 characters by the PPD specification,
+longer text strings can be included by URI-encoding the text with the "text"
+scheme, for example "text:some%20text". Multiple <code>text</code> URIs are
+combined (with spaces between each URI) by the <tt>ppdLocalizeIPPReason</tt>
+into a single string that can be displayed to the user.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Map com.vendor-error to text but no page</em>
+*cupsIPPReason com.vendor-error/A serious error occurred: ""
+
+<em>*% Map com.vendor-error to more than 80 characters of text but no page</em>
+*cupsIPPReason com.vendor-error/A serious error occurred: "text:Now%20is%20the%20time
+text:for%20all%20good%20men%20to%20come%20to%20the%20aid%20of%20their%20country."
+
+<em>*% Map com.vendor-error to text and a local page</em>
+*cupsIPPReason com.vendor-error/A serious error occurred: "/help/com.vendor/error.html"
+
+<em>*% Map com.vendor-error to text and a remote page</em>
+*cupsIPPReason com.vendor-error/A serious error occurred: "http://www.vendor.com/help"
+
+<em>*% Map com.vendor-error to text and a local, Apple help book, and remote page</em>
+*APHelpBook: "file:///Library/Printers/vendor/Help.bundle"
+*cupsIPPReason com.vendor-error/A serious error occurred: "/help/com.vendor/error.html
+help:anchor='com.vendor-error'%20bookID=Vendor%20Help
+http://www.vendor.com/help"
+*End
+</pre>
+
+<h3><span class='info'>CUPS 1.5</span><a name='cupsIPPSupplies'>cupsIPPSupplies</a></h3>
+
+<p class='summary'>*cupsIPPSupplies: boolean</p>
+
+<p>This keyword tells the IPP backend whether it should report the current marker-xxx supply attribute values. The default value is <code>True</code>.
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Do not use IPP marker-xxx attributes to report supply levels</em>
+*cupsIPPSupplies: False
+</pre>
+
+<h3><span class='info'>CUPS 1.2/Mac OS X 10.5</span><a name='cupsLanguages'>cupsLanguages</a></h3>
+
+<p class='summary'>*cupsLanguages: "locale list"</p>
+
+<p>This keyword describes which language localizations are
+included in the PPD. The "locale list" string is a space-delimited
+list of locale names ("en", "en_US", "fr_CA", etc.)</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify Canadian, UK, and US English, and Canadian and French French</em>
+*cupsLanguages: "en_CA en_UK en_US fr_CA fr_FR"
+</pre>
+
+<h3><a name='cupsManualCopies'>cupsManualCopies</a></h3>
+
+<p class='summary'>*cupsManualCopies: boolean</p>
+
+<p>This boolean keyword notifies the RIP filters that the
+destination printer does not support copy generation in
+hardware. The default value is <code>false</code>.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Tell the RIP filters to generate the copies for us</em>
+*cupsManualCopies: true
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMarkerName'>cupsMarkerName</a></h3>
+
+<p class='summary'>*cupsMarkerName/Name Text: ""</p>
+
+<p>This optional keyword maps <code>marker-names</code> strings that are
+generated by the driver to human readable text.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Map cyanToner to "Cyan Toner"</em>
+*cupsMarkerName cyanToner/Cyan Toner: ""
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMarkerNotice'>cupsMarkerNotice</a></h3>
+
+<p class='summary'>*cupsMarkerNotice: "disclaimer text"</p>
+
+<p>This optional keyword provides disclaimer text for the supply level
+information provided by the driver, typically something like "supply levels
+are approximate".</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*cupsMarkerNotice: "Supply levels are approximate."
+</pre>
+
+<h3><a name='cupsModelNumber'>cupsModelNumber</a></h3>
+
+<p class='summary'>*cupsModelNumber: number</p>
+
+<p>This integer keyword specifies a printer-specific model
+number. This number can be used by a filter program to adjust
+the output for a specific model of printer.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify an integer for a driver-specific model number</em>
+*cupsModelNumber: 1234
+</pre>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsPJLCharset'>cupsPJLCharset</a></h3>
+
+<p class='summary'>*cupsPJLCharset: "ISO character set name"</p>
+
+<p>This string keyword specifies the character set that is used
+for strings in PJL commands. If not specified, US-ASCII is
+assumed.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify UTF-8 is used in PJL strings</em>
+*cupsPJLCharset: "UTF-8"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsPJLDisplay'>cupsPJLDisplay</a></h3>
+
+<p class='summary'>*cupsPJLDisplay: "what"</p>
+
+<p>This optional keyword specifies which command is used to display the
+job ID, name, and user on the printer's control panel. "What" is either "none"
+to disable this functionality, "job" to use "@PJL JOB DISPLAY", or "rdymsg"
+to use "@PJL RDYMSG DISPLAY". The default is "job".</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Display job information using @PJL SET RDYMSG DISPLAY="foo"</em>
+*cupsPJLDisplay: "rdymsg"
+
+<em>*% Display job information display</em>
+*cupsPJLDisplay: "none"
+</pre>
+
+<h3><span class='info'>CUPS 1.2/Mac OS X 10.5</span><a name='cupsPortMonitor'>cupsPortMonitor</a></h3>
+
+<p class='summary'>*cupsPortMonitor urischeme/Descriptive Text: "port monitor"</p>
+
+<p>This string keyword specifies printer-specific "port
+monitor" filters that may be used with the printer. The CUPS
+scheduler also looks for the <tt>Protocols</tt> keyword to see
+if the <tt>BCP</tt> or <tt>TBCP</tt> protocols are supported. If
+so, the corresponding port monitor ("bcp" and "tbcp",
+respectively) is listed in the printer's
+<tt>port-monitor-supported</tt> keyword.</p>
+
+<p>The "urischeme" portion of the keyword specifies the URI scheme
+that this port monitor should be used for. Typically this is used to
+pre-select a particular port monitor for each type of connection that
+is supported by the printer. The "port monitor" string can be "none"
+to disable the port monitor for the given URI scheme.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify a PostScript printer that supports the TBCP protocol</em>
+*Protocols: TBCP PJL
+
+<em>*% Specify that TBCP should be used for socket connections but not USB</em>
+*cupsPortMonitor socket/AppSocket Printing: "tbcp"
+*cupsPortMonitor usb/USB Printing: "none"
+
+<em>*% Specify a printer-specific port monitor for an Epson USB printer</em>
+*cupsPortMonitor usb/USB Status Monitor: "epson-usb"
+</pre>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsPreFilter'>cupsPreFilter</a></h3>
+
+<p class='summary'>*cupsPreFilter: "source/type cost program"</p>
+
+<p>This string keyword provides a pre-filter rule. The pre-filter
+program will be inserted in the conversion chain immediately
+before the filter that accepts the given MIME type.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% PDF pre-filter</em>
+*cupsPreFilter: "application/pdf 100 mypdfprefilter"
+
+<em>*% PNG pre-filter</em>
+*cupsPreFilter: "image/png 0 mypngprefilter"
+</pre>
+
+
+<h3><span class='info'>CUPS 1.5</span><a name='cupsPrintQuality'>cupsPrintQuality</a></h3>
+
+<p class='summary'>*cupsPrintQuality keyword/text: "code"</p>
+
+<p>This UI keyword defines standard print qualities that directly map from the IPP "print-quality" job template keyword. Standard keyword values are "Draft", "Normal", and "High" which are mapped from the IPP "print-quality" values 3, 4, and 5 respectively. Each <code>cupsPrintQuality</code> option typically sets output mode and resolution parameters in the page device dictionary, eliminating the need for separate (and sometimes confusing) output mode and resolution options.</p>
+
+<blockquote><b>Note:</b>
+
+<p>Unlike all of the other keywords defined in this document, <code>cupsPrintQuality</code> is a UI keyword that MUST be enclosed inside the PPD <code>OpenUI</code> and <code>CloseUI</code> keywords.</p>
+
+</blockquote>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*OpenUI *cupsPrintQuality/Print Quality: PickOne
+*OrderDependency: 10 AnySetup *cupsPrintQuality
+*DefaultcupsPrintQuality: Normal
+*cupsPrintQuality Draft/Draft: "code"
+*cupsPrintQuality Normal/Normal: "code"
+*cupsPrintQuality High/Photo: "code"
+*CloseUI: *cupsPrintQuality
+</pre>
+
+<h3><span class='info'>CUPS 1.5</span><a name='cupsSingleFile'>cupsSingleFile</a></h3>
+
+<p class='summary'>*cupsSingleFile: Boolean</p>
+
+<p>This boolean keyword tells the scheduler whether to print multiple files in a job together or singly. The default is "False" which uses a single instance of the backend for all files in the print job. Setting this keyword to "True" will result in separate instances of the backend for each file in the print job.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Send all print data to a single backend</em>
+*cupsSingleFile: False
+
+<em>*% Send each file using a separate backend</em>
+*cupsSingleFile: True
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsSNMPSupplies'>cupsSNMPSupplies</a></h3>
+
+<p class='summary'>*cupsSNMPSupplies: boolean</p>
+
+<p>This keyword tells the standard network backends whether they should query
+the standard SNMP Printer MIB OIDs for supply levels. The default value is
+<code>True</code>.
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Do not use SNMP queries to report supply levels</em>
+*cupsSNMPSupplies: False
+</pre>
+
+<h3><a name='cupsVersion'>cupsVersion</a></h3>
+
+<p class='summary'>*cupsVersion: major.minor</p>
+
+<p>This required keyword describes which version of the CUPS
+PPD file extensions was used. Currently it must be the string
+"1.0", "1.1", "1.2", or "1.3".</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify a CUPS 1.2 driver</em>
+*cupsVersion: "1.2"
+</pre>
+
+
+<h2 class='title'><a name='MACOSX'>Mac OS X Attributes</a></h2>
+
+<h3><span class='info'>Mac OS X 10.3</span><a name='APDialogExtension'>APDialogExtension</a></h3>
+
+<p class='summary'>*APDialogExtension: "/Library/Printers/vendor/filename.plugin"</p>
+
+<p>This keyword defines additional option panes that are displayed in the
+print dialog. Each keyword adds one or more option panes. See the "OutputBinsPDE"
+example and <a href='http://developer.apple.com/qa/qa2004/qa1352.html'>Apple
+Technical Q&amp;A QA1352</a> for information on writing your own print dialog
+plug-ins.</p>
+
+<blockquote><b>Note:</b>
+
+<p>Starting with Mac OS X 10.5, each plug-in must be compiled "4-way fat"
+(32-bit and 64-bit for both PowerPC and Intel) with garbage collection enabled
+in order to be usable with all applications.</p>
+
+</blockquote>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Add two panes for finishing and driver options
+*APDialogExtension: "/Library/Printers/vendor/finishing.plugin"
+*APDialogExtension: "/Library/Printers/vendor/options.plugin"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.4</span><a name='APDuplexRequiresFlippedMargin'>APDuplexRequiresFlippedMargin</a></h3>
+
+<p class='summary'>*APDuplexRequiresFlippedMargin: boolean</p>
+
+<p>This boolean keyword notifies the RIP filters that the
+destination printer requires the top and bottom margins of the
+<tt>ImageableArea</tt> to be swapped for the back page. The
+default is <tt>true</tt> when <tt>cupsBackSide</tt> is <tt>Flipped</tt>
+and <tt>false</tt> otherwise. <a href='#TABLE_2'>Table 2</a> shows how
+<tt>APDuplexRequiresFlippedMargin</tt> interacts with <tt>cupsBackSide</tt>
+and the <tt>Tumble</tt> page attribute.</p>
+
+<div class='table'>
+<table width='80%' summary='Margin Flipping Modes'>
+<caption>Table 2: <a name='TABLE_2'>Margin Flipping Modes</a></caption>
+<thead>
+<tr>
+ <th>APDuplexRequiresFlippedMargin</th>
+ <th>cupsBackSide</th>
+ <th>Tumble Value</th>
+ <th>Margins</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>false</td>
+ <td>any</td>
+ <td>any</td>
+ <td>Normal</td>
+</tr>
+<tr>
+ <td>any</td>
+ <td>Normal</td>
+ <td>any</td>
+ <td>Normal</td>
+</tr>
+<tr>
+ <td>true</td>
+ <td>ManualDuplex</td>
+ <td>false</td>
+ <td>Normal</td>
+</tr>
+<tr>
+ <td>true</td>
+ <td>ManualDuplex</td>
+ <td>true</td>
+ <td>Flipped</td>
+</tr>
+<tr>
+ <td>true</td>
+ <td>Rotated</td>
+ <td>false</td>
+ <td>Flipped</td>
+</tr>
+<tr>
+ <td>true</td>
+ <td>Rotated</td>
+ <td>true</td>
+ <td>Normal</td>
+</tr>
+<tr>
+ <td>true or unspecified</td>
+ <td>Flipped</td>
+ <td>any</td>
+ <td>Flipped</td>
+</tr>
+</tbody>
+</table></div>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Rotate the back side images</em>
+*cupsBackSide: Rotated
+
+<em>*% Don't swap the top and bottom margins for the back side</em>
+*APDuplexRequiresFlippedMargin: false
+</pre>
+
+<p>Also see the related <a href='#cupsBackSide'><tt>cupsBackSide</tt></a>
+keyword.</p>
+
+<h3><a name='APHelpBook'>APHelpBook</a></h3>
+
+<p class='summary'>*APHelpBook: "bundle URL"</p>
+
+<p>This string keyword specifies the Apple help book bundle to use when
+looking up IPP reason codes for this printer driver. The
+<a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> keyword maps
+"help" URIs to this file.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+*APHelpBook: "file:///Library/Printers/vendor/Help.bundle"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.6</span><a name='APICADriver'>APICADriver</a></h3>
+
+<p class='summary'>*APICADriver: boolean</p>
+
+<p>This keyword specifies whether the device has a matching Image Capture
+Architecture (ICA) driver for scanning. The default is <tt>False</tt>.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APICADriver: True
+*APScanAppBundleID: "com.apple.ImageCaptureApp"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.3</span><a name='APPrinterIconPath'>APPrinterIconPath</a></h3>
+
+<p class='summary'>*APPrinterIconPath: "/Library/Printers/vendor/filename.icns"</p>
+
+<p>This keyword defines the location of a printer icon file to use when
+displaying the printer. The file must be in the Apple icon format.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Apple icon file
+*APPrinterIconPath: "/Library/Printers/vendor/Icons/filename.icns"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.4</span><a name='APPrinterLowInkTool'>APPrinterLowInkTool</a></h3>
+
+<p class='summary'>*APPrinterLowInkTool: "/Library/Printers/vendor/program"</p>
+
+<p>This keyword defines an program that checks the ink/toner/marker levels
+on a printer, returning an XML document with those levels. See the "InkTool"
+example and
+<a href='http://developer.apple.com/technotes/tn2005/tn2144.html'>Apple
+Technical Note TN2144</a> for more information.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Use a vendor monitoring program
+*APPrinterLowInkTool: "/Library/Printers/vendor/Tools/lowinktool"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.5</span><a name='APPrinterPreset'>APPrinterPreset</a></h3>
+
+<p class='summary'>*APPrinterPreset name/text: "*Option Choice ..."</p>
+
+<p>This keyword defines presets for multiple options that show up
+in the print dialog of applications (such as iPhoto) that set the job
+style hint to <tt>NSPrintPhotoJobStyleHint</tt>. Each preset maps to one or
+more pairs of PPD options and choices as well as providing key/value data for
+the application. The following standard preset names are currently defined:</p>
+
+<ul>
+
+ <li><code>General_with_Paper_Auto-Detect</code>; Normal quality general printing with auto-detected media.</li>
+
+ <li><code>General_with_Paper_Auto-Detect_-_Draft</code>; Draft quality general printing with auto-detected media.</li>
+
+ <li><code>General_on_Plain_Paper</code>; Normal quality general printing on plain paper.</li>
+
+ <li><code>General_on_Plain_Paper_-_Draft</code>; Draft quality general printing on plain paper.</li>
+
+ <li><code>Photo_with_Paper_Auto-Detect</code>; Normal quality photo printing with auto-detected media.</li>
+
+ <li><code>Photo_with_Paper_Auto-Detect_-_Fine</code>; High quality photo printing with auto-detected media.</li>
+
+ <li><code>Photo_on_Plain_Paper</code>; Normal quality photo printing on plain paper.</li>
+
+ <li><code>Photo_on_Plain_Paper_-_Fine</code>; High quality photo printing on plain paper.</li>
+
+ <li><code>Photo_on_Photo_Paper</code>; Normal quality photo printing on glossy photo paper.</li>
+
+ <li><code>Photo_on_Photo_Paper_-_Fine</code>; High quality photo printing on glossy photo paper.</li>
+
+ <li><code>Photo_on_Matte_Paper</code>; Normal quality photo printing on matte paper.</li>
+
+ <li><code>Photo_on_Matte_Paper_-_Fine</code>; High quality photo printing on matte paper.</li>
+
+</ul>
+
+<p>The value string consists of pairs of keywords, either an option name and
+choice (*MainKeyword OptionKeyword) or a preset identifier and value
+(com.apple.print.preset.foo value). The following preset identifiers are currently used:</p>
+
+<ul>
+
+ <li><code>com.apple.print.preset.graphicsType</code>; specifies the type of printing used for this printing - "General" for general purpose printing and "Photo" for photo printing.</li>
+
+ <li><code>com.apple.print.preset.media-front-coating</code>; specifies the media type selected by this preset - "none" (plain paper), "glossy", "high-gloss", "semi-gloss", "satin", "matte", and "autodetect".</li>
+
+ <li><code>com.apple.print.preset.output-mode</code>; specifies the output mode for this preset - "color" (default for color printers) or "monochrome" (grayscale, default for B&amp;W printers).</li>
+
+ <li><code>com.apple.print.preset.quality</code>; specifies the overall print quality selected by this preset - "low" (draft), "mid" (normal), or "high".</li>
+
+</ul>
+
+<p>Presets, like options, can also be localized in multiple languages.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APPrinterPreset Photo_on_Photo_Paper/Photo on Photo Paper: "
+ *MediaType Glossy
+ *ColorModel RGB
+ *Resolution 300dpi
+ com.apple.print.preset.graphicsType Photo
+ com.apple.print.preset.quality mid
+ com.apple.print.preset.media-front-coating glossy"
+*End
+*fr.APPrinterPreset Photo_on_Photo_Paper/Photo sur papier photographique: ""
+</pre>
+
+<h3><span class='info'>Mac OS X 10.3</span><a name='APPrinterUtilityPath'>APPrinterUtilityPath</a></h3>
+
+<p class='summary'>*APPrinterPrinterUtilityPath: "/Library/Printers/vendor/filename.app"</p>
+
+<p>This keyword defines a GUI application that can be used to do printer
+maintenance functions such as cleaning the print head(s). See ... for more
+information.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Define the printer utility application
+*APPrinterPrinterUtilityPath: "/Library/Printers/vendor/Tools/utility.app"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.6</span><a name='APScannerOnly'>APScannerOnly</a></h3>
+
+<p class='summary'>*APScannerOnly: boolean</p>
+
+<p>This keyword specifies whether the device has scanning but no printing
+capabilities. The default is <tt>False</tt>.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APICADriver: True
+*APScannerOnly: True
+</pre>
+
+<h3><span class='info'>Mac OS X 10.3</span><a name='APScanAppBundleID'>APScanAppBundleID</a></h3>
+
+<p class='summary'>*APScanAppBundleID: "bundle ID"</p>
+
+<p>This keyword defines the application to use when scanning pages from
+the device.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APICADriver: True
+*APScanAppBundleID: "com.apple.ImageCaptureApp"
+</pre>
+
+
+<h2 class='title'><a name='HISTORY'>Change History</a></h2>
+
+<h3>Changes in CUPS 1.5</h3>
+
+<ul>
+
+ <li>Changes all instances of PPD attributes to PPD keywords, to be consistent with the parent specification from Adobe.</li>
+
+</ul>
+
+
+<h3>Changes in CUPS 1.4.5</h3>
+
+<ul>
+
+ <li>Added <a href='#cupsPrintQuality'><tt>cupsPrintQuality</tt></a> UI keyword.</li>
+
+ <li>Added new properties and values for the <a href='#APPrinterPreset'><tt>APPrinterPreset</tt></a> keyword.</li>
+
+</ul>
+
+
+<h3>Changes in CUPS 1.4</h3>
+
+<ul>
+
+ <li>Added <a href='#APICADriver'><tt>APICADriver</tt></a>
+ keyword.</li>
+
+ <li>Added <a href='#cupsCommands'><tt>cupsCommands</tt></a>
+ keyword.</li>
+
+ <li>Added <a href='#cupsMarkerName'><tt>cupsMarkerName</tt></a>
+ keyword.</li>
+
+ <li>Added <a href='#cupsMarkerNotice'><tt>cupsMarkerNotice</tt></a>
+ keyword.</li>
+
+ <li>Added <a href='#cupsPJLDisplay'><tt>cupsPJLDisplay</tt></a>
+ keyword.</li>
+
+ <li>Added <a href='#cupsSNMPSupplies'><tt>cupsSNMPSupplies</tt></a>
+ keyword.</li>
+
+ <li>Added <a href='#cupsUIResolver'><tt>cupsUIResolver</tt></a> and
+ <a href='#cupsUIConstraints'><tt>cupsUIConstraints</tt></a>
+ keywords.</li>
+
+ <li>Added
+ <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a>,
+ <a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a>,
+ <a href='#cupsMinSize'><tt>cupsMinSize</tt></a>, and
+ <a href='#cupsMaxSize'><tt>cupsMaxSize</tt></a> keywords.</li>
+
+</ul>
+
+
+<h3>Changes in CUPS 1.3.1</h3>
+
+<ul>
+
+ <li>Added missing Mac OS X <tt>AP</tt> keywords.</li>
+
+ <li>Added section on auto-configuration including the
+ <tt>OID<i>MainKeyword</i></tt> and <tt>?<i>MainKeyword</i></tt>
+ keywords.</li>
+
+ <li>Minor reorganization.</li>
+
+</ul>
+
+
+<h3>Changes in CUPS 1.3</h3>
+
+<ul>
+
+ <li>Added <a href='#cupsBackSide'><tt>cupsBackSide</tt></a> and
+ deprecated <a href='#cupsFlipDuplex'><tt>cupsFlipDuplex</tt></a>.</li>
+
+ <li>Added text URI information to
+ <a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> documentation.</li>
+
+ <li>Added <a href='#APPrinterPreset'><tt>APPrinterPreset</tt></a>,
+ <a href='#cupsIPPFinishings'><tt>cupsIPPFinishings</tt></a>, and
+ <a href='#cupsPreFilter'><tt>cupsPreFilter</tt></a> keywords.</li>
+
+ <li>Added discussion of custom option code, sample
+ <tt>CustomPageSize</tt> code, and "do not use dict and put" note.</li>
+
+</ul>
+
+<h3>Changes in CUPS 1.2.8</h3>
+
+<ul>
+
+ <li>Added section on supported PostScript commands for raster
+ drivers</li>
+
+</ul>
+
+<h3>Changes in CUPS 1.2</h3>
+
+<ul>
+
+ <li>Added globalization support keywords</li>
+
+ <li>Added custom option values support</li>
+
+ <li>Added <a href='#APHelpBook'><tt>APHelpBook</tt></a> keyword</li>
+
+ <li>Added <a href='#APDuplexRequiresFlippedMargin'><tt>APDuplexRequiresFlippedMargin</tt></a>
+ keyword</li>
+
+ <li>Added <a href='#cupsICCProfile'><tt>cupsICCProfile</tt></a> keyword</li>
+
+ <li>Added <a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> keyword</li>
+
+ <li>Added <a href='#cupsLanguages'><tt>cupsLanguages</tt></a> keyword</li>
+
+ <li>Added <a href='#cupsPortMonitor'><tt>cupsPortMonitor</tt></a> keyword</li>
+
+ <li>Removed <tt>cupsProtocol</tt> keyword</li>
+
+</ul>
+
+<h3>Changes in CUPS 1.1</h3>
+
+<ul>
+
+ <li>Added <a href='#cupsFlipDuplex'><tt>cupsFlipDuplex</tt></a> keyword</li>
+
+ <li>Added <tt>cupsProtocol</tt> keyword</li>
+
+</ul>
diff --git a/filter/testimage.c b/filter/testimage.c
new file mode 100644
index 000000000..57e3a197d
--- /dev/null
+++ b/filter/testimage.c
@@ -0,0 +1,99 @@
+/*
+ * "$Id$"
+ *
+ * Image library test program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image.h"
+
+
+/*
+ * 'main()' - Main entry...
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ cups_image_t *img; /* Image to print */
+ cups_icspace_t primary; /* Primary image colorspace */
+ FILE *out; /* Output PPM/PGM file */
+ cups_ib_t *line; /* Line from file */
+ int y, /* Current line */
+ width, /* Width of image */
+ height, /* Height of image */
+ depth; /* Depth of image */
+
+
+ if (argc != 3)
+ {
+ puts("Usage: testimage filename.ext filename.[ppm|pgm]");
+ return (1);
+ }
+
+ if (strstr(argv[2], ".ppm") != NULL)
+ primary = CUPS_IMAGE_RGB;
+ else
+ primary = CUPS_IMAGE_WHITE;
+
+ img = cupsImageOpen(argv[1], primary, CUPS_IMAGE_WHITE, 100, 0, NULL);
+
+ if (!img)
+ {
+ perror(argv[1]);
+ return (1);
+ }
+
+ out = fopen(argv[2], "wb");
+
+ if (!out)
+ {
+ perror(argv[2]);
+ cupsImageClose(img);
+ return (1);
+ }
+
+ width = cupsImageGetWidth(img);
+ height = cupsImageGetHeight(img);
+ depth = cupsImageGetDepth(img);
+ line = calloc(width, depth);
+
+ fprintf(out, "P%d\n%d\n%d\n255\n",
+ cupsImageGetColorSpace(img) == CUPS_IMAGE_WHITE ? 5 : 6,
+ width, height);
+
+ for (y = 0; y < height; y ++)
+ {
+ cupsImageGetRow(img, 0, y, width, line);
+ fwrite(line, width, depth, out);
+ }
+
+ cupsImageClose(img);
+ fclose(out);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/testraster.c b/filter/testraster.c
new file mode 100644
index 000000000..2e2956f38
--- /dev/null
+++ b/filter/testraster.c
@@ -0,0 +1,1078 @@
+/*
+ * "$Id$"
+ *
+ * Raster test program routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Test the raster functions.
+ * do_ppd_tests() - Test the default option commands in a PPD file.
+ * do_ps_tests() - Test standard PostScript commands.
+ * do_ras_file() - Test reading of a raster file.
+ * do_raster_tests() - Test reading and writing of raster data.
+ * print_changes() - Print differences in the page header.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "image-private.h"
+#ifdef WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+# include <fcntl.h>
+#endif /* WIN32 */
+
+
+/*
+ * Test PS commands and header...
+ */
+
+static const char *dsc_code =
+"[{\n"
+"%%BeginFeature: *PageSize Tabloid\n"
+"<</PageSize[792 1224]>>setpagedevice\n"
+"%%EndFeature\n"
+"} stopped cleartomark\n";
+static const char *setpagedevice_code =
+"<<"
+"/MediaClass(Media Class)"
+"/MediaColor((Media Color))"
+"/MediaType(Media\\\\Type)"
+"/OutputType<416263>"
+"/AdvanceDistance 1000"
+"/AdvanceMedia 1"
+"/Collate false"
+"/CutMedia 2"
+"/Duplex true"
+"/HWResolution[100 200]"
+"/InsertSheet true"
+"/Jog 3"
+"/LeadingEdge 1"
+"/ManualFeed true"
+"/MediaPosition 8#777"
+"/MediaWeight 16#fe01"
+"/MirrorPrint true"
+"/NegativePrint true"
+"/NumCopies 1"
+"/Orientation 1"
+"/OutputFaceUp true"
+"/PageSize[612 792.1]"
+"/Separations true"
+"/TraySwitch true"
+"/Tumble true"
+"/cupsMediaType 2"
+"/cupsColorOrder 1"
+"/cupsColorSpace 1"
+"/cupsCompression 1"
+"/cupsRowCount 1"
+"/cupsRowFeed 1"
+"/cupsRowStep 1"
+"/cupsBorderlessScalingFactor 1.001"
+"/cupsInteger0 1"
+"/cupsInteger1 2"
+"/cupsInteger2 3"
+"/cupsInteger3 4"
+"/cupsInteger4 5"
+"/cupsInteger5 6"
+"/cupsInteger6 7"
+"/cupsInteger7 8"
+"/cupsInteger8 9"
+"/cupsInteger9 10"
+"/cupsInteger10 11"
+"/cupsInteger11 12"
+"/cupsInteger12 13"
+"/cupsInteger13 14"
+"/cupsInteger14 15"
+"/cupsInteger15 16"
+"/cupsReal0 1.1"
+"/cupsReal1 2.1"
+"/cupsReal2 3.1"
+"/cupsReal3 4.1"
+"/cupsReal4 5.1"
+"/cupsReal5 6.1"
+"/cupsReal6 7.1"
+"/cupsReal7 8.1"
+"/cupsReal8 9.1"
+"/cupsReal9 10.1"
+"/cupsReal10 11.1"
+"/cupsReal11 12.1"
+"/cupsReal12 13.1"
+"/cupsReal13 14.1"
+"/cupsReal14 15.1"
+"/cupsReal15 16.1"
+"/cupsString0(1)"
+"/cupsString1(2)"
+"/cupsString2(3)"
+"/cupsString3(4)"
+"/cupsString4(5)"
+"/cupsString5(6)"
+"/cupsString6(7)"
+"/cupsString7(8)"
+"/cupsString8(9)"
+"/cupsString9(10)"
+"/cupsString10(11)"
+"/cupsString11(12)"
+"/cupsString12(13)"
+"/cupsString13(14)"
+"/cupsString14(15)"
+"/cupsString15(16)"
+"/cupsMarkerType(Marker Type)"
+"/cupsRenderingIntent(Rendering Intent)"
+"/cupsPageSizeName(Letter)"
+"/cupsPreferredBitsPerColor 17"
+">> setpagedevice";
+
+static cups_page_header2_t setpagedevice_header =
+{
+ "Media Class", /* MediaClass */
+ "(Media Color)", /* MediaColor */
+ "Media\\Type", /* MediaType */
+ "Abc", /* OutputType */
+ 1000, /* AdvanceDistance */
+ CUPS_ADVANCE_FILE, /* AdvanceMedia */
+ CUPS_FALSE, /* Collate */
+ CUPS_CUT_JOB, /* CutMedia */
+ CUPS_TRUE, /* Duplex */
+ { 100, 200 }, /* HWResolution */
+ { 0, 0, 0, 0 }, /* ImagingBoundingBox */
+ CUPS_TRUE, /* InsertSheet */
+ CUPS_JOG_SET, /* Jog */
+ CUPS_EDGE_RIGHT, /* LeadingEdge */
+ { 0, 0 }, /* Margins */
+ CUPS_TRUE, /* ManualFeed */
+ 0777, /* MediaPosition */
+ 0xfe01, /* MediaWeight */
+ CUPS_TRUE, /* MirrorPrint */
+ CUPS_TRUE, /* NegativePrint */
+ 1, /* NumCopies */
+ CUPS_ORIENT_90, /* Orientation */
+ CUPS_TRUE, /* OutputFaceUp */
+ { 612, 792 }, /* PageSize */
+ CUPS_TRUE, /* Separations */
+ CUPS_TRUE, /* TraySwitch */
+ CUPS_TRUE, /* Tumble */
+ 0, /* cupsWidth */
+ 0, /* cupsHeight */
+ 2, /* cupsMediaType */
+ 0, /* cupsBitsPerColor */
+ 0, /* cupsBitsPerPixel */
+ 0, /* cupsBytesPerLine */
+ CUPS_ORDER_BANDED, /* cupsColorOrder */
+ CUPS_CSPACE_RGB, /* cupsColorSpace */
+ 1, /* cupsCompression */
+ 1, /* cupsRowCount */
+ 1, /* cupsRowFeed */
+ 1, /* cupsRowStep */
+ 0, /* cupsNumColors */
+ 1.001, /* cupsBorderlessScalingFactor */
+ { 612.0, 792.1 }, /* cupsPageSize */
+ { 0.0, 0.0, 0.0, 0.0 }, /* cupsImagingBBox */
+ { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 },
+ /* cupsInteger[16] */
+ { 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 8.1, 9.1, 10.1, 11.1, 12.1, 13.1,
+ 14.1, 15.1, 16.1 }, /* cupsReal[16] */
+ { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13",
+ "14", "15", "16" }, /* cupsString[16] */
+ "Marker Type", /* cupsMarkerType */
+ "Rendering Intent", /* cupsRenderingIntent */
+ "Letter" /* cupsPageSizeName */
+};
+
+
+/*
+ * Local functions...
+ */
+
+static int do_ppd_tests(const char *filename, int num_options,
+ cups_option_t *options);
+static int do_ps_tests(void);
+static int do_ras_file(const char *filename);
+static int do_raster_tests(cups_mode_t mode);
+static void print_changes(cups_page_header2_t *header,
+ cups_page_header2_t *expected);
+
+
+/*
+ * 'main()' - Test the raster functions.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int errors; /* Number of errors */
+ const char *ext; /* Filename extension */
+
+
+ if (argc == 1)
+ {
+ errors = do_ps_tests();
+ errors += do_raster_tests(CUPS_RASTER_WRITE);
+ errors += do_raster_tests(CUPS_RASTER_WRITE_COMPRESSED);
+ errors += do_raster_tests(CUPS_RASTER_WRITE_PWG);
+ }
+ else
+ {
+ int i; /* Looping var */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+
+
+ for (errors = 0, num_options = 0, options = NULL, i = 1; i < argc; i ++)
+ {
+ if (argv[i][0] == '-')
+ {
+ if (argv[i][1] == 'o')
+ {
+ if (argv[i][2])
+ num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
+ else
+ {
+ i ++;
+ if (i < argc)
+ num_options = cupsParseOptions(argv[i], num_options, &options);
+ else
+ {
+ puts("Usage: testraster [-o name=value ...] [filename.ppd ...]");
+ puts(" testraster [filename.ras ...]");
+ return (1);
+ }
+ }
+ }
+ else
+ {
+ puts("Usage: testraster [-o name=value ...] [filename.ppd ...]");
+ puts(" testraster [filename.ras ...]");
+ return (1);
+ }
+ }
+ else if ((ext = strrchr(argv[i], '.')) != NULL)
+ {
+ if (!strcmp(ext, ".ppd"))
+ errors += do_ppd_tests(argv[i], num_options, options);
+ else
+ errors += do_ras_file(argv[i]);
+ }
+ else
+ {
+ puts("Usage: testraster [-o name=value ...] [filename.ppd ...]");
+ puts(" testraster [filename.ras ...]");
+ return (1);
+ }
+ }
+
+ cupsFreeOptions(num_options, options);
+ }
+
+ return (errors);
+}
+
+
+/*
+ * 'do_ppd_tests()' - Test the default option commands in a PPD file.
+ */
+
+static int /* O - Number of errors */
+do_ppd_tests(const char *filename, /* I - PPD file */
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ ppd_file_t *ppd; /* PPD file data */
+ cups_page_header2_t header; /* Page header */
+
+
+ printf("\"%s\": ", filename);
+ fflush(stdout);
+
+ if ((ppd = ppdOpenFile(filename)) == NULL)
+ {
+ ppd_status_t status; /* Status from PPD loader */
+ int line; /* Line number containing error */
+
+
+ status = ppdLastError(&line);
+
+ puts("FAIL (bad PPD file)");
+ printf(" %s on line %d\n", ppdErrorString(status), line);
+
+ return (1);
+ }
+
+ ppdMarkDefaults(ppd);
+ cupsMarkOptions(ppd, num_options, options);
+
+ if (cupsRasterInterpretPPD(&header, ppd, 0, NULL, NULL))
+ {
+ puts("FAIL (error from function)");
+ puts(cupsRasterErrorString());
+
+ return (1);
+ }
+ else
+ {
+ puts("PASS");
+
+ return (0);
+ }
+}
+
+
+/*
+ * 'do_ps_tests()' - Test standard PostScript commands.
+ */
+
+static int
+do_ps_tests(void)
+{
+ cups_page_header2_t header; /* Page header */
+ int preferred_bits; /* Preferred bits */
+ int errors = 0; /* Number of errors */
+
+
+ /*
+ * Test PS exec code...
+ */
+
+ fputs("_cupsRasterExecPS(\"setpagedevice\"): ", stdout);
+ fflush(stdout);
+
+ memset(&header, 0, sizeof(header));
+ header.Collate = CUPS_TRUE;
+ preferred_bits = 0;
+
+ if (_cupsRasterExecPS(&header, &preferred_bits, setpagedevice_code))
+ {
+ puts("FAIL (error from function)");
+ puts(cupsRasterErrorString());
+ errors ++;
+ }
+ else if (preferred_bits != 17 ||
+ memcmp(&header, &setpagedevice_header, sizeof(header)))
+ {
+ puts("FAIL (bad header)");
+
+ if (preferred_bits != 17)
+ printf(" cupsPreferredBitsPerColor %d, expected 17\n",
+ preferred_bits);
+
+ print_changes(&setpagedevice_header, &header);
+ errors ++;
+ }
+ else
+ puts("PASS");
+
+ fputs("_cupsRasterExecPS(\"roll\"): ", stdout);
+ fflush(stdout);
+
+ if (_cupsRasterExecPS(&header, &preferred_bits,
+ "792 612 0 0 0\n"
+ "pop pop pop\n"
+ "<</PageSize[5 -2 roll]/ImagingBBox null>>"
+ "setpagedevice\n"))
+ {
+ puts("FAIL (error from function)");
+ puts(cupsRasterErrorString());
+ errors ++;
+ }
+ else if (header.PageSize[0] != 792 || header.PageSize[1] != 612)
+ {
+ printf("FAIL (PageSize [%d %d], expected [792 612])\n", header.PageSize[0],
+ header.PageSize[1]);
+ errors ++;
+ }
+ else
+ puts("PASS");
+
+ fputs("_cupsRasterExecPS(\"dup index\"): ", stdout);
+ fflush(stdout);
+
+ if (_cupsRasterExecPS(&header, &preferred_bits,
+ "true false dup\n"
+ "<</Collate 4 index"
+ "/Duplex 5 index"
+ "/Tumble 6 index>>setpagedevice\n"
+ "pop pop pop"))
+ {
+ puts("FAIL (error from function)");
+ puts(cupsRasterErrorString());
+ errors ++;
+ }
+ else
+ {
+ if (!header.Collate)
+ {
+ printf("FAIL (Collate false, expected true)\n");
+ errors ++;
+ }
+
+ if (header.Duplex)
+ {
+ printf("FAIL (Duplex true, expected false)\n");
+ errors ++;
+ }
+
+ if (header.Tumble)
+ {
+ printf("FAIL (Tumble true, expected false)\n");
+ errors ++;
+ }
+
+ if(header.Collate && !header.Duplex && !header.Tumble)
+ puts("PASS");
+ }
+
+ fputs("_cupsRasterExecPS(\"%%Begin/EndFeature code\"): ", stdout);
+ fflush(stdout);
+
+ if (_cupsRasterExecPS(&header, &preferred_bits, dsc_code))
+ {
+ puts("FAIL (error from function)");
+ puts(cupsRasterErrorString());
+ errors ++;
+ }
+ else if (header.PageSize[0] != 792 || header.PageSize[1] != 1224)
+ {
+ printf("FAIL (bad PageSize [%d %d], expected [792 1224])\n",
+ header.PageSize[0], header.PageSize[1]);
+ errors ++;
+ }
+ else
+ puts("PASS");
+
+ return (errors);
+}
+
+
+/*
+ * 'do_ras_file()' - Test reading of a raster file.
+ */
+
+static int /* O - Number of errors */
+do_ras_file(const char *filename) /* I - Filename */
+{
+ unsigned y; /* Looping vars */
+ int fd; /* File descriptor */
+ cups_raster_t *ras; /* Raster stream */
+ cups_page_header2_t header; /* Page header */
+ unsigned char *data; /* Raster data */
+ int errors = 0; /* Number of errors */
+ unsigned pages = 0; /* Number of pages */
+
+
+ if ((fd = open(filename, O_RDONLY)) < 0)
+ {
+ printf("%s: %s\n", filename, strerror(errno));
+ return (1);
+ }
+
+ if ((ras = cupsRasterOpen(fd, CUPS_RASTER_READ)) == NULL)
+ {
+ printf("%s: cupsRasterOpen failed.\n", filename);
+ close(fd);
+ return (1);
+ }
+
+ printf("%s:\n", filename);
+
+ while (cupsRasterReadHeader2(ras, &header))
+ {
+ pages ++;
+ data = malloc(header.cupsBytesPerLine);
+
+ printf(" Page %u: %ux%ux%u@%ux%udpi", pages,
+ header.cupsWidth, header.cupsHeight, header.cupsBitsPerPixel,
+ header.HWResolution[0], header.HWResolution[1]);
+ fflush(stdout);
+
+ for (y = 0; y < header.cupsHeight; y ++)
+ if (cupsRasterReadPixels(ras, data, header.cupsBytesPerLine) <
+ header.cupsBytesPerLine)
+ break;
+
+ if (y < header.cupsHeight)
+ printf(" ERROR AT LINE %d\n", y);
+ else
+ putchar('\n');
+
+ free(data);
+ }
+
+ cupsRasterClose(ras);
+ close(fd);
+
+ return (errors);
+}
+
+
+/*
+ * 'do_raster_tests()' - Test reading and writing of raster data.
+ */
+
+static int /* O - Number of errors */
+do_raster_tests(cups_mode_t mode) /* O - Write mode */
+{
+ int page, x, y; /* Looping vars */
+ FILE *fp; /* Raster file */
+ cups_raster_t *r; /* Raster stream */
+ cups_page_header2_t header, /* Page header */
+ expected; /* Expected page header */
+ unsigned char data[2048]; /* Raster data */
+ int errors = 0; /* Number of errors */
+
+
+ /*
+ * Test writing...
+ */
+
+ printf("cupsRasterOpen(%s): ",
+ mode == CUPS_RASTER_WRITE ? "CUPS_RASTER_WRITE" :
+ mode == CUPS_RASTER_WRITE ? "CUPS_RASTER_WRITE_COMPRESSED" :
+ "CUPS_RASTER_WRITE_PWG");
+ fflush(stdout);
+
+ if ((fp = fopen("test.raster", "wb")) == NULL)
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ return (1);
+ }
+
+ if ((r = cupsRasterOpen(fileno(fp), mode)) == NULL)
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ fclose(fp);
+ return (1);
+ }
+
+ puts("PASS");
+
+ for (page = 0; page < 4; page ++)
+ {
+ memset(&header, 0, sizeof(header));
+ header.cupsWidth = 256;
+ header.cupsHeight = 256;
+ header.cupsBytesPerLine = 256;
+
+ if (page & 1)
+ {
+ header.cupsBytesPerLine *= 2;
+ header.cupsColorSpace = CUPS_CSPACE_CMYK;
+ header.cupsColorOrder = CUPS_ORDER_CHUNKED;
+ header.cupsNumColors = 4;
+ }
+ else
+ {
+ header.cupsColorSpace = CUPS_CSPACE_K;
+ header.cupsColorOrder = CUPS_ORDER_BANDED;
+ header.cupsNumColors = 1;
+ }
+
+ if (page & 2)
+ {
+ header.cupsBytesPerLine *= 2;
+ header.cupsBitsPerColor = 16;
+ header.cupsBitsPerPixel = (page & 1) ? 64 : 16;
+ }
+ else
+ {
+ header.cupsBitsPerColor = 8;
+ header.cupsBitsPerPixel = (page & 1) ? 32 : 8;
+ }
+
+ if (cupsRasterWriteHeader2(r, &header))
+ puts("cupsRasterWriteHeader2: PASS");
+ else
+ {
+ puts("cupsRasterWriteHeader2: FAIL");
+ errors ++;
+ }
+
+ fputs("cupsRasterWritePixels: ", stdout);
+ fflush(stdout);
+
+ memset(data, 0, header.cupsBytesPerLine);
+ for (y = 0; y < 64; y ++)
+ if (!cupsRasterWritePixels(r, data, header.cupsBytesPerLine))
+ break;
+
+ if (y < 64)
+ {
+ puts("FAIL");
+ errors ++;
+ }
+ else
+ {
+ for (x = 0; x < header.cupsBytesPerLine; x ++)
+ data[x] = x;
+
+ for (y = 0; y < 64; y ++)
+ if (!cupsRasterWritePixels(r, data, header.cupsBytesPerLine))
+ break;
+
+ if (y < 64)
+ {
+ puts("FAIL");
+ errors ++;
+ }
+ else
+ {
+ memset(data, 255, header.cupsBytesPerLine);
+ for (y = 0; y < 64; y ++)
+ if (!cupsRasterWritePixels(r, data, header.cupsBytesPerLine))
+ break;
+
+ if (y < 64)
+ {
+ puts("FAIL");
+ errors ++;
+ }
+ else
+ {
+ for (x = 0; x < header.cupsBytesPerLine; x ++)
+ data[x] = x / 4;
+
+ for (y = 0; y < 64; y ++)
+ if (!cupsRasterWritePixels(r, data, header.cupsBytesPerLine))
+ break;
+
+ if (y < 64)
+ {
+ puts("FAIL");
+ errors ++;
+ }
+ else
+ puts("PASS");
+ }
+ }
+ }
+ }
+
+ cupsRasterClose(r);
+ fclose(fp);
+
+ /*
+ * Test reading...
+ */
+
+ fputs("cupsRasterOpen(CUPS_RASTER_READ): ", stdout);
+ fflush(stdout);
+
+ if ((fp = fopen("test.raster", "rb")) == NULL)
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ return (1);
+ }
+
+ if ((r = cupsRasterOpen(fileno(fp), CUPS_RASTER_READ)) == NULL)
+ {
+ printf("FAIL (%s)\n", strerror(errno));
+ fclose(fp);
+ return (1);
+ }
+
+ puts("PASS");
+
+ for (page = 0; page < 4; page ++)
+ {
+ memset(&expected, 0, sizeof(expected));
+ expected.cupsWidth = 256;
+ expected.cupsHeight = 256;
+ expected.cupsBytesPerLine = 256;
+
+ if (page & 1)
+ {
+ expected.cupsBytesPerLine *= 2;
+ expected.cupsColorSpace = CUPS_CSPACE_CMYK;
+ expected.cupsColorOrder = CUPS_ORDER_CHUNKED;
+ expected.cupsNumColors = 4;
+ }
+ else
+ {
+ expected.cupsColorSpace = CUPS_CSPACE_K;
+ expected.cupsColorOrder = CUPS_ORDER_BANDED;
+ expected.cupsNumColors = 1;
+ }
+
+ if (page & 2)
+ {
+ expected.cupsBytesPerLine *= 2;
+ expected.cupsBitsPerColor = 16;
+ expected.cupsBitsPerPixel = (page & 1) ? 64 : 16;
+ }
+ else
+ {
+ expected.cupsBitsPerColor = 8;
+ expected.cupsBitsPerPixel = (page & 1) ? 32 : 8;
+ }
+
+ fputs("cupsRasterReadHeader2: ", stdout);
+ fflush(stdout);
+
+ if (!cupsRasterReadHeader2(r, &header))
+ {
+ puts("FAIL (read error)");
+ errors ++;
+ break;
+ }
+
+ if (memcmp(&header, &expected, sizeof(header)))
+ {
+ puts("FAIL (bad page header)");
+ errors ++;
+ print_changes(&header, &expected);
+ }
+
+ fputs("cupsRasterReadPixels: ", stdout);
+ fflush(stdout);
+
+ for (y = 0; y < 64; y ++)
+ {
+ if (!cupsRasterReadPixels(r, data, header.cupsBytesPerLine))
+ {
+ puts("FAIL (read error)");
+ errors ++;
+ break;
+ }
+
+ if (data[0] != 0 || memcmp(data, data + 1, header.cupsBytesPerLine - 1))
+ {
+ printf("FAIL (raster line %d corrupt)\n", y);
+ errors ++;
+ break;
+ }
+ }
+
+ if (y == 64)
+ {
+ for (y = 0; y < 64; y ++)
+ {
+ if (!cupsRasterReadPixels(r, data, header.cupsBytesPerLine))
+ {
+ puts("FAIL (read error)");
+ errors ++;
+ break;
+ }
+
+ for (x = 0; x < header.cupsBytesPerLine; x ++)
+ if (data[x] != (x & 255))
+ break;
+
+ if (x < header.cupsBytesPerLine)
+ {
+ printf("FAIL (raster line %d corrupt)\n", y + 64);
+ errors ++;
+ break;
+ }
+ }
+
+ if (y == 64)
+ {
+ for (y = 0; y < 64; y ++)
+ {
+ if (!cupsRasterReadPixels(r, data, header.cupsBytesPerLine))
+ {
+ puts("FAIL (read error)");
+ errors ++;
+ break;
+ }
+
+ if (data[0] != 255 || memcmp(data, data + 1, header.cupsBytesPerLine - 1))
+ {
+ printf("fail (raster line %d corrupt)\n", y + 128);
+ errors ++;
+ break;
+ }
+ }
+
+ if (y == 64)
+ {
+ for (y = 0; y < 64; y ++)
+ {
+ if (!cupsRasterReadPixels(r, data, header.cupsBytesPerLine))
+ {
+ puts("FAIL (read error)");
+ errors ++;
+ break;
+ }
+
+ for (x = 0; x < header.cupsBytesPerLine; x ++)
+ if (data[x] != ((x / 4) & 255))
+ break;
+
+ if (x < header.cupsBytesPerLine)
+ {
+ printf("FAIL (raster line %d corrupt)\n", y + 192);
+ errors ++;
+ break;
+ }
+ }
+
+ if (y == 64)
+ puts("PASS");
+ }
+ }
+ }
+ }
+
+ cupsRasterClose(r);
+ fclose(fp);
+
+ return (errors);
+}
+
+
+/*
+ * 'print_changes()' - Print differences in the page header.
+ */
+
+static void
+print_changes(
+ cups_page_header2_t *header, /* I - Actual page header */
+ cups_page_header2_t *expected) /* I - Expected page header */
+{
+ int i; /* Looping var */
+
+
+ if (strcmp(header->MediaClass, expected->MediaClass))
+ printf(" MediaClass (%s), expected (%s)\n", header->MediaClass,
+ expected->MediaClass);
+
+ if (strcmp(header->MediaColor, expected->MediaColor))
+ printf(" MediaColor (%s), expected (%s)\n", header->MediaColor,
+ expected->MediaColor);
+
+ if (strcmp(header->MediaType, expected->MediaType))
+ printf(" MediaType (%s), expected (%s)\n", header->MediaType,
+ expected->MediaType);
+
+ if (strcmp(header->OutputType, expected->OutputType))
+ printf(" OutputType (%s), expected (%s)\n", header->OutputType,
+ expected->OutputType);
+
+ if (header->AdvanceDistance != expected->AdvanceDistance)
+ printf(" AdvanceDistance %d, expected %d\n", header->AdvanceDistance,
+ expected->AdvanceDistance);
+
+ if (header->AdvanceMedia != expected->AdvanceMedia)
+ printf(" AdvanceMedia %d, expected %d\n", header->AdvanceMedia,
+ expected->AdvanceMedia);
+
+ if (header->Collate != expected->Collate)
+ printf(" Collate %d, expected %d\n", header->Collate,
+ expected->Collate);
+
+ if (header->CutMedia != expected->CutMedia)
+ printf(" CutMedia %d, expected %d\n", header->CutMedia,
+ expected->CutMedia);
+
+ if (header->Duplex != expected->Duplex)
+ printf(" Duplex %d, expected %d\n", header->Duplex,
+ expected->Duplex);
+
+ if (header->HWResolution[0] != expected->HWResolution[0] ||
+ header->HWResolution[1] != expected->HWResolution[1])
+ printf(" HWResolution [%d %d], expected [%d %d]\n",
+ header->HWResolution[0], header->HWResolution[1],
+ expected->HWResolution[0], expected->HWResolution[1]);
+
+ if (memcmp(header->ImagingBoundingBox, expected->ImagingBoundingBox,
+ sizeof(header->ImagingBoundingBox)))
+ printf(" ImagingBoundingBox [%d %d %d %d], expected [%d %d %d %d]\n",
+ header->ImagingBoundingBox[0],
+ header->ImagingBoundingBox[1],
+ header->ImagingBoundingBox[2],
+ header->ImagingBoundingBox[3],
+ expected->ImagingBoundingBox[0],
+ expected->ImagingBoundingBox[1],
+ expected->ImagingBoundingBox[2],
+ expected->ImagingBoundingBox[3]);
+
+ if (header->InsertSheet != expected->InsertSheet)
+ printf(" InsertSheet %d, expected %d\n", header->InsertSheet,
+ expected->InsertSheet);
+
+ if (header->Jog != expected->Jog)
+ printf(" Jog %d, expected %d\n", header->Jog,
+ expected->Jog);
+
+ if (header->LeadingEdge != expected->LeadingEdge)
+ printf(" LeadingEdge %d, expected %d\n", header->LeadingEdge,
+ expected->LeadingEdge);
+
+ if (header->Margins[0] != expected->Margins[0] ||
+ header->Margins[1] != expected->Margins[1])
+ printf(" Margins [%d %d], expected [%d %d]\n",
+ header->Margins[0], header->Margins[1],
+ expected->Margins[0], expected->Margins[1]);
+
+ if (header->ManualFeed != expected->ManualFeed)
+ printf(" ManualFeed %d, expected %d\n", header->ManualFeed,
+ expected->ManualFeed);
+
+ if (header->MediaPosition != expected->MediaPosition)
+ printf(" MediaPosition %d, expected %d\n", header->MediaPosition,
+ expected->MediaPosition);
+
+ if (header->MediaWeight != expected->MediaWeight)
+ printf(" MediaWeight %d, expected %d\n", header->MediaWeight,
+ expected->MediaWeight);
+
+ if (header->MirrorPrint != expected->MirrorPrint)
+ printf(" MirrorPrint %d, expected %d\n", header->MirrorPrint,
+ expected->MirrorPrint);
+
+ if (header->NegativePrint != expected->NegativePrint)
+ printf(" NegativePrint %d, expected %d\n", header->NegativePrint,
+ expected->NegativePrint);
+
+ if (header->NumCopies != expected->NumCopies)
+ printf(" NumCopies %d, expected %d\n", header->NumCopies,
+ expected->NumCopies);
+
+ if (header->Orientation != expected->Orientation)
+ printf(" Orientation %d, expected %d\n", header->Orientation,
+ expected->Orientation);
+
+ if (header->OutputFaceUp != expected->OutputFaceUp)
+ printf(" OutputFaceUp %d, expected %d\n", header->OutputFaceUp,
+ expected->OutputFaceUp);
+
+ if (header->PageSize[0] != expected->PageSize[0] ||
+ header->PageSize[1] != expected->PageSize[1])
+ printf(" PageSize [%d %d], expected [%d %d]\n",
+ header->PageSize[0], header->PageSize[1],
+ expected->PageSize[0], expected->PageSize[1]);
+
+ if (header->Separations != expected->Separations)
+ printf(" Separations %d, expected %d\n", header->Separations,
+ expected->Separations);
+
+ if (header->TraySwitch != expected->TraySwitch)
+ printf(" TraySwitch %d, expected %d\n", header->TraySwitch,
+ expected->TraySwitch);
+
+ if (header->Tumble != expected->Tumble)
+ printf(" Tumble %d, expected %d\n", header->Tumble,
+ expected->Tumble);
+
+ if (header->cupsWidth != expected->cupsWidth)
+ printf(" cupsWidth %d, expected %d\n", header->cupsWidth,
+ expected->cupsWidth);
+
+ if (header->cupsHeight != expected->cupsHeight)
+ printf(" cupsHeight %d, expected %d\n", header->cupsHeight,
+ expected->cupsHeight);
+
+ if (header->cupsMediaType != expected->cupsMediaType)
+ printf(" cupsMediaType %d, expected %d\n", header->cupsMediaType,
+ expected->cupsMediaType);
+
+ if (header->cupsBitsPerColor != expected->cupsBitsPerColor)
+ printf(" cupsBitsPerColor %d, expected %d\n", header->cupsBitsPerColor,
+ expected->cupsBitsPerColor);
+
+ if (header->cupsBitsPerPixel != expected->cupsBitsPerPixel)
+ printf(" cupsBitsPerPixel %d, expected %d\n", header->cupsBitsPerPixel,
+ expected->cupsBitsPerPixel);
+
+ if (header->cupsBytesPerLine != expected->cupsBytesPerLine)
+ printf(" cupsBytesPerLine %d, expected %d\n", header->cupsBytesPerLine,
+ expected->cupsBytesPerLine);
+
+ if (header->cupsColorOrder != expected->cupsColorOrder)
+ printf(" cupsColorOrder %d, expected %d\n", header->cupsColorOrder,
+ expected->cupsColorOrder);
+
+ if (header->cupsColorSpace != expected->cupsColorSpace)
+ printf(" cupsColorSpace %d, expected %d\n", header->cupsColorSpace,
+ expected->cupsColorSpace);
+
+ if (header->cupsCompression != expected->cupsCompression)
+ printf(" cupsCompression %d, expected %d\n", header->cupsCompression,
+ expected->cupsCompression);
+
+ if (header->cupsRowCount != expected->cupsRowCount)
+ printf(" cupsRowCount %d, expected %d\n", header->cupsRowCount,
+ expected->cupsRowCount);
+
+ if (header->cupsRowFeed != expected->cupsRowFeed)
+ printf(" cupsRowFeed %d, expected %d\n", header->cupsRowFeed,
+ expected->cupsRowFeed);
+
+ if (header->cupsRowStep != expected->cupsRowStep)
+ printf(" cupsRowStep %d, expected %d\n", header->cupsRowStep,
+ expected->cupsRowStep);
+
+ if (header->cupsNumColors != expected->cupsNumColors)
+ printf(" cupsNumColors %d, expected %d\n", header->cupsNumColors,
+ expected->cupsNumColors);
+
+ if (header->cupsBorderlessScalingFactor !=
+ expected->cupsBorderlessScalingFactor)
+ printf(" cupsBorderlessScalingFactor %g, expected %g\n",
+ header->cupsBorderlessScalingFactor,
+ expected->cupsBorderlessScalingFactor);
+
+ if (header->cupsPageSize[0] != expected->cupsPageSize[0] ||
+ header->cupsPageSize[1] != expected->cupsPageSize[1])
+ printf(" cupsPageSize [%g %g], expected [%g %g]\n",
+ header->cupsPageSize[0], header->cupsPageSize[1],
+ expected->cupsPageSize[0], expected->cupsPageSize[1]);
+
+ if (header->cupsImagingBBox[0] != expected->cupsImagingBBox[0] ||
+ header->cupsImagingBBox[1] != expected->cupsImagingBBox[1] ||
+ header->cupsImagingBBox[2] != expected->cupsImagingBBox[2] ||
+ header->cupsImagingBBox[3] != expected->cupsImagingBBox[3])
+ printf(" cupsImagingBBox [%g %g %g %g], expected [%g %g %g %g]\n",
+ header->cupsImagingBBox[0], header->cupsImagingBBox[1],
+ header->cupsImagingBBox[2], header->cupsImagingBBox[3],
+ expected->cupsImagingBBox[0], expected->cupsImagingBBox[1],
+ expected->cupsImagingBBox[2], expected->cupsImagingBBox[3]);
+
+ for (i = 0; i < 16; i ++)
+ if (header->cupsInteger[i] != expected->cupsInteger[i])
+ printf(" cupsInteger%d %d, expected %d\n", i, header->cupsInteger[i],
+ expected->cupsInteger[i]);
+
+ for (i = 0; i < 16; i ++)
+ if (header->cupsReal[i] != expected->cupsReal[i])
+ printf(" cupsReal%d %g, expected %g\n", i, header->cupsReal[i],
+ expected->cupsReal[i]);
+
+ for (i = 0; i < 16; i ++)
+ if (strcmp(header->cupsString[i], expected->cupsString[i]))
+ printf(" cupsString%d (%s), expected (%s)\n", i,
+ header->cupsString[i], expected->cupsString[i]);
+
+ if (strcmp(header->cupsMarkerType, expected->cupsMarkerType))
+ printf(" cupsMarkerType (%s), expected (%s)\n", header->cupsMarkerType,
+ expected->cupsMarkerType);
+
+ if (strcmp(header->cupsRenderingIntent, expected->cupsRenderingIntent))
+ printf(" cupsRenderingIntent (%s), expected (%s)\n",
+ header->cupsRenderingIntent,
+ expected->cupsRenderingIntent);
+
+ if (strcmp(header->cupsPageSizeName, expected->cupsPageSizeName))
+ printf(" cupsPageSizeName (%s), expected (%s)\n",
+ header->cupsPageSizeName,
+ expected->cupsPageSizeName);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/textcommon.c b/filter/textcommon.c
new file mode 100644
index 000000000..8c7204370
--- /dev/null
+++ b/filter/textcommon.c
@@ -0,0 +1,1214 @@
+/*
+ * "$Id$"
+ *
+ * Common text filter routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * TextMain() - Standard main entry for text filters.
+ * compare_keywords() - Compare two C/C++ keywords.
+ * getutf8() - Get a UTF-8 encoded wide character...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "textcommon.h"
+#include <cups/language-private.h>
+
+
+/*
+ * Globals...
+ */
+
+int WrapLines = 1, /* Wrap text in lines */
+ SizeLines = 60, /* Number of lines on a page */
+ SizeColumns = 80, /* Number of columns on a line */
+ PageColumns = 1, /* Number of columns on a page */
+ ColumnGutter = 0, /* Number of characters between text columns */
+ ColumnWidth = 80, /* Width of each column */
+ PrettyPrint = 0, /* Do pretty code formatting */
+ Copies = 1; /* Number of copies */
+lchar_t **Page = NULL; /* Page characters */
+int NumPages = 0; /* Number of pages in document */
+float CharsPerInch = 10; /* Number of character columns per inch */
+float LinesPerInch = 6; /* Number of lines per inch */
+int NumKeywords = 0; /* Number of known keywords */
+char **Keywords = NULL; /* List of known keywords */
+
+
+/*
+ * Local globals...
+ */
+
+static char *code_keywords[] = /* List of known C/C++ keywords... */
+ {
+ "and",
+ "and_eq",
+ "asm",
+ "auto",
+ "bitand",
+ "bitor",
+ "bool",
+ "break",
+ "case",
+ "catch",
+ "char",
+ "class",
+ "compl",
+ "const",
+ "const_cast",
+ "continue",
+ "default",
+ "delete",
+ "do",
+ "double",
+ "dynamic_cast",
+ "else",
+ "enum",
+ "explicit",
+ "extern",
+ "false",
+ "float",
+ "for",
+ "friend",
+ "goto",
+ "if",
+ "inline",
+ "int",
+ "long",
+ "mutable",
+ "namespace",
+ "new",
+ "not",
+ "not_eq",
+ "operator",
+ "or",
+ "or_eq",
+ "private",
+ "protected",
+ "public",
+ "register",
+ "reinterpret_cast",
+ "return",
+ "short",
+ "signed",
+ "sizeof",
+ "static",
+ "static_cast",
+ "struct",
+ "switch",
+ "template",
+ "this",
+ "throw",
+ "true",
+ "try",
+ "typedef",
+ "typename",
+ "union",
+ "unsigned",
+ "virtual",
+ "void",
+ "volatile",
+ "while",
+ "xor",
+ "xor_eq"
+ },
+ *sh_keywords[] = /* List of known Boure/Korn/zsh/bash keywords... */
+ {
+ "alias",
+ "bg",
+ "break",
+ "case",
+ "cd",
+ "command",
+ "continue",
+ "do",
+ "done",
+ "echo",
+ "elif",
+ "else",
+ "esac",
+ "eval",
+ "exec",
+ "exit",
+ "export",
+ "fc",
+ "fg",
+ "fi",
+ "for",
+ "function",
+ "getopts",
+ "if",
+ "in",
+ "jobs",
+ "kill",
+ "let",
+ "limit",
+ "newgrp",
+ "print",
+ "pwd",
+ "read",
+ "readonly",
+ "return",
+ "select",
+ "set",
+ "shift",
+ "test",
+ "then",
+ "time",
+ "times",
+ "trap",
+ "typeset",
+ "ulimit",
+ "umask",
+ "unalias",
+ "unlimit",
+ "unset",
+ "until",
+ "wait",
+ "whence"
+ "while",
+ },
+ *csh_keywords[] = /* List of known csh/tcsh keywords... */
+ {
+ "alias",
+ "aliases",
+ "bg",
+ "bindkey",
+ "break",
+ "breaksw",
+ "builtins",
+ "case",
+ "cd",
+ "chdir",
+ "complete",
+ "continue",
+ "default",
+ "dirs",
+ "echo",
+ "echotc",
+ "else",
+ "end",
+ "endif",
+ "eval",
+ "exec",
+ "exit",
+ "fg",
+ "foreach",
+ "glob",
+ "goto",
+ "history",
+ "if",
+ "jobs",
+ "kill",
+ "limit",
+ "login",
+ "logout",
+ "ls",
+ "nice",
+ "nohup",
+ "notify",
+ "onintr",
+ "popd",
+ "pushd",
+ "pwd",
+ "rehash",
+ "repeat",
+ "set",
+ "setenv",
+ "settc",
+ "shift",
+ "source",
+ "stop",
+ "suspend",
+ "switch",
+ "telltc",
+ "then",
+ "time",
+ "umask",
+ "unalias",
+ "unbindkey",
+ "unhash",
+ "unlimit",
+ "unset",
+ "unsetenv",
+ "wait",
+ "where",
+ "which",
+ "while"
+ },
+ *perl_keywords[] = /* List of known perl keywords... */
+ {
+ "abs",
+ "accept",
+ "alarm",
+ "and",
+ "atan2",
+ "bind",
+ "binmode",
+ "bless",
+ "caller",
+ "chdir",
+ "chmod",
+ "chomp",
+ "chop",
+ "chown",
+ "chr",
+ "chroot",
+ "closdir",
+ "close",
+ "connect",
+ "continue",
+ "cos",
+ "crypt",
+ "dbmclose",
+ "dbmopen",
+ "defined",
+ "delete",
+ "die",
+ "do",
+ "dump",
+ "each",
+ "else",
+ "elsif",
+ "endgrent",
+ "endhostent",
+ "endnetent",
+ "endprotoent",
+ "endpwent",
+ "endservent",
+ "eof",
+ "eval",
+ "exec",
+ "exists",
+ "exit",
+ "exp",
+ "fcntl",
+ "fileno",
+ "flock",
+ "for",
+ "foreach",
+ "fork",
+ "format",
+ "formline",
+ "getc",
+ "getgrent",
+ "getgrgid",
+ "getgrnam",
+ "gethostbyaddr",
+ "gethostbyname",
+ "gethostent",
+ "getlogin",
+ "getnetbyaddr",
+ "getnetbyname",
+ "getnetent",
+ "getpeername",
+ "getpgrp",
+ "getppid",
+ "getpriority",
+ "getprotobyname",
+ "getprotobynumber",
+ "getprotoent",
+ "getpwent",
+ "getpwnam",
+ "getpwuid",
+ "getservbyname",
+ "getservbyport",
+ "getservent",
+ "getsockname",
+ "getsockopt",
+ "glob",
+ "gmtime",
+ "goto",
+ "grep",
+ "hex",
+ "if",
+ "import",
+ "index",
+ "int",
+ "ioctl",
+ "join",
+ "keys",
+ "kill",
+ "last",
+ "lc",
+ "lcfirst",
+ "length",
+ "link",
+ "listen",
+ "local",
+ "localtime",
+ "log",
+ "lstat",
+ "map",
+ "mkdir",
+ "msgctl",
+ "msgget",
+ "msgrcv",
+ "msgsend",
+ "my",
+ "next",
+ "no",
+ "not",
+ "oct",
+ "open",
+ "opendir",
+ "or",
+ "ord",
+ "pack",
+ "package",
+ "pipe",
+ "pop",
+ "pos",
+ "print",
+ "printf",
+ "push",
+ "quotemeta",
+ "rand",
+ "read",
+ "readdir",
+ "readlink",
+ "recv",
+ "redo",
+ "ref",
+ "rename",
+ "require",
+ "reset",
+ "return",
+ "reverse",
+ "rewinddir",
+ "rindex",
+ "rmdir",
+ "scalar",
+ "seek",
+ "seekdir",
+ "select",
+ "semctl",
+ "semget",
+ "semop",
+ "send",
+ "setgrent",
+ "sethostent",
+ "setnetent",
+ "setpgrp",
+ "setpriority",
+ "setprotoent",
+ "setpwent",
+ "setservent",
+ "setsockopt",
+ "shift",
+ "shmctl",
+ "shmget",
+ "shmread",
+ "shmwrite",
+ "shutdown",
+ "sin",
+ "sleep",
+ "socket",
+ "socketpair",
+ "sort",
+ "splice",
+ "split",
+ "sprintf",
+ "sqrt",
+ "srand",
+ "stat",
+ "study",
+ "sub",
+ "substr",
+ "symlink",
+ "syscall",
+ "sysread",
+ "sysseek",
+ "system",
+ "syswrite",
+ "tell",
+ "telldir",
+ "tie",
+ "tied",
+ "time",
+ "times"
+ "times",
+ "truncate",
+ "uc",
+ "ucfirst",
+ "umask",
+ "undef",
+ "unless",
+ "unlink",
+ "unpack",
+ "unshift",
+ "untie",
+ "until",
+ "use",
+ "utime",
+ "values",
+ "vec",
+ "wait",
+ "waitpid",
+ "wantarray",
+ "warn",
+ "while",
+ "write"
+ };
+
+
+/*
+ * Local functions...
+ */
+
+static int compare_keywords(const void *, const void *);
+static int getutf8(FILE *fp);
+
+
+/*
+ * 'TextMain()' - Standard main entry for text filters.
+ */
+
+int /* O - Exit status */
+TextMain(const char *name, /* I - Name of filter */
+ int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ FILE *fp; /* Print file */
+ ppd_file_t *ppd; /* PPD file */
+ int i, /* Looping var */
+ ch, /* Current char from file */
+ lastch, /* Previous char from file */
+ attr, /* Current attribute */
+ line, /* Current line */
+ column, /* Current column */
+ page_column; /* Current page column */
+ int num_options; /* Number of print options */
+ cups_option_t *options; /* Print options */
+ const char *val; /* Option value */
+ char keyword[64], /* Keyword string */
+ *keyptr; /* Pointer into string */
+ int keycol; /* Column where keyword starts */
+ int ccomment; /* Inside a C-style comment? */
+ int cstring; /* Inside a C string */
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options [file]"),
+ name);
+ return (1);
+ }
+
+ /*
+ * If we have 7 arguments, print the file named on the command-line.
+ * Otherwise, send stdin instead...
+ */
+
+ if (argc == 6)
+ fp = stdin;
+ else
+ {
+ /*
+ * Try to open the print file...
+ */
+
+ if ((fp = fopen(argv[6], "rb")) == NULL)
+ {
+ perror("DEBUG: unable to open print file - ");
+ return (1);
+ }
+ }
+
+ /*
+ * Process command-line options and write the prolog...
+ */
+
+ options = NULL;
+ num_options = cupsParseOptions(argv[5], 0, &options);
+
+ if ((val = cupsGetOption("prettyprint", num_options, options)) != NULL &&
+ _cups_strcasecmp(val, "no") && _cups_strcasecmp(val, "off") &&
+ _cups_strcasecmp(val, "false"))
+ {
+ PageLeft = 72.0f;
+ PageRight = PageWidth - 36.0f;
+ PageBottom = PageBottom > 36.0f ? PageBottom : 36.0f;
+ PageTop = PageLength - 36.0f;
+ CharsPerInch = 12;
+ LinesPerInch = 8;
+
+ if ((val = getenv("CONTENT_TYPE")) == NULL)
+ {
+ PrettyPrint = PRETTY_PLAIN;
+ NumKeywords = 0;
+ Keywords = NULL;
+ }
+ else if (_cups_strcasecmp(val, "application/x-cshell") == 0)
+ {
+ PrettyPrint = PRETTY_SHELL;
+ NumKeywords = sizeof(csh_keywords) / sizeof(csh_keywords[0]);
+ Keywords = csh_keywords;
+ }
+ else if (_cups_strcasecmp(val, "application/x-csource") == 0)
+ {
+ PrettyPrint = PRETTY_CODE;
+ NumKeywords = sizeof(code_keywords) / sizeof(code_keywords[0]);
+ Keywords = code_keywords;
+ }
+ else if (_cups_strcasecmp(val, "application/x-perl") == 0)
+ {
+ PrettyPrint = PRETTY_PERL;
+ NumKeywords = sizeof(perl_keywords) / sizeof(perl_keywords[0]);
+ Keywords = perl_keywords;
+ }
+ else if (_cups_strcasecmp(val, "application/x-shell") == 0)
+ {
+ PrettyPrint = PRETTY_SHELL;
+ NumKeywords = sizeof(sh_keywords) / sizeof(sh_keywords[0]);
+ Keywords = sh_keywords;
+ }
+ else
+ {
+ PrettyPrint = PRETTY_PLAIN;
+ NumKeywords = 0;
+ Keywords = NULL;
+ }
+ }
+
+ ppd = SetCommonOptions(num_options, options, 1);
+
+ if ((val = cupsGetOption("wrap", num_options, options)) == NULL)
+ WrapLines = 1;
+ else
+ WrapLines = !_cups_strcasecmp(val, "true") || !_cups_strcasecmp(val, "on") ||
+ !_cups_strcasecmp(val, "yes");
+
+ if ((val = cupsGetOption("columns", num_options, options)) != NULL)
+ {
+ PageColumns = atoi(val);
+
+ if (PageColumns < 1)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("Bad columns value %d."),
+ PageColumns);
+ return (1);
+ }
+ }
+
+ if ((val = cupsGetOption("cpi", num_options, options)) != NULL)
+ {
+ CharsPerInch = atof(val);
+
+ if (CharsPerInch <= 0.0)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("Bad cpi value %f."),
+ CharsPerInch);
+ return (1);
+ }
+ }
+
+ if ((val = cupsGetOption("lpi", num_options, options)) != NULL)
+ {
+ LinesPerInch = atof(val);
+
+ if (LinesPerInch <= 0.0)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("Bad lpi value %f."),
+ LinesPerInch);
+ return (1);
+ }
+ }
+
+ if (PrettyPrint)
+ PageTop -= 216.0f / LinesPerInch;
+
+ Copies = atoi(argv[4]);
+
+ WriteProlog(argv[3], argv[2], getenv("CLASSIFICATION"),
+ cupsGetOption("page-label", num_options, options), ppd);
+
+ /*
+ * Read text from the specified source and print it...
+ */
+
+ lastch = 0;
+ column = 0;
+ line = 0;
+ page_column = 0;
+ attr = 0;
+ keyptr = keyword;
+ keycol = 0;
+ ccomment = 0;
+ cstring = 0;
+
+ while ((ch = getutf8(fp)) >= 0)
+ {
+ /*
+ * Control codes:
+ *
+ * BS Backspace (0x08)
+ * HT Horizontal tab; next 8th column (0x09)
+ * LF Line feed; forward full line (0x0a)
+ * VT Vertical tab; reverse full line (0x0b)
+ * FF Form feed (0x0c)
+ * CR Carriage return (0x0d)
+ * ESC 7 Reverse full line (0x1b 0x37)
+ * ESC 8 Reverse half line (0x1b 0x38)
+ * ESC 9 Forward half line (0x1b 0x39)
+ */
+
+ switch (ch)
+ {
+ case 0x08 : /* BS - backspace for boldface & underline */
+ if (column > 0)
+ column --;
+
+ keyptr = keyword;
+ keycol = column;
+ break;
+
+ case 0x09 : /* HT - tab to next 8th column */
+ if (PrettyPrint && keyptr > keyword)
+ {
+ *keyptr = '\0';
+ keyptr = keyword;
+
+ if (bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
+ compare_keywords))
+ {
+ /*
+ * Put keywords in boldface...
+ */
+
+ i = page_column * (ColumnWidth + ColumnGutter);
+
+ while (keycol < column)
+ {
+ Page[line][keycol + i].attr |= ATTR_BOLD;
+ keycol ++;
+ }
+ }
+ }
+
+ column = (column + 8) & ~7;
+
+ if (column >= ColumnWidth && WrapLines)
+ { /* Wrap text to margins */
+ line ++;
+ column = 0;
+
+ if (line >= SizeLines)
+ {
+ page_column ++;
+ line = 0;
+
+ if (page_column >= PageColumns)
+ {
+ WritePage();
+ page_column = 0;
+ }
+ }
+ }
+
+ keycol = column;
+
+ attr &= ~ATTR_BOLD;
+ break;
+
+ case 0x0d : /* CR */
+#ifndef __APPLE__
+ /*
+ * All but MacOS/Darwin treat CR as was intended by ANSI
+ * folks, namely to move to column 0/1. Some programs still
+ * use this to do boldfacing and underlining...
+ */
+
+ column = 0;
+ break;
+#else
+ /*
+ * MacOS/Darwin still need to treat CR as a line ending.
+ */
+
+ {
+ int nextch;
+ if ((nextch = getc(fp)) != 0x0a)
+ ungetc(nextch, fp);
+ else
+ ch = nextch;
+ }
+#endif /* !__APPLE__ */
+
+ case 0x0a : /* LF - output current line */
+ if (PrettyPrint && keyptr > keyword)
+ {
+ *keyptr = '\0';
+ keyptr = keyword;
+
+ if (bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
+ compare_keywords))
+ {
+ /*
+ * Put keywords in boldface...
+ */
+
+ i = page_column * (ColumnWidth + ColumnGutter);
+
+ while (keycol < column)
+ {
+ Page[line][keycol + i].attr |= ATTR_BOLD;
+ keycol ++;
+ }
+ }
+ }
+
+ line ++;
+ column = 0;
+ keycol = 0;
+
+ if (!ccomment && !cstring)
+ attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE);
+
+ if (line >= SizeLines)
+ {
+ page_column ++;
+ line = 0;
+
+ if (page_column >= PageColumns)
+ {
+ WritePage();
+ page_column = 0;
+ }
+ }
+ break;
+
+ case 0x0b : /* VT - move up 1 line */
+ if (line > 0)
+ line --;
+
+ keyptr = keyword;
+ keycol = column;
+
+ if (!ccomment && !cstring)
+ attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE);
+ break;
+
+ case 0x0c : /* FF - eject current page... */
+ if (PrettyPrint && keyptr > keyword)
+ {
+ *keyptr = '\0';
+ keyptr = keyword;
+
+ if (bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
+ compare_keywords))
+ {
+ /*
+ * Put keywords in boldface...
+ */
+
+ i = page_column * (ColumnWidth + ColumnGutter);
+
+ while (keycol < column)
+ {
+ Page[line][keycol + i].attr |= ATTR_BOLD;
+ keycol ++;
+ }
+ }
+ }
+
+ page_column ++;
+ column = 0;
+ keycol = 0;
+ line = 0;
+
+ if (!ccomment && !cstring)
+ attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE);
+
+ if (page_column >= PageColumns)
+ {
+ WritePage();
+ page_column = 0;
+ }
+ break;
+
+ case 0x1b : /* Escape sequence */
+ ch = getutf8(fp);
+ if (ch == '7')
+ {
+ /*
+ * ESC 7 Reverse full line (0x1b 0x37)
+ */
+
+ if (line > 0)
+ line --;
+ }
+ else if (ch == '8')
+ {
+ /*
+ * ESC 8 Reverse half line (0x1b 0x38)
+ */
+
+ if ((attr & ATTR_RAISED) && line > 0)
+ {
+ attr &= ~ATTR_RAISED;
+ line --;
+ }
+ else if (attr & ATTR_LOWERED)
+ attr &= ~ATTR_LOWERED;
+ else
+ attr |= ATTR_RAISED;
+ }
+ else if (ch == '9')
+ {
+ /*
+ * ESC 9 Forward half line (0x1b 0x39)
+ */
+
+ if ((attr & ATTR_LOWERED) && line < (SizeLines - 1))
+ {
+ attr &= ~ATTR_LOWERED;
+ line ++;
+ }
+ else if (attr & ATTR_RAISED)
+ attr &= ~ATTR_RAISED;
+ else
+ attr |= ATTR_LOWERED;
+ }
+ break;
+
+ default : /* All others... */
+ if (ch < ' ')
+ break; /* Ignore other control chars */
+
+ if (PrettyPrint > PRETTY_PLAIN)
+ {
+ /*
+ * Do highlighting of C/C++ keywords, preprocessor commands,
+ * and comments...
+ */
+
+ if (ch == ' ' && (attr & ATTR_BOLD))
+ {
+ /*
+ * Stop bolding preprocessor command...
+ */
+
+ attr &= ~ATTR_BOLD;
+ }
+ else if (!(isalnum(ch & 255) || ch == '_') && keyptr > keyword)
+ {
+ /*
+ * Look for a keyword...
+ */
+
+ *keyptr = '\0';
+ keyptr = keyword;
+
+ if (!(attr & ATTR_ITALIC) &&
+ bsearch(&keyptr, Keywords, NumKeywords, sizeof(char *),
+ compare_keywords))
+ {
+ /*
+ * Put keywords in boldface...
+ */
+
+ i = page_column * (ColumnWidth + ColumnGutter);
+
+ while (keycol < column)
+ {
+ Page[line][keycol + i].attr |= ATTR_BOLD;
+ keycol ++;
+ }
+ }
+ }
+ else if ((isalnum(ch & 255) || ch == '_') && !ccomment && !cstring)
+ {
+ /*
+ * Add characters to the current keyword (if they'll fit).
+ */
+
+ if (keyptr == keyword)
+ keycol = column;
+
+ if (keyptr < (keyword + sizeof(keyword) - 1))
+ *keyptr++ = ch;
+ }
+ else if (ch == '\"' && lastch != '\\' && !ccomment && !cstring)
+ {
+ /*
+ * Start a C string constant...
+ */
+
+ cstring = -1;
+ attr = ATTR_BLUE;
+ }
+ else if (ch == '*' && lastch == '/' && !cstring &&
+ PrettyPrint != PRETTY_SHELL)
+ {
+ /*
+ * Start a C-style comment...
+ */
+
+ ccomment = 1;
+ attr = ATTR_ITALIC | ATTR_GREEN;
+ }
+ else if (ch == '/' && lastch == '/' && !cstring &&
+ PrettyPrint == PRETTY_CODE)
+ {
+ /*
+ * Start a C++-style comment...
+ */
+
+ attr = ATTR_ITALIC | ATTR_GREEN;
+ }
+ else if (ch == '#' && !cstring && PrettyPrint != PRETTY_CODE)
+ {
+ /*
+ * Start a shell-style comment...
+ */
+
+ attr = ATTR_ITALIC | ATTR_GREEN;
+ }
+ else if (ch == '#' && column == 0 && !ccomment && !cstring &&
+ PrettyPrint == PRETTY_CODE)
+ {
+ /*
+ * Start a preprocessor command...
+ */
+
+ attr = ATTR_BOLD | ATTR_RED;
+ }
+ }
+
+ if (column >= ColumnWidth && WrapLines)
+ { /* Wrap text to margins */
+ column = 0;
+ line ++;
+
+ if (line >= SizeLines)
+ {
+ page_column ++;
+ line = 0;
+
+ if (page_column >= PageColumns)
+ {
+ WritePage();
+ page_column = 0;
+ }
+ }
+ }
+
+ /*
+ * Add text to the current column & line...
+ */
+
+ if (column < ColumnWidth)
+ {
+ i = column + page_column * (ColumnWidth + ColumnGutter);
+
+ if (PrettyPrint)
+ Page[line][i].attr = attr;
+ else if (ch == ' ' && Page[line][i].ch)
+ ch = Page[line][i].ch;
+ else if (ch == Page[line][i].ch)
+ Page[line][i].attr |= ATTR_BOLD;
+ else if (Page[line][i].ch == '_')
+ Page[line][i].attr |= ATTR_UNDERLINE;
+ else if (ch == '_')
+ {
+ Page[line][i].attr |= ATTR_UNDERLINE;
+
+ if (Page[line][i].ch)
+ ch = Page[line][i].ch;
+ }
+ else
+ Page[line][i].attr = attr;
+
+ Page[line][i].ch = ch;
+ }
+
+ if (PrettyPrint)
+ {
+ if ((ch == '{' || ch == '}') && !ccomment && !cstring &&
+ column < ColumnWidth)
+ {
+ /*
+ * Highlight curley braces...
+ */
+
+ Page[line][column].attr |= ATTR_BOLD;
+ }
+ else if ((ch == '/' || ch == '*') && lastch == '/' &&
+ column < ColumnWidth && PrettyPrint != PRETTY_SHELL)
+ {
+ /*
+ * Highlight first comment character...
+ */
+
+ Page[line][column - 1].attr = attr;
+ }
+ else if (ch == '\"' && lastch != '\\' && !ccomment && cstring > 0)
+ {
+ /*
+ * End a C string constant...
+ */
+
+ cstring = 0;
+ attr &= ~ATTR_BLUE;
+ }
+ else if (ch == '/' && lastch == '*' && ccomment)
+ {
+ /*
+ * End a C-style comment...
+ */
+
+ ccomment = 0;
+ attr &= ~(ATTR_ITALIC | ATTR_GREEN);
+ }
+
+ if (cstring < 0)
+ cstring = 1;
+ }
+
+ column ++;
+ break;
+ }
+
+ /*
+ * Save this character for the next cycle.
+ */
+
+ lastch = ch;
+ }
+
+ /*
+ * Write any remaining page data...
+ */
+
+ if (line > 0 || page_column > 0 || column > 0)
+ WritePage();
+
+ /*
+ * Write the epilog and return...
+ */
+
+ WriteEpilogue();
+
+ if (ppd != NULL)
+ ppdClose(ppd);
+
+ return (0);
+}
+
+
+/*
+ * 'compare_keywords()' - Compare two C/C++ keywords.
+ */
+
+static int /* O - Result of strcmp */
+compare_keywords(const void *k1, /* I - First keyword */
+ const void *k2) /* I - Second keyword */
+{
+ return (strcmp(*((const char **)k1), *((const char **)k2)));
+}
+
+
+/*
+ * 'getutf8()' - Get a UTF-8 encoded wide character...
+ */
+
+static int /* O - Character or -1 on error */
+getutf8(FILE *fp) /* I - File to read from */
+{
+ int ch; /* Current character value */
+ int next; /* Next character from file */
+
+
+ /*
+ * Read the first character and process things accordingly...
+ *
+ * UTF-8 maps 16-bit characters to:
+ *
+ * 0 to 127 = 0xxxxxxx
+ * 128 to 2047 = 110xxxxx 10yyyyyy (xxxxxyyyyyy)
+ * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz (xxxxyyyyyyzzzzzz)
+ *
+ * We also accept:
+ *
+ * 128 to 191 = 10xxxxxx
+ *
+ * since this range of values is otherwise undefined unless you are
+ * in the middle of a multi-byte character...
+ *
+ * This code currently does not support anything beyond 16-bit
+ * characters, in part because PostScript doesn't support more than
+ * 16-bit characters...
+ */
+
+ if ((ch = getc(fp)) == EOF)
+ return (EOF);
+
+ if (ch < 0xc0) /* One byte character? */
+ return (ch);
+ else if ((ch & 0xe0) == 0xc0)
+ {
+ /*
+ * Two byte character...
+ */
+
+ if ((next = getc(fp)) == EOF)
+ return (EOF);
+ else
+ return (((ch & 0x1f) << 6) | (next & 0x3f));
+ }
+ else if ((ch & 0xf0) == 0xe0)
+ {
+ /*
+ * Three byte character...
+ */
+
+ if ((next = getc(fp)) == EOF)
+ return (EOF);
+
+ ch = ((ch & 0x0f) << 6) | (next & 0x3f);
+
+ if ((next = getc(fp)) == EOF)
+ return (EOF);
+ else
+ return ((ch << 6) | (next & 0x3f));
+ }
+ else
+ {
+ /*
+ * More than three bytes... We don't support that...
+ */
+
+ return (EOF);
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/textcommon.h b/filter/textcommon.h
new file mode 100644
index 000000000..1e6c631de
--- /dev/null
+++ b/filter/textcommon.h
@@ -0,0 +1,114 @@
+/*
+ * "$Id$"
+ *
+ * Common text filter definitions for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "common.h"
+
+
+/*
+ * C++ magic...
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/*
+ * Constants...
+ */
+
+#define ATTR_NORMAL 0x00
+#define ATTR_BOLD 0x01
+#define ATTR_ITALIC 0x02
+#define ATTR_BOLDITALIC 0x03
+#define ATTR_FONT 0x03
+
+#define ATTR_UNDERLINE 0x04
+#define ATTR_RAISED 0x08
+#define ATTR_LOWERED 0x10
+#define ATTR_RED 0x20
+#define ATTR_GREEN 0x40
+#define ATTR_BLUE 0x80
+
+#define PRETTY_OFF 0
+#define PRETTY_PLAIN 1
+#define PRETTY_CODE 2
+#define PRETTY_SHELL 3
+#define PRETTY_PERL 4
+#define PRETTY_HTML 5
+
+
+/*
+ * Structures...
+ */
+
+typedef struct /**** Character/attribute structure... ****/
+{
+ unsigned short ch, /* Character */
+ attr; /* Any attributes */
+} lchar_t;
+
+
+/*
+ * Globals...
+ */
+
+extern int WrapLines, /* Wrap text in lines */
+ SizeLines, /* Number of lines on a page */
+ SizeColumns, /* Number of columns on a line */
+ PageColumns, /* Number of columns on a page */
+ ColumnGutter, /* Number of characters between text columns */
+ ColumnWidth, /* Width of each column */
+ PrettyPrint, /* Do pretty code formatting? */
+ Copies; /* Number of copies to produce */
+extern lchar_t **Page; /* Page characters */
+extern int NumPages; /* Number of pages in document */
+extern float CharsPerInch, /* Number of character columns per inch */
+ LinesPerInch; /* Number of lines per inch */
+extern int UTF8, /* Use UTF-8 encoding? */
+ NumKeywords; /* Number of known keywords */
+extern char **Keywords; /* List of known keywords... */
+
+
+/*
+ * Required functions...
+ */
+
+extern int TextMain(const char *name, int argc, char *argv[]);
+extern void WriteEpilogue(void);
+extern void WritePage(void);
+extern void WriteProlog(const char *title, const char *user,
+ const char *classification, const char *label,
+ ppd_file_t *ppd);
+
+
+/*
+ * C++ magic...
+ */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/filter/texttops.c b/filter/texttops.c
new file mode 100644
index 000000000..96251245b
--- /dev/null
+++ b/filter/texttops.c
@@ -0,0 +1,1165 @@
+/*
+ * "$Id$"
+ *
+ * Text to PostScript filter for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry for text to PostScript filter.
+ * WriteEpilogue() - Write the PostScript file epilogue.
+ * WritePage() - Write a page of text.
+ * WriteProlog() - Write the PostScript file prolog with options.
+ * write_line() - Write a row of text.
+ * write_string() - Write a string of text.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "textcommon.h"
+#include <cups/language-private.h>
+
+
+/*
+ * Globals...
+ */
+
+char *Glyphs[65536]; /* PostScript glyphs for Unicode */
+int NumFonts; /* Number of fonts to use */
+char *Fonts[256][4]; /* Fonts to use */
+unsigned short Chars[65536]; /* 0xffcc (ff = font, cc = char) */
+unsigned short Codes[65536]; /* Unicode glyph mapping to fonts */
+int Widths[256]; /* Widths of each font */
+int Directions[256];/* Text directions for each font */
+
+
+/*
+ * Local functions...
+ */
+
+static void write_line(int row, lchar_t *line);
+static void write_string(int col, int row, int len, lchar_t *s);
+static void write_text(const char *s);
+
+
+/*
+ * 'main()' - Main entry for text to PostScript filter.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ return (TextMain("texttops", argc, argv));
+}
+
+
+/*
+ * 'WriteEpilogue()' - Write the PostScript file epilogue.
+ */
+
+void
+WriteEpilogue(void)
+{
+ puts("%%Trailer");
+ printf("%%%%Pages: %d\n", NumPages);
+ puts("%%EOF");
+
+ free(Page[0]);
+ free(Page);
+}
+
+
+/*
+ * 'WritePage()' - Write a page of text.
+ */
+
+void
+WritePage(void)
+{
+ int line; /* Current line */
+
+
+ NumPages ++;
+ printf("%%%%Page: %d %d\n", NumPages, NumPages);
+
+ puts("gsave");
+
+ if (PrettyPrint)
+ printf("%d H\n", NumPages);
+
+ for (line = 0; line < SizeLines; line ++)
+ write_line(line, Page[line]);
+
+ puts("grestore");
+ puts("showpage");
+
+ memset(Page[0], 0, sizeof(lchar_t) * SizeColumns * SizeLines);
+}
+
+
+/*
+ * 'WriteProlog()' - Write the PostScript file prolog with options.
+ */
+
+void
+WriteProlog(const char *title, /* I - Title of job */
+ const char *user, /* I - Username */
+ const char *classification, /* I - Classification */
+ const char *label, /* I - Page label */
+ ppd_file_t *ppd) /* I - PPD file info */
+{
+ int i, j, k; /* Looping vars */
+ char *charset; /* Character set string */
+ char filename[1024]; /* Glyph filenames */
+ FILE *fp; /* Glyph files */
+ const char *datadir; /* CUPS_DATADIR environment variable */
+ char line[1024], /* Line from file */
+ *lineptr, /* Pointer into line */
+ *valptr; /* Pointer to value in line */
+ int ch, unicode; /* Character values */
+ int start, end; /* Start and end values for range */
+ char glyph[64]; /* Glyph name */
+ time_t curtime; /* Current time */
+ struct tm *curtm; /* Current date */
+ char curdate[255]; /* Current date (text format) */
+ int num_fonts; /* Number of unique fonts */
+ char *fonts[1024]; /* Unique fonts */
+ static char *names[] = /* Font names */
+ {
+ "cupsNormal",
+ "cupsBold",
+ "cupsItalic"
+ };
+
+
+ /*
+ * Get the data directory...
+ */
+
+ if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+
+ /*
+ * Adjust margins as necessary...
+ */
+
+ if (classification || label)
+ {
+ /*
+ * Leave room for labels...
+ */
+
+ PageBottom += 36;
+ PageTop -= 36;
+ }
+
+ /*
+ * Allocate memory for the page...
+ */
+
+ SizeColumns = (PageRight - PageLeft) / 72.0 * CharsPerInch;
+ SizeLines = (PageTop - PageBottom) / 72.0 * LinesPerInch;
+
+ if (SizeColumns <= 0 || SizeColumns > 32767 ||
+ SizeLines <= 0 || SizeLines > 32767)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to print %dx%d text page."),
+ SizeColumns, SizeLines);
+ exit(1);
+ }
+
+ if ((Page = calloc(sizeof(lchar_t *), SizeLines)) == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to print %dx%d text page."),
+ SizeColumns, SizeLines);
+ exit(1);
+ }
+
+ if ((Page[0] = calloc(sizeof(lchar_t), SizeColumns * SizeLines)) == NULL)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to print %dx%d text page."),
+ SizeColumns, SizeLines);
+ exit(1);
+ }
+
+ for (i = 1; i < SizeLines; i ++)
+ Page[i] = Page[0] + i * SizeColumns;
+
+ if (PageColumns > 1)
+ {
+ ColumnGutter = CharsPerInch / 2;
+ ColumnWidth = (SizeColumns - ColumnGutter * (PageColumns - 1)) /
+ PageColumns;
+ }
+ else
+ ColumnWidth = SizeColumns;
+
+ if (ColumnWidth <= 0)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to print %d text columns."), PageColumns);
+ exit(1);
+ }
+
+ /*
+ * Output the DSC header...
+ */
+
+ curtime = time(NULL);
+ curtm = localtime(&curtime);
+ strftime(curdate, sizeof(curdate), "%c", curtm);
+
+ puts("%!PS-Adobe-3.0");
+ printf("%%%%BoundingBox: 0 0 %.0f %.0f\n", PageWidth, PageLength);
+ printf("%%cupsRotation: %d\n", (Orientation & 3) * 90);
+ puts("%%Creator: texttops/" CUPS_SVERSION);
+ printf("%%%%CreationDate: %s\n", curdate);
+ WriteTextComment("Title", title);
+ WriteTextComment("For", user);
+ puts("%%Pages: (atend)");
+
+ /*
+ * Initialize globals...
+ */
+
+ NumFonts = 0;
+ memset(Fonts, 0, sizeof(Fonts));
+ memset(Glyphs, 0, sizeof(Glyphs));
+ memset(Chars, 0, sizeof(Chars));
+ memset(Codes, 0, sizeof(Codes));
+
+ /*
+ * Load the PostScript glyph names and the corresponding character
+ * set definition...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/data/psglyphs", datadir);
+
+ if ((fp = fopen(filename, "r")) != NULL)
+ {
+ while (fscanf(fp, "%x%63s", &unicode, glyph) == 2)
+ Glyphs[unicode] = strdup(glyph);
+
+ fclose(fp);
+ }
+ else
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open psglyphs"));
+ exit(1);
+ }
+
+ /*
+ * Get the output character set...
+ */
+
+ charset = getenv("CHARSET");
+ if (charset != NULL && strcmp(charset, "us-ascii") != 0)
+ {
+ snprintf(filename, sizeof(filename), "%s/charsets/%s", datadir, charset);
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ {
+ /*
+ * Can't open charset file!
+ */
+
+ _cupsLangPrintError("ERROR", _("Unable to open charset file"));
+ exit(1);
+ }
+
+ /*
+ * Opened charset file; now see if this is really a charset file...
+ */
+
+ if (fgets(line, sizeof(line), fp) == NULL)
+ {
+ /*
+ * Bad/empty charset file!
+ */
+
+ fclose(fp);
+ _cupsLangPrintFilter(stderr, "ERROR", _("Bad charset file \"%s\"."),
+ filename);
+ exit(1);
+ }
+
+ if (strncmp(line, "charset", 7) != 0)
+ {
+ /*
+ * Bad format/not a charset file!
+ */
+
+ fclose(fp);
+ _cupsLangPrintFilter(stderr, "ERROR", _("Bad charset file \"%s\"."),
+ filename);
+ exit(1);
+ }
+
+ /*
+ * See if this is an 8-bit or UTF-8 character set file...
+ */
+
+ line[strlen(line) - 1] = '\0'; /* Drop \n */
+ for (lineptr = line + 7; isspace(*lineptr & 255); lineptr ++); /* Skip whitespace */
+
+ if (strcmp(lineptr, "utf8") == 0)
+ {
+ /*
+ * UTF-8 (Unicode) text...
+ */
+
+ NumFonts = 0;
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Skip comment and blank lines...
+ */
+
+ if (line[0] == '#' || line[0] == '\n')
+ continue;
+
+ /*
+ * Read the font descriptions that should look like:
+ *
+ * start end direction width normal [bold italic bold-italic]
+ */
+
+ lineptr = line;
+
+ start = strtol(lineptr, &lineptr, 16);
+ end = strtol(lineptr, &lineptr, 16);
+
+ while (isspace(*lineptr & 255))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+
+ if (!*lineptr)
+ {
+ /*
+ * Can't have a font without all required values...
+ */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Bad font description line: %s"), valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ *lineptr++ = '\0';
+
+ if (strcmp(valptr, "ltor") == 0)
+ Directions[NumFonts] = 1;
+ else if (strcmp(valptr, "rtol") == 0)
+ Directions[NumFonts] = -1;
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("Bad text direction: %s"),
+ valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ /*
+ * Got the direction, now get the width...
+ */
+
+ while (isspace(*lineptr & 255))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+
+ if (!*lineptr)
+ {
+ /*
+ * Can't have a font without all required values...
+ */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Bad font description line: %s"), valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ *lineptr++ = '\0';
+
+ if (strcmp(valptr, "single") == 0)
+ Widths[NumFonts] = 1;
+ else if (strcmp(valptr, "double") == 0)
+ Widths[NumFonts] = 2;
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Bad text width: %s"), valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ /*
+ * Get the fonts...
+ */
+
+ for (i = 0; *lineptr && i < 4; i ++)
+ {
+ while (isspace(*lineptr & 255))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+
+ if (*lineptr)
+ *lineptr++ = '\0';
+
+ if (lineptr > valptr)
+ Fonts[NumFonts][i] = strdup(valptr);
+ }
+
+ /*
+ * Fill in remaining fonts as needed...
+ */
+
+ for (j = i; j < 4; j ++)
+ Fonts[NumFonts][j] = strdup(Fonts[NumFonts][0]);
+
+ /*
+ * Define the character mappings...
+ */
+
+ for (i = start, j = NumFonts * 256; i <= end; i ++, j ++)
+ {
+ Chars[i] = j;
+ Codes[j] = i;
+ }
+
+ /*
+ * Move to the next font, stopping if needed...
+ */
+
+ NumFonts ++;
+ if (NumFonts >= 256)
+ break;
+ }
+
+ fclose(fp);
+ }
+ else
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("Bad charset type: %s"), lineptr);
+ fclose(fp);
+ exit(1);
+ }
+ }
+ else
+ {
+ /*
+ * Standard ASCII output just uses Courier, Courier-Bold, and
+ * possibly Courier-Oblique.
+ */
+
+ NumFonts = 1;
+
+ Fonts[0][ATTR_NORMAL] = strdup("Courier");
+ Fonts[0][ATTR_BOLD] = strdup("Courier-Bold");
+ Fonts[0][ATTR_ITALIC] = strdup("Courier-Oblique");
+ Fonts[0][ATTR_BOLDITALIC] = strdup("Courier-BoldOblique");
+
+ Widths[0] = 1;
+ Directions[0] = 1;
+
+ /*
+ * Define US-ASCII characters...
+ */
+
+ for (i = 32; i < 127; i ++)
+ {
+ Chars[i] = i;
+ Codes[i] = i;
+ }
+ }
+
+ /*
+ * Generate a list of unique fonts to use...
+ */
+
+ for (i = 0, num_fonts = 0; i < NumFonts; i ++)
+ for (j = PrettyPrint ? 2 : 1; j >= 0; j --)
+ {
+ for (k = 0; k < num_fonts; k ++)
+ if (strcmp(Fonts[i][j], fonts[k]) == 0)
+ break;
+
+ if (k >= num_fonts)
+ {
+ /*
+ * Add new font...
+ */
+
+ fonts[num_fonts] = Fonts[i][j];
+ num_fonts ++;
+ }
+ }
+
+ /*
+ * List the fonts that will be used...
+ */
+
+ for (i = 0; i < num_fonts; i ++)
+ if (i == 0)
+ printf("%%%%DocumentNeededResources: font %s\n", fonts[i]);
+ else
+ printf("%%%%+ font %s\n", fonts[i]);
+
+ puts("%%DocumentSuppliedResources: procset texttops 1.1 0");
+
+ for (i = 0; i < num_fonts; i ++)
+ {
+ if (ppd != NULL)
+ {
+ fprintf(stderr, "DEBUG: ppd->num_fonts = %d\n", ppd->num_fonts);
+
+ for (j = 0; j < ppd->num_fonts; j ++)
+ {
+ fprintf(stderr, "DEBUG: ppd->fonts[%d] = %s\n", j, ppd->fonts[j]);
+
+ if (strcmp(fonts[i], ppd->fonts[j]) == 0)
+ break;
+ }
+ }
+ else
+ j = 0;
+
+ if ((ppd != NULL && j >= ppd->num_fonts) ||
+ strncmp(fonts[i], "Courier", 7) == 0 ||
+ strcmp(fonts[i], "Symbol") == 0)
+ {
+ /*
+ * Need to embed this font...
+ */
+
+ printf("%%%%+ font %s\n", fonts[i]);
+ }
+ }
+
+ puts("%%EndComments");
+
+ puts("%%BeginProlog");
+
+ /*
+ * Download any missing fonts...
+ */
+
+ for (i = 0; i < num_fonts; i ++)
+ {
+ if (ppd != NULL)
+ {
+ for (j = 0; j < ppd->num_fonts; j ++)
+ if (strcmp(fonts[i], ppd->fonts[j]) == 0)
+ break;
+ }
+ else
+ j = 0;
+
+ if ((ppd != NULL && j >= ppd->num_fonts) ||
+ strncmp(fonts[i], "Courier", 7) == 0 ||
+ strcmp(fonts[i], "Symbol") == 0)
+ {
+ /*
+ * Need to embed this font...
+ */
+
+ printf("%%%%BeginResource: font %s\n", fonts[i]);
+
+ /**** MRS: Need to use CUPS_FONTPATH env var! ****/
+ /**** Also look for Fontmap file or name.pfa, name.pfb... ****/
+ snprintf(filename, sizeof(filename), "%s/fonts/%s", datadir, fonts[i]);
+ if ((fp = fopen(filename, "rb")) != NULL)
+ {
+ while ((j = fread(line, 1, sizeof(line), fp)) > 0)
+ fwrite(line, 1, j, stdout);
+
+ fclose(fp);
+ }
+
+ puts("\n%%EndResource");
+ }
+ }
+
+ /*
+ * Write the encoding array(s)...
+ */
+
+ puts("% character encoding(s)");
+
+ for (i = 0; i < NumFonts; i ++)
+ {
+ printf("/cupsEncoding%02x [\n", i);
+
+ for (ch = 0; ch < 256; ch ++)
+ {
+ if (Glyphs[Codes[i * 256 + ch]])
+ printf("/%s", Glyphs[Codes[i * 256 + ch]]);
+ else if (Codes[i * 256 + ch] > 255)
+ printf("/uni%04X", Codes[i * 256 + ch]);
+ else
+ printf("/.notdef");
+
+ if ((ch & 7) == 7)
+ putchar('\n');
+ }
+
+ puts("] def");
+ }
+
+ /*
+ * Create the fonts...
+ */
+
+ if (NumFonts == 1)
+ {
+ /*
+ * Just reencode the named fonts...
+ */
+
+ puts("% Reencode fonts");
+
+ for (i = PrettyPrint ? 2 : 1; i >= 0; i --)
+ {
+ printf("/%s findfont\n", Fonts[0][i]);
+ puts("dup length 1 add dict begin\n"
+ " { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
+ " /Encoding cupsEncoding00 def\n"
+ " currentdict\n"
+ "end");
+ printf("/%s exch definefont pop\n", names[i]);
+ }
+ }
+ else
+ {
+ /*
+ * Construct composite fonts... Start by reencoding the base fonts...
+ */
+
+ puts("% Reencode base fonts");
+
+ for (i = PrettyPrint ? 2 : 1; i >= 0; i --)
+ for (j = 0; j < NumFonts; j ++)
+ {
+ printf("/%s findfont\n", Fonts[j][i]);
+ printf("dup length 1 add dict begin\n"
+ " { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
+ " /Encoding cupsEncoding%02x def\n"
+ " currentdict\n"
+ "end\n", j);
+ printf("/%s%02x exch definefont /%s%02x exch def\n", names[i], j,
+ names[i], j);
+ }
+
+ /*
+ * Then merge them into composite fonts...
+ */
+
+ puts("% Create composite fonts...");
+
+ for (i = PrettyPrint ? 2 : 1; i >= 0; i --)
+ {
+ puts("8 dict begin");
+ puts("/FontType 0 def/FontMatrix[1.0 0 0 1.0 0 0]def/FMapType 2 def/Encoding[");
+ for (j = 0; j < NumFonts; j ++)
+ if (j == (NumFonts - 1))
+ printf("%d", j);
+ else if ((j & 15) == 15)
+ printf("%d\n", j);
+ else
+ printf("%d ", j);
+ puts("]def/FDepVector[");
+ for (j = 0; j < NumFonts; j ++)
+ if (j == (NumFonts - 1))
+ printf("%s%02x", names[i], j);
+ else if ((j & 3) == 3)
+ printf("%s%02x\n", names[i], j);
+ else
+ printf("%s%02x ", names[i], j);
+ puts("]def currentdict end");
+ printf("/%s exch definefont pop\n", names[i]);
+ }
+ }
+
+ /*
+ * Output the texttops procset...
+ */
+
+ puts("%%BeginResource: procset texttops 1.1 0");
+
+ puts("% Define fonts");
+
+ printf("/FN /cupsNormal findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
+ 120.0 / CharsPerInch, 68.0 / LinesPerInch);
+ printf("/FB /cupsBold findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
+ 120.0 / CharsPerInch, 68.0 / LinesPerInch);
+ if (PrettyPrint)
+ printf("/FI /cupsItalic findfont [%.3f 0 0 %.3f 0 0] makefont def\n",
+ 120.0 / CharsPerInch, 68.0 / LinesPerInch);
+
+ puts("% Common procedures");
+
+ puts("/N { FN setfont moveto } bind def");
+ puts("/B { FB setfont moveto } bind def");
+ printf("/U { gsave 0.5 setlinewidth 0 %.3f rmoveto "
+ "0 rlineto stroke grestore } bind def\n", -6.8 / LinesPerInch);
+
+ if (PrettyPrint)
+ {
+ if (ColorDevice)
+ {
+ puts("/S { 0.0 setgray show } bind def");
+ puts("/r { 0.5 0.0 0.0 setrgbcolor show } bind def");
+ puts("/g { 0.0 0.5 0.0 setrgbcolor show } bind def");
+ puts("/b { 0.0 0.0 0.5 setrgbcolor show } bind def");
+ }
+ else
+ {
+ puts("/S { 0.0 setgray show } bind def");
+ puts("/r { 0.2 setgray show } bind def");
+ puts("/g { 0.2 setgray show } bind def");
+ puts("/b { 0.2 setgray show } bind def");
+ }
+
+ puts("/I { FI setfont moveto } bind def");
+
+ puts("/n {");
+ puts("\t20 string cvs % convert page number to string");
+ if (NumFonts > 1)
+ {
+ /*
+ * Convert a number to double-byte chars...
+ */
+
+ puts("\tdup length % get length");
+ puts("\tdup 2 mul string /P exch def % P = string twice as long");
+ puts("\t0 1 2 index 1 sub { % loop through each character in the page number");
+ puts("\t\tdup 3 index exch get % get character N from the page number");
+ puts("\t\texch 2 mul dup % compute offset in P");
+ puts("\t\tP exch 0 put % font 0");
+ puts("\t\t1 add P exch 2 index put % character");
+ puts("\t\tpop % discard character");
+ puts("\t} for % do for loop");
+ puts("\tpop pop % discard string and length");
+ puts("\tP % put string on stack");
+ }
+ puts("} bind def");
+
+ printf("/T");
+ write_text(title);
+ puts("def");
+
+ printf("/D");
+ write_text(curdate);
+ puts("def");
+
+ puts("/H {");
+ puts("\tgsave");
+ puts("\t0.9 setgray");
+
+ if (Duplex)
+ {
+ puts("\tdup 2 mod 0 eq {");
+ printf("\t\t%.3f %.3f translate } {\n",
+ PageWidth - PageRight, PageTop + 72.0f / LinesPerInch);
+ printf("\t\t%.3f %.3f translate } ifelse\n",
+ PageLeft, PageTop + 72.0f / LinesPerInch);
+ }
+ else
+ printf("\t%.3f %.3f translate\n",
+ PageLeft, PageTop + 72.0f / LinesPerInch);
+
+ printf("\t0 0 %.3f %.3f rectfill\n", PageRight - PageLeft,
+ 144.0f / LinesPerInch);
+
+ puts("\tFB setfont");
+ puts("\t0 setgray");
+
+ if (Duplex)
+ {
+ puts("\tdup 2 mod 0 eq {");
+ printf("\t\tT stringwidth pop neg %.3f add %.3f } {\n",
+ PageRight - PageLeft - 36.0f / LinesPerInch,
+ (0.5f + 0.157f) * 72.0f / LinesPerInch);
+ printf("\t\t%.3f %.3f } ifelse\n", 36.0f / LinesPerInch,
+ (0.5f + 0.157f) * 72.0f / LinesPerInch);
+ }
+ else
+ printf("\t%.3f %.3f\n", 36.0f / LinesPerInch,
+ (0.5f + 0.157f) * 72.0f / LinesPerInch);
+
+ puts("\tmoveto T show");
+
+ printf("\tD dup stringwidth pop neg 2 div %.3f add %.3f\n",
+ (PageRight - PageLeft) * 0.5,
+ (0.5f + 0.157f) * 72.0f / LinesPerInch);
+ puts("\tmoveto show");
+
+ if (Duplex)
+ {
+ puts("\tdup n exch 2 mod 0 eq {");
+ printf("\t\t%.3f %.3f } {\n", 36.0f / LinesPerInch,
+ (0.5f + 0.157f) * 72.0f / LinesPerInch);
+ printf("\t\tdup stringwidth pop neg %.3f add %.3f } ifelse\n",
+ PageRight - PageLeft - 36.0f / LinesPerInch,
+ (0.5f + 0.157f) * 72.0f / LinesPerInch);
+ }
+ else
+ printf("\tn dup stringwidth pop neg %.3f add %.3f\n",
+ PageRight - PageLeft - 36.0f / LinesPerInch,
+ (0.5f + 0.157f) * 72.0f / LinesPerInch);
+
+ puts("\tmoveto show");
+ puts("\tgrestore");
+ puts("} bind def");
+ }
+ else
+ puts("/S { show } bind def");
+
+ puts("%%EndResource");
+
+ puts("%%EndProlog");
+}
+
+
+/*
+ * 'write_line()' - Write a row of text.
+ */
+
+static void
+write_line(int row, /* I - Row number (0 to N) */
+ lchar_t *line) /* I - Line to print */
+{
+ int i; /* Looping var */
+ int col; /* Current column */
+ int attr; /* Current attribute */
+ int font, /* Font to use */
+ lastfont, /* Last font */
+ mono; /* Monospaced? */
+ lchar_t *start; /* First character in sequence */
+
+
+ for (col = 0; col < SizeColumns;)
+ {
+ while (col < SizeColumns && (line->ch == ' ' || line->ch == 0))
+ {
+ col ++;
+ line ++;
+ }
+
+ if (col >= SizeColumns)
+ break;
+
+ if (NumFonts == 1)
+ {
+ /*
+ * All characters in a single font - assume monospaced...
+ */
+
+ attr = line->attr;
+ start = line;
+
+ while (col < SizeColumns && line->ch != 0 && attr == line->attr)
+ {
+ col ++;
+ line ++;
+ }
+
+ write_string(col - (line - start), row, line - start, start);
+ }
+ else
+ {
+ /*
+ * Multiple fonts; break up based on the font...
+ */
+
+ attr = line->attr;
+ start = line;
+ lastfont = Chars[line->ch] / 256;
+ mono = strncmp(Fonts[lastfont][0], "Courier", 7) == 0;
+ col ++;
+ line ++;
+
+ if (mono)
+ {
+ while (col < SizeColumns && line->ch != 0 && attr == line->attr)
+ {
+ font = Chars[line->ch] / 256;
+ if (strncmp(Fonts[font][0], "Courier", 7) != 0 ||
+ font != lastfont)
+ break;
+
+ col ++;
+ line ++;
+ }
+ }
+
+ if (Directions[lastfont] > 0)
+ write_string(col - (line - start), row, line - start, start);
+ else
+ {
+ /*
+ * Do right-to-left text...
+ */
+
+ while (col < SizeColumns && line->ch != 0 && attr == line->attr)
+ {
+ if (Directions[Chars[line->ch] / 256] > 0 &&
+ !ispunct(line->ch & 255) && !isspace(line->ch & 255))
+ break;
+
+ col ++;
+ line ++;
+ }
+
+ for (i = 1; start < line; i ++, start ++)
+ if (!isspace(start->ch & 255))
+ write_string(col - i, row, 1, start);
+ }
+ }
+ }
+}
+
+
+/*
+ * 'write_string()' - Write a string of text.
+ */
+
+static void
+write_string(int col, /* I - Start column */
+ int row, /* I - Row */
+ int len, /* I - Number of characters */
+ lchar_t *s) /* I - String to print */
+{
+ int ch; /* Current character */
+ float x, y; /* Position of text */
+ unsigned attr; /* Character attributes */
+
+
+ /*
+ * Position the text and set the font...
+ */
+
+ if (Duplex && (NumPages & 1) == 0)
+ {
+ x = PageWidth - PageRight;
+ y = PageTop;
+ }
+ else
+ {
+ x = PageLeft;
+ y = PageTop;
+ }
+
+ x += (float)col * 72.0f / (float)CharsPerInch;
+ y -= (float)(row + 0.843) * 72.0f / (float)LinesPerInch;
+
+ attr = s->attr;
+
+ if (attr & ATTR_RAISED)
+ y += 36.0 / (float)LinesPerInch;
+ else if (attr & ATTR_LOWERED)
+ y -= 36.0 / (float)LinesPerInch;
+
+ if (x == (int)x)
+ printf("%.0f ", x);
+ else
+ printf("%.3f ", x);
+
+ if (y == (int)y)
+ printf("%.0f ", y);
+ else
+ printf("%.3f ", y);
+
+ if (attr & ATTR_BOLD)
+ putchar('B');
+ else if (attr & ATTR_ITALIC)
+ putchar('I');
+ else
+ putchar('N');
+
+ if (attr & ATTR_UNDERLINE)
+ printf(" %.3f U", (float)len * 72.0 / (float)CharsPerInch);
+
+ if (NumFonts > 1)
+ {
+ /*
+ * Write a hex string...
+ */
+
+ putchar('<');
+
+ while (len > 0)
+ {
+ printf("%04x", Chars[s->ch]);
+
+ len --;
+ s ++;
+ }
+
+ putchar('>');
+ }
+ else
+ {
+ /*
+ * Write a quoted string...
+ */
+
+ putchar('(');
+
+ while (len > 0)
+ {
+ ch = Chars[s->ch];
+
+ if (ch < 32 || ch > 126)
+ {
+ /*
+ * Quote 8-bit and control characters...
+ */
+
+ printf("\\%03o", ch);
+ }
+ else
+ {
+ /*
+ * Quote the parenthesis and backslash as needed...
+ */
+
+ if (ch == '(' || ch == ')' || ch == '\\')
+ putchar('\\');
+
+ putchar(ch);
+ }
+
+ len --;
+ s ++;
+ }
+
+ putchar(')');
+ }
+
+ if (PrettyPrint)
+ {
+ if (attr & ATTR_RED)
+ puts("r");
+ else if (attr & ATTR_GREEN)
+ puts("g");
+ else if (attr & ATTR_BLUE)
+ puts("b");
+ else
+ puts("S");
+ }
+ else
+ puts("S");
+}
+
+
+/*
+ * 'write_text()' - Write a text string, quoting/encoding as needed.
+ */
+
+static void
+write_text(const char *s) /* I - String to write */
+{
+ int ch; /* Actual character value (UTF8) */
+ const unsigned char *utf8; /* UTF8 text */
+
+
+ if (NumFonts > 1)
+ {
+ /*
+ * 8/8 encoding...
+ */
+
+ putchar('<');
+
+ utf8 = (const unsigned char *)s;
+
+ while (*utf8)
+ {
+ if (*utf8 < 0xc0)
+ ch = *utf8 ++;
+ else if ((*utf8 & 0xe0) == 0xc0)
+ {
+ /*
+ * Two byte character...
+ */
+
+ ch = ((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f);
+ utf8 += 2;
+ }
+ else
+ {
+ /*
+ * Three byte character...
+ */
+
+ ch = ((((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f)) << 6) |
+ (utf8[2] & 0x3f);
+ utf8 += 3;
+ }
+
+ printf("%04x", Chars[ch]);
+ }
+
+ putchar('>');
+ }
+ else
+ {
+ /*
+ * Standard 8-bit encoding...
+ */
+
+ putchar('(');
+
+ while (*s)
+ {
+ if (*s < 32 || *s > 126)
+ printf("\\%03o", *s);
+ else
+ {
+ if (*s == '(' || *s == ')' || *s == '\\')
+ putchar('\\');
+
+ putchar(*s);
+ }
+
+ s ++;
+ }
+
+ putchar(')');
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/fonts/Makefile b/fonts/Makefile
new file mode 100644
index 000000000..04f689447
--- /dev/null
+++ b/fonts/Makefile
@@ -0,0 +1,118 @@
+#
+# "$Id$"
+#
+# Fonts makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1993-2006 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+#
+# Font files...
+#
+
+FONTS = \
+ Monospace \
+ Monospace-Bold \
+ Monospace-BoldOblique \
+ Monospace-Oblique
+
+
+#
+# Make everything...
+#
+
+all:
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Clean all config and object files...
+#
+
+clean:
+
+
+#
+# Dummy depend target...
+#
+
+depend:
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+ $(INSTALL_DIR) -m 755 $(DATADIR)/fonts
+ if test "x$(BANNERTOPS)" != x -o "x$(TEXTTOPS)" != x; then \
+ for file in $(FONTS); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/fonts; \
+ done \
+ fi
+
+
+#
+# Install programs...
+#
+
+install-exec:
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall files...
+#
+
+uninstall:
+ for file in $(FONTS); do \
+ $(RM) $(DATADIR)/fonts/$$file; \
+ done
+ $(RMDIR) $(DATADIR)/fonts
+
+
+#
+# End of "$Id$".
+#
diff --git a/fonts/Monospace b/fonts/Monospace
new file mode 100644
index 000000000..2512b85fa
--- /dev/null
+++ b/fonts/Monospace
@@ -0,0 +1,2744 @@
+%!PS-AdobeFont-1.0: Monospace 1.15
+%%DocumentSuppliedResources: font Monospace
+%%Title: Monospace
+%Version: 1.15
+%%CreationDate: Thu Oct 27 10:50:21 2005
+%%Creator: mike
+%Copyright: Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.
+%Copyright: DejaVu changes are in public domain
+
+% Generated by FontForge 20051018 (http://fontforge.sf.net/)
+%%EndComments
+
+FontDirectory/Monospace known{/Monospace findfont dup/UniqueID known{dup
+/UniqueID get 4166841 eq exch/FontType get 1 eq and}{pop false}ifelse
+{save true}{false}ifelse}{false}ifelse
+11 dict begin
+/FontType 1 def
+/FontMatrix [0.000488281 0 0 0.000488281 0 0 ]readonly def
+/FontName /Monospace def
+/FontBBox {-109 -1034 1342 2133 }readonly def
+/UniqueID 4166841 def
+/PaintType 0 def
+/FontInfo 11 dict dup begin
+ /version (1.15) readonly def
+ /Notice (Copyright \050c\051 2003 by Bitstream, Inc. All Rights Reserved.\012DejaVu changes are in public domain\012) readonly def
+% Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.
+% DejaVu changes are in public domain
+ /FullName (Monospace) readonly def
+ /FamilyName (Monospace) readonly def
+ /Weight (Book) readonly def
+ /FSType 0 def
+ /ItalicAngle 0 def
+ /isFixedPitch true def
+ /UnderlinePosition -213 def
+ /UnderlineThickness 141 def
+ /ascent 1556 def
+end readonly def
+/Encoding 256 array
+ 0 1 255 { 1 index exch /.notdef put} for
+dup 32/space put
+dup 33/exclam put
+dup 34/quotedbl put
+dup 35/numbersign put
+dup 36/dollar put
+dup 37/percent put
+dup 38/ampersand put
+dup 39/quotesingle put
+dup 40/parenleft put
+dup 41/parenright put
+dup 42/asterisk put
+dup 43/plus put
+dup 44/comma put
+dup 45/hyphen put
+dup 46/period put
+dup 47/slash put
+dup 48/zero put
+dup 49/one put
+dup 50/two put
+dup 51/three put
+dup 52/four put
+dup 53/five put
+dup 54/six put
+dup 55/seven put
+dup 56/eight put
+dup 57/nine put
+dup 58/colon put
+dup 59/semicolon put
+dup 60/less put
+dup 61/equal put
+dup 62/greater put
+dup 63/question put
+dup 64/at put
+dup 65/A put
+dup 66/B put
+dup 67/C put
+dup 68/D put
+dup 69/E put
+dup 70/F put
+dup 71/G put
+dup 72/H put
+dup 73/I put
+dup 74/J put
+dup 75/K put
+dup 76/L put
+dup 77/M put
+dup 78/N put
+dup 79/O put
+dup 80/P put
+dup 81/Q put
+dup 82/R put
+dup 83/S put
+dup 84/T put
+dup 85/U put
+dup 86/V put
+dup 87/W put
+dup 88/X put
+dup 89/Y put
+dup 90/Z put
+dup 91/bracketleft put
+dup 92/backslash put
+dup 93/bracketright put
+dup 94/asciicircum put
+dup 95/underscore put
+dup 96/grave put
+dup 97/a put
+dup 98/b put
+dup 99/c put
+dup 100/d put
+dup 101/e put
+dup 102/f put
+dup 103/g put
+dup 104/h put
+dup 105/i put
+dup 106/j put
+dup 107/k put
+dup 108/l put
+dup 109/m put
+dup 110/n put
+dup 111/o put
+dup 112/p put
+dup 113/q put
+dup 114/r put
+dup 115/s put
+dup 116/t put
+dup 117/u put
+dup 118/v put
+dup 119/w put
+dup 120/x put
+dup 121/y put
+dup 122/z put
+dup 123/braceleft put
+dup 124/bar put
+dup 125/braceright put
+dup 126/asciitilde put
+dup 160/nonbreakingspace put
+dup 161/exclamdown put
+dup 162/cent put
+dup 163/sterling put
+dup 164/currency put
+dup 165/yen put
+dup 166/brokenbar put
+dup 167/section put
+dup 168/dieresis put
+dup 169/copyright put
+dup 170/ordfeminine put
+dup 171/guillemotleft put
+dup 172/logicalnot put
+dup 173/sfthyphen put
+dup 174/registered put
+dup 175/macron put
+dup 176/degree put
+dup 177/plusminus put
+dup 178/twosuperior put
+dup 179/threesuperior put
+dup 180/acute put
+dup 181/mu put
+dup 182/paragraph put
+dup 183/periodcentered put
+dup 184/cedilla put
+dup 185/onesuperior put
+dup 186/ordmasculine put
+dup 187/guillemotright put
+dup 188/onequarter put
+dup 189/onehalf put
+dup 190/threequarters put
+dup 191/questiondown put
+dup 192/Agrave put
+dup 193/Aacute put
+dup 194/Acircumflex put
+dup 195/Atilde put
+dup 196/Adieresis put
+dup 197/Aring put
+dup 198/AE put
+dup 199/Ccedilla put
+dup 200/Egrave put
+dup 201/Eacute put
+dup 202/Ecircumflex put
+dup 203/Edieresis put
+dup 204/Igrave put
+dup 205/Iacute put
+dup 206/Icircumflex put
+dup 207/Idieresis put
+dup 208/Eth put
+dup 209/Ntilde put
+dup 210/Ograve put
+dup 211/Oacute put
+dup 212/Ocircumflex put
+dup 213/Otilde put
+dup 214/Odieresis put
+dup 215/multiply put
+dup 216/Oslash put
+dup 217/Ugrave put
+dup 218/Uacute put
+dup 219/Ucircumflex put
+dup 220/Udieresis put
+dup 221/Yacute put
+dup 222/Thorn put
+dup 223/germandbls put
+dup 224/agrave put
+dup 225/aacute put
+dup 226/acircumflex put
+dup 227/atilde put
+dup 228/adieresis put
+dup 229/aring put
+dup 230/ae put
+dup 231/ccedilla put
+dup 232/egrave put
+dup 233/eacute put
+dup 234/ecircumflex put
+dup 235/edieresis put
+dup 236/igrave put
+dup 237/iacute put
+dup 238/icircumflex put
+dup 239/idieresis put
+dup 240/eth put
+dup 241/ntilde put
+dup 242/ograve put
+dup 243/oacute put
+dup 244/ocircumflex put
+dup 245/otilde put
+dup 246/odieresis put
+dup 247/divide put
+dup 248/oslash put
+dup 249/ugrave put
+dup 250/uacute put
+dup 251/ucircumflex put
+dup 252/udieresis put
+dup 253/yacute put
+dup 254/thorn put
+dup 255/ydieresis put
+readonly def
+currentdict end
+currentfile eexec
+17F6ABC0BD4E5B049FA8ED1415B73797205424D2E47FC5DF8590627DC99082760E8B3E17
+0C18AF49528FA9DB386CE480B471EC8797784FB466233A879056FB46290A8F49442020C3
+E00AF7FDB602BAC1C4F8636E32FDDB936FC70C567B075E18878EA286E1D24CC1E14B50B7
+DCDD17FD5295A3F44E0DA80366E61263EA00234FA095739BDE371FED9A24338A8CAB0F53
+5964F1515D62E477A2F1C2BEEA2DF171E3962F0DE53E2763D7DE117F6B5328691D69C4D8
+D071D89F6AB4731DFE0A1FCC4F32351620B2B48E12AEAD940270EF4990B511E7D052C3A4
+2AAEF583BD41B85778646ED2E9A86A73A1089F502672860E7A7A9CFC2F7B2E221C6C9080
+7B7E7B4218C9B10B574C73E195D6C97D1EDC5FA365221BD82148D1ADEA7F235FFC14AD5A
+47E11207058A7A9059FF373F66FEA5A9113CE0BCAF084AAE135556FE84AA4C5A9070BD77
+E7D39A94BA711FDFE442366E9F27F14EF80FFF2C342189C2E28D9FC541F049944C1CF913
+2A014935BF47B42C4E0847A335B4E6CE5016C1B8FC0C3E153C07ADF3C0B00CE001DDF36F
+DE0CC04A25FA1635707299ACB277BFF663DE9558664D1DE90465FBC67BAEA7B1851FCC85
+7364E4BB97470017B40C4D54096C4AE2469A5D037963C7F009DD25A32C20487FF1F1F0A0
+124BF0B10891BC1FBDC65F9192B7236A694E1CFD1388CD27288222AE80032683C803533D
+E6C39DF03BFA02DB5F35C1B99531836F38F6F04192AE3228C0F19841842F5C907529175B
+6BF7B4A8D7B3F27FB39A58B7D3CF11A306701B548C3DC231102A45496B5535C96FBF0412
+004ED0658F28F845F4B0C5F02A680737A738A559E8E6BFCA7584C0A9FAB1B5D3C8995508
+856337933B9A49D0624F25CC06C8243C2A8816426753B631100403B630D81FCA4D08527F
+3AE881DA5332F16C4D8B15F3CBD4DF36430C2199BE5CD27CCF4BE86F5519C046E73442E3
+AEC3F3DAD10948A6AF7740BE87874A288FB27851EF698B571A027E5787BB45BA566A2822
+69423D624D118CA8D14B389A93193F1C8CF64CDC3F0153D4B8CA8AA843C2C26AAC2971DA
+7F52B17B21ACE56A7021C6255A2707BFF033A1477C42C0B5D2001820FC9A8BFFB4E9DBAB
+B595E925C78C9CF87420160DC0B549CBD8A3D12352AFE06CFEF38A2D3715AECCF86E0919
+790BA8FEAE050576C4DFCB416E2DF5FA3B25192F16A935C9CA82C87CC997CA5909B956FA
+1622B10EAD7465B8FE6B347675D7C363581C9B52C9D020AD5CF983284D9359F4C8F9E91B
+C073DAFC702EA788540E72A08668BEA885605C8D42E5F6BAE086F3591C614D438FAB01E1
+3D69768ED2249FF1079E2EE704F9672DF9DF9C8A41CADAE9013809F1DA83673A8398B477
+A13B4B0093E151F6489A2D9BC119A66232A1AB85F31979FBA9EE7F163FD59FE14C72FAFF
+A1CFCC482619E13021FEC7F10C6730E5A7FCAEE84EB5011F13E407591BCE6353D5AD0634
+D4414B008C95F31170FD8F33F83C6B02DDDF05401012E7260A3DD0213857AF9072EF5DA7
+389AE027997C2D7130443A4B2E505A9F17B00E84E142E4ECBFF3AEF2C2C4E84F162E2F7E
+436222EBA20B0DB87346084A2BF64B70B1796729F845D456702C7625AD2CA3D232345C9C
+12B9DCBDFAB9B8F697E5E4EF2D473D119F81A46F6FD8A03AAC73211F36FF824DE6E03788
+BD669A0E7F2813A4AA830C8EF8BE445CABE6019318806D10C5952157FF8F8286C1EE7015
+45C8F60EFA854EAE66835A2046A6915D395F1E0366A459E43236162A929ABE6ECDB26B57
+EAE7CE3731E0DB75ED207292FD83B6B288231E4F3F8170DCB831DF571EC07CE2D698CB6B
+88C63F342E89FA1BE8879269D9F818C4F740C38EB419A8A814E52AC7CA90187730F43520
+115D7388390F20A8119771ED45AE1E58C1DD30B171E7B5B2E75DC63EDF55BCB9D7BF3119
+5E4BC6D91227A24B996F83BF8AA17D3A1DFD34B32E91C4F51C229796662763D1668E884B
+E9BE85D60132A4C45ECFA6FEBEFFD3E34AF21DA897B24A5B836D4DF2E81D1B51FE682095
+63128FFE15E36687F7720F3C980EDED7A794EB420F3E0465B1E93755F64A9C54A24058FE
+E496317919512048C2B01062574EAA66A2F86D01F58D9D252F2A84E7B44A057D8DE0EF2F
+EF7B752B46B1643D7E57D2871CC15D0DAC4852901205AEB7C996A957C4A0605AAC287AA6
+581DD2C8ED591B89BA7126687F970D7D49E84AD96BCE16AFE6508B25E85D530D9A9F7A11
+E788CBC50E80F8A4ECD26C241C37078EDC447DFF2A43ED7BF1E00B6F227926A9913ACEB0
+98B833E54B3FD10F9D0CE4B8ED76549239A7F4FE846B9D57F26B53229856681CA7D3EFB0
+22CCF57311C872CD0D0342A2FFC59E2F13B32D530B0268A4D01A14193D1B17001E205355
+1E42338F7BAE7D9B02780A3D972AE4E904DD34761AA66159CEF52B226277596A2A9433D6
+4B5AA165D9595B99829EEA6E26F4E10DE1B6E0F33BDBB010A036D221B7F4191F4420B6EF
+621566F238B0ACC9A7C41B90823D9DA08E327896CAE4AEE60F860240EC8A89C03E44E2CD
+D4E767F4D457275E3F7AD41D4983D7C6BCEE26E6A7EBAD234DADE81B2C98C1F3F396979C
+04A4E00E6F4AFDDDBE9D9EB775D1A1EE76399AEC7D30D3CD09AFD73601ADF5593B56D0B1
+4471810AF628AF86D1237E3690509FBAB8FB2F4D041CDA612467B254CBBF83780C60C1C7
+AED265168AFC379F832EBA6D6DFA2CE6FBE127690B37309F6A613608BA98A5B77E9ED5E4
+E7C373750542C245C20D10035D1163AE93970F3A8CCA7B5A57DD0503060637DEA1CDC404
+713E1DE9E328DD8D902D24E0C70B17620EA2217B7E51589626FF6923A0D76DE1B480DFC9
+CE2B7BE62919C80623B7E39BBBE748E8E70242233CCCC5899AE70F1A3B380418564AAB15
+E4CCB6BE3A9329C58D8843AA7D287D851168FB531FA694CAE2B9D77C13720A9499C13D50
+B4D6AB2A5BCAE592D465FBADE34CF7316886A7287918889EEB7FE26AB47B5319F833422D
+803421C29FBCCF0D64657D945676C968938B633371EA7B3114BE2C23FD20581CDE846A7F
+C5C57C4A4BFBE5A649B20E3756BA94FA8C45D0542134790D6105890BB01C961ACB87C761
+743FBA8F2549015D6B171EFD0390ECDB7744E185BB9D88BA42C4CCD61CF9AAC20B6E4C0D
+A70F20091A75C9250C9F9287CDDD78D39400A85D28C70E38B38D33903E7496D3EE1FE98D
+B047C84C59A60A58DA8DAC47A058A825544C1B4F4CBDFDD99A04BB691854A20A773544DA
+A39EC11B14C864220F74CC2307075EBB4847AFF216614A471B1B169DCFF4F89FE390CB97
+46089C958316DEFEDDDF9F3BE4A6BCD0423836A7AC3F7A29CC863418B703668188C962D3
+6803BCEF438B47363A40762165AB9671A46F9253DDE8AFC38DAE53F7E34230ADE2830956
+F5B7EB9BE9E0086B7FB715173272B381B494085744ED8F2EDFAA567E2DFEC2861A231157
+818D7DC0898DCB8B8AE30BC0F1A65F018BBDFF3ACBA4436B5E824B6B4CC0F4402856E259
+F1D5F1C770A1589A621F9747B5F7E81908016DD977ADED8019C39BF5CB9AB35CA82CC83E
+AEC842F6913929F8339EC1DCB27A53E3E1006174E2C8CBE4756F6762395DFB5AD85947BC
+63137E05269807A5958D5A346528162B4C1B485E858DDB2ED3AF35A0485CBDECE9A2893D
+C28B94DABA77498C26861FEF72571B5B66477862642465030FA5633E47B24BB8697E5A20
+73945D8E2338E554D66EAF307D9035AC9678414E799EC56AD03EB72A72B227DC18C3B27E
+8AA1679D14FFBABF22FD2EE80C94AD06C34FE7F7597A82E1EFF272F2FCD72AECE10D5102
+BA8682441BAB1E8DD83EFAD74757A96051DE07782FE7B7D7BDF36DF39A434E59F1D2630D
+93B66D1AD1A9565211B13427A036019C538D4C4314905257E8FEB31FC5DD316F606D7BFB
+9CC3829EBCEAAF3722E465C60AB1D7CBA1D2D229CC28D11DF8FAFD2169339C0B61AEC73B
+6FC855B5567FBF05D9088734DDD8755700C80A5C942915811567F103D0CB70611DE63F61
+9B2908AEED0B33A1CD43A84785FF49EE977D5C45E1ADE13672FBB01DB79096DFF6036904
+30B27DD8C0609AB745C238EC6F73B1CB8234794DDD9E1A41681CC004362DB2A97B8A96E9
+C981F7848C4BA5ECCE7CB87713B6B7C7CDB7450AFA5FA6719A8EF035D672A136AD494139
+8E777EBDBCA5DC8A9DFD54654883221071167CB4756FCD042891D85E4B2F5F306F39CD0F
+B2E267665EC0A394A150D73A9AFE7C1098609BB6247A6DD24B01BD3B78DA1E49AAAFF696
+D27A53696FC27DA3B017224587D43372CD3406CCE3AC952D73C9AF01058C8EFFBD0C177B
+204C6DF2CFC597FF177ADCAB6FCBD5F0267B00CA18311A4250FD04DF3809D4DB2C0E4778
+3D905D787362901E1171745B2A66848A3B617F29FE183DF6F746F9011AB14925AAFA1C4C
+159C27D3BF8537D6FAA40A20B47745BD7148C698C450F18D0ADEBA3095F0379B7D0B4354
+E1BFFF0C63C7D745F0085D7239612CB0E5EF4B8FAEF7C19A7300881206500AC612D0C42C
+66F4B99C32AF8CFFB05749260B56B7B425B550C427368E45AB7BB682C9D3E07FAF35DC89
+0AC6191384133DA9DCA3F3977243D277E0A1B833E37C4399B67DC083168310ED294ABA2B
+6A96F5F1F7E8A18E5C8A95CE1E224DBBFFCBE5E54BCD199625EBB5E5DDF1F2795DD53D81
+86A5EEE389B4EA7402B14D2BA4B3D9A1F50079AE9809A0B0A5061764A3320D9AB4B5CF1C
+4BCAAA4CB0F2926A46397B9D8F3B3956E647FCF3034A34B6BAB88BD4C53FB84638DA56D2
+2C65DB9BDEB68FCAD5CAB7B184EAEC585677704583CE9372F90471EA5B68FC5D1DD702A0
+A7668E6C7416E4A5CD646EFD2359DBB7367492BC0B4E6BAFA13D3D3975604E1A187A6E61
+EF6087394EAC2F8FA9FB4C040A994545480329FF5FF9B4727A39356F8A4043A74A9A7E2D
+250826ADD481F91B9DB916A9FD5FE4469A9861A96BDF6BD3DAE13293B9DC2A318A35D7FF
+DBCD241F2FB394644895A3F53C457C752A72E8167E6B7D4495B3C1DF0EC53127509988F1
+49D6C49CDA35B00652F148D3CAEFA3EFD8954E80766AEFCB85953366389FD4DF6D70E36E
+B321BDB176FE7B75CC31A73F4DB7BDF5E0B45C23FFAD7B7EE35B9B6E9EA4141F4F98430B
+D93BE0FCF80D63D7860E9B43D161DA7A68C2BD51E2E95ED7B54A91466D0716603CC41E83
+7004D94DABC5D971330DF98672136E372129A77CB496C7200FE3E287F7936E8002B54C51
+25B364B6E07943A078E2C018678B7E159C1DFDE7633CC3633B38D50C54B98B45DF4A972B
+93B4B4013F8F1EC0083B09F3FAFD2CE2B2ED5791DDC0945679A122F21B4C5D67DA6E5A5F
+2A5893AD3AA7AFD891ABC6860F14EE16DDE548520DC88C2CE6099861B038EB25A01589D3
+2F4AE37FAA4D171416651CCE37FA4EB8D063A0977988E50F9036C0A9C8E99E6D586EED28
+E0FEFBE7406386EB9FBDCBD8DF820F6371C99C6F7A4F2E3F43FD2792A9A2D3F81BD3DC6E
+DEB59B1B4DACC2F278A0C6C1D3B841A73525F311504CEFC8538CD53C487F612D9045AB40
+8B8A76195907E3B679CE68322703C2F80A50401BD44BB5D14080A46F859075C9B51BF0A2
+C42321EDE4254F558FE33357746631F407C16675320B8DF3E24E0FBE2E93BF718CBCCF5F
+F21F013313BAF474F239CD0FE72EB03279791A95BB322DF5C4725763052185CD5CDEDC76
+071B4B2337B406337237A2A6490D75598CF6010D22582B8A12871C17003839A8A8C42E92
+EFC92B7EF0763D7B6481965F890802C7AD345F2FFB5A444DE404C833D1D9DB1CEE2DABB6
+42DB540CB398BD2C16A7383E649A0714154E72D94438FF904755399C1674F5E01CD45590
+CD04C4FE3292356650A3D431D7600426A1475B5919722726468C247BCD565965DA6E4A83
+28644CB1FD2A23B1B45F74E6B4BA9AE065BE873BBB80505D16D54D9DE69026CF1DE8DEBD
+E472F067C70CB4104D23ED0CC9BF68055283A6CC2AAF48FC59A580DA8597F95EBB8F61FB
+C4F6B12FEE888AD60897383AB17D227C0CEF95E86F149ED6B71C2FD67F5A996E8B34C5EE
+23DFFEE49200A250611E32FE3300AEE9BF13790703B6AC983C965F1C52D2BE0BE876D4A8
+85FCE072D5D584B12CF2CF91BD7D7F9EDA1D6FD62F40AB5682312D6138030FA1EBE9B194
+1DA4ABAE5A781EA979F608C6F0D5481CF48AACE9F79031574204447596555188C3D6048D
+B9D7D8D1F0B67DD5F3468E7C7B647DCD1AC3B3C95E1DA6DA05816B49DC8BB86E85C0094C
+6C9A703B88F020363930195842A753EE42B4BEC13B668101203BBB7D5CF7E9C3E39716B9
+85F4BA374147BC7B13BC2515C8A500596D35152A102FA248B9E30D6050C11045B9A81213
+7C228594EE2725F43CCE59D3F1669F0B4722B2171811C2A12B1905C0B40EF1B1957731A3
+A20D29302DB48D061351430549F57084C31D008391BC9D20534EA98CA6F951E00FDE49F6
+22913C19F44E489CF9A80274B43CA60CA5C517C821426D5BFA185649ADC0F1AFFE8ABFBC
+A0A03CF0DB690CAF902219A5580EEB11DD3ED650979550454929EFDCC32C7E8418B80F54
+F0CAD6049E2EB23D5DBC2D680772F03E8F3D19913E6F771AC65C1575AA6968CC6857633A
+C2520C09AE900BA1CED6C5C21C2CF8BCA8D676A539F22DFE03B4134AA8181CB38BB0F69F
+C83517AB3AAB165F2A1FA474E067627199406D26881E8066E509D3C39A1A8C4BF99D4D46
+922EEA6D05F7EBDD33A33774F24A650B9170D2CBC9A69317CF90010F9688EC72B3DFD2B7
+0EAE5DE97C03A5CBC355E8A57F7C36D9AF8DA95B4A307965074244B72B5689F6DA0FD360
+DD95C184A7037397C0598153F96AEBF3E059B042A3251AEBAFDB90631C7A7E52C89E7623
+07487D51B8A019BE505E4078DF87A79565DAEAFCBDCF4D99E658A3A6F33C252CC8FDEA27
+CC974B91269FB2FD905A619159300A0274E79C1F52ACACBF68E03CBA15523A0B2081C739
+3D397D3D4BDF3094FBC5D20852EF7766A4C83B708E2F75008756044AB2B55C57559CF7A4
+636F74B49D18E81057BE38166F87DF24C73B337533DCAFC8F7D4EF0A3C4C6B82E9BFA3E4
+F3116E011FFC4A89B7FB72CFF1B0229D6D578AC85DC6E6C3CB956193689607D6D7A48367
+0D7C529E5C5C223E081E3C6F1F3A2B8BA8EB5C4DBD19F9A5566694EDDAB69837B65C8299
+63A95E321181E4BA0B097FBDF72647838C8B49DE3AA88B6F755317FB1785E12DDA71F944
+49D3D1DBC0C167B3793747D9D6EBF6FA13A74FE1FFB6A2EBBDDE14A21040380DA4BC9088
+C60ED587EDF6E2A00BC041990F00C7568373598310FBB5FE87A1656E381A2C449C63B236
+5BDA6D3C51D1E5A1A0ED408221B2FA8397FE2FC992F990DB3E772F3EA54CB468AD471FB8
+0FB1E1A9CC6444B98D2993F5DAAC9B5CDE3ED8AD6FD8DE80001DC7D67A09B39BA8D0B35A
+CEFD510CF34838F06C72047309CFA29787631CD33E0E4457DF26244706966FCAD9A90668
+A155F9BC4214693A80C3440F56C2A01D87AD998493130C344E9560A88F9969585B6D2D4C
+AEDCA0D1954D6C84E0F717C48548C60B39D0013FC95E3DA0C13796130F3E0D8A240F8ACC
+4BFD93D26A7185DE5AA0C493EF230D0A5EB0DDFBD49A66A61D814D2D03EE94B40A25F8C6
+5F615B8C4402B4FFF0A882316E9123C0267E0773E048658ECF5C0008EC18976EE2F8CB4C
+E5B4C17F857B83E16622180B70F0433488E58826B39221566EAE2A9C350177F10D9737CA
+6ED009C263E3198F02D7A3514B3AA1AE7B0BDBE901D84DC256855A3DFCC83BF51C9B3CCA
+1FD2756DC6D54280E164E942530CC560BDD8FA6AEAD30EF5BD8A4A30EE5755C7A4D7C550
+F0399CCEB87FB781EF298DBA53BF7FC3373388DDE9AE21AFE51A7EADFE83767E8A112DBF
+C595A9B0E833CE7F8ECE227028F10E36B8147340F6C0152DADF434AB60CC64BD9158E0E8
+C30F38FD0D5D7573D43FC3AA9403BE945DF46D040AAD91FF69D0B0FDDAF19EDE36F089AB
+D8E00D8417C463C1CB3292E6AC20CAF026C74FE0F97CF8D7956678D1A104002A68D53664
+A82EAA93112A3BD2B55113F37E8588E78C0429E482259A2A0C11F745A74429FBABB8A53C
+D40101CE27011FE51335D3417E41ED1A8D260EAAB7C3F118B426DF541FFBDA96C4FA9859
+66B99AAB27B4DBFD28304F386879C6DF62242B689DE14BEAA08BF07AE4A38B203B024F88
+808C5E227B6AE750142874E5E59B23AB9B36025B6D67EAE9B8DB60B9A04A388525D1F50D
+C46F8172AD8DACEB870ABB56944F916B492DD6E9D296049973D661689E8A416014D4D2C2
+782EAB49362E9FBFD5BD6F0C95F243BE717535005F99A22FF28A7A02A5F4BA4B1F505449
+61ED383753ADD0D2952FA9313CAA827F3D8F8977C98D760E4BBDC134DFBC0A008230D337
+35A048B81A94A8CB7034DE777595158CBABDB648F1A2325655EB64B42C24D190C2979F9F
+AB4C9DA55299AEADE3801F9956E3C62A77A16746073EBBD364AC634B37671C8F153B8EF7
+D9F110CEE184CE3394349EBFD88E43D15B309DAFF263F4BECF1C581FC4CE876B68D3F1C5
+EB2F001FBA2809FDC3F834833F39B74C9E5018C8A7CBEECDFCB121EDCE0282988BC5BF4D
+156D91F53B4EF6B9FF7D95CF1B39B679F06190A10C3FFF40D461000E3F8E422AC042148F
+E12B5A776BB1F15D44D41CED498A9AEFD2CAF59CDCDE5C4158B8CA1CBDF4FB5AE83D99B1
+A39770AA15397D85F77F42846B0893AE39A0F4612A62A7D963B767DFB1E92A0B73FC65CC
+EDBAD8D74D2C24E08B2D551538DD954D94A80B92E897E8C10D1725988EAF003E9BABE962
+2C9C8D278A6BF1935574C80C6815BDF0BB7011FBEA53A59C0C45D1978A1D3E6A7BCC87F4
+2C5FDC7886044CE5798F06096AB7FB360316E1BFCE3E719A1EA906E0C5949E00DE7AED0D
+E6C25832D30CE1867387C8254F51171A9037C8CBC6D339B4647E9077D605C13E30324180
+A433FF9F3A7BBC3B0B775A860F7BAB63D7538E2092F902F019D29FE8DD198EBD85DF0564
+D39C10DC176F698641996117778D7F899153CB26D568C057DA39FBE2D21ACF39E0756E16
+7FB5AF562F190A7B940A8F4BFF98AE156D74CE4C8CEAAB103FE6F06B7D578E5D7675DBA7
+27FCC0B96031ADF2D3F204EF9DF63D8A4263EBE46B74F1A2CB67D620FF5B2585A53C7CB0
+DA53F6F219B277BE9F8735014BDF61936C3377A6D1348D3C670A65CD057B32DBBFFFF5E4
+D830E9CA83BABE9298431F93884E2083D6ED6DA68A30C7372539DE05E8CC9DD8A748C810
+462687C6B9B75B305C3A31BC32A122365DEB55AF6F6D2BA9468247BC0853E7144E46AAE7
+E0D7C76E8BA15289ED307E0943F5E3A05F051AD2C2EBDC7E2BA46F91B4CA94308D1D2FF3
+FCAB4EDDF761FFCF83C23C979E4D318A51A26424D78E5B215EA33F04E1BE296A9693F065
+9309FF404423775875D73F230FCD5CFB1AEF0F6CE5674F865C300105791111C1AAFC98A1
+557123E1C34749937C8BDE11E41C21B1B0FC53E8C5D199D3289DE09C7D7A95EB23D5192B
+AAA67A13DABCDDF6C48115036065984276B126F294D6BDDFB90BE9319F3A3D031A22BBC6
+05766A7BC934472D23812B37720AC3403189F34F2CAC2B674B04D3B3B46B6662B1C2489A
+2964D8EE5EAAC87A8AC7208E5E87358DDBEF9EBB52B96102CDB82D8BCC5D8A404DA247FC
+C304D7153187BB579C75F71DA411E4B0FA80D2131D11C6BD693F3AA001FB349FA11B5FB4
+9DDC4B2A6443A8932AC4813795934D61D38BAEB1847EE5D3A7D01708524B3933B442709E
+CBF2D39460259D44CE01645BCBCDC2BB9588C855936C6100009D867FBDC902475BB43DA2
+F7A309AE56082F18E670A25BA12213EB7D9BF6679452CD4814353BC62C1ECD5E1A7C50EE
+43277A1D5D124BA9F596E19A29C24C234B1102893D2BEEA07F22450E26BE882D0FDC2AEA
+5457AFEAD360063AF6A079958A343F444DC6EE7126AB88ED079C0165CF95765CC52DBBB7
+3CBECD85BB4F1176C4608201A6E2D3FA69C439B4AB2A9D5441F519DDC85C35C2DEE504DF
+5ED9E958F768E9FED68D18748C8521FD6163FFE0DECF1BA44B11A261A4997D13E045C255
+0CD95881B9BC5D65A7C4AF0DA73A637F4979A3B54B9857402738B1E9FF94CDC075F51817
+CDFE1DC677E938F4ADB9E4CE4DDF4F12EE6C72352175B8389F39F84181C189F1BA529E9D
+8D84B7E36790C1F57CE2117811E986D00B58EEFF6C8121934AF2FC54D09C486A5D9CA8F7
+6887CF4D7FE4841F3222F0C4E4F7D92C014FB4D48DB83FA87C243D453915BD6BDF5278BF
+1C16090730765D68AD17160744DFD19AC8A754915E669074D4F3A9A1F37F7D720B38D5E1
+5D734093944BA853010ED6C6CC7D5D885D6A1366B2FEE42E54718A2DC1BBD437830EF66E
+A0F540524597090FC7C762F19C3946274500428C3C3AAD98D9611484C8CD302D64991438
+1F7E531BEC859E6D6624ADE92B17C4D88AE651E49658CD23840C404E1E2EEA4F56D6725F
+E514D3AE47AB1127EA69CE677705C603CAEB0DA31233E15ACC5D78ECBB90DBA3878F19FF
+F2A62395FE3B8EEDCCBA872A42334251BB515C34F513D2FB745033E903863C24A7F8A47F
+0DE02964F1D3AA92E60BEC967BE17A207ACCC4512B8E8D62E767608FEC0D4F0C6D339364
+0332BFDAA278713788075972FE7B5799FCCA94BDE4C881CE667C4B7D10F1A4CE65766CC1
+F3486E0F23DC940A93B3D88EA329FAB54F531034113FC7970DC304A20FA97FFE7116C6D7
+1504BC0FED9A1C8E617AFED697DD3FA441CB5894D783512E1FFB859EA5686F64381EE1A3
+471572DA94B4D7AAC35E3E77EC8ABBB310D46A70C5AB691B050019B1408DB7D155AD3F75
+27E8FEF1F1492E8C96C96A0EAA70AEE119B244995F1DDAC5F9E1B4EDD07AA389382345EE
+2873FF17B725037B66F7B5B3CB74237808E8A1E8FA6B597F418D62D174E716C0A857219C
+DD489083E9086E5A3564A8D0925003BB0935792B38A458F451CD15D8824E457132B50F8F
+1A486AE2AFAAB124EB8D387A4AD23B552803298F23AB33D96547E1A028FDEE361836B59B
+879F544757214D635D0AD01C8B8D8FD61B852E3F6BFC9281C99D1F360032349FB484BF27
+256B591CAF48AE5A6A1117BFB824F3850E95E75AB6FF948233763934CB18CD290BAE9E53
+747FA478BDB6E343336F58D89E05BAE9B912D484171ED576DE30D6516D68FF80CC6BC36B
+62CCBF407447126E8B3D6D07DF3C187AAB240B84B5D07CEF0CEE8AAD28DEE446F321C622
+0A7E0026C64802A9A006887A170FBCB19B4C29CE1D4E089F5193171CA3D3EBDC1A1286A0
+60C648D24BBBB8791BC400BFCAC653A673F4C3A59C44D364D408B72437C06DAD89512F6B
+9526FF964C3B2646DA7E34E3DC95D2408ED3816C6177133287B88C896EA7D575D1389971
+2A9D3A2E689C003CE2D5DC4073ED052F37A3183BDCE5EB3B509385AC8268DDC54A33F8B6
+865FD8D63ED1C51B89B07DFCA39914F10AE7233C7A62EC9B83A8C6E3CFDA24528B1D1F80
+3C74A108E7239456B412EDCDDD5995A6E56535CC9D47E871B0CF8B36BED4818FDD112A70
+2704D417B79347BA3CF24A1B116937BDCCACF86D8D4C544AE863DA44A29C308F740F5DD2
+3FABD1DC281D722590624DAE38EB4A119F5F271C42169287D8E37D34EDAD684EA20CF29E
+EF4B6BA4D65E41E9E8BD9EF2321C2453DD84C5AA056017E7F5321A3C11614D810D0095E0
+5DA9C4ED65463C672FF360E0104F58A79D7C399F058A9C6BC6298AE226E06F294787A1BB
+0EF6E1AEF499BEE46F2AD81296667E2896098DC7535E1415E7BC0C3844E308807AD7E5ED
+59EFB26E2E6E5FA00B7CB6B1A160DB111AA0072ECB249F30A29643BE8F51276A0DA7ECA6
+03136C0147C73658D218BAD2A6DD880C62186178E527901CA62511326630815850E0F4B3
+7D3EF6B96BACDC9EAE70FDCE411297A167780F749BF79652EC2BDD4E620CFB45B8AA9AC7
+9BFDDF782E3B3A6FA9A0B20F8CD7362AE18479685828245B6069F437171A4678C6C1547B
+5E4E998C8835104327C75298AB50A6A0D2ECFCA02D466C08669A93BDCD3BB186F04770DC
+6AB7C774D2258C4E8C54D56C4EC2FE59EB24697C8BACB485E4DC203630B052FE09D83C97
+781AAA7CDDDD22804591A689B563D318FF5D269ABFD3278C345F6028127C672C3D3D8168
+5739CD11FF84E88C3BF219A41AC1C1272BE1D130A8D01EC18A83906CBC0E02FB4F430026
+5FC5E19B6A5BF67379EA2AD989A1BE64B8BC230CCE5E6782514D465C736B904F42D18417
+EF0A985121A8B155C06E1D0ED8BB3EE89226D931C9A8A0F5E80882DA98C72E346DEA25CA
+C3962B6C5879B6AEA1F91DE7FFF9453F98FF1FB2805B21994C0DB8DCCB8872273BD7D964
+EBA87F2FFBC46DB4FB8FDDB5840A162CD6F6BAF0377B43E5DC9DF9054B1AF843D5A4A38A
+481EB2DCF93C088FB019F8209BDD37502B8190281BA5F0A91171AE14E313617E74B751AC
+AB74070193E0F231497C20484851F0182889D77581BBE0B1539663F844854D59F93CB6EB
+A5CC3D2B3FCCF8D6C3758F5F333033513DB561A9E318F599797BCF0FC43391DD600A91F0
+B478A983687DADDCF974419A58F98338D9FEF2036373B5CAE2CCBC0169413BEE50EA39E0
+AA6E922F751B981FCBAA8702428C7FEEC0BAA712989D5F1CB3692F5EE3A014F716D42CB1
+42FA136A7ED845F781C18C1ECA0B6B10699AFDE08BA05393E413BFCA01C7A097933F87CE
+45D7A7339F2793483DFB43A26B277C5B5D5A3A51CDDD80D0D6C1FA7D16E03DA0F7D86E50
+85D4516BEB44D0AA911A7945B244CD4A83FEC04985877D15CAB67EC734B1749D837AAE24
+1832A1B555172307301CF5D25EF9DB48B9BB1979893FF637A3C3A86A6D1688F0B45A411E
+C8C02AEFA1764F5BB2423707FAE1439295E75E365785FE9B9E5C485779D124604AA59F95
+B8A4025E3D8246CE7AEB3F659B0309C77B6D10FDB120F6A4DF76EE00EF3607EF9D22EBAD
+0DBA789B86339482B98F91CB29598365A5E735EA4B7AB18AE1AA8AB8BFCB207C558BDEE6
+F6865D10C8B3487D342C1F6E74CC0B13B522BC054AD4EA9EDAEA215359465BB97CEB6F7C
+657ABE5577BCDBA7DD3A61B2C99F552BB70479328AD21F95C8A1F98D019CB23B6EED8808
+658742B1AF408ECF70B36ACCD4F06E4D160EA52DEF62E9CED463FB758C6121724B6E31A3
+A097A7D21B0D5A021B28FC000C68F6A4126A5418EB129AA699D04482EEBE82AFE18A7D3D
+0608E71F5899272A4E614E34005578746F6A9D082E29E2F03EF54E9F55D393AD28477E27
+C780AC02449FDFE3314490520FEBA7B38A16E94A302569CFF6958FCDC79561F3F93FC71E
+14E780E4F1E9DA30A9B1CFF569368069B140F5B8E67EDA15D0F25404A32362327A0FEE9F
+9AE430D517AA8465C72E9490C31153E3528F08843A100BEC4D4BFB6C5E87CA088D4D4C18
+2E398D02AD5D8007CA369A83881AC0C886E72D91A48EC085002017066262AD81925B365B
+7E594F3DF58C55A9DD737F2069BF951DB68720AA4043BD6F039AB927F7149DDB7830AC67
+293A70B6906135DFF159B352BE8AE55F1D03AB3BF5642CE1B1A49F773FFA1FBFCFFF851B
+3DA54CC2A5BCC6C2EB2BC5CD41676EB08B727526CBC01FC9C7A076A5342BAABD5341B6B7
+3ED8A27013ECA0861430BE51B07CED3522A6031EE04E74F985F10D3776A206BBA86FD199
+64B37F1A8998F4BCD2599A891C5A61C131B23D29788719C15728644886443D12492C87ED
+8EDFEC9C5620F7AE2C5CAA568333C26C8866A2E2651408D2BA3B40B68875FE271283A331
+F8EACD13FAED2342A5A3A74A1E76B74283898D8B265E0FC9CD3597CFE85FB55B56AC02A7
+55298DAC4A7471FE68872B311B690E5BC0AFCAFC4CD7EBB5326E453BB07A94843935CB49
+095EE8C7AB1BDFB71011CE6A8AB7F51363DCB97AF77C5C1CF0996F7F1A33BA929E9D32F3
+FABF10FF45E9E53A4A80B808548BF1D70383418B57C986341796FC5E1309EED60AD85476
+A7FE1AB5AE38258D917F267ADA978D02FA7F44200954F8230FEAABC0D7ED444864C91AE4
+4D6BFCB7E09DB0014B6E11FE753C6CF12592156B7946465D1D51C8FDFF1671B9DF64FD18
+0680EBDFE37D5B19B60BAF8A1081C8107C0C207941025CCBADF11423B7F09356B7D2B25E
+3C8386FA4F41617DE67D7BE0C3790F853CDCDF996CAE79A0D0113AE8293426662D18E2F2
+92452A9F2D9B3845FC5B9ED4088DB9CC86886D82FE7310F2A158BD57739A0A1C36A7EF21
+6167ADE2542E5124FDD3143D353122182A9AA36A530C96AEFA8ADACF50A5B0266B59E396
+AEA8DF4FBB2AD02EBF24B49D4BEBEA6F1555B5515FE3052CCE0C540D20A82D6EAEA1196D
+5A2C029DFC79E48CE0448F7A9FD83C7F107B40E55383E9656321497CB2742756FBDC2646
+A850AFBB90C1573979B32A29CD3E1C7A3350C9E1727E884CA842E9C60601092595D44011
+BB4F24E8A505EEB5397445011750A059265CF4212B4A5EACF7CEF1E922722B365987886E
+481215C980DAA2114E03DCC02D1BF8B29098F54733B3090E4DCFF294E01915AF5AA3889A
+99F6656F8BB7DBB5844EE7A9FA0FDB8AE67A2634BCFF57B248772F9B5F2E9CF95410060E
+22C51E6437EE48FECCF819B1655F052CE6C6EF2175A54652EBC6C38F7BF60799733741CB
+D7E030198D32B9956AE908436200C6EFF6611568EF351402A3EF854B0736390F7A16B7A1
+50EDD6E39B2E0D42439FD75C1D0311C8C45138AEE49A7DA2F742AE3C21E19F6ABD62198B
+6DC17A3A315AA746961425A18051A0C0C5653D40F9A6D3A542F430DFE71ADAA74586FA56
+9EB935247FBF47098C4D85417C0A3C6E567F7A65B7C23C1060AFD086186E394896D1DE26
+9244085D469240E8391ECD7B219A887F01853AEF9A3191AE70D8D11FB13C7578348599D1
+95186180E4AA0C3419322A318487A712CCC0EE9954C87A6FF2FB447278EA942C101E925C
+95DF648D275C836F03A4D1FA85144C7D57622FAD6BEFDDDD7AE2E931D430E29885E83E81
+4C7DF4DFE157A423A163E1372999E34A0689EF8F66EAFA66BCE76DC6CD5F3317BC7801E7
+F090410D2AB40B640777C30476CF9BD7446A9860594FEA131D308D9AEF8F96B7B8731ADB
+CAAA0FB8585DBBE770852E8A76A43FDF93FE9566F81A02C2AAB4014CD74CFC1682F33686
+418EE5FB80C2DC2A155F16292FB6B5C35B230038A91814B625EBEC0089B75E7F3019490C
+32BE5B78620FEC427B756A3A8085E42ED93304D80108A5D957E479933173EDF77913E5AB
+C5B84133CF6B09FEAAC3A41068883696A3E2FAA73FD401E4A5E58F3F7258207159970234
+FD586D1C34EAE89F2213B28F3597EEE1C0D11CA93310C8A294C88119600944A539795B41
+E332CFAC0E578B7E9E9CDB291FAC7B0CA3C125FD3D783E4D955DA04AF2EA8B5C97869104
+84FB27D05B95C8C8FA91C84AD9BE171106D0AF6AF582343250BA953452E1237EFB0142AE
+5837EBB076D5C7B6F25AF4625465CC89B27977E6CB71AD1D4058AA871CF3FC749BC4B87D
+D7F75D3D18E455C67705EBD876D9073D828D4D083ECD7925822732C07E1581B1FCE4A337
+EC7644EAFEE206C62C1A64E10F0F1603CFC09C98FC36E61A59E9DF4C1D410BA2B775C44E
+91001A452798FFD0954AD15D9D20823B52740716F40354E503816CDF0EDD7B6B97879260
+1204972E0B4F8E783317388D31B2DAD3132653A0585F9EF80BA68093A79B773836CD6E62
+CEF409A9A4007D3D7760167F0719F5A12DACD27BF8E0903C75A2BF680048538EF924B616
+FADD681B2E850B2C6AF69E86C491CCB41F8F9FB000F76155B651133D09135EDE439B6A99
+D4B35A49E2AF4F82A369ADAA500C873732664D50879258A9C663196BC29FBBAF20A7FC9E
+7DC8904DB9536C92E45F958AD46C067DEFC27FDCB71A7A1E2391FA6B6306B71ADBF3D6EB
+1544F077E38D93C9ED11B2CE62D3E94064FE75DBA762BADF76E071BCC5507244670FAF79
+F5B0E11CD72FDF68DDD6C03E6D42E4D505F88554662BCD0CB4F5A0A33CAE7BF80854E715
+8B4E020F2D7517F8B5AAE67675E7518C6A14F00938F36E23DA2172719B351F0A19CE3691
+12DB35771C4EC37F61669D570932E14B82E3B419ADBF6D0E201587E0DC75A1DEE6262DC2
+6EFB9A02174CE7C7BA8E626ED0BB8732AA3618909F69F2D4147F3018494E22ABDC63C89E
+DFEE86E6B21DA05163A32415E6142528918A6936F05948C14B2E34FB4694D5F664AA766C
+5FEFBBA0F344FFA065F5394F621DB9E6427EA543BBAAF77515D7EEFC5186ED5F9EC74A97
+FD1663195D941CD67C91A5217C8D5C7F1BB848C6A3BD03A2BE6A48C1B2E8BE247D02C01D
+B04A994F207D25D5FC46939095986DDDE77FCBF9698D3748D12888D33A7E429AE13C8194
+D624AE196D2F1F384F2B31801B2C3FF3217046A5E11890FE1D63DB4159CFAC405D657BA4
+E47734669D01E953B6702B972981C08A0B028F5655F7C8BD1DDFE145BA1D57129CB9D5E1
+8996C0A0E01285E799F4753CA5879F862A765B6927D7AE8FB474E8169708E1D30E2780A4
+F6893E46DA3F20CBA50BC6B8A310A9BB06713EB126961C97A9F2A4393D663E078026657C
+AAC7E6C723215F0FBE58AF074418AE70EC0E710C97A1CF4A0FF853A8051F18BF4AA7DA5D
+5B52CE39EB779B75843F14E7736363EB213F3DA581741C7D21D8DC268063C46E97FB0B2F
+B525AEC2C6F2D25E0EC43F91225719B4087A92D3A44DF7B5333C64B92862755D5D9566C7
+FFAA3554AB50821AF913213B8738D8FBEB7CF5BDC7E8F191EB3B66A8AC1DD9EF0D5FB967
+B9B1833D8C67F0B6AB2A32F00D20FA51E841BFA6ED035779536EB6EEB30CB751C81D7270
+FF877E2A0EB624FC8CB8D40830B9FE2762FDA8F5A861A0006CE1397598A712DEB751647A
+2E5AA196BD31465961D4CFB2F9E8C5C20BE1C92592B3E457CDD05B11DCEF03127B494B8E
+4AAE645ED3D891973EE5D633A24B19B06B0F2389FD5ECE0FC1C5091B8334209AC3DE128F
+8772D373142113CD296AE0DE58B844496A70FBBC89C09629E095EB1E36DB8E73155735C6
+A4029C1CB8D935F3B563F68AFB6D1DE6D40A59A1F7092466355C7C1A5C3792353FC4A598
+73E5DB876C029895CC933DA80DC11368BB19DEA413FAF2F7652AC6A18ADD92A7D647883A
+4201773313B677A7A1D0F4985FC8714CD9632C8266BF7317E557E79CE1EAFF26C5E19F95
+698799264FC251C8382158ED39E613F3BE87660A5F1F2C6F7D9EC08A901E4800463E6498
+65F2FCFAB56F971730824AED3970830FDF3E57802A4CE2DF1EC509522D0FF75EE464A502
+D77A0E9095DEAA555B6EAB3506F2B13B817B60AA418891969AB75873FB0553874048C1F0
+0A9C61105A9215572B1343571CD14FF0AFA30B040AA95AF309F412692288FF9D941CB245
+5B8FE672B4E78D6FDD3AD9EFBE0EAC354C7AD246456CE0C8166441D72762B6518B6EA8F3
+15898649D17F406FC07C50F87F04C9DC12284D655F3A4A14A3D55E80E2D3D054828CE8A4
+2E33D9963903C2BD11AC757687014D2DED8D1238BEBB7260A96D973B062ECE3D429BEF7B
+63B4394A2B1DE4F56D0729A7956030F8757762F13A90E211B7B245F3E968446F5AB19621
+5C0A0F6F13957C0584357FB760C68D41A89049B5FFC42A021B1AE9217BCFFFF0063877C9
+4E884FF624D80BFE56F79CA93EBD70844BD30D51D57E19634287881CEFF135EC18ED3873
+596C7C9656B31BE31655F2630934492EE1FC3E44B9607F1AD8F4E162C356A1383AE4E797
+0D2FD92A69282CD16663B2B9D199702FD3CA9B6CC7FB12A7A0C2713B3F5E81F844BEEB2D
+F3EE1F31BB05BF57377B9356B776D84711164A49AD69C338D8AA3EAC2F616E735E5677FB
+D54A8140DBA442BFC8CE397B2F7F200E9B8AE8417733F90B2ABD1C70F81259D944090B92
+845767E935B2BB7D5181EF5B3D50FC31585BAC37CFA267B966DE999D3B40B2023F132ED9
+C72F827C28D41751D67B98ED61FE3E611A4AD1AB2C45F303677C79A49F774F710004E604
+0AE91BEFC6C8DB58218637DE4923CDB315E941E5E124AFED06CBD0B75484B7B9DB3179FC
+5759BCE19BE50D07541DDEDF00C0BFCB084FD3BDD10C4EEC22DB607D65C29A6D78178AC5
+AEF0CB466EAE31EEBFC7B25B2AE157C69BC0747EA3222297F4DD937E1523B9864B62A666
+A4ABB9B4B3A908DA0C37059E847AC1405D2E4246A3CB9AD3B39BF3BEF16D48F769B69422
+7D6743C49F6DBCBA1113DF16B64272848F092C34103B40DC3118AF1CAB1E743BE858404C
+3A9831ACE27D3DE50EC75F982D9DC1B6E34BC678A07D214B0A22AA146AB298647927FA54
+222DA2AE878C8A0FCFDCBF90A76CCE2D6CD623818121598C31D0485C900827C91AB17ED8
+3DEE367788418FA250F9841DEBBC95114D82CFF93E8C6164C65CED77D5DDAB4F65FDF19A
+26FDF57FC3AFB4F4D155B1AF747A668724F1E2FBCAB941987A17D4B455A74F4E5DB5BD62
+496B197DF439701DD993EB50F92D161ED2E37170EE2D1DFA169C2AA43752C765FAA87107
+3DE44D8BAA93E6511DC365B68157C81C8F3DAC8C624E58EB22CEEB668A058E23F3DAA93A
+D05C5B1DF3DB0C88D6FD40113A851F1387E9E2EBD2460EB7FB642BDF4CEDF1B22DBC51B4
+2DD058AEF2CB32B20A30F1948A363458FE07B146012FC3842DE485E687408187A89B93E5
+FFBE019CEE53E8A46C3BD54D12D35DD09D638B7033F0E8B48CC29FC898128F2359AEF423
+192C75DFE9EFD8FB5CD2ACD71811F5B8BA259E9F4179CB1385F85C9B1CEDE79C47ABE400
+0ED992A100198FFBFA4ED40B9B55FD2053DC49A2ADCFF0D18FBF9964BB2976D676FE54E5
+5051BF7FE08C5C70E8AB9A363F98DF09D22AFCFC8290E828CFA5E965574043B310D9A570
+98EC92E2876DDADC2AB52B05564EEF2A64AE2327DBD80795618500D96F296E178CEB3042
+F1BC49CD8112A5A373D6A72A8248DF6D682245A134FCB990F9FAB1CFEE41DCCAB9CCA831
+2B833D6D21BDE04BB26F445093A8C7334F58F3B0FE626C0832DB7BE2EE788357695F3B49
+FDF2B8225E7ABB6FF7A51EA4F03F3F4CA1BE00F70D74416FFAC47C4A8480D12FDBDF2450
+5D53A882988C5747FD8729FFD263C88749AAD3FB70B064AF33BD21630FD5853FC8EEBC7D
+91CF02EAD8C57CE136A4B223AF4BAF7D7C08BF31F1718318BBFA9D416594EBC59E8D0BF1
+A2AC0249835FC1C274065D9A28D0B8D751B9677FBE7D970771A8FD96700F00A13AF76158
+AB7437F5EC667D32D8287ECB8A1794383896EA4BD9AE047EBE471A9500E94C3B9EDD0AD8
+24C9D9DAFD1F058929D21244D81A276712454324322A3CFE36FE1CD8172F502F427322F8
+FC8ABF150BF749B132A9E93FCD99AE015F1D75D923F9743C23F0F2264ADE0BD0AA7C1C8A
+4BDDEDE18EBA55BBC33B3C9E9204B1418D7B1CF592A5707805C13D62C284B991C817B643
+00FAB2E0457E59E07CAEBDEA55F1D8FC9F6938509E1A11168539B92705BCC03115D29137
+45D24D1533D6988DBDC21795FB59E25850B74A265C47FF6F7A548066FA6203C503BE4E7E
+1590689F1A4F73B7B39AD4ED10D89ADA19673655EBE215CADBA0FBD85DF65326ADDA0305
+FFF9BE785E52F0797A345F8A49A58A704106EB220F88F27180B3630AA358BBEE6E27908D
+512882ED69166A628B32F06FF47D9D05214A4C8728305DF287A48150F2652EFCB1B7CB95
+AD2746D2F4C10847800E9EBEF69188B770D583A079C79DA8D7FD9349E925E9A9A30F2D8B
+35EE7115158B3B353AD7E4E4E740D93289F2CDBE6A75E6BCC8A0A3221CCE578D3A974521
+9C418768B4E332783174173ACAAC86FB61F81DCABA0F46FD3B90D46BBD8F6469C30DA380
+A5A356499394FD428F7DA46DABF232202A8A293B2DA79B4933D0790630A57DDB232E9E25
+4DA8C370F1B3EBBF9182C71EA3BB243DA9685B9B8C1DC22D73B3BE40AE56B08716D1F035
+586556DC0DFC07AAA66F5B3084B7BF87D0AF89BC6AF8CE1CB73B56A39515D44DFADEF15C
+E018E31E7B4C61B109A6E105505AB97FB8CD2E53D37BAA3B1C2EC25DB055D87245A8BE47
+94A6E03B71A5F1D13B6E5A7E6C5594CAFC6E303CCC61E01516262F9BCAC1B745EE5B2AA8
+C0E8209C20A1EF19E93222C31B95E4B4FCD0F78F7821FE995494A98BD756FE546700A590
+FFB496FF6852E53470E1A5AB253464BDC12CFF3B5DACF8EBB0B99E822322F21999337A6E
+5E849866939D87B2F16DA93B9F8CA7C83BDC49A4F8C5EA64E8F8A1C00E0BEA534C499C84
+4F39E38A06EAA1102A1DFC0E25643EF8A6245427D8E77EA2AC7B352463671EB6DE8571A3
+84D98E1B35C3213F13132FE76D03AA87E5918FE48CBCB8A2F3EA9B1886BB540095D97BD6
+188DA701888410081B8BF49C7043BD8C48E18A51042E92B542176964E292BEAA06E310C7
+FDBFB496D6B7BA5B07A1D36D516EC19C37E1DD06B9F6F85BF740D26FD0DFC09ABC3D4A11
+CEEC922B651C147BDC3124DECBABCC8986F5D48556CCC5AF38F7EAAED9D719B983DE7742
+67F8CEB3302B8CCA7DB832794C3C4F0156E72BED47BFA0F7E4B25E13C0222584601BA304
+FE38C5E96D3B5E709B6F5FBC623FC9BC36A4C4E8D82452D260F13186EBA95EE4DB5D4ACC
+945D0A3C5C1800C1D3198D509F7B8ED0A0E33612E25B9344F1D53CD949CF9F65463B7C58
+4E12D78D3E6CF003F9A4185A37ABC6D5BD7F331CCC01540452A36524DBB34EC2FA260C07
+824D76439B0059A8127F940EFC1FF165005123C6B43C9700034D5AB9C7FA1AB62E9FD91D
+ABDE5F3D5C03A771B0554ABE655545E133AB8C230517D51830492F29E86963AA55E9B79D
+79013BB52D623E660A4D356C293233B79E7263ECE8F8B6EB3E56C82C2051111F49D45D12
+5148AB7554D601BEAA3037CDC84ABA8825658A09C008D19163FE5FD06D56D1A687EBB6CB
+1C9812EE0E765F14077116182F67D3006048F8BE549CC71A354048520E66860A0D9350A8
+864ACEF55EF91E17EFEAB4D6266C9BAA1D6D3D309073C9DE287BC0619D7E37EAAC4B7CDA
+D320D993B7B8F387FB039AA7E1F84AEF034E7845A1B1B5306AD8FDA2834B59F18E6F1A09
+66221CD9531258458E428EA237FCC45BCBB9C5DDE72061FEF2FDE731706A4C92E5B0B255
+49F60FD845C45D940B4C5A4F38740A40DA356A56B8D155477C04A26B747941180F6EEC05
+A5BA892A0D8E4638A812BC405E2775EC3A2D0E3C288D0DEBFF53582FCEAC6936C152B8F7
+6F9D556F2474BF5ACE2B63550FB94C36E29A8501CAA4C22FDCF908C62012639ACAA7619F
+01BF96A552A662DB5664E1DB1A4FDC4E5E9050088D730C8E1F387CBF93619952DD8E23B1
+4A385AC6C222AEB44127DA14539A079EB16991F0CA2D851467828C23A4D524CD5AD92FF8
+0439F6F47D703E9BBAE227628420C2DE818A9D2A6BF085B5262E026C7A04ABE831065F31
+68772805AAA986AD811CB78F3FF8A0FA7A211127BDDA087C1459520F9420CB06AA4518BA
+A8935A97BB88A62EC76AB2990D8D414392E31C68A91E9DA122ADC8AF3BF4CE550CB1D22E
+B2DC916E735D19215C489BD7B62B842970214B0D809639706303AE7CA8E270ECE748D283
+A8370B4F6A37092EC768426FDAEADFADF8598591AFE55984ECAAD3177973A78EAD02CBC3
+F7DB13A7864EC1E7A68ECC54EDE88E7A62A4AEFA9DB238BAF1A22079F23930CBF7CBE82C
+2B98E37F28A47054BD47B48637179F4C57164B26F4EE0B484FC8692AADB29EA0C770C789
+8FDC78DD58B009B4901A678305A0DA4E89B2152A596E13FAAA822DDEFCAA30BD2FFBB1A3
+5DC54BEB87BF96E4C3D25334D86761D7D78C50D71DD13BEC2830A96761CBDDBFADED0A3B
+6A0EFC34F96CF540E238410D22EE85AFD0AF104A624D3F9EE5F04D9D8805D7BB502E0223
+AFD0CE95C2B32B30030AC7385BC898C282A5EA204957853640D4BF963C97540744F4D888
+72006B2239C9EB3390FE16B4C3415F6EC97827597FF791B3D1B3BEE6D0329604ADD0C131
+6B24B8544ABAD72B337F00B8FE300BB4EC7372EFE3AC8156328238B94E66E1EC7CAEF9B4
+D58DED07D9CC777719E2C973EDF779310890AF183F94254B2CA3277120A03222FAD58E4A
+ED28AAB3DA49B5ACF246666A597BF2656CE2960FC95BC24CEAC5431F73074538B8715071
+FF284765EB54207CA22596B3BECAE73DFC68A4F9A287B8DE7DFC27D0F860771239436FB2
+587B07C1FCA6C74A020A819701431808AAB5B6291992D83DC28F2D943AD0DE2D94BEFBE8
+A15AFEB7057DD4A97B4C172CCCDB490E6F9FC265636A35A2DC556648B5F9F80D180FA320
+AC69A0A61A3954BCAD612FABC12D486A0F2FF0457073F61F2A74345B1ECA9DEDCF26EAD8
+D02D3F4678C7AA82907721A828984C6196464440B2255DB9171706819E0BCB7169EB6722
+912EBFDC6CD488FA34A5556F28D2B448A7187B1E15255202DC9DE4F609682B0B6D2F61E0
+4EFEF15CAE39FD3F6F7B32F226C759A17E6C611BBA79D93186C853BD59D73B19E514D770
+89CE29127F5B36F1C0D661597A6FBF85C15307F624630DB6564BC755145BD19088CBA598
+86B29328DA2452957E306EE08CD942AD6FE6697231EB43DBD8D37B4ADD0B4D8947A057B2
+1D9A133A7DEEB89C1D35B3F49F803700CAE8774A4F9BFD45CE309A4342E3B7DC36B6F76A
+7B51A81B70E038E3E4999D6EE027DECBCA548FB5F4DE4C49981D4617133BB3E0919C4778
+B80894FF4437120F1035520C75F882591EFD511B6F47C166C7663EA2DEEE335DB1A3106A
+5FE0C49565C2AAA0BE977DB611B07D38DC41E6DB8F959798286DC0CE835CE64459558D4A
+20DF59F2E8A63E2DB701619617CE4DD55E82EB396D5D701B691533D0B20C3A0C20F5054F
+72EDE3BDC2393ECED94EC52C25A755B58F4E2596702FCA68B64DC554DAC85CFD99478701
+BBF2A47966CF72E683B5934F0EA5DD86F35B1556026AF02BCADE75ED3C579CC1D9430956
+9A53EB8ACBBA2551B9BF06594F66229489319F5A5A94E51281FEF7BE86AF12D8A8A1CF43
+04ACD3B27D6B9A574F09E2C41D245D8873A78D1CDDF4CC88D96D9F714FEDE70ACA30B83A
+797AD3DDA7D6E52A5AF906CAC560813DB2226BA5BBEA60932640ACEAA2E7B2D412068A2E
+49FE781E2544FDF8C762D947871EAA0DCFC183676B5644AE02DB3CAFABFF140BBF755966
+C9BD319925746E320AFD5B157C55E3EDB4D0DC3FA112964D68BE2A5FF08E8B31BC9E510A
+F6CAAFE84C0A103117913E2C9ED8FEFF96B941AC14AE07B1CEE2308E36F617DC33CCF32D
+3A52F4F6561A784FF2C1144625133FA8E30F7A86E82F675F1EB56579077EF6AE086BC2C0
+B389CDB5C5999A1FF3E51BF766227A03DEFF391312065305E5C3BFA97FE7D5E2ABD0AA7F
+609D8A0E524F99B416172F7A0D174196FB411F79A7CA6F8694DF4F5DC48BB58F39460131
+D47167AF47DD3A6AF1E12C75D947F4C130BAA07174DC577B49726123F34FE9C76411FE62
+8E354B43A5F54BE0F210C7523BF018DB36CAD6DB8063F14FC3FD1B4B69706D45E615C3E2
+9F4E1FF8943FA55F1B9B4411BD0DFFA260664CACF3C2C3D9CEEDC1274B71805FEA88C3EC
+E5BBA17D17E6250494278450141FD4A514CE968C33093FE07E64F168388D141E52E46DFB
+1E2A9F4BB5132C1E6FE25245FBBB3B1CB7CF24FE6A134382F9863D4683AD93338D3A6726
+BAC2C4174FCF4A523453EA28F2095CC1159AE0E0927380C93DE4B979E26D56881A2647FE
+0C46D0B6B50B0CA3750D6974A8DE149E252ED68FE33B26E2F04F06FE6C3FEE1E7FD72C05
+135DA55508F10522A7A2D8AB07220E73283F978B50D75FF36E789094CBA1A8E342428B89
+3B9A664939AC711933A2A1C425291A9E95C396879EF54BB6F3DA82E88CA8C34E9CDC22F1
+BAF6588CD3C54DAF5A7873501EDA6A25B793F219D3D229F6A028D34A19A9ABEFF2AAE4B8
+E62A05421D9CC0F78E2709BEB6133A0708BC174F5D745A6CC53E6DEAD27A1E6CD77832E8
+87935BB8736AFA3736E4B4313D6D1B7EB464A02B0C6DC3BC7C84630C2E9DD020AF3F6694
+90BB8CF0185DF9239E0D27B20FBBA001DA7C30F0DAFC8AFBF45C02019E4AB0AAE458B083
+1051F65D0E398A75F52FC3D617A25CDC2EA1FACD7113E0EBA0262595AB5EF65C1D54CB71
+BD87CC35C9BB992E0A63ECB8A1448619148ADADB906DB75076E0DA42BC6501F6B6717C62
+71E3881CC2D6747D0A0BC7B6B982CDA89E2B9D9870C96A86D3A4E1FA0B04140131F302D4
+A36AB220399A6E551FB6051283E405556A1591E402FA9F04B87F1E3C2AD60DE3128EBAED
+2CCDAC808AA1CC5E64052FBCDC1EC710A3551B3AD6E21D20FB112543EE0DE94DED4DD8C8
+6526F470C83B1DB3536D6DD8C8E021B7A9A82C23A31A6F09E15BFBBEE0A8971B3F471437
+F0873BC669016F219A728510C712415C515D3AE02BAD8467A1E0D911448C0CB280C70F26
+14BC2E52782C1CE5E79C783BF880D1B914E44FAD64E140666274D68560DECA2194D70377
+4EC76B35669FAC269409712901F0D3555B60175AC7799E31CAB70D06EA8D9C359C9DB9B6
+A3E02F6923C498617C041C28CD7E57486569429C3E4C89944E0EB150813854E3C2EEC4D7
+37E2DBB99287ECE4279F3E0D9D8EEFED11867F0E05E40DB8858CFC5DDBE873A174D756EF
+5D5E0D5F251F0FC0BFA7F69EF8D20E34B1B3B5D45501DBDB453D82F56BC6271C281A8A1E
+7D0D8C9B920256EF07F4AAC8FE2189485089F52D024BE36045E0BE613F0FFFE13D223B0B
+2478A20B98E76A783A98E7AFC642AC9CB333D6D39AD4E08B2BDA75686951965AFEB5D211
+57CF3DC3B911A4E45144B3D9D4AA4CF13DA039CC95A9CC8DF44CF17F3D09A1823D65CD4B
+29E2408B1C3FC6C1F3980378E1098255136F0D4BF90D0C4C042F1C86D40BB762E72C7EE1
+BC530755416A0DAC2B3DA0E7BEEBE7AEA9A39825EDEBD6CA316FEBB14C701BB7EA4F7800
+3DF2462E2E429FFC3EE8904D963A0017A606EA0E526EFF1E60BF825B2ED9CB42678B6F6C
+E55A893A047A4E5E38F15349B777566334153DE574290C6043694C364A3CFFFD07180F5A
+44CD991A0535D13C91FA1134BC457A455022614F3AFAB921A70603C47C96B5E466942AE5
+83621BA1544F2AABC4CF7C6E8B77F52FE39F5798E2FB9F180E3C86ABAC210C57A0226E38
+75885E3572BD47BE016C361E84754FCE64AC3345393F511C99BBCD70443D497D575BD81A
+47373184CD09ECD9F4A55F1CB26E921A2B8BDDDBC8052EC0B8CC812CCC2353586B0451B4
+791EB68293CB3B4C41B46723D2F138D5BAA8AA4580A5660F0DD13F25BD665D4994908BBB
+74182C783EDA6C5187C32B7D5DDACE8DB1571E7061A063AA56DEE4B0B6F5544437417E0F
+5F07EEDA1263224E5E44B83CB057BF54725859FED215E5B528BEFCA470C8527F40A09AE0
+20CD42E31306D1E9095137CB6E7FA08191BBCD7176B87A372A97671B9CC090936EF7E4E7
+85F1C6B541387A701828AD82A958C34DBE426FB12A03AA3BA2C97535DA8526164DCC150B
+67442F7D6765D16EBE7FAF904F42A8185DD30DE284916705D3D8826DF1D37E668F9669BB
+343D3200509218C5F929E0DFAA7FE3B79646F62835C808BAC29CEF8CA6D8363F0AC7291F
+E45A85DF8F0B9FC14C7182170AB1F51D9D9C33D8D98713CBF0931063EA95EBB031904EC5
+7FA914B7D7B254C3B178E174F807269B2BE5F340A3674FC03D7550017B70C0E53472442B
+3FDD4D1D45437DBC5AD56D690D9098D9DCDB17AAE217F73B54BA5D965EE197EEC8823FE4
+783FB5A4693273C7142728AD3F78946C0A8B7D3714DEAFED570BA2A9DF9240B61ADA22AE
+3F9B21FD1D73D4A474EA14EBFE6AC82B068D08EA2988E7C610EA5097B62DBECEDA5278F7
+27824E5BA9EA442B328C3B02E03C88511DA9C72A271027176EAC2C7B6392E9E99D8B42E1
+2CDD9991E43099C503DA5FB60E5D4F8FD3CB67FFAF46A1DD243D9DF13116880E727A9271
+BB778126C01AF95B75137A0E3831BFF257CA37DE0B3B4DF3C983D091F09519365B2B812A
+0B6273D30B01515013C73AC3B8D9C4520B5267E734651E013B8002D09F3B5BA7984A588C
+F6115DC9EB84C1C9AA0CBC9777D8923B3230E0A2963E08743E51CDEEDE33F7DDB10AFF69
+BAC8682A2B0885B8059661599B805B9684010A3B6DA56E23E265BC209158D3ABC69BD6C7
+6B13BA17F225D990CF0A42C1A37A5EC523FD80E60DD542322B42202D77F646FE34DB9AD7
+9908DF03C1C5C351E542294D245E1098989BCBEEED311FC5E7C8ADD52E52BF6F0F1331DD
+7F874B30B0A16484EE328FEBB0CA559613500BFE6994EA8357ECAEDB310CEA3235A421E1
+85471BFDAA649E3CC9128A0409C454B3C951FFEFFE648F1ADAA14D5317929411AB7D78F2
+B888B63481346F415314E1967919783F8D143EC05B7BC2D5D9F7315F41F0331911FD0018
+44E301CEAC9579DC227E0DF9FE2D217AC8D7B014CCB01DE9AE852AD42FAEF07CD5CAACAC
+324F3C00E330939FF4B5B677DA731FF712A6F8A10687D29A296B0E685A4F52F3009A4608
+8A935788703C71B584A8E855683278077851E1416171568CA50BCB4EBC8DE6C952FEC45D
+37FC6EA2EE7E151A96452C332221961EAED2B6262431C4C7BFFDD59EAEB9E3DBB17C3EB7
+3D90F0F872289F8AC482B4913C0A05E698C91682C37503A38C841C25A8BA855E7C1CD3EF
+5F1E025E58B2EB4599D76DEF57A60CF24E814B3166042F8084B08711D1C68DA4110BFA7D
+E8D3FBBEB3DE32CD01E237A403F8581AC2A015106AD81FA0DF90301D6BD887631A83623B
+4EEEBFEEDA012BD6C504B450A5F43137757C2EC7DB3662748B105F8B22EC030895E0F607
+5BBBF246422A7D0D6E8953CA66170A8947034CD6EE37EB7BBD0D9F02A538AA0F3D2D2076
+8C307F9558765FA715444282C823FFA3E95640778053A383886551D4F86D490FC156636E
+A5A3BD258674262202F4F76746ADD02FE0DCCD540EBD60EAB42D01FE252DBEC93598D6E2
+0312F2F4704AB003FF956FDA5C2A88F716A4EEC93503FA913CA019456AD0A8F6368CF6E5
+AD1B7CE1BB20BF0CB453379DEB3423B0649A6380ED7D0B40768730D37A9A98B2339852AA
+286809BC86757FAF3DD54C18C3CDE9E72FA874BE9D82655E0551DAF13FD665BD14DC7891
+12FCA109A1C73D4B0A7F230E2F9512D0DDC8029983A1984406A5F100567B88BA186329B5
+7A68539D43F67BE6263EFA278181688FA595ED3BC7C7483C4DCDDFFC01E641C231EBD842
+D21B48105397FC32D6A8D555015760029C2CAB13AC8D603CABF46867CABA01A99B95C92C
+3C224E8F59B3B327A01AE685ACFE6D67F28FA6663F6E47466DD0A6665592546D08AB7C5C
+EFD20D6D5115C775E033E0DAC75F2C6411D999DFB21172A8D0D3E427F768CF7535320DBB
+6053BF3A17536AF6B2C00979FED18A593F71146F9DEA8B31639AE0586B24763DF3469507
+3D1172972B5E1CB82BC46A60ACB82FC66B05D9228C67F3FB25E2D91FD11B696C9FE505CB
+9BD2B2D85D3A22595C338574978048050FD13A59C41B3B0CC2868DE4E017B53935793DAA
+3F6DABDA50B06F8141511C3D5093069CD1ECADB90C42431B5188D912A5DF033B633AB3EE
+67E4943935EA094071001B6F8FDFA00C0E8415358DDA77F2DDF4F7E2694CA6933C804849
+54A1DB8B5B6FE3A7A970DAFDDD1107FBC4C596C379881A6B148D21733CB2700FD9F4FDAA
+6DC49C40A6675C0284FB931AB93CFDE9A94FFC23BF259230AE1724F22485864833541367
+D274CE18EC890E4376F48144950FBE566FD285330486F5F23BAD7AF0A636821A122A4970
+35D77B580B5862D776826AA3735AEAE9D5D7D04C4582778F9B0F713A906618632FB653EF
+4FEA9BD993D11E0E51FF3A3DD50EFB462C4251A42D63863256FC819037BE597382C6BE60
+955D060340A268DCDA514793C845FF10EF0C72D6FF27BD1858B49D50516D48D6FD33AF71
+11CD37F5F7F0C4A4508BE16B80565557D025B529ABDAA2850E4EB6D8AA30ECF49B5D18CA
+AB0BE944E0B95AA0BBE9F4CA91A56FBD41983A6703FA0FE415171CE8C11AF45004FAC49A
+4346C206EBF58FFA74F22D21A1E069AC9DEBE6D36156C32E74A4ECD8BE2C0A6983D404C1
+07DE0A75C732AEA64C88389E15D474F8C0E7789B8707E2F46297012F4F51D07A10794D03
+195654BE0F7DF9A4F5F102C5A68CD37D129051620F807301FC8BD8252B4CEEE5EF78E803
+9D41B48CD3262419E9A4F93B678B9F471F4B221E7D165C1D2980CACA79F4E549D2ED61B5
+02E583516547A49E2804F1149855D77A0D86F3B1B429C56523FA773FA9452CD5B6340E64
+B04FDAE2E5B6B234D03E87E2FD39AFA134265000F7A9506F55505874D0B584C504DCD29E
+CCCB8D71485AEC7BC34AB30453AE4E3B2720CBEB6A9C9FDD7FE7DD565902C6BF2118DA3E
+95595C12A7744212827DF07AC5AA7B1E05D42FF38758A3C3105C5F0422030BB0102A9BEE
+0E07E20AA089C118908BD7207E686EDC8FEC0580F7FDD106F202676424FE815EAB287182
+61FDE8A17F2662BDC02C0E109A020C57C8F37C4B606FA2AFB8C0993E2CD1A91AE5BBF801
+390AB8EB8841FEB2B066F565E497DECCC37DFDC2581DA9AE15E8C215DC41FC92AEB57757
+E92E18FBFE36E0E6AF6887671A9578C318C7FF50178B32CC9A046370946ABBE792708330
+D1C370012CFA2BF4A5DF75CF019ABD1882566333B0E637B9935426FB127699885121D83A
+4DB8A43A648A459C83D623EFDF5A60F11ADD585EFF0579C91F8B5ACBE889D4993BA6FCBD
+64318022C3310DB5CE4324954D78F06ACAA1FA4C8C4120DD41DC4EE2CCA72CA36FCC368C
+A31323A17E4CFB07A0A02CA23F8518CE8ACE1548FD4B67F0A5C414C309DEE52E5327E09F
+4B2A07EDAD8A309C54DBCFE3A59B9BFD3174BED78566F6642916B5B01CF4DDABF72BAB82
+60EB5945BFD987B96B80DF607C64747F5344A27DCBF4EB9797BA5D17B7635D0D936833F5
+0AD01CF4B9FFC273C05AD87745D79BA436590D9B50988311A06EAF7CE77B5492A542ED4D
+129DEF268D2BB87D07DA19ABA6D4F78874A0A6960C9934670B9EDC47102EF929581A8698
+A9CD8F43E4F071577730D9D18AC416AB398124D9EBB91AB66A4CADBEDE5043EDF627CC88
+C68DED934ECCABBB9A7FC34DFB1B65ADD724BA67DAAEEBD04679816733D344635D997125
+7B2BA27D1F44A7D7E48F9C9A4A412030AF12FB89B15B07C3B18F9C6EB6AFED69D6A9951C
+3C1563481B46E4AE5841D88BF8C64461CEE73A332AA07C89414B4380D0CFAD8D61C72E68
+6B34B0EA660EE0C8370A99398D9B0166F8A77FF24BE1AD496B0C0E8ED04734527A5A8C79
+64F2568C9B00E98F7165D0594080DFFF7CE5FF8C26097FAFEEE33307E282858726E675C2
+4B4C31AD2B5B1B855B73D553E77D3320E4D88BEFAB426B94EA33FC9AD8FA81B6636CD4BF
+FC2D11BD1F52BC5BAA38C072AB771A9A107554A327EA10452F9C7624BC2DCD6DE2D43EB7
+0298DE357909FF66BE487285902388A024E120D587890FECE3A00376884947E1E6334BBD
+79B4774980E8A110E7BB841F9289805FEED0DA0F4D4B8048F190DE68517EF34963FA1BC8
+F8C575012E01C280B647902BBC2B80365E9A66E28EC8698EAC50CFDF1C6D113827AFEB9A
+45434209C921460BFF483BE373CAD65640FB3A8B7E5AC12CEAEDD5EE1B244FC42CCE85FE
+4D34FB21BEF3EA9B959B6DB1624F05ACA4602052A78FF842BB1148ED529A460DCEFDAE01
+6A10B5B3C9D11ABD14C53020138A9624F0DFC3B1E445290EDCD7F2DBF4BE408EA8EC21D4
+4D9DB728B76DA63AF62EB7F89DC43144028D1098287566586F195B124B89799E3881AE23
+F89DD6610230B09D6B8BDE79BA206B87BCBC18DBE1BC155862D28CD742C38DF8CC906233
+09F933D073491984DA9D927635800B84A1C2350CD18D962DC9A2A235E2443F5EA72DA9F6
+45BE3240B03AB4D9D95C3B57CA05FE3A7011E12B182AAD81B426BB17D44D5C1EB10959DA
+01563CA2260F6010ED7D37609ACF759EDF8C044860FBE3C89213394F03A309C04EE231EB
+FD84191ECF14A020C7A4D7BF855213D927DBD921E2324BBABA6B7A06D69B4271C66F4FC7
+F15DD52ECEEB76C4C97A85CD59A38E1CDEE2F78354B0B71155227553FBBAE0EBF0D625EA
+34B78125DABA3211CA9CF1D4AFA909080061588AF14CB97BC4DCC1E1A0BC04A40B107318
+1CAB643F064192A6074D3220EE050DE3A56D1558AC0F7DA0E2844EB48999EE9409F0F683
+92569D7E7DE78F070FA44C2E8ECDB09578598508EF3B97FA2B585A163EB540F2E8290244
+D60006EF558A5CCCB1D40CDED1CCEBD665A320CB82797F38DE80CF0DA15BB0E13B8CC180
+9D99437A5B25041EF68916C6E601B0432A2DB84C8DE1EBE4AD5A3EE34249E47CDA593424
+7C9E3F3251C59AEEB48BE773A6D775E6723F3B2AA55B2439CF841E1C729153B22550BD91
+F272DFD3EAA1336E94C8AEE4DEAA00C772BF05FFBE35BDE7AE2A0EAFC33A71DEC72B3179
+E4CE0DBFC083372451A7006B32357B94CD7975ADF21D5977D10444C80257874005F8A02D
+317CA3C38DD0F156F191F88A8BCFE274976220F0D25BA30DC195F5AC0CA478FC1173A7CD
+2A93B482916358E8B0ACEC25E51F975E210C895E1200FF2D29419EC300BB8284EACA5027
+69676CFA8099A110D1AA50B5A4523CBAF5FEEE90B605C5CADDFE233D235E008667D7C0C8
+B2BBEE796F1F78F4819A201131D4399FF2CC2D59B05F923780E775A9ECC284A68A2D76E3
+65E687530B96FC564DD173613D190EE8F1E6BAFC238FD9642D356E764860855820937E40
+44A41861BC40DCC84BD6F9969DEC343DC6F3F7C8FE9342793553B5C335CEF67084B9F1B7
+FDC790015B7F9D682EF547C986CBBC0606E0DE60E95AF386CF4A475902C58FC382C5A35A
+2CAC908457D5B69C88E95BCCF40A9B12012DB3F548C3ED3A549BE0E5B0BD17B38022F2EF
+2987ECC4A6EA46BBFAE4D6B330C3FA7DB68F0695F7A52C2E9BA1B97A6A2FB6ABA4B8EC07
+5E01D2C021D66FD6E47A4014E5AB39DAD64DA85D3171D7398BFF397E371C483283854453
+4E7815254A0612E9B79143E83555FFAB3438D5F56CC1B72BAD832D3F03F49675BFF38F9B
+8F1A89D2E739F07B2FD36BFEE46B0F8E22EB6F23710D0BA81F3B421E9691306ED6D87F65
+4FA8C6ACAA3356D8AEF5BABD5F6E6231E64A772C550212A6EB17D9EFB987D124E63EB266
+72F2C1C00DF095C829BA7AE2EC7C7C26FEEEF5C7AF6DCB1C846F6B6DBF3F7AA0585F6396
+0A27CB026B55B06954B296E45841706AB1D655A5EE4B774A336B137EEBB2AF2F958123A3
+A9649E57BD61EAD0FD1B05C16C1AAD5AC103C0CB1BE0DA4BF4DF83A7F47814A64A11B90F
+B0E449D75637E8C8366346E6839AE374FA3A2CCF4437F3F4C21B3649E8F25499556971F7
+210B267ABAF315E8B1D2120AD9D3110258BA296B3BA195931492AB8A28F1CCCB4AA607D4
+7DEE5BF92546FCACFF9D9243B8941D011F272431B2782CACBC99D9BEBC4CA43C90864DC8
+4C800605BDC071902BA524866FA1D98C709BF9200EA73C2FD8F41BEA226F37947CFE0B83
+1BD00F2237535653F63AAE9A6484A558FC74B7475EB0D895E62344F509D216A97B96B466
+24B8C4CDDE55B5E76D06AEBF9877562210AB2113912A2354E60C6986EB1077526250325B
+B926BEACF55EB2D98858849EE63A44003D3FBDC186315D8AEF57F8F829EB61C4BAB6C9A6
+E3626F0F3D7E6BA066E31D3F322D060AB9990A619D26BF75C261C69F2B88A9C28C70007E
+9B2C08AA5E8F73D00BC882F3680CC9A78E6D70DC8884A65D53E86B6A4030027F7D403CD5
+6106F3DAACACCBB4481C81FED3B7A711B04F016E18330367108EE6BD1A3121A9BD33EB35
+E824BFEE0D128D00208F3E1C860CC99AC8174444D75DF99CDEB40EB09C20355DCA68E13B
+630DAFABCBB6BB51FA406C924F40FA40E3FD6DA0C673DF1A2F695E8EC2127D51B6F034EA
+E96345AF0294778C6BDE553B2A9578927C484B51B4566B120F8A074C52318F06033716D2
+563658FCE1FC71C655D3319E3DAE16886B92DF451714283F5C1BC3FF960295B947D0D3ED
+1A101F34565F24519FF5E7764E3C5F2304FC8F6F313CF6864E09FF079C93167E654A7FD2
+4F6550BB972F93C43FB9399A0E82D58A43B926F454F38447110891E0011904A776271E60
+FC7AD11E984AF84FB551AE9E7CB68466AF9AD82FAB71590A265A08A58C16046254ACB03E
+98EFA92EF2EEC42B4733B1BD9FC767DFE45D4E74FE31B3EA3588746D5A6ED60F874E7C00
+88E2E423BF78909FCE19952A9BF46BAB57640CE2478015C7137D87D722254B3A70D848BB
+177F0926A2E8DB72506A41C381B6C9D9F4B22700C5AF711F5EE5C7C1CA502483DEF489EA
+0EE03CDD50292460C7352EA9B5B4A50FCA148F7FB3191432787A1D4EE5AA9080D95B810F
+B13F5267F1486BF1A49740C61E0C6C885E3C5B9B28534CFE99F9C656CBC3500DFEA2C3C0
+68DF8B93243857CCB6D50EA01222C1CD2AC256063A27F29969BCCEB98B677F10FF3041A5
+D78B64EB9034C4D2B3EAB0BCBCC6C3A4E3F9F8EE0BC45A934C97F79E3ED5B9889285F535
+7B5AECE08D84E86C95B68CD40E4D747A33024028EB6D6CC22D05306803C5120BA4988696
+F91F4576E3BF631FE32273E3618F378FE44B56431230AD82B5F7FAD86941DFB3716D4598
+C9B3C3B92E0839F583D28577946992529A301525F1D784C6E8D21999972522D79AC7072E
+DCE82D02F952750C4EF7BB486F202D22C5117C4AF3C61C182C177BD247A4F58A55764371
+235A5BC43A4BF5F2977EFB2B293246BB9A55B4E52C4CC35F4C5362395B69B56CB8E21F4F
+230A12741F10EE5869AFF80FB230EDAE5BACC982A7B715287BE10A2C77CAB7DCB986463E
+00C3CF475A746BAAF746FC1657BFA756A3EF1C5721A9E5129AF438C17CF2717AA26F3B55
+6E16EC7012EA595BE25CAC595AD380BDE9357F70CE740D44CED744EB001FA180E54CEA76
+A0F33436BEF0173CFBE3F450823F53702405E39AA9AE532ACB2D87F94B89385941573FE1
+B00E96F44433409EBC3B007A2BA87A026E9A99AB844F0826F837CEAF0ED515B75FE083EA
+47AD5BCB8DCE6ADEB4DEBD9DDC83554336FB9B23FDBE3E9812E8D388DA8036B2EA0F0544
+5EE65BD22CEA0325423876C76D30F77443A1AD4B8640369327DCB70945C94E625CA480E5
+D18DB76FF293F7FB61730A67DEC184BFCB2CEC8A47476E40533B00EACA213C3A9162C02F
+229EE91BAD96D2E7FC21930BA22596037E2BAA35AF874BDC4ABDC9DF92F2CA2CD38C5626
+4457D579CCA2C2D9A69E72B46BE5B19789934A526195CE74263C4E4EE29AA0F0897E1375
+F9914C3E39CC8E254031F58F1618565CAA96AFC2F8636856214A86A5BDC3B48F05FB5391
+797D5A8DFF2793D1C1346E54C7EE0E6170C82C5F826C58E46902D7AE72F4725410FC008A
+D1DBFF2B0F6D269D5390F43663AF29E2138582F6B223C0C577428E2E320AD6E2D8EC8F9B
+28F4358A71590309F5D75F86078B95A66DCDE939BB502BD0298E6690CC33832DAD2F7133
+EC7CBCF9EAE3134D91FDEB4BC8C98AE7C8020BF3B3D88D8F207880958F1DEFFD714A947C
+1E2A6DBBBA6E150EBBB7576D612BAEEFBA83E85F20F4B5FD8CA126CE2E063A87005E4FC9
+4DF19C2EF01DBE2B45D5F255152BDB78BAA8506BA36190DD155AC40D4448F0DBB3A0C0AE
+FBE24ADC1CC30F4E1412CBC6CD52DF405A4252F8557E8154730E483B8541E663E0BAE8C7
+816D95CA8B6D800446E4665EE726DBF0ED62395CBDE723ACFCF0EBA7D39697EF738A6F21
+CF591045F1CA5C3E68C2CD77143D7F694A7B9FE3348F70719B0F7D805E1BB83A1AC9F346
+1DA81E3167465C8ADDF6EB04F86193152EE00970D2066F79B191EE15E33606D83505C36F
+9E8B05926BC156D236E865636E459EB06DC8A9AE6BF433511AAF8B2F37F0655488CD800D
+BFC43897B1028A659F689618B15FBB801F303FE42402DA3F49CFDC8D03E5C28249400DC9
+44596A2BBF7F3BAD818203685C7C1B13C05CBB7E86EFB28B6C4D1C9D46DD08CA022E54C5
+4C6D84E0B15412F3BB3B7CFEA7A9A06BBCE4C69157ABBDD52FC5FACF0A23A53953C35191
+8379F3FF2F3BF089CF82158BD6E7013F5DC178EE34C55CB37A84C98C2F24A64B34978D95
+F82760C5382AEEC5761418A7D75704EF2EFA8EAD21B8EE44B87A8FFC59EAFE6B2CAA3D90
+CD2CD737421FEF85551E5E499847EF4B9D7D33F72A9B9E739CB294A16041EF1FAE98F726
+AA1460D1C782A2D3A717F925B4AE0E1A32FBA63A20692348F7BCA69DDF3FC0BF734930BE
+518FC35FE0DE9F36E6C6AF15D770FB35B68AFC513969D9A0934131FB9A0A60B351E38659
+E3D6ED518CD1D9BFB40A16AC9E77CDEF94E5C3CF0FAE13076F4BCE2841C7EF7E0B364A1D
+5B932335CE17861FEEE20D02237AA90A704EB6B74477BCA3B8BEBF8CE59E19E861832F0B
+950FE683E1E5C05547F00BBD3478125768EBEADB91C6F3D2529FF871939CC7C10D0F07AF
+58FCC9F8F9538870C3559DDF56BD94B5C1F239E44324C68F756B33989B482C45A7B78D76
+6E95E12F4E8853A430877E892A392C0228C567BBD42BE2E2FFA7F27578842D7B5D05B799
+C080B6E55B53D196FB2C4CFD7BF64115742FFC49465B2B62D80E877AA7E7D9D8811327C6
+6DB937B48FF75E410B5F639F02774678625F24CE25814E5718941D731B2F8F52A61CCEEF
+66D7A63A4D74DA48992E4794B453734C9C3CB488DFBA825C094CD8B9729AD572DE4B4B7E
+557644A0821BFDF2AEB7BF98C740C6F7BB79E0D80891BD9926DA4DAD346C785B381DF173
+23760CC55A8D050F73E8B8B751438037EFD9505DCFE058874FDE5AA5DEDF7B0B1978F714
+3F0981B964DB2F7A55B97C7ADF41DC95CA295C8DF2858BEFB21B94F5957715F982BCA5A8
+D6BD438C12C8E95ACC46E9720C7AF8A61A1D952F80E1D65769283FD18C2ADA03242F333C
+527384FC8E5FC02B32B4802A8AFD6A0FBBD5678CAA927B5E970CAE60F72773BB4CE9E49A
+0455728B49422E2AFCE32DE8528696E6ED42B350B80C39BE82CB53478FD8EA4B63DAE5AC
+3ED27E83AFFCCC52E65675EED25001048297E293DADC529D37B5BFAD0C659292A7D89F81
+88A37651DED8312E33EB4F39EEBA2102712D108E8122F06AAC04528E3EC813EBE0D99EA5
+72E4EA566ABE4FF8FF53362FA3158FA52FC599728D97AA69A5C46FCBF2B0B75D2704F9E7
+CC7CDCCA951FE69E9C2B9B448D44E82D3DE480087E98D1A580354D4D0A8F893DFB7EE4D9
+30990BB3B886A2F0AE65B2F8C5FB109B5B7A69886E73E7883783FB030DA933B5853DDFDF
+EC18E867FD17F24DF97CF72D95C7EC0897D20F2FAE74A9280DDAD0497CA6D099FA350C68
+1A46CCBD7B8E7AB3AD45658B8F8B3DAA18D6C5DF704A51DF6F2DB5F7FC218980B65BB446
+99569FF1D4081B16356114E4E72166A09ADF09827750DFB537E9F3CB07A29E2D4A435579
+8F9FCFA874A4772D04B7AF6306A75C68260ABCC1B2F59C447845735F8D9557A97635C2B5
+046B8AEC2815C5094D918D67638C10C7820BBD26EA458B076D5979E4DEE7DBD341097400
+2DED95CC963CA2D607FFA38BF2F6175E77ED9A8ECE8B81EDCD7FD6470E63E48A68C0BF40
+952AD9C1426B3FA70F59D03F317C1484FEEED313A9B21DD3410F3DAF2D664C8176FF63EE
+2FF4D366A2E12AE43B34039BA38EF175253B582F457EE300E0F4AE056909C751F8E9F889
+EC08A1668980672230F7564C28C98BE3021A863086442F0D1B0169F98CA5460CFA959A93
+61E44F39FD8F5F1395C18B9DE0DABFDCB82717E34E836578901B33EC4CC2AF27E94609C6
+D78FDE2D2EE6D169036CAEE5530FC220D59A1BCE8DDDD67C2902E53E21493FF9DF4F06D6
+0787A3E6D31507E4A924BA17142C4421D2B87ADCC7A1D0861607A50C49E8359E0BCEEBDF
+BF997E7988B54950D1B8104C504AF8B321D155FA250380D4753C739CC0C2866ACB76E1FB
+D3A7CEB9C6DED0AEDCB16CB9C0FF78FC48A3B7B9CB117DDBB3F2EAFCA2A9462C3F125163
+6D130D50AC1C2E4381A5E89C22432DA5646E4D7191EB57F78AE5C8C63190C8A350D7A084
+54619FEADA6DEB239AC9CF577DE28BC967871FEECA21CBC24B7F5BC4656441B627A81771
+7B793E36D510ECD9835595B08C54504A35DCD31FB2354A2E3B9029FF9586BDDED0E8BBA6
+C0DBBEEF15BD4ABA2296F949104B44C7AF0FE063A14CC8498E52DA2497EBF940DE5F6AA3
+3788199C9ABC1A3EDE12C4CD6324EE6C6856BCF9C5B009C150A304BC37ED7581BEF3827B
+ED0C87705C2EE399BBC1A2888BB0EB5BE6CE090C4EC75F44B77EC20C37D890E9225CA515
+0A3710734549550537F5E097610804FE488C0E67F063AE0B685D4AB5FF167D9462A87061
+3E240E17905E7A47119CEA30BB69011C3AAE24AF76EB189D7BCB06EE72CBB7C1225D366A
+661A2DFF5F3E9E5C6AF1D81553146BE97DF02DCB92B690BE5C0D2C44E1A57FEC0BED0149
+9A6D08BCDC64AAC6568A1D3045616E470F23AEF55E642FDF155842FAFF49EFC7F6261F25
+662E6373E1A107326EE123240146DC3E8A7BE75E51FCB2931C8F42A6E76542B763192B1A
+287CF88D28D0C897BECC7924801EC1D7B7B7E519DF69DFA0DADFDA635C9942F0AE4DA3AC
+B6F1EFE8003E1192DE4EBB8C0656DC6BE46462C97C02B63B7A660B12B1E169416683BB75
+DD6AFD649F97018C8DBE0D4CA139D964A7FE98E7E86EC3F4E846C3DAE736F4C348D39E35
+C98D98B96E6A0436F5B5DD9ECA1DCCCA921879F11D42512810B55584A2F72607D20F801D
+029534B9D3D7C2FA984005D00398FE7E549CE68EAA5B2B21D87EC383973C2D7A3A095293
+A510DF4F80074C4919883DF6091561EDD20B440E6FFDFAC0895B3D4EA594B7396B4B3AF3
+78559044AA7863D818DC89064CB7518D7448C749E66B56F9914E538EEFBAF56FE087CDDA
+AA59C8A6146C282DF632571830B849A87E0A1089979BA0B38911386EC7834B8C3D212224
+D76CE946A6DE2B2C246A92CBB976736A586DAFE1B3D62DA86B7ED2C92D1B852FA2DA29E5
+7AE135B93A7110018E0968145A18CA917354614CB1937AD9EDE813A70B30CFB5AEBCA5ED
+C158CF63704ACA8275356C4837B9CA53F4BFE2718FCD0F4502F90632E5F65FBB14C56351
+21B5A367A979E1515FB818FD72D9AE26CBDE09F79C244AE16E4AA13609878D0DC151915D
+151AC0844AE2CD57426FC916E920ED93AD36F9412EEEDC7CBE6EDF7EE7DF16D52CE0AF4F
+2E5470517F51B4D4DC734AE36A66D44BAB9531B8E2AA28A811F08F4283FAF1394E56FFC0
+9BC31790081146224C8A599F9209D59027843EC5C1DF4C9919B0513050868A107F9B48EA
+8D68EDDC6947CBD4031CAEC69E35BA5F7F2CE967A9A645B064059A523A06E8BB5F33CBC2
+70D056A003D76AA7BA382CD149BE61990747C75F16D48EB550EB230CE7A87D8150AE1352
+C3A828660FEC741DF9A0F41677F8ACD0376724B7060B0DEA0478692B3E3EFBEC197768B0
+022B89CE385C383C478221B9128B577FEE85289F1AE5680F3F0BAA120916102059E3EB49
+74EE47955A35175C55EE172D41B79D47A1D69B679F08AE94B8CF805744C571B87A9B53DB
+2C9F9573FE047343039413D96C6E757C9FEC200EDB3AFF4D330DABF5F2FD5A165C137BEA
+4F975CB34D9B372E543A61C95408C284AF4ECB516028144A64CA94CD5B4282257E8820EF
+1CE2CEFEF2B2254C7555950DBC6CE5E30176DBD5DB8DBCA2159961DCE778A703908A4E01
+BA33D7645C00261888C7A63D0893DB6EE0BC2165F002CE8B909264173D563EA04940844A
+F99D5750540EA9AF7EE79B37173C4150F42CCD60053870250E45921EA215D6A318C232DF
+9000542ED5479DCAB19B839D4F2BC2871F552FE440D7EAB59F1E46130D45E1322D1EB470
+AD5948C18BE73A0EC5028E37D6E7A0D2B0305683D244FC5E80207825FD8E587A74900042
+9C60722A87D9C0D96B32159A5E00120A9FB93A5F49014C86ADD51C4A1DE4D5120DC04763
+136663D080AE9A62F7136088200DC77777868075E545F8AFF504E55024DA59E61CC7D28F
+0D2CF46A746EA11F9CC96E28A12F1C4E208D77BC61FC5F7C32CD6210AF8D5167D0781F33
+F55EB7C7BB8DCF35FEAEA7B268051C9BDE278D9AFDC8B1F832A96FEA08ADA9EEFD8B4D64
+525E223E0F8BE2D4492FF02DEFCE293DF9BC0B63FADFC0CF36D86408C198354D60810EC9
+A184885B1049D002D5250D46763042EF9466A3CC6D5D77F15DDED407743E5B0E66F07E2F
+0D6B34DD74B03ABDD904746F47AC74EC694F2423AAD5AC1BA4D92CC812D14AD5BFBE7EED
+E711C2FF2CA96229106E9B1EBCB7B247E9DF0D3497B50AFB597128670D3C37D33E8B3E81
+4CC5939FC944F0DA9F486517F19CF6DBBC50315F25BCDC9E2EC95BC5C32C3873FFBD02E1
+10C4EBDB28C5D812B259385DE0F27DCCEEF80D106CCF483FCCA045664F74BB6F3A93467B
+F8CE0D96A004A1E0432B509E1E28CD71BEF3CC18FEB60DEC9C3C8B4C7DCDC14360C02604
+65A67941AF7445642F51288B5BBE76CBB54DCEBFE0FC2BB4F9DCEAD53743B355DBB7095C
+4869B00D783D56AB252AD6242BAC1D7F71701B0BDCCA9788B29FEB31245E97BA0BBF6167
+570DE4DB44AB1823F301C2804D20BB08494685CEC27C481041C456C5D1024B7787385BA8
+F7799355810EA9BC21F6B14F7A4FC8F85276FFBEACADA152C746133E53A53F8788030D93
+5206C09FC2A130AAF5A6B28BF9F81A3AB72F910FFBBAAC14993777786D6F6B42FD005566
+B7D5C006BCC0DD10EC2D8EA90ED65F8EB52B488F5D5AD6AB2A46FF7C06B95523D79246CF
+34576847ECC644C0A85F3D379DB1F97A246FE3B066D0A6F7B6BA63854EEAC4C82A92C3F4
+53A9A906DF74B5996B96D2A13A1F7EF9682D8F0669D4D241BA1012B13D69CE14263707E2
+22BBB0E36F19ADB165BEEAD76B323B55740716B85043EEF89D393EA418BFA7806FD23FAE
+5D26CB811E5113DA77A37560F82AE3D2F4D8C4970AE092D0E56888D525D45563D0CB4DB3
+5317E01296570AB93CE8FBEE77BEB7E9DBDEE9F3208656C8B536F8E44F89203343DEF8D0
+C6CF20273522C4E2ED3AB104E4C98E0C773C991C89E16BAD8D6EF4D70EB69F9B9E7192D9
+36E057EEB0048168D2199D790379433974A70E9F418899D3822B0354596149DEF74FD653
+162778EC18B4AC9093ED9A6A3B3C76EEC9CDBF5A4A4ED23BF60E04E5D53A1CCE0360E178
+A682D70D86C5E5D8B4DB2BBCF7082558185084F8D8A22C96C7296DABE818F67FA9E5ECB6
+F5064065B7CFD19BADB214DAF76DC8EE0348E93849BCF1940962F297DB8181847B9FA9FA
+6B443B870C7FFC99CAC69584C8CB64B01098EA4D3496EB66CB4A146766706945BE8AC9E5
+1F82AD6B2891A38D0065D37C2ABF340C05F8BEE47A35F3B01485CBD9B4C79D6DE4CE40C6
+E73806BA1CFEBA9C3A0816054A8A41B757375D6A0E013F96D8D168F0A18E44FCE3975699
+FAEE3089DA2C4C743E8F746C7CE589968319BF03874B6F577D2ADF4711B8BD42EB9A51C7
+256916C4258B3EE07BD2CF4431F1C835C2E1E86887E100703EAA07336E54673C3A3EB4F1
+B687442C6D4AEBF412398D1F1465B8FFDC4FEFD5ABD396EEA8FE981E585F3CA45798A874
+EC4D3D7D2BB31E4CD62898F6D6F27E87B2D2E8BB78BA524A54731D04E0A21C19C05C5F45
+357270669300949C580629390B2734F0F1A32C764E0BBCB8177DE0E5B8FE4E958E9651E8
+703C8AB58326FE0449A73AC645B2DE49E6FC099399003449124AEC31A8714834A8601652
+6198B6AEA7A2F0895EA9F9BBEB13311BB006F4F6452C8F23064057B7329D3B98C5C2ED39
+139FA2436C0B610542069B96D6A0027D4C3B79CC646C8E063C38C3EE4145236F955A60D7
+073D6B8DADBD102BE5EB88FEB9B889A0E7FDDE15B9F69F734EDC33F16BDCB9FB84481969
+6CA99D5D5BB5EA6B2C082EBAA52963C8454A0A1E475013829CBC977864B617A14DDDA328
+E086803BC06FEEBE32D8977F9A8376325B773199B29B1CB15CDFAE065B3A127D8D160E1C
+472206B7E4497C9E91B5F487FAFF62724D86478741E6A2FF610256AB92AB688F2AB751DD
+90D96090E98A2C94C59F0756709F828EDF55D4C7A56E329F3085A8F7CBC2765929BE87DF
+11B087B08DA4D082594FB949640C24586FF1C8B505EDAF05C4BE22EF8574AADDC544C702
+C76D7A9096B206979CCF7AE4249552B38A2FA76F2A9E4EA55ECF7E7B4AC88F77B6FE203A
+2D4780CAC541C94107DA1031658D2041ABBDA42FA36A744F55B1B79090B3FC71BA917778
+CCEA41B76A06564B753BA93BF518CDCC98192399E4960A870D13B48A5B18AAFBC7AC0527
+66F9727D135DB7FEB447986F1817A66EA426643E1D2A4127680EB0BE913BFBBF01BCC874
+92F6D772F4823ACB23F378CE68FCDD439A23947BF8AECFD88A8F8FF4E28526920B833CDA
+DA3F234880E1CF5DCB0D1E333809B0BACE4D1A3CF36E122F5258E7B277125C9AC20AC18B
+9323D1C8332E6CE51FF5C7CFD5201E85498BD05430993DD8E18A04C75200C6B883B0386A
+8E81A4A6E3CC28E4D0744D8EAB410D60B93B82B64D387EE84A27DEF4115D554C338EB123
+40E9B6B62FAE4846FBE23DE6EFF018EA67317C8743F171AD6A008CC1190D6ACF47B5712E
+607B1D6A6EBF3EC767F51A6D432CBE352E67FB4D976D852144289006679AAE4E5C582043
+3ED4A6F4DDB4F6056AF923B84B8436BDEBE43AA7FF0A84B71F469C7BF396E0EA95D31AE5
+23B41676AAAC68203F1214E08BDFA403EBDCFCBA37023A566A0BCF34D4237B6A86FAE988
+DDF9D5699021CFEFCF8BCC3862836220C39BCC82553FBA41585259B0494FA1FFD2C92C93
+C4380B885A55A0F4E829CE6EFFC72F6FE64B66E64A2E3B0E82043D164D0EFCBD3CE98D2B
+8EC210F6570A60C92ED09E5B8BA6618BDA36F14BB1B1E6DCCEBE50E612A09660377A67D9
+3B19D79AC625693FAE271348044AD13EA26B4FE7D1520A814C2F7730537068C5C34984B5
+0B8BD7F836B957067E02A65B6D26456BE4334F180030082A26D89091E30D628BCA32307B
+310C0078D3FCD2283D078740BDC955B4DE611BA1D09A04AE30EB30154C0573F459E75557
+A006418C7EA44ABAEF9382C182CC6AE260328551D722FF8D4B06D292E09215F79118A716
+77B0F6B4A7F15BAF61BBABDEFD83C92231DC7E4A491333DCE7B5D1FF92B6D79462D8B95C
+E8300AE364B0D92F7C40797EBBC62F9847C796775385E343FDB02A0726FF6D5E118B8913
+F77E2DE8D7A93359530808B89BA7CE125C2DD1174D30F0EF295CFDC6E4B039283D23F235
+24D860B97851E7A59A8863959F75757E6F9F7BB8C5629675225CE1F9543F3EED0D931D2E
+18A9206F709E5586CF19A965C5CDDE330517E19596DB1A817C3146433FB0220655949098
+0FF33A01F79C04CF7D46D80AEAE67F867DD572EFC12B469C9BE08D9ECCE54050A6331593
+4FBAFBD5E4F2348251582AA624E6743A0C8FA08FB3739A303D919A9796797642F6CD65D6
+7548C40C32912745452600D2093AD67A34D3219CB539CECB093009B13AA77CAE78AECB0D
+A624DA455725B2707A8B27FB75411B96DD0F8F33A31CCA0D0DF08BB08679C6D2F06CF847
+23DDFCC89E54D68DBC2E8AF22D0E20F86317847D41BD78B463593DE423200FCEC1341B6B
+A61B327CD89757825968B6D40BDCEB55BC00827EDF7994C12CFED6A4C16F5F3CE38747CC
+8942C8CE454794209ADCE9A7D2608224AAAC684EE97DC956453071AAB23DAC8D28D1E2EA
+13D28DAFF068BF11859F8E1B8E8C571EA30CCAD1333788647E250577D2E908F41ECA1B5C
+1A2199B479F0D38731EFF6F8DDF3B86FD436D41F24306BE4D1771EF24B287EA32C5A60FC
+BAD6655A20261020A3690E70DCAC494A6AF3214BAEED8C00CC86E861C4BA6F545F94194D
+9FD1736A81A26ADB9BF05BBFED3157D6893014E87FCD8419D750AB2F51711D1D4FCCA860
+FFD22A121805E91AAE796708CF754C5030742FA9AE9CE22FD45089F532C769E906D2D74A
+6C7DADF54ABB9F8CE74AA0E8B86F9CE77CA934DE33404BD07BE3CD88FF1D9C27DF034032
+554121F6214B95B17E1F8B2909C31B93E3BCD416DC76A4D150B7DC1A0D16B57A3E7207E5
+34BDF060F416E97B6C97AD7FC846F6A3CFDC92BAA822FCD90087A19C6C04BFB4BEEECF2C
+E8B184E9D9A72005D2E2B306AB25E7708A36C3C6CE857244BAEEAED79DCC8420EE0DF1C7
+A3BAE477C4DC1EFD1CCDA761F230AC93BAD22F569758FAEA83B6FC12796C503856E171C2
+1B8DE2926E0000BD7BCB2087184865B43DA908765DB836C1397F86C4EF27C6B667D35B3E
+ABE731CD32C0501DA20A26F086373E4CCA74922D3988B857A715B8C70F131A190A33D9D8
+C36E061A60E1B5C63C749AE965EBED843204279D515969A3A5A5C0616FBA3D7DCF19AA8F
+B0B8FE4D5134EAD0CC503F0BBFA49E7C2110BDD4BE27DC7B67DD0F417AF8C33FEC671208
+9D5309074D1B15CD52FD2CF319D1A3B149D7A513AD9D7C0C1EF8CD2CD7031F082B27CFE3
+1CB2737CCA9492AEC194A92BB2E5FDF0A94A30836D1FDCB78D9AD2A3E4A289A7E58177B2
+9D92BA721571204A74441EDA8385B79E67E5AE5F52A2A181E8C22E3343A30AA03E2DF4AF
+B65F91D82A7823D2A172196B613DB060917CB303C574522DFAD536167A501EC998004BBC
+7DCFE97EE8AE4F169D604214B9746475C32B7E557223B20DE15E67DFBE2B4251DE61F732
+9BE3B01CA9D20CC06173FF97EF9C15C4109A1A6A321C4CFF59F448D7021A0A0E2ACBEB78
+C4C7417E652E46DB60BC50D79A8247146CCCD3D288F7DFDD1379154E6E67C3245B8D4F78
+394936ACA8A3BDD330219F916595035D95CF1AC043B3205981126CDB837EC4A69FD88C20
+EB20E8204E3C5388A84F25AC5E96F58BBD258326C4961CC39627359AC1BBD203C878FA14
+6466C407F206184AF3D5666E7A3D6A01A866523FB85A86CBC08C62ABA290248E9E23647E
+4A3D39C6C1A4DB8EBFE9BE7D70B228A3D426D6F5F0B73EE30A462983D166782B02AC2B3D
+CBF181470A396FC272782D83A2F6978586975FF35C955A2A15DDF14A0A152B91344856DE
+24E10D9BCA853424AA1ECA78A8598A300F620C5D5DCAFC26E087A118219F6F17B1A468A8
+B3C2CA6E1113F428BFA8776F863D89B432CCD125F7E37002067D775FADA0365E6314B022
+E782134FCD614431D014018CE7E6A66092EE5113F3E94ABD5CC5EBB42B11DAA52D18C34C
+3A8A973F1BB6AFA1C81BC36EED9595E5AC3ACBD580D6D499273CC5A04FF2FF51CBF886D2
+4A80DC14D0C7C69B04E77E3C0D9DF24D295128632562A1BACE9CB3D69332EB08490CBB94
+37A4CBEDA79BC03409C7EFC8B8C38072D37F9C2EEA32C59644EB148EA83C21534D28211B
+E074DB78285632BE3DEBDE8524490B9CE18FD89374171B546D349828B5C2E9A497539CCE
+B501FCD13C47F4C2C57E7B625963E7159A57A3C18FF6DE06B357E7D125574D6BC2A3B891
+A918E00AF3BBDF845E6E3BB21FFDC4F724085C73B147EC7C72AAFE2C7087133CF8759CE3
+5365425F272C61CF5F96B1490DEDE8E9FE77E6F7FAD03A79DF2E2A90E1A12263EE5E67B4
+4B1A7C1737E4B178FEE720652505F6C5AD062FBEAF7C8134E984B8FEEA448340FEE7E3B8
+54436EE0CF964B7F854AB52C1A7FC0CB455EA3B879034C34361FC56935B400E93022A073
+44F0552946915B6DF0464C8F7DA5EF0C6CC85A877BEAB9FFC4854252FC2D01C275E634B5
+2F4A439AD072ED4917A6132CEA7669CC1D91CFA66EBC689CCA482E9D5DAC4F2D4A138041
+82792ED95C8305E0BCD5B0D70C6E89F7F292FFF59D405B86A00765E0E2A42C18004366A4
+C9AA307E15395495BD16D691EB48649FC2E377B388B6F5A8D519D6CC18B4F2176FA9481A
+BF4A0674FD8627F5A544C3954A4F51C234DD631301465BCFF18734190C48531D3C22A368
+3A8887D4C665D442C58CF05192C957A5B8D5246E925963FB22A4476E74122D5C5A45A64A
+DDD5280D5BCE3DD52BA0C2C5BB01E25C6107BB785D48C5E37EC652343D5DF64124E0544E
+58785F88A7677C2995B938923A3D31BFEBE629A0C0B10E89DC24AD5C5BB67CE96706620D
+44122A38FE39966D83C60B29DCEACE2D5B7C62B8DD63A8C4933EC9C2DB8F0E1EA95C4325
+E6A392A6FA28BC9D8A4614B57D6454ACBE1D4855126AF4F741EA672C5DC8785B9510F1E7
+CD009ABC0DA119E418B9D1732893A71295FFB947382B621A35430765814A4D87BC9225F7
+C30315EE1C82AA20C6694A2BBAB918D6218A862B9606E868B7CE46ADD21F18FC192F3E53
+680F2300AF3404BDA02406D991FCBD977F993BE179ECE640101FF69DD7130AE252104759
+BE35F677641AA99B77998EC68F2C33A8BEB421CDD80A32C85187445EB30F882B11DAA52D
+15208664CED636B5A8630DAC33A8F1A8ABF26A1E28B1E9C5A8BF20B535534D337780DF72
+2D36FB033EFAC9F460A030DBA78B9DA909984C36A8D3A206501585E2E7CFAEE68CFFA72F
+3C55906EF2D704D8815FC8DA8CAD942581B20FE0532732DD02C2E7809FDD9EAE6CDE2B79
+F81DFFEDBF5B25B0F81E884877AD96AC10D4CDE1212BDF99DB3BE6B407AC12D6FF84909E
+B43A9E47C76B6D10F728AC30B0AC9902AB6FC8F894FF1B8EC121C32DAB55C6A781D5AD57
+45F94D85EF8BCC8F2672EDA77E61499065D9C1C6CB105E0DA67E2562663B52D97CE325FD
+4C0C6A01D33FB1D3DBE738088EB49F61BA3A7E70F567109226E247AFF09D9B0A2103C79B
+33467BA06B94DB8BAC62F45935DBCBF027F1C7C36DD12E895077A646392EC61266C98961
+FAE84D5338D421424846807E904E1B276CACA31010E0B3E5F5A05E98B82A5576C060F452
+6CE73581B41C6BFB71867D47293EB5E120E0878CBD4F670B69EE75C203CACDA0B87CD4D8
+6A7FE930BE7BB0D0E004FC34C2A51B5304FE437BAE9F2A2615DD834E6D680A1EED495A87
+5362C820E355D56B2B5D2C70EF2756A992BABD7C94555961A2C39C5AFF95AE8B88DB2B33
+2D0F4551212BD258BD2D6C53A290657A3475E173AF1CC8A893337932D9B35FF9CD005B2E
+7854D0997F23CB9D359D7462EC0827DAA520FAAB6B0A396695DFCA5758BFA64DDF4203ED
+FE4F89457895CE06250121FD57536E08E898DC20F084890D65772A9E242F5A07A0CA75C9
+C3551E79784A8A3256455B6C88CDB8652ECB2A457D00B90E2C0DBAEEED508EE964DF1329
+B34B20E37D58D92B6AA15B5D5F56702C9EB9755025FC8FC393C430CCFA34180ED1BCF887
+05C6E3EFEE8A9D5C99EC0F48CBCC34F37FE10FDCC68B021E14A1D131FCF8D5C2F8FBF465
+8A60A554D418D590E03A268503D12C542393342599828553AD4589E8B0E6DFB2EC663AA3
+B6A37FB206C1B732C18A052A0F309DCA19DAE82D110FD3337A863206216B00317508BA1C
+1859349EEEE49B9D25C897D29C4F28C3757D350B3000612D4C32AB5E072DC92700132514
+30C91CDE6C1035138C683763736103E836DB99ADC686EDE265182E8B02063D76441E6122
+F10EB88DC27F1273BEBC4219A5E6934C51E2A9FD36C7CAA59FC5A5D2049C0781FB48B30B
+750640992D5CE69D1602543B81712E8514041B4991A115956C268DE747B0F136F8819023
+8D14DDE8DDEBB7E147057EFAB2D0F0002CCD0C6D997248A1AA973D284D6A04A3E009EEF4
+3F9E859CFB4833C7E485DF4786089D9061F6F4C1EC74BD179D01636788A88597B7F9742E
+17C41DBEA3E371FC867274D265589AF7BEACF9748E7E21B73318BB6728F455EF9BB67165
+6C39614711B33B96FF3F74EAFFCE174F0CFD3704637E5CD8AAAA0127AC58C82CA7B20971
+670582631831E7E5EDB9A27C26C67165C891679515E0514E6D6CB7ADD9CAE98B9E578DA4
+7B521CE6E8A0AD1DE58A024F954A424B707C462C83F5B459D000E5195F45FC4DD186DDDE
+4E305D1A2743BE9C41B337785B9D57EBEC790987B6E1D03EC686CD01C3E2E14D63E07AC8
+FBDF1D5D1B38A2BC1BFBAE604908BEA0990033F9F4FBBB8CAA310EA2C217EB5FDB8E0B08
+98F64639043595E8D09010D98F959A7BF315716FE1E05109992F33231C10B7296E284A87
+219767CAB7BC5DD096DC7E164E114FCB6CB16F078275B08936A7A036D17B96863A068423
+D4B72E67EA43483968214F6243E538AEFDD7B076B0B6F7CE98A914D2A2332751DA48BCC8
+0A950FD81DACC79DD6E3A2EC69B724FCB10CAAA58272FA64D625557153DC7C1683858F9C
+00C98EC395D7A364E65B33A0A8FF31C7FC19CE7DFB5D77E2B5196C924039F2B4D4859C11
+F3E9D42760F5DDB4A3BC9B78C0CFD18F9B75F4756DDFE2D7C3C8C4A60E6ABD17A234CC78
+10A6AC5778570C86C63B27926FA00D01A204CB6E7EDDFA36476E7278B67789B17EAB6F9B
+384465DC8EA130CFB75204A20E63D0A77F4F2148BF88AF8D86A7CC39FEFCEAFEB7CAF7B0
+65D7CFC437E55773A2F24A1F7156C4488FEE00627ECE1B4CD8F8536B91B477331073BEAC
+A38423E177E3BD2F6E5E31673EEF7C4510D430BE12AEABD40D3E7116C4C91F47CF12E4DD
+6500656EA37E109AB7F5982BEEBDE4C4E1AB125EB84B560F82716B4D672D13CB3D424596
+8B201C3B628AE15A0E35EDAE952720D3D7DC3C373E1589C1B94E758BA485AD155FB984F0
+7EE774778F52A84919E48959C071F7ADA4D5D64A81E8D5D792F9E8DE6C491EF9ED29EF53
+3CE191646D7EA108500A935EC3EC9B4092EDC5920FD07A5549EDA2F643175B7CC27F7AC1
+098BD65DEA60D6780634EAD4FA2117E74458703F9722C9BFAC8863D2BBF338EF586B4E34
+2583F1EE4907414A1FF2DD25BBD2F5F3B10EE054A6783DE20C414E7366BBB3068D0E3CCD
+A8AC3FE053EE1B89F32EA80EAE51D9FE242D06752BECDEF0F9FCC48DD72BF764378C8628
+98B308C826837EEE3C1F745325F1D989D33650C5A11AB9F5C47C20993159CA359ABB6E14
+ABED7BD14F7AB1B604EA8179D2254BB6D2F9F08904B91C645844368329765045BC4B0EDD
+D8A5256C878D64941DCF0EED82A61004E584A8BA9CF9ADF76F5CB0B2F26FA4A4E6499C45
+92ECBFBD4736242A8C64D6E692524B3E663CD47D0341637139F2029358BF07AB385466AC
+BFBDA0A68E684D4132E529F4CA6E3017AB2EA78F4281C290E2EB2A948281C7C466AE758C
+19FB86A7C335C50BC32E68FC5973E533DC14720A90E5AE57F8E8D87B0567F291C797A00A
+B00F1488437F05B149E4CE5B182C5CF82C3B15097C269913088C9A493C976319BFB2C669
+553240D1025AB656ED019592AA7AA98DF352A6F0CD453FB20FDA9BC5E53B003528C1701A
+94F06022EB7DC590D290D564DD37357DD75AFCA9704642DDA1E23E47FE3EAC9E6B5D22B8
+AA0912C8176CB668997D9B9946314647ECBAE379CC2E8A836F697E614CD975560278F0AE
+74EA9A7C10F94564170B11426EB79670083D2F68E3336898E5D670AA4785929A2ECB553D
+356F8AFD7B0F95E8AFE1947C638684800A8720AB299EF7538D6D56FB1B679FA5987BAC22
+A06F3716B089EA008B1DC55E3CD09A39F0A903B8EB764E5AA9C1AC0B5231C440F68D4E01
+C36BAFC2FF18F34087A5B90744D85B8DB03B3F8F3578E1605487328A11ED9C7E7AB8DB6B
+580D7329026F14F24304B195893CC1D091D960730D2C45751109DE55DE39047015AA14B5
+C497C41867A5DA02E7091FB40E952E8ADDCB0117562A04E71739AE2F9F2CF315D510DD0A
+063AEE64F428F29AF03B9436652EE54D68BB45FF0E3A373E5CDDC9AD707A989AEC860A32
+2AB8C2CBE68F36F2523B1145ADF788BDBE0F577AD7F5B082ADA4E4F798199883011BDDE0
+18783C3E8246D2829325798FD75CED42DE6FA551BAB1A8E0637BE3D487AF286EC8B42278
+14FF0E5BD8B32A0C524FF0A0C22C8735BF7145D82F6721E7774D2EAB4C28BCE0634A10CD
+571490C14979ADB3126983F20925E30D7DE2AC03C146432D8B15DEFEF9504467604D9F02
+32F7E56163F09E9BE071FE10FC3CDB00F40004AF8B01239CE23B5F69E37B35D5DAFA76B7
+8576B031E3386C6099407C8042816A4EF9CE790110CF24C114EFDB9C8529A43C41168F10
+A17C2ACD6C4E299A9DE70657E70B16CEDF35EB41392648F09A02E1E4717400DE1A346671
+37A7CD6A6EBC5F48A19FF169A279F815BEAE49B489923AB6243E4C8AF35B4CA1EFBD8EA2
+D21211D869E0D3DA441860B6BC465EA8497507B8323CBC9B41AE6C774EFAA7224385FDA0
+CA5104978442A4279CA25C29401BBA1367CEF35A2BE9D24CADBD7BD9695BE9AF03BD8DA6
+A62111A9B59A24A4ACF6334807CABD977D251213079A7265437C822AE4893BF048B19907
+E997F038CBDD1FD0B412AA2817453698EF05EEF47AB03E9FA77751C57210969591876316
+C83D5052163EDC28DBACB472D2873919B63E9271310702DB9521E8C18020470A4DC60EC7
+A1007BC82BCCFABFA1F575011A9067817930AE0321659ABFCFB4CFD6EA7AA86AEC98D64A
+1854B666D075107ADC85FCDC67D89C379741264E6554B7F60E19A5292D356E64538777EC
+830B8F0931D34A61F9CFF3C37E187D99D5A2E7E876D1E8996F73FDCD7E614101F97B8BEC
+A0744AC91DB473C0103B6820134BA545183483C05E1EF90B59B78305350080D2204D751C
+C8AE8DD9462DD62F0FBCE507F6EF39AAD77024E89975AD12BF8F86130D9B76AC7BC4D4BA
+BEB06B76BA3D77DAF45E769C732882DF011DD3E00845CC703EEDB8EDCAF7A6EF4FAB06ED
+AAE69FA3A9436774577899367B202442BD6CD24377AAAB605114823C26D249CB0E130CF9
+60D8313DC983131AF766483BA063D7ABC0BC24EC06DA0720D4884F9421B9946AC15C30A2
+DFD1375F5CD56D83C8B94CA84D3467574641768C02ED50024DA171F856880506E3AA5840
+1E65B0B73B80BE8CAAC83A1012D1F244F4B99BB4BFF9F001FDA8F06946883B1F0657C3F0
+22900DC7E6EBF936A8D55CD5D0D66291E24240F8B997361BB943B5A9D36900ECE284CD7F
+66047938301E2632D00CEC224B1811F43475B3EBD58006DE58DA2F91EBCE1833CC23C395
+C071663B9A91B8FF22C98D840700E3256087FE0A616FF9C2323FBE8CA67CEE432A2D2AC4
+D00407877B33CB35B83591CABBF8700623D58B8C745C6FD0CDB21A2C7B26BD8495AC72EC
+A551C5B077D0EE92F5A67FBB4D438114D161566167535A3B8BD74EB10382D997C418428E
+F88388B24D9D78C103572341D2BAF842DF6522087E28058CCC1A8A7858EAA41D1F588C55
+282E7AD9708396959DAD7EEA79291F5FA856A15E0DBA1758E9788685F3FE87AD15E29379
+8CA04AD209B10DE234315BC07132D32C82ED96B649EF7BD65B80A45FB3A48C5C3A994628
+118633137D02298916DA8E3EC7598B8FF27058EF911807A26F2189169D7D53A305F89659
+B6AD13AB05ED759A14FC3FA59F36902ABFDE6D02CA63BE37DE57EA0FB0ADE69626B8AFF2
+C4CE000A5AD361A7311FB0503F6C6EAF4E12E90DD26C2FF14CF944F1C7D370D1035DDDE5
+DDACF493116C4B10BEF55FD88CEBC22252BF641FE8E871D2A051F774A5D3D9921D1BA16B
+26765180C16A4800F59B9A6B990340D78EF95CE32DC7F14F34A67FFA19474C8EA4641284
+DBA859874D070F5B345083E1AC095CA5348E0358FE7B10F3DB25027CA0C6F63D034974E4
+64ADDEF24654F73B0473208664323C568A2EE651373FB821BA60F3ED0844FB75754B1D3F
+D47D3097CECD9D8AA2E3C12A286F3AE09EE3F27E136DCD543BC7BDD8F4E1831FB190FBCB
+8B5EB2BB4C91830CDC404EF0F46DA4A9F41345181D0F74F39F36F5D1E2FB935D595E6331
+80AB43D32F82C5F339DEB75288209C1F7E006326239FAD725314A95ED40D51CC657E52C0
+CEC73AC090702C85B9F171C89B2C787F1E7B4EDAA41CFAA83E47CE0BDD74E9AD13E71539
+A19872ADC0B12C705E9B4B271016B208974D97623777A64FD6F4DC176B98B07F9BA07D8B
+949DDE4A4236D3F19F360265D8E745845F2E6D74C1982803330033B524B6692E58EEB2E8
+D1A3EC8575839D85FD65EFBAB49938B9BFFCC0A23D8549BEFFC4FFD9B5644B205E17EFFB
+A6D24813F3F490722DCC5401EC9BB107ABD77D11FDD60D882E20F1993F9F471BDE3DF47B
+13D8BDC905A1EC61E9325D4F6CB62477FCF08BA409B7B1BADDDBD072A8FB38E26AC452FD
+B77D07A223CCE2EF62F7F7365B8C9697413D77A188491448143F300B09DAC3F77EC6E287
+C372410597198B2E7AF074597B6AA4E86AEBB31E56BA401D0E6E94C40A4F6EEC7703C3EE
+06EF6FF5DDFDFC2B7443D67C04D7311BCF21761DCEA797936EBA6098C91A973EAB0A9D6A
+E81C1893C7CE1A8D2181DB792D20C29F3E6C5310DA2F4A25DECE6246ADE8B78C0593ED7C
+62D5D6C89B6EA4AEA664A79DED2FC50F958F8B1C7B92942B4E58323F2BABCA0B77B79992
+4738A89BE91ACC5306B0B6E45D672069AEB3485A0B52E931993E600B2E65F969D17585B9
+23D1E5C75F44E2866DDAF942C6ED937C4B7BF2409F1BF6397FD27BB5DC7DD077F0F988AF
+0677615675590C950D0F9A39EADB0FD85644D3996C41A5B45393BF9FD3EAA4435F9A99CC
+5A35051000E4FB703F801E8B71115A0EA3BE19D5AACCF5B0833AA87FA7CD506C3131B6E0
+5B3B92A493B57268CA478EAB09E71B1DC304A329DC6E7453F4B3721CD13C2B670C19A764
+9CCB29BACB087E768F9A817E893A4A0A7EC4EE391DF074C947B2978A844D944A10E2229E
+0BBD69B27AA210D58954353D1266F57823ECED7EAD0AB583F4F27CEDF3F92D1FCCF34BBD
+ABD82B2BE6BF7F958EAB3F5921D8CEC898D7076524B12D68DB720BB81305F195EF87BA96
+264878A18F98FCB5136177EF743037D4F7141A15744FBA348614DEEAA97A3510FF277A18
+8081B35AB29A53ABCFF2AF1DA946971AA55A72022A6DD32A7F55C05EEC925CE21704A5F9
+C35D5CE2130C32A48EBB7C30EFC34419355761BCD0732AD4B351BD046C32805BB089A3EF
+B013E4F54374E8AFEC10ECFFEE05982915D22E25A2158F5BEED6A95EC6005490FF895CA5
+DB459A2DB44108AC0A9602723619CC2E013155ABD1286C9CC50397CC7AD975A042833A03
+3C2F010A0208D2B5F7FCAC1F4661332E91F43507BC6C55396FFBA9E2965CCA72EA47E3D6
+A0EE5BA53A8DC8579A85383B394A043B26E15EBCE158D95F14C714793513A6E11C0B4FD9
+A02704707112AAB327416114A7E25F6487E6749A8BE860330104E85A2791DE3C98B6D6DA
+8D9F251995C972404D1A0D4F044E828F03848565B821BA154D836BF8BCDE9B4F3968E32A
+D031AEC5216746F5BB0C24B6EA06EC50E0AFB4BEB48CCE75B016708682FBC063DA14314E
+37152516354E42C8A6AEABEC056F7D9B85CE992D20061F25C87125A9DEED6DBDEF357EA8
+68E970CC703B5C8E67F94C2084FED1C6FE0F9BC6D26D132D7A8AB5EAC1B2801ADA11C806
+1D005081A47B901204BFF62BBEC6E119C24E047088B44278CC47816306864CC85A242CC8
+0D2A4A10BACAA701E62980CBB93B59190E7ED184E280B0A20F8CA4749C6375EE133A0A79
+5215D020563EE1AF19A3C573BCF56533C2BE07D4669C21E22FD33530D408714E42371322
+E72A367B66EE7CF614BF7F4647E6FC1B9F9E18867CB630B159D965F6B4CE54BFAC489F10
+FD115E894741C99B40E2810CB37E6F9529CF01989C96E6242D67BDFAF52888F1AEBF1870
+AACAEEFED464733028168BA7FA51311F251B9EB544BB6BB6F5FA90A20BCA883E3804916A
+C83A39F9381FEA3D8ADEEE8A62634D02F3C7FCD8F01268976A3B90C59BFB9AB1F7293C14
+48E00102EF69931EE40BC3FACCAC7014FD78DD06EB156C860DDFCD7963038197189A681A
+AFD7B886C6E7E26C87D4293AE6B1B4E7884FEDEACC9A2B049119147417F3AEB87B33A413
+C4FBBE3D0E5FB7D61B114A85A9C6F4A95D123234A394615192765DD73865CE47E4E0402B
+42D3A1410AA055B18FE654FEC978F28FDB9865B09227A98940613EB39D7B8E4CF55CBCE6
+C13A5ED3DE5F617B495CE502392AC8DCE6A7B8CC7AE9B37943DEF4E6D4015D3936DBE823
+79E1210BC38B20BECCAEEABA24BA09357AD20C0289D2DC03E4CBB007B8B49AC2F1A47CD0
+5037FA11C1E1F36ED2F1DED20FF9D5042D9F9300B5C79C1803A9CFD65D80BEFF3AFFE22D
+A6A1A48AE94C7F647195C920B4FA1E025B960BF661D592FE4FEE71702A7093BCD4AC1510
+7CA7CD0BFF3E766CD241DD6059DB2EE8AC74EFDFE8EAAF57B8AF7AA57B41EDF431549CA5
+DEA22928192F8D1D14F3087C9653F3C8FADB30FB994C72FEFAF5AFA5EFFCEC3725285D25
+19B356ECF7F22D1C6101DBF3F476575476166E599DA264073283C19A8ACCEF9C0EE2C69D
+D9F0FEE3E57CF25CF842D0D3CBA7204B63FF0C4FB0D364BFF2D43D04FAEA7BEAE5300B14
+319DEC628BE834B7F995DDB697963AC750576C154BA3B31C102BAB9BB93272D6799437AC
+9CDD83275AA5A15164757D9D06F95CC444B756237352134AACD5BDA0C41FC0FD98DF9C74
+96D32139692846A141BEDA8E79E7279F1ACB7491ECBABD9FDD1AE69C61B22DCFDC81E440
+B2965F0D82C291D07806957E6D017B8EA7AF37F05F5331BBFEA70A3AB8B078C4F87F4D64
+CCB62D889852BAE9C0FED70BAEB159343A9F3E1F2BBFDE54D5E9353B39B65C16E2412234
+D4E7E1C96D282E1C8D1B38D9B9293FFCDB5EFD759D583C9EE63A407F08A6B212AAD91FA9
+FA501D1C725EA8B08AF2880F1BF0EB6CBF885B70953517189B8536EC2C7960C7E6D5CDE5
+22282682107CF85CB025FBFF2E88FDC5ED4EA44DF630359EDF17BCC33BAB47C302F193E6
+5EEE260DE65D388E935B2471A70A40B5DAAC06911ACD2E5BC9D2853A501EBFB39711151D
+643E9E4F78CE0FE4678ACA19C3F7B45E4DE13696E35FDB7EB7AB60853A6CB942DB425AD5
+CCC11AD042773482E0DBEA11FB1D3810AD5DD26B175339603E4E8F32A14BF7E994ACD717
+AE314DC77EAB6061863F7DFE05D95FEAF8436FA218FC3F59EF8FCA198BE6CCAEB3D4F3CB
+BAF8F585FE5997C4619EF19E53DC30BD017A67E318612FF82EA2553D060B7D406904327E
+779B4980085565B8FD0D7B497FB4350AA989820067B13355329BFAD8D9281F0703A9049B
+75DB584D5FC19F3015BC11EBFFC3BDE393117DEEAF11994DF5B62B5CAB0B16AE64DB714B
+E1ACE83640FEC6AFB4D5A66D7DF0AE5DBF347EF96B535E8ED1839CB030703846EA3D2E78
+6721D7A3409C8C23E7B0A609525D8A675C88E069E4E39C4E06EC3CBF5D65F4FF176DCDF4
+2DE2AD6EFCF7D2EBFA8E3FFB2353676C39B167AF4BAE04624856DD334890E8446134DF7A
+2435D76D4D76090E7B6914873A08688FAD94CD3CF36C10F983A211BC0A8B0276265CFB28
+A976E83092D7B210B997F392AB4B31AC6DD977276E3EA61B4095F5804ABA0E21D8681A5D
+E660B5C095054FEB45E9CDEE557675F66C4380A89FCF51E51347BA633FF52CE6F3FD9596
+5B329DE8A88AEC6F101338F1E0ADFD99212B29B725A6C4997117FF445DE895963F2787B9
+0A892C0A22B2D244834CF54A73082597044AC27F5253BBD4B01C42A69B8DFE25299DF085
+8C545801C56453C0E3659CA5A6F4FA3622968F77EBD8E551C8B5FB354B8192F3978E4DE7
+52544D029EEC168734C623C3DBECF5B362328EEAB289EAC40B85EC5A36FA3F73CA1C9A61
+771E4B2DE1633636F3BFCECC3D70741DEDA306255AE27D4FDBB89B811BBFDEEF8867E490
+C1A731C51EBED996DF36340D570FE89004AE7FEB5F686E1129100685EE41086A245154C8
+1D80DC435DE1253923B72DE0C6B2EE3DDDDFE5C0CDE38F683E7CE4813425EB35F9AAD55D
+3CD3E62314510DF6C2FC0EE94CC188DA028C82FD9BE6C8597B271FD0ECA5FA6AA0704A0E
+9C1EA47EE0DAA990E98E4BCE43EC3ADDCDA75ABFFF6E6FB98AB71271A73C3DFDFAE883F3
+B37A0D2193BD185786280B4DC961470011902D56F511759FAA40308DCE49EA5DE8C073F5
+AB3A29630B93ED1D1EC77A97CB5B157F65B583A96D2D50FD6EE078CD6D7A7CC4A31DFE09
+23A866725740D3E39ABA8305BBE4D4196EFF98A37788B9E71EA6E120DF0E6B9F14BE583A
+EF3F2058C22BAE7DC3B63BC150EA62ED03BC238C27E65DAFB0992DFE8C8F5879B75753E7
+375E76ED56BEDD1C983B9548818E6C2BB71E38BF3F771B65F84706D75FD761A14ADAAD2F
+4BC97ACCC1191441BF0AF940FDF539F961C670AC4C8129C1DF1E479207F50D1E08478503
+409C4E9D165946571AC1CA1D7EF9D31546CA99C1AF6F7611E605A08EE2E49162EFE39E33
+726D6ECF05520DE13F634AAB828595C898678BD119D7F6BE976AE504AF22FCFAB6F930A0
+29E176F442504F3ABAAEF24723311428384D691A98DF4689C6930D8860FEF6E355163282
+700594922D73799A67D834F1551D7BE208615F590781651CEC7AB705EB278B3470D7371B
+A90AC7F0FC6EA11A906030EADF328B63E21A135A4BE6C6C1670C9F795097749D994277D5
+3866BED00493512C771C973CFED9D7125A095FCC4ED15B97E3CF56398981A8ED0D26266E
+5516FBE18D099AB62B457C6D8A1CACDBD04A3F64D4D95A6F65B7DB021DB83C43DFC24A27
+E772D8A805FDE4F4645178693D5CD29B7ED26821B4DD1AAB2D256693A99F612500A903C3
+65889A1266CEF14E112C91F2E2DF5B27A3D979E957C5F70C9AB7F64B88F2466ECA5DD0F4
+465D920F5E78A955878C261079CECD27783086379EC6BDA8CBAD8726167520DCEC08D65D
+4A9BB2729462365F7E3B97E6432EC01F8833870F1877FAE22E893400A346BF8D8729727E
+E7694035DDCEEF10B596B3CE9754E69560A1D8F61AE59FD3CFBD0D1CB94A14AA155C2CE5
+03D238912CA0DA82E700EED99544762C22B8CB36E4EE2C73738CF1721ADDF2091411F98F
+2F7EB86C46E4DB9CF84EE208F6049F73B788BFE5B38328DB074752C8BF9B51327A7E40BE
+F48A409C0B2377236D94327A0A1E36BF296A670F5E75AA2F4C0AC6815D20B635F02B6929
+D72C60CAAFBBA4DC377B5DD92E904EBC2BC2ABCBE404197C803F7878F33FAA8C66EA0062
+CBB1E24BE46D23AF9762C2050F85CF03084FDC271BC0910266FB693A4C5EE4057C2319D4
+3921EC66E5408A0D28DB2C094C92CE16A2A9802A3D075B12D15C0F4F4B603EA70D69D94C
+102436EB6A835D4E9C0937298843750472396D20FD66A039871D21588EDF04E607E03A0F
+E4671CF071D2A24DE7AF33D9C1E3124607854CCC014BB6980C4ACE3B73F1544846CBA010
+A86E003A464014699ADFC587294C8F64F80F1311F4E0B8CC1624B7CBABB7EDAC646C7351
+D67CDD61B352D8E21DFA5D802D5CBA52A364B019FA24579BA36A99414E3B018B8632031A
+365F4A0E9E5CFEE1C936E546C11AC93A2B7EF433C2010FEB3B2F315D806F6D1F42FCDA3D
+144DE40934AD30A14F3AA66539FD901C6A7A9173DD4B2EB6F0F546C43DB1BE141B1E3442
+E0E0DDDBFD1E6C582102C5D3CA9A856A7082530B3C84DAD4FE67C718D7AE874C0B59171E
+2CB2F1BD37A1C4DBB3E767E0E844E6A189A828384D042D055A118DE26D9C5787CB81B102
+F8DDFE285F0D24E0CA87658F2DD9B553B1D52A37B0E0A1E18AAFE6EE4D0CA2E3CBBE5907
+16FB32D9030A6C60523FFCBEA0D682CFD92341BF5C533EB7084EB42EF42A0B6E7D172B14
+805780F54FDBEB03AFD73D2219C74CBC569573B5DA65CDF3CD11D8CD1E3E60DC1AFAF5C7
+417DC5C8BCCDF6E129DE171607901C35ED11B0299BF2104C08158EA843AE803B63CAB426
+842C3B4D93954728352468A44B6A02115782156AB7DE5FA01B7A2C7C3C69BD02999A4F89
+3600E0E79F60EBF221A40269A40904EC3DDE24A4FCCF92DCA20AF2614B11D85F2EF90015
+9C878BE4D889D1471E17AEBFDF34C29ABFBC8B1FE07BA33A5C6B51B3DA5887AF6C6EB0FA
+A7F7AC8EE55FA82C66210012FF0EF781815EB18D1530008AD7EB0705E854B3FA44AA79C8
+EB7A91BC40EFD85DBB3AA61209C03D1C8D70A57AB608FC5EDA04465E8C6545DCF52C867D
+6F2F5175EDF68957BA609B1A5E6F9FB15F628EA7F0D74186E278D45F89F981660029CDA0
+B1CAAEF12FDEF8C4686171A9FD08BB0226DB70C564766AF171C6D25A08C6669F71CE6749
+43F553CCBBDA80CD3C55F283F3068BC8070B96EA52D2853565E00DDD209166FD46C17B85
+604F4F4FBFAC1E7B3FBE13DFF9C2354E625FC87FB3EDE892C48BBF9D11A3FCDF65A29E76
+FCEBA941644FF4485A4E14E5749CAE0CA96819C9B637CFAE5B6CEB8BC390444763570362
+D8B397C3783EE5DFFD08EA0F09DDC3F1A29452B3287443D67C04D6ED1E61B2DB7921A52C
+7D25073B58CBA2699AB8578FC49CA9D550D482F1BC7CD283BB8B02390DDEFDE7CFB447B3
+FE99D6FB4A225DF571790CFA6FF35BA51440BE6740510D7BF8CD55FE16E6F394FABBBFE7
+2D2070BF9CAFFD58FCA0A70BA2F898511477A950293A2197A3E8A7E3FE7AEFCA9DC6704C
+0ACAF82C39784D0D800F52E775150D976F1BC9B9D91EA99E44FC9CC9EBC08DED6F939CB9
+86CE37724553657133AB4903D0950B235130395EFFC27F76466ACE37A323358C6F935EFB
+E8109BDDCE9EA7B22F92DA7A5F5AC992B4FA798C0F670C0467A63FE7571F707053A11071
+F6BD8D93C1B32F1359A827222080AFF5940135A1DA02DFC6AE1113A93E5FC5BDE02F9739
+0FE65F8680B0999EF41AB024E35A88876DF86E413AAFBDDFAD693C0BCD4654FD8F5B9A51
+BEF91593357F8F16B7C59CF6DB3E5B6B5597B8F8EE953FDAB759EF5F42B8D7E0282CBCFD
+DD13062501C683FD109D972DBAB823909E117A55B08E20776A79BA61CE6D84AD8995BE0D
+4D2AD126F6C195AF54998FFB9131E1F3DFC61F6AAD217D0DC339BF8DCE17D074EF5537E4
+7EC63E4B707D0048543D939DCE6852DAF6DC1FCF95D689441B998C8A5EEFA7DFEB894B4A
+90216B335464CA50BEAB87DBC6B3E23AEFD21DBA17B004D9BCD94357EDA82F2E388054DC
+593050F7226E133A937F83462C4A91079B8E96029FA17A4162384ECF11F95D53F3984022
+B02C4C82A702F75C0C3F91FF94571981380466C8BCAB42C2D3A33C282E7E6F5A73EA38FC
+7E296FCF8B1E4C24DB0E2F7F076F659EAED92DA4C9700B6746ECD85995746D648B9FCEB8
+FCF7DE89F299DF6A6D7DD11FAD78270D2F45D75FB0BE0FED1C1290B733212C1D1BFA80B5
+D17CAFD3F3FF5E504B3EA44727AF6F3F37DCED87DB486BAEFC2D7DD7DA55635F671895F0
+EE51D1102B1B491542C9F3CC8F1D1F14CAE5700DC1566B7B44ECDA0150ACB072820C480F
+F92F348C108CE1F70BBB830CB9BC69A3F3E4E52D191BCC2BCE475734B38238725E3F3A01
+84AB62B13458F221C2C505587407B5623B23FE444ED5BEB0F37CA4265FEAEFA74CB365D7
+401CD4C247AF0DE67280316545EA659C2401A8D8F8279A8BEAB4FA83F9AFBFBA32794C7C
+A7268F6BD3CEBC42895E3317C1E8ACC0D82735559AC7EA0378524E879BA243CD6F938C6A
+6BA39385EE7944805C6E3D0CEC912D1D711D90459D032D0F29DDED3320E437A8809727F0
+E42B52CDF7B49A350D8DF3ACC7FA81AED6E290DC3D40BA6A7001ECE8222BFBF2E7D21AF5
+B5DDDE2E531A5042892CAF60BA4BADD60AD61E811BCD9D7608E00CEB90989E48DC676155
+EF3D790B8A4FC96A351DC301FEA7B959A8CB44F228B852CBCE8F9450E4D288E48C3A5D6C
+616B9BE51F38E9ABE16CAE86549316ED8B58E9B0D81E7994BD83A314601CFEBB5413C580
+399D87BF9ADE8D90BB6CC68CC36972159CB55335D74EAAB882A1C3724A2707037E5098C2
+2A6655650DFBB2F87BAA1B3EFF8AC76397A226B95492C64E648FFCC08F8A552E333F1E65
+660AEEAFA3B0296CFC6B300D3C6FBDA01CEE297241588DB27E449C03F0386EDB5D4DACD1
+59BFE6C5915988099909AEFD10008CF1BE8EE8E9F1DCD980DCF0394503177FF49827A3B9
+D9FADC16F0890A6D330146809CB5F3823DB1F9FE042B95146D6880EEFD113174FE00681A
+697ED8BCC6E6B61188903CB3CF5F6248EE181772F5F873B671812B8FA93C1089BBFEC5EF
+0696EE1715FB37348E75AE88A096C1141D19E7AACC7A1DFB282D180E8A08A8C92610D2D4
+E3ABDEAB7DB34FA630A8F5151DF12269454146FF715DA88798240C01F82BCD3BCD81C558
+E6CA13767923803162A8EADC641182B71A205CBF91D93ABD4D194E327234F4FA56F4C496
+40BCDFCCB269A49F449929DE799A99D15460CB9C131CA83204DD513D68F10A07FDC0DCC4
+6B93F8D87EFDE4590E3FE360779B5082401493763FA73519E8CBCA4F815AD8A95BD10135
+3A1F379DBF7ABDACC2E5FD6CBD2AFE90044D86BCEE408AE8A32C89C224EB483256854C72
+E68653701EA2AB54C09F98A365FF042C4018A0DDACE380B54FE568F3C72FF16E73A594C0
+E9F3A228171F6EF548EEB0A2F52A1EF48CD81AE008B8251196854A03D4474EF064C3B9A8
+C92427F5C3297BFED28C85C235272303BBA92E37257868DA3D4CC651A8E8B007AB388337
+29587176479D1F6A95417EDC03D9AA5B6FC390DC64753B279206DF1037A26F38A56D8A5E
+97DA5E3F416F12FA14484C939EBB24CCF60CE0CB682821439DBA8DD842E6AEF330609AD0
+756ED23585F99CA1BF6A9D1520682D939B38408BF49DE661E632FFE11A7B9286AF457698
+1F26E731E8576D259BE89AFD3E96A0872F1992FFC3D5687C5324822D09FE555153E1B03C
+7C1FBDCF72E8B369BC26A0995C6B5F5C3F0B6505AF28033E46CCD32D396F1FCF2BBC314A
+CAF1BB2CDCE7B5E89015E304E1ED36853C9B8C4550894C208398A4596EABD6A675EA1716
+2AD277A409A2809727CB0F7D02F74910093346FE37D14EE063F6D3B6EF9C682988ADFAD4
+75D07035999A7247440FC2DA98D5EF04D718281C8F36719ECF7701D2AEF8B845B983A1D8
+46AD41CE818E1427A23A2E5F842A4BE05A6E867653B6D4530E40B96288C1FB0C49F47CA0
+ED4CE1456C3582C385155F309A5EF60819E3E2EAAB741278811A9DFFBAB54762ABC5F045
+1841D0984BE8960BB21E8642071E442D5EB7491F2261C855151628787A4C699EDA1F05DD
+C578A9CB506FE5308A90B3752D067DCE9E715F12F662C5303CB064B3F5FB46358CB4F803
+21D29935FC49B937C066A1AC82913863D01C1FA85156CD0869652350602D766CB27BE412
+1E50493C0AFAB232057614AF48CBD74C4685360FD02900F8780AA8F0827F2F7E0B0B0306
+80A4CF3969036081462D92FE2DDE06DB413B4E76550706B43AE982AE2467353B8059A32D
+B35DC0D388D6264C573182970C2D0526A6F57AFB21DFC59D22F8D791A214F50D716428A4
+BD37D25A5958BFAE8DABA9E2438270B90440AC7DCD9D4D8A3AAE7E6F0D54FD15D1C8C1D2
+3E04E9BDA3CD2D97C1DE1E6499DD2B2C9D1B789D600EC6B2B9E24739D65D9C8114606645
+D8F2ED5178E3647DC8CE3827E53FFBDFD5948F7302AD1D70987FAF02E5FD03A1B9CCC6AF
+C658B742C88DC2547B3A4EC4CC5414220EAE69E23F7BEC39DC476D24331422D0FF109416
+CDD40545F6802040ECE231B7840CD13B8611D88A25CD60BA268CEFFA145592ECF8CEC07D
+A9846135D35E035CB55F46FD5B9AB7D60CCDE973A3A51AC2F0314471629CB80CE30E6ADD
+71B6819EAE128437C1AA243E869CE668C8BCA434D5A1156A41581D27F3B52DD26BD4089C
+A25EF40DF171EE2109A17BCBC93B05EAC8418F4E415B6AE72CD4211DAA97780F11A4FD11
+A96409AA6BF06A69E6ABF9D31FB157C698F9CD86DEDAB707BA74814C9C96BADB58EEAA87
+3B4D4BE0C4A6FEC42B9AA8A70F57DE8399EB5D574B132BCB2D3FBE7ABCB621BBC3E483E3
+378CEDBD2FC9B758AE746BE44EB4973581E0F402C1738FB987E7C7B32FA9E3DD3E822F7B
+7B79A5D67E0E7C455ACBB780BC94AFB886122FEDE728272B619765C841DEEB915C501C9D
+5E162E25835F660E33C017C88A2BC8D1E93D32CE0C43A83C17937B7E886810F774215EEC
+57A17AFA1F89AAD6751ADE08A4EE4A6DE1208F3A35D927850042155EF6F44BBA6BABA143
+BD726F652D7F8EFB9EF14D281186F9A8BAE057F048D7914429B7BD0D95DECE36C48C6F17
+599FDC8F31FA2A0444C683962895C68AFF8B343B9CE4703A2761AC84B1B31946A7C8373E
+A369BF33219296783C5A3465179E1BAFE1BF8443801C972CF6D28BADDA13F78986F6DA38
+8CE4453D5E7AC0CB518D5C889688F3E54C3C00BAFF896961357BE6B4B487064A9660E353
+E8CD453B5B828AC0F166B50E0C1CAD4CE97469403B22EB2C3FCA6A734706EF4CF7F9331B
+53E13D0A5653473636154D94CCD625F8858B69ABC25762AE4FA1763BCEB2989CCCDD275E
+ED8E95DC14500574276083F59BCA0A2BE8BB1A9A5510C63FB48939BB2ADE959B0342E759
+F556A6BEA0D78099719C9D4FB5D8741598522D483B77155C9030D252E28C2AD364C84364
+39A58ED8E27CCB1469CAAB4CD8B7293BFE89A7BB6B72C4EA5D7C29EBD5B2A9DD66BAE6F1
+9FA45E886E5A79B5FC7A65438695659213E0F4C7A6590911CA0C976668C7C2697C4F0A54
+4E3240D23DE40D53274415F5D6CA333CEE4E6E04EF7C42E84DC0B8F583F83185E1E1CA10
+D210AE0816DBFED7AA382EE1CE6EE1ED7B3F3AEB25DA4B1F3555F39BA2DA5B87B9F78B57
+9B65915E2440B09090E4E8FB0C342933AD8DC8BA3DE1340F00A037CBC4D1E775D3555532
+F828FBAD77499AD45D007BDE4AD065F462D727AAA69E314BFC1055C5FE9637676246DB67
+A6BBB7A78AAF4DD18611871835C218A45DD0852434ACCDEEC60AA4DC48D752FE4303AB75
+654E270D27E951410DC5354E85590305BD4B0631C90E369D992ACE973879CB962EC25EF8
+D01C2F4BC4155F409AA95E65B89D4D1AF4989B6BC3681E913CC4CD798AACE97678D4EB0F
+131D6C2378314EFF41C585571F3901B0D7BBA1E30CD7ED9E4C706446D55B9E269FF75547
+AF498C716FC0A951DCEBC8BFCF05DB2375B79CC1EDC162ABA073F01C06C0D64E4D17A692
+98482F4B4C1747A08B78073D590F5291936AC3016D5C2CF84DD6D93CA7FBF9FC7C9BCD98
+4EC0E07F03D6E632100BC328068B2C9C8BAABBA4E0CBEEE49D37025FD0CD005FE50DE670
+F7BF621CBA9C4723F3D7A6D1BA5AECCEA901403C03B66F6F92D403E4D89C238D75946080
+404B79D35F8D5E0DCDFB0E22AEE8B6BC7D994D05B7AED76A40A22DF9339DE4CD937D54D1
+E09B6660992B6FBC6B36791D5AA53093E29C78BF59E0D137B06FEE0A553939725EC59380
+82954AEB8EE503154E8B56F4B45B6357402D78D1282BFFD0D38D8940F0B3AA1D48419ADC
+33E11C96A48FF09E3A6CCBF7C88A0750868FD61D0BAA581E6A010BE41462FF3F71DE3B9D
+6951D2771373AAB7360AB1A7EF6C04113553AA399FD21B02E1C90FD6FF8DB09B6F485CD2
+EEECFB5CE1C4E0F3675CD792BF28D726C065D5B8BEB92681072CBF17EFBA31BADD5AD401
+C3171B406ED57D757E59AE1C61AB425A580C179771334CDBB633428DDA41FFA7E6BA6668
+568930B3AAB9B51EA7E63845A2D50CDD60F8F60C3FAA5549626895644C1BC9DDAC415BF7
+96137F82FD0FBAA9F66269000CE1421BE1F617564FAC0CDD70AB2B2DDF5C804540182B4B
+EA2608F4C00A220D73EA038B76AAE89BDB8B6496D3F8CFC7FA60701303795C1BA8EED486
+48BC6DBBE06A28E84D4151F85C790E5C6C7862B7B5E1ADAC6EF0C300B1AAE19F092A0D2A
+160208C31B9D36A334511C10339995BBCB3C06D5A7E0658B6E7988FA3704C6E109EB3E60
+687983DEA045BCF7596F869A5FCF88A68982DA5FD4E26F72E758C60917094E7A0BB9E32C
+B16880994E573A73F4CEE17243CFCBB4FD85F64A249B74454654E360DF55D6BBFE5DCBE9
+AEDFF628B1F054645AFF8DCB417683CAA103C4FB59E9FCDEC985F0CB8FE454B245C42F81
+BB62E1128B7581F1634D63FA0DB839B631A5C46A6AA19A0586FF8E1F36639B416C2E348C
+2BC4A28C9A4BAA5274EAF37037C0E0B1F74715F5DC6040AA6BDF49175744A7B214F90355
+2CF60765D50B7A92B7CF05BE188C4934EC815F2F3C274D5DE6945E5A25631DD732EC10A5
+D1D5911919442FB0BA3B411A655B8E9B2937D2EE2B317A9F8656898B2BBA3C93BF7FF001
+FEEEB4701A01F6493C6AE310789AAAB18E543F822AE6389A95F8E07F6948D90DF226DC22
+3FF6584CF81705161648F245BF7A95ED126F084190D003824AF91827912987CC74BBD073
+5898D710810A4057B652E46548031A2473758D5157BE9F657D6AD6E598FD6EA797F66E6B
+AADF37C84C671A8938BD6ABB7B9B3B793EC1B8A70C1284D8C31B180E68BFCA71428EE2FD
+D10185264F9AE8049B64DC56132A74B609867D3B9D4815D1BBC83A6CDDE66504F2917544
+5FEB2E0203BE174203BF266862F83828A462BF880AB22EDB59CB180A8E0CC4259E4DEF1E
+1F3114AF8C03DC00C7B1F39027EBCC62D308E1A99E9C0B4AF746DB1BFC872B10C8D1275A
+93128F35E8883DBAE47AE1EEEC72ED408ADB618C32C9D780AFC63F1F4D3CA1784A0E483D
+401BA2C3E2B8B9A13307028DC563727C72F97C2A7373F9B8B664782C69999D827E4EA508
+585A47401D5274B658CC683401DB1B0977A4214BF0E747116F3A2C06F75395A4A4A5D8D2
+68E17F8AE00E264098436DC1054456A72D426FF4DD84EF7AE9F4C49434CF6C9218E7B91C
+EBA8EA88CBF22F4F2DBCA527FCD11EA79E4E5719E8FDBFF5ED895F5E640353DFD38F6D11
+BA785ADD90035A3D7BA68620F26CBEBAACC14E13C904F0FD147D0D6326D94B42748B7D72
+94BF4F97386309EBC593B8BB4AF0D09C2EC2C666CF0BC151CE7F7F763FEBF83F521CF115
+AE13A8C069F3188140C2E1208BCCF8D05A3A79FBBE8E58232A7438DE1EE565B56146C9AE
+4DC0CA21A5F17B05229FE0373C3291266A413C382CFB63365ECD9F80DC6CFF7C37CDDB9A
+98786B3130B61DDE400B3383D300974B9CA0BE9326C2843267B805D9C2BDB088156A7641
+704B203D0485852AB3017B851D63BB4876A3CA32AB30B87A3A9789D10DD76168B2FC0BE7
+2DC6037A9ED4315DFDAC2691ACBB975B777FA7460A851217B7328BA52876260F0E9A43E2
+962A80174051139EAAE4773184190EB46E72554267C0FD1B9388271B7DED405931F65479
+FCC4596027F11BEA64C684BCCA6896CBE3BA2CB2F71C1AA16B55F63D27CC239ADEF62E8F
+090863B0659D8E41B45B65F91BA24BCCB6FF5F37A03320282156468CFE46F95612300B5D
+1D811C58AE9DDD905174565900634F0E20AA6D7A15E43872300C876087B005CEFCDFBBD3
+10D23C04EA817DE15F350C4F90207637DDCD73BE0834A1651709EC3EBC1F7A73457ADED7
+68D88A2653796D132233C25030EC8E8159D128E2260D60F18097E68B95A56E3C590D4F0C
+E778F72FB0A5E182264651B3B93BB5115BF14FB1D71AD9C9EF953344C4E7B04B16000DF7
+0D8500FB657C4D368B669D92638E0FB331EC3AFDC59E75730FACB442DFC31FD087174379
+B491511BC6727E4C31C2FF756C409508979DC47972A9C0369BB61A450BC888B21213DFCE
+0FB400AAFE8B250112CFBDEE410B03F344E1C6E3A5743304D23BB7897D6DD6A052346AE1
+66C20F309083C0CC33B1B7D4909D8218AACB35134DF67F72752F697C4A6C568ABF2A6BA0
+6138D0DC6FF73066A5E9E559E0A25A0E4BAA0F0544D680C812E16F70CC0F3521491ED1F9
+747958D476519258AF9141DB94B1599F78D80AC9FB2AF393CC98B307DD3DBC5BE037C41A
+CA0450771CD31D126F3577A82E0D32E1E114753962A635DFB27FA9BE95240B38D4B20E64
+651847E20DB85F80D062E80D1377EE0D6A751B5C5E5F89E6A9F09DA05C3BA03ADA1878EC
+6EAA9FB0E3D4A8E707B0EF507256D60F76E25B61421A4DC14CAF733B03F43951CB3A4880
+7664484002BCC03695237E902217ED414DBC57A89802EBF93D4DF4ED83E5CCF8A79BA8C8
+92ACD02A4D1BC0BECB65C3D2CBFFB5B11CC143D37EE56A55338854EA43506FD200B7F350
+EC0DD9A283D0C46C5D3E728F920875DE6D3EAC17B025CFD20823D2C435C120D20F80F948
+6A37B71B68462D9C38AC003E66871047A6DDA56FD5CE319C209DDDE831FAC80D8C6BF498
+DC6B58592451BE41740BEA4766E0D71E540EF881A9110CA16E9ADF2ABD9FF296279AB2F5
+CFCFCF8020D42B01F4CEA91440C7634A4B901E5B2377D6F37174C692ADEF3337C616119C
+AB1735338F2E3AE72B22DEF9735318CF8B69F23E110D8439365C67CABA3D2C16FC96FCD7
+5076AA46F4F5B0DCE6E2D5250E2026609A76C41410B8CF45DC8BCB815E45C07F0C248BAA
+FE71A474EB9CAC749EDE8FED1AC13AEEB5549AC306B1ECF05DAE05E5A339ACCD9FC8E52A
+4EDD4E2E5660CB8640D7DF392BF2CA1B0864C01472B4ED4A7649719276F3709FDF5B890B
+6150DBEE2EF12390B63FAF9C65AE46AF648DA2CAA1AFEFA6982E07C63F810D044BB122DD
+2AA67ED2E98BC3B7505BFAD72E05E228FEB9FFB56068FBBBA1E8193EF539DF257A1D3019
+3B2E42386E6017DEC0593454C76E13DAEC50FCB81BA6ECC997225B79DF89783784083F87
+BFB92457456F60D9424C93CEDD40D4D462359E7060282A5A54E3F8F54C86CF6740A8AE60
+C66DEF9B52513D70B64FB40671EB762780F36180F14724069D029D1B43DDB672A5A6A9C8
+9BBBB54CE48D4D25E61A670344B4D8DDC7E57ADADE6CA7A1BB5134276528D0450E5DA9C1
+B8DDE79D25D3DDF220204561E67855D168FD7ADD01F497AFD5D3E89DD83E069486F55B59
+B91823689873ABA14D5CEAC606FA8393F1B34582F871B6C4131B9C483A4BBED1CD69BA47
+37D050F57ADF9C806CECCDA795101376838E893016CC92DFEAD0699E6BE626FFFAC028E5
+462A1E7CA9AC3FD199B4C4FF894A3E695E18646BA33B900365CE6B810C7D53DFCBD7F8D0
+D6DF20F3B09ABD2C7E862A5C8280E55612343FB741297A6BB95FD9423C4E0602A8F8156E
+365AB54540AD5449FEB3E4D13C94794F17A0BD06D9E26DC3833C87FAA477041D1394E0C5
+993507E130C4F60019FC0B4B74652B2BEF4A9603FDDB3A534001448A8F691C0A97267826
+1CDBCDF47FB4B0A7830B434F180625B451173BA129726834181EAEC346CDDF68F32A57D1
+5ECD44FEB77C2054908C6F6CD73DF94E4FEB47EAB786106F25CEC7020AC7BCE0C45F7935
+46E02937D310ADA5C46379838E266B25127413F0AAE1AC370E3C753C6A7539C8AE525CE8
+9BA7C49158D4205E10C054DF541B7472A0A6040E68897ED029F42E013E0B8EA547A7612B
+157718C7ED485CFE6CF0500C88A0CA1C96A2320535EAAFEFA930325B59E551C8D57BBF90
+2A5A7785E69CA885CB7456ED7D063C93161B7F0AB5C4A33B19CD8F9260114B75BBA018E5
+CFD6EA1CA19DA6A157C632769EEA695B634311B4168E776F9B81AE354455AB0E9BB355BF
+1AD45D85173062B1B2E66F2820512ECE3A912A5383AD544FD4B0269E30EE1D120EA034FE
+5257DD2B857C4812CFCFF94EA3B8AD00E18C2AA887CD8E2801740C69E148DCEFB34B4897
+84D875555B9362A35304998FBA3FBFA98D6902DC326F0F407751DD3ED02C77F9B22D768D
+B8C3BE360CED4964E0D413D9B288E403DC8E6D89EB0B68B4BD3959B151B45FA8BD1967B3
+70D20BC10CBBF7F626F1B4C3F125833567B9E88DA21EF2CA6C209DEC8EA977752467090C
+0467D01B5B0EC2ABAD8596A3A342B120A7E3103B009E8BA2B95378DB329B917C95587A82
+EF5F72890BAAA37264BB4555F5C69D10A4E64A462ECA8B4A1BB166D88036BA071BC33DCE
+3E79FC9F144BC2E446B720155812C06F10752D1391963AE98C4CB8B035C3C8E2F7CCC529
+ED8AC3A052DEFD0302D1F4D5A1BDA6B042C1D90CF84123DCE6A7C29B3AC8FEA16F07A210
+3B2C7098ACFE7FD92682FEDC1132EA886581B798496D59B5AA47CE3BF3A9C7CAC6345386
+F60ADD73B0D52642F4E87461B1C2792155D2123D0D7BA43904891ECB1573D871B973FD0B
+52D76A445B55F960BCD3AC44BF762B7AE12DB4FBBB0409C102445C759E7738C4D3FE2BAF
+B97DAEB3517F5FA545180AE55DD7D4A0BB03EECADD21902226EE99A7156689824D02FBFF
+41FF30B9D94D14348BEAF7D3710725E9A8054DFFA2794D7D5A90482E9A49600885043C5B
+E0E220ADE6CE0FA63C5826CADE8A8363440C47E6E7590CC8F5D445121E8F8B947D8DC4E5
+DB5301E89AEA62B903ABE3AADD4E93A49A83B0BEB040F7F2C320301042CC9D31CCCFFD70
+32DB766066FC83EE7109C6D8DA79610D5E1E94848556E4DE9FCF55DDF8BE524361A4D673
+6F09CB8AFF3347C41B9397538ECF26274DCE7A27E76301007A492E0C6BECDCA0B1C9D1E5
+345AA204F29F361FBAC0211BCB444F8D9B9637791F5D3B869A5117CCD73EC5124F1ECF23
+705209F4CA831C5AE5BE9EEEB390A8666BE40363642DABBE28D1E06182A95ED0F7D1177E
+D3294B4C29D8D1FAAA210543C3850FBCBAC813C21AF5D62621623DA41A27F9DA0ED6B0C3
+A2AB61A913094FA2574C52FA1195521962C8D6B8DB2A10139A9C09AFAC133A8BBACF0A86
+01F38217602E70DB3651DBB083C791E7317694AD1F50FAE278155390264C32975838DE33
+CFB0ECA1B0BD993C2A02E1DC2F46293018DA3AE825AB81621894620054724C3A8D95ED48
+1E899F972E6537B21FFB8A4C55319D15A03ABE885C333BE19ADBC450D58C5DA2B76DA6E6
+2487A71FFD2A851F0551F17A00D165FFC44F204565FD24B0D11C2C21238F5D6F64277FDB
+4D0704DD6271C69F4A5CE05258832BFBB7D303C00EBF68DEF694D77215084C74BD2D89C7
+8FCFA635F694723DC79E99D87F03ABD7A06BC1BD7643092790AE2D15D63D2C98288AD284
+7F48081116C31D98680BF2C03E4C2FE4DA45851E4FCB6FEEA80294ED5709A796716B134A
+8EEE8ADE6C3709541E3D234F952B4B2ACD1422756B8765AAB9C32338736207BFD12DC05C
+4D7496F1AC0797D5A3047F9449A8C5237C75EFFEB8E157B262A833BFFA03A26CA8AA1188
+84426DA94B43BD21B1028EB2A6A30F41179DA886DCBE99AAB28A1B329BFB743ABA0A2F4B
+B4C400F1F3BD3C9A0109F63EE563AFBDC1591BF3CFDC863429A79F6E0A21A749A934EC7A
+08541245B9F3CA401EADE0438C18B9FA2A78B618F38C611F6C053D2F6A0726CD20687DD3
+B09863DC0DBAF040D15DE51397DDEF2712F688D291B71DB3F59A7D87E2F44FFED1144981
+A11BB9824B1F4FB6C9A1CB11867A187796E5076C811A9E085EB5C202E0CDE461CA541CAC
+D3FCDB4031FC78D7410C4D1DE558A5B697F03F9EED11F731678677448420B876AF142242
+574C740985FD2B6038AFCF1A81C4D89D00C73A09C93AFE68E5158B06B1E4A5122A371687
+93C5744583791291A8B8C2CCADC8C1BD233285F91C87566E36545ECBF3A8D5F9B3721292
+8BF2218F2242E3F19F91120CDF7D7B118392A4F3742911D47C4B6B2A61A7F79378DC8DB5
+9DB041A761DB0EFF44C948341C174E5C6660DD5D3E5517EEE0DD88A655F3F9524168CDB8
+AA2A506EED7498CD8A320E2FA42D10B1F16F8FAB5B5E85DEA6DA3005ADE58DB47E35C71A
+C9527AEB0DB1B59D7DBD35A5E5C3643E17139FE1BAF662C7E88031D01A9BEAF71A18DC76
+F8AA4EE94C2575C438BCEDE9118D5124135A071E3DC0B103DB08D7277EB7E9BBCEE953F9
+77E01A009A031D4A204B87C0F0BB722508B76E4F4ECE45295A2FE89A1DCD981EBB4F9877
+246527356F2E8DDD3A67C8A39047F4DBD69B37112BDADAB6342FB6C522FA37CE74FD74B4
+D37D919B612C91586A2F1EC2E1AD95A5DA5F6FC0E260362765A262386FD8B9C27CE5FA84
+EF0B7CA9A77B1C41DDB5CB9450AB1366C00176A7D47DA6E4BDB2C1C548426B69987EEAE9
+66F4A937FA6597B2A1F2A690C3B467C57DC1A6E271B4B4FB7A60EFE602B5A2CDEA496F54
+073DF69EE58BD31963B17870B41EF97E852E286E1EF07D48FD2CEE44F51FBE8FAFE8B171
+82DF3D6343C85AAC1F58494274574A6231652AA194027CDDC257B942A7FA1E9002E9D75E
+80EF552962CC5DD48735A14C8B81020C167319755636653041031E89BD815A299BEE48C1
+626BB77614622D88D310B0E19CB4A9E57C174BC369BF13C727FB452170D9E830ACCA78FC
+F7F0148CA9BC1EAD7CA3BE325B60C676B3C5AAFF6FCA80FBB8737C7BDF51549439E06B38
+79D71DB53A757EC2C2D66FFE2CDD0C166E2981980AA2166112BDD1B14C19916A14403BBC
+7E0FA36A3818F6B4D4711BADDA0B113F6EEE39916EC8952E6A7858BC65BB175488A6BB74
+6E78C5D7C565EB59ED211C5DDA7443653F6467C403F9725AE83953468488A6EA8237CA9D
+538328329A8B23D3C96727A7BE68B59048E394D2BD3E9B5B97E6C88DB0D3B2CA42C1E845
+9B375667990B8B28CAE32BB63B8973E40533D1E5FCB26B2F680F985DF33F37AE6F32B9B4
+CDA270B0B060C8E511A0220EF06F0BE429D2B977A3782A086676AE58C244D74E364533D7
+467DDB36A7B93F27A9B729BB3F0087C01E6E38ABB26A2CCBD35F2AFA01C1A085535F4427
+521B968EF7DC76BA612329090FBCB6C99F73A61BF1B3D0975F2C7457666994C94C5E6FCD
+4D4CCF29DA3E355CC64034655471885713804F44081F1F4C426670A0390BA6D2C25977A4
+91720310D0421B3D5FEB3C88BBD35B2D4132497904A74C3535A15B924023C464CD70D227
+F28490233A568AFE309F6908C0F369189803ABA18497C20B5E47D5D969DA3EFE03059316
+C0CC37688CC42783823A1618AA7C0AB924CF1D4B961CDA7DC6FAAD0E8F742D33ABC15730
+CF0E246173CD0A8F21466C9A4A9F86EE6ED508BCFA0E4AB5AB079F1EBA14D78E4B562F81
+4A1F870260F35D55D415CD2C10EDC209F23BD8A0A0ED6FB8EE11C30EBC2250559B02221F
+7861C08C18BA12E748D7181EA7314E355E27EBBE1B3C00C69C549D4442998259D9966E9A
+6C89F9D8796A0DA2745CE68C3D15368621F9AEDD74264565EFF245EC7D5E235D524D19A0
+6D1512B3A823AFE1944DEEE38E6C365D8EF2917C382A537FD94DEB1F7A959A69A3990033
+F48466A241B4B39E8AB9643677BF42BFA3080B8B389DC2BD74DD9CF7D2D466CAB7CC7EBD
+33FDFC9CBBC0B2A0D3176B3D5D9C78B121705E9AC8DB4B76711A8D299D6EC76386C78241
+FBE1887604B50BDAA81187B0987D0B7A2108A32BAB0406AB8977F4EB25957E88F93D0CDC
+E9121D49CD3FAB7EF4B4627A731C43E7198EBF05E662A2A81F46E0C55510B6D47A5363BF
+63A34E483316B4FAB3BCBD0F190F554E8133E1F31745424E0B29C031D84F24A1250CC3DC
+28384EEA40BDC069C457BD958A8D2ADDDE965903B436FE8BABA1D722F82B6BC781980B54
+86FC63E2F918716776F756BB91752A0F591F518CD941AD6453AC1D5ADB8016E17F0367EF
+973A4F6DF74BDC2691457DB95EA4C5729031B8397663BD0C4388B8E514B279F0F003947F
+9DEEA6E76F6C3D3BC3F64987B5AF5F7D520BC76119DD36265453DF598CFA741E9A404704
+4C2AE3E1E7472CC11BAA4D5A32304447DCE4A766DD19A50542BF90C3F1F93BA6669BCF83
+808634A13FD2AE46048C42A90A8D0768E3BEE2B902E564CF27FAE1AE71E5862A8554967B
+1BC8FD84EDD3410EADF57CB3E4617B65B26A2B90CD6D47E7796217B51BA60D29D81F424A
+4590B5A8FAB9B7404CD142CA01B5ECDACF659A4B4997BF1D1B6F9847D3BF5102CEB53754
+1410448BF07E8E49786A718F56FEE3966C4852147B9193233C8008A2D2DFB70448078B95
+81FA5F9CFBBABBBC5D7E6BED86C9E69E71FB53AC96FA096AA8E6E46B67BD96A58A18AC48
+854D5C6466329B0A9C7C910A0ADFEC02A784B3553FC43E4C2EA8E1382AB1D9C103CD1260
+E3709CD18400AF2936AF02BC37FC32054A73CBF36B98521FBCF62D4F25FC7E0F3989B25C
+084FC5B84F16F1812B52D7AB115F0A80DA3D846A3DE4A83C512778B469CB887EDEA0FC37
+9581C927228B510F441071FC705C98024CC64E9BD21CD7DF90BAE4D271DCEB183FCBAE68
+DC78E977A8D23206CD3D7E3AEC0E8607E24A431C6E24F649370C897A65FECE2BD91C7D82
+F7A1CFA96AF95891FB8A2806CBBD2AF6DE7205E8E7269DD0E8703758F93D0BFE29CD178A
+62BE495A0F7574EDF1679AC65A72C43131B63AA8507A225C447CB2D71E0974A1405E5CF2
+E13C7FE15F3FE046377500E9C4A1D0C2825E49B8AFFA5B54785B39D27D181B0AD38E0E1D
+35C03186235676EB44E268F6308B17B45B2AA604CBBD05E33497F4788E969E01EC50A3E0
+F8A6CDD1CD8950505828E16F2B85AED36EAFC45D9466045D43AD9B3B3B2B92D5AE0A383C
+4C0D8C27BBA70E4A6E7F4D134E4D684B9AD5BC57F19810F88F618F49C66DB98D76F950C5
+25AEDFFFF5641D0DA2532994BFA810022AEB15505DFEB561227DAF7FFC9B2E1578108ABD
+66424877BAEC36FA8FCFCD8E23ABD236399F4AB2FCD5CB2DC84B80ECB9C6EEEE7271999D
+37272C0F8D1A306814BA2D302F7A3D8C08EF5375B38450E852820875DD008B55CD50230F
+9F1C513684B5A7E0BC1C992804AA638CBEDAB8D673556F9ABCAEA81059B0EDC0193FB823
+92E4D7B739E8B0053F84B7891434CDDF773E15DFD66122A300E0A561CBADBC15058310BC
+C9E44582D513D63E90832C521CA6F7E6C70D3A9F461BC33908F1773575043419B5310F74
+1FC502C5E52D7CE3421D0BA35BFEFB54E477106DFA69677F822FEE85CFEAA54EDF1E641E
+D5E73F733F3021A0CA6F5CD5EA5ED8C09B1F3B1CA953E92A4117839A678572DEADA59C50
+BF67C6367BB03CE4FBFEB71F652918939FF2B61C6A89E2278D42FB30BEAF2CE7E6ED6D59
+CC0B941DBB15F4BC70AF627817277ED59A95A3FA22FE35AAB686FF442237C1B4A9FDF6EF
+62E4F90266EEDC96AF7F7D538DF26632B6189C2C74F62106734308EAF30D9A6E25A8FC26
+12180B467359D44B592BC4679DBE01856CE65D2E0FAC04DED5207CAF770198827720A708
+E0667AD7A3EE70879A25C40D468E307E01C4EA8B0FB67A854674010A90CC42CD6821F717
+19055EAB05AF9C9856C6FB31850960CDFF7CBA473C4098A45A1E15C533182D146B64D9D1
+BCC4EBE36F926B2D4BCA8737364CA448CEE8A27610425E06420404B99D7C2FF4E02A90F8
+583262933685471C74FC236671D814DE1F3016BBBEB1780E4DE6489CD71F5DC6DC2BCAD8
+D742B695074F28EB6A91DA6977D8BFEE0A7012DF751455F36459FDD63FE1D1317858A2A0
+EBCC845331CB6BC509661F464ABB2B3341D1AF150993D73D547DBE8E13A249B4CE85D9D8
+3F35B2B7AA450CE28CD22F826F69F7B1F7AC8D802D97FB20536ABDF8CD275E67C22674B3
+1C6B69C7C8410B93FA3FD167764F2DE0DB966B9BAE9168554D718E00A5017263D49F1CA3
+443F1C126EA11DE16A4D19BFC9BB8AC52A5471D755EBD49B535760254143E163B22940A8
+0F2AC318C264DCCEF794B02CE91CFFD152416C37AF6F7F1D151F4143FB808D10D635E811
+CBFEB3EF3C291F8CA480769FA0D3D80E1ABB4199DE5EDDFCF720D95B1F7E57B80D529A22
+49AE1E2DDCDD4CFB478E88CA5EDC7C4A97B7BF8D1DB4CF194227B699D1A5884FA7163E87
+7117F2A46897135F0202B6AD25EA7BE2AAFC933D1E3761F0DA9432A72BF4FA0755CF555B
+7DC892A63879333E1D5C4614215138BD11967D5746163ADF35C13D81DDC09045989E9AFB
+668CD3E34572836F7ED5981CE6ED895DBD5B7BB1AC7BD9A4A197FF9C400050A97F8684A5
+E9732512D1BA6C9F4EB27773CED4ED9E63DDE7DE003BA708798235CF66D0C7517AEDDBAB
+F667F6AFC423511BC344A8CF07EB7C697072B9CDB4958C40685DD2C6317B20ED0CE5DF6C
+204B8029D48783B1AE8EF5FABFFAFBB42BE9D26B4840C04FCF826CF6168DC1533BBD3452
+7D2AE02FF4237675F45ECF4C1994D45E0A15E6D03A3E399BF9B0821AACB73329636833A8
+B4937F8DF6DC557D20FB4C1A33D7E7A2411BF35BB0888ECBBAFC4F1DDDFDF71BCC627304
+C4F92B71BFF5D96A822DC9C71687C1FD37299C4BB76B7F2343741882ED86E05FDFD97CC8
+76EEEE402AC25F9B5945C48629A605632DB0E7D210CAE8C887718F10FF689AF3BC23E960
+A1872ADD99BDCB14CB388B4BED0C9730947ED47775DC9A2B028778ADD281B8A7107C7348
+FF35B6403BFBDBC3AEE99D2DF222D796BE4EEE6071ECA471DB5740647D136B49D2FA83EC
+7C12E402BCBE75C7BE2CB2C058D041A3A390D60165866D1B84A5A21AD65E5B7313071ED0
+CF488AD4CB6D7BC4CE06B620262D4C3952BC443E10EEEF07FE3A1CC72F2921AFA14CE11A
+40655EF499B2FEBAB39B530BB27682D3618705104D6A781ED1463EF6217F8DA8DB308E47
+2654FB4A1F5CB5A147B50FE10357E109DCFF49AC818F53621619B37A9FC57A5DAB97F829
+82D2A91D92888851F9C58DB754808668EA721894C859EBB4E09123B8E21AF0D4ED31092B
+1E866C80FA135E73CB59677CD3E74925A82A6E8AB6A1E28E1735E2BBA3B79CC8D1D6531E
+A41214CB887AA60C94B642AC36F9720A420E64F321A474FBB57576C2B0155450B51EB175
+D39DA3945AD41ACDB958DE15C25913F7C3D7C0AE3A6CB987835B26DEE2F92FB85E7B872F
+1035CC7E7332A9418126BD493C892033FEB7A254B47623F8645C52D240C70F1FEDA77C1F
+87A90806E9AAEF356EAC0758714EC5018B1B481B79B416A2D6DC92D7B22AE75894517C16
+C3DD09C667BBCBDD6C3D36AB00B636323B2B6116125F6319FB4C16A57764E8B879086C2D
+F146DF03073509C72932A516FD7BF9F9B1936B643201F590D1D551C2C5D48BDC93785B5E
+67F1E6EC0A5D14D59A190CF6894060C1953D2DB3C79F48844F7A0B0F0FDC3AEA8A53E33D
+577B67E9213ABFB350929FEB36A97DE7658B441CBAB1F0E26B3FC5612202817A5C2F423A
+AE4430703E9FEA99B861C4A8CC09F79AC6E6F53DCCEB0EE7847CBF73ECF35D4F5530082D
+1AF3AC71BC3918496CE6AABC23D61A98D11BC6D7B40885FB6FF6AC67ECF47C6733390DCF
+A88F9B9326B5D130874910D3E479ADA40777274C02847ACEF3AEE8E0DA0434C9B35859C0
+3D23BFCB376446EA2DE09F42AC3713F0673D7DE567E8A0A1B15A1DC88FC081530804B744
+2B0681289D586D9757631803ABE18DEAE727DBE5DC052A0A1F0E70480DA458FA96A010B9
+57E4D1CB0085713817AFEA72535EC98D71B4B9ECEBE04C51974D94F874B0E3E74D149C96
+BEB4CBDC17D81564C3C84A14F5130A08AC7B71F1A2B81CFF6682062EC4DC6D8E1BDC312E
+ED6ACE315A2A28C772216C052947E079071314DD07BB321F1EC8322F00CE57D3B0E53E6A
+7A2B9002F1ED47621CC255EAB1F3152D5CF2456764014A5DE60DD0CEBED98B584457377B
+F67065F706978C6AA2914A68A942DF2B2742622007655BA8780AEF5086CE17B67B8B3AA7
+E432EAE81226FF8CEC95D0498BCC0FE737DEE690FEC30B80F8DD74F05B9B88794A54611B
+C12F61CF8BBDD49F33C5690E1F03DE89937040BA0775FAEC6ED05026ECC6DC4D0A0EB441
+66ABCC55B3194DFC9213025725A8EA81A3290031FC365D3741922FA26E1499B93C2B59A4
+BC226A3F86FF1551DAB5F9F850ACD311DF36EE86E5B3EAA4579972223DAAF9E475F9BDA8
+4D95A89DBE06611D73BF0717D1FE0258086C1B97103CB62D8DCEA974B41388C00F176979
+E8EFBCF4FFE9144820AF24BCC47EE0597276455F92BD1FA21FE19E1D98E6E8D6BDD6AFAB
+E61C7B650C109A61E1A3C6E92A6F2BD8C872A32DB437E2EFA5A19641608CF2D5E109952F
+8B2D9C0F0B96322665B1698490E37E860900EC392CD42DD9AA6DE6F0E5A5EE7BCD34A538
+95D129885A10D9446993F5CFB6978DBA5B9BAB29773756B9867E4A2561AEA643414BA7E6
+00DA0932D0252E094EEFE73E2AB163397C2266CEC81ED1CB7724335E1FDE7CD753646810
+F94A631F2DCCED349080D4E9BA7E9585E3F52F77114012C081C806A447BA8AE735E406BC
+532B46F55134817DC0B30496C6F5367A4DDB55FE033A236404D643C4C3DDF9D8DAC0F165
+C2B8BDA4194795FF0146830C21CC1E991300548E7A0A0B032BFBD828A960FCE987A5ACB5
+E2224DCCE6CEA1F7C6BE69248B6044ED317F1F3C028142B52DD60DDEA986214D93685E9A
+F3A2D9F7899A614FB41BAE93640B9BD10CC3981505415BD61325AE4E2EDF73E7AFDBDA1A
+D4DD09F759787DA42A474F1B6C134AA6FEE8CB1B5BE1E9AC6AA2D1E60F7FE74EB2FAE2A6
+BD8874F746D14A51F860741F5DCB208C461F8118A4741573CE37DFC57E8B6EEB1D369758
+7956D6255ABB0E047F04D5AF7E59DF62EE011BCB403ABE71C63490F9E3F28096149F866B
+480EC82AB9BCF835EDB42F72B33526DC06CA515920C92FF73CA0C1A1F1F61FE8F373C486
+5DF775DAF6C7BE60F2DD4232B73801BE6BC491FA63205730E4974A531F1E75E74A9ACD2E
+D4A9A9A45FEEA8414614B535372F94E55BF70152086AD2738807B85E0ABB2F5AF149C8C9
+9A9F38A6CF85E31358F8846145F428A89DA1C26DAFCFACAE7992CAC52BE50FBE0EE43CBB
+2228490A00E9716E513C434DFDFC38263D773404743713BB490DE92A2C4F3E2E67032D40
+B31649A0672EB3E41079316EF1020DEE6DC23B95B093FBB87A0A88733645423F72CFCA9B
+4B499F178EE31E5C8B8D432D5872CDC09713CF21DAAC84AFC235E8AF0F8DD6D6CE213937
+7314BABC357F9DDE5B3F2EF4843827A6F0D1DE9C8D0DB30E14F9C94FBA3A7726D6479706
+162D0071B70C19CF32BC2FD0113504C82EEC7669A66331267B4EB18C5F1902B6B2C78C3A
+86E5AA1D2BEBB6AD05539A612C230DA216C24B40029A8CD96B8FF0FF000E816B6A7C4F70
+90E217124A1D6A78604D5A340C278BA9B16CD4B5518E0376B3C518E1493AFA9FDF83C36F
+6F28785DEA18DD992EA6C2909ED188A31E933A0F5B521ED9C46E7A70BAD32D05AFDC381C
+9EA3D56E2E8C48276A82F9EC08440D6468D0DE0577EA8D5171B678F3AC9F3BE2D5DC899A
+4D945959C9990F334EEB92F34B88F256FFA564C591D5B18F79BCF9817E827BE4BA219423
+252095B90DB4347B2D54F2BE6D31B87B525D103680700F13CC1C0F72B0DCCFDC01F2E924
+B5E1442F21025659C39289B7B4AF03169F584C49D38EAC00B1910B823745054F00B322CD
+174BE2AB28915D81A829B6C87486ED7EA4D44D6EDB6BD69C25112E0387FE9826C0F3F2BA
+D1C6BE26E603730DF1C4CB227936404E138136082AD61492923E173484955187CE3DE172
+0FCDFE244D85D3C5716B7A4338A8130748567E0044D3D9DAD19A9785272819ADC5CC9876
+B764CA881499268F67D6FE0ED4C73D463BA920F27CC02D187573082A1793D228D2011E2F
+59A15D7349B2EE7C9E7BE1AC231DCBE9DC98A2796F5FD4A5853B8BAF6F266520CEA0C42B
+0AA848B977E9FBB93F77CC2F6224A339242BA2D7CC565373E3636DC0CFAD06B7C5C8FF10
+392C03A29675102DAA1E7BD4D45A2BCB6F6C73F8C3A6DA9D520F858EE0E4028FF39A7C8E
+AD10A54E91112AD1A6BB7DFF7D3421533DE306FD859D5F750268EF950F4CBA3623B38703
+1FE153AB39B304EC57FC95710ADFFCAC53508224A7DFFF79AB8A24E4DF0846926EA4CDD5
+665E4F1734764B53C911EE8AB436EA08ABF1FC7BDFDD754D22C6CDD1D6EF1786C10688E2
+E2830A80A5AA37C08D1545C24EEA559618C927E4E5A1D6F83CE3CC7B100D4E04561B1BA3
+08A400644C6B49F4D5AA8EC1B5D769D16B28E1FB6DB45B118FD348D2A6F241766EC0BA04
+DD24F51F3F288D954D2C7E3B402361D6343C5A26F78D2C220E83D33662BB0CD33D84209F
+7AED4D30489645AE647D045AB0BD56E20943BBC8642B2DCDDC09F955EFCD74F04337A15B
+9DC924D48D1AF6AE222B76563139CC37966D32937FC5BA436843EB57761B9F052B0BE1F7
+132E40D0F0C783CC80B728B75FB600127673C0FFC2838A8B52AA3C957E978000314DC091
+9D1DE4DCF84280D7939ACCAAA46ED513080442D497C7CBB2EF36C43CB3BD66844691DB7B
+2F1ACF8D9695E03F747E3C0CDC2105871F13D27C3FA07E30A27F5414960DC3A51AC1B569
+F30811EC03218F259BA3E4668F83F6670968C7DFB3E7CFF0D12CE126E4C27DE03595C823
+528C95F4B1C92AE796CD890EBE3DA9746B92A835817B6EAA2FCD276A77436225C44E89B3
+6A0066BB7AA1E94C3203AB45A6E2DAA5DEA3B0F0E068A251CBBF98D376CF76ECBEBCF3E2
+1F375D73BC558151341B01B27E16ABCD30F60FF9A91AF52808606625051C54ECFDD28E8C
+90E211E0174A616C68BFC718DDF2656FA27BE3DF485F050BB57F96B7D1F6531CB2B73B46
+D21629F201D40C5A37B572428805651E2EC179424D8F5251A84384783A83D2C89B6833D6
+D0697FFEEEBFEA9C8CA21A627F50A1168EDE8C5E085B5930192973DD939E36F10AD90B9F
+C02C0B116F922ABDB2A94213E4D9AB7903770FE69017FA7B28894A5CC4C66930FA7FE05D
+35D664AFD098B8A76C9F2EF0A11E36B6D7362B62205AC9282D8082C15E1BA41E8A711DA1
+CFD28A83BEB3ACA3F7095FCE5880F18EE93F9EE03C706AF5547B198B4A08B9731A61141C
+9A953B2A5A3DFEDA3545EAC5D7D8D556E72118187899AD1D13D51B44F1E422F4809BF42D
+FF01E2F05B9BF68849A398CFC799771C1AFC256B7D333549A0A71FB7A8813D5028BB8F2F
+397C1A68F22F3F1B9C2B7C2D4F4EB721E73D6E63BA651C802CE8E57F5CAE8C1F6C4AAEF7
+BFE00547D8344D7741BAE7BA30F21197146C8B31523C1C651420D130A2DBC055FD437CD4
+D92E7DD74D6F1A1027CC95CC028F44F2C5B95E72CD31F200B0A3584946E55B9A6A20163A
+3EC73566552D848290C8EE0C821F08DC9F1AD94C9E94E8C5B865BEBE2047092AFCF291BC
+EE941AF3156D6C8AE07E63B81F27937759F91A6C8795051BFC02164475850E295E6F40E8
+4DEC3874F6762DCDE08F738816A14E5D5423590D87B85F7E0E88EA234561903039FBC1F7
+70ED97405878F62A7AA078601FF5277CAAE4722171DF7954AF82DB007C56E59A7A59F133
+071E193E18D2D24EFBA31F3E598B9FDE11C0416579BA3AF70C8F7F0D069C3BF3FDCA150D
+ECD1E82A3D7E1C11F13D37F27CA578A761A9E5EE2B425EAEB8298120429D457998BCD81E
+81531F1F23CC05417FD802E9C1B7FA92F129CDB8F498C78F9B936FBDB2EBEE402AC25BF3
+CED327EACFFAFB1619E023F018E22F30FAB458228AFFC545AB15D66D4A0B08716E484F4C
+FF688C67B70B3878ED20939A1EDFDF9D62FF19EBD66C9FEA31F18B6221208CF315DF5108
+CE58848845FE2386F9F916108102A8EEA1E6A4806535410FAC7AD182F6F317E0A864DA31
+35FB3C0802E830A039535E66BB3ADCEC299454B7966FEAA81861965F79C0578D5D48F3FE
+5FBAD2239BBF5F107E5FF42EE8EF094D8586E8810522BAA1E231B4FBDD6CF6C62D3B36AA
+8477D9273E95D66CF67F5061EB4E3EC2048518063703DFB7EFF5C2F5A3968FAA705225FE
+9E088D592EEB980C54777F46BB385CD979BBFC34F3870583C13643D449A49D275E38FB4E
+A31E0C69CC3CD31BD790FD0960EEE331BC1C7D47AEE5ECD11D6EF0FDAFFD1FA2C0F33C85
+31357F04EFCD25B6CA2E0800E7CC8B467D4EC22FCE69FA0F1245253B8B3E842C10276456
+ED5D4BA9B19B07B8AE60115D4F423228878C7E6461523A102F03E2C997C826B0E01A8C74
+737BBFCC420E2A864B051B219EB2F65AF711C8034EE858E8E41E93E80D519D7D5B78FDD0
+E4BC44CB9657C8DD9C37EB9ADC2E33E42B02DA3E069B9B20D7A727DE8070E17FB032C9C3
+4F5623EBABB58EE9097C85E0A2D93279EB7F6CCFB82CC798F06208D106AE7E811BB77F43
+E4F96EBDB0E29E9CC6CFFA79A00837A14A424A9E97B16F52CE9C0068C43523E286038ED8
+D91087DD7764B1DCC9FB73CB72A1AAFC3A09D353C64A8E3480D2C3E9D1F583E2437BC1C0
+529AE01639F1CB00AF09CFD84C38037DA70512DCB7242EA3BDADF8429ADEB743E5509292
+37BA921D7AEBE87A100E99B0D806D0AA4B3BA6740FBDAB5D1E0FE3716EE4957BDA0258F2
+70B527DFB9E2FE35FB0A6AB0FFB583B9529FB51BF336852ED0D4135E6408AD228714EA74
+D76CA630E0AE366233CD90CD586C9D8031173646A78B88F1F88B409110801D522DDE383E
+93675E5993EC6C007C5ACF1AA8D0F10A85A144E189273AC6E135E986EBC2A85074D3C290
+1AD3BA21B44827EC7A55EFD8A429FDA1DAD0929E86FA7692CC46E7B312B441806598F2FD
+6090A17540D1140AE17D9A96678347EFDF0B510A8BD31A07F26FDE43A5E012D76BB72FD8
+8A70CFE950A471C724288EA13FCF2A5A7A3D54B2D30BAAACDC818C588BDE628B30011DC2
+5CCFC66F6C7C5F780280D8E4C421A0C30749C2B33EB4AB3882CF161E116498C4204455C5
+B70C59800A0530493F63B843B3BCAAC5F025163431DF3FF39FF9330084D41A696DB77343
+7C3DBD4E794431B80E72838210F2BFDEA75DDE26997A6F28065DEAF13EB71B0B098C8209
+3121ECFE486A0CC366FD76927D530C3448FA16790C4A96F66274D5E7A71427AF984C5004
+620F3011223C4556D8D996A9415812F1868EC9744B1101FFD7876B0F0765CCA2E7BFCEFE
+6AE75779A6AC7876D5435153A48C4B931D23F7AF10A71532249DD0BB4F52514EB90B98BA
+7EFCB01C47BE21CF5C2C82827AECAB3666D9DB46D415C31870CC7934BA73C5736117F639
+45883151F82A1728E5E591DACEFFC0AEE8E0234EE158F45F8CE995953F2D52D0DB5D23F6
+E02079E115F3844925501E263EA3EA7C364DDB44BA125796D630202D46DE831E5FCA2BF2
+8709E4C2A8139444CB401254A0149E4DCBC69AE1438FDC782A6DD7D08134A27C1C32033D
+B1707A8CB8F458B3FAC6643712117752FCBC008F2EEEA842035EDD4E50DFF848E20201AB
+074E662074C5F57290E7FE6EC37D5C1C11EE8DCAD4BB3CFEF95193F16A3AC6CBE11EC609
+111C0C056856B5CBC8C5F59CE7FB37CD8F3B53FE0EE6DCAAF3C933B849FD60852EEADBEA
+C506630B94EB9814AD4A9D31D2F355A3A176685CED59E6F2A6F61458311635006CCA9833
+BE5552DEA87A360F2FE23679A8C5E05A5A8C395FA909C7BC287C6587D2BA7C4C22DC3396
+0BCD0B32BA37DC1C1F59E730B8F1ED109E215993B16FA35C7859B8F8F299449CE26091CC
+5E9A4893D1D1AC688865BEBC3805855B245A9E90F715B904B9761E3EFC7676E9DB688EAE
+D6C5470282E8F065A2CF7CBE00FA66260F1AE895921852BBE6CCC06732EF7290620A1371
+3C98977827D534617AA33769F4A89CE899D29A6048516B0B9E764C4B7A668470CC188EBF
+54D31E95714E4F85F3EEDD46DF34786702A088B30A31D55BBF6EC09153F5A170E28FC2C9
+F39EC3EC34BE68B1B13F39C7138B176B064210B8751043F03C35601891F31570D77B94FD
+05420F77B5BBF0F15B62C06CD8E026D7402D53D5455D608D9A903482DF22066AA82B0927
+918EFC606CEA50534BBC94269A487505D937C2A0FA09DA28BA69A0B90EA305CA02332254
+5AABC58727B5169F010548A30B750484B8A6F33BFD0026BED604C56CE9CD713A05FD9816
+C1A8CF1FFE9A458AD7A3A0B0F4FD0E506608C58669AB9809DAE774920917406CA8E68F9B
+E4C6B9D36C0A31494625FDF84661D20DB004C8E6C1CE34646992D7A2780AA7BD04B7C15D
+8A696817A5D5F4A00D9C25E6695C383C273877B1F75544713AA173E9892ECFF80CF54382
+02A2513C677A4AF1C3BFF5B282C807A77F222ACF5AC497A36DF8BA7C537391827360220B
+40F2AF6FCD3D3A9EB8847899F3FEEBCE598050D7CE593565F3CDDA813453B62983C0D90B
+71BFE793AA1B2F0CE07F43C8D4DD8BF656EEF5C6C3CF0FE90C9891344FE3F4644ED8E98F
+6C1E8C00726BC7B8D2AA8AD0681339EBD2B1BE983E36988BB22257DC27CE5E183AABA617
+D9AF549235E8EC30B37B85BC3F371764AED219FACE0CFEACF611FEFAB312466E6C02B341
+904ADF69B17706D8AB2EA734D8895813DF940ADD72547D373DCF82D1C484D7544B06AD93
+3C4D95655ACBF08429DC60D26DD8690BB9B865D0846FC0D32117612B8A8DA0D6955B38E6
+7B7EB2405F7177097ADD4CF54475866A52BB7FB9DBF8055D96586EC8C634DF0768B27E29
+92CA552A1E4B920C56DBF6E6C03A74745A0AF944DCE92093C8BAAED7B40F2185D776081F
+5B3049BDF295D0C4EEC9E3CC12F9B19922A76724879D842C1851C16A9447296DDD5096FF
+804D0DEA8530DC5D0AFAFFEEEC6B3057F16FADE808E85040E4275FA41A9B7770048508AC
+6AAC18540E2D903789AEA54DE0AFD72E582F596734D44EE33A9A719620F0B17FF028CCC9
+A1DDC29D41D9714C27CCC48A06A49551D8F5754D8AAE52D92D31269C9696924D52A44EC3
+D483A0849738125FEE094ACDC8C09574D7FB5FDAAE0F44497115EF7C152453BF1B6EAD42
+44B784EB072BBBAAF2962F61879D74D8850B1C544ED2AD2483EC46F99CA7E5A281C38C40
+A5BFAB0500A37CADA0FA0DCD05838A4180C0DD8AABAE616FDA7CD77572EBAB61656158D2
+C27C2DA43871390F39B4D3E193CF95C19D2D2B8072857284405C68F5AE101A49F786502B
+8040587DC7E2AD00DF02504FB119202E0FDFDE2DE00D4AFB2B67C8DAC5838050CF1C2D19
+C2D2F17FDA9BB90DA4F6DA74DCED5972E2F8221EA6A0AAE477190CF01D645D452F0E477D
+436DFB6EFF88407904DD172E6CA5E132CBEDE212BEE43C446CEBBCC250D13467915BFAAC
+24AE63D231CB519A0007AECCD201482201282B6C7BB3C4C45392D32D5E6F0A673FB8C27B
+D70813CBB4285D3755BE80CA5EFF3B8CC0738C090F535004A14D6EEA4B56CDB2E70DD71F
+98DB9A8041A2F80882BC5EA1AC8661C20632CA27198917A619646193B4A3EDD8CFA675EF
+5F83AF3D18735EB811698BA7EB58563F0C706A2DC7D372369CE227DE737713C18948DC20
+5D9E574513D54ACF922CC559100D90AA3439E5B3D02E0ED2EA9005F75BF378CEFE680D93
+CDEA6ECCC4B3F43CA57B128FFD4ACF5020CA5258B2A03AB259EEE34B80590D44F58F3D18
+7190011DDC9B6FE1F5D9D8F1090EE4BDB4FB56272C579E33C7A3ED0AB39D96C1AA74E197
+7F30423B3E2AC868292F70B3DC9D2A1FEEE89FF3BBBB195E409C5F473BCDFE107769B6EF
+E8371487FD8408D67313A1E0A6E2E448A0321C0FC931AFEABC4F648E4185DAC8DFA30D9A
+87C0380046D38FBDBCA63BD498FF6F96FB141AC9D0CCF2D58971BDA0703CB600FEC9C22C
+781DD3CF1D0604930CA0D8D9C35C247643892A82095F9F12196EBF4638132CC259278A69
+6BE54B1BA1B56DB1EE0F1C8FE42989AF69E38473B2A4317356A415E1FCCAB2463C80B5F9
+185D0B49D4188DE1B620BA6D108F3D3732BF34FAB723C1373FE6440296A18732444F56D2
+2E4666EB01FD9E25BB52F399EF53375C9280D7F6C3E774A8FE3EAA78EED6A94F85089E6C
+FDDAAE0774DD926D148BFDA4563FDFFE56AEE78D03B9BADC66DF13351F3538D6220D5D3B
+814D6F55C97A4509358DA25B47CB33923506BFE54ABC45FFCE8B35EC6EC9B5EF3AD16EBF
+9FC871736AE364350BCE0C88152854A653BAC1ACA37600276DFBF99E9BB4B19E90A6F234
+A11071922039565046DB5A6912908CB86AD30FD7FE3660C06F05554A0C970AE20BB57E92
+448EBC532764FCCD1FD1F8B7E10FD0EA90E043C3064B246CF3E2299BCD5FCBB0B8BA8C1F
+7A78688A0AE89D73DA9E7D94B20A3566F0870462FC72C6D7390CB82761F428AE82DDBB9B
+DDEB99B653807E6257A2DB61EA8F4FB2C1D133EB3D8D6DDAD980E5DC555C4183B6F1C380
+B932C33ED0AF6426372558F6E01186A41CB25FB6CEA786229ACB9E61A133E138685C485F
+505EEA8B5BCB465E5A697E2D6AFFDF040CCC78B8A7DD2F76EFCD0ECB1DB60B7F6996A75A
+A0059F9458D34FB95925FFF126E616B6FF585B566CB41926564D8BD98D8353DF5725E722
+86E1B9D1DF3644A4C45E3318ED821CE90B2D0495E97C5033C8733756CD10C763C2BC5CD8
+0EE9043A531A0DE7DCE115224D0E272AD0CA70D3E206B070728E093BA13F03E8D419E50F
+F85B3DAED2E7A581948541410B2469172006F0C24854049C0180D0DF6686E314757D9D4A
+7F6D641D499DF6550A60ABA333DB90F4615BACB3C808FF6F58272CC252236B29FC67FFCA
+5ED9063DF8100D915C5B8F10D7B1AD3E848E797F82E9B76786A4524AC083B09D91396DB9
+05F133D6E300AA5FFB1E1D161D00B4CBB09DFEB87CDA9527A23FD4591E2DF7E920A3F4F4
+26A7D3AB614E8D45DB0399550E166F01C4C4F660430642F813212E24C7CB24CBA11EBAA7
+B9F63BB00955F125A92658AFAC7044896843138F90299686F549A427A542B2588230C21A
+09938ED97A7A6382FC70174F303673CE2AE93D8103F5E633298E1DA2C36908F6F6039FD8
+37747FDE7F714A66CD8871AEF65B8A68529FD63F87AF84F3AD411F820AE9BCB84A7EA4F4
+3838492DC675D80FD615CFC9D6EA741C6B91AB432C0CBFE06FFCC562D71C6440176F39F5
+3D810FD4D3810E22089724E8A7F53D295681C2E07334D656EA4D3F7AD037D3B9C760042F
+86A0E2240343EFCAC8E2578DB30BECDF093CFBD0056110EF5834A1E683CD7D624B04AC43
+A663469E0D3AAEF64944EF7C43F8FBA221DC846E86A8866AC53384FD35D10FCF34EB7404
+BB38289451048BBBE520F6018C3F3B8F6FF3FDE4C5F33D89E44DBAF04AC4FC17A4196676
+F16B8A2F02FAC4B8933CE617FDF903113354619906A8637566B3E61FA8C849261A625CBD
+87BA5F1EC6479E7B9423BA14D9CA0C68E11BEAF1D1E948DE44257986388E75DB6FD9AE41
+13C36EA637EBD0812F272EB8381437855C7B0F262728CC886BCB624437F8CA30F107427C
+7D1103CB94B19CB2129FD2B388D62CAD6078EB7528810DC458907A14EA0CA0B0C28DABCD
+988174387FC28FF98B7C9BCCEFA0407D138828621AF7815C13EC04F7FCAF82ACD3E8E773
+B886BBBE2C4F2818E39A2D7F964A29B9E977F53C7107EB586D628F85798E70489189808E
+159E28A8D81FF9D642F3FA4FFDC2059947719184D1E83FD5EEAC7FEFD5DE2DFA8D808AAE
+91FE63E94AAFAE17FEDDE11C1EE21085438581DE1F5EABB4FD2A2C3CE0010492612F5797
+163F19DCA534DDF49FB45D0381664FE5CDEF1CD0C319B6748AC4B8996DED871EECB3E223
+8E924F30CE315DEC278EB94C6206951B2D4E735463650B5020CA8CBC756618AE1D8781D7
+B22ADE2D20CF71A9ED08111EAAF4E3DB1F081CE992ED1F7BFFF2B883EFD95F51CE612CE5
+6588D7A8F342EFB74A989AAA55ABCE83A773333315FAF1AEF25CDC4F19FD2293A51AD64D
+A070635BE2763AEC91BE2DC9F233D8968860E76352E6DA9F7E5EAF068E19CF1DDB22EB76
+FBE149738F247F4369273B6A901705B7DB396F662986D91803DE93D89B8312826CAF94A7
+80EB2EF254FD8F19710452E7EA41399D50177F4A8CD017EA2446C1295B6C1598BCF35060
+4288FB0A9C7CBE9D94E6517CECA11528D286CFBF0D621DA7D93C7D1029FE0C70F20ADA26
+E05A67C4E301A086770130934D6ADD3419070C6E2F0173AE4DA51F478DE9BBE3687D09A3
+A48D7FFCA601801BA38BB9D87F091DD410BD354C24C74E2E049407B8A3A98F90FFA8327A
+6260CEEC0D9CFCB9BD04C3C08FEA15D0884A9017E239335985C85E17697F874DD3EDC192
+AB8542A11C8B5F50A2B737F27E9A4078D72ED0656D5AFD0EB04F76565CA2777930DC4B0E
+62715FE6D2A8A78D8C0187FFF43BF6C434DBB5DB369F4045558E5F4F047554D4641D02DE
+A9A78C9B3B64D32D3415CA488D399273879BB9BA3EB375F630F273DAB8EDC0B015A3728E
+B55013B32BE513A0AC4769876686C9816035C2D199E955DF7A99CC07B680229F2E9C4302
+D5F7F4DD4B9C3BD69982E0DD8699EDC973E55A259376CBABBED36F28024A9EA504154EEF
+B9F2C5649E7338C52CD19690D7BC56CD06D5882366EE32FE4B56D7703237F3D38A4D5C07
+F4B851534F597A1723BD364620757118169DFEA997B90D243990C23B6583EAA176021C29
+923483CC99E04537F611D02C44E99A05FA78A0EF13F05F695F38E3E631750BC0427F162D
+96057F1A50A392131DD979868B617C037D26CB9A92F478C57E822C3E946B1A30388A3813
+39C0A4215EE9314A42BED741A0345B13D16F462E60E493EB57A775B3A01EBE558F8423B3
+047BCA02DCD80CD35A3AD41ACB26D75C92B1DEFF4CE5E8A8332AA185DF670FA87410E36C
+D27F4064090E39970DE94F2A9476DFAA41225BB65C0103F5F2F277F932CB3B1F273464F3
+1C6E88064995D7C6DDA4C597ED8C8AA2174DD99D8769F818CBD824E04EB3458DD29A78B4
+1BACA60903E1BC1AC6527351EE55A550CF7BB448C3926E5AB461E374AAEBF86885B8D912
+23108CA0D5D57C333DFE6EAF41FB5C7071B83EDA33362E2090A76DF9832BB5DF1E3AAFFE
+135801E3634415E1E8A561360B599DDC5F84F3DC12E3A4DA3E325A67DB748F6768D42289
+0520E9FCA4928178B888C4BB626D82D9B52DD2A8558BE9A3013B4492CD8F11CD4B8CA79D
+771D9A9127EB7D3F8AC0E09CF86F94AE011B568EC3A12B6C8B930084C0982FF9400E5308
+23E79DE9CE44B754947CF6EB96BB9C9FA45869AEFC46A19F957B677E93E25D7CCECA4389
+35D70BC5C89EA5E2D1BC207365D7950B8227E70D4CBF3613A1ED87A7CF85485DAB70AC0F
+3CD67859B72D6384000CA9B3831D32CC774B27AC9A2C21A4CAFD3493A2BFC37464066BA3
+4A4BB4BAFA36019452F8A580C4F27BB5D81BDFD8902B510FE95DDB23CC43AAF71E464CB1
+AA6120E3CC15775000BFD24AD031F000F787696A6A6FE9F2EB409B259E706BC64E2BB7A3
+286718CFDD3D1D2F3BBE7218949E69815A570AA59CE6545BC1A2036381515AD097A81D2F
+51AC22395AECC7D208F77CA9ECF5F2C121A7854AEF87CD2170A1F9F7FE9657F2C5C77344
+F7F07A90FC698A63382D7E59D7EBC856553BC2C821A6664E3BFFF963C3671EB7CD32C9F5
+AAD7CF79F066B847C533DE4298824AF0DB3C96B780358DAD0F71CAA85AA876EE8C056864
+FC9F11FBAD9D966AC00667AE21F9DA3555D55D81283142FF4071541CEF9C87882323BC72
+454D5261D13BC65EC5113899474CFD4C05D13D8FCB5F3A49A4967B8C46817DA1E71F7EDF
+3FC7375ADA580A715D37FB8D56B2A9EE3296D302AC10A9C5AF7DB8E92C39EFBDCF74D102
+C9939DB7F7C2293A9BF92E3A81C2A17B1C2048150935B977B85EB6AFBFA266ADF1D7CDE5
+8EEADD8B2D7D2EE4D9FF56CDD2CB1CBDBE229B03353D7370F9149ACBF086403B96B6E859
+952A34C0B58B4891E029FC505417DA6175CC8786CD4326548C65941E17587AAEF46006AA
+01599C4D9C3D66BC8F7776B38822AABEC1D52E1B29702C498D6583AA9BC40F656DD6F74D
+0528F562A31E90F620B7E96FAEA15F1F2F0B68FDDDB00D9FFCDB10635AA54C47AEB4FF60
+EB3E40FC4F82A0F73B8440023753309E443CA66CBB5C02CF7D77DDC5917078EDCF50BDEF
+1341027323183AD881EEB8CE2CE4B983C611508E8911F098ED89DBF2ABBA49F1E7DDBE0D
+6BFC1EE74A839F7CCCCF4A12339519C2EFDA56941A74044CF1B0222361ADF02CADA96F2B
+94AF954304B3CB7635C2E7E6BABDAAD0CADF6127F63A07BE097E6C7FF598272D39D3EC65
+4EC2E9B795C1E6A65C50AC1D540130B16DB5D763B9923DAD3CC2D8DBA1D3D2158C01EF3D
+0F41E368C49FE8AB6DE7774CEB1134B1FED9E8911F9C2F29B8A65D2F030B966444B96EA3
+48E804BB6343A01E2A5A4B3A39EDAC4EC5A8F9F8BCB4377B0A10820E5B5FCD84A1343A02
+CADC1D5EC78CEDA3EEBC08E795D41C30390EDDB0D6228C706CF39C2989618E1A2C86FE80
+32E093F244E65BBD5AE8EEB19AFA5EC0717D5A0365890E707DC35B2B56187314BC1EE8AA
+F3CF2A8E90B5A04CC30BEA3E50101256E48D0DDAE0E8DE05D62DC3AF06655AE331010C67
+EF2377D07B7075866B905644D7003205A1D9380B56386E291962F5A8CC209C4D540CE82A
+02B4E654BD66EDEF1DA488CF02B1F37ACA1566F5FF3E4A25E9DC0FBE6F1CCBF4315DB6EB
+F3027B8751BA5BE3E68C3B428012CDD1F23ED25C9F09B53321698639D37C581873723846
+06606C0B4E522B57B592A205EA908633A20BBFE46689A9C749FCB2C1BA5D4B3EC7DBF4FA
+C810240BD7D2CBF721EA3F824497D9B105348C6DF4E964AADFF293FB406A4678D7E1CD5D
+24E189EAEA1CF128CAC24C3764922AC24104808451776ADDF427A8E1DE5227B82546F1CC
+8FD56C60EA96726924AD39459785E481A86C59E43F2964C332FAF11BEB87EA9F7CB71920
+1E31DB06A94C12CFCFC4CB0E5925B81BD827842A8FF3021BCB63E9CE7BF8984006062267
+DB5F53DCFF1F1C08E053020257982E81CD41F6D55D6DC148CE7E1588146E2E7A721E0C63
+4451BA6D6B0BA5E1434EA112CBC5BC508BAC211A55498D30FEE9DA4BB5D39E19767CE082
+CE5E2737B404708070E8E6F325D8E9A705398C4D2704CD50AB6567411B18D49F2D55D690
+CBB1B4D50EF9893F8071E8423DEC6A6738A92E527446549C87D4BE374C6BAB141331BE47
+B0A1415937AF7A047BF16B2AEFAFEDF28D15B66C241E346884870E8F3ADCAE8A1403CC77
+1EBDBA2F12EC4BC01547238E69EEE4B08FBFAFC2E81CDE882C9D7558501B0BC04175CA89
+D1EA401ACD6AFC5AAC4128539AA1F3ABFA352F69A1322A7E505F68774598F26EF248F658
+D0EB1ED0278DC608903AE7D8DB3A2FFBB486057720D8F7B6039C2BD00FBD67B73E183EC0
+D539325173FE5D5F6443A6D98B967ADFF599124199825EC044717674D4EA3D0CB23058DF
+D156708E37DA80BC192F0D51ACD25D144411F856E36B135403F818297025F27FBF7EEEED
+1D964BD4F0BEA178AC1780B1FAC7D64C2BED556696F164B97CA0C400F8ECA0E508884249
+8F32B23F9AC97B52EC55580C0C7DF9EAA9B8DAAF266DC0A02C2F3AF10D756AFF097A7610
+9C299FDFFBAC8A6C3652285901A145DE49C093F4AC2BE72327C35E6F0756F18C9D219D28
+24230C2F226FB0E9E47291136B363658230009DD11F2A8F23BC2F90E7EBFB384E1BD8E75
+42295AE84096E3BCB7F7E7ECFB394FA8B2C9B4746455DB755A59613D085C34D07BCF89C7
+2EABB16DDBA4C2C09B48A5D21D75CD9529E4684F29479264C9DF6FF211B72559F0BE453C
+C83C1FB4EAE42A8DBC18B2F0DA7DF4CEB2EA36129B469CB59D74C5A6897676B3855E9E28
+5F0BCD467538175CD6485237686CF42A046B714941BFC56FD1ABCDFD292B5368AE331149
+B401F69DD62B294FF941B1CCDDEC0DCD5507889C8310A6FB7D7F3A9F0713AF8E52A5077D
+10ECCD6B5E24B260052A25E09C477D1F4A4710EF521C44F5765EF8DAEE3B7BA4E286D764
+59802F38D8E97D9A557963FCF5CE32A7DD5BF847703BC9314102928DA945BC4301440841
+94AB6BEB1EAF29A147BD1155D2A5E68517E4C347098D4D49AA10A359132C633B02E3AB33
+4BA68714EB41277EE78BDB1418DFC5A584F6541F3EC0EFC75E66263F61CF2DDDC5DE5648
+B14B8A275CAE0728A9B60FD75210FFB3EE02535815F68572A9C29DE316C7A6C991DA22B8
+08CD58C392DAA11A2390AD45CB6161063043C464DFEC11E8B068A0CF516E38BF736AA9FA
+A03AE4EBC45C03A4064A4CF07B171499954D8F93A7598F3D51E953F91C7A70F35C88A384
+97839CB7F9CFCF788932B261AB359F8834660BB0CB5C69A4178BC3A6A98D6DB0C7C346F5
+E44ECE30B1C3E5EB4D203CED8B5DFB17F8211D672013A41F5760D90D593B7079D6F231D3
+03E9C3BFFFDF1E98B8F156BF47EF60F082FB02AB362582361B5274444E6C615A8ADAFA43
+71CBD86CAB86AA91D096EA244AF3C69C4A2F9D62A0F5BDB7649DEF309347F364469383E1
+4B72A52AB0B0DC030D8E785C81724959CD02E1BBDF43E6B92DCC1AB433576ED1F7B7157A
+483C99F4662ECEE5116AFC2B28263AEAE6FC04C656B02E15D619275C7D79894320559E18
+B75EDEBFA7230375F5EB1A66DC3AFF798C6B67D05D8B49F28AEBB509364AFFA36EF12063
+8D958796CDB5409D5D3D8270B4E602A530EA46300695868F972A1E3764FD44BABAB416DB
+AD0E3799FE67EA3A134F9841C79F89AF7FCF182A484627FC0A70A8528346E3C27F655232
+10ED76FDD4626CE3EC9F34F506F9A7F68C50B9434024B7C40A3D1ACE1E616694E442625B
+FB49252EB156B12AACB84BB3985FBB8431A9BC0D1F071F7947ABC095FEB24EBDC9381FD4
+ED98028BE53D441AFA5534C9D27A3D21CCC2EA3B6A652E08CAD80B56751ECB06F18CC9B7
+CEC29919314FB5283AFE5A1951D3669B446F094550DAAD91C36CE3E5D30238C65D2E1D67
+5648C147047FDCF267AACDBBA50B1F9C7959C5F12DBB94B64FD02741211F297176F5F849
+412EDC12029643AE2AF2CAE8552C69A90BA2AB2DED3FC3D5D5E8987CB9B538FF90B693D4
+B842EF7D8AF1055F53FF8442AB5854E94BD016AD3F29CCE91F6D222C7E0D3EF3DE72AD41
+C2E179FC20B4E0E694E50082E944C77CA4D878BA6F19410FF616569C59E94AEC542AB9CE
+BDBC0C9726DB1D56FE5B66463699266E4802B8572C7D2E45DAF827DC6FF7543A45A8B7FB
+908AFA10A67EDA2CC08F677503D0D30D74BA3379234897DBAA955011163C4E0138858535
+1FFDBEB8804F00B6799ACE948E698EBBA5C391BA1D2FC74F20C448FC0BB8766BB3858B46
+2E06F751F2762A5B8DBC4D2B7B96FCB3EACB4757528964DC348C274F757178EB41BBDDE2
+E075E7F340C899F2253DA8D35B2C544792077D7CD7678698C2D8A3E36D440640FF920E74
+7036EE2E46227F170C5F311BA5D89C0EEEAE6BD2CD006C5D18BEEFD521894E5DD7E865A1
+B894E8D3E24AFC5A89D18773A7028DACEC61BDF9CFEA5FD37826AC0A7B51C7CFE3813A36
+8D62036C6B5CE16E56601864092F2997816C600AAF2DF34CB4832981CA5737A5EEE14F2C
+08302588D473353CC126C39CB3F6829CF84358384005A577A7F8E9BEBBE001DCD4BE0538
+6490A8E7BBAB5DBB98B5548E478614B9CB730CFAA373114384BA850D00FC9B4DCFCB6B8C
+A57D4288E62BDF5D36BBC888C6CF5F501BA8B6D8C5D69D5699D80AD979974F42420D114D
+9BD3F2ED149514EF44BBB2746A00E3C633FFA966AD76B0AED0568E44B94C1F820869D86E
+91A78A7C5DB8F454D313637FCD271D92FC20C9F578B21A969EC9B1C015D8FA455AB419B2
+B743CF348AE9BBF466F8FBD617E29374DD71A846A75441CC79C4B1030266EC8E46801E38
+CB9FAC30D2804203AE5CA81D0FAD237EC8D8EA6C544F8BA10B91C2D3A402E940D3092E16
+9D44A95F8292E2DA06C709302F69729A5C5042A009D319FC7049C50DA4653337A6BE5A22
+B325F1C64CAF8682D3D4904654D636DDA229F6F41FE01DFE8CCA48B171FAF8C099A92C28
+D3691CE8EAC30941176151B67198121ACCF7A6EF4FAB0843C385003036DA94117B66FFAA
+0A6A8C007404A9C0781D60652E48D530A656B7E005C5053A8CB7483D1EECC4A85D907859
+982A74B1731BE0B8F4B1E91E4481A68057F9AEFD9438343C1229B0E676842A85641CF32E
+364CE9EDBB8D4603CAF04A5B2111760E1E77370474393F89179413D5B9184938BB00DC79
+FA7602A1A591EAD89E9D7DE655378E10E301B4005D6B5BF682DF253B0D8A34004DE431B7
+C82C1741D9952B20F7312F6B44806226115791D0E38C6A5E855B2197DE0317858F25C62F
+2177D7E6237CD2CCB630FBB13107B25EC2A75EEA8AFE6AE0642AF1F23D171E99AEECB731
+5034D2410795B40495BE25FC6EE051D78792D65BEF57BE88C0DD7A7C6221D0B7ABD88762
+9AB940664A7F4B6261069B5DBC95BDBFB9DEFC25D4DD38B184CEDFB2653553894B7EB379
+4CE19DAD9160266B97A32BFF96C0A1B7B6EC126F34DD8B242AE0FCCFB7DA22EA249A14C3
+E6208F2FF090AB21CE1EBA11D66D654B30CD73CA6B2258F67706792E63E52B1F9829313A
+C0D6FDB303995546B77974C0B07F906944B68B50CBDD7DDA5DBEC4740FC6333D1E62984F
+A9C13C623620B27680BCDEBEE51E3B5841643383374E04BC65E4CBFA38C91ABA62D7AF44
+C721491F6C78A9088DDE50BBFA9CDDA44E567D776559D3E11030CAEE6E5E7D07289CB58C
+852AB6E55F52A6F5730A099C982DD11296E4E33CCF20BF6EBF16C1EF76785F13A1AF9EF1
+A52FF02C06A959B6839550F4FC30D277AD524E215E05B63A9C7B74E2FCACAEF3DE606002
+349C3FD26BA26FFDD6737BEC9C5DAB55F0A63AECC534DBDC2174490980A9AE98B00F6BE5
+2334C6090BDD9AA329F6A66F551B3E41A0DE3EC021C7916F521DB7CF1D5A6B7B9D72851D
+285358554917F453CC15A1D73FD528AD12230892C6774001C56840F60EC5439F6F54F741
+96E6D3D74010F14A30DF85B16D23A7194634CDD9E4D2D74FA1ECB3DB09DE7D7FA438468E
+D1AAA438A463FC988C4460B1C55FAAB585AA17837CE6597B162601010A04725655079C2B
+627139B1A2AD607FC365CA845CE554AC4881BF87DA677B2B240AF10286A947D624EFC074
+1D7EDBF557FC7BF5409AFEEF4535C7A02D9F195B1A20D54C25BB918EC1DE3492D8301448
+81CC8EBA460A299805212312643D95AC08F93ADE8DA467C4286ABC575D17265D7B268809
+C055D44FBBC1672E34B73EC73F114FACCEF8817B3EACC68C88D07249769D0AFA2B797863
+B6ADDE44995C903A35A619EEDDB8F1D76E736C26EC4E8BBEB51B05DBDFD840C0DB53C766
+625664B8506BB1A66DE8A04041ED2F68663BD15E3B932234F37CFF8128E4B2AC1C191297
+D4202B56DE39AEC4006ABE003B7594062C26F206C124E1AD656B8598F190A335A0351034
+388C225B0B542D11E3CC96C0B72789349BBCD9C445C19265D32440F6248F2315A9024BBA
+0CB6B71BD71DA2B06B57FB0483262A653161E6ACFB5E916C22B6DAE5847740A36A40A505
+668EFD5FB438F9F1779C02A19D2C14D6F1DB6B120C060D2ED8BDEE9733497FC9134A82E7
+42970EDA3F136E0740CCAA97EF05658BC1BC0F5855303168E2BCBBA37305459215393674
+3D51B4670061818712549FB6CC007C1F13B8C74A8AEB05B30D37E6587148A94CB7C1F27F
+1B4B37D298DA91CAA996A180DB262FEE001AE974B819D288A619A8ECC8E442D4A2EE0D93
+B89A0FFB9A03EA573BB8D40676E9C67EAADAC5C0A807D7422AB90881515D4DE087893B8D
+A0329DDA3C42689CAE4F29C791EF79B2965F6DBA3C25AB0CE23ACFCCBFAF41ED546B4A05
+0203147147ED047719FAE976A2B71A81A0EDC3DF0A3E03B4CB8208BD7AA6CD91151B1A31
+5AC3C27534D9D73F285CBC0F3D7E0C2CCE2DA1502BD04AE6789ABF17DC7CC9214C67F2E8
+5DE2A1A71AE65A91D7F139756A1A9F912D759CA02A433F0C44E12E8739C4C2BF217B8FF9
+55FB47DCC70B1790B3E906B9AEC41467E5E0E9CA0317BFD62F2A493EA5DF4103A385B56B
+45290A56E816C06EBAEC8D38509777CEBB11CE12509834FB28FA7A19FAADE81BDBF0E427
+46EAD35477D51E467EFAFAC373E3E72012AC7AD85901AB832B8197A5EF7ACC5A9D6362DF
+89CB52589A3CE810CBA525DC46E2C00680EB66CB4E20CC4872B5F6F9BE3636117140C3CA
+545CC3926EE9005FFF15AB7848A95ACAB42E3B565AE93DC7A1CB80B2854EEE6F14422013
+D50C7BDD75E97822BA7C7D65FD383BDD5BE7DC9942888CB7C39CF56F17ECB0676B73D3A0
+2A37319899D89426DA1B299009379DB2C217DC43FC08F4A43E13BF8522A2275EBA64628A
+78B877E2EFF40FBF2B5C628981B0E66643757F5F8412A5B48AF6CE0D230D57100D2F3446
+CA7C8EBF6F3EACC15C3115BA9BD61CF3D6309C18BECDE16EB18F6D008C5C5CA0FA426B52
+5CC0F33A5743D4FAC4830C4B7ADD35ED3BD7F7B072847D2D430DDF667A6FBE49A371BF0E
+BBAD32173AB5928B86FE1F4E74116041E0F6E4F1041BFE588A17C7ECFF96EBCC224EF0E0
+8E3D8566BC221C1991BEE248920A4BF4E424FFD1BD34D1CA66F53DBD6A1AA33B33CE4EC3
+ECE8DF81BC73A54DC350A3939F07521808FD40C566B03124BC7300D28035F2162B76F6B7
+F7A26EFE392EBC35BD718DD1697BC9FA8214A1E137E28308F7C37854FCFC6BD031A851F5
+E54751C2C409A314A0AF104BC8D561A5A8E7C6B0BF4F1EDF9B42F577A9B9AA91D690DA70
+6BFD54903E6A1591588A845EAF9B49A8C5BF35B06AE495F4A8CA94D64163B2BC03482DA0
+BBA8B30CC65711C8B45AB4EBAF027958D578B94DCA70863767A0627B0751AD63EB628BED
+CBD2C89DFC2A3BAAE500389F9D25F1EE6FAF3BD85B018296528A0B6049688B2CF7BB1941
+386D49D254EAA716D29051B9A5295E937F700C7D46872B6D593869A88576DAC22A2F8B3A
+5076656122DD5178AA5FF49A84BBBE20DEE581FAAE017BDA5B7D4886BD8E90755D766EA4
+B2E825F73B8DCAFC4AA1A8263A179EC15E6E7EA656B1BBA6E19756324876082C9CBF9094
+CD62531D1BC54FFD2F9F9DEB6282DE12B66D570EE73905B0287CF19E628533EA058D5FCE
+AB66B6DFADC6AF54995ACB056B8BF3AF89EB021073FA98A4B6803DF89CEAEA3874B09625
+67D46C4D830F0CCA68C7F24B20B94FF73A0D270D2247193214DE5E85775E15F5ABF0C88F
+59931730842A814185AE10BCC62DC83846FE3031B140D6E0E05F4E5B6053F71781B10D05
+81904D48290FB4A157670B791271F7B1B32BDA4A71776B196767EA25D5A935CBE1626C6E
+5B3D8E64F74F03DFC72FB5C63BF586540071EE17C883AE11F2D154EE9AC0B2F7F71D4D08
+CC170A9D5206AF1585BCC8AABC2C2C714DF83AD1FB773CBECCCC388E0D3769CDF84DE17A
+83618678EF40D4171BAF7236BB081887A042DB575528027CDAC918086C6D8FF005639565
+F6676782F78AAA4EAD4ED8162A35E447C2D60A07E6222415B516C8FE60B9C0FD24E78996
+C1316D99AC6BF81AE6A7E53BDB0DF9AD231123474DC9A0105CBB4D98EC4ABB4F9BB4D3DF
+9BEFC99537B06378E91C875FCE12910CA65C33C47F1D8A864D17D5C5B288D5BF6393C576
+ECB62660756C8746C2125A8434A5DEEF7480CBC48C21595A28BC9931AD897C754A87CC3F
+608999E7FE39CE1F60C099357246117C8A074BC1E405EA7FAD3277CA45F5053C2EE050C4
+B93A1F85B90084A12D625DABAF2291ED36699134DB6BBF4AEAD7CFE27379AA6AA93B31A9
+AAAD3F8F998BA94D3CED13C1730326F08928C6A648CD010845C7CAB2B935ED2450239B20
+63D25104A1E9F4DC48BD8BDA6FEC274BE5807DD2355F6CDD587263837ABF3C8CF8466D3D
+9C38D0302F1CE94C967BEF58E6B867C9FE138A7DAA9E7C791865A3E8BA65A254C7032E38
+FFAEAAAD4EE632983D975F167172AFD8FF70A1CF6C90C24B9C1C3E1CF51046BCA8C2F0C3
+D56B931C70848521756E221AECB2F0015B3476FB304B28C4B7966A3F693AC9E1C5D69C55
+8DE014A05981CC5E1AE6083A91594F0BF812B1348B5401E4170AC65CA29A7182073F0E18
+8BDFDA17EF3933750DE211D30CED8B11A1107DE4F12336FEEF5AFB522B2060BB745526FB
+D06E42C1D4C7F529706078FF598EE48C9521793F53F770636FF6CE984FBBDA645DB8E631
+E041B10E43E836B1F8C58C4F2D4A7BDD4165FCD7B19243AC560E80A6FE7A3EB4FFDA465D
+9ADF12EF99FD68D90139A58A53583CD9A0A574B8E0A604E84FCBDCCF67B8A2DE8D411996
+12EB00DBBB8448B80098B458B143C6D1CCEFA354EDD81B01BD6EE4A0ACF2AC0338BFE143
+06DF27EC691542D79715D36E06DE6D7C2D3C9C0A7DF0094CFF0B50FB21D67138DCB7D447
+B45EAC890C4C6E08852F9C00D6DFB9C60A24061A3014844C84BCCDB993E0B8206E5DCD85
+A97D0F1AA82F5AAC40B5D490BC1C60F05B33BFE6F6C07138A4BD1ED177C2FFD13278F53B
+1B20218F1685385A604934223F259646450DEFF801D97C1D38E8621C612A4E49B9CC2279
+7DC683D7AFAFE54FFED9563E880B86C25982D6733EA3B8558461207C91F024640FEB1D2D
+5A7F80D16FC694DDC1A59B7E30D1924ABA53497F37345B31D2429F6804AC66E9FCCCF4EB
+9EE2BF2836E5B55F29D445762ADBF6BAA501E198FC7FDFA66F3474B116E9A77319AFB981
+7C2F4BE21CDCA0FCB65F07DCDB906AE92CC40B4A8E967D91A00E9110BC5E3289AEC2643C
+02F77C6313DB7BCA506CB8BB3F3A434904BBBB46D7C724766DB3BB73422B659F7D5AD5FE
+6DAD7B204230C92AEB30AE4E510478F620BE0E4D6AB477971A22A5C6AA66835513B1E2A2
+278BE747880EA3E1EFAD48ED0B7B5C320B833587A22D5C944F5ACA917C4C49FCA58CCF19
+BD800F5DD3246DFB9A772AEE6DB700127D07167F2D69CABC855BA8850571850D913A0606
+3DAB1EDBB6AEA9724368DABE65C57341467A58E819ACD98BCCCCC971E30F0488694579C6
+C4991EDEFF6DDD79693EA8BAD8AC9495D8884E5B09D163C7A0D343C031CB29F879CC5064
+B65AD297089E7AEC41026B5E055DC47A7C529ED28F3D27A191239D4E3EA911C84084B411
+13D7029A39E6C6A2E931727711F1F06B807841406515B7711A6B96E6AEF79E271C6E7D42
+7146AC3915D35E9C2D4C9E7C5689F7B0371BAADD037840BD034F4C411AB29B36D4314729
+E97666CCED8F1A5AFF6FA352AF6AD9D9343DA8E3F97A8C756B48675750D128A3862C19D9
+086B597EE751BB0D87A3B7A56866CB6AFD2CF8B1B322C9B2493D40BD5B89C4AD69F347D7
+26C22E0E39ECE377C995A611B54C0B2EE3B6CB16673F50779C212AF1AFB93DFB2C931A09
+39A1379C379E3F7327A687B5C4D8D909D3CCC5C3195935D8A09D5E5BFF12E61EFF4FC6E5
+F99A1460C5D1FBA82C84136BCD64D96AD968D6EC728DF4A85573E021734AC6C2100B6F67
+F4E648F5E284618A1868E773D9CC819AE8BB433FD388E971F211301B3ED077CC37FA4B58
+0B50F8BD2309D8E81936C050E3F0C8C7D81A80DA508533BF5FCAA977C17A572DD92CF1A6
+B7172AB4C66890E9F4FEC661AD629FA0FD23E9427C481408A637F9E649DDDC31668366C3
+692B524D9B4DA99938076EAB2343FEEA1560550B8E8CD18D3CB23BDB1AF30F60EFF18936
+46B26A09E5411F6C456917CFC6BF3F74B2079D0AA56935E672464F6444F2E17DB330F94D
+FA7CFF92DB6C800B2311AB86A21658D431EA7C811E020538CA2335B9DFF550C077E83B29
+544FC63F5407B1C9CBC3E6E6259742EC85BAA006D2715D686619A94AC7EAE394915CA656
+B8DE89A462A85CA179C276B4F90C399167DF0D928518DA2A45B3125CD16AEFD65C85801F
+BDA3D139B3B349AA86037B579B8FA94C713DBF1DB2A904652E89AA8281DD58D4CFE3434D
+6C86F0BF7921486C9AE78F322DD841CB43AD7EEAFB5735DBF68D03DFD6640DEFBE22B305
+B33DE7C444D16D31C3EFBDC78547D77962EA985B734970BD6C4B729C7364348B1CC321A9
+46D096A078A45797F63B1734E968CA55B8E905160740F68676AD286C9F44E1A94D17F911
+0EF21F8EFCE27A76D1D7869FD19C5A9AC889675172335D312E8E1DF59ED55F8FC13D0E6D
+9601039BAB9AEF7A4F3BA688E288A089B326E0B582384B9BD80A0BAFA1130E2034F95D21
+49DEA8E5F576EFE035C5E58CE82CCC0B3A95980097B2D4A80BE162C8E3760C3532697651
+2626F6C64864810E304D98D77F13BD535DD5BFCDAEFFFCEDC1CED370DB2EEF6D90E1F0F8
+D4C3FAEE71AD31B0F4798ACD68E1A5FD00A327846DE3AD55B0F493E534AE6E30D2DA7EDF
+3F68459CA7192321B98C8DB02D3399F72A0216F822FB8D0B5B650B38586BF22197F78D31
+55B67843202DDEFF5B04D4230DB2FC50443C21C8C28E7AE0E399767E03BEE4590C4D47F9
+27210114B296F1E8263213544DA56D46BB179ADBA6DC415D6A46679A4A7494AE4B2F0812
+9C5D06F92D2D500F336304FE3454F07A2083D6B6BD5D5AB3D6F917F555C7F7124AAC6F38
+4262A051D865369A95DD8EB9DFE43DCBCE770D3C8BB6630AC2F8DAFCE58C5C4060BAC1B2
+EEBAE9E56AED8725DEBA7CE23DF18E1A52A5B87F39EF416565DA17A5BB6566A8129CFD77
+D3DA3E3583E6F59EAA14F7788C06D3492FC84F7C6BDA74C9FA885EBB7125E87760A1E848
+E9CAA638A813D6EBE8EA2A3E9ABA7DC8C392A066331D9EACDE6C6819AE12A85B096CBFE5
+29BA283C2CB73FC34472C5289914EF347AC8119139A3E6F0CFFB5772D5AB65B276C171EE
+D565CF9B1E629AF962BBB00CD86FED8DCA3DA0BDE9ACB286C516114BDC1AE1AC41DD8453
+795253786205499EF2E971F3DFC51C72AC5225EF4E0D9DEA403F24002591D9F55276CC38
+0DCCFBEB33F7733A1DACEBF1AF33D55029C44364284F6CDC12ED12BBE809666607771634
+90828A6F10683FAC8C3C4DDF38A0CFD1D1FEDAFB7100FD9C02AC8796C7B3B2793D11C107
+DF10D22D9C294A3AD3897431EE593AB265D97450A6B2DC4917ADBF04B04F32F5802EE354
+4D3A95CDDE623A423213D0063B79F8F40EECC82F3C5985CD12B0A46F5AB9DD5175A9F3DA
+06E40950ECD37DE39B5EA6205D9427EF43D5B0D090A62B669E437D0C31B6A03850EA8BCE
+5D2D48C25EDA80913821DEE94881348DF1726A7D61ACD9520267B5C668F46B1660E87E27
+658B7D3C2F1C06ED70D97AB144D22A4CFF4A54D73F703A5AAFCB5AE2C7C5B33CAE3F0BD3
+29600C9BF8BAA060ACD3C4D5A72851A2A18AF29212B1E070EEFC452048CF312134436B5C
+E91FBD2E526CF0A35F42C1D8092DA30270EFF9577ED231B303B472670B458C6B53B1C766
+09159D861584F0901E7C8DED964E9ADB0B424092B4B50C490BC8DF607EB9345C7AA94CEA
+F430F8DD439472CBEBE11C26F9D7C7C5F8F04F6D3D97043E282CC848A1BFC73C095841C0
+ED64E7449BF4CD53A64F0B932C45B0770D6D18CCA6147E9F992A93275AC93D1B3B0F02B1
+9F117034AEA1F3F0F77D482A3DD8D5B2F69122E5B08C067D39A1C25D042D1EF4F47377AB
+CE1C38418BD39E7400F10247FA13291E34BA3CE681CDBD28F3F14EEC90A21C76806DA1CB
+25AB9B96031D1A472C1146004C4DF21E61E07087A8DB5C33DCEA85EBDE4587FB2FBCDC2C
+5C6B92E61C72B067EB5F07233162AFD24FE6A2A9D0BD11F401610D5C5F91E46D36B2401D
+A81BA2716D4AEDA19136E58A14F5A367942B70DED7DB1E0703609FB97F8C72C062934495
+DE54A6C45EE6C8B5F368F2817ACD4A10F14A846C1FF578084779649C4BD01D9CBA1E88E0
+1DB953307EE9BF10E6C17B020FCEEF709840DF73B4CE45D4C2583CF4B357C33DE67C8CFE
+8FFE367E89759117EF10E08899F466D342E75083CAD4795950C026505BA8CDE648FEC333
+BC5842ABEDC3CFCD3B27E707D6EAC3D54FE7B9C964E28AE0FFC96A06802C5A8327FC2CBD
+DBA565FE970FFE18008C9DAD42EA99FF7BCD0656362AFF37432A182C59988B0BF458C370
+725CF7D7F864747CDEFA9688FF6D2CDCB49052F349F9BAC9F8261B5FF65BCD2E531BA32F
+7FD7D3F0E3042811B345E8676907FE71D4FA94437A3A42872285F010D909D468462942BA
+696325E79D943D0E44992A20EA118ACF9CA5F1B20E52719854476111D6479B3842A9CEF7
+749437F57055B19C5FD6993F5737E8555B19161FEF7F3560C6FC498EE8148B6327EC40EF
+7CABBF6B7A99D14A789F6F5431BA4714CDA494E29542EDDBB4A250ACAFB9802B6A3D8FE2
+1CAB7FA79D9682C1B1752DD2E671ED5E4574BFF967156A503753B65075653471F29E06BF
+7342AB3284E9EAC6F14232F32C3B0266416738EB5A138DC33DB2FA3A74E649532B4BA7A9
+AD51E0278FE837ED68A9A5E40AA236314885AEC0DE2BB1811BCC18F0A75CBEF875D886AD
+55A873B8D3FC81BA69DA0C68778CFC5F02C17A851EBACDCFC9A0682D514144CF47382163
+6B1A61CCD572575E6A81671DDAF8C442E4268041F8E03398A9EE0F63B352839BFC4D4720
+0F86CB77549091DAE5FEE2CEFB21F4B987496FB8F993E3CC18EA9CF06442403830E06738
+20BBF3E4690163AECDCF693BEACC77B5591FCE1D2DC11621BE67F9C439F7864BCF981F3B
+8A9CC1F21424AB86102448FE45A42993737F7C09275C627CD601906B75CC9370AD491B59
+2777DD8683ACC7CC961D6CABAB46A2AA65D8FDA3E66DC5C75ECECD209FFBBB76263E036B
+8F62EAD1B802D3662A23A28079CB47ABA48799F3DB0D7E46710675B2C434513E997D189E
+0A9661186D9D623D5B47BB377E4B0CE197D80E9AEE04E55059C6292C52E00D0AD892FE67
+600AFA285DC92263DC1F15EEBCA803647789D4D420FFB53C0CE4A669B4B963D5F2FA6FFC
+3B28AABD6D97AA2F92EA3FF8EDE7AB264CEB19062030F43D8438DA703B68D2615928E4F7
+9687B03BAD9F3447ADD3090BBE186FFD3E42CBA236104DD1D9A8E9357CAD999E889D313B
+262A4232C5926869139EF1165172932601BA4CB406177E25E6150605DB931A70870F5BA5
+1DAB4D15D500B261F9D708174568422C714F30B696095757C66F7D2E6A5CFD146D90F21F
+27F62393B532583B49558C8C6124F2F428794133E093D4FE09805FB2F18BED35D12CA321
+B79B0369E46FE3191F47B07D234866AD7EA52C50F4C0562597AD1F7D186060BE2339C324
+F154C2EDF64C7A40E8419E7542B8CA143E172E3C62471AC1F42342051B3FEA08368A31D2
+56A7D51FAE801A420FA30E5D479283A21B50AF52C6BB4196433D933FAEBE36EC577C59A9
+BF52F260443A622B637FD4F6BFD330F8DAE7E4374E16B8E98BE92E3404CA22763671CE0D
+276981334084462B06763958C81E7D85C76223546F3ADA094E5597AC68967D96CD9E76B5
+0518144684C71739C488751FFFD3B9859E23DFAEBC15A0AAD8417416CD5B47656E8BA799
+BB2ADFA07B90E634895108D5F97BAB5B560F0608C1239F49967B34941B908AA695840FE8
+4519FA60763EF706ABAF2E0C7D407E5DF05807FCDACB17685226D6B5070522D4A6AAC8B8
+77891A1390386A074745E5F4875F625E9BBED05B54D04EB6A6D8352E7E4E47FB7EF432C0
+808D0C139EF7EF5220838D1CFA3A839B10B772D8F2A197E8FCD7EDFAB65B7234A7E1C0CE
+D75C3120A58706A26004C2218744B095AF45009AD3036AEE08068311B20974C4A95C8CCD
+4EC20B2B8B8EC4F2D6F9281968EB51ED0E377E3BEA2481810C3B0B289AE6A3EF50339AC3
+B7F06050B7705C260D942DFE3B104C13728A2140F9E137AE5E476FA67245FC92F1DFD28A
+81CDE2EDB4978F971F668664658A674999A62287F74C8BCDF0C306C20FCE35EB1BB7318F
+9D7BC39F215535A9796A7AE7D117A273DD5F1B0F5FC5F87863A817993C96CC2CC0FE3504
+44698065A0654D045BE4FAA60A218D260FB013868B18AD6DF01B793D298F0CE041671E71
+81893BB81310462FD1906C5F8137FF46937B206588D2715297D008E6AFB90DB28E3D64DE
+73EFC4A6DDE7466A3D1BB402FC04AA80DF2BC39AFD30207230828FABCECFBED8E11598AD
+CA43FE742EA8D1BA8CEBE4449495398E5DE432B8218E02A5340C854455069082EC8AA449
+63A13C0069F468BFC1D3D75D4458383E04268297EFAED1D02B91AE933DECE8DC3337DC99
+D7AD1DC4B999A3AD5E8953C7820BBE425470B21BB61ED6007F236467503327FF73979677
+918B34DBEBC181DB99526586BB6E9889DD810A0CA022C62FCA58F2D4D738A74BA24E2FA8
+29B80401DCB36889A4CA08B77377DEB0C4172DAE920E318DCE78DA14ABDB77EECFA5A1A2
+6FF51D6569AF1218C4256D4B4D206ABBFB1D2C7AC2102815EABF306CDE0615FBA775B5E3
+446A2095C406CC1BFC1BF4A53E65FFF0ED565B45AD332505AFE0F91C8569897834C06194
+6C745ED6618A60065F6E3B3B49A61BF3265F3BB1FCF8A25F4880DC771ABCE6BD03B48C77
+83BDC1CE678E423ADEFE9AB04D40097D8DB062DA0A248D1C81AC57FBCE032B232C6FD553
+8AC5AE7983412BC80D23EB71E4DC3B946FBFC4B98C4250BF8D57CC55D929B55C354A3F9D
+1C5329F36B06CC099C2201E7FA501F75CC7D5579FFAF9F9C63C6DFEDE80B5387117EDB49
+9D3F1C72D650FC120FDFC8E42479469DBCD81AB244C316963CD6EA1C34DA43400C5A2B7F
+E9F0B71EC4EA67255AAF6A2F49982441962CA30DCCDE6F7894520FD2B811619713D91DED
+5D1FBCBB42B1368E7F8F4B8438C515B4661879D353096F880AE278905424DBE523DB7B41
+A5867878E478B85960607BD1C129E85249CA520BDAA479CFFCDA162E46DDE5EF6BED9684
+31F3289735FA2891C13C0C341159905F43BFA6412B6ACF04C2A11B87AD4B41A35385AB66
+68CF890B1E9A43598F03AE5A833A932E5C5A70E498C405CC56BD0BF1074EF1431980F575
+67D7C62291703308B41C4B94A99DB6F6F1F924E791025D5E2F56F3A0B60903FC0CC0B2DA
+8CC5785C6FB239ABB091B7718A9BA16D5A33083289E8347CB56172FF037F6FE1A9F7EF4D
+5D68E23A9A3B9F63C2045AE2B1758489AFBABE23DC1FB610B37DC573D2C0AAF544ACC904
+B69C7775244B1ADB77B51727FC66D02637CF2E9C596A05AB6BEB23295A093AA90DC3C3E8
+F17CEBB44AD7A8BFA8898D6BDA4F84DCA2A30FB5F0D151D8F6666690BC71002F31AF05EF
+E033513CE82E8639B45CD235F24CDB7C7C3576149CE989FECDE2F51FC835CA9A023D889B
+F6DAA3DB5A8AC49DEFF48266333B5B01130F954242A7D5A369CFE937D3AF1C4F2C64051E
+59FC2AAA3871EA827C5B74C70C259FD4DC5DE81E2970519C433F1331D1D08F5DB9BBC9EE
+80D1B7972C7F1514F7116E25DF3E382785504969CC0AB8DEF43F5F45676B2090DE9A775C
+04B5A4613D38FA586F05753CC38A684BF33D2991F909CFE097F97696CA2C59CC20A6D89F
+4710B1EF765EDC4D5A0B7BDD33D8E818D97C9A19848903D1684436488AA7E204F577BA24
+F1D1E0D39ACE2DCB56550281BB24BB686F605B7146660EBB47F8E329EA27F94319D795A3
+71D2D04F6B3DBC4A61D4A7A6B748A60B5D8F3586FF31AC143FB706770E4DAC9A6741EE88
+79870FD251625EE5E77853F6C5D2F621C26757FE64857FE4D0502F84C14825D9BEDAD55A
+35C640D9999543CFA0467165E5AA8E50699A1C13589A862BD656A22A50EB6F479D5C79F4
+585212673DC2BA0DA86109FFA40F5FFA1F660F8C055D2E9B9668B2966DCDACF5F189D835
+C029F51B85111D9D48F507AE75A7BA53CA97B39A5287CA4709DBEB723E6D68BFCA745FCF
+7DEA768DB0FE6140198D62E880E49E2997AB132521C94D259CFFAC9036B0F2C2E15E22AA
+6151E9D4737FD36B9676450E6F7C9E7531FD2F4F307D6D548F37A3DCE2CA5A811EC19778
+12B37C5722AFE78E1425C2C1C06461C1508818C9536FC9117951719B8D431551B4793C81
+CA6938CB75BF746C247A9F48354B0A4BDFB2D6DF3E305218173503195BBBBDDA322153A8
+2085F0FB5ED657637791A4A7E1C1B23CE0F8AFA1ECAE76A3FBB3E6B7A2BDA2E2252B2E43
+4413F7B626AB00CB381737A2BC0837E33C3E25C63852B841E70722F7ECF6238890D63CCD
+2C93F7A2CEF10AA710AFD333322F4907E87A12DEF07F5C7BE344E73CF12CB388BB6F049C
+D9713EBD215989CEEA7473C00E40F79CC0038762139D9FE2B2BBB290C51A3B4B9090D039
+C22B1A620DC1C3128C0EAFF4C62A29AF0338C65B6730BDB7D5A6A7261C04816B7D11463A
+935AA0D33802EC148CB8E7DF6B8FD0FB064BDEABD0DFC3AD5A80CDAE645B7FBBC59359EB
+A0D70699CCB53887530C3AC4E796DDA9AA05F36CC0A6D0C2F616E761CDB1ECEC164974B5
+0C0D38697DF56BD7F7F1772771054F18E3F5EDEBCE00939E70A43766D0E99EADFEE152A2
+FEACA0BD0BDFEAD28E3437753ED58E345FC0D6F4E395667411D4246C460DA5D3BF2F5374
+EAEAE1DF1A76A592C4957BB9C4D406257388DE96591969B30D10DED2C5B647B66CC0BCF6
+146FEF353A20A3A2E40C1A7B7964033816D6A544399965E9C17FC44C524268B0228E209D
+2276C1071535597E57EC3D9C4D8328CA914F54536B1F63C89325D6B26DAB4A5B1FB8260C
+241331D1B55C91406537C5323ADD2E3CDDDC9E199CE067262690BFDCB5184E25795251EE
+181E745001ADEAEE0A9442D57002D48D6B53E693C37E0BC64ADA28301235E9799D9D0AAA
+B4A23F6D8B4EAA5AD3B6B40618330441F6A24E44B160715740198B551C2883CB17FAFFD0
+3B4CE68ACBE3F6B33E29987B5258C1F7DFB87DB89735F05AE7966FF1F2B6546AF2A56918
+3687B6DC7B1AD435DA0209B0AE7CA01A3A3359291B1435C0BF04BDBE2B8778E4EBEE35D3
+17EB5CC7A3F7C5B7743AE69B16A6B9C89491D121617C20CBFA52E93274E6BBC8C0E9924A
+002CBDD7922F3437560E3747B93775FA549457CDCB2A9943AD403BF8AF05EB1CA0EE347E
+E832C6A17A3A53EDD50EF553A0E8D6723D3DAACEB6F81CBDB5B78A5B207A98183C3650BE
+A88F82AF734CE32FFB1118E54FBCBFA2C2705D65FD4A1B3A3734F188078A7B09738C3EE3
+A12FCE8B7221C3041224D324AD3C514EEE792E3D47B1E8DA34AC3E577163E7AAD2C85170
+7D630EDFF8403AA2720B09218E0013FACA789243FD76719860373949951B1907097E01F7
+2840CC3089FBF9A86B01E6E5A882444A3D167A302AEFFD3AA9463A68C7922104E365FEDB
+9BE61D5EC0A3AC5722F2BCC5101BABC86333955964509096B6799F286BEE15441C3DCD84
+A846B35D0B027C48DDCBE123DD9D2DD6A4808F0B3F98BD4BE29E1001905D8606390EEB35
+396A3A981529655D67FF0539BD3E1FF2FABBA0D4393CA781FDE2864DA5D2A0FA6F78063C
+03CA44F27436C3421683D242EF3952B8707863F6DE2E3C94ACFA9FC60EAF7C8D09BE2D27
+BAEAD24C01748E1EC790EF22AF24F1F7BF0AA1FACDFB5C8E0A9B3A1E9E53047E4E791D7B
+9DBC38B9EE8EB0E5CAF79C84E81897A4B202C6A3F22438D9B043D982F605E5C73CB01CE9
+56E9DA66D7BB53F38BC43DD2962D6589AA47BA3E0AD6BB8E0557127CF8F6F83AAAA3597A
+8B57BBCDEEB2223AA2EB36BC84C7BF53F3B7D9C221FE76629512D04EC454D92060750F55
+0E76BCBBFBF9566266A8D033931774C37CDBE5FA71FB43137E5592DD67945201E1D10467
+A3BC5C273DE16E64035C39E4A36D7AA7F4E8389A1FDBF891B00613396194EFDC5B77A9D0
+9AF9C1A4EAE52C87A096FDFF8699EB01E9EFD3F786A7D45AAF8D9D33B934CDFD85C495F2
+09009C628EE54F19A9F02CE631DDC692C3C56D2FF00B8F277A18D1F38A63C394C717A0A9
+0B01AD75390D853D63D0E0678C35022369BC8C985C8229C98CE6BFE1C40770461A5E26C7
+7A7AAB035D6AAA9B0394021020797E627E2E7D17B39FD2E7AC6FEB917A148FB996911869
+49A036A0E5B85D8BCC59570E4C689F2E802262ED26A13C18A57F99A74DA94491C5727246
+D3FA45A7964F212454E119A32738582CD4F5899ED604F76F0327CC1E5746A86CDADA7F97
+E11EBB6524AF8107F3A8F0B8E5F887B799DCF9F9481859EC4E5FF63AF0C294C2AF716EB1
+3EC7DCFB796E3CE4B4CDA1DD15186CDE479CE4EECD1FB27F5A05B69FBDF436EF246E8BD1
+A03FCEA5FB213D81F80D6ED7960896101E046D1101A7522F31AD1BF6C08C5ED8F6574F48
+2B6FFEBF34A2A157567F1B82BCE3A46C14A168B0F4658055BBBA2E9C29A4DF42764F95CE
+0EE9645C6E0BFF33CBBF3436F7A4FAB4B2A5055FF1DCEC075431A99670E03248CBCAED63
+4457D0EFC6565472A356B1169775BF5156DDF85E03688FE2AA31A158A65A1D9AA4489CC5
+6FDA78AB85C35C42B1754180577244C5343C21E222DA72B8BFA097BB860E9F834B62AF9D
+D50481FC4B1B9861A1C2A9F340237C949FF030096DC29FEB028A00A5AEE8507AA290848B
+714C13145AB3F4EA42C8EBBE4A3CC737C487D0DA0CE29BEFBEEE34F5CBE03DC91E5E2053
+F114C70CBE94DEA1653A26DD4CD332F62AB71115DADB2C6B3339878B9997AC3AB5F5ADD4
+9F432AC706A5256DCC4592C30DF40C5C47A2FDC72851FBB0E4EEFDA227B72EAEA758DEA2
+341344315496A6F22D42FFC55B4E90821C251F0D8B5FD3E0802D04E10DCC31E5024D330B
+25AD95CE31981E90BFECB17E786A10ABF9A19220DB82744A43BF5B4DE0FD8C54171EA498
+AD14E0972D6EA90B5CB9846354C855E2E13B369BCACBF8F1852CE60227AB27CC84B9D326
+68E851BCE4086558BA8106D9249C3785F3C59E43827307C87C72033501ED888E32325158
+879454289A07888F09EC7EF1D6F55B92363BC740E170085C4D16547007A66B6F0E1FDB4A
+4FDE032A497377F8B309B5803CB7B450A246A0CAFDB2F8CEE254EC5F6BC7C1EA38BFDD79
+268969FE9DEB9FD896E40E479222BD480EA1AD9E5E0EF7780D3E48D62219E5518499D46E
+DE92464609DCDD07B5C948792B71F1854C114259463E839A2DE74A11A7FD114EDE9329D9
+F1EE8BE5463AF8A04943BF77CF68B0F3CA2571D4BDC19B980F8919AFF6EC80758056F93C
+76758F0AB6313052355085DF8F0BD62C7380AA3D32102F48F4F84C153295AB27F3F55694
+E3C6339B3E34166DB450373B9F326A1E108ECD95B0887A4CB8C54A811B398C0B37289C81
+676CD8D528C75437BB2DA5C83C0FCDA94588BD785E4F800E87FDE1F277AFBC3ED0C5680B
+27DC483446A828114CC9B239D8D1C2D920CF149B097F9A78E35C0BAFA1B0AAE5730BA067
+B142087578ECDED1DD73E8541BACE5FB813E14483193467EF8585682295816C4E29E197E
+ED404E94340398A95A470A9E06BAB7BE0F5FB22338A833F9157594C5030639AE0E69894D
+49098CA950C39937BF17194797AAAB7E076A2087467A2D29683142D84B0810F1C603A95B
+3A81C3225003834CC446ED0944654805AAA164B088489DE9F71701AF4DA42C675388EA82
+CB8368EB21003C19AA278FC474731F2D74A008F24792F651F110E23EFCAC719E2E9C0481
+10968EB515AC09006E062EBDCECDB6D93772EAB20D7C105DB828A891F2711DB786B575ED
+484349390AB27A3A767D8092B7585C8CF32F5FDF2B9D78A27FB8E05C4C25D970602ACA43
+31FC692DC5C7F7C0FC5669DD8B150D7A4EB22218DFAA75E79263D106AE84AA8B573B722F
+BAF6D7F79097AE4007A3E519C107AD00F63069BCA7314000DFF2B06E4A9DC82FD10B27FA
+16775E13913364DA3020F7CDF748CFCEBB7117CC4251031F6795F4289C4A63088E985927
+B971471069135C4DC3BE1FC3912B02F933F26F72297FCBA9F21820493FB49A1A862991E6
+948A274C9C5954AA6BA752D4B4096C953E92D916369F9AD0DA5055521E3420ACAA45D436
+6D061135613BD328630FEDA1634FFCD8E2F23097218C2449520D986694B882081A791CB1
+78925494D19A7EC770AABFB956E69DAFCA7C72698AEB9DA304765F3D9E351022F02B0C37
+9E8897E597144B416A008212A0780DDFB9FC1D89063A05D216AFED272F8836E5356A8BCA
+818D7F491044995DBB9574BFA5B9E346409B9C4F768B59F654E9D607F3D5A078F1F5C0DA
+6EAA9123F369B3341B40BCBEF1EFD9D56DD82A15B550E105F03100B18C7647702879FE4C
+7D61243D5688B2979BF250CB1E594B1A2B9212EB957DBD3D41C0029A06C9BBC302F6E969
+4E998A090296411D7871E35D9B367C1191A3F9A638BDE0784508A7B4475F768C24BCAB2B
+AB375DA779894022D09EFC62788289D9E72B74F7C52F2AB389038D4BDD244E1CC79B01DF
+79E905BF50CFF6A5C06E68FD894BB1CB7E513B33F34400DC38EF8EF6E39268635F66CF70
+D5EF4EBE5D4F36430233785252376CE73CC9E6F83BEF01F6D1C5AAECB6848CA50996581D
+E069F69083ACF3090F29844580712073716A36392BB2FC1049EAA0E114976B098A344B66
+E0CCBDCE847B2D3B620DFFEF1ED2FC8FEB76D1766F76F3855F2C2DE7CF10F4DD4664B006
+2262CA279472C2FC0882A8F0B5A4DAE04D4293FA7E08D7639B3D7FCAEA1124A261BEA0C7
+560C6C52E61802C8502C66D4896EB0D8964E0ADE75283048DD0A1E243690D989A49FF16B
+33740C7A49B820032167807CF695F91C55C0BA6D6AE7FC7368885C674B8BF30931870677
+03A60AD58F42F6766DBE60A74B2C2E7CBCE56EE68DD0D269FDF5765AA414157BC63F5CB9
+123E0532224DEDFEA2E668F3875AE4C5260F93398EF86BD5867E0E18B497FD85C4FF4A4A
+3AADF54256544BCD7811B58134BFC41026132D8D30BF6903C2940157AF0568C9B6BB3009
+7577212F65BDEF06FF06760E38BD32AF61BCFA7E2324D68AB590F2E45A9761124928F6C5
+64BDDB6B51180CBF141F48EF9FF6DAAAFF2E379A2CCE80EC839A2EDB91827F9D1BA0AE40
+FD36DBA0E8ABCE564309F7DDAD96A5C7D87212F8D586F013ED189D6850322E4670CE2D07
+18CB688DAFCF1961FB0F4AFDA71382DE9CD976FC29B4CEBADDF073774D9B8AE9F2374C04
+F704860ACB17F8A16B4051EDBDA362CED1BE1BFD0700524188278DC8D6B22E0D585F26A7
+C4447076AE0998A76AECEB8454959F30BF5A4BEF1495D6549392AE39D97388B5AB14612A
+D6472A6B625134E17B540AC0D514C1239ECCAE5C75C9F7ECFDDDF66320D00052D874E6AB
+792FB1CF5F37BE8F34A14CFAF642917406C3C519EF56C92114E706BCA38731B52D68B9E1
+61BDADBD17A62D1074CBED9FC77F5558CD4970878E0349536745C3DDC0E6BB4CE878B2DF
+361B4DCDC5FDEBE160168F4D0DC81436B008714A2EA3BB569961F07BCDAE095A44F578AE
+6D0E6B5DC7CDD38FCC37177DF292411C89B4B64612C82029570C5A7B9B55F38E063BD3FD
+E00421B42FA18751B624D59495604A52A0DE27FEBBF7689E0DEA085841050DEFB7C9FA52
+D3515731A1BD61D4BF5E82841B221EF88D921E1EFF65F731948CA481E500A46E84487BE4
+E3F9DAC68918F117B77A2B5B68181C914FB764CC5876D2A42CFE47F045F72E5E443B4921
+D0D63323C748984F622F00F63C886F404C671119FEC90A598084F85B4866A5C79E987C5D
+BE5458A2A0FBCE0BA6ECB7433F9D75142DE04FBA357042FA9793BC9803E78E573A14E140
+BAE5E044DFB28D9BF672461BB3A3E50E1BFC83EDFC49A962DEA01047208F49C4CEC837A9
+D2318E35301D2B18DF1E8D828B58FCE8D5F1450E4CCF92BE5CA2B30516A4E585D6C83BF2
+80C7442A4F942584BCAF4C2CB5C2F56170817BF0535EBA87C75BDAA0190710A7E2D4029E
+CC54559EE6424E26F0FF8E1C2D3D012B3FAC397B1A446918F1D299A19B7A28C4D7F146F0
+CA4E29B96D275B54C16B1AC37FAF498462C7BA8D2C11291175FD05A5B3E08290EED58ACF
+680DB2202F229D7A69F982E644285FD1FAF320A0C88E35BEC245D249AFBCF6CAD552423B
+EA2AB070F314FB9B3EE02ACDE1FFA602D19E1805F27D1AFCD58D6D227EA765E6630149C9
+59ABDC3067CC97A797C555FDC59B9E4DE3B0681898C970609B1B6B15A15A65EEE2DEECE7
+2BEFB1E2C7A2BE2B3FF19B2CCAE4937DA4B593A60FBE0E0DF3925043E677D44B5FF7B42F
+73EB65150EC0533B294B675BD7D5CC6A7BB6A4F043FDF87940F8A8CD366BFC008273CDE7
+72EC15D7367371283EE5BC26CD6D46CE665661E16C691727CAB0833942367DE588BBF434
+06F4DD67988AD1C0D5C3D24DA8A833021F65E4E4393959434E03CCBBCC98699A8B1550E9
+C3192D3D3755F81C51E6CCF4C4E6575D9D4EA77261B987C8FC8CF67035D281D76041F70C
+2B2FDC8FCD2719A93FBEEEDF54685031ED2E960D2CCF2B5DB0840B2554B1723A703C41CA
+1E6169F96A1050CBA7A1554FF8A6D7E4BAB0B549664DB9B808FE7C5EA9ABA7B071E71125
+54D021BFF7345D1295333E876E28E14F2274CA0E5E4F3838B775890CC30909661D5B86CC
+4F681967BC8B5B9169C6D8F1B30ACB914E1140C6A5AC5B6855EE83BF9F8C5AC875D93BA4
+1C62B9D44917BD3B46F65B23FA3044FE5A6F812DF1E77139253576ABA80A57B38D315E82
+CE42DBB3BEFA62E400A194B5F59DCBFE915D3B5DC010B4DB140127BBF0195434F5A43957
+881974EAA69CCEB2E588DA124EC3F7CD00F6BB81AC494088F061065C204A851B8890A5F4
+EBE9D680DEC34FC853FBC85E20E3D9DDA86549FE11396BE73B2978AA8A4C80BA94788D8E
+D03D48C88C9E047CAB868D7DB3837EFD41267AFDF4808944506ED385295788CFBCBD89A9
+8DD84168F808E49BD346874FB281AC70FB138E100D914093C582E7C85F5EB6243A941DF8
+253B06BD01E8F75C693123BC20D17307B8E8839CDC5CD180FBBFAFFF702E0E9F6077237C
+F81EBE9737C296BD5180F40EB79A41BDEB37FB0FCBE238F1B86F45D8F25B39FD7DD4DE88
+4F1D9659A27AA3F25CE066D8D84FC09932B8B2D3BC89941CADBA33F7AA87ADC13453C674
+E8AF9CF633ACC730085EC2A843949B9E5BED6AC3ACAEE21D620495A0DC04260AE555D15B
+59143C29566D3331B26DD93469C682409BE8D37BC93424E115F7DCDC95EECD57953BBD28
+974F249FC98A73A384260A0568A69B382886A9AB09B6215E463319F8736865F700134E65
+1D78B9C819501DC01CE5C55A2D58F12D74988AF124CC6C7E213520C940F6F8CB4CDCA9A9
+DD2B569D06A967208EC37AD2F0BFBA7AB7DFE87AD7A5AF4B6E77E2C8F90C9A97D7EC58FD
+2D7ADB97CB6AB5189AB4E5C29A1044887CBF775E09348A2FF946E9D7FAB0A13D7405937A
+EA98600DF50B8FDB161DF14D091B58E925BF12EF3176F3EC504E1E75FB868CC46146389C
+23DBFE0F908356283136F4A2A3AF2C197997302BB3E545907C3295AC0FD06D2069D602DD
+052BFBEE41D7C926B303D4C1CB548EC9537A0F5FB5C31899FD160BD9EC390F2E0F6575AA
+032A78BFB98714D731B0804898F148ADF072B3E714009932FC8ADB363B18B2B15627D3DB
+B20DE94FE90B2CF68F85D7961E9035DE17AA5505254D50704903F28EF414D3CA13077AE5
+A0BEAF8F5E11FEF25C8484A34A1C39FA1E8CE92F42BEB83158BF26EB1944E6213E5B1531
+C7065B2F1449D3D444855727E691A501BE62F659322006FF9A22A5288260A785611791A4
+56E6915D344495E82303F067471E323B888A61ECFCEF90676C5F490A9DD6B6803C5789FC
+A7B0B7A1C7EA4BDEF4463CD5304C626E8D714619CBDD4C4EAE61EA1D2386642DD4DC77CF
+3351FA6ACEB1ECD55CE4308DFE9A09763EA427021D90972F2B8711A98C246FB448FB3FEB
+9887A101F53321CE647B3B9CD077A31915269E6D049E48305F3B2E84351FA7C2394520FA
+BD5EC8CDF9EFAA99573B1788E0C77FCA125F590C38939FDE67561BE1EB47575028ED1F4D
+27A7094B0500824F6FEF2710FCC5768F506616AEAE73807BE2ED2E0DD4C1A337993C9A62
+C7601418A586D038E886E1E22843C38A9F34845DF71AEC30726E9AD413A84081F1E31A53
+73D5CFDF816D8F6CCD90C2B438BBF715F0EDE86DC31341A0899CC6374C573FCF2AF67A47
+5371828212D9AA17F18FF25801F83D0AE19A4712E24C2C024A7505A2FB269EB3E7DDF59E
+7D95DAD916A5D35B7D16A82764DDBB3773CB0C6E3B1F2FDCC0553B26795C348B6C0DBFEA
+E7CA7B74D90257D8AF4F9D4F3C776D858CFD230781D2D6F28CEB29BF4EC4D413DB9B47DE
+E4B36F6CCE14C09A033D580D573C21B4A45DC172C0EA0DF41A0BD5CCCD6479166B30961E
+A2094DF2262D9E81465ED2C66BBF8B28CC4A25CB7C259BEE2C2F0991614D161B25D4635B
+C869B8008A2156BA56B48D6220DEBB6713A035003DEAA0160477F5BF7E336E90CCF67155
+0A55B6A015468E8A8FC8050C979178EBE2F7434E11E6A77E2F99A133F81FB87A75F42EC9
+AE9ED23A3DCB35312036CD819952BCA72525A39594C79C52568556C3A90E95C6E789A99B
+04348DFF652C9A178C5F88EE957D2D037FBCF584AB699B276AC228DB743B4C4548EB54EC
+38F6157163A870C35A4A7861ACC66118FD3EBAF43154C13A4FB8C52AFAF5F7FC67571D85
+F994E66BA3E8ADE5973138F61AFAC440C1EAD910FF8F79B11B73C697FF7D921266E48D51
+DA2FD0B438CCE7BFC1A1233FB8B5D812D8E18846B6401E9CB3A33C514693F19CC21A2500
+FCB0B0EF63EA74441BE9BB70477A63A641B639C54F93F4D4BB8E76D0E6F49D134FEC890A
+B6E118D754ECDB3FBAD7FD4493AD9415ED13C05A0FFD949F3363CD400C5E2B547F1CD6FF
+E503F2F4620579B69415F4BC356F943868F198B4243D250992B83BEBA3F07930F0F93366
+72AE171AD02B20606532EAA8F819AC8968430201EFF0FE42E8CAB1A10431FF0353827919
+847B2B20B0B60241ACD440C8917B4D0723D44A5FDBA7681E9541AB784B1A109473D3AAF2
+C035C27419CE30E5EE3C62F0EA884E4D4F164776DFF12D212629EA3AB2B103F000BE0A92
+298F4D73B79AF1929DF56280BAC6F03ED3F9DCFEF4B138F88758E14D4E90C95DBD9FFC40
+173E6F795689C812D24BB1791879326ABD3CD7FD2985FA950B73099AE1B86959E46C4709
+1278D31A41B159811140598A24861E34F2BF09ECE88BC36747DDD892AE3918C41A961D35
+28D8A8649E626FCDC9551E073855DBC34B57F6D198831CC189FE1C452FCAF8980998D621
+F31D2B9C7794DDC8B32FF3F8BE6934B03CE603020E7A37B51DB4E1FC33F625A8983B95C1
+853A1B1B4D4F4942562DB9A0FFAD4AD95A977DE81139687123317B757CE75ECDC8287609
+6D7797D50287BE38960290831474ACCE3F57676811A5DCEC78E91488C53167DA013E3797
+A9A8C05968C8888B2A55EF2032D66F6174B61CD24D0C62BC49250AE6D9B505371CB15160
+C591809EE7551D40D3CBF88D33F8A3A9412E6221D9E656D22083980999E405957E9D5A36
+64EF1F676EAAF5FA309D23C56C95541E7E51958358B436DC4CA542DF18398AB8E4D05FD2
+D24BC091DDD9F4F963A20791D88703056B5AAB84655B3739821EB288F1A1182F67154973
+AEE39C7E8CA894130CB0A9A811A1DE595BF12D04EA825F2A11A365CD1CA85D7C7F2DE801
+985F64094A9D168AE1F9CF287CE99031D0A1742DC08698572926219E0965501497C9D355
+6E9E32D23BD070BBBE905C512C864DCB8BD9E8AF46FF4CFDE9D86E8F34DECEDD99E8A745
+E72885340086FC17EBA499548D8C535CFAFB42D202DF4C91BF817BB786E577C7508CF99E
+A088D9B070F5A5201D23CD76C9DFF960F0A77EE8CC94FB5CDB8707F8A7420B7FC2AA40D0
+6E04F60C595DD66DD436A4E2BD606121E423E0177B17E73CDC168DDB7806294A1A2DC177
+87C4296B2BB174D55D9255EC44CF850A68DA75BE1B577E8DC80B715876712DF29CBFB81E
+80BE970CB01B9F8018C381EE021B57E01FD3A742CA387317883EB3F06FFA93E0473BDF27
+98D77D6B3A962CF9F42D181FB4AFE59DC053F2C059035649A646F22A927A4EFBA9E6D3A0
+2C7762AC72BC6827D49171F1F57C354FEE5E92E96A30156B8484BB3D9FE7A21B59008AB9
+9692940D35EDFC207A14D20D2FE364ED08F54A255D1F434B432F00C67863997266F64862
+D92AF31C3C7961692F6952157C8922AC8C8061E5CE8E4FE5E024C1324140354E9DC3A768
+B2092B0184FC1A46FAE459AFBC0069ED4C2CEE34ED7D756D65A7474B28FE5F56F6E69150
+6EA2272C75943E3CC9CE5FEB2346AA91136F5B306805EC51D6BC12E5D557F1F290E14CC6
+043CA5CD3D0EF095D4E62BF2068072ED630BF1451B8A35DB5783B6496DA31E98129FB96E
+02175D288D2854C505E2403AC9AE94145AF6D327270DB865EFF70867894567B87FF7E5D0
+16848740741342E871BBD632ECF7673E1C3ED00255BB34A67D709E16EA1E0BD24F6510CC
+C1097402E3994605B5CAD28A48DE6F37787A77488D8C62614F5FC3340E952066B61C9DE5
+1EAE3FBAD5D8B5AC64F8B261BBF06FC677A28EB58F4C8A08A136AF3FE387E24E6B100774
+24D077650EC787BC8498BE6D7A1DB54A690C768825ED63AC24E62E40D5CCB2AD05A2675B
+301C895800F08F936C7175F6BB3A5CBB86536D5EF41B111F3EBAD9769324DA1D88C4E835
+223D976FBE5B9DA39161F6F3A7BA02031BC20EE1143E1FA73599CD30CD43F0552510F0A3
+67E8E0963D12B74C429E15BE22C0AAC2717AAF021D437A784CCFA60E8BE2ECBCD962B1BB
+EC8CAD0439CDB73131D32363354CB9BBAE21B01A27830971D1D7B842E3145D5A400BAEE3
+76C639A3B5D2AD8D51B75F7FA86465DE401BB13FDE3407A093479B87B0E3B2BDF33E9569
+6501ABCD07786B1ECF72DA8083FA1D79873753B466A0423F1B504236B95C497F39F5D5A0
+0417B3D8AF9721E5F3B5ED2DFE47D9BD0930F4E9234F181CD24394891F7B554766BFEFE3
+CB4533E3D01DD656FBE2C170B82393C0F3BBCE9367C9D5735AF8317450C7F4B163CE95F2
+6F2F7DB25CD88EE9B01716DBF1FFDA7FF16D54EA39841BFD3EDAF3684D2298ED45C8486A
+F5014230F331FCFB320D28D5A1A17D02D5593538946C8669B346F4693FADAC663FC608C6
+E091F481E1C39749D26AA37062D7D94115152B214506B91617E829833AE67807905C70A6
+8412293287EEB2286A27DC7D7B9AF75FD4E32DAA4641EFFA2A79A04DA0EFF958F411890C
+A50246E5A1F53315ACE19B22C9C14B897272237374BDA4221E3FD18A7D4E26A09DE3D246
+D604FA90092F188E4D2C6C0144E6D49DE9BC8ED4561B9CD8EE8D308EAD97B6150056AC9B
+9551CDC472A642A9DA02BAC20EC5B57698D68ABD0ABF1B0FB5231479D72CF429C39DB34E
+A75AB17BA21AB31E9DE9E2584C2EEA8BDCA322F0D03291CEFFF011843BD70C43F49551B9
+B10DA24AFC0B79A87B6F493EF73E690A4A705DC8CDE5E2602EC6E99168357A69816EA5A4
+5945A242CC85BF5E7B665DB8276C11483E879A1F9A59E4FC8D6B700519ADD96909BC3EB0
+DDABA0BA75AE8809B6B802FA830E63583622109614A63B928AFE297D434A33BD0A12ED89
+0C15CAD72DBFA7EB5F30B12077EF47A6EC309ED1009141176F7932955588C053DF307C96
+B719564855ACC024859429DCF8DDFB3F7ADE1BD65C9B6A97BF5A56FAE58F41BE9ACC6AAA
+B0356F58900CF66FBAB2E2439C031103D8600FCCB20D209DD510DFE90716F654C539D349
+99130FA43BABF53F8AE298F10CB073B797AA50E00FE9F88D9337CAC4DBB0FE101C28283E
+6D4DB8FAE80B4A998525F647E7023AC5B9BAC987D5A9233541214BF0DCCE6C524BC1C56A
+ED18B4F76F8010AEB8E1024082D22AB60BD9F338AF6228A09E7DFA8438F2ACC066D2CCD8
+853062A5818DA00F1747B6BAB166F40D7639DE8CA985C2808B0010608FC7923C7771F728
+FDAFB1F118E2640C2C42301C465F40817C13E20448F16AC7D42E39FBE359F744C12DC67E
+99A4B92D9691E1F6D2096F11FE4F017A4C2B22E4C550DD25E3E31E8531CE8DE879451600
+4C9236E36E8009F5706C8BEE72F007538DA5918999B97C386DD6D62F7B433DD99B74B490
+263C2AA2D059D2DE95CC604A5442116DAE3264568FFE88A9B1E4801052084DC11101EB03
+E514E220E7BA851FDB7B5C8CF635B2496FF38CE6DAA23FEFE02C25B520473E5E07EB9354
+EC2CB7A7A75FEE158D51A7CBE8EC36DFCD038BC52E9FA6483A5F4815C132B2C40544B08D
+8C8A80B1916609636C2B53FE27E2B4715852A6F035C139F9EFA33ABBA2550B8CEB8F9C0B
+EF80BF543D1745FA88347997D01BEE8A8E2FD52FC40D3BFD3D438FCFA1CC5B4082ADB51A
+5EBE54EE1C95DDAF8E5FF6FCC98C3336A292A0FA05CB5B48C122D6A3330898979AAD071A
+4BAC19B03B03CBA077252506F8E68EBF004B962BB85B15A87FE5497E8F2E208117834E48
+62EBA7AEFBA9A8997F71142BD6F6550F3BB358738B182A9CDD411159DA92B0B3E49E4226
+627A196036ABEED57F176C72B30AE16C1C01B330577FE8FB0C0F7E09BF821BFB4F056A8C
+B52D5797C0FA48A9625292440F76387FFF46837A2445688696830AF32EACB2B6096367EB
+A8C8C42341D2F3EB5D5190D9F7241FB1EC16DF0D6D40FABACD1D7E99EEF4AD6118696165
+3354A8DE539F92DD3426A196A7DC33F92B170D57E48AA80902D9F31AC582A4B569D15C86
+A8E6FC94D75970BC6BCDF2C77318B1DBCC7E398B48FAC8D2E392E93CC37F0BE6186DD645
+EB077151C6F58EE8203B697010EFCA123FA904A4EA80388FFD88C126AF7F6656E66B5417
+8134B77DB4E0797C9213483E787939113C39215FB9F5B3B141512D962C500863C2F362C2
+3B73E9AB89571A003E413435A02FA3569228CC6C0D5EDED34373FC7EBDA1200537C1B72E
+9FAEC2E74E5E6C3E13CEF1B8F332E7CE6CBDC4A17EB9CC265638AE57E28E34CE99CB44C4
+AF96FE97893390FF2583486F7D8B0B2D9B13A8DC0551E8AB85046C9E4091B6D5D5B193F8
+3EB3E2131A6EC9DCC9DE88F4B64E45AE7B5B6CF10D4F812C9C784BF65FD9E942951AD808
+FC9F010A0F45723593A354E578F8FEB67978485F40620C83EEF210B6678CF323437DDC88
+5436567D76EEF3A83448EA76A3306CDE9D5045FB2BCAC94A7A58B21C0166D5C4339566C4
+203535359326524E7AE47FD406959610B24FE98ACE978A82B5F644B112EF6A289C018244
+85AEF2D0C38178851D0D5A6612C861AB52B46597558EE8E588F95BC8D657B02AADE2AA25
+9BDDA214A736CB417F9564699D293A98C7A7615F47806B5424CD1FB7292AD1F2D7DF6837
+675AD97FDCFA6825F4E22A4C0930299B0CCF9BCC67806E4E6A8EEDF449D96634C19EAA00
+912240EADD63C8FB02A227B987A17964F5C867079495B383FAE560309FABE8BBA46C3F85
+E766A98E5B8A980DF3205AFEB8416B4610E6853409B658DE2A7A3C2C6A292FF33A46D9C0
+E34FABFD57E19C89A8F88D8C4798A96F4C8C3655808FF336C7DB56F52E0C6AC761DC0E0B
+39E33065A02A8812D91AD303F3DA2C1D61913C76F1D2DE272503B223ED71DF65A5168433
+A7BB3C3547A7E6A5A190F200992B73151BB9EE0D8D55F9AAB9D2E73677D3AD16D20D553A
+D7A7A1668B19F58E7BB9A5CF973A861645016DC2D07A39D5430D6D1644B88035B8575DDA
+D2DB0E6C040FAD93BD0B8486715821F2D47814EBC7EACE1A5CB5D3A2E19352EEE008F258
+6192627BD0B3033199DACE43803176F7A19946985CF975DD1BB313DC58DDB80A2671637F
+E89D6354DDE8F8825550F1F616DAFCE19CFA095A36BC49B8437C00DB2DFF9B82ED7226A8
+06020769A534706BD6180DDBEDEA953C98D639FBC8130732B42F0C512237F541ECD03603
+8EC9F5BEC45B45F87A324B60E13280A18A2F6F333C34CC254464F774DD53906B7FBC79C1
+CA8CABD58310D272CB49F4B3C83EF616A9743CE5C56BF52B00776EE469A45B18B8457CE9
+DEA7CD6378C87304224B578E213AD3D9E5FF6E642BEFBD59162DF73F0B631C8831132284
+39374839A1DBA4C4B4C4E30B7D411B5247F258F18A8723659A17A52F8194FD810318B32E
+19DC9B355C028E98A36545D65073D0F8F4DFF0F9637C6F599C2F883B10FADE5077B49257
+F16D0ABC0DDD9356F6B10FCB64D6B6ED9888E0312B092DC9D154CE76AC14D14DB564EF77
+0EB48216D431D21672D50AA13307610DA45B3AC8FA46EE7F61D0C643E53B65CC659E91A6
+71BF448EF3FAD8D18794B383523AE67CE1903510BBE2B2D5CC5D29F3DAFF71A54E582E22
+420D62CD7CC8A4E093207432EE4FD0FA3B2E72E5E4E62B450C557BFD0A83C540C1FE9E80
+C62D150ACC0CBCE73BE88F13D7E4D9A3791C806B38D12315C043CC022AC8CD3C61331345
+5D19B2036306F132C074043CBFED8F1C1F60C74F074708D3755A6F28628B31C0D8068669
+C8BB86C6412F32C8D6772CFCEA101D1ECC32AEEBDBE423A7DE28BE36D54D61CED5FABCF2
+F0E731800ABB9B10E413129331BC441F80A6617F9A5E551CB4BF74893227C7D9DF21DC11
+6C7E796F8ADEB43D2D223B4647DC5D53E65786C5A0DE8F3CD5BC6662B051291E36D47414
+F94D999AD31C1D6916EB723436B41A72844806C0A8D4BA41A04F1848DF180A3C3E27D8BC
+961FC8509CB3D4069B33C5E01F3C0B04D55AF2EC4CFC4DD7EEC9AC9426CC907DC70D9EC4
+E428D30D8B28A27EF202E3788C5D14B0AF13D750EB7A8C5C4E5141AB5A477BD660753B64
+EF5C871681283A0DA5AD98DB70A90D72BFDCA0E18450D3091EFAEBAD23EDECF3F016BCF3
+BFBF286FD52B5D38D3D02E8161F8485D3B9B78C485A196C5CA052DFF546E4CAAAA9F9F8D
+925E6F4D842B599E1A482C92F8CC86789F192987C3750771A11076C35415FEA472B29595
+9A437980A15C2136D26C83DA0AD724B1E961251F80B9D751A89A004DBD66C2540F758AE9
+A8D9A87A40CEC4A048AD21AAB511A630EE7C6DB0BFC5516B18140B0FB30CCD128475CF08
+1B10D9E5DED0BE1ED477142BAE698358D9FE9090CF0DE3FFF6692A18E2AEFEE40CF40B0C
+AC0CBFAFD61CA62667B8C6AF75F2C8C610189522E5C334C3EE4C5949629430D193846DB1
+3F2F49284722C3D93FA7553DB263182610D960D1154CE3E72E93D477003E26405DF8457E
+919785328FD7A0EC5E75FEA4A69A4B83A0B1BF8A257C95DB99ACE02E4E1AB1C7381F70EE
+AFF4424E5DBC89F8744C31CEF9E39CBE52AE7B222C3003ECE5CDB70CBC5705BF14A8DD96
+858B2D91BCD9048CF5499B557B47EC7EAD4F691D9C0ACB5AD0EDD67F18D0C60BCC5B26ED
+977B54870AD334A5BC6FE43C10EFC67449DD1EE7E447AAEA62CBBD3708A5C53B50D9A422
+D90DED5D2DE9496DCBA55431336DD959C87DB3C827D74142F295A7FA2AFF3FF16B6B3A19
+1947BEB998BFBA0058C8A0C851E677368674FE190B2498042A1091F5DE30DF16380DD89D
+0F8D076F0AEA1FC15F065FB5F094FD7DCB9BEA369B473A796441BB35C3F7D083CDBA9263
+3AECE8EE5EA3A475C84552463F714F38F73B83ACD3DC7FDC9731E55C25735B62EC439FD7
+421236A8ABF2E15F572D93F863CABB5104F2F71C5CD8360ED6A16F0EA6E20965EFFFAB3B
+9AE5935C206A074C7C3A21F8B50E6E19950DC462F06515B3271974877B0C33B7D2F735C1
+06597443E2C5421CAE134AF0E035786DE9969914E2F0B8982F9496D64DBFE6DDD678B875
+9825EA82937D32C5D3DF19C9F35700C733C65D3AE498C2039D41BBDE6CE9D975E753A022
+67E5354D1739005A656DEA77ECEEAD9D8C3B85512D8BF6B1B5ABD84B6D05CAF87B254ACC
+3F650BEA548DC6EF6B1467BEA6E424945B7A6656F5DBC695D3E5434E0B88E5BE68B5BDEA
+9F91337F7A74A5E7AECF9EC30AA070AC66E8B1D8AA70408B0F11683BBDE539EE5DBF9D32
+9B1A1C8CC14407B0FD0BC4E282D2BB466E3CFCB7E2E375A0DD49FEC7A0ED1CB15EBCF2E7
+F96F1094AA840E618E69EC295ACE5999BE90F77C523822EF0C15585CD816D7918D2AB0DB
+65CB72F1AB5CE5625C75B493E801D7A0DEE575BCF53E4F0BAA2290275470C5F6B49BCF03
+E4E8E31CE64D3A6A6C42ECE25B6BE2D2D8D8A821C4C727806944639CB4DC84777A2CE101
+8CE5EE0470D863ACDBA2B69B48EC7EBB23BC73760396F13BF6A60BB6D664D7B553C2AE9F
+32EE16F06A114A3BC7289747FC6D85BA0332D23EC947B25D6C10750A83027A745C1737AF
+E9BBDB080BEE663646BE3894B184F9B892CA8EF2B3AC255DD53388D87859F9EAF8BC82CD
+B12EE266A079F78EA317C41C505CDFA41B1CDD8A63B884DE1EEFDA7B7DB1EF77D0E98742
+79C50B55DA61FF95BFA7076ADF6BD3586E2120666BBCC3E431CBB19963982E50B9B1F375
+55AD6DA4AB02B305E074972C7961D66C1D1327AB93813F7A7C6C860A81281795033C8AD2
+8FD44E1AF0668D8ED469DC184B612DAFC1529F3AE5D8420B703821A559D58D5C574C15F4
+9C6CB20FCA5AF432FAF63E73F23638129D3E80509C0BE0034458DDE29F5C88807FE1C90E
+5BAC2CFD565D686945583260334165D27B08EF3C7839396EE421686BBFF67996E5FC31F7
+C4C96155412C4E51D5B6C97F6C47AE74BE984B347222CAD8B76EF218F34CB3BDCDBFF446
+C8E52F3E2A121903E260C844B093439194BD3078E158273B28A7674F0528C9306CD09C1F
+8D612881D46B8D4AA4C33206EEF23F0DF150AB91D4EF3A55120E3CABF490A2FDC34F85DE
+0B4C3E712D3DE425B3B0B5053CCF7729D8FF20207EE09D7ECA11A2685FD4AAE6275B9C0A
+E26543A3F0C826FBAB318690FCB471623009FC751E656D31538951000A413132B4C95E2A
+75C56BAD12A492F5F44C14016CE7751831A892BAF050422E459E71A614409DFF87BEAF8E
+9D61471C279C9B2981C3A1D119678516111B965A060822114F9CDA77DF46059D434C6A0D
+D4E57EACFDB4560FD29807C7160051BB778CDD807B3602F6CA02F699E8A42C7A6143B149
+2E78C8796116ACC803B5CEB308B9F8E9F11DCE649719618A9EF689919605EE6FA001E178
+4A008D1D5AA354777566B4F5D496ED915709E2FB39688745DFCC3AEB5D520B77C8066429
+6C67D95C50FB86B9DFBEBA2AD8234EA2C967A02B72DFA5BEA5BEB8DB4A30428FAC98FB5E
+6FBECB93EABA637684F4A82447EC00D422DB058D521299658F7D392FC1B0130A9B995477
+7FC2011549660457BA46B01E4D7AD51D1829BBD0C80576E893816FF1355C006FD22876AE
+654B0D851931E1BF3E80090B762846ADC7EFE333D7C6D529D6B50FA87347EB35438B18B6
+DAB4B45CD3202370F744013D15C01AF637A755734706E667AFF3A498F437465B45255BFE
+C519F8BF9FC37A61707A8D70F26AC6C90C73AC9CBE1A2C7F9D607BFDC999B784C7D15BAD
+C0CED80AEE87A20D3CD2C57834020350B4310B17E62B192D376EF6947C8EE477331DEA66
+CCF090F1787B19397BD8129449C47D5E03EEF8D4B8238105D626115DAE76062AB6A01E4A
+874EE181607F505FAEB9F8743CC79A0C674B8E5BD9EB8D02A5653C8AD1E6CD5FCBE83D12
+A64399F646860E564F1E118C5F18ED59BE775F93A3CDD8F1D4630A48A43C0F2AC8DA9A45
+7562CC56B57A802A3F8543BED0A96363529DD39675BFF7DF6F532D190BFD5C6B8AB3988D
+6D375A117DA0C00AA1C9AB60C5023D52793CAF943B7318DB12377D962E53DB536BE2A1B3
+0199D481CB100B3DFC30F3D01EC4EB8C9CA7CE497440C54A12F1EFA9B50ECF7C6AC073F5
+12AC731C94BD7C24209A1BD1340DD6CA5C787E42DC97E23B125B786D4AA2B149D05EA6AA
+891AE6BA361D1A42665E123EFABCCE667BD894ED319B8CA398EB6A5E213F813FCC912F54
+205D51716450E1744CB2A5A8612EBDE46F35257AAE6D3AEC55D65E07C50736AB52295D2F
+5FF8D43AF818B05071354B5A462DCA72E6A5E482A807802A1DC14132E50425E75C6CB612
+F558228B7659A6CC4F2BEE307FFA31A861D88C994C650DD0F1845A26EF0B8D975B9E2120
+D6C669DE20802B62F23867D708EE1FF1EA35CCD53F5CAEB8EDA12E12A58E9F90D150A692
+194564E1DBB173B1B3AE5795460A5D1204F1C02A960659A0C0063A7D5E7497A581B0972B
+B235C90F7D2F89D6F1279AC5A0A15DCDC5B1391F5E5C94AA03320AFB4895AC4F31F28C29
+3D9F6790243F7070E0AE21864C7A42129AC0EEADAD9D11CD447C307ED64DB0BB41BC3BDE
+C9EDA6638EFDBA140CA92B7AD459482B2F573E29B03381A23176CEC332BBD7219231554D
+C5FE2C2C56676A137945671D5F55E080EF0306681C44B994A5FEB444A672512C424991FE
+6D8D33D099D464B44C8365D37CCF13792CD726375A5DA9CFFB56A5628FD564DCC124D2DC
+4FC1E2AC8C0CD8DBA8E27138B3B5DBF786AFF59096E52C999D6A26C5637F277FFEEF34F1
+841A3420594149463AF075107E62315AA0B2D78CCF9A72D1EB9CFD1E7900B0CF877BE2F1
+C7A0B60A1D995F2C5C37F7EDCD09998E7B7E3E2A2C90D4AF8F9DB1ED529B9C3DFA0531A4
+9359BD1C4BF3B82A095562D38C7F15C3FDAF09BC39B670A529B9B7EDA1683D2410856031
+5737EAEAD181EB46EC51BAB3FE026E532E65F7E76A368C7100DD7AE43F881B45DE624CAB
+E5AEE7D7EAE8CE12230A0336A098760C71E0003321B6F512527AA59726B249BA92A18C1F
+1508D2E3881C1E004B830F9F24A706153F4B4565AB16978D608184FE0FCF816F567911F0
+9BFB10C7FCFE2CDE6ABC0C83657809FB8BE214E5570ACA4CB31226DF4F590BC37EAC8226
+DDFD5DF293A15CEDA79699E59CE459F1BFC0B08DA76C1234F996BF4B2B345A18B1AEBC38
+C04218864D6A7ED071173DB25DC27B8FA8A6DA897D83085CDDD24B3F3F1CF936C74B61F8
+020620AA9114411700938AB9E9269C13F97723E29E86EB5F14D1E86D15E8C8D678EC3CFF
+DA4577F97BE67A8D3F60F56CDF929524E00A400C35BF46F64134324791FCD6DFB72DA7E7
+8B7EAF388F8D3C860E8E295867BD9032E74239F627DC645D0F2E99C6F56E3DD919447CE5
+CD3126F491688A53F54FACAAE5A14C796CD964F693C8556103BF132E93E2D9816282CD3F
+32B84CA3798DD4675F6CC06E0A26C443E8CC9AC465E57DBBEE15BB206798C8ABAE8BF0F5
+DF4F029FAD45DD95671892AA63338E63779E321AC933FA3FFC368412BD62387E45BF0808
+7C3594EA7E6628BF2921F2AD33C4A7AB22DD7EE3272150D07ED085C5EEF85F5CF78FC9B1
+468D9698273BCBF896DA6CD43E088F7AF97AD83BF300817D35F93D74FF285EB6ECB223C3
+9368103876A36B5D84C099136868530F1DCDA96B56560E6B0B18D2C66C7FED082850CA25
+E7947934A1B66176B5C332CB1DA71B6D49754A06873F8C37C2C64A16442F0D983F6B989D
+8153F027A9C8FED72FBB1C2A7A56361BE460D85338E47D0DD878336B040E685C48993D7F
+B6B12CEA753190E47BDE31F458FC098A286EE4EF94A0804EEF0324F92643B4EB5FF1767F
+9D0A99B59B1CEAA7FCB5CF1AE8B5E70E3949B085287554E8BB456CBA6EAC53040C589860
+195605D082EBF7E46BC4A7D2284C6518D8F49D524712B15981CBEE064FF6BFAA6BE46386
+BB84F6C20D8D0EC6A18A6B74C30A4BCB0F2B81F100A6E78DC4EBA3E6B9788F424467BCCF
+FD6C58F5DA79A9691CB6D74DCD537AA085D385318AD6EC7C2F04567BF97EC15A73E963F5
+37CE3F70338D0E3994E0C9412702FD7BAEEE2E7A35A65E57FECD397D3EE54C863E641E6E
+AC90E91A8C0F00D839B5ED9D9B2D7D78088907ED499480BB50EB9EC1FC3608A8FC1A20D6
+0C1F86BB28318444201E7E9F0D812D71B125B467BFBACBEFE734A7635786A7AB03AECF40
+AC5A6262239EF8E0F538231D2ECCC1720CD40D56CDAF38AFC197BDB28AFC98F57FC9588A
+F65EE7268ECB44AEC3F5DA1453F0B4021BDB7D7829043C2B1D55BDDCF4687FF7D5092824
+30AC8A512FCD528156758D24318A9CF77678F040D05FA800B1910B33B7E12213008CCE3D
+B9A5E90F708B26AD23F82CF3088D030B0559A6598FCEA3392073693C64AD3BFEFF0A05C1
+C9BBADB073A756AF42D91F8D88F0839E32C317319AB514A6A24CED9082F6473E2B983EEA
+6724C8D82ED94A9A2BC4F375DFD2C84CCF06F9EBEFC67D357441CD976F0CBAA0C8BC2DED
+B2AD5B5CC894AA880A164B68E2F5031566D8785EB72CB183F23AABFED617A6A9B08F4B8A
+203D029CC05C13537C2FD2C98FF701CBB7FCDCFFF2DD7C1B152D68FD70E9F15ABB7634A4
+CC1DD8BA1F5EE887060F223B792F7D204A338B8A3526841D45D872DF6DC3A9073E4A828F
+B70D993043F881AA83A543EB448B726197AEAC9A78CD6456035E5DCACA540D559601B595
+580EAAB91811B756A069A6EBCB887120F245D9CC70C730BF1F7990D119BA7CB75B5278D9
+045BCACF83947457578586A93E32B03E95942B3C036A21DAF4C6F0C5852EB71499C3B9FD
+EDF36F528E9A0124992798C4BCED2711E4A2BEDA7A7FEA0652962B4448818A141E81BDF1
+2F11F423BF5675CF46B506DBC8FF2C4695FD27FEC069DF0A43B7136791E0A3782FC4C296
+9E06336C4F6109809F6ED605A56D1330046925FB5F62032E0E4E2C3FED27427C8B766C2D
+26738A0AC701E7FD89EA4C9136E5F82306DB83E2E9C2B0CFADCE967B2A8EBCEBD67544A1
+89614D6B61E9C77AA77E3E739C03D593E00B07EA925F6321FF5B8F3C0FDBC3948C6D649D
+96529559EDDFF57ECA28B2C0FE35D90D010C10E6E1B826CA23415E17ED863ED5715E7B4C
+075F0E1806E51DB91E55AC8B64DB7731E8A33C1E8F5C8FBE17309859E5DCB58D10D3F658
+05923AFEC306B4359EC6A6E8F9DE3500799B7C7B322204AE472ABC69EFC886C11DE790E3
+603304713B3312C9CFC76ED0E421E2A034CED3E88D53A8D80A3F28F2CCB9E3358B152EF4
+421447CAB89C002C355274B50ADBA185A44A746FA19D7D481F7CB902E73E4AD2A74A1CE6
+3D9978AC3BD8B0DFD03E09425481F63EE2CDAB4AE17CD75A3AB05F9246B3DDC3E0AF1D9E
+CBB521D540C01CC26CA6F3AA5BB49C804D312BA93E92CF11F6BBAC18A0EF051C52C41191
+8C01263AB5901221AE0F1BA6C924B8F937B49985E6D5C17B54E39E649E6D023F0AA42BC1
+D75A384B05519BB0E4118DEB70D272542D60E64957B749BB76016A1D356C681227228948
+5D89E1CD945BF9DCB49A5B831C082755540A032087A2ED82D166E292303CB1180C49E739
+5E403D0C5E6931ED6E36B52FAFE37CDAE28183F15C8AFE3DCCFD9A48A4BC21669E4D3667
+0DF71C4E6087F5B3ED2FA7AE8B5AAEF2A27F063332527B09D712CA18521744D89F90E9D1
+3BCD7EB332AD7BA8055BB8A859C4C16591FC3CE1474E260A74E3160DE648F815383B0310
+DB2FB9A4587FE13A4E909A83594584CFD382F05EAF8654DF5B44E39496290A7EABC36381
+8978F6C05B5EB3838572EB0C64C1D81E9AA0906FCD84E62B68E2D3BA876D536E7794067C
+9C2370FF2E2E46004062B260CBFC29CB5FA0219C2EC6C8AB8CC4418ED8FDDE6747F8EFA1
+76A6C6D1276845AEC38B41EAB3727BBA0462E2E809D76E0B5BCAC08FED585BA6E5D8D0AA
+3A36FEE108F55C23879B62C0A425F176E3C8C9031BD8B3E1B6C3D8DC383FDE0E36B33901
+50296F6869A4FC7E095517136B547295D1DEBFA341EBAEF34A179B070EEB60AA91839D97
+AA51768827E4A1CD55C5303D1D99341537B13FACB6F490072D8139BBB060FA1A02C93D3E
+08888E313859B439AF27A3E5E7709BDA43F851D13AB5B2EF395A931A99D0A2FD8C6088FB
+33D318D8EE1F7C7EE2D2199A638E3858EEA06B3A167F69FA5AABEE4558773A75610E7E30
+F3062576A2A7FD3E9F08FDAE5F1931A7FAEF85496071AF8E16AEE74C0A756927E0720708
+7846DF0F9A7C5444D007729FB69042683DFD7DB0078199812F85FC9DFF1E45C77C104F91
+37787E3867D5AC37FD7E86D52AC67672D89F04782F980EE918C6152DFE7657C6798557CD
+ABC854E81C980DE5AAD8E0BC259247F73B92572973D482BA7E4F619F50B0DC247ADD0997
+CE4E98A71E4A041F46CE605D32AD047D2E4260033C3FBF80525396507815EEF46960A904
+1B83CF32AFF7712BE97D636B4162190F2D13CACEC58BB25E89496122D23CFA6676E790CC
+29F48483788C724531BB3EDBD557950162907B68541B51ED6DD74C06C2BFD5346CC819CC
+8CD654F17C9E798168C90DDEEE78B6AE37709D35923AAC0EF066146D93C8179832E1A7F0
+44C4637E560853D227D3A14EA62E2428567E0CEBCAA3C43B0977DA30251BCB74E445E981
+6521CF8F1955A9BF920121E4FFD1E022FF42581269DAEEE779282512DD46BDA9F7BCCFEA
+77886D52E0B6A9C64A37AE0564DD09B4868BD1C6860FBFBA2FF022C291AAF670DB7AC717
+D82F709B07DABA0158FA67C0BC0DE958FDA1A63ABD29864C005FFA7FDCF73AFFA597D16D
+51A1E16FED7C1E8DB6972353AE498A9F1B0AC3B778675312C7F01A7533E1A53F31964A3D
+372A140EAACBBF7EEF600F69D8C466905CC21CFD1D1EB70B2469788BCF405ED84412A5AD
+04AE871A79DEE0797426510EA8F790993002857BF2BD33963EC10B329A596226AAD8745E
+EEC9A84BDF4793293D941756C6A582D273467EE704A878C40A1F8E6F4130DBEE6E484582
+4B78AEA786EEDF2E119F0D563C969A64B29F13327C52D03A16CD690341B2E0CA3B622F15
+ECC91DE30A47C82390F5EC38D3A52C24D3F4ED18E8733C1635C25854F05C394686913404
+E6A11B597213B0D506EC7EF6B9A6F4755B5A71099AD0FC9FF11244D70A5B987603F59AC2
+A01F251D9CC39F24FB322ED3FE0A0014A412D7C9A94088C8C2FC99657219FC27B299FBC5
+4E08F729AA6C013BB76CD320B23DDE9D9D9B78A34E6424BA1EB1C95B5005A53F90D3A2FC
+DED3AB361A9388D2EE3FF47F4F9BFB29A1375351FDA929DE5A89346D7BDE86588EA5F95C
+CD052B256653437D4B9F98F82A4E9D860B9E6CF4616E80E743936059A3ECEE59298A2CA7
+D83610215D893D065D73A0079E6BA899593C2D46866E980DC125DDA38519F181E20B026F
+86B1CC7ED4C00C954146B530CAA58C3C52BE08BCD25DE61A6D7F8BF7C7D1E325C4D2D610
+169CCA13C7AFFA18DD3907C06A0FFCC09C7033B9B721871E31E4A25DFF7FC74899E1886D
+8F3BD163AD7C34FB6A948C0FF667D97C8E918D8E663490CC7BB6AAF3689689725C07569B
+D17661CB0990AF49011A3C324CA124C4CF555C021041B7D301FAB7D36518B34771E424AD
+B62E962D8B2C46863DB108E1316AC529A404741DCB27DF4A081965B96ECB7C4564550BE7
+78629AD19568AB733BA2A1599F585BF5132B5B5E59F51BCF1C284AC371799C898950667B
+44E71E5FC7E221C927DA70742469E3BFC1813CF5EAE32F109A87BB258438A6B744D3D642
+5B3C42DC2C542A8382C3B7BE8A5C43DE7E4A123D4130D3ABF3E95568DE13C5A5421352A3
+5A083A98EE09EB0EC99C0C33EC688D2573E9969AE74329D3D6E925C568A5BE0811C333C3
+372551F2A32BD9E0FCE86D3D2E83379BD55634101F863DE3407564E3A1A73D8572341037
+A6E3AAFA61F7ACCAD510F7C17261408E8BCF0AA72436BCF21F69EF6D3128CDFF321A54BA
+3014DBB6E3354197EA88BD4AB5EF052589E3635601EE76508DADC4E2DDD9B9710CD11963
+B8B611C5D089CF34D6DB9E94FA9696EBDFE31DA2AC089FB93B8F5CB31C301607F29494E7
+490278F0E378BFD712EA4AA99234E3205D0F4E0F0705F352B62574B884E571183CF1D44F
+C911A617AA1F23AC0BBE3E088A84D04AC51349E3E92ED227268DCB4DDA76B2DE3B473331
+91087C2A70BC8B0554C3F21D5B5A303F6FD58CD4343F0EB68087715D0086C3938DFF43E6
+92F01DB8319C4C2DB1E2D0B41117431086D4C51B010420F52C94C4B2040FA0FF2ACC4A23
+8C44EDE007896F73FD591E491C9359598F5786978E481141D70BD1FF759CE62EDE7648C2
+9E1C59FA4F7F61A2ED8ADF9E4654F1BF161D7E19FD0CA8307993F2FCDB726E4C92412D6C
+F260767375AD211B46CDF539D66B2CAD7410FEF73A289812B6DFE69F6E6F24A3E66653E6
+C1BC17BA415FDA7E4FD466433CF5AE80827D928EE9A2B4FFE178E37B01E8AF99A8A26490
+0AB2637E25B3B5F4CD857E7CDC2F589CCF52D546F217D9B48C894E11F57BCFD6B6CC54A9
+B2242A8A39FEC8578F3F7D9B726F977F78103E4C2429A3C9B96372F3622D7C6FAD2C660C
+FC73A3BB8539853BB061AB6F1EF3E6447983CCC1131276693F0BC5C2938DDE7864776E92
+8C2AF847D27FACFB07656A2DCDA533FF094927D920E227E9618A47E949E20A61D97412BF
+273AFB50BF67F54190D982231FEFD98ABB2676E59E106F5E3945BB9739A87DB7E0091FCE
+97F86052A8C9E9A49753E66CC322C3051FA489096E2FA9C2E5DF52E439EED2B9D1A8D918
+E19A9C8F97FDC6B9A8982A1AFFAAC4E50899661D2BF6EE5EA6F1FF825114A1B3316BEC52
+EC64416C7161B920D7DE9C339DE346A2BE6792F82CBCFCE4FEE70F04DAAFE5FD13778B1E
+D7F5F6BBC097FDCADD6808536570ACCCF31DEBCAAE581CE6D4C6364E58665C530026FD50
+1FC1B1414B0371D2BE2675E304B041C7E635DC98DEE3F1811EB0995FB3167480F31C8F8D
+85E3B5F1054AB5B5721B7E8C3FFAFC18F50C8EB58A5CA56DDDF3FFBACE09BDCB27852DDE
+9A1DB9A9C4A51092D145A41E07981235051BC56F9319F03FD37B28388FF4AD8007F98B67
+C7E8FA79B54EB9F249A0A383F7AB987B6EDF5508069528D49FA26659AF0203E73A13AD7B
+3F64D294AFF49E42A76D493AEE50B099E049F8750AE058C2863FA2F4EF9EB18F6D2C11B5
+906194F7B480DBE6FE3D6610BD08AEE0078BBA1411B26DDF14B16A3DAEC2B18B29EDD557
+645FF36507654C2A86B7B2D18C5F886E8F02FA3092D35D4802AE25A6CDF17C469E85F67B
+1964A75CF22A241F2580875F639ED480E7AAA04620C6C58B5C839F0B659D9D2AB6EE6E0C
+80EEA564E9CF0F9F7F0E70410426047F0EE92451C92C483AE8F456FD95E21C7549392C5E
+41018826DB42CE4709FEE1A86F6CF18A0DF73A96F8147AD819E5639F95E6CA508B9CD05F
+D0BBCD49AA42A09A168987B7D8747E4D3CAFC699DC40EABBF633E2B6339A824058BDD026
+180BB7BBE9937EC7B87E853DE8308BEBA2D7B1156E0524DB6D983B9EA396B3BCB9A6E425
+8C55325437EFEC9AA659E57B07B838576B65B10A9B4A77304383D9540200A24ABE5663F7
+29C64D293498F678469024A1F552E508B49B610D3EF334279AE58F4BE914742752E9FE31
+1642DF1310E0E54CABB5CFF9CBC0A9FD8C81AC09D7762D9A989C2ECE1B24CED02D991D83
+1E6BBE94F7D981DC75EE82BE1AB6E1021046AB988E5147D3E037E447B1B38834F9FC48A3
+23A734D2DF86BF8313892964B6FD68CB8E4DC0B1EAAE8E85B137E34C22C8F6CF2A5DE4B4
+B914D13FE7C0E3B73AE8A998CD19BA81E3825ADBB97854B7B89C7FFD8E059340566B7348
+36E6FD18BA8B1B60EFD13DB954CF005A501D70673FA63F79FDFFC78571E075E0503A472D
+A3AAADEE2A7EC2710E7E910C9B3866BEF6001C47235AF38A70553649D910DC9195389373
+A87A62E97BD65CCA58128204FAE813DEE989DC1E72D36AA9675A25ECF1B8FB2CA45DF4B0
+23887604842BD3626CC1DB5722382315912FBC9C383275F430A76AC081366D100F40E42B
+7A4D3A3CDEC8C47E8C56C696A756EF3EC9B47CB9570EABDDD906EECC8F754C92B174562F
+118BE4FF9E0E84E15BBE5323267155546449138A613D2767AD28F188442F1FD558F1D09D
+2C296FEB0FD94EDFD259F9C0E11F255FA4C39DA709FF2AC75FC4259BAD43DD8B27127F04
+049683A5A26A38E27654DDFD99247AC366003DF016EFCF2D96C6B2F9858F21BCA07EB0ED
+516C2BC8EE39B0C568FB5FD8886B21632AC942E7E02C7BB24E007A08E8F628D74EE676D6
+
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+{restore}if
diff --git a/fonts/Monospace-Bold b/fonts/Monospace-Bold
new file mode 100644
index 000000000..5474cd6d6
--- /dev/null
+++ b/fonts/Monospace-Bold
@@ -0,0 +1,2354 @@
+%!PS-AdobeFont-1.0: Monospace-Bold 1.15
+%%DocumentSuppliedResources: font Monospace-Bold
+%%Title: Monospace-Bold
+%Version: 1.15
+%%CreationDate: Thu Oct 27 10:50:21 2005
+%%Creator: mike
+%Copyright: Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.
+%Copyright: DejaVu changes are in public domain
+
+% Generated by FontForge 20051018 (http://fontforge.sf.net/)
+%%EndComments
+
+FontDirectory/Monospace-Bold known{/Monospace-Bold findfont dup/UniqueID known{dup
+/UniqueID get 4234665 eq exch/FontType get 1 eq and}{pop false}ifelse
+{save true}{false}ifelse}{false}ifelse
+11 dict begin
+/FontType 1 def
+/FontMatrix [0.000488281 0 0 0.000488281 0 0 ]readonly def
+/FontName /Monospace-Bold def
+/FontBBox {-141 -1034 1457 2154 }readonly def
+/UniqueID 4234665 def
+/PaintType 0 def
+/FontInfo 11 dict dup begin
+ /version (1.15) readonly def
+ /Notice (Copyright \050c\051 2003 by Bitstream, Inc. All Rights Reserved.\012DejaVu changes are in public domain\012) readonly def
+% Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.
+% DejaVu changes are in public domain
+ /FullName (Monospace Bold) readonly def
+ /FamilyName (Monospace) readonly def
+ /Weight (Bold) readonly def
+ /FSType 0 def
+ /ItalicAngle 0 def
+ /isFixedPitch true def
+ /UnderlinePosition -221 def
+ /UnderlineThickness 246 def
+ /ascent 1556 def
+end readonly def
+/Encoding 256 array
+ 0 1 255 { 1 index exch /.notdef put} for
+dup 32/space put
+dup 33/exclam put
+dup 34/quotedbl put
+dup 35/numbersign put
+dup 36/dollar put
+dup 37/percent put
+dup 38/ampersand put
+dup 39/quotesingle put
+dup 40/parenleft put
+dup 41/parenright put
+dup 42/asterisk put
+dup 43/plus put
+dup 44/comma put
+dup 45/hyphen put
+dup 46/period put
+dup 47/slash put
+dup 48/zero put
+dup 49/one put
+dup 50/two put
+dup 51/three put
+dup 52/four put
+dup 53/five put
+dup 54/six put
+dup 55/seven put
+dup 56/eight put
+dup 57/nine put
+dup 58/colon put
+dup 59/semicolon put
+dup 60/less put
+dup 61/equal put
+dup 62/greater put
+dup 63/question put
+dup 64/at put
+dup 65/A put
+dup 66/B put
+dup 67/C put
+dup 68/D put
+dup 69/E put
+dup 70/F put
+dup 71/G put
+dup 72/H put
+dup 73/I put
+dup 74/J put
+dup 75/K put
+dup 76/L put
+dup 77/M put
+dup 78/N put
+dup 79/O put
+dup 80/P put
+dup 81/Q put
+dup 82/R put
+dup 83/S put
+dup 84/T put
+dup 85/U put
+dup 86/V put
+dup 87/W put
+dup 88/X put
+dup 89/Y put
+dup 90/Z put
+dup 91/bracketleft put
+dup 92/backslash put
+dup 93/bracketright put
+dup 94/asciicircum put
+dup 95/underscore put
+dup 96/grave put
+dup 97/a put
+dup 98/b put
+dup 99/c put
+dup 100/d put
+dup 101/e put
+dup 102/f put
+dup 103/g put
+dup 104/h put
+dup 105/i put
+dup 106/j put
+dup 107/k put
+dup 108/l put
+dup 109/m put
+dup 110/n put
+dup 111/o put
+dup 112/p put
+dup 113/q put
+dup 114/r put
+dup 115/s put
+dup 116/t put
+dup 117/u put
+dup 118/v put
+dup 119/w put
+dup 120/x put
+dup 121/y put
+dup 122/z put
+dup 123/braceleft put
+dup 124/bar put
+dup 125/braceright put
+dup 126/asciitilde put
+dup 160/nonbreakingspace put
+dup 161/exclamdown put
+dup 162/cent put
+dup 163/sterling put
+dup 164/currency put
+dup 165/yen put
+dup 166/brokenbar put
+dup 167/section put
+dup 168/dieresis put
+dup 169/copyright put
+dup 170/ordfeminine put
+dup 171/guillemotleft put
+dup 172/logicalnot put
+dup 173/sfthyphen put
+dup 174/registered put
+dup 175/macron put
+dup 176/degree put
+dup 177/plusminus put
+dup 178/twosuperior put
+dup 179/threesuperior put
+dup 180/acute put
+dup 181/mu put
+dup 182/paragraph put
+dup 183/periodcentered put
+dup 184/cedilla put
+dup 185/onesuperior put
+dup 186/ordmasculine put
+dup 187/guillemotright put
+dup 188/onequarter put
+dup 189/onehalf put
+dup 190/threequarters put
+dup 191/questiondown put
+dup 192/Agrave put
+dup 193/Aacute put
+dup 194/Acircumflex put
+dup 195/Atilde put
+dup 196/Adieresis put
+dup 197/Aring put
+dup 198/AE put
+dup 199/Ccedilla put
+dup 200/Egrave put
+dup 201/Eacute put
+dup 202/Ecircumflex put
+dup 203/Edieresis put
+dup 204/Igrave put
+dup 205/Iacute put
+dup 206/Icircumflex put
+dup 207/Idieresis put
+dup 208/Eth put
+dup 209/Ntilde put
+dup 210/Ograve put
+dup 211/Oacute put
+dup 212/Ocircumflex put
+dup 213/Otilde put
+dup 214/Odieresis put
+dup 215/multiply put
+dup 216/Oslash put
+dup 217/Ugrave put
+dup 218/Uacute put
+dup 219/Ucircumflex put
+dup 220/Udieresis put
+dup 221/Yacute put
+dup 222/Thorn put
+dup 223/germandbls put
+dup 224/agrave put
+dup 225/aacute put
+dup 226/acircumflex put
+dup 227/atilde put
+dup 228/adieresis put
+dup 229/aring put
+dup 230/ae put
+dup 231/ccedilla put
+dup 232/egrave put
+dup 233/eacute put
+dup 234/ecircumflex put
+dup 235/edieresis put
+dup 236/igrave put
+dup 237/iacute put
+dup 238/icircumflex put
+dup 239/idieresis put
+dup 240/eth put
+dup 241/ntilde put
+dup 242/ograve put
+dup 243/oacute put
+dup 244/ocircumflex put
+dup 245/otilde put
+dup 246/odieresis put
+dup 247/divide put
+dup 248/oslash put
+dup 249/ugrave put
+dup 250/uacute put
+dup 251/ucircumflex put
+dup 252/udieresis put
+dup 253/yacute put
+dup 254/thorn put
+dup 255/ydieresis put
+readonly def
+currentdict end
+currentfile eexec
+11167FB533773667FB8D3EFE82119D83C5E325D3F9FA9CD7D01B1F3F3E52876279E4660D
+B5D444F0B7CE226ED8DF687C9F94FD3D6282F90864241946A4B8E8575E48452B9C0794B0
+E485E0EE753D96B6C08DFAE68281203752A25CAF8EADA400FDB4F9AC57F07D7C3CED86D6
+7F5FCFCD9D4635282E9D92A5D9598F79FCB9FB1A677408CF7EDE532374FF6A6A9703662D
+17B5D4F6CD9CF249432F8C76D70BD990DDA5FEBDB59A17FC8A068E1DCF23729F4CCF2C91
+59376F20EBE27AC7473D31BBE76EA67D9AC99ED58644032A828859BD9DDE391FC993707F
+97CABF55422D4C37042F25E17BB78E63EABE7783BE0C56F59E74EFBE7783B90310E817D7
+A01D0AC31EA0C9B67EA7A3EAC553F3DCD76270BAFB428DC7AB7EE802E06EC54B705A5A6F
+125250A008FA7375643EDFF171457F65345A08795AE0F1E5FAC5A9CCD3E258A9CF83382F
+B3385DA7FEEB19F6D001A7B5A214115B01B441014E51A9BF8057017663645BCE7E2C6228
+940658CCE20121AE23DB19754C876CF1E7ABB40B2C949C0D45AEDCEF0165C46A0E720BD4
+6260D7AB7E8B5A77F64542DB42BB3C48EF0F9D026C8563478B4B80B60DE0005A3C61B5BE
+DEF534F95EC79CDBCE5AE2CABEAE6289BE6D998B2E0B090DC31F890A264618C9E9473962
+3BCC88789A953C3C9BD07F5B1D7A1621B71A12FE379E85E6562D62C449F1EF7B467D126A
+41D13410BF85D7735CB440A7363A7C9755F3BAA6554FDBF71FFBC2B9EC7EF2BCF0228D5A
+98361A9F79AC87EB346D5AC82847C2FF02AAEAAB6C8272350A534C5BCBD678B28C6F7B97
+44BF3243F970909CBBE5E4116F2A1F56EF992D3EE51889C80FA54C5C9982BFD90C1ED83B
+3D7A917C2588207D5A15D4316C408332591A8845B322124D17D41E10FABF2662439FC0FA
+92B839F0A6AE2065D029FE012F75D7B4B0947202894211CD4786A74385DC0817DDC3A2FF
+8EFD3EE4CE9F31AA40282C2A0E88D02ED77F991C910D3CC20F1A6C513E105A65117D6FF8
+B448255F66674BD2CD7B66EEA96CEE551D97B27E7B0BB692664DB358985F0DCB1E5FA9D7
+F92799971280852C5DB56F5E0788208521AB6B2589034B48624D393F005525342C7441E2
+67D1BD07BBF43C69DC7BEC5A47993AFF6F6A9747787AB8FF45BCDBE88FCF290DD28FB3D4
+2FB726AECC1832A03E970FEC71D7CA532B45C8C5BF64CEA9F6F9483D369EC9FC0D82E3C7
+A5863D816D35503EBDC1CE27C57258E0D773318E88B9006AA04541D8F14B4F23F7B3D23F
+6B4E990457C5525DCA3B63EE75C3A53611FA30AEB04A33EAC156049E60651AE830726330
+C3530A1BE5F3CA8AB63BAD85DA0080A22FA54A6DE4AD3EE96BB9EC60D3EC4AEA7B5FC82F
+8EC803B2C6198E5ABF9B67A82B24D8F5C672E6A825FE0481B1744DBC008B0B1110761F23
+ACF02284979F836FAC0BAA9216C35A5AB25B95197F282592E27C9FBD8D5EFB330B08A956
+B6079D05D4500F00518B164CECA074491CEFF09A99055371AD3D0A9F1DD2EF38B33A0FBF
+6C83E4AB7584D24400671CD568DE38F6DAB1660578C65AFC0FB5AE268AB26D47F38CB9C7
+E48BD5A7D4F62199EF7180D923958A41F3FDCDB0A856375B3BBAF2C4C32752FB0B641240
+E50FD465CB53BEF09BB0D73D204B2064B3B6322A1D227E8D7B4FAB71BBD3E2FFC59712B1
+EEC12CFEAEAA8135895D705C6BD8DC5726A21888E25B675475D53431DE441B7177F41A30
+A216DC48B78D025AF5CFC53ECCF08C494EDDB4D460CADF0E325C81B932F4BE839E5B6F3A
+3AF49B330AB3DD8637D9D0BD305C15D20FB84B14725D4269A78D316B2C2401698B125DEC
+EFC2D7DC0206C6535846C435E5DDCD2294C5ECA8FE4C3342D032CDEC2398A43971E15CDC
+CC308BA14659D338D478ED2C91DFEE282D221AF7150507F3F35054CBA77F7B68B102C7A3
+B0A94AAC5EB7ACC45F29A2B23A8BA397727E1533E78F84870A647D8D2F364F0A9D9CFB1A
+F82AA4A2FA9D4A33E2F508BE63488D4505E4BF2B22029A24EBF8ED5BA75646FBA0B80D8E
+B076A4028B10A89BA8735E03092071307C212B76BBAB410DD4783C8653F472A853105F4A
+0900CD58BDAD0DE8967A8084D49E03CAE74D6724924E2D85411B0E712ED4410F59793490
+429E6271123A4A3B45BE180248BE5F2BF16BFECE9B005C9AF12523C38E6DEBAA9F1BF6D4
+AC2B193FEF981CD5E4ED3573521A82DDBDDBD61F43EFE8CF474FFE43D82DA07FD8A1A494
+6E8C187FC6C85663A05E65BE968841C923CC2AEDC5193F624FE2FA5B4F33232BC9361141
+60C54189960EDF10F1B44C91417CA26FB66E4A89B19AC2280C59CB7C3428A0251E34B5AB
+90368B31EDDFAA2BA749EFBDB7C99EFB9C5E67E9C6C62438E73DEA816919881E804E3D8A
+EF1D5108C4895E2E285618AD7DC3A42F1E28378335D46ECAD9B3058B165257BDDCEFD817
+350ED1B3E3ADF86C3BA4E9624C2E592A8216F4B2700BC88992913406E7DB2B5F5DF3174E
+A6D7639B616AE160282DCFDC85CAE0C73F3E695B09EE0FF5752321EA51A914A7C89FD9FA
+0E66B2F01EC9033EE9DBD246725CB36EEBD34EB3481FC21C4AD3AD26B394E858E3F4C3B9
+4CCF83497813A5CAA32C5FE41787FD97734992458BDDEA1A9CE2D7135A65B592B73FE851
+C2671A257B5518E2C008553432C6FA79BCA95000F31BF7F0AD101A30607D1D34987D89B0
+F3E1A190231908C2451B8FB0D18EC8F873AB09F1419D48B041A02BC4F819FA17E81C3289
+77EF1BCA4E86CDE766B795EC8A1B299F57DBB4C72660533C8A96AE701F9EFBF198FE4D5D
+C66C3EAAB293D0D9D908236037C83A759F2156AAEA78B6AE37DF0AA85A5F89215171FC75
+3A323D43A3295A2462D8902458F15F6345815BECCD373E3EF4F0993F7D52AAD4E2030CB7
+2862D8FA6E6138B71ACC7D62E7261FBD56148C8DE661AE9844FE920ACC2503E278DF0B04
+F669145B9C8D435BD90C3DBA004C09B39227A5409965E6ED90E5082B923D69B0842FDB38
+0D742890F9A9FE4BB8F923FFED2581277AD8FB61E2F17BB90D1A7E4195D7EB3FF833FE3B
+72E696C3DAE0A3A49918540BF1C6046FFF094E01680EA558415209926FBD70B3CB4B044F
+DC5FC844150C311F9C1C031F4D5B99DEE4F72F2307B8EFF74735B1ED593465D0D7998E61
+DA4D497AF119FC332156B8D882B4005FC8850E4DA96B7AE93E1552AEDE068D0E2B266C45
+0753CD2DA48A059CEE49F1E86E2F77F701FB177FA32D5F93FE4D6A01275EEB54692AA6C8
+95EE530E862079535A543DE4067CD630A7D8CC83AB9E04377B8D3A05F23280A6E1D68356
+C76D531990EB15EA707C0E5BB5055F428997E2A731A4F7B5288E54B2C4B949833EC117F3
+0A0575603796041BE985C63F48CD55E76638E7E54BBCCC9D2C73ABE423C6A7159CCBF80C
+8FD931FACC6D8257D9202645B3138E367E160CA3CF22E1C5ACE59AFC77BFDFC25A5D6DDF
+E6C2F6B68D062D0490D05B05B55A7A0C6E56A52A2EADC106E3BB6410205CED012BB49DC3
+6EC89674C22C7D17E3A6AD10A2812095454DA4D44414F42A8678BEB35D372D3851EBC535
+888D9E937906CC0475986D2656E16D78B391E8E8D3E9C91D980D526C6470E79B728ACB9C
+B9F63C6000B9E60AD76959F7B14F06B631778911EA9DB59D8B9BE7DECC68DEEF068032B9
+272227B91840B30B7506A3FD57306015EF686A174F48B734D9070498D2184773E7353A24
+51D3276238B8874FDEB7161D1A8506BEF79EC5245651C29B9251EE17F834D200E2219A3A
+9CD838C9BB31182C00A52E06DA6EA4E446FCFB62C92284116E14C3D38973F1704D5EB2E7
+6E6F88F7444364046AB43C4D7D44A23FA47B5EA158949A3E1F15DE70F40812444C6F0F4D
+A9940F2B3CD1B7B1450C1BFE7A6E111503CFA45FF012A6DED44CBA623FCEAF5262BBF810
+90A4FC1EE72D5EF3852987026F50770F7410E486F1D15D25888C8D88188647F8776CFBB0
+C7D4F02644BD13C84C592DCE82A56F08920B2FB13BAFB405154895458F55DEECAB846104
+7B157C02450E0E529A10559BD8CD9592FFBC923092C1EB0AAE96E5CE64A6D5B636988F69
+EF02E3F5B84451BA2F6CC360B647908FA940E844C3DAE8FAF73E9ED416D6B8A20660EAF0
+2C662828F3E137B0956B15AA9C129A312E753202D429FC734325F1F82A3D9058ADB87688
+4B979CAEFF660A8EF9191F4E0D2CCAE5E5458139A0AD0637319FF41CD7DE9877AB094F4A
+3F27EC8F5C7D42B1D892B829E1DBBFA9295B8383B23658ED25DA227B9F625B89E26C854C
+0130CEB1F82D24E53D5FCCE082433A4029B1B4A5905D25BA809EEA54895220DCAED1B2AE
+879E7BEE3CFA3C71FFBC77AEF4A415C96F2CE40EF47E2080FB59AB00DB4E8D527D9E41D3
+8DE95CBE66EAC589F5831C4BF0BBE1455F4960FE388B84074DA43DF499BE3810C38A4BA1
+D23F3A6C331F09135931FF0A7D77160E3FC9CBF4937D5814A12848C17ED3F62FEE21B11E
+43889F3947F67F66BE8DE7EFA954E2CF8BFFAA33DEE3F3C397FC572DDFD7E42578DC39AB
+7CACDE5A30E25CB6D949E2C89B02E48F70CA2D0FBA47F19B72CCF99B4C71C69B1E1A381E
+F620B2BF283FD34CE116F5C2DD1BB9DAF60BD431A6CD475ADA9F7490E17D5DB183763467
+0C167B8E958A4C476820EB53A778B9131FC7205BCA2EE3791B8FB54AB6996B82B65B8E60
+71529E0E3A721E6306EE6448EC9607C427F543EB8C6717D0BF598F619D36A3FD7C0E3DBB
+E7B5D923DC8EF2BD288C55EF93640E4249E0E9E36E1FCC19CEC8619495B71D84236313E8
+C552ED0F230DBEE3C395269DE393EB34F630A5043B054154A47EE48BCFA1B3DF9D142315
+F1826809F0BADC495B2C7DC93D34155D843427BCF872288B49D2A0AB22AF861112C324F3
+4428FD31584D3B5E88ADD1EDD809DA66F90C756386198CA263562A95BAAA64B1CA36897C
+1069CDE2D44EE87FC186A24C10C23B8F3DE59B41D1AD8E01EDF4C32EE70F053DAB84D24D
+33A6024D7A86570D96B34892F8E299414E7084D99B3C3A89531A7861A39EAEAD9506B0C7
+017E3A730C91AF6857DECFCE2FFF482DB160369A16BD17456EB74258D2D39F7177998A85
+6694D74A57318BBE392EBBCD069FCC8EFB71AC1516E350FE4F936BECB2A8DC4280BF3A64
+27F1B741C4FD53AFB32EB78D9C06D74B5F71DD967E087F733D50655900E086D358B46C2E
+8EA8CB494C0EBBCA4B0A9C74B48E0236F9CA651D73D2DB6FB1F1F6F7561194C8858F3FF4
+B3F46FED001DC472F71BD6E16EC1516605779FBC1FF81D6ED6996F955C001DB98BC8E7EF
+16065AE3A00E7C65B4F080F78C5E0CBC9EF8D4E6A8A3E76258B31BD4F6766A4B00A37AA3
+E5BEC4C495D5B92E701B7423FF09FE895CA54F82D584942A93ADA1C7AC5576345DB685AC
+6E04586E55C997FD31D13FAD4D2FEC0181A8A0BAD0CE863F9052735AE3F245F549B8F2C1
+A5486F65BC217A57D404832AE633EEEDE8806889AEACC54237FC2C493CABE98111D34EDA
+6739E5CA8FA33EBD70757FDC1243E9F1D58D69796A7BE700CB9A39F69ED0D811D4D286D0
+80BCA0D9E78E54B63E640C53BD479106062953EDCD604D10F3FF50620AB8D1B79F1F873E
+E47512F37296FA930C5FCECC28FC6025270DF4B2CBC428ABB88BA940AD55CCA0EBFDDF91
+3AE3271FBFA6DEE0B62D6B94F40053A11410D91A1CA9DB0E9947AB24EC592A9FF3F00FCE
+F1C436A94332952DFD7825CFE35489E12C6A8A7521AA5B32B307A7BE5200E45E1FDC5588
+96F0A32E97E31CF40BBA08833E7D7EF78DDD5D48685B19943705D87E40C235C0EDCDC6E5
+93AEEB193C8957E5A05E17F4609FB3626BD14CB597362AA65699A50DF076A54FB1012403
+E32A3CD7761DFF0B3F41AAC0BD55C1148A24BBF31B4CA15608F12DA8F671D76E33E00AAE
+450412798B7BF74C216E112883E9920B0EDD24701790AEB565D9BF4927BD3856493D6B56
+2C5A231DEFF338A986DEE08AE42A6FB978608C3B9A4A1D8E17164A08E2FDB5D1E1D38AA5
+5E2E4B4D2F5C0317ECE305DCBB207D7599943B1116A0AF9B917E1EE7FEDD285F249B212E
+AA66724290030E1220C5E26EE5623636FB5897E0CE1E0DA00B8E716A963B4A9498E113A2
+C6E68B6D35503EFB27C4D82FE3B48A7005560DF04BC6AAA01EAA47070C81D60C40614920
+12654837A5317AF1D7F24404E050CDB6C3D1B1BA2480FC9940707A9984D507A3C078365D
+30662300B4E28756F69F8B65F9212B4A0FE63448CAAB6331DA9E7DA65347370F03E51135
+591456D774040BDA4BF0D318161C082F69ED644E51EFE26EFC45CFA0391220B09BE1157C
+3E4B55CF5203F2AFA61D7C0F6F281460A761987144ACA50A2834954890D9BC811B72D0D5
+FBE77F8D01496257522EC90143BDCBBC30EB08B9D15097E0AA0AC15F6F7FEEE91224BC4F
+531A65905AE9337D97652775BD7C43740E29EB66AEDF91D658C2A2F9849A26457C8866F6
+F96D59E6721018ED0637D6126F08EF685174F130D9735CA45227B508B52FB7D9BCCA10D3
+BF16A889EEA13847DA7CAB63C73C0F068C3BBEA8E162295F884B7E28BA144E30450A823B
+9025847C739B6EEAD71967F8DBCA0AC8FBBC2A7847BD7B957B8E44EC96CA2888B47F86DA
+786EFEB0C741D7CB67CC25371E59148D4C3ED2C5349A1EBE6B9DC8744EBBA600856B22F5
+1832C41955FF582F4E0337809EEFC33FCDBF9C31723278A8D085F1404D16A573314F2876
+85C67FC651E691B1C12121B0E209E3E7A0FAC4272D58F16863202CC7594D0A6B10A4948B
+1FEE719857ECEA0CFF0D0643154CE968A7E909A6CF9A9672B2159717E854044AA6A13F05
+A3581A47D624126498DF26635EA643734E2DD2A2EFF5D2F70BCDE6F39C9D54F0A1DC05D7
+8BE1C28495B0064C2A18A02859FD8B1F91DB7D29BBBE7401B1891CAEB5BE54468DBE8B76
+74C2257466643C14A9657C1E79627D8743C14B4CD25C03AE56AB0D1D5EF596474C7881FC
+0706543A538D2017E48205664D7443834DE0344BB76CCBFB64824E753FEE37F39581FD32
+27AF8959D869EA87D806668DC29436C60A8C9DCE55349B7C992F821C28A28482843577A1
+44C905FED079A06273C7960BADCB5196F3C9E2DCC87C0B1E03C5B5CC64AFD58CC72DA649
+040DEBDA7ACDA5BE6DEB142FADDFD883DC4F004B7B7FC5A1A8A44AA9C4A6B3CC034D4F92
+CB6293FE7A3EAAADE9568655CC3CF1EF283B1ECD15EDA0A2E3CADE0C3148A5E449CD5D92
+557FC15E2A3B99F6CAB2DE4E3DDD038184E46F1914481C7E5B5A1862C899AAFC1A4965F0
+5C152968522019B3D635C2A67DA80CA60F264E6F75F419ACE6F48F32C5B6FEA7E340DB0C
+5C25F7FA380B1A7D7F4534F0ADB02EA93B4901B581A9EE79D3710248F0A5E03BABC2A066
+5583642E51E78893B375950891A694ED7C18B2CE872619ABE151DC8710F5395E79E5FB02
+5F05A3BD9364756A54FB8B31C81C2285942F9FA6940BF3D676C16FBCCF34A433028A9A0B
+18A39831E0F04F03D7A4465DAB80894AD108CCFD1F004013B9D619E0EB552DAA5BFE0EA5
+53FCC2D38EA0FAA38BC25AA6E954A2ABE35AEC8383E556D1067F2A8F4FEAF745DF55771A
+95502B33A40807C7692BDA00A142A4EB394838F57880B4ADE4D21DA150CB60752D5A11E0
+A309F50D63AF0C59DB2D58EA0C827441997566E8AC0F39C354CE94175BBC62A265FCA7A1
+87B3BE75E83EC96FFFA43F6675D9374771E2AAB0FB1A14E9843F864852CDB0E23D30F1E2
+EF19FBBB4501D41F4878208E041A8B5C0A46B3352A2CD1F5BE78B3C89B58DE076CC603BF
+04163F64660236214F9B029CBE96F0F4DE40C8919EE1FB5435FBDB25083FB3EBD505B0AB
+CCDAE8CF4AEC0DA7D890621D68D0056FBCA5832892EBE9E2BB72A2BCBD224F1D3E8E7AB4
+771CAD9C6A4A0E40A6BFE15313E15EDED08DB8941E04094149B69FAAD438E8C7047C8A41
+ED0B10070C48F804C11FE88BCF655BA3636A4C7426584812DF512535225E8499D867F83C
+86BD170854BE047A028889695FEE4E7FC63DBD109AE00664414FC96496F85DC4BB719BE6
+B7C5BC4D7289028A003CBDF447018981D0A8E11656A4D75D6F5145C5DE04CFD6234551DD
+F89930E9267D1080FAE4F9C66B1BC736C7375B902FA53D9E8BCF2B5A7BC4B6341CD65F79
+9673CF52F26D649882A3A2EB1609DBF2D4A4F02DA65BB417EEEE635485BAD51E96EFD4A6
+BDF0861B1922D31BAE22AEBB9DF54E2C5ABA5B97ECCB069903B2AA28D790560A64E3B93C
+E0D3FDC457944A22A390C874D655AEA7BEA5B305B1BCA2F13DC73F1E8DC7662E20FC276F
+1D29E9D96E8EEF0E3B2B0FAEEF541CCAEBAF485019979872A72A8ABCF89071E28DF389D6
+8418B9EE2488F611AC58EBBC150F3E93AE1B3A1C5426EFC55B22E5A7D1DABF78E4C6D196
+757CA1120B657ACDD4EBD7276EBD4A67A7440B46FA59C59E2E6681FC2BBA58FC8A82804C
+F8C4AC4032B09681B6CCA415C532B91CDF0B0400AA088C9044C3895F3BF46C611BA136EB
+AF72086A9D2BC385201BBD78DF875CD8F7D67C0D4F26D3D9C6345C55FDCE9B26BAEA3963
+A7DB21622C3B3B3DD82DFC66FE74937EE3728FB20328B047463856F9BD4E1B1F0D088A3F
+19408DF937A84D543A5BB17445979A37399586A368E99FC2542D8F401D0BF360CA619854
+EDD0BE31318865A20F221772253518E9E09BE9DF95901147411D4C0879D26D8F930E4B30
+3FFEBD5FBB076BD9BC5B0A4C99F0B85800F25994108428F98697DA6E7C14F1780BDECC94
+16B682AF9E92A7AA7DD0B33EB695DFF884D14BFED98D3D9F84E36ED4FB2DD86F1A42D8B4
+A2EAF46CA449E0ADD9BA067F2DE96897318BDB05A560BED7588999185585F81C9BAA0AA0
+9449C1BE1F14AA0C729E6B66622D18B8D5340B74BCD66B967E6F29365A5745012C881F6E
+CB10CB82B46B7AC551B5ED79C41709AB70B4AB493C4BC6DA1CAE87011B5961A5FF4B0ACB
+17A95F29D49FDE6830C3B2D170968738A8815149B242B4884161186079DD6A1217FE9CE7
+E60E7045A21B10138832AE5C880FD54FEC7B71974DC8704DEB006E01EF9F61F7FC22A117
+123D5A2EA6AC39CDFC6BBB6380404B8F98CCD1E4FF7CBBCACC4AA13F260C081D9AF5108E
+518516A2C58B27CDF940B960FDD3D51AF3FA1BEAA90687FE8BD145E9984AD71187BE737B
+6765F385FC7A58FA771C84759CA27F908038C2B7BDF81DDB6797A3EB4EB6E8ADD3FB9FF4
+E92692577747890EC0CF77796BCC291929FB27FA69F10AC7912D9A7E6FB84DE14D9D6D12
+115A8630F8CD3F26A86F291714B931D3822B8A07E9276659D5F36EFE72858A444557FE0A
+3BDC70E9D52F941E790EE7B7454557B792002BB07AC33F10F2CD2E5E16E88018F6F79D54
+34E408572D30A3316C3F1BD36E1BA16A49C3623317C62ACCCFD869EA76921D729E70F2F4
+63FA8F0035EEDE8EAB1E7BEE4C389DF3BF6625DF10CBF19701381B68525BFE96C2CD919C
+2922EE99525048392C1BCF26B3141B551E9DFE25A2D0E84348BC032C28ED8A118DB6A083
+B1AC44A0EC9184D101FCC6A9CC4F5F9756783376BCB2DC289982795796454835FDF5F325
+DB4DFE924D2C02458FEDED43FE8DAE2EC4BB61536CF755E7E920835455CCE84B5C0C791B
+9CB6D494445F304B173628D8057F45E9860DC8DE045E351750C0E71B2B13F78AE4941AA2
+F3E2E8E05125DFE290AF817D87693AAB16345CF0CF6CBFF594371E9815A5F3360CD52D8F
+095AE10808F33F86E07E4B8A2BB3486F93D04C88FCACC7907E359442D0CAFCC088657360
+6C54F56DDC5039A88396731AFC577DC3324A0D24AA9348245F660A496410E3286B81D6F8
+7999933D898C0FF0D3FCBA5F9D5CF3326B863E941236E31FEF86B7DEF1014D1C6CF86B92
+4FEBF9FDEBD3709805485B618DAD03D15B5C401B94B2F4500F2FBE72CFEC2A69164D6185
+DF5160441DF72FC509EB7C1C1322AA5658B09E1BCE9BC99763E7DE13057E836E57D24460
+DEFEA1CE7C2553BBE5F5CDCA7869B7153A0C5349A7D0B546F971FC63864BA7F00BFE51E3
+905A87F67398D568709D27E5A746970F72EF9C71ABE7CE96044ECF80352F712B605A6B10
+8426A06A27E13FD837C520096D15F9B1A44E6F955E3FACD91B643BF0EE74D3FD6E9A10CD
+F05C01FBC7BEA26D8AE8565CB89BB2E52EC98A4F4898D146084CDF4E6509462D267CE81D
+D7A0E6E2EFEAFA1BBF696803FD40F021716C2838C19D32F741FA334D228E2BD34DA2D561
+E6609CD823CE02EBB683A6F1EECD93C9103E5328143EFF6C9E05956969D2F25AC992FC76
+39B5C238FA4A3157B959B4AF11B6AA05823C015134836A6560EA7F07EC86117511E13B10
+75D0D2259D36E7B8065D930184C7DDB1AC2B42A566FEEA6927313BE91C7EAADA352D9E76
+43D467F94AD5ECAE37BC145278B4048AFDF432B2E2F219661CEE53E159490F1E0FB04DF6
+D42F4B322AC01E5732859AEC445D6E120091996DCE46602EFA8C01EB0E1D8BB6D0D12174
+E4990498577B86CCEF0EF5F7EE913A3A8D78EF9CE4F37B0BE1B5F40A4D0B00EADBD92C7A
+5083E8D4B093D7BDA5B88E08D5DA4EBF7FBDEA06DFB8C5161A92548160163EB7AA97B603
+96D869524163EE546E1E35F764A4879D2DF056A5E77438D45D81F9356A4F8EA0D007E0B5
+DD2441879A48AEEDCB1A2F493C3E648EA138D4DC080022EC7A62E08373CF032F48C2F585
+0589F04122726500E8B29216CCCF6ABC2A04A726224F9B029A25DE8C5965A6ED3F6E3518
+B72C6A0A64802424E91DDBA855C20EC358F6FBD79C30CC6DA41C9C117B23139C150DDB33
+7FC090A907DCB0FA4DCF914E3CB53EDCF7DFB6D2A200F7C2E8401667D828605C64D9A62C
+7360AECC44BC3951D2ABD75976528B0B98913A2741D0E160B48FC0458FF56DDAF4FCF5B0
+6A351BE0A90F851C44BEC636C0AC688226C8B0FD136F2B612BB66ACBA8FF149783F24B99
+A0FFBD405F655FE2DC577E01953716C44965782D86658859FA313876424484951448ED6C
+E43106D4F8FAD95C3163A1AD47AB14DAEE015A257735B0B14BA8C1F807B54E54670BFB7E
+9311D936086C6DDADE803F4E304B6E823A937E1A92C28C5A61D0FA1DA992DEF383ADC936
+E910075C9573B15ED356345ADF2EABFBBF8CB6D1D35DB404CB70DF440642562D8778E5E3
+1C547AA1DD408A97F44048AFF9317364BB3A8D35503CA5F0FA509CD0A20DE629DD243EDC
+163402620ABBCC4E9D7E679A92E7FBC45CCD3923AEC1C20C8F15647B0E661F82C738FC61
+FB3C954B9097633B78D21C958491977377BA0FB845FA5357F3519572002CA6A88FCC39BD
+CB51A2F2BA462905906DC5A76632708E41585A47368D650954826C722853A1B9364D3F21
+0A844A8AB86EF33C8176B76E891F2AEE7C1DD8C6B0A2B52CE2AB398533B6D862593D30BC
+2BC3046C588E63E2C02F17A5336D7B03B8CDEE76F5B8A8AB32F431F9FD1FD85013779781
+274597F8B717CFA22066ED723769550D604ACA4772C711C672FA57A9A30E962E9ABBA798
+AC43517D02EC267E25CA09B5FF087C0498660A975A7BC1F726B9B0362E786A5E6DA97B9C
+83C8B7BE172423C79CD95A2DAD481CAEF11924E4357833DF7692C22ECE4A7C92B6C84B8D
+4E1332A9AC1C897DF2777C9A3C8AA4B77574A5BC296BD2BB4DB715609DEB685CE804B710
+D098CF51391D799C2F59017002C2F2018970BC614F4A4A246A49E795FC2627A5361A474C
+4EEA15FD114C5E067D2F091A25E56A019A2DC6E00F9A3CEAE73F68C7387A2BA310AF9980
+8709635A5A2AFA101FBC0FF8AF9D7F7CC1E44FD2344BE0ED353D24E8624D464938BC13D4
+078B481D9B32937D75B52CFEDAC13FEA859123B76C50856986F05DAFA7AB1885ED53E88F
+57CB20D166DA5B3723AF472A0C3BA1325015BE2097BA520E15E0CCE3FC8D3AEC37F3DED1
+671FDE5EF193849D5141B9956A68DC514D6A9FCD67AF25D8751AA32D114A58728CDF973B
+05464EA3CA55ACBDBC0C2CE814CF10E8639273C33DAA263C217A8C6F1A8EB1BACCB6C7FF
+E50DFE35E2919D0CDD7C099FE7313B8D610C90034EEF74908906ACE8631A193C5C6341DE
+6A311DAC36AC2E9FA441E985249302F9273EFEA3FD5AC02111A0B697CBE2FF96B245D2B7
+0847404C184BFE1E3C883E66D90EA64C797597CDE06554DE22537638509E69D9E18030F9
+E2ACC66700F2429D8C5787837421EEB83B023FF531F48B40EBD3E58A13A0FDFB227C2A28
+C9A81C16A7554BD0831F68AEEC7A1E834BE1F90CC96D7E6C5B06A5EE89B231C183E2BAC8
+4840BE8EE0CD47E46517F6C46F27B3691E5D271781E612602AA935061867860C660E6BBE
+E57583687BE3C61186D98BCF7EBC3A3AFB9B88C7C466DFA58BA37840A537F1206C522FA5
+DCD1C129B51AA8EBEA4F5883B7D1EAD667B178B56FE7D831DAF15C631F52197F7E92B34E
+DD68CFC92859C49922404F21F4BBBE4643501E39AF897D93EC8B89FCAB6BB8912F42E805
+532691D4BBA96077BB351BB9070DC2D5C17D60374AA9C8CC6B6ACF929B77E252F71A6F61
+74FE8058A8DF23CFF45A046CF30031D87FBE2D408BDB0C9939FBF6F16CCA38D97AB8B19D
+7278EF78814FA670EC235651A4703B229B50BA6B3EAEC8A22F41AF0CD01984238C34C2A7
+9E18A8E493F64F74EA3638FC4EF88B7D788648B4A2ABF02432988F9A3C871FCE7C59B339
+4E00539AB825DFDA2C420E378D1A20CD0FB6F060349ACBE266DB820841088A9FF50C2686
+F90561D8248881869D04A809E738761CD091B084610BA958A39CA3F19CBE38437DF0FE69
+D23264E56B4760044F11EC435631D06C6C7934427BAF1015C9BA4E370CFD16F1E892AC3D
+7932504A52DC9D9576CDCE2C37AB393A55180156F6F583B753E117E42F6BA85A64155118
+2FE36FC5D5C4C80F88F8825E88CA9F5CEBA97FD8ACBFA3C87FC906F443361B71F6B2D875
+DEBFADDC1CF3EA8A7D099C30A4207CDCB3901C13FA35DA02FB95DD0E6EB587D46D739A27
+B2A325237F8D33B1413618E8FAF1C9C146581EA841E8B85174D1787BEBEE6E409FD6B64B
+3B066F62CA10009B10FF02A9D708203C02EC1F3309653B617F053754EE9863EB202D7ED6
+F5E47D80B48D99040CD17B44646694D8BB68F39FD6EE4ED77606D35B4B668A16608AF657
+FEB98F826C291B26325B6EB8587CC3EDFF18FDC96C56241ED36A6115BAB6579D5CFEE016
+75D3E4F23ECEDE16AB09586B9F5A56511EAFE9BD38D5B36B0CA45F1992475C129798465D
+0B7E94BE9B308E87794522507AC3AF7B29C91AE0C6ABEAB8989289F238509063C3E74CB9
+393F2934A5FA0EB173E2982F412875AB7F1ACBEBCFCEF7647203869322300D4C110D30EC
+C61E846AD1FE42361F357830D5D6DE7DBCDA6154F8C5B6591EA2580F34C2C5422150BCC6
+E8076F510E571BF3633255677A1971CB0624BB1A6DE11FBE9CD1260FE400240C4C5CC59B
+A1EC6CEE2E054995D33FB5ADC781D78A371A9116CD8F9DC09CFF2F3542BC1DC1B4E61D3A
+7310C9674DC24DEC68073F4A979FFF96DAC759988735089B043BFCFDA203DA4F99D8E719
+1FDFDD18F3B53895F7AD46093B8A9D55CFD2E527A50F46DF23E0288FB8F61E2254DE6933
+DB7E78462CF03E7E454F6774415D3DF25926B9C7E48AE576B05FE164CDBFD3AF56FF9A94
+D0C08EB26C4514140BA55B503A52D98CEC90C721AC3D2E280288D0F73C2A5ACE87AD9798
+E15AED95526210EC6428D10C1422482799D1BF69DD623B1B16DE95592FCB6366B5E91C1A
+3E03F6D086258AE19576E5E66F9E6A8C029E26FB7471ACE648E9A9FC74251ABF854772EE
+B42D96D9C87EEB12785547AB30CFB71FE683C621CBE389225C1F0DD6CC7C24FB9E5AA117
+A4A9C83A78776C0198745A21B6E154A9D560BBA0D419092CF341F1606686D396C9F417CA
+DBFAB2D360D2035196C85A204AC2F0F3B3EB17BD337E6E9D57BB414613A636E22E944FB2
+556D9046E9CCCFE0B82BF68E0148B17CABC0A926DF4885D2572D53435CF8CA462BBD9A53
+AE3673D6C6A7BB9E857B9E01CD95F2336EC1DB562088E8C2B4C6DA9F8E7F6506A6E69D06
+82785BEAFEE2B57C1BE191673F51C6E2DB711667E34518363119A27D7D3618AC791B920A
+E66FDFEE50BFF094E587DF23A4C100EEA75AB4E1B3384F99966543D48A3FCAACFC76E5C2
+00DE81A2DF1C7D7E4FE1D8FF59FE187C6271A80B42C9CC854096BD3FCE15048E7AB421A0
+89C15E9574D535142E877C1D72BC5A1173D157A1B61768CD39FB88D574A1BC3C67BBFDE7
+02EE677084111B8ED795273745892D9260CED632285E633DE80F3DE62FBF73350D71D72B
+84F5A18D3BD43386D05642FDF1FAB29CA63B82E1969679FAA6283160946E0E3C7B3519A3
+5D791580141D2F980023C39C122C2D102E4243502B517678C7A4E522753F91F4EAF73C75
+C644080E3509EDB077EE84E1DAFC06B25101FDF01F1FDEF68C326A6F67253E18A0336EFB
+2375FA4F70A077A2D09471AFD31FF4DB23B1FFEFE8A0CE644E864BE68E05EE75192D65DE
+9D14F9A385AA2B9C4E5BE385FF1E2C8C9ED1C9CF4D48AAE769AE7FD807280FE96EA290B7
+8DC5A9F78F89CE562183C8D8DF90E6AF14B20C0431617FBF64BA977EB5DC3BD63BF0B81C
+AD3D586409EBB6211CCFC8CF02A74A30CB9B3D2BFA8F954E3F9590A664B16E4E3EE7092C
+DE1D42C778AD283AA66B630DCD68C968B393C23CE8D76AA2A9B911AD24D3C73C02B2763A
+088ED7A1CF3B4BD07C9A0DFF7B642708B13B8E9C32923FBF1531AFA279E162804C301BC2
+F69F4E24A05BC2D93BB622B5528D2263FEF2C8A4CC1D6F01C282FEF8A188484450FB1359
+DAE4530DDA82A2B5359165BEDF8FF28880034D8EAC5E7C03A8FDD59EEB8E2564B3889509
+27EDFD59C2CA931F4058C6406DB402B71CDD3EC21F2533903830DC407F814B86ED983E29
+991A94AF27C008B2B448972C6CB7FBC5C30D577774624318C371737D090F67F6C36FC195
+F7E2DB836CEE170DE9ABDB2D99FA06E340CB144F8E65A29F13DDB34D2D462B38C7CB6695
+09D77000F9044C659B941CDDE2CDD35D12D6FE94B502CE6C67824A695D42828E2D111AE0
+752383F579A86B38BFD3F173D34FD9937F11027F44748A8903342287B85AFB49BFE24240
+0049F4683217BD8974D21EF4E373EBE69221DE4FC036AD9CDE8D1986D16260F361255CDD
+6357354CCC036EF8248802C5A9DD6BE470FD647A913409EB0AF9B629050604C166A70835
+3B78E1A2A179B3161553FDD55B036867914EFB8A9436F668860770DC512D8779E53883D4
+DCF5913BE9C0AA9D002788725BDDF0B5FDD0B3E49A4DB4F79E9D28FB4872CDE8999A0E62
+A6A7934A80F1DE7B84672A65513F4B1B845437DBA6DD1DF9ABF70DD356DE74C924213528
+F24124F153637EB9ECFE91AA71DB9A92C19B376F7E409F81BE121349E2D5173B821F018C
+A19039FBD57F6F7012D5E4684D149E92FD9E1EA48F3037B162560E3F29C6AA8100C0A633
+D685733DBB08D30DE48A53E28A3D4776B715355EA7E690664BD3F1F77AED2343A05F748E
+DB986519D8E92CB843BC8C62EB5F46E73D734D079464EBBC97693FB5A95FC3CD7EAD4A42
+AE6090F18938D286AAF8D0AD64C77E46822EEAFBB655A0995110AEA8C61C4F198EEB8E8C
+CD40D1A4317508E96EF47F6C9F4E6D37D81F8296BEACA5FF63732C8FFB8798545E86539D
+6FA3EFB324A89107534E638B54059790DAAF10234064B5C51B1B233F977777FFCF18AEEA
+AC8E9691C9C4E5652B68D4BF4D262565AA53E2E639FA7DE00A6E8E81075DAE11D09DC355
+2DF890E2F4FB7BF42D94BEDD9FF9E708765DBB5E2D86984BB5E9FD3AA69529A7B4A547A1
+3E7DD7AF3DB740A8076FB06D05EDFE10D4F77467D4950E515CCA452D9FD9FB023B7F7AD7
+188060BC823B479ABE20DCA872E7028AB0F44C36DB113876703856A5C632AB2D5F6543D8
+98C9FC6EAD7609E3002A348619733FFB0C715F55842ECA2FA2A1B89DB93A3BA102504DC3
+BE1F54AAC59EC23E6EA3223912EAFC711DA3210451BB58AA7AB7F14B1621C61D9875C97F
+D4DEF3435C6C8BF9BA8574E2D2CC43EA26E34C774953AA0790E650ADC9BF79D57D90F994
+C1EA2B452B4CC7A59463C7CD5675632250C7A51A13B494D7228EF4843C8C1A75E3E2DD33
+3B64FA9ABF7E79185E0CFE9E416B619BAB1F0E27524B1736A97629DB8A9723231E1BB587
+8F94C1A223CABA2435BFDCC4D2879FCCE344F6387E33DC32DD59D38388A7EB620A28153B
+C3BD9BDC43B6918A64E00AC4B27B4BE4A1C7BBF0A6EAF2656E196F70526C7ADCE42B3A12
+DF7DF2DC001F96C1C9D6B74BBC11177772A906922EAA6D745CF0A63DEB2D8C0364D2BBB8
+0A0A2FDA0DCF6E4325742AE90BB62AEAC0DBF0962C8101216C67D0535E96A464BA2185CC
+612AEB75F66FA580590C43D13C7C8C25B858F63AD20258BE0C77809A641A8F8A662B9C81
+0F4B3D1A53A80E062BF3F388A2AE1D4877BE988DEAFB3A5EE0743EE75CD07D7BD867606E
+45AC6243C9C775429CED85E6E5CA20021C6603514D6A6B36C153CA063213F8894ADBE917
+891A1ECF868C64E7BCA2580A0180F6746F4B6016A5326D778EDBC993072DF8D6F78A53B0
+5CBDBD5EDA4C30CD8FA370F701F093A06904AFB9D82167C82E1D069047D37B9A437AD75D
+9F7F6AB574925D167B6C4BEFEC85AD45CAE11BFC1396F5E6B39843E71660875105150AEE
+F2290EFA830DF0B9817D30D52B75FCD43BD20D30ECCA85B20B32698600DD8A8D0BC107D0
+C77B43C87161B766C69F02E81D58DB7006C5D5660DDE997AB669060C70F8AC2FAC3E13E1
+BCBAAA34143320C795625287013C7EF306BAA36A61B9C71F91AEE7E543F4586A7D8BD432
+BE60AFE2EE0DDF5718B227784E7165C4D2C4610ABE9521854902526E553D0A0CBBC26EF6
+E109C7040C3E876F71581B2831BB782CED2D8ABA918859741B1F748E0B8F81B168C7AE91
+25957055231EF91B31C3C09E2FEFF6C1BA4CDAF73B07684306BDF5F735DE2980E24C91E0
+A96B53BF903A23A324E2C3DE3432762CC7995CF5435A07252D6B8053DFA0A02AAA0E52C8
+8AB643C591431E6D3271B7AA05C5B5EC445463AF4E13D37E419947E18F22EF9CDF1BD04E
+2E7F106D231986C21CCF02D103253678E4F56EAE1078993E69B76D07F1DB6B7C91F2C754
+7D521E7FF0ED8DD23A6277AF86E4F67B1D9B4FEC627AA69470922186E477EF75A7D77EF9
+FC4A16ECF9A37597119B804C927377352CEF88AC515D6E914FC1EF5AEA7AF1F3D3802C82
+60305538E678EDDDFA87ACD3BAEF1A09F4F4AE1AC97CC0E7785F3DB18B6EEAE005FCFD6A
+C2A611CB6F4D8671C08791B9FED03755A13B8AD33C3341CE9C4FA948103DC77EF727AE31
+0C00806D7639F922B967830BF717CACFAF26E2331C571CFE01B214ED596815C833CA2973
+1D3B159B691BE5722D8ECFC2FC07E0E2A12FA9E76AA3F13374310C58E8E7CB36C68DD1D4
+3E1EC626199B5B77D977E9786CD9102454834775BEE6EDAB046E7BF335BC4572544D9377
+D60C6C389934E35E40252BB891D295E8A64C12C3790DDB9AE563FBFAC83A3AE606116ABF
+36E94DB1368234A61027B95C152985B30D67C03A99C6C6A6DCAB9AFF3A8B5766302685C2
+A6438B11F72D91D3B1D2DCD97832861DF613EF54D4858B02A73D37AFCB0BE38C44ECC588
+20F47EA30645B18817B79268694829B33EEB7990C52A4057BE22490C688ED1D4B0B8096E
+F6E24114065FDA365D05F9804107459ABF86DB0E7F38378C018003F089E79764B45D087D
+02DBDBE171A3F280F8BB673D13826CDCFC624AF331BA9732D81E16E522B551CFB43117A3
+D2FA42EE3159041494C5B94E66FC3D59C0AFCC0785C89F4810F772E72CF7133CC7C75A25
+BF0648BE3E0EDD3A724DDB9277D8956876F0718ED0FFF0D7CCE2A8CD683D2246EB26C7C5
+0EDA3D83BF795B55207FB1B8F9559D27194AA9B0DFB8900AC8227ECFB43EC08A7B325DDE
+D23F0ABA4A1B771483E181383EE1AD282C1E69B5A9E652EB71934CB6065FFB8FBFDB8307
+785AF2FB59FBDC229974A8714C47302429B17F5B10492C7594D66BC8CE44A8C42755499A
+F34DD4DF71DC73E2DDEB16DA14D446A0E0AEFAAFA47A5290E7ED5AB76C076B892156B159
+A5FD0E83D88CCCBEAE6395046A76559F8F33DBADD30F8D530A342297E4E6BC9E0A0C9F17
+60ECD67C3008E01E34E5F688377CF8B6DAC331FAF3974572242DB1850F972DAA8D73F9B4
+1A21CD8F3ACFAE89915EF1A2E369899F81826565A454B0E68C02625AD18E47742280439E
+B28A956044CE0A1A6E71895528109927487B2E543BE901144FD3AFE5811E2D5937439E5E
+29B6B5CDE26F27174D6DF8D026696953A6ACCB3E84AD623C1183484F38484C41E31D18FE
+52BAF597742D38312C7F83A31DC53EF0FB87325CC73E13A9A8B467C07237D23FAD848035
+AE90BC164C363787E65E8E759BFB8A1D0E36205BD6F9B5D95788E2A8ADE9D6CD15E1437D
+F89755AC4FA834643732D4F5AFB8B379C8A404EB2D5795FBA40A0344DDFE3E0BF2475616
+9AABA8F303DCD70653B3FC4F15565E9A3C53E2190F3F8EE18DF5C5E74A5EBA1375946280
+93BA397B914D8AF25792043641E70260C6DFFDDA2E09DEA65B3C58260635C4E3E0D4E384
+8D7CC744A7D0E00EFE5A4F35B392E536F2EEF714EC49168304DA679F87088CEECC5DDBA4
+EA30D04BDD075553947644E66E5D5F50643FFE8A48D3B16633CD2083F05755BD47B71767
+53983E6F4394FD61B4964F749977AE31C2D5C25C3C40D1B7E070C7A019EC00E3C55A3255
+EBC73C47F2A4BED7BF0387F9E494FA3E2327D76584727AD5E8198BD80A56B7EBA9B0D92A
+D0310E640E53ACCD7DDD57F3A286A301FC3E1ACBE21A4E9C572BB15721A64648027EB8CA
+13BE6FD4C97E304406554A623F3F9FC0F95497D97A325BBCB5735E2A67BAE21C6650F633
+05B25DA1E1DF9417597E09C8EAE3C3AFED656BE4A8021F5AFFCF55CCDED9BDCE2E7E195B
+1BC94C800ED80960503D735684810117CDF144B739AA5F912E71530A244D4C9DD5BC1AA6
+4A6DBACBF7B11706973418E8C2E04CF96E21B56C41162C78FCE26B025FA9E920C9C7641A
+1303D118AC0AFB7C87A371346C19944F5AB905B59AD125C892D213989989BCE2366CD210
+8A07518095BF0051EE471575E0189E41C7350F1DDC40526C34081730EDE9756CA029B128
+6C63DA99B0A4422DED67441301E7AC53A74190D24E9CC438FC2826339FF05E3B58F8FC83
+FB8F58B14DC842565BD87ADF791E8E4413030B60A484128B0A91F91EB8F69B90FAFEE2C8
+7326618D44D4845ED40A2DDA09B5CBE186E330D4BD84A49A28E3F5D1AA6B37773C12FEB6
+885436DA31DF8145CF2A993242E6F2177BC470F58DA16422C8BAF4FFAEBD8B0D4AD5D41C
+A32147945C2158CB5113C64ABA334DA9EFE8A371332F1540E374E0AEBEAB6BDDFFD4545C
+E156121E3348E6BC1D3120D4BA238EBBFE05AFA4FDFB3968494088F06109BD62AF8023B1
+1F8802FA6322E0F11C03C97C229C80C656EC7E96E4B5D7BC8040E0901BECB86D9A4A5C70
+52B867CB27F11307C4CF24BA0F56CF555DF0A8F247D5A98B1B04B19EE9B394B3FF9473B0
+2D943013C77EBEEF429D97B42BD8E25E251FD7BB352C3994DFF181324936F0AE8267CE8B
+657D167E89F690B0079BB26351FC13A13F968BC5E99FD306DAFC454A5F1A7ED0F388CE57
+62AF1A627ED239CE9B4391FCA709030E0734D5D8E1F7F89B3BA991AB9D4AEA597C4B074A
+69F44BC22323039A98347F49DF7A98BF48E617184A03E7276716DC5895B5628A004FCF5E
+01C22F2304746521740C919F3BD418DE025AC898B104BF9D15DAFE189246D3FF215BE37C
+E1134F41B0D0F0AD80719202E6E3691465AC0C9430C80028CBACD2B80A95A6C10F39A5F6
+12DD73AF2C3E4E0770FA137759F5ABFED0186BEAE50031C202975200B58CD5C7AF95E60A
+DDB460008A52BB26F4847E6E290A2CCB1F984E97B899D7B63948411FB074178475CFC3DC
+E212536D720C6F704C1458D45E5F2D7DA34903ECF51947DE98552CB2CC5705494121A96D
+BABFF6E7B1CA155EC91D910DB288BA8DD87736EA60C2B5A35AD67E4C4B323F1CEFD5844F
+1B6947FCC7A11305A1CF3CBE545C891CCB7A10F9685C9E2979F7DED90DD1D5C69B934635
+B1444A33B4CB56210DD269B7CE94BE1282EE7A2E2652CC743F33D25F1E83680DC05392F5
+31CE3343914C7E6C77D9A0AA13DA8E7A97B402924097FFF414076A8E055E76FEB93C4CBD
+8841A560092F4ADCEAB9AD16D7EECD6696BB47AC93950A844B70386F77572A3766CF3AD2
+500DB126AD78931F8FA3D7DA41C1F3E8FC42CFAC03070E28707D0FCA1A6A837521BFC1C1
+86990ABEFB76BA56B8ED8475F19E3B6EB8AEB62EF86989559B76679FF475C79DEC1A0DD0
+FCFA1FE72E35E5A50086F49757FB1E65957488453EFEC4E973A48EEEA0F4D64054DC9667
+0AEF518AE6999EB2A61C1DC53795AD29A18F30369C3F4378B78DD76781E7B96C39D068E8
+819ACD8DDB59E4D0B60D42398E336838FAE48E164F7935EABCF60B8B6CDB887BA75245FB
+F061E3756EBFC0ACA6E0FFE3CFE8D3F67FB75186DF4557165E1A492FD523C7343B1C2D37
+F05C4CEBC077B8DA778BE378F322AC5CC3B06C2A74687B0B3AF9D08D453753B5FC6E4289
+F362954B80C0E4DF1915E1719431244BF87E065B4A033E0B204E6072D006EB10DCB9F916
+0042925BB8A82EE47AB260686DF9EA59803AFD45C4D0B19234F6BE7913519D61B5E6250C
+4E5BC6CF722B53B283F4D5E5D2AA7DE35B5C87FD62C9E9DFFD671BAE7E08E68E11710E80
+5448DE7D5D65F4AA2E27EF0FF16CA3E6569A53745123A9FD7F0DC8A57D1AAD7CAB961645
+F0BFA125101F21F64F0CEC860CE306F02FB0AF49F0C0C6D11B437FEA68992FAA2D6CDB42
+6686056F769470CDA1C158913715FDB4D4687D06545AC87BBD5283D8B9E1FD1B1B0F256D
+7C675712C2A6622A179F5AC2ABCD06070A038068033D07E64E0C70DEAF9D61DB3F4EFEE9
+ACA908C30023FE3CB81597386872FB5D5557BD4461D513B6A62EFCBBD3062E67095F1DBB
+3167E0338EAC1A52B38FED183AB520E882595FA77F561312F83C102B04486D2942CEE713
+92563D7E609E81354D6F8192CE3310890CFE69B41907B023C3451075383E4BCF6102A669
+4B0593D81EDC415CF7EE2C2803CE5810EDC28B09155F92CB20C139B43E07BFAB08978CD5
+65270BD77658B0D4259BBD9C3A2200B64F73ABE0D77CE6D491253C7590F98F3AA8AF8BD0
+5946A659EC1099D13E733C96A4D84405915B12D7A5399645D0C37C1944387D088FB083FD
+22BDF34BB31B396F618C518DA593A9584F8ED6E9F299E72A6F0863B4A3C9F184B1AAFC98
+0CC313B225EE3384D2D814A4E96C744E0DC6A666114241DA125F1178D8F1D986B7D31548
+F9B6079DD38BDBC0AA94F135C44D8B7B6E9A0A0B63FB5BA59152E97F61515F49B906C9FD
+42772EB4016B53417C5A2C8E881B0376656115231306FE3AEDEB6182220C2181DA354D5C
+28E0D758C573C113542CB5346ABEA9B5BF0243146C186DC5AE0BD9505E5517A6224EA50C
+315C9BCBF6707540621B95B9F0BCCA2DF5BF3E8021CE9DDD2A74B6DDB0E9F6DC8E3BFC11
+C0697E87E6C4C642D2172889DDF4C17FCD3E463B30D7A930E4B26BA7289702ED77F2AC66
+BC9ED957863A22905F0996D337CFAE61389D3C70ABE7444E8138BC1BC31F8E572C0CFAD6
+BE60B1AD639AD39BE03AD66728C1CE5B7F2DA53098008E10B82CC2BECEC7B45421F0BDA2
+183588B519182DD0C80B0EF409E2F34C38A7D205CACB19864507CCEF34C5B7A18B9FB51E
+3AFBC0970A799FD34464F7AA8135C32914D4DBC466DE2922595EC4A255405D04139C0CD7
+F162674F39D8C01F1E6062B5C946F2F4F5E2F49ECDFE43D2642272377C5393E9717CE335
+11B8542FFF199FDA0867DDE128B387A39CAA79DAA1DA1388B88A5C921BED6709418DA595
+7C8D96831B6FFAB26238DD3D11181345B4AA07FEE3D76093BA5C069C9CFE9E823416B6ED
+487308D542C84630AAEDDE0B59A256526169B820E56504014812661336692959ADEB6805
+C7091B7899F0EF46299C414925315D10A8C9652931AC7141FBD3DBB0C34476AB2808FF11
+9B10C17C796E67EF18A386F9E55E34E0D32701D1F77C78FB542D49C53337B9074D92DCC7
+0D4AE59389BF27E9CD453608A19855F6A976347AB95CEE2B07FFF6765F97E66978173C61
+61E38E6CC3BB2E278C61BDB601DB7835E9515D347F37A63EC6DADD2F72BCD46AA4FBC82E
+EC40DC7ECB825867B98D6F457BE4502C98DA8756CB9285B7DD1C867B9FCCE8591EF331AF
+44E38E3523AA39BF0922C6F59F1E9343AD34DD39DDF485FAC00B38EFF62E16CECB735ABF
+903630A30396F2912163FA8B23E97F5B81E2B5B538C454967644E63B351B068EF4BA9B3E
+70C65BF5BE8F0352F7C0E25EDB22716A632FD832D51AF2D26C880035D8017C02B0065DF8
+44E289E6D559125A31F76E256197DEEE1F2CE1D0BB7303A3CE177B692D3D0F8931A35048
+F86168DEEF39FEDD4860DBE06F21F21D35E8B982D299CC945E2C8E1D73D1891ACD1AE977
+9584F2F3E9B5621C6EEAFCF91E293996F35562C16AB5F35B6A0B55D9FA85FE3B08692C03
+E453B44C8E1438205A9F18DB136F954C7155DA1288BFB6927A4C308C86C682B78087FC5D
+CD3976667B4CDFB90CF4E882B1C35D9515760DD4ECADABE73C3E9758E0A8A3B01BAA6A2F
+091CFB987E893A722ED935642252512C3C3492FE736403EBFA8FD18FA9E9CC5B0E802E4A
+CF77415626A072B3EA3C637D2F998B91B7A7274C2DB664F4A9D73595C2F47DD61E303403
+04E0DFCF9CF520E33AC7E0978B004641E5B6A88A0657F615C2FAC770AD1DF1E31BFF6E1B
+8A32F32F0BE2A2649B9BF3F046D8ECF27A0AA62909D0A80262633733EFCB4C21A295120E
+9B9D193A12073BB638C3BFE75AEAF1B3F43FBE3FBA8176DBFC8AB0CCD2E874DE912E3A7B
+13421673D66744ACD888E2687051B8CBA461B90E7302963CC5DB88AE64303BE9BABD47BC
+05A780E1545EB389973A5CF4CF9E53953DDD085E617213B10B3836101E98A0638C1CDCE7
+C9E0D9FE79D94FCA6472E2C9C9FAF3D7D9F260FC849EED1236AD5774045E52CB82B0F7A5
+FE589651B53D7E9FE4A8848A702D6D5D0A415337F6E8DC7148ECCF94B23AF1C11616158B
+EB253C903DC963B61D2C27DDF6E13CDA799C54FF9762A1864E516B913C401713B8854414
+B4CA200EBFAA01F382C70F27589796D7EDD4A35334853B33347F231F24C1817657C93000
+2B59E0A2C4A9796822D5F7BFB3193DD9808398FDC53BC25F402AB126C1B2C83914888851
+037FF02EB53642AA0E6CCBF0ED5812527BB367DB4E67A6B8046DA7C215448808EAB80496
+FFADA52671C89E018CBC8D36CF78675E0A721FEE1112BF9C78D478024364E91CFE2468EF
+B6A0BD9E1DA67863124D9F5F996EF1FED356C7FD2AA3DB3E3F6CA36262E896894FED244C
+F3BFAD999C6F42F13D4AF617C03E29DD1F8ED75BD11F94B1BEA408ECFF117610EAFBF4FB
+241AC338E6A8714A92F2A5AEDE86C493792743F648F2AF6E9A2C692A9669180F629947B2
+6474C03FB8B712031E24F7529143F432607D57E81CBB91A0DC6588EAD2DF8AB5C43C45EB
+9DFA398AE8272E43503D987B36504181B2E9AF2357ECD3E6FDEC731B623D921F8D1D0A19
+027876125DC02D8FD29CD8521B36373D4498E2D2D9144C85BA8D5D9AF13BD5C8278F036D
+ADADFACE6FFEFDADFB88D3CFF12B2CA14BBA16CA7267A4CAC32A0EDE215D7C0FC7EF3B6A
+59A33CD5145E2D8E3530F94B5BECFF74357DBA205348FB22D4E3D40F77ACE73BF519CAE7
+5277729978A61B1B9B76E846EE15C8139B927EC9E2F8B684E0E5A30AF34A0027B9F2351A
+B149CE2C8DC951CD54B4D6974E0BD74BA6C2F83BF680F0A01CB39D8B835C097E262A77D9
+55A699E86D30312427EDDD64EF7A3ABA1CCDEC22EFF658FBEB30B8FDF59A9C4185A55704
+530A1499CD700E1D6AD5DBDE3B662DAFEBDBB185C32C7E34406FA6B3878D5B564ACC5D9B
+EDF6C7B42411081423FCD2BEB0AE7EE02272F547D551547A11F8CAF8D9F2CFD8FF3626E6
+3CCFFCF9277E6003911C54371677D671AB17424633B776DC98004EA4EA0917E085616ED1
+273E73F2FB891557CC5A9BB65FF704EE526EBF8B34359AF0381A61059E7B740D8069C128
+0F942C6410FE3ED272251F2653817FDDEF786B1F7BA9C6CE02C56C33D98E937EB303717A
+1AA3FE1CE2D10A5D07F0E7DD4269F44488ED497E75C92657A2CBD792B9E3DEC8C073ED52
+661DC43A52A6A8218385FD37E1D7791E540F225AAA90480B69468660E05F5B826851F985
+8D127FF6ABA8E58C4F69961AD4896B4EAD41D14399A3F7588E04E63FC1435DBD45530015
+D9C5A1DE717D3923919C31B79898FF17D949F47D354CD81840DABDC5585E3ABF11E556F2
+9EFC55559AF05084F95A5900033AC0AA2FE370C49C71411B98B69DAD30D9D9F75DC90A04
+E59234156EB4B9DD2F923A2DF771818759BC86E763FF36898697F37343FE7197EF5ECCD5
+0933E2C446D7AD1AE945A87A3B7F62F8E14899729CEF06BCDBBF29D65ACA3EB4293CEF53
+501735F2DEE6CB331ADC94F27492130776C3E3B422975275C115A1E9882C6A4559A698D4
+46C5CBE11497CB48EE316810CE428A6A08BFFFB3D196DAD7BD4778F216055C79C325477C
+92443E2978BE1EDFDE5836C722B96A070269D2D3A1438374BA6071FAD1FFC511BD8974A5
+803AFAA40E3509B10223D7924DF9215650E9F13E75293B799B4256B7DB4878F3936CFCBB
+33D0A37E209A1E3EA8EE6A3455A84E28552DFD56BCCA0BFB10B7F7D25983D3865A9C617D
+C85CECEF64CD8E470916B0111075DF6D051186CCCF48813C07E53D7DE553FA3B50B6F7D7
+EA60B3EF169527C6206D89C15436344E8C4AAA490C0D6F300D3A18EE3C50D30BE9ACB50D
+5BAED6CA52732E7530C67CEFEC9ACE3659FF09897A62F22A6383F7B62289052485B2139C
+48187D0FD3F64D65EF4E2678AB5133A09D448986C96C383FCA7E3518D91BD02A51BE54A2
+F7221ADC7317ECA49522C765BF38BE70EA692F063BEF59D5465E3D65DB466ECE7568BBB8
+526587C1A4FBCBA6D585509FC29F6223D68C4BA4AB48D83192EF4D323FCFCD2C399BA52F
+776CF7CBC0F7B9F828A7441FC1540DF41FFE91718AC9CCE2EFD9D0E8D8FBCE8402B441A0
+AA2F95E4508D703E86875A48BC8C579A2CC0D3086B99290845A44B3E14B28D95246607D5
+ABD998C92B5CE660D40D31BBA97CAD73DB5ADA4613520BD4C4D19F34A9D3E57D66DB2090
+30CC7F57D5108AC7DF5F528C04A15B360C8CD1ACB78F090AC2518C1EA0D64F0DF393460E
+25C7F07970E49ED6DAF204DD86A718DE11F8DEC66E247880CE1DF51FFD8A5797C63948A4
+80D37C43C508219F322B346B65ADB3A801FFB1033D409838FE05234432EFF0FE2127AB0B
+EBC5890CB026BF94AAC5DD98E4153015B36D30B72E5192DD9D5EC6E8609423DDFF7339DE
+5EAD4AE73019DFBF3BBD13FC154FCCE5F459FF033A826C7C4DE12ADE39CD85D3366B8CEA
+64D4CC905F352424FE9120F447B75A51379885369A73600366055384C7BE79205D2B868A
+1A6246C803C27D558DEE4EE108C013C6CFB8AC1016479E37C0FF0D4371ADE9EDBC986BE8
+A8861975C6761CF9DFB6F89244B2B447AA9E48E8EEBBFE1AD875AFE06D2BD72D0867FE65
+68D316B08DF35217AB5BC65200870036F850433BA2C26D1AF67C859E8DEA24AE44C6F303
+059B3AA2CC0F2DCBFA798E151627BB8CA785FEB783D59D10132725E44133655873FA414E
+C6C9EB631DF1D0D3ABEF257BDFA9B1BBF6C17731195DB3B53EA289A0D3E63F41A330CBCE
+863B1B6352A72A11F54C813595FA055BB5FF7F27735D4D3F5C87ED89FD18A4709B73CF8E
+64F9793F12A0946B974A03C4BE4C1C2CEF752D57E323981438F021334D69737DB7B9A0CC
+4CD5A93A3B9478DFEA4096D143BED8D3C4E19C7BE85436745B6BD0D54DE8DBCD1268E5AE
+D92F8D23596A27B730088F4529D03E2C88966525D62C4A90D4869514362F605EBB9852AC
+904758B83108A59E29BA45404380D86D51EC2567A3574A9C6889B22CC1C23063A782746A
+02F43654B378E2C60A66F583FA666105EE8AC6C54C17AE79D0BDCAEFD951139FD96D45B8
+2F75F1928870A9876678588B6FF4B76F3062A0B895F8095ED27A8E620C2CA398EA161BF6
+9EEE9567D3C4CBE7ABC01D7AF30BFBB269CBBD0BCE7208BE1C94E95639E99337C56FBAF3
+AF87E956EBBBF2D87FFECC8B32220949A038C48BE761CAD77799F8191AC0975236C15458
+A7957630480517AC0F89026DC1B4AF3B005DA7DAEDBE41EA451D4B28516204427BACF5ED
+968101E14C29396B7BBDAA67F10A602207F365E96CC6E050248C46BAE78348C4E016AB3F
+1A1DB7E9BBDF6C8CD37615A12891667153DE23FC013ACBDE84E5E490FDBF9066C1CB00E0
+528714B54E71B5626E71D387B8FD41B21E2DD15CD595EEDD545A90E8F0D02388820B2A97
+527EF7DAA65732B6EE2F07E2936318FB75143DDE8F5FDE804346AEFF05637BF48A705A85
+B6F3863470ED141E118801AD9F47FB05BDC65AAF8F398BD3EB895C3AC5C94DB7CED1AE7D
+1D7311DD67343AE0B5724A8827CC26E463AA76B00F4CD3168F1C92C64EAB1D001907B900
+6B1A12550668E688E2D0ED3355ED0271228CBBE4D56848F0B08EA24B00B5B20BAD06EE1B
+C6606DAA509FDC41D2BE545F9FA650E8FBB0E78CC856A5331A8A6476FA3C44487B9F37AA
+5DBDE9BE2A64C69CE8438170E2B40893AFFC0BE099EAB03E5034458D54BF9B64BEEF7167
+A25AEC8A1F7217E492E5674E4C8B343B9249B384BA88DCC4F8902FD4D535C0246E1609F5
+4285F84C2D4B489369576E74272255C329942F764CD4A51C730C99E7F5F8B7C52DD252C8
+500319E4CBE6C696C77CE1ED8BD05D22E4861CF9D156B95499B3718A47E5BEC9FD72E1DA
+DBDBF137EFD6CF8BCE7D64A27B8C9BF6E24C929BF07F5A62BEC7BC760706D31B98DD8E87
+97559CF8E4357AC49FF6B47667228686A3AE789D68B059FBAB877F3F1BD00841A1F151E1
+EFA94F69BCF41D4F9DB5423430A2AD2BCD53BC87A5178F74EE469772FEFE1153C8454288
+31B12B8276E3E54162B64B393BBF23F1EAB4D1D385FFA5CB3C57809CAD0A453A10661D25
+685A9C56B41A53C3B1CE6E41418D8B8104A2BAF3667EC877C9B6269BCFCAACFAF695EAA6
+BF13891E52B4FBB7543F1BE26A867EE6B515DA051C3C7BA25BA135FC186D4379D9AB4949
+582692485409A5DC52BD6836D8CADC2A48A4F5B4FCDC69099C3EFC7166ED293A795DFDC7
+3FC01A91C9C15219723FEA15A4FAAC3511AE8D0DCCAA1FDDF7E2AF4CBA80E38FC6D2D8E5
+B9AFE27366ADFF0529348BE4E56484F0E31BFB7B9DA4F06626599FEAD323CA644677794F
+541EC7888B181EB0AAED60E6F0E5FB4F2FE2564E2988D6441E58C2C0C1DE63CF65D625B1
+46FC422A0E0E77C43C8FA2CCD310B5694EC8CD1B9A3ABFFA25687D4013C0E5703094D5ED
+37295E540A1B2B2E836FF73B23E8CDD190D1FC04DC6CB9D5947AA853F6748388D400B6FC
+7DCCA73AFE6D1FBC61A7A3AEE4D24BA702A2F4493D484F19CDA1A850C95486E4E4D43F8A
+A584D14F82AA0B3862E1FB06E941A90FEACC607D27AE58CF19399886879BAB287A429D5C
+0C821C26C61F169F1B90CF77878968F56737041BE38776374546623553223E6E2A8682E7
+737528C915EBD41B263DF7E12E4A4C6967FAE40F90DA0D0410E0F22BDE01F018D63A8C23
+C157E72C6910157A63B33AAC9E5F3C58F771B8CD24F0E24C4EC17277C8B8DE5DDE52176F
+A9740EAD3F62125BE32678C35005CD445EEAB9AA1E9A71FD11614426E171EE85F5D9A17C
+536C87D58C5140A64B080966EC5A3E0AED8BACE84496BD019E6023AB562FBC1F28CBF296
+3FF98D715ACEF7BDDDFD65DB78CB3F0E16C440EE636A0D7C05CB97C085F7C5222ACC6305
+4DA8C3F7D950B0399B7250BCB66D0D520AB951530E728B4892779DF0FE56C9A27E279DD5
+02883DD2E2E4013D03491C52B21DCE600D68156106418DF5273C6F6FC9A3E1E9889DCE43
+17628702B21201E48D23A7E0EC5E1DAF104F3BA1F659B8FDCE301C3D7ACAE1B7CD6846BD
+496B16BF6DAC876C117242B3088287DF82F260F960CF90849F515702F71EED275A40A579
+B0B8F707681B5FAB21A81FD992254AFC0D43E88D641445FDAE5D6874C4EC37B2BE38D5B4
+6DEB232B7100BCABA7ABBD53F5455EB07ECFA23B1703A2690869A8D0E60276830D7B4FAB
+231FDF2784CC788CE61A4909B89C5B8A5791FC3160166BAB1BE25E57BFB2D162CFCF36D9
+CE524A56A15DC752BDEE0CFE605E5BA650ACCF0DE4286C70EDDFDF8527A02C3958B17C82
+1769E8EE3E46FCD93AFABBDAE4809836C56C242B0C6C63107AC6C3364B7C79BA5C62BF62
+EB6277B4F6905CB999C568AE118A690FCBDB37433DD2B360A7C66EB52DAEB0662D61DE6A
+74637C6C8B373F9EF9A473486F3A4326ED5A442BD2566912C9531C5EA6BA89553FB67C16
+1933CA4D7FF5886F2F6B3ACEBF939B682968D4B0590B0D39A0871A78EF3885E47F892C16
+FE93101266B12AB988DB622F4E408C442937B56007334AE919983566CCF994B3084C0D42
+5EF94563A51CB142F0829F5398B647AAC6E0010DFCCCCC15BD0EA5A6CC90EF8F790980F1
+4C8A27B2792B3C83E1317CB932DB3B28F008D442D374AA75573F5A324D7C5D6DE8ABE5D2
+CF78A931DCCAD7831AC5A7A5D5DE80E475DB271F0CD21A47B1E7DB5233705ED0D421EC5A
+2BEE73D5949400151866E065B28D6E1F6574E2D335BB542D16EDA5823886430390F9A0D2
+B937F7ABD1DA9E04894ABC066F8CF0B8BC196BC1465A378BA14D2284AE4DEA134DDD7440
+77DBA60CD0F9E478EAE5F7DC0D6309C9EA514D44C279700088581B29BC0136E2F4EA3E9B
+64403DDB054736966C331AC20514637A3CAAD1B27C569045C444D48FFB63091B6D20CC67
+FA5034880794ACF58358861548044DACE9BF02B4A23925639B7A6A5DD4B6AEB2F18C1619
+DA2E4597905CF4A00ADA215FF258BF38FEE6923D67424DC1B05015C8D09DB1FB7F660C6D
+E061FA2690AF2CA528AFDDEAEEBE6291D61955BE374DEBC8A915639DBC5382A17810993F
+92E7EB5D2492E76F6142679171DB74170A6B390CBF7E13CD5307CF04D4C471BE0C7EFEEF
+B36F609D765DAFF2E682983BB0CA6B70B713F1217C8F2272637C8AE97B3E15D5D451AAF0
+44FA166A93B277E334DB8EC58EA397CD013B53DE2D7944387712E80F086942728B9A4877
+C1193716F71ABCD563EA769AA555CA4C48FBAB634B1AACB77C7A576C4DEE78C5CCE3D3F6
+E483B076A4024292A35BC7080245E56B6D58926983C0D9C31206130B3B8AD5CCCF8A8659
+465C36D5C5FBEDD7B455EB4BAFF35AAAA12BEBFC6A7B40AA15B5B957625C37494177CBD3
+E3E59740FE558926927022C6411B9F07ED9BBC31AD206944E56146CA8BC0A9E8C9172C0C
+0B7C46FCB490EBD02E86F69564B8030A3280E376839D680786A0A068DFCF0A3DA5048898
+69C9AF0362765CB583B785FE8C0FDCCE4F39527A7B73565CEC9E798FCE909941522819D4
+519A12043D35DCFA7D9188EDFEE780E04A868346C68A3ACE74B16641873B8985C1F0C263
+9BF63ED86CB556943932F9AC71096EC23E9584C8CEC8E95C52A493E4463B168BEB6F259E
+71B2B22B53554E487A897256E37BD4C1D3B48DA9AA5C5CB8D5D85C61D6E1BE3A607BEF1A
+A8ACD46A93FE3C07D0BB9EBBAAF0433C7E5C6D5040CF9F5AFFB1AD8104D1328005CC5B10
+A1993D3EEAF3C3BA4A0B1A260A72DDA6ABD5358DE5171F1DBAB667AC022F46D3BDE54809
+790CC4EA533392E6C039013D4B0FA21E36143CD9E708C89CB13E09D624551CF86BB79C3F
+13868988903A7C5C744743FC8CC6B48219FBFFA584E016953F8CF342DCD69077D9387A34
+EEFAD0463AD98FCE21EE8342A3CC4B9CC10F6804EE9CAF70FD1C56CFEF02B7CF2D89CBAA
+E45918EC9445AF3D1C43DFA501D9B3789314063A748A6907BEC153F294D6D046B9C76D01
+4CC021D3074C0A2D8E92B45EBF14C1C5AA39546A2362CB8A6FA0F5198AF84119260DA3D3
+A89AAF0A976B1D5A020ED16268C8F1908400DDB8E27F57DC2B00E3E4F0DF1777A934DD89
+311A8C7309C24A670A6A9E03C094B548D223C31521DD7FC2BEB3DEFAF7904EC0123FFBE5
+4E627D9AEF3AD29FBAC003520D0B165F3AE91AC94FD8F3FA9A6BF9FB81863D03BEF8506A
+A74C7DC0B50BD327C6942905BD07FBD62E4C3B16A06070BDFBD80414CB9D5261A5F721CD
+FC7D1F1A6811E1362F9372CBAA3C8DA63BB103B2C10BF6F2504306DB05835B80FB70BC39
+DEC4DB3ED1EC4C2B64CC907D751407B6B8379F449210D0BB68CA1C445ACEEBF9C31419B2
+C4C5B8780991D042AB3948A5C5C8005E0BE1859B13F8AE6D4AF62F00B415BE5BB641B964
+53F037C492B988D839B96AC0FE01DC0EA9E064FF06EFFEFA446F41AE8E44AE58355CBBE4
+57DBEE1EACEBE69E6686B687CFFE11DDF76C2EEEB6662B1A2A176BA63E8800A51160A6DB
+886AC4C5868D17487273984BA2A47F39837F197D6A9B279D71157B6ECC2A72F83C1A5C45
+B17698F3183C00B6A61C732604E5520320309069628602318F4F68DF0BBC2BAC6E90D1DD
+ADAA738EFDC3F63E8F24DEC44D41D2CA546AAB5A88FF61081C144DF568F35C21A887FBAD
+C87166B58486340679B5F844DBDD772E9848400746A207BD04F470D2B2F14A36225FD693
+E1BC7CD6AA3BC7FE471C56B411B084FF8A67B0B42954C0915C7388BCC44DB2CBA0A70F4B
+1692AC59029B8181D12F6A1F22170E04696799AECE8E6B4A96FE89B7A18A4B6684815BAB
+D8D94F98302D44EA827914CFDE8CAC4CE48586630DDDE0FD1F9A57E8AB0EBD27F6A25186
+7986192B6D3F46C796247B1A220455A49745710E32F4D03B4F15636197C6F84967054365
+F7C0B1C20DADB63AA474551586EA5F055F8F3EBB1214ACB3128D4C6FA566C8E506DAD848
+6DC4A245D1977218241A5FC37AF7C03342EEEEEDB2EADED36EC0C43BA42F14E3E9601784
+5780F5C6E5262D96C0C50C87C9CE4E4666D1EF982FA7D4F99EB0A5EF4AB0456FEA1225A4
+E6873C1B6888ABEDCB0D84275EB400E73695564A15E338E00DC77981DE14FEFB40796373
+631102384B1A3C0EC239F19A2DEF2689F75F5D55E22AE9EA06A8A33424765D84E458AF21
+B8C99E6BBBE5517587FF76E7D02BC5AE43007F2228014951C93C50EE50EAB764BFC8A084
+86E97549CC9A8C53E442C8AF409C98382080D32974A105D60383E077138C34F887159B4D
+5745F7B6443B446C5840BB92A3B0BC317EDB0CAC5310AEBF16285AD0C4DCDE6E27C0185E
+9CA90D3086D6E11EB43E65F25F74377AE8BABC97E0D9ACFDC1339D0613600BF6E2F6FCBF
+66A0AAAEBDF0E9B3241F57D08C17612666F8286FC17AD0CCC5AF7F355668E146C3FF61EC
+07A85AD2A655DACD2CC58D5D0216CCE6F8621405AC7A4A160B6B2C9B6C5857D40A5BFABC
+199AD07AE8BE3169A9182F81F80A094608F1C2B894A6CC33CE4DB65AC02E3528601A27B0
+FB7E14B2B97F6391B0CC8963A71C6794E74037CED7C0F2D9B7EA192C44A5C1EC78535F45
+A5A38F6C9E9E811B950B7D0B2BCC7AB21E8B10057E64A72CD86549B52D74C806C242FEAD
+5751BBF62735377DF1C0582C89B0794D01FDA343EFA486AB2746A6780508206D0C42F020
+94F3B8ED6371412FD4CFF17DB123DD857DF02FEF68954C8A64FAE88C67351FFE15834360
+1F9DA7526CDD58BAFD5372A39BB7AF47A04BA972ED382B7CE3FDD92B98B9147EC77C5496
+773F33E58D6B9F48447D3BEB6B12CF2FA194EBD93B318014CA0EFE61E6299E097B394F88
+6D15B7DE6DBDD12A8B38C5D0F328FCA5798E951D950DED554353AFC64543CF6735456CA2
+72333B0797B4CF24D247BC76F9FD325A2044F01046343862E92591CF371C1A2F6118E36D
+2AA1EECFFBE7115C525A722072311E353526224622B96265B29C10F6FA3E35B8B4AC8AB9
+084F74CA7C2E39C19361F97BADE96E7962B8356C92DCCE8B5AB85C48F569001F238D113E
+8E0D83B793ABB238B8DBEDF30F33BE03ED480AE7672942C7F60FBB2B2ED85451DBEC08D6
+3F33AF72437E6598E90C52D62319A1F2018AAB1155506A96D4F2558004CAA6EC715D8EF5
+A34C7779ABAF2CC9A288DD88B96F0F3F1E45A6A7049348446526EF562DAB4EDDD8BB3030
+E913252DED80A8075C1C93E27509193CAEEDC132A3176490B03C53DACCC26417A5838515
+FD4A8093EAF7718341F9A6973474EBD66C63884BC78E318CF04B9D3449196110EB6BC018
+C1DB6CCBCA2ECD1016F1E884320B14B27BB8A15FB42E190C30E45965C32C21104F49FAA5
+B3F983C768BE7C909127C19EE6392D6E9E698D650CEFB7AE48B2442522D88C6D6FDA41DA
+B8B3187F497DA1BDA3FDBC8B71A619063D9461393FFD5A072F237B7FAB49597636B7A41E
+91DE676102B0FB2ECB4D5135C015B99419925667444BAB52923DE73287D3934DCB1BDE9E
+72ECC4C55A55BB24A71B5A37960993BC88A0C66B82C2E2AD597EDAE4F74FE918106413E7
+233C832EAD1D2A2E515D734960730EDB2A8072D539E2C69CC5C9E569109B20670157AB44
+41BC249E8DAECBD9F2115663E7C88AD8C4067158B822CB278DBE410E8B1E3E79D4E20C6A
+E8FBB5746390C823D5D818C3583A41A2D080DF439916FF23709C6E816F7DA9FCC60E5B6B
+FD17813DC59636D33A2523AED576BCDFB0DC88725D6B6F286B2C3DD85E53D825DFAAC9A8
+8572519A254CB4435907A2A57EE96CE3078F80E24C0DB0FC3B047684460F5314B1EE091D
+6CE4B884D06DEEBB7E1ADF4B44376699AEBD7A5F4AE19B5FF8022459E9E2D43117F4C1D7
+630028D14169FBCB72DDBE7E4BFB4B7EE1DCEEEB91623718BD1E5B9E16DD4F3ED2469BC3
+1BE0D51A530DE079DE096431EB3C624898333E4A271A79D33816881ECA7C355C1C0EDE72
+039E2800D050F507D05D8DC2A6F79C1E58D269B1CF397160A813A827B5D5060CE32B3454
+DBFD65339F3B75CEA60BE92A1848B7CA7EB730BFA278E8D549D3DC68E9EB32553FA32360
+4F516DCCC56EB0751383005BCA15849491D9A0BA4227295B88BD819FAE10216E1E2F7CCC
+DE0FA17076C881DC4ED1E03F3004437849D059449BF180F4E5A547218D6CA90D235A179F
+BE73FCDE7531099D073127D048B9D3050959CD6DB6FF19E57BB9F296536E33293F4856B8
+20A8E948E00F7FB3226F846EAB9F1A7DFCB11871E7B85C4A7BE6A023BDB2314FD77868FB
+E02DA316769382443FDE43AD3979D243726923904918AB90A8405B0184189C7FD724DD7A
+E4EA99A6E31C18B5A00448A8146A9897584A935118BBD8F7BA9EC471461E5D932434345B
+630674C3ACD3C97E0A5C1E6FB286D9A3ECF40FA51AD7C1FF9992E0EFB3633F4FE8450FB2
+15947E2AA9E07D07A98723DFF9D31CF3C50C4796D98DEBE12BD475765D8AEA0180CCB73E
+C33CC144FCE23D5D90282349CB17E9FA753A6B8D0F3FA480C5D6D4E11FB30393DC4A774A
+6C568A6794F6C71DBB7A1E0D9F5BF8DAF1EC3CC18CB067FF86201124CA66FD8F7B884910
+DF8511ECA9F027A27CBD235BA14613E32213923BE966B04A79A6328431B07F762BD7AADB
+CAC4E00EC767F91C3BDC7FB20329CBC2A91A98EF384CEAB49CE57F3A4D83C4A690E49D37
+BA278E9D39B92740923B3F3E5B8AA7743F2B8EFAA230C211884999091373843DBE82C2B2
+3FF81D8D7BDD75E9782C9F3BA1C587402A335ED42FE47F837366C61306807EB50BAB23F7
+196DD1080B0389BD1221115F17D9B51FC600C77D5B02D78F05ED65F895AD34CCEB36EFDD
+8A3289F4AC4472CC5513E688B96053B6DB54198E0C0B51C3FA3723AB54F2615E0FD7B488
+B3DF35A895E558A05C100605A213129C0D8DF08C92A772450F2F1EE7806DF2B5C5DB82BC
+4B72137716329403F9CCF85B592DDA02CD4FA4780D60E8B9BD7D079C59070046432F8A2D
+8BCE7098D4A81E6933807B0D9EB617C2D8F7DC8E29A5C10030C93918378EC771EAC7FC78
+9BB4D5D1CB078D4B2F0F239039EF9F1B45D768CF1870089F76F54F86CF4BF7A443A1B333
+EBA476838752720F8ACF49C0147F62068606057E9E8F55D3C26BC0328216D6E55B9A18E8
+BD8FDC0AE1FBD60D1244AE9B060313ED36231A8610D0DB8BBF8B9D0C218082678F828853
+2BF2FCCB4E13251E1FB176AF17CFD1B4E74B195FD65493F74C9755562D91D83CDBBF8693
+161FD054345DC816F885596C6B5F423605D0DA925E27D8A44F6EC50E36C368B29AF9FA5F
+7D634E4390814758A934E216DC092F352B49916F6F117EEC457AF1029FD0FA1B267BF519
+C85866DB602A67F6ADCB772EE699DF5FBE9799BD6B0CDFEBFAF2FFBA9E7D1C7A4E9A8D72
+B1730290E8EF082B6313E162E1C1EFFC7A404C28B4B3E4C9485041E941455CEC85C94BC6
+B727E5872EC049B0F6654CA3F21E107FFC105175C30BD172B8FEE93D16EB85F14DC911AA
+E9CAB4579778040FCC18F15C35F5CB1DDAB8C393476B882571B1C81777835F011B5DC4D7
+91703453E60205ADB46E9F9049F980603DEFA613F14F370EC8729C5D365BC4D128C65114
+833F57FEAA89834597C2AAFCDB74C5CA0A35B6C380EB029CBCEF5B7BE1D253760653677A
+78D18C6230986DA5EBC43888B7CD821C1EDC997A4A3574F695CFBECB60C7F07C5FC4B9CD
+CC49ED481593019AB8400DAE0BCA31F101B5483B3DCC330631F1EC7F4E5D3EB5D6E38ABE
+DE013DBDDD4FF6D9689C2F4F3E7D0F2FAD680B94B5375853A079678C3C2FD7CECE27C8F8
+7603BA3C73B1CA9CD33F9D114630E413F118161CE5C6B38C8C5827710231B9E8905FAD73
+DB3AC1FB0C7883FB8C0A96E05859265637903B41E662CC4D5FB36368E4400737C5F34F1F
+465CB2065E90A9B453C7D2A3102CE69537616A15A462087234A358808EECECF2E1704E35
+0AF5A17DFC5D5E83798E98861B94A1170CB4DA8BCA63957EB1B7E0515CAAEC440A291161
+F6B81BA7DEC7270FD3F2C07B8629E1CE3FF15376660078185A05C41D4FBF99285413F001
+4CE1D20E4EB2EF6676D1AA2FA8A4DC9BD3AF6F664F9B4E4B3BCF606D14AEA0DBC253E9A8
+75AB27F3D5A7328850C2E90B6BDA2420E82BC0ADF07C005357514257694FD442A6E701EC
+CC91B7E0845B17CC8F09892BA35CD5334DD73AA0424AE8A0E1CA52D2109E62EDE237177F
+1B469CDCB95F1ED1934C09C1C71A9061D0C29059C00D7A6CC1DD2AA2DDC209164890161E
+8B4532199F7A5503A4438B3769C9E1F8368764D4F5A5FC7CB397E27844ABC9F2498A6BBD
+B6AA3C33125B52F692D2E4ED469E7B3ED78D60BA285131AA78F581FECEDADBFD2E7932A2
+D96A86944BC7D3F511558E3BFD8AE1250924162874186ED3D12210C79C044682F7BC3029
+D9A352D3533BD903F26A180686482129DE478F6A0FAD7DFCB9EF25F13260B9B0273645B6
+24583701E37773426743C9AD1569FCB3C69277C3958944EB211758D1787C86F9DB344713
+9F522EC5328337AA586BDE5B734EBC6F5F392F7BD9D6910F204C63E9529C9561FEEFF567
+800BCB0E900BB465DE21A576A809A13F3E4FB24A9223B41E52BC297040808840FC7FE337
+7B7B71A0318EFEA9A421FBCF3B797BE09579FC5559C3085163CCD30F2757E457A04923FF
+DD33B439351FBA13AF5DF216A968D8F093540D70222A5F98CF9E6EE6FA6ABA02B3BFFFFF
+1AD6B5A3E48298FDB66E69459C7E9646829B032E99DBC5B4C98731D868D14159E95224EA
+9237CFDF32A20DA1A4CAFC0D55CB9DC4BAE3468A0A91EEACB9F6C76F677DC6BB83BABAC6
+7A7238F67F41F0A67EAE0578F56D3734C87304C0D3800E9B52DBCFF05F6EAA9440691225
+CAAB4C86856463B0E0ECE208CF4920871DB1EADA477879A4C64194DDC2325040FA104327
+FEE2F853DB4515C154B3B8A78419DC4B17C78F14BE6C7E8BB47388B11075474AEC54D6AA
+C53AE725242BA69651DCDDBA6774C3DB95B947A044D009DE74575030C947F25274EB0A1D
+331D25E53F231FE7C2B7817F44B6E98D0B845BD0A31DD9C8E3B6845CC80B259C0B850278
+5E0542CD65CDD0102FADBA33501C1251340F10AC63988FF53BAA60345A145455009B80E6
+D67C8722B22FBB74554A88B0284F641DA252B9A2556B5EC15DE1EB75C0F74CBEF4FF7CA9
+50B90497D23A935511F5B7EEA0B92BC686D71EA186B49B21E9183279379637F8BC3A3079
+3419AB94A6EAB55F602ED0D4EB20BF6AE82050C432FEA1EA3B5BF2A16B879E586C1130D6
+CD5682D7A1F51704EB03EEF129D7994D80183B70E3D60A5EE4CA8E21D4703605FC8E2CDC
+03E1FD17A2B788FD74DA79A0942856C022E9ED417BE6F097328E22717AD8A4976A855FC1
+5B8CDCB66FCAD6E6D87021578F2A3D93CBA708390E849C1A96E234EB91F54F53299529BF
+1BD1DC11722FB9DB27C98F2FB05D62DA1B7EA32CFEA033EF7C1C47B3FFCFD9A4BCBAEE4D
+66C94E8488D397644A2735E9AC8E0A5B4C61504D43D85B27026F15059B0717A0E9C2A893
+FD1A0C53815951FE68958615A581D9F1C22DDB219C3C7213F20C496AA0D04E9B3957F71F
+94A2A9E20FC1DE943A30D72E20E0DC0AD7D974164656FFA36F1940909464CA435D47546F
+4E74ACC7817BB6842CF97FF285E4EABC7CFFC7A314983AD5DE3FA821AEBA7E95252B0524
+D423F8FE71FC1E4D8883876DAB19415FF39A330D8F1F2E9E728F2D47EA05397F8F6D4A17
+7BE4BE649DB34CD403FE663509DB51FA3DBB4F3DBF4C969DDE8E18CC54AEFDBB23E286F3
+EF0AD94165558C2E1E91854A7B2D547735A3BF9A4AD940C328709F99801FD5CE9EB34C2C
+394BC530B2F79D6EB01FB151A20C03F64A76D6018699B09BABE16CCCFC516FE46A906633
+26E06B7BA28EE26134B52B96696BBA8A235103E8516FEDF892039A768C632C39CEDB3AAC
+19D71D351AE1DBDC46ADA5D3D547084243A87FECF11DD3A99C79E08A17969322C177544A
+A0A79990D1C52BDE6777A77DE02D9E9192A6D06D4B1D2FA19A95D1EB5B2F700A3D76D383
+D6D8E68D85759C829BA020BEA26587350B8BB4A22BB437999F0207B51E3C29508CE76AD0
+CF2FDDE225F0A1C2437E8607CD180CCE7A4975A535A9F1AE496A3A7D83A276C67BAA1981
+66BD3AACFA8CF66632E6D18D256F878143ED7EC542D7C29F16B0CE96D65201519B1A1C6F
+941B4812CE4597C92727C2B1E3D41AB59F3B026C32230374B012491D5DC66E20871B0EFA
+4A1989D8AB26B772A7BE6002E4FB4AF7F5DD5B0639FB0E59349A6AD7522240F19DEFAC33
+D0FD050E565E36E87C5CBF0D924A3EC16BCB31277F53770CDC95254C0B9DF1CBEA0D4386
+299D005AC2C1B4985DED85978FA75596D95488F9A16F77CD6572064B658D6FBB7F765CC3
+18C1032AB570E04589F6B56A67E0DA0D485062899BBB0E760E649B0485B13F76922AFF97
+59BF4651ABD8AE83EAB7544A2CF451E9BB18F0C4EEB431D46B65CC1B9049F243FE740FB0
+276059C3A80EAC689D5A511399334BBEFEE83FE0138D3F46FDE381EA63DD0A5AC4E36754
+BA7AC6784CF3A1428945483EC5DF805B846C2C758EEC2DF8A63B55EB7FC0762080071E10
+EEDAE6674E5539B69A6335C68F1FC10BF1F41157D082CB9376292CDD4362F14185D87F50
+369E7B562DD7F75DCBC86A5E8187192B61E3EC233F9E26230855498C1A580470CC20E233
+C8215A825640A89D8E21E4FC2A4EC8CE44778B4C96B217C0CDB6D2645FD5E4DC24D293C3
+84512BDF80C6B99FE14E429AB9C08E7AB2D752F44C1E826E91DF652505F6C84F050707B7
+9E222C6861D5302739CF4561C0A5FF82CCF7E7BB2B3F23360B8B0AFE8D3A272F6EAEB35F
+5419938DA96A1EF1FB50DEFDB9C9895BAA791556F51D3BFDC373AC0FEE03560918977CB7
+851EDC56750C708883149FA8D939B5BC7F7035ED3E2F2CE7295765C0BC09FA3E18D350C9
+9B40E2810C1FD915C2AF3AF93855AEA12DBA06896A51C9B2443E2D9A9068FC76E353699C
+B8A782C2126D7947101849809294F5763E150498F31BFE1D5D8AF704BB59176DA3DF2CF9
+0013ECB8E30250E5AF4152D892F4BE558D140613936DF6F9D43629B1594FBBA870B0FE5D
+1BC168BC183C60BA2ACB3C9BE52F853AD4FC1B009801ADC0FB070C65084ECD3165874E91
+4915B5F188E4CC3BC03240CBE3224662D2B3AB7B3E177E6ED05C7EDC0E96600FF6527A4F
+2A63179E47E74DD67A4D11BB1954DD479D7B66FA38BCBC85411B841D963417853482EDC6
+0753CBD2E0B0EA725170E33CF7B7F801BB348538360EF54A01CEB35AD465CFAF5ECA3EA0
+CE3DA1240E1C94A7F88375ABC46AFB407FED5EDBFDD79AF542956435D271EA685D9E8474
+ADBB88246355C959AE1408A5C4E9209FEF36253B0EA5DF070DF4BB364FFA3386A7FDA80C
+046EE0F54552D258C3BF0C964718077914D4A43854FEB495FC4D421C2939978770ABD337
+3160C7D8C9D81F1F3ECF40D24885AD5F26805DFAFFBE9661031313540B02E71E1B9676F1
+5DA9BC5311178BE39B0FB98F3D7F1064B7E76FE3A15315E234C712AF8542E4E1CA1BC2E0
+8AE69382A34FAEFA2E0F67A6B62144B0C767A45C5DB57648171D43E8E07611E04E230C15
+5A16B786236833B51833EA22321EE4A3B2E273EA7D452957438428BBBBA25E31A5332106
+54AAB61F2302CE54F7B2A0128327D60ECDDE0E455FA05B16747F75D9A27638A174482ED5
+DD91C796158D9A20FB380971BC4E30FF0BC9B9556B4B53085044044AB9418C2144087A39
+3FF2988DAC87F5B872684A327B30E362978BB4903DE7A4C3967F62712B8EA2221CFE4BC8
+72E0EB73E63A06844ECC468DD8C9D2D774C3332553B9FFE6143545F214E3DCC512E15990
+9EA880363696C962E6912D26FEF0618B88BD1587CA13C3A82A423F19CF9347D55D005380
+3B1B91B352177813C3E20C5F04AB4B9A2AA11CD39E11125CEAC385C25299DE0B617D81AD
+8091CE925DBF4675E7D70A515B83800F1115762A7E964FCAE0C61BEFEAE27CD77E39153B
+DAA1C87FBAC70011B9A0F62A838A8122903AC09A39E53F56935778804BF3D025F664A9C4
+3E314ED0673FEA3ED9857079FC6A49A8B77617014A7054017601B5C6E75C8CD05F89C2DF
+D8ED46914521C2D972BBE86480177A3A2B2DD174C77BE7FC9E0069568B392C124774A1D8
+DED4DB00F17024B55A5048A4F33C6EC5B0BB43EE3AAB650D9BE28160D4C0F128BE5FA21A
+A29DC060CBDABAD9BDD6CE0B5A4B2051E038794AEA31C482C2B5586320652D940FC3D6A8
+012EBE0EABD7BC1491162F8FC1C40D07B904B5758515C1286DE71562A790E8A86B6D626D
+6327F9C7EE4EAEF270D5A6081025B95DBB7F57C33B819CD417850311E3CA2899703649A2
+623255DF77C213A59602CB749F49A381C6101D27D7975ECB414D601B1F893AB8B8159410
+E92550514FE10C04C2D218C7B8EFAB3A007816C50B3CB724411558E8DC8520908C205239
+501DB6FF5B5CE1767C7EFAACE931987BE0797361B3565571F440FE447A168AB3360C3E36
+1E6DCF8F6482885ADEEED01DFA23F47C6B44E6268DAA6962225B10D37E57E20D9C55376B
+9D6A880A90D535F91D3893FC09B5409F2D2A428BBBEF2D9DC4686BFF8A863A6CCAE5FCBC
+5090B2B9841AD3205B0EFBFF72AABED459118C799C6B281B64500243BCF11D5531BB74F8
+A7F676670EA1342A41AC8FBCAF459C9D11D5673A0592AFF53ACD4B94904F7FB3759C59A2
+A7E5FC2126ABFB56535D0A6240CDB83223EDE4371D910931D7994AE05CDC24FD81FE8126
+5E40835FCED262A0DEE35F705E0668983D65A8CE7DB1177CA8B7BE0A73A99D4D3C44F401
+DD6CC8CC119FC36438F18A924D6DE1C2040D2BAFE336277A751D6D4D05A828AB3FB8BD48
+A7DE7C166360788AC8DD81662727B330D860166B2AE789181E4231B5AA3A205663024162
+C053F2213D30B5102B3C430F9B67E3FCE64FBA1BB617DE61D2A64FECEF8B6BE7D4074E75
+DD4AA701474CB17982EC4203E1754A19DE41874EE1818BD4F243869BEA6422CDAD1FDE4A
+84A1410C9BC92A32525D6DC52EF3E90F5829CEA418542FCA02FDA62666386F628543CB04
+D08188E6B9B0092E6D00C6C75C5CA9436AD0597C741D4B2C63E585470994B5466C509B0F
+D077B49D87DD6BBEAC8C6C4197B9C0789025B49BDD9534F42CCF987DF9B04B18D19F9343
+A91696E0E206F4DBDEB45D6D7697B49C4FF5584800CB512611EEC8415BFE1983BA96BB82
+3AC3E496D9D79C6426B97A1455E070695A27E407CCFCE7472F147EC95134B89BFFB87146
+982FB4756612EE55A782F303B54670333FC04E707FCB84D255B05D52AFAE8F473E8C4FF1
+F6E95EC1B820ACD2D3E980A1B778C4568693AFD446C6E416C48A45CBAD61564329C4ECB3
+A98B4ECFB3551D1F1C03717D29A5DB62C8F1B21D036714A94CE536D0E84E3E10800AB513
+91E05C62F2A9FFEB3A738E3262E1919FDF43EF49842F6EE5D309FDFFA0B74FF64262AB5E
+813C8042B2F450A5CF7B547A8383039E7C14567EAFCE9644DAB0A54249EDCF4C24EFEF7B
+B3EF129DF5A11E12A78FEBA6080680AF4476F4C0AFF6E8B27B07D6EBBF5B1FEB28341344
+3154B99A65CFE335224F382137E3AC87777A6719AC1CA6832B61AE8CD6A1931105707F0A
+DDA25615B526EA2543F6FAFD00D70E4091B6D5D58C9CD62B19C70D7469F6FDCABAE2A517
+66C9B0DB0AB351973A4E2FDFF81DB1651DEDB905ACC447FAB2B2803E90DF264C96092528
+8211E23246BF45FD1AC67983A7FD5B371581B8BED06B9CF8E6AA6C4BC84771219E7404B5
+6DCD474D9B859D1891FC2231869763E6B8F0615D7AE7B83260DE84BA39D6D60F50BA70A9
+EA8FAC771A0F0A745932D00C1328806D938CAE671B94EEFF484E5FBE9A74A97CAD47358E
+A3CE9F399407407FC199677DD7BB6B7B9B00AAE6EA1633EE18DDBD40FEFD138F8423B304
+4B9E9AB192B7C767D7D63AAC804F0D5309E0FE72A8259BF12DBE7A215B8FC8460C285C4E
+26067E3C558163C1622617B082C6FC941F8563CF4ABECD0DBF79CD5DD86B492E3C46D0DA
+BD16AC96ECD6B41212431FECB4EF59DC7DD3071CE030BD5DE690BCDDEA9A2594C50CF77D
+53B223EEA513B40CEC7005C4F6B6DE2D3680EAFFB6FBE0DE70E7DB5C11F2BD4085C123A4
+73E5CA0785FE70E38E081B5971D4C390A87CF5DD83C8BD63C4307D22A1680792E27FC431
+8D403102A052645B4AAA9BEEE578CA28E2C15DFE12134BCCB2171C15A45C5D4D8ACC0EE4
+A2C8AF801D64D5979E52AC410A69277160104A386D747814F0DC0C178CCC2BB40E175992
+9D3F05ED411630ADFB8E4E57CD223E012F457A8A7C2BEF27BDFD41D3B39673ACEB92A48C
+E3464A8720196A60E21C1736066FD19154C02D7BC22E821C76F4B89185FA39B48B00BB85
+AE14236DFF7E1EE1466C65A1B4B9453D8ACF727CDC0EA04D85E2A4F41976E4833C145444
+B0465FBCF96BEA9554304FBFBA4C39ED11F2E1D9588EAC200B31441889B081775BF75B6D
+7AA3055C85ACFD57DCBDDC12257F565F1980DA3215AB29A2545B2FEB107C91A454DD3C32
+D7D620943472E7AEB5805E64EE7B1D3582A2DD74D439AF03C00478FC35EC9017F1A37B59
+A31A196CFBC38B4921A76E41E3A6E2C0E5059FC3848DEBAA378D87736B01C6710B5B0DAE
+FB06D00BE44EE7C687DBF6CBAE699D88694891A95392324C6C49595C7113FD6D521A182E
+FDB264432F3B661D4E86766A7DCA2E53F72F7FB78A0C436DF0D516EED141D796F3591226
+E617BAE549DFFAC4CFA0F555DF7DFAA525DA35DB699A892B09E654992F99F89CED6273C5
+9EB9C512BFA0465E61FDE63D312B1B2758E645893A19C82A81E5E0F5AE8E51621EAB69A4
+1D425F9F78B47ED5CEC857DA012E641D5C203532691F9177F4531EAE8E6A7D5A2B1B374B
+B921CA70F41E7F32A8D83C54AE01DC76C88A96C1403FEB6942029A86B1306AB096F8A42C
+2D7FE35C7E9F3DD494579CEF39755AAF7C74909CF5F7322C4FFB2C5A196658B7AB49056A
+E3DCABCDFE40DB0912B5E15BBAE08B72D7AFA7D64265F4185401E6E723E151EACB8C7494
+819998FDEE918EE491E4F9D5F889378256F2F7858762A5E049A618ADF34DB73540486414
+1187E3CCF635097AFEE95F695F806BA1419D85C50FA033E4E9FCC155849677B3A20F6451
+D8E4E5AB1BFBD967B5F53C21A30EDF1286A0E19FC557598294586D5184D1CDF8BC83594E
+17333A522E32233DAA8A6EB39A6330013C32A2E74F0EB6234B63D47A4C8D21E1618E5906
+5EB21FA9A926E01A78A60FBD71808A0B75F65786A9E3E08488FE89E433C287DED44763E4
+F317DAE0709D7D54EA969B751F4C62AC976693FCD366804E66B2BA8D955945B86D492E74
+F17C0484FA5C45D7F60DB0D4578C5725A88A9DEF8E5D31EA02411CAF6F703AF96F50FBBE
+6739B57D4C1C318FE7D491C94565DEBC43078303D329E87078EF9B48D66C3E98ACCFEDC0
+A31761AF6854E5C4DAD36C809876D93C06D91416770CE8852B5E54AA22F6EF1A5BAD532B
+E4F55FE7E2AB457F3242030F443975DFB0F2CDCDC1BFE629C8BAE7AF2D21C9BEB3EA10CD
+E4EAC54AC081CD3C0AA161C52BFAC3A9E4F0FF77563D6FDDE73E44E926E1BDFAB4B1A11E
+2B4A7E1D2CF9D6B9DE48D99DF99E0DA53F5A449B344AB2ABFB94BE9E60E6E9B328B58337
+A4D4BD60CBCE14C364A2A1D5C02410C2E8A98CFF3A48D23C752413A4FCCC5C044AC99451
+20B15B31CC5C7B5FC6D80866C1110B45F9B274326656CE6D74F3481B7D5DE8E5AA907509
+C15914FD27CE89F911641DFD588812A8292504EBDA5645E8C510F5E88EF44C573CE46D01
+EFBC6E3E1BE9600D77210B10330748F210F2CEE4841940A78AE1352654139757283F0FE8
+12040846B6B24F1D96EA06CEDF19F0E3359C8B30C3986C2E20F5801C7F74ACA621E8C4B2
+4C38B9888AE24013371F19C80165522AC90C40832C71E617E042ABFA071BAC4D87D91F86
+4209F5073D3E54A26FC2FC8F89DE3C1B121881665D48339FD2FE7B0ABEF5491941DD26D2
+B379900687DC8DAF6E35153F409DD58DA91742E93CFAFD431EDB7A32FF814048DCEF7459
+830CFFFCF958160B1B54525EFC46D8892C30561D0D7780625B0876D816A0099AF1EAE992
+AAB126289D55638559BBAF487E1A9E2F118B3D498C49767B28FA680BAE464632C94435FA
+E32836F8093885A91F66CD5070B91558616853AB410AABF0DABCC02BB85344751A2B2911
+3847CBEDA65616487A853D9104D0E00012F179EEB06D9EC54CB50DCEE655CDEE79F89318
+F8212779CC310304A2F604402C8EB99DEDB3051CD1EC0D03309EBDB8C3B5A89E06C49957
+5E00904DA0106F87D58FAEEB8581EB47E982E29C5ABEEC747205A33C7B05A0CED74C3403
+0012BB647B5AB617AC8508E8A0F254E102406EF1EA86DC39CD9335FC8A5CCB1504757BC3
+AC11BCBE92800AED15E84FC3A6FD8BC6C27C4A13AD946DBC65E45B3C1F72D4D2C1793512
+9CAF2C6C238F1E57F428CA2CA51ED139015DD06B931A9FD41A8A759142F50D4A18D9E071
+3CC7607EF0337C7B401CC2E47F0DDE63B32BC1DF572F94991D1BF97F1BC17DCFAB95A834
+E34652C6BD93277754DBBB1DBAB6F0158CBB6E9304F9A1B5DBB370C3EEF6A0F937A0C7BF
+789CBB57E308D2D3EC0A0F04BC3BAC016AE4CFEFD4A5F5FF9F2289460CC7E6FF27A7B421
+BA3BA86F2A48C2002C4C0379D90B50952B6A629ABEC22143A906752E0BB2DA15C36EF74E
+DB102D691DECF27A7C252D866640FE74BB7BD351C4DB5C8E4956FD73CD6675FC53DCAFE2
+256AC5E46FEF1D0044B5A347682FAF71ED9CC08F231605BC342148E3CAD6A80ACEECC89F
+767E814046DE67F5277CD737D09A62B499DFF7908242C6E5F17987573334AC66ABEE66D6
+1C61D14C3687DBEAA7BE38D248A7B8CC775C5B577305C3F41BAF7C7D64B43E7326133C2E
+795F50EF42EB3F5817277E2690C8785064AB6BC61AB04F578549BF671D88E113DC704764
+91AC7787C2561DF6AE9F3BA5FA24F5F2C49B8B72833D030536BCF0AF10592FF37E223065
+ED6F4BF075F70A7D0ABA84CA427CCACF9A0CFE46A429FA64597C677C71A231C997AF401D
+07FD7FD98F4A5826DAEC4D76B2E6A8DF68AB8EF09A0A6BD0097840364FBBBD4B93950A16
+CD68B07CDCE7C341AB8647A3338B1608D67CEA47D26EB1ACC0F94D928F2930C2CBEA594E
+B773548213CF17642DF03784B9293BBB8BAB745893C2CA0F9450A337E448A282A285867E
+0B0A2F5DD49A23D475709131946B03E8C2F7B2D21DD7F1EE583B22A73D81E5F72136802F
+D917750E53E63031FFBA218DAF8B3DBEC561581706AED8A5CFB6593F5CC98BABB048587E
+C9EE27EC04859B6C233474BA9FA8F8D909B17705C6F2BA0CEF169B46497E712C458354F9
+F0E1B72581F18BF74AE06CEEE0DC27FA684432625C579A29843D44973D4BCA13998DBEC3
+0375F1C05CCA91819C3F7C7F2A240B515AAA8403230F9367CF391F3538ED5BD391E70F24
+51B6CA9F969CCCBB58A05FB86E90BA4FDDAEDDA84A73CD40617486DF08FE7985A55F77A6
+B2CF450665F98F0D173D0DFA608A4E89CA6B7CF2F86134CA0B97FE3FA0856613C7E71D9A
+4389BEBE6C1DDF23A7D617ECF980EB78AC5FE99665CEBDF1BB8C1CF29C345B94591CE29F
+3E77AC66C3A9A1FB34526A1F335E71FC1AB62B4E8237E80CAA0265FDD418322B068FD4AB
+0E603448CC61D57106F1BDDB5785AF5A18C211021FB6F91AEA6112BE9F34A75C6C428EE0
+8101FD9904EEF19996EDC2235F3CAE00B0FD20331597B63535D001A5A2951F4057C83A8C
+04EC71AF466EB9EE31CAE51F453423FC327FCC256D71D4E2D956538C16231BC8E6A54FB2
+85E7D5A967CCDA56DEE48109FA4776F87466F0F62355CA0990097B2BF7F947C0198F13F6
+EA5321370A9CDDD612DEB3C91766A19B4228AD5A4D782D9C51BD3DDF268D53C24F6E4543
+52B2780CC5906D6D08A27AC49043FC1ADBFC07ECC113D815AF2BB5922E42776ADBAFA1D8
+E8608AEDDDA45E181521E5A8C39BFB2E9E72A7342D641574D84AAE3D23F114E2C675E50E
+98C0C4D59107E15753F2E29B2EBAA4D40A0FCB785E0F20FE5EC3F4C42AF3445298625AD4
+656A42B95D3F3BA64495423BCE66806EAD119E6F949E5E0CB7D20D8B218FF77704BA5CCF
+C6B96CDE2E22E2A1866F80C103C986D01BD96F2207438F8132ADF46C5E889C2752458D26
+050C2D2D9996A7E90414880A34BF4F6F7EA862ACC40E6446C8C64BA66314493C05D5552B
+FFD967B26CAFB3238DFB04A14757FCF34B547F81448D5BE2C385775093FA69D2B5264954
+7552C28488251224E4571A0537F87370D575C6093047374077BCDD8315E40EADF2ED65B2
+9BE930D5A78E0E4F21ECB50582FE1501FF48EC392D1717D5037175395D726475E79B5EA6
+68150DA75B9FA24A530FEA3EB4D2E4D73A66C800452FA1053CCEFD77046B058693170362
+AA4EBD8C51C334C4C24AE69086BA5A9AB3E8540E0AC782324DF007DA127A7CC2EAAB55D7
+33201140FA9B632F11D41030ACEDF37F12D4E4801645CE624BA973671E41C1A11169592D
+CC529462D2047E2A5D06FE543E5471D0A0FB591A9D3568D2B642C2DAF22BFAF136DC1635
+11611AE38717F04BCE872368BA82FF9256AAB0AAE93D52A286FC62802FFE2E8FF98414AD
+A2E28D0C07D95FE5C9B025A9AAD8A355710C6085D45BCA501AFE400EE1F9B34545AECCE9
+8DF25A6C7330711288765392C4529746FACD974BD8CB996395FEB547A9D674F5E56D4841
+32A4B48D87A380C52E05C86083677D88696CD2CA221E676C8F950FEB61CC6CE37D055DDB
+83089B0814A90EA5B3EDF692055D7DE2208F5F5151667ADD999A0301E9D2A017634D3C5F
+8B645C726D0BEE71D4098E0739B44D565FF574FE93A250AAB0879413C38763AA3B294956
+BF0649C5495E92262A3EE9E3CDCEFD1DCED80221217ECCD09A04B2759C746D720C3E88E6
+22174A8E496228CE9BEB430557D8AC5A813670400BCF93AEE40CFC554A933EEABB239B80
+EE603F1617B3238E4EAF043699EC674D348997BD3105B8EFCD06E55F78AEA6AFE81EF9EC
+836F4703650D803CD01DC38094F11CFF0B34734308908ED646E5B37BB9524C886DF94F83
+B2D470752A139E6A06ADAEB559E3D5A1F4EEB78F896AAE3D9836D4C7D4576877307821A0
+DCBC61D1318B937ADB53865F9F9B6B90659DC518108B81196CB6E81D676B1EAAF9B0F3F6
+FB499A99BCC7169E7F37E9808634E2A0CA9DF40F204F86FCD7BD135D177ADF005B5D9D9A
+0690DAE940905664994FCA90777CB9B3C4591FC0881FD146A41E9EBE7B8F74DD407642F4
+5BD399C6EF5471E987E01A009F532C2E66305C890B0B582824B527ADEDF668456AF3776E
+4634332C59C3133D8581D47EF6B45B636422CB5FA0B117FE1AE0361B93CAD6850624F353
+FD41296FE84391636A2EF92A3658E07B857DA4FC19889E760494957276BFF9543FEC23E5
+2A7C9174B581D299B52DD03AE726A95634C8BAC12F17B80B3B40BF98BE848CC4837C3CFE
+FE2E3B64B5A8BDE695ED0BA15451AFC5F0576DB1E9E9F29F05D4DD02EC3AE44E15171CC5
+EC254176D86C83C062B7206966E7F0A8822816251C0AC4A746F661897E24D2A44AAE93E1
+259A4C582FA34DBD0B4952CEBD2753EDFCC37ED685FA00E67C455D03072C2A218647B582
+F58270B59936EFFE692E0F27DF5D73AEB8D2CE0970629D51B9EB91C0D2712CC3BC71640E
+9ECA1D662FFA06E071D1E013695854792DDD672080A0AA42657C9664D6D850757DDBB167
+9FF6A837674A5DBF38B2A435C2AE04EB86D351FA0CB82F0D5F00A96D55976B44D6B6BF5A
+75346A8CD71230B6A44268B73188A84C47F09EFD13CBEB51CCF7ECDE43A3BEC6933643A6
+68B023344E407CB2A6055EBD6E75A27B6FFEFBD095828A8C5B9A14FD78AF99BFCDFB0A27
+3313455D19B2036304167E9F8264FE47E1F5AC04EC94FFB3E1D6C90E1758758D2E811C7F
+DF1EB0AF24EF89E907484BD07B8D825B98D99AEDF1FE0D67FC98A0159DD6492503B86C35
+FDBFA654E3CF4B00D0E4E50A77BAFC6D4CD69A668AB5D0436E9A2DA573E04EF308A6A928
+29F21A8419FF3B7689590D3787B3CDAC9B6A98FC0AC7B06DA9748F5765A25708C3E9DEB4
+1DF4EFD5BD9E0C1090BA956EB65087F5FA803CE15BD0FB4090EA9DA33F86512A67CF8775
+BA3C3D834FA4D6798CBE5D5439279DD0EE083DE2026B2EFE83C203C632193D30D390443F
+A5D1D1288C2B7395BF91F3FA657BDD688A562EBBA50DF28EA5834DC1F9CE073B704D2DD8
+594620A53DA722209A6C4A9A906B552B562917A86373C43132B5997CCDFCFA398C35EAB2
+D275883CF4C5AF773B535BBA0CACB12ADBD2B3407C8F046F1D4F391EADA619AA2DB788A1
+93B7F6975889D7676AFB6EA09978E9590E75F7B106112D0B62063A21DC59110EA5E123A6
+51F2BB21FBD6C80083E5B3405835F9AB6DE5A7C579F8F7B006983B897E4C9224BA21EF0C
+DB8546D2F477D280F554F98AABF7F6D7E890B327129F4D43E3BE119D1E9B1D42FA1A7F39
+0941803CC1752DF5A9198AC5AFC71DD6402095EE312A89D1466307F0353A610881A56891
+4EAF39DB13B984A78C1B9EF169EF8781DE0BE7B20698502E8F81BFC06DBF766B3CE28A43
+4801EB4FE9703BA5933AC6F0872CFFCDDADF1135D02714C30D5F54D36DF3415F416D66A7
+EA918A64E00AF9213CF9CFC63B200BBB4402E53DD95BC8B5AAC20E62964AA87173563396
+AFDEF06AC069AFBB08D6600AA3A61C23682551F73B2B7E4DD70392464C439FA6CEE41A1B
+4EC280388A8DF86195788A9B766DCB0E1AD6AB7A1C66A1835D7AAA8FC92741104C6A5553
+C149A5BEB648BD3488C13494D9661FC8F9DD431E9EC1989CA9B35E67A2BC9FED7BC3E362
+6389B29B863DC77F8ED314B47B4B86C9E559A6E41366D47672D9E9314B192833D3752C70
+3A571CF80D6F165C660F42F58DB5CEF453943C7DD0D252476F678E44C6340B7E4D52C927
+5855FEA030BB191D34FBF80C039955C2AC6F0C38F6FFE281A52F13B62543DF45BBDEEC7B
+A2CC3A125963D1524EFF639AFD013A472B336E43E9256C3EBC5910A05F641EA1ECB98857
+FDF7613E9A3790F9FBE16F8B1E9CAC2829EC0B651F00E1B6B56F0025ED82BFC5FE1D227E
+3DC00ED525823F310A834A747ED0FB5F5DAB7EAB307D0906AECE8AEDC3808C53C3C9E954
+6771D79028ED61CE595EACA42B6ACB8C47B1417F1E88391C0CE35415C9FB29106F8EFF96
+82843119AF94F798D7079D40F21B94BB3061C2155A87075846A62B1E1292B465E946AE00
+A3EA7C2057244AC8C4D54A8618AD7B06A833E9C26BD2BF4A40CFC7F7D780DF4C31B0CBE7
+0657FBF4AEED88152E1FCA2956141559002CEA98E7299FD83BC9BF9CA0523697D9E188AB
+2D883665C329A8A4803C8E66072DA31E615FF9254BA8CD94A5C6CA0EE7AAFF3108F48D79
+0523D58E98803CE03FC53E71DF394691240284E210C77595F292696975A206A43AA7FC7E
+C0CEF778307863F56016C13EA6A26299FF417E0668692ABCD895E7CAF13A9C1BEE2B1E62
+0DF960006550CBCFCBBB006257051D7254425C49F840B8EE5A44A61E5AF465A3A831FC26
+A8A2062943955676AC4D5168EE2464067C056B1DCE6FE780108953F9FAFB6F89DC775E63
+6E3EBD3308468ED7B31CCB4D80142AE342D630B919584B2DD67E904A48C5CEEB65C1C84D
+8D2964A4842E8C2A83129C91662137BE032B007A30A0A4D2B31ED3B1F44AD5275FF105BA
+929ADE2B78FBE0F3F34E2E9A35568D96214AC1A347510E8E5EF0C9CCF08798C5B0C09DC7
+3FE817E2BD84AF14627A8210099509770C680C327ED697A255B28E81DF6B512060D47084
+B8AC21EF59C34AA36A9D14A093116EADC45F3F64AB297E114053081C8D6B135B36D25AF7
+7F2050648799554FE6BB50CB6E957E26A0C62788EB76901B438AA6422118463BCE7AB3F8
+C21E007C21A9434A0294650543B58F0925F664585BC875ACBFCF44F5BED0D8AFB0D8FD6E
+215A03ECB350DA054FE30172E920C34E64AC011A655F5A782178DCB3F65FEFE0CAA68993
+DF30FAA2471396F6D74213C38A511773DC7E84A9831C2E8C4B51EFE3D8DD0674050B8DBC
+F1E09ECA5BBCAB73780ACB37D46742594C6070EDC7F5C555FD50044208F6A26316F17B25
+1DDCC694443233702745485F3CA188CD3E1F833C99ED46EE525D31C6518A86B723E890CF
+DE3A834170507C9F24F28A124DDC734BE002039E81148D73F8C86918DE78E07964001EFD
+9A3EE31A0347EC258360D2CA6AEBE7EC4D5FE0A29D415DD78A13B8CB8DA84AC8E480FD48
+F4A9440EABFD6A1C4988A7D6FA7146CBC14FAEB8864C578A81D86C61C0D08AE6D50F5654
+DDCBD02D7D9D9AAA56C417D2A3C42AE47ED81350FF917E7D5D390D4BC8AB934353D902AD
+98BBAE982ECABC933FD33310FEC3266BB373AF3B53D8880A8106253FA48D78899D0E6548
+A9EBCDED56B39BC0FA78BEA9A795BE60BD3D60C1DDF5375DE0800F1FD55AB46B49536F7B
+5986E790A4FFAB8B81B7CEA21980D0634E7B2CC00D1D7A9A7C00A5CBAF65476A714ACE77
+99795EBC2A944A688BC40F2A23DF71B3826654EA7646D2338BF23E216A8EA59AE50DF2E1
+D6A05A86C25EDA267225592F695FFCEC993CFAE93452BB3F2C17470552564F2AB70AAC50
+D49ECC01A418903401B4BC6F3E0D3DAA9CD062AA1A8B93016BC008924F8AA7075ABDC5E0
+01A215A63EC8A8F1FF0E7F5A1102D2D5DBEEDE248904EE28590A4E48C98B4E97DCA69479
+08FEBD5BD880AA737D2A600A71D1CC35B20612F656EF4C125ECF75DC0E1BDB57BB09BB26
+332CD1B9AD52147CDD30D03EAAD4EDF4C7C2E4092C409701BBC8EC163E4C660EB018B0C3
+4D4844EBB910E0566DF844ED250624A6C8BAC481B32024FD4EABA3D4E8A67F83FA4E4927
+A15D64462B3004F5610EB847E9413CE174D64908B0464A144DB43FA1FC8356FBBC00D303
+74E22B3EBB141575D6EA036CF0B469597C57AAAC00F840EDF201E57C0D84929A34108847
+E90C97352CA858A6B1F76E1C772C1DA2A8362D02EC7C112E8755C7D720AC5A2BC528913B
+37E0BDF15147DE30321647D8001FDCFA437709AF90ACF0E56196A9696C0054E67BC6630D
+7D99F3092D8DFEF0C788715D9BC43788542693045A485D5231D731EA740BE448DBB72ABC
+A34AA5B8B2A4EF6E91F61B0A8AD9666808888DD61A09CBF2FA30E812BF1B73EE2D387C6E
+4821DA27733C60795C8EA0E806F74601EB9F3676284A37ECE9495CB87015F18DFB39B9E2
+93303261BE268AA644CC7793A6266C026A06BFDC3074E7A67C8F6B35729CE40D6C343C4B
+95EB9C778F6D513CFAEBC5FBB8AC844D1982F300675B0920C098AB288D12423A3401B6BC
+CE7725E619706B6241BE210CE68A5B3F068C7255C6A0959CCD3AA40627230F27057001DF
+328A741F867833911AC3D24DBC1C79462012801A6E0897F2896AD1B5345F72BB639C799B
+FB4C6EFCC57760C82015F6855099EF7C5DE59C5766BC6DD4F4A61110E8CD93BDD891A83F
+D8DADC0AAF16032E8B02E69F1EF25EF7CA8C23815C38F7FEEC5E4A4F11BF1E0C2275FDE1
+B29CF45A585F47962E6137150F0AEAE31ABAE6DD3D66E54D8B7E6707445857348F6326A0
+9F403CAD72D93B038C91B7465347160DE4FB2F2F81B4BD24449CE03BA177C8E13B3D590E
+A6F4C5CE396D238C642BAD4C5BD4C0B2EC8B935BF9D9A85F64D867799103E285264A5F53
+CBD2E0B0D69176ED284676494369C38711ABCC23E61961F6B46C576B407D273EE84E274A
+E02EC5C8923ED2D5AE650450F5A1665CC148AA0FA6E26143BBAFA846E9263E49C9ABA1C9
+E4ACC9A7E6ED0865B42023F21A1F234F485C4F22B58925B336BF883906ECA1000F456773
+48250626716520CB2CA5DC9EED93F694A1CC6D7EE74CBDC660E3A033EEB0CCDADB32C5FE
+9F5A4BB9BE18F13A6CC678213E631916E283D5B12DD6B9926279CAAF46A469CC3D4EF950
+D701A667C2BFE15292FC3A2ED9E1C916B90C9E25606ABF91FE44BBF18CB230EAEF6B0C30
+3E94C24F82957557840C11F4845C7F2C49337CB588FB9791EF1C40D4CA00CD5254426E84
+391C265D4B21E9FA474843065E306BF794BF3F798505285246B906CA4F343743C5539EFF
+AFFF1F93CBC5DBCA989E64B2133EDC8DECB05FFE150469EC1433E3A3C0B49B7C14EF6069
+CCC488A1AC96C39203C010647ADC1BF32B69623D291608BBEEF2C5FDE603863C91029AE1
+B6287F8576F73922B5192BF1B226ADC2DD17D98B8D0558874DEBF7018C82A9E9AA9D89F7
+DE237D1DFDDE2BD43EFDCE2ADE67906EE2525A667883685DCF78BCBAE353486C96B3831F
+C1E1C7DF12DDB8CF10895DABD16A1DFA87AF1FDF8F4A6DF019395D713269024BA721CA02
+C1E2E605BED8AB8C822CC84903A7E5BA090900F1A409F4B1D30F740325E4995A5C9FFDAB
+1B8480D7B5B8CEE4F35206E13EC960650A2C1D0C4D7D7407A86E583EBA40267A67A8E87B
+19D41649DDEBD7A73593AF94C2366CCC6F81BE9558CCC90CE95060ABA2BB508467640E6A
+726ED96B571CE6F2AC68EC104D3C2D3AD54F8490DE638B77C93595E2B1A44B079F79B487
+B92C12B16B203F91DEC2E7183AE99D79DCE4BDE5B240767D52438DC5AED4ACC691683BB4
+3D2A1636C917B6E270F309D3B75D34FEBF8BA64B01FDDD848D52C30FFAEDE43EA21C9ECF
+487A31ACC1B1405E615C9DB6A9B96BC45114E20FAD0CCA71B410BB14A39997E9653FB11A
+666995E488B650EEA712FCA7206F5228061BD5BC385DAE9CF087449EF683F69F673F30C0
+33DDD590F086EDBC3A72F9B17F488E2B36A381141F355AA1AC81AD4C103101AF96259CE4
+30A0612CA3110A5953666DB362D982687010AB9B81A63256AF6E69AF6D8B3150FE860D29
+E0DE5D686096A3D523EB8CEB214DC73CDCF00D2E98BBC713C6D7883AFFA02188A5E8A8C1
+007EEE1B185AF14BF0D0E06BB144660A5891C8C7710B2B85CED49F14A5D5B028A8FB6464
+3CB3B42D1EC8C334D51A270A3A2D483B223C3D95C733D79A9EACD97F7BB32D28BB381D40
+399F0B9BF194521F189D37040DAFDC8723BF45FAD60D2527503894BCD4B0B746734915F4
+F5B04D4E5044631F40BC3758DCBBB2A2AB63D7B44EEED53991AFD2988E13A7A6C389641B
+32819144DA32DDB3ED45873E6BA0604A9E682558C0BA2B139D29E4986037AD326BDF4079
+B6C071DC3607D52DA49F6BF8DCEF6F04C4AB860D660BC30E758518E16102642A190F89BF
+D0078394DACB5052E74EFEDA5BC176A861D8C5D78C83A46B4D5230786068F12BCFE1E73E
+4F7865D5B86144B26AA5490F229E6FF7CC5964AEB6631B08E2A4EBFCCEA10488CABAF2D1
+576155E6C862855CCF52C74834BE25DFABC0BC4FB7A1EA21B2AAAAE45D1455D844C6AC2C
+C57D081149F6E40B1FE620B697424B85A7177F19BC63E93975A08CF009C4659EF47A3680
+488C43751FCD7D848FF55C472F02029253403CB04872EA4364DEE69934F6D049113FEBC0
+E3E5D978CB8A2423B9910E3901981DAB495C4F323C3E3036BA45B66BCEFB4DB5C7AE91B1
+7A4A956471BC552A1C109EF67D97069D3DD5663063262FF4270CEC1079BC4C4C2AF643C4
+FE0B5F3B39389C104D40B84035710A59AB041F67B5FE2E5D3CA3E720D1C7A3F104A74C05
+DAFEDF29777AD6FAFCEA4854B864DDFC878DAB7C42CE153FA01857AC1D5B1990EB73C82B
+A01D3557E10D14742444761671084F1242C9D2EE9E211465F5F8F0333C77B123D6C03A92
+D0D8B91822D6E20DAD190F4D7A1FB12418D6FE63A2B1148CBE94328ACB42845E27928643
+444C3378FBBA83ADF56A3DF9ACF9C1F2A8F3F2F3814E26D9DE7494E2F709A57E373A594E
+4F64FDFDA6BC3866E3F7BF58127F6337165826F3D20DCB22EE9D7DE5CC14D10DD3BEF093
+2B0D75E289E5A332700C2CC5EDC65CC61C592E19144A13A38E24B1FFF7F904CE261FB76A
+31DE7360290C8B750D92E08A25DCBF3BE97529DD52F004AD59C6721FEF0EA46F1693C5D0
+992C517536B390C86F5E788995B35B6311E6EED72D15594717CF385DF042F8515455E808
+C54A0155E58D4277FFFE04CF0C16E1259F39E84292F592BF936FD50BE54ECAB54BD27CDC
+4AFD246C35D901882765CFA13A381A4F888462CA5A775DBFCF37B864AADD8796ECB2E13B
+4156BDA78E6E7308F3CA382B478A60C441B09483E6CCBD51E02E5664E8DEC087AAC030D1
+431A2301C1034BFE73EBB7F2744F689D09F424F22A48960C991526F7063B78EE26D0F997
+B917DBE51D7D291F54F1C22D3E9F9B8472CED7317B6E91F4BFD2E3623D6F3FD2401BA7CD
+6F93918D2D629AB72C4060B6E72AAA295F0EAD79B0A7C651D5A9FE6348EFC9396664557C
+0D5688F01962E8526CE7A55866CD56847F49BD43A674D6C22EA7EAC1A4D437D2A9BCFA53
+5361CD640DFE5189DEC2AF088359B13C6AE7027EA51DD1E757DFDA89A9BC23BBC1138839
+C549FEA71E42F497440214911982F115D3A9278D2119E0A17F0BB1F8A86B7A776C3EB940
+8819B2602C66C523FE07DC9AEB0E6D4AB6F39A308A6E8F755CFA0F41796159FC55B3A083
+F28494B4C0FC25322D17E6083E79394BA1F444CF84E5DD9D9721121277CAA3E0E380A7BF
+93C2335695E2F34D05CC3C3FA3322A7C863A16A9A5AD4BF1C629BEBFC20FE361AA2C6CC4
+C0D3EAB00097D9D2344B8772B049CF951DCDB1C23C138B2D7DA551A22A53EA2F604D7BDE
+8AB2D034ADB57A65DCA8CB55AC778F9649BBBAF8E7223096CDB9780455268FB9CD379AF1
+DDECC2F7C22A25683BA56EC7AC869150810D8A6A5B854A78DDA6C21C9FDBA227E26809CE
+FD44A8E4593DFA5B9D170A19B9DC779F507FA0B28B5C8E3AC017005FDC519E8CB69B9385
+760AE1A8A111E763FB0C3B083BE1F083AA14DF9CC83142A1DFEE5312097BCD8DDD91F113
+0A3B920FEC7E9383B23F7A396BDF28BD1EBB48934BC490D133D594021C256B698BC4E93D
+1E746522E485DD53C1B7980EDF066F7C7FF9F27FEC20ADDD1FEB09CFC81F2B0E0820B90F
+FB40B66CEA152312DC5E7F8CF45AA0B45636859EA9DA112F76B714CD83CE2803D3BDBBC0
+A3FD5EAA7609A1E4A82DA08701A3AC0818DAD502DECE3A5C7D9B5D6DA50F8535AA1C3C91
+A9358EEBDDBDD94AAF1DDE610E9036E1D5E1F180D426A8B33B4E640BE49073C4B0C0639B
+0A28D6E08D76DCFA2F4B409EA1EFF27437809073F29FED0E64506185022EB0A5F9A54BCF
+ACB0F2BDD859222546338939F73C212749C36D6B0E9AF72EBD059C3838FAC738DFAA69B4
+FA87CFF491D877DFBAD90222DFE9564CDA37E5576BD66F635720F398EB6863C5143FDF5D
+A4F07317547B86C5B335CE05755AAEEAA8A927933B252E82BEF3DE30DFDAC82D1354CB63
+028B03BF59AE93FF30771BC27B186C7A9F7AFA7525F719EC5EFAF2526524BAA29793D5ED
+C1003A42ADC2A344D0E4210254F2DD33AC58649887FED4080AF18554646C01BF9BC54959
+D0C06E459CD818580444E37BD2852F44C8D6FA18F7DB6FC15174524EFDD0BC9867832DB2
+F837374BB8C9031A27B17A386E6D00BA61D49003665E1231D79E05EFF440E48FAEC9CCC3
+5985299B3FA94586B516C2317B1AC9C91005994A84466514D7EBD12AB998D4D99BA37C73
+EE3C723217B4D9BD5A0AAB12760886A8A99A4AAF038EE5626035CAAB42C6AD08EAD6CD2F
+0FCF85C2CE2D6150A559250140D19610DDABB115D625C17455F928B55F762028E49E4769
+872B96F84031DA85ADE6F18D601F6D576C9CB68B8FF011B13DA0DDE4D6E35E5A3E6EEB73
+248161764FB3B122A4F40ACC83CFC073D4657C042248684EAC14C56615AB156BD549C964
+C8E5A5DD901BA9B583B4D176FAACDE48BA78601EC7BBDF45AC7319F7598A93B68088BC1F
+B6B4F429609FDAAF3235BFEDF0AB25B6D2BC024B533E6E300165ADBE42C890F17B9FFF6E
+45B5BAA3A14FB36D26E7DE60CE24F4893BE0E2CC7A780BEB1EAE0C6AA0EDCC3BF991E5B9
+A6F98F5F5428AFE21113C1D8DA34783DC47969B9669EC1F97EFD43FAAF5C02FDB722840C
+108CBFEAC5E0BE99AB3E21CE4E622DFDF8C32250C10D68EB0B6788E5269479CC441B32AC
+1FBFC5660164E498713F6A2809F1BFDD79E8340EBB90481932706B378FE8DE987D5BFA1C
+B688817968E797903E558F8C7D0DEADA0B5F08D3D9D27C92E4DBE0F123261737DA41C264
+E59CBA14C0F60459CA59AC58D1A766EABC8E5CBCE3D94E1779099B56EBA27F5263DB950C
+ECFF97261AC0BF39C4364FDE7BB1CF10DB8C3EF5763BB7976815D78C6F886ECC77F92BB4
+46D284D2948A94FA4E5E59D104858DD3ACEDD4088302B71E6A9DD709D47DF40DA7FF78EA
+7A1E226F2C24E73D292B63100F1A6C98548019DE887E739A4DDB4E1D0676967C64723EF0
+F1CEDBA21FF8BA11539BA9F93E55FA54B3DA6B81C50899ADE4EF9369DADE1FA36E2A889A
+A3C22215AB36718E57BC68FD115801B35CDCD592DB87FBDD9AB399896E4DF414835FCE3E
+EE36D6ED5672E8113B19913958321650C8CCD69DA0D9D7E9C0607715534BA674118C8BB7
+CA7AF1A57328FA73270221F6A2D429D4424F1C13D8CD7C6FDE11B2A119C30EBBEB1DD394
+29B266261E39BDDD5F2446444A9AC581712FCA7B9073E1F4BE450445FC14EA0352D7633D
+75C5C5F24DC0C99B888707A6E9DE9927EAAFF533868CC8ABF725EEB94A96699A0821DCEF
+BB2A1DFD6D566446CF3CA7C80460C0772C5B7D47BA2D601D3EE74A5855AF4A35649D7DAF
+0A87747B37F2B1BC2E13DA21A70EC7D78831B840EE91B89BC147C1A58DBA58FB3749F3CD
+1216FF6DE2271EC85C84D07598EF77275ECECBAEC3C99F7686836A8480BA6BCC30B555A4
+0CD5506DEB52F16CC6B4F7FC8B2D8A508FE947505B6C4DE055A188D28FB639553C63D5DE
+2FB330ADD822C7206651DC5E0C5259E6F3F489C0D57BCEC574BEB3E8CAD2BD4FAD239B9C
+4E6C0F410805E831003F27A569B327A52A5B72446F83813FB2230FB670C2DAA0E36876E8
+82C612BA77B7C486DAB6B41AD9D41A5A8FA66E116F48F8A4573536008C9677D75EA140B2
+C11892F86AD1FC350E49C55069284311885787693154DC010F49927AAB51AD8C816BB00A
+216DB9AC0739409ACEE53EFBE5429DC7FFCEB9F54909649F1CA3DAC3B450703DB8A4DD3B
+170969E3381FBE10637C9E69A646C1E58EE791FA68E4350FA17BB704AC1C746591B940DE
+618B5ECF8FE03DA7E6ECF7F208A004815161E7F680AA7EF1001D6E99526DCC4F9E8F7754
+A56EAF46E1E7CCA21E319FF7E44D531E4BB04B7138E6F6A522B58CCDBBF09EBB18287550
+66CC6E7D2660B9DAEE62164A62E49684BCB64D521F6062904D26D8DB101AE8733777CA16
+B20066E6E88C7BFB3C56156AECC89B449912B0C0F362C949FF0503D9C349003284CAF806
+952AE72AF962F13CAE5A87FDFCCEBB81F154487B260229A9904C44F027C776C4FA9BE776
+DD6D4FE4B8D8C9F52897F843CFD2B14BD3FDE0509659E8065F6790F2C95EC56FCFB366D4
+582422CC5011BDCD3466235BA9212F14F2FA0F377DF05784D75F45E5F863A27879B9BF1F
+DDA7916CDA88995E2B52F93A7433CCA2173C1B3AFD83D736D4555A1BCDC83740E9E69A11
+9B5629B03F5A9D18047663D0A6154C4772AFBE9DB5DCC115263D91F95DF2CCA51A4A655B
+FB0B99EA0BF628C0FFD5564E882303DE00B69D666F3FE93A2F2358E3BB4BF60B6F89A7F7
+9421015C3B64A82FA30A92D62B0D3564ED96AD8C228A30F4BBAEC782E3A01DF417CF9F5E
+8B7BEBB8840BEC912AB7B35BE4EFF43E8891AC25F57DF8AECEFF1840C865A93FD1F6C3E5
+F0E48AFF008F52A23B5F3ED5612823AE23E084A84201F9BAAFA5C1D6670CA499BCD92FA3
+C51C0F5C2262941FFAAD5B4317068E78A1215B8F32E60E77196008D95FBE342426E61DB6
+7DF41434115C10B5E04DABD307EF04426DA652094C53EA304AE96BDD6DAC136E1B0913B4
+6874CECD3F1EC272BC4B5A3264A7C3D8881F2415165383BDAF1DCA39A1C53C3BD45E1665
+16EC26F583D1705592AA862D75CD754B66F0CC89EA5A06351BAB9FEF4A8B592D636C23A0
+7D82581D2E972AF42ECF8CFEFF5168695E998D8A756FBEA0FB03FF2FDBF1A3979767E0E2
+A15F041CF0870AC7105E8A2AF5FBB0E00F212C0430C407278400139624895C0B67AE7649
+207A1EE4A781EE6AF39E8C4A77FD75DB7992CB90D9AC239BED5A56105ADF5E224525B4EB
+DE5D43734ED2BBBA28C8CDE0334C9393DF8CCA236FD8E15D5D970900F4DB12C02FA5E2A6
+837C40C097B24942820B116C7693B43F0870BEF05AEB81D73E2CC42E448712D37C22212C
+280E111F738B765A74DF533182178E6CE806AAC22F5E270E1CFD406902C45BB6A58DE01A
+9D75F874C698BD4A9EE40414A446B6E49C8D198583D4A0B51F8FFE1FB809B8E7EBA85242
+477A9C0AEE9DAA8F7E78A5B73DF068D38CE0A7B36D857862DC2CA4C0FAC20A0B9F7F6BCD
+EEE7EC90079B59F46B7A354D1A8D6D4A71DF790E23C4E106EAEC1497DA2B5E36F3EB9E12
+4D049B5E3D92C68D388E1D9D8749E93D2AE063770EE9B9D9491E62223949D60B11AB8C97
+A87C3CD45D13D1B033272698389E80746211AC1E09ED156F7E3AAE2016B178CD4ACAB399
+0C849249133D5C2F855D55A31697C551581953F622621231DBF209EB003D04CFD33BC791
+7AA01C79C2AFCC2308263D0B886A9524FEF38FB01CC278A73A86B06A0467F6A8E57F488E
+F20C22BCDDF368A4322F629D81680312B763585EADED366B810A95977066B421D630CAA9
+0A18AE200329931AF4A1F4DFA5830DB32425AB3B36A023ACD186B4F51AA3D021B44ECE3A
+042C12DC54CEE0B038DA451724D8DA69CA2ECBC3C9E986263ACB791A659174BC940473FD
+03CBD870A2079E225D78D7AA550A3F42FBC2F027F184F54903A1DEED269E6F2CEE48A7E0
+E9DE7018417C65A6DB9CC89A93B1297981530C330F7988161203354F17ED6184EC023C95
+584E45E8E88836C5263398540DCB7EEDDA5299BA8CDFC93E39287F425DB852EAC42A88CF
+3145792AC6712403EB9BF1ADA24CC204F9757B4EFFACA94F74E5CB546569F0C21EA5DC63
+6A7C20A40C6FFF3B173D7C64DE1D6E47AAD74AEE3B27FF5E577CF3BABDAAF91BF166FE00
+65B36A224C4E83252D7820667A3D7A1EE57326683285F217FC893C374DE7F859DED7C50F
+AD5A30931D50E568A12C43C746018C1C35306EAD324CB66B0F747BD24023CEBC636F21AA
+B1A396FF13A2ED3321EA129F72CE2E2B9FA6E00CAB30CD5E8DBA1703962F33E9FB3CFB01
+E91BADEFD13500034B926A667F48ADC59A4CF6D07FD4E7EA96417B25B08FC1F284EF2B3A
+D0A720A95E1AEB3834C453ABDB93F78CA55544597E02CFC6D818423FA15D5D7AA96D9EE7
+6FB33A9A708DF038B19E7ECF0E068B627C26E5A3C53DFDC0A9678C8AFC496078056F8902
+05A38FBA09155052F80832357B84CA86F3B9C399410FFED89BCAF4ACD808B6C7BE343571
+DD2E812C5CA964B8933141A33895804CA34F77074785B58913B2CCC2445B0D54F4D326EB
+E5D8307C92E0AEBA068341A5A14D3AB5AA38D35C0C020F3AB33608BB9C7C28F7BD1022B1
+5ACAF78740EC7DB4AFA3F8917D5722CED290D5764E7FDEB6B0E9EE78A8E51F4F88FDB506
+87EAB486D0218B9DC1D29FACFB7BE25F4D85C1E8AF20B039E23F1E92C79FB13C7EEFAE44
+6567C47AAAC59487CA15B65D3D14CA2D8AC17A8F3ACD19C7B58C2BBCB22DC2F3DE7FF42C
+A6EF389584E4F59CC35D84EF94F3ED5A604DF5CA83035B54817526302662BA6DB7202638
+B4BC47B6E907B0BC3FCF31D06943FF8E04C1344AE04F96583A8FE674A79615A76807E1F0
+FA1EDC93A9538ACBA48C054B4087CEED23E7B4F1750A7629C333102F38001A7A29DFA697
+A3DFAF60BB89908CD78AF393A469E54A41D31CBD35D2BD98E5C04DB8ABD7C6AF6A47F51E
+2F9F4DB3CAD40A85C32ACEAD6C196981E16F90541929DFC9BDF8293ADDA1840EC116F3E1
+191AA907CC72F75FF0923BE2862199035CA1CD4C423171118BB8D250B5897EC9C2AB8C88
+D7FBB99AA99D6D194B33A9152E8C1750498EAAD12C4EB45C1604FB747BA3FCE8DA3EA4B9
+6861CAB69A1FD8D04011CDE1807BB405DFC1482CB2ED7D3AAA1F8714CC8163FD8F0B36BD
+31AFCAEA934265898AA67B80877BDA58F3E701F78CF052AF02F08D3AA1FCE61EA12D53E7
+022B3824A1B700FDA87D31F3413929CC5D1D287B2B5C91F82D9F6DCBCB599D19B4220E27
+C3AAC4F0999C1723924CD7E9C06AFF56F27054FCD334BD9567217D5BB294CEDBCB77920E
+A6FBA60BF77B255E5FBD2BAE7AA22D0AD45C8322A899C45D0B12B3EFEB4444B0CB284019
+33DADF209B797C0F2E77AEB82AE01F09E7897905A43ACB91D64BC3DFFA88A52F8FE2C901
+78A045A48573C28B02782D54B9BF615CB5FDD714342378CDE02AA661A18893B49723A650
+308A721D0D626460AF055C356B3503F6B4CAEA685B1495CF6AE66D14CA45996137D7E173
+7B1ADCC54A6F30E1E270F4507D9B4B10F647320ED3595D6C1B077C8DA047FE03665AE73E
+68A82F78EF7C1DE60427BABED7396E6C412E44FC8D98AEA402C00A784D3A3FBC7793AA8C
+C87A07101BBF6FA2C3178D93DBCF3E00C95F5C0E2ABEA7158330D7EADDECD7B5EE420BD1
+C4C40016AA88FAD7B44B6DCFD9729B136DD16F7B54470F0FBD3A671A13C5DA0A52258636
+1F2FF96985D9B5B582A1B0E51FF2A2BCB8EBB5018DE067019B6C3DE3A052440D893BE3DD
+414D2FA37489D3E34FC6E97FF94D2A2CE6B460498B996D2E21E2EA92E937E68AA000BC8B
+9349E5DFDA563D70EE336C181E9B12FCC65C40A2507685E03D2D4EFE013BA6D6B36D5D5F
+03E7B0920B195FA23FA98993DBFC8F7DC4B7C6BC72C8280C78C150B99604C93323273001
+6078600837D5B179B1AF3FF5692963612F93A8BED3B2630E9EE9738B5F016B0D42D908F8
+9D67A5555DADA0529F1F0445FDDFB01953E264DD3AD489AC710CBDCADB39A99CFD9A0200
+2CE7F462BA691742EB31B0DBDF6F7F26FCEC9BE173A4D78CB40332EAD8A1793F70598EF7
+CDBEBC02F493DB8C654994F6150B43FB49CBB5E886A515828E25F83C8FE14E782C43E332
+B351A8E68094839AE4BE33E8D026CDCF79995EB0160FC1ED53C1835909A1F51407181A1D
+82B529685DD92FE74A21862FEF7B2ED4962A360BA825B08E961380522CC75BAD11FB7F6B
+15378AFC8BBE9521854926147E47A08D728CB679330AE15AB75213AE7793450108837607
+F592719EDC0420A2D9CCB8A9BD7D58D9C7E4775B753F2E928588DB470F6A23378968AE20
+380CF35131CA742AE80AB160434F7AA2A88B2FE42F54FBEDE83A99D5DDF22108250113B4
+34B8C3F8E46D57658C37E229B4791CDF9B2E2C5CB26A83F4B71739741EDF475222665072
+EEA39059AE36739F8CE47842BD9CCC13BABCF2888CB5AB13A12E83E3E1D0BB27C879D435
+684482F1ACBCA88855A0BA49E685B8EC66ADE40A153F64DD355CEFE3FA55F78E499A0303
+45CD4B0471B73FDDB5E5F3B7233F6204EEDE30D7DF03617F267636A4276F6EE6D065A405
+03081E2FD97C1738247526B2F1E374665F400980561ACA6BA65076EB0A23F4955268851A
+3781AC4CE6687986945A3E0AFAC73DEDB76E2FA23BB33E094DF1FF05602E52A49E1B510B
+5562EF0D58E45430AF43EEE073DDF0EC00614C0E2DF121C173E1ECE36B4D87D0FD9D13B2
+75A7C0C8F9B62B5032B77C8909097B3D4B7482A3623DD75BEF4EF27EDCD3E91F628DC448
+4E15D7D633B3415402E48B1B577EFAB6413CB65CBCA453F5EB78E778055798816D895A42
+22EBC77D51C992C56ECDB984D5DD94BFFD01E3EE1082F6D189E3A4D04D6FD2C206235A44
+2578CCBA9CF00D7D2CFC3BDB2D6CAC8AE35DD17F39E0AE8D0A84AA451789BF3C672F7F50
+CDE8F58C4AD3251B124722AC292A11FE426B0B51B2EE4EC7C65103F1128B54820C458E09
+7376F3295D30ACDD561EAD278082B7FDBF592F5261B0BA27A71B8474EC2815A8E62957FC
+FEDA68BA3300AEBC9FCC1C5ED4ABFB2B91C08AAB32BBA60A669B9BAF89524FA6B3B63AA4
+6191B699D7DC81F8E21A990BBB3F906D4F93C3CADD734FE6BC866DE02D2EE1D119A71565
+752224235EB79D3668084A41D7CCB27C48595EA82BDED902BBD71818547D4E755DD372A5
+276B2EC7C66F730F79C111AB99493BF93BE7F252EDDF129D8F7B7DE6AB41E9F8861AB866
+51F4D928F6449852F6FDF2B84E2D8341D6E7CF35FFA7CFD875A02F83733D2F8EA7FD2448
+7A575976B07F5BC799DB0925F0D6967E0C18DD80906639AEB86B4098A732C969703C8DB6
+E9F1E849E75FC37714D4A745A08EA4B374CFEEEAB664116D809AC06A8B3FB1DF8F71BC8E
+BB5AA0467A728A6446768BC45F128D5EE2596FA35BD65F90DBA5A78B5D02E2FA2EA43FCE
+1D2987C8081EC335A63ADA5DE5F6A87020AECCF4ABE0D17D4AFFE79462708D14E3A5820B
+BA2663912A5CEFBF01788B0BD19D08CA965E30C9B7FDD2B8156F23AF2653BA4D42E6AEEA
+A4A812E561FC68A7316634CBDA855E683AFE67ADB8632345B8718289DA3D1F0B00234049
+08EBC15F22DEB99C37280695EAED4D3EDBC084D9FCE7214B85788B6DD81E5AC6B93B47A0
+4BD833CC79B0AA2D4FCC9707874F3C7149F5F751D1A52F59B014E604984C6B2CCF869B38
+A045E50B957DAA6EEE0A74305705DFF1D7EC14BA595E5EEFBE93903DD31B977525AFBCC5
+7C31113400041DADCB603614F882FD78B88D6931DC3FEDA881B6FE8081110CB885B8EEF4
+58DFD7D303B413024A16D40FBF7792785C2B5DBA567798CE9C99195EF294799EBA4CE802
+3D6B0B1C344C90002AB158D3617EACA713F48AB12C062E8BDD7D7C5EBCA6617547A915DA
+48C5497DD8439BC2C304AA1ECB709867EAD1B4E37305A3FFB1A8E9D52462C769CE6928CD
+CE5521F6C134C61F08832CD620385D38CDAD88BEB32B997D9C8EEFEA6F17135A47116412
+3EA3E64254752EAA4745350ADA708255901462AC021792ED74770B031C21C58A7F50A32F
+ED93D45E5D9DCFC27891989CA4BB010E2DF384657530B1256ECFB2613F7FD59ED67E5288
+048E5994C2EB3DBE5D9E77536B967D7DFCC87376A5075C7CA33B7C36251001F0501137FB
+62E0D60F991CE5E3992C3EA4DF89FE2B75048B35B95C5E6EDDC4130FEFF7586C58629AD0
+752666C8A3A1885096FB0ADA14524AAC57E72F66304EDF923F2547D6AFFC0823CB5A8EAC
+CC46B4786B46D611FD42D633818CE9A23DED24AA2764AC6AE7884AFD1DE22A63AD5B105B
+4042B44E44E8A5ECE975FFB6D14E1BF1924F4EFA0D0DAD4E2CA0F5B1473F6D9A7BFD42CA
+966B065D46D3F97056CB9BBA064E62E6A1CE5836BE83371BA46B58BCADA103A2F0E72F68
+E361D46664551B3AD71FDCCC221DE21C3E78C33D597AF3E533EFCD4573E0C2EDE28FEB42
+6D9B7A423ED593E57D7D5FD7C5D97D0B8AA3C1B1F902E89201E28EA19D0D140F8DBB4BD1
+A62309913048A6A82494D26CBBF9DD4456109471043BEC23E4E3D52BC1A33BD7DA7CD67E
+D13E738B1FCEAFF839598F54FACEA0EB1F7D3C5419C2BC588B16A1CCF8814C0AEAFE671D
+DDB96353D32D1F86191490516C461A4666235CCDC5179B4324B7936E26916DA037699EE1
+622E25173E9E1286306E6034D667CF1510AD4789188F7D0772D2DB127665273683698804
+9B9EB1D8A2689D5C46B5B455492FD96281133AA54945D039BA684A89ADEDA43A9496F996
+EB442E2C020D4EABAC6750E320D8DDC7256BEADCEF54E609B20DF4A6E39CEED8B3D4CA98
+0FF47314CC3A3A3E978C4F8911D5AF92C7A0110902A8F5362DB47F19DBCFFB4789C90A34
+8CFA880D4CB23D284C57072C7880B016C2F4338288D32F641EFF0E1F2D04FBEC6D02C61E
+B27A4146B19A5BCE213327C003B1DAC40740AA1E9FB73911F3777FD976F90FC42D91D5DB
+7ABB08EB6A5E4D367DAB5B31347A726FE7F04854DBA180019823FDFB4A44479DC0F84952
+8BD0BFC0025117A8D6B36FA9F88A76DC36E4DF00A2E3D2BDC2FFBCFCA12E3F4CED77C1EA
+B2AE53A27BE8D1E77A618343F6673CAD03754FC14543BBA5FA50E1D7A8DB2646042879E5
+0D1D259898D91048C8B8B0D421C3FAF3E875D7FA4D7EFA088B657442742D89D0923577C7
+7ACCC9D8319DE2640A2422AB011CC520245A59A1D86CCD5F9D5616A35BA2977AC7686BAA
+AFE1A277F407594D6A60D5231EA34761A78C1AAED1A1A6AB100535435C615B8D89C4E078
+829B475470ADDC46331469053DA6B4DAB9F0B0344D97B744BBE1962200DA293864FD2936
+2A6F74DE71CA9A5A1A6E697CD643D33B89A7314A605E54CBE1CF0EC3AE3F11982EC3B0EB
+5D9505D4BFC7402D6539038C6D5E0B27620F7FAC514CE55B230F9A7AD528ECBCFDCDCBA4
+AFBB51CBB1F892545F88C9C5AEE7D3B522ED35F53696EFA39D72B734086CF673DB0EC924
+556F1CBE7D12A8232E51F563E848D7C9170A2AB0AA5702DCF43AC2DA03403374BD85E3F0
+CBC2EC8D2A823A8ABFAD7FE39742DC1DA40DD0AA6E5E1CC84B3B80C909C2E6E01659194E
+592493C1B1D39EBDA54FE9E501BC06D9F2D5B507B8A6A5A9A56DE260459DF378DB3C5348
+84C391C7BFBB36216286796C176220211850D52596BEDFF1455EB36F869D93F275BC2E02
+07CE5F8E5F07ABE7D6B59E6533462CED7C4288A61A5AA7E206986061233FFF0CCF6EF957
+D9FA5B99FB733BDBB3BA0C66508E483BAA1FD689D51B5175533DE2614ECE76F9BB8C5DE0
+DED71BB2F386E03D51CCAEAF84F0EFB290FCDF2C0219B1EC25CCCC33571E29739D8A0025
+FEDA1849B5EEE32D4DB59456B1CFCA8E8F7108003DBA2A20120DA0D7E3CE40FEA9193615
+2F1EE75A674D8C6624CB60E8A42B218AC9E41EBBB6771DB40D83262877AF2A369A20CF57
+BA61484D323FCFCAC034BBBCD8F92644830578DFA45421988048B1660C823CE8F291E099
+311CF62AE24CA332086F6C9CEE197DA96FD2EB0A8E49D2E7045AE7619916124FF5D85907
+DF15FB7951BE56AC6C10EC2A98AC525012A7A75F39B5A6DA63168608C5D1F8A4188F12B0
+F37049B2E1E70A225DCCE1432B0DC309215BC07A2D68A261664C3394CD4A800E30E77823
+E1D8D98B0002208B09873C0A3E6724B3A1A21C074232C400EFD5D526C213550F826EE84C
+3FEAEADF6CCC9E7FEB9A91DE653D1F4CBAECF29E197FE8B9CE2201E39DBABB02299477F4
+791D5CBB3ABBB53077409E1C4D23E7E43B071E523414A00EB50E0A1BA6CA87896C9191EC
+C6154FA8483509FCB65DB129EACF38D00481C70D5D4A1FA9A3B2E84B321222E1CEBAF617
+A8E7EDB4DF284FFC1429CDD667C52D8F2D79E97BBDEBFA0EBCD52A54C963797F9940942D
+3D4D1E9962C34589D754761089F50A3BFE1F9F51C1F1F67560BBEDFD67680C61337F53D2
+7B2D18B4DE7DA691587FC93909CCC2BA2E853D4590936D3B989502BBBBD9929E370B59F5
+073D7EDA6875A191C5BBB8C0413CFF0444F16685442A6EB0F33EFFB569D3AB77151271B0
+B2C5E7078442F1568B5BEE33BDD450854289BFA1CCD81866AFA983921423678D8C9FB9A6
+D9E77A177CD5434BB12C4615DBC5A21317F9B6775EDE6E44A29AF506F119820B5197BD05
+207E0607F1083F0FA4F1E34E9EEC2AD41DF659EF2473724C7FE34AD74D33B15AC0877234
+224B88851D27BEC30033A417C61798F8C0C35123860ED2569A62BC7B2509CB0DF03E3A49
+9CA57311614D12AED1DC3FB1470726AD11CE5D420F4A94586435E7C18661CFF62BE322D9
+A395002F4DB83E37145BC240CB6E5FDCA11686656EECFB072B3422184AF75C8FAC2B6E7F
+33C3BBCBBC8B894A05BE1B75BD64A3CCB485F7359C785C449AC4CA3EBF59496AAA7D0DAD
+FF7BF3F8300AC6644BB4C8E7613C5A4C309EE67AF77701CC1DF39B0C01A296309FA6DF84
+3875E1A057BC7E5ECB644240AEC11AA4157F67136831E5449EDB5017C03509B78B35B016
+DB6C9DA02AFAA51337B3E6FC0091904D04B328D1D57F33CA77E5BDBD38AFA74A7444158B
+20009EB4A2029AC86EF3076BFA6A97469DF182172D39D9BB16D5F15B526B61FBCA683306
+7097DF4ACCB7CFCABB675161A3EEC657E8A8DA7AB590CBB4EEE9999BD8BD3C2885E3C0DD
+52E7850E680F9CC5048FE8B0BBB656CEDC82C07CB9FEF713BE8C5021CA593E445C034796
+B34DC2ACC85FD770DDBB7179F518BAC017B53293A52859A4220DFADC93FBD31F191E2467
+DEB59636682EA309C19F1C5FC8643D9D7BF9A9F928994D15BF645E83B37DDB833F0422FF
+6422A9545FE2F0B2D959C8839BDA8F2D76E369AB05F324089853CE660EEFC774D714954F
+EBDCD762E9490AB0B5CA9EF9B4DA51665C5CFE10AF8822C0831F80470467CF1F49B88E69
+4C75793F8BD37EEAB798D310F5115C5F5DF6D650D75981132E94140843F8440739AD7543
+82B6A4109CD818116DA0FAD8E0FB22903897A1D4C49284411F0BF018E880AEA118322543
+098F74BCA2C1EA19B2FED0C0D1D74329F4F23027D75C304C2BDC5355D5B5424F000090CE
+EF554020B76DFF1EBF9EB929AC89CD76CD5D0E784207743F1C8C0B2275EF960766295992
+5C97D6D4EDFE071B4AFA15C5D9EB72A67C1FB72FC634337D827603AA7C37E62EB623F5C4
+5E23AB693ED30B6736149463A8A01AB28A087F8C80ABEDF20358899FC34F1B587B017B30
+99E8AA24D9054F66E79DDEC2AC82FBB0115923D68239EF1CCA2CE89E935EEE0C451301EE
+075EE992B3183D0E149A65A12AC23DF90D4B05E79F8A0120123D972B919EC7DCA6F00711
+FAC4F842BE2B8384137E5858EC111C33348E85EBBC6C176169969F30841CE85A381EE1A5
+BAF76C017C559D955FCF8FF05A5CDB40E91AC7BD74CDCB519DCC657F3F3F54DCD402CF96
+FBB2C1EFAA5757CDEF80BC6575CE488E2DC246AE31A3E9634DF5337FAAE9259DEBB8C64B
+5F190C04BED5616CADBA4C014A6290BA5D70D2619724A960D60989F52B79C09433DF6715
+54167E161E4A1455A02846FBD422E4270D03841B3B5888FB8399C1F9645B870ABD3F9199
+B8D81BEF3316A3004D07B378962BCB2A0D6531A948B59B7C46DECD179FD73C95D5EF6390
+A105F0B15BB743B0B7D0A23EB7F9065637B717840FB9A2F7FB7C5DB79DD08DD7E024BBDA
+9453FCF5AE11747C590480EE6003F5330860DCB1219FA7458846C8F25B816BB245D50901
+F892E2489F34259C300EDD02B616FE650D5514AD5734B77C7BED0DC3E495C418B6A9EC0B
+EC39E783C913F71D96E9B0A476CF3F2D0253F90BE85D186A823453B109C79AB859726BDF
+85236314120C93F4D44B55EB5A0C11A2D4602149DC836A2F41AA9F096F4082E3B199BD2C
+AA2653AE68087AA655B4113CBF54998BF44C8837E6DC8FDD599160C1B191C2B18AF7EDBC
+2BCC5CEAD0E765C856E0A39E8E904A821DA88AB030ECBAF39CEB016FD34BCF6049F558B3
+EEE3C1EA53B87E7BC2CD8455209A708590ECBB9566A78262C6268FB2180C3C4825267A3F
+BCAC25E204D05417C85E4C46BE30E4FC876D461967483D9ECC839024333A235C05E61545
+E52220B3E3CE601C4480A959F032244A1CF4204A36CA332EC0258A916D0E68B043F30949
+0DDBB75B000DDB359B315FC9BBDE10A42A3A7D6D506B21D1B48254F84FCA27774A98E249
+FCFCE9E96B7EB51D85A671987AD1F3B35C755667B64DA70EFAF67CE8B14A866AE04CA6E7
+EED0905E5FD17B98D75F91279E033C5FAE681AE10A17C818E79204D6AF3925D70AC627B3
+6B81D9D8D75232F308BE848BB67A87A561821201C796FDF6F39B031F5049490AE19E8DBE
+A908EA44E378232A09032D368F1C22E1E7984FA82E14FE340911E786105AC959A5A52534
+C585F1A85C5DE7F78CDC5B43546C8CA3629906BC586B11DDDF157CF1031B182BA3D335A7
+A779F56FC0C037C2948DFD410B53FCDA94E73B53BB76C71B132405ECD8F0B4AB5262BA72
+230B7420F4E03F7BDA0162F59938DBE1220B5CEB12FF83C7C9606A67078C95075D827631
+1ACC893D484D548A52A547C96A30AE7A3B30FB715770CA5861556BEE0E9D8E837D385C7A
+40D24B46DBB4A23A24ED5844F5ED69D58CFE897C8FB9555D41578C97234763E41E1E3062
+185FADD8A80EB9BF519D1A21C1EF6ED7D16F42F5F083046A63711E79E2B4646EFC2E656E
+55355D7D3E6411B465B535043F9A6A57601D15F4B24D1AF71EB93A0C7C07C85FFC32871C
+1DAF85DA374524B0554E196A18A149870C508BDC9FE22CEF54BEEDBC1820BF4B7DEFECA9
+062F3ADC6E93E560F7D37EF6AE086BFA66D02D82C8454FC5CEB362007AB53947B2A14059
+E449E45A379008271758E200F71807B3664771BFB9C46668BBE1A35AD7B208C9AE0CD84F
+8ACFCCDEF782E5E6D3B21F236F004B41E7E6FDA292970F74127259DD470368EE2C17E7F3
+215DBF172A740F42F74BC74C8A5469974446122D11741EFE5CA3AC65D03154E425C85F6C
+525B3CC38005CC7999643144C6BF34EE658BF922456FB08DA18CAF92332BA728EC95FAF5
+8BFF30FF9F1FF2BF14009A5E6B9536F6C5DF9CDA8C2F34842C8EC1FD510F878F1D3605F3
+47B6C95921C8700AFF9E75B7E2B404D13BF906CACB3A1B0529A3168C31C96ACC12723A00
+455229C1BAFE2DC474FC46E969F6A07CBC2D4C3D9C8C81D9BFD84A95756451670D128EBA
+ED2CEF998B03950827D203804F46DD1F1CEBA6110E29A93DDD2C38E8D02769A9523842C8
+533F6EE2CA11FD585EA4FB551DED51FAC17FD30E0BAAC02D6206159911CA2BCB19CADDAA
+4FA6F2911442CBE8A69FA4CF3CC4792CADFF5FB70D1A8441046F0103A36CDC7B8F82C115
+DDA815EF71DC8295D8BEE1D412DB942B2619D67A5C1F8B06DCC13BEDEC191D9E818E722B
+ADE04C6C358A27D1EC9B5C0C198B9B235EB6DAE815C0561A8C29526AD3212B32A3D4FA35
+831008C5A9AD3B9A8D68903021B9513619868E2F8535DB856AFACC031B890ADE468A9903
+B716040C73E77CC57813869E1AD1FC706BC34DF7477FDFE9A0C21AD33C78AE789D829935
+51CF312B811250B8F6244A098EAABCB3A6EE2DCF7209F04AC039A4EF35867AF00F01657E
+B517482EA86295127A388A8BF4B605ED4E13F03B2A3839990ACEF98156084F5BB2206344
+5941C560132D0349D52CB72C85B983DF6391B885C5C6048D5F74FBBF496C70FE021AA578
+280053474B6C1F9AEC55F6DA9DCCF3CAC7A7DEC6F743A81FA0DCF7621B484589330E3201
+8A1B7257F719BBD0161EC4ACAB731F2026B77298EFA4104EDBA6B299858184FD1D4C907D
+B3A6D0192F8C7DF66D3B0C947AF0F91F7CB09320BC0D0B11CC026162450096809A8D1E8F
+01A09E2D3C64E6C91E2B31AEC3F1607381714BAF0D00240FE58264BCFFDA303E87296DFF
+1BF630DCF9AF3BDB5ECA30991897AED39EC4CF40070109746FBE9D6E5A24F70D8B2D050E
+B63D55AC6D18153F3D5D04E10B704A2B47E7555627A84F394B3FFFB6AB7363A9DBBD11D9
+323050BE1C294A586CCBC043FF952C34582F4D4F8A9F6E71A246B47B7B87AFA9BDA0ACA3
+CC3ED5129B810A98883B1A449E5834344BCF7C09117052EC619C8512DDFC81A68CB6D179
+CB3D6F3BE24A1F29669B7C666A9A0C6148E54BAE665515F5490639C66BA808E40B615EBF
+5B59D3CDEEA96951927E406F696745250F0A5A8B8850C3A3AA7F59CC3F18F3FC141DDECE
+33CB43777CB6359B9015B27CCA83BB4EDA646BEBBEB1FE0BCD0E1114C0F983918DFF74B5
+57B7A614EC0FDB3D1FA926CC76D3B6F0527BADACC1C302DC6D4019E89EF7DD3195494638
+794543E29846DCA17B1724C3B2C09172B9402437E747F22F1C959AFD01C092E87ECC0CEF
+C7C422538164E8E551775CB7660B90009EF7C910845385B97FFC2DD5E8DC1DD3C0B2128E
+9553A042C74308F74DC7F04CA995F9B9870AD1E8F89382E9E9DE8600936F1E2180D59B2C
+B8A3536BD7F2C47142C756D26411B6E5E34B03C49CFE87398C7334C786B729DA1F36028D
+DD5A16009B6BCCA2DD6737C7C4C3CE7004B488B86507D095B567868A6ED59964EA34095A
+DFE44C9FEB502977A1369EDBFBEDE949CF421C576859E181AE2CEABCE6C35A88F5050345
+FBAEE8E1FCD98F6DE17E66DAF5D5929046C074E8D85C4AFDC71367857E8A7B1AC3E526F1
+8B7DF5E90F2DCA4007344D0EE044E663D50BF80300A3F1F1DB03B14DF2CDA7A367F91A5D
+AC834BE8E057EDCE5274252AB3FFC1D1DE90857EED51040A2FD881583184CDD2CDF4D629
+B907353B9F878AF4E46FD64C85360927664DAEB7371EEB887F5AEC4F76C6700824FC8E05
+53A785DE724528E12C1FA1A8D32059EAA3A99E6D481665DA762E6325A4310222D7DF3918
+E96FFB85B3C04D9E7CF4F3328FBC31F736E93559EEC6D60A878990E8108012A2785233E8
+2E57C735254C7B38E16C6C7E7179246054583C7299050C31496993555A1243826532B139
+71188CC8580B73C43CBFD1E8F23369F56EAE15FB0FA461BB771026722695A8F4C6BFFA3D
+76BD2E85D3BBCF1F7F53D23639E39754A4D71B48F1A8C8A18C2004A05EBA0656E3E9884F
+9FCC00D55514EE382FEDB40BA636BA174FE950F2B0BEBB9C926E77ED32B08ECB1F4D4499
+02387444393D3A97BD81109E56701374F13CC9774778ED60E3EAE3C78BB6E0B7ACC43B0E
+5F29F3DF4610E97F86D7DE9CE585E2BC144E1193C123BDDBCFF83336625ADD90F1DEBBF9
+74CE0797BD5369D2E3C448BEF8AC728723EBF987B4F1CCCA1B3FF3C0CF8F0287E3F5430D
+BC67542E10C560A28AB12B3513C1120D8975A6EE71DE0175AD8FB16C3DCE4B265DED2815
+F03C7FDD72E34A27215870758DB124A5D630723BAE250535FF92FFADB0ADA3C4D31D007F
+562836EB114CB81FFE1E9F54756A3D1A8E3CE7DA8EAC4036555B6583937F6307017392F0
+FA28BE83A6C4AC9183B899DE736F86D05A91CCC5545B7AA2694841AA98ECC5712A76011C
+9637D079BCD5295AE2999EC5C032F7ABEC0804E2A2510303EE071A9777E89E32804C51F6
+1458AF5736CFE2DCC50564CF3EFB629FDA6C39CCDBC5417AEAEDD0509A025B43A682B218
+8AD0D62B96ADD583B027B85C532A1F1C2CBDCCA5FD54A3ABA6EBEE74F2568BD9AC0E19BE
+26C1C2436C4FF76B4F50F05A37A1A73A02D155C2DB4A849082AFDB1284F9566407CBF976
+F2D7C124BB538A0B26898CC818BFD9D34D41DA06677516C8D78B6C801B864DE2B7830E1F
+868F33DA7E549639ACF55183CAEDFDEA0664AD59BBAF56FAE34AD40EAA21F539F916E41D
+690419E36D2C268B7F72B86BE962AC175BED26F6411B70A92CCB9D7A27FF88929F0D13DA
+90CC5948B6411F7B04586E283389D530C85CACF958D145C88A34E03781617B40171D3187
+430BB6102B6F1B2C9DE91D2D7BC2A8D5770736B9402415C966FF73EB321FE99505100C1E
+47433619A68E08EBC593B85B638EFF1C484BAC03B045BE97A0E8AB48C929F3E801A3D057
+6415902C739C6F92B15E8AF8DA0DEC3450DF6AF7522ED6F316439B8C6FEF58F96BC9C096
+C6E5C9FA97C1524F6F4B84D614EA7B2217B7DFCA1AE90496066A04DDBBBEB49965526701
+3A7513B3453AD0543D475A82C2CDABEFBF7EE5FE95DF01DD6EB4E2F5B36E5AD98A5CB658
+87327AB12AB875E4D9D7CFD34C4F02325EC3E37553B4EE12DD5CE535B2F6C7651DC26A62
+CAED8B3A97A143029F3EF41678CAC2E5F2CC6EE9BD567FF58F32435045214B62BFB112F7
+14FD95F9BBB4F3B3FB620429E12CD2C52C55E483CCEEA72D524C4CF1D91E80F27ACAF36B
+5BC7D386BFCF9D70D3CC730D5D2C9C75BAAEA9EE1FF093321AF65CCC73B6BA6F977249F6
+746D69E200645A4E40EAE0986FF0CF3F1B5572BF9536DCEA02B6925801D1C466129D45A2
+E927BDBF6D6F84C3548C78E70DAE806CAD180FC468F979685F845BB2311524539B1C7ACC
+C9EF641183A100AB51C155E89961090E2349C601C6769CAC3B1C2537BE0CFD560B9B2369
+4E1B8E9083DF9261B17EF6475C0A42466B4DBC8C601CD82D6236729CB8C80FCB57E7AFA5
+D9D9B35F66E5B29251086BB760BE94831670D955DC8288817A9DBCF7A6ED48038596CD76
+BB2FA5541EF78AF5CE421CCFB286624BF3C98829323A7EE8CDDA3C5DE22044672C8D233A
+C08521CA69962135FDDC8EA4139BCB13B64EC0DEA02C437BF522F41A8768ECC542D5EA8A
+9F85417B598931410BC08259AF88E410B695A9A6EBD730853F2FDFE3FB00875F21E1EF5F
+60D8D8F62E643A6F4D124FD84FD72FD21DCE57144CBEE5EED9C05796B3F59338903913F0
+CA0B073B074A44B1E1951353EE514CB41BF3D50DCFF683CD15836226EE9E73F55D4078F6
+5E3A288CF7F124ED183DDF2C0EDCA6C375160756DC3DC33757CBE85822FB2ADC859CA8CF
+7CEAB1DF3A48E751A6604C3E4E53A9C9CB967813C3181D7E4C1DC954A26EA4B28E23E39D
+C2564845970739B40AC5B267B4CC07C90E289EC9288AD379A7B684B97BFDB45F036BA95B
+EEBB25A5BBFD3F0EFEE2ECDEEFADBEFE80BF2A8C01BA345B29DFA9B25B2D2234F358BB99
+2054FBDB728192CB5EAB19319257140E95B8F31E14BE579364136543A847989F4E410786
+A0A068E38A439250C3D61EBECB1AC741D529A5A74A546FF7BC9F2CEEB11CB98F4FA97BDA
+C74A7EC4DE3948859D3091CE7D8992D2C094590B0AF2038429E30A6BF3C7533A900A4240
+E082BC40535E8A07E55E6FACA93FDCF4BE35823B30A2810DC991AEFE4320F927105101D8
+48A790904C823CBE8286DBC1D8E7CC50B1E5931640FBD0213B0FEB7AF7AC38CCC6B738CA
+74B1FE58BF8B559A7D3AF0D2ABEF706671A977E737B5E49C4BBBE7B412FC8512C17661A8
+9827E24623F4428598A65FC5A79E77736EE2506E5A61DC3ED221F412AEF9FB3AFF6A79F2
+EF15CE24C810321A72FC6705FCFE24032801E3F61EC145D6A82C43DB8E5F9D20AE3FD7A6
+72477CEA2B6D04C24804AA1597A4A3E0B7E3E15D307D8A13D4311F4EA895199D208B23EF
+DB35D975CA9D6D9A036F27FE597C41804A8B5EE10EBD4C16DD09C6228988A780CB315C53
+C2455FFAAB2D71FF87E67EE35A65AB2B8BCC351DCCD62BE2DC199B3574FCEDAD5809517B
+8E3BB1B197078CD7F691B4D0474EA1F398AE3AF07263E8BD0842B8012EBE5F51CD5FF11C
+35CBA2B275CAFC8D0B3D4FAD5B0931C03A3E0F79F31EED87ED8AE3C4F628FE1A1F2205B1
+55BAC7504D754C58BDC458A4B24F8A4E1401AD5B66E3547DCF9409C1C811CC2DF862062C
+74A773A5B7686504B4C7396230D5F2F0A2BE098245EBA1758F20E0E5FE2C94E899AFB774
+4F29CF4D61334CDDD7C38BF479B0CC3DA8E67FB6D3150523C09A24286D86A9F4E1F5C2DC
+CB18719F6087FD27EB5BBD9BEDE21B10C26BC38CD98952A128F4CF48F8651B97F6244F23
+E61EE0FBCB5D3BFD9C2E14792920066CA5E70449C4F13057DFD33A11B71C7991D29A7185
+CBDDFEDA7CFB85ABDB7F854F4342EA020DB708556762994759BBAD1E9F83E7F2961B017C
+4EB56B73B37F019A8B91DF3EFEAEF75E016457A70AA33D31C9BCA76BA4B805646F8264A4
+6C15C2470F4903A99B0D0BF9B7B7D384F640FAE3DF6AC2ECB533DF89838B258D8128F5C9
+1DB7350B9BDF201455D5AAC7C08F39B643D8CCF26AF3563DBA05B5AE422388644CEC7ED2
+3EADA9060442A728F966D50989C477BD2E4BD4E206C8B014D2707DA596661CD7035B526B
+61CBD0FE916D0D7B4B22ABD91B4902C44187E74D71647F7143FAC8E4E9907DBAFE15215B
+6F20B82E09B29630E5F1CD15268481847192856F1BB23A00D7E6522090B3672286DCA1E3
+D2DE32FFC4C978F61180D497D9DF1C1CD48B1857CBD40EA172DA1438862A7A28F570B5B1
+73B53E1E81C6EC11A269001C6E6070CDD0156DE95E320F3B496036C1136F15EE35D79F2C
+962280292A3678BC4DE5D1C2535F09571A5EFF5379BA71C9996B7003F27BE9C810C68D9E
+8D55287AD3D1B570C57CCAFB53109C3EB5674920E6FE3AD170F783B1AF3BAC0BA5CA1598
+6218777F4EE1FD7738963D6DE1D8E1BF1353D5D96DE89C2DE3AD2015265D9077AEA8F26A
+9A391A61A27CB0F9E8CE16A12D1C2128E8CB7AE0E861E3CB56769A07E812F1169A283C65
+A22F19881485367B098EF3B97BB9E41775BBE13F4E1560F2AA0FEBE4A31118F55142E590
+B51D5A0867B89F00D9D461D74DACADA920DB5452D80982761B357AFD2F613113854673B1
+3F0F1EAA566427323E2B35F2FED6339DC28170D90EF4F8E4E77506115BFB2FC891AAFAA6
+59611E9FC6F5384DC5096D54E09567BA8379C7D058CE8A3E203EA28DB122519E483A46D5
+F527919C4AA0F635F6F29C4AC9363EA96B0802002BD547E0C248AEFB8DAA0A75DAE5B8B2
+7C7B4716769521B4F3A8B68B0251CA46BA9B7FCD00B3D4A59002B249860669961FE8F4B6
+B594B68D781B24DEE41869F320C0CA419B596F3AE725B4089A388AC4F84A201392C1AE79
+D6AD6F13023E6412BF29DFBF33F00D8966E8C87FB883F97B1430DDD9EE0D0E8ECE00DACC
+CDDE43F90351DC64D38EB3013CFCAC2792F613EB56CCF8553C3D9A4B2E9544058BCA3B86
+6F2E33A68CB60097D017252DF367F584DD224D38163B6BB1F5E8154C9590B8E3425FD89F
+4575B5150F2C674CE5421E4930766BE7A55D1A01044D2FDA079E1E5CAD18F5F0B7897741
+EE1F4FAD109E503F44526746BB3B5C803047AAB46B1D2CE31F3E026853F52528C3CF6BBB
+6BD36DFB524170B10BC85C070459CDD84D25C0EC712B5E8C8D1E6A736993351DA8261CA2
+81F4013542CB6BF8168AE8F04C55BD7EBFAE0EA6C3B45CD9698C7CD576793A1007E2B391
+0310CC96F4D2C5C0565CFF92468AAD585185BF6A19CA9D27D6E1440CD56CA0AD46F4D1DF
+0DAD5F2A2C1D2B1ADD80030E38080DC4CCD773B7E7A74EE7F9A964BFAD960B2542E6EFB4
+64FFA0ED1C8828B8C266897C0F7AED40851746A573DBF08F602BCF9E1B339BE24BF35D0F
+AE254E6D6170A224FB5225D8859F5C440F96359783D21940DE8553275485D0287DC71919
+A3D81FA8D8167DDA0F42E1CB15A19D673B896729B2A492531E9FB8811837318C24546170
+9F428D0E7B0A6C416FCA1B5B8849B86EB6ACB1B901E2D90E0939F3856934894315E3BDB8
+1DEEFF69B45C8C7871E73E6A20B64362FECA450D8BEA3878AAA0676BC8F9DFF37AFECA0C
+C1096900829EF7DE769DCFA7FF9DF38C9C313829A5B9A7FF7707BC554F1B4FE54214371C
+6681D624954BBBB90BA5AAA44175DC50C6BF1E8A618471C3D1D58471F2567084E503EFF8
+F4083B75F03B7848069ED9AD01AF51BC5A9C3F34E0EF36FFDD3D3DB350740A56231E8323
+60E8327F218D6E7F2490258F03B904CBC4763871F37E1B8C88D592876E0648184954B702
+CA5FF4851485BE6501DE9AF291D2D4A55CE425E405833285358EFB271ECA61CB37942EC9
+9D53EED6939D6E828C6B2E013E0ECE1A60736726F77775C299D6784E51B1863D304A9069
+F217C825FF94E4982C8B3CC30242232FA59A8274011712957B3F1DDF558CAF79DE460A9F
+B15A2D1A3999EBCB3501BE97E719138CBFB37242A4883B3300E20CD21EDBBE0F0D8EDE3A
+D6940338657BE43C6C04EA6C48BD51CE3D064B55EFC5DD632E1084BD01ADDF53C114D329
+438792E470EFAEEA5DFD2FC40553C736BF612A8AB8B0FFE6F16DE99FCA0A0B5026B2A50C
+C15F0886047EBA1F115984B30050C579C1CA97D31BF4167448D89B3BC66EB4A099E4DE4A
+89F186334430655C7A2709930DCF66404322FE8C1AEB3C7952A4DD19CB35C3F50802FD7E
+E82D233FAE8EE5377A6211C0D55E5C188CC858D2A38990ED8B2E804FFD60DA6C477D90DE
+24A93AE87BBA8558770C427EE99A8623F26EA053C077837CB691CD6BA6A22EE8C584594F
+B5A8F2C75D5ADF7EBD927BD53B6F5809A0D6088C094EE056EAB006CB8C4BB2C035D57A55
+57C3BB319E4F0F9BA89129924EB53F7D349C0435A1ACFAABBFF97E9FEF3DB3DF03C21E47
+C5FBC852A8DD098CEA2C335CCDA04F2D2C9E7E38A327C7D78CCA84B96C432EA51C9A3CE2
+37BDEED3EA86D69716E5D60DAA77F31CADE9BB9FA1CFFB8A3A293A5B3FF9FEF03CF96BB7
+F259C3FC6EFC422FC55673819F3F4272A675B2ABCF8A4DB411090346889715D49FB199B9
+6AC6C2981257EA9211FA518AA5E582E35E0034AC42F607F587787EF3A6EA75C1C396FC99
+331D4DE3A906906D334CE8DCACAD9D6880B84BE0068ED1F365B9E7DF9D35E79412BAA94A
+BDF0274B01E64B865E7D4532CD08516C8649BCFD7EE65685B27BD947156ECBBB358C110A
+5D5767808E8D924F31464FD3BFBEB53FDE41411840C1B689963B2A5781467C9E44E681C3
+5CB292DFF210C75FB4014107B364F2D3B8D3394AFC8B14BA28585E1238DCD8395E05852F
+C813E23F7A278E72C7463995EAB78999388E9F093C84F3FE3A164FACC9A0890FBE7CEAFB
+0C988CC963B228D9939928E886095F772F12F8B05F4D66ABD8F3332BF5426002B905A049
+886BD5D9EBA35960612E1DFFC74FB5479E37A19A17BCB600E200FBD9437F1FF156028386
+FA46C79694EF0EDF059E63EEB766646DFFBF7385C0893EA15B3A1C982C051C49F4AF465C
+A9E6E837C463F580B883A93C1E8BDD68EFE50FE6616A831DF101F184D2ACB6112A10720C
+6D173FA6E5C494A271FE20AB7959234BA355301BF8276B34BD198A6F6415C094936BB323
+322CD5957A5BDF76EEC4EBAD015276DEF92868B49CA04FAB36BF6670CA237B4530BF5DE0
+B5774A3E67AAE1EFC2653CF7ACE86FDEB7C8D78B29D1B92170D47EAD57AC140DCB44DC34
+AF59FEBC88B667842227BAE500E6A1DBEBAB7750429B00703863C2D3B3BD0420D3660EBD
+6C14592216F03A404E4E46458A9370BE3A92618924313DE6453AED7361D34CFB4369C789
+770D33E94993EDD582C6140423189EAF3CDD7A672D0DD00207B86A4D8FACE9976D83D81E
+CECF00CE22D20B441038D424E3958FFFB7FF68D6214BFDA59085FA022DBA5C94071A3F72
+1221CE61C19B19542C3321030BF5CE4D8022B49573793EB824E9CB243D0E9EB6B89A34DC
+744450FCDD335E607B45DDF26A57C7DBF83A8C0136ED272D908A0A469C9E61F3CE9EA255
+3D81B9E0B98F323928B0F44D62FF942276A4BF297FE225EDAE82A20680A011229F58DEA6
+9FCE234B22B2AEC35A208E23EC809A5F790F09E11FD738CF62168B1BC2F7DA9564B8D576
+11AAE9CA0094FBAA861B6114A66A4692291D5F4EDF5E230CA8E6526C55B62C8FCD46D435
+6407C7082BCA46845FB9A2865EE0CE8F860278152F0A849BDB8B85E481132797F49DD35B
+247BBE4369FCB4A20FF77D6F791568CFD158CC1319F17868CEF028224D2AF3243EC6740C
+93FE35E7372CF7E68F06DECC8160B7C04F7086F4A4FA66DB58100D6513000C4CC90BB363
+6BC1B6ADE24EA559EE3245CB74502FE440D7ED58AE19B182E0EB645D7BCC5D8CF1EC26BF
+D8BAA713B6215595BF42FC097D5DAB7C030C522A694E027CF558BA7EBD711EA18249BDC3
+DF346537E5FF50755BF03D38A338EDF1974B21FD6E75548FB8E2CACD173F40EB5A9F15B2
+FFC720F0190ACEE2B6E5B040F7B89AB214DD89E1E8AA859BF436EE19C5DE800ABBEA049C
+9B6FA77C93A833C02A11CE4E502D174403B582F617D388CD71407FA8C7060B9F3AE414B6
+63F4B524051CAEEFE1C919346B60DD19E9FEC14191B72DC49CF0FA248E568F6AD137EC5F
+73BC3F3F79CFF305D88447E05B4BC7B25D20B5916787EB38D2BBA64411FE911BAF1C69F0
+FECE979BA0267D3A297E80FE07FB6F6330C3D4E9777C095B74DB138EA9BE483655FDC269
+A8759203B594DB7C9F6AB5909651C4A27B18E51CE5F695C2ACEE18DA6AE89A3BCFF95D65
+365BF11C14A5FB2BD261CF6ABA383FC467C81FFFD366672895BA37633C3A89739B397604
+0734CF9218B3710863906ED0002D0E756F66DDA0B38F40882E388DDAF61AA9EBCC87B0DB
+E04F06F6CD3CA3F24EBC695C1CA0DFDE7DDA8864EDA643FB93E0AD976D5C1F36F65E7A0B
+2B1767B0C302AC325B83FB1BB658381C387FBA199CD1C3EC7602CF0E19C96C10890DCEC5
+6166BD141F3061BB7A0654BEDC8DB922337942873A2F6E8E11FC291F8C16AF1A0C8221E9
+62106D02C4F575F4A9F61287E4C20D948E9E4CC7E74B99776EF3A27A0C2ADF127E60174E
+4BFEA136B745DCA205A07EFBA484F7E0F76E5FA389DBEDDE4557C73C6B8BD6CFE9D0EF6E
+E197EB8A5EB0468F5A80F6E71F9D65382067B3216C740744E671A533F046B48D61845500
+488CF8202A1E91176F97E50970BC00D58CFC9B1BAEC3435DE567CC6B5C601ED7BD437C25
+86E02997F7AFE95F1AD71CCEC4E9C2B9D8D17BDCB66A128122AC0E0CA37CE810AEBB216D
+C4AB46AE69CB2AA97CAC99C1C6A5B112A1BC553658BFA93E931B4F28ECC6C0C43E18FCDA
+5972FCB8882A86CA41349630542DAF536846B01DD5ADCC84FA4AE1CC58EC5B325C4EFFD4
+E32EC77120141D233E5C02CF7A52399AF39D64F4B9000B881F13070D85E8DB91DBD38A42
+08D5C6D8ED42A48272851DE276E5ACF698E6088343F852E0B139E724BBAE48A44EDD7A63
+B5772F61E178C2CBC38F728DC708FD792737E5A495FAA3335133C45CC887FCC94889DB5E
+2DD34C1DC8B2901EF49320B2B8E7708A778A54A540CDF310ECAFE13653DAA2D6C9CAAA00
+7AAAC4D9CBD01F61F0E1D8F35C06019B1D6CCCEC5CD9A1A263CA630C8C14EC325F8E5718
+D4CC035FE652C2A2DCC53B7EB5AB33B43C7D1EDACA8F589C5966BD92DF8B62D56523BD33
+501CBFE506B9061B096C184C5504A61CD6B5E03A8338F5B16ECB0324A8785DF1EE193710
+B76D5301448B0C664F565ED0538257FCFBCB051683FC200D4AD675FC4CABAACBEF11BC38
+E95F474AF3FA7FB187E5876B1F04A26DAD7904E39F3D53A1D5FED70E523867C3E1A5B65D
+BE0B1D6CA84EDEF3D0A24D042CA491D6BC39647EF390BA25E2F998ACE7386F8424E3E03D
+6EAA815E717F835E3528069BC3A65CE58FDC49B602E0418A3972D9E5F6192AF89397AED8
+32CB25A607DDE31B69FB61164EA5633C019B3E4BC93078739879A2364CF42633C07D1BE2
+57AF2B07A1E5ED68B06BFB81CAC77F6D2EA4750266E8919E8911391688D4EADAB19B3E54
+4460DA693474250CA9A864C17B7BB5059C0D08B32400A51339C4ED7385D9C1DD1839D96C
+8C0A6BE1CECD38544854E9698401E33EBF50C1DAAD1652D0EB978D8025D86E07C3DD64FC
+92D362A13E173F1A5D015A43AC3CB57732C6A2A204B990635B607938D99422B450E54B7B
+4CF6D22BE2F6B9E936611A0132538CD1D8AF62A260501B3696EFBB0EE006F658EFD8AFB4
+19C3C8957B3D9DA5F8758CCBD17734D80E2E207A58E8E97B2B9B78012FAA2C73CBE0061B
+EB3F30CC034F7FE5D3251DA71BD8372BCC7F271B5DDF11167AB166C59F63B9923F043611
+52240DAC4CE6B15DD8FF9ED6F74FAB00A4D2D9F89BED255126AEC97ABE2D0C7D3947907B
+0AF2FF6A641A43BFDE3126F54E213C03C54E01BE7DBA01F71E523FCAA4C02970BAFC51DE
+EA7A8530D73D62B5F3F457AFB500C5734AF579603D2CAB9AE49281EED2CC8FF7101B4F45
+F619FE5FD48A83D934F6A0D394B07B1235AC8FA8F3DC3CCD9479D87398074DA6AFC3402F
+21B31DE8621AAD29EFD4F9CAF0A9FA9D9A0D097625412B4FD723E1363E5729F40D8C02DF
+8D222A48C23B2E25CDF4F69D283E006E0679F1BD904A9075FB0A8094C1BBC3400A2BEE5F
+736CDCFE47991E539406DFC399BD0B76D3A5C8F91BC2BCD841E4AFBB521D46B8E0558F4F
+A800637D47167FD2EF79F5251095FFA2F3BDB915015010FA689E4E87F921298735A30EAD
+938B6BA40D4E58042A3065AB059C598A96DEE3AF09237FE8A6BE9CEF014AF36D91508C93
+F7A18393BC321C3A4110B160261477F6D9B6771DC8738D8259BC4FF1F2C1A657638CF4F5
+08AA9400D4AEF4ED4508BB30F35E38D968E008230DFE501A9612966F7E35B6D8DF26338D
+B63BD1B88885992D8D3BC7EFCCD89622689192CF14C328C4E4DED3025E56F3E73FE2472A
+144AF139106A197E00EDC57C2443686A234D214FEE4AA2E3EF978444D4A2BD1373423CE4
+E5F82099974FE66D53972F774F2BCE9003538CC59003D0DDAF9889FBF2519EA31F3A515F
+8D2C0091937DCAD3FC757E18FBA1C37F8FCC69685E95932B3DE60F80837EAE690DCE306A
+EB060698E560BD148CCCB42240665ABD523CB02FE18214AE45C44756E9D3A8183DED7506
+E560EDB4D43E3971712C3D23714B0F83D3BF19C7320FFEFD07E9E8CC573D97FED37FD3DA
+5EE98331C70CEFDB6F6564D8EA0B985F1206239822A4644CF2D7ECDC63FC5D2014359891
+5916E41FB338545CECC1B9E37DBEFCED4A55DB485C86C56EA97DA572A2B74D2650C8C839
+1C57A1FC4F75913C8446846F26614E8C72080DE0FBC3FCF92864DF37F8A3C66109AA56BB
+3CDD02BF5330C38BD39B081AFE90F775FA6C78BBFC51DC0FF37B9CAB4058888CB3D4DB26
+40D7224C0DBF9467C720CBB5F684B2A1CA8951B29182A3913EE398B8E77CB27868A439CF
+9DD03BAA0B60DEF70FF776096D86E71394968B7D64CE289373BFC8BB2CC0BDF78E1178E3
+D6F5473427E7AB841223F963FBB2A5743A823367D9AC4A5ACD8BA483F5BB5AEA19B1E882
+670B74FF997E3321BE8A96D7C0435EB77A36F7AD6AD0C7B21F5C74895090908FCDDFA655
+628898D8FD6218A60C301D959265B430369C564E01CDCB05F42B520625FC0FA93F9736AC
+7D5ABC70D1A25F6A6A95C1CF4A584B51E9CA9FBFC9F24EC4F2257B2AEBBD9581438668A9
+F84CE7E9919C84227D76B11B1BFB61788C69603F0106CE5FA226129EBAC295709495748D
+7E1856EF2F1D5F19458B977506F64AA7E433E4E62662F10FFF43701F2A726C3F8CEB19CF
+D467C3B4E835A99941C7E46101CE2C97683A17530F32808DE665326D6605984689241CD4
+5DDDBB5C964F3FCF7FD89D8B580D941B856613EB1A8E59052B296E8CAB02B561863B3671
+E0E73789B112F7DB5F0B2313B083D17166D05B65DCEE648210AB9D3F3DFFE60EC4649552
+2F101001B3FBAFE7BF2F0EDB70A95C572767FC1880F84A70DBEE39648A176BA8C7C87EDC
+D424245F6F66C910AAC0C60E5078260A698AD823965D83268AC7A98EA0E7A23A7599470F
+F6B2E6C6F32FD3714B210C775DFF039590A0A159BCD248E95CDE7A234CD8F64CCD5ED383
+D2E49F9FF4DB2BC7E7F8E1F45643BBA556CC2A8C7C0D32CCE2D17CE77C6C8B021AF086B5
+1F0649C7E2081705B2C0C57B205E8C6985C849B01EF956BD97F8862BE1B061733C8DECB3
+47F4AA8CCF7FADCC4C335D3917604DBA283DBC054C76199749C7748A48417624EAB6C930
+B403FCF33E8A48AE4D064E70CAF24F68AAF18D1F87E4A920E2796BAEEA34BD4F208C90AB
+87D599E2A4A2427715819D7FD510ECBEA421E32FA9C3B672BB5329FF756B0E4B31C2B16C
+ADB8ED6D90BF002B29D4B4F9AB7DB03B83EC9A165A3F1148A9C1958B8071F279440A019E
+743A624CFD4166857D8DA38C230DBC91DEDCE97E006B242E14CF25EACDE17E7E2A6621F5
+662820DD295589E5BCFEBA6E737C3DEF3D3482D7737CDE224E3509858B999B66F6F365B7
+34C207A58FB6C0DCC099E1A50D95A7BA53E0E51EB4D6B55B681B37FDAC9543F143EE5B57
+292DE45AECC7F8528F70642A9ED6A987748EB0FCF8E4964131787205AAAE1D84B18E2736
+911C20659F9813B7F90F69F2B93360E2983CC40A3122DEA8263FAFD8DDCA7CDF12908042
+F5B2045B3AA8BB0336816C80F1C89F7141CB3C64C08E8879145B10696164E0872635D06C
+186444A971B188D84C0B908CAA9D14DE8E69A758841AD6FA932A648E9694E399F234D090
+D365A315CEF4F66DB8E959A56FBEC35DF6A4E969A49FCAA95FA2797D401DC1B42BD82BE6
+5BDF85A7B8A3FDE93B698F10F675E8E0B7D2AB4B3DB8E0FA5D21184C9487BCDE17AB44BD
+DDC9278A72C83EC2896B02DA5D91F2BF9FD44D56CB65B65DBE0D325427E6456E4046DB1C
+5229F513A4EEEFC319A58334835FA5DDFB73D4C8E92C4A3A2F449939939E07BF9B3B2200
+1488481193B08870E0F077E47E7946186ACAEB9FA732474E2DA080AB573A4DD27BD99894
+F2EED2C80BC44C46596FB47502649BBD83744562DEC7224B1CC54CF28192D3C23956A7EA
+96DBF54D85353CBBA1770E0FB58B6F1852409BCB1BDB61313C3C7C3A349591AEC393EAC1
+BD80E7CCB94C3604C5BA8B0828AF45182C683FF51D2D2C00570F6A172E2F9DEE877B03BB
+45E866CD7E5A99E63B4141C4B12A21F62CFDD331137CD027F94DDF9F054C162D74FA1CC3
+94F404C707DA1F4BD2A8C1C762F243F14FC71E546EBB5733C43AB43FF23BA9C2CB9058CE
+3F3808A129A03B6E13BF8DFFD23A1D02C839FB6ACDE2BAD2474EE64FF7AF05FB40E30A23
+6BE270B787D6FB1FFCC0C4D7625B13217071FE46C2DC56DA79F278C69E85D7856927D0FB
+108EFF1E3AFBCB9CE54BE2F76DD439BB182D3DF1F2796DF6B5733959A950ECCFFE7E0B7C
+6BDF71CCC7DA4FEB31D6FD79C506250FEDE21414A1A842747F350664CF53E6710808AD08
+A6FD26ABD8CC592F693BA372A5C0D0A6F4277A92553CC72CD6212865DA7D032D1904F1BF
+668B0B37511CFBE3AAF595EFE422FB3007AE3022CEB6C87058941DDD0DBF6F9ABC5E8CC2
+6AF7BEFBC1F4B1A03636965919D070FAE1F7F9BF42FF16E9778708478A279DB9DDA512CD
+B372E39B9C5C87CC7A6E55BAE1626E8AA3ED7BAB198149D33D8E79960DEE846CBD2ABA76
+1979C57754955E90D7533C0B38CE5851C926F0738CF4EF1BB2951DCEBAA0A0704870DD80
+FFDF92D2136C1F470FF5345C7A93F4DB72360B4DAE833E2614154FA43A2347FAF4ADEB0B
+73C8FB0AE22A42F80B03C7207F75851AA036C76934BF67B10ED6A5B2000A2F300A9E1552
+FF9F4C66ED0FB34900CB8649CA50BE457B967184D0AE2BAAFFA2AF24881761BA01759D8B
+EA601F2C09E5A15B1289A9BEB266392CF5CFF78EDDE664F3FD6B77A6C10BDAB1E57E4ADC
+2EEA4F2897D2ECA99DBEDB2046C7E889EE2FB30F172EF290BD4E16FB68C14E88A58E3F70
+9895FC431776EC963284E03B6975ADB155128913F0A3C910E6D3F0AA11A1D6D67C0EF96C
+145D63F6E629C61C934BE19A0EC8D5ECB08AB1305C5C53F41628E7AA2945D72A18F5CD78
+3DAEDA17DBC867BD813F81E2D828B09EE77EC5BD7943FAA62E9682214C65735152E0AFBC
+E7808699369C181FAA4977771FD8D716DB2BEA0FA4CFDB606A2EE243E0F4B576A3C5FAE3
+8F67C4E29DC0D86EAEDBBA90803E2AB710F16BBE42748967150D969C2E07115A9B2A2507
+A87F7EBAC946F7178505BD9FB0E08D86DAAF88D8A5EDB321FC2E7915CB80E6C0C2B125EE
+0FC6124990A00E685E157EC94D72CCE6169F852E0D19DDAFAD022C4DA4D19B979D33790A
+E763E04F78D6449C7D3674A12D1C01BD73872284A3D7CE4B551CB80602FA4145DD2E4360
+1CDCF3D6567887A6B0A73B7E1B6BA01DC93C51E9FDA181B20835A75541320F1BA53EE871
+16D938FC03B909D4FC6558223DF057E3E6195C1E26D33B28AE7156B88D7B5A6A85ED8498
+48EF890A5402467A8B11E2DA4719C395D6F40E91535F1DE6C7FE1FA57705A8F1321E2D74
+69593D7E6FD067E07B51E7BCCB382B1B00B655116F3F382D990AFAF26347CC6FDA803727
+C1E13C6429D1F5D5E5D9D56EACCDB32E30AA10DDF5E0294E59123E4C2E020AF1D13A0F89
+99F30A49D8049E7D9B8676D2C13DD896FF4CB82995F6517462886B4D6DC37BE8B13D07BD
+23CC78524F835DB22AAB29A1E6468E8607FE3C9E1B1CDA29B98623C87EF39A2DE0BE849C
+438EEA208FAD0DF05BB478D8E54501EAB704ED405598D38D6A58628BFF784EE969725A1E
+8BF897007D0D6F53025453714BE52FB6A5E4FFADE5563846F778B71FB0D225F8C9AE9985
+9CE14DF67AACCBFAC3AFACF1CC6FFB6BB517C87A382D1AC1615DFD97E52D3020E531B8D5
+C6318FB90D30C2CE9EB7EC0D2DD8FBC83A48BE41F22EFAB7B5CB7262E8BFC1196C69AA92
+EF1AA1D59DE9B1C55D5B7C0019D68F23323CEB4FA767550B090439C2D1867631A97CEF5E
+7871494CBCD1EE56C0EBD4B2EC412EAFFD1783CF073E9B6575CE9642F704486C6CB319BB
+19CD270D1EF9B63FE25255F6CD5D3B77B64FFF7B562742593E6DAB5EDC5E9E9467A1A478
+8BFE80F892B3DD660B1765B757CDF91B61E5AC7C7FA68857656473C32CDBCC21C3A0E812
+FBB939809D552C9394686F8CE36CFC3FE8994D26CF4917CF0F11E0DF8B806B5AC7B092A9
+255EA0364A9DF03B85D67BD2B4B4FABBC8161542814E432486F103F2DF6097DED715E2DB
+B130A753D35EC68126DB76A2952575BAC3FABE2BE9FF73D18E60BA667575FE3327769770
+925F00FE13573F5050DE00CF24CD231CF619B2351371433DB15B1E97AFB39FDC4E07F1B8
+45449EF4CD86B3F0C0BA12D52A81D5386A9B3DDC62E588FA80D5A1E31FF503945EE0FCC6
+841AD3D4E56F9C801E84B01FE978E7684F451822423122221FDCF6702D48CD226DB839A0
+E095A31975298CF2FD71E6423F0FA5191D8BF7E27E6963A23F31131E68278485BBC5208B
+6C5D2765BD053C47566A65DC4B173E1580183763326010D54652BCF7BF68FADE1E3B8B28
+E5C601E241431E665178E56C36AA1125B07D8E4E9627027D73CD5A664B40D82199E3622B
+EB76FC104B2E5A6E009B4AEB180ADE287F763B73A6F8636C0CBAB936F79859941ADBA525
+72CC725A8834FB6247ACFDED0131BD5032ED40A04AB7C655AD7E954E4CEAB74524582D7C
+142FEAEC28F549E36135C085A35DE07E782E72CA53BF7B2C8EE8C3D8346E2C2BA619924F
+FD9E5FDF9564723BC0FBC215BA0F785532DEF5AE95939F027A62A402A7FECD77F064AF12
+9472A23D2118B569DE04888A8ACCFD6DA14E928A7C2FCE35531FF112F93202859771381D
+6D161E6BCF5C6DE9B375DE8E983A64AE6AB75FD52D590B78C13885B46FBEFCABED5BAD69
+04C4624E71B29C4EF6B6C2564485210616C08A3C41C83BD947940BE454185EEB33B0F0D3
+680F9BEC8417063BF03100F3484678BD0F51869F3244EB71775D0397B8DB029D13A2A318
+2320FAC3561E7C994DF8F94EA306736B7059857552CBDA0E2DB4689A1572B509DC658E6F
+5C7FDD812DBBFDDE644F980A58E05F14454F916D4458DB067719254EF77A887D71FA3385
+3D6A8D1FD29885E3F52C6E424EE0AC4E1E64180999A7266C896CC3140A3C59DE77DD941D
+376EBFA09D7F3761704BAA2C738610F39E7FCA335BE7B36F9306795D5B2056C57FC42C84
+66BB9141ADE2ECD7A4ED5BF9251C3091D8B950B95CF07303B165A65A4CD198BFFA8DDB46
+1032A70916E66838CF2A76CF444ECBCB9ED23B3B32143C9A98A395E51CFC281106A7DAF3
+74AD4BDF3089EBE727C93E58025BD6C8D917065C4873A5DB3E90084716C5082F6CBAA4FC
+E60176DA9B75DBC2DC5BEFDEAB261C915A7F68CD5F3296FA854324B661BE571A9CB98157
+9C6FE6A5EFFE43C9933EC292550619B794FEDB97CA0FBDADC4FC665D7955B43BD3B23A0F
+1B76D78F7A1CED8FE598074469135890FE8789FADA3CFD4FB965A1FA62E55328EC450B3F
+1E6B00FE274A494D25E94A2A95131D5E6C8DC6E27B65BEAFCE6095420696940A282C5AA5
+B9E66F243FA307C989352A1D557B83C5855C004D86A4BBEB11BE9F152693A77925B014E1
+6AD084959F78B2A136EA406231AB1509E43176B268B8EE14FBC281CE832FDC2475447A21
+49CD45645A78E4A0027060CAB18394DD5A3E7721B27AEB22C9E98AD563BB5FB2B0A0A759
+93F090DC2249F1CD8ED869E0316A2AD4EDB4C24B18B758AD2C746AA9E7544299C8170211
+6D591080B15C376BA8386FACF02BF9E84AB8C7470483A4D6921CA9A2F191A42BA49928BD
+BA244CF5918E55F59E27D9CE90517F9485D91F1D5B02EC941BEB6AC9C7CE3E684E882D18
+7C9B3EC948A745932BBE4DAF8FA61A84FD7D1BE556891F8C339E63457FB447024A3EF140
+99E8FD37DB2AD623BA1476C883F62395E98C1B99F981F3FCE92A9DEE9D99627F5DA6753A
+F46B1B69666048C981DE59BA35C0481FA33A17D511EEDD45D90AA7576573625F167C3BA4
+35B8FFEFBED92F368B92A0DC32975BB2C9C8B1A121CFC44075474B78B496E953D45B9762
+B2ECD85E0CE52B15510E80AE563235E400CBEAC6EDB602386FE1237ECF4D3C14C92280CF
+F9768E60748AF4865981EDE419204FD2F18FC50E49245260BE2319DC1E624C2E59BFE1FB
+CD04A3F5FAFD8D159E42B8E52E0B2279FA442E613AAE3DB6A1016579D3170F8F489E3793
+12A6E32F45128B15E01373AD0C1449D0E5F31D5DC50EED3EB856629EC2E51616F40C9DB2
+F4EB8BFC519F473A02BBF02FE0E8F86D0EBBDE611081C24B3ABE09239A9682D8D573580E
+86D5FB31227823CABCA34D9BC918F38D9B3273223408871EE2D29133367C6048E0FCD93D
+22144710814CEF24D9680041F020EC73546ABD22B6F521DADB8E1F6AD20AA8F33FDEDDAF
+273CB366CC1F7FE33927075C911FC4D9D8175A7AA4E483C2F4AB658EBD523405F83F5CC7
+E328F3FFA5A66900508DE0682F4B4632880A3C807D606A2038F796B3A150F2202C538F3B
+92DEAAE46528E1BA68E19E6FEB80CBF5155A91C16AA6FF5CA472B4444D0981D1D9F7C9E9
+FCCFF9E67FDFDD78AA2AB765E34C7BC29B2D8BB138AFFC8351FA98DA41C552F6C1479229
+5909A4EF7F4865E16BBE81EA742178C3E86B9D2B957DABD2D6A558921D4FC3429A30BA66
+13783DD39563547E9CD1FBAE6257DA11204DC8130C89C5B80541E0668752872C050A4320
+92BEE57ECC95266FB612532DD8D5465C938AE4979559CBFA8F2D7903E48CF9DEB397EA6F
+31F274D48E8956D337310359199708CEA05DDD64CA417300ABA7EBE4CCB70DB7BB31FB45
+E2B9E0F15423FBB2EE5964278A536790F16ED4F9CE31F6DACE8C0FC489CA73D2457CF3CE
+BB9BEBD0CFD2D1F11816BACCA5D4F9A84EDF8D7F09190C16F1B6D1766AF98A34E5A28693
+B555E507017C1B9A1B9D8D2F52E2899ECEBB6A341BDB98DB0885D97C5BB9D35EB6D18099
+594DA2A6257D5E4806D45CCA23CE2545697E3DF34B6E7558D080B030268AC56A576AEA44
+B4DA78A686340EA9B2249C58381347DE308439CBCB5988DB881340139156FFCA9A8961C6
+2004EB36FB0C77F8B762B388EAE846531CC38B75AEF785311A6F8AD5C0FDE8A61D89292D
+AC55E1920923E91BBDBB40675A3D956163323406F2EAD0BC79E4E31C2C2B22B46D266657
+FD150611305CE08885360A76FF28F3DC837ACA58CAC71443120508A80F9F7086DAAC40A2
+9082706907B9751B19D67567FA243BB6595E1DF225DA36FC4F8D86712B1BEAA0D297AFB6
+D20AB0ECC8CAF709E991604552ADAD7F22F8F229527B60BCD4DD9786AA36A13328881677
+7E00F57F9E562B2CCF2D1F6F6968054D8C9B08FCA9E0DFA07C11BCDA281DE484968626FB
+52B677BCAEF983444B24B0D959B66FBB9631AD4796C435888E09D90B1FE97274D8459A07
+9863D3DF6856A45BF8555999FD430FF9AF50FA060364A727503362129D627BCDDE83F679
+549FBE4258B08DF47BDC2BC161D5E61804588615C5CCC3CA6948C25DC854EDEF94A2315E
+A89ADD8163BFEA9D72B430ADE3D9C17D69C9362D2827EEB15BFE3B8806A8CE373469DCA9
+13FE773C8B9DB720538BCC4D8D5481CA29661C00D1F5CAD55799F363AD2CD563EAAA70F0
+6E250629F63A0ACCD3AB2F89F579557B8299F1642663399DF9DEF3BEBE9F9FB3505E9581
+4D58D1335C9AB341F1928FB7553474865191AD7D8A89C8505B88C1C22BA7E3A88A512AEE
+41B79569560C45B67497A6AED27FBBE40C8B2310157AED1078B9F352B79BCC93DDDE7803
+F479CAF0EB48AC801A0BB9EE972A258F110446154E8DF88DDC10523E8CA22A62285B6285
+E7B3A4AD23216701310C4152DCD1E39F771BF8305D35E0BD42432A0C03AF965756F25CE7
+0869B6DAFAFC69C8DB3631C918A7CB0A1A6E3248C5E1E665E926DAAFC9BED400CD4584AE
+03DAEA56407CFFE84729215EEE16B10BF164B5AD7303A77423679FE14F6626C934A14587
+97A4ECA95603E5F4023CFA4262EA9E949CFF449EF9A82005B23631255E615B060E4BE2F5
+526E06676500DB126EA3D38E3562E1819BB68624010F5A984D446790AC8EBE11C5137500
+1814CCFDB10A27EB87382CF5788150D66B803F0833CD73063F2CDB1C2A56E12F8DF75310
+EDE85042D615FE028F68C668017A2A32594B89C428059DDE3FCDB18F9906C7E813DEA4EC
+C3296C1A21BD4BD3C373E91E0D6B6582D99DF35F5091C09602547B864DFE966532EE4669
+49DEA26C0F7B42D8023F8EDA050D8482361EA43C52FFF4F54335284BEAC3F427B6C59058
+912C233525631F113FB15B888D5112759466A337C37A22346C6A4963E3CB53ACB141A59B
+3BAF30349CA7D8827C2CEEB62EDBD851C2AD9BB8083DFBBF305ACE6868046BD93B59C2AC
+75D6F3B1C243C6EF66533D2DADF52D81DF1397ADC532CE86363BAFD043F9B1B8E6B83547
+4E3BC3018912BE08A570BB4000BB13F249F38DF8C73906EE9ADC7D5630F04BECA0A86EB4
+52ABFECF46D03CBAF4BE02061EA50576A984FEDE9DE35DEDE1988DAF0A6308EC4B6BDFE2
+CB0C7198122C19F73CA7436955379985DDE2ECF851D83A425B4427A4A17AAC64D9E68691
+2645FEEA0A8A0F7A7C1CC0B3E96C519386EC14626AEF3E9E8718877DBDF45C9B8984F81C
+99980A8F8F3C9618F34407CA7916D2C4741AB9B4F916763E1592BA2C2D5979E2256E2D17
+A77905EC38606C3645F1348E77ED501DCB783B8BF677E55415DF7373C47212BC59CB71A5
+4425410E29A19F74A9EA8AA508B19464BD0BD1958931B135DB014C6F358ACB880C189070
+E27188EDAA43009B515994E8F3481A9DFF6DB2D5D474F0957603B0A45A7E6ABA97640576
+11054B1ED7C692263C1B2BC424FC68615E9973A230849E771175432E48746AD8E3A15746
+1622190775BAF10F8BB66D2DF99170760B26DF8714BDF178334D0F90A615939C95DF51FF
+D90B28F5BB67FA593ED31E035342E6F187DFAC21FEB26107E4ABC7F484AE11CAF85543EB
+6FA887B4FEC65A760FA33E6AD078F420D4828B526B37B4AFCDF396459B6338896D7EE8DE
+FA3E10C6087DD4E3F56CA302D955FABDF1EC04A5FE4F12CD40535879AF0AA992D40E53BE
+2EFC1FD35E3DFA33EAFBBA4E851434334BD4551B4228BEB88C5F8D259864132E2B893C98
+2A9560ADB25C06487A75809CE201F001E426EAFDA88F9C7AC36F57B06B212F03AB8FD9D9
+6EB6122E968F3536977ABEF5E75AF5C9C30684D3D7833E3495F7F9BA021B5C4A1F76408F
+B42837E068F91D9D2FB467802873702AF6216CFE60C42B1C8F70E7555AEFAE95B6D44C9B
+967E68064CEED38C09BC1A3FC447FEA9902A26B6D5FCC8A42F47AD2FB2C4DAC61AA0ABFA
+58515C45C912BACA7D3D32EB79DC14A4D8DAD9EC0CF8F4F213D3E109127FB7047D2DC47C
+0DA7A5B790318A1E13163DB7DA71AD64BEC58BCF31A596DC90163B1C46C9175059B27DB2
+D858EB1AD055891E58C34233140240EDA5AD13695EC1FA606EC0CA9CD84293A75829B1DA
+2DBB20D97F96D626D7E6D2332B664BF543849554B07ADAD02CF6DFA3BBA2D8D707810B0D
+20BC441FCAD69B8D986480B1E191FF390FA02B76787CE41E3F779936A2EA8CC0167BA167
+E4E08204BB8F4D0CE908AFF57F1E9CEB3F00C1B863BF65443684BA425888ECA909B2A6AC
+5436D996810370BE779C30D21941A101B2EBFD4F38DE2295CA0FD39AFEFC997377EFE1EA
+C62A9347DE13284235061173CDBD0C97A06045EE97A193E79350B8762ADDDC2494A68628
+173A30563595266EE3AEAE1179EE7CCF47A7F9A84DA4B4120FF6B12FD8784BBB674404C9
+973DB36020A9A7EC459F263213846A56FB52BE79B8D1F52FD8EB086A761C665D94D01336
+D5029A5C9C7D7C1234BB170E90CBCF1AF8E5F5B21CCF7C11F9F2A28384B844B1F8F1E543
+393EA9DFDF15ABB11520408BA5242CE5B5AA7EDA7DD72D3D9B939AB2AA4257764929C8CF
+5F6806A21D524DDBABA96FC46B942AA00F9485C1F071BC6C94E65A153045F88BACB20D69
+6EC1405D8880ED1456162625EF0EDA8ED6022F4E6BCB8800A23F762EA3853E45B4ADE7AD
+4620E7CB83EB1CDBD40ABA6234EBE853B3378EBD4F077AF9E12E692995EE06D45CD4CAD5
+ECED7947A89DCE4A66F1B265BE66BCFAE487B41AC623ACDC6667018626CA450FA2E60512
+23B86144AC9A5169C29FFBAEEB9E1D65CDEF2A5BBD29DDA5021AB9F435C459A3809A5DD3
+6EDDD773C0530A1BE54910B014A6AFCC1D95E36A5C8C7D8DD1DD091D7B14E811D864B1E9
+41122A7867ADB016F949DFAE0BA06FBBBCE87C833C6B244AC48A7481C54FE756C2438B00
+9ABD319AF57D0F69874D274F96A12BD417E8CBA7E20FE608A73A88A935EFB77DBC198005
+1CFB9CBA94E196A412C45CAA4F890DD9334611CA1D8D6F6DFC3C180180F22683BB00B8B1
+0D78BF4D64DE288D2ECA95878C2BF266880E547D3826C5D1F3C6B4B0A3EF0345D8FA66C7
+EC77180BB59A6CA349687F18FF5FB5B10AFDD7A440E20F55650F258A10899BD9467DE2B2
+086D32150FF9242346A6546F9A1548436BEDD02049983A46A2CDB4BBA8BFA5F04D7BCD4D
+35DEBB30496780236DBE224DA28218DF58037509FAAF6BE46DFE5A93C1F072F37D80FD97
+33FDCA1345C468C85CF501D4EE30D36EF5FD87837DDFBD703B8F6AC4AB3DCAAD7E7C5E54
+B6383A74F4533EB9FBA0BD8D1D1703590CE24FC3DA5E5BC929BB6EFAD09F02BBA5E30315
+2AB1CE32A6A2F61448A765D912A8DCD8A8E0003CC2BF739F4DBDB388320D990B9F00E04E
+05AD6B650435F44CA9570D878D89CE782E06C68BA9024EB887C6FA18223F587338BDA034
+893624FB950E74209BBD763A9677FCDE1236B74CBCFDDBEDECB58DB1DC445BE8672ACEBB
+05F0E677D133DDAD4607720462C63FD9409C29C75039A9EC34EF0BD89B3AC6045389A3E2
+136C9A6D502D335789CB74B7F369A6877C01CBA68278828D17C5B7C0DA4F385FA21DD8C4
+C68B9E17A35905DC4006DDD3D35186E31CFD74C26E7FDC450E6729F81FA36000E7EF2AE3
+9C4D80D9A94429DBBCCFC44A7044F424E90C5D156CE1696CFA2EA4742338359287297CAA
+5D616C1F7C7E7E71CE9099028D6516FFAE321143EEA343250553B3249C2937C1797ABCEB
+BFBBA9BDCCD5A15DFB20E3772660DBE2C410BAB6F4B1BBDC61AF96F88BF830C23564D4F8
+2FE22F6B22B63D06D1B40DDD976E19C8B361239546890888FAC5E7ACB15C4762C4871DEE
+EF368A59B6BF8A359E29967FDC8A59E03E357D3B84843B20EAE12741CD9E2F2A3A32CFF9
+1DA33E881008CC686D03A1D55651986C00F7796559D4D8825AA811EE8810B921FE485D43
+1873E682B76E96ADF5A586B9C1C5A876AD507C51545009F09E2241835ABE9C6CBC76D88B
+7BCA368487A11BD7654EA0B1EC5F8EFC9B587718C732037B875ABE9F5D44C82B29FEF550
+B80FC0FF7AF43A6CDDAD7A3E8024A09C04CC5570C1E91B97E7829AE7402C870E5496E8F4
+B12B0D9DD500DB6F8546F7C2F965387C37A701F2B43D236AFDD777537967741E88F7BEFC
+9D9B3C7D6A86B1AB92919A48589CF276BB9F00DA2D7BE38F46C9E5B2365948E32A30D830
+0FA8980D7D7C6ED2252D9465EFF276856698108122833A0B3E774EFDF55A69070FBC7E53
+E955C4E02CA71323261353E8F5D1A4948ED41F4AD7E25585E6DFCF5553C9187632617F3F
+9D2230A478E4BB63497500A3CD8AF78C780E700B14272AB399D2D2FD9979A9F422DD2B92
+8CDDFEED37A40A77F93A1BFB9ED9297B2BFCBF9FD40A44D2227F4C7EEE3066F1020EA335
+91BCB47A260B744919F0359E2AE3C619592C325474063675E5D85DAD5A00CC879EFE071E
+68CA2CBD108FAB3849D312DDB823BBD18D7C3D61DE7A5E4AFEDB203D4056B43EE1D93CA5
+0BCC10AECAA08799E0888B637B6D122EFEDF40DEF30CA93485F424928F3CD6AC66D85035
+F8BEB418C560E00331294B1F57831C33F8ECBB2561837A5A0B0E5E2EA2DC3F72A1C09990
+11BD2F0A0916AD62A8DBA859AE63FD73491390CDE70B0C0B7D36354BAA08BD6014B790FB
+33FB26BF6C2215E16379072959ACBEC5485642A7C7ADB0B826DF3390C36C9B28E724D2A5
+7F57EF0B1846B358669EDBBDA569EA1B28E9AFF2DB2A8DEFECDC073D954F3879175289ED
+9F159376F3D1301EF514B47D3EDD5092C4618A80D20ED37D4EDFC8621CB7E4683AD8B2F5
+51D666B8F39C0CA193BE383B0DD31BD540408314871CDEB6117ECADF8E187D1D5ACF5239
+1F8B2B1C6E6F89A35022D0A2B8CE22B79B200AE116A4E9E097872CFCE5BFF8CE9DDE2E85
+087649207EBEEA22E07187C24404533EEDDDA851CA5E7C18657BAB75029DED2D381CF4AD
+2D5D52A310EF4B8477008C11393D74B34F0FCA4026ED3C12C71941A6D77F501A649C8823
+2D9A1EA080561578DC7A1D591B8E922BA280977ACF3549A24125FBE9049C30CB9DC547E0
+766EEDD5C0210C248C4E7E435C81AF15B187F84C216BD842380436BC3467225938AAC1E1
+FF7CBC6E6C59BBD50767D3BCFE93564F1905AA38F1DDAE4A783E857D148289304F8DF194
+CCE5CFE440CEEDDC5F3CD1E1587F67DBC41DF3CB4F08AD19178CC4B77B1DA3CA02B6F40E
+36984E0439E53877225B9F8576A9A2B57286D6F759A060956CD30B6E37473CBB55D76FA0
+2F4588E66305A1F40DACA56CBCD42883B960B6DE2F91DE519C80D8FBEDBE38024EC6F6FB
+B6FBDD5323235130771153124CB95ABDF622F737A42078D8E81C9965B7324F231A072739
+5129FB30006987B2BB806D414672310FAAD37F3FD005EC54D6BD2170AAB9A21E52A9A7C8
+C6AF03F51488D34B06F22D93E72FA5BF7097918FF67DEF79A6D62CB216ADB114A01CDFF7
+DD387A0CC150E852D4D267187F6A6DD6B78C9E283C9D547DC6373A36F3252CC683CDE9D8
+EB7221146E8C54D1A90DE57003A0CA78440EBFBF35028112B431C508298BAB97DC45875C
+D002FBC1E47BE8096D13D485E2604EEF44B0324B0F494D874A723D080A9A32B9668605E0
+18BDA773FFFE5566DDA289972B087D9E69268B2CC04CC1F22DEA738A2248F370328C7FE6
+D50DCC267BF736C8C3418626BACC805DC44F60A862413D4C76104D6AA64F813ED9766563
+3236CC8EB519A9C3A2D53D20658BD68463BFBB0B97A795A78280B0C05DFA3FAA5EC6E6E2
+879ED3817C5FFD07949528C3C60DC6A8F1C73B7B87975A101AD9097F694B7D3140B2EED4
+52E98F073ED4648992EE76954A712C1804DE95D1C1C98048E5ED790B3269BE49C7653292
+E69CB482E19611F24773F00E483B8541F7D1EF3CB9730F527FF6309EC105CDDC9BE9F9D9
+4C28B3520719E5AB1EACB85BFC4CA92ECE780476DFB3BA759550A261B675ED4E1C1325C2
+EAC510BCF993FA03281FFF75833EFDB168EAF8B2AB92AAB82B389E7086822363A74829F9
+FA36C1703081E55EAC5E6358866EAE8BC04C37770DC97392713F110C143B7CEEFFCDD84C
+A6713C01B4AF3732DE935DCDC2223015E57FBF98DCC32ABA1A989176963124CD353DB3E1
+8998F5F322EBB591528544A4A4E0618076FB07540DADD6D00F8B66A60ED5496CBB703E59
+45EE138D7CD77C301CBF0814A7AEAC93127862431265081273C1E04B6C2B4DD0936D8F34
+98B2EDBF2E2E09397169EC99FB85AF23E929F4871EB8FED7AA77B2E22AD7AE6C86F15B07
+A01B8A1E3F8381CF2A7AA25FD49876DF2E0DB253DED331F7CC0A545BDFF42CACED8946D7
+9661F3A340952AE1CAC541F0F6E66682A22AEE604941AAFE270C3C2AF132C9925A01B35E
+D770156A0AF4EF33B00DE099330D5A874F84A23621C6352DE80952305BF501442710DED6
+97682CB92BFFB645C2A48C49D47F8664BFDA17F5ED7A0F64CA28A05CA58F06A9296E6BFA
+858B5A728B28E12C75D947DBDF779F738D67BE839FC0D80F3DECCF255898CB916E2BCFAD
+74FE85DB8AA036791DEB28487B368F14F1FC79E54D4D94074F8FB530036B09CA8C44468A
+A199990933422C6AAAD716F03358E8FCDE9DF706F0590037971AF1D705DCDB45085D8940
+31468CB922E90E44AAABFE7DB1D6D4BD37081491EF89F46FF4F7FEE501495112CF757202
+448FA93DCDA89464D7AABDDB7BEEFC9671BE5A929DE84677636F12F4BC22A59E22F57BE1
+E680B67FAA2F00FB39B6FC7A48E43DDAB93FE9DD75869375A874B7CD49D22C314D617848
+139D61022A79D94AE1FF9E07C7A7C3437709E09B92A8F33AEC386DD37374051F0387BBD5
+F366C3EA12F5AEA0569D15B22729E006748E900A17E5D4EDD52FCF4561925C7ECEE84B3C
+F29BA83B03EC7ADE70040D898BD3EADCA66DF42045C795ADFCEDE3DFCDAFCC68391DF6BF
+C9CF4A49A45550F6301B581D19B8A8F7CD9E06BE7A3C5358D6A319188A803E8A5CBF9877
+B8E53CBD98E3CF270330BE2BE853E5BEEC128633EBD5471D9E5AE1D67D28E17C752C5443
+E16B6E1AE341E83ED9B6CFCE88A12A7329525C0A3BD2D8AFEF72D727B3104F12BC874446
+FF1E5204DCFC9CE7F772855D63A2A8DE36D382346F8C43D7153B9BDA92AA04600267E704
+E9F43F3D625EE0EE228617C7ECFF39AE97806096BD66B914A43EEF2917100C2F0E1B2554
+C891D50C3A0037190C9AD8BB6563E004696DCE62881C1F6F8F05A96DDAF3F89CDBB780CF
+6B7196124DC1730D05CF821CA85156F7EA996C7E3A44BE8D4EA29ECEB2E49CA7D676EA3C
+874594DA4B8ED45B1568EACD8FF68963E24F2E05EAE0908D1E81165B872F3C6284181CD9
+A06996A7D247A1661D65DC5558E0CBFE14724BE1D44B08A1E06D880D87905E889AEB0ECE
+71E3A9037621470305B423EE63C2BCB5B227B264A4CD5CF8573D8B320004D212B65A44E9
+A856A3631BA02C46868994BC9985F219C9DFCAD9591F2B76B34904DD221E7C9BD2DF06EA
+B632E6CA2A24699AE6C9C6B4937A8293CA61D36F3193D888D5081E4CCB837D93438602EE
+DB2D197BDBCD0A00534B493E250ADEBB1D79238C8F8076801EBE4A282C98750ED7BA28C5
+9B903A26553E03E5B1B99A2B1D13BB6624717357E3F368B65C8B2AB2606577E45345C971
+CE54702D072593814090A9EE9559DBB28B3A3F44328C33F652FF066F87F1B251EA5098F1
+1E970A3505B982A023147D7D8B077E626727B1AEFF6277BB306423D55070829D73895B67
+3E2E6F9A1F954B6EF69507E1BE86D6C594AE270D54C39B1645FDA847DC3D3267AC9E3190
+9A509C03DBFC0A063FE9FA2BDCF21199FF1397A93F13522702B339AF7E6CD121FC2E3D4A
+22132ED26FB31F2EAB17B8DA9AEFD61386EA3EBB771A43B60EFFF3CA55238BE1A0852F8E
+5B78DE572FF42616F1D4A64E40C722AF8E194464F506FB9A6F52E52ECDC7D31287373EDE
+F46C5DEDA0CDAE20AD6C88D6315714304D8589D6A24DCD9A0491598AC69638C04A19C07D
+CEEC1F8325317431B3892F270779A55F293085402C4B4085268AD69995186470A2E2A106
+44AEE77DBC20926ADA20F91B5BDCC0181BB34C18D1FB68A32808ACD569EA71E627FB5419
+EA3228DAE56414EA93250EA395BA750C60084D2BEDF6144E970B0C5C7CF40B05EDB70452
+7775F2D0A55E33BECD54B9F91807B097575929FA313EEA4B8EBA80F9499BE28AF2A3BF03
+CDFA19AFB30DAC150756F90B432083DF21C79616A054384D91F913520EC45133A30C84B1
+C1EFA0D1AA9B4FB33908CD93F76F6A8CD03F8714EB0E688DD3A5931BA940C68DA296B217
+BB6E1BA16FCC974E3E9F45A30B47EBC5CDCC6E2FC6AFDD826A1BB6851F68BB88C2879B21
+81BA06EB195D8775B8CA20B436B664BDEF465309FBFFAA48B0736069FD790DBA0047E4BE
+7591F6B5849B2A1B891895EC40234269370FF1E66AF3D391300E07F7987D3B168C9F4770
+9AEA1367B53613F52EEAA64D8D296396EE3B6338B8479022B19A9992964200413F29C3C9
+9DDC50C2C61B92465E339B9A585CF0BD532B2F2F3B7BC3597AE2B89C686781AB7C1A2A44
+A6A897F1CEB49F63DB43D9DAC45F92880661E79D2C292CF910A3E75013D4D3EE05CC1A7F
+7EFF6810E89660F47D06DF62507A067B1F37A100CA620992848EF811D2B0FFE0FB8A85AF
+D58086E2BF8ABA3FF4435FCEFA66F460BB9919A7EF73B5FC511BB3D4C91BE3E90DDDF6B4
+4A2521451B568A167D4CAA98A2BC114B77B2184D15F98943660EC92BD6D0B5D79449FAE3
+089A4709F68872DCA3AC59ECC84A66EA19DB2FDFEDF7F8E57D90F6FB0E856931EE8EA3BE
+8F3D692E4CBA21BFF24CC7DD3366D5F7E57A190F61502CBA9C274DEAED962E5EE3CE7B16
+2E34BA08806B7358D820009CB348B10F225EA9DCB92B0C0CCA4192C3437043132CA73E96
+6527062BA32227B2DA597C8E3E75436467F2D6895B5AAF1BCF55A02267E5FC21AAD0E8E7
+F2459C0B6EF0C372D72F697DD46475075C4172E50405703CD18C23A6D3E7ED6F526C3EDA
+DC5AF40507AA9A76C86E8136CD695C955D7942553361E63FAAE9C23BF3A24F35F8F9B659
+90D7A6656AE186B1C596A8E3F69748427F0C09F5641F284B674F46CF3D0E2708419C1689
+F40A35DFACD95F8C6A1EE07E7AC8E9FAB58FEE8D52E81D486F5950685CD4EB36EBC16FA7
+C0F420D6ADE912042CD2AA3C60B2468A59DE0A5CDAD889180BF05405064ADE97876CE977
+D6F665803C8BE866AB0F1B08452A478408095AA3B8EB0FE8490AA682DD00CD3AD3592FBB
+54CC977B46E3CE307E7D8EFBA586000BB17EB0F2EFD0B0EE61CE18ECD565DEE97E37CCFA
+323BABB4D6354DA19CD9080C96D13A5E6AA1888B17970D7DA8D1B461822CD70CCCAB9F30
+D48F924C91DE9F3243FEABDE5C3C620CD32A5AEECD6BD20EF890F1457285ECFDBBD22BA3
+FAF661BA18BBC1E6EF81DAA2E2A7CBD7A058ADFF961B5A103D967C610530EB58E2D78DAA
+17BEC7C9176EFE8EE633FC227BDA64E54A6533B6D56B787F5098C47824ACEECD50CF4C3F
+172C3C7DAF7B6EC9FA8775C52609D08B073B784951D66C8AC33222604C634E99E99D28C8
+B45846715733EB3446CDDF659D1BE4B439CF32FC2841AD3DEC81A95B20B04790A669EE4A
+A9B40DCB3BB6F0A68E5A2763A8CE7B72586CB6006FCB68C3EED89E54698EE5928F10F5D5
+616EDBF01C349C20E99261495735C1CAFF99E2B1FC986A36552A37D7B57C1D4EF460ED45
+FEF6967FAEDE8AE1B2C7AD835D31AC8160B760E7A36333B83843EE3F55BA19E2F6CD7D33
+9FF0657577CA58BAFA3AC0B7302E88871974DC65218E856338C81F00E4FB35F8DCCE6208
+D7F1BD45C3792D21C308A3CB7B50AFAD17EDFA027545355991E99C1EE99D85BBE5BBBCED
+4E9C6334ACE88F82894B4B1F81F51DC6BBFB2621CF7ED7FAB3170A5DBF6F5E82BA316172
+60223D7049D20ECFED36DD022307D5ECEC358D4A8E7DE800F7D7C048FB265C96108B6D56
+EFBA19A79D37CA7DF37EA1F778B74CD5BE98A2B13BA7E69DE56365CAC9456A3C248D6828
+6BBAC51CFD6D73BED3BD7A7A7B9800B63D1A94882A52F322CC329F1BD691574732DCC32A
+3425E83B88EEF053240D7C7C643A7FCB0DC7B452E1AF9131CB776D450EBEAC8F282B218F
+D1540E4816E53C488F026A6934CD059DD5A09DB1DD8016815D066551BCFCD503CAE5FC7E
+996E67351A6D681EB67D78F1174B3041096687912F43F6ABD7078C7792EC69A42ADB3F40
+95F326C049344123D0F93EF2D79DA7E77875AE9110F3E87FD87AD187B566DBB723E06877
+462C366B15BCBC0D244C2DA7D033E0BE800D3DEB29B295B6326AF0E5F151D50D6E1AFADA
+88A3E0B990C1660004FE5B25F2BD607AC5A141ADCF984FD2EE49871B9BF5D5A1B3D96780
+B4E0AEEF7B4400AFBBDA0350A1586294FCFB5EC075978ECC7F6222AFBC50C6A0CA10DBD7
+8615D8128DE67FE07F2E3869900367476DA42C78AE359894BF443298166E7C935B310FF5
+E1BB2FA0677A947A7ECF0A89C3FBBD60D4D8104F220360D505EFA6AB9CE111C3137F6E51
+0616EA60ED8D1ADBB1B058BA22A6A76CCF8F0FBC04AAB81C6439F44D5659E937118995D9
+C299BC02E354FD4E62E10AE9D2D80CCC72780909F49E6732A61B131E7AAB8EC3D7EFC725
+A153D69D3204AD5F6A3AD6728C2B9E26D337E846A797A13CDB160D740D11FC38CCA2DB5D
+E33074C7E5601C8573641E40BCEDD6B84CA7D15C1B86F42D4EC74C2CDAF65D5E22929717
+C6237AF09A0461AD9237F71C011BF36C00CC630E0C55D1B04D7D989EA011D282B77A4BC3
+C54B5440557303C245FAEC70FD1945A8556B8033269E6EA1C1DAAD39CF5A1BA9F6448684
+EC60E9809ED363B0134FD6F19F208FDB26A4A828EA42322550BD312044EAD339FD8DF100
+0E9F64428FF8C72C51FDAE3E7A69B6D0BFC9B2664D7864163ADF48D2F3EC3629063A39E0
+0B8B4DF52D2B855AC448BCFC2A3BED94D0CFC4A66FC6CB22D158C9B1FF632CE71DF9E1DB
+CDDCB6AD62101DD1A776CA2A111B283E25D1CFD8B5F238E0FCB2008FC1DDA4EF6CC11C85
+96E38D6DC1CC624C11EFFF6DE5AD410B7773BA0C9C8B9E5F3B7C601222D810E921D55DF1
+575F452CEE78BAC9E306B0801234709349F8C7D603AA39CA94E878781D5355B6A534D5CA
+06B774BA53AF73D36F60705629854BB39552ED6A4508A20633D2FDE04ADC59EFB86BCC91
+AABFC0BC1CC136BBD43D8934C54D3062D129F4AA3A37AAB7E870C6272D32D2E56D0F260A
+75F6037AA30AE59A3A5C3417021026BA3DF9E6E55765F5B0933AECF62E28C342CE6C6687
+6FE4231A5AB35F194D7029849D8169BC54B94F34DCA13AFE4F5261102648C1FF98212831
+D76A892CB55AB502AAF52AD08635464A7C65AA6947F6CE69BE3C7984CD36057A31B2D8B1
+935122CC567A10025B6F4E305D40B600D3147961F914DFF15C07E6971A4B58E2D8F02F4D
+54F50947094617BBDC1811AF2FFD72F5376BD65059737BE960D52C9B41F2FFFD1927F3CF
+750FF71292AFE92B978F1A89EDB201F71D014FBC8D2758687039EEBF1ACFAB367C555381
+EA24C44F1E0EE7FAE39EBA4413FA3DE14F947FF5B3909323BD35193B6E2BEAB668B94A12
+40E61DC39EFB28634214B3A46CC0E00BD66D5B2D92B14A708098207C092B45351778E984
+E75DCC4AF44F9774821AE9FD16F44B733C611D708BA56895FD42150EC39E3A86E7253C70
+480114E55C14AB9F448CDE802540B710B1B22C0BF0CF557FE300A2BA25A0D841084A0178
+338EAE9D3DD9B19B062C76015CD0CE257D80DFDDF86C52FD7BDC4648EDF57FE1DD48C1C9
+AE6A3D17FC3CA05716E302BDF2F219B52E16CA97E63ACF67D27EBEC25BED0450B057D378
+9545B823DDCB91E9162D0B8BA526A918BA140A99E32287165394D51499E3CE10F75C9881
+BB3E3E6734B5380623496697FF66123076CAD8648A11D710988ABE094F9A11F4645E399B
+91444EF95F0317E07B38A3D6FDA2241425A175F8495D25FA347425E419A78BFC62D17F92
+888986182D3DD448C236B84F46C7100EC23F321E73BF1839EF3500A0B147DA4B93CAB290
+CDEA0EC5567AD07078D426A98601D292966C172EEBCF61258B805CE42DEDCBF73995B8E1
+6580EE97FF610B938FCBC6D2DCC05D59E5D9F3BB90981F92C4545DEE34794CBD60FDCDFD
+80449225D216246049948AF7B161D509D34F457F210116D1BDB10AFF53AEA6B51A49FB22
+FDF56471F610550D3133616E184B7D06539032DD560C4B5B54859C4232781326ADDF91C0
+98BFDC7B24A57BC4E69E97707CEA01F58D0E5B72919B202EB8852561D37FA219DE667986
+23D6CD0535C2CD0F642238D80452DF1482B1197076EA7CCDFC3C336B0FC883DE2FABB5DD
+C80041A4104E575BFD65B4EED3BF9CDBDD4B83BCFC7295392850F8EB50C4D85DCF6AECB5
+C88F6EA597966AC63872251EDBF270A94512187EE6483D272D50B5E4B7F4556EB9B474E3
+85DC8A6152FEAB40CA34CCA515302C6FF2E66C42E731673962D2FE5320D577A67AF1B02C
+A3697EA85E771565B97A476E388A5DA358B8A1D30DF2EF680288F20E3F5BAF340B44B7EB
+5E531E569896FDD63DA9AE424B0CC244D99A0256488922A394F2E31FAAA47D95D90BCB0E
+83429ED543041F2B8635F3033122F4E114096D497F6D993541A6CD7A6747232B88A3593A
+71DDC13689EBB077B3552C366A4685B48DB7E9A0102F02A1C1A31662568DD1D4D3D95D9D
+B2C491A04534833CA789145A6570F4B6E8FEEB77A9E9240FA9820695380C4A231D61A58E
+F20C07FB1CE230170387CFA28C408D3251ACE1216FF77CA0D54A35591822489C0CF393B2
+4C26623EBC3A3A9C8DBCC5779A2EB09A8EE6F1EF3D97C107F9BF10252698367A16D05E84
+E0B41817D06814D26FF79AA87661C7C2D5487DE11BE2E4DDD7C926834DF8532652AC8DC4
+43FDD086A256005BFCD9C4D9F05D0EE9650FCA24327400BB5FD44F183227F62720787691
+75AF9CF033C19D7B4D2D52FEF89DC3BA145A1CF750AC8AA71EB65FA16FCB377F0492736F
+33A408D699FA3A9472D422751E333B368FAB32C05E959591C3977F0A9B94E0EAC792E1DB
+BC609E1315D59901672AE9A5ED9381FFB2864EDBF657D8EC8FE580409B0C8AF08892C00D
+DA1D2D32CB52611060BFBDADCC73B272936A150A03EC52B4AB5A196C28394154DDBB879F
+627E656510322DAF03F018E917A40C6C70371658095B7A9CA96575E976DE9D2E3719BE63
+33CE53FA1B970455CC734181CBDF92969555C42909B590908F43C81FBE180F043FF8EE57
+965D3B28C0FEBEEB075B2DE3444B117F6836E12234670651230446DFD71133C169B9D743
+1B26A1E5B251B4E7A170133FF9B403D3F345213A67C80EA3F48E12A2B564B97E5E570651
+070EA250C155D9F7F50D95BF852F1A337B152A2167BBA4F2E1FD348DEA9AC2B2DB341B06
+07422BAE29EFE1F7E1CC7EF9EB9C1CE879C0BC2B4D3E3BB126879C4BCC0F9219D89064CB
+BB943487ADAD2E7A5E6A72FAC3C2002226C24462D7CAE7ABD0687F785028CC6E3C4F1026
+A994669C2320444BC35BC6CF8239FD0A4B4C663EEADF9FE60ED2E4ADD276680C5C84488E
+2956D72DDD2A49BBC3367EB742CC9D69AE615CE4693636373743DE1FC06429C5D5F19E42
+A6285DF5394041362F5F43F219977A7B4101E8A3EF45502DD8E702D677423271333664ED
+727310F0A2F12CB90332228BDA42FF040CA6359948EBBFEA768FE2E85F344E38A48A21DB
+04C8C47CFC95B14DB8ADEA6A4994A366E8D46A4A1453880390130A157DA8B5D14B250893
+C3DDE306C62E466968F1EBFF0AB0224AC7F87B8746B816EC02F7FB710176EC2104662591
+4D2E5083ED6DDD42EB82AE75EFCA4B4017E00B80CF11CF347CF1D9A1F43C5A7E16A47CE1
+CF113A4ED121F109F763DE14B756E396C59E9412CB166FDED494706C7B9BB806387921A4
+C4A1FA6556D82F252E69C479D4314252A146F14A310B0D3861FAA13FBAEDABDE8B238342
+897C50E88A951A7C63670040DC49BEEC93CE42819BC79A5C974E968E523CDFF701B6A0C2
+C1E00D0A2C889BC270C0A94A58B8F44AE45AE3ACF02357A1A78AFE2E09755E0E48BE6221
+A06C91800234AE2E2687049E0372C8B0B2573BA6F044FB9827C1D6DD90234D91CC1BF4CC
+FBF14E163DA400E2BE334A4D806B3A934CB6ED7674DE6267B3BA9BF4820C4D41FF661E7D
+10E0EB3F7358BAD6C01B7E1EB1DEF5996678548E589A2FB993126E55BCD6BC1BB1F0D4C8
+1B1088A7688BF682E63D54F55CAF1C2EFA84B79974439C4F90B8D05DC7C300D450BFCA2C
+240CE0D01156FF5EEA35C9542374BEEFFBFFB332E14526213ECF605DA61DDDE45AEED1B5
+C29217566ABCD452A266C8668369B6C4871FED4D830735A947A15BF41F0210235476E83B
+EE843F80375DC95FD0D3D0480202033BCD2D83DEA1B0DBECB3D55EA6AFB96F5B6FC48B6A
+7C1308346583BADC3B7AA668DD819F81E82747226FB67162B8F921790663FD7C0F7DBE63
+BFA878DA1434AE325EC02D786FECEC94696863A3235D048E80BD57857B7F0E6B84C2067D
+F04AD7AF6AF06195B4FCD01D3257480979D79740D4A5EF82D2D5F6359890B1BDA818B8B7
+43620F6844689B7005B608ACC102444067FC7752EE4FCCCF24321872ED9437AF8D263AB4
+123213968A9801D2F9E902D540FBB430BFDE25C15A8185B42BBE510DF4E9F456286F28AD
+DBEA5596EBDD910C7E375DD40500995C867C2E5BF9AAF54E57E730C3C1F199E78ADEA406
+8AF853A645C0DEDEC05C825DF25511FD40B0B6761547BB986AF1E878F905723580D7490D
+026D2D7A49A2E553010593189A0980DFDB18122405110422806CE79E7088487F7FC5C80D
+33217362356D42CCFFC9F51FC103A68A60E4CBFEEF0852C998FDF4A3CEED447A2D77A9D1
+16F88B6ED092FA4D25C59E731A03ECE98247E96B055EB4176B8BA5F795E6EE92F8DB0446
+540207D9FD913E00D20683128E3B99F3EFA0ABBB945606B30E0CAB0EB6B91D30EC381184
+E5046DD2DAD0A4B5D3C6ECCCFF402C1BF5B42E7AC1EB818BC76B92BDE97DB485A9E4660C
+DC3F409129B5BD00E573E2B4DFE2E0113E288974DBF9AC6BEFE9CA8DD0F73C8443C906CC
+4D21BC9ADFF2E9ACEFEF101A1087EC168EB9EDD54D55CF072F4DAADA363C28D9E2FE52EB
+2A58F4BE72A494F370575246965A4C4670A7F4B47F118FE5BC17ADF7DDAA469EFD6A13D9
+8A148B02700D4D374EFA01E2C6502E6BE36F2FC25CFF1D6A4695110595BD358705674162
+54D33C3DDCBC891265EC7F0FC06BD7BDF70D7000328062F889C4BE68F4FAF0D2C2F5D8B5
+C61C40A3134433C222071270F466D9EEFAC22119C67A9EB2F626DF8CF62F028ED74CF733
+1181D642532801BFB127A1946362F2F8BC33B8651A565ABA0226943CA88FAA9F0D8CAD31
+7B7D2B0B0A5D10907355FEBAA4BFC717BBC99A604178B897CC8CD98A14531E9742FDF11F
+8D17D2ED67DE68CF3E2DBC0FF6A23C876F3101DF942314DF0D06160643C4096C65B90E15
+4E2D0CC44AE46932068856CE3EBD03D8A74EE5BBFF74CCC54F0E1D3EB0756C29923686DA
+2410B414A5CD43855C82BDAB7AE111E284FA77BACBCD412A438F59FA4006C11F4B45C502
+24F939A12289F846A43E1A5EF39DED94922AF63537D12EAE8E4641D5434BFD058FBF163E
+586556CB1E13D15A5487091D9BD004C556CD533A25E40F97AEFB4AFA5A2079C87701E65C
+96405AF89D0D7BB41FEC6C4AE2834F99B1426B47EEA08FF81B13AD5738DCF2013E45FF93
+38652EA8A36B8690ACF0997A1CC2501219AFBFCEEB79ADF018B5A55C8734924D5F6EA575
+F0DE17E3BB3AB11F8930DA1A8F3CACD9A0452145BA4F00BCBF072826F1B6F1B9FFEA2736
+7319B85F39FFA7EBA15305A338452211E2D011E566B2B5A822E478BE2852853A1A8D1270
+C9E5E6B80959DC2C1FA70F62765CB50154AE0FAABAF9BC997BFC4C54F63D4D2B948FAA26
+0ABAC11CF0677CA044B1783FB87D31B1960CB0B21024AD08580B0CD6BC4BE22BF8A144D9
+88063037F1D2F17552A15D47D21CFE1B88298BC7F715555783299A9FDD4D131F1645D195
+E6AC8EC0BBD1827548A0F971080AF1DC214CC3720969B735EB0858DEB89821FCBD047BEA
+1F1F8B5F27C98785342D56C145D03A0469D92E932ADBF560D35D555893B0D2F795918DDB
+D65386906E232A3545C916A9AA57403E5244686BD99006CBDA3E93BF9A22A2F172B58147
+4480A90190018CE07634573D67C93211A9577AAC8799CFE6FED8F9274D45ADA841A66CE1
+EB00BB0330615CF756DDF0D6B9DA2B59480E63F0A40DC2E635EBAE9C5ED7283188B89551
+96C155259DB91835ED78A3D3BF07EAF6CB3B3CF6F4C0633C764D8B76592FDE07B62D7DF6
+F5D16F26EAC7DD91E4296442225A5A02A2990B222BB8A1239B38F83A807F828683935682
+51A567B9F68558885FD32E58C4B22D467DC494F20A3428F68A18F0037E8CF4837FDD62D6
+EA3CB73E8ECDA81132256DD09F7CDE0CDCDBA85DF239F2671E0295031A3184F7A31F5F05
+A29A40534BB0E02C99089977172A469A12D331448D690EFA0E05099A960ECC3D9DCC4BE3
+1447F5D77CF9F59078307213D6666E6D9567AD8A341A10C93A6EE3C726FA3A730835E134
+C83E47BBFFB68A5B8ACA88414800FA1971F0B7162DF5EA90BCBDEC7B2C2916F4EB39FED7
+98DCE6D49E8D36A188A18596C02FA8F8B5B1C9C67BB8BB1369EC2FE51BD0E554F52517BD
+5736CB8B581C4B083F891903EEC740B3F52F404BE51F26FBB90739620719C528DC56AA6F
+185DE3A0145225AAF56C7B8B510F0B6C5BCE56F69DFC3AB39C5A9A6110C54B0C014BFED6
+06808B965E8B4CE61BC3CBE66BCB6AB0C53457E2EF94EAA1B05A3B9C459542579FC7FD69
+043E9A4A79E6688CF835BD981FF5935E7111EC2B4FFDFE1E05825BC54C55A06D737E1BF0
+5F332D6B958078B4F3BB7FB1952960F35C28AC9DE3B8A5443650A22DBD69F43F1008543F
+AD0ADAFE7A2D4CC1158F6DFE38D5ED78CEA0E8B742D86AF575C3DD05E07339D95A52E7D0
+8F28B53F42E0EF55E488782D6DAC953C2B46C759D7AB0FD9D521B996B4F492C762250AEA
+0371EDF1A6C892CC2AAE5E8CF85C9532294A7598152455F1229296BA051DD83CDC08920A
+E0CDCD29814EFBFCD435FB171DC21C75B6765E2FEE6EBC57941C984E05C107F0B696839C
+E94FF8D337BF520AB53FCA1CA456E5404EC1F05F71725E8545FE4DF3E612FC6C14403108
+2EDD3E5150943EF21E845230ED91BB60C95CA91F1389F299667673221A8680DE65D12BDB
+1AFB6C7BE73520179FEAB41FF62A57B14FDE16CDE460F4FEFA016A555445C78CE88DD0EE
+A01D49F22F4516E316BB4EB03E5C012291EA5A5314ADD2D16645075E84E50A11F7ADE384
+592EA0A2AFD06BF19D2AC55F9C7EF98FFE32747DBB496FE6A61F01BBF83E0AB9CAACBBA3
+3598EC42C422EE412EF1B1F1704E7E59F28C354F9F6F5B64E780EEE47370607120870DE6
+2623F01C4F8A46059E4DCDF4CCF5775F157DD756D45AE5AA6BD5EB415B04559796AB1270
+3CBAC585D4DE40AA03CF8DA7BA33D863EFAA0F7B990316A7351D9A533E2AB6576024DE45
+176D6823F31DC55A0CC29B5BDCFEC6C75F5D11D67BDFF15D083CA9CB9DF28DF02AE258EC
+5611ED8D721FE60910CA5484A9F5DF3449F85D7F9900C61F4FB43617446E5E74E1849977
+0A0B686EBE371582B0F8B9D811F40D7B01296DD6D3DADFEB2FCE5DA4D93F97B38251626E
+D3C9350AA320EB926688474DBBA786DF88FE9BB502AC65937890DF9BF4E1F20197F3CD40
+9B2F7766078FABDA9C535FE03BE36DF70FF23BA71CB322A9A18A88CE6ED79AB299A0B707
+6E180B8F282CEDE8551094B7D2AD13360CDD68E0F4B8488324C0ACE44BB04EF246B02BED
+49DFA83A9C5219E88FF327CC0599177FCB71819B2EF4758D1D95911FEA16A6C50ED66FC4
+6B478A4DA493651F59A1F637C656AA6F8B11102EE41C33730E4BF7F400E6947A4F1E153E
+2460624E874EB6BA5FDE3C2026964483783E1767F6E8AA12F646F3C47410F0040DD1207C
+56F29EE16D2DD32C0FD73894A44E87E656D3582E3D615C6053E1B7B70E64279D617A958C
+265B6BD1DE5F706ADF911D83972D46F929331C5BDAB2DCC47D10BA4D62D5B246F99A19F1
+E884117F99304249E8A87C6E6FA5083DC0F9E97626DA3E16AE4ED909D1B7E3A911B99E7D
+9808528039AB0641948F10D793A2AEBC4686BD895773F143559DCFDCD6C09D4C1630E454
+0F112093F70B4C76C5D97D28E6FC8DFE2B2322E000404218CE03458E9196B95E63CD625E
+61C03D7A4271A6A4AD5CB055F113D7F10C69E4F282B9D6EC5A60A901ED1EE9BAB97FD40D
+33184163AA17A3F8EE9CADB38F047772FC8D39E3BFC7C9F5D0A3A277F7BB73C27516363C
+BB23E8B0224234F7FC63206B19687CE91EE596D7F8921A5C7FB1CB746511BC9AEF5B6B74
+45CE95D7B58443C4FB4DCAB1F6819B94336058A708F936D38860AED70500373A4CC6A1CE
+10F2BEF120E18CB10EF236457BD1529A5C6C2DBCBFB85F70F7DBDFCF25B9485E92C02108
+88CD2DD84215188B778BF35BF1381779ECC36974BCCBBC37D7999EDB9EC98C92D7C8BB3F
+798BBEBDD852E320E3540C46C0371AF1CCC1F59D9C78A92F710C28A2B9707C8567A9AAE1
+1642EB8BFF1E9CE99B30A784DEAF11210C44EA275F137EBE69C197039E9D35A8E76C799A
+E73B0D65EE4D1FD59E0E8B32030B6B4CE02E698F7090205E7B466C985ADEADB18CBCE64E
+5074D90C4764823413CDA39DC16CE421D60F485FACA831FDC4EF6204894EB5B108734F3B
+48E6AF64C0BF82E71AEC055DBD588D62AB4585555FCCF3982204397FB4BB4602B313EDB0
+B746734B8E6AF4FB59CA0457D45F6CA15966C3ADB050F7B83D75D43B2D54E8CF9604494B
+7C712E0263E7154B31C205F51F1EFAE4FFBFCD5F522FD9E85AD6C6DEC091D7CD445F56F4
+A6D087280B252E7901A34EB4BA00206E4EDFD63FBDA45A17DFB1873BF8B6E82B4FCF7AB3
+CC1099EDE08FAE748854C9E468C9C8B8FFF239E366B4E8FC76048B0638F7FBB9DB80E711
+91F51D4CA50ABB65E361BE32D12605B10C8ACDCF2101D66928C9D95099C296B33651B44A
+BF0EC9C0B7A6B686AC630264897CD3274A1E87AA8FD7182A124ACCE7CAFE4887E06A7B34
+FC7DF7973AEE69B8381047E2D254375C46BEBA1730FCC6FE4D6564DA9EA963D0B7D45475
+FBBB54BB12F389AE979D1F36E4FAE0EC7A1B2B7B86ECA42C85268E0953A461C8EE02C407
+FC387141C52866DB49D8BFCC065FD264E5F57423E3DBDF1270D2BB7DA6A860D22722E052
+3489A3A0B5F0E7E46DCBABBD89D3E4112A031B37576D35B95452B25B5CD04E18EF24FB0B
+98A00B549599F3E924EBFC4FAEFCE504A1877F69375FFE7E9E7D2EE82CB2C80A87630A98
+88F13C26E568F5AF98F6D30A7C3E20695AFA9B2809FD646A8334AAC86B1020FE968085A5
+70ABD597C472F693F3EDCD5E88767D23293C1F64BA94029DA5921C251FBECA22F1BA47DA
+142810A60CC9090E7996F3B09423D4D850C83F47B497E4C17718020B0DB9915933FD016A
+D32B50CD62E6E20BC09646093ED3BA9F9D0AB09F5B6B01F69CC8F706B3CC3828B7794A67
+3F2C3CAD3A2EF13171C65111A9D34F0FBEA00FCD22C509FDD913C7DC144618BD743B3639
+1E4694442AA86AECC639CB1A857DEBB2D5DBBAC329C4E1AE4F095EBD6259D0EDC896A818
+829311503650962679D627D060C51C4A78E80BF764C7DF2121896E0B02E74B9E65CA2CD5
+5A6ABA7884C961B474FD4AB32172A6E070B29FBFBB424417D6D1F89F6A8BFCC880C82C9B
+7C4F23739259076A57B3BEA79878839E3C0DA5FBC47A52B81724DBD303C58B027F1F1D43
+2DFE420EA7C773BC0884909AD03F7793F40878A46813EA207D855FD8D397DAE056F89394
+602DCB1174532DEDAA96C5907FB020BDB735AFEF6896EB193CB16A56A3274398A20A503D
+B1B66729D094A21DD45E12511715FC962E0F3238630954BA513374FBCE28737B80CEF5B9
+802097BA8D3BF8BF5315838C014B08D9BBF849EB92459D04D0B735E487858E333E140CDF
+71A6B463EBEFF3A86A5E1AB29902A14DB4C72DD9FDECB05F2EECDCC4314A600D6724FE39
+7478CFCC6478622A8441B88BBFF9AACE6FE02E7B96B09BAC4B90A65F04AA6126304339D7
+E450C24922FF6F3027FB0F6AE9C19BF3C633708255E1E9F06B8245485273A72DB47FF9F5
+E5AB05B1D8518691885AFB8DD3350D9305C4DB91FB120F666DEAC0AE0C64EB19106F386E
+E8A848CBCC9091EC8FA9004353981D5C214D920A07B439E78EF98628E1C0CF014D54F271
+349676D7BB0E41418A67DB24F36B3D8953A73D18E95DA0645666B485DA0061B2D49480BD
+C081AE8CE6C696BB8A7224E933FAECAEA2C09551F961556F7D1314A869D1E698DC887BFD
+F0E57FE8459FB5B1EABC88F50FB6B3BE5B6DEED96854201D97A6A199F4C5E0929762832B
+E47A897217131F32718E2FE87A2A5CAF8594242C504CF3C86C73B68C09B05DC02F428941
+F441110CEC6283
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+{restore}if
diff --git a/fonts/Monospace-BoldOblique b/fonts/Monospace-BoldOblique
new file mode 100644
index 000000000..880b52fb0
--- /dev/null
+++ b/fonts/Monospace-BoldOblique
@@ -0,0 +1,2445 @@
+%!PS-AdobeFont-1.0: Monospace-BoldOblique 1.15
+%%DocumentSuppliedResources: font Monospace-BoldOblique
+%%Title: Monospace-BoldOblique
+%Version: 1.15
+%%CreationDate: Thu Oct 27 10:50:21 2005
+%%Creator: mike
+%Copyright: Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.
+%Copyright: DejaVu changes are in public domain
+
+% Generated by FontForge 20051018 (http://fontforge.sf.net/)
+%%EndComments
+
+FontDirectory/Monospace-BoldOblique known{/Monospace-BoldOblique findfont dup/UniqueID known{dup
+/UniqueID get 4092906 eq exch/FontType get 1 eq and}{pop false}ifelse
+{save true}{false}ifelse}{false}ifelse
+11 dict begin
+/FontType 1 def
+/FontMatrix [0.000488281 0 0 0.000488281 0 0 ]readonly def
+/FontName /Monospace-BoldOblique def
+/FontBBox {-173 -1034 1654 2157 }readonly def
+/UniqueID 4092906 def
+/PaintType 0 def
+/FontInfo 11 dict dup begin
+ /version (1.15) readonly def
+ /Notice (Copyright \050c\051 2003 by Bitstream, Inc. All Rights Reserved.\012DejaVu changes are in public domain\012) readonly def
+% Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.
+% DejaVu changes are in public domain
+ /FullName (Monospace Bold Oblique) readonly def
+ /FamilyName (Monospace) readonly def
+ /Weight (Bold) readonly def
+ /FSType 0 def
+ /ItalicAngle -11 def
+ /isFixedPitch true def
+ /UnderlinePosition -221 def
+ /UnderlineThickness 246 def
+ /ascent 1556 def
+end readonly def
+/Encoding 256 array
+ 0 1 255 { 1 index exch /.notdef put} for
+dup 32/space put
+dup 33/exclam put
+dup 34/quotedbl put
+dup 35/numbersign put
+dup 36/dollar put
+dup 37/percent put
+dup 38/ampersand put
+dup 39/quotesingle put
+dup 40/parenleft put
+dup 41/parenright put
+dup 42/asterisk put
+dup 43/plus put
+dup 44/comma put
+dup 45/hyphen put
+dup 46/period put
+dup 47/slash put
+dup 48/zero put
+dup 49/one put
+dup 50/two put
+dup 51/three put
+dup 52/four put
+dup 53/five put
+dup 54/six put
+dup 55/seven put
+dup 56/eight put
+dup 57/nine put
+dup 58/colon put
+dup 59/semicolon put
+dup 60/less put
+dup 61/equal put
+dup 62/greater put
+dup 63/question put
+dup 64/at put
+dup 65/A put
+dup 66/B put
+dup 67/C put
+dup 68/D put
+dup 69/E put
+dup 70/F put
+dup 71/G put
+dup 72/H put
+dup 73/I put
+dup 74/J put
+dup 75/K put
+dup 76/L put
+dup 77/M put
+dup 78/N put
+dup 79/O put
+dup 80/P put
+dup 81/Q put
+dup 82/R put
+dup 83/S put
+dup 84/T put
+dup 85/U put
+dup 86/V put
+dup 87/W put
+dup 88/X put
+dup 89/Y put
+dup 90/Z put
+dup 91/bracketleft put
+dup 92/backslash put
+dup 93/bracketright put
+dup 94/asciicircum put
+dup 95/underscore put
+dup 96/grave put
+dup 97/a put
+dup 98/b put
+dup 99/c put
+dup 100/d put
+dup 101/e put
+dup 102/f put
+dup 103/g put
+dup 104/h put
+dup 105/i put
+dup 106/j put
+dup 107/k put
+dup 108/l put
+dup 109/m put
+dup 110/n put
+dup 111/o put
+dup 112/p put
+dup 113/q put
+dup 114/r put
+dup 115/s put
+dup 116/t put
+dup 117/u put
+dup 118/v put
+dup 119/w put
+dup 120/x put
+dup 121/y put
+dup 122/z put
+dup 123/braceleft put
+dup 124/bar put
+dup 125/braceright put
+dup 126/asciitilde put
+dup 160/nonbreakingspace put
+dup 161/exclamdown put
+dup 162/cent put
+dup 163/sterling put
+dup 164/currency put
+dup 165/yen put
+dup 166/brokenbar put
+dup 167/section put
+dup 168/dieresis put
+dup 169/copyright put
+dup 170/ordfeminine put
+dup 171/guillemotleft put
+dup 172/logicalnot put
+dup 173/sfthyphen put
+dup 174/registered put
+dup 175/macron put
+dup 176/degree put
+dup 177/plusminus put
+dup 178/twosuperior put
+dup 179/threesuperior put
+dup 180/acute put
+dup 181/mu put
+dup 182/paragraph put
+dup 183/periodcentered put
+dup 184/cedilla put
+dup 185/onesuperior put
+dup 186/ordmasculine put
+dup 187/guillemotright put
+dup 188/onequarter put
+dup 189/onehalf put
+dup 190/threequarters put
+dup 191/questiondown put
+dup 192/Agrave put
+dup 193/Aacute put
+dup 194/Acircumflex put
+dup 195/Atilde put
+dup 196/Adieresis put
+dup 197/Aring put
+dup 198/AE put
+dup 199/Ccedilla put
+dup 200/Egrave put
+dup 201/Eacute put
+dup 202/Ecircumflex put
+dup 203/Edieresis put
+dup 204/Igrave put
+dup 205/Iacute put
+dup 206/Icircumflex put
+dup 207/Idieresis put
+dup 208/Eth put
+dup 209/Ntilde put
+dup 210/Ograve put
+dup 211/Oacute put
+dup 212/Ocircumflex put
+dup 213/Otilde put
+dup 214/Odieresis put
+dup 215/multiply put
+dup 216/Oslash put
+dup 217/Ugrave put
+dup 218/Uacute put
+dup 219/Ucircumflex put
+dup 220/Udieresis put
+dup 221/Yacute put
+dup 222/Thorn put
+dup 223/germandbls put
+dup 224/agrave put
+dup 225/aacute put
+dup 226/acircumflex put
+dup 227/atilde put
+dup 228/adieresis put
+dup 229/aring put
+dup 230/ae put
+dup 231/ccedilla put
+dup 232/egrave put
+dup 233/eacute put
+dup 234/ecircumflex put
+dup 235/edieresis put
+dup 236/igrave put
+dup 237/iacute put
+dup 238/icircumflex put
+dup 239/idieresis put
+dup 240/eth put
+dup 241/ntilde put
+dup 242/ograve put
+dup 243/oacute put
+dup 244/ocircumflex put
+dup 245/otilde put
+dup 246/odieresis put
+dup 247/divide put
+dup 248/oslash put
+dup 249/ugrave put
+dup 250/uacute put
+dup 251/ucircumflex put
+dup 252/udieresis put
+dup 253/yacute put
+dup 254/thorn put
+dup 255/ydieresis put
+readonly def
+currentdict end
+currentfile eexec
+1CED864D422F76FD8FAEF6132F502482A3D8B4A45438351BEF76DE83DDF4E51528714B6A
+2E0891A07E6A4C4AF06631204074926585455A5677B5DB36647E8D4B74F135293000FE37
+CEAC7E5D7112AD08238B10F0A7E8C6B22250EC0C3AE0CEC1B5D58D6CE79A5C9E8AA78533
+80CBA7928F215BFBAB9974AFFD4EAE72E2F13FA51DBB826B3345FF4EFECC42059C923D3D
+744770EB5214390157686984CE97B7A323A282FB3942AC23170668648757127D1F629DE9
+F47CC4D8B96EB65B46A5F601947908C6623ED3C619000369C9E67729C539451F62FC5580
+9EE2C0DEDB3928CC0FDD6D955E88BDD03D1ACF344F28493FCB53D4FC1B863FA25220FE1A
+1481C7750500555A9BD2D8D14147C9F8D44BF71EF40F09B0A188725D6B400C688671D7B5
+547DF767FF1075536B17074CB44E973ABC27A9494A2D5880537C8D53A2C7262E53EB25FF
+C4C00E380FF2F8B0A0D33A03BD016174D197257B13A27D23E9EFE76CC0F6D8975A0015DA
+DA093AA1B08F2BD290040DBD6674FF79F4718DA59796045B4D8091C39F6B407D5F2715C4
+E5CCF1F7A8909DC995C81CB305B02836E96488ABED0835D20FBD3507AEA8C9B51EB85BC7
+148CB611417A4A894FEB958C0CFC59F6359567D6A13A0D01A7AC80E9918450DE949D19BE
+31C7FFE9CCB6A9980AC3CFE03409367CCF926A75F8CAF8C2BCE07AE51FA505E0EAEDB20C
+4B530DFF7DABB79822CCAB90A5366E32840749B94EF996104D44B3E13E3EDA856C4CFD10
+3CE65A33CE8A22AFF27E081A93AEC929F7766C0F1F8C8A5414D3BB4C46F8E791D02C1710
+95FFE94019D62F166E3EDBD88B350E8211CFC504E546F14016DA01DFF478C25015A6530B
+8D38CA3F7AF4DB3B8959EACC030207E8239C17E351E737F58960875256AE6BF5094C042B
+F753341EDA79F533F602F673B803394FA140B5F9E0768413A9EA96961CA0002036751C33
+FEFB66DC4FF30585349AF7C9924B9C94E20DD44381028847816BE17FA4D554B30A78AF24
+11318819B1553C659F9866EAE2C775A9E06BB5E90AF8B32B1A7BB290EFFA41F5B5033C85
+401D3B85F125D61EE0B245E0FF52B1F46CA409A86A88A8E40CF38BB9940168BF936734B1
+F45EF8AFE5BDA9F613972D9F61EF5FE3F8D4D19690C2AFC60C3FC4681906BD2570945EC1
+8B6161A8A960546C23964E2B005EB85B4146C5EA93313E99557B8820C6690E945AE88661
+AAB10C0D47BD67CC00C03BA82A04407CD9B692351FBA25E75E4486A21D9A0542762D5A64
+F8B1B879A11EBFBCE426F221372C7DA133D7CC2B2C0F9E6F269B3DDD14A4167F184F76BB
+F0A6AE68F88340051B93CCAC09BBCE3A674F684ADC4F2F5D121A3CDA013FD031637EADC3
+36D6EFF295A86B54867FCFE1F05BF5A73C737040BD3B1A0E924193B83B6BB378B2453D9A
+A3D53B864E1EFA1822D4D2EAE2B310A42389ABF90F4D439E0DC7CF34E8B90439EE25C677
+00F9DD5CBFC6DD5681E3C79F26089F6D569E0F07CDBA2881D812766439FFC0894C0E191E
+054AFA67FC1B1AAC7ACDC5B6D710F1D0D7D6EA32937FBD67CA71A1D5C5EF59A3C0D833C4
+5F78B126A88A81E73971B7E12AF16C4B23086F282FB309755696851DB9685FA9564AD878
+BB22CCFFF759CA65A594FFC2FAD61F774BB8450A09B08631B1E808E267E855F003A5B951
+D8B4BB325401E199F57345709782E2959757EAB5BE7AD6B5BFF17014E3A1A8382819CE75
+EAC4C68377FC032EC0D74603F25A2B1386F7FEEE876467D0DDEE2B2B9D03E25F32137D1B
+4A8F90BBA322636C8571B6E215111579F95C346171C8BFE6777B081660877518D1B44917
+ECAEE307B68D51DF094AAD59DDA212747661AB31A9F31392C4EEDE462668675988A83172
+AD88BAFEEBBE500AFB2A4D9CDC985494CDB271AA0741C0709A2A4991B5EEC213F3BCF107
+E6EC214DEE85916ADD3440AA2A7D24F0645E254639EFD1AA093BAE93015A7FCCADE66817
+F4AFF9E5A10DC390AC33D707D8A8401F93D0318626FB23F8E6226B5C5230FAA6323C32AD
+9F73A91ACC682BEF7AB3A99347316812A926E30DA8AD7CA702E52C73CC37D8A2F8D3D679
+D2F4F17419B85D061833B63DDCA501DB6E5FE81B5F8E601C59057D912CF9163D1DDB4237
+6D4CFAEDCF4E4F66600F71D7C31061A9846A0F153536DAD78AFC80AC89DFBB1CECE4D89A
+DCC95F5E7E03A41A6BBDEAFB3372ACF32ED1D5DA6CF8A768812D69620806585686FF6658
+81AD1D1AB17E7282E6150A3EB40B400ECD78E202FA63A5508EC4D6FD78EC3998991D3829
+B4CAF3B7714AADF0AA04D5239F5BB40A7678938E493E6E58BA9AADAC797A8A7AFAF594E5
+82CE777C987C6E9B4EE421FD1E44B7C3DB349621789B8142C2773C049CD999E3BD26B634
+BC86CDCC6F930EAC04C71A25E8A2D1DE3539C8981723ABBFAF835B9615FA36A3D89E1502
+F46C09FE21AD93811C447461729A4283E1C865419A5437973C07F830FB3645906DE1EF79
+5A4D0DA6079B77C3D0CC1D1581EB24BD9644CBE0FF57D58295D3C1529F95B61F21B4480C
+9B1FDD14B20A776EE20F18FDB5A595778724CD68D237057519E58622DB09E9F86D8FDC28
+1F5FC5BDA84BBB46836244A7510737F6FC411F39FC9A6EB3FCB5D9541C7B3410F60AA52E
+FF65CD9C4D20B21CC0E16A7DF3800DABF3475105AFAF14D2CBFE8C4A0CB98910441699B4
+B7419F0F91E4E7E68F6AE3640B4E82A52856FEC5D51863D14CC9A7E54DFC3F18EA6FE05B
+DDA764A8FFB62408BA412567BCD78692A562E309C2DBCD900AC231610AB97A7701B98440
+5EAB031BD3922A9B29AA0A38BA410AC99CCA246E324FA59BF265924EB41343043C2D8CCB
+FFE1F6EE81437B8C256179A5A69D7C0BAE4F13C59D7356B0FC9878D14CC9F1882E68EFB5
+0B324F590A76A19F01520AFE617A6ED645A9BBB0D4AEF69A01099C2F7F93382700E3C7C1
+2862E5289B66EAAB1DBE13802C29D11452A82968592995686EB09AC67B64CAC41E9177B1
+1A21741097ED55CB5F383DCE927C5EE5FCC13B261589586DCB03ACF7E74C67606A71E235
+A335469B97FDB6DA8613437685ECE63BED792266DB50ECAFBF082DEFE04803CCCAC08B1F
+47D3EEE82D635A9F97975EFD80A316371ADF86031250077B1CC0F403845FAA306ECCAC14
+A194E85663252D9FAEA449B2A2AC2C76EF828F9EEA8556CA4057EE0BEF356C1DCC76308F
+05CD254A737EAFDF2912E74C38C3617EDAE3969A03B01AB3254C909B93979E6226E20D48
+69B44FE0F9D8002A02ED206544DD099567DDA0489BD957DC14818C7CC1264D405BCC9E9D
+A31BA99C5A695E106794694B7FF847497FC8A7E961C57CE3959D71253007B8C2A6733FCC
+B6E43863F782DC8D37C60A226D46AFB6176C9507C7837C1DD2E23559FA1377794CC32079
+90FD6E0EAB77096F8C4896081B5203495207EE8CFCE63AF48840778C1DE08A449953DF83
+D5EC0B82593EF1D059D2C5B9350F21AE58BAB03F57A4CCDD4D4CD8CAF475E0315CA8612A
+C3E66CC597DFD5F4F53BC6788B84C1E2E8A8AD02FEE9D9D5F7471508D7E3F447F55EB1D9
+D54EE8207131F8FB5B2A394C0C08F35E8F93AC9E0D0F93A77C28F9FDE8990CAB8E3908FF
+EB8DC0EFCC98F88315E0DA33B6C6B4B50B17661DE788C1A874BCD2407C3047DC79DD6650
+B6908207965CB5BF7E7B83A7030D30D3799F406C9875E3CFA9A42401CA2C7115B1446472
+4D38382EAD16C042B8F2B352F6A9FC7FBC2E488BE6A2D97FBC1E643FE4CDA2097253798A
+D26DDBD706E4CBC5661BD87E5E488960F643A960E9DE3891163276B377FF96D9D2E93B81
+17DEC91E5D3BA80B14A699C56E8F48DA2EE0A8DFC2C981B106C70E0766CC379D97653EE5
+465EED2B6FEE0C1CD2F4776D30E08EEAFCC427D6420F516F9F0CB3C060659C4CADAAAD94
+40B3FF65406F49F4174C2B0C606A3B03A8BE0F7767139539BDC38B93965ED44BE4E2A53A
+149EE0D512D37958A9BC369452B6A121DFA0BAAEC6E9F6E00533AD6EF857E662C7FF4AF4
+5B7732E3C5A037E3A752682EBA6976330FF3FC1CC6271EB7B2024D2B00386A8A5737F052
+F98A223E309E457645E4D1C91B59E827C451D0CF32DC3B3D725BF5E325F9D2CC1994C319
+2B4C1D05BDCB87122F41D6F72A762FA45509074D76A32974ED953C5257F9EA335152E96C
+1EAD2DFC8B7A85B5DDA1975EA400EF5DEA8F43C82EF663D3E5E122D4EB1C67E7E16CEA46
+F12D63DFECB85A84C7B77637FD330F89503DB4B342124ADE972AA14D81F492A5695225D4
+39A6EDB80209D1A49A7B393D00C1B5429DEE9D81EE2E7570A5E244E6457612C61E3869BD
+772FB5CCCE59811D7CF516105765ACE6B68061B1B411FE664C84A767F66238231C96159A
+21C3CBFEDF73F3B56A25264CD5FCFE91C36977A683B369716D6525FDC97E5D2828F26961
+292D8D5F7279E6C0C87F89827B1ED97187E3EB9E3ED021F23DF98790F5095C6063E144B5
+34FB190D15B1DED675CF8CF5C8FDA3434844ED1BB8E1D93F43D5829E6603AB001D423EA8
+279972CCF3AFB4BF776483A41C607AF581B1031E6DA4D716B7876D7785FA7DA4C74DE445
+33EE4B832B5B27154617AE7C5E32F4CDBEFA77290FE45D80011C0E7BF5BDE91A63708F0A
+FAC6D6AFF5FE1EEB23C187EF486BE3E8EB042616A4763634BE5B4CF31417D6B7A807A3F3
+C3A6F6C285A7C7BD46AB63CA1F9BBE01A4E8E98E4CB44D2F26CCB99A85402F0A474E531D
+9675475FA6F06A7347FD8FA30BFA67ADACCECA881CF703E2E15D8585A9EFE607E311922B
+D9F0F8B7715021C9A90986D4C0E681F024CD13CD38A34DC8415FB96E6DEBA849D1CFD157
+181439E3C004ACF2D5E7C40F2366A89977662CC8D0C0CE03E77F77696871B7BCF85DEF44
+9F1DFD9A9B4F68B870A1ACEAB20CD407A27C5B75533A08CDDF6D0C97650EC5FD4AC0208E
+07C59FA798DFD38FB86AF3E71503F76634DFB15F6323927C87AFDFA9178D71391DC51E76
+75BC787B749BB53926B0BA5FDCFFB241AE27B036C586CCCCFA0896D78A63578A986E329B
+DA9F0E5EB0C5C1DEF06FD3667910600941AA707EF6EA9ACCF721C8DCF7760BFA32E3D5CB
+86E79CF66DE28D80CFF83950238BA7EAF551FC3A8E4EE0302C840E7FA11D2F1BBBEA8EEE
+94C313EB4B47975CFDB214B3134711BCD1F2E3ABDF11E591E9EABFF57C226CA83B3DBAE9
+DD3FC6F2C3C4777E9B5479A7E904D0E1F7D36CDFF6B32323E4218F8CFD5EF467865B2636
+81FFD990E58EA69595D4D86F2122C52BBFB43650FA8145B1B6AF095541123E31E99B3981
+A701C47091FA0C752499D2754E3D6A2E3322730CFA4EABB60807FC81AB82D6A4C81949EE
+75B45A30EFAD61F1984993AB44AE604BB045120D01CCC85B0EB54302E05AF8B5FAAEF675
+62057457ED730857620073F014DB40BDA7E41941A3FCB28A9EB2DA319C3193A90030F0CC
+0DE63B94B68E7548B709AE50267036A770646EF39C64B31DB865D12A60E502DB4EB11C5F
+F784708E3F670FEBB1888296C3753D690EB6D9ED17216471CD3C4D5FB8F3F6DA866E326C
+58E8E892A3E6BF60ACD586D6CC8A0C984EB030E4C5E1883B78C4A04ABACD295FA292830F
+2884504E35363BF69D7B2F16E43F5B94CF2CA934185C684B1F87108B58C0FA15F75F48AA
+A03892283FD1FAB239D5A09BFA310E59F2244FEF8481E1494A263EC2E3D4CC5ABAE4E37B
+D73F74559FF9B32EC960E5689C3E86033F1D20210FC448143FEF0C77809CF789F6B8A55C
+F383BE3D85B82DEDFE4DC4480C508325A5D28216C097BEF9893103004E551D0516E05B33
+1408028C881732A82151E3572C279972EE0DA66503B2A7A7E450F1A4866B9FD0215B7BA4
+84C0E5B95276E6FCC43896D4222EC7ED7CA5A4D873D0E80523DA60CFED59C07C7704072B
+8D988611AB4CE42D6F85CF336CD7FBDB4FD1B13BEF8D97BE6355EFBFC2F53E7D59E257B0
+F71B620746A03C7D7C5B2CCE57177F16490074171B8DC509297CD5E43B498F86C2BCB119
+8C408DC0DDC294DD2253FFC5B03DA71DBF93E8BF8E2AB316D852369AF766C92CB2C82CFF
+4F9247BF252C7712AE3978F76F78AD8C9002426B3736257E92CED2337961A693797AD3A7
+3138CA2489CC0E2AF826E4DDEBBB1C1C2F07C6B98C721A0519A2CA6DBF7AA6CC5C1184AA
+E5A05AD35274696A805327F95544D71747E356D5C1B83431FD8CE05F0378CA6BAA36E7F6
+8CCDA7246655D8866D21E21E63B23440457B8863118B7080AA83318B32D45756D17AAF29
+20A7DCA29679F76FEF9C33D543E54460506CF9254E16656E033D7558A09FE3BDAB6A283F
+0A881A67E3FF025A92F37748527EC24A7337AAA5B6254A5F95FEE2380125D05A25A9BA64
+4E60FBC4C25C2AAC69CDAC16ED0D79188DEFF61692D56DD91481D11F6B6AF7C86CE24BA3
+761E2380974ED69FEBECB22EED4C4E244C635C52E0B162A79C948592CC6BFDDBCA26C8AD
+D9A35E6EDC3D659EAFDE4C4F430133C337461E97D2460BB6C8C2550A500433C5F96EC312
+3044426764FD9EA134359F414F59105A3705DB72BB3199B0CF9240979119D7E0FC27BC13
+849501B45F654ED63F93B6D74590BDA5A019A93A397A59E9B8A41E5F61219F5884390F12
+321281D125799406F9E234F1133BEECAF2EA304AB4C313C902214FB7D7993723772C39CB
+0127B4E82830DE0B9A7D60FB452F70F90ED4CD2D2628A132816ADED99B9F355D20313F71
+1B0586F2A20C90705BBE628F2C9720534FE780FF3EC15DE762EDFC86ECE91A1A9E530C54
+56A887921523806EFAB6E9E397838087921945D0EFDAD8EAD7D27E3C24B4BCEF2C8B92C9
+06A725065BB42F0DE1653DF32C802EE2EC33EBE5FFB0470AE8AEAEF3119ECA6FA4728AF2
+CEED07C5F5024A27EB62475A8254E8DD444685EBC545BCEFF63FBC285208350AF5065CDB
+466FBAB8540D8679430793A202CDB44EEA4082A36797F4308F037F64739247389189E303
+F31A1AF0C1780FD9AADC74528533AC6EEACE64E043E09EC5BE365D706FBCB09338597286
+30962CBE409AEBA4142B80C11603B4276DF35E15E62CD9478711D2CC8454561B687C2463
+9F68BBE2659168C72BF87743E758D33649ABDF6A7A4F42F625B2F83A4F141CFFF14A661C
+9DA1E1D045F6891F82EF2E548E11497164235049BD3E3CE707E99874DFCF2E912DC431F3
+7F9894E3C7BA894BF1677FA0F392BA9FB652BC93D898501C5E6B4E20FA8AC7CE6FDC9AC1
+D86723440BF06D420E78F5B32BEE9BE5DCAE455DF6EF63128622CD90C39B46CB9EE4F45D
+72A5EB1512EDCB4DB7220E561160941421D6860979A039B9E5D5706126A3D65BB8F46740
+2332E34E1709298538D20F5BFD178A2AF0391E93672D1BDACAA87CAD9C13873C98B3BFE1
+D28D783690420FC7A88F50241EDF64BCAC2B64E2B0BEF2B5C646318674EAEB1A15D431D2
+1678A73D2165F9A356E648D47FB6B7B5A889391E194BF80550962C1E996DDE28AEBB2529
+6508102B534332948DE46D92DEA56C8D19A08FAD37A646BE88C0B6178F72FFA422F33D81
+D5C4F69504B96A0CC6FF3F4525E0F78BF4F1B27D7970FF1B2F9703952C823C0E99BBA0E6
+63E413EDA3C4ED453176723D3B91683DA70365774570A5E36C40CEFAF29BB91948820395
+B60D780E7EFF9BF0C7496905628CD5084A34D852EC665C81497DDAE2D38594C8556937E3
+FC505A281C3B582A9288EBC36E39B8A1148AE6B29B265016DBBEE8DDA7B0E9C7EFF37B87
+2E95507CCD7FEF306906F05B7FF2387A2AD253178616AFC3BE56667A9B1875C81D960245
+54B5B785D210EB8285BCA0D3462CB40CC8A7310567AB5C1ACFCF279EDC74DFC8863A0441
+897C6FC2C12B875832FC9CEAEF57543C65AE75987834B1C2ED9FCB266A9B8703C2F53E69
+3375F4BAC0C609D464FC164426B01930746D0C66516E02FA50A95B742A7117DD03D67414
+D40A0E37D0C9340181B3D689A09898DA6B4EBF8B9D022DEF18DCBB58D2AAE351488A28DF
+8C01110345C31A7CCF136CAC367B7609DDF27B64326B1A93D69677314EB62E1603C7E522
+420000203B5A9014148875FFB716CDA3B0EE8558AB8A864DF11BD863A640FFE835E0D469
+F1587F32E5F329C2BAD5B2604B58204B7667397F349D4A5EC7D40F53AC32B5D493F8128C
+295165B31A382D32383E1B45C12992EA246D677319AF5C09E2F540411404949A9825F62B
+5A306FDE4A93720B5067B3433353F3473E078A92F433D8A3E7CDB486131A4EFBA06065A2
+97C4706E1C0049557496AAB1BEA12A9B7BC411608EF41ED6F3EF7288494B9B5B9728066A
+F99B7AFDCF6C245C06FAB5FC1175D9816EB90FF3116A4040CD614F18ED3339C5828BC121
+550D55A8595E4E679F37A744926179453C7E27190D64F3284656CE7C0D334A7420275903
+F9C0889248ACDA0D646C1885FE98F4E2E9DA8353852DCDDC9A36DD4359723FBDD1FC3334
+E4F49C07F30DED223A031BB54AC966DA65C9979D32FA1F3E9B2F46EE773891A4CD8A9BD4
+EF1AF2763F1BB5A3F9067317D9B5BAB7C622F974A3DA0934EBA78E353E220C29FECF3541
+528AC86A4EE2F73AC9D38FEE530D517C00CF43377D607942F881613C9BE20B59D48AE852
+31E81B23EC531003D7505E6584FF64CE940DBF2DB3742B142A20B1C8B6AA07D9538D4E16
+B70AD1D7C07EE5BA566876C92F548A643A158096AE000A8C6E1948D46AF2FE91AA3587D9
+F39E0315C506F739461E8B73ADFD18B15285A15A6161491B7CD85F80C1C7240E35BA7FFA
+40876F878B468DF1B50EC980FBC4C8C62BB16DC81A38A21ED69CD2AEA4A56B093BA9FC57
+1EEF14D429176852D4CB3762BA789C741EFC39C26606E93BD525C2850E99822BE0DA5CA8
+CB749B6A650ABE24C3667428E8DB1C790ACF96E0D4B48441B019D29D85AAD46F3FC6BB14
+8DC9DFFA73A5C6B041C48A60616850C31D1F648757E4ADD8AC4B6EACAA801A88D3043842
+6352AC493AD6D01C83BAA2B645217F62E167B30964B8493EBE3D5370EDECA3F75193416A
+C763EC9318BB4A8651D858AFD090692FE0F3114698F8F7E729C5F0C20BE9EEF9E12AFA46
+8B77608629D6E5D5269898206BD5BB4D6BB72D97A959E793984D26012E4C5BF4B3D70C7F
+43AB875FBC17E8CD19E0E56EE012782E73DC04B62B806142265938B4FB9B366B109921E5
+353E29F046F530734E2E312E953708B41884E50A0B4A7D2BA9A8132BE0FCF7FF5E37F0AE
+7FB48513B73D346FCD60996A2ABC8659A8E93CF9A0E1135BBC4A438E71813F2C217744EA
+4D42E3DB03AE3038CD53F8FEDDCDEDBAE5C69D7EBF6DD4A41A1510A12358D5DA5F98AC07
+DFB9C648B5A72AC100480E34D38B897E9390E223C1E057FC09AA828D2524CFEB0B36E2F4
+794FF8D66E9734AF0559123BB70725C1B466E5230C8BEDB01B073C10F4011D7C0F6F2814
+60A76371335A96AD7469C7C7012A3AF9E1BF900B64384B1FB1804CEA27DC37DCBB64B8EF
+98BC8179AF176295DAE271D686E87D3B9DC68C138FB4F7E2FDD5962B35DC6FD46DD24242
+CC30107200FE6F7730D33F274B6E532FE791EBA9AA79E4049D3E406C74CE152AE8FD1BAA
+96920AB1EB2CCEF4D3E3F58DD499C8458CAEC9FE7F1E91DFB25BEFB7EC37E53EA6A524F0
+6D22F8403643F13063D750BFE2CC05C32380A92172F9071F5B526764B3B98EA9246387A6
+09DB489CCAC4B35B07FCF17955B42ACEE5656DD90B6746EB8D11A8C43AAD98AE1EFF5751
+F313B455A66D646D83D4055FEF177C96DDB064BB5E6F880935CF01D146A8C792757F0CCC
+25F3FF24869BA74D81DD1572901F099C6FEEC45992B8DBB77043A0527F628ABEE2DAEE4B
+EAE37E89071761307BFE39AFF657DAC83DBAD2C5F602917213DB0C5D4A9604F37DF37C3C
+49FF2FF5CB143505FCCB025002F292789FA6690B573DF46E2DD0DCCAF4F5E4369075E359
+5B999C19872053E9930701583E88627BCA93A11BF22CC6F45F440CE2FD768CD93B64ECD5
+4916B0764C459A2689A72E147AE9E66995BF88E4EB0DE2B9067D0FBAAA1658620F4B8F3C
+5B469F5543F02D4DCFFBA5071BBA25C7D025C1635C5F5E2F72A850C3E5F63978689C3D55
+4F139D38F8F28E79D6C96AD77F03BB29A928F5C81FCAB3406BB16B427E26DD0394634FB1
+1134F07F316FAAEC79F04BAA0F2CC7D8BE3E76805500A40DB647A3AB774DD011C6D2D65F
+03B4F2A45079ECE8831C28A4EB68F462561CF76650BD8000FB8971FF4ABD066FFA0C1E74
+6D21E35ACDE42E376A6C6488602674C537CDCF5F163101D4AEE68F0688E16337454C4CC6
+07D2BF89342B8F38438B6E4F142BC7496E17F12F7D241FE0653E8F1AA12BF5E2F91F6886
+20870CC5794A56888CC248E076DBC743CAB5B43D784D9C576755750C79F3116BAF053ED6
+659D9F02375AF7D017CE1DD368481271F3959A5F84F49B1D0C796F547A5DF8551908E48B
+65E05E8DA081C69CFC95FD9889148A5594C1C839EC62D9D12A20B39D4163C193843F829E
+6FA88926D80FBA23988EE8A69544A3B6D72D7B87716A963B4A9498E11893F19395D7DC37
+83FBE1AEDCB3ED86AFF660A4D3E25FA7F21848C1A8815334D443269EB21DBD8794A744B9
+7C9BA089AE6D1F3AC68615EC11DC1A6FDE19B1D732BE963890C6DE995CB4184614B3741B
+A64842BA7486D4774D90FF43CAD4A6D8AB1BA46E0EB7A8812BB1D973F13DB24A043124FE
+60C9C97151A8B582BDA433FFA3B9F734EEA35F1B86674150A50F75543D3BA208743F0978
+C6532B70CF70FD58BAE0B3EF4157279C6E9CA885CD1CEB3694A286993A238AFD737D34E0
+585C5396C21991883B928672AF8E7060F41EB9D955C2F3BBF7378E52964BB318920778EF
+A1EF42EA6D8C53508A79C1DE7D85E0C9A292B820EF3FCF714BB533423A60BA1D5A084A35
+CE918A6867A12FD0C3B3BFD50BB025AA2B304EA290544A2758FACF6BC401A0391B070F24
+C3777E8D5DD438F24CCC919DA93C2D548A2279FAD56A845F4CE6A9912A77B202DCC77F45
+4A3B3BA11741E32D2D1C4F824978A078FEE972A6646FCB3843C655DB8FC065D66434DF6E
+F46BBA42413CA88FAA9F0B2FFD2D753D6B891D8A6B75AE8189123A0DB91B971C00300F5B
+CFC2387EAF61C367C981BFF3F0BFB148227E9A7DE7299DE595B027970CCBB78B0C524CC1
+DA29C98A769081FF8B2EAD1D01A97FB975C084784F33109CE38732F4B7BC2E89E38F7C22
+7E295B9D644CCDF0C3F899203C33DEEA916EE508679BC12117140BF786E118733EF50B94
+E8547E486E9BEEA26D42565201E05B4F7354989423115D89BEB2F1596F2458D7F248483D
+7E1B4E359D679B0F4E1B2C73EC3C37373AEDC75723340A07B4BB35C820D69B0550BFE3B4
+24B44BF1C627C21EA62F4D81E59AE4FF9EE17315064544BA9908A49492439F5F4CA58F3B
+82923CD1045F2A43449ED3BC3FE872A89A470857B1B0FFEB942D08B41E80EA5CD66FACE9
+94559A4A143270F8CCC95D2880C2206E0BA08216A85966E084F061B13887EEE5D335DEF2
+B872D0816C8923B106A629E90ABBC2016A819DB95E63CD4C7B56FE64A917915FB3E9E16A
+E1E74DC608F123DC565D6AA5839F8FCEDCA33258DD1F2471C787E8DEF9FB417D33225428
+874680419E9DBB9479530B26C4385F3FBA517222155729798049856C640C8745A7212A4B
+E7473EEF586E548BDD5ABFB34EFABE513FF7EC3E28CBD7521C8AB00FC7162D85E7D9515D
+E56C53B4BC1FF18CAD6DCDF28317F32F5DC5A2D9F3B15616165F15D7757A05C4A7187384
+1261A65046B57EEFDB367EE48468EB4BEBD7A67368DF534C217E3CFB16F15CA97B986922
+B078C7B76E634EAC55BC29D2376AE295D49C9916F562ADD7823E23EC90CBE7395919DBB4
+6B5E21E56F9A5B204BF0662F68C49E9303623D847763A1AC888D00D7ABCF34C3401D2EE1
+59005343EE15EFB9D5A5A1D330A8D5EB442A1BB47C523A18F4733B76373FA37AF4234363
+03EC4BED56C72AB6316966E2FCB2363FF2D4CA597E68BCC3FE3F139C272C7454B85E9FD9
+E23D8B6A38159E91B587C2B5F01D75817B75315B989E85D71E52CA4F13497F8A11C207D0
+89FD55A01D3251D7553AF6BD067A65158DAA766E24AF513B5711A0AB231087315A3D97C1
+2B5E790F4488FDA7EDCD02DBC2FCE692DB6D56F16BBA576687769642F0169DC57DFD04F2
+FF63861E7C03F841F84AD6C096A57520694E536A26A19D977AF1DA8793C7434764FC12B5
+16BBCB418F59C91ED4BE658224960F0DB0C95879A591F94DC288FD475A32079D31E6C41E
+808FA8D9968817012620E7F30F14B2C1C0A5BE47E647832CF3334F68F4CA0CF338223262
+1A0478FA29D7D90CFCF76D83F39E44A4A878000A6A252BDECE5DA448EEEF21A63695323E
+9C69DAD5E67438DE4F7B20B6B0A035751A39FFBD912F4EFA1713546D0156C53BD3F3BFB3
+AD47F99BA96E0234178A7E980830ABDC6E8C5CE38CF0CC56570447291D422D9ACA5CD12D
+D4444402FE14825BA95670755422399CE362805AFD38C923358F5DB8BF1078C3FC6AB6CA
+E3B057B7760CD16F2EFADE9EA0D40D6296E4BDEB33AD023109148BAEB6307D20AD3F8A77
+F5063C8319ECF4E56586C12982AB630890FFB2158AD97B5AFDEC586DE615E8304FCA1C52
+0369FEBC2C9EEE9068A6DEAC05706FE7E024E8254C4CE5C7404DE853DAEA209E7D067F88
+571FEF20076CF19D6CACD0D29B43E04E132D40C0FEC8FD4FA9A7621BD18215BE346A0F5F
+C6DC05175753865A2D987B947FEDE67B23FE2D3635C357633D57C90C41923F889541D703
+9399785BAA6EF2ADBFA1940227CFEF4448BA652201223FAC24CF955B98087C4CA2664263
+BE8746DFC29FA5DEA877AF83897FE2B068B061B5C05871FA675C449654E6AEAD3A8F896A
+A3588948271FB7F9CD953144CD070DEF9F6CF516C8AD51B47B87766087329889670AB278
+9CF4A2552225A1C997BEE8C3D9FE338609022837E306282A21867ADCD56FA9763D34A547
+8C7C7570B19D04D6164EADCE146E617C85A122E9265746EF9A929CD2A9E341095C7E646D
+95D437FD5BE233E352B27BD9A19D0FAE0FF524257DCDA23C6D5AADF460EE7358D4490D7B
+9DBD68A72EBDF1D266BC974D7F56D3C89850C024CEE759D09214108D6916D34B407E62AD
+89B402AC74F74EF4C0E96569977627C9BB63B6C6F536D1A9CB279B636EDE90A804F32254
+DC167ACDEAF8778B164E36ED23DB890438AEB44487E3355E536835BE443021621DCA9E4C
+8C39A54F4B7C28716329997C1B0BE5CB5FFFC7E99724D5D8C829783D156155639D79DBF1
+FDBF3082B62BCD5A3A04BDD2D94BAFB7BB997ED0A6524DBB227EFB29BD49A240CBF7644B
+AFA665795211AA5735F435336C88EEE7972E94505873F66EA6657AE8A1480119EC9896EC
+EB6C9250F5BE682193B4CF0C9CBAF146D2A61C895BE6518CDEEA1E460EA8119433685E51
+87CC18A77BAFB8C8C411EEE0CC655631E7ECFDCE6C59B397C9D568D0EAF9C6C540E508AD
+3CEC230FFC326F1D9570218D51591C335D89BED38711EDDACE3FDB2F667B1107EB410283
+61F09D4082975C1EC481504D446B0284D017F96B94FA8875B08B11CE175C1CDE5D0CC9BC
+93202FF57BACADCAE11ED701021E7720B88A78AFDDD6D71409E4DE4EB766970C87E3D900
+76EAD2457BD9D819B99CC7B0AE137CC3E018F0EC1450E91D2ED5BDB94D86BB77BA4F291D
+8DC1443FDD001C7EB25B09208B92FA8EA31CD9D0A6DB0059C0B4643D898CD15CDDCB211B
+885155CCF420E1C62B867A923C1071D1B4495FC4914D957D3208D4C0EE082C898D74A063
+2B60AB2D9657B9F510BBE6A2B9AC95D1192350183541E598FCD52B811F4543A1CF25A85C
+12F9B4E51CDBB6067286D7B6919EE8BEE3B3B6C55BA28AF9E7604D13148000CC0C1F2619
+DA17AFD8CE1DFE099B7039FE71D8F6439F0E046C72F76E2CE69E7D787C9AD548563517CB
+72B57FBE712261D00FEC755C108E9020548F4B49D805FF248370459EB32985DFF1BFAA2C
+E0EE93D945744965FD6945525C176FD953B5394E521DA5CE283F147FE0A538C74F326BA6
+60D9721EC2A777B3F9047EEE5535159EDA109AB7CD240520DB61BD088FC45F4A0EB42614
+4AFFD87C7C1DF28DA381BA980D2B144708F7E471230DE98BB691D78F4D8A72B8CB519474
+9D392D4CCD79A03DDFB93F8A8163BD07FECD4851EAF615A49607385852857FCE90F3E499
+3056B7E80244FA21F488EFB3341095E684F428574DDAF149AA105863626B4952129CC819
+06D28957E534DDB5C030E718CE15C9561A04BF18A0F3785CA6ADBB5E2CA74C9166D95FC5
+8537624A9B0663B9D4684E64D1C17BA9DE128EBE66E057FD3CE3B5C7AD929640C7B26B71
+48E82F21A36B86664317A1412DA80BDF4C867852BE5E650B772F6DA9919F32B96860783A
+AB469C9C88A0BA958D3986121F396C4D2183D104DB5D0382A846DF7D40E195182CD24C79
+01C1A9E556EB8CCDE58C61E44E7E80F37568AB5858AB86FBFD0711552F0CEBC1F4A4FB1A
+0D55986B73B49D49911008851EFB478C9E93BE7A1AD4E10FE0222432F64329B0B1577D3C
+E603C0B50AEF8FDB39804ECF0B566C2757DF12F65F3AEFEDCAD98A6B9DE485E0E96F3974
+FC7B196065C86992DE0BA6D4CF123A0CDCB94CEEFB8420916000F18B643DCD6A48FA32D9
+F5FA37D93CDFAA1BE4D95FB3D597CAF2EE196814A3B2E30A494C70EA193DF6647D96DF61
+BFCE1C5043899E5D33176B746ED3F555AA0AC6A6057C0D1B2D283C33142114CE60DE0811
+A8816D22DDE6BC1854B6C8930A5FA6496769388FCF338446838C3FD937C391CE06946181
+83051E106A440443F143CCD973B24B9E5D27E384853212CA4AE98C16B49A4A311A7759D3
+41B4497DCE2627B7D6E4FFF124EDC45B2573371C034707AAC8CD3A3F9547534422428B11
+6F840382D0D36802DB6386A9E73B4E3E4D3BBC0FD636A9F21967B1D550D727CB401598DE
+144B1E04B617FBBDE509F475F0F2181C0F0C6C3F49228D0859269839C52FC2018CDEBA3B
+51108199DDC78BD12E55B48B557E07797FC27BD87D41FE591E26F284B3E80C3B6B4C227F
+25562C846B64143CA3864C1974777D33EB196C29B3391D658208C62B8D0679C5A2380B4C
+95CC97B4192EECE50BB950FA8387505E858D309FB172A852DE81ADE4F7B7D1AACEBFE2AD
+6F0106EDED3D7EED9F3827929B54C17364D62141CF95137DBC1EE377FAEC39147CB344B0
+94AFBA1B7A0A82D41E1FC63DAB168534255D02890B465F496A2625CB78E683DF3B64060F
+255876747A24DDC01E0074211C23F8E28DBD6A6A0FE90C42A35983A92EC58F0383124C88
+9FB29494FE686DA32A5140BFB5E34941EE0A436BC5777AC41D188069BAC81E7E5A76CD21
+3D5312E317771DBE5EC3A6A3DDE1BF1176C051E8949CD8AEA5B12D67B8EF50C3ACB62E11
+73B9C04AAD76EF38A14E2974394080439A18C0194676434BF803672E115B12401E2DB0AC
+7DB89D1D784AECCCE8B0B1541D3494A3DD019EEE3600C839B16070F7373244891AA199D4
+5AE86ECC513C403991885AFB8DFE85B21C3290DE9277B6BE583EDF324C3DEDE193B1D568
+9977EF532122FE8592BE4B649B773685A6BB1EEB7C9A7B00F123A4DD784F52A0D0A88FC1
+292AAC4EED21D1669C7BF24448A28405A6D958F702620DF8DEDCD899B7D88D9E8FA886E3
+87E91ED91318B7C0FB7353FBA22DB282D8AE1EDE64EFE64DD31D2CEC0712454C66502976
+2944EEDCB22AE9D3ADA5D9AA6D49004F5FB72CD0C6594D7D51F56FD7DD5FEF94B0CF6CBA
+C823B03E69EB1F5A067C384EEE3021A4EC292CE7A87CE3A068B51DA6C9BC7A5293553DF3
+21226509A3F95ABC67B047D344BA7595A2D6210E748968EAB2999E24CC2041D1FEB1B7D7
+CCDB4FD8E57E1DB84C47F072CF15CB9425FEB8CEBA0C6A7B807CCD6A640C2DA23990BACF
+69E414FDE169EE9DCF25B85463CFB6B1212A980DF38301DD90961CA8B53AC3E6EE9FF9E1
+54A3DCA66C6644F75164B3DEF201C66BE4D54F108A27689C79B0384070151567A306DC4F
+61E6A5400E74429CA8F6CD35DE63EE5D81D30EB252BC34D99255BBDD7333A73531B4176F
+104318299AE0FC04EE26B4B3B70C39AE5D96A968229113A6C9605483A55AAE4E1B4FE4ED
+C3E61E7E416F905BFC6E7B8B982919BDE420725B76E9F3D2C993DF2A9A71B62202595AB0
+A15C1DFE629AECF2BB6362843CC82646B95C88BB074CBD23361008B6A575B19E27A49D26
+CEF1C27B1DC89A9CFA5725E8C886D376166E813DFEC08ADEE5A31660B1882C4115D12B40
+2D62CB4CB1C938D07FCF89E61B352551AC0B0E37837EAF6AC464C58A79068B2C7FD4FC89
+D471C914D867EE903B948B64B0AB8E3F80CB1A70260E84418014FFDC90F20B07E7DF7751
+17432E151473F92B8D7FC93827D2A1F1A204EAB90CC4E493F962FEBD84B816359F4088D6
+3B9B33B4A2CCFCA49AE19EAD91C9A6D3079C1E0A167C874C16741F3A0243A88E45D1F144
+32B31A286B1112DDAB9E816DF3BBFAA348C75305099E610EB9CAEEE570506483383F3681
+C287B3ECC3CB25835A3594604EDC661BEB1E4EFCEDAD9E4B6B09587C4C2810550FA9CB99
+CF035064646F9DFECF48B98DB27A51B26EDBF083A7EA8BC696DE161CC10301FCEAB82E94
+FA5FB6707DA84B83D8007435F44B216B36EF71DA5E490ADE62D61DB7802070FEBEE23F42
+4BBF0521F693EA29A40ABE744C030FB428C52A4CABD3D5E43283958CF3924290884E1198
+E50DEA4BDA72BB3CF95A1FFC8508139A48AECE8FED2704BB2EB8851E3A7132DCD145203C
+CA826F0453C71FC2581AAB287947A14425D928D75307080488E1A30224D933A090857214
+029F05EAC8F5724F146A5E5E6392DA33465082CF2FA942F83BDC6A6870C0585B1339679C
+8619069983A6FD382142C46F2D63E4B129A62216936FFDCEB97A1C5A9575CCA5A1C421C7
+600AF4CF4640A41F6584D73B5B3AE1A8D98DCBB4F3AF7D2E7316588C1B3BD6FB3E1FA8CC
+EC6C8A857374D1383B0C9D1D314A10EDECF095E3A4069E79A94DD59FE72639FB02413D68
+4FEB3ED14BA97F733516C88771DEC6C4F7AAC18160D7F1C85916ED3F69CC6181574D0C2F
+AF7D3E1EFA05EB5084F4F9BF4DFC6A4DA0985918622D90860C8838C5B8EE35B059733381
+EA94BF0FFCEA70FC4EF0AF2BB2B5FC4BAEF9D0CEA3E8516323451D868F723D01E0B78749
+4A69738FB836BFEE328A0A4541A03012D44B4830F174B7E35B0A25086DF34532C428E41C
+83F0814F0F0D52021F42037B4DF2A6759DAD05A346E019A0633745439D835620555BBA5E
+136A950B9BB234C1B3450E58CACDD658FFFD69B8E87D4EAE015F5427452AE657736DE2E0
+D66DFF9E03E20E37B377AE912B90DF242285B89610A55386CB1BFD83652E6BA1DCA7D1AC
+A79748D0C07475ACFC652460785F6D82D1EB593DCBCFF0157856D5799635FA3E129FC93C
+71A23376E61DDE5014964C4554743312A14FBF83FE99739D6C9C45EA465A4B55EFE80045
+D1021AFDDA6E5E13925F3F69A19741615D56991688E0A794DB1534BB43F010A76D4E29C4
+ECD9A16A90A7588DA1C31500FD55E32B2ABA623524B1E4BD40259F5C746EA160C13416E9
+167D2A5507D8D484427C0C5153E0865241A7BE0C298ACB22E5A2BB24AC7F78DB58415206
+F1C435587D4ED941AB7335D0CFA0528409704BC8FDA106CEFD32B77F1D6A02DEE4B05FE7
+3DF87C5D95533B4983A7FD9C3FD2A3C109F9D1719C372B01073C33C5CDA6E20F91EE2F2D
+AC11D4B111E070DD059698CF18553C4A9A8707046A420F9BC6A6C208906987F2F5883E1F
+8EF30E5A9F78BD73AE6C563EB04FD51AC339900528D76C28AE2913FC28C4CF2F585876DA
+472A01FE1934645BA0AEFD5102C2F36362DDFF6EE3B4A12B63CA06698F06A0F25487EE6A
+28CEEC421948B856D0CD999682277ACB8EB94DD7D88F18FED1725C3F0A9545795ACA2B6E
+9C44687395B6EF3B76806A500019CB2A70C07E571100B7FCF486E0D14340DEF49740B1E9
+65ED400EABD0F69E310CBCAE8714030F5776CFDB057AB354CC2F1053F84EB8008F455DC3
+9870CEB793F611999E33B32E64572D46CEB3E64E0881CA70C576E2FC07AC9349EBF26BC5
+6D4E84EA3C835070D0C52A41DF388C8FFC979174084133CCD6639B616A4A20DB37F2A437
+0EF7E9F11A14D28B18076E8321FA194D9070D1D8226B2911595E3567C156BB1624F63635
+24D1F3634A08E48178D1486C48243DF9156D63B32901417626676305F6ECF88998B46F1B
+50AF077104C052E9A20EAE6924DE1DDBDC99FE3305F4BF802ACD8DEBAAF15A3F8879553C
+B1F4B3D7839D6989775507FAC15DF1B0DC95F554B16E0DF685CBDBB41E4A852CF7DC8A96
+8DA449DD5966EED3F7802A7B12A95CEC94DAF052CADC2CA2D84D7A8FD9BD74F90F47991C
+4FB5C5D9342C445E963AF1CAF3E5DF7AA4D483C9F8EF73CFE48C6A25889E3B5B71CA4E4B
+0FF97995BC83939E986AD7F6B379CAD7FD04C46234D8F85A234A878939110DEBDEAE85DC
+636BE2A646F64D9661844FFEF6D22FB15F5B38C129DDF372C3198992CB6C378E8C306739
+012DD4B486CC3148BA4498EA8C0149E59D4AF1E7A0C00E0F94D58CA91C0C4261F459A4B4
+2F8791E72A634D734A3F5DF66AF91FA8ECD4671C67ADDFFD2E2FD30FCC3EFBF0AEBCE786
+DC44B9316B000A73773D1C354964AA129D82722BE5C666D5DAAC7A087F1BDDEBE3FB9AA4
+CA53FB8684F87577A264E607053D5E321108EE9B8CE78600F1986C9F2510C8AE368BF871
+8C8AD6E2864E257E40602D3107ADF63FD9DA46BCDBDB77B5164C43C9F1D0A1E2A50C7C0F
+7BC6B45BEC60EAF2FC74022B8F0463F39CBCCF2B38318C6EB370B7CC45AFB3C1350F2A4B
+48629916CFF777829AE2904FA90C19C748BFC921ED3985BB03DFEC5E9E250321B75723CD
+1AAFE40242C54B182846A979E80024A9E72029A7205F13157E57C5F40951623EF59EE581
+20E1C1F1EC93870BCDF45A74A731DC31CB5EE13F8C568E4C80C7D9ECE815610F215AE88F
+7157CBCE990172AE920EBED45161194EF998C933252599CA45540855A0E4FEA0866C2D41
+8DA00464051D7C0E2E5932D7D80921BD7F6997C9FC550BDD83433D959768C0E35E8750BA
+0AD159CC296B98CA650724BF9693E410AB6106B9D423AA2EE6A47DD102EAC9B74D66858E
+FFA99A6422C9B5B2D466E817E8ABCD4E953A9DF9CBBFFE5748E6F47DCC8831566DCA5EB7
+26B68A5C1C575340F5D034E15209E7A6C5A3284F3720A5C197111539E4D3F4B3392D8F4F
+C400E3CC89544B440BFB258003A6B7EBE045D625BB3166DF4869F2D8CF74EB7303F0AC40
+93C24843BBFCD9A617E2C7BD53572F0B61DF1BCF677B5439B97483C973AE56D0E206FAFC
+1082F9B2D0D5F900F6575BD6E11FD0863577F4CB1277C1D156711DFFA1012EF22725D52D
+0136939EF40B0F661853385E154C8660C3C472618E7115D705CD837DFB7C0EC85F8B0A59
+DD1564378A8CF2B03768B9CC5AD7ECA0DDDD4D405B0DACD6D13468C833DE9DC82271BC80
+E4A6357569407FB09C289458B2ED792D01A9BBC25ECADAA8F2955811145BD3D681834C23
+28C5E3760EA15AA03D3E0C4E67191EFA44E4A4928089E1224BFB0E79B5BA440E036007D5
+32CB8560DD157D60A5A690894208C9FCA54F32FBBF9C9BCB8A3A9ADCFCF2BCA1564290E9
+832C9E79304A223F60B7B58245E65D598EFC1FA06847E1AAAEC8BB3ACB454AB5EEB9265B
+04589BB8FCB5F87576703AA3594B688F5001053D34F17FAE60486EA07E6CBAE2C6358DA6
+AA1E68A556A1E2B1B2DAEC2302FE04241CA53BAB74E4EF219ABB868FD624B519C70EAB34
+B5A953F17AEB07E867B4317B48B2DAC162B6A9EBFFF4910FFD8A96BDF6E501030928E380
+A6277590835C01A704FAF9C32907990804D0A1F70529C09742422B48586C8762D5E8871A
+F91527187537526FA52601116969BCF7C4FF8A22446A184E9CAC17AF709489FA39D372A6
+6C3D580B183D1AFBD6A21736DE9A09F2968AE69FB587F4FBF7BF281DA926F6F55DB0430B
+B45CFEBC493195A1B98F68A514C64483E30F22A7DAD69FA38ABC4B51110560DF23517214
+081F999A3F1D415D8993C940BC40C481F77402B51E7573801DBE672A8739BE239923B996
+23B97992EE35B62734095822B8331F69EEF8BD26FE6A6FCC0F6524CE9BEEFBF40D70DCAC
+49BCA97837DD526C105AE9624303C120407740601B1808D28F311B42B2EC20E1FDABFF13
+2DC42A1EA01827AC85F44F4E24C9B72BC9EC17361053BFEEA913CA872A24FCAD6415C77E
+59FBC9182B6E931C0580BAFE050432866D75828FBDC44889A794C63F0855E75CB056F36A
+A4F5F72D64E5AC055EAC800972934F2534FBB67469E7E41FB8F5819D03ACCCDEE81EF213
+0E1A4FD88BC7074BFD5D83FEEC51C9D1AFA13EDAC699B3DE2595C88525891F2179D8A0A3
+650CC93EC86F1B79D135BCDF82E797480322E4115A5DF19F16DF7C2557D750347CBFF239
+979DBF0DD515FA7B9A12F57670103E579FE7E7A9E0608CA20D0CB3FD1862E99248035DF7
+008C5972B216D066B473085B42AE54AE3C4651E4961F412E7702535F351F4273A97414A5
+3FF91785AA3A90119E4B93B8BA0375207191A2EAF3600CBD3A2ECE12D8EAF640295AFFD8
+83A7779F6DDF812467E38DB5E6B5F1C1DF8B4A0B95BF02E5C5F896936CB4408BF19CB9F5
+58541953A868C07F1FEA9A3EE0CE28BA312C12336E4B1161A934DB4035DF951B428B0320
+5FCAF9201D34DCBA174888CA3EF9D8E708B7CCE5CC95ABA181B7D251BFD9D6B3D7358EDE
+A8A32B7F85C3F2FAA6D2C8D08751CC807E719311621F76D554B7238E9BBE15F19A7102A3
+0F343CC0110F464BBE35CD3920EC3A3EAE89EEF21717ED7015359D47FD7BFD16CE001058
+0B6DCB1BBAC9FCB2EE435D6AF4284B0CFB140CFC4B7BAD83E8A5EDF7C27C3001225D1030
+0F48379F84B62D77D289B6F2CBAB0CB27B5B9F840EE86072FEE3A858A62753BB5550BE8B
+A63CAA5AB5E3756451A79F6A65D6CAB3DB0FC739345392377CCA2661A58AF73837441681
+567C6E81C0C8944033A4F36D599CA915EFE4D03D95C245298D10FA0A5BC9E9569D84E13E
+9653D44C827182AB29339203E578FB73FD1F1354142BF3D553A6720EA72318EE76E226D2
+AC788224721DD4522A247C18ECE489334991DCAE23D459656224ACD39B04DF5ED6A19375
+DA2C2113CB7B8696EB78522BAA320D94A6C04E9CCE17D07C833B6760173F99151D27C561
+61DFAF6BD81FC42872E3DC8BEF1472CD53E32271A997CEA4A057D8CB8DAE15FA7AB150C0
+D92A1A65CA400C436CA993854B8C18D78F1B593139F5F227ABB34E1590A37886467BB263
+14C735651C3245FBB4F620A013D98499BDCF3BFDD6F1923DD9701F295E50E4C3C74DCE02
+571B4F4CB40C06B325AE0D51CF1D9BA0892ED1DE29419E3B8D6BA907B54A96BB67C1EE59
+31E85906AD2C09A9A964401769446BBE07199EC8EA8E3947B5EC31AC7537F93C9CA4FCAD
+771A110F2D3AC7CB6DBFBBC2855F2F360D8EBB53045AAB46D65D206F03E0F4C453FA6169
+1DD1171543A53B89A2353511525EA85A4A825F3BB6BBD2889CFB8696E89902EB0DDB58A2
+279D214EDD2E20E0DC1F06A02B09AE75B20DCD226D353ED6541007905383551B46C2802F
+EEB4AB6DA75C2ABB220E8168268AA384B3D4F8D9CA591B6BADBC27E4CED9B4324B2C4C19
+80ED6D6F7792FFEA1BF7D9F4D5CF6E52120BBAD41C87C749C042EE247978B45A1B30DA2B
+C2785D51B7E02482A095B8D8A3D2132F9C80ABA4508931AF7A99A07C0286144C4F666802
+A68D63210AD70C872F74D40F72547ABA3F4779DB29A4C86633E273B3DE4B5F52759E171F
+C67D16C74D105780E2B85DAA2D13807660CAB1830AEB605CA7577743D01AB9D001A65C75
+95F576940C1D3E48C8F5FF569E6B17954E98284DAA7C062347F0C043D9B71AE0FE0554F1
+D2C8DDA86EE58CDB0D63C974812D902CA525FA81B3332E4A87A5261D6B3FF4FE11F44A1D
+73804F9DEF69D93F195C05C8C16781252FB8DDE0C59687454BA4D7A3CF762DB5AD308A64
+6978CB14A6A8DC6570806D7016E3B7FC0FF01ADC1D983B8A720AA7882DC49442A7D94A6E
+8F01E5DC1201D9D0747A7DE1500D7BAD256BB6992F5B5E1BEC1D88BA81C11F80F994653B
+36586D1EA5B5F805B16438070875630DB4B42B0CD171B152FB6BA57E9A755F80F91AF208
+2832357ED13E723AEC166195D6D88DDDE42571059A5B8667D28F3CEEBF24002360F226B2
+9C6103C47D98A6A330FDB99A0326B702EEC1D3B8A118F98DDD07ADAF1B24470C8C465217
+172119E78D37FA0E679D3F4EB4BD103D821FD839127AF7A26042853B99C89049A7268D82
+DF8079A1D47144010BC562504310AEA3E2FE85D91CE43275B50FDA31256265A4C318E075
+2C7CC99FA1618BC3979A58399060CBD9C4C8C7D5455A63BBC4963336C5BC72ECB5245CB9
+FEB9D399E925F9C67EC1FFAF1B28A1071A58CAA3AF9ADAD934F4D1459FCCFB856644B2E6
+FA6FFE63D48676EEBFCFDC2CCD9EC64B71A30342D364A165AD365F82C9971C565291E1A4
+FB4A40806D264B5A3EA0EDD1DDD6972D5EE5A27D633D546EBD8D3B184D7740E519857AEA
+F8E2108FA525B504780CA54567B09C188D5D960C2CB3AD7FF016955229DDD88BEAC3BB94
+C955A5A27029E2E76FDFCCFA2538DB7FDF8995A4A785630B22EB30AB37722535C95A432D
+04B82EB054DD30227EEE30D77607A4C2BBFCB2F653CA8895DBEF75AEB36BC7A48DAAF131
+193DC36826ACB8F8F33048F223D6BB88DC9FF78BF729C07E70117D205D39EC03A0C89BDD
+926E7CC6664ED8355F2EC41D9B3CA8B4B58A201BBE9535A5620FB6C100D97161F308B01F
+5E9E22428400DC8F41D6CB367BA6E8CD890D0672E8506B4C6CB352AE06BAA26700E74856
+7FCBE12864C32480CA3A1CED87517146FEC7578E3DC027CF2A59A5A09A3CB76657362158
+5A1BD78D218EAC0B318D8C96F2594734AAFABDBB4C2B6927AD5299698366B1BAF03BCAB1
+E9BC91A11A33A1352BD8F7170AE64A116675C3ABB5840114D8E1208D851BA251C88A7764
+A90E769FA91AB807AC6777F777030BA02DED02C2C391B69282AAC1BD8B99F7F9BC778E98
+B2DAA85A3EF8E9DBDDB7887890B0B2310285DE0EDDB6B4628550AD5C2FCA48FEC21F1BDB
+3C6384784EB6557DF3DBF585103EF3B0276C48154823C79224218011DAF0763BAB3A9CE8
+C412D7676245E96BDD47F2E79E126FFD8AD75139B3B37FB13DDEE30FFAE28F7327B859F3
+14E4514546B87FA7FD4FD545872FB0AE4F8AEAC3B882A23DAE3D98098BA60847B013CAC5
+6577FFE3D8A1FAE941DEDCCDC7101E7DFB0B17F0E11100A2947B73FD8A22341639966D6F
+DAEFF59CF0508E01920C167369109507A6E7ECD9CCFC30F7AA87BA0C1C82BD959FF8C43F
+234EC01C7E2B3AAF12F543FCF5C2A2077DF5E0E9E3A976F107BC8E8856427511FD5EA85A
+BE944C72CBBB3DBF4C9870F2EF2FB3398449AED9E345A43E8A6B0A99EDAF4118C89A3612
+CA99B59D4BBF25800E147BCC6CC51D1B3239DBC3A15CE68ECE1F2CDD6D8732238A922C04
+AB8859F9255477B00DB497320B8017AC48BE9C10D2452A82BDCE5C37953D644D50761302
+FD40AF015C8FF79C82015EBD62EDEAF0C0AC637F54F436ACD2D0876390EF02E29A4E3B3F
+59C7B3E1EDB64B75F0DAF5B401015114F226BC68E31187214A69EAE0261DD7DD59B033D9
+311A2F01E44FC47F13927C1C9921A5881F2172CAAC71B0FE038C1B6CE87B04EFA42DD4D3
+65F6249C359F8071BADA34F2BD0A2A2C7B6B8AFA6A1F765AF2A9E77942190D1929EFC2E5
+509B9066CFB90D5D2A4732088CFFCB20A56A3218B020F491688AFC95CF8240EE7B7C38AA
+13CF17FDA80F40DBFD5F92D1185968B43A26D0E38D0C9F91E7226E5BDE34F083FA117E2A
+EF3CA2FE14C63CF404CF833DFBC09E27D96F5A6C16FBDA79DCF00652DC6AB73C4F6548F2
+16C8B245B15D9B5B29746E53FAA0D95E4C0357A3BE36A6CD993AECB9A42828E934A36388
+FB546D8C9D3531EC7B729D44D8AB61975BC7135E5ED59FEE11F12CF5C9C59160DE698385
+778A751CC279F807DD68BD5CF994340A16FF47147F029468C24E6E7AB08C2C69E9A5C5B9
+8C62FF6197C8455BBDB7BE9D069BADCCBE86FEB495B52BF65CF17C4B1157210C98948036
+55444C22444519D8A72A2899C20138698BD646E94748B62C3CCEB35C56837BEF1BDE5B39
+AF2E40A4D73DD747F1429CB4A953F949B97D56DE8601E7F299C218FA0D367559A750802F
+64DA3BC53F83A733B1379AA57CDB1D657C2EE623A9696CFB580CB63902F87B4786A55EA6
+2BDA6CF94FA9CA44F388138020463F5BEEA1E273BD5BED2E9B08B60558D6A2901929C23D
+2E6A61351A5CFA65DF52819D002CF21CE650520436C9681C60D81582D5568A6A0536E236
+26A13B4CD55903D130BFD7EFF26E806768C8EEA16359FD842898B8DC539E3170D4FCF3B8
+72621BD4C65DFD9F7EDDC0B17BB478990673970D4D4A07C7170698D784360F7A6A53768E
+D9B41AB73360FE08C21855615214C91BAEF2F6A5AB71CA45E4B52326EBFB99A0CD401A7E
+2944424878194E14C2BF7D183EA1B4C0BF9A3B2157EDD6143E9E9B30891F1185C3E2942B
+EC87C1EDE03B77FE7CE0D145C0D918D13EB28EE264DC78409D7FADFB03718C6DF7D50A71
+EB216B5735A990274C349119C8739E5505F23C7025A79F4A22FFCC532981D27A70B94A48
+CDEEDE1590A2A0FBE661ED24CEEEC4DFFADA11F6514A8D7C026D2D685B07F9DFAD07147F
+C7EBD82D9A52AAB50D1B52945ADD441A5F3A6C809127457895402C1AA796582950808F4A
+21BE6BD2FE25CB9576AE1640ECDE763FFCFFFDD8096C9AD89B8B2390A2275F224F2FFFEF
+148E4E1F29DB6BEAE998065B0306535D588F901C3904FF47D1428DDF213BB0D9D558006B
+B5F032CEC1BDF4F8997B304CE400EDB24EE46C97DA278E03B768C2A23C88878B9A79DA41
+68175815CD1336A71D57C6E07CC7B8596425C9F8214F0BC2D99400B9FD644C1F8CF0AD3B
+795B074D9D9CF25C18D3847873744228A6AB058D5D213587F16740AB978CE10EC3274FB3
+DD411E0392432D67C9945091AA3D90F95C3AF2B808FFA37B6C6359EA023D1ACB7A007F4D
+5AAD3D9EE2467F5FD642FF3AAB11451EDE32138525FD48DAC480E29A16561A7FAF95759D
+F83FC7504396991BA3CE2072851D7B962FA387A40F62DA05B81B39CFA6123F5B2CF261B4
+C7A84DAF87238729FF71D6F3DCED7CC97CB9C373D6B150C035853167C49368F16E447A18
+0F7F9D4CC3978E3E6B5F3B4CC7FA3078883D4C8BAC0A94E9B69B7CCB94E6D5898EC61A06
+E5A960058E6A1696C0BE287F24869414CA8D16E761C120FF5116A19EBD39109B0E251664
+DB0A5722B4366151759BDBA4A74204893F585A940EB1BCC870873F6F4E08BC88A239F23F
+FC51016CF6F8CA8830346363BBA0E1FF376EB66174CF31ED9AE04219301EBF61A1BB5E55
+A89EEC27A12666287AE6AEA4D45A3706FDED0A70326CB050B6D25FC56216F932C1294E54
+88E3C331627D85B34875E7B51E4E7AF724CDBABB1F14EB6F23088595F2BF26D88C04D4F2
+4B94D94DD47761AA0A9BF649B06F7A2D56D30FC432FB49B570A53280A341BAB378037DEF
+7FDC3B284C83F7CEE6800CBA2E20844A4DF8F2F5400167D136F810A7A739195896E470F9
+5875E669A770691C885365FBBAD1BD8461B005DBDD60891F12D8D4C8D51C8605B3CFED8C
+EFF997868478A6A9D642789127727FA231B4BADFF182AB67B8D19402633BCD4913957BE8
+8F95E11EFB60934E8F26BD79622385F5D1CC5F7F492BD69C8C4BE47D76EE6466880A1885
+F63C3F4C893032D90FA8CCAEF615340A8424B4B1752C9009DD1EE6E0A10A0BE83DCF2CF1
+E746AC5A62FB5809310D5F64A267028A7EF02493B6DF22012D036A19B4AE3A9ED9A5F9C1
+6EA82AFC6DF1DDD7E243B4464FDC28B63DF4CAB59A58949558B1C1B4DD96800A69D14E7F
+9DA1E1FB6DDEF437C2D31493631E79A41AEF27721579C7B40AC30421726959CA6CFC3F65
+5B309D67F0D50DBD33DE84CCB5EEFDC4923A4200341A8B5F9541428A9B6B94CB973BE6A2
+F39DF0CC141B9CAC1D0F25FD087A176D68BF69C6D2BA5084B586B289B00346DADBB42774
+251ABF854004F12EE97092CBEC6BECA5B74F21DB1BB72C9BBD9C0E11CDB4F64F347FCBEE
+AE58924610D8A5ECC6EEACAAD54B36117A2EA580B9D6FB9635EF4ECC1649D1AC8634CD74
+0D01BA7F6F2379AB2BE4425C02198E8E75FB46CC405F706C2E2CEE54582CC08A239A6DF9
+BBD208AD5AB256C5CA2230DDBBAB210FABE5D4582B22F0E66ADF21F4F755D8E16EB071A1
+3EB431CB00EBA9EE617E43AC2E0DF733151A82D3000DE349C9B9E44227CF001D50E6C62D
+A792040A868EB92A635208145CF8C25F51B698BC3460273AE679D251A43D5D1ED8D5D759
+6743700F9B67ADF9E103EE9C2D1727808433DA9D16ABDAE228FB35FADED5D54816E066A1
+8EC29EF2242125D1687D60655B3EBBD8E6227D0CAEC0E0BDB7845914D063890125E568E3
+8B14160794781E8EB631115576CF5A7E9639B02A28CF363720067EB527988EA1D2DDA4DB
+CD35790CD4F91A253D0A9814143492857A320088FB02B28ADE5CCB4BD7878682E2895B07
+7029BEA07B654A13EAC49FC3E9BE70BFEB73418204F9164A26E47632CB0FB20C643A3245
+4777AE40288C6942D4C0C88FAB77120BC73DEA4EF0AC703DFBBE9FE79796671938382F22
+8A9C5B45C48FA131C17BE362EBDEE57378738DBC29297A9B69A7854A6D702524A76573BF
+F76434BE57EA370D43CCED36DD0223939D362102547E2B7896BEADA8F0B3243979B3B4B3
+4F43500473F7C712B5E3B25BBBCEDDD40797649305E5E7AF2B767CB21C93195FA3B2BFC1
+A5891A91CA879BDD643A4A3B384C7A55718BD872E01674336419D2B1EFCBD888FE8FE9EA
+3F07C87A87BEF21E66F8B26D25841401C499B31DF68FF0491E660E40C79E5EC2312BBF1E
+364F6177BDA9DA10DCB347E40C8F423B12700C4C47DA4B09A27CB14310C7EE8DBFA567DB
+0BA6DF2499B5ECE65519504C42B6813E0B906ED94861EFEBD5281DC0531513893F7EBF2B
+9F43022A81ACE291CA736570C6E099A8CCB59D8E7568AA5D18FBBA8986905D35E9B52D59
+1E36EC95612B25F371F2743890AA44974F54814A4BDCC23F5DC100B5584B09A746938953
+B5D519A50D3F1FCE6040918E3CA5E3DDCF5506055FF493A8AD4F8A081BC3524D88336AF1
+80888D96699045EE95F984547B4D9844C9B596CDFBAC8ADB0194B7141DAA0385470F2AD9
+F542FD1369E418C5B380CE40E2461D3B68E091021E21DDC50D96C5578D73B9E84227EA05
+8231936F4264834C133C58D71D347100684A1F3F5A5B461D669B92BD7A00745C98906EB3
+15ACF12D2E94B597940D85CA5B69506661133A6B11BC940ADB550FD9B3FC14499677212F
+B6166E695839DCEA3F1442E2C9E32E28EFAD1678796946725A1C0C62A1EC5972933A8FA0
+D37AD1D8EFDCA892F53962F57906EDF22B55AAAA17562F2F876C0B5C85197FCD583E2A87
+6C28672FB7ACCB063154A1FFC37A33B104AA37C7417F46EE3D4B59BB4E4DDD58A2EFD829
+71275C35081723630CA67016C8BEB30A7441E0BC9A4973888F0A377D7A3ADDE25981BBB8
+036AA2D9B15B71D54A7BC6C8DF79E7D2D50E97F1DB6E796655F47B5E988653996F1D3885
+60BB63A3C364B5AD590A5DB33524282B3C6A7C228EFBFC222FA475FFF99E83EECDCC09C5
+406985D9B3C00199EE2A620A7F820D1DC40353E0A76B46DA672AE1CFE632FA3523C8B32E
+2C0D7344DE9DEB24C7E311E981B216361C401B2C7E135028BA08D3B91D39099DEB9DBB2A
+4050AD37B9B823815BC6AA107A3C7B935BF259D9FECE88232061E4796B425B5BAF4C5E8C
+4E9190E159743D7F3E4AB2191B8EE8877D8936E5D324FB57E6936F8267C015CE6D04291B
+200E1C964660503C96C4A4B782D09F4D3BA952B7EC7AD5B568D27E3A07B26486BC45F394
+128A011F68B0434829C59772C66A001A50FE3C5F2C4683BD81AD8C4B7F7A25127CDE5E2D
+EC216243C2398A1551F8C1E37939FF94CEC8A9C1CBAC52BF6371DE25BE148EB39FCD9552
+3065F034E4F96B1C5D61120DC87D04E7DED973471C0A3FA1E1E6BE6E2F01DC0199399B87
+5EB88A3E4AA85EFC9D9F28B3DC52319D374AA64118E1383A8A577538C29859090DB65026
+4A866725524BEB3FBBBEF6AB74FE8F786D1FA8AD94BE90794AC7E72DB71DF74F577F169D
+F3B310C2D69D729A2DD755AECBC0E463716BA5DCD4680D4D4F4164420F2B46DBCC60BE6D
+A68DA2B2AF32608266241BDA6CF36E132D83D16092DFF4D138BED509909E250DFD9FAE30
+53BE12A825D3A91E404449013E219BC67A2B18E40D497125A2F39BD16824CA7D2A2E5173
+89D69D5D838BA27ABDA5012B426E58456B2399ECB1B4009CFDD6307F6D104647AAD6D083
+A562E7282007B3B2A0B6FB23F2EEBD0E7F643A9BC7075D893335DB246CCBD8A37DC6F1B9
+649AF15271717A769484B5531A1A7D99A43E90490F86C170193442D01EBF02842D349B7A
+580D601534F1EA401D27D98455EC4A5800F4BF5893EE080441F6CD28226E4F6AEDDDB7EE
+7CE77F2BB54FF006967504CCF02F4875EBA2448C00FF58DA77B50A4F4A007663B5B64B18
+702C96AA0E6F85410580F931BBF249E91AF47477EA284CD42572FEA81C462D7E0CB5F81D
+EBB94225776D69B02F04D76B51BAF103B265139F85EBA00F47BACB0A1FAB9D39B648B5CF
+06E58CF1CC43A431315953006CED0FF5701401B01CE4F335015EB6E41DE8D14F1B5C5757
+1371E7875B17C44B374184836C07D47F4FA44F8E49959BA63A4647F757B3837BD334D2A0
+423E620AC5E1C5B18C3A400A8CCB7119C3331812AD8863FC3A97B470293F83CFC37E8BDD
+D2EEE4C5F88423740C93563603FCEC652CD447869112070497A5141CD7DC66F62EB445F2
+DAFE1378B286E730801959EC5FCED464E1BDB06D725970C08CA0ABB730C12C720E219519
+FEF20F96A1B0FA671565B45FCF41A40D5AFBAA092A09F72ED35FE94A98DCF5649F6AA3EB
+FEE7ADE1E19B4429C4E1E76880C398246201CB067D8A734B23BD3118A8F5F7516E5B1452
+72CB0AD9F41ECD8FA61ED0CA87385B2B45B1BBA6CDBD7B9C9890F727BBAF5EA03273E387
+FBFE8D0143D1B215003C9EECFFC9970AD21B0A7E90F56E53B3409E102F89D95B3EC58DF1
+B1C8D48CCF22BEE22EDEDF25CA18A0461D2C582220ED664F198B93B388FD8CA9CAA6D8AC
+95F10E458BE5480C767D6606675208E4C823FAD4A3B8E77915BD881C345B0A8C34F01B75
+2566AE58CF3BC97B215EAAA7189AD6BCE0A524C0998235A61713C538CBE9769E2350F670
+4BA790CF77CE5BABE376D5C2B2F9EB8D90B762BC59D9DEA5234ED14A949B002258212E36
+D5A22B4D847EA8C4171D74B78A5E225E3D956FE7F8B95FA133C50F864725C1B8F11C2D1B
+3AA7D08C0745209E00B98BBE59E463D60C79122469F9ABB8A7CF777BD90999206C83F8CE
+8C95C79993C20CA63CF556C821C8DD3D5124D2F293E5506D9CA515E026223D115DB59D8C
+883FD825FA3EBB449524F1BE7811BE76856A063BAF9C09A3930417DB889B4DFC1563F688
+02F4AE1BA0EFE463FE884CFAFC0FECD0F4396B006B9230D9D3BBE6757318184EE7EB6FE7
+00E148C53CF3FB7DC90811F6D5CC8F9FFF975EC7DDA685B76D05C0320E7C3AB3479D00FA
+927FB3E9E4363115D05E3D62AC3FD06310DFC6117117AD8BCF44233B05901E32D8A1BE67
+CA059C513BA968CA1EFE077CF8D651540EABC16EA1F61AB1D7F74F41EA52E1BAA0A19576
+5547168636187DE931C6F97C624391A212859C3A95F42DC367AACF13BBDD503FC1350FC2
+FC6259B290A18447FBF37284CE1F00DD81929B13F366C0C4FE86E834DFC7FBF5B4DE4D5A
+33D014E3229A7957A112519134F0794825317A8D56EBA39ED15725CD940D974912D4A79D
+C499D3B2DFD7FD67DC7E79F70A04D5AAF40FFA6A568AA4FE042FC2AE31E83F60671CAF60
+B8425E4F3959FADE3947B2DD3438C7B08D71A036B2ED959168D507274BC4C04BC9A9448C
+0385531153595DF90BCCA1EDD889B3C9F3CE3FE63FC858AE51CACCA7160C3296038EDA20
+38625CE0DD5C236F6F18B3B41FB6D5953F18D5FD4F700A95B08BB10431090C652BFAD23B
+D4A9211D0CF59E5C2D0AAC5708386D14F02858C820A191239D08E6121A77A83FE89BF056
+C42A6A56B55EA35DAD6696F64F3B702C21F4D97D87CB80ADF688E6F1094B00714820BA53
+65CD655C9DD5BC030FB2029972D15CA71610085A1A7CA47E290D5554413EB88B70D94881
+1BA89738DBC0C16EB47A3CB6190E191E67004BFBAB73A067501BD283CA816CAB52515721
+4CF005497DC884ED61CD5F5235EDFC207A0E8BE0696E7F93BC267C1CBD85BF4BFBDB755D
+BEB88A7D4B978AC52B7D1AB8D828448F848EB6D2F839AE9F4BBF34E1BD5DE77FA93F23A9
+D111529C49A295893296D10F51BCF03327CF774BB1AC501BD8BCA58F3E82BEF79C39F434
+845435E9DADBEFA2AD5D79D8B0ADED3DAC9C1AD9E6A24B206C9DBBECD552B2E6DF97F864
+C8925A37EEF8718CD4D277949D389959D852977FCF96E2C46477CA973846DD65AF478490
+028CEF70A4290B22C4DD7514F1DB34820656EAABD1FCDB7A9BEE0C18E577D9F27CC50777
+D55B4EEA53E8F681F76D4791300A06C380E57B35FA48314BE3C4A70D1B73E743A2B264F7
+3E3C73CB25FD2D33D74064BA8803858C8353C1036E09EE4489433C92F43ACAE005051DF4
+A89628CD3B3EB9A569AE2DC5EB290715FB1028B2E32BA7BC4C48AF1FAFD94412BC7A036D
+A31924EE68FEB3ED8DB8340154D5757AB86B7D5D37464D58A22B54E37FA9891FE1A54C01
+D7FA05BCED8CA937BBE67979068B177A777B2B315E6B1F77AB6930DE1372A95A0A1A01FE
+C9405011F1F3AA2252EBA22A54C779661AFFD26FDFB10044D8B68277234762FA2ADF8EB6
+B53B75E663976FFBF7D43502184FA7CF047A8CDC2CF0220E542ED63EE9588C41E35496AC
+39715683CED932BDAC827F5CCB9BE1D3BDDEE2D2C900AB23E2B54766DA16CC227E58E53F
+788F5A8880B5FE8A7355DC73B6B26BF783F02E2CCD5F96794DCECAA0E7A603CAF330FF6B
+D8D56153CB4272AACA3DCAA5932B7F754D23BE23B2282F6C2C59B2C1EE4410F342160BCA
+093ED020E4EDD16C7E6E03FBDB06D510E6680A471E3B4E2C4319FC138B92A8EE4058A0D1
+8D7FCC51D9F16E9B74EC75CB482903BFD27C4A17654A6AD85D608558C6A717D47005A8DF
+B52C28282EEF5B9F7DB1086D19021269438BA974CB8C34A8B85C5542519424FDA394E116
+61636091F18BA443113DB75E9FE5C5B8971E8749D15FAB20B90C10D3682102CCC30CFC3B
+67DC2D519C96B9F607B6BAA01FBD8B78236BDCD6EC3536D15BB3A069272C646403BC64F6
+FD55E28988D01DBEEC75547D4D4A975761E5BDBD5E3D7601065C4F9657D3E492DB6A3558
+037943383B261335F01494978F46999DCD5584F7B5DEA427D20F20E29B1D80AEF1E279AB
+F27AB8410172E203B3945F98FF87A2FEE2B89293BE2F5DBD88A200130143D79A5F8943A3
+D0895650BD6CC2FC5D5675B30B12B4E095F2475F7D8788EC9AA952FFC8DACB281EAEF931
+34A6F83920FF8E7C58441BE339ACCBBCD4C9BA4C8EB9A5F6A45614F991D9EB0A76B2C869
+944CBE0D6C0CA4C8BAD0B897328A4D354C60A31AD9EBC0F97835BF4CB7976BDB95152A1E
+919144C60E884BC6E6857496C77C3C7AD9F52C53A9051238011D41F14687E5B3F666CCE4
+86D16F3CDFB9AEDE1CCB3452A68F5FD75FB96600750457E3C3FA6579BF938439AFC75386
+D1C0A1FE73AD6968DE195544F85CFC697793F1F66DE6CBD8137A918B2C24A99724C978F7
+46BF6AECA401F5D298CD1081970FA904F2E2CBB2D749526C2E14A43970B2B2CD28EE9178
+A58F60F7BE3F87967B4C1BEA2ED73DF6692862CE919E3B406480A69CAB794692D0FD1C6A
+65FB1065BCB5AB47306164C0241A6177D8AD8E629C77F84A1AB5CA62B493C5C016AEA0C1
+E45AE05B54646CA6E134B776D09A11FE04953679CFF2777B01370F482CA655CBA8D1F91E
+07D0106FE37E83267B5432ABB51D56C88EDC58A11D8D90FB5E82BC023C4521A6649B9388
+5BA6C0D139C3BDB8B0325CBC27AC4E8F673E53D84476E1632DD4A09E94D375B65B0FA682
+18609F5996F543A985FB6CA55D302D63F86F234F94C9A5A15B0333F722702682424DA956
+1E6614FFBF8A9293F5750E06BDBB05D3BF6F56865577FCC010643699D0AAD5633BE88939
+AE6324C36A7A5FD5F148162952C357C4FA5E8DCBAEEDD28D71A809ADFD563AB3C4CB790D
+8FC41B81784B3E9C672A2F6A2230E90882EA374A579ED2BF72795E84B089635FC4F2B48C
+D51C418BF26AA4939CFF22A0B37182836E70AC08C971EDFB46A31BA11480BB855D53A01F
+5A0688B2CDB04B9C2CF22A63ABCDC965993AEE1DBE2BE79DA4D1BB595E24E87267FF1648
+D7F8E531B275C5499FD4202A948E2DD9FBC7CEF688566DBC53B886A2F9843F94CDECFC63
+78E6937D4CB278E11EE9E2957D8BA31145058010C98A752CF568AAD0FF5C4C67988868ED
+19762F2F54D6D58A3747A6C5A052543ADAF50DE5AEC5DBFE6A2F78F08A50E5F65C328290
+B383524AD0A1A477A9815C8378DDC0CD7E8CDAF6F097E5DD40900B0DD7A7354A37B9D90E
+7C4FFEBFD1DBFBE33B5EBCA7607243A53EA746FFB8CA2D88E73D2696281CB210E6D5A0D8
+46F669F24E3448DAF1DE413B6248564E718D903654ACEBCE09A7CA994306D924535F5792
+21C39D8E386B1573B9B7C26256419D8B52F4980018DCC0001DC87F590C378EC0DCBAB4B1
+8F362A7F64BD16DE2E647A4B0573D92F1300D5D8423A1FC658E708457646CA9585071B72
+E66A2D919AE292B460E816FDC8CCAD369EB90FBAF5BAC731FDE38CE2E45B755934264D8E
+4EABBA7D6C0C91B4444BEC23D8FE44230223BD612D845BF57659A9594168655749D147AD
+CD4182BA77EC41BA34595990446E1D093CA7264512C12DB9EDCC3A2E97B478DA4A2E7A81
+3CCE2592BB816CCED1196A40E76E4B0BD2EEEA1EA7BF331D497548FEE91A56C7C057C3CA
+E25412546FAA9C1B8382F5F01004E506A0DF3BE419B38AA7196EFB6C9B469E49DD63572A
+60FC9A5483CFB723FA04BAE4AD526E8C3B14E252750A79C13D07CC1A1A424B33586F7072
+F28D5C61DBE7F0EB9BF47110B4CB018190CF5BD564CE48B9775FEA3DC1FBB03206573E02
+C60969330F0DAC03A4EEF803D7F860C14C50D809EA5D5FB13001048D2CEC6B56C2423CAA
+EA0FBBC4FDF550F0EA3D921F522A65CCB0E1F590106F163DE12D1410F35D72E7C6168D64
+829F8144C5B7CC9F902081954923AD742954477ADFDD4D321A593A41806C002B02D9DE03
+38DE6B6401408FB03D282489D23B6CD09A77EC31A7EBE000D54150B03A8610D0DB8BBF8B
+9C7E94419C0E522521585F2B7C657CABEEEBA79F2C8FE57C86F593F805945E7DA313B826
+2DC421EFEBA8237EFCF9B054D12CBCD0A3BB32C4A5BAC3E8C105C32860E80FD83F095A20
+AA4497CB6F4A879E5F7AD6C2A8272E937A61BB95402F130A37261569D47A88D4ADB80A1B
+1EE5FF03D8890B212E3508C408EF145C570FE2656ECAB9EF52657A04456B580344FD4F87
+2B5D5308DB567B1E957073892D8F83A2C8F93CCFC11D3965EA0B985B5521C997786CE86A
+3D9E0A3407EC73E51BCBE2B53D11DD304F0B7469E34A5F6904F5B3807A62534D742DBD4D
+3EED49B28F68BBAF5DB1E261ABD0C7739CC09A4779D5D2AB15ED9762FC6E72F78B71DFA3
+23C29D48F47E44A38D87168413E3F589B9470C79EF8A4EB6216F1F0F74FE2853E7EFF2EC
+902018A4F6FAF4CFA75B646447DA90B8DD612A65ECD9504C751D331B3762DD369EB0D179
+CBB70EDADDF73E58919C65DE73497A87B4ACF06360FEE10E7593507C6663B0FD0308C95B
+F21B9ADE7966A23FA4CD0648051F2CC20ADC25C8F983EC2DC97E2160BCC62CE3051273F6
+3D65913AFAC94E548B6BE0BECE2B704778A24C4348F128A4EF617A7F43AA327193B5BE44
+C2045CB1840DF5FB6CDCBE455EECA489E22F0FF715F4FD6D14A874031C58A8446730D0AE
+D36887A4B33DC943FB6A9469AA781FB0E994AAE327A86408D63885662065330B6AC00AEA
+FADA28C53CB4255EA1858ECD3869BD7A27EB5C9949530081E5E103DB50CB34534A4C63BB
+78E91AC992D1D58F2D08E7706D25CE375CD041F049F762B4B20FA9052DB766881540D4FF
+1BD7A4FB927F0A3ECD257938BE91A220D9FA4E00201CC64A1E9816E9D71E95931A5D018F
+0AF2877F2737A7749BDF3C90A1694FB81EA9C970629EDEDB5EBF19A60EDA5D7419F3EC1C
+A51FF1544B23800B0DDE96AD4E5E660AB20AA419182AC33ECE2A48675FB2D74770AAFDBD
+6C300C6360B9B5FF14B7022BE140C05133BD0D848A605491C156D08EA88FD0C4D2334200
+B8437E6088DB32493099469000426A3CDCC627757C9DF0BFA4E9E0CD5D0C8F3E921B1E41
+48CB6D876F445CA4CB9FD7E7FFD4032B2A97EFB025B182A88CA72212186417A5C373B5A4
+3357E58EEAB3FD609C5DFDE96D4BA104C74D69AC17E20058D0B4E875A53F547DEACEBE20
+CF74242301FA39FA6FE6B0C22C5FBEF3DAE3B2727949C20CB8A1CA7A70C7A09E0BF76794
+BD67F51F3D3A1C2005E4DAA6CA87768747DB8A7ED1334F03D3C3EEBD796AF804DB774DBB
+403B4B0F6820033CBC99BDDDBCCBBAF0FE7C56959608DA53BF83A56606CD524D3A80D591
+AEEA4658F0E252308551371D192F88F5D8D58D2B898C494FB23463837B8249B5EA5B1DA3
+12A1CCFDF4234C772102A6F0405227A48F6B216BEE7520409C77C77B8F962977F9DEC1FE
+098EBC19A77E3B155DF2514D4E8087E0CE8D53B272735F463871AB02BEA13B9E402C2239
+73D2B968E55031BF9A929B6468599889CFC84ACC422439464277D86FC347D3681EF42838
+08CE24709A9A3ADF4621805A61E3AE1252051A00A8DE2ECE5DB8D6D415F2648E7FDF4219
+4F8A063187F64980D3216EA297178A6F87395F40DDF9DEC4D649D74736AEAFBA82E7D0C9
+05D44A8E2F02D356741C23DC37F482F54CE53DE8800BDDBCD170B8F089339C7CAFF13A4E
+2D4C4EE33BAF718DAF51BDDA347FD8760F3297CC169112DFAFC9871CE42FF8C29D7A2168
+0C6E23A2FD776240694B44696F69D11454646066BD4B6ED7BF4CF3550BF0F32FCD0ED0BC
+CE20286B8CB1645C308B74D0EF5CFF8927E1F2FAB0366BE55CD069AA7676E4592FD42342
+617A186D3C144D173DDF6E01F5E5E5A67A9648144BBD646BD3D76BE1AF70EEFBEF0361A0
+4BEFEB59E94AA5CE2400907C9FADCFC3633ABB62F24B0980093FEB72977CC3E44AEA7007
+B4721D8B35BA81A01C600FDFC070A29337FDD56DCBA7EF9DF7364E0230500F9B8A075625
+7B12FAA98EF15E011D6A6D02C84655D15AE62181FA4D0CE38A6FD6B2DE4F57B0B963095C
+95536BD7A53D0FB7C1167F251A9C43DE263D68FAD27C6C10ADFB6D02BD1339CEE7DD6EC2
+FAA687A55AC07E279CCDD84F46A6DEEBBB380B1DE2897DC279C784A9E352683352B059B6
+15990972B53695F73097EE77081F23E15DA3B489A9B088C2D7C76B89948F31D68C3F3FC5
+0243D545C56B62CFBF55E1102D9C761E8A7B0F9A547F9B0935CD78E32AFCE9A451C2F455
+DF2DF4117955D9C9B30619FD8A9EF23827E70FF05B55511185288C06668B65BF67CD8C77
+CE1363B83499E455CDF30270842A22F23D101F7CE773BD709D2E9172B169E25C2AF2B64F
+93DABC5C18CF61B30DE7ACF3B7D746EC1B725B90B767D24DB244DC37A42861250A52A287
+F2B7062AC268559A2C231F3A93E510527BDBC3DFC742B457D774C6FC8B023C02E783F2CB
+C50C4D37DD81433BAE0A8A9CFA280E7008C47CD75E1A77242B5C1ADCAF70E3C0F870C126
+197091879369A7B31FEB8086E1733E377DF5AD77358D296D3C1CB2EB54B7DB9C8E5AB4E1
+005A775EFA44328FD755D84A064876CAA2E1016DA7DCC961F2101A8FCB699B73A23CB866
+51E728C07CB9EFF654EC83A5DAF21DCF2F777535680C32E4A88AA2D7D65F166B430CFE51
+9F252F51640D7443D75CCD2F5E8494D1210B3F5BEC029002C754BF6B506B5715601F5134
+B6D95060BAC8F6CFA2249FE4B5DA5B098873CCD2C5A6E983F6C62C3C0A9274899858AE7B
+5364B4434187B91EFB705FAB6372E3A003D5361138EA6AC70C048E7E05E2F319AA81DE1A
+8D1836CD2B049800B991CFEADF399960C02EAFA33CA1D987B161234EF3A67DC53B6FE467
+857D5897446EC2D4C5FE183320F28B74EF3900815A540EB68C325F038A564A23AE235D12
+A475030624FBEAB5A8A536D0011C89AD8557AA5307A5DD4E46AD91FA15B8D6A297DE7717
+0BC90F8C526B6B9496F1D4C83491DD2FDE4CCE06420D943C5104B0C56DC184D8293D9305
+9AD7C5F6251F7AE7C19BD13AC98FCCF587FA9A223082B43F04267535CBAF822F0DF7A642
+7370794C4CE3723238828BC3459A01D8B363A6B9342CB523A13CE1139525AF0C372F8AA9
+98A3E2962BF6728F815D33AA537B8E27ED9174ED4422ECA87BD9E0EFA86566C4314BCFCC
+324D5FB4105E9A965CD258FB0A2B970FE0A21F951F3C86EDC5543B067E2CE337CDC04E30
+EE665A3725A4110E845D9025978D445DE6284A55197735A5C018D99CAAFE6597F3D58D37
+68EEAE6F5428AB3B23B5F2F9E8EFF5D6DDF1B4BEDC6D245E63F2E5DC0911E8CA2A9DB100
+CCC4EB9C54BEB0EEBB2E1027BFBD041DD39B27C151EA50EFCDA46F4273F74C85AA88B1A6
+7BA9A98C7C6D7C406D8B3F7892565B8856C77668B86A0BA9BF743C5884FB94CB729403E9
+28EA9C8ADB060911FC0E3DCB9B828FDC489FBC1F15FC2D75807EE98AFF5D841D88303A7E
+4CB6DAEC1872D384214EC0E3039478DF79CBB7C12202F9F56F3206FE61B04AECBE1D7757
+0CB8A43D3E145B0ADA7CE219CBC99952BF54D734673632B68AEE6CDA8BA19BF7937100A5
+FA294B86F7439FB59E367CEED44FEA1F4CC2FBA570AC2C32FA6D9F67474BCA9318A84A31
+107CA7AE187454434340DB2F3A0B2B41E552EE49E828C20266B88BD04DBE61AC6FF59A8A
+D065A704C18C315CE79A72B061A94558964300564DE5B41B0BA3A0493851A355ACB34BCE
+7FA00DCDF05F3BB733C9C79BE3F83D6103171A648F81BB138B4996B606A7A8A997761548
+08F89BCC7C81BB14F916F8AECD873406778E51BB93E56C25DFEC6C3778AAD6B537E6F488
+D29898E17B5D38BE14ED70D79A62B9282DDF229114C0BF9830F2E18A4717C45BF1B29A76
+31B60D13A283C7F92EC4EA3D98D2331270030A14BF9A8E07D87E66BC034F830DEFFBB5D9
+9E95293C70571BBC4B65E1AA13DDC945815FA79746024F5751F8FFE718D97B8AF465BA54
+598EAD21B323C3CE47AF7BCBA58BCCCFFFA0FD2B463C85DE8D02378C86BA7D3F44C54165
+E00E64FDF7228570A6F94C2A1F8CC5D947A470552302D6B3850EF092D6923FFD39E01F7A
+B0ACC7B6467877CC301A03136B93A57AC0949D62D3F3E63DFBAF695767877516DFA1CBAC
+F68BED7E2AC83C1612F234CB12A368CEE9657C6519908C7B046494842013EF81A4986D38
+58EAAC69D84FF32CC5CCAE2E438DE88A426365EEE0FE9745DB5B7D494C3ADEE8C6C31EAC
+CAEEFC174DE952E2D668BD28D621DF9C81BA0355E943BA3ADFF04721B586C659494D5A36
+985AF4AA408939371F448293A0C04CBE72C558E4DE12B36F823445A2267806836D265BC0
+8B279386DF1579512252A9CC6F69D83959FD3F1FC6057DBF5F28C644AD4862ADBF133C2D
+5779D96F1EB234FE09E0FFC62EDE6D295F19F52A9A6124197CC250EBF77DECDD5F8B024A
+D635E941AC0CB5CA59F6278FE2AE87F7A005A5A9FBDE7609B4DB903112DAB7B612969DF3
+F99F3D34D95467DCBA57E6755BC80C4D18EF9F440A2562DDED104A80D075F8D0C308B10C
+E31B777B438DF32A77433152571170DD44AF096981632062E3F525ECB3697F3EDD316E15
+2E502A9B8B351710611DDB75B710D6CA9801ADFB57EEBE007527611D47C181C3BA7BADC3
+1210B9FAEF3608350D905791F025960862B0B06B4BFCCE7FD92EDA6D9B2FE67206ED53AD
+E69BE630442EAB6BD2977E3BBFF487CB15A7127B40BFA161D8BA602AE211C8E3FCE684C0
+3E4B7E8148C2F61DD65E1D07355B37E62A6BFC70656B4C32FCDC5926EFE37AED5253F67F
+DF9A556956D96848B81A6E11D005984DC36E99F1874803398FA37966B1A37B8282BF9093
+65A1B89C1E1CC37B02254B75C75D77A39F9D1DBFE7B79F70AD0DD6038D824A7DB8DBBD79
+B6A5302D5859D5925B79A210210103791C4212F579EE900CB3FAF002DB06E0ED6D5E74CB
+71ED20AD85A257F1244C79A2B6E703DADBFFBFFD414C1EF6C7A7CC4B12F72811C0F0DFEA
+A4DBCF715812A3E827C06AF347EE1D72F9FBE9BE3D061DB13CE123C71C8341C2F56762A4
+FD0C1CCCEF591D01E7608B097621C45DBCFA96348DA2F80839F0EB6026AF7C14E73E8506
+FC9C1F68C88CBEE385FC280F18D7817A8606FF3FDD506FABBCC72662B0DF81EE90727ED5
+90306DFE6119A9CBC84172C3D434DDE35039F91591837F903585245D0131DADCB710309C
+596B7A8CF8839B2C347C2493234386F988A7066BE6B26F9EC504868915D71E1EB5E9AD4C
+F2C5F71E761B50FCEB823CAD364F3E5F3B1D10BA4916D915ED0040A920C9C9ECF344E685
+2B805F4B1FC9062625BA815ABECC0EE80D708D0BD141681233E5A483FB2DE7DF9B13237B
+649715BACEAB3F4BF6C6403F8460D190C77E4DAEF62F437361F6B9DA9B4787A68DEC88D4
+556111ACAB7C7BB5F2F1933291DF83425C10895A2B47330B661DDFA456F130D91EEE2A4E
+F9AE28D45DCB80DB7322DD6D7E394D475AEE95D0DAC575AE569BF9D26CBA1CFEC9DF25CA
+A1A701F60B297064A17CD878E101FD6A6F981905E50CD52A807B466465F0526BD502F249
+B8C4408C130D017E6238B5B5BFBFBA518BBF414E11E2D25926362F4EC5E83E6C26B19C04
+D68C4D6D891B10773EF156166D9CABB85F08A1C130D9D35351CC9E7E739460EAB51F3F8E
+A011A2CB3354F759E9EB297219157F02BED05B78BCD8C73E3881C835A7D986A3877815FA
+5ADB7713819D931FD05C53FC0C584C45763B6725094485EE3C48E246A1E8968C6DA8979A
+2D12CF4A97A8822BA5A066F62333C313694562FBBD8ED26D32E8D09426D0AFE33BFF61CE
+23F03ADFE9FFF17EC5063381102289356B1696475310DB04806487792F7EF42CCDB4B8F9
+9DE168D16AA56321F29B09EAEDAA9727CDE7DBBEB62F33EC6FF1E9A74696A7F4B15A2684
+968D5CF34F65E88601368BEA29104246000EF93B64098CBB9F26DB4EA1791C48E245109D
+23F39C97F87BE05A31B4AEB6B7A8E49A4648F8A6AA3EB1B80E2A0014CC18A59B43441A81
+D78794CC162D367AC2E22C4985C0EC45B9E29F1D00EFCB898807DF65A3373208127922EE
+E16DB24D335DA01050CED1BE9470624CCBBD978063F6C538F90CED1FF48A83E404FE5DD9
+2DC2DEDB2324409E78583E5C7874A9661480386FDC2FD62329D5BB33AE4B5ADE5FCB9BCD
+B016857AE69032C019ACC0D16E07C92B252C2AD5E2AB2BC9A1BC074EB697D7842AC5F61F
+6832A8942C6BB35E3802123DDF726304D74F10FE22E386C2AEEE158BEC56DBDD264A2321
+1A3D0B53183DB2F74A306D00758DF51ECAE68DD8944FAC719EF56190017CE10DA46066D8
+AA27F9D6B8BE4911E2FE16D77303A58EA4C184BA139F7D39C4B1BE8C72B8104D1FF671BB
+DFB1C1F8E518CAD156D4ABB057B622287CEAEEB574F2C202462FE2575EA7D8CD820FB4C4
+B87F022D732D07DD009845BA831A6E2A248D5ADF9C179276905A494DD35E4F7E581141BF
+AC76849B0F38B5A726049BFC2196C38B6EF6F7A0D38730CF3CF850A689553B7595070858
+97211A03A40B37BFB57363CCA5CDFB04E01759813DF0B67A693FADFD5692DBCBC543DC30
+65192915E654112AF3676DC58854D602C427315FDB2E0624D826BB60B5EBFB4CB190299F
+930D0385629EAF0C0EB37F4C01C5C770BF1F0F825A2A4B6FE50D2DB566D5B7A819FAD0A0
+0E4A7E8686E9FA936C0315622C95735E251FAB0407814B0F2F848860B942A413C7F43239
+C413EFFB4B01C1CF1BB9AD882DF6A3B64B5B7C7F0EB4E707DC5012133AB2493E7C3A88DB
+5D0A51394FC7D6E66ED529D16686537DE3FB1EA7116363C4F5945B344FDF031FDDECDACF
+34F2458908AE0F62E2D200A9B147C1FBC1877FB41DF6979AFA02071312BEE01A786E5EE1
+FF1B4462913540CDB34B783D104BE4071888AAB52177898F5537712D8DA1B09BAA0F094E
+8174BD25333D3043CEC70925961865785A6F81359B7A580D60134A293C8DF73F9896BD62
+809715A8C846915E7E636CEFD18125CDFF15E380A8901B0BD2B7CDFB80916D4839849795
+A7231BDBBFB9858A7834BAC1FF8B8365D9602985E8D8EDF33D04AF77E24525460278EF7F
+03AFD42AEC3F4201F8C56C2F4885F0CE693EA5BF4F62A8CD61F3A7827A1C40FA52228ABC
+8D19EE1089AB3E80336EF6070B9EB31781EB9C6F6E3BF3BAB61443BFB63C08BBADE7E842
+67C6A44128F33D7843DEBBA3BA7E723E91922C437D24A329E72547DE8ADE2C9676C2A078
+A12CAAEAE690A31FA18076FA77BCFD1EFB5762ACE44FDB97FB5219DCF9F542F87A959EA2
+F118162323B46DA8A0C116269D8301850EA28761CC0E5ED06ED48968EBBBACB891CE73FA
+52B7C262C73DAE25843C00923D04893302DC2EA0EEC7A2CBBFD949A3B4135F5AEF66411D
+CDE7856F7FDAA0E630C3BBD42305182E3475589B41461360EE1B72298D97825C499D9F49
+653AD3EACEDB5F9790BECB554A643AF9F1CD3455DD51E79FB0A6221C4FAF81BD822A1BE1
+AB8F8B18E4141787961546744132ECC7F19EB3E81863CB6B3FAB60D3963D6E6F106A2558
+589B07BA69CD18152F8A8B884BB24FF318A071CDC695F6D8DFF7D04E16F0AFE7BF2F03CE
+F6977E0CA4B46C24E22FA22C0B9DA11EDE76B5B511B1DDB6CDE7C314EC86E2B79E1C4FE5
+357797A5EA3373FB14A212440F6CB0821AF449122D94828CC38E44AD6C7C7FA78B932192
+55ACF779D9634B75999314B31F79003E030054010133046C6CA9AF0FF33AEB9E7C63553F
+F34203EEBF0E3F104453C1430A3642E79A4F5D708551C4751C9F4DF3862FA15814A10567
+69516410AA29695690A5DF3E7B407A2E5F05C8DB7AFA0132D5F43177388FCDB17B325990
+1AA479F19C138122AA2EC5674A7D41D85233345FAC3ECBEDE642BE5669128E17DDA2D86E
+34088BB76C64685FF98F01D48175847E0F49E2404E9C5E9F9073F3796DC575468B53F9F7
+39F93EA3FDF18DAC9489FFBB9B18F150CED84E6A4241580023C622129B1A91A8079CA92B
+1A8B26B955986833D3144BB4EA25866AD4B499247D44EF273ACB2F1637F195AE7E89541F
+C6B70C8064F12B696A0C9BB09DED5F41E19914918F7F4834428A01350DDAFF763611C173
+12EB28618542E8EBF479BBF5B120E02ECCF7D3F9638979F0602194DC2512C682FC947B4C
+CD5BE48F0CD4BAF3710BB42195ADC7DA9EAEC09E124D49E7CBAF579616DFAB94961998E1
+4EFD0128982A15580D1A2ACAFC740EAD92FAC43E7FEFB551EB9322A8EA302B573A6C4B90
+87041EEE1D7B60CF1E50A88F59EB46F1DE9F9760F21B8EB325E90B536AD68829FB965237
+5097A06AAC312372A7D3EA7134A53C253505997B4FB2BC25EC2ABC8BAFAEE96BEB6EE940
+A76AEDF4F00EDAE82434B3D5C8B854BFF71EC073A0DE2D98FDA384E4DDB1D84704BAB88E
+DF057C84DE21A1F7C4FA509F1E22C7B8FF788DA95A7215DEE81784B7F47643CB85D08DAF
+425E251EB72FE482CAB41D49389B323E66D27863D719D78C676EC91981B0E516C21942E4
+66804EED7E214B4EED83A1831D925019709A3EB1B2CE62491339DEA3A3890107CC5C486E
+F7A861D7B023B2835A87F62008BCB96748B6037BE07D54A22AA4206C85BF24208016BFDF
+EC4E68D8CA14CCFEC2CE496819159C153610C4521D312B8538FD3AEEC5FEB1021FE9595F
+767ABEE99B952F0AF794FC4D7FB0BA7B8CD73B543ADF833989ECA557EF2FE9E80C786180
+FE2B6249F45440E94C98C00ED7B95EF5AED26A9058826EEFE0377F4CF786450929E290E1
+D89E70679A7BA87CB29FCBE1A79F24A2713D182F1BF990340FD0E00012A25801BC643A9D
+DA70E046D123E7E64B884B0F8024639E055D6F7FAE5CC5108B68125C02EE9EC0C41368E5
+6F869A55ED15563BADF2F88086EAD3E67E8714AC03D2A12B7E99C2947D6422E5F11B74EA
+2CC153B8409A2A03C0AE3AE784AB05475F3D086EBC28089DDCF12C8D4324A8659EDB40DD
+5AE08B2752D196ADBD0E540590A414A6BC6931CD78CF0D78B23080B4D5C5D86B9E4E0EC5
+3D774845DF7C74D07F242655018AAA23E64165DD462F5D2A282B5165096732D55A3946BC
+C00AEFA41085AB8F2B6BD34C065DA2C9C2999903FBF17E9E7E39E874981E9A850504F7D2
+A1B69C85F532C6749BC675FC181CA05F486858C0F22BFEC83F14D4754C3C42F0AE0ADB56
+9A48214A9DBB6D163E528E4DE29157A8E7089EFF2E2AA6AC85AAAE8925CA4A019DC38668
+418C964DDD2EE6F2B92BA48E10789DEC415FA94C81CB95093F71BA384081A7A01D3C2DBB
+A934E37E27B4232C8A3802CAB57BE8BC899635B620F54FA5639EA9BFAA5294E57856664B
+B3B3DFBE40DFA0E09A14ED2DBE9C47CB032A86D9482D29959E21FE32CEBAB87FBEA9D283
+7044E2161D62CCCF0A3E3195F874F78AE00DAC349EFCBA46A8419CE0A7788B1A2527DE7F
+1908F9C67D4C59DFA016D21F61D3F29AA54763F81F2837C5D4DB2807F3E47EDF257588E8
+64FEDBD51B1C169035F1B64D80EE209C5A2315B961D33E4957E11A2225F0E8CA0BCC1E18
+9428EF1FC4BBFF887EDF1375E2768129D8558658D78D876F455FF4F0C65F35004AFBDEC0
+F99C007905DB17D92A64B5D1A390233820D41BEA0F2B732B12BAA6777E96A94F23CCFB02
+2AB8BF09CF9EE6960FFA056EBDB46B04B8F187D05CEB9CF0BA0F796BB494D5F511010E0E
+14BE33E45C807F4FD23AB76B0F0E3969010DB86834D787B8E0F92689807033BEF513DED8
+EB3EADA76AEEAADBB191518A950F227A0ACBEDEB778F43FCB3A281F7B7C35F58BB1B3814
+49E40140D8059E950413B9CD3F93240629B030023DD6233C59ECA2035392E64869AF7FD9
+4116ED71B821F0AEE5A68CD691653C2D6DAAB8AFE466D5D7F1BC3ADD65C0AF0EAAAA1486
+DEF5F16684DFD78B7A41F7816CE8A787019D9ABD2F4E4253C9229A2DF73C22DF22B93A8E
+4FFC4769448A3E00CF85A939424EC3856CBA520420BB7001372D2F703C5B36CCCFCC5BC0
+1619D9DC961BDB0D9A2FB18759149632141348364E794B15E7BC79420F0711382127B262
+292FBB7F4D0B37A7627E8EC5F5FC374B98B18FF02DB2F442D8DB5ED06F90C3BBB17D05A0
+5D7D11A6A7C2E62F15E7644ADDA44F1A3CC71B61645C7497C242DED8199E31DB0A247C08
+1739BBE040E7CC7299BF09DC0CE4CC6C59BA7D1867CD3CF518ED80959FD8B26748EBFE0F
+DF816836E57738FEE205BE2941BF7F155FFF82EB877B7DEE42BAAF4BF2E2057453611C33
+B2FC235D7141ACBCF65F068F2A90A86B8D19B6A0D7223024B42CD6D71C04EE865279A1D1
+6A401D2393058EB9A16020EC8E69943F631333D3C08C9892F8FA620CACC3D1A4F411FB78
+A6CC30F441BE858EB8ED7A92164C59FAE8C5C6F275C2025FC60E326FC2F7CD6EC4612DC7
+1D58EC6E363D90BFD5A93F552F7C3A6DE059A13C14CA2C15D35E1E5E10775ADC9D925185
+1ECE6C1AD5BF430846F62165FB21A393838DC98C2501D598E83EE90B31378D4D92CFE8C9
+869538BA6614A71D3F29E455DDEF8321C2AD78CC2C0A832B3D0F1C09E3B5FA99B121C283
+0200791629A4094DE00EB9AEC55670263DEF10783A699D69BF861FEA783A51937E1BB83B
+D96026CD631C7CC3C7EF3BB698700B307079EF2F28F52FC05FE409E020B5E044D1766C37
+55064E5B49FA1FCC37E6D8341525F9DC92B35455711091F1229AA39B397E9ED05EEE7797
+B9A9EFB8FC162EABECFD465756E8B747A3041355178430CB089E1CA3783DE19454F97E0B
+3B24813D695BA962CE2046C8F2778B0A7808D046AC0713E1A6DAD26033D153421A24E667
+AA649DA942425C45875437F703E68F68AC5F5AF9B4E087FF4AB87DA00D174E090D834BB0
+14B00764C1CAA2AD4FA2B457858F2784BCA840C7A8BC929505056E3BF3FF533D94C9CE14
+76DA773403FC3F80E1A2335699A55079B6993B0FB187499392167930A874EB1954E6DA45
+C9591EEDC1E8247F237C8657B6FAD992B9426D584E116EBAD9B9F2214A8E850F541A208C
+A8792F3980B4CF5E75970884DD7583FE277F82ADC1FF35E5F3FB216AB68C353B25F34C0C
+F2C4A60B1E51EE88F7BA84FB1C23601FA2270049E573C05218BEEFD56DF0A648665DB6B7
+81C3B0B503202DC005B8F2F00430288086BC3B4D0625BA2966630F71DC0483FC43DC4AD4
+AFBEFCE65FB61CE89F07FF29B9A9007700503043B24CD9DD8BF9E4714CA99B9504BD7FBF
+DAF7ADBAD4168CBEDD5EC802F2DFE773585C5162E564CF1C39BD04CDAA50C2032956EE47
+948EE6628F9EC006711877235813960C9926CBF2372B9329C3CCE4F4190FACCF33B25BE9
+BB4DDEB7E91E8D8ED843DF6F0352E51AE0670C4E0A91E78664D5F88F77F6B9EFFD25071A
+F9BF35C2D572275E5FBC2461277DCB0DCE505C6DCDF913CE7A99DA563AC06E1C4B07D7BB
+0A24BA8CDFEDD3C16107DA2195FF9677EB104C08C085D6364BCB745BDE0D313D93E318CD
+F7929B299185C098642464F491E64EF9A2DC1DBC34153495AD62F886309CC6B6571D6177
+91D94AD5A337912569067DFA1311EA41D5455C24D3B60ED3E698E10978C10FFB9A7C2137
+92A6FC31939290392D8ACD3253593287DFFC13CC9D80870AF32A2B82AD21C49560FABC56
+48FE43EE74D71F0E6D8008100FDC812029C4F1FA3ABE01A4EE9D99A2FA574F93BBC6F17C
+7301329B2363DF36FA029621D478A795F9D564EE356CEF0A1E60ED1DBF5FA08590D677D0
+9A1FFF7CF8D657D3D1CF2915BD56B44BCF420FF4A523162CA1791A56287BE773D74F7246
+F52C0D1E22AEA987241202665D0F5EA6391ABF31F16A5BE4353FFAAC2408A0680A33752C
+D527145AE349CD781E339C8A9D87E5C0B1312F5B3C150FAFB4588ACC7D6357A5A3B4510A
+556A7FAD44643F04BC6D42A23E83640091DC70FBE51B57A7E0EF1E2D6112624AA21136AA
+A1B1C6DBC1D1515491F0EE3F9C4338B58E3D0603E1C12A0588118F9261139CE44B5183C2
+AEC863C7D7CAC0DD272FC5142FDD80FC668A6CE709CD7F297DEA655A767CB8A088474BDF
+5EC4263121C7B3F154D8396B2470FF226A397257FE5D24EFBD3AE08CEB5CFE9194DC4C6C
+147F24D3B36830FAB0AAF03DA1442C1E5E77951538CC9A022370A8C3E39273E4B8E3FB8D
+28EE116FEB770A6F223CFFD7925C64CEDB8A7D66212CB443B2A0207EDF102672ADDF2084
+5C2D36FF281B33BD3408CF628D7637F1E92A5D2168DBB183BDF98D99E5A68D9995AE6123
+3675A1AE7BDBD80642E27D6271437F24D28884C90351E819D9785E556334E20EEAFCCDE9
+2929DF0BAC01FF12B56C2B4EED3E554F3ABC0096BC7E5D9409C923E9ABE6032B20784815
+DE1C1663D6EC86D7476A0E9698CD3B201F5F9CBFFBE604C4C2E823045473B0381B1968ED
+20DC0D0EC89487B4FFF6F3F83A3D68EE78868FE5262235C3609C6756BE484D87923175F4
+80A084A25B5776FF76742A70F7A60D8B76C3E13409A38A258E3E334F66FEE4567A68BF1C
+8CEC4A80CFA0361BF63B7A0D5A0819C85E1A9EC223C0569857D730688E6D177E4BEB8E31
+F873625E39573842035C5C6D66D923654A8FAD9421E1026987A9C825505DB5382184EFD3
+6C84BDA96B464796D72571760CADB46199643060A0552D8DF95A9E6C30787CBD2F57B0FA
+D1FA43FBB1E488FBDAE8273BA4F191398652EC86743D32FD5708673AD1D39F62425934FC
+AC949F047C873CB94E4A3CCE44A458EAF26953DE54F645CA7B35553204A0F5C7A32E92E5
+27785DE73A3E2A3A3FCB54EA4E395E73C5C89F64B77EE218F935AA4C42106A33C78D03A6
+90813236AEE3E50C2C44323B83401444174174DE4895D090CDB64274B70F557204C772E2
+D1C47C79C1EC238D5B345F7D9CBF27C6B98C5163E6D1D93F23F311DFD594658B903480F9
+A475D3A3D9BF909D042CD76AF8D574D71BA12EB33259C745D3FF5403E579F794EC95CA20
+9959A9CDF439138715101F9FFB3E867A2FEFC41EEE21AC816B7E48F340634714E98CFB91
+E97CDEC4C25CFF567676460102255E8BF37C8B4BFA821EF0165779094CC8ADEBE5778333
+9B9F4DC83DE0360DC52628543D41E0FC9EF2EA434DB9520C2CF5E74863D9BA197F8E7A97
+912643D24CD024E6468A188E0D1E903C48B9A996ECF5D9B64A64E026046E90F5C92CE2F1
+260BC6D4F298DA5A10B3620C4BEBB5C721B830ECC1DC8CDB86AAD6C20C9EB56DE6520D0E
+29B6C3EB14A93D43B951CC2C690B277B426B84E4BBB4E1719278150A03C450A9FB44F6E9
+16DFC8986441969A50F06A4483EA651839C31E89A9E4644E96094DE5320CE79DA5499528
+AFDF9C150A4CB53A4EF9BAB6989BA5D0703A4F2F5D4CBC95719C0518DED3474F875DE58A
+3A2C369EDF2BD851E5F2E0BCCD47A0452C8751E45DE47CC2C340EF4AB6F4F885B0C2C21C
+8E8B252249C5B45EFA5B3E8A27CB39556A262F03A04639280ED71F8D01E12E4FF9D37C3D
+3DF6164A4C300E495CEF60F368C4F5277FDC5B27E369483237780072A6709BB6B1E32F33
+53AEDF5A0B1A30EEEFFAEC01A0E9630E5A50BABC081DCF71997F181CC310023AED5BA74E
+769DA4D3FA84951BA80EA57C39C805F1C4B42C7673403CDE1573E1641B76F1AE22E57954
+48B4C46AB50E3EA8B82FA89C9BEF737337168E18498C3653AC2BA51C757A15A8BE8B1675
+FCB325B5130E13C36A66E3056C8A0157DB84F7D6636EB06B83FE198579DF5135C77839D9
+548214B53BD51BFC1EBB8CF2E4B1ED77EAF56E953221F95D30D6F16DCF13A57664DB4DB2
+B45DBB6410A9963DEE6496DCADA35B5AEED478EC9297FCB64555373F4ABE73D92B97CDFC
+0D83E4D2E80C6433533451BA99E9B2777492AB98DCB69C2AB9737E5A075FA29CB29307BD
+315A4A67E7A5519B55CD6DC3E241AA0A067B0FFD337D72FB0B5B290982EE91CAC2504A02
+71315319A641ED197E14017EBCFF2B124E1D449C5A692BBD0E7486686DBEE2F15552583A
+A52385CC9064ECC3873A1530112161BDE2008B484BB616459466E66985829F8415D83DB3
+4736B604DEB0E730A3ABA6D04ADE6666E303C40BA9B35FA5C753743239361A8AD23B80CD
+AEEC9B8BF6CFE55D9EFAABE474D9BE5F06255EB903315DCD4E2D3469D08AE17F2813D7ED
+F8B3B5D004347932D9B38955E27B786CCF0724784E0D545588B51460D9C2572C6E4C4B4F
+9A01217FB8F2FBD0757BDC1882292CA04C24E7828D9A6F64B151A4EF2507C3D3EEB98F76
+77D041A5DCBED1BDB61B43034F4F6F5807953BE78631376E6D3AC14411587526E7DD2E68
+9D6241942A0C990123F2FB111F926A68B809DC5CA2CDED30262E71CFA275767F76D5514D
+9B7A435A07670F011DDDDD31D8B944151A6A47C6EAF3AE44881252A078F261814A06492F
+628BC815F32E0B889863A15409164250C9ECBFAE7A749AACEA6AAA3FBF9BBF40722DAE91
+167BFB833791D3426DF713F829F60F3F9638E1559B82C3704E048AC9879E4AF5C70C9641
+BBA5C04816B4EA6CDA7BE2DC728364587A5E7FFEB8DA7BDBFCB842FCEAF179244EC8B247
+7AB7337897FC0946AE494BC487510CA123CBFAB3B7EDCEE9DA82C37D55AAB651B887E6F0
+5A71F2331B1FF033A1D553186C786C224B1CA80D6693F4F6A948E338BE6CC540E86FEFED
+280166B01B5B8F9B278A91E1BC632C3B06A4BC08530D8F1C89A6928E91B8E7C393C9AE2F
+91F826E8AA3E11C72CBB0A552EA0261D5912A191127D351B12371E985C6DB66834869EBD
+746F758FB0140C248852AECB41CC4972B6CEA24800F2528CFA99E667FD10EE57CF671099
+527AA11667321AE9277E4293811190986CEEFE93FB7C4A1F1A5884BD786B13F8B73A1A46
+19257501BEBE4E2A6BC3DF7BE7451D9364F00EF318111A8E4FC065022AF0EC88040267E7
+BA268C6FEFBA8AFB91120EFE066B8B23E40A0A0F209D3097881CC2B7141BDAF8FF7C5964
+4C029DDA226401B9B98C6A53AF6A93B39F6E3673A3054EEA3CF8CAFADAE0805018CFA969
+7E879B9C31521B340B288FC8910E5B6E061A027A4C69DA1BF038999D693108AFB70D0DBA
+A90F3B2C073FE4251064E1FC887AD3708256487DA8EEE60795CF11DEAABF0CCD9CE8E372
+AD4CC8C8DC413B9D2019440173F6F83CC66ECA28C8029C1AB834DF7BF2AF0E0D86C66BA2
+6EF90A1761FBADC03C1FE598D954339A2970A5C9EC56236D9183E6155A511A272D005087
+14F8749B03A5A2B9DE2886B539F1A377FAB65ED3437D55988512B1B1C638015B0ECE68C5
+3AEC61020E34BD8E6AD7659399F0E1D8D23F5EE282BC764249B664D75FAFE67CB5A9DA4F
+2094ECB30CB6B68D52AA665BBA751B446118C74148DF979A0FF173364D79202606AC2756
+8D41821B1E4D4175411CD766FCA1C25093E6CE9A37C2048755DB82D7448526B59766288C
+9225108E8E86261B57C521991CDC273C0BD25EF4434670C80AF8DB7300F26A9701537DD3
+8FAD0BB2E9EB8F0FC9F2C8629BA97AA1980C39E9BE5740501BD4D57D71235C84C3EF6B4D
+CA3D1EFCDF79B8D4EB7C29EC5AB15EC38B2104745E45235A1F37F19E921CB2213F1A91C1
+C392817E7D3AD3A6ED1EC8EE290CF5B1CFA2BF21DF8B9069F4496B7E80E7E96673B77EF3
+AD7B2FD6653510AB77BBF1AC8A07DDE48A8C2AD11EAF2CA95540A164C1B0834106FCED12
+E179477B185DF43148633CE3AF60539493D0C88173C0E63CB5A44790FE41C211966EE03D
+424F492C2C87C04F0C28CAFEBEBEA7D11AC959E0C8A88776B4372E356C913943BFC88983
+1C8F95A399DFD02779301D05205EBB921C1F52AA522746CA533AC829EBF7235FBCB0AD82
+69A64B2C68748ED4843FB583151429A1E9537CB40960FFE9C9340CC11BEE00EC7005641E
+964F4B0183C49262F3202EB6525EEC66CB68B27185B7DBE343FBFE8BBB34393DA1FBE929
+50702ABD341F45EEAF0EE66C848EAC04CFC854FC058A9418834B4F18E6D861AB31DC1C42
+DFA8D939921067BFF8815B708537A120CDB13E775802C57A0D0CCBC6ECD4CA0DDAD91F01
+97DDD9118990BD71A1CB241B88DDE7EA4F13236CBCD7CA64FC858CBF1E5A38C98C19E3AE
+AC0B7B256BA7E15F0E49C84A437DF190A81D0E179B2AFD03A427F2F9AD83DD2A4EA893B5
+BCDA0F09C419FF0D0EE4A811886E2784800865CC8177D4E80FA005C014AD9B124D3D060B
+526237FCAF98F23D1F7195F72CDE4E72B87FC4A872FA95441483FEC58EDE0C8B97909B95
+D5FF189C0D49053B187E0A1A8AB85DBB6D765EC78742E334378EDAD7F2FA77E9CED5F652
+295145D463126659E0F6BA982BDC32363FCEC79AAD13248135E6A28222BE0127D807306D
+C94C817B649AC020B8B3DDB18CC5B05B83014A10DB5FB9AE6BE4A078FF056EF661B2F4BD
+B422CD7E80AE9B6835330AFF67FF1024136EF097F4DD5344D37FD7562802B2A1713431D6
+FC1EFFEB21A02267D7F6B2552C97FBCD4BDE4214DB01C1376F07928CABFB1106B02FD2BA
+BDC8C71D0278DCB64375613479FBD3D7D893D279A3FBE92BC92BD99B6FEF817344AC2DD6
+EEF172D3BB609E961180734E1B4C4F4B2D704BA4D1D3103BA4F62DAAD46DF7136070EB14
+549FE8C727CAF060D877D22E21F474F9627507EB1FE2A28534789407DB20FD6D6D9F5CB0
+7CCD392440EDA0E18E1A5EAA7B2C8BEB249A627EEA58DCA375DAE4EA816AEE7BE8BD92AC
+AE63C97BA1DF13081EE64198B83926153C8AD6F1C86FA73986BFAA5F0EF5091A4B591BB3
+32ED4334E6D67A0288D390261E88FA39574FEB6F7B19B808DC87426BF13BFE2F76ED7103
+87A5283D27CEF752B20D831D8494A2E35DE7F68856AFB67B6EDC883C45840C6E83F1E9D9
+4E4351D50BB9A03B0F0B0527CCEED0081C96A029EF47F68A1BFB0A5DC673A0C8254216CB
+D84693230437E107267B9244E2287BC6CBCDF73B24DB5B947D5738568471FA1FFAC537B2
+BF13C99D56230D49E12AAFDF51B03265A9A14529147FDE45C234282644C9BAD0C6892861
+029C9F27E4AE13F8278E135E89E81A7E552B11DCAD49507502B47B1580A6222672EE9C3D
+A05B74A4719A849179B6C93BECD1F18FDC9CDB1EA52ADF96D29409B9B9DD63861A2C74F5
+1A99843FD141AC60A49FA6A134FF4C4328AA9D95BCE4B89B4BE4CFDC1DF3603DDB0D7DCD
+E1A3FEC7059299A216BF88469B5C9B16C20680B14D414902E8A7D80E5429AA24D94EFDCF
+500C1F1ED0F3853E2715598355B9440AFB9A8D06F6C038EBE0574B24E3A168E93833F462
+B24FA106DD40C967878248B2E1D58CB8E4646DE1F2B5BCF7FC02B4BC7DF7593737F583AF
+03264E5C35FBF1227DEF2C4F6889C2F77C3B84638CB682645D0F2E99E0C4EF9ACEBB11CF
+0F658F7D3163C488C6E642B5B03C1E40F69BC2293497374FB157F42111ED5B96E04040D1
+8C0020820B37A22DA38F4E21A64FFC24131CCA0F575529157E9A59EC6546004241A8F51E
+9E85066AB22B72FA003CC868F965DFC34A2A0055FF86443CD3ABD3EDC30E9196C20629B2
+AF3A1A0C42C88C20449F889A39BDE45EEA0551AA0BF0E9641D7D1FE0F3C286C7EE34800C
+20A72C954EEE657FB36E10ACDC18D165C8DEFEC48D154FBA121CF1066508A075A669612D
+26B9309F2CD33B2109AE9E6B1EBD4391F7B66F625367766F8CF0B8BC2D201124CFD9920C
+B61F71C4781B459ED271EED5937FBA4359FE1DDA7F3907ADD7C15ED021E7735985E6AA8E
+F21011A13E5CED0B69877C636D293BB99AE7B9457E8C4B84C4EC695C5944622B5F47DEB5
+1F3D653C7ED73B53D16B504E761B8C105CBA84E45B408B415045310CFE8D693AAC924ED6
+C61A12C7B0CED04E630D8A04F8838F286E646960120FE35D0D13F9E273DB647A999F1580
+C1448CDA80B9489BB8E5E4507A7A5B5329A2E962EED597E4B7C4E6C72740EEB351A3364D
+0B0689BC2658395E2B69A8FF0600EC50868404BAF6792A59983C6E372DDBEEA9953870AD
+319849F018362B016EC38C0B7F947402449352CCCDE055068417434416F0475EC82A5441
+987A472F59AD152C56FE81F1501E88D0BA843083736F783C366CB18C8A787FCB60E6F8C4
+3B56BD458D9A42FBFFBE128C928DB06C7BF8F2C0FE209B25DBE0F28C1CBC8328C8E868E1
+F1DA76549F34B6FEC13E1400B2F9A66E00D89CAA99B2DDD6A0BFC73C09C7D774CC05629A
+E23AF62DD1E58D3843EAE55452281A0DC2B31CFCE75A7FEAAB90041602CA5293EA58F8ED
+C18635ED0234B9799A12388C2AA469FEE8CFE1B112F7BE610990CD51BB13D955CD02D571
+323F565D7BC240FE71E3A3A1B92BB9A1C7EC2EC6406F06AE7C0D14262319D389A7CD8D34
+D41313DE9B2336963A5EC892A8051BEEBED24ADCB1F0BBDE77C4E3AED1D777C0EF2F1AAB
+DEE62B1967964C98CA08561EA234879DFB0F50BA067E1462CB63544786D56935ADCE3E7B
+399B1B3D0098DC19E4EFC04922CCC28609390A7B163D66853C2C8FF94591CD1DF499DB82
+F0F6FB7FB6D3571735528F544C16786CFCC7FA10D28FFBDB6C455AF2A6E1F6BECC080B6B
+EFAEA5D51607A260620EDD1DC6E8AAB588BFCAD39A98E028BD26DBCCB149D818E0B91BF0
+8AFB55C618FDEDC15ED7055521BC90689E61965FBF22172F584827852B6DCD8FD466953F
+D16A806E20C5C96064F28BAC94F3A7818B18EAAD9BBDFA0FC302E663B989D97A76E925C1
+CD1307E43C97F88DD731AC971B862E99633A531788BDAA4847A1FD124660B00000007168
+72191B3F124402B990F3C379862AE823A3646762EF68A69D3AA91C56F50B10807C915447
+38AB8EB6C01618880F72A6C2DA6764158320CFBEFC9F23A0C1DB0AED395C70B28C4D47F9
+7C5018499E45AE5407C03CDFA41D02E18F7AE56346D872B03CD5FBDE0D0DBF11C1FD313D
+E0A7856974BCBE0EB331CE51D190BFDE4C08BE9CFF6F2A32072454EBF4DDDD1E3B9CDE7F
+9ED3B2C1C5C60A12813DD88D75CFA6A9CC4583764D40C7001764B69A739EC079E7ACA5C4
+1DDAD7D15C8807719EDCB3054D9DE3DA92912F019B50B62C8C4AE9488CD7D683565B2031
+DBE9E7573595ABA60602B6023C1D4DC8370A529873DFF92DE908CFBFAEE97B0273CE36AE
+6C931F5282CD2341DAC0D6DC59A693FF4AE740E77322F8073471F6CB3CA99E7A530F5E82
+7E4C5185E015655F784855E4989F27CFB02AEFD20C3D0E9E4C1346ED248A6EBEE2BCEB80
+1B912CE4AE5475DCD5D0516397CC74589AD3D52E70A9DC423CAB42BE428CC2DFA56E2C9B
+DB4F083F8A7B3B2B9063EAB3FC255A489707792141F87A2FCE77B89AF7099DAAE3EBBE9B
+3655691A5538305B664C75DF2DCFCD53C87C38D9EDF8F7DF8A808851ED31E8348C77CA4F
+3AEC6C2BE721FA3CE9D54B72B414A0992AC3A9DEFCF40579F59B0E30EE3A9B599772936D
+5E5B921D5693FD702A30BDECC82AE6CC10132C2B6C697326CDB3201D35C4396887B5CD1F
+1909A0C3A19BA71AAE02E8639B6AD1426866196F0F9F0DEAAF8BDC53720674296BD41161
+DAA21FA4534BA100FA41161734E310C6E88B8BACC050174028F4DF483785184B30AD1BD0
+2EEE2F93A187C5F48EB3ADB9D63AA4D52D76AB07B93CDA7F12F3C7D9E58DB297D2048375
+5E5C6D1B8F9C5C07A142E0A68177BD7AB073CFB934EF14D9616B15BA2B38AB4FA4B5877D
+04F5308D74D642B46352FD84B4FFF058C282D308AD2AA99270964618A04C0E522AB7A4EA
+123FEC9A47F13060E534C0C58C327B063D59CF96413E176031FB21F3AF9E3BF1BA6521EB
+C71336E468A8FFD6AC2EEAED7ED016D2775AD2A7432534704B399BAD93E0A1FD5C8E6FDF
+E8DE157ED4FBFA62C5F0D12DFE4C519713A76D6B2D35FFAC7C0B90ABAA8BEC8D2221FA39
+5685428736398AB87F9B73F7094E02A5019A360FB5E0A2857AB2439999377C9D4B1529B8
+D8DC1EE0B68D1A5AE1BE39949A8D53F9274D51650124E4BC873C07FF0786CA64EAE168E3
+B8E0210945249FA48059080232CBCB56A910E40D14A479F193BFBBD701384407A2DC56C9
+BEE9A4F3F011F02D0AE09C3F6EE0808336C70C6BD82525858EECB6521238C717469BE58B
+6865E2E9867FC248A82B44142F5E825665F6780B03015A6CD2B1592F36B7F1C03D58DCE1
+9588FC260148D0DE42196BD052136CA1BD82BBC0AAAC6ADE4500B9F374DCE51779697BFE
+670245D126066964B61D59864EB636C43D6ABA70429614DB400CAC2ED06D85D3E7C3D9DB
+B5E2E7EAD6031B9798EDF30772FB9CA88F52D2A56C1CBA8F95202DA92870CA6EAD0358F2
+183C791783746255B2E87EA261A1D9C4B7B9B4174D412BDC01F4AC19DA76C423992291A0
+B0B85C1F62AAC83B253D8C251DDC43D921AE994E7122F7A49EDC473B0D9B71D8801A0D43
+B589E6C1395255D3515A637670589D6BF4CB75870D2BFF2491B7DF7EF95F04C0531C3C00
+6BA3CBFE26F52EB9D041DB138FEF272218451237E60685E66390659CB98F178E3BEB8834
+6B1E49C6D9EEE0677281D460E3AA55250A0D8D37DF9DDDE21F002A70E2F9A22F0AFAED24
+80C169B2BEF14DB7E75ED43E2317948F2F5F17A8A301E5DD65D1950AFFB85A1B4A26AA89
+104519AB57E70A3F506453128E1614BF850F371F29A9CA224B2B258C9830F3046D4F1C8D
+3DCA9AAAC020617CEDB6FC6E1EDC69E17812FE92EA38C97ED91987A65C72FA48C353326C
+DC7BD08632C96BF3C9A7C095391BCD9335E8F254E937A77855854EF20235319423D2DBC7
+DD2435B9EF9B9CE1046B95421A98E910196E802263650E5D2087E34E384ED7FABFB6DBDD
+48342333407D7163A1B1031F841AD55FDBE7C1553CF17CF057652E243CDCFC8F86D8911C
+C6DA2FA6BD522ED649C52DB102498790D6D55EF2AE27790595E8D8489EFC05F505566958
+33A31087D230F6041DEB7173D2BFFF6B59E643B532C2649D4902CA7FBD79F3347ED28EDE
+D5EFC41B0B6CC97F6165806BABA7930768FE8E4B8313A5C9D69BF0B029CFF51B9470A22D
+98A6257A6BC6B34F11536130A980D985E24F69E0846C395DA6C35C036940E609F9677B0D
+EA2B923A92626EEC8E224E2BED76CBCCF6F2DC14CF8D90BDEC80E7088CA871846C68247D
+C4912B6DBAD4C97A472C1FEB6B2B460929E374B23975046E6081E210116ECB0F3680D99F
+E7BC4794EA19037638DFD2ABEB7365F2A7BDFA3C7766B3FF642F0639D897A3F0772EF880
+EAC10E1BA44C207039C64D2DE51AB6F71E703F36B24F9BCD0179853B815DBAB59057E8F4
+7C74B338BF128922C8057518CB7FA34AF8F590BDB76296E4258570F5CDCE24B4F9755C88
+F4F3CFAFFA1EF7EA5052A2C7D8A823D0A1EA7740A726FDD7B1D28D17B01A0EFCD601F20E
+FEFB1688FBB375573F54EA1913230461B54B64174D7C99ED8A2DD269CB60B02050A2B300
+C0E7039663C388C4670BA295EC5BFAF496DFC11816ECFB433AB94380D1982DF52B362305
+289A0EA2205C91DAD93A6428491028D50A987C5501D0FEE5509196EFD2CD36D695B71289
+E2A4A96BB065C0D9242351C6A3732E49D51B5E472F9EF2524716B7478AB7460F43267CE5
+6B2DFBEE8D34E1BA79A57B175D8B9496BA2C806C2F6CDFDEB0DCCD0D813E79E766FB8548
+9087D61E7506F04102C2DCDE9B44EF10B38443F7207B707A265E1111FC0E411F04A64524
+3465AE5AD4FEC01561DFB4C1384B8FF54A0AEBBF189822B63ED986B8197B3B1085087B01
+B9EC606AF3C1CBEF701224ACAC1BAB4DE76FE28BC7F538DF318EBB3CDA0E9FB06214F497
+BC2926399C79CCC70A464C2B58D51A52BF06A5650D21929E4C2EE5AB624F5EFA25E64B63
+2ABBC3285A79C5576ABE016283D08E19246B77166612E83B2244A1BF5A7CAE45A691AA7D
+BC31377285E78F094870584C23A2216453B9F0804BBF32FFDF810A2DEE41CB2743472A57
+D050F61E285D232C6EA0C2EAC1C0FECA0E489970C7B83D6F1D64B187BCBDF29815CAFF8B
+8EC2AC2705DB255240A5A435A0B0AB6F2C9451C7E14FED26DA327D432A30B672CC7E0D99
+8653AEAA0DC7FB4161E604CEF7464934795E01C7CD625A2C7C4988CCD213C19CE963C6EC
+F45078DD17A158FB2F9FD1241FE5FE0C45D05AF19E5C5D5AED76D297414EBF0E95E451F8
+B61EF47D7A80B240518FD2BD42C53B96BCB17F04B850CC889859887A2EBCA1499C10D034
+D545C5101EC917FD27B1F87B4460B8D5036A7072070ADB83573796D07A4C4C5348FA845E
+C31C83BAAA79D880FC9965C08621C9BB6A982CACF2E9076CC88F14F4E2B1403A980AA310
+33CC1C16B108D3C390F95E87D6DA3FB4E9AEECA82F70424F82C243D0F0DB273FEFA8F57A
+CB2994DF51CCD21C45A00F60EED00CB7C2CB6D131A57AD4CC98FA2BD0313E15AB964221A
+6662B6319E305F2D2255741DA5465C9602E7AA3558B98B906B4AEC3AC8CBF877E51AE0A3
+CD1423A0AFD38716B0B74C7F492412AB575D9DA05634E20D34026A1E02B58806AE95378C
+8018A42F273FE95E72C6E8BC54646FDC010E807B2E78AEE753E9A223B8B014CE464AB7BC
+5C6FFB19A0687C0FD300BFA19FA2E9A65FD2A4BB8B5E6967289A70EB18821A32CA0751A5
+972A6F3E3054E10972F59A9DCDEFC5DB1E9FDD87003B98228BDDC733DF066CA5490A902F
+2930EA9C937B586CDBD433532E6230F87773FFB354BDEEB778ACC289F3015C5158828790
+BD620956700DBDD6C2A9CC76FCA2868936D279495651B5798491478B1B77CE6656E8FB2A
+69FDFCC2C8FE04C5C6AF6054C01678278164ACD9CB8C7BB41E0A4A4A3513283C38B03B6C
+27E66FA995F58346B724189632494406D7B8E6CE243C5BF1CDE8C87AEB0E6F43C52D5D3D
+4F3F9C876FB9ADA96302D73FD3DD51D82E1314024C5B1262CC009052C4E598A2B7D855B7
+BEF4FB97D65D8B26B69CA86C173CE21A159B3765FD48A6E978137FB2C7B9C4A39A94EB09
+A9825BCFB87EDB546D917F4BB3B618906C643280D3A33CC87311002B465D440C5FE3B8EA
+1C3AFE1CBA90999683875070513E14D37D5AC6214D5E38748901D3740350CBABF87ACACA
+FBE7CB2A97332D9BFED8B0A7EB95BCA79E8D4D6A80C1162A49C73961822A568D43BA71A4
+90E3571845A95B8AC2313098F7C3379DB959167CA17281F8FC7933F10BAF70A573981F5E
+02810780D9780AE94EACC4F4A2D1BE14649E1B776175FB5EAF25DE613686161995472B24
+86AC004708550BCF2CE0CF3032A02BEA90E1163319C20894648844A936D39C7A266060A6
+093B59CBDD59E4FC67AF429BCBFB4037DEC87FD9CE0FC26D488C1987E0D6A79AB19A7601
+3C3286ADA28464BE78C5C591126978FE183EB480403432664318992C47600105BD1C223C
+E78F8F5B3C1C56F298C28B700886B9E467E7ECBA6BFD0BCA114CC74CFE8252FD9FF4C39F
+AD3071CC0E832A9F4BF89F9AE4FFA1FF02CE797052DDE080C175AE529C61B639D842BDBD
+B8D349090DDA8F503C909349A69BDC6D972805B15D2E8D321E9296E3E0965E7BDB040FAD
+CA90D1BE06E438AB653E7553EB43A4430E3AB1A43BEB97715FE97A8B76A7B5B1262DAA01
+DFF0259186017062090F6B9A35B9962DF2F7EB85B6D20A693B1D925DB4BF06996F60BDD4
+6C2381937E21B3299CF3BAA565727DFBFCD38BF24143D400CF99A7F3D09D17D5E1CBA49A
+9C607D434EDDD31BC70D277CDDCC5CE03C001B53CB1D448A87DB676F6BE0681BF57F66C0
+43BA1BF6889DC9F054A544C4D498B74988D5DC13262AB95205386343ED6D3C077B058B57
+4C464D02E35DD342CF013B84CBA67538AE13A3F50BE444014ADF085E95D736139E1646AF
+7C4A401E25B3511364DA040AEAFF801A664E71B0D2C6E46B510A97D5B75B2377E54BC7B8
+C4B368602743EB5856E4385C4FB3F364C54239B5794F69E39791CE5BD967BD03E212B8B6
+E14336AF3900878E5031993E3043B23376975A43CB032C9D9C1E485CF34F3A1F2055AEC7
+9A2D2E68CF82F1CA0DDF7200B9FE4172947540769AC5FA6AA53A87E6A79AE9CAC84C0FE5
+F0C0752F85329F95AB21AC314B7D32C538E70112C12A34DF2CE7127E5696F88CF65BD083
+5E57CF98FE8AE4873FD1EDC9F775E6920E87000CAF9C8B7FE3CA5A84A5AFE056CA8D5610
+69F8979E13055582F11FADFDE7BF60FA9EF36AEF0D85F29D94CE5C571574EE03FCE5E5BC
+A5B2D3E4FA107FED636226B59D00CCE51BEB891DFE12F04BCEEC13606B051D5A50B08F93
+D0B3ECDE4EF0DE6E06829E559BB2AEBD02D0B7A1C505743ABBFE54A9682123C3695E86C7
+54465D3A60369CF9C3FA800658DC52000B8F6915A9F5549849EE092CFA885BD5FA96E6E3
+D04DE784BF6F17F333AC90FD8AFA98ED04F003E47A44893E943B6504791D21FFEE630A7D
+026F82D0B903496D3E08DC35768EE6FF9AB617D29193A5FDF8A0976336297CA65BA71A1F
+56E19EEBAF4AC438B9807AC1F4CB0DC9F740910E2BC32220D37A337FECB98301B0A203DB
+739DC361838D4577296B9DF5E1DEF57DBFCA489801685288238CD8DA085C709663DE7F84
+127FC9E6C4FCDF327532C87635A6D7822D36583930BC9FA1746966A175670A2EE77D5FE5
+DB0F43189C37191F0ED80A333E8B117508E17C010FDDAA44820EF17FA9AFBDB754507F4E
+1AC0D09A0FAFC80ADA11DA469995CD7FAF67CD8E29AB323C03B6A1DE80B684FC2AE84B46
+BFE4748300EF789A12A166FCD29ED3AED2FDC431BF9B3A450E2B15BDCE9F15C13E4C28FF
+15E145C661B3EF6DF748C32129BD734087B8DF6A5C00B4765F2B518ED29FC53D283587F1
+2B62F177D14E3956A64C425AD811AE6833F2E095AC0F7BED54333095002EF33824F6A7C2
+3CD332BAEC7AB22642A5331A0C1656E3E2E4FA99825B5F1A04350BD96AD4E491F97E47C9
+F5FDEF0466EE0566D5F2ECBDC2C3B0DCA65728196BC139EDA445C7B5435E293F50C91CE5
+4FF3AB7112603BE44D41198C3A5BF2CA4BC460C0BD8D86073948C452AFD0A35CDF30CE1F
+AB58276DC2A49CE15CB2C1EE44E0C3E07D73936CF675B1A40B1A2DA5C61BFE4E56C92FD7
+CFA03B2D6A9A108054AE303195132BBBCEAE17F83B7B9140BB11DC6D2A3B17A46CE4FD4E
+0EEB5FDBF8028B1E7052C602C5E7BC63D6F6A9172032D538B495C3D8E3DB6FAFB0CEE41F
+35884819BB65463B11378A7526B582A4D2EE1726615B66E8514B4173C47B399F86ADAF7F
+E7F7C08A707A30AE31400B603A31951A7F617BC16E5905ADEA0197382CF2F799F8ABE8DA
+134FC37C99767D4ADFD45502F189ECF7D08471186F4D29A054DED0C5AFA56A8AB3AD5F3C
+71D784803E0237F41B764C6A91676BF4623E80803231960AF3B941EFD842235968071455
+F1BECCB46F437930B443A1C4F681AE595A7F7057496C5BF98FECFF07CE1B4E3653B7AF75
+2F647322BF2FD773C8C79B305EA2365EB878FEC55A277066560401CCA10AB996645BAE4E
+728E34864C7F2F0ECECF66C0387B2DADBDA23EBC4C0B904C5D152C9856EA1FB76D10BFE0
+7213A87551081FDBEFC207AE33B860649D445724095B28D45354590E967DA4960814E184
+2ED400AA72982427E378092623D784272A07450265A89A88C13F0A71A03C4234EE525034
+2F5F28BAF685A2D8AD6C195B4CC3ED9DFC0E82910D692ADE7236347002251126C4CF7C82
+175624CC08445EC64357BE592FA06FFE3FB52720F4CCB0A78173F0BFE317F2C22EC52607
+C9479BFEDD6FF60EC8F1F613251BDDED25F2639E469B344B86ABF4BAA8A9E05C5AA49C91
+826B39636461E805364EA49E222129B12D357641D89411DC5081064473E78BE378BE642D
+16B4CA3D926E508E5905AB84C588EF25E3AE064348C93A28880A02B0665C2486BB41BCBC
+8CDB229607ECFD58E01D99D71BC1AE9DACE87D02D7567D570CE3BB7EBB5877A5E309B181
+0E75AB6AA6E2A72B9DAFDF89862C96141D72DAAA090F0EC8A239F1CB565C7B7523ADD890
+76109390815D4D128B26523BF36FFEEB3D1DEFB8C44460FE64C11F1183A99BBF9C5D7BAC
+B644531BC4873EEF693B2E5401D764F0172127F873786FE8A95142DACBEE14E4B1E11E5E
+13B3015B6344C9B27CAD49C457FFFDA86E0097D8533F76344AB561593CC09BDBC1758F07
+9F31AFC4BFCCFDC2D54B8FA7F1265E8AD350C44C940B8111B4A59D078423535205A22202
+92F892CC2A5AA50ABFA912D6FB0304EA164E191CCC659DA1E00B2DE5A6830B60D69AC9D3
+CEFEFC2CB0DC016B7FB41D5853A0BE141DC15CAE07A90E56187BAF3716B7A7CC839FB123
+69DCD8656F62C1E631FCED16D171A3521ACF60675FFD2911A20DFE45A57887984AE2C41C
+A8C6C24A12445E167CAC1A3FAF610DDCC8649C6F6CF07AF89125C6F37C70B682BB77394D
+F4F6E7A111A0ACA9CD25E1679891B3FE9FDB3EDDE1D3805DF7C42BC5FE4A6D91C7042F67
+6ECFE15B9A90AEA755B3E032C60A71554102A9FF4C2E9E467F0B7DB9CA0F2AC3CBC3CDFB
+8DC2A7365807E409E75E89047415598A8720B25CD32FBC18C12EF6E1F9A193132C0DA8AB
+134A567DE1BA0583E12BA2045A36C298ECC4F909510D29ACAE1EED825ADA28437F457BE1
+94FA7EA3ACD0119F438ED2A2A31BFC511BCC3CDBCDF34B6DE3DFC6F4836178D9BB35BF9A
+C546AD2D1527D1B020D2A975E83848CC431CCDAB997A195E2AB6B3D5A8980D5824EDA901
+EDBD85AA2B82480CC76BA911F2D4F7E2675E69F4005412AB2E88861A7D925EBDE0799075
+F858F32B8BBEBE0F6138D4C8AEB2EA647046C533519867FCF286E04AB146CE6EF4080A8B
+2026BDA70349038DE8C2B71B2B2834E57D4D486F95CAB49C4DDC2DD17D8C959101CD2DF3
+D9E4E9FEC4CC05B2490A90A30C898E8588CDEAC838565BD0B6B494F2DFA565A606789728
+0EAC877E47201EFF4329FE524BACE5E90E8525CA1F5206B83D1FBD284D1109651141B4F1
+CD1D1F5A0406B90E4FEB435BFFB60BEC00454F406B6CBCC3883F8D470226A8214207DA07
+76CEFA99D769166A8327F8543039B44FE297A1EC1611713846E67B20E0DF311F715E4CC0
+3D1AD8EE1D14FE0AA2D55D1C30F9C1F12C9D8BB8E5429FDC4247AD4718B634AE34213480
+45B9ABE0C2E231914402548748A388FFE3D5148DE9F9BE6CDC21DEE4B5F9FB0C3A52EE12
+A9B23D6815E76979C6266A811157E380AF6C7911D55DD522FB766932E2CD361406517268
+43C8C1EA841219D167757C201022045656A45FA93AEA1B404B16882F20BC30B36FC2DB62
+96DC200D567BA9B4D49366EC4D3AF556013DA5878F04B437257CCCD164EA4460E472DBFD
+AF091AF1C2131C55FD31E7DE78BF0380C4B34C89528CE0A36ECEDEBFFB34DC33AF1006F7
+EAE6444F7F063BD1B1B9C88850B1997D3A24BD1650FF98744C9A0CD6F7246CE22A1A91AC
+D1EA6FBD9237C32B80D6BF79B40A3E622E83DFF1366BC6B7B6295D5785BA00342C146BC2
+527FCF50B73C17B76D6B4B0B98BE03BAD8A67C7D547C866DB6FCAC78C69735F26DE9FE2C
+D9504F5AF31727791158F17D129677F5F9BAEF97A1899A7DAEEA53E70EC6C822C3F893B7
+3A4C313551553E902E762BC58D8D1E9508D9D3355D5FC528DA87BC94DD9EE305ED737379
+CEAC96549D3E7E505A13F11EBBF0BEAD38601BE5BF68B1EBBC504F8D9B4219307F7DE93B
+EA6B153F5BB35E2B50AE9309229698580334EA4590E06E41D834EF86DECDF64687DF0258
+6AB142A457531A9103D49D0D64FD583046A107210FF1FD544A8B07EA3DFCC04ED74BA498
+E927C72907E896B8E6C0C0FD016A42B6F45AD628761A78C405C51BC07DB9D90D54674B0C
+62F43785115A94708879349142D612DACF210116A3EE5F0AE9EFFFB694C328C73EB4FA11
+56E38C4E25BFCF9F441C2B0A6752091DD9F9C2175495B973CCC0EBDCD43125CADBE4DFA9
+3E11EE051D6D46B0B8A8C4DD6443D392CB7801D131DD58696594B1FFA5DB9D70F46E1C7A
+84B445E50922880FE987BF899BB603CA937D4DD3386C24D24AD31038CD9C5727AABF3DF3
+0FA105F554A39A091655147C8511B818A5932FA9B33C2B1DE319C5F704BD439ED6E1B8DD
+FDBFFBBB038B350E1B8579A1B2F55B24FCAFCBB6905F24C82A3FCE3374F979405E69BD62
+6346E4531E130DA4358CC11FAC6E705228CD1D4BD865DE15F2C8629E77CE5152E3CE5207
+D42D9265A4F27C5FC3AF11712F1736F56CAE5DB347163DE798EA934C189E5FD6ADF49DD8
+4E9692559753CAE3584F3C43902F775B9534A4B541DF22DDDF723339562A5785E37CC808
+47E59091A5A339467B57F15902EBD2399B55A19E098ED661A475A559E465A502CA339B3C
+64A55AA28D3DDF57133DE6FC6443B563A0D49F898E0CBF45E55748AEA9E7A215D26E07B2
+C8CEBD2D9D233D8E86D53D079691EA21DE11F9C4FE0D3C904C5FDCDF2301BE7C896C2FE1
+036C2B3D9EC21292BF87593E27BBDA40DB83CA23F65C56064816657C97DD53CFC7FB54E5
+353730E625C5B31F030BB0E1D09429E6C6496EBCB17C114667F9B8A31ED328AF0EE9E7F0
+1AD0E70AF25BF2BBE8F99A4AAE42A6466347CE5FECF91355D61A312C550AABF782CBF1CB
+649FD914B4AB1EC2BBDC6EFD65621921858E9CEAD02447DAC2CCD4D9D880BCB1513A5AF0
+D931F417C1342554E7EFE9529B18CB931453AFA51E2830037D2DBA79C565EDF25A0A7059
+315E242D82F2A32DACB9D86C62658FFB7E5A11D00B59CF45B48C1682FE8FC4A4FA41746F
+E6F734D86B7CA91C976D40B64601831546DF211405F1F44FB6B8FAD3E880B74B66A93783
+F12CBBA01B8D456A1BB0DB78EF455B230B53F95C4E7B13EAA9A8BD49F886CEDBD9066819
+085B30488B011B125737F16BB6B31908808E7B076BF88E2F23684929602C888BB3A51D29
+A3D8DF55B39A48E5115E686380452EC5784D09C44ACB5EB20ABF8DFA9DF66344BCFCF175
+A877296E511AC83765358D8C091B91A6C70AAEF9A66C2F36F6387D5795B60261381CAB7D
+9A1EF15EE18683C485317692DC0CCC859F5DCF51C3930355BEE5592A9E5DEE4360E8151B
+582E019C674501C0F27D1EEC05B1F55FE9F79C5FCA04AEC51BF01CF8BF5DEFA0C9DA4DF1
+0D923E6E56D35364023C84D9D71D68168A73ACA6A6CB8304C1A830C3CC7155D9C5141DBA
+165A1C733FF5320A1D1028B7B543D2A1516071D0C02AC030E52BF79E464D8938294A7D92
+5874AE6FCB352EFD4790F6973A627FD2979C19FBF19D2870FAEB6BE729D34FED4C87264D
+65FC15436A57DA96DC09C7CA864CEE0D98AE9C498F258C4599CC97A1B9095825760D06A5
+C53E257F54407EF4DEBE04606D65E3D09C01535736D3852089D8FC0D2CEB60BE19D959F0
+CE1858D5B4B72A953FDD1CAB16B1768236162A67C1B77CC4DF6393A480DA4223B65C9747
+67A08C86DD75BEBC418E370D5C2853523D68852E705A4BE611142EF56ED90583181D8559
+9AD285830BE0986BD8FABE86377F5529A5749A30C89A272711A694AE29E2700034B6B620
+5413F9BB288AA9B0BDE0E91CE8643E96C8A771FEFD1EFED94DF8D67CABBE928E3A845723
+BA2B85A2BF2BB4F784F2324040C42292BA0966DF1A495D7DA80B9B79F76D10F1A12D53E7
+A16B3175CBC39C1BE14A36CA1E3C7CABD9F8DA323243F0703C3BBABD48B1CD35BBF2755F
+2508FD2D66FDDD1DC21D232CCDD7CA5E749A841F82EFF35249BD72B0820CC69FF176164E
+EB3E885E1DA18762FCD40761FB5C91D692F2678BA2BC45CF1BECC0A8C28EFD62D1EE29BC
+2CA29D922AF0A592E19AC004573F357ABCFA00916487664065D3864EFBC54AE0A70952EF
+676B5087CDD43D9540C784DBAFA0C0ACB72E35CF6D82789E3352A16D379A4C26118C4B5B
+8E5C7258B2B9082556A1B018085F19168CB7787CA06283382260FA3743D036EC4142DD7D
+2654BF95651123718193310928CE49B532F6B26181B078228B97B4BACCD79F6A8DAF1004
+096284F2D45BA3BA14F1D0CAD558239BF696B1F2D6F6AA2D11693B497A7FF12BEB36F65C
+C453320F8241820AFA96FB54E83DF38BEA9C7A004EE4965EB7104982F4D7847D397B9EA5
+9F93C61BD259C3BAA15323EDA020E35DD78B7FBE6D7CAFC5C34D9C8A60B079EA6A3123FF
+B7352EA72DB9BF6C80E7D97AC188A9B8BEEE3C80819D35EDF1CE62AC4DA459EB208BFF41
+4A3EF9C4E3514F44EEDF60CB817EC66E3D698702B5DC889EE0C064A387C7487DD97B4EE1
+2792DAB796E4123E9D7F3191B22F2481A4602CFDE1E708EC6BFA63C771058B380EE6AD48
+2524F9F1FB75D470EC11226A138F4B9E5360AB443D5091B324271E8B251297D8236E3C5C
+E92AB19E2005DB4A8BB12950E6A3C47C16229F300F8BDEB8A54211BA195589F6C8CE22C1
+A32B3610EF0E43458132703F86AB9CCAE7F99CD7DA69EEE32CB011EEED797C841ADED034
+4BE043DC76BC7E5F877620283E923259EC2100FB83832D104A256105EE8FA5742D7E252A
+7539334AAACF79E4EFD98C32661AFCEEEB5A9CE44B2CEB765C6FC6B361E95CBAE60A8680
+D2741C9AC12B834BE5EE4F498B1FC7137BCDC32A225DBB86B1F342BE3FBB03A17624066D
+2D652F7F7F8D431AE8DC401FA2FC64AC056A9F29DFFBDE1E07BA398624F3337B6001D1B4
+F54E9E67B059415D43144EA8DDECCB6B57022B678CE554EC7979BC4DE26BBDA16059A3F1
+16457844011864CEA021FC099B7FC141923CEE982E2915C6D0C28767027E139BBA2EB02D
+49DD1B247EFC7A2A1504C4DCAF35305671CBB20B2BFEB0EAE475ED4AD53293B94A6E6AC8
+41FE1E9CACBADD1744428F6F992348A3B1D391CF65C86E2F1E57382D245C920C7CF3140D
+6AF604F686019AF155ABC0B0BB9835FC49755277A5DF9E6F0A7B8E91EEE7A2287704D71B
+64D4F6D0C927DF674B35A38E98CD7ED00B76966B2E44912BB1EB240C25AE3DE8E7668062
+55CFEBBE98D8A49657D1B230F8A9AFB157AB3BF74C8485F5A275B2C065797A9B3E1021DD
+7FC20AF45DBB60346C53E3CEEE031619153CAE0CA4A3C25458D73EC46E8B7196CEFFAD73
+6243CD4F81D73A2A7D0C3F58DFDEACFD4330655FA5082CB75FAEA9B99D8BE6A0FFF920FA
+9F8AA5CC2EFD3BD09C3B8A94BA03D1411D6AC5894A8402330D5564AF8E75AE549A11BD49
+E15B20F7879DAF938B09E430CE1B57EDD9346CA8AF022DE5548A4726D49E8DC439D7DE79
+7C006A7AA78B018A1D68E15AA83FAF97394FA4F0E1460DA5AA9710656AA1E294016F2F8F
+D7B10DFCD2D10AB59308DE6108C3D44CA6B5B1A0A5408E6FDCBDE1B5CF86CD7A9F815146
+B9721F11ECF3EFF7640EAEE03D8D3B4B4F055C6EA18A7FF129F369A1FDEB7B71A3223890
+BCAE11DB2848941B6323221AD976E5986280844ECB67C4A1ACE6BC87517A2DDB2F928A01
+8727B99FDCF0D0CFF57A0BEB04C7DA62E41E9623AF0FA6EB651E0D1C9C72140CFF8A7A2B
+BBA67EEF1AD2419BD5D399E09F2BAE43881E8AC834E46F6F1C96B6EB4DEEB32637DAFA37
+89C2BD92A4989F9AD822A6483D516A143EEF6DE93ACDFF3B118F8B80865EEA782EEF6DEF
+D8E5E9252B378E3F09E770F38CF1A71A5CA9E872EEC7E1AB4AE8B4DCEA41630FD47B9602
+81A711304DDA075014AD733B83D5631276F636D4A470C1DB8F5B1E1AC5B005FE2B5B4D79
+346B39D86048D7066C0F5476FA7E8A8F7D48488F49507237719121AAE83EF6938AF31754
+5C848CE4E8A118A8093F5720CC4884D3886A5BEA6312782D229ECDC11D4AA1731A5B098E
+DAFBB3EAF2C539FBFE55E96C1129EF344000D8DDD7C7CD53196B27AB252155A634FEA9D7
+971E3079ABD8F38DC7C166B5DC2D0B1C66D776BA678C5C57E8EFDD55EFA2F5B5FF8DADC6
+0F18A0026B3159C7FF28D5283E6835147CE4D5E5ECB6A8E537CDD7F8F7A0E7B6FC53292E
+FE0F780D9B58293F527159A8440C09FD842877464711F7256DD732AB76D834EFD0C5557B
+DE603FCF0E35B4025848595E585A7707A33F0693022B06FC2032659BA15DA56C183E51DE
+A5A8921061E9ADC27AB380DCFC851ABBD9A51632F60EF08C2FCF84A86A89516D66DBB232
+A4EF10707682B9AF6A9B584766C8432FE43BD4D2111F81446E0D508817D6E6742261939E
+36C71EE1945C10C1CF6FCA1236AE71A10957B57B1F8F69EDACBBB9898735D2071C073E43
+6585FE7EB0BC41E40DC59BCE6C311D84F9C41929DEE8317615033CE146B3C8DD7C1DFC28
+471226DCBB5A003FB6185793B313EACB67A443C60A2A7873EA4F13C0DEE9209D4829FBDE
+5E93380F14C2F04448CCCE8C92A0494E4F5BE68792D35D019F1C4279D261579261B6A990
+6ED88C23D9D7993D36FB0F0ACC744B14FCA75D62AFBDBDDE020DB4EC979F9A816DB0AA8F
+767A0CA4D561E00EE5917AA1FCCD701A8FA3BAC8AF96268B9E141D891F15B918882FBDF0
+4B611708AB3D464936D9AB17E781DE646C2BE7EBABF82F4D547F09719EB03FC702894480
+9E8C963D076BCF1DD1C29F3E6A57DDD550B4C50C940363F0015EC80F170B282BF9E9E8A8
+7E11B31975583D1B8678BE0F782DD2DA711A0EFDC5EFD9BCB47C4C458AE693207F67915B
+388CF71C508BE8A2E3336692A068097AFC21A42DF45A12CCD4E6E005857D04328032A455
+070E65A5F1574DD06B48CB94508FC3DAB04FC0D777C24F1B8A32F5401919441A01C7FEA8
+90AB7C15FE2FCFE62713F42E9ADECCFA5114E46E8FE38448282A694BEC76034775C730DE
+B2813ED4E2EB75C8D2CF9F6EAA42A82C5C711BE920E4497E4DC4F60ECD923B6F21FF8C9B
+2AE3EB19CBB422FD027B4C8CC503F523E7B18DD1858D1DA08C9B0D0B9C9870D549436AE8
+D21746C86310CB94923304496CB2112D91AFEA2776A9CC7CD79D381AB7E251B6B13E8DCC
+36DB7BDAB3AD9D22C7A9F6CEEE7C130E3753C4AFC946839697EFFDBC4005EACCDFEFC029
+9D259947810AFE57002A3FD3B9446977345BC5D5D53B6F9722C47DDA534BFF98C2433B0E
+EA965E20ABEA481A9C81C612ED51CCC35A74CDB473AD0A5D2E42950AC1F66DE6393BC9B7
+B02B00441EF8CC421695854293874A7168496467FACB15062D50600824D18F65E3FB83DC
+C5273D5743A84DB5CF9D38AAB1478BC6CC1F849ECDDD397DC56D1B1BA395684520D68729
+FF5132F4F7B48A17DD6FCC303871D6AA2F29CAEF2EF77E0C149829B9225746D43286D1D0
+940E765628810673F32809AE451309BDBAE942726E9A2D57711683B3C4D39F6DC393A20F
+BF0A8F4F73E8A103B3D9B12572BA4B846A0A9EF3702546EB97A046264F067FDC72CCD091
+E357B618687BE9E5C7E667914F44EECBF3DA82C9464380981288AB2F9B058DB262EF5BB3
+0A4E0327AF77B82AAF49479A96A6CE7051D2277EEBF286FECA3B0CFB56E1A94B147620DF
+BB6207691D8E751D5E468B36BD64C8220F2883A5DA60346EED5616F924660658111CE6A1
+0FE807C63FB67BECA2AC00D98C47B5F1CD6B9FCAA51848D97EAED90AFA582F925DB9DD91
+F77B73CE5BCFC0A8B21C4A75862B345ECD68545A4ED15FD4A3235429019E3C922537DFF6
+F0C2907B10D068D116EACC7E0C82EECD67C0A377E367500BAA0B47EE6444C4FA196C7DCB
+F1B080A2531A96E2A874DDD02793E72C1D259C3004474DFC91F2BA21554D2DBA3E4613D6
+535691E6E4AC04940353EC25951DB2D4EB2FCE5D701249B835FFED7C78225A84A24D138F
+631AB67295866BBBD000C1D5BD26B43EBBE4740716DA3D8293CE4E359792F7120811B32E
+2B378B876D41E70631187CEF898EDE78C0A8986CA30889A8F53C2344384E3FEFFBE7AF07
+171E031BFA6536E2E6719D934F74B39169E1D912790256B06BAD12CC3AE588B2B2DF1C7B
+ED6A3E99773C25BA78DAB1C8E902D65E4E55FA9005C4D80819AEB20723269B6C091AFEE9
+29D46C11C198A7BB0D4260EC9464156F655EB1D460DB7C72D932CA927D39EF98F35EB6DA
+7F8143A443DA3D0E909E6B846DC2DFBED888DB41F2C03D9C9B61F31B2E8334DB7205FA8E
+C2B94D71CCF61FDB51C66D8AF7A47417DEC7FFBD8A052779869E709F3B36BB74340E78D0
+3BED0A4618738C9D2C3C447C0D50BAFD176208820D1F314E21615B7A4397883F8D59E65E
+80A814CB6E8FBA91B0C410A8B7E37188C1849AA206A66162902591AA90F18E0426C586AE
+80F63CD8764DAB7FE811172A87AEE833E935F5F56AED5062E2B35F6077EA26AD8DBB1011
+745F36D936EE50A88144F211B37D8C169938EDBAF26E277DC7A921C0154317BB081A7537
+F0FC37CD6EBDB6F97130CCE08B85690E173D7158367C616412A63D0B8ABAEB47B1BE35D3
+23456EFCF7962953F630002DFEA23DF4672FEB5DA149B713FC91C94505596471E44D590C
+54FC5D336DF319A98AA87DB9D313B9DB208DDAF46FD5469AF90F548E704DE24E3344B95D
+6EED106864FAD4001FD8DE48DEB22C8AC3FAE18F7B176804DCE5AA2144A073FC9BFE4CAC
+CD6CA534902429E28CBEECFA8D984A71E77B5662A1AD114F301F548F192B11ED7EB56BB3
+F8FE62001753FBF161D538878778501F917441F9C5DC3B39704BC1A234117157303EEB24
+EF453A1E05208A07B8AB22DA331527E0871EE7D713917E86C80D2FEC3B934E5B7540C672
+34D0FA0E4AEE6A5B1706F2F3AE147690A76815F5575A5C5B44682028A065FE8037E10526
+5F282058D027620C117A57CACB77AE153E8517134168668E79017166CC435DD24831DE0F
+65872D49DF581C872FBD74E0E2502B9C0C741322E9CA72152E7DA26D84696366D3DB5C56
+943FE579F99CFE384EDEFEDFB30F7EF5ACFF5BB88327E5A63B796C7EA2461B21419592B3
+65DABD1DB63F6AFE1B959CD018163A48D82D0D36284F118263E9D2B8FA2E3104BAE034E1
+A1DEE263980EFDB385CD6D687D1092752D7E3A6C46D678BA2A2F3E208988AEF16EB2C67C
+0C5DDFC85C6819746A034BE35F5C6DC967D64005E4104A7EC6C55CEE199CAD3F98D83A22
+E9A32D0B0F4E7DDC4BF81D77914EC3C3DA3AAF51424CE3B50AB293152EF0EC717F16815C
+4ACCEA27FFF69DAD5AC1DD549C6CB01F23F3C5A3DA340CD914849991C554202076C37DBC
+7FD48DF9DF23F5DDDBCEFE0114A2877C31385A184742AF5AB3007908A359240E9DBB0AC9
+501B7BAA815CC273D953E0D50802CAF8C00FCC054B10F0AB7C072C573FC4D3EF018754EA
+32203E847125B73AD879F613804FFB9470CF39D0694155B3D5D500E3379A163C86CB1AD7
+85C3AD12B724AA4F203C212FC0FB7051CD0EEFA161920E515FC83EBE802800D1C851E085
+B069541D8E183032EE5FB6D8200376FF0FA5786796E7B33352601711A2323AB0F2CB64A9
+B71C936643B259BB73CAD6D04B33201FD772599DC49B9611533D53630A3C91A6DA4E3CFF
+519BB469F2C23613B0D445D98377E8EEE6218E0CF7333EB5C4257AE30DC6F8FD35C5978D
+4071F0D9464C260223902E3C76703BB2E3B3FDD9ACB3F6E43C3BBEDDDAA846A4893A6E6D
+6E8D5AF8FD12DFCBEF1B5D8F537AEE87AD8AB3B486910F0013FA6239528F698F61B6A2FC
+FA7CDF66B238222B989DD390A1647AFDB9AB7E287F5CD96B7E443C293B39C7C8A91A207D
+E7F0A73A48387C9955747277BCA7E97EC37EF0741EDC541F9804C12F95F3325F2E80CCCE
+0CA03C931C7FFFB7419BB3B2A3A67325DAE74C4D597C41E922B09ED70F411F7E29486C5A
+3D94A857CC69502C6DFBB6E63780DC3908B989F01116B28CD8BA096CD0B09B3EF4AC8E64
+55FC7300CD8861EE2F1FEEFCC03D95FAE9DCA58000441A1D3419B77DA35E80CA40C0C49C
+E1DAA21511AF32DDCCF3935CF78808330C469C4F12481571303335C945937C0080E56DF3
+ADAE10198495A9E04DA1AD8453A5C3B7D9E6E8A8F6F57BA249F0E9CCDFCD8D25C8E39BCE
+2B158052D9112093EDB087E2DAAA0C835634BF21B6C767D7D622BFC669B78040109BD4E3
+673468377348A6EF3D0E6D1D7BE8A07BEAE0D72CC158FFD8904003E7D928F7F9B78097AB
+A98804FF2BEEB62C695333EA76444009C03751DA71269219D0B30BE98C710803DC3C1159
+2CF0B2D8317B13358B3D96F2B79F801E303417DC8FFA4C1B5B246C5167410518BF7B122F
+072E1C356BB87B6BAA4B36609C3CBC4FF578ABCB0A9B4241AC991354B9BE34E831FBDDA1
+D97665C37DD1AA4E2E2AF3D41D2E9561646C40D622883D790D6986C60A2E5B2D27D9370F
+0F2E57DBCEBDB45A6244D1DDE4F64D30B94621B21EBDD2DD7F87E75E9BC4F47F1E94450F
+AB7D3A2687C66FE4495A05AD81E2C0AB09B4814422272290A024FC55819E7DDB08666BB6
+FF9C9C4F1AB70697649197C550C48D221DD1BFFD20AD9B43F876F19CD818F3EBAD352B94
+03A050E79CA2A369363033508882A1B63D0755B43E01BBDFE55E7F6C171E1A6BB37365F5
+6241C6DF75D3E1B1364A655982D595C66A186310A5B2B3A4C99D39069337E0B7F3448D7E
+E8AB0C5EF3AD79CD8D9C86C1E54392437C1077573076513C0DACCE6D16A3ECCED9C438BC
+F7859B1ECB294B03260BA9D9890424DAA816587C4004FF0905C6026A04E130E3B59F1952
+02270BCEFD5B7CF306389D3F255EC17C85C6C53D597E11DB5C1E0902508F22044441EEA9
+A474CB66BC40D45A2E0DEF1C83FC4432E155567ED91D8A928D2986479F149E4AB3987D95
+93B419964BFCA0E042CCF7807B125F29E22A488BDB19285FCAB04AC29A564D599075B2E5
+B3CF0C6D53BCC23C1ED6A5206A6AE91E2F21AFDD4542D64A85F397B3CB0DC1F2A0C2AA87
+5C38974242DFB90B4CA67259D610BC8691037931C69D18242CF469FADC88CDC85FDEB881
+A431ADFD4071F3C856EE5BA0196D1A7F157887642EB50C8662ACF5BBD27C4038206FD907
+8AB7146AF5B02FBC3B84E61DC936C2B79F204C8765D6F366CE1DE4FAA944852EA71AA25E
+BFD160E6286C927FC76EB19F4C5878B5D847FC5A941B8F2A1C7C38A0C310DDDB5D171E4D
+0A1774ED965F237A5396E5A94F87367DB141DACB4448F67789C26DCE06FA01C92014ACD0
+1209D727E37A5C64067B2DC0F91530D8AAF59DE0D750B2A18BE91D7A3362EB026C438FAB
+EB0AB75C8B2F4137D843BE8EF156CFA20563E291B34F19F97081D4E43F4A62DC72591D54
+289D839CD857540EFA38AE1A02A13EEE35A0A4A3576FF6AD5598A76B3E83FB67F5062FDA
+4A2DA616282CEFC090E154EBEE481B906CC206AC6A5A9AA442265E95CA379785B96E76DC
+D4095708AF8A65DC213E42581C59359F3B48EFE9F20AA85E04EBD4F8B4B8201607BC2CFF
+FC71D43AB06A3D82E766054F2A54734A38A714058C7573B847C8A3A82304638F2579F037
+83B88E29709F5AED8F17F68BFED85C7589F5343D8A1B73935D693E70E49F67EBF2E85104
+F1A384F7D6BB00AB4067F816CB11C71C625136E073E4C98486A5972DF70B5537693FF55C
+DA94FFF774F7C10120F4836B9E26941B8AD2E48B90D71ED129A48DB73DDC0E7CD569272F
+33014FABEABE382BC029832CA1A7EEFBCBD24CB435B58703F1E9909FF7D30D37154F2D5A
+29CFDBE1892DBAACC07E68544AD4A1E672DD620A5EA6F84B360D6B0C9D2A16600731892F
+4BA194089DD0D829F7DDE7885C7FDB37B8DB601623B7B398070E617E2DB13AA6B7C7EDA1
+352570A133F0DD267E23EF4885DDD4B6A2EFAD3B55741CE7B36475A878228A200A49202D
+13A9EC655051C1EC4FB61E9D3C1029D21C4B943A64479F82B247759FE49DBCD64EAD1605
+81159DDDF18584457D99949AF2F2EE4F2E3AED242C25919F51CB76A188867D5959D8AF10
+FCCC2DD8D2EBD266B751EDF244BB8284A4705E1A4649A050348AE54A048E515F29469FDD
+B04A905C3B9C2B3744455C781BE4487DB56A085A9BDF8F8256FA4C1B37DFF3295F5418AE
+C03ADCB277B3157A1DA2D7176E12B334A49E7CB311D6BEE45459160E34B024E8B68A1768
+E83A7B8D7E0D5167E4BC7EA55157A20C82EF009A2631CF53205E11B7D0E7675329822052
+C2FD7C1FA61D269A90B94A4F103E6FB3EF6B1B0304ECF573EEBB1A432F7AC539EB7D40CD
+C2F67D1D3E87E6B66CC16B63E00EA442036DA83A7E3CC8F2946CA59FCC0C085D642DE6CF
+7C8B642EE62B830ABCC7CDE13DEE8C11A4718ACE97C8D47BE41AF8DFB4A95D44EDD219FA
+137541C53086519D6F32112A2507D37B2EB7D2FC10AE66CC5D5A2D6A4F8E6F084A95C923
+CB40B8437D3D51231B50C72DC5FEC25ADEAED8D72EA6FE59859CD3512F36A0A46D55607A
+AA143A65CCA0203366C702554B905A093B2E845FD90002C689CFCFFF02586DBEBCB11688
+7FF863EA45DD0EED511F4CAF921015383CA0391E393A44419B34E82789A62502C19B3287
+DEF1F5B24C60F5677576902DCF76F00BC4D3A056875990D18BA69154154C76B2BAA38ACC
+39C8C1D55892583B7C32CBE6411834223200F22B416709FCF635EA5016BC3CCAE42C68EF
+AA30B0EE474890D25C9EB745915FB60F517600C7F380582C7BDF4B34FADC9C60CB139D03
+626F4DAC953F9446C02331E2804245F7AF2BABE7FD2636854AF0CC676792580B228AF541
+6172AFF0C2FD5730C2D71C9FA3E17D36F9AA4120E180D025B710EB9F95AD8AE31B66D872
+20F028D258A85409CDF37158F840C2F418A0470357AA99A825A9537D24BCEB415329EB6D
+5D985445AB19B08ACFC1F58510119ED297B034334EEAEA319D0EF5F7DBE4836DF61041FE
+071BCDF1644E9C2D924251049CEEB73548286CC1EA170F0895771CED237B33FA8EAF5571
+E22C890F0B552D319EDE4A59928F14FFDD911F08C17E939FC035D7AEEFCD77AB4A2E7C4D
+91B25D75F5C6CE9122C27E0E4A033417F389CF8796EE0F55794001AD285C9285436E983C
+94ACA66A8C8027689688D0FA18DB23BEEF57C73CE751FC6ED14FB4D9601080258B7D4885
+4CF3F9A8DC58E073B3D2961729AD90372490C0202095ABF65A8C95691D7A32DC000B6FB3
+EFE315D903FF04A6B366788B5A5FADA322BDC00BFE337DFEF5EA0B899E36CC226DCE1B75
+CC352F71064E7F05420E4C3D1102F55E082E04F1CDA182E5DFFB5EF1283E721CECC5978A
+A1EFACAB70A21438B380BE3A972AF19381FCDFCC60FF173ABA8BC049D0D9F22DBD722FED
+1711CCDF75C710D083B0F3A56338A7708DEA014BA01943086306885854CBBFB8E372AD75
+6A00B5CE723A2558D80EA8B34F987AF7828CC5457865D9299E3070077F8D04D94C569806
+97CCB42D01ECF928629FDDC07CF668E87ED8313BDAA0D5FD84B0B416FA83998B1ABC0B03
+A3E43B188B7D74287A1463CF2967C7FF64335B205A69E974789EF5741A6CA9A3B62FAE04
+37B957A01ADC30C6C1CEBFAA7044161B9A094377D57E4E990FEA040EE9E37414D70376A3
+66D16916752F4F51F45171892908A53A3F6EE0497A69CE4D4F4085B1BC10F65623456980
+DDCE8C933CAC5C779D518720F5B8F511C8FE4C53E23103A12B2FA4DD02938ECA2AE76C58
+000D38B2FA467C1E1A8A442F9EC4F02E0DABB0204F2AE527B6F7CC775DCD07DBD96C589A
+B912F727B9B81FCDEC5B3761842E845FDB6CF3840CF0F183F2ECFD28A92BB4F5CCE7DE8A
+ED8912F728E39646F57DDD2816BCB3BE81DBF41DB3D3837BDF55B60E083EEFCD1A012A38
+846E025EC9AF4CA745679C60F88F01E3AEE7B65599AB02836F7A1F192466F5F729483DD8
+7C2E1CC75A61F0D7171C85DB04073B9A319A2F2B76C632AF2ED220FD9D7A1F9010836070
+E0D864D1D31180C1B6E35B6CA08D7261CC843915F15F802B3613E14218DC9EB7548A5680
+C1A9E7A6AB73A75DB974B4359BC428F1CDD2BA5E7F4590DCD96F1C3BD35AAF8549463541
+2A28027140D352FD0D9EFD97CCE7A86729432B246EDBC0A54EDDD6E67636A6F908BA5BD5
+0A90F4F1365DEE1C1E8989C0AC6C4A64861096C1B1D3CFAE51DDDD96CC24C5C11275EC50
+5F8DBCB44E345EBEEAD458D458A177542F5EE64FEEACA55A61AF8738E6BF38A6C9B211DC
+F7F2675EB86CF3711C97FF23FB5F5FEB1867467158BC75F7BF7414BA151937085005B8DA
+A6D82F31DCA1007E8D3D317D13BDE2428072D2A3A2743EBD214348B15EC3504426FDF73E
+3588BD1789A8FB8BCC1E1A021BF64D274EF0C9FAC95EB50E2D7A1768E82BDB5A4239DD1D
+9DD8E1775D3BD4CC4C07523E74FA545D5D650E9BC87B80E41EAAAD235833D1CF3B6B9411
+4EC21687773049E082646C8F29641D858D9890B41FE8C54649F840A0B81166130722EFFC
+A6446C5509D988E0B4A9AE8E8765E1DFEF579A6D658C4781BA3B3DACB899F0AC467B9C14
+C66C8930E9A8558C8A19AFD95FFF4A3DADD1DDF80245C2F5F91D23B39CAAF4D2BB1216F6
+4490CBDD7FEFED8406D62DDA4A4B0F0FD80487C9752A0948F74930FD47AAD59FFB8B5540
+DE795994B0B6F209699D1DBFE7B7A94DF25522C7BF57C77EE9530784756D2FD8D058B9F3
+BEE20B4BCD63C950F9A4A01F66680608D66AA87E2FE5FBCC265505325711299F6E8F54FD
+1686C4B532C504753EA7BA292A91A0FEB9E5BD690F1FC1D1B16D3B9870CB2CD14F7454A0
+8F365FA3FF1F0A8A33F9476A7053BF19ADB66EE28825530115BF79F60AE108B28822EC6F
+313C14E43C02FE8871307F481D8B00F0E7C847A3F239723F4003226EE84B31A72F19BE81
+CB986F92710E37B1F6F263403CBB97392DDC7550F03A1ED56165B3082314995D75A4588A
+C4E503C6BFF1E642802E0C3F1058B45E370D3DEEC937533E1CCAB26BEA94E9F89F6C5DE7
+6701DA7753CD1FFE77A42B11765EC6F80520EE01878ACB37096CB9C091387AB3BD68205D
+1CA6E5BDFFABB2550E6B942F65FA977D55A459DDBFE4E17581CC19FC3B589F976EC22F91
+8E95546F8A447EA621DC289B7B7D67CC9C246322B221E6EFF507C2DBD4A93E41C2F7AD94
+4BBBB57372F85E601FFB6984CA66A5B7E98650E84F498AF13C4B0EEB0038953B5A33DEA6
+9CAD47277A632B26BE464E87951E89B8E0C051BC34220EC245E6E31383B22980AC124D84
+3662E9A1C8663100520AEE44DA661F4307BE10122C14D706993A586C7400BA3C74F020B2
+047CCBE55A6DCCA5AD37AACF9ADC82A59060518FA39649A726CF23543CE91A1A1070FCFF
+CA48C8C6A9B02CC28479D8F58040984250C0AA0F581DFC8A5F978EC3DEAD276FBF7722C0
+2C3E41D993368CC019110A5ABD10C1ACD5A5705160AF288A60BA2AFD20D22099265BD254
+28EDA9461AC8193680AD019787902636FF81AF8C0CFE7BF8C064850BAE2E652CAB330EAF
+13508DC67B881361C4F29B45D9885BC4CE554493AB16F995A98D40B7DB137953488710E2
+03295B129EB42BE45B089F8F40D505380EC2EC7C1DDCA1940DB8678A1CA0232F3140FDC9
+C00FC77392237C66F9A0A8B88A7D7D7162F72A1319BB22E8DDF62DDE64C9796FEB38C360
+D00F5C94FB772344423AECC5B4491B100A2A93D716B57B5B44083101335682DC6BCAC0DC
+B500EF88D04F4F955A1214F56508DFCE4299A8B5DDE9A997E431A55B0E8DB6CA1C332502
+200C5C5899731AF052BC28D2980C00DB0DAEA4CA5EAF199A5DBD0BF794AC18CBACC20981
+96FD0AC31CEB455C61991445EBE8AC899B9AE530847D5DF608D011437B2FB24E4A1C45F8
+05FE4FF8D4109B5394447D7C9FAE9F57EB904B7D6635C77377D84D628F0BB1898FD9DEB9
+3E82CC2ACF52553E9ADDEB1E275280C62E4E8AC9722C5E1CB54DE4C4DCCCE6166F7F70C1
+50747CE19775F12C19E4A81599CB9C57918A42BB0E9AA638429B13B606EFA7EE2FBD7632
+0275BA3CCEB743B7101BCDDB2CE5EDF843E8944E4D87E1BBEF47C9D5611E1805CA0F2850
+CF8A205D53F054DD143C3C90D9605C3B7AF045C553A6332D791209DE72E02C146312B25A
+9A5F4AFDBCD83EB67685ACF487664FCF0CA5C455F5848E18A5ABCC174F55984E368335D7
+BC77BE4E2923147A111FC8CC57CBFD5BD87D09867347F01E11DA0780E4FDE4DDA54833CB
+10ED212340A0180CDC5924F675AC6DAE629555524297FD133BBACC4F51BA326AB7D07DCE
+2093D6DC8E6126DEDE9ECBA129DF931399C72CE690C0B119B117A14E3AFC18094DEF65C8
+4DE9705255D3D411BDC6958D872CBAB28C9586DA888066A2A00B05FB21B5DFE2B9B4C87A
+A0C4D7B91EFC7E8076DC5817C35652903605B78FEBFF1B4783A170D8060FC151CE533755
+7B8B3B1EE083114F977201446CB8A5BFB5DDF0852365330CD5C82CFA9BB2DFA6BABDF675
+45586F4D28605BCCCD80BA8B59B501C629D6E6BD5D676665462D5DB2784C5D6D8A42B406
+11700F3A27FD143BC1EFD859F7705C795EEEA9FFE57E25AECCC5C7E270833AA9604C6248
+612C356B6D9937E3B770F3B4FD632A0D8778C5EE2CE62C4E780AF5CFAC1C7C564637044C
+0C8C90B9BD886F9BDC287FA97D4B4F4E4E8D7816BB25DD740D8C9307B94DFC8E8E91F41A
+189E20E2B438AFC4F42607744E8BF74F3106312D7480A71840D4994ECB0A7A088784AA68
+84BF4DA162D5C38A4EC6354D19F06313DF2D4167B57BD2E5F544490D711E4B97F8D5B68B
+F4098D8C9F2D8B8256EA8CCE05D189DEF0E86938052C44D7DA68445A6AEB7AEFD865BC96
+592DD991DB7FF294AC7DD8241E23DE5C908046179B44B9E8A79472154E254D44BD9FFF4A
+435B05DEB14C08377D2ABCB8A26F706A366335F2DBFBF5D59B9DA9C67CB396A17A40C874
+C28E4AB5E242B6AE244EF37D90C8699BF1F2D5F8CD1D3130C0CA72B7040991FA90B3C413
+699CEFA97113609A486483E2A72DDF26953094C4E2970A243DE23963F929C3CED76AB062
+8072F5AF6EE3F950DCF88F57F33CABA2C8E4598D4FA6AF46656512E180DEA02FE3BC8701
+C4EFD669BDB52129FEC53E6FC55499680208E6A874BE255EC21B8C75A9D0D8A2622A4CFA
+7E6BB9E8986AD3EE513F341C595AB2A14784466170C4D6DC2E9BAC82B988CA2609FF4B01
+185CC5A2B639A028E4A378503F55C147E6F8B30CFE5380A7A07981C15BE3C7120257C67B
+4B603314DC2B65A2E4036151713B934F460FBC1B052417B907F70FA06E2219F310E34443
+A17AD4524ADCD140341BF982EE4D8DE7D969AC5621129C600231B16E97B62B6F618CBBCB
+638020E75A77DBE28CB0EC9E4221F5D573DEE815512CEBEA629E6761617E69BA730B1EE6
+14C96D5758E519783F0862FB4F5C10D444882A344972A91E12051B2B29DFEF503D8762AD
+895871D7CD4CC8BE62E1315831FC25712EA1C4DAFE49CA332CCDB5AC2C2D67F6594D592D
+221B7DE7E93261E9D34179DE194AB2F4F4DA9DF9EE3EFAFEA6F1193940AED5655FEFCEE9
+E38DB186C5B5DAC4B0AA13A89EA5E81303A681133ED154B164E3A1D416DF8623A38213E8
+049B876C7C22F625A57248C0B61E4DE518F982E11672AF1765984203B7B7A17C2CD7C7A3
+847B6FCE423541C14C6712572DBE3BB99D1144021286B4E3939560998BC16A6CB47F9905
+BD48B9E25D1B548F6AED304BAD2823E364DAC055423B76800ECDA7C554211DB47BD28200
+79FE362F799925A8BEC4B4770574290D0654CEC588933BE1845BE51FDA15760DAB3257C2
+67E89BA950E833DDF7D7FC37F54AFE1954B006E3C758ED7BF3B28217EF77FFE36196D8A0
+A81157CA87889D7239BCC205459C3A11B808545C8A256F97F3B7369EDD1CF5D916E71B0A
+77BBC006A71865EB15837635FFAED75D3172D91BF820230392B102D1C6AE05F36AD0236C
+90133DEAF1B0F7658B6121D1F2F293DBCC6524C89A3554827D44601BFAB910BB7C908B8A
+7EB7E84221ADDE214CDEB6B74765F2E8148F013F4D6CFEC4C7BB344D82B176D665A98424
+CC385736C4E1D81808ED22869C8132E5EFBFCCDFD1DEF732C3604BB683E4728EB60386E4
+D03D08E76B36DB7D39F07F505FC13A336B7AFF4D9587D1EFA16105FFFEEEB8BC2406766A
+D3742312A7DA69A7B666A178BE43DE659D46CFB1A0309EBEF7B886EA3B3B554EB7225644
+EEDCADBBA3978EA1EB59B35EEE61BF1396A61922DC59487016F66561EFCEA19F30295719
+156A8C9099F0C07B5C076DCEA85C4924ADB96095AF46C1F9BA08BFAD5A4DC49E95CAB635
+CF1DFAE9A1FDB81E27609EEBE67A9636AF703415EFBF5EF0EAF7C10B1B04F139E60FE96A
+6BB3104555EF08139F1641575A227E86F0DF716C829AEB4BC5CA32128AE75286C6CE0147
+F4D6873FF3B94A6CA54F701B9494B380D65E691F988CF7C6D74BF67A42F169FE5AF96CDA
+656683349FBD542386DB635D09CC032C6BD486D08ABCD17A69C7FBDB61378024D2866932
+47E834F7BE079A875D8243E46E1533BCD01EAD3BB390A727226935F1BB5A9A1C395C92FB
+679D980E6E67EECF4DEB74D75C164D53DAA8AA3955A91C29F28AECFC65BA8D7572374DE4
+F35056460B36941E7E0BAB36B8C28E081A29D92526D2F19BE960DB6CB355003BEB9B3054
+2A56413F77FCFA28B73258A8F4D473C04F8876C2B32901F62FDCF97261B3CF09D0BD6087
+ADD051543706CDFEF061C5F909E6BACFB2DCA11F38DA994E7BE7373AC2877648A0628662
+00AEE5E012297FFFCF714986436209EAFF78C09FBD9C54160A4D4C0629FE3F85CE065438
+8A996B462D6F520EFEDF8EA2578FBD42753A2882BB3FFFE6F65A89D0A74E27F306BBED76
+1F35A13A1DBE04D998F5CD63054D98D5A209E82637FB48929F7C70C154F66B6E40DB0F74
+18C103D628A4BEB3BD0455D886D752D58009ACB9D52EEF4F119F22CE23AABF40C558BA77
+5363C68AEFA720A3B14576B1EFD95405666BDB2966B36C206DF8DC7C2797412602A7603E
+C13F0F2FE5747134C666FC26974D7FE913158CBEDA9AD94535099E136A43B962A93F881D
+880E205772643F2B60C8BCEC7E4612BF86F9C0FA3A2F13191C1A6C3D50B35D6E07F8ED98
+1B6D2F8DE15FD9709A8E541A0276CCA6542FF3B921CF5A5EB6FA0AFD68A952114C9A3F8E
+3B3FF6CFB9EAAB6DBBC62F38461824B3D0831C5E560C6459E6453B629B95F9D2CD117AD6
+E038075BE1D25A833FCB17D3FF657B483AB6CB82FE2AF17EC4AF1FDCC3FD6942A0425826
+3DE038F6D17E3F79404D44819424A2A4C559D44241D5F577FD60A00990FC2D14C271DBA2
+177747C6DE94CBC7C9C72D0459752D7E9680CE0181DBB43180AF135BCEE65DEBE77C1687
+078AB912E9183A60EE6229F6B9ADBA395A5559739C3E29C8B0EB221A036BA888FABE661B
+F4D4EE0B4B6D62C5A6C96EF3C57A8B104E14B9DF763CC16B81729D771B557C4CD2191384
+0B40201E52A80869810ACF32FF93C005CD90B15F8628832CC689542A4D4DE58B55B050B8
+3E246BF54510B53218A2C556758FCC89C07E5E7D892AB0B9264529368EF16CC4BD6348B9
+57F2D5AAA98E0F999D4D400E77CBE175D35F004A19AB64F00169769EFE8E7D287A7C024C
+A1A0D3F915EFBB25CF9604BBDECDA184C0D81EEB197FFC04B2190687D6086DC57FC08F7F
+2DA512C57A3B9CE44115F9A6A7434E203CAB798A8ED7A68D9DEC0919B0B7B334337B652C
+34F200CA9C679806B47152B2325AA1D1275B62F78B8610CE4D37F7F7DDD281AE294B7DAB
+508AFE5492C4A497DF7D37837D43ED2A3D91C04ABCA7B0F7414A451ED560D20B0164DB0F
+227CC753A9CD526F8C57468912A3780F3E9A6D626405FB486F6945AED27C48661FE726AF
+EDF3D69BC7ACF0CC657CFFD5347869D16AC4C6ED41F643C9BC981425125B563065DD7963
+22413E1EBADDAA6993AA9629CF048863BB3AAE34B44308D27C48B6F4F9E8E1CE6C471466
+678EE304328CCD8EF1DE777AE28EA758360EE7BE768332794871E18009B99351710E22F1
+83146E57B21C72EB728B83C9BC618904CC0094FDB26814C8667AFA12D26076575D26106B
+1407B08EBAB89EEEE0CAF34616054550D610DB759C168E26C08557822B995606459FE74F
+1D085225CF359A8092A9175FB03ECA2812D7467622F4F0132EB4B1DC6C40CC969842000C
+3DDEDCDCFA0E8CA62B214E34F1051F468224AA8D0867170019FE82F745DB85ACE622A175
+E50A3A371D5580313E08E2BE5A6262A83CF8B6DF0A02F258F81C636D02F381AB20166A5C
+AD53633533D61E534CFAB2899BFAC061ED7734EF53E7652C6D56186FC27D54991C8411CD
+D2E9D048910765AF119118607413B556016B075BB4245947B9ECB4DE17C38172AF945904
+92630EF8789A3B7D973C9152A4EAA90AE6C984622AAC31DD7952553DB1289CD44C16A3F6
+7FCF7BB135F885F083A539D05DD1128322FBA172737E00842BD674AE3AD8CB68D95004F7
+0EB5E23E04182E56D4E9355FEF193B4606D4C3D6B9275521AC4EE52E7148DE5196E7F84E
+A8E19C639D8D20F70EA1D413CE48295B47880A8535F8E0A626E913543AD381A8259FC5FA
+593DBE84701260503BFDF27E719A99635B710F44EB5382AC3E6444E6B7C6D5931AD45866
+08F06FD25CFFC918DFB136AE01275EEA017BFD989D0236E7297EAE998B198FD2DCA030A3
+B851EF96074946664C4C12A680DF7A412475EF3E641DE2644A11F9FECF59332241712B76
+4E6F32AA42AB853E51078416EAE47704A0063CDE2E539A46DC16516C1E4680A8B1785BF6
+CFA86A558F74164390C3D35DB0CB7659910B6709393EBF9397920D1CA964859983FB49BF
+7DF5472D866E654ED33A10B1726A5F3DA71B93CF1A21AD65ED51DEBE5625236470C49485
+AA53F0271E41C2A20553C67DC3388EB8C51EBF88E533B014FB9CCECD1CE071FEB8353D85
+E89DEDC7AC71C3873601B71CCC7BA3B5988DED9FF85CD350ED374EB8BBF2813854EACAE8
+3460EC71E78B7EFF1EDC8EB3E7AF2764C63760B38F6015B5299A1B1969251CF1E80B8E50
+4EC30439ABD13E9FE242520E37F523A1CE4008A75E490C2D5283F66FF5CEF6A97FE86B78
+4551D1B4BA916A12CD2BF1434FC74F43342297E4E6BC9E0A0C9F54ED31CDF86C93847E27
+B3C4DF7815D96E6DC9E88DF85BB7956FEC3DE7E867765E6986DCF54BE77F07AC3E36F27D
+C4C0BCAE8CF485A549534819543CBBF33C6DC3B04766DBC4DBEEE029DF6D7AF91D1170E6
+1F7968397BBFA987A4C4BC74CE816AAC3646A02C8E216BF2CED3FBE06C98AD6C5168A570
+98AFDC8F3D4C59616DBA4D3DD61E7774F6583644B27E85A670EA442C9D575265A892A87D
+07583509186E84C57EC343221FCB436F363AF502CB6CE631EC7711DBB3C37FCAD34D110E
+B82FF2F7209B3F68EBCA22D918D3FE424215139DC75CA266904FD5F6D40269D39517051D
+5B077D26B22F5D3F07CEB35444782EAC7DD819A401590F38571C148EBEA2E682E472DBFA
+43103B2183117A9002D04D419A7DB18BE5365FE9F8E2F8498035A992ACC07EE86E1A2AAE
+1258DC4B4C6F8D0D930B31FD0EEA876D0D726C7328DC4D5C76B6BEEE6190EB3B650F88D6
+45BC3FB7822F2DB69C2174C93E39A70320B47816BA3E8EA313BBF34C3EE729112A0C9254
+1D09C9BFDB31F939E8D03E31BD3263500F7B92E6072E1A418F7A70112C7C3609799A7203
+3A1809AAA623C58E93213D12DD3A8C37F3E156A7435A42D3AA20E62DC8D4D69BC694DB70
+533729E878603C0CFFEE8D5A4C1A7F29EB6E07799846CC096A8257643A9F85D5CC913E03
+E72C1030636E078D42761C2C3F0E1E84C205B4D8A3D17F63BE4D70ADC45F2DDF2B5121AA
+A4AB3D909D1FE0179CF72BDEA0250B110CB4F74648535A1E9BE45A8844EB110F60C490AC
+BAA48F32526582B619AF1DCEEA109B7DCCE048996547BE21D4DF519608B5ABDA68ABCDE7
+AADC339F5626E64C93110B21C112E12B5E75F15A8FF5B0DCDFE85A1E2F0968E721C242E0
+4B9543CE6D394F8D00B20A007EDA10672C511445DCD8470ED2413862E6809C15A2E9205D
+E522936138B66C44D5BB9B20C908A6CC8D6F6DEDF3568E5EC6672107A24032130CB5D5CC
+B8849075CC87FF04B7D8D5370E0294C87D20283B1E6D54679D4E73CBD1D7BE72B992E0C7
+0686C5BC456FC44BD468B6B1BB22D7DACC0FF36C94AC831D391CB9FCADE8F469A5F89414
+B22001501F06BA70414A074A4B7A6A0F2AA2AEA1DAE282C549ED6F656394D187E68940DD
+EEAFD5414238578E2A5757134DA9B6730BEDDF727773B2EC1A17E4DEEEA30482475C93BC
+484083883EAC5E0D7AA0DAC552FC82F99D6522FEFD818F8023B1F945FB86AB96713B3041
+03F2B5E3913A5D769D5033B2B23D69BB7F21E34B0E808A750A89885CDB2B65B490F7EE6F
+DD0A636187F0271C9DA27274A01D4380A02BDECD5D7A5A1AE228C22532838CCA3750A8FF
+48D831F27F3712E85B956F03F534D2A478F8F819EDE0071BF9132F78DC0F5B7D578FC0DA
+B3BA0CAC5FD186610C32FF89D130E0AB9E9E2980D9069D4AF6EA32E2ABFFE99B09BF4FF6
+588E56A2A87DB9313742A901826BFD2C80526CA519010BC7290C8B3A9F47B917343D0698
+E17565724A7DB1207EBC6B16B449D9E8B67F7CF227AF62815C71E553F644B89ACC4B9EE3
+A8CB7073905DE06FB65E44E0A762AA5D3A109B5A9092658CFD43E64F634BC8C16945DE3C
+267546354C88EA3C459AF00C4DA9214692BDA482D65130CB6ACAAA37CFAF3CB336090A42
+E7C67D0961B02F1B2C167726893D18FA3092EA8B2CD553480FCCBCE14BE635D0399225A5
+F65F995B463D640A43FBFD8892A6DD3E0B284455EACD55F2F973023DB12EC59EFAADE85F
+55139137DD595514800B235421CCAC9B0CEF4701977406565B494E6AA763FDE3127B2695
+6F0E38CEE9988649FDC62BB0C46DA3D253ED787F2997F0285CF008F7E34586E304AC3AA4
+87316B18797A189483105B0B4F9C96BC191A337667B58678C725BCCC51A5DE3FC6564C2D
+35432A453B0E92F550EE81A89AE84B79C3A0E22E6A23D0F2C263660AEE964EA461A40BE5
+8D2B1CEC1CD8342B764DF2A9901F20B0A7B44E5EAB40D3F0A0601794E5B42ECB812AE487
+4B96EFF33C2BA5801A2511B074F335AF4A530880F73F7A4344D22B2A9AAEC85B1D26C878
+201247E53901F4C41CEE45555EEBB174270919C0448DAC16160EB7AE2B09E96ABD9C09AE
+B7A95C4B5226D8F3125DD27E6CF0CF6E2A0D5CD6BFB414ABBC6C4A382E5B7F34BF4BBFAB
+013F885C4F224147075FDAACA41AF49F4D9034C22B0B9483DE0B075E641B5B3ABDAD073B
+0374B79BF3A07FCD45C148C8374401B57421B9B57CCAA25D4C8CC7C9EC5BFAD5879CCC93
+665C1BE2826EBB24893C36F75F9617BE4A54E01FC7A2F52DC845C95AAB9505EE18E370CC
+B5F6DFDD80DCDA36A05051C3478022A57E91F4A078F5B486F88C17763C285A2CDB6615BD
+62544FBAC5F75939A9153D31ED2CB79ACA1FF6F2483EA35AA9CA0582C2F2DE156E8BEEB7
+EF12CF7453475E7460A3E92DC95BF6189CE2144B23D4FE778E29AD6120B5B93F441D6FFC
+0310F8F22E39393A21F342A59688B6C11A66A3AF852AAA03C46A932587AA5D3685A3F4DF
+B1B857FB12619686F7FC6C2430B9C24F1311DDBBCFC8FC294D84EF5E99FF22EF6BB4B2D2
+20B301EB713FA8C76EC566A253A5A7DD2323D70FF5B48F2CA57A9D3F94C737326D2CBBD2
+2D7FEE0100D039D28474A64372EEC52C616F800C2CC1B53BA93A18E153CB91E089EF0F12
+318E3A844F017EF68C496477D1EFBED61D215ABE6467563A625FC0563E2A113B6A58C7CA
+75ABA028750E3444F6B19DBD850DA52880F3D8B765A8E9310A1F22502BF2ACD7A3E40191
+3A1D8B7B79BA0CD8D85225CC31474CBAF4479834FF184475C7FB6EACCDD0D5F1733FC56B
+BFFEA34E08A0B7EC795FBCFD8149E900F00B6E207B6E9464880A5344C309FD2BBBC58D32
+68EF30C36BB5A5C892013E8832BA813AFE822D11B3E3ACFD02CA56421671DA938398F57D
+11FD157449D3E423DB6A0A4EBCE845936F542BEB5B31406A6B5C8842783A5E19A6E8FDC7
+94D322239F4866F9EFD89CD88D9FF11C167AA63A9B6707DB1356D757C80623F10B31C661
+FE9D9F118208851FB3DDB8B0DD1937005B15D900B8B854C4571F3A9C1D0D67909E1AA591
+A59B2A45B5D8F481EF7B5DD6D4E6C8CD5FBA9C812F8BEB1C2A6E4BF8F51D7A507D6B6E18
+1991B5D4955FE3210612526CF495CDF2C3CD39A26F4BF6D98DD43C4D407D261C603B837F
+E8E09B15F403D721FA990224D46FEA9D7931D4CAFE3181F21B3B47A1D3910913C3110A1A
+45EE125EE773556E17EB3BC516E336B2C7733D8FE30FB7C22626BF7D94EDF00FD945EC44
+0D4570B85180A90BC46B280069BBF5B69A3DCEF13EF0F159B07FD5DE0289EAC807EFD6F8
+30A20CFE8DEF807947EC1442EDBC9C32701A9CE873748F33ABE5BBA35A85453DFAFC4CBA
+2F01ADE4DECE86290C4DCDFD676DA97B69BAC7A8BD920C4345DDEC907CA183FBDDD2638E
+D5432F9188CEA76B10E40260C4A8B559FBC422C41143432EC319E1727E8989EEF94B85A1
+8FE398A4928F6554DA075ECAF0A5B9305580853E010CB59142F847621234B4B7DAC52D86
+151E920633C2951731D4534A174CA7685E8F617EBA01DC1C756F91F8456DE200DD557AA6
+830A506DF674D90871943F822ABAC2867414D3B9D8D410E8BE29C00C7FBFA5B03858146B
+DEEB557A662A30F1C858376DFADD19125C60CF5A73C1B4B0BA6B6218F1BAE096C21F004D
+8716DBEC943156F291C61FA23F1FC37C20CA2CA6CD42A3A1223CC0DA7ECCC0D4C2604EF5
+796F53C1749E6B5E2E22F52A2BA077D324253BFAD6563AC2F6126B3F94E160D579BD0DE3
+8806C554406E63CC803A83D29E0DDE72B999D345E655899DD0E9873CA47C216C902A7443
+3F54D6D8BB3A716DFA65239FA2AF27DE88A97E521119041FC89312C4B23AC10861590A65
+871B7F0731BF11E3712182E7FD8AC4C94C366E93BE90243B0F5C29201E418CDF3DCD649F
+0D9A0C1696B0EDCB31616DB976F4761FD47AFC1872CAE6802FB506DD67737DCC10A658C1
+DA0CD9A920A96E5CECB844A302FF0C312C5D7A8801203EFDED0049FF37E9887132A484C4
+1D332E72A6FCE3C3D48705D86F4187910AEAD72CED404526CDCE1B8A34C91FFE62BCC410
+64663903D557C5CEE087600C09E32C8EB537EA43F56C62E78DA50FD5F598C0FEC55BD912
+BADFA2F5DD75523FB189146F92B31FDF6BCDD1119867C6480B258FB96A916092301679EA
+E82FE1D96EE14E382B00484A2F983FA5272B2B86280917EA80DA0449286CE2042B893755
+EC15ADDD93C432CD6989F9B6B8DE2A83A94F2B5FF22CC849DAB24A224DEA14A11BD68F10
+06FA67E62E6507B027F21A940F7E63A09BC9BC5299143AEA8B008665C9EB1F584D7070B2
+FD5B5E0C10FDE0AE740FC6C5FFBC1693FF4D2285D87392FEAC408409016980AAC25D93BA
+3C3F5E1F432706E6122FE76519F584F96A552D58855495FE5F0F4919DF8285C668416523
+DA7F2703095BFB3621FE24F6F2C97C073FC5AED60F7A32CDDF72327A1A0D32D58BB98F97
+01FF1F6CE4ACB58F44090E39269DA552D9E242806BBBEE9B65A619728E863896C26AE155
+6CE6915DC42ADB2E3A386FC4CBE64EF8CDD835A84783991F9274DF20FB6B1FEC860E54AD
+44F85774FD50E3B7817173C23DD46003BCE91605B7F861666F0774489635F4611060EA85
+8D66ADAA95B2BB066285F485B6CFC8FD3754B01CA01266D27BFD2712F4DECF25AB7FEDB2
+A4455070BB51804379A3D4D184E89B1D1BF94F870800CADAA95FB57B1227F0B691D253D4
+A85EFB1D8D182049259115AD8272544FBD0CD49E7A9F551E22F027272C60A1367CEA64CE
+49A07AA8183B4B471D83072DF31DBD739B6F64158165F8941084E880C8CC46F06F3AC420
+B70E97D8A8B3DE6478633FBD016C258DDD12DE9062988CB9CEC82E21D9960971AFBFE9C8
+B2DB92E3F848653BF165A78118962E8DBE219E4FDCD68BA661541B0220B2AA0CAD74284C
+8F28AC3E19638A0EB29903E703FC1145A0E9D33584455E5D1FA7BD6A733F8D8AA9AFF447
+583B0176258139CA3757A4FEA374425E9BE34B4683B392B6E334951FDF4E6047077B7011
+39F27A73FD2B4B115D8D408EA5E14636470794941040894AB66F19EFCFE812AB289C3315
+2EB58271E458B257F63715B3C05B454AAA50290F32AD47F089DABB1C480D92D69FF08211
+7C867A731F50E3EC9DA99D966AE570F584494A3A55EFA002D97D3A0EAD08DAD1494E57FD
+61EF7BA94C4D0C3E85732A07994726452A69DB3C27DFAFEA6BD6A2D192264E6B4B846A30
+A6BB1625381511EE16BE4CD4D5C7CE332A8524AD748DE4ACC5E08F3167E99F63B785964D
+B5871FCE8BB244F5DA0C7F00C5D198B13904D2B57A8399420AC2DF333B638F2A29B2E261
+D447F2AD9EA4F11128EDD65C6524A6B53412A7E92B1F3D7B4F7338A1CEB909357ADB0819
+57C48AD11E96AF967A60638E91B6FEEB4AD90C33F98AD1EA2B51F302B51D6D1ED82DBE81
+3DA68ECE9BD145FA28B7B6A5D6A9F7141439DFDA0E2D59530751F16B010326B54FCEEAEE
+2E5644C6F693FECC5AFB1F64CCA65DE08A89584B90D0B6B5C5F4CF75F2C2B1CFD0D32B2B
+F7101CE6BAEE7D0E845E975D44FDB3297D0944B9268E367A2608BF4BABFE4142B692CD16
+73AC17BBFB416A37580302558CAC6F7549CD60B75C9B5960A86E050612E9EE6DEAF19EE2
+6219E9C5D28AA076B3FA2504C1523269F093A0E00268E765CEF7DA0DF01AA3DAA12926B1
+A89D9BB8ABEA16CA2D2867790C7553E1E87F8CDA07810A4D94AEFFBC15FBF4D543BE0967
+B11D2FBD221D5BDDAF28718E4042000F5FBC07CD343FC7E6D9A94B8F6E9EB3B02D5BC584
+9AFA37ED5AEFAD28217ED06986DB0F51D4632CC5D1E2A49B950C3666815FB44BD4059294
+7401269A17539E88901FCE325629E59AD0CC15D6C3FF32D2497DC7A9797582D88C7F03CC
+F2F230692DD463F4A471540737E6995FC32200E7BDAE53AC1465188312C2FB7B52ED98F9
+FE530B8F1CF8A6675FB9E603F58BE9CAC46585B6D305D888822806BC5FF084210489FB79
+2E511A939E01E69AD152624777EE98EA396DEC7D2C633290FBA60BBC153D9A0C1DC5A269
+740EF5CF4B2879A839932E1C8850D1EF95E8B5A0D719351EFC71D7AEEF92EF29D3C41D90
+86DDA4AAA9735908CFEB590E365B69B2D2FEF8193FB2CB24113859F3BD2E99F01F2B1B4E
+080300193B5AB6F7711522EEC833D74A13F8686A6E585E7B6315FA28EA544B4EAE4EF62B
+88B781FED5741046AC84484CDD1B670017F0D0D2F19D3EF24E984B14CD052E3B38553850
+6307817BA3938801B9E1D137447D979B5148AC1B822D49059EEB945AEC4DC1EBEC2FF6CD
+DFB19A0370A02F9CAA30B6725A6CDCBCA72242B805E6559BFD292668FB5ECE523F0F44E0
+E75D483645B6988AFB0D5E8EC5688CB56B69A7B6A7F160ECC40894BAE45AD555571CC25B
+A86E81C5931DC238346DACF3EA05C078D309693F1E812BA249D84F6AD605D073B22AC83A
+F2749BF32A32C9115AC414D58A78D96A0F480C706266244B6A668486F54A16973E7A83B6
+36EB03E66507A277958C19D9AD4DE66BEE89B7463731F724DF5650CBE74EC300665131C4
+01BCC4D03891C6ABB61FADEDD7C83D56F35BAD5D731E0B3EA4F9C9A07FE5D3DCE21B5BAA
+1C8E79B19E38CD61EB802B2C2F467D1A8129D45788B85C9F7B53232501ABC0768CF3830C
+308A87783868ACC346DD0141702B517E5C07B5E29B238E55549F98EC3BBDB67EEC173ACB
+0DD4B3550D958C7E777D39F9C21CAA5B51404C28DE12061DCA1CD427089D2AD99D23DF19
+B0729235CA955CBC5E4077A0FFBF3BB64ACF02204B706733BE9CB2EFBFDF21F62E4E7ED9
+34A78E626472A53747557AE2C209324D1F8278E31FF96305F0BB41DB5B165AED08AD9312
+F1FBF368E09C4A4004649E40D578DECB4A1F82EF4EAF76BD8CDA9C4C61EB1E187E7E319E
+03EFEF18E4969C5DCAB53D8CF41AF5D4DB3D9CCBE23D1A126CB60B1864DEF1B702995622
+9BDFF2387711F1F06B807841406515B774B970666855333607B4DBEB4B670F6A452AD43D
+FA2F83DF711AAEFD9FD74A307335AE574B4097AF88C2B4C928BDBF40F822BA98F7F8CBE6
+26DB9AF8DB0B6A309680C026E9FCAC9A541974056EEA1A0F9F71AF08237DC5FA78D8C38E
+5E057DD2812E4591CA207000DD62CFF38CB97C8049B8CFDF0CE6BA900CCC85E02C758C1C
+27B00DBC3FDDDE584457C872ED79218368C8D8F36079045A6B9AD62AAD7A53E2ABF1AA60
+4AB15BEEF2736FC7AABED55B17B8E665B58D03CC42F70EEA4AF5F1D82B4EA91ED721C498
+DE4DBFF06C3E58E0350BF931D27189680C68C68D73555F02B76F1A786B4FEAD6D6FF846E
+370790C8529BEFE512A8AE178689A55C747FB7603D3F9A4BFC36FE91CF212CCC569CB895
+7680FD2D466A1C057C0022B4972841AE7746C47813AA324519B461AAACCAE87134DAA64F
+093742B7B3B691274EA2148071E77E636AE14ECD0CC3C9CC7C18ADB23954FBE043DB23E4
+DA069CDD55E908173D71582A774B57793F5228274CA43C4EC01FE31CE14699656A9EB6AD
+9468D7CA25467349B9F56CF2873A09467107F6B9C20147D2095B7294FCBB671EDF0B804D
+76F6E1AA7CE9D7CF60CDF7F85AD1C410422A779B908F3E6F6C8571B6FC4F7F012FB99FEB
+4292E9F354A3E9DAB81E22D4C75DA3BE9C8868BF2395D815D097010EF8A6A58CC91A6FBA
+C59344E785465D4B91F7633D1718D16852CE793825CC4B422EC90C3216999A55400FE0F7
+CDC38A0F6360802991885FEB799FFDB3C1C87C0127CA781A22BFB9AA8A6D6E414DD2C31C
+CA6304577E4D617A5388657632349D4F49D1582152E43683200FC465146137FF942F1888
+44975B7A2E508083B0261E8EACC54747310FFA32C00A0DF9B59F77A360349E259D9DB841
+47ED76941E8C8C6F053116A004C3998B7C84D94B60044480D048AB31F355B8F6768C189B
+E4A024183988E8C3717BE19D29B4BAA4A94A3624C0DC4F8A7A99121DCC71EA32D2B8D6E3
+B4DAA6B632E8D64717D32CC76C1322BF2FA82D3C349E7FBFAC44BA0304E4AB4A8689D819
+CC3A0DD336BB7E45CA84991DE87CA3C615E3DDED468DC67E402BAFE01E096C61E0BE0645
+AD50A227015278116EAEBF7895E5513E4A811BB90E1D2E204F3E0E656B3F75D25008E84A
+9FC4AE44628B7B38A484E23992C2C1EC229EE966480FCEEE199F0892689FA18B489F2C31
+F2F2196620809EF6E0524D99A86C627B053EA195870585D6B3C54C3B55C80E352482998A
+2673772C4524BB4467A867FD953C07504C6154201CF96D422D0A3151342FC9C66DE45FD1
+29EEDFC9ADF67374A4C1CD2E76048EA9D4212A32F468E74007A6C3A8251DAAC735228DA0
+5C245346BFB1903F217D62F63087721672EC60B846652D9CE8AA2350919ACB2D8490C6B0
+5B63EC808D611BB1D7AC1CB102AD7350773DC8248384D1FCD72953CE507723529CD4202F
+AAA080F519FABBFA48C620A1511A2FCDA8BA96E7784520AE0093AC58623AFCDAF0EEF6B2
+5DC8813512254752576AA9608DBADCA38F319EBF5164C1244FC3B6DF2523D8D8F19D23E3
+53C1C484FA52DA7B8D84D71100B076BC3082DDF29D6A14AE8BBC72B1626F882C1B98EB3D
+F31DE2C5174A0AC1E5F2F82EB3CFA93EF6741473DA694CE020EAC6E1EF41636351E12946
+E3BA2B1D0246D059563F2BEDE7A67648AE6CA534F32E52FE7F4F2CC936F9EF70C8EF1597
+A073E36D237BD34A3CA8BAD7D01C54BA5012C690D680158A694D2CC0362B7FFB8A888A39
+F2CB418D7FDEC46B0E5F104A032581415B083A992D6E8CB4D0E9FA93ADDACCE7BA34D919
+9E579DC050DA9032B1C8ACE46D1E2D224556FC0FFDC35FED173D86FFFED1AAE13734D1DA
+D2F06EDFC4FD311FC2279A79783B7C56928D5EA6F8FB4560776F99BABD3D228E8C62CCE6
+C06B7A122FC441CC5490C9085C8A469F524403B8ACF9A607651464467DE098CE068FC171
+55ED9489C819F31A3BA4E1EA3C728212D8C40CC1FDA9EC60AED881A93A411592719E4FFF
+B035AA8F25B9DA96D536969496A96B05BACF2BF1C7BA6EC50759CE388EB3625683C753E0
+E3383877F4B2F74B1951730F51ACC3B0107B6DAE39AD2B17E78B4194F5C8D162CA37104A
+E00F81F7E254B4D1104C01F404F41CEF92CBA628122589CED905CDE34196FE690EDE9CD9
+AEB0B9D7645D051E78CDDC34B58A64308A2CAE739A825F18525688E03E6138F5DA8D8898
+539F5E4BFC1C64DB496A16D9542674AD655EEA6DAB57AE3FD9058532AD0301CA47AD0B4C
+6998716CEF388E0B2FAD6D14578958FFA3330E3759FB8EBC2C25C61EF372235135D2853F
+CF308CF00441DEB973BB742C7CF4AB0C189B9FAB10C7969777928CC525D9C122781AEFEE
+8B82537EB27D7B264F5CC973B096B13C688DA097128CA6467997A5401DCD797F08EBF73F
+AFB5EFAE784C63F5D81CB073FA5DDA3B8F78FBCB37AD0CD54514F07C59B6FEDF0C86FC6C
+C0C5E03D5B75B147D0EFE4A484A55555F7FB840BC2DDC488A1AE3C26A22A7975C57090C5
+D2A8E484E6E7831AA47BAD43DF7C1D5C92AFE866DCE8E0B81E5D36DAA24FEF28D44C5E67
+18B277E8CED636116EF9EFC5DD3F06241C40F23A6334BD4C7DB7523C565A669C19EF1578
+329B297AE7F4EB69E25EC5F9BA77635BDED28ED33E3D1FCC4EC257E4BAEBE188003E3AC6
+BB930837230D7625415B260E4CAA348690646BD20F33E1022E1926AC163A59CB3BAD761A
+CF10756E27B6FF79801478D2B3F1CEA0B64835439C60AA4D861B7C4FF471A169482B751A
+C64854226AD0E38528F72B72FD8472D83909464F26AD09804D05D3B6DFAAEFBF0D0AF345
+CE1BD364299B1646141C294AC917E55458DEAFDDF0A9734218D5F5685F0ADDEBE6231377
+006D9E3FB3FEC843050CE2050D818396BA57EBCBA3ACF483A42EAF1C434B35216305BBD3
+F9598DDE9BEE0B47A4B8984849063BA638D97AEF425CE3C5A82F3A4B2CCFCF9711B77599
+32D10869BA44FD4DE4D9EAA863C811DEBE27EB910C265492A45BAA73973E3D8849218608
+0B6285D62F797879D6E118341BBB8AA44D0FE79DD91FD58F988D53AD07C17AE0EDA91C84
+8F2E83031A8BE1569D1E7FF432BDC605E434CD52BDBD52BDFA689A6A52AA4204BBF90ED6
+5A206B03D55B8E275755DD2853D6D944AC74107C3160AD7E87324BE16F5B0D6FC37DC819
+8259AD5C06483BC15F983B4FA914BE907B9AE230E655EB1FBAE374EBFB84553420C34D61
+AB2523A8C838526A9C88A1467E0C27AE1C3DEC1B011D156C8D8C2AEA0B7ABDA324656AB1
+AC7D4F5CEC922426E9D5DCAD965E0D4D0C5F4A223230E157A22DDFA14FFECEB183168421
+CB6462B3109211D59D9F00AE30827E55F27C17A7248446A21F4107973B0BC987919E692E
+1F76F7F540F7A4C440597B265290601FCCEF11BAAD4FAF3DDC4AE6218213F42F2BB253BC
+E6B0EF2E6C3858988141C626DA7A65D7E48175E4DE032CF76619736AE7BBE01C026A3970
+EC79C5DFE931F076DB5F674C163E5367F03AE6E2E7271B273CE5EF0004D7AE89B63DB32C
+0064FE4980ADCDE7357820F5943FF1B2AC49DBA19B2F124F15C7AEED84CA6F15C30A9A39
+3C7D492A0460E2000CDA313E9E420C5F5E47F959CC2329B6F8A1B7B818F0D44A2A176614
+D847F360F445A4168693257AE71D832577FD2E432EFF0E9322B3B4A404EE13501645466F
+5CE3B19EA1016D089DF6F96E5377A68592B981E728FE3DFB2449C7F187B3DED6F5DB1D55
+14FAD8DC06D95B6B4377AD1F0BCF7B744EC490328CB734FB1A45506F9B6EA2B85E7CF093
+742CB10D1D5FB7664A9A7DA82C2C2DA07F43A95CDFD02B9EE4D954B2BBDA540689DE8A37
+62219CEDEDE4C78F7E314EB519996C0610ABD85C749012C63973AE84DE4BF8B6B1333024
+BB6E856DE3BED4C890DA1B7612689910607EBC32814DBBDBF179AC0E7C8C0A31B19775EA
+14DDC7057CA38E53EE24A11CFF34A4E78672C14B215A8F7B70F3B6231E8C9E2206052580
+902E05AD3FFE970ED2228053898E3EE2605B4D4B364D463F0F3ADECA545BF39E0B14E0E3
+A7E5429E661A9718CC86D935E11FB2DC10FB436AAB75BE0AA27B8480AEA99AE6ACC68698
+7D69781BC4791A2A202B0289BADD16C29FD7A5C7C1146E51B4441F1BB5CBBB04D54C336D
+B0AD62057F7F97AF8F7BFFAE47D1BD86D2936B8BABF25E91E41CD8917AAF282949F0D9EB
+1D4ED2B89478BC159FD71E7207A65437B20D18144E4BEFA99C89983FBB71240EAAB20E62
+40E63F517EA139D1AC71946470F28E0BC26DFCFDD4533FA5BFC0C663F53C42BBFC16CB96
+8C0E61E2A6C4DB7B688ADD4E2F9D1010FA4B4E8E278236C66C7C1E5FE6B3EF982A970C22
+11006A98ABA967E7BCFA17176463E2509AA6218FE0A7CBEBD9F9151370FCC669EEA0AFA7
+265F498B879C4C94AD02327D680059C8F7A388260D1013DB99887C5BED8A68925C3D9E0D
+56335F93A402BE584D1798266F41C5FF3C647DDD2C2D788A7A56C8278303C0E9F20F8595
+4F6B47B79B6CB9C6FC80AE76BABFEC2B750B5ECB267A6866AFC68A51F6FAC54B84B9FDE5
+54165EC7104F5626108754BF07116A75EDE93A35CBE84FE778DC3BD50A8421A959B512D7
+E7881889E5AD2DCAF9CEF64E86A98BF5384D4F341B53CED94D430F3DAEFB506EA693FA23
+6830EC178791B015ABE069A44CE20752334986A43EC06F8ED44B0796FA741F0B18BA5821
+10C4D7C3B9B681047FBCF17DCAE103ADA23C9D41955B2C0DF276D5DEAE83A941E8241B51
+DD9FAC40AE8FA3B9308470CCCE30E17C1C015019E1A69BE8A054194A1190B956F414D473
+DC5605BC7284C0025F01A715D7282736704B3E824BEC160772EA327572384DFFA650A292
+FEF417B2C4B395AF893BCA339134D3BDE3E4A8CE7D76E2556C59D7292003C5487DF76D55
+4549FE9977FDDE5460389F32D5663656528C257C2057EA3EB5D70D20F550824C71DE3212
+32A29241C8BE67ED9540B3F461A001C8F63898DCE28423A3F5CE806DEE0B50E8F5A76C86
+530491F67C48B8683996B6BBF6DBC1666BC6E9B2BF4624701A67B52F792333DC12CC6142
+B2568EBB0ADDD4F9F3443D45204B013E098E62C6ABE0FB14C2158574A7C0B24EDCFE3557
+2C5C30294889CDA3C7C1C67558AA3C05D012F516479DEFCAB7ADB890F9E96E9615634176
+5E8BDD3CA8E85DA76443A538AD530EAEB42E6876FC74AF2B6AC2526F64C8D323B5F5CFC3
+BAE26A4F30D4477EFBDF054BC83513705CE5830AF048CFEBFB4AADDF2E7483A4F1860D18
+7D318914C3622F4EA58942D5527484D2AF2D0AE2DF74A1975268F9ECE82E364F5A3B186E
+39A4A10049D6358C044B6B05E9B90217D0A3BC0EBE473DF1A7CE2A4DA8D5648DE7BA58DF
+0335B7A4C4DB44B2BC583DF0394BBF14541329B64142B6FF4E37F523DDAFD8C1067DBE8E
+4770563B8AE958C26BB51920158795D0A4DE9DDD3C2874A572436749FF5535BDB59E8C83
+E421F605083516551E89A2FE34FB9B4AE55036A3D7ADC71F64281A3C54EAAC2670CB34E2
+AE94E71943719DDD21B8AA335EA3181896301B065FB0519AC8160BF9FE18957E5B72396E
+240ED3A9779F04FBEDC858B2DFCA71863A17E73D53958AAC58CED0DD0026D562BE9F395B
+49C12C0C29D4B84C28881D17B10F5026F8B208BAA6DA070F94110587A76E00282D3CC5BA
+D88C3A9A714C063F8B325495644DCCEC332257733448C50A40DE95BA8E5AD73FBBE404AE
+EA1B1F49DE4F9F1770B73ACB5E9CC4B5D1204A97335197B14DCB3DA403DA430EF0C2CB46
+E050B1E17FE0105A619BCAE09A33CA4DD54E84B8568299C1F2EB116C16D54DE40D9880D1
+B2FE45706CF0340CD591FB94B130BF0EEEB3F1EA675B032AA0A780F0E0E69A63E932E01F
+43EB43DE97EF02CAD65BD2013569695789971D843DF14DEE9A32A1EF22BAAD4A4468AC40
+588EFF9BF91CE0C09C30DF0E2504AB95E85E70F6769679C12EC83204FF0C5CEC67A26CAE
+748F530A80ED96E3C6D28F8F12F5B3A7A53B1BE5B096B0D186784402A3CC1D4EE4162128
+D0FF956979EF79DEEDB9732249CA150D159D1FF502E33E4A305F066A9617BCB637DEB999
+DE15A2DFCF9297E2E93F65D90A233B7F512882AB88439B26B9C672A08EC301262BD37164
+37191838D992F15154E96EA15454E4EE9E9D4C01CE2090120620F5E5A0849036975EDDE7
+9E207B17DFA344C8300D07BF024C89B9621F8FDA10A5032197BA4B6C127FC68C3D1397E2
+88219E9F151363321807084F8596DB0A24A8D6E41732C843C01843A9B4D9C1041D28C7F3
+F4DD289EAE019B6E8A3CA2952A8BFAAE3CFA6F0527BD3CC9544196A0DBBCAE1F095C3674
+B34358049CF212CD96530B9875DE99D93BFF4D87E544C7FF8E79F757ACBFC7DED0A8FB1B
+4BD53D1E76FE95E930E3F329DF6310107223E4E576F38CECAEF561B5E95CAAEAD603B792
+F1B1BB7EBE2C73E7144AD8D50F0581AE74C9A811A52E986FB6E249F9290E515639900754
+C8FBF4ABD9F642970190D28CF4BEEFC7C39D1271DE2A357949A69BDC6D8343487BF6BD25
+1C1DBC1132B1FA6FDB4D3233ED570D9310F8C9DD92B7217EEDAE942A25DDD6D5C24BB4F3
+9809C658BCD0CE41C70709AB8899E4956D9615C1A2B1A627E47CCC17DA3454291667EE26
+AF97D99AECD1F7AAA7AEC910734786FC797D819AA8D539D10EE8DEF86E4499010310E241
+C9FCC7F3E2B0FCC692D9B2D8346717A5781E6AACF1A891E2E6E65225F35026AE348E0E16
+7475CE6A9A0C14FB588A483B9483AC475043907935061B48D03677ECFEB8377235E44F7F
+581F02557B6F009E964A4C345494EF9EB4427ABF1D2DECCE71A87D55C57ED6E561CFB835
+8C8A38E387531A6D04AA87F5AA92D73B2DF8C972402001B9FA67DADE45F803540AD55272
+AAC3A49F23F910EBEE137F616544F86DC7E33CF672859A545677018279B5D1AB673640DB
+4EB45C3049D2BAB6116D34B3CF6A88ADFCA5A657E93C32EF5912DBCE65C9527C068D03D5
+A23A29E934391FB4317CADA46B7CA8A4F0440CACC958028D20197C1F1C0D3CF39F107548
+5928CFC10177DC70FB5133A7ECC5C82C978858DC1CF44A53B4461E85B6591131B19806BE
+EB57CF868D200A7F27567F124140D712AC0DF6D6FB8045671207AB0CA4735D4422EE8133
+3E0143072416E707CDEC20286F72E3070E374D79D95CE144AEEC86E6DC9001B991F15CDE
+9EE7E8368B4BACF9DBA6E83848E5A3088C2858C71BB5841E990BEF89DE5ED42A6EF9F0B7
+8127DBF344A29104E9272D0ED77B5C32D245B17293C54F8D939E314350B42D95A3A2F4D7
+6FEC437F8CA935638E8558D7919ABD0DBD6323F83AF703B38E8445FDCACC8F1919D2BD4D
+808D18FE28285B62FA958B34CFF05150BFC884F0A323F67CBEFB98B393607F500530A1BB
+CD2E2C93D25EF97621F872091C13D1BACDCE7DF636FFA29B24C51111E7C10F0FBD250FD7
+0899B2D370B955A7B467F9C726CCA0C1B05938FAB3357BD97FFC32A78589BAD9B54CEB88
+E0C95CDF9387637A043394276D50FD4E6A6170DB7325B11EA2145BAD3643F51114332630
+229198CC4A68C207E61284CE848E0CB6F9F7FB24E72D5D0877F2697F39F7F9F713FE2360
+A199760E993836E477943388D08EF210C1C782E086639B507CA9CD5428FFF902EA82B280
+DD203279043B62ED9C93150CE5D365C3ABB3C353172273AFF2C75BCB68FADEC1964DAABA
+777D83401AA12D8B5173796F691D8A2E9BE7FDA49421AB46A014EF1C566B78AA4889C684
+D45B5C9181DCD1B12D4BFCC354454B6A85C4FA25E74D55A1C6CCE8C4FB9ECAAF885BE22C
+A5DBE8ECBCF909D4487E6C64DD9B489DF6BF4B1F2A38B7D18983B2E41696D55446FE1261
+11A0940EB96A23142770F5A17CD8D89E85C6CF269F6041B0F32467D1DE4C0335F543CC07
+492BD7BFD0209DFEEE502FEE06D2D0EA9A0F81CD36DBBFA8E386BF486338444DCA97AA8F
+83FDC85A8A88A801854C22B3849467A660173E5E81C055E30CDC869B1BB9C367923A3491
+F51197DC9971B477FE060AAC5C91FF8D67677C3B08705254972D8CBB0DB05A10771844A8
+4391AC7B60179F20E345D2C9DFDFE1C42D947DB12F84F1CE05991AB56FE498345230BB3C
+7F92A3AF86D20828D86E931BEBC818BE595D2E17D3F9E105E39649E89E13656F9461087A
+36E1DB0DCD850BBCD07249227B65E494CE8C88BC106F7CEA5EFE48E482F66F5F6763A766
+0262501535FA5FC71CFA87BFDA2F8FD2BFF0553D2008EBF081BC56BBA010C00081EA5D80
+190C4FFD7A105FE500915F6F652A0A00FF97A7C825E8617077473C38B5D820C24F78E387
+A776A8904C265AE4CABF3D1845011DB66A4D732F842FFD7CA1F5FB53714D0EA9F43AD20D
+280FEBA87134571F5405A57094243FB22E12635ADBF0D1900E93684D1D8B5EB04D9D01CE
+A3CAD54C9B4666E336DC6EF82DA6915CEC1F11C89E249B0A5C460BE552BFB4AD545CEE0A
+3A97B65EEBDE82FA1893442E7446C901C50838934D82DB73DB7780946506B966CA83A142
+5D1A82EA07C3941EB1942325E258A5F39BC9D7B8D84F7AC876C9E47B854BE1D40154A54A
+DC42BBB5E5D318A6E8B2B985F2F87F5A2486F261CCB59F171111D04D29E38CCB692F21D4
+E5909148ABDA6CE4FCD577E3EB39D8199C63E1EE22443B0176D84D2EC501F16BD5B01826
+67DCD1C99DF0A8B3F27BEDD2917BB900484171D2AAA6E0B39FED994DEA6FBA6877EF4D94
+F552177A83541F4111D1EAFE83A5D102A011726403648B148DEFD8754E91E52BFA9A5F80
+273475A427EF5C5CA4D981A2D98AA00A4BEAA2779FF342B5EC0A452F860620B88AFBAE3E
+1FFC666C05647B3E73CD54BF35FF47411585FC84CFD702FA116EBDEB396AF5D9C298C3CB
+BD97E8EE08EAADB0C854F18D2AC5D08771ABBCE5B70895E8F04C3CCC49525BBA4407E081
+62A272E0F623578EF4502FE2DD325DD87021079967B1FD01B95E8A0CC6E65317D947B340
+7B42052106F27ECBF69B431C6D73F9CE9220BE91C38E1AA2F9779E128BDA6A76ADE5AB3E
+B9744A6365A95368D5F7C9C297F5AF8C0E21B16FB8B8DDDE4AC3EE393BE599B2B3E3698D
+38C84A69DA371E8C323EA53BB232F07A761473580CC3F0CBD5C73FFDAC3BAFBB1D9E7D77
+1CA641EFBB2A190E8DFCDAD040736BE41D29723711CE965926CA4A56C6E4C5FEE60C6634
+C3B3BBE74BB0ACB8BC0FF9C426679D863DC1745AC462037444B6631529D8A8BB22EF605E
+53297B146FC90E7A751C5E151545E89281BCBC7271731E5B0362994090B2560A8E62858E
+860FF9644008AD601B15FFD2BC3D25D06FA0D78F003AC39D89FE621C1E368BB9221E2C59
+15A56634D5EBB299635F48DFA2BD37431E224E38CED95C183604B9CC3C8B153434D6DBA9
+CA955106159337D2709025F848B5440990957B0F12D416F823A75EA2567DD02849BB9B98
+FD5F32844E8F24ABDE050C333DCD9C9E4DFFD97C22C0045740B6B3E94DD8964F1E601544
+4465655844C809A51B9658EFBBA085489139EBD2344E68FFCAF99BC6C50C68C0C03EC1E4
+0C378E68F1CD3A8C459D732377514B1CF1594627569C16F9441AB05F9B4D7B1A6AF79E5F
+E62D1DAAF71234F31509DD947BF67EEBFA0FAD13B794D4292516AB84FB96F5DD8C6D65C6
+0B822B78E917D7BF5BA9F2A4C90D94625B0DD2E31AD0D12EB3AC5F882F72D07F88045B35
+55AF20B6AA3648EFD5CF73798F3CF86B139C909D1D253FDDCF78F0915EF8CEFF7FAD6CD3
+C784BB88B8F31D1DA52FC67500D064DE56C233C333CAFD866D102FAFA71A2B2FCD2715EB
+47C5B65909EAFDC5250EDB78FDA4854EF0706F226C1191ED8E1ECD79A43BAF7154547059
+D567146000900625B22D3F7E356DFEBC00D4B6E6C1296A4E4038973B9156D5D748B6C0EF
+0B82B459E24670C9A951629E57FA90935E710899C37A5310822E99AD7D7B32018DF94FF0
+E723CDFFDBA6BE5DE8FC147C794E9FBD12D3CC53C5E14A328F6FC6C6FA479A0E0F760253
+899B220E7ACFB537262764F994D680BD4A48F618E7FFE9E92FBB09ADA32A7656B14E53C6
+B43774A908AC61698B44B4FF91D6BBDA42D53DDF348CD277A2A07A0ED439FF4D94F769D7
+6FAFC6F19F7A307927FB233796CA701B40A1C3E93A98703802B5D41F8A57F0D699B7ADEF
+AD6D130B06C3D34C8D2414A21C75D4FAD9EEF2791AAF7731033336E141E15CFBCD7C3923
+C663CB78D678F222738BB970C5ABDEC1C983D465F71D8189A9F1A031875460CB9E46FDEE
+A4074549FDE7A01F209409850C6848DBD1C9EA058A28D224363CD796F106683166A00DF8
+F5239AE3288F9D0C14E05217849FA07DB6DE17148462C0AC9195FF3C20B76C452DC58273
+3B81BB7526C69124C4AEFC411FBC581C29E01494C28F40A9FA088AA7B727E5C6D8842122
+79BC38AF7593B2A53E8B0FAB585CEF88D5F497727EF2342F89EA4901DD5FC97AFC1BB805
+817AF7C8FB9E1055D8A2DE3DC09C09BB71A999CABB055C4E2600D91BD4A0A6FB2E9066DB
+CDAD3FC26D0921B2B9ABDCF99D74CEEDAE954EE6AC80E6AF69EAD98BBF0F14788D973381
+5714B6C0BDA27CB3E7235065ECF910CF27DA939D6354D3CDB120FA8E0E1C28E48445BF7F
+06CE9F6867641A9238175665ACA110E8908243CB693C60D369E1C12D39ADCB6350395F6E
+7ACBB1FBA75E91D21C141394842D6D107CB412C754C0068DB283EEBF44046213B55C2BC2
+5E403DE803680684F0F5E2054548D3AA52D5EB1F4E8D32279697818359850B50DCAE5559
+B000B4D74C97AD069101159A5FC03C66FD88F44824E0D28681870E6FF118DB32ECD10A88
+1540C1B63BE33ED8EA640F50C47055797C2E6A04BE027BA3A2E8F9344FA48BE1EF0D3A58
+59F9CFF0FDFF085F78712C711D4AEDA295775AD416408D226C4DDDFED69F5FFDDBD3D6BB
+590EFE0CBA5404FE99FC4AA90D53FD3CEA35AB8042784717D1EB67529B74825206798862
+08D744892CFE8944B9EDB4452072D39363878167C371C3BE4816955959F7773BB66AB794
+2A2EB43BA482610A388035F9542C3D321BF1B1FFE827812A6C9A2F22B17CE0D04BB34653
+02D0F9331F41370AEA4F1B09AC2AF71F588B250D4B777CE024E9280CFE9EB36D9CADCFBB
+4C1BD4CCD1C035B15D736C6F49AC229909BC877036E6F584D4155E0D20AC99E41040AE3A
+23A0645A1B3C8C9553840388140AC1B49585231B98797C1C19D483A6E69FF566E6DC0AEC
+71807AC1F4D3DBEBB2F4A4F6576DBA8A0B1B8643C9BD1D97A912E90A737268F6A91E0A70
+FEE73DAEED851EDFC631701755AC7B2EA3EC8990EBFB3EEB64B75FF320BA84821750BE74
+F2F2C8097EE95B2402D6F4C31E1BB947A5F86168745F8BE621289CB65BB1AA299214F52F
+80950D6AEE089AD94BA4D19B9767B4B3D3CA631DBC1B2A37B3BE026429532E717BCAEF7E
+8BCE17D47F40F3665C00A0BD87BB6033CD56FA275BF4BD06CF4F2B0ED24A061064092815
+9D73667E820E4235F1C4E629610A1C260C43774831CD75A5375399644CA9C46BE2F516C6
+7B059743008E82085EC673CCCA702BF07B8A9F57BE338D2D0F8D2FF6090F3AA1BA20A9CF
+C02EC2471992118F070FEFD45B3C0FC0B55162490FA9D9DD60A6732532F1AC45A4D5ADA8
+DAD9ED5D24080E2C94F6A30ACAB0F075A50EC19544623D14A5A9A783A61A75D6F6E6249B
+7B4AD8EDDD1154ECCA8ACA427736DB27758A0D7AD3F79745FAEF53B171D96FC735281986
+C4214ED6754154011F4D0B1BF910142DA99D3BAFC74D8F2BFED52422BEAA5DE0BD18538F
+1C8CA315FBE5510954227B90718FB84785E0ECD9243B7C991690D2A7ED913E5080A15D27
+927BF869EB1279474726B8317FBF9B77774B2A97C294D56D02C40087DAF596AC35C2BDBE
+CE3CC534DC34CB2042F85F686F4FF4098890439464D56CD011FCB85BA87C6B51E9C0ABCC
+EB9A96152F5137E6590DE02C9E9C24D133FF585394FC59779F64E1AEBED7A007A269482E
+E8943604DD95A632EF16B0888DD6080EEDAFE8F386E05427DA25E6D15E38BAC599A57266
+C416F20DB2B81BFB7AF0F10223DF1E760C2B3EF6EC37AC447833E8220604CB3643CD2CE9
+53FD9E2D22F6053A7780F79DD161807B661E196C77DFED2AAA7ED10253943A7FA2C25602
+3586BF0508910EA8C688036557439C183A1E9B9165DC2BF055E58DDB25672E7E701B3CCA
+056B592AE84DA9278C95328EEDECA8E7A4FB521D3646F3195D9A21517DF98B334AE2E201
+BC4D0D3162B6D0F53F801263DB7AB69F1D2998038804A2A8E96E588853D7BF448C3DED2F
+CCB995EBD6520A2C6FED07E13EE3E546FFAC962C6C30F570B8BDE1ED758550150515C927
+2C6760A12A097D07A6A8AC10C5FBB66E29BF85A74AB804A6CC99FE01946620D14C3B8B6F
+FEB0C74E4EA1A225D5B9B5DD45389FCFCBAE9D45AD3C7F3E875C0FAB231F7902B5C860F0
+2B4A13B39AE999E051B7B8D05BBED72B29ABF13ECC485FC1EBF0DCE452ECCFE6F230B2E6
+B778E45197B80EE42F4ED63DAAA570C4ABF8CE4B30AF7B694B70780F96BC9742F7F1D3CE
+66AD5E473D8CD8002A436B078918949013B721329F9A931DF6F084FA5FB7C66BA81B6980
+0CC79452F5EE2991BFA84EA8689A5B7D20AEE04B0E5B0FFC03B8D8D1DF4F1D3FA29BD6F5
+433809C897B31F184AD02C8E9FEEFCA647EACE79EEA1DB444269C3F88EBB896B2A81995E
+9030FD059C48589B1FECD0F98490152F1A1CCA7929F19951D345E342A805FE72B4A1B4BF
+F2730AA22A41D1E07A890AA61F2B9B6607191C92D052A673B15FD49145611AF6754E4F32
+C12533BCF702626D7F1E44A7D7150640F09819CEAA1C0A2E2E8FCC3CB262CF29232A38B7
+F0EF66086AC8197B5226C5D69A6F57F16733BEC14D8E7A47509BE951DF1B810CCF6932FF
+4DC57D208B13AB86C0E22569A6C11661C91711C35C61BDB6268C82E08AC53589A13FFB3C
+F5EDBEC7E7A41CB81401DF66295606B544A9DF4924416423D6732B4631EB73266E370083
+16D0DA6106AC038C1406A5B6F8639BE3EE6C880F9DDE71085C6446F9F2815E2A6ADFCA93
+5A7BFDF4D5AFD5CC7C8C487D57B090A5CB7A7712E207FA7000E39CCB41AABB32923D5E1B
+C8D7F2C05D9A3FFDAE5AB0BBA940A8A25114CE99B207FC2DB264D44472B188C5CB9F41C1
+913B880EF8108348BEB174712B2FC1192F37175C5060C9B1F63F729A4E94D0DA524E2DDC
+ED8C1F460B782DC62F4C23C6C0FDDCFFA7E2F918CF417C2A4ADDDE53381F65E3DB52D291
+C72998809B59818B71BF922A04C053E2921679838CF482AC654E982A60D2C097C4A5B134
+34657AA08F5568536FFD2574AA4A88873C762371971480ABF1290A05AFDDF9C072DD721D
+EF36CACA75F4AA4E28F965AC02A54735E167A7DABF06ABD1FB339E34848F1CEAE16D4744
+0107AD4A526B99C6396BDC4426B858BB7FE38037F46E180E3F8108C79E457904E0AA9BFF
+6D3E9B2A89D3F40ACC279C87F0A1DA1245AC6E766F7FF56A7F7DB7352673036D8162CB5F
+C666B6F2E944E19F78EF0B87EFAEFF4209A5F83A563A6954873F88B2CB402462804E2850
+C1C5379CF747707E54B6FE28163C31E581B5951E1A12169B1496CFFD8D862FE0126A0460
+7435B53E7E1453255BC1BF14B67D8275CE9DD068529E5314A28087EA792E841448B2720B
+FCAC76DBA06A85D1FFA731D06757170CFA16D6758D5E371655C64747E1FBEFDA27115923
+C701004B5E38E32E4E9FFC294639B67A0A8BBB44D6050AD78A41747910AB112CC7D995CF
+004B43B8C0AE28049672D0591392A2EF95A8021F2AB281DA86EC270D683060B8D9D6127A
+CD4D5900209C117295822A9963D86D5B85D66E4502E5D2E03DF43DF5A162F502C454E971
+09A24B58B9BD864D5E11F8818811AAF0FE432527F897C7B9B1853DD7E73250BDC414A83A
+85C6916FA701AB3B71AF0AA8429DB2A9F85BA74E49DDCAC5174C927F28C1970D0FCFF89B
+ED30E83163D21EE4741659EBD12F2FDDC934E812ABF1A0A0CD1D2AF47DF045BF6C6CC15B
+4E61D058650AAAB48CB9027757EBB21398C5899AB5876F13E23655A7AB3C19AB2D3BD7AE
+55F808B6F4409012629F99A24FA15581F9EAB68177DD80DF8A78F0440E5FDDDE882A0976
+076F1B708C63FECE076193E53934681157F1EEAE0DB94A68289A3963775E0793C3FE3862
+9A6D3161E25A76A5CC1017884136E801A9EC1958AEAEEEB543BEE46B55FACAFC0A8B0814
+9121CFDAEDF975B4722D7EAC6768779DE79D4031D42622D3B2EC0A8DB5BB117DE455F37C
+7E5A948088828127F042301446E89F67A6748440460844A5DACD816D728B00C725C771EA
+647896AC27708EC7F9C858CD6E5264BA8DE4D1B2662CD161C0099FFA627070C7A228BE5B
+F38052CFE6640BD91780ACB62158ED53E83CB21BB2DD3C2C40B70CAA21FCFF4BD6F07220
+67A644BE891798B0FCEB7FC5365ED584349903AE4BE36990F66113C3E3E2A12A2B822A5B
+D334342AAA886A4C3460598A6D2C6C120369E27F5D8DC14D2C79C7B5215F0D6D0D7D7F69
+AD2A561C66C113DF9F60548A6725826E9C508BA07AAB59F3BFCC74D70D3D00546745392E
+FDF15D348F0A5E36AD6C250CDD7D4AC53DD79991F36631371908BB9CDCF2089F4E37EF58
+E9A5AA78F3896AB9769C510A5965BFA79E40083388A56649126390F24312A4AC2D05C2B9
+A5CAA54F62628212354D6EFA8875F4B424732598FD8ADD1DA5459243D233D95F8840D51F
+93847579566AE17644FCC7165E551BB9BFE7666E02F77CAE781D41D2EAD5388553E06363
+99653C07C45F603D6C017AC9DAAFA14339F25210A4A91DEC0DDED2501D38C15AD3371153
+CE2CB9E7A77DFA80BBAED85CD46D3495AF1D3BA9246885CCAB880908970E87B0BBAB6447
+A611956A2614BB89323FE3546868CD7C558C0BE2DF1F3649C0190BBDD38C8168DC698555
+2E913FA8BEC47F2ADA8211F4FC25EA75F5BF578FADF6707F051A0DDE5CC99C83DE55EAB3
+D81F40A05370B3609A9EE133982CAECB4108661833572E5360D31CB29916146F3D43C127
+E1DD71CA9413C462AEF379BAAC990E9C3BCF2C22E90F15AE7CF1DC3C52A44894E123881D
+B6396ABA0C77AA2EA0BBD78C7312C9B9FC36271B058DAD3F57C44F57CB825908CB62B3A5
+CE1BA60AD20892AA2A559C53E8A883E9F9CBBA38D13E8E71A8C008861454A58087E729F1
+C50723854AE1F620D3E2D716697529BF345A269ADC240B8EB1593604E08A12E8C184EA2D
+A26B206A5643EF0071D752A3D4982A507246F237880919ECE1538E34EFBB9D991129B948
+A0D37A10321F792A35C6602F5191D34100396E0E89C0CD41CF82D1A3E55FBF6575DC08EF
+59485DDB2F33B1689738ECA78A59501F8A838D3BB960C025617D8C50855F31044D02F076
+8B5B1E6058737389AEC850E66C6F478F96C5C1D2F451841C30D6C1EFFC5B780D26A3BB24
+AA555A045DE634041EAE5F0572AB927AFA68877A77FF3AE277505B133BEF87C2899DD7CF
+A9275F03B6B8461DD1791D0B0558E2E7A36295DAC3CAF878BC670E6B005FA34E78938F50
+DE3B75424769ADD07717737AB4E965A9565C1459C3197B545A64A5F22F7F3BC0A0641122
+85134DF7405EB961B367250242455D9896F92FD1B784AF5DF40C408B0F30A4689168029D
+B522BFBE784FBCADE1D1301EACB5EB09DE63E20D5B313D2D04DE931862F08309633401FD
+2117426434AB74A5A8480F6F9466E93FED5AF4DF1B3C81E5ED77DA855D1DCC9803DBFBEF
+79994E045DCFA6FAF3BF1DEA57EB30FCFD0BE7A17855D82DEE77AD5F61C08DFF00958DFF
+B5604F75DC8CC24623F582BCD220CDFE0D340A1C476D09289C5213DD812A0BAEAA492E8E
+AF3436C2D490FB5104DF3139BA8D5DC7AF08BD1C9517206FCC738B626C3E29E590E2883C
+30A4C745F59E54463086B20B76628FA4DD6E295144B43C87311DD11B559472034543C376
+65CD9B874ACEF7028F342E2B34CA04260ABF8C8E6193A64B94B6E1EA6DB6AC39FF3EC27D
+A41A460DB7FB38555E272E1CDB792E682E887EB5C5AC5C0D4037C2BEE840A825AE864D34
+B205B65BA9E9B4D07A16FD1D285EB96E172E89A1024E5C0BEAAF1E37861ABE6767B98CDB
+50C786E66AFC82AC474391C08F1FD549FAD7401F72E04B3A9A6C52C1B697E9D4E3E33122
+EEE5D0C72B03CCE96FC3D26966FC06C9BA4B7B838076796DC95CFA3FC222B3097C43BEE6
+251843EC7E8C81377481BA2C5F77C47C2BBC53FCBD8305C557C2FF07B9CEA70184E9DB31
+98CD10E6D6B9D3ECFF62AE429193DF88CF2A6548766C2DDAD04C3062D17BD5F4AE274043
+07735A6DD95F65E3CB850883474E57A0376F867507756D7FA74D0ABC7AC4ADD08E0AEF53
+39B613F64A33F92ED360B7C0A65F8F81290408D0B8752B7C03796629304BB83A455D51B7
+4C89ECDA38CBE83C5FFC54A7E5CAF3E2636865BEB3D6092CB7E4EFE6B13F710988F1B492
+9F4EA0676EA6B8495DF63F8BCFFCD47EE238221BA37F1C53B40A20D70347145DD5A04858
+4F1B55173B2808416CA7BDDA7775DC4F208742F7DE0382C97916342A192E47D3BE4454E6
+A2F80C8B72550D55E9B463299A2008334589CD4B5C19FD948BE6F9991EB7988F004E3BB4
+EDCFFD47BCF21276935650AACC3169B54109D8C02EE11D3B2670A7CD006DBC704EAD9F5D
+3D1678C93199034AC92DD1959D25423A135441DAB773A78739663959C3AF3BE598102B4B
+504DE19444E3BBACD584E15F6BB0D6AAC894FE5F86999096DF225232AA65B122511D3D0C
+6AF2A7B25273CDCE5F4791416BD85DF4841C49ED8179DAA39FBE9E8A5D0A1BE58D67A0CD
+CED550F9E02274A337EED7DFA9C3E23AB6AFF8F782AB4DBA173D8D0DF5A687070A4F8782
+DEFAC64D97487B10BB114338A16A081C64853076AB441E0598135A79028847D19229E650
+E96257DA27FA1C78F42302D996744BD5DDCAD26FD13F21B2D31ADD3878493ECDEDF6A257
+CA47BB5203286AD59910C8BE7604244C6E0041F3AC99029A5C61CF29A105FE4572BDBD01
+8B55B411B4CED2FB4F793F842CE40F2F8D07D8E10E79587970FD254F4106278DC7FC6E86
+6D7A1729C01D612A7FF65A63CF1C27CC79AA57699B0188285F474BA5BE90322DA6F653ED
+3BD73542F9557352A042731F7448ECC6F931218E6B25ABC903E201F61BF1A7796135506A
+DC2091CC49E8776202498C3C779C5A0DAA64C92D65FD3002E359062E1051FEC9DD47DDB2
+08AC3EC609544FC692BC2638E17AE95601E0153EEEAF7FF294CAB662116B455AEFA27744
+FA0AE2C7274442ED99491738BF4E832BD2991C59C2D94665FB6FE9EDD8BBD65EB2936F9F
+8855722E84B50DD6EE83331138EF9779751C13E8757A54DDEE891507D2D00289B8667C6E
+D9DF722391C9A4C7BBC146C735253EFC8E7B436134CEC60EE2ABC2F999EAF00352F141F6
+B3203DFD0FCEEF69B74CC180714A56B020B8832D291F17398E5B219300AB472699C5FFA8
+45878442020D780E1F2DD784AD116221769CB0C92A8B9864D646FC6DE853C19AFA0C9034
+6AAA5ECF81394BAB6F82035CF59E4CECA428E4D9513C5DE593D9B2A9EA127510CC68B5E8
+43A17803AC404DDDAC646E6E73C63C63001DA49CEDB5630B2E5A4231CD3F21DCABE8B3A0
+3ED509459FFFFB2457F1D5608E09448CA76E516407057805B82CAEE2B5FDF19BA480D93A
+396EFE8199D04CF81E08E979C2C84EAEBC3CAD9DCF81189FF9A1ACF3FC19A88B30020EAD
+5DE7A2EB7804FA0DA9BF71A339C3A304F51E47F11F9F0F754B04473A3ACADF6FFF079CD6
+C6F6B58A4BD5B340AADACEFDD5140B637EB3209BF8FB72B493643CFAF4900AAFC63A4EAF
+D7B9A4A241ED10FC7CA1490304E2DDE4B22354B33253B41438CEDFA00E5146648B219E4C
+E22D7BEA2EFA6A063DC8B1772371E3698C243C48CA4705352C3996DA94B1258B79C0B4D9
+63E69A95DD8318CBCB338354B91AF6852EE956A28F0DE835004D7F96C0E149DE50241951
+0621F7317209D1E1FD2172242E4B079FE328941BB0720194EFB48EAA04E59196EE8611D3
+325D1C12A3947C9E8453042F5F6F4B7B381BBDD7D927A8FABE70AE7282291265E7AEA516
+8E8D1BA24C71653323E26AA6344BC0D9F1717255E81D4C6A8B4AEE128C71F228D5775ED8
+257434AA754C770309C9FD1E8D1B69A12A78A726C80A9F74136FEE214D9EA87DD2E07F79
+53C78272BC75F22F54BA647413B5500051159EFC793BF1F44A6B8053414A331AE9AD43C2
+9AB2FDFA1107242078E6B581EA6DB98A73EDFB2AB8D733A91F8137C92E27ABB2ADBDF87D
+E8B9086A12D3D9F7F5CD98D8393FD4D55F8FB26E849373C89C5FBE982C59A13FD4C655D0
+DD98A9056D4F4C36CF1611CE5B1931F38077D845F1D0CB9A32FA9E9560F3DE0D90B922E8
+EDCFF38CE0F00B53894EDE37276432C4786665233C4B72A2E770C1A6B137EBCD8275F64D
+F1C19140C3A4186408993F112C44EAF2EB0D97FAD7503835AD56965D66B85B037984B561
+B125093AAECF14B8240026FD89389E6B1485C76EF24B838E1E67ACE175054E8EB18DAC7B
+9FE59483EDB1EF741098E13D72AE7C263A8102336E6AA6492DF4C098FEF95D7B73F90CCD
+3A77ECCD01816353DC819A90AEC7F58CB524B91D861D24DC8565ED19C3E44B91F6FB76C6
+E34B107A33EEA9BA30E8046DA880C4F6C7A5C3E58E45B4061E400F12F63219DB2DB438DE
+57CB2ADEA50CE263FAAB683A5F993657C38A7301C8F0971A258465A2A03915341AF17D89
+B60A4A6E35153F4089E7394EBE36F3FA0E52D561C6954E60080A4CD4BC3DCB8C38E2F835
+A4F7EE9D8CC16A8FB6F205B4B9B9052517956A19D11038ABCBC28ADAED8AF15A274F634B
+D4EE6FA279A872A087A53486CE9F0230F464B877E9CF8002765094E2E3B08F2F479F311A
+A80699980FBD99914C09E6677161DACAE71884A21BB600BEB151D1698CBCB8F3C4CA9222
+8BEC63501DA8BD9819EB03006A427402FBC8C702E9F8CF2B0DCDC7BFCF0A5081A47BE7F6
+56366881FE8FB14E160E786A080B98A9CC17E0B52F93E31EAEAC7AF0FA0379C64F7EFC69
+5B80F3EBEB7745F3FABFCF0B4FA1AA56CFC3485B50C09783DE242F277D1054891CD9E78D
+C67525BC2308F66F9CA11AA6AD31D48C3FE3FF0346ECD3648F803C50B86DAC19B0DD85DD
+D09CA881CE34034530BBD51EB6075147CF0077AEC54690677B17334DE7DE56AFDFAA80A3
+D8F9700A9DB28A760C5DABFF102D5138EAD1E697D050D4BB9E6DDD28F0D2C669F0713049
+29534D421413BC278180F1172594DEE9DDBF4BACE639DBD04EA2497A4E72032C5C981038
+7749BA925E3E46CA02CCF1AC8C2931D1F538EED1B3B725C6C4AAC7D65DB7DFA4F86257D2
+69BA6B0CA4902214C3A37D0D2DD45E2427599F3C55FD813840A251F96DEF09C7E72D7007
+59A90A9F65B1DC63CB2020CEC0BCC6C54F428B8AEBC5FBA51EDEF53D88378F012C780D7F
+A904DF1DA8B7148308BF2175B11B83281E132FB20AF80ACACB781EEB48894FE148F5FA96
+3AAECF094DB605BE46AE4EECDB1B8C1C64308F6F21239596B12DF0CFA846A09810F803BC
+BA672B89004AD755D201D19CEBA6C99873EEDEC4929078513912D0815566BCBE3994F345
+68151B5B3375936A8825CA58392851D1A873DFC8BA308C58AC1F9EDBEAFAFDEE682C071A
+BA64798C8486AF1510073C04773B4CDF2B77C3C4E3A3EC365FC4E08FC93B116F8F183947
+28029EE89EEC18724AC9D36A2BE1428D90F85557C4D2AD1442855DE6CF1D06C0BA192F79
+2D08D3AD3FB804AF6B68B3885556ADB4A4D11CC336B1B998344083129C66446868CB7657
+E8946E25AC33ADD0BD39D1D3396FA15B344B4BBA42C4F6265BA738A58FA31AFEA589A025
+428664B136A771A9B63606A6E63A29376255DDF52E89C2336454C3452110A4D0C73A27BD
+D2A47D47744A3B9A4B84BC63349FF5C75A6CE2010E70B24A053C9BC8DB1089F4CB4047F0
+D102860A352BD4F0E9B2FE00C730CA3620434DBBB5180092CED4F7CBB8021E705F4C13BC
+759B366A4D054B804EA3A8A9604674EC0DB26E93112CB244FEB1DA9CF920CB24DF6A0E7D
+7F3B117B9E62ACAE126303EDFEACD893A8947CC822D84757FDD6460A0A344E31D1E8FE98
+FACAAFB39C49EEFDF56DD8014572563FBD5527097CC805E6B03066A81E6120337F83D1C7
+BAE66253655316248F0CE35FBD61A2372D7B8A1573D34211AD49C592716566EAFA3FFB23
+50B54A4FD1521FFB1DE011FCD82792B93D87788F8409AFD40C7448DF74CAB5343D62C534
+26F0120A12C601E35C4A17788FA6086B3B4C7C70F1043198C61E3EA717533971E8F78E56
+17C84A3B5EE522B4C7C33FB5F1B93089EE7EC6D3FA90EB7C886D04116C3C0947FC5F3B85
+45636538CBCAA1DDBA880A0D5A30FFFB07401B25CA5572D41426D4A6D98F3EE01AC1BFE6
+D40C58F4A2413631E59140F65AEBC0990A76BE20C2996D00053F353945CEC87AB8970B88
+20DF8527A018548EEBC55906E04B0A3A498877B2D1ABAEC069260F05541301AAFB158200
+DCD67355FC73930DD4B47DE9ED0501CE7E38823203CE6D714E5501DE6C9922187592236C
+E424564D6FA776E1EABC1000B2A854D06860F6ED7668C4D5DB5CABF4E89D9E05166CDCBE
+D679B2E1645790F968D0F12843561B95FC90B8CD75EE2D053CBAE61E215082E5609C1146
+32C8B81CF298E477C0427D4CC68E6FCDB88393BE8520CA93DF1E3B519980FB3523BB18B1
+99F1626457857CF7641AC66E257634B349B2D5A8728DD02A890391BF2EF8C6358E4BEFE1
+6A214068AA175A1E7FF734960FDDC28989AED8261D18B4D996372FDF4788AED732041886
+24521DBEB9985BECDA0A6CE64DEC42A2539CCD4F55323057B8AD70BBD5B05872B864FFFF
+2D627668ACC1D8D1908C1E3E2C76D45DD2058C717C02D279B0AC4B2E526C657FF7C5DEB5
+3538D1B2116AAA957A6B16F0CF83430395996462F8183F71041D543C330183A941CC5E37
+8C348ADA81F946090676425EDD0EAD6EA996CBBDBF83B606D78B08684BBEBCFFED1D0875
+6CF352F872A71DFEB693608F24E3F4D663E53661B35A0BBEB3B630489FBEA39BCD26BB90
+0923FC711CDA89442435FE3A491FA23170B6223A577282C24FB7E895E2A0715D2B78F20F
+F1F9B06AA9D754FBB32CBBBA06663C59B7A8B22E666B26F2B9D8C55179953581E756BEBB
+82CB10E21A7F590C6569324ECC4C34DB4BFD9EFA84897068199ED8344A438A1FFA475534
+0EEB53B8E087515ABA25BA2B1414EE4F86E257387D4C0C7D010888AEF962069C57450925
+6C3F0625BFD6909356DD62C01875C69204C843E6BA873049D72ACEFBCD9106FD45B8E9B9
+8CED3AE42ADAE6A7BEFE925BF6421E88540D9E599CCBFB9E8DED2C5DE0B7AC4B331EAD42
+DEE8EDC35312B1062CAECCBC903CEB8F67897BEC2305B6C333FB766D92C6CDBD77CB4F31
+F63AE1C04A249361D2EF6E0BAAEB7FA3B87E0BE0E1E50C1F480AEE2DD2B6B4D7DD89A020
+8C9B43ED6F46F3883AB7E53869E3C2ED3DB0DBB1A05B1629E48B3D7F420F02FDA6B1CBB9
+3DEF237CDE1F7BD8C80AC7AE5388C30335378E0E374D0C41EB824BAF001A4C47C399F301
+13B442A2C1B27EC161CF528FC2B256579E3C96AD5F4575454449B3B5E1CBDB300A364C7E
+6675B6B924B48E58A0629E729941C3830D23968002C56F84F53CF124E771FC83CCAA3363
+5A130FD70D9422B524BEBC6FFF2369A71DAABD932B9D4ABEE240F07A4DE04C280D9CDC39
+A52D9B09799279368965C40C32771BCBA0EA9BFD488BFC3D154B8E421391BC7081D27262
+B40B8B953C02432B8074CE466299EE8BA9A0BF0D47F797EB5A8300B1E80EB44EA0C0D51F
+8577BBEFE06C2C31199B4B4483BDBC10B9821B7CBCCA73E4A96932ACB5DFA52B2F3F346A
+444EED0B3B0E81E8B65867CAEC517B99B84F574AB31FFABC2E0DA312F12E549436538E9C
+82417153110E8060C80101B8AB8955FBC6FCB64499BC6AA18EB6DFB9406304B2FA5A003A
+650C15B78EF641381F9A474623E69167793F9896DC82AC4A01FE4E267E9713507AB69A60
+DA690E3F3031CB836256B21FC26BE0B340FBB84AFA550F7ED8C3D0DAB80AA2FEC258477D
+6576F86E6D8FFB91F99917A1EFD4902BC12AECE66A5EBCC6585ADE4D96CDF5A78D10EED9
+4D543079A9F60B3650D17C81748189C5A1859982574E1E821E943AD2C59000D8CE586E64
+178DECF669143E9D12131FA2AB2516A3472C7B41DBE5E8D2812FC7DBBC2415055EC1EE77
+A1BC7FAEC22051FDFA79F47C5D511C3F55DEC0369CE994D574299A9E3AB915935C654D71
+F3FD4988F5265EB95349304260ACFB633722F5AE8F43D3EF4ED5A0D333AB72ED10C1BCDF
+30A2C85CA9A4B10DF95613BB465C2757CD153E81A1CB4B6D6B7A723BF5FBDB791B38E900
+EE8CA0F36399A767FEEB1C239880F13643BFF60481776C3856A033436C14768B09134DD7
+2C79C88DB4A5E7AF3F76B4806DFA232841268CE4D3D6D8FCF5820EC52B713C9ECAF0320A
+5E94C45E93A785D5F4DB8E5A1F43BB8AF4218EBC91BF88D10311EC6812F42BDAB8BA486E
+77AB14763C2E489EED940D934AEB3840BDEDCB9307830202AD02B3E7E27E0358F8502DD0
+F01935DFA95F69B68F5CD4F90ED84AD59DEF5E62508CE3A5AF67B2FFE39D37C59E5251AB
+5E26C96C0B08D593BDB3F7ED93F9BFAA609723BF87BA135847B8535611C5E4EA0BD324F8
+3B38289C3C5D54713A58DE72FADFB4B89E7F4C40261C1779B97CB9F9570530D5943A00EF
+FE435F5541AA079CC0E8452EF366D9DC18B0A6A0454FF9AFF47957973F77B9806373C9A3
+D048558F532788AECECD659B8B2751958B3F454011DB88F3BEB0D50053DC70B0244AC1FD
+20D70C444E1CB00399EC559D6A2513DBFC001689156FB89CCEDC3EA3C9B70BF2FDB3A1C0
+9CF814E7F1332B7C752DA6B2910663D3E0AB53E89A236ED66418A280FB4A561DF005B08F
+885D58BEF1429418D81F67A00403D87E16519FACA45298D16ECD5CE1839D3BDBCD784710
+8622BCFBCE4C100602211E6762998BE4F6F211EB916468F587A4DCFCC2030FA5FCFE8018
+1299E339E35ECDC494D4314368270D837927C46EDC1299FA541480A07F085D583F2B9390
+EF3B4A2A8ECA8B28648D8132A0D5B37E353731056BAC85AE7491369809C4A06ED7B0CB7D
+BB71404D67DCEADEF47603F7C1A3337AC93CA5510F022893466AF4C74C24428275C44E23
+0FFA5972C9D36359FCE3899A3D60EF63920F154DD39CCE56BA57E540C1A3497B3EFE96A5
+EEAEE028AC28D81A541F833A62C8F7AC492BF304C632A023C7A170F8B3ECAA4284CD01A5
+6F74B4A41F1FD464BF46C890325D17CF9C8ADB8AACDD9CCA20015374111DACDA8744BE20
+DD6C99E09B51AB2287016DD65383E8918B5557B78578CECCA7EAEFF8E9BE9E1B13A24613
+C953C5BB45BB74A5A935F32E708927D5FDC1805B5EB9745D35654E25BA50FBBD7DB58D7D
+6F70E102C640B771CAF3C1C138AA9A828E79F377A1FC8913012E5547D3602B22B4C365DF
+269CBE55BC4AA79FABC53F01EE7D809481DDD3EE602A7266B7280DAFDC68259CBA490414
+84E4EADF0F8E4CEA8A8CFF260B8F4C9C5A3F2ED699B4CC72DADF932F844E65C1BD385CC0
+F2EF81820D16CBD8CE2B27ACEC225FD1DB77723EA0F03B1CF07630B907C7494EB4CAA725
+18144B1E15B0B34E8F3890269BAFCAF6DF4EDF3861ECB5266C285085BF4E1C6FC0FBA7A2
+6504467B734692FC2C9797D1B6536FD42314CB0FBDC0B104EBCA6539F47A97E1C8974876
+9BF5EC71AF381DBAF9016B5A794EF38776FD9F811F31EB98010FB1FCBBF23A00794E2FC5
+9637254DF49FB9C0F459FDFA0AB0C8C040AD780D6CF3C9173472B8A6F041D3B30720C1C0
+324B977866A3F892FE9A12DE84A6F0D723ADC584A17C055F07F4BEC7486D6B064885E410
+B48509BBD815C3BC2D57F23515AC82551CE3D334424F3456944460013BC5B7B43AB19D7A
+62C9C2431CAB250705DDA8CD0395FC754AF7E0B10BEC12EF69100A831CEB62F5C016142C
+32B8A41F852F57BA1DF144C2A534C06559BA009A92E345305589796697EF28E097DC06FB
+8465A9DBDE8F5C38BD9D0EFFC3712F9F070F1FD50BF691811F94E12F26D47AC350C01C96
+BDC13416E1272D457AD210AFD2822408337E8BA7E63FF468AE68983966BDE984F4894F2A
+47E982E29C6855351180079ED4E9D53912764533F5EE35A93B31A4885855A31DCC719522
+8D266F9C539DF45036A97F920B717D08ECF274B66EBA30E223A49D67975E8962F617C107
+23261A6FA71061BF91EDC235B9288E4D856FF764A5E65AAA044865D0666523B24CA1AA3F
+87A58577ADE42B6DD75960840BBE46C584818A5C7E4E0FC13D41E9E1062BF50260E86A39
+09C5C59BE2E8301ED90C22A42CD5DCC436AF0A0E8987853B1FBF316986DCF54BCE866D05
+1992116762A7E54B08DB4E6126604B30F6D304E3D1B8FC6E602E11D791648C024661CE90
+7A6808EEBC6E3E2C0CFF9A9C6DE679F7E0246CFAB927F1D1A642958267645432FD9861D4
+92DE7CD99824C0A7D93A27F279C0D9919E4D14BC0855F4B562447974B2ECD1171B848D17
+8216047A6834390D7704EB2D6B16EC16A478C69AAD1A4F766FDB6D609628AFFA7F34796D
+0667AE68EAF4D3BF8C7316A99E5CAC797F0220A930B7F3005EC0C72A2A925DEFD27F2DE0
+8120030CD29A9F5553E5609363E34A9526327EB61AC707C48F
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+{restore}if
diff --git a/fonts/Monospace-Oblique b/fonts/Monospace-Oblique
new file mode 100644
index 000000000..932292770
--- /dev/null
+++ b/fonts/Monospace-Oblique
@@ -0,0 +1,2706 @@
+%!PS-AdobeFont-1.0: Monospace-Oblique 1.15
+%%DocumentSuppliedResources: font Monospace-Oblique
+%%Title: Monospace-Oblique
+%Version: 1.15
+%%CreationDate: Thu Oct 27 10:50:21 2005
+%%Creator: mike
+%Copyright: Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.
+%Copyright: DejaVu changes are in public domain
+
+% Generated by FontForge 20051018 (http://fontforge.sf.net/)
+%%EndComments
+
+FontDirectory/Monospace-Oblique known{/Monospace-Oblique findfont dup/UniqueID known{dup
+/UniqueID get 4136343 eq exch/FontType get 1 eq and}{pop false}ifelse
+{save true}{false}ifelse}{false}ifelse
+11 dict begin
+/FontType 1 def
+/FontMatrix [0.000488281 0 0 0.000488281 0 0 ]readonly def
+/FontName /Monospace-Oblique def
+/FontBBox {-239 -1034 1512 2105 }readonly def
+/UniqueID 4136343 def
+/PaintType 0 def
+/FontInfo 11 dict dup begin
+ /version (1.15) readonly def
+ /Notice (Copyright \050c\051 2003 by Bitstream, Inc. All Rights Reserved.\012DejaVu changes are in public domain\012) readonly def
+% Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.
+% DejaVu changes are in public domain
+ /FullName (Monospace Oblique) readonly def
+ /FamilyName (Monospace) readonly def
+ /Weight (Book) readonly def
+ /FSType 0 def
+ /ItalicAngle -11 def
+ /isFixedPitch true def
+ /UnderlinePosition -213 def
+ /UnderlineThickness 141 def
+ /ascent 1556 def
+end readonly def
+/Encoding 256 array
+ 0 1 255 { 1 index exch /.notdef put} for
+dup 32/space put
+dup 33/exclam put
+dup 34/quotedbl put
+dup 35/numbersign put
+dup 36/dollar put
+dup 37/percent put
+dup 38/ampersand put
+dup 39/quotesingle put
+dup 40/parenleft put
+dup 41/parenright put
+dup 42/asterisk put
+dup 43/plus put
+dup 44/comma put
+dup 45/hyphen put
+dup 46/period put
+dup 47/slash put
+dup 48/zero put
+dup 49/one put
+dup 50/two put
+dup 51/three put
+dup 52/four put
+dup 53/five put
+dup 54/six put
+dup 55/seven put
+dup 56/eight put
+dup 57/nine put
+dup 58/colon put
+dup 59/semicolon put
+dup 60/less put
+dup 61/equal put
+dup 62/greater put
+dup 63/question put
+dup 64/at put
+dup 65/A put
+dup 66/B put
+dup 67/C put
+dup 68/D put
+dup 69/E put
+dup 70/F put
+dup 71/G put
+dup 72/H put
+dup 73/I put
+dup 74/J put
+dup 75/K put
+dup 76/L put
+dup 77/M put
+dup 78/N put
+dup 79/O put
+dup 80/P put
+dup 81/Q put
+dup 82/R put
+dup 83/S put
+dup 84/T put
+dup 85/U put
+dup 86/V put
+dup 87/W put
+dup 88/X put
+dup 89/Y put
+dup 90/Z put
+dup 91/bracketleft put
+dup 92/backslash put
+dup 93/bracketright put
+dup 94/asciicircum put
+dup 95/underscore put
+dup 96/grave put
+dup 97/a put
+dup 98/b put
+dup 99/c put
+dup 100/d put
+dup 101/e put
+dup 102/f put
+dup 103/g put
+dup 104/h put
+dup 105/i put
+dup 106/j put
+dup 107/k put
+dup 108/l put
+dup 109/m put
+dup 110/n put
+dup 111/o put
+dup 112/p put
+dup 113/q put
+dup 114/r put
+dup 115/s put
+dup 116/t put
+dup 117/u put
+dup 118/v put
+dup 119/w put
+dup 120/x put
+dup 121/y put
+dup 122/z put
+dup 123/braceleft put
+dup 124/bar put
+dup 125/braceright put
+dup 126/asciitilde put
+dup 160/nonbreakingspace put
+dup 161/exclamdown put
+dup 162/cent put
+dup 163/sterling put
+dup 164/currency put
+dup 165/yen put
+dup 166/brokenbar put
+dup 167/section put
+dup 168/dieresis put
+dup 169/copyright put
+dup 170/ordfeminine put
+dup 171/guillemotleft put
+dup 172/logicalnot put
+dup 173/sfthyphen put
+dup 174/registered put
+dup 175/macron put
+dup 176/degree put
+dup 177/plusminus put
+dup 178/twosuperior put
+dup 179/threesuperior put
+dup 180/acute put
+dup 181/mu put
+dup 182/paragraph put
+dup 183/periodcentered put
+dup 184/cedilla put
+dup 185/onesuperior put
+dup 186/ordmasculine put
+dup 187/guillemotright put
+dup 188/onequarter put
+dup 189/onehalf put
+dup 190/threequarters put
+dup 191/questiondown put
+dup 192/Agrave put
+dup 193/Aacute put
+dup 194/Acircumflex put
+dup 195/Atilde put
+dup 196/Adieresis put
+dup 197/Aring put
+dup 198/AE put
+dup 199/Ccedilla put
+dup 200/Egrave put
+dup 201/Eacute put
+dup 202/Ecircumflex put
+dup 203/Edieresis put
+dup 204/Igrave put
+dup 205/Iacute put
+dup 206/Icircumflex put
+dup 207/Idieresis put
+dup 208/Eth put
+dup 209/Ntilde put
+dup 210/Ograve put
+dup 211/Oacute put
+dup 212/Ocircumflex put
+dup 213/Otilde put
+dup 214/Odieresis put
+dup 215/multiply put
+dup 216/Oslash put
+dup 217/Ugrave put
+dup 218/Uacute put
+dup 219/Ucircumflex put
+dup 220/Udieresis put
+dup 221/Yacute put
+dup 222/Thorn put
+dup 223/germandbls put
+dup 224/agrave put
+dup 225/aacute put
+dup 226/acircumflex put
+dup 227/atilde put
+dup 228/adieresis put
+dup 229/aring put
+dup 230/ae put
+dup 231/ccedilla put
+dup 232/egrave put
+dup 233/eacute put
+dup 234/ecircumflex put
+dup 235/edieresis put
+dup 236/igrave put
+dup 237/iacute put
+dup 238/icircumflex put
+dup 239/idieresis put
+dup 240/eth put
+dup 241/ntilde put
+dup 242/ograve put
+dup 243/oacute put
+dup 244/ocircumflex put
+dup 245/otilde put
+dup 246/odieresis put
+dup 247/divide put
+dup 248/oslash put
+dup 249/ugrave put
+dup 250/uacute put
+dup 251/ucircumflex put
+dup 252/udieresis put
+dup 253/yacute put
+dup 254/thorn put
+dup 255/ydieresis put
+readonly def
+currentdict end
+currentfile eexec
+12D37711F3EF58D4B0160CA0E8A8B30BEAB80C582DE4028394F513096550F71FA11E0919
+505AD6B7CD35BB9BC351DECCB83DC12688E510CD157D892C101B29A3F7371CD20D496932
+3EB249027679D3DB7582D953F033C85D9B05B2E5B9E3F8CC14BCEA62C23DCEDB24A737CE
+0B749199BDC0ED14B3F80C24B773C7D94E0C32CB6CABC70B74F04C589AE25F78DAF2C485
+03C9800E9816B03D596C6E3855892618845E5102FF46233B460979463BD7A820DDD6835A
+95C220225DFE27AA6BB31E99C60F679AC7C5A3363C40EF4C555EB47B0B8DB21ABCDD571D
+28DE4719336D102E1E7D1EDCC5B3B0E60354D35EB856F234AB60D3C84342CB01D8747F93
+73140C128A546250AD327045F7903E144A248D16DBC150EBAAE66ED529E3E69214BF4A15
+12C2CA07FCF9A1CA5DD6D5A3577FF552FCE29E2CE9236A470FD258273428609693228B91
+5420FBA3ECF0A2406B4484196374D33A6C4ECFB322185AB88BAE99CB4FF8147A0C4D3274
+29B1B69D3985E21294AC5BF3777F72FD8986BCFF6374642612A36E01B5F19A4C313C684F
+B4A10E6D366CE685E4D566655263E514862031506A3B886388753592B0F9A5D61EE9C644
+3E5E6BCD8E4FB03ECBF8955C142520D0F71F7E4DC8C45E335345B990BE35EEF99170556D
+05A25CFF99E21151C7C1407675D515921EDD3FA3B98A58FBD14CDF1AB6AEFF424587D2F3
+CCBAA445F12ACC21F1AFB0EBA2D9D9EFED2C77A01C7B4FF0042E9BF457442297D0989DE2
+DC27042B646D45A9BCB9D9B80AAD373DC283EF83A52BBC4FF0B2E17194CF18618BEB8CCB
+BA24F7B836924BAF4DA12D018EB41F3307ED0F6B29C51B20D92FE58C27CF5E7D8A3386EB
+04685234F0D2D1704EFDE3C72CAEE80A17BFC25C4ECE7DA8A4F9044856A19794E13B9199
+279CDE03A30495084E75DB7C213CEA250A5DE3A17D168335FEF9BE57291A770F53502F9F
+78ADC6BAA3223B013B120789D9672B286D7713F8AE9802A4424B889344D6D06B280F60AC
+A1A81A0D8ED436C84543D86A866C981A4A8ABD3488FE907F39B32311E4C2EE313AE91061
+A1FE81235477F816259BA0D0151DCB3F28B2F59518B09E249369379B19E5DFC19EE63BEA
+CBB0636880CB367BB50ACF4767E2A9E9BD7F0339D4128C54E622D4C39C5FB383438B4A73
+9BC3A717D1E3F8A8CE7AC4FB789C7531FCDF82C32E4C8591C3D707E6CEB702C2D210627C
+558FB139108437B8E9D99B2F8532F76709E821391A07BB1A9305F62EE8F9E1EA1844FFAC
+C5205E5428D155457F451A8177E75D61195BC5A9F564297E4C36C9D3F730D1ECDF921096
+C42A26E66BFDB9AE5682CE255B0DF1265A763798CAEA7A3138CAE6A7F6711899EE2FE701
+D825DF705F2BA8D8C6A6FC077C7F63C35D0CC5A183A03EEDB7A81D71092717E60CCD03D9
+D7EA295AE3407BFA22C26CF4D7689B46CB49FFCDC43F3BF5B3A49E53387FF86B4267B880
+361199FE0B20B7955DE33F541FFFA0DAD7917CD64ABBABF977ED46127DBCFCB179757EB8
+BC08D07CA46AAF440882C7ACC9B93C575C363FA81F381CCBA6B3ED329D349D8D7E3E1884
+8327A19CA6C83DDC89005AB7D6725D11AC8BD6F2C7CE8B10131F7A82484D03A3C6D854AD
+4E173EC6852F0E46D46F6B85B2641AE69CA53069AE2B330F57223C297E09358F7DE81F08
+CAE980A507F685FB2156714E7E9E88D88FBCAACF86ED25335647B1238F31BDD5D820EE43
+821F5CF2F7D9A67586D99E9D4931AAA7C2D32FAEE392CD9FA4DB8F69D76C3BBB48A10CAF
+BA3E78F64701913B414845FE6A5F78A24CF5CD29097FE21032C5FFB34F107F51B3D8C848
+2100FE54272E0E17B79419FC0AC8966CCB7AFCF723A8F721B06CC80CE0B07B92DFD20E93
+BF01ED0C72F6385A49524A7AF5EDF658FCEA7475FC6CA315926826FAD3A90FEB182B6651
+B1966E20F7300D288DB7A53402D5D8D0A748E3C0D21B9DD078FE8560B40C06B2A7037659
+A8603518F2A67C62BBD9A29F452723A8EFE6CFA2C356EDFACDC8AE936533498DB168588B
+6B96C1FA3A2740E3BAF4470783C49202FB9D1A9A9DC3B375F1187CC1DFECBC616584EE00
+BD76FE39C6EF0B7A7ED422042C1EBD392A51BB458F920DC197915A74CE8E6635EAA0A772
+426427212311ADCEFEE54E075B8E03ABF3D4F7939D35809F0B6AAFFD9C08562B9E6BF8CB
+B6E3303A1B3851920EEA8EA61B081D22A585403C8D25E645987434DA4A16E57A585B4097
+3FE63FF99E2BB9B860DEC906F8FC183A6C57570859D7E381A6CEDCECFD566DD50CA67801
+ACC6151D9C6D7D5A3A19C5A283EF37F1F418A469BA10E45EBAB0432A366C1549CB402F12
+DD99AC7F802EB9D2B56899BEEB60C65C6B22EEB9A00C680E94E8B190B1C3A395B6535C3A
+3831D857819FC23F840B273D3133F1BF243EDCF846D8E308E04F6A38B5C73502F34C6680
+0AF88F2E920E39CE4C31DB700CE6A2777048E4B2509EDD822FB0036D888B86ADD2A01C8C
+AD1EDAF950AA9EE999B4EECA0DBF02064602085C18FFF27707F09511AF5611DC76220CF9
+FA55BB850E7F4359A9B597ED3E3298B765D9AEA76484DCC7338551FAA0F1BB8CA3D0A628
+5BA8BD8E8342155B682CD6C8FBE6631D627C4616E80114385D6B52E2C827D5E7A2C1CDE2
+B32BF8686B1E6A3E8689D1C2191C6C3E9697633E65521500EC357746647364248682F2CC
+37AE635B876025B85622049F99B824C32D060CC599FD4CDD9BB51530FAE7EA750DFB07AC
+A3226EA764D547F7158AD27B0187FB701626E7364C72377402A88754F1D3B5842031E319
+9DC3FAB04D7A3C1FF486AC03EDE9CB78A5E911F56B06635ADF5867E64C2871317AA8B298
+3F0FEB5251C244D589A8C9BE5A9C6382F9B409CE2D4F19AF79FDD4157C326A43EC78BC27
+FA5384398C5F927955B2B67EE653CC6EFDCAF7C23C0D08B8C3DC41CB5844E057EE1A277F
+8DC7FA99594391BA6DFF30FC9FEA550E58F39934675E587698AF82F00F428AC930567362
+B401C42AA7B9B4FEC9443E9AF5FB3E999A94ED088D97CB11E6955BC9E561D59EE34BA1ED
+A6C9217EF560D154BA8F19865CB8C913F12986A48DE78E9D284C0885C8B69DB0CB47560F
+D88FC212B29C91E004D18376A09A184ED29866DC4A179293A52A1BA548E6F8439B326A16
+2FA0CE6AED75A05FA30EF09A72CFE06124BDF8016C638725770D529A0163954177D45382
+3A74FD8E44B3773EA1280431E880CD2398A944C4D045AE91138244E0BC15343D6AD7225C
+20406C0AA1A4257FB281C2FC949CC3D215F827F782F9F4BD121F67794A8F13F19FEA800B
+6C7240E804D6FBACC9A2CDB6E7D24F6C61E89CB47C94D8E961ACB9355A12B42486447C02
+7AF9D7B1C4F0E4CAA8E28BE31684D721083208D76482B9BE451A4F0426F5DA9A2413D98F
+CA9BFC29E1A8680172ECF33C7218D796D6447FB643974250FE831F4D5F0ED8ACD2B0E9E8
+DC6479E203625F2C5D62F96244773D954ED8F9B4D74A0D8426A9A61176EE6AA0DB4BB3FD
+8E0F9F49119F2F2F1EDFAF9FCE35316F718A3DBCD0DA416574C87366E3321DAE1798F437
+7FF418523E807C3D80C80A5057F16781ED3CDE4EA1AF173093712B3F76DA73D0FE64E273
+C4309D9BF5CB0308A3BFCDC1D7BF1830D22C77414BEAF5868006615536737E20C438265E
+74B43F267E748B834FB03691FE68D944561F1DEB1CA295E442C6EBC274B6D9A0D4C2BCC6
+5D6401049EBC97F0F7A5678389267B0D6C10757954FAD66FEB12875BF4349BBC775A0804
+00E25D70A165C7ABE5F5F4427DBE548C9701E20CE28356478DFFA5F08C30FC08228CD6F3
+C6B030734A683BC5196F3D29C43E80F96D4EE3DD54785633987F385340098B5498A7DC1E
+07D42614FE6F1BA7068B0677345C695A494BBF150C8E4F91EAD66E387856CB09986439A4
+03A2EA248EDD1D00A4D490B9DC4BD11E36E155EBCA715B513D991A19548B417539B36308
+0D7E8E3ADECC1073EAF675C90D5897E13CA0AAAB196E8A48F867F0F71E5E5E24C36D5492
+E476ED92090842D327E4682E483F082FF71BD290542C19242F596801E9B67386498D3855
+BD5AFDF1A0A6AC211B38278F7ABDEB586EE5FD5ED91382EED8677D8A1792B270A46812DC
+BA8A1379D5E5B7413CD43C6CB3E447E49F35CF2E7BC2E99229286B2A636F83C16BECF6E8
+63E23449DB08CD8FDF0F5F8EDE5A410131B866B55C6BBA8528C17072EAA042662D855A3E
+5D164BA81ECD230EEFBD2A37F823D410469B05F3198B56400B89B6637BEDE2A19465F240
+338ABE767699529CECBBAEF4879AC00A6639589927A1CA91298FD051FF15223EC94FBB3C
+1C61D1611D05E59ED9BE06C0C9DB3C311CDA93CFD321508D1187007207A02EE50F422383
+DCE98954FF609844A8AE9C29B56C1AAC1238D45FA35A3DA527E3FB618CAEC32EE156BFB6
+2E8F66F6FCA7EA0B9BCF0A144A05FD8FE25BFF681E3AE6784D6A670FA08776299E0ADA1B
+A972D1E35CE0BDA9F06F8A8B96C8750CF25E24F69A0A49C65F7A9716FA4C5F3CEF3512F7
+AC82BE0C5F21A6876F73880FC7CEA205B4286929ED2513D38A5695208A5CD4DE401B214A
+BE67DA7B8B2C63F5B06BB039D7294DC883723FB83F736A5EE8A02C9F968FCFE5556E52D7
+9E070ED53CF85FE574F52C9446E61BC83DDE8C5AB547B08E19561E6F4B84D422DE6DF197
+3B2572006AAE0CC1F19E342389DF278FF04BDC5CBE51E27FA51D696B123DA5B342648532
+FAD98EBE03894533AFE4BECE638CA5785DDC9D7ECEB71E59B01285978563920DBF542794
+6B13DF1BD0C0D349B77290CE840C17E9F71A7E34F3EF3472AB04E9DEC00BC4C258F522AB
+15C73CF78CCB3A83D7A2047FA52A4C7196C4E750C14D77EBF5C799702BB84B646BF7F9A1
+2A6D27166F7AC9B7A2D6B6062627331C8435A64C04096FEEF7867334828680E41990E319
+334217DE53F32DD9FE73537D000A5493EBC0B5282FC1D72E0DFEEB51694F6B2DF87F3E80
+858DADF97EA3E4A864AC9AF980B1BA0159E7E046EF395143D2C2AAC26A0FC3A8F1ADB37B
+6E3AF132D51D9ACBABDB4244AD14C837A30C3B9CA47CEA267845DFD9FD5A0522BB50BC0B
+CADD7730E893A06E8F175DF29B4092EDAE7CB28F8FD389C14EACC8FFDC815355B9FB564A
+F8C33D5871ECFC0CD0E33A0AAFD6F7323A3FD696B4EE641249BFDF82EAC73D0D823A5BC0
+EC34C42269F5699F129273CC384C8A17BEDC4BA4E384BE7D6213EB49FFFC5C98FBE27877
+85F64405CA64B5F2C10470B82BC1471F59C8EEEC668D88CF0441451E275328E3903A54D9
+216F0F70F63DCE071BA66B31E59EF5731CC778455222D441C0809C690AA9E70AEB6546AB
+6B6D27A66004E67813F7509A3F2B2FFD717A77FBE48A7480FE4F2E0E9DF61D378D817928
+926F8F202341E945DDD9F747F6AA931A9369326C3AEECFAE75D289691683E6635E215E10
+9C76807AA3B71450BDEAC4AC8A55F7B6B7933745E2F3F2F3049CE858B10E17F8C236B247
+FAC04A7C3E6298C1A2036E14EE164AE8478FA4AE6F24A9E542D3D2B450E4EDEE099AA693
+16E89A308123CC5DF3E4822A5B57C7FEC21271BFA0168C3309ADF2DABEA0610FB18ABF69
+5622E7A1C371B3EC501D52A1DFB94AC84E30A500449867BEFCB5A07DC54A2F961F296DF4
+9829E92B8E0928315D60103EAF984847A6FF6185F8C1EEAC3A114F7588AD864F3A16B94E
+3AE4E0738E13B6190AF3A27427DEA99F8A6491CF60C2F8F5C8A524CDDFC5AF2F7304DF82
+DD8E2F273DC82A9F0F7812297C485AE2B330DBE5B0C2E91922484FAC56649226FE104F57
+E88622612FD6CC084725C3C717D6B04432D13EC9DD5BDE98FA56EBFD2C7FC973AB611168
+C43379538659B695DEC62E8D58BEFCF44F9F0F52273D998C6BD8766BF4B26E479DA21563
+04B1248C80C58E7A9609B64934AD07C1945F03AD258D32D4D47B6C1A95D44B135F380A64
+C7ACDDD22D510DCD056A38C8400F21900F1692BF2210F6B161EB8C6E7702291C0CD2123F
+6EDA46B95BAB323A99784F32A3FAADE6599CAF43F3CF39D43776A205B6024F6DCB27349E
+C394FD27D389C1CED32138732AF2EDD4215A8E81A058BDF9797E0EE81D13B7773897EEAA
+B71BF9D0D6D913DC0887442A470D5878766BC30C065E64456A88F88F754C3B6CC402BD8F
+BE60B69F6CF942EC531A6768887DC1D6C08A690109E86D08D9470B9A684D751101A2821E
+48805AD36D0E6D3BFF33FFC4994645AD2B599188B30649ADF04EF349B934E99E3D767C6F
+95DB404233259FFA5BF4CD809B4E08F51653D72C2C24B7419B49585672244128A45AF33A
+82BF11CF4B402B322D7DD20410A85B28CD32DBBCBAD192079514ED52996086747DEDB275
+8C8CD1F05B82B0BB80F5A0BD1C7A2F726B29F6D8DBDC9E199C494A8682D3A12F3430388E
+845B4878CF87871AC6914DCE0E7AC20407F04B3A41EA5EE88C23AB19D61E5446ECA0CD77
+0D6992CA5DFEE0265BF81AD4EAF93BD5C068D1A0FB1704499AC8F16E26754ABBF318E528
+D7B12C0CE352E4FB67A1F6DBAF06C9EE5C0A04A926EB75A2E76E1050CF4300721B0F130C
+E912C53166696D93B131CE8D487FE3B5A8450EC7A8961479FBF29E63DA9B03E79F2FE5C7
+14B57DAAB035A0D2A6A9BB5FED68F49C58360E5E974709D12AAD0680E1C0145526CE2C88
+36FC489C50D8D3FC5C0AE2C517030391268B306D231A9BB1E881928727235C693FC86B6F
+A9A62D337FCD128CFE1BCACDABE9F384B90C10DF4967A447D53828F62E753D639E4432AF
+361F680C212BFB50065241FD8403C80D5FD3F57A60643D586449C76238BAD444D1282943
+FBF39869CCADCDCD0815A484C494FA16930F3636FE854A1530277D1232303C0A86365066
+89FFD5E3C5AC028CDD18A3FB360C8973AEE50FA93127D6C7B3F323689F3075CEB2017BF8
+BF827381B96044E245DA2A845A536E053A1D5B540A8A27745547FF27CC9368EEACA827C7
+A47E56107A68B58A4ADC9B4A56C69C16A061F50C79A7034D317FA0F61A123D749AE3A140
+4D8A29EF631D5F925C8116256B40B81EAA31C326F4902BF46D68C5D6930EC624F3F50587
+9CB9DE9740CA93D36B8C84FF21E7E2AE48FAB457A8973106BA5A4A9D35D19AEAB1AE1E2E
+8794C96BEA993A03C1CAC00697D95BF3287D7B14701DF8EF79683F2771A444D334E7074E
+0B1602CC3D08293FCC6815946798BA56470783A0BCEEF3BBAE34D9ADDD47EC0E23E63505
+67965078615B540448EFE238DF5F70F1439123534B37B01D7189DFB6B21E783474B476F1
+9857F50753D49ACB4EA73BAFD9727E3EDB0ABD056CA73046DD3743451C0C2E54AC8646A9
+C1E269B570605A92E28FF146F6C9E49FEBC2B0D1946D673064640F610FC762ECBF415845
+E80463295D0EC0F6CDD35852CC9126E08DA99B91A75CF7EBD86466AE0C381E87E9D99BEA
+1F6D35F3603AF79212C5146712B20727A4CA38A6CD684B5503BA1C18590EDF890902448D
+ED527E7EB9A15623500BDA827261BEC6E0AFC5D644DD384BA6B3BBA29EF93FEAC2BA6C56
+82AAD04CA8FEC95DC915B8566A268801A7242DACB08C0A47122DFE37EFE10B721CF410A0
+471163142D46D3FEA4282739312E53BF815FA207F0DDFD7200FE6F7730D33F25ECCCE770
+2765D198251988F9D85E4828719243D6275E563E439F7F7162BDCC0BE33CF25EDA87DB8B
+D51D0B64335C358ADAE488D997D3ED523C3187A50D1E287E00552844DC66F3417D145635
+3984699130F9B7E860359DE4B14195307288A8EED3BE2AE04339CE84BC1C1D02861C32BA
+47C050474FA44D746FB2BCC7A1469C9246DF0725F6B854FA1AB68D68E96228E2CB7834E8
+01684DDB14552974A23ECA2254EF2B6D195650ABF1E2BD69B2BBE1BF520CA77E748C0152
+FC5665C36AEBD0002190FA221DD3115ECAF905114FA7222822523711E48DC71EF5FF7BC0
+9BF1C3DEA0283B5868357DBBFF7B4C6F91C47F941B40F03259AD826AE6FF057EF4B07B9A
+058C4B7BDF58C6FE1D71FE9F5E96ACEDF8DB833A4CBE46BDF8009F0FBECA3314AFBB162F
+0545C10E45F1F697A2B895849DE0EA02F2770349317E43BE527A3B1D808785CA305E06F6
+84935F0E7AA4E015A8A4FF3E8F7E6E5472D161EA42B964F48D1450F9E52D5CB33C5D84B1
+4138225527E6680BB40D7E73B2CB4BEC73EEF10629E9C614DDF422DCE8E4B6F64DFC4ECC
+3C48660A9E1983F4A84E4EB254D5EDA7E1A6736D98D878502A6320CC661E4F47418B4D4A
+9D0DD2A9733C000A0AD41583095DFF2D1AFDCF6ECF69C85E5C9BB3F202BDDFB142E6C18E
+60B07D7EA40340938542A5EA036B354AB35FA8FA0B9391765A8C498B85F454AEC3F177F6
+8A122FFC8976D4AC99A370B3B7D706EB1BD36B3AE5D51C9482FFADA8DC7584795E8696F2
+81A0F0E3E9912BEA16AA15597B801EE5571F4BD4FB95052049A663FFF72DF8FC6FA0CBFD
+A15889F230C5AA3B25F4DA1500DC0302010956C520A7F73E1A7A938E895784C05399030B
+D4452FF0BA27AC1563BFF0BA19B2C5427E2E6B8A06BBAB6137DB007FC4692267B0D10ED3
+1C0341AAA6F3BF586940AACD797830468685029B2284346296F1500FE92FABCDAB796F35
+46274B8A69AEA68FBC6E1EBAE3957865D7DC284EA7A6CED43CFC91B1CFA4038F413DFB36
+491FBDB1902914D92F2E45BCE9EBCC1484C97058783BA2C17F42B57A180C0F4E35B71090
+CB0A51F6AAD0A5B01E9AA7B8E69FA463B54A124AC05B01A942526B070244A2ECB6DBA5F8
+01DB459733371F92936CDFB4F35F7DC4ACDFE02A4002186F98A1000FA168B6B409D152ED
+D5BE9141CBE10E0EA1C17687E011FFA488E8D9DA7D75E847770AD67132F8DBA4DAB8E567
+54CE8BD5B72DEA699E2EDB0BC2868B71E012E631C747F23F5C221BE43E034DE187BDD469
+E712F4FFFF09597BDEA4E71E76693FC639F758606E99774C1FEDBB5F121AB9B0240D1AF3
+86B28EB0024E13C0CCB25457F4996665A9F68682995960BBBB9622C70E1910C36BF19E5D
+AE05BA5AA16E07F1E26F00C5009F6D5BF8B2AB9A3A34ABCC391B1EED111BB98B0A357D67
+91EDB58EA4B24336B4C0CD8994CD552E29288AB0A7FBF948891C41639412F0F2B70FC00D
+2C509270C53B5EA1306176290600581E0E7A793FF3C6A085B9C627F941E36C4D6D31154F
+6CD00209EFB60C1AAE01636B10484C673C58881FF8B54AA1EDAACC309F1C72C434247C7D
+ACA423249AFFC2ED1E53D1B862FB553E583C4694C99B6116AE9F6BAF64D2B512C9C624FD
+EAD7A00D757B5526D4AC98137C875D0E0E051ACBDE4996DF3B4D5719114C22D5DCF02A06
+4DBF81847FB12C931C2D8F6E9C557666DD6AF7B28E7E763DA7BE334EB3FB89DC1D5D8F12
+6ABFCDB56CE31A41E098375CD932B9ED53E5DCFD6A943A983F071F8B6EC1C35DAC748BFD
+32B8FAA674B8F902B433BF12F554D391B56A3C8E36B6AADCD9489CFF80136FC575D7E64A
+957656B2C4FC270F23AD3790BCC95E85894C61108A9EDA8EC4D22E9846ABE07A528583E3
+3084991834D424B8D52EA04CF93C1275FBAF578710888BAB0E447C395F0988035DBF6B79
+D65169437CD509EFFF8D61A333C909BAD589AA1069281E3DD8A266D4809471F65218DFB9
+9CF1D4A6C4C07B0A508DE36F53D506B25268058512AADAD9E9EEA08EE51C0B12977CC9DA
+DC195E944C659D2E847FA471A403D3069BCFAC82479AD29FCBEF4EF6C93EDEE4F0C0E44A
+34F25718B7158938A3A9CE183D707D4F789A5BD28F331C23B3290AFC5E4504794654A814
+BCD943F786F603E24C01E81C1E8577047C3E85BB4D861278CE2E7E32193D1849A9A310C8
+419214AB037971D051A9355EADEE4F56DECF0B20C0AE7A396797480EE47FF822F96DFDB2
+39122A3C8F8A83B8B3E105B3950C8E5703BFC5E591437422FD417A71797DCD2872FDD9FF
+28EFB8E20B2EC948F0D4EB1C67E7E16CEA436DEDE1B17E0C4A11F1E91D3CE839DEC8390A
+FF3C58953D098B24597766D01BD59A89ADA6F1040482EBA4157EF2FE71B220551809013A
+B5B47CFFA33546A676DFF72EC6D1A04D82750805E38EAEDFAD935833B94133FD5FF8A58A
+5A01CD5715627E74E0856D1F8455F6379F2E8256CE604480CA874DBA0D06E190833A8015
+7BB75CA24E95175821FE790DF854F15E7EDE318E0C0171FAC8BEB5390B47D5814E4D1F13
+0FDCA640E0FDB9D0A5068E98158FE775AF2D0C7D9136087E00E07B67AFC8FF6DD8FD9CCE
+ECA3ABCD3DD58DF9F14C032941B13E01BF6EA44844D52FBC037A47BD94310EC47A1F7B54
+B6BC07C7092D8946CF949C654EC1AA520804F8531C1534BFA935FAAD3B9D7EC925BB0C4E
+2C7E8E205C09104B8FDD7F8AE970107E94EC5C2D5A7F28DD7C0BD6C911CCAD24CC303D5F
+0C6C9A4A585247D5EBE57AC01E7D8E3A384DAE4803718C1C81D3035324BDCA7BB452A030
+89FDFEB64728A25EACA1F4AB96A6749C4BFD6DF72102371863F719D55825AE83673701D7
+C5139567073180C72C6CF38A0CBEBDDB043D2B412BFC25A08CBB18FDA0AE80554DC1082D
+E4D70908AA0C667073F0CEC5655C947CDBE6C501B1E38BE843A5A8CB02312EB04CB098F0
+638ECBF704DEB82CB1AE8CFB27B368D95A72757162884704BC4A74DC7ECCCFD1842D8957
+BB1AF1B020A97A149AAC0E0BA7699703E9879E49F122A838BC7465161E9C4C62E02B38AA
+396C1E65209428DC112B08AA731031B4198BF48048132ACA9B40FAAC94A236BD16BEB9C6
+83A511F57E22ECE0C6C63C0A3C5366FBC488DD3CCB19CA471ECD0B895B644C2735C8D008
+945C02FB39F91ED4D633C151251CAE4E82B18B55D978E6A7DAFD6F4D5497EFC807AE9AC4
+2BB5E96A8630756DD2EF1A7529AAB9DC1CD2A98C9F70ECC97D8D1F920A5EDAB809C7BEAD
+04B8E0C3266E1C2601FCDC61B73007294ED1176FA5C5E94075A95BABC2589B04B2DC6A7F
+2A244975EB7CED7636A6216A7CEBE34CE405D1C2BBDCF3D30D0B65AB3F92357B9AF56455
+2F36A611924DBC9C90AEF0F6DA64EBB58510AA8AD7BC633B8340A942721C69B39A01A69C
+28E44C520708800484B236420555098D369EAF3A1251B128881C6A71F464B0DC77B9D1B0
+68B476024784DF5B722667126F0ED991F123124FEEF22BEE19DA1869CA12E0C94229BBA5
+B2CDCDE1BAD1DD53B2A713C4EFBDE270F0C8AB7F9AA27FA800DB025FA10B2FDBFE4B8A98
+A1283CDCF35BDB1A6291884C494FC6224B965B55742FC5DAC852C0D014CBE5D8E64406AA
+5845853F669A1667A543E64D5F86444D0CC1C4F796B0F51C0BBEFC8A7195C72566851BFD
+01D5A7F44A707448E67D202D89994F2BDA312FF16B5287D1D13E4FF8CA905D012B2DCC06
+42DD1A85636EE7981F13C099535D935C1A1FF5218CB190A58BAB01C2F502323676ED3AC6
+AA4485008B7D142EB15455355811F1FE8B7FBBE5D93534A4936308067A6F6C1D80F6A287
+696606946C8D61C244DFFFA6FAB178513EC0F1724B24B3F26F1725471AE031FF8E15109E
+A992D90EFDEDF8796BE5C16425E1E1391680C229067BA9C69CDC20077C02364C6E62EEA2
+CC5A7EFAE6A9493FB1FCC5C93228AB5DBDA8A2BF8161FEC4492B02B4F29CE42BA9C5ACB6
+8708C055BA56CF6210662112EBAF899E62CDB2EB8A685EFBD1BE151B4F2CCA5DEBB90B5E
+55FEC92DAABBFAF7C3778BA79A59B131682568FD96640F3794EB7C57A508DDEA025C7120
+89F193118946022A9024289B2FD5D6FBB8B8413B0DF5F65227DC12E99B7B657F846D798B
+F5E74A3DCFFF1B9E1EADBE5A22268846CB5749B22A96CB7C2A7E1BF47E9E8F5FF7354314
+3112230BA9E8A3218442BB7DDA51AB8641BCC1A4F6D25B53A4ECDC171F1B384C6546F6D8
+7239CF09E6C8573BD593FBA1ED2C42443F6090EA7A5F4AF4781270BFD801F57F42A7C51B
+AA65AFCADED310E6F29FFF5D641C2807B8CC4DF05D45CA5BB072F73E5A7364851C7DEFF5
+270D676F9F86E425D14171E3862B7FAAC43E181CE165BF319EF549BC8B5C3D3EC51017B5
+8FCC9817F9E527D8DD01F33C9B99A98F675312D26BB76FA0DFF8B239A1CC7AD1A5AA9333
+8AC724B6A4C9B5CADFBFF718A5593C51E476468BBCF2E5E77A151DD9DA236E5765CC545B
+AD8D10D62B238BB574D665D0A6CEC479D1719D587C1362C2AF7C04793B2A7B20C297D5AC
+0F96F6019E1648B603AD04F8817F6A6F5E568A775850DEE71372303059B137BB129580D7
+D10134DECD6D801AA62089EF6A573DE96E0958552DE214E3615A306B798B6D68314DBF57
+4305E2B09CE8816EA4515CD6D2FECD2EA452FC01F62464E73FA7006117556487B6F58197
+5EE9CA6DCA4480FB0B9450FA07B5FED7528ECC235BD8D3A24CA63382B0DDCADAC78384D1
+E5A6EA0646E3655E6C86C323CEED8F76A53677A70AC54CCFB97A3713E5209E1A0F9B6863
+289A62261BAD054A7A495C3D0F883735284B7ED4A624C39C8A03B93FA9BB91BB396C0E4F
+E3A173A5100CC25ACD1E3967588C56F6F3E70AA6E9F5621E4B9F3A25C0ED1B89054EE11B
+ED849B16F521BD9A143D0B29796D66BD57B4011EC290045DDE9C4800C2D0D1DE24501859
+50DEDB737635EDE2D1559E0BA7C0B361BBAC80FCE4E4B35746B8865813930ABAA5BEB288
+1D820EDA6A683CA4A94EECDB1BD0415D0586C844C66736751640C5E8055C6093FED9F84D
+EADE6273926A863D231C9B461B41EFEB4D945D529AF5BF494858A5E5E0A0BF1B179B697A
+F25A3E29991DA1DE79DF293961AB7CA49846941E82FC59B1C06B9BE8BA005138F6979DF2
+7909F57060DE9028ED61B1EDC811A60090CDEBD7781D628BAF2C540FC7B4783BB1763630
+96B50637075013D726F9D0EFA2ACF762929C06075D5992B5E386496B381858B6AB040CEC
+184571C870023678728ED7332630969C86BF521693DE56D09D6D8B0B37511C7D714E9932
+6DD501DC3AF262A1837BEB8AE03DC161F61251A615103EFFFBA7757615F60F7AF5DFEE44
+5F9E832E4794299721776D643A4395D21F905685BA9038521F05E3C3E5BD1D3EF9C229CA
+695BCA0132C4A64A71334D9E76C48F6F4D5901CBD9DAEBE194071FB0FE7D2C5C395DF93A
+C1C64AA36EEDF18B1CA6E2B510E52A35091AE7673924F36F7AAEB981B9957A3EF3123C5E
+05AFF67CDB142D00CD16E03754BF6C68CFA2D734333AD69B3A3296EC597C8B76CC3232AB
+45ECC8B2C90253A7001485D49E6310FDB5DAD3E7EEB4305BE7DF36342C4B1E11E0945B5D
+EB63198EE676FEB7D3382D0CA6EC11E11E8130AA9740FA070EB518CEAD8C85D8BE693FC7
+15B31D6CEB164254D322B7032075DE964C94AD8B28BA58A3A30EA9DE79234F4DE0CCE216
+DC09F22CFFC1E740B082DF65F10F9D9D173E1F4A996F16D5DDE396179B4CE389A555C3BF
+BA3B9059418EE567C4DC661C151F9EBD8F2E006288A6CF3B86D8F260E15E77682FE2976F
+14D4E69ECE6B15C1042EBDABA1D24D9758EC60EA675421D5556C26A83CAC3B003F8426F7
+98195AF444EE55CA608A69408D69B7B103FE873A1CBDE862A7F7C4B27E778D4ECEB1F596
+C4796B37DDA26AE61A4579506AC65F72BE3D01C2BFC79556913780F541E26E5316F6A56B
+5C92DABA9B7B9A9E80BDD4FF1D3F27559F83021D89CE8497F665F2CF2FED3805F8CA7D36
+355E41188F853B192CC64320849EA08D09BC87D24DEFFA9196F75F00893DF4A069BB4340
+A9A451102003DC8FEDDDE6B648EE1675851310D15FE319BFD1E411DAC0402698598396EC
+9B01FAA040F37D13D65D9F88120D6212C7BE51B98FECC29CBEFBA669EF8B73A39EF24D86
+8C692FBD3C55724FCC7BA3912B87998A4E50566ED69BB2742FCD60FD3BAD55EBFAAA0E9C
+8BB15FD2BB7BD82D65E722297E9173E09D8C228A76755A3611170CE15924D3F2BC9FFDDE
+B0F2CDFC4CE44B6507B03916E334B4FE336473D0DAD959DBF3B11684D09C67872EB406DC
+E8AADD34D2A0FE88056B2184D2B07825749A3131CFBA4A6885CF4D84D914DEA0A4DEBD54
+F35F031C2B4C18D2C0E5DA80463FC86645A3B63209C53BD98B394398E506D8E34F0637C6
+BD702B6BAB0E45F12EA06112EDD4983034410D96D3EF907D32C71AD4953A8C90FB289510
+70AD7E985BE69AB6D180E110FDF29770905DDEC7DF995FF72724A275CE8CE825B9322B9E
+B301DD7E90A6075123279F9EA89333E39457333EBDFC5F07AB1563003D0E766A010F2342
+A5E210C256CA182DF768439CCBFC43477E25E15BFDB3A224BC1C9D67B0A0EE160B7142B3
+58330DC30E49446C18969AB491CBEAA64AE611F587A3A7F7BD3B206CD034D0EFDC12C992
+4FC9F60EB7A7B7BDD94E900C5A58AAC8C17B3588A95D614197E1D5D1013888DCBD84F7C2
+51DDBDB5E1EE146350A94679DBE6A67BD7EFF924C402C23DB55C00664754CC9E4D3B1422
+16AEB7A712CE85947C4680102B651F83DFE71428028B258E722D827C2C347CE087C741CD
+F0846675E34D56EF99E21854CA02AE9BF9B41B34E58A1D5144A6E9D698172FC2D8E8DC49
+098B77980978D67285DA23F821896D3ACFE7ACB6FD5DD87AE6D07F5FDE7AA553A869E594
+BC2EBEA2E0ABDD5E747FCF0F7D1381F9E121E97B11456F80215AC688AC777CFB9419D95C
+DAB35AF315C5C83114FF51BD583F17EC51A911F255521B3DE63C5B0A016EDB98722E0B15
+FE68117B4406CAE3F29DF6CC813569882C169070F6F499DAD42E1ED6DEDBFD464D352B53
+0BB28FE2554FAFDD48FFB9E1A433E94681A5B9DB2AA285BC5CDA48C1BF7AE7999E5A6678
+D9ABB9A68BD4A60756C13ED1975E2107F6D1FC4FCB2E18FC25E68DD2E53A623D15B95541
+31F1DD74E82AF748119B40F6E4E703DEE1856BACBBFF672DF548327A95F3B52DD40105C3
+604A24047CD989DDDBBCCA27D28F3BCD681CD55AFAA1CC5F29B39FE1D6B59FBADAE71196
+CD83F5329C9B969A5BA06BA67AFC193C4BDA78A275C64E2D82F373EDB713498ACCA9FE26
+9FC4736828D55A98AB9FE487AF40164FC38085F9DE01332E3710F22EA52DA9CAA28DDB5E
+3AA72EE9444F818DB13EAEE426543DAD3C78D48B513DFF77C18555DA53B33B04C8887199
+7B2C9E86E12E94AF3F379D196532D2CDB84741211A584B7560DEBA3C53CC78E240186671
+8D295EA11162384F00A727EA4B7EE6527DD7DFBBF5966FB4372A35BD2FA7BB7A6FCFE23D
+AAB6570FA52506E3EF532E7E7930298FFBE47D48641C0E26D1BA636AEDCDE13DDFB3C822
+DC32C43759F016752DE8F256DF5B57EC3C623C05037F1E41C38C66D18A27610CA8BC0E5E
+FE4FA49EB0E287E855990B9C83A103A1151727B192496B318A0730AC902D7C4B154155A9
+47AEF1B7255276631566EE5B995D9596517E42DE25FFC666FC0703336FCFCAA2B97031EF
+9B95FD714ACB1A47A249DA377A6EC9338558939C6327B90B77249CFB4CE6FC947BF1E88F
+17F20A194DDD37657E8D5BC31F624B6976A0078063FF707BADEF04391782C6660BCA4623
+17BC929F6411D2351B9DD2F67CE4BE04D251829BA6E5ABE574FB3D3D8D2858AC7B87F3E9
+951F0FAD71060D85DD3BF22DF505778932D2C7CEE2BD318C0E9601D085FD258C6ABC091F
+EC3F44C639B2852EBB31BA5522AF78BEDDBBC52E804D5DDF23DD119B951551695BE44C23
+5DCD52729FE0FD451F9CEF413EE55AF45128E35BB451D654496CF1C8C2BEA6C95F87040D
+928EE96A22AA91E8166577727896E7A26EA5298620E50832956DC5B4B95986C69079A1B6
+8F64DDDCC518AAEC30D9E908BEA76C19D54388435012C2F8ABAC88BD1F82A1083F729569
+0A4076112B601F35B1E104720EB73D88E0E62CC0FE278EAF5BE953AD8D44604C35D05A14
+7123538297A5B80677AE45EBE1620302B8248F2B0CCFA068CBF76C863CDCEDF677AFEF18
+F4934012F795C9CD39EED5915DDAD4F640BF75DC91CE77E4B449703C1FBED867745F67C9
+BC48C987BCE8B838D35930735744DB987AA4E8EDC83236D764D1237028F6AE8A6CCCA003
+692C28CD708F1C9F4B0468140AECAEEDC465455D8C69159ED0AD0D0B004A8B51ADFDEB3D
+82220B8D2DBCC5E1CC0F550E44B83FA668B30044A2E9978A810D4EF995490065DCFDEE41
+E94DAA51D26F13EB8218220FCB1F0F32D5B5C15E715A4FCC605B2F8800F44B82633A83DE
+FA4C3430104CE6650AF07AB2668E751DA4845205FD29B7B03F46B51DEDC3B6DB3E534E15
+AA0B33BD6E0D2C5F8442EF326828B9A3188EB15DB04F301A98E00710AC5CFBFB9B2B99BD
+5AED103DE636341AB7B03E24016228C0DD81EC95D5A8B8EE1C44944858784C024BE6C8FB
+D038801D2423D09711C5FAAB0E16C87D307B53FA9F874E6FBF1004E47C6A6907DF86BA73
+9DAAD79101866EF02234D746C72BC60A69F7BFC111C5C26B87440D836432E283EB0CB8A9
+39ACB06AF4FF3857EEC12A1BD1189514CD518060FC75DDB601F545CCC37676ABE3EDD86A
+7FA54DA5C33D42861E585D05EFD8B41D42F7A9A904F48FD96E30EF9C74433B35B1EC9F3F
+15607376F04695749F917ACA32779CE1CD986051E43C2EE748542E4C7CD50E3C30DD46B7
+C6F809D1051F977E7D351C67403B913BE5273A97429416656D83C0BE7C08CBEF00BB4651
+D0D5CE1E8885A32CBC72DD26CAB330BE9845425E048B1EE1AC7591F0F0CC9F73E1EBF665
+76591E3DD449304DAFDFB6A44C7BC4DCD9202AA223C9128A961792E3C0DFDA3515BCABBA
+78F38651862266E779C228C596BBF3903F097765DA142C99E5185BE9DE2F01AFFF441965
+198BD1FBE9BB8D61BA6C685BEBCBD4381C20F71F8DEBEFF62D7946B04C7D357E54ECAF48
+A49EEF2ED25179C1C3FD45268363FA20D07A84D60484C712A43D224C57551FBDAF4973BE
+EC02A16076184E3108DCADFA44B93710DB3388E633AFA06AFEC76802F05EFAE2CFC74A5B
+AF3600A46B026AB514EFBB7184C75BD39FE9427F6F0F9D2435BE1B26BBD4816A72B8AB67
+DA7A6960F5A7A0E7FB1F83DCA6E3E8E8F1BB11E22D378FA743B7791E981D117A2E8126A0
+F3CF5C9B0C35BAF8B66211813FE63B029E2A3913CAAC2603AA4AC900EB8428FDF58DE83C
+D998B69BCB6ABB67FAB1647806FE19FD695372D671EA0B6566719938456CC79D265C9791
+725AD53DF396BFA79E945F4AD42DEE0C69C995EE8DC3D8E85BF383DA9C1256AB133CECC2
+49A3BCBF384F53AD50B3A58606F4A92D68DF6C072E66997978A92EF5124DFAC8B3938E60
+94C0FAF7556D0F75925FE99AB3E80FEA8042A977931E75635051DC896059C30D7ADC38E8
+90131D3472CE1BBBBABF231728199245250B618AA5F830D20C8B1117E4406C97F59A9A76
+205946764DECECD486D1C217242CF8C58263535485E89344DEFAB9D94079EC177AF6DC31
+051EA610E81026B7569A061E99309A04CC3977C9BBA45E88B6AAEBF585B5C79E42548C23
+060E0E103CE6EA0897B43EAA35366DEFC5B1E5E673424D707F05C770F31218BF56855627
+8C9F75A113F5DB640C2EDB7F9D3138A5C314243030CE2BC58F4EFC9B546E407A1764118F
+F9D2208C6219D088CD8A214CBC0C1DF55772A04DFABD89E08F7C98455E8A5F1F82BA749C
+7C5C5E6CEDABDB9B3F6E1D717ED97A50D0906BD4682D9A529B3530F29113A35D5681980B
+8D099BAC264E382DCFAB0419F3313453A080795E7CF66860ECCB8782191F4CB0EB2D2965
+F14D28EB35DBF1C95437674D84C1C331F4EE99C8DECD6946069B3A4A7DEEE0E48E817AF3
+08C28DF99E67A4413655CEB10BECCB27448530B1688517F0C5DBDB97A17C6F12C6AFBF55
+AB5AC791F5363E56AFDC38DAB07B7A47B9FBEA91427847C5EC1D584FF56E6F2735FCEC80
+DEB8D89F90090A11819D08591A37EC3948E36AFD44237CAB16533CFB51B50E1EBFC4A6D7
+BFA520FDA738662AE6C0214DBB2723FBFFC986E9DD47A493FC0090575CCDDD6C38EAA038
+3858C077F57E1DFDA8DA95C9A18D9432DA2C86DE069CB675D9C8189EF01C567CE476E0B5
+31FE688044569D34362235F894E746E6306C03E76E615571D9CE6FB31D63BF1DAF29AB76
+27C0D02D7760EFE583C8C2FAD4AF0A90AE91642F2F20725858CBC2FABB5A5A36F19A3C6E
+455DDEBAF968A90312E83193605CE8E5454E396C2C59557EFA1BE1E0F8A0AADD060F77E3
+C642635484956025266155DE24655C44BB0B4D07099D81760DD0823EB9EBABBA27A559F4
+8803E6999B782A4D91C388B46E1EBA6E8BF7CE9080F46B539A507F5DD17AAA05D05A551C
+B57918F3AF43390187E3765548F4E5A3360A95C80DD6AE1B26E1F90B8391A3872ECFBA2A
+087415ABEBB9119CAA1D411EF7E0F0737AB30979A30B2ECBC8EA42F38B41421CFC94BFB1
+FD30BAEB6AE340D043A15138AC4A7FB12CC0AB80547DA81D91166B09CB56A5504C048DF4
+D4E1E7083B5EF010A38F4BD375A3918D25B05026FFEF87AC25AB554EE74AEED323B4AE63
+0F1320CC97909D2819A8EB0A90AB5F1147DD888AEC5D42C8C5F2B2728A80AE8673831189
+D76571F665756C2C01AD4F936EE0E607C27FA9B8E38BA5C67B52E7A50E09AFB2D0610A00
+863C59F7A1BF14A5D3FF8954CBBC3D13F709B433822DB8CA2E64BA1FDA4F9478A5AF24FC
+A4427F49F39EBEDD3BA9DF9B2ACE9FCB01BCC9153A7DE685AC5284427B0C573A6E5D9013
+86834552B2356F11011083B65724EF7F8C7D7CA259E0C03793B9EEEDA5B6DA8376E72EB8
+033A415DE664EA5CF53B88655FC02AE5E530C6A90F443F740444956B60F6ED760294DBC1
+9F492DB3A5D4E532D0DBD9EE8139092D3E89D7CA7490400FA4EBE56334B1A17C9826AEB7
+74749C9193FBEE0414C7E7877E26B8274283F14A14AC7CA27139CBB8CB89A6D38DA283DD
+3D421153DB2D917391215433E356E64E4A07F6D82EED542FBEDAFD11D0BD4EF3041C6865
+2ACBB1FE71C6B7B3850FF45176850FFD64D18D4D55BA5E74D037D3CDFC62563CE2929233
+1E42E636DEBE14DE81804C1A15903CFBE782409A1E8684819BE6AD86F1C0EABC03F4CCA3
+A959E0B6C57F02D29062A6F0E3E5978C4726C01F607307C16F5F64460E81042B8E2F6524
+EA16F9BC21AE861DEE4013959FBA74E40B750AEAD9607FF6D15D96F6C28F4E9398C70CF4
+1B654A2A337FC8AEC523F27F6C5F0DA4B2D4A3758A0DAC65BF2167DEA823C3D108D3661C
+CC47D80C948444701335BC4DF8A8A8E433776FBBBDF0C97E985DA1311451CC85AF9E5BD2
+FFF576BC8E4A79C92A00678761D47D093A26796DE0316A80BA5CE0BB69E188F4C38E7BEE
+45C8DE646991071844CBB503847613EC82BCD6950F44D64D8117B52E3A63402C09931410
+D7A1AA9A04F9815D52C3BB9FBC829F9DFA76ACD77BC751475979D82275B709AF02783A64
+A633CD8F213DDE9216664C22E9F9AE3370B282E9098B86D4FDE991FB9D16D04C0C7F5262
+D539102F6529D73F20D1996061515A8F1219B228502590166332AE7D27CC822ACCF92861
+5091818F53CE6A7F1C5A68CCC3D6C7BFC81167C3C2294C9591B71CEFFC88A245E16484DD
+1080375D15B6A3BBDE47CD198D0BE312AE1F5F6EF6DE4A2CA38A717D7104466509C8593B
+FA6B5DB6DF788C6952A28E25CA9E20D636EF9E84FE3CE4D3A4647464F79111A610A1AF84
+E0BD4B8F7BA06C3AF012C74C91DEC0C597E6F4C19546D258D9E53E7943D6694EE85C74B4
+93276817411892299BC02A2CFB065F5655DD87E69743313801CAF098FA1C56841174EF0D
+4A7F27B2E91762069656895B9FCC9434434ED722BB9A532606688F303D0C514B31D179CB
+DED0DFF008F09184FA548FE7C276989AF46C9C63000814F90372A1295717CE87B2D9EA55
+34C0A4D467A0F6A32482B8139AC4240E3569476BD4F8D5CA5CD62F28BD2FD820602FB678
+69D696EEFFF2C173D2C7EBA377390670908EA07A7E90BA16790314AA8A923B234C8ADA37
+25888BC9A631A4A5B308378369C29B79966AB44E3F4DF846B0438C31B6143C9C3A003C86
+A2119FC5FC1509BACEE7A9A1EF43945214A1E37879CABF18B7A18E8BFF45E9C5E7CF05C1
+81F2BF236310B0AC2B1D45E0F6E3961AFA34CD8597914B6D503F7F5BB964B7DDF195A95B
+FD5F3FE49340767491F213D849B3299AE439801B84A2718489868599F29DB6849A5471D9
+043C6B4BCB4AAA48DC6CA3DCDBE782D3113463400F09399DB804AA81FAEA98C6C7FF513E
+1CEFDDD822C4A5ED4F0EC1AD96EBC6A713BB82FAD69C3E914AE2CE2AD2DE8FA301364658
+0987D4836813D3DF7BA9A77601FE3DD487408794D7167D6297BB19C8ECA466D56F130AB5
+E0ACE40D575558A8221EF634AA1D43CB10B8CB8ABE6EB2EBF97C8ECBCA498BD740A73DF4
+0CDE64C2C0F2D1468C01047ECC2320A9FB6D965C83A2CC768323CD1FF3590D6DE86AAA5A
+4ADF258AFA132E8D8C04AA614E11D26466CD9F265AAE7D8F3629857C73946C1CDE7EE21E
+15C1ABC4A1F591DC1CBC14B66269525A664419D0C9AA2C4713790AF5E23B566EE38D0530
+886A48F041B8B009C5522B55E63813023C763C68545AEF0FBDF2674C94219D0233EE3D3D
+165B31C9BD4B9F27649B860D935D77557035BDF4238B499C5CEE68E946454034E4841914
+987B718F237862C350178B8FCBFDDDE9E184B3EA11240ACAA8AB1880410F42E0C66D7A2F
+CD1DF1A3E421353590D9880F7A5A0065314D2E892D45090526A1378ED18A694F6820EDAA
+5599C2EAA34954D28B021848397DADFB07F7529EE0C975F5AEB815D91BB7CEACD2888F3C
+9EB8BFC41EEF2883618CCBAA18890E36B6CD9973E0A0665387DDD9829DABD9DE59C20652
+6608C3FE3D5033C33DF477762D37F080E3CC292D9E18348B2200956458F0CE0987B39876
+733331F948C4F15C818AEB8F829C03DA8BE6EEB40AF79A1686AB9A289FFA67BE3A42C396
+D5D24246959921707E84C9D4BA448BD725D6DDF0F735C9ACA2FF7CC28B75A81100CB2B6E
+05B75DECBC1204C68ADD1B324CD24F99E5ADF9DD3A41CDF704184E27303DA98C72037B29
+276445BE607B12363036C6EA298E2B47890FE0C3948DD0AA3D0FAC17ADA775F58FCC520C
+3B289ABB6315218DD1D5A6F36198EF93C58096B8A4A97D6B49278A7E41E0ED9C9D28186C
+C8B5D8DC860505D94B5BE90D1765C154C43238EEFD91F5A385B6FCDD19272F1E9E3E50D3
+83C523509B45D8A166727E8022861AB6D8A8DA71EF875A19362015DA1672CAB7E9D80E0F
+93A00867BF6A4B2894CBC866BD744013E8FED49596E6D0CE6D18D5CF56CFFB2BBC53FCBD
+9F2B1D7221A7F5B539AA962F74E002DFDB8A1425A881DA6D62DB3E1E43CD9C20C4B8C0BE
+FCE4B01FADC43B7406529B30BDD270098761F3BEC88EA6AC40C5143AFF3B926512F2D560
+F381B90202556D8E3AAE54712179B1C33131D52A4423676F83EEB850FD9D3281F4E092C4
+A3B402DEA3D01774B5BC9AA527D7E2A28EA9E6097064DF15F9A0F5B1AAE25ABA18689AC4
+2F1E2F1BEFF552DC96BFF8798FCD5877FB4F4B5082AF6D3F24293C7D34344959BA691E53
+8575D64484F2B36F1223DBC2A9959793C29DAC7C28E334775A1081818099D1CA68B693D9
+ED1D3163BEE2611E01B87E8B443A0D8AD12F251752E7850C29F2A535971E4BF055EF7322
+652B71CDFA987F4A51269AE8783EBD530F6180AD15739754EADD4811134E25FF8D2C6FC8
+9FB63D240BA9E80CFAEA02523BAE484EEF08045792885AD55A5D77F4A6645001DF9A596C
+877DF33EBA8E728567A4C4FE3D848C7C16E8A3B156AFFBCCAE51E668656929F9D061648B
+27093B54604B900461B0E9ECF73718C3B5FB199592BC7C59466F041BA9963920E2174F59
+7F943A02728D5B7FF69735757F5071904A2F6FA79DFD8F35E96DD4F92ECAF58A184CD6F3
+C05E50A25BE5E77BB2856AF8C71C69BDB8EFCC82EE65BA7841387E9CD655FDCA5707DD67
+26B96EF73B36B83362698C5945C75AAFDBBDA1ECA470512B7E11CAC4FFA3C3C66A07BFB0
+1F927E762871045195410E088ECB16884172E616721D58A5F51B5CC0AD3B3858180E1A36
+76CE2B46D4D91D06B146F81BED26358E5301AFD2DBB78D60F9F1A6185B50BF7A18CD41C1
+DD9065950F64ACDE99EBDCA136676247E455813438395B2D3FFEB24A2DE4D8D742EBADC7
+CEA283AD867A1239C224B59D55BEB159D6E4F5E588AD01DD7D398AD7BA539E6F82F8AAAF
+9F5F1A7444DEDCBFD014548440DF870D701E9485467492E832E235FDC1AA087952B7126A
+017E73A40F8CF1EB23E9BE25B942B2CAD61746F5277B807FFCD1C99CE3B2EC69FE5A648E
+92A04C71CDB188935DCFC4D261DCD29215431D80A7979C571CB7E1CCBB7E3627DDCE9717
+148CA0E8BD7F7F22BE4ECF15E8B6CF1B0B98D55A3285DC2819172495EFE082B32E72FD3A
+91986A13CCEDC5D832C77A4B559175C53EEE61089B4580FC39F34997A4DF83E427FE668C
+3D89C417FE22308176F895549F6E5BCE6EB9AC04675AA645BFB2D81A22CB7B30CA206A3F
+01B9FDABC7055B295236A79DF2522E4BB918AB2643351186D695E56E61CFF970A4118686
+E85A4D2E34C515D0203848CD2E92566F38E1D0DA886DC2BBDABF5B3D7B4BDEC68C5FE6C1
+8EA7E92F5470CA95AA5CDDB9936632E9DDDBC7FDDB86D4E96CCE3E8C579874BEED51CBE4
+D861D6657AE53192DB369EA930F87A9CD2FD7F9361D7CD884062870D4149126AC714B191
+1AC77CAFDD1C48686AC3474BDB9ED4B73EF67193714A392C4B273E919AFFA7EFBE7C690C
+82E547D56C79ACC4935BAD6C4F333FB5774FE84084EB940DD7E002410132F4A84894E2E7
+4661DC6CA73050FF3BFC04AA8959E9C91D2EABD7447839F3B32E1ACF1482E6DB7ECF37BB
+EE26C27AC90BDAFE91F8D92534DAE644CFC38E2A2C540A3868B0E16A6DDB60B02628A94D
+5702C1EC2211AFC1A9F7E888B90263734588B6FA7BD2CFFF5B56F91A70633C1353885C24
+8C5FDF9CA938673645E3D320D7C5566F4CF7C9C6E86C9945386A16FCB72D342D936B0E30
+6EBECF12E4F45A6CEC4947A71D674128FB0F72C198E4F4227CF98E2F3CDB7E7AB55AE127
+1C2A39C526CDDFB66A183B6589505CA7F5EE98C400A6C760441B01000F2ECE968EBA5DE5
+102C3974AD4716D7789E07AA39A3458740D9F55D5B35DC0B557CBA9661B6588B37F63173
+7579616AB866890E1AF0B90399F1F7E95E18703E6F723E70B2C00B6640EBB44353DC5A25
+D007F285A25B3241BD80CF83C220ADB9288AE09FA0DBACA187671CAE9C04B61AFA10337E
+75FE9FF0A4BF03605D0FFE41DEEB2F2DB93CF868CC7155DE51819D14FE17986BD187DA95
+96C1904E8AECA0F6DEEE83C9D8CEBEF4C0D13D5D5A13E6F3839CF955A6AAE6F7F5DE124F
+0174F811324CDDBFF0247214BA4A343959EECD37D67EAB103B4B9CBDE0FB77ECD1AC24A2
+C9FDB80D0C07AFE58C4839CF9D4CE6B78A1173AE2F05C51F17827754A8EF22B5FA54F3E5
+9ADD2A1103F898664DE8ACDB89929B04776F51E241134E9A77F071CA83DEF1E04EF457C7
+56A29D540B3ED164BAE4BA2C56967BCF5BA142CF8640CD829A952063BF1D9714AD903999
+F3B59167E2B440BA083635B6A11A652E94AA1135F9E00B0BEB10B533811FEBC64C7107EE
+7A2B4CEB6D019A305F633A9229121A9E1097C289129181CA5EDFDB7F9EAC133C6025FEB9
+9C9BBA2BFA67603A7790A146174C061889EC6A77DAE40C6C4E002263203BD6BD05D3699C
+7C21644A24D562DB3C2CEBDABD3DA2F607458CD4EDB1FF6F9275F767B8FF38AF5DDEA7FD
+A18A1CC091BEDABC7C1A959031009969572A97AC1C6836F3C24F6960ADB94D89C5FFEE9B
+3391C4671A09EA87B8675CE4D3C473E3B8A750671BC95439E75243100CCD0E0873A6A218
+C8E574583C968E46EC6115266614DCF130AF7F2CB1DB978B409846735D7B29F1F8042921
+7C32639EBF476E5B0EF1367F65F0600DD11C0142BA2386FB01479DED4F8AB419AB5A82DD
+66295577726A4C30D92A8972B72D0EC338487B630E86FD7984A97502583B27F5D1BA3A0A
+8236ED3B99EF2AFC4018CF8EA12D89158A04353B33FAB1E638F1817E72E8B6AD3C58A86E
+0DF708B6F1EAB273E746FDA3A8013271F16D3F0DBA72A07FB48CA2E0815F5635EEF35FBF
+27DF180FE2F9522E57CB690E4DF7BAB0C4F07D34BB8984D569340061B64C6D1B5B5E2090
+31A81A794634F445055CAFCE9E72BC0724EE4C9CE1F94D461E9619B3CFB47B5C404D15E0
+3C61B1F11D23808893679372E8BF24AA8D6D443F9A29C2908331F799593CBFD1AC2EAD9D
+855295E0B486E8AD72F570B3D768D775D4EDE2B9E48FAB6EF2C3A72F458D8B2DC2D534A8
+55FC77ACB99BDA7B5FD432D848815D327BE30A97556203F1C4276993E1A83329E62E8288
+7ABC85C17622A83B380B8E0C381376DA627C5852F0A031B80E22273170CA4D1367B183FA
+169F6EA37C541C3E4EC299A8F34835D56AAE798E69B233309FFA71761469CC4736E2D627
+073DB92380000DA1B9D6353AD27DB894F3DCA36918E7CA103B60B1AEC505D6BA9B22A92F
+BD69B9B2EFFD277157AEBE234B579E82D829D06DC06E67A4AF366F76D9321CFEF7DB3167
+3024556E61DD0FF006848A044D80407DDD75F123B155681F47C15283A44286FAE9549D8E
+49477A38347F5AC9940F511E0222BDF46263DE6DBE16990D0975C2279487BCAA41177833
+C54F854836CD22346F409021DD7424D157B2E6DC9CD664EABD2B5352B1326C1C046D6E91
+306E84D44B798DFACAFABCF352426442DA14795EE6EE5A1E451238E946943534A0E4D53F
+5CFF56D8AA689FE7E45D8974C5CE1D4DD9608AA42A873D0A0257D8766E7DEE544C350556
+5E58D358F0AB8DC7038795861DDADC8B0387D823F3AB985FFAE915019CE53B91A2666F39
+73143D04434D1B572ACF9B335F0B921E1E49428DA8AB0BD8D09B351C8BCA247A86FF7253
+4EF78A5150BA14BDBA2D535D5A46017518104E810EC678C9202699159CD05060C1C9A5DF
+7421F17177B9141550BC2B2D9F2BC5DA1346AF811667AA0F5DDE7F690B366F6FC9C3A488
+B88D827C24ADE4AF85A5D5CEC82BED8485EFADAB9D9CBFA07A879A9D6141EBCB10028BDB
+83DC99174B710E444714AA5D275073EFD6C542654E303D4F61826E7C505FDECB175C31F3
+455A2E835D12123392DB79B22ADCB30658228C0142B6D271FEACA94A186539740AEE942D
+11F4B10B00C6DA85D934FDA37B37332E61C66AB95EBB5473308E3F2E33F220CF1960202E
+5A2A81C85E8E831D4A48A7A9CB178A3F59AEFC408EC69D76722CE9FE89F5B7F1A31C7606
+32EAFE6DB673C6E76B0E472B2F0844506A481EAB5479CF0C559F02718F76D41F78B2CED2
+19D72BD4D9CFA3F99F1B8869E0A8AE58F40DCFBEB1B8FDB98032C3430E7402B9B1A93141
+74557B5A1CA485CFCF20D6830140FE0FFDE105A08DDB301E2109E5E371C2EB2568481443
+51F989472D19D12AB51C7F23AD18B592118EBB0945747EBD9F4DABE0C8EF4F3B8AAF5FA0
+34B3FDB56EC249523B1A3C32BC4A6719AE510FB82BE0CC27D6D4FA2A806941EA8E3CDEB8
+A30F91078D22260FFD25E57D8B3BF7A743031731EB7396D5E9A949039FB9ED19E38D5C5C
+644696E3EC29B78591F522484829BD1A58FA3595AB26E0566838DA3ECD428D905824B697
+3FBF19090E11E99B789B61C0BC97C86C7FFB32FAB5C7FE00EECB9C8C126C55C959A6B06B
+C709F0923589F9E540E746AC6949DE143744799EBEF6761AB9DA2E06127C18617324286C
+874740B4B5F82DEC59585397A4B75A5FCE31AB26478A7BF1AEE14AF3098F589C1FB7C010
+ADF80512E936F57CDE3B8E244B00A80054664EF33B5BA3E4FF2F43DE74496A57C0F13B65
+A60A2F4CE599BB104E72EDBF9BEDE7B943F9404760B7A79AC38AC19086516CB33AF7F962
+0157DAD4D4AA68B8C96A66AC15C526A1711081F56738F3238EF37EF609BEB0792D41941F
+6F1C7D95E0391CFF720A51755979EBE6323C653EDAF0808644E41FACCC09C29E1A210B10
+881AA79E4D9714F33A96735C3B2D0B13EE6272BD4D157E7FADE7F6BE9825E5655E80A018
+5EB33917002B5342002CE5D24859B6EA11E571FBD6F1F753974F965E7B5A8E0B3BAA8AC4
+A6C6D56EC55E44BC9D42C8A9AA29249B420DADF448F6DE76D1DC62763D5B01A4030A7D78
+28BBF81417BB287B267F64F8676174097E43E99785609F9C542ED5D29121D5626A9C7461
+5B145C86C2AEE98A127B25A990D9D73987958DF6831FC937B06AEFEEE14583B91590C768
+7A9FC1CEA0EAAD6F29FFAE96F8ADAA658DE66B8567E8A9E56D866B8A9A08C3D389B3373A
+AF2D0AABBAD35D8F3AAD5D04B69CD31F7BE8ACFF96CE6DB8C42E9F842E4254EB34C2DB18
+F0BD1D6EFF4ECDDCB5E77E92CE64F20260E68903EA705FBACBDAAC6CDD7FB431948F1504
+876DCAE96AA501F25FC5707CAE2DA29E995B6C4BC6CE6C641CED312FA02000D9057627ED
+14D531443C740E7CA081652087E0360C095652A1CC56A27B7FA61B3420ABACDAF14E02AC
+C80FD7B412A97CE4F33DAD5C747EF14281EBEFD492468839338802E42FBF554DA46DDE16
+88D26DB26DD3613986E9D28D14D4BAF9F739F93E8EC34A2BBA207294D8212D2CFE560918
+A72DDF5A537C4571281DAB8743A487D8C370D67C0EFD1698BFAB848E86D24DA2D213712B
+BA731CA3F76B657051083119FDA759A58F8CEF458085052FB1440D6938E438774FF94EF8
+896FB0AC6A92DAEA2E7C00BD76000C5BA8BAB7E5282952B4F16BB9AE8265F8637118A4FB
+F229CA87AE41C6ACDF9F8D318D6C3028A70BBB245DFB2E1137E3BE90284B26E8FF4CF77D
+66231F1BAFF98284128D08E8FA4FA75981A22F45CC026B1906FAB73C2FC219D3F7253831
+17A24392036B26AEBF3495F3300F63AFB9F0FA950673F5584FB20CDB57EB0E947F31DD76
+945838D69875CD1A4E7D2AF5382044DFDE866E37CCE23F3D06B1F5A941FD06CC0550D64F
+312A9D6A655414490AB1B1FD54E34748E1D408782FCF8FA6A611232CC7218B4A0EB93CD2
+09876191651777FB56BE434096B02918A658A7403E45F59A1CDDAC1BA53DD186DB8E35A6
+4078C11DC0DE5165205CBE612FF365C193BA540F5C6CDCAD0255E361622E94607400A330
+BCFABF835275473D4C7767015963CE0FB7DC88B4AEB660FBE4F86039E51DEA6DB4DD229F
+73D4A0A322C6D349A4C8BB304B96B32DC129DDF372FC424D1815C4EC51C9B0743D6831E2
+6BB5E28E89DAFC8845F00E47992877FD57EE0C02A76FBE2FDE8802A176E8A03509AE57D2
+0CE44217026FE28F2E06435ABF13D27875C5B4C6057DB1E1F70163C1011972A9C0DECED7
+6C8B547B8202977D802062E4189713D7F579093F4B9A72C69516F1179DC3512584977589
+461AC3D1BE8BE1C05867EF6FDC26E3B82D9CF9D159DC0CC1F9D6F94166A60E6CB9FF3FA6
+0D2B136FB725DE769BC3A8B64722456F049421CB7F863A357B318A979C3513C9065F5CA5
+93022DF125C9DBFBB822B1F84936DC5314F17DDF2960FEE70CA3E7289409EA5AE6F15DA6
+0E407C6262D41D52C864705B7DD26AF2CB813689E24E9673686ACB1970FB41CAA49378F4
+31C53F3A08AC7AF4D13F7FA81B6C3F71FF999380205C74E1B29B5A4FBD349783DF613FE7
+E2CBC7AA7B424965C42EF2CA80C60E0EC6F7665BB3CBC009F0F5C6D4E8ED5CFEF0E5DB9E
+3DC006C98706723B2BEC309ED20CF1CDC60D66BB478B87E8947419ABD499CCE74F80FE97
+89041D176C3BEDC9EEF152024E3678134EDF755D8C247E3332F7ECE95E649E73A54C5BAD
+228A629F5F6C8EF48935C8591910230DC5D04C395325F0C211BEC315F26F84AE8DE9DC91
+A9B5796CA0ABCD4774CC3DE12C39C2FC257165DD8A7E458E87CB67B6A487F10C351C4881
+0A636E4109845E0C664C47A2E11F9C99BD72570B26E854B4BCBB49F4011CB2CA4464FA72
+6DD8C1F05C69527991D634487D48BC554A80DC32B334D3BF6D65F1AC32D0E764825C8760
+8B6317DCDC713644DA60322D68CE38FAB781D24E14B19E711BCDB629AF7DB032CC9C4393
+195992B6ED1AF8B84AA21B5E3BB12EBA01DAB58DCC2E9549747FD222454D0327C66D62E2
+7EEA7AD48B09DE56F0968E271E59E8965E16862B7968A14078BBA821C2A4487F877E3932
+1D56C51B010AFB2844BB7E4AA57E3AECEAF7213B1C70F6EB993706C4F2A613257027370F
+CCA30A862ADC2D07E4619A8F753B13B94C275A14403C97CC131A924EEDF78933502A8E93
+344E91F5A238B236B228DC9FB65C60F8888DCA6B8A1EA897530D193537FF73E8DC70B3EC
+4CE290AAAABFAC0EB4C9534C7F3EDE90E840A1CE7975204FE70B52ED5576B0956E62EE25
+7857BB5DEF2AFD8D46228E9625C5C0FE48311A07CA246ADFD9BA1435340914455C0CAA4E
+92914E7AF31E25438AA05FA2656094BB31855A27BCDC45683EFF1291934C3C115D8CF919
+7A245EFEFE3F7FDEC037ECDFE70737A4D961CA634AE153B01F03B1A9F72B602A8358D258
+E03E54AF79090DB322ECE0CE33377E42E5373F443E851550E5D44F06C1C513173CD04D47
+9A9E70C9774780821872EFC100F5F5F34A1E0754E037F6F5917EF5126E5F12D46BDDC038
+2D11C217839C1DFE8D34BE69124B3934B22B4E8225BFCB2F265E197474B9349BAF2C1FCA
+352EF3F4AFAF1074DDB24E8A70218C83DA835CC97F6C55B6FC10C199BC9EE1033F6F2890
+FEFC3998D9F2941E350297F56B377A0EB5BA47A8195331A7CF3BFE934A97B88F18A38551
+3EA97201C200B5419E83D8AE47D6D6F3E864CFCA8A874DEEA5CADECD31CECFD46771E9FA
+7B24F3509E6B0B04F8C4C1C8E27DB0F2F9E0A422988B2D525670841C73E5D11F4B1DF7AE
+9AE2D8A3B5C354446C86862C687A3C21CA35FF2E962FB591310B8C0213A914278B65C7C2
+83E1CC558F6091BF4B159428BA249CDC3395D72E1D5E998C88F379A5C0DBFFE5833349FD
+5C61034AC1EEA717B26646D9024C3D8763F3B33E60A5BADFB514937B9AEA89009F5F6779
+8D5D92AB0CB3D57FB123DD852BA04E3C0AE9D8021F0735B69289822FE2727140AD5B911E
+376B13EAFACC44BB0F0A8DB9079DF3F3720779B5BF1C02CE47463281F6E496AB7695291F
+26C2E02A026A104C8EC76E0DE5D7272A3B83A947E3568DD72E8B2DA7869D1FF74F6E6C0C
+70CF5EB3D5D650498D267117C37DD3FB5870C84FB972E5C52DC3E0CCE6FA398D4807F1ED
+F253D014AFFE0C5EF86A8E431D1EB82D6D223809BCEA39DAF9AC1CD37243CF73E0635BB6
+6B8887C9C2B2C740F8373237B52A89E589D811C40C5170A7B7ADC6C5643F76C4D5031862
+961B7E211127BD0F716CAC04C4F8D8D0958FCF4D420947354D495BAB0C0D2D76030FA004
+910DC71A861857B1B073C6CC56691822B8749EC78741ED8EB2FE26F37E1F9A3B36947EAD
+661BA045810DAE798DAB615C0FA2B242209D8EE04BA06A78FDA985402076CB3A893E5364
+2C998BBA5F530C8944EEBCCF46B9BA42AA25E0D859953A948E85A8022C68EBD496553B68
+2555030C9336F53FE11C84168F19533F5AA4BA9C94FD120491D55C1D3FAB459F80F70034
+48F1AAAD448969D1DDC31D65619CD33070EC9BBF9B4A53C180015AB0D807744FB32AC68A
+DFD7986E082D57C22EAD0C5352E86911E8088BF50E5F9E1D70241959CD3C18145B258B50
+261CC153E7CAB9BD1E723209024540E123C2333D5A5C4C45ACA1358790816CC30F3D9BBD
+8453E76263FC425F7C2E41F79B402DD79552BE2C837B3048BD534F90B3AE2CB1F15A559E
+C00F1E783101866534B0039C433AF1DEA08C4CBAB477327EB3A56AD0F7AF75CDEE8D96A8
+0BF499251B400B85B4D157DB4E54184AEC11547522A187287E945DBC7E31CE99E8499737
+2675C3059133BAE517DC46AE28E735C72E31B30AAF58CE26BAD1FC878E54A72D0C44F980
+4C9D5D93947A846B01F61AD1325CFA2DE62664F181557BCB92050CD697A26133B06D6C6B
+2B2CDF60CE774CC5EF0CE86EA4E4879ECFE1C9B03E3EC73E35D53F5A1DC2AC8105953D02
+277742EE13CC39195503F2F5C8C29CDA7E4D54AD44DF4BAF5006FB9C081A938A5B51EDF0
+A20A005D40125960D589531F23CBA7C55CCF78C72DDBC8E9D84BC2A0C95DC0134FC564CD
+B08777FFD70A0EF725693F54E8C46CD77A5B9FDC91E83AD010DBA9802E3E140943706AA9
+2FE69EC2474E61FBFDDECD7FA0641290E709A9145D8ABF5DC42285CD98CEC24BA9A7345E
+BAF82D4461F027FD8C609CDC0EFDB7696CDB4116EBB91F0FD74676DD5E5C880CC9531A26
+D0256575BC551C3CB40BC4382B30302AB0B891201F818BFDF6D4BC88DA3E4CCCD97DFA0B
+C01A7FD9BF8DAA71C8D18B08E213AA8FC7ED8E3172F80615EB510FCD5AC5D508047BE71E
+5C0E2F8E200E2BB4A8BD0C4ACE1D5CDFBBF09C74516F09AD40BB4DCB48310BD33D28B81F
+B6D0D04144E925C43A7CEE48D7772344EEBCF29D226ACACF8E693C74A0C11DA4177FB477
+6148575C305615CC381612776C6C6ADF8A92408F434717F365CD54EC0507D77032A1EEB6
+6478EC198AAE86D1DD2719CB3AB7A34757C07DAC27ED8A2EE44C55EB3F7074DBC98738E6
+175EBE6393151DF9EEBFFA3B8F5CACE947311B9CAA3C9BD0FB3B359EB30A910D2128D437
+E9216956AE6574F55D25E0E5D8A8E0C96293CBE723960A373ECE00A392D78456EFD6E287
+D57562DB3BC3D2A7E767ABEA1D7231C4888B7F7DA7DB7ADF3EDDA0815CFF72C4A40E6CB1
+2D55239788BCDC55F9F4FA9772782128F15E16E71F33F6C5B75BE8DEF23D8B4E0DFD8173
+879DB3411147841801D556A6390538919D7D2608F5140F564EADF2DC08DF0AD03F8C126F
+FC49829551BFBF7EF652359414F56CBB309705B39D719A5DACD7401D6AB251FCC278936F
+5A0DAE9A899AB62B9A33FCF22092DA0984A4BBC5C90C6F0448D48BF510E9FC8C9B67C447
+1271E9ABCCBB65A4D92DD146C910AC34752CE16939378F0030039D7DC4187B66257475C6
+AB2E3883693090DF350A42D3ABEDE7E84B3EE9187FF09775889B28DF0C1F289AA28E9EFC
+ECE418B40D7AE3EBDA065B2C1B0AFEC58B67199E52E33FA3A305708BE5A2B5C88795617C
+DA1EF1314095D09920B6EAC7FFE58978DEDDA2F17E598278DA325949A4C14C5C0EB76029
+1E325DA7F4DD83F453B6DC912C790EEFF754F69B308DAE37ED42DEE308EFE13437599F15
+406532D885197F621DD87FEEFFBC70BD47AB8FA0FAE972242FBA4F7A7F09D01628F87645
+1D3A6B885B11F74B42C8FDE4DC02F0E677F0A7132B751720464BC97DE5BD08EE4170E7F5
+036BEEF0824340EAB34A358635B8279825717994AE76928D15502BBAC200294388F53B1B
+C01EDEBC38390B986B27E68AEF3C05883E851BF71A6EC8A3DA59A3767D40005DD98704CB
+EE22059B92062B96273D77BA9BCDC6D856102AC322CED73033E6E86DE0CF2B015570C46F
+9BB93DD4979472A4BB5DF56ACA2F9636B6A11253421FA471BB93A5561874B43C99BC2EDF
+333511242334B62A0BD58E9161260561B9CB3CED25518A3CF7691ABFA61980BD4E5B6FA0
+7ABB135421400F7086EB0C4FF44E220A7FE7D92A159BFC63E4D01700E719D56BB6F440E4
+142852FFBE5ECC6B6A1A66D20C7F07A5AE5909685A3A71922C7AB0D1C18A27BB6E6044CB
+B8D2C5A86785378EF5CC4167479142722523E12132F03E5D408F69CDAAFA5C55FB6E8AF5
+8EFB0D41B8448A2E30C66C99B5524AF66BC0F8C5BDEF2B8F0877C5E316ADE6BF0FC19DDA
+AF9F915CF3119AED62D21C33DCE3F7EFAFF5A7B0CDC005CE387D4B16C6030F751DF94863
+99BC7E769FAF52EAD494C8154AF2CA80A6982C7F5B2206D9D4B39B6E61956ADFC144723F
+99BA540F0C9D1DE18921A04A3206DECFF8D04C727FC9E88DEA9C056E2179B22AD2607017
+9A901B66146D0951DDFD1B9E384EB181D7945A4F83F2A06EB41A2459903FB0AC43CBCA77
+1F62A2E9727007042980C7FF98F349CE0CDCFF6F3447C3AF2712CA82D6828DB71C48A1EE
+E331572A4591BD9D3FA077E2F29D0DCF9C68CFE2B6A71FBAFB0E02C241582E09E3C848B2
+CB8AB75D633C42598FA07F85D5EC3F577079CF2F0E68162E66D83176EF3B23291D741AA5
+77D747220835A8B966049F3AA22CFC0D6B1F55EBB917EF80B50487FF81BA7ADDB90CC430
+CAD43AD6199CF4CDE68193659F7E4860F259EB99B56C0E62390597DE3E05983AD165982B
+E8305FF7E77363A9CE624FBC98626C21F6723F61352E036656B96277E783D4E6BD0EDF58
+5611C8D7BB3132B9E7C21B65B6EC5E3BF908677F6A5C5DD76BB16CDE31232CF2DD3F437B
+BCBA6901A99D9692EF82FF0F8CDF49DAB5A947DC27007F604C3D2CA84455F9F30A75BA00
+71B9C36D21B4080D1C9CD31712527B8A6B5D6C39C29690E92E036D49E186D640E2F45673
+789BE4F96524657EC01BBF37F792212AC8688FCB572D26D10ECB727A316DD79CAD673E6D
+2897D77D5EA7723E541C0BD23F4CD3DC2A5B9E2EFA15A024E825CDCC81CCB5B588CE4B18
+1D6E90D3EC7CCD947D371B98CC18A30C33E90EB7A5C180A6D500758CADE6787D5E89779A
+067C2DEC491D78466EFC113586C71C5B7E2697685BF5AF1C6806BD2FD63DD7A5202F3C50
+93EC7D2C129E0C3A8CC8950CCB2901894B1233AB3F71CA25E34BED65930899A695EBBC51
+2F28FE435C99ACDB6CFBF1836CFC762BA9FEF40EC118CA6B8ED46BBF94082D4CB52FA712
+397BC0C630D77283AF633364F319FBCCDF6756304CB60B8A14AC86F62AC180AADBCAC4E0
+077C3299BD7486A05378F35430E5E1FB84A01A7C4A0B48DCD72BA02699B8087B5858C7FD
+A52A85F08BD02409CE14EF70619E0D344612BA9971C830A0FA719F6EA5F3ADDB460C1430
+4A987565651FC9D13B307E48B7BDD9EC6CE1459E6062C2267D20D5D17992A4B84027B410
+36DDBAA9670152215FA62B5054356BDFFFA7F623EDDFE2BB20A935AED52A2EC844973BB6
+BEB38FBD1D4B21B9D802569D6255049FD9175DAFB66E7FB6E30170D872BDD64BAA1B16FE
+81AC65EE9053D339A0C009DC5364D958ABF3E87D38A4E9ADCE9037BF4FC62E8D3D1812EA
+8028CCA0852526736660713DA8E3B4C0CF2940659E8BB23F3B553D4FCD40EDE971697C27
+E41F2A6C0C29139B2209D091003326D69A2F081AC4B7F61BE46AC6662574D463DB86338F
+40BC2640EF0CAC42C1DEE896C41DC6DC5A86B1A0E5CED10D826660947B11AA1E9AA44692
+E63082D4527C7CF7ABCD388E7ADC0C1EA3E4845469B19505F5E5FD66B65C50F9AB02BBAA
+73B8EAB789D7F226365500A2E9ECD9A220BE7BE3D04635E9C95CC1196749F6B07151AD92
+12ECA4122683808000AD54E24730571C9BACE4A563029DB9B921CFD536954CE064DA5D1B
+B49D74C55D08B1753124965A402A52188F44A14D9C28449C665266E999D7605E719175C7
+6070B3A4A28B6ED3513322386B2B65689A4B65788A6BD0A869468B4F3544C6E6E6ECE246
+506B988CC39625ED5148E0F620482A198DFD8CDDECC485F003B7A752B1B46B00DE60FE76
+D86911A37A0C26EE72968C5783CDB1744192EFD434CE8BF0B1C45DCF7226F120E85C800D
+0C97EFC7159B9CC14EE505042F371750E32F98485337BB26D4BB702BEDA217CAF9F0863D
+733B2406270DA91A556BEA4D620A8155258DB0DC3C11EBCE82561957B2AC8204DDA993E7
+58CCEFA6989442B696635B7D29AAAE8E14396E72F838E305E79F25B5AD19D4310A368419
+E3F773930F2D6BAF2C8DAC2F2C7F3420594BD9E1AC2D6CD7A185F7F673984ED76D18B836
+388084525C12BAB5BFA4844121E86E4C747B283ACA5C61E672679AE73940CB44ACB61CD7
+18DC458AA1CFB314A0769445D0D06EBA26549A4EE1AF27005D27ADDADE65EF1FC6EE7BDC
+CFA6881D20F2B22972FC4357BF445008069FC6AE550B2D9BA16D565667364E1800167E33
+0A36ED921DDF850A3F993F0B00B1C378004CB008A631D30FD498D676AC38783DE7103FE4
+F314BA9168C19B0FC49363EE43704A9A119B360B5203EDAA03E7DEE736D7E6E94CB80CA6
+42C856E2AF8D68315141E7E9E9F63B48A9F3AEE965F0B62483F3C5AF47CF61DC4EEDBAA9
+F70846E660A7FED078BD46445CE45ED58C63AC224AAC16885D3F4E3F94F0779E180693E8
+B4A15469CEB06D6ADBC5DEFD221406A8C48B95A72303F54DA54B745B504DFC5F522CE50A
+EDC0D27842FDE517791D8389ABF07F352EA4A752D4DB20B50CDEF5CEF9C6C8EF510FEE9B
+F1737412D9CDE528A66B37A4BB9272BF9C8292BAC9EC2F66E730C3D038E981638C503993
+FF43DDA2C59AD94337CA7B45FE8C270334D4B330682344E372B08A09BF9AFCA47B68656C
+1428369C660EFF4392C79DA407B29373D09D4EA1157A8A8D1D81D38034DE3E7272DB3525
+4547B81EA3B0E2C89E60992C4E95D17968EEFA64BF116B4A9A2C0C0B242DF6A571CCBBB7
+6A58E80D84D48D18C5B2F75CA84A7B7AACAEB5548F2A13D95C8918C4EA6C8087F866DF76
+46538BDCF0B13A918A64E00AEDC53F222D8BA4AA75D90121FC69AA03E8B07E1FD92A67B5
+02B9BC301225181043E987D5930FC2E3C77553BE300959CD767FF441D019828837680A8D
+DBAE996F1B3739EEBCA8CAE9AEDCE3E3784EDDCFA86EC38BD460F979CFF0347BBBD36DEA
+F8DB645DC277536BF8F1BA745EB4A2127CA7B71253C6539A31299156F12E07E5C9591C45
+0C0E804503F8F4520C9FA55A490F6C827004FE2413123851B780FF78743B72C9E1499B81
+77773A6788D1101D8551E12C46BFAAC185F7B6C9916796B3A351DBACF4A69A515EA1F765
+67B5A62DD9D6FBDC9574F8CC8DD20EC6AF803477B8C78497EA757DB04EEDB5F3522B1CF2
+E4EDCF923B14A6E4AAC3413D841EB5ECBA4116CE6549E55BDCA1DA667AE75F9626998ECB
+5D82C4D207BF45C16A728847E952E8200194A04288336F8FC2AAD5FEDD5D17287B77882C
+42E5F956B9DEEFD55ECDD8354C0CA47BC0164B2294C4B2DED139084B4C1213B74CF02E17
+C4B43FFC034A2051CFAE1CF99D72492C567A750C704AB26AEEAD7A06D3D98616FDB0C0E3
+34D99387EBB43874FC89A225720BDFE02090EFFF13CAA7EAD31827B6DE1E98E450DAADD1
+515D7A65B28AF7057C7B26720025A8918D1A6810F2147D64230FF7925FB42A7AE373C210
+5C99311C02EA1B33361D538B7742BC02B68E238BB4B62A4785B27F071D3F1AF43BEDEE81
+F7717E213F352B861562C314EA8E03B8EDF986E488A1664547CFE7A59DB4B657FAFD0DAE
+15ED435D89355108E44135142B60C2FFBEDF32F28DF01F02F2DE4C3C40E95CB0D8D64E23
+672A423743DDBDD3AED5E910E634C9BAA69C8F6B33C8D0DEBF5FA56D7E6D51E7EC3A8DE7
+14DA3A104DDF5FBF10EEFDF85520ED2B71F11EB46ED74F70BA58146EF447CF88E92D99BF
+681D3DC3DB4AD32D0915FD7C458D3AE35A060C59FD3A8B0B7E99A3A7F8978CBF381A6235
+D7534A4D11472936DBFDCD33844B8E36205089FABA95BDADBB0B55F9C8814E5F283413A7
+08CC3D15F487E170DD7DFE8C471FE85C06383D444F65298EBA6FC3761D7F8D6F18916A16
+EA794043EFFCB72B5837672E8999904EEA79EBE0D3464CB48E9AEDCDDD2FD9CF7C111C57
+2C280A48DC5B83052ABEF370DC98EDB610EA5E43C5A9A8BBFCF10917003E4E25943534A0
+E4D281F2CF61C6E7C0C10AAEBF23B7CAB563CE25555B82462A71A2D0C511390117AFC3D9
+3C948C1F37F052C17EC23E87B3B43B4E874A723DBD01DC97602F498A1993D8E6A5AF7426
+9E487DF83C45F7F9DE891963DDC7099951AD3E59AC9E5586AFB026A66E6FF8B3A9DDBC51
+79E697BA2B46BC285AD67722E8087F813B774AA31E66BBD187AD9876315619C33138DA8D
+834BC729A8948E617CD7A4B802D0F7FB484807D09CD337097462B9690533562506B7DC80
+7CE404B4A1C2899535B13540A75DD666E1ED18CF75D95A3FEB472B7A596A007455682108
+01948D18DF7E008D8086552D5F472341BEC1A3E2856B445C0099339B9FE2ACDCBFF172FC
+5BFA8A63067E9EAF13AC8D6F0FEAB24FF4E326A252BAE6F48175927E7D45F2A84CCC0AAA
+1400A922DFBB601E2129A649464C417901D7EE4B66B91A6DF5B787F9B6B758E2DDF58724
+37F4658116E04EFACCADA54863E874F314AC25C4D10858A2EAF9687A4C45AAFB755251B0
+E2A298855AA83D44F254C832073A4E065694BF538C63CCC8CB0C3AE89663E24906614A15
+2DB4E4EC5FCB83A229285C1CE0B52954FB21A166142D8F82B60997DD39ABEDB4D3A8680B
+8BED2755297909B1D66724FF4B556FE99D26C655F7BF055A529562F4B1DFD7A16166CF1F
+75606228E96A320CAD4C2589BC86C4940FE50CDFE12BD5EB50A5A2B0223A6358FE07FCD6
+C791193E83A8B66766BA2F2E3D15E3275C27ADF65E2088D058082ACD6B7AA272B26967F1
+7606DA71E7CA51EBF5662FB025419DC26D155113947B966933287A14F066AC40D7028A08
+07130DA33A7DFA24144A05BFFB1D979252E83F21A493F7149C33D7508523CD56C09F3963
+322C64BC63B8CCCD8FE84E0DB44917107B6567579983BE44F73C9E524F44956C93D85975
+E4531A3DC0FA9CDB9916DA0432E4EF9C48FC9FC482BC9744F6D818889C4B5D0B766D2243
+B50B9EA3F0D20DE6A86F7D0C0F4B58E3B526C2DD36E01BCBC6EB8364B15909C335D8FCA4
+7845F72F203AE4FE8F9D0FD1F1364DEBF7EF7CB08D6BFA764A7E79B9D76A412D879D2709
+0F4D54A848C5EFD424C553A5CE0486D29AC6F2C6B372DFE8DF265097F184F2B88CB3C690
+052719F268460D78153B97D77F824C82B466DAFF2630CB263115406B8B91C9FE8E9AE54C
+A2C96C85789610964525453B9D902ACFE6EB379887C72B472189B9E7CD6033F2E57E9C90
+206E218B9834ED77760A12FA0A5A6F86D2C226E1DDA31A5CF2D0EFBC4AA20242D662A869
+CC6A8C5E4B3732A9985A2BC6DEF9A1FE49309CF5557695B66955CBC49938FF605AB6F57D
+CC7D570CC84A8F10C50D2DEC2BF6746CA9F256725BA75D273325E24D04AAF0F2DD9AA3F5
+F282773B5CB4B5DB26ABE691245BE7A3FF07C4AF6817725B03419F1B72068A5EA81870C9
+93E040F4BC52C454FD43AC24E3A7B909582F2AB3584FA66031EABC8CEEDB7DE30D3FA311
+A41DAC1CC909AEA330FCFA89BEF8D0D5217172BE25BCB3DC180DAAC52B9A95E588ABEE17
+105E3DA435AD2698CF07035DD5C19C8DCD58480CCD20C1FF529D37B5BF95716DD5B36F74
+B58FE28847962E7C3E2ADD93C91B529C48233EADBC2668AF421CEAFC5D8C65DFCB6493E0
+5A86E7A5CDAC1CB839DF0E099E67A2F8A7CB966BE497C573A5506AB4944AF2FD770F5834
+ED14B897BBAD1F3218007AB429C3250F7EB284AA16149DE1E6B6B540B5AEC33C4BE0A12A
+11C3D63B8574C6B2B4155629FC9C13EFADB572BF35C2939226A90310A067B4F47A8719B6
+63035EC0FA87AB6FE5515F1B1419C12F06BF3D49393481B7F45534B71FED5E1B8F8B6480
+28AED0652F5C7FC254C25858EDCC0B92C6E6145A8DECF4CC54C822A6EA80F62122A58FD3
+1BFC6FBD5DE46F258D4215FC361C0B8BA50E3D63E7423EBD6EBDEF07696D25A6FB25F44A
+5D747225006F4AEEE6EC177CEAC8DDB0A7D9F536BC69B59A5AC650AF57F92798785D44E5
+79EE905CB999C568B7DB553BD63184F22E59FFBE661535B35770A1EFB0F6530B455DFC54
+1A4CA7E19136D9F3ED1A7C8F58752296CF5232C45902E6129AF4380E677A74D06E2A3A01
+9C72A32A8555E52F5113112FBC4A2A42BCE68F7F5484D650CD206B0787C1875E7BF15183
+3FCE25FFA474F67497605D6C6517BFF948E873E4AC2BDB6995045E489D6310C22F6B4582
+906FB0A5484C4BBCE8FA61D80E4277EF0D37D09B869C0A174B97BB3E127776A0FFA4D941
+B0BC194C78F189369E13D86645749416506452668810DFB0B4011A40E60CBF7CFA855CA0
+F36C517B959FD11587B9C6C6EDA0FA01FEBDA786B36F3E21948F878D6DCAFA94E10509FF
+5F8DDF25EEE7CB8E058F0BE6FB4DA87C28F225763AEB26BA7BFD8A52467F096A759F4379
+C150E63BBE70940EBD573424ED3559B16F83D22068E16633D95A0267E18EF9391B9199B5
+80A91B7A74BBF60CF13E4EF71AD3FFF9ED5604D73BD0C5A15812A439A3FE6641F2DE8B52
+EF0BC70B7693FEA9CA49F93525D29B037AA40A33FC2199C3F29139FA63408048F29B7F3C
+6EB0CCEAF6C51D4AD842A315257AEFFEE6D5A02C9A56A144B0AB2837402ECDFE10B85F84
+88A87D9512E0FDA5CA64AB541E1BE99C9B89EFE7D3F17874F7593FDFBDE867653562CFA9
+C06BC81560883D1F051CFB128310229768A77E87DAD9A45810446E4E116341AAA3D4B332
+68322B7DC8984E41EAA6826393C2319424202AFF4928CEFDC24D7EFF4B64533FBC25164C
+E0083FC7DBF81E663C4E1746A7A7E4D7C0EC4CB4D9FD396508D6A96CD400C85212F522CA
+F4F6290CC2843E2B632571FAE0ADFD99A7E3F9831B0EE07340BF0C7D6EDF95DEDAD7D492
+DCD83D871ECE63ADC0A50C3E76E5157D3872E0F78E036B3A36459E78484C9307B3DCB831
+A99D9411C1CF4EAE117D651BE3BC04C2AB067E512F0F89A566F275DBBEB231DB42A0A197
+C301F33F4E65EFDDAEF015999BBC1FB75E1F6A7925D3E2075E98E314BCC10C94877F0B0A
+007708984B326817A532F7AAE87E026AA715FE64373BBEBAE99A0F83CD0C77173DB845C1
+028F25015FC3DA0488676715D3EC8D1149A90AE16F418218404CC465D4EE8BEDEEE36F47
+DFDC27D07FB5F4EC0BB8DB4601DCFD54A2BE85A9476000D20181311F5B6F4111CFE1A850
+DAC7C23D30B674627F1A852FAC1F0437D18E6B3CE4FC7911FE7255390E0739D2A83DEAC7
+02185389034889A8A437BF74BFC3A5BA6BB8735A8FEC009D55492F7D43C5C6F92E469260
+4723A88723FD31B20AFBD42C150EE51108B05E8F7027ED40735A1D63931FD3CD5833FA1E
+C77980CFA0F7A8C47164639255AD00AEC0764BAEB2045025B7C6536309CC9A38291A1F6C
+141D1A42F33BAF14C5844C13E8AFF8A7CB4AEC72E6039A60CC67F03DB21AAF2976BDA0A3
+9D92A848D743DAAA36C288ECBDFB46D53E958762B1FD0F570F40154838506B656A081473
+18FF01FFBE5D17C131949F5489E4C74EED3369A496D05E0C9256EE92D3424E95A30485F9
+A00B0595FDBF84B03BC9672A4816D2D290AD1DF00E54C668DFE765D9EC28815477D7FB69
+781C0A050660946AB8AB1E29EE5ECB2C1A272591CC48EDBB5EBF26D765E24F5CF4BF43ED
+17E5BBB55C55DAF106C46E4D8241E4AA01AF7CCF79176FB4BEE78D5299C313E2DC300237
+D1E149743E16081CF124BBCD7D9325125C9C9AAD57E86A94D18CF62D4E0785F820A9B7F9
+E3AE3FAF0F7DB0262BE9BA917540B8CD3421643A01CB26F81555B05DA466F1136A7F3E80
+3461C2F063ABF750BC814579689D3CAA094035CA96298F7F264C6546143DA15C6E085DB5
+2065E8ECACDEB3ED4FC0D1AA4B01E3ED36211DE438DD1B3712EC858D66BD3779C96D4994
+234A8FD8C1340CA9EA51A2750A6B0C65EE1C54C321F4D060F7F5F07B49C9528AE0A1D45B
+5549FD72B0A15BF903B1F70B92458817DB0FD9F1731E82885835A717B0A1304BC067338B
+1638D51E99D5C23872D4CE5097B89635C3BF28D6D2FC96BBD80C26BEA1968B8A59C278A9
+8BA49B1E59E3584E54DA5998C5E70AF167DAE2710F7656169647D2781AD1C27766703FC9
+6C08A0739EC521182A77410F2E2A788B47C745B4B0A2313F49AC8802EA461F04F3D54FE5
+58D2B21E9348C19FF519939154AA3ED07E24D3C15971F380551408C897D618749CB38BAF
+625434B73061407AC05E0D7B0885791153FC0AD5C3275C03F528FCEA3BE91D9CA9C3B402
+3C931D467854D68DDBC0FBAF70D38365C0C76344472A876E74C04CEA12DAB0A55E776BAB
+CAEEFE1CB7E834BEE48DBC155599C4A0BC00E6B8746D7D0B9CDBABC463D8E2688F46F126
+520ACADDFAE65101EDA0F523C6B9503D8FD1A5B9F0B6DBF0C286358D92FDE66720F5AF47
+CA87A0B6E04E46BFBF21EBD5CDEA194B6425B5ECF81518178E0259E386F5F852C6870E7E
+034582EC658F59C2E07428737B36B77B9AD3BD6D28EB1742453C5D4867FE879805A80331
+C6E52C0557E5D036DB1EE67E7274AF769DEBEB23121AD503E3023A8515FD5ADEA11AA020
+2BCFE0AE826A09874CCE19AD2A2A188C7331127751342E542258D3996DABBA1B6DF80323
+5B6A223DE4F193B862224F807F99C0749994F0C72CC784AF11C411D34D649FDA1C77CB0D
+BE519001F9E757BD8035A0C9AEA86609B71A4622D5C78589502CD2DD58709544A76526F1
+603F205AACDCB62EEF46D9042A2C9E76B887826827C6F22D73760CDCDD0FBEB827BD2E1C
+3B5B0726A08DD2AEB614FFFD02C36F9E8B404160C909B70414BC8DE600A5D56479B83015
+9B8E61AADC8C8AA077816ECB6317A9B16D30DD8D4499FFAEE87CE97F72453A37D187D91F
+A0C29A65A8F9C88ED22CF19CC0B40324449CA4E7751D77A0D76669AD420216EBDA92CFFC
+50454E7EDDC5C4DAF66B67675B576ED2C90EDD9F8182589ACEF1B034D2F848D0CBFAF84E
+38B7C42D2670D0A5E382FA11AD3F2FD6BC79EA02C074644F35842D1DAEF70507A361A0DA
+03F5517B789C5684461F698F2FB20A7801CA9EE12981B5A793A481F48E33B596832AE4EB
+7AF3681CC464F6895127CF10D14477611CF8AA88D0F6888225DBE342A708BD62EED4FF31
+CCC1ADB38DAB151C94E9A1554980B3C077683DCC0513ED4C55D57BBBA0ADB8A5E79A1B4A
+BE43C703948452C44F1734F1C433797315C644A8E76D13DDF5E0296143F61FAD14E16ADE
+97BC12ACC5DDEE482231A9E9145E69D63CFE889A1BEE0907362C60ABF581EA8541E36ECB
+30457098E7DA18D6FFD57901AEB7913C59AF691D1A1FD3DF485F7EE669A5915EABA6456F
+955F2D2F7D56CE0E349EA743B3F44ED555AAEB7F2A71711E08FB67B9738928AB842F6111
+2B9126C7474753CFB458EBF75D817175179B3FA956F1D998C52FC9CEC7217440889D0481
+CB91C8A8D1D1C6967964C7DCE3D9EB0BE6598DA5708DBDEE4EDF76CE91E128732A8CF56E
+C8BA08828E9B270A818F98FABCA757BF3C3855C6DB448F7A4A6853522F7541D46AF3818D
+B905D64847078757E0110C0BE6AF4BFF722FBAF5D8A4138BFFF94C7678A10F9FD850998D
+B710D5BBF763B8A70491CA4D53124CB95A953B080CC31174646AD474BBF5BDF057A1186D
+B083E6E762C669E935A02D60EC62FB71B6990D25BE44E949C85D1582611D826197E8F617
+CF2FC506489E59CB380E2ECA368916347B1E1B59DC1AC765676B904A63D7F8CCB1F7E2B9
+B8290B30E53B28F6FBF55D191BFBCB51F3BDDA71C7A9B1152F686191B0AD05FEDD3FC37D
+42AFD7B3021D255DB7A00E6C2B3E714BAF7E61BFE8B7A88BD5B6EDE4C1DCADCC30565AFA
+1E2458F35E44CB6F7228BA384CC1B7A64CE912998D42572F45A30B2C4F919BB21F66E1AE
+6C787773E419E1AC1AD41A3DDC044C1BEC45CA2D0382A11C1543683F9DE1302FEB0C9DF1
+8BF8B9F0272132E1CFEB54E38A8B90C3F5630A3EF083C73C4E83BF0C312F09D5352F41CA
+7C8EBF842E7F46F3D97C4AB03040640B95D465D50789EFD68A12F1A450AF35844A7A2302
+3F25728A85EEA2D9D124C4B04AFA44205E110CF923A4D713552FFAEDAECFED8898AFF89D
+BB682A961D1F815C3F978B9C190006959D4330D772C884F6B0C77B2D1FF722DD86448C76
+A68AF642A08994966D3C2836D7063A59B168AABF47179CDD6D6F902C601A89FEF38E5A69
+9753828649B3470B5A03A2B58AA910B758ADCD5739611894DAE786D5AA005A5826DBFE38
+8B0F4105BC76C0437FEE9CA6C861FFB1EEF6620B7562B44AA0D29D1DBFE7B7954971087F
+E8D291A0DB5E4CB0512B104EA6044CB75C099716AABCB5EC89B14BD18F5D1A73E9A8DF5C
+A593BDA22FA28D8837519C38432667684C7C23594AEA6B39E3A819B72A00652C205B02B6
+F8127CA0C7381B8D433B86E6DDAE2ED9482345792276F4604A9208AD8CABAE8B0A0BD0D2
+7D0D5955C20C6E4425E295F5AF9FCA7DF682FBDD5B8B107B5FDBCBB0D751B2D2BDA99314
+A9CC66F9E92FF5048E5A6AE2B8B03611C7000B0903491DA44123CCBBC67B1D4086C22ACD
+08599534BC98EDEE0A73117ED20679CF3D9ED1506774C67526D9AF3DEC36B9FF799479DC
+52A70429F79C8878509E8DFB756BDA3D76B31B9BBD77DAD3956B1D951C157F02EDF252E8
+D02AD799A9DED7B38B352FD0841B96DAB3A3562F68178448DD8F1F5FE40438933F97530D
+0E6C918C571B921F9F7B054B798CA04426237F4085044F7395D0E4FE3CAB961348D11912
+E5FC311138A82F470FF3C8DF00B1B0563BE81C25AB58E95CC392203F9668BF187DF43482
+BCEA0456394E31DA0819AB3E71FB8E02FDD90E05A39D0D5B4EF919E958B862C3A96A1275
+F66C689964B85C4C60A9E6D44EC9900B85245C8CAC2847882497A97043255228B8C29529
+12EA890FF254BD8C584126DAD1B2AC1AACF528564883F0C15C41A8749EE4AEF5FB514940
+060D3397DDAB08DB2113F942B03375B4A2AAAF9501734C17DC220BC97E367C2160982356
+2ED3C739164B659C480317952AFF044A4550DF79113B4F7FDBEC7B332EDFCAB7DA5B4AA1
+469479B4490EA5462191AD1B336DB782BF7A2CBFD7D4B885E2083110511FDE57459457D6
+68D29B1E31E734B30E4EE6AC28E8D74A2DEDD48BA964776BECDED8A86934A88D60A85279
+9E9C65EE342F2555ACCC0E47202CE451274D76C6FAA943BDDB5C35855499141FA589F452
+C5F424280D5863C7ED7544701C4B0660AC835D58905E458947DC5C220540D1FEBB4F18BF
+7649596ED3C3F8D76CD146E5B5995F406CDC2F8D1D0D7CD4FD1BFF5907BBA5AD0B475F85
+D4C75829E57476F12E1315742C875008A96A06A76627DD694E1EFC09D05159B101C8613B
+F0FA5E027B1C7F089D07B48BAFB047E4A75B101B417F82FF32BAAB877D7798A2DFA48A40
+85C47A5DA67FF503552D60295D5C61803C2700879C685494886505DB291413B22C7CDD3E
+9C36F74A88E53FD9AE6E4AD73025C80555094DD7D1A171A1F85833A390793DCC86DC25B3
+1BF605ED87669F1D4D44FE035636746A80865E4320BAB50B42B6A6037B1A7134AA8B42F6
+4A85B58C318E600D80E892B337786190C009CDA82D95786A6F723408E1F79C330221E753
+F1A30D90450D9FCE6539A7E4B2AD69557746FDE8E4E6207FDC9068C400244A0CBF276F84
+A2286A98A9B4A60457D3C1C2B1FFBEBBA67DA76E0B3D1027B914755CA8152E1CA4542714
+9F709EE182D12B9D653D960F7242567EFE61643037028C97B19D96BE9F5EDA4230A329B2
+78CA496D0C8894CF6FF8A410AA93EBD0F54CDA812CB5935DAC06DC7968F1FD4DA26B621B
+CB0C9FDD45A51E5043E501E17A042CC421E80413C5861941796E1F0213C02A968CB5CF10
+EEA25AA24095839B12D6C260D99B5C42B65C40824D408464B30D6F9E02E8686294CEA8A9
+39AF573CFFCAE51DFCF51D229D3753F144CBB1ACFE9253F5E36CB4199CB5768E6E1CE224
+396923C6E1C9B1ACDAD64CE0DF19C102CCBE2F7D206EEE22350016B1DFD13EC06891C41A
+353318C8744A912692209F590799C99741F3656DE0110C310E8F460C3B94C7F5EC4598D3
+786D7C297707C6CA9CD9AA80A18141C9937EA927FFD3586CA76ECA5E5335DF22CB4AFBC1
+8DAAA401CA2CB71E1E97BAA78CA4D1AB912028138B9901EEAA6E17263C540958263A509C
+1E3C266138BC36DFB2B82E145C794AF0606D7B9724E40BD70E3B83D7B32E32E0BE470279
+C05473C3649009D96F47300ED3668B9F140E65746CEE1DEEE623734F93E1C309B3F5E5BA
+EFA93C4E96DDB8E14DB661CC2D23995A845F8916079EB740DF80158A8740C15DE4B367F8
+85B1755C69254BEB14DBDEDA5279C0A4BD93D43B940AC1AB933C20EC96B8B833DAB56BD9
+15C46666D22E72B629E97EB44CD41B441F6E079E40FA868F3D74CE320D23402BED7C4A49
+4468869683DD4BF0C4B59BECAD9706D091FF749B749DFCCADAAA2907457760A7A2269285
+F31D4D815E0AF703CF9A0D671F4637881245B134D4E25A8DFB7E58F7DD06912E6FB27CB4
+1B137208E30C0BF65FC3C078E9AD98BA6A46E3D29F035FB6A430964B84D9CE91A03F6719
+614D8F12760A8EEA1999780E00AD8FEE24095D7FEF3BD669042F0D03010814916A66401A
+3183CC41D8EA4423A97EFD187FC1D832146031D4837294C35EE6E1E0E8ABE8F68CEFB5D5
+97C10241B7D8D83F281221F1B84FBA400A586364C58E1B611CE0E2092E0734FA0EA881F4
+2A8E82E9B02C0A5BBB21940EB06554D01940FE87BD2BC7D03032646D583028436B495E6C
+A8F58566A946BD076D693177F13DF96B3A43C1650085A23D199A4773C717DE2A19BD8C46
+C0D6487698620D89A1A07FA0205D14870AA43C6ABFA2599A84AB5CDD18A66F6540320B28
+A1A9904402F62213DD74DEF28E2260842BA1F5ECC26C2450352EC67BC2C956C325B1F996
+4051364A7592346F0C28DD2C52BA5123691B47B857284B4862961504778C8B5E06ABD1C6
+F37E2343C185BCB458D42DA166D9479F8E529BFAB0AC782010BE8E526F5E4C17BF9A6BDA
+F8BD46522BB6A877C54ECCE890C389FCC576B605B65C7D17A483FDA2C826A6E8F27915FC
+9E006666AD30D11B31AEF6DD8BB9FCEFB655F4D7DB73767FE1FACFE15CEF7FB27C3ACFE3
+4E761F9BACEDC1CDEC22B0F50619FF7AED2689F2EE768CB0BAFB857680B15D9CE8AB0A24
+36450529F86FE3A7CCCCFF0287092F18AD672F424DB6EDFD50AE8EDD481022EA1FFD016E
+E3B4BC8583BCFB45436471B5B4340892F390E061E0F28B4019812B0CC299C3D70151F87F
+15018D49097A50B1EB5B90A736ECBD060A802A30632C2A681FF14E1ED5AC77726CC1B76D
+378180CBEC15DEBD4CA283F2441B1E02CF8CC7D91A212EF2E0B1F194C196D731EF43A420
+2E0A1BAE1C3C1F060688BCEC9C24B07984F8EC84242EF6660E7966DAED4AD845FC859DB0
+71F1EA8C7E9E5235058EC9C42ABB815C699A883344E95504F9C5F6BF340DF54AB9BDD438
+B8D63DEA04CBBCE565E3D78B71C6E2C04D4E1EA83DDB824C8AE8E9CC621CC1C75906F900
+D2152DF36AE9390162C3DDDD20E79F9402FFF7A1D66377037D2A5E8F9E0889F55C711DB6
+38AFACC568A1B4E4EA06E3A3B749DF4026A0EFD2AD56BD458D9A5837F046F81ADB9C1872
+71238A54CDB3290187DB1504008362EFBB553C0167B5B58DDD5DD0788B4806D02AFDACB7
+78DC36578DB5486BFF8FA27ED2705587C3B0A471DC74A47479EF2B7F0D35A77D9683CCCA
+F64C5E79F57F96DA3EE6666053089561CC89A0AD22E9DDD5AAE38F6ABDA3476E5BF7EA15
+B4D782E42F6B1E778C9CD33436D1B2B72FE8B01E18E01C6558816D0ADE36FDF34B8D8F2A
+A15E028CE59BD9DE568683CFCB8ED3CFA289CDF4525A46BB7B0A91A62491A09821633CE5
+C54994009761A3E6DD30D61612EF66F49E190A2EF1D189D75C9EAEF9CD21E505F9CF63B9
+5B399B25C2808CED1FC3F6BCD950156394711567792045A8C90A10A193650379B5F44F80
+B9D3C265064754B0390963D2A060AAD443CF6C377C6DD81E4B313D94CD22DE546C56CE4F
+06FFB5C4D703D1CEB9E9957ACDA546D0B327450F212252B3686FA87442CA18B2B0D2C1E0
+F91CCD54AD769C78D4E719BBC32554B6F486ACC1EFF4C8A3DEC5C359821715C2B64C2CD8
+43D25F4899375AD2011C3A89914CBEA23970C20ABFC55AC3318BB03FE1B061CC5E1C6BCF
+B4E5A9488F08845DC4B03A79CCD15CA393BFF66051555DA32B68BE66DB340662F445782E
+EEBEE5CFDB73AE4F9864435B828D168F17B59E9ED6B1E4DBBEBED2075911DFEECF1D97F2
+C57D0D5EB64FCDF7BD4F2F390F0182C997AEA6B3D5C5AB9CA14A3928F6358CCE901D205A
+ED5C22BC9838128C8631B69B02787A956865F15EBDB937DFBEBAC70381767AA7EF592146
+BE4EC825A96C8695E9DF2490962D6A9F877E260A19362995C03E00B44DAE22F3E1AFFECC
+ECF056319ABDD8009FE30466EAD5BFF178E43BEE8445C0F3A4CFADC000CB29A66736B803
+46E6BBA25CB8EDADED812DE0D7962C2C05A0DAFFE6AE2604F628F823659537651DEE00FF
+795ABFB6C2FAA5E2531A36DD12AA069E8E0EAD1C6737FAA3B412F97E6D5DAB28460AB7E8
+160E0656C551452575ED47630A545FDFBB6763F61CC4BE7BD81AFD6861AEF0B34044B583
+836311C2BD2F0A5C74A455962A1991DC75DFF5BD46265C8805FCABE04238795013F09F40
+D2F2F7C5D12F251752D938DC7C9BE00E5F7506E51E0EC4A7AED0FFBE5353DD0A6FC560E8
+3FEEEEAF01316D5386633AE96A5609FBA122684608F90C54E9E3C1700ACD31686FAF7BA4
+84AE837057BB3FBEB1B6C9AEE7412A74C5EC366F682BAE51CA425FB274D17C41D0DA1632
+751E2D58CB0837549DD2296065176FEE15365363284E0F4778575C464110F5CFB186E92C
+B488958079B3DDF229F4448C19B24023C1EE9F226EED46316480F01DAE2D4A5EA42A3DB3
+85E3668A3CDFDAAB384BD79DF85A103A8E09561B4E826D3079658295512DDCDB7AC7ED56
+0966855109359E217E44805FB55FCC926CBBD27D34D5D1339D9306CEB6BF3468616AF144
+765C64DBCFA2BE91F92AD7DB47DC92CCB3297AA99593851BBD29C07E7011584945C5F390
+E048B582367C97BEDC1B31BBB1D2D8C038C05DD28E3915D6E35ECA809B335190DAB354AD
+3D3EF2A5E3FFC5D8F0F7A87A8EE9C6F9E07154919054DCE87D8FFE62E279CC05A4DA0BD8
+B933A49F7FEFD11E241DC1E4786B73D15FABD2915541B9019AF06EA28A1DB0FC3ADDE1B8
+A370187BC285F66D544A23184D17E346CDD21C0B1ADAD499D78EE0258279A8FBB802EB50
+887CE8290DE6F29AB3F6D0884BF63AC982A21682CCA88BBA82A237F39AC8D1EC827CBB72
+559AF2F5E640B1E43AF7448258469187427A600608E5FFCFB50D3406D453D30B830D0B44
+B7BBDBF0A5F00A33A4BA6429C9D3460BD6DCA861970E123E67CDC85ED1A304FCD0C18B1B
+19CA443F0B85423F4EA44E0A31DCD363CF59630319D2ABA44E822902062C4194D1B4A04D
+DF98F54946C5769EDEA86028E88DADC98D785521AB79728C029FE0515C9BB6DBDCA26033
+1B28F70CE1445AEDCC0E267903013BA6F98A564E6FB70FAD1343200A4E3AFF261381434F
+4C8E3DCC87F1482C99E9E2EFC4A0D7352DAC825045D1CB8E102D9FF018467759C808D863
+55C4D25B3D1097317FDD11BA90BED164B5204A40110751287F19926A82FDC6E8216584CF
+CB1B805BA9237ADA8D5BED21A89F6628495EE78DBBEC0163316E7301AAF1315E00302F64
+D22A33EE587C3116003CFBE41718A07DC7CE295DF8D7CDF05245C46893759E0F2DD35507
+CCA29752106D0CF2DBC8CCF6ABA8826EA7B0455585B26DCBCF0F598A7DBA8FBF04879EE1
+82637DB44C1FD37E7A74481A333CBEFE4B413D8AB6A3F4DFFC471A611CC70C55618499B6
+5EF14ABA68839AB4656971DF193FBC70467BEB52171F3E140FF40BA1C77BF02500842784
+4A06AD4F0ADE586113BB339DDA9FA72FD99DA3B1FCD26D25E79B28069013D8FBF48897D5
+2B92448BECA722F486F3EF5C751FD6DFD0560987137C75E466FF9F2002B7CE576A9282B1
+ED5450AF132C858CC092E7CE3CEBF5C78E3DE84D130CB8E1C9A9D08495FA3918969D06A7
+8D10750170BC3ADBB4628BFFAEDB8F47A2197D95DB975DDE5FEB8FD97AAA479AEEC667A4
+8DC0D8D44C02F7B7497A394944AB7094F3396623AE275B60F32AE74A3ED40FAC1B465F26
+6A8FE9162EA850F4DE855DC492315E3DB9390000F84363328D4891009B8F10AB08F1E4FF
+DFCD0B78719F59B0FEF3F2D7990F388EAFEB85C6F8383D3E50F3317EDD0B44AB566F798F
+F7B1CF7C9CD522350CD1D92E56061D508E66FAB2756999B57075108DC7A0AAB4D77849E1
+00B8B7B5690763983245CE5B96853F7E1E90D5807B02C0E44FB50170AD7AFC8CA8229AD7
+941453154232B97C0CFFB5D710DD5B4AF78146FAEB62DC9E73F72BCD539713B683311ACB
+BFBC5533E9800939175CDC5634FEF7D7BD135D6347EE83118C6FECD86799534165E063CA
+5461B7AB4002D1972C22665FE8F75B4A6E7CD2D868311ACC98E29AED65A9DD734A55E7D9
+43A4F53D0602F79E2EEFD38BA394581DF5895435A9E8FA35DBF89F3F7E00E09EC5858D12
+6D0993DC87BB9331168488F7B12BA780D07450007F067B824CD0D7F0FCD3EF8D5DABA99E
+BFD130AC89B20F0E2BFD4F8256D1B4041F90E3E145DF48A61BBE573394B2E70CF92F274F
+4639A6910E6E6945DA69476BA89E1CE00241213B739E1C9A0A9B352DE885B04A47B10BFA
+4A040533606F2585F78DAC66EA103984E5484A06D583AEE68BD0D8415B0F6CE4505E571F
+3A21899D8CE43837035AECF430D1AB85A8AB0080BB31D421FC1818C32CC591417CBB595A
+7FB281122ACC1742E7A7B6807AE5AF3F98C94B85ABC8FE8482F5CD9F7A0A18DA819D2A8E
+A1841FB1255E3F4DCD1FC2BD3E182A45AFF9E888D7B3D49F4C5272722BF9CFBA654CEE4B
+09C0C9897B4495BB6D38B00F0E4CF7891D61CE6542FD8F84C2590C62C47E967790F812E5
+D0DC81571ED64FB311336B154421EDCE032F253098D7360F2079719047F9A47F2AE63CA8
+DFBF90423BCC6630F75CA70936096BBB9719034946F340464563DCA8ED94EAC3837C497A
+50315ABFF0CEDC6CB3B7B1C30A8442648734645999BA94AB7EAA67798AB5407CB484344B
+86204DBB56D3627091D3709FAAE6CA20AB5733F556C40059E56B42DAF823CD0F5139B240
+7CB44AF4DDC58EB2499525536E01363B4E1A36331838E88C6F0BCF423F70DAA9ED12B5FC
+98C606C301616A1DCE9DAB545FA0ECDD8B967DFD1C1F096D242CB1368A7075BF72E12B91
+A953923276693A46023276B9BCD24108A524C40026E305427EFBA8D9A8C87D1AEEEA0AA9
+F4BD27476FACEB36ACE046FD8A5AFE4123B6944DA5E7BBE7C4F608EB0DA74DF816ED7453
+6DD277F8E59F65AEA8541DA98E492DFD48504D645345E957129E2A60FC5BAB29BFFE74E6
+4D66EF0BEBA0B02A78BDFF4CDA36A04C20AD552AA92BB75D52A78745C7B47F7D399C17FD
+C56C1588083E04035263D46D90144165184F0E630A4FB68874E4C715A3708E84A8C08142
+988557DE1FE684AEA24BED59A1AF602A04F7E916FECB96D2D2149E71642AAFE15B0E399D
+3C66A5944B4B0BA234670AE5D78380041161A606B33BD1B38D9F53A592D3C021F6636731
+6110C7E4DF35E8BB85F649E568ADFF1736A1B27E5B13AFF8C4504230D877FDE932AEFC2F
+F9E0BFC61BFA1541A6F2C6F53A22311DBA8A8067D67EC1A240E27F85FC0D46C4DD2F519D
+7B72897EA5B38704848B4834AE19C7BD5E19E5C65BE109EB9B02CB0376E603B1B6BD18A3
+CF63B906F8BA66BB52B1BCAAFE70BD7A2A184424DC53C91582F47173486998947B074A87
+B49FB5148B6FF3FB34FCCD25CF2940042E7E90EF0E9DA4B520F123CFDABD3B3CD2DD8CA8
+039F6CB5E379D17FF8C3E7F9F597A25201332F0062A0E6A06CA14750DA000B4570B4B3D4
+859038CCA94E63854AD5DF2AEB672F92D99F6E5B03A8A174D64695141A12F8D6E0BAD839
+D104B24B2B02F83B30910AAE4978C9558D256F12A120EFCC8BBC9FE8122DA3BB72C7A77A
+F47200C9C18DC6560B9D3B82AACB581A4F3735B4D2D215CCA7046DFCB3468917E96B6A67
+865B57BD51428A0221225C3A79D3D129B52497ED727331C1924340B127752929C29EEF01
+677C812CC6AEFCBFF1E3D24594D430E0164B6B933EC66A7FD00B4E701657F6766A186BCB
+872F32AB18CEEBD3E14574AA775B3A73B3BA7BE94916FEA42716105E6326C21A59B62AD1
+681A9672934A3EE224B4E634B6B4DA3EF82969768B243092A98BCEAD10097659B9264DC7
+E83CA911201CF43984F4384DDD10F5E7741F78F3013591AE7541965489C0CE0B2C78228E
+2148182930C04ACA997CB303C5C096147E25E0773262E62A8FBB81351EE809D416F63B48
+615E95245EFAE2FE041D10F0755A3FBED883200C13537A1FC5B1CA14BB847C8BA1049B6F
+7CFD9784512E4D2582198F8594B4B689772DAA8EC2AC7969E3B20DAF8A17D36C91F1A5E7
+4FA921F611BFEE1982F590D8BC0613CA86B0338CA0F5FA6107B9CABEE94D143C98DAC455
+F64B2D213C5F3CE2F7430673D5E2224765ED4341D8FD04864F8861369ABE41DB25207682
+C81BFE06C3513FA019456A976CD751B29F4E65C7853DC7E5AA99539926284A316DAAC56F
+64767BC4BEDACCE77C7D8C774F0896034ECF9B9E418203D94B94018D126ED69E431D792B
+89FAD0AD799A0660B1282C226C03EA2E2EAD24432912D2D405A7A5130525AB9A4C6BE1B3
+CCF9094EE61401F04BAE9CDE3CFB0A0A1D33054F993EF6A6A8F1E026E744F19F19F8DD45
+01199F97E79F711C1C219532B448CCEDB409AA0EA129135C1791AF1BE7FECC1C9B1D89E0
+906EC96620278EF044C18228F5CBB67DBB36C7BD10DA5378224949CB6B2EDFAC66404F22
+42AF5508383B90080331ED71451BB59A8A2B91E05365884DDA3A23C9BA8A043C9A5E399E
+5A4350138459B562729D850CAF38D18C4DD8B6F9D8D69402099C0791C82FD8F1937B1F8B
+05E3D4E22DF453D2E8CE4248BB5A61CAC9E36908DD9049CA1EAA4E7773D54F9BF82D4447
+010C37DC6CB5A199B0BCA9AA3743592E651B69D1D4BD2563135944545A1DD8CA0B1928A4
+93361DEE737C834868A6CC2B6BA3A44E198D1EC12123BB95103C8699B4B76D7062ECADF3
+13FC6AFB6D364ACEE2091991D4045CA2A5E33C7BBFC82149C437FC423ABDEDD7E4BCA0F7
+BD1ACA371A129F11735758E0E88F453DB813998F91CDC3428B5D8FFDBAC983213F9C35C9
+C6B5B1DA85C0F0FF0089BFFE9269AA245A8F8BA47E373D2AEAF9F492835B1A3B3AD9AD49
+076B2DA90C516B95C8D603B758D285B811C97A3B28BD0DFD924F4F4A6C6B1C1E0F7E51EB
+582914400A9B2610D008D43D9623BFA18A64B6160A72606CEF0A31DF88C7ECB3327A0F48
+3B0DBF54F1A02BD3DF36AADE1A65D4ABBCFC72149DA3992CFBF54D1DA3DAC66DB428DF19
+90F4C7923A23EFAB36FEA4B00661289D7FB382ACFBB03C6C82B58A46701FB75E36E1C697
+7026DF6B66554C2C36397230657BFF069FD03DFF9128A2240EBE1B838512F48F1482991D
+E0AD6B6590DDB2052564F6798C1BB88C06D53C4D4C76A4BB1C35355468B3C71547D76010
+C8902F5DF9C07A43E99230DA6CC708BEEF6D3E976C07404DE4A1C7BBF11CEAD519AA6006
+EEFD89D2CC4351FC3E72415E8965B1785AD0E29EE59032F6D0487941940FD8EB73B9CE70
+704AE65D7C3E7E30FC066DAFAF38E2A19025F628E7FE6054694D7AD21ADA5B747E54AD1D
+4DD57BFCADCDAD35E795A23BAA5171B8081EC9803B8FE6242AB1B421A20C6CD6A107572C
+9DA40E22D64E0D053972699180A9B5062CF460A715CF99CFDA1861BA3876047D969CD8F5
+889104DC3CD6A91E6765BD2CCF49F21BAABCCCC6984D5DDC1F872F85A45D42C490352D53
+70695AA4420AC5E6A0CE1C5B72186FD1FDFC64CB7680ABAFFB390C494FDA8852E6523BB8
+E184A625027F79620D9712D570AA5E2DE15863B222F7F5880DCB462BBEC2B5198E005DD1
+17B6867C218FD965BEC790161999B8D27E7694909828261593BE4DCE97FE5868285EEDEF
+EAB74A5707DC3C7824C1D4B170F729D9E04A3891E2C90FBA545FBB6F8883C60ADAEFD251
+6453F30B02B63D0438F927ADD8CABC0F78290C5D0433A1C611E4754BB72DB7A96364D9AB
+8B698A63CFABED083D9DB7B3934DA6FED9C162D33BC52D95F98632C93A8B6611C5C3CFAD
+B32DE2F520ACC68788CEB420269963C96B341D7702F7830FAE6CE78D23A99258FCBC3955
+9EA5748F18B560FBB1557019420217FC3FF9E1F98FA219728C74FFB024771CAB8A1675AB
+F57B229870ABE51416A8D5906D27EBF989A3F4C6A94E0B9CC383C5F161B0079868B17D03
+2C992D39EEF4FF295EE6331E26022D098D1753BC6F949C0FA5567C8CBB382A92D13881F8
+734E4AFD1E7157D9ED6DE9EE7DA0B8A08F54B7C8121D9D4A5805373016BE8DAA8B2C20A2
+CCC748F20209A63A4A7988AAC44D829241E0033FE88CD314A751EA836287DB68B32C9F5D
+0808946D8706556B3E597F70857C9C1ABC8728E256E9A34CA4D88D08A12AD64C1344E0A6
+7FCAF84A2E338B6734319ABB816F50BFAF49009AD63FCF1C9A4C7889485D7D6A3804A5C3
+52534EEE795E391609D1B6500321D29935FC49B937C061D556BBA407DF6A79C3372E1B91
+9539E5C21B816C060642188482BA31D8F3C4CAF759F7710E269235EB9F47C2699CB14C6E
+0CB2DBA8CA246D4F8A4D95B4452A4AA20FED42E66C415FF1FB74BBB434FFF1831BECD82B
+23B04ED0C66B5E1CCE3E166EC586CDB122D6FBDCDE2444230D932261DA28CA59BA47B23C
+461E0EF7AD3E03C501EDD54727F14196906C9413FEA8E2DDB9C7B955B3A7B83D91DA4BD0
+2C7FD4A96FD70634E2069AD2189A546F0B4FCF0DCB00C0E5F3527A3F0FCAD178C8D2BC4F
+4ABEB2250B4EEFBA149604B1A3D2178279E28B7E91E859E110510CD6C87D52E74CAF03AE
+69A5D08D4F6A45B3DA591EC6198259C39E4ABA9D417336E18E0E07CFC28C84B466F034AF
+A8541DDCFA4038288A6BA7A2503AA194DBAEBF3DEEF9BE93EFCDC351442B48AA8C0C9B67
+EAB4F75821E1FD55E60757D11BA394F8F336242890254F43F598650EE6EE730FA54E7EE7
+AF00FF3F55703D39B2623C7657E4CBB969AA8D7CE187C0119E485E391F57A6A42B2EBEB8
+F22B0F46012D822C8EC9ED9FB4085AE3C5FD36A9628B07B1A963337BA95E1EE89FD3ACBE
+4921FAC06134DDBF72062F31B1D351020C16B886A36CA9D5EEAA6470CF5044C7B6710392
+1577D9D5CC9E49A36C30ADF473FE06CAF00A5DDB44475F74152D2E520A1975CD1C0A15F6
+A47893FEC6BC00E1A44E8F6A1651D39BEE76E67C83B735872BECCCF0F907207778C4664E
+85C7D637FD201814BBC7D1C6200038B17F75E08B23F4AD0737259F9C07C47556FAE21B18
+1A110F056B1A612375A511FDAD2C291CF389622FD073F292ED09953B11E2A6626E6A4CDB
+8B50B8F9C7147114DF64C9FD8CD2E064CD9A3EB95555FB2B8D6E8A4BCDDC54E97E9F0B5D
+D3815077F6A825F924FCA5821E78BBB3E493F77CC71FCB3A5D9092453A0084AFA1ECF49C
+384A274B9B2CE36C0B1413C473D041B4BE0080B561F7A03F5A1641A6FCD1959506EFE270
+88ACA5283BF1D38901F2E071BBA4B2E35BB79D9CE9CD3B776C7348EE014D21BE0421CBE0
+4026C044120006AE1816528B353850C3577F4A0CD8BBABA169DE487AFBDA975B850736F9
+1345BE2B5ED8D94DC2505B8D6218F3167050BFE7E723008CA3C29E3244509D0893C580F9
+4FAE8F724DEB1EE280AE8993C9502E9F40477FBAAE9C3F9DFD0A78FC38D537FC0BD23851
+8499DD3CC9E583C292D200B9A082008E52604EE8AABDF15DB108C8D5A693CD829C8812F1
+0CE53781E50A9D234AB33BE6693C3FB59B921DB35FDD87A393F137D0CE119CE835138F18
+7F2338E0AED3D973652DBB79D7761D39B8A819BCED55B483BEA6B5E971E06475D03E2B9B
+B3B9D6677636111D4725EE36A077BE72347358A1EF91E5FFB77A0ED25542DD3FE9D7BC18
+596E2DF47A12A43F324444FE90226A63DC1CD5F265CD7EF81FE20A592D5A181B7AA251A8
+0CFDCDFA15B8A43A88F6889D2EDF93093DF25CC232BD1DB179536A1E3C46274F7F36A443
+86A764B04DFA73FF34D7BCF86C0A5122EA5332CA1D797DCCE9BDC7C8516BF80532BBDCEE
+A7C2A883683CC3CBBF1E96490C2B7D21DA99A3D6A0ED78252B12E1C97CE41D2B837E948E
+94BAB7BD87C929D8FAED67A8FAC5AF8E73F2518428646B0A70387CF9DF41DF0F4B5E7A5E
+786909F6FF0CB78649EC9F653FE445B4D588370E86EFDCB1EDAAD1D2601725EDD7CB78E7
+E815A4B76528F51FB88CF25A44B187001C63988B6E32531DD4E961DF683D794C0AE3DF76
+D0C29D5A279E668E08501979650610050BE7FAA5B67B93E47C807D22B26CE24B9BEB46F5
+B09C4A4683ECE59E931850DFB86108AD5937DA19A2132BC076AEFADF3AE07F65451E7A69
+5A583E0741864156E31C4DB9795ED7BCEDEEAE6ACD259FBDEFD4B4F4F187726A7A247974
+7B22593130F566D3DFD71E500EDCA19CD8B7B7FB5EBAD025660F5D8B3F24A224D741BB9E
+84942742D9D88E771B721E72859DF2CFFE2B288EABC083FAA26D815BA98A7A9F701395A9
+7A8058CDC1CF51740E293F51B6F0D61666A365235AE1296E1C9485A0043F651DF417CB94
+E53A1D79AA96CD5D8AFA0637EDC6CDAA761FD5F4E712745FAA66F74E7CA9D4C7929884D5
+32E12C92625B882AE1B60E0BFCB317DA1704F8A9337A42A8BE38DBDDEDC1E6FA9EB01F4C
+FB0BA8A2B29D02D9DBE63D2D592348A645747C55A939E94753887A853D3DBE03C0BF8BB6
+C4892B94415E60C3B7927B3B7BDCF56B45189044192DD6CF8FD192C5929C1741B6E53FE0
+7B4CD9EF8409287D791BE417165B54D5FFEF0F742984E18340AA54EC8D3E0D7A479F269D
+B8FBD0671C09E265CBE33A64CA9BF752D334803C09D32EA7EB774C32EC2E2D8706173E56
+C6A9690179F2191453DA57206855397146877BC55A562AF975C3715AA39F85C39A681FBE
+F83A7377E88E569732533A5EA193CCB76318E9D6ADD7400BB9CFF14D698C4179033570C6
+D00D70E5EEF63015399E5F49C4DEBF22666D76B6D60F801D023FF4EE8D63A1DC0709481D
+491F88979DC7AF7260BC0EE1CAD6A7A3EB0CE78C93865884383489F457F2AC5CE0C832F3
+F4B81820F37DDDB712560F066ED63777198E3491EBF087DA503CD59812FB082ED11E072C
+1C1482D879AE9F461ABBD5D4BE7D8B50D50C55DDF9C49D64FF968207614A85DF8DD56502
+809FA54B200F7DD9A6D4262AD7F0CF61F87A69DEE18A9B8C67F1CC152A8509E64211A064
+F39F3CCE5894A8EC0E23C9A557DF5FD50E2A5CAA3338C1781D04CB638A47C7A5A6FF8230
+1867BFD856A6BF11BA8DF56963D17291AA202C991F7EC97B501F79CEEAE44474806A06C4
+00BA8E8C5AC49448ED4C248327E2CD223B9199ADA618FF99F8DB84065C36A8205F5D3356
+C690D972B139D97449C080821798A70E55801EB4532D0EA1C05DC635932D1848310C063E
+05BB58B016A99FDD3102CF2BF2AFC5C6FAD3C031FA24F9BDAAC454529565E4EB52F838EB
+D4A61A32FFB3A5768F3B1135629AFFB808AA85788B3BA755AA51A6580803B6CE45D94581
+849CF2FA75442E759F1A544237938E831F504BF6408034B034009BD82E623AA31B66D128
+2741C8692C56E3F251BE3D582C32A9B770D5DB3E9DA9BF50A527B37DD41C425623F3B787
+7186F26937B3E04E291EE805DCEDDFA214158DFE50A3ACCD0DABAB73F5F51BFCA200C466
+B9A786E7CFF65F4B24C29D39A844A6F6D6BE41C298C2BCCC5CBDBF3C3B731121F834E230
+C8AA3BF6E2C40EBFFF4723BC0B2AC407B93DBEBEDD49CD639EEC65777A5B6F94B8DC1C59
+05040D8E4B205068BDBD5F812058D4D8BC2E16114D22D81701D36665CEC878D148AE79B0
+F67957B5505708ED3D98FA55BAB6FD20E2C8BA1C326F514AF29CE979DF66BF1F71A579C2
+EEAA176A3632CE7F136885EF3D530C15DDB59C28CC8E820F55E31667E8D8555DF76807CE
+3B37007E37A06AB32A21B2DD297C72785A88AD6F45784224D29241B013663073D8E1F7C1
+DD2BF95BF7C74B8743B31EF48655049EAD7BB13B87E648BF938059202183DD2970BCE1ED
+3018733F8E5B7EF9255A29ACF581426DDB9224858BB380AC7BFFA1DC8D2589A83FAF5ACB
+A4985D845B3F635046887AA62327FE0B0F020239E9FC7477821F7BD43EA2EBF1DC9CCF32
+FF6111507BF24557126C3BEAF30DCAFA051E3E9C26882BC3F4915F54AF9965505D89D11A
+562EA74783739F0C788D0BE3547F16F9BD13F96D861B2DAB90A4BD23043D588D9B583C8E
+15E9530D006DB4F17E0B4EA0A851397C4B781D707F98179B6E212A6FD87E2509B6AE4CF9
+EEEC87747374BB2144CE2E7A70B0F2C03A69493F9DD476675AF200F15EBEA4F7770001F5
+461B9079488E9FC1FE2EBC86DFE8CA2D2ACA5F746804F639228E813C8A1D1680F0A12499
+CE56678DFCF24FFC05C80F78989CDFB4F0CDA8E66428511E9BB0ACB8EC04161CC575AEA7
+522A229C75815C78B3248031DE073E0C5E538BD886F85555AA2E0A0456C2933A95E83AF7
+D16C8F8DA487452AC84487EC764A1A2EB1CC754F517FAD18C7F76769E67E3363D8881823
+6949A35827574BD65623CD4FE89C0F11AC2E050584CA49DEF1C513A8F7690652F963447E
+DC79D866F8C42EC7F3092DF52EBCF6E64D19E44CE1403BBC3A29C56CAFA903D315D42058
+A01E6124B82F1093A3027891C49FF06C8C1638563F92BA051AA5F750FF5F6108F6C0071C
+E9CA1CC669841592DE89A5383CEA9207C9DEF1A4FD137847A80630FECCE16A6454F4E857
+80A9B166DCFC50AD94E332CBC546CBC0A39507C8205050473351C6263B33FD705594E654
+06B19A80DBDD061D12BB89775D6BF4933B3FBF3BAF6B287A32EA01ED2B5B33C48715EF5F
+4650C9B92EEDE15F46DC093FDE463578EB377697703D7ED7C0E576001487567316B333E9
+CCD75BCBA59E69E1AB62F39D0546EE67FD4C1339A93E01951F0C2A38A994406406D2C64B
+D719DAF35CBB25BBC68E6DA6016ED0AD7E1930CB951C1CC22A8D82E144969FF25FF153F5
+D7A7A6608471BC31ED1F4B4E6E58173FDD83FCAC6FA079FE172CAB3BF667C0FAA4827244
+1445223D78002593602829313EEB37EF4EF8C96129E96484E36328213B9DD5F55B731167
+FA55DBCE903768321B2F375FF1323016F7A8C0B401BF8E2A983EBAC57AA4CE5668BBE152
+E1BAF5615559760ADAAFBBF1EA43703AAC9A74F21383017152EA311AC3D3F8762E1D8918
+887A0BD9E880D3C052A48B4EDEE667370097EFDE700B49D0A19F32AA3B43C9B58A3EC400
+DED3BA2829B90F54D8F0B3BECED9136941272DC0332FDDEAABBE38A0F8BE05287CB0D281
+DF55F4E8AB705B54DD026BC09E5831A64C728D9895D21E1FBD24D198ECD475CEEA216726
+E8BB15D4F8E946B5B097CC9C89E79470F0DEE451DB14D96C994DAFB07A0221BD48F79587
+DFC722BE7B360A93B98B42443494076BA779417DA3C17BFBE69B4B547A3EFAC6552E4D4B
+9B03D51C863CCB46A8ED112C0B19608879DEAC918544B43B4199B2C0DA7B318FF13E0CF8
+47612E7279C334F681AC44CEBAB0D6E141506AB98322FE9F41430E69FA2F482CEFD68F3B
+1280C9B6EA383C053F9474397E8800A6DB961655D18ABB68600F570C2D02E4750622174D
+6A9AB48B05DDB2D56D74DAA537A642E1FBB63E55FDCD54615D08EAC22EF484FADB9862C8
+6FE2E6C300A367EECFE4337110796C21F60F9CA9D034917B1C98FA45EC79DA8DCDB216E4
+A3DD97F0C51F7828743AA768F2E442D2264DE35D7F191AE874B856C8473ECFF241A46AA3
+C2261E74BAEC485E0602ACDF8FF0A0077E84E6C8330951209C87E117DC57D6018E7D4EDB
+E79E6F59C75D8D030B442B65B3513F74610B98C40E3C2D500D41ACECA44257F8E24B0B19
+4B6C8E20C51E61AE4F633F8586B52CF2D9438958C52F7DB15B499E69FE3BDC8E983CC34F
+80B57FE1279254A228E7286CE78E771BF9436154847370D7DAEA0D995D9D7FC2F0637731
+29E076BF10576E480C1D82C29648A2AD8CD36814C67045E4A67737C22B5B5EA48387D991
+E35B8DB9695290D7CA13B1106C6FFE40A6EFF1DAF1A841F3A5F75B68D441687872E91EAD
+4AE10D047756DECBFBE4F87262C2008D4ABEE51A0641AA309631D7E54258182E56901E59
+D1F6C7F15E8D3FB2CA70AE578B2CA08C65FFE542A479407F98D06F398DF54DCC16FBE30C
+67FDD4A3227238EED53CFE2AE0088A1E2F9AA08917947C4CF795D3E464D55987C4DFD14E
+EEE7C9EABC34C4F4C77B56C8E486BC35E38DCAB4E7FA1746C5854175AF400460BF82BDE3
+C9E066F4ABA7E1DAF6C04035AB86B1289E3702FF3DFE4FA431238AE487D486150A1C52D1
+047B1663D12962B478BB1E4B750FAA1E2A09ACE4AE89058F3E2B928167FEF099922EA552
+6435952A7ACECF1650B319BB3BB8734F9F54696B556BEA7EEC47E4A77D81280415E02DC2
+3F4D9A73F44AAA9646671EFEA5549FCC9A5915239DDA6E1C872F742B28A203AA88401DB7
+00C36DD78CEA2A9293E8768D5C59721D16A41000A2E1B230DFAF4A1BAC797DDB85BCC5A5
+A38BE413D0270D7259289AD4788D1D9769234BAE6CBA1DF835601A76CFA75C005C0EB325
+6A100B43C0AC0D0051084902D68F0517C91EA5F4161961644230055C97947D5756C62F12
+C550E113B2A88EC56345C965D81EDC09F62AE036C18AAD798250E5A0A07E607F3E2D0ED7
+B889CC2961339149DA012D74F290574735CF2706FAFF605861571D78FB92A8CDDC84C83C
+BEBFC000D43211962C578111F8FB8E8506EB1871A518CC7313242FA11F8D51BFC3797637
+F5E1AC8EC1435B36D98BF1BF34C960C6CE650D5115A7A244ED7489BDB7F6514BE25372F0
+9E3F378CF95A0E462C0E0E1B4E84696F1977059079AA626D0F441D2CE7F4B52A49B14FA1
+19762B9FF8966772E936F0C6BBB0B24F7846FA1109562BB57A995AB8DA48C9EDD5E90FC3
+4C51EE9DFF7A2D4AC959320FE10B800C83E9B83FC89FA220F965DB0495A4EB5EB1AA21DE
+5EB75C0CC0619C9C38F942CD525ABD40EAC721322D47D7117D750325AECC9A021D1A12D9
+D439AFC0425F9046622EA9F34FE1FAE58C428311D62DF1FACA2127AA627E91F5063FE47D
+F727DEE5B989E1D4A89B900FA7A9CE3259A3A86D966609FC254CBE319DBF40FCB0515567
+A54AFDCA6CB575C49E893A136D1680BA06CD3C427E1D1DD707AEF67C44B89A4CCC1F40BD
+64820463144AFF0DB7CF78F08BEC8C7DB7356EBE85A0DFFAD4D3DFA0F7F4AD70E7A5B49D
+9E51D73AF08C7B65B9914071A837733C0819ED07223BCEC52D623D29CFC3463233DA8E44
+02C013306E90993BB54CD78043BFCE18E490443AB6D7567FDBB9C5ED761968B39DD21669
+EC5DBB5DC7205B279B3095460CEE2273600AD169C649D846A1DB9E6524A7FD5D9EA9C9F1
+A02CBF4D9874ABDDCCE5F70F7B3F408F6186A0CBF83EC8A342D7CCC022C55BCB472D5896
+069976044EE83A88622CB1C774EA75B34DE55D618E7D22D50ADD05328B59F9AA9B683EBF
+4741311B7C07541228ED36A71F9175F4D0EFE9C11B0AAA03403F1BD623F43B4E8C8A9E5D
+8D2B43F240C89DECE40B79C64DF6FDA815F08D51BACDD7D6932B73F74A3486993CDA0834
+3812F920486140EE379675C07291435631EEB4E03CB5DAB603EFE0545CF4130F9D7D421D
+5114A4FEE9E4B2897BC6D232ADB685C55EDF8C2A8C47814A38B8C7BF34FB777360449448
+90946A15CDE17EF60BA40E77DAF5BECFDCA9A09FFCB93D0010A161BFDD40EBF7605EBA0A
+50C3BFC9B8A48CFB895FA52EDDD86221D6EBEB0E9A3D8D0F80B88DA1B8099DCDD7703C53
+0C90F979DA5A2CF528B610B5645087D2CCF5D8F639E420AACF09F97231C3250DEFF28978
+43F44E473AEE74810B77D8449877E45AB5A30E29A4E98CD78F57A47A195C3CE22A5BDED9
+1B3C576D10D7467B3940542E70A7DFC92F4876E384131982D7680FE05A5812C80621EFC0
+A2F0BEA16B3D4D9C07B8AC4A540C803246CE437DA13FE610EF3211F81CB7801C642279E4
+9CF563ADD932DE6ECA45918DDBE97DA17B443C7BA15FCF39D91F9C4501B03E56B9F6DD75
+F3A47EFA6B7D9702EDF6C79C9183F37DFC805E5689F27B53D5487767B276AA037A210C02
+AE23A2C4C89E6CCDD49FF5FC857B2E8B8A9976C238456D000DBD35B00A9401657DF88913
+BE616D0800945CE1404968E78028B727B6DB6547F5155F4C5E0C97C3FEC8882EDFEF555E
+98E76A3BEEBE09DBCDA40C2C35BC1A8C7A6B7812AFCB1468D527F723C947F56B9B1B4A45
+BC11CE5C3CA9D950E4729A242866E226A66E3D8F71D9AE73F0F8740E2974CAD28FE613C6
+B67BDFAEC416CF799EABCA17EC183A0FC013A16EA73B5156AD203C2D07898D20AC23D03E
+C5E4534F153440C72D3DB5DAB3EF1AF626472D039892379A39E894B10BE22EB8296E209A
+8C823E4999F6BF0A1D3CD90825C752A98AA190A2E19266329A49014C772510AFB6B85D23
+FC3811B1BE5CACAB09B5D46E3813DDFF41B8ABBF8E8ECC2CB14D48632DA2E5F5F748E14A
+8877B8E5F2E2621014B93A7AF3113E3A8B3BCDDB1CAB7E7FEDEB79E1825E27151E7C74B4
+CBCB8B40A82F1F333AD206F18835FA8EE49BAF6E22E851DF09857DD303CA2CCDABE607FA
+78740F70DD481DBD1EE04F730B5A3762082B1B47E69F39201D42A8E21F0F48CB5EF716F2
+4E3B4B20E53CAC08BF494E71495B4E95E46B6AC1802F01DBCFA8DBD1A3ED82894A5DC263
+700908A3AB700075586F3F3406496A1DBF40121744A9A1C51D3E135CBDBB5BA68D3BABA6
+21AAAB308EF3B0287A32AB2E584FECA9A3E00E0A3A7C038C225C51788C3D13232240EADD
+63C8FB02A0471517FFC82E8E2AF6AC526F0A3DEE7726821ED3627638AD691FD4B240B9FF
+613B72C089D11C22C610F9B9E244EDC11BFEBEB5B1C5E4B4A4362683363B14FCFFD748AD
+339C432D31744B43591ED1DAC1721A9FAB9DA2B016070D89914C0EDDA9EFC894440C8B4F
+3CE96EC4DEFCC4C57AF0DF67C40575095323A5D73D671D2A716A787DDC6837A6AF455F6E
+B524888B98EE8E8F48FC9443899D3CC6FCF6EA214CF462BE414302FA0B39C1DB687B5186
+EC46781405BED3DD98FA23D796D197E9CA2287D4494E876F8AE61898792E3794AF5B3901
+815FBC50E7876043D1F14E61A6F998617EB751C113739F035F4E9DA35DD53DBAAA91056D
+1EEC865258540B185DF50A01862EED02EE626051FBAE63DF6D94666EFAF4ECE522CC8066
+EBEC91734715C3919932E28169F49981D7316E982C287F716FFA8D61B939F8A47899D57A
+C3D845FFDB0F21BBF2AFB9980EB0D4E180B4A22A902299FCA5B157AF5DDACDF2C9DD3E58
+2AEC6BBC869919860893B9FCFA4881FF8AD0D10066CCA51A0B63D478D1DD7BFDED04DF2F
+58186AF02494A6EEE99FB66AF9F3B7C6A9E1BBA52AF2FA10596044F7A9D4B0CB337AD6AC
+5BF8CDBB69390F7536B977311C6C9127F26DEE4378A17CC931587F77F14DDEAD5DDEE1E8
+B57FCBE1382D9529880BEE3DF9FDDC6A3F9C6056988E5FDD101A54459F6932133871851C
+4871EF219571A1FC43A42BF14E8B029D8AD6EF458B59057FD6BA634ABA8D6C11EEF4BCD9
+402F47D4739BDDF22948A9D5E7754F621D27565CFC92BEBD62555B12BEE04955923A9E8D
+6B0C3D336E8345FBDD40B8E7C9A43DB83A895EEDDE6211EB1360FB016A9DC23F5055839A
+9A71775D8A45056735F14F87600916F187A53C323C86CDE455356176FB014584B4A04126
+3FA11150B2DEA71B44BB130243973600B3A9204C13304853D33A15CCC111C0F08360DA8A
+A2C615A72FC79C1B128D04ABA0E92A138CBFB37253EE80A18BC9D92B5845E895A7DC4060
+41AB37F3D4827254BAC860D6EDE8C5912D8DAE2F943A4430269FC9F9894024C73C90D77F
+0FC81E16F618BF7DFC1AF1CB2EC0972F62B30F5B37747A8AE2C7A2C7C34595B8F1DF513B
+973BE2F1ED822FD4BD7D5B07BDDA6006019700257B103BA495F9148012C4CDB2C3180DE0
+B395BCACDE2FFFBC1C64DA5D7ED1738B68AE483E5007EF90C9A770D73988849F2D2D6EC7
+734422A7D0BD41042988E4F215A81B4D2545A2C84A1CB218825221D3E33D5D5A2DA7E91F
+90B275B9F73571286905C58ACE35E0FCAEA9A9BAC32784C8CFF609B09114D6836AE6315E
+4943E9AFAE0905E0516603C5CC2C54C364CDF9282DB7BA8DFE921D7B4833C48A8045A60E
+ADFE47F9E1818BC4F97657007DEEAB9DCA84280E3014EEBF7D4D0D1DBFEDB072B20CC4C2
+BDC4414DA5070757F4EB8F65B1DC1D8C934F9BC20F516A9C6295724DCAB93A9CFB0D75CE
+A6237E7F225DB1CBAA18C679E2C6F0121FC59D090E5DED3306F50DD0F92D5D9FA2003095
+CE6C5157C569F3E5FC02D4F3FA115B9B294C74CF95DDED62CF1E5490A6FBC97065247D4E
+23D1E39B0EFEC6663C27674AFCEFBEA9E482909EF6B6B8E3AAB9FC169B0DCC8449B50A08
+221406F001A4D140579FA9338C675DAD54E854CF359452C07D07EC05F28301D94FCB46DA
+0D0F5502DB24BBA0364EFF694A7F4E86FEB6845CD59493BCDE8BBC61A30FA209B890F097
+5600D91FD896E6E0DD0626B4BCA3487AE1C577320E0C251AEDCB44910510CE89CCFAAFAA
+CB88770FA29636576011B67C6FBEA6A310AD45A006100C4473E844ED4DDF69341BDB9FC8
+3D37F678B9F7A2BEF245F823186C56AB3667795C79EC85D68B9A34E9779E29889E67DF20
+26B22D42C423C1425A678D8868543E96DFF0EA75C3666B0EC85A015B7048F5ADD08EFB1D
+B674AF6D008808168A8EF8EAA7D43F942043F3508D6AAE60CAC9C9950B81C5ED863B6653
+0C98AEBE1942E63CBA37FA6E02DA11AB27F8579BBA5220635D424AE097A88C830B3D42BD
+6B7D89F6F40F63B362E5215373F943ECEF08666D86D2D3AF045EDA7F9F796A5522608F6E
+3FAD8953F166C11FD0688B127AC306770C934311A4890C48ED4EA8D12D04C5E2FF9B6DE1
+5253DFA7627F3600C89884B2B3861B364FEB31805A1D91B95D2DAAE9D16538DDCB94EBC1
+23F63ADE7C1B9D48E526EAEC0FFD822160DE068723170F5B753B5C10A0A79CD09ABF1E96
+A8811EB377BA65F37ECBC966A054A65FBE686C3BE9FA4573BF86865A5D997FFB690841A1
+F273016436C3D76351BAE06BA745BF00F27428B1113B5351567C9B254948D8A91F6927DA
+381F993B0F941458CE5F5189091A65B5D90FEF01051919863C47FB4EB11D18CCF8E5C8AB
+3E518A0923BF4AA13F83BB3FE88A4C3D680B7FD65D649E0159C6C9151FE7959E77699105
+B8E4E1B10C0C5B56C400325D32EB5716BD0FB13AFC7A424222B970A894C7D33BABF63B59
+EF13538F526CEA62F5856F1BB23A00D7E65220E5241D7EBCD0F84C44ED3EB468DA011023
+4358E69CB5AD8C0B53F2AC1D014358CA2C2A3C901AC5B2850DF73455D690D3944BB641E6
+995053A40D4A513425BE0A17D619DF7ED39076E9FF9163282CBABEB14BF7E4A49A5D93C8
+69B9F57C9D86AAD074633AA533F5734F2B98B0CFF7ACD4726BB1CB239032FBA59B3D0FEB
+3F3C169C667807380CAF379766B5984B4CD3D71975B62EBEFF09056E62917083E35CAFD5
+6FEB1C7A89658F46733CDA47E99797EFB6E48332D24C1B9766F92D4D4AC4EF17CF6418BB
+CD0694C26CD6B5421AFFDC33764719826667B6F88E604F982049D286A35B5EC47E07605C
+A8D53448C6A436B183BAD32E8138CF289C5D0ECAE1A2818BC3CAFA0B02C9097BDF043F15
+8625F6B756D85C81A4B42865A4AF790BE63EB95C72BE08598898E801FABABC845EBBA1B4
+4D4ED41CFF1CD460612F8C2B249B1A206656B2CFC3910C57465343DCA6DF0DCDA3F6DE56
+8D6AD6F83DDFEE9DE523EC0BC45138BB80B7315D894B27D73C4C1DC582BBA0A8917E2E10
+F94369E0A956F61EE11CBB2B45ED6027D448538B36C471D2D3BB6BAF447B60F6023F55A3
+24A5C71573438FBF1A7B40A746A73F5E1B51FA3F38DC9A2806BCA0B8B6817B1A265826B3
+27D425929BDEAC8136A91329B43EAB1AF325960D105915D185E0522CAEF00A15A2014F6D
+E29C3093AFF98028F5061818F8783B37FD1881ED44D6516EFBADD5D6B500D5502BFE6A5D
+908A07BABD50514A1484901A51AF83C338624298070D04C1DC09D03E565C7D25726E37AC
+1D1A9F5DB891126F9944BFA1080C7906A263BA892363087DFCBF6B92D9AF9CA1D7781A99
+9DD794B3385C18AD819D9558CEEBC46F9097E9B6CE6A00F1BD43C98730CB80D48937D0D7
+36862809C16C794C4435B41DFC392291E699EBE1AA54537375B6FBB27F1230B77A0A05F9
+2BFA166CDB8B180036DB3F48E4851A538C628C8D5D9CD556317A0CF0E6C28183E07249E6
+D6D47F35F1C3220596EF0CC1F0580ACB2B029B5A5B0C10DAEAD5D3F698CFEC641F16D80C
+0225611726C1D8C4482A00038BEC8E0B9EF7263C32DF0F80E01473C41307FD9C10742079
+9F2E0486F5C937EBFA48B7B61DBA9094AFF525790B61C3858F76685675BC6ABD1B9E9A8C
+A17C98CF85E49D6CB5A6B7CEE52D67EC249CC2681F802C06FFC639BF3A0EEF23AE39AF5D
+C3E77F63D07EC30E4B3E06F74E707DBDE5B6DC0DC1A9DB02ECA2FBA6C87CDF278EA55812
+40495E2C138BE9CD3AE2A1A427151A5EE3CDCE28421B137B1427CC48EEE8EC1355B48FB2
+86F40371EB9DCAA5E163C65967FFD4FBDF7B358463D00AB081ECE83596C2EA2F3CBBD847
+6D6EEFF31FD8A0E3CF4B6362BE42331CC2737891CFA525B1CE62F2FA4B1F2FCBA54D0452
+B77579DD1C56DDDD6DFB2DCB816B47FEFE0E84D3A19FEAD6290FBF751BAA095C068334BD
+77F0F04DEB6443DA99E84D250849045DBE0ED267F2789B475127E6C57059359EB08AA04D
+3FCEE5B1E61EAFD90B19668647CC52FE842FB9D5A58E3E50E4CD7A2EBF1FC9DDF4CA4B0D
+29AAAFC8344627C9BC74C49BD24774EB0CC6DA70B3F3BEE134F298528373CA8B96121B31
+2C5D02525A1166E8A644D04194DF8E1D9323FE92DAC4833CF0E08C716716069AAC65A421
+142B305E97E668A32B397244555BB14653C18384550BB417C05EC9343BE28E62845ECB49
+AE6AFD50A5619CD1F5779FE6AE1C2A2C10420F0E9426AF4614FE2E6E925214E0ED5C6133
+E9E44ABC962770A4E598E8D4300F9C93CC152C5067FFAE77FE9A171A5E463D1E9E5A332A
+564281F49055D0A99F49A20368EA7C75285EF8215FC37FA69A66101EE4E2E32A1A2AA753
+8EE3FAE3D4C31F96C34A74677BC9221FB904F777F69D2B85825E09C8BEBC973E4AE85EFD
+123507D5D428372188270978D9C7ACEE75DB5D1F1E2988832870B7EE4F5366DE20237EF3
+E526DC33E2A4FA186A43325779EE8253D76DD1C4FB007F1A2B8E0272334A5956C488ACB1
+1D09C8399B4181B626636F6EFED9A5086BDA64AFA3677A48D13464C2E0813421D96B08F5
+F3B7D2CBF5B2875A1C217F4677B026B21A07A8C61140B1A91D552A1947952448D7492460
+FCFAB5A22A7E9BFC577ADAFEE42FB8C0EAD717071E54493AA7BFAE960641332AFF9AD94F
+9FA05A94FD5CB6014FBC8D274ABD58DE566F621672550D2453ED92AC8E317D6D28F5A443
+D211A3A65005F8A18006D2EC7749AC8F57FA4142BDD1D62EB99A2C4A2EA448AD5DECCAD8
+7B54EE483B40CE76CE2CC0239B0B50C8AF29E007A10FADC1863D9844B2380052383F333A
+29A7168871919497C878D7DDFE5D22667C51FFF6C2926B3D219D3A3C02EDF6A9FAD14E90
+90D293156E00F6292F11808EF0E73CA26147998707EA4ABFF7B77A5E29ABACC005EF74DA
+D402BB1AACE7CDFA12F93421506980C275BACC61B292DD800E07E1D640A187E73A0B682F
+0005D5BD5F6E53171C376B1573B9F1FEF247AC3494D828991A9050C2B85870A9C2E08C14
+A92632C3553AFE16C771A3FF2DE42949E1AD0665A0BAC07C8B1C9622873C54DCAC6D642C
+1F050F2CF566713BC4C09E28AD0E7CC6986CDCF68D5D8DAA0B20B6310E4198A1B95BB262
+7B1816093B84234255C361928DB4BC5AC3A67A487C540394E833E3D879B3C96ABD4ECC4C
+95FE7718D1D6443C84458B694AD25EF8824F947569C001931C133D999D6DB574698BB17C
+B86246A3559E4E4EFC079D0BC9FBE3A8668DF9311E7EFFE4316B47C4982168D69331CEFB
+AB51A1BE03A6C2CCCCAFE7BFA2A836AB5819FC8E18E33C4CA59955247D0EF9AF810141E7
+B60D58D38A2A5F4686C1FBCC929A2601EEED2A4A4DE9AC90F726F1D1A16BDCCFF5280A6D
+52B626B3D927E606189991FF548FAC99C1DAC6B894B4BAA370678060B1D6CE7D1F74E251
+920D7279E493017DFB862ACA5BA417A9A975E4D6736C2DEA7418CC1A07DD3812BBBE56C6
+F3CE5DBC16353009E547376D99F03FE9A087C29A1161F2629D00206C219300B1D09F4BF2
+AD8475A269466201C57EDB25D8A458E4FF1424FDF09B1879F5AC6512952D56EA719263D6
+F8BD77D3B5C04A2D9E27EEF0FF3F42484F667DD1B3E483C45DA8057AF1C3746820D7C663
+5C363BCBF2106DC618AA1F46C34E9562F33EE3D392A6072FA236BDFED8D8FFE526694AAD
+A68AF0ED535F0E1E2CE19ECABC2FC66ACB07E44FDFF7111639117086B1876725BEA99E8B
+D0CD8055DB154A8A7BE4165118C104A5C1B2629B4C948EF51A68C7A3B5ED70C2AB40F0A7
+53B75AF07F4248699B03A7654C366AA3A25121D8590E787FA902D5E29516BAD7C842C649
+41EB1350B2BAC0E28946943E0D5C227326D7B1C3939FA481245B19E7959B770DB9355DE2
+E5B6FB5F66E273BB9CC91527F87F35E95AAD29D867A0D35E9E6B1BE8F1EAA06FDEF2BF33
+E694D4747D525AFFF997EC367C1E1D0B55C2146BBE47581FF99824269E43B795FB02F80F
+83B1BB3222C6A48B9651325E4A6274BE9047DABB7FC9F85751DC9239E82CBC5ECA22358C
+8EB9DA76B9CBF92894268C49CDE4F67B6299CB46FAF1A8E42FD584BA74C47767613325EC
+95CBE6A43BEA5FF97C7C2195E970504893EAC878AAEC0CC2E86CCEC442DB62FA15C4BEBF
+35D8AD91711A689415A84DA6AD6D1E2646E363D143FFCE360B3E9D282A84559B1202AFC8
+41A603E80631FA5F1914411B13811ECAB8CEF64906B0361F5F558A22026F46FC88A389CD
+E0B23523E884686C7D4D9FEB4C3D66BC410E2111A73988E73CE96CC26A9ABAF3C860D8F2
+658FD13A44F3DA9B5E53E348FA51B64299FCBF16D16E07CFD4C5446614FFAED07FFE9E25
+A10696029806CE3E23582A1FFC5B83185A0411E8353BE08D7AC131E2BC7B7A8EA6B36653
+82B2C4C217CA8A09ABADE43A7A5249643758B7FD0CEAB8A9AD8E8ADF1A9D13C2E5EAEBE6
+D29ED3734EDF200A92E19490CF4E42DFEA28AFEEA7FEBCBEC1645C6A101B51303BAFB113
+8D90761074D935F9F553787C1F653FFA3DE1A8808D185F38D57DB5E1B16C1EE5B1385C4F
+3C9FAD7CB2460DEAD9DEB549303502AFF17660B9330D162C891F1039B68ED4682BE6BC89
+7800F158A24B07539CA9CFC6324D52054527406D915BC0932F1D7A86E2FD1F649386CA6C
+6E27C50CB7A63862D606CDFC3ED8C6328A756AFB01865C264FA74B586E5A6D34CA48CC74
+24B5EE73BEACE92A3A4D97BFBAE51EDC60643B8FCF024EF05E263C0BF15AC37665BE3428
+86F6B507B63463EB2DBBB5B2EC5CA4F227F9D5CB0124BDCE2C0AB3D4358273910E916D43
+6FF95985D564BB420489DD1A0919C8100EA03EC5702A9925C68C86B4972C118B04016533
+BD9726054B7B563BEBBCD62CCC5A08F133ED0554872DE4188F1F15D52CB5592B1E35A319
+C6E5EFBC10CEC89E9DD78884E18FBCC408378351B276FB389136ABAC62515C1F5C3D3755
+3E0FF12DC19621DC4E6C148FC4F56F8FE32CDF567DA11F80ABB91D224D4AA7ECDA2A5035
+9825F25B2150EE449C101935B44549EB3E6830D551C551E1501D7CE5B3968B770016F605
+8F0CD392393DE4576167DF1061732E9F7A42464610BF841387941487AB1BDF04AD40EA13
+90A50F076215B6DBA43231647418BDBFD39FB143D43E0B8912F36348FC7A1CA96DEA49AF
+416D8A6CE75EA49395667E19CABC2B8D43543A488B130A2D85386518D86987BDF99A26D8
+B4EE1E29A4BBB8AD0AD4A27B346FB5F9E8E5F180F0D5748FD98A64715954A3125A749A43
+EA2B18CD4DAD93656B8FD9CE27E5EED5BBC369C060BBB43B4038ACFEAE8D437A354CC373
+66B2715885DDE1BE0F5DCF688E5AFE08E163264DAC1BCCFE9666B01970F2F16B47772ECF
+751055380EF0002FC3877CD3F89FB0D9E018A6541FB71AA3F6CE602C4DE2920386F01185
+E2CF256CD8F8EB24F460270B6CB8982C46CA5E58566ACF504EED68FEB0255B6D58B33687
+551FACECF40487D58D4DB520A1BF372DD3B66710DF6224E9B6D2EC15B31EB4E41A6CFD53
+42E3FF218807059B0EC60B96CA5F9F4CEBDB3ADA79C16624824F479F5FFF981B0E109BCF
+8C15D2254FF75BCDBDD4AFFB96CEA4968C38611FC2204054673FA7AF01DADAF779AE58E6
+8600044320439E79D45D56352B704E5F12E56ED1788E0817DB76B80F134C9752F0082CC1
+D4205003C0B2E73BD54138B10E0A16CB57A0ECBD17DED50FCDF7BDD848576E87868A911C
+C5F0B1C36BFDDCE813366DED05732C46C9DADA44D71E94C3C4A5030EF7061684CA509C70
+8A242B8A39D649530F379E81A1F5B4456A452038BE180E35889AB052D14823392AEE2379
+FF3564A86A2F50AFF40962F665F3C005CFF6992FB85040E6601D20135D7227F05892F344
+2578C821EE1F00E68E0475C0266FE10458A18634B226AF224A80FA07A1E3A29FF6AD2838
+CCCCEE4E5E9035220AE9F53C02DCA89F00418FDF632653C5C64BEED2209ED102489720BB
+D735B06159B60BB162997140BB6AA99CD063B94A7DE5098A8CEE9A1AC5ECCB0E0D12D399
+27FF2FF621919638D4205E39DEED766108D63938FAB0DB2B2C9D1BDFCB14517C7E98369A
+7BD3E31ACCCCEAFB954D92A22209C9E825CB38C9B5A529823B0A85BAC2605864B022BE5B
+B8DAA6312E8DEFE04593F4E8D0284DBBA42CDFB7C189F280FF48B79891EEF4FCF59A413B
+7CFAA37EF7A154DF78808E4AB8CDA33FC51F6E389227BA952469AD2D7BAC328342467482
+FE311D122B9AFE8A16E9B6F5551CBEE36A3EADD5FE7A524A556F3D7AB3217FD8C574DF32
+083E0D1EA61A8E01E3BE1392BD2955486E289C3E1727FE71C50D1B50E4B7D945C5555851
+AFE225EAC181B0EA541AF40AE45309B4BE2DE1BC9B36E0B7849D0844330F3850572B3869
+FCA1BFDA818FFE1CB7095423D611D85890BDAC15318028FE9F3033D1DCAD9381B9237247
+D65829AB81AFB878C7EF54CBB6CA38526AFFF404662434D7714FD8A5D0800C8FCDF69A5B
+A6938079F41D08E80746259C7D7D24E149E2C55424223CCC1AB2008545CB8C5B51CEB8FE
+DAC374E94A7836030F536F34A55352ED405D9C31AC2F82FF072B9B885968D534C9792F45
+1BC48E942D28CFF06246597246776530F72392C98D29CCDDBD9063EC24D559437B844430
+0D2D742E08C0126F4116198C72AD9D95E83A534A6D353FE873038825687C3AB0281600CD
+FB2558D70450E14684F610E144A7568C471334FBEDE0CBFE913297A657321182AFD4045B
+D5D205551C6F9B904781B32529C2AB0FE1DEE6269CF6009203027C9425262CA5AF2EB250
+493B9C1018F2907DCC656816D57FE4C987CBE7F7F1BF0EAF8AA40E23B456093B3DA29C21
+5CC7F911ABD9ED34866EAEA9E1E7998C4126CB3B44F7A8075C37640E0AABFF1B9B0EF003
+96A9CA8999EFEC2FDE533584B5F49BB4DB1E121B581E12F2392E7ABBCEB56B35E8D0E507
+980457C24100377B95668B167C6E5388760883BB173A6993A88104A3E08747F1B75F553E
+65E448C8188A3942182FEF0593BDFDAD67691E125012714A0B4A61F5E918980E1A167A32
+D7CC3D46435CF3F2A84458F309661A2095792F79D1CA6378DF864A308E162F1D8B35CA85
+98045B55B19BFB7D18C05B0216F5A7B75167E7866537F3F8F6BFCEC95B946B4AB1B0B015
+E45ACFBA6F4E24FFBD0FC639591A95337ACD84FCA6A164857EAFFF41D00138A582E321A1
+D6205B3E73E2A55882FD873FDAD0F9D205D47F75055FA3863E5210EF6A56F8D12397E3BD
+EDBBF54C8A328E62E03BE58D301B285E398A7AC55F6E08493099CCF7A70E79CA81E275BC
+86805E22DC3126C98916CC09B06CCCEEC5B66469CCB92AA21B71A49A2596076818B17ADB
+301590C5CA8635CFB881832F8621E6C15EF5D59F20F75098FBC0A7E79690CB5CB3F746FD
+D8B0A8B92AC145E9303ACF6FC91820119325FF5D8BEDA62446311A73D89739E628B907DD
+AD9B8CB60E076AC1092DE241A56495D0C1A5EBC43888BB8DD087BD6CDF38E1DE93630923
+CD7F57AF1604A42B70D2E073935E66025F44ABB3E8B620E065810AE1D2415D7A58175D06
+B7CB4C211499F9F9EC43B92C3E93DCDF03699D731DD288C1651A62A25AA9BAEB1B79AC89
+974C233D6ABEE67B4729A746A700348845A42953CD858ED53F385288ED83EC2B54C2F416
+3D4E2E5011485D9293567429D4BA52F1F4CCCD80BA8B59B501C629AE567F24C3AAFEAA0B
+4612ECA7694CBDFF876C3B9B5391D6EC38DD10166C3CF3CFEB02DAF1EDFB661899D3EBC2
+556EAD791F18381618D14F7B7B115A35DC0E8E282B8D1B4C9E68B09E9C8589837660444C
+89E477BA7BD0CDB39EA9FADEA33A9990458A06660A30EDB737BD11627B68DF9445A34D4E
+4993BA9E24CEDF0FD6955CECA5C9C79A340AB31096FCE9FFD84B2F49C8D504F55F413860
+7BC83217782E1A269E662DE79C67506F14AF71EF7302282256C1894AFA5DEADE51BF4222
+F2D0F1F4FC1EA7E128D7645E07941187D5CF65EC19667F2D204222C6958BF58525124ECC
+17C02EFB44881DBFC89A8D5D73A05295B71AD83BD9C54ACF1FF0C542D13DD9CD6957078B
+FC5F8A0BA938AB3466F44919BD38C5A0B14E899208598792AC43F532D41C6B8C4393DBE4
+472B5339C02B620F6D49C0B0BA93BEAC6373539881206C1F8E5A0F4241D0116737C4EE62
+575A47D79F1DE2569516D24FCEE9B7829CD545FE71D3DAE6FCE4BD780437E597F5849135
+D69B7E51E2D6A83FD3A8E67FDB1825D2A56E4BD7D6ABC291D052997EEDFF0DD618211607
+1D1CE4B60708315358C989BDE51C97FF5F2B2141893287F822D6AE440A811FEB93E0E600
+AF51552FE111FA4AB014A89EF562FA552A8CFA6E5CFBE95D81B7E50C04BE883DA4E460E0
+83438DF33E15F8D759FCB651B18357B40094736416124FF1D59B4B7BE4940CC5875676CA
+EE4A30F059BC59596E693595CC889B2627B3392C5EB267863CB753908FEF7712BA9ADC4B
+E47B18FE8807AFF106669E8EED7E0DC5AEB3DA3FFD8AD8D8B841626B800B5B82292D8A56
+D5E9FA394EB1686C441CE523407401BB4044C4C5BC448888BF122AC6D703AD6333EABC52
+C999312CB3E16FE4FF2FC8859D8662CCD6E35DA8B02BD22E776020C3BDD774E9A24EB72F
+7231F1B9B3A096E4A47AF15B4AAE20946F8358BCAB1D5E3FF566D361508DE82D46038A28
+BC879A9E75016FE30A8AFBCB1F2ABDECB4ABA14CAA2323A5DA6C57A712EC6CAFB1FEDF0C
+235E50B30127F62CF88E77362F6CCA0810E29B35EE5B7BB29920BAF6FFAB5EB3FF5377CD
+A310FBD9AF79001E8583748164CD7C4138DCBA043B67CA3993C385B9F054585517E4F73C
+C5F63F46F78235501F636BA4BB41BD0CA9BCEF79F0CFBFA446E09EF8C6B915AD718CA59D
+B97A78CEA2195C968842C94B36EBA1F3DADE4872E3FD7542D6E477EE9343CE5F801BAE59
+CBE5A2F66DA2177389308B526493A523A9496C7C928F021542A1D6676CB3207979AFD6CE
+2E4B37B3E3621312782607BE9F9598D470564F6C3E502FA2067C1DB36C0928D7491F5119
+72EA2A488D3A4A0BAAAFC021FC89DEBE05D7E992122A5887ABD7C88AAF0B12E3A0E6457D
+E7BDDDAE5C4449AD3D0EBC9B0BA6C5A72C2EF5048238A8595B33F570FE36F1C9A3ADC38A
+1EC604428BECD165520FE81172BBD2DC01EE2A923F88DF8A6CD992DE1875FE3C122B42A8
+2F4CD38D5336DE782586385878CEF7124AF8454C75E92B4AA8786F40B0414497A099F755
+F1BA0AB892066BBE83E472880AD336EA7012100B03D06E9BC9904651AA7F93B107EFF61F
+6A2F7CA20240BF1D3E83B3256398CBECC74F8882E40B3E10C0535ED23A8214E19464082A
+DDF3F590F9CBB75F06820A1DAF1DBBA19CA4D57B7CDB841980BE2E879E8D83E74FBB3EF9
+7D644DFCA51DAD4F342534160CF07F8822082DF31D8A6282711D849DA3F583B32ACB48E3
+0C130028571B9565E61BBF8253E97435F60AC0C91934C5A3FFECA5155B25455D59C18CF4
+66AE7A467EB5799BF2488B1568340F368267625F1ACB7FA34A8E582B0528FDFF256154C2
+F4F2D0F61A03D13A58E01548646D6B4659B4613E83476159E8E597546BD1F7902FD0DFB1
+71390A36A8389E25388391BAE75567201CD1A6225F774AF5E3132222EB969BCE588E1E18
+15BC60934C8E132627D342B1F7D780F9B5DC657A975387202EE08E957F3D123B4C115F71
+CA9CD0A5ED37C7626C8596E9A4DA7FF5A114A85E545F89C3694F3FB28A5224CA6F930538
+9B76D686F13C370887F75F88F50C98974857520DD8806736D034C188403234F1CEC012A1
+17F9DC0B03346D88401DFEA09A28944CBDF75E79EC6B26F204CD6D4F7CF02FB3066E7085
+BC35AD0CF7CF47AF38524C05B13E51A8BECD2B4EB4E9AA3A7FBF08A1E71A61B2ABBBB10B
+714A0E46FFDF3FFEE96BAE962C10B8FD824E700E3ED94FBB1E03AECF77CDF572F623ABF6
+9D1AF511F65408CCCF16BFB2F1A0895D5CF069A78A3ABF523D4053F8A4F6DA0F3C6247A4
+5F2F6F21C964B50EF4615BF41283B6C655E55397A6FBC23249D306151A4E5F57C26AB256
+345B45B3D81AB1AA64C80F09C6000ADE9948C42E03356C0377EE74E17281985B8ACBC958
+EB9289159091E36937DF725063C434D30DADEDC3007066C7302D0B12F8CCCDBAFC57BB30
+261918964E42F08D1345D4018BB1E84E31B0F57210033C0EF479D1ED0AD35CB7178B173C
+6AF59A4824FE5FAA88AA847FF999B3152F7C12F7258F7C5DA155B8BC0F166D9B6AD20188
+3154BFCC9E3B9B267FF8831BFB906C6CBA7D05842E95129D60B562678A322B94BC988601
+E8E32A6C507F02005BB1CB8B220A6903B4F621ECA9FA513FA4ABA25D107A39ADD5D32593
+5D8875831F02E4556E6EF278C01E8A7FFFFCD1D5EB4689A2DD86D291F473120B984218F7
+DBCFD434EAB3EF19D1A67F4EE9D239FBC0BAE239D0C634D29950EEB6FC06F0481A10B225
+7B80E1F0395CCE4C4291A54A5154FF1B0896D2E0CAF112D0E534F014FCD73082FE9E8A67
+ED23FDD4F7C37651FDBEDF999D44D9BD7D57EF6038598BCE94ACC2B6C0BCE60433F834E3
+524E3FA6028B6D5DE7631B10A2BB1C77BAEE351FC7373C175D3878502C2DC5D40596ED3D
+8940052DCDC8EBE7F1853D85B06AF9114FD739E558F0FCA26F3817A990605F9C9807F900
+A18C71248300BCFD22D7857C390431356FA4BF993357647D9A094763D668B7908CA93E2E
+EAB15E34E48B1EAF8082C6FCBA7DA5E9848B33BC59D6B50C9CB5108F3C356A45A854338D
+81881FC425875EC59D361ED95CE99FD7A279A807671C8141A000A5419E8B9549F3617114
+6077CAF18A152CD041F94E113DEE2932F1AD09D55359B7B39F4771F15521DE58C311D143
+AFA24A92D36037968DED5FA71402B34442F9820F31D1C608124C2B50EED276FD06CB04B2
+3D0579FAC4ACD7C674EC5E6527AA352E38B35B14FD647E645CBE09C5D3EBC76D35D02820
+C91A1E422057E99A86EFC9845EBD5735B8F61A957B44C33F7CA9502E08F39E24111E73DD
+7C5BF59212BE06698913B89C221944A9E539B1E79038B3E2D2FC40DC4D9115256D8BEED0
+343FFE190D6242A3054711C86A20E0C4DFE2C270375DBD1009A6ED640D505F25F475E0A4
+DBC0D9840A68F2E657C1AD8AAD7A260AD74DFBDB32B2C6CCA9A49361755DFBC09935041C
+BC531A5924CF763C29DBE8F169BBE77A261B1DFBF1504A04CE7C3EFBC0E36DB1CD256AB7
+F40C272E2C3C217779A2D45E1A33E504A32183552ECB71EB562040C03D276A91590A286D
+2A90E7A292B21AC7FC70082F18903E2B3246A66D95C47F7FA0099524F38018566485DDE1
+4FBB810C07BBBC487546F0C2BB295D1BEC35D797B0A6AE0616ED8465BBF239A46FEFE3F2
+E20F85E3E383C16D6F97044B6E4E80DB26953D609F8AE0FDDC92A41FF2A7EA7744585B51
+27F7D1D756487DF4D75289DC3FB822A16E1A8063D5BD6B2D7201DBF78BF4A34FD17D8133
+F8662DD9704ABE347C405D6111474E69C5F22552E4C6EBAB4A6537B46FA2EFADB55485BE
+A4359C8BE0B2A696BB946E89A5AB3EC81AB9B584E6EC841BCF4192EF82EFCEA357C90039
+3AD2705B9BEBC894E42369F7CDB749E1A174EE4CB77454CE86BAB1B631899C547321C9EE
+0499149D87F3FF59D13335D54177268569DE1AD675BCDB9281C21ADADDF54B32E62B3EA1
+2FC565A670778959ACB4C4A36B6FEB86B174D3FFB0B2617B2A84EA37BA5B4DAE6B7F1DA7
+36C01E446799F135BD5573B086D61B5D902097E93C9460E586BC8C5FB863507F7938B02D
+90EE19C51E00DEFF3764A3483F52777644D3F20C0B99A8807F25FD6080373B09C68B45A7
+BEA9F0731DE751BDF4147C690A9E767DB679A8F51849D094DC1E8209EF159084231610F4
+187ED2875D1E93A2C977C3F1C86614B60F81B31CFCF2086E91C3A09456F376DF76F6F4C5
+6F6D96CA852C7B749255150C5C16453A84B9FADBBF40273B18FF8E61F309B649BE8C8BE3
+75F739C6CABCC9FF39CFAB9997E77507A7EE5D521C769F6A9A03472C51AF83D6682700F3
+9D1114A04992A23768D8547D668A9C1302DFE2A2011E3B0A101ECA1A41A79C2AD80DA863
+CBC5D77DB3FDA136ABFA30603EFB15F99F848F18B2B55D3038E7E7F6B691350D3C0D6766
+4D0849BFE0CE481B1B732326AB02CE44BB2C15122A57D42264349E72BD47BE006DACE8F2
+A0ADAC696138227F9ECFFABC0466C2EB581211CC0A24061CDB43FBF37A4E8BA1434A35E0
+2AF6B5914D493F64328F8590CDCD38169368F805D5B64AC0F4B996ADA8879157AA0EE3EA
+605553CAEFB6D31B01F66016C64F7188556D66F185A29164AAB1ADFC1FFE71934CEC127B
+147F36AF98AA9A7877A7188EE0160EE26705D1AD9B5F86D8B6BEE71C1BA240FC2A903D65
+0C3C69CCCDDF00222CB01141C0F03958D9BD5524D8C31D4554073E2DB0169849487244D2
+2A28987A82DDAA0CD060C8A8740F1A11509152B4602A6D0DDC4456849FE5E402F9ED88E1
+DDF8E5AD854B5FC77575AD955C95BD033D69F4A2D2EA6B6EF587EB16ED3E0F52E7578FC7
+F22324AFB86353B1EA4C51179440F2CC64A37A92BDE6A88B24104CB8EC78C660A40E43E0
+27E0EB69D813A3C29C9C3614E6408532FA474CF9FC5AD498F8335DF4A04BAD633110405E
+EE6A5E40D6BD7E23337B1B623735BC3130720DFD1FD1A86C4A90145EE483728278C48E5A
+CCC333FBE140DDBE0A28168D6B2BDB902491E0340DC052C28FEBB140B85BF1FC4DC35582
+1752E935381556DFE0A1439A0BC810F9527331CA35508E3D0A451B3D285D37A25F1F949B
+9C9ED1BEF8289E5AA1A3BA045CA7CB647F1C1A528D85938E04ACB1E7F08F5ED3D18C9E86
+7AB607E8BACF757C98BB71878979DE3862927977A0CE431174DF24872B21988D6AD35B07
+42C01ECC82FD805CBF22BA02CF596876EE1E135254A8BB6DAEEBB2BFF9911EFD7C3A25B8
+55B95EDAAB6F25A31BB29BDF2B0FC3E0F4479DD96BEF601E4DF77A459B73B69A9C55A87C
+D63851038A7ABCC475BBA0365C4CEF17A742D1371131397AA139032620E16D89B3BB7A1F
+7B018BDC6EC29A8FC02D6C6E943EC1B1A718DB6AC51BD7C5FDCBF2BF792CF9ADCE89D130
+DC5C200FE8625BB13A02F45E06A53B7D186838EEC83906E8298CF83CF5A28EBA36D67F56
+64EC006E350266F7D2C81ED295F572CAA52FCBCA9B605E421DF4E9393D1E775838992B7F
+63BA394188312C75E64F9BF0217E6E31905945D27BACA0693E0660563A0BE2868E22A604
+C901BD00FD8E9088C4255B2583EEC2417AF39CBDB672845EF9BE24901D270059E7EF3C99
+0BDCED89538A8CCFA5A0BEBBEB671720576DD349566E591ED760FBFFEAD66148F05D37E2
+0833FDE02A4E85F2CE08B0E03DCEF68D454E135F8F07BF93724E0B7E0FE769A0AAC5B513
+F4A763347B10B50B88792E1CB3E6E948B75A8835DBCF188436153A2C2B44CB18D8996FEA
+75324C8973D1F0E4A3942E2A05E43B3C4AA46EF7B54039542193CF76CAF775DFB15B31F0
+41AD173F8821FDDBD7275618B37F2693A29C9A990B7BDE96FC532242929F81B1B61025CA
+717236C5D41ABD690EC853317D21B20C2CD6E9701202305CC34F5855934E03F1F58A0D32
+D73602B07ABB1904173E09D799769D7127B665537FD6FCBE10E725CF814B83475FB8E443
+027F490BB8488157A4208D031ED3992E2E0EE89C5E19AE11B16E95452F86B04C3E233A13
+02B300C9A21E2D920B49DB479AD034860B77C8C1279EF314FB4073B6077625270113848F
+BFA4C6D1CC72D3DD8DAB5298D5A5BAF7E832FB36B13875D241286EB56495FA62909539F8
+9D043095F5B32E10F59B8204F0C598FCD78FBAE872D833662FE913E595E3A2073A41CB74
+5AF21AF5790DFC9D3CB011FEEC385B5DCED039630C8BEDF0790C235CF0174F3DF205DFC9
+A621B1A32351499845F888DCA445879AF5871EDD1572FB6B07B52A583A288434502D0333
+FF418B95580F4DE9B2F5BA2906F074AC91F566E5E394AA7695A161D01DEC146BFDE0448D
+E6DD22D7A3C0BE7D02A29EBE15AD1F302299D673379CA3C2E500C573B8F81E0ADE5F59CB
+BB8E0B5EDFFE4797C763D4FF7CE0117EE17E80CAC2A3EE7840C03867DC19B51885FC6ACB
+FC0EC204489CD1A6ECACA8112FC1603C254E40049812D1BA5C561C1224BA56B97FD66DFF
+C43D96FDD510AC6DF46A9C7AB22FDD5E9318C4A5F598E34A3E60989577333E2CF7AF6129
+FAEF2704C1C3B997691E484675D62AFCD81F86A6EF5FA4DAE7D4F690BDA5E35D0C3EAB49
+A377A2A0B6019DDDD8E293738FA7503120A91AE095F613B3F925BB4D433A67090AD6AA88
+37979DC1DBE9FD46CAB54F1D9AB5B9E20CEB07AA93346801BF8EE52977FE36EB1CC51587
+FE57ADAB168CF8A7B95665F65FEC3F3EA5920401402D8D22A3D4000DDCB5D06C5A901430
+865872360B37C1277EA4C31B32C16C9EDCC6162049204A9A028943915A7753F72452ABB9
+901712C494B0E175E27B99F6F34A232A826ABDA15D82D4FD0AD88BA50545A5D9A4E3A90F
+51987EBFFF48CC52D8E7FBF1121DEDE46BCC71F7F3941EE02897013189FD60D9F41C2F3D
+86A0C693DACAA72D68404118DBE5524D07B1D2EFFA1F54EF0D0205FDECE28BB1080F2112
+AD17E04A000C581BDBA02571C412DBC9BDF10FBFDE1CB328239362BB008ED70FE062B84C
+E93030327374F47D62D4740DFD23B3F1FBAEEC619ED18446690E0339D2BCCDCFE3DA5D5A
+215224657F8CB4587553B7344A4CCA78DF1D955679F3C308317D8EC48269D5E1A9917E0C
+46BD6D7284BA185DEC43E31CE9B148CF708C722AB59CE7429617978F678E7B42B6DAFE8D
+CA1690208AF9541B8EF5C8057A459A6D6BB3F0410DD1DAAE469A71B7A416CACE53E775AD
+CA8787E88CEE3F57834B13D46A5DC1215DDFF7668A9CEC79FBBA1964F794F71D7BC2567B
+10AAA3EFBC22781C66B3C89B7973748CC35978F844A5EE16CDD95BD4AF3C6C63C79577A1
+20B893398A583BDEFC646E917250AFE307E1FB053C3A8EFB26CD4F65D58DAE816549C502
+DCEFE24A4DDED6ABC44FDFBEA9A92B2F78F20710997E683F8D9BDB7C603A9204CD90E932
+7ADF5B551419354EF67AFF7225026D2703874F841A034FBCB33267D8794C1C1BB9B26F16
+04BBCEE30D6D2BA30AB3F8E03E0DB4D57190A570686C420FA4775B5F8D984C4C7505DF4D
+309ED3BF16BB32B62241928BB3D978E10CEEC6AA72A00F786AC72F6ADC5E1BF1A234B6E2
+06FD0F6DB21BBB5D0D800BC43197CEBAE8AF770BBFAD4E41488AE5A8283EBD2E58BB4BC4
+5DBAE530D05418381BB610F5AD1AC375681618A7913CEFDB93815EAD3006729FD89DF4B2
+39E5DE1DCCB4BEC942EDBFCCC34C46704F5B31BEECC45558BD2E2DF554E6130112161BDA
+86C779B47D9E79EE1A6C41A722F1C8710C5470F02B98B6A102A962E456827E7A8E9C2527
+5F9EF9B0D3420A3CF1F96B798CE32F47C076A1973AA532ED91B44B6627D5ECDB94E488CC
+A0E54247BD99B1035769E7DCBC91BA655EBC0576E42738B7BAF5F7A19EFFFB78E0DD567B
+51C9064ACCF00AA9D6AA5F8EE73AC3FDDC1F501DC67D9257629C767B9AE582A1BBEE8C0C
+1B4BA4D5830FDC6C3A3D164EC1B30B8EA721ECDE61AECAF5DEDE7CE02F336A22E302D711
+AC6B83152A1B41C67A5D3EF767153F5FB882D0448B39B8507ECEEA86CE74EAACC8AC3E78
+E20FB23FD92C81D2EBD9014530F0AEED1595039D94AD48CCA8BE1C77233A9AC19CAF5A45
+CE5E96C5B2A962E8DC39339A2B10975C18C5B6162226221AD8BB4307F64E2B2C4F01FDF3
+1A6DC4966C9D6D2E3D5E92F0D21DF7779E35404C97B632DFF66716FBF8993294CA6B09BA
+8F7F840DAC99DF3D75413A0F417416C7FEC264D6CC58355B1290692666A47E47F0BA3CFF
+5DBC8EE2F4FA068D8059C1CF153C65BAEEC4F8196600B9D5C09DA14C8D5F87D88FC7DFEF
+B797D33E292D4A6201AC0DFA4B50285805501F3AF1E2A48C3493FE2DB06589B0C045B0BE
+5A2C5601F2F4644E6FBA9263BAEC6008760AD7833187540BDE0DA3EC762393EA778DF052
+BB978B708C7A2DAC5D62B2B4BC6EDA8DE77E548366C34411463BF5DACFAB701D0F64E937
+F5188E46151F8D47932243856F3727904404BD99EFC5F0AC5DD895CFD4067B7F338E2DF2
+BA69A84D26FCA6DA0ADF101669B9B502DA75D202F863D2AB8F821937F180352211F24835
+707B5D821DD71A74E4B9562370F2C61A228FA42F12983E32C15B13AF9F2D59CFE9FFE1D2
+4412F40E1BC6D90E8D943DFB8D5A36EFBDC7836025D6193A8B7AFDBA1EC3455F2EC95A6C
+BCADD64C7D41322C98479EFF511BD4BD70C06EAED0DEFFA2790649282EDCC5F3ECFBB70E
+7D62E1184DF3A46B154DD1AED7BA74CA7841DE08B4DB92DCF4F1C2EA54738F2BBD8A7B70
+0EC21D05AC8650A7F1802EF604A9DE97E8BCA273D26D97972ED752E3E9CA7D3FC11AF401
+D01398DEF5206AA94D0A79DE65F02C3E9A02C2DEAA900017DB7C0AD39F93BC2EB27F2E64
+3BF0FA8AE458C73B62B7709AB58D8AF25511B5C3FFDC5F45C4DF09400AB5E69054AB6BAE
+57D427BFC6A6A65DCAC262E99797304D660B672E72BF8BEC5FCFD074A5D1E949634D1DDD
+3399A80D693E3494DE56E1D0CCDD217FC6C6A2F4D6ECB7E3636E438ACD4E6B7166B27342
+2298824C5C547423EEBAA5FAFF2FF810A73C2BCC057F7FA1E96F21D665D377F727CA2FB8
+93307ADB216DB69824B72312242DE1105C4D7B048476E64C71F4C4659F084916660CD035
+85B922CB2EB7FE0E940A7A122313A85E0AAAA7A2699B4D1227D8A2F8F59B8FA5F6CFB63B
+7ED2F9AAEFB6A71D186815A0CE5816A787E25288A9CCBCFA886423F776DE6C09B17858FF
+CDBB8A52CD54BDDA98CE2BBE25849A2B4B113B6B7044431419512A00CBC8E5703E5A4A1F
+954BABB0CA465884524BD70CE67D6FC9E2BD7E0615DF712866788A17AF26D842CEDC9EEB
+B0A3061963958B9140BE41E74B7893265FAA57FE53140658DC931F0B897D0E857AE3A337
+F04D884ABE8D8E1DF1632DCFC2BB65E4BB2791B215957D5EDAD04A4D1F4372414D26CD68
+3CD89B893EF0CA895C2D36FF87A1CFB2E9F1A628CD59432046022B3E44BF2B5D5DE76F51
+5165FC2EBB07FBB23F262C07066D215DC73EDF780FFBC54502E57C69DDFC77D9896D3824
+D4749482FDBDEB40058FBF293BBEDC8C7AAFACCBEB160334D29AA7F61F34B929F020F8FF
+17CE610B0E0D1823DF605B2E145C9E78AF8396E4AFB267C7679ACB0B7BCA258F7AEFBDA5
+E49F3C3A17F0290F9DC6C5F51F193E2DB779CF8081C733BA0D7FFBB9EA3A2FE3ABFB4782
+B2510CA124ADFE0BFBA82C46A0BFC430C2CFBFE41DC3DFC070FA9DB38F0D33982127C8CF
+74AF1001B096849C8A518B6CA05445858EF78DE8B3B6F3019CEC8E10775EF9842DCB56AF
+982AB270C89644AA55B486BCD8616B440105FA6C34298422C994EF6C30C1574ADEBC0F43
+85029231FF5FA84AAEFAD31442120059A7A1D24BB44D14844A039F366ABCA742A6279402
+7B53DD4431B167F07AC0EFC75ED8545431371D5FEEF2E51649D1AC862FD5E8C18ED86FC9
+9639B861D2B502A2B5F75062891ACAD88D39729CE2CB515DF3C49413A974476A515E3F15
+E071A6A82D5A51036FABDCFF62659D0B54DC1B9E68945E87A4CFC0E4D285D23BD9583126
+4D2B4E4515A7B34F83A077F848306AD71CDB2B5E6F701DF84AC82CE1096B987E2DA09727
+CBD0DACE976AB94EE6B133C09B787C80F275DA36605CF5955FC706A332E3140B43AF9C02
+9C23C489C5C15F77F076C6A21DF7B91E9249E93854406CDCF2EAA68DEA68BABDF5AFB702
+CD9457BC4FDEC0251834A5FE1EBC40D1C8F21C3C56B2558E1EBA3AFD3E0B53AC7793E078
+73F8A219C6057DBF6BC066367D953F44EBCE2704D2258344AD65CA865CAC50085E5E321F
+B66E4404028E313876B65E5CCE58DDECD17DE76874030B63B267639147EBDA692745AE09
+775C4CC4C0B44469A01BA55B87913D834952541CC527D6D24238A5CAA83CDEAC1D7B5449
+7B6F9F57E0AEBCC7EE2DF0CECCFFC7FDB46DE41FA6E6D41AEC58E9A2CF359F9762ADC653
+5C52FE93E9FFE3225887009B596AC2B29336E0EEFF29738D4181D339F0FBEF72D29C750D
+FE1318CA42C5393D639E7650AB689225BCE2072C88526B9AF5B970CAAB8331D89B888345
+BC5E839314B671E70CD895F56D945E8584A7A956EF105BCEC436117D4BDB3791A741B7BB
+5B2F0033241EC02B40B75BBAA4C99D5F48FB370569C6E42B8747476E405B9D683D2FAADC
+7C4A02FCB91C654F47C80AFFEE61D2310619E72C36695090BBBBFB5E0B7169B96BDBC9EC
+4E8AD00B36B4FBB0B849CC04675277733D2FEF6A6EE9C83BE4900D02B95B516DD10A53FF
+4431B3BE8C68AE823BA121DBC6C22470BEAE5AF5441CA8208D3DBBC3C444704E7644F8C6
+11B0890325648B2EC17FBAE41012E7D49566E5016D94336D4C701DE2805AA001E79C9032
+C64838049D8D065A171C11F06BE58A478B9299B3A517C73CE84EF38D07F291EDE3535CB8
+D769308C2252C63839CCAC3BC9E8A24E871D90398F3187E3557E40A24FB1C61FCA55BB70
+5EC3B1ADE33F0C6340338B197654B373EF588D43E710869321FCCE8A00596981C49B185C
+DA92F64E0A65CD32D9448491EEEF78E4F410806EF4D6DC5F7804E99B87E640CFC46B6975
+AD18A05C470D233D23A20B4F85E8E008301D9763C4CB53A6CB6F380A439DDF64E4F69367
+446A0B57A0E98A6ADD0CF0CAEEC82BDEA2D130AA246EA0E4FA2E8DBB4459D5FFDFD7798F
+842CA8BC7458DDAE4C28FF65568617C25E0CE82CE644B3F6445C7408E257FA1791199F5E
+711023E5BC7E5AB961E867B06B83418954EF9A59EAC6566D572B4E97B5C6750A49636929
+562C6E0E2737F5B9BC06EBEF9FE62D9CF4FA509A42D192482B878757B319F886FA9EEF7A
+563DE61A0BABBD76B9A9FC2009A9049FC6662C32434B6C8F4E410C2F5A146EB951D25138
+47D03A64A453B748A14D2A2FC9AE56A9585F1E6725ECFAAB26E99418F8F2F944AFFF32D8
+AFED5E292F40728B8804D91737AA9CDC05485F9F7031841B12F431355EA522C674101B83
+09CF71D8D27477286DC05428F7E8443EC7E4471CF97ABB18753524A79A1B331CAB1E3FE3
+6D19BFE3724777670FA07CAA0A501E1B5524E62C15D0B888414300EAB0DEA137D43A0B70
+FB6563163E0AE68D160B96B4A71817DCBD24BDD8FAD76ED2ACF5E0CE1DBB5AD9A1AD4B98
+997987FBB15346F93053314D53CF4BA6A9FC6B3EEC4E5DE20393D00A6D69FD55B98E3045
+C27469B46C39C40B0F5BF53DC1142AF67212F469FE7F7334A39CF19443C1243FAF6B05AD
+1FDC50457F06D14F119EC724269EAC946793DA2CFF0C1AE736320C5F01B51F2780277D4F
+A77680C81BCB7FA34A8F4F63F07CC619DB4BA4AE94420E532E6D06558D8B0D9299DF88E5
+479F1C82178C7FDB90830CEAB719A0EC4DA5E66DE2D4B97F11113E0DDA557353222E6329
+8F21D925AEE6FAF6121AD7F2E7F805F88901E53E353152729A737C197937EF857257BC70
+0890EABC66A8DDD6F4636DF744612B2E744BCA5D376D2CE87993132742B66FEA1AA5A4D1
+0A5DB79DC3EC04D88B5B5CCC988AD647B7719AFF1F2FDC55B7DD113655F19E6D47D2CFD7
+B2BDF4FD564A6798D3696B5BAD5F7A3E8609B9D9D0DDC4F32F2798052ECF1EF3793B16C1
+F489004AB008CA729064EA7193D2AAFFA934AC2DE6CB00FFC86A54B11426A97A5E161899
+4DD7FD85144308CC4C376272E86849BDB4351A9CB9BAC62C53FF3D06580CD2CAC229FDAC
+CF8BABD15E1D7D81A2388597FCF2508AF5F8D189B5E5A86441E73002DCE94CF0DD953575
+470ED6D6AD57F62FAB4EEA0EE65C5C2FFB9FCFD5F850DEF261314A155A18AAD1B47EAB24
+FB7C0408B1C3DC80C6FF2D6CAA3348BF792803DDBD9258C694FA9A4FEB1D3BE1E22562D9
+46D3BF713B8ECC1532BACC2ACA978761621A122252F5CF0A658C06EFFD96B39B7EAA7C0C
+E691FFE170A91871B6DED3BAB734E733ADC503B5AF97D595247FA80B81AF8ED77F99B192
+0731917779642446DA30FC7DD5A5661F9268302D2B812D750A3F144C89038A6F573B0C62
+EC227C3C5970D8EA34781CF49E56E1ADF0743CE23940279CCDD27AFB7BB7B740F579D9FA
+B7BF912D52F35DFAA22B7D182C022E2FAB7BD0D90F7B6A03D0D6EBA225C70E07CC00F2A4
+599DC63A9218C17AB08927C0AFE57C6D3F0E7E2240A8E0C3CC6CD9854BE51B7F69040BB4
+ADEF206D2110DD52D5746D0085D583E67DF440125C26EB27BB8EC054A2AFEAAAB3139B53
+653E4C82D085D35BE137B6E30FA4C81EB3F968B12B2F4DB0AC653BB3E13BCBD9994C47DD
+99727A7BB5908BFAACCA7EDEC566AB58DEE6B4CA521699CB6C3C7460440A522145347A0B
+9B572D96702B497B8F9C3EE612B3445781F3FA7AAC78DA64950EFAF975623382BB6FF724
+3B1078C354E6F4CFE12BB8F374100D8E9033460B5911D4A18BAEE611272EB961EDABF97F
+F350744757DA2435292D03C54CBA103EB72626EC2680077B5DA99E248BC7581F791F157D
+0F0A359070827288F6961A8B42F98C948AAEE02CA29166EBED6F41CC2B14274CC8CBE8BE
+70EACDEF5DED806EBEF4FDB794A1A9EF45E6BB01183CC4058DD5D6BF33CB6A195DC97AAB
+72DAAA73A8922281DAEFEE6EFBE9E66F1B4C6D5A72830D9CBDAF7CC287ABB0753DBA936A
+B515518C6C121E52BD84359EC983A7DEC5E395DBECDD837788A01387CA0CA84F6984A9DA
+4D93CB543AA1101AF32021F2D2530300C6A16C7B27FC6D98E8E192AD089E9D10F10243A0
+1403222518D2B80A79360F81472FBAAFF0348BD16D8AD6888CF4971C2B61A8DA0A469009
+45F508DF6DE8F7A061EE437A227887D1C24BF05EA03A0B79CED06821B6A53F8275C885E9
+F5891E8DFFE67F22BDFE05507F478C90D8A90424097FA970E2B5C88820520C79AD9B539A
+A10EF6701499CB72F33021E5066D86EF1B2AEE8165CAC5A97E3C20E24229C072A41B515D
+3B1AD941352CA33927D63A7B0065AA432994EF31520C80F4FA3E68CA9CA548AAD31A64E8
+D383F59BFEBC0288E76332EDF7DCEDBABB3E068DF02D19FD7D0FDAD1BE7EF4947524554E
+EA87550C141BF3EA6A20FF4834D2044AC7733FFCBF34EE678ACA19A3A8FE3D943C2B3505
+242111C2B6307A00989A20E8CB7E4267AECDC4E6F5F9CD70568C5AA8A4E899E404C7CEED
+9989C788AFE029340B6A3D6376476181D19844598ED5CCF1AD2CF4A676FBFD17C0EF5BE4
+66CBA814647C2E0B5A2D85F3D3C8C16242848ACC70063D67918F800424305F2140A76BE5
+AC8A5CE0E32E26618F308EA578CDCB1CFED7CD12AFEABC6F6A236BE927BD11AD0A961943
+56C174C7881373770078D3D9BDF23CB838C5D64F923EC5831B791D5604931A8834AA6D95
+A79FC44C7DFC090CBBCB177A42A22E6897CE9376D17FE945E1E813AA473CC1530A7A834D
+0EC298E73517624640BB35203A089D9483D047A87CA2646DBD18EB02BB9F0EE711FA83BB
+BE07B54F1B7AFF9F36575BA99F81F75326F59D9EE26D4E4F642004285B6BAF192396F4C7
+731C5504593DF687B274EF80F27105F4569AF2EF4C5C5E88D476A73EC4444ABAD8E9AB3F
+950C9CF21BD78ACE310C328F988CF22A7EC165E724DDA3F25D403B28A1B61F668C013524
+32458C657E8FA6CBD2E6E91106AF5B9C8EE170FD1FB323404E4101CC134FE8F0887AEEF2
+3013CCFDFFDCFD5FF60897B720A00204E8544F51735C976EC497BDDC085BD209F756C77E
+296716650CC169558746490D024BD14FA54EB4E0CB75E8E91FA2E256F3DB4844308C7998
+A0EFE04FC6B14B73A43AE16D586C6683520A82286BA58D24ECEC212CDD93D2810EB4856B
+13D432AA6CDF05600A12C7FEAF7B990E9E8CBB8AAE023FCBDF953180AF6913D0DE5B8660
+E23AC2B170320467ADC89CD584E9A366F063ACDFD5FD44E5BAB3B7167254ECFB222AB3FF
+2187E43CBA6FB705317EE5DAA8D9F5DB83957CD64508A61EDA6B5D5BDEEFB2C6214DD059
+8AF10A03A486022A8DB111374E8442CA13D467BE84BB1001E7B9DBCAF50F767330FD3F62
+A310CDF232600D7DFAD998A0EA10EFFC49A702347E6C23BE9027C2BDE2E9A14CD55788CB
+0C8B4891930AE2BB346CAC0A2CA7C904D2343316A6F4202E22D4E448049B18EBE76FE3D9
+7EC95EC99264B6F938108A36CDC5C4D7DB364F89E9371EABC18B1CE08CE519BB2C4973DC
+4C0ECA366D8C6CC07A2DD320B997D5987297B330703D2A2DFE33EFAE86200B750D1A2D2F
+762E43A94523A2136492B440F6551374F3591FCE4D37F7C192C592133B3315D3435A9DF0
+F2F3F621ADCDF53F9CEB8E7B332E701AFFF13641C88DF71858352BA45506D267877FDD8E
+BEE4E80EBF692631C7C7133012E4CA6082B90533BE3082C34084385CD16C7A4B7123EDFB
+66EE5F20C2C66226542B98B437C6925E7CB65C02F4C659DAB78FC4ED155C312DBCD5BC7A
+F588D049D52655E57D3964D3BB713C6F7B33296292BB6273D626EFDB0CC6E0D346F8383F
+315C275FC9FE745C9CC2416F3E1B896CE9D4621E0B1798959434E380E5672C9301474FE5
+C50B8344DC9BAD4ED7A57F965ECB1F9DBE601D2967701D4C083529B6DE730D9940D03381
+EFCD0F2E5632CD6948F1C7D3B624A248786D69E581B916263DF67B7AD6C34F034B3F48E4
+D26F64BBAD4B57E5E3E4B11BBE3EADF529E0473547DFA0781ABACA0F03AEAE3C14884A2B
+47AEFD5174D2A5F45530A8C9A0B7C66DCA9CCB84AD031574B6D3FC3E6F1B0D794D061CC3
+3FBF13B5CFC934C0561396DC77DC2AA6FE3AB54B6215EE21A65582A8A9585AFA2CAF8194
+B3B887EA4C7F71696F93642371258BDD862C0CF23B819B194777DA8503A584CB26B849F9
+5CF461F3321BBCCBCA5DFCB054837FB3C288ACC2F394158F2263A8D4956ED155081F1A93
+B5180BFB3B694BFFD214C63D1CC0AC82521BA89EFE47A573D8FADF7C7B31CC98ACB47E9A
+517CD04C18F8A8116592704192274FA9D817D49AFF1BF2EDA8273B04A86E308F51336DA5
+FC70705D6142F000986593A7BBD524A4A03F5A1831E7434B0700B89EC3D45BFC3CBE0841
+06E053FB46BED0AE359A76CFB808CCB22DE78B1A88415AC79249BA9F9BC5BE2C3041DAE1
+9F6B46545F534821E0BF703A6AC49F4DF2D24A4A90AED84C71F87799BCC37ED9FEADEF35
+97ABB6D731757C04C00002C40F34DA0F35E39F6330A1651F89C321627DF1D1289C1C6782
+35D205CDBDE6BE95F64A2510AD7CE06D51BFB98E7AEAAAD4E2AC15E631BF136E4082B01E
+409BD78C495C88D3B62E3112B7B72268C4B1BF55E4FF2EB726ACD3A99148B0D0DC516294
+1E9B8C97C861AD1551703D9B1B17D1613F8BA6917B319BC2910728C5B46EF2CF9E1A06E3
+645C52A5D4F72494C1C18F858D211D2EE721FE457969D9A9BAECB4A0058780025142153E
+9B94CF1B20B717D5F9AC5BA9271B4CD61628402FC3883ED1D43BB2EE931614D871E7814E
+5ECC895E6CD9BB8A27F55004E7BB3E4A09B1D9C5D6B49140BA231B867F68F3A3C9981BF3
+9D9BCDDDB6330C8329FD52B1F1B6A7E392AD3EAA4D8E63BF3A895365FFAF54F297126CA6
+3FC07DB3763E7D2B79D2974BD0A380AAB25DB48F06BED0CD275640E5759C966A22E2437C
+11E92131BDDA040BAEDA876D8861FC551F32591621A14BE6EEA790B77752FA636B8A627F
+51428CD373F2ECC19DC714100A200E098E262FCDDCA6328A18B060219FF495AD46AB95DB
+2E33D5A697E5D25CB5F0FCF988D62C9AC53E415735BF0DFFDEE23ECA22528B3D66DFF37C
+77EDA16945BC694775901CFA106809ED3B59312B4A1023AB13738FF47921A0601D0A56A7
+4FB9F6B73F1564EFA5F2A31DB04365A577A1D9DF9FFFE6A4692E2ABF7DA3876BA90B7FB3
+168962EB38E03DC5E06E1633947848968BD649CE9B3064CDD5F88477195EDD4018F60FB3
+D2BA8190C9B2165FB5DB5AD79240CFBA8D4B2DC061F5392759EA162CE0FBDAB3D8EC991D
+3238D835F27F6440F50942305538B3EB8B4C9CB46ADC7A0DEF82807C277B9CDAEB65B874
+1E3CCA532A619367426CAAFADE5756F0C22E6FBA7CA826E663ED6716308482C957703BA0
+FD4322B105202352E9091B44793A849E17B9D4931D7E4FFBAAFF32D1705FF5D82A878139
+0B5CBB1E5E00A02E80C299CC3C9612FFC9AE200C4F4B919E958039D4628480A7A0279EAA
+DD0D28BD5E1D07BC18D66FA86EC9843665066045DC5DEE15146D9B4CEC6B0CA6EC946967
+3A464C46BCFF5451383B65B62D348907887BDD77931996B56645F118E9392215662998D8
+51AE73BC084FF9931D22E5012F6D18ABF618DFB01CFCBFE1A2C53B61B84D3B85A5D04196
+FC8A0E507A87560ECB8E2DB3CA84A2C97AFEE1005F6A44E00E3924527B1FCB8A3954C746
+D6F0E4266940814355AB8B57D3AB85A89EFFD1E384FD8E832E6A846D6B8DAF0C99C3803C
+F9BC1CC4A1B611DB8B3B3F1763F6BB877952ADE48CD9BEDEF049137CC2F0D859CB4EB075
+2A1E581D835921533C868480469430E3AE90B9C965B4130B20E22A060A182827628CFA56
+FBED3BE7A4C078E939BD9F79D1A51017DB08B27472B813B5D94CE9CEDCEF61AD4AC1DFA2
+37261EB3360CAA70EB0AEBB1777928B2199791EB0F4E0DA70F0A59DDB0B7FBD49AEF255C
+BF51C0F35AE0A242100AB96E0A2B51F82D5413FA7AA2C603F913066AB8AC55FD474829EE
+82E5DBC360130AF5FAE5EE9159B5E09ECE9678DE75A50F49EA5C24FEA536658D48417F7B
+5DC4737FAF73D41EA93B3889B9FE272D79788E337120691A76D0820E24F5657DF5CF2BA4
+BCE1799E533A991BC20CC52CEF9142186FBFB77E214A4311A243CFB5AD566995DE9CF7C4
+06D4235FA3ADE98D6C6CF3DAA3AF13106D38C4FBA7DD764FA38225DC7C41BEA8E87F6013
+8D320F004E832F52EE5D716F21C47ED0BE801523BB94D9691B393704380A58722C70E0CB
+F70EAAF9B5CABA0D298A0152E246CF19A63DDFCE9D45E691EBD404B4EF6F14B3AB70329C
+286C3CF24CED4D7591E4FC548ECB3B7864677028CD1073C949F6E334E528D62EB1EF23CD
+E94DBB71E289FD419A9D51579BEE2F1E66C0EDBD29A32859F1E5CAB29264EC3D6AD03E0B
+7BCA83FE20945CA48A4BF76C1F89B747DDD06BD000373561D123AB04AF26D1A785AB792A
+95ECEA3DC6F5E36A143204A17492A6C3C9F974D73919F4830BC2ADF839B83753C3C58011
+BA6975CEE5655357AA6981C18EAB50DD25E4956D2912BDC0B401BF8E3E719D34D4543E00
+6570D7F59EE1E6E683B53B0DB9A8DD3C188FBF57C719C8E1A35EB957151D5CA1208DC55F
+F81AE455B267013FE1515015206F1DA5E7F9F56C1F0A2FE55C1724CDE3E00C9FD055F198
+ED0E75DABCBCA26D558C90BEBAEF6F67D9DBE1758FA9C67FD49528CFA39AA21A4CB6D797
+C5E81AAAEADA6E7EC773F9C5ED0D2B0E722BBC8D449F5692E6FD2E90EB3673648EC34907
+8D99E469FEC7D6F63606E607BF946C78C1347CE1CF45DF42036AF0DEBA6AB19ECF358DD8
+C691742D3A0FB495C0947C3528B0AF579C16598750E475F169C1A36E8DCB33D2151CBE14
+52496F4F9414BC8EFFEB38D22714D2388B56035A4D431EF4D07D126CA898324F2BE44E42
+BDD930AD74363F011B2EA953CA48A7065C5E21B0B0E9C87FEDCFCA17AB6DEE77B167F31F
+6E157B289EDC38F47D836250303B7A6662825E184A464B3B6BAF6A31627EEC2E932E617B
+16806DAF25E7A6CEB17E89C602FBB0191592BDC0244293F46E0E698281FA9B697EA945FD
+9063410A495A75AF971B7F50331D3FE964B3B2E7C6EA890198D4AB7D515F58936D7104AB
+67013017B699EB3F3DF5F49744076536B951160156CB7F9D64B035C6BF0C3119ABACE506
+F15605840976E567A1ABA8B94B3B956A2982806AA50413B5F89514E0B065A6710FCF6173
+5C91FA417686324F69A98BD4EF2B0EB1A3CE20DEBAF35E592CFC68CB3F1640B91D20D415
+08DFC28FC3AD0143A8EB9BCDCD2D2BB45844D387845FEC9A6C9E26F495573F7435B6C62E
+93DAC158FFDB41A137F5DAF1F8FA134C26A1A40BCB646E26A513C76A6EB07B559522863A
+6373062B7C033FB23364CD9540C146CC7D0C1F33A137E5BE097F7FDE6281EB9B9C2F8203
+6DC40494242533C561CF736393C54CA3306FB4974FD76685D26BFA885CAF41AEE3B4230F
+DF98BA4EC7646D3F25A8A337C557E4AD260C6246EECDBCF0BED340BFAE2A0BE007640D51
+A583D0747A5F354406DF9D3544CEE1A8E45E0C3ED5B5727171DE29E75ED1E06E4B878C08
+1EA5AF1FBC2CEEF821380656867929E482C13FE6D3FCECA67CC16450E0BDDC5996D7B281
+7E15F29F94780F3E4561A3F0D53DCAD7295D68013E2A12F73E2887F500C5C40497802B5C
+69FE8CA2F4EBEC94CEF708EB00D4E44C73741A432687036ADDD9021FC35ED215E742BA4C
+D8093F29B90132352A60AA49F1A6351C80D63BFCDD2C4E136F18D605FC406EEBD81FF609
+F396669F082D83B9E1C9573A21C8BFF715FA8401CD7B5DF1BB56C709A32AA27DA08F2BFC
+4CC9D74491D7452C51C19D585407E97414FF616B8EB4FDB31672B93EF09B1478907D3B22
+8AFC23A38B48E0B1AEED91089548C135CF3BE546F737BBDAF3A3DB727B8AEED13A2CE344
+56ECCE70D653AEBF7B71EAC15074263FB58C10985830EAEE832E65609A6651374DFFB88A
+CFD2FA6BB43ACAE247BBD826E54B6F6AB6DDFF4A51F5DCA90062BD3E033AC713FB95862B
+540B9EF93991984FB86936A0841FD6491989B55980D917A53663A63952B9CCB826ADAB9B
+DC71EAE0BD3B580E767F7CDAD1E0EE09C9A5F015610FF572B4778D19260E5C5154AEB615
+F494F6905F04B1420E9C4531A7F6A8840E79A83AA20DC7BC86C9F51B0D10F6F0DA001852
+FDFFB7E60D675CEEAD92F73756A91D67A760145DC0EF8565833F84C50D0E17A3A1F33676
+E467012444D09186160B317F0D6063194E46E5A484CEF017C919D3E063AE2E79171D937B
+1536CA40EC4E4C71FB24CC038B20CE25504189986C5195E7C89D71DA60F40C8E34BD62EE
+44018745746F174D3E30E8F2AC3CB4165474B456A8E4BD62244C4698B6C18630122561F4
+6A5776B7961FE532C7DCCED058CDF95197466C2D6B5ADCC3A2BB6487B5DFFF6E95612798
+18FB8D213AF93B346458431C42C697F3E98EF51A234B8D717718B7EC360F181BCCA72A74
+C99FC0BE536FBC7F71B32AC4F85035EAC720C49C03CAC855FA49D1BEEF2799B86D21F3DE
+5F3BA47568811A2909D19CB06A3B62A285744DDAD31745AC58AB7D9BBFDAFF5E86EF4806
+5BA5BA3E78F6B85DED5261177F0B7D20B03ED496B3957A34A4ED1D493FF084653D014BE4
+1DEA598AD3EE6907A53828B49DF06C3BF1CEF5AB6946BF2E56D646077AFA325482FF16F7
+93656A895E24CB4263E382CDE6D67C5506FA7E0BD0B20BDFE0766803BC9DF615E456FCA4
+8BC2E2AD6E4348414F748F031E23854AE6FC92650A55DE479AFAD409836481881C04729F
+DC49DF2D9FC46D2BFB3B68DA59CED1280D0A97C7BFFFEBFC72E9BBED16C24B734343C111
+4A999791D052352ED194974774876A84B7B9339B85E6566B1C721A535A378AF89D834374
+78DAA191261D4C83E12F372EB245CBB39AF956E9A28289BDA6399BD2390618BCF9AC4EDD
+18CAA6EA6AF116C9560FA860C615467195720014657D4767D70F6817979FEED7A181CCAB
+AF11554132B382423713EA8F05092EB14DFF6F06E1A813BBC84091E76038D6E3DA10DCFF
+81E750DAAA2BF7BB75C4B1A3347DC8436E47D1B9780DA48842492B86E7D9DD848E1E8F62
+4BA0B054DBBE5328F208952E19707BDC6012F04A475D47D8C7EB6A64C2AFAE3A363CAD97
+936DF3D6347D8CF1862818495A6836AE1343272EB8F34BB4C3F9B0A631E922C920446DA8
+34E9C2F3551BF71677176A1F414188645F43BAD39FBC3453265C05EAF83C3F8B85CB80B4
+B3B5AC99B901E6E2C9A1C065848A814033FA6D5551954D4B36BE89E01C1CD16949005298
+CDA21D4BA36577A9784DAA57DFDFD0621EAEE192200CD5932A18442B6E925280A7B52D2E
+8C7116DC0CAE26B92A9A81B5B6B62836E3857CD38F2F5AB075E642760C0B442725756915
+413B2636001AC3D87FBFABC43D6EDD8D111B01942EB7FA47D71AA4520026FB22834DF914
+791FDB207DF0897D89A0057B2BA1DBDDDDE182DD14C85EF10D35F6ED8CD2398171EE25C7
+9C54D90C059A566A0936B8716CA905803FBD950BC4595D9F4CB59C37574AAE4055D5B472
+DE1E6DD3A7C58CED64FFE344AF8B8698F8F1D2FBFEAAEA7F136EA0044472CDE262C7FC8A
+0416A868086A5A9A2669B7C6B97482C570FB3192255D5DA008C9E13D1F5A4A3EDB7A5C35
+F71797DAC5B5F32A5C03C429198D56BC5B8BBFBF890C6A29A4DF397B2863B75FFD8DA751
+95F747DFC65379BA575CFE55A02C589CC8E62B8A8623FCC135E90ABD9900782B42378CA2
+C55BFCEED08EBCACB61C53C5678787DC29D2455EC3A379C1ECA2707DD3E8C008E26C42E6
+C48C8E3B9E0F667C541B963313F4FEF02BD67EFEFC63A1A0093A95F15FD139398A4CAC17
+83471AC10E3598688E1A6E261AE763A28C58E8A5B9CE4DD7B8971764340B9862AF36C89D
+F6708F535653BA9CE2711624A646B1D1BE8AB250275A1718841830BFABA2A900AD276D4D
+592A5D7164C6A7B00A62B08C7F27ACBC78C91E91298AA4B56D090B0A8546549B2BD2E3BB
+6FB39B6CDC7EBFB5798FC9589DD707C01842E40FFD597F2BB1B3EE4408F9D38600804C82
+2ABEEDAD6AA6EA75BAEF32E3C33CDA01847303D9C142140FA1B6E71E2BD3C78F5ABEC001
+66B2D689A8C4B0A7A1C32F3AB9DE8CEB7D20B59524656606DB340F4B7727FB35D2176112
+F91C3AABAC27DE231F74AEE1F6CDB49E2844F40F5F01FC9E96465FAD1D10E1A921D81F9B
+3F13CF82DC97DEE3462F58797B21E6DE4279A153669FE49D78CFEA9835D5A85ADE360B6B
+4EBA9BB8E9FF8AFD2287EE69877FC6C5593A69114EB174AD40F150282B1939D8A3BCFDF9
+74A8864679AFA7619D7EF1F347AD39E2899DDA9EA99E112D15E809E899A2294CC42F4EC1
+251631ED566907E1947F95ED61DD306F67BE79407AF36F34DAECABF7057555BDBE1DF645
+433F5DC42894C3CCF54D21C17B64FBDDB881A2C27765017B51BFA8147BF24157E7CE1314
+79D5C001348767CF1E82A9A43BECDF2F173A42292C8145FDB705CCEFD9ED6CC945A4CB6F
+6DAF4DDECB1DEBB0ABD084011D033F0A06F66D9E2C40DACDC790BD663A2436F50B3A91BB
+27B40F6B05B4D84169CA16CA7C7E609957A918BD60284C78DA035DC6215AA76115F0FAF5
+4C90315EB8A8F3FF25734F79300F0E676D06836B5FD19BED6CC7DF74548575820A735D25
+89F676D0129D8A44EB47AC1B673657EFDCE874541E2179437B9393978525FBB93A1CDB32
+1D1E47B3B6FDE0924CAD789284CE6F18837E89CD0E1739CEDA90AF44ADA49DB336934144
+D8BED19D5090A3E79B6A96E303A45E0DF44E795A08E1B5612BD05BE52E0508D60E5979ED
+B9BB44EB5851737FD5660B71661FC76DB3F9347FD7CFDD2E9C23AC26F805AD8E70A52F73
+B11DE295E3285A08BBEDFBD62C67A540400A01D6FD969896C8D5C46C7093646E530824E2
+C9DFF21E870EEF04CABCB2F62EAC60C1B62CE5403A1B5620DF7A3065B44C7D28366AC821
+86E49974DBA9CAD1249E3EDD876981C595BAC7D05F18D6430F31B96879DFE16021590211
+9F228B03E1378D8E9F7080D517F8C668CC27A9A60F74134827F37CC38C65E577D1DCEEDF
+2A207906E90A51A72AC31C4431BBB18242DE354DCAF50978E619E8A06CA801937B522396
+AD588A1FDEB567116CDFF51876FA3640027CE40CBE18D9423F05EDA77E876433F496FF70
+0D89FD7B47B848C5336C80A5EC644FEDB3F4A9EA02AA43A6EEFCDD27762051D2DE2DA02F
+A03CD491478948B3039FD532751EA70F56C254893A034971CA7F65BFF5662D4A61AF91BF
+752BAB772A556644F711EEF61958DA954494C50941CE83C6B7B6B2859AE7E9754FABA903
+35437EFE4C7B2B36B99251E0C8122A16E4F9C883DC4CD72B5E2A854622B73E6E3C4DA098
+1B208CBCEF104F5777F2BAF65746B7EC51F3C51AD38A12089E4971BAED178A9302F20DC4
+88CEDEB2CD8BF9607912EBF7B0BFC3F226228C96C0C128C498FA351081022E47F62EFB15
+23545AA028A8CE0F56C85BE3186D6811E4B86B31EE3234C595D34164B27D40295D2C2DC8
+1BED866C6A0405C4742CDF5A2563524C93AB0D350CD8B3DF7D219379F302A3A1C12E0954
+09698ACDAC5A2A89B7F54C846A0378E44E923CFFDE69B53F62FC661571E22880B065261C
+B0929D4E234503B81FCD8771685310EF5CFCB2210073EE65770F445B93EACC6DE6556C80
+59794A7499C2402066996593653192CE60E4907FED614060F4A9F68F0B949C33A7D5672C
+60317CC5AD98FF3301C2176E6CEAB2EF6ACEF60B6FB96F553CD8CCB05C2B1EED6044CB83
+40DF43DB21B567EF0A5657704E4DE711FC3EA7933BAEE7744234A369326D1B0BDE34A8C7
+2E328F30FE150DFD111D75122F29CED31C666793100CC8B69A17CFE330BCA55848B86397
+F9DD4950D6DF2B4486E26AA8FFB58445EBB14BBCCA683F3DCF2AC64025ECA14151D278C2
+977A9E046EAA361E658451DF157386033AD47B48C674EBCCDB79B8032A7D8FC01C8AD15F
+E1B9A410C5D4B51E20AC8E8DDAC4BF6020A2751114FB024A96B95E3053F38A3E9444CF7C
+C666B514EFDCCC3E167CA0B5F8095EB8D4060937718F6D8705A15B3E515201D9CB804467
+25B98EA469785969D46E24F05EA3AFDB074901774745286056761846B80553F0D3460CF8
+29C7794E4A360D3C731448086638214DC101591F4531543E9DB6BBEB1B91DF1FB3D1C4EF
+B13058C4B339935CFB4660CDB385C473BF7ABA5B5BC69083FEA6A17C6D04B23E9437C8ED
+14C680DFC74453C4FF2A6BEED2BB7DE8B346EA2DEAE4435DF08305BCE245ED67E41DBBF2
+96E3E10562A55D667D3F9CD286FDC42624B4BAF764E3C3378C8135A99F314C1CAC47B3B2
+E1FB39499594B223CC03EAC5F75BA3D91D892883D2843B29397BE6E06842D48B75DF75E5
+480F6501AF694E0E76D228DF52219C15E7F33267A9D1C3515308EF73D3DB303FCB9497AB
+FA1236E8DBE95DE4EC90A9592CE96949D0DC55EF858A18DD37AF76A51EB3B98BDE0ED83E
+7F4C6297245315E685559B4AA1D37E47053657E710D0AA3CCD41ECCCECC286BD133B64A2
+E8583148702FA532121E1E7B058BA1D24E7DF660A9E130BB8BE6DD87D005CEBAB1C8E87C
+34C3EA39378893ED7752DC543535761B4A237ABD04B53080196D79D692DE2E53B7167B6D
+76DA2279335AC5BF986E1AEADD9EE3A100756B15353BECE08FA788CAB5F63BC7AD58C442
+4AB03866AE0E18D4DC71BDF4B58A79C75D616933A31BD5BC14A2743E4A1EB88D90DB1854
+F132A946B090E2A092F71CD84239403C0CAFE30A7900061AF680F855DA5E91B023830B93
+48050178113D7831EFB051CA8534A3FA88222FB85D1A1E9D99936C49DE0A1DD7C8383F29
+B9B2EE1CD7064488D60C7E76F4F2DB018A4B9C95CCBE2F9CD7DEDE9501BEAA9C0D08C590
+1F9211AEF3AAC99DEFBD5F9C431EAA31798BD7D3A3A5604892F44CB3B736E8F8F79202B1
+6E9ED3ED418EF08539CD3DD9E624BADD761A44835AC95D5D07F7D67B93EB70AD8E86E0EB
+5AC1D4263F51E84583E424D0444B673747A8B353A780A6F8549F11A4962641A47CB1C3E3
+C4A241D244BA92AB05E6BA17BE0D6DC648C1F9D5F88EC20E103D1589D0E86D2B27CC077D
+810BD20514BE94853BCCFEF33D7655EE94DB8559BE3FC78C539E70F84E20534E7A5D6930
+A02889A4A82BA058888AB3EC75769BF961283481CF006D73FFA088EE019BB4AA990FC858
+621437BFB2D79C49157B5757CDC8EEAAD540E02BE1404EEBDC0B7BF094B80789D03B5F7F
+5756535B392A64F9617ED0856A7D167A78032855ADF1E672851A439D9DF57967EFC56D44
+FCC6D878C31CE7904C70433721C4E981F2643C08D96E4753850A4F427FA3D984E00832BD
+53437FDAB0A491C81CD6CF81D8BF5247E01CAD335A6DC9A69962B5830DEE96B57C9B08A0
+A5F401CC9CE286D3FB2B24F8E77508E4182551B4EE7B8139B80B805B64923ACE685CD576
+BF57A5F538B3F03C38B7DDFDE686B8F79271F8E4E909960D6D36523D4A217E4036AD4C84
+1E228DEC38AD432162211F5BA65FE03E0796A29EB8A8C4DB9BEA37E5C15A4AFF900A3456
+723DD6CB1F8BE7C5372A815691A92B5F1DD97BFC89FA5EBCDCC61AE4EF0245684ED4FC18
+7631D4292A94C9E3BBA81159E3688CAF6FC988236FAD971D774B54626DA436D10BD42A1E
+86036DB36914728E66B8EEA3B432126A5C1F0FF3928557A3D7583BE21007D81D40D8359D
+83075211A8366B16613E1B40EB840DFCCED4063CF06117963EF200E0FC0A558B1B69DED6
+08A00C25C68AA7EA0D902047A0981330DB2788E994E2196FED97CE2E777C0213532CB19C
+A28B07792F57F19433A14D1E6506958E8B6483D3651A1EA10D988C541CDA715DE138B612
+76926F9793C603B1836E4E9A4DE110A69D60E0F9BB0D5DB9F4B67209EFBE8D69D4C20B15
+0640052CD4367DDCE4722A87E9914B7DF541DEFA52278ECEB60572E0CC31AFC6C30ADEF7
+5898DB0B4A5D00F169688EC5212983AD3DCA6604CD2B3FD4A351EB4661F025716B2DCA8A
+F52CE6D269979C1F7E7942F583B2CB678F8DC52CB250C603D48B206D5547816C220AF203
+609BFE7B53CE4C88178C95A4E8F2F8B4BACB1CA5EF4CC1E76347AA958F2789D441AA1193
+C56ED7B27A0099B3EEBAC6AA6302891D3F16A913D980522CDDD8E3303437EC9AFBC4858E
+D3DD92E3E329B34B344718E4950DE3829812896AA20A9480582570DC88FD7F4AC2F46B24
+CDDD8EC6BE4862DE1412F427B698B83AF5A0EA767778564F3C3CA40EA60281099297E104
+E46E308BBF5EF23CCA84F9D6A6F773157582EE0F1BC477274999637E199E269DAD3D67BF
+D3EBBE840CD906E73A31EC7EB044E41F6B72367F6EABF54DA9F1664A1664338E202105FE
+E7F071026D12CEDC2D86D581C496B400D58CFCBB7B2A551BDABAFAC1125090DDDEFD4F55
+55B21AC1F6E5DDAE6700935C521AE129F886598539C41D07FE2680F25442BC29BDE2902A
+07FEEEB0A14E4F0201483BDD99D4142194BA2FB991F76B35D0DC31526A417212E5151E31
+60F3AD665ED99E0C7E50A43F58B2D6A8A075A96DFAFEA84C12EAD776CC6A3445771DE987
+DD0775A8DA30A1D0B92ED1D1A8B3E0133198B33C58A9E79943083C1EF44C0AE8A12D3BF6
+7CE1EF00C97E220DF31245B47F4720DA1F1B66A11A1AECBC9183C654DCEE7A16D47A3503
+74458A7303ECAC951588D2DEFE51919ACE2093697639CF60467FE9E43DC30B9FD53D4C22
+DB1F7B81EC206548C1E6E6B6CFE038764C4702F62CC23C38AFBC762D24E7625804867B40
+1626B14B8E45C6D9641B591D868FBADB07FCBE00C193F2F13F174648665CDA538E8977FE
+E8B54B74CD4F84BDF7A1D2D1E64539F146D3D116BEBBAAEA5FED99C5DE42526EEFBB78CB
+F8AAEC9F769B94FEF470C60E0B2F79C7F99D8C9C7C32A68302B352496255FB3785F74B43
+B4A173961F9018930515E6D1A57897420C404F32B3A0E2CDBBF8B53DCCDA0F0954BF6F80
+2638FBACAE414DB6C63F60ABFF719EAC3831C7D5AE46AAA7BECE1B71875D46504E61C29A
+3AFA16498509FC57DF4B4BF40CD4D8D59399EEF835D97EEF06B373F6E006EC22FC61BD13
+99EB69F248D991725232C1C5BBFFEBF0477A08BDD42F32FA43C5F5C06C2BF639E1C86F0D
+8E49B70E134B038781A1E85AE2A16FD1364479A5A46EEB1191390F469D0C573079523D1E
+F2B049171F9345AC5FAD682E4CAE51E1717FB19F8AAED47B7572EFD188806BD9FAE5AB42
+37683C9797DEB62E1FD9DD5CD1D477918D19D004AE0334E7F6A705C4B6D01FEDD05DA5FA
+063F81B6C6842D81A774C04531F708045021B8F11243E2C3F3EF7FAF5BA95C117B9DD6E1
+AABBC678F5046CBB55FB58849B6500A1A9593AB0BE9E2CD823FD35F60A485C3DDA2A36E4
+D13984CFFDC0992E39CBE5CD18076A92820D874E2576C83A6B02384D33F07DF51788BBF8
+27DD031A3520EAA36248860261133BAB4441635E255AE14B59B37B35CACB94688809FC1E
+DFAD40EB2307B2E0B8303BD47A15F736F58A4B7D8ACC44141E5E7D85D24B6CD12591633B
+7A005A49120406ED1CE82835C70426862D94F10BE0A51C894074506444BC899136DCE869
+D20F94E6E1D67F579E94D83DBD0B2230E55B90E01088DDA3748DEB1A7FBEB2D9D5625149
+06F512CAB6655C97060CE906ABD62996B2F1EFB10585C49EB019986CD391C1250C9E290F
+435A19B3035A30B415C614D64E396E5AF2970E36BB508E4AA4A030C9A38ED4D04B967E2C
+F5BDFC66833DCC48BC43772864DC29337040BC9AFBBA5E6272CEB78222394AF8362D32AF
+C1AA0E3359A4DCF2A98F14C1876631E2C98E8E29C41655F970963592C4BA3D028420B197
+559C882A42896CA2FCAE8919352A02C39BF565A6841E3B181234E3750125F983E415A065
+137F3C67B80FBF6390B53BEDBD3ABF8E11C807C89B1420C37C790BAFFDE9EFFDE9092673
+DFC748B14ADE1A7B9883C545C0C145DA0D404571F94F4A161F7A747EFC311D1F52C33CF5
+993D987161F2AF52920FE97AEFC3651767C8750FDB45920C972401A337517BB88B3B65EC
+B1E6A67B6B0728E3A1E46B1FDCBBE1D3757D715F91AE74F3740D2329944246FFC50665A3
+87B472AB71CA71539C2D15C56AEE7951666BB869FDDB6D91FB4F90A00163E7F1F4634472
+46DC61B4B08ED312157BA05105B93F0F8DE781CFB59480E1B8596A3354C8783CEF52EFDC
+74C9D143C16088448B8A9CBBCEC59900B16961E845CC92AAF400943EEDFE174CB3E465DA
+6D92240D8CEED8557EC7631EA9D2B4F0758CDD9847D703A5623FC1C96D321482243A6E9C
+853FA07459B8DF72F6D6CADDE4D92A8B110566984A4B8678B8CC8FF4B2F4665030FC2B47
+A0102CBB3D8F4E0C40D761D05BF4B9A684FCE51A5F750093AE65299413225E64BB20D6C3
+E287D934DD3040DEFDA92AFBA6E79483DF64FE3CB9B265F7CDDB2F5DEA767D5967CF0393
+B7405BE70F810DEF309C5D2EE786DBD819EA4A4253125AEA8DDE8F9AC42AB35E11773CC8
+434462261939FE3EE8F30383450E3C6CBB033FC839332F6B6092E724274A89C86BB4ECCE
+2FF70EF35268E9EFD66F1A75222BAA8CC9F9F4BB4943CB28207C633004F31E0721FA48B7
+D1E9D10A0694EF6A58A1F01EAA6BE615F2B1BAC49B9CC0A77FE251B7CF5611ACB1A0BD53
+8ABF1BE4F584AABB038F4FE84606BD96CF25FE9146651587023F868B13557E4153F2FAE2
+070BE3D081C4CC5410E803F04FC2284EDEE54DD387DD61F0B3C2A1815B35DBE6FFE337D0
+7C50DFF344C2A4D9921DC7FD0FBA8CA06FB07CED571BE57E89C3E429B40F0D8EDE7B522A
+32AF6249D1EB966D27A5424495A82F15DBC8FC90B8619C0363AFA45C26D60FBB408606D9
+A37B385582513B61641595F7328A1EC830E90BB7C8B186552E2F645E2F09553BAA432558
+DEAEDDD0591CA23F19E6B9D2143F0CFC9550A43DE70F69A66A89C4E505E02FDF77C87E3F
+A3768B12B7B7137C5DF761978563CC1C81AF9B7721D1E21A7E18CFD583EE4BC928E75AE8
+3F4DEF7A587D0AF30DE0CF4D74872360DB3BCD6529906995C1294DB90C93B44EBFB95527
+3D0B704C529EE441EA8E1EE2E3B03B7BA50CEC0C34AC176EB56AADB692EE9A53C215AB0C
+5736A3A4EC7E37F2ED5E4BDC7B82D0E35E06915E068FD974F225E70461D780906A7B7831
+AA07687C177FE71B84A4136C7A6BF2FE6408A9C7049795C49326069BF24244430A960ABC
+ACE67533486D6D5C6CA89D71904C5C48D02969628A2184F6B36C5FFB64A671116196BBE7
+4FA57CA9CC66378C0CF086FBDF05DFA609BCED01EF21DB027551B888242BDD941C302340
+0C2622E8557A0E12DDF981313D1F5953B57835592C8828C102C16EC39D06B63F31C373A2
+5077672A1134EFE0D4437E8F38AB373B214EB5F2BE1F6D80A07E1AA296AB7F974EE1DD76
+EED4B86A3CBA0E3C9D9F1A12F5E58913054D4557C2CC1C2C147196C7CB1435CC90C5D7CB
+D2379FE287CE562D9B7660E157E175ECCE8AA94B1173665484D19D65A9B191D4C09D43B7
+90D1DA313C09025020B2315B0112B8E059E01525EE0AF0189CE06A307801725A26B2B3D1
+F0A1BFA9056E1D7DF67B1A8E82946D5328AAB07A9D90E21F5163B1E3DD6D789068C8A1DB
+553FCEA69C14609A69805B3333EB608E4744C58C454DE66723A7794D09DEF7C6C981DDF8
+1B84B3E498D055ECEB6E8372D331861437AA69AE7D9A0932F4E71B9930D6F2DC38161257
+A32B87A7D37D200A5B9B5B257C0C9833BF04F91496BBAE83E9AE742362D8E74E0A4AE5CA
+029B5CA078EA6D8F00B1ABB84A08FF1C03BA539128A42166D06E09FA8AE71B74A216ECCC
+82DB316C9589BC68456F8ECD9B4BEF1E12506D537B6BE4CBB15C969B05D2F220B6E2678F
+4F2D497DFB72D8F9584FBF0D363547F84E1B28FEA0C869A090FADD5B90E36B88326F6589
+BCFD8FDAB3993532F04949DB9EC2D2F2F1360E2E75AE76A6796A2E7AFED4DAB1B7B10D54
+33AB4C76331AABAE0D3ACAAA62C1BC3F72662EC71B76568BF3450B45C2D09BECB562A49D
+3428A9DEED6D956CE1AFD83D90A0FC021957B45B8C03CDE0579EDADAB4BA570B29809545
+3A1D56FB60FCF22C038803ED3908D09A5E4E3EACD180A6D355FD7EB96B05305E841DED98
+07F75F133A6CA5D3415D0376504634B8DC2AC7A5BB53F9A3A032A878DFFA224FAD7A22B6
+9416767480B814D12E7D316D07AE8AA5117C04503B2E194F5CE94EFEE005DA30AD9114C8
+BA99323CF76547C24D607E40B62C51D86B672675E6F0730ABDC9B7B186D7EFDC4BEE86A6
+6456C4074BAF42818B46DB83D70FC8D1CA702CBB672B38BF0E776B52755468462B2EA034
+DA32113FC26E122261018D3A125D174D301FF7B16B57A406CD70110AD35710C2B67B7330
+CEC7B6B33770572AA9227AC52B0D6C6D0E25515C5844FD5D24140E01F3A4099BE114B94F
+DB65580BAB585F3561FC997C5DFC1A27A5AB4CC6DAB5DF46F3D575316C81A2049089FCD4
+1E4740F4D16EEB08F117EEED488A6A9DE20B498CB60E48EB5A0839134B9F102BFBBBA982
+74ECB5679EBC7CD178B6F179ED979AE8E9A41763A97B4E14A7AB6A2C1A446615786CA3FA
+32BAC716808B486702635502AA9F336C101A6E6A5F3033F5A92E13B9DFEEA4E7E98422E3
+3D051264262DAF41BDE94B43E0A375A42C59702EF2C43445C5EC7B6002BDE7C342F52AC3
+A5844A0EE75F5670C8B80AEBDDB2FE3D28BD6961037C0C54BE5ED708F683D1494DDFBCDC
+976AB35442BB049A5ABAD1246996AB4E56CB0DC9596EE6ED06D02BB2DF9A7C9CD5B07BDB
+7AD345607291736909E194D93DC68A1C612945A264A81603A9D0DFD5435DDB97F42957BC
+AB7D6B400E2943A3F455918135E6EFFB0AA5E9C3509860CB5727363AC596CA1D08979225
+814CBD4A22CB979E1A6F6B9BD0359E782E852F51DAB107EFB2C2F1CE5D69D5471704572B
+65A8B8B45305088AF7FA401348962022C952067504E39F3E879025FBE8E5ADD940B6D4D1
+737101C3999B9C6F58B259219AF84F1C146AE2DDF02C492FB5F582E739F1D1A3A0752CBD
+5C401C91BFA7BE13F936DDA112AD87ACFAA7DF7CDB341443967E8CE3091F024329934DA6
+AE431187CF6C1955744518EDEFA73ED94EF60764C59EC21CBB08EA73512314A7E0658DCD
+B61CDF37259EDE297DDDD7022DF5174DE5FA5216E566D1AF3249DE12E3A4EEF90A125EB0
+5633B85E3A12463693D5E2D6C01F5353761DE77FC8BDEF35FE0432E1CE3254F0F50A1B77
+C2245BB6DAA558E893F89AD98296C328D37C816CA808943AC488BC0090A4DB29DB0EAE82
+C89337A7C3FD1B4000202C42489974411B7B63D69BCB12E7EE7173E51D1DA17D7C82E6D9
+F810E76A97A9F118F1989B9DF448249BA2AD095A9698BB74D744C9ABCADAD6260E069C9C
+73B05D41228C475C1207FB4AA8A14562FDC889D6870F5D045073F18D8716944B52A7F9C5
+0005002C0D1032B7F3ED2F60E9B27D056D1BF9AE3B1C9B4AE9A76EFAB3EB926376080C14
+5100DBBA2FAFB47E119443AAC33CD4A49DBB8C0E8629C56B8427AA94A6E076EDD6A16574
+336E6AC1D23E04E9BDA3CD2C926604C4E8170A3B9599FBFA9D3C8BD6192020E0296968C2
+EFA8C621C0FB0AFD399FD8E14CCDD94D5C6406D6B1A2564507BC818467322EDC55C3A3EE
+E343DC08142264D205F542C023F8C82CAFAF6DC194E2016202247696F03CAD55224FDBCB
+0E8DD2C9DC53F5BA9DAB23C033C788CBA2382EEA7390EE61A9672345EE2749CCA136632B
+34AA12A5FC16974E9EB835A5598ADA0898BA5C87757D5EADAB5D0F71E4B75B8B1D711128
+E277A973EC136CAFFEF269A28B00881991B33CC8C5DF618B95C049CD97D746978B6C3AC0
+CB9EF6A51BD9702D0C14AB484DA4AC2400BDC557CD5E57A2421ADEC7F2326370E6F5D5C2
+9DAC782AB9255D0F4D0C98E7F9E0D7D31B114B1BD18AA2510E4F4A97582A15F170C12EFE
+80842C1D3FB9C74F40DDCC8517FB123EDCA605305E841DDB1E5AD5448DD4972A20045021
+196CC951B8C99E3F000CF984252686EBBDE5DA0593C8514F131FA94949AAE1AED3E780CB
+0504CFAD74171757769C8B2F51D54DBDE3EEB48E75486B4A75E4431F8BCD1A985C4484BB
+1B5CA35F1BFE7B3A7C41A42B66756A229A7A5A0DA6B7A5084EEF6B8AC804C17F1E88E5C3
+D0C1D55BD687A9803A1AA74A60C0360873B37C79B09A1B823C3C8AA322BFA2E9B77701D2
+BD815C11DF5C55C393B73F98B73A500EEE6CBDC9E4F5405C73C3B635D6D0CA58BB47D41B
+25149C3962190A1CB6FE7A8D6D4E26A205733F42BE8A2B0A8B4573C92CC98FDD07318671
+F3D3D5C7C757DD5AC7350F64E70381D190A05C674AAA796DE36886AA50955B422BF5995B
+6F8EAD32715151456AEF2AD3D16FA3120B0E95D817F9CCCF7B2A55D529272B1E1BC060B9
+9F6342A1229DD8EC1DDFE9B59DBDF216006E98EC1AA5A1F55EA3D7EDCE63ADE2D4A3BE57
+E45A1FFFC04D1C9F1466583BB2AD58AF695DB3DC075327144B35BC40EADC993BF3BB97EC
+A3F7756324E46DC6F4A13CE5266433C90FDEF6F46D38A9CE9DBD993B941AABE630ACA87B
+B14EE46C977EAF512A769611F269A17D6A7889F28F4D38CB9F20580F6F4F5324FBF8F6B4
+F6C101ED306407463004171F3C8EEC70B9A2FBAFE213D1450F9E368E56183F4449780F4C
+20171C3354E3AFD7D31B9CD7979F57FE545B06F40AB613B5B91D21D9E50B7B01E057F02D
+DE24F4720972007D62736223D8C3C442CA0BBC8F31D29387399CEEC87700982A394A11CC
+C73E118113558A4D44BA30924C4310F7C83F2C6D3FF570FCB031C12322CBD38CF98053AF
+BEC2E7DA168EAB3B646713AD5C3FB0CAC7BE1D7CC779FDBEDA2FB78CADFB0EDE7BC13C17
+531C20EFA0C63BC58AA447545EB89FE0271198D71AE26924F939A063521C082560D97EE9
+6130A6F6EB7CB75BADBA1A8A00736860986EC623DA35F8210E26B843345B941C0C0B262E
+B8EEB95482CB4EB437431E541F1C2820699258B1D17229E1DC8D7B170742CA64773F8062
+330A53950E929080661E588C1E4B85B5235130D50876837EF131D3F01CB0508954F39838
+ED8A7F38E5E7AEC8A74FC71EFE42E03E01B3CE075AC305B223B03944F9C39193A9EB6334
+FE05EFB242FECDEB2CFB62E0852B8AE333A92B8CD54F33318B1B22A8FBE47619A40D2CE1
+226735134BD860754D2804FC482441D48F1239B2D53E0ABD6FA1D556E4551203DDC5C79A
+F0169D0306F1BD451D9FAF5A200FAC1C833CD3E72E37AF7D95860D2D04A1FCAE8EDCC522
+255D759C135B7812CBD0A6EA9BDCC084E528A533B79FE9CE5BA00E86448CA798C6CA5B05
+5EF88EEB8EB276D2E84524D64468EA6D25F062CE4D47C1E15CD734BBD04308FF67DA439D
+577A00E4824EBFCB2EA5A00B55655157AFA0DA8FBBBC520A39B37D9FAE15A2CC90DE8B11
+9F69965BD22F20B63A3DC8C71A15510F85AC76F3248D2E5593266D9874E3C099649F78A1
+85F07DC3D9C1CA1FB2FCDF2808945571904E3E37A00EAF493BFDF11E9B6D4DD951C76EB9
+9BA671641E4A3FFA7C16F3AF41ECE3EDAEB91B0D8065D2324856C13B02C6666AE0DE50A2
+EB8380E0CF9665C3005EBFBC1AC075D05713A70CDD5590E7B9A54CDAA5F5BD2463AE744A
+A12F29C1C2D241712C3A80DC860C4BE572905586FCF974241213D073D3AFE446608B31B9
+E4F368D5627A50E0D55F22899B18E8BBD1DC96EA7EE8411650950B38E5E977E25A210070
+B8BCD0C109AAA5E1D838AFB35A25B0C32267672D34D5E1F139DFC10AE6D23F14B07190A6
+0DA8E6522D3050EACCE19A9D1C762BFF247CADBD1D1F172C006DB745A3F4D05D33957DFB
+471AE4ACE69B8AE49D8257B8B88D36865C0301D3DBF8114850A2B05D2A8121B3335DD399
+067962216367A8E8CC834D69BF7E16D06B4C7F602F908DA3903FEAC017228C976741A421
+C49048140D1B8D484153AB948A01CD7113C0AB9BD5466F8A26557E9F984BEA514EBE72E8
+C38FAB5F634EAB033C960539945FFDCF63E1DF47A8C6BF4460F6DB6778BE2D90B90BAEF4
+6AADCACBC8D1DE9BA3E9D4A2A8EB70F5CC3F02ECF6D76BCFDCAB9BBD36DF52DF860D64E1
+F0958B74361BA4298D792AF1D119905FE6D3067BFA8146CE1633D5C4658847F3F9E18143
+F1AB4D35C953AA5105FF94FC0C345E478B5B1D4584CA7BC050A31740EDE0FAC5EFA57126
+2CDAE360AB92ACBFD23807A0394160A8EF0B0F320CE3685040D091289DBCE3454B1ED51C
+83D8EDB2C86C71805DDBD584BB61E88A673ECD1535F5891EF7695F182F783B59ECBB0DA0
+B445D7AB5DF5C9BD042929611182301813145BAAC4D54644E93BC8FD2CEDE0207B5D60ED
+FF95CE7CC60DA632FEA04F8BC518E4A5197BBE065062556EADE480A86B8A2E0C9F1BF739
+1102D97C4D6A33B05C2EC5F457306266572C06274ABA9EEDB8F3C4E405EB5F132AB3E947
+CFF44017C6D8B79980DDEB698BB03BEB0C864A0766EDE34FED65FA889C5F149736CB7640
+B13BDA9CC6D5BF72FBC3009CB4FF5A877CA3E973A2A08FF25B212B8665DC4D6630B6EB48
+0D6E1E8DCA6F34AC6EAA482A4C6AD1763E17665BDE15BC08806A3FF8BE68584C8EABDFB1
+1E415329EFD07459890671D21872E0B0CB2EE1577B4A9283F224E3D0CA7106ED0C91FFFB
+4A3B8CBDB5E528C8D95D19741F16DF780F6D49FF6815351D0F0D92A0CD72FD14A19E1DB9
+97C3CC11BD6FB2AEB5281951D508A3EAAAFBB048B87AFC7CAB9BBE1D1C407D52978B6AC4
+6136E779209453BC2A6A86C198D1DFD8818526715228EBB5F411E1554004F48FDDD2607B
+E0D3979B82E35B78985FAC19CC95022D1F0AB9358CFE21C27BAB89AE4B03CD35565BC65B
+E6E25BBC43F5298B14000AC0867BAE57BCBC40E938C304F37D9AC390A90BB5ACC906599E
+789066315EEC0C15FDEC2F6E637A3082C85B2ED6BCFD621F033396CF1B7330D97265F873
+C92A64271C6CD63635758B05C10F67831EE579EF0B4AEAC245BC87541C1E7561E24B5E01
+B323E220BF1170BE5A4319684883C910556AB899372CF97C572D1AA86A34D826D6D4A048
+AE28B9D3E63A00A6CD36A5C4472E1B7840FD3B09A16190BB63588E98921E17D4180AA540
+56457195934F082F0C0F7D104E9271FB8E7D0CECCD395BCFF6539B76EC3FDBB1363A56ED
+366E8F9DD48A9349E4DD8A78C5B683E8365F3D0B4F2F8DE3D70B0B8825667406898EFF52
+A957499AE83E6FD2037CBDBE6B9265B0CB7323F86AD386F7A65CBFA93DD00255BBA82F96
+34A80487F68BC69000869F6CBDD217096BBE6BD9179DEEBE12422C308CE023854FBC077B
+BF1B820172633D8F70B26A302EE6B64258FE46DA73AB8C384756200C95A5623D0F2A41E4
+7EE54394A784941A06F082C737B9C6C5855C5F11729D6777E38A6B5F061C8E324CD2469C
+37B564AED2568502B980A054BA7007E8D9ED7733D3956BF5A3AD62C262CFA0BA9BFE0772
+7B67909D59A0084BBB85DE630245D514D86A920891417AB9FBC93863498E04E1DB27EC92
+6F5455BF6A5D09BB6C4968E10A177CA4B057E7D360F4646C986BDC5FB0C7ADA94D69F257
+96A37E10F1C62FE65D66790A0599D0A20ACD87AE4ECAD36C45678542E8D8E364DA954F9E
+E832D403BAD839441AA6F7118FD8C18B5C36F20EA984755E672FD1C2DECC0F6764711C3E
+7F6710BB8C7911BBDDB001B9CCBDD363B8CD618CF15ED57B63E5436047E7FB5BAE45D062
+D2EDEC99D9335118AC31D73AC1770FD0E5618608C7F42507753B5115520D4E220339B3B8
+AC54C83451996E8A489FA86B1E6C990A5000614688D4C29AD6EF8010131BEC1AD2670F9C
+DBAC78485175F999CDFFB8572F30648EB8F49548850B6CBED30114EFB970C8A58E814239
+CB0C1A855ECB24E0E38A6F4AC9EA5D255A9EE180F41213F8168F03E4F646411AB5B4AFFB
+B17C2533092A51313D3556E734FA0970E0760CE24A573A511EDF00457F348C5E465C1AF1
+198BCBA0CA6DB414B66EBF68E557E2EA72E80D7615B3A3017214BF1525A6CCCD1BBB3925
+C42E13E162797DC077B2674BCA2265F48F72407B24CA2002C2DBD2DAEFE4D0BF1B1D682E
+40B74BAD6C4B69328848F208D5ECA1A49B6F59E89B306FC5C47E6C007A5B0E5380538B38
+1DAAB61199AF1857C9D0649570534B486FB5144D9588547716F848A8015C8C2D21995D4C
+860802DFB07E4DF45E09C7D7FD5EE824CE4128ADF624250D69ACC87A0A10F647E7575DF1
+E7ADE6B0BCF063411797D563441EBCFB213F200A4CE96623BD6CF127727364E0450EFE99
+288E9A3B1FA4A1E776C9BC581931B72749EF0DF7D786F898CEB10158B705BD15B6A9ADC9
+9C7E2E3624905EC361BEEBA65E43FEDA49EB8F8A85187973C5D19FB54BDDCD79E42E2C08
+130865F10D7D600246548D33303B617CD6F81E0A11F4BC23DA3B167E5B2FBDA8BE051C49
+536C4B0940C61A954418AFAD8B0B19D85DEB12B1219DE27FF75797D0DA16F00F80AC113D
+F19AE8BF86FCBB602F3BC696611935FDCB61F05EE17FDC36E0B1087187F80D5C3EAE1B17
+DC1BA5817CBA5C3CBAB6BD6455AA2C3B44B57494B8BD08859C1213B24A62755F7CCA048F
+63F3F430CCEB00BBF39343F25AD4B6C62039A3F7B943344F86312E7566620694B77C5B69
+2AB977A7331B5F38D883F9B7C4F89E4A66F725E0EBD8E988AB9AAECF32D31C75A3E6849C
+32E4F06196DB937008FFA15DA36CA90BECBE909AEF6CA20E2315C82BA27385D08720E1FC
+BD5652AE843BE5F3D457B7F488E7AFDDDCD29BDF7ACEDF1075ED819674E47D0FC92DB7FE
+0AFDE6D58685F855FFDF52CE51B9C2720A82712A4B7BD96DE3EA95CD1635ECF7663C1D54
+A885A6AE72D84462639C52F987138050CBF73A5504F66D1430DFACF226FF12069A80ABDD
+0141CC2E05524BAC464CA4C59AF2912A2A4EA112F8C8A0BC4C908BD6C0BBA0123110F3E9
+CE3A216081892A19AC53FAD507E34110EFC7D4699A98849C5502F9DCD4418FA81EAC9481
+E4C20B4F46BE4DD134FFB03E47D6547D6540E1EA036167460F2922629E01ED36553AF423
+0050BBA670A4B74790B213D70D7ED543F9787E8920551C4703DB62110EF2E30DF12E91F6
+8AE86C3C6F9EB3043C162C0A0CFF7D4FA90CFDA5278D2B47D265D06CC33FCDDFDF3C68D3
+6BEDCBABB491F89962A46F90923C51EFEACB39FA22A36CDDEA38855682F126AEBEC06558
+94CE26C769392D71F1C4CBC34E3A4565EE74D67AB272327B457D346B756322FCA806938F
+BFB118244CE3B164ABB58135A96B7E1211220995376CD058DDBC291AEFEE79A41501AA17
+BE5200BA08E047BF985A97A8DCC1640E279DD35938B57C186918F163012A4C947D665449
+5CAC149C96F6A40502ACF8BE05D671777DCD218EF7FFF41AF93A80418A2AB81FA89120BC
+91A462F034E8801E1251BC3327321C7C0652ED3B26CB8B6CADF42AE3D97A8DB1A732E452
+FF187A97A2E03372667F91825FF3CC861B4122A1A0A3F4564323209DCB8FD2A886E95F58
+1539C74E4F5A0EC5B63DFB416F3859B46DCDBE7D724DACA0C5B6483FEABF3F36D6B13D2A
+49DACF1EAC4FA6C7B161A22CD876F5D511C2C2FC96C8B3AE53311E2D9468874BBB9E6B4B
+D18C5DA32F4E00923F59D2FC2079BD4BEDFA9E960249C650EADF2937CF7E339FD103CF71
+AF2549D4E9763E75A84744E73F70B669B6808258677265A9C2A48D95CF90D1E1585B4B60
+D19CA105909FE1D0EBCF533562ED6953C71C3CBD9CC474B6F6418A87C6B608E9D62CD3B4
+15565A14EAA18B23199A1521B101314B38A6662F5EE6390C9DEB538F5AF1BCC84DC9CA33
+E2D403FB1FB1A2E12D485D534F1A8A27447B5F9F13ECE527F7CD3CD9144AC5F137637659
+8199D0EE633CCD95797F4D55447D3105AA87498F1FC8B8750A440C46ABF820EF499F9D5A
+2818FFC414EEABC029AD6F961CA43BF94BFAEEDB8962A6124A192E1343E16A5E20204016
+B5175FF8252310B60F276148849E8556BBBD44CB9E59F5992AC845CDB2BC3B33BD7F0816
+2C36B7D91BD17A37F77A7938A5209FE92DEAD16A595E91917F6E49ECAD8C7B01F1565089
+815BAD961827931E718DF2B1F9743B938ACA21B648916FA76C5C99BFAC1DA9526A8F8793
+733B8CB1123A12E1FAEFE75332D850FB7F296539E76031DDEA6851EA00D97F7B83945C3E
+5C29D9B7F31B9A7B541B7640C17347CB2E39C15FDCF8C8B8ECE605239020783F333064E9
+ABBF3236976CC021E852C2D1C1A95D6DFD5746E076D14E75D2D31D0E93260802D9B4B846
+865DDE6FD59150562F6EF062B5DFE7C136978FB4A84ECB6AD463E199CB6ED2A9EDD7CBED
+D8BB618DA4E68319C7F194C0DEE2AF19A36943837505AA05FCFA86550C704A7EF74227D6
+58BFB33945D1E1FF102C91F6378D54AF74F1CEB81BEE7A848B8C933E4F9AB1D6914D9010
+9FF6C47194AFE0004A7245ABA2CE53A6C0B8636FB445E1D27E631618DCEE6E1FAFA19B28
+A3FF71FE46241F832D43FA786CAA4B5125821F13BA3023B54DC4E59CBB027C1720432DED
+5D53E05E2E830F53F6CEFFA0F17394A13EDC3ED8EE8493523394C5C73CA15C428E481D73
+FD4BAC226F9B923A1BC380535B19161F12034CC22DB93B335E1D603F8FAFF5BAF4410A02
+C8D0391C8B118EFBE289DD957956EF0CAC55D68F2069FF4D24ADE54DC83286E790F7EC12
+2EA9CE466BDD9175E8D50EF54A5219997A440C689634B35CB4C440327CD35CB05AE77E39
+87D742854CEC4E4784D4C1B06340295D19C1944BCF826E96FF84B4C80E173892B6DEAB45
+DFC0BF6CE1142215881A64D73D10AE8BB835CAFEED23A7810FB3FA4E8D811809BECD7062
+2C9C6CE8725C331F42F991BC35674C0E451EB19887FF4792D738D4E22E4BB897C03E79BA
+7F79F5CBFC2FB014BB58DEFF61A4AF62F3029F6829CF1DF5BD69FB1C73C68E36F2B3B1B2
+30B1D436D6DCA96563DA655E275ABB2AFD15D313D000D8E3F0D3461421D52B2A22623249
+E155D6276A5E6E0B5746C1BAB10B628092CD035976220A0121A3D16BC6B6F222511DA119
+E245943C5E7D68E32308EFD355CA3438436A5942292295282CB1FCDAE8B7A3AD3CB39CCC
+5A6DDC8FC771700383C268F4D676E9DBDC33C14688F23179089396251728AF49BE24D02A
+7CA4B1AA3CC148FB87E7C87EE41FE22723009FE89BD2DC689DDC9F034931ED7802B014F1
+C20D8F53EC110CDF35B8360FB1C58C9AA0F366260F36D21232E89FA1314476FFBA7F3AB8
+935147AF814D3BFF97635B11AB9EA47F6EF5952ABE438B536CF0FF25848F7480DFF36F43
+7CE6BD8701F4394A80E4D62731086ADAEEC41E6017A8AB72F890E9ED036C13BE24A7F2D0
+ABF1999B865B61349C501A9024FD08A319FB8E5DBA6E7283E8FC0BE48B9672CECD1F1091
+23A155914F163FD67AA466048A46DE447257D86C493B90178F37A23D66D192E552E46CB8
+E3C6D39B4CF574DF2C38CA6C74D0881E6E5C068766AC2898185BB326890F530984F3F31F
+57F80C0220E2CDC14CE937420869C037B4C197C44B59FF91FAD5DAA875A7802A293679A8
+2AF31176B3DBDCA9FB5BF5C40038E7F119C61B7554F35DA79D942B9BE756497B3C9B7A19
+E5BCFFFD7BDD046EED61780D4CC5A7F8E3A78B7B2414212870BA0D27FF3C01B2AB030EEB
+8F036B48673D6AB3460BB45939214BAB345B8D1FD6D2CDD3CAB37376244A7AC0FA3DF861
+60A193EE77CCCA93B2D984FA9CF07A54E9207EE127EF5B877A561216609567F9BD907BB2
+11A7383579FAB14FFACCFCC0E260DDCE27377C32FC039FF52A5D8059E7D4CFC880B0D634
+51482FC24A8E711B3D962A0926F4A0FBDF29036E0499FE6F5D115B7A95A059D6FCC36C87
+03DB34BB67B65F511637D91C428EED31371E9E9A00FA82BAC36AE2FDD0ADAD995E0E96FB
+C909C5AC04BB213EBB5865A2CCE6942DD92EC73AF8C7D554A4B32910C7CE57EE79D11ACB
+26D7CADECC469CF16953A50DDB0FF9A909F0382FC342CB38E2F3D8EDD0DC5919433386D1
+14B708E1AE5F01C2F08B8C8741D67BD1F02B4934A76D79B095AF43B68958BDE13D0F570B
+71128A40A050BFF9C5D944C09A4B5D8AD0758B497771699B4E577436B15E31EF7D804663
+F768B9F5C9829EFFD5B479E1A0813E49D48705EFCCBCB2B23A7F0C39DAC69E7E35D7F4BA
+770945D9F36A39D251B6CB76C88AD374E177B0F9D703865A69CEB6C0157419E781888F73
+47D0D641C43FF3521C3F380E26ADA5237ADE8C5FEEC8AF046C1B46903941181D958F16D1
+908D95A62869DE2DFD0AAC4D7441238B2ED50CDF729B10961883EC733F806C587C2D8F7D
+B205AA3E7F6E34D5A2A2003E8CFDD22A63DAC1B04A11D77A6830CED7D9DA87BBD9E8D278
+275D1626D31054A23E9283FEC3D634BA1544AC5AD0E28DBD03C5CABF697DEAAE65D6167D
+0E2EC4BC6C3B91581AC32B45F7ABA1B825848552D1413D1B5111168959A23F54C5B8E5E1
+B49C4096D5F546388E1279891E01D1FFDF63940F7AA520570B408C9C2CDA7F5A4B058919
+53B35D7523EA69927469DC90F6D8E15782204AE32885DC6BE6107D5EEFB29F69FBFECE44
+70CEFB37D0093844BE3ED424EFF064CF724A54B6B720ED020E70ADAC6716787FEEA1F22C
+84A5E59BC6A643A29F50E3B76E6658D5BD8CA3554EA68CBFACD0CA0882B8E3389EE7945B
+AC71B219233EE299C4C8FFB3BEB77BD483DE2A89DE4E697FA3A057EC47448CB99A7F1696
+00BBE4735D36408548405A8D4CE4209445DD0C4FFAA271ADCD14DDAA1598D44247156649
+1009AFC9B40874D4499857EF50BA7038F25A2159AAF9AC535EE1BC83E515D1439057F042
+C62DCB063AF8F014090AC771CC83DDFFFE0336CD4F14E3B6397E7AA442FF3C385A5A4B59
+2080801CC0BD5EA5F608A7936BD16248E3CAA7B49A475BEC9720EE44A06921A93375F344
+013752C467DB023F3F01FA7F427121DE5C4AFF495A06932C52FAA62C043B22ADA265BC90
+61B7702F9E44E326B54A423A472D23817F6135E05C1DDE477A9E27F42F5555E8FC22060B
+D53ECBCA45C31C09BACC68EEA5126EE5E73502F2CF42BC5916B95590B778D556C4DB817B
+2780787590B62405840D01F6B5301260E1EF0856219246C2CA7FBFB307FA728241E9A08F
+F8FE0F6E708228172358EB98895B3C3C7FBAB501BEA9911A6C6769456E491C89B2FBD751
+C9339E174850B679B47118416AF8E849438FA52C4E2A0D1D8AB94385FED3747F9A8E78E5
+47FA728DA9C44F5D2296072A8ED789FAFFD237802988A20A8C16F78A50D2AB87A2BF8EC2
+8503F757AC6E9E556686A37D84D7B9DD81345E70D212D3D83E7D074A2BD9191D05205B27
+56E74664E1C3169AA601EE6276EB238E3EB9586C37ED4089E5C7AF97021FDADB6AAAF8ED
+54CF169A574A7A6066EA74B3A255CFE9B6FDC2EABF4915325BEC03173370C41B71A65C08
+C4C809A78F52E89A27514E2771572235B8CE4E21229953786A90542924444BF56C163D41
+BCBDA2BD5981499D1BBFC7F7FDCD4EBAE43341EE9EBC04A5B3E86ABAACEE27AAAAEEA722
+63298EF83E19321B7CF9B1FAE2520159C2731E6023FBDDC81296BD2303788705D7A6FF72
+5ACD9365879F3742C0A375E23B124F85E2E533F958EDD9CEF05698E4F7E2C035EE665851
+E1B9B324D381BECE9AE126892F2B51826E44B80DF026FED2832BE1414CDC410B142E9248
+380FB3EF59A1CB8944C21E3B8F0450293E6FCE004AC4B002989C877AC2648964D137D881
+7C37A778E0EB56D243F6606A883875808323739C0B55B5F82C5BBC389566B7C24604D9E1
+9070CD37A2199B77BD81C6C0E4317AA361CD7F3D4CB2EEACF59D09FCB317C2E5656DD9EE
+54D8D9C2FE364E21FDCC38F9FBE33457A70B75A4F9BE1DF8B6577B9E103F2276B77BDCA6
+0AB499915F331113F04C81F9572AFD95245AD3573A195D9CD1AF7D26FAB028F7A821DE62
+8132A99E8B39D4597457CBA2281394CF68069397BFB22BCF992989D8AFAFF25129A9F9CE
+040FCB4752291D822EBD224DAC909194EAA4A07FC65F1EDC6C2D376190875FB8D2D19820
+7F71663705D83FE18CCAB848C11C5E112193D753B6A2BD9183054AE6021629E7927E4064
+9CEB4114C9B59F9827B98A70052FB67B5C45360C9C272DCD0C7DAC2A515707F6B63B2718
+B53B84441A28F777122D848B490C796185AD91E8474267D48B36DA7E3A7F70FC0F9319D3
+F937FD90AB3859794AC608FB96E283ED974159234761B8A114C8856FA00353C44D5C3976
+54488B0CFDBBC5A243595E2950E2ADFF06568551EC636B7D18FC1E68130F6623EB109415
+5F58F46A636EB98B30DE84A313ED1ED0EC0C8032B21ECFD11F2292A31E24E702D4723F50
+632F9D91DFF52142CFE2749A16B5B81F0ECEF869A7486191A3A910AE94C24471231B733D
+FD6645C3856F341C0E1ECC17432635133CF66336D3C2C4F103C3EFE59FC7E45545A0A5A0
+CA19C0DBBF2B8CD3CBB482CD5BA7EBCA2CD5AC9E0C201FA4ACE28F00EB491ECEC3871AA9
+C0A303D585F94FCE1365117A59BD2644CE990F0A04239ED4B52CB5A0639BE554A2FFB03A
+B9BC1E6C7989680B41BE26D2B01EFFE47819E737BBDB28868E0CEA2FFE4C7300B82E3016
+3BEEAA5EC834B2A2509BE99FCA5B087861C63EE1F84AACFA6FD77543D91C9C2E525BE531
+C02FF04A1F50C50B1F9CA7157F8A7787DD417868E48A035904BDA647EACC821F0ABB4053
+F19B502075211F1E1BD2714EE43D1AE7E19F8D13354D331E1935BB1246544EFA1DE7390F
+7A561A6CC3F48C222A9C6C0B3A89714A16B3F61B6E26E3238FD641D431C7F6EC8005ECB3
+113C00A96AD8842746CF3D457F0F951D90C797716C3E8A08059207DBBB40D9095D8074E1
+069E36841ECC7EBF2081F293C194A044F5FD536D0F3B6551AD3CEA2FB84A5A32E20E34E2
+CDC9AF5E6839C3521EBECE2F4B39788F313FAB6D0F089BE45A7F4FB021D15C2661BA55F8
+691E8A9E5AE18FA617E5AC262F24962132E051BA7DDBBD3C5E7B3256ED5BBF7A670E0091
+B3AA0F6860559521C858CE6FC640029FD9D5FE03D1CC485A27080DE3BA08A36DDF87C81E
+CE731AF1CE3F87FB19F91E324FF044110AE7C39110F9787C7F69E9C09FFBE37BA8B3DD17
+9B1EA5E176D6562DAC43992B8B5AED68898B6D56189426727100A36D92E2CB96672F58EE
+EF30E90EC2569CEE9DA1B590F16B88E5E55FAEE2477E36E9CECA4D4DD9E969FC0D27CB94
+B5C3E738635D3C9AB4A0191CB553399EBB25D1D43DDA545A732B66DCF18A913EB214AAE9
+A408BC1E04449C07E114142FC22AC8639359B2413F3ADF5303088B00DBCD6AAF1ED46964
+F749F420207CE7CB3A27A4C260E174E17C6892695B3167B65271C232F1C67BCAD83B0216
+278FAD19834B58E7E1A2813EAB45DAC586EDEF11FF9CFC828811CC290C4EA40017A4BBD8
+889D5373B0002C0DCE55B2EABAB80E58B4341F386781264AD72C9B251255C0983AEB350B
+03410B4C7E7E2ABE655E3A7AAB548D49C1EC489006EF4167BE2EA41CAD999E4CD6328ED0
+726C61B51EDF0952909C38480A6E801ADC241B50A972D31C7AC63BEB3746172F1CAFFA20
+D6E1009B9B1E79308ED3CD70D3F2975B0D241D8CDFD191A934E83E0BF3A938E19B3C461F
+566B19516C068AD6BA4DF7CB37EA8343DB1ECD5CAEE329432E15147CE61AC4EEC2866463
+557C05CD59FCE1659245B7D8AB628F2ED8B24F6AD0B1AD37797FC20C098445EA1F43E3B3
+388550D0AFD24C74AAB269C1FE7596CF8F010D665111305ECFDEF52E89C240510D5D83F8
+FFC38DD47A537F55F7F79CB460F36812A1E3C26E8A7DD6131DA076BFA93D6C03E6E4C279
+D720B41A9CCD6A58EE1BD43A3035CDCE464BDC7CEBD79B867F30B0D15400B897A5ED7324
+A4A75568BD1211D036A5710F23C7A2E1D3F7E45C929FDA7ED13EFBEC7604427BCF853F92
+D954E627D0ED842663CFB64A2A6358C86F80FFB6A955C17B04B096D76B03DA9660D93004
+C44AAB74C40F99C702BBF33C4FE471ED4E6A0ABF3B15B340708D5D16FAB80D1E51F7D1A3
+8C7AC19A871C5D47963CE3CB961AF75A47C09B7AE97A3EB1C16D64D12A0798D5CAB48F68
+0E6B2DD1F7BCF7FD97719CBD7FCA4BC1CF31640675AB798F7A7CCD4E4A109E0E00A806F5
+8888F7A7091A9B7CFD350599C9AA0E7F679AB200035F48A57172C499737631A4F442F3A1
+BF5A3E5A2B77E02B66768DB9E76AE46E403E0E4BFBC1F14256ECD89BDF623F266389DF28
+AAC38991DDD4743F4A3B8EAEA45BF38EEFD1B7D3998B9B8542E78EB9FEFCB9D256EA8EA7
+6B56BA2A4849598F03483C59ED550D3508D12B35E4B82C2703883BBAFC0885BAE8B1440C
+D2E368939FFE45BFEB172FCC597F19B089FC567332C97C3567C9DA05A3B99DADAB2BA61E
+B9CFC9C1407322118C7B7BE2686FB5DBF0D31C5116F2F232AC8C3B6B1ED3E36AE2E9A638
+1E714212A76D2733DCF8F2BA8C1BB345A8B3D98162EE87C308539AEC3EC8EDA6CFDC423F
+BDF208A89A906314950C1877A12E14C1DCBE5033474850128DFECB859E33F6EE578BB384
+DDC252AF788BD61E95E5375D134D6457B0A4690D7239440FF37E9F67CF10D1EE312653A0
+22702614C537EE7FFC677F630A079A98139EAA23FA2764B1D37CF5360002711890C12374
+CE980C83FF11E102C7AC31E4D96862CD3B8A77FB59FB8F3932750F21929B00912332196F
+D9AABC0E4703C7BBB695FB1EC820CB6F69B9869FB819DD43AB4000BF70FA0320B5D3D2DF
+8801021F0B0A45EEBCA8BFE6B616DCA4641358A4A18CFC749B17058929CAEFE146183C73
+BFD0BC668BE2EB8CC7003FBFC5F79373DAA86E4D9B65953031DCED7595D7779FA985FB1F
+176161B955D22591CD434DA21E63FD9DF743B49B16A5ABE84E74293B1CE2BB4E2481770C
+9B90A6641984001AF9E6DFB280D37922ED6A77D3C92F9E0F82B4CEC5FE92CFDCDF708EA3
+47EE98261C07F434E88A2042877D47C813992A1DBED99A6898288156CA26C7E473988BE2
+F5EC8DDD0FEE7D552832B69523330C12C6F0A307CDA286454EEBEB0B236AF69390B6FD9D
+3546DE7015FBA1D36B08769D5DF07FFCC8AAAC31825F0F515813221E1D467F126CB9BDCD
+E95DF5C7D64FF789BDB3A3339130A974D96606CBB812C8AEE855F29C5BDD9BA49FBDD481
+14DB68A228B685F35B5C33A9CE2CA9E0C30690831780284D6A75C9F9D86CC5A492EA5264
+09E1A2736EABD5FEF257F027B7363F8BF39519DB2940A1DFF0B3DCEC5CFBEE09633B4DF2
+6C29184ABEC66BB894F685BCF2AAF1301B1AB15398050C86A84E87491489F15FD2907D7D
+ADD73C36FD0F7A40E021077CDD8AAA237DC9CB5E13C00EB7E91353BC58E0B8870BB319F5
+074B651F0D5179AABF87D023AFE75B3AA68D62FB959A5B6EFEA8D204C09F72B038A8C5D0
+9977F1457ED158E3BB57CE63EC2EE4577DE42F9D91AA5ADF0460374A36C972C33616D040
+2D8C1257C018B736CAD8BC182ECF63CEA524C8B3835E9CBF7618D930717C9DF018778787
+B5BD608E6DDE644B3CEC092A232B66420872C1412751FE7A72D604B7C01CB200506DD521
+F45DAE82F0C7CD4AB3B8E2E1B5A9B3D13546DA5A45A3195DC9A550D428882299614F9E8D
+47E1674C7A95FE4B8E5EDA9D9499614A78DC322870B32E916C14088CFA3A76BA4F7CE4B6
+5C979130800F2F2D998F48DC5A2EC1CD18496402265677FD28F48CB38145EBDB30D2BBFF
+15CA9FAEC6802D7BDC7F1A281DB9A6553B7D3F757A1FAA6AB91C0D31757FBE705EFE4C71
+AB0749AEFFE6768B35A0AC03636F4757B38C2F4C0A78EAA3557473913AC1AD37B72E79FB
+75E2DA3A4A7AA867032A952D519BC5FC9BB684D0F21A661DEBE79B1C1513A16D8E32EB13
+E8DBB3F132C87ECE0972BF63001E8B9DC6C3F445191D536F8983B142BD94DD8F41C8756E
+EFDB106BDEE3224FA448DAC03ACA80AE79B7DA40347D3C3A643B915C51BFCB861438C546
+1A59FB26B538BDFBB8D7DE77955A8FE6016F770BAB928D277CD4C2B3FD3839FE75308F21
+826B36084E485927C5DB75AA7B6133F468C71D218307B40CFE1BB6AD24E3C2240EE17084
+AF6C1E0D83CCE1699FDDB4763BC15F722D0383F5F4638785268FC439EB0A8C6B5AF7B938
+957DD111A83BA935CCF13A9DCBCAC9188CA67EDF1A6D18A34C956DE87418EA5E4796E59B
+D981015C8D276CF4D8884AE423314AD62781108BA767131E08302A926C44B858B792DC52
+FBD6D15B5E9C4CABAA159FB5BCA5CAD068A5A718613598B518D015D3B6C43A01A5540849
+EC15F399A1DDEA9BDC47B409B10067FCCDA5932FD02BEF518433D8E7C83BA8567A2248DC
+2271BB39F07414DF7655BCA33FA7811592168ABD559F49EC0F7968E87130093E607C2F1F
+087154DA681D1C92C1B5EB87BFFF15C7DB4F8E319E42BDEC5B95A2F816BFC0A0CE997CB8
+BCCEA3DF23280D4C922482CA09EDA8C31F9C5FD9C22480DE591A3649A29F0293F976F366
+7A66D3923D6BEBD0C1A1F06C11C2C4207B2981E91DF0C0ABC84CE8B7B23B4837C51E2A94
+A7E3AB209AB5B99D40F39B1DE342502818A23235455B56BDCED3ACD910CD92E9E71DEF41
+0E3A01D9B7156F9DE0FC8916AB29D79F5B093C1CDD19CC1FDD6FFBD050ED563CA3C60022
+404A2E53E9EA3186A3177A57FB4B726DAFA37A4FD45D2C191E3E771C0CDA22EFAD7915B2
+15CCBD2A35E04CDF4779FE80B980ADE2D2E71B8F936D905AD7382B08C43A3ED6BBC5578C
+80417621C7A3A87079ADF2B635671C36A1F57B971FF2918E14E80549150AB492D9709508
+ED98B983A9D40188F93847967A10FD16DFFE2C1276EACD959435C36899210DBEA62023A7
+ED706126E4E5E005B7608F078E3F0A42E87C84B37215F883E0F078127D47C4B362CEE951
+69F92B2887F67A3F1D02BEBF0277BA479264E7AD5E1087F613330246606F4907D3BA39C4
+644B7F9BC608BAC3107D9C66FF7CD9E9D624703055DFE0262E96B17BF017579001A7EE29
+4F4217B697CD9A397D35D8CB781D9FE282D9082D273AB082CCD017D7843E1AE3A41613F1
+F69AE113E8A993C83FFDBEDEFA92A9101B54D1AFB5BC7B41F3AB3C610E60AC17861E45B7
+34D7706BF6971921CF0E5344DC613EB31AB4E31775D990CEC15AF459BE474959EB24CABD
+ED3B7D6A6540AA81B806D326D7614808FA2039A6675AC11F4E90EED294E867A84116FB5D
+89BEB45F738B1275BBB4106108FB19D6EA4CA71E3B0C2BEA1EAC19D27EB928EBACA9DD62
+75865C4B86025B626202116190ECF58F149257C62C70EEEC110B540C636BBF747801A21F
+B32A82CCF24062325AEB3B5DFEDD49AE625635C34CC330A93F1029F3A3A731537A0BF076
+C938773406C1670F4976AD1AAA5D3629EFE797A1133A683FBEC7DB8C480B32CA888ABB6F
+049CDD5D65EAB1E23EABAEF26756618BF3CBA5D62286C938D3F6F20C731DB6044B89AF92
+F58FE18DC156E0F0D7A548C6D838F57899D7A693A6D158E5B9A19D4CCE4CE574FA1F9570
+7092879FA2C3F4AC5F223E3E0A174B97BB2CBC7815A20FF509B43D6EA17D515BDD9B3CF9
+4827C88EB2AC1FD13192752DB92070FBF319E4DD93EC6C9287108E248BC3F814CF3F85A4
+F6EEDCF1B78BBEE9987BB0767968894F13E299C79F50E052B7627584F1C78BC8EA588B4C
+FB6C1204AAD2D47B42955EEE8563913BDC8167B5E82B48F3243F218E8832BCEED22BEEB6
+1B434A2AA2E93CB5654868F0A7E049852EE328F6A555AE92CB23702AE1B71B5E6EDF1BDE
+ED68CA1E96EDD0A9B214C02A429479FE612C312D8B8BBE3DFD711D25D816709B78125476
+4AC1676AEB53B4CE261AD842C485829A8DBB25956041C5BBACB27B75F0659622F2791718
+110991560C261EC4834C976182843A56DC1918191840DFE95A5FA00624A6C24228805545
+4E7EDDCC9CA865B10991C4B73BBC16BBF6F0F4D4058FE9163BAC69EFB2A3269FE9F2A092
+BE8F9D59D9AD9F434998B44AB3892EA4360C38BFB150DA95EEEBA94B419D9D126410188B
+475E794541F41D5C9D12D96BEDA86DF04640E6D766F0276BA1D0EE6E3B47A758D8D2D6DA
+90B97B6ACFFA7D7BFEDF0BF7101F32248C7C72560F770D52AFCDC8F285846E00F5B0A83F
+346B85D71DD49927304D228E2BE7980904A813AD23D5EE752D210FA2EBF72200914C8AA8
+ACD6B586437EAC4287C0D3C569E1969E71797949592DD7E1A65096819C7F3ED6218F1D0E
+6FAFF3597787C9AF1C875E66878D55C64B2140B873C14F9D344E80F6E1434D0814B3C55C
+7FF47038B2DD9104B7E836E0804B3E4042F5E1627E4C871AF0C42B498BD34475CDFD89CE
+72E8D6DEAE27C84CBC4270348B684D5DB84C025A0CDD01F010F345ED7C75251990AC320B
+AFF49806BAC46C8E87895DAD7D223A89AACBC9745439B6FB5B8603010AB29F2F9D3EB3D8
+24E2471720BC1ED2EE9BB61682AD6328D642B131780AB02A598BA9806C8327C43E1880D8
+37C5CDEB36BFD7812569F2FCBDF7B68934689238D59AB7D111FBF5BAD7DB4E85148373C9
+6016A50269968F2DB4824C1BA985C6FF1AC4BBB99F57232795F390BEA26222E79BB218A2
+23E68505A11925BCB27A403E5D27C9FB0EAFB29B7B6396CC58431D267FDB5DA11A64662A
+EF150E3C268732F5EAC6C2FDF28FA507531ECAEBD55F4B0AB89D8F4C4CD41EAA211EDFD6
+65091948FF530681FBE7919E476C4DBE1397C51E4AA2C4BA1F0BBA3ED714E766E2638ECE
+21B08E93C2EE29FB886C75B9436D2ADEB232736CFB5BAEED34EB47FF78CE41C6444377DE
+8B7970BB19E9B52F5422305F14BB7AF0BF98F46D1D1E17B13E679C99112388F39827338E
+E36498823D40CAB56D7C2749AAFF144D3F89A703F2F416C34592AAA4C6C30A96F3287868
+CE6F6EAA22A55E06F5D353F441E62A851A138B6E26631EF586EFA6952D428AF7D71901A9
+7E5BA59D462E10388C233E191AEEA380D9E2E23579C4345DB63F7691D0378F950B9CD2C2
+C0C17A8CF6144A7E81CDB3A5DAF7F2AE6A5F92E6910CA0D7A50569EA890FF71DD49D5012
+BD3FA623A1331BDE94EA4D2CD2C538AF787632B6339925FD6CBFD8ECBA7CC464B31DFFCA
+F79AB027945A2C1E9C058ED8F0F3221A0353961BB2B2EA75876B74EDDDAFB7ABFEA39F38
+36A8E19C9372D3CD704A19B301BAD2801B16BEFF75BCADC90D2EEA514A199105FDAB37EC
+8A75B14E67B638CAF1ADFBAF70D38355A66B513BFEDBBA2CC6981C25E364297C873C908E
+A288D930A8A18AF24C38B92F520DB5A41D708A438BC39356730D028198A08AD3430237FB
+8EC675CE19EAF97C06CDF706B138EAD722EAD2C7C6108A4C474210CE38A7A4EB0FF573DA
+59B024BED3579A7C870AFF17EB284527030EAD8F515D18EE490FD5D32545527F38BE7B7D
+CE9C1D1283B1771AAD8953E6D89EBC068E1C42C8431D6EC365F736652C4D74C627BC0689
+A3F273D9D9D94FF32CC504AADE91D4E17105EBA804952F566F0849A34B4E150223E5ED27
+786FD43209CC4F4EE8F4DB98D2C1DB336AE17E745DD8EB3D95A9984A632475430B0E80AE
+49A5118C73F0E060C7AC98A8F03E9E7BCA9492AE7D5CED0AA5F177E5EA1F6FFB5AA43A13
+76C8FAD9344ECD8E6B64EDA15AA52B37DDE5AEF3242C236D2C5B401000EE78D62A889665
+2553636E765463181099C47679428ED39AD2F77F8F35DC07A726666751D8DF804635DB17
+C4A81D61036E8CE9CE5E441226584EC469082C6C765909DCE05DD9C9D932F295EB587B37
+C7C32818BA4126B809ED89CEC7F14494720018DC93BC5F2635B5F1ADECFC9B4D2B028FFE
+AC248B2663FCD7A43E5468B43FA11E3BC439A5B519DFCDDE7403AB81F0771A7D85BCDF08
+B2C1DF316723EBCB4FBCEAA61454F48D6A354FCAA92E58757D9CE79F92166468522C00BC
+FFD765E0F3BCCE1C41E1717BDAD21746C86310CB9490510FCE6DB36CAD377215650FD82B
+9E3FD5E1188EB4D87A216B9B475DF5B634C39C87DD4B89EBF8DD52E7850E680F9CC7E610
+774D1F96C682B067FDC4456954D74B9D1FF2C18CCB9FB0C059517D174974D58D3376C32A
+53A2F6C1E6844152C3EB1E954A095D9EFCF72158B0C58A1B55EB29741FFD07F55030A9EC
+945C351CEE57273FBD4ECFDA6EB2A4FC374E1763B50648C68678B5FB5CDA2DA8D87EC85F
+738F2C2F2DFD4F93E44CD2BC2BB5B8103073EC603487DB06311F97BBFBACF934E3524EC4
+3006CC8A613AD9DDADE1023D0044F0C27F577900A62888C75FCA2B1F7DC59683028FE95F
+78039BACCF4E9710D3594B1205B5B08AAB01B04827A82516467C561E80484C2AF83781E0
+F947645951BC5CA167AADE20C8AE192CF9F800C409971D09BD173FE2FB130D8C543F4B57
+D7170BF0146B6138A12D9B04B717CB244E68A023E96E30918A1CBBC4A17EB994398BD47D
+CE04656333D38F705EE4ED3A75E569A68409CBD18DF1FD537ABAE8E5D4E67D45FE12CD4B
+5ADE49AA221D208F8C0C93FA8D659A01F2B9AC7869AAB3A69C1DC5B48FB8A91039BBA6E8
+3FE9985115B0B304F0E5293FFE5BC54CC84840EF951EAE7E4A1F0D4D1231E0A2F505F54B
+9CC2E373991495EED14DCF911DB949E4FA0016D5DD8D1126BE6A149AACD3B51F26347320
+A064FA81697B41AA19D5EBB8500022559BBCFFEA94E6F6F5C8755D9B669418107341FB18
+6855A75AAB2D1FBCCD70DE7120277E9B9D8C9BAE1CED962255F61D28EE29C001D0758578
+0B24E2F7B0CD7EBE33EE42A55A217C5832730B414D5109844A5E9934CA865AD2AE9127C7
+CAC28FE451C17A44C8C79395762EB7747B2DD7780DA0B2145CD2732B2D62724271FE4B5D
+96B882BF2C73F1E2BB9D700B83CE16AE2D6AB9726E12B09872EA940C1FADFEF125F89D09
+1FE5580E48ABF5493F9D8CC50CCCE629D6F8ACAF3998943225C5D2D795A1A10E2C1AC6D8
+B057F4A8225F0B24E4D6410F4A38D75D14601250E427EBFDD43AAF5E5C1EE0CCDB6D4504
+E3F854ED2EF4E8BDFA1F7422AB86B17896E6D3D0B14B81C515B489C3BE5B471461D6901D
+B39949A0B137BF9AF0C3A8124BB3FB4C1DC43A9ECCC48DB999E5FEB94B60DF942AE440AA
+4E69A70EEE8860EE2CE8570ABFA7519AC16AA1991540596881033B01CDB54E4DB401430B
+20696CD808C73AEBB6E61A5C41C96D7FC338E6E92A112ABF427C6E0EB23E278B3E5967BE
+13998C6786382093F74E2B067D428E9877F44DF94F6FEC76109987F3D7F13CE7C4C24648
+61128BB2C51BC858F4B87C3B3938698B4CE4CEAC0A73D872D5A43269B11B95D85FDB1F49
+545527BB2AA699944776B9A623DF59DB1B3035A6177A713667D78F7457C950D2664BA6DB
+1076009612A6806B24AB931A8466BE6EED4BC7776F1AB926213490BDA0F8E65E84B960D2
+625E6FC88744371574FC22DE9CAC8E37D0F0BEDACE16C034A588888EBA681CB89FB9D2E5
+3F04BAE4629739F91C372321D3F2653E4D24439E6B8AAFD71184436B86AA3D9C0B170A54
+728385BF8B6ECCDB25ED1D3363837400E80789F16FC73CD235568FE7F51385693E41555A
+F53AB56069EBF4F2B5D0C7859E988DCCAA37F0AD98EB34169D3E9BF7C664BE123640569D
+89F1C34BACC3B967853750B3627FD055A2AE8B2BBD6DDC2F6AC54BC7FF5122A540D0D200
+FF8FCF17DFD821E8034BFFEC18E1CD7DF35D4E1D80614347D92743B7CBE2910AD330A5B1
+C1D5DC95379F601A289069159AC6183E283257AB2C97C8BB3D6500B012BC6A9F47B0A57F
+2639AAD56552486847B304AD088CB8AEB07D032C4C275029A69563E350F3D64A67A7B88D
+561AB9C9DE1FC593DFC448FAD9E42063AF99A70DC8EFDB928FEFF2225FA1DE159DE073E6
+3A55D312B9B1810B375E116D79617D0F348EB2184E8A150E94223C792193E1A096646EE2
+A0D82C33EBB19E422988824963C50BAAA8598B9D51DB4149A366F621852EF0B17B4A41A2
+3436A438D8E65735F6B4D1E2EF89A12E4002AC8E585BC407EE6F34CD2D7046E042C463EE
+EBC4971A00B9A5F29102455E787BC66620D627385BAA3812F6B0BCF03AF1728064E1A8B7
+D7F5574C5DC22F5C0472CBD0E351F430823302827B31BF2338D85F80DDCCD3EA5E49B9A8
+8B8BBE6B0132C8198DA4436F609C27D13E7E561F05E783F04630B3EC03272F33E3F08419
+D5B4C16B386DCA42D17E89D7ACF46F6F4A79BBA082700F7F98327F2C7E62D8B1E6BFAF8C
+212819FB632C3DCB4AC92A8A0F94F350FB0BE0C89503CD0A52B3AE4817C2CA7193563FE9
+20CC6F4E24C116AB47AF0E3313702E1E96BD9817C1297C30FC7178314E401E4CB3847ACB
+1CBB1A672D928C1945E6629F626F66A679E9E39263C3A6804BA6A7D18F0CD0F1E01FEAFA
+7786ECD7026C94DD0310F20E8BF525CF5EB072E1EE59E66FDBF54880401F7F66A4C5D019
+297B0EF4C6D3478BFE76B93FACE72F5CDEFFABEBD78DD06E377787E873CB76C7F5130748
+E42599B216AF2254DDFC5AA8146EA01E76FFA094DD65EBF264C301F1311A53E86082E20A
+9B5E98CADFA0A10BE2A96CA3D0A33104911C1EF4CAE7E4E7CE3F6A765952D3E72E914DEB
+FC50474634A05EC92FA59914A798E42044484FB6F7E3E5D1AF45828422B971D5E7B91601
+848A2624DC276C47F14441338E47FF6F1741A38939A8B75ADC8702F0553ACD787BD49F4C
+D4D2CA40759C000A619BE27C2923D72438EB49D684DBBE48DBC67AF1935C9833B9E25252
+1E2869C7E808FC1ACD822659AC94F94FF2E11174FB7A7D199EDE962C61672D9F5D2C93F1
+BC99052FB782D94B08617E3C7BF232D9EDD6FD466A2ED7E55318F6E789E4A09F636B91E9
+6EE41F556224A8108BE1CFB2A83A57BA6C8995B6F7A5BE1D454A18CBF2E71FFC4D23A3B4
+9A202FEFF154CCE053BFABCC83CE4FE091E31B4759761F3D535348EF85AE276108592DCA
+9A84E1EA28786F871636712C1B85B412DFE705AC768AC8F5B65BD49CE921CDDB5C4D41DF
+BB2A7F14263AD2295F25ACFBF3F621D19437F0DDCB174280EA65836E9DCE638364E04085
+29F239946EB500E4455E7B79A412EB03C72D7D18A1EFC6A5C86AA2987C43E3987A5EF3F4
+F35712C790EB5137ABC92B2DAE1CD4E06E21B0DC03E2503687BA0DB73A4DDDEFB41C3BF5
+199ED14731480556C59F1127993C587517CC2406EFA6529122D90D9A9E4C1400B97B5DA0
+3A17AC4C5E238267969046365CA9ADE8D7C76746091704DF72709098602891ED11EE7AF8
+FD7B26DDE5E9CBD0BAB0E2E8C2B6BD49F2FF4CD016EE88B55F087152E7B2E4F67D081FAB
+847050548D26D0FE5365833D2A4791018284552C1F40D9ECE2605A3BE0EE2ED5DECE4D4D
+A8D5D81ED6101786D8AF3E5EBEB78FBECD7D3B471FF8C6900E12D0F45671D44DA582421F
+9BBD5759CDCC9FEE1991520E8F84BB8ACA4A370237E4C4FF92BE8EE6C307DFC47078E167
+DA4C7B2740B9A429012F4BB8519507F2A18F51BDD82168B9576E29531A5B26CD7B0FD7DB
+6E346CAB301B33CEBEE1F3D61D73B7D6145F89985653445FA519F91597A0F984DADE3094
+7109124D39A2A7E6D1CFDAF96A73FA0849075111F1ABC010A6871CC05709441C20CEF9B9
+A9AD1A8B1C207D0FE1E7D9D238D0A65EDAFE0BB3802D68CBF0B4CC151A8B330DD04E07DE
+C3329735761D7FDE1ACC1B0E86566891E6AE571EB4936A3BC13A3684A52CAF7B7BD84C73
+C68F436156F5A1F05A1898FEAD0F35CF7778CC824139B47484C71C4EE3625F86D1B12317
+7620B46984D92F7C1D38D392F8981CA76FD1678CFDD43FA5F2A5B5F92FEDFF593F699866
+F063DA7E0AD329FF3C45A2236A3F7A6D420E3A66B2BE1BFBF1CC584BE3B68BA2714DB085
+1B803EB1A075C6B1495099C0A5CC7C51369BE2A79E23D793BCD72A8BD7DEC3E180ABF90D
+D5D4137A796716083BBDD2C75EAEE01531EABFBD93F8D442525DD798E799D7EA30AB15BD
+9A20FE527E524FD7D6BD01884C12044BD7E81DE8293F50F63201D31838FDC0C7B20EEB93
+2372EA2F80F325EBE41BFC037B9FFB5150E421E2E785B5DDB910C3569DCE72A9441AA858
+D0325B3BF2FB3FE83A3D558A63AED58F48C5ACD609D5E1B048A6B519E061E601F4387F03
+7049B8CD97F402EED07DF88A9FB133E9DE42A205727495050C9C6B9D346E0B159C704A3B
+99F4F4A11A7B530F48BA5EFE0C6141F6F973C844BD43119D3AF52E22D2C6B615E53FB90B
+E1683719BC94124D51559326EDCFE600F75B0427CCE88D215A5B57F6DC59F504F2A7AC5B
+2B90F94AD673C8872A03DCDEB8712634E1BA3CB2E227ED6535160B62FABBC22B7FBA8174
+70E62F61792B40AAA5454010B2B008FB1DB7C11038CB98C8CD5401C95DB173A4AFD3CC0F
+7E5F19B6DFDC8BDF118786ECE351307B0E4C30233C0177781085FA1B2C5D1EF51BF9490B
+B6D1CD1C18F0782098F9E484F9420D635C79D6AC0740B7AE70BBBFEAF8B8958BD921D2A9
+798546BDD7858F810FEB5D84CF411AA3827A50420FE741BC3812CDE1865F4A2EF6A25A4C
+ED7EB24CCD38095AFE425D3B0A90539A1CD93DE3F35B020D047EFCE7E1C5C18633B419A2
+1167ACFD3CC3EE0629C0717AE994F151BEFF9EF0AF6E0F14358FBFBA8B61D669ADA8C47C
+AA03859AD7E8C07FC39514A8A85E5C5D02B5DDB48725BC15B70AB80FF7F563D481106810
+D8DF1EE07EAF9DB56374124F654CCB454E3C7B0BB490E0D9CB50460E1857C32C95021954
+35C010736A65A00FC28A348ECD4B494F5FEF4D236FBCB951535C546F248F0BAA11F372DD
+67F838667C2657A7ABC4631530F275D7A5ED73DEC263A1749630C251ED3F5B9708876730
+0ED8DBD0F588D874267EE87E8486B700B58DE87DA46980B752B5EAA853699AE65D50A6D5
+1A41D217244B8BC5C39D98272731E8D605EEABE0E6E487BC89F5962D2423DAF0C580D424
+719EBA7E9FC3C8C49AA2ED9BF1B679C51EC07D7C4F4401DA63B66AF7061BAE89C443718E
+EEA6FBD03E21DDAD5A1B2C251FF101AADE3FF3243F71CA14F19F71E3CB8689BE24E506C3
+C2E9BF2ADC82BFDBAD0C07082B75EAE1ECD31A8B90B9A582FEC64B65A8DF81E54B867EEB
+E71C191443897E25FAC6EDE419F11912D284F8819AF00617BB03330055E5C49023BD472E
+B32FE903E2C3A3BD9452389DA13CB1E4662ABFE88ABCA6DF0E55878CADFE425B8BF42313
+9107696719E947249B70C02251E24CBB3F3E027245651181113F3C2DDA0FF61B1243B6C4
+CDB870D3E05B7DA867C1853A6F8E53CDDD654831048A6F58EEDE299A70E0C18C02600DA3
+7D1507535286BD1C167BF37F925C8468967709EDBF94DFE0BFCFF11F0B715C77BF1FF7D7
+0BD8258DBDEE61ED4785F85DF2C52157FEC3C01282226FCC96E0ED8CDC8874A209E54A9C
+0E8EDA0887E0561CE0B3ECBAB1019F39132E6DA0FE6761379C4424EFC66C36EB4AD7D125
+B88A0A7C19ABABD4A60FBDF0CC1414A77837EB57609D6E4C5DA8A37D18B05B4F755776FC
+1930C15DFA2B545D8DCC65B7C8C4A3B9A8DBFC8C64CF90C1047828084070516FF3897E5C
+CD223CA4E5DE09834C960D0483F48156CB48B73EB3387A01208AC9991949027675AB9AAF
+B3D1AE8791DDA72EEA9053C50218F89B65935D6E40979F583456658C00C593034A067B3F
+5B9F7177E6032F1F6BC96AD544F8B98472724D7F48C91D08B4CE91B5EE736A22996CD971
+34E2D4221E0891CA4C8708A6059DB1C48350106A304F7000A1D165D44CCD6F6EE7EA5434
+4F5506C13BA5D12A04548D75D266E0A027DE905EB4DF15ECA1CDFA1D4EE0B9D650AFF4A6
+3ED6A0AD78D63938669B505CD5B799DDB4A3BAD89CAB921F18D26DC9B581B0E28EA395A2
+349B5909107EE11E9CC364961A335C913A34094E63C9163E45A5FF43D3B58E5101E8E2F0
+AFCE604BC96F676F942301846A6F3C54AF5A4D60F37B7A4C3BE982FDEE76F0B8
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+{restore}if
diff --git a/install-sh b/install-sh
new file mode 100755
index 000000000..05fe96fe4
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,222 @@
+#!/bin/sh
+#
+# "$Id: install-sh 8688 2009-05-27 16:42:40Z mike $"
+#
+# Install a program, script, or datafile.
+#
+# Copyright 2008-2009 by Apple Inc.
+#
+# This script is not compatible with BSD (or any other) install program, as it
+# allows owner and group changes to fail with a warning and makes sure that the
+# destination directory permissions are as specified - BSD install and the
+# original X11 install script did not change permissions of existing
+# directories. It also does not support the transform options since CUPS does
+# not use them...
+#
+# Original script from X11R5 (mit/util/scripts/install.sh)
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+
+# set DOITPROG to echo to test this script
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+# Force umask to 022...
+umask 022
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c)
+ instcmd="$cpprog"
+ shift
+ continue
+ ;;
+
+ -d)
+ dir_arg=true
+ shift
+ continue
+ ;;
+
+ -m)
+ chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue
+ ;;
+
+ -o)
+ chowncmd="$chownprog $2"
+ shift
+ shift
+ continue
+ ;;
+
+ -g)
+ chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue
+ ;;
+
+ -s)
+ stripcmd="$stripprog"
+ shift
+ continue
+ ;;
+
+ *)
+ if [ x"$src" = x ]; then
+ src="$1"
+ else
+ dst="$1"
+ fi
+ shift
+ continue
+ ;;
+ esac
+done
+
+if [ x"$src" = x ]; then
+ echo "install-sh: No input file specified"
+ exit 1
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst="$src"
+ src=""
+
+ if [ -d "$dst" ]; then
+ instcmd=:
+ else
+ instcmd=$mkdirprog
+ fi
+else
+ # Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if [ ! -f "$src" -a ! -d "$src" ]; then
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]; then
+ echo "install: No destination specified"
+ exit 1
+ fi
+
+ # If destination is a directory, append the input filename.
+ if [ -d "$dst" ]; then
+ dst="$dst/`basename $src`"
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir="`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`"
+
+# Make sure that the destination directory exists.
+# This part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+ defaultIFS='
+ '
+ IFS="${IFS-${defaultIFS}}"
+
+ oIFS="${IFS}"
+ # Some sh's can't handle IFS=/ for some reason.
+ IFS='%'
+ set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+ IFS="${oIFS}"
+
+ pathcomp=''
+
+ while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ]; then $doit $mkdirprog "${pathcomp}"; fi
+
+ pathcomp="${pathcomp}/"
+ done
+fi
+
+if [ x"$dir_arg" != x ]; then
+ # Make a directory...
+ $doit $instcmd $dst || exit 1
+
+ # Allow chown/chgrp to fail, but log a warning
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst || echo "warning: Unable to change owner of $dst!"; fi
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst || echo "warning: Unable to change group of $dst!"; fi
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst || exit 1; fi
+else
+ # Install a file...
+ dstfile="`basename $dst`"
+
+ # Check the destination file - for libraries just use the "-x" option
+ # to strip...
+ case "$dstfile" in
+ *.a | *.dylib | *.sl | *.sl.* | *.so | *.so.*)
+ stripopt="-x"
+ ;;
+ *)
+ stripopt=""
+ ;;
+ esac
+
+ # Make a temp file name in the proper directory.
+ dsttmp="$dstdir/#inst.$$#"
+
+ # Move or copy the file name to the temp name
+ $doit $instcmd $src $dsttmp || exit 1
+
+ # Update permissions and strip as needed, then move to the final name.
+ # If the chmod, strip, rm, or mv commands fail, remove the installed
+ # file...
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $stripopt "$dsttmp" || echo "warning: Unable to strip $dst!"; fi
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp" || echo "warning: Unable to change owner of $dst!"; fi
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp" || echo "warning: Unable to change group of $dst!"; fi
+
+ trap "rm -f ${dsttmp}" 0 &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; fi &&
+ $doit $rmcmd -f "$dstdir/$dstfile" &&
+ $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+fi
+
+exit 0
diff --git a/locale/Dependencies b/locale/Dependencies
new file mode 100644
index 000000000..45dd3faec
--- /dev/null
+++ b/locale/Dependencies
@@ -0,0 +1,26 @@
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+checkpo.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+checkpo.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+checkpo.o: ../cups/language.h ../cups/string-private.h ../config.h
+checkpo.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+checkpo.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+checkpo.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+checkpo.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+checkpo.o: ../cups/thread-private.h
+po2strings.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+po2strings.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+po2strings.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+po2strings.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+po2strings.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+po2strings.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+po2strings.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+po2strings.o: ../cups/transcode.h ../cups/thread-private.h
+translate.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+translate.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+translate.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+translate.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+translate.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+translate.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+translate.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+translate.o: ../cups/transcode.h ../cups/thread-private.h
diff --git a/locale/Makefile b/locale/Makefile
new file mode 100644
index 000000000..7d4aaad84
--- /dev/null
+++ b/locale/Makefile
@@ -0,0 +1,219 @@
+#
+# "$Id$"
+#
+# Locale file makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1993-2007 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+
+OBJS = checkpo.o po2strings.o strings2po.o translate.o
+TARGETS = checkpo po2strings strings2po translate
+
+
+#
+# Make everything...
+#
+
+all: $(TARGETS)
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Clean all config and object files...
+#
+
+clean:
+ $(RM) $(TARGETS) $(OBJS)
+
+
+#
+# Update dependencies (without system header dependencies...)
+#
+
+depend:
+ makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data: $(INSTALL_LANGUAGES)
+
+install-languages:
+ $(INSTALL_DIR) -m 755 $(LOCALEDIR)
+ for loc in $(LANGUAGES) ; do \
+ if test -f cups_$$loc.po; then \
+ $(INSTALL_DIR) -m 755 $(LOCALEDIR)/$$loc ; \
+ $(INSTALL_DATA) cups_$$loc.po $(LOCALEDIR)/$$loc/cups_$$loc.po ; \
+ fi ; \
+ done
+
+install-langbundle: po2strings
+ $(INSTALL_DIR) -m 755 "$(BUILDROOT)$(BUNDLEDIR)/Resources/English.lproj"
+ $(INSTALL_DATA) cups.strings "$(BUILDROOT)$(BUNDLEDIR)/Resources/English.lproj"
+
+
+#
+# Install programs...
+#
+
+install-exec:
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall files...
+#
+
+uninstall: $(UNINSTALL_LANGUAGES)
+
+uninstall-languages:
+ -for loc in $(LANGUAGES) ; do \
+ $(RM) $(LOCALEDIR)/$$loc/cups_$$loc.po ; \
+ done
+
+uninstall-langbundle:
+ $(RM) "$(BUILDROOT)$(BUNDLEDIR)/Resources/English.lproj/cups.strings"
+
+
+#
+# pot - Creates/updates the cups.pot template file, merges changes into existing
+# message catalogs, and updates the cups.strings file. We don't use
+# xgettext to update the cups.strings file due to known xgettext bugs.
+#
+
+pot: checkpo po2strings
+ echo Updating cups.pot...
+ mv cups.pot cups.pot.bck
+ touch cups.pot
+ cd ..; xgettext -o locale/cups.pot -cTRANSLATORS -s \
+ --keyword=_ --no-wrap \
+ --copyright-holder="Apple Inc." \
+ --package-name="CUPS" --package-version="1.5" \
+ --msgid-bugs-address="http://www.cups.org/str.php" \
+ */*.c */*.cxx
+ (cat cups.header; tail +6 cups.pot; cat cups.footer) > cups.pot.N
+ mv cups.pot.N cups.pot
+ echo Checking cups.pot...
+ ./checkpo cups.pot
+ for loc in $(LANGUAGES) ; do \
+ echo Merging changes into cups_$$loc.po... ; \
+ msgmerge -o cups_$$loc.po -s -N --no-location cups_$$loc.po cups.pot ; \
+ done
+ echo Updating cups.strings...
+ ./po2strings cups.pot cups.strings
+
+
+#
+# checkpo - A simple utility to check PO files for correct translation
+# strings. Dependency on static library is deliberate.
+#
+# checkpo filename.po [... filenameN.po]
+#
+
+checkpo: checkpo.o ../cups/$(LIBCUPSSTATIC)
+ echo Linking $<...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o checkpo checkpo.o \
+ ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ $(COMMONLIBS) $(LIBZ)
+
+checkall: checkpo
+ for file in *.po; do \
+ ./checkpo $$file; \
+ done
+
+
+#
+# po2strings - A simple utility which uses iconv to convert GNU gettext
+# message catalogs to Mac OS X .strings files.
+#
+# po2strings filename.po filename.strings
+#
+
+po2strings: po2strings.o ../cups/$(LIBCUPSSTATIC)
+ echo Linking $<...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o po2strings po2strings.o \
+ ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ $(COMMONLIBS) $(LIBZ)
+
+
+#
+# strings2po - A simple utility which uses iconv to convert Mac OS X
+# .strings files to GNU gettext message catalogs.
+#
+# strings2po filename.strings filename.po
+#
+
+strings2po: strings2po.o
+ echo Linking $<...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o strings2po strings2po.o
+
+
+#
+# translate - A simple utility which uses Google to translate the cups.pot
+# file to one of several languages.
+#
+# translate outfile language
+#
+
+translate: translate.o ../cups/$(LIBCUPSSTATIC)
+ echo Linking $<...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o translate translate.o \
+ ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ $(COMMONLIBS) $(LIBZ)
+
+
+#
+# Dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id$".
+#
diff --git a/locale/checkpo.c b/locale/checkpo.c
new file mode 100644
index 000000000..fa2afbad3
--- /dev/null
+++ b/locale/checkpo.c
@@ -0,0 +1,413 @@
+/*
+ * "$Id$"
+ *
+ * Verify that translations in the .po file have the same number and type of
+ * printf-style format strings.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Usage:
+ *
+ * checkpo filename.po [... filenameN.po]
+ *
+ * Compile with:
+ *
+ * gcc -o checkpo checkpo.c `cups-config --libs`
+ *
+ * Contents:
+ *
+ * main() - Validate .po files.
+ * abbreviate() - Abbreviate a message string as needed.
+ * collect_formats() - Collect all of the format strings in the msgid.
+ * free_formats() - Free all of the format strings.
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * Local functions...
+ */
+
+static char *abbreviate(const char *s, char *buf, int bufsize);
+static cups_array_t *collect_formats(const char *id);
+static void free_formats(cups_array_t *fmts);
+
+
+/*
+ * 'main()' - Validate .po files.
+ */
+
+int /* O - Exit code */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ cups_array_t *po; /* .po file */
+ _cups_message_t *msg; /* Current message */
+ cups_array_t *idfmts, /* Format strings in msgid */
+ *strfmts; /* Format strings in msgstr */
+ char *idfmt, /* Current msgid format string */
+ *strfmt; /* Current msgstr format string */
+ int fmtidx; /* Format index */
+ int status, /* Exit status */
+ pass, /* Pass/fail status */
+ untranslated; /* Untranslated messages */
+ char idbuf[80], /* Abbreviated msgid */
+ strbuf[80]; /* Abbreviated msgstr */
+
+
+ if (argc < 2)
+ {
+ puts("Usage: checkpo filename.po [... filenameN.po]");
+ return (1);
+ }
+
+ /*
+ * Check every .po file on the command-line...
+ */
+
+ for (i = 1, status = 0; i < argc; i ++)
+ {
+ /*
+ * Use the CUPS .po loader to get the message strings...
+ */
+
+ if ((po = _cupsMessageLoad(argv[i], 1)) == NULL)
+ {
+ perror(argv[i]);
+ return (1);
+ }
+
+ if (i > 1)
+ putchar('\n');
+ printf("%s: ", argv[i]);
+ fflush(stdout);
+
+ /*
+ * Scan every message for a % string and then match them up with
+ * the corresponding string in the translation...
+ */
+
+ pass = 1;
+ untranslated = 0;
+
+ for (msg = (_cups_message_t *)cupsArrayFirst(po);
+ msg;
+ msg = (_cups_message_t *)cupsArrayNext(po))
+ {
+ /*
+ * Make sure filter message prefixes are not translated...
+ */
+
+ if (!strncmp(msg->id, "ALERT:", 6) || !strncmp(msg->id, "CRIT:", 5) ||
+ !strncmp(msg->id, "DEBUG:", 6) || !strncmp(msg->id, "DEBUG2:", 7) ||
+ !strncmp(msg->id, "EMERG:", 6) || !strncmp(msg->id, "ERROR:", 6) ||
+ !strncmp(msg->id, "INFO:", 5) || !strncmp(msg->id, "NOTICE:", 7) ||
+ !strncmp(msg->id, "WARNING:", 8))
+ {
+ if (pass)
+ {
+ pass = 0;
+ puts("FAIL");
+ }
+
+ printf(" Bad prefix on filter message \"%s\"\n",
+ abbreviate(msg->id, idbuf, sizeof(idbuf)));
+ }
+
+ idfmt = msg->id + strlen(msg->id) - 1;
+ if (idfmt >= msg->id && *idfmt == '\n')
+ {
+ if (pass)
+ {
+ pass = 0;
+ puts("FAIL");
+ }
+
+ printf(" Trailing newline in message \"%s\"\n",
+ abbreviate(msg->id, idbuf, sizeof(idbuf)));
+ }
+
+ for (; idfmt >= msg->id; idfmt --)
+ if (!isspace(*idfmt & 255))
+ break;
+
+ if (idfmt >= msg->id && *idfmt == '!')
+ {
+ if (pass)
+ {
+ pass = 0;
+ puts("FAIL");
+ }
+
+ printf(" Exclamation in message \"%s\"\n",
+ abbreviate(msg->id, idbuf, sizeof(idbuf)));
+ }
+
+ if ((idfmt - 2) >= msg->id && !strncmp(idfmt - 2, "...", 3))
+ {
+ if (pass)
+ {
+ pass = 0;
+ puts("FAIL");
+ }
+
+ printf(" Ellipsis in message \"%s\"\n",
+ abbreviate(msg->id, idbuf, sizeof(idbuf)));
+ }
+
+
+ if (!msg->str || !msg->str[0])
+ {
+ untranslated ++;
+ continue;
+ }
+ else if (strchr(msg->id, '%'))
+ {
+ idfmts = collect_formats(msg->id);
+ strfmts = collect_formats(msg->str);
+ fmtidx = 0;
+
+ for (strfmt = (char *)cupsArrayFirst(strfmts);
+ strfmt;
+ strfmt = (char *)cupsArrayNext(strfmts))
+ {
+ if (isdigit(strfmt[1] & 255) && strfmt[2] == '$')
+ {
+ /*
+ * Handle positioned format stuff...
+ */
+
+ fmtidx = strfmt[1] - '1';
+ strfmt += 3;
+ if ((idfmt = (char *)cupsArrayIndex(idfmts, fmtidx)) != NULL)
+ idfmt ++;
+ }
+ else
+ {
+ /*
+ * Compare against the current format...
+ */
+
+ idfmt = (char *)cupsArrayIndex(idfmts, fmtidx);
+ }
+
+ fmtidx ++;
+
+ if (!idfmt || strcmp(strfmt, idfmt))
+ break;
+ }
+
+ if (cupsArrayCount(strfmts) != cupsArrayCount(idfmts) || strfmt)
+ {
+ if (pass)
+ {
+ pass = 0;
+ puts("FAIL");
+ }
+
+ printf(" Bad translation string \"%s\"\n for \"%s\"\n",
+ abbreviate(msg->str, strbuf, sizeof(strbuf)),
+ abbreviate(msg->id, idbuf, sizeof(idbuf)));
+ fputs(" Translation formats:", stdout);
+ for (strfmt = (char *)cupsArrayFirst(strfmts);
+ strfmt;
+ strfmt = (char *)cupsArrayNext(strfmts))
+ printf(" %s", strfmt);
+ fputs("\n Original formats:", stdout);
+ for (idfmt = (char *)cupsArrayFirst(idfmts);
+ idfmt;
+ idfmt = (char *)cupsArrayNext(idfmts))
+ printf(" %s", idfmt);
+ putchar('\n');
+ putchar('\n');
+ }
+
+ free_formats(idfmts);
+ free_formats(strfmts);
+ }
+
+ /*
+ * Only allow \\, \n, \r, \t, \", and \### character escapes...
+ */
+
+ for (strfmt = msg->str; *strfmt; strfmt ++)
+ if (*strfmt == '\\' &&
+ strfmt[1] != '\\' && strfmt[1] != 'n' && strfmt[1] != 'r' &&
+ strfmt[1] != 't' && strfmt[1] != '\"' && !isdigit(strfmt[1] & 255))
+ {
+ if (pass)
+ {
+ pass = 0;
+ puts("FAIL");
+ }
+
+ printf(" Bad escape \\%c in filter message \"%s\"\n"
+ " for \"%s\"\n", strfmt[1],
+ abbreviate(msg->str, strbuf, sizeof(strbuf)),
+ abbreviate(msg->id, idbuf, sizeof(idbuf)));
+ break;
+ }
+ }
+
+ if (pass)
+ {
+ if ((untranslated * 10) >= cupsArrayCount(po) &&
+ strcmp(argv[i], "cups.pot"))
+ {
+ /*
+ * Only allow 10% of messages to be untranslated before we fail...
+ */
+
+ pass = 0;
+ puts("FAIL");
+ printf(" Too many untranslated messages (%d of %d)\n",
+ untranslated, cupsArrayCount(po));
+ }
+ else if (untranslated > 0)
+ printf("PASS (%d of %d untranslated)\n", untranslated,
+ cupsArrayCount(po));
+ else
+ puts("PASS");
+ }
+
+ if (!pass)
+ status = 1;
+
+ _cupsMessageFree(po);
+ }
+
+ return (status);
+}
+
+
+/*
+ * 'abbreviate()' - Abbreviate a message string as needed.
+ */
+
+static char * /* O - Abbreviated string */
+abbreviate(const char *s, /* I - String to abbreviate */
+ char *buf, /* I - Buffer */
+ int bufsize) /* I - Size of buffer */
+{
+ char *bufptr; /* Pointer into buffer */
+
+
+ for (bufptr = buf, bufsize -= 4; *s && bufsize > 0; s ++)
+ {
+ if (*s == '\n')
+ {
+ if (bufsize < 2)
+ break;
+
+ *bufptr++ = '\\';
+ *bufptr++ = 'n';
+ bufsize -= 2;
+ }
+ else if (*s == '\t')
+ {
+ if (bufsize < 2)
+ break;
+
+ *bufptr++ = '\\';
+ *bufptr++ = 't';
+ bufsize -= 2;
+ }
+ else if (*s >= 0 && *s < ' ')
+ {
+ if (bufsize < 4)
+ break;
+
+ sprintf(bufptr, "\\%03o", *s);
+ bufptr += 4;
+ bufsize -= 4;
+ }
+ else
+ {
+ *bufptr++ = *s;
+ bufsize --;
+ }
+ }
+
+ if (*s)
+ strcpy(bufptr, "...");
+ else
+ *bufptr = '\0';
+
+ return (buf);
+}
+
+
+/*
+ * 'collect_formats()' - Collect all of the format strings in the msgid.
+ */
+
+static cups_array_t * /* O - Array of format strings */
+collect_formats(const char *id) /* I - msgid string */
+{
+ cups_array_t *fmts; /* Array of format strings */
+ char buf[255], /* Format string buffer */
+ *bufptr; /* Pointer into format string */
+
+
+ fmts = cupsArrayNew(NULL, NULL);
+
+ while ((id = strchr(id, '%')) != NULL)
+ {
+ if (id[1] == '%')
+ {
+ /*
+ * Skip %%...
+ */
+
+ id += 2;
+ continue;
+ }
+
+ for (bufptr = buf; *id && bufptr < (buf + sizeof(buf) - 1); id ++)
+ {
+ *bufptr++ = *id;
+
+ if (strchr("CDEFGIOSUXcdeifgopsux", *id))
+ {
+ id ++;
+ break;
+ }
+ }
+
+ *bufptr = '\0';
+ cupsArrayAdd(fmts, strdup(buf));
+ }
+
+ return (fmts);
+}
+
+
+/*
+ * 'free_formats()' - Free all of the format strings.
+ */
+
+static void
+free_formats(cups_array_t *fmts) /* I - Array of format strings */
+{
+ char *s; /* Current string */
+
+
+ for (s = (char *)cupsArrayFirst(fmts); s; s = (char *)cupsArrayNext(fmts))
+ free(s);
+
+ cupsArrayDelete(fmts);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/locale/cups.footer b/locale/cups.footer
new file mode 100644
index 000000000..490c9d4eb
--- /dev/null
+++ b/locale/cups.footer
@@ -0,0 +1,5 @@
+
+
+#
+# End of "$Id$".
+#
diff --git a/locale/cups.header b/locale/cups.header
new file mode 100644
index 000000000..a50d50a55
--- /dev/null
+++ b/locale/cups.header
@@ -0,0 +1,27 @@
+#
+# "$Id$"
+#
+# Message catalog template for CUPS.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 2005-2007 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+#
+# Notes for Translators:
+#
+# The "checkpo" program located in the "locale" source directory can be used
+# to verify that your translations do not introduce formatting errors or other
+# problems. Run with:
+#
+# cd locale
+# ./checkpo cups_LL.po
+#
+# where "LL" is your locale.
+#
diff --git a/locale/cups.pot b/locale/cups.pot
new file mode 100644
index 000000000..3043dc182
--- /dev/null
+++ b/locale/cups.pot
@@ -0,0 +1,6976 @@
+#
+# "$Id$"
+#
+# Message catalog template for CUPS.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 2005-2007 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+#
+# Notes for Translators:
+#
+# The "checkpo" program located in the "locale" source directory can be used
+# to verify that your translations do not introduce formatting errors or other
+# problems. Run with:
+#
+# cd locale
+# ./checkpo cups_LL.po
+#
+# where "LL" is your locale.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.5\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2011-05-10 22:32-0700\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: systemv/lpstat.c:1873 systemv/lpstat.c:1998
+msgid "\t\t(all)"
+msgstr ""
+
+#: systemv/lpstat.c:1876 systemv/lpstat.c:1879 systemv/lpstat.c:2001
+#: systemv/lpstat.c:2004
+msgid "\t\t(none)"
+msgstr ""
+
+#: berkeley/lpc.c:433
+#, c-format
+msgid "\t%d entries"
+msgstr ""
+
+#: systemv/lpstat.c:753 systemv/lpstat.c:769
+#, c-format
+msgid "\t%s"
+msgstr ""
+
+#: systemv/lpstat.c:1854 systemv/lpstat.c:1979
+msgid "\tAfter fault: continue"
+msgstr ""
+
+#: systemv/lpstat.c:1478 systemv/lpstat.c:1823 systemv/lpstat.c:1949
+#, c-format
+msgid "\tAlerts: %s"
+msgstr ""
+
+#: systemv/lpstat.c:1877 systemv/lpstat.c:2002
+msgid "\tBanner required"
+msgstr ""
+
+#: systemv/lpstat.c:1878 systemv/lpstat.c:2003
+msgid "\tCharset sets:"
+msgstr ""
+
+#: systemv/lpstat.c:1842 systemv/lpstat.c:1967
+msgid "\tConnection: direct"
+msgstr ""
+
+#: systemv/lpstat.c:1833 systemv/lpstat.c:1959
+msgid "\tConnection: remote"
+msgstr ""
+
+#: systemv/lpstat.c:1797 systemv/lpstat.c:1923
+msgid "\tContent types: any"
+msgstr ""
+
+#: systemv/lpstat.c:1881 systemv/lpstat.c:2006
+msgid "\tDefault page size:"
+msgstr ""
+
+#: systemv/lpstat.c:1880 systemv/lpstat.c:2005
+msgid "\tDefault pitch:"
+msgstr ""
+
+#: systemv/lpstat.c:1882 systemv/lpstat.c:2007
+msgid "\tDefault port settings:"
+msgstr ""
+
+#: systemv/lpstat.c:1803 systemv/lpstat.c:1929
+#, c-format
+msgid "\tDescription: %s"
+msgstr ""
+
+#: systemv/lpstat.c:1796 systemv/lpstat.c:1922
+msgid "\tForm mounted:"
+msgstr ""
+
+#: systemv/lpstat.c:1875 systemv/lpstat.c:2000
+msgid "\tForms allowed:"
+msgstr ""
+
+#: systemv/lpstat.c:1837 systemv/lpstat.c:1963
+#, c-format
+msgid "\tInterface: %s.ppd"
+msgstr ""
+
+#: systemv/lpstat.c:1846 systemv/lpstat.c:1971
+#, c-format
+msgid "\tInterface: %s/interfaces/%s"
+msgstr ""
+
+#: systemv/lpstat.c:1850 systemv/lpstat.c:1975
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd"
+msgstr ""
+
+#: systemv/lpstat.c:1828 systemv/lpstat.c:1954
+#, c-format
+msgid "\tLocation: %s"
+msgstr ""
+
+#: systemv/lpstat.c:1853 systemv/lpstat.c:1978
+msgid "\tOn fault: no alert"
+msgstr ""
+
+#: systemv/lpstat.c:1798 systemv/lpstat.c:1924
+msgid "\tPrinter types: unknown"
+msgstr ""
+
+#: systemv/lpstat.c:1459
+#, c-format
+msgid "\tStatus: %s"
+msgstr ""
+
+#: systemv/lpstat.c:1858 systemv/lpstat.c:1872 systemv/lpstat.c:1983
+#: systemv/lpstat.c:1997
+msgid "\tUsers allowed:"
+msgstr ""
+
+#: systemv/lpstat.c:1865 systemv/lpstat.c:1990
+msgid "\tUsers denied:"
+msgstr ""
+
+#: berkeley/lpc.c:435
+msgid "\tdaemon present"
+msgstr ""
+
+#: berkeley/lpc.c:431
+msgid "\tno entries"
+msgstr ""
+
+#: berkeley/lpc.c:403 berkeley/lpc.c:415
+#, c-format
+msgid "\tprinter is on device '%s' speed -1"
+msgstr ""
+
+#: berkeley/lpc.c:428
+msgid "\tprinting is disabled"
+msgstr ""
+
+#: berkeley/lpc.c:426
+msgid "\tprinting is enabled"
+msgstr ""
+
+#: systemv/lpstat.c:1481
+#, c-format
+msgid "\tqueued for %s"
+msgstr ""
+
+#: berkeley/lpc.c:423
+msgid "\tqueuing is disabled"
+msgstr ""
+
+#: berkeley/lpc.c:421
+msgid "\tqueuing is enabled"
+msgstr ""
+
+#: systemv/lpstat.c:1789 systemv/lpstat.c:1915
+msgid "\treason unknown"
+msgstr ""
+
+#: systemv/cupstestppd.c:436
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS"
+msgstr ""
+
+#: systemv/cupstestppd.c:3619
+msgid " Ignore specific warnings."
+msgstr ""
+
+#: systemv/cupstestppd.c:3623
+msgid " Issue warnings instead of errors."
+msgstr ""
+
+#: systemv/cupstestppd.c:392 systemv/cupstestppd.c:397
+msgid " REF: Page 15, section 3.1."
+msgstr ""
+
+#: systemv/cupstestppd.c:387
+msgid " REF: Page 15, section 3.2."
+msgstr ""
+
+#: systemv/cupstestppd.c:407
+msgid " REF: Page 19, section 3.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:360
+msgid " REF: Page 20, section 3.4."
+msgstr ""
+
+#: systemv/cupstestppd.c:412
+msgid " REF: Page 27, section 3.5."
+msgstr ""
+
+#: systemv/cupstestppd.c:355
+msgid " REF: Page 42, section 5.2."
+msgstr ""
+
+#: systemv/cupstestppd.c:402
+msgid " REF: Pages 16-17, section 3.2."
+msgstr ""
+
+#: systemv/cupstestppd.c:372
+msgid " REF: Pages 42-45, section 5.2."
+msgstr ""
+
+#: systemv/cupstestppd.c:366
+msgid " REF: Pages 45-46, section 5.2."
+msgstr ""
+
+#: systemv/cupstestppd.c:377
+msgid " REF: Pages 48-49, section 5.2."
+msgstr ""
+
+#: systemv/cupstestppd.c:382
+msgid " REF: Pages 52-54, section 5.2."
+msgstr ""
+
+#: berkeley/lpq.c:554
+#, c-format
+msgid " %-39.39s %.0f bytes"
+msgstr ""
+
+#: systemv/cupstestppd.c:555
+#, c-format
+msgid " PASS Default%s"
+msgstr ""
+
+#: systemv/cupstestppd.c:490
+msgid " PASS DefaultImageableArea"
+msgstr ""
+
+#: systemv/cupstestppd.c:524
+msgid " PASS DefaultPaperDimension"
+msgstr ""
+
+#: systemv/cupstestppd.c:597
+msgid " PASS FileVersion"
+msgstr ""
+
+#: systemv/cupstestppd.c:641
+msgid " PASS FormatVersion"
+msgstr ""
+
+#: systemv/cupstestppd.c:661
+msgid " PASS LanguageEncoding"
+msgstr ""
+
+#: systemv/cupstestppd.c:681
+msgid " PASS LanguageVersion"
+msgstr ""
+
+#: systemv/cupstestppd.c:733
+msgid " PASS Manufacturer"
+msgstr ""
+
+#: systemv/cupstestppd.c:773
+msgid " PASS ModelName"
+msgstr ""
+
+#: systemv/cupstestppd.c:793
+msgid " PASS NickName"
+msgstr ""
+
+#: systemv/cupstestppd.c:853
+msgid " PASS PCFileName"
+msgstr ""
+
+#: systemv/cupstestppd.c:928
+msgid " PASS PSVersion"
+msgstr ""
+
+#: systemv/cupstestppd.c:833
+msgid " PASS PageRegion"
+msgstr ""
+
+#: systemv/cupstestppd.c:813
+msgid " PASS PageSize"
+msgstr ""
+
+#: systemv/cupstestppd.c:888
+msgid " PASS Product"
+msgstr ""
+
+#: systemv/cupstestppd.c:963
+msgid " PASS ShortNickName"
+msgstr ""
+
+#: systemv/cupstestppd.c:1338
+#, c-format
+msgid " WARN %s has no corresponding options."
+msgstr ""
+
+#: systemv/cupstestppd.c:1450
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2."
+msgstr ""
+
+#: systemv/cupstestppd.c:1309
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should be named Duplex.\n"
+" REF: Page 122, section 5.17"
+msgstr ""
+
+#: systemv/cupstestppd.c:1708
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings."
+msgstr ""
+
+#: systemv/cupstestppd.c:1354
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:1690
+#, c-format
+msgid " WARN Line %d only contains whitespace."
+msgstr ""
+
+#: systemv/cupstestppd.c:1362
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:1713
+msgid " WARN Non-Windows PPD files should use lines ending with only LF, not CR LF."
+msgstr ""
+
+#: systemv/cupstestppd.c:1346
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f.\n"
+" REF: Page 42, section 5.2."
+msgstr ""
+
+#: systemv/cupstestppd.c:1377
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:1385
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:1420
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7."
+msgstr ""
+
+#: systemv/cupstestppd.c:1411
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7."
+msgstr ""
+
+#: systemv/cupstestppd.c:1394
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3."
+msgstr ""
+
+#: systemv/cupsaddsmb.c:282
+msgid " cupsaddsmb [options] -a"
+msgstr ""
+
+#: systemv/cupstestdsc.c:427
+msgid " cupstestdsc [options] -"
+msgstr ""
+
+#: systemv/cupstestppd.c:3614
+msgid " program | cupstestppd [options] -"
+msgstr ""
+
+#: systemv/cupstestppd.c:3546
+#, c-format
+msgid ""
+" %s \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")."
+msgstr ""
+
+#: systemv/cupstestppd.c:2212
+#, c-format
+msgid " %s %s %s does not exist."
+msgstr ""
+
+#: systemv/cupstestppd.c:3703
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization."
+msgstr ""
+
+#: systemv/cupstestppd.c:2282
+#, c-format
+msgid ""
+" %s Bad %s choice %s.\n"
+" REF: Page 122, section 5.17"
+msgstr ""
+
+#: systemv/cupstestppd.c:3306 systemv/cupstestppd.c:3355
+#: systemv/cupstestppd.c:3394
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s."
+msgstr ""
+
+#: systemv/cupstestppd.c:3260
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s."
+msgstr ""
+
+#: systemv/cupstestppd.c:2335
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"."
+msgstr ""
+
+#: systemv/cupstestppd.c:2814
+#, c-format
+msgid " %s Bad cupsICCProfile %s."
+msgstr ""
+
+#: systemv/cupstestppd.c:2421
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"."
+msgstr ""
+
+#: systemv/cupstestppd.c:1786
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\""
+msgstr ""
+
+#: systemv/cupstestppd.c:3210
+#, c-format
+msgid " %s Bad language \"%s\"."
+msgstr ""
+
+#: systemv/cupstestppd.c:2379 systemv/cupstestppd.c:2465
+#: systemv/cupstestppd.c:2523 systemv/cupstestppd.c:2578
+#: systemv/cupstestppd.c:2633 systemv/cupstestppd.c:2688
+#: systemv/cupstestppd.c:2741 systemv/cupstestppd.c:2863
+#, c-format
+msgid " %s Bad permissions on %s file \"%s\"."
+msgstr ""
+
+#: systemv/cupstestppd.c:2405 systemv/cupstestppd.c:2492
+#: systemv/cupstestppd.c:2547 systemv/cupstestppd.c:2602
+#: systemv/cupstestppd.c:2657 systemv/cupstestppd.c:2712
+#, c-format
+msgid " %s Bad spelling of %s - should be %s."
+msgstr ""
+
+#: systemv/cupstestppd.c:2757
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID."
+msgstr ""
+
+#: systemv/cupstestppd.c:2169
+#, c-format
+msgid " %s Default choices conflicting."
+msgstr ""
+
+#: systemv/cupstestppd.c:1767
+#, c-format
+msgid " %s Empty cupsUIConstraints %s"
+msgstr ""
+
+#: systemv/cupstestppd.c:3338 systemv/cupstestppd.c:3378
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s."
+msgstr ""
+
+#: systemv/cupstestppd.c:3246
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s."
+msgstr ""
+
+#: systemv/cupstestppd.c:2364 systemv/cupstestppd.c:2450
+#: systemv/cupstestppd.c:2508 systemv/cupstestppd.c:2563
+#: systemv/cupstestppd.c:2618 systemv/cupstestppd.c:2673
+#: systemv/cupstestppd.c:2725 systemv/cupstestppd.c:2848
+#, c-format
+msgid " %s Missing %s file \"%s\"."
+msgstr ""
+
+#: systemv/cupstestppd.c:2971
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option.\n"
+" REF: Page 100, section 5.14."
+msgstr ""
+
+#: systemv/cupstestppd.c:2956
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option.\n"
+" REF: Page 99, section 5.14."
+msgstr ""
+
+#: systemv/cupstestppd.c:1977 systemv/cupstestppd.c:2018
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"."
+msgstr ""
+
+#: systemv/cupstestppd.c:1872
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\""
+msgstr ""
+
+#: systemv/cupstestppd.c:1804
+#, c-format
+msgid " %s Missing cupsUIResolver %s"
+msgstr ""
+
+#: systemv/cupstestppd.c:1963 systemv/cupstestppd.c:2004
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"."
+msgstr ""
+
+#: systemv/cupstestppd.c:1856
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\""
+msgstr ""
+
+#: systemv/cupstestppd.c:3432
+#, c-format
+msgid " %s No base translation \"%s\" is included in file."
+msgstr ""
+
+#: systemv/cupstestppd.c:2258
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None.\n"
+" REF: Page 122, section 5.17"
+msgstr ""
+
+#: systemv/cupstestppd.c:3029 systemv/cupstestppd.c:3043
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s."
+msgstr ""
+
+#: systemv/cupstestppd.c:3009
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)."
+msgstr ""
+
+#: systemv/cupstestppd.c:3152
+#, c-format
+msgid " %s Size \"%s\" should be \"%s\"."
+msgstr ""
+
+#: systemv/cupstestppd.c:3118
+#, c-format
+msgid " %s Size \"%s\" should be the Adobe standard name \"%s\"."
+msgstr ""
+
+#: systemv/cupstestppd.c:2891
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s."
+msgstr ""
+
+#: systemv/cupstestppd.c:1927
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop."
+msgstr ""
+
+#: systemv/cupstestppd.c:1909
+#, c-format
+msgid " %s cupsUIResolver %s does not list at least two different options."
+msgstr ""
+
+#: systemv/cupstestppd.c:2127
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case."
+msgstr ""
+
+#: systemv/cupstestppd.c:1132
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5"
+msgstr ""
+
+#: systemv/cupstestppd.c:546
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5."
+msgstr ""
+
+#: systemv/cupstestppd.c:480
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15."
+msgstr ""
+
+#: systemv/cupstestppd.c:516
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15."
+msgstr ""
+
+#: systemv/cupstestppd.c:989
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4."
+msgstr ""
+
+#: systemv/cupstestppd.c:709
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1."
+msgstr ""
+
+#: systemv/cupstestppd.c:725
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1."
+msgstr ""
+
+#: systemv/cupstestppd.c:764
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:920
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:881
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:955
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:1113
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9"
+msgstr ""
+
+#: systemv/cupstestppd.c:589
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:633
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:1177
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1."
+msgstr ""
+
+#: systemv/cupstestppd.c:1191
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English."
+msgstr ""
+
+#: systemv/cupstestppd.c:3573 systemv/cupstestppd.c:3595
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s"
+msgstr ""
+
+#: systemv/cupstestppd.c:1250
+#, c-format
+msgid " **FAIL** Default translation string for option %s choice %s contains 8-bit characters."
+msgstr ""
+
+#: systemv/cupstestppd.c:1223
+#, c-format
+msgid " **FAIL** Default translation string for option %s contains 8-bit characters."
+msgstr ""
+
+#: systemv/cupstestppd.c:2065
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case."
+msgstr ""
+
+#: systemv/cupstestppd.c:2110
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s."
+msgstr ""
+
+#: systemv/cupstestppd.c:2087
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case."
+msgstr ""
+
+#: systemv/cupstestppd.c:566
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5."
+msgstr ""
+
+#: systemv/cupstestppd.c:465
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15."
+msgstr ""
+
+#: systemv/cupstestppd.c:501
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15."
+msgstr ""
+
+#: systemv/cupstestppd.c:607
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:651
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:1040
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15."
+msgstr ""
+
+#: systemv/cupstestppd.c:671
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:691
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:743
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:783
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:803
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:863
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:938
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:843
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14."
+msgstr ""
+
+#: systemv/cupstestppd.c:1009
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14."
+msgstr ""
+
+#: systemv/cupstestppd.c:823
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14."
+msgstr ""
+
+#: systemv/cupstestppd.c:1062
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15."
+msgstr ""
+
+#: systemv/cupstestppd.c:898
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:973
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3."
+msgstr ""
+
+#: systemv/cupstestppd.c:335
+#, c-format
+msgid " **FAIL** Unable to open PPD file - %s"
+msgstr ""
+
+#: systemv/cupstestppd.c:347
+#, c-format
+msgid " **FAIL** Unable to open PPD file - %s on line %d."
+msgstr ""
+
+#: systemv/cupstestppd.c:1462
+#, c-format
+msgid " %d ERRORS FOUND"
+msgstr ""
+
+#: systemv/cupstestdsc.c:431
+msgid " -h Show program usage"
+msgstr ""
+
+#: systemv/cupstestdsc.c:234 systemv/cupstestdsc.c:276
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d.\n"
+" REF: Page 39, %%%%BoundingBox:"
+msgstr ""
+
+#: systemv/cupstestdsc.c:305
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d.\n"
+" REF: Page 53, %%%%Page:"
+msgstr ""
+
+#: systemv/cupstestdsc.c:218 systemv/cupstestdsc.c:258
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d.\n"
+" REF: Page 43, %%%%Pages:"
+msgstr ""
+
+#: systemv/cupstestdsc.c:176
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d).\n"
+" REF: Page 25, Line Length"
+msgstr ""
+
+#: systemv/cupstestdsc.c:192
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line.\n"
+" REF: Page 17, 3.1 Conforming Documents"
+msgstr ""
+
+#: systemv/cupstestdsc.c:362
+#, c-format
+msgid " Missing %%EndComments comment. REF: Page 41, %%EndComments"
+msgstr ""
+
+#: systemv/cupstestdsc.c:342
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment.\n"
+" REF: Page 39, %%BoundingBox:"
+msgstr ""
+
+#: systemv/cupstestdsc.c:372
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments.\n"
+" REF: Page 53, %%Page:"
+msgstr ""
+
+#: systemv/cupstestdsc.c:352
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment.\n"
+" REF: Page 43, %%Pages:"
+msgstr ""
+
+#: systemv/cupstestppd.c:1464
+msgid " NO ERRORS FOUND"
+msgstr ""
+
+#: systemv/cupstestdsc.c:395
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters."
+msgstr ""
+
+#: systemv/cupstestdsc.c:390
+#, c-format
+msgid " Too many %%BeginDocument comments."
+msgstr ""
+
+#: systemv/cupstestdsc.c:382
+#, c-format
+msgid " Too many %%EndDocument comments."
+msgstr ""
+
+#: systemv/cupstestdsc.c:402
+msgid " Warning: file contains binary data."
+msgstr ""
+
+#: systemv/cupstestdsc.c:410
+#, c-format
+msgid " Warning: no %%EndComments comment in file."
+msgstr ""
+
+#: systemv/cupstestdsc.c:406
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file."
+msgstr ""
+
+#: systemv/cupsctl.c:216
+msgid " --[no-]debug-logging Turn debug logging on/off."
+msgstr ""
+
+#: systemv/cupsctl.c:218
+msgid " --[no-]remote-admin Turn remote administration on/off."
+msgstr ""
+
+#: systemv/cupsctl.c:220
+msgid " --[no-]remote-any Allow/prevent access from the Internet."
+msgstr ""
+
+#: systemv/cupsctl.c:222
+msgid " --[no-]remote-printers Show/hide remote printers."
+msgstr ""
+
+#: systemv/cupsctl.c:224
+msgid " --[no-]share-printers Turn printer sharing on/off."
+msgstr ""
+
+#: systemv/cupsctl.c:226
+msgid " --[no-]user-cancel-any Allow/prevent users to cancel any job."
+msgstr ""
+
+#: ppdc/ppdc.cxx:456
+msgid " --cr End lines with CR (Mac OS 9)."
+msgstr ""
+
+#: ppdc/ppdc.cxx:458
+msgid " --crlf End lines with CR + LF (Windows)."
+msgstr ""
+
+#: ppdc/ppdc.cxx:460
+msgid " --lf End lines with LF (UNIX/Linux/Mac OS X)."
+msgstr ""
+
+#: test/ipptool.c:3828
+msgid " -4 Connect using IPv4."
+msgstr ""
+
+#: test/ipptool.c:3829
+msgid " -6 Connect using IPv6."
+msgstr ""
+
+#: test/ipptool.c:3830
+msgid " -C Send requests using chunking (default)."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1439 scheduler/cupsfilter.c:1466
+msgid " -D Remove the input file when finished."
+msgstr ""
+
+#: ppdc/ppdc.cxx:438 ppdc/ppdhtml.cxx:175 ppdc/ppdpo.cxx:255
+msgid " -D name=value Set named variable to value."
+msgstr ""
+
+#: systemv/cupsctl.c:211
+msgid " -E Enable encryption."
+msgstr ""
+
+#: systemv/cupsaddsmb.c:285
+msgid " -E Encrypt the connection to the server."
+msgstr ""
+
+#: test/ipptool.c:3832
+msgid " -E Test with TLS encryption."
+msgstr ""
+
+#: scheduler/main.c:2191
+msgid " -F Run in the foreground but detach from console."
+msgstr ""
+
+#: systemv/cupsaddsmb.c:287
+msgid " -H samba-server Use the named SAMBA server."
+msgstr ""
+
+#: test/ipptool.c:3834
+msgid " -I Ignore errors."
+msgstr ""
+
+#: ppdc/ppdc.cxx:440 ppdc/ppdhtml.cxx:177 ppdc/ppdi.cxx:131 ppdc/ppdpo.cxx:257
+msgid " -I include-dir Add include directory to search path."
+msgstr ""
+
+#: systemv/cupstestppd.c:3618
+msgid " -I {filename,filters,none,profiles}"
+msgstr ""
+
+#: scheduler/cupsfilter.c:1468
+msgid " -J title Set title."
+msgstr ""
+
+#: test/ipptool.c:3835
+msgid " -L Send requests using content-length."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1441 scheduler/cupsfilter.c:1469
+msgid " -P filename.ppd Set PPD file."
+msgstr ""
+
+#: systemv/cupstestppd.c:3620
+msgid " -R root-directory Set alternate root."
+msgstr ""
+
+#: test/ipptool.c:3837
+msgid " -S Test with SSL encryption."
+msgstr ""
+
+#: test/ipptool.c:3839
+msgid " -T Set the receive/send timeout in seconds."
+msgstr ""
+
+#: systemv/cupsaddsmb.c:289
+msgid " -U samba-user Authenticate using the named SAMBA user."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1442 scheduler/cupsfilter.c:1470
+msgid " -U username Set username for job."
+msgstr ""
+
+#: systemv/cupsctl.c:212
+msgid " -U username Specify username."
+msgstr ""
+
+#: test/ipptool.c:3841
+msgid " -V version Set default IPP version."
+msgstr ""
+
+#: systemv/cupstestppd.c:3621
+msgid " -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,translations}"
+msgstr ""
+
+#: test/ipptool.c:3843
+msgid " -X Produce XML plist instead of plain text."
+msgstr ""
+
+#: systemv/cupsaddsmb.c:291
+msgid " -a Export all printers."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1471
+msgid " -a 'name=value ...' Set option(s)."
+msgstr ""
+
+#: ppdc/ppdc.cxx:442
+msgid " -c catalog.po Load the specified message catalog."
+msgstr ""
+
+#: scheduler/main.c:2188
+msgid " -c config-file Load alternate configuration file."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1472
+msgid " -c copies Set number of copies."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1443
+msgid " -c cupsd.conf Set cupsd.conf file to use."
+msgstr ""
+
+#: test/ipptool.c:3845
+msgid " -d name=value Set named variable to value."
+msgstr ""
+
+#: ppdc/ppdc.cxx:444
+msgid " -d output-dir Specify the output directory."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1445 scheduler/cupsfilter.c:1473
+msgid " -d printer Use the named printer."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1447 scheduler/cupsfilter.c:1475
+msgid " -e Use every filter from the PPD file."
+msgstr ""
+
+#: scheduler/main.c:2190
+msgid " -f Run in the foreground."
+msgstr ""
+
+#: test/ipptool.c:3847
+msgid " -f filename Set default request filename."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1477
+msgid " -f filename Set file to be converted (otherwise stdin)."
+msgstr ""
+
+#: scheduler/main.c:2193
+msgid " -h Show this usage message."
+msgstr ""
+
+#: systemv/cupsaddsmb.c:292
+msgid " -h cups-server Use the named CUPS server."
+msgstr ""
+
+#: systemv/cupsctl.c:213
+msgid " -h server[:port] Specify server address."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1449 scheduler/cupsfilter.c:1479
+msgid " -i mime/type Set input MIME type (otherwise auto-typed)."
+msgstr ""
+
+#: test/ipptool.c:3849
+msgid " -i seconds Repeat the last file with the given time interval."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1451
+msgid " -j job-id[,N] Filter file N from the specified job (default is file 1)."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1481
+msgid " -j mime/type Set output MIME type (otherwise application/pdf)."
+msgstr ""
+
+#: scheduler/main.c:2194
+msgid " -l Run cupsd from launchd(8)."
+msgstr ""
+
+#: ppdc/ppdc.cxx:446
+msgid " -l lang[,lang,...] Specify the output language(s) (locale)."
+msgstr ""
+
+#: ppdc/ppdc.cxx:448
+msgid " -m Use the ModelName value as the filename."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1453
+msgid " -m mime/type Set output MIME type (otherwise application/pdf)."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1455
+msgid " -n copies Set number of copies."
+msgstr ""
+
+#: test/ipptool.c:3851
+msgid " -n count Repeat the last file the given number of times."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1483
+msgid " -o filename Set file to be generated (otherwise stdout)."
+msgstr ""
+
+#: ppdc/ppdi.cxx:133
+msgid " -o filename.drv Set driver information file (otherwise ppdi.drv)."
+msgstr ""
+
+#: ppdc/ppdmerge.cxx:370
+msgid " -o filename.ppd[.gz] Set output file (otherwise stdout)."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1456
+msgid " -o name=value Set option(s)."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1457
+msgid " -p filename.ppd Set PPD file."
+msgstr ""
+
+#: test/ipptool.c:3853
+msgid " -q Be quiet - no output except errors."
+msgstr ""
+
+#: systemv/cupstestppd.c:3625
+msgid " -q Run silently."
+msgstr ""
+
+#: systemv/cupstestppd.c:3626
+msgid " -r Use 'relaxed' open mode."
+msgstr ""
+
+#: test/ipptool.c:3855
+msgid " -t Produce a test report."
+msgstr ""
+
+#: ppdc/ppdc.cxx:450
+msgid " -t Test PPDs instead of generating them."
+msgstr ""
+
+#: scheduler/main.c:2195
+msgid " -t Test the configuration file."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1458
+msgid " -t title Set title."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1459 scheduler/cupsfilter.c:1485
+msgid " -u Remove the PPD file when finished."
+msgstr ""
+
+#: systemv/cupstestppd.c:3627
+msgid " -v Be slightly verbose."
+msgstr ""
+
+#: ppdc/ppdc.cxx:452 ppdc/ppdpo.cxx:259
+msgid " -v Be verbose (more v's for more verbosity)."
+msgstr ""
+
+#: systemv/cupsaddsmb.c:294
+msgid " -v Be verbose (show commands)."
+msgstr ""
+
+#: test/ipptool.c:3856
+msgid " -v Show all attributes sent and received."
+msgstr ""
+
+#: systemv/cupstestppd.c:3628
+msgid " -vv Be very verbose."
+msgstr ""
+
+#: ppdc/ppdc.cxx:454
+msgid " -z Compress PPD files using GNU zip."
+msgstr ""
+
+#: systemv/cupstestppd.c:333 systemv/cupstestppd.c:345
+#: systemv/cupstestppd.c:462 systemv/cupstestppd.c:477
+#: systemv/cupstestppd.c:498 systemv/cupstestppd.c:513
+#: systemv/cupstestppd.c:543 systemv/cupstestppd.c:563
+#: systemv/cupstestppd.c:586 systemv/cupstestppd.c:604
+#: systemv/cupstestppd.c:630 systemv/cupstestppd.c:648
+#: systemv/cupstestppd.c:668 systemv/cupstestppd.c:688
+#: systemv/cupstestppd.c:706 systemv/cupstestppd.c:722
+#: systemv/cupstestppd.c:740 systemv/cupstestppd.c:761
+#: systemv/cupstestppd.c:780 systemv/cupstestppd.c:800
+#: systemv/cupstestppd.c:820 systemv/cupstestppd.c:840
+#: systemv/cupstestppd.c:860 systemv/cupstestppd.c:878
+#: systemv/cupstestppd.c:895 systemv/cupstestppd.c:917
+#: systemv/cupstestppd.c:935 systemv/cupstestppd.c:952
+#: systemv/cupstestppd.c:970 systemv/cupstestppd.c:986
+#: systemv/cupstestppd.c:1006 systemv/cupstestppd.c:1037
+#: systemv/cupstestppd.c:1059 systemv/cupstestppd.c:1110
+#: systemv/cupstestppd.c:1129 systemv/cupstestppd.c:1173
+#: systemv/cupstestppd.c:1187 systemv/cupstestppd.c:1219
+#: systemv/cupstestppd.c:1246 systemv/cupstestppd.c:1764
+#: systemv/cupstestppd.c:1783 systemv/cupstestppd.c:1801
+#: systemv/cupstestppd.c:1853 systemv/cupstestppd.c:1869
+#: systemv/cupstestppd.c:1906 systemv/cupstestppd.c:1924
+#: systemv/cupstestppd.c:1960 systemv/cupstestppd.c:1974
+#: systemv/cupstestppd.c:2001 systemv/cupstestppd.c:2015
+#: systemv/cupstestppd.c:2061 systemv/cupstestppd.c:2083
+#: systemv/cupstestppd.c:2106 systemv/cupstestppd.c:2123
+#: systemv/cupstestppd.c:2165 systemv/cupstestppd.c:2208
+#: systemv/cupstestppd.c:2255 systemv/cupstestppd.c:2279
+#: systemv/cupstestppd.c:2331 systemv/cupstestppd.c:2361
+#: systemv/cupstestppd.c:2375 systemv/cupstestppd.c:2401
+#: systemv/cupstestppd.c:2417 systemv/cupstestppd.c:2447
+#: systemv/cupstestppd.c:2461 systemv/cupstestppd.c:2488
+#: systemv/cupstestppd.c:2505 systemv/cupstestppd.c:2519
+#: systemv/cupstestppd.c:2543 systemv/cupstestppd.c:2560
+#: systemv/cupstestppd.c:2574 systemv/cupstestppd.c:2598
+#: systemv/cupstestppd.c:2615 systemv/cupstestppd.c:2629
+#: systemv/cupstestppd.c:2653 systemv/cupstestppd.c:2670
+#: systemv/cupstestppd.c:2684 systemv/cupstestppd.c:2708
+#: systemv/cupstestppd.c:2722 systemv/cupstestppd.c:2737
+#: systemv/cupstestppd.c:2754 systemv/cupstestppd.c:2810
+#: systemv/cupstestppd.c:2845 systemv/cupstestppd.c:2859
+#: systemv/cupstestppd.c:2887 systemv/cupstestppd.c:2952
+#: systemv/cupstestppd.c:2967 systemv/cupstestppd.c:3005
+#: systemv/cupstestppd.c:3025 systemv/cupstestppd.c:3039
+#: systemv/cupstestppd.c:3206 systemv/cupstestppd.c:3242
+#: systemv/cupstestppd.c:3256 systemv/cupstestppd.c:3302
+#: systemv/cupstestppd.c:3334 systemv/cupstestppd.c:3351
+#: systemv/cupstestppd.c:3374 systemv/cupstestppd.c:3390
+#: systemv/cupstestppd.c:3428 systemv/cupstestppd.c:3569
+#: systemv/cupstestppd.c:3591 systemv/cupstestppd.c:3699
+msgid " FAIL"
+msgstr ""
+
+#: systemv/cupstestppd.c:1270
+msgid " PASS"
+msgstr ""
+
+#: berkeley/lpq.c:560
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes"
+msgstr ""
+
+#: berkeley/lpq.c:565
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes"
+msgstr ""
+
+#: filter/bannertops.c:784
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr ""
+
+#: filter/bannertops.c:805
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr ""
+
+#: filter/bannertops.c:775
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr ""
+
+#: filter/bannertops.c:794
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr ""
+
+#: systemv/lpstat.c:747
+#, c-format
+msgid "%s accepting requests since %s"
+msgstr ""
+
+#: scheduler/ipp.c:11155
+#, c-format
+msgid "%s cannot be changed."
+msgstr ""
+
+#: berkeley/lpc.c:189
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc."
+msgstr ""
+
+#: berkeley/lpq.c:651
+#, c-format
+msgid "%s is not ready"
+msgstr ""
+
+#: berkeley/lpq.c:644
+#, c-format
+msgid "%s is ready"
+msgstr ""
+
+#: berkeley/lpq.c:647
+#, c-format
+msgid "%s is ready and printing"
+msgstr ""
+
+#: driver/rastertoescpx.c:1775 driver/rastertopclx.c:1800
+#: filter/rastertoepson.c:985 filter/rastertohp.c:711
+#: filter/rastertolabel.c:1134
+#, c-format
+msgid "%s job-id user title copies options [file]"
+msgstr ""
+
+#: systemv/lpstat.c:751
+#, c-format
+msgid "%s not accepting requests since %s -"
+msgstr ""
+
+#: scheduler/ipp.c:718
+#, c-format
+msgid "%s not supported."
+msgstr ""
+
+#: systemv/lpstat.c:762
+#, c-format
+msgid "%s/%s accepting requests since %s"
+msgstr ""
+
+#: systemv/lpstat.c:767
+#, c-format
+msgid "%s/%s not accepting requests since %s -"
+msgstr ""
+
+#: berkeley/lpq.c:552
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]"
+msgstr ""
+
+#. TRANSLATORS: Message is "subject: error"
+#: cups/langprintf.c:86 scheduler/cupsfilter.c:720 systemv/lpadmin.c:805
+#: systemv/lpadmin.c:856 systemv/lpadmin.c:906 systemv/lpadmin.c:962
+#: systemv/lpadmin.c:1060 systemv/lpadmin.c:1113 systemv/lpadmin.c:1170
+#: systemv/lpadmin.c:1481
+#, c-format
+msgid "%s: %s"
+msgstr ""
+
+#: systemv/cancel.c:294 systemv/cancel.c:357
+#, c-format
+msgid "%s: %s failed: %s"
+msgstr ""
+
+#: systemv/cupsaccept.c:68
+#, c-format
+msgid "%s: Don't know what to do."
+msgstr ""
+
+#: berkeley/lpq.c:236 berkeley/lpr.c:344 systemv/lp.c:584
+#, c-format
+msgid "%s: Error - %s environment variable names non-existent destination \"%s\"."
+msgstr ""
+
+#: systemv/lp.c:231
+#, c-format
+msgid "%s: Error - bad job ID."
+msgstr ""
+
+#: systemv/lp.c:219
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously."
+msgstr ""
+
+#: systemv/lp.c:505
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided."
+msgstr ""
+
+#: systemv/lp.c:461
+#, c-format
+msgid "%s: Error - expected character set after \"-S\" option."
+msgstr ""
+
+#: systemv/lp.c:480
+#, c-format
+msgid "%s: Error - expected content type after \"-T\" option."
+msgstr ""
+
+#: berkeley/lpr.c:240
+#, c-format
+msgid "%s: Error - expected copies after \"-#\" option."
+msgstr ""
+
+#: systemv/lp.c:264
+#, c-format
+msgid "%s: Error - expected copies after \"-n\" option."
+msgstr ""
+
+#: berkeley/lpr.c:209
+#, c-format
+msgid "%s: Error - expected destination after \"-P\" option."
+msgstr ""
+
+#: systemv/lpstat.c:231
+#, c-format
+msgid "%s: Error - expected destination after \"-b\" option."
+msgstr ""
+
+#: systemv/lp.c:138
+#, c-format
+msgid "%s: Error - expected destination after \"-d\" option."
+msgstr ""
+
+#: systemv/lp.c:168
+#, c-format
+msgid "%s: Error - expected form after \"-f\" option."
+msgstr ""
+
+#: systemv/lp.c:391
+#, c-format
+msgid "%s: Error - expected hold name after \"-H\" option."
+msgstr ""
+
+#: berkeley/lpr.c:103
+#, c-format
+msgid "%s: Error - expected hostname after \"-H\" option."
+msgstr ""
+
+#: berkeley/lpq.c:180 berkeley/lprm.c:123 systemv/cancel.c:124
+#: systemv/cupsaccept.c:123 systemv/lp.c:189 systemv/lpstat.c:291
+#, c-format
+msgid "%s: Error - expected hostname after \"-h\" option."
+msgstr ""
+
+#: systemv/lp.c:371
+#, c-format
+msgid "%s: Error - expected mode list after \"-y\" option."
+msgstr ""
+
+#: berkeley/lpr.c:263
+#, c-format
+msgid "%s: Error - expected name after \"-%c\" option."
+msgstr ""
+
+#: berkeley/lpr.c:153 systemv/lp.c:288
+#, c-format
+msgid "%s: Error - expected option=value after \"-o\" option."
+msgstr ""
+
+#: systemv/lp.c:441
+#, c-format
+msgid "%s: Error - expected page list after \"-P\" option."
+msgstr ""
+
+#: systemv/lp.c:308
+#, c-format
+msgid "%s: Error - expected priority after \"-%c\" option."
+msgstr ""
+
+#: systemv/cupsaccept.c:141
+#, c-format
+msgid "%s: Error - expected reason text after \"-r\" option."
+msgstr ""
+
+#: systemv/lp.c:354
+#, c-format
+msgid "%s: Error - expected title after \"-t\" option."
+msgstr ""
+
+#: berkeley/lpq.c:111 berkeley/lpr.c:84 berkeley/lprm.c:104
+#: systemv/cancel.c:94 systemv/cupsaccept.c:101 systemv/lp.c:116
+#: systemv/lpadmin.c:438 systemv/lpstat.c:137
+#, c-format
+msgid "%s: Error - expected username after \"-U\" option."
+msgstr ""
+
+#: systemv/cancel.c:145
+#, c-format
+msgid "%s: Error - expected username after \"-u\" option."
+msgstr ""
+
+#: berkeley/lpr.c:125
+#, c-format
+msgid "%s: Error - expected value after \"-%c\" option."
+msgstr ""
+
+#: systemv/lpstat.c:157 systemv/lpstat.c:171
+#, c-format
+msgid "%s: Error - need \"completed\", \"not-completed\", or \"all\" after \"-W\" option."
+msgstr ""
+
+#: berkeley/lpq.c:241 berkeley/lpr.c:349 systemv/lp.c:589
+#, c-format
+msgid "%s: Error - no default destination available."
+msgstr ""
+
+#: systemv/lp.c:330
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100."
+msgstr ""
+
+#: berkeley/lpr.c:352 systemv/lp.c:592
+#, c-format
+msgid "%s: Error - scheduler not responding."
+msgstr ""
+
+#: berkeley/lpr.c:305 systemv/lp.c:537
+#, c-format
+msgid "%s: Error - too many files - \"%s\"."
+msgstr ""
+
+#: berkeley/lpr.c:287 systemv/lp.c:520
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s"
+msgstr ""
+
+#: berkeley/lpr.c:396 systemv/lp.c:624
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s."
+msgstr ""
+
+#: berkeley/lprm.c:87 berkeley/lprm.c:172 systemv/cancel.c:214
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"."
+msgstr ""
+
+#: berkeley/lpq.c:150
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"."
+msgstr ""
+
+#: berkeley/lpr.c:274 berkeley/lprm.c:139 systemv/cancel.c:156
+#: systemv/cupsaccept.c:164 systemv/lp.c:496 systemv/lpstat.c:452
+#, c-format
+msgid "%s: Error - unknown option \"%c\"."
+msgstr ""
+
+#: systemv/cupsaccept.c:157
+#, c-format
+msgid "%s: Error - unknown option \"%s\"."
+msgstr ""
+
+#: systemv/lp.c:208
+#, c-format
+msgid "%s: Expected job ID after \"-i\" option."
+msgstr ""
+
+#: systemv/lpstat.c:504 systemv/lpstat.c:543
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"."
+msgstr ""
+
+#: scheduler/cupsfilter.c:575
+#, c-format
+msgid "%s: Invalid filter string \"%s\"."
+msgstr ""
+
+#: systemv/lp.c:418
+#, c-format
+msgid "%s: Need job ID (\"-i jobid\") before \"-H restart\"."
+msgstr ""
+
+#: scheduler/cupsfilter.c:466
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s."
+msgstr ""
+
+#: systemv/cupsaccept.c:198
+#, c-format
+msgid "%s: Operation failed: %s"
+msgstr ""
+
+#: berkeley/lpq.c:97 berkeley/lpr.c:70 berkeley/lprm.c:67 systemv/cancel.c:81
+#: systemv/cupsaccept.c:88 systemv/cupsaddsmb.c:86 systemv/lp.c:102
+#: systemv/lpadmin.c:239 systemv/lpinfo.c:88 systemv/lpmove.c:73
+#: systemv/lpstat.c:102 test/ipptool.c:278 test/ipptool.c:295
+#, c-format
+msgid "%s: Sorry, no encryption support."
+msgstr ""
+
+#: berkeley/lpq.c:295 scheduler/cupsfilter.c:1227 systemv/cancel.c:237
+#: systemv/cupsaddsmb.c:144 systemv/cupsaddsmb.c:171
+#, c-format
+msgid "%s: Unable to connect to server."
+msgstr ""
+
+#: systemv/cancel.c:317
+#, c-format
+msgid "%s: Unable to contact server."
+msgstr ""
+
+#: scheduler/cupsfilter.c:432
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"."
+msgstr ""
+
+#: ppdc/ppdmerge.cxx:96
+#, c-format
+msgid "%s: Unable to open %s: %s"
+msgstr ""
+
+#: scheduler/cupsfilter.c:670 ppdc/ppdmerge.cxx:112
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d."
+msgstr ""
+
+#: scheduler/cupsfilter.c:397
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"."
+msgstr ""
+
+#: berkeley/lpq.c:153 systemv/lpstat.c:558
+#, c-format
+msgid "%s: Unknown destination \"%s\"."
+msgstr ""
+
+#: scheduler/cupsfilter.c:443
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1433
+#, c-format
+msgid "%s: Unknown option \"%c\"."
+msgstr ""
+
+#: scheduler/cupsfilter.c:424
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s."
+msgstr ""
+
+#: berkeley/lpr.c:139
+#, c-format
+msgid "%s: Warning - \"%c\" format modifier not supported - output may not be correct."
+msgstr ""
+
+#: systemv/lp.c:468
+#, c-format
+msgid "%s: Warning - character set option ignored."
+msgstr ""
+
+#: systemv/lp.c:487
+#, c-format
+msgid "%s: Warning - content type option ignored."
+msgstr ""
+
+#: systemv/lp.c:175
+#, c-format
+msgid "%s: Warning - form option ignored."
+msgstr ""
+
+#: systemv/lp.c:378
+#, c-format
+msgid "%s: Warning - mode option ignored."
+msgstr ""
+
+#: ppdc/sample.c:316
+msgid "-1"
+msgstr ""
+
+#: ppdc/sample.c:307
+msgid "-10"
+msgstr ""
+
+#: ppdc/sample.c:399
+msgid "-100"
+msgstr ""
+
+#: ppdc/sample.c:398
+msgid "-105"
+msgstr ""
+
+#: ppdc/sample.c:306
+msgid "-11"
+msgstr ""
+
+#: ppdc/sample.c:397
+msgid "-110"
+msgstr ""
+
+#: ppdc/sample.c:396
+msgid "-115"
+msgstr ""
+
+#: ppdc/sample.c:305
+msgid "-12"
+msgstr ""
+
+#: ppdc/sample.c:395
+msgid "-120"
+msgstr ""
+
+#: ppdc/sample.c:304
+msgid "-13"
+msgstr ""
+
+#: ppdc/sample.c:303
+msgid "-14"
+msgstr ""
+
+#: ppdc/sample.c:302
+msgid "-15"
+msgstr ""
+
+#: ppdc/sample.c:315
+msgid "-2"
+msgstr ""
+
+#: ppdc/sample.c:415
+msgid "-20"
+msgstr ""
+
+#: ppdc/sample.c:414
+msgid "-25"
+msgstr ""
+
+#: ppdc/sample.c:314
+msgid "-3"
+msgstr ""
+
+#: ppdc/sample.c:413
+msgid "-30"
+msgstr ""
+
+#: ppdc/sample.c:412
+msgid "-35"
+msgstr ""
+
+#: ppdc/sample.c:313
+msgid "-4"
+msgstr ""
+
+#: ppdc/sample.c:411
+msgid "-40"
+msgstr ""
+
+#: ppdc/sample.c:410
+msgid "-45"
+msgstr ""
+
+#: ppdc/sample.c:312
+msgid "-5"
+msgstr ""
+
+#: ppdc/sample.c:409
+msgid "-50"
+msgstr ""
+
+#: ppdc/sample.c:408
+msgid "-55"
+msgstr ""
+
+#: ppdc/sample.c:311
+msgid "-6"
+msgstr ""
+
+#: ppdc/sample.c:407
+msgid "-60"
+msgstr ""
+
+#: ppdc/sample.c:406
+msgid "-65"
+msgstr ""
+
+#: ppdc/sample.c:310
+msgid "-7"
+msgstr ""
+
+#: ppdc/sample.c:405
+msgid "-70"
+msgstr ""
+
+#: ppdc/sample.c:404
+msgid "-75"
+msgstr ""
+
+#: ppdc/sample.c:309
+msgid "-8"
+msgstr ""
+
+#: ppdc/sample.c:403
+msgid "-80"
+msgstr ""
+
+#: ppdc/sample.c:402
+msgid "-85"
+msgstr ""
+
+#: ppdc/sample.c:308
+msgid "-9"
+msgstr ""
+
+#: ppdc/sample.c:401
+msgid "-90"
+msgstr ""
+
+#: ppdc/sample.c:400
+msgid "-95"
+msgstr ""
+
+#: ppdc/sample.c:317
+msgid "0"
+msgstr ""
+
+#: ppdc/sample.c:318
+msgid "1"
+msgstr ""
+
+#: ppdc/sample.c:390
+msgid "1 inch/sec."
+msgstr ""
+
+#: ppdc/sample.c:178
+msgid "1.25x0.25\""
+msgstr ""
+
+#: ppdc/sample.c:179
+msgid "1.25x2.25\""
+msgstr ""
+
+#: ppdc/sample.c:438
+msgid "1.5 inch/sec."
+msgstr ""
+
+#: ppdc/sample.c:180
+msgid "1.50x0.25\""
+msgstr ""
+
+#: ppdc/sample.c:181
+msgid "1.50x0.50\""
+msgstr ""
+
+#: ppdc/sample.c:182
+msgid "1.50x1.00\""
+msgstr ""
+
+#: ppdc/sample.c:183
+msgid "1.50x2.00\""
+msgstr ""
+
+#: ppdc/sample.c:327
+msgid "10"
+msgstr ""
+
+#: ppdc/sample.c:449
+msgid "10 inches/sec."
+msgstr ""
+
+#: ppdc/sample.c:3
+msgid "10 x 11\""
+msgstr ""
+
+#: ppdc/sample.c:4
+msgid "10 x 13\""
+msgstr ""
+
+#: ppdc/sample.c:5
+msgid "10 x 14\""
+msgstr ""
+
+#: ppdc/sample.c:429
+msgid "100"
+msgstr ""
+
+#: ppdc/sample.c:340
+msgid "100 mm/sec."
+msgstr ""
+
+#: ppdc/sample.c:430
+msgid "105"
+msgstr ""
+
+#: ppdc/sample.c:328
+msgid "11"
+msgstr ""
+
+#: ppdc/sample.c:450
+msgid "11 inches/sec."
+msgstr ""
+
+#: ppdc/sample.c:431
+msgid "110"
+msgstr ""
+
+#: ppdc/sample.c:432
+msgid "115"
+msgstr ""
+
+#: ppdc/sample.c:329
+msgid "12"
+msgstr ""
+
+#: ppdc/sample.c:451
+msgid "12 inches/sec."
+msgstr ""
+
+#: ppdc/sample.c:6
+msgid "12 x 11\""
+msgstr ""
+
+#: ppdc/sample.c:433
+msgid "120"
+msgstr ""
+
+#: ppdc/sample.c:341
+msgid "120 mm/sec."
+msgstr ""
+
+#: ppdc/sample.c:249
+msgid "120x60dpi"
+msgstr ""
+
+#: ppdc/sample.c:255
+msgid "120x72dpi"
+msgstr ""
+
+#: ppdc/sample.c:330
+msgid "13"
+msgstr ""
+
+#: ppdc/sample.c:238
+msgid "136dpi"
+msgstr ""
+
+#: ppdc/sample.c:331
+msgid "14"
+msgstr ""
+
+#: ppdc/sample.c:332
+msgid "15"
+msgstr ""
+
+#: ppdc/sample.c:334
+msgid "15 mm/sec."
+msgstr ""
+
+#: ppdc/sample.c:7
+msgid "15 x 11\""
+msgstr ""
+
+#: ppdc/sample.c:342
+msgid "150 mm/sec."
+msgstr ""
+
+#: ppdc/sample.c:289
+msgid "150dpi"
+msgstr ""
+
+#: ppdc/sample.c:374
+msgid "16"
+msgstr ""
+
+#: ppdc/sample.c:375
+msgid "17"
+msgstr ""
+
+#: ppdc/sample.c:376
+msgid "18"
+msgstr ""
+
+#: ppdc/sample.c:250
+msgid "180dpi"
+msgstr ""
+
+#: ppdc/sample.c:377
+msgid "19"
+msgstr ""
+
+#: ppdc/sample.c:319
+msgid "2"
+msgstr ""
+
+#: ppdc/sample.c:391
+msgid "2 inches/sec."
+msgstr ""
+
+#: ppdc/sample.c:276
+msgid "2-Sided Printing"
+msgstr ""
+
+#: ppdc/sample.c:184
+msgid "2.00x0.37\""
+msgstr ""
+
+#: ppdc/sample.c:185
+msgid "2.00x0.50\""
+msgstr ""
+
+#: ppdc/sample.c:186
+msgid "2.00x1.00\""
+msgstr ""
+
+#: ppdc/sample.c:187
+msgid "2.00x1.25\""
+msgstr ""
+
+#: ppdc/sample.c:188
+msgid "2.00x2.00\""
+msgstr ""
+
+#: ppdc/sample.c:189
+msgid "2.00x3.00\""
+msgstr ""
+
+#: ppdc/sample.c:190
+msgid "2.00x4.00\""
+msgstr ""
+
+#: ppdc/sample.c:191
+msgid "2.00x5.50\""
+msgstr ""
+
+#: ppdc/sample.c:192
+msgid "2.25x0.50\""
+msgstr ""
+
+#: ppdc/sample.c:193
+msgid "2.25x1.25\""
+msgstr ""
+
+#: ppdc/sample.c:194
+msgid "2.25x4.00\""
+msgstr ""
+
+#: ppdc/sample.c:195
+msgid "2.25x5.50\""
+msgstr ""
+
+#: ppdc/sample.c:196
+msgid "2.38x5.50\""
+msgstr ""
+
+#: ppdc/sample.c:439
+msgid "2.5 inches/sec."
+msgstr ""
+
+#: ppdc/sample.c:197
+msgid "2.50x1.00\""
+msgstr ""
+
+#: ppdc/sample.c:198
+msgid "2.50x2.00\""
+msgstr ""
+
+#: ppdc/sample.c:199
+msgid "2.75x1.25\""
+msgstr ""
+
+#: ppdc/sample.c:200
+msgid "2.9 x 1\""
+msgstr ""
+
+#: ppdc/sample.c:378
+msgid "20"
+msgstr ""
+
+#: ppdc/sample.c:335
+msgid "20 mm/sec."
+msgstr ""
+
+#: ppdc/sample.c:343
+msgid "200 mm/sec."
+msgstr ""
+
+#: ppdc/sample.c:239
+msgid "203dpi"
+msgstr ""
+
+#: ppdc/sample.c:379
+msgid "21"
+msgstr ""
+
+#: ppdc/sample.c:380
+msgid "22"
+msgstr ""
+
+#: ppdc/sample.c:381
+msgid "23"
+msgstr ""
+
+#: ppdc/sample.c:382
+msgid "24"
+msgstr ""
+
+#: ppdc/sample.c:247
+msgid "24-Pin Series"
+msgstr ""
+
+#: ppdc/sample.c:256
+msgid "240x72dpi"
+msgstr ""
+
+#: ppdc/sample.c:383
+msgid "25"
+msgstr ""
+
+#: ppdc/sample.c:344
+msgid "250 mm/sec."
+msgstr ""
+
+#: ppdc/sample.c:384
+msgid "26"
+msgstr ""
+
+#: ppdc/sample.c:385
+msgid "27"
+msgstr ""
+
+#: ppdc/sample.c:386
+msgid "28"
+msgstr ""
+
+#: ppdc/sample.c:387
+msgid "29"
+msgstr ""
+
+#: ppdc/sample.c:320
+msgid "3"
+msgstr ""
+
+#: ppdc/sample.c:392
+msgid "3 inches/sec."
+msgstr ""
+
+#: ppdc/sample.c:201
+msgid "3.00x1.00\""
+msgstr ""
+
+#: ppdc/sample.c:202
+msgid "3.00x1.25\""
+msgstr ""
+
+#: ppdc/sample.c:203
+msgid "3.00x2.00\""
+msgstr ""
+
+#: ppdc/sample.c:204
+msgid "3.00x3.00\""
+msgstr ""
+
+#: ppdc/sample.c:205
+msgid "3.00x5.00\""
+msgstr ""
+
+#: ppdc/sample.c:206
+msgid "3.25x2.00\""
+msgstr ""
+
+#: ppdc/sample.c:207
+msgid "3.25x5.00\""
+msgstr ""
+
+#: ppdc/sample.c:208
+msgid "3.25x5.50\""
+msgstr ""
+
+#: ppdc/sample.c:209
+msgid "3.25x5.83\""
+msgstr ""
+
+#: ppdc/sample.c:210
+msgid "3.25x7.83\""
+msgstr ""
+
+#: ppdc/sample.c:168
+msgid "3.5\" Disk"
+msgstr ""
+
+#: ppdc/sample.c:177
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr ""
+
+#: ppdc/sample.c:211
+msgid "3.50x1.00\""
+msgstr ""
+
+#: ppdc/sample.c:388
+msgid "30"
+msgstr ""
+
+#: ppdc/sample.c:336
+msgid "30 mm/sec."
+msgstr ""
+
+#: ppdc/sample.c:345
+msgid "300 mm/sec."
+msgstr ""
+
+#: ppdc/sample.c:240
+msgid "300dpi"
+msgstr ""
+
+#: ppdc/sample.c:416
+msgid "35"
+msgstr ""
+
+#: ppdc/sample.c:252
+msgid "360dpi"
+msgstr ""
+
+#: ppdc/sample.c:251
+msgid "360x180dpi"
+msgstr ""
+
+#: ppdc/sample.c:321
+msgid "4"
+msgstr ""
+
+#: ppdc/sample.c:393
+msgid "4 inches/sec."
+msgstr ""
+
+#: ppdc/sample.c:212
+msgid "4.00x1.00\""
+msgstr ""
+
+#: ppdc/sample.c:220
+msgid "4.00x13.00\""
+msgstr ""
+
+#: ppdc/sample.c:213
+msgid "4.00x2.00\""
+msgstr ""
+
+#: ppdc/sample.c:214
+msgid "4.00x2.50\""
+msgstr ""
+
+#: ppdc/sample.c:215
+msgid "4.00x3.00\""
+msgstr ""
+
+#: ppdc/sample.c:216
+msgid "4.00x4.00\""
+msgstr ""
+
+#: ppdc/sample.c:217
+msgid "4.00x5.00\""
+msgstr ""
+
+#: ppdc/sample.c:218
+msgid "4.00x6.00\""
+msgstr ""
+
+#: ppdc/sample.c:219
+msgid "4.00x6.50\""
+msgstr ""
+
+#: ppdc/sample.c:417
+msgid "40"
+msgstr ""
+
+#: ppdc/sample.c:337
+msgid "40 mm/sec."
+msgstr ""
+
+#: ppdc/sample.c:418
+msgid "45"
+msgstr ""
+
+#: ppdc/sample.c:322
+msgid "5"
+msgstr ""
+
+#: ppdc/sample.c:443
+msgid "5 inches/sec."
+msgstr ""
+
+#: ppdc/sample.c:419
+msgid "50"
+msgstr ""
+
+#: ppdc/sample.c:420
+msgid "55"
+msgstr ""
+
+#: ppdc/sample.c:323
+msgid "6"
+msgstr ""
+
+#: ppdc/sample.c:444
+msgid "6 inches/sec."
+msgstr ""
+
+#: ppdc/sample.c:221
+msgid "6.00x1.00\""
+msgstr ""
+
+#: ppdc/sample.c:222
+msgid "6.00x2.00\""
+msgstr ""
+
+#: ppdc/sample.c:223
+msgid "6.00x3.00\""
+msgstr ""
+
+#: ppdc/sample.c:224
+msgid "6.00x4.00\""
+msgstr ""
+
+#: ppdc/sample.c:225
+msgid "6.00x5.00\""
+msgstr ""
+
+#: ppdc/sample.c:226
+msgid "6.00x6.00\""
+msgstr ""
+
+#: ppdc/sample.c:227
+msgid "6.00x6.50\""
+msgstr ""
+
+#: ppdc/sample.c:421
+msgid "60"
+msgstr ""
+
+#: ppdc/sample.c:338
+msgid "60 mm/sec."
+msgstr ""
+
+#: ppdc/sample.c:267
+msgid "600dpi"
+msgstr ""
+
+#: ppdc/sample.c:248
+msgid "60dpi"
+msgstr ""
+
+#: ppdc/sample.c:254
+msgid "60x72dpi"
+msgstr ""
+
+#: ppdc/sample.c:422
+msgid "65"
+msgstr ""
+
+#: ppdc/sample.c:324
+msgid "7"
+msgstr ""
+
+#: ppdc/sample.c:446
+msgid "7 inches/sec."
+msgstr ""
+
+#: ppdc/sample.c:8
+msgid "7 x 9\""
+msgstr ""
+
+#: ppdc/sample.c:423
+msgid "70"
+msgstr ""
+
+#: ppdc/sample.c:258
+msgid "720dpi"
+msgstr ""
+
+#: ppdc/sample.c:424
+msgid "75"
+msgstr ""
+
+#: ppdc/sample.c:325
+msgid "8"
+msgstr ""
+
+#: ppdc/sample.c:447
+msgid "8 inches/sec."
+msgstr ""
+
+#: ppdc/sample.c:9
+msgid "8 x 10\""
+msgstr ""
+
+#: ppdc/sample.c:228
+msgid "8.00x1.00\""
+msgstr ""
+
+#: ppdc/sample.c:229
+msgid "8.00x2.00\""
+msgstr ""
+
+#: ppdc/sample.c:230
+msgid "8.00x3.00\""
+msgstr ""
+
+#: ppdc/sample.c:231
+msgid "8.00x4.00\""
+msgstr ""
+
+#: ppdc/sample.c:232
+msgid "8.00x5.00\""
+msgstr ""
+
+#: ppdc/sample.c:233
+msgid "8.00x6.00\""
+msgstr ""
+
+#: ppdc/sample.c:234
+msgid "8.00x6.50\""
+msgstr ""
+
+#: ppdc/sample.c:425
+msgid "80"
+msgstr ""
+
+#: ppdc/sample.c:339
+msgid "80 mm/sec."
+msgstr ""
+
+#: ppdc/sample.c:426
+msgid "85"
+msgstr ""
+
+#: ppdc/sample.c:326
+msgid "9"
+msgstr ""
+
+#: ppdc/sample.c:448
+msgid "9 inches/sec."
+msgstr ""
+
+#: ppdc/sample.c:10
+msgid "9 x 11\""
+msgstr ""
+
+#: ppdc/sample.c:11
+msgid "9 x 12\""
+msgstr ""
+
+#: ppdc/sample.c:253
+msgid "9-Pin Series"
+msgstr ""
+
+#: ppdc/sample.c:427
+msgid "90"
+msgstr ""
+
+#: ppdc/sample.c:428
+msgid "95"
+msgstr ""
+
+#: berkeley/lpc.c:213
+msgid "?Invalid help command unknown."
+msgstr ""
+
+#: cgi-bin/admin.c:2443
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+#: cgi-bin/admin.c:2439
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#: scheduler/ipp.c:2431
+#, c-format
+msgid "A class named \"%s\" already exists."
+msgstr ""
+
+#: scheduler/ipp.c:1034
+#, c-format
+msgid "A printer named \"%s\" already exists."
+msgstr ""
+
+#: ppdc/sample.c:12
+msgid "A0"
+msgstr ""
+
+#: ppdc/sample.c:13
+msgid "A0 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:14
+msgid "A1"
+msgstr ""
+
+#: ppdc/sample.c:15
+msgid "A1 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:34
+msgid "A10"
+msgstr ""
+
+#: ppdc/sample.c:16
+msgid "A2"
+msgstr ""
+
+#: ppdc/sample.c:17
+msgid "A2 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:18
+msgid "A3"
+msgstr ""
+
+#: ppdc/sample.c:19
+msgid "A3 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:20
+msgid "A3 Oversize"
+msgstr ""
+
+#: ppdc/sample.c:21
+msgid "A3 Oversize Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:22
+msgid "A4"
+msgstr ""
+
+#: ppdc/sample.c:24
+msgid "A4 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:23
+msgid "A4 Oversize"
+msgstr ""
+
+#: ppdc/sample.c:25
+msgid "A4 Small"
+msgstr ""
+
+#: ppdc/sample.c:26
+msgid "A5"
+msgstr ""
+
+#: ppdc/sample.c:28
+msgid "A5 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:27
+msgid "A5 Oversize"
+msgstr ""
+
+#: ppdc/sample.c:29
+msgid "A6"
+msgstr ""
+
+#: ppdc/sample.c:30
+msgid "A6 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:31
+msgid "A7"
+msgstr ""
+
+#: ppdc/sample.c:32
+msgid "A8"
+msgstr ""
+
+#: ppdc/sample.c:33
+msgid "A9"
+msgstr ""
+
+#: ppdc/sample.c:35
+msgid "ANSI A"
+msgstr ""
+
+#: ppdc/sample.c:36
+msgid "ANSI B"
+msgstr ""
+
+#: ppdc/sample.c:37
+msgid "ANSI C"
+msgstr ""
+
+#: ppdc/sample.c:38
+msgid "ANSI D"
+msgstr ""
+
+#: ppdc/sample.c:39
+msgid "ANSI E"
+msgstr ""
+
+#: ppdc/sample.c:44
+msgid "ARCH C"
+msgstr ""
+
+#: ppdc/sample.c:45
+msgid "ARCH C Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:46
+msgid "ARCH D"
+msgstr ""
+
+#: ppdc/sample.c:47
+msgid "ARCH D Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:48
+msgid "ARCH E"
+msgstr ""
+
+#: ppdc/sample.c:49
+msgid "ARCH E Long Edge"
+msgstr ""
+
+#: cgi-bin/classes.c:169 cgi-bin/printers.c:172
+msgid "Accept Jobs"
+msgstr ""
+
+#: cups/http-support.c:1254
+msgid "Accepted"
+msgstr ""
+
+#: cgi-bin/admin.c:570
+msgid "Add Class"
+msgstr ""
+
+#: cgi-bin/admin.c:883
+msgid "Add Printer"
+msgstr ""
+
+#: cgi-bin/admin.c:444 cgi-bin/admin.c:477 cgi-bin/admin.c:525
+#: cgi-bin/admin.c:535
+msgid "Add RSS Subscription"
+msgstr ""
+
+#: ppdc/sample.c:160
+msgid "Address"
+msgstr ""
+
+#: ppdc/sample.c:169
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr ""
+
+#: cgi-bin/admin.c:210 cgi-bin/admin.c:284 cgi-bin/admin.c:2864
+msgid "Administration"
+msgstr ""
+
+#: ppdc/sample.c:435
+msgid "Always"
+msgstr ""
+
+#: backend/socket.c:129
+msgid "AppSocket/HP JetDirect"
+msgstr ""
+
+#: ppdc/sample.c:456
+msgid "Applicator"
+msgstr ""
+
+#: scheduler/ipp.c:1159
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d."
+msgstr ""
+
+#: scheduler/ipp.c:352
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)."
+msgstr ""
+
+#: ppdc/sample.c:123
+msgid "B0"
+msgstr ""
+
+#: ppdc/sample.c:124
+msgid "B1"
+msgstr ""
+
+#: ppdc/sample.c:134
+msgid "B10"
+msgstr ""
+
+#: ppdc/sample.c:125
+msgid "B2"
+msgstr ""
+
+#: ppdc/sample.c:126
+msgid "B3"
+msgstr ""
+
+#: ppdc/sample.c:127
+msgid "B4"
+msgstr ""
+
+#: ppdc/sample.c:128
+msgid "B5"
+msgstr ""
+
+#: ppdc/sample.c:129
+msgid "B5 Oversize"
+msgstr ""
+
+#: ppdc/sample.c:130
+msgid "B6"
+msgstr ""
+
+#: ppdc/sample.c:131
+msgid "B7"
+msgstr ""
+
+#: ppdc/sample.c:132
+msgid "B8"
+msgstr ""
+
+#: ppdc/sample.c:133
+msgid "B9"
+msgstr ""
+
+#: cups/dest.c:827
+msgid "Bad NULL dests pointer"
+msgstr ""
+
+#: cups/ppd.c:345
+msgid "Bad OpenGroup"
+msgstr ""
+
+#: cups/ppd.c:347
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr ""
+
+#: cups/ppd.c:349
+msgid "Bad OrderDependency"
+msgstr ""
+
+#: cups/ppd-cache.c:144 cups/ppd-cache.c:189 cups/ppd-cache.c:227
+#: cups/ppd-cache.c:233 cups/ppd-cache.c:249 cups/ppd-cache.c:265
+#: cups/ppd-cache.c:274 cups/ppd-cache.c:282 cups/ppd-cache.c:299
+#: cups/ppd-cache.c:307 cups/ppd-cache.c:322 cups/ppd-cache.c:330
+#: cups/ppd-cache.c:348 cups/ppd-cache.c:360 cups/ppd-cache.c:375
+#: cups/ppd-cache.c:387 cups/ppd-cache.c:409 cups/ppd-cache.c:417
+#: cups/ppd-cache.c:435 cups/ppd-cache.c:443 cups/ppd-cache.c:458
+#: cups/ppd-cache.c:466 cups/ppd-cache.c:484 cups/ppd-cache.c:492
+#: cups/ppd-cache.c:519 cups/ppd-cache.c:546 cups/ppd-cache.c:554
+#: cups/ppd-cache.c:562
+msgid "Bad PPD cache file."
+msgstr ""
+
+#: cups/http-support.c:1269
+msgid "Bad Request"
+msgstr ""
+
+#: cups/snmp.c:1002
+msgid "Bad SNMP version number"
+msgstr ""
+
+#: cups/ppd.c:350
+msgid "Bad UIConstraints"
+msgstr ""
+
+#: filter/pstext.c:278 filter/texttops.c:297 filter/texttops.c:309
+#, c-format
+msgid "Bad charset file \"%s\"."
+msgstr ""
+
+#: filter/texttops.c:472
+#, c-format
+msgid "Bad charset type: %s"
+msgstr ""
+
+#: filter/textcommon.c:613
+#, c-format
+msgid "Bad columns value %d."
+msgstr ""
+
+#: scheduler/ipp.c:1460
+#, c-format
+msgid "Bad copies value %d."
+msgstr ""
+
+#: filter/textcommon.c:625
+#, c-format
+msgid "Bad cpi value %f."
+msgstr ""
+
+#: cups/ppd.c:358
+msgid "Bad custom parameter"
+msgstr ""
+
+#: cups/http-support.c:1421 scheduler/ipp.c:2550
+#, c-format
+msgid "Bad device-uri \"%s\"."
+msgstr ""
+
+#: scheduler/ipp.c:2591
+#, c-format
+msgid "Bad device-uri scheme \"%s\"."
+msgstr ""
+
+#: scheduler/ipp.c:9382 scheduler/ipp.c:9398 scheduler/ipp.c:10574
+#: scheduler/ipp.c:12079
+#, c-format
+msgid "Bad document-format \"%s\"."
+msgstr ""
+
+#: scheduler/ipp.c:10590
+#, c-format
+msgid "Bad document-format-default \"%s\"."
+msgstr ""
+
+#: cups/util.c:927
+msgid "Bad filename buffer"
+msgstr ""
+
+#: filter/pstext.c:324 filter/pstext.c:362
+#, c-format
+msgid "Bad font description line \"%s\"."
+msgstr ""
+
+#: filter/texttops.c:364 filter/texttops.c:402
+#, c-format
+msgid "Bad font description line: %s"
+msgstr ""
+
+#: scheduler/ipp.c:11171
+msgid "Bad job-priority value."
+msgstr ""
+
+#: scheduler/ipp.c:1490
+#, c-format
+msgid "Bad job-sheets value \"%s\"."
+msgstr ""
+
+#: scheduler/ipp.c:1474
+msgid "Bad job-sheets value type."
+msgstr ""
+
+#: scheduler/ipp.c:11201
+msgid "Bad job-state value."
+msgstr ""
+
+#: scheduler/ipp.c:4057 scheduler/ipp.c:4510 scheduler/ipp.c:7242
+#: scheduler/ipp.c:7389 scheduler/ipp.c:8832 scheduler/ipp.c:9085
+#: scheduler/ipp.c:9933 scheduler/ipp.c:10158 scheduler/ipp.c:10475
+#: scheduler/ipp.c:11063
+#, c-format
+msgid "Bad job-uri \"%s\"."
+msgstr ""
+
+#: filter/textcommon.c:637
+#, c-format
+msgid "Bad lpi value %f."
+msgstr ""
+
+#: scheduler/ipp.c:2194 scheduler/ipp.c:6784
+#, c-format
+msgid "Bad notify-pull-method \"%s\"."
+msgstr ""
+
+#: scheduler/ipp.c:2158 scheduler/ipp.c:6748
+#, c-format
+msgid "Bad notify-recipient-uri \"%s\"."
+msgstr ""
+
+#: scheduler/ipp.c:1506
+#, c-format
+msgid "Bad number-up value %d."
+msgstr ""
+
+#: cups/adminutil.c:292
+#, c-format
+msgid "Bad option + choice on line %d."
+msgstr ""
+
+#: scheduler/ipp.c:1523
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr ""
+
+#: scheduler/ipp.c:2634
+#, c-format
+msgid "Bad port-monitor \"%s\"."
+msgstr ""
+
+#: scheduler/ipp.c:2695
+#, c-format
+msgid "Bad printer-state value %d."
+msgstr ""
+
+#: scheduler/ipp.c:320
+#, c-format
+msgid "Bad request ID %d."
+msgstr ""
+
+#: scheduler/ipp.c:305
+#, c-format
+msgid "Bad request version number %d.%d."
+msgstr ""
+
+#: cgi-bin/admin.c:1485
+msgid "Bad subscription ID"
+msgstr ""
+
+#: filter/pstext.c:337
+#, c-format
+msgid "Bad text direction \"%s\"."
+msgstr ""
+
+#: filter/texttops.c:377
+#, c-format
+msgid "Bad text direction: %s"
+msgstr ""
+
+#: filter/pstext.c:375
+#, c-format
+msgid "Bad text width \"%s\"."
+msgstr ""
+
+#: filter/texttops.c:416
+#, c-format
+msgid "Bad text width: %s"
+msgstr ""
+
+#: cups/ppd.c:360
+msgid "Bad value string"
+msgstr ""
+
+#: cgi-bin/admin.c:3409 cgi-bin/admin.c:3655
+msgid "Banners"
+msgstr ""
+
+#: filter/bannertops.c:666
+msgid "Billing Information: "
+msgstr ""
+
+#: ppdc/sample.c:293
+msgid "Bond Paper"
+msgstr ""
+
+#: backend/usb-darwin.c:1861
+#, c-format
+msgid "Boolean expected for waiteof option \"%s\"."
+msgstr ""
+
+#: filter/pstops.c:2113
+msgid "Buffer overflow detected, aborting."
+msgstr ""
+
+#: ppdc/sample.c:260
+msgid "CMYK"
+msgstr ""
+
+#: ppdc/sample.c:369
+msgid "CPCL Label Printer"
+msgstr ""
+
+#: cgi-bin/admin.c:1486 cgi-bin/admin.c:1525 cgi-bin/admin.c:1535
+msgid "Cancel RSS Subscription"
+msgstr ""
+
+#: backend/ipp.c:1793
+msgid "Canceling print job."
+msgstr ""
+
+#: scheduler/ipp.c:2675
+msgid "Cannot share a remote Kerberized printer."
+msgstr ""
+
+#: ppdc/sample.c:285
+msgid "Cassette"
+msgstr ""
+
+#: cgi-bin/admin.c:1708 cgi-bin/admin.c:1872 cgi-bin/admin.c:1884
+#: cgi-bin/admin.c:1895
+msgid "Change Settings"
+msgstr ""
+
+#: scheduler/ipp.c:2206 scheduler/ipp.c:6796
+#, c-format
+msgid "Character set \"%s\" not supported."
+msgstr ""
+
+#: cgi-bin/classes.c:195 cgi-bin/classes.c:322
+msgid "Classes"
+msgstr ""
+
+#: cgi-bin/printers.c:182
+msgid "Clean Print Heads"
+msgstr ""
+
+#: scheduler/ipp.c:4959
+msgid "Close-Job doesn't support the job-uri attribute."
+msgstr ""
+
+#: ppdc/sample.c:288
+msgid "Color"
+msgstr ""
+
+#: ppdc/sample.c:259
+msgid "Color Mode"
+msgstr ""
+
+#: berkeley/lpc.c:204
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?"
+msgstr ""
+
+#: cups/snmp.c:1006
+msgid "Community name uses indefinite length"
+msgstr ""
+
+#: backend/ipp.c:762 backend/lpd.c:868 backend/socket.c:395
+msgid "Connected to printer."
+msgstr ""
+
+#: backend/ipp.c:669 backend/lpd.c:708 backend/socket.c:314
+msgid "Connecting to printer."
+msgstr ""
+
+#: cups/http-support.c:1242
+msgid "Continue"
+msgstr ""
+
+#: ppdc/sample.c:371
+msgid "Continuous"
+msgstr ""
+
+#: backend/lpd.c:1019 backend/lpd.c:1161
+msgid "Control file sent successfully."
+msgstr ""
+
+#: backend/ipp.c:1186 backend/lpd.c:462
+msgid "Copying print data."
+msgstr ""
+
+#: cups/http-support.c:1251
+msgid "Created"
+msgstr ""
+
+#: filter/bannertops.c:854
+msgid "Created On: "
+msgstr ""
+
+#: cups/ppd.c:1073 cups/ppd.c:1113 cups/ppd.c:1358 cups/ppd.c:1461
+msgid "Custom"
+msgstr ""
+
+#: ppdc/sample.c:365
+msgid "CustominCutInterval"
+msgstr ""
+
+#: ppdc/sample.c:363
+msgid "CustominTearInterval"
+msgstr ""
+
+#: ppdc/sample.c:349
+msgid "Cut"
+msgstr ""
+
+#: ppdc/sample.c:457
+msgid "Cutter"
+msgstr ""
+
+#: ppdc/sample.c:245
+msgid "Dark"
+msgstr ""
+
+#: ppdc/sample.c:241
+msgid "Darkness"
+msgstr ""
+
+#: backend/lpd.c:1109
+msgid "Data file sent successfully."
+msgstr ""
+
+#: cgi-bin/admin.c:2168 cgi-bin/admin.c:2179 cgi-bin/admin.c:2224
+msgid "Delete Class"
+msgstr ""
+
+#: cgi-bin/admin.c:2253 cgi-bin/admin.c:2264 cgi-bin/admin.c:2309
+msgid "Delete Printer"
+msgstr ""
+
+#: filter/bannertops.c:735
+msgid "Description: "
+msgstr ""
+
+#: ppdc/sample.c:287
+msgid "DeskJet Series"
+msgstr ""
+
+#: scheduler/ipp.c:1426
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr ""
+
+#: systemv/lpinfo.c:300
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s"
+msgstr ""
+
+#: ppdc/sample.c:442
+msgid "Direct Thermal Media"
+msgstr ""
+
+#: cups/file.c:263
+#, c-format
+msgid "Directory \"%s\" has insecure permissions (0%o/uid=%d/gid=%d)."
+msgstr ""
+
+#: cups/file.c:280
+#, c-format
+msgid "Directory \"%s\" is a file."
+msgstr ""
+
+#: cups/file.c:251
+#, c-format
+msgid "Directory \"%s\" not available: %s"
+msgstr ""
+
+#: cups/file.c:236
+#, c-format
+msgid "Directory \"%s\" permissions OK (0%o/uid=%d/gid=%d)."
+msgstr ""
+
+#: ppdc/sample.c:351
+msgid "Disabled"
+msgstr ""
+
+#: scheduler/ipp.c:7291
+#, c-format
+msgid "Document #%d does not exist in job #%d."
+msgstr ""
+
+#: filter/bannertops.c:820
+msgid "Driver Name: "
+msgstr ""
+
+#: filter/bannertops.c:831
+msgid "Driver Version: "
+msgstr ""
+
+#: ppdc/sample.c:281
+msgid "Duplexer"
+msgstr ""
+
+#: ppdc/sample.c:235
+msgid "Dymo"
+msgstr ""
+
+#: ppdc/sample.c:437
+msgid "EPL1 Label Printer"
+msgstr ""
+
+#: ppdc/sample.c:440
+msgid "EPL2 Label Printer"
+msgstr ""
+
+#: cgi-bin/admin.c:1923 cgi-bin/admin.c:1935 cgi-bin/admin.c:1989
+#: cgi-bin/admin.c:1996 cgi-bin/admin.c:2031 cgi-bin/admin.c:2044
+#: cgi-bin/admin.c:2068 cgi-bin/admin.c:2141
+msgid "Edit Configuration File"
+msgstr ""
+
+#: cups/adminutil.c:337
+msgid "Empty PPD file."
+msgstr ""
+
+#. TRANSLATORS: Banner/cover sheet after the print job.
+#: cgi-bin/admin.c:3680
+msgid "Ending Banner"
+msgstr ""
+
+#: ppdc/sample.c:2
+msgid "English"
+msgstr ""
+
+#: systemv/lppasswd.c:193
+msgid "Enter old password:"
+msgstr ""
+
+#: systemv/lppasswd.c:224
+msgid "Enter password again:"
+msgstr ""
+
+#: systemv/lppasswd.c:212
+msgid "Enter password:"
+msgstr ""
+
+#: scheduler/client.c:2439
+msgid "Enter your username and password or the root username and password to access this page. If you are using Kerberos authentication, make sure you have a valid Kerberos ticket."
+msgstr ""
+
+#: ppdc/sample.c:70
+msgid "Envelope #10 "
+msgstr ""
+
+#: ppdc/sample.c:71
+msgid "Envelope #11"
+msgstr ""
+
+#: ppdc/sample.c:72
+msgid "Envelope #12"
+msgstr ""
+
+#: ppdc/sample.c:73
+msgid "Envelope #14"
+msgstr ""
+
+#: ppdc/sample.c:74
+msgid "Envelope #9"
+msgstr ""
+
+#: ppdc/sample.c:86
+msgid "Envelope B4"
+msgstr ""
+
+#: ppdc/sample.c:87
+msgid "Envelope B5"
+msgstr ""
+
+#: ppdc/sample.c:88
+msgid "Envelope B6"
+msgstr ""
+
+#: ppdc/sample.c:75
+msgid "Envelope C0"
+msgstr ""
+
+#: ppdc/sample.c:76
+msgid "Envelope C1"
+msgstr ""
+
+#: ppdc/sample.c:77
+msgid "Envelope C2"
+msgstr ""
+
+#: ppdc/sample.c:78
+msgid "Envelope C3"
+msgstr ""
+
+#: ppdc/sample.c:64
+msgid "Envelope C4"
+msgstr ""
+
+#: ppdc/sample.c:65
+msgid "Envelope C5"
+msgstr ""
+
+#: ppdc/sample.c:66
+msgid "Envelope C6"
+msgstr ""
+
+#: ppdc/sample.c:79
+msgid "Envelope C65"
+msgstr ""
+
+#: ppdc/sample.c:80
+msgid "Envelope C7"
+msgstr ""
+
+#: ppdc/sample.c:81
+msgid "Envelope Choukei 3"
+msgstr ""
+
+#: ppdc/sample.c:82
+msgid "Envelope Choukei 3 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:83
+msgid "Envelope Choukei 4"
+msgstr ""
+
+#: ppdc/sample.c:84
+msgid "Envelope Choukei 4 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:67
+msgid "Envelope DL"
+msgstr ""
+
+#: ppdc/sample.c:275
+msgid "Envelope Feed"
+msgstr ""
+
+#: ppdc/sample.c:85
+msgid "Envelope Invite"
+msgstr ""
+
+#: ppdc/sample.c:89
+msgid "Envelope Italian"
+msgstr ""
+
+#: ppdc/sample.c:90
+msgid "Envelope Kaku2"
+msgstr ""
+
+#: ppdc/sample.c:91
+msgid "Envelope Kaku2 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:92
+msgid "Envelope Kaku3"
+msgstr ""
+
+#: ppdc/sample.c:93
+msgid "Envelope Kaku3 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:94
+msgid "Envelope Monarch"
+msgstr ""
+
+#: ppdc/sample.c:96
+msgid "Envelope PRC1 "
+msgstr ""
+
+#: ppdc/sample.c:97
+msgid "Envelope PRC1 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:114
+msgid "Envelope PRC10"
+msgstr ""
+
+#: ppdc/sample.c:115
+msgid "Envelope PRC10 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:98
+msgid "Envelope PRC2"
+msgstr ""
+
+#: ppdc/sample.c:99
+msgid "Envelope PRC2 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:100
+msgid "Envelope PRC3"
+msgstr ""
+
+#: ppdc/sample.c:101
+msgid "Envelope PRC3 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:102
+msgid "Envelope PRC4"
+msgstr ""
+
+#: ppdc/sample.c:103
+msgid "Envelope PRC4 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:105
+msgid "Envelope PRC5 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:104
+msgid "Envelope PRC5PRC5"
+msgstr ""
+
+#: ppdc/sample.c:106
+msgid "Envelope PRC6"
+msgstr ""
+
+#: ppdc/sample.c:107
+msgid "Envelope PRC6 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:108
+msgid "Envelope PRC7"
+msgstr ""
+
+#: ppdc/sample.c:109
+msgid "Envelope PRC7 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:110
+msgid "Envelope PRC8"
+msgstr ""
+
+#: ppdc/sample.c:111
+msgid "Envelope PRC8 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:112
+msgid "Envelope PRC9"
+msgstr ""
+
+#: ppdc/sample.c:113
+msgid "Envelope PRC9 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:95
+msgid "Envelope Personal"
+msgstr ""
+
+#: ppdc/sample.c:116
+msgid "Envelope You4"
+msgstr ""
+
+#: ppdc/sample.c:117
+msgid "Envelope You4 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:246
+msgid "Epson"
+msgstr ""
+
+#: cgi-bin/admin.c:3723
+msgid "Error Policy"
+msgstr ""
+
+#: filter/rastertopwg.c:160 filter/rastertopwg.c:175 filter/rastertopwg.c:186
+#: filter/rastertopwg.c:197
+msgid "Error sending raster data."
+msgstr ""
+
+#: systemv/lpinfo.c:103 systemv/lpmove.c:88
+msgid "Error: need hostname after \"-h\" option."
+msgstr ""
+
+#: ppdc/sample.c:361
+msgid "Every 10 Labels"
+msgstr ""
+
+#: ppdc/sample.c:353
+msgid "Every 2 Labels"
+msgstr ""
+
+#: ppdc/sample.c:354
+msgid "Every 3 Labels"
+msgstr ""
+
+#: ppdc/sample.c:355
+msgid "Every 4 Labels"
+msgstr ""
+
+#: ppdc/sample.c:356
+msgid "Every 5 Labels"
+msgstr ""
+
+#: ppdc/sample.c:357
+msgid "Every 6 Labels"
+msgstr ""
+
+#: ppdc/sample.c:358
+msgid "Every 7 Labels"
+msgstr ""
+
+#: ppdc/sample.c:359
+msgid "Every 8 Labels"
+msgstr ""
+
+#: ppdc/sample.c:360
+msgid "Every 9 Labels"
+msgstr ""
+
+#: ppdc/sample.c:352
+msgid "Every Label"
+msgstr ""
+
+#: ppdc/sample.c:118
+msgid "Executive"
+msgstr ""
+
+#: cups/http-support.c:1297
+msgid "Expectation Failed"
+msgstr ""
+
+#: cgi-bin/admin.c:2431 cgi-bin/admin.c:2450
+msgid "Export Printers to Samba"
+msgstr ""
+
+#: systemv/cupstestdsc.c:172 systemv/cupstestdsc.c:189
+#: systemv/cupstestdsc.c:214 systemv/cupstestdsc.c:231
+#: systemv/cupstestdsc.c:255 systemv/cupstestdsc.c:273
+#: systemv/cupstestdsc.c:302 systemv/cupstestdsc.c:339
+#: systemv/cupstestdsc.c:349 systemv/cupstestdsc.c:359
+#: systemv/cupstestdsc.c:369 systemv/cupstestdsc.c:379
+#: systemv/cupstestdsc.c:387
+msgid "FAIL"
+msgstr ""
+
+#: ppdc/sample.c:119
+msgid "FanFold German"
+msgstr ""
+
+#: ppdc/sample.c:120
+msgid "FanFold Legal German"
+msgstr ""
+
+#: ppdc/sample.c:121
+msgid "Fanfold US"
+msgstr ""
+
+#: cups/file.c:270
+#, c-format
+msgid "File \"%s\" has insecure permissions (0%o/uid=%d/gid=%d)."
+msgstr ""
+
+#: cups/file.c:284
+#, c-format
+msgid "File \"%s\" is a directory."
+msgstr ""
+
+#: cups/file.c:256
+#, c-format
+msgid "File \"%s\" not available: %s"
+msgstr ""
+
+#: cups/file.c:242
+#, c-format
+msgid "File \"%s\" permissions OK (0%o/uid=%d/gid=%d)."
+msgstr ""
+
+#: ppdc/sample.c:166
+msgid "File Folder"
+msgstr ""
+
+#: ppdc/sample.c:175
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr ""
+
+#: scheduler/ipp.c:2570
+#, c-format
+msgid "File device URIs have been disabled. To enable, see the FileDevice directive in \"%s/cupsd.conf\"."
+msgstr ""
+
+#: driver/rastertoescpx.c:1899 driver/rastertopclx.c:1924
+#: filter/rastertoepson.c:1117 filter/rastertohp.c:845
+#: filter/rastertolabel.c:1273
+#, c-format
+msgid "Finished page %d."
+msgstr ""
+
+#: ppdc/sample.c:122
+msgid "Folio"
+msgstr ""
+
+#: cups/http-support.c:1276
+msgid "Forbidden"
+msgstr ""
+
+#: filter/imagetoraster.c:1187
+#, c-format
+msgid "Formatting page %d."
+msgstr ""
+
+#: cups/ppd.c:701 cups/ppd.c:1262
+msgid "General"
+msgstr ""
+
+#: ppdc/sample.c:265
+msgid "Generic"
+msgstr ""
+
+#: cups/snmp.c:1016
+msgid "Get-Response-PDU uses indefinite length"
+msgstr ""
+
+#: ppdc/sample.c:296
+msgid "Glossy Paper"
+msgstr ""
+
+#: scheduler/ipp.c:4035 scheduler/ipp.c:4436 scheduler/ipp.c:4971
+#: scheduler/ipp.c:7220 scheduler/ipp.c:7367 scheduler/ipp.c:8809
+#: scheduler/ipp.c:9911 scheduler/ipp.c:10136 scheduler/ipp.c:10453
+#: scheduler/ipp.c:11041
+msgid "Got a printer-uri attribute but no job-id."
+msgstr ""
+
+#: ppdc/sample.c:261
+msgid "Grayscale"
+msgstr ""
+
+#: ppdc/sample.c:286
+msgid "HP"
+msgstr ""
+
+#: ppdc/sample.c:167
+msgid "Hanging Folder"
+msgstr ""
+
+#: ppdc/sample.c:176
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr ""
+
+#: ppdc/sample.c:1
+msgid "ISOLatin1"
+msgstr ""
+
+#: cups/ppd.c:353
+msgid "Illegal control character"
+msgstr ""
+
+#: cups/ppd.c:354
+msgid "Illegal main keyword string"
+msgstr ""
+
+#: cups/ppd.c:355
+msgid "Illegal option keyword string"
+msgstr ""
+
+#: cups/ppd.c:356
+msgid "Illegal translation string"
+msgstr ""
+
+#: cups/ppd.c:357
+msgid "Illegal whitespace character"
+msgstr ""
+
+#: ppdc/sample.c:280
+msgid "Installable Options"
+msgstr ""
+
+#: ppdc/sample.c:283
+msgid "Installed"
+msgstr ""
+
+#: ppdc/sample.c:299
+msgid "IntelliBar Label Printer"
+msgstr ""
+
+#: ppdc/sample.c:298
+msgid "Intellitech"
+msgstr ""
+
+#: cups/http-support.c:1303
+msgid "Internal Server Error"
+msgstr ""
+
+#: cups/ppd.c:344
+msgid "Internal error"
+msgstr ""
+
+#: ppdc/sample.c:164
+msgid "Internet Postage 2-Part"
+msgstr ""
+
+#: ppdc/sample.c:173
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr ""
+
+#: ppdc/sample.c:165
+msgid "Internet Postage 3-Part"
+msgstr ""
+
+#: ppdc/sample.c:174
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr ""
+
+#: backend/ipp.c:293
+msgid "Internet Printing Protocol"
+msgstr ""
+
+#: cups/ppd.c:1380
+msgid "JCL"
+msgstr ""
+
+#: ppdc/sample.c:50
+msgid "JIS B0"
+msgstr ""
+
+#: ppdc/sample.c:52
+msgid "JIS B1"
+msgstr ""
+
+#: ppdc/sample.c:51
+msgid "JIS B10"
+msgstr ""
+
+#: ppdc/sample.c:53
+msgid "JIS B2"
+msgstr ""
+
+#: ppdc/sample.c:54
+msgid "JIS B3"
+msgstr ""
+
+#: ppdc/sample.c:55
+msgid "JIS B4"
+msgstr ""
+
+#: ppdc/sample.c:56
+msgid "JIS B4 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:57
+msgid "JIS B5"
+msgstr ""
+
+#: ppdc/sample.c:58
+msgid "JIS B5 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:59
+msgid "JIS B6"
+msgstr ""
+
+#: ppdc/sample.c:60
+msgid "JIS B6 Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:61
+msgid "JIS B7"
+msgstr ""
+
+#: ppdc/sample.c:62
+msgid "JIS B8"
+msgstr ""
+
+#: ppdc/sample.c:63
+msgid "JIS B9"
+msgstr ""
+
+#: scheduler/ipp.c:10208
+#, c-format
+msgid "Job #%d cannot be restarted - no files."
+msgstr ""
+
+#: scheduler/ipp.c:4075 scheduler/ipp.c:4306 scheduler/ipp.c:4361
+#: scheduler/ipp.c:4538 scheduler/ipp.c:4981 scheduler/ipp.c:6882
+#: scheduler/ipp.c:7260 scheduler/ipp.c:7407 scheduler/ipp.c:7707
+#: scheduler/ipp.c:8656 scheduler/ipp.c:8678 scheduler/ipp.c:8850
+#: scheduler/ipp.c:9059 scheduler/ipp.c:9102 scheduler/ipp.c:9951
+#: scheduler/ipp.c:10176 scheduler/ipp.c:10493 scheduler/ipp.c:11081
+#, c-format
+msgid "Job #%d does not exist."
+msgstr ""
+
+#: scheduler/ipp.c:4570
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr ""
+
+#: scheduler/ipp.c:4564
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr ""
+
+#: scheduler/ipp.c:4576
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr ""
+
+#: scheduler/ipp.c:9144 scheduler/ipp.c:11096
+#, c-format
+msgid "Job #%d is finished and cannot be altered."
+msgstr ""
+
+#: scheduler/ipp.c:10190
+#, c-format
+msgid "Job #%d is not complete."
+msgstr ""
+
+#: scheduler/ipp.c:4090
+#, c-format
+msgid "Job #%d is not held for authentication."
+msgstr ""
+
+#: scheduler/ipp.c:9965
+#, c-format
+msgid "Job #%d is not held."
+msgstr ""
+
+#: cgi-bin/ipp-var.c:1055
+msgid "Job Completed"
+msgstr ""
+
+#: cgi-bin/ipp-var.c:1053
+msgid "Job Created"
+msgstr ""
+
+#: filter/bannertops.c:623
+msgid "Job ID: "
+msgstr ""
+
+#: cgi-bin/ipp-var.c:1059
+msgid "Job Options Changed"
+msgstr ""
+
+#: cgi-bin/ipp-var.c:1057
+msgid "Job Stopped"
+msgstr ""
+
+#: filter/bannertops.c:631
+msgid "Job UUID: "
+msgstr ""
+
+#: scheduler/ipp.c:11179
+msgid "Job is completed and cannot be changed."
+msgstr ""
+
+#: cgi-bin/jobs.c:198
+msgid "Job operation failed:"
+msgstr ""
+
+#: scheduler/ipp.c:11215 scheduler/ipp.c:11234 scheduler/ipp.c:11245
+msgid "Job state cannot be changed."
+msgstr ""
+
+#: scheduler/ipp.c:10056
+msgid "Job subscriptions cannot be renewed."
+msgstr ""
+
+#: cgi-bin/jobs.c:103 cgi-bin/jobs.c:114 cgi-bin/jobs.c:195
+msgid "Jobs"
+msgstr ""
+
+#: backend/lpd.c:185
+msgid "LPD/LPR Host or Printer"
+msgstr ""
+
+#: ppdc/sample.c:236
+msgid "Label Printer"
+msgstr ""
+
+#: ppdc/sample.c:452
+msgid "Label Top"
+msgstr ""
+
+#: scheduler/ipp.c:2215 scheduler/ipp.c:6805
+#, c-format
+msgid "Language \"%s\" not supported."
+msgstr ""
+
+#: ppdc/sample.c:161
+msgid "Large Address"
+msgstr ""
+
+#: ppdc/sample.c:170
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr ""
+
+#: ppdc/sample.c:297
+msgid "LaserJet Series PCL 4/5"
+msgstr ""
+
+#: ppdc/sample.c:40
+msgid "Letter Oversize"
+msgstr ""
+
+#: ppdc/sample.c:41
+msgid "Letter Oversize Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:242
+msgid "Light"
+msgstr ""
+
+#: cups/ppd.c:352
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr ""
+
+#: cgi-bin/admin.c:2468
+msgid "List Available Printers"
+msgstr ""
+
+#: filter/imagetoraster.c:667
+msgid "Loading print file."
+msgstr ""
+
+#: filter/bannertops.c:744
+msgid "Location: "
+msgstr ""
+
+#: ppdc/sample.c:278
+msgid "Long-Edge (Portrait)"
+msgstr ""
+
+#: cups/http-support.c:1518
+msgid "Looking for printer."
+msgstr ""
+
+#: filter/bannertops.c:753
+msgid "Make and Model: "
+msgstr ""
+
+#: ppdc/sample.c:274
+msgid "Manual Feed"
+msgstr ""
+
+#: filter/bannertops.c:780
+msgid "Media Dimensions: "
+msgstr ""
+
+#: filter/bannertops.c:800
+msgid "Media Limits: "
+msgstr ""
+
+#: filter/bannertops.c:769
+msgid "Media Name: "
+msgstr ""
+
+#: cups/ppd.c:748 cups/ppd.c:1317
+msgid "Media Size"
+msgstr ""
+
+#: cups/ppd.c:752 cups/ppd.c:1321 ppdc/sample.c:268
+msgid "Media Source"
+msgstr ""
+
+#: ppdc/sample.c:370
+msgid "Media Tracking"
+msgstr ""
+
+#: cups/ppd.c:750 cups/ppd.c:1319 ppdc/sample.c:291
+msgid "Media Type"
+msgstr ""
+
+#: ppdc/sample.c:243
+msgid "Medium"
+msgstr ""
+
+#: cups/ppd.c:341
+msgid "Memory allocation error"
+msgstr ""
+
+#: cups/ppd.c:361
+msgid "Missing CloseGroup"
+msgstr ""
+
+#: cups/ppd.c:342
+msgid "Missing PPD-Adobe-4.x header"
+msgstr ""
+
+#: cups/ppd.c:351
+msgid "Missing asterisk in column 1"
+msgstr ""
+
+#: scheduler/ipp.c:7283
+msgid "Missing document-number attribute."
+msgstr ""
+
+#: cups/adminutil.c:273
+#, c-format
+msgid "Missing double quote on line %d."
+msgstr ""
+
+#: cgi-bin/admin.c:737 cgi-bin/admin.c:2180 cgi-bin/admin.c:2265
+#: cgi-bin/admin.c:2904 cgi-bin/admin.c:3158 cgi-bin/admin.c:3269
+#: cgi-bin/admin.c:3979
+msgid "Missing form variable"
+msgstr ""
+
+#: cups/pwg-media.c:470
+msgid "Missing media or media-col."
+msgstr ""
+
+#: cups/pwg-media.c:389
+msgid "Missing media-size in media-col."
+msgstr ""
+
+#: scheduler/ipp.c:7837
+msgid "Missing notify-subscription-ids attribute."
+msgstr ""
+
+#: cups/ppd.c:359
+msgid "Missing option keyword"
+msgstr ""
+
+#: scheduler/ipp.c:4217 scheduler/ipp.c:4242
+msgid "Missing requesting-user-name attribute."
+msgstr ""
+
+#: scheduler/ipp.c:488
+msgid "Missing required attributes."
+msgstr ""
+
+#: filter/bannertops.c:222
+#, c-format
+msgid "Missing value on line %d of banner file."
+msgstr ""
+
+#: cups/adminutil.c:254
+#, c-format
+msgid "Missing value on line %d."
+msgstr ""
+
+#: cups/ppd.c:343
+msgid "Missing value string"
+msgstr ""
+
+#: cups/pwg-media.c:377
+msgid "Missing x-dimension in media-size."
+msgstr ""
+
+#: cups/pwg-media.c:383
+msgid "Missing y-dimension in media-size."
+msgstr ""
+
+#: systemv/lpinfo.c:470
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s"
+msgstr ""
+
+#: cgi-bin/admin.c:570
+msgid "Modify Class"
+msgstr ""
+
+#: cgi-bin/admin.c:883
+msgid "Modify Printer"
+msgstr ""
+
+#: cgi-bin/ipp-var.c:425 cgi-bin/ipp-var.c:516
+msgid "Move All Jobs"
+msgstr ""
+
+#: cgi-bin/ipp-var.c:364 cgi-bin/ipp-var.c:423 cgi-bin/ipp-var.c:514
+msgid "Move Job"
+msgstr ""
+
+#: cups/http-support.c:1260
+msgid "Moved Permanently"
+msgstr ""
+
+#: cups/ppd.c:340
+msgid "NULL PPD file pointer"
+msgstr ""
+
+#: cups/snmp.c:1053
+msgid "Name OID uses indefinite length"
+msgstr ""
+
+#: scheduler/ipp.c:1222
+msgid "Nested classes are not allowed."
+msgstr ""
+
+#: ppdc/sample.c:436
+msgid "Never"
+msgstr ""
+
+#: ppdc/sample.c:262
+msgid "New Stylus Color Series"
+msgstr ""
+
+#: ppdc/sample.c:264
+msgid "New Stylus Photo Series"
+msgstr ""
+
+#: cups/ppd.c:1909
+msgid "No"
+msgstr ""
+
+#: cups/http-support.c:1257
+msgid "No Content"
+msgstr ""
+
+#: cups/util.c:1286
+msgid "No PPD name"
+msgstr ""
+
+#: cups/snmp.c:1047
+msgid "No VarBind SEQUENCE"
+msgstr ""
+
+#: cups/adminutil.c:788
+msgid "No Windows printer drivers are installed."
+msgstr ""
+
+#: cups/request.c:577 cups/request.c:871
+msgid "No active connection"
+msgstr ""
+
+#: scheduler/ipp.c:4487
+#, c-format
+msgid "No active jobs on %s."
+msgstr ""
+
+#: scheduler/ipp.c:329
+msgid "No attributes in request."
+msgstr ""
+
+#: scheduler/ipp.c:4118
+msgid "No authentication information provided."
+msgstr ""
+
+#: cups/snmp.c:1004
+msgid "No community name"
+msgstr ""
+
+#: scheduler/ipp.c:7083
+msgid "No default printer."
+msgstr ""
+
+#: cgi-bin/ipp-var.c:436 scheduler/ipp.c:8413
+msgid "No destinations added."
+msgstr ""
+
+#: backend/usb.c:200
+msgid "No device URI found in argv[0] or in DEVICE_URI environment variable."
+msgstr ""
+
+#: cups/snmp.c:1034
+msgid "No error-index"
+msgstr ""
+
+#: cups/snmp.c:1026
+msgid "No error-status"
+msgstr ""
+
+#: scheduler/ipp.c:9348 scheduler/ipp.c:10556
+msgid "No file in print request."
+msgstr ""
+
+#: filter/pstext.c:438
+msgid "No fonts in charset file."
+msgstr ""
+
+#: cups/util.c:921
+msgid "No modification time"
+msgstr ""
+
+#: cups/snmp.c:1051
+msgid "No name OID"
+msgstr ""
+
+#: driver/rastertoescpx.c:1918 driver/rastertopclx.c:1943
+#: filter/rastertoepson.c:1147 filter/rastertohp.c:876
+#: filter/rastertolabel.c:1302
+msgid "No pages were found."
+msgstr ""
+
+#: cups/util.c:915
+msgid "No printer name"
+msgstr ""
+
+#: cups/util.c:1789
+msgid "No printer-uri found"
+msgstr ""
+
+#: cups/util.c:1774
+msgid "No printer-uri found for class"
+msgstr ""
+
+#: scheduler/ipp.c:7486
+msgid "No printer-uri in request."
+msgstr ""
+
+#: cups/snmp.c:1018
+msgid "No request-id"
+msgstr ""
+
+#: scheduler/ipp.c:6690
+msgid "No subscription attributes in request."
+msgstr ""
+
+#: scheduler/ipp.c:8749
+msgid "No subscriptions found."
+msgstr ""
+
+#: cups/snmp.c:1042
+msgid "No variable-bindings SEQUENCE"
+msgstr ""
+
+#: cups/snmp.c:997
+msgid "No version number"
+msgstr ""
+
+#: ppdc/sample.c:373
+msgid "Non-continuous (Mark sensing)"
+msgstr ""
+
+#: ppdc/sample.c:372
+msgid "Non-continuous (Web sensing)"
+msgstr ""
+
+#: ppdc/sample.c:244
+msgid "Normal"
+msgstr ""
+
+#: cups/http-support.c:1279
+msgid "Not Found"
+msgstr ""
+
+#: cups/http-support.c:1291
+msgid "Not Implemented"
+msgstr ""
+
+#: ppdc/sample.c:282
+msgid "Not Installed"
+msgstr ""
+
+#: cups/http-support.c:1266
+msgid "Not Modified"
+msgstr ""
+
+#: cups/http-support.c:1294
+msgid "Not Supported"
+msgstr ""
+
+#: scheduler/ipp.c:1598 scheduler/ipp.c:11777
+msgid "Not allowed to print."
+msgstr ""
+
+#: ppdc/sample.c:143
+msgid "Note"
+msgstr ""
+
+#: systemv/cupstestdsc.c:433
+msgid "Note: this program only validates the DSC comments, not the PostScript itself."
+msgstr ""
+
+#: cups/http-support.c:1248 cups/ppd.c:338
+msgid "OK"
+msgstr ""
+
+#: ppdc/sample.c:277
+msgid "Off (1-Sided)"
+msgstr ""
+
+#: ppdc/sample.c:367
+msgid "Oki"
+msgstr ""
+
+#: cgi-bin/help.c:90 cgi-bin/help.c:131 cgi-bin/help.c:141 cgi-bin/help.c:172
+msgid "Online Help"
+msgstr ""
+
+#: cups/adminutil.c:955
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr ""
+
+#: cups/ppd.c:346
+msgid "OpenGroup without a CloseGroup first"
+msgstr ""
+
+#: cups/ppd.c:348
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr ""
+
+#: cgi-bin/admin.c:3750
+msgid "Operation Policy"
+msgstr ""
+
+#: filter/pstops.c:2261
+#, c-format
+msgid "Option \"%s\" cannot be included via %%%%IncludeFeature."
+msgstr ""
+
+#: cgi-bin/admin.c:3400 cgi-bin/admin.c:3484
+msgid "Options Installed"
+msgstr ""
+
+#: scheduler/cupsfilter.c:1438 scheduler/cupsfilter.c:1465
+#: scheduler/main.c:2187 systemv/cupsaddsmb.c:284 systemv/cupsctl.c:209
+#: systemv/cupstestdsc.c:429 systemv/cupstestppd.c:3616 test/ipptool.c:3827
+#: ppdc/ppdc.cxx:437 ppdc/ppdhtml.cxx:174 ppdc/ppdi.cxx:130
+#: ppdc/ppdmerge.cxx:369 ppdc/ppdpo.cxx:254
+msgid "Options:"
+msgstr ""
+
+#: filter/bannertops.c:674
+msgid "Options: "
+msgstr ""
+
+#: cups/ppd-cache.c:152
+msgid "Out of date PPD cache file."
+msgstr ""
+
+#: cups/ppd-cache.c:1313
+msgid "Out of memory."
+msgstr ""
+
+#: cups/ppd.c:754 cups/ppd.c:1323
+msgid "Output Mode"
+msgstr ""
+
+#: systemv/lpstat.c:1188 systemv/lpstat.c:1192
+#, c-format
+msgid "Output for printer %s is sent to %s"
+msgstr ""
+
+#: systemv/lpstat.c:1182
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s"
+msgstr ""
+
+#: systemv/lpstat.c:1206 systemv/lpstat.c:1210
+#, c-format
+msgid "Output for printer %s/%s is sent to %s"
+msgstr ""
+
+#: systemv/lpstat.c:1200
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s"
+msgstr ""
+
+#: systemv/cupstestdsc.c:399
+msgid "PASS"
+msgstr ""
+
+#: ppdc/sample.c:266
+msgid "PCL Laser Printer"
+msgstr ""
+
+#: ppdc/sample.c:146
+msgid "PRC16K"
+msgstr ""
+
+#: ppdc/sample.c:147
+msgid "PRC16K Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:148
+msgid "PRC32K"
+msgstr ""
+
+#: ppdc/sample.c:151
+msgid "PRC32K Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:149
+msgid "PRC32K Oversize"
+msgstr ""
+
+#: ppdc/sample.c:150
+msgid "PRC32K Oversize Long Edge"
+msgstr ""
+
+#: cups/snmp.c:1014
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr ""
+
+#: cups/snmp.c:993
+msgid "Packet does not start with SEQUENCE"
+msgstr ""
+
+#: ppdc/sample.c:366
+msgid "ParamCustominCutInterval"
+msgstr ""
+
+#: ppdc/sample.c:364
+msgid "ParamCustominTearInterval"
+msgstr ""
+
+#: cups/auth.c:194 cups/auth.c:360
+#, c-format
+msgid "Password for %s on %s? "
+msgstr ""
+
+#: systemv/cupsaddsmb.c:252
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr ""
+
+#: cgi-bin/classes.c:167
+msgid "Pause Class"
+msgstr ""
+
+#: cgi-bin/printers.c:170
+msgid "Pause Printer"
+msgstr ""
+
+#: ppdc/sample.c:454
+msgid "Peel-Off"
+msgstr ""
+
+#: ppdc/sample.c:157
+msgid "Photo"
+msgstr ""
+
+#: ppdc/sample.c:158
+msgid "Photo Labels"
+msgstr ""
+
+#: ppdc/sample.c:292
+msgid "Plain Paper"
+msgstr ""
+
+#: cgi-bin/admin.c:3418 cgi-bin/admin.c:3699
+msgid "Policies"
+msgstr ""
+
+#: cgi-bin/admin.c:3425 cgi-bin/admin.c:3768 cgi-bin/admin.c:3781
+msgid "Port Monitor"
+msgstr ""
+
+#: ppdc/sample.c:284
+msgid "PostScript Printer"
+msgstr ""
+
+#: ppdc/sample.c:144
+msgid "Postcard"
+msgstr ""
+
+#: ppdc/sample.c:68
+msgid "Postcard Double "
+msgstr ""
+
+#: ppdc/sample.c:69
+msgid "Postcard Double Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:145
+msgid "Postcard Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:301
+msgid "Print Density"
+msgstr ""
+
+#: cups/notify.c:82
+msgid "Print Job:"
+msgstr ""
+
+#: ppdc/sample.c:346
+msgid "Print Mode"
+msgstr ""
+
+#: ppdc/sample.c:389
+msgid "Print Rate"
+msgstr ""
+
+#: cgi-bin/printers.c:179
+msgid "Print Self-Test Page"
+msgstr ""
+
+#: ppdc/sample.c:333
+msgid "Print Speed"
+msgstr ""
+
+#: cgi-bin/ipp-var.c:792
+msgid "Print Test Page"
+msgstr ""
+
+#: ppdc/sample.c:362
+msgid "Print and Cut"
+msgstr ""
+
+#: ppdc/sample.c:350
+msgid "Print and Tear"
+msgstr ""
+
+#: backend/ipp.c:1459
+#, c-format
+msgid "Print file accepted - job ID %d."
+msgstr ""
+
+#: backend/ipp.c:1450
+msgid "Print file accepted - job ID unknown."
+msgstr ""
+
+#: backend/parallel.c:286 backend/socket.c:424 backend/usb-unix.c:195
+msgid "Print file sent."
+msgstr ""
+
+#: backend/ipp.c:1414
+msgid "Print file was not accepted."
+msgstr ""
+
+#: filter/bannertops.c:648
+msgid "Printed For: "
+msgstr ""
+
+#: filter/bannertops.c:656
+msgid "Printed From: "
+msgstr ""
+
+#: filter/bannertops.c:876
+msgid "Printed On: "
+msgstr ""
+
+#: cgi-bin/ipp-var.c:1047
+msgid "Printer Added"
+msgstr ""
+
+#: ppdc/sample.c:269
+msgid "Printer Default"
+msgstr ""
+
+#: cgi-bin/ipp-var.c:1051
+msgid "Printer Deleted"
+msgstr ""
+
+#: cgi-bin/ipp-var.c:1049
+msgid "Printer Modified"
+msgstr ""
+
+#: filter/bannertops.c:614
+msgid "Printer Name: "
+msgstr ""
+
+#: cgi-bin/ipp-var.c:1045
+msgid "Printer Paused"
+msgstr ""
+
+#: ppdc/sample.c:300
+msgid "Printer Settings"
+msgstr ""
+
+#: backend/usb-unix.c:132
+msgid "Printer busy, will retry in 10 seconds."
+msgstr ""
+
+#: backend/parallel.c:234 backend/serial.c:256
+msgid "Printer busy; will retry in 30 seconds."
+msgstr ""
+
+#: backend/lpd.c:617 backend/lpd.c:1005 backend/lpd.c:1092 backend/lpd.c:1147
+#, c-format
+msgid "Printer did not respond after %d seconds."
+msgstr ""
+
+#: backend/ipp.c:867 backend/ipp.c:874
+#, c-format
+msgid "Printer does not support IPP/%d.%d, trying IPP/%s."
+msgstr ""
+
+#: backend/usb-unix.c:429 backend/usb-unix.c:513
+msgid "Printer is busy, will retry in 5 seconds."
+msgstr ""
+
+#: backend/runloop.c:253 backend/runloop.c:371
+msgid "Printer is not currently connected."
+msgstr ""
+
+#: backend/runloop.c:392
+msgid "Printer is now connected."
+msgstr ""
+
+#: backend/usb-darwin.c:1304
+msgid "Printer is now online."
+msgstr ""
+
+#: backend/usb-darwin.c:1322
+msgid "Printer is offline."
+msgstr ""
+
+#: backend/usb-unix.c:139
+msgid "Printer not connected, will retry in 30 seconds."
+msgstr ""
+
+#: backend/parallel.c:240
+msgid "Printer not connected; will retry in 30 seconds."
+msgstr ""
+
+#: cups/notify.c:126
+msgid "Printer:"
+msgstr ""
+
+#: cgi-bin/printers.c:204 cgi-bin/printers.c:332
+msgid "Printers"
+msgstr ""
+
+#: driver/rastertoescpx.c:1882 driver/rastertopclx.c:1904
+#: filter/rastertoepson.c:1093 filter/rastertohp.c:817
+#: filter/rastertolabel.c:1249
+#, c-format
+msgid "Printing page %d, %d%% complete."
+msgstr ""
+
+#: filter/imagetops.c:817
+#, c-format
+msgid "Printing page %d."
+msgstr ""
+
+#: cgi-bin/classes.c:173 cgi-bin/printers.c:176
+msgid "Purge Jobs"
+msgstr ""
+
+#: ppdc/sample.c:152
+msgid "Quarto"
+msgstr ""
+
+#: scheduler/ipp.c:1593 scheduler/ipp.c:11772
+msgid "Quota limit reached."
+msgstr ""
+
+#: berkeley/lpq.c:515
+msgid "Rank Owner Job File(s) Total Size"
+msgstr ""
+
+#. TRANSLATORS: Pri is job priority.
+#: berkeley/lpq.c:511
+msgid "Rank Owner Pri Job Files Total Size"
+msgstr ""
+
+#: backend/ipp.c:1772 backend/socket.c:475 driver/rastertoescpx.c:1923
+#: driver/rastertopclx.c:1948 filter/rastertoepson.c:1152
+#: filter/rastertohp.c:881 filter/rastertolabel.c:1307
+msgid "Ready to print."
+msgstr ""
+
+#: cgi-bin/classes.c:171 cgi-bin/printers.c:174
+msgid "Reject Jobs"
+msgstr ""
+
+#: backend/lpd.c:1015 backend/lpd.c:1157
+#, c-format
+msgid "Remote host did not accept control file (%d)."
+msgstr ""
+
+#: backend/lpd.c:1105
+#, c-format
+msgid "Remote host did not accept data file (%d)."
+msgstr ""
+
+#: ppdc/sample.c:434
+msgid "Reprint After Error"
+msgstr ""
+
+#: cups/http-support.c:1282
+msgid "Request Entity Too Large"
+msgstr ""
+
+#: cups/ppd.c:756 cups/ppd.c:1325 ppdc/sample.c:237
+msgid "Resolution"
+msgstr ""
+
+#: cgi-bin/classes.c:165
+msgid "Resume Class"
+msgstr ""
+
+#: cgi-bin/printers.c:167
+msgid "Resume Printer"
+msgstr ""
+
+#: ppdc/sample.c:162
+msgid "Return Address"
+msgstr ""
+
+#: ppdc/sample.c:171
+msgid "Return Address - 3/4 x 2\""
+msgstr ""
+
+#: ppdc/sample.c:455
+msgid "Rewind"
+msgstr ""
+
+#: cups/adminutil.c:2169
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'"
+msgstr ""
+
+#: cups/snmp.c:995
+msgid "SEQUENCE uses indefinite length"
+msgstr ""
+
+#: cups/http-support.c:1306
+msgid "SSL/TLS Negotiation Error"
+msgstr ""
+
+#: cups/http-support.c:1263
+msgid "See Other"
+msgstr ""
+
+#: backend/usb-darwin.c:541
+msgid "Sending data to printer."
+msgstr ""
+
+#: backend/serial.c:783 backend/serial.c:942 backend/serial.c:1064
+#: backend/serial.c:1158
+#, c-format
+msgid "Serial Port #%d"
+msgstr ""
+
+#: cgi-bin/ipp-var.c:1061
+msgid "Server Restarted"
+msgstr ""
+
+#: cgi-bin/ipp-var.c:1067
+msgid "Server Security Auditing"
+msgstr ""
+
+#: cgi-bin/ipp-var.c:1063
+msgid "Server Started"
+msgstr ""
+
+#: cgi-bin/ipp-var.c:1065
+msgid "Server Stopped"
+msgstr ""
+
+#: cups/http-support.c:1300
+msgid "Service Unavailable"
+msgstr ""
+
+#: cgi-bin/admin.c:2905 cgi-bin/admin.c:2951 cgi-bin/admin.c:3108
+#: cgi-bin/admin.c:3127
+msgid "Set Allowed Users"
+msgstr ""
+
+#: cgi-bin/admin.c:3154
+msgid "Set As Server Default"
+msgstr ""
+
+#: cgi-bin/admin.c:3254
+msgid "Set Class Options"
+msgstr ""
+
+#: cgi-bin/admin.c:3254 cgi-bin/admin.c:3428 cgi-bin/admin.c:3810
+msgid "Set Printer Options"
+msgstr ""
+
+#: cgi-bin/admin.c:3980 cgi-bin/admin.c:4024 cgi-bin/admin.c:4042
+msgid "Set Publishing"
+msgstr ""
+
+#: ppdc/sample.c:163
+msgid "Shipping Address"
+msgstr ""
+
+#: ppdc/sample.c:172
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr ""
+
+#: ppdc/sample.c:279
+msgid "Short-Edge (Landscape)"
+msgstr ""
+
+#: ppdc/sample.c:294
+msgid "Special Paper"
+msgstr ""
+
+#: backend/lpd.c:1056
+#, c-format
+msgid "Spooling job, %.0f%% complete."
+msgstr ""
+
+#: ppdc/sample.c:347
+msgid "Standard"
+msgstr ""
+
+#. TRANSLATORS: Banner/cover sheet before the print job.
+#: cgi-bin/admin.c:3671
+msgid "Starting Banner"
+msgstr ""
+
+#: driver/rastertoescpx.c:1866 driver/rastertopclx.c:1887
+#: filter/rastertoepson.c:1069 filter/rastertohp.c:793
+#: filter/rastertolabel.c:1225
+#, c-format
+msgid "Starting page %d."
+msgstr ""
+
+#: ppdc/sample.c:153
+msgid "Statement"
+msgstr ""
+
+#: ppdc/sample.c:257
+msgid "Stylus Color Series"
+msgstr ""
+
+#: ppdc/sample.c:263
+msgid "Stylus Photo Series"
+msgstr ""
+
+#: scheduler/ipp.c:4633 scheduler/ipp.c:7853 scheduler/ipp.c:8562
+#: scheduler/ipp.c:10044
+#, c-format
+msgid "Subscription #%d does not exist."
+msgstr ""
+
+#: ppdc/sample.c:154
+msgid "Super A"
+msgstr ""
+
+#: ppdc/sample.c:155
+msgid "Super B"
+msgstr ""
+
+#: ppdc/sample.c:159
+msgid "Super B/A3"
+msgstr ""
+
+#: cups/http-support.c:1245
+msgid "Switching Protocols"
+msgstr ""
+
+#: ppdc/sample.c:156
+msgid "Tabloid"
+msgstr ""
+
+#: ppdc/sample.c:42
+msgid "Tabloid Oversize"
+msgstr ""
+
+#: ppdc/sample.c:43
+msgid "Tabloid Oversize Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:348
+msgid "Tear"
+msgstr ""
+
+#: ppdc/sample.c:453
+msgid "Tear-Off"
+msgstr ""
+
+#: ppdc/sample.c:394
+msgid "Tear-Off Adjust Position"
+msgstr ""
+
+#: scheduler/ipp.c:7557 scheduler/ipp.c:7635 scheduler/ipp.c:7651
+#: scheduler/ipp.c:7669
+#, c-format
+msgid "The %s attribute cannot be provided with job-ids."
+msgstr ""
+
+#: scheduler/ipp.c:8084
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr ""
+
+#: scheduler/ipp.c:8071
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr ""
+
+#: driver/rastertoescpx.c:1794 driver/rastertopclx.c:1819
+#: filter/rastertoepson.c:1038 filter/rastertohp.c:764
+#: filter/rastertolabel.c:1189
+msgid "The PPD file could not be opened."
+msgstr ""
+
+#: cgi-bin/admin.c:750
+msgid "The class name may only contain up to 127 printable characters and may not contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+
+#: cups/localize.c:353
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+#: cups/localize.c:351
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+#: cups/localize.c:343
+msgid "The fuser's temperature is high."
+msgstr ""
+
+#: cups/localize.c:345
+msgid "The fuser's temperature is low."
+msgstr ""
+
+#: scheduler/ipp.c:2242
+msgid "The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+
+#: scheduler/ipp.c:2225 scheduler/ipp.c:6815
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)."
+msgstr ""
+
+#: cups/localize.c:349
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+#: cups/localize.c:347
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+#: cups/localize.c:331
+msgid "The output bin is almost full."
+msgstr ""
+
+#: cups/localize.c:333
+msgid "The output bin is full."
+msgstr ""
+
+#: cups/localize.c:329
+msgid "The output bin is missing."
+msgstr ""
+
+#: filter/imagetoraster.c:466
+msgid "The page setup information was not valid."
+msgstr ""
+
+#: cups/localize.c:325
+msgid "The paper tray is almost empty."
+msgstr ""
+
+#: cups/localize.c:327
+msgid "The paper tray is empty."
+msgstr ""
+
+#: cups/localize.c:323
+msgid "The paper tray is missing."
+msgstr ""
+
+#: cups/localize.c:306
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+#: filter/imagetops.c:322 filter/imagetoraster.c:682
+msgid "The print file could not be opened."
+msgstr ""
+
+#: backend/ipp.c:884
+msgid "The printer URI is incorrect or no longer exists."
+msgstr ""
+
+#: cups/localize.c:335
+msgid "The printer is almost out of ink."
+msgstr ""
+
+#: backend/ipp.c:735 backend/ipp.c:849 backend/ipp.c:950 backend/ipp.c:1245
+#: backend/ipp.c:1394 backend/lpd.c:842 backend/socket.c:374
+msgid "The printer is busy."
+msgstr ""
+
+#: cups/localize.c:313
+msgid "The printer is low on toner."
+msgstr ""
+
+#: cups/localize.c:311
+msgid "The printer is not connected."
+msgstr ""
+
+#: backend/ipp.c:713 backend/ipp.c:746 backend/ipp.c:845 backend/lpd.c:821
+#: backend/lpd.c:862 backend/socket.c:353 backend/socket.c:386
+msgid "The printer is not responding."
+msgstr ""
+
+#: cups/localize.c:337
+msgid "The printer is out of ink."
+msgstr ""
+
+#: cups/localize.c:315
+msgid "The printer is out of toner."
+msgstr ""
+
+#: backend/ipp.c:728 backend/lpd.c:835 backend/socket.c:367
+msgid "The printer is unreachable at this time."
+msgstr ""
+
+#: backend/ipp.c:722 backend/lpd.c:829 backend/socket.c:361
+msgid "The printer may not exist or is unavailable at this time."
+msgstr ""
+
+#: cgi-bin/admin.c:932
+msgid "The printer name may only contain up to 127 printable characters and may not contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+
+#: scheduler/ipp.c:904 scheduler/ipp.c:1216 scheduler/ipp.c:4282
+#: scheduler/ipp.c:4453 scheduler/ipp.c:6346 scheduler/ipp.c:6649
+#: scheduler/ipp.c:6963 scheduler/ipp.c:7523 scheduler/ipp.c:8289
+#: scheduler/ipp.c:8345 scheduler/ipp.c:8668 scheduler/ipp.c:8918
+#: scheduler/ipp.c:9007 scheduler/ipp.c:9040 scheduler/ipp.c:9363
+#: scheduler/ipp.c:9756 scheduler/ipp.c:9837 scheduler/ipp.c:10950
+#: scheduler/ipp.c:11405 scheduler/ipp.c:11735 scheduler/ipp.c:11817
+#: scheduler/ipp.c:12109
+msgid "The printer or class does not exist."
+msgstr ""
+
+#: scheduler/ipp.c:1384
+msgid "The printer or class is not shared."
+msgstr ""
+
+#: cups/localize.c:317
+msgid "The printer's cover is open."
+msgstr ""
+
+#: cups/localize.c:321
+msgid "The printer's door is open."
+msgstr ""
+
+#: cups/localize.c:319
+msgid "The printer's interlock is open."
+msgstr ""
+
+#: cups/localize.c:339
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+#: cups/localize.c:341
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#: scheduler/ipp.c:1011 scheduler/ipp.c:2408
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr ""
+
+#: scheduler/ipp.c:4259
+msgid "The printer-uri attribute is required."
+msgstr ""
+
+#: scheduler/ipp.c:995
+msgid "The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr ""
+
+#: scheduler/ipp.c:2392
+msgid "The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+
+#: cgi-bin/admin.c:474
+msgid "The subscription name may not contain spaces, slashes (/), question marks (?), or the pound sign (#)."
+msgstr ""
+
+#: scheduler/client.c:2462
+msgid "The web interface is currently disabled. Run \"cupsctl WebInterface=yes\" to enable it."
+msgstr ""
+
+#: scheduler/ipp.c:7618
+#, c-format
+msgid "The which-jobs value \"%s\" is not supported."
+msgstr ""
+
+#: scheduler/ipp.c:6893
+msgid "There are too many subscriptions."
+msgstr ""
+
+#: cups/localize.c:308
+msgid "There is a paper jam."
+msgstr ""
+
+#: backend/usb-darwin.c:377 backend/usb-darwin.c:436 backend/usb-darwin.c:503
+#: backend/usb-darwin.c:524
+msgid "There was an unrecoverable USB error."
+msgstr ""
+
+#: ppdc/sample.c:441
+msgid "Thermal Transfer Media"
+msgstr ""
+
+#: filter/bannertops.c:640
+msgid "Title: "
+msgstr ""
+
+#: scheduler/ipp.c:1587
+msgid "Too many active jobs."
+msgstr ""
+
+#: scheduler/ipp.c:1481
+#, c-format
+msgid "Too many job-sheets values (%d > 2)."
+msgstr ""
+
+#: scheduler/ipp.c:2729
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)."
+msgstr ""
+
+#: ppdc/sample.c:295
+msgid "Transparency"
+msgstr ""
+
+#: ppdc/sample.c:290
+msgid "Tray"
+msgstr ""
+
+#: ppdc/sample.c:270
+msgid "Tray 1"
+msgstr ""
+
+#: ppdc/sample.c:271
+msgid "Tray 2"
+msgstr ""
+
+#: ppdc/sample.c:272
+msgid "Tray 3"
+msgstr ""
+
+#: ppdc/sample.c:273
+msgid "Tray 4"
+msgstr ""
+
+#: cups/http-support.c:1285
+msgid "URI Too Long"
+msgstr ""
+
+#: ppdc/sample.c:135
+msgid "US Ledger"
+msgstr ""
+
+#: ppdc/sample.c:136
+msgid "US Legal"
+msgstr ""
+
+#: ppdc/sample.c:137
+msgid "US Legal Oversize"
+msgstr ""
+
+#: ppdc/sample.c:138
+msgid "US Letter"
+msgstr ""
+
+#: ppdc/sample.c:139
+msgid "US Letter Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:140
+msgid "US Letter Oversize"
+msgstr ""
+
+#: ppdc/sample.c:141
+msgid "US Letter Oversize Long Edge"
+msgstr ""
+
+#: ppdc/sample.c:142
+msgid "US Letter Small"
+msgstr ""
+
+#: backend/serial.c:796
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr ""
+
+#: cgi-bin/admin.c:2033 cgi-bin/admin.c:2046 cgi-bin/admin.c:2070
+msgid "Unable to access cupsd.conf file:"
+msgstr ""
+
+#: cgi-bin/admin.c:526
+msgid "Unable to add RSS subscription:"
+msgstr ""
+
+#: cgi-bin/admin.c:815
+msgid "Unable to add class:"
+msgstr ""
+
+#: backend/ipp.c:1534
+msgid "Unable to add document to print job."
+msgstr ""
+
+#: scheduler/ipp.c:1628
+#, c-format
+msgid "Unable to add job for destination \"%s\"."
+msgstr ""
+
+#: cgi-bin/admin.c:1060 cgi-bin/admin.c:1420
+msgid "Unable to add printer:"
+msgstr ""
+
+#: scheduler/ipp.c:1326
+msgid "Unable to allocate memory for file types."
+msgstr ""
+
+#: filter/pstops.c:456
+msgid "Unable to allocate memory for page info"
+msgstr ""
+
+#: filter/pstops.c:450
+msgid "Unable to allocate memory for pages array"
+msgstr ""
+
+#: cgi-bin/admin.c:1526
+msgid "Unable to cancel RSS subscription:"
+msgstr ""
+
+#: backend/ipp.c:1814
+msgid "Unable to cancel print job."
+msgstr ""
+
+#: cgi-bin/admin.c:4025
+msgid "Unable to change printer-is-shared attribute:"
+msgstr ""
+
+#: cgi-bin/admin.c:3109
+msgid "Unable to change printer:"
+msgstr ""
+
+#: cgi-bin/admin.c:1710 cgi-bin/admin.c:1874
+msgid "Unable to change server settings:"
+msgstr ""
+
+#: cups/adminutil.c:911 cups/request.c:972
+msgid "Unable to connect to host."
+msgstr ""
+
+#: cups/http-addrlist.c:172
+msgid "Unable to connect to server"
+msgstr ""
+
+#: backend/ipp.c:691 backend/ipp.c:1090 backend/lpd.c:801
+#: backend/parallel.c:219 backend/serial.c:241 backend/socket.c:333
+#: backend/usb-unix.c:117
+msgid "Unable to contact printer, queuing on next printer in class."
+msgstr ""
+
+#: cups/adminutil.c:726
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)."
+msgstr ""
+
+#: cups/adminutil.c:691
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)."
+msgstr ""
+
+#: cups/adminutil.c:522
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)."
+msgstr ""
+
+#: scheduler/ipp.c:2849
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#: scheduler/ipp.c:2904
+msgid "Unable to copy PPD file."
+msgstr ""
+
+#: cups/adminutil.c:487
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)."
+msgstr ""
+
+#: cups/adminutil.c:610
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)."
+msgstr ""
+
+#: scheduler/ipp.c:2826
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+#: filter/imagetops.c:141 filter/imagetoraster.c:301
+msgid "Unable to copy print file"
+msgstr ""
+
+#: backend/ipp.c:1904
+msgid "Unable to create compressed print file"
+msgstr ""
+
+#: filter/imagetoraster.c:242
+msgid "Unable to create pipes for filters"
+msgstr ""
+
+#: cups/util.c:601 cups/util.c:1644
+msgid "Unable to create printer-uri"
+msgstr ""
+
+#: scheduler/cupsfilter.c:1242
+msgid "Unable to create temporary file"
+msgstr ""
+
+#: cgi-bin/admin.c:1924 cgi-bin/admin.c:1936
+msgid "Unable to create temporary file:"
+msgstr ""
+
+#: cgi-bin/admin.c:2227
+msgid "Unable to delete class:"
+msgstr ""
+
+#: cgi-bin/admin.c:2312
+msgid "Unable to delete printer:"
+msgstr ""
+
+#: cgi-bin/classes.c:260 cgi-bin/printers.c:269
+msgid "Unable to do maintenance command:"
+msgstr ""
+
+#: cgi-bin/admin.c:2048
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+#: cups/http.c:4033
+msgid "Unable to establish a secure connection to host (certificate chain invalid)."
+msgstr ""
+
+#: cups/http.c:4023
+msgid "Unable to establish a secure connection to host (certificate not yet valid)."
+msgstr ""
+
+#: cups/http.c:4018
+msgid "Unable to establish a secure connection to host (expired certificate)."
+msgstr ""
+
+#: cups/http.c:4028
+msgid "Unable to establish a secure connection to host (host name mismatch)."
+msgstr ""
+
+#: cups/http.c:4038
+msgid "Unable to establish a secure connection to host (peer dropped connection before responding)."
+msgstr ""
+
+#: cups/http.c:4013
+msgid "Unable to establish a secure connection to host (self-signed certificate)."
+msgstr ""
+
+#: cups/http.c:4008
+msgid "Unable to establish a secure connection to host (untrusted certificate)."
+msgstr ""
+
+#: cups/http.c:4065
+msgid "Unable to establish a secure connection to host."
+msgstr ""
+
+#: cgi-bin/ipp-var.c:365
+msgid "Unable to find destination for job"
+msgstr ""
+
+#: cups/http-support.c:1631
+msgid "Unable to find printer."
+msgstr ""
+
+#: filter/imagetoraster.c:266
+msgid "Unable to fork filter"
+msgstr ""
+
+#: backend/ipp.c:1926
+msgid "Unable to generate compressed print file"
+msgstr ""
+
+#: backend/ipp.c:2709
+msgid "Unable to get backend exit status."
+msgstr ""
+
+#: cgi-bin/classes.c:450
+msgid "Unable to get class list:"
+msgstr ""
+
+#: cgi-bin/classes.c:549
+msgid "Unable to get class status:"
+msgstr ""
+
+#: cgi-bin/admin.c:1321
+msgid "Unable to get list of printer drivers:"
+msgstr ""
+
+#: backend/ipp.c:1623
+msgid "Unable to get print job status."
+msgstr ""
+
+#: cgi-bin/admin.c:2959
+msgid "Unable to get printer attributes:"
+msgstr ""
+
+#: cgi-bin/printers.c:467
+msgid "Unable to get printer list:"
+msgstr ""
+
+#: backend/ipp.c:903
+msgid "Unable to get printer status."
+msgstr ""
+
+#: cgi-bin/printers.c:569
+msgid "Unable to get printer status:"
+msgstr ""
+
+#: cups/adminutil.c:565 cups/adminutil.c:769
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)."
+msgstr ""
+
+#: cups/adminutil.c:639
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)."
+msgstr ""
+
+#: backend/ipp.c:624 backend/lpd.c:419 backend/socket.c:275
+#, c-format
+msgid "Unable to locate printer \"%s\"."
+msgstr ""
+
+#: backend/dnssd.c:497 backend/ipp.c:310 backend/lpd.c:202
+#: backend/socket.c:171
+msgid "Unable to locate printer."
+msgstr ""
+
+#: cgi-bin/admin.c:814
+msgid "Unable to modify class:"
+msgstr ""
+
+#: cgi-bin/admin.c:1059 cgi-bin/admin.c:1419
+msgid "Unable to modify printer:"
+msgstr ""
+
+#: cgi-bin/ipp-var.c:432 cgi-bin/ipp-var.c:521
+msgid "Unable to move job"
+msgstr ""
+
+#: cgi-bin/ipp-var.c:434 cgi-bin/ipp-var.c:523
+msgid "Unable to move jobs"
+msgstr ""
+
+#: cups/ppd.c:339
+msgid "Unable to open PPD file"
+msgstr ""
+
+#: cgi-bin/admin.c:3305
+msgid "Unable to open PPD file:"
+msgstr ""
+
+#: filter/texttops.c:282
+msgid "Unable to open charset file"
+msgstr ""
+
+#: backend/ipp.c:1910
+msgid "Unable to open compressed print file"
+msgstr ""
+
+#: cgi-bin/admin.c:2683
+msgid "Unable to open cupsd.conf file:"
+msgstr ""
+
+#: backend/parallel.c:246 backend/serial.c:261 backend/usb-unix.c:145
+msgid "Unable to open device file"
+msgstr ""
+
+#: scheduler/ipp.c:7304
+#, c-format
+msgid "Unable to open document #%d in job #%d."
+msgstr ""
+
+#: backend/ipp.c:351 backend/ipp.c:1916 backend/lpd.c:486
+#: backend/parallel.c:150 backend/serial.c:190 backend/socket.c:158
+#: backend/usb.c:237 filter/bannertops.c:183 filter/gziptoany.c:71
+#: filter/pstext.c:89 filter/pstext.c:249 filter/pstext.c:266
+#: filter/pstops.c:305
+msgid "Unable to open print file"
+msgstr ""
+
+#: filter/texttops.c:263
+msgid "Unable to open psglyphs"
+msgstr ""
+
+#: driver/rastertoescpx.c:1814 driver/rastertopclx.c:1839
+#: filter/rastertoepson.c:998 filter/rastertohp.c:724
+#: filter/rastertolabel.c:1147
+msgid "Unable to open raster file"
+msgstr ""
+
+#: filter/texttops.c:216
+#, c-format
+msgid "Unable to print %d text columns."
+msgstr ""
+
+#: filter/texttops.c:180 filter/texttops.c:188 filter/texttops.c:196
+#, c-format
+msgid "Unable to print %dx%d text page."
+msgstr ""
+
+#: cgi-bin/ipp-var.c:795
+msgid "Unable to print test page:"
+msgstr ""
+
+#: backend/runloop.c:95 backend/runloop.c:322
+msgid "Unable to read print data"
+msgstr ""
+
+#: backend/usb-darwin.c:611 backend/usb-darwin.c:655
+msgid "Unable to read print data."
+msgstr ""
+
+#: cups/adminutil.c:2205
+#, c-format
+msgid "Unable to run \"%s\": %s"
+msgstr ""
+
+#: filter/pstops.c:568
+msgid "Unable to see in file"
+msgstr ""
+
+#: cgi-bin/ipp-var.c:598 cgi-bin/ipp-var.c:618
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#: backend/usb-darwin.c:733 backend/usb-libusb.c:179 backend/usb-libusb.c:781
+msgid "Unable to send data to printer."
+msgstr ""
+
+#: filter/imagetoraster.c:1245 filter/imagetoraster.c:1342
+#: filter/imagetoraster.c:1383
+msgid "Unable to send raster data to the driver."
+msgstr ""
+
+#: cups/adminutil.c:821
+#, c-format
+msgid "Unable to set Windows printer driver (%d)."
+msgstr ""
+
+#: cgi-bin/admin.c:3926
+msgid "Unable to set options:"
+msgstr ""
+
+#: cgi-bin/admin.c:3196
+msgid "Unable to set server default:"
+msgstr ""
+
+#: backend/ipp.c:2570 backend/ipp.c:2645 backend/ipp.c:2653
+msgid "Unable to start backend process."
+msgstr ""
+
+#: cgi-bin/admin.c:1986
+msgid "Unable to upload cupsd.conf file:"
+msgstr ""
+
+#: backend/usb-darwin.c:2000 backend/usb-darwin.c:2024
+msgid "Unable to use legacy USB class driver."
+msgstr ""
+
+#: backend/runloop.c:124 backend/runloop.c:377
+msgid "Unable to write print data"
+msgstr ""
+
+#: filter/gziptoany.c:90
+#, c-format
+msgid "Unable to write uncompressed print data: %s"
+msgstr ""
+
+#: cups/http-support.c:1273
+msgid "Unauthorized"
+msgstr ""
+
+#: cgi-bin/admin.c:3622
+msgid "Units"
+msgstr ""
+
+#: cups/http-support.c:1313 cups/ppd.c:366
+msgid "Unknown"
+msgstr ""
+
+#: filter/pstops.c:2269
+#, c-format
+msgid "Unknown choice \"%s\" for option \"%s\"."
+msgstr ""
+
+#: backend/ipp.c:493
+#, c-format
+msgid "Unknown encryption option value: \"%s\"."
+msgstr ""
+
+#: backend/lpd.c:348
+#, c-format
+msgid "Unknown file order: \"%s\"."
+msgstr ""
+
+#: backend/lpd.c:319
+#, c-format
+msgid "Unknown format character: \"%c\"."
+msgstr ""
+
+#: backend/ipp.c:540
+#, c-format
+msgid "Unknown option \"%s\" with value \"%s\"."
+msgstr ""
+
+#: filter/pstops.c:2252
+#, c-format
+msgid "Unknown option \"%s\"."
+msgstr ""
+
+#: backend/lpd.c:334
+#, c-format
+msgid "Unknown print mode: \"%s\"."
+msgstr ""
+
+#: scheduler/ipp.c:11607
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr ""
+
+#: scheduler/ipp.c:11590
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr ""
+
+#: backend/ipp.c:512
+#, c-format
+msgid "Unknown version option value: \"%s\"."
+msgstr ""
+
+#: backend/serial.c:379
+#, c-format
+msgid "Unsupported baud rate: %s"
+msgstr ""
+
+#: filter/pstops.c:2460
+#, c-format
+msgid "Unsupported brightness value %s, using brightness=100."
+msgstr ""
+
+#: scheduler/ipp.c:429
+#, c-format
+msgid "Unsupported character set \"%s\"."
+msgstr ""
+
+#: scheduler/ipp.c:9329 scheduler/ipp.c:10526 scheduler/ipp.c:12061
+#, c-format
+msgid "Unsupported compression \"%s\"."
+msgstr ""
+
+#: scheduler/ipp.c:9463 scheduler/ipp.c:10671 scheduler/ipp.c:12090
+#, c-format
+msgid "Unsupported document-format \"%s\"."
+msgstr ""
+
+#: scheduler/ipp.c:10654
+#, c-format
+msgid "Unsupported document-format \"%s/%s\"."
+msgstr ""
+
+#: scheduler/ipp.c:1447
+#, c-format
+msgid "Unsupported format \"%s\"."
+msgstr ""
+
+#: filter/pstops.c:2542
+#, c-format
+msgid "Unsupported gamma value %s, using gamma=1000."
+msgstr ""
+
+#: scheduler/ipp.c:1545
+msgid "Unsupported margins."
+msgstr ""
+
+#: cups/pwg-media.c:464
+msgid "Unsupported media value."
+msgstr ""
+
+#: filter/pstops.c:2586
+#, c-format
+msgid "Unsupported number-up value %d, using number-up=1."
+msgstr ""
+
+#: filter/pstops.c:2620
+#, c-format
+msgid "Unsupported number-up-layout value %s, using number-up-layout=lrtb."
+msgstr ""
+
+#: filter/pstops.c:2671
+#, c-format
+msgid "Unsupported page-border value %s, using page-border=none."
+msgstr ""
+
+#: filter/rastertopwg.c:130 filter/rastertopwg.c:138 filter/rastertopwg.c:147
+msgid "Unsupported raster data."
+msgstr ""
+
+#: cups/snmp.c:1112
+msgid "Unsupported value type"
+msgstr ""
+
+#: cups/http-support.c:1288
+msgid "Upgrade Required"
+msgstr ""
+
+#: systemv/lpadmin.c:668
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]"
+msgstr ""
+
+#: filter/pdftops.c:109
+#, c-format
+msgid "Usage: %s job user title copies options [filename]"
+msgstr ""
+
+#: backend/dnssd.c:171 backend/ipp.c:299 backend/lpd.c:191
+#: backend/parallel.c:127 backend/serial.c:167 backend/socket.c:135
+#: backend/usb.c:183 driver/commandtoescpx.c:57 driver/commandtopclx.c:57
+#: filter/textcommon.c:518 monitor/bcp.c:62 monitor/tbcp.c:61
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]"
+msgstr ""
+
+#: filter/bannertops.c:118 filter/commandtops.c:73 filter/gziptoany.c:50
+#: filter/imagetops.c:123 filter/imagetoraster.c:215 filter/pstops.c:269
+#, c-format
+msgid "Usage: %s job-id user title copies options file"
+msgstr ""
+
+#: scheduler/cupsfilter.c:1464
+msgid "Usage: convert [ options ]"
+msgstr ""
+
+#: systemv/cupsaddsmb.c:281
+msgid "Usage: cupsaddsmb [options] printer1 ... printerN"
+msgstr ""
+
+#: systemv/cupsctl.c:206
+msgid "Usage: cupsctl [options] [param=value ... paramN=valueN]"
+msgstr ""
+
+#: scheduler/main.c:2186
+msgid "Usage: cupsd [options]"
+msgstr ""
+
+#: scheduler/cupsfilter.c:1437
+msgid "Usage: cupsfilter [ options ] filename"
+msgstr ""
+
+#: systemv/cupstestdsc.c:425
+msgid "Usage: cupstestdsc [options] filename.ps [... filename.ps]"
+msgstr ""
+
+#: systemv/cupstestppd.c:3612
+msgid "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]"
+msgstr ""
+
+#: test/ipptool.c:3825
+msgid "Usage: ipptool [options] URI filename [ ... filenameN ]"
+msgstr ""
+
+#: systemv/lpmove.c:125
+msgid "Usage: lpmove job/src dest"
+msgstr ""
+
+#: systemv/lpoptions.c:553
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer"
+msgstr ""
+
+#: systemv/lppasswd.c:476
+msgid "Usage: lppasswd [-g groupname]"
+msgstr ""
+
+#: systemv/lppasswd.c:479
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]"
+msgstr ""
+
+#: berkeley/lpq.c:670
+msgid "Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]"
+msgstr ""
+
+#: ppdc/ppdc.cxx:435
+msgid "Usage: ppdc [options] filename.drv [ ... filenameN.drv ]"
+msgstr ""
+
+#: ppdc/ppdhtml.cxx:172
+msgid "Usage: ppdhtml [options] filename.drv >filename.html"
+msgstr ""
+
+#: ppdc/ppdi.cxx:128
+msgid "Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]"
+msgstr ""
+
+#: ppdc/ppdmerge.cxx:367
+msgid "Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]"
+msgstr ""
+
+#: ppdc/ppdpo.cxx:252
+msgid "Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]"
+msgstr ""
+
+#: backend/snmp.c:218
+msgid "Usage: snmp [host-or-ip-address]"
+msgstr ""
+
+#: cups/snmp.c:1064
+msgid "Value uses indefinite length"
+msgstr ""
+
+#: cups/snmp.c:1049
+msgid "VarBind uses indefinite length"
+msgstr ""
+
+#: cups/snmp.c:999
+msgid "Version uses indefinite length"
+msgstr ""
+
+#: backend/ipp.c:1558
+msgid "Waiting for job to complete."
+msgstr ""
+
+#: backend/usb-darwin.c:455 backend/usb-libusb.c:118
+msgid "Waiting for printer to become available."
+msgstr ""
+
+#: backend/socket.c:444
+msgid "Waiting for printer to finish."
+msgstr ""
+
+#: cups/adminutil.c:793
+msgid "Warning, no Windows 2000 printer drivers are installed."
+msgstr ""
+
+#: cups/http-support.c:1309
+msgid "Web Interface is Disabled"
+msgstr ""
+
+#: cups/ppd.c:1907
+msgid "Yes"
+msgstr ""
+
+#: scheduler/client.c:2449
+#, c-format
+msgid "You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%s:%d%s</A>."
+msgstr ""
+
+#: systemv/lppasswd.c:254
+msgid "Your password must be at least 6 characters long, cannot contain your username, and must contain at least one letter and number."
+msgstr ""
+
+#: ppdc/sample.c:445
+msgid "ZPL Label Printer"
+msgstr ""
+
+#: ppdc/sample.c:368
+msgid "Zebra"
+msgstr ""
+
+#: cups/notify.c:102
+msgid "aborted"
+msgstr ""
+
+#: cups/notify.c:99
+msgid "canceled"
+msgstr ""
+
+#: cups/notify.c:105
+msgid "completed"
+msgstr ""
+
+#: scheduler/cupsfilter.c:355
+msgid "convert: Use the -f option to specify a file to convert."
+msgstr ""
+
+#: scheduler/ipp.c:7176
+msgid "cups-deviced failed to execute."
+msgstr ""
+
+#: scheduler/ipp.c:8006 scheduler/ipp.c:8256
+msgid "cups-driverd failed to execute."
+msgstr ""
+
+#: systemv/cupsaddsmb.c:233
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s"
+msgstr ""
+
+#: systemv/cupsctl.c:147
+msgid "cupsctl: Cannot set Listen or Port directly."
+msgstr ""
+
+#: systemv/cupsctl.c:158
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s"
+msgstr ""
+
+#: systemv/cupsctl.c:201
+#, c-format
+msgid "cupsctl: Unknown option \"%s\""
+msgstr ""
+
+#: systemv/cupsctl.c:203
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\""
+msgstr ""
+
+#: scheduler/main.c:197
+msgid "cupsd: Expected config filename after \"-c\" option."
+msgstr ""
+
+#: scheduler/main.c:229 scheduler/main.c:236
+msgid "cupsd: Unable to get current directory."
+msgstr ""
+
+#: scheduler/main.c:303
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting."
+msgstr ""
+
+#: scheduler/main.c:296
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting."
+msgstr ""
+
+#: scheduler/main.c:263
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1215
+#, c-format
+msgid "cupsfilter: Invalid document number %d."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1209
+#, c-format
+msgid "cupsfilter: Invalid job ID %d."
+msgstr ""
+
+#: scheduler/cupsfilter.c:363
+msgid "cupsfilter: Only one filename can be specified."
+msgstr ""
+
+#: scheduler/cupsfilter.c:1257
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s"
+msgstr ""
+
+#: systemv/cupstestppd.c:260
+msgid "cupstestppd: The -q option is incompatible with the -v option."
+msgstr ""
+
+#: systemv/cupstestppd.c:276
+msgid "cupstestppd: The -v option is incompatible with the -q option."
+msgstr ""
+
+#: systemv/lpstat.c:1228 systemv/lpstat.c:1231 systemv/lpstat.c:1234
+#, c-format
+msgid "device for %s/%s: %s"
+msgstr ""
+
+#: systemv/lpstat.c:1215 systemv/lpstat.c:1218 systemv/lpstat.c:1221
+#, c-format
+msgid "device for %s: %s"
+msgstr ""
+
+#: cups/snmp.c:1036
+msgid "error-index uses indefinite length"
+msgstr ""
+
+#: cups/snmp.c:1028
+msgid "error-status uses indefinite length"
+msgstr ""
+
+#: cups/notify.c:90
+msgid "held"
+msgstr ""
+
+#: berkeley/lpc.c:209
+msgid "help\t\tGet help on commands."
+msgstr ""
+
+#: cups/notify.c:131
+msgid "idle"
+msgstr ""
+
+#: test/ipptool.c:347
+msgid "ipptool: \"-i\" and \"-n\" are incompatible with -X\"."
+msgstr ""
+
+#: test/ipptool.c:422
+msgid "ipptool: \"-i\" is incompatible with \"-X\"."
+msgstr ""
+
+#: test/ipptool.c:446
+msgid "ipptool: \"-n\" is incompatible with \"-X\"."
+msgstr ""
+
+#: test/ipptool.c:504
+#, c-format
+msgid "ipptool: Bad URI - %s."
+msgstr ""
+
+#: test/ipptool.c:336
+#, c-format
+msgid "ipptool: Bad version %s for \"-V\"."
+msgstr ""
+
+#: test/ipptool.c:415
+msgid "ipptool: Invalid seconds for \"-i\"."
+msgstr ""
+
+#: test/ipptool.c:485
+msgid "ipptool: May only specify a single URI."
+msgstr ""
+
+#: test/ipptool.c:438
+msgid "ipptool: Missing count for \"-n\"."
+msgstr ""
+
+#: test/ipptool.c:382
+msgid "ipptool: Missing filename for \"-f\"."
+msgstr ""
+
+#: test/ipptool.c:363
+msgid "ipptool: Missing name=value for \"-d\"."
+msgstr ""
+
+#: test/ipptool.c:405
+msgid "ipptool: Missing seconds for \"-i\"."
+msgstr ""
+
+#: test/ipptool.c:306
+msgid "ipptool: Missing timeout for \"-T\"."
+msgstr ""
+
+#: test/ipptool.c:319
+msgid "ipptool: Missing version for \"-V\"."
+msgstr ""
+
+#: test/ipptool.c:527
+msgid "ipptool: URI required before test file."
+msgstr ""
+
+#: test/ipptool.c:465
+#, c-format
+msgid "ipptool: Unknown option \"-%c\"."
+msgstr ""
+
+#: scheduler/ipp.c:8996
+msgid "job-printer-uri attribute missing."
+msgstr ""
+
+#: systemv/lpadmin.c:131 systemv/lpadmin.c:375
+msgid "lpadmin: Class name can only contain printable characters."
+msgstr ""
+
+#: systemv/lpadmin.c:614
+msgid "lpadmin: Expected PPD after \"-P\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:457
+msgid "lpadmin: Expected allow/deny:userlist after \"-u\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:364
+msgid "lpadmin: Expected class after \"-r\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:120
+msgid "lpadmin: Expected class name after \"-c\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:558
+msgid "lpadmin: Expected description after \"-D\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:491
+msgid "lpadmin: Expected device URI after \"-v\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:574
+msgid "lpadmin: Expected file type(s) after \"-I\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:202
+msgid "lpadmin: Expected hostname after \"-h\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:221
+msgid "lpadmin: Expected interface after \"-i\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:594
+msgid "lpadmin: Expected location after \"-L\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:274
+msgid "lpadmin: Expected model after \"-m\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:417
+msgid "lpadmin: Expected name after \"-R\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:294
+msgid "lpadmin: Expected name=value after \"-o\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:313
+msgid "lpadmin: Expected printer after \"-p\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:164
+msgid "lpadmin: Expected printer name after \"-d\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:525
+msgid "lpadmin: Expected printer or class after \"-x\" option."
+msgstr ""
+
+#: systemv/lpadmin.c:975
+msgid "lpadmin: No member names were seen."
+msgstr ""
+
+#: systemv/lpadmin.c:762
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s."
+msgstr ""
+
+#: systemv/lpadmin.c:989
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s."
+msgstr ""
+
+#: systemv/lpadmin.c:175 systemv/lpadmin.c:324 systemv/lpadmin.c:536
+msgid "lpadmin: Printer name can only contain printable characters."
+msgstr ""
+
+#: systemv/lpadmin.c:105
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first."
+msgstr ""
+
+#: systemv/lpadmin.c:96 systemv/lpadmin.c:149 systemv/lpadmin.c:253
+#: systemv/lpadmin.c:339 systemv/lpadmin.c:393 systemv/lpadmin.c:510
+#: systemv/lpadmin.c:647
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s"
+msgstr ""
+
+#: systemv/lpadmin.c:1332
+msgid "lpadmin: Unable to create temporary file"
+msgstr ""
+
+#: systemv/lpadmin.c:402
+msgid ""
+"lpadmin: Unable to delete option:\n"
+" You must specify a printer name first."
+msgstr ""
+
+#: systemv/lpadmin.c:1342
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s"
+msgstr ""
+
+#: systemv/lpadmin.c:348
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first."
+msgstr ""
+
+#: systemv/lpadmin.c:656
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first."
+msgstr ""
+
+#: systemv/lpadmin.c:474
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"."
+msgstr ""
+
+#: systemv/lpadmin.c:629
+#, c-format
+msgid "lpadmin: Unknown argument \"%s\"."
+msgstr ""
+
+#: systemv/lpadmin.c:624
+#, c-format
+msgid "lpadmin: Unknown option \"%c\"."
+msgstr ""
+
+#: systemv/lpadmin.c:580
+msgid "lpadmin: Warning - content type list ignored."
+msgstr ""
+
+#: berkeley/lpc.c:76 berkeley/lpc.c:104 berkeley/lpc.c:140
+msgid "lpc> "
+msgstr ""
+
+#: systemv/lpinfo.c:137
+msgid "lpinfo: Expected 1284 device ID string after \"--device-id\"."
+msgstr ""
+
+#: systemv/lpinfo.c:190
+msgid "lpinfo: Expected language after \"--language\"."
+msgstr ""
+
+#: systemv/lpinfo.c:207
+msgid "lpinfo: Expected make and model after \"--make-and-model\"."
+msgstr ""
+
+#: systemv/lpinfo.c:224
+msgid "lpinfo: Expected product string after \"--product\"."
+msgstr ""
+
+#: systemv/lpinfo.c:155
+msgid "lpinfo: Expected scheme list after \"--exclude-schemes\"."
+msgstr ""
+
+#: systemv/lpinfo.c:173
+msgid "lpinfo: Expected scheme list after \"--include-schemes\"."
+msgstr ""
+
+#: systemv/lpinfo.c:241
+msgid "lpinfo: Expected timeout after \"--timeout\"."
+msgstr ""
+
+#: systemv/lpinfo.c:265
+#, c-format
+msgid "lpinfo: Unknown argument \"%s\"."
+msgstr ""
+
+#: systemv/lpinfo.c:259
+#, c-format
+msgid "lpinfo: Unknown option \"%c\"."
+msgstr ""
+
+#: systemv/lpinfo.c:252
+#, c-format
+msgid "lpinfo: Unknown option \"%s\"."
+msgstr ""
+
+#: systemv/lpmove.c:133
+#, c-format
+msgid "lpmove: Unable to connect to server: %s"
+msgstr ""
+
+#: systemv/lpmove.c:119
+#, c-format
+msgid "lpmove: Unknown argument \"%s\"."
+msgstr ""
+
+#: systemv/lpmove.c:97
+#, c-format
+msgid "lpmove: Unknown option \"%c\"."
+msgstr ""
+
+#: systemv/lpoptions.c:150 systemv/lpoptions.c:168 systemv/lpoptions.c:244
+msgid "lpoptions: No printers."
+msgstr ""
+
+#: systemv/lpoptions.c:219
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s"
+msgstr ""
+
+#: systemv/lpoptions.c:521
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s"
+msgstr ""
+
+#: systemv/lpoptions.c:529
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s."
+msgstr ""
+
+#: systemv/lpoptions.c:99
+msgid "lpoptions: Unknown printer or class."
+msgstr ""
+
+#: systemv/lppasswd.c:173
+msgid "lppasswd: Only root can add or delete passwords."
+msgstr ""
+
+#: systemv/lppasswd.c:302
+msgid "lppasswd: Password file busy."
+msgstr ""
+
+#: systemv/lppasswd.c:431
+msgid "lppasswd: Password file not updated."
+msgstr ""
+
+#: systemv/lppasswd.c:398
+msgid "lppasswd: Sorry, password doesn't match."
+msgstr ""
+
+#: systemv/lppasswd.c:253
+msgid "lppasswd: Sorry, password rejected."
+msgstr ""
+
+#: systemv/lppasswd.c:230
+msgid "lppasswd: Sorry, passwords don't match."
+msgstr ""
+
+#: systemv/lppasswd.c:199 systemv/lppasswd.c:218
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s"
+msgstr ""
+
+#: systemv/lppasswd.c:304 systemv/lppasswd.c:312 systemv/lppasswd.c:329
+#, c-format
+msgid "lppasswd: Unable to open password file: %s"
+msgstr ""
+
+#: systemv/lppasswd.c:364 systemv/lppasswd.c:377 systemv/lppasswd.c:408
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s"
+msgstr ""
+
+#: systemv/lppasswd.c:446
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s"
+msgstr ""
+
+#: systemv/lppasswd.c:458
+#, c-format
+msgid "lppasswd: failed to rename password file: %s"
+msgstr ""
+
+#: systemv/lppasswd.c:389
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist."
+msgstr ""
+
+#: systemv/lpstat.c:1036
+#, c-format
+msgid "lpstat: error - %s environment variable names non-existent destination \"%s\"."
+msgstr ""
+
+#: systemv/lpstat.c:967
+#, c-format
+msgid "members of class %s:"
+msgstr ""
+
+#: berkeley/lpq.c:582
+msgid "no entries"
+msgstr ""
+
+#: systemv/lpstat.c:1040
+msgid "no system default destination"
+msgstr ""
+
+#: scheduler/ipp.c:6864
+msgid "notify-events not specified."
+msgstr ""
+
+#: scheduler/ipp.c:2179 scheduler/ipp.c:6769
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used."
+msgstr ""
+
+#: scheduler/ipp.c:2169 scheduler/ipp.c:6759
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme."
+msgstr ""
+
+#: cups/notify.c:87
+msgid "pending"
+msgstr ""
+
+#: ppdc/ppdc.cxx:113 ppdc/ppdpo.cxx:93
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"."
+msgstr ""
+
+#: ppdc/ppdpo.cxx:134
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:412
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-import.cxx:264
+#, c-format
+msgid "ppdc: Bad font attribute: %s"
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1797
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1115
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:2034
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:2710
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1699
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:934
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:957
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:396
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1095
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:449
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:437
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:505
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:494
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:516
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:697
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:2896
+#, c-format
+msgid "ppdc: Expected driver type keyword following DriverType on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:828
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1079
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1690
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1207
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:2610
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1503
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1682
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:355
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:3268
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1060
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:3099
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:3132
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:3222
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:3285
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1158
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1247
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1783
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:481
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1575
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1609
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1587
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1766
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-catalog.cxx:341 ppdc/ppdc-catalog.cxx:353
+#, c-format
+msgid "ppdc: Expected quoted string on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1006
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:574
+#, c-format
+msgid "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1864
+#, c-format
+msgid "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:363
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1103
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:2785
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:3388
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:730
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:374
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1087
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:229
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:974
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:966
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:982
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1629
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1601
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc.cxx:251 ppdc/ppdpo.cxx:123
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"."
+msgstr ""
+
+#: ppdc/ppdc.cxx:187
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"."
+msgstr ""
+
+#: ppdc/ppdc.cxx:126
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:2403 ppdc/ppdc-source.cxx:2635
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:2504 ppdc/ppdc-source.cxx:2539
+#: ppdc/ppdc-source.cxx:2569
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-catalog.cxx:418
+#, c-format
+msgid "ppdc: Need a msgid line before any translation strings on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-driver.cxx:730
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1652 ppdc/ppdc-source.cxx:2873
+#: ppdc/ppdc-source.cxx:2959 ppdc/ppdc-source.cxx:3052
+#: ppdc/ppdc-source.cxx:3185 ppdc/ppdc-source.cxx:3318
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1645
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:707
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:2486
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc.cxx:374
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s."
+msgstr ""
+
+#: ppdc/ppdc.cxx:266
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s"
+msgstr ""
+
+#: ppdc/ppdc.cxx:287
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s"
+msgstr ""
+
+#: ppdc/ppdc.cxx:303 ppdc/ppdc.cxx:309
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s"
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1731
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:2642
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc.cxx:198
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s"
+msgstr ""
+
+#: ppdc/ppdc.cxx:135
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s"
+msgstr ""
+
+#: ppdc/ppdc-file.cxx:49
+#, c-format
+msgid "ppdc: Unable to open %s: %s"
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:2055
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-catalog.cxx:435
+#, c-format
+msgid "ppdc: Unexpected text on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:2915
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:908
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:3145
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-catalog.cxx:463
+#, c-format
+msgid "ppdc: Unknown message catalog format for \"%s\"."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:3399
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:1016
+#, c-format
+msgid "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc-source.cxx:2165
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s."
+msgstr ""
+
+#: ppdc/ppdc.cxx:365
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\"."
+msgstr ""
+
+#: ppdc/ppdc.cxx:380
+#, c-format
+msgid "ppdc: Writing %s."
+msgstr ""
+
+#: ppdc/ppdc.cxx:148
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"."
+msgstr ""
+
+#: ppdc/ppdmerge.cxx:136
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s."
+msgstr ""
+
+#: ppdc/ppdmerge.cxx:176
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s."
+msgstr ""
+
+#: ppdc/ppdmerge.cxx:160
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s - %s"
+msgstr ""
+
+#: systemv/lpstat.c:1781
+#, c-format
+msgid "printer %s disabled since %s -"
+msgstr ""
+
+#: systemv/lpstat.c:1770
+#, c-format
+msgid "printer %s is idle. enabled since %s"
+msgstr ""
+
+#: systemv/lpstat.c:1775
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s"
+msgstr ""
+
+#: systemv/lpstat.c:1906
+#, c-format
+msgid "printer %s/%s disabled since %s -"
+msgstr ""
+
+#: systemv/lpstat.c:1892
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s"
+msgstr ""
+
+#: systemv/lpstat.c:1899
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s"
+msgstr ""
+
+#: cups/notify.c:93 cups/notify.c:134
+msgid "processing"
+msgstr ""
+
+#: systemv/lp.c:639
+#, c-format
+msgid "request id is %s-%d (%d file(s))"
+msgstr ""
+
+#: cups/snmp.c:1020
+msgid "request-id uses indefinite length"
+msgstr ""
+
+#: systemv/lpstat.c:2045
+msgid "scheduler is not running"
+msgstr ""
+
+#: systemv/lpstat.c:2041
+msgid "scheduler is running"
+msgstr ""
+
+#: cups/adminutil.c:2276
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr ""
+
+#: berkeley/lpc.c:211
+msgid "status\t\tShow status of daemon and queue."
+msgstr ""
+
+#: cups/notify.c:96 cups/notify.c:137
+msgid "stopped"
+msgstr ""
+
+#: systemv/lpstat.c:1014
+#, c-format
+msgid "system default destination: %s"
+msgstr ""
+
+#: systemv/lpstat.c:1011
+#, c-format
+msgid "system default destination: %s/%s"
+msgstr ""
+
+#: cups/notify.c:108 cups/notify.c:140
+msgid "unknown"
+msgstr ""
+
+#: cups/notify.c:117
+msgid "untitled"
+msgstr ""
+
+#: cups/snmp.c:1045
+msgid "variable-bindings uses indefinite length"
+msgstr ""
+
+
+#
+# End of "$Id$".
+#
diff --git a/locale/cups.strings b/locale/cups.strings
new file mode 100644
index 000000000..a008ad292
--- /dev/null
+++ b/locale/cups.strings
@@ -0,0 +1,1547 @@
+"\t\t(all)" = "\t\t(all)";
+"\t\t(none)" = "\t\t(none)";
+"\t%d entries" = "\t%d entries";
+"\t%s" = "\t%s";
+"\tAfter fault: continue" = "\tAfter fault: continue";
+"\tAlerts: %s" = "\tAlerts: %s";
+"\tBanner required" = "\tBanner required";
+"\tCharset sets:" = "\tCharset sets:";
+"\tConnection: direct" = "\tConnection: direct";
+"\tConnection: remote" = "\tConnection: remote";
+"\tContent types: any" = "\tContent types: any";
+"\tDefault page size:" = "\tDefault page size:";
+"\tDefault pitch:" = "\tDefault pitch:";
+"\tDefault port settings:" = "\tDefault port settings:";
+"\tDescription: %s" = "\tDescription: %s";
+"\tForm mounted:" = "\tForm mounted:";
+"\tForms allowed:" = "\tForms allowed:";
+"\tInterface: %s.ppd" = "\tInterface: %s.ppd";
+"\tInterface: %s/interfaces/%s" = "\tInterface: %s/interfaces/%s";
+"\tInterface: %s/ppd/%s.ppd" = "\tInterface: %s/ppd/%s.ppd";
+"\tLocation: %s" = "\tLocation: %s";
+"\tOn fault: no alert" = "\tOn fault: no alert";
+"\tPrinter types: unknown" = "\tPrinter types: unknown";
+"\tStatus: %s" = "\tStatus: %s";
+"\tUsers allowed:" = "\tUsers allowed:";
+"\tUsers denied:" = "\tUsers denied:";
+"\tdaemon present" = "\tdaemon present";
+"\tno entries" = "\tno entries";
+"\tprinter is on device '%s' speed -1" = "\tprinter is on device '%s' speed -1";
+"\tprinting is disabled" = "\tprinting is disabled";
+"\tprinting is enabled" = "\tprinting is enabled";
+"\tqueued for %s" = "\tqueued for %s";
+"\tqueuing is disabled" = "\tqueuing is disabled";
+"\tqueuing is enabled" = "\tqueuing is enabled";
+"\treason unknown" = "\treason unknown";
+"\n DETAILED CONFORMANCE TEST RESULTS" = "\n DETAILED CONFORMANCE TEST RESULTS";
+" Ignore specific warnings." = " Ignore specific warnings.";
+" Issue warnings instead of errors." = " Issue warnings instead of errors.";
+" REF: Page 15, section 3.1." = " REF: Page 15, section 3.1.";
+" REF: Page 15, section 3.2." = " REF: Page 15, section 3.2.";
+" REF: Page 19, section 3.3." = " REF: Page 19, section 3.3.";
+" REF: Page 20, section 3.4." = " REF: Page 20, section 3.4.";
+" REF: Page 27, section 3.5." = " REF: Page 27, section 3.5.";
+" REF: Page 42, section 5.2." = " REF: Page 42, section 5.2.";
+" REF: Pages 16-17, section 3.2." = " REF: Pages 16-17, section 3.2.";
+" REF: Pages 42-45, section 5.2." = " REF: Pages 42-45, section 5.2.";
+" REF: Pages 45-46, section 5.2." = " REF: Pages 45-46, section 5.2.";
+" REF: Pages 48-49, section 5.2." = " REF: Pages 48-49, section 5.2.";
+" REF: Pages 52-54, section 5.2." = " REF: Pages 52-54, section 5.2.";
+" %-39.39s %.0f bytes" = " %-39.39s %.0f bytes";
+" PASS Default%s" = " PASS Default%s";
+" PASS DefaultImageableArea" = " PASS DefaultImageableArea";
+" PASS DefaultPaperDimension" = " PASS DefaultPaperDimension";
+" PASS FileVersion" = " PASS FileVersion";
+" PASS FormatVersion" = " PASS FormatVersion";
+" PASS LanguageEncoding" = " PASS LanguageEncoding";
+" PASS LanguageVersion" = " PASS LanguageVersion";
+" PASS Manufacturer" = " PASS Manufacturer";
+" PASS ModelName" = " PASS ModelName";
+" PASS NickName" = " PASS NickName";
+" PASS PCFileName" = " PASS PCFileName";
+" PASS PSVersion" = " PASS PSVersion";
+" PASS PageRegion" = " PASS PageRegion";
+" PASS PageSize" = " PASS PageSize";
+" PASS Product" = " PASS Product";
+" PASS ShortNickName" = " PASS ShortNickName";
+" WARN %s has no corresponding options." = " WARN %s has no corresponding options.";
+" WARN %s shares a common prefix with %s\n REF: Page 15, section 3.2." = " WARN %s shares a common prefix with %s\n REF: Page 15, section 3.2.";
+" WARN Duplex option keyword %s may not work as expected and should be named Duplex.\n REF: Page 122, section 5.17" = " WARN Duplex option keyword %s may not work as expected and should be named Duplex.\n REF: Page 122, section 5.17";
+" WARN File contains a mix of CR, LF, and CR LF line endings." = " WARN File contains a mix of CR, LF, and CR LF line endings.";
+" WARN LanguageEncoding required by PPD 4.3 spec.\n REF: Pages 56-57, section 5.3." = " WARN LanguageEncoding required by PPD 4.3 spec.\n REF: Pages 56-57, section 5.3.";
+" WARN Line %d only contains whitespace." = " WARN Line %d only contains whitespace.";
+" WARN Manufacturer required by PPD 4.3 spec.\n REF: Pages 58-59, section 5.3." = " WARN Manufacturer required by PPD 4.3 spec.\n REF: Pages 58-59, section 5.3.";
+" WARN Non-Windows PPD files should use lines ending with only LF, not CR LF." = " WARN Non-Windows PPD files should use lines ending with only LF, not CR LF.";
+" WARN Obsolete PPD version %.1f.\n REF: Page 42, section 5.2." = " WARN Obsolete PPD version %.1f.\n REF: Page 42, section 5.2.";
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n REF: Pages 61-62, section 5.3." = " WARN PCFileName longer than 8.3 in violation of PPD spec.\n REF: Pages 61-62, section 5.3.";
+" WARN PCFileName should contain a unique filename.\n REF: Pages 61-62, section 5.3." = " WARN PCFileName should contain a unique filename.\n REF: Pages 61-62, section 5.3.";
+" WARN Protocols contains PJL but JCL attributes are not set.\n REF: Pages 78-79, section 5.7." = " WARN Protocols contains PJL but JCL attributes are not set.\n REF: Pages 78-79, section 5.7.";
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n REF: Pages 78-79, section 5.7." = " WARN Protocols contains both PJL and BCP; expected TBCP.\n REF: Pages 78-79, section 5.7.";
+" WARN ShortNickName required by PPD 4.3 spec.\n REF: Pages 64-65, section 5.3." = " WARN ShortNickName required by PPD 4.3 spec.\n REF: Pages 64-65, section 5.3.";
+" cupsaddsmb [options] -a" = " cupsaddsmb [options] -a";
+" cupstestdsc [options] -" = " cupstestdsc [options] -";
+" program | cupstestppd [options] -" = " program | cupstestppd [options] -";
+" %s \"%s %s\" conflicts with \"%s %s\"\n (constraint=\"%s %s %s %s\")." = " %s \"%s %s\" conflicts with \"%s %s\"\n (constraint=\"%s %s %s %s\").";
+" %s %s %s does not exist." = " %s %s %s does not exist.";
+" %s %s file \"%s\" has the wrong capitalization." = " %s %s file \"%s\" has the wrong capitalization.";
+" %s Bad %s choice %s.\n REF: Page 122, section 5.17" = " %s Bad %s choice %s.\n REF: Page 122, section 5.17";
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s." = " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s.";
+" %s Bad UTF-8 \"%s\" translation string for option %s." = " %s Bad UTF-8 \"%s\" translation string for option %s.";
+" %s Bad cupsFilter value \"%s\"." = " %s Bad cupsFilter value \"%s\".";
+" %s Bad cupsICCProfile %s." = " %s Bad cupsICCProfile %s.";
+" %s Bad cupsPreFilter value \"%s\"." = " %s Bad cupsPreFilter value \"%s\".";
+" %s Bad cupsUIConstraints %s: \"%s\"" = " %s Bad cupsUIConstraints %s: \"%s\"";
+" %s Bad language \"%s\"." = " %s Bad language \"%s\".";
+" %s Bad permissions on %s file \"%s\"." = " %s Bad permissions on %s file \"%s\".";
+" %s Bad spelling of %s - should be %s." = " %s Bad spelling of %s - should be %s.";
+" %s Cannot provide both APScanAppPath and APScanAppBundleID." = " %s Cannot provide both APScanAppPath and APScanAppBundleID.";
+" %s Default choices conflicting." = " %s Default choices conflicting.";
+" %s Empty cupsUIConstraints %s" = " %s Empty cupsUIConstraints %s";
+" %s Missing \"%s\" translation string for option %s, choice %s." = " %s Missing \"%s\" translation string for option %s, choice %s.";
+" %s Missing \"%s\" translation string for option %s." = " %s Missing \"%s\" translation string for option %s.";
+" %s Missing %s file \"%s\"." = " %s Missing %s file \"%s\".";
+" %s Missing REQUIRED PageRegion option.\n REF: Page 100, section 5.14." = " %s Missing REQUIRED PageRegion option.\n REF: Page 100, section 5.14.";
+" %s Missing REQUIRED PageSize option.\n REF: Page 99, section 5.14." = " %s Missing REQUIRED PageSize option.\n REF: Page 99, section 5.14.";
+" %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"." = " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\".";
+" %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"" = " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"";
+" %s Missing cupsUIResolver %s" = " %s Missing cupsUIResolver %s";
+" %s Missing option %s in UIConstraints \"*%s %s *%s %s\"." = " %s Missing option %s in UIConstraints \"*%s %s *%s %s\".";
+" %s Missing option %s in cupsUIConstraints %s: \"%s\"" = " %s Missing option %s in cupsUIConstraints %s: \"%s\"";
+" %s No base translation \"%s\" is included in file." = " %s No base translation \"%s\" is included in file.";
+" %s REQUIRED %s does not define choice None.\n REF: Page 122, section 5.17" = " %s REQUIRED %s does not define choice None.\n REF: Page 122, section 5.17";
+" %s Size \"%s\" defined for %s but not for %s." = " %s Size \"%s\" defined for %s but not for %s.";
+" %s Size \"%s\" has unexpected dimensions (%gx%g)." = " %s Size \"%s\" has unexpected dimensions (%gx%g).";
+" %s Size \"%s\" should be \"%s\"." = " %s Size \"%s\" should be \"%s\".";
+" %s Size \"%s\" should be the Adobe standard name \"%s\"." = " %s Size \"%s\" should be the Adobe standard name \"%s\".";
+" %s cupsICCProfile %s hash value collides with %s." = " %s cupsICCProfile %s hash value collides with %s.";
+" %s cupsUIResolver %s causes a loop." = " %s cupsUIResolver %s causes a loop.";
+" %s cupsUIResolver %s does not list at least two different options." = " %s cupsUIResolver %s does not list at least two different options.";
+" **FAIL** %s choice names %s and %s differ only by case." = " **FAIL** %s choice names %s and %s differ only by case.";
+" **FAIL** %s must be 1284DeviceID\n REF: Page 72, section 5.5" = " **FAIL** %s must be 1284DeviceID\n REF: Page 72, section 5.5";
+" **FAIL** BAD Default%s %s\n REF: Page 40, section 4.5." = " **FAIL** BAD Default%s %s\n REF: Page 40, section 4.5.";
+" **FAIL** BAD DefaultImageableArea %s\n REF: Page 102, section 5.15." = " **FAIL** BAD DefaultImageableArea %s\n REF: Page 102, section 5.15.";
+" **FAIL** BAD DefaultPaperDimension %s\n REF: Page 103, section 5.15." = " **FAIL** BAD DefaultPaperDimension %s\n REF: Page 103, section 5.15.";
+" **FAIL** BAD JobPatchFile attribute in file\n REF: Page 24, section 3.4." = " **FAIL** BAD JobPatchFile attribute in file\n REF: Page 24, section 3.4.";
+" **FAIL** BAD Manufacturer (should be \"HP\")\n REF: Page 211, table D.1." = " **FAIL** BAD Manufacturer (should be \"HP\")\n REF: Page 211, table D.1.";
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n REF: Page 211, table D.1." = " **FAIL** BAD Manufacturer (should be \"Oki\")\n REF: Page 211, table D.1.";
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n REF: Pages 59-60, section 5.3." = " **FAIL** BAD ModelName - \"%c\" not allowed in string.\n REF: Pages 59-60, section 5.3.";
+" **FAIL** BAD PSVersion - not \"(string) int\".\n REF: Pages 62-64, section 5.3." = " **FAIL** BAD PSVersion - not \"(string) int\".\n REF: Pages 62-64, section 5.3.";
+" **FAIL** BAD Product - not \"(string)\".\n REF: Page 62, section 5.3." = " **FAIL** BAD Product - not \"(string)\".\n REF: Page 62, section 5.3.";
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n REF: Pages 64-65, section 5.3." = " **FAIL** BAD ShortNickName - longer than 31 chars.\n REF: Pages 64-65, section 5.3.";
+" **FAIL** Bad %s choice %s\n REF: Page 84, section 5.9" = " **FAIL** Bad %s choice %s\n REF: Page 84, section 5.9";
+" **FAIL** Bad FileVersion \"%s\"\n REF: Page 56, section 5.3." = " **FAIL** Bad FileVersion \"%s\"\n REF: Page 56, section 5.3.";
+" **FAIL** Bad FormatVersion \"%s\"\n REF: Page 56, section 5.3." = " **FAIL** Bad FormatVersion \"%s\"\n REF: Page 56, section 5.3.";
+" **FAIL** Bad LanguageEncoding %s - must be ISOLatin1." = " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1.";
+" **FAIL** Bad LanguageVersion %s - must be English." = " **FAIL** Bad LanguageVersion %s - must be English.";
+" **FAIL** Default option code cannot be interpreted: %s" = " **FAIL** Default option code cannot be interpreted: %s";
+" **FAIL** Default translation string for option %s choice %s contains 8-bit characters." = " **FAIL** Default translation string for option %s choice %s contains 8-bit characters.";
+" **FAIL** Default translation string for option %s contains 8-bit characters." = " **FAIL** Default translation string for option %s contains 8-bit characters.";
+" **FAIL** Group names %s and %s differ only by case." = " **FAIL** Group names %s and %s differ only by case.";
+" **FAIL** Multiple occurrences of %s choice name %s." = " **FAIL** Multiple occurrences of %s choice name %s.";
+" **FAIL** Option names %s and %s differ only by case." = " **FAIL** Option names %s and %s differ only by case.";
+" **FAIL** REQUIRED Default%s\n REF: Page 40, section 4.5." = " **FAIL** REQUIRED Default%s\n REF: Page 40, section 4.5.";
+" **FAIL** REQUIRED DefaultImageableArea\n REF: Page 102, section 5.15." = " **FAIL** REQUIRED DefaultImageableArea\n REF: Page 102, section 5.15.";
+" **FAIL** REQUIRED DefaultPaperDimension\n REF: Page 103, section 5.15." = " **FAIL** REQUIRED DefaultPaperDimension\n REF: Page 103, section 5.15.";
+" **FAIL** REQUIRED FileVersion\n REF: Page 56, section 5.3." = " **FAIL** REQUIRED FileVersion\n REF: Page 56, section 5.3.";
+" **FAIL** REQUIRED FormatVersion\n REF: Page 56, section 5.3." = " **FAIL** REQUIRED FormatVersion\n REF: Page 56, section 5.3.";
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n REF: Page 41, section 5.\n REF: Page 102, section 5.15." = " **FAIL** REQUIRED ImageableArea for PageSize %s\n REF: Page 41, section 5.\n REF: Page 102, section 5.15.";
+" **FAIL** REQUIRED LanguageEncoding\n REF: Pages 56-57, section 5.3." = " **FAIL** REQUIRED LanguageEncoding\n REF: Pages 56-57, section 5.3.";
+" **FAIL** REQUIRED LanguageVersion\n REF: Pages 57-58, section 5.3." = " **FAIL** REQUIRED LanguageVersion\n REF: Pages 57-58, section 5.3.";
+" **FAIL** REQUIRED Manufacturer\n REF: Pages 58-59, section 5.3." = " **FAIL** REQUIRED Manufacturer\n REF: Pages 58-59, section 5.3.";
+" **FAIL** REQUIRED ModelName\n REF: Pages 59-60, section 5.3." = " **FAIL** REQUIRED ModelName\n REF: Pages 59-60, section 5.3.";
+" **FAIL** REQUIRED NickName\n REF: Page 60, section 5.3." = " **FAIL** REQUIRED NickName\n REF: Page 60, section 5.3.";
+" **FAIL** REQUIRED PCFileName\n REF: Pages 61-62, section 5.3." = " **FAIL** REQUIRED PCFileName\n REF: Pages 61-62, section 5.3.";
+" **FAIL** REQUIRED PSVersion\n REF: Pages 62-64, section 5.3." = " **FAIL** REQUIRED PSVersion\n REF: Pages 62-64, section 5.3.";
+" **FAIL** REQUIRED PageRegion\n REF: Page 100, section 5.14." = " **FAIL** REQUIRED PageRegion\n REF: Page 100, section 5.14.";
+" **FAIL** REQUIRED PageSize\n REF: Page 41, section 5.\n REF: Page 99, section 5.14." = " **FAIL** REQUIRED PageSize\n REF: Page 41, section 5.\n REF: Page 99, section 5.14.";
+" **FAIL** REQUIRED PageSize\n REF: Pages 99-100, section 5.14." = " **FAIL** REQUIRED PageSize\n REF: Pages 99-100, section 5.14.";
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n REF: Page 41, section 5.\n REF: Page 103, section 5.15." = " **FAIL** REQUIRED PaperDimension for PageSize %s\n REF: Page 41, section 5.\n REF: Page 103, section 5.15.";
+" **FAIL** REQUIRED Product\n REF: Page 62, section 5.3." = " **FAIL** REQUIRED Product\n REF: Page 62, section 5.3.";
+" **FAIL** REQUIRED ShortNickName\n REF: Page 64-65, section 5.3." = " **FAIL** REQUIRED ShortNickName\n REF: Page 64-65, section 5.3.";
+" **FAIL** Unable to open PPD file - %s" = " **FAIL** Unable to open PPD file - %s";
+" **FAIL** Unable to open PPD file - %s on line %d." = " **FAIL** Unable to open PPD file - %s on line %d.";
+" %d ERRORS FOUND" = " %d ERRORS FOUND";
+" -h Show program usage" = " -h Show program usage";
+" Bad %%%%BoundingBox: on line %d.\n REF: Page 39, %%%%BoundingBox:" = " Bad %%%%BoundingBox: on line %d.\n REF: Page 39, %%%%BoundingBox:";
+" Bad %%%%Page: on line %d.\n REF: Page 53, %%%%Page:" = " Bad %%%%Page: on line %d.\n REF: Page 53, %%%%Page:";
+" Bad %%%%Pages: on line %d.\n REF: Page 43, %%%%Pages:" = " Bad %%%%Pages: on line %d.\n REF: Page 43, %%%%Pages:";
+" Line %d is longer than 255 characters (%d).\n REF: Page 25, Line Length" = " Line %d is longer than 255 characters (%d).\n REF: Page 25, Line Length";
+" Missing %!PS-Adobe-3.0 on first line.\n REF: Page 17, 3.1 Conforming Documents" = " Missing %!PS-Adobe-3.0 on first line.\n REF: Page 17, 3.1 Conforming Documents";
+" Missing %%EndComments comment. REF: Page 41, %%EndComments" = " Missing %%EndComments comment. REF: Page 41, %%EndComments";
+" Missing or bad %%BoundingBox: comment.\n REF: Page 39, %%BoundingBox:" = " Missing or bad %%BoundingBox: comment.\n REF: Page 39, %%BoundingBox:";
+" Missing or bad %%Page: comments.\n REF: Page 53, %%Page:" = " Missing or bad %%Page: comments.\n REF: Page 53, %%Page:";
+" Missing or bad %%Pages: comment.\n REF: Page 43, %%Pages:" = " Missing or bad %%Pages: comment.\n REF: Page 43, %%Pages:";
+" NO ERRORS FOUND" = " NO ERRORS FOUND";
+" Saw %d lines that exceeded 255 characters." = " Saw %d lines that exceeded 255 characters.";
+" Too many %%BeginDocument comments." = " Too many %%BeginDocument comments.";
+" Too many %%EndDocument comments." = " Too many %%EndDocument comments.";
+" Warning: file contains binary data." = " Warning: file contains binary data.";
+" Warning: no %%EndComments comment in file." = " Warning: no %%EndComments comment in file.";
+" Warning: obsolete DSC version %.1f in file." = " Warning: obsolete DSC version %.1f in file.";
+" --[no-]debug-logging Turn debug logging on/off." = " --[no-]debug-logging Turn debug logging on/off.";
+" --[no-]remote-admin Turn remote administration on/off." = " --[no-]remote-admin Turn remote administration on/off.";
+" --[no-]remote-any Allow/prevent access from the Internet." = " --[no-]remote-any Allow/prevent access from the Internet.";
+" --[no-]remote-printers Show/hide remote printers." = " --[no-]remote-printers Show/hide remote printers.";
+" --[no-]share-printers Turn printer sharing on/off." = " --[no-]share-printers Turn printer sharing on/off.";
+" --[no-]user-cancel-any Allow/prevent users to cancel any job." = " --[no-]user-cancel-any Allow/prevent users to cancel any job.";
+" --cr End lines with CR (Mac OS 9)." = " --cr End lines with CR (Mac OS 9).";
+" --crlf End lines with CR + LF (Windows)." = " --crlf End lines with CR + LF (Windows).";
+" --lf End lines with LF (UNIX/Linux/Mac OS X)." = " --lf End lines with LF (UNIX/Linux/Mac OS X).";
+" -4 Connect using IPv4." = " -4 Connect using IPv4.";
+" -6 Connect using IPv6." = " -6 Connect using IPv6.";
+" -C Send requests using chunking (default)." = " -C Send requests using chunking (default).";
+" -D Remove the input file when finished." = " -D Remove the input file when finished.";
+" -D name=value Set named variable to value." = " -D name=value Set named variable to value.";
+" -E Enable encryption." = " -E Enable encryption.";
+" -E Encrypt the connection to the server." = " -E Encrypt the connection to the server.";
+" -E Test with TLS encryption." = " -E Test with TLS encryption.";
+" -F Run in the foreground but detach from console." = " -F Run in the foreground but detach from console.";
+" -H samba-server Use the named SAMBA server." = " -H samba-server Use the named SAMBA server.";
+" -I Ignore errors." = " -I Ignore errors.";
+" -I include-dir Add include directory to search path." = " -I include-dir Add include directory to search path.";
+" -I {filename,filters,none,profiles}" = " -I {filename,filters,none,profiles}";
+" -J title Set title." = " -J title Set title.";
+" -L Send requests using content-length." = " -L Send requests using content-length.";
+" -P filename.ppd Set PPD file." = " -P filename.ppd Set PPD file.";
+" -R root-directory Set alternate root." = " -R root-directory Set alternate root.";
+" -S Test with SSL encryption." = " -S Test with SSL encryption.";
+" -T Set the receive/send timeout in seconds." = " -T Set the receive/send timeout in seconds.";
+" -U samba-user Authenticate using the named SAMBA user." = " -U samba-user Authenticate using the named SAMBA user.";
+" -U username Set username for job." = " -U username Set username for job.";
+" -U username Specify username." = " -U username Specify username.";
+" -V version Set default IPP version." = " -V version Set default IPP version.";
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,translations}" = " -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,translations}";
+" -X Produce XML plist instead of plain text." = " -X Produce XML plist instead of plain text.";
+" -a Export all printers." = " -a Export all printers.";
+" -a 'name=value ...' Set option(s)." = " -a 'name=value ...' Set option(s).";
+" -c catalog.po Load the specified message catalog." = " -c catalog.po Load the specified message catalog.";
+" -c config-file Load alternate configuration file." = " -c config-file Load alternate configuration file.";
+" -c copies Set number of copies." = " -c copies Set number of copies.";
+" -c cupsd.conf Set cupsd.conf file to use." = " -c cupsd.conf Set cupsd.conf file to use.";
+" -d name=value Set named variable to value." = " -d name=value Set named variable to value.";
+" -d output-dir Specify the output directory." = " -d output-dir Specify the output directory.";
+" -d printer Use the named printer." = " -d printer Use the named printer.";
+" -e Use every filter from the PPD file." = " -e Use every filter from the PPD file.";
+" -f Run in the foreground." = " -f Run in the foreground.";
+" -f filename Set default request filename." = " -f filename Set default request filename.";
+" -f filename Set file to be converted (otherwise stdin)." = " -f filename Set file to be converted (otherwise stdin).";
+" -h Show this usage message." = " -h Show this usage message.";
+" -h cups-server Use the named CUPS server." = " -h cups-server Use the named CUPS server.";
+" -h server[:port] Specify server address." = " -h server[:port] Specify server address.";
+" -i mime/type Set input MIME type (otherwise auto-typed)." = " -i mime/type Set input MIME type (otherwise auto-typed).";
+" -i seconds Repeat the last file with the given time interval." = " -i seconds Repeat the last file with the given time interval.";
+" -j job-id[,N] Filter file N from the specified job (default is file 1)." = " -j job-id[,N] Filter file N from the specified job (default is file 1).";
+" -j mime/type Set output MIME type (otherwise application/pdf)." = " -j mime/type Set output MIME type (otherwise application/pdf).";
+" -l Run cupsd from launchd(8)." = " -l Run cupsd from launchd(8).";
+" -l lang[,lang,...] Specify the output language(s) (locale)." = " -l lang[,lang,...] Specify the output language(s) (locale).";
+" -m Use the ModelName value as the filename." = " -m Use the ModelName value as the filename.";
+" -m mime/type Set output MIME type (otherwise application/pdf)." = " -m mime/type Set output MIME type (otherwise application/pdf).";
+" -n copies Set number of copies." = " -n copies Set number of copies.";
+" -n count Repeat the last file the given number of times." = " -n count Repeat the last file the given number of times.";
+" -o filename Set file to be generated (otherwise stdout)." = " -o filename Set file to be generated (otherwise stdout).";
+" -o filename.drv Set driver information file (otherwise ppdi.drv)." = " -o filename.drv Set driver information file (otherwise ppdi.drv).";
+" -o filename.ppd[.gz] Set output file (otherwise stdout)." = " -o filename.ppd[.gz] Set output file (otherwise stdout).";
+" -o name=value Set option(s)." = " -o name=value Set option(s).";
+" -p filename.ppd Set PPD file." = " -p filename.ppd Set PPD file.";
+" -q Be quiet - no output except errors." = " -q Be quiet - no output except errors.";
+" -q Run silently." = " -q Run silently.";
+" -r Use 'relaxed' open mode." = " -r Use 'relaxed' open mode.";
+" -t Produce a test report." = " -t Produce a test report.";
+" -t Test PPDs instead of generating them." = " -t Test PPDs instead of generating them.";
+" -t Test the configuration file." = " -t Test the configuration file.";
+" -t title Set title." = " -t title Set title.";
+" -u Remove the PPD file when finished." = " -u Remove the PPD file when finished.";
+" -v Be slightly verbose." = " -v Be slightly verbose.";
+" -v Be verbose (more v's for more verbosity)." = " -v Be verbose (more v's for more verbosity).";
+" -v Be verbose (show commands)." = " -v Be verbose (show commands).";
+" -v Show all attributes sent and received." = " -v Show all attributes sent and received.";
+" -vv Be very verbose." = " -vv Be very verbose.";
+" -z Compress PPD files using GNU zip." = " -z Compress PPD files using GNU zip.";
+" FAIL" = " FAIL";
+" PASS" = " PASS";
+"%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes" = "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes";
+"%-7s %-7.7s %-7d %-31.31s %.0f bytes" = "%-7s %-7.7s %-7d %-31.31s %.0f bytes";
+"%.0f x %.0f millimeters" = "%.0f x %.0f millimeters";
+"%.0f x %.0f to %.0f x %.0f millimeters" = "%.0f x %.0f to %.0f x %.0f millimeters";
+"%.2f x %.2f inches" = "%.2f x %.2f inches";
+"%.2f x %.2f to %.2f x %.2f inches" = "%.2f x %.2f to %.2f x %.2f inches";
+"%s accepting requests since %s" = "%s accepting requests since %s";
+"%s cannot be changed." = "%s cannot be changed.";
+"%s is not implemented by the CUPS version of lpc." = "%s is not implemented by the CUPS version of lpc.";
+"%s is not ready" = "%s is not ready";
+"%s is ready" = "%s is ready";
+"%s is ready and printing" = "%s is ready and printing";
+"%s job-id user title copies options [file]" = "%s job-id user title copies options [file]";
+"%s not accepting requests since %s -" = "%s not accepting requests since %s -";
+"%s not supported." = "%s not supported.";
+"%s/%s accepting requests since %s" = "%s/%s accepting requests since %s";
+"%s/%s not accepting requests since %s -" = "%s/%s not accepting requests since %s -";
+"%s: %-33.33s [job %d localhost]" = "%s: %-33.33s [job %d localhost]";
+// TRANSLATORS: Message is "subject: error"
+"%s: %s" = "%s: %s";
+"%s: %s failed: %s" = "%s: %s failed: %s";
+"%s: Don't know what to do." = "%s: Don't know what to do.";
+"%s: Error - %s environment variable names non-existent destination \"%s\"." = "%s: Error - %s environment variable names non-existent destination \"%s\".";
+"%s: Error - bad job ID." = "%s: Error - bad job ID.";
+"%s: Error - cannot print files and alter jobs simultaneously." = "%s: Error - cannot print files and alter jobs simultaneously.";
+"%s: Error - cannot print from stdin if files or a job ID are provided." = "%s: Error - cannot print from stdin if files or a job ID are provided.";
+"%s: Error - expected character set after \"-S\" option." = "%s: Error - expected character set after \"-S\" option.";
+"%s: Error - expected content type after \"-T\" option." = "%s: Error - expected content type after \"-T\" option.";
+"%s: Error - expected copies after \"-#\" option." = "%s: Error - expected copies after \"-#\" option.";
+"%s: Error - expected copies after \"-n\" option." = "%s: Error - expected copies after \"-n\" option.";
+"%s: Error - expected destination after \"-P\" option." = "%s: Error - expected destination after \"-P\" option.";
+"%s: Error - expected destination after \"-b\" option." = "%s: Error - expected destination after \"-b\" option.";
+"%s: Error - expected destination after \"-d\" option." = "%s: Error - expected destination after \"-d\" option.";
+"%s: Error - expected form after \"-f\" option." = "%s: Error - expected form after \"-f\" option.";
+"%s: Error - expected hold name after \"-H\" option." = "%s: Error - expected hold name after \"-H\" option.";
+"%s: Error - expected hostname after \"-H\" option." = "%s: Error - expected hostname after \"-H\" option.";
+"%s: Error - expected hostname after \"-h\" option." = "%s: Error - expected hostname after \"-h\" option.";
+"%s: Error - expected mode list after \"-y\" option." = "%s: Error - expected mode list after \"-y\" option.";
+"%s: Error - expected name after \"-%c\" option." = "%s: Error - expected name after \"-%c\" option.";
+"%s: Error - expected option=value after \"-o\" option." = "%s: Error - expected option=value after \"-o\" option.";
+"%s: Error - expected page list after \"-P\" option." = "%s: Error - expected page list after \"-P\" option.";
+"%s: Error - expected priority after \"-%c\" option." = "%s: Error - expected priority after \"-%c\" option.";
+"%s: Error - expected reason text after \"-r\" option." = "%s: Error - expected reason text after \"-r\" option.";
+"%s: Error - expected title after \"-t\" option." = "%s: Error - expected title after \"-t\" option.";
+"%s: Error - expected username after \"-U\" option." = "%s: Error - expected username after \"-U\" option.";
+"%s: Error - expected username after \"-u\" option." = "%s: Error - expected username after \"-u\" option.";
+"%s: Error - expected value after \"-%c\" option." = "%s: Error - expected value after \"-%c\" option.";
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after \"-W\" option." = "%s: Error - need \"completed\", \"not-completed\", or \"all\" after \"-W\" option.";
+"%s: Error - no default destination available." = "%s: Error - no default destination available.";
+"%s: Error - priority must be between 1 and 100." = "%s: Error - priority must be between 1 and 100.";
+"%s: Error - scheduler not responding." = "%s: Error - scheduler not responding.";
+"%s: Error - too many files - \"%s\"." = "%s: Error - too many files - \"%s\".";
+"%s: Error - unable to access \"%s\" - %s" = "%s: Error - unable to access \"%s\" - %s";
+"%s: Error - unable to queue from stdin - %s." = "%s: Error - unable to queue from stdin - %s.";
+"%s: Error - unknown destination \"%s\"." = "%s: Error - unknown destination \"%s\".";
+"%s: Error - unknown destination \"%s/%s\"." = "%s: Error - unknown destination \"%s/%s\".";
+"%s: Error - unknown option \"%c\"." = "%s: Error - unknown option \"%c\".";
+"%s: Error - unknown option \"%s\"." = "%s: Error - unknown option \"%s\".";
+"%s: Expected job ID after \"-i\" option." = "%s: Expected job ID after \"-i\" option.";
+"%s: Invalid destination name in list \"%s\"." = "%s: Invalid destination name in list \"%s\".";
+"%s: Invalid filter string \"%s\"." = "%s: Invalid filter string \"%s\".";
+"%s: Need job ID (\"-i jobid\") before \"-H restart\"." = "%s: Need job ID (\"-i jobid\") before \"-H restart\".";
+"%s: No filter to convert from %s/%s to %s/%s." = "%s: No filter to convert from %s/%s to %s/%s.";
+"%s: Operation failed: %s" = "%s: Operation failed: %s";
+"%s: Sorry, no encryption support." = "%s: Sorry, no encryption support.";
+"%s: Unable to connect to server." = "%s: Unable to connect to server.";
+"%s: Unable to contact server." = "%s: Unable to contact server.";
+"%s: Unable to determine MIME type of \"%s\"." = "%s: Unable to determine MIME type of \"%s\".";
+"%s: Unable to open %s: %s" = "%s: Unable to open %s: %s";
+"%s: Unable to open PPD file: %s on line %d." = "%s: Unable to open PPD file: %s on line %d.";
+"%s: Unable to read MIME database from \"%s\" or \"%s\"." = "%s: Unable to read MIME database from \"%s\" or \"%s\".";
+"%s: Unknown destination \"%s\"." = "%s: Unknown destination \"%s\".";
+"%s: Unknown destination MIME type %s/%s." = "%s: Unknown destination MIME type %s/%s.";
+"%s: Unknown option \"%c\"." = "%s: Unknown option \"%c\".";
+"%s: Unknown source MIME type %s/%s." = "%s: Unknown source MIME type %s/%s.";
+"%s: Warning - \"%c\" format modifier not supported - output may not be correct." = "%s: Warning - \"%c\" format modifier not supported - output may not be correct.";
+"%s: Warning - character set option ignored." = "%s: Warning - character set option ignored.";
+"%s: Warning - content type option ignored." = "%s: Warning - content type option ignored.";
+"%s: Warning - form option ignored." = "%s: Warning - form option ignored.";
+"%s: Warning - mode option ignored." = "%s: Warning - mode option ignored.";
+"-1" = "-1";
+"-10" = "-10";
+"-100" = "-100";
+"-105" = "-105";
+"-11" = "-11";
+"-110" = "-110";
+"-115" = "-115";
+"-12" = "-12";
+"-120" = "-120";
+"-13" = "-13";
+"-14" = "-14";
+"-15" = "-15";
+"-2" = "-2";
+"-20" = "-20";
+"-25" = "-25";
+"-3" = "-3";
+"-30" = "-30";
+"-35" = "-35";
+"-4" = "-4";
+"-40" = "-40";
+"-45" = "-45";
+"-5" = "-5";
+"-50" = "-50";
+"-55" = "-55";
+"-6" = "-6";
+"-60" = "-60";
+"-65" = "-65";
+"-7" = "-7";
+"-70" = "-70";
+"-75" = "-75";
+"-8" = "-8";
+"-80" = "-80";
+"-85" = "-85";
+"-9" = "-9";
+"-90" = "-90";
+"-95" = "-95";
+"0" = "0";
+"1" = "1";
+"1 inch/sec." = "1 inch/sec.";
+"1.25x0.25\"" = "1.25x0.25\"";
+"1.25x2.25\"" = "1.25x2.25\"";
+"1.5 inch/sec." = "1.5 inch/sec.";
+"1.50x0.25\"" = "1.50x0.25\"";
+"1.50x0.50\"" = "1.50x0.50\"";
+"1.50x1.00\"" = "1.50x1.00\"";
+"1.50x2.00\"" = "1.50x2.00\"";
+"10" = "10";
+"10 inches/sec." = "10 inches/sec.";
+"10 x 11\"" = "10 x 11\"";
+"10 x 13\"" = "10 x 13\"";
+"10 x 14\"" = "10 x 14\"";
+"100" = "100";
+"100 mm/sec." = "100 mm/sec.";
+"105" = "105";
+"11" = "11";
+"11 inches/sec." = "11 inches/sec.";
+"110" = "110";
+"115" = "115";
+"12" = "12";
+"12 inches/sec." = "12 inches/sec.";
+"12 x 11\"" = "12 x 11\"";
+"120" = "120";
+"120 mm/sec." = "120 mm/sec.";
+"120x60dpi" = "120x60dpi";
+"120x72dpi" = "120x72dpi";
+"13" = "13";
+"136dpi" = "136dpi";
+"14" = "14";
+"15" = "15";
+"15 mm/sec." = "15 mm/sec.";
+"15 x 11\"" = "15 x 11\"";
+"150 mm/sec." = "150 mm/sec.";
+"150dpi" = "150dpi";
+"16" = "16";
+"17" = "17";
+"18" = "18";
+"180dpi" = "180dpi";
+"19" = "19";
+"2" = "2";
+"2 inches/sec." = "2 inches/sec.";
+"2-Sided Printing" = "2-Sided Printing";
+"2.00x0.37\"" = "2.00x0.37\"";
+"2.00x0.50\"" = "2.00x0.50\"";
+"2.00x1.00\"" = "2.00x1.00\"";
+"2.00x1.25\"" = "2.00x1.25\"";
+"2.00x2.00\"" = "2.00x2.00\"";
+"2.00x3.00\"" = "2.00x3.00\"";
+"2.00x4.00\"" = "2.00x4.00\"";
+"2.00x5.50\"" = "2.00x5.50\"";
+"2.25x0.50\"" = "2.25x0.50\"";
+"2.25x1.25\"" = "2.25x1.25\"";
+"2.25x4.00\"" = "2.25x4.00\"";
+"2.25x5.50\"" = "2.25x5.50\"";
+"2.38x5.50\"" = "2.38x5.50\"";
+"2.5 inches/sec." = "2.5 inches/sec.";
+"2.50x1.00\"" = "2.50x1.00\"";
+"2.50x2.00\"" = "2.50x2.00\"";
+"2.75x1.25\"" = "2.75x1.25\"";
+"2.9 x 1\"" = "2.9 x 1\"";
+"20" = "20";
+"20 mm/sec." = "20 mm/sec.";
+"200 mm/sec." = "200 mm/sec.";
+"203dpi" = "203dpi";
+"21" = "21";
+"22" = "22";
+"23" = "23";
+"24" = "24";
+"24-Pin Series" = "24-Pin Series";
+"240x72dpi" = "240x72dpi";
+"25" = "25";
+"250 mm/sec." = "250 mm/sec.";
+"26" = "26";
+"27" = "27";
+"28" = "28";
+"29" = "29";
+"3" = "3";
+"3 inches/sec." = "3 inches/sec.";
+"3.00x1.00\"" = "3.00x1.00\"";
+"3.00x1.25\"" = "3.00x1.25\"";
+"3.00x2.00\"" = "3.00x2.00\"";
+"3.00x3.00\"" = "3.00x3.00\"";
+"3.00x5.00\"" = "3.00x5.00\"";
+"3.25x2.00\"" = "3.25x2.00\"";
+"3.25x5.00\"" = "3.25x5.00\"";
+"3.25x5.50\"" = "3.25x5.50\"";
+"3.25x5.83\"" = "3.25x5.83\"";
+"3.25x7.83\"" = "3.25x7.83\"";
+"3.5\" Disk" = "3.5\" Disk";
+"3.5\" Disk - 2 1/8 x 2 3/4\"" = "3.5\" Disk - 2 1/8 x 2 3/4\"";
+"3.50x1.00\"" = "3.50x1.00\"";
+"30" = "30";
+"30 mm/sec." = "30 mm/sec.";
+"300 mm/sec." = "300 mm/sec.";
+"300dpi" = "300dpi";
+"35" = "35";
+"360dpi" = "360dpi";
+"360x180dpi" = "360x180dpi";
+"4" = "4";
+"4 inches/sec." = "4 inches/sec.";
+"4.00x1.00\"" = "4.00x1.00\"";
+"4.00x13.00\"" = "4.00x13.00\"";
+"4.00x2.00\"" = "4.00x2.00\"";
+"4.00x2.50\"" = "4.00x2.50\"";
+"4.00x3.00\"" = "4.00x3.00\"";
+"4.00x4.00\"" = "4.00x4.00\"";
+"4.00x5.00\"" = "4.00x5.00\"";
+"4.00x6.00\"" = "4.00x6.00\"";
+"4.00x6.50\"" = "4.00x6.50\"";
+"40" = "40";
+"40 mm/sec." = "40 mm/sec.";
+"45" = "45";
+"5" = "5";
+"5 inches/sec." = "5 inches/sec.";
+"50" = "50";
+"55" = "55";
+"6" = "6";
+"6 inches/sec." = "6 inches/sec.";
+"6.00x1.00\"" = "6.00x1.00\"";
+"6.00x2.00\"" = "6.00x2.00\"";
+"6.00x3.00\"" = "6.00x3.00\"";
+"6.00x4.00\"" = "6.00x4.00\"";
+"6.00x5.00\"" = "6.00x5.00\"";
+"6.00x6.00\"" = "6.00x6.00\"";
+"6.00x6.50\"" = "6.00x6.50\"";
+"60" = "60";
+"60 mm/sec." = "60 mm/sec.";
+"600dpi" = "600dpi";
+"60dpi" = "60dpi";
+"60x72dpi" = "60x72dpi";
+"65" = "65";
+"7" = "7";
+"7 inches/sec." = "7 inches/sec.";
+"7 x 9\"" = "7 x 9\"";
+"70" = "70";
+"720dpi" = "720dpi";
+"75" = "75";
+"8" = "8";
+"8 inches/sec." = "8 inches/sec.";
+"8 x 10\"" = "8 x 10\"";
+"8.00x1.00\"" = "8.00x1.00\"";
+"8.00x2.00\"" = "8.00x2.00\"";
+"8.00x3.00\"" = "8.00x3.00\"";
+"8.00x4.00\"" = "8.00x4.00\"";
+"8.00x5.00\"" = "8.00x5.00\"";
+"8.00x6.00\"" = "8.00x6.00\"";
+"8.00x6.50\"" = "8.00x6.50\"";
+"80" = "80";
+"80 mm/sec." = "80 mm/sec.";
+"85" = "85";
+"9" = "9";
+"9 inches/sec." = "9 inches/sec.";
+"9 x 11\"" = "9 x 11\"";
+"9 x 12\"" = "9 x 12\"";
+"9-Pin Series" = "9-Pin Series";
+"90" = "90";
+"95" = "95";
+"?Invalid help command unknown." = "?Invalid help command unknown.";
+"A Samba password is required to export printer drivers" = "A Samba password is required to export printer drivers";
+"A Samba username is required to export printer drivers" = "A Samba username is required to export printer drivers";
+"A class named \"%s\" already exists." = "A class named \"%s\" already exists.";
+"A printer named \"%s\" already exists." = "A printer named \"%s\" already exists.";
+"A0" = "A0";
+"A0 Long Edge" = "A0 Long Edge";
+"A1" = "A1";
+"A1 Long Edge" = "A1 Long Edge";
+"A10" = "A10";
+"A2" = "A2";
+"A2 Long Edge" = "A2 Long Edge";
+"A3" = "A3";
+"A3 Long Edge" = "A3 Long Edge";
+"A3 Oversize" = "A3 Oversize";
+"A3 Oversize Long Edge" = "A3 Oversize Long Edge";
+"A4" = "A4";
+"A4 Long Edge" = "A4 Long Edge";
+"A4 Oversize" = "A4 Oversize";
+"A4 Small" = "A4 Small";
+"A5" = "A5";
+"A5 Long Edge" = "A5 Long Edge";
+"A5 Oversize" = "A5 Oversize";
+"A6" = "A6";
+"A6 Long Edge" = "A6 Long Edge";
+"A7" = "A7";
+"A8" = "A8";
+"A9" = "A9";
+"ANSI A" = "ANSI A";
+"ANSI B" = "ANSI B";
+"ANSI C" = "ANSI C";
+"ANSI D" = "ANSI D";
+"ANSI E" = "ANSI E";
+"ARCH C" = "ARCH C";
+"ARCH C Long Edge" = "ARCH C Long Edge";
+"ARCH D" = "ARCH D";
+"ARCH D Long Edge" = "ARCH D Long Edge";
+"ARCH E" = "ARCH E";
+"ARCH E Long Edge" = "ARCH E Long Edge";
+"Accept Jobs" = "Accept Jobs";
+"Accepted" = "Accepted";
+"Add Class" = "Add Class";
+"Add Printer" = "Add Printer";
+"Add RSS Subscription" = "Add RSS Subscription";
+"Address" = "Address";
+"Address - 1 1/8 x 3 1/2\"" = "Address - 1 1/8 x 3 1/2\"";
+"Administration" = "Administration";
+"Always" = "Always";
+"AppSocket/HP JetDirect" = "AppSocket/HP JetDirect";
+"Applicator" = "Applicator";
+"Attempt to set %s printer-state to bad value %d." = "Attempt to set %s printer-state to bad value %d.";
+"Attribute groups are out of order (%x < %x)." = "Attribute groups are out of order (%x < %x).";
+"B0" = "B0";
+"B1" = "B1";
+"B10" = "B10";
+"B2" = "B2";
+"B3" = "B3";
+"B4" = "B4";
+"B5" = "B5";
+"B5 Oversize" = "B5 Oversize";
+"B6" = "B6";
+"B7" = "B7";
+"B8" = "B8";
+"B9" = "B9";
+"Bad NULL dests pointer" = "Bad NULL dests pointer";
+"Bad OpenGroup" = "Bad OpenGroup";
+"Bad OpenUI/JCLOpenUI" = "Bad OpenUI/JCLOpenUI";
+"Bad OrderDependency" = "Bad OrderDependency";
+"Bad PPD cache file." = "Bad PPD cache file.";
+"Bad Request" = "Bad Request";
+"Bad SNMP version number" = "Bad SNMP version number";
+"Bad UIConstraints" = "Bad UIConstraints";
+"Bad charset file \"%s\"." = "Bad charset file \"%s\".";
+"Bad charset type: %s" = "Bad charset type: %s";
+"Bad columns value %d." = "Bad columns value %d.";
+"Bad copies value %d." = "Bad copies value %d.";
+"Bad cpi value %f." = "Bad cpi value %f.";
+"Bad custom parameter" = "Bad custom parameter";
+"Bad device-uri \"%s\"." = "Bad device-uri \"%s\".";
+"Bad device-uri scheme \"%s\"." = "Bad device-uri scheme \"%s\".";
+"Bad document-format \"%s\"." = "Bad document-format \"%s\".";
+"Bad document-format-default \"%s\"." = "Bad document-format-default \"%s\".";
+"Bad filename buffer" = "Bad filename buffer";
+"Bad font description line \"%s\"." = "Bad font description line \"%s\".";
+"Bad font description line: %s" = "Bad font description line: %s";
+"Bad job-priority value." = "Bad job-priority value.";
+"Bad job-sheets value \"%s\"." = "Bad job-sheets value \"%s\".";
+"Bad job-sheets value type." = "Bad job-sheets value type.";
+"Bad job-state value." = "Bad job-state value.";
+"Bad job-uri \"%s\"." = "Bad job-uri \"%s\".";
+"Bad lpi value %f." = "Bad lpi value %f.";
+"Bad notify-pull-method \"%s\"." = "Bad notify-pull-method \"%s\".";
+"Bad notify-recipient-uri \"%s\"." = "Bad notify-recipient-uri \"%s\".";
+"Bad number-up value %d." = "Bad number-up value %d.";
+"Bad option + choice on line %d." = "Bad option + choice on line %d.";
+"Bad page-ranges values %d-%d." = "Bad page-ranges values %d-%d.";
+"Bad port-monitor \"%s\"." = "Bad port-monitor \"%s\".";
+"Bad printer-state value %d." = "Bad printer-state value %d.";
+"Bad request ID %d." = "Bad request ID %d.";
+"Bad request version number %d.%d." = "Bad request version number %d.%d.";
+"Bad subscription ID" = "Bad subscription ID";
+"Bad text direction \"%s\"." = "Bad text direction \"%s\".";
+"Bad text direction: %s" = "Bad text direction: %s";
+"Bad text width \"%s\"." = "Bad text width \"%s\".";
+"Bad text width: %s" = "Bad text width: %s";
+"Bad value string" = "Bad value string";
+"Banners" = "Banners";
+"Billing Information: " = "Billing Information: ";
+"Bond Paper" = "Bond Paper";
+"Boolean expected for waiteof option \"%s\"." = "Boolean expected for waiteof option \"%s\".";
+"Buffer overflow detected, aborting." = "Buffer overflow detected, aborting.";
+"CMYK" = "CMYK";
+"CPCL Label Printer" = "CPCL Label Printer";
+"Cancel RSS Subscription" = "Cancel RSS Subscription";
+"Canceling print job." = "Canceling print job.";
+"Cannot share a remote Kerberized printer." = "Cannot share a remote Kerberized printer.";
+"Cassette" = "Cassette";
+"Change Settings" = "Change Settings";
+"Character set \"%s\" not supported." = "Character set \"%s\" not supported.";
+"Classes" = "Classes";
+"Clean Print Heads" = "Clean Print Heads";
+"Close-Job doesn't support the job-uri attribute." = "Close-Job doesn't support the job-uri attribute.";
+"Color" = "Color";
+"Color Mode" = "Color Mode";
+"Commands may be abbreviated. Commands are:\n\nexit help quit status ?" = "Commands may be abbreviated. Commands are:\n\nexit help quit status ?";
+"Community name uses indefinite length" = "Community name uses indefinite length";
+"Connected to printer." = "Connected to printer.";
+"Connecting to printer." = "Connecting to printer.";
+"Continue" = "Continue";
+"Continuous" = "Continuous";
+"Control file sent successfully." = "Control file sent successfully.";
+"Copying print data." = "Copying print data.";
+"Created" = "Created";
+"Created On: " = "Created On: ";
+"Custom" = "Custom";
+"CustominCutInterval" = "CustominCutInterval";
+"CustominTearInterval" = "CustominTearInterval";
+"Cut" = "Cut";
+"Cutter" = "Cutter";
+"Dark" = "Dark";
+"Darkness" = "Darkness";
+"Data file sent successfully." = "Data file sent successfully.";
+"Delete Class" = "Delete Class";
+"Delete Printer" = "Delete Printer";
+"Description: " = "Description: ";
+"DeskJet Series" = "DeskJet Series";
+"Destination \"%s\" is not accepting jobs." = "Destination \"%s\" is not accepting jobs.";
+"Device: uri = %s\n class = %s\n info = %s\n make-and-model = %s\n device-id = %s\n location = %s" = "Device: uri = %s\n class = %s\n info = %s\n make-and-model = %s\n device-id = %s\n location = %s";
+"Direct Thermal Media" = "Direct Thermal Media";
+"Directory \"%s\" has insecure permissions (0%o/uid=%d/gid=%d)." = "Directory \"%s\" has insecure permissions (0%o/uid=%d/gid=%d).";
+"Directory \"%s\" is a file." = "Directory \"%s\" is a file.";
+"Directory \"%s\" not available: %s" = "Directory \"%s\" not available: %s";
+"Directory \"%s\" permissions OK (0%o/uid=%d/gid=%d)." = "Directory \"%s\" permissions OK (0%o/uid=%d/gid=%d).";
+"Disabled" = "Disabled";
+"Document #%d does not exist in job #%d." = "Document #%d does not exist in job #%d.";
+"Driver Name: " = "Driver Name: ";
+"Driver Version: " = "Driver Version: ";
+"Duplexer" = "Duplexer";
+"Dymo" = "Dymo";
+"EPL1 Label Printer" = "EPL1 Label Printer";
+"EPL2 Label Printer" = "EPL2 Label Printer";
+"Edit Configuration File" = "Edit Configuration File";
+"Empty PPD file." = "Empty PPD file.";
+// TRANSLATORS: Banner/cover sheet after the print job.
+"Ending Banner" = "Ending Banner";
+"English" = "English";
+"Enter old password:" = "Enter old password:";
+"Enter password again:" = "Enter password again:";
+"Enter password:" = "Enter password:";
+"Enter your username and password or the root username and password to access this page. If you are using Kerberos authentication, make sure you have a valid Kerberos ticket." = "Enter your username and password or the root username and password to access this page. If you are using Kerberos authentication, make sure you have a valid Kerberos ticket.";
+"Envelope #10 " = "Envelope #10 ";
+"Envelope #11" = "Envelope #11";
+"Envelope #12" = "Envelope #12";
+"Envelope #14" = "Envelope #14";
+"Envelope #9" = "Envelope #9";
+"Envelope B4" = "Envelope B4";
+"Envelope B5" = "Envelope B5";
+"Envelope B6" = "Envelope B6";
+"Envelope C0" = "Envelope C0";
+"Envelope C1" = "Envelope C1";
+"Envelope C2" = "Envelope C2";
+"Envelope C3" = "Envelope C3";
+"Envelope C4" = "Envelope C4";
+"Envelope C5" = "Envelope C5";
+"Envelope C6" = "Envelope C6";
+"Envelope C65" = "Envelope C65";
+"Envelope C7" = "Envelope C7";
+"Envelope Choukei 3" = "Envelope Choukei 3";
+"Envelope Choukei 3 Long Edge" = "Envelope Choukei 3 Long Edge";
+"Envelope Choukei 4" = "Envelope Choukei 4";
+"Envelope Choukei 4 Long Edge" = "Envelope Choukei 4 Long Edge";
+"Envelope DL" = "Envelope DL";
+"Envelope Feed" = "Envelope Feed";
+"Envelope Invite" = "Envelope Invite";
+"Envelope Italian" = "Envelope Italian";
+"Envelope Kaku2" = "Envelope Kaku2";
+"Envelope Kaku2 Long Edge" = "Envelope Kaku2 Long Edge";
+"Envelope Kaku3" = "Envelope Kaku3";
+"Envelope Kaku3 Long Edge" = "Envelope Kaku3 Long Edge";
+"Envelope Monarch" = "Envelope Monarch";
+"Envelope PRC1 " = "Envelope PRC1 ";
+"Envelope PRC1 Long Edge" = "Envelope PRC1 Long Edge";
+"Envelope PRC10" = "Envelope PRC10";
+"Envelope PRC10 Long Edge" = "Envelope PRC10 Long Edge";
+"Envelope PRC2" = "Envelope PRC2";
+"Envelope PRC2 Long Edge" = "Envelope PRC2 Long Edge";
+"Envelope PRC3" = "Envelope PRC3";
+"Envelope PRC3 Long Edge" = "Envelope PRC3 Long Edge";
+"Envelope PRC4" = "Envelope PRC4";
+"Envelope PRC4 Long Edge" = "Envelope PRC4 Long Edge";
+"Envelope PRC5 Long Edge" = "Envelope PRC5 Long Edge";
+"Envelope PRC5PRC5" = "Envelope PRC5PRC5";
+"Envelope PRC6" = "Envelope PRC6";
+"Envelope PRC6 Long Edge" = "Envelope PRC6 Long Edge";
+"Envelope PRC7" = "Envelope PRC7";
+"Envelope PRC7 Long Edge" = "Envelope PRC7 Long Edge";
+"Envelope PRC8" = "Envelope PRC8";
+"Envelope PRC8 Long Edge" = "Envelope PRC8 Long Edge";
+"Envelope PRC9" = "Envelope PRC9";
+"Envelope PRC9 Long Edge" = "Envelope PRC9 Long Edge";
+"Envelope Personal" = "Envelope Personal";
+"Envelope You4" = "Envelope You4";
+"Envelope You4 Long Edge" = "Envelope You4 Long Edge";
+"Epson" = "Epson";
+"Error Policy" = "Error Policy";
+"Error sending raster data." = "Error sending raster data.";
+"Error: need hostname after \"-h\" option." = "Error: need hostname after \"-h\" option.";
+"Every 10 Labels" = "Every 10 Labels";
+"Every 2 Labels" = "Every 2 Labels";
+"Every 3 Labels" = "Every 3 Labels";
+"Every 4 Labels" = "Every 4 Labels";
+"Every 5 Labels" = "Every 5 Labels";
+"Every 6 Labels" = "Every 6 Labels";
+"Every 7 Labels" = "Every 7 Labels";
+"Every 8 Labels" = "Every 8 Labels";
+"Every 9 Labels" = "Every 9 Labels";
+"Every Label" = "Every Label";
+"Executive" = "Executive";
+"Expectation Failed" = "Expectation Failed";
+"Export Printers to Samba" = "Export Printers to Samba";
+"FAIL" = "FAIL";
+"FanFold German" = "FanFold German";
+"FanFold Legal German" = "FanFold Legal German";
+"Fanfold US" = "Fanfold US";
+"File \"%s\" has insecure permissions (0%o/uid=%d/gid=%d)." = "File \"%s\" has insecure permissions (0%o/uid=%d/gid=%d).";
+"File \"%s\" is a directory." = "File \"%s\" is a directory.";
+"File \"%s\" not available: %s" = "File \"%s\" not available: %s";
+"File \"%s\" permissions OK (0%o/uid=%d/gid=%d)." = "File \"%s\" permissions OK (0%o/uid=%d/gid=%d).";
+"File Folder" = "File Folder";
+"File Folder - 9/16 x 3 7/16\"" = "File Folder - 9/16 x 3 7/16\"";
+"File device URIs have been disabled. To enable, see the FileDevice directive in \"%s/cupsd.conf\"." = "File device URIs have been disabled. To enable, see the FileDevice directive in \"%s/cupsd.conf\".";
+"Finished page %d." = "Finished page %d.";
+"Folio" = "Folio";
+"Forbidden" = "Forbidden";
+"Formatting page %d." = "Formatting page %d.";
+"General" = "General";
+"Generic" = "Generic";
+"Get-Response-PDU uses indefinite length" = "Get-Response-PDU uses indefinite length";
+"Glossy Paper" = "Glossy Paper";
+"Got a printer-uri attribute but no job-id." = "Got a printer-uri attribute but no job-id.";
+"Grayscale" = "Grayscale";
+"HP" = "HP";
+"Hanging Folder" = "Hanging Folder";
+"Hanging Folder - 9/16 x 2\"" = "Hanging Folder - 9/16 x 2\"";
+"ISOLatin1" = "ISOLatin1";
+"Illegal control character" = "Illegal control character";
+"Illegal main keyword string" = "Illegal main keyword string";
+"Illegal option keyword string" = "Illegal option keyword string";
+"Illegal translation string" = "Illegal translation string";
+"Illegal whitespace character" = "Illegal whitespace character";
+"Installable Options" = "Installable Options";
+"Installed" = "Installed";
+"IntelliBar Label Printer" = "IntelliBar Label Printer";
+"Intellitech" = "Intellitech";
+"Internal Server Error" = "Internal Server Error";
+"Internal error" = "Internal error";
+"Internet Postage 2-Part" = "Internet Postage 2-Part";
+"Internet Postage 2-Part - 2 1/4 x 7 1/2\"" = "Internet Postage 2-Part - 2 1/4 x 7 1/2\"";
+"Internet Postage 3-Part" = "Internet Postage 3-Part";
+"Internet Postage 3-Part - 2 1/4 x 7\"" = "Internet Postage 3-Part - 2 1/4 x 7\"";
+"Internet Printing Protocol" = "Internet Printing Protocol";
+"JCL" = "JCL";
+"JIS B0" = "JIS B0";
+"JIS B1" = "JIS B1";
+"JIS B10" = "JIS B10";
+"JIS B2" = "JIS B2";
+"JIS B3" = "JIS B3";
+"JIS B4" = "JIS B4";
+"JIS B4 Long Edge" = "JIS B4 Long Edge";
+"JIS B5" = "JIS B5";
+"JIS B5 Long Edge" = "JIS B5 Long Edge";
+"JIS B6" = "JIS B6";
+"JIS B6 Long Edge" = "JIS B6 Long Edge";
+"JIS B7" = "JIS B7";
+"JIS B8" = "JIS B8";
+"JIS B9" = "JIS B9";
+"Job #%d cannot be restarted - no files." = "Job #%d cannot be restarted - no files.";
+"Job #%d does not exist." = "Job #%d does not exist.";
+"Job #%d is already aborted - can't cancel." = "Job #%d is already aborted - can't cancel.";
+"Job #%d is already canceled - can't cancel." = "Job #%d is already canceled - can't cancel.";
+"Job #%d is already completed - can't cancel." = "Job #%d is already completed - can't cancel.";
+"Job #%d is finished and cannot be altered." = "Job #%d is finished and cannot be altered.";
+"Job #%d is not complete." = "Job #%d is not complete.";
+"Job #%d is not held for authentication." = "Job #%d is not held for authentication.";
+"Job #%d is not held." = "Job #%d is not held.";
+"Job Completed" = "Job Completed";
+"Job Created" = "Job Created";
+"Job ID: " = "Job ID: ";
+"Job Options Changed" = "Job Options Changed";
+"Job Stopped" = "Job Stopped";
+"Job UUID: " = "Job UUID: ";
+"Job is completed and cannot be changed." = "Job is completed and cannot be changed.";
+"Job operation failed:" = "Job operation failed:";
+"Job state cannot be changed." = "Job state cannot be changed.";
+"Job subscriptions cannot be renewed." = "Job subscriptions cannot be renewed.";
+"Jobs" = "Jobs";
+"LPD/LPR Host or Printer" = "LPD/LPR Host or Printer";
+"Label Printer" = "Label Printer";
+"Label Top" = "Label Top";
+"Language \"%s\" not supported." = "Language \"%s\" not supported.";
+"Large Address" = "Large Address";
+"Large Address - 1 4/10 x 3 1/2\"" = "Large Address - 1 4/10 x 3 1/2\"";
+"LaserJet Series PCL 4/5" = "LaserJet Series PCL 4/5";
+"Letter Oversize" = "Letter Oversize";
+"Letter Oversize Long Edge" = "Letter Oversize Long Edge";
+"Light" = "Light";
+"Line longer than the maximum allowed (255 characters)" = "Line longer than the maximum allowed (255 characters)";
+"List Available Printers" = "List Available Printers";
+"Loading print file." = "Loading print file.";
+"Location: " = "Location: ";
+"Long-Edge (Portrait)" = "Long-Edge (Portrait)";
+"Looking for printer." = "Looking for printer.";
+"Make and Model: " = "Make and Model: ";
+"Manual Feed" = "Manual Feed";
+"Media Dimensions: " = "Media Dimensions: ";
+"Media Limits: " = "Media Limits: ";
+"Media Name: " = "Media Name: ";
+"Media Size" = "Media Size";
+"Media Source" = "Media Source";
+"Media Tracking" = "Media Tracking";
+"Media Type" = "Media Type";
+"Medium" = "Medium";
+"Memory allocation error" = "Memory allocation error";
+"Missing CloseGroup" = "Missing CloseGroup";
+"Missing PPD-Adobe-4.x header" = "Missing PPD-Adobe-4.x header";
+"Missing asterisk in column 1" = "Missing asterisk in column 1";
+"Missing document-number attribute." = "Missing document-number attribute.";
+"Missing double quote on line %d." = "Missing double quote on line %d.";
+"Missing form variable" = "Missing form variable";
+"Missing media or media-col." = "Missing media or media-col.";
+"Missing media-size in media-col." = "Missing media-size in media-col.";
+"Missing notify-subscription-ids attribute." = "Missing notify-subscription-ids attribute.";
+"Missing option keyword" = "Missing option keyword";
+"Missing requesting-user-name attribute." = "Missing requesting-user-name attribute.";
+"Missing required attributes." = "Missing required attributes.";
+"Missing value on line %d of banner file." = "Missing value on line %d of banner file.";
+"Missing value on line %d." = "Missing value on line %d.";
+"Missing value string" = "Missing value string";
+"Missing x-dimension in media-size." = "Missing x-dimension in media-size.";
+"Missing y-dimension in media-size." = "Missing y-dimension in media-size.";
+"Model: name = %s\n natural_language = %s\n make-and-model = %s\n device-id = %s" = "Model: name = %s\n natural_language = %s\n make-and-model = %s\n device-id = %s";
+"Modify Class" = "Modify Class";
+"Modify Printer" = "Modify Printer";
+"Move All Jobs" = "Move All Jobs";
+"Move Job" = "Move Job";
+"Moved Permanently" = "Moved Permanently";
+"NULL PPD file pointer" = "NULL PPD file pointer";
+"Name OID uses indefinite length" = "Name OID uses indefinite length";
+"Nested classes are not allowed." = "Nested classes are not allowed.";
+"Never" = "Never";
+"New Stylus Color Series" = "New Stylus Color Series";
+"New Stylus Photo Series" = "New Stylus Photo Series";
+"No" = "No";
+"No Content" = "No Content";
+"No PPD name" = "No PPD name";
+"No VarBind SEQUENCE" = "No VarBind SEQUENCE";
+"No Windows printer drivers are installed." = "No Windows printer drivers are installed.";
+"No active connection" = "No active connection";
+"No active jobs on %s." = "No active jobs on %s.";
+"No attributes in request." = "No attributes in request.";
+"No authentication information provided." = "No authentication information provided.";
+"No community name" = "No community name";
+"No default printer." = "No default printer.";
+"No destinations added." = "No destinations added.";
+"No device URI found in argv[0] or in DEVICE_URI environment variable." = "No device URI found in argv[0] or in DEVICE_URI environment variable.";
+"No error-index" = "No error-index";
+"No error-status" = "No error-status";
+"No file in print request." = "No file in print request.";
+"No fonts in charset file." = "No fonts in charset file.";
+"No modification time" = "No modification time";
+"No name OID" = "No name OID";
+"No pages were found." = "No pages were found.";
+"No printer name" = "No printer name";
+"No printer-uri found" = "No printer-uri found";
+"No printer-uri found for class" = "No printer-uri found for class";
+"No printer-uri in request." = "No printer-uri in request.";
+"No request-id" = "No request-id";
+"No subscription attributes in request." = "No subscription attributes in request.";
+"No subscriptions found." = "No subscriptions found.";
+"No variable-bindings SEQUENCE" = "No variable-bindings SEQUENCE";
+"No version number" = "No version number";
+"Non-continuous (Mark sensing)" = "Non-continuous (Mark sensing)";
+"Non-continuous (Web sensing)" = "Non-continuous (Web sensing)";
+"Normal" = "Normal";
+"Not Found" = "Not Found";
+"Not Implemented" = "Not Implemented";
+"Not Installed" = "Not Installed";
+"Not Modified" = "Not Modified";
+"Not Supported" = "Not Supported";
+"Not allowed to print." = "Not allowed to print.";
+"Note" = "Note";
+"Note: this program only validates the DSC comments, not the PostScript itself." = "Note: this program only validates the DSC comments, not the PostScript itself.";
+"OK" = "OK";
+"Off (1-Sided)" = "Off (1-Sided)";
+"Oki" = "Oki";
+"Online Help" = "Online Help";
+"Open of %s failed: %s" = "Open of %s failed: %s";
+"OpenGroup without a CloseGroup first" = "OpenGroup without a CloseGroup first";
+"OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first" = "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first";
+"Operation Policy" = "Operation Policy";
+"Option \"%s\" cannot be included via %%%%IncludeFeature." = "Option \"%s\" cannot be included via %%%%IncludeFeature.";
+"Options Installed" = "Options Installed";
+"Options:" = "Options:";
+"Options: " = "Options: ";
+"Out of date PPD cache file." = "Out of date PPD cache file.";
+"Out of memory." = "Out of memory.";
+"Output Mode" = "Output Mode";
+"Output for printer %s is sent to %s" = "Output for printer %s is sent to %s";
+"Output for printer %s is sent to remote printer %s on %s" = "Output for printer %s is sent to remote printer %s on %s";
+"Output for printer %s/%s is sent to %s" = "Output for printer %s/%s is sent to %s";
+"Output for printer %s/%s is sent to remote printer %s on %s" = "Output for printer %s/%s is sent to remote printer %s on %s";
+"PASS" = "PASS";
+"PCL Laser Printer" = "PCL Laser Printer";
+"PRC16K" = "PRC16K";
+"PRC16K Long Edge" = "PRC16K Long Edge";
+"PRC32K" = "PRC32K";
+"PRC32K Long Edge" = "PRC32K Long Edge";
+"PRC32K Oversize" = "PRC32K Oversize";
+"PRC32K Oversize Long Edge" = "PRC32K Oversize Long Edge";
+"Packet does not contain a Get-Response-PDU" = "Packet does not contain a Get-Response-PDU";
+"Packet does not start with SEQUENCE" = "Packet does not start with SEQUENCE";
+"ParamCustominCutInterval" = "ParamCustominCutInterval";
+"ParamCustominTearInterval" = "ParamCustominTearInterval";
+"Password for %s on %s? " = "Password for %s on %s? ";
+"Password for %s required to access %s via SAMBA: " = "Password for %s required to access %s via SAMBA: ";
+"Pause Class" = "Pause Class";
+"Pause Printer" = "Pause Printer";
+"Peel-Off" = "Peel-Off";
+"Photo" = "Photo";
+"Photo Labels" = "Photo Labels";
+"Plain Paper" = "Plain Paper";
+"Policies" = "Policies";
+"Port Monitor" = "Port Monitor";
+"PostScript Printer" = "PostScript Printer";
+"Postcard" = "Postcard";
+"Postcard Double " = "Postcard Double ";
+"Postcard Double Long Edge" = "Postcard Double Long Edge";
+"Postcard Long Edge" = "Postcard Long Edge";
+"Print Density" = "Print Density";
+"Print Job:" = "Print Job:";
+"Print Mode" = "Print Mode";
+"Print Rate" = "Print Rate";
+"Print Self-Test Page" = "Print Self-Test Page";
+"Print Speed" = "Print Speed";
+"Print Test Page" = "Print Test Page";
+"Print and Cut" = "Print and Cut";
+"Print and Tear" = "Print and Tear";
+"Print file accepted - job ID %d." = "Print file accepted - job ID %d.";
+"Print file accepted - job ID unknown." = "Print file accepted - job ID unknown.";
+"Print file sent." = "Print file sent.";
+"Print file was not accepted." = "Print file was not accepted.";
+"Printed For: " = "Printed For: ";
+"Printed From: " = "Printed From: ";
+"Printed On: " = "Printed On: ";
+"Printer Added" = "Printer Added";
+"Printer Default" = "Printer Default";
+"Printer Deleted" = "Printer Deleted";
+"Printer Modified" = "Printer Modified";
+"Printer Name: " = "Printer Name: ";
+"Printer Paused" = "Printer Paused";
+"Printer Settings" = "Printer Settings";
+"Printer busy, will retry in 10 seconds." = "Printer busy, will retry in 10 seconds.";
+"Printer busy; will retry in 30 seconds." = "Printer busy; will retry in 30 seconds.";
+"Printer did not respond after %d seconds." = "Printer did not respond after %d seconds.";
+"Printer does not support IPP/%d.%d, trying IPP/%s." = "Printer does not support IPP/%d.%d, trying IPP/%s.";
+"Printer is busy, will retry in 5 seconds." = "Printer is busy, will retry in 5 seconds.";
+"Printer is not currently connected." = "Printer is not currently connected.";
+"Printer is now connected." = "Printer is now connected.";
+"Printer is now online." = "Printer is now online.";
+"Printer is offline." = "Printer is offline.";
+"Printer not connected, will retry in 30 seconds." = "Printer not connected, will retry in 30 seconds.";
+"Printer not connected; will retry in 30 seconds." = "Printer not connected; will retry in 30 seconds.";
+"Printer:" = "Printer:";
+"Printers" = "Printers";
+"Printing page %d, %d%% complete." = "Printing page %d, %d%% complete.";
+"Printing page %d." = "Printing page %d.";
+"Purge Jobs" = "Purge Jobs";
+"Quarto" = "Quarto";
+"Quota limit reached." = "Quota limit reached.";
+"Rank Owner Job File(s) Total Size" = "Rank Owner Job File(s) Total Size";
+// TRANSLATORS: Pri is job priority.
+"Rank Owner Pri Job Files Total Size" = "Rank Owner Pri Job Files Total Size";
+"Ready to print." = "Ready to print.";
+"Reject Jobs" = "Reject Jobs";
+"Remote host did not accept control file (%d)." = "Remote host did not accept control file (%d).";
+"Remote host did not accept data file (%d)." = "Remote host did not accept data file (%d).";
+"Reprint After Error" = "Reprint After Error";
+"Request Entity Too Large" = "Request Entity Too Large";
+"Resolution" = "Resolution";
+"Resume Class" = "Resume Class";
+"Resume Printer" = "Resume Printer";
+"Return Address" = "Return Address";
+"Return Address - 3/4 x 2\"" = "Return Address - 3/4 x 2\"";
+"Rewind" = "Rewind";
+"Running command: %s %s -N -A %s -c '%s'" = "Running command: %s %s -N -A %s -c '%s'";
+"SEQUENCE uses indefinite length" = "SEQUENCE uses indefinite length";
+"SSL/TLS Negotiation Error" = "SSL/TLS Negotiation Error";
+"See Other" = "See Other";
+"Sending data to printer." = "Sending data to printer.";
+"Serial Port #%d" = "Serial Port #%d";
+"Server Restarted" = "Server Restarted";
+"Server Security Auditing" = "Server Security Auditing";
+"Server Started" = "Server Started";
+"Server Stopped" = "Server Stopped";
+"Service Unavailable" = "Service Unavailable";
+"Set Allowed Users" = "Set Allowed Users";
+"Set As Server Default" = "Set As Server Default";
+"Set Class Options" = "Set Class Options";
+"Set Printer Options" = "Set Printer Options";
+"Set Publishing" = "Set Publishing";
+"Shipping Address" = "Shipping Address";
+"Shipping Address - 2 5/16 x 4\"" = "Shipping Address - 2 5/16 x 4\"";
+"Short-Edge (Landscape)" = "Short-Edge (Landscape)";
+"Special Paper" = "Special Paper";
+"Spooling job, %.0f%% complete." = "Spooling job, %.0f%% complete.";
+"Standard" = "Standard";
+// TRANSLATORS: Banner/cover sheet before the print job.
+"Starting Banner" = "Starting Banner";
+"Starting page %d." = "Starting page %d.";
+"Statement" = "Statement";
+"Stylus Color Series" = "Stylus Color Series";
+"Stylus Photo Series" = "Stylus Photo Series";
+"Subscription #%d does not exist." = "Subscription #%d does not exist.";
+"Super A" = "Super A";
+"Super B" = "Super B";
+"Super B/A3" = "Super B/A3";
+"Switching Protocols" = "Switching Protocols";
+"Tabloid" = "Tabloid";
+"Tabloid Oversize" = "Tabloid Oversize";
+"Tabloid Oversize Long Edge" = "Tabloid Oversize Long Edge";
+"Tear" = "Tear";
+"Tear-Off" = "Tear-Off";
+"Tear-Off Adjust Position" = "Tear-Off Adjust Position";
+"The %s attribute cannot be provided with job-ids." = "The %s attribute cannot be provided with job-ids.";
+"The PPD file \"%s\" could not be found." = "The PPD file \"%s\" could not be found.";
+"The PPD file \"%s\" could not be opened: %s" = "The PPD file \"%s\" could not be opened: %s";
+"The PPD file could not be opened." = "The PPD file could not be opened.";
+"The class name may only contain up to 127 printable characters and may not contain spaces, slashes (/), or the pound sign (#)." = "The class name may only contain up to 127 printable characters and may not contain spaces, slashes (/), or the pound sign (#).";
+"The developer unit needs to be replaced." = "The developer unit needs to be replaced.";
+"The developer unit will need to be replaced soon." = "The developer unit will need to be replaced soon.";
+"The fuser's temperature is high." = "The fuser's temperature is high.";
+"The fuser's temperature is low." = "The fuser's temperature is low.";
+"The notify-lease-duration attribute cannot be used with job subscriptions." = "The notify-lease-duration attribute cannot be used with job subscriptions.";
+"The notify-user-data value is too large (%d > 63 octets)." = "The notify-user-data value is too large (%d > 63 octets).";
+"The optical photoconductor needs to be replaced." = "The optical photoconductor needs to be replaced.";
+"The optical photoconductor will need to be replaced soon." = "The optical photoconductor will need to be replaced soon.";
+"The output bin is almost full." = "The output bin is almost full.";
+"The output bin is full." = "The output bin is full.";
+"The output bin is missing." = "The output bin is missing.";
+"The page setup information was not valid." = "The page setup information was not valid.";
+"The paper tray is almost empty." = "The paper tray is almost empty.";
+"The paper tray is empty." = "The paper tray is empty.";
+"The paper tray is missing." = "The paper tray is missing.";
+"The paper tray needs to be filled." = "The paper tray needs to be filled.";
+"The print file could not be opened." = "The print file could not be opened.";
+"The printer URI is incorrect or no longer exists." = "The printer URI is incorrect or no longer exists.";
+"The printer is almost out of ink." = "The printer is almost out of ink.";
+"The printer is busy." = "The printer is busy.";
+"The printer is low on toner." = "The printer is low on toner.";
+"The printer is not connected." = "The printer is not connected.";
+"The printer is not responding." = "The printer is not responding.";
+"The printer is out of ink." = "The printer is out of ink.";
+"The printer is out of toner." = "The printer is out of toner.";
+"The printer is unreachable at this time." = "The printer is unreachable at this time.";
+"The printer may not exist or is unavailable at this time." = "The printer may not exist or is unavailable at this time.";
+"The printer name may only contain up to 127 printable characters and may not contain spaces, slashes (/), or the pound sign (#)." = "The printer name may only contain up to 127 printable characters and may not contain spaces, slashes (/), or the pound sign (#).";
+"The printer or class does not exist." = "The printer or class does not exist.";
+"The printer or class is not shared." = "The printer or class is not shared.";
+"The printer's cover is open." = "The printer's cover is open.";
+"The printer's door is open." = "The printer's door is open.";
+"The printer's interlock is open." = "The printer's interlock is open.";
+"The printer's waste bin is almost full." = "The printer's waste bin is almost full.";
+"The printer's waste bin is full." = "The printer's waste bin is full.";
+"The printer-uri \"%s\" contains invalid characters." = "The printer-uri \"%s\" contains invalid characters.";
+"The printer-uri attribute is required." = "The printer-uri attribute is required.";
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"." = "The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\".";
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"." = "The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\".";
+"The subscription name may not contain spaces, slashes (/), question marks (?), or the pound sign (#)." = "The subscription name may not contain spaces, slashes (/), question marks (?), or the pound sign (#).";
+"The web interface is currently disabled. Run \"cupsctl WebInterface=yes\" to enable it." = "The web interface is currently disabled. Run \"cupsctl WebInterface=yes\" to enable it.";
+"The which-jobs value \"%s\" is not supported." = "The which-jobs value \"%s\" is not supported.";
+"There are too many subscriptions." = "There are too many subscriptions.";
+"There is a paper jam." = "There is a paper jam.";
+"There was an unrecoverable USB error." = "There was an unrecoverable USB error.";
+"Thermal Transfer Media" = "Thermal Transfer Media";
+"Title: " = "Title: ";
+"Too many active jobs." = "Too many active jobs.";
+"Too many job-sheets values (%d > 2)." = "Too many job-sheets values (%d > 2).";
+"Too many printer-state-reasons values (%d > %d)." = "Too many printer-state-reasons values (%d > %d).";
+"Transparency" = "Transparency";
+"Tray" = "Tray";
+"Tray 1" = "Tray 1";
+"Tray 2" = "Tray 2";
+"Tray 3" = "Tray 3";
+"Tray 4" = "Tray 4";
+"URI Too Long" = "URI Too Long";
+"US Ledger" = "US Ledger";
+"US Legal" = "US Legal";
+"US Legal Oversize" = "US Legal Oversize";
+"US Letter" = "US Letter";
+"US Letter Long Edge" = "US Letter Long Edge";
+"US Letter Oversize" = "US Letter Oversize";
+"US Letter Oversize Long Edge" = "US Letter Oversize Long Edge";
+"US Letter Small" = "US Letter Small";
+"USB Serial Port #%d" = "USB Serial Port #%d";
+"Unable to access cupsd.conf file:" = "Unable to access cupsd.conf file:";
+"Unable to add RSS subscription:" = "Unable to add RSS subscription:";
+"Unable to add class:" = "Unable to add class:";
+"Unable to add document to print job." = "Unable to add document to print job.";
+"Unable to add job for destination \"%s\"." = "Unable to add job for destination \"%s\".";
+"Unable to add printer:" = "Unable to add printer:";
+"Unable to allocate memory for file types." = "Unable to allocate memory for file types.";
+"Unable to allocate memory for page info" = "Unable to allocate memory for page info";
+"Unable to allocate memory for pages array" = "Unable to allocate memory for pages array";
+"Unable to cancel RSS subscription:" = "Unable to cancel RSS subscription:";
+"Unable to cancel print job." = "Unable to cancel print job.";
+"Unable to change printer-is-shared attribute:" = "Unable to change printer-is-shared attribute:";
+"Unable to change printer:" = "Unable to change printer:";
+"Unable to change server settings:" = "Unable to change server settings:";
+"Unable to connect to host." = "Unable to connect to host.";
+"Unable to connect to server" = "Unable to connect to server";
+"Unable to contact printer, queuing on next printer in class." = "Unable to contact printer, queuing on next printer in class.";
+"Unable to copy 64-bit CUPS printer driver files (%d)." = "Unable to copy 64-bit CUPS printer driver files (%d).";
+"Unable to copy 64-bit Windows printer driver files (%d)." = "Unable to copy 64-bit Windows printer driver files (%d).";
+"Unable to copy CUPS printer driver files (%d)." = "Unable to copy CUPS printer driver files (%d).";
+"Unable to copy PPD file - %s" = "Unable to copy PPD file - %s";
+"Unable to copy PPD file." = "Unable to copy PPD file.";
+"Unable to copy Windows 2000 printer driver files (%d)." = "Unable to copy Windows 2000 printer driver files (%d).";
+"Unable to copy Windows 9x printer driver files (%d)." = "Unable to copy Windows 9x printer driver files (%d).";
+"Unable to copy interface script - %s" = "Unable to copy interface script - %s";
+"Unable to copy print file" = "Unable to copy print file";
+"Unable to create compressed print file" = "Unable to create compressed print file";
+"Unable to create pipes for filters" = "Unable to create pipes for filters";
+"Unable to create printer-uri" = "Unable to create printer-uri";
+"Unable to create temporary file" = "Unable to create temporary file";
+"Unable to create temporary file:" = "Unable to create temporary file:";
+"Unable to delete class:" = "Unable to delete class:";
+"Unable to delete printer:" = "Unable to delete printer:";
+"Unable to do maintenance command:" = "Unable to do maintenance command:";
+"Unable to edit cupsd.conf files larger than 1MB" = "Unable to edit cupsd.conf files larger than 1MB";
+"Unable to establish a secure connection to host (certificate chain invalid)." = "Unable to establish a secure connection to host (certificate chain invalid).";
+"Unable to establish a secure connection to host (certificate not yet valid)." = "Unable to establish a secure connection to host (certificate not yet valid).";
+"Unable to establish a secure connection to host (expired certificate)." = "Unable to establish a secure connection to host (expired certificate).";
+"Unable to establish a secure connection to host (host name mismatch)." = "Unable to establish a secure connection to host (host name mismatch).";
+"Unable to establish a secure connection to host (peer dropped connection before responding)." = "Unable to establish a secure connection to host (peer dropped connection before responding).";
+"Unable to establish a secure connection to host (self-signed certificate)." = "Unable to establish a secure connection to host (self-signed certificate).";
+"Unable to establish a secure connection to host (untrusted certificate)." = "Unable to establish a secure connection to host (untrusted certificate).";
+"Unable to establish a secure connection to host." = "Unable to establish a secure connection to host.";
+"Unable to find destination for job" = "Unable to find destination for job";
+"Unable to find printer." = "Unable to find printer.";
+"Unable to fork filter" = "Unable to fork filter";
+"Unable to generate compressed print file" = "Unable to generate compressed print file";
+"Unable to get backend exit status." = "Unable to get backend exit status.";
+"Unable to get class list:" = "Unable to get class list:";
+"Unable to get class status:" = "Unable to get class status:";
+"Unable to get list of printer drivers:" = "Unable to get list of printer drivers:";
+"Unable to get print job status." = "Unable to get print job status.";
+"Unable to get printer attributes:" = "Unable to get printer attributes:";
+"Unable to get printer list:" = "Unable to get printer list:";
+"Unable to get printer status." = "Unable to get printer status.";
+"Unable to get printer status:" = "Unable to get printer status:";
+"Unable to install Windows 2000 printer driver files (%d)." = "Unable to install Windows 2000 printer driver files (%d).";
+"Unable to install Windows 9x printer driver files (%d)." = "Unable to install Windows 9x printer driver files (%d).";
+"Unable to locate printer \"%s\"." = "Unable to locate printer \"%s\".";
+"Unable to locate printer." = "Unable to locate printer.";
+"Unable to modify class:" = "Unable to modify class:";
+"Unable to modify printer:" = "Unable to modify printer:";
+"Unable to move job" = "Unable to move job";
+"Unable to move jobs" = "Unable to move jobs";
+"Unable to open PPD file" = "Unable to open PPD file";
+"Unable to open PPD file:" = "Unable to open PPD file:";
+"Unable to open charset file" = "Unable to open charset file";
+"Unable to open compressed print file" = "Unable to open compressed print file";
+"Unable to open cupsd.conf file:" = "Unable to open cupsd.conf file:";
+"Unable to open device file" = "Unable to open device file";
+"Unable to open document #%d in job #%d." = "Unable to open document #%d in job #%d.";
+"Unable to open print file" = "Unable to open print file";
+"Unable to open psglyphs" = "Unable to open psglyphs";
+"Unable to open raster file" = "Unable to open raster file";
+"Unable to print %d text columns." = "Unable to print %d text columns.";
+"Unable to print %dx%d text page." = "Unable to print %dx%d text page.";
+"Unable to print test page:" = "Unable to print test page:";
+"Unable to read print data" = "Unable to read print data";
+"Unable to read print data." = "Unable to read print data.";
+"Unable to run \"%s\": %s" = "Unable to run \"%s\": %s";
+"Unable to see in file" = "Unable to see in file";
+"Unable to send command to printer driver" = "Unable to send command to printer driver";
+"Unable to send data to printer." = "Unable to send data to printer.";
+"Unable to send raster data to the driver." = "Unable to send raster data to the driver.";
+"Unable to set Windows printer driver (%d)." = "Unable to set Windows printer driver (%d).";
+"Unable to set options:" = "Unable to set options:";
+"Unable to set server default:" = "Unable to set server default:";
+"Unable to start backend process." = "Unable to start backend process.";
+"Unable to upload cupsd.conf file:" = "Unable to upload cupsd.conf file:";
+"Unable to use legacy USB class driver." = "Unable to use legacy USB class driver.";
+"Unable to write print data" = "Unable to write print data";
+"Unable to write uncompressed print data: %s" = "Unable to write uncompressed print data: %s";
+"Unauthorized" = "Unauthorized";
+"Units" = "Units";
+"Unknown" = "Unknown";
+"Unknown choice \"%s\" for option \"%s\"." = "Unknown choice \"%s\" for option \"%s\".";
+"Unknown encryption option value: \"%s\"." = "Unknown encryption option value: \"%s\".";
+"Unknown file order: \"%s\"." = "Unknown file order: \"%s\".";
+"Unknown format character: \"%c\"." = "Unknown format character: \"%c\".";
+"Unknown option \"%s\" with value \"%s\"." = "Unknown option \"%s\" with value \"%s\".";
+"Unknown option \"%s\"." = "Unknown option \"%s\".";
+"Unknown print mode: \"%s\"." = "Unknown print mode: \"%s\".";
+"Unknown printer-error-policy \"%s\"." = "Unknown printer-error-policy \"%s\".";
+"Unknown printer-op-policy \"%s\"." = "Unknown printer-op-policy \"%s\".";
+"Unknown version option value: \"%s\"." = "Unknown version option value: \"%s\".";
+"Unsupported baud rate: %s" = "Unsupported baud rate: %s";
+"Unsupported brightness value %s, using brightness=100." = "Unsupported brightness value %s, using brightness=100.";
+"Unsupported character set \"%s\"." = "Unsupported character set \"%s\".";
+"Unsupported compression \"%s\"." = "Unsupported compression \"%s\".";
+"Unsupported document-format \"%s\"." = "Unsupported document-format \"%s\".";
+"Unsupported document-format \"%s/%s\"." = "Unsupported document-format \"%s/%s\".";
+"Unsupported format \"%s\"." = "Unsupported format \"%s\".";
+"Unsupported gamma value %s, using gamma=1000." = "Unsupported gamma value %s, using gamma=1000.";
+"Unsupported margins." = "Unsupported margins.";
+"Unsupported media value." = "Unsupported media value.";
+"Unsupported number-up value %d, using number-up=1." = "Unsupported number-up value %d, using number-up=1.";
+"Unsupported number-up-layout value %s, using number-up-layout=lrtb." = "Unsupported number-up-layout value %s, using number-up-layout=lrtb.";
+"Unsupported page-border value %s, using page-border=none." = "Unsupported page-border value %s, using page-border=none.";
+"Unsupported raster data." = "Unsupported raster data.";
+"Unsupported value type" = "Unsupported value type";
+"Upgrade Required" = "Upgrade Required";
+"Usage:\n\n lpadmin [-h server] -d destination\n lpadmin [-h server] -x destination\n lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n [-r remove-class] [-v device] [-D description]\n [-P ppd-file] [-o name=value]\n [-u allow:user,user] [-u deny:user,user]" = "Usage:\n\n lpadmin [-h server] -d destination\n lpadmin [-h server] -x destination\n lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n [-r remove-class] [-v device] [-D description]\n [-P ppd-file] [-o name=value]\n [-u allow:user,user] [-u deny:user,user]";
+"Usage: %s job user title copies options [filename]" = "Usage: %s job user title copies options [filename]";
+"Usage: %s job-id user title copies options [file]" = "Usage: %s job-id user title copies options [file]";
+"Usage: %s job-id user title copies options file" = "Usage: %s job-id user title copies options file";
+"Usage: convert [ options ]" = "Usage: convert [ options ]";
+"Usage: cupsaddsmb [options] printer1 ... printerN" = "Usage: cupsaddsmb [options] printer1 ... printerN";
+"Usage: cupsctl [options] [param=value ... paramN=valueN]" = "Usage: cupsctl [options] [param=value ... paramN=valueN]";
+"Usage: cupsd [options]" = "Usage: cupsd [options]";
+"Usage: cupsfilter [ options ] filename" = "Usage: cupsfilter [ options ] filename";
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]" = "Usage: cupstestdsc [options] filename.ps [... filename.ps]";
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]" = "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]";
+"Usage: ipptool [options] URI filename [ ... filenameN ]" = "Usage: ipptool [options] URI filename [ ... filenameN ]";
+"Usage: lpmove job/src dest" = "Usage: lpmove job/src dest";
+"Usage: lpoptions [-h server] [-E] -d printer\n lpoptions [-h server] [-E] [-p printer] -l\n lpoptions [-h server] [-E] -p printer -o option[=value] ...\n lpoptions [-h server] [-E] -x printer" = "Usage: lpoptions [-h server] [-E] -d printer\n lpoptions [-h server] [-E] [-p printer] -l\n lpoptions [-h server] [-E] -p printer -o option[=value] ...\n lpoptions [-h server] [-E] -x printer";
+"Usage: lppasswd [-g groupname]" = "Usage: lppasswd [-g groupname]";
+"Usage: lppasswd [-g groupname] [username]\n lppasswd [-g groupname] -a [username]\n lppasswd [-g groupname] -x [username]" = "Usage: lppasswd [-g groupname] [username]\n lppasswd [-g groupname] -a [username]\n lppasswd [-g groupname] -x [username]";
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]" = "Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]";
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]" = "Usage: ppdc [options] filename.drv [ ... filenameN.drv ]";
+"Usage: ppdhtml [options] filename.drv >filename.html" = "Usage: ppdhtml [options] filename.drv >filename.html";
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]" = "Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]";
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]" = "Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]";
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]" = "Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]";
+"Usage: snmp [host-or-ip-address]" = "Usage: snmp [host-or-ip-address]";
+"Value uses indefinite length" = "Value uses indefinite length";
+"VarBind uses indefinite length" = "VarBind uses indefinite length";
+"Version uses indefinite length" = "Version uses indefinite length";
+"Waiting for job to complete." = "Waiting for job to complete.";
+"Waiting for printer to become available." = "Waiting for printer to become available.";
+"Waiting for printer to finish." = "Waiting for printer to finish.";
+"Warning, no Windows 2000 printer drivers are installed." = "Warning, no Windows 2000 printer drivers are installed.";
+"Web Interface is Disabled" = "Web Interface is Disabled";
+"Yes" = "Yes";
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%s:%d%s</A>." = "You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%s:%d%s</A>.";
+"Your password must be at least 6 characters long, cannot contain your username, and must contain at least one letter and number." = "Your password must be at least 6 characters long, cannot contain your username, and must contain at least one letter and number.";
+"ZPL Label Printer" = "ZPL Label Printer";
+"Zebra" = "Zebra";
+"aborted" = "aborted";
+"canceled" = "canceled";
+"completed" = "completed";
+"convert: Use the -f option to specify a file to convert." = "convert: Use the -f option to specify a file to convert.";
+"cups-deviced failed to execute." = "cups-deviced failed to execute.";
+"cups-driverd failed to execute." = "cups-driverd failed to execute.";
+"cupsaddsmb: No PPD file for printer \"%s\" - %s" = "cupsaddsmb: No PPD file for printer \"%s\" - %s";
+"cupsctl: Cannot set Listen or Port directly." = "cupsctl: Cannot set Listen or Port directly.";
+"cupsctl: Unable to connect to server: %s" = "cupsctl: Unable to connect to server: %s";
+"cupsctl: Unknown option \"%s\"" = "cupsctl: Unknown option \"%s\"";
+"cupsctl: Unknown option \"-%c\"" = "cupsctl: Unknown option \"-%c\"";
+"cupsd: Expected config filename after \"-c\" option." = "cupsd: Expected config filename after \"-c\" option.";
+"cupsd: Unable to get current directory." = "cupsd: Unable to get current directory.";
+"cupsd: Unknown argument \"%s\" - aborting." = "cupsd: Unknown argument \"%s\" - aborting.";
+"cupsd: Unknown option \"%c\" - aborting." = "cupsd: Unknown option \"%c\" - aborting.";
+"cupsd: launchd(8) support not compiled in, running in normal mode." = "cupsd: launchd(8) support not compiled in, running in normal mode.";
+"cupsfilter: Invalid document number %d." = "cupsfilter: Invalid document number %d.";
+"cupsfilter: Invalid job ID %d." = "cupsfilter: Invalid job ID %d.";
+"cupsfilter: Only one filename can be specified." = "cupsfilter: Only one filename can be specified.";
+"cupsfilter: Unable to get job file - %s" = "cupsfilter: Unable to get job file - %s";
+"cupstestppd: The -q option is incompatible with the -v option." = "cupstestppd: The -q option is incompatible with the -v option.";
+"cupstestppd: The -v option is incompatible with the -q option." = "cupstestppd: The -v option is incompatible with the -q option.";
+"device for %s/%s: %s" = "device for %s/%s: %s";
+"device for %s: %s" = "device for %s: %s";
+"error-index uses indefinite length" = "error-index uses indefinite length";
+"error-status uses indefinite length" = "error-status uses indefinite length";
+"held" = "held";
+"help\t\tGet help on commands." = "help\t\tGet help on commands.";
+"idle" = "idle";
+"ipptool: \"-i\" and \"-n\" are incompatible with -X\"." = "ipptool: \"-i\" and \"-n\" are incompatible with -X\".";
+"ipptool: \"-i\" is incompatible with \"-X\"." = "ipptool: \"-i\" is incompatible with \"-X\".";
+"ipptool: \"-n\" is incompatible with \"-X\"." = "ipptool: \"-n\" is incompatible with \"-X\".";
+"ipptool: Bad URI - %s." = "ipptool: Bad URI - %s.";
+"ipptool: Bad version %s for \"-V\"." = "ipptool: Bad version %s for \"-V\".";
+"ipptool: Invalid seconds for \"-i\"." = "ipptool: Invalid seconds for \"-i\".";
+"ipptool: May only specify a single URI." = "ipptool: May only specify a single URI.";
+"ipptool: Missing count for \"-n\"." = "ipptool: Missing count for \"-n\".";
+"ipptool: Missing filename for \"-f\"." = "ipptool: Missing filename for \"-f\".";
+"ipptool: Missing name=value for \"-d\"." = "ipptool: Missing name=value for \"-d\".";
+"ipptool: Missing seconds for \"-i\"." = "ipptool: Missing seconds for \"-i\".";
+"ipptool: Missing timeout for \"-T\"." = "ipptool: Missing timeout for \"-T\".";
+"ipptool: Missing version for \"-V\"." = "ipptool: Missing version for \"-V\".";
+"ipptool: URI required before test file." = "ipptool: URI required before test file.";
+"ipptool: Unknown option \"-%c\"." = "ipptool: Unknown option \"-%c\".";
+"job-printer-uri attribute missing." = "job-printer-uri attribute missing.";
+"lpadmin: Class name can only contain printable characters." = "lpadmin: Class name can only contain printable characters.";
+"lpadmin: Expected PPD after \"-P\" option." = "lpadmin: Expected PPD after \"-P\" option.";
+"lpadmin: Expected allow/deny:userlist after \"-u\" option." = "lpadmin: Expected allow/deny:userlist after \"-u\" option.";
+"lpadmin: Expected class after \"-r\" option." = "lpadmin: Expected class after \"-r\" option.";
+"lpadmin: Expected class name after \"-c\" option." = "lpadmin: Expected class name after \"-c\" option.";
+"lpadmin: Expected description after \"-D\" option." = "lpadmin: Expected description after \"-D\" option.";
+"lpadmin: Expected device URI after \"-v\" option." = "lpadmin: Expected device URI after \"-v\" option.";
+"lpadmin: Expected file type(s) after \"-I\" option." = "lpadmin: Expected file type(s) after \"-I\" option.";
+"lpadmin: Expected hostname after \"-h\" option." = "lpadmin: Expected hostname after \"-h\" option.";
+"lpadmin: Expected interface after \"-i\" option." = "lpadmin: Expected interface after \"-i\" option.";
+"lpadmin: Expected location after \"-L\" option." = "lpadmin: Expected location after \"-L\" option.";
+"lpadmin: Expected model after \"-m\" option." = "lpadmin: Expected model after \"-m\" option.";
+"lpadmin: Expected name after \"-R\" option." = "lpadmin: Expected name after \"-R\" option.";
+"lpadmin: Expected name=value after \"-o\" option." = "lpadmin: Expected name=value after \"-o\" option.";
+"lpadmin: Expected printer after \"-p\" option." = "lpadmin: Expected printer after \"-p\" option.";
+"lpadmin: Expected printer name after \"-d\" option." = "lpadmin: Expected printer name after \"-d\" option.";
+"lpadmin: Expected printer or class after \"-x\" option." = "lpadmin: Expected printer or class after \"-x\" option.";
+"lpadmin: No member names were seen." = "lpadmin: No member names were seen.";
+"lpadmin: Printer %s is already a member of class %s." = "lpadmin: Printer %s is already a member of class %s.";
+"lpadmin: Printer %s is not a member of class %s." = "lpadmin: Printer %s is not a member of class %s.";
+"lpadmin: Printer name can only contain printable characters." = "lpadmin: Printer name can only contain printable characters.";
+"lpadmin: Unable to add a printer to the class:\n You must specify a printer name first." = "lpadmin: Unable to add a printer to the class:\n You must specify a printer name first.";
+"lpadmin: Unable to connect to server: %s" = "lpadmin: Unable to connect to server: %s";
+"lpadmin: Unable to create temporary file" = "lpadmin: Unable to create temporary file";
+"lpadmin: Unable to delete option:\n You must specify a printer name first." = "lpadmin: Unable to delete option:\n You must specify a printer name first.";
+"lpadmin: Unable to open PPD file \"%s\" - %s" = "lpadmin: Unable to open PPD file \"%s\" - %s";
+"lpadmin: Unable to remove a printer from the class:\n You must specify a printer name first." = "lpadmin: Unable to remove a printer from the class:\n You must specify a printer name first.";
+"lpadmin: Unable to set the printer options:\n You must specify a printer name first." = "lpadmin: Unable to set the printer options:\n You must specify a printer name first.";
+"lpadmin: Unknown allow/deny option \"%s\"." = "lpadmin: Unknown allow/deny option \"%s\".";
+"lpadmin: Unknown argument \"%s\"." = "lpadmin: Unknown argument \"%s\".";
+"lpadmin: Unknown option \"%c\"." = "lpadmin: Unknown option \"%c\".";
+"lpadmin: Warning - content type list ignored." = "lpadmin: Warning - content type list ignored.";
+"lpc> " = "lpc> ";
+"lpinfo: Expected 1284 device ID string after \"--device-id\"." = "lpinfo: Expected 1284 device ID string after \"--device-id\".";
+"lpinfo: Expected language after \"--language\"." = "lpinfo: Expected language after \"--language\".";
+"lpinfo: Expected make and model after \"--make-and-model\"." = "lpinfo: Expected make and model after \"--make-and-model\".";
+"lpinfo: Expected product string after \"--product\"." = "lpinfo: Expected product string after \"--product\".";
+"lpinfo: Expected scheme list after \"--exclude-schemes\"." = "lpinfo: Expected scheme list after \"--exclude-schemes\".";
+"lpinfo: Expected scheme list after \"--include-schemes\"." = "lpinfo: Expected scheme list after \"--include-schemes\".";
+"lpinfo: Expected timeout after \"--timeout\"." = "lpinfo: Expected timeout after \"--timeout\".";
+"lpinfo: Unknown argument \"%s\"." = "lpinfo: Unknown argument \"%s\".";
+"lpinfo: Unknown option \"%c\"." = "lpinfo: Unknown option \"%c\".";
+"lpinfo: Unknown option \"%s\"." = "lpinfo: Unknown option \"%s\".";
+"lpmove: Unable to connect to server: %s" = "lpmove: Unable to connect to server: %s";
+"lpmove: Unknown argument \"%s\"." = "lpmove: Unknown argument \"%s\".";
+"lpmove: Unknown option \"%c\"." = "lpmove: Unknown option \"%c\".";
+"lpoptions: No printers." = "lpoptions: No printers.";
+"lpoptions: Unable to add printer or instance: %s" = "lpoptions: Unable to add printer or instance: %s";
+"lpoptions: Unable to get PPD file for %s: %s" = "lpoptions: Unable to get PPD file for %s: %s";
+"lpoptions: Unable to open PPD file for %s." = "lpoptions: Unable to open PPD file for %s.";
+"lpoptions: Unknown printer or class." = "lpoptions: Unknown printer or class.";
+"lppasswd: Only root can add or delete passwords." = "lppasswd: Only root can add or delete passwords.";
+"lppasswd: Password file busy." = "lppasswd: Password file busy.";
+"lppasswd: Password file not updated." = "lppasswd: Password file not updated.";
+"lppasswd: Sorry, password doesn't match." = "lppasswd: Sorry, password doesn't match.";
+"lppasswd: Sorry, password rejected." = "lppasswd: Sorry, password rejected.";
+"lppasswd: Sorry, passwords don't match." = "lppasswd: Sorry, passwords don't match.";
+"lppasswd: Unable to copy password string: %s" = "lppasswd: Unable to copy password string: %s";
+"lppasswd: Unable to open password file: %s" = "lppasswd: Unable to open password file: %s";
+"lppasswd: Unable to write to password file: %s" = "lppasswd: Unable to write to password file: %s";
+"lppasswd: failed to backup old password file: %s" = "lppasswd: failed to backup old password file: %s";
+"lppasswd: failed to rename password file: %s" = "lppasswd: failed to rename password file: %s";
+"lppasswd: user \"%s\" and group \"%s\" do not exist." = "lppasswd: user \"%s\" and group \"%s\" do not exist.";
+"lpstat: error - %s environment variable names non-existent destination \"%s\"." = "lpstat: error - %s environment variable names non-existent destination \"%s\".";
+"members of class %s:" = "members of class %s:";
+"no entries" = "no entries";
+"no system default destination" = "no system default destination";
+"notify-events not specified." = "notify-events not specified.";
+"notify-recipient-uri URI \"%s\" is already used." = "notify-recipient-uri URI \"%s\" is already used.";
+"notify-recipient-uri URI \"%s\" uses unknown scheme." = "notify-recipient-uri URI \"%s\" uses unknown scheme.";
+"pending" = "pending";
+"ppdc: Adding include directory \"%s\"." = "ppdc: Adding include directory \"%s\".";
+"ppdc: Adding/updating UI text from %s." = "ppdc: Adding/updating UI text from %s.";
+"ppdc: Bad boolean value (%s) on line %d of %s." = "ppdc: Bad boolean value (%s) on line %d of %s.";
+"ppdc: Bad font attribute: %s" = "ppdc: Bad font attribute: %s";
+"ppdc: Bad resolution name \"%s\" on line %d of %s." = "ppdc: Bad resolution name \"%s\" on line %d of %s.";
+"ppdc: Bad status keyword %s on line %d of %s." = "ppdc: Bad status keyword %s on line %d of %s.";
+"ppdc: Bad variable substitution ($%c) on line %d of %s." = "ppdc: Bad variable substitution ($%c) on line %d of %s.";
+"ppdc: Choice found on line %d of %s with no Option." = "ppdc: Choice found on line %d of %s with no Option.";
+"ppdc: Duplicate #po for locale %s on line %d of %s." = "ppdc: Duplicate #po for locale %s on line %d of %s.";
+"ppdc: Expected a filter definition on line %d of %s." = "ppdc: Expected a filter definition on line %d of %s.";
+"ppdc: Expected a program name on line %d of %s." = "ppdc: Expected a program name on line %d of %s.";
+"ppdc: Expected boolean value on line %d of %s." = "ppdc: Expected boolean value on line %d of %s.";
+"ppdc: Expected charset after Font on line %d of %s." = "ppdc: Expected charset after Font on line %d of %s.";
+"ppdc: Expected choice code on line %d of %s." = "ppdc: Expected choice code on line %d of %s.";
+"ppdc: Expected choice name/text on line %d of %s." = "ppdc: Expected choice name/text on line %d of %s.";
+"ppdc: Expected color order for ColorModel on line %d of %s." = "ppdc: Expected color order for ColorModel on line %d of %s.";
+"ppdc: Expected colorspace for ColorModel on line %d of %s." = "ppdc: Expected colorspace for ColorModel on line %d of %s.";
+"ppdc: Expected compression for ColorModel on line %d of %s." = "ppdc: Expected compression for ColorModel on line %d of %s.";
+"ppdc: Expected constraints string for UIConstraints on line %d of %s." = "ppdc: Expected constraints string for UIConstraints on line %d of %s.";
+"ppdc: Expected driver type keyword following DriverType on line %d of %s." = "ppdc: Expected driver type keyword following DriverType on line %d of %s.";
+"ppdc: Expected duplex type after Duplex on line %d of %s." = "ppdc: Expected duplex type after Duplex on line %d of %s.";
+"ppdc: Expected encoding after Font on line %d of %s." = "ppdc: Expected encoding after Font on line %d of %s.";
+"ppdc: Expected filename after #po %s on line %d of %s." = "ppdc: Expected filename after #po %s on line %d of %s.";
+"ppdc: Expected group name/text on line %d of %s." = "ppdc: Expected group name/text on line %d of %s.";
+"ppdc: Expected include filename on line %d of %s." = "ppdc: Expected include filename on line %d of %s.";
+"ppdc: Expected integer on line %d of %s." = "ppdc: Expected integer on line %d of %s.";
+"ppdc: Expected locale after #po on line %d of %s." = "ppdc: Expected locale after #po on line %d of %s.";
+"ppdc: Expected name after %s on line %d of %s." = "ppdc: Expected name after %s on line %d of %s.";
+"ppdc: Expected name after FileName on line %d of %s." = "ppdc: Expected name after FileName on line %d of %s.";
+"ppdc: Expected name after Font on line %d of %s." = "ppdc: Expected name after Font on line %d of %s.";
+"ppdc: Expected name after Manufacturer on line %d of %s." = "ppdc: Expected name after Manufacturer on line %d of %s.";
+"ppdc: Expected name after MediaSize on line %d of %s." = "ppdc: Expected name after MediaSize on line %d of %s.";
+"ppdc: Expected name after ModelName on line %d of %s." = "ppdc: Expected name after ModelName on line %d of %s.";
+"ppdc: Expected name after PCFileName on line %d of %s." = "ppdc: Expected name after PCFileName on line %d of %s.";
+"ppdc: Expected name/text after %s on line %d of %s." = "ppdc: Expected name/text after %s on line %d of %s.";
+"ppdc: Expected name/text after Installable on line %d of %s." = "ppdc: Expected name/text after Installable on line %d of %s.";
+"ppdc: Expected name/text after Resolution on line %d of %s." = "ppdc: Expected name/text after Resolution on line %d of %s.";
+"ppdc: Expected name/text combination for ColorModel on line %d of %s." = "ppdc: Expected name/text combination for ColorModel on line %d of %s.";
+"ppdc: Expected option name/text on line %d of %s." = "ppdc: Expected option name/text on line %d of %s.";
+"ppdc: Expected option section on line %d of %s." = "ppdc: Expected option section on line %d of %s.";
+"ppdc: Expected option type on line %d of %s." = "ppdc: Expected option type on line %d of %s.";
+"ppdc: Expected override field after Resolution on line %d of %s." = "ppdc: Expected override field after Resolution on line %d of %s.";
+"ppdc: Expected quoted string on line %d of %s." = "ppdc: Expected quoted string on line %d of %s.";
+"ppdc: Expected real number on line %d of %s." = "ppdc: Expected real number on line %d of %s.";
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s." = "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s.";
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d of %s." = "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d of %s.";
+"ppdc: Expected selector after %s on line %d of %s." = "ppdc: Expected selector after %s on line %d of %s.";
+"ppdc: Expected status after Font on line %d of %s." = "ppdc: Expected status after Font on line %d of %s.";
+"ppdc: Expected string after Copyright on line %d of %s." = "ppdc: Expected string after Copyright on line %d of %s.";
+"ppdc: Expected string after Version on line %d of %s." = "ppdc: Expected string after Version on line %d of %s.";
+"ppdc: Expected two option names on line %d of %s." = "ppdc: Expected two option names on line %d of %s.";
+"ppdc: Expected value after %s on line %d of %s." = "ppdc: Expected value after %s on line %d of %s.";
+"ppdc: Expected version after Font on line %d of %s." = "ppdc: Expected version after Font on line %d of %s.";
+"ppdc: Invalid #include/#po filename \"%s\"." = "ppdc: Invalid #include/#po filename \"%s\".";
+"ppdc: Invalid cost for filter on line %d of %s." = "ppdc: Invalid cost for filter on line %d of %s.";
+"ppdc: Invalid empty MIME type for filter on line %d of %s." = "ppdc: Invalid empty MIME type for filter on line %d of %s.";
+"ppdc: Invalid empty program name for filter on line %d of %s." = "ppdc: Invalid empty program name for filter on line %d of %s.";
+"ppdc: Invalid option section \"%s\" on line %d of %s." = "ppdc: Invalid option section \"%s\" on line %d of %s.";
+"ppdc: Invalid option type \"%s\" on line %d of %s." = "ppdc: Invalid option type \"%s\" on line %d of %s.";
+"ppdc: Loading driver information file \"%s\"." = "ppdc: Loading driver information file \"%s\".";
+"ppdc: Loading messages for locale \"%s\"." = "ppdc: Loading messages for locale \"%s\".";
+"ppdc: Loading messages from \"%s\"." = "ppdc: Loading messages from \"%s\".";
+"ppdc: Missing #endif at end of \"%s\"." = "ppdc: Missing #endif at end of \"%s\".";
+"ppdc: Missing #if on line %d of %s." = "ppdc: Missing #if on line %d of %s.";
+"ppdc: Need a msgid line before any translation strings on line %d of %s." = "ppdc: Need a msgid line before any translation strings on line %d of %s.";
+"ppdc: No message catalog provided for locale %s." = "ppdc: No message catalog provided for locale %s.";
+"ppdc: Option %s defined in two different groups on line %d of %s." = "ppdc: Option %s defined in two different groups on line %d of %s.";
+"ppdc: Option %s redefined with a different type on line %d of %s." = "ppdc: Option %s redefined with a different type on line %d of %s.";
+"ppdc: Option constraint must *name on line %d of %s." = "ppdc: Option constraint must *name on line %d of %s.";
+"ppdc: Too many nested #if's on line %d of %s." = "ppdc: Too many nested #if's on line %d of %s.";
+"ppdc: Unable to create PPD file \"%s\" - %s." = "ppdc: Unable to create PPD file \"%s\" - %s.";
+"ppdc: Unable to create output directory %s: %s" = "ppdc: Unable to create output directory %s: %s";
+"ppdc: Unable to create output pipes: %s" = "ppdc: Unable to create output pipes: %s";
+"ppdc: Unable to execute cupstestppd: %s" = "ppdc: Unable to execute cupstestppd: %s";
+"ppdc: Unable to find #po file %s on line %d of %s." = "ppdc: Unable to find #po file %s on line %d of %s.";
+"ppdc: Unable to find include file \"%s\" on line %d of %s." = "ppdc: Unable to find include file \"%s\" on line %d of %s.";
+"ppdc: Unable to find localization for \"%s\" - %s" = "ppdc: Unable to find localization for \"%s\" - %s";
+"ppdc: Unable to load localization file \"%s\" - %s" = "ppdc: Unable to load localization file \"%s\" - %s";
+"ppdc: Unable to open %s: %s" = "ppdc: Unable to open %s: %s";
+"ppdc: Undefined variable (%s) on line %d of %s." = "ppdc: Undefined variable (%s) on line %d of %s.";
+"ppdc: Unexpected text on line %d of %s." = "ppdc: Unexpected text on line %d of %s.";
+"ppdc: Unknown driver type %s on line %d of %s." = "ppdc: Unknown driver type %s on line %d of %s.";
+"ppdc: Unknown duplex type \"%s\" on line %d of %s." = "ppdc: Unknown duplex type \"%s\" on line %d of %s.";
+"ppdc: Unknown media size \"%s\" on line %d of %s." = "ppdc: Unknown media size \"%s\" on line %d of %s.";
+"ppdc: Unknown message catalog format for \"%s\"." = "ppdc: Unknown message catalog format for \"%s\".";
+"ppdc: Unknown token \"%s\" seen on line %d of %s." = "ppdc: Unknown token \"%s\" seen on line %d of %s.";
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s." = "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s.";
+"ppdc: Unterminated string starting with %c on line %d of %s." = "ppdc: Unterminated string starting with %c on line %d of %s.";
+"ppdc: Warning - overlapping filename \"%s\"." = "ppdc: Warning - overlapping filename \"%s\".";
+"ppdc: Writing %s." = "ppdc: Writing %s.";
+"ppdc: Writing PPD files to directory \"%s\"." = "ppdc: Writing PPD files to directory \"%s\".";
+"ppdmerge: Bad LanguageVersion \"%s\" in %s." = "ppdmerge: Bad LanguageVersion \"%s\" in %s.";
+"ppdmerge: Ignoring PPD file %s." = "ppdmerge: Ignoring PPD file %s.";
+"ppdmerge: Unable to backup %s to %s - %s" = "ppdmerge: Unable to backup %s to %s - %s";
+"printer %s disabled since %s -" = "printer %s disabled since %s -";
+"printer %s is idle. enabled since %s" = "printer %s is idle. enabled since %s";
+"printer %s now printing %s-%d. enabled since %s" = "printer %s now printing %s-%d. enabled since %s";
+"printer %s/%s disabled since %s -" = "printer %s/%s disabled since %s -";
+"printer %s/%s is idle. enabled since %s" = "printer %s/%s is idle. enabled since %s";
+"printer %s/%s now printing %s-%d. enabled since %s" = "printer %s/%s now printing %s-%d. enabled since %s";
+"processing" = "processing";
+"request id is %s-%d (%d file(s))" = "request id is %s-%d (%d file(s))";
+"request-id uses indefinite length" = "request-id uses indefinite length";
+"scheduler is not running" = "scheduler is not running";
+"scheduler is running" = "scheduler is running";
+"stat of %s failed: %s" = "stat of %s failed: %s";
+"status\t\tShow status of daemon and queue." = "status\t\tShow status of daemon and queue.";
+"stopped" = "stopped";
+"system default destination: %s" = "system default destination: %s";
+"system default destination: %s/%s" = "system default destination: %s/%s";
+"unknown" = "unknown";
+"untitled" = "untitled";
+"variable-bindings uses indefinite length" = "variable-bindings uses indefinite length";
diff --git a/locale/cups_da.po b/locale/cups_da.po
new file mode 100644
index 000000000..b26b04982
--- /dev/null
+++ b/locale/cups_da.po
@@ -0,0 +1,7113 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-16 12:00-0800\n"
+"Last-Translator: Apple Inc.\n"
+"Language-Team: Apple Inc.\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(alle)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(ingen)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d optegnelser\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tEfter fejl: Fortsæt\n"
+
+msgid "\tAlerts:"
+msgstr "\tAdvarsler:"
+
+msgid "\tBanner required\n"
+msgstr "\tBanner kræves\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tTegnsæt:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tForbindelse: Direkte\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tForbindelse: Ekstern\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tStandardsidestørrelse:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tStandardhøjde:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tStandardportindstillinger:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tBeskrivelse: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tAktiv formular:\n"
+"\tIndholdstyper: alle\n"
+"\tPrintertyper: Ukendt\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tFormularer tilladt:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tGrænseflade: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tGrænseflade: %s/grænseflader/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tGrænseflade: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tPlacering: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tVed fejl: Ingen advarsel\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tBrugere tilladt:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tBrugere ikke tilladt:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tdaemon til stede\n"
+
+msgid "\tno entries\n"
+msgstr "\tingen optegnelser\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\tprinter er på enheden '%s', hastighed -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\tudskrivning er slået fra\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\tudskrivning er slået til\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\tstår i kø til %s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tkø er slået fra\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tkø er slået til\n"
+
+msgid "\treason unknown\n"
+msgstr "\tårsag ukendt\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" DETALJEREDE RESULTATER AF TEST AF OVERENSSTEMMELSE\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " REF: Side 15, afsnit 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " REF: Side 15, afsnit 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " REF: Side 19, afsnit 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " REF: Side 20, afsnit 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " REF: Side 27, afsnit 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " REF: Side 42, afsnit 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " REF: Side 16-17, afsnit 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " REF: Side 42-45, afsnit 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " REF: Side 45-46, afsnit 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " REF: Side 48-49, afsnit 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " REF: Side 52-54, afsnit 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f byte\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " PASS Default%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " PASS DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " PASS DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " PASS FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " PASS FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " PASS LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " PASS LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " PASS Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " PASS ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " PASS NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " PASS PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " PASS PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " PASS PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " PASS PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " PASS Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " PASS ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" WARN \"%s %s\" er i konflikt med \"%s %s\"\n"
+" (begrænsning=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" WARN %s deler et almindeligt præfiks med %s\n"
+" REF: Side 15, afsnit 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" WARN LanguageEncoding kræves af PPD 4.3 spec.\n"
+" REF: Side 56-57, afsnit 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" WARN Manufacturer kræves af PPD 4.3 spec.\n"
+" REF: Side 58-59, afsnit 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" WARN PCFileName længere end 8.3 overtræder PPD-spec.\n"
+" REF: Side 61-62, afsnit 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protokoller indeholder PJL, men JCL-attributter er ikke "
+"indstillet.\n"
+" REF: Side 78-79, afsnit 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protokoller indeholder både PJL og BCP; forventede TBCP.\n"
+" REF: Side 78-79, afsnit 5.7.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" WARN ShortNickName kræves af PPD 4.3 spec.\n"
+" REF: Side 64-65, afsnit 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s Manglende cupsFilter-arkiv \"%s\"\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s Manglende cupsPreFilter-arkiv \"%s\"\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** UGYLDIG Default%s %s\n"
+" REF: Side 40, afsnit 4.5.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **FAIL** UGYLDIG JobPatchFile-egenskab i arkiv\n"
+" REF: Side 24, afsnit 3.4.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** UGYLDIG Manufacturer (skulle være \"HP\")\n"
+" REF: Side 211, tabel D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** UGYLDIG Manufacturer (skulle være \"Oki\")\n"
+" REF: Side 211, tabel D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** UGYLDIGT ModelName - \"%c\" ikke tilladt i streng.\n"
+" REF: Side 59-60, afsnit 5.3.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** UGYLDIG PSVersion - ikke \"(string) int\".\n"
+" REF: Side 62-64, afsnit 5.3.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** UGYLDIGT Product - ikke \"(string)\".\n"
+" REF: Side 62, afsnit 5.3.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** UGYLDIGT ShortNickName - længere end 31 tegn.\n"
+" REF: Side 64-65, afsnit 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** Ugyldig FileVersion \"%s\"\n"
+" REF: Side 56, afsnit 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** Ugyldig FormatVersion \"%s\"\n"
+" REF: Side 56, afsnit 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr ""
+" **FAIL** Standardkode til indstilling kunne ikke fortolkes: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Side 40, afsnit 4.5.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Side 102, afsnit 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Side 103, afsnit 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Side 56, afsnit 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Side 56, afsnit 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** REQUIRED ImageableArea til PageSize %s\n"
+" REF: Side 41, afsnit 5.\n"
+" REF: Side 102, afsnit 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Side 56-57, afsnit 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Side 57-58, afsnit 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Side 58-59, afsnit 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Side 59-60, afsnit 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Side 60, afsnit 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Side 61-62, afsnit 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Side 62-64, afsnit 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Side 100, afsnit 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Side 41, afsnit 5.\n"
+" REF: Side 99, afsnit 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Side 99-100, afsnit 5.14.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** REQUIRED PaperDimension til PageSize %s\n"
+" REF: Side 41, afsnit 5.\n"
+" REF: Side 103, afsnit 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED Product\n"
+" REF: Side 62, afsnit 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Side 64-65, afsnit 5.3.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " %d FEJL FUNDET\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " INGEN FEJL FUNDET\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " FAIL\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** Kan ikke åbne PPD-arkiv - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** Kan ikke åbne PPD-arkiv - %s på linje %d.\n"
+
+msgid " PASS\n"
+msgstr " PASS\n"
+
+msgid "#10 Envelope"
+msgstr "#10-kuvert"
+
+msgid "#11 Envelope"
+msgstr "#11-kuvert"
+
+msgid "#12 Envelope"
+msgstr "#12-kuvert"
+
+msgid "#14 Envelope"
+msgstr "#14-kuvert"
+
+msgid "#9 Envelope"
+msgstr "#9-kuvert"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f byte\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f byte\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f mm"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f til %.0f x %.0f mm"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f tommer"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f til %.2f x %.2f tommer"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s accepterer anmodninger siden %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%s kan ikke ændres."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s er ikke implementeret af CUPS-versionen af lpc.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s er ikke klar\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s er klar\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s er klar og udskriver\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s accepterer ikke anmodninger siden %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s accepterer anmodninger siden %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s accepterer ikke anmodninger siden %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [job %d localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s mislykkedes: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: Fejl - ingen tilgængelig standarddestination.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: Fejl - prioritet skal være mellem 1 og 100.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: Fejl - for mange arkiver - \"%s\"\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: Fejl - kan ikke få adgang til \"%s\" - %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s: Fejl - kan ikke sætte i kø fra stdin - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: Filter \"%s\" ikke tilgængeligt: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: Ugyldig filterstreng \"%s\"\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: Handling mislykkedes: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: Kan ikke oprette forbindelse til server\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: Kan ikke åbne %s: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: Kan ikke åbne PPD-arkiv: %s på linje %d\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: Fejl - ingen tilgængelig standarddestination.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 tomme/sek."
+
+msgid "1.25x0.25\""
+msgstr "1,25 x 0,25\""
+
+msgid "1.25x2.25\""
+msgstr "1,25 x 2,25\""
+
+msgid "1.5 inch/sec."
+msgstr "1,5 tomme/sek."
+
+msgid "1.50x0.25\""
+msgstr "1,50 x 0,25\""
+
+msgid "1.50x0.50\""
+msgstr "1,50 x 0,50\""
+
+msgid "1.50x1.00\""
+msgstr "1,50 x 1,00\""
+
+msgid "1.50x2.00\""
+msgstr "1,50 x 2,00\""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 tommer/sek."
+
+msgid "10 x 11\""
+msgstr "10 x 11\""
+
+msgid "10 x 13\""
+msgstr "10 x 13\""
+
+msgid "10 x 14\""
+msgstr "10 x 14\""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 mm/sek."
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 tommer/sek."
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 tommer/sek."
+
+msgid "12 x 11\""
+msgstr "12 x 11\""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 mm/sek."
+
+msgid "120x60dpi"
+msgstr "120 x 60 dpi"
+
+msgid "120x72dpi"
+msgstr "120 x 72 dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136 dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 mm/sek."
+
+msgid "15 x 11\""
+msgstr "15 x 11\""
+
+msgid "150 mm/sec."
+msgstr "150 mm/sek."
+
+msgid "150dpi"
+msgstr "150 dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180 dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 tommer/sek."
+
+msgid "2-Sided Printing"
+msgstr "Dobbeltsidet udskrivning"
+
+msgid "2.00x0.37\""
+msgstr "2,00 x 0,37\""
+
+msgid "2.00x0.50\""
+msgstr "2,00 x 0,50\""
+
+msgid "2.00x1.00\""
+msgstr "2,00 x 1,00\""
+
+msgid "2.00x1.25\""
+msgstr "2,00 x 1,25\""
+
+msgid "2.00x2.00\""
+msgstr "2,00 x 2,00\""
+
+msgid "2.00x3.00\""
+msgstr "2,00 x 3,00\""
+
+msgid "2.00x4.00\""
+msgstr "2,00 x 4,00\""
+
+msgid "2.00x5.50\""
+msgstr "2,00 x 5,50\""
+
+msgid "2.25x0.50\""
+msgstr "2,25 x 0,50\""
+
+msgid "2.25x1.25\""
+msgstr "2,25 x 1,25\""
+
+msgid "2.25x4.00\""
+msgstr "2,25 x 4,00\""
+
+msgid "2.25x5.50\""
+msgstr "2,25 x 5,50\""
+
+msgid "2.38x5.50\""
+msgstr "2,38 x 5,50\""
+
+msgid "2.5 inches/sec."
+msgstr "2,5 tommer/sek."
+
+msgid "2.50x1.00\""
+msgstr "2,50 x 1,00\""
+
+msgid "2.50x2.00\""
+msgstr "2,50 x 2,00\""
+
+msgid "2.75x1.25\""
+msgstr "2,75 x 1,25\""
+
+msgid "2.9 x 1\""
+msgstr "2,9 x 1\""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 mm/sek."
+
+msgid "200 mm/sec."
+msgstr "200 mm/sek."
+
+msgid "203dpi"
+msgstr "203 dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "24-bens serien"
+
+msgid "240x72dpi"
+msgstr "240 x 72 dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 mm/sek."
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 tommer/sek."
+
+msgid "3.00x1.00\""
+msgstr "3,00 x 1,00\""
+
+msgid "3.00x1.25\""
+msgstr "3,00 x 1,25\""
+
+msgid "3.00x2.00\""
+msgstr "3,00 x 2,00\""
+
+msgid "3.00x3.00\""
+msgstr "3,00 x 3,00\""
+
+msgid "3.00x5.00\""
+msgstr "3,00 x 5,00\""
+
+msgid "3.25x2.00\""
+msgstr "3,25 x 2,00\""
+
+msgid "3.25x5.00\""
+msgstr "3,25 x 5,00\""
+
+msgid "3.25x5.50\""
+msgstr "3,25 x 5,50\""
+
+msgid "3.25x5.83\""
+msgstr "3,25 x 5,83\""
+
+msgid "3.25x7.83\""
+msgstr "3,25 x 7,83\""
+
+msgid "3.5\" Disk"
+msgstr "3,5\" disk"
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "3,5\" disk - 2 1/8 x 2 3/4\""
+
+msgid "3.50x1.00\""
+msgstr "3,50 x 1,00\""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 mm/sek."
+
+msgid "300 mm/sec."
+msgstr "300 mm/sek."
+
+msgid "300dpi"
+msgstr "300 dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360 dpi"
+
+msgid "360x180dpi"
+msgstr "360 x 180 dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 tommer/sek."
+
+msgid "4.00x1.00\""
+msgstr "4,00 x 1,00\""
+
+msgid "4.00x13.00\""
+msgstr "4,00 x 13,00\""
+
+msgid "4.00x2.00\""
+msgstr "4,00 x 2,00\""
+
+msgid "4.00x2.50\""
+msgstr "4,00 x 2,50\""
+
+msgid "4.00x3.00\""
+msgstr "4,00 x 3,00\""
+
+msgid "4.00x4.00\""
+msgstr "4,00 x 4,00\""
+
+msgid "4.00x5.00\""
+msgstr "4,00 x 5,00\""
+
+msgid "4.00x6.00\""
+msgstr "4,00 x 6,00\""
+
+msgid "4.00x6.50\""
+msgstr "4,00 x 6,50\""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 mm/sek."
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 tommer/sek."
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 tommer/sek."
+
+msgid "6.00x1.00\""
+msgstr "6,00 x 1,00\""
+
+msgid "6.00x2.00\""
+msgstr "6,00 x 2,00\""
+
+msgid "6.00x3.00\""
+msgstr "6,00 x 3,00\""
+
+msgid "6.00x4.00\""
+msgstr "6,00 x 4,00\""
+
+msgid "6.00x5.00\""
+msgstr "6,00 x 5,00\""
+
+msgid "6.00x6.00\""
+msgstr "6,00 x 6,00\""
+
+msgid "6.00x6.50\""
+msgstr "6,00 x 6,50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/sek."
+
+msgid "600dpi"
+msgstr "600 dpi"
+
+msgid "60dpi"
+msgstr "60 dpi"
+
+msgid "60x720dpi"
+msgstr "60 x 720 dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 tommer/sek."
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720 dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 tommer/sek."
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8,00 x 1,00\""
+
+msgid "8.00x2.00\""
+msgstr "8,00 x 2,00\""
+
+msgid "8.00x3.00\""
+msgstr "8,00 x 3,00\""
+
+msgid "8.00x4.00\""
+msgstr "8,00 x 4,00\""
+
+msgid "8.00x5.00\""
+msgstr "8,00 x 5,00\""
+
+msgid "8.00x6.00\""
+msgstr "8,00 x 6,00\""
+
+msgid "8.00x6.50\""
+msgstr "8,00 x 6,50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/sek."
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 tommer/sek."
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "9-bens serien"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?Ugyldig hjælpekommando ukendt\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (overstørrelse)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (overstørrelse)"
+
+msgid "A4 (Small)"
+msgstr "A4 (beskåret)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (overstørrelse)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "Accepter job"
+
+msgid "Accepted"
+msgstr "Accepteret"
+
+msgid "Add Class"
+msgstr "Tilføj klasse"
+
+msgid "Add Printer"
+msgstr "Tilføj printer"
+
+msgid "Add RSS Subscription"
+msgstr "Tilføj RSS-abonnement"
+
+msgid "Address"
+msgstr "Adresse"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "Adresse - 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "Administration"
+
+msgid "Always"
+msgstr "Altid"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "Bruger"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "Ugyldig NULL dests-markør"
+
+msgid "Bad OpenGroup"
+msgstr "Ugyldig OpenGroup"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "Ugyldig OpenUI/JCLOpenUI"
+
+msgid "Bad OrderDependency"
+msgstr "Ugyldig OrderDependency"
+
+msgid "Bad Request"
+msgstr "Ugyldig anmodning"
+
+msgid "Bad SNMP version number"
+msgstr "Ugyldigt versionsnummer på SNMP"
+
+msgid "Bad UIConstraints"
+msgstr "Ugyldig UIConstraints"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Ugyldig værdi for kopier %d."
+
+msgid "Bad custom parameter"
+msgstr "Ugylidig speciel parameter"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Ugyldig skriftattribut: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Ugyldig værdi for number-up %d."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Ugyldige værdier for page-ranges %d-%d."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Bannere"
+
+msgid "Billing Information: "
+msgstr "Faktureringsoplysninger: "
+
+msgid "Bond Paper"
+msgstr "Bond-papir"
+
+msgid "C0 Envelope"
+msgstr "C0-kuvert"
+
+msgid "C1 Envelope"
+msgstr "C1-kuvert"
+
+msgid "C2 Envelope"
+msgstr "C2-kuvert"
+
+msgid "C3 Envelope"
+msgstr "C3-kuvert"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "C4-kuvert"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "C5-kuvert"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "C6-kuvert"
+
+msgid "C65 Envelope"
+msgstr "C65-kuvert"
+
+msgid "C7 Envelope"
+msgstr "C7-kuvert"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "CPCL-etiketprinter"
+
+msgid "Cancel RSS Subscription"
+msgstr "Annuller RSS-abonnement"
+
+msgid "Change Settings"
+msgstr "Skift indstillinger"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Chou3-kuvert"
+
+msgid "Chou4 Envelope"
+msgstr "Chou4-kuvert"
+
+msgid "Classes"
+msgstr "Klasser"
+
+msgid "Clean Print Heads"
+msgstr "Rengør skrivehoveder"
+
+msgid "Color"
+msgstr "Farve"
+
+msgid "Color Mode"
+msgstr "Farvefunktion"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"Kommandoer kan være forkortet. Kommandoer er:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "Fællesnavn bruger uendelig længde"
+
+msgid "Continue"
+msgstr "Fortsæt"
+
+msgid "Continuous"
+msgstr "Fortsat"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Oprettet"
+
+msgid "Created On: "
+msgstr "Oprettet den: "
+
+msgid "Custom"
+msgstr "Speciel"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Klip"
+
+msgid "Cutter"
+msgstr "Klipper"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "DL-kuvert"
+
+msgid "Dark"
+msgstr "Mørk"
+
+msgid "Darkness"
+msgstr "Mørke"
+
+msgid "Delete Class"
+msgstr "Slet klasse"
+
+msgid "Delete Printer"
+msgstr "Slet printer"
+
+msgid "Description: "
+msgstr "Beskrivelse: "
+
+msgid "DeskJet Series"
+msgstr "DeskJet-serie"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "Destinationen \"%s\" accepterer ikke job."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"Enhed: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "Direkte termisk medie"
+
+msgid "Disabled"
+msgstr "Slået fra"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "Dokument %d findes ikke i job %d."
+
+msgid "Double Postcard"
+msgstr "Dobbelt postkort"
+
+msgid "Driver Name: "
+msgstr "Navn på printerarkiv: "
+
+msgid "Driver Version: "
+msgstr "Version på printerarkiv: "
+
+msgid "Duplexer"
+msgstr "Dupleksenhed"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: Kan ikke tildele hukommelse til sideinfo: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: Kan ikke tildele hukommelse til rækkefølge af sider: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "EPL1-etiketprinter"
+
+msgid "EPL2 Label Printer"
+msgstr "EPL2-etiketprinter"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: Ugyldigt tegnsætsarkiv %s\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: Ugyldig type på tegnsæt %s\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: Ugyldig linje til skriftbeskrivelse: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: Ugyldig tekstretning %s\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: Ugyldig tekstbredde %s\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: Fejl %d under afsendelse af PAPSendData-anmodning: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: Ingen skrifter i tegnsætsarkiv %s\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: Printer svarer ikke!\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: Printer sendte uventet EOF\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: Ekstern vært accepterede ikke kontrolarkiv (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: Ekstern vært accepterede ikke dataarkiv (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr ""
+"ERROR: Der opstod en timeout-fejl under afsendelse af data til printeren\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: Kan ikke føje arkivet %d til job: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: Kan ikke annullere jobbet %d: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: Kan ikke kopiere PDF-arkiv"
+
+msgid "ERROR: Unable to create pipe"
+msgstr ""
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: Kan ikke oprette socket"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr "ERROR: Kan ikke oprette midlertidigt komprimeret udskriftsarkiv: %s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: Kan ikke oprette midlertidigt arkiv"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: Kan ikke udføre pictwpstops: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: Kan ikke udføre gs-program"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: Kan ikke udføre pdftops-program"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: Kan ikke fork pictwpstops: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: Kan ikke hente PAP-anmodning"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: Kan ikke hente PAP-svar"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr "ERROR: Kan ikke hente PPD-arkiv til printeren \"%s\" - %s.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: Kan ikke hente AppleTalk-standardzone"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: Kan ikke søge efter PAP-svar"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: Kan ikke slå AppleTalk-printere op"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: Kan ikke oprette AppleTalk-adresse"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: Kan ikke åbne \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: Kan ikke åbne %s: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: Kan ikke åbne bannerarkiv \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: Kan ikke åbne enhedsarkivet \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: Kan ikke åbne arkivet \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: Kan ikke åbne arkivet \"%s\": %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: Kan ikke åbne udskriftarkivet \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: Kan ikke åbne udskriftsarkivet %s - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: Kan ikke åbne udskriftarkivet %s: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr "ERROR: Kan ikke åbne midlertidigt komprimeret udskriftsarkiv: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: Kan ikke læse udskriftsdata"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: Kan ikke reservere port"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: Kan ikke forsøge at forskyde %ld i arkiv - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: Kan ikke forsøge at forskyde %lld i arkiv - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: Kan ikke sende LPD-kommando"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: Kan ikke sende PAP tickle-anmodning"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: Kan ikke sende startanmodningen PAP send data"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: Kan ikke sende udskriftsarkiv til printer"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: Kan ikke sende udpunkteringsnul til printer"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: Kan ikke vente på pictwpstops: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: Kan ikke skrive %d byte til \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: Kan ikke skrive kontrolarkiv"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: Kan ikke skrive udskriftsdata"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: Kan ikke skrive udskriftsdata: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr "ERROR: Kan ikke skrive ukomprimerede dokumentdata: %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: Ukendt arkivrækkefølge \"%s\"\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: Ukendt formattegn \"%c\"\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: Ukendt udskriftsfunktion \"%s\"\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: select() mislykkedes"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: Kan ikke stat udskriftsarkiv"
+
+msgid "Edit Configuration File"
+msgstr "Rediger konfigurationsarkiv"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Slutbanner"
+
+msgid "English"
+msgstr "Danish"
+
+msgid "Enter old password:"
+msgstr "Skriv gammel adgangskode:"
+
+msgid "Enter password again:"
+msgstr "Skriv adgangskode igen:"
+
+msgid "Enter password:"
+msgstr "Skriv adgangskode:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Skriv dit brugernavn og din adgangskode eller root-brugernavnet og -"
+"adgangskoden for at få adgang til denne side. Hvis du bruger Kerberos-"
+"godkendelse, skal du sikre dig, at du har en gyldig Kerberos-billet."
+
+msgid "Envelope Feed"
+msgstr "Ilægning af kuvert"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Fejlpolitik"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "Hver 10. etiket"
+
+msgid "Every 2 Labels"
+msgstr "Hver 2. etiket"
+
+msgid "Every 3 Labels"
+msgstr "Hver 3. etiket"
+
+msgid "Every 4 Labels"
+msgstr "Hver 4. etiket"
+
+msgid "Every 5 Labels"
+msgstr "Hver 5. etiket"
+
+msgid "Every 6 Labels"
+msgstr "Hver 6. etiket"
+
+msgid "Every 7 Labels"
+msgstr "Hver 7. etiket"
+
+msgid "Every 8 Labels"
+msgstr "Hver 8. etiket"
+
+msgid "Every 9 Labels"
+msgstr "Hver 9. etiket"
+
+msgid "Every Label"
+msgstr "Alle etiketter"
+
+msgid "Expectation Failed"
+msgstr "Forventning mislykkedes"
+
+msgid "Export Printers to Samba"
+msgstr "Eksporter printere til Samba"
+
+msgid "FAIL\n"
+msgstr "FAIL\n"
+
+msgid "File Folder"
+msgstr "Arkivmappe"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Arkivmappe - 9/16 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"Arkivets enheds-URI'er er blevet slået fra! Du slår det til ved at se i "
+"FileDevice-direktivet i \"%s/cupsd.conf\"."
+
+msgid "Folio"
+msgstr "8,5 x 13\""
+
+msgid "Forbidden"
+msgstr "Forbudt"
+
+msgid "General"
+msgstr "Generelt"
+
+msgid "Generic"
+msgstr "Generel"
+
+msgid "German FanFold"
+msgstr "Tysk FanFold"
+
+msgid "German FanFold Legal"
+msgstr "Tysk FanFold, 8,5 x 14\""
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU bruger uendelig længde"
+
+msgid "Glossy Paper"
+msgstr "Glittet papir"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Gråtoner"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Hængende mappe"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Hængende mappe - 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk slået fra i Systemindstillinger\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk slået fra i Systemindstillinger.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: Annullerer udskriftsjob...\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: Sluttet til printer...\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: Opretter forbindelse til printer...\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: Kontrolarkiv sendt\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr ""
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: Dataarkiv sendt\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: Formaterer siden %d...\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: Indlæser billedarkivet...\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: Søger efter printer...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: Ã…bner forbindelse\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr "INFO: Udskriftsarkiv sendt, venter på, at printer bliver færdig...\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: Printer i brug; prøver igen om 10 sekunder...\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: Printer i brug; prøver igen om 30 sekunder...\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: Printer i brug; prøver igen om 5 sekunder...\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr "INFO: Printer understøtter ikke IPP/%d.%d, prøver IPP/1.0...\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: Printer i brug; prøver igen om 5 sekunder...\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: Printer er passiv.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: Printer er passiv.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: Printer er nu aktiv.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: Printer er passiv.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: Printer ikke tilsluttet; prøver igen om 30 sekunder...\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: Udskriver side %d, %d%% færdig...\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: Udskriver side %d...\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: Klar til at udskrive.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: Sender kontrolarkiv (%lu byte)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: Sender kontrolarkiv (%u byte)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: Sender data\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: Sender dataarkiv (%ld byte)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: Sender dataarkiv (%lld byte)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: Sender udskriftsdata...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: Sendt udskriftsarkiv, %ld byte...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: Sendt udskriftsarkiv, %lld byte...\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: Spoler LPR-job, %.0f%% færdig...\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr ""
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: Kan ikke kontakte printer, sætter job i kø på næste printer i "
+"klassen...\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: Bruger AppleTalk-standardzone \"%s\"\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: Venter på, at job bliver færdigt...\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: Venter på, at printer bliver tilgængelig...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "ISO B4-kuvert"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (overstørrelse)"
+
+msgid "ISO B5 Envelope"
+msgstr "ISO B5-kuvert"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "ISO B6-kuvert"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "Ulovligt kontroltegn"
+
+msgid "Illegal main keyword string"
+msgstr "Ulovlig streng til hovednøgleord"
+
+msgid "Illegal option keyword string"
+msgstr "Ulovlig nøgleordsstreng til indstilling"
+
+msgid "Illegal translation string"
+msgstr "Ulovlig oversættelsesstreng"
+
+msgid "Illegal whitespace character"
+msgstr "Ulovlig tegn for tom plads"
+
+msgid "Installable Options"
+msgstr "Ekstraudstyr"
+
+msgid "Installed"
+msgstr "Installeret"
+
+msgid "IntelliBar Label Printer"
+msgstr "IntelliBar-etiketprinter"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr ""
+
+msgid "Internal error"
+msgstr "Intern fejl"
+
+msgid "Internet Postage 2-Part"
+msgstr "Internet-porto 2-Part"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Internet-porto 2-Part - 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "Internet-porto 3-Part"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Internet-porto 3-Part - 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "Internet Printing Protocol"
+
+msgid "Invite Envelope"
+msgstr "Invite-kuvert"
+
+msgid "Italian Envelope"
+msgstr "Italiensk kuvert"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "Job #%d er allerede afbrudt - kan ikke annullere."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "Job #%d er allerede annulleret - kan ikke annullere."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "Job #%d er allerede færdigt - kan ikke annullere."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "Job færdigt"
+
+msgid "Job Created"
+msgstr "Job oprettet"
+
+msgid "Job ID: "
+msgstr "Job-id: "
+
+msgid "Job Options Changed"
+msgstr "Jobindstillinger ændret"
+
+msgid "Job Stopped"
+msgstr "Job stoppet"
+
+msgid "Job UUID: "
+msgstr "Job-uuid: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "Job er færdigt og kan ikke ændres."
+
+msgid "Job operation failed:"
+msgstr "Jobhandling mislykkedes:"
+
+msgid "Job state cannot be changed."
+msgstr "Jobstatus kan ikke ændres."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "Job"
+
+msgid "Kaku2 Envelope"
+msgstr "Kaku2-kuvert"
+
+msgid "Kaku3 Envelope"
+msgstr "Kaku3-kuvert"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "LPD/LPR-vært eller -printer"
+
+msgid "Label Printer"
+msgstr "Etiketprinter"
+
+msgid "Label Top"
+msgstr "Top af etiket"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Stor adresse"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Stor adresse - 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet Series PCL 4/5"
+
+msgid "Light"
+msgstr "Lys"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Linje længere end det maksimalt tilladte (255 tegn)"
+
+msgid "List Available Printers"
+msgstr "Vis tilgængelige printere"
+
+msgid "Location: "
+msgstr "Placering: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "Lang kant (stående)"
+
+msgid "Make and Model: "
+msgstr "Mærke og model: "
+
+msgid "Manual Feed"
+msgstr "Manuel ilægning"
+
+msgid "Media Dimensions: "
+msgstr "Mediestørrelser: "
+
+msgid "Media Limits: "
+msgstr "Mediebegrænsninger: "
+
+msgid "Media Name: "
+msgstr "Medienavn: "
+
+msgid "Media Size"
+msgstr "Mediestørrelse"
+
+msgid "Media Source"
+msgstr "Mediekilde"
+
+msgid "Media Tracking"
+msgstr "Mediesporing"
+
+msgid "Media Type"
+msgstr "Medietype"
+
+msgid "Medium"
+msgstr "Medium"
+
+msgid "Memory allocation error"
+msgstr "Fejl i hukommelsestildeling"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "Manglende PPD-Adobe-4.x header"
+
+msgid "Missing asterisk in column 1"
+msgstr "Manglende stjerne i kolonne 1"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "Manglende værdistreng"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "Rediger klasse"
+
+msgid "Modify Printer"
+msgstr "Rediger printer"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Monarch-kuvert"
+
+msgid "Move All Jobs"
+msgstr "Flyt alle job"
+
+msgid "Move Job"
+msgstr "Flyt job"
+
+msgid "Moved Permanently"
+msgstr "Flyttet permanent"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: Udskriftsarkiv accepteret - job-id %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: Udskriftsarkiv accepteret - job-id ukendt.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "NULL PPD-arkivmarkør"
+
+msgid "Name OID uses indefinite length"
+msgstr "Navn-oid bruger uendelig længde"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Aldrig"
+
+msgid "New Stylus Color Series"
+msgstr "Ny Stylus Color Series"
+
+msgid "New Stylus Photo Series"
+msgstr "Ny Stylus Photo Series"
+
+msgid "No"
+msgstr "Nej"
+
+msgid "No Content"
+msgstr "Intet indhold"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "Ingen VarBind SEQUENCE"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "Ingen aktiv forbindelse"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "Intet fællesskabsnavn"
+
+msgid "No default printer"
+msgstr "Ingen standardprinter"
+
+msgid "No destinations added."
+msgstr "Ingen destinationer tilføjet."
+
+msgid "No error-index"
+msgstr "Intet error-index"
+
+msgid "No error-status"
+msgstr "Ingen error-status"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "Ingen navn-oid"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "Ingen request-id"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "Ingen abonnementer fundet."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "Ingen variable-bindings SEQUENCE"
+
+msgid "No version number"
+msgstr "Intet versionsnummer"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "Ikke fortsat (mærkefølsom)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "Ikke fortsat (webfølsom)"
+
+msgid "Normal"
+msgstr "Normal"
+
+msgid "Not Found"
+msgstr "Ikke fundet"
+
+msgid "Not Implemented"
+msgstr "Ikke implementeret"
+
+msgid "Not Installed"
+msgstr "Ikke installeret"
+
+msgid "Not Modified"
+msgstr "Ikke ændret"
+
+msgid "Not Supported"
+msgstr "Ikke understøttet"
+
+msgid "Not allowed to print."
+msgstr "MÃ¥ ikke udskrive."
+
+msgid "Note"
+msgstr "Bemærk"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Off (1-Sided)"
+msgstr "Fra (ensidet)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Hjælp på skærmen"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "Ã¥bning af %s mislykkedes: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup uden en CloseGroup først"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI uden en CloseUI/JCLCloseUI først"
+
+msgid "Operation Policy"
+msgstr "Driftspolitik"
+
+msgid "Options Installed"
+msgstr "Ekstraudstyr installeret"
+
+msgid "Options: "
+msgstr "Ekstraudstyr: "
+
+msgid "Output Mode"
+msgstr "Udskriftsfunktion"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "Udskrifter til printer %s er sendt til %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr "Udskrifter til printer %s er sendt til ekstern printer %s på %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "Udskrifter til printer %s/%s er sendt til %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr "Udskrifter til printer %s/%s er sendt til ekstern printer %s på %s\n"
+
+msgid "PASS\n"
+msgstr "PASS\n"
+
+msgid "PCL Laser Printer"
+msgstr "PCL-laserprinter"
+
+msgid "PRC1 Envelope"
+msgstr "PRC1-kuvert"
+
+msgid "PRC10 Envelope"
+msgstr "PRC10-kuvert"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "PRC2-kuvert"
+
+msgid "PRC3 Envelope"
+msgstr "PRC3-kuvert"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (overstørrelse)"
+
+msgid "PRC4 Envelope"
+msgstr "PRC4-kuvert"
+
+msgid "PRC5 Envelope"
+msgstr "PRC5-kuvert"
+
+msgid "PRC6 Envelope"
+msgstr "PRC6-kuvert"
+
+msgid "PRC7 Envelope"
+msgstr "PRC7-kuvert"
+
+msgid "PRC8 Envelope"
+msgstr "PRC8-kuvert"
+
+msgid "PRC9 Envelope"
+msgstr "PRC9-kuvert"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "Pakke indeholder ikke en Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "Pakke starter ikke med SEQUENCE"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "Adgangskode til %s på %s? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "Adgangskode til %s kræves til adgang til %s via SAMBA: "
+
+msgid "Pause Class"
+msgstr "Sæt klasse på pause"
+
+msgid "Pause Printer"
+msgstr "Sæt printer på pause"
+
+msgid "Peel-Off"
+msgstr "Aftrækkelig"
+
+msgid "Personal Envelope"
+msgstr "Personlig kuvert"
+
+msgid "Photo"
+msgstr "Foto"
+
+msgid "Photo Labels"
+msgstr "Fotoetiketter"
+
+msgid "Plain Paper"
+msgstr "Almindeligt papir"
+
+msgid "Policies"
+msgstr "Politikker"
+
+msgid "Port Monitor"
+msgstr "Portovervågning"
+
+msgid "PostScript Printer"
+msgstr "PostScript-printer"
+
+msgid "Postcard"
+msgstr "Postkort"
+
+msgid "Print Density"
+msgstr "Tryktæthed"
+
+msgid "Print Job:"
+msgstr "Udskriftsjob:"
+
+msgid "Print Mode"
+msgstr "Udskriftsfunktion"
+
+msgid "Print Rate"
+msgstr "Udskriftshastighed"
+
+msgid "Print Self-Test Page"
+msgstr "Udskriv testside"
+
+msgid "Print Speed"
+msgstr "Udskriftshastighed"
+
+msgid "Print Test Page"
+msgstr "Udskriv testside"
+
+msgid "Print and Cut"
+msgstr "Udskriv og klip"
+
+msgid "Print and Tear"
+msgstr "Udskriv og riv af"
+
+msgid "Printed For: "
+msgstr "Udskrevet til: "
+
+msgid "Printed From: "
+msgstr "Udskrevet fra: "
+
+msgid "Printed On: "
+msgstr "Udskrevet den: "
+
+msgid "Printer Added"
+msgstr "Printer tilføjet"
+
+msgid "Printer Default"
+msgstr "Printerstandard"
+
+msgid "Printer Deleted"
+msgstr "Printer slettet"
+
+msgid "Printer Modified"
+msgstr "Printer ændret"
+
+msgid "Printer Name: "
+msgstr "Printernavn: "
+
+msgid "Printer Paused"
+msgstr "Printer på pause"
+
+msgid "Printer Settings"
+msgstr "Printerindstillinger"
+
+msgid "Printer:"
+msgstr "Printer:"
+
+msgid "Printers"
+msgstr "Printere"
+
+msgid "Purge Jobs"
+msgstr "Udrens job"
+
+msgid "Quarto"
+msgstr "Kvartformat"
+
+msgid "Quota limit reached."
+msgstr "Maks. kvote nået."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr "Grad Ejer Job Arkiv(er) Str. i alt\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"Grad Ejer Pri Job Arkiver Str. i alt\n"
+
+msgid "Reject Jobs"
+msgstr "Afvis job"
+
+msgid "Reprint After Error"
+msgstr "Udskriv igen efter fejl"
+
+msgid "Request Entity Too Large"
+msgstr "Enhedsanmodning for stor"
+
+msgid "Resolution"
+msgstr "Opløsning"
+
+msgid "Resume Class"
+msgstr "Genoptag klasse"
+
+msgid "Resume Printer"
+msgstr "Genoptag printer"
+
+msgid "Return Address"
+msgstr "Returadresse"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Returadresse - 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "Spol tilbage"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Aktiv kommando: %s %s -N -A %s -c '%s'\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE bruger uendelig længde"
+
+msgid "See Other"
+msgstr "Se andet"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "Seriel port #%d"
+
+msgid "Server Restarted"
+msgstr "Server startet igen"
+
+msgid "Server Security Auditing"
+msgstr "Kontrol af serversikkerhed"
+
+msgid "Server Started"
+msgstr "Server startet"
+
+msgid "Server Stopped"
+msgstr "Server stoppet"
+
+msgid "Service Unavailable"
+msgstr "Service utilgængelig"
+
+msgid "Set Allowed Users"
+msgstr "Indstil tilladte brugere"
+
+msgid "Set As Server Default"
+msgstr "Indstil som serverstandard"
+
+msgid "Set Class Options"
+msgstr "Foretag klasseindstillinger "
+
+msgid "Set Printer Options"
+msgstr "Foretag printerindstillinger "
+
+msgid "Set Publishing"
+msgstr "Indstil publicering"
+
+msgid "Shipping Address"
+msgstr "Leveringsadresse"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "Leveringsadresse - 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "Kort kant (liggende)"
+
+msgid "Special Paper"
+msgstr "Specielt papir"
+
+msgid "Standard"
+msgstr "Standard"
+
+msgid "Starting Banner"
+msgstr "Starter banner"
+
+msgid "Statement"
+msgstr "Udtalelse"
+
+msgid "Stylus Color Series"
+msgstr "Stylus Color Series"
+
+msgid "Stylus Photo Series"
+msgstr "Stylus Photo Series"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "Skifter protokoller"
+
+msgid "Tabloid"
+msgstr "17 x 11\""
+
+msgid "Tabloid (Oversize)"
+msgstr "17 x 11\" (overstørrelse)"
+
+msgid "Tear"
+msgstr "Riv"
+
+msgid "Tear-Off"
+msgstr "Riv af"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Riv af, juster position"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "PPD-arkivet \"%s\" findes ikke."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "PPD-arkivet \"%s\" kunne ikke åbnes: %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Klassenavnet må kun indeholde op til 127 tegn, der kan udskrives, og må ikke "
+"indeholde mellemrum, skråstreger (/) og nummertegnet (#)."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr "Egenskaben notify-lease-duration kan ikke bruges med jobabonnementer."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Printernavnet må kun indeholde op til 127 tegn, der kan udskrives, og må "
+"ikke indeholde mellemrum, skråstreger (/) og nummertegnet (#)."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "Printeren eller klassen findes ikke."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "Printer-uri \"%s\" indeholder ugyldige tegn."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr "Printer-uri skal have formatet \"ipp://VÆRTSNAVN/klasser/KLASSENAVN\"."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+"Printer-uri skal have formatet \"ipp://VÆRTSNAVN/printere/PRINTERNAVN\"."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"Abonnementsnavnet må ikke indeholde mellemrum, skråstreger (/), "
+"spørgsmålstegn (?) og nummertegnet (#)."
+
+msgid "There are too many subscriptions."
+msgstr "Der er for mange abonnementer."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "Termiske overførselsmedier"
+
+msgid "Title: "
+msgstr "Titel: "
+
+msgid "Too many active jobs."
+msgstr "For mange aktive job."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "Gennemsigtighed"
+
+msgid "Tray"
+msgstr "Bakke"
+
+msgid "Tray 1"
+msgstr "Bakke 1"
+
+msgid "Tray 2"
+msgstr "Bakke 2"
+
+msgid "Tray 3"
+msgstr "Bakke 3"
+
+msgid "Tray 4"
+msgstr "Bakke 4"
+
+msgid "URI Too Long"
+msgstr "URI for lang"
+
+msgid "US Executive"
+msgstr "7,25 x 10,5\""
+
+msgid "US Fanfold"
+msgstr "Amerikansk fanfold"
+
+msgid "US Ledger"
+msgstr "17 x 11\""
+
+msgid "US Legal"
+msgstr "8,5 x 14\""
+
+msgid "US Legal (Oversize)"
+msgstr "8,5 x 14\" (overstørrelse)"
+
+msgid "US Letter"
+msgstr "8,5 x 11\""
+
+msgid "US Letter (Oversize)"
+msgstr "8,5 x 11\" (overstørrelse)"
+
+msgid "US Letter (Small)"
+msgstr "8,5 x 11\" (beskåret)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "Seriel USB-port #%d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "Kan ikke få adgang til arkivet cupsd.conf:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "Kan ikke tilføje RSS-abonnement:"
+
+msgid "Unable to add class:"
+msgstr "Kan ikke tilføje klasse:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "Kan ikke tilføje printer:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "Kan ikke annullere RSS-abonnement:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "Kan ikke ændre egenskaben printer-is-shared:"
+
+msgid "Unable to change printer:"
+msgstr "Kan ikke skifte printer:"
+
+msgid "Unable to change server settings:"
+msgstr "Kan ikke ændre serverindstillinger:"
+
+msgid "Unable to connect to host."
+msgstr "Kan ikke oprette forbindelse til vært."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "Kan ikke oprette midlertidigt arkiv:"
+
+msgid "Unable to delete class:"
+msgstr "Kan ikke slette klasse:"
+
+msgid "Unable to delete printer:"
+msgstr "Kan ikke slette printer:"
+
+msgid "Unable to do maintenance command:"
+msgstr "Kan ikke udføre vedligeholdelseskommando:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "Kan ikke hente klasseliste:"
+
+msgid "Unable to get class status:"
+msgstr "Kan ikke hente klassestatus:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "Kan ikke hente liste over printerarkiver:"
+
+msgid "Unable to get printer attributes:"
+msgstr "Kan ikke hente printerattributter:"
+
+msgid "Unable to get printer list:"
+msgstr "Kan ikke hente printerliste:"
+
+msgid "Unable to get printer status:"
+msgstr "Kan ikke hente printerstatus:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "Kan ikke ændre klasse:"
+
+msgid "Unable to modify printer:"
+msgstr "Kan ikke ændre printer:"
+
+msgid "Unable to move job"
+msgstr "Kan ikke flytte job"
+
+msgid "Unable to move jobs"
+msgstr "Kan ikke flytte job"
+
+msgid "Unable to open PPD file"
+msgstr "Kan ikke åbne PPD-arkiv"
+
+msgid "Unable to open PPD file:"
+msgstr "Kan ikke åbne PPD-arkiv:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "Kan ikke åbne arkivet cupsd.conf:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "Kan ikke udskrive testside:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "Kan ikke afvikle \"%s\": %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "Kan ikke foretageindstillinger:"
+
+msgid "Unable to set server default:"
+msgstr "Kan ikke indstille serverstandard:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "Kan ikke overføre arkivet cupsd.conf:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "Ikke godkendt"
+
+msgid "Units"
+msgstr "Enheder"
+
+msgid "Unknown"
+msgstr "Ukendt"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "Ukendt printer-error-policy \"%s\"."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "Ukendt printer-op-policy \"%s\"."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Ikke understøttet værditype"
+
+msgid "Upgrade Required"
+msgstr "Opgradering kræves"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Brug:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "Brug: %s job user title copies options [filename]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "Brug: %s job-id user title copies options [file]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "Brug: %s job-id user title copies options file\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Brug: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Indstillinger:\n"
+" -E Krypter forbindelsen til serveren\n"
+" -H samba-server Brug den navngivne SAMBA-server\n"
+" -U samba-user Godkend vha. den navngivne SAMBA-bruger\n"
+" -a Eksporter alle printere\n"
+" -h cups-server Brug den navngivne CUPS-server\n"
+" -v Vær detaljeret (vis kommandoer)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Brug: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Indstillinger:\n"
+"\n"
+" -E Slå kryptering til\n"
+" -U brugernavn Angiv brugernavn\n"
+" -h server[:port] Angiv serveradresse\n"
+"\n"
+" --[no-]debug-logging Slå fejlfindingslog til/fra\n"
+" --[no-]remote-admin Slå ekstern administration til/fra\n"
+" --[no-]remote-any Tillad/afvis adgang fra Internet\n"
+" --[no-]remote-printers Vis/skjul eksterne printere\n"
+" --[no-]share-printers Slå printerdeling til/fra\n"
+" --[no-]user-cancel-any Brugere må/må ikke annullere alle job\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Brug: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Indlæs alternativt konfigurationsarkiv\n"
+"-f Afvikl i forgrunden\n"
+"-F Afvikl i baggrunden, men fjern\n"
+"-h Vis denne brugsmeddelelse\n"
+"-l Start cupsd fra startd(8)\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Brug: cupstestdsc [options] arkivnavn.ps [... arkivnavn.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Indstillinger:\n"
+"\n"
+" -h Vis programbrug\n"
+"\n"
+" Bemærk: Dette program godkender kun DSC-kommentarer, ikke selve "
+"PostScript.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Brug: lpmove job/src dest\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Brug: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Brug: lppasswd [-g groupname]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Brug: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Brug: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Brug: ppdc [options] arkivnavn.drv [ ... arkivnavnN.drv ]\n"
+"Indstillinger:\n"
+" -D name=value Indstil navngiven variabel til værdi.\n"
+" -I include-dir Tilføj inkluder bibliotek i søgesti.\n"
+" -c catalog.po Indlæs det anførte beskedkatalog.\n"
+" -d output-dir Angiv resultatbiblioteket.\n"
+" -l lang[,lang,...] Angiv resultatsproget(-sprogene) (locale).\n"
+" -m Brug ModelName-værdien som arkivnavnet.\n"
+" -t Test PPD'er i stedet for at generere dem.\n"
+" -v Vær detaljeret (flere v'er giver flere detaljer).\n"
+" -z Komprimer PPD-arkiver vha. GNU zip.\n"
+" --cr Afslut linjer med CR (Mac OS 9).\n"
+" --crlf Afslut linjer med CR + LF (Windows).\n"
+" --lf Afslut linjer med LF (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"Brug: ppdhtml [options] arkivnavn.drv >arkivnavn.html\n"
+" -D name=value Indstil navngiven variabel til værdi.\n"
+"Indstillinger:\n"
+" -I include-dir Tilføj inkluder bibliotek i søgesti.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Brug: ppdi [options] arkivnavn.ppd [ ... arkivnavnN.ppd ]\n"
+"Indstillinger:\n"
+" -I include-dir\n"
+" -o arkivnavn.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Brug: ppdmerge [options] arkivnavn.ppd [ ... arkivnavnN.ppd ]\n"
+"Indstillinger:\n"
+" -o arkivnavn.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"Brug: ppdpo [options] -o arkivnavn.po arkivnavn.drv [ ... arkivnavnN.drv ]\n"
+"Indstillinger:\n"
+" -D name=value Indstil navngiven variabel til værdi.\n"
+" -I include-dir Tilføj inkluder bibliotek i søgesti.\n"
+" -v Vær detaljeret (flere v'er giver flere detaljer).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Brug: snmp [host-or-ip-address]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Værdi bruger uendelig længde"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind bruger uendelig længde"
+
+msgid "Version uses indefinite length"
+msgstr "Version bruger uendelig længde"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: Tilføjer kun de første %d fundne printere"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: Boolesk forventet for indstillingen waiteof \"%s\"\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: Printer svarer ikke!\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: Printer sendte uventet EOF\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: Kan ikke åbne \"%s:%s\": %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: Kan ikke sende PAP status-anmodning"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: Uventet PAP-pakke af typen %d\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: Ukendt PAP-pakke af typen %d\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: tal forventet for indstillingen status \"%s\"\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Ja"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"Du skal åbne denne side vha. URL-adressen <A HREF=\"https://%s:%d%s"
+"\">https://%s:%d%s</A>."
+
+msgid "You4 Envelope"
+msgstr "You4-kuvert"
+
+msgid "ZPL Label Printer"
+msgstr "ZPL-etiketprinter"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "afbrudt"
+
+msgid "canceled"
+msgstr "annulleret"
+
+msgid "completed"
+msgstr "færdig"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr ""
+"konverter: Brug indstillingen -f til at anføre et arkiv, der skal "
+"konverteres.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "cups-deviced blev ikke udført."
+
+msgid "cups-driverd failed to execute."
+msgstr "cups-driverd blev ikke udført."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: Intet PPD-arkiv til printeren \"%s\" - %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: Kan ikke oprette forbindelse til server: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr ""
+"cupsd: launchd(8)-understøttelse ikke medkompileret, afvikles i normal "
+"funktion.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: Kan ikke hente jobarkiv - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr ""
+"cupstestppd: Indstillingen -q er ikke kompatibel med indstillingen -v.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr ""
+"cupstestppd: Indstillingen -v er ikke kompatibel med indstillingen -q.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "enhed til %s/%s: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "enhed til %s: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "error-index bruger uendelig længde"
+
+msgid "error-status uses indefinite length"
+msgstr "error-status bruger uendelig længde"
+
+msgid "held"
+msgstr "udsat"
+
+msgid "help\t\tget help on commands\n"
+msgstr "hjælp\t\tfå hjælp til kommandoer"
+
+msgid "idle"
+msgstr "ledig"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: Printeren %s er allerede medlem af klassen %s.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: Printeren %s er ikke medlem af klassen %s.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: Kan ikke oprette forbindelse til server: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: Kan ikke åbne PPD-arkivet \"%s\" - %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: Kan ikke åbne arkivet \"%s\": %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: Kan ikke oprette forbindelse til server: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: Kan ikke tilføje printer eller tilfælde: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: Kan ikke hente PPD-arkivet til %s: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: Beklager, adgangskode afvist. Adgangskoden skal bestå af mindst 6 "
+"tegn, må ikke indeholde dit brugernavn og skal indeholde mindst et bogstav "
+"og et tal.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: Kan ikke kopiere adgangskodestreng: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: Kan ikke åbne adgangskodearkiv: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: Kan ikke skrive til adgangskodearkiv: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr "lppasswd: kunne ikke sikkerhedskopiere gammelt adgangskodearkiv: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: kunne ikke omdøbe adgangskodearkiv: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: brugeren \"%s\" og gruppen \"%s\" findes ikke.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "medlemmer af klassen %s:\n"
+
+msgid "no entries\n"
+msgstr "ingen optegnelser"
+
+msgid "no system default destination\n"
+msgstr "ingen standarddestination til system"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "afventer"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: Tilføjer inkluder bibliotek \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: Tilføjer/opdaterer ui-tekst fra %s...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: Ugyldig booleesk værdi (%s) på linje %d af %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: Ugyldig variabelerstatning ($%c) på linje %d af %s.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: Forventede booleesk værdi på linje %d af %s.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: Forventede valgkode på linje %d af %s.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: Forventede valgnavn/-tekst på linje %d af %s.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: Indlæser oplysningsarkiv til printerarkiv \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: Indlæser beskeder til lokalitet \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: Indlæser beskeder fra \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: Kan ikke oprette PPD-arkivet \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: Kan ikke oprette resultatbibliotek %s: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: Kan ikke oprette resultatrør: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: Kan ikke udføre cupstestppd: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: Kan ikke finde lokalisering for \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: Kan ikke indlæse lokaliseringsarkivet \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: Udefineret variabel (%s) på linje %d af %s.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: Skriver %s...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: Skriver PPD-arkiver til bibliotek \"%s\"...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: Ignorerer PPD-arkiv %s...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: Kan ikke sikkerhedskopiere %s til %s- %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "printeren %s slået fra siden %s -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "printeren %s er ledig. Slået til siden %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "printeren %s udskriver nu %s-%d. Slået til siden %s\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "printeren %s/%s slået fra siden %s -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "printeren %s/%s er ledig. Slået til siden %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "printeren %s/%s udskriver nu %s-%d. Slået til siden %s\n"
+
+msgid "processing"
+msgstr "behandler"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "anmodnings-id er %s-%d (%d arkiv(er))\n"
+
+msgid "request-id uses indefinite length"
+msgstr "request-id bruger uendelig længde"
+
+msgid "scheduler is not running\n"
+msgstr "planlægger er ikke aktiv\n"
+
+msgid "scheduler is running\n"
+msgstr "planlægger er aktiv\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "stat af %s mislykkedes: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "status\t\tvis status for daemon og kø\n"
+
+msgid "stopped"
+msgstr "stoppet"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "standarddestination til system: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "standarddestination til system: %s/%s\n"
+
+msgid "unknown"
+msgstr "ukendt"
+
+msgid "untitled"
+msgstr "uden navn"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindings bruger uendelig længde"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " WARN %s har ingen tilsvarende indstillinger!\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " WARN Standardvalg er i konflikt!\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " WARN Nøgleordet til dupleksindstillingen %s virker muligvis "
+#~ "ikke som forventet og skal hedde Dupleks!\n"
+#~ " REF: Side 122, afsnit 5.17.\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " WARN Arkiv indeholder en blanding af linjeskifttyperne CR, LF og "
+#~ "CR LF!\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " WARN Linje %d indeholder kun tom plads!\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " WARN Manglende APDialogExtension-arkiv \"%s\"\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " WARN Manglende APPrinterIconPath-arkiv \"%s\"\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " WARN PPD-arkiver, som ikke stammer fra Windows, må kun bruge "
+#~ "linjeskifttypen LF, ikke CR LF!\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " WARN Forældet PPD-version %.1f!\n"
+#~ " REF: Side 42, afsnit 5.2.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s eksisterer ikke!\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s Ugyldigt %s-valg %s!\n"
+#~ " REF: Side 122, afsnit 5.17.\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr ""
+#~ " %s Ugyldig UTF-8 \"%s\"-oversættelsesstreng til indstillingen %s!\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Ugyldig UTF-8 \"%s\"-oversættelsesstreng til indstillingen %s, "
+#~ "valg %s!\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Ugyldig cupsFilter-værdi \"%s\"!\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s Ugyldig cupsICCProfile %s!\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Ugyldig cupsPreFilter-værdi \"%s\"!\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Ugyldig cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s Ugyldigt sprog \"%s\"!\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s Tom cupsUIConstraints %s!\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr ""
+#~ " %s Manglende \"%s\"-oversættelsesstreng til indstillingen %s!\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Manglende \"%s\"-oversættelsesstreng til indstillingen %s, valg "
+#~ "%s!\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Manglende valg *%s %s i UIConstraints \"*%s %s *%s %s\"!\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Manglende valg *%s %s i cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s Manglende cupsICCProfile-arkiv \"%s\"!\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s Manglende cupsUIResolver %s!\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Manglende indstilling %s i UIConstraints \"*%s %s *%s %s\"!\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr ""
+#~ " %s Manglende indstilling %s i cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr ""
+#~ " %s Ingen basisoversættelse af \"%s\" er inkluderet i arkiv!\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s REQUIRED %s definerer ikke valget Ingen!\n"
+#~ " REF: Side 122, afsnit 5.17.\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " %s cupsICCProfile %s-talværdi kolliderer med %s!\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver %s forårsager en sløjfe!\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** %s navne på valg %s og %s adskilles kun af brugen af "
+#~ "store/små bogstaver!\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **FAIL** %s skal være 1284DeviceID!\n"
+#~ " REF: Side 72, afsnit 5.5.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** UGYLDIGT DefaultImageableArea %s!\n"
+#~ " REF: Side 102, afsnit 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** UGYLDIG DefaultPaperDimension %s!\n"
+#~ " REF: Side 103, afsnit 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **FAIL** Ugyldigt %s-valg %s!\n"
+#~ " REF: Side 84, afsnit 5.9.\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr ""
+#~ " **FAIL** Ugyldig LanguageEncoding %s - skal være ISOLatin1!\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr " **FAIL** Ugyldig LanguageVersion %s - skal være dansk!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **FAIL** Standardoversættelsesstreng til indstillingen %s, valg %"
+#~ "s, indeholder 8 bit tegn!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **FAIL** Standardoversættelsesstreng til indstillingen %s "
+#~ "indeholder 8 bit tegn!\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Gruppenavne %s og %s adskilles kun af brugen af store/små "
+#~ "bogstaver!\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **FAIL** Flere forekomster af %s valg af navn %s!\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Navne på indstillinger %s og %s adskilles kun af brugen "
+#~ "af store/små bogstaver!\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " Ugyldig %%%%BoundingBox: på linje %d!\n"
+#~ " REF: Side 39, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " Ugyldig %%%%Page: på linje %d!\n"
+#~ " REF: Side 53, %%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " Ugyldige %%%%Pages: på linje %d!\n"
+#~ " REF: Side 43, %%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " Linje %d er på mere end 255 tegn (%d)!\n"
+#~ " REF: Side 25, Linjelængde\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " Manglende %!PS-Adobe-3.0 på første linje!\n"
+#~ " REF: Side 17, 3.1 Overensstemmende dokumenter\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " Manglende %%EndComments-kommentar!\n"
+#~ " REF: Side 41, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " Manglende eller ugyldig %%BoundingBox: kommentar!\n"
+#~ " REF: Side 39, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " Manglende eller ugyldig %%Page: kommentarer!\n"
+#~ " REF: Side 53, %%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " Manglende eller ugyldig %%Pages: kommentar!\n"
+#~ " REF: Side 43, %%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " SÃ¥ %d linjer, der overskred 255 tegn!\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " For mange %%BeginDocument-kommentarer!\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " For mange %%EndDocument-kommentarer!\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " Advarsel: Arkiv indeholder binære data!\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " Advarsel: Ingen %%EndComments-kommentar i arkiv!\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " Advarsel: Forældet DSC-version %.1f i arkiv!\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s ikke understøttet!"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: Ved ikke, hvad jeg skal gøre!\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: Fejl - %s-miljøvariabel navngiver ikke eksisterende destination \"%s"
+#~ "\"!\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: Fejl - ugyldig job-id!\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr "%s: Fejl - kan ikke udskrive arkiver og ændre job på samme tid!\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: Fejl - kan ikke udskrive fra stdin, hvis der leveres arkiver eller en "
+#~ "job-id!\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: Fejl - forventede tegnsæt efter indstillingen '-S'!\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: Fejl - forventede indholdstype efter indstillingen '-T'!\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: Fejl - forventede kopier efter indstillingen '-n'!\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s: Fejl - forventede antal kopier efter indstillingen '-#'!\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: Fejl - forventede destination efter indstillingen '-P'!\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: Fejl - forventede destination efter indstillingen '-b'!\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: Fejl - forventede destination efter indstillingen '-d'!\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: Fejl - forventede formular efter indstillingen '-f'!\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: Error - forventede udsat navn efter indstillingen '-H'!\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: Error - forventede værtsnavn efter indstillingen '-H'!\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: Error - forventede værtsnavn efter indstillingen '-H'!\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: Error - forventede funktionsliste efter indstillingen '-y'!\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: Error - forventede navn efter indstillingen '-%c'!\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr ""
+#~ "%s: Error - forventede alternativ streng efter indstillingen '-o'!\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: Error - forventede sideliste efter indstillingen '-P'!\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: Error - forventede prioritet efter indstillingen '-%c'!\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s: Fejl - forventede årsagstekst efter indstillingen '-r'!\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: Error - forventede titel efter indstillingen '-t'!\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s: Error - forventede brugernavn efter indstillingen '-U'!\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s: Error - forventede brugernavn efter indstillingen '-u'!\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: Error - forventede værdi efter indstillingen '-%c'!\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: Fejl - skal have \"completed\", \"not-completed\" eller \"all\" efter "
+#~ "indstillingen '-W'!\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: Fejl - planlægger svarer ikke!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: Fejl - ukendt destination \"%s\"!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: Fejl - ukendt destination \"%s/%s\"!\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: Fejl - ukendt indstilling '%c'!\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: Fejl - ukendt indstilling '%s'!\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: Forventede job-id efter indstillingen '-i'!\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: Ugyldigt destinationsnavn på listen \"%s\"!\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr "%s: Skal have job-id ('-i jobid') før '-H restart'!\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: Intet filter til konvertering fra %s/%s til %s/%s!\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr ""
+#~ "%s: Beklager, der er ikke medkompileret krypteringsunderstøttelse!\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: Kan ikke kontakte server!\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: Kan ikke bestemme MIME-typen på \"%s\"!\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s: Kan ikke åbne %s - %s\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s: Kan ikke åbne %s - %s på linje %d.\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s: Kan ikke læse MIME-database fra \"%s\" eller \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: Ukendt destination \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: Ukendt destination på MIME-typen \"%s/%s\"!\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: Ukendt indstilling '%c'!\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: Ukendt kilde på MIME-typen %s/%s!\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: Advarsel - '%c'-formatmodifikation ikke understøttet - resultat "
+#~ "muligvis ikke korrekt!"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: Advarsel - indstillingen tegnsæt ignoreret!\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: Advarsel - indstillingen indholdstype ignoreret!\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: Advarsel - indstillingen formular ignoreret!\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: Advarsel - indstillingen funktion ignoreret!\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: Fejl - %s-miljøvariabel navngiver ikke eksisterende destination \"%s"
+#~ "\"!\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: Fejl - forventede option=value efter indstillingen '-o'!\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "600 dpi gråtoner"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr "Der kræves en Samba-adgangskode til eksport af printerarkiver!"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr "Der kræves et Samba-brugernavn til eksport af printerarkiver!"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "Der findes allerede en klasse kaldet \"%s\"!"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "Der findes allerede en printer kaldet \"%s\"!"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr "Forsøger at indstille %s-printer-state til ugyldig værdi %d!"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "Egenskabsgrupper er ikke i rækkefølge (%x < %x)!"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "Ugyldig enheds-URI \"%s\"!\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "Ugyldig device-uri \"%s\"!"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "Ugyldig device-uri-plan \"%s\"!"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "Ugyldigt document-format \"%s\"!"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Ugyldig arkivnavnebuffer!"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Ugyldig værdi for job-priority!"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Ugyldig værdi for job-sheets \"%s\"!"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Ugyldig værditype på job-sheets!"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Ugyldig værdi for job-state!"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Ugyldig egenskab for job-uri \"%s\"!"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "Ugyldig notify-pull-method \"%s\"!"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "Ugyldig notify-recipient-uri URI \"%s\"!"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "Ugyldig indstilling + valg på linje %d!"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "Ugyldig port-monitor \"%s\"!"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Ugyldig værdi for printer-state %d!"
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "Ugyldigt versionsnummer på anmodning %d.%d!"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "Ugyldig abonnements-id!"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "Tegnsættet \"%s\" understøttes ikke!"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "Kunne ikke scanne typen \"%s\"!"
+
+#~ msgid "Cover open."
+#~ msgstr "Dæksel åbent."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "Fremkalder næsten tom."
+
+#~ msgid "Developer empty!"
+#~ msgstr "Fremkalder tom!"
+
+#~ msgid "Door open."
+#~ msgstr "Dæksel åbent."
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Ugyldig %%BoundingBox: Kommentar set!\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: Ugyldig %%IncludeFeature: Kommentar!\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: Ugyldig %%Page: Kommentar i arkiv!\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: Ugyldig %%PageBoundingBox: Kommentar i arkiv!\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: Ugyldigt SCSI-enhedsarkiv \"%s\"!\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: Ugyldig kolonneværdi %d!\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: Ugyldig cpi-værdi %f!\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: Ugyldig lpi-værdi %f!\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: Ugyldigt sidelayout!\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: Destinationsprinter findes ikke!\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Dubleret %%BoundingBox: Kommentar set!\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: Dublerede %%Pages: Kommentar set!\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: Tomt udskriftsarkiv!\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr "ERROR: Forventede streng med anførselstegn på linje %d af %s!\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: Uoprettelig USB-fejl!\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr "ERROR: Ugyldig HP-GL/2-kommando set, kan ikke udskrive arkiv!\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: Manglende %%EndProlog!\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: Manglende %%EndSetup!\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Manglende enheds-URI på kommandolinjen og ingen DEVICE_URI-"
+#~ "miljøvariabel!\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: Manglende værdi på linje %d i bannerarkiv!\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: Kræver en msgid-linje før evt. oversætterstrenge på linje %d i %"
+#~ "s!\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: Ingen %%BoundingBox: Kommentar i header!\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: Ingen %%Pages: Kommentar i header!\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Ingen enheds-URI fundet i argv[0] eller i DEVICE_URI-"
+#~ "miljøvariabel!\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: Ingen sider fundet!\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: Ikke mere papir!\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: PRINTER-miljøvariabel ikke defineret!\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: Udskriftsarkiv blev ikke accepteret (%s)!\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: Printer svarer ikke!\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: Kan ikke oprette midlertidigt arkiv - %s.\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: Kan ikke oprette midlertidigt arkiv: %s\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: Kan ikke hente attributter til jobbet %d (%s)!\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: Kan ikke hente printerstatus (%s)!\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: Kan ikke finde printeren '%s'!\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: Kan ikke åbne billedarkiv til udskrivning!\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: Kan ikke åbne midlertidigt arkiv"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: Kan ikke udskrive %d tekstspalter!\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: Kan ikke udskrive %dx%d tekstside!\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: Kan ikke læse udskriftsdata!\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: Kan ikke sende udskriftsdata (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: Kan ikke sende udskriftsdata!\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: Kan ikke skrive %d byte til printer!\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr "ERROR: Kan ikke skrive rasterdata til driver!\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: Kan ikke skrive til midlertidigt arkiv"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: Uventet tekst på linje %d af %s!\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: Ukendt værdi i krypteringsindstilling \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: Ukendt beskedkatalogformat til \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: Ukendt indstilling \"%s\" med værdien \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: Ukendt værdi på versionsindstilling \"%s\"!\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr ""
+#~ "ERROR: Værdi for lysstyrke %s ikke understøttet, bruger lysstyrke=100!\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: Værdi for gamma %s ikke understøttet, bruger gamma=1000!\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr ""
+#~ "ERROR: Værdi for number-up %d ikke understøttet, bruger number-up=1!\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: Værdi for number-up-layout %s ikke understøttet, bruger number-up-"
+#~ "layout=lrtb!\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: Værdi for page-border %s ikke understøttet, bruger page-"
+#~ "border=none!\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr "ERROR: doc_printf-overløb (%d byte) registreret, annullerer!\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr "ERROR: pdftops-filter gik ned på signalet %d!\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr "ERROR: pdftops-filter afsluttede med status %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops afsluttede på signalet %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops afsluttede med status %d!\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: Kan gendannes: Kan ikke oprette forbindelse til printer; prøver "
+#~ "igen om 30 sekunder...\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "Tomt PPD-arkiv!"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "ERROR: Værtsnavn kræves efter indstillingen '-h'!\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Fixertemperatur høj!"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "Fixertemperatur lav!"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "Fik en printer-uri-egenskab, men ingen job-id!"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Blæk/toner næsten tom."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Blæk/toner tom!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Affaldsbeholder til blæk/toner næsten fuld."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Affaldsbeholder til blæk/toner fuld!"
+
+#~ msgid "Interlock open."
+#~ msgstr "Sikkerhedsafbryder åben."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "Job #%d kan ikke startes igen - ingen arkiver!"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "Job #%d eksisterer ikke!"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "Job #%d er færdigt og kan ikke ændres!"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "Job #%d er ikke færdigt!"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "Job #%d er ikke udsat til godkendelse!"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "Job #%d er ikke udsat!"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "Job #%s eksisterer ikke!"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "Job %d findes ikke!"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "Jobabonnementer kan ikke fornys!"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "Sproget \"%s\" understøttes ikke!"
+
+#~ msgid "Media jam!"
+#~ msgstr "Mediestop!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Mediebakke næsten tom."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Mediebakke tom!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Mediebakke mangler!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "Mediebakke skal fyldes op."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "Manglende document-number-attribut!"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "Manglende dobbelt anførselstegn i linje %d!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "Manglende formularvariabel!"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "Manglende notify-subscription-ids-egenskab!"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "Manglende requesting-user-name-egenskab!"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "Manglende nødvendige attributter!"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "Manglende værdi i linje %d!"
+
+#~ msgid "No PPD name!"
+#~ msgstr "Intet PPD-navn!"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Der er ikke installeret nogen Windows-printerdrivere!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "Ingen aktive job på %s!"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "Ingen attributter i anmodning!"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "Ingen godkendelsesoplysninger leveret!"
+
+#~ msgid "No file!?!"
+#~ msgstr "Intet arkiv!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "Intet ændringstidspunkt!"
+
+#~ msgid "No printer name!"
+#~ msgstr "Intet printernavn!"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "Ingen printer-uri fundet til klasse!"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "Ingen printer-uri fundet!"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "Ingen printer-uri i anmodning!"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "Ingen abonnementsattributter i anmodning!"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC næsten slidt op."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC slidt op!"
+
+#~ msgid "Out of toner!"
+#~ msgstr "Ikke mere toner!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Udbakke næsten fuld."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Udbakke fuld!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Udbakke mangler!"
+
+#~ msgid "Printer offline."
+#~ msgstr "Printer passiv."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "SCSI-printer"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "Værdien for notify-user-data er for stor (%d > 63 oktetter)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "Printeren eller klassen er ikke delt!"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "Egenskaben printer-uri kræves!"
+
+#~ msgid "Toner low."
+#~ msgstr "Toner lav."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "For mange job-sheets-værdier (%d > 2)!"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "For mange printer-state-reasons-værdier (%d > %d)!"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "Kan ikke tilføje job til destinationen \"%s\"!"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "Kan ikke tildele hukommelse til arkivtyper!"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr "Kan ikke kopiere 64 bit CUPS-printerarkiver (%d)!"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr "Kan ikke kopiere 64 bit Windows-printerarkiver (%d)!"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr "Kan ikke kopiere CUPS-printerarkiver (%d)!"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "Kan ikke kopiere PPD-arkiv - %s!"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "Kan ikke kopiere PPD-arkiv!"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr "Kan ikke kopiere Windows 2000-printerarkiver (%d)!"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr "Kan ikke kopiere Windows 9x-printerarkiver (%d)!"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "Kan ikke kopiere grænsefladeinstruks - %s!"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "Kan ikke oprette printer-uri!"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr "Kan ikke redigere cupsd.conf-arkiver på mere end 1 MB!"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "Kan ikke finde jobbets destination!"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "Kan ikke finde printer!\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr "Kan ikke installere Windows 2000-printerarkiver (%d)!"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr "Kan ikke installere Windows 9x-printerarkiver (%d)!"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "Kan ikke åbne dokument %d i job %d!"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "Kan ikke sende kommando til printerarkiv!"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Kan ikke indstille Windows-printerarkiv (%d)!"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "Kan ikke bruge oprindeligt printerarkiv af USB-klasse!\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "Ukendt printerfejl (%s)!"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Ikke understøttet tegnsæt \"%s\"!"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "Ikke understøttet komprimering \"%s\"!"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "Ikke understøttet komprimeringsegenskab %s!"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "Ikke understøttet format \"%s\"!"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "Ikke understøttet format \"%s\"!"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "Ikke understøttet format '%s/%s'!"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "Brug: convert [ options ]\n"
+#~ "\n"
+#~ "Indstillinger:\n"
+#~ "\n"
+#~ " -f arkivnavn Indstil arkiv, der skal konverteres (otherwise "
+#~ "stdin)\n"
+#~ " -o arkivnavn Indstil arkiv, der skal genereres (otherwise "
+#~ "stdout)\n"
+#~ " -i mime/type Indstil indgående MIME-type (otherwise auto-"
+#~ "typed)\n"
+#~ " -j mime/type Indstil udgående MIME-type (otherwise application/"
+#~ "pdf)\n"
+#~ " -P arkivnavn.ppd Indstil PPD-arkiv\n"
+#~ " -a 'name=value ...' Juster indstilling(er)\n"
+#~ " -U brugernavn Indstil brugernavn til job\n"
+#~ " -J titel Indstil titel\n"
+#~ " -c kopier Indstil antal kopier\n"
+#~ " -u Fjern PPD-arkiv når færdig\n"
+#~ " -D Fjern indgående arkiv når færdig\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "Brug: cupsfilter -m mime/type [ options ] arkivnavn\n"
+#~ "\n"
+#~ "Indstillinger:\n"
+#~ "\n"
+#~ " -c cupsd.conf Indstil cupsd.conf-arkiv til at bruge\n"
+#~ " -j job-id[,N] Filter arkiv N fra det anførte job (standard er arkiv "
+#~ "1)\n"
+#~ " -n kopier Indstil antal kopier\n"
+#~ " -o name=value Juster indstilling(er)\n"
+#~ " -p arkivnan.ppd Indstil PPD-arkiv\n"
+#~ " -t titel Indstil titel\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Brug: cupstestppd [options] arkivnavn1.ppd[.gz] [... arkivnavnN.ppd[."
+#~ "gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Indstillinger:\n"
+#~ "\n"
+#~ " -R root-directory Indstil alternativ root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Udsted advarsler i stedet for fejl\n"
+#~ " -q Afvikl i baggrunden\n"
+#~ " -r Brug 'relaxed' åben funktion\n"
+#~ " -v Vær en anelse detaljeret\n"
+#~ " -vv Vær meget detaljseret\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: Kunne ikke læse anmodningen om side-channel!\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr ""
+#~ "WARNING: Indstillingen \"%s\" kan ikke inkluderes via IncludeFeature!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Ekstern vært svarede ikke med kommandostatus-byte efter %d "
+#~ "sekunder!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Ekstern vært svarede ikke med kontrolstatus-byte efter %d "
+#~ "sekunder!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Ekstern vært svarede ikke med datastatus-byte efter %d "
+#~ "sekunder!\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr "WARNING: Timeout i SCSI-kommando (%d); prøver igen...\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: Dette dokument overholder ikke Adobe Document Structuring "
+#~ "Conventions og udskrives muligvis ikke korrekt!\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: Ukendt valg \"%s\" til indstillingen \"%s\"!\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: Ukendt indstilling \"%s\"!\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: Ikke understøttet baudhastighed %s!\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: Kan gendannes: Netværksværten '%s' er i brug; prøver igen om %d "
+#~ "sekunder...\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr ""
+#~ "Advarsel - der er ikke installeret nogen Windows 2000-printerarkiver!"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: Ukendt indstilling \"%s\"!\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: Ukendt indstilling \"-%c\"!\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr "cupsd: Forventede config-arkivnavn efter indstillingen \"-c\"!\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: Kan ikke hente aktuelt bibliotek!\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: Ukendt argument \"%s\" - afbryder!\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: Ukendt indstilling \"%c\" - afbryder!\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: Ugyldigt dokumentnummer %d!\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: Ugyldig job-id %d!\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: Der kan kun anføres et arkivnavn!\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter: Kan ikke oprette midlertidigt arkiv: %s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "egenskaben job-printer-uri mangler!"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Klassenavn må kun indeholde tegn, der kan udskrives!\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: Forventede PPD efter indstillingen '-P'!\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr "lpadmin: Forventede allow/deny:userlist efter indstillingen '-u'!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: Forventede klasse efter indstillingen '-r'!\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: Forventede klassenavn efter indstillingen '-c'!\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: Forventede beskrivelse efter indstillingen '-D'!\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: Forventede enheds-URI efter indstillingen '-v'!\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: Forventede arkivtype(r) efter indstillingen '-I'!\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: Forventede værtsnavn efter indstillingen '-h'!\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: Forventede grænseflade efter indstillingen '-i'!\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: Forventede placering efter indstillingen '-L'!\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: Forventede model efter indstillingen '-m'!\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: Forventede navn=værdi efter indstillingen '-o'!\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: Forventede printer efter indstillingen '-p'!\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: Forventede printernavn efter indstillingen '-d'!\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr ""
+#~ "lpadmin: Forventede printer eller klasse efter indstillingen '-x'!\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: Ingen medlemsnavne set!\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Printernavn må kun indeholde tegn, der kan udskrives!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke føje en printer til klassen:\n"
+#~ " Du skal først angive et printernavn!\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin: Kan ikke oprette midlertidigt arkiv - %s\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin: Kan ikke oprette midlertidigt arkiv: %s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke fjerne en printer fra klassen:\n"
+#~ " Du skal først angive et printernavn!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke indstille PPD-arkivet:\n"
+#~ " Du skal først angive et printernavn!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke indstille enheds-URI'en:\n"
+#~ " Du skal først angive et printernavn!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke indstille grænsefladeinstruksen eller PPD-arkivet:\n"
+#~ " Du skal først angive et printernavn!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke indstille grænsefladeinstruksen:\n"
+#~ " Du skal først angive et printernavn!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke indstille printerbeskrivelsen:\n"
+#~ " Du skal først angive et printernavn!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke indstille printerens placering:\n"
+#~ " Du skal først angive et printernavn!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke indstille printerens udstyr:\n"
+#~ " Du skal først angive et printernavn!\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: Ukendt indstilling for tillad/afvis \"%s\"!\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: Ukendt argument \"%s\"!\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: Ukendt indstilling '%c'!\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin: Advarsel - listen indholdstype ignoreret!\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr "lpinfo: Forventede 1284-enheds-id-streng efter --device-id!\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: Forventede sprog efter --language!\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo: Forventede mærke og model efter --make-and-model!\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo: Forventede produktstreng efter --product!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo: Forventede planliste efter --exclude-schemes!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo: Forventede planliste efter --include-schemes!\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: Forventede timeout efter --timeout!\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: Ukendt argument \"%s\"!\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: Ukendt indstilling '%c'!\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: Ukendt indstilling '%s'!\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: Ukendt argument \"%s\"!\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: Ukendt indstilling '%c'!\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: Ingen printere!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: Kan ikke åbne PPD-arkivet til %s!\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: Ukendt printer eller klasse!\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: Det er kun root, der må tilføje og slette adgangskoder!\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: Adgangskodearkiv i brug!\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: Adgangskodearkiv ikke opdateret!\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: Beklager, adgangskoderne er ikke de samme!\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: Beklager, adgangskoderne er ikke de samme!\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: Fejl - %s-miljøvariabel navngiver ikke eksisterende destination "
+#~ "\"%s\"!\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-events ikke anført!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "notify-recipient-uri URI \"%s\" er allerede brugt!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "notify-recipient-uri URI \"%s\" bruger ukendt skema!"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d ikke i orden!"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ugyldigt opløsningsnavn \"%s\" på linje %d af %s!\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: Ugyldigt statusnøgleord %s på linje %d af %s!\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc: Valg fundet på linje %d af %s uden nogen indstilling!\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc: Dubleret #po for lokalitet %s på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede en filterdefinition på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede et programnavn på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede tegnsæt efter Font på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Forventede farverækkefølge til ColorModel på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede farveområde til ColorModel på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede komprimering til ColorModel på linje %d af %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Forventede begrænsningsstreng til UIConstraints på linje %d af %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Forventede nøgleord til printerarkivtype efter DriverType på linje %"
+#~ "d af %s!\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede duplekstype efter Duplex på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede kodning efter Font på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede arkivnavn efter #po %s på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede gruppenavn/-tekst på linje %d af %s.\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede inkluder arkivnavn på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede heltal på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede lokalitet efter #po på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede navn efter %s på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede navn efter FileName på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede navn efter Font på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede navn efter Manufacturer på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede navn efter MediaSize på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede navn efter ModelName på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede navn efter PCFileName på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede navn/tekst efter %s på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede navn/tekst efter Installable på linje %d af %s.\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede navn/tekst efter Resolution på linje %d af %s.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Forventede navn-/tekstkombination til ColorModel på linje %d af %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede indstillingsnavn/-tekst på linje %d af %s.\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede indstillingssektion på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede indstillingstype på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Forventede tilsidesættelsesfelt efter Resolution på linje %d af %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede rigtigt tal på linje %d af %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Forventede opløsnings-/medietype efter ColorProfile på linje %d af %"
+#~ "s.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Forventede opløsnings-/medietype efter SimpleColorProfile på linje %"
+#~ "d af %s.\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede vælger efter %s på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede status efter Font på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede streng efter Copyright på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede streng efter Version på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede to indstillingsnavne på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede værdi efter %s på linje %d af %s!\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Forventede version efter Font på linje %d af %s!\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: Ugyldigt #include/#po-arkivnavn \"%s\"!\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Ugyldig omkostning for filter på linje %d af %s!\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Ugyldig tom MIME-type for filter på linje %d af %s!\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Ugyldigt tomt programnavn for filter på linje %d af %s!\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ugyldig indstillingssektion \"%s\" på linje %d af %s!\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ugyldig indstillingstype \"%s\" på linje %d af %s!\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: Manglende #endif i slutningen af \"%s\"!\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: Manglende #if på linje %d af %s!\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc: Intet beskedkatalog til lokalitet %s!\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Indstilling %s omdefineret med en anden type på linje %d af %s!\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr "ppdc: Indstillingen constraint skal *name på linje %d af %s.\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: For mange indlejrede #if-udsagn på linje %d af %s!\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: Kan ikke finde #po-arkiv %s på linje %d af %s!\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Kan ikke finde inkluder arkiv \"%s\" på linje %d af %s!\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: Ukendt type printerarkiv %s på linje %d af %s!\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ukendt duplekstype \"%s\" på linje %d af %s!\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ukendt mediestørrelse \"%s\" på linje %d af %s!\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: Ukendt mærke \"%s\" set på linje %d af %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Ukendt udpunkteringstegn i rigtige tal \"%s\" på linje %d af %s!\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr "ppdc: Uafsluttet streng startende fra %c på linje %d af %s!\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: Ugyldig LanguageVersion \"%s\" in %s!\n"
diff --git a/locale/cups_de.po b/locale/cups_de.po
new file mode 100644
index 000000000..83782a39f
--- /dev/null
+++ b/locale/cups_de.po
@@ -0,0 +1,7155 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-16 12:00-0800\n"
+"Last-Translator: Apple Inc.\n"
+"Language-Team: Apple Inc.\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(alles)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(ohne)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d Einträge\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tNach Fehler: fortsetzen\n"
+
+msgid "\tAlerts:"
+msgstr "\tWarnhinweise:"
+
+msgid "\tBanner required\n"
+msgstr "\tBanner erforderlich\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tZeichensätze:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tVerbindung: direkt\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tVerbindung: enfernt\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tStandardseitengröße:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tStandardzeilenhöhe:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tStandard-Anschlusseinstellungen:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tBeschreibung: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tFormular aktiviert:\n"
+"\tInhaltstypen: beliebig\n"
+"\tDruckertypen: unbekannt\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tZugelassene Formulare:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tSchnittstelle: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tSchnittstelle: %s/interfaces/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tSchnittstelle: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tStandort: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tBei Fehler: kein Warnhinweis\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tZugelassene Benutzer:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tGesperrte Benutzer:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tDaemon vorhanden\n"
+
+msgid "\tno entries\n"
+msgstr "\tkeine Einträge\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\tDrucker ist auf Geschwindigkeit des Geräts „%s“ -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\tDrucken ist deaktiviert\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\tDrucken ist aktiviert\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\tWarteliste für %s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tWarteliste ist deaktiviert\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tWarteliste ist aktiviert\n"
+
+msgid "\treason unknown\n"
+msgstr "\tGrund unbekannt\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" AUSFÜHRLICHE KONFORMITÄTSTESTERGEBNISSE\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " REF: Seite 15, Abschnitt 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " REF: Seite 15, Abschnitt 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " REF: Seite 19, Abschnitt 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " REF: Seite 20, Abschnitt 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " REF: Seite 27, Abschnitt 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " REF: Seite 42, Abschnitt 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " REF: Seite 16–17, Abschnitt 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " REF: Seite 42–45, Abschnitt 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " REF: Seite 45–46, Abschnitt 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " REF: Seite 48–49, Abschnitt 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " REF: Seite 52–54, Abschnitt 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f Byte\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " PASS Default%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " PASS DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " PASS DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " PASS FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " PASS FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " PASS LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " PASS LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " PASS Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " PASS ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " PASS NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " PASS PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " PASS PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " PASS PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " PASS PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " PASS Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " PASS ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" WARN Konflikt zwischen „%s %s“ und „%s %s“\n"
+" (constraint=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" WARN %s hat eine gemeinsames übliches Präfix mit %s\n"
+" REF: Seite 15, Abschnitt 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" WARN LanguageEncoding benötigt von PPD 4.3 Spezifikation.\n"
+" REF: Seite 56–57, Abschnitt 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" WARN Manufacturer benötigt von PPD 4.3 Spezifikation.\n"
+" REF: Seite 58–59, Abschnitt 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" WARN PCFileName ist länger als 8.3 und verstößt gegen die PPD-"
+"Spezifikation.\n"
+" REF: Seite 61–62, Abschnitt 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protokolle enthalten PJL, aber JCL-Attribute sind nicht "
+"festgelegt.\n"
+" REF: Seite 78–79, Abschnitt 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protokolle enthalten PJL sowie BCP; es wurde aber TBCP "
+"erwartet.\n"
+" REF: Seite 78–79, section 5.7.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" WARN ShortNickName benötigt von PPD 4.3 Spezifikation.\n"
+" REF: Seite 64–65, Abschnitt 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s Fehlende cupsFilter-Datei „%s“\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s Fehlende cupsPreFilter-Datei „%s“\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FEHLER** UNGÜLTIG: Default%s „%s“\n"
+" REF: Seite 40, Abschnitt 4.5.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **FEHLER** UNGÃœLTIG: JobPatchFile-Attribut in Datei\n"
+" REF: Seite 24, Abschnitt 3.4.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FEHLER** UNGÜLTIG: Manufacturer (sollte „HP“ sein)\n"
+" REF: Seite 211, Tabelle D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FEHLER** UNGÜLTIG: Manufacturer (sollte „Oki“ sein)\n"
+" REF: Seite 211, Tabelle D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FEHLER** UNGÜLTIG: ModelName – „%c“ nicht zulässig im String.\n"
+" REF: Seite 59–60, Abschnitt 5.3.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FEHLER** UNGÜLTIG: PSVersion – nicht „(string) int“.\n"
+" REF: Seite 62–64, Abschnitt 5.3.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FEHLER** UNGÜLTIG: Product – nicht „(string)“.\n"
+" REF: Seite 62, Abschnitt 5.3.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **FEHLER** UNGÜLTIG: ShortNickName – länger als 31 Zeichen.\n"
+" REF: Seite 64–65, Abschnitt 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FEHLER** Ungültige FileVersion „%s“\n"
+" REF: Seite 56, Abschnitt 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FEHLER** Ungültige FormatVersion „%s“\n"
+" REF: Seite 56, Abschnitt 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr ""
+" **FEHLER** Standardoptionscode kann nicht interpretiert werden: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: Default%s\n"
+" REF: Seite 40, Abschnitt 4.5.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: DefaultImageableArea\n"
+" REF: Seite 102, Abschnitt 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: DefaultPaperDimension\n"
+" REF: Seite 103, Abschnitt 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: FileVersion\n"
+" REF: Seite 56, Abschnitt 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: FormatVersion\n"
+" REF: Seite 56, Abschnitt 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: ImageableArea für PageSize „%s“\n"
+" REF: Seite 41, Abschnitt 5.\n"
+" REF: Seite 102, Abschnitt 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: LanguageEncoding\n"
+" REF: Seite 56–57, Abschnitt 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: LanguageVersion\n"
+" REF: Seite 57–58, Abschnitt 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: Manufacturer\n"
+" REF: Seite 58–59, Abschnitt 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: ModelName\n"
+" REF: Seite 59–60, Abschnitt 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: NickName\n"
+" REF: Seite 60, Abschnitt 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: PCFileName\n"
+" REF: Seite 61–62, Abschnitt 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: PSVersion\n"
+" REF: Seite 62–64, Abschnitt 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: PageRegion\n"
+" REF: Seite 100, Abschnitt 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: PageSize\n"
+" REF: Seite 41, Abschnitt 5.\n"
+" REF: Seite 99, Abschnitt 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: PageSize\n"
+" REF: Seite 99–100, Abschnitt 5.14.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: PaperDimension für PageSize „%s“\n"
+" REF: Seite 41, Abschnitt 5.\n"
+" REF: Seite 103, Abschnitt 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: Product\n"
+" REF: Seite 62, Abschnitt 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **FEHLER** BENÖTIGT: ShortNickName\n"
+" REF: Seite 64–65, Abschnitt 5.3.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " %d FEHLER GEFUNDEN\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " KEINE FEHLER GEFUNDEN\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " FEHLER\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" FEHLER\n"
+" **FEHLER** PPD-Datei konnte nicht geöffnet werden – %s.\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" FEHLER\n"
+" **FEHLER** PPD-Datei konnte nicht geöffnet werden – %s in Zeile %d.\n"
+
+msgid " PASS\n"
+msgstr " PASS\n"
+
+msgid "#10 Envelope"
+msgstr "US #10 Umschlag"
+
+msgid "#11 Envelope"
+msgstr "US #11 Umschlag"
+
+msgid "#12 Envelope"
+msgstr "US #12 Umschlag"
+
+msgid "#14 Envelope"
+msgstr "US #14 Umschlag"
+
+msgid "#9 Envelope"
+msgstr "US #9 Umschlag"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f Byte\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f Byte\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f Millimeter"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f bis %.0f x %.0f Millimeter"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f Zoll"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f bis %.2f x %.2f Zoll"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s akzeptiert Anfragen seit %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%s kann nicht geändert werden."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s ist nicht implementiert in der CUPS-Version von lpc.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s ist nicht bereit\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s ist bereit\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s ist bereit und druckt\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s akzeptiert keine Anfragen seit %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s akzeptiert Anfragen seit %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s akzeptiert keine Anfragen seit %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [Druckauftrag %d localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s fehlgeschlagen: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: Fehler – kein Standardziel verfügbar.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: Fehler – Priorität muss zwischen 1 und 100 sein.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: Fehler – zu viele Dateien – „%s“\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: Fehler – kein Zugriff auf „%s“ – %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s: Fehler – keine Warteliste für „stdin“ – %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: Filter „%s“ nicht verfügbar: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: Ungültiger Filterstring „%s“\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: Aktion fehlgeschlagen: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: Verbindung mit Server fehlgeschlagen\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: „%s“ konnte nicht geöffnet werden: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: PPD-Datei konnte nicht geöffnet werden – %s in Zeile %d\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: Fehler – kein Standardziel verfügbar.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 Zoll/Sek."
+
+msgid "1.25x0.25\""
+msgstr "1,25x0,25 Zoll"
+
+msgid "1.25x2.25\""
+msgstr "1,25x2,25 Zoll"
+
+msgid "1.5 inch/sec."
+msgstr "1,5 Zoll/Sek."
+
+msgid "1.50x0.25\""
+msgstr "1,50x0,25 Zoll"
+
+msgid "1.50x0.50\""
+msgstr "1,50x0,50 Zoll"
+
+msgid "1.50x1.00\""
+msgstr "1,50x1,00 Zoll"
+
+msgid "1.50x2.00\""
+msgstr "1,50x2,00 Zoll"
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 Zoll/Sek."
+
+msgid "10 x 11\""
+msgstr "10 x 11 Zoll"
+
+msgid "10 x 13\""
+msgstr "10 x 13 Zoll"
+
+msgid "10 x 14\""
+msgstr "10 x 14 Zoll"
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 mm/Sek."
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 Zoll/Sek."
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 Zoll/Sek."
+
+msgid "12 x 11\""
+msgstr "12 x 11 Zoll"
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 mm/Sek."
+
+msgid "120x60dpi"
+msgstr "120x60 dpi"
+
+msgid "120x72dpi"
+msgstr "120x72 dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136 dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 mm/Sek."
+
+msgid "15 x 11\""
+msgstr "15 x 11 Zoll"
+
+msgid "150 mm/sec."
+msgstr "150 mm/Sek."
+
+msgid "150dpi"
+msgstr "150 dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180 dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 Zoll/Sek."
+
+msgid "2-Sided Printing"
+msgstr "Doppelseitig drucken"
+
+msgid "2.00x0.37\""
+msgstr "2,00x0,37 Zoll"
+
+msgid "2.00x0.50\""
+msgstr "2,00x0,50 Zoll"
+
+msgid "2.00x1.00\""
+msgstr "2,00x1,00 Zoll"
+
+msgid "2.00x1.25\""
+msgstr "2,00x1,25 Zoll"
+
+msgid "2.00x2.00\""
+msgstr "2,00x2,00 Zoll"
+
+msgid "2.00x3.00\""
+msgstr "2,00x3,00 Zoll"
+
+msgid "2.00x4.00\""
+msgstr "2,00x4,00 Zoll"
+
+msgid "2.00x5.50\""
+msgstr "2,00x5,50 Zoll"
+
+msgid "2.25x0.50\""
+msgstr "2,25x0,50 Zoll"
+
+msgid "2.25x1.25\""
+msgstr "2,25x1,25 Zoll"
+
+msgid "2.25x4.00\""
+msgstr "2,25x4,00 Zoll"
+
+msgid "2.25x5.50\""
+msgstr "2,25x5,50 Zoll"
+
+msgid "2.38x5.50\""
+msgstr "2,38x5,50 Zoll"
+
+msgid "2.5 inches/sec."
+msgstr "2,5 Zoll/Sek."
+
+msgid "2.50x1.00\""
+msgstr "2,50x1,00 Zoll"
+
+msgid "2.50x2.00\""
+msgstr "2,50x2,00 Zoll"
+
+msgid "2.75x1.25\""
+msgstr "2,75x1,25 Zoll"
+
+msgid "2.9 x 1\""
+msgstr "2,9 x 1 Zoll"
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 mm/Sek."
+
+msgid "200 mm/sec."
+msgstr "200 mm/Sek."
+
+msgid "203dpi"
+msgstr "203 dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "24-Pin Serie"
+
+msgid "240x72dpi"
+msgstr "240x72 dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 mm/Sek."
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 Zoll/Sek."
+
+msgid "3.00x1.00\""
+msgstr "3,00x1,00 Zoll"
+
+msgid "3.00x1.25\""
+msgstr "3,00x1,25 Zoll"
+
+msgid "3.00x2.00\""
+msgstr "3,00x2,00 Zoll"
+
+msgid "3.00x3.00\""
+msgstr "3,00x3,00 Zoll"
+
+msgid "3.00x5.00\""
+msgstr "3,00x5,00 Zoll"
+
+msgid "3.25x2.00\""
+msgstr "3,25x2,00 Zoll"
+
+msgid "3.25x5.00\""
+msgstr "3,25x5,00 Zoll"
+
+msgid "3.25x5.50\""
+msgstr "3,25x5,50 Zoll"
+
+msgid "3.25x5.83\""
+msgstr "3,25x5,83 Zoll"
+
+msgid "3.25x7.83\""
+msgstr "3,25x7,83 Zoll"
+
+msgid "3.5\" Disk"
+msgstr "3,5-Zoll-Diskette"
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "3,5-Zoll-Diskette – 2 1/8 x 2 3/4 Zoll"
+
+msgid "3.50x1.00\""
+msgstr "3,50x1,00 Zoll"
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 mm/Sek."
+
+msgid "300 mm/sec."
+msgstr "300 mm/Sek."
+
+msgid "300dpi"
+msgstr "300 dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360 dpi"
+
+msgid "360x180dpi"
+msgstr "360x180 dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 Zoll/Sek."
+
+msgid "4.00x1.00\""
+msgstr "4,00x1,00 Zoll"
+
+msgid "4.00x13.00\""
+msgstr "4,00x13,00 Zoll"
+
+msgid "4.00x2.00\""
+msgstr "4,00x2,00 Zoll"
+
+msgid "4.00x2.50\""
+msgstr "4,00x2,50 Zoll"
+
+msgid "4.00x3.00\""
+msgstr "4,00x3,00 Zoll"
+
+msgid "4.00x4.00\""
+msgstr "4,00x4,00 Zoll"
+
+msgid "4.00x5.00\""
+msgstr "4,00x5,00 Zoll"
+
+msgid "4.00x6.00\""
+msgstr "4,00x6,00 Zoll"
+
+msgid "4.00x6.50\""
+msgstr "4,00x6,50 Zoll"
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 mm/Sek."
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 Zoll/Sek."
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 Zoll/Sek."
+
+msgid "6.00x1.00\""
+msgstr "6,00x1,00 Zoll"
+
+msgid "6.00x2.00\""
+msgstr "6,00x2,00 Zoll"
+
+msgid "6.00x3.00\""
+msgstr "6,00x3,00 Zoll"
+
+msgid "6.00x4.00\""
+msgstr "6,00x4,00 Zoll"
+
+msgid "6.00x5.00\""
+msgstr "6,00x5,00 Zoll"
+
+msgid "6.00x6.00\""
+msgstr "6,00x6,00 Zoll"
+
+msgid "6.00x6.50\""
+msgstr "6,00x6,50 Zoll"
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/Sek."
+
+msgid "600dpi"
+msgstr "600 dpi"
+
+msgid "60dpi"
+msgstr "60 dpi"
+
+msgid "60x720dpi"
+msgstr "60x720 dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 Zoll/Sek."
+
+msgid "7 x 9\""
+msgstr "7 x 9 Zoll"
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720 dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 Zoll/Sek."
+
+msgid "8 x 10\""
+msgstr "8 x 10 Zoll"
+
+msgid "8.00x1.00\""
+msgstr "8,00x1,00 Zoll"
+
+msgid "8.00x2.00\""
+msgstr "8,00x2,00 Zoll"
+
+msgid "8.00x3.00\""
+msgstr "8,00x3,00 Zoll"
+
+msgid "8.00x4.00\""
+msgstr "8,00x4,00 Zoll"
+
+msgid "8.00x5.00\""
+msgstr "8,00x5,00 Zoll"
+
+msgid "8.00x6.00\""
+msgstr "8,00x6,00 Zoll"
+
+msgid "8.00x6.50\""
+msgstr "8,00x6,50 Zoll"
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/Sek."
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 Zoll/Sek."
+
+msgid "9 x 11\""
+msgstr "9 x 11 Zoll"
+
+msgid "9 x 12\""
+msgstr "9 x 12 Zoll"
+
+msgid "9-Pin Series"
+msgstr "9-Pin Serie"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?Ungültiger Hilfebefehl ist unbekannt\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "DIN A0"
+
+msgid "A1"
+msgstr "DIN A1"
+
+msgid "A10"
+msgstr "DIN A10"
+
+msgid "A2"
+msgstr "DIN A2"
+
+msgid "A3"
+msgstr "DIN A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (Übergröße)"
+
+msgid "A4"
+msgstr "DIN A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (Übergröße)"
+
+msgid "A4 (Small)"
+msgstr "A4 (klein)"
+
+msgid "A5"
+msgstr "DIN A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (Übergröße)"
+
+msgid "A6"
+msgstr "DIN A6"
+
+msgid "A7"
+msgstr "DIN A7"
+
+msgid "A8"
+msgstr "DIN A8"
+
+msgid "A9"
+msgstr "DIN A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "Druckaufträge akzeptieren"
+
+msgid "Accepted"
+msgstr "Akzeptiert"
+
+msgid "Add Class"
+msgstr "Klasse hinzufügen"
+
+msgid "Add Printer"
+msgstr "Drucker hinzufügen"
+
+msgid "Add RSS Subscription"
+msgstr "RSS-Abo hinzufügen"
+
+msgid "Address"
+msgstr "Adresse"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "Adresse – 1 1/8 x 3 1/2 Zoll"
+
+msgid "Administration"
+msgstr "Verwaltung"
+
+msgid "Always"
+msgstr "Immer"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "Applicator"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "DIN B0"
+
+msgid "B1"
+msgstr "DIN B1"
+
+msgid "B10"
+msgstr "DIN B10"
+
+msgid "B2"
+msgstr "DIN B2"
+
+msgid "B3"
+msgstr "DIN B3"
+
+msgid "B4"
+msgstr "DIN B4"
+
+msgid "B5"
+msgstr "DIN B5"
+
+msgid "B6"
+msgstr "DIN B6"
+
+msgid "B7"
+msgstr "DIN B7"
+
+msgid "B8"
+msgstr "DIN B8"
+
+msgid "B9"
+msgstr "DIN B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "Ungültiger NULL-Dests-Pointer"
+
+msgid "Bad OpenGroup"
+msgstr "Ungültige OpenGroup"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "Ungültiges OpenUI/JCLOpenUI"
+
+msgid "Bad OrderDependency"
+msgstr "Ungültige OrderDependency"
+
+msgid "Bad Request"
+msgstr "Ungültige Anfrage"
+
+msgid "Bad SNMP version number"
+msgstr "Ungültige SNMP-Versionsnummer"
+
+msgid "Bad UIConstraints"
+msgstr "Ungültige UIConstraints"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Ungültiger Kopienwert „%d“."
+
+msgid "Bad custom parameter"
+msgstr "Ungültiger angepasster Parameter"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Ungültiges Schriftattribut: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Ungültiger Number-Up-Wert „%d“."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Ungültige Seitenbereichswerte %d–%d."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Banner"
+
+msgid "Billing Information: "
+msgstr "Rechnungsinformationen: "
+
+msgid "Bond Paper"
+msgstr "Papier bündeln"
+
+msgid "C0 Envelope"
+msgstr "DIN C0 Umschlag"
+
+msgid "C1 Envelope"
+msgstr "DIN C1 Umschlag"
+
+msgid "C2 Envelope"
+msgstr "DIN C2 Umschlag"
+
+msgid "C3 Envelope"
+msgstr "DIN C3 Umschlag"
+
+msgid "C4"
+msgstr "DIN C4"
+
+msgid "C4 Envelope"
+msgstr "DIN C4 Umschlag"
+
+msgid "C5"
+msgstr "DIN C5"
+
+msgid "C5 Envelope"
+msgstr "DIN C5 Umschlag"
+
+msgid "C6"
+msgstr "DIN C6"
+
+msgid "C6 Envelope"
+msgstr "DIN C6 Umschlag"
+
+msgid "C65 Envelope"
+msgstr "DIN C65 Umschlag"
+
+msgid "C7 Envelope"
+msgstr "DIN C7 Umschlag"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "CPCL Etikettendrucker"
+
+msgid "Cancel RSS Subscription"
+msgstr "RSS-Abo widerrufen"
+
+msgid "Change Settings"
+msgstr "Einstellungen ändern"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Chou3 Umschlag"
+
+msgid "Chou4 Envelope"
+msgstr "Chou4 Umschlag"
+
+msgid "Classes"
+msgstr "Klassen"
+
+msgid "Clean Print Heads"
+msgstr "Saubere Druckerköpfe"
+
+msgid "Color"
+msgstr "Farbe"
+
+msgid "Color Mode"
+msgstr "Farbmodus"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"Befehle können abgekürzt werden. Befehle sind:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "Community-Name hat unbestimmte Länge"
+
+msgid "Continue"
+msgstr "Weiter"
+
+msgid "Continuous"
+msgstr "Kontinuierlich"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Erstellt"
+
+msgid "Created On: "
+msgstr "Erstellt am: "
+
+msgid "Custom"
+msgstr "Eigene"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Abschneiden"
+
+msgid "Cutter"
+msgstr "Abschneider"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "DL Umschlag"
+
+msgid "Dark"
+msgstr "Dunkel"
+
+msgid "Darkness"
+msgstr "Dunkelheit"
+
+msgid "Delete Class"
+msgstr "Klasse löschen"
+
+msgid "Delete Printer"
+msgstr "Drucker löschen"
+
+msgid "Description: "
+msgstr "Beschreibung: "
+
+msgid "DeskJet Series"
+msgstr "DeskJet Serie"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "Ziel „%s“ akzeptiert keine Druckaufträge."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"Gerät: URI = %s\n"
+" Klasse = %s\n"
+" Info = %s\n"
+" Hersteller und Modell = %s\n"
+" Geräte-ID = %s\n"
+" Standort = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "Direct Thermal Media"
+
+msgid "Disabled"
+msgstr "Deaktiviert"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "Dokument „%d“ nicht gefunden in Druckauftrag „%d“."
+
+msgid "Double Postcard"
+msgstr "Doppelpostkarte"
+
+msgid "Driver Name: "
+msgstr "Treibername: "
+
+msgid "Driver Version: "
+msgstr "Treiberversion: "
+
+msgid "Duplexer"
+msgstr "Duplexer"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: Speicher für Seiteninfo konnte nicht zugewiesen werden: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: Speicher für Seiten-Array konnte nicht zugewiesen werden: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "EPL1 Etikettendrucker"
+
+msgid "EPL2 Label Printer"
+msgstr "EPL2 Etikettendrucker"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: Ungültige Zeichensatzdatei „%s“\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: Ungültiger Zeichensatztyp „%s“\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: Ungültige Schriftbeschreibungszeile: „%s“\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: Ungültige Textrichtung „%s“\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: Ungültige Textweite „%s“\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: Fehler „%d“ beim Senden der PAPSendData-Anfrage: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: Keine Schriften in Zeichensatzdatei „%s“\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: Drucker reagiert nicht\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: Drucker sendete unerwartet EOF\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: Entfernter Host hat die Steuerungsdatei nicht akzeptiert (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: Entfernter Host hat Datendatei nicht akzeptiert (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr ""
+"ERROR: Beim Senden der Daten an den Drucker ist ein Fehler wegen "
+"Zeitüberschreitung aufgetreten.\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr ""
+"ERROR: Datei „%d“ konnte nicht zu Druckauftrag hinzugefügt werden: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: Druckauftrag „%d“ konnte nicht abgebrochen werden: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: PDF-Datei konnte nicht kopiert werden"
+
+msgid "ERROR: Unable to create pipe"
+msgstr ""
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: Socket konnte nicht erstellt werden"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: Temporäre komprimierte Druckdatei konnte nicht erstellt werden: %s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: Temporäre Datei konnte nicht erstellt werden"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: pictwpstops konnte nicht ausgeführt werden: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: gs-Programm konnte nicht ausgeführt werden"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: pdftops-Programm konnte nicht ausgeführt werden"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: Fork für pictwpstops konnte nicht ausgeführt werden: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: PAP-Anfrage konnte nicht empfangen werden"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: PAP-Antwort konnte nicht empfangen werden"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr ""
+"ERROR: PPD-Datei für Drucker „%s“ konnte nicht abgefragt werden – %s.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: AppleTalk-Standardzone konnte nicht abgefragt werden"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: Abfrage der PAP-Antwort nicht möglich"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: Suche nach AppleTalk-Druckern nicht möglich"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: Erstellen der AppleTalk-Adresse nicht möglich"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: „%s“ konnte nicht geöffnet werden – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: „%s“ konnte nicht geöffnet werden: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: Bannerdatei „%s“ konnte nicht geöffnet werden – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: Gerätedatei „%s“ konnte nicht geöffnet werden – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: Datei „%s“ konnte nicht geöffnet werden – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: Datei „%s“ konnte nicht geöffnet werden: %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: Druckdatei „%s“ konnte nicht geöffnet werden: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: Druckdatei „%s“ konnte nicht geöffnet werden – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: Druckdatei „%s“ konnte nicht geöffnet werden: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: Temporäre komprimierte Druckdatei konnte nicht geöffnet werden: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: Druckdaten konnten nicht gelesen werden"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: Anschluss konnte nicht reserviert werden"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr ""
+"ERROR: Nach dem Versatz „%ld“ in der Datei konnte nicht gesucht werden – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr ""
+"ERROR: Nach dem Versatz „%lld“ in der Datei konnte nicht gesucht werden – %"
+"s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: LPD-Befehl konnte nicht gesendet werden"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: PAP-Rückkopplungsanfrage konnte nicht gesendet werden"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr ""
+"ERROR: Erste PAP-Anfrage zum Senden von Daten konnte nicht gesendet werden"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: Druckdatei konnte nicht an den Drucker gesendet werden"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr ""
+"ERROR: Nachfolgende Nullen konnten nicht an den Drucker gesendet werden"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: Warten auf pictwpstops nicht möglich: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: %d Byte konnten nicht auf „%s“ geschrieben werden: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: Steuerungsdatei konnte nicht geschrieben werden"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: Druckdaten konnten nicht geschrieben werden"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: Druckdaten konnten nicht geschrieben werden: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr ""
+"ERROR: Unkomprimierte Dokumentdaten konnten nicht geschrieben werden: %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: Unbekannte Dateianordnung „%s“\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: Unbekanntes Formatzeichen „%c“\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: Unbekannter Druckmodus „%s“\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: Auswahl() fehlgeschlagen"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: „stat“ für Druckdatei nicht möglich"
+
+msgid "Edit Configuration File"
+msgstr "Konfigurationsdatei bearbeiten"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Banner beenden"
+
+msgid "English"
+msgstr "German"
+
+msgid "Enter old password:"
+msgstr "Altes Kennwort eingeben:"
+
+msgid "Enter password again:"
+msgstr "Kennwort erneut eingeben:"
+
+msgid "Enter password:"
+msgstr "Kennwort eingeben:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Geben Sie Ihren Benutzernamen und das Kennwort oder den root-Benutzernamen "
+"und -Kennwort ein, um auf diese Seite zuzgreifen. Falls Sie die Kerberos-"
+"Authentifizierung verwenden, stellen Sie sicher, dass Sie ein gültiges "
+"Kerberos-Ticket haben."
+
+msgid "Envelope Feed"
+msgstr "Umschlagzuführung"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Fehlerbehandlung"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "Alle 10 Etiketten"
+
+msgid "Every 2 Labels"
+msgstr "Alle 2 Etiketten"
+
+msgid "Every 3 Labels"
+msgstr "Alle 3 Etiketten"
+
+msgid "Every 4 Labels"
+msgstr "Alle 4 Etiketten"
+
+msgid "Every 5 Labels"
+msgstr "Alle 5 Etiketten"
+
+msgid "Every 6 Labels"
+msgstr "Alle 6 Etiketten"
+
+msgid "Every 7 Labels"
+msgstr "Alle 7 Etiketten"
+
+msgid "Every 8 Labels"
+msgstr "Alle 8 Etiketten"
+
+msgid "Every 9 Labels"
+msgstr "Alle 9 Etiketten"
+
+msgid "Every Label"
+msgstr "Bei jedem Etikett"
+
+msgid "Expectation Failed"
+msgstr "Erwartete Daten nicht erhalten"
+
+msgid "Export Printers to Samba"
+msgstr "Drucker zu Samba exportieren"
+
+msgid "FAIL\n"
+msgstr "FEHLER\n"
+
+msgid "File Folder"
+msgstr "Dateiordner"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Dateiordner – 9/16 x 3 7/16 Zoll"
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"Dateigeräte-URIs wurden deaktiviert! Infos zum Aktivieren finden Sie im "
+"FileDevice-Verzeichnis unter „%s/cupsd.conf“."
+
+msgid "Folio"
+msgstr "Folio"
+
+msgid "Forbidden"
+msgstr "Verboten"
+
+msgid "General"
+msgstr "Allgemein"
+
+msgid "Generic"
+msgstr "Allgemein"
+
+msgid "German FanFold"
+msgstr "Deutsch Endlospapier"
+
+msgid "German FanFold Legal"
+msgstr "Deutsch Endlospapier (Brief)"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU hat unbestimmte Länge"
+
+msgid "Glossy Paper"
+msgstr "Glanzpapier"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Graustufen"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Hängeordner"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Hängeordner – 9/16 x 2 Zoll"
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk wurde in den Systemeinstellungen deaktiviert.\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk wurde in den Systemeinstellungen deaktiviert.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: Druckauftrag abbrechen …\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: Mit Drucker verbunden …\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: Mit Drucker verbinden …\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: Steuerungsdatei erfolgreich übertragen\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr ""
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: Datendatei erfolgreich übertragen\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: Seite %d formatieren …\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: Bilddatei laden …\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: Drucker suchen …\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: Verbindung herstellen\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr "INFO: Druckdatei gesendet, warten auf Abschließen des Druckers …\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: Drucker ist ausgelastet, erneuter Versuch in 10 Sekunden …\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: Drucker ist ausgelastet, erneuter Versuch in 30 Sekunden …\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: Drucker ist ausgelastet, erneuter Versuch in 5 Sekunden …\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr ""
+"INFO: Drucker unterstützt IPP/%d.%d nicht, erneuter Versuch mit IPP/1.0 …\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: Drucker ausgelastet, erneuter Versuch in 5 Sekunden …\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: Drucker ist derzeit offline.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: Drucker ist derzeit offline.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: Drucker ist jetzt online.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: Drucker ist offline.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: Drucker nicht verbunden, erneuter Versuch in 30 Sekunden …\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: Seite %d drucken, %d %% abgeschlossen …\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: Seite %d drucken …\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: Bereit zum Drucken\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: Steuerungsdatei senden (%lu Byte)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: Steuerungsdatei senden (%u Byte)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: Daten senden\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: Datendatei senden (%ld Byte)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: Datendatei senden (%lld Byte)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: Druckdaten senden …\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: Druckdatei gesendet, %ld Byte …\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: Druckdatei gesendet, %lld Byte …\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: LPR-Druckauftrag aufzeichnen, %.0f %% abgeschlossen …\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr ""
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: Verbindung zum Drucker nicht möglich; an den nächsten Drucker der "
+"Klasse senden …\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: Standard-AppleTalk-Zone „%s“ verwenden\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: Warten, bis der Druckauftrag agbeschlossen ist …\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: Warten, bis der Drucker verfügbar ist …\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "ISO B4 Umschlag"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (Übergröße)"
+
+msgid "ISO B5 Envelope"
+msgstr "ISO B5 Umschlag"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "ISO B6 Umschlag"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "Ungültiges Steuerungszeichen"
+
+msgid "Illegal main keyword string"
+msgstr "Ungültiger Main-Keyword-String"
+
+msgid "Illegal option keyword string"
+msgstr "Ungültiger Option-Keyword-String"
+
+msgid "Illegal translation string"
+msgstr "Ungültiger Übersetzungsstring"
+
+msgid "Illegal whitespace character"
+msgstr "Ungültiges Leerzeichen"
+
+msgid "Installable Options"
+msgstr "Installationsoptionen"
+
+msgid "Installed"
+msgstr "Installiert"
+
+msgid "IntelliBar Label Printer"
+msgstr "IntelliBar Etikettendrucker"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr ""
+
+msgid "Internal error"
+msgstr "Interner Fehler"
+
+msgid "Internet Postage 2-Part"
+msgstr "Internet Postage 2-teilig"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Internet Postage 2-teilig – 2 1/4 x 7 1/2 Zoll"
+
+msgid "Internet Postage 3-Part"
+msgstr "Internet Postage 3-teilig"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Internet Postage 3-teilig – 2 1/4 x 7 Zoll"
+
+msgid "Internet Printing Protocol"
+msgstr "Internet-Druckerprotokoll"
+
+msgid "Invite Envelope"
+msgstr "Einladung Umschlag"
+
+msgid "Italian Envelope"
+msgstr "Italienisch Umschlag"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "Druckauftrag Nr. %d wurde bereits abgebrochen – Abbruch nicht möglich."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "Druckauftrag Nr. %d wurde bereits abgebrochen – Abbruch nicht möglich."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr ""
+"Druckauftrag Nr. %d wurde bereits abgeschlossen – Abbruch nicht möglich."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "Druckauftrag abgeschlossen"
+
+msgid "Job Created"
+msgstr "Druckauftrag erzeugt"
+
+msgid "Job ID: "
+msgstr "Druckauftrags-ID: "
+
+msgid "Job Options Changed"
+msgstr "Druckauftragsoptionen wurden geändert"
+
+msgid "Job Stopped"
+msgstr "Druckauftrag gestoppt"
+
+msgid "Job UUID: "
+msgstr "Druckauftrags-UUID: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "Druckauftrag ist abgeschlossen und kann nicht geändert werden."
+
+msgid "Job operation failed:"
+msgstr "Druckvorgang fehlgeschlagen:"
+
+msgid "Job state cannot be changed."
+msgstr "Druckauftragsstatus kann nicht geändert werden."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "Druckaufträge"
+
+msgid "Kaku2 Envelope"
+msgstr "Kaku2 Umschlag"
+
+msgid "Kaku3 Envelope"
+msgstr "Kaku3 Umschlag"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "LPD/LPR-Host oder -Drucker"
+
+msgid "Label Printer"
+msgstr "Etikettendrucker"
+
+msgid "Label Top"
+msgstr "Etikett (oben)"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Adresse (groß)"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Adresse (groß) – 1 4/10 x 3 1/2 Zoll"
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet Serie PCL 4/5"
+
+msgid "Light"
+msgstr "Hell"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Zeile ist länger als maximal zulässig (255 Zeichen)"
+
+msgid "List Available Printers"
+msgstr "Verfügbare Drucker anzeigen"
+
+msgid "Location: "
+msgstr "Standort: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "Lange Kante (Hochformat)"
+
+msgid "Make and Model: "
+msgstr "Hersteller und Modell: "
+
+msgid "Manual Feed"
+msgstr "Manuelle Papierzufuhr"
+
+msgid "Media Dimensions: "
+msgstr "Medienmaße: "
+
+msgid "Media Limits: "
+msgstr "Mediendruckgrenzen: "
+
+msgid "Media Name: "
+msgstr "Medienname: "
+
+msgid "Media Size"
+msgstr "Mediengröße"
+
+msgid "Media Source"
+msgstr "Medienquelle"
+
+msgid "Media Tracking"
+msgstr "Medienführung"
+
+msgid "Media Type"
+msgstr "Medienart"
+
+msgid "Medium"
+msgstr "Medium"
+
+msgid "Memory allocation error"
+msgstr "Fehler bei der Speicherzuteilung"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "PPD-Adobe-4.x Header fehlt"
+
+msgid "Missing asterisk in column 1"
+msgstr "Sternchen in Spalte 1 fehlt"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "Wertestring fehlt"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Modell: Name = %s\n"
+" Standardsprache = %s\n"
+" Hersteller und Modell = %s\n"
+" Geräte-ID = %s\n"
+
+msgid "Modify Class"
+msgstr "Klasse verändern"
+
+msgid "Modify Printer"
+msgstr "Drucker verändern"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "US Monarch Umschlag"
+
+msgid "Move All Jobs"
+msgstr "Alle Druckaufträge bewegen"
+
+msgid "Move Job"
+msgstr "Druckauftrag bewegen"
+
+msgid "Moved Permanently"
+msgstr "Dauerhaft bewegt"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: Druckdatei akzeptiert – Druckauftrags-ID %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: Druckdatei akzeptiert – Druckauftrags-ID unbekannt.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "NULL PPD File Pointer"
+
+msgid "Name OID uses indefinite length"
+msgstr "Name-OID hat unbestimmte Länge"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Niemals"
+
+msgid "New Stylus Color Series"
+msgstr "New Stylus Color Serie"
+
+msgid "New Stylus Photo Series"
+msgstr "New Stylus Photo Serie"
+
+msgid "No"
+msgstr "Nein"
+
+msgid "No Content"
+msgstr "Kein Inhalt"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "Keine VarBind SEQUENCE"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "Keine aktive Verbindung"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "Kein Community-Name"
+
+msgid "No default printer"
+msgstr "Kein Standarddrucker"
+
+msgid "No destinations added."
+msgstr "Keine Ziele hinzugefügt."
+
+msgid "No error-index"
+msgstr "Kein Fehlerindex"
+
+msgid "No error-status"
+msgstr "Kein Fehlerstatus"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "Kein Name-OID"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "Keine Anfrage-ID"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "Keine Subskriptionen gefunden."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "Keine „variable-bindings SEQUENCE“"
+
+msgid "No version number"
+msgstr "Keine Versionsnummer"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "Nicht fortlaufend (Mark-Sensing)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "Nicht fortlaufend (Web-Sensing)"
+
+msgid "Normal"
+msgstr "Normal"
+
+msgid "Not Found"
+msgstr "Nicht gefunden"
+
+msgid "Not Implemented"
+msgstr "Nicht implementiert"
+
+msgid "Not Installed"
+msgstr "Nicht installiert"
+
+msgid "Not Modified"
+msgstr "Nicht verändert"
+
+msgid "Not Supported"
+msgstr "Nicht unterstützt"
+
+msgid "Not allowed to print."
+msgstr "Drucken nicht erlaubt."
+
+msgid "Note"
+msgstr "Hinweis"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Off (1-Sided)"
+msgstr "Aus (Einseitig)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Online-Hilfe"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "%s öffnen fehlgeschlagen: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup ohne CloseGroup zuerst"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI ohne CloseUI/JCLCloseUI zuerst"
+
+msgid "Operation Policy"
+msgstr "Nutzungsrichtlinien"
+
+msgid "Options Installed"
+msgstr "Installierte Optionen"
+
+msgid "Options: "
+msgstr "Optionen: "
+
+msgid "Output Mode"
+msgstr "Ausgabemodus"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "Ausgabe für Drucker „%s“ wird an „%s“ gesendet\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr ""
+"Ausgabe für Drucker „%s“ wird an den entfernten Drucker „%s“ auf „%s“ "
+"gesendet\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "Ausgabe für Drucker „%s/%s“ wird an „%s“ gesendet\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr ""
+"Ausgabe für Drucker „%s/%s“ wird an den entfernten Drucker „%s“ auf „%s“ "
+"gesendet\n"
+
+msgid "PASS\n"
+msgstr "PASS\n"
+
+msgid "PCL Laser Printer"
+msgstr "PCL Laserdrucker"
+
+msgid "PRC1 Envelope"
+msgstr "PRC1 Umschlag"
+
+msgid "PRC10 Envelope"
+msgstr "PRC10 Umschlag"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "PRC2 Umschlag"
+
+msgid "PRC3 Envelope"
+msgstr "PRC3 Umschlag"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (Übergröße)"
+
+msgid "PRC4 Envelope"
+msgstr "PRC4 Umschlag"
+
+msgid "PRC5 Envelope"
+msgstr "PRC5 Umschlag"
+
+msgid "PRC6 Envelope"
+msgstr "PRC6 Umschlag"
+
+msgid "PRC7 Envelope"
+msgstr "PRC7 Umschlag"
+
+msgid "PRC8 Envelope"
+msgstr "PRC8 Umschlag"
+
+msgid "PRC9 Envelope"
+msgstr "PRC9 Umschlag"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "Paket enthält kein Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "Paket beginnt nicht mit SEQUENCE"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "Das Kennwort für „%s“ auf „%s“? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr ""
+"Das Kennwort für „%s“ wird benötigt für den Zugriff auf „%s“ über SAMBA: "
+
+msgid "Pause Class"
+msgstr "Klasse anhalten"
+
+msgid "Pause Printer"
+msgstr "Drucker anhalten"
+
+msgid "Peel-Off"
+msgstr "Aufkleber"
+
+msgid "Personal Envelope"
+msgstr "Persönlicher Umschlag"
+
+msgid "Photo"
+msgstr "Foto"
+
+msgid "Photo Labels"
+msgstr "Foto-Etiketten"
+
+msgid "Plain Paper"
+msgstr "Standardpapier"
+
+msgid "Policies"
+msgstr "Richtlinien "
+
+msgid "Port Monitor"
+msgstr "Port-Monitor"
+
+msgid "PostScript Printer"
+msgstr "PostScript-Drucker"
+
+msgid "Postcard"
+msgstr "Postkarte"
+
+msgid "Print Density"
+msgstr "Druckdichte"
+
+msgid "Print Job:"
+msgstr "Druckauftrag:"
+
+msgid "Print Mode"
+msgstr "Druckmodus"
+
+msgid "Print Rate"
+msgstr "Druckrate"
+
+msgid "Print Self-Test Page"
+msgstr "Selbsttestseite drucken"
+
+msgid "Print Speed"
+msgstr "Druckgeschwindigkeit"
+
+msgid "Print Test Page"
+msgstr "Testseite drucken"
+
+msgid "Print and Cut"
+msgstr "Drucken und abschneiden"
+
+msgid "Print and Tear"
+msgstr "Drucken und abziehen"
+
+msgid "Printed For: "
+msgstr "Gedruckt für: "
+
+msgid "Printed From: "
+msgstr "Gedruckt von: "
+
+msgid "Printed On: "
+msgstr "Gedruckt am: "
+
+msgid "Printer Added"
+msgstr "Drucker hinzugefügt"
+
+msgid "Printer Default"
+msgstr "Standardeinstellung für Drucker"
+
+msgid "Printer Deleted"
+msgstr "Drucker gelöscht"
+
+msgid "Printer Modified"
+msgstr "Drucker geändert"
+
+msgid "Printer Name: "
+msgstr "Druckername: "
+
+msgid "Printer Paused"
+msgstr "Drucker angehalten"
+
+msgid "Printer Settings"
+msgstr "Druckereinstellungen"
+
+msgid "Printer:"
+msgstr "Drucker:"
+
+msgid "Printers"
+msgstr "Drucker"
+
+msgid "Purge Jobs"
+msgstr "Druckaufträge aufräumen"
+
+msgid "Quarto"
+msgstr "US Quarto"
+
+msgid "Quota limit reached."
+msgstr "Kontingentgrenze erreicht."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr ""
+"Rang Eigentümer Druckauftrag Datei(en) "
+"Gesamtgröße\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"Rang Eigentümer Druckauftrag Dateien "
+"Gesamtgröße\n"
+
+msgid "Reject Jobs"
+msgstr "Druckaufträge ablehnen"
+
+msgid "Reprint After Error"
+msgstr "Druckvorgang nach dem Fehler fortsetzen"
+
+msgid "Request Entity Too Large"
+msgstr "Gesamte Anfrage zu groß"
+
+msgid "Resolution"
+msgstr "Auflösung"
+
+msgid "Resume Class"
+msgstr "Klasse fortsetzen"
+
+msgid "Resume Printer"
+msgstr "Drucken fortsetzen"
+
+msgid "Return Address"
+msgstr "Absender-Adresse"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Absender-Adresse – 3/4 x 2 Zoll"
+
+msgid "Rewind"
+msgstr "Zurückdrehen"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Befehl ausführen: %s %s -N -A %s -c '%s'\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE hat unbestimmte Länge"
+
+msgid "See Other"
+msgstr "Siehe auch"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "Serieller Anschluss Nr. %d"
+
+msgid "Server Restarted"
+msgstr "Server neu gestartet"
+
+msgid "Server Security Auditing"
+msgstr "Server Security Auditing"
+
+msgid "Server Started"
+msgstr "Server gestartet"
+
+msgid "Server Stopped"
+msgstr "Server gestoppt"
+
+msgid "Service Unavailable"
+msgstr "Dienst nicht verfügbar"
+
+msgid "Set Allowed Users"
+msgstr "Zugelassene Benutzer festlegen"
+
+msgid "Set As Server Default"
+msgstr "Als Standardeinstellungen für Server festlegen"
+
+msgid "Set Class Options"
+msgstr "Klassenoptionen festlegen"
+
+msgid "Set Printer Options"
+msgstr "Druckeroptionen festlegen"
+
+msgid "Set Publishing"
+msgstr "Veröffentlichung festlegen"
+
+msgid "Shipping Address"
+msgstr "Lieferadresse"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "Lieferadresse – 2 5/16 x 4 Zoll"
+
+msgid "Short-Edge (Landscape)"
+msgstr "Kurze Kante (Querformat)"
+
+msgid "Special Paper"
+msgstr "Spezialpapier"
+
+msgid "Standard"
+msgstr "Standard"
+
+msgid "Starting Banner"
+msgstr "Startbanner"
+
+msgid "Statement"
+msgstr "US Statement"
+
+msgid "Stylus Color Series"
+msgstr "Stylus Color Serie"
+
+msgid "Stylus Photo Series"
+msgstr "Stylus Photo Serie"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "Protokoll wechseln"
+
+msgid "Tabloid"
+msgstr "US Tabloid"
+
+msgid "Tabloid (Oversize)"
+msgstr "US Tabloid (Übergröße)"
+
+msgid "Tear"
+msgstr "Abziehen"
+
+msgid "Tear-Off"
+msgstr "Abziehen"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Abziehposition"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "Die PPD-Datei „%s“ konnte nicht gefunden werden."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "Die PPD-Datei „%s“ konnte nicht geöffnet werden: %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Der Klassenname darf maximal 127 druckbare Zeichen haben und darf keine "
+"Leerzeichen, Schrägstriche (/) oder Rautezeichen (#) enthalten."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+"Das Attribut „notify-lease-duration“ kann nicht mit Druckauftrags-"
+"Subskriptionen verwendet werden."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Der Druckername darf maximal 127 druckbare Zeichen haben und darf keine "
+"Leerzeichen, Schrägstriche (/) oder Rautezeichen (#) enthalten."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "Der Drucker oder die Klasse wurden nicht gefunden!"
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "Die Drucker-URI „%s“ enthält ungültige Zeichen."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr ""
+"Die Drucker-URI muss in der folgenden Form vorliegen: ipp://HOSTNAME/classes/"
+"CLASSNAME"
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+"Die Drucker-URI muss in der folgenden Form vorliegen: ipp://HOSTNAME/"
+"printers/PRINTERNAME"
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"Der Subkriptionsname darf keine Leerzeichen, Schrägstriche (/), Fragezeichen "
+"(?) oder Rautezeichen (#) enthalten."
+
+msgid "There are too many subscriptions."
+msgstr "Es liegen zu viele Subskriptionen vor."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "Thermal Transfer Media"
+
+msgid "Title: "
+msgstr "Titel: "
+
+msgid "Too many active jobs."
+msgstr "Zu viele aktive Druckaufträge."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "Transparenz"
+
+msgid "Tray"
+msgstr "Fach"
+
+msgid "Tray 1"
+msgstr "Fach 1"
+
+msgid "Tray 2"
+msgstr "Fach 2"
+
+msgid "Tray 3"
+msgstr "Fach 3"
+
+msgid "Tray 4"
+msgstr "Fach 4"
+
+msgid "URI Too Long"
+msgstr "URI zu lang"
+
+msgid "US Executive"
+msgstr "US Executive"
+
+msgid "US Fanfold"
+msgstr "US Endlospapier"
+
+msgid "US Ledger"
+msgstr "US Ledger"
+
+msgid "US Legal"
+msgstr "US Lang"
+
+msgid "US Legal (Oversize)"
+msgstr "US Lang (Übergröße)"
+
+msgid "US Letter"
+msgstr "US Brief"
+
+msgid "US Letter (Oversize)"
+msgstr "US Brief (Übergröße)"
+
+msgid "US Letter (Small)"
+msgstr "US Brief (klein)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "USB Serieller Anschluss Nr. %d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "Kein Zugriff auf Datei „cupsd.conf“:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "RSS-Abo konnte nicht hinzugefügt werden:"
+
+msgid "Unable to add class:"
+msgstr "Klasse konnte nicht hinzugefügt werden:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "Drucker konnte nicht hinzugefügt werden:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "RSS-Abo konnte nicht widerrufen werden:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "Attribut „printer-is-shared“ konnte nicht geändert werden:"
+
+msgid "Unable to change printer:"
+msgstr "Drucker konnte nicht geändert werden:"
+
+msgid "Unable to change server settings:"
+msgstr "Servereinstellungen konnten nicht geändert werden:"
+
+msgid "Unable to connect to host."
+msgstr "Verbindungsaufbau zum Host fehlgeschlagen."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "Temporäre Datei konnte nicht erstellt werden:"
+
+msgid "Unable to delete class:"
+msgstr "Klasse konnte nicht gelöscht werden:"
+
+msgid "Unable to delete printer:"
+msgstr "Drucker konnte nicht gelöscht werden:"
+
+msgid "Unable to do maintenance command:"
+msgstr "Wartungsbefehl konnte nicht ausgeführt werden:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "Klassenliste konnte nicht abgerufen werden:"
+
+msgid "Unable to get class status:"
+msgstr "Klassenstatus konnte nicht abgerufen werden:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "Liste der Druckertreiber konnte nicht abgerufen werden:"
+
+msgid "Unable to get printer attributes:"
+msgstr "Druckerattribute konnten nicht abgerufen werden:"
+
+msgid "Unable to get printer list:"
+msgstr "Druckerliste konnte nicht abgerufen werden:"
+
+msgid "Unable to get printer status:"
+msgstr "Druckerstatus konnte nicht abgerufen werden:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "Klasse konnte nicht verändert werden:"
+
+msgid "Unable to modify printer:"
+msgstr "Drucker konnte nicht verändert werden:"
+
+msgid "Unable to move job"
+msgstr "Druckauftrag konnte nicht bewegt werden"
+
+msgid "Unable to move jobs"
+msgstr "Druckaufträge konnten nicht bewegt werden"
+
+msgid "Unable to open PPD file"
+msgstr "Die PPD-Datei konnte nicht geöffnet werden"
+
+msgid "Unable to open PPD file:"
+msgstr "Die PPD-Datei konnte nicht geöffnet werden:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "Die Datei „cupsd.conf“ konnte nicht geöffnet werden:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "Testseite konnte nicht gedruckt werden:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "„%s“ konnte nicht ausgeführt werden: %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "Optionen konnten nicht festgelegt werden:"
+
+msgid "Unable to set server default:"
+msgstr "Standardeinstellungen für Server konnten nicht festgelegt werden:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "Die Datei „cupsd.conf“ konnte nicht hochgeladen werden:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "Nicht berechtigt"
+
+msgid "Units"
+msgstr "Einheiten"
+
+msgid "Unknown"
+msgstr "Unbekannt"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "Unbekannte printer-error-policy „%s“."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "Unbekannte printer-op-policy „%s“."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Wertetyp nicht unterstützt"
+
+msgid "Upgrade Required"
+msgstr "Aktualisierung erforderlich"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "Usage: %s job user title copies options [filename]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "Usage: %s job-id user title copies options [file]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "Usage: %s job-id user title copies options file\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Usage: lpmove job/src dest\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Usage: lppasswd [-g groupname]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Usage: snmp [host-or-ip-address]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Wert hat unbestimmte Länge"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind hat unbestimmte Länge"
+
+msgid "Version uses indefinite length"
+msgstr "Version hat unbestimmte Länge"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: Nur die ersten %d gefundenen Drucker werden hinzugefügt"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: Boolscher Wert erwartet für waiteof-Option „%s“\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: Drucker reagiert nicht\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: Drucker sendete unerwartet EOF\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: „%s:%s“ konnte nicht geöffnet werden: %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: PAP-Statusanfrage konnte nicht gesendet werden"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: Unerwartetes PAP-Paket des Typs „%d“\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: Unbekanntes PAP-Paket des Typs „%d“\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: Zahlwert erwartet für Statusoption „%s“\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Ja"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"Auf diese Seite greifen Sie zu über die URL <A HREF=\"https://%s:%d%s"
+"\">https://%s:%d%s</A>."
+
+msgid "You4 Envelope"
+msgstr "You4 Umschlag"
+
+msgid "ZPL Label Printer"
+msgstr "ZPL Etikettendrucker"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "abgebrochen"
+
+msgid "canceled"
+msgstr "abgebrochen"
+
+msgid "completed"
+msgstr "abgeschlossen"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr ""
+"konvertieren: Mit der -f Option eine Datei zum Konvertieren festlegen.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "„cups-deviced“ konnte nicht ausgeführt werden."
+
+msgid "cups-driverd failed to execute."
+msgstr "„cups-driverd“ konnte nicht ausgeführt werden."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: keine PPD-Datei für Drucker „%s“ – %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: Verbindungsaufbau zum Server fehlgeschlagen: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr ""
+"cupsd: „launchd(8) support“ nicht übersetzt, in „normal mode“ ausführen.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: Druckauftragsdatei konnte nicht geladen werden – %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd: '-q'-Option ist nicht kompatibel mit der '-v'-Option.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd: '-v'-Option ist nicht kompatibel mit der '-q'-Option.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "Gerät für %s/%s: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "Gerät für %s: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "Fehlerindex hat unbestimmte Länge"
+
+msgid "error-status uses indefinite length"
+msgstr "Fehlerstatus hat unbestimmte Länge"
+
+msgid "held"
+msgstr "gehalten"
+
+msgid "help\t\tget help on commands\n"
+msgstr "help\t\tget help on commands\n"
+
+msgid "idle"
+msgstr "inaktiv"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: Drucker „%s“ gehört bereits zur Klasse „%s“.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: Drucker „%s“ gehört bereits zur Klasse „%s“.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: Verbindungsaufbau zum Server fehlgeschlagen: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: PPD-Datei „%s“ konnte nicht geöffnet werden – %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: Datei „%s“ konnte nicht geöffnet werden: %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: Verbindungsaufbau zum Server fehlgeschlagen: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: Drucker oder Instanz konnten nicht hinzugefügt werden: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: PPD-Datei für „%s“ konnte nicht geladen werden: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: Kennwort abgelehnt.\n"
+"Das Kennwort muss mindestens 6 Zeichen lang sein, darf nicht Ihren "
+"Benutzernamen enthalten und muss mindestens einen Buchstaben und eine Zahl "
+"enthalten.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: Kennwortstring konnte nicht kopiert werden: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: Kennwortdatei konnte nicht geöffnet werden: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: In die Kennwortdatei konnte nicht geschrieben werden: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr "lppasswd: Sichern der alten Kennwortdatei fehlgeschlagen: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: Kennwortdatei konnte nicht umbenannt werden: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: Benutzer „%s“ und Gruppe „%s“ existieren nicht.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "gehört zu Klasse „%s“:\n"
+
+msgid "no entries\n"
+msgstr "keine Einträge\n"
+
+msgid "no system default destination\n"
+msgstr "kein System-Standardzielort\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "ausstehend"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: Ordner „%s“ hinzufügen …\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: UI-Text von „%s“ hinzufügen/aktualisieren …\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: Ungültiger Boolscher Wert (%s) in Zeile %d von %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: Ungültige Variablenersetzung ($%c) in Zeile %d von %s.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: Boolschen Wert erwartet in Zeile %d von %s.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: Auswahlcode erwartet in Zeile %d von %s.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: Auswahlname/-text erwartet in Zeile %d von %s.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: Treiberinfodatei „%s“ laden …\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: Meldungen für Locale „%s“ laden …\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: Meldungen von „%s“ laden …\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: PPD-Datei „%s“ konnte nicht erstellt werden – %s.\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: Ausgabeordner „%s“ konnte nicht erstellt werden: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: Ausgabekanäle konnten nicht erstellt werden: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: cupstestppd konnte nicht ausgeführt werden: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: Lokalisierung für „%s“ wurde nicht gefunden – %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: Lokalisierungsdatei „%s“ konnte nicht geladen werden – %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: Nicht defnierte Variable (%s) in Zeile %d von %s.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: %s schreiben …\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: PPD-Dateien schreiben in Ordner „%s“ …\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: PPD-Datei „%s“ ignorieren …\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: Backup von „%s“ auf %s fehlgeschlagen – %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "Drucker „%s“ deaktiviert seit %s -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "Drucker „%s“ ist inaktiv; aktiviert seit %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "Drucker „%s“ druckt gerade %s–%d; aktiviert seit %s\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "Drucker „%s/%s“ deaktiviert seit %s -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "Drucker „%s/%s“ ist inaktiv; aktiviert seit %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "Drucker „%s/%s“ druckt gerade %s–%d; aktiviert seit %s\n"
+
+msgid "processing"
+msgstr "Bearbeiten"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "Anfrage-ID ist %s–%d (%d Datei(en))\n"
+
+msgid "request-id uses indefinite length"
+msgstr "Anfrage-ID hat unbestimmte Länge"
+
+msgid "scheduler is not running\n"
+msgstr "Scheduler ist nicht aktiv\n"
+
+msgid "scheduler is running\n"
+msgstr "Scheduler ist aktiv\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "Status von %s fehlgeschlagen: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "Status\t\tStatus für Daemon und Warteliste anzeigen\n"
+
+msgid "stopped"
+msgstr "Gestoppt"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "System-Standardzielort: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "System-Standardzielort: %s/%s\n"
+
+msgid "unknown"
+msgstr "Unbekannt"
+
+msgid "untitled"
+msgstr "Ohne Titel"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindings hat unbestimmte Länge"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " WARN %s hat keine passenden Optionen!\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " WARN Konflikt bei Standardauswahl!\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " WARN Duplex-Option-Keyword „%s“ funktioniert u. U. nicht wie "
+#~ "erwartet – es sollte „Duplex“ heißen!\n"
+#~ " REF: Seite 122, Abschnitt 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " WARN Datei enthält Mischung aus den Zeilenenden „CR“, „LF“ und "
+#~ "„CR LF“!\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " WARN Zeile %d enthält nur Leerzeichen!\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " WARN APDialogExtension-Datei „%s“ fehlt\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " WARN APPrinterIconPath-Datei „%s“ fehlt\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " WARN Windows-fremde PPD-Datei sollte nur Zeilenenden mit „LF“ "
+#~ "verwenden, nicht mit „CR LF“!\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " WARN Veraltete PPD-Version %.1f!\n"
+#~ " REF: Seite 42, Abschnitt 5.2.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s existiert nicht!\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s Ungültig: %s Auswahl %s!\n"
+#~ " REF: Seite 122, Abschnitt 5.17\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr ""
+#~ " %s Ungültiger UTF-8 „%s“ Übersetzungsstring für Option „%s“!\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Ungültiger UTF-8 „%s“ Übersetzungsstring für Option „%s“, "
+#~ "Auswahl „%s“!\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Ungültiger cupsFilter-Wert „%s“!\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s Ungültiges cupsICCProfile „%s“!\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Ungültiger cupsPreFilter-Wert „%s“!\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Ungültiges cupsUIConstraints „%s“: „%s“!\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s Ungültige Sprache „%s“!\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s Leeres cupsUIConstraints „%s“!\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s Fehlender „%s“-Übersetzungsstring für Option „%s“!\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Fehlender „%s“-Übersetzungsstring für Option „%s“, Auswahl „%"
+#~ "s“!\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Fehlende Auswahl „*%s %s“ in UIConstraints „*%s %s *%s %s“!\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr ""
+#~ " %s Fehlende Auswahl „*%s %s“ in cupsUIConstraints „%s“: „%s“!\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s Fehlende cupsICCProfile-Datei „%s“!\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s Fehlender cupsUIResolver „%s“!\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr " %s Fehlende Option „%s“ in UIConstraints „*%s %s *%s %s“!\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Fehlende Option „%s“ in cupsUIConstraints „%s“: „%s“!\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr " %s Keine Basisübersetzung „%s“ in der Datei enthalten!\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s BENÖTIGT: „%s“ definiert Auswahl nicht als „None“!\n"
+#~ " REF: Seite 122, Abschnitt 5.17\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " %s Hash-Wert von cupsICCProfile „%s“ in Konflikt mit „%s“!\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver „%s“ erzeugt eine Schleife!\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FEHLER** %s-Auswahlnamen „%s“ und „%s“ unterscheiden sich nur "
+#~ "durch Groß-/Kleinschreibung!\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **FEHLER** „%s“ muss 1284DeviceID sein!\n"
+#~ " REF: Seite 72, Abschnitt 5.5\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **FEHLER** UNGÜLTIG: DefaultImageableArea „%s“!\n"
+#~ " REF: Seite 102, Abschnitt 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **FEHLER** UNGÜLTIG: DefaultPaperDimension „%s“!\n"
+#~ " REF: Seite 103, Abschnitt 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **FEHLER** Ungültig: „%s“ Auswahl „%s“!\n"
+#~ " REF: Seite 84, Abschnitt 5.9\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr ""
+#~ " **FEHLER** Ungültiges LanguageEncoding „%s“ – muss „ISOLatin1“ "
+#~ "sein!\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr ""
+#~ " **FEHLER** Ungültige LanguageVersion „%s“ – muss „Englisch“ sein!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **FEHLER** Standard-Übersetzungsstring für Option „%s“ Auswahl „%"
+#~ "s“ enthält 8-Bit-Zeichen!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **FEHLER** Standard-Übersetzungsstring für Option „%s“ enthält 8-"
+#~ "Bit-Zeichen!\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FEHLER** Gruppennamen „%s“ und „%s“ unterscheiden sich nur durch "
+#~ "Groß-/Kleinschreibung!\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **FEHLER** Mehrere Vorkommen des „%s“-Auswahlnamens „%s“!\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FEHLER** Optionnamen „%s“ und „%s“ unterscheiden sich nur durch "
+#~ "Groß-/Kleinschreibung!\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " Ungültige %%%%BoundingBox: in Zeile %d!\n"
+#~ " REF: Seite 39, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " Ungültige %%%%Page: in Zeile %d!\n"
+#~ " REF: Seite 53, %%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " Ungültige %%%%Pages: in Zeile %d!\n"
+#~ " REF: Seite 43, %%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " Zeile %d ist länger als 255 Zeichen (%d)!\n"
+#~ " REF: Seite 25, Line Length\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " %!PS-Adobe-3.0 fehlt in der ersten Zeile!\n"
+#~ " REF: Seite 17, 3.1 Conforming Documents\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " %%EndComments-Kommentar fehlt!\n"
+#~ " REF: Seite 41, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " %%BoundingBox fehlt oder ist ungültig: Kommentar!\n"
+#~ " REF: Seite 39, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " %%Page fehlt oder ist ungültig: Kommentare!\n"
+#~ " REF: Seite 53, %%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " %%Pages fehlt oder ist ungültig: Kommentar!\n"
+#~ " REF: Seite 43, %%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " %d Zeilen mit über 255 Zeichen gefunden!\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " Zu viele %%BeginDocument-Kommentare!\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " Zu viele %%EndDocument-Kommentare!\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " Achtung: Datei enthält Binärdaten!\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " Achtung: kein %%EndComments-Kommentar in der Datei!\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " Achtung: veraltete DSC-Version %.1f in der Datei!\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s nicht unterstützt!"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: Weiß nicht, was ich tun soll!\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: Fehler – %s Umgebungsvariablennamen nicht vorhanden für Ziel „%s“!\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: Fehler – ungültige Druckauftrags-ID!\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr ""
+#~ "%s: Fehler – kann nicht gleichzeitig Dateien drucken und Druckaufträge "
+#~ "ändern!\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: Fehler – kann nicht von „stdin“, wenn Dateien oder eine Druckauftrags-"
+#~ "ID übergeben werden!\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: Fehler – Zeichensatz erwartet nach '-S'-Option!\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: Fehler – Inhaltstyp erwartet nach '-T'-Option!\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: Fehler – Kopien erwartet nach '-n'-Option!\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s: Fehler – Kopienanzahl erwartet nach '-#'-Option!\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: Fehler – Ziel erwartet nach '-P'-Option!\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: Fehler – Ziel erwartet nach '-b'-Option!\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: Fehler – Ziel erwartet nach '-d'-Option!\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: Fehler – Form erwartet nach '-f'-Option!\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: Fehler – Name halten erwartet nach '-H'-Option!\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: Fehler – Hostname erwartet nach '-H'-Option!\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: Fehler – Hostname erwartet nach '-h'-Option!\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: Fehler – Modusliste erwartet nach '-y'-Option!\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: Fehler – Name erwartet nach '-%c'-Option!\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s: Fehler – Optionsstring erwartet nach '-o'-Option!\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: Fehler – Seitenliste erwartet nach '-P'-Option!\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: Fehler – Priorität erwartet nach '-%c'-Option!\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s: Fehler – Text mit Grund erwartet nach '-r'-Option!\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: Fehler – Titel erwartet nach '-t'-Option!\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s: Fehler – Benutzername erwartet nach '-U'-Option!\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s: Fehler – Benutzername erwartet nach '-u'-Option!\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: Fehler – Wert erwartet nach '-%c'-Option!\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: Fehler – benötigt „completed“, „not-completed“ oder „all“ nach '-W'-"
+#~ "Option!\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: Fehler – Scheduler reagiert nicht!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: Fehler – unbekanntes Ziel „%s“!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: Fehler – unbekanntes Ziel „%s/%s“!\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: Fehler – unbekannte Option '%c'!\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: Fehler – unbekannte Option '%s'!\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: Druckauftrags-ID erwartet nach '-i'-Option!\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: Ungültiger Zielname in Liste „%s“!\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr "%s: Druckauftrags-ID ('-i jobid') benötigt vor '-H restart'!\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: Kein Filter für Konvertierung von %s/%s zu %s/%s!\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s: Verschlüsselungsunterstützung nicht verfügbar!\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: Verbindungsaufbau zum Server fehlgeschlagen!\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: MIME-Typ von „%s“ konnte nicht bestimmt werden!\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s: „%s“ konnte nicht geöffnet werden – %s\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s: „%s“ konnte nicht geöffnet werden – %s in Zeile %d.\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr ""
+#~ "%s: MIME-Datenbank von „%s“ oder „%s“ konnte nicht gelesen werden!\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: Unbekanntes Ziel „%s“!\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: Unbekannter Ziel-MIME-Typ „%s/%s“!\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: Unbekannte Option '%c'!\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: Unbekannter Quell-MIME-Typ „%s/%s“!\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: Achtung – '%c'-Format-Modifier nicht unterstützt – Ausgabe ist u. U. "
+#~ "nicht korrekt!\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: Achtung – Zeichensatzoption ignoriert!\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: Achtung – Inhaltstypoption ignoriert!\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: Achtung – Formoption ignoriert!\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: Achtung – Modusoption ignoriert!\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: Fehler – %s Umgebungsvariablennamen nicht vorhanden für Ziel „%s“!\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: Fehler – „option=value“ erwartet nach '-o'-Option!\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "600 DPI Graustufen"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr ""
+#~ "Es wird ein Samba-Kennwort benötigt, um Druckertreiber exportieren zu "
+#~ "können!"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr ""
+#~ "Es wird ein Samba-Benutzername benötigt, um Druckertreiber exportieren zu "
+#~ "können!"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "Es gibt bereits eine Klasse mit dem Namen „%s“!"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "Es gibt bereits einen Drucker mit dem Namen „%s“!"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr ""
+#~ "Versuch, den Druckerstatus für „%s“ auf den ungültigen Wert „%d“ zu "
+#~ "setzen!"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "Attributgruppen sind durcheinander (%x < %x)!"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "Ungültige Geräte-URI „%s“!\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "Ungültige Geräte-URI „%s“!"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "Ungültiges Geräte-URI-Schema „%s“!"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "Ungültiges Dokumentformat „%s“!"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Ungültiger Dateinamen-Puffer!"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Ungültiger Wert für Druckauftragspriorität!"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Ungültiger Wert „%s“ für Druckauftragslisten!"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Ungültiger Wertetyp für Druckauftragslisten!"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Ungültiger Wert für Druckauftragsstatus!"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Ungültiges Druckauftrags-URI-Attribut „%s“!"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "Ungültige Notify-Pull-Methode „%s“!"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "Ungültige Notify-Recipient-URI: URI „%s“!"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "Ungültige Option + Auswahl in Zeile %d!"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "Ungültiger Port-Monitor „%s“!"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Ungültiger Wert „%d“ für Druckerstatus!"
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "Ungültige Anfrage-Versionsnummer %d.%d!"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "Ungültige Subskriptions-ID!"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "Zeichensatz „%s“ nicht unterstützt!"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "Typ „%s“ konnte nicht durchsucht werden!"
+
+#~ msgid "Cover open."
+#~ msgstr "Die Abdeckung ist offen."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "Der Entwickler ist fast leer."
+
+#~ msgid "Developer empty!"
+#~ msgstr "Der Entwickler ist leer!"
+
+#~ msgid "Door open."
+#~ msgstr "Die Tür ist offen."
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Ungültige %%BoundingBox: Kommentar gesehen!\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: Ungültiges %%IncludeFeature: Kommentar!\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: Ungültige %%Page: Kommentar in Datei!\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: Ungültige %%PageBoundingBox: Kommentar in Datei!\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: Ungültige SCSI-Gerätedatei „%s“!\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: Ungültiger Spaltenwert „%d“!\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: Ungültiger cpi-Wert „%f“!\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: Ungültiger lpi-Wert „%f“!\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: Ungültiges Seitenformat!\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: Zieldrucker existiert nicht!\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Doppelte %%BoundingBox: Kommentar gesehen!\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: Doppelte %%Pages: Kommentar gesehen!\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: Leere Druckdatei!\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr "ERROR: String mit Anführungszeichen erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: Schwerwiegender USB-Fehler!\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr ""
+#~ "ERROR: Ungültiger HP-GL/2-Befehl aufgetreten; Datei konnte nicht gedruckt "
+#~ "werden!\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: Fehlender %%EndProlog!\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: Fehlendes %%EndSetup!\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Geräte-URI fehlt in der Befehlszeile und keine DEVICE_URI "
+#~ "Umgebungsvariable vorhanden!\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: Wert fehlt in Zeile %d der Bannerdatei!\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: msgid-Zeile benötigt vor allen Übersetzungsstrings in Zeile %d von "
+#~ "%s!\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: Keine %%BoundingBox: Kommentar im Header!\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: Keine %%Pages: Kommentar im Header!\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Keine Geräte-URI gefunden in „argv[0]“ oder in DEVICE_URI "
+#~ "Umgebungsvariable!\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: Keine Seiten gefunden!\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: Kein Papier mehr!\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: DRUCKER: Umgebungsvariable nicht definiert!\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: Druckdatei wurde nicht akzeptiert (%s)!\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: Drucker reagiert nicht!\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: Temporäre Datei konnte nicht erstellt werden – %s.\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: Temporäre Datei konnte nicht erstellt werden: %s.\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr ""
+#~ "ERROR: Attribute für Druckauftrag „%d“ konnten nicht abgefragt werden (%"
+#~ "s)!\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: Druckerstatus konnte nicht abgefragt werden (%s)!\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: Drucker „%s“ konnte nicht gefunden werden!\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: Bilddatei konnte nicht zum Drucken geöffnet werden!\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: Temporäre Datei konnte nicht geöffnet werden"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: %d Textspalten konnten nicht gedruckt werden!\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: %dx%d Textseite konnte nicht gedruckt werden!\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: Druckdaten konnten nicht gelesen werden!\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: Druckdaten konnten nicht gesendet werden (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: Druckdaten konnten nicht gesendet werden!\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: %d Byte konnten nicht auf den Drucker geschrieben werden!\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr ""
+#~ "ERROR: Rasterdaten konnten nicht auf den Treiber geschrieben werden!\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: Temporäre Datei konnte nicht geschrieben werden"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: Unerwarteter Text in Zeile %d von %s!\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: Unbekannter Verschlüsselungsoptionswert „%s“!\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: Unbekanntes Message-Catalog-Format für „%s“!\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: Unbekannte Option „%s“ mit Wert „%s“!\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: Unbekannter Versionsoptionswert „%s“!\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr ""
+#~ "ERROR: Nicht unterstützter Helligkeitswert „%s“; „brightness=100“ "
+#~ "verwenden!\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr ""
+#~ "ERROR: Nicht unterstützter Gammawert „%s“; „gamma=1000“ verwenden!\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr ""
+#~ "ERROR: Nicht unterstützter Number-Up-Wert „%d“; „number-up=1“ verwenden!\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: Nicht unterstützter Number-Up-Layout-Wert „%s“; „number-up-"
+#~ "layout=lrtb“ verwenden!\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: Nicht unterstützter Seitenrandwert „%s“; „page-border=none“ "
+#~ "verwenden!\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr "ERROR: doc_printf-Overflow (%d Byte) festgestellt; abbrechen!\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr "ERROR: pdftops-Filter fehlgeschlagen bei Signal „%d“!\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr "ERROR: pdftops-Filter ausgestiegen mit Status „%d“!\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops-Filter ausgestiegen bei Signal „%d“!\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops-Filter ausgestiegen mit Status „%d“!\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: wiederherstellbar: Verbindung zum Drucker nicht möglich, erneuter "
+#~ "Versuch in 30 Sekunden …\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "Leere PPD-Datei!"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "Fehler: Hostname benötigt nach '-h'-Option!\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Die Temperatur des Fixierers ist zu hoch!"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "Die Temperatur des Fixierers ist zu niedrig!"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "Drucker-URI-Attribute vorhanden, aber keine Druckauftrags-ID!"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Tinte/Toner fast leer."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Tinte/Toner leer!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Tinten/Toner-Abfallbehälter fast voll."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Tinten/Toner-Abfallbehälter voll!"
+
+#~ msgid "Interlock open."
+#~ msgstr "Die Verriegelung ist offen."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr ""
+#~ "Druckauftrag Nr. %d kann nicht neu gestartet werden – keine Dateien "
+#~ "vorhanden!"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "Druckauftrag Nr. %d existiert nicht!"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr ""
+#~ "Druckauftrag Nr. %d ist abgeschlossen und kann nicht geändert werden!"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "Druckauftrag Nr. %d ist nicht abgeschlossen!"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "Druckauftrag Nr. %d benötigt keine Authentifizierung!"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "Druckauftrag Nr. %d wird nicht gehalten!"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "Druckauftrag Nr. %s existiert nicht!"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "Druckauftrag %d wurde nicht gefunden!"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "Druckauftrags-Subskription kann nicht erneuert werden."
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "Sprache „%s“ nicht unterstützt!"
+
+#~ msgid "Media jam!"
+#~ msgstr "Papierstau im Medienfach!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Das Medienfach ist fast leer."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Das Medienfach ist leer!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Das Medienfach fehlt!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "Das Medienfach muss aufgefüllt werden."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "Attribut „document-number“ fehlt!"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "Doppeltes Anführungszeichen in Zeile %d fehlt!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "Formvariable fehlt!"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "Attribut „notify-subscription-ids“ fehlt!"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "Attribut „requesting-user-name“ fehlt!"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "Benötigte Attribute fehlen!"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "Wert in Zeile %d fehlt!"
+
+#~ msgid "No PPD name!"
+#~ msgstr "Kein PPD-Name!"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Es sind keine Windows-Druckertreiber installiert!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "Keine aktiven Druckaufträge auf %s!"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "Keine Attribute abgerufen!"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "Keine Authentifizierungs-Informationen übergeben!"
+
+#~ msgid "No file!?!"
+#~ msgstr "Keine Datei!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "Kein Änderungsdatum!"
+
+#~ msgid "No printer name!"
+#~ msgstr "Kein Druckername!"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "Keine Drucker-URI gefunden für Klasse!"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "Keine Drucker-URI gefunden!"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "Keine Drucker-URI abgerufen!"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "Keine Subskriptionsattribute abgerufen!"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "Die Bildtrommel (OPC) muss bald ausgetauscht werden."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "Die Bildtrommel (OPC) muss ausgetauscht werden!"
+
+#~ msgid "Out of toner!"
+#~ msgstr "Der Toner ist leer!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Das Ausgabefach ist fast voll."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Das Ausgabefach ist voll!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Das Ausgabefach fehlt!"
+
+#~ msgid "Printer offline."
+#~ msgstr "Der Drucker ist offline."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "SCSI-Drucker"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "Der Wert für „notify-user-data“ ist zu groß (%d > 63 Oktetts)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "Der Drucker oder die Klasse sind nicht freigegeben!"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "Das Drucker-URI-Attribut wird benötigt!"
+
+#~ msgid "Toner low."
+#~ msgstr "Wenig Toner."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "Zu viele job-sheets-Werte (%d > 2)!"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "Zu viele printer-state-reasons-Werte (%d > %d)!"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "Druckauftrag für das Ziel „%s“ konnte nicht hinzugefügt werden!"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "Der Speicher für die Dateitypen konnte nicht zugeordnet werden."
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "64-Bit CUPS-Druckertreiberdateien konnten nicht kopiert werden (%d)!"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr ""
+#~ "64-Bit Windows-Druckertreiberdateien konnten nicht kopiert werden (%d)!"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr "CUPS-Druckertreiberdateien konnten nicht kopiert werden (%d)!"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "PPD-Datei konnte nicht kopiert werden – %s!"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "PPD-Datei konnte nicht kopiert werden!"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Windows 2000 Druckertreiberdateien konnten nicht kopiert werden (%d)!"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr "Windows 9x Druckertreiberdateien konnten nicht kopiert werden (%d)!"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "Schnittstellenskript konnte nicht kopiert werden – %s!"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "Drucker-URI konnte nicht erstellt werden!"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr ""
+#~ "„cupsd.conf“-Dateien größer als 1 MB können nicht bearbeitet werden!"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "Ziel für den Druckauftrag konnte nicht gefunden werden!"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "Drucker konnte nicht gefunden werden!\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Windows 2000 Druckertreiberdateien konnten nicht installiert werden (%d)!"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "Windows 9x Druckertreiberdateien konnten nicht installiert werden (%d)!"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr ""
+#~ "Das Dokument „%d“ in Druckauftrag „%d“ konnte nicht geöffnet werden!"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "Befehl konnte nicht an den Druckertreiber gesendet werden!"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Windows-Druckertreiber konnte nicht festgelegt werden (%d)!"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "Alte USB-Klasse-Treiber konnten nicht verwendet werden!\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "Unbekannter Druckerfehler (%s)!"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Zeichensatz „%s“ nicht unterstützt!"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "Komprimierung „%s“ nicht unterstützt!"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "Komprimierungsattribut „%s“ nicht unterstützt!"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "Format „%s“ nicht unterstützt!"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "Format „%s“ nicht unterstützt!"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "Format „%s/%s“ nicht unterstützt!"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: Lesen der Side-Channel-Anfrage fehlgeschlagen!\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr ""
+#~ "WARNING: Option „%s“ kann nicht mithilfe von „IncludeFeature“ "
+#~ "eingeschlossen werden!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Entfernter Host hat nicht mit dem Befehlstatusbyte geantwortet "
+#~ "nach %d Sekunden!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Entfernter Host hat nicht mit dem Steuerungsstatusbyte "
+#~ "geantwortet nach %d Sekunden!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Entfernter Host hat nicht mit dem Datenstatusbyte geantwortet "
+#~ "nach %d Sekunden!\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr ""
+#~ "WARNING: Zeitüberschreitung bei SCSI-Befehl (%d); erneut versuchen …\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: Dieses Dokument entspricht nicht den Dokumentstruktur-"
+#~ "Konventionen von Adobe und wird u. U. nicht korrekt gedruckt!\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: Unbekannte Auswahl „%s“ für Option „%s“!\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: Unbekannte Option „%s“!\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: Baud-Rate „%s“ wird nicht unterstützt!\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: wiederherstellbar: Netzwerkhost „%s“ ist ausgelastet; erneuter "
+#~ "Versuch in %d Sekunden …\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr "Achtung: Es sind keine Windows 2000 Druckertreiber installiert!"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: unbekannte Option „%s“!\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: unbekannte Option „-%c“!\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr "cupsd: „config filename“ erwartet nach '-c'-Option!\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: Aktueller Ordner konnte nicht gefunden werden!\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: unbekanntes Argument „%s“ – abbrechen!\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: unbekannte Option „%c“ – abbrechen!\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: ungültige Dokumentnummer %d!\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: ungültige Druckauftrags-ID %d!\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: Nur ein Dateiname kann angegeben werden!\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter: Temporäre Datei konnte nicht erstellt werden: %s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "job-printer-URI-Attribut fehlt!"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Klassenname kann nur druckbare Zeichen enthalten!\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: PPD erwartet nach '-P'-Option!\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr "lpadmin: „allow/deny:userlist“ erwartet nach '-u'-Option!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: Klasse erwartet nach '-r'-Option!\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: Klassenname erwartet nach '-c'-Option!\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: Beschreibung erwartet nach '-D'-Option!\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: Geräte-URI erwartet nach '-v'-Option!\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: Dateityp(en) erwartet nach '-I'-Option!\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: Hostname erwartet nach '-h'-Option!\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: Schnittstelle erwartet nach '-i'-Option!\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: Standort erwartet nach '-L'-Option!\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: Modell erwartet nach '-m'-Option!\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: name=value erwartet nach '-o'-Option!\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: Drucker erwartet nach '-p'-Option!\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: Druckername erwartet nach '-d'-Option!\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin: Drucker oder Klasse erwartet nach '-x'-Option!\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: Keine zugehörigen Namen gefunden!\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Druckername kann nur druckbare Zeichen enthalten!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Drucker konnte nicht zu der Klasse hinzugefügt werden:\n"
+#~ " Legen Sie zuerst einen Druckernamen fest!\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin: Temporäre Datei konnte nicht erstellt werden – %s\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin: Temporäre Datei konnte nicht erstellt werden: %s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Drucker konnte nicht aus der Klasse entfernt werden:\n"
+#~ " Legen Sie zuerst einen Druckernamen fest!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Die PPD-Datei konnte nicht festgelegt werden:\n"
+#~ " Legen Sie zuerst einen Druckernamen fest!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Die Geräte-URI konnte nicht festgelegt werden:\n"
+#~ " Legen Sie zuerst einen Druckernamen fest!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Das Schnittstellenskript oder die PPD-Datei konnten nicht "
+#~ "festgelegt werden:\n"
+#~ " Legen Sie zuerst einen Druckernamen fest!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Das Schnittstellenskript konnte nicht festgelegt werden:\n"
+#~ " Legen Sie zuerst einen Druckernamen fest!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Die Druckerbeschreibung konnte nicht festgelegt werden:\n"
+#~ " Legen Sie zuerst einen Druckernamen fest!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Der Druckerstandort konnte nicht festgelegt werden:\n"
+#~ " Legen Sie zuerst einen Druckernamen fest!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Die Druckeroptionen konnten nicht festgelegt werden:\n"
+#~ " Legen Sie zuerst einen Druckernamen fest!\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: unbekannte allow/deny-Option „%s“!\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: unbekanntes Argument „%s“!\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: unbekannte Option '%c'!\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin: Achtung – Inhaltstypliste ignoriert!\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr "lpinfo: 1284 Geräte-ID String erwartet nach „--device-id“!\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: Sprache erwartet nach „--language“!\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo: Hersteller und Modell erwartet nach „--make-and-model“!\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo: Produktstring erwartet nach „--product“!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo: Schemaliste erwartet nach „--exclude-schemes“!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo: Schemaliste erwartet nach „--include-schemes“!\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: Zeitüberschreitung erwartet nach „--timeout“!\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: unbekanntes Argument „%s“!\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: unbekannte Option '%c'!\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: unbekannte Option '%s'!\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: unbekanntes Argument „%s“!\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: unbekannte Option '%c'!\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: Keine Drucker!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: PPD-Datei für „%s“ konnte nicht geöffnet werden!\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: Drucker oder Klasse unbekannt!\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: Nur „root“ kann Kennwörter hinzufügen und löschen!\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: Kennwortdatei wird gerade verwendet!\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: Kennwortdatei ist nicht aktualisiert!\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: Kennwörter stimmen nicht überein!\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: Kennwörter stimmen nicht überein!\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: Fehler – %s Umgebungsvariablennamen nicht vorhanden für Ziel „%"
+#~ "s“!\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "„notify-events“ nicht festgelegt!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "notify-recipient-uri URI „%s“ wird bereits verwendet!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "notify-recipient-uri URI „%s“ verwendet unbekanntes Schema!"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id „%d“ ist ungültig!"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ungültiger aufzulösender Name „%s“ in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: Ungültiges Status-Keyword „%s“ in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc: Auswahl in Zeile %d von %s gefunden ohne Option!\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc: Duplikat #po für Locale „%s“ in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: Filterdefinition erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: Programmname erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Zeichensatz nach Schrift erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Farbreihenfolge für ColorModel erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Farbraum für ColorModel erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Komprimierung für ColorModel erwartet in Zeile %d von %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Constraints String für UIConstraints erwartet in Zeile %d von %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Treibertyp-Keyword nach DriverType erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr "ppdc: Duplextyp nach Duplex erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Codierung nach Schrift erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc: Dateiname nach #po %s erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Gruppenname/-text erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc: „include filename“ erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: „integer“ erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc: Locale nach #po erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Name nach „%s“ erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: Name nach FileName erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Name nach Font erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc: Name nach Manufacturer erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: Name nach MediaSize erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: Name nach ModelName erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: Name nach PCFileName erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Name/Text nach „%s“ erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr "ppdc: Name/Text nach Installable erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: Name/Text nach Resolution erwartet in Zeile %d von %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Kombination aus Name/Text für ColorModel erwartet in Zeile %d von %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Optionsname/-text erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: „option section“ erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: „option type“ erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: „override field“ nach Resolution erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: „real number“ erwartet in Zeile %d von %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: „resolution/mediatype“ nach ColorProfile erwartet in Zeile %d von %"
+#~ "s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: „resolution/mediatype“ nach SimpleColorProfile erwartet in Zeile %d "
+#~ "von %s!\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: „selector“ nach „%s“ erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Status nach Font erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc: „string“ nach Copyright erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc: „string“ nach Version erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: Zwei Optionsnamen erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: „value“ nach „%s“ erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Version nach Font erwartet in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: ungültiger #include/#po Dateiname „%s“!\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Ungültiges „cost“ für Filter in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Ungültiger leerer MIME-Typ für Filter in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Ungültiger leerer Programmname für Filter in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ungültiger Optionsabschnitt „%s“ in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ungültiger Optionstyp „%s“ in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: #endif fehlt am Ende von „%s“!\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: #if fehlt in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc: Kein Message-Catalog verfügbar für Locale „%s“!\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Option „%s“ neu definiert durch anderen Typ in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr "ppdc: Option „constraint must *name“ in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: Zu viele verschachtelte #if in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: #po-Datei „%s“ wurde nicht gefunden in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: include-Datei „%s“ wurde nicht gefunden in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: Unbekannter Treibertyp „%s“ in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Unbekannter Duplextyp „%s“ in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Unbekannte Mediengröße „%s“ in Zeile %d von %s!\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: Unbekannter Token „%s“ gefunden in Zeile %d von %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Unbekannte nachfolgende Zeichen in Real Number „%s“ in Zeile %d von "
+#~ "%s!\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr "ppdc: Unvollständiger String beginnend mit %c in Zeile %d von %s!\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: Ungültige LanguageVersion „%s“ in %s!\n"
diff --git a/locale/cups_es.po b/locale/cups_es.po
new file mode 100644
index 000000000..f31505796
--- /dev/null
+++ b/locale/cups_es.po
@@ -0,0 +1,7215 @@
+#
+# "$Id$"
+#
+# Spanish message catalog for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 2005-2007 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-07-02 20:00+0100\n"
+"Last-Translator: Juan Pablo González Riopedre <riopedre13@yahoo.es>\n"
+"Language-Team: Spanish\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(todos)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(ninguno)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d entradas\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tTras fallo: continuar\n"
+
+msgid "\tAlerts:"
+msgstr "\tAlertas:"
+
+msgid "\tBanner required\n"
+msgstr "\tSe necesita un rótulo\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tAjustes del juego de caracteres:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tConexión: directa\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tConexión: remota\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tTamaño de página predeterminado:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tPaso predeterminado:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tAjustes del puerto predeterminados:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tDescripción: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tFormulario montado:\n"
+"\tTipos de contenido: cualquiera\n"
+"\tTipos de impresora: desconocido\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tFormularios permitidos:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tInterfaz: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tInterfaz: %s/interfaces/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tInterfaz: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tUbicación: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tEn fallo: no alertar\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tUsuarios permitidos:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tUsuarios denegados:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tdemonio presente\n"
+
+msgid "\tno entries\n"
+msgstr "\tno hay entradas\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\tla impresora está conectada a '%s' velocidad -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\tla impresión está desactivada\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\tla impresión está activada\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\ten cola para %s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tla cola está desactivada\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tla cola está activada\n"
+
+msgid "\treason unknown\n"
+msgstr "\trazón desconocida\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" RESULTADOS DETALLADOS DE LA PRUEBA DE CONFORMIDAD\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " REF: Página 15, sección 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " REF: Página 15, sección 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " REF: Página 19, sección 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " REF: Página 20, sección 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " REF: Página 27, sección 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " REF: Página 42, sección 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " REF: Páginas 16-17, sección 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " REF: Páginas 42-45, sección 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " REF: Páginas 45-46, sección 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " REF: Páginas 48-49, sección 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " REF: Páginas 52-54, sección 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f bytes\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " PASA %s predeterminado\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " PASA DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " PASA DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " PASA FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " PASA FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " PASA LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " PASA LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " PASA Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " PASA ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " PASA NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " PASA PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " PASA PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " PASA PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " PASA PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " PASA Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " PASA ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" ADVERTENCIA \"%s %s\" está en conflicto con \"%s %s\"\n"
+" (restricción=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" ADVERTENCIA %s comparte un prefijo común con %s\n"
+" REF: Página 15, sección 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" ADVERTENCIA Se necesita LanguageEncoding por especificación de "
+"PPD 4.3.\n"
+" REF: Páginas 56-57, sección 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" ADVERTENCIA Se necesita Manufacturer por especificación de PPD "
+"4.3.\n"
+" REF: Páginas 58-59, sección 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" ADVERTENCIA PCFileName es mas largo que 8.3 violando la "
+"especificación PPD.\n"
+" REF: Páginas 61-62, sección 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" ADVERTENCIA Los protocolos contienen PJL pero no se especifican "
+"los atributos JCL.\n"
+" REF: Páginas 78-79, sección 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" ADVERTENCIA Los protocolos contienen a ambos, PJL y BCP; se "
+"esperaba TBCP.\n"
+" REF: Páginas 78-79, sección 5.7.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" ADVERTENCIA Se necesita ShortNickName por especificación de PPD "
+"4.3.\n"
+" REF: Páginas 64-65, sección 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr " %s Falta el archivo APDialogExtension \"%s\"\n"
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr " %s Falta el archivo APPrinterIconPath \"%s\"\n"
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr " %s Falta el archivo APPrinterLowInkTool \"%s\"\n"
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr " %s Falta el archivo APPrinterUtilityPath \"%s\"\n"
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr " %s Falta el archivo APScanAppPath \"%s\"\n"
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s Falta archivo cupsFilter \"%s\"\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s Falta archivo cupsPreFilter \"%s\"\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FALLO** Default%s %s INCORRECTO\n"
+" REF: Página 40, sección 4.5.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **FALLO** Atributo JobPatchFile en archivo, INCORRECTO\n"
+" REF: Página 24, sección 3.4.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FALLO** Fabricante INCORRECTO (debería ser \"HP\")\n"
+" REF: Página 211, tabla D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FALLO** Fabricante INCORRECTO (debería ser \"Oki\")\n"
+" REF: Página 211, tabla D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FALLO** ModelName - \"%c\" INCORRECTO no permitido en la cadena.\n"
+" REF: Páginas 59-60, sección 5.3.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FALLO** PSVersion INCORRECTO - no es \"(string) int\".\n"
+" REF: Páginas 62-64, sección 5.3.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FALLO** Product INCORRECTO - no es \"(string)\".\n"
+" REF: Página 62, sección 5.3.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **FALLO** ShortNickName INCORRECTO - mayor de 31 caracteres.\n"
+" REF: Páginas 64-65, sección 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FALLO** FileVersion \"%s\" incorrecto\n"
+" REF: Página 56, sección 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FALLO** FormatVersion \"%s\" incorrecto\n"
+" REF: Página 56, sección 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr ""
+" **FALLO** El código de opción predeterminado no puede ser "
+"interpretado: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FALLO** SE NECESITA Default%s\n"
+" REF: Página 40, sección 4.5.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FALLO** SE NECESITA DefaultImageableArea\n"
+" REF: Página 102, sección 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FALLO** SE NECESITA DefaultPaperDimension\n"
+" REF: Página 103, sección 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FALLO** SE NECESITA FileVersion\n"
+" REF: Página 56, sección 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FALLO** SE NECESITA FormatVersion\n"
+" REF: Página 56, sección 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FALLO** SE NECESITA ImageableArea para PageSize %s\n"
+" REF: Página 41, sección 5.\n"
+" REF: Página 102, sección 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **FALLO** SE NECESITA LanguageEncoding\n"
+" REF: Páginas 56-57, sección 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **FALLO** SE NECESITA LanguageVersion\n"
+" REF: Páginas 57-58, sección 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **FALLO** SE NECESITA Manufacturer\n"
+" REF: Páginas 58-59, sección 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FALLO** SE NECESITA ModelName\n"
+" REF: Páginas 59-60, sección 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **FALLO** SE NECESITA NickName\n"
+" REF: Página 60, sección 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **FALLO** SE NECESITA PCFileName\n"
+" REF: Páginas 61-62, sección 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FALLO** SE NECESITA PSVersion\n"
+" REF: Páginas 62-64, sección 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **FALLO** SE NECESITA PageRegion\n"
+" REF: Página 100, sección 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **FALLO** SE NECESITA PageSize\n"
+" REF: Página 41, sección 5.\n"
+" REF: Página 99, sección 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **FALLO** SE NECESITA PageSize\n"
+" REF: Páginas 99-100, sección 5.14.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FALLO** SE NECESITA PaperDimension para PageSize %s\n"
+" REF: Página 41, sección 5.\n"
+" REF: Página 103, sección 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FALLO** SE NECESITA Product\n"
+" REF: Página 62, sección 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **FALLO** SE NECESITA ShortNickName\n"
+" REF: Página 64-65, sección 5.3.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " %d ERRORES ENCONTRADOS\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " NO SE HAN ENCONTRADO ERRORES\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " FALLO\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" FALLO\n"
+" **FALLO** No se ha podido abrir el archivo PPD - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" FALLO\n"
+" **FALLO** No se ha podido abrir el archivo PPD - %s en la línea %d.\n"
+
+msgid " PASS\n"
+msgstr " PASA\n"
+
+msgid "#10 Envelope"
+msgstr "Sobre nº 10"
+
+msgid "#11 Envelope"
+msgstr "Sobre nº 11"
+
+msgid "#12 Envelope"
+msgstr "Sobre nº 12"
+
+msgid "#14 Envelope"
+msgstr "Sobre nº 14"
+
+msgid "#9 Envelope"
+msgstr "Sobre nº 9"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f milímetros"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f a %.0f x %.0f milímetros"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f pulgadas"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f a %.2f x %.2f pulgadas"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s aceptando peticiones desde %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%s no puede ser cambiado."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s no está implementado en la versión de CUPS de lpc.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s no está preparada\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s está preparada\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s está preparada e imprimiendo\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s no acepta peticiones desde %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s aceptando peticiones desde %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s no acepta peticiones desde %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [trabajo %d localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s ha fallado: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: Error - destino predeterminado no disponible.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: Error - la prioridad debe estar entre 1 y 100.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: Error - demasiados archivos - \"%s\"\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: Error - no se ha podido acceder a \"%s\" - %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s: Error - no se ha podido poner en cola desde stdin - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: Filtro \"%s\" no disponible: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: Cadena de filtro \"%s\" inválida\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: La operación ha fallado: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: No se ha podido conectar al servidor\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: No se pudo abrir %s: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: No se pudo abrir archivo PPD: %s en línea %d\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr "%s: No se ha podido abrir el archivo PPD: %s en la línea %d.\n"
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: error - destino predeterminado no disponible.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 pulg./seg"
+
+msgid "1.25x0.25\""
+msgstr "1.25x0.25 pulg."
+
+msgid "1.25x2.25\""
+msgstr "1.25x2.25 pulg."
+
+msgid "1.5 inch/sec."
+msgstr "1.5 pulg./seg"
+
+msgid "1.50x0.25\""
+msgstr "1.50x0.25 pulg."
+
+msgid "1.50x0.50\""
+msgstr "1.50x0.50 pulg."
+
+msgid "1.50x1.00\""
+msgstr "1.50x1.00 pulg."
+
+msgid "1.50x2.00\""
+msgstr "1.50x2.00 pulg."
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 pulg./seg"
+
+msgid "10 x 11\""
+msgstr "10 x 11 pulg."
+
+msgid "10 x 13\""
+msgstr "10 x 13 pulg."
+
+msgid "10 x 14\""
+msgstr "10 x 14 pulg."
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 mm/seg"
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 pulg./seg"
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 pulg./seg"
+
+msgid "12 x 11\""
+msgstr "12 x 11 pulg."
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 mm/seg"
+
+msgid "120x60dpi"
+msgstr "120x60ppp"
+
+msgid "120x72dpi"
+msgstr "120x72ppp"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136ppp"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 mm/seg"
+
+msgid "15 x 11\""
+msgstr "15 x 11 pulg."
+
+msgid "150 mm/sec."
+msgstr "150 mm/seg"
+
+msgid "150dpi"
+msgstr "150ppp"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180ppp"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 pulg./seg"
+
+msgid "2-Sided Printing"
+msgstr "Dúplex"
+
+msgid "2.00x0.37\""
+msgstr "2.00x0.37 pulg."
+
+msgid "2.00x0.50\""
+msgstr "2.00x0.50 pulg."
+
+msgid "2.00x1.00\""
+msgstr "2.00x1.00 pulg."
+
+msgid "2.00x1.25\""
+msgstr "2.00x1.25 pulg."
+
+msgid "2.00x2.00\""
+msgstr "2.00x2.00 pulg."
+
+msgid "2.00x3.00\""
+msgstr "2.00x3.00 pulg."
+
+msgid "2.00x4.00\""
+msgstr "2.00x4.00 pulg."
+
+msgid "2.00x5.50\""
+msgstr "2.00x5.50 pulg."
+
+msgid "2.25x0.50\""
+msgstr "2.25x0.50 pulg."
+
+msgid "2.25x1.25\""
+msgstr "2.25x1.25 pulg."
+
+msgid "2.25x4.00\""
+msgstr "2.25x4.00 pulg."
+
+msgid "2.25x5.50\""
+msgstr "2.25x5.50 pulg."
+
+msgid "2.38x5.50\""
+msgstr "2.38x5.50 pulg."
+
+msgid "2.5 inches/sec."
+msgstr "2.5 pulg./seg"
+
+msgid "2.50x1.00\""
+msgstr "2.50x1.00 pulg."
+
+msgid "2.50x2.00\""
+msgstr "2.50x2.00 pulg."
+
+msgid "2.75x1.25\""
+msgstr "2.75x1.25 pulg."
+
+msgid "2.9 x 1\""
+msgstr "2.9 x 1 pulg."
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 mm/seg"
+
+msgid "200 mm/sec."
+msgstr "200 mm/seg"
+
+msgid "203dpi"
+msgstr "203ppp"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "24-Pin Series"
+
+msgid "240x72dpi"
+msgstr "240x72ppp"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 mm/seg"
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 pulg./seg"
+
+msgid "3.00x1.00\""
+msgstr "3.00x1.00 pulg."
+
+msgid "3.00x1.25\""
+msgstr "3.00x1.25 pulg."
+
+msgid "3.00x2.00\""
+msgstr "3.00x2.00 pulg."
+
+msgid "3.00x3.00\""
+msgstr "3.00x3.00 pulg."
+
+msgid "3.00x5.00\""
+msgstr "3.00x5.00 pulg."
+
+msgid "3.25x2.00\""
+msgstr "3.25x2.00 pulg."
+
+msgid "3.25x5.00\""
+msgstr "3.25x5.00 pulg."
+
+msgid "3.25x5.50\""
+msgstr "3.25x5.50 pulg."
+
+msgid "3.25x5.83\""
+msgstr "3.25x5.83 pulg."
+
+msgid "3.25x7.83\""
+msgstr "3.25x7.83 pulg."
+
+msgid "3.5\" Disk"
+msgstr "Disco de 3.5 pulg."
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "Disco de 3.5 pulg. - 2 1/8 x 2 3/4 pulg."
+
+msgid "3.50x1.00\""
+msgstr "3.50x1.00 pulg."
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 mm/seg"
+
+msgid "300 mm/sec."
+msgstr "300 mm/seg"
+
+msgid "300dpi"
+msgstr "300ppp"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360ppp"
+
+msgid "360x180dpi"
+msgstr "360x180ppp"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 pulg./seg"
+
+msgid "4.00x1.00\""
+msgstr "4.00x1.00 pulg."
+
+msgid "4.00x13.00\""
+msgstr "4.00x13.00 pulg."
+
+msgid "4.00x2.00\""
+msgstr "4.00x2.00 pulg."
+
+msgid "4.00x2.50\""
+msgstr "4.00x2.50 pulg."
+
+msgid "4.00x3.00\""
+msgstr "4.00x3.00 pulg."
+
+msgid "4.00x4.00\""
+msgstr "4.00x4.00 pulg."
+
+msgid "4.00x5.00\""
+msgstr "4.00x5.00 pulg."
+
+msgid "4.00x6.00\""
+msgstr "4.00x6.00 pulg."
+
+msgid "4.00x6.50\""
+msgstr "4.00x6.50 pulg."
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 mm/seg"
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 pulg./seg"
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 pulg./seg"
+
+msgid "6.00x1.00\""
+msgstr "6.00x1.00 pulg."
+
+msgid "6.00x2.00\""
+msgstr "6.00x2.00 pulg."
+
+msgid "6.00x3.00\""
+msgstr "6.00x3.00 pulg."
+
+msgid "6.00x4.00\""
+msgstr "6.00x4.00 pulg."
+
+msgid "6.00x5.00\""
+msgstr "6.00x5.00 pulg."
+
+msgid "6.00x6.00\""
+msgstr "6.00x6.00 pulg."
+
+msgid "6.00x6.50\""
+msgstr "6.00x6.50 pulg."
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/seg"
+
+msgid "600dpi"
+msgstr "600ppp"
+
+msgid "60dpi"
+msgstr "60ppp"
+
+msgid "60x720dpi"
+msgstr "60x720ppp"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 pulg./seg"
+
+msgid "7 x 9\""
+msgstr "7 x 9 pulg."
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720ppp"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 pulg./seg"
+
+msgid "8 x 10\""
+msgstr "8 x 10 pulg."
+
+msgid "8.00x1.00\""
+msgstr "8.00x1.00 pulg."
+
+msgid "8.00x2.00\""
+msgstr "8.00x2.00 pulg."
+
+msgid "8.00x3.00\""
+msgstr "8.00x3.00 pulg."
+
+msgid "8.00x4.00\""
+msgstr "8.00x4.00 pulg."
+
+msgid "8.00x5.00\""
+msgstr "8.00x5.00 pulg."
+
+msgid "8.00x6.00\""
+msgstr "8.00x6.00 pulg."
+
+msgid "8.00x6.50\""
+msgstr "8.00x6.50 pulg."
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/seg"
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 pulg./seg"
+
+msgid "9 x 11\""
+msgstr "9 x 11 pulg."
+
+msgid "9 x 12\""
+msgstr "9 x 12 pulg."
+
+msgid "9-Pin Series"
+msgstr "9-Pin Series"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?Comando de ayuda inválido desconocido\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (extragrande)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (extragrande)"
+
+msgid "A4 (Small)"
+msgstr "A4 (pequeño)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (extragrande)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "Aceptar trabajos"
+
+msgid "Accepted"
+msgstr "Aceptado"
+
+msgid "Add Class"
+msgstr "Añadir clase"
+
+msgid "Add Printer"
+msgstr "Añadir impresora"
+
+msgid "Add RSS Subscription"
+msgstr "Añadir subscripción RSS"
+
+msgid "Address"
+msgstr "Dirección"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "Dirección - 1 1/8 x 3 1/2 pulg."
+
+msgid "Administration"
+msgstr "Administración"
+
+msgid "Always"
+msgstr "Siempre"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "Aplicador"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "Puntero destino NULLincorrecto"
+
+msgid "Bad OpenGroup"
+msgstr "OpenGroup incorrecto"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "OpenUI/JCLOpenUI incorrecto"
+
+msgid "Bad OrderDependency"
+msgstr "OrderDependency incorrecto"
+
+msgid "Bad Request"
+msgstr "Petición incorrecta"
+
+msgid "Bad SNMP version number"
+msgstr "Número de versión SNMP incorrecto"
+
+msgid "Bad UIConstraints"
+msgstr "UIConstraints incorrecto"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Valor de copias %d incorrecto."
+
+msgid "Bad custom parameter"
+msgstr "Parámetro a medida incorrecto"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Atributo de fuente: %s incorrecto\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Valor number-up (páginas por hoja) %d incorrecto."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Valores de page-ranges %d-%d incorrectos."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Rótulos"
+
+msgid "Billing Information: "
+msgstr "Información de facturación: "
+
+msgid "Bond Paper"
+msgstr "Papel de cartas"
+
+msgid "C0 Envelope"
+msgstr "Sobre C0"
+
+msgid "C1 Envelope"
+msgstr "Sobre C1"
+
+msgid "C2 Envelope"
+msgstr "Sobre C2"
+
+msgid "C3 Envelope"
+msgstr "Sobre C3"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "Sobre C4"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "Sobre C5"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "Sobre C6"
+
+msgid "C65 Envelope"
+msgstr "Sobre C65"
+
+msgid "C7 Envelope"
+msgstr "Sobre C7"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "Impresora de etiquetas CPCL"
+
+msgid "Cancel RSS Subscription"
+msgstr "Cancelar subscripción RSS"
+
+msgid "Change Settings"
+msgstr "Cambiar configuración"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Sobre Chou3"
+
+msgid "Chou4 Envelope"
+msgstr "Sobre Chou4"
+
+msgid "Classes"
+msgstr "Clases"
+
+msgid "Clean Print Heads"
+msgstr "Limpiar cabezales de impresión"
+
+msgid "Color"
+msgstr "Color"
+
+msgid "Color Mode"
+msgstr "Modo de color"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"Los comandos se pueden abreviar. Los comandos son:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "Nombre de comunidad usa una longitud indefinida"
+
+msgid "Continue"
+msgstr "Continuar"
+
+msgid "Continuous"
+msgstr "Continuo"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Creado"
+
+msgid "Created On: "
+msgstr "Creado en: "
+
+msgid "Custom"
+msgstr "A medida"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Cortar"
+
+msgid "Cutter"
+msgstr "Cortadora"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "Sobre DL"
+
+msgid "Dark"
+msgstr "Oscuro"
+
+msgid "Darkness"
+msgstr "Oscuridad"
+
+msgid "Delete Class"
+msgstr "Borrar clase"
+
+msgid "Delete Printer"
+msgstr "Borrar impresora"
+
+msgid "Description: "
+msgstr "Descripción: "
+
+msgid "DeskJet Series"
+msgstr "DeskJet Series"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "El destino %s no acepta trabajos."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"Dispositivo: uri = %s\n"
+" clase = %s\n"
+" info = %s\n"
+" marca y modelo = %s\n"
+" id dispositivo= %s\n"
+" ubicación = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "Soporte térmico directo"
+
+msgid "Disabled"
+msgstr "Deshabilitado"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "No se encuentra el documento %d en el trabajo %d."
+
+msgid "Double Postcard"
+msgstr "Postal doble"
+
+msgid "Driver Name: "
+msgstr "Nombre del controlador: "
+
+msgid "Driver Version: "
+msgstr "Versión del controlador: "
+
+msgid "Duplexer"
+msgstr "Unidad de impresión dúplex"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr ""
+"EMERG: No se ha podido asignar memoria para la información de página: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr ""
+"EMERG: No se ha podido asignar memoria para la secuencia de páginas: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "Impresora de etiquetas EPL1"
+
+msgid "EPL2 Label Printer"
+msgstr "Impresora de etiquetas EPL2"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr "ERROR: %s job-id usuario título copias opciones [archivo]\n"
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: Archivo de juego de caracteres incorrecto %s\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: Tipo de juego de caracteres incorrecto %s\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: Línea de descripción tipográfica incorrecta: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: Dirección de texto incorrecta %s\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: Anchura de texto incorrecta %s\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: Error %d enviando petición PAPSendData: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: No hay fuentes en el archivo de juego de caracteres %s\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: La impresora no responde\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: La impresora envió un inesperado EOF\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: El ordenador remoto no ha aceptado el archivo de control (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: El ordenador remoto no ha aceptado el archivo de datos (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr ""
+"ERROR: Hay un error de tiempo de espera mientras se enviaban datos a la "
+"impresora\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: No se ha podido añadir el archivo %d al trabajo: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: No se ha podido cancelar el trabajo %d: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: No se ha podido copiar el archivo PDF"
+
+msgid "ERROR: Unable to create pipe"
+msgstr "ERROR: No se ha podido crear el canal (pipe)"
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: No se ha podido crear socket"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: No se ha podido crear el archivo de impresión temporal comprimido: %"
+"s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: No se ha podido crear el archivo temporal"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: No se ha podido ejecutar pictwpstops: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: No se ha podido ejecutar el programa gs"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: No se ha podido ejecutar el programa pdftops"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr "ERROR: No se ha podido ejecutar el programa pstops"
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: No se ha podido bifurcar (fork) pictwpstops: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: No se ha podido obtener una petición PAP"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: No se ha podido obtener una respuesta PAP"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr ""
+"ERROR: No se ha podido obtener el archivo PPD para la impresora \"%s\" - %"
+"s.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: No se ha podido conseguir la zona AppleTalk predeterminada"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: No se ha podido buscar una respuesta PAP"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: No se han podido mirar las impresoras AppleTalk"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: No se ha podido crear la dirección AppleTalk"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: No se ha podido abrir \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: No se ha podido abrir %s: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: No se ha podido abrir el archivo de rótulo \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: No se ha podido abrir el archivo de dispositivo \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: No se ha podido abrir el archivo \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: No se ha podido abrir el archivo \"%s\": %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: No se ha podido abrir el archivo de impresión \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: No se ha podido abrir el archivo de impresión %s - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: No se ha podido abrir el archivo de impresión %s: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr "ERROR: No se ha podido abrir el archivo de trama de datos - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: No se ha podido abrir el archivo de impresión temporal comprimido: %"
+"s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: No se han podido leer los datos de impresión"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: No se ha podido reservar puerto"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: No se ha podido alcanzar la posición %ld en el archivo - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: No se ha podido alcanzar la posición %lld en el archivo - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: No se ha podido enviar comando LPD"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: No se ha podido enviar una petición PAP"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr ""
+"ERROR: No se ha podido enviar la petición inicial de datos de envío PAP"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: No se ha podido imprimir el archivo en la impresora"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: No se ha podido enviar carácter nulo del final a la impresora"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: No se puede esperar por pictwpstops: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: No se han podido escribir %d bytes a \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: No se ha podido escribir el archivo de control"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: No se han podido escribir los datos de impresión"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: No se han podido escribir los datos de impresión: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr ""
+"ERROR: No se han podido escribir los datos de documento sin comprimir: %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: Orden de archivos \"%s\" desconocido\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: Carácter de formato \"%c\" desconocido\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: Modo de impresión \"%s\" desconocido\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: select() ha fallado"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: no se ha podido ejecutar 'stat' sobre el archivo de impresión"
+
+msgid "Edit Configuration File"
+msgstr "Editar archivo de configuración"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Rótulo final"
+
+msgid "English"
+msgstr "Spanish"
+
+msgid "Enter old password:"
+msgstr "Introduzca la contraseña antigua:"
+
+msgid "Enter password again:"
+msgstr "Introduzca nuevamente la contraseña:"
+
+msgid "Enter password:"
+msgstr "Introduzca la contraseña:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Introduzca su nombre de usuario y contraseña o el nombre de usuario y "
+"contraseña de root para poder acceder a esta página. Si está usando "
+"autentificación Kerberos, asegúrese de que tiene un ticket Kerberos válido."
+
+msgid "Envelope Feed"
+msgstr "Alimentador de sobre"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Directiva de error"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "Cada 10 etiquetas"
+
+msgid "Every 2 Labels"
+msgstr "Cada 2 etiquetas"
+
+msgid "Every 3 Labels"
+msgstr "Cada 3 etiquetas"
+
+msgid "Every 4 Labels"
+msgstr "Cada 4 etiquetas"
+
+msgid "Every 5 Labels"
+msgstr "Cada 5 etiquetas"
+
+msgid "Every 6 Labels"
+msgstr "Cada 6 etiquetas"
+
+msgid "Every 7 Labels"
+msgstr "Cada 7 etiquetas"
+
+msgid "Every 8 Labels"
+msgstr "Cada 8 etiquetas"
+
+msgid "Every 9 Labels"
+msgstr "Cada 9 etiquetas"
+
+msgid "Every Label"
+msgstr "Cada etiqueta"
+
+msgid "Expectation Failed"
+msgstr "Lo que se esperaba, falló."
+
+msgid "Export Printers to Samba"
+msgstr "Exportar impresoras a Samba"
+
+msgid "FAIL\n"
+msgstr "FALLO\n"
+
+msgid "File Folder"
+msgstr "Carpeta de archivos"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Carpeta de archivosr - 9/16 x 3 7/16 pulg."
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"Los URIs del dispositivo de archivo han sido deshabilitados. Para "
+"habilitarlos, vea la directiva FileDevice en \"%s/cupsd.conf\"."
+
+msgid "Folio"
+msgstr "Folio"
+
+msgid "Forbidden"
+msgstr "Prohibido"
+
+msgid "General"
+msgstr "General"
+
+msgid "Generic"
+msgstr "Genérico"
+
+msgid "German FanFold"
+msgstr "FanFold alemán"
+
+msgid "German FanFold Legal"
+msgstr "FanFold Legal alemán"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU usa una longitud indefinida"
+
+msgid "Glossy Paper"
+msgstr "Papel satinado"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Escale de grises"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Carpeta colgante"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Carpeta colgante - 9/16 x 2 pulg."
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk desactivado en Preferencias del sistema\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk desactivado en Preferencias del sistema.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: Cancelando trabajo de impresión...\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: Conectado a la impresora...\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: Conectando a la impresora...\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: Archivo de control enviado correctamente\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr "INFO: Copiando datos de impresión...\n"
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: Archivo de datos enviado correctamente\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr "INFO: Acabada la página %d...\n"
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: Formateando página %d...\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: Cargando archivo de imagen...\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: Buscando impresora...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: Abriendo la conexión\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr ""
+"INFO: Archivo de impresión enviado; esperando a que finalice la "
+"impresora...\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: Impresora ocupada; reintento en 10 segundos...\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: Impresora ocupada; reintento en 30 segundos...\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: Impresora ocupada; reintento en 5 segundos...\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr ""
+"INFO: La impresora no es compatible con IPP/%d.%d, probando IPP/1.0...\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: La impresora está ocupada; reintento en 5 segundos...\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: La impresora está actualmente fuera de línea.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: La impresora está sin conexión en estos momentos.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: La impresora ya tiene conexión.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: La impresora está sin conexión.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: Impresora no conectada; reintento en 30 segundos...\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: Imprimiendo página %d, %d%% completado...\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: Imprimiendo página %d...\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: Lista para imprimir.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: Enviando archivo de control (%lu bytes)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: Enviando archivo de control (%u bytes)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: Enviando datos\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: Enviando archivo de datos (%ld bytes)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: Enviando archivo de datos (%lld bytes)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: Enviando datos de impresión...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: Archivo de impresión enviado, %ld bytes...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: Archivo de impresión enviado, %lld bytes...\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: Guardando trabajo LPR en cola, %.0f%% completado...\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr "INFO: Iniciando página %d...\n"
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: No se ha podido contactar con la impresora; poniendo en cola en la "
+"siguiente impresora de la clase...\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: Usando zona AppleTalk predeterminada \"%s\"\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: Esperando a que finalice el trabajo...\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: Esperando a que la impresora esté disponible...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "Sobre ISO B4"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (extragrande)"
+
+msgid "ISO B5 Envelope"
+msgstr "Sobre ISO B5"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "Sobre ISO B6"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "Carácter de control ilegal"
+
+msgid "Illegal main keyword string"
+msgstr "Cadena de clave principal ilegal"
+
+msgid "Illegal option keyword string"
+msgstr "Cadena de clave de opción ilegal"
+
+msgid "Illegal translation string"
+msgstr "Cadena de traducción ilegal"
+
+msgid "Illegal whitespace character"
+msgstr "Carácter de espacio en blanco ilegal"
+
+msgid "Installable Options"
+msgstr "Opciones instalables"
+
+msgid "Installed"
+msgstr "Instalada"
+
+msgid "IntelliBar Label Printer"
+msgstr "Impresora de etiquetas IntelliBar"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr "Error interno del servidor"
+
+msgid "Internal error"
+msgstr "Error interno"
+
+msgid "Internet Postage 2-Part"
+msgstr "Correo por Internet Parte-2"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Correo por Internet Parte-2 - 2 1/4 x 7 1/2 pulg."
+
+msgid "Internet Postage 3-Part"
+msgstr "Correo por Internet Parte-3"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Correo por Internet Parte-3 - 2 1/4 x 7 pulg."
+
+msgid "Internet Printing Protocol"
+msgstr "Protocolo de Impresión de Internet IPP"
+
+msgid "Invite Envelope"
+msgstr "Sobre de invitación"
+
+msgid "Italian Envelope"
+msgstr "Sobre Italiano"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "El trabajo #%d ya está anulado - no se puede cancelar."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "El trabajo #%d ya está cancelado - no se puede cancelar."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "El trabajo #%d ya ha sido completado - no se puede cancelar."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "Trabajo completado"
+
+msgid "Job Created"
+msgstr "Trabajo creado"
+
+msgid "Job ID: "
+msgstr "ID del trabajo: "
+
+msgid "Job Options Changed"
+msgstr "Opciones de trabajo cambiadas"
+
+msgid "Job Stopped"
+msgstr "Trabajo detenido"
+
+msgid "Job UUID: "
+msgstr "UUID del trabajo: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "El trabajo está terminado y no puede ser cambiado."
+
+msgid "Job operation failed:"
+msgstr "La operación del trabajo ha fallado:"
+
+msgid "Job state cannot be changed."
+msgstr "No se puede cambiar el estado del trabajo."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "Trabajos"
+
+msgid "Kaku2 Envelope"
+msgstr "Sobre Kaku2"
+
+msgid "Kaku3 Envelope"
+msgstr "Sobre Kaku3"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "Equipo o impresora LPD/LPR"
+
+msgid "Label Printer"
+msgstr "Impresora de etiquetas"
+
+msgid "Label Top"
+msgstr "Parte superior de la etiqueta"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Dirección grande"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Dirección grande - 1 4/10 x 3 1/2 pulg."
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet Series PCL 4/5"
+
+msgid "Light"
+msgstr "Ligero"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Línea más larga que el máximo permitido (255 caracteres)"
+
+msgid "List Available Printers"
+msgstr "Listar impresoras disponibles"
+
+msgid "Location: "
+msgstr "Ubicación: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "Lado largo (retrato)"
+
+msgid "Make and Model: "
+msgstr "Marca y modelo: "
+
+msgid "Manual Feed"
+msgstr "Alimentación manual"
+
+msgid "Media Dimensions: "
+msgstr "Dimensiones del papel: "
+
+msgid "Media Limits: "
+msgstr "Límites del papel: "
+
+msgid "Media Name: "
+msgstr "Nombre del soporte: "
+
+msgid "Media Size"
+msgstr "Tamaño de papel"
+
+msgid "Media Source"
+msgstr "Fuente del papel"
+
+msgid "Media Tracking"
+msgstr "Seguimiento del medio"
+
+msgid "Media Type"
+msgstr "Tipo de papel"
+
+msgid "Medium"
+msgstr "Media"
+
+msgid "Memory allocation error"
+msgstr "Error de reserva de memoria"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "Falta cabecera PPD-Adobe-4.x"
+
+msgid "Missing asterisk in column 1"
+msgstr "Falta un asterisco en la columna 1"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "Falta cadena de valores"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Modelo: nombre = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "Modificar clase"
+
+msgid "Modify Printer"
+msgstr "Modificar impresora"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Sobre Monarch"
+
+msgid "Move All Jobs"
+msgstr "Mover todos los trabajos"
+
+msgid "Move Job"
+msgstr "Mover trabajo"
+
+msgid "Moved Permanently"
+msgstr "Movido permanentemente"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: Archivo de impresión aceptado: ID de trabajo %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: Archivo de impresión aceptado: ID de trabajo desconocido.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "Puntero de archivo PPD NULO"
+
+msgid "Name OID uses indefinite length"
+msgstr "Nombre OID usa una longitud indefinida"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Nunca"
+
+msgid "New Stylus Color Series"
+msgstr "Nueva Stylus Color Series"
+
+msgid "New Stylus Photo Series"
+msgstr "Nueva Stylus Photo Series"
+
+msgid "No"
+msgstr "No"
+
+msgid "No Content"
+msgstr "No hay contenido"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "No hay Varbind SEQUENCE"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "No hay conexión activa"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "No hay nombre de comunidad"
+
+msgid "No default printer"
+msgstr "No hay impresora predeterminada"
+
+msgid "No destinations added."
+msgstr "No se han añadido destinos."
+
+msgid "No error-index"
+msgstr "No hay error-index"
+
+msgid "No error-status"
+msgstr "No hay error-status"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "No hay nombre OID"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "No hay request-id"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "No se han encontrado subscripciones."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "No hay variable-bindings SEQUENCE"
+
+msgid "No version number"
+msgstr "No hay número de versión"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "No continuo (sensible a señal)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "No continuo (sensible a web)"
+
+msgid "Normal"
+msgstr "Normal"
+
+msgid "Not Found"
+msgstr "No encontrado"
+
+msgid "Not Implemented"
+msgstr "No implementado"
+
+msgid "Not Installed"
+msgstr "No instalado"
+
+msgid "Not Modified"
+msgstr "No modificado"
+
+msgid "Not Supported"
+msgstr "No permitido"
+
+msgid "Not allowed to print."
+msgstr "No se permite imprimir."
+
+msgid "Note"
+msgstr "Nota"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Off (1-Sided)"
+msgstr "Desactivado (1 cara)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Ayuda en línea"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "La apertura de %s ha fallado: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup sin un CloseGroup previo"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI sin un CloseUI/JCLCloseUI previo"
+
+msgid "Operation Policy"
+msgstr "Directiva de operación"
+
+msgid "Options Installed"
+msgstr "Opciones instaladas"
+
+msgid "Options: "
+msgstr "Opciones: "
+
+msgid "Output Mode"
+msgstr "Modo de salida"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "La salida de la impresora %s se ha enviado a %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr ""
+"La salida de la impresora %s se ha enviado a la impresora remota %s en %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "La salida de la impresora %s/%s se ha enviado a %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr ""
+"La salida de la impresora %s/%s se ha enviado a la impresora remota %s en %"
+"s\n"
+
+msgid "PASS\n"
+msgstr "PASA\n"
+
+msgid "PCL Laser Printer"
+msgstr "Impresora Laser PCL"
+
+msgid "PRC1 Envelope"
+msgstr "Sobre PRC1"
+
+msgid "PRC10 Envelope"
+msgstr "Sobre PRC10"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "Sobre PRC2"
+
+msgid "PRC3 Envelope"
+msgstr "Sobre PRC3"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (extragrande)"
+
+msgid "PRC4 Envelope"
+msgstr "Sobre PRC4"
+
+msgid "PRC5 Envelope"
+msgstr "Sobre PRC5"
+
+msgid "PRC6 Envelope"
+msgstr "Sobre PRC6"
+
+msgid "PRC7 Envelope"
+msgstr "Sobre PRC7"
+
+msgid "PRC8 Envelope"
+msgstr "Sobre PRC8"
+
+msgid "PRC9 Envelope"
+msgstr "Sobre PRC9"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "El paquete no contiene un Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "El paquete no empieza por SEQUENCE"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "¿Contraseña de %s en %s? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "Se requiere la contraseña de %s para acceder a %s vía SAMBA: "
+
+msgid "Pause Class"
+msgstr "Pausar clase"
+
+msgid "Pause Printer"
+msgstr "Pausar impresora"
+
+msgid "Peel-Off"
+msgstr "Despegar"
+
+msgid "Personal Envelope"
+msgstr "Sobre personal"
+
+msgid "Photo"
+msgstr "Foto"
+
+msgid "Photo Labels"
+msgstr "Foto pequeña"
+
+msgid "Plain Paper"
+msgstr "Papel normal"
+
+msgid "Policies"
+msgstr "Reglas"
+
+msgid "Port Monitor"
+msgstr "Monitor de puerto"
+
+msgid "PostScript Printer"
+msgstr "Impresora PostScript"
+
+msgid "Postcard"
+msgstr "Postal"
+
+msgid "Print Density"
+msgstr "Densidad de impresión"
+
+msgid "Print Job:"
+msgstr "Imprimir trabajo:"
+
+msgid "Print Mode"
+msgstr "Modo de impresión"
+
+msgid "Print Rate"
+msgstr "Tasa de impresión"
+
+msgid "Print Self-Test Page"
+msgstr "Imprimir página de auto-prueba"
+
+msgid "Print Speed"
+msgstr "Velocidad de impresión"
+
+msgid "Print Test Page"
+msgstr "Imprimir página de prueba"
+
+msgid "Print and Cut"
+msgstr "Imprimir y cortar"
+
+msgid "Print and Tear"
+msgstr "Imprimir y romper"
+
+msgid "Printed For: "
+msgstr "Impreso para: "
+
+msgid "Printed From: "
+msgstr "Impreso desde: "
+
+msgid "Printed On: "
+msgstr "Impreso en: "
+
+msgid "Printer Added"
+msgstr "Impresora añadida"
+
+msgid "Printer Default"
+msgstr "Predeterminado de la impresora"
+
+msgid "Printer Deleted"
+msgstr "Impresora borrada"
+
+msgid "Printer Modified"
+msgstr "Impresora modificada"
+
+msgid "Printer Name: "
+msgstr "Nombre de la impresora: "
+
+msgid "Printer Paused"
+msgstr "Impresora en pausa"
+
+msgid "Printer Settings"
+msgstr "Configuración de la impresora"
+
+msgid "Printer:"
+msgstr "Impresora:"
+
+msgid "Printers"
+msgstr "Impresoras"
+
+msgid "Purge Jobs"
+msgstr "Purgar trabajos"
+
+msgid "Quarto"
+msgstr "Quarto"
+
+msgid "Quota limit reached."
+msgstr "Se ha alcanzado el límite de cuota."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr "Rango Propiet. Trabajo Archivo(s) Tamaño total\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"Rango Propiet. Pri Trabajo Archivos Tamaño total\n"
+
+msgid "Reject Jobs"
+msgstr "Rechazar trabajos"
+
+msgid "Reprint After Error"
+msgstr "Volver a imprimir tras un error"
+
+msgid "Request Entity Too Large"
+msgstr "La entidad requerida es demasiado larga"
+
+msgid "Resolution"
+msgstr "Resolución"
+
+msgid "Resume Class"
+msgstr "Reanudar clase"
+
+msgid "Resume Printer"
+msgstr "Reanudar impresora"
+
+msgid "Return Address"
+msgstr "Remite"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Remite - 3/4 x 2 pulg."
+
+msgid "Rewind"
+msgstr "Rebobinar"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Ejecutando comando: %s %s -N -A '%s -c '%s'\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE usa una longitud indefinida"
+
+msgid "See Other"
+msgstr "Ver otros"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "Puerto serie #%d"
+
+msgid "Server Restarted"
+msgstr "Servidor reiniciado"
+
+msgid "Server Security Auditing"
+msgstr "Auditoría de seguridad del servidor"
+
+msgid "Server Started"
+msgstr "Servidor iniciado"
+
+msgid "Server Stopped"
+msgstr "Servidor parado"
+
+msgid "Service Unavailable"
+msgstr "Servicio no disponible"
+
+msgid "Set Allowed Users"
+msgstr "Establecer usuarios permitidos"
+
+msgid "Set As Server Default"
+msgstr "Establecer como predeterminada del servidor"
+
+msgid "Set Class Options"
+msgstr "Cambiar opciones clase"
+
+msgid "Set Printer Options"
+msgstr "Cambiar opciones impresora"
+
+msgid "Set Publishing"
+msgstr "Hacer pública"
+
+msgid "Shipping Address"
+msgstr "Dirección de envío"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "Dirección de envío - 2 5/16 x 4 pulg."
+
+msgid "Short-Edge (Landscape)"
+msgstr "Lado corto (apaisado)"
+
+msgid "Special Paper"
+msgstr "Papel especial"
+
+msgid "Standard"
+msgstr "Estándar"
+
+msgid "Starting Banner"
+msgstr "Rótulo inicial"
+
+msgid "Statement"
+msgstr "Declaración"
+
+msgid "Stylus Color Series"
+msgstr "Stylus Color Series"
+
+msgid "Stylus Photo Series"
+msgstr "Stylus Photo Series"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B (13 x 19 pulg.)"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "Protocolos de conexión"
+
+msgid "Tabloid"
+msgstr "Tabloide"
+
+msgid "Tabloid (Oversize)"
+msgstr "Tabloide (extragrande)"
+
+msgid "Tear"
+msgstr "Pestaña"
+
+msgid "Tear-Off"
+msgstr "Pestaña desprendible"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Ajuste de posición de la pestaña desprendible"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "No se ha podido encontrar el archivo PPD \"%s\"."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "No se ha podido abrir el archivo PPD \"%s\": %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"El nombre de la clase sólo puede contener hasta 127 caracteres imprimibles y "
+"no puede contener espacios, barras (/), o la almohadilla (#)."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+"El atributo notify-lease-duration no puede ser usado con subscripciones de "
+"trabajos."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"El nombre de la impresora sólo puede contener hasta 127 caracteres "
+"imprimibles y no puede contener espacios, barras (/), o la almohadilla (#)."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "No se ha encontrado la impresora o la clase."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "El printer-uri \"%s\" contiene caracteres incorrectos."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr ""
+"El printer-uri debe ser de la forma \"ipp://NOMBRE_ORDENADOR/classes/"
+"NOMBRE_CLASE\"."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+"El printer-uri debe ser de la forma \"ipp://NOMBRE_ORDENADOR/printers/"
+"NOMBRE_IMPRESORA\"."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"El nombre de la subscripción no puede contener espacios, barras (/), signos "
+"de interrogación (?), o la almohadilla (#)."
+
+msgid "There are too many subscriptions."
+msgstr "Hay demasiadas subscripciones."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "Soporte de transferencia térmica"
+
+msgid "Title: "
+msgstr "Título: "
+
+msgid "Too many active jobs."
+msgstr "Demasiados trabajos activos."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "Transparencia"
+
+msgid "Tray"
+msgstr "Bandeja"
+
+msgid "Tray 1"
+msgstr "Bandeja 1"
+
+msgid "Tray 2"
+msgstr "Bandeja 2"
+
+msgid "Tray 3"
+msgstr "Bandeja 3"
+
+msgid "Tray 4"
+msgstr "Bandeja 4"
+
+msgid "URI Too Long"
+msgstr "URI demasiado largo"
+
+msgid "US Executive"
+msgstr "Ejecutivo de EE.UU"
+
+msgid "US Fanfold"
+msgstr "FanFold de EE.UU"
+
+msgid "US Ledger"
+msgstr "Libro Mayor, 17 x 11 pulg."
+
+msgid "US Legal"
+msgstr "Legal EE.UU."
+
+msgid "US Legal (Oversize)"
+msgstr "Legal EE.UU. (extragrande)"
+
+msgid "US Letter"
+msgstr "Carta EE.UU."
+
+msgid "US Letter (Oversize)"
+msgstr "Carta EE.UU. (extragrande)"
+
+msgid "US Letter (Small)"
+msgstr "Carta EE.UU. (pequeña)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "Puerto serie USB #%d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "No se ha podido acceder al archivo cupsd.conf"
+
+msgid "Unable to add RSS subscription:"
+msgstr "No se ha podido añadir la subscripción RSS:"
+
+msgid "Unable to add class:"
+msgstr "No se ha podido añadir la clase:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "No se ha podido añadir la impresora:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "No se ha podido cancelar la subscripción RSS:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "No se ha podido cambiar el atributo printer-is-shared:"
+
+msgid "Unable to change printer:"
+msgstr "No se ha podido cambiar la impresora:"
+
+msgid "Unable to change server settings:"
+msgstr "No se ha podido cambiar la configuración del servidor:"
+
+msgid "Unable to connect to host."
+msgstr "No se ha podido conectar al servidor."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "No se ha podido crear el archivo temporal:"
+
+msgid "Unable to delete class:"
+msgstr "No se ha podido borrar la clase:"
+
+msgid "Unable to delete printer:"
+msgstr "No se ha podido borrar la impresora:"
+
+msgid "Unable to do maintenance command:"
+msgstr "No se ha podido realizar el comando de mantenimiento:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "No se ha podido obtener la lista de clases:"
+
+msgid "Unable to get class status:"
+msgstr "No se ha podido obtener el estado de la clase:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "No se ha podido obtener la lista de controladores de impresora:"
+
+msgid "Unable to get printer attributes:"
+msgstr "No se han podido obtener los atributos de la impresora:"
+
+msgid "Unable to get printer list:"
+msgstr "No se ha podido obtener la lista de impresoras:"
+
+msgid "Unable to get printer status:"
+msgstr "No se ha podido obtener el estado de la impresora"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "No se ha podido modificar la clase:"
+
+msgid "Unable to modify printer:"
+msgstr "No se ha podido modificar la impresora:"
+
+msgid "Unable to move job"
+msgstr "No se ha podido mover el trabajo"
+
+msgid "Unable to move jobs"
+msgstr "No se han podido mover los trabajos"
+
+msgid "Unable to open PPD file"
+msgstr "No se ha podido abrir el archivo PPD"
+
+msgid "Unable to open PPD file:"
+msgstr "No se ha podido abrir el archivo PPD:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "No se ha podido abrir el archivo cupsd.conf:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "No se ha podido imprimir la página de prueba:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "No se ha podido ejecutar \"%s\": %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "No se han podido cambiar las opciones:"
+
+msgid "Unable to set server default:"
+msgstr "No se han podido cambiar los ajustes predeterminados del servidor:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "No se ha podido copiar el archivo cupsd.conf:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "No autorizado"
+
+msgid "Units"
+msgstr "Unidades"
+
+msgid "Unknown"
+msgstr "Desconocido"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "printer-error-policy \"%s\" incorrecto."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "printer-op-policy \"%s\" incorrecto."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Tipo de valor no permitido"
+
+msgid "Upgrade Required"
+msgstr "Se requiere actualización"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Uso:\n"
+"\n"
+" lpadmin [-h servidor] -d destino\n"
+" lpadmin [-h servidor] -x destino\n"
+" lpadmin [-h servidor] -p impresora [-c clase] [-i interfaz] [-m modelo]\n"
+" [-r clase] [-v dispositivo] [-D descripción]\n"
+" [-P archivo_ppd] [-o nombre=valor]\n"
+" [-u allow:usuario,usuario] [-u deny:usuario,usuario]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "Uso: %s trabajo usuario título copias opciones [archivo]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "Uso: %s job-id usuario título copias opciones [archivo]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "Uso: %s job-id usuario título copias opciones archivo\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+"Uso: convert [ opciones ]\n"
+"\n"
+"Opciones:\n"
+"\n"
+" -e Usar cada filtro del archivo PPD\n"
+" -f nombre_archivo Establecer el archivo a convertir (de lo "
+"contrario, stdin)\n"
+" -o nombre_archivo Establecer el archivo a generar (de lo "
+"contrario, stdout)\n"
+" -i tipo/mime Establecer el tipo MIME de entrada (de lo contrario, "
+"auto-typed)\n"
+" -j tipo/mime Establecer el tipo MIME de salida (de lo contrario, "
+"application/pdf)\n"
+" -P nombre_archivo.ppd Establecer el archivo PPD\n"
+" -a 'nombre=valor ...' Establecer opciones\n"
+" -U nombre_usuario Establecer un nombre de usuario para el "
+"trabajo\n"
+" -J título Establecer el título\n"
+" -c copias Establecer el número de copias\n"
+" -u Borrar el archivo PPD al finalizar\n"
+" -D Borrar el archivo de entrada al finalizar\n"
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Uso: cupsaddsmb [opciones] impresora1 ... impresoraN\n"
+" cupsaddsmb [opciones] -a\n"
+"\n"
+"Opciones:\n"
+" -E Hace que se use encriptación en la conexión con el "
+"servidor\n"
+" -H servidor_samba Usa el servidor SAMBA especificado\n"
+" -U usuario_samba Autentifica usando el usuario SAMBA especificado\n"
+" -a Exporta todas las impresoras\n"
+" -h servidor_cups Usa el servidor CUPS especificado\n"
+" -v Ser detallado (mostrar comandos)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Uso: cupsctl [opciones] [param=valor ... paramN=valorN]\n"
+"\n"
+"Opciones:\n"
+"\n"
+" -E Activar encriptación\n"
+" -U nombre_usuario Especificar nombre de usuario\n"
+" -h servidor[:puerto] Especificar la dirección del servidor\n"
+"\n"
+" --[no-]debug-logging Activar o desactivar el registro de depuración\n"
+" --[no-]remote-admin Activar o desactivar la administración remota\n"
+" --[no-]remote-any Permitir o impedir el acceso desde Internet\n"
+" --[no-]remote-printers Mostrar u ocultar las impresoras remotas\n"
+" --[no-]share-printers Activar o desactivar la compartición de "
+"impresoras\n"
+" --[no-]user-cancel-any Permitir o impedir a los usuarios cancelar "
+"cualquier trabajo\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Uso: cupsd (-c archivo-configuración) (-f) (-F) (-h) (-l)\n"
+"\n"
+"-c archivo-configuración Carga un archivo de configuración alternativo\n"
+"-f Se ejecuta en primer plano\n"
+"-F Se ejecuta en primer plano pero separado\n"
+"-h Muestra este mensaje de cómo se usa\n"
+"-l Ejecuta cupsd desde launchd(8)\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+"Uso: cupsfilter -m tipo/mime [ opciones ] nombre_archivo\n"
+"\n"
+"Opciones:\n"
+"\n"
+" -c cupsd.conf Establecer el archivo cupsd.conf a usar\n"
+" -e Usar cada filtro del archivo PPD\n"
+" -j job-id[,N] Filtrar el archivo N del trabajo especificado (el valor "
+"predeterminado es el archivo 1)\n"
+" -n copias Establecer el número de copias\n"
+" -o nombre=valor Establecer opciones\n"
+" -p nombre_archivo.ppd Establecer el archivo PPD\n"
+" -t título Establecer el título\n"
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Uso: cupstestdsc [opciones] nombre_archivo.ps [... nombre_archivo.ps]\n"
+" cupstestdsc [opciones] -\n"
+"\n"
+"Opciones:\n"
+"\n"
+" -h Muestra cómo se usa el programa\n"
+"\n"
+" Nota: este programa sólo valida los comentarios DSC, no el PostScript en "
+"sí mismo.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Uso: lpmove trabajo/fuente destino\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Uso: lpoptions [-h servidor] [-E] -d impresora\n"
+" lpoptions [-h servidor] [-E] [-p impresora] -l\n"
+" lpoptions [-h servidor] [-E] -p impresora -o opción[=valor] ...\n"
+" lpoptions [-h servidor] [-E] -x impresora\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Usage: lppasswd [-g nombre_grupo]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Usage: lppasswd [-g nombre_grupo] [nombre_usuario]\n"
+" lppasswd [-g nombre_grupo] -a [nombre_usuario]\n"
+" lppasswd [-g nombre_grupo] -x [nombre_usuario]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Uso: lpq (-P dest) (-U nombre_usuario) (-h nombre_ordenador(:puerto)) (-l) "
+"(+intervalo)\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Uso: ppdc [opciones] nombre_archivo.drv [ ... nombre_archivoN.drv ]\n"
+"Options:\n"
+" -D nombre=valor Establecer la variable nombre al valor.\n"
+" -I include-dir Añadir el directorio include a la ruta de búsqueda.\n"
+" -c catálogo.po Cargar el catálogo de mensajes especificado.\n"
+" -d dir-salida Especificar el directorio de salida.\n"
+" -l idioma[,idioma,...] Especificar el/los idioma(s) de salida.\n"
+" -m Usar el valor ModelName como nombre de archivo.\n"
+" -t Chequear el PPDs en vez de generarlo.\n"
+" -v Ser detallado (más v's para más detalle).\n"
+" -z Comprimir los archivos PPD usando GNU zip.\n"
+" --cr Terminar las líneas con CR (Mac OS 9).\n"
+" --crlf Terminar las líneas con CR + LF (Windows).\n"
+" --lf Terminar las líneas con LF (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"Uso: ppdhtml [opciones] nombre_archivo.drv >nombre_archivo.html\n"
+"Opciones:\n"
+" -D nombre=valor Establecer la variable nombre al valor.\n"
+" -I include-dir Añadir el directorio include a la ruta de búsqueda.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Uso: ppdi [opciones] nombre_archivo.ppd [ ... nombre_archivoN.ppd ]\n"
+"Opciones:\n"
+" -I include-dir\n"
+" -o nombre_archivo.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Uso: ppdmerge [opciones] nombre_archivo.ppd [ ... nombre_archivoN.ppd ]\n"
+"Opciones:\n"
+" -o nombre_archivo.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"Uso: ppdpo [opciones] -o nombre_archivo.po nombre_archivo.drv [ ... "
+"nombre_archivoN.drv ]\n"
+"Opciones:\n"
+" -D nombre=valor Establecer la variable nombre al valor.\n"
+" -I include-dir Añadir el directorio include a la ruta de búsqueda.\n"
+" -v Ser detallado (más v's para más detalle).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Uso: snmp [ordenador-o-dirección-ip]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Valor usa una longitud indefinida"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind usa una longitud indefinida"
+
+msgid "Version uses indefinite length"
+msgstr "Versión usa una longitud indefinida"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: Añadiendo sólo las primeras %d impresoras encontradas"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr ""
+"WARNING: Se esperaba un valor booleano para la opción waiteof \"%s\".\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: La impresora no responde\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: La impresora envió un EOF inesperado\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: No se ha podido abrir \"%s:%s\": %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: No se ha podido enviar la petición de estado PAP"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: Paquete PAP de tipo %d no esperado\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: Paquete PAP de tipo %d desconocido\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: se esperaba un número para la opción de estado \"%s\"\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Si"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"Debe acceder a esta página usando el URL <A HREF=\"https://%s:%d%s\">https://"
+"%s:%d%s</A>."
+
+msgid "You4 Envelope"
+msgstr "Sobre You4"
+
+msgid "ZPL Label Printer"
+msgstr "Impresora de etiquetas ZPL"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "cancelado"
+
+msgid "canceled"
+msgstr "cancelado"
+
+msgid "completed"
+msgstr "completado"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr "convert: Use la opción -f para especificar el fichero a convertir.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "Ha fallado al ejecutarse cups-deviced."
+
+msgid "cups-driverd failed to execute."
+msgstr "Ha fallado al ejecutarse cups-driverd."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: No hay archivo PPD para la impresora \"%s\" - %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: No se ha podido conectar al servidor: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr ""
+"cupsd: el uso de launchd(8) no ha sido compilado, ejecutándose en modo "
+"normal.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: No se ha podido obtener el archivo del trabajo - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd: La opción -q es incompatible con la opción -v.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd: La opción -v es incompatible con la opción -q.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "tipo de conexión para %s/%s: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "tipo de conexión para %s: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "error-index usa una longitud indefinida"
+
+msgid "error-status uses indefinite length"
+msgstr "error-status usa una longitud indefinida"
+
+msgid "held"
+msgstr "retenido"
+
+msgid "help\t\tget help on commands\n"
+msgstr "help\t\tproporciona ayuda sobre los comandos\n"
+
+msgid "idle"
+msgstr "inactiva"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: La impresora %s ya es miembro de la clase %s.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: La impresora %s no es miembro de la clase %s.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: No se ha podido conectar al servidor: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: No se ha podido abrir el archivo PPD \"%s\" - %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: No se ha podido abrir el archivo \"%s\": %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: No se ha podido conectar al servidor: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: No se ha podido añadir la impresora o la instancia: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: No se ha podido obtener el archivo PPD para %s: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: Lo siento, se ha rechazado la contraseña.\n"
+"Su contraseña debe tener al menos 6 caracteres, no puede contener\n"
+"su nombre de usuario, y debe tener al menos una letra y un número.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: No se ha podido copiar la cadena de contraseña: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: No se ha podido abrir el archivo de contraseñas: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: No se ha podido escribir en el archivo de contraseñas: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr ""
+"lppasswd: falló al hacer una copia de seguridad del antiguo archivo de "
+"contraseñas: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: falló al cambiar de nombre al archivo de contraseñas: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: el usuario \"%s\" y el grupo \"%s\" no existen.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "miembros de la clase %s:\n"
+
+msgid "no entries\n"
+msgstr "no hay entradas\n"
+
+msgid "no system default destination\n"
+msgstr "no hay un destino predeterminado del sistema\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "pendiente"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: Añadiendo directorio include \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: Añadiendo/actualizando texto UI desde %s...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: Valor lógico (%s) incorrecto en línea %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: Sustitución de variable ($%c) errónea en la línea %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: Se esperaba un valor lógico en la línea %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: Se esperaba un código apropiado en la línea %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: Se esperaba un nombre/texto apropiado en la línea %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: Cargando archivo de información de controlador \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: Cargando mensajes del idioma \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: Cargando mensajes desde \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: No se ha podido crear el archivo PPD \"%s\" - %s.\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: No se ha podido crear el directorio de salida %s: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: No se han podido crear canales (pipes) de salida: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: No se ha podido ejecutar cupstestppd: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: No se ha podido encontrar localización para \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: No se ha podido cargar el archivo de localización \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: Variable no definida (%s) en la línea %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: Escribiendo %s...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: Escribiendo archivos PPD al directorio \"%s\"...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: Ignorando archivo PPD %s...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: No se ha podido hacer copia de seguridad de %s a %s- %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "la impresora %s está deshabilitada desde %s -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "la impresora %s está inactiva. activada desde %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "la impresora %s está imprimiendo %s-%d. activada desde %s\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "la impresora %s/%s está desactivada desde %s -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "la impresora %s/%s está inactiva. activada desde %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "la impresora %s/%s está imprimiendo %s-%d. activada desde %s\n"
+
+msgid "processing"
+msgstr "en proceso"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "la id solicitada es %s-%d (%d archivo(s))\n"
+
+msgid "request-id uses indefinite length"
+msgstr "request-id usa una longitud indefinida"
+
+msgid "scheduler is not running\n"
+msgstr "el planificador de tareas no se está ejecutando\n"
+
+msgid "scheduler is running\n"
+msgstr "el planificador de tareas se está ejecutando\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "estado de %s ha fallado: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "status\t\tmuestra el estado del demonio y la cola\n"
+
+msgid "stopped"
+msgstr "parada"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "destino predeterminado del sistema: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "destino predeterminado del sistema: %s/%s\n"
+
+msgid "unknown"
+msgstr "desconocido"
+
+msgid "untitled"
+msgstr "sin título"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindings usa una longitud indefinida"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " ADVERTENCIA %s tiene opciones que no corresponden.\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr ""
+#~ " ADVERTENCIA Las preferencias predeterminadas están en "
+#~ "conflicto.\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " ADVERTENCIA La clave de opción Duplex %s puede que no funcione "
+#~ "como se espera y debería llamarse Duplex.\n"
+#~ " REF: Página 122, sección 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " ADVERTENCIA El archivo contiene una mezcla de líneas acabadas "
+#~ "en CR, LF y CR LF.\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr ""
+#~ " ADVERTENCIA La línea %d solo contiene espacios en blanco.\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " ADVERTENCIA Los archivos PPD que no sean de Windows deben "
+#~ "tener líneas que acaben sólo en LF, no en CR LF.\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " ADVERTENCIA Versión de PPD %.1f anticuada.\n"
+#~ " REF: Página 42, sección 5.2.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s no existe.\n"
+
+#~ msgid " %s %s file \"%s\" has the wrong capitalization!\n"
+#~ msgstr " %s archivo %s \"%s\" tiene las mayúsculas equivocadas.\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s Preferencia %s incorrecta %s.\n"
+#~ " REF: Página 122, sección 5.17\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr ""
+#~ " %s Cadena de traducción UTF-8 \"%s\" incorrecta para opción %s.\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Cadena de traducción UTF-8 \"%s\" incorrecta para opción %s, "
+#~ "preferencia %s.\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Valor cupsFilter \"%s\" incorrecto.\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s cupsICCProfile %s incorrecto.\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Valor cupsPreFilter \"%s\" incorrecto.\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s cupsUIConstraints %s: \"%s\" incorrecto.\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s Idioma incorrecto \"%s\".\n"
+
+#~ msgid " %s Bad spelling of %s - should be %s!\n"
+#~ msgstr " %s %s mal escrito - debería ser %s.\n"
+
+#~ msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID!\n"
+#~ msgstr ""
+#~ " %s No puede proporcionar APScanAppPath y APScanAppBundleID.\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s cupsUIConstraints %s vacío.\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s Falta cadena de traducción \"%s\" para opción %s.\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Falta cadena de traducción \"%s\" para opción %s, preferencia %"
+#~ "s.\n"
+
+#~ msgid ""
+#~ " %s Missing REQUIRED PageRegion option!\n"
+#~ " REF: Page 100, section 5.14.\n"
+#~ msgstr ""
+#~ " %s Falta la opción NECESARIA PageRegion.\n"
+#~ " REF: Página 100, sección 5.14.\n"
+
+#~ msgid ""
+#~ " %s Missing REQUIRED PageSize option!\n"
+#~ " REF: Page 99, section 5.14.\n"
+#~ msgstr ""
+#~ " %s Falta la opción NECESARIA PageSize.\n"
+#~ " REF: Página 99, sección 5.14.\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Falta la preferencia *%s %s en UIConstraint \"*%s %s *%s %s\".\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr ""
+#~ " %s Falta la preferencia *%s %s en cupsUIConstraints %s: \"%s\".\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s Falta el archivo cupsICCProfile \"%s\".\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s Falta cupsUIResolver %s.\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr " %s Falta la opción %s en UIConstraints \"*%s %s *%s %s\".\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Falta la opción %s en cupsUIConstraints %s: \"%s\".\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr " %s No hay traducción base \"%s\" incluida en el archivo.\n"
+
+#~ msgid ""
+#~ " %s Non-standard size name \"%s\"!\n"
+#~ " REF: Page 187, section B.2.\n"
+#~ msgstr ""
+#~ " %s Tamaño de nombre \"%s\" no estándar.\n"
+#~ " REF: Página 187, sección B.2.\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s NECESARIA %s no define la opción None.\n"
+#~ " REF: Página 122, sección 5.17\n"
+
+#~ msgid " %s Size \"%s\" defined for %s but not for %s!\n"
+#~ msgstr " %s Tamaño \"%s\" definido para %s pero no para %s.\n"
+
+#~ msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)!\n"
+#~ msgstr " %s El tamaño \"%s\" tiene inesperadas dimensiones (%gx%g).\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " %s valor hash de cupsICCProfile %s colisiona con %s!\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver %s genera un bucle.\n"
+
+#~ msgid ""
+#~ " %s cupsUIResolver %s does not list at least two different "
+#~ "options!\n"
+#~ msgstr ""
+#~ " %s cupsUIResolver %s no lista al menos dos opciones diferentes.\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FALLO** %s nombres de opción %s y %s se diferencian sólo en la "
+#~ "capitalización.\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **FALLO** %s debe ser 1284DeviceID.\n"
+#~ " REF: Página 72, sección 5.5\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **FALLO** DefaultImageableArea %s INCORRECTO\n"
+#~ " REF: Página 102, sección 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **FALLO** DefaultPaperDimension %s INCORRECTO.\n"
+#~ " REF: Página 103, sección 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **FALLO** Preferencia %s incorrecta %s.\n"
+#~ " REF: Página 84, sección 5.9\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr ""
+#~ " **FALLO** LanguageEncoding %s incorrecto: debería ser ISOLatin1.\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr ""
+#~ " **FALLO** LanguageVersion %s incorrecto: debería ser Inglés.\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **FALLO** Cadena de traducción predeterminada para opción %s "
+#~ "preferencia %s contiene caracteres de 8-bits.\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **FALLO** Cadena de traducción predeterminada para opción %s "
+#~ "contiene caracteres de 8-bits.\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FALLO** Nombres de grupo %s y %s se diferencian sólo en la "
+#~ "capitalización.\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **FALLO** Múltiples apariciones de %s nombre de opción %s.\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FALLO** Nombres de opción %s y %s se diferencian sólo en la "
+#~ "capitalización.\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " %%%%BoundingBox: incorrecto en línea %d.\n"
+#~ " REF: Página 39, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " %%%%Page: incorrecto en línea %d.\n"
+#~ " REF: Página 53, %%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " %%%%Pages: incorrecto en línea %d.\n"
+#~ " REF: Página 43, %%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " La línea %d es más larga de 255 caracteres (%d).\n"
+#~ " REF: Página 25, Longitud de Línea\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " Falta %!PS-Adobe-3.0 en la primera línea.\n"
+#~ " REF: Página 17, 3.1 Conformidad de documentos\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " Falta comentario %%EndComments.\n"
+#~ " REF: Página 41, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " Falta comentario %%BoundingBox: o incorrecto.\n"
+#~ " REF: Página 39, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " Falta comentario %%Page: o incorrecto.\n"
+#~ " REF: Página 53, %%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " Falta comentario %%Pages: o incorrecto.\n"
+#~ " REF: Página 43, %%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " Se han visto %d líneas que exceden de 255 caracteres.\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " Demasiados comentarios %%BeginDocument.\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " Demasiados comentarios %%EndDocument.\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " Advertencia: el archivo contiene datos binarios.\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " Advertencia: no hay comentario %%EndComments en el archivo.\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " Advertencia: versión DSC %.1f obsoleta en el archivo.\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "No se admite el uso de %s."
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: No sé que hay que hacer.\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: Error - %s nombres de variables de entorno no existen en destino \"%s"
+#~ "\".\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: Error - ID de trabajo incorrecta.\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr ""
+#~ "%s: Error - no se pueden imprimir archivos y alterar trabajos al mismo "
+#~ "tiempo.\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: Error - no se puede imprimir desde stdin si se proporcionan archivos "
+#~ "o una ID de trabajo.\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr ""
+#~ "%s: Error - se esperaba un juego de caracteres tras la opción '-S'.\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: Error - se esperaba un tipo de contenido tras la opción '-T'.\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: Error - se esperaba número de copias tras la opción '-n'.\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s: Error - se esperaba un número de copias tras la opción '-#'.\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: Error - se esperaba un destino tras la opción '-P'.\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: Error - se esperaba un destino tras la opción '-b'.\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: Error - se esperaba un destino tras la opción '-d'.\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: Error - se esperaba un formulario tras la opción '-f'.\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr ""
+#~ "%s: Error - se esperaba un nombre de retención tras la opción '-H'.\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr ""
+#~ "%s: Error - se esperaba un nombre de ordenador tras la opción '-H'.\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr ""
+#~ "%s: Error - se esperaba un nombre de ordenador tras la opción '-h'.\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: Error - se esperaba una lista de modos tras la opción '-y'.\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: Error - se esperaba un nombre tras la opción '%c'.\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr ""
+#~ "%s: Error - se esperaba una cadena de opciones tras la opción '-o'.\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: Error - se esperaba una lista de páginas tras la opción '-P'.\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr ""
+#~ "%s: Error - se esperaba un valor de prioridad tras la opción '-%c'.\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr ""
+#~ "%s: Error - se esperaba un texto con una razón tras la opción '-r'.\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: Error - se esperaba un título tras la opción '-t'.\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s: Error - se esperaba un nombre de usuario tras la opción '-U'.\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s: Error - se esperaba un nombre de usuario tras la opción '-u'.\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: Error - se esperaba un valor tras la opción '%c'.\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: Error - se necesita \"completed\", \"not completed\", o \"all\" tras "
+#~ "la opción '-W'.\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: Error - el programa planificador de tareas no responde.\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: Error - destino \"%s\" desconocido.\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: Error - destino \"%s/%s\" desconocido.\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: Error - opción '%c' desconocida.\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: Error: opción '%s' desconocida.\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s : Se esperaba una ID de trabajo tras la opción '-i'.\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: Nombre de destino no válido en la lista \"%s\".\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr ""
+#~ "%s: Se necesita un ID de trabajo ('-i id_trabajo') antes de '-H "
+#~ "restart'.\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: No hay ningún filtro que convertir de %s/%s a %s/%s.\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s: Lo siento, no está compilado con la opción de encriptación.\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: No se ha podido contactar con el servidor.\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: No se ha podido determinar el tipo MIME de \"%s\".\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s: No se pudo leer base de datos MIME desde \"%s\" o \"%s\".\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: Destino \"%s\" desconocido.\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: Tipo MIME de destino %s/%s desconocido.\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: Opción '%c' desconocida.\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: Tipo MIME de origen %s/%s desconocido.\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: Advertencia - no se admite el uso del modificador de formato '%c' - "
+#~ "la salida puede no ser correcta.\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr ""
+#~ "%s: Advertencia - opción de juego de caracteres no tenida en cuenta.\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr ""
+#~ "%s: Advertencia - opción de tipo de contenido no tenida en cuenta.\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: Advertencia - opción de formulario no tenida en cuenta.\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: Advertencia - opción de modo no tenida en cuenta.\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: error - %s nombres de variables de entorno no existen en destino \"%s"
+#~ "\".\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: error - se esperaba opción=valor tras la opción '-o'.\n"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr ""
+#~ "Se requiere una contraseña Samba para exportar los controladores de "
+#~ "impresora."
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr ""
+#~ "Se requiere un nombre de usuario Samba para exportar los controladores de "
+#~ "impresora."
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "Ya existe una clase llamada \"%s\"."
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "Ya existe una impresora llamada \"%s\"."
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr ""
+#~ "Se ha intentado cambiar el valor printer-state de %s a un valor "
+#~ "incorrecto %d."
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "Los grupos de atributos están desordenados (%x < %x)."
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "URI de dispositivoi \"%s\" incorrecto.\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "device-uri \"%s\" incorrecto."
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "Esquema device-uri \"%s\" incorrecto."
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "document-format \"%s\" incorrecto."
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Nombre de archivo del búfer incorrecto."
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Valor job-priority incorrecto."
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Valor de job-sheets \"%s\" incorrecto."
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Tipo de valor de job-sheets incorrecto."
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Valor job-state incorrecto."
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Atributo job-uri \"%s\" incorrecto."
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "notify-pull-method \"%s\" incorrecto."
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "URI notify-recipient-uri \"%s\" incorrecto."
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "Opción + preferencia incorrectas en línea %d."
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "port-monitor \"%s\" incorrecto."
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Valor printer-state %d incorrecto."
+
+#~ msgid "Bad request ID %d!"
+#~ msgstr "ID %d de petición incorrecta."
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "Petición incorrecta de número de versión %d.%d."
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "ID de subscripción incorrecto."
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "No se admite el uso del juego de caracteres \"%s\"."
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "No se puede analizar el tipo \"%s\"."
+
+#~ msgid "Cover open."
+#~ msgstr "Cubierta abierta."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "Revelador casi vacío."
+
+#~ msgid "Developer empty!"
+#~ msgstr "Revelador vacío."
+
+#~ msgid "Door open."
+#~ msgstr "Puerta abierta."
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Se ha detectado un comentario %%BoundingBox: incorrecto.\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: Comentario %%IncludeFeature: incorrecto.\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: Comentario %%Page: incorrecto en el archivo.\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: Comentario %%PageBoundingBox: incorrecto en el archivo.\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: archivo de dispositivo SCSI \"%s\" incorrecto.\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: Valor de columnas %d incorrecto.\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: Valor de cpi %f incorrecto.\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: Valor de lpi %f incorrecto.\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: Ajuste de página incorrecto.\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: La impresora destino no existe.\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Se ha detectado un comentario %%BoundingBox: duplicado.\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: Se ha detectado un comentario %%Pages: duplicado.\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: Archivo de impresión vacío.\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr ""
+#~ "ERROR: Se esperaba una cadena entrecomillada en la línea %d de %s.\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: Error fatal de USB.\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr ""
+#~ "ERROR: Se ha detectado un comando HP-GL/2 no válido; no se puede imprimir "
+#~ "el archivo.\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: Falta %%EndProlog.\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: Falta %%EndSetup.\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: Falta el valor en la línea %d del archivo de rótulo.\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: Se necesita una línea msgid antes de cualquier cadena de "
+#~ "traducción en línea %d de %s.\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: No hay comentario %%BoundingBox: en la cabecera.\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: No hay comentario %%Pages: en la cabecera.\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: No se ha encontrado el URI del dispositivo en argv[0] o en la "
+#~ "variable de entorno DEVICE_URI.\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: No se han encontrado páginas.\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: No hay papel.\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: Variable de entorno PRINTER no definida.\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: No se ha aceptado la impresión del archivo (%s).\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: La impresora no responde.\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr ""
+#~ "ERROR: No se han podido obtener los atributos del trabajo %d (%s).\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: No se ha podido obtener el estado de la impresora (%s).\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: No se ha podido localizar la impresora '%s'.\n"
+
+#~ msgid "ERROR: Unable to open PPD file!\n"
+#~ msgstr "ERROR: No se ha podido abrir el archivo PPD.\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr ""
+#~ "ERROR: No se ha podido abrir el archivo de imagen para imprimirlo.\n"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: No se ha podido imprimir %d columnas de texto.\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: No se ha podido imprimir %dx%d páginas de texto.\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: No se han podido leer los datos de impresión.\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: No se han podido enviar los datos de impresión (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: No se han podido enviar los datos de impresión.\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: No se han podido escribir %d bytes a la impresora.\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr ""
+#~ "ERROR: No se ha podido escribir la trama de datos (raster) al "
+#~ "controlador.\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: No se ha podido escribir al archivo temporal"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: Texto inesperado en la línea %d del %s.\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: Valor de opción de encriptación \"%s\" desconocida.\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: Formato del catálogo de mensajes para \"%s\" desconocido.\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: Opción \"%s\" con valor \"%s\" desconocida.\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: Valor de opción de versión \"%s\" desconocida.\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr "ERROR: Valor de brillo %s no permitido; usando brillo=100.\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: Valor gamma %s no permitido; usando gamma=1000.\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr ""
+#~ "ERROR: Valor de number-up (páginas por hoja) %d no permitido; usando "
+#~ "number-up=1.\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: Valor de number-up-layout (disposición de páginas por hoja) %s no "
+#~ "permitido; usando number-up-layout=lrtb.\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: Valor de page-border (borde de página) %s no permitido; usando "
+#~ "page-border=none (ninguno).\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr ""
+#~ "ERROR: Se ha detectado un desbordamiento de doc_printf (%d bytes); "
+#~ "cancelando.\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops se ha cerrado con la señal %d.\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops se ha cerrado con el estado %d.\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: recuperable: No se ha podido establecer conexión con la impresora; "
+#~ "reintento en 30 segundos...\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "Archivo PPD vacío."
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "Error: se necesita un nombre de ordenador tras la opción '-h'.\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Temperatura del fusor alta."
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "Temperatura del fusor baja."
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "Se ha obtenido el atributo printer-uri pero no el job-id."
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Tinta/toner casi vacíos."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Tinta/toner vacíos."
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Recipiente de residuos de tinta/tóner casi lleno."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Recipiente de residuos de tinta/tóner lleno."
+
+#~ msgid "Interlock open."
+#~ msgstr "Dispositivo de seguridad abierto."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "El trabajo #%d no puede ser reiniciado - no hay archivos."
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "El trabajo #%d no existe."
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "El trabajo #%d ha terminado y no puede ser modificado."
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "El trabajo #%d no ha sido completado."
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "El trabajo #%d no está retenido para autentificación."
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "El trabajo #%d no está retenido."
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "El trabajo #%s no existe."
+
+#~ msgid "Job %d not found!"
+#~ msgstr "No se ha encontrado el trabajo %d."
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "Las suscripciones de trabajos no han podido ser renovadas."
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "No se admite el uso del idioma \"%s\"."
+
+#~ msgid "Media jam!"
+#~ msgstr "Atasco de papel."
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Bandeja de papel casi vacía."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Bandeja de papel vacía."
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Falta la bandeja de papel."
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "Hay que poner papel en la bandeja."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "Falta el atributo document-number."
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "Faltan dobles comillas en línea %d."
+
+#~ msgid "Missing form variable!"
+#~ msgstr "Variable de formulario desaparecida."
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "Atributo notify-subscription-ids desaparecido."
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "Falta el atributo requesting-user-name."
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "Faltan atributos necesarios."
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "Falta un valor en la línea %d."
+
+#~ msgid "Nested classes are not allowed!"
+#~ msgstr "No se permiten clases anidadas."
+
+#~ msgid "No PPD name!"
+#~ msgstr "No hay nombre de PPD."
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "No está instalado ningún controlador de impresora de Windows."
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "No hay trabajos activos en %s."
+
+#~ msgid "No attributes in request!"
+#~ msgstr "No hay atributos en la solicitud."
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "No se ha proporcionado información de autentificación."
+
+#~ msgid "No file!?!"
+#~ msgstr "¡¿¡No hay archivo!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "No hay tiempo de modificación."
+
+#~ msgid "No printer name!"
+#~ msgstr "No hay nombre de impresora."
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "No se encontró printer-uri para la clase."
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "No se encontró printer-uri."
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "No hay printer-uri en la petición."
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "No hay atributos de subscripción en la solicitud."
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC prácticamente agotado."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC agotado."
+
+#~ msgid "Out of toner!"
+#~ msgstr "No hay toner."
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Recipiente de salida casi lleno."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Recipiente de salida lleno."
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Falta la bandeja de salida."
+
+#~ msgid "Printer offline."
+#~ msgstr "Impresora desconectada."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "Impresora SCSI"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "El valor notify-user-data es demasiado grande (%d > 63 octetos)."
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "La impresora o clase no está compartida."
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "Se necesita el atributo printer-uri."
+
+#~ msgid "Toner low."
+#~ msgstr "Toner bajo."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "Demasiados valores de job-sheets (%d > 2)."
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "Demasiados valores printer-state-reasons (%d > %d)."
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "No se ha podido añadir el trabajo para el destino \"%s\"."
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "No se ha podido reservar memoria para tipos de archivo."
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "No se han podido copiar los archivos del controlador de impresora de 64-"
+#~ "bit de CUPS (%d)."
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr ""
+#~ "No se han podido copiar los archivos del controlador de impresora de 64-"
+#~ "bit de Windows (%d)."
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "No se han podido copiar los archivos del controlador de impresora de CUPS "
+#~ "(%d)."
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "No se ha podido copiar el archivo PPD - %s."
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "No se ha podido copiar el archivo PPD."
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "No se han podido copiar los archivos del controlador de impresora de "
+#~ "Windows 2000 (%d)."
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "No se han podido copiar los archivos del controlador de impresora de "
+#~ "Windows 9x (%d)."
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "No se ha podido copiar el script de interfaz - %s."
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "No se ha podido crear printer-uri."
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr "No se pueden editar archivos cupsd.conf mayores de 1MB."
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "No se ha podido encontrar destino para el trabajo."
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "No se ha podido encontrar la impresora.\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "No se han podido instalar los archivos del controlador de impresora de "
+#~ "Windows 2000 (%d)."
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "No se han podido instalar los archivos del controlador de impresora de "
+#~ "Windows 9x (%d)."
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "No se ha podido abrir el documento %d del trabajo %d."
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "No se ha podido enviar un comando al controlador de la impresora."
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr ""
+#~ "No se ha podido configurar el controlador de impresora de Windows (%d)."
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "No se ha podido usar el controlador de dispositivo USB obsoleto.\n"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Juego de caracteres \"%s\" no permitido."
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "No se admite el uso de la compresión \"%s\"."
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "No se admite el uso del atributo de compresión %s."
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "No se admite el uso del formato \"%s\"."
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "No se admite el uso del formato '%s'."
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "No se admite el uso del formato '%s/%s'."
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+#~ "translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Uso: cupstestppd [opciones] nombre_archivo1.ppd[.gz] [... nombre_archivoN."
+#~ "ppd[.gz]]\n"
+#~ " programa | cupstestppd [opciones] -\n"
+#~ "\n"
+#~ "Opciones:\n"
+#~ "\n"
+#~ " -R directorio-raíz Establecer directorio raíz alternativo\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+#~ "translations}\n"
+#~ " Emitir avisos (warnings) en vez de errores\n"
+#~ " -q Ejecución silenciosa\n"
+#~ " -r Usar modo abierto 'relajado'\n"
+#~ " -v Ser ligeramente detallado\n"
+#~ " -vv Ser muy detallado\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: No se ha podido leer la petición del canal lateral.\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr "WARNING: La opción \"%s\" no puede incluirse con IncludeFeature.\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: El ordenador remoto no ha respondido con el byte de estado del "
+#~ "comando después de %d segundos.\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: El ordenador remoto no ha respondido con el byte de estado de "
+#~ "control después de %d segundos.\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: El ordenador remoto no ha respondido con el byte de estado de "
+#~ "los datos después de %d segundos.\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr ""
+#~ "WARNING: Agotado el tiempo de espera para el comando SCSI (%d); "
+#~ "reintentando...\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: Este documento no se ajusta a las Convenciones de Estructuración "
+#~ "de Documentos de Adobe y puede que no se imprima correctamente.\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: Preferencia \"%s\" desconocida para la opción \"%s\".\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: Opción \"%s\" desconocida.\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: No se admite el uso de la velocidad en baudios %s.\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: recuperable: El ordenador de red '%s' está ocupado; reintento en "
+#~ "%d segundos...\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr ""
+#~ "Advertencia, no está instalado ningún controlador de impresora de Windows "
+#~ "2000."
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: Opción \"%s\" desconocida.\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: Opción \"-%c\" desconocida.\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr ""
+#~ "cupsd: Se esperaba un nombre de archivo de configuración tras la opción "
+#~ "\"-c\".\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: No se ha podido obtener el directorio actual.\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: Argumento \"%s\" desconocido - cancelando.\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: Opción \"%c\" desconocida - cancelando.\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: Número de documento %d inválido.\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: ID de trabajo %d inválida.\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: Solo se puede especificar un nombre de archivo.\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "Falta el atributo job-printer-uri."
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr ""
+#~ "lpadmin: El nombre de la clase sólo puede contener caracteres "
+#~ "imprimibles.\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: Se esperaba un PPD tras la opción '-P'.\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr ""
+#~ "lpadmin: Se esperaba allow/deny:lista_usuarios tras la opción '-u'.\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: Se esperaba una clase tras la opción '-r'\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: Se esperaba un nombre de clase tras la opción '-c'\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: Se esperaba una descripción tras la opción '-D'.\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: Se esperaba un URI de dispositivo tras la opción '-v'.\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: Se esperaba tipo(s) de archivo(s) tras la opción '-l'.\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: Se esperaba un nombre de ordenador tras la opción '-h'.\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: Se esperaba una interfaz tras la opción '-i'.\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: Se esperaba una ubicación tras la opción '-L'.\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: Se esperaba un modelo tras la opción '-m'.\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: Se esperaba un nombre=valor tras la opción '-o'.\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: Se esperaba una impresora tras la opción '-p'.\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: Se esperaba un nombre de impresora tras la opción '-d'\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin: Se esperaba una impresora o clase tras la opción '-x'.\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: No se han visto nombres de miembros.\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr ""
+#~ "lpadmin: El nombre de la impresora sólo puede contener caracteres "
+#~ "imprimibles.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: No se ha podido añadir una impresora a la clase:\n"
+#~ " Debe especificar un nombre de impresora primero.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: No se ha podido quitar una impresora de la clase:\n"
+#~ " Primero debe especificar un nombre de impresora.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: No se ha podido establecer el archivo PPD:\n"
+#~ " Primero debe especificar un nombre de impresora.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: No se ha podido ajustar el URI de dispositivo:\n"
+#~ " Primero debe especificar un nombre de impresora.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: No se ha podido establecer el script de interfaz o el archivo "
+#~ "PPD:\n"
+#~ " Primero debe especificar un nombre de impresora.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: No se ha podido establecer el script de interfaz:\n"
+#~ " Primero debe especificar un nombre de impresora.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: No se ha podido establecer la descripción de la impresora:\n"
+#~ " Primero debe especificar un nombre de impresora.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: No se ha podido establecer la ubicación de la impresora:\n"
+#~ " Primero debe especificar un nombre de impresora.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: No se han podido establecer las opciones de impresora:\n"
+#~ " Primero debe especificar un nombre de impresora.\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: Opción allow/deny desconocida \"%s\".\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: Argumento '%s' desconocido.\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: Opción '%c' desconocida.\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr ""
+#~ "lpadmin: Advertencia - lista de tipo de contenido no tenida en cuenta.\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr ""
+#~ "lpinfo: Se esperaba una cadena ID de dispositivo 1284 tras --device-id.\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: Se esperaba un idioma tras --language.\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo: Se esperaba marca y modelo tras --make-and-model.\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo: Se esperaba una cadena de producto tras --product.\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo: Se esperaba una lista de esquemas tras --exclude-schemes.\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo: Se esperaba una lista de esquemas tras --include-schemes.\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: Se esperaba un tiempo tras --timeout.\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo Argumento '%s' desconocido.\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: Opción '%c' desconocida.\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: Opción desconocida '%s'.\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: Argumento '%s' desconocido.\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: Opción '%c' desconocida.\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: ¡¿¡No hay impresoras!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: No se ha podido abrir el archivo PPD para %s.\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: Impresora o clase desconocida.\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: Solo el usuario root puede añadir o borrar contraseñas.\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: Archivo de contraseñas ocupado.\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: Archivo de contraseñas no actualizado.\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: Lo siento, las contraseñas no coinciden.\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: Lo siento, las contraseñas no coinciden.\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: error - Los nombre de variable de entorno %s no existen en el "
+#~ "destino \"%s\".\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-events no especificado."
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "El URI notify-recipient-uri \"%s\" ya está usado."
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "El URI notify-recipient-uri \"%s\" usa un esquema desconocido."
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d incorrecto."
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Resolución de nombre \"%s\" incorrecta en línea %d de %s.\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: Clave de estado %s incorrecta en línea %d de %s.\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc: Selección encontrada en línea %d de %s sin opciones.\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc: #po duplicado para código regional %s en línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba una definición de filtro en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un nombre de programa en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba un juego de caracteres tras Font en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba un orden de color para ColorModel en la línea %d de %"
+#~ "s.\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba colorspace para ColorModel en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba compresión para ColorModel en la línea %d de %s.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba una cadena de restricciones para UIConstraints en la "
+#~ "línea %d de %s.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba una clave de tipo de controlador tras DriverType en la "
+#~ "línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba un tipo dúplex tras Duplex en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba una codificación tras Font en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba un nombre de archivo tras #po %s en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un nombre/texto de grupo en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba un nombre de archivo include en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un número entero en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba un código regional tras #po en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un nombre tras %s en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un nombre tras FileName en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un nombre tras Font en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba un nombre tras Manufacturer en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un nombre tras MediaSize en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un nombre tras ModelName en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un nombre tras PCFileName en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un nombre/texto tras %s en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba un nombre/texto tras Installable en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba un nombre/texto tras Resolution en la línea %d de %s.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba una combinación nombre/texto para ColorModel en la "
+#~ "línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba una opción de nombre/texto en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba una sección de opciones en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un tipo de opción en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba un campo de anulación tras Resolution en la línea %d de "
+#~ "%s.\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un número real en la línea %d de %s.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba resolución/tipo de soporte tras ColorProfile en la "
+#~ "línea %d de %s.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Se esperaba resolución/tipo de soporte tras SimpleColorProfile en "
+#~ "la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un selector tras %s en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un estado tras Font en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba una cadena tras Copyright en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba una cadena tras Version en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaban dos nombres de opciones en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba un valor tras %s en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Se esperaba una versión tras Font en la línea %d de %s'.\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: Nombre de fichero #include/#po incorrecto \"%s\".\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Coste incorrecto para el filtro en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Tipo MIME vacío incorrecto para el filtro en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Nombre de programa vacío incorrecto para el filtro en la línea %d "
+#~ "de %s.\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Sección de opción incorrecta \"%s\" en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Tipo de opción incorrecta \"%s\" en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: Falta un #endif al final de \"%s\".\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: Falta un #if en la línea %d de %s.\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr ""
+#~ "ppdc: No se ha proporcionado catálogo de mensajes para el idioma %s.\n"
+
+#~ msgid "ppdc: Option %s defined in two different groups on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Opción %s definida en dos diferentes grupos en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Opción %s redefinida con un tipo diferente en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr "ppdc: Opción de restricción debe *name en línea %d de %s.\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: Demasiados #if anidados en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: No se ha podido encontrar el archivo #po %s en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: No se ha podido encontrar el archivo include \"%s\" en la línea %d "
+#~ "de %s.\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: Tipo de controlador desconocido %s en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Tipo dúplex desconocido \"%s\" en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Tamaño de papel desconocido \"%s\" en la línea %d de %s.\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: Elemento desconocido \"%s\" visto en la línea %d de %s.\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Caracteres finales desconocidos en el número real \"%s\" en la "
+#~ "línea %d de %s.\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Cadena que comienza por %c sin terminar en la línea %d de %s.\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: LanguageVersion \"%s\" incorrecto en %s.\n"
diff --git a/locale/cups_eu.po b/locale/cups_eu.po
new file mode 100644
index 000000000..56d7afdb1
--- /dev/null
+++ b/locale/cups_eu.po
@@ -0,0 +1,7231 @@
+# translation of cups_1.4rc1_eu.po to Basque
+#
+# "$Id$"
+#
+# Message catalog template for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 2005-2007 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+#
+# Notes for Translators:
+#
+# The following prefixes MUST NOT be translated: "ALERT:", "CRIT:", "INFO:",
+# "NOTICE:", and "WARNING:".
+#
+# The "checkpo" program located in the "locale" source directory can be used
+# to verify that your translations do not introduce formatting errors or other
+# problems. Run with:
+#
+# cd locale
+# ./checkpo cups_LL.po
+#
+# where "LL" is your locale.
+#
+# Iñaki Larrañaga Murgoitio <dooteo@euskalgnu.org>, 2009.
+msgid ""
+msgstr ""
+"Project-Id-Version: cups_1.4rc1_eu\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-07-03 19:34+0200\n"
+"Last-Translator: Iñaki Larrañaga Murgoitio <dooteo@euskalgnu.org>\n"
+"Language-Team: Basque <itzulpena@euskalgnu.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(denak)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(bat ere ez)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d sarrera\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tHutsegitearen ostean: jarraitu\n"
+
+msgid "\tAlerts:"
+msgstr "\tAlertak:"
+
+msgid "\tBanner required\n"
+msgstr "\tTitularra behar da\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tKaraktere-jokoa:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tKonexioa: zuzena\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tKonexioa: urrunekoa\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tOrrialde-tamaina lehenetsia:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tTarte lehenetsia:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tAtakaren ezarpen lehenetsiak:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tDeskripzioa: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tInprimakia muntatuta:\n"
+"\tEduki mota: edozer\n"
+"\tInprimagailu motak: ezezaguna\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tBaimendutako inprimakiak:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tInterfazea: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tInterfazea: %s/interfaces/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tInterfazea: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tKokalekua: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tHutsegitean: alertarik ez\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tBaimendutako erabiltzaileak:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tUkatutako erabiltzaileak:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tdaemona badago\n"
+
+msgid "\tno entries\n"
+msgstr "\tsarrerarik ez\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\tinprimagailua '%s' gailuan dago abiadura -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\tinprimatzea desgaituta dago\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\tinprimatzea gaituta dago\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\t%s(e)n ilaratuta\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tilaratzea desgaituta\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tilaratzea gaituta\n"
+
+msgid "\treason unknown\n"
+msgstr "\tarrazoi ezezaguna\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" ADOSTASUNAREN PROBAREN EMAITZ XEHETUA\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " Erref.: 15. orrialdea, 3.1 atala.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " Erref.: 15. orrialdea, 3.2 atala.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " Erref.: 19. orrialdea, 3.3 atala.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " Erref.: 20. orrialdea, 3.4 atala.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " Erref.: 27. orrialdea, 3.5 atala.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " Erref.: 42. orrialdea, 5.2 atala.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " Erref.: 16-17 orrialdeak, 3.2 atala.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " Erref.: 42-45 orrialdeak, 5.2 atala.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " Erref.: 45-46 orrialdeak, 5.2 atala.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " Erref.: 48-49 orrialdeak, 5.2 atala.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " Erref.: 52-54 orrialdeak, 5.2 atala.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f byte\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " BALIOZKOA Lehenetsia%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " BALIOZKOA DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " BALIOZKOA DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " BALIOZKOA FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " BALIOZKOA FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " BALIOZKOA LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " BALIOZKOA LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " BALIOZKOA Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " BALIOZKOA ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " BALIOZKOA NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " BALIOZKOA PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " BALIOZKOA PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " BALIOZKOA PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " BALIOZKOA PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " BALIOZKOA Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " BALIOZKOA ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" ABISUA \"%s %s\" gatazkan dago honekin: \"%s %s\"\n"
+" (murriztapena=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" ABISUA %s(e)k aurrizki amankomuna partekatzen du %s(r)ekin\n"
+" Erref: 15. orrialdea, 3.2 atala.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" ABISUA PPD 4.3 zehaztapenak LanguageEncoding behar du.\n"
+" Erref: 56-57 orrialdeak, 5.3 atala.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" ABISUA PPD 4.3 zehaztapenak Manufacturer behar du.\n"
+" Erref: 58-59 orrialdeak, 5.3 atala.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" ABISUA PCFileName 8.3 baino luzeagoa da, eta PPD zehaztapenaren "
+"bortxaketa da.\n"
+" Erref: 61-62 orrialdeak, 5.3 atala.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" ABISUA Protokoloek PJL dute, baina JCL atributuak ez daude "
+"ezarrita.\n"
+" Erref: 78-79 orrialdeak, 5.7 atala.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" ABISUA Protokoloek bai PJL bai BCP dituzte, baina TBCP espero "
+"zen.\n"
+" Erref: 78-79 orrialdeak, 5.7 atala.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" ABISUA PPD 4.3 zehaztapenak ShortNickName behar du.\n"
+" Erref: 64-65 orrialdeak, 5.3 atala.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr " %s APDialogExtension-en \"%s\" fitxategia falta da\n"
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr " %s APPrinterIconPath-en \"%s\" fitxategia falta da\n"
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr " %s APPrinterLowInkTool-en \"%s\" fitxategia falta da\n"
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr " %s APPrinterUtilityPath-en \"%s\" fitxategia falta da\n"
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr " %s APScanAppPath-en \"%s\" fitxategia falta da\n"
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s cupsFilter-en \"%s\" fitxategia falta da\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s cupsPreFilter-en \"%s\" fitxategia falta da\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **HUTSEGITEA** OKERREKO Default%s %s\n"
+" Erref: 40. orrialdea, 4.5 atala.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **HUTSEGITEA** OKERREKO JobPatchFile atributua fitxategian\n"
+" Erref: 24. orrialdea, 3.4 atala.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **HUTSEGITEA** OKERREKO Manufacturer (\"HP\" izan beharko luke)\n"
+" Erref: 211. orrialdea, D.1 taula.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **HUTSEGITEA** OKERREKO Manufacturer (\"Oki\" izan beharko luke)\n"
+" Erref: 211. orrialdea, D.1 taula.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** OKERREKO ModelName - \"%c\" ez dago baimenduta "
+"katean.\n"
+" Erref: 59-60 orrialdeak, 5.3 atala.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** OKERREKO PSVersion - ez da \"(string) int\".\n"
+" Erref: 62-64 orrialdeak, 5.3 atala.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** OKERREKO Product - ez da \"(string)\".\n"
+" Erref: 62. orrialdea, 5.3 atala.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** OKERREKO ShortNickName - 31 karaktere baino luzeagoa.\n"
+" Erref: 64-65 orrialdeak, 5.3 atala.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** Okerreko \"%s\" FileVersion\n"
+" Erref: 56. orrialdea, 5.3 atala.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** Okerreko \"%s\" FormatVersion\n"
+" Erref: 56. orrialdea, 5.3 atala.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr ""
+" **HUTSEGITEA** Aukera lehenetsiaren kodea ezin da interpretatu: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **HUTSEGITEA** Default%s BEHARREZKOA DA\n"
+" Erref: 40. orrialdea, 4.5 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **HUTSEGITEA** DefaultImageableArea BEHARREZKOA DA\n"
+" Erref: 102. orrialdea, 5.15 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **HUTSEGITEA** DefaultPaperDimension BEHARREZKOA DA\n"
+" Erref: 103. orrialdea, 5.15 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** FileVersion BEHARREZKOA DA\n"
+" Erref: 56. orrialdea, 5.3 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** FormatVersion BEHARREZKOA DA\n"
+" Erref: 56. orrialdea, 5.3 atala.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **HUTSEGITEA** ImageableArea BEHARREZKOA DA %s PageSize-rentzako\n"
+" Erref: 41. orrialdea, 5 atala.\n"
+" Erref: 102. orrialdea, 5.15 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** LanguageEncoding BEHARREZKOA DA\n"
+" Erref: 56-57 orrialdeak, 5.3 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** LanguageVersion BEHARREZKOA DA\n"
+" Erref: 57-58 orrialdeak, 5.3 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** Manufacturer BEHARREZKOA DA\n"
+" Erref: 58-59 orrialdeak, 5.3 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** ModelName BEHARREZKOA DA\n"
+" Erref: 59-60 orrialdeak, 5.3 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** NickName BEHARREZKOA DA\n"
+" Erref: 60. orrialdea, 5.3 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** PCFileName BEHARREZKOA DA\n"
+" Erref: 61-62 orrialdeak, 5.3 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** PSVersion BEHARREZKOA DA\n"
+" Erref: 62-64 orrialdeak, 5.3 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **HUTSEGITEA** PageRegion BEHARREZKOA DA\n"
+" Erref: 100. orrialdea, 5.14 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **HUTSEGITEA** REQUIRED BEHARREZKOA DA\n"
+"ageSize\n"
+" Erref: EF. orrialdea: atalasection 5.\n"
+" Erref: EF. orrialdea: sec atalation 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **HUTSEGITEA** PageSize BEHARREZKOA DA\n"
+" Erref: 99-100 orrialdeak, 5.14 atala.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **HUTSEGITEA** PaperDimension BEHARREZKOA DA %s PageSize-rentzako\n"
+" Erref: 41. orrialdea, 5 atala.\n"
+" Erref: 103. orrialdea, 5.15 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** Product BEHARREZKOA DA\n"
+" Erref: 62. orrialdea, 5.3 atala.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **HUTSEGITEA** ShortNickName BEHARREZKOA DA\n"
+" Erref: 64-65 orrialdeak, 5.3 atala.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " %d ERRORE AURKITU DIRA\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " EZ DA ERRORERIK AURKITU\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " HUTSEGITEA\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" HUTSEGITEA\n"
+" **HUTSEGITEA** Ezin da PPD fitxategia ireki - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" HUTSEGITEA\n"
+" **HUTSEGITEA** Ezin da PPD fitxategia ireki - %s %d lerroan.\n"
+
+msgid " PASS\n"
+msgstr " BALIOZKOA\n"
+
+msgid "#10 Envelope"
+msgstr "10. gutunazala"
+
+msgid "#11 Envelope"
+msgstr "11. gutunazala"
+
+msgid "#12 Envelope"
+msgstr "12. gutunazala"
+
+msgid "#14 Envelope"
+msgstr "14. gutunazala"
+
+msgid "#9 Envelope"
+msgstr "9. gutunazala"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f byte\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f byte\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f milimetro"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f -> %.0f x %.0f milimetro"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f hatz"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f -> %.2f x %.2f hatz"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s(e)k eskaerak onartzen ditu %s unetik\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%s ezin da aldatu."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s ez dago CUPSen lpc bertsioan garatuta.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s ez dago prest\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s prest dago\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s prest dago eta inprimatzen\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s(e)k ez du eskaerarik onartzen %s unetik\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s-(e)k eskaerak onartzen ditu %s unetik\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s-(e)k ez ditu eskaerarik onartzen %s unetik\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [%d lana localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s(e)k huts egin du: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: errorea - helburu lehenetsia ez dago eskuragarri\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: errorea - lehentasuna 1 eta 100 artean egon behar du\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: errorea - fitxategi gehiegi - \"%s\"\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: errorea - ezin da \"%s\" atzitu - %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s: errorea - ezin da stdin-etik ilaratu - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: \"%s\" iragazkia ez dago erabilgarri: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: \"%s\" iragazkiaren kate baliogabea\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: huts egin du eragiketak: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: ezin da zerbitzariarekin konektatu\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: ezin da %s ireki: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: ezin da PPD fitxategia ireki: %s %d lerroan\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr "%s: ezin da PPD fitxategia ireki: %s %d lerroan\n"
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: errorea - helburu lehenetsia ez dago eskuragarri\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 hazt/seg"
+
+msgid "1.25x0.25\""
+msgstr "1.25x0.25\""
+
+msgid "1.25x2.25\""
+msgstr "1.25x2.25\""
+
+msgid "1.5 inch/sec."
+msgstr "1.5 hatz/seg"
+
+msgid "1.50x0.25\""
+msgstr "1.50x0.25\""
+
+msgid "1.50x0.50\""
+msgstr "1.50x0.50\""
+
+msgid "1.50x1.00\""
+msgstr "1.50x1.00\""
+
+msgid "1.50x2.00\""
+msgstr "1.50x2.00\""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 hatz/seg"
+
+msgid "10 x 11\""
+msgstr "10 x 11\""
+
+msgid "10 x 13\""
+msgstr "10 x 13\""
+
+msgid "10 x 14\""
+msgstr "10 x 14\""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 mm/seg"
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 hatz/seg"
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 hatz/seg"
+
+msgid "12 x 11\""
+msgstr "12 x 11\""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 mm/seg"
+
+msgid "120x60dpi"
+msgstr "120x60dpi"
+
+msgid "120x72dpi"
+msgstr "120x72dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 mm/seg"
+
+msgid "15 x 11\""
+msgstr "15 x 11\""
+
+msgid "150 mm/sec."
+msgstr "150 mm/seg"
+
+msgid "150dpi"
+msgstr "150dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 hatz/seg"
+
+msgid "2-Sided Printing"
+msgstr "2 alboetatik inprimatzea"
+
+msgid "2.00x0.37\""
+msgstr "2.00x0.37\""
+
+msgid "2.00x0.50\""
+msgstr "2.00x0.50\""
+
+msgid "2.00x1.00\""
+msgstr "2.00x1.00\""
+
+msgid "2.00x1.25\""
+msgstr "2.00x1.25\""
+
+msgid "2.00x2.00\""
+msgstr "2.00x2.00\""
+
+msgid "2.00x3.00\""
+msgstr "2.00x3.00\""
+
+msgid "2.00x4.00\""
+msgstr "2.00x4.00\""
+
+msgid "2.00x5.50\""
+msgstr "2.00x5.50\""
+
+msgid "2.25x0.50\""
+msgstr "2.25x0.50\""
+
+msgid "2.25x1.25\""
+msgstr "2.25x1.25\""
+
+msgid "2.25x4.00\""
+msgstr "2.25x4.00\""
+
+msgid "2.25x5.50\""
+msgstr "2.25x5.50\""
+
+msgid "2.38x5.50\""
+msgstr "2.38x5.50\""
+
+msgid "2.5 inches/sec."
+msgstr "2.hatz/seg"
+
+msgid "2.50x1.00\""
+msgstr "2.50x1.00\""
+
+msgid "2.50x2.00\""
+msgstr "2.50x2.00\""
+
+msgid "2.75x1.25\""
+msgstr "2.75x1.25\""
+
+msgid "2.9 x 1\""
+msgstr "2.9 x 1\""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 mm/seg"
+
+msgid "200 mm/sec."
+msgstr "200 mm/seg"
+
+msgid "203dpi"
+msgstr "203dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "24 orrratzeko serieak"
+
+msgid "240x72dpi"
+msgstr "240x72dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 mm/seg"
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 hatz/seg"
+
+msgid "3.00x1.00\""
+msgstr "3.00x1.00\""
+
+msgid "3.00x1.25\""
+msgstr "3.00x1.25\""
+
+msgid "3.00x2.00\""
+msgstr "3.00x2.00\""
+
+msgid "3.00x3.00\""
+msgstr "3.00x3.00\""
+
+msgid "3.00x5.00\""
+msgstr "3.00x5.00\""
+
+msgid "3.25x2.00\""
+msgstr "3.25x2.00\""
+
+msgid "3.25x5.00\""
+msgstr "3.25x5.00\""
+
+msgid "3.25x5.50\""
+msgstr "3.25x5.50\""
+
+msgid "3.25x5.83\""
+msgstr "3.25x5.83\""
+
+msgid "3.25x7.83\""
+msgstr "3.25x7.83\""
+
+msgid "3.5\" Disk"
+msgstr "3.5\" diskoa"
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "3.5\" diskoa - 2 1/8 x 2 3/4\""
+
+msgid "3.50x1.00\""
+msgstr "3.50x1.00\""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 mm/seg"
+
+msgid "300 mm/sec."
+msgstr "300 mm/seg"
+
+msgid "300dpi"
+msgstr "300dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360dpi"
+
+msgid "360x180dpi"
+msgstr "360x180dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 hatz/seg"
+
+msgid "4.00x1.00\""
+msgstr "4.00x1.00\""
+
+msgid "4.00x13.00\""
+msgstr "4.00x13.00\""
+
+msgid "4.00x2.00\""
+msgstr "4.00x2.00\""
+
+msgid "4.00x2.50\""
+msgstr "4.00x2.50\""
+
+msgid "4.00x3.00\""
+msgstr "4.00x3.00\""
+
+msgid "4.00x4.00\""
+msgstr "4.00x4.00\""
+
+msgid "4.00x5.00\""
+msgstr "4.00x5.00\""
+
+msgid "4.00x6.00\""
+msgstr "4.00x6.00\""
+
+msgid "4.00x6.50\""
+msgstr "4.00x6.50\""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 mm/seg"
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 hatz/seg"
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 hatz/seg"
+
+msgid "6.00x1.00\""
+msgstr "6.00x1.00\""
+
+msgid "6.00x2.00\""
+msgstr "6.00x2.00\""
+
+msgid "6.00x3.00\""
+msgstr "6.00x3.00\""
+
+msgid "6.00x4.00\""
+msgstr "6.00x4.00\""
+
+msgid "6.00x5.00\""
+msgstr "6.00x5.00\""
+
+msgid "6.00x6.00\""
+msgstr "6.00x6.00\""
+
+msgid "6.00x6.50\""
+msgstr "6.00x6.50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/seg"
+
+msgid "600dpi"
+msgstr "600dpi"
+
+msgid "60dpi"
+msgstr "60dpi"
+
+msgid "60x720dpi"
+msgstr "60x720dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 hatz/seg"
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 hatz/seg"
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8.00x1.00\""
+
+msgid "8.00x2.00\""
+msgstr "8.00x2.00\""
+
+msgid "8.00x3.00\""
+msgstr "8.00x3.00\""
+
+msgid "8.00x4.00\""
+msgstr "8.00x4.00\""
+
+msgid "8.00x5.00\""
+msgstr "8.00x5.00\""
+
+msgid "8.00x6.00\""
+msgstr "8.00x6.00\""
+
+msgid "8.00x6.50\""
+msgstr "8.00x6.50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/seg"
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 hatz/seg"
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "9 orratzeko serieak"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "? laguntzako komando ezezagun baliogabea\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (handiagoa)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (handiagoa)"
+
+msgid "A4 (Small)"
+msgstr "A4 (txikia)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (handiagoa)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "Onartu lanak"
+
+msgid "Accepted"
+msgstr "Onartuta"
+
+msgid "Add Class"
+msgstr "Gehitu klasea"
+
+msgid "Add Printer"
+msgstr "Gehitu inprimagailua"
+
+msgid "Add RSS Subscription"
+msgstr "Gehitu RSS harpidetza"
+
+msgid "Address"
+msgstr "Helbidea"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "Helbidea - 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "Administrazioa"
+
+msgid "Always"
+msgstr "Beti"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "Aplikatzailea"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "Okerreko helburuko NULL erakuslea"
+
+msgid "Bad OpenGroup"
+msgstr "Okerreko OpenGroup"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "Okerreko OpenUI/JCLOpenUI"
+
+msgid "Bad OrderDependency"
+msgstr "Okerreko OrderDependency"
+
+msgid "Bad Request"
+msgstr "Okerreko eskaera"
+
+msgid "Bad SNMP version number"
+msgstr "Okerreko SNMP bertsio zenbakia"
+
+msgid "Bad UIConstraints"
+msgstr "Okerreko UIConstraints"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Okerreko kopien %d balioa."
+
+msgid "Bad custom parameter"
+msgstr "Okerreko parametro pertsonalizatua"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Okerreko letra-atributua: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Okerreko number-up balioa: %d."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Okerreko page-ranges balioak: %d-%d."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Titularrak"
+
+msgid "Billing Information: "
+msgstr "Fakturazioaren informazioa: "
+
+msgid "Bond Paper"
+msgstr "Tituluentzako papera"
+
+msgid "C0 Envelope"
+msgstr "C0 gainazala"
+
+msgid "C1 Envelope"
+msgstr "C1 gainazala"
+
+msgid "C2 Envelope"
+msgstr "C2 gainazala"
+
+msgid "C3 Envelope"
+msgstr "C3 gainazala"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "C4 gainazala"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "C5 gainazala"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "C6 gainazala"
+
+msgid "C65 Envelope"
+msgstr "C65 gainazala"
+
+msgid "C7 Envelope"
+msgstr "C7 gainazala"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "CPCL etiketen inprimagailua"
+
+msgid "Cancel RSS Subscription"
+msgstr "Utzi RSS harpidetza"
+
+msgid "Change Settings"
+msgstr "Aldatu ezarpenak"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Chou3 gainazala"
+
+msgid "Chou4 Envelope"
+msgstr "Chou4 gainazala"
+
+msgid "Classes"
+msgstr "Klaseak"
+
+msgid "Clean Print Heads"
+msgstr "Garbitu inprimatze-buruak"
+
+msgid "Color"
+msgstr "Kolorea"
+
+msgid "Color Mode"
+msgstr "Koloreen modua"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"Komandoa laburtu daitezke. Hauek dira komandoak:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "Komunitatearen izenak definitu gabeko luzera darabil"
+
+msgid "Continue"
+msgstr "Jarraitu"
+
+msgid "Continuous"
+msgstr "Jarraia"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Sortuta"
+
+msgid "Created On: "
+msgstr "Sorrera-data:"
+
+msgid "Custom"
+msgstr "Pertsonalizatu"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Ebaki"
+
+msgid "Cutter"
+msgstr "Ebakigailua"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "DL gutunazala"
+
+msgid "Dark"
+msgstr "Iluna"
+
+msgid "Darkness"
+msgstr "Iluntasuna"
+
+msgid "Delete Class"
+msgstr "Ezabatu klasea"
+
+msgid "Delete Printer"
+msgstr "Ezabatu inprimagailua"
+
+msgid "Description: "
+msgstr "Deskripzioa: "
+
+msgid "DeskJet Series"
+msgstr "DeskJet serieak"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "\"%s\" helburuak ez du lanik onartzen."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"Gailua: URIa = %s\n"
+" klasea = %s\n"
+" informazioa = %s\n"
+" marka eta modeloa = %s\n"
+" gailuaren IDa = %s\n"
+" kokalekua = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "Zuzeneko euskarri termikoa"
+
+msgid "Disabled"
+msgstr "Desgaituta"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "Ez da %d dokumentua aurkitu %d lanean."
+
+msgid "Double Postcard"
+msgstr "Postal bikoitza"
+
+msgid "Driver Name: "
+msgstr "Kontrolatzailearen izena:"
+
+msgid "Driver Version: "
+msgstr "Kontrolatzailearen bertsioa:"
+
+msgid "Duplexer"
+msgstr "Duplexatzailea"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr ""
+"EMERG: ezin da memoriarik esleitu orrialdearen informazioarentzako: %s.\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: ezin da memoriarik esleitu orrialdeen arrayarentzako: %s.\n"
+
+msgid "EPL1 Label Printer"
+msgstr "EPL1 etiketen inprimagailua"
+
+msgid "EPL2 Label Printer"
+msgstr "EPL2 etiketen inprimagailua"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr "ERROR: %s job-id erabiltzailea titulua kopiak aukerak [fitxategia]\n"
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: karaktere-jokoaren fitxategia okerra: %s\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: karaktere-jokoaren mota okerra: %s\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: letra-deskripzioaren lerroa okerra: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: testuaren norabidea okerra: %s\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: testuaren zabalera okerra: %s\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: %d errorea PAPSendData eskaera bidaltzean: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: ez da letra-tiporik aurkitu karaktere-jokoaren %s fitxategian\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: inprimagailuak ez du erantzuten\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: inprimagailuak ustekabeko EOF bidali du\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: urruneko ostalariak ez du kontrol-fitxategia onartu (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: urruneko ostalariak ez du datuen fitxategia onartu (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr "ERROR: denbora-muga gainditu da inprimagailura datuak bidaltzean\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: ezin da %d fitxategia lanari gehitu: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: ezin da %d lana bertan behera utzi: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: ezin da PDF fitxategia kopiatu"
+
+msgid "ERROR: Unable to create pipe"
+msgstr "ERROR: ezin da kanalizazioa sortu"
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: ezin da socket-a sortu"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: ezin da aldi baterako inprimatzeko konprimitutako fitxategia sortu: %"
+"s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: ezin da aldi baterako fitxategia sortu"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: ezin da pictwpstops exekutatu: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: ezin da gs programa exekutatu"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: ezin da pdftops programa exekutatu"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr "ERROR: ezin da pstops programa exekutatu"
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: ezin da pictwpstops sardetu: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: ezin da PAP eskaera lortu"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: ezin da PAP erantzuna lortu"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr ""
+"ERROR: ezin da \"%s\" - \"%s\" inprimagailuaren PPD fitxategia lortu.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: ezin da AppleTalk zona lehenetsia lortu"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: ezin da PAP erantzuna aurktitu"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: ezin da AppleTalk inprimagailurik aurkitu"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: ezin da AppleTalk helbiderik sortu"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: ezin da \"%s\" - \"%s\" ireki\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: ezin da %s ireki: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: ezin da \"%s\" titularraren fitxategia ireki: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: ezin da \"%s\" gailuaren fitxategia ireki: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: ezin da \"%s\" fitxategia ireki: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: ezin da \"%s\" fitxategia ireki: %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: ezin da \"%s\" inprimatzeko fitxategia ireki: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: ezin da %s inprimatzeko fitxategia ireki: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: ezin da %s inprimatzeko fitxategia ireki: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr "ERROR: ezin da bilbearen fitxategia ireki: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: ezin da aldi baterako konprimitutako inprimatzeko fitxategia ireki: %"
+"s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: ezin da inprimatzeko daturik irakurri"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: ezin da ataka erreserbatu"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: ezin da fitxategiko %ld posizioan kokatu: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: ezin da fitxategiko %lld posizioan kokatu: %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: ezin da LPD komandoa bidali"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: ezin da PAP eskaera bidali"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: ezin da PAPren hasierako datuak bidaltzeko eskaera bidali"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: ezin da inprimatzeko fitxategia inprimagailura bidali"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: ezin da NULL balioa bidali inprimagailura"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: ezin da pictwpstops-ren zain egon: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: ezin dira %d byte idatzi \"%s\"(e)n: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: ezin da kontrol-fitxategia idatzi"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: ezin da inprimatzeko daturik idatzi"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: ezin da inprimatzeko daturik idatzi: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr "ERROR: ezin da deskonprimitutako dokumentuaren daturik idatzi: %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: \"%s\" fitxategiaren ordena ezezaguna\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: \"%c\" karakterearen formatua ezezaguna\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: inprimatzeko \"%s\" modua ezezaguna\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: huts egin du select()-ek"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: ezin da 'stat' exekutatu inprimatzeko fitxategiarentzako"
+
+msgid "Edit Configuration File"
+msgstr "Editatu konfigurazioko fitxategia"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Titularraren amaiera"
+
+msgid "English"
+msgstr "Basque"
+
+msgid "Enter old password:"
+msgstr "Sartu pasahitz zaharra:"
+
+msgid "Enter password again:"
+msgstr "Sartu pasahitza berriro:"
+
+msgid "Enter password:"
+msgstr "Sartu pasahitza:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Idatzi zure erabiltzaile-izena eta pasahitza, edo supererabiltzailearen "
+"izena eta pasahitza, orrialde honetara sarbidetzeko. Kerberos "
+"autentifikazioa erabiltzen ari bazara, ziurtatu zaitez baliozko Kerberos "
+"txartela duzula."
+
+msgid "Envelope Feed"
+msgstr "Gutunazalen iturria"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Erroreen politika"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "10 etiketez behin"
+
+msgid "Every 2 Labels"
+msgstr "2 etiketez behin"
+
+msgid "Every 3 Labels"
+msgstr "3 etiketez behin"
+
+msgid "Every 4 Labels"
+msgstr "4 etiketez behin"
+
+msgid "Every 5 Labels"
+msgstr "5 etiketez behin"
+
+msgid "Every 6 Labels"
+msgstr "6 etiketez behin"
+
+msgid "Every 7 Labels"
+msgstr "7 etiketez behin"
+
+msgid "Every 8 Labels"
+msgstr "8 etiketez behin"
+
+msgid "Every 9 Labels"
+msgstr "9 etiketez behin"
+
+msgid "Every Label"
+msgstr "Etiketa bakoitzeko"
+
+msgid "Expectation Failed"
+msgstr "Espero zenak huts egin du"
+
+msgid "Export Printers to Samba"
+msgstr "Esportatu inprimagailuak Samba-ra"
+
+msgid "FAIL\n"
+msgstr "HUTSEGITEA\n"
+
+msgid "File Folder"
+msgstr "Fitxategien karpeta"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Fitxategien karpeta - 9/16 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"Fitxategiaren gailuaren URIak desgaitu egin dira. Gaitzeko, ikus FileDevice "
+"direktiba \"%s/cupsd.conf\" fitxategian."
+
+msgid "Folio"
+msgstr "Folioa"
+
+msgid "Forbidden"
+msgstr "Debekatua"
+
+msgid "General"
+msgstr "Orokorra"
+
+msgid "Generic"
+msgstr "Generikoa"
+
+msgid "German FanFold"
+msgstr "FanFold alemana"
+
+msgid "German FanFold Legal"
+msgstr "FanFold Legal alemana"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU definitu gabeko luzera darabil"
+
+msgid "Glossy Paper"
+msgstr "Paper satinatua"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Gris-eskala"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Esekitako karpeta"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Esekitako karpeta - 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk desgaituta sistemako hobespenetan\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk desgaituta sistemako hobespenetan.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: inprimatzeko lana bertan behera uzten...\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: inprimagailura konektatuta...\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: inprimagailura konektatzen...\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: kontrol-fitxategia ongi bidali da\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr "INFO: inprimatzeko datuak kopiatzen...\n"
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: datuen fitxategia ongi bidali da\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr "INFO: %d orrialdea amaituta...\n"
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: %d orrialdeari formatua ematen...\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: irudiaren fitxategia kargatzen...\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: inprimagailua bilatzen...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: konexioa irekitzen\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr ""
+"INFO: inprimatzeko fitxategia bidalita, inprimagailuak amaitu zain...\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: inprimagailua lanpetuta. 10 segundotan saiatu da berriro...\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: inprimagailua lanpetuta. 30 segundotan saiatu da berriro...\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: inprimagailua lanpetuta. 5 segundotan saiatu da berriro...\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr ""
+"INFO: inprimagailuak ez du IPP/%d.%d onartzen. Honekin saiatzen: IPP/1.0...\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr ""
+"INFO: inprimagailua lanpetuta dago. 5 segundotan saiatu da berriro...\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: inprimagailua unean lineaz kanpo dago.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: inprimagailua unean linean dago.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: inprimagailua orain linean dago.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: inprimagailua lineaz kanpo dago.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr ""
+"INFO: inprimagailua ez dago konektatuta. 30 segundo barru saiatuko da "
+"berriro...\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: %d orrialdea inprimatzen. %% %d osatuta...\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: %d orrialdea inprimatzen...\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: inprimatzeko prest.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: kontrol-fitxategia bidaltzen (%lu byte)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: kontrol-fitxategia bidaltzen (%u byte)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: datuen fitxategia bidaltzen\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: datuen fitxategia bidaltzen (%ld byte)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: datuen fitxategia bidaltzen (%lld byte)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: inprimatzeko datuak bidaltzen...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: inprimatzeko fitxategia bidalita, %ld byte...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: inprimatzeko fitxategia bidalita, %lld byte...\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: LPR lana ilaran jartzen. %% %.0f osatuta...\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr "INFO: %d orrialdea hasten...\n"
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: ezin da inprimagailuarekin kontaktatu, klaseko hurrengo inprimagailuan "
+"ilaratzen...\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: \"%s\" AppleTalk zona lehenetsia erabiltzen\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: lana osatzeko itxoiten...\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: inprimagailua erabilgarri egon arte itxoiten...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "ISO B4 gutunazala"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (handiagoa)"
+
+msgid "ISO B5 Envelope"
+msgstr "ISO B5 gutunazala"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "ISO B6 gutunazala"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "Kontrol-karaktere ilegala"
+
+msgid "Illegal main keyword string"
+msgstr "Gako-hitzaren kate nagusia ilegala"
+
+msgid "Illegal option keyword string"
+msgstr "Aukeraren gako-hitzaren katea ilegala"
+
+msgid "Illegal translation string"
+msgstr "Itzulpenaren katea ilegala"
+
+msgid "Illegal whitespace character"
+msgstr "Zuriunea karakterea ilegala"
+
+msgid "Installable Options"
+msgstr "Aukera instalagarriak"
+
+msgid "Installed"
+msgstr "Instalatuta"
+
+msgid "IntelliBar Label Printer"
+msgstr "IntelliBar etiketen inprimagailua"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr "Zerbitzariaren barneko errorea"
+
+msgid "Internal error"
+msgstr "Barneko errorea"
+
+msgid "Internet Postage 2-Part"
+msgstr "Interneteko posta 2. zatia"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Interneteko posta 2. zatia - 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "Interneteko posta 3. zatia"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Interneteko posta 3. zatia - 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "Interneten inPrimatzeko Protokoloa"
+
+msgid "Invite Envelope"
+msgstr "Gobidapeneko gutunazala"
+
+msgid "Italian Envelope"
+msgstr "Gutunazal italiarra"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "%d. lana jadanik abortatuta dago, ezin da bertan behera utzi."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr ""
+"%d. lana jadanik bertan behera utzita dago, ezin da bertan behera utzi."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "%d. lana jadanik burututa dago, ezin da bertan behera utzi."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "Lana burututa"
+
+msgid "Job Created"
+msgstr "Lana sortuta"
+
+msgid "Job ID: "
+msgstr "Lanaren IDa: "
+
+msgid "Job Options Changed"
+msgstr "Lanaren aukerak aldatuta"
+
+msgid "Job Stopped"
+msgstr "Lana geldituta"
+
+msgid "Job UUID: "
+msgstr "Lanaren UUIDa:"
+
+msgid "Job is completed and cannot be changed."
+msgstr "Lana burututa dago eta ezin da aldatu."
+
+msgid "Job operation failed:"
+msgstr "Lanaren eragiketak huts egin du:"
+
+msgid "Job state cannot be changed."
+msgstr "Lanaren egoera ezin da aldatu."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "Lanak"
+
+msgid "Kaku2 Envelope"
+msgstr "Kaku2 gutunazala"
+
+msgid "Kaku3 Envelope"
+msgstr "Kaku3 gutunazala"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "LPD/LPR ostalaria edo inprimagailua"
+
+msgid "Label Printer"
+msgstr "Etiketen inprimagailua"
+
+msgid "Label Top"
+msgstr "Etiketaren goian"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Helbide luzea"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Helbide luzea - 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet PCL 4/5 serieak"
+
+msgid "Light"
+msgstr "Argia"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Lerroa baimendutako gehienezkoa (255 karaktere) baino luzeagoa"
+
+msgid "List Available Printers"
+msgstr "Inprimagailu erabilgarrien zerrenda"
+
+msgid "Location: "
+msgstr "Kokalekua: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "Ertz-luzea (bertikala)"
+
+msgid "Make and Model: "
+msgstr "Marka eta modeloa: "
+
+msgid "Manual Feed"
+msgstr "Eskuzko iturria"
+
+msgid "Media Dimensions: "
+msgstr "Paperaren dimentsioak: "
+
+msgid "Media Limits: "
+msgstr "Paperaren mugak: "
+
+msgid "Media Name: "
+msgstr "Paperaren izena: "
+
+msgid "Media Size"
+msgstr "Paperaren tamaina"
+
+msgid "Media Source"
+msgstr "Paperaren iturria"
+
+msgid "Media Tracking"
+msgstr "Paperaren jarraipena"
+
+msgid "Media Type"
+msgstr "Paper mota"
+
+msgid "Medium"
+msgstr "Euskarria"
+
+msgid "Memory allocation error"
+msgstr "Errorea memoria esleitzean"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "PPD-Adobe-4.x goiburukoa falta da"
+
+msgid "Missing asterisk in column 1"
+msgstr "Izartxoa falta da 1. zutabean"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "Balioaren katea falta da"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Modeloa: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "Aldatu klasea"
+
+msgid "Modify Printer"
+msgstr "Aldatu inprimagailua"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Monarch gutunazala"
+
+msgid "Move All Jobs"
+msgstr "Aldatu lan guztiak lekuz"
+
+msgid "Move Job"
+msgstr "Aldatu lana lekuz"
+
+msgid "Moved Permanently"
+msgstr "Betirako lekuz aldatuta"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: inptimatzeko fitxategia onartuta - lanaren IDa: %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: inptimatzeko fitxategia onartuta - lanaren IDa: ezezaguna.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "PPD fitxategiaren erakusle NULUA"
+
+msgid "Name OID uses indefinite length"
+msgstr "Izenaren OIDak definitu gabeko luzera darabil"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Inoiz ere ez"
+
+msgid "New Stylus Color Series"
+msgstr "Stylus Color serie berriak"
+
+msgid "New Stylus Photo Series"
+msgstr "Stylus Photo serie berriak"
+
+msgid "No"
+msgstr "Ez"
+
+msgid "No Content"
+msgstr "Edukirik ez"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "'VarBind SEQUENCE'-rik ez"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "Ez dago konexio aktiborik"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "Ez dago komunitatearen izenik"
+
+msgid "No default printer"
+msgstr "Ez dago inprimagailu lehenetsirik"
+
+msgid "No destinations added."
+msgstr "Ez da helbururik gehitu."
+
+msgid "No error-index"
+msgstr "Ez dago error-index parametroa"
+
+msgid "No error-status"
+msgstr "Ez dago error-status parametroa"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "Ez dago izenaren OIDrik"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "Ez dago request-id"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "Ez da harpidetzarik aurkitu."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "Ez dago 'variable-bindings SEQUENCE'-rik"
+
+msgid "No version number"
+msgstr "Ez dago bertsioaren zenbakirik"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "Ez da jarraia (markaren detekzioa)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "Ez da jarraia (web detekzioa)"
+
+msgid "Normal"
+msgstr "Arrunta"
+
+msgid "Not Found"
+msgstr "Ez da aurkitu"
+
+msgid "Not Implemented"
+msgstr "Ez dago garatuta"
+
+msgid "Not Installed"
+msgstr "Ez dago instalatuta"
+
+msgid "Not Modified"
+msgstr "Ez dago aldatuta"
+
+msgid "Not Supported"
+msgstr "EZ dago onartuta"
+
+msgid "Not allowed to print."
+msgstr "Inprimatzea ez dago baimenduta."
+
+msgid "Note"
+msgstr "Oharra"
+
+msgid "OK"
+msgstr "Ados"
+
+msgid "Off (1-Sided)"
+msgstr "Desaktibatuta (1 aldea)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Lineako laguntza"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "Huts egin du %s irekitzean: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup aurreko CloseGroup-rik gabe"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI aurreko CloseUI/JCLCloseUI-rik gabe"
+
+msgid "Operation Policy"
+msgstr "Eragiketaren politika"
+
+msgid "Options Installed"
+msgstr "Instalatutako aukerak"
+
+msgid "Options: "
+msgstr "Aukerak: "
+
+msgid "Output Mode"
+msgstr "Irteeraren modua"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "%s inprimagailuarentzako irteera %s(e)ra bidalita\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr ""
+"%s inprimagailuarentzako irteera urruneko %s inprimagailura bidalita %s(e)n\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "%s/%s inprimagailuarentzako irteera %s(e)ra bidalita\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr ""
+"%s/%s inprimagailuarentzako irteera urruneko %s inprimagailura bidalita %s(e)"
+"n\n"
+
+msgid "PASS\n"
+msgstr "BALIOZKOA\n"
+
+msgid "PCL Laser Printer"
+msgstr "PCL laser inprimagailua"
+
+msgid "PRC1 Envelope"
+msgstr "PRC1 gutunazala"
+
+msgid "PRC10 Envelope"
+msgstr "PRC10 gutunazala"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "PRC2 gutunazala"
+
+msgid "PRC3 Envelope"
+msgstr "PRC3 gutunazala"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (handiagoa)"
+
+msgid "PRC4 Envelope"
+msgstr "PRC4 gutunazala"
+
+msgid "PRC5 Envelope"
+msgstr "PRC5 gutunazala"
+
+msgid "PRC6 Envelope"
+msgstr "PRC6 gutunazala"
+
+msgid "PRC7 Envelope"
+msgstr "PRC7 gutunazala"
+
+msgid "PRC8 Envelope"
+msgstr "PRC8 gutunazala"
+
+msgid "PRC9 Envelope"
+msgstr "PRC9 gutunazala"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "Paketeak ez dauka Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "Paketeak ez da SEQUENCErekin hasten"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "%s(r)en pasahitza %s(e)n?"
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "%s(r)en pasahitza behar da %s(e)n SAMBA bidez sarbidetzeko: "
+
+msgid "Pause Class"
+msgstr "Pausatu klasea"
+
+msgid "Pause Printer"
+msgstr "Pausatu inprimagailua"
+
+msgid "Peel-Off"
+msgstr "Altxatu"
+
+msgid "Personal Envelope"
+msgstr "Gutunazal pertsonala"
+
+msgid "Photo"
+msgstr "Argazkia"
+
+msgid "Photo Labels"
+msgstr "Argakien etiketak"
+
+msgid "Plain Paper"
+msgstr "Paper soila"
+
+msgid "Policies"
+msgstr "Politikak"
+
+msgid "Port Monitor"
+msgstr "Atakaren monitorea"
+
+msgid "PostScript Printer"
+msgstr "PostScript inprimagailua"
+
+msgid "Postcard"
+msgstr "Postala"
+
+msgid "Print Density"
+msgstr "Inprimatze-dentsitatea"
+
+msgid "Print Job:"
+msgstr "Inprimatzeko lana:"
+
+msgid "Print Mode"
+msgstr "Inprimatze modua"
+
+msgid "Print Rate"
+msgstr "Inprimatze-emaria"
+
+msgid "Print Self-Test Page"
+msgstr "Inprimatu auto-probako orrialdea"
+
+msgid "Print Speed"
+msgstr "Inprimatzeko abiadura"
+
+msgid "Print Test Page"
+msgstr "Inprimatu probako orrialdea"
+
+msgid "Print and Cut"
+msgstr "Inprimatu eta ebaki"
+
+msgid "Print and Tear"
+msgstr "Inprimatu eta altxatu"
+
+msgid "Printed For: "
+msgstr "Honentzako inprimatuta: "
+
+msgid "Printed From: "
+msgstr "Hemendik inprimatuta: "
+
+msgid "Printed On: "
+msgstr "Inprimatze-data: "
+
+msgid "Printer Added"
+msgstr "Inprimagailua gehituta"
+
+msgid "Printer Default"
+msgstr "Inprimagailu lehenetsia"
+
+msgid "Printer Deleted"
+msgstr "Inprimagailua ezabatuta"
+
+msgid "Printer Modified"
+msgstr "Inprimagailua aldatuta"
+
+msgid "Printer Name: "
+msgstr "Inprimagailuaren izena: "
+
+msgid "Printer Paused"
+msgstr "Inprimagailua pausatuta"
+
+msgid "Printer Settings"
+msgstr "Inprimagailuaren ezarpenak"
+
+msgid "Printer:"
+msgstr "Inprimagailua:"
+
+msgid "Printers"
+msgstr "Inprimagailuak"
+
+msgid "Purge Jobs"
+msgstr "Garbitu lanak"
+
+msgid "Quarto"
+msgstr "Laurdena"
+
+msgid "Quota limit reached."
+msgstr "Kuotaren mugara iritsita."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr ""
+"Errenk. Jabea Lana Fitxategiak Tamaina osoa\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"Errenk. Jabea Lehent. Lana Fitxategiak Tamaina osoa\n"
+
+msgid "Reject Jobs"
+msgstr "Ukatu lanak"
+
+msgid "Reprint After Error"
+msgstr "Inprimatu berriro erroreen ostean"
+
+msgid "Request Entity Too Large"
+msgstr "Eskaeraren entitatea luzeegia"
+
+msgid "Resolution"
+msgstr "Bereizmena"
+
+msgid "Resume Class"
+msgstr "Jarraitu klasea"
+
+msgid "Resume Printer"
+msgstr "Jarraitu inprimagailua"
+
+msgid "Return Address"
+msgstr "Itzulerako helbidea"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Itzulerako helbidea - 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "Birboninatu"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Komandoa exekutaten: %s %s -N -A %s -c '%s'\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCEk definitu gabeko luzera darabil"
+
+msgid "See Other"
+msgstr "Ikusi besteak"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "Serieko %d. ataka"
+
+msgid "Server Restarted"
+msgstr "Zerbitzaria berrabiarazita"
+
+msgid "Server Security Auditing"
+msgstr "Zerbitzariko segurtasun auditoretza"
+
+msgid "Server Started"
+msgstr "Zerbitzaria abiarazita"
+
+msgid "Server Stopped"
+msgstr "Zerbitzaria geldituta"
+
+msgid "Service Unavailable"
+msgstr "Zerbitzaria ez dago eskuragarri"
+
+msgid "Set Allowed Users"
+msgstr "Ezarri baimendutako erabiltzaileak"
+
+msgid "Set As Server Default"
+msgstr "Ezarri zerbitzari lehenetsi gisa"
+
+msgid "Set Class Options"
+msgstr "Ezarri klasearen aukerak"
+
+msgid "Set Printer Options"
+msgstr "Ezarri inprimagailuaren aukerak"
+
+msgid "Set Publishing"
+msgstr "Argitaratu"
+
+msgid "Shipping Address"
+msgstr "Bidaltzeko helbidea"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "Bidaltzeko helbidea - 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "Ertz laburra (horizontala)"
+
+msgid "Special Paper"
+msgstr "Paper berezia"
+
+msgid "Standard"
+msgstr "Estandarra"
+
+msgid "Starting Banner"
+msgstr "Hasierako titularra"
+
+msgid "Statement"
+msgstr "Instrukzioa"
+
+msgid "Stylus Color Series"
+msgstr "Stylus Color serieak"
+
+msgid "Stylus Photo Series"
+msgstr "Stylus Photo serieak"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "Protokoloak aldatzen"
+
+msgid "Tabloid"
+msgstr "Tabloidea"
+
+msgid "Tabloid (Oversize)"
+msgstr "Tabloidea (handiagoa)"
+
+msgid "Tear"
+msgstr "Altxatu"
+
+msgid "Tear-Off"
+msgstr "Altxatu"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Altxatze-posizioaren doiketa"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "Ezin izan da \"%s\" PPD fitxategia aurkitu."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "Ezin izan da \"%s\" PPD fitxategia ireki: %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Klasearen izenak inprimagarriak diren 127 karaktere sooilik eduki ditzake, "
+"eta ezin du zuriune, barrak (/) edo traolaren (#) ikurrik eduki."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr "notify-lease-duration atributua ezin da erabili lanen harpidetzekin."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Inprimagailuaren izenak inprimagarriak diren 127 karaktere sooilik eduki "
+"ditzake, eta ezin du zuriune, barrak (/) edo traolaren (#) ikurrik eduki."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "Inprimagailua edo klasea ez da aurkitu."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "\"%s\" printer-uri atributuak baliogabeko karaktereak ditu."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr ""
+"printer-uri \"ipp://OSTALARIIZENA/classes/KLASEIZENA\" erakoa izan behar du."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+"printer-uri \"ipp://OSTALARIIZENA/printers/INPRIMAGAILUIZENA\" erakoa izan "
+"behar du."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"Harpidetzaren izenak inprimagarriak ezin du zuriune, barrak (/), galdera "
+"ikurra (?) edo traolaren (#) ikurrik eduki."
+
+msgid "There are too many subscriptions."
+msgstr "Harpidetza gehiegi daude."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "Transferentzia termikoaren euskarria"
+
+msgid "Title: "
+msgstr "Titulua: "
+
+msgid "Too many active jobs."
+msgstr "Lan aktibo gehiegi."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "Gardentasuna"
+
+msgid "Tray"
+msgstr "Erretilua"
+
+msgid "Tray 1"
+msgstr "1. erretilua"
+
+msgid "Tray 2"
+msgstr "2. erretilua"
+
+msgid "Tray 3"
+msgstr "3. erretilua"
+
+msgid "Tray 4"
+msgstr "4. erretilua"
+
+msgid "URI Too Long"
+msgstr "URIa luzeegia"
+
+msgid "US Executive"
+msgstr "US exekutiboa"
+
+msgid "US Fanfold"
+msgstr "US Fanfold"
+
+msgid "US Ledger"
+msgstr "US Ledger"
+
+msgid "US Legal"
+msgstr "US legala"
+
+msgid "US Legal (Oversize)"
+msgstr "US legala (handiagoa)"
+
+msgid "US Letter"
+msgstr "US gutuna"
+
+msgid "US Letter (Oversize)"
+msgstr "US gutuna (handiagoa)"
+
+msgid "US Letter (Small)"
+msgstr "US gutuna (txikia)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "USB zerieko %d. ataka"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "Ezin da cupsd.conf fitxategia atzitu:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "Ezin da RSS harpidetza gehitu:"
+
+msgid "Unable to add class:"
+msgstr "Ezin da klasea gehitu:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "Ezin da inprimagailua gehitu:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "Ezin da RSS harpidetza bertan behera utzi:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "Ezin da printer-is-shared atributua aldatu:"
+
+msgid "Unable to change printer:"
+msgstr "Ezin da inprimagailua aldatu:"
+
+msgid "Unable to change server settings:"
+msgstr "Ezin dira zerbitzariaren ezarpenak aldatu:"
+
+msgid "Unable to connect to host."
+msgstr "Ezin da ostalariarekin konektatu."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "Ezin da aldi baterako fitxategia sortu:"
+
+msgid "Unable to delete class:"
+msgstr "Ezin da klasea ezabatu:"
+
+msgid "Unable to delete printer:"
+msgstr "Ezin da inprimagailua ezabatu:"
+
+msgid "Unable to do maintenance command:"
+msgstr "Ezin da mantenimenduko komandoa landu:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "Ezin da klaseen zerrenda lortu:"
+
+msgid "Unable to get class status:"
+msgstr "Ezin da klasearen egoera lortu:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "Ezin da inprimagailuen kontrolatzaileen zerrenda lortu:"
+
+msgid "Unable to get printer attributes:"
+msgstr "Ezin dira inprimagailuaren atributuak lortu:"
+
+msgid "Unable to get printer list:"
+msgstr "Ezin da inprimagailuen zerrenda lortu:"
+
+msgid "Unable to get printer status:"
+msgstr "Ezin da inprimagailuaren egoera lortu:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "Ezin da klasea eraldatu:"
+
+msgid "Unable to modify printer:"
+msgstr "Ezin da inprimagailua eraldatu:"
+
+msgid "Unable to move job"
+msgstr "Ezin da lana lekuz aldatu"
+
+msgid "Unable to move jobs"
+msgstr "Ezin dira lanak lekuz aldatu"
+
+msgid "Unable to open PPD file"
+msgstr "Ezin da PPD fitxategia ireki"
+
+msgid "Unable to open PPD file:"
+msgstr "Ezin da PPD fitxategia ireki:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "Ezin da cupsd.conf fitxategia ireki:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "Ezin da probako orrialdea inprimatu:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "Ezin da \"%s\" exekutatu: %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "Ezin dira aukerak ezarri:"
+
+msgid "Unable to set server default:"
+msgstr "Ezain da zerbitzari lehenetsia ezarri:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "Ezin da cupsd.conf fitxategia igo:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "Autorizaziorik ez"
+
+msgid "Units"
+msgstr "Unitateak"
+
+msgid "Unknown"
+msgstr "Ezezaguna"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "\"%s\" printer-error-policy ezezaguna."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "\"%s\" printer-op-policy ezezaguna."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Onartu gabeko balio mota"
+
+msgid "Upgrade Required"
+msgstr "Eguneratu egin behar da"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Erabilera:\n"
+"\n"
+" lpadmin [-h zerbitzaria] -d helburua\n"
+" lpadmin [-h zerbitzaria] -x helburua\n"
+" lpadmin [-h zerbitzaria] -p inprimagailua [-c klasea_gehitzeko] [-i "
+"interfazea] [-m modeloa]\n"
+" [-r klasea_kentzeko] [-v gailua] [-D deskripzioa]\n"
+" [-P ppd-fitxategia] [-o izena=balioa]\n"
+" [-u allow:erabiltzailea,erabiltzailea] [-u deny:"
+"erabiltzailea,erabiltzailea]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr ""
+"Erabilera: %s lana erabiltzailea titulua kopiak aukerak [fitxategi-izena]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr ""
+"Erabilera: %s lanaren_IDa erabiltzailea titulua kopiak aukerak [fitxategi-"
+"izena]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr ""
+"Erabilera: %s lanaren_IDa erabiltzailea titulua kopiak aukerak fitxategia\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+"Erabilera: convert [ Aukerak ]\n"
+"\n"
+"Aukerak:\n"
+" -e Erabili PPD fitxategiko iragazki bakoitza\n"
+" -f fitxategi-izena Ezarri fitxategia bihurtzeko (bestela stdin)\n"
+" -o fitxategi-izena Ezarri fitxategia sortzeko (bestela stdout)\n"
+" -i mime/mota Ezarri sarrerako MIME mota (bestela mota "
+"automatikoa)\n"
+" -j mime/mota Ezarri irteerako MIME mota (bestela application/pdf)\n"
+" -P fitxategi-izena.ppd Ezarri PPD fitxategia\n"
+" -a 'izena=balioa ...' Ezarri aukerak\n"
+" -U erabiltzaile-izena Ezarri lanaren erabiltzaile-izena\n"
+" -J titulua Ezarri titulua\n"
+" -c kopiak Ezarri kopia kopurua\n"
+" -u Kendu PPD fitxategia amaitutakoan\n"
+" -D Kendu sarrerako fitxategia amaitutakoan\n"
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Erabilera: cupsaddsmb [aukerak] inprimagailua1 ... inprimagailuaN\n"
+" cupsaddsmb [aukerak] -a\n"
+"\n"
+"Aukerak:\n"
+" -E Enkriptatu zerbitzarirako konexioa\n"
+" -H samba-zerbitzaria Erabili izendatutako SAMBA zerbitzaria\n"
+" -U samba-erabiltzailea Autentifikatu izendatutako SAMBAko erabiltzailea "
+"erabiliz\n"
+" -a Esportatu inprimagailu guztiak\n"
+" -h cups-zerbitzaria Erabili izendatutako CUPS zerbitzaria\n"
+" -v Hitzez hitz (erakutsi komandoak)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Erabilera: cupsctl [aukerak] [param=balioa ... paramN=balioaN]\n"
+"\n"
+"Aukerak:\n"
+"\n"
+" -E Gaitu enkriptatzea\n"
+" -U erabiltzaile-izena Zehaztu erabiltzaile-izena\n"
+" -h zerbitzaria[:ataka] Zehaztu zerbitzariaren helbidea\n"
+"\n"
+" --[no-]debug-logging Txandakatu arazketaren erregistroak aktibatzea/"
+"desaktibatzea\n"
+" --[no-]remote-admin Txandakatu urruneko administrazioa aktibatzea/"
+"desaktibatzea\n"
+" --[no-]remote-any Baimendu/Saihestu atzitzea Internetetik\n"
+" --[no-]remote-printers Erakutsi/Ezkutatu urruneko inprimagailuak\n"
+" --[no-]share-printers Baimendu/Saihestu inprimagailua partekatzea\n"
+" --[no-]user-cancel-any Baimendu/Saihestu erabiltzaileek edozer lan "
+"bertan behera uztea\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Erabilera: cupsd [-c konfigurazio-fitxategia] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c konfigurazio-fitxategia Kargatu konfigurazioko beste fitxategi bat\n"
+"-f Exekutatu aurreko planoan\n"
+"-F Exekutatu aurreko planoan baina bereiztuta\n"
+"-h Erakutsi erabileraren mezu hau\n"
+"-l Exekutatu cupsd launchd(8)-etik\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+"Erabilera: cupsfilter -m mime/mota [ aukerak ] fitxategi-izena\n"
+"\n"
+"Aukerak:\n"
+"\n"
+" -c cupsd.conf Ezarri cupsd.conf fitxategia erabiltzeko\n"
+" -e Erabili PPD fitxategiko iragazki bakoitza\n"
+" -j lanaren-id[,N] Iragazi N fitxategia zehaztutako lanetik (lehenetsia "
+"1. fitxategia da)\n"
+" -n kopiak Ezarri kopia kopurua\n"
+" -o izena=balioa Ezarri aukerak\n"
+" -p fitxategi-izena.ppd Ezarri PPD fitxategia\n"
+" -t titulua Ezarri titulua\n"
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Erabilera: cupstestdsc [aukerak] fitxategi-izena.ps [... fitxategi-izena."
+"ps]\n"
+" cupstestdsc [aukerak] -\n"
+"\n"
+"Aukerak:\n"
+"\n"
+" -h Erakutsi programaren erabilera\n"
+"\n"
+" Oharra: programa honek DSC iruzkinak soilik balidatzen ditu, ez "
+"PostScript bera.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Erabilera: lpmove lana/iturria helburua\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Erabilera: lpoptions [-h zerbitzaria] [-E] -d inprimagailua\n"
+" lpoptions [-h zerbitzaria] [-E] [-p inprimagailua] -l\n"
+" lpoptions [-h zerbitzaria] [-E] -p inprimagailua -o aukera"
+"[=balioa] ...\n"
+" lpoptions [-h zerbitzaria] [-E] -x inprimagailua\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Erabilera: lppasswd [-g talde-izena]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Erabilera: lppasswd [-g talde-izena] [erabiltzaile-izena]\n"
+" lppasswd [-g talde-izena] -a [erabiltzaile-izena]\n"
+" lppasswd [-g talde-izena] -x [erabiltzaile-izena]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Erabilera: lpq [-P helb] [-U erab-izena] [-h ostalari-izena[:ataka]] [-l] "
+"[+barrutia]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Erabilera: ppdc [aukerak] fitxategia.drv [ ... fitxategiaN.drv ]\n"
+"\n"
+"Aukerak:\n"
+" -D izena=balioa Ezarri izendatutako aldagaia balioarekin.\n"
+" -I include-dir Gehitu include direktorioa bilaketako bide-izenari.\n"
+" -c katalogoa.po Kargatu zehaztutako mezuen katalogoa.\n"
+" -d irteerako-dir Zehaztu irteerako direktorioa.\n"
+" -l hizk[,hizk,...] Zehaztu irteerako hizkuntzak (lokalak).\n"
+" -m Erabili ModelName balioa fitxategi-izen gisa.\n"
+" -t Probatu PPDak, haiek sortu ordez.\n"
+" -v Hitzez hitz (zenbat eta 'v' gehiago, xehetasun "
+"gehiago).\n"
+" -z Konprimitu PPD fitxategiak GNU zip erabiliz.\n"
+" --cr Amaitu lerroak CRrekin (Mac OS 9).\n"
+" --crlf Amaitu lerroak CR + LFrekin (Windows).\n"
+" --lf Amaitu lerroak LFrekin (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"Erabilera: ppdhtml [aukerak] fitxategia.drv >fitxategia.html\n"
+" -D izena=balioa Ezarri izendatutako aldagaia balioarekin.\n"
+"Aukerak:\n"
+" -I include-dir Gehitu include direktorioa bilaketako bide-izenari.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Erabilera: ppdi [aukerak] fitxategia.ppd [ ... fitxategiaN.ppd ]\n"
+"Aukerak:\n"
+" -I include-dir\n"
+" -o fitxategia.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Erabilera: ppdmerge [aukerak] fitxategia.ppd [ ... fitxategiaN.ppd ]\n"
+"Aukerak:\n"
+" -o fitxategia.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"Erabilera: ppdpo [aukerak] -o fitxategia.po fitxategia.drv [ ... fitxategiaN."
+"drv ]\n"
+"Aukerak:\n"
+" -D izena=balioa Ezarri izendatutako aldagaia balioarekin.\n"
+" -I include-dir Gehitu include direktorioa bilaketako bide-izenari.\n"
+" -v Hitzez hitz (zenbat eta 'v' gehiago, xehetasun "
+"gehiago).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Erabilera: snmp [ostalari-edo-ip-helbidea]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Balioak definitu gabeko luzera darabil"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind-ek definitu gabeko luzera darabil"
+
+msgid "Version uses indefinite length"
+msgstr "Bertsioak definitu gabeko luzera darabil"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: aurkitutako aurreneko %d inprimagailu gehitzen"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: \"%s\" waitof aukeran boolear bat espero zen\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: inprimagailuak ez du erantzuten\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: inprimagailuak ustekabeko EOF bidali du\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: ezin da \"%s:%s\" ireki: %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: ezin da PAP egoeraren eskaera bidali"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: ustekabeko PAP paketea %d motakoa\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: %d motako PAP pakete ezezaguna\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: zenbakia espero en \"%s\" egoeraren aukeran\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Bai"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"Orrialde hau honako URLan atxitu deakezu: <A HREF=\"https://%s:%d%s"
+"\">https://%s:%d%s</A>."
+
+msgid "You4 Envelope"
+msgstr "You4 gutunazala"
+
+msgid "ZPL Label Printer"
+msgstr "ZPL etiketen inprimagailua"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "abortatuta"
+
+msgid "canceled"
+msgstr "bertan behera utzita"
+
+msgid "completed"
+msgstr "burututa"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr "convert: erabili -f aukera bihurtzea nahi den fitxategia zehazteko.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "cups-deviced programak huts egin du exekutatzean."
+
+msgid "cups-driverd failed to execute."
+msgstr "cups-driverd programak huts egin du exekutatzean."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr ""
+"cupsaddsmb: ez dago PPD fitxategirik \"%s\" inprimagailuarentzako: %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: ezin da zerbitzariarekin konektatu: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr ""
+"cupsd: ez da launchd(8) euskarriarekin konpilatu. Modu arruntean "
+"exekutatzen.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: ezin da lanaren fitxategia lortu: %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd: -q aukera ez da bateragarria -v aukerarekin.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd: -v aukera ez da bateragarria -q aukerarekin.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "%s/%s(r)en gailua: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "%s(r)en gailua: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "'error-index'-ek definitu gabeko luzera darabil"
+
+msgid "error-status uses indefinite length"
+msgstr "'error-status'-ek definitu gabeko luzera darabil"
+
+msgid "held"
+msgstr "eutsita"
+
+msgid "help\t\tget help on commands\n"
+msgstr "help\t\tkomandoei buruzko laguntza eskaintzen du\n"
+
+msgid "idle"
+msgstr "inaktibo"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: %s inprimagailua jadanik %s klasearen kidea da.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: %s inprimagailua ez da %s klaseko kidea.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: ezin da zerbitzariarekin konektatu: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: ezin da \"%s\" PPD fitxategia ireki: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: ezin da \"%s\" fitxategia ireki: %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: ezin da zerbitzariarekin konektatu: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: ezin da inprimagailua edo instantzia gehitu: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: ezin da PPD fitxategia lortu %s inprimagailuarentzako: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: pasahitza ukatu da.\n"
+"Zure pasahitzak gutxiene 6 karaktere izan behar ditu, ezin du\n"
+"zure erabiltzaile-izenik eduki, eta gutxienez hizki bat eta zenbaki bat "
+"eduki behar du.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: ezin da pasahitzaren katea kopiatu: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: ezin da pasahitzen fitxategia ireki: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: ezin da pasahitzen fitxategian idatzi: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr ""
+"lppasswd: huts egin du pasahitzen fitxategi zaharraren babeskopia egitean: %"
+"s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: huts egin du pasahitzen fitxategia izenez aldatzean: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: \"%s\" erabiltzailea eta \"%s\" taldea ez dira existitzen.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "%s klasearen kideak:\n"
+
+msgid "no entries\n"
+msgstr "sarrerarik ez\n"
+
+msgid "no system default destination\n"
+msgstr "ez dago sistemako helburu lehenetsirik.\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "zain"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: \"%s\" include direktorioa gehitzen...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: UIaren testua gehitzen/eguneratzen %s(e)tik...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: okerreko balio boolearra (%s) %d lerroan of(e)n %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: okerreko aldagaien ordezkaketa ($%c) %d lerroan %s(e)n.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: balio boolearra espero zen %d lerroan %s(e)n.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: hautaketaren kodea espero zen %d lerroan %s(e)n.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: hautaketaren izena/tesua espero zen %d lerroan %s(e)n.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: kontrolatzailearen \"%s\" datu-fitxategia kargatzen...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: \"%s\" lokalaren mezuak kargatzen...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: mezuak \"%s\"(e)tik kargatzen...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: ezin da \"%s\" PPD fitxategia sortu: %s.\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: ezin da %s irteerako direktorioa sortu: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: ezin dira irteerako kanalizazioak sortu: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: ezin da cupstestppd exekutatu: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: ezin da lokalizazioa aurkitu \"%s\"(r)entzako: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: ezin da \"%s\" lokalizazioaren fitxategia kargatu: %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: definitu gabeko aldagaia (%s) %d lerroan %s(e)n.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: %s inprimatzen...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: PPD fitxategiak \"%s\" direktorioan idazten...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: %s PPD fitxategiari ezikusi egiten...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: ezin da %s(r)en babeskopia %s(e)n egin: %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "printer %s desgaituta %s ostean\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "%s inprimagailua inaktibo dago. Gaituta %s ostetik.\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr ""
+"%s inprimagailua orain %s-%d inprimatzen ari da. Gaituta %s ostetik.\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "%s/%s inprimagailua desgaituta %s ostetik\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "%s/%s inprimagailua inaktibo dago. Gaituta %s ostetik.\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr ""
+"%s/%s inprimagailua orain %s-%d inprimatzen ari da. Gaituta %s ostetik.\n"
+
+msgid "processing"
+msgstr "prozesatzen"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "eskaeraren IDa %s-%d da (%d fitxategi)\n"
+
+msgid "request-id uses indefinite length"
+msgstr "'request-id'-ek definitu gabeko luzera darabil"
+
+msgid "scheduler is not running\n"
+msgstr "antolatzailea ez da exekutatzen ari.\n"
+
+msgid "scheduler is running\n"
+msgstr "antolatzailea exekutatzen ari da.\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "%s(e)n estatistikak huts egin du: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "status\t\terakutsi daemon-aren eta ilararen egoera\n"
+
+msgid "stopped"
+msgstr "geldituta"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "sistemako helburu lehenetsia: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "sistemako helburu lehenetsia: %s/%s\n"
+
+msgid "unknown"
+msgstr "ezezaguna"
+
+msgid "untitled"
+msgstr "izengabea"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "'variable-bindings'-ek definitu gabeko luzera darabil"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " ABISUA %s(e)k ez dagozkion aukerak ditu.\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " ABISUA Aukera lehenetsiak gatazkan.\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " ABISUA Duplex aukeraren %s gakoak baliteke behar ez bezala "
+#~ "funtzionatzea eta Duplex izena eduki beharko luke.\n"
+#~ " Erref: 122. orrialdea, 5.17 atala\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " ABISUA Fitxategiak nahastutako CR, LF eta CR-LF lerro amaierak "
+#~ "ditu.\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " ABISUA %d lerroak zuriuneak soilik ditu.\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " ABISUA Windows-ekoak ez diren PPD fitxategien lerroak LFrekin "
+#~ "amaitu beharko lukete, ez CR-LFrekin\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " ABISUA PPDren %.1f bertsio zaharkitua.\n"
+#~ " Erref: 42. orrialdea, 5.2 atala.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s ez da existitzen.\n"
+
+#~ msgid " %s %s file \"%s\" has the wrong capitalization!\n"
+#~ msgstr " %s %s \"%s\" fitxategiak okerreko kapitalizazioa du.\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s Okerreko %s(r)en %s hautaketa.\n"
+#~ " Erref: 122. orrialdea, 5.17 atala.\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr ""
+#~ " %s Okerreko \"%s\" UTF-8 itzulpeneko katea %s aukerarentzako.\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Okerreko \"%s\" UTF-8 itzulpeneko katea %s aukerarentzako, %s "
+#~ "hautaketa.\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Okerreko cupsFilter-en \"%s\" balioa\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s Okerreko %s cupsICCProfile.\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Okerreko cupsPreFilter-ren \"%s\" balioa.\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Okerreko %s cupsUIConstraints: \"%s\".\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s Okerreko \"%s\" hizkuntza\n"
+
+#~ msgid " %s Bad spelling of %s - should be %s!\n"
+#~ msgstr " %s %s(r)en okerreko ortografia - %s izan beharko luke.\n"
+
+#~ msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID!\n"
+#~ msgstr " %s Ezin dira APScanAppPath eta APScanAppBundleID eman.\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s %s cupsUIConstraints hutsa\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s \"%s\" itzulpeneko katea falta da %s aukeran\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s \"%s\" itzulpeneko katea falta da %s aukeran, %s hautaketa.\n"
+
+#~ msgid ""
+#~ " %s Missing REQUIRED PageRegion option!\n"
+#~ " REF: Page 100, section 5.14.\n"
+#~ msgstr ""
+#~ " %s BEHARREZKOA DEN PageRegion aukera falta da.\n"
+#~ " Erref: 100. orrialdea, 5.14 atala.\n"
+
+#~ msgid ""
+#~ " %s Missing REQUIRED PageSize option!\n"
+#~ " REF: Page 99, section 5.14.\n"
+#~ msgstr ""
+#~ " %s BEHARREZKOA DEN PageSize aukera falta da.\n"
+#~ " Erref: 99. orrialdea, 5.14 atala.\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s *%s %s aukera falta da \"*%s %s *%s %s\" UIConstraints-en\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s *%s %s aukera falta da %s cupsUIConstraints-en: \"%s\"\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s cupsICCProfile-en \"%s\" fitxategia falta da.\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s %s cupsUIResolver falta da\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr " %s %s aukera falta da \"*%s %s *%s %s\" UIConstraints-en\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s %s aukera falta da %s cupsUIConstraints-en: \"%s\"\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr " %s Ez da oinarrizko \"%s\" itzulpena sartu fitxategian.\n"
+
+#~ msgid ""
+#~ " %s Non-standard size name \"%s\"!\n"
+#~ " REF: Page 187, section B.2.\n"
+#~ msgstr ""
+#~ " %s Tamaina ez estandarra dauka \"%s\" izenak.\n"
+#~ " Erref: 187. orrialdea, B.2 atala.\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s BEHARREZKOA DEN %s(e)k ez du 'Bat ere ez' aukera definitzen.\n"
+#~ " Erref: 122. orrialdea, 5.17 atala.\n"
+
+#~ msgid " %s Size \"%s\" defined for %s but not for %s!\n"
+#~ msgstr ""
+#~ " %s \"%s\" tamaina definituta %s(r)entzako, baina ez honentzako: %"
+#~ "s.\n"
+
+#~ msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)!\n"
+#~ msgstr " %s \"%s\" tamainak ustekabeko dimentsioak ditu (%gx%g).\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr ""
+#~ " %s cupsICCProfile-ren %s hash balioak beste honekin talka egiten "
+#~ "du: %s\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s %s cupsUIResolver-ek begizta sortzen du\n"
+
+#~ msgid ""
+#~ " %s cupsUIResolver %s does not list at least two different "
+#~ "options!\n"
+#~ msgstr ""
+#~ " %s %s cupsUIResolver-ek ez du gutxienez bi aukera desberdin "
+#~ "zerrendatu.\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **HUTSEGITEA** %s aukeraren %s eta %s izenak letren "
+#~ "kapitalizazioan soilik desberdintzen dira.\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **HUTSEGITEA** %s 1284DeviceID izan behar du\n"
+#~ " Erref: 72. orrialdea, 5.5 atala.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **HUTSEGITEA** OKERREKO DefaultImageableArea %s.\n"
+#~ " Erref: 102. orrialdea, 5.15 atala.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **HUTSEGITEA** OKERREKO DefaultPaperDimension %s.\n"
+#~ " Erref: 103. orrialdea, 5.15 atala.\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **HUTSEGITEA** Okerreko %s %s aukera\n"
+#~ " Erref: 84. orrialdea, 5.9 atala.\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr ""
+#~ " **HUTSEGITEA** Okerreko %s LanguageEncoding - ISOLatin1 izan behar "
+#~ "du\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr ""
+#~ " **HUTSEGITEA** Okerreko %s LanguageVersion - Ingelesa izan behar "
+#~ "du\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **HUTSEGITEA** %s aukeraren %s hautaketaren itzulpen-kate "
+#~ "lehenetsiak 8 biteko karaktereak ditu.\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **HUTSEGITEA** %s aukeraren itzulpen-kate lehenetsiak 8 biteko "
+#~ "karaktereak ditu.\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **HUTSEGITEA** %s eta %s talde-izenak letren kapitalizazioan "
+#~ "soilik desberdintzen dira.\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr ""
+#~ " **HUTSEGITEA** %s aukeraren %s izenaren hainbat agerraldi daude.\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **HUTSEGITEA** %s eta %s aukeren izenak letra kapitalizatuetan "
+#~ "soilik desberdintzen dira.\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " Okerreko %%%%BoundingBox: %d lerroan\n"
+#~ " Erref: 39. orrialdea, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " Okerreko %%%%Page: %d lerroan\n"
+#~ " Erref: 53. orrialdea, %%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " Okerreko %%%%Pages: %d lerroan\n"
+#~ " Erref: 43. orrialdea, %%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " %d lerroa 255 karaktere baino luzeagoa da (%d)!\n"
+#~ " Erref: 25. orrialdea, lerroaren luzera\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " %!PS-Adobe-3.0 falta da aurreneko lerroan\n"
+#~ " Erref: 17. orrialdea, 3.1 Adostasunaren dokumentuak\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " %%EndComments iruzkina falta da\n"
+#~ " Erref: 41. orrialdea, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " %%BoundingBox okerrekoa edo falta da: iruzkina\n"
+#~ " Erref: 39. orrialdea, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " %%Page okerrekoa edo falta da: iruzkinak\n"
+#~ " Erref: 53. orrialdea, %%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " %%Pages okerrekoa edo falta da: iruzkina\n"
+#~ " Erref: 43. orrialdea, %%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " 255 karaktere baino luzeagoak diren %d lerro aurkitu dira\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " %%BeginDocument iruzkin gehiegi\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " %%EndDocument iruzkin gehiegi\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " Abisua: fitxategiak datu bitarrak ditu\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " Abisua: ez dago %%EndComments iruzkinik fitxategian\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " Abisua: DSC %.1f bertsio zaharkitua fitxategian\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s ez dago onartuta."
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: ez daki zer egin.\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: errorea - Inguruneko %s aldagaiak existitzen ez den \"%s\" helburua "
+#~ "izendatzen du\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: errorea - lanaren okerreko IDa\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr ""
+#~ "%s: errorea - ezin dira fitxategiak inprimatu eta aldi berean lanak "
+#~ "aldatu\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: errorea - ezin da stdin-etik inprimatu fitxategiak edo lan baten IDa "
+#~ "ematen bada\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: errorea - '-S' aukeraren ondoren karaktere-jokoa espero zen\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: errorea - '-T' aukeraren ondoren eduki mota espero zen\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: errorea - '-n' aukeraren ondoren kopiak espero ziren\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr ""
+#~ "%s: errorea - '-#' aukeraren ondoren kopien zenbatzailea espero zen\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: errorea - '-P' aukeraren ondoren helburua espero zen\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: errorea - '-b' aukeraren ondoren helburua espero zen\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: errorea - '-d' aukeraren ondoren helburua espero zen\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: errorea - '-f' aukeraren ondoren inprimakia espero zen\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: errorea - '-H' aukeraren ondoren eusteko izena espero zen\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: errorea - '-H' aukeraren ondoren ostalari-izena espero zen\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: errorea - '-h' aukeraren ondoren ostalari-izena espero zen\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: errorea - '-y' aukeraren ondoren moduen zerrenda espero zen\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: errorea - '-%c' aukeraren ondoren izena espero zen\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s: errorea - '-o' aukeraren ondoren aukera-katea espero zen\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr ""
+#~ "%s: errorea - '-P' aukeraren ondoren orrialdeen zerrenda espero zen\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: errorea - '-%c' aukeraren ondoren lehentasuna espero zen\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr ""
+#~ "%s: errorea - '-r' aukeraren ondoren arrazoiaren testua espero zen\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: errorea - '-t' aukeraren ondoren titulua espero zen\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr ""
+#~ "%s: errorea - '-U' aukeraren ondoren erabiltzaile-izena espero zen\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr ""
+#~ "%s: errorea - '-u' aukeraren ondoren erabiltzaile-izena espero zen\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: errorea - '-%c' aukeraren ondoren balio bat espero zen\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: errorea - '-W' aukeraren ondoren \"completed\", \"not-completed\", "
+#~ "edo \"all\" egon behar du\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: errorea - antolatzaileak ez du erantzuten\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: errorea - \"%s\" helburu ezezaguna\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: errorea - \"%s/%s\" helburu ezezaguna\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: errorea - '%c' aukera ezezaguna\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: errorea - '%s' aukera ezezaguna\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: '-i' aukeraren ondoren lanaren IDa espero zen\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: helburuaren izen baliogabea \"%s\" zerrendan\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr "%s: lanaren IDa ('-i lanIDa') behar da '-H restart'-en aurretik\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: ez dago iragazkirik %s/%s -> %s/%s bihurtzeko\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s: ez da enkriptatzeko euskarriarekin konpilatu\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: ezin da zerbitzariarekin kontaktatu\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: ezin da \"%s\"(r)en MIME mota zehaztu\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s: ezin da MIMEen datu-basea irakurri \"%s\" edo \"%s\"(e)ndik\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: \"%s\" helburu ezezaguna\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: %s/%s MIME motaren helburu ezezaguna\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: '%c' aukera ezezaguna\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: %s/%s MIME moten iturburu ezeaguna\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: abisua - '%c' formatuaren eraldatzailea ez dago onartuta - irteera ez "
+#~ "da zuzena izango\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: abisua - karaktere-jokoaren aukerari ezikusi egin zaio\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: abisua - edukiaren motaren aukerari ezikusi egin zaio\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: abisua - inprimakiaren aukerari ezikusi egin zaio\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: abisua - moduen aukerari ezikusi egin zaio\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: errorea - inguruneko %s aldagaiak existitzen ez den \"%s\" helburua "
+#~ "izandatzen du\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: errorea - '-o' aukeraren ondoren aukera=balioa espero zen\n"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr ""
+#~ "Samba-ko pasahitza behar da inprimagailuaren kontrolatzaileak "
+#~ "esportatzeko."
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr ""
+#~ "Samba-ko erabiltzaile-izena behar da inprimagailuaren kontrolatzaileak "
+#~ "esportatzeko."
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "\"%s\" izeneko klasea badago lehendik ere."
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "\"%s\" izeneko inprimagailua badago lehendik ere."
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr ""
+#~ "%s inprimagailuaren egoera okerreko %d balioarekin ezartzen saiatzen."
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "Taldeen atributuak ordenatik kanpo daude (%x < %x)"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "Okerreko gailuaren URIa: \"%s\"\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "Okerreko device-uri: \"%s\"."
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "Okerreko device-uri eskema: \"%s\"."
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "Okerreko document-format: \"%s\"."
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Okerreko fitxategi-izenaren buferra."
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Okerreko job-priority balioa."
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Okerreko job-sheets balioa: \"%s\"."
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Okerreko job-sheets balio mota."
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Okerreko job-state balioa."
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Okerreko job-uri atributua: \"%s\"."
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "Okerreko notify-pull-method: \"%s\"."
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "Okerreko notify-recipient-uri URIa: \"%s\"."
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "Okerreko aukera + hautaketa %d. lerroan."
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "Okerreko port-monitor: \"%s\"."
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Okerreko printer-state balioa: %d."
+
+#~ msgid "Bad request ID %d!"
+#~ msgstr "Okerreko eskaeraren IDa: %d."
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "Okerreko eskaeraren bertsio zenbakia: %d.%d."
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "Okerreko harpidetzaren IDa."
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "\"%s\" karaktere-jokoa ez dago onartuta."
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "Ezin izan da \"%s\" mota eskaneatu."
+
+#~ msgid "Cover open."
+#~ msgstr "Estalkia irekita."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "Errebelatzailea ia hutsik."
+
+#~ msgid "Developer empty!"
+#~ msgstr "Errebelatzailea hutsik!"
+
+#~ msgid "Door open."
+#~ msgstr "Atea irekita."
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: %%BoundingBox: iruzkin okerra ikusi da\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: %%IncludeFeature: iruzkin okerra\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: %%Page: iruzkin okerra fitxategian\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: %%PageBoundingBox: iruzkin okerra fitxategian\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: SCSI gailuaren fitxategia okerra: \"%s\"\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: zutabeen balioa okerra: %d\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: cpi-ren balioa okerra: %f\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: lpi balioa okerra: %f\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: orrialdearen konfigurazioa okerra\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: helburuko inprimagailua ez da existitzen\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: bikoiztutako %%BoundingBox: iruzkina ikusi da\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: bikoiztutako %%Pages: iruzkina ikusi da\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: inprimatzeko fitxategia hutsik dago.\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr "ERROR: komatxoen arteko katea espero zen %2$s(r)en %1$d lerroan\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: USBaren errore larria\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr ""
+#~ "ERROR: baliogabeko HP-GL/2 komandoa ikusi da, ezin da fitxategia "
+#~ "inprimatu\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: %%EndProlog falta da\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: %%EndSetup falta da\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: gailuaren URIa falta da komando-lerroan eta ez dago inguruneko "
+#~ "DEVICE_URI aldagairik\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: balioa falta da titularraren fitxategiko %d lerroan\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: msgid lerro bat behar da itzulpeneko edozein kateren aurretik %d "
+#~ "lerroan %s(e)n\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: ez dago %%BoundingBox: iruzkinik goiburuan\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: ez dago %%Pages: iruzkinik goiburuan\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: ez da gailuaren URIrik aurkitu argv[0] argumentuan edo inguruneko "
+#~ "DEVICE_URI aldagaian\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: ez dira orrialderik aurkitu\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: ez dago paperik\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: inguruneko PRINTER aldagaia ez dago definituta\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: inprimatzeko fitxategia ez da onartu (%s)\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: inprimagailuak ez du erantzuten\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: ezin da %d lanaren atributurik lortu (%s)\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: ezin da inprimagailuaren egoera lortu (%s)\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: ezin da '%s' inprimagailua aurkitu\n"
+
+#~ msgid "ERROR: Unable to open PPD file!\n"
+#~ msgstr "ERROR: ezin da PPD fitxategia ireki\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: ezin da irudiaren fitxategia ireki inprimatzeko\n"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: ezin dira testuaren %d zutabe inprimatu\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: ezin da %dx%d testu orrialde inprimatu\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: ezin da inprimatzeko daturik irakurri\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: ezin da inprimatzeko daturik bidali (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: ezin da inprimatzeko daturik bidali\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: ezin dira %d byte idatzi inprimagailuan\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr "ERROR: ezin da bilbeko daturik idatzi kontrolatzailean\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: ezin da aldi baterako fitxategian idatzi"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: ustekabeko testua %2$s fitxategiko %1$d lerroan\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: enkriptatzeko aukeraren \"%s\" balioa ezezaguna\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: mezuaren katalogo-formatua ezezaguna \"%s\"(r)entzako\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: \"%s\" aukera ezezaguna \"%s\" balioarekin\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: bertsioaren aukeraren \"%s\" balioa ezezaguna\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr "ERROR: distiraren %s balioa onartu gabea. Distira=100 erabiltzen\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: gammaren %s balioa onartu gabea. Gamma=100 erabiltzen\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr ""
+#~ "ERROR: number-up parametroaren %d balioa onartu gabea. number-up=1 "
+#~ "erabiltzen\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: number-up-layout parametroaren %s balioa onartu gabea. number-up-"
+#~ "layout=1 erabiltzen\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: page-border parametroaren %s balioa onartu gabea. page-border=none "
+#~ "erabiltzen\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr ""
+#~ "ERROR: gainezkatutako doc_printf (%d byte) detektattua. Bertan behera "
+#~ "uzten\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops %d seinalearekin irten da\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops %d egoerarekin irten da\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: berreskura daiteke. Ezin da inprimagailuarekin konektatu. 30 "
+#~ "segundo barru saiatuko da berriro...\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "PPD fitxategia hutsik dago."
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "Errorea: ostalari-izena behar da '-h' aukeraren ondoren\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Fuser-aren tenperatura altua."
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "Fuser-aren tenperatura baxua."
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "printer-uri atributua lortu da, baina ez job-id."
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Tinta/Tonerra ia hutsik."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Tinta/Tonerra hutsik!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Tinta/Tonerraren zakarrontzia ia beteta."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Tinta/Tonerraren zakarrontzia beteta!"
+
+#~ msgid "Interlock open."
+#~ msgstr "Segurtasun-blokeoa irekita."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "%d. lana ezin da berrabiatu. Ez dago fitxategirik."
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "%d. lana ez da existitzen."
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "%d. lana jadanik burututa dago, eta ezin da aldatu."
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "%d. lana ez dago burututa."
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "%d. lana ez dago atxikituta autentifikatzeko."
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "%d. lana ez dago atxikituta."
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "%s. lana ez da existitzen."
+
+#~ msgid "Job %d not found!"
+#~ msgstr "%d lana ez da aurkitu."
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "Lanaren harpidetzak ezin dira berritu."
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "\"%s\" hizkuntza ez dago onartuta."
+
+#~ msgid "Media jam!"
+#~ msgstr "Paper gatazka!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Paperen erretilua is hutsik."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Paperen erretilua hutsik!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Paperen erretilua falta da!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "Paperen erretilua bete egin behar da."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "document-number atributua falta da."
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "Komatxo bikoitzak falta dira %d lerroan."
+
+#~ msgid "Missing form variable!"
+#~ msgstr "Inprimakiaren aldagaia falta da."
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "notify-subscription-ids atributua falta da."
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "requesting-user-name atributua falta da."
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "Beharrezko atributuak falta dira."
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "Balioa falta da %d lerroan."
+
+#~ msgid "No PPD name!"
+#~ msgstr "PPD izenik ez."
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Ez daude Windows-eko inprimagailuen kontrolatzailerik instalatuta!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "Ez dago lan aktiborik %s(e)n."
+
+#~ msgid "No attributes in request!"
+#~ msgstr "Ez dago atributurik eskaeran."
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "Ez da autentifikatzeko informaziorik eman."
+
+#~ msgid "No file!?!"
+#~ msgstr "Fitxategirik ez?"
+
+#~ msgid "No modification time!"
+#~ msgstr "Ez dago aldaketa-ordurik."
+
+#~ msgid "No printer name!"
+#~ msgstr "Ez dago inprimagailuaren izenik."
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "Ez da printer-uri aurkitu klasearentzako"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "Ez da printer-uri aurkitu."
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "Ez da printer-uri aurkitu eskaeran."
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "Ez dago harpidetzako atributurik eskaeran."
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPCa ia agortuta."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPCa agortuta."
+
+#~ msgid "Out of toner!"
+#~ msgstr "Tonerra agortuta!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Irteerako ontzia ia beteta."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Irteerako ontzia beteta!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Irteerako erretilua falta da."
+
+#~ msgid "Printer offline."
+#~ msgstr "Inprimagailua lineaz kanpo."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "SCSI inprimagailua"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "notify-user-data balioa handiegia da (%d > 63 zortzikote)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "Inprimagailua edo klasea ez dago partekatuta."
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "printer-uri atributua behar da."
+
+#~ msgid "Toner low."
+#~ msgstr "Tonerra baxua."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "job-sheets balio gehiegi (%d > 2)."
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "printer-state-reasons balio gehiegi (%d > %d)."
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "Ezin da lana gehitu \"%s\" helbururako."
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "Ezin da memoria esleitu fitxategi motentzako."
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "Ezin dira 64 bit-eko CUPSeko inprimagailuen kontrolatzaileen fitxategiak "
+#~ "kopiatu (%d)."
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr ""
+#~ "Ezin dira 64 bit-eko Windows-eko inprimagailuen kontrolatzaileen "
+#~ "fitxategiak kopiatu (%d)."
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "Ezin dira CUPSeko inprimagailuen kontrolatzaileen fitxategiak kopiatu (%"
+#~ "d)."
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "Ezin da PPD fitxategia kopiatu: %s."
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "Ezin da PPD fitxategia kopiatu."
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Ezin dira Windows 2000ko inprimagailuen kontrolatzaileen fitxategiak "
+#~ "kopiatu (%d)."
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "Ezin dira Windows 9x sistemako inprimagailuen kontrolatzaileen "
+#~ "fitxategiak kopiatu (%d)."
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "Ezin da interfazeko script-a kopiatu: %s."
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "Ezin da printer-uri sortu."
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr ""
+#~ "Ezin dira 1 MB baino handiagoak diren cupsd.conf fitxategiak editatu."
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "Ezin da helburua aurkitu lanarentzako."
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "Ezin da inprimagailua aurkitu.\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Ezin dira Windows 2000ko inprimagailuen kontrolatzaileen fitxategiak "
+#~ "instalatu (%d)."
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "Ezin dira Windows 9x sistemako inprimagailuen kontrolatzaileen "
+#~ "fitxategiak instalatu (%d)."
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "Ezin da %d. dokumentua ireki %d. lanean."
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "Ezin da komandoa bidali inprimagailuaren kontrolatzaileari."
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Ezin da Windows-eko inprimagailuaren kontrolatzailea ezarri (%d)."
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "Ezin da USB klaseko kontrolatzaile zaharkitua erabili.\n"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Onartu gabeko \"%s\" karaktere-jokoa."
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "Onartu gabeko \"%s\" konpresioa."
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "Onartu gabeko %s konpresio atributua."
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "Onartu gabeko \"%s\" formatua."
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "Onartu gabeko '%s' formatua."
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "Onartu gabeko '%s/%s' formatua."
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+#~ "translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Erabilera: cupstestppd [aukerak] fitxategia1.ppd[.gz] [... fitxategia.ppd"
+#~ "[.gz]]\n"
+#~ " programa | cupstestppd [aukerak] -\n"
+#~ "\n"
+#~ "Aukerak:\n"
+#~ "\n"
+#~ " -R erroko-direktorioa Ezarri beste erro bat\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+#~ "translations}\n"
+#~ " Igorri abisuak erroreen ordez\n"
+#~ " -q Exekutatu isilean\n"
+#~ " -r Erabili modu ireki 'lasaia'\n"
+#~ " -v Erakutsi xehetasun piskatekoa\n"
+#~ " -vv Xehetasun askokoa\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: huts egin du albo-kanaleko eskaera irakurtzean\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr "WARNING: \"%s\" aukera ezin da sartu IncludeFeature bidez\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: urruneko ostalariak ez du erantzun komandoaren egoeraren "
+#~ "bytearekin %d segundo ondoren\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: urruneko ostalariak ez du erantzun kotroleko egoeraren "
+#~ "bytearekin %d segundo ondoren\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: urruneko ostalariak ez du erantzun datuen egoeraren bytearekin %"
+#~ "d segundo ondoren\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr ""
+#~ "WARNING: SCSI komandoak denboraren muga gainditu du (%d). Berriro "
+#~ "saiatzen...\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: dokumentu hau ez dator bat Abode Document Structuring "
+#~ "Conventions-eko zehaztapenekin, eta ez da ongi inprimatuko.\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: \"%s\" hautaketa ezezaguna \"%s\" aukeran\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: \"%s\" aukera ezezaguna\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: %s baudio-emaria onartu gabea\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: berreskuratu daiteke. Sareko '%s' ostalaria lanpetuta dago. "
+#~ "Berriro saiatuko da %d segundo barru...\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr ""
+#~ "Abisua, ez dago Windows 2000 sistemako inprimagailuen kontrolatzailerik "
+#~ "instalatuta."
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: \"%s\" aukera ezezaguna.\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: \"-%c\" aukera ezezaguna.\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr ""
+#~ "cupsd: konfigurazioko fitxategia espero zen \"-c\" aukeraren ondoren.\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: ezin da uneko direktorioa lortu.\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: \"%s\" argumentu ezezaguna. Abortatzen.\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: \"%c\" aukera ezezaguna. Abortatzen.\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: baliogabeko %d dokumentu-zenbakia.\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: baliogabeko %d lanaren IDa.\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: fitxategi-izen bakarra soilik zehaztu daiteke.\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "job-printer-uri atributua falta da."
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr ""
+#~ "lpadmin: klasearen izenak karaktere inprimagarriak soilik eduki ditzake.\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: PPDa espero zen '-P' aukeraren ondoren.\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr ""
+#~ "lpadmin: Expected alerabiltzaile-zerrenda espero zen st afaukeraren "
+#~ "ondoren.\n"
+#~ "option!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: klasea espero zen '-r' aukeraren ondoren.\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: klasearen izena espero zen '-c' aukeraren ondoren.\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: deskripzioa espero zen '-D' aukeraren ondoren.\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: gailuaren URIa espero zen '-v' aukeraren ondoren.\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: fitxategi motak espero ziren '-I' aukeraren ondoren.\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: ostalari-izena espero zen '-h' aukeraren ondoren.\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: interfazea espero zen '-i' aukeraren ondoren.\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: kokalekua espero zen '-L' aukeraren ondoren.\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: modeloa espero zen '-m' aukeraren ondoren.\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: izena=balioa espero zen '-o' aukeraren ondoren.\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: inprimagailua espero zen '-p' aukeraren ondoren.\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr ""
+#~ "lpadmin: inprimagailuaren izena espero zen '-d' aukeraren ondoren.\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr ""
+#~ "lpadmin: inprimagailua edo klasea espero zen '-x' aukeraren ondoren.\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: ez da kideen izenik ikusi.\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr ""
+#~ "lpadmin: inprimagailuaren izenak karaktere inprimagarriak soilik eduki "
+#~ "ditzake.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: ezin da inprimagailua klaseari gehitu:\n"
+#~ " Aurrenik inprimagailuaren izena zehaztu behar duzu.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: ezin da inprimagailua klasetik kendu:\n"
+#~ " Aurrenik inprimagailuaren izena zehaztu behar duzu.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: ezin da PPD fitxategia ezarri:\n"
+#~ " Aurrenik inprimagailuaren izena zehaztu behar duzu.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: ezin da gailuaren URIa ezarri:\n"
+#~ " Aurrenik inprimagailuaren izena zehaztu behar duzu.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: ezin da interfazearen script-a edo PPD fitxategia ezarri:\n"
+#~ " Aurrenik inprimagailuaren izena zehaztu behar duzu.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: ezin da interfazearen script-a ezarri:\n"
+#~ " Aurrenik inprimagailuaren izena zehaztu behar duzu.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: ezin da inprimagailuaren deskripzioa ezarri:\n"
+#~ " Aurrenik inprimagailuaren izena zehaztu behar duzu.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: ezin da inprimagailuaren kokalekua ezarri:\n"
+#~ " Aurrenik inprimagailuaren izena zehaztu behar duzu.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: ezin dira inprimagailuaren aukerak ezarri:\n"
+#~ " Aurrenik inprimagailuaren izena zehaztu behar duzu.\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: \"%s\" allow/deny aukera ezezaguna.\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: '%s' argumentu ezezaguna.\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: '%c' aukera ezezaguna.\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin: abisua - edukiaren moten zerrendari ezikusi egin zaio.\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr ""
+#~ "lpinfo: 1284 gailuaren IDaren katea espero zen --device-id aukeraren "
+#~ "ondoren.\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: hizkuntza espero zen --language aukeraren ondoren.\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr ""
+#~ "lpinfo: marka eta modeloa espero ziren --make-and-model aukeraren "
+#~ "ondoren.\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr ""
+#~ "lpinfo: produktuaren katea espero zen --product aukeraren ondoren.\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr ""
+#~ "lpinfo: eskemen zerrenda espero zen --exclude-schemes aukeraren ondoren.\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr ""
+#~ "lpinfo: eskemen zerrenda espero zen --include-schemes aukeraren ondoren.\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: denbora-muga espero zen --timeout aukeraren ondoren.\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: '%s' argumentu ezezaguna.\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: '%c' aukera ezezaguna.\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: '%s' aukera ezezaguna.\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: '%s' argumentu ezezaguna.\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: '%c' aukera ezezaguna.\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: inprimagailurik ez?\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: ezin da PPD fitxategia ireki %s(r)entzako.\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: inprimagailua edo klasea ezezaguna.\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr ""
+#~ "lppasswd: supererabiltzaileak (root) soilik gehitu edo ezabatu ditzake "
+#~ "pasahitzak.\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: pasahitzen fitxategia lanpetuta.\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: pasahitzen fitxategia ez da eguneratu.\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: pasahitzak ez dira berdinak.\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: pasahitzak ez datoz bat.\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: errorea . Inguruneko %s aldagaiak existitzen ez den \"%s\" "
+#~ "helburua izendatzen du.\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-events ez da zehaztu."
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "\"%s\" notify-recipient-uri URIa jadanik erabilita dago."
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "\"%s\" notify-recipient-uri URIak eskema ezezaguna darabil."
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "%d notify-subscription-id ez da ona."
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: okerreko \"%s\" bereizmen izena%d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: okerreko %s egoeraren gako-hitza %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc: hautaketa aurkituta %d lerroan aukerarik gabeko %s(e)n.\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc: %s lokalaren #po-a bikoiztua %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: iragazkiaren definizioa espero zen %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: programaren izena espero zen %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: karaktere-jokoa espero zen Font-en ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: koloreen ordena espero zen ColorModel-entzako %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: kolore-espazioa espero zen ColorModel-entzako %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: konpresioa espero zen ColorModel-entzako %d lerroan %s(e)n.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: murriztapenen katea espero zen UIConstraints-entzako %d lerroan %s"
+#~ "(e)n.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: kontrolatzaile motaren gako-hitza espero zen DriverType-ren ondoren "
+#~ "%d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr "ppdc: duplex mota espero zen Duplex-en ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc: kodeketa espero zen Font-en ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: fitxategi-izena espero zen %s #po ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: taldearen izena/testua espero zen %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc: include fitxategi-izena espero zen %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: osoko zenbakia espero zen %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc: lokala espero zen espero zen #po ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: izena espero zen %s(rÇ)en ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: izena espero zen FileName ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: izena espero zen Font ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc: izena espero zen Manufacturer ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: izena espero zen MediaSize ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: izena espero zen ModelName ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: izena espero zen PCFileName ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: izena/testua espero zen %s ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: izena/testua espero zen Installable ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: izena/testua espero zen Resolution ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: izena/testuaren konbinazioa espero zen ColorModel-arentzako %d "
+#~ "lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc: aukeraren izena/testua espero zen %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: aukeraren atala espero zen %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: aukera mota espero zen %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: gainidazketaren eremua espero zen Resolution ondoren %d lerroan %s"
+#~ "(e)n.\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: zenbaki erreala espero zen %d lerroan %s(e)n.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: bereizmena/euskarri mota espero zen ColorProfile ondoren %d lerroan "
+#~ "%s(e)n.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: bereizmena/euskarri mota espero zen SimpleColorProfile ondoren %d "
+#~ "lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: hautatzailea espero zen %s ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: egoera espero zen Font ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc: katea espero zen Copyright ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc: katea espero zen Version ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: aukeren bi izen espero ziren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: balioa espero zen %s ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: bertsioa espero zen Font ondoren %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: baliogabeko #include/#po \"%s\" fitxategi-izena.\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: baliogabeko iragazkiaren kostua %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: baliogabeko MIME mota hutsa iragazkiarentzako %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: baliogabeko prorgramare izen hutsa iragazkiarentzako %d lerroan %s"
+#~ "(e)n.\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: baliogabeko aukeraren \"%s\" atala %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: baliogabeko aukeraren \"%s\" mota %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: #endif falta da \"%s\"(r)en amaieran.\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: #if falta da %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc: ez da mezuen katalogorik eman %s lokalarentzako.\n"
+
+#~ msgid "ppdc: Option %s defined in two different groups on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %s aukera bi talde desberdinetan definituta %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %s aukera berriro definituta mota desberdin batekin %d lerroan %s(e)"
+#~ "n.\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: aukeraren murriztapenak *izena eduki behar du %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: habiarazitako #if gehiegi %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: ezin da %s #po fitxategia aurkitu %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: ezin da \"%s\" include fitxategia aurkitu %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: %s kontrolatzaile mota ezezaguna %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: \"%s\" duplex mota ezezaguna %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: \"%s\" euskarri-tamaina ezezaguna %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: \"%s\" token ezezaguna ikusi da %d lerroan %s(e)n.\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: amaierako karaktere ezezagunak \"%s\" zenbaki errealean %d lerroan %"
+#~ "s(e)n.\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr "ppdc: %c(r)ekin hasitako amaitu gabeko katea %d lerroan %s(e)n.\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: okerreko \"%s\" LanguageVersion %s(e)n\n"
diff --git a/locale/cups_fi.po b/locale/cups_fi.po
new file mode 100644
index 000000000..a2450763e
--- /dev/null
+++ b/locale/cups_fi.po
@@ -0,0 +1,7130 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-12 15:10+0200\n"
+"Last-Translator: Teppo Turtiainen <teppot@iki.fi>\n"
+"Language-Team: Finnish\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(kaikki)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(ei mitään)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d tietuetta\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tVian jälkeen: jatka\n"
+
+msgid "\tAlerts:"
+msgstr "\tVaroitukset:"
+
+msgid "\tBanner required\n"
+msgstr "\tOtsikko vaaditaan\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tMerkistöt:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tYhteys: suora\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tYhteys: etä\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tSivun oletuskoko:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tOletusmerkkiväli:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tPortin oletusasetukset:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tKuvaus: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tLomake liitetty:\n"
+"\tSisältötyypit: mikä tahansa\n"
+"\tTulostintyypit: tuntematon\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tLomakkeet sallittu:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tLiitäntä: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tLiitäntä: %s/interfaces/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tLiitäntä: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tSijainti: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tVian aikana: ei varoitusta\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tKäyttäjät sallittu:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tKäyttäjät estetty:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\ttaustaprosessi käynnissä\n"
+
+msgid "\tno entries\n"
+msgstr "\tei tietueita\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\ttulostin on laitteessa â€%s†nopeus -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\ttulostus on pois käytöstä\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\ttulostus on käytössä\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\tjonossa kohteelle %s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tjonotus on pois käytöstä\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tjonotus on käytössä\n"
+
+msgid "\treason unknown\n"
+msgstr "\tsyy tuntematon\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" YKSITYISKOHTAISET STANDARDIENMUKAISUUSTESTIN TULOKSET\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " VIITE: sivu 15, osa 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " VIITE: sivu 15, osa 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " VIITE: sivu 19, osa 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " VIITE: sivu 20, osa 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " VIITE: sivu 27, osa 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " VIITE: sivu 42, osa 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " VIITE: sivut 16 - 17, osa 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " VIITE: sivut 42 - 45, osa 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " VIITE: sivut 45 - 46, osa 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " VIITE: sivut 48 - 49, osa 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " VIITE: sivut 52 - 54, osa 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f tavua\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " PASS Default%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " PASS DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " PASS DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " PASS FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " PASS FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " PASS LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " PASS LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " PASS Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " PASS ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " PASS NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " PASS PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " PASS PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " PASS PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " PASS PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " PASS Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " PASS ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" WARN â€%s %s†on ristiriidassa kohteen â€%s %s†kanssa\n"
+" (rajoitus=â€%s %s %s %sâ€)\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" WARN %s jakaa yleisen etuliitteen kohteen %s kanssa\n"
+" VIITE: sivu 15, osa 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" WARN LanguageEncoding vaaditaan PPD 4.3 -määrityksessä.\n"
+" VIITE: sivut 56 - 57, osa 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" WARN Manufacturer vaaditaan PPD 4.3 -määrityksessä.\n"
+" VIITE: sivut 58 - 59, osa 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" WARN PCFileName on PPD-määrityksen vastaisesti pidempi kuin 8.3.\n"
+" VIITE: sivut 61 - 62, osa 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protokollat sisältävät PJL:ää, mutta JCL-attribuutteja ei "
+"ole asetettu.\n"
+" VIITE: sivut 78 - 79, osa 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protokollat sisältävät sekä PJL:ää etä BCP:tä; TBCP:tä "
+"odotettiin.\n"
+" VIITE: sivut 78 - 79, osa 5.7.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" WARN ShortNickName vaaditaan PPD 4.3 -määrityksessä.\n"
+" VIITE: sivut 64 - 65, osa 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s cupsFilter-tiedosto â€%s†puuttuu!\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s cupsPreFilter-tiedosto â€%s†puuttuu!\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** VIRHEELLINEN Default%s %s\n"
+" VIITE: sivu 40, osa 4.5.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **FAIL** VIRHEELLINEN JobPatchFile-attribuutti tiedostossa\n"
+" REF: sivu 24, osa 3.4.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** VIRHEELLINEN Manufacturer (tulisi olla â€HPâ€)\n"
+" REF: sivu 211, taulukko D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** VIRHEELLINEN Manufacturer (tulisi olla â€Okiâ€)\n"
+" REF: sivu 211, taulukko D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** VIRHEELLINEN ModelName - â€%c†ei ole sallittu "
+"merkkijonossa.\n"
+" VIITE: sivut 59 - 60, osa 5.3.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** VIRHEELLINEN PSVersion - ei â€(string) intâ€.\n"
+" VIITE: sivut 62 - 64, osa 5.3.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** VIRHEELLINEN Product - ei â€(string)â€.\n"
+" VIITE: sivu 62, osa 5.3.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** VIRHEELLINEN ShortNickName - pidempi kuin 31 merkkiä.\n"
+" VIITE: sivut 64 - 65, osa 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** Virheellinen FileVersion â€%sâ€\n"
+" VIITE: Sivu 56, osa 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** Virheellinen FormatVersion â€%sâ€\n"
+" VIITE: Sivu 56, osa 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr " **FAIL** Oletusarvoista valintakoodia ei voida tulkita: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** VAADITAAN Default%s\n"
+" VIITE: sivu 40, osa 4.5.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** VAADITAAN DefaultImageableArea\n"
+" VIITE: sivu 102, osa 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** VAADITAAN DefaultPaperDimension\n"
+" VIITE: sivu 103, osa 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** VAADITAAN FileVersion\n"
+" VIITE: sivu 56, osa 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** VAADITAAN FormatVersion\n"
+" VIITE: sivu 56, osa 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** VAADITAAN ImageableArea PageSize-arvolle %s\n"
+" VIITE: sivu 41, osa 5.\n"
+" VIITE: sivu 102, osa 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **FAIL** VAADITAAN LanguageEncoding\n"
+" VIITE: sivut 56 - 57, osa 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **FAIL** VAADITAAN LanguageVersion\n"
+" VIITE: sivut 57 - 58, osa 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **FAIL** VAADITAAN Manufacturer\n"
+" VIITE: sivut 58 - 59, osa 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** VAADITAAN ModelName\n"
+" VIITE: sivut 59 - 60, osa 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **FAIL** VAADITAAN NickName\n"
+" VIITE: sivu 60, osa 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **FAIL** VAADITAAN PCFileName\n"
+" VIITE: sivut 61 - 62, osa 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** VAADITAAN PSVersion\n"
+" VIITE: sivut 62 - 64, osa 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **FAIL** VAADITAAN PageRegion\n"
+" VIITE: sivu 100, osa 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **FAIL** VAADITAAN PageSize\n"
+" VIITE: sivu 41, osa 5.\n"
+" VIITE: sivu 99, osa 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **FAIL** VAADITAAN PageSize\n"
+" VIITE: sivut 99 - 100, osa 5.14.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** VAADITAAN PaperDimension PageSize-arvolle %s\n"
+" VIITE: sivu 41, osa 5.\n"
+" VIITE: sivu 103, osa 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** VAADITAAN Product\n"
+" VIITE: sivu 62, osa 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** VAADITAAN ShortNickName\n"
+" VIITE: sivu 64 - 65, osa 5.3.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " %d VIRHETTÄ LÖYDETTIIN\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " VIRHEITÄ EI LÖYTYNYT\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " FAIL\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** PPD-tiedostoa ei voida avata - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** PPD-tiedostoa ei voida avata - %s rivillä %d.\n"
+
+msgid " PASS\n"
+msgstr " PASS\n"
+
+msgid "#10 Envelope"
+msgstr "#10 Envelope"
+
+msgid "#11 Envelope"
+msgstr "#11 Envelope"
+
+msgid "#12 Envelope"
+msgstr "#12 Envelope"
+
+msgid "#14 Envelope"
+msgstr "#14 Envelope"
+
+msgid "#9 Envelope"
+msgstr "#9 Envelope"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f tavua\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f tavua\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f millimetriä"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f - %.0f x %.0f millimetriä"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f tuumaa"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f - %.2f x %.2f tuumaa"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s vastaanottaa pyyntöjä alkaen %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "Kohdetta %s ei voida muuttaa."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "Kohdetta %s ei ole toteutettu lpc:n CUPS-versiossa.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s ei ole valmis\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s on valmis\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s on valmis ja tulostaa\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s ei vastaanota pyyntöjä alkaen %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s vastaanottaa pyyntöjä alkaen %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s ei vastaanota pyyntöjä alkaen %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [työ %d localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s epäonnistui: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: Virhe - oletuskohdetta ei ole käytettävissä.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: Virhe - tärkeyden on oltava 1 - 100.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: Virhe - liikaa tiedostoja - â€%sâ€\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: Virhe - kohdetta â€%s†ei voida käyttää - %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s: Virhe - oletussyötevirrasta ei voida laittaa jonoon - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: Suodin â€%s†ei ole käytettävissä: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: Virheellinen suodinmerkkijono â€%sâ€\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: Toiminto epäonnistui: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: Palvelimeen ei voida yhdistää\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: Kohdetta %s ei voida avata: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: PPD-tiedostoa s ei voida avata: %s linjalla %d.\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: virhe - oletuskohdetta ei ole käytettävissä.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 tuumaa/s"
+
+msgid "1.25x0.25\""
+msgstr "1,25 x 0,25 \""
+
+msgid "1.25x2.25\""
+msgstr "1,25 x 2,25 \""
+
+msgid "1.5 inch/sec."
+msgstr "1,5 tuumaa/s"
+
+msgid "1.50x0.25\""
+msgstr "1,50 x 0,25 \""
+
+msgid "1.50x0.50\""
+msgstr "1,50 x 0,50 \""
+
+msgid "1.50x1.00\""
+msgstr "1,50 x 1,00 \""
+
+msgid "1.50x2.00\""
+msgstr "1,50 x 2,00 \""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 tuumaa/s"
+
+msgid "10 x 11\""
+msgstr "10 x 11 \""
+
+msgid "10 x 13\""
+msgstr "10 x 13 \""
+
+msgid "10 x 14\""
+msgstr "10 x 14 \""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 mm/s"
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 tuumaa/s"
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 tuumaa/s"
+
+msgid "12 x 11\""
+msgstr "12 x 11 \""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 mm/s"
+
+msgid "120x60dpi"
+msgstr "120 x 60 dpi"
+
+msgid "120x72dpi"
+msgstr "120 x 72 dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136 dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 mm/s"
+
+msgid "15 x 11\""
+msgstr "15 x 11 \""
+
+msgid "150 mm/sec."
+msgstr "150 mm/s"
+
+msgid "150dpi"
+msgstr "150 dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180 dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 tuumaa/s"
+
+msgid "2-Sided Printing"
+msgstr "Kaksipuolinen tulostus"
+
+msgid "2.00x0.37\""
+msgstr "2,00 x 0,37 \""
+
+msgid "2.00x0.50\""
+msgstr "2,00 x 0,50 \""
+
+msgid "2.00x1.00\""
+msgstr "2,00 x 1,00 \""
+
+msgid "2.00x1.25\""
+msgstr "2,00 x 1,25 \""
+
+msgid "2.00x2.00\""
+msgstr "2,00 x 2,00 \""
+
+msgid "2.00x3.00\""
+msgstr "2,00 x 3,00 \""
+
+msgid "2.00x4.00\""
+msgstr "2,00 x 4,00 \""
+
+msgid "2.00x5.50\""
+msgstr "2,00 x 5,50 \""
+
+msgid "2.25x0.50\""
+msgstr "2,25 x 0,50 \""
+
+msgid "2.25x1.25\""
+msgstr "2,25 x 1,25 \""
+
+msgid "2.25x4.00\""
+msgstr "2,25 x 4,00 \""
+
+msgid "2.25x5.50\""
+msgstr "2,25 x 5,50 \""
+
+msgid "2.38x5.50\""
+msgstr "2,38 x 5,50 \""
+
+msgid "2.5 inches/sec."
+msgstr "2,5 tuumaa/s"
+
+msgid "2.50x1.00\""
+msgstr "2,50 x 1,00 \""
+
+msgid "2.50x2.00\""
+msgstr "2,50 x 2,00 \""
+
+msgid "2.75x1.25\""
+msgstr "2,75 x 1,25 \""
+
+msgid "2.9 x 1\""
+msgstr "2,9 x 1 \""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 mm/s"
+
+msgid "200 mm/sec."
+msgstr "200 mm/s"
+
+msgid "203dpi"
+msgstr "203 dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "24-nastainen"
+
+msgid "240x72dpi"
+msgstr "240 x 72 dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 mm/s"
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 tuumaa/s"
+
+msgid "3.00x1.00\""
+msgstr "3,00 x 1,00 \""
+
+msgid "3.00x1.25\""
+msgstr "3,00 x 1,25 \""
+
+msgid "3.00x2.00\""
+msgstr "3,00 x 2,00 \""
+
+msgid "3.00x3.00\""
+msgstr "3,00 x 3,00 \""
+
+msgid "3.00x5.00\""
+msgstr "3,00 x 5,00 \""
+
+msgid "3.25x2.00\""
+msgstr "3,25 x 2,00 \""
+
+msgid "3.25x5.00\""
+msgstr "3,25 x 5,00 \""
+
+msgid "3.25x5.50\""
+msgstr "3,25 x 5,50 \""
+
+msgid "3.25x5.83\""
+msgstr "3,25 x 5,83 \""
+
+msgid "3.25x7.83\""
+msgstr "3,25 x 7,83 \""
+
+msgid "3.5\" Disk"
+msgstr "3,5 \" levy"
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "3,5 \" levy - 2 1/8 x 2 3/4 \""
+
+msgid "3.50x1.00\""
+msgstr "3,50 x 1,00 \""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 mm/s"
+
+msgid "300 mm/sec."
+msgstr "300 mm/s"
+
+msgid "300dpi"
+msgstr "300 dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360 dpi"
+
+msgid "360x180dpi"
+msgstr "360 x 180 dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 tuumaa/s"
+
+msgid "4.00x1.00\""
+msgstr "4,00 x 1,00 \""
+
+msgid "4.00x13.00\""
+msgstr "4,00 x 13,00 \""
+
+msgid "4.00x2.00\""
+msgstr "4,00 x 2,00 \""
+
+msgid "4.00x2.50\""
+msgstr "4,00 x 2,50 \""
+
+msgid "4.00x3.00\""
+msgstr "4,00 x 3,00 \""
+
+msgid "4.00x4.00\""
+msgstr "4,00 x 4,00 \""
+
+msgid "4.00x5.00\""
+msgstr "4,00 x 5,00 \""
+
+msgid "4.00x6.00\""
+msgstr "4,00 x 6,00 \""
+
+msgid "4.00x6.50\""
+msgstr "4,00 x 6,50 \""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 mm/s"
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 tuumaa/s"
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 tuumaa/s"
+
+msgid "6.00x1.00\""
+msgstr "6,00 x 1,00 \""
+
+msgid "6.00x2.00\""
+msgstr "6,00 x 2,00 \""
+
+msgid "6.00x3.00\""
+msgstr "6,00 x 3,00 \""
+
+msgid "6.00x4.00\""
+msgstr "6,00 x 4,00 \""
+
+msgid "6.00x5.00\""
+msgstr "6,00 x 5,00 \""
+
+msgid "6.00x6.00\""
+msgstr "6,00 x 6,00 \""
+
+msgid "6.00x6.50\""
+msgstr "6,00 x 6,50 \""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/s"
+
+msgid "600dpi"
+msgstr "600 dpi"
+
+msgid "60dpi"
+msgstr "60 dpi"
+
+msgid "60x720dpi"
+msgstr "60 x 720 dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 tuumaa/s"
+
+msgid "7 x 9\""
+msgstr "7 x 9 \""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720 dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 tuumaa/s"
+
+msgid "8 x 10\""
+msgstr "8 x 10 \""
+
+msgid "8.00x1.00\""
+msgstr "8,00 x 1,00 \""
+
+msgid "8.00x2.00\""
+msgstr "8,00 x 2,00 \""
+
+msgid "8.00x3.00\""
+msgstr "8,00 x 3,00 \""
+
+msgid "8.00x4.00\""
+msgstr "8,00 x 4,00 \""
+
+msgid "8.00x5.00\""
+msgstr "8,00 x 5,00 \""
+
+msgid "8.00x6.00\""
+msgstr "8,00 x 6,00 \""
+
+msgid "8.00x6.50\""
+msgstr "8,00 x 6,50 \""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/s"
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 tuumaa/s"
+
+msgid "9 x 11\""
+msgstr "9 x 11 \""
+
+msgid "9 x 12\""
+msgstr "9 x 12 \""
+
+msgid "9-Pin Series"
+msgstr "9-nastainen"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?Virheellinen ohje tuntematon komento\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (ylikokoinen)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (ylikokoinen)"
+
+msgid "A4 (Small)"
+msgstr "A4 (pieni)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (ylikokoinen)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "Hyväksy töitä"
+
+msgid "Accepted"
+msgstr "Hyväksytty"
+
+msgid "Add Class"
+msgstr "Lisää luokka"
+
+msgid "Add Printer"
+msgstr "Lisää tulostin"
+
+msgid "Add RSS Subscription"
+msgstr "Lisää RSS-tilaus"
+
+msgid "Address"
+msgstr "Osoite"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "Osoite - 1 1/8 x 3 1/2 \""
+
+msgid "Administration"
+msgstr "Ylläpito"
+
+msgid "Always"
+msgstr "Aina"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "Applikaattori"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "Virheellinen NULL dests -osoitin"
+
+msgid "Bad OpenGroup"
+msgstr "Virheellinen OpenGroup"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "Virheellinen OpenUI/JCLOpenUI"
+
+msgid "Bad OrderDependency"
+msgstr "Virheellinen OrderDependency"
+
+msgid "Bad Request"
+msgstr "Virheellinen pyyntö"
+
+msgid "Bad SNMP version number"
+msgstr "Virheellinen SNMP-versionumero"
+
+msgid "Bad UIConstraints"
+msgstr "Virheellinen UIConstraints"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Virheellinen kopioiden määrä %d."
+
+msgid "Bad custom parameter"
+msgstr "Virheellinen muokattu parametri"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Virheellinen kirjasinattribuutti: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Virheellinen number-up-arvo %d."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Virheelliset page-ranges-arvot %d - %d."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Otsikot"
+
+msgid "Billing Information: "
+msgstr "Laskutustiedot: "
+
+msgid "Bond Paper"
+msgstr "Bond-paperi"
+
+msgid "C0 Envelope"
+msgstr "C0 Envelope"
+
+msgid "C1 Envelope"
+msgstr "C1 Envelope"
+
+msgid "C2 Envelope"
+msgstr "C2 Envelope"
+
+msgid "C3 Envelope"
+msgstr "C3 Envelope"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "C4 Envelope"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "C5 Envelope"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "C6 Envelope"
+
+msgid "C65 Envelope"
+msgstr "C65 Envelope"
+
+msgid "C7 Envelope"
+msgstr "C7 Envelope"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "CPCL-tarratulostin"
+
+msgid "Cancel RSS Subscription"
+msgstr "Peru RSS-tilaus"
+
+msgid "Change Settings"
+msgstr "Muuta asetuksia"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Chou3 Envelope"
+
+msgid "Chou4 Envelope"
+msgstr "Chou4 Envelope"
+
+msgid "Classes"
+msgstr "Luokat"
+
+msgid "Clean Print Heads"
+msgstr "Puhdista tulostuspäät"
+
+msgid "Color"
+msgstr "Väri"
+
+msgid "Color Mode"
+msgstr "Väritila"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"Komennot voidaan lyhentää. Komennot ovat:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "Yhteisönimi käyttää määrittämätöntä pituutta"
+
+msgid "Continue"
+msgstr "Jatka"
+
+msgid "Continuous"
+msgstr "Jatkuva"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Luotu"
+
+msgid "Created On: "
+msgstr "Luotu: "
+
+msgid "Custom"
+msgstr "Muokattu"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Leikkaa"
+
+msgid "Cutter"
+msgstr "Leikkaaja"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "DL Envelope"
+
+msgid "Dark"
+msgstr "Tumma"
+
+msgid "Darkness"
+msgstr "Tummuus"
+
+msgid "Delete Class"
+msgstr "Poista luokka"
+
+msgid "Delete Printer"
+msgstr "Poista tulostin"
+
+msgid "Description: "
+msgstr "Kuvaus: "
+
+msgid "DeskJet Series"
+msgstr "DeskJet-sarja"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "Kohde â€%s†ei vastaanota töitä."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"Laite: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "Suora lämpömedia"
+
+msgid "Disabled"
+msgstr "Pois käytöstä"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "Dokumenttia %d ei löytynyt työstä %d."
+
+msgid "Double Postcard"
+msgstr "Double Postcard"
+
+msgid "Driver Name: "
+msgstr "Ajurin nimi: "
+
+msgid "Driver Version: "
+msgstr "Ajurin versio: "
+
+msgid "Duplexer"
+msgstr "Duplekseri"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: ei voida varata muistia sivutiedolle: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: ei voida varata muistia sivutaululle: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "EPL1-tarratulostin"
+
+msgid "EPL2 Label Printer"
+msgstr "EPL2-tarratulostin"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: Virheellinen merkistötiedosto %s\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: Virheellinen merkistötyyppi %s\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: Virheellinen kirjasinkuvausrivi: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: Virheellinen tekstin suunta %s\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: Virheellinen tekstin leveys %s\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: Virhe %d lähetettäessä PAPSendData-pyyntöä: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: Merkistötiedostossa %s ei ole kirjasimia\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: Tulostin ei vastaa\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: Tulostin lähetti odottamattoman EOF:n\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: Etäpalvelin ei hyväksynyt ohjaustiedostoa (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: Etäpalvelin ei hyväksynyt datatiedostoa (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr "ERROR: Lähetettäessä dataa tulostimelle tapahtui aikakatkaisuvirhe\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: Tiedostoa %d ei voida lisätä työhön: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: Työtä %d ei voida peruuttaa: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: PDF-tiedostoa ei voida kopioida"
+
+msgid "ERROR: Unable to create pipe"
+msgstr ""
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: Socketia ei voida luoda"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr "ERROR: Tilapäistä pakattua tulostustiedostoa ei voida luoda: %s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: Tilapäistiedostoa ei voida luoda"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: pictwpstops:ia ei voida suorittaa: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: gs-ohjelmaa ei voida suorittaa"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: pdftops-ohjelmaa ei voida suorittaa"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: pictwpstops:ia ei voida forkata: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: PAP-pyyntöä ei voida hakea"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: PAP-vastausta ei voida hakea"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr "ERROR: Tulostimen â€%s†PPD-tiedostoa ei voida hakea - %s.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: Oletusarvoista AppleTalk-vyöhykettä ei voida hakea"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: PAP-vastausta ei voida etsiä"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: AppleTalk-tulostimia ei voida etsiä"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: AppleTalk-osoitteita ei voida tehdä"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: Kohdetta â€%s†ei voida avata - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: Kohdetta %s ei voida avata: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: Otsikkotiedostoa â€%s†ei voida avata - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: Laitetiedostoa â€%s†ei voida avata: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: Tiedostoa â€%s†ei voida avata - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: Tiedostoa â€%s†ei voida avata: %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: Tulostustiedostoa â€%s†ei voida avata: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: Tulostustiedostoa %s ei voida avata - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: Tulostustiedostoa %s ei voida avata: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr "ERROR: Tilapäistä pakattua tulostustiedostoa ei voida avata: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: Tulostusdataa ei voida lukea"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: Porttia ei voida varata"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: Tiedostossa ei voida siirtyä kohtaan %ld - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: Tiedostossa ei voida siirtyä kohtaan %lld - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: LPD-komentoa ei voida lähettää"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: PAP tickle -pyyntöä ei voida lähettää"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: Alkuperäistä PAP send data -pyyntöä ei voida lähettää"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: Tulostustiedostoa ei voida lähettää tulostimelle"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: Loppu-NUL:ia ei voida lähettää tulostimelle"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: pictwpstops:ia ei voida odottaa: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: %d tavua ei voida kirjoittaa kohteeseen â€%sâ€: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: Ohjaustiedostoa ei voida kirjoittaa"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: Tulostusdataa ei voida kirjoittaa"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: Tulostusdataa ei voida kirjoittaa: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr "ERROR: Pakkaamatonta dokumenttidataa ei voida kirjoittaa: %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: Tuntematon tiedostojärjestys â€%sâ€\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: Tuntematon muotomerkki â€%câ€\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: Tuntematon tulostustila â€%sâ€\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: select() epäonnistui"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: tulostustiedostoa ei voida statata"
+
+msgid "Edit Configuration File"
+msgstr "Muokkaa asetustiedostoa"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Loppuotsikko"
+
+msgid "English"
+msgstr "Finnish"
+
+msgid "Enter old password:"
+msgstr "Syötä vanha salasana:"
+
+msgid "Enter password again:"
+msgstr "Syötä salasana uudelleen:"
+
+msgid "Enter password:"
+msgstr "Syötä salasana:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Syötä oma käyttäjätunnuksesi ja salasanasi tai rootin käyttäjätunnus ja "
+"salasana tämän sivun käyttämistä varten. Jos käytät Kerberos-todentamista, "
+"varmista, että sinulla on kelvollinen Kerberos-lippu."
+
+msgid "Envelope Feed"
+msgstr "Kirjekuoren syöttö"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Virhekäytäntö"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "Joka 10. tarra"
+
+msgid "Every 2 Labels"
+msgstr "Joka 2. tarra"
+
+msgid "Every 3 Labels"
+msgstr "Joka 3. tarra"
+
+msgid "Every 4 Labels"
+msgstr "Joka 4. tarra"
+
+msgid "Every 5 Labels"
+msgstr "Joka 5. tarra"
+
+msgid "Every 6 Labels"
+msgstr "Joka 6. tarra"
+
+msgid "Every 7 Labels"
+msgstr "Joka 7. tarra"
+
+msgid "Every 8 Labels"
+msgstr "Joka 8. tarra"
+
+msgid "Every 9 Labels"
+msgstr "Joka 9. tarra"
+
+msgid "Every Label"
+msgstr "Joka tarra"
+
+msgid "Expectation Failed"
+msgstr "Odotus epäonnistui"
+
+msgid "Export Printers to Samba"
+msgstr "Vie tulostimet Sambaan"
+
+msgid "FAIL\n"
+msgstr "FAIL\n"
+
+msgid "File Folder"
+msgstr "Arkistokansio"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Arkistokansio - 9/16 x 3 7/16 \""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"Tiedostolaitteiden osoitteet on poistettu käytöstä! Voit ottaa ne käyttöön â€%"
+"s/cupsd.confâ€-tiedoston FileDevice-säännöllä."
+
+msgid "Folio"
+msgstr "Folio"
+
+msgid "Forbidden"
+msgstr "Kielletty"
+
+msgid "General"
+msgstr "Yleiset"
+
+msgid "Generic"
+msgstr "Yleinen"
+
+msgid "German FanFold"
+msgstr "German FanFold"
+
+msgid "German FanFold Legal"
+msgstr "German FanFold Legal"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU käyttää määrittämätöntä pituutta"
+
+msgid "Glossy Paper"
+msgstr "Kiiltävä paperi"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Harmaasävy"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Riippukansio"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Riippukansio - 9/16 x 2 \""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk poistettu käytöstä järjestelmäasetuksissa\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk poistettu käytöstä järjestelmäasetuksissa.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: Perutaan tulostustyötä...\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: Yhteydessä tulostimeen...\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: Yhdistetään tulostimeen...\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: Ohjaustiedoston lähetys onnistui\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr ""
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: Datatiedoston lähetys onnistui\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: Muotoillaan sivua %d...\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: Ladataan kuvatiedostoa...\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: Etsitään tulostinta...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: Avataan yhteyttä\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr ""
+"INFO: Tulostustiedosto lähetetty, odotetaan tulostuksen valmistumista...\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: Tulostin varattu; yritetään uudelleen 10 sekunnin kuluttua...\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: Tulostin varattu; yritetään uudelleen 30 sekunnin kuluttua...\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: Tulostin varattu; yritetään uudelleen 5 sekunnin kuluttua...\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr "INFO: Tulostin ei tue IPP-versiota %d.%d. Yritetään IPP/1.0:aa...\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr ""
+"INFO: Tulostin on varattu; yritetään uudelleen 5 sekunnin kuluttua...\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: Tulostin on tällä hetkellä offline.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: Tulostin on tällä hetkellä offline.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: Tulostin on nyt online.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: Tulostin on offline.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr ""
+"INFO: Tulostinta ei ole yhdistetty; yritetään uudelleen 30 sekunnin "
+"kuluttua...\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: Tulostetaan sivua %d, %d %% suoritettu...\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: Tulostetaan sivua %d...\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: Valmis tulostamaan.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: Lähetetään ohjaustiedostoa (%lu tavua)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: Lähetetään ohjaustiedostoa (%u tavua)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: Lähetetään dataa\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: Lähetetään datatiedostoa (%ld tavua)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: Lähetetään datatiedostoa (%lld tavua)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: Lähetetään tulostusdataa...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: Lähetettiin tulostustiedosto, %ld tavua...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: Lähetettiin tulostustiedosto, %lld tavua...\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: Lähetetään LPR-työtä, %.0f %% suoritettu...\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr ""
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: Tulostimeen ei saada yhteyttä, jonotetaan luokan seuraavalle "
+"tulostimelle...\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: Käytetään oletusarvoista AppleTalk-vyöhykettä â€%sâ€\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: Odotetaan työn valmistumista...\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: Odotetaan, että tulostin tulee käytettäväksi...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "ISO B4 Envelope"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (ylikokoinen)"
+
+msgid "ISO B5 Envelope"
+msgstr "ISO B5 Envelope"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "ISO B6 Envelope"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "Virheellinen ohjausmerkki"
+
+msgid "Illegal main keyword string"
+msgstr "Virheellinen pääavainsanan merkkijono"
+
+msgid "Illegal option keyword string"
+msgstr "Virheellinen valinta-avainsanan merkkijono"
+
+msgid "Illegal translation string"
+msgstr "Virheellinen käännösmerkkijono"
+
+msgid "Illegal whitespace character"
+msgstr "Virheellinen tyhjä merkki"
+
+msgid "Installable Options"
+msgstr "Asennettavat lisävarusteet"
+
+msgid "Installed"
+msgstr "Asennettu"
+
+msgid "IntelliBar Label Printer"
+msgstr "IntelliBar-tarratulostin"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr ""
+
+msgid "Internal error"
+msgstr "Sisäinen virhe"
+
+msgid "Internet Postage 2-Part"
+msgstr "Internet-postimerkki kaksiosainen"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Internet-postimerkki kaksiosainen - 2 1/4 x 7 1/2 \""
+
+msgid "Internet Postage 3-Part"
+msgstr "Internet-postimerkki kolmiosainen"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Internet-postimerkki kolmiosainen - 2 1/4 x 7 \""
+
+msgid "Internet Printing Protocol"
+msgstr "Internet Printing Protocol"
+
+msgid "Invite Envelope"
+msgstr "Kutsun kirjekuori"
+
+msgid "Italian Envelope"
+msgstr "Italialainen kirjekuori"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "Työ %d on jo keskeytetty - ei voida perua."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "Työ %d on jo peruttu - ei voida perua."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "Työ %d on jo suoritettu - ei voida perua."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "Työ suoritettu"
+
+msgid "Job Created"
+msgstr "Työ luotu"
+
+msgid "Job ID: "
+msgstr "Työn tunnus: "
+
+msgid "Job Options Changed"
+msgstr "Työn valintoja muutettu"
+
+msgid "Job Stopped"
+msgstr "Työ pysäytetty"
+
+msgid "Job UUID: "
+msgstr "Työn UUID: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "Työ on suoritettu eikä sitä voida muuttaa."
+
+msgid "Job operation failed:"
+msgstr "Työtoiminto epäonnistui:"
+
+msgid "Job state cannot be changed."
+msgstr "Työn tilaa ei voida muuttaa."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "Työt"
+
+msgid "Kaku2 Envelope"
+msgstr "Kaku2 Envelope"
+
+msgid "Kaku3 Envelope"
+msgstr "Kaku3 Envelope"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "LPD/LPR-palvelin tai -tulostin"
+
+msgid "Label Printer"
+msgstr "Tarratulostin"
+
+msgid "Label Top"
+msgstr "Tarran yläpuoli"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Suuri osoite"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Suuri osoite - 1 4/10 x 3 1/2 \""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet Series PCL 4/5"
+
+msgid "Light"
+msgstr "Vaalea"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Rivi on pidempi kuin suurin sallittu (255 merkkiä)"
+
+msgid "List Available Printers"
+msgstr "Luetteloi käytettävissä olevat tulostimet"
+
+msgid "Location: "
+msgstr "Sijainti: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "Pitkä reuna (pysty)"
+
+msgid "Make and Model: "
+msgstr "Merkki ja malli: "
+
+msgid "Manual Feed"
+msgstr "Käsinsyöttö"
+
+msgid "Media Dimensions: "
+msgstr "Median mitat: "
+
+msgid "Media Limits: "
+msgstr "Median rajat: "
+
+msgid "Media Name: "
+msgstr "Median nimi: "
+
+msgid "Media Size"
+msgstr "Median koko"
+
+msgid "Media Source"
+msgstr "Median lähde"
+
+msgid "Media Tracking"
+msgstr "Median seuranta"
+
+msgid "Media Type"
+msgstr "Median tyyppi"
+
+msgid "Medium"
+msgstr "Keskikokoinen"
+
+msgid "Memory allocation error"
+msgstr "Muistinvarausvirhe"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "PPD-Adobe-4.x-otsake puuttuu"
+
+msgid "Missing asterisk in column 1"
+msgstr "Tähtimerkki puuttuu sarakkeesta 1"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "Arvomerkkijono puuttuu"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Malli: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "Muokkaa luokkaa"
+
+msgid "Modify Printer"
+msgstr "Muokkaa tulostinta"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Monarch Envelope"
+
+msgid "Move All Jobs"
+msgstr "Siirrä kaikki työt"
+
+msgid "Move Job"
+msgstr "Siirrä työ"
+
+msgid "Moved Permanently"
+msgstr "Siirretty pysyvästi"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: Tulostustiedosto hyväksytty - työn tunnus %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: Tulostustiedosto hyväksytty - työn tunnus tuntematon.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "PPD-tiedoston osoitin NULL"
+
+msgid "Name OID uses indefinite length"
+msgstr "Nimi-OID käyttää määrittelemätöntä pituutta"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Ei koskaan"
+
+msgid "New Stylus Color Series"
+msgstr "Uusi Stylus Color Series"
+
+msgid "New Stylus Photo Series"
+msgstr "Uusi Stylus Photo Series"
+
+msgid "No"
+msgstr "Ei"
+
+msgid "No Content"
+msgstr "Ei sisältöä"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "Ei VarBind SEQUENCE:a"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "Ei aktiivista yhteyttä"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "Ei yhteisönimeä"
+
+msgid "No default printer"
+msgstr "Ei oletustulostinta"
+
+msgid "No destinations added."
+msgstr "Kohteita ei lisätty."
+
+msgid "No error-index"
+msgstr "Ei virheindeksiä"
+
+msgid "No error-status"
+msgstr "Ei virhetilaa"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "Ei nimi-OID:tä"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "Ei pyyntötunnistetta"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "Tilauksia ei löytynyt."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "Ei variable-bindings SEQUENCE:a"
+
+msgid "No version number"
+msgstr "Ei versionumeroa"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "Ei-jatkuva (mark sensing)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "Ei-jatkuva (web sensing)"
+
+msgid "Normal"
+msgstr "Normaali"
+
+msgid "Not Found"
+msgstr "Ei löytynyt"
+
+msgid "Not Implemented"
+msgstr "Ei toteutettu"
+
+msgid "Not Installed"
+msgstr "Ei asennettu"
+
+msgid "Not Modified"
+msgstr "Ei muokattu"
+
+msgid "Not Supported"
+msgstr "Ei tuettu"
+
+msgid "Not allowed to print."
+msgstr "Tulostaminen ei ole sallittua."
+
+msgid "Note"
+msgstr "Huomaa"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Off (1-Sided)"
+msgstr "Pois (yksipuolinen)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Verkko-ohjeet"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "kohteen %s avaaminen epäonnistui: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup ilman edeltävää CloseGroup:ia"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI ilman edeltävää CloseUI/JCLCloseUI:ta"
+
+msgid "Operation Policy"
+msgstr "Toimintakäytäntö"
+
+msgid "Options Installed"
+msgstr "Valinnat asennettu"
+
+msgid "Options: "
+msgstr "Valinnat: "
+
+msgid "Output Mode"
+msgstr "Tulostetila"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "Tulostimen %s tuloste lähetetään kohteeseen %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr "Tulostimen %s tuloste lähetetään etätulostimelle %s kohteessa %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "Tulostimen %s/%s tuloste lähetetään kohteeseen %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr "Tulostimen %s/%s tuloste lähetetään etätulostimelle %s kohteessa %s\n"
+
+msgid "PASS\n"
+msgstr "PASS\n"
+
+msgid "PCL Laser Printer"
+msgstr "PCL-lasertulostin"
+
+msgid "PRC1 Envelope"
+msgstr "PRC1 Envelope"
+
+msgid "PRC10 Envelope"
+msgstr "PRC10 Envelope"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "PRC2 Envelope"
+
+msgid "PRC3 Envelope"
+msgstr "PRC3 Envelope"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (ylikokoinen)"
+
+msgid "PRC4 Envelope"
+msgstr "PRC4 Envelope"
+
+msgid "PRC5 Envelope"
+msgstr "PRC5 Envelope"
+
+msgid "PRC6 Envelope"
+msgstr "PRC6 Envelope"
+
+msgid "PRC7 Envelope"
+msgstr "PRC7 Envelope"
+
+msgid "PRC8 Envelope"
+msgstr "PRC8 Envelope"
+
+msgid "PRC9 Envelope"
+msgstr "PRC9 Envelope"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "Paketti ei sisällä Get-Response-PDU:ta"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "Paketti ei ala SEQUENCE:lla"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "Salasana kohteelle %s kohteessa %s? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr ""
+"Kohteelle %s tarvitaan salasana kohteen %s käyttämiseen Samban kautta: "
+
+msgid "Pause Class"
+msgstr "Keskeytä luokka"
+
+msgid "Pause Printer"
+msgstr "Keskeytä tulostin"
+
+msgid "Peel-Off"
+msgstr "Irrotettava"
+
+msgid "Personal Envelope"
+msgstr "Personal Envelope"
+
+msgid "Photo"
+msgstr "Valokuva"
+
+msgid "Photo Labels"
+msgstr "Valokuvatarrat"
+
+msgid "Plain Paper"
+msgstr "Tavallinen paperi"
+
+msgid "Policies"
+msgstr "Käytännöt"
+
+msgid "Port Monitor"
+msgstr "Porttimonitori"
+
+msgid "PostScript Printer"
+msgstr "PostScript-tulostin"
+
+msgid "Postcard"
+msgstr "Postikortti"
+
+msgid "Print Density"
+msgstr "Tulostustiheys"
+
+msgid "Print Job:"
+msgstr "Tulosta työ:"
+
+msgid "Print Mode"
+msgstr "Tulostustila"
+
+msgid "Print Rate"
+msgstr "Tulostustaajuus"
+
+msgid "Print Self-Test Page"
+msgstr "Tulosta itsetestisivu"
+
+msgid "Print Speed"
+msgstr "Tulostusnopeus"
+
+msgid "Print Test Page"
+msgstr "Tulosta testisivu"
+
+msgid "Print and Cut"
+msgstr "Tulosta ja leikkaa"
+
+msgid "Print and Tear"
+msgstr "Tulosta ja revi"
+
+msgid "Printed For: "
+msgstr "Tulostettu kohteelle: "
+
+msgid "Printed From: "
+msgstr "Tulostettu kohteesta: "
+
+msgid "Printed On: "
+msgstr "Tulostettu: "
+
+msgid "Printer Added"
+msgstr "Tulostin lisätty"
+
+msgid "Printer Default"
+msgstr "Tulostimen oletus"
+
+msgid "Printer Deleted"
+msgstr "Tulostin poistettu"
+
+msgid "Printer Modified"
+msgstr "Tulostinta muokattu"
+
+msgid "Printer Name: "
+msgstr "Tulostimen nimi: "
+
+msgid "Printer Paused"
+msgstr "Tulostin keskeytetty"
+
+msgid "Printer Settings"
+msgstr "Tulostinasetukset"
+
+msgid "Printer:"
+msgstr "Tulostin:"
+
+msgid "Printers"
+msgstr "Tulostimet"
+
+msgid "Purge Jobs"
+msgstr "Poista työt"
+
+msgid "Quarto"
+msgstr "Quarto"
+
+msgid "Quota limit reached."
+msgstr "Kiintiöraja saavutettu."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr ""
+"Sija Omistaja Työ Tiedostot Koko yhteensä\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"Sija Omistaja Pri Työ Tiedostot Koko "
+"yhteensä\n"
+
+msgid "Reject Jobs"
+msgstr "Hylkää työt"
+
+msgid "Reprint After Error"
+msgstr "Tulosta uudelleen virheen jälkeen"
+
+msgid "Request Entity Too Large"
+msgstr "Pyydetty kohde liian suuri"
+
+msgid "Resolution"
+msgstr "Tarkkuus"
+
+msgid "Resume Class"
+msgstr "Jatka luokka"
+
+msgid "Resume Printer"
+msgstr "Jatka tulostin"
+
+msgid "Return Address"
+msgstr "Palautusosoite"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Palautusosoite - 3/4 x 2 \""
+
+msgid "Rewind"
+msgstr "Kelaa taaksepäin"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Suoritetaan komentoa: %s %s -N -A %s -c '%s'\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE käyttää määrittämätöntä pituutta"
+
+msgid "See Other"
+msgstr "Katso muu"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "Sarjaportti %d"
+
+msgid "Server Restarted"
+msgstr "Palvelin käynnistettiin uudelleen"
+
+msgid "Server Security Auditing"
+msgstr "Palvelimen turvallisuustarkastus"
+
+msgid "Server Started"
+msgstr "Palvelin käynnistetty"
+
+msgid "Server Stopped"
+msgstr "Palvelin pysäytetty"
+
+msgid "Service Unavailable"
+msgstr "Palvelu ei käytettävissä"
+
+msgid "Set Allowed Users"
+msgstr "Aseta sallitut käyttäjät"
+
+msgid "Set As Server Default"
+msgstr "Aseta palvelimen oletukseksi"
+
+msgid "Set Class Options"
+msgstr "Aseta luokan valinnat"
+
+msgid "Set Printer Options"
+msgstr "Aseta tulostimen valinnat"
+
+msgid "Set Publishing"
+msgstr "Aseta julkaisu"
+
+msgid "Shipping Address"
+msgstr "Lähetysosoite"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "Lähetysosoite - 2 5/16 x 4 \""
+
+msgid "Short-Edge (Landscape)"
+msgstr "Lyhyt reuna (vaaka)"
+
+msgid "Special Paper"
+msgstr "Erikoispaperi"
+
+msgid "Standard"
+msgstr "Standardi"
+
+msgid "Starting Banner"
+msgstr "Aloitetaan otsikkoa"
+
+msgid "Statement"
+msgstr "Lausunto"
+
+msgid "Stylus Color Series"
+msgstr "Stylus Color Series"
+
+msgid "Stylus Photo Series"
+msgstr "Stylus Photo Series"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "Vaihdetaan protokollia"
+
+msgid "Tabloid"
+msgstr "Tabloid"
+
+msgid "Tabloid (Oversize)"
+msgstr "Tabloid (ylisuuri)"
+
+msgid "Tear"
+msgstr "Revi"
+
+msgid "Tear-Off"
+msgstr "Repäisy"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Repäisykohdan säätö"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "PPD-tiedostoa â€%s†ei löytynyt."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "PPD-tiedostoa â€%s†ei voitu avata: %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Luokan nimi voi sisältää enintään 127 näkyvää merkkiä eikä voi sisältää "
+"välilyöntejä, kauttaviivoja (/) eikä ristikkomerkkiä (#)."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+"notify-lease-duration-attribuuttia ei voida käyttää työtilausten kanssa."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Tulostimen nimi voi sisältää enintään 127 näkyvää merkkiä eikä voi sisältää "
+"välilyöntejä, kauttaviivoja (/) eikä ristikkomerkkiä (#)."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "Tulostinta tai luokkaa ei löytynyt."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "printer-uri â€%s†sisältää virheellisiä merkkejä."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr ""
+"printer-uri:n on oltava muotoa â€ipp://PALVELINNIMI/classes/LUOKANNIMIâ€."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+"printer-uri:n on oltava muotoa â€ipp://PALVELINNIMI/printers/TULOSTIMENNIMIâ€."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"Tilauksen nimi ei voi sisältää välilyöntejä, kauttaviivoja (/), "
+"kysymysmerkkejä (?) eikä ristikkomerkkiä (#)."
+
+msgid "There are too many subscriptions."
+msgstr "Tilauksia on liikaa."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "Lämpösiirtomedia"
+
+msgid "Title: "
+msgstr "Otsikko: "
+
+msgid "Too many active jobs."
+msgstr "Liikaa aktiivisia töitä."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "Kalvo"
+
+msgid "Tray"
+msgstr "Alusta"
+
+msgid "Tray 1"
+msgstr "Alusta 1"
+
+msgid "Tray 2"
+msgstr "Alusta 2"
+
+msgid "Tray 3"
+msgstr "Alusta 3"
+
+msgid "Tray 4"
+msgstr "Alusta 4"
+
+msgid "URI Too Long"
+msgstr "Osoite liian pitkä"
+
+msgid "US Executive"
+msgstr "US Executive"
+
+msgid "US Fanfold"
+msgstr "US Fanfold"
+
+msgid "US Ledger"
+msgstr "US Ledger"
+
+msgid "US Legal"
+msgstr "US Legal"
+
+msgid "US Legal (Oversize)"
+msgstr "US Legal (ylikokoinen)"
+
+msgid "US Letter"
+msgstr "US Letter"
+
+msgid "US Letter (Oversize)"
+msgstr "US Letter (ylikokoinen)"
+
+msgid "US Letter (Small)"
+msgstr "US Letter (pieni)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "USB-sarjaportti %d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "cupsd.conf-tiedostoa ei voida käyttää:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "RSS-tilausta ei voida lisätä:"
+
+msgid "Unable to add class:"
+msgstr "Luokkaa ei voida lisätä:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "Tulostinta ei voida lisätä:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "RSS-tilausta ei voida perua:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "printer-is-shared-attribuuttia ei voida muuttaa:"
+
+msgid "Unable to change printer:"
+msgstr "Tulostinta ei voida vaihtaa:"
+
+msgid "Unable to change server settings:"
+msgstr "Palvelimen asetuksia ei voida muuttaa:"
+
+msgid "Unable to connect to host."
+msgstr "Palvelimeen ei voida yhdistää."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "Tilapäistiedostoa ei voida luoda:"
+
+msgid "Unable to delete class:"
+msgstr "Luokkaa ei voida poistaa:"
+
+msgid "Unable to delete printer:"
+msgstr "Tulostinta ei voida poistaa:"
+
+msgid "Unable to do maintenance command:"
+msgstr "Ylläpitokomentoa ei voida suorittaa:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "Luokkaluetteloa ei voida hakea:"
+
+msgid "Unable to get class status:"
+msgstr "Luokan tilaa ei voida hakea:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "Luetteloa tulostinajureista ei voida hakea:"
+
+msgid "Unable to get printer attributes:"
+msgstr "Tulostimen attribuutteja ei voida hakea:"
+
+msgid "Unable to get printer list:"
+msgstr "Tulostinluetteloa ei voida hakea:"
+
+msgid "Unable to get printer status:"
+msgstr "Tulostimen tilaa ei voida hakea:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "Luokkaa ei voida muokata:"
+
+msgid "Unable to modify printer:"
+msgstr "Tulostinta ei voida muokata:"
+
+msgid "Unable to move job"
+msgstr "Työtä ei voida siirtää"
+
+msgid "Unable to move jobs"
+msgstr "Töitä ei voida siirtää"
+
+msgid "Unable to open PPD file"
+msgstr "PPD-tiedostoa ei voida avata"
+
+msgid "Unable to open PPD file:"
+msgstr "PPD-tiedostoa ei voida avata:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "cupsd.conf-tiedostoa ei voida avata:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "Testisivua ei voida tulostaa:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "Kohdetta â€%s†ei voida suorittaa: %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "Valintoja ei voida asettaa:"
+
+msgid "Unable to set server default:"
+msgstr "Palvelimen oletusta ei voida asettaa:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "cupsd.conf-tiedostoa ei voida lähettää:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "Valtuuttamaton"
+
+msgid "Units"
+msgstr "Yksiköt"
+
+msgid "Unknown"
+msgstr "Tuntematon"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "Tuntematon printer-error-policy â€%sâ€."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "Tuntematon printer-op-policy â€%sâ€."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Ei-tuettu arvotyyppi"
+
+msgid "Upgrade Required"
+msgstr "Päivitys vaaditaan"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Käyttö:\n"
+"\n"
+" lpadmin [-h palvelin] -d kohde\n"
+" lpadmin [-h palvelin] -x kohde\n"
+" lpadmin [-h palvelin] -p tulostin [-c lisää-luokka] [-i liitäntä] [-m "
+"malli]\n"
+" [-r poista-luokka] [-v laite] [-D kuvaus]\n"
+" [-P ppd-tiedosto] [-o nimi=arvo]\n"
+" [-u allow:käyttäjä,käyttäjä] [-u deny:käyttäjä,"
+"käyttäjä]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "Käyttö: %s työ käyttäjä otsikko kopioita valinnat [tiedostonimi]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "Käyttö: %s job-id käyttäjä otsikko kopioita valinnat [tiedosto]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "Käyttö: %s job-id käyttäjä otsikko kopioita valinnat tiedosto\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Käyttö: cupsaddsmb [valitsimet] tulostin1 ... tulostinN\n"
+" cupsaddsmb [valitsimet] -a\n"
+"\n"
+"Valitsimet:\n"
+" -E Salaa yhteys palvelimeen\n"
+" -H samba-palvelin Käytä nimettyä SAMBA-palvelinta\n"
+" -U samba-käyttäjä Todentaudu käyttäen nimettyä SAMBA-käyttäjää\n"
+" -a Vie kaikki tulostimet\n"
+" -h cups-palvelin Käytä nimettyä CUPS-palvelinta\n"
+" -v Ole monisanainen (näytä komennot)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Käyttö: cupsctl [valitsimet] [param=arvo ... paramN=arvoN]\n"
+"\n"
+"Valitsimet:\n"
+"\n"
+" -E Ota salaus käyttöön\n"
+" -U käyttäjätunnus Määrittele käyttäjätunnus\n"
+" -h palvelin[:portti] Määrittele palvelimen osoite\n"
+"\n"
+" --[no-]debug-logging Laita virheiden kirjaaminen päälle tai pois "
+"päältä\n"
+" --[no-]remote-admin Laita etähallinta päälle tai pois päältä\n"
+" --[no-]remote-any Salli tai estä pääsy internetistä\n"
+" --[no-]remote-printers Näytä tai kätke etätulostimet\n"
+" --[no-]share-printers Laita tulostinjako päälle tai pois päältä\n"
+" --[no-]user-cancel-any Salli tai estä käyttäjien perua mikä tahansa "
+"työ\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Käyttö: cupsd [-c määrittelytiedosto] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c määrittelytiedosto Lataa vaihtoehtoinen määrittelytiedosto\n"
+"-f Suorita etualalla\n"
+"-F Suorita etualalla, mutta irrota\n"
+"-h Näytä tämä käyttöohje\n"
+"-l Suorita cupsd launchd(8):sta\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Käyttö: cupstestdsc [valitsimet] tiedostonimi.ps [... tiedostonimi.ps]\n"
+" cupstestdsc [valitsimet] -\n"
+"\n"
+"Valitsimet:\n"
+"\n"
+" -h Näytä ohjelman käyttö\n"
+"\n"
+" Huomaa: tämä ohjelma tarkistaa vain DSC-kommentit, ei itse "
+"PostScriptiä.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Käyttö: lpmove työ/lähde kohde\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Käyttö: lpoptions [-h palvelin] [-E] -d tulostin\n"
+" lpoptions [-h palvelin] [-E] [-p tulostin] -l\n"
+" lpoptions [-h palvelin] [-E] -p tulostin -o valinta[=arvo] ...\n"
+" lpoptions [-h palvelin] [-E] -x tulostin\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Käyttö: lppasswd [-g ryhmätunnus]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Käyttö: lppasswd [-g ryhmätunnus] [käyttäjätunnus]\n"
+" lppasswd [-g ryhmätunnus] -a [käyttäjätunnus]\n"
+" lppasswd [-g ryhmätunnus] -x [käyttäjätunnus]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Käyttö: lpq [-P kohde] [-U käyttäjätunnus] [-h palvelinnimi[:portti]] [-l] "
+"[+aikaväli]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Käyttö: ppdc [valitsimet] tiedostonimi.drv [ ... tiedostonimiN.drv ]\n"
+"Valitsimet:\n"
+" -D nimi=arvo Aseta nimetty muuttuja arvoon.\n"
+" -I include-hakemisto Lisää include-hakemisto hakupolkuun.\n"
+" -c katalogi.po Lataa määritellyn viestikatalogin.\n"
+" -d tulostehakemisto Määrittele tulostehakemisto.\n"
+" -l kieli[,kieli,...] Määrittele tulostekieli (lokaali).\n"
+" -m Käytä ModelName-arvoa tiedostonimenä.\n"
+" -t Testaa PPD:t niiden luomisen sijasta.\n"
+" -v Ole monisanainen (useammat v-kirjaimet lisäävät "
+"monisanaisuutta).\n"
+" -z Pakkaa PPD-tiedostot GNU zipillä.\n"
+" --cr Päätä rivit CR:llä (Mac OS 9).\n"
+" --crlf Päätä rivit CR + LF:llä (Windows).\n"
+" --lf Päätä rivit LF:llä (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"Käyttö: ppdhtml [valitsimet] tiedostonimi.drv > tiedostonimi.html\n"
+" -D nimi=arvo Aseta nimetty muuttuja arvoon.\n"
+"Valinnat:\n"
+" -I include-hakemisto Lisää include-hakemisto hakupolkuun.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Käyttö: ppdi [valitsimet] tiedostonimi.ppd [ ... tiedostonimiN.ppd ]\n"
+"Valitsimet:\n"
+" -I include-hakemisto\n"
+" -o tiedostonimi.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Käyttö: ppdmerge [valitsimet] tiedostonimi.ppd [ ... tiedostonimiN.ppd ]\n"
+"Valitsimet:\n"
+" -o tiedostonimi.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"Käyttö: ppdpo [valitsimet] -o tiedostonimi.po tiedostonimi.drv [ ... "
+"tiedostonimiN.drv ]\n"
+"Valitsimet:\n"
+" -D nimi=arvo Aseta nimetty muuttuja arvoon.\n"
+" -I include-hakemisto Lisää include-hakemisto hakupolkuun.\n"
+" -v Ole monisanainen (useammat v-kirjaimet lisäävät "
+"monisanaisuutta).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Käyttö: snmp [palvelin-tai-ip-osoite]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Arvo käyttää määrittämätöntä pituutta"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind käyttää määrittämätöntä pituutta"
+
+msgid "Version uses indefinite length"
+msgstr "Versio käyttää määrittämätöntä pituutta"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: Lisätään vain %d ensimmäistä löydettyä tulostinta"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: waiteof-valinnalle â€%s†odotettiin totuusarvoa\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: Tulostin ei vastaa\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: Tulostin lähetti odottamattoman EOF:n\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: Kohdetta â€%s:%s†ei voida avata: %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: PAP status -pyyntöä ei voida lähettää"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: Odottamaton PAP-paketti tyyppiä %d\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: Tuntematon PAP-paketti tyyppiä %d\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: tilavalinnalle â€%s†odotettiin numeroarvoa\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Kyllä"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"Sivua on käytettävä käyttäen osoitetta <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+
+msgid "You4 Envelope"
+msgstr "You4 Envelope"
+
+msgid "ZPL Label Printer"
+msgstr "ZPL-tarratulostin"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "keskeytetty"
+
+msgid "canceled"
+msgstr "peruttu"
+
+msgid "completed"
+msgstr "suoritettu"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr "convert: Määrittele muunnettava tiedosto f-valitsimella.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "cups-deviced:n suorittaminen epäonnistui."
+
+msgid "cups-driverd failed to execute."
+msgstr "cups-driverd:n suorittaminen epäonnistui."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: Tulostimelle â€%s†ei ole PPD-tiedostoa - %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: Palvelimeen ei voida yhdistää: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr ""
+"cupsd: launchd(8)-tukea ei ole käännetty mukaan, toimitaan normaalitilassa.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: Työtiedostoa ei voida hakea - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd: q-valitsin ei ole yhteensopiva v-valitsimen kanssa.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd: v-valitsin ei ole yhteensopiva q-valitsimen kanssa.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "laite kohteelle %s/%s: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "laite kohteelle %s: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "error-index käyttää määrittämätöntä pituutta"
+
+msgid "error-status uses indefinite length"
+msgstr "error-status käyttää määrittämätöntä pituutta"
+
+msgid "held"
+msgstr "pidetty"
+
+msgid "help\t\tget help on commands\n"
+msgstr "help\t\tsaat tietoja komennoista\n"
+
+msgid "idle"
+msgstr "toimeton"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: Tulostin %s on jo luokan %s jäsen.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: Tulostin %s ei ole luokan %s jäsen.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: Palvelimeen ei voida yhdistää: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: PPD-tiedostoa â€%s†ei voida avata - %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: Tiedostoa â€%s†ei voida avata: %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: Palvelimeen ei voida yhdistää: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: Tulostinta tai esiintymää ei voida lisätä: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: PPD-tiedostoa ei voida hakea kohteelle %s: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: Salasana hylättiin.\n"
+"Salasanan on oltava vähintään 6 merkkiä pitkä, se ei saa sisältää\n"
+"käyttäjätunnustasi ja sen on sisällettävä vähintään yksi kirjain ja numero.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: Salasanamerkkijonoa ei voida kopioida: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: Salasanatiedostoa ei voida avata: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: Salasanatiedostoon ei voida kirjoittaa: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr "lppasswd: vanhaa salasanatiedostoa ei voitu varmuuskopioida: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: salasanatiedoston nimeä ei voitu muuttaa: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: käyttäjää â€%s†ja ryhmää â€%s†ei ole olemassa.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "jäsen luokassa %s:\n"
+
+msgid "no entries\n"
+msgstr "ei tietueita\n"
+
+msgid "no system default destination\n"
+msgstr "ei järjestelmän oletuskohdetta\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "odottaa"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: Lisätään include-hakemistoa â€%sâ€...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: Lisätään/päivitetään käyttöliittymätekstiä kohteesta %s...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: Virheellinen totuusarvo (%s) rivillä %d / %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: Virheellinen muuttujan korvaus ($%c) rivillä %d / %s.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: Odotettiin totuusarvoa rivillä %d / %s.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: Odotettiin vaihtoehtokoodia rivillä %d / %s.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: Odotettiin vaihtoehtonimeä/-tekstiä rivillä %d / %s.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: Ladataan ajurin tietotiedostoa â€%sâ€...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: Ladataan viestejä lokaalille â€%sâ€...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: Ladataan viestejä kohteesta â€%sâ€...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: PPD-tiedostoa â€%s†ei voida luoda - %s.\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: Tulostushakemistoa %s ei voida luoda: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: Tulostusputkia ei voida luoda: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: cupstestppd:ia ei voida suorittaa: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: Lokalisointia kohteelle â€%s†ei löytynyt - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: Lokalisointitiedostoa â€%s†ei voitu ladata - %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: Määrittelemätön muuttuja (%s) rivillä %d / %s.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: Kirjoitetaan %s...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: Kirjoitetaan PPD-tiedostoja hakemistoon â€%sâ€...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: Jätetään huomioimatta PPD-tiedosto %s...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: Kohdetta %s ei voida varmuuskopioida kohteeseen %s - %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "tulostin %s poissa käytöstä alkaen %s -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "tulostin %s on toimettomana. käytössä alkaen %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "tulostin %s tulostaa %s-%d. käytössä alkaen %s\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "tulostin %s/%s poissa käytöstä alkaen %s -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "tulostin %s/%s on toimettomana. käytössä alkaen %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "tulostin %s/%s tulostaa %s-%d. käytössä alkaen %s\n"
+
+msgid "processing"
+msgstr "käsitellään"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "pyynnön tunnus on %s-%d (%d tiedostoa)\n"
+
+msgid "request-id uses indefinite length"
+msgstr "request-id käyttää määrittämätöntä pituutta"
+
+msgid "scheduler is not running\n"
+msgstr "ajastin ei ole käynnissä\n"
+
+msgid "scheduler is running\n"
+msgstr "ajastin on käynnissä\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "kohteen %s stat epäonnistui: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "status\t\tnäytä taustaprosessin tila ja jono\n"
+
+msgid "stopped"
+msgstr "pysäytetty"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "järjestelmän oletuskohde: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "järjestelmän oletuskohde: %s/%s\n"
+
+msgid "unknown"
+msgstr "tuntematon"
+
+msgid "untitled"
+msgstr "nimetön"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindings käyttää määrittämätöntä pituutta"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " WARN Kohteella %s ei ole vastaavia valintoja!\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " WARN Oletusvaihtoehdot ovat ristiriidassa!\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " WARN Kaksipuoleisuusvalinnan avainsana %s ei ehkä toimi "
+#~ "odotetulla tavalla ja sen pitäisi olla nimeltään Duplex!\n"
+#~ " VIITE: sivu 122, osa 5.17.\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " WARN Tiedosto sisältää sekaisin CR-, LF- ja CR LF -"
+#~ "rivinvaihtoja!\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " WARN Rivi %d sisältää vain tyhjää!\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " WARN APDialogExtension-tiedosto â€%s†puuttuu\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " WARN APPrinterIconPath-tiedosto â€%s†puuttuu\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " WARN Muiden kuin Windowsin PPD-tiedostojen tulisi käyttää LF-"
+#~ "rivinvaihtoja eikä CR LF -rivinvaihtoja!\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " WARN Vanhentunut PPD-versio %.1f!\n"
+#~ " VIITE: sivu 42, osa 5.2.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " Kohdetta %s %s %s ei ole olemassa!\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s Virheellinen %s vaihtoehto %s!\n"
+#~ " VIITE: sivu 122, osa 5.17.\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr ""
+#~ " %s Virheellinen UTF-8 â€%s†käännösmerkkijono valinnalle %s!\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Virheellinen UTF-8 â€%s†käännösmerkkijono valinnalle %s, "
+#~ "vaihtoehto %s!\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Virheellinen cupsFilter-arvo â€%sâ€!\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s Virheellinen cupsICCProfile %s!\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Virheellinen cupsPreFilter-arvo â€%sâ€!\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Virheellinen cupsUIConstraints %s: â€%sâ€!\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s Virheellinen kieli â€%sâ€!\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s Tyhjä cupsUIConstraints %s!\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s Käännösmerkkijono â€%s†valinnalle %s puuttuu!\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Käännösmerkkijono â€%s†valinnalle %s puuttuu, vaihtoehto %s!\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Vaihtoehto *%s %s kohteessa UIConstraints â€*%s %s *%s %s†"
+#~ "puuttuu!\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr ""
+#~ " %s Vaihtoehto *%s %s kohteessa cupsUIConstraints %s: â€%s†"
+#~ "puuttuu!\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s cupsICCProfile-tiedosto â€%s†puuttuu!\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s cupsUIResolver %s puuttuu!\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Valinta %s kohteessa UIConstraints â€*%s %s *%s %s†puuttuu!\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr ""
+#~ " %s Valinta %s kohteessa cupsUIConstraints %s: â€%s†puuttuu!\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr " %s Tiedostossa ei ole peruskäännöstä â€%sâ€!\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s VAADITTU %s ei määrittele vaihtoehtoa None!\n"
+#~ " VIITE: sivu 122, osa 5.17.\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr ""
+#~ " %s cupsICCProfile %s hajautusarvo törmää kohteen %s kanssa!\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver %s aiheuttaa silmukan!\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Kohteen %s vaihtoehtojen nimet %s ja %s eroavat "
+#~ "toisistaan vain isojen ja pienten merkkien osalta!\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **FAIL** %s on oltava 1284DeviceID!\n"
+#~ " VIITE: sivu 72, osa 5.5.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** VIRHEELLINEN DefaultImageableArea %s!\n"
+#~ " VIITE: sivu 102, osa 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** VIRHEELLINEN DefaultPaperDimension %s!\n"
+#~ " VIITE: sivu 103, osa 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **FAIL** Virheellinen %s vaihtoehto %s!\n"
+#~ " VIITE: sivu 84, osa 5.9.\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr ""
+#~ " **FAIL** Virheellinen LanguageEncoding %s - pitää olla ISOLatin1!\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr ""
+#~ " **FAIL** Virheellinen LanguageVersion %s - pitää olla English!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **FAIL** Oletusarvoinen käännösmerkkijono valinnan %s "
+#~ "vaihtoehdolle %s sisältää 8-bittisiä merkkejä!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **FAIL** Oletusarvoinen käännösmerkkijono valinnalle %s sisältää 8-"
+#~ "bittisiä merkkejä!\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Ryhmien nimet %s ja %s eroavat toisistaan vain isojen ja "
+#~ "pienten merkkien osalta!\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr ""
+#~ " **FAIL** Useita esiintymiä kohteen %s vaihtoehtojen nimeä %s!\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Vaihtoehtojen nimet %s ja %s eroavat toisistaan vain "
+#~ "isojen ja pienten merkkien osalta!\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " Virheellinen %%%%BoundingBox: rivillä %d!\n"
+#~ " VIITE: sivu 39, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " Virheellinen %%%%Page: rivillä %d!\n"
+#~ " VIITE: sivu 53, %%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " Virheellinen %%%%Pages: rivillä %d!\n"
+#~ " VIITE: sivu 43, %%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " Rivi %d on pidempi kuin 255 merkkiä (%d)!\n"
+#~ " VIITE: sivu 25, Line Length\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " %!PS-Adobe-3.0 puuttuu ensimmäiseltä riviltä!\n"
+#~ " VIITE: sivu 17, 3.1 Conforming Documents\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " %%EndComments-kommentti puuttuu!\n"
+#~ " VIITE: sivu 41, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " %%BoundingBox:-kommentti puuttuu tai on virheellinen!\n"
+#~ " VIITE: sivu 39, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " %%Page:-kommentit puuttuvat tai ovat virheellisiä!\n"
+#~ " VIITE: sivu 53, %%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " %%Pages:-kommentti puuttuu tai on virheellinen!\n"
+#~ " VIITE: sivu 43, %%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " %d riviä ovat pidempiä kuin 255 merkkiä!\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " Liikaa %%BeginDocument-kommentteja!\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " Liikaa %%EndDocument-kommentteja!\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " Varoitus: tiedosto sisältää binääridataa!\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " Varoitus: tiedostossa ei ole %%EndComments-kommenttia!\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " Varoitus: tiedostossa on vanhentunut DSC-versio %.1f!\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s ei ole tuettu!"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: En tiedä mitä tehdä!\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: Virhe - %s ympäristömuuttujanimien kohdetta â€%s†ei ole olemassa!\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: Virhe - virheellinen työn tunnus!\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr ""
+#~ "%s: Virhe - tiedostoja ei voida tulostaa ja työtä muuttaa "
+#~ "samanaikaisesti!\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: Virhe - oletussyötevirrasta ei voida tulostaa, jos annetaan "
+#~ "tiedostoja tai työn tunnus!\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: Virhe - S-valitsimen jälkeen odotettiin merkistöä!\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: Virhe - T-valitsimen jälkeen odotettiin sisältötyyppiä!\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: Virhe - n-valitsimen jälkeen odotettiin kopioiden lukumäärää!\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s: Virhe - #-valitsimen jälkeen odotettiin kopioiden lukumäärää!\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: Virhe - P-valitsimen jälkeen odotettiin kohdetta!\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: Virhe - b-valitsimen jälkeen odotettiin kohdetta!\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: Virhe - d-valitsimen jälkeen odotettiin kohdetta!\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: Virhe - f-valitsimen jälkeen odotettiin muotoa!\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: Virhe - H-valitsimen jälkeen odotettiin pidon nimeä!\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: Virhe - H-valitsimen jälkeen odotettiin palvelinnimeä!\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: Virhe - h-valitsimen jälkeen odotettiin palvelinnimeä!\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: Virhe - y-valitsimen jälkeen odotettiin tilaluetteloa!\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: Virhe - %c-valitsimen jälkeen odotettiin nimeä!\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s: Virhe - o-valitsimen jälkeen odotettiin valintamerkkijonoa!\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: Virhe - P-valitsimen jälkeen odotettiin sivuluetteloa!\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: Virhe - %c-valitsimen jälkeen odotettiin tärkeyttä!\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s: Virhe - r-valitsimen jälkeen odotettiin syytekstiä!\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: Virhe - t-valitsimen jälkeen odotettiin otsikkoa!\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s: Virhe - U-valitsimen jälkeen odotettiin käyttäjätunnusta!\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s: Virhe - u-valitsimen jälkeen odotettiin käyttäjätunnusta!\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: Virhe - %c-valitsimen jälkeen odotettiin arvoa!\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: Virhe - W-valitsimen jälkeen tarvitaan â€completedâ€, â€not-completed†"
+#~ "tai â€allâ€!\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: Virhe - ajastin ei vastaa!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: Virhe - tuntematon kohde - â€%sâ€\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: Virhe - tuntematon kohde - â€%s/%sâ€\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: Virhe - tuntematon valitsin â€%câ€!\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: Virhe - tuntematon valitsin â€%sâ€!\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: i-valitsimen jälkeen odotettiin työn tunnusta!\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: Virheellinen kohdenimi luettelossa â€%sâ€!\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr ""
+#~ "%s: Tarvitaan työn tunnus (â€-i jobidâ€) ennen â€-H restart†-valitsinta!\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: Ei suodinta, jolla muuntaa muodosta %s/%s muotoon %s/%s!\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s: Salaustukea ei ole käännetty mukaan!\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: Palvelinta ei tavoitettu!\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: Kohteen â€%s†MIME-tyyppiä ei voida määrittää!\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s: Kohdetta %s ei voida avata - %s\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s: Kohdetta %s ei voida avata - %s linjalla %d.\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s: MIME-tietokantaa ei voida lukea kohteesta â€%s†tai â€%sâ€!\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: Tuntematon kohde - â€%sâ€\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: Tuntematon kohde-MIME-tyyppi %s/%s!\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: Tuntematon valitsin â€%câ€!\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: Tuntematon lähde-MIME-tyyppi %s/%s!\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: Varoitus - %c-muotovalitsinta ei tueta - tuloste saattaa olla "
+#~ "virheellinen!\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: Varoitus - merkistövalitsin jätettiin huomioimatta!\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: Varoitus - sisältötyyppivalitsin jätettiin huomioimatta!\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: Varoitus - lomakevalitsin jätettiin huomioimatta!\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: Varoitus - tilavalitsin jätettiin huomioimatta!\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: virhe - %s ympäristömuuttujanimien kohdetta â€%s†ei ole olemassa!\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: virhe - o-valitsimen jälkeen odotettiin valinta=arvo!\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "600 dpi harmaasävy"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr "Tulostinajureiden viemiseen tarvitaan Samba-salasana!"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr "Tulostinajureiden viemiseen tarvitaan Samba-käyttäjätunnus!"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "Luokka nimeltä â€%s†on jo olemassa!"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "Tulostin nimeltä â€%s†on jo olemassa!"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr "Yritettiin asettaa %s printer-state virheelliseen arvoon %d!"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "Attribuuttiryhmät ovat epäjärjestyksessä (%x < %x)!"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "Virheellinen laite-osoite â€%sâ€!\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "Virheellinen device-uri â€%sâ€!"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "Virheellinen device-uri-malli â€%sâ€!"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "Virheellinen document-format â€%sâ€!"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Virheellinen tiedostonimipuskuri!"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Virheellinen job-priority-arvo!"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Virheellinen job-sheets-arvo â€%sâ€!"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Virheellinen job-sheets-arvon tyyppi!"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Virheellinen job-state-arvo!"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Virheellinen job-uri-attribuutti â€%sâ€!"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "Virheellinen notify-pull-method â€%sâ€!"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "Virheellinen notify-recipient-uri-osoite â€%sâ€!"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "Virheellinen valinta ja vaihtoehto rivillä %d!"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "Virheellinen port-monitor â€%sâ€!"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Virheellinen printer-state-arvo %d!"
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "Virheellinen pyynnön versionumero %d.%d!"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "Virheellinen tilaustunnus!"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "Merkistöä â€%s†ei tueta!"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "Tyyppiä â€%s†ei voitu skannata!"
+
+#~ msgid "Cover open."
+#~ msgstr "Kansi avoinna."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "Kehite lähes loppu."
+
+#~ msgid "Developer empty!"
+#~ msgstr "Kehite loppu!"
+
+#~ msgid "Door open."
+#~ msgstr "Ovi avoinna."
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Virheellinen %%BoundingBox:-kommentti havaittu!\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: Virheellinen %%IncludeFeature:-kommentti!\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: Virheellinen %%Page:-kommentti tiedostossa!\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: Virheellinen %%PageBoundingBox:-kommentti tiedostossa!\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: Virheellinen SCSI-laitetiedosto â€%sâ€!\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: Virheellinen sarakearvo %d!\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: Virheellinen cpi-arvo %f!\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: Virheellinen lpi-arvo %f!\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: Virheellinen arkin määrittely!\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: Kohdetulostinta ei ole olemassa!\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Monistunut %%BoundingBox:-kommentti havaittu!\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: Monistunut %%Pages:-kommentti havaittu!\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: Tyhjä tulostustiedosto!\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr ""
+#~ "ERROR: Odotettiin lainausmerkin merkittyä merkkijonoa rivillä %d / %s!\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: Vakava USB-virhe!\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr ""
+#~ "ERROR: Virheellinen HP-GL/2-komento havaittu, tiedostoa ei voida "
+#~ "tulostaa!\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: %%EndProlog puuttuu!\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: %%EndSetup puuttuu!\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Laitteen osoite puuttuu komentoriviltä eikä DEVICE_URI-"
+#~ "ympäristömuuttujaa ole määritelty!\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: Arvo puuttuu otsikkotiedoston riviltä %d!\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: Tarvitaan msgid-rivi ennen käännösmerkkijonoja rivillä %d / %s!\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: Otsakkeessa ei ole %%PageBoundingBox:-kommenttia!\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: Otsakkeessa ei ole %%Pages:-kommenttia!\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Laitteen osoitetta ei löytynyt argv[0]:stä eikä DEVICE_URI-"
+#~ "ympäristömuuttujasta!\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: Sivuja ei löytynyt!\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: Paperi loppu!\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: PRINTER-ympäristömuuttujaa ei ole määritelty!\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: Tulostustiedostoa ei hyväksytty (%s)!\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: Tulostin ei vastaa!\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: Tilapäistiedostoa ei voida luoda - %s.\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: Tilapäistiedostoa ei voida luoda: %s.\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: Työn %d ominaisuuksia ei voida hakea (%s)!\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: Tulostimen tilaa ei voida hakea (%s)!\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: Tulostinta â€%s†ei löytynyt!\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: Kuvatiedostoa ei voida avata tulostusta varten!\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: Tilapäistiedostoa ei voida avata"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: %d tekstisaraketta ei voida tulostaa!\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: %d x %d tekstisivua ei voida tulostaa!\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: Tulostusdataa ei voida lukea!\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: Tulostusdataa ei voida lähettää (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: Tulostusdataa ei voida lähettää!\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: %d tavua ei voida kirjoittaa tulostimelle!\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr "ERROR: Rasteridataa ei voida kirjoittaa ajurille!\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: Tilapäistiedostoon ei voida kirjoittaa"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: Odottamatonta tekstiä rivillä %d / %s!\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: Tuntematon salausvalinnan arvo â€%sâ€!\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: Tuntematon viestikatalogimuoto kohteelle â€%sâ€!\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: Tuntematon valinta â€%s†arvolla â€%sâ€!\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: Tuntematon versiovalinnan arvo â€%sâ€!\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr "ERROR: Ei-tuettu kirkkausarvo %s, käytetään kirkkaus=100!\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: Ei-tuettu gamma-arvo %s, käytetään gamma=1000!\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr "ERROR: Ei-tuettu number-up-arvo %d, käytetään number-up=1!\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: Ei-tuettu number-up-layout-arvo %s, käytetään number-up-"
+#~ "layout=lrtb!\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr "ERROR: Ei-tuettu page-border-arvo %s, käytetään page-border=none!\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr "ERROR: Havaittiin doc_printf-ylivuoto (%d tavua), keskeytetään!\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr "ERROR: pdftops-suodin kaatui signaaliin %d!\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr "ERROR: pdftops-suodin lopetti signaaliin %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops lopetti signaaliin %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops lopetti paluuarvolla %d!\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: korjattavissa: Tulostimeen ei voida yhdistää, yritetään uudelleen "
+#~ "30 sekunnin kuluttua...\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "Tyhjä PPD-tiedosto!"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "Virhe: h-valitsimen jälkeen tarvitaan palvelinnimi!\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Lämpövastuksen lämpötila on korkea!"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "Lämpövastuksen lämpötila on matala!"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "Saatiin printer-uri-attribuutti, mutta ei job-id:tä!"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Väriaine lähes loppu."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Väriaine loppu!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Hukkavärisäiliö lähes täynnä."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Hukkavärisäiliö täynnä!"
+
+#~ msgid "Interlock open."
+#~ msgstr "Välilukko avoinna."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "Työtä %d ei voida aloittaa uudelleen - ei tiedostoja!"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "Työtä %d ei ole olemassa!"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "Työ %d on suoritettu eikä sitä voida muuttaa!"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "Työtä %d ei ole suoritettu!"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "Työtä %d ei pidetä todentamista varten!"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "Työtä %d ei pidetä!"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "Työtä %s ei ole olemassa!"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "Työtä %d ei löytynyt!"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "Työtilauksia ei voida uudistaa!"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "Kieltä â€%s†ei tueta!"
+
+#~ msgid "Media jam!"
+#~ msgstr "Mediatukos!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Syöttöalusta lähes tyhjä."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Syöttöalusta tyhjä!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Syöttöalusta puuttuu!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "Syöttöalusta on täytettävä."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "Document-number-attribuutti puuttuu!"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "Kaksinkertainen lainausmerkki puuttuu riviltä %d!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "Muotomuuttuja puuttuu!"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "notify-subscription-ids-attribuutti puuttuu!"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "requesting-user-name-attribuutti puuttuu!"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "Vaadittuja attribuutteja puuttuu!"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "Arvo puuttuu riviltä %d!"
+
+#~ msgid "No PPD name!"
+#~ msgstr "Ei PPD-nimeä!"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Windows-tulostinajureita ei ole asennettu!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "Kohteessa %s ei ole aktiivisia töitä!"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "Pyynnössä ei ole attribuutteja!"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "Todentamistietoja ei annettu!"
+
+#~ msgid "No file!?!"
+#~ msgstr "Ei tiedostoa!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "Ei muokkausaikaa!"
+
+#~ msgid "No printer name!"
+#~ msgstr "Ei tulostimen nimeä!"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "Luokalle ei löytynyt tulostinosoitetta!"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "Tulostinosoitetta ei löytynyt!"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "Pyynnössä ei ole tulostinosoitetta!"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "Pyynnössä ei ole tilausattribuutteja!"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC:n käyttöikä päättymässä."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC:n käyttöikä päättynyt!"
+
+#~ msgid "Out of toner!"
+#~ msgstr "Väriaine loppu!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Tulostusalusta lähes täynnä."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Tulostusalusta täynnä!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Tulostusalusta puuttuu!"
+
+#~ msgid "Printer offline."
+#~ msgstr "Tulostin offline."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "SCSI-tulostin"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "notify-user-data-arvon on liian suuri (%d > 63 oktettia)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "Tulostinta tai luokkaa ei ole jaettu!"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "printer-uri-attribuutti tarvitaan!"
+
+#~ msgid "Toner low."
+#~ msgstr "Väriaine vähissä."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "Liikaa job-sheets-arvoja (%d > 2)!"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "Liikaa printer-state-reasons-arvoja (%d > %d)!"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "Työtä ei voida lisätä kohteelle â€%sâ€!"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "Tiedostotyypeille ei voida varata muistia!"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr "64-bittisiä CUPS-tulostinajuritiedostoja ei voida kopioida (%d)!"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr "64-bittisiä Windows-tulostinajuritiedostoja ei voida kopioida (%d)!"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr "CUPS-tulostinajuritiedostoja ei voida kopioida (%d)!"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "PPD-tiedostoa ei voida kopioida - %s!"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "PPD-tiedostoa ei voida kopioida!"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr "Windows 2000 -tulostinajuritiedostoja ei voida kopioida (%d)!"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr "Windows 9x -tulostinajuritiedostoja ei voida kopioida (%d)!"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "Liitäntäskriptiä ei voida kopioida - %s!"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "Tulostinosoitetta ei voida luoda!"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr ""
+#~ "cupsd.conf-tiedostoja, joka ovat suurempia kuin 1 Mt, ei voida muokata!"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "Työlle ei löydy kohdetta!"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "Tulostinta ei löytynyt!\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr "Windows 2000 -tulostinajuritiedostoja ei voida asentaa (%d)!"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr "Windows 9x -tulostinajuritiedostoja ei voida asentaa (%d)!"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "Dokumenttia %d työssä %d ei voida avata!"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "Komentoa ei voida lähettää tulostinajurille!"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Windows-tulostinajuria ei voida asettaa (%d)!"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "Vanhaa USB-luokka-ajuria ei voida käyttää!\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "Tuntematon tulostinvirhe (%s)!"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Ei-tuettu merkistö â€%sâ€!"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "Ei-tuettu pakkausmenetelmä â€%sâ€!"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "Ei-tuettu pakkausattribuutti %s!"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "Ei-tuettu muoto â€%sâ€!"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "Ei-tuettu muoto â€%sâ€!"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "Ei-tuettu muoto â€%s/%sâ€!"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "Käyttö: convert [ valitsimet ]\n"
+#~ "\n"
+#~ "Valitsimet:\n"
+#~ "\n"
+#~ " -f tiedostonimi Aseta muunnettava tiedosto (muussa tapauksessa "
+#~ "stdin)\n"
+#~ " -o tiedostonimi Aseta luotava tiedosto (muussa tapauksessa "
+#~ "stdout)\n"
+#~ " -i mime/tyyppi Aseta syötteen MIME-tyyppi (muussa tapauksessa "
+#~ "määritetään automaattisesti)\n"
+#~ " -j mime/tyyppi Aseta tulosteen MIME-tyyppi (muussa tapauksessa "
+#~ "application/pdf)\n"
+#~ " -P tiedostonimi.ppd Aseta PPD-tiedosto\n"
+#~ " -a 'nimi=arvo ...' Aseta valintoja\n"
+#~ " -U käyttäjätunnus Aseta työn käyttäjätunnus\n"
+#~ " -J otsikko Aseta otsikko\n"
+#~ " -c kopioita Aseta kopioiden määrä\n"
+#~ " -u Poista PPD-tiedosto, kun valmis\n"
+#~ " -D Poista syötetiedosto, kun valmis\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "Käyttö: cupsfilter -m mime/tyyppi [ valitsimet ] tiedostonimi\n"
+#~ "\n"
+#~ "Valitsimet:\n"
+#~ "\n"
+#~ " -c cupsd.conf Aseta käytettävä cupsd.conf-tiedosto\n"
+#~ " -j job-id[,N] Suodintiedosto N määritellystä työstä (oletus on "
+#~ "tiedosto 1)\n"
+#~ " -n kopiot Aseta kopioiden määrä\n"
+#~ " -o nimi=arvo Aseta valintoja\n"
+#~ " -p tiedostonimi.ppd Aseta PPD-tiedosto\n"
+#~ " -t otsikko Aseta otsikko\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Käyttö: cupstestppd [valitsimet] tiedostonimi1.ppd[.gz] [... "
+#~ "tiedostonimiN.ppd[.gz]]\n"
+#~ " ohjelma | cupstestppd [valitsimet] -\n"
+#~ "\n"
+#~ "Valitsimet:\n"
+#~ "\n"
+#~ " -R juurihakemisto Aseta vaihtoehtoinen juuri\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Anna varoituksia virheiden sijasta\n"
+#~ " -q Suorita hiljaa\n"
+#~ " -r Käytä â€rentoa†avointa tilaa\n"
+#~ " -v Ole monisanainen\n"
+#~ " -vv Ole erittäin monisanainen\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: Sivukanavapyyntöä ei voitu lukea!\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr ""
+#~ "WARNING: Valintaa â€%s†ei voida sisällyttää IncludeFeature:n kautta!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Etäpalvelin ei vastannut komentotilatavulla %d sekunnin "
+#~ "jälkeen!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Etäpalvelin ei vastannut ohjaustilatavulla %d sekunnin jälkeen!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Etäpalvelin ei vastannut datatilatavulla %d sekunnin jälkeen!\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr ""
+#~ "WARNING: SCSI-komento aikakatkaistiin (%d); yritetään uudelleen...\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: Tämä dokumentti ei ole Adobe Document Structuring Conventions -"
+#~ "määrityksen mukainen eikä välttämättä tulostu oikein!\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: Tuntematon vaihtoehto â€%s†valinnalle â€%sâ€!\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: Tuntematon valinta â€%sâ€!\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: Ei-tuettu siirtonopeus %s!\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: korjattavissa: Verkkopalvelin â€%s†on varattu; yritetään "
+#~ "uudelleen %d sekunnin kuluttua...\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr "Varoitus, Windows 2000 -tulostinajureita ei ole asennettu!"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: Tuntematon valinta â€%sâ€!\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: Tuntematon valinta â€-%câ€!\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr "cupsd: c-valitsimen jälkeen odotettiin määrittelytiedoston nimeä!\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: Nykyistä hakemistoa ei voida hakea!\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: Tuntematon argumentti â€%s†- keskeytetään!\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: Tuntematon valinta â€%c†- keskeytetään!\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: Virheellinen dokumenttinumero %d!\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: Virheellinen työtunnus %d!\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: Vain yksi tiedostonimi voidaan määritellä!\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter: Tilapäistiedostoa ei voida luoda: %s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "job-printer-uri-attribuutti puuttuu!"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Luokan nimi voi sisältää vain näkyviä merkkejä!\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: P-valitsimen jälkeen odotettiin PPD:tä!\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr ""
+#~ "lpadmin: u-valitsimen jälkeen odotettiin allow/deny:käyttäjäluettelo!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: r-valitsimen jälkeen odotettiin luokkaa!\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: c-valitsimen jälkeen odotettiin luokan nimeä!\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: D-valitsimen jälkeen odotettiin kuvausta!\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: v-valitsimen jälkeen odotettiin laiteosoitetta!\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: I-valitsimen jälkeen odotettiin tiedostotyyppejä!\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: h-valitsimen jälkeen odotettiin palvelinnimeä!\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: i-valitsimen jälkeen odotettiin liitäntää!\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: L-valitsimen jälkeen odotettiin sijaintia!\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: m-valitsimen jälkeen odotettiin mallia!\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: o-valitsimen jälkeen odotettiin nimi=arvo!\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: p-valitsimen jälkeen odotettiin tulostinta!\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: d-valitsimen jälkeen odotettiin tulostimen nimeä!\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin: x-valitsimen jälkeen odotettiin tulostinta tai luokkaa!\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: Jäsennimiä ei havaittu!\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Tulostimen nimi voi sisältää vain näkyviä merkkejä!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Tulostinta ei voida lisätä luokkaan:\n"
+#~ " Määrittele tulostimen nimi ensin!\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin: Tilapäistiedostoa ei voida luoda - %s.\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin: Tilapäistiedostoa ei voida luoda: %s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Tulostinta ei voida poistaa luokasta:\n"
+#~ " Määrittele tulostimen nimi ensin!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: PPD-tiedostoa ei voida asettaa:\n"
+#~ " Määrittele tulostimen nimi ensin!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Laiteosoitetta ei voida asettaa:\n"
+#~ " Määrittele tulostimen nimi ensin!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Liitäntäskriptiä tai PPD-tiedostoa ei voida asettaa:\n"
+#~ " Määrittele tulostimen nimi ensin!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Liitäntäskriptiä ei voida asettaa:\n"
+#~ " Määrittele tulostimen nimi ensin!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Tulostimen kuvausta ei voida asettaa:\n"
+#~ " Määrittele tulostimen nimi ensin!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Tulostimen sijaintia ei voida asettaa:\n"
+#~ " Määrittele tulostimen nimi ensin!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Tulostimen valintoja ei voida asettaa:\n"
+#~ " Määrittele tulostimen nimi ensin!\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: Tuntematon allow/deny-valinta â€%sâ€!\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: Tuntematon argumentti â€%sâ€!\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: Tuntematon valinta â€%câ€!\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr ""
+#~ "lpadmin: Varoitus - sisällöntyyppiluettelo jätettiin huomioimatta!\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr ""
+#~ "lpinfo: --device-id:n jälkeen odotettiin 1284-laitetunnistemerkkijonoa!\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: --language:n jälkeen odotettiin kieltä!\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo: --make-and-model:n jälkeen odotettiin merkkiä ja mallia!\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo: --product:n jälkeen odotettiin tuotemerkkijonoa!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo: --exclude-schemes:n jälkeen odotettiin malliluetteloa!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo: --include-schemes:n jälkeen odotettiin malliluetteloa!\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: --timeout:n jälkeen odotettiin aikakatkaisua!\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: Tuntematon argumentti â€%sâ€!\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: Tuntematon valinta â€%câ€!\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: Tuntematon valinta â€%sâ€!\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: Tuntematon argumentti â€%sâ€!\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: Tuntematon valinta â€%câ€!\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: Ei tulostimia!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: PPD-tiedostoa ei voida avata kohteelle %s!\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: Tuntematon tulostin tai luokka!\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: Vain root voi lisätä tai poistaa salasanoja!\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: Salasanatiedosto on varattu!\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: Salasanatiedostoa ei päivitetty!\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: Salasana ei täsmää!\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: Salasanat eivät täsmää!\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: virhe - %s ympäristömuuttujanimien kohdetta â€%s†ei ole "
+#~ "olemassa!\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-events:iä ei määritelty!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "notify-recipient-uri-osoite â€%s†on jo käytössä!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "notify-recipient-uri-osoite â€%s†käyttää tuntematonta mallia!"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d ei kelpaa!"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Virheellinen tarkkuuden nimi â€%s†rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: Virheellinen tila-avainsana â€%s†rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc: Riviltä %d / %s löytyi vaihtoehto ilman valintaa!\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc: Kaksoiskappale #po lokaalille %s rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin suodinmääritystä rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin ohjelman nimeä rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin merkistöä Font:in jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin värijärjestystä ColorModel:ille rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin väriavaruutta ColorModel:ille rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin pakkausta ColorModel:ille rivillä %d / %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Odotettiin rajoitusmerkkijonoa UIConstraints:ille rivillä %d / %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Odotettiin ajurintyypin avainsanaa DriverType:lle rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Odotettiin dupleksityyppiä Duplex:in jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin koodausta Font:in jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin tiedostonimeä #po:n %s jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin ryhmänimeä/-tekstiä rivillä %d / %s.\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin include-tiedoston nimeä rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin kokonaislukua rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin lokaalia #po:n jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin nimeä kohteen %s jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin nimeä FileName:n jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin nimeä Font:in jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin nimeä Manufacturer:in jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin nimeä MediaSize:n jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin nimeä ModelName:n jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin nimeä PCFileName:n jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Odotettiin nimeä/tekstiä kohteen %s jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Odotettiin nimeä/tekstiä Installable:n jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Odotettiin nimeä/tekstiä Resolution:in jälkeen rivillä %d / %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Odotettiin nimi-/tekstiyhdistelmää ColorModel:ille rivillä %d / %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin valintanimeä/-tekstiä rivillä %d / %s.\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin valintaosiota rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin valintatyyppiä rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Odotettiin ohituskenttää Resolution:in jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin reaalilukua rivillä %d / %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Odotettiin tarkkuutta/mediatyyppi ColorProfile:n jälkeen rivillä %"
+#~ "d / %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Odotettiin tarkkuutta/mediatyyppi SimpleColorProfile:n jälkeen "
+#~ "rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin valitsijaa kohteen %s jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin tilaa Font:in jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Odotettiin merkkijonoa Copyright:in jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin merkkijonoa Version:in jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin kahta valintanimeä rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin arvoa kohteen %s jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Odotettiin versiota Font:in jälkeen rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: Virheellinen #include/#po-tiedostonimi â€%sâ€!\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Virheellinen hinta suotimelle rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Virheellinen tyhjä MIME-tyyppi suotimelle rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Virheellinen tyhjä ohjelman nimi suotimelle rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Virheellinen valintaosio â€%s†rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Virheellinen valintatyyppi â€%s†rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: #endif puuttuu kohteen â€%s†lopusta!\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: #if puuttuu riviltä %d / %s!\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc: Ei viestikatalogia lokaalille %s!\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Valinta %s määritelty uudelleen eri tyypillä rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr "ppdc: Valintarajoituksen on tehtävä *name rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: Liikaa sisäkkäisiä #if:ejä rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: #po-tiedostoa %s ei löytynyt riviltä %d / %s!\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: include-tiedostoa â€%s†ei löytynyt riviltä %d / %s!\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: Tuntematon ajurityyppi %s rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Tuntematon dupleksityyppi â€%s†rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Tuntematon mediakoko â€%s†rivillä %d / %s!\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: Tuntematon token â€%s†rivillä %d / %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Tuntemattomia seuraavia merkkejä reaaliluvussa â€%s†rivillä %d / %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr "ppdc: Määrittelemätön merkkijono, joka alkaa %c, rivillä %d / %s!\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: Virheellinen LanguageVersion â€%s†kohteessa %s!\n"
diff --git a/locale/cups_fr.po b/locale/cups_fr.po
new file mode 100644
index 000000000..c23f58ebf
--- /dev/null
+++ b/locale/cups_fr.po
@@ -0,0 +1,7233 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-16 12:00-0800\n"
+"Last-Translator: Apple Inc.\n"
+"Language-Team: Apple Inc.\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(tous)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(aucun)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d entrées\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tAprès une erreur : poursuivre\n"
+
+msgid "\tAlerts:"
+msgstr "\tAlertes :"
+
+msgid "\tBanner required\n"
+msgstr "\tBannière requise\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tJeux de caractères :\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tConnexion : directe\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tConnexion : distante\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tTaille de papier par défaut :\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tTon par défaut :\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tRéglages par défaut du port :\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tDescription : %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tFormat monté :\n"
+"\tType de contenu : any (quelconque)\n"
+"\tType d’imprimantes : unknown (inconnu)\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tFormats autorisés :\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tInterface : %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tInterface : %s/interfaces/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tInterface : %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tEmplacement : %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tEn cas d’erreur : aucun avertissement\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tUtilisateurs autorisés :\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tUtilisateurs refusés :\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tdaemon présent\n"
+
+msgid "\tno entries\n"
+msgstr "\taucune entrée\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\tl’imprimante correspond au périphérique « %s », débit -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\tl’impression est désactivée\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\tl’impression est activée\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\tmis en file d’attente pour %s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tla mise en file d’attente est désactivée\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tla mise en file d’attente est activée\n"
+
+msgid "\treason unknown\n"
+msgstr "\traison inconnue\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" RÉSULTATS DÉTAILLÉS DU TEST DE CONFORMITÉ\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " REF : page 15, rubrique 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " REF : page 15, rubrique 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " REF : page 19, rubrique 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " REF : page 20, rubrique 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " REF : page 27, rubrique 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " REF : page 42, rubrique 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " REF : pages 16 et 17, rubrique 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " REF : pages 42 à 45, rubrique 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " REF : pages 45 et 46, rubrique 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " REF : pages 48 et 49, rubrique 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " REF : pages 52 à 54, rubrique 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f octets\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " VALIDE Default%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " VALIDE DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " VALIDE DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " VALIDE FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " VALIDE FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " VALIDE LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " VALIDE LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " VALIDE Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " VALIDE ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " VALIDE NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " VALIDE PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " VALIDE PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " VALIDE PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " VALIDE PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " VALIDE Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " VALIDE ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" ATTN « %s %s » entre en conflit avec « %s %s ».\n"
+" (constraint=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" ATTN %s partage un préfixe avec %s\n"
+" REF : page 15, rubrique 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" ATTN LanguageEncoding requis d’après les spécifications PPD 4.3\n"
+" REF : pages 56 et 57, rubrique 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" ATTN Paramètre Manufacturer requis d’après les spécifications PPD "
+"4.3\n"
+" REF : pages 58 et 59, rubrique 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" ATTN Le nom de fichier PCFileName ne respecte pas les "
+"spécifications PPD pour le format 8.3\n"
+" REF : pages 61 et 62, rubrique 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" ATTN La section Protocols contient PJL mais les attributs JCL ne "
+"sont pas définis.\n"
+" REF : pages 78 et 79, rubrique 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" ATTN La section Protocols contient PJL et BCP, mais TBCP est "
+"attendu.\n"
+" REF : pages 78 et 79, rubrique 5.7.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" ATTN ShortNickName requis d’après les spécifications PPD 4.3\n"
+" REF : pages 64 et 65, rubrique 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s Fichier cupsFilter manquant « %s ».\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s Fichier cupsPreFilter manquant « %s ».\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **ÉCHEC** Default%s %s erroné.\n"
+" REF : page 40, rubrique 4.5.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **ÉCHEC** Attribut JobPatchFile erroné dans le fichier.\n"
+" REF : page 24, rubrique 3.4.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **ÉCHEC** Manufacturer erroné (doit être « HP »)\n"
+" REF : page 211, tableau D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **ÉCHEC** Manufacturer incorrect (doit être « Oki »)\n"
+" REF : page 211, tableau D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** ModelName erroné - « %c » interdit dans la chaîne.\n"
+" REF : pages 59 et 60, rubrique 5.3.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** PSVersion erroné - différent de « (string) int ».\n"
+" REF : pages 62 à 64, rubrique 5.3.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** Paramètre Product erroné - différent de « (string) ».\n"
+" REF : page 62, rubrique 5.3.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** ShortNickName erroné - dépasse 31 caractères.\n"
+" REF : pages 64 et 65, rubrique 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** FileVersion « %s » incorrect\n"
+" REF : page 56, rubrique 5.3."
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** FormatVersion « %s » incorrect\n"
+" REF : page 56, section 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr ""
+" **ÉCHEC** Le code de l’option par défaut ne peut pas être "
+"interprété : %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **ÉCHEC** Default%s requis\n"
+" REF : page 40, rubrique 4.5.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **ÉCHEC** DefaultImageableArea requis\n"
+" REF : page 102, rubrique 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **ÉCHEC** DefaultPaperDimension requis\n"
+" REF : page 103, rubrique 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** FileVersion requis\n"
+" REF : page 56, rubrique 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** FormatVersion requis\n"
+" REF : page 56, rubrique 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **ÉCHEC** ImageableArea requis pour PageSize %s\n"
+" REF : page 41, rubrique 5.\n"
+" REF : page 102, rubrique 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** LanguageEncoding requis\n"
+" REF : pages 56 et 57, rubrique 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** LanguageVersion requis\n"
+" REF : pages 57 et 58, rubrique 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** Manufacturer requis\n"
+" REF : pages 58 et 59, rubrique 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** ModelName requis\n"
+" REF : pages 59 et 60, rubrique 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** NickName requis\n"
+" REF : page 60, rubrique 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** PCFileName requis\n"
+" REF : pages 61 et 62, rubrique 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** PSVersion requis\n"
+" REF : pages 62 à 64, rubrique 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **ÉCHEC** PageRegion requis\n"
+" REF : page 100, rubrique 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **ÉCHEC** PageSize requis\n"
+" REF : page 41, rubrique 5.\n"
+" REF : page 99, rubrique 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **ÉCHEC** PageSize requis\n"
+" REF : pages 99 et 100, rubrique 5.14.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **ÉCHEC** PaperDimension requis pour PageSize %s\n"
+" REF : page 41, rubrique 5.\n"
+" REF : page 103, rubrique 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** Product requis\n"
+" REF : page 62, rubrique 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **ÉCHEC** ShortNickName requis\n"
+" REF : page 64 et 65, rubrique 5.3.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr "%d ERREURS TROUVÉES\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " AUCUNE ERREUR RENCONTRÉE\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " ÉCHEC\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" ÉCHEC\n"
+" **ÉCHEC** Impossible d’ouvrir le fichier - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" ÉCHEC\n"
+" **ÉCHEC** Impossible d’ouvrir le fichier - %s en ligne %d.\n"
+
+msgid " PASS\n"
+msgstr " VALIDE\n"
+
+msgid "#10 Envelope"
+msgstr "#10 Enveloppe"
+
+msgid "#11 Envelope"
+msgstr "#11 Enveloppe"
+
+msgid "#12 Envelope"
+msgstr "#12 Enveloppe"
+
+msgid "#14 Envelope"
+msgstr "#14 Enveloppe"
+
+msgid "#9 Envelope"
+msgstr "#9 Enveloppe"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f octets\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f octets\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f millimètres"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f à %.0f x %.0f millimètres"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f pouces"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f à %.2f x %.2f pouces"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s acceptant des requêtes depuis %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "Impossible de modifier « %s »."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s n’est pas implémenté par la version CUPS de lpc.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s n’est pas prêt\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s est prêt\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s est prêt et en cours d’impression\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s n’acceptant pas de requêtes depuis %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s%s acceptant des requêtes depuis %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s n’acceptant pas de requêtes depuis %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s : %-33.33s [tâche %d localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s : %s échoué : %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s : erreur - aucune destination par défaut disponible.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s : erreur - la priorité doit être comprise entre 1 et 100.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s : erreur - fichiers trop nombreux - « %s »\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s : erreur - impossible d’accéder à « %s » - %s"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr ""
+"%s : erreur - impossible de mettre en file d’attente depuis stdin - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s : filtre « %s » indisponible : %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s : chaîne de filtre « %s » non valide"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s : l’opération a échoué : %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s : Connexion impossible au serveur\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s : impossible d’ouvrir %s : %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s : impossible d’ouvrir le fichier PPD : %s à la ligne %d\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s : erreur - aucune destination par défaut disponible.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 po/s"
+
+msgid "1.25x0.25\""
+msgstr "1,25 x 0,25\""
+
+msgid "1.25x2.25\""
+msgstr "1,25 x 2,25\""
+
+msgid "1.5 inch/sec."
+msgstr "1,5 po/s"
+
+msgid "1.50x0.25\""
+msgstr "1,50 x 0,25\""
+
+msgid "1.50x0.50\""
+msgstr "1,50 x 0,50\""
+
+msgid "1.50x1.00\""
+msgstr "1,50 x 1,00\""
+
+msgid "1.50x2.00\""
+msgstr "1,50 x 2,00\""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 po/s"
+
+msgid "10 x 11\""
+msgstr "10 x 11\""
+
+msgid "10 x 13\""
+msgstr "10 x 13\""
+
+msgid "10 x 14\""
+msgstr "10 x 14\""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 mm/s"
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 po/s"
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 po/s"
+
+msgid "12 x 11\""
+msgstr "12 x 11\""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 mm/s"
+
+msgid "120x60dpi"
+msgstr "120 x 60 ppp"
+
+msgid "120x72dpi"
+msgstr "120 x 72 ppp"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136 ppp"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 mm/s"
+
+msgid "15 x 11\""
+msgstr "15 x 11\""
+
+msgid "150 mm/sec."
+msgstr "150 mm/s"
+
+msgid "150dpi"
+msgstr "150 ppp"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180 ppp"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 po/s"
+
+msgid "2-Sided Printing"
+msgstr "Impression recto-verso"
+
+msgid "2.00x0.37\""
+msgstr "2,00 x 0,37\""
+
+msgid "2.00x0.50\""
+msgstr "2,00 x 0,50\""
+
+msgid "2.00x1.00\""
+msgstr "2,00 x 1,00\""
+
+msgid "2.00x1.25\""
+msgstr "2,00 x 1,25\""
+
+msgid "2.00x2.00\""
+msgstr "2,00 x 2,00\""
+
+msgid "2.00x3.00\""
+msgstr "2,00 x 3,00\""
+
+msgid "2.00x4.00\""
+msgstr "2,00 x 4,00\""
+
+msgid "2.00x5.50\""
+msgstr "2,00 x 5,50\""
+
+msgid "2.25x0.50\""
+msgstr "2,25 x 0,50\""
+
+msgid "2.25x1.25\""
+msgstr "2,25 x 1,25\""
+
+msgid "2.25x4.00\""
+msgstr "2,25 x 4,00\""
+
+msgid "2.25x5.50\""
+msgstr "2,25 x 5,50\""
+
+msgid "2.38x5.50\""
+msgstr "2,38 x 5,50\""
+
+msgid "2.5 inches/sec."
+msgstr "2,5 po/s"
+
+msgid "2.50x1.00\""
+msgstr "2,50 x 1,00\""
+
+msgid "2.50x2.00\""
+msgstr "2,50 x 2,00\""
+
+msgid "2.75x1.25\""
+msgstr "2,75 x 1,25\""
+
+msgid "2.9 x 1\""
+msgstr "2.9 x 1\""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 mm/s"
+
+msgid "200 mm/sec."
+msgstr "200 mm/s"
+
+msgid "203dpi"
+msgstr "203 ppp"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "Série 24 broches"
+
+msgid "240x72dpi"
+msgstr "240 x 72 ppp"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 mm/s"
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 po/s"
+
+msgid "3.00x1.00\""
+msgstr "3,00 x 1,00\""
+
+msgid "3.00x1.25\""
+msgstr "3,00 x 1,25\""
+
+msgid "3.00x2.00\""
+msgstr "3,00 x 2,00\""
+
+msgid "3.00x3.00\""
+msgstr "3,00 x 3,00\""
+
+msgid "3.00x5.00\""
+msgstr "3,00 x 5,00\""
+
+msgid "3.25x2.00\""
+msgstr "3,25 x 2,00\""
+
+msgid "3.25x5.00\""
+msgstr "3,25 x 5,00\""
+
+msgid "3.25x5.50\""
+msgstr "3,25 x 5,50\""
+
+msgid "3.25x5.83\""
+msgstr "3,25 x 5,83\""
+
+msgid "3.25x7.83\""
+msgstr "3,25 x 7,83\""
+
+msgid "3.5\" Disk"
+msgstr "Disque 3,5\""
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "Disque 3,5\" - 2 1/8 x 2 3/4\""
+
+msgid "3.50x1.00\""
+msgstr "3,50 x 1,00\""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 mm/s"
+
+msgid "300 mm/sec."
+msgstr "300 mm/s"
+
+msgid "300dpi"
+msgstr "300 ppp"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360 ppp"
+
+msgid "360x180dpi"
+msgstr "360 x 180 ppp"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 po/s"
+
+msgid "4.00x1.00\""
+msgstr "4,00 x 1,00\""
+
+msgid "4.00x13.00\""
+msgstr "4,00 x 13,00\""
+
+msgid "4.00x2.00\""
+msgstr "4,00 x 2,00\""
+
+msgid "4.00x2.50\""
+msgstr "4,00 x 2,50\""
+
+msgid "4.00x3.00\""
+msgstr "4,00 x 3,00\""
+
+msgid "4.00x4.00\""
+msgstr "4,00 x 4,00\""
+
+msgid "4.00x5.00\""
+msgstr "4,00 x 5,00\""
+
+msgid "4.00x6.00\""
+msgstr "4,00 x 6,00\""
+
+msgid "4.00x6.50\""
+msgstr "4,00 x 6,50\""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 mm/s"
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 po/s"
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 po/s"
+
+msgid "6.00x1.00\""
+msgstr "6,00 x 1,00\""
+
+msgid "6.00x2.00\""
+msgstr "6,00 x 2,00\""
+
+msgid "6.00x3.00\""
+msgstr "6,00 x 3,00\""
+
+msgid "6.00x4.00\""
+msgstr "6,00 x 4,00\""
+
+msgid "6.00x5.00\""
+msgstr "6,00 x 5,00\""
+
+msgid "6.00x6.00\""
+msgstr "6,00 x 6,00\""
+
+msgid "6.00x6.50\""
+msgstr "6,00 x 6,50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/s"
+
+msgid "600dpi"
+msgstr "600 ppp"
+
+msgid "60dpi"
+msgstr "60 ppp"
+
+msgid "60x720dpi"
+msgstr "60 x 720 ppp"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 po/s"
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720 ppp"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 po/s"
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8,00 x 1,00\""
+
+msgid "8.00x2.00\""
+msgstr "8,00 x 2,00\""
+
+msgid "8.00x3.00\""
+msgstr "8,00 x 3,00\""
+
+msgid "8.00x4.00\""
+msgstr "8,00 x 4,00\""
+
+msgid "8.00x5.00\""
+msgstr "8,00 x 5,00\""
+
+msgid "8.00x6.00\""
+msgstr "8,00 x 6,00\""
+
+msgid "8.00x6.50\""
+msgstr "8,00 x 6,50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/s"
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 po/s"
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "Série 9 broches"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?Commande inconnue d’aide\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (format supérieur)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (format supérieur)"
+
+msgid "A4 (Small)"
+msgstr "A4 (petit format)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (format supérieur)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "Accepter les tâches"
+
+msgid "Accepted"
+msgstr "Accepté"
+
+msgid "Add Class"
+msgstr "Ajouter une classe"
+
+msgid "Add Printer"
+msgstr "Ajouter une imprimante"
+
+msgid "Add RSS Subscription"
+msgstr "Ajouter abonnement RSS"
+
+msgid "Address"
+msgstr "Adresse"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "Adresse - 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "Administration"
+
+msgid "Always"
+msgstr "Toujours"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "Applicator"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "Pointeur de dests NULL incorrect"
+
+msgid "Bad OpenGroup"
+msgstr "OpenGroup erroné"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "OpenUI/JCLOpenUI erroné"
+
+msgid "Bad OrderDependency"
+msgstr "OrderDependency erroné"
+
+msgid "Bad Request"
+msgstr "Requête incorrecte"
+
+msgid "Bad SNMP version number"
+msgstr "Numéro de version SNMP incorrect"
+
+msgid "Bad UIConstraints"
+msgstr "UIConstraints erroné"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Nombre de copies erroné : %d."
+
+msgid "Bad custom parameter"
+msgstr "Paramètre personnalisé incorrect"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Attribut de police incorrect : %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Valeur de number-up %d incorrecte."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Intervalle de pages erroné : %d-%d."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Bannières"
+
+msgid "Billing Information: "
+msgstr "Informations de facturation : "
+
+msgid "Bond Paper"
+msgstr "Papier pour titres"
+
+msgid "C0 Envelope"
+msgstr "C0 Enveloppe"
+
+msgid "C1 Envelope"
+msgstr "C1 Enveloppe"
+
+msgid "C2 Envelope"
+msgstr "C2 Enveloppe"
+
+msgid "C3 Envelope"
+msgstr "C3 Enveloppe"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "C4 Enveloppe"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "C5 Enveloppe"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "C6 Enveloppe"
+
+msgid "C65 Envelope"
+msgstr "C65 Enveloppe"
+
+msgid "C7 Envelope"
+msgstr "C7 Enveloppe"
+
+msgid "CMYK"
+msgstr "CMJN"
+
+msgid "CPCL Label Printer"
+msgstr "Imprimante pour étiquettes CPCL"
+
+msgid "Cancel RSS Subscription"
+msgstr "Annuler abonnement RSS"
+
+msgid "Change Settings"
+msgstr "Modifier les paramètres"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Chou3 Enveloppe"
+
+msgid "Chou4 Envelope"
+msgstr "Chou4 Enveloppe"
+
+msgid "Classes"
+msgstr "Classes"
+
+msgid "Clean Print Heads"
+msgstr "Nettoyer les têtes d’impression"
+
+msgid "Color"
+msgstr "Couleur"
+
+msgid "Color Mode"
+msgstr "Mode de couleur"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"Les commandes peuvent être abrégées. Celles-ci correspondent à :\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "Le nom de la communauté s’avère être de longueur indéfinie"
+
+msgid "Continue"
+msgstr "Continuer"
+
+msgid "Continuous"
+msgstr "Continu"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Créé"
+
+msgid "Created On: "
+msgstr "Créé le : "
+
+msgid "Custom"
+msgstr "Personnalisation"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Couper"
+
+msgid "Cutter"
+msgstr "Cutter"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "DL Enveloppe"
+
+msgid "Dark"
+msgstr "Foncé"
+
+msgid "Darkness"
+msgstr "Tons foncés"
+
+msgid "Delete Class"
+msgstr "Supprimer la classe"
+
+msgid "Delete Printer"
+msgstr "Supprimer l’imprimante"
+
+msgid "Description: "
+msgstr "Description : "
+
+msgid "DeskJet Series"
+msgstr "Série DeskJet"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "La destination « %s » n’accepte pas de tâche."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"Périphérique : uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "Papier pour impression thermique directe"
+
+msgid "Disabled"
+msgstr "Désactivé"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "Document %d introuvable dans la tâche %d."
+
+msgid "Double Postcard"
+msgstr "Carte postale double"
+
+msgid "Driver Name: "
+msgstr "Nom du gestionnaire : "
+
+msgid "Driver Version: "
+msgstr "Version du gestionnaire : "
+
+msgid "Duplexer"
+msgstr "Duplexeur"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr ""
+"EMERG: impossible d’allouer de la mémoire pour les informations de la page : "
+"%s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr ""
+"EMERG: impossible d’allouer de la mémoire pour l’étalage des pages : %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "Imprimante pour étiquettes EPL1"
+
+msgid "EPL2 Label Printer"
+msgstr "Imprimante pour étiquettes EPL2"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: fichier de jeu de caractères %s erroné\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: type de jeu de caractères %s erroné\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: ligne de description de police erronée : %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: direction de texte %s erronée\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: largeur de texte %s erronée\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: erreur %d lors de l’envoi de la requête PAPSendData : %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr ""
+"ERROR: aucune police ne se trouve dans le fichier du jeu de caractères %s\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: l’imprimante ne répond pas.\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: l’imprimante a envoyé un code EOF inattendu.\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: l’hôte à distance n’a pas accepté le fichier contrôle (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: l’hôte à distance n’a pas accepté le fichier de données (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr ""
+"ERROR: le délai d’attente a été dépassé lors de l’envoi de données à "
+"l’imprimante.\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: impossible d’ajouter le fichier %d à la tâche : %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: impossible d’annuler la tâche %d : %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: impossible de copier le fichier PDF"
+
+msgid "ERROR: Unable to create pipe"
+msgstr ""
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: impossible de créer un socket"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: impossible de créer un fichier d’impression temporaire compressé : %"
+"s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: impossible de créer un fichier temporaire."
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: impossible d’exécuter pictwpstops : %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: impossible d’exécuter le programme gs"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: impossible d’exécuter le programme pdftops"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: impossible d’effectuer le fork de pictwpstops : %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: impossible d’obtenir la requête PAP"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: impossible d’obtenir la réponse PAP"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr ""
+"ERROR: impossible d’obtenir le fichier PPD pour l’imprimante « %s » - %s.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: impossible de déterminer la zone AppleTalk par défaut"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: impossible de rechercher une réponse PAP"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: impossible de rechercher des imprimantes AppleTalk"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: impossible de générer une adresse AppleTalk"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: impossible d’ouvrir « %s » - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: impossible d’ouvrir %s : %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: impossible d’ouvrir le fichier de bannière « %s » - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: impossible d’ouvrir le fichier « %s » de périphérique : %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: impossible d’ouvrir le fichier « %s » - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: impossible d’ouvrir le fichier « %s » : %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: impossible d’ouvrir le fichier d’impression « %s » : %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: impossible d’ouvrir le fichier d’impression %s - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: impossible d’ouvrir le fichier d’impression %s : %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: impossible d’ouvrir le fichier d’impression temporaire compressé : %"
+"s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: impossible de lire les données d’impression."
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: impossible de réserver le port"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr ""
+"ERROR: impossible de chercher jusqu’au décalage %ld dans le fichier - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr ""
+"ERROR: impossible de chercher jusqu’au décalage %lld dans le fichier - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: impossible d’envoyer la commande LPD"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: impossible d’envoyer la requête de passage PAP"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: impossible d’envoyer la requête initiale de données d’envoi PAP"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: impossible d’envoyer le fichier d’impression à l’imprimante"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: impossible d’envoyer la valeur Null de fin à l’imprimante"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: impossible d’attendre les pictwpstop : %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: impossible d’écrire %d octets sur « %s » : %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: impossible d’écrire le contenu du fichier de contrôle"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: impossible d’écrire les données d’impression"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: impossible d’écrire le contenu des données d’impression : %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr ""
+"ERROR: impossible d’écrire de données de document non compressées : %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: ordre de fichier « %s » inconnu\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: caractère de format « %c » inconnu\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: mode d’impression « %s » inconnu\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: la fonction select() a échoué"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: impossible de lancer le fichier d’impression"
+
+msgid "Edit Configuration File"
+msgstr "Modifier le fichier de configuration"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Fin de la bannière"
+
+msgid "English"
+msgstr "French"
+
+msgid "Enter old password:"
+msgstr "Ancien mot de passe :"
+
+msgid "Enter password again:"
+msgstr "Confirmez le nouveau mot de passe :"
+
+msgid "Enter password:"
+msgstr "Entrez le nouveau mot de passe :"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Entrez votre nom d’utilisateur et votre mot de passe ou bien identifiez-vous "
+"en tant que « root » pour accéder à cette page. Si vous utilisez "
+"l’authentification Kerberos, assurez-vous de disposer d’un ticket Kerberos "
+"valide."
+
+msgid "Envelope Feed"
+msgstr "Alimentation au format enveloppe"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Règles d’erreur"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "Toutes les 10 étiquettes"
+
+msgid "Every 2 Labels"
+msgstr "Toutes les 2 étiquettes"
+
+msgid "Every 3 Labels"
+msgstr "Toutes les 3 étiquettes"
+
+msgid "Every 4 Labels"
+msgstr "Toutes les 4 étiquettes"
+
+msgid "Every 5 Labels"
+msgstr "Toutes les 5 étiquettes"
+
+msgid "Every 6 Labels"
+msgstr "Toutes les 6 étiquettes"
+
+msgid "Every 7 Labels"
+msgstr "Toutes les 7 étiquettes"
+
+msgid "Every 8 Labels"
+msgstr "Toutes les 8 étiquettes"
+
+msgid "Every 9 Labels"
+msgstr "Toutes les 9 étiquettes"
+
+msgid "Every Label"
+msgstr "Chaque étiquette"
+
+msgid "Expectation Failed"
+msgstr "Échec de la condition de valeur attendue"
+
+msgid "Export Printers to Samba"
+msgstr "Exporter les imprimantes vers SAMBA"
+
+msgid "FAIL\n"
+msgstr "ÉCHEC\n"
+
+msgid "File Folder"
+msgstr "Dossier de fichier"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Dossier de fichier - 9/16 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"Les URI des périphériques de fichier ont été désactivés. Pour l’activer, "
+"reportez-vous à la directive FileDevice dans « %s/cupsd.conf »."
+
+msgid "Folio"
+msgstr "Folio"
+
+msgid "Forbidden"
+msgstr "Interdit"
+
+msgid "General"
+msgstr "Général"
+
+msgid "Generic"
+msgstr "Générique"
+
+msgid "German FanFold"
+msgstr "German FanFold"
+
+msgid "German FanFold Legal"
+msgstr "German FanFold Légal"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU s’avère être de longueur indéfinie"
+
+msgid "Glossy Paper"
+msgstr "Papier brillant"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Niveaux de gris"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Dossier suspendu"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Dossier suspendu - 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk désactivé dans les Préférences Système.\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk désactivé dans les Préférences Système.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: annulation de la tâche d’impression…\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: connecté à l’imprimante…\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: connexion à l’imprimante…\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: fichier de contrôle envoyé correctement\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr ""
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: fichier de données envoyé correctement\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: mise en forme de la page %d…\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: chargement du fichier image…\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: recherche de l’imprimante…\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: établissement de la connexion\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr ""
+"INFO: fichier d’impression envoyé, en attente de la fin de la tâche "
+"d’impression…\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: imprimante occupée ; nouvel essai dans 10 secondes…\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: imprimante occupée ; nouvel essai dans 30 secondes…\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: imprimante occupée ; nouvel essai dans 5 secondes…\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr ""
+"INFO: imprimante ne prenant pas en charge IPP/%d.%d ; tentative avec "
+"IPP/1.0…\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: imprimante occupée ; nouvel essai dans 5 secondes…\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: imprimante actuellement déconnectée.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: imprimante actuellement hors ligne.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: imprimante en ligne à présent.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: imprimante hors ligne.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: imprimante non connectée ; nouvel essai dans 30 secondes…\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: impression de la page %d, %d %% accompli…\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: impression de la page %d…\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: prêt pour l’impression.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: envoi du fichier de contrôle (%lu octets)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: envoi du fichier de contrôle (%u octets)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: envoi des données\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: envoi du fichier de données (%ld octets)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: envoi du fichier de données (%lld octets)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: envoi des données d’impression…\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: fichier d’impression envoyé, %ld octets…\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: fichier d’impression envoyé, %lld octets…\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: mise en attente de la tâche LPR, %.0f %% achevé…\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr ""
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: impossible d’entrer en contact avec l’imprimante, mise en file "
+"d’attente sur l’imprimante suivante par ordre de classe…\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: utilisation de la zone AppleTalk par défaut « %s »\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: en attente de la fin de la tâche…\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: attente de disponibilité de l’imprimante…\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "ISO B4 Enveloppe"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (format supérieur)"
+
+msgid "ISO B5 Envelope"
+msgstr "ISO B5 Enveloppe"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "ISO B6 Enveloppe"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "Caractère de contrôle interdit"
+
+msgid "Illegal main keyword string"
+msgstr "Mot-clé essentiel interdit"
+
+msgid "Illegal option keyword string"
+msgstr "Mot-clé d’option interdit"
+
+msgid "Illegal translation string"
+msgstr "Traduction interdite"
+
+msgid "Illegal whitespace character"
+msgstr "Caractère « espace blanc » interdit"
+
+msgid "Installable Options"
+msgstr "Options installables"
+
+msgid "Installed"
+msgstr "Installée"
+
+msgid "IntelliBar Label Printer"
+msgstr "Imprimante pour étiquettes IntelliBar"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr ""
+
+msgid "Internal error"
+msgstr "Erreur interne"
+
+msgid "Internet Postage 2-Part"
+msgstr "Affranchissement Internet en 2 parties"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Affranchissement Internet en 2 parties - 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "Affranchissement Internet en 3 parties"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Affranchissement Internet en 3 parties - 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "Internet Printing Protocol"
+
+msgid "Invite Envelope"
+msgstr "Enveloppe d’invitation"
+
+msgid "Italian Envelope"
+msgstr "Enveloppe à l’italienne"
+
+msgid "JCL"
+msgstr "JCL ( Langage de contrôle de tâche )"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "La tâche n°%d est déjà abandonnée - impossible de l’annuler."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "La tâche n°%d est déjà annulée - impossible de l’annuler."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "La tâche n°%d est déjà terminée - impossible de l’annuler."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "terminée"
+
+msgid "Job Created"
+msgstr "Tâche créée"
+
+msgid "Job ID: "
+msgstr "Identifiant de tâche : "
+
+msgid "Job Options Changed"
+msgstr "Options de la tâche modifiées"
+
+msgid "Job Stopped"
+msgstr "arrêtée"
+
+msgid "Job UUID: "
+msgstr "UUID de tâche : "
+
+msgid "Job is completed and cannot be changed."
+msgstr "La tâche est terminée et ne peut être modifiée."
+
+msgid "Job operation failed:"
+msgstr "L’opération sur la tâche a échoué :"
+
+msgid "Job state cannot be changed."
+msgstr "L’état de la tâche ne peut être modifié."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "Tâches"
+
+msgid "Kaku2 Envelope"
+msgstr "Enveloppe Kaku2"
+
+msgid "Kaku3 Envelope"
+msgstr "Enveloppe Kaku3"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "Hôte ou imprimante LPD/LPR"
+
+msgid "Label Printer"
+msgstr "Imprimante pour étiquettes"
+
+msgid "Label Top"
+msgstr "Étiquette supérieure"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Adresse étendue"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Adresse étendue - 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet série PCL 4/5"
+
+msgid "Light"
+msgstr "Clair"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Ligne dépassant la longueur maximale autorisée (255 caractères)"
+
+msgid "List Available Printers"
+msgstr "Énumérer les imprimantes disponibles"
+
+msgid "Location: "
+msgstr "Emplacement : "
+
+msgid "Long-Edge (Portrait)"
+msgstr "Bord le plus long (Portrait)"
+
+msgid "Make and Model: "
+msgstr "Marque et modèle : "
+
+msgid "Manual Feed"
+msgstr "Alimentation manuelle"
+
+msgid "Media Dimensions: "
+msgstr "Dimensions du papier : "
+
+msgid "Media Limits: "
+msgstr "Limites du papier : "
+
+msgid "Media Name: "
+msgstr "Nom du papier : "
+
+msgid "Media Size"
+msgstr "Taille du papier"
+
+msgid "Media Source"
+msgstr "Source du papier"
+
+msgid "Media Tracking"
+msgstr "Crénage du papier"
+
+msgid "Media Type"
+msgstr "Type de papier"
+
+msgid "Medium"
+msgstr "Moyen"
+
+msgid "Memory allocation error"
+msgstr "Erreur d’allocation de mémoire"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "Entête PPD-Adobe-4.x manquant"
+
+msgid "Missing asterisk in column 1"
+msgstr "Astérisque manquant à la colonne 1"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "Chaîne de valeur manquante"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Modèle : name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "Modifier la classe"
+
+msgid "Modify Printer"
+msgstr "Modifier l’imprimante"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Enveloppe Monarch"
+
+msgid "Move All Jobs"
+msgstr "Transférer toutes les tâches"
+
+msgid "Move Job"
+msgstr "Transférer la tâche"
+
+msgid "Moved Permanently"
+msgstr "Transférées de façon permanente"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: fichier d’impression accepté - identifiant de tâche %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: fichier d’impression accepté - identifiant de tâche inconnu.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "Pointeur de fichier PPD NULL."
+
+msgid "Name OID uses indefinite length"
+msgstr "L’OID du nom s’avère être de longueur indéfinie"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Jamais"
+
+msgid "New Stylus Color Series"
+msgstr "Nouvelles série Stylus Color"
+
+msgid "New Stylus Photo Series"
+msgstr "Nouvelles série Stylus Photo"
+
+msgid "No"
+msgstr "Non"
+
+msgid "No Content"
+msgstr "Aucun contenu"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "Aucune SEQUENCE VarBind"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "Aucune connexion active"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "Aucun nom de communauté"
+
+msgid "No default printer"
+msgstr "Aucune imprimante par défaut"
+
+msgid "No destinations added."
+msgstr "Aucune destination ajoutée."
+
+msgid "No error-index"
+msgstr "Paramètre error-index absent"
+
+msgid "No error-status"
+msgstr "Paramètre error-status absent"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "Aucun OID de nom"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "Paramètre request-id absent"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "Aucun abonnement trouvé."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "Aucune SEQUENCE variable-bindings"
+
+msgid "No version number"
+msgstr "Aucun numéro de version"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "Non continu (détection de marque)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "Non continu (détection Web)"
+
+msgid "Normal"
+msgstr "Normal"
+
+msgid "Not Found"
+msgstr "Introuvable"
+
+msgid "Not Implemented"
+msgstr "Non implémentée"
+
+msgid "Not Installed"
+msgstr "Non installée"
+
+msgid "Not Modified"
+msgstr "Non modifiée"
+
+msgid "Not Supported"
+msgstr "Non prise en charge"
+
+msgid "Not allowed to print."
+msgstr "Impression interdite"
+
+msgid "Note"
+msgstr "Remarque"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Off (1-Sided)"
+msgstr "Désactivé (recto)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Aide en ligne"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "L’ouverture de %s a échoué : %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup sans CloseGroup préalable"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI sans CloseUI/JCLCloseUI préalable"
+
+msgid "Operation Policy"
+msgstr "Règles de fonctionnement"
+
+msgid "Options Installed"
+msgstr "Options installées"
+
+msgid "Options: "
+msgstr "Options : "
+
+msgid "Output Mode"
+msgstr "Mode de sortie"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "La sortie de l’imprimante %s est envoyée à %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr ""
+"La sortie de l’imprimante %s est envoyée à l’imprimante distante %s sur %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "La sortie de l’imprimante %s/%s est envoyée à %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr ""
+"La sortie de l’imprimante %s/%s est envoyée à l’imprimante distante %s sur %"
+"s\n"
+
+msgid "PASS\n"
+msgstr "VALIDE\n"
+
+msgid "PCL Laser Printer"
+msgstr "Imprimante laser PCL"
+
+msgid "PRC1 Envelope"
+msgstr "Enveloppe PRC1"
+
+msgid "PRC10 Envelope"
+msgstr "Enveloppe PRC10"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "Enveloppe PRC2"
+
+msgid "PRC3 Envelope"
+msgstr "Enveloppe PRC3"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (format supérieur)"
+
+msgid "PRC4 Envelope"
+msgstr "Enveloppe PRC4"
+
+msgid "PRC5 Envelope"
+msgstr "Enveloppe PRC5"
+
+msgid "PRC6 Envelope"
+msgstr "Enveloppe PRC6"
+
+msgid "PRC7 Envelope"
+msgstr "Enveloppe PRC7"
+
+msgid "PRC8 Envelope"
+msgstr "Enveloppe PRC8"
+
+msgid "PRC9 Envelope"
+msgstr "Enveloppe PRC9"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "Le paquet ne contient aucun paramètre Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "Le paquet ne commence pas par SEQUENCE"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "Mot de passe pour %s sur %s ? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "Un mot de passe pour %s est nécessaire pour accéder à %s via SAMBA : "
+
+msgid "Pause Class"
+msgstr "Suspendre la classe"
+
+msgid "Pause Printer"
+msgstr "Suspendre l’imprimante"
+
+msgid "Peel-Off"
+msgstr "Décoller"
+
+msgid "Personal Envelope"
+msgstr "Enveloppe personnelle"
+
+msgid "Photo"
+msgstr "Photo"
+
+msgid "Photo Labels"
+msgstr "Étiquettes photo"
+
+msgid "Plain Paper"
+msgstr "Papier vierge"
+
+msgid "Policies"
+msgstr "Règles"
+
+msgid "Port Monitor"
+msgstr "Moniteur de port"
+
+msgid "PostScript Printer"
+msgstr "Imprimante PostScript"
+
+msgid "Postcard"
+msgstr "Carte postale"
+
+msgid "Print Density"
+msgstr "Densité d’impression"
+
+msgid "Print Job:"
+msgstr "Tâche d’impression :"
+
+msgid "Print Mode"
+msgstr "Mode d’impression"
+
+msgid "Print Rate"
+msgstr "Taux d’impression"
+
+msgid "Print Self-Test Page"
+msgstr "Imprimer une page d’autotest"
+
+msgid "Print Speed"
+msgstr "Vitesse d’impression"
+
+msgid "Print Test Page"
+msgstr "Imprimer la page de test"
+
+msgid "Print and Cut"
+msgstr "Impression à découper"
+
+msgid "Print and Tear"
+msgstr "Impression à détacher"
+
+msgid "Printed For: "
+msgstr "Imprimé pour : "
+
+msgid "Printed From: "
+msgstr "Imprimé de : "
+
+msgid "Printed On: "
+msgstr "Imprimé sur : "
+
+msgid "Printer Added"
+msgstr "ajoutée"
+
+msgid "Printer Default"
+msgstr "par défaut"
+
+msgid "Printer Deleted"
+msgstr "supprimée"
+
+msgid "Printer Modified"
+msgstr "modifiée"
+
+msgid "Printer Name: "
+msgstr "Nom de l’imprimante : "
+
+msgid "Printer Paused"
+msgstr "en pause"
+
+msgid "Printer Settings"
+msgstr "Réglages de l’imprimante"
+
+msgid "Printer:"
+msgstr "Imprimante :"
+
+msgid "Printers"
+msgstr "Imprimantes"
+
+msgid "Purge Jobs"
+msgstr "Purger les tâches"
+
+msgid "Quarto"
+msgstr "Quarto"
+
+msgid "Quota limit reached."
+msgstr "Quota atteint."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr ""
+"Classmt Proprio Tâche Fichier(s) Taille "
+"totale\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"Classmt Proprio Pri Tâche Fichiers Taille totale\n"
+
+msgid "Reject Jobs"
+msgstr "Refuser les tâches"
+
+msgid "Reprint After Error"
+msgstr "Réimprimer après erreur"
+
+msgid "Request Entity Too Large"
+msgstr "Entité de requête trop volumineuse"
+
+msgid "Resolution"
+msgstr "Résolution"
+
+msgid "Resume Class"
+msgstr "Relancer la classe"
+
+msgid "Resume Printer"
+msgstr "Relancer l’imprimante"
+
+msgid "Return Address"
+msgstr "Renvoyer l’adresse"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Renvoyer l’adresse - 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "Rembobiner"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Commande en cours d’exécution : %s %s -N -A %s -c « %s »\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE s’avère être de longueur indéfinie"
+
+msgid "See Other"
+msgstr "Autres"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "Port série #%d"
+
+msgid "Server Restarted"
+msgstr "Le serveur a redémarré"
+
+msgid "Server Security Auditing"
+msgstr "Vérification de la sécurité du serveur"
+
+msgid "Server Started"
+msgstr "Le serveur a démarré"
+
+msgid "Server Stopped"
+msgstr "Le serveur s’est arrêté"
+
+msgid "Service Unavailable"
+msgstr "Service indisponible"
+
+msgid "Set Allowed Users"
+msgstr "Définir les autorisations"
+
+msgid "Set As Server Default"
+msgstr "Définir comme valeur par défaut pour le serveur"
+
+msgid "Set Class Options"
+msgstr "Définir les options de classe"
+
+msgid "Set Printer Options"
+msgstr "Définir les options de l’imprimante"
+
+msgid "Set Publishing"
+msgstr "Définir la publication"
+
+msgid "Shipping Address"
+msgstr "Adresse de livraison"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "Adresse de livraison - 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "Bord le plus court (paysage)"
+
+msgid "Special Paper"
+msgstr "Papier spécial"
+
+msgid "Standard"
+msgstr "Standard"
+
+msgid "Starting Banner"
+msgstr "Début de la bannière"
+
+msgid "Statement"
+msgstr "Déclaration"
+
+msgid "Stylus Color Series"
+msgstr "Série Stylus Color"
+
+msgid "Stylus Photo Series"
+msgstr "Série Stylus Photo"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "Permuter les protocoles"
+
+msgid "Tabloid"
+msgstr "Tabloïd"
+
+msgid "Tabloid (Oversize)"
+msgstr "Tabloïd (format supérieur)"
+
+msgid "Tear"
+msgstr "Détacher"
+
+msgid "Tear-Off"
+msgstr "Détacher"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Position d’ajustement du détachement"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "Le fichier PPD « %s » n’a pu être trouvé."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "Le fichier PPD « %s » n’a pu être ouvert : %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Le nom de classe doit comporter au plus 127 caractères, tous imprimables, "
+"sans espace, « / » et « # »."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+"L’attribut « notify-lease-duration » ne peut pas être utilisé dans un "
+"abonnement de tâche."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Le nom d’imprimante doit comporter au plus 127 caractères, tous imprimables, "
+"sans espace, « / » et « # »."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "L’imprimante ou la classe n’a pas été trouvée."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "Le paramètre printer-uri « %s » contient des caractères non valides."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr ""
+"L’attribut « printer-uri » doit se présenter sous la forme « ipp://HOSTNAME/"
+"classes/CLASSNAME »."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+"L’attribut « printer-uri » doit se présenter sous la forme « ipp://HOSTNAME/"
+"printers/PRINTERNAME »."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"Le nom de l’abonnement ne doit pas contenir d’espace ni aucun des symboles "
+"« / », « ? » et « # »."
+
+msgid "There are too many subscriptions."
+msgstr "Les abonnements sont trop nombreux."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "Papier pour transfert thermique"
+
+msgid "Title: "
+msgstr "Titre : "
+
+msgid "Too many active jobs."
+msgstr "Trop de tâches en cours."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "Transparence"
+
+msgid "Tray"
+msgstr "Bac"
+
+msgid "Tray 1"
+msgstr "Bac 1"
+
+msgid "Tray 2"
+msgstr "Bac 2"
+
+msgid "Tray 3"
+msgstr "Bac 3"
+
+msgid "Tray 4"
+msgstr "Bac 4"
+
+msgid "URI Too Long"
+msgstr "URI trop long"
+
+msgid "US Executive"
+msgstr "US Executive"
+
+msgid "US Fanfold"
+msgstr "US Fanfold"
+
+msgid "US Ledger"
+msgstr "US Ledger"
+
+msgid "US Legal"
+msgstr "US Légal"
+
+msgid "US Legal (Oversize)"
+msgstr "US Légal (format supérieur)"
+
+msgid "US Letter"
+msgstr "US Lettre"
+
+msgid "US Letter (Oversize)"
+msgstr "US Lettre (format supérieur)"
+
+msgid "US Letter (Small)"
+msgstr "US Lettre (format inférieur)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "Port série USB #%d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "Impossible d’accéder au fichier cupsd.conf :"
+
+msgid "Unable to add RSS subscription:"
+msgstr "Impossible d’ajouter d’abonnement RSS :"
+
+msgid "Unable to add class:"
+msgstr "Impossible d’ajouter la classe :"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "Impossible d’ajouter l’imprimante :"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "Impossible d’annuler l’abonnement RSS :"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "Impossible de modifier l’attribut « printer-is-shared » :"
+
+msgid "Unable to change printer:"
+msgstr "Impossible de modifier l’imprimante :"
+
+msgid "Unable to change server settings:"
+msgstr "Impossible de modifier les réglages du serveur :"
+
+msgid "Unable to connect to host."
+msgstr "Connexion à l’hôte impossible."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "Impossible de créer le fichier temporaire :"
+
+msgid "Unable to delete class:"
+msgstr "Impossible de supprimer la classe :"
+
+msgid "Unable to delete printer:"
+msgstr "Impossible de supprimer l’imprimante :"
+
+msgid "Unable to do maintenance command:"
+msgstr "Impossible de lancer la commande de maintenance :"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "Impossible d’obtenir la liste des classes :"
+
+msgid "Unable to get class status:"
+msgstr "Impossible d’obtenir l’état de la classe :"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "Impossible d’obtenir la liste des gestionnaires d’impression :"
+
+msgid "Unable to get printer attributes:"
+msgstr "Impossible de récupérer les attributs de l’imprimante :"
+
+msgid "Unable to get printer list:"
+msgstr "Impossible d’obtenir la liste des imprimantes :"
+
+msgid "Unable to get printer status:"
+msgstr "Impossible d’obtenir l’état de l’imprimante :"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "Impossible de modifier la classe :"
+
+msgid "Unable to modify printer:"
+msgstr "Impossible de modifier l’imprimante :"
+
+msgid "Unable to move job"
+msgstr "Impossible de transférer la tâche."
+
+msgid "Unable to move jobs"
+msgstr "Impossible de transférer les tâches."
+
+msgid "Unable to open PPD file"
+msgstr "Impossible d’ouvrir le fichier PPD."
+
+msgid "Unable to open PPD file:"
+msgstr "Impossible d’ouvrir le fichier PPD :"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "Impossible d’ouvrir le fichier cupsd.conf :"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "Impossible d’imprimer la page de test :"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "Impossible d’exécuter « %s » : %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "Impossible de définir les options :"
+
+msgid "Unable to set server default:"
+msgstr "Impossible de définir la valeur par défaut pour le serveur :"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "Impossible de transmettre le fichier cupsd.conf :"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "Non autorisé"
+
+msgid "Units"
+msgstr "Unités"
+
+msgid "Unknown"
+msgstr "Inconnu"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "Paramètre printer-error-policy « %s » inconnu."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "Paramètre printer-op-policy « %s » inconnu."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Type de valeur non pris en charge"
+
+msgid "Upgrade Required"
+msgstr "Mise à niveau obligatoire"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Usage :\n"
+"\n"
+" lpadmin [-h serveur] -d destination\n"
+" lpadmin [-h serveur] -x destination\n"
+" lpadmin [-h serveur] -p imprimante [-c ajouter-classe] [-i interface] [-"
+"m modèle]\n"
+" [-r supprimer-classe] [-v périphérique] [-D "
+"description]\n"
+" [-P fichier-ppd] [-o nom=valeur]\n"
+" [-u allow:utilisateur,utilisateur] [-u deny:"
+"utilisateur,utilisateur]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "Usage : %s tâche utilisateur titre copies options [nom_fichier]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "Usage : %s id-tâche utilisateur titre copies options [fichier]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "Usage : %s id-tâche utilisateur titre copies options fichier\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Usage : cupsaddsmb [options] imprimante1 … imprimanteN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options :\n"
+" -E Chiffrer la connexion au serveur\n"
+" -H serveur_samba Faire appel au serveur SAMBA indiqué\n"
+" -U utilisateur_samba S’authentifier par le biais de l’utilisateur SAMBA "
+"indiqué\n"
+" -a Exporter toutes les imprimantes\n"
+" -h serveur_cups Faire appel au serveur CUPS indiqué\n"
+" -v Activer la verbosité (afficher les commandes)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Usage : cupsctl [options] [paramètre=valeur … paramètreN=valeurN]\n"
+"\n"
+"Options :\n"
+"\n"
+" -E Activer le chiffrement\n"
+" -U nom_utilisateur Indiquer le nom de l’utilisateur\n"
+" -h serveur[:port] Indiquer l’adresse du serveur\n"
+"\n"
+" --[no-]debug-logging Activer/désactiver le listage de débogage\n"
+" --[no-]remote-admin Activer/désactiver l’administration à distance\n"
+" --[no-]remote-any Autoriser/interdire l’accès à partir d’Internet\n"
+" --[no-]remote-printers Afficher/masquer les imprimantes à distance\n"
+" --[no-]share-printers Activer/désactiver le partage d’imprimante\n"
+" --[no-]user-cancel-any Autoriser/interdire aux utilisateurs d’annuler "
+"toute tâche\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Usage : cupsd [-c fichier_config] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c fichier_config Charger un autre fichier de configuration\n"
+"-f Exécuter en premier plan\n"
+"-F Exécuter en premier plan mais en mode détaché\n"
+"-h Afficher le présent message d’usage des options\n"
+"-l Exécuter cupsd à partir de launchd(8)\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Usage : cupstestdsc [options] nom_fichier.ps [… nom_fichier.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options :\n"
+"\n"
+" -h Afficher l’utilisation du programme\n"
+"\n"
+" Remarque : ce programme ne fait que valider les commentaires DSC et non "
+"le PostScript en tant que tel.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Usage : lpmove job/src dest\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Usage : lpoptions [-h serveur] [-E] -d imprimante\n"
+" lpoptions [-h serveur] [-E] [-p imprimante] -l\n"
+" lpoptions [-h serveur] [-E] -p imprimante -o option[=valeur] …\n"
+" lpoptions [-h serveur] [-E] -x imprimante\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Usage : lppasswd [-g nom_groupe]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Usage : lppasswd [-g nom_groupe] [nom_utilisateur]\n"
+" lppasswd [-g nom_groupe] -a [nom_utilisateur]\n"
+" lppasswd [-g nom_groupe] -x [nom_utilisateur]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Usage : lpq [-P dest] [-U nom_utilisateur] [-h nom_hôte[:port]] [-l] "
+"[+intervalle]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Usage : ppdc [options] nom_fichier.drv [ … nom_fichierN.drv ]\n"
+"Options :\n"
+" -D nom=valeur Définir la variable; dont le nom est indiqué; sur la "
+"valeur fournie.\n"
+" -I inclure-rép Inclure le répertoire au chemin de recherche.\n"
+" -c catalogue.po Charger le catalogue indiqué de messages.\n"
+" -d sortie-rép Préciser le répertoire de sortie.\n"
+" -l langue[,langue,…] Préciser la ou les langues de sortie (locale).\n"
+" -m Utiliser la valeur de ModelName comme nom de "
+"fichier.\n"
+" -t Tester les PPD au lieu de les générer.\n"
+" -v Activer la verbosité (lettres V complémentaires pour "
+"augmenter la verbosité).\n"
+" -z Comprimer les fichiers PPD par la méthode de zip "
+"GNU.\n"
+" --cr Fin de lignes à l’aide de CR (Mac OS 9).\n"
+" --crlf Fin de lignes à l’aide de CR + LF (Windows).\n"
+" --lf Fin de lignes à l’aide de LF (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"Usage : ppdhtml [options] nom_fichier.drv >nom_fichier.html\n"
+" -D nom=valeur Définir la variable, dont le nom est précisé, sur la "
+"valeur indiquée.\n"
+"Options :\n"
+" -I inclure-rép Inclure le répertoire au chemin de recherche.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Usage : ppdi [options] nom_fichier.ppd [ … nom_fichierN.ppd ]\n"
+"Options :\n"
+" -I inclure-rép\n"
+" -o nom_fichier.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Usage : ppdmerge [options] nom_fichier.ppd [ … nom_fichierN.ppd ]\n"
+"Options :\n"
+" -o nom_fichier.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"Usage : ppdpo [options] -o nom_fichier.po nom_fichier.drv [ … nom_fichierN."
+"drv ]\n"
+"Options :\n"
+" -D nom=valeur Définir la variable, dont le nom est précisé, sur la "
+"valeur indiquée.\n"
+" -I inclure-rép Inclure le répertoire au chemin de recherche.\n"
+" -v Activer la verbosité (lettres V complémentaires pour "
+"augmenter la verbosité).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Usage : snmp [hôte-ou-adresse-ip]\n"
+
+msgid "Value uses indefinite length"
+msgstr "La valeur s’avère être de longueur indéfinie"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind s’avère être de longueur indéfinie"
+
+msgid "Version uses indefinite length"
+msgstr "La version s’avère être de longueur indéfinie"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: ajout limité aux %d premières imprimantes trouvées"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: valeur booléenne attendue pour l’option waiteof « %s »\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: l’imprimante ne répond pas.\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr ""
+"WARNING: l’imprimante a envoyé le caractère EOF de manière inattendue\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: impossible d’ouvrir « %s :%s » : %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: impossible d’envoyer la requête d’état PAP"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: paquet PAP inattendu, de type %d\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: paquet PAP inconnu, de type %d\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: nombre attendu pour l’option d’état « %s »\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Oui"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"Vous devez accéder à cette page par l’URL <A HREF=\"https://%s:%d%s"
+"\">https://%s:%d%s</A>."
+
+msgid "You4 Envelope"
+msgstr "Enveloppe You4"
+
+msgid "ZPL Label Printer"
+msgstr "Imprimante pour étiquettes ZPL"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "abandonnée"
+
+msgid "canceled"
+msgstr "annulée"
+
+msgid "completed"
+msgstr "terminée"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr "convert : utilisez l’option -f pour préciser un fichier à convertir.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "L’exécution de « cups-deviced » a échoué."
+
+msgid "cups-driverd failed to execute."
+msgstr "L’exécution de « cups-driverd » a échoué."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb : aucun fichier PPD pour l’imprimante « %s » - %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl : connexion impossible au serveur : %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr ""
+"cupsd : prise en charge de launchd(8) non compilée dans le code ; exécution "
+"en mode normal.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter : impossible d’obtenir le fichier de tâche - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd : l’option -q est incompatible avec l’option -v.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd : l’option -v est incompatible avec l’option -q.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "périphérique pour %s/%s : %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "périphérique pour %s : %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "Le paramètre error-index s’avère être de longueur indéfinie"
+
+msgid "error-status uses indefinite length"
+msgstr "Le paramètre error-status s’avère être de longueur indéfinie"
+
+msgid "held"
+msgstr "retenue"
+
+msgid "help\t\tget help on commands\n"
+msgstr "help\t\taccéder à l’aide relative aux commandes\n"
+
+msgid "idle"
+msgstr "inactive"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin : l’imprimante %s est déjà un membre de la classe %s.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin : l’imprimante %s n’est pas un membre de la classe %s.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin : connexion impossible au serveur : %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin : impossible d’ouvrir le fichier PPD « %s » - %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin : impossible d’ouvrir le fichier « %s » : %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove : connexion impossible au serveur : %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions : impossible d’ajouter d’imprimante ou d’instance : %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions : impossible d’obtenir le fichier PPD de %s : %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd : mot de passe rejeté.\n"
+"Votre mot de passe doit comporter au moins six caractères, au moins une "
+"lettre et un chiffre,\n"
+"et ne peut pas reprendre votre nom d’utilisateur.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd : impossible de copier la chaîne de mot de passe : %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd : impossible d’ouvrir le fichier des mots de passe : %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr ""
+"lppasswd : impossible d’écrire dans le fichier des mots de passe : %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr ""
+"lppasswd : impossible d’effectuer de copie de sauvegarde de l’ancien fichier "
+"des mots de passe : %s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd : impossible de renommer le fichier des mots de passe : %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd : l’utilisateur « %s » et le groupe « %s » n’existent pas.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "membres de la classe %s :\n"
+
+msgid "no entries\n"
+msgstr "aucune entrée\n"
+
+msgid "no system default destination\n"
+msgstr "aucune destination système par défaut\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "en attente"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc : inclusion du répertoire « %s »…\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr ""
+"ppdc : ajout/actualisation du texte de l’interface utilisateur à partir de %"
+"s…\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc : valeur booléenne (%s) incorrecte à la ligne %d sur %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr ""
+"ppdc : substitution de variables ($%c) incorrecte à la ligne %d sur %s.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc : valeur booléenne attendue à la ligne %d sur %s.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc : code de choix attendu à la ligne %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc : nom/texte de choix attendu à la ligne %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc : chargement du fichier « %s » des informations de gestionnaire…\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc : chargement de messages pour la langue « %s »…\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc : chargement de messages de « %s »…\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc : impossible de créer le fichier PPD « %s » - %s.\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc : impossible de créer le répertoire de sortie %s : %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc : impossible de créer les canaux de sortie : %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc : impossible d’exécuter cupstestppd : %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc : impossible de déterminer la localisation de « %s » - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc : impossible de charger le fichier de localisation « %s » - %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc : variable indéfinie (%s) à la ligne %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc : écriture de %s…\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc : écriture des fichiers PPD dans le répertoire « %s »…\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge : fichier PPD %s ignoré…\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr ""
+"ppdmerge : impossible d’effectuer de copie de sauvegarde de %s en %s- %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "l’imprimante %s est désactivée depuis %s -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "l’imprimante %s est inactive, mais activée depuis %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "l’imprimante %s est en cours d’impression %s-%d (activée depuis %s)\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "l’imprimante %s/%s est désactivée depuis %s -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "l’imprimante %s/%s est inactive, mais activée depuis %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr ""
+"l’imprimante %s/%s est en cours d’impression %s-%d (activée depuis %s)\n"
+
+msgid "processing"
+msgstr "en cours"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "l’identifiant de la requête est %s-%d (%d fichier(s))\n"
+
+msgid "request-id uses indefinite length"
+msgstr "Le paramètre request-id s’avère être de longueur indéfinie"
+
+msgid "scheduler is not running\n"
+msgstr "le programmateur n’est pas en cours d’exécution\n"
+
+msgid "scheduler is running\n"
+msgstr "le programmateur s’exécute\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "stat sur %s a échoué : %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "status\t\tafficher l’état du daemon et la file d’attente\n"
+
+msgid "stopped"
+msgstr "arrêtée"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "destination système par défaut : %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "destination système par défaut : %s/%s\n"
+
+msgid "unknown"
+msgstr "inconnu"
+
+msgid "untitled"
+msgstr "sans titre"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindings s’avère être de longueur indéfinie"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " ATTN Aucune option ne correspond à %s.\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " ATTN Choix par défaut en conflit.\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " ATTN Le mot-clé %s d’option duplex peut ne pas fonctionner "
+#~ "comme attendu et doit s’intituler Duplex.\n"
+#~ " REF : page 122, rubrique 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " ATTN Le fichier contient un mélange de fins de ligne CR, LF et "
+#~ "CR LF.\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " ATTN La ligne %d ne contient que des espaces blancs.\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " ATTN Fichier APDialogExtension « %s » manquant\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " ATTN Fichier APPrinterIconPath « %s » manquant\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " ATTN Les fichiers PPD non-Windows doivent utiliser des fins de "
+#~ "ligne définis uniquement par LF et non CR LF.\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " ATTN Version PPD obsolète %.1f.\n"
+#~ " REF : page 42, rubrique 5.2.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s n’existe pas.\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s Choix %s erroné %s.\n"
+#~ " REF  : page 122, rubrique 5.17\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr ""
+#~ " %s Chaîne de traduction UTF-8 « %s » incorrecte pour l’option %s.\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Chaîne de traduction UTF-8 « %s » incorrecte pour l’option %s, "
+#~ "le choix %s.\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Valeur cupsFilter « %s » incorrecte.\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s cupsICCProfile « %s »  incorrect.\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Valeur cupsPreFilter « %s » incorrecte.\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s cupsUIConstraints %s : « %s ».\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s Langue « %s » incorrecte.\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s cupsUIConstraints %s vide.\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s Chaîne de traduction « %s » manquante pour l’option %s.\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Chaîne de traduction « %s » manquante pour l’option %s et le "
+#~ "choix %s.\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Choix manquant *%s %s dans UIConstraints « *%s %s *%s %s ».\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Choix manquant *%s %s dans cupsUIConstraints %s :« %s ».\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s Fichier cupsICCProfile manquant « %s ».\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s cupsUIResolver manquant « %s ».\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Option %s manquante dans UIConstraints « *%s %s *%s %s ».\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Option %s manquante dans cupsUIConstraints %s : « %s ».\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr ""
+#~ " %s Aucune traduction de base « %s » n’est comprise dans le "
+#~ "fichier.\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s %s requis ne définit pas le choix Aucun.\n"
+#~ " REF : page 122, rubrique 5.17\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr ""
+#~ " %s La valeur de hachage cupsICCProfile %s entre en collision avec %"
+#~ "s.\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver %s provoque une boucle.\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **ÉCHEC** Les noms de choix %s %s et %s diffèrent seulement par "
+#~ "leurs majuscules.\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **ÉCHEC** %s doit correspondre à 1284DeviceID.\n"
+#~ " REF : page 72, rubrique 5.5.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **ÉCHEC** DefaultImageableArea %s erroné.\n"
+#~ " REF : page 102, rubrique 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **ÉCHEC** DefaultPaperDimension %s erroné.\n"
+#~ " REF : page 103, rubrique 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **ÉCHEC** Choix %s %s erroné.\n"
+#~ " REF : page 84, rubrique 5.9\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr ""
+#~ " **ÉCHEC** LanguageEncoding %s incorrect - doit correspondre à "
+#~ "ISOLatin1.\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr ""
+#~ " **ÉCHEC** LanguageVersion %s incorrect - doit correspondre à "
+#~ "Anglais.\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **ÉCHEC** La chaîne de traduction par défaut pour l’option %s, "
+#~ "choix %s, contient des caractères 8 bits.\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **ÉCHEC** La chaîne de traduction par défaut pour l’option %s "
+#~ "contient des caractères 8 bits.\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **ÉCHEC** Les noms de groupe %s et %s diffèrent seulement par "
+#~ "leurs majuscules.\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **ÉCHEC** Plusieurs occurrences de %s, nom de choix %s.\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **ÉCHEC** Noms d’option %s et %s diffèrent seulement par leurs "
+#~ "majuscules.\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " %%%%BoundingBox erroné : %d en ligne.\n"
+#~ " REF : page 39, %%%%BoundingBox :\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " %%%%Page erroné  : %d en ligne.\n"
+#~ " REF : page 53, %%%%Page :\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " %%%%Pages erroné : %d en ligne.\n"
+#~ " REF : page 43, %%%%Pages :\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " La ligne %d dépasse 255 caractères (%d).\n"
+#~ " REF : page 25, longueur de ligne\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " %!PS-Adobe-3.0 manquant à la première ligne.\n"
+#~ " REF : page 17, 3.1 Uniformisation des documents\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " Commentaire %%EndComments manquant.\n"
+#~ " REF : page 41, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " %%BoundingBox manquant ou erroné : commentaire.\n"
+#~ " REF : page 39, %%BoundingBox :\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " %%Page manquant ou erroné : commentaires.\n"
+#~ " REF: page 53, %%Page :\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " %%Pages manquant ou erroné : commentaire.\n"
+#~ " REF : page 43, %%Pages :\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " %d lignes dépassant 255 caractères rencontrées.\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " Commentaires %%BeginDocument trop nombreux.\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " Commentaires %%EndDocument trop nombreux.\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " Attention : le fichier contient des données binaires.\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " Attention : pas de commentaire %%EndComments dans le fichier.\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " Attention : version DSC obsolète %.1f dans le fichier.\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s : opération non prise en charge."
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s : aucune décision possible.\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s : Erreur - %s destination non-existante des noms de variable "
+#~ "d’environnement « %s ».\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s : erreur - ID de tâche incorrect.\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr ""
+#~ "%s : erreur - ne peut pas imprimer les fichiers et modifier les tâches "
+#~ "simultanément.\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s : erreur - ne peut pas imprimer depuis stdin si les fichiers ou l’ID "
+#~ "de tâche sont fournis.\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s : erreur - jeu de caractères attendu après l’option « -S ».\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s : erreur - type de contenu attendu après l’option « -T ».\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s : erreur - copies attendues après l’option « -n ».\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s : erreur - nombre de copies attendu après l’option « -# ».\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s : erreur - destination attendue après l’option « -P ».\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s : erreur - destination attendue après l’option « -b ».\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s : erreur - destination attendue après l’option « -d ».\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s : erreur - formulaire attendu après l’option « -f ».\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s : erreur - nom de maintien attendu après l’option « -H ».\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s : erreur - nom d’hôte attendu après l’option « -H ».\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s : erreur - nom d’hôte attendu après l’option « -h ».\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s : erreur - liste des modes attendue après l’option « -y ».\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s : erreur - nom attendu après l’option « -%c ».\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s : erreur - chaîne d’option attendue après l’option « -o ».\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s : erreur - liste de pages attendue après l’option « -P ».\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s : erreur - priorité attendue après l’option « -%c ».\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s : erreur - raison attendue après l’option « -r ».\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s : erreur - titre attendu après l’option « -t ».\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s : erreur - nom d’utilisateur attendu après l’option « -U.\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s : erreur - nom d’utilisateur attendu après l’option « -u ».\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s : erreur - valeur attendue après l’option « -%c ».\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s : erreur - « terminé », « pas terminé » ou « tout » nécessaire après "
+#~ "l’option « -W ».\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: Erreur - le programmateur ne répond pas.\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s : erreur - destination inconnue « %s ».\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s : erreur - destination inconnue « %s/%s ».\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s : erreur - option inconnue « -%c ».\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s : erreur - option inconnue « -%s ».\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s : erreur - ID de tâche attendu après l’option « -i ».\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s : nom de destination dans la liste « %s »  non valide.\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr ""
+#~ "%s : identifiant de tâche (« -i jobid ») nécessaire avant « -H restart ».\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s : aucun filtre pour convertir %s/%s en %s/%s.\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr ""
+#~ "%s : désolé, aucune prise en charge du chiffrement incluse dans la "
+#~ "compilation.\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s : impossible de contacter le serveur.\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr " %s : impossible de déterminer le type MIME de « %s ».\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s : impossible d’ouvrir %s - %s\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s : impossible d’ouvrir %s - %s à la ligne %d."
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr ""
+#~ "%s : impossible de lire la base de données MIME à partir de « %s » ou « %"
+#~ "s ».\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s : destination inconnue « %s ».\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s : destination inconnue du type MIME %s/%s.\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s : option inconnue « %c ».\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s : source inconnue du type MIME %s/%s.\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s : avertissement - modification de format « %c » non prise en charge - "
+#~ "la sortie risque d’être incorrecte.\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s : avertissement - option du jeu de caractères ignorée.\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s : avertissement - option du type de contenu ignorée.\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s : avertissement - option de formulaire ignorée.\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s : avertissement - option de mode ignorée.\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s : erreur - %s destination non-existante des noms de variable "
+#~ "d’environnement « %s ».\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s : erreur - « option=valeur » attendu après l’option « -o ».\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "600 ppp (niveaux de gris)"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr ""
+#~ "Un mot de passe SAMBA est nécessaire pour exporter les gestionnaires "
+#~ "d’impression."
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr ""
+#~ "Un nom d’utilisateur SAMBA est nécessaire pour exporter les gestionnaires "
+#~ "d’impression."
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "Une classe porte déjà le nom de « %s »."
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "Une imprimante porte déjà le nom de « %s »."
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr ""
+#~ "Tentative d’attribution d’une valeur erronée au paramètre « printer-"
+#~ "state » %s : %d."
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "Les groupes d’attributs ne sont pas dans le bon ordre (%x < %x)."
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "URI de périphérique « %s » incorrect.\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "device-uri « %s » incorrect."
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "Schéma de device-uri « %s » incorrect."
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "document-format « %s » incorrect."
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Tampon des noms de fichier incorrect."
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Valeur de job-priority incorrecte."
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Valeur de job-sheets « %s » incorrecte."
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Type de job-sheets incorrect."
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Valeur de job-state incorrecte."
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Attribut de job-uri « %s » incorrect."
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "Paramètre notify-pull-method « %s » incorrect."
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "URI de notify-recipient-uri « %s » incorrect."
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "Couple option/choix incorrect à la ligne %d.\n"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "port-monitor « %s » incorrect"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Valeur de printer-state %d incorrecte."
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "Numéro de version de requête %d.%d incorrect."
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "Identifiant d’abonnement incorrect."
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "Jeu de caractères « %s » non pris en charge."
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "Impossible d’analyser le type « %s »."
+
+#~ msgid "Cover open."
+#~ msgstr "Couvercle ouvert."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "Développeur presque vide."
+
+#~ msgid "Developer empty!"
+#~ msgstr "Développeur vide."
+
+#~ msgid "Door open."
+#~ msgstr "Capot ouvert."
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: %%BoundingBox erroné : commentaire vu.\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: %%IncludeFeature erroné : commentaire.\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: %%Page erroné : commentaire dans le fichier.\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: %%PageBoundingBox erroné : commentaire dans le fichier.\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: fichier de périphérique SCSI « %s » erroné.\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: valeur de colonnes %d erronée.\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: valeur de cpi %f erronée.\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: valeur de lpi %f erronée.\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: format d’impression erroné.\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: l’imprimante de destination n’existe pas.\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: %%BoundingBox en double : commentaire vu.\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: %%Pages en double : commentaire vu.\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: fichier d’impression vide.\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr ""
+#~ "ERROR: chaîne entre guillemets droits attendue à la ligne %d sur %s.\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: erreur USB fatale.\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr ""
+#~ "ERROR: commande HP-GL/2 non valide détectée ; impossible d’imprimer le "
+#~ "fichier.\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: %%EndProlog manquant.\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: %%EndSetup manquant.\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: URI du périphérique manquant sur la ligne de commande et aucune "
+#~ "variable d’environnement DEVICE_URI.\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: valeur manquante à la ligne %d du fichier de bannière.\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: une ligne msgid est obligatoire avant toute chaîne de traduction à "
+#~ "la ligne %d sur %s.\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: aucun %%BoundingBox : commentaire dans l’en-tête.\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: aucun %%Pages : commentaire dans l’en-tête.\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: aucun URI trouvé pour le périphérique, dans argv[0] ou la variable "
+#~ "d’environnement DEVICE_URI.\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: aucune page trouvée.\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: plus de papier.\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: variable d’environnement d’imprimante non définie.\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: fichier d’impression non accepté (%s).\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: l’imprimante ne répond pas.\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: impossible de créer un fichier temporaire - %s.\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: impossible de créer un fichier temporaire : %s\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: impossible d’obtenir les attributs %d de la tâche (%s).\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: impossible de déterminer l’état de l’imprimante (%s).\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: impossible de localiser l’imprimante « %s ».\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr ""
+#~ "ERROR: impossible d’ouvrir le fichier image en vue de l’impression.\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: impossible d’ouvrir le fichier temporaire."
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: impossible d’imprimer %d colonnes de texte.\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: impossible d’imprimer la page de texte en %d x %d.\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: impossible de lire les données d’impression.\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: impossible d’envoyer les données d’impression (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: impossible d’envoyer les données d’impression.\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: impossible d’écrire %d octets vers l’imprimante.\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr ""
+#~ "ERROR: impossible d’écrire de données de trame dans le gestionnaire.\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: impossible d’écrire dans le fichier temporaire"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: texte inattendu à la ligne %d sur %s.\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: valeur de l’option de chiffrement « %s » inconnue.\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: format du catalogue de messages inconnu pour « %s ».\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: option « %s » inconnue avec la valeur « %s ».\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: inconnue version option value « %s ».\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr ""
+#~ "ERROR: valeur de luminosité non prise en charge %s, brightness=100.\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: valeur de gamma non prise en charge %s, gamma=1000.\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr "ERROR: valeur number-up non prise en charge %d, number-up=1.\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: valeur de number-up-layout non prise en charge %s, number-up-"
+#~ "layout=lrtb.\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: valeur de page-border non prise en charge %s, page-border=none.\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr ""
+#~ "ERROR: dépassement de capacité de doc_printf (%d octets) détecté, "
+#~ "processus en cours d’interruption.\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr ""
+#~ "ERROR: le filtre pdftops a cessé de fonctionner à l’issue du signal %d.\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr ""
+#~ "ERROR: le filtre pdftops a indiqué l’état %d lors de sa fermeture.\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops a quitté au signal %d.\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops a indiqué l’état %d lors de sa fermeture.\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: problème réversible : impossible de se connecter à l’imprimante ; "
+#~ "nouvel essai dans 30 secondes…\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "Fichier PPD vide."
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "Erreur : un nom d’hôte après l’option « -h » est nécessaire.\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Température de l’unité-fusible élevée."
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "Température de l’unité-fusible faible."
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "Attribut « printer-uri » trouvé mais sans attribut « job-id »"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Encre/toner presque vide."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Encre/toner vide."
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Poubelle d’encre/de toner presque remplie."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Poubelle d’encre/de toner remplie."
+
+#~ msgid "Interlock open."
+#~ msgstr "Dispositif de verrouillage ouvert."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "La tâche n°%d ne peut être redémarrée - aucun fichier."
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "La tâche n°%d n’existe pas."
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "La tâche n°%d est terminée et ne peut plus être modifiée."
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "La tâche n°%d n’est pas terminée."
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "La tâche n°%d n’est pas en attente d’authentification."
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "La tâche n°%d n’est pas retenue."
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "La tâche n°%s n’existe pas."
+
+#~ msgid "Job %d not found!"
+#~ msgstr "La tâche n°%d n’a pas été trouvée."
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "Les abonnements de tâche ne peuvent être renouvelés."
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "Langue « %s » non prise en charge."
+
+#~ msgid "Media jam!"
+#~ msgstr "Bourrage papier"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Bac à papier presque vide."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Bac à papier vide."
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Bac manquant."
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "Le bac à papier doit être rempli."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "Attribut « document-number » manquant."
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "Caractère Ë manquant à la ligne %d."
+
+#~ msgid "Missing form variable!"
+#~ msgstr "Un champ du formulaire HTML n’a pas été rempli."
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "Attribut notify-subscription-ids manquant"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "Attribut « requesting-user-name » manquant"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "Il manque des attributs indispensables."
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "Valeur manquante à la ligne %d.\n"
+
+#~ msgid "No PPD name!"
+#~ msgstr "Aucun nom PPD"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Aucun pilote d’impression Windows n’est installé."
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "Aucune tâche en cours sur « %s »."
+
+#~ msgid "No attributes in request!"
+#~ msgstr "Aucun attribut dans la requête."
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "Aucune information d’authentification."
+
+#~ msgid "No file!?!"
+#~ msgstr "Aucun fichier !?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "Aucune heure de modification"
+
+#~ msgid "No printer name!"
+#~ msgstr "Aucun nom d’imprimante."
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "Paramètre printer-uri absent pour la classe."
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "Paramètre printer-uri absent."
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "Paramètre printer-uri absent de la requête."
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "Aucun attribut d’abonnement dans la requête."
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC presque en fin de vie."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC en fin de vie."
+
+#~ msgid "Out of toner!"
+#~ msgstr "Plus de toner."
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Corbeille de sortie presque pleine."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Corbeille de sortie pleine."
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Bac en sortie manquant."
+
+#~ msgid "Printer offline."
+#~ msgstr "hors ligne."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "Imprimante SCSI"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr ""
+#~ "La valeur de l’attribut « notify-user-data » est trop grande (%d > 63 "
+#~ "octets)."
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "L’imprimante ou la classe n’est pas partagée."
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "L’attribut « job-printer-uri » est obligatoire."
+
+#~ msgid "Toner low."
+#~ msgstr "Niveau du toner faible."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "Valeurs job-sheets trop nombreuses (%d > 2)."
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "Valeurs printer-state-reasons trop nombreuses (%d > %d)."
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "Impossible d’ajouter de tâche à la destination « %s »."
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "Impossible d’allouer de la mémoire pour les types de fichiers."
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "Impossible de copier les fichiers des gestionnaires d’impression CUPS "
+#~ "64 bits (%d)."
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr ""
+#~ "Impossible de copier les fichiers des pilotes d’impression Windows "
+#~ "64 bits (%d)."
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "Impossible de copier les fichiers du gestionnaire d’impression CUPS (%d)."
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "Impossible de copier le fichier PPD - « %s »."
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "Impossible de copier le fichier PPD."
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Impossible de copier les fichiers des pilotes d’impression pour Windows "
+#~ "2000 (%d)."
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "Impossible de copier les fichiers des pilotes d’impression pour Windows "
+#~ "9x (%d)."
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "Impossible de copier le script d’interface - « %s »."
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "Impossible de créer le paramètre printer-uri."
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr ""
+#~ "Impossible de modifier des fichiers cupsd.conf de taille supérieure à "
+#~ "1 Mo."
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "Impossible de trouver la destination de la tâche."
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "Impossible de retrouver l’imprimante.\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Impossible d’installer les fichiers des pilotes d’impression pour Windows "
+#~ "2000 (%d)."
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "Impossible d’installer les fichiers des pilotes d’impression pour Windows "
+#~ "9x (%d)."
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "Impossible d’ouvrir le document %d dans la tâche %d."
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "Impossible d’envoyer la commande au gestionnaire de l’imprimante."
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr ""
+#~ "Impossible d’installer les fichiers des pilotes d’impression pour Windows "
+#~ "(%d).\n"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "Impossible d’exploiter l’ancien gestionnaire de la classe USB.\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "Erreur inconnue relative à l’imprimante (%s)"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Jeu de caractères « %s » non pris en charge."
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "Compression « %s » non prise en charge"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "Attribut de compression %s non pris en charge"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "Format « %s » non pris en charge"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "Format « %s » non pris en charge"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "Format « %s/%s » non pris en charge"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "Usage : convert [ options ]\n"
+#~ "\n"
+#~ "Options :\n"
+#~ "\n"
+#~ " -f nom_fichier Définir le fichier à convertir (dans le cas "
+#~ "contraire, stdin)\n"
+#~ " -o nom_fichier Définir le fichier à générer (dans le cas "
+#~ "contraire, stdout)\n"
+#~ " -i mime/type Définir le type MIME en entrée (dans le cas "
+#~ "contraire, auto-typed)\n"
+#~ " -j mime/type Définir le type MIME en sortie (dans le cas "
+#~ "contraire, application/pdf)\n"
+#~ " -P nom_fichier.ppd Définir le fichier PPD\n"
+#~ " -a 'nom=valeur …' Définir la ou les options\n"
+#~ " -U nom_utilisateur Définir le nom d’utilisateur pour la tâche\n"
+#~ " -J titre Définir le titre\n"
+#~ " -c copies Définir le nombre de copies\n"
+#~ " -u Supprimer le fichier PPD une fois terminé\n"
+#~ " -D Supprimer le fichier en entrée une fois terminé\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "Usage : cupsfilter -m mime/type [ options ] nom_fichier\n"
+#~ "\n"
+#~ "Options :\n"
+#~ "\n"
+#~ " -c cupsd.conf Définir le fichier cupsd.conf à utiliser\n"
+#~ " -j id-tâche[,N] Filtrer le fichier N sur la tâche indiquée (par "
+#~ "défaut, fichier 1)\n"
+#~ " -n copies Définir le nombre de copies\n"
+#~ " -o nom=valeur Définir la ou les options\n"
+#~ " -p nom_fichier.ppd Définir le fichier PPD\n"
+#~ " -t titre Définir le titre\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Usage : cupstestppd [options] nom_fichier1.ppd[.gz] [… nom_fichierN.ppd[."
+#~ "gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options :\n"
+#~ "\n"
+#~ " -R répertoire_root Définir un autre utilisateur root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Produire des avertissements plutôt que des "
+#~ "erreurs\n"
+#~ " -q Exécuter sans sortie à l’utilisateur\n"
+#~ " -r Utiliser le mode d’ouverture « sans contrainte »\n"
+#~ " -v Produire une légère verbosité\n"
+#~ " -vv Produire une importante verbosité\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: échec de lecture de la requête de canal latéral.\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr ""
+#~ "WARNING: l’option « %s » ne peut être incluse par le biais "
+#~ "d’IncludeFeature.\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: l’hôte à distance n’a pas répondu au bout de %d secondes par un "
+#~ "octet d’état de commande.\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: l’hôte à distance n’a pas répondu au bout de %d secondes par un "
+#~ "octet d’état de contrôle.\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: l’hôte à distance n’a pas répondu au bout de %d secondes par un "
+#~ "octet d’état de données.\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr "WARNING: la commande SCSI a expiré (%d) ; nouvel essai…\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: ce document n’est pas conforme aux normes Adobe (Adobe Document "
+#~ "Structuring Conventions) et risque de ne pas s’imprimer correctement.\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: choix « %s » inconnu pour l’option « %s ».\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: option « %s » inconnue.\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: débit en bauds %s non pris en charge.\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: problème réversible : l’hôte du réseau « %s » est occupé ; nouvel "
+#~ "essai dans %d secondes…\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr ""
+#~ "WARNING: aucun pilote d’impression pour Windows 2000 n’est installé."
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl : option « %s » inconnue\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl : option « -%c » inconnue\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr ""
+#~ "cupsd : nom de fichier de configuration attendu après l’option « -c ».\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd : impossible de déterminer le répertoire actif.\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd : argument « %s » inconnu - interruption en cours…\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd : option inconnue « %c » - interruption en cours…\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter : numéro de document %d non valide.\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter : identifiant %d de tâche non valide.\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter : un seul nom de fichier peut être spécifié.\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter : impossible de créer le fichier temporaire : %s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "Attribut « job-printer-uri » manquant."
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr ""
+#~ "lpadmin : le nom d’une classe doit se limiter aux caractères "
+#~ "imprimables.\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin : fichier PPD attendu après l’option « -P ».\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr ""
+#~ "lpadmin : paramètre allow/deny:liste_utilisateurs attendu après l’option "
+#~ "« -u ».\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin : classe attendue après l’option « -r ».\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin : nom de classe attendu après l’option « -c ».\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin : description attendue après l’option « -D ».\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin : URI de périphérique attendu après l’option « -v ».\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr ""
+#~ "lpadmin : type ou types de fichier attendu(s) après l’option « -I ».\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin : nom d’hôte attendu après l’option « -h ».\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin : interface attendue après l’option « -i ».\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin : emplacement attendu après l’option « -L ».\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin : modèle attendu après l’option « -m ».\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin : nom=valeur attendu après l’option « -o ».\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin : imprimante attendue après l’option « -p ».\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin : nom d’imprimante attendu après l’option « -d ».\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin : imprimante ou classe attendue après l’option « -x ».\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin : aucun nom de membre détecté.\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr ""
+#~ "lpadmin : le nom de l’imprimante doit se limiter aux caractères "
+#~ "imprimables.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin : impossible d’ajouter d’imprimante à la classe :\n"
+#~ " Vous devez d’abord indiquer le nom d’une imprimante.\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin : impossible de créer un fichier temporaire - %s\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin : impossible de créer un fichier temporaire : %s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin : impossible de retirer une imprimante de la classe :\n"
+#~ " Vous devez d’abord indiquer le nom d’une imprimante.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin : impossible de définir le fichier PPD :\n"
+#~ " Vous devez d’abord indiquer le nom d’une imprimante.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin : impossible de définir l’URI du périphérique :\n"
+#~ " Vous devez d’abord indiquer le nom d’une imprimante.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin : impossible de définir le script ou le fichier PPD interface :\n"
+#~ " Vous devez d’abord indiquer le nom d’une imprimante.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin : impossible de définir le script interface :\n"
+#~ " Vous devez d’abord indiquer le nom d’une imprimante.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin : impossible de définir la description de l’imprimante :\n"
+#~ " Vous devez d’abord indiquer le nom d’une imprimante.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin : impossible de définir l’emplacement de l’imprimante :\n"
+#~ " Vous devez d’abord indiquer le nom d’une imprimante.\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin : impossible de définir les options de l’imprimante :\n"
+#~ " Vous devez d’abord indiquer le nom d’une imprimante.\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin : option allow/deny « %s » inconnue.\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin : argument « %s » inconnu.\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin : option « %c » inconnue.\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin : avertissement - liste des types de contenu ignorée.\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr ""
+#~ "lpinfo : chaîne de l’identifiant du périphérique 1284 attendue après « --"
+#~ "id-périphérique ».\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo : langue attendue après « --language ».\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo : marque et modèle attendus après « --make-and-model »\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo : chaîne du produit attendue après « --product ».\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo : liste des schémas attendue après « --exclude-schemes ».\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo : liste des schémas attendue après « --include-schemes ».\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo : délai d’attente attendu après « --timeout ».\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo : argument « %s » inconnu.\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo : option « %c » inconnue.\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo : option « %s » inconnue.\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove : argument « %s » inconnu.\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove : option « %c » inconnue.\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions : aucune imprimante !?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions : impossible d’ouvrir le fichier PPD de %s ».\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions : imprimante ou classe inconnue.\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr ""
+#~ "lppasswd : seul l’utilisateur « root » est en mesure d’ajouter ou de "
+#~ "supprimer des mots de passe.\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd : fichier des mots de passe occupé.\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd : fichier des mots de passe non mis à jour.\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd : mot de passe non concordant.\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd : les mots de passe ne concordent pas.\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat : erreur - destination « %s » inexistante pour les noms de "
+#~ "variables d’environnement %s.\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "Attribut « notify-events » non renseigné."
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr ""
+#~ "L’URI « %s », indiquée par le paramètre notify-recipient-uri, est déjà "
+#~ "utilisée."
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr ""
+#~ "L’URI « %s » du paramètre « notify-recipient-uri » utilise un mode inconnu."
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d erroné."
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc : nom de résolution « %s » incorrect à la ligne %d sur %s.\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc : mot-clé d’état %s incorrect à la ligne %d sur %s.\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc : choix trouvé à la ligne %d sur %s, sans Option.\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc : #po en double pour la langue %s à la ligne %d sur %s.\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc : définition de filtre attendue à la ligne %d sur %s.\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc : nom de programme attendu à la ligne %d sur %s.\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr "ppdc : jeu de caractères attendu après Font à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc : ordre de couleurs attendu pour ColorModel à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc : espace de couleurs attendu pour ColorModel à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc : compression attendue pour ColorModel à la ligne %d de %s.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc : chaîne des contraintes attendue pour UIConstraints à la ligne %d "
+#~ "de %s.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc : mot-clé attendu du type de gestionnaire après DriverType à la "
+#~ "ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr "ppdc : type de duplex attendu après Duplex à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc : encodage attendu après Font à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc : nom de fichier attendu après #po %s à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc : nom/texte de groupe attendu à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc : nom de fichier d’inclusion attendu à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc : nombre entier attendu à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc : langue attendue après #po à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc : nom attendu après %s à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc : nom attendu après FileName à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc : nom attendu après Font à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc : nom attendu après Manufacturer à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc : nom attendu après MediaSize à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc : nom attendu après ModelName à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc : nom attendu après PCFileName à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc : nom/texte attendu après %s à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr "ppdc : nom/texte attendu après Installable à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc : nom/texte attendu après Resolution à la ligne %d de %s.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc : association nom/texte attendue pour ColorModel à la ligne %d de %"
+#~ "s.\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc : nom/texte d’option attendu à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc : section d’option attendue à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc : type d’option attendu à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc : champ de remplacement attendu après Resolution à la ligne %d de %"
+#~ "s.\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc : nombre réel attendu à la ligne %d de %s.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc : résolution/type de papier attendu après ColorProfile à la ligne %d "
+#~ "de %s.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc : résolution/type de papier attendu après SimpleColorProfile à la "
+#~ "ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc : sélecteur attendu après %s à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc : état attendu après Font à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc : chaîne attendue après Copyright à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc : chaîne attendue après Version à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc : deux noms d’option attendus à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc : valeur attendue après %s à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc : version attendue après Font à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc : nom de fichier #include/#po « %s » non valide\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc : coût pour le filtre à la ligne %d de %s non valide\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr "ppdc : type MIME pour le filtre à la ligne %d de %s non valide\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc : nom de programme vide pour le filtre à la ligne %d de %s non "
+#~ "valide\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc : section d’option « %s » à la ligne %d de %s non valide\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc : type d’option « %s » à la ligne %d de %s non valide\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc : #endif absent à la fin de « %s ».\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc : #if absent à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc : aucun catalogue de messages fourni pour la langue %s.\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc : option %s redéfinie sous un autre type à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr "ppdc : contrainte d’option doit inclure *nom à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc : instructions #if imbriquées trop nombreuses à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc : impossible de retrouver le fichier #po %s à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc : impossible de retrouver le fichier d’inclusion « %s » à la ligne %d "
+#~ "de %s.\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc : type de gestionnaire %s inconnu à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc : type de duplex « %s » inconnu à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc : taille du papier « %s » inconnue à la ligne %d de %s.\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc : jeton « %s » inconnu détecté à la ligne %d de %s.\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc : caractères de fin, dans le nombre réel « %s », inconnus à la ligne %"
+#~ "d de %s.\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc : chaîne commençant par %c non terminée, à la ligne %d de %s.\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge : LanguageVersion « %s » incorrect dans %s.\n"
diff --git a/locale/cups_id.po b/locale/cups_id.po
new file mode 100644
index 000000000..0acac4b36
--- /dev/null
+++ b/locale/cups_id.po
@@ -0,0 +1,6982 @@
+# translation of cups_id.po to Bahasa Indonesia
+#
+# "$Id$"
+#
+# Message catalog template for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 2005-2007 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# Citra Paska <dirgitadevina@yahoo.co.id>, 2008, 2009.
+#
+# Notes for Translators:
+#
+# The following prefixes MUST NOT be translated: "ALERT:", "CRIT:", "INFO:",
+# "NOTICE:", and "WARNING:".
+#
+# The "checkpo" program located in the "locale" source directory can be used
+# to verify that your translations do not introduce formatting errors or other
+# problems. Run with:
+#
+# cd locale
+# ./checkpo cups_LL.po
+#
+# where "LL" is your locale.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: cups_id\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-09-29 05:17+0700\n"
+"Last-Translator: Citra Paska <dirgitadevina@yahoo.co.id>\n"
+"Language-Team: Bahasa Indonesia\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(semua)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(nihil)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d entri\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tUsai kesalahan: lanjut\n"
+
+msgid "\tAlerts:"
+msgstr "\tPeringatan:"
+
+msgid "\tBanner required\n"
+msgstr "\tBanner diperlukan\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tSet karakter:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tKoneksi: langsung\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tKoneksi: jarak jauh\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tUkuran halaman utama:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tTiti utama:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tPengaturan port utama:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tDeskripsi: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tFormulir yang diakuisisi:\n"
+"\tJenis isi: apa saja\n"
+"\tJenis pencetak: tak dikenal\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tFormulir yang diperbolehkan:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tAntarmuka: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tAntarmuka: %s/interfaces/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tAntarmuka: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tLokasi: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tSaat gagal: tanpa peringatan\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tPengguna yang diperbolehkan:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tPengguna yang dilarang:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tjurik hadir\n"
+
+msgid "\tno entries\n"
+msgstr "\ttidak ada entri\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\tpencetak pada perangkat '%s' kecepatan -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\tproses cetak dinonaktifkan\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\tproses cetak diaktifkan\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\tantrian untuk %s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tantrian dinonaktifkan\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tantrian diaktifkan\n"
+
+msgid "\treason unknown\n"
+msgstr "\talasan tak dikenal\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" DETIL HASIL KECOCOKAN TES\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " REF: Halaman 15, seksi 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " REF: Halaman 15, seksi 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " REF: Halaman 19, seksi 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " REF: Halaman 20, seksi 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " REF: Halaman 27, seksi 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " REF: Halaman 42, seksi 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " REF: Halaman 16-17, seksi 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " REF: Halaman 42-45, seksi 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " REF: Halaman 45-46, seksi 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " REF: Halaman 48-49, seksi 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " REF: Halaman 52-54, seksi 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f bita\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " PASS Default%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " PASS DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " PASS DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " PASS FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " PASS FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " PASS LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " PASS LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " PASS Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " PASS ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " PASS NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " PASS PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " PASS PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " PASS PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " PASS PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " PASS Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " PASS ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" WARN \"%s %s\" konflik dengan \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" WARN %s berbagi prefiks umum dengan %s\n"
+" REF: Halaman 15, seksi 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" WARN LanguageEncoding diperlukan oleh spesifikasi PPD 4.3.\n"
+" REF: Halaman 56-57, seksi 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" WARN Manufacturer diperlukan oleh spesifikasi PPD 4.3.\n"
+" REF: Halaman 58-59, seksi 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" WARN PCFileName lebih panjang dari 8.3 melanggar spesifikasi "
+"PPD.\n"
+" REF: Halaman 61-62, seksi 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protocols mengandung PJL tetapi atribut JCL tidak diset.\n"
+" REF: Halaman 78-79, seksi 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protocols mengandung PJL dan BCP; diharapkan TBCP.\n"
+" REF: Halaman 78-79, seksi 5.7.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" WARN ShortNickName diperlukan oleh spesifikasi PPD 4.3.\n"
+" REF: Halaman 64-65, seksi 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr " %s Kehilangan berkas APDialogExtension \"%s\"\n"
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr " %s Kehilangan berkas APPrinterIconPath \"%s\"\n"
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr " %s Kehilangan berkas APPrinterLowInkTool \"%s\"\n"
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr " %s Kehilangan berkas APPrinterUtilityPath \"%s\"\n"
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr " %s Kehilangan berkas APScanAppPath \"%s\"\n"
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s Kehilangan berkas cupsFilter \"%s\"\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s Kehilangan berkas cupsPreFilter \"%s\"\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** Default%s %s JELEK\n"
+" REF: Halaman 40, seksi 4.5.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **FAIL** Atribut JobPatchFile JELEK dalam berkas\n"
+" REF: Halaman 24, seksi 3.4.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** Manufacturer JELEK (seharusnya \"HP\")\n"
+" REF: Halaman 211, tabel D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** Manufacturer JELEK (seharusnya \"Oki\")\n"
+" REF: Halaman 211, tabel D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** ModelName JELEK - \"%c\" tidak diperbolehkan dalam string.\n"
+" REF: Halaman 59-60, seksi 5.3.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** PSVersion JELEK - bukan \"(string) int\".\n"
+" REF: Halaman 62-64, seksi 5.3.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** Product JELEK - bukan \"(string)\".\n"
+" REF: Halaman 62, seksi 5.3.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** ShortNickName JELEK - lebih dari 31 karakter.\n"
+" REF: Halaman 64-65, seksi 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** FileVersion \"%s\" jelek\n"
+" REF: Halaman 56, seksi 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** FormatVersion \"%s\" jelek\n"
+" REF: Halaman 56, seksi 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr " **FAIL** Kode opsi utama tidak bisa diinterpretasikan: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN Default%s\n"
+" REF: Halaman 40, seksi 4.5.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN DefaultImageableArea\n"
+" REF: Halaman 102, seksi 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN DefaultPaperDimension\n"
+" REF: Halaman 103, seksi 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN FileVersion\n"
+" REF: Halaman 56, seksi 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN FormatVersion\n"
+" REF: Halaman 56, seksi 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN ImageableArea untuk PageSize %s\n"
+" REF: Halaman 41, seksi 5.\n"
+" REF: Halaman 102, seksi 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN LanguageEncoding\n"
+" REF: Halaman 56-57, seksi 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN LanguageVersion\n"
+" REF: Halaman 57-58, seksi 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN Manufacturer\n"
+" REF: Halaman 58-59, seksi 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN ModelName\n"
+" REF: Halaman 59-60, seksi 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN NickName\n"
+" REF: Halaman 60, seksi 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN PCFileName\n"
+" REF: Halaman 61-62, seksi 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN PSVersion\n"
+" REF: Halaman 62-64, seksi 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN PageRegion\n"
+" REF: Halaman 100, seksi 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN PageSize\n"
+" REF: Halaman 41, seksi 5.\n"
+" REF: Halaman 99, seksi 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN PageSize\n"
+" REF: Halaman 99-100, seksi 5.14.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN PaperDimension untuk PageSize %s\n"
+" REF: Halaman 41, seksi 5.\n"
+" REF: Halaman 103, seksi 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN Product\n"
+" REF: Halaman 62, seksi 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** DIPERLUKAN ShortNickName\n"
+" REF: Halaman 64-65, seksi 5.3.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " %d KESALAHAN DITEMUKAN\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " TIDAK ADA KESALAHAN\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " GAGAL\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" GAGAL\n"
+" **FAIL** Tidak bisa membuka berkas PPD - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" GAGAL\n"
+" **FAIL** Tidak bisa membuka berkas PPD - %s pada baris %d.\n"
+
+msgid " PASS\n"
+msgstr " LEWAT\n"
+
+msgid "#10 Envelope"
+msgstr "#10 Amplop"
+
+msgid "#11 Envelope"
+msgstr "#11 Amplop"
+
+msgid "#12 Envelope"
+msgstr "#12 Amplop"
+
+msgid "#14 Envelope"
+msgstr "#14 Amplop"
+
+msgid "#9 Envelope"
+msgstr "#9 Amplop"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bita\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f bita\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f milimeter"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f hingga %.0f x %.0f milimeter"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f inci"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f hingga %.2f x %.2f inci"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s menerima permintaan sejak %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%s tidak bisa diubah."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s tidak diimplementasikan oleh versi lpc CUPS.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s tidak siap\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s siap\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s siap dan sedang mencetak\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s tidak menerima permintaan sejak %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s menerima permintaan sejak %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s tidak menerima permintaan sejak %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [tugas %d localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s gagal: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: Kesalahan - tidak tersedia tujuan utama.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: Kesalahan - prioritas harus antara 1 dan 100.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: Kesalahan - terlalu banyak berkas - \"%s\"\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: Kesalahan - tidak bisa mengakses \"%s\" - %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: Penyaring \"%s\" tak tersedia: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: String penyaring \"%s\" tidak sah\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: Operasi gagal: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: Tidak bisa terhubung ke server\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: Tidak bisa membuka %s: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: Tidak bisa membuka berkas PPD: %s pada baris %d\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr "%s: Tidak bisa membuka berkas PPD: %s pada baris %d.\n"
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: kesalahan - tidak ada tujuan utama.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 inci/det."
+
+msgid "1.25x0.25\""
+msgstr "1,25x0,25\""
+
+msgid "1.25x2.25\""
+msgstr "1,25x2,25\""
+
+msgid "1.5 inch/sec."
+msgstr "1,5 inci/det."
+
+msgid "1.50x0.25\""
+msgstr "1,50x0,25\""
+
+msgid "1.50x0.50\""
+msgstr "1,50x0,50\""
+
+msgid "1.50x1.00\""
+msgstr "1,50x1,00\""
+
+msgid "1.50x2.00\""
+msgstr "1,50x2,00\""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 inci/det."
+
+msgid "10 x 11\""
+msgstr "10 x 11\""
+
+msgid "10 x 13\""
+msgstr "10 x 13\""
+
+msgid "10 x 14\""
+msgstr "10 x 14\""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 mm/det."
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 inci/det."
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 inci/det."
+
+msgid "12 x 11\""
+msgstr "12 x 11\""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 mm/det."
+
+msgid "120x60dpi"
+msgstr "120x60dpi"
+
+msgid "120x72dpi"
+msgstr "120x72dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 mm/det."
+
+msgid "15 x 11\""
+msgstr "15 x 11\""
+
+msgid "150 mm/sec."
+msgstr "150 mm/det."
+
+msgid "150dpi"
+msgstr "150dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 inci/det."
+
+msgid "2-Sided Printing"
+msgstr "2-Sisi Pencetakan"
+
+msgid "2.00x0.37\""
+msgstr "2,00x0,37\""
+
+msgid "2.00x0.50\""
+msgstr "2,00x0,50\""
+
+msgid "2.00x1.00\""
+msgstr "2,00x1.00\""
+
+msgid "2.00x1.25\""
+msgstr "2,00x1,25\""
+
+msgid "2.00x2.00\""
+msgstr "2,00x2,00\""
+
+msgid "2.00x3.00\""
+msgstr "2,00x3,00\""
+
+msgid "2.00x4.00\""
+msgstr "2,00x4,00\""
+
+msgid "2.00x5.50\""
+msgstr "2,00x5,50\""
+
+msgid "2.25x0.50\""
+msgstr "2,25x0,50\""
+
+msgid "2.25x1.25\""
+msgstr "2,25x1,25\""
+
+msgid "2.25x4.00\""
+msgstr "2,25x4,00\""
+
+msgid "2.25x5.50\""
+msgstr "2,25x5,50\""
+
+msgid "2.38x5.50\""
+msgstr "2,38x5,50\""
+
+msgid "2.5 inches/sec."
+msgstr "2,5 inci/det."
+
+msgid "2.50x1.00\""
+msgstr "2,50x1,00\""
+
+msgid "2.50x2.00\""
+msgstr "2,50x2,00\""
+
+msgid "2.75x1.25\""
+msgstr "2,75x1,25\""
+
+msgid "2.9 x 1\""
+msgstr "2,9 x 1\""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 mm/det."
+
+msgid "200 mm/sec."
+msgstr "200 mm/det."
+
+msgid "203dpi"
+msgstr "203dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "Seri 24-Pin"
+
+msgid "240x72dpi"
+msgstr "240x72dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 mm/det."
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 inci/det."
+
+msgid "3.00x1.00\""
+msgstr "3,00x1,00\""
+
+msgid "3.00x1.25\""
+msgstr "3,00x1,25\""
+
+msgid "3.00x2.00\""
+msgstr "3,00x2,00\""
+
+msgid "3.00x3.00\""
+msgstr "3,00x3,00\""
+
+msgid "3.00x5.00\""
+msgstr "3,00x5,00\""
+
+msgid "3.25x2.00\""
+msgstr "3,25x2,00\""
+
+msgid "3.25x5.00\""
+msgstr "3,25x5,00\""
+
+msgid "3.25x5.50\""
+msgstr "3,25x5,50\""
+
+msgid "3.25x5.83\""
+msgstr "3,25x5,83\""
+
+msgid "3.25x7.83\""
+msgstr "3,25x7,83\""
+
+msgid "3.5\" Disk"
+msgstr "Diska 3,5\""
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "Diska 3.5\" - 2 1/8 x 2 3/4\""
+
+msgid "3.50x1.00\""
+msgstr "3,50x1,00\""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 mm/det."
+
+msgid "300 mm/sec."
+msgstr "300 mm/det."
+
+msgid "300dpi"
+msgstr "300dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360dpi"
+
+msgid "360x180dpi"
+msgstr "360x180dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 inci/det."
+
+msgid "4.00x1.00\""
+msgstr "4,00x1,00\""
+
+msgid "4.00x13.00\""
+msgstr "4,00x13,00\""
+
+msgid "4.00x2.00\""
+msgstr "4,00x2,00\""
+
+msgid "4.00x2.50\""
+msgstr "4,00x2,50\""
+
+msgid "4.00x3.00\""
+msgstr "4,00x3,00\""
+
+msgid "4.00x4.00\""
+msgstr "4,00x4,00\""
+
+msgid "4.00x5.00\""
+msgstr "4,00x5,00\""
+
+msgid "4.00x6.00\""
+msgstr "4,00x6,00\""
+
+msgid "4.00x6.50\""
+msgstr "4,00x6,50\""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 mm/det."
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 inci/det."
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 inci/det."
+
+msgid "6.00x1.00\""
+msgstr "6,00x1,00\""
+
+msgid "6.00x2.00\""
+msgstr "6,00x2,00\""
+
+msgid "6.00x3.00\""
+msgstr "6,00x3,00\""
+
+msgid "6.00x4.00\""
+msgstr "6,00x4,00\""
+
+msgid "6.00x5.00\""
+msgstr "6,00x5,00\""
+
+msgid "6.00x6.00\""
+msgstr "6,00x6,00\""
+
+msgid "6.00x6.50\""
+msgstr "6,00x6,50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/det."
+
+msgid "600dpi"
+msgstr "600dpi"
+
+msgid "60dpi"
+msgstr "60dpi"
+
+msgid "60x720dpi"
+msgstr "60x720dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 inci/det."
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 inci/det."
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8,00x1,00\""
+
+msgid "8.00x2.00\""
+msgstr "8,00x2,00\""
+
+msgid "8.00x3.00\""
+msgstr "8,00x3,00\""
+
+msgid "8.00x4.00\""
+msgstr "8,00x4,00\""
+
+msgid "8.00x5.00\""
+msgstr "8,00x5,00\""
+
+msgid "8.00x6.00\""
+msgstr "8,00x6,00\""
+
+msgid "8.00x6.50\""
+msgstr "8,00x6,50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/det."
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 inci/det."
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "Seri 9-Pin"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr ""
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (Besar)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (Besar)"
+
+msgid "A4 (Small)"
+msgstr "A4 (Kecil)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (Besar)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "Terima Tugas"
+
+msgid "Accepted"
+msgstr "Diterima"
+
+msgid "Add Class"
+msgstr "Tambah Kelas"
+
+msgid "Add Printer"
+msgstr "Tambah Pencetak"
+
+msgid "Add RSS Subscription"
+msgstr "Tambah Subskripsi RSS"
+
+msgid "Address"
+msgstr "Alamat"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "Alamat - 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "Administrasi"
+
+msgid "Always"
+msgstr "Selalu"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "Aplikator"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr ""
+
+msgid "Bad OpenGroup"
+msgstr "OpenGroup Jelek"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "OpenUI/JCLOpenUI Jelek"
+
+msgid "Bad OrderDependency"
+msgstr "OrderDependency Jelek"
+
+msgid "Bad Request"
+msgstr "Permintaan Jelek"
+
+msgid "Bad SNMP version number"
+msgstr "Nomor versi SNMP jelek"
+
+msgid "Bad UIConstraints"
+msgstr "UIConstraints Jelek"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Nilai rangkap %d jelek."
+
+msgid "Bad custom parameter"
+msgstr "Parameter ubahan jelek"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Atribut huruf jelek: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Nilai number-up %d jelek."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Nilai page-ranges %d-%d jelek."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Pataka"
+
+msgid "Billing Information: "
+msgstr "Informasi Tagihan: "
+
+msgid "Bond Paper"
+msgstr "Kertas Surat"
+
+msgid "C0 Envelope"
+msgstr "C0 Amplop"
+
+msgid "C1 Envelope"
+msgstr "C1 Amplop"
+
+msgid "C2 Envelope"
+msgstr "C2 Amplop"
+
+msgid "C3 Envelope"
+msgstr "C3 Amplop"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "C4 Amplop"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "C5 Amplop"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "C6 Amplop"
+
+msgid "C65 Envelope"
+msgstr "C65 Amplop"
+
+msgid "C7 Envelope"
+msgstr "C7 Amplop"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr ""
+
+msgid "Cancel RSS Subscription"
+msgstr "Batal Subskripsi RSS"
+
+msgid "Change Settings"
+msgstr "Ubah Pengaturan"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Chou3 Amplop"
+
+msgid "Chou4 Envelope"
+msgstr "Chou4 Amplop"
+
+msgid "Classes"
+msgstr "Kelas"
+
+msgid "Clean Print Heads"
+msgstr "Bersihkan Kepala Pencetak"
+
+msgid "Color"
+msgstr "Warna"
+
+msgid "Color Mode"
+msgstr "Modus Warna"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"Perintah bisa saja singkat. Perintahnya:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "Nama komunitas memiliki panjang tak terdefinisi"
+
+msgid "Continue"
+msgstr "Lanjut"
+
+msgid "Continuous"
+msgstr "Terus-menerus"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Dibuat"
+
+msgid "Created On: "
+msgstr "Dibuat Pada: "
+
+msgid "Custom"
+msgstr "Ubahan"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Potong"
+
+msgid "Cutter"
+msgstr "Pemotong"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "DL Amplop"
+
+msgid "Dark"
+msgstr "Gelap"
+
+msgid "Darkness"
+msgstr "Gelap"
+
+msgid "Delete Class"
+msgstr "Hapus Kelas"
+
+msgid "Delete Printer"
+msgstr "Hapus Pencetak"
+
+msgid "Description: "
+msgstr "Deskripsi: "
+
+msgid "DeskJet Series"
+msgstr "Seri Deskjet"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "Tujuan \"%s\" bukanlah tugas yang diterima."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"Perangkat: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "Media Termal Langsung"
+
+msgid "Disabled"
+msgstr "Dinonaktifkan"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "Dokumen %d tidak ditemukan di tugas %d."
+
+msgid "Double Postcard"
+msgstr "Kartu Pos Ganda"
+
+msgid "Driver Name: "
+msgstr "Nama Penggerak: "
+
+msgid "Driver Version: "
+msgstr "Versi Penggerak: "
+
+msgid "Duplexer"
+msgstr "Pendupleks"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: Tidak bisa mengalokasikan memori untuk halaman info: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: Tidak bisa mengalokasikan memori untuk larik halaman: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "EPL1 Pencetak Label"
+
+msgid "EPL2 Label Printer"
+msgstr "EPL2 Pencetak Label"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: Berkas set karakter %s jelek\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: Jenis set karakter %s jelek\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: Baris deskripsi huruf: %s jelek\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: Arah teks %s jelek\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: Lebar teks %s jelek\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: Kesalahan %d mengirim permintaan PAPSendData: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: Tidak ada huruf pada berkas set karakter %s\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: Pencetak tidak merespon\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: Pencetak mengirim EOF yang tak diharapkan\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: Host jarak jauh tidak menerima berkas kontrol (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: Host jarak jauh tidak menerima data berkas (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr "ERROR: Kehabisan waktu saat mengirim data ke pencetak\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: Tidak bisa menambah berkas %d untuk tugas: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: Tidak bisa membatalkan tugas %d: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: Tidak bisa menyalin berkas PPD"
+
+msgid "ERROR: Unable to create pipe"
+msgstr "ERROR: Tidak bisa membuat pipa"
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: Tidak bisa membuat soket"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr "ERROR: Tidak bisa membuat berkas cetak berkompresi temporer: %s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: Tidak bisa membuat berkas temporer"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: Tidak bisa mengeksekusi pictwpstops: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: Tidak bisa mengeksekusi program gs"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: Tidak bisa mengeksekusi program pdftops"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr "ERROR: Tidak bisa mengeksekusi program pstops"
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr ""
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: Tidak bisa memperoleh permintaan PAP"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: Tidak bisa memperoleh respon PAP"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr "ERROR: Tidak bisa memperoleh berkas PPD untuk pencetak \"%s\" - %s.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: Tidak bisa memperoleh zona baku AppleTalk"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr ""
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr ""
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: Tidak bisa membuat alamat AppleTalk"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: Tidak bisa membuka \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: Tidak bisa membuka %s: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: Tidak bisa membuka berkas perangkat \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: Tidak bisa membuka berkas \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: Tidak bisa membuka berkas \"%s\": %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: Tidak bisa membuka berkas cetak \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: Tidak bisa membuka berkas cetak %s - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: Tidak bisa membuka berkas cetak %s: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr "ERROR: Tidak bisa membuka berkas cetak temporer berkompresi: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: Tidak bisa membaca data yang hendak dicetak"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: Tidak bisa mencari letak %ld dalam berkas - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: Tidak bisa mencari letak %lld dalam berkas - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: Tidak bisa mengirim perintah LPD"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr ""
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr ""
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: Tidak bisa mengirim data ke pencetak"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: Tidak bisa menunggu pictwpstops: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: Tidak bisa menulis %d bita ke \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: Tidak bisa menulis berkas kontrol"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: Tidak bisa menulis data yang hendak dicetak"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: Tidak bisa menulis data yang hendak dicetak: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: Urutan berkas \"%s\" tak dikenal\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: Format karakter \"%c\" tak dikenal\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: Modus cetak \"%s\" tak dikenal\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: select() gagal"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: tak dapat memulai berkas yang hendak dicetak"
+
+msgid "Edit Configuration File"
+msgstr "Sunting Berkas Konfigurasi"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Akhir Pataka"
+
+msgid "English"
+msgstr "Indonesian"
+
+msgid "Enter old password:"
+msgstr "Masukkan sandi lama:"
+
+msgid "Enter password again:"
+msgstr "Masukkan lagi sandinya:"
+
+msgid "Enter password:"
+msgstr "Masukkan sandi:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Masukkan nama pengguna dan sandi Anda atau nama pengguna dan sandi root "
+"untuk mengakses halaman ini. Apabila Anda menggunakan otentikasi Kerberos, "
+"pastikan bahwa Anda memiliki tiket Kerberos yang sah."
+
+msgid "Envelope Feed"
+msgstr "Amplop Feed"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Polis Kesalahan"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "Tiap 10 Label"
+
+msgid "Every 2 Labels"
+msgstr "Tiap 2 Label"
+
+msgid "Every 3 Labels"
+msgstr "Tiap 3 Label"
+
+msgid "Every 4 Labels"
+msgstr "Tiap 4 Label"
+
+msgid "Every 5 Labels"
+msgstr "Tiap 5 Label"
+
+msgid "Every 6 Labels"
+msgstr "Tiap 6 Label"
+
+msgid "Every 7 Labels"
+msgstr "Tiap 7 Label"
+
+msgid "Every 8 Labels"
+msgstr "Tiap 8 Label"
+
+msgid "Every 9 Labels"
+msgstr "Tiap 9 Label"
+
+msgid "Every Label"
+msgstr "Tiap Label"
+
+msgid "Expectation Failed"
+msgstr ""
+
+msgid "Export Printers to Samba"
+msgstr "Ekspor Pencetak melalui Samba"
+
+msgid "FAIL\n"
+msgstr "GAGAL\n"
+
+msgid "File Folder"
+msgstr "Map"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Map - 9/16 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"Berkas URI perangkat telah dinonaktifkan! Untuk mengaktifkannya, lihatlah "
+"petunjuk FileDevice dalam \"%s/cupsd.conf\"."
+
+msgid "Folio"
+msgstr "Folio"
+
+msgid "Forbidden"
+msgstr "Terlarang"
+
+msgid "General"
+msgstr "Umum"
+
+msgid "Generic"
+msgstr "Umum"
+
+msgid "German FanFold"
+msgstr "FanFold Jerman"
+
+msgid "German FanFold Legal"
+msgstr "FanFold Legal Jerman"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU memiliki panjang tak terdefinisi"
+
+msgid "Glossy Paper"
+msgstr "Kertas Glosi"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Skala Abu-abu"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Map Gantung"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Map Gantung - 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk ditiadakan pada Preferensi Sistem\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk ditiadakan pada Preferensi Sistem.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: Membatalkan tugas mencetak...\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: Terhubung ke pencetak...\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: Menghubungi pencetak...\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: Berkas kontrol berhasil dikirim\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr "INFO: Menyalin data yang hendak dicetak...\n"
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: Berkas data berhasil dikirim\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr "INFO: Halaman selesai %d...\n"
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: Memformat halaman %d...\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: Memuat berkas gambar...\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: Mencari pencetak...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: Membuka hubungan\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr ""
+"INFO: Berkas cetak dikirim, menunggu pencetak selesai mengerjakannya...\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: Pencetak sibuk; dicoba ulang 10 detik lagi...\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: Pencetak sibuk; dicoba ulang 30 detik lagi...\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: Pencetak sibuk; dicoba ulang 5 detik lagi...\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr "INFO: Pencetak tidak mendukung IPP/%d.%d, mencoba IPP/1.0...\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: Pencetak sibuk; dicoba ulang 5 detik lagi...\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: Pencetak saat ini tak terhubung.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: Pencetak saat ini tak terhubung.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: Pencetak saat ini terhubung.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: Pencetak saat ini tak terhubung.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: Pencetak tak terhubung; dicoba ulang 30 detik lagi...\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: Mencetak halaman %d, %d%% selesai...\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: Mencetak halaman %d...\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: Siap mencetak.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: Mengirim berkas kontrol (%lu bita)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: Mengirim berkas kontrol (%u bita)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: Mengirim data\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: Mengirim berkas data (%ld bita)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: Mengirim berkas data (%lld bita)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: Mengirim data yang hendak dicetak...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: Mengirim berkas yang hendak dicetak, %ld bita...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: Mengirim berkas yang hendak dicetak, %lld bita...\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr "INFO: Memulai halaman %d...\n"
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: Tidak bisa menghubungi pencetak, diantrikan ke pencetak selanjutnya "
+"pada kelas...\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: Menggunakan zona baku AppleTalk \"%s\"\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: Menunggu tugas diselesaikan...\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: Menunggu pencetak tersedia...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "ISO B4 Amplop"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (Besar)"
+
+msgid "ISO B5 Envelope"
+msgstr "ISO B5 Amplop"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "ISO B6 Amplop"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "Karakter kontrol ilegal"
+
+msgid "Illegal main keyword string"
+msgstr "String kata kunci utama ilegal"
+
+msgid "Illegal option keyword string"
+msgstr "String opsi kata kunci ilegal"
+
+msgid "Illegal translation string"
+msgstr "String translasi ilegal"
+
+msgid "Illegal whitespace character"
+msgstr ""
+
+msgid "Installable Options"
+msgstr ""
+
+msgid "Installed"
+msgstr ""
+
+msgid "IntelliBar Label Printer"
+msgstr "Pencetak Label IntelliBar"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr "Kesalahan Internal Server"
+
+msgid "Internal error"
+msgstr "Kesalahan internal"
+
+msgid "Internet Postage 2-Part"
+msgstr "Perangko Internet 2-Bagian"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Perangko Internet 2-Bagian - 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "Perangko Internet 3-Bagian"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Perangko Internet 3-Bagian - 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "Protokol Cetak Internet"
+
+msgid "Invite Envelope"
+msgstr "Amplop Undangan"
+
+msgid "Italian Envelope"
+msgstr "Amplop Italia"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "Tugas #%d telah dibatalkan - tidak bisa dibatalkan lagi."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "Tugas #%d sudah dibatalkan - tidak bisa dibatalkan lagi."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "Tugas #%d sudah diselesaikan - tidak bisa dibatalkan."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "Tugas Diselesaikan"
+
+msgid "Job Created"
+msgstr "Tugas Dibuat"
+
+msgid "Job ID: "
+msgstr "ID Tugas: "
+
+msgid "Job Options Changed"
+msgstr "Perubahan Opsi Tugas"
+
+msgid "Job Stopped"
+msgstr "Tugas Dihentikan"
+
+msgid "Job UUID: "
+msgstr "UUID Tugas: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "Tugas sudah diselesaikan dan tidak bisa diubah."
+
+msgid "Job operation failed:"
+msgstr "Operasi tugas gagal:"
+
+msgid "Job state cannot be changed."
+msgstr "Status tugas tidak bisa diubah."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "Tugas"
+
+msgid "Kaku2 Envelope"
+msgstr "Kaku2 Amplop"
+
+msgid "Kaku3 Envelope"
+msgstr "Kaku3 Amplop"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "Host atau Pencetak LPD/LPR"
+
+msgid "Label Printer"
+msgstr "Pencetak Label"
+
+msgid "Label Top"
+msgstr "Label Atas"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Alamat Besar"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Alamat Besar - 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "Seri LaserJet PCL 4/5"
+
+msgid "Light"
+msgstr "Cahaya"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Baris melebihi panjang yang diperbolehkan (255 karakter)"
+
+msgid "List Available Printers"
+msgstr "Daftar Pencetak yang Tersedia"
+
+msgid "Location: "
+msgstr "Lokasi: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "Sisi Panjang (Tegak)"
+
+msgid "Make and Model: "
+msgstr "Pembuat dan Model: "
+
+msgid "Manual Feed"
+msgstr ""
+
+msgid "Media Dimensions: "
+msgstr "Dimensi Media: "
+
+msgid "Media Limits: "
+msgstr "Batas Media: "
+
+msgid "Media Name: "
+msgstr "Nama Media: "
+
+msgid "Media Size"
+msgstr "Ukuran Media"
+
+msgid "Media Source"
+msgstr "Sumber Media"
+
+msgid "Media Tracking"
+msgstr ""
+
+msgid "Media Type"
+msgstr "Jenis Media"
+
+msgid "Medium"
+msgstr ""
+
+msgid "Memory allocation error"
+msgstr "Kesalahan alokasi memori"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "Kehilangan tajuk PPD-Adobe-4.x"
+
+msgid "Missing asterisk in column 1"
+msgstr "Kehilangan asterik pada kolom 1"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "Kehilangan string nilai"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "Ubah Kelas"
+
+msgid "Modify Printer"
+msgstr "Ubah Pencetak"
+
+msgid "Monarch"
+msgstr "Monarki"
+
+msgid "Monarch Envelope"
+msgstr "Amplop Monarki"
+
+msgid "Move All Jobs"
+msgstr "Pindah Semua Tugas"
+
+msgid "Move Job"
+msgstr "Pindah Tugas"
+
+msgid "Moved Permanently"
+msgstr "Dipindahkan Permanen"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: Berkas yang hendak dicetak diterima - ID tugas %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: Berkas yang hendak dicetak diterima - ID tugas tak dikenal.\n"
+
+msgid "NULL PPD file pointer"
+msgstr ""
+
+msgid "Name OID uses indefinite length"
+msgstr "Nama OID memiliki panjang tak terdefinisi"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Tidak Pernah"
+
+msgid "New Stylus Color Series"
+msgstr "Seri Stylus Color Baru"
+
+msgid "New Stylus Photo Series"
+msgstr "Seri Stylus Photo Baru"
+
+msgid "No"
+msgstr "Tidak"
+
+msgid "No Content"
+msgstr "Tak Ada Isi"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "Tidak ada VarBind SEQUENCE"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "Tidak ada koneksi yang aktif"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "Tidak ada nama komunitas"
+
+msgid "No default printer"
+msgstr "Tidak ada pencetak utama"
+
+msgid "No destinations added."
+msgstr "Tidak ada tujuan yang ditambah."
+
+msgid "No error-index"
+msgstr "Tidak ada error-index"
+
+msgid "No error-status"
+msgstr "Tidak ada error-status"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "Tidak ada nama OID"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "Tidak ada request-id"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "Tidak ada subskripsi yang ditemukan."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "Tidak ada variable-bindings SEQUENCE"
+
+msgid "No version number"
+msgstr "Tidak ada nomor versi"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "Tak bersambungan (Penanda)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "Tak bersambungan (Web)"
+
+msgid "Normal"
+msgstr "Normal"
+
+msgid "Not Found"
+msgstr "Tidak Ketemu"
+
+msgid "Not Implemented"
+msgstr "Tidak Diimplementasikan"
+
+msgid "Not Installed"
+msgstr "Tidak Terpasang"
+
+msgid "Not Modified"
+msgstr "Tidak Diubah"
+
+msgid "Not Supported"
+msgstr "Tidak Didukung"
+
+msgid "Not allowed to print."
+msgstr "Tidak diperbolehkan mencetak."
+
+msgid "Note"
+msgstr "Catatan"
+
+msgid "OK"
+msgstr "Oke"
+
+msgid "Off (1-Sided)"
+msgstr "Mati (1-Sisi)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Bantuan Langsung"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "Gagal membuka %s: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup tanpa CloseGroup lebih dulu"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI tanpa CloseUI/JCLCloseUI lebih dulu"
+
+msgid "Operation Policy"
+msgstr "Polis Operasi"
+
+msgid "Options Installed"
+msgstr "Opsi yang Terpasang"
+
+msgid "Options: "
+msgstr "Opsi: "
+
+msgid "Output Mode"
+msgstr "Modus Keluaran"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "Keluaran untuk pencetak %s dikirim ke %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr "Keluaran untuk pencetak %s dikirim ke pencetak jarak jauh %s pada %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "Keluaran untuk pencetak %s/%s dikirim ke %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr ""
+"Keluaran untuk pencetak %s/%s dikirim ke pencetak jarak jauh %s pada %s\n"
+
+msgid "PASS\n"
+msgstr "LEWAT\n"
+
+msgid "PCL Laser Printer"
+msgstr "Pencetak Laser PCL"
+
+msgid "PRC1 Envelope"
+msgstr "PRC1 Amplop"
+
+msgid "PRC10 Envelope"
+msgstr "PRC10 Amplop"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "PRC2 Amplop"
+
+msgid "PRC3 Envelope"
+msgstr "PRC3 Amplop"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (Besar)"
+
+msgid "PRC4 Envelope"
+msgstr "PRC4 Amplop"
+
+msgid "PRC5 Envelope"
+msgstr "PRC5 Amplop"
+
+msgid "PRC6 Envelope"
+msgstr "PRC6 Amplop"
+
+msgid "PRC7 Envelope"
+msgstr "PRC7 Amplop"
+
+msgid "PRC8 Envelope"
+msgstr "PRC8 Amplop"
+
+msgid "PRC9 Envelope"
+msgstr "PRC9 Amplop"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "Paket tidak mengandung Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "Paket tidak dimulai dengan SEQUENCE"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "Sandi untuk %s pada %s? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "Sandi untuk %s diperlukan untuk mengakses %s via SAMBA: "
+
+msgid "Pause Class"
+msgstr "Tahan Kelas"
+
+msgid "Pause Printer"
+msgstr "Tahan Pencetak"
+
+msgid "Peel-Off"
+msgstr ""
+
+msgid "Personal Envelope"
+msgstr "Amplop Pribadi"
+
+msgid "Photo"
+msgstr "Foto"
+
+msgid "Photo Labels"
+msgstr "Label Foto"
+
+msgid "Plain Paper"
+msgstr "Kertas Biasa"
+
+msgid "Policies"
+msgstr "Kebijakan"
+
+msgid "Port Monitor"
+msgstr "Port Monitor"
+
+msgid "PostScript Printer"
+msgstr "Pencetak PostScript"
+
+msgid "Postcard"
+msgstr "Kartu Pos"
+
+msgid "Print Density"
+msgstr "Densitas Cetak"
+
+msgid "Print Job:"
+msgstr "Tugas Cetak:"
+
+msgid "Print Mode"
+msgstr "Modus Cetak"
+
+msgid "Print Rate"
+msgstr ""
+
+msgid "Print Self-Test Page"
+msgstr "Cetak Halaman Uji-Mandiri"
+
+msgid "Print Speed"
+msgstr "Kecepatan Cetak"
+
+msgid "Print Test Page"
+msgstr "Cetak Halaman Uji"
+
+msgid "Print and Cut"
+msgstr "Cetak dan Potong"
+
+msgid "Print and Tear"
+msgstr ""
+
+msgid "Printed For: "
+msgstr "Dicetak Untuk: "
+
+msgid "Printed From: "
+msgstr "Dicetak Dari: "
+
+msgid "Printed On: "
+msgstr "Dicetak Pada: "
+
+msgid "Printer Added"
+msgstr "Pencetak Ditambah"
+
+msgid "Printer Default"
+msgstr "Pencetak Utama"
+
+msgid "Printer Deleted"
+msgstr "Pencetak Dihapus"
+
+msgid "Printer Modified"
+msgstr "Pencetak Diubah"
+
+msgid "Printer Name: "
+msgstr "Nama Pencetak: "
+
+msgid "Printer Paused"
+msgstr "Pencetak Ditahan"
+
+msgid "Printer Settings"
+msgstr "Pengaturan Pencetak"
+
+msgid "Printer:"
+msgstr "Pencetak:"
+
+msgid "Printers"
+msgstr "Pencetak"
+
+msgid "Purge Jobs"
+msgstr "Membersihkan Tugas"
+
+msgid "Quarto"
+msgstr "Kuarto"
+
+msgid "Quota limit reached."
+msgstr "Batas kuota telah dicapai."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr "Urut Tuan Tgs Berkas Ukur Total\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"Urut Tuan Pri Tugas Berkas Ukuran Total\n"
+
+msgid "Reject Jobs"
+msgstr "Tolak Tugas"
+
+msgid "Reprint After Error"
+msgstr "Cetak Ulang Usai Kesalahan"
+
+msgid "Request Entity Too Large"
+msgstr "Entitas Pesanan Terlalu Besar"
+
+msgid "Resolution"
+msgstr "Resolusi"
+
+msgid "Resume Class"
+msgstr ""
+
+msgid "Resume Printer"
+msgstr ""
+
+msgid "Return Address"
+msgstr "Alamat Pengembalian"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Alamat Pengembalian - 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "Ulang"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Menjalankan perintah: %s %s -N -A %s -c '%s'\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE memiliki panjang tak terdefinisi"
+
+msgid "See Other"
+msgstr "Lihat Lainnya"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "Port Serial #%d"
+
+msgid "Server Restarted"
+msgstr "Server Dijalankan Ulang"
+
+msgid "Server Security Auditing"
+msgstr "Audit Sekuritas Server"
+
+msgid "Server Started"
+msgstr "Server Dijalankan"
+
+msgid "Server Stopped"
+msgstr "Server Dihentikan"
+
+msgid "Service Unavailable"
+msgstr "Layanan Tak Tersedia"
+
+msgid "Set Allowed Users"
+msgstr "Atur Pengguna yang Boleh"
+
+msgid "Set As Server Default"
+msgstr "Atur Sebagai Baku Server"
+
+msgid "Set Class Options"
+msgstr "Atur Opsi Kelas"
+
+msgid "Set Printer Options"
+msgstr "Atur Opsi Pencetak"
+
+msgid "Set Publishing"
+msgstr "Atur Penerbitan"
+
+msgid "Shipping Address"
+msgstr "Alamat Pengiriman"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "Alamat Pengiriman - 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "Sisi-Pendek (Mendatar)"
+
+msgid "Special Paper"
+msgstr "Kertas Khusus"
+
+msgid "Standard"
+msgstr "Standar"
+
+msgid "Starting Banner"
+msgstr "Menjalankan Pataka"
+
+msgid "Statement"
+msgstr "Pernyataan"
+
+msgid "Stylus Color Series"
+msgstr "Seri Stylus Color"
+
+msgid "Stylus Photo Series"
+msgstr "Seri Stylus Photo"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "Berpindah Protokol"
+
+msgid "Tabloid"
+msgstr "Tabloid"
+
+msgid "Tabloid (Oversize)"
+msgstr "Tabloid (Besar)"
+
+msgid "Tear"
+msgstr ""
+
+msgid "Tear-Off"
+msgstr ""
+
+msgid "Tear-Off Adjust Position"
+msgstr ""
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "Berkas PPD \"%s\" tak bisa ditemukan."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "Berkas PPD \"%s\" tak bisa dibuka: %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Nama kelas paling banyak 127 karakter cetak dan tidak mengandung spasi, "
+"garis miring (/), atau pun tanda pagar (#)."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+"Atribut notify-lease-duration tak bisa digunakan bersama subskripsi tugas."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Nama pencetak paling banyak 127 karakter cetak dan tidak mengandung spasi, "
+"garis miring (/), atau tanda pagar (#)."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "Pencetak atau kelas tidak ditemukan."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "Terdapat karakter tidak sah pada printer-uri \"%s\"."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr ""
+"Bentuk printer-uri seharusnya menuruti format \"ipp://HOSTNAME/classes/"
+"CLASSNAME\"."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+"Bentuk printer-uri seharusnya menuruti format \"ipp://HOSTNAME/printers/"
+"PRINTERNAME\"."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"Nama subskripsi tidak bisa mengandung spasi, garis miring (/), tanda tanya "
+"(?), atau tanda pagar (#)."
+
+msgid "There are too many subscriptions."
+msgstr "Terlalu banyak subskripsi."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr ""
+
+msgid "Title: "
+msgstr "Judul: "
+
+msgid "Too many active jobs."
+msgstr "Terlalu banyak tugas yang aktif."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "Transparansi"
+
+msgid "Tray"
+msgstr "Baki"
+
+msgid "Tray 1"
+msgstr "Baki 1"
+
+msgid "Tray 2"
+msgstr "Baki 2"
+
+msgid "Tray 3"
+msgstr "Baki 3"
+
+msgid "Tray 4"
+msgstr "Baki 4"
+
+msgid "URI Too Long"
+msgstr "URI Terlalu Panjang"
+
+msgid "US Executive"
+msgstr "Eksekutif AS"
+
+msgid "US Fanfold"
+msgstr "Fanfold AS"
+
+msgid "US Ledger"
+msgstr "Ledger AS"
+
+msgid "US Legal"
+msgstr "Legal AS"
+
+msgid "US Legal (Oversize)"
+msgstr "Legal AS (Besar)"
+
+msgid "US Letter"
+msgstr "Kuarto AS"
+
+msgid "US Letter (Oversize)"
+msgstr "Kuarto AS (Besar)"
+
+msgid "US Letter (Small)"
+msgstr "Kuarto AS (Kecil)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "Port Serial USB #%d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "Tidak bisa mengakses berkas cupsd.conf:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "Tidak bisa menambah subskripsi RSS:"
+
+msgid "Unable to add class:"
+msgstr "Tidak bisa menambah kelas:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "Tidak bisa menambah pencetak:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "Tidak bisa membatalkan subskripsi RSS:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "Tidak bisa mengubah atribut printer-is-shared:"
+
+msgid "Unable to change printer:"
+msgstr "Tidak bisa mengubah pencetak:"
+
+msgid "Unable to change server settings:"
+msgstr "Tidak bisa mengubah pengaturan server:"
+
+msgid "Unable to connect to host."
+msgstr "Tidak bisa terhubung ke host."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "Tidak bisa membuat berkas temporer:"
+
+msgid "Unable to delete class:"
+msgstr "Tidak bisa menghapus kelas:"
+
+msgid "Unable to delete printer:"
+msgstr "Tidak bisa menghapus pencetak:"
+
+msgid "Unable to do maintenance command:"
+msgstr ""
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "Tidak bisa memperoleh daftar kelas:"
+
+msgid "Unable to get class status:"
+msgstr "Tidak bisa memperoleh status kelas:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "Tidak bisa memperoleh daftar penggerak pencetak:"
+
+msgid "Unable to get printer attributes:"
+msgstr "Tidak bisa memperoleh atribut pencetak:"
+
+msgid "Unable to get printer list:"
+msgstr "Tidak bisa memperoleh daftar pencetak:"
+
+msgid "Unable to get printer status:"
+msgstr "Tidak bisa memperoleh status pencetak:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "Tidak bisa mengubah kelas:"
+
+msgid "Unable to modify printer:"
+msgstr "Tidak bisa mengubah pencetak"
+
+msgid "Unable to move job"
+msgstr "Tidak bisa memindahkan tugas"
+
+msgid "Unable to move jobs"
+msgstr "Tidak bisa memindahkan tugas"
+
+msgid "Unable to open PPD file"
+msgstr "Tidak bisa membuka berkas PPD"
+
+msgid "Unable to open PPD file:"
+msgstr "Tidak bisa membuka berkas PPD:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "Tidak bisa membuka berkas cupsd.conf:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "Tidak bisa mencetak halaman uji:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "Tidak bisa menjalankan \"%s\": %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "Tidak bisa mengeset opsi:"
+
+msgid "Unable to set server default:"
+msgstr ""
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "Tidak bisa mengunggah berkas cupsd.conf:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "Terlarang"
+
+msgid "Units"
+msgstr "Unit"
+
+msgid "Unknown"
+msgstr "Tak Dikenal"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "printer-error-policy \"%s\" tak dikenal."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "printer-op-policy \"%s\" tak dikenal."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Jenis nilai tak didukung"
+
+msgid "Upgrade Required"
+msgstr "Diperlukan Naik-Tingkat"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Penggunaan:\n"
+"\n"
+" lpadmin [-h server] -d tujuan\n"
+" lpadmin [-h server] -x tujuan\n"
+" lpadmin [-h server] -p pencetak [-c tambah-kelas] [-i antarmuka] [-m "
+"model]\n"
+" [-r buang-kelas] [-v perangkat] [-D deskripsi]\n"
+" [-P berkas-ppd] [-o nama=nilai]\n"
+" [-u allow:pengguna,pengguna] [-u deny:pengguna,"
+"pengguna]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "Penggunaan: %s tugas pengguna judul salinan opsi [berkas]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "Penggunaan: %s id-tugas pengguna judul rangkap opsi [berkas]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "Penggunaan: %s id-tugas pengguna judul rangkap opsi berkas\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Penggunaan: cupsaddsmb [opsi] pencetak1 ... pencetakN\n"
+" cupsaddsmb [opsi] -a\n"
+"\n"
+"Opsi:\n"
+" -E Mengenkripsi koneksi ke server\n"
+" -H samba-server Menggunakan server SAMBA yang diberikan\n"
+" -U samba-user Otentikasi menggunakan nama pengguna SAMBA yang "
+"diberikan\n"
+" -a Mengekspor semua pencetak\n"
+" -h cups-server Menggunakan server CUPS yang ditentukan\n"
+" -v Menjadi riuh (menampilkan perintah)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Penggunaan: cupsctl [opsi] [param=nilai ... paramN=nilaiN]\n"
+"\n"
+"Opsi:\n"
+"\n"
+" -E Mengaktifkan enkripsi\n"
+" -U namapengguna Menentukan nama pengguna\n"
+" -h server[:portal Menentukan alamat server\n"
+"\n"
+" --[no-]debug-logging Mengaktifkan/tidak pencatat debug\n"
+" --[no-]remote-admin Mengaktifkan/tidak administrasi jarak jauh\n"
+" --[no-]remote-any Biarkan/cegah akses dari Internet\n"
+" --[no-]remote-printers Tampilkan/sembunyikan pencetak jarak jauh\n"
+" --[no-]share-printers Mengaktifkan/tidak pencetak yang dikongsi\n"
+" --[no-]user-cancel-any Biarkan/cegah pengguna biasa membatalkan tugas\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Penggunaan: cupsd [-c berkas-konfigurasi] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c berkas-konfigurasi Memuat berkas konfigurasi alternatif\n"
+"-f Berjalan pada latar depan\n"
+"-F Berjalan pada latar depan tapi terpisah\n"
+"-h Tampilkan pesan ini\n"
+"-l Menjalankan cupsd dari launchd(8)\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+"Penggunaan: cupsfilter -m mime/jenis [ opsi ] berkas\n"
+"\n"
+"Opsi:\n"
+"\n"
+" -c cupsd.conf Mengeset berkas cupsd.conf untuk digunakan\n"
+" -e Menggunakan tiap penyaring dari berkas PPD\n"
+" -j job-id[,N] Menyaring berkas N dari tugas yang diberikan (baku adalah "
+"berkas 1)\n"
+" -n copies Mengeset banyaknya salinan\n"
+" -o name=value Mengeset opsi\n"
+" -p filename.ppd Mengeset berkas PPD\n"
+" -t title Mengeset judul\n"
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Penggunaan: cupstestdsc [opsi] berkas.ps [... berkas.ps]\n"
+" cupstestdsc [opsi] -\n"
+"\n"
+"Opsi:\n"
+"\n"
+" -h Menampilkan cara guna program\n"
+"\n"
+" Catatan: program ini hanya memvalidasi komentar DSC, bukan PostScript "
+"itu sendiri.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Penggunaan: lpmove tugas/sumber tujuan\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Penggunaan: lpoptions [-h server] [-E] -d pencetak\n"
+" lpoptions [-h server] [-E] [-p pencetak] -l\n"
+" lpoptions [-h server] [-E] -p pencetak -o opsi[=nilai] ...\n"
+" lpoptions [-h server] [-E] -x pencetak\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Penggunaan: lppasswd [-g namakelompok]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Penggunaan: lppasswd [-g namakelompok] [namapengguna]\n"
+" lppasswd [-g namakelompok] -a [namapengguna]\n"
+" lppasswd [-g namakelompok] -x [namapengguna]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Penggunaan: lpq [-P tujuan] [-U namapengguna] [-h namahost[:portal]] [-l] "
+"[+interval]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Penggunaan: ppdc [opsi] berkas.drv [ ... berkasN.drv ]\n"
+"Opsi:\n"
+" -D nama=nilai Atur nilai variabel bernama.\n"
+" -I dir-inklusi Tambah direktori dalam jalur pencarian.\n"
+" -c katalog.po Memuat katalog pesan yang diinginkan.\n"
+" -d dir-keluaran Menentukan direktori keluaran.\n"
+" -l bhsa[,bhsa,...] Menentukan bahasa keluaran (lokal).\n"
+" -m Menggunakan nilai ModelName sebagai nama berkas.\n"
+" -t Menguji PPD ketimbang membuatnya.\n"
+" -v Menjadi riuh (tambahkan v lagi untuk lebih riuh).\n"
+" -z Kompres berkas PPD dengan GNU zip.\n"
+" --cr Akhiri baris dengan CR (Mac OS 9).\n"
+" --crlf Akhiri baris dengan CR + LF (Windows).\n"
+" --lf Akhiri baris dengan LF (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Penggunaan: ppdi [opsi] berkas.ppd [ ... berkasN.ppd ]\n"
+"Opsi:\n"
+" -I direktori\n"
+" -o berkas.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Penggunaan: ppdmerge [opsi] berkas.ppd [ ... berkasN.ppd ]\n"
+"Opsi:\n"
+" -o berkas.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Penggunaan: snmp [host-atau-alamat-ip]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Value memiliki panjang tak terdefinisi"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind memiliki panjang tak terdefinisi"
+
+msgid "Version uses indefinite length"
+msgstr "Version memiliki panjang tak terdefinisi"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: Hanya menambah %d pencetak pertama yang ditemukan"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: Diharapkan boolean untuk opsi waiteof \"%s\"\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: Pencetak tidak merespon!\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: Pencetak mengirim EOF yang tak diharapkan\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: Tidak bisa membuka \"%s:%s\": %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: Tidak bisa mengirim permintaan status PAP"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: Paket PAP berjenis %d tak dikenal\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: angka diharapkan untuk opsi status \"%s\"\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Ya"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"Anda harus mengakses halaman ini melalui URL <A HREF=\"https://%s:%d%s"
+"\">https://%s:%d%s</A>."
+
+msgid "You4 Envelope"
+msgstr "You4 Amplop"
+
+msgid "ZPL Label Printer"
+msgstr "Pencetak Label ZPL"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "digagalkan"
+
+msgid "canceled"
+msgstr "dibatalkan"
+
+msgid "completed"
+msgstr "diselesaikan"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr ""
+"konversi: Gunakan opsi -f untuk menentukan berkas yang hendak dikonversi.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "cups-deviced gagal dieksekusi."
+
+msgid "cups-driverd failed to execute."
+msgstr "cups-driverd gagal dieksekusi."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: Tidak ada berkas PPD untuk pencetak \"%s\" - %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: Tidak bisa menghubungi server: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr ""
+"cupsd: dukungan launchd(8) tidak dikompilasi serta, menjalankan dalam modus "
+"normal.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: Tidak bisa memperoleh berkas tugas - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd: Opsi -q tidak cocok dengan opsi -v.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd: Opsi -v tidak cocok dengan opsi -q.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "perangkat untuk %s/%s: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "perangkat untuk %s: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "error-index memiliki panjang tak terdefinisi"
+
+msgid "error-status uses indefinite length"
+msgstr "error-status memiliki panjang tak terdefinisi"
+
+msgid "held"
+msgstr "ditahan"
+
+msgid "help\t\tget help on commands\n"
+msgstr "bantuan\t\tmemperoleh bantuan dari baris perintah\n"
+
+msgid "idle"
+msgstr "menganggur"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: Pencetak %s sudah menjadi anggota kelas %s.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: Pencetak %s bukanlah anggota kelas %s.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: Tidak bisa terkoneksi ke server: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: Tidak bisa membuka berkas PPD \"%s\" - %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: Tidak bisa membuka berkas \"%s\": %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: Tidak bisa terkoneksi ke server: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: Tidak bisa menambah pencetak: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: Tidak bisa mendapatkan berkas PPD untuk %s: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: Maaf, sandi ditolak.\n"
+"Sandi Anda harus setidaknya 6 karakter, tidak memuat\n"
+"nama pengguna Anda, dan setidaknya memiliki satu huruf serta angka.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: Tidak bisa menyalin string sandi: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: Tidak bisa membuka berkas sandi: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: Tidak bisa menulis ke berkas sandi: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr "lppasswd: gagal mencadangkan berkas sandi yang lama: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: gagal mengubah nama berkas sandi: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: pengguna \"%s\" dan kelompok \"%s\" tidak ada.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "anggota kelas %s:\n"
+
+msgid "no entries\n"
+msgstr "tak ada entri\n"
+
+msgid "no system default destination\n"
+msgstr "tak ada tujuan sistem utama\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "tunda"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: Menambahkan direktori \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdf: Menambah/memperbaharui teks UI dari %s...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: Nilai boolean jelek (%s) pada baris %d dari %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: Subtitusi variabel jelek ($%c) pada baris %d dari %s.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: Diharapkan nilai boolean pada baris %d dari %s.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: Diharapkan kode pilihan pada baris %d dari %s.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: Diharapkan nama/teks pilihan pada baris %d dari %s.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: Memuat berkas informasi penggerak \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: Memuat pesan untuk loakl \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: Memuat pesan dari \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: Tidak bisa membuat berkas PPD \"%s\" - %s.\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: Tidak bisa membuat direktori keluaran %s: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: Tidak bisa membuat pipa keluaran: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: Tidak bisa mengeksekusi cupstestppd: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: Tidak bisa menemukan lokalisasi bagi \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: Tidak bisa memuat berkas lokalisasi \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: Variabel tak berdefinisi (%s) pada baris %d dari %s.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: Menulis %s...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: Menulis berkas PPD ke direktori \"%s\"...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: Mengabaikan berkas PPD %s...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: Tidak bisa mencadangkan %s ke %s- %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "pencetak %s ditiadakan sejak %s -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "pencetak %s sedang menganggur. diaktifkan sejak %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "pencetak %s saat ini tengah mencetak %s-%d. diaktifkan sejak %s\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "pencetak %s/%s dinonaktifkan sejak %s -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "pencetak %s/%s sedang menganggur. diaktifkan sejak %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "pencetak %s/%s saat ini tengah mencetak %s-%d. diaktifkan sejak %s\n"
+
+msgid "processing"
+msgstr "memproses"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "identitas permintaan adalah %s-%d (%d berkas)\n"
+
+msgid "request-id uses indefinite length"
+msgstr "request-id memiliki panjang tak terdefinisi"
+
+msgid "scheduler is not running\n"
+msgstr "penjadwal tidak berjalan\n"
+
+msgid "scheduler is running\n"
+msgstr "penjadwal tengah berjalan\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "status dari %s gagal: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "status\t\tmenampilkan status daemon dan antrian\n"
+
+msgid "stopped"
+msgstr "dihentikan"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "tujuan utama sistem: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "tujuan utama sistem: %s/%s\n"
+
+msgid "unknown"
+msgstr "tak dikenal"
+
+msgid "untitled"
+msgstr "tak berjudul"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindings memiliki panjang tak terdefinisi"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " WARN %s tidak memiliki opsi yang berkorespondensi!\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " WARN Pilihan utama mengalam konflik!\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " WARN Opsi kata kunci Duplex %s mungkin tidak bekerja seperti "
+#~ "yang diharapkan dan seharusnya dinamai Duplex!\n"
+#~ " REF: Halaman 122, seksi 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " WARN Berkas memiliki campuran CR, LF, dan CR LF pada akhir "
+#~ "baris!\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " WARN Baris %d hanya mengandung spasi!\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " WARN Berkas PPD non-Windows seharusnya hanya berakhir baris "
+#~ "LF, bukan CR LF!\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " WARN PPD versi %.1f telah usang!\n"
+#~ " REF: Halaman 42, seksi 5.2.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s tidak ada!\n"
+
+#~ msgid " %s %s file \"%s\" has the wrong capitalization!\n"
+#~ msgstr " %s %s berkas \"%s\" memiliki kapitalisasi yang salah!\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr " %s UTF-8 jelek \"%s\" string translasi untuk opsi %s!\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s UTF-8 jelek \"%s\" string translasi untuk opsi %s, pilihan %s!\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Nilai cupsFilter jelek \"%s\"!\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s cupsICCProfile jelek \"%s\"!\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Nilai cupsPreFilter jelek \"%s\"!\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s cupsUIConstraints jelek %s: \"%s\"!\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s Bahasa jelek \"%s\"!\n"
+
+#~ msgid " %s Bad spelling of %s - should be %s!\n"
+#~ msgstr " %s Ejaan dari %s jelek - seharusnya %s!\n"
+
+#~ msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID!\n"
+#~ msgstr ""
+#~ " %s Tidak dapat menyediakan APScanAppPath dan APScanAppBundleID!\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s cupsUIConstraints %s kosong!\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s Kehilangan \"%s\" string translasi untuk opsi %s!\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Kehilangan \"%s\" string translasi untuk opsi %s, pilihan %s!\n"
+
+#~ msgid ""
+#~ " %s Missing REQUIRED PageRegion option!\n"
+#~ " REF: Page 100, section 5.14.\n"
+#~ msgstr ""
+#~ " %s Kehilangan opsi PageRegion yang DIPERLUKAN!\n"
+#~ " REF: Halaman 100, seksi 5.14.\n"
+
+#~ msgid ""
+#~ " %s Missing REQUIRED PageSize option!\n"
+#~ " REF: Page 99, section 5.14.\n"
+#~ msgstr ""
+#~ " %s Kehilangan opsi PageSize yang DIPERLUKAN!\n"
+#~ " REF: Halaman 99, seksi 5.14.\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Kehilangan pilihan *%s %s dalam UIConstraints \"*%s %s *%s %s"
+#~ "\"!\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr ""
+#~ " %s Kehilangan pilihan *%s %s dalam cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s Kehilangan berkas cupsICCProfile \"%s\"!\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s Kehilangan cupsUIResolver %s!\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Kehilangan opsi %s dalam UIConstraints \"*%s %s *%s %s\"!\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Kehilangan opsi %s dalam cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr ""
+#~ " %s Tidak ada basis translasi \"%s\" yang disertakan pada berkas!\n"
+
+#~ msgid ""
+#~ " %s Non-standard size name \"%s\"!\n"
+#~ " REF: Page 187, section B.2.\n"
+#~ msgstr ""
+#~ " %s Nama ukuran nonstandar \"%s\"!\n"
+#~ " REF: Halaman 187, seksi B.2.\n"
+
+#~ msgid " %s Size \"%s\" defined for %s but not for %s!\n"
+#~ msgstr " %s Ukuran \"%s\" ditentukan untuk %s bukan untuk %s!\n"
+
+#~ msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)!\n"
+#~ msgstr ""
+#~ " %s Ukuran \"%s\" memiliki dimensi yang tak diharapkan (%gx%g)!\n"
+
+#~ msgid ""
+#~ " %s cupsUIResolver %s does not list at least two different "
+#~ "options!\n"
+#~ msgstr ""
+#~ " %s cupsUIResolver %s tidak menyediakan setidaknya dua opsi "
+#~ "berbeda!\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** %s nama yang dipilih %s dan %s berbeda hanya pada besar/"
+#~ "kecilnya huruf!\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **FAIL** %s seharusnya 1284DeviceID!\n"
+#~ " REF: Halaman 72, seksi 5.5\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** DefaultImageableArea %s JELEK!\n"
+#~ " REF: Halaman 102, seksi 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** DefaultPaperDimension %s JELEK!\n"
+#~ " REF: Halaman 103, seksi 5.15.\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr " **FAIL** LanguageEncoding %s jelek - seharusnya ISOLatin1!\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr " **FAIL** LanguageVersion %s jelek - seharusnya English!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **FAIL** String translasi utama untuk opsi %s pilihan %s "
+#~ "mengandung karakter 8-bit!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **FAIL** String translasi utama untuk opsi %s mengandung karakter "
+#~ "8-bit!\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Nama kelompok %s dan %s berbeda hanya besar/kecilnya "
+#~ "huruf!\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **FAIL** Terjadi ganda dari %s nama yang dipilih %s!\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Nama opsi %s dan %s berbeda hanya besar/kecilnya huruf!\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " %%%%BoundingBox jelek: pada baris %d!\n"
+#~ " REF: Halaman 39, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " Baris %d lebih dari 255 karakter (%d)!\n"
+#~ " REF: Halaman 25, Line Length (Panjang Baris)\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " Kehilangan %!PS-Adobe-3.0 pada baris pertama!\n"
+#~ " REF: Halaman 17, 3.1 Conforming Documents (Menyesuaikan Dokumen)\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " Kehilangan komentar %%EndComments!\n"
+#~ " REF: Halaman 41, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " Kehilangan atau %%BoundingBox jelek: komentar!\n"
+#~ " REF: Halaman 39, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " Kehilangan atau %%Page jelek: komentar!\n"
+#~ " REF: Halaman 53, %%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " Kehilangan atau %%Pages jelek: komentar!\n"
+#~ " REF: Halaman 43, %%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " Menemukan %d baris yang melebihi 255 karakter!\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " Terlalu banyak komentar %%BeginDocument!\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " Terlalu banyak komentar %%EndDocument!\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " Peringatan: berkas mengandung data biner!\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " Peringatan: tidak ada komentar %%EndComments dalam berkas!\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " Peringatan: DSC usang versi %.1f dalam berkas!\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s tidak didukung!"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: Tidak tahu apa yang hendak dikerjakan!\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: Kesalahan - Nama variabel lingkungan %s sebenarnya tidak ada \"%s\"!\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: Kesalahan - ID tugas jelek!\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr ""
+#~ "%s: Kesalahan - tidak bisa mencetak dan mengubah tugas secara bersamaan!\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: Kesalahan - tidak bisa mencetak dari stdin apabila berkas atau ID "
+#~ "tugas disediakan!\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan set karakter usai opsi '-S'!\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan jenis konten usai opsi '-T'!\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan banyaknya rangkap usai opsi '-n'!\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr ""
+#~ "%s: Kesalahan - diharapkan banyak hitungan rangkap usai opsi '-#'!\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan target usai opsi '-P'!\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan target usai opsi '-b'!\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan target usai opsi '-d'!\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan formulir usai opsi '-f'!\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan nama yang ditahan usai opsi '-H'!\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan nama host usai opsi '-H'!\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan nama host usai opsi '-h'!\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan daftar modus usai opsi '-y'!\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan nama usai opsi '-%c'!\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan opsi string usai opsi '-o'!\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan daftar halaman usai opsi '-P'!\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan prioritas usai opsi '-%c'!\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan teks alasan usai opsi '-r'!\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan judul usai opsi '-t'!\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan nama pengguna usai opsi '-U'!\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan nama pengguna usai opsi '-u'!\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: Kesalahan - diharapkan nilai usai opsi '-%c'!\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: Kesalahan - diperlukan \"completed\", \"not-completed\", atau \"all\" "
+#~ "usai opsi '-W'!\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: Kesalahan - penjadwal tidak merespon!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: Kesalahan - tujuan tak dikenal \"%s\"!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: Kesalahan - tujuan tak dikenal \"%s/%s\"!\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: Kesalahan - opsi tak dikenal '%c'!\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: Kesalahan - opsi '%s' tak dikenal!\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: Diharapkan ID tugas usai opsi '-i'!\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: Nama tujuan tidak sah pada daftar \"%s\"!\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr "%s: Memerlukan ID tugas ('-i jobid') sebelum '-H restart'!\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: Tidak ada penyaring untuk konversi dari %s/%s ke %s/%s!\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s: Maaf, tidak ada dukungan enkripsi yang dikompilasi serta!\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: Tidak bisa mengontak server!\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: Tidak bisa menentukan jenis MIME dari \"%s\"!\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s: Tak dapat membaca basis data MIME dari \"%s\" atau \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: Tujuan tak dikenal \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: Jenis MIME yang dituju tak dikenal %s/%s!\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: Opsi tak dikenal '%c'!\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: Sumber jenis MIME tak dikenal %s/%s!\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: Peringatan - format peubah '%c' tidak didukung - keluaran yang "
+#~ "dihasilkan mungkin tak tepat!\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: Peringatan - opsi set karakter diabaikan!\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: Peringatan - opsi jenis konten diabaikan!\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: Peringatan - opsi formulir diabaikan!\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: Peringatan - opsi modus diabaikan!\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: kesalahan - nama variabel lingkungan %s merupakan tujuan yang tidak "
+#~ "ada \"%s\"!\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: kesalahan - diharapkan opsi=nilai usai opsi '-o'!\n"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr "Diperlukan sandi Samba untuk mengekspor penggerak pencetak!"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr "Diperlukan nama pengguna Samba untuk mengekspor penggerak pencetak!"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "Kelas bernama \"%s\" sudah ada!"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "Pencetak bernama \"%s\" sudah ada!"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "Kelompok atribut di luar jangkauan (%x < %x)!"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "URI perangkat \"%s\" jelek!\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "device-uri \"%s\" jelek!"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "Skema device-uri \"%s\" jelek!"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "document-format \"%s\" jelek!"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Nama berkas penyangga jelek!"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Nilai job-priority jelek!"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Nilai job-sheets \"%s\" jelek!"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Jenis nilai job-sheets jelek!"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Nilai job-state jelek!"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Atribut job-uri \"%s\" jelek!"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "notify-pull-method \"%s\" jelek!"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "URI notify-recipient-uri \"%s\" jelek!"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "Opsi + yang dipilih pada baris %d jelek!"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "port-monitor \"%s\" jelek!"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Nilai printer-state %d jelek!"
+
+#~ msgid "Bad request ID %d!"
+#~ msgstr "ID permintaan %d jelek!"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "ID subskripsi jelek!"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "Set karakter \"%s\" tidak didukung!"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "Tidak akan memindai jenis \"%s\"!"
+
+#~ msgid "Cover open."
+#~ msgstr "Penutup terbuka."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "Developer hampir kosong."
+
+#~ msgid "Developer empty!"
+#~ msgstr "Developer kosong!"
+
+#~ msgid "Door open."
+#~ msgstr "Pintu terbuka."
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: Berkas perangkat SCSI \"%s\" jelek!\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: Nilai kolom %d jelek!\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: Nilai cpi %f jelek!\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: Nilai lpi %f jelek!\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: Pengaturan halaman jelek!\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: Pencetak yang dituju tidak ada!\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: Mencetak berkas kosong!\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: Kesalahan fatal USB!\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr ""
+#~ "ERROR: Ketidaksahan HP-GL/2 komentar terlihat, tak bisa mencetak berkas!\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr ""
+#~ "ERROR: Kehilangan nilai pada baris %d dari berkas pataka (banner)!\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: Memerlukan baris msgid sebelum string translasi pada baris %d dari "
+#~ "%s!\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Tak ditemukan URI perangkat pada argv[0] atau dalam variabel "
+#~ "lingkungan DEVICE_URI!\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: Tidak ketemu halaman!\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: Kehabisan kertas!\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: Variabel lingkungan PRINTER belum ditentukan!\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: Berkas cetak tidak diterima (%s)!\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: Pencetak tidak merespon!\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: Tidak bisa memperoleh atribut tugas %d (%s)!\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: Tidak bisa memperoleh status pencetak (%s)!\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: Tidak bisa menentukan lokasi pencetak '%s'!\n"
+
+#~ msgid "ERROR: Unable to open PPD file!\n"
+#~ msgstr "ERROR: Tidak bisa membuka berkas PPD!\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: Tidak bisa membuka berkas gambar untuk mencetak!\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: Tidak bisa membaca data yang hendak dicetak!\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: Tidak bisa mengirim data yang hendak dicetak (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: Tidak bisa mengirim data yang hendak dicetak!\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: Tidak bisa menulis %d bita ke pencetak!\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: Tidak bisa menulis di berkas temporer"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: Teks tak diharapkan pada baris %d dari %s!\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: Nilai opsi enkripsi \"%s\" tak dikenal!\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: Format katalog pesan \"%s\" tak dikenal!\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: Opsi \"%s\" dengan nilai \"%s\" tak dikenal!\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: Nilai opsi versi \"%s\" tak dikenal!\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr ""
+#~ "ERROR: Nilai kecerahan %s tak didukung, gunakanlah brightness=100!\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: Nilai gama %s tak didukung, gunakanlah gamma=1000!\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr "ERROR: Nilai number-up %d tak didukung, gunakanlah number-up=1!\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: Nilai number-up-layout %s tak didukung, gunakanlah number-up-"
+#~ "layout=lrtb!\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: Nilai page-border %s tak didukung, gunakanlah page-border=none!\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr "ERROR: Kelebihan doc_printf (%d bita) terdeteksi, dibatalkan!\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops tertutup pada sinyal %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops tertutup dengan status %d!\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: pemulihan: Tidak bisa menghubungi pencetak; akan mencoba ulang "
+#~ "dalam 30 detik...\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "Berkas PPD kosong!"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "Kesalahan: perlu nama host usai opsi '-h'!\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Suhu fusi tinggi!"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "Suhu fusi rendah!"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "Memperoleh atribut printer-uri tetapi bukan job-id!"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Tinta/toner hampir kosong."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Tinta/toner kosong!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Baki buangan tinta/toner hampir penuh."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Baki buangan tinta/toner sudah penuh!"
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "Tugas #%d tidak bisa dicetak ulang - tidak ada berkas!"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "Tugas #%d tidak ada!"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "Tugas #%d sudah diselesaikan dan tidak dapat diubah!"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "Tugas #%d tidak selesai!"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "Tugas #%d tidak ditahan untuk otentikasi!"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "Tugas #%d tidak ditahan!"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "Tugas #%s tidak ada!"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "Tugas %d tidak ketemu!"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "Subkripsi tugas tidak bisa diperbaharui!"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "Bahasa \"%s\" tidak didukung!"
+
+#~ msgid "Media jam!"
+#~ msgstr "Media tersangkut!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Baki media hampir kosong."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Baki media kosong!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Baki media hilang!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "Baki media perlu diisi."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "Kehilangan atribut document-number!"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "Kehilangan tanda kutip pada baris %d!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "Kehilangan variabel formulir!"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "Kehilangan atribut notify-subscription-ids!"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "Kehilangan atribut requesting-user-name!"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "Kehilangan atribut yang diperlukan!"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "Kehilangan nilai pada baris %d!"
+
+#~ msgid "Nested classes are not allowed!"
+#~ msgstr "Kelas bersarang tidak diperbolehkan!"
+
+#~ msgid "No PPD name!"
+#~ msgstr "Tidak ada nama PPD!"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Tidak ada penggerak pencetak Windows yang terpasang!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "Tidak ada tugas yang aktif pada %s!"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "Tidak ada atribut dalam permintaan!"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "Tidak ada informasi otentikasi yang tersedia!"
+
+#~ msgid "No file!?!"
+#~ msgstr "Tidak ada berkas!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "Tidak ada waktu modifikasi!"
+
+#~ msgid "No printer name!"
+#~ msgstr "Tidak ada nama pencetak!"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "Tidak ditemukan printer-uri untuk kelas!"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "Tidak ditemukan printer-uri!"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "Tidak ada printer-uri dalam permintaan!"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "Tidak ada atribut subskripsi dalam permintaan!"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC nyaris di ujung hayat."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC sudah di ujung hayat!"
+
+#~ msgid "Out of toner!"
+#~ msgstr "Kehabisan toner!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Baki keluaran hampir penuh."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Baki keluaran penuh!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Baki keluaran hilang!"
+
+#~ msgid "Printer offline."
+#~ msgstr "Pencetak tak terhubung."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "Pencetak SCSI"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "Nilai notify-user-data terlalu besar (%d > 63 oktet)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "Pencetak atau kelas tidak dikongsikan!"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "Atribut printer-uri diperlukan!"
+
+#~ msgid "Toner low."
+#~ msgstr "Toner lemah."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "Terlalu banyak nilai job-sheets (%d > 2)!"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "Terlalu banyak nilai printer-state-reasons (%d > %d)!"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "Tidak bisa menambah tugas untuk tujuan \"%s\"!"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "Tidak bisa mengalokasikan memori untuk jenis berkas!"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr "Tidak bisa menyalin berkas penggerak pencetak CUPS 64-bit (%d)!"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr "Tidak bisa menyalin berkas penggerak pencetak Windows 64-bit (%d)!"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr "Tidak bisa menyalin berkas penggerak pencetak CUPS (%d)!"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "Tidak bisa menyalin berkas PPD - %s!"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "Tidak bisa menyalin berkas PPD!"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr "Tidak bisa menyalin berkas penggerak pencetak Windows 2000 (%d)!"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr "Tidak bisa menyalin berkas penggerak pencetak Windows 9x (%d)!"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "Tidak bisa menyalin skrip antarmuka - %s!"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "Tidak bisa membuat printer-uri!"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr "Tidak bisa menyunting berkas cupsd.conf lebih dari 1MB!"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "Tidak bisa menemukan tujuan untuk tugas!"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "Tidak bisa menemukan pencetak!\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr "Tidak bisa memasang berkas penggerak pencetak Windows 2000 (%d)!"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr "Tidak bisa memasang berkas penggerak pencetak Windows 9x (%d)!"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "Tidak bisa membuka dokumen %d pada tugas %d!"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Tidak bisa mengeset penggerak pencetak Windows (%d)!"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Set karakter \"%s\" tak didukung!"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "Kompresi \"%s\" tak didukung!"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "Atribut kompresi %s tak didukung!"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "Format \"%s\" tak didukung!"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "Format '%s' tak didukung!"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "Format '%s/%s' tak didukung!"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+#~ "translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Penggunaan: cupstestppd [opsi] berkas1.ppd[.gz] [... berkasN.ppd[.gz]]\n"
+#~ " program | cupstestppd [opsi] -\n"
+#~ "\n"
+#~ "Opsi:\n"
+#~ "\n"
+#~ " -R direktori-root Mengeset root alternatif\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+#~ "translations}\n"
+#~ " Menampilkan peringatan ketimbang kesalahan\n"
+#~ " -q Berjalan senyap\n"
+#~ " -r Menggunakan modus 'relaxed' terbuka\n"
+#~ " -v Menjadi riuh\n"
+#~ " -vv Menjadi sangat riuh\n"
+
+#~ msgid ""
+#~ "Usage: ppdhtml [options] filename.drv >filename.html\n"
+#~ " -D name=value Set named variable to value.\n"
+#~ "Options:\n"
+#~ " -I include-dir Add include directory to search path.\n"
+#~ msgstr ""
+#~ "Penggunaan: ppdhtml [opsi] berkas.drv >berkas.html\n"
+#~ " -D nama=nilai Atur nilai variabel bernama.\n"
+#~ "Opsi:\n"
+#~ " -I dir-inklusi Tambah direktori dalam jalur pencarian.\n"
+
+#~ msgid ""
+#~ "Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+#~ "Options:\n"
+#~ " -D name=value Set named variable to value.\n"
+#~ " -I include-dir Add include directory to search path.\n"
+#~ " -v Be verbose (more v's for more verbosity).\n"
+#~ msgstr ""
+#~ "Penggunaan: ppdpo [opsi] -o berkas.po berkas.drv [ ... berkasN.drv ]\n"
+#~ "Opsi:\n"
+#~ " -D nama=nilai Mengeset nilai variabel bernama.\n"
+#~ " -I dir-inklusi Tambah direktori dalam jalur pencarian.\n"
+#~ " -v Menjadi riuh (tambahkan v lagi untuk lebih riuh).\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: Gagal membaca permintaan kanal sisi!\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr "WARNING: Opsi \"%s\" tidak akan disertakan via IncludeFeature!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Host jarak jauh tidak merespon pada bita status perintah usai %d "
+#~ "detik!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Host jarak jauh tidak merespon pada bita kontrol status usai %d "
+#~ "detik!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Host jarak jauh tidak merespon pada bita status data usai %d "
+#~ "detik!\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr "WARNING: Perintah SCSI kehabisan waktu (%d); mencoba ulang...\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: Dokumen ini tidak sesuai dengan Adobe Document Structuring "
+#~ "Conventions dan mungkin tidak tercetak dengan benar!\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: Pilihan \"%s\" tak dikenal untuk opsi \"%s\"!\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: Opsi \"%s\" tak dikenal!\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr "Peringatan, tak ada penggerak pencetak Windows 2000 yang terpasang!"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: Opsi tak dikenal \"%s\"!\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: Opsi tak dikenal \"-%c\"!\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr "cupsd: Diharapkan nama berkas konfigurasi usai opsi \"-c\"!\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: Tidak bisa memperoleh direktori sekarang!\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: Argumen \"%s\" tak dikenal - digagalkan!\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: Opsi \"%c\" tak dikenal - digagalkan!\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: Jumlah dokumen %d tidak sah!\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: ID tugas %d tak sah!\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: Hanya satu nama berkas yang bisa ditentukan!\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "Atribut job-printer-uri hilang!"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Nama kelas hanya boleh diisi karakter cetak!\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: Diharapkan PPD usai opsi '-P'!\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr "lpadmin: Diharapkan allow/deny:daftarpengguna usai opsi '-u'!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: Diharapkan kelas usai opsi '-r'!\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: Diharapkan nama kelas usai opsi '-c'!\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: Diharapkan deskripsi usai opsi '-D'!\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: Diharapkan URI perangkat usai opsi '-v'!\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: Diharapkan jenis berkas usai opsi '-I'!\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: Diharapkan nama host usai opsi '-h'!\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: Diharapkan antarmuka usai opsi '-i'!\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: Diharapkan lokasi usai opsi '-L'!\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: Diharapkan model usai opsi '-m'!\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: Diharapkan nama=nilai usai opsi '-o'!\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: Diharapkan pencetak usai opsi '-p'!\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: Diharapkan nama pencetak usai opsi '-d'!\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin: Diharapkan pencetak atau kelas usai opsi '-x'!\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: Tidak ada nama anggota yang terlihat!\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Nama pencetak hanya bisa mengandung karakter cetak!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Tidak bisa menambah pencetak ke kelas:\n"
+#~ " Anda harus menentukan nama pencetak lebih dulu!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Tidak bisa membuang pencetak dari kelas:\n"
+#~ " Anda harus menentukan nama pencetak lebih dulu!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Tidak bisa mengeset berkas PPD:\n"
+#~ " Anda harus menentukan nama pencetak lebih dulu!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Tidak bisa mengeset URI perangkat:\n"
+#~ " Anda harus menentukan nama pencetak lebih dulu!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Tidak bisa mengeset skrip antarmuka atau berkas PPD:\n"
+#~ " Anda harus menentukan nama pencetak lebih dulu!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Tidak bisa mengeset skrip antarmuka:\n"
+#~ " Anda harus menentukan nama pencetak lebih dulu!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Tidak bisa mengeset deskripsi pencetak:\n"
+#~ " Anda harus menentukan nama pencetak lebih dulu!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Tidak bisa mengeset lokasi pencetak:\n"
+#~ " Anda harus menentukan nama pencetak lebih dulu!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Tidak bisa mengeset opsi pencetak:\n"
+#~ " Anda harus menentukan nama pencetak lebih dulu!\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: Opsi boleh/larang tak dikenal \"%s\"!\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: Argumen tak dikenal '%s'!\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: Opsi tak dikenal '%c'!\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin: Peringatan - jenis isi diabaikan!\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: Diharapkan bahasa usai --language!\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo: Diharapkan pembuat dan model usai --make-and-model!\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo: Diharapkan string produk usai --product!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo: Diharapkan daftar skema usai --exclude-scemes!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo: Diharapkan daftar skema usai --include-schemes!\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: Diharapkan waktu habis usai --timeout!\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: Argumen tak dikenal '%s'!\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: Opsi tak dikenal '%c'!\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: Opsi tak dikenal '%s'!\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: Argumen tak dikenal '%s'!\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: Opsi tak dikenal '%c'!\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: Tidak ada pencetak!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: Tidak bisa membuka berkas PPD untuk %s!\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: Pencetak atau kelas tak dikenal!\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: Hanya root yang bisa menambah atau menghapus sandi!\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: Berkas sandi sedang sibuk!\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: Berkas sandi tidak diperbaharui!\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: Maaf, sandi tidak cocok!\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: Maaf, sandi tidak cocok!\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: kesalahan - nama variabel lingkungan %s bukanlah tujuan yang ada "
+#~ "\"%s\"!\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-events tidak dispesifikasikan!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "URI notify-recipient-uri \"%s\" sudah dipakai!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "URI notify-recipient-uri \"%s\" memakai skema tak dikenal!"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d tidak baik!"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Nama resolusi jelek \"%s\" pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: Kata kunci status jelek %s pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc: Ditemukan pilihan pada baris %d dari %s tanpa Option!\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc: Duplikat #po untuk lokal %s pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan definisi penyaring pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan nama program pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Diharapkan urutan warna untuk ColorModel pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Diharapkan ruang warna untuk ColorModel pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan kompresi untuk ColorModel pada baris %d dari %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Diharapkan string konstrain untuk UIConstraints pada baris %d dari %"
+#~ "s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Diharapkan kata kunci jenis penggerak diikuti DriverType pada baris "
+#~ "%d dari %s!\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan jenis dupleks usai Duplex pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan enkode usai Font pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan nama berkas usai #po %s pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan nama/teks kelompok pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Diharapkan nama berkas yang disertakan pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan integer pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan lokal usai #po pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan nama usai %s pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan nama usai FileName pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan nama usai Font pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan nama usai Manufacturer pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan nama usai MediaSize pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan nama usai ModelName pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan nama usai PCFileName pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan nama/teks usai %s pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Diharapkan nama/teks usai Installable pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan nama/teks usai Resolution pada baris %d dari %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Diharapkan nama/teks kombinasi untuk ColorModel pada baris %d dari %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan opsi nama/teks pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan opsi seksi pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan opsi jenis pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan bilangan real pada baris %d dari %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Diharapkan resolusi/jenis media diikuti ColorProfile pada baris %d "
+#~ "dari %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Diharapkan resolusi/jenis media diikuti SimpleColorProfile pada "
+#~ "baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapan selektor usai %s pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan status usai Font pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan string usai Copyright pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan string usai Version pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan dua opsi nama pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan nilai usai %s pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Diharapkan versi usai Font pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: Nama berkas #include/#po \"%s\" tak sah!\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Nilai tak sah bagi penyaring pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Jenis MIME kosong tak sah untuk penyaring pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Nama program korong tak sah untuk penyaring pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Seksi opsi \"%s\" tak sah pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Jenis opsi \"%s\" tak sah pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: Kehilangan #endif di akhir \"%s\"!\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: Kehilangan #if pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc: Tak tersedia katalog pesan untuk lokal %s!\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: Terlalu banyak #if bersarang pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: Tidak bisa menemukan berkas #po %s pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Tidak bisa menemukan berkas yang disertakan \"%s\" pada baris %d "
+#~ "dari %s!\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: Jenis penggerak tak dikenal %s pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Jenis dupleks tak dikenal \"%s\" pada baris %d dari %s!\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ukuran media tak dikenal \"%s\" pada baris %d dari %s!\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: LanguageVersion \"%s\" jelek pada %s!\n"
diff --git a/locale/cups_it.po b/locale/cups_it.po
new file mode 100644
index 000000000..a20aab132
--- /dev/null
+++ b/locale/cups_it.po
@@ -0,0 +1,7273 @@
+# Vincenzo Reale <smart2128@baslug.org>, 2009.
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2010-01-10 01:03+0100\n"
+"Last-Translator: Vincenzo Reale <smart2128@baslug.org>\n"
+"Language-Team: Italian <kde-i18n-it@kde.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Lokalize 1.0\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(tutti)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(nessuno)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d voci\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tDopo il fallimento: continua\n"
+
+msgid "\tAlerts:"
+msgstr "\tAvvisi:"
+
+msgid "\tBanner required\n"
+msgstr "\tBanner richiesto\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tSet di caratteri:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tConnessione: diretta\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tConnessione: remota\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tDimensioni predefinite pagina:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tTono predefinito:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tImpostazioni predefinite porta:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tDescrizione: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tModulo montato:\n"
+"\tTipi di contenuto: qualsiasi\n"
+"\tTipi di stampante: sconosciuti\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tModuli consentiti:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tInterfaccia: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tInterfaccia: %s/interfacce/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tInterfaccia: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tPosizione: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tIn caso di fallimento: nessun avviso\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tUtenti autorizzati:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tUtenti non autorizzati:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tpresente demone\n"
+
+msgid "\tno entries\n"
+msgstr "\tnessuna voce\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\tla stampante è sul dispositivo '%s' velocità -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\tla stampa è disabilitata\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\tla stampa è abilitata\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\tin coda per %s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tla coda è disabilitata\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tla coda è abilitata\n"
+
+msgid "\treason unknown\n"
+msgstr "\tmotivo sconosciuto\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" RISULTATI DETTAGLIATI DEL TEST DI CONFORMITÀ\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " RIF: pagina 15, sezione 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " RIF: pagina 15, sezione 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " RIF: pagina 19, sezione 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " RIF: pagina 20, sezione 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " RIF: pagina 27, sezione 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " RIF: pagina 42, sezione 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " RIF: pagine 16-17, sezione 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " RIF: pagine 42-45, sezione 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " RIF: pagine 45-46, sezione 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " RIF: pagine 48-49, sezione 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " RIF: pagine 52-54, sezione 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f byte\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " PASS Default%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " PASS DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " PASS DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " PASS FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " PASS FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " PASS LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " PASS LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " PASS Produttore\n"
+
+msgid " PASS ModelName\n"
+msgstr " PASS ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " PASS NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " PASS PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " PASS PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " PASS PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " PASS PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " PASS Prodotto\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " PASS ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" WARN \"%s %s\" è in conflitto con \"%s %s\"\n"
+" (limitazione=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" WARN %s condivide un prefisso comune con %s\n"
+" RIF: pagina 15, sezione 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" WARN LanguageEncoding richiesto dalla specifica PPD 4.3.\n"
+" RIF: pagine 56-57, sezione 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" WARN Produttore richiesto dalla specifica PPD 4.3.\n"
+" RIF: pagine 58-59, sezione 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" WARN PCFileName maggiore di 8.3 in violazione della specifica "
+"PPD.\n"
+" RIF: pagine 61-62, sezione 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protocols contiene PJL, ma gli attributi JCL non sono "
+"impostati.\n"
+" RIF: pagine 78-79, sezione 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protocols contiene sia PJL che BCP; atteso TBCP.\n"
+" RIF: pagine 78-79, sezione 5.7.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" WARN ShortNickName richiesto dalla specifica PPD 4.3.\n"
+" RIF: pagine 64-65, sezione 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr " %s File APDialogExtension \"%s\" mancante\n"
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr " %s File APPrinterIconPath \"%s\" mancante\n"
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr " %s File APPrinterLowInkTool \"%s\" mancante\n"
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr " %s File APPrinterUtilityPath \"%s\" mancante\n"
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr " %s File APScanAppPath \"%s\" mancante\n"
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s Documento cupsFilter \"%s\" mancante!\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s Documento cupsPreFilter \"%s\" mancante\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** Default%s %s ERRATO\n"
+" RIF: pagina 40, sezione 4.5.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **FAIL** Attributo JobPatchFile ERRATO nel documento\n"
+" RIF: pagina 24, sezione 3.4.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** Produttore ERRATO (dovrebbe essere \"HP\")\n"
+" RIF: pagina 211, tabella D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** Produttore ERRATO (dovrebbe essere \"Oki\")\n"
+" RIF: pagina 211, tabella D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** ModelName ERRATO: \"%c\" non consentito nella stringa.\n"
+" RIF: pagine 59-60, sezione 5.3.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** PSVersion ERRATO: non è \"(string) int\".\n"
+" RIF: pagine 62-64, sezione 5.3.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** Product ERRATO: non è \"(string)\".\n"
+" RIF: pagine 62, sezione 5.3.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** ShortNickName ERRATO: maggiore di 31 caratteri.\n"
+" RIF: pagine 64-65, sezione 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** FileVersion \"%s\" Errata \n"
+" RIF: pagina 56, sezione 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** FormatVersion \"%s\" Errata \n"
+" RIF: pagina 56, sezione 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr ""
+" **FAIL** Impossibile interpretare il codice opzione di default: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** RICHIESTO Default%s\n"
+" RIF: pagina 40, sezione 4.5.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** RICHIESTO DefaultImageableArea\n"
+" RIF: pagina 102, sezione 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** RICHIESTO DefaultPaperDimension\n"
+" RIF: pagina 103, sezione 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** RICHIESTO FileVersion\n"
+" RIF: pagina 56, sezione 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** RICHIESTO FormatVersion\n"
+" RIF: pagina 56, sezione 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** RICHIESTO ImageableArea per PageSize %s\n"
+" RIF: pagina 41, sezione 5.\n"
+" RIF: pagina 102, sezione 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **FAIL** RICHIESTO LanguageEncoding\n"
+" RIF: pagine 56-57, sezione 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **FAIL** RICHIESTO LanguageVersion\n"
+" RIF: pagine 57-58, sezione 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **FAIL** RICHIESTO Produttore\n"
+" RIF: pagine 58-59, sezione 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** RICHIESTO ModelName\n"
+" RIF: pagine 59-60, sezione 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **FAIL** RICHIESTO NickName\n"
+" RIF: pagina 60, sezione 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **FAIL** RICHIESTO PCFileName\n"
+" RIF: pagine 61-62, sezione 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** RICHIESTO PSVersion\n"
+" RIF: pagine 62-64, sezione 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **FAIL** RICHIESTO PageRegion\n"
+" RIF: pagina 100, sezione 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **FAIL** RICHIESTO PageSize\n"
+" RIF: pagina 41, sezione 5.\n"
+" RIF: pagina 99, sezione 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **FAIL** RICHIESTO PageSize\n"
+" RIF: pagine 99-100, sezione 5.14.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** RICHIESTO PaperDimension per PageSize %s\n"
+" RIF: pagina 41, sezione 5.\n"
+" RIF: pagina 103, sezione 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** RICHIESTO prodotto\n"
+" RIF: pagina 62, sezione 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** RICHIESTO ShortNickName\n"
+" RIF: pagina 64-65, sezione 5.3.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " %d ERRORI RILEVATI\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " NESSUN ERRORE RILEVATO\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " FAIL\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** Impossibile aprire il documento PPD: %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** Impossibile aprire il file PPD: %s alla riga %d.\n"
+
+msgid " PASS\n"
+msgstr " PASS\n"
+
+msgid "#10 Envelope"
+msgstr "Busta num. 10"
+
+msgid "#11 Envelope"
+msgstr "Busta num. 11"
+
+msgid "#12 Envelope"
+msgstr "Busta num. 12"
+
+msgid "#14 Envelope"
+msgstr "Busta num. 14"
+
+msgid "#9 Envelope"
+msgstr "Busta num. 9"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f byte\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f byte\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f millimetri"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f a %.0f x %.0f millimetri"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f pollici"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f a %.2f x %.2f pollici"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s accetta richieste da %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%s non può essere modificato."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s non è implementato dalla versione CUPS di lpc.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s non è pronta\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s è pronta\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s è pronta e stampa\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s non accetta richieste da %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s accetta richieste da %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s non accetta richieste da %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [operazione localhost %d]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s fallito: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: Errore: nessuna destinazione predefinita disponibile.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: Errore: la priorità deve essere tra 1 e 100.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: Errore: troppi documenti - \"%s\"\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: Errore: impossibile accedere a \"%s\" - %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s: Errore: impossibile effettuare la coda da stdin - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: Filtro \"%s\" non disponibile: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: Stringa filtro \"%s\" non valida\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: Operazione fallita; %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: Impossibile connettersi al server\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: impossibile aprire %s: - %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: Impossibile aprire il documento PPD: %s alla riga %d\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr "%s: Impossibile aprire il file PPD: %s alla riga %d.\n"
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: Errore: nessuna destinazione predefinita disponibile.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 poll./sec."
+
+msgid "1.25x0.25\""
+msgstr "1,25 x 0,25\""
+
+msgid "1.25x2.25\""
+msgstr "1,25 x 2,25\""
+
+msgid "1.5 inch/sec."
+msgstr "1,5 poll./sec."
+
+msgid "1.50x0.25\""
+msgstr "1,50 x 0,25\""
+
+msgid "1.50x0.50\""
+msgstr "1,50 x 0,50\""
+
+msgid "1.50x1.00\""
+msgstr "1,50 x 1,00\""
+
+msgid "1.50x2.00\""
+msgstr "1,50 x 2,00\""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 poll./sec."
+
+msgid "10 x 11\""
+msgstr "10 x 11\""
+
+msgid "10 x 13\""
+msgstr "10 x 13\""
+
+msgid "10 x 14\""
+msgstr "10 x 14\""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 mm/sec."
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 poll./sec."
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 poll./sec."
+
+msgid "12 x 11\""
+msgstr "12 x 11\""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 mm/sec."
+
+msgid "120x60dpi"
+msgstr "120 x 60 dpi"
+
+msgid "120x72dpi"
+msgstr "120 x 72 dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136 dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 mm/sec."
+
+msgid "15 x 11\""
+msgstr "15 x 11\""
+
+msgid "150 mm/sec."
+msgstr "150 mm/sec."
+
+msgid "150dpi"
+msgstr "150 dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180 dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 poll./sec."
+
+msgid "2-Sided Printing"
+msgstr "Stampa su due lati"
+
+msgid "2.00x0.37\""
+msgstr "2,00 x 0,37\""
+
+msgid "2.00x0.50\""
+msgstr "2,00 x 0,50\""
+
+msgid "2.00x1.00\""
+msgstr "2,00 x 1,00\""
+
+msgid "2.00x1.25\""
+msgstr "2,00 x 1,25\""
+
+msgid "2.00x2.00\""
+msgstr "2,00 x 2,00\""
+
+msgid "2.00x3.00\""
+msgstr "2,00 x 3,00\""
+
+msgid "2.00x4.00\""
+msgstr "2,00 x 4,00\""
+
+msgid "2.00x5.50\""
+msgstr "2,00 x 5,50\""
+
+msgid "2.25x0.50\""
+msgstr "2,25 x 0,50\""
+
+msgid "2.25x1.25\""
+msgstr "2,25 x 1,25\""
+
+msgid "2.25x4.00\""
+msgstr "2,25 x 4,00\""
+
+msgid "2.25x5.50\""
+msgstr "2,25 x 5,50\""
+
+msgid "2.38x5.50\""
+msgstr "2,38 x 5,50\""
+
+msgid "2.5 inches/sec."
+msgstr "2,5 poll./sec."
+
+msgid "2.50x1.00\""
+msgstr "2,50 x 1,00\""
+
+msgid "2.50x2.00\""
+msgstr "2,50 x 2,00\""
+
+msgid "2.75x1.25\""
+msgstr "2,75 x 1,25\""
+
+msgid "2.9 x 1\""
+msgstr "2.9 x 1\""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 mm/sec."
+
+msgid "200 mm/sec."
+msgstr "200 mm/sec."
+
+msgid "203dpi"
+msgstr "203 dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "Serie a 24 pin"
+
+msgid "240x72dpi"
+msgstr "240 x 72 dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 mm/sec."
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 poll./sec."
+
+msgid "3.00x1.00\""
+msgstr "3,00 x 1,00\""
+
+msgid "3.00x1.25\""
+msgstr "3,00 x 1,25\""
+
+msgid "3.00x2.00\""
+msgstr "3,00 x 2,00\""
+
+msgid "3.00x3.00\""
+msgstr "3,00 x 3,00\""
+
+msgid "3.00x5.00\""
+msgstr "3,00 x 5,00\""
+
+msgid "3.25x2.00\""
+msgstr "3,25 x 2,00\""
+
+msgid "3.25x5.00\""
+msgstr "3,25 x 5,00\""
+
+msgid "3.25x5.50\""
+msgstr "3,25 x 5,50\""
+
+msgid "3.25x5.83\""
+msgstr "3,25 x 5,83\""
+
+msgid "3.25x7.83\""
+msgstr "3,25 x 7,83\""
+
+msgid "3.5\" Disk"
+msgstr "Disco da 3,5\""
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "Disco da 3,5\": 2 1/8 x 2 3/4\""
+
+msgid "3.50x1.00\""
+msgstr "3,50 x 1,00\""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 mm/sec."
+
+msgid "300 mm/sec."
+msgstr "300 mm/sec."
+
+msgid "300dpi"
+msgstr "300 dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360 dpi"
+
+msgid "360x180dpi"
+msgstr "360 x 180 dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 poll./sec."
+
+msgid "4.00x1.00\""
+msgstr "4,00 x 1,00\""
+
+msgid "4.00x13.00\""
+msgstr "4,00 x 13,00\""
+
+msgid "4.00x2.00\""
+msgstr "4,00 x 2,00\""
+
+msgid "4.00x2.50\""
+msgstr "4,00 x 2,50\""
+
+msgid "4.00x3.00\""
+msgstr "4,00 x 3,00\""
+
+msgid "4.00x4.00\""
+msgstr "4,00 x 4,00\""
+
+msgid "4.00x5.00\""
+msgstr "4,00 x 5,00\""
+
+msgid "4.00x6.00\""
+msgstr "4,00 x 6,00\""
+
+msgid "4.00x6.50\""
+msgstr "4,00 x 6,50\""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 mm/sec."
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 poll./sec."
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 poll./sec."
+
+msgid "6.00x1.00\""
+msgstr "6,00 x 1,00\""
+
+msgid "6.00x2.00\""
+msgstr "6,00 x 2,00\""
+
+msgid "6.00x3.00\""
+msgstr "6,00 x 3,00\""
+
+msgid "6.00x4.00\""
+msgstr "6,00 x 4,00\""
+
+msgid "6.00x5.00\""
+msgstr "6,00 x 5,00\""
+
+msgid "6.00x6.00\""
+msgstr "6,00 x 6,00\""
+
+msgid "6.00x6.50\""
+msgstr "6,00 x 6,50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/sec."
+
+msgid "600dpi"
+msgstr "600 dpi"
+
+msgid "60dpi"
+msgstr "60 dpi"
+
+msgid "60x720dpi"
+msgstr "60 x 720 dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 poll./sec."
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720 dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 poll./sec."
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8,00 x 1,00\""
+
+msgid "8.00x2.00\""
+msgstr "8,00 x 2,00\""
+
+msgid "8.00x3.00\""
+msgstr "8,00 x 3,00\""
+
+msgid "8.00x4.00\""
+msgstr "8,00 x 4,00\""
+
+msgid "8.00x5.00\""
+msgstr "8,00 x 5,00\""
+
+msgid "8.00x6.00\""
+msgstr "8,00 x 6,00\""
+
+msgid "8.00x6.50\""
+msgstr "8,00 x 6,50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/sec."
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 poll./sec."
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "Serie a 9 pin"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?Sconosciuto comando aiuto non valido\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (senza margini)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (senza margini)"
+
+msgid "A4 (Small)"
+msgstr "A4 (con margini)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (senza margini)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "Accetta stampe"
+
+msgid "Accepted"
+msgstr "Accettate"
+
+msgid "Add Class"
+msgstr "Aggiungi classe"
+
+msgid "Add Printer"
+msgstr "Aggiungi stampante"
+
+msgid "Add RSS Subscription"
+msgstr "Aggiungi sottoscrizione RSS"
+
+msgid "Address"
+msgstr "Indirizzo"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "Indirizzo: 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "Amministrazione"
+
+msgid "Always"
+msgstr "Sempre"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "Applicatore"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "Puntatore dest. NULL errato"
+
+msgid "Bad OpenGroup"
+msgstr "OpenGroup errato"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "OpenUI/JCLOpenUI errato"
+
+msgid "Bad OrderDependency"
+msgstr "OrderDependency errato"
+
+msgid "Bad Request"
+msgstr "Richiesta errata"
+
+msgid "Bad SNMP version number"
+msgstr "Numero versione SNMP errato"
+
+msgid "Bad UIConstraints"
+msgstr "UIConstraints errato"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Valore copie %d errato."
+
+msgid "Bad custom parameter"
+msgstr "Parametro personalizzato errato"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Attributo font errato: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Valore number-up %d errato."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Valori page-ranges %d-%d errati."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Banner"
+
+msgid "Billing Information: "
+msgstr "Informazioni pagamento: "
+
+msgid "Bond Paper"
+msgstr "Carta normale"
+
+msgid "C0 Envelope"
+msgstr "Busta C0"
+
+msgid "C1 Envelope"
+msgstr "Busta C1"
+
+msgid "C2 Envelope"
+msgstr "Busta C2"
+
+msgid "C3 Envelope"
+msgstr "Busta C3"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "Busta C4"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "Busta C5"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "Busta C6"
+
+msgid "C65 Envelope"
+msgstr "Busta C65"
+
+msgid "C7 Envelope"
+msgstr "Busta C7"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "Stampante etichetta CPCL"
+
+msgid "Cancel RSS Subscription"
+msgstr "Annulla sottoscrizione RSS"
+
+msgid "Change Settings"
+msgstr "Modifica impostazioni"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Busta Chou3"
+
+msgid "Chou4 Envelope"
+msgstr "Busta Chou4"
+
+msgid "Classes"
+msgstr "Classi"
+
+msgid "Clean Print Heads"
+msgstr "Pulisci testine stampante"
+
+msgid "Color"
+msgstr "Colore"
+
+msgid "Color Mode"
+msgstr "Modalità colore"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"I comandi possono essere abbreviati. I comandi sono:\n"
+"\n"
+"esci aiuto chiudi stato ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "I nomi comunitari utilizzano una lunghezza indefinita"
+
+msgid "Continue"
+msgstr "Continua"
+
+msgid "Continuous"
+msgstr "Continuo"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Creato"
+
+msgid "Created On: "
+msgstr "Creato il: "
+
+msgid "Custom"
+msgstr "Personalizzato"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Taglia"
+
+msgid "Cutter"
+msgstr "Cutter"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "Busta DL"
+
+msgid "Dark"
+msgstr "Scuro"
+
+msgid "Darkness"
+msgstr "Oscurità"
+
+msgid "Delete Class"
+msgstr "Elimina classe"
+
+msgid "Delete Printer"
+msgstr "Elimina stampante"
+
+msgid "Description: "
+msgstr "Descrizione: "
+
+msgid "DeskJet Series"
+msgstr "Serie DeskJet"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "La destinazione \"%s\" non accetta operazioni."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"Dispositivo: uri = %s\n"
+" classe = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" posizione = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "Media termico diretto"
+
+msgid "Disabled"
+msgstr "Disabilitato"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "Documento %d non trovato nell'operazione %d."
+
+msgid "Double Postcard"
+msgstr "Cartolina postale doppia"
+
+msgid "Driver Name: "
+msgstr "Nome driver: "
+
+msgid "Driver Version: "
+msgstr "Versione driver: "
+
+msgid "Duplexer"
+msgstr "Duplexer"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: impossibile allocare memoria per info pagina: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: impossibile allocare memoria per matrice pagine: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "Stampante etichette EPL1"
+
+msgid "EPL2 Label Printer"
+msgstr "Stampante etichette EPL2"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr "ERROR: %s job-id utente titolo copie opzioni [file]\n"
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: documento charset errato %s\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: tipo charset errato %s\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: riga descrizione font errata: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: direzione testo errata %s\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: ampiezza testo errata %s\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: errore %d durante l'invio della richiesta PAPSendData: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: nessun font nel set di caratteri %s\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: la stampante non risponde\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: la stampante ha inviato un EOF inatteso\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: l'host remoto non ha accettato il documento di controllo (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: l'host remoto non ha accettato il documento dati (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr ""
+"ERROR: si è verificato un errore di timeout durante l'invio di dati alla "
+"stampante\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: impossibile aggiungere il documento %d alla stampa: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: impossibile annullare la stampa %d: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: impossibile copiare il documento PDF"
+
+msgid "ERROR: Unable to create pipe"
+msgstr "ERROR: Impossibile creare il canale"
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: impossibile creare il socket"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: impossibile creare il documento di stampa compresso temporaneo: %s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: impossibile creare il documento temporaneo"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: impossibile eseguire pictwpstops: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: impossibile eseguire il programma gs"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: impossibile eseguire il programma pdftops"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr "ERROR: Impossibile eseguire il programma pstops"
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: impossibile biforcare pictwpstops: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: impossibile ottenere richiesta PAP"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: impossibile ottenere risposta PAP"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr ""
+"ERROR: impossibile aprire il documento PPD per la stampante \"%s\" - %s.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: impossibile ottenere zona di default AppleTalk"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: impossibile cercare risposta PAP"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: impossibile cercare stampanti AppleTalk"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: impossibile rendere indirizzo AppleTalk"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: impossibile aprire \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: impossibile aprire %s: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: impossibile aprire documento banner \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: impossibile aprire documento dispositivo \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: impossibile aprire documento \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: impossibile aprire documento \"%s\": %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: impossibile aprire documento di stampa \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: impossibile aprire il documento di stampa %s - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: impossibile aprire il documento di stampa %s: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr "ERROR: Impossibile aprire il file raster - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: impossibile aprire il documento di stampa compresso temporaneo: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: impossibile leggere i dati di stampa"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: impossibile prenotare una porta"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: impossibile trovare distanza %ld nel documento - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: impossibile trovare distanza %lld nel documento - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: impossibile inviare comando LPD"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: impossibile inviare richiesta PAP"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: impossibile inviare richiesta dati PAP iniziale"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: impossibile inviare il documento di stampa alla stampante"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: impossibile inviare trailing nul alla stampante"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: impossibile attendere per pictwpstops: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: impossibile scrivere %d byte su \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: impossibile scrivere documento controllo"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: impossibile scrivere dati di stampa"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: impossibile scrivere dati di stampa: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr "ERROR: impossibile scrivere dati documento non compressi: %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: ordine documento sconosciuto \"%s\"\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: carattere formato sconosciuto \"%c\"\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: modalità di stampa \"%s\" sconosciuta\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: selezione() fallita"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: impossibile avviare documento di stampa"
+
+msgid "Edit Configuration File"
+msgstr "Modifica documento di configurazione"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Banner finale"
+
+msgid "English"
+msgstr "Italian"
+
+msgid "Enter old password:"
+msgstr "Inserisci la vecchia password:"
+
+msgid "Enter password again:"
+msgstr "Inserisci di nuovo la password:"
+
+msgid "Enter password:"
+msgstr "Inserisci la password:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Per accedere a questa pagina, inserisci il tuo nome utente e la password o "
+"il nome utente e la password di root."
+
+msgid "Envelope Feed"
+msgstr "Feed busta"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Politica errori"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "Ogni 10 etichette"
+
+msgid "Every 2 Labels"
+msgstr "Ogni 2 etichette"
+
+msgid "Every 3 Labels"
+msgstr "Ogni 3 etichette"
+
+msgid "Every 4 Labels"
+msgstr "Ogni 4 etichette"
+
+msgid "Every 5 Labels"
+msgstr "Ogni 5 etichette"
+
+msgid "Every 6 Labels"
+msgstr "Ogni 6 etichette"
+
+msgid "Every 7 Labels"
+msgstr "Ogni 7 etichette"
+
+msgid "Every 8 Labels"
+msgstr "Ogni 8 etichette"
+
+msgid "Every 9 Labels"
+msgstr "Ogni 9 etichette"
+
+msgid "Every Label"
+msgstr "Ogni etichetta"
+
+msgid "Expectation Failed"
+msgstr "Attesa fallita"
+
+msgid "Export Printers to Samba"
+msgstr "Esporta stampanti a Samba"
+
+msgid "FAIL\n"
+msgstr "FAIL\n"
+
+msgid "File Folder"
+msgstr "Cartella documento"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Cartella documento: 9/16 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"Gli URI del dispositivo documento sono stati disabilitati! Per abilitarli, "
+"consulta l'istruzione del FileDevice in \"%s/cupsd.conf\"."
+
+msgid "Folio"
+msgstr "Foglio"
+
+msgid "Forbidden"
+msgstr "Vietato"
+
+msgid "General"
+msgstr "Generale"
+
+msgid "Generic"
+msgstr "Generico"
+
+msgid "German FanFold"
+msgstr "Modulo continuo tedesco"
+
+msgid "German FanFold Legal"
+msgstr "Modulo continuo legale tedesco"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU utilizza una lunghezza indefinita"
+
+msgid "Glossy Paper"
+msgstr "Carta patinata"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Scala di grigi"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Cartella interruzione"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Cartella interruzione - 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk disabilitata in Preferenze di Sistema.\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk disabilitata in Preferenze di Sistema.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: annullo lavoro di stampa...\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: connesso alla stampante...\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: connetto alla stampante...\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: documento di controllo inviato con successo\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr "INFO: Copia dei dati di stampa...\n"
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: documento dati inviato con successo\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr "INFO: Pagina %d completata...\n"
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: formatto pagina %d...\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: carico documento immagine...\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: cerco la stampante...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: apro la connessione\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr "INFO: documento stampa inviato, attendo che la stampante finisca...\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: stampante occupata; riprovo fra 10 secondi...\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: stampante occupata; riprovo fra 30 secondi...\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: stampante occupata; riprovo fra 5 secondi...\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr "INFO: la stampante non supporta IPP/%d.%d, provo IPP/1.0...\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: la stampante è occupata; riprovo fra 5 secondi...\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: la stampante al momento non è in linea.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: la stampante al momento non è in linea.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: la stampante è adesso in linea.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: la stampante non è in linea.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: stampante non connessa; riprovo fra 30 secondi...\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: stampo pagina %d, %d%% completato...\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: stampo pagina %d...\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: pronta per stampare.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: invio documento di controllo (%lu byte)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: invio documento di controllo (%u byte)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: invio dati\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: invio documento dati (%ld byte)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: invio documento dati (%lld byte)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: invio dati di stampa...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: inviato documento stampa, %ld byte...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: inviato documento stampa, %lld byte...\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: eseguo lo spool della stampa LPR, %.0f%% completato...\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr "INFO: Pagina iniziale %d...\n"
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: impossibile contattare la stampante, in coda sulla stampante "
+"successiva nella classe...\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: uso una zona di default AppleTalk\"%s\"\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: attendo che la stampa sia completata...\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: attendo che la stampante sia disponibile...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "Busta ISO B4"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (senza margini)"
+
+msgid "ISO B5 Envelope"
+msgstr "Busta ISO B5"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "Busta ISO B6"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "ISOLatin1"
+
+msgid "Illegal control character"
+msgstr "Carattere di controllo non consentito"
+
+msgid "Illegal main keyword string"
+msgstr "Stringa di parola chiave principale non consentita"
+
+msgid "Illegal option keyword string"
+msgstr "Stringa di parola chiave opzionale non consentita"
+
+msgid "Illegal translation string"
+msgstr "Stringa di traduzione non consentita"
+
+msgid "Illegal whitespace character"
+msgstr "Carattere spazio bianco non consentito"
+
+msgid "Installable Options"
+msgstr "Opzioni installabili"
+
+msgid "Installed"
+msgstr "Installate"
+
+msgid "IntelliBar Label Printer"
+msgstr "Stampante etichette IntelliBar"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr "Errore interno del server"
+
+msgid "Internal error"
+msgstr "Errore interno"
+
+msgid "Internet Postage 2-Part"
+msgstr "Francobollo Internet 2-Part"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Francobollo Internet 2-Part - 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "Francobollo Internet 3-Part"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Francobollo Internet 3-Part - 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "IPP (Internet Printing Protocol)"
+
+msgid "Invite Envelope"
+msgstr "Busta invito"
+
+msgid "Italian Envelope"
+msgstr "Busta standard italiana"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "La stampa #%d è già interrotta: impossibile annullare."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "La stampa #%d è già annullata: impossibile annullare."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "La stampa #%d è già completata: impossibile annullare."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "Stampa completata"
+
+msgid "Job Created"
+msgstr "Stampa creata"
+
+msgid "Job ID: "
+msgstr "ID stampa: "
+
+msgid "Job Options Changed"
+msgstr "Opzioni di stampa modificate"
+
+msgid "Job Stopped"
+msgstr "Stampa interrotta"
+
+msgid "Job UUID: "
+msgstr "UUID stampa: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "La stampa è completata e non può essere modificata."
+
+msgid "Job operation failed:"
+msgstr "Operazione stampa fallita:"
+
+msgid "Job state cannot be changed."
+msgstr "Lo stato della stampa non può essere modificato."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "Stampe"
+
+msgid "Kaku2 Envelope"
+msgstr "Busta Kaku2"
+
+msgid "Kaku3 Envelope"
+msgstr "Busta Kaku3"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "Host o stampante LPD/LPR"
+
+msgid "Label Printer"
+msgstr "Stampante etichette"
+
+msgid "Label Top"
+msgstr "Etichetta superiore"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Indirizzo esteso"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Indirizzo esteso: - 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet Serie PCL 4/5"
+
+msgid "Light"
+msgstr "Luce"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Lunghezza riga superiore al limite massimo concesso (255 caratteri)"
+
+msgid "List Available Printers"
+msgstr "Elenco stampanti disponibili"
+
+msgid "Location: "
+msgstr "Posizione: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "Taglio largo (ritratto)"
+
+msgid "Make and Model: "
+msgstr "Produzione e modello: "
+
+msgid "Manual Feed"
+msgstr "Alimentazione manuale"
+
+msgid "Media Dimensions: "
+msgstr "Dimensioni media: "
+
+msgid "Media Limits: "
+msgstr "Limiti media: "
+
+msgid "Media Name: "
+msgstr "Nome media: "
+
+msgid "Media Size"
+msgstr "Dimensione media"
+
+msgid "Media Source"
+msgstr "Sorgente media"
+
+msgid "Media Tracking"
+msgstr "Rilevamento media"
+
+msgid "Media Type"
+msgstr "Tipo media"
+
+msgid "Medium"
+msgstr "Media"
+
+msgid "Memory allocation error"
+msgstr "Errore di allocazione della memoria"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "Intestazione PPD-Adobe-4.x mancante"
+
+msgid "Missing asterisk in column 1"
+msgstr "Asterisco mancante nella colonna 1"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "Stringa di valore mancante"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Modello: nome = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "Modifica classe"
+
+msgid "Modify Printer"
+msgstr "Modifica stampante"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Busta Monarch"
+
+msgid "Move All Jobs"
+msgstr "Sposta tutte le stampe"
+
+msgid "Move Job"
+msgstr "Sposta stampa"
+
+msgid "Moved Permanently"
+msgstr "Spostamento permanente"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: documento di stampa accettato: ID stampa %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: documento di stampa accettato: ID stampa sconosciuto.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "Puntatore documento NULL PPD"
+
+msgid "Name OID uses indefinite length"
+msgstr "Il nome OID utilizza una lunghezza indefinita"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Mai"
+
+msgid "New Stylus Color Series"
+msgstr "Nuova serie Stylus Color"
+
+msgid "New Stylus Photo Series"
+msgstr "Nuova serie Stylus Photo"
+
+msgid "No"
+msgstr "No"
+
+msgid "No Content"
+msgstr "Nessun contenuto"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "Nessuna SEQUENZA VarBind"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "Nessuna connessione attiva"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "Nessun nome comunitario"
+
+msgid "No default printer"
+msgstr "Nessuna stampante predefinita"
+
+msgid "No destinations added."
+msgstr "Nessuna destinazione aggiunta."
+
+msgid "No error-index"
+msgstr "Nessun error-index"
+
+msgid "No error-status"
+msgstr "Nessun error-status"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "Nessun nome OID"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "Nessun request-id"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "Nessuna sottoscrizione trovata."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "Nessuna SEQUENZA variable-bindings"
+
+msgid "No version number"
+msgstr "Nessun numero versione"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "Non-continuous (rilevamento contrassegno)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "Non-continuous (rilevamento web)"
+
+msgid "Normal"
+msgstr "Normale"
+
+msgid "Not Found"
+msgstr "Non trovato"
+
+msgid "Not Implemented"
+msgstr "Non implementato"
+
+msgid "Not Installed"
+msgstr "Non installato"
+
+msgid "Not Modified"
+msgstr "Non modificato"
+
+msgid "Not Supported"
+msgstr "Non supportato"
+
+msgid "Not allowed to print."
+msgstr "Non autorizzata a stampare."
+
+msgid "Note"
+msgstr "Nota"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Off (1-Sided)"
+msgstr "Off (su un lato)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Aiuto Online"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "Apertura di %s fallita: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup senza un CloseGroup precedente"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI senza un CloseUI/JCLCloseUI precedente"
+
+msgid "Operation Policy"
+msgstr "Politica operativa"
+
+msgid "Options Installed"
+msgstr "Opzioni installate"
+
+msgid "Options: "
+msgstr "Opzioni: "
+
+msgid "Output Mode"
+msgstr "Modalità di uscita"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "L'uscita per la stampante %s è inviata a %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr ""
+"L'uscita per la stampante %s è inviata alla stampante remota %s su %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "L'uscita per la stampante %s/%s è inviata a %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr ""
+"L'uscita per la stampante %s/%s è inviata alla stampante remota %s su %s\n"
+
+msgid "PASS\n"
+msgstr "PASS\n"
+
+msgid "PCL Laser Printer"
+msgstr "Stampante laser PCL"
+
+msgid "PRC1 Envelope"
+msgstr "Busta PRC1"
+
+msgid "PRC10 Envelope"
+msgstr "Busta PRC10"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "Busta PRC2"
+
+msgid "PRC3 Envelope"
+msgstr "Busta PRC3"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (senza margini)"
+
+msgid "PRC4 Envelope"
+msgstr "Busta PRC4"
+
+msgid "PRC5 Envelope"
+msgstr "Busta PRC5"
+
+msgid "PRC6 Envelope"
+msgstr "Busta PRC6"
+
+msgid "PRC7 Envelope"
+msgstr "Busta PRC7"
+
+msgid "PRC8 Envelope"
+msgstr "Busta PRC8"
+
+msgid "PRC9 Envelope"
+msgstr "Busta PRC9"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "Il pacchetto non contiene un Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "Il pacchetto non inizia con una SEQUENZA"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "Password per %s su %s? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "Password per %s necessaria per accedere a %s via SAMBA: "
+
+msgid "Pause Class"
+msgstr "Metti in pausa classe"
+
+msgid "Pause Printer"
+msgstr "Metti in pausa stampante"
+
+msgid "Peel-Off"
+msgstr "Stacca"
+
+msgid "Personal Envelope"
+msgstr "Busta personale"
+
+msgid "Photo"
+msgstr "Foto"
+
+msgid "Photo Labels"
+msgstr "Etichette foto"
+
+msgid "Plain Paper"
+msgstr "Carta normale"
+
+msgid "Policies"
+msgstr "Politiche"
+
+msgid "Port Monitor"
+msgstr "Monitor porta"
+
+msgid "PostScript Printer"
+msgstr "Stampante PostScript"
+
+msgid "Postcard"
+msgstr "Cartolina postale"
+
+msgid "Print Density"
+msgstr "Densità di stampa"
+
+msgid "Print Job:"
+msgstr "Stampa:"
+
+msgid "Print Mode"
+msgstr "Modalità di stampa"
+
+msgid "Print Rate"
+msgstr "Velocità di stampa"
+
+msgid "Print Self-Test Page"
+msgstr "Pagina di autoverifica"
+
+msgid "Print Speed"
+msgstr "Velocità di stampa"
+
+msgid "Print Test Page"
+msgstr "Stampa pagina di prova"
+
+msgid "Print and Cut"
+msgstr "Stampa e taglia"
+
+msgid "Print and Tear"
+msgstr "Stampa e separa"
+
+msgid "Printed For: "
+msgstr "Stampato per: "
+
+msgid "Printed From: "
+msgstr "Stampato da: "
+
+msgid "Printed On: "
+msgstr "Stampato su: "
+
+msgid "Printer Added"
+msgstr "Aggiunta stampante"
+
+msgid "Printer Default"
+msgstr "Stampate di default"
+
+msgid "Printer Deleted"
+msgstr "Stampante eliminata"
+
+msgid "Printer Modified"
+msgstr "Manutenzione stampanti"
+
+msgid "Printer Name: "
+msgstr "Nome stampante: "
+
+msgid "Printer Paused"
+msgstr "Stampante in pausa"
+
+msgid "Printer Settings"
+msgstr "Impostazioni stampante"
+
+msgid "Printer:"
+msgstr "Stampante:"
+
+msgid "Printers"
+msgstr "Stampanti"
+
+msgid "Purge Jobs"
+msgstr "Libera stampe"
+
+msgid "Quarto"
+msgstr "Quarto"
+
+msgid "Quota limit reached."
+msgstr "Limite di quota raggiunto."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr "Posiz. Proprietario Stampa Doc. Dim. totali\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr "Posiz. Proprietario Stampa Doc. Dim. totali\n"
+
+msgid "Reject Jobs"
+msgstr "Scarta stampe"
+
+msgid "Reprint After Error"
+msgstr "Ristampa dopo errore"
+
+msgid "Request Entity Too Large"
+msgstr "Richiesta di dimensioni eccessive"
+
+msgid "Resolution"
+msgstr "Risoluzione"
+
+msgid "Resume Class"
+msgstr "Riprendi classe"
+
+msgid "Resume Printer"
+msgstr "Riprendi stampante"
+
+msgid "Return Address"
+msgstr "Indirizzo mittente"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Indirizzo mittente - 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "Riavvolgi"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Esecuzione del comando: %s %s -N -A %s -c '%s'\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENZA utilizza una lunghezza indefinita"
+
+msgid "See Other"
+msgstr "Vedi altro"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "Porta seriale#%d"
+
+msgid "Server Restarted"
+msgstr "Server riavviato"
+
+msgid "Server Security Auditing"
+msgstr "Auditing sicurezza server"
+
+msgid "Server Started"
+msgstr "Server avviato"
+
+msgid "Server Stopped"
+msgstr "Server interrotto"
+
+msgid "Service Unavailable"
+msgstr "Servizio non disponibile"
+
+msgid "Set Allowed Users"
+msgstr "Imposta utenti autorizzati"
+
+msgid "Set As Server Default"
+msgstr "Imposta come server di default"
+
+msgid "Set Class Options"
+msgstr "Imposta opzioni classe"
+
+msgid "Set Printer Options"
+msgstr "Imposta opzioni stampante"
+
+msgid "Set Publishing"
+msgstr "Imposta pubblicazione"
+
+msgid "Shipping Address"
+msgstr "Indirizzo di spedizione"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "Indirizzo di spedizione - 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "Lato corto (panoramica)"
+
+msgid "Special Paper"
+msgstr "Carta speciale"
+
+msgid "Standard"
+msgstr "Standard"
+
+msgid "Starting Banner"
+msgstr "Banner iniziale"
+
+msgid "Statement"
+msgstr "Istruzione"
+
+msgid "Stylus Color Series"
+msgstr "Serie Stylus Color"
+
+msgid "Stylus Photo Series"
+msgstr "Serie Stylus Photo"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "Cambio protocolli"
+
+msgid "Tabloid"
+msgstr "Tabloid"
+
+msgid "Tabloid (Oversize)"
+msgstr "Tabloid (senza margini)"
+
+msgid "Tear"
+msgstr "Separa"
+
+msgid "Tear-Off"
+msgstr "Separa"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Posizione di regolazione separa"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "Impossibile trovare il documento PPD \"%s\"."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "Impossibile aprire il documento PPD \"%s\": %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Il nome della classe può contenere fino a 127 caratteri stampabili e non può "
+"contenere spazi, barre (/) o cancelletti (#)."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+"L'attributo notify-lease-duration non può essere usato con le sottoscrizioni "
+"delle stampe."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Il nome della stampante può contenere fino a 127 caratteri stampabili e non "
+"può contenere spazi, barre (/) o cancelletti (#)."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "La stampante o la classe non è stata trovata."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "Printer-uri \"%s\" contiene caratteri non validi."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr ""
+"È richiesto un printer-uri con formato \"ipp://HOSTNAME/classes/CLASSNAME\"."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+"È richiesto un printer-uri con formato \"ipp://HOSTNAME/printers/PRINTERNAME"
+"\"."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"Il nome della sottoscrizione non può contenere spazi, barre (/), punti "
+"interrogativi (?) o cancelletti (#)."
+
+msgid "There are too many subscriptions."
+msgstr "Ci sono troppe sottoscrizioni."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "Media trasferimento termico"
+
+msgid "Title: "
+msgstr "Titolo: "
+
+msgid "Too many active jobs."
+msgstr "Troppe stampe attive."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "Trasparenza"
+
+msgid "Tray"
+msgstr "Vassoio"
+
+msgid "Tray 1"
+msgstr "Vassoio 1"
+
+msgid "Tray 2"
+msgstr "Vassoio 2"
+
+msgid "Tray 3"
+msgstr "Vassoio 3"
+
+msgid "Tray 4"
+msgstr "Vassoio 4"
+
+msgid "URI Too Long"
+msgstr "URI troppo lungo"
+
+msgid "US Executive"
+msgstr "Executive USA"
+
+msgid "US Fanfold"
+msgstr "Modulo continuo USA"
+
+msgid "US Ledger"
+msgstr "Ledger USA"
+
+msgid "US Legal"
+msgstr "Legale USA"
+
+msgid "US Legal (Oversize)"
+msgstr "Legale USA (senza margini)"
+
+msgid "US Letter"
+msgstr "Lettera USA"
+
+msgid "US Letter (Oversize)"
+msgstr "Lettera USA (senza margini)"
+
+msgid "US Letter (Small)"
+msgstr "Lettera USA (con margini)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "Porta seriale#%d USB"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "Impossibile accedere al documento cupsd.conf:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "Impossibile aggiungere la sottoscrizione RSS:"
+
+msgid "Unable to add class:"
+msgstr "Impossibile aggiungere la classe:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "Impossibile aggiungere la stampante:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "Impossibile annullare la sottoscrizione RSS:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "Impossibile modificare l'attributo printer-is-shared:"
+
+msgid "Unable to change printer:"
+msgstr "Impossibile cambiare stampante:"
+
+msgid "Unable to change server settings:"
+msgstr "Impossibile modificare le impostazioni del server:"
+
+msgid "Unable to connect to host."
+msgstr "Impossibile connettersi all'host."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "Impossibile creare il documento temporaneo:"
+
+msgid "Unable to delete class:"
+msgstr "Impossibile eliminare la classe:"
+
+msgid "Unable to delete printer:"
+msgstr "Impossibile eliminare la stampante:"
+
+msgid "Unable to do maintenance command:"
+msgstr "Impossibile eseguire il comando di manutenzione:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "Impossibile ottenere l'elenco delle classi:"
+
+msgid "Unable to get class status:"
+msgstr "Impossibile ottenere lo stato della classe:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "Impossibile ottenere l'elenco dei driver della stampante:"
+
+msgid "Unable to get printer attributes:"
+msgstr "Impossibile ottenere gli attributi della stampante:"
+
+msgid "Unable to get printer list:"
+msgstr "Impossibile ottenere l'elenco delle stampanti:"
+
+msgid "Unable to get printer status:"
+msgstr "Impossibile ottenere lo stato della stampante:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "Impossibile modificare la classe:"
+
+msgid "Unable to modify printer:"
+msgstr "Impossibile modificare la stampante:"
+
+msgid "Unable to move job"
+msgstr "Impossibile spostare la stampa"
+
+msgid "Unable to move jobs"
+msgstr "Impossibile spostare le stampe"
+
+msgid "Unable to open PPD file"
+msgstr "Impossibile aprire il documento PPD"
+
+msgid "Unable to open PPD file:"
+msgstr "Impossibile aprire il documento PPD:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "Impossibile aprire il documento cupsd.conf:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "Impossibile stampare la pagina di prova:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "Impossibile eseguire \"%s\": %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "Impossibile configurare le opzioni:"
+
+msgid "Unable to set server default:"
+msgstr "Impossibile impostare il server di default:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "Impossibile caricare il documento cupsd.conf:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "Non autorizzato"
+
+msgid "Units"
+msgstr "Unità"
+
+msgid "Unknown"
+msgstr "Sconosciuto"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "Printer-error-policy \"%s\" sconosciuto."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "Printer-op-policy \"%s\" sconosciuto."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Tipo valore non supportato"
+
+msgid "Upgrade Required"
+msgstr "Richiesto aggiornamento"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Utilizzo:\n"
+"\n"
+" lpadmin [-h server] -d destinazione\n"
+" lpadmin [-h server] -x destinazione\n"
+" lpadmin [-h server] -p stampante [-c add-class] [-i interfaccia] [-m "
+"modello]\n"
+" [-r remove-class] [-v dispositivo] [-D descrizione]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u consenti:utente,utente] [-u non consentire:utente,"
+"utente]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "Utilizzo: [nome documento] opzioni titolo copie utente stampa %s\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "Utilizzo: [documento] opzioni titolo copie utente ID stampa %s\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "Utilizzo: documento opzioni titolo copie utente ID stampa %s\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+"Utilizzo: convert [ opzioni ]\n"
+"\n"
+"Opzioni:\n"
+"\n"
+" -e Utilizza ogni filtro dal file PPD\n"
+" -f nomefile Imposta il file da convertire (altrimenti stdin)\n"
+" -o nomefile Imposta il file da generare (altrimenti stdout)\n"
+" -i tipo/mime Imposta il tipo MIME in ingresso (altrimenti auto-"
+"typed)\n"
+" -j tipo/mime Imposta il tipo MIME di uscita (altrimenti "
+"application/pdf)\n"
+" -P nomefile.ppd Imposta file PPD\n"
+" -a 'nome=valore ...' Imposta opzione(i)\n"
+" -U nomeutente Imposta il nome utente per la stampa\n"
+" -J titolo Imposta il titolo\n"
+" -c copie Imposta il numero di copie\n"
+" -u Rimuove il file PPD al completamento\n"
+" -D Rimuove il file in ingresso al completamento\n"
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Utilizzo: cupsaddsmb [opzioni] stampante1 ... stampanteN\n"
+" cupsaddsmb [opzioni] -a\n"
+"\n"
+"Opzioni:\n"
+" -E Codifica la connessione al server\n"
+" -H samba-server Utilizza il server SAMBA specificato\n"
+" -U samba-user Effettua l'autenticazione utilizzando l'utente SAMBA "
+"specificato\n"
+" -a Esporta tutte le stampanti\n"
+" -h cups-server Utilizza il server CUPS specificato\n"
+" -v Cerca di essere dettagliato (mostra comandi)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Utilizzo: cupsctl [opzioni] [param=value ... paramN=valueN]\n"
+"\n"
+"Opzioni:\n"
+"\n"
+" -E Abilita codifica\n"
+" -U nome utente Specifica nome utente\n"
+" -h server[:porta] Specifica indirizzo server\n"
+"\n"
+" --[no-]debug-logging Attiva o disattiva logging di debug\n"
+" --[no-]remote-admin Attiva o disattiva amministrazione remota\n"
+" --[no-]remote-any Consenti/impedisci accesso da Internet\n"
+" --[no-]remote-printers Mostra/nascondi stampanti remote\n"
+" --[no-]share-printers Attiva o disattiva condivisione stampanti\n"
+" --[no-]-]user-cancel-any Consenti/impedisci agli utenti di annullare "
+"qualsiasi stampa\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Utilizzo: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Carica documento di configurazione alternativo\n"
+"-f Esegui in primo piano\n"
+"-F Esegui in primo piano, ma sganciato\n"
+"-h Mostra questo messaggio relativo all'utilizzo\n"
+"-l Esegui cupsd da launchd(8)\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+"Utilizzo: cupsfilter -m tipo/mime [ opzioni ] nomefile\n"
+"\n"
+"Opzioni:\n"
+"\n"
+" -c cupsd.conf Imposta il file cupsd.conf da utilizzare\n"
+" -e Usa ogni filtro dal file PPD\n"
+" -j job-id[,N] Filtra il file N dalla stampa specificata (predefinito è "
+"il file 1)\n"
+" -n copies Imposta il numero di copie\n"
+" -o name=value Imposta opzione(i)\n"
+" -p filename.ppd Imposta il file PPD\n"
+" -t title Imposta il titolo\n"
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Utilizzo: cupstestdsc [opzioni] nomedocumento.ps [... nomedocumento.ps]\n"
+" cupstestdsc [opzioni] -\n"
+"\n"
+"Opzioni:\n"
+"\n"
+" -h Mostra l'utilizzo del programma\n"
+"\n"
+" Nota: questo programma convalida solo i commenti DSC, non il PostScript "
+"stesso.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Utilizzo: lpmove stampa/fonte dest\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Utilizzo: lpoptions [-h server] [-E] -d stampante\n"
+" lpoptions [-h server] [-E] [-p stampante] -l\n"
+" lpoptions [-h server] [-E] -p stampante -o opzione[=valore] ...\n"
+" lpoptions [-h server] [-E] -x stampante\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Utilizzo: lppasswd [-g nomegruppo]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Utilizzo: lppasswd [-g nomegruppo] [nomeutente]\n"
+" lppasswd [-g nomegruppo] -a [nomeutente]\n"
+" lppasswd [-g nomegruppo] -x [nomeutente]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Utilizzo: lpq [-P dest] [-U nomeutente] [-h nomehost[:porta]] [-l] "
+"[+intervallo]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Utilizzo: ppdc [opzioni] nomedocumento.drv [ ... nomedocumentoN.drv ]\n"
+"Opzioni:\n"
+" -D name=value Imposta la variabile specificata con il valore.\n"
+" -I include-dir Aggiunge includi directory al percorso di ricerca.\n"
+" -c catalog.po Carica il catalogo messaggi specificato.\n"
+" -d output-dir Specifica la directory di output.\n"
+" -l lingua[,lingua,...] Specifica la lingua(e) di output (impostazioni "
+"internazionali).\n"
+" -m Utilizza il valore ModelName come nome documento.\n"
+" -t Verifica PPD invece di generarli.\n"
+" -v Cerca di essere abbastanza dettagliato (più v per "
+"ulteriori dettagli).\n"
+" -z Comprime i documenti PPD utilizzando GNU zip.\n"
+" --cr Termina le linee con CR (Mac OS 9).\n"
+" --crlf Termina linee con CR + LF (Windows).\n"
+" --lf Termina linee con LF (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"Utilizzo: ppdhtml [opzioni] nomedocumento.drv >nomedocumento.html\n"
+" -D name=value Imposta il nome specificato con il valore .\n"
+"Opzioni:\n"
+" -I include-dir Aggiunge includi directory al percorso di ricerca.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Utilizzo: ppdi [options] nomedocumento.ppd [ ... nomedocumentoN.ppd ]\n"
+"Opzioni:\n"
+" -I include-dir\n"
+" -o nomedocumento.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Utilizzo: ppdmerge [opzioni] nomedocumento.ppd [ ... nomedocumentoN.ppd ]\n"
+"Opzioni:\n"
+" -o nomedocumento.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"Utilizzo: ppdpo [opzioni] -o nomedocumento.po nomedocumento.drv [ ... "
+"nomedocumentoN.drv ]\n"
+"Opzioni:\n"
+" -D name=value Imposta la variabile specificata con il valore.\n"
+" -I include-dir Aggiunge includi directory al percorso di ricerca.\n"
+" -v Cerca di essere dettagliato (più v per ulteriori "
+"dettagli).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Utilizzo: snmp [host-or-ip-address]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Il valore utilizza una lunghezza indefinita"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind utilizza una lunghezza indefinita"
+
+msgid "Version uses indefinite length"
+msgstr "La versione utilizza una lunghezza indefinita"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: aggiungi solo le prime stampanti %d trovate"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: atteso booleano per l'opzione waiteof \"%s\"\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: la stampante non risponde\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: la stampante ha inviato un EOF inatteso!\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: impossibile aprire documento \"%s:%s\": %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: impossibile inviare richiesta PAP"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: pacchetto PAP inatteso di tipo %d\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: pacchetto PAP sconosciuto di tipo %d\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: atteso numero per l'opzione status \"%s\"\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Sì"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"Devi accedere a questa pagina utilizzando l'URL <A HREF=\"https://%s:%d%s"
+"\">https://%s:%d%s</A>."
+
+msgid "You4 Envelope"
+msgstr "Busta You4"
+
+msgid "ZPL Label Printer"
+msgstr "Stampante etichetta ZPL"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "interrotto"
+
+msgid "canceled"
+msgstr "annullato"
+
+msgid "completed"
+msgstr "completato"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr ""
+"convert: utilizza l'opzione -f per specificare un documento da convertire.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "esecuzione di cups-deviced fallita."
+
+msgid "cups-driverd failed to execute."
+msgstr "esecuzione di cups-driverd fallita."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: nessun documento PPD per la stampante \"%s\" - %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: impossibile connettersi al server: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr ""
+"cupsd: supporto launchd(8) non compilato, eseguo in modalità normale.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: impossibile aprire documento di stampa - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd: l'opzione -q è incompatibile con l'opzione -v.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd: l'opzione -v è incompatibile con l'opzione -q.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "dispositivo per %s/%s: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "dispositivo per %s: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "error-index utilizza una lunghezza indefinita"
+
+msgid "error-status uses indefinite length"
+msgstr "error-status utilizza una lunghezza indefinita"
+
+msgid "held"
+msgstr "bloccato"
+
+msgid "help\t\tget help on commands\n"
+msgstr "help\t\tottieni aiuto riguardo ai comandi\n"
+
+msgid "idle"
+msgstr "inattivo"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: la stampante %s è già un membro della classe %s.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: la stampante %s non è un membro della classe %s.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: impossibile connettersi al server: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: impossibile aprire documento PPD \"%s\" - %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: impossibile aprire documento \"%s\": %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: impossibile connettersi al server: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: impossibile aggiungere una stampante o un'istanza: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: impossibile aprire il file PPD per %s: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: spiacente, password rifiutata.\n"
+"La password deve essere di almeno 6 caratteri, non può contenere\n"
+"il nome utente e deve contenere almeno una lettera e un numero.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: impossibile copiare la stringa della password: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: impossibile aprire il documento delle password: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: impossibile scrivere il documento delle password: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr ""
+"lppasswd: copia di sicurezza del vecchio documento delle password fallita: %"
+"s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: rinomina del documento delle password fallita: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: l'utente \"%s\" e il gruppo \"%s\" non esistono.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "membri della classe %s:\n"
+
+msgid "no entries\n"
+msgstr "nessuna voce\n"
+
+msgid "no system default destination\n"
+msgstr "nessuna destinazione predefinita di sistema\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "in sospeso"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: aggiungi includi directory \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: aggiungi/aggiorna testo UI da %s...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: valore booleano errato (%s) alla riga %d di %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: sostituzione variabile errata ($%c) alla riga %d di %s.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: atteso un valore booleano alla riga %d di %s.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: atteso codice scelta alla riga %d di %s.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: attesa scelta nome/testo alla riga %d di %s.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: carico documento informazioni del driver \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: carico messaggi per impostazioni internazionali \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: carico messaggi da \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: impossibile creare il documento PPD \"%s\" - %s.\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: impossibile creare la directory di output %s: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: impossibile creare pipe di output: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: impossibile eseguire cupstestppd: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: impossibile trovare localizzazione per \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr ""
+"ppdc: impossibile caricare documento di localizzazione per \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: variabile non definita (%s) alla riga %d di %s.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: scrivo %s...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: scrivo documenti PPD nella directory \"%s\"...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: ignoro documento %s PPD...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: impossibile eseguire copia di backup di %s su %s- %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "la stampante %s è disabilitata da %s -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "la stampante %s è in attesa. Abilitata da %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "la stampante %s sta stampando %s-%d. Abilitata da %s\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "la stampante %s/%s è disabilitata da %s -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "la stampante %s/%s è in attesa. Abilitata da %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "la stampante %s/%s sta stampando %s-%d. Abilitata da %s\n"
+
+msgid "processing"
+msgstr "elaborazione in corso"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "l'id richiesto è %s-%d (%d file)\n"
+
+msgid "request-id uses indefinite length"
+msgstr "request-id utilizza una lunghezza indefinita"
+
+msgid "scheduler is not running\n"
+msgstr "la stampa programmata non è in esecuzione\n"
+
+msgid "scheduler is running\n"
+msgstr "la stampa programmata è in esecuzione\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "verifica di %s fallita: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "stato\t\tmostra lo stato del demone e della coda\n"
+
+msgid "stopped"
+msgstr "interrotto"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "destinazione predefinita di sistema: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "destinazione predefinita di sistema: %s/%s\n"
+
+msgid "unknown"
+msgstr "Sconosciuto"
+
+msgid "untitled"
+msgstr "senza titolo"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindings utilizza una lunghezza indefinita"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " WARN %s non ha opzioni corrispondenti!\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " WARN Conflitto tra le scelte predefinite!\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " WARN La parola chiave Duplex %s potrebbe non funzionare "
+#~ "correttamente e dovrebbe essere Duplex!\n"
+#~ " RIF: pagina 122, sezione 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " WARN Il documento contiene un misto di interruzioni di riga "
+#~ "CR, LF e CR LF!\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " WARN La riga %d contiene solamente spazi bianchi!\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " WARN Documento APDialogExtension mancante \"%s\"\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " WARN Documento APPrinterIconPath mancante \"%s\"\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " WARN I documenti PPD per sistemi diversi da Windows dovrebbero "
+#~ "usare solo interruzioni di riga LF, non CR LF!\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " WARN Versione PPD %.1f obsoleta!\n"
+#~ " RIF: pagina 42, sezione 5.2.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s non esiste!\n"
+
+#~ msgid " %s %s file \"%s\" has the wrong capitalization!\n"
+#~ msgstr " %s %s il file \"%s\" ha una capitalizzazione errata!\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s Errato %s scelta %s!\n"
+#~ " Rif: pagina 122, sezione 5.17\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr ""
+#~ " %s Stringa traduzione UTF-8 \"%s\" errata per l'opzione %s!\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Stringa traduzione UTF-8 \"%s\" errata per l'opzione %s, scelta "
+#~ "%s!\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Valore cupsFilter \"%s\" errato!\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s cupsICCProfile %s errato!\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Valore cupsPreFilter \"%s\" errato!\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s cupsUIConstraints %s errato: \"%s\"!\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s lingua \"%s\" errata!\n"
+
+#~ msgid " %s Bad spelling of %s - should be %s!\n"
+#~ msgstr " %s Ortografia non corretta di %s - dovrebbe essere %s!\n"
+
+#~ msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID!\n"
+#~ msgstr ""
+#~ " %s Impossibile fornire contemporaneamente APScanAppPath e "
+#~ "APScanAppBundleID!\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s cupsUIConstraints %s vuoto!\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s Manca stringa traduzione \"%s\" per l'opzione %s!\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Manca stringa traduzione \"%s\" per l'opzione %s, scelta %s!\n"
+
+#~ msgid ""
+#~ " %s Missing REQUIRED PageRegion option!\n"
+#~ " REF: Page 100, section 5.14.\n"
+#~ msgstr ""
+#~ " %s Opzione RICHIESTA PageRegion mancante!\n"
+#~ " REF: Pagina 100, sezione 5.14.\n"
+
+#~ msgid ""
+#~ " %s Missing REQUIRED PageSize option!\n"
+#~ " REF: Page 99, section 5.14.\n"
+#~ msgstr ""
+#~ " %s Opzione RICHIESTA PageSize mancante!\n"
+#~ " REF: Pagina 99, sezione 5.14.\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Manca stringa traduzione *%s %s in UIConstraints \"*%s %s *%s %s"
+#~ "\"!\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr ""
+#~ " %s Manca stringa traduzione *%s %s in cupsUIConstraints %s: \"%s"
+#~ "\"!\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s Documento cupsICCProfile \"%s\" mancante!\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s cupsUIResolver %s mancante!\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr " %s Manca opzione %s in UIConstraints \"*%s %s *%s %s\"!\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Manca opzione %s in cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr ""
+#~ " %s Nessuna traduzione base \"%s\" è compresa nel documento!\n"
+
+#~ msgid ""
+#~ " %s Non-standard size name \"%s\"!\n"
+#~ " REF: Page 187, section B.2.\n"
+#~ msgstr ""
+#~ " %s Dimensione del nome \"%s\" non standard!\n"
+#~ " REF: Pagina 187, sezione B.2.\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s %s RICHIESTO non definisce la scelta Nessuno!\n"
+#~ " RIF: pagina 122, sezione 5.17\n"
+
+#~ msgid " %s Size \"%s\" defined for %s but not for %s!\n"
+#~ msgstr " %s Dimensione \"%s\" definita per %s ma non per %s.\n"
+
+#~ msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)!\n"
+#~ msgstr " %s La misura \"%s\" ha dimensioni inattese (%gx%g)!\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " %s il valore hash cupsICCProfile %s si scontra con %s!\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver %s causa un loop!\n"
+
+#~ msgid ""
+#~ " %s cupsUIResolver %s does not list at least two different "
+#~ "options!\n"
+#~ msgstr ""
+#~ " %s il cupsUIResolver %s non elenca almeno due diverse opzioni.\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** %s i nomi di scelta %s e %s differiscono solo per "
+#~ "maiuscole e minuscole!\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **FAIL** %s deve essere 1284DeviceID!\n"
+#~ " RIF: pagina 72, sezione 5.5\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** DefaultImageableArea %s ERRATO!\n"
+#~ " RIF: pagina 102, sezione 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** DefaultPaperDimension %s ERRATO!\n"
+#~ " RIF: pagina 103, sezione 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **FAIL** Scelta %s Errata %s \n"
+#~ " RIF: pagina 84, sezione 5.9.\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr " **FAIL** LanguageEncoding %s: deve essere ISOLatin1!\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr " **FAIL** LanguageVersion %s errata: deve essere inglese!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **FAIL** La stringa di traduzione predefinita per l'opzione %s "
+#~ "scelta %s contiene caratteri di 8-bit!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **FAIL** La stringa di traduzione predefinita per l'opzione %s "
+#~ "contiene caratteri di 8-bit!\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** I nomi dei gruppi %s e %s differiscono solo per maiuscole "
+#~ "e minuscole!\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **FAIL** Varie occorrenze dei nomi di scelta %s %s!\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** i nomi delle opzioni %s e %s differiscono solo per "
+#~ "maiuscole e minuscole!\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " %%%%BoundingBox: errato alla riga %d!\n"
+#~ " RIF: pagina 39, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " %%%%Page: errato alla riga %d!\n"
+#~ " RIF: pagina 53, %%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " %%%%Pages: errato alla riga %d!\n"
+#~ " RIF: pagina 43, %%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " La riga %d eccede i 255 caratteri (%d)!\n"
+#~ " RIF: pagina 25, lunghezza della riga\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " %!PS-Adobe-3.0 mancante alla prima riga!\n"
+#~ " RIF: pagina 17, 3.1 uniformare documenti\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " Commento %%EndComments mancante!\n"
+#~ " RIF: pagina 41, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " Commento %%BoundingBox: mancante o errato!\n"
+#~ " RIF: pagina 39, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " Commenti %%Page: mancante o errato!\n"
+#~ " RIF: pagina 53, %%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " Commento %%Pages: mancante o errato!\n"
+#~ " RIF: pagina 43, %%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " Trovate %d righe che eccedono i 255 caratteri!\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " Troppi commenti %%BeginDocument!\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " Troppi commenti %%EndDocument!\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " Attenzione: il documento contiene dati binari!\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " Attenzione: nessun commento %%EndComments nel documento!\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " Attenzione: versione DSC %.1f obsoleta nel documento!\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s non supportato!"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: non so cosa fare!\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: Errore: i nomi della variabile d'ambiente %s non esistono nella "
+#~ "destinazione \"%s\"!\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: Errore: ID dell'operazione errato!\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr ""
+#~ "%s: Errore: impossibile stampare documenti e modificare operazioni "
+#~ "contemporaneamente!\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: Errore: impossibile stampare da stdin se vengono forniti documenti o "
+#~ "ID dell'operazione!\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: Errore: atteso set di caratteri dopo l'opzione '-S'!\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: Errore: atteso tipo di contenuto dopo l'opzione '-T'!\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: Errore: attese copie dopo l'opzione '-n'!\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s: Errore: atteso numero di copie dopo l'opzione '-#'!\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: Errore: attesa destinazione dopo l'opzione '-P'!\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: Errore: attesa destinazione dopo l'opzione '-b'!\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: Errore: attesa destinazione dopo l'opzione '-d'!\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: Errore: atteso modulo dopo l'opzione '-f'!\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: Errore: atteso nome di blocco dopo l'opzione '-H'!\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: Errore: atteso hostname dopo l'opzione '-H'!\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: Errore: atteso hostname dopo l'opzione '-h'!\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: Errore: atteso elenco modalità dopo l'opzione '-y'!\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: Errore: atteso nome dopo l'opzione '-%c'!\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s: Errore: attesa stringa di opzione dopo l'opzione '-o'!\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: Errore: atteso elenco delle pagine dopo l'opzione '-P'!\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: Errore: attesa priorità dopo l'opzione '-%c'!\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s: Errore: atteso testo di motivazione dopo l'opzione '-r'!\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: Errore: atteso titolo dopo l'opzione '-t'!\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s: Errore: atteso nome utente dopo l'opzione '-U'!\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s: Errore: atteso nome utente dopo l'opzione '-u'!\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: Errore: atteso valore dopo l'opzione '-%c'!\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: Errore: dopo l'opzione '-W', occorre \"completati\", \"non completati"
+#~ "\" o \"tutti\"!\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: Errore: la stampa programmata non risponde!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: Errore: destinazione \"%s\" sconosciuta!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: Errore: destinazione \"%s/%s\" sconosciuta!\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: Errore: opzione '%c' sconosciuta!\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: Errore: opzione '%s' sconosciuta!\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: Atteso ID dell'operazione dopo l'opzione '-i'!\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: Nome di destinazione non valido nell'elenco \"%s\"!\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr ""
+#~ "%s: prima di '-H restart' è richiesto l'ID dell'operazione ('-i "
+#~ "jobid')!\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: Nessun filtro per convertire da %s/%s a %s/%s!\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s: Spiacente, nessun supporto di codifica compilato!\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: Impossibile contattare il server!\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: Impossibile determinare il tipo MIME di \"%s\"!\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s: Impossibile aprire %s - %s\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s: Errore: impossibile aprire %s - %s alla riga %d.\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s: impossibile leggere il database MIME da \"%s\" o \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: Destinazione sconosciuta \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: Errore: tipo MIME di destinazione %s/%s sconosciuto!\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: Opzione '%c' sconosciuta!\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: Tipo MIME sorgente %s/%s sconosciuto!\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: Attenzione: modificatore di formato '%c' non supportato; il risultato "
+#~ "potrebbe non essere corretto!\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: Attenzione: opzione del set di caratteri ignorata!\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: Attenzione: opzione del tipo di contenuto ignorata!\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: Attenzione: opzione del modulo ignorata!\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: Attenzione: opzione modalità ignorata!\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: Errore: i nomi della variabile d'ambiente %s non esistono nella "
+#~ "destinazione \"%s\"!\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: Errore: attesa opzione=valore dopo l'opzione '-o'!\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "Scala di grigi a 600 DPI"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr "Per esportare i driver di stampa è necessaria una password Samba!"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr "Per esportare i driver di stampa è necessario un nome utente Samba!"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "Esiste già una classe chiamata \"%s\"!"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "Esiste già una stampante chiamata \"%s\"!"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr "Tentativo di impostare printer-state %s a un valore %d errato!"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "I gruppi di attributi non sono ordinati (%x < %x)!"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "URI dispositivo \"%s\" errato!\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "uri dispositivo \"%s\" errato!"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "Schema device-uri \"%s\" errato!"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "document-format \"%s\" errato!"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Buffer nome documento errato!"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Valore job-priority errato!"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Valore job-sheets \"%s\" errato!"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Tipo valore job-sheets errato!"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Valore job-state errato!"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Attributo job-uri \"%s\" errato!"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "notify-pull-method \"%s\" errato!"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "URI notify-recipient-uri \"%s\" errato!"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "Opzione + scelta errata alla riga %d!"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "Port-monitor \"%s\" errato!"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Valore printer-state %d errato!"
+
+#~ msgid "Bad request ID %d!"
+#~ msgstr "ID di richiesta errato %d."
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "Numero versione richiesta %d.%d errato!"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "ID abbonamento errato!"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "Set di caratteri \"%s\" non supportato!"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "Impossibile eseguire scansione del tipo \"%s\"!"
+
+#~ msgid "Cover open."
+#~ msgstr "Coperchio aperto"
+
+#~ msgid "Developer almost empty."
+#~ msgstr "Developer quasi vuoto."
+
+#~ msgid "Developer empty!"
+#~ msgstr "Developer vuoto!"
+
+#~ msgid "Door open."
+#~ msgstr "Porta aperta"
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: %%BoundingBox errato: commento visto!\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: %%IncludeFeature errato: commento!\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: %%Page errato: commento nel documento!\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: %%PageBoundingBox errato: commento nel documento!\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: dispositivo SCSI \"%s\" errato!\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: valore colonne errato %d!\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: valore cpi errato %f!\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: valore lpi errato %f!\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: Formato di stampa errato!\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: la stampante di destinazione non esiste!\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: %%BoundingBox duplicato: commento visto!\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: %%Pages duplicato: commento visto!\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: documento di stampa vuoto!\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr "ERROR: attesa stringa tra virgolette nella riga %d di %s!\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: errore USB fatale!\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr ""
+#~ "ERROR: visto comando HP-GL/2 non valido, impossibile stampare documento!\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: %%EndProlog mancante!\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: %%EndSetup mancante!\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: manca URI su linea di comando e nessuna variabile ambiente "
+#~ "DEVICE_URI!\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: manca valore alla riga %d del documento banner!\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: occorre una riga msgid prima di ogni stringa di traduzione alla "
+#~ "riga %d di %s!\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: nessun %%BoundingBox: commento nell'intestazione!\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: nessun %%Pages: commento nell'intestazione!\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: nessun dispositivo URI trovato in argv[0] e nessuna variabile "
+#~ "ambiente in DEVICE_URI!\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: nessuna pagina trovata!\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: carta esaurita!\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: variabile ambiente PRINTER non definita!\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: il documento stampa non è stato accettato (%s)!\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: la stampante non risponde!\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: impossibile creare il documento temporaneo: %s.\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: impossibile creare il documento temporaneo: %s.\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr ""
+#~ "ERROR: impossibile ottenere gli attributi (%2$s) della stampa %1$d!\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: impossibile ottenere lo stato della stampante (%s)!\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: impossibile individuare la stampante '%s'!\n"
+
+#~ msgid "ERROR: Unable to open PPD file!\n"
+#~ msgstr "ERROR: Impossibile aprire il file PPD.\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: impossibile aprire il documento immagine per la stampa!\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: impossibile aprire il documento temporaneo"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: impossibile stampare colonne di testo %d!\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: impossibile stampare pagina di testo %dx%d!\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: impossibile leggere i dati di stampa!\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: impossibile inviare i dati di stampa (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: impossibile inviare i dati di stampa!\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: impossibile scrivere %d byte sulla stampante!\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr "ERROR: impossibile scrivere dati raster sul driver!\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: impossibile scrivere documento temporaneo"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: testo inatteso alla riga %d di %s!\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: valore opzione di codifica sconosciuto \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: formato catalogo messaggio di \"%s\" sconosciuto!\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: opzione \"%s\" con valore \"%s\" sconosciuta!\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: valore opzione versione sconosciuto \"%s\"!\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr ""
+#~ "ERROR: valore luminosità %s non supportato, utilizzo luminosità=100!\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: valore gamma %s non supportato, utilizzo gamma=1000!\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr "ERROR: valore number-up %d non supportato, utilizzo number-up=1!\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: valore number-up-layout %s non supportato, utilizzo number-up-"
+#~ "layout=lrtb!\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: valore page-border %s non supportato, utilizzo page-border=none!\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr "ERROR: rilevato overflow (%d byte) doc_printf, interrompo!\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr "ERROR: il filtro pdftops si è chiuso al segnale %d!\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr "ERROR: il filtro pdftops si è chiuso con stato %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops si è chiuso al segnale %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops si è chiuso con stato %d!\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: recuperabile: impossibile stabilire connessione con la stampante; "
+#~ "riprovo fra 30 secondi...\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "Documento PPD vuoto!"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "Errore: è necessario un nome host dopo l'opzione '-h'!\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Temperatura del fusibile elevata!"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "Temperatura del fusibile bassa!"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "Ottenuto un attributo printer-uri, ma nessun job-id!"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Inchiostro/toner quasi vuoto."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Inchiostro/toner vuoto!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Cestino inchiostro/toner quasi pieno."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Cestino inchiostro/toner pieno!"
+
+#~ msgid "Interlock open."
+#~ msgstr "Interblocco aperto."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "La stampa #%d non può essere riavviata: nessun documento!"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "La stampa #%d non esiste!"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "La stampa #%d è terminata e non può essere modificata!"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "La stampa %d non è completa!"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "La stampa #%d non è bloccata per l'autenticazione!"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "La stampa #%d non è bloccata!"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "La stampa #%s non esiste!"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "Stampa %d non trovata!"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "Le sottoscrizioni delle stampe non possono essere rinnovate!"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "Lingua \"%s\" non supportata!"
+
+#~ msgid "Media jam!"
+#~ msgstr "Inceppamento supporto!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Cassetto carta quasi vuoto."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Cassetto carta vuoto!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Cassetto carta mancante!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "Bisogna riempire il cassetto carta."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "Attributo document-number mancante!"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "Doppi apici mancanti alla riga %d!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "Variabile modulo mancante"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "Attributo notify-subscription-ids mancante!"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "Attributo requesting-user-name mancante!"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "Attributi necessari mancanti!"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "Valore mancante alla riga %d!"
+
+#~ msgid "Nested classes are not allowed!"
+#~ msgstr "Le classi nidificate non sono consentite."
+
+#~ msgid "No PPD name!"
+#~ msgstr "Nessun nome PPD!"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Non è installato nessun driver di stampa Windows!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "Nessuna stampa attiva su %s!"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "Nessun attributo nella richiesta!"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "Nessuna informazione di autenticazione fornita!"
+
+#~ msgid "No file!?!"
+#~ msgstr "Nessun documento!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "Nessuna ora modifica!"
+
+#~ msgid "No printer name!"
+#~ msgstr "Nessun nome stampante!"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "Nessun printer-uri trovato per la classe!"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "Nessun printer-uri trovato!"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "Nessun printer-uri nella richiesta!"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "Nessun attributo di sottoscrizione nella richiesta!"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC quasi alla fine del proprio ciclo di vita utile."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC alla fine del proprio ciclo di vita utile!"
+
+#~ msgid "Out of toner!"
+#~ msgstr "Toner esaurito!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Vassoio di uscita quasi pieno."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Vassoio di uscita pieno!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Vassoio di uscita mancante!"
+
+#~ msgid "Printer offline."
+#~ msgstr "Stampante non in linea."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "Stampante SCSI"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "Il valore notify-user-data è troppo grande (%d > 63 ottetti)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "La stampante o la classe non è condivisa!"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "Attributo printer-uri richiesto!"
+
+#~ msgid "Toner low."
+#~ msgstr "Toner basso."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "Troppi valori job-sheets (%d > 2)!"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "Troppi valori printer-state-reasons (%d > %d)!"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "Impossibile aggiungere la stampa alla destinazione \"%s\"!"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "Impossibile allocare memoria per tipi di documento!"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "Impossibile copiare i documenti dei driver della stampante per CPU a 64 "
+#~ "bit (%d)!"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr ""
+#~ "Impossibile copiare i documenti dei driver della stampante per Windows a "
+#~ "64 bit (%d)!"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "Impossibile copiare i documenti CUPS dei driver della stampante (%d)!"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "Impossibile copiare il documento PPD: %s!"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "Impossibile copiare il documento PPD!"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Impossibile copiare i documenti dei driver della stampante per Windows "
+#~ "2000 (%d)!"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "Impossibile copiare i documenti dei driver della stampante per Windows 9x "
+#~ "(%d)!"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "Impossibile copiare lo script di interfaccia: %s!"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "Impossibile creare printer-uri!"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr "Impossibile modificare i documenti cupsd.conf più grandi di 1 MB!"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "Impossibile trovare una destinazione per la stampa!"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "Impossibile trovare la stampante!\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Impossibile installare i documenti dei driver di stampa per Windows 2000 "
+#~ "(%d)!"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "Impossibile installare i documenti dei driver di stampa per Windows 9x (%"
+#~ "d)!"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "Impossibile aprire il documento %d nella stampa %d!"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "Impossibile inviare comandi al driver della stampante!"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Impossibile configurare il driver della stampante per Windows (%d)!"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "Impossibile utilizzare il driver della classe USB legacy!\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "Errore della stampante sconosciuto (%s)!"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Set di caratteri \"%s\" non supportato!"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "Compressione \"%s\" non supportata!"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "Attributo compressione %s non supportato!"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "Formato \"%s\" non supportato!"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "Formato '%s non supportato'!"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "Formato '%s/%s' non supportato!"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "Utilizzo: convert [ opzioni ]\n"
+#~ "\n"
+#~ "Opzioni:\n"
+#~ "\n"
+#~ " -f nome documento Imposta il documento da convertire "
+#~ "(altrimenti stdin)\n"
+#~ " -o nome documento Imposta il documento da generare (altrimenti "
+#~ "stdout)\n"
+#~ " -i mime/type Imposta il tipo MIME input (altrimenti auto-"
+#~ "typed)\n"
+#~ " -j mime/type Imposta il tipo MIME output (altrimenti "
+#~ "application/pdf)\n"
+#~ " -P filename.ppd Imposta il documento PPD\n"
+#~ " -a 'nome=valore ...' Imposta opzione(i)\n"
+#~ " -U nome utente Imposta il nome utente per la stampa\n"
+#~ " -J titolo Imposta il titolo\n"
+#~ " -c copie Imposta il numero di copie\n"
+#~ " -u Rimuove il documento PPD terminata l'azione\n"
+#~ " -D Rimuove il documento input terminata l'azione\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "Utilizzo: cupsfilter -m mime/type [ opzioni] filename\n"
+#~ "\n"
+#~ "Opzioni:\n"
+#~ "\n"
+#~ " -c cupsd.conf Imposta il documento cupsd.conf da utilizzare\n"
+#~ " -j job-id[,N] Filtra il documento N dalla stampa specificata "
+#~ "(l'opzione di default è documento 1)\n"
+#~ " -n copies Imposta il numero di copie\n"
+#~ " -o name=value Imposta l'opzione(i)\n"
+#~ " -p filename.ppd Imposta il documento PPD\n"
+#~ " -t title Imposta il titolo\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+#~ "translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Utilizzo: cupstestppd [opzioni] nomefile1.ppd[.gz] [... nomefileN.ppd[."
+#~ "gz]]\n"
+#~ " programma | cupstestppd [opzioni] -\n"
+#~ "\n"
+#~ "Opzioni:\n"
+#~ "\n"
+#~ " -R cartella-radice Imposta radice alternativa\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+#~ "translations}\n"
+#~ " Emette avvisi al posto degli errori\n"
+#~ " -q Esecuzione silenziosa\n"
+#~ " -r Modalità di apertura 'rilassata'\n"
+#~ " -v Abbastanza dettagliato\n"
+#~ " -vv Molto dettagliato\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Utilizzo: cupstestppd [opzioni] nomefile1.ppd[.gz] [... nomefileN.ppd[."
+#~ "gz]]\n"
+#~ " programma | cupstestppd [opzioni] -\n"
+#~ "\n"
+#~ "Opzioni:\n"
+#~ "\n"
+#~ " -R root-directory Configura root alternativa\n"
+#~ " -W {tutti,nessuno,limitazioni,default,filtri,traduzioni}\n"
+#~ " Avvisi per problemi invece di errori\n"
+#~ " -q Esegui in silenzio\n"
+#~ " -r Utilizza modalità di apertura 'rilassata'\n"
+#~ " -v Cerca di essere abbastanza dettagliato\n"
+#~ " -vv Cerca di essere molto dettagliato\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: impossibile leggere richiesta canale laterale!\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr ""
+#~ "WARNING: impossibile includere l'opzione \"%s\" tramite IncludeFeature!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: l'host remoto non ha risposto con byte stato comando dopo %d "
+#~ "secondi!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: l'host remoto non ha risposto con byte stato controllo dopo %d "
+#~ "secondi!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: l'host remoto non ha risposto con byte stato dati dopo %d "
+#~ "secondi!\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr "WARNING: comando SCSI scaduto (%d); riprovo...\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: questo documento non è conforme alle convenzioni Adobe sulla "
+#~ "struttura dei documenti (Adobe Document Structuring Conventions) e "
+#~ "potrebbe non essere stampato correttamente!\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: scelta sconosciuta \"%s\" per opzione \"%s\"!\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: opzione sconosciuta \"%s\"!\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: tasso baud %s non supportato!\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: recuperabile: l'host del network '%s' è occupato; riprovo fra %d "
+#~ "secondi...\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr ""
+#~ "Attenzione: non è installato nessun driver di stampa per Windows 2000!"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: opzione sconosciuta \"%s\"!\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: opzione sconosciuta \"-%c\"!\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr ""
+#~ "cupsd: atteso nome documento di configurazione dopo l'opzione \"-c\"!\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: impossibile aprire la directory attuale!\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: argomento sconosciuto \"%s\" - interruzione!\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: opzione sconosciuta \"%c\" - interrompo!\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: numero documento %d non valido!\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: ID stampa %d non valido!\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: è possibile specificare solo un nome documento!\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter: impossibile creare il documento temporaneo: %s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "attributo job-printer-uri mancante!"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr ""
+#~ "lpadmin: il nome della classe può contenere solo caratteri stampabili!\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: atteso PPD dopo l'opzione '-P'!\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr "lpadmin: atteso allow/deny:userlist dopo l'opzione '-u'!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: attesa classe dopo l'opzione '-r'!\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: atteso nome classe dopo l'opzione '-c'!\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: attesa descrizione dopo l'opzione '-D'!\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: atteso URI di dispositivo dopo l'opzione '-v'!\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: attesi tipi di documento dopo l'opzione '-I'!\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: atteso nome host dopo l'opzione '-h'!\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: attesa interfaccia dopo l'opzione '-i'!\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: attesa posizione dopo l'opzione '-L'!\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: atteso modello dopo l'opzione '-m'!\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: atteso nome=valore dopo l'opzione '-o'!\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: attesa stampante dopo l'opzione '-p'!\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: atteso nome stampante dopo l'opzione '-d'!\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin: attesa stampante o classe dopo l'opzione '-x'!\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: nessun nome utente trovato!\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr ""
+#~ "lpadmin: il nome della stampante può contenere solo caratteri "
+#~ "stampabili!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: impossibile aggiungere una stampante alla classe:\n"
+#~ " Devi specificare prima il nome di una stampante!\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin: impossibile creare il documento temporaneo - %s\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin: impossibile creare il documento temporaneo: %s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: impossibile rimuovere una stampante dalla classe:\n"
+#~ " Devi specificare prima il nome di una stampante!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: impossibile impostare il documento PPD:\n"
+#~ " Devi specificare prima il nome di una stampante!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: impossibile impostare URI dispositivo:\n"
+#~ " Devi specificare prima il nome di una stampante!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: impossibile impostare lo script di interfaccia o il documento "
+#~ "PPD:\n"
+#~ " Devi specificare prima il nome di una stampante!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: impossibile impostare lo script di interfaccia:\n"
+#~ " Devi specificare prima il nome di una stampante!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: impossibile impostare la descrizione della stampante:\n"
+#~ " Devi specificare prima il nome di una stampante!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: impossibile impostare la posizione della stampante:\n"
+#~ " Devi specificare prima il nome di una stampante!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: impossibile impostare le opzioni della stampante:\n"
+#~ " Devi specificare prima il nome di una stampante!\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: opzione consenti/non consentire \"%s\" sconosciuta!\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: argomento '%s' sconosciuto!\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: opzione '%c' sconosciuta!\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin: attenzione, elenco dei tipi di contenuto ignorato!\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr "lpinfo: attesa stringa ID dispositivo 1284 dopo --device-id!\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: attesa lingua dopo --language!\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo: attesi marca e modello dopo --make-and-model!\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo: attesa stringa prodotto dopo --product!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo: atteso elenco schema dopo --exclude-schemes!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo: atteso elenco schema dopo --include-schemes!\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: atteso timeout dopo --timeout!\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: argomento '%s' sconosciuto!\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: opzione '%c' sconosciuta!\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: opzione '%s' sconosciuta!\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: argomento '%s' sconosciuto!\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: opzione '%c' sconosciuta!\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: nessuna stampante!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: impossibile aprire il documento PPD per %s!\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: stampante o classe sconosciuta!\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: solo root può aggiungere o eliminare le password!\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: il documento delle password è occupato!\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: documento delle password non aggiornato!\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: spiacente, la password non corrisponde!\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: spiacente, le password non corrispondono!\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: errore: i nomi della variabile d'ambiente %s non esistono nella "
+#~ "destinazione \"%s\"!\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-events non specificato!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "notify-recipient-uri URI \"%s\" è già utilizzato!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "notify-recipient-uri URI \"%s\" utilizza uno schema sconosciuto!"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d non corretto!"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: nome risoluzione errato (%s) alla riga %d di %s.\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: chiave stato errata (%s) alla riga %d di %s.\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc: scelta trovata alla riga %d di %s senza opzione!\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: duplica #po per impostazioni internazionali %s alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: attesa una definizione filtro alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: atteso un nome applicazione alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr "ppdc: atteso un set di caratteri dopo Font alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: atteso ordine colore per ColorModel alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: atteso spazio colore per ColorModel alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: attesa compressione per ColorModel alla riga %d di %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: attesa stringa limitazioni per UIConstraints alla riga %d di %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: attesa parola chiave tipo driver dopo DriverType alla riga %d di %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr "ppdc: atteso tipo duplex dopo Duplex alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc: attesa codifica dopo Font alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc: atteso nome documento dopo #po %s alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: atteso nome/testo gruppo alla riga %d di %s.\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc: atteso nome documento alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: atteso intero alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: attese impostazioni internazionali dopo #po alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: atteso nome dopo %s alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: atteso nome dopo FileName alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: atteso nome dopo Font alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc: atteso nome dopo Produttore alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: atteso nome dopo MediaSize alla riga %d di %s.\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: atteso nome dopo ModelName alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: atteso nome dopo PCFileName alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: atteso nome/testo dopo %s alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr "ppdc: atteso nome/testo dopo Installabile alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: atteso nome/testo dopo Risoluzione alla riga %d di %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: attesa combinazione nome/testo per ColorModel alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc: attesa opzione nome/testo alla riga %d di %s.\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: attesa sezione opzione alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: atteso tipo opzione alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: atteso campo sostituzione dopo Risoluzione alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: atteso numero reale alla riga %d di %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: atteso risoluzione/mediatype dopo ColorProfile alla riga %d of %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: atteso risoluzione/mediatype dopo SimpleColorProfile alla riga %d "
+#~ "of %s!\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: atteso selettore dopo %s alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: atteso stato dopo Font alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc: attesa stringa dopo Copyright alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc: attesa stringa dopo Versione alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: attesi due nomi opzione alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: atteso valore dopo %s alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: attesa versione dopo Font alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: nome documento #include/#po \"%s\" non valido!\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: costo non valido per filtro alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr "ppdc: tipo MIME vuoto non valido per filtro alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: nome programma vuoto non valido per filtro alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: sezione opzione \"%s\" non valida alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: tipo opzione \"%s\" non valida alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: #endif mancante alla fine di \"%s\"!\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: #if mancante alla riga %d di %s!\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr ""
+#~ "ppdc: nessun catalogo messaggi fornito per impostazioni internazionali %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Option %s defined in two different groups on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: L'opzione %s è definita in due gruppi differenti alla riga %d di %"
+#~ "s.\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: opzione %s ridefinita con un tipo diverso alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: l'opzione limitazione deve essere *indicata alla riga %d of %s!\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: troppi #if' nidificati alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: impossibile trovare il documento #po %s alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: impossibile trovare includi documento \"%s\" alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: tipo driver %s sconosciuto alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: tipo duplex \"%s\" sconosciuto alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: tipo media \"%s\" sconosciuto alla riga %d di %s!\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: token \"%s\" sconosciuto visto alla riga %d di %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: caratteri trailing sconosciuti nel numero reale \"%s\" alla riga %d "
+#~ "di %s!\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr "ppdc: stringa non terminata che inizia con %c alla riga %d di %s!\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: LanguageVersion \"%s\" errato in %s!\n"
diff --git a/locale/cups_ja.po b/locale/cups_ja.po
new file mode 100644
index 000000000..9b061daa2
--- /dev/null
+++ b/locale/cups_ja.po
@@ -0,0 +1,7205 @@
+#
+# "$Id$"
+#
+# Message catalog template for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 2005-2007 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+#
+# Notes for Translators:
+#
+# The following prefixes MUST NOT be translated: "ALERT:", "CRIT:", "INFO:",
+# "NOTICE:", and "WARNING:".
+#
+# The "checkpo" program located in the "locale" source directory can be used
+# to verify that your translations do not introduce formatting errors or other
+# problems. Run with:
+#
+# cd locale
+# ./checkpo cups_LL.po
+#
+# where "LL" is your locale.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-20 16:43+0900\n"
+"Last-Translator: OPFC TRANSCUPS <opfc-transcups@sourceforge.jp>\n"
+"Language-Team: OPFC TRANSCUPS <opfc-transcups@sourceforge.jp>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(ã™ã¹ã¦)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(ãªã—)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d エントリー\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\t失敗後: 継続\n"
+
+msgid "\tAlerts:"
+msgstr "\t警告:"
+
+msgid "\tBanner required\n"
+msgstr "\tãƒãƒŠãƒ¼ãŒå¿…è¦\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\t文字セット:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\t接続: ç›´çµ\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\t接続: リモート\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tデフォルト用紙サイズ:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tデフォルトピッãƒ:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tデフォルトãƒãƒ¼ãƒˆè¨­å®š:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\t説明: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\t設定ã•ã‚ŒãŸãƒ•ã‚©ãƒ¼ãƒ :\n"
+"\tコンテンツã®ç¨®é¡ž: ã™ã¹ã¦\n"
+"\tプリンターã®ç¨®é¡ž: ä¸æ˜Ž\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\t許å¯ã•ã‚Œã¦ã„るフォーム:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tインターフェイス: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tインターフェイス: %s/interfaces/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tインターフェイス: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\t場所: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\t失敗時: 警告ãªã—\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\t許å¯ã•ã‚Œã¦ã„るユーザー:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tæ‹’å¦ã•ã‚Œã¦ã„るユーザー:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tデーモンã¯æä¾›ã•ã‚Œã¦ã„ã¾ã™\n"
+
+msgid "\tno entries\n"
+msgstr "\tエントリーãŒã‚ã‚Šã¾ã›ã‚“\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\tデãƒã‚¤ã‚¹ '%s' 上ã®ãƒ—リンター 速度 -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\tå°åˆ·ã¯ç„¡åŠ¹ã§ã™\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\tå°åˆ·ã¯æœ‰åŠ¹ã§ã™\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\t%s ã«ã‚­ãƒ¥ãƒ¼ã—ã¾ã—ãŸ\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tキューã¯ç„¡åŠ¹ã§ã™\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tキューã¯æœ‰åŠ¹ã§ã™\n"
+
+msgid "\treason unknown\n"
+msgstr "\t未知ã®ç†ç”±\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" é©åˆãƒ†ã‚¹ãƒˆçµæžœè©³ç´°\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " å‚ç…§: 15 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 3.1。\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " å‚ç…§: 15 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 3.2。\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " å‚ç…§: 19 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 3.3。\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " å‚ç…§: 20 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 3.4。\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " å‚ç…§: 27 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 3.5。\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " å‚ç…§: 42 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.2。\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " å‚ç…§: 16-17 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 3.2。\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " å‚ç…§: 42-45 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.2。\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " å‚ç…§: 45-46 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.2。\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " å‚ç…§: 48-49 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.2。\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " å‚ç…§: 52-54 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.2。\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f ãƒã‚¤ãƒˆ\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " åˆæ ¼ Default%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " åˆæ ¼ DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " åˆæ ¼ DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " åˆæ ¼ FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " åˆæ ¼ FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " åˆæ ¼ LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " åˆæ ¼ LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " åˆæ ¼ Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " åˆæ ¼ ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " åˆæ ¼ NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " åˆæ ¼ PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " åˆæ ¼ PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " åˆæ ¼ PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " åˆæ ¼ PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " åˆæ ¼ Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " åˆæ ¼ ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" 警告 \"%s %s\" 㯠\"%s %s\" ã¨ç«¶åˆã—ã¾ã™\n"
+" (ç¦å‰‡=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" 警告 %s 㯠%s ã¨ä¸€èˆ¬ãƒ—レフィックスを共有ã—ã¾ã™ã€‚\n"
+" å‚ç…§: 15 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 3.2。\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" 警告 LanguageEncoding 㯠PPD 4.3 仕様ã§å¿…é ˆã§ã™ã€‚\n"
+" å‚ç…§: 56-57 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" 警告 Manufacturer 㯠PPD 4.3 仕様ã§å¿…é ˆã§ã™ã€‚\n"
+" å‚ç…§: 58-59 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" 警告 8.3 文字より長ㄠPCFileName 㯠PPD 仕様é•åã§ã™ã€‚\n"
+" å‚ç…§: 61-62 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" 警告 プロトコル㌠PJL ã‚’å«ã‚“ã§ã„ã¾ã™ãŒ JCL 属性ãŒè¨­å®šã•ã‚Œã¦ã„ã¾ã›"
+"ん。\n"
+" å‚ç…§: 78-79 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.7。\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" 警告 プロトコル㌠PJL 㨠BCP ã®ä¸¡æ–¹ã‚’å«ã‚“ã§ã„ã¾ã™; TBCP を想定ã—ã¾"
+"ã™ã€‚\n"
+" å‚ç…§: 78-79 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.7。\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" 警告 ShortNickName 㯠PPD 4.3 仕様ã§å¿…é ˆã§ã™ã€‚\n"
+" å‚ç…§: 64-65 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr " %s APDialogExtension ファイル \"%s\" ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“\n"
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr " %s APPrinterIconPath ファイル \"%s\" ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“\n"
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr " %s APPrinterLowInkTool ファイル \"%s\" ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“\n"
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr " %s APPrinterUtilityPath ファイル \"%s\" ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“\n"
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr " %s APScanAppPath ファイル \"%s\" ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“\n"
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s cupsFilter ファイル \"%s\" ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s cupsPreFilter ファイル \"%s\" ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **失敗** ä¸æ­£ãª Default%s %s\n"
+" å‚ç…§: 40 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 4.5。\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **失敗** ファイルã«ä¸æ­£ãª JobPatchFile 属性ãŒã‚ã‚Šã¾ã™\n"
+" å‚ç…§: 24 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 3.4。\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **失敗** ä¸æ­£ãª Manufacturer (\"HP\" ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“)\n"
+" å‚ç…§: 211 ページã€è¡¨ D.1。\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **失敗** ä¸æ­£ãª Manufacturer (\"Oki\" ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“)\n"
+" å‚ç…§: 211 ページã€è¡¨ D.1。\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **失敗** ä¸æ­£ãª ModelName - 文字列㫠\"%c\" ã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“。\n"
+" å‚ç…§: 59-60 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **失敗** ä¸æ­£ãª PSVersion - \"(文字列) æ•´æ•°\" ã§ã¯ã‚ã‚Šã¾ã›ã‚“。\n"
+" å‚ç…§: 62-64 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **失敗** ä¸æ­£ãª Product - \"(文字列)\" ã§ã¯ã‚ã‚Šã¾ã›ã‚“。\n"
+" å‚ç…§: 62 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **失敗** ä¸æ­£ãª ShortNickName - 31 文字を超ãˆã¦ã„ã¾ã™ã€‚\n"
+" å‚ç…§: 64-65 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **失敗** ä¸æ­£ãªFileVersion \"%s\"\n"
+" å‚ç…§: 56 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **失敗** FormatVersion ãŒé•ã„ã¾ã™ \"%s\"\n"
+" å‚ç…§: 56 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr " **失敗** デフォルトã®ã‚ªãƒ—ションコードãŒè§£é‡ˆã§ãã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **失敗** Default%s ã¯å¿…é ˆ\n"
+" å‚ç…§: 40 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 4.5。\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **失敗** DefaultImageableArea ã¯å¿…é ˆ\n"
+" å‚ç…§: 102 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.15。\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **失敗** DefaultPaperDimension ã¯å¿…é ˆ\n"
+" å‚ç…§: 103 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.15。\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **失敗** FileVersion ã¯å¿…é ˆ\n"
+" å‚ç…§: 56 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **失敗** FormatVersion ã¯å¿…é ˆ\n"
+" å‚ç…§: 56 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **失敗** PageSize %s ã« ImageableArea ã¯å¿…é ˆ\n"
+" å‚ç…§: 41 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5。\n"
+" å‚ç…§: 102 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.15。\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **失敗** LanguageEncoding ã¯å¿…é ˆ\n"
+" å‚ç…§: 56-57 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **失敗** LanguageVersion ã¯å¿…é ˆ\n"
+" å‚ç…§: 57-58 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **失敗** Manufacturer ã¯å¿…é ˆ\n"
+" å‚ç…§: 58-59 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **失敗** ModelName ã¯å¿…é ˆ\n"
+" å‚ç…§: 59-60 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **失敗** NickName ã¯å¿…é ˆ\n"
+" å‚ç…§: 60 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **失敗** PCFileName ã¯å¿…é ˆ\n"
+" å‚ç…§: 61-62 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **失敗** PSVersion ã¯å¿…é ˆ\n"
+" å‚ç…§: 62-64 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **失敗** PageRegion ã¯å¿…é ˆ\n"
+" å‚ç…§: 100 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.14。\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **失敗** PageSize ã¯å¿…é ˆ\n"
+" å‚ç…§: 41 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5。\n"
+" å‚ç…§: 99 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.14。\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **失敗** PageSize ã¯å¿…é ˆ\n"
+" å‚ç…§: 99-100 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.14。\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **失敗** PageSize %s ã« PaperDimension ã¯å¿…é ˆ\n"
+" å‚ç…§: 41 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5。\n"
+" å‚ç…§: 103 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.15。\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **失敗** Product ã¯å¿…é ˆ\n"
+" å‚ç…§: 62 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **失敗** ShortNickName ã¯å¿…é ˆ\n"
+" å‚ç…§: 64-65 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.3。\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " %d 個ã®ã‚¨ãƒ©ãƒ¼ãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸ\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " エラーã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " 失敗\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" 失敗\n"
+" **失敗** PPD ファイルを開ã‘ã¾ã›ã‚“ - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" 失敗\n"
+" **失敗** PPD ファイルを開ã‘ã¾ã›ã‚“ - %s (%d è¡Œ)。\n"
+
+msgid " PASS\n"
+msgstr " åˆæ ¼\n"
+
+msgid "#10 Envelope"
+msgstr "#10 å°ç­’"
+
+msgid "#11 Envelope"
+msgstr "#11 å°ç­’"
+
+msgid "#12 Envelope"
+msgstr "#12 å°ç­’"
+
+msgid "#14 Envelope"
+msgstr "#14 å°ç­’"
+
+msgid "#9 Envelope"
+msgstr "#9 å°ç­’"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f ãƒã‚¤ãƒˆ\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f ãƒã‚¤ãƒˆ\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f ミリメートル"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f to %.0f x %.0f ミリメートル"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f インãƒ"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f to %.2f x %.2f インãƒ"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s 㯠%s ã‹ã‚‰ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’å—ã‘付ã‘ã¦ã„ã¾ã™\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%s ã¯å¤‰æ›´ã§ãã¾ã›ã‚“。"
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s 㯠lpc ã® CUPS ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã¯å®Ÿè£…ã•ã‚Œã¦ã„ã¾ã›ã‚“。\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s ã¯æº–å‚™ãŒã§ãã¦ã„ã¾ã›ã‚“\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s ã¯æº–å‚™ãŒã§ãã¦ã„ã¾ã™\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s ã¯æº–å‚™ãŒã§ãã¦ãŠã‚Šå°åˆ·ã—ã¦ã„ã¾ã™\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s 㯠%s ã‹ã‚‰ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’å—ã‘付ã‘ã¦ã„ã¾ã›ã‚“\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s 㯠%s ã‹ã‚‰ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’å—ã‘付ã‘ã¦ã„ã¾ã™\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s 㯠%s ã‹ã‚‰ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’å—ã‘付ã‘ã¦ã„ã¾ã›ã‚“\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s:%-33.33s [ジョブ %d localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s ã«å¤±æ•—ã—ã¾ã—ãŸ: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: エラー - 利用å¯èƒ½ãªãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®å®›å…ˆãŒã‚ã‚Šã¾ã›ã‚“。\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: エラー - 優先度㯠1 ã‹ã‚‰ 100 ã®é–“ã§ã‚ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: エラー - ファイルãŒå¤šã™ãŽã¾ã™ - \"%s\"\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: エラー - \"%s\" ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“ - %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s: エラー - 標準入力ã‹ã‚‰ã‚­ãƒ¥ãƒ¼ã«ãƒ‡ãƒ¼ã‚¿ã‚’入力ã§ãã¾ã›ã‚“! - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: フィルター \"%s\" ã¯åˆ©ç”¨ã§ãã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: 無効ãªãƒ•ã‚£ãƒ«ã‚¿ãƒ¼æ–‡å­—列ã§ã™ \"%s\"\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: æ“作ã«å¤±æ•—ã—ã¾ã—ãŸ: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: サーãƒãƒ¼ã«æŽ¥ç¶šã§ãã¾ã›ã‚“\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: %sã‚’é–‹ã‘ã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: PPD ファイルを開ã‘ã¾ã›ã‚“: %s ã® %d 行目\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr "%s: PPD ファイルを開ã‘ã¾ã›ã‚“: %s ã® %d 行目\n"
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: エラー - 利用å¯èƒ½ãªãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®å®›å…ˆãŒã‚ã‚Šã¾ã›ã‚“。\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 インãƒ/秒"
+
+msgid "1.25x0.25\""
+msgstr "1.25x0.25インãƒ"
+
+msgid "1.25x2.25\""
+msgstr "1.25x2.25インãƒ"
+
+msgid "1.5 inch/sec."
+msgstr "1.5 インãƒ/秒"
+
+msgid "1.50x0.25\""
+msgstr "1.50x0.25インãƒ"
+
+msgid "1.50x0.50\""
+msgstr "1.50x0.50インãƒ"
+
+msgid "1.50x1.00\""
+msgstr "1.50x1.00インãƒ"
+
+msgid "1.50x2.00\""
+msgstr "1.50x2.00インãƒ"
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 インãƒ/秒"
+
+msgid "10 x 11\""
+msgstr "10 x 11インãƒ"
+
+msgid "10 x 13\""
+msgstr "10 x 13インãƒ"
+
+msgid "10 x 14\""
+msgstr "10 x 14インãƒ"
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 ミリメートル/秒"
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 インãƒ/秒"
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 インãƒ/秒"
+
+msgid "12 x 11\""
+msgstr "12 x 11インãƒ"
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 ミリメートル/秒"
+
+msgid "120x60dpi"
+msgstr "120x60dpi"
+
+msgid "120x72dpi"
+msgstr "120x72dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 ミリメートル/秒"
+
+msgid "15 x 11\""
+msgstr "15 x 11インãƒ"
+
+msgid "150 mm/sec."
+msgstr "150 ミリメートル/秒"
+
+msgid "150dpi"
+msgstr "150dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 インãƒ/秒"
+
+msgid "2-Sided Printing"
+msgstr "両é¢å°åˆ·"
+
+msgid "2.00x0.37\""
+msgstr "2.00x0.37インãƒ"
+
+msgid "2.00x0.50\""
+msgstr "2.00x0.50インãƒ"
+
+msgid "2.00x1.00\""
+msgstr "2.00x1.00インãƒ"
+
+msgid "2.00x1.25\""
+msgstr "2.00x1.25インãƒ"
+
+msgid "2.00x2.00\""
+msgstr "2.00x2.00インãƒ"
+
+msgid "2.00x3.00\""
+msgstr "2.00x3.00インãƒ"
+
+msgid "2.00x4.00\""
+msgstr "2.00x4.00インãƒ"
+
+msgid "2.00x5.50\""
+msgstr "2.00x5.50インãƒ"
+
+msgid "2.25x0.50\""
+msgstr "2.25x0.50インãƒ"
+
+msgid "2.25x1.25\""
+msgstr "2.25x1.25インãƒ"
+
+msgid "2.25x4.00\""
+msgstr "2.25x4.00インãƒ"
+
+msgid "2.25x5.50\""
+msgstr "2.25x5.50インãƒ"
+
+msgid "2.38x5.50\""
+msgstr "2.38x5.50インãƒ"
+
+msgid "2.5 inches/sec."
+msgstr "2.5 インãƒ/秒"
+
+msgid "2.50x1.00\""
+msgstr "2.50x1.00インãƒ"
+
+msgid "2.50x2.00\""
+msgstr "2.50x2.00インãƒ"
+
+msgid "2.75x1.25\""
+msgstr "2.75x1.25インãƒ"
+
+msgid "2.9 x 1\""
+msgstr "2.9 x 1インãƒ"
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 ミリメートル/秒"
+
+msgid "200 mm/sec."
+msgstr "200 ミリメートル/秒"
+
+msgid "203dpi"
+msgstr "203dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "24ピンシリーズ"
+
+msgid "240x72dpi"
+msgstr "240x72dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 ミリメートル/秒"
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 インãƒ/秒"
+
+msgid "3.00x1.00\""
+msgstr "3.00x1.00インãƒ"
+
+msgid "3.00x1.25\""
+msgstr "3.00x1.25インãƒ"
+
+msgid "3.00x2.00\""
+msgstr "3.00x2.00インãƒ"
+
+msgid "3.00x3.00\""
+msgstr "3.00x3.00インãƒ"
+
+msgid "3.00x5.00\""
+msgstr "3.00x5.00インãƒ"
+
+msgid "3.25x2.00\""
+msgstr "3.25x2.00インãƒ"
+
+msgid "3.25x5.00\""
+msgstr "3.25x5.00インãƒ"
+
+msgid "3.25x5.50\""
+msgstr "3.25x5.50インãƒ"
+
+msgid "3.25x5.83\""
+msgstr "3.25x5.83インãƒ"
+
+msgid "3.25x7.83\""
+msgstr "3.25x7.83インãƒ"
+
+msgid "3.5\" Disk"
+msgstr "3.5 インãƒDisk"
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "3.5インムDisk - 2 1/8 x 2 3/4インãƒ"
+
+msgid "3.50x1.00\""
+msgstr "3.50x1.00インãƒ"
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 ミリメートル/秒"
+
+msgid "300 mm/sec."
+msgstr "300 ミリメートル/秒"
+
+msgid "300dpi"
+msgstr "300dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360dpi"
+
+msgid "360x180dpi"
+msgstr "360x180dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 インãƒ/秒"
+
+msgid "4.00x1.00\""
+msgstr "4.00x1.00インãƒ"
+
+msgid "4.00x13.00\""
+msgstr "4.00x13.00インãƒ"
+
+msgid "4.00x2.00\""
+msgstr "4.00x2.00インãƒ"
+
+msgid "4.00x2.50\""
+msgstr "4.00x2.50インãƒ"
+
+msgid "4.00x3.00\""
+msgstr "4.00x3.00インãƒ"
+
+msgid "4.00x4.00\""
+msgstr "4.00x4.00インãƒ"
+
+msgid "4.00x5.00\""
+msgstr "4.00x5.00インãƒ"
+
+msgid "4.00x6.00\""
+msgstr "4.00x6.00インãƒ"
+
+msgid "4.00x6.50\""
+msgstr "4.00x6.50インãƒ"
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 ミリメートル/秒"
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 インãƒ/秒"
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 インãƒ/秒"
+
+msgid "6.00x1.00\""
+msgstr "6.00x1.00\""
+
+msgid "6.00x2.00\""
+msgstr "6.00x2.00\""
+
+msgid "6.00x3.00\""
+msgstr "6.00x3.00\""
+
+msgid "6.00x4.00\""
+msgstr "6.00x4.00\""
+
+msgid "6.00x5.00\""
+msgstr "6.00x5.00\""
+
+msgid "6.00x6.00\""
+msgstr "6.00x6.00\""
+
+msgid "6.00x6.50\""
+msgstr "6.00x6.50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/秒"
+
+msgid "600dpi"
+msgstr "600dpi"
+
+msgid "60dpi"
+msgstr "60dpi"
+
+msgid "60x720dpi"
+msgstr "60x720dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 インãƒ/秒"
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 インãƒ/秒"
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8.00x1.00\""
+
+msgid "8.00x2.00\""
+msgstr "8.00x2.00\""
+
+msgid "8.00x3.00\""
+msgstr "8.00x3.00\""
+
+msgid "8.00x4.00\""
+msgstr "8.00x4.00\""
+
+msgid "8.00x5.00\""
+msgstr "8.00x5.00\""
+
+msgid "8.00x6.00\""
+msgstr "8.00x6.00\""
+
+msgid "8.00x6.50\""
+msgstr "8.00x6.50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/秒"
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 インãƒ/秒"
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "9-Pin Series"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?無効ãªãƒ˜ãƒ«ãƒ—コマンドã§ã™\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (特大)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (特大)"
+
+msgid "A4 (Small)"
+msgstr "A4 (å°)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (特大)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "ジョブã®å—ã‘付ã‘"
+
+msgid "Accepted"
+msgstr "å—ã‘付ã‘ã¾ã—ãŸ"
+
+msgid "Add Class"
+msgstr "クラスã®è¿½åŠ "
+
+msgid "Add Printer"
+msgstr "プリンターã®è¿½åŠ "
+
+msgid "Add RSS Subscription"
+msgstr "RSS 購読を追加"
+
+msgid "Address"
+msgstr "アドレス"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "アドレス - 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "管ç†"
+
+msgid "Always"
+msgstr "常ã«æœ‰åŠ¹"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "アプリケーター"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "ä¸æ­£ãª NULL é€ä¿¡å…ˆãƒã‚¤ãƒ³ã‚¿ãƒ¼"
+
+msgid "Bad OpenGroup"
+msgstr "ä¸æ­£ãª OpenGroup"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "ä¸æ­£ãª OpenUI/JCLOpenUI"
+
+msgid "Bad OrderDependency"
+msgstr "ä¸æ­£ãª OrderDependency"
+
+msgid "Bad Request"
+msgstr "ä¸æ­£ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆ"
+
+msgid "Bad SNMP version number"
+msgstr "ä¸æ­£ãª SNMP ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç•ªå·"
+
+msgid "Bad UIConstraints"
+msgstr "ä¸æ­£ãª UIConstraints"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "%d ã¯ä¸æ­£ãªã‚³ãƒ”ー値ã§ã™ã€‚"
+
+msgid "Bad custom parameter"
+msgstr "ä¸æ­£ãªã‚«ã‚¹ã‚¿ãƒ ãƒ‘ラメーター"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "ä¸æ­£ãªãƒ•ã‚©ãƒ³ãƒˆå±žæ€§: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "%d ã¯ä¸æ­£ãª number-up 値ã§ã™ã€‚"
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "%d-%d ã¯ä¸æ­£ãª page-ranges 値ã§ã™ã€‚"
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "ãƒãƒŠãƒ¼"
+
+msgid "Billing Information: "
+msgstr "課金情報: "
+
+msgid "Bond Paper"
+msgstr "ボンド紙"
+
+msgid "C0 Envelope"
+msgstr "C0 å°ç­’"
+
+msgid "C1 Envelope"
+msgstr "C1 å°ç­’"
+
+msgid "C2 Envelope"
+msgstr "C2 å°ç­’"
+
+msgid "C3 Envelope"
+msgstr "C3 å°ç­’"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "C4 å°ç­’"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "C5 å°ç­’"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "C6 å°ç­’"
+
+msgid "C65 Envelope"
+msgstr "C65 å°ç­’"
+
+msgid "C7 Envelope"
+msgstr "C7 å°ç­’"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "CPCL ラベルプリンター"
+
+msgid "Cancel RSS Subscription"
+msgstr "RSS 購読をキャンセル"
+
+msgid "Change Settings"
+msgstr "設定ã®å¤‰æ›´"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "å°ç­’ 長形3å·"
+
+msgid "Chou4 Envelope"
+msgstr "å°ç­’ 長形4å·"
+
+msgid "Classes"
+msgstr "クラス"
+
+msgid "Clean Print Heads"
+msgstr "プリントヘッドクリーニング"
+
+msgid "Color"
+msgstr "カラー"
+
+msgid "Color Mode"
+msgstr "カラーモード"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"コマンドã¯çŸ­ç¸®ã§ãã¾ã™ã€‚ コマンド:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "コミュニティåã®é•·ã•ãŒä¸å®š"
+
+msgid "Continue"
+msgstr "継続"
+
+msgid "Continuous"
+msgstr "連続"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "ジョブ作æˆ"
+
+msgid "Created On: "
+msgstr "ジョブ作æˆæ—¥: "
+
+msgid "Custom"
+msgstr "カスタム"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "カット"
+
+msgid "Cutter"
+msgstr "カッター"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "DL å°ç­’"
+
+msgid "Dark"
+msgstr "濃ã„"
+
+msgid "Darkness"
+msgstr "濃ã•"
+
+msgid "Delete Class"
+msgstr "クラスã®å‰Šé™¤"
+
+msgid "Delete Printer"
+msgstr "プリンターã®å‰Šé™¤"
+
+msgid "Description: "
+msgstr "説明: "
+
+msgid "DeskJet Series"
+msgstr "DeskJet Series"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "宛先 \"%s\" ã¯ã‚¸ãƒ§ãƒ–ã‚’å—ã‘付ã‘ã¦ã„ã¾ã›ã‚“。"
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"デãƒã‚¤ã‚¹: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "感熱紙"
+
+msgid "Disabled"
+msgstr "無効"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "ドキュメント %d ãŒã‚¸ãƒ§ãƒ– %d ã«è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"
+
+msgid "Double Postcard"
+msgstr "往復ã¯ãŒã"
+
+msgid "Driver Name: "
+msgstr "ドライãƒãƒ¼å: "
+
+msgid "Driver Version: "
+msgstr "ドライãƒãƒ¼ãƒãƒ¼ã‚¸ãƒ§ãƒ³: "
+
+msgid "Duplexer"
+msgstr "両é¢ã‚ªãƒ—ション"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: ページ情報ã®ãƒ¡ãƒ¢ãƒªãƒ¼å‰²ã‚Šå½“ã¦ãŒã§ãã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: ページアレイã®ãƒ¡ãƒ¢ãƒªãƒ¼å‰²ã‚Šå½“ã¦ãŒã§ãã¾ã›ã‚“: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "EPL1 ラベルプリンター"
+
+msgid "EPL2 Label Printer"
+msgstr "EPL2 ラベルプリンター"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr "ERROR: %s ジョブID ユーザー タイトル コピー数 オプション [ファイル]\n"
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: ä¸æ­£ãª charset ファイル %s ã§ã™\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: ä¸æ­£ãª charset タイプ %s ã§ã™\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: ä¸æ­£ãªãƒ•ã‚©ãƒ³ãƒˆè¨˜è¿°è¡Œ: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: ä¸æ­£ãª ãƒ†ã‚­ã‚¹ãƒˆæ–¹å‘ %s ã§ã™\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: ä¸æ­£ãª テキスト幅 %s ã§ã™\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: エラー %d PAPSendData request ã®é€ä¿¡: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: charset ファイル %s ã«ãƒ•ã‚©ãƒ³ãƒˆãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: プリンターãŒå¿œç­”ã—ã¦ã„ã¾ã›ã‚“\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: プリンター㌠想定外㮠EOF ã‚’é€ä¿¡ã—ã¾ã—ãŸ\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr ""
+"ERROR: リモートホストãŒã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ãƒ•ã‚¡ã‚¤ãƒ«ã‚’å—ã‘付ã‘ã¾ã›ã‚“ã§ã—㟠(%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: リモートホストãŒãƒ‡ãƒ¼ã‚¿ãƒ•ã‚¡ã‚¤ãƒ«ã‚’å—ã‘付ã‘ã¾ã›ã‚“ã§ã—㟠(%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr "ERROR: プリンターã¸ã®ãƒ‡ãƒ¼ã‚¿é€ä¿¡ä¸­ã«ã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: ファイル %d をジョブã«è¿½åŠ ã§ãã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: ジョブ %d をキャンセルã§ãã¾ã›ã‚“: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: PDF ファイルをコピーã§ãã¾ã›ã‚“"
+
+msgid "ERROR: Unable to create pipe"
+msgstr "ERROR: pipe を生æˆã§ãã¾ã›ã‚“"
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: ソケットを作æˆã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr "ERROR: テンãƒãƒ©ãƒªãƒ¼ã®åœ§ç¸®ãƒ—リントファイルを作æˆã§ãã¾ã›ã‚“: %s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: テンãƒãƒ©ãƒªãƒ¼ãƒ•ã‚¡ã‚¤ãƒ«ã‚’作æˆã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: pictwpstops を実行ã§ãã¾ã›ã‚“: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: gs プログラムを実行ã§ãã¾ã›ã‚“"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: pdftops プログラムを実行ã§ãã¾ã›ã‚“"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr "ERROR: pstops プログラムを実行ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: pictwpstops をフォークã§ãã¾ã›ã‚“: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: PAP リクエストをå–å¾—ã§ãã¾ã›ã‚“"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: PAP レスãƒãƒ³ã‚¹ã‚’å–å¾—ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr "ERROR: プリンター \"%s\" ã® PPD ファイルをå–å¾—ã§ãã¾ã›ã‚“ - %s\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: デフォルト㮠AppleTalk ゾーンをå–å¾—ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: PAP レスãƒãƒ³ã‚¹ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: AppleTalk プリンターãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: AppleTalk アドレスを作æˆã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: \"%s\" ã‚’é–‹ã‘ã¾ã›ã‚“ - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: %s ã‚’é–‹ã‘ã¾ã›ã‚“: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: ãƒãƒŠãƒ¼ãƒ•ã‚¡ã‚¤ãƒ« \"%s\" ã‚’é–‹ã‘ã¾ã›ã‚“ - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: デãƒã‚¤ã‚¹ãƒ•ã‚¡ã‚¤ãƒ« \"%s\" ã‚’é–‹ã‘ã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: ファイル \"%s\" ã‚’é–‹ã‘ã¾ã›ã‚“ - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: ファイル \"%s\" ã‚’é–‹ã‘ã¾ã›ã‚“: %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: プリントファイル \"%s\" ã‚’é–‹ã‘ã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: プリントファイル %s ã‚’é–‹ã‘ã¾ã›ã‚“ - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: プリントファイル %s ã‚’é–‹ã‘ã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr "ERROR: ラスターファイル %s ã‚’é–‹ã‘ã¾ã›ã‚“\n"
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr "ERROR: テンãƒãƒ©ãƒªãƒ¼ã®åœ§ç¸®ãƒ—リントファイルを開ã‘ã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: プリントデータを読ã¿è¾¼ã‚ã¾ã›ã‚“"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: ãƒãƒ¼ãƒˆã‚’予約ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: ファイルã§ã®ã‚ªãƒ•ã‚»ãƒƒãƒˆ %ld ã¸ã‚·ãƒ¼ã‚¯ã§ãã¾ã›ã‚“ - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: ファイルã§ã®ã‚ªãƒ•ã‚»ãƒƒãƒˆ %lld ã¸ã‚·ãƒ¼ã‚¯ã§ãã¾ã›ã‚“ - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: LPD コマンドをé€ä¿¡ã§ãã¾ã›ã‚“"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: PAP tickle è¦æ±‚ã‚’é€ä¿¡ã§ãã¾ã›ã‚“"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: PAP ã®åˆæœŸãƒ‡ãƒ¼ã‚¿é€ä¿¡è¦æ±‚ã‚’é€ä¿¡ã§ãã¾ã›ã‚“"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: プリントファイルをプリンターã¸é€ä¿¡ã§ãã¾ã›ã‚“"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: 最後㮠NUL をプリンターã¸é€ä¿¡ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: pictwpstops ã‚’å¾…ã¤ã“ã¨ãŒã§ãã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: %d ãƒã‚¤ãƒˆã‚’ \"%s\" ã«æ›¸ãè¾¼ã‚ã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: コントロールファイルを書ãè¾¼ã‚ã¾ã›ã‚“"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: プリントデータを書ãè¾¼ã‚ã¾ã›ã‚“"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: プリントデータを書ãè¾¼ã‚ã¾ã›ã‚“: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr "ERROR: éžåœ§ç¸®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆãƒ‡ãƒ¼ã‚¿ã‚’書ãè¾¼ã‚ã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: \"%s\" ã¯æœªçŸ¥ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚ªãƒ¼ãƒ€ãƒ¼ã§ã™\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: \"%c\" ã¯æœªçŸ¥ã®æ›¸å¼æ–‡å­—ã§ã™\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: \"%s\" ã¯æœªçŸ¥ã®ãƒ—リントモードã§ã™\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: select() ãŒå¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: プリントファイルã®çŠ¶æ…‹ã‚’å–å¾—ã§ãã¾ã›ã‚“"
+
+msgid "Edit Configuration File"
+msgstr "設定ファイルã®ç·¨é›†"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "終了ãƒãƒŠãƒ¼"
+
+msgid "English"
+msgstr "Japanese"
+
+msgid "Enter old password:"
+msgstr "å¤ã„パスワードを入力:"
+
+msgid "Enter password again:"
+msgstr "パスワードをå†åº¦å…¥åŠ›:"
+
+msgid "Enter password:"
+msgstr "パスワードを入力:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"ã“ã®ãƒšãƒ¼ã‚¸ã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ãŸã‚ã«ã€ã‚ãªãŸã®ãƒ¦ãƒ¼ã‚¶ãƒ¼åã¨ãƒ‘スワードã€ã‚ã‚‹ã„㯠"
+"root ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼åã¨ãƒ‘スワードを入力ã—ã¦ãã ã•ã„。Kerberos èªè¨¼ã‚’使用ã—ã¦ã„ã‚‹"
+"å ´åˆã€æœ‰åŠ¹ãª Kerberos ãƒã‚±ãƒƒãƒˆãŒã‚ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。"
+
+msgid "Envelope Feed"
+msgstr "å°ç­’フィード"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "エラーãƒãƒªã‚·ãƒ¼"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "10 ラベルã”ã¨"
+
+msgid "Every 2 Labels"
+msgstr "2 ラベルã”ã¨"
+
+msgid "Every 3 Labels"
+msgstr "3 ラベルã”ã¨"
+
+msgid "Every 4 Labels"
+msgstr "4 ラベルã”ã¨"
+
+msgid "Every 5 Labels"
+msgstr "5 ラベルã”ã¨"
+
+msgid "Every 6 Labels"
+msgstr "6 ラベルã”ã¨"
+
+msgid "Every 7 Labels"
+msgstr "7 ラベルã”ã¨"
+
+msgid "Every 8 Labels"
+msgstr "8 ラベルã”ã¨"
+
+msgid "Every 9 Labels"
+msgstr "9 ラベルã”ã¨"
+
+msgid "Every Label"
+msgstr "ã™ã¹ã¦ã®ãƒ©ãƒ™ãƒ«"
+
+msgid "Expectation Failed"
+msgstr "Expectation Failed"
+
+msgid "Export Printers to Samba"
+msgstr "Samba ã¸ãƒ—リンターをエクスãƒãƒ¼ãƒˆ"
+
+msgid "FAIL\n"
+msgstr "失敗\n"
+
+msgid "File Folder"
+msgstr "ファイルフォルダー"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "ファイルフォルダー - 9/16 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"ファイルデãƒã‚¤ã‚¹ URI ã¯ç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™! 有効ã«ã™ã‚‹ã«ã¯ã€\"%s/cupsd.conf\" "
+"ã® FileDevice ディレクティブをå‚ç…§ã—ã¦ãã ã•ã„。"
+
+msgid "Folio"
+msgstr "フォリオ"
+
+msgid "Forbidden"
+msgstr "Forbidden"
+
+msgid "General"
+msgstr "一般"
+
+msgid "Generic"
+msgstr "汎用"
+
+msgid "German FanFold"
+msgstr "German FanFold"
+
+msgid "German FanFold Legal"
+msgstr "German FanFold Legal"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU ã¯ä¸ç¢ºå®šã®é•·ã•ã‚’使用ã—ã¦ã„ã¾ã™"
+
+msgid "Glossy Paper"
+msgstr "光沢紙"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "グレースケール"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Hanging Folder"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Hanging Folder - 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk ãŒã‚·ã‚¹ãƒ†ãƒ ãƒ—レファレンスã§ç„¡åŠ¹ã«ã•ã‚Œã¦ã„ã¾ã™\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk ãŒã‚·ã‚¹ãƒ†ãƒ ãƒ—レファレンスã§ç„¡åŠ¹ã«ã•ã‚Œã¦ã„ã¾ã™ã€‚\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: プリントジョブをキャンセルã—ã¦ã„ã¾ã™...\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: プリンターã«æŽ¥ç¶šã—ã¾ã—ãŸ...\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: プリンターã«æŽ¥ç¶šä¸­...\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: コントロールファイルãŒæ­£å¸¸ã«é€ä¿¡ã•ã‚Œã¾ã—ãŸ\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr "INFO: å°åˆ·ãƒ‡ãƒ¼ã‚¿ã‚’コピーã—ã¦ã„ã¾ã™..."
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: データファイルãŒæ­£å¸¸ã«é€ä¿¡ã•ã‚Œã¾ã—ãŸ\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr "INFO: ページ %d を終了...\n"
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: ページ %d をフォーマット中...\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: イメージファイルをロード中...\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: プリンターを探ã—ã¦ã„ã¾ã™...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: コãƒã‚¯ã‚·ãƒ§ãƒ³ã‚’é–‹ã„ã¦ã„ã¾ã™\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr ""
+"INFO: プリントファイルをé€ä¿¡ã—ã€ãƒ—リンターãŒä½œæ¥­ã‚’完了ã™ã‚‹ã®ã‚’å¾…ã£ã¦ã„ã¾"
+"ã™...\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: プリンターãŒãƒ“ジー状態ã§ã™ã€‚10 秒後ã«å†è©¦è¡Œã—ã¾ã™...\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: プリンターãŒãƒ“ジー状態ã§ã™ã€‚30 秒後ã«å†è©¦è¡Œã—ã¾ã™...\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: プリンターãŒãƒ“ジー状態ã§ã™ã€‚5 秒後ã«å†è©¦è¡Œã—ã¾ã™...\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr ""
+"INFO: プリンター㌠IPP/%d.%d をサãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“。IPP/1.0 を試ã—ã¾ã™...\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: プリンターãŒãƒ“ジー状態ã§ã™ã€‚5 秒後ã«å†è©¦è¡Œã—ã¾ã™...\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: プリンターã¯ç¾åœ¨ã‚ªãƒ•ãƒ©ã‚¤ãƒ³ã§ã™ã€‚\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: プリンターã¯ç¾åœ¨ã‚ªãƒ•ãƒ©ã‚¤ãƒ³ã§ã™ã€‚\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: プリンターã¯ç¾åœ¨ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ã§ã™ã€‚\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: プリンターã¯ã‚ªãƒ•ãƒ©ã‚¤ãƒ³ã§ã™ã€‚\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: プリンターã«æŽ¥ç¶šã§ãã¾ã›ã‚“。30 秒後ã«å†è©¦è¡Œã—ã¾ã™...\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: ページ %d をプリント中ã€%d%% 完了ã—ã¾ã—ãŸ...\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: ページ %d をプリント中...\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: プリントã®æº–å‚™ãŒã§ãã¦ã„ã¾ã™\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: コントロールファイルをé€ä¿¡ä¸­ (%lu ãƒã‚¤ãƒˆ)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: コントロールファイルをé€ä¿¡ä¸­ (%u ãƒã‚¤ãƒˆ)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: データをé€ä¿¡ä¸­\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: データファイルをé€ä¿¡ä¸­ (%ld ãƒã‚¤ãƒˆ)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: データファイルをé€ä¿¡ä¸­ (%lld ãƒã‚¤ãƒˆ)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: プリントデータをé€ä¿¡ä¸­...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: プリントファイルをé€ä¿¡ã€%ld ãƒã‚¤ãƒˆ...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: プリントファイルをé€ä¿¡ã€%lld ãƒã‚¤ãƒˆ...\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: LPR ジョブをスプール中ã€%.0f%% 完了ã—ã¾ã—ãŸ...\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr "INFO: ページ %d を開始...\n"
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: プリンターã¨äº¤ä¿¡ã§ãã¾ã›ã‚“。クラス内ã®æ¬¡ã®ãƒ—リンターã«ã‚­ãƒ¥ãƒ¼ã—ã¾ã™...\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: デフォルト㮠AppleTalk ゾーン \"%s\" を使ã„ã¾ã™\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: ジョブãŒå®Œäº†ã™ã‚‹ã®ã‚’å¾…ã£ã¦ã„ã¾ã™...\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: プリンターãŒä½¿ç”¨å¯èƒ½ã«ãªã‚‹ã®ã‚’å¾…ã£ã¦ã„ã¾ã™...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "ISO B4 å°ç­’"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (特大)"
+
+msgid "ISO B5 Envelope"
+msgstr "ISO B5 å°ç­’"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "ISO B6 å°ç­’"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "ä¸æ­£ãªåˆ¶å¾¡æ–‡å­—"
+
+msgid "Illegal main keyword string"
+msgstr "ä¸æ­£ãªãƒ¡ã‚¤ãƒ³ã‚­ãƒ¼ãƒ¯ãƒ¼ãƒ‰æ–‡å­—列"
+
+msgid "Illegal option keyword string"
+msgstr "ä¸æ­£ãªã‚ªãƒ—ションキーワード文字列"
+
+msgid "Illegal translation string"
+msgstr "ä¸æ­£ãªç¿»è¨³æ–‡å­—列"
+
+msgid "Illegal whitespace character"
+msgstr "ä¸æ­£ãªç©ºç™½æ–‡å­—"
+
+msgid "Installable Options"
+msgstr "インストールå¯èƒ½ã‚ªãƒ—ション"
+
+msgid "Installed"
+msgstr "インストールã•ã‚Œã¦ã„ã¾ã™"
+
+msgid "IntelliBar Label Printer"
+msgstr "IntelliBar ラベルプリンター"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr "サーãƒãƒ¼å†…部エラー"
+
+msgid "Internal error"
+msgstr "内部エラー"
+
+msgid "Internet Postage 2-Part"
+msgstr "Internet Postage 2-Part"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "Internet Postage 3-Part"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Internet Postage 3-Part - 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "インターãƒãƒƒãƒˆå°åˆ·ãƒ—ロトコル"
+
+msgid "Invite Envelope"
+msgstr "招待状å°ç­’"
+
+msgid "Italian Envelope"
+msgstr "イタリアå°ç­’"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "ã‚¸ãƒ§ãƒ–ç•ªå· %d ã¯ã™ã§ã«ä¸­æ–­ã•ã‚Œã¦ã„ã¾ã™ - キャンセルã§ãã¾ã›ã‚“。"
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "ã‚¸ãƒ§ãƒ–ç•ªå· %d ã¯ã™ã§ã«ã‚­ãƒ£ãƒ³ã‚»ãƒ«ã•ã‚Œã¦ã„ã¾ã™ - キャンセルã§ãã¾ã›ã‚“。"
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "ã‚¸ãƒ§ãƒ–ç•ªå· %d ã¯ã™ã§ã«å®Œäº†ã—ã¦ã„ã¾ã™ - キャンセルã§ãã¾ã›ã‚“。"
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "ジョブ完了"
+
+msgid "Job Created"
+msgstr "ジョブ作æˆ"
+
+msgid "Job ID: "
+msgstr "ジョブ ID: "
+
+msgid "Job Options Changed"
+msgstr "ジョブオプション変更"
+
+msgid "Job Stopped"
+msgstr "ジョブ中止"
+
+msgid "Job UUID: "
+msgstr "ジョブ UUID: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "ジョブã¯å®Œäº†ã—変更ã§ãã¾ã›ã‚“。"
+
+msgid "Job operation failed:"
+msgstr "ジョブæ“作失敗:"
+
+msgid "Job state cannot be changed."
+msgstr "ジョブã®çŠ¶æ…‹ã‚’変更ã§ãã¾ã›ã‚“。"
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "ジョブ"
+
+msgid "Kaku2 Envelope"
+msgstr "角 2 å°ç­’"
+
+msgid "Kaku3 Envelope"
+msgstr "角 3 å°ç­’"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "LPD/LPR ホストã¾ãŸã¯ãƒ—リンター"
+
+msgid "Label Printer"
+msgstr "ラベルプリンター"
+
+msgid "Label Top"
+msgstr "ラベルトップ"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "ラージアドレス"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "ラージアドレス - 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet Series PCL 4/5"
+
+msgid "Light"
+msgstr "è–„ã„"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "1 è¡ŒãŒæœ€å¤§å€¤ (255 文字) を超ãˆã¦ã„ã¾ã™"
+
+msgid "List Available Printers"
+msgstr "使用å¯èƒ½ãªãƒ—リンターをリスト化"
+
+msgid "Location: "
+msgstr "場所: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "長辺給紙 (縦å‘ã)"
+
+msgid "Make and Model: "
+msgstr "プリンタードライãƒãƒ¼: "
+
+msgid "Manual Feed"
+msgstr "手差ã—"
+
+msgid "Media Dimensions: "
+msgstr "用紙ã®å¤§ãã•: "
+
+msgid "Media Limits: "
+msgstr "用紙ã®å°å­—領域: "
+
+msgid "Media Name: "
+msgstr "用紙å:"
+
+msgid "Media Size"
+msgstr "用紙サイズ"
+
+msgid "Media Source"
+msgstr "給紙"
+
+msgid "Media Tracking"
+msgstr "用紙ã®çµŒè·¯"
+
+msgid "Media Type"
+msgstr "用紙種類"
+
+msgid "Medium"
+msgstr "紙質"
+
+msgid "Memory allocation error"
+msgstr "メモリ割り当ã¦ã‚¨ãƒ©ãƒ¼"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "PPD-Adobe-4.x ヘッダãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "Missing asterisk in column 1"
+msgstr "1 列目ã«ã‚¢ã‚¹ã‚¿ãƒªã‚¹ã‚¯ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "値文字列ãŒã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"モデル: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "クラスã®å¤‰æ›´"
+
+msgid "Modify Printer"
+msgstr "プリンターã®å¤‰æ›´"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Monarch å°ç­’"
+
+msgid "Move All Jobs"
+msgstr "ã™ã¹ã¦ã®ã‚¸ãƒ§ãƒ–ã®ç§»å‹•"
+
+msgid "Move Job"
+msgstr "ジョブã®ç§»å‹•"
+
+msgid "Moved Permanently"
+msgstr "別ã®å ´æ‰€ã¸ç§»å‹•ã—ã¾ã—ãŸ"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: プリントファイルをå—ã‘付ã‘ã¾ã—㟠- ジョブ ID %d。\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: プリントファイルをå—ã‘付ã‘ã¾ã—㟠- ジョブ ID ä¸æ˜Žã€‚\n"
+
+msgid "NULL PPD file pointer"
+msgstr "PPD ファイルãƒã‚¤ãƒ³ã‚¿ãƒ¼ãŒ NULL ã§ã™"
+
+msgid "Name OID uses indefinite length"
+msgstr "OID åã¯é™å®šçš„ãªé•·ã•ã‚’使用ã—ã¾ã™"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Never"
+
+msgid "New Stylus Color Series"
+msgstr "New Stylus Color シリーズ"
+
+msgid "New Stylus Photo Series"
+msgstr "New Stylus Photo シリーズ"
+
+msgid "No"
+msgstr "ã„ã„ãˆ"
+
+msgid "No Content"
+msgstr "中身ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "VarBind SEQUENCE ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "アクティブãªæŽ¥ç¶šã¯ã‚ã‚Šã¾ã›ã‚“"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "コミュニティåãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "No default printer"
+msgstr "デフォルトã®ãƒ—リンターã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "No destinations added."
+msgstr "追加ã•ã‚ŒãŸå®›å…ˆã¯ã‚ã‚Šã¾ã›ã‚“"
+
+msgid "No error-index"
+msgstr "エラーインデックスãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "No error-status"
+msgstr "エラーステータスãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "OID åãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "リクエストID ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "サブスクリプションãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "variable-bindings SEQUENCE ãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "No version number"
+msgstr "ãƒãƒ¼ã‚¸ãƒ§ãƒ³åãŒã‚ã‚Šã¾ã›ã‚“"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "éžé€£ç¶šã§ã™ (Mark sensing)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "éžé€£ç¶šã§ã™ (Web sensing)"
+
+msgid "Normal"
+msgstr "標準"
+
+msgid "Not Found"
+msgstr "見ã¤ã‹ã‚Šã¾ã›ã‚“"
+
+msgid "Not Implemented"
+msgstr "実装ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "Not Installed"
+msgstr "インストールã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "Not Modified"
+msgstr "変更ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "Not Supported"
+msgstr "サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "Not allowed to print."
+msgstr "å°åˆ·ãŒè¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“。"
+
+msgid "Note"
+msgstr "注æ„"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Off (1-Sided)"
+msgstr "Off (片é¢)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "オンラインヘルプ"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "%s ã®ã‚ªãƒ¼ãƒ—ンã«å¤±æ•—ã—ã¾ã—ãŸ: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup ã®å‰ã«ã¾ãš CloseGroup ãŒå¿…è¦ã§ã™"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI ã®å‰ã«ã¾ãš CloseUI/JCLCloseUI ãŒå¿…è¦ã§ã™"
+
+msgid "Operation Policy"
+msgstr "æ“作ãƒãƒªã‚·ãƒ¼"
+
+msgid "Options Installed"
+msgstr "インストールã•ã‚ŒãŸã‚ªãƒ—ション"
+
+msgid "Options: "
+msgstr "オプション:"
+
+msgid "Output Mode"
+msgstr "出力モード"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "プリンター %s ã®å‡ºåŠ›ã¯ %s ã«é€ã‚‰ã‚Œã¾ã™\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr "プリンター %s ã®å‡ºåŠ›ã¯ã€ãƒªãƒ¢ãƒ¼ãƒˆãƒ—リンター %s (%s 上) ã«é€ã‚‰ã‚Œã¾ã™\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "プリンター %s/%s ã®å‡ºåŠ›ã¯ %s ã«é€ã‚‰ã‚Œã¾ã™\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr ""
+"プリンター %s/%s ã®å‡ºåŠ›ã¯ã€ãƒªãƒ¢ãƒ¼ãƒˆãƒ—リンター %s (%s 上) ã«é€ã‚‰ã‚Œã¾ã™\n"
+
+msgid "PASS\n"
+msgstr "åˆæ ¼\n"
+
+msgid "PCL Laser Printer"
+msgstr "PCL レーザープリンター"
+
+msgid "PRC1 Envelope"
+msgstr "PRC1 å°ç­’"
+
+msgid "PRC10 Envelope"
+msgstr "PRC10 å°ç­’"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "PRC2 å°ç­’"
+
+msgid "PRC3 Envelope"
+msgstr "PRC3 å°ç­’"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (特大)"
+
+msgid "PRC4 Envelope"
+msgstr "PRC4 å°ç­’"
+
+msgid "PRC5 Envelope"
+msgstr "PRC5 å°ç­’"
+
+msgid "PRC6 Envelope"
+msgstr "PRC6 å°ç­’"
+
+msgid "PRC7 Envelope"
+msgstr "PRC7 å°ç­’"
+
+msgid "PRC8 Envelope"
+msgstr "PRC8 å°ç­’"
+
+msgid "PRC9 Envelope"
+msgstr "PRC9 å°ç­’"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "パケット㌠Get-Response-PDU ã‚’å«ã‚“ã§ã„ã¾ã›ã‚“"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "パケット㌠SEQUENCE ã‹ã‚‰å§‹ã¾ã‚Šã¾ã›ã‚“"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "%s ã®ãƒ‘スワード (%s 上)? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "%s ã®ãƒ‘スワード (SAMBA 経由㧠%s ã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã®ã«å¿…è¦):"
+
+msgid "Pause Class"
+msgstr "クラスã®ä¼‘æ­¢"
+
+msgid "Pause Printer"
+msgstr "プリンターã®ä¼‘æ­¢"
+
+msgid "Peel-Off"
+msgstr "Peel-Off"
+
+msgid "Personal Envelope"
+msgstr "パーソナルå°ç­’"
+
+msgid "Photo"
+msgstr "写真"
+
+msgid "Photo Labels"
+msgstr "写真ラベル"
+
+msgid "Plain Paper"
+msgstr "普通紙"
+
+msgid "Policies"
+msgstr "ãƒãƒªã‚·ãƒ¼"
+
+msgid "Port Monitor"
+msgstr "ãƒãƒ¼ãƒˆãƒ¢ãƒ‹ã‚¿ãƒ¼"
+
+msgid "PostScript Printer"
+msgstr "ãƒã‚¹ãƒˆã‚¹ã‚¯ãƒªãƒ—トプリンター"
+
+msgid "Postcard"
+msgstr "ãƒã‚¬ã‚­"
+
+msgid "Print Density"
+msgstr "å°åˆ·å¯†åº¦"
+
+msgid "Print Job:"
+msgstr "ジョブã®å°åˆ·:"
+
+msgid "Print Mode"
+msgstr "å°åˆ·ãƒ¢ãƒ¼ãƒ‰"
+
+msgid "Print Rate"
+msgstr "å°åˆ·ãƒ¬ãƒ¼ãƒˆ"
+
+msgid "Print Self-Test Page"
+msgstr "自己テストページã®å°åˆ·"
+
+msgid "Print Speed"
+msgstr "å°åˆ·é€Ÿåº¦"
+
+msgid "Print Test Page"
+msgstr "テストページã®å°åˆ·"
+
+msgid "Print and Cut"
+msgstr "プリントã—ã¦ã‚«ãƒƒãƒˆ"
+
+msgid "Print and Tear"
+msgstr "プリントã—ã¦åˆ‡ã‚Šå–ã‚‹"
+
+msgid "Printed For: "
+msgstr "プリント対象:"
+
+msgid "Printed From: "
+msgstr "プリント元:"
+
+msgid "Printed On: "
+msgstr "プリント先:"
+
+msgid "Printer Added"
+msgstr "追加ã•ã‚ŒãŸãƒ—リンター"
+
+msgid "Printer Default"
+msgstr "デフォルトã®ãƒ—リンター"
+
+msgid "Printer Deleted"
+msgstr "削除ã•ã‚ŒãŸãƒ—リンター"
+
+msgid "Printer Modified"
+msgstr "変更ã•ã‚ŒãŸãƒ—リンター"
+
+msgid "Printer Name: "
+msgstr "プリンターå:"
+
+msgid "Printer Paused"
+msgstr "プリンターã®ä¼‘æ­¢"
+
+msgid "Printer Settings"
+msgstr "プリンター設定"
+
+msgid "Printer:"
+msgstr "プリンター:"
+
+msgid "Printers"
+msgstr "プリンター"
+
+msgid "Purge Jobs"
+msgstr "ジョブã®å‰Šé™¤"
+
+msgid "Quarto"
+msgstr "Quarto"
+
+msgid "Quota limit reached."
+msgstr "Quota ã®åˆ¶é™ã«é”ã—ã¾ã—ãŸã€‚"
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr "ランク 所有者 ジョブ ファイル åˆè¨ˆã‚µã‚¤ã‚º\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"ランク 所有者 優先 ジョブ ファイル åˆè¨ˆã‚µã‚¤ã‚º\n"
+
+msgid "Reject Jobs"
+msgstr "ジョブã®æ‹’å¦"
+
+msgid "Reprint After Error"
+msgstr "エラー後ã®å†å°åˆ·"
+
+msgid "Request Entity Too Large"
+msgstr "è¦æ±‚ã™ã‚‹ã‚¨ãƒ³ãƒ†ã‚£ãƒ†ã‚£ãŒå¤§ãã™ãŽã¾ã™"
+
+msgid "Resolution"
+msgstr "解åƒåº¦"
+
+msgid "Resume Class"
+msgstr "クラスをå†é–‹ã™ã‚‹"
+
+msgid "Resume Printer"
+msgstr "プリンターをå†é–‹ã™ã‚‹"
+
+msgid "Return Address"
+msgstr "アドレスを戻ã™"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "アドレスを戻㙠ー 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "戻る"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "コマンドを実行中: %s %s -N -A %s -c '%s'\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE ã¯ä¸å®šé•·ã‚’使用ã—ã¦ã„ã¾ã™"
+
+msgid "See Other"
+msgstr "残りを見ã¦ãã ã•ã„"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "シリアルãƒãƒ¼ãƒˆ #%d"
+
+msgid "Server Restarted"
+msgstr "å†èµ·å‹•ã•ã‚ŒãŸã‚µãƒ¼ãƒãƒ¼"
+
+msgid "Server Security Auditing"
+msgstr "サーãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãƒ¼ãƒã‚§ãƒƒã‚¯"
+
+msgid "Server Started"
+msgstr "開始ã•ã‚ŒãŸã‚µãƒ¼ãƒãƒ¼"
+
+msgid "Server Stopped"
+msgstr "åœæ­¢ã•ã‚ŒãŸã‚µãƒ¼ãƒãƒ¼"
+
+msgid "Service Unavailable"
+msgstr "利用ã§ããªã„サービス"
+
+msgid "Set Allowed Users"
+msgstr "許å¯ã™ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®è¨­å®š"
+
+msgid "Set As Server Default"
+msgstr "サーãƒãƒ¼ã‚’デフォルトã«è¨­å®š"
+
+msgid "Set Class Options"
+msgstr "クラスオプションを設定"
+
+msgid "Set Printer Options"
+msgstr "プリンターオプションã®è¨­å®š"
+
+msgid "Set Publishing"
+msgstr "公開ã®è¨­å®š"
+
+msgid "Shipping Address"
+msgstr "発é€ã‚¢ãƒ‰ãƒ¬ã‚¹"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "発é€ã‚¢ãƒ‰ãƒ¬ã‚¹ - 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "短辺 (横原稿)"
+
+msgid "Special Paper"
+msgstr "スペシャルペーパー"
+
+msgid "Standard"
+msgstr "標準"
+
+msgid "Starting Banner"
+msgstr "開始ãƒãƒŠãƒ¼"
+
+msgid "Statement"
+msgstr "記述"
+
+msgid "Stylus Color Series"
+msgstr "Stylus Color シリーズ"
+
+msgid "Stylus Photo Series"
+msgstr "Stylus Photo シリーズ"
+
+msgid "Super A"
+msgstr "スーパー A"
+
+msgid "Super B"
+msgstr "スーパー B"
+
+msgid "Super B/A3"
+msgstr "スーパー B/A3"
+
+msgid "Switching Protocols"
+msgstr "プロトコルã®å¤‰æ›´"
+
+msgid "Tabloid"
+msgstr "タブロイド"
+
+msgid "Tabloid (Oversize)"
+msgstr "タブロイド (特大)"
+
+msgid "Tear"
+msgstr "Tear"
+
+msgid "Tear-Off"
+msgstr "Tear-Off"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Tear-Off ä½ç½®èª¿ç¯€"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "PPD ファイル \"%s\" ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "PPD ファイル \"%s\" ãŒé–‹ãã¾ã›ã‚“ã§ã—ãŸ: %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"クラスå㯠127 文字以内ã®è¡¨ç¤ºå¯èƒ½æ–‡å­—ã‹ã‚‰æˆã‚Šã€ç©ºç™½ã€ã‚¹ãƒ©ãƒƒã‚·ãƒ¥ (/)ã€ãƒãƒ³ãƒ‰è¨˜"
+"å· (#) ã‚’å«ã‚“ã§ã¯ãªã‚Šã¾ã›ã‚“。"
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+"notify-lease-duration 属性ã¯ã€ã‚¸ãƒ§ãƒ–サブスクリプションã¨ä¸€ç·’ã«ä½¿ã†ã“ã¨ã¯ã§ã"
+"ã¾ã›ã‚“。"
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"プリンターå㯠127 文字以内ã®è¡¨ç¤ºå¯èƒ½æ–‡å­—ã‹ã‚‰æˆã‚Šã€ç©ºç™½ã€ã‚¹ãƒ©ãƒƒã‚·ãƒ¥ (/)ã€ãƒãƒ³"
+"ãƒ‰è¨˜å· (#) ã‚’å«ã‚“ã§ã¯ãªã‚Šã¾ã›ã‚“。"
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "プリンターã¾ãŸã¯ã‚¯ãƒ©ã‚¹ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "printer-uri \"%s\" ã«ã¯ã€ç„¡åŠ¹ãªæ–‡å­—ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚"
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr ""
+"printer-uri ã¯ã€\"ipp://ホストå/classes/クラスå\" å½¢å¼ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›"
+"ん。"
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+"printer-uri 㯠\"ipp://ホストå/printers/プリンターå\" å½¢å¼ã§ãªã‘ã‚Œã°ãªã‚Šã¾"
+"ã›ã‚“。"
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"サブスクリプションåã«ã¯ã€ã‚¹ãƒšãƒ¼ã‚¹ã€ã‚¹ãƒ©ãƒƒã‚·ãƒ¥ (/)ã€ç–‘å•åºœ (?)ã€ãƒãƒ³ãƒ‰è¨˜å· "
+"(#) を使用ã—ãªã„ã§ãã ã•ã„。"
+
+msgid "There are too many subscriptions."
+msgstr "サブスクリプションãŒå¤šã™ãŽã¾ã™ã€‚"
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "熱転写メディア"
+
+msgid "Title: "
+msgstr "タイトル: "
+
+msgid "Too many active jobs."
+msgstr "アクティブãªã‚¸ãƒ§ãƒ–ãŒå¤šã™ãŽã¾ã™ã€‚"
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "OHP シート"
+
+msgid "Tray"
+msgstr "トレイ"
+
+msgid "Tray 1"
+msgstr "トレイ 1"
+
+msgid "Tray 2"
+msgstr "トレイ 2"
+
+msgid "Tray 3"
+msgstr "トレイ 3"
+
+msgid "Tray 4"
+msgstr "トレイ 4"
+
+msgid "URI Too Long"
+msgstr "URI ãŒé•·éŽãŽã¾ã™"
+
+msgid "US Executive"
+msgstr "US エグゼクティブ"
+
+msgid "US Fanfold"
+msgstr "US Fanfold"
+
+msgid "US Ledger"
+msgstr "US レジャー"
+
+msgid "US Legal"
+msgstr "US リーガル"
+
+msgid "US Legal (Oversize)"
+msgstr "US リーガル (特大)"
+
+msgid "US Letter"
+msgstr "US レター"
+
+msgid "US Letter (Oversize)"
+msgstr "US レター (特大)"
+
+msgid "US Letter (Small)"
+msgstr "US レター (å°)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "USB シリアルãƒãƒ¼ãƒˆ #%d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "cupsd.conf ファイルã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to add RSS subscription:"
+msgstr " RSS 購読を追加ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to add class:"
+msgstr "クラスを追加ã§ãã¾ã›ã‚“:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "プリンターを追加ãŒã§ãã¾ã›ã‚“:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "RSS 購読をキャンセルã§ãã¾ã›ã‚“:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "printer-is-shared 属性を変更ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“:"
+
+msgid "Unable to change printer:"
+msgstr "プリンターを変更ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to change server settings:"
+msgstr "サーãƒãƒ¼ã®è¨­å®šã‚’変更ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to connect to host."
+msgstr "ホストã«æŽ¥ç¶šã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "テンãƒãƒ©ãƒªãƒ•ã‚¡ã‚¤ãƒ«ã‚’作æˆã§ãã¾ã›ã‚“:"
+
+msgid "Unable to delete class:"
+msgstr "クラスを削除ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to delete printer:"
+msgstr "プリンターを削除ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to do maintenance command:"
+msgstr "メンテナンスコマンドを実行ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "クラスリストをå–å¾—ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to get class status:"
+msgstr "クラスã®çŠ¶æ…‹ã‚’å–å¾—ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "プリンタードライãƒãƒ¼ã®ãƒªã‚¹ãƒˆã‚’å–å¾—ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to get printer attributes:"
+msgstr "プリンター属性をå–å¾—ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to get printer list:"
+msgstr "プリンターリストをå–å¾—ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to get printer status:"
+msgstr "プリンターã®çŠ¶æ…‹ã‚’å–å¾—ã§ãã¾ã›ã‚“:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "クラスを変更ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to modify printer:"
+msgstr "プリンターを変更ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to move job"
+msgstr "ジョブを移動ã§ãã¾ã›ã‚“"
+
+msgid "Unable to move jobs"
+msgstr "複数ã®ã‚¸ãƒ§ãƒ–を移動ã§ãã¾ã›ã‚“"
+
+msgid "Unable to open PPD file"
+msgstr "PPD ファイルを読ã¿è¾¼ã‚€ã“ã¨ãŒã§ãã¾ã›ã‚“"
+
+msgid "Unable to open PPD file:"
+msgstr "PPD ファイルを読ã¿è¾¼ã‚€ã“ã¨ãŒã§ãã¾ã›ã‚“:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "cupsd.conf ファイルを開ã‘ã¾ã›ã‚“:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "テストページをå°åˆ·ã§ãã¾ã›ã‚“:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "\"%s\" を実行ã§ãã¾ã›ã‚“: %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "オプションを設定ã§ãã¾ã›ã‚“:"
+
+msgid "Unable to set server default:"
+msgstr "サーãƒãƒ¼ã‚’デフォルトã«è¨­å®šã§ãã¾ã›ã‚“:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "cupsd.conf ファイルをアップロードã§ãã¾ã›ã‚“:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "ä¸è¨±å¯"
+
+msgid "Units"
+msgstr "ユニット"
+
+msgid "Unknown"
+msgstr "未知"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "\"%s\" ã¯æœªçŸ¥ã® printer-error-policy ã§ã™ã€‚"
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "\"%s\" ã¯æœªçŸ¥ã® printer-op-policy ã§ã™ã€‚"
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„åž‹ã®å€¤ã§ã™"
+
+msgid "Upgrade Required"
+msgstr "アップグレードãŒå¿…è¦ã§ã™"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"使ã„æ–¹:\n"
+"\n"
+" lpadmin [-h サーãƒãƒ¼] -d 宛先\n"
+" lpadmin [-h サーãƒãƒ¼] -x 宛先\n"
+" lpadmin [-h サーãƒãƒ¼] -p プリンター [-c 追加クラス] [-i インターフェイ"
+"ス]\n"
+" [-m モデル] [-r 削除クラス] [-v デãƒã‚¤ã‚¹]\n"
+" [-D 宛先] [-P PPD ファイル] [-o åå‰=値]\n"
+" [-u allow:ユーザー,ユーザー] [-u deny:ユーザー,ユー"
+"ザー]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr ""
+"使ã„æ–¹: %s ジョブID ユーザー タイトル コピー数 オプション [ファイルå]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "使ã„æ–¹: %s ジョブID ユーザー タイトル コピー数 オプション [ファイル]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "使ã„æ–¹: %s ジョブID ユーザー タイトル コピー数 オプション ファイル\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+"使ã„æ–¹: convert [オプション]\n"
+"\n"
+"オプション:\n"
+"\n"
+" -e PPD ファイルã‹ã‚‰ã™ã¹ã¦ã®ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã‚’使用ã™ã‚‹\n"
+" -f filename 変æ›ã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã‚’指定ã™ã‚‹ (指定ãŒãªã‘れ㰠stdin ã¨ãª"
+"ã‚‹)\n"
+" -o filename 生æˆã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã‚’指定ã™ã‚‹ (指定ãŒãªã‘れ㰠stdout ã¨ãª"
+"ã‚‹)\n"
+" -i mime/type 入力㮠MIME タイプを指定ã™ã‚‹ (指定ãŒãªã‘ã‚Œã°è‡ªå‹•ã‚¿ã‚¤"
+"プ)\n"
+" -j mime/type 出力㮠MIME タイプを指定ã™ã‚‹ (指定ãŒãªã‘れ㰠"
+"application/pdf)\n"
+" -P filename.ppd PPD ファイルを指定ã™ã‚‹\n"
+" -a 'name=value ...' オプションを指定ã™ã‚‹\n"
+" -U username ジョブã®ãƒ¦ãƒ¼ã‚¶ãƒ¼åを指定ã™ã‚‹\n"
+" -J title タイトルを指定ã™ã‚‹\n"
+" -c copies 部数を指定ã™ã‚‹\n"
+" -u 終了ã—ãŸã¨ãã« PPD ファイルを削除ã™ã‚‹\n"
+" -D 終了ã—ãŸã¨ãã«å…¥åŠ›ãƒ•ã‚¡ã‚¤ãƒ«ã‚’削除ã™ã‚‹\n"
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"使ã„æ–¹: cupsaddsmb [オプション] プリンター ... プリンターN\n"
+" cupsaddsmb [オプション] -a\n"
+"\n"
+"オプション:\n"
+" -E サーãƒãƒ¼ã¨ã®æŽ¥ç¶šã‚’æš—å·åŒ–ã™ã‚‹\n"
+" -H sambaサーãƒãƒ¼ 指定㮠SAMBA サーãƒãƒ¼ã‚’使ã†\n"
+" -U sambaユーザー 指定㮠SAMBA ユーザーを使ã£ã¦èªè¨¼ã™ã‚‹\n"
+" -a ã™ã¹ã¦ã®ãƒ—リンターをエキスãƒãƒ¼ãƒˆã™ã‚‹\n"
+" -h cupsサーãƒãƒ¼ 指定㮠CUPS サーãƒãƒ¼ã‚’使ã†\n"
+" -v 冗長ã«ã™ã‚‹ (コマンドを表示ã™ã‚‹)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"使ã„æ–¹: cupsctl [オプション] [パラメータ=値 ... パラメータN=値N]\n"
+"\n"
+"オプション:\n"
+"\n"
+" -E æš—å·åŒ–を有効ã«ã™ã‚‹\n"
+" -U ユーザå ユーザーåを指定ã™ã‚‹\n"
+" -h サーãƒãƒ¼[:ãƒãƒ¼ãƒˆ] サーãƒãƒ¼ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’指定ã™ã‚‹\n"
+"\n"
+" --[no-]debug-logging デãƒãƒƒã‚°ãƒ­ã‚°ã®æœ‰åŠ¹/無効を切り替ãˆã‚‹\n"
+" --[no-]remote-admin リモート管ç†ã®æœ‰åŠ¹/無効を切り替ãˆã‚‹\n"
+" --[no-]remote-any インターãƒãƒƒãƒˆã‹ã‚‰ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯/ç¦æ­¢ã™ã‚‹\n"
+" --[no-]remote-printers リモートプリンターを表示/éžè¡¨ç¤ºã«ã™ã‚‹\n"
+" --[no-]share-printers プリンター共有ã®æœ‰åŠ¹/無効を切り替ãˆã‚‹\n"
+" --[no-]user-cancel-any ã‚らゆるジョブã®ã‚­ãƒ£ãƒ³ã‚»ãƒ«ã‚’ユーザーã«è¨±å¯/ç¦æ­¢ã™"
+"ã‚‹\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"使ã„æ–¹: cupsd [-c 設定ファイル] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c 設定ファイル 別ã®è¨­å®šãƒ•ã‚¡ã‚¤ãƒ«ã‚’ロードã™ã‚‹\n"
+"-f フォアグラウンドã§å®Ÿè¡Œã™ã‚‹\n"
+"-F フォアグラウンドã§å®Ÿè¡Œã™ã‚‹ãŒãƒ‡ã‚¿ãƒƒãƒã™ã‚‹\n"
+"-h ã“ã®ä½¿ã„方を表示ã™ã‚‹\n"
+"-l launchd(8) ã‹ã‚‰ cupsd を実行ã™ã‚‹\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+"使ã„æ–¹: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf 使用ã™ã‚‹ cupsd.conf ファイルã®æŒ‡å®š\n"
+" -e PPD ファイルã§æŒ‡å®šã•ã‚ŒãŸã™ã¹ã¦ã®ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã‚’使用ã™ã‚‹\n"
+" -j job-id[,N] フィルターファイル N を指定ã•ã‚ŒãŸã‚¸ãƒ§ãƒ–ã‹ã‚‰ä½¿ç”¨ã™ã‚‹ (デ"
+"フォルト㯠ファイル 1)\n"
+" -n copies å°åˆ·éƒ¨æ•°ã‚’指定ã™ã‚‹\n"
+" -o name=value オプションを指定ã™ã‚‹\n"
+" -p filename.ppd PPDファイルを指定ã™ã‚‹\n"
+" -t title タイトルを指定ã™ã‚‹\n"
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"使ã„æ–¹: cupstestdsc [オプション] ファイルå.ps [... ファイルå.ps]\n"
+" cupstestdsc [オプション] -\n"
+"\n"
+"オプション:\n"
+"\n"
+" -h プログラムã®ä½¿ã„方を表示ã™ã‚‹\n"
+"\n"
+" 注æ„: ã“ã®ãƒ—ログラム㯠DSC コメントを検証ã™ã‚‹ã ã‘ã§ã€PostScript 自身を検"
+"証ã™ã‚‹ã‚‚ã®ã§ã¯ã‚ã‚Šã¾ã›ã‚“。\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "使ã„æ–¹: lpmove ジョブ/ソース 宛先\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"使ã„æ–¹: lpoptions [-h サーãƒãƒ¼] [-E] -d プリンター\n"
+"   lpoptions [-h サーãƒãƒ¼] [-E] [-p プリンター] -l\n"
+" lpoptions [-h サーãƒãƒ¼] [-E] -p プリンター -o オプション[=値] ...\n"
+" lpoptions [-h サーãƒãƒ¼] [-E] -x プリンター\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "使ã„æ–¹: lppasswd [-g グループå]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"使ã„æ–¹: lppasswd [-g グループå] [ユーザå]\n"
+" lppasswd [-g グループå] -a [ユーザå]\n"
+" lppasswd [-g グループå] -x [ユーザå]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"使ã„æ–¹: lpq [-P 宛先] [-U ユーザーå] [-h ホストå[:ãƒãƒ¼ãƒˆ]] [-l] [+é–“éš”]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"使ã„æ–¹: ppdc [オプション] ファイルå.drv [ ... ファイルåN.drv ]\n"
+"オプション:\n"
+" -D 変数å=値 変数åã§æŒ‡å®šã—ãŸå¤‰æ•°ã«å€¤ã‚’セットã™ã‚‹\n"
+" -I include-dir include-dir ã§æŒ‡å®šã—ãŸãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’サーãƒãƒ‘スã«è¿½åŠ \n"
+" -c catalog.po 指定ã—ãŸãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚«ã‚¿ãƒ­ã‚°ã‚’ロードã™ã‚‹\n"
+" -d output-dir 出力ディレクトリ(output-dir)を指定ã™ã‚‹\n"
+" -l lang[,lang,...] 出力言語を指定ã™ã‚‹ã€‚(複数å¯èƒ½)\n"
+" -m ModelName ã®å€¤ã‚’ファイルåã¨ã—ã¦ä½¿ç”¨ã™ã‚‹\n"
+" -t PPD を出力ã—ãªã„ã§ãƒ†ã‚¹ãƒˆã™ã‚‹\n"
+" -v 冗長出力を行ㆠ(v を追加ã—ã¦ã•ã‚‰ã«å†—é•·ã«)\n"
+" -z PPD ファイルを GNU zip を使ã£ã¦åœ§ç¸®ã™ã‚‹\n"
+" --cr ラインã®æœ€å¾Œã¯ CR (Mac OS 9 æ–¹å¼).\n"
+" --crlf ラインã®æœ€å¾Œã¯ CR + LF (Windows æ–¹å¼).\n"
+" --lf ラインã®æœ€å¾Œã¯ LF (UNIX/Linux/Mac OS X æ–¹å¼).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"使ã„æ–¹: ppdhtml [オプション] ファイルå.drv >ファイルå.html\n"
+" -D 変数å=値 変数åã§æŒ‡å®šã—ãŸå¤‰æ•°ã«å€¤ã‚’セットã™ã‚‹\n"
+"オプション:\n"
+" -I include-dir include-dir ã§æŒ‡å®šã—ãŸãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’サーãƒãƒ‘スã«è¿½åŠ \n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"使ã„æ–¹: ppdi [オプション] ファイルå.ppd [ ... ファイルåN.ppd ]\n"
+"オプション:\n"
+" -I インクルードディレクトリ\n"
+" -o ファイルå.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"使ã„æ–¹: ppdmerge [オプション] ファイルå.ppd [ ... ファイルåN.ppd ]\n"
+"オプション:\n"
+" -o ファイルå.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"使ã„æ–¹: ppdpo [オプション] -o ファイルå.po ファイルå.drv [ ... ファイルåN."
+"drv ]\n"
+"オプション:\n"
+" -D 変数å=値 変数åã§æŒ‡å®šã—ãŸå¤‰æ•°ã«å€¤ã‚’セットã™ã‚‹\n"
+" -I include-dir include-dir ã§æŒ‡å®šã—ãŸãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’サーãƒãƒ‘スã«è¿½åŠ \n"
+" -v 冗長出力を行ㆠ(v を追加ã—ã¦ã•ã‚‰ã«å†—é•·ã«)\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "使ã„æ–¹: snmp [ホストã¾ãŸã¯IPアドレス]\n"
+
+msgid "Value uses indefinite length"
+msgstr "値ã¯ä¸å®šé•·ã§ã™"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind ã¯ä¸å®šé•·ã§ã™"
+
+msgid "Version uses indefinite length"
+msgstr "Version ã¯ä¸å®šé•·ã§ã™"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: 発見ã—ãŸé †ç•ªã« %d å°ã®ãƒ—リンターã ã‘追加ã—ã¾ã™"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: è«–ç†å€¤ã¯ã€waiteof オプション \"%s\" ã§ã‚ã‚‹ã¹ãã§ã™\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: プリンターãŒåå¿œã—ã¾ã›ã‚“\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: プリンターãŒæ„図ã—ãªã„ EOF ã‚’è¿”ã—ã¾ã—ãŸ\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: \"%s:%s\": %s ã‚’é–‹ã‘ã¾ã›ã‚“\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: PAP ステータス・リクエストをé€ä¿¡ã§ãã¾ã›ã‚“"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: %d タイプã®æ„図ã—ãªã„ PAP パケット\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: 未知㮠PAP パケットã®ã‚¿ã‚¤ãƒ— %d\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: ステータス・オプションã®æœŸå¾…値㯠\"%s\"\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "ã¯ã„"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"ã“ã®ãƒšãƒ¼ã‚¸ã«ã¯ URL <A HREF=\"https://%s:%d%s\">https://%s:%d%s</A> を使ã£ã¦ã‚¢"
+"クセスã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
+
+msgid "You4 Envelope"
+msgstr "æ´‹å½¢ 4 å·"
+
+msgid "ZPL Label Printer"
+msgstr "ZPL ラベル・プリンター"
+
+msgid "Zebra"
+msgstr "ゼブラ"
+
+msgid "aborted"
+msgstr "åœæ­¢"
+
+msgid "canceled"
+msgstr "キャンセル"
+
+msgid "completed"
+msgstr "完了"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr ""
+"convert: 変æ›ã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã‚’指定ã™ã‚‹ã«ã¯ã€-f オプションを使ã£ã¦ãã ã•ã„。\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "cups-deviced ã®å®Ÿè¡Œã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
+
+msgid "cups-driverd failed to execute."
+msgstr "cups-driverd ã®å®Ÿè¡Œã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: プリンター \"%s\" ã® PPD ファイルãŒã‚ã‚Šã¾ã›ã‚“ - %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: サーãƒãƒ¼: %s ã«æŽ¥ç¶šã§ãã¾ã›ã‚“\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr ""
+"cupsd: launchd(8) サãƒãƒ¼ãƒˆãŒã‚³ãƒ³ãƒ‘イルã•ã‚Œã¦ã„ãªã„ã®ã§ã€é€šå¸¸ãƒ¢ãƒ¼ãƒ‰ã§å‹•ä½œã—ã¾"
+"ã™ã€‚\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: ジョブ・ファイルをå–å¾—ã§ãã¾ã›ã‚“ - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd: -q オプション㯠-v オプションã¨ä¸¡ç«‹ã§ãã¾ã›ã‚“。\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd: -v オプション㯠-q オプションã¨ä¸¡ç«‹ã§ãã¾ã›ã‚“。\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "%s/%s ã®ãƒ‡ãƒã‚¤ã‚¹: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "%s ã®ãƒ‡ãƒã‚¤ã‚¹: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "エラー・インデックスã¯ä¸å®šé•·ã§ã™"
+
+msgid "error-status uses indefinite length"
+msgstr "エラー・ステータスã¯ä¸å®šé•·ã§ã™"
+
+msgid "held"
+msgstr "ホールド"
+
+msgid "help\t\tget help on commands\n"
+msgstr "help\t\tコマンドã®ãƒ˜ãƒ«ãƒ—ã‚’å–å¾—\n"
+
+msgid "idle"
+msgstr "待機中"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: プリンター %s ã¯ã™ã§ã«ã‚¯ãƒ©ã‚¹ %s ã®ãƒ¡ãƒ³ãƒãƒ¼ã§ã™ã€‚\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: プリンター %s ã¯ã‚¯ãƒ©ã‚¹ %s ã®ãƒ¡ãƒ³ãƒãƒ¼ã§ã¯ã‚ã‚Šã¾ã›ã‚“。\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: サーãƒãƒ¼ã«æŽ¥ç¶šã§ãã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: PPD ファイル \"%s\" ã‚’é–‹ã‘ã¾ã›ã‚“ - %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: ファイル \"%s\" ã‚’é–‹ã‘ã¾ã›ã‚“: %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: サーãƒãƒ¼ã«æŽ¥ç¶šã§ãã¾ã›ã‚“: %s!\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: プリンターã¾ãŸã¯ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã‚’追加ã§ãã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: %s ã® PPD ファイルを開ã‘ã¾ã›ã‚“!: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: ã™ã¿ã¾ã›ã‚“ãŒã€ãƒ‘スワードã¯æ‹’å¦ã•ã‚Œã¾ã—ãŸã€‚\n"
+"パスワードã¯å°‘ãªãã¨ã‚‚ 6 文字以上ã§ã€ã‚ãªãŸã®ãƒ¦ãƒ¼ã‚¶ãƒ¼åã‚’å«ã‚“ã§ã¯ãªã‚‰ãšã€\n"
+"å°‘ãªãã¨ã‚‚ 1 ã¤ã®è‹±å­—ãŠã‚ˆã³æ•°å€¤ã‚’å«ã‚“ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: パスワード文字列をコピーã§ãã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: パスワードファイルを開ã‘ã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: パスワードファイルã«æ›¸ãè¾¼ã‚ã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr "lppasswd: å¤ã„パスワードファイルã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã«å¤±æ•—ã—ã¾ã—ãŸ: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: パスワードファイルã®åå‰ã®å¤‰æ›´ã«å¤±æ•—ã—ã¾ã—ãŸ: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: ユーザー \"%s\" ãŠã‚ˆã³ã‚°ãƒ«ãƒ¼ãƒ— \"%s\" ã¯å­˜åœ¨ã—ã¾ã›ã‚“。\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "クラス %s ã®ãƒ¡ãƒ³ãƒãƒ¼:\n"
+
+msgid "no entries\n"
+msgstr "エントリーãŒã‚ã‚Šã¾ã›ã‚“\n"
+
+msgid "no system default destination\n"
+msgstr "システムã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®å®›å…ˆãŒã‚ã‚Šã¾ã›ã‚“\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "ä¿ç•™"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: ディレクトリー \"%s\" を追加ã—ã¦ã„ã¾ã™...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: %s ã‹ã‚‰ UI テキストを追加ã¾ãŸã¯æ›´æ–°ã—ã¦ã„ã¾ã™...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: ä¸æ­£ãª boolean 値 (%s) ãŒã‚ã‚Šã¾ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s。\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: ä¸æ­£ãªæ•°å€¤ç½®æ› ($%c) ãŒã‚ã‚Šã¾ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s。\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠boolean 値ãŒå¿…è¦ã§ã™ã€‚\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠choice code ãŒå¿…è¦ã§ã™ã€‚\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠choice name/text ãŒå¿…è¦ã§ã™ã€‚\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: ドライãƒãƒ¼æƒ…報ファイル \"%s\" を読ã¿è¾¼ã‚“ã§ã„ã¾ã™...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: ロケール \"%s\" ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’読ã¿è¾¼ã‚“ã§ã„ã¾ã™...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: \"%s\" ã‹ã‚‰ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’読ã¿è¾¼ã‚“ã§ã„ã¾ã™...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: PPD ファイル \"%s\" を作æˆã§ãã¾ã›ã‚“ - %s。\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: ディレクトリー \"%s\" を作æˆã§ãã¾ã›ã‚“ - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: 出力 pipe ãŒä½œæˆã§ãã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: cupstestppd を実行ã§ãã¾ã›ã‚“: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: \"%s\" ã«å¯¾ã™ã‚‹åœ°åŸŸåŒ–情報ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ - %s \n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: \"%s\" ã«å¯¾ã™ã‚‹åœ°åŸŸåŒ–情報を読ã¿è¾¼ã‚ã¾ã›ã‚“ - %s \n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: 変数 (%s) ã¯æœªå®šç¾©ã§ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s。\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: %s を書ã込んã§ã„ã¾ã™...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: ディレクトリー \"%s\" ã« PPD ファイルを書ã込んã§ã„ã¾ã™...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: PPD ファイル %s を無視ã—ã¾ã™...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: %s ã‚’ %s ã«ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã§ãã¾ã›ã‚“ - %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "プリンター %s 㯠%s ã‹ã‚‰ç„¡åŠ¹ã§ã™ -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "プリンター %s ã¯å¾…機中ã§ã™ã€‚%s 以æ¥æœ‰åŠ¹ã§ã™\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "プリンター %s 㯠%s-%d ã‚’å°åˆ·ã—ã¦ã„ã¾ã™ã€‚%s 以æ¥æœ‰åŠ¹ã§ã™\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "プリンター %s/%s 㯠%s ã‹ã‚‰ç„¡åŠ¹ã§ã™ -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "プリンター %s/%s ã¯å¾…機中ã§ã™ã€‚%s 以æ¥æœ‰åŠ¹ã§ã™\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "プリンター %s/%s ã¯ç¾åœ¨ %s-%d ã‚’å°åˆ·ä¸­ã§ã™ã€‚%s 以æ¥æœ‰åŠ¹ã§ã™\n"
+
+msgid "processing"
+msgstr "処ç†ä¸­"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "リクエスト ID 㯠%s-%d ã§ã™ (%d 個ã®ãƒ•ã‚¡ã‚¤ãƒ«)\n"
+
+msgid "request-id uses indefinite length"
+msgstr "リクエスト ID ã®é•·ã•ãŒä¸å®š"
+
+msgid "scheduler is not running\n"
+msgstr "スケジューラーã¯å‹•ä½œã—ã¦ã„ã¾ã›ã‚“\n"
+
+msgid "scheduler is running\n"
+msgstr "スケジューラーã¯å‹•ä½œä¸­ã§ã™\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "%s ã®çŠ¶æ…‹å–å¾—ã«å¤±æ•—ã—ã¾ã—ãŸ: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "status\t\tデーモンã¨ã‚­ãƒ¥ãƒ¼ã®çŠ¶æ…‹ã‚’表示\n"
+
+msgid "stopped"
+msgstr "åœæ­¢"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "システムã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®å®›å…ˆ: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "システムã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®å®›å…ˆ: %s/%s\n"
+
+msgid "unknown"
+msgstr "未知"
+
+msgid "untitled"
+msgstr "タイトルãªã—"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindings ã®é•·ã•ãŒä¸å®š"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " 警告 %s ã¯ç›¸å½“ã™ã‚‹ã‚ªãƒ—ションãŒã‚ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " 警告 デフォルトã®é¸æŠžè‚¢ãŒç«¶åˆã—ã¦ã„ã¾ã™!\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " 警告 Duplex オプションキーワード %s ã¯æœŸå¾…通りã«å‹•ä½œã—ãªã„ã‹ã‚‚"
+#~ "ã—ã‚Œã¾ã›ã‚“。ã¾ãŸã€Duplex ã¨ã„ã†åå‰ã§ã‚ã‚‹ã¹ãã§ã™!\n"
+#~ " å‚ç…§: 122 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " 警告 ファイル㌠CRã€LFã€CR LF ã®è¡Œæœ«ã‚’混在ã—ã¦å«ã‚“ã§ã„ã¾ã™!\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " 警告 %d è¡ŒãŒç©ºç™½ã ã‘ã§ã™!\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " 警告 éž Windows PPD ファイルã¯ã€CR LF ã§ãªã LF ã®ã¿ã‚’行末ã«ä½¿"
+#~ "ã†ã¹ãã§ã™!\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " 警告 PPD ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %.1f ã¯ç¾åœ¨ä½¿ã‚ã‚Œã¦ã„ã¾ã›ã‚“!\n"
+#~ " å‚ç…§: 42 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.2。\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s ãŒå­˜åœ¨ã—ã¾ã›ã‚“!\n"
+
+#~ msgid " %s %s file \"%s\" has the wrong capitalization!\n"
+#~ msgstr ""
+#~ " %s %s ファイル \"%s\" ã¯ä¸æ­£ãªå¤§æ–‡å­—ã§å§‹ã¾ã‚‹ãƒ¯ãƒ¼ãƒ‰ã‚’å«ã‚“ã§ã„ã¾ã™!\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s ä¸æ­£ãª %s ㌠%s ã‚’é¸ã‚“ã§ã„ã¾ã™!\n"
+#~ " å‚ç…§: 122 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.17\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr " %s ä¸æ­£ãª UTF-8 \"%s\" 翻訳文字列 (オプション %s 用)ã§ã™!\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s ä¸æ­£ãª UTF-8 \"%s\" 翻訳文字列 (オプション %s ã€é¸æŠž %s)ã§ã™!\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s ä¸æ­£ãªå€¤ãŒ cupsFilter ã«è¨­å®šã•ã‚Œã¦ã„ã¾ã™ \"%s\"!\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s ä¸æ­£ãª cupsICCProfile %sã§ã™!\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s ä¸æ­£ãªå€¤ãŒ cupsPreFilter ã«è¨­å®šã•ã‚Œã¦ã„ã¾ã™ \"%s\"!\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s ä¸æ­£ãª cupsUIConstraints %s: \"%s\"ã§ã™!\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s 無効ãªè¨€èªž \"%s\"ã§ã™!\n"
+
+#~ msgid " %s Bad spelling of %s - should be %s!\n"
+#~ msgstr " %s %s ã®ä¸æ­£ãªç¶´ã‚Šã§ã™ - %s ã§ã‚ã‚‹ã¹ãã§ã™!\n"
+
+#~ msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID!\n"
+#~ msgstr ""
+#~ " %s APScanAppPath 㨠APScanAppBundleID ã¯åŒæ™‚ã«æŒ‡å®šã§ãã¾ã›ã‚“!\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s 空㮠cupsUIConstraints %sã§ã™!\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s \"%s\" 翻訳文字列 (オプション %s 用) ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s \"%s\" 翻訳文字列 (オプション %s ã€é¸æŠž %s) ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid ""
+#~ " %s Missing REQUIRED PageRegion option!\n"
+#~ " REF: Page 100, section 5.14.\n"
+#~ msgstr ""
+#~ " %s 必須㮠PageRegion オプションãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+#~ " å‚ç…§: 100 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.14。\n"
+
+#~ msgid ""
+#~ " %s Missing REQUIRED PageSize option!\n"
+#~ " REF: Page 99, section 5.14.\n"
+#~ msgstr ""
+#~ " %s 必須㮠PageSize オプションãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+#~ " å‚ç…§: 99 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.14。\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s  é¸æŠž *%s %s ㌠UIConstraints \"*%s %s *%s %s\" 内ã«è¦‹ã¤ã‹ã‚Šã¾ã›"
+#~ "ã‚“!\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr ""
+#~ " %s é¸æŠž *%s %s ㌠cupsUIConstraints %s: \"%s\" 内ã«è¦‹ã¤ã‹ã‚Šã¾ã›"
+#~ "ã‚“!\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s cupsICCProfile ファイル \"%s\" ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s cupsUIResolver ファイル %s ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s オプション %s ãŒUIConstraints \"*%s %s *%s %s\" ã«è¦‹ã¤ã‹ã‚Šã¾ã›"
+#~ "ã‚“!\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr ""
+#~ " %s オプション %s ãŒcupsUIConstraints %s ã«è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!: \"%s\"\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr " %s ファイルã«ãƒ™ãƒ¼ã‚¹ç¿»è¨³æ–‡å­—列 \"%s\" ãŒã‚ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid ""
+#~ " %s Non-standard size name \"%s\"!\n"
+#~ " REF: Page 187, section B.2.\n"
+#~ msgstr ""
+#~ " %s サイズå \"%s\" ã¯æ¨™æº–ã«ã‚ã‚Šã¾ã›ã‚“!\n"
+#~ " å‚ç…§: 187 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ B.2。\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s 必須㮠%s ãŒé¸æŠžè‚¢ None を定義ã—ã¦ã„ã¾ã›ã‚“!\n"
+#~ " å‚ç…§: 122 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.17。\n"
+
+#~ msgid " %s Size \"%s\" defined for %s but not for %s!\n"
+#~ msgstr ""
+#~ " %s サイズ \"%s\" 㯠%s å‘ã‘ã«å®šç¾©ã•ã‚Œã¦ã„ã¾ã™ãŒã€%s ã«ã¯ã‚ã‚Šã¾ã›"
+#~ "ã‚“!\n"
+
+#~ msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)!\n"
+#~ msgstr " %s サイズ \"%s\" ã¯è¦å®šå¤–ã®å¯¸æ³• (%gx%g) ã‚’æŒã£ã¦ã„ã¾ã™!\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " %s cupsICCProfileã®ãƒãƒƒã‚·ãƒ¥å€¤ %s ㌠%s ã¨ä¸€è‡´ã—ã¾ã›ã‚“!\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolverã® %s ãŒãƒ«ãƒ¼ãƒ—ã—ã¦ã„ã¾ã™!\n"
+
+#~ msgid ""
+#~ " %s cupsUIResolver %s does not list at least two different "
+#~ "options!\n"
+#~ msgstr ""
+#~ " %s cupsUIResolver %s ã¯æœ€ä½Žã§ã‚‚二ã¤ã®ç•°ãªã£ãŸã‚ªãƒ—ションをæŒã£ã¦ã„ãª"
+#~ "ã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **失敗** %s ãŒé¸æŠžã—㟠%s 㨠%s ã¯å¤§æ–‡å­—/å°æ–‡å­—ã®ã¿ãŒé•ã†ã ã‘ã§"
+#~ "ã™!\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **失敗** %s 㯠1284DeviceID ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“!\n"
+#~ " å‚ç…§: 72 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.5\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **失敗** %s ã¯ä¸æ­£ãª DefaultImageableArea ã§ã™!\n"
+#~ " å‚ç…§: 102 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.15。\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **失敗** %s ã¯ä¸æ­£ãª DefaultPaperDimension ã§ã™!\n"
+#~ " å‚ç…§: 103 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.15。\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **失敗** ä¸æ­£ãª %s ㌠%s ã‚’é¸ã‚“ã§ã„ã¾ã™!\n"
+#~ " å‚ç…§: 84 ページã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ 5.9\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr ""
+#~ " **失敗** 無効㪠LanguageEncoding %s - ISOLatin1 ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›"
+#~ "ã‚“!\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr ""
+#~ " **失敗** 無効㪠LanguageVersion %s - English ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›"
+#~ "ã‚“!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **失敗** オプション %sã€é¸æŠž %s ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®ç¿»è¨³æ–‡å­—列㌠8 ビット"
+#~ "文字をå«ã‚“ã§ã„ã¾ã™!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **失敗** オプション %s ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®ç¿»è¨³æ–‡å­—列㌠8 ビット文字をå«"
+#~ "ã‚“ã§ã„ã¾ã™!\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **失敗** グループå %s 㨠%s ã¯å¤§æ–‡å­—/å°æ–‡å­—ãŒé•ã†ã ã‘ã§ã™!\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **失敗** %s ã§è¤‡æ•°ã®ã‚ªãƒ—ション %s ãŒé¸æŠžã•ã‚Œã¦ã„ã¾ã™!\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **失敗** オプションå %s 㨠%s ã¯å¤§æ–‡å­—/å°æ–‡å­—ãŒé•ã†ã ã‘ã§ã™!\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " ä¸æ­£ãª %%%%BoundingBox: (%d è¡Œ)!\n"
+#~ " å‚ç…§: 39 ページã€%%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " ä¸æ­£ãª %%%%Page: (%d è¡Œ)!\n"
+#~ " å‚ç…§: 53 ページã€%%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " ä¸æ­£ãª %%%%Pages: (%d è¡Œ)!\n"
+#~ " å‚ç…§: 43 ページã€%%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " %d 行㌠255文字より長ããªã£ã¦ã„ã¾ã™ (%d)!\n"
+#~ " å‚ç…§: 25 ページã€Line Length\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " 先頭行㫠%!PS-Adobe-3.0 ãŒã‚ã‚Šã¾ã›ã‚“!\n"
+#~ " å‚ç…§: 17 ページã€3.1 Conforming Documents\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " %%EndComments コメントãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+#~ " å‚ç…§: 41 ページã€%%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " %%BoundingBox: コメントãŒè¦‹ã¤ã‹ã‚‰ãªã„ã‹ä¸æ­£ã§ã™!\n"
+#~ " å‚ç…§: 39 ページã€%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " %%Page: コメントãŒè¦‹ã¤ã‹ã‚‰ãªã„ã‹ä¸æ­£ã§ã™!\n"
+#~ " å‚ç…§: 53 ページã€%%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " %%Pages: コメントãŒè¦‹ã¤ã‹ã‚‰ãªã„ã‹ä¸æ­£ã§ã™!\n"
+#~ " å‚ç…§: 43 ページã€%%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " 255文字を超ãˆã‚‹ %d è¡ŒãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸ!\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " %%BeginDocument コメントãŒå¤šã™ãŽã¾ã™!\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " %%EndDocument コメントãŒå¤šã™ãŽã¾ã™!\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " 警告: ファイルã«ãƒã‚¤ãƒŠãƒªãƒ‡ãƒ¼ã‚¿ãŒå«ã¾ã‚Œã¦ã„ã¾ã™!\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " 警告: ファイル㫠%%EndComments コメントãŒã‚ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " 警告: ファイルã¯æ™‚代é…れ㮠DSC ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %.1f ã§ã™!\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“!"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: 何ãŒèµ·ãã¦ã„ã‚‹ã‹ä¸æ˜Žã§ã™!\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr "%s: エラー - 環境変数 %s ãŒå­˜åœ¨ã—ãªã„宛先 \"%s\" を指ã—ã¦ã„ã¾ã™!\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: エラー - ä¸æ­£ãªã‚¸ãƒ§ãƒ– ID ã§ã™!\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr ""
+#~ "%s: エラー - ファイルをå°åˆ·ã§ããšã€ã‚¸ãƒ§ãƒ–ã‚’åŒæ™‚ã«å¤‰ãˆã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“!\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: エラー - ファイルã¾ãŸã¯ã‚¸ãƒ§ãƒ– ID ãŒæä¾›ã•ã‚Œã¦ã„ã‚‹å ´åˆã€æ¨™æº–入力ã‹ã‚‰å°"
+#~ "刷ã§ãã¾ã›ã‚“。 \n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: エラー - '-S' オプションã®ã‚ã¨ã«ã¯æ–‡å­—セットãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: エラー - '-T' オプションã®ã‚ã¨ã«ã¯ã‚³ãƒ³ãƒ†ãƒ³ãƒ„タイプãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: エラー - '-n' オプションã®ã‚ã¨ã«ã¯ã‚³ãƒ”ー数ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s: エラー - '-#' オプションã®ã‚ã¨ã«ã¯ã‚³ãƒ”ー数ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: エラー - '-P' オプションã®ã‚ã¨ã«ã¯å®›å…ˆãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: エラー - '-b' オプションã®ã‚ã¨ã«å®›å…ˆãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: エラー - '-d' オプションã®ã‚ã¨ã«ã¯ãƒ—リンターåãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: エラー - '-f' オプションã®ã‚ã¨ã«ã¯ç”¨ç´™åãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: エラー - '-H' オプションã®ã‚ã¨ã«ã¯ãƒ›ãƒ¼ãƒ«ãƒ‰åãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: エラー - '-H' オプションã®ã‚ã¨ã«ã¯ãƒ›ã‚¹ãƒˆåãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: エラー - '-h' オプションã®ã‚ã¨ã«ã¯ãƒ›ã‚¹ãƒˆåãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: エラー - '-y' オプションã®ã‚ã¨ã«ã¯ãƒ¢ãƒ¼ãƒ‰ãƒªã‚¹ãƒˆãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: エラー - '-%c' オプションã®ã‚ã¨ã«ã¯åå‰ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s: エラー - '-o' オプションã®ã‚ã¨ã«ã¯æ–‡å­—列ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: エラー - '-P' オプションã®ã‚ã¨ã«ã¯ãƒšãƒ¼ã‚¸ãƒªã‚¹ãƒˆãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: エラー - '-%c' オプションã®ã‚ã¨ã«ã¯å„ªå…ˆåº¦ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s: エラー - '-r' ã®ã‚ã¨ã«ã¯ç†ç”±ã®ãƒ†ã‚­ã‚¹ãƒˆãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: エラー - '-t' オプションã®ã‚ã¨ã«ã¯ã‚¿ã‚¤ãƒˆãƒ«ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s: エラー - '-U' オプションã®ã‚ã¨ã«ã¯ãƒ¦ãƒ¼ã‚¶åãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s: エラー - '-u' オプションã®ã‚ã¨ã«ã¯ãƒ¦ãƒ¼ã‚¶åãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: エラー - '-%c' オプションã®ã‚ã¨ã«ã¯å€¤ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: エラー - '-W' オプションã®ã‚ã¨ã«ã¯ã€\"completed\"ã€\"not-completed\"ã€"
+#~ "\"all\" ã®ã„ãšã‚Œã‹ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: エラー - スケジューラãŒå¿œç­”ã—ã¦ã„ã¾ã›ã‚“!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: エラー - \"%s\" ã¯æœªçŸ¥ã®å®›å…ˆã§ã™!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: エラー - \"%s/%s\" ã¯æœªçŸ¥ã®å®›å…ˆã§ã™!\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: エラー - '%c' ã¯æœªçŸ¥ã®ã‚ªãƒ—ションã§ã™!\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: エラー - '%s' ã¯æœªçŸ¥ã®ã‚ªãƒ—ションã§ã™!\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: '-i' オプションã®ã‚ã¨ã«ã¯ã‚¸ãƒ§ãƒ– ID ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: リスト \"%s\" ã«ç„¡åŠ¹ãªå®›å…ˆåãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr "%s: '-H restart' ã®å‰ã«ã¯ã‚¸ãƒ§ãƒ– ID ('-i ジョブID') ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: %s/%s ã‹ã‚‰ %s/%s ã«å¤‰æ›ã™ã‚‹ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ãŒã‚ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr ""
+#~ "%s: ã™ã¿ã¾ã›ã‚“ã€æš—å·åŒ–サãƒãƒ¼ãƒˆã¯ã‚³ãƒ³ãƒ‘イル時ã«çµ„ã¿è¾¼ã¾ã‚Œã¦ã„ã¾ã›ã‚“!\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: サーãƒãƒ¼ã«é€£çµ¡ã§ãã¾ã›ã‚“!\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: \"%s\" ã® MIME タイプを判別ã§ãã¾ã›ã‚“!\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr ""
+#~ "%s: \"%s\" ã¾ãŸã¯ \"%s\" ã‹ã‚‰ MIME データベースを読ã¿å–ã‚‹ã“ã¨ãŒã§ãã¾ã›"
+#~ "ã‚“!\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: \"%s\" ã¯æœªçŸ¥ã®å®›å…ˆã§ã™!\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: %s/%s ã¯æœªçŸ¥ã®å®›å…ˆ MIME タイプã§ã™!\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: '%c' ã¯æœªçŸ¥ã®ã‚ªãƒ—ションã§ã™!\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: %s/%s ã¯æœªçŸ¥ã®ã‚½ãƒ¼ã‚¹ MIME タイプã§ã™!\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: 警告 - '%c' å½¢å¼ä¿®é£¾å­ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“ - 出力ã¯æ­£ã—ããªã„ã‚‚ã®"
+#~ "ã«ãªã‚‹ã‹ã‚‚ã—ã‚Œã¾ã›ã‚“!\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: 警告 - 文字セットオプションã¯ç„¡è¦–ã•ã‚Œã¾ã™!\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: 警告 - コンテンツタイプオプションã¯ç„¡è¦–ã•ã‚Œã¾ã™!\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: 警告 - 用紙オプションã¯ç„¡è¦–ã•ã‚Œã¾ã™!\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: 警告 - モードオプションã¯ç„¡è¦–ã•ã‚Œã¾ã™!\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr "%s: エラー - 環境変数 %s ãŒå­˜åœ¨ã—ãªã„宛先 \"%s\" を指ã—ã¦ã„ã¾ã™!\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: エラー - '-o' オプションã®ã‚ã¨ã«ã¯ オプション=値 ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr ""
+#~ "プリンタードライãƒãƒ¼ã‚’エクスãƒãƒ¼ãƒˆã™ã‚‹ã«ã¯ Samba ã®ãƒ‘スワードãŒå¿…è¦ã§ã™!"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr ""
+#~ "プリンタードライãƒãƒ¼ã‚’エクスãƒãƒ¼ãƒˆã™ã‚‹ã«ã¯ã€Samba ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼åãŒå¿…è¦ã§ã™!"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "\"%s\" ã¨ã„ã†åå‰ã®ã‚¯ãƒ©ã‚¹ã¯ã™ã§ã«å­˜åœ¨ã—ã¾ã™!"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "\"%s\" ã¨ã„ã†åå‰ã®ãƒ—リンターã¯ã™ã§ã«å­˜åœ¨ã—ã¾ã™!"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr "%s printer-state ã« ä¸æ­£ãªå€¤ %d を設定ã—よã†ã¨ã—ã¦ã„ã¾ã™!"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "属性グループã¯ç¯„囲外ã§ã™ (%x < %x)!"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "\"%s\" ã¯ç„¡åŠ¹ãªãƒ‡ãƒã‚¤ã‚¹ URI ã§ã™!\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "\"%s\" ã¯ç„¡åŠ¹ãª device-uri ã§ã™!"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "\"%s\" ã¯ç„¡åŠ¹ãª device-uri スキーマã§ã™!"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "\"%s\" ã¯ä¸æ­£ãª document-format ã§ã™!"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "ä¸æ­£ãªãƒ•ã‚¡ã‚¤ãƒ«åãƒãƒƒãƒ•ã‚¡ãƒ¼ã§ã™!"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "ä¸æ­£ãª job-priority 値ã§ã™!"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "\"%s\" ã¯ä¸æ­£ãª job-sheets 値ã§ã™!"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "ä¸æ­£ãª job-sheets 値タイプ ã§ã™!"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "ä¸æ­£ãª job-state 値ã§ã™!"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "\"%s\" ã¯ç„¡åŠ¹ãª job-uri 属性ã§ã™!"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "\"%s\" ã¯ç„¡åŠ¹ãª notify-pull-method ã§ã™!"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "URI \"%s\" ã¯ä¸æ­£ãª notify-recipient-uri ã§ã™!"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "%d è¡Œã«ä¸æ­£ãªã‚ªãƒ—ションã¨é¸æŠžãŒã‚ã‚Šã¾ã™!"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "\"%s\" ã¯ç„¡åŠ¹ãª port-monitor ã§ã™!"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "%d ã¯ç„¡åŠ¹ãª printer-state 値ã§ã™!"
+
+#~ msgid "Bad request ID %d!"
+#~ msgstr "%d ã¯ç„¡åŠ¹ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆIDã§ã™!"
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç•ªå· %d.%d ã¯ç„¡åŠ¹ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆã§ã™!"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "ä¸æ­£ãªã‚µãƒ–スクリプション ID ã§ã™!"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "文字セット \"%s\" ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“!"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "タイプ \"%s\" を検査ã§ãã¾ã›ã‚“ã§ã—ãŸ!"
+
+#~ msgid "Cover open."
+#~ msgstr "ã‚«ãƒãƒ¼ãŒé–‹ã„ã¦ã„ã¾ã™ã€‚"
+
+#~ msgid "Developer almost empty."
+#~ msgstr "ç¾åƒå‰¤ãŒç„¡ããªã‚Šã‹ã‘ã¦ã„ã¾ã™ã€‚"
+
+#~ msgid "Developer empty!"
+#~ msgstr "ç¾åƒå‰¤ãŒç„¡ããªã‚Šã¾ã—ãŸ!"
+
+#~ msgid "Door open."
+#~ msgstr "ドアãŒé–‹ã„ã¦ã„ã¾ã™ã€‚"
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: ä¸æ­£ãª %%BoundingBox: コメントãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: ä¸æ­£ãª %%IncludeFeature: コメントã§ã™!\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: ä¸æ­£ãª %%Page: コメントãŒãƒ•ã‚¡ã‚¤ãƒ«ã«ã‚ã‚Šã¾ã™!\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: ä¸æ­£ãª %%PageBoundingBox: コメントãŒãƒ•ã‚¡ã‚¤ãƒ«ã«ã‚ã‚Šã¾ã™!\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: ä¸æ­£ãª SCSI デãƒã‚¤ã‚¹ãƒ•ã‚¡ã‚¤ãƒ« \"%s\" ã§ã™!\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: ä¸æ­£ãª columns 値 %d ã§ã™!\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: ä¸æ­£ãª cpi 値 %f ã§ã™!\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: ä¸æ­£ãª lpi 値 %f ã§ã™!\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: ä¸æ­£ãªãƒšãƒ¼ã‚¸è¨­å®šã§ã™!\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: é€ä¿¡å…ˆã®ãƒ—リンターãŒå­˜åœ¨ã—ã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: é‡è¤‡ã—㟠%%BoundingBox: コメントãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: é‡è¤‡ã—㟠%%Pages: コメントãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: 空ã®ãƒ—リントファイルã§ã™!\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr "ERROR: %d è¡Œ: %s ã«ã¯å¼•ç”¨ç¬¦ã§å›²ã¾ã‚ŒãŸæ–‡å­—列ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: 致命的㪠USB エラーã§ã™!\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr ""
+#~ "ERROR: 無効㪠HP-GL/2 コマンドãŒã‚ã‚Šã€ãƒ•ã‚¡ã‚¤ãƒ«ã‚’プリントã§ãã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: %%EndProlog ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: %%EndSetup ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: コマンドラインã«ãƒ‡ãƒã‚¤ã‚¹ URI ãŒè¦‹ã¤ã‹ã‚‰ãšã€ç’°å¢ƒå¤‰æ•° DEVICE_URI も見"
+#~ "ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: ãƒãƒŠãƒ¼ãƒ•ã‚¡ã‚¤ãƒ«ã® %d 行目ã«å€¤ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr "ERROR: %d è¡Œ: %s ã®ç¿»è¨³æ–‡å­—列ã®å‰ã« msgid è¡ŒãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: %%BoundingBox: コメントãŒã‚ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: %%Pages: コメントãŒãƒ˜ãƒƒãƒ€ãƒ¼ã«ã‚ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: argv[0] ã¾ãŸã¯ 環境変数 DEVICE_URI ã«ãƒ‡ãƒã‚¤ã‚¹ URI ãŒè¦‹ã¤ã‹ã‚Šã¾ã›"
+#~ "ã‚“!\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: ページãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: 用紙切れã§ã™!\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: PRINTER 環境変数ãŒå®šç¾©ã•ã‚Œã¦ã„ã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: プリントファイルãŒå—ã‘付ã‘られã¾ã›ã‚“ã§ã—㟠(%s)!\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: プリンターãŒå¿œç­”ã—ã¦ã„ã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: ジョブ %d ã®å±žæ€§ (%s) ã‚’å–å¾—ã§ãã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: プリンターã®ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ (%s) ã‚’å–å¾—ã§ãã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: プリンター '%s' ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“\"!\n"
+
+#~ msgid "ERROR: Unable to open PPD file!\n"
+#~ msgstr "ERROR: PPD ファイルを開ã‘ã¾ã›ã‚“!"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: å°åˆ·ã®ãŸã‚ã®ã‚¤ãƒ¡ãƒ¼ã‚¸ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é–‹ã‘ã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: テキストカラム %d をプリントã§ãã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: テキストページ %dx%d をプリントã§ãã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: プリントデータを読ã¿è¾¼ã‚ã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: プリントデータをé€ä¿¡ã§ãã¾ã›ã‚“ (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: プリントデータをé€ä¿¡ã§ãã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: %d ãƒã‚¤ãƒˆã‚’プリンターã«æ›¸ãè¾¼ã‚ã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr "ERROR: ラスターデータをドライãƒãƒ¼ã¸æ›¸ãè¾¼ã‚ã¾ã›ã‚“!\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: テンãƒãƒ©ãƒªãƒ¼ãƒ•ã‚¡ã‚¤ãƒ«ã¸æ›¸ãè¾¼ã‚ã¾ã›ã‚“"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: %d è¡Œ: %s ã¯äºˆæœŸã›ã¬ãƒ†ã‚­ã‚¹ãƒˆã§ã™!\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: \"%s\" ã¯æœªçŸ¥ã®æš—å·ã‚ªãƒ—ション値ã§ã™!\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: \"%s\" ã¯æœªçŸ¥ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚«ã‚¿ãƒ­ã‚°ã®æ›¸å¼ã§ã™!\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: \"%s\" (値 \"%s\") ã¯æœªçŸ¥ã®ã‚ªãƒ—ションã§ã™!\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: \"%s\" ã¯æœªçŸ¥ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚ªãƒ—ション値ã§ã™!\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr ""
+#~ "ERROR: %s ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„è¼åº¦å€¤ã§ã™ã€‚brightness=100 を使用ã—ã¾ã™!\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr ""
+#~ "ERROR: %s ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„ガンマ値ã§ã™ã€‚gamma=1000 を使用ã—ã¾ã™!\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr ""
+#~ "ERROR: %d ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„ number-up 値ã§ã™ã€‚number-up=1 を使用ã—ã¾"
+#~ "ã™!\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: %s ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„ number-up-layout 値ã§ã™ã€‚number-up-"
+#~ "layout=lrtb を使用ã—ã¾ã™!\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: %s ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„ page-border 値ã§ã™ã€‚page-border=none を使"
+#~ "用ã—ã¾ã™!\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr ""
+#~ "ERROR: doc_printf オーãƒãƒ¼ãƒ•ãƒ­ãƒ¼ (%d ãƒã‚¤ãƒˆ) ãŒæ¤œå‡ºã•ã‚Œã€ä¸­æ–­ã—ã¾ã—ãŸ!\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops ã¯ã‚·ã‚°ãƒŠãƒ« %d ã§çµ‚了ã—ã¾ã—ãŸ!\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops ã¯çŠ¶æ…‹ %d ã§çµ‚了ã—ã¾ã—ãŸ!\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: 回復å¯èƒ½: プリンターã«æŽ¥ç¶šã§ãã¾ã›ã‚“。30 秒後ã«å†è©¦è¡Œã—ã¾ã™...\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "PPD ファイルãŒç©ºã§ã™!"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "Error: '-h' オプションã®ã‚ã¨ã«ã¯ãƒ›ã‚¹ãƒˆåãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "定ç€å™¨ã®æ¸©åº¦ãŒä¸Šã£ã¦ã„ã¾ã™!"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "定ç€å™¨ã®æ¸©åº¦ãŒä¸‹ã£ã¦ã„ã¾ã™!"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "printer-uri 属性をå–å¾—ã—ã¾ã—ãŸãŒã€job-id ã‚’å–å¾—ã§ãã¾ã›ã‚“ã§ã—ãŸ!"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "インクã¾ãŸã¯ãƒˆãƒŠãƒ¼ãŒã»ã¨ã‚“ã©ã‚ã‚Šã¾ã›ã‚“。"
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "インクã¾ãŸã¯ãƒˆãƒŠãƒ¼ãŒã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "廃インクã¾ãŸã¯å»ƒãƒˆãƒŠãƒ¼å®¹å™¨ãŒã»ã¨ã‚“ã©ä¸€æ¯ã§ã™ã€‚"
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "廃インクã¾ãŸã¯å»ƒãƒˆãƒŠãƒ¼å®¹å™¨ãŒä¸€æ¯ã§ã™!"
+
+#~ msgid "Interlock open."
+#~ msgstr "インターロックãŒé–‹ã„ã¦ã„ã¾ã™ã€‚"
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "ã‚¸ãƒ§ãƒ–ç•ªå· %d ã‚’å†é–‹ã§ãã¾ã›ã‚“ - ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "ã‚¸ãƒ§ãƒ–ç•ªå· %d ã¯å­˜åœ¨ã—ã¾ã›ã‚“!"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "ã‚¸ãƒ§ãƒ–ç•ªå· %d ã¯ã™ã§ã«çµ‚了ã—ã€å¤‰æ›´ã§ãã¾ã›ã‚“!"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "ã‚¸ãƒ§ãƒ–ç•ªå· %d ã¯å®Œäº†ã—ã¦ã„ã¾ã›ã‚“!"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "ã‚¸ãƒ§ãƒ–ç•ªå· %d ã¯èªè¨¼ã®ãŸã‚ã«ä¿ç•™ã•ã‚Œã¦ã„ã¾ã›ã‚“!"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "ã‚¸ãƒ§ãƒ–ç•ªå· %d ã¯ä¿ç•™ã•ã‚Œã¦ã„ã¾ã›ã‚“!"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "ã‚¸ãƒ§ãƒ–ç•ªå· #%s ã¯å­˜åœ¨ã—ã¾ã›ã‚“!"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "ã‚¸ãƒ§ãƒ–ç•ªå· %d ã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "ジョブサブスクリプションãŒæ›´æ–°ã§ãã¾ã›ã‚“!"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "言語 \"%s\" ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“!"
+
+#~ msgid "Media jam!"
+#~ msgstr "紙詰ã¾ã‚Šã§ã™!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "用紙トレイãŒç©ºã«ãªã‚Šã‹ã‘ã¦ã„ã¾ã™ã€‚"
+
+#~ msgid "Media tray empty!"
+#~ msgstr "用紙トレイãŒç©ºã«ãªã‚Šã¾ã—ãŸ!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "用紙トレイãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "用紙トレイã«è£œå……ãŒå¿…è¦ã§ã™ã€‚"
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "document-number 属性ãŒã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "%d è¡Œã«äºŒé‡å¼•ç”¨ç¬¦ãŒã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "form 変数ãŒã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "notify-subscription-ids 属性ãŒã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "requesting-user-name 属性ãŒè¨­å®šã•ã‚Œã¦ã„ã¾ã›ã‚“!"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "å¿…é ˆã®å±žæ€§ãŒè¨­å®šã•ã‚Œã¦ã„ã¾ã›ã‚“!"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "%d è¡Œã«å€¤ãŒã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "No PPD name!"
+#~ msgstr "PPD ã®åå‰ãŒã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Windows プリンタードライãƒãƒ¼ãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚Œã¦ã„ã¾ã›ã‚“!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "%s ã«ã¯ã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªã‚¸ãƒ§ãƒ–ã¯ã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "リクエストã«å±žæ€§ãŒã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "èªè¨¼æƒ…å ±ãŒæä¾›ã•ã‚Œã¦ã„ã¾ã›ã‚“!"
+
+#~ msgid "No file!?!"
+#~ msgstr "ファイルãŒã‚ã‚Šã¾ã›ã‚“!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "変更時刻ãŒã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "No printer name!"
+#~ msgstr "プリンターåãŒã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "クラスã®ãƒ—リンターURI ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "プリンターURI ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "プリンターURI ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆãŒã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "リクエストã«ã‚µãƒ–スクリプション属性ãŒã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC ã¯ã‚‚ã†ã™ã交æ›ãŒå¿…è¦ã«ãªã‚Šã¾ã™ã€‚"
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC ã¯äº¤æ›æ™‚期ã§ã™!"
+
+#~ msgid "Out of toner!"
+#~ msgstr "トナー切れã§ã™!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "排紙トレイãŒã»ã¨ã‚“ã©ä¸€æ¯ã§ã™ã€‚"
+
+#~ msgid "Output bin full!"
+#~ msgstr "排紙トレイãŒä¸€æ¯ã§ã™!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "排紙トレイãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "Printer offline."
+#~ msgstr "プリンターã¯ã‚ªãƒ•ãƒ©ã‚¤ãƒ³ã§ã™ã€‚"
+
+#~ msgid "SCSI Printer"
+#~ msgstr "SCSI プリンター"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "notify-user-data 値ãŒå¤§ãã™ãŽã¾ã™ (%d > 63 オクテット)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "プリンターã¾ãŸã¯ã‚¯ãƒ©ã‚¹ã¯å…±æœ‰ã§ãã¾ã›ã‚“!"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "printer-uri 属性ã¯å¿…é ˆã§ã™!"
+
+#~ msgid "Toner low."
+#~ msgstr "トナーãŒå°‘ãªããªã£ã¦ã„ã¾ã™ã€‚"
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "job-sheets 値ãŒå¤šã™ãŽã¾ã™ (%d > 2)!"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "printer-state-reasons 値ãŒå¤šã™ãŽã¾ã™ (%d > %d)!"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "宛先\"%s\"ã«ã‚¸ãƒ§ãƒ–を追加ã§ãã¾ã›ã‚“!"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "ファイルタイプ用ã«ãƒ¡ãƒ¢ãƒªã‚’割り当ã¦ã‚‰ã‚Œã¾ã›ã‚“!"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "64-bit 版㮠CUPS プリンタードライãƒãƒ¼ãƒ•ã‚¡ã‚¤ãƒ«ã‚’コピーã§ãã¾ã›ã‚“ (%d)!"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr "64-bit 版㮠Windows プリンタードライãƒãƒ¼ã‚’コピーã§ãã¾ã›ã‚“ (%d)!"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr "複数㮠CUPS プリンタードライãƒãƒ¼ãƒ•ã‚¡ã‚¤ãƒ«ã‚’コピーã§ãã¾ã›ã‚“ (%d)ï¼"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "PPD ファイルをコピーã§ãã¾ã›ã‚“ï¼ - %s"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "PPD ファイルをコピーã§ãã¾ã›ã‚“!"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "複数㮠Windows 2000 プリンタードライãƒãƒ¼ãƒ•ã‚¡ã‚¤ãƒ«ã‚’コピーã§ãã¾ã›ã‚“ (%d)!"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "複数㮠Windows 9x プリンタードライãƒãƒ¼ãƒ•ã‚¡ã‚¤ãƒ«ã‚’コピーã§ãã¾ã›ã‚“ (%d)!"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "インターフェイススクリプトをコピーã§ãã¾ã›ã‚“! - %s"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "printer-uri を作æˆã§ãã¾ã›ã‚“!"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr "1MB 以上㮠cupsd.conf ファイルã¯ç·¨é›†ã§ãã¾ã›ã‚“!"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "ジョブã®å®›å…ˆãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "プリンターãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "複数㮠Windows 2000 プリンタードライãƒãƒ¼ãƒ•ã‚¡ã‚¤ãƒ«ã‚’インストールã§ãã¾ã›ã‚“ "
+#~ "(%d)!"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "複数㮠Windows 9x プリンタードライãƒãƒ¼ãƒ•ã‚¡ã‚¤ãƒ«ã‚’インストールã§ãã¾ã›ã‚“ (%"
+#~ "d)!"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "ドキュメント %d (ジョブ %d)ã‚’é–‹ã‘ã¾ã›ã‚“!"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "プリンタードライãƒãƒ¼ã«ã‚³ãƒžãƒ³ãƒ‰ã‚’é€ä¿¡ã§ãã¾ã›ã‚“!"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Windows プリンタードライãƒãƒ¼ã‚’設定ã§ãã¾ã›ã‚“ (%d)!"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "å¤ã„タイプ㮠USB クラスドライãƒãƒ¼ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“!\n"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "\"%s\" ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„文字セットã§ã™!"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "\"%s\" ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„圧縮形å¼ã§ã™!"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "%s ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„圧縮属性ã§ã™!"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "\"%s\" ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„å½¢å¼ã§ã™!"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "'%s' ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„å½¢å¼ã§ã™!"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "'%s/%s' ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„å½¢å¼ã§ã™!"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+#~ "translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "使ã„æ–¹: cupstestppd [オプション] filename1.ppd[.gz] [... filenameN.ppd[."
+#~ "gz]]\n"
+#~ " program | cupstestppd [オプション] -\n"
+#~ "\n"
+#~ "オプション:\n"
+#~ "\n"
+#~ " -R root-directory é•ã†ãƒ«ãƒ¼ãƒˆãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’指定\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+#~ "translations}\n"
+#~ " 指定ã•ã‚ŒãŸã‚‚ã®ã‚’エラーã®ä»£ã‚ã‚Šã«è­¦å‘Šã¨ã—ã¦æ‰±ã†\n"
+#~ " -q メッセージãªã—モードã§å‹•ã\n"
+#~ " -r 「リラックスã€ã‚ªãƒ¼ãƒ—ンモードã§é–‹ã\n"
+#~ " -v メッセージ多ã‚モード\n"
+#~ " -vv メッセージéžå¸¸ã«å¤šã‚モード\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: サイドãƒãƒ£ãƒ³ãƒãƒ«ã®èª­ã¿å‡ºã—ã«å¤±æ•—ã—ã¾ã—ãŸ!\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr ""
+#~ "WARNING: オプション \"%s\" 㯠IncludeFeature 経由ã§å«ã‚ã‚‹ã“ã¨ã¯ã§ãã¾ã›"
+#~ "ã‚“!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: リモートホスト㯠%d 秒経ã£ã¦ã‚‚コマンド・ステータス・ãƒã‚¤ãƒˆã‚’è¿”ã—"
+#~ "ã¾ã›ã‚“ã§ã—ãŸ!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: リモートホスト㯠%d 秒経ã£ã¦ã‚‚コントロール・ステータス・ãƒã‚¤ãƒˆã‚’"
+#~ "è¿”ã—ã¾ã›ã‚“ã§ã—ãŸ!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: リモートホスト㯠%d 秒経ã£ã¦ã‚‚データ・ステータス・ãƒã‚¤ãƒˆã‚’è¿”ã—ã¾"
+#~ "ã›ã‚“ã§ã—ãŸ!\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr "WARNING: SCSI コマンドã¯ã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã—ã¾ã—㟠(%d)。å†è©¦è¡Œä¸­...\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: ã“ã®æ›¸é¡žã¯ Adobe Document Structuring Conventions ã«é©åˆã—ã¦ãŠã‚‰"
+#~ "ãšã€æ­£ã—ãプリントã§ããªã„å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: \"%s\" (オプション \"%s\" 用) ã¯æœªçŸ¥ã®è¨­å®šã§ã™!\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: \"%s\" ã¯æœªçŸ¥ã®ã‚ªãƒ—ションã§ã™!\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: %s ã¯ã‚µãƒãƒ¼ãƒˆã—ãªã„ボーレートã§ã™!\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: 回復å¯èƒ½: ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ›ã‚¹ãƒˆ '%s' ã¯ãƒ“ジー状態ã§ã™ (%d 秒後ã«å†è©¦"
+#~ "è¡Œã—ã¾ã™...)\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr ""
+#~ "警告ã€Windows 2000 プリンタードライãƒãƒ¼ãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚Œã¦ã„ã¾ã›ã‚“!"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: \"%s\" ã¯æœªçŸ¥ã®ã‚ªãƒ—ションã§ã™!\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: \"-%c\"ã¯æœªçŸ¥ã®ã‚ªãƒ—ションã§ã™!\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr "cupsd: -c オプションã®ã‚ã¨ã«ã¯è¨­å®šãƒ•ã‚¡ã‚¤ãƒ«åãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: カレント・ディレクトリをå–å¾—ã§ãã¾ã›ã‚“!\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: \"%s\" ã¯æœªçŸ¥ã®å¼•æ•°ã§ã™ - åœæ­¢ã—ã¾ã™!\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: \"%c\" ã¯æœªçŸ¥ã®ã‚ªãƒ—ションã§ã™ - åœæ­¢ã—ã¾ã™!\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: ä¸æ­£ãªæ–‡æ›¸ç•ªå· %d ã§ã™!\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: ä¸æ­£ãªã‚¸ãƒ§ãƒ–ID %d ã§ã™!\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: ã²ã¨ã¤ã®ãƒ•ã‚¡ã‚¤ãƒ«åã®ã¿ã‚’指定ã§ãã¾ã™!\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "job-printer-uri 属性ãŒã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr "lpadmin: クラスåã¯è¡¨ç¤ºå¯èƒ½æ–‡å­—ã®ã¿ã§æ§‹æˆã•ã‚Œãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: '-P' オプションã®ã‚ã¨ã« PPD ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr ""
+#~ "lpadmin: '-u' オプションã®ã‚ã¨ã«ã¯ allow/deny:ユーザーリスト ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: '-r' オプションã®ã‚ã¨ã«ã¯ã‚¯ãƒ©ã‚¹åãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: '-c' オプションã®ã‚ã¨ã«ã¯ã‚¯ãƒ©ã‚¹åãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: '-D' オプションã®ã‚ã¨ã«èª¬æ˜ŽãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: '-v' オプションã®ã‚ã¨ã«ã¯ãƒ‡ãƒã‚¤ã‚¹ URI ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: '-I' オプションã®ã‚ã¨ã«ãƒ•ã‚¡ã‚¤ãƒ«å½¢å¼ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: '-h' オプションã®ã‚ã¨ã«ã¯ãƒ›ã‚¹ãƒˆåãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: '-i' オプションã®ã‚ã¨ã«ã¯ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ã‚¤ã‚¹åãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: '-L' オプションã®ã‚ã¨ã«å ´æ‰€ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: '-m' オプションã®ã‚ã¨ã«ã¯ãƒ¢ãƒ‡ãƒ«åãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: '-o' オプションã®ã‚ã¨ã«ã¯ 変数å=値 ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: '-p' オプションã®ã‚ã¨ã«ã¯ãƒ—リンターåãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: '-d' オプションã®ã‚ã¨ã«ã¯ãƒ—リンターåãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr ""
+#~ "lpadmin: '-x' オプションã®ã‚ã¨ã«ã¯ãƒ—リンターåã¾ãŸã¯ã‚¯ãƒ©ã‚¹åãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: メンãƒãƒ¼åãŒè¦‹å½“ãŸã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr "lpadmin: プリンターåã«ã¯å°å­—å¯èƒ½ãªæ–‡å­—ã®ã¿ä½¿ç”¨ã§ãã¾ã™!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: クラスã«ãƒ—リンターを追加ã§ãã¾ã›ã‚“:\n"
+#~ " å…ˆã«ãƒ—リンターåを指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: クラスã‹ã‚‰ãƒ—リンターを削除ã§ãã¾ã›ã‚“:\n"
+#~ " å…ˆã«ãƒ—リンターåを指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: PPD ファイルを設定ã§ãã¾ã›ã‚“:\n"
+#~ " å…ˆã«ãƒ—リンターåを指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: デãƒã‚¤ã‚¹ URI を設定ã§ãã¾ã›ã‚“:\n"
+#~ " å…ˆã«ãƒ—リンターåを指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: インターフェイス・スクリプトã¾ãŸã¯ PPD ファイルを設定ã§ãã¾ã›"
+#~ "ã‚“:\n"
+#~ " å…ˆã«ãƒ—リンターåを指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: インターフェイススクリプトを設定ã§ãã¾ã›ã‚“:\n"
+#~ " å…ˆã«ãƒ—リンターåを指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: プリンターã®èª¬æ˜Žã‚’設定ã§ãã¾ã›ã‚“:\n"
+#~ " å…ˆã«ãƒ—リンターåを指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: プリンターã®å ´æ‰€ãŒè¨­å®šã§ãã¾ã›ã‚“:\n"
+#~ " å…ˆã«ãƒ—リンターåを指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: プリンター・オプションを設定ã§ãã¾ã›ã‚“:\n"
+#~ " å…ˆã«ãƒ—リンターåを指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin:\"%s\" ã¯æœªçŸ¥ã® allow/deny オプションã§ã™!\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: '%s' ã¯æœªçŸ¥ã®å¼•æ•°ã§ã™!\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: '%c' ã¯æœªçŸ¥ã®ã‚ªãƒ—ションã§ã™!\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin: 警告 - コンテンツタイプリストã¯ç„¡è¦–ã•ã‚Œã¾ã™!\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr ""
+#~ "lpinfo: --device-id ã®å¾Œã«ã¯ã€1284デãƒã‚¤ã‚¹IDを指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: --language ã®å¾Œã«ã¯ã€è¨€èªžã‚’指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr ""
+#~ "lpinfo: --make-and-model ã®å¾Œã«ã¯ã€ãƒ¡ãƒ¼ã‚«ãƒ¼ã¨ãƒ¢ãƒ‡ãƒ«ã‚’指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾"
+#~ "ã™!\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo: --product ã®å¾Œã«ã¯ã€è£½å“åを指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr ""
+#~ "lpinfo: --exclude-schemes ã®å¾Œã«ã¯ã€ã‚¹ã‚­ãƒ¼ãƒžãƒ»ãƒªã‚¹ãƒˆã‚’指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾"
+#~ "ã™!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr ""
+#~ "lpinfo: --include-schemes ã®å¾Œã«ã¯ã€ã‚¹ã‚­ãƒ¼ãƒžãƒ»ãƒªã‚¹ãƒˆã‚’指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾"
+#~ "ã™!\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr ""
+#~ "lpinfo: --timeout ã®å¾Œã«ã¯ã€ã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆå€¤ã‚’指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: 未知ã®å¼•æ•° '%s'!\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: 未知ã®ã‚ªãƒ—ション '%c'!\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: 未知ã®ã‚ªãƒ—ション '%s'!\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: 未知ã®å¼•æ•° '%s'!\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: 未知ã®ã‚ªãƒ—ション '%c'!\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: プリンターãŒã‚ã‚Šã¾ã›ã‚“!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: %s ã® PPD ファイルを開ã‘ã¾ã›ã‚“!\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: 未知ã®ãƒ—リンターã¾ãŸã¯ã‚¯ãƒ©ã‚¹ã§ã™!\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: root ã ã‘ãŒãƒ‘スワードã®è¿½åŠ ã¨å‰Šé™¤ã‚’è¡Œãˆã¾ã™!\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: パスワードファイルãŒãƒ“ジー状態ã§ã™!\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: パスワードファイルã¯æ›´æ–°ã•ã‚Œã¾ã›ã‚“!\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: ã™ã¿ã¾ã›ã‚“ãŒã€ãƒ‘スワードãŒãƒžãƒƒãƒã—ã¾ã›ã‚“!\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: ã™ã¿ã¾ã›ã‚“ãŒã€ãƒ‘スワードãŒãƒžãƒƒãƒã—ã¾ã›ã‚“!\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: エラー - 環境変数 %s ãŒã€å­˜åœ¨ã—ãªã„宛先 \"%s\" を指ã—ã¦ã„ã¾ã™!\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-events ãŒæŒ‡å®šã•ã‚Œã¦ã„ã¾ã›ã‚“!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "notify-recipient-uri URI \"%s\" ã¯ã™ã§ã«ä½¿ã‚ã‚Œã¦ã„ã¾ã™!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "notify-recipient-uri URI \"%s\" ã«ã¯æœªçŸ¥ã®ã‚¹ã‚­ãƒ¼ãƒ ãŒä½¿ã‚ã‚Œã¦ã„ã¾ã™!"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d ã¯è‰¯ãã‚ã‚Šã¾ã›ã‚“!"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: ä¸æ­£ãª resolution å \"%s\" ãŒã‚ã‚Šã¾ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s !\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: ä¸æ­£ãª status キーワード %s ãŒã‚ã‚Šã¾ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s !\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã§ã€Option ãŒãªã„ã®ã« Choice ãŒè¦‹ã¤ã‹ã‚Šã¾ã—"
+#~ "ãŸ!\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: locale %s ã«å¯¾ã—㦠#po ãŒ2é‡ã«å®šç¾©ã•ã‚Œã¦ã„ã¾ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å "
+#~ "%s !\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„ã¦ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼å®šç¾©ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„ã¦ãƒ—ログラムåãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠Font ã®å¾Œã« charset ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠ColorModel ã«å¯¾ã™ã‚‹ color order ãŒå¿…"
+#~ "è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠ColorModel ã«å¯¾ã™ã‚‹ colorspace ãŒå¿…"
+#~ "è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠ColorModel ã«å¯¾ã™ã‚‹ compression ãŒå¿…"
+#~ "è¦ã§ã™!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠UIConstraints ã«å¯¾ã™ã‚‹ constraint ãŒ"
+#~ "å¿…è¦ã§ã™!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠DriverType ã®å¾Œã« driver type "
+#~ "keyword ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠Duplex ã®å¾Œã« type ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠Font ã®å¾Œã« encoding ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc: #po %s ã®å¾Œã«ãƒ•ã‚¡ã‚¤ãƒ«åãŒå¿…è¦ã§ã™! (%d 行目, ファイル %s)\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠group name/text ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠include ファイルåãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„ã¦æ•´æ•°æŒ‡å®šãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠#po ã®å¾Œã« locale ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: %s ã®å¾Œã« name ãŒå¿…è¦ã§ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s!\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠FileName ã®å¾Œã« name ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠Font ã®å¾Œã« name ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠Manufacturer ã®å¾Œã« name ãŒå¿…è¦ã§"
+#~ "ã™!\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠MediaSize ã®å¾Œã« name ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠ModelName ã®å¾Œã« name ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠PCFileName ã®å¾Œã« name ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: %s ã®å¾Œã« name/text ãŒå¿…è¦ã§ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠Installable ã®å¾Œã« name/text ãŒå¿…è¦"
+#~ "ã§ã™!\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠Resolution ã®å¾Œã« name/text ãŒå¿…è¦ã§"
+#~ "ã™!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠ColorModel ã«å¯¾ã™ã‚‹ name/text ãŒå¿…è¦"
+#~ "ã§ã™!\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠option name/text ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠option section ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠option type ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠Resolution ã®å¾Œã« override field ãŒ"
+#~ "å¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„ã¦å®Ÿæ•°ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠ColorProfile ã«ç¶šã„㦠resolution/"
+#~ "mediatype ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠SimpleColorProfile ã«ç¶šã„㦠"
+#~ "resolution/mediatype ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: %s ã®å¾Œã« selector ãŒå¿…è¦ã§ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s!\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠Font ã®å¾Œã« status ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠Copyright ã®å¾Œã«æ–‡å­—列ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠Version ã®å¾Œã«æ–‡å­—列ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠2 ã¤ã®ã‚ªãƒ—ションåãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: %s ã®å¾Œã« value ãŒå¿…è¦ã§ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s!\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠Font ã®å¾Œã« version ãŒå¿…è¦ã§ã™!\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: 無効㪠#include/#po ファイルåã§ã™ \"%s\"!\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„ã¦ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã«å¯¾ã™ã‚‹ç„¡åŠ¹ãª cost ãŒã‚ã‚Š"
+#~ "ã¾ã™!\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„ã¦ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã«å¯¾ã™ã‚‹ç„¡åŠ¹ãªç©ºã® MIME "
+#~ "type ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„ã¦ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã«å¯¾ã™ã‚‹ç„¡åŠ¹ãªç©ºã® program "
+#~ "name ãŒã‚ã‚Šã¾ã™!\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: 無効㪠option section ãŒã‚ã‚Šã¾ã™ \"%s\"。%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s!\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: 無効㪠option type ãŒã‚ã‚Šã¾ã™ \"%s\"。%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s!\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: \"%s\" ã®æœ€å¾Œã« #endif ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠#if ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc: ロケール %s ã«å¯¾ã™ã‚‹ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚«ã‚¿ãƒ­ã‚°ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“!\n"
+
+#~ msgid "ppdc: Option %s defined in two different groups on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: オプション %s ãŒè¡Œ %dã€ãƒ•ã‚¡ã‚¤ãƒ« %s ã® 2 ã¤ã®ç•°ãªã‚‹ã‚°ãƒ«ãƒ¼ãƒ—ã§å®šç¾©ã•ã‚Œ"
+#~ "ã¦ã„ã¾ã™!\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: オプション %s ã¯ç•°ãªã‚‹åž‹ã§å†å®šç¾©ã•ã‚Œã¦ã„ã¾ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠Option constraint 㯠*name ã§æŒ‡å®šã—"
+#~ "ã¾ã™!\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: %d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s ã«ãŠã„㦠#if ã®ãƒã‚¹ãƒˆãŒå¤šã™ãŽã¾ã™!\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: #po ファイル %s ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s!\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: インクルードファイル %s ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s!\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: %s ã¯æœªçŸ¥ã®ãƒ‰ãƒ©ã‚¤ãƒãƒ¼ã‚¿ã‚¤ãƒ—ã§ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s。\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: \"%s\" ã¯æœªçŸ¥ã®ä¸¡é¢ã‚¿ã‚¤ãƒ—ã§ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s!\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: \"%s\" ã¯æœªçŸ¥ã®ç”¨ç´™ã‚µã‚¤ã‚ºã§ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s!\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: 未知㮠token \"%s\" ãŒã‚ã‚Šã¾ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: 実数ã«æœªçŸ¥ã®çµ‚了文字 \"%s\" ãŒã‚ã‚Šã¾ã™ã€‚%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %s!\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %c ã§å§‹ã¾ã‚‹æ–‡å­—ã«å¯¾ã—ã¦çµ‚端文字ãŒã‚ã‚Šã¾ã›ã‚“。%d 行目ã€ãƒ•ã‚¡ã‚¤ãƒ«å %"
+#~ "s!\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: ä¸æ­£ãª LanguageVersion \"%s\" ㌠%s ã«ã‚ã‚Šã¾ã™!\n"
diff --git a/locale/cups_ko.po b/locale/cups_ko.po
new file mode 100644
index 000000000..af6765880
--- /dev/null
+++ b/locale/cups_ko.po
@@ -0,0 +1,7068 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-16 12:00-0800\n"
+"Last-Translator: Apple Inc.\n"
+"Language-Team: Apple Inc.\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(ì „ì²´)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(ì—†ìŒ)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%dê°œì˜ ì—”íŠ¸ë¦¬\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\t결함 후: 계ì†\n"
+
+msgid "\tAlerts:"
+msgstr "\t경고:"
+
+msgid "\tBanner required\n"
+msgstr "\t배너 필요함\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\të¬¸ìž ì„¸íŠ¸ 설정:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tì—°ê²°: ì§ì ‘\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tì—°ê²°: ì›ê²©\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\t기본 페ì´ì§€ í¬ê¸°:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\t기본 피치:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\t기본 í¬íŠ¸ 설정:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\t설명: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\t구성 마운트ë¨:\n"
+"\t콘í…츠 유형: 모ë‘\n"
+"\t프린터 유형: ì•Œ 수 ì—†ìŒ\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\t구성 허용ë¨:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tì¸í„°íŽ˜ì´ìŠ¤: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tì¸í„°íŽ˜ì´ìŠ¤: %s/ì¸í„°íŽ˜ì´ìŠ¤/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tì¸í„°íŽ˜ì´ìŠ¤: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\t위치: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\t결함 시: 경고 안 함\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tì‚¬ìš©ìž í—ˆìš©ë¨:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tì‚¬ìš©ìž ê±°ë¶€ë¨:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\të°ëª¬ 표시\n"
+
+msgid "\tno entries\n"
+msgstr "\t엔트리 ì—†ìŒ\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\t프린터가 '%s' 스피드 -1 ìž¥ë¹„ì— ìžˆìŠµë‹ˆë‹¤\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\t프린트가 비활성화ë˜ì—ˆìŠµë‹ˆë‹¤\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\t프린트가 활성화ë˜ì—ˆìŠµë‹ˆë‹¤\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\t%sì— ëŒ€í•œ 대기열\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tëŒ€ê¸°ì—´ì´ ë¹„í™œì„±í™”ë˜ì—ˆìŠµë‹ˆë‹¤\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tëŒ€ê¸°ì—´ì´ í™œì„±í™”ë˜ì—ˆìŠµë‹ˆë‹¤\n"
+
+msgid "\treason unknown\n"
+msgstr "\tì•Œ 수 없는 ì´ìœ \n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" ì í•© 테스트 ìƒì„¸ ê²°ê³¼\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " REF: 15페ì´ì§€, 섹션 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " REF: 15페ì´ì§€, 섹션 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " REF: 19페ì´ì§€, 섹션 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " REF: 20페ì´ì§€, 섹션 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " REF: 27페ì´ì§€, 섹션 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " REF: 42페ì´ì§€, 섹션 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " REF: 16-17페ì´ì§€, 섹션 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " REF: 42-45페ì´ì§€, 섹션 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " REF: 45-46페ì´ì§€, 섹션 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " REF: 48-49페ì´ì§€, 섹션 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " REF: 52-54페ì´ì§€, 섹션 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0fë°”ì´íŠ¸\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " PASS Default%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " PASS DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " PASS DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " PASS FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " PASS FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " PASS LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " PASS LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " PASS Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " PASS ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " PASS NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " PASS PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " PASS PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " PASS PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " PASS PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " PASS Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " PASS ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" WARN \"%s %s\"ì´(ê°€) \"%s %s\"와(ê³¼) 충ëŒí•©ë‹ˆë‹¤\n"
+" (제한=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" WARN %sì´(ê°€) %s와(ê³¼) ì¼ë°˜ì ì¸ ì ‘ë‘어를 공유합니다\n"
+" REF: 15페ì´ì§€, 섹션 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" WARN PPD 4.3 ì‚¬ì–‘ì€ LanguageEncodingì´ í•„ìš”í•©ë‹ˆë‹¤.\n"
+" REF: 56-57페ì´ì§€, 섹션 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" WARN PPD 4.3 ì‚¬ì–‘ì€ Manufacturerì´ í•„ìš”í•©ë‹ˆë‹¤.\n"
+" REF: 58-59페ì´ì§€, 섹션 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" WARN PPD ì‚¬ì–‘ì— ìœ„ë°˜ë˜ëŠ” 8.3 ì´ìƒì˜ PCFileName.\n"
+" REF: 61-62페ì´ì§€, 섹션 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN í”„ë¡œí† ì½œì€ PJLì„ í¬í•¨í•˜ì§€ë§Œ JCL ì†ì„±ì€ 설정ë˜ì§€ 않았습니다.\n"
+" REF: 78-79페ì´ì§€, 섹션 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN í”„ë¡œí† ì½œì€ PJL ë° BCP를 ëª¨ë‘ í¬í•¨í•©ë‹ˆë‹¤; TBCP 예ìƒë¨.\n"
+" REF: 78-79페ì´ì§€, 섹션 5.7.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" WARN PPD 4.3 ì‚¬ì–‘ì€ ShortNickNameì´ í•„ìš”í•©ë‹ˆë‹¤.\n"
+" REF: 64-65페ì´ì§€, 섹션 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s \"%s\" cupsFilter 파ì¼ì´ 유실ë¨\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s \"%s\" cupsPreFilter íŒŒì¼ ìœ ì‹¤ë¨\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** ìž˜ëª»ëœ Default%s %s\n"
+" REF: 40페ì´ì§€, 섹션 4.5.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **FAIL** 파ì¼ì— 있는 ìž˜ëª»ëœ JobPatchFile ì†ì„±\n"
+" REF: 24페ì´ì§€, 섹션 3.4.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** ìž˜ëª»ëœ Manufacturer(\"HP\"ì´ì–´ì•¼ 함)\n"
+" REF: 211페ì´ì§€, í‘œ D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** ìž˜ëª»ëœ Manufacturer(\"Oki\"ì´ì–´ì•¼ 함)\n"
+" REF: 211페ì´ì§€, í‘œ D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** ìž˜ëª»ëœ ModelName - \"%c\"ì€(는) 스트ë§ì—ì„œ 허용ë˜ì§€ 않습니"
+"다.\n"
+" REF: 59-60페ì´ì§€, 섹션 5.3.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** ìž˜ëª»ëœ PSVersion - \"(string) int\"ì´(ê°€) 아닙니다.\n"
+" REF: 62-64페ì´ì§€, 섹션 5.3.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** ìž˜ëª»ëœ Product - \"(string)\"ì´(ê°€) 아닙니다.\n"
+" REF: 62페ì´ì§€, 섹션 5.3.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** ìž˜ëª»ëœ ShortNickName - 31ìžë³´ë‹¤ ê¹ë‹ˆë‹¤.\n"
+" REF: 64-65페ì´ì§€, 섹션 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** ìž˜ëª»ëœ FileVersion \"%s\"\n"
+" REF: 56페ì´ì§€, 섹션 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** ìž˜ëª»ëœ FormatVersion \"%s\"\n"
+" REF: 56페ì´ì§€, 섹션 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr " **FAIL** 기본 옵션 코드를 í•´ì„í•  수 없습니다: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** Default%s í•„ìš”\n"
+" REF: 40페ì´ì§€, 섹션 4.5.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** DefaultImageableArea í•„ìš”\n"
+" REF: 102페ì´ì§€, 섹션 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** DefaultPaperDimension í•„ìš”\n"
+" REF: 103페ì´ì§€, 섹션 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** FileVersion í•„ìš”\n"
+" REF: 56페ì´ì§€, 섹션 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** FormatVersion í•„ìš”\n"
+" REF: 56페ì´ì§€, 섹션 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** %s PageSizeì— ëŒ€í•œ ImageableArea í•„ìš”\n"
+" REF: 41페ì´ì§€, 섹션 5.\n"
+" REF: 102페ì´ì§€, 섹션 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **FAIL** LanguageEncoding í•„ìš”\n"
+" REF: 56-57페ì´ì§€, 섹션 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **FAIL** LanguageVersion í•„ìš”\n"
+" REF: 57-58페ì´ì§€, 섹션 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **FAIL** Manufacturer í•„ìš”\n"
+" REF: 58-59페ì´ì§€, 섹션 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** ModelName í•„ìš”\n"
+" REF: 59-60페ì´ì§€, 섹션 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **FAIL** NickName í•„ìš”\n"
+" REF: 60페ì´ì§€, 섹션 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **FAIL** PCFileName í•„ìš”\n"
+" REF: 61-62페ì´ì§€, 섹션 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** PSVersion í•„ìš”\n"
+" REF: 62-64페ì´ì§€, 섹션 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **FAIL** PageRegion í•„ìš”\n"
+" REF: 100페ì´ì§€, 섹션 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **FAIL** PageSize í•„ìš”\n"
+" REF: 41페ì´ì§€, 섹션 5.\n"
+" REF: 99페ì´ì§€, 섹션 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **FAIL** PageSize í•„ìš”\n"
+" REF: 99-100페ì´ì§€, 섹션 5.14.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** %s PageSizeì— ëŒ€í•œ PaperDimension í•„ìš”\n"
+" REF: 41페ì´ì§€, 섹션 5.\n"
+" REF: 103페ì´ì§€, 섹션 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** Product í•„ìš”\n"
+" REF: 62페ì´ì§€, 섹션 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** ShortNickName í•„ìš”\n"
+" REF: 64-65페ì´ì§€, 섹션 5.3.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " %dê°œì˜ ì˜¤ë¥˜ 발견\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " ë°œê²¬ëœ ì˜¤ë¥˜ ì—†ìŒ\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " FAIL\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** PPD 파ì¼ì„ ì—´ 수 ì—†ìŒ - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** PPD 파ì¼ì„ ì—´ 수 ì—†ìŒ - %s, %d번째 줄.\n"
+
+msgid " PASS\n"
+msgstr " PASS\n"
+
+msgid "#10 Envelope"
+msgstr "#10 봉투"
+
+msgid "#11 Envelope"
+msgstr "#11 봉투"
+
+msgid "#12 Envelope"
+msgstr "#12 봉투"
+
+msgid "#14 Envelope"
+msgstr "#14 봉투"
+
+msgid "#9 Envelope"
+msgstr "#9 봉투"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0fë°”ì´íŠ¸\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0fë°”ì´íŠ¸\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0fmm"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f~%.0f x %.0fmm"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2fì¸ì¹˜"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f~%.2f x %.2fì¸ì¹˜"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr " %2$s ì´í›„ì— %1$s ìŠ¹ì¸ ìš”ì²­\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%sì„(를) 변경할 수 없습니다."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "CUPS ë²„ì „ì˜ lpc로는 %sì´(ê°€) 실행ë˜ì§€ 않습니다.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%sì´(ê°€) 준비ë˜ì§€ ì•ŠìŒ\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%sì´(ê°€) 준비ë¨\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%sì´(ê°€) 준비ë˜ì—ˆê³  프린트 중\n"
+
+#, fuzzy, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%2$s ì´í›„ì— %1$s ìŠ¹ì¸ ìš”ì²­ 안 함 -\n"
+"\t%1$s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%3$s ì´í›„ì— %1$s/%2$s ìŠ¹ì¸ ìš”ì²­\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%3$s ì´í›„ì— %1$s/%2$s ìŠ¹ì¸ ìš”ì²­ 안 함 -\n"
+"\t%4$s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [작업 %d 로컬호스트]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s 실패: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: 오류 - 사용 가능한 기본 대ìƒì´ 없습니다.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: 오류 - 우선순위는 1ì—ì„œ 100사ì´ì—¬ì•¼ 합니다.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: 오류 - 너무 ë§Žì€ íŒŒì¼ - \"%s\"\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: 오류 - \"%s\"ì— ì—°ê²°í•  수 ì—†ìŒ - %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s: 오류 - stdinì—ì„œ 대기할 수 ì—†ìŒ - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: \"%s\" 필터를 사용할 수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: 유효하지 ì•Šì€ í•„í„° 문ìžì—´ \"%s\"\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: ìž‘ë™ ì‹¤íŒ¨: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: ì„œë²„ì— ì—°ê²°í•  수 ì—†ìŒ\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: %sì„(를) ì—´ 수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: PPD 파ì¼ì„ ì—´ 수 ì—†ìŒ: %s, %d번째 줄\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: 오류 - 사용 가능한 기본 대ìƒì´ 없습니다.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1ì¸ì¹˜/ì´ˆ"
+
+msgid "1.25x0.25\""
+msgstr "1.25x0.25\""
+
+msgid "1.25x2.25\""
+msgstr "1.25x2.25\""
+
+msgid "1.5 inch/sec."
+msgstr "1.5ì¸ì¹˜/ì´ˆ"
+
+msgid "1.50x0.25\""
+msgstr "1.50x0.25\""
+
+msgid "1.50x0.50\""
+msgstr "1.50x0.50\""
+
+msgid "1.50x1.00\""
+msgstr "1.50x1.00\""
+
+msgid "1.50x2.00\""
+msgstr "1.50x2.00\""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10ì¸ì¹˜/ì´ˆ"
+
+msgid "10 x 11\""
+msgstr "10 x 11\""
+
+msgid "10 x 13\""
+msgstr "10 x 13\""
+
+msgid "10 x 14\""
+msgstr "10 x 14\""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100mm/ì´ˆ"
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11ì¸ì¹˜/ì´ˆ"
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12ì¸ì¹˜/ì´ˆ"
+
+msgid "12 x 11\""
+msgstr "12 x 11\""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120mm/ì´ˆ"
+
+msgid "120x60dpi"
+msgstr "120x60dpi"
+
+msgid "120x72dpi"
+msgstr "120x72dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15mm/ì´ˆ"
+
+msgid "15 x 11\""
+msgstr "15 x 11\""
+
+msgid "150 mm/sec."
+msgstr "150mm/ì´ˆ"
+
+msgid "150dpi"
+msgstr "150dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2ì¸ì¹˜/ì´ˆ"
+
+msgid "2-Sided Printing"
+msgstr "양면 프린트 중"
+
+msgid "2.00x0.37\""
+msgstr "2.00x0.37\""
+
+msgid "2.00x0.50\""
+msgstr "2.00x0.50\""
+
+msgid "2.00x1.00\""
+msgstr "2.00x1.00\""
+
+msgid "2.00x1.25\""
+msgstr "2.00x1.25\""
+
+msgid "2.00x2.00\""
+msgstr "2.00x2.00\""
+
+msgid "2.00x3.00\""
+msgstr "2.00x3.00\""
+
+msgid "2.00x4.00\""
+msgstr "2.00x4.00\""
+
+msgid "2.00x5.50\""
+msgstr "2.00x5.50\""
+
+msgid "2.25x0.50\""
+msgstr "2.25x0.50\""
+
+msgid "2.25x1.25\""
+msgstr "2.25x1.25\""
+
+msgid "2.25x4.00\""
+msgstr "2.25x4.00\""
+
+msgid "2.25x5.50\""
+msgstr "2.25x5.50\""
+
+msgid "2.38x5.50\""
+msgstr "2.38x5.50\""
+
+msgid "2.5 inches/sec."
+msgstr "2.5ì¸ì¹˜/ì´ˆ"
+
+msgid "2.50x1.00\""
+msgstr "2.50x1.00\""
+
+msgid "2.50x2.00\""
+msgstr "2.50x2.00\""
+
+msgid "2.75x1.25\""
+msgstr "2.75x1.25\""
+
+msgid "2.9 x 1\""
+msgstr "2.9 x 1\""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20mm/ì´ˆ"
+
+msgid "200 mm/sec."
+msgstr "200mm/ì´ˆ"
+
+msgid "203dpi"
+msgstr "203dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "24핀 시리즈"
+
+msgid "240x72dpi"
+msgstr "240x72dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250mm/ì´ˆ"
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3ì¸ì¹˜/ì´ˆ"
+
+msgid "3.00x1.00\""
+msgstr "3.00x1.00\""
+
+msgid "3.00x1.25\""
+msgstr "3.00x1.25\""
+
+msgid "3.00x2.00\""
+msgstr "3.00x2.00\""
+
+msgid "3.00x3.00\""
+msgstr "3.00x3.00\""
+
+msgid "3.00x5.00\""
+msgstr "3.00x5.00\""
+
+msgid "3.25x2.00\""
+msgstr "3.25x2.00\""
+
+msgid "3.25x5.00\""
+msgstr "3.25x5.00\""
+
+msgid "3.25x5.50\""
+msgstr "3.25x5.50\""
+
+msgid "3.25x5.83\""
+msgstr "3.25x5.83\""
+
+msgid "3.25x7.83\""
+msgstr "3.25x7.83\""
+
+msgid "3.5\" Disk"
+msgstr "3.5\" 디스í¬"
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "3.5\" ë””ìŠ¤í¬ - 2 1/8 x 2 3/4\""
+
+msgid "3.50x1.00\""
+msgstr "3.50x1.00\""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30mm/ì´ˆ"
+
+msgid "300 mm/sec."
+msgstr "300mm/ì´ˆ"
+
+msgid "300dpi"
+msgstr "300dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360dpi"
+
+msgid "360x180dpi"
+msgstr "360x180dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4ì¸ì¹˜/ì´ˆ"
+
+msgid "4.00x1.00\""
+msgstr "4.00x1.00\""
+
+msgid "4.00x13.00\""
+msgstr "4.00x13.00\""
+
+msgid "4.00x2.00\""
+msgstr "4.00x2.00\""
+
+msgid "4.00x2.50\""
+msgstr "4.00x2.50\""
+
+msgid "4.00x3.00\""
+msgstr "4.00x3.00\""
+
+msgid "4.00x4.00\""
+msgstr "4.00x4.00\""
+
+msgid "4.00x5.00\""
+msgstr "4.00x5.00\""
+
+msgid "4.00x6.00\""
+msgstr "4.00x6.00\""
+
+msgid "4.00x6.50\""
+msgstr "4.00x6.50\""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40mm/ì´ˆ"
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5ì¸ì¹˜/ì´ˆ"
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6ì¸ì¹˜/ì´ˆ"
+
+msgid "6.00x1.00\""
+msgstr "6.00x1.00\""
+
+msgid "6.00x2.00\""
+msgstr "6.00x2.00\""
+
+msgid "6.00x3.00\""
+msgstr "6.00x3.00\""
+
+msgid "6.00x4.00\""
+msgstr "6.00x4.00\""
+
+msgid "6.00x5.00\""
+msgstr "6.00x5.00\""
+
+msgid "6.00x6.00\""
+msgstr "6.00x6.00\""
+
+msgid "6.00x6.50\""
+msgstr "6.00x6.50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60mm/ì´ˆ"
+
+msgid "600dpi"
+msgstr "600dpi"
+
+msgid "60dpi"
+msgstr "60dpi"
+
+msgid "60x720dpi"
+msgstr "60x720dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7ì¸ì¹˜/ì´ˆ"
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8ì¸ì¹˜/ì´ˆ"
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8.00x1.00\""
+
+msgid "8.00x2.00\""
+msgstr "8.00x2.00\""
+
+msgid "8.00x3.00\""
+msgstr "8.00x3.00\""
+
+msgid "8.00x4.00\""
+msgstr "8.00x4.00\""
+
+msgid "8.00x5.00\""
+msgstr "8.00x5.00\""
+
+msgid "8.00x6.00\""
+msgstr "8.00x6.00\""
+
+msgid "8.00x6.50\""
+msgstr "8.00x6.50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80mm/ì´ˆ"
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9ì¸ì¹˜/ì´ˆ"
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "9핀 시리즈"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?유효하지 ì•Šì€ ë„ì›€ë§ ëª…ë ¹ì„ ì•Œ 수 ì—†ìŒ\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3(대)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4(대)"
+
+msgid "A4 (Small)"
+msgstr "A4(소)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5(대)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "작업 허용"
+
+msgid "Accepted"
+msgstr "허용ë¨"
+
+msgid "Add Class"
+msgstr "í´ëž˜ìŠ¤ 추가"
+
+msgid "Add Printer"
+msgstr "프린터 추가"
+
+msgid "Add RSS Subscription"
+msgstr "RSS êµ¬ë… ì¶”ê°€"
+
+msgid "Address"
+msgstr "주소"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "주소 - 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "관리"
+
+msgid "Always"
+msgstr "í•­ìƒ"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "ì ìš©ìž"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "ìž˜ëª»ëœ NULL dests í¬ì¸í„°"
+
+msgid "Bad OpenGroup"
+msgstr "ìž˜ëª»ëœ OpenGroup"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "ìž˜ëª»ëœ OpenUI/JCLOpenUI"
+
+msgid "Bad OrderDependency"
+msgstr "ìž˜ëª»ëœ OrderDependency"
+
+msgid "Bad Request"
+msgstr "ìž˜ëª»ëœ ìš”ì²­"
+
+msgid "Bad SNMP version number"
+msgstr "ìž˜ëª»ëœ SNMP 버전 번호"
+
+msgid "Bad UIConstraints"
+msgstr "ìž˜ëª»ëœ UIConstraints"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "ìž˜ëª»ëœ ë³µì‚¬ 매수 ê°’ %d."
+
+msgid "Bad custom parameter"
+msgstr "ìž˜ëª»ëœ ì‚¬ìš©ìž ì„¤ì • 매개변수"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "ìž˜ëª»ëœ ì„œì²´ ì†ì„±: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "ìž˜ëª»ëœ number-up ê°’ %d."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "ìž˜ëª»ëœ page-ranges ê°’ %d-%d."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "배너"
+
+msgid "Billing Information: "
+msgstr "지불 정보: "
+
+msgid "Bond Paper"
+msgstr "고급 종ì´"
+
+msgid "C0 Envelope"
+msgstr "C0 봉투"
+
+msgid "C1 Envelope"
+msgstr "C1 봉투"
+
+msgid "C2 Envelope"
+msgstr "C2 봉투"
+
+msgid "C3 Envelope"
+msgstr "C3 봉투"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "C4 봉투"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "C5 봉투"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "C6 봉투"
+
+msgid "C65 Envelope"
+msgstr "C65 봉투"
+
+msgid "C7 Envelope"
+msgstr "C7 봉투"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "CPCL ë ˆì´ë¸” 프린터"
+
+msgid "Cancel RSS Subscription"
+msgstr "RSS êµ¬ë… ì·¨ì†Œ"
+
+msgid "Change Settings"
+msgstr "설정값 변경"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Chou3 봉투"
+
+msgid "Chou4 Envelope"
+msgstr "Chou4 봉투"
+
+msgid "Classes"
+msgstr "í´ëž˜ìŠ¤"
+
+msgid "Clean Print Heads"
+msgstr "프린트 ë¨¸ë¦¬ë§ ì§€ìš°ê¸°"
+
+msgid "Color"
+msgstr "색ìƒ"
+
+msgid "Color Mode"
+msgstr "ìƒ‰ìƒ ëª¨ë“œ"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"ëª…ë ¹ì´ ìƒëžµë  수 있습니다. ëª…ë ¹ì€ ë‹¤ìŒê³¼ 같습니다:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "커뮤니티 ì´ë¦„ 길ì´ê°€ 무제한입니다"
+
+msgid "Continue"
+msgstr "계ì†"
+
+msgid "Continuous"
+msgstr "계ì†"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "ìƒì„±ë¨"
+
+msgid "Created On: "
+msgstr "다ìŒì— ìƒì„±ë¨: "
+
+msgid "Custom"
+msgstr "사용ìží™”"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "오려ë‘기"
+
+msgid "Cutter"
+msgstr "ìžë¥´ê¸° ë„구"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "DL 봉투"
+
+msgid "Dark"
+msgstr "어둡게"
+
+msgid "Darkness"
+msgstr "ì–´ë‘ "
+
+msgid "Delete Class"
+msgstr "í´ëž˜ìŠ¤ ì‚­ì œ"
+
+msgid "Delete Printer"
+msgstr "프린터 삭제"
+
+msgid "Description: "
+msgstr "설명: "
+
+msgid "DeskJet Series"
+msgstr "DeskJet 시리즈"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "\"%s\" 대ìƒì´ ìž‘ì—…ì„ í—ˆìš©í•˜ì§€ 않습니다."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"장비: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "ì§ì ‘ ì—´ 미디어"
+
+msgid "Disabled"
+msgstr "비활성화ë¨"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "ë„í멘트 %dì„ ìž‘ì—… %dì—ì„œ ì°¾ì„ ìˆ˜ 없습니다."
+
+msgid "Double Postcard"
+msgstr "ì´ì¤‘ 엽서"
+
+msgid "Driver Name: "
+msgstr "ë“œë¼ì´ë²„ ì´ë¦„: "
+
+msgid "Driver Version: "
+msgstr "ë“œë¼ì´ë²„ 버전: "
+
+msgid "Duplexer"
+msgstr "양면 프린터"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: 페ì´ì§€ ì •ë³´ì— ë©”ëª¨ë¦¬ë¥¼ 할당할 수 없습니다: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: 페ì´ì§€ ë°°ì—´ì— ë©”ëª¨ë¦¬ë¥¼ 할당할 수 없습니다: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "EPL1 ë ˆì´ë¸” 프린터"
+
+msgid "EPL2 Label Printer"
+msgstr "EPL2 ë ˆì´ë¸” 프린터"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: ìž˜ëª»ëœ ë¬¸ìž ì„¸íŠ¸ íŒŒì¼ %s\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: ìž˜ëª»ëœ ë¬¸ìž ì„¸íŠ¸ 유형 %s\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: ìž˜ëª»ëœ ì„œì²´ 설명 줄: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: ìž˜ëª»ëœ í…스트 ë°©í–¥ %s\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: ìž˜ëª»ëœ í…스트 ê¸¸ì´ %s\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: %d 오류가 ë‹¤ìŒ PAPSendData ìš”ì²­ì„ ë³´ë‚´ëŠ” 중: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: %s ë¬¸ìž ì„¸íŠ¸ 파ì¼ì— 서체 ì—†ìŒ\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: 프린터가 ì‘답하지 ì•ŠìŒ\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: 프린터가 예기치 ì•Šì€ EOF를 보냄\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: ì›ê²© 호스트가 제어 파ì¼ì„ 허용하지 ì•ŠìŒ(%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: ì›ê²© 호스트가 ë°ì´í„° 파ì¼ì„ 허용하지 ì•ŠìŒ(%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr "ERROR: ë°ì´í„°ë¥¼ 프린터로 전송하는 ë™ì•ˆ 시간초과 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: ìž‘ì—…ì— %d 파ì¼ì„ 추가할 수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: %d ìž‘ì—…ì„ ì·¨ì†Œí•  수 ì—†ìŒ: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: PDF 파ì¼ì„ 복사할 수 ì—†ìŒ"
+
+msgid "ERROR: Unable to create pipe"
+msgstr ""
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: ì†Œì¼“ì„ ìƒì„±í•  수 ì—†ìŒ"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr "ERROR: ìž„ì‹œ 압축 프린트 파ì¼ì„ ìƒì„±í•  수 ì—†ìŒ: %s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: ìž„ì‹œ 파ì¼ì„ ìƒì„±í•  수 ì—†ìŒ"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: pictwpstops를 실행할 수 ì—†ìŒ: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: gs í”„ë¡œê·¸ëž¨ì„ ì‹¤í–‰í•  수 ì—†ìŒ"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: pdftops í”„ë¡œê·¸ëž¨ì„ ì‹¤í–‰í•  수 ì—†ìŒ"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: pictwpstops를 분리(fork)í•  수 ì—†ìŒ: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: PAP ìš”ì²­ì„ ì–»ì„ ìˆ˜ ì—†ìŒ"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: PAP ì‘ë‹µì„ ì–»ì„ ìˆ˜ ì—†ìŒ"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr "ERROR: \"%s\"í”„ë¦°í„°ì— ëŒ€í•œ PPD 파ì¼ì„ ì–»ì„ ìˆ˜ ì—†ìŒ - %s.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: 기본 AppleTalk ì˜ì—­ì„ ì–»ì„ ìˆ˜ ì—†ìŒ"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: PAP ì‘ë‹µì„ ì°¾ì„ ìˆ˜ ì—†ìŒ"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: AppleTalk 프린터를 ì°¾ì„ ìˆ˜ ì—†ìŒ"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: AppleTalk 주소를 ìƒì„±í•  수 ì—†ìŒ"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: \"%s\"ì„(를) ì—´ 수 ì—†ìŒ - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: %sì„(를) ì—´ 수 ì—†ìŒ: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: \"%s\" 배너 파ì¼ì„ ì—´ 수 ì—†ìŒ - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: \"%s\" 장비 파ì¼ì„ ì—´ 수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: \"%s\" 파ì¼ì„ ì—´ 수 ì—†ìŒ - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: \"%s\" 파ì¼ì„ ì—´ 수 ì—†ìŒ: %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: \"%s\" 프린트 파ì¼ì„ ì—´ 수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: %s 프린트 파ì¼ì„ ì—´ 수 ì—†ìŒ - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: %s 프린트 파ì¼ì„ ì—´ 수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr "ERROR: 임시로 압축한 프린트 파ì¼ì„ ì—´ 수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: 프린트 ë°ì´í„°ë¥¼ ì½ì„ 수 ì—†ìŒ"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: í¬íŠ¸ë¥¼ 예약할 수 ì—†ìŒ"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: 파ì¼ì—ì„œ %ld ì˜¤í”„ì…‹ì„ ì°¾ì„ ìˆ˜ ì—†ìŒ - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: 파ì¼ì—ì„œ %lld ì˜¤í”„ì…‹ì„ ì°¾ì„ ìˆ˜ ì—†ìŒ - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: LPD ëª…ë ¹ì„ ë³´ë‚¼ 수 ì—†ìŒ"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: PAP tickle ìš”ì²­ì„ ë³´ë‚¼ 수 ì—†ìŒ"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: 초기 PAP 전송 ë°ì´í„° ìš”ì²­ì„ ë³´ë‚¼ 수 ì—†ìŒ"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: 프린트 파ì¼ì„ 프린터로 보낼 수 ì—†ìŒ"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: ëìžë¦¬ nulì„ í”„ë¦°í„°ë¡œ 보낼 수 ì—†ìŒ"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: pictwpstops를 기다릴 수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: \"%2$s\"ì— %1$dë°”ì´íŠ¸ë¥¼ 쓸 수 ì—†ìŒ: %3$s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: 제어 파ì¼ì„ 쓸 수 ì—†ìŒ"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: 프린트 ë°ì´í„°ë¥¼ 쓸 수 ì—†ìŒ"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: 프린트 ë°ì´í„°ë¥¼ 쓸 수 ì—†ìŒ: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr "ERROR: 압축ë˜ì§€ ì•Šì€ ë„í멘트 ë°ì´í„°ë¥¼ 쓸 수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: ì•Œ 수 없는 íŒŒì¼ ìˆœì„œ \"%s\"\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: ì•Œ 수 없는 í¬ë§· ë¬¸ìž \"%c\"\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: 알 수 없는 \"%s\" 프린트 모드\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: select() 실패"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: 프린트 파ì¼ì„ 시작할 수 ì—†ìŒ"
+
+msgid "Edit Configuration File"
+msgstr "구성 íŒŒì¼ íŽ¸ì§‘"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "배너 종료 중"
+
+msgid "English"
+msgstr "Korean"
+
+msgid "Enter old password:"
+msgstr "ì´ì „ 암호 ìž…ë ¥:"
+
+msgid "Enter password again:"
+msgstr "암호 다시 입력:"
+
+msgid "Enter password:"
+msgstr "암호 입력:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"ì´ íŽ˜ì´ì§€ì— 연결하려면 ì‚¬ìš©ìž ì´ë¦„ ë° ì•”í˜¸ ë˜ëŠ” root ì‚¬ìš©ìž ì´ë¦„ ë° ì•”í˜¸ë¥¼ ìž…"
+"력하십시오. Kerberos ì¸ì¦ì„ 사용하고 있다면, 유효한 Kerberos í‹°ì¼“ì„ ê°€ì§€ê³  있"
+"는지 확ì¸í•˜ì‹­ì‹œì˜¤."
+
+msgid "Envelope Feed"
+msgstr "봉투 공급"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "오류 정책"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "10ê°œ ë ˆì´ë¸”마다"
+
+msgid "Every 2 Labels"
+msgstr "2ê°œ ë ˆì´ë¸”마다"
+
+msgid "Every 3 Labels"
+msgstr "3ê°œ ë ˆì´ë¸”마다"
+
+msgid "Every 4 Labels"
+msgstr "4ê°œ ë ˆì´ë¸”마다"
+
+msgid "Every 5 Labels"
+msgstr "5ê°œ ë ˆì´ë¸”마다"
+
+msgid "Every 6 Labels"
+msgstr "6ê°œ ë ˆì´ë¸”마다"
+
+msgid "Every 7 Labels"
+msgstr "7ê°œ ë ˆì´ë¸”마다"
+
+msgid "Every 8 Labels"
+msgstr "8ê°œ ë ˆì´ë¸”마다"
+
+msgid "Every 9 Labels"
+msgstr "9ê°œ ë ˆì´ë¸”마다"
+
+msgid "Every Label"
+msgstr "모든 ë ˆì´ë¸”"
+
+msgid "Expectation Failed"
+msgstr "ì˜ˆìƒ ì‹¤íŒ¨"
+
+msgid "Export Printers to Samba"
+msgstr "Samba로 프린터 보내기"
+
+msgid "FAIL\n"
+msgstr "실패\n"
+
+msgid "File Folder"
+msgstr "íŒŒì¼ í´ë”"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "íŒŒì¼ í´ë” - 9/16 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"íŒŒì¼ ìž¥ë¹„ URIê°€ 비활성화ë˜ì—ˆìŠµë‹ˆë‹¤! 활성화하려면, \"%s/cupsd.conf\"ì— ìžˆëŠ” "
+"FileDevice ì§€ì‹œë¬¸ì„ ë³´ì‹­ì‹œì˜¤."
+
+msgid "Folio"
+msgstr "2절지"
+
+msgid "Forbidden"
+msgstr "금지ë¨"
+
+msgid "General"
+msgstr "ì¼ë°˜"
+
+msgid "Generic"
+msgstr "ì¼ë°˜"
+
+msgid "German FanFold"
+msgstr "ë…ì¼ FanFold"
+
+msgid "German FanFold Legal"
+msgstr "ë…ì¼ FanFold 공문서"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU 길ì´ê°€ 무제한입니다"
+
+msgid "Glossy Paper"
+msgstr "글로시 종ì´"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "ê·¸ë ˆì´ ìŠ¤ì¼€ì¼"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "행잉 í´ë”"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "행잉 í´ë” - 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: 시스템 환경설정ì—ì„œ AppleTalkê°€ 비활성화ë¨\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: 시스템 환경설정ì—ì„œ AppleTalkê°€ 비활성화ë˜ì—ˆìŠµë‹ˆë‹¤.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: 프린트 작업 취소 중...\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: í”„ë¦°í„°ì— ì—°ê²°ë¨...\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: í”„ë¦°íŠ¸ì— ì—°ê²° 중...\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: 제어 파ì¼ì„ 성공ì ìœ¼ë¡œ 보냄\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr ""
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: ë°ì´í„° 파ì¼ì„ 성공ì ìœ¼ë¡œ 보냄\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: %d페ì´ì§€ í¬ë§· 중...\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: ì´ë¯¸ì§€ íŒŒì¼ ë¡œë“œ 중...\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: 프린터 검색 중...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: 연결 열기\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr "INFO: 프린트 파ì¼ì„ 보냈고, 프린터 ìž‘ì—… 종료 대기 중...\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: 프린터 사용 중; 10ì´ˆ í›„ì— ë‹¤ì‹œ ì‹œë„...\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: 프린터 사용 중; 30ì´ˆ í›„ì— ë‹¤ì‹œ ì‹œë„...\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: 프린터 사용 중; 5ì´ˆ í›„ì— ë‹¤ì‹œ ì‹œë„...\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr ""
+"INFO: 프린터가 IPP/%d.%dì„ ì§€ì›í•˜ì§€ 않기 때문ì—, IPP/1.0ì„ ì‹œë„ ì¤‘...\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: 프린터 사용 중; 5ì´ˆ í›„ì— ë‹¤ì‹œ ì‹œë„...\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: 현재 프린터가 오프ë¼ì¸ìž…니다.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: 현재 프린터가 오프ë¼ì¸ìž…니다.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: 현재 프린터가 온ë¼ì¸ìž…니다.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: 프린터가 오프ë¼ì¸ìž…니다.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: 프린터가 ì—°ê²°ë˜ì§€ ì•ŠìŒ; 30ì´ˆ í›„ì— ë‹¤ì‹œ ì‹œë„...\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: %d페ì´ì§€ 프린트 중, %d%% 완료...\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: %d페ì´ì§€ 프린트 중...\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: 프린트할 준비가 ë˜ì—ˆìŠµë‹ˆë‹¤.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: 제어 íŒŒì¼ ë³´ë‚´ëŠ” 중(%luë°”ì´íŠ¸)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: 제어 íŒŒì¼ ë³´ë‚´ëŠ” 중(%uë°”ì´íŠ¸)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: ë°ì´í„° 보내는 중\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: ë°ì´í„° íŒŒì¼ ë³´ë‚´ëŠ” 중(%ldë°”ì´íŠ¸)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: ë°ì´í„° íŒŒì¼ ë³´ë‚´ëŠ” 중(%lldë°”ì´íŠ¸)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: 프린트 ë°ì´í„° 보내는 중...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: 프린트 íŒŒì¼ ë³´ëƒ„, %ldë°”ì´íŠ¸...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: 프린트 íŒŒì¼ ë³´ëƒ„, %lldë°”ì´íŠ¸...\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: LPR 작업 스풀 중, %.0f%% 완료...\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr ""
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: í”„ë¦°í„°ì— ì—°ê²°í•  수 없기 때문ì—, í´ëž˜ìŠ¤ì— 있는 ë‹¤ìŒ í”„ë¦°í„° 대기 중...\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: \"%s\" 기본 AppleTalk ì˜ì—­ 사용 중 \n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: 작업 완료 대기 중...\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: 프린터 사용 대기 중...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "ISO B4 봉투"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5(대)"
+
+msgid "ISO B5 Envelope"
+msgstr "ISO B5 봉투"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "ISO B6 봉투"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "올바르지 ì•Šì€ ì œì–´ 문ìž"
+
+msgid "Illegal main keyword string"
+msgstr "올바르지 ì•Šì€ ì£¼ 키워드 스트ë§"
+
+msgid "Illegal option keyword string"
+msgstr "올바르지 ì•Šì€ ì˜µì…˜ 키워드 스트ë§"
+
+msgid "Illegal translation string"
+msgstr "올바르지 ì•Šì€ ë²ˆì—­ 스트ë§"
+
+msgid "Illegal whitespace character"
+msgstr "올바르지 ì•Šì€ ì—¬ë°± 문ìž"
+
+msgid "Installable Options"
+msgstr "설치 가능한 옵션"
+
+msgid "Installed"
+msgstr "설치ë¨"
+
+msgid "IntelliBar Label Printer"
+msgstr "IntelliBar ë ˆì´ë¸” 프린터"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr ""
+
+msgid "Internal error"
+msgstr "내부 오류"
+
+msgid "Internet Postage 2-Part"
+msgstr "ì¸í„°ë„· ìš°í‘œ 2부분"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "ì¸í„°ë„· ìš°í‘œ 2부분 - 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "ì¸í„°ë„· ìš°í‘œ 3부분"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "ì¸í„°ë„· ìš°í‘œ 3부분 - 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "ì¸í„°ë„· 프린트 프로토콜"
+
+msgid "Invite Envelope"
+msgstr "초대 봉투"
+
+msgid "Italian Envelope"
+msgstr "ì´íƒˆë¦¬ì•„ 봉투"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "#%d ìž‘ì—…ì´ ì´ë¯¸ ì¤‘ë‹¨ë¨ - 취소할 수 없습니다."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "#%d ìž‘ì—…ì´ ì´ë¯¸ ì·¨ì†Œë¨ - 취소할 수 없습니다."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "#%d ìž‘ì—…ì´ ì´ë¯¸ ì™„ë£Œë¨ - 취소할 수 없습니다."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "ìž‘ì—…ì´ ì™„ë£Œë¨"
+
+msgid "Job Created"
+msgstr "ìž‘ì—…ì´ ìƒì„±ë¨"
+
+msgid "Job ID: "
+msgstr "ìž‘ì—… ID: "
+
+msgid "Job Options Changed"
+msgstr "ìž‘ì—… ì˜µì…˜ì´ ë³€ê²½ë¨"
+
+msgid "Job Stopped"
+msgstr "ìž‘ì—…ì´ ì¤‘ë‹¨ë¨"
+
+msgid "Job UUID: "
+msgstr "ìž‘ì—… UUID: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "ìž‘ì—…ì´ ì™„ë£Œë˜ì—ˆê³  변경할 수 없습니다."
+
+msgid "Job operation failed:"
+msgstr "ìž‘ì—… ì‹¤í–‰ì— ì‹¤íŒ¨í•¨:"
+
+msgid "Job state cannot be changed."
+msgstr "ìž‘ì—… ìƒíƒœë¥¼ 변경할 수 없습니다."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "ìž‘ì—…"
+
+msgid "Kaku2 Envelope"
+msgstr "Kaku2 봉투"
+
+msgid "Kaku3 Envelope"
+msgstr "Kaku3 봉투"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "LPD/LPR 호스트 ë˜ëŠ” 프린터"
+
+msgid "Label Printer"
+msgstr "ë ˆì´ë¸” 프린터"
+
+msgid "Label Top"
+msgstr "ë ˆì´ë¸” ìƒë‹¨"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "주소 í¬ê²Œ"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "주소 í¬ê²Œ - 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet 시리즈 PCL 4/5"
+
+msgid "Light"
+msgstr "불빛"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "ì¤„ì— í—ˆìš©ë˜ëŠ” 최대 길ì´ë³´ë‹¤ ê¹€(255ìž)"
+
+msgid "List Available Printers"
+msgstr "사용 가능한 프린터 목ë¡"
+
+msgid "Location: "
+msgstr "위치: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "가장ìžë¦¬ 길게(세로)"
+
+msgid "Make and Model: "
+msgstr "제조사 ë° ëª¨ë¸: "
+
+msgid "Manual Feed"
+msgstr "ìˆ˜ë™ ê³µê¸‰"
+
+msgid "Media Dimensions: "
+msgstr "미디어 í¬ê¸°: "
+
+msgid "Media Limits: "
+msgstr "미디어 제한: "
+
+msgid "Media Name: "
+msgstr "미디어 ì´ë¦„: "
+
+msgid "Media Size"
+msgstr "미디어 í¬ê¸°"
+
+msgid "Media Source"
+msgstr "미디어 소스"
+
+msgid "Media Tracking"
+msgstr "미디어 추ì "
+
+msgid "Media Type"
+msgstr "미디어 유형"
+
+msgid "Medium"
+msgstr "중간"
+
+msgid "Memory allocation error"
+msgstr "메모리 할당 오류"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "PPD-Adobe-4.x 머리ë§ì´ 유실ë¨"
+
+msgid "Missing asterisk in column 1"
+msgstr "1ì—´ì— ìžˆëŠ” 별표가 유실ë¨"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "ê°’ 스트ë§ì´ 유실ë¨"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"모ë¸: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "í´ëž˜ìŠ¤ 수정"
+
+msgid "Modify Printer"
+msgstr "프린터 수정"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Monarch 봉투"
+
+msgid "Move All Jobs"
+msgstr "모든 ìž‘ì—… ì´ë™"
+
+msgid "Move Job"
+msgstr "ìž‘ì—… ì´ë™"
+
+msgid "Moved Permanently"
+msgstr "ì˜êµ¬ì ìœ¼ë¡œ ì´ë™"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: 프린트 파ì¼ì´ í—ˆìš©ë¨ - ìž‘ì—… ID %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: 프린트 파ì¼ì´ í—ˆìš©ë¨ - ì•Œ 수 없는 ìž‘ì—… ID.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "NULL PPD íŒŒì¼ í¬ì¸í„°"
+
+msgid "Name OID uses indefinite length"
+msgstr "ì´ë¦„ OID 길ì´ê°€ 무제한입니다"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "안 함"
+
+msgid "New Stylus Color Series"
+msgstr "새로운 Stylus Color 시리즈"
+
+msgid "New Stylus Photo Series"
+msgstr "새로운 Stylus Photo 시리즈"
+
+msgid "No"
+msgstr "아니요"
+
+msgid "No Content"
+msgstr "콘í…츠 ì—†ìŒ"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "VarBind SEQUENCE ì—†ìŒ"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "활성 ì—°ê²°ì´ ì—†ìŒ"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "커뮤니티 ì´ë¦„ ì—†ìŒ"
+
+msgid "No default printer"
+msgstr "기본 프린터가 ì—†ìŒ"
+
+msgid "No destinations added."
+msgstr "ì¶”ê°€ëœ ëŒ€ìƒì´ 없습니다."
+
+msgid "No error-index"
+msgstr "error-index ì—†ìŒ"
+
+msgid "No error-status"
+msgstr "error-status ì—†ìŒ"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "ì´ë¦„ OID ì—†ìŒ"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "request-id ì—†ìŒ"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "ë°œê²¬ëœ êµ¬ë…ì´ ì—†ìŠµë‹ˆë‹¤."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "variable-bindings SEQUENCE ì—†ìŒ"
+
+msgid "No version number"
+msgstr "버전 번호 ì—†ìŒ"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "중단(ë§ˆí¬ ì„¼ì‹±)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "중단(웹 센싱)"
+
+msgid "Normal"
+msgstr "ì¼ë°˜"
+
+msgid "Not Found"
+msgstr "ì—†ìŒ"
+
+msgid "Not Implemented"
+msgstr "실행ë˜ì§€ ì•ŠìŒ"
+
+msgid "Not Installed"
+msgstr "설치ë˜ì§€ ì•ŠìŒ"
+
+msgid "Not Modified"
+msgstr "수정ë˜ì§€ ì•ŠìŒ"
+
+msgid "Not Supported"
+msgstr "지ì›ë˜ì§€ ì•ŠìŒ"
+
+msgid "Not allowed to print."
+msgstr "프린트가 허용ë˜ì§€ 않습니다."
+
+msgid "Note"
+msgstr "참고"
+
+msgid "OK"
+msgstr "승ì¸"
+
+msgid "Off (1-Sided)"
+msgstr "ë”(í•œ 쪽 ë°©í–¥)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "온ë¼ì¸ ë„움ë§"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "%s 열기 실패: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "ìš°ì„  CloseGroupì´ ì—†ëŠ” OpenGroup"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "우선 CloseUI/JCLCloseUI가 없는 OpenUI/JCLOpenUI"
+
+msgid "Operation Policy"
+msgstr "ë™ìž‘ ì •ì±…"
+
+msgid "Options Installed"
+msgstr "ì„¤ì¹˜ëœ ì˜µì…˜"
+
+msgid "Options: "
+msgstr "옵션: "
+
+msgid "Output Mode"
+msgstr "출력 모드"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "%s 프린터 ì¶œë ¥ì„ %s(으)ë¡œ 보냄\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr "%1$s 프린터 ì¶œë ¥ì„ %3$sì— ìžˆëŠ” %2$s ì›ê²© 프린터로 보냄\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "%s/%s 프린터 ì¶œë ¥ì„ %së¡œ 보냄\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr "%1$s/%2$s 프린터 ì¶œë ¥ì„ %4$sì— ìžˆëŠ” %3$s ì›ê²© 프린터로 보냄\n"
+
+msgid "PASS\n"
+msgstr "PASS\n"
+
+msgid "PCL Laser Printer"
+msgstr "PCL ë ˆì´ì € 프린터"
+
+msgid "PRC1 Envelope"
+msgstr "PRC1 봉투"
+
+msgid "PRC10 Envelope"
+msgstr "PRC10 봉투"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "PRC2 봉투"
+
+msgid "PRC3 Envelope"
+msgstr "PRC3 봉투"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K(대)"
+
+msgid "PRC4 Envelope"
+msgstr "PRC4 봉투"
+
+msgid "PRC5 Envelope"
+msgstr "PRC5 봉투"
+
+msgid "PRC6 Envelope"
+msgstr "PRC6 봉투"
+
+msgid "PRC7 Envelope"
+msgstr "PRC7 봉투"
+
+msgid "PRC8 Envelope"
+msgstr "PRC8 봉투"
+
+msgid "PRC9 Envelope"
+msgstr "PRC9 봉투"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "íŒ¨í‚·ì— Get-Response-PDUê°€ 없습니다"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "íŒ¨í‚·ì´ SEQUENCEë¡œ 시작하지 않습니다"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "%2$sì˜ %1$s 암호? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "SAMBA를 통해 %2$sì— ì—°ê²°í•˜ë ¤ë©´ 필요한 %1$sì˜ ì•”í˜¸: "
+
+msgid "Pause Class"
+msgstr "í´ëž˜ìŠ¤ ì¼ì‹œì •ì§€"
+
+msgid "Pause Printer"
+msgstr "프린터 ì¼ì‹œì •ì§€"
+
+msgid "Peel-Off"
+msgstr "착탈ì‹"
+
+msgid "Personal Envelope"
+msgstr "ê°œì¸ ë´‰íˆ¬"
+
+msgid "Photo"
+msgstr "사진"
+
+msgid "Photo Labels"
+msgstr "사진 ë ˆì´ë¸”"
+
+msgid "Plain Paper"
+msgstr "ì¼ë°˜ 종ì´"
+
+msgid "Policies"
+msgstr "ì •ì±…"
+
+msgid "Port Monitor"
+msgstr "í¬íŠ¸ 모니터"
+
+msgid "PostScript Printer"
+msgstr "PostScript 프린터"
+
+msgid "Postcard"
+msgstr "엽서"
+
+msgid "Print Density"
+msgstr "프린트 í•´ìƒë„"
+
+msgid "Print Job:"
+msgstr "프린트 작업:"
+
+msgid "Print Mode"
+msgstr "프린트 모드"
+
+msgid "Print Rate"
+msgstr "프린트 비율"
+
+msgid "Print Self-Test Page"
+msgstr "프린트 ìžì²´ 테스트 페ì´ì§€"
+
+msgid "Print Speed"
+msgstr "프린트 ì†ë„"
+
+msgid "Print Test Page"
+msgstr "프린트 테스트 페ì´ì§€"
+
+msgid "Print and Cut"
+msgstr "프린트 ë° ìžë¥´ê¸°"
+
+msgid "Print and Tear"
+msgstr "프린트 ë° í‹°ì–´"
+
+msgid "Printed For: "
+msgstr "다ìŒì´ 프린트ë¨: "
+
+msgid "Printed From: "
+msgstr "다ìŒì—ì„œ 프린트ë¨: "
+
+msgid "Printed On: "
+msgstr "다ìŒì—ì„œ 프린트ë¨: "
+
+msgid "Printer Added"
+msgstr "ì¶”ê°€ëœ í”„ë¦°í„°"
+
+msgid "Printer Default"
+msgstr "기본 프린터"
+
+msgid "Printer Deleted"
+msgstr "ì‚­ì œëœ í”„ë¦°í„°"
+
+msgid "Printer Modified"
+msgstr "ìˆ˜ì •ëœ í”„ë¦°í„°"
+
+msgid "Printer Name: "
+msgstr "프린터 ì´ë¦„: "
+
+msgid "Printer Paused"
+msgstr "ì¤‘ë‹¨ëœ í”„ë¦°í„°"
+
+msgid "Printer Settings"
+msgstr "프린터 설정"
+
+msgid "Printer:"
+msgstr "프린터:"
+
+msgid "Printers"
+msgstr "프린터"
+
+msgid "Purge Jobs"
+msgstr "작업 비우기"
+
+msgid "Quarto"
+msgstr "4절지"
+
+msgid "Quota limit reached."
+msgstr "ìš©ëŸ‰ì´ í•œê³„ì— ë„달했습니다."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr "단계 ì†Œìœ ìž ìž‘ì—… íŒŒì¼ ì´ í¬ê¸°\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"단계 ì†Œìœ ìž ìš°ì„ ìˆœìœ„ ìž‘ì—… íŒŒì¼ ì´ í¬ê¸°\n"
+
+msgid "Reject Jobs"
+msgstr "작업 거부"
+
+msgid "Reprint After Error"
+msgstr "오류 시 다시 프린트"
+
+msgid "Request Entity Too Large"
+msgstr "요청한 ìš©ëŸ‰ì´ ë„ˆë¬´ í½ë‹ˆë‹¤"
+
+msgid "Resolution"
+msgstr "í•´ìƒë„"
+
+msgid "Resume Class"
+msgstr "í´ëž˜ìŠ¤ 다시 시작"
+
+msgid "Resume Printer"
+msgstr "프린터 다시 시작"
+
+msgid "Return Address"
+msgstr "주소 반환"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "주소 반환 - 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "뒤로가기"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "실행 ì¤‘ì¸ ëª…ë ¹: %s %s -N -A %s -c '%s'\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE 길ì´ê°€ 무제한입니다"
+
+msgid "See Other"
+msgstr "기타 보기"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "시리얼 í¬íŠ¸ #%d"
+
+msgid "Server Restarted"
+msgstr "서버 재시ë™ë¨"
+
+msgid "Server Security Auditing"
+msgstr "서버 보안 ê°ì‚¬"
+
+msgid "Server Started"
+msgstr "서버 ì‹œë™ë¨"
+
+msgid "Server Stopped"
+msgstr "서버 중단ë¨"
+
+msgid "Service Unavailable"
+msgstr "사용할 수 없는 서비스"
+
+msgid "Set Allowed Users"
+msgstr "í—ˆìš©ëœ ì‚¬ìš©ìž ì„¤ì •"
+
+msgid "Set As Server Default"
+msgstr "서버 기본값으로 설정"
+
+msgid "Set Class Options"
+msgstr "í´ëž˜ìŠ¤ 옵션 설정"
+
+msgid "Set Printer Options"
+msgstr "프린터 옵션 설정"
+
+msgid "Set Publishing"
+msgstr "발행 설정"
+
+msgid "Shipping Address"
+msgstr "발송 주소"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "발송 주소 - 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "가장ìžë¦¬ 짧게(가로)"
+
+msgid "Special Paper"
+msgstr "특수 종ì´"
+
+msgid "Standard"
+msgstr "표준"
+
+msgid "Starting Banner"
+msgstr "배너 시작 중"
+
+msgid "Statement"
+msgstr "대차표"
+
+msgid "Stylus Color Series"
+msgstr "Stylus Color 시리즈"
+
+msgid "Stylus Photo Series"
+msgstr "Stylus Photo 시리즈"
+
+msgid "Super A"
+msgstr "ìˆ˜í¼ A"
+
+msgid "Super B"
+msgstr "ìˆ˜í¼ B"
+
+msgid "Super B/A3"
+msgstr "ìˆ˜í¼ B/A3"
+
+msgid "Switching Protocols"
+msgstr "프로토콜 전환 중"
+
+msgid "Tabloid"
+msgstr "타블로ì´ë“œ"
+
+msgid "Tabloid (Oversize)"
+msgstr "타블로ì´ë“œ(대)"
+
+msgid "Tear"
+msgstr "절취"
+
+msgid "Tear-Off"
+msgstr "절취선"
+
+msgid "Tear-Off Adjust Position"
+msgstr "절취선 조절 위치"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "\"%s\" PPD 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "\"%s\" PPD 파ì¼ì„ ì—´ 수 없습니다: %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"í´ëž˜ìŠ¤ ì´ë¦„ì€ ìµœëŒ€ 127ìžì˜ 프린트 가능한 문ìžë§Œì„ í¬í•¨í•  수 있고 빈 칸, 슬래"
+"ì‹œ(/) ë˜ëŠ” 파운드 기호(#)를 í¬í•¨í•˜ì§€ 않습니다."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr "notify-lease-duration ì†ì„±ì„ ìž‘ì—… 구ë…ê³¼ 함께 사용할 수 없습니다."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"프린터 ì´ë¦„ì€ ìµœëŒ€ 127ìžì˜ 프린트 가능한 문ìžë§Œì„ í¬í•¨í•  수 있고 빈 칸, 슬래"
+"ì‹œ(/) ë˜ëŠ” 파운드 기호(#)를 í¬í•¨í•˜ì§€ 않습니다."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "프린터 ë˜ëŠ” í´ëž˜ìŠ¤ê°€ 없습니다."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "\"%s\" printer-uriê°€ 유효하지 ì•Šì€ ë¬¸ìžë¥¼ í¬í•¨í•©ë‹ˆë‹¤."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr "printer-uri는 \"ipp://HOSTNAME/classes/CLASSNAME\" 형태여야 합니다."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr "printer-uri는 \"ipp://HOSTNAME/printers/PRINTERNAME\" 형태여야 합니다."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"êµ¬ë… ì´ë¦„ì€ ë¹ˆ 칸, 슬래시(/), 물ìŒí‘œ(?) ë˜ëŠ” 파운드 기호(#)를 í¬í•¨í•˜ì§€ 않습니"
+"다."
+
+msgid "There are too many subscriptions."
+msgstr "구ë…ì´ ë„ˆë¬´ 많습니다."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "열 전송 미디어"
+
+msgid "Title: "
+msgstr "제목: "
+
+msgid "Too many active jobs."
+msgstr "활성 ìž‘ì—…ì´ ë„ˆë¬´ 많습니다."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "투명ë„"
+
+msgid "Tray"
+msgstr "트레ì´"
+
+msgid "Tray 1"
+msgstr "íŠ¸ë ˆì´ 1"
+
+msgid "Tray 2"
+msgstr "íŠ¸ë ˆì´ 2"
+
+msgid "Tray 3"
+msgstr "íŠ¸ë ˆì´ 3"
+
+msgid "Tray 4"
+msgstr "íŠ¸ë ˆì´ 4"
+
+msgid "URI Too Long"
+msgstr "URI가 너무 김"
+
+msgid "US Executive"
+msgstr "US 행정 용지"
+
+msgid "US Fanfold"
+msgstr "US ì—°ì† ìš©ì§€"
+
+msgid "US Ledger"
+msgstr "US ì›ìž¥"
+
+msgid "US Legal"
+msgstr "US 공문서"
+
+msgid "US Legal (Oversize)"
+msgstr "US 공문서(대)"
+
+msgid "US Letter"
+msgstr "US 편지지"
+
+msgid "US Letter (Oversize)"
+msgstr "US 편지지(대)"
+
+msgid "US Letter (Small)"
+msgstr "US 편지지(소)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "USB 시리얼 í¬íŠ¸ #%d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "cupsd.conf 파ì¼ì— ì—°ê²°í•  수 ì—†ìŒ:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "RSS 구ë…ì„ ì¶”ê°€í•  수 ì—†ìŒ:"
+
+msgid "Unable to add class:"
+msgstr "í´ëž˜ìŠ¤ë¥¼ 추가할 수 ì—†ìŒ:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "프린터를 추가할 수 ì—†ìŒ:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "RSS 구ë…ì„ ì·¨ì†Œí•  수 ì—†ìŒ:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "printer-is-shared ì†ì„±ì„ 변경할 수 ì—†ìŒ:"
+
+msgid "Unable to change printer:"
+msgstr "프린터를 변경할 수 ì—†ìŒ:"
+
+msgid "Unable to change server settings:"
+msgstr "서버 ì„¤ì •ê°’ì„ ë³€ê²½í•  수 ì—†ìŒ:"
+
+msgid "Unable to connect to host."
+msgstr "í˜¸ìŠ¤íŠ¸ì— ì—°ê²°í•  수 ì—†ìŒ."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "ìž„ì‹œ 파ì¼ì„ ìƒì„±í•  수 ì—†ìŒ:"
+
+msgid "Unable to delete class:"
+msgstr "í´ëž˜ìŠ¤ë¥¼ 삭제할 수 ì—†ìŒ:"
+
+msgid "Unable to delete printer:"
+msgstr "프린터를 삭제할 수 ì—†ìŒ:"
+
+msgid "Unable to do maintenance command:"
+msgstr "ëª…ë ¹ì„ ìœ ì§€í•  수 ì—†ìŒ:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "í´ëž˜ìŠ¤ 목ë¡ì„ ì–»ì„ ìˆ˜ ì—†ìŒ:"
+
+msgid "Unable to get class status:"
+msgstr "í´ëž˜ìŠ¤ ìƒíƒœë¥¼ ì•Œ 수 ì—†ìŒ:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "프린터 ë“œë¼ì´ë²„ 목ë¡ì„ ì–»ì„ ìˆ˜ ì—†ìŒ:"
+
+msgid "Unable to get printer attributes:"
+msgstr "프린터 ì†ì„±ì„ ì–»ì„ ìˆ˜ ì—†ìŒ:"
+
+msgid "Unable to get printer list:"
+msgstr "프린터 목ë¡ì„ ì–»ì„ ìˆ˜ ì—†ìŒ:"
+
+msgid "Unable to get printer status:"
+msgstr "프린터 ìƒíƒœë¥¼ ì•Œ 수 없습니다:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "í´ëž˜ìŠ¤ë¥¼ 수정할 수 ì—†ìŒ:"
+
+msgid "Unable to modify printer:"
+msgstr "프린터를 수정할 수 ì—†ìŒ:"
+
+msgid "Unable to move job"
+msgstr "ìž‘ì—…ì„ ì´ë™í•  수 없습니다"
+
+msgid "Unable to move jobs"
+msgstr "ìž‘ì—…ì„ ì´ë™í•  수 없습니다"
+
+msgid "Unable to open PPD file"
+msgstr "PPD 파ì¼ì„ ì—´ 수 없습니다"
+
+msgid "Unable to open PPD file:"
+msgstr "PPD 파ì¼ì„ ì—´ 수 ì—†ìŒ:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "cupsd.conf 파ì¼ì„ ì—´ 수 ì—†ìŒ:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "테스트 페ì´ì§€ë¥¼ 프린트할 수 ì—†ìŒ:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "\"%s\"ì„(를) 실행할 수 ì—†ìŒ: %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "ì˜µì…˜ì„ ì„¤ì •í•  수 ì—†ìŒ:"
+
+msgid "Unable to set server default:"
+msgstr "서버 ê¸°ë³¸ê°’ì„ ì„¤ì •í•  수 ì—†ìŒ:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "cupsd.conf 파ì¼ì„ 업로드할 수 없습니다:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "ì¸ì¦ë˜ì§€ ì•ŠìŒ"
+
+msgid "Units"
+msgstr "장비"
+
+msgid "Unknown"
+msgstr "ì•Œ 수 ì—†ìŒ"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "알 수 없는 printer-error-policy \"%s\" ."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "알 수 없는 printer-op-policy \"%s\"."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "지ì›ë˜ì§€ 않는 ê°’ 유형"
+
+msgid "Upgrade Required"
+msgstr "업그레ì´ë“œ 필요함"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"사용법:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "사용법: %s job user title copies options [filename]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "사용법: %s job-id user title copies options [file]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "사용법: %s job-id user title copies options file\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"사용법: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"옵션:\n"
+" -E 서버 연결 암호화\n"
+" -H samba-server SAMBA 서버 사용\n"
+" -U samba-user ì´ë¦„ì´ ìžˆëŠ” SAMBA 사용ìžë¥¼ 사용하여 ì¸ì¦\n"
+" -a 모든 프린터 보내기\n"
+" -h cups-server ì´ë¦„ì´ ìžˆëŠ” CUPS 서버 사용\n"
+" -v ìƒì„¸í•˜ê²Œ(명령 보기)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"사용법: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"옵션:\n"
+"\n"
+" -E 암호화 활성화\n"
+" -U username ì‚¬ìš©ìž ì´ë¦„ 지정\n"
+" -h server[:port] 서버 주소 지정\n"
+"\n"
+" --[no-]debug-logging 디버그 로그 켜기/ë„기\n"
+" --[no-]remote-admin ì›ê²© 관리 켜기/ë„기\n"
+" --[no-]remote-any ì¸í„°ë„· ì ‘ê·¼ 허용/차단\n"
+" --[no-]remote-printers ì›ê²© 프린터 보기/가리기\n"
+" --[no-]share-printers 프린터 공유 켜기/ë„기\n"
+" --[no-]user-cancel-any 사용ìžê°€ 모든 ìž‘ì—…ì„ ì·¨ì†Œí•˜ëŠ” ê²ƒì„ í—ˆìš©/차단\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"사용법: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file 대체 구성 íŒŒì¼ ë¡œë“œ\n"
+"-f ì „ë©´ì— ì‹¤í–‰\n"
+"-F ì „ë©´ì— ì‹¤í–‰í•˜ì§€ë§Œ 분리\n"
+"-h ì´ ì‚¬ìš©ë²• 메시지 보기\\n-l launchd(8)ì—"
+"서 cupsd 실행\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"사용법: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"옵션:\n"
+"\n"
+" -h 프로그램 사용법 보기\n"
+"\n"
+" 참고: ì´ í”„ë¡œê·¸ëž¨ì€ DSC ëª…ë ¹ë§Œì„ ìœ íš¨í™”í•˜ê³ , PostScript ìžì²´ëŠ” 유효화하"
+"지 않습니다.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "사용법: lpmove job/src dest\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"사용법: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "사용법: lppasswd [-g groupname]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"사용법: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"사용법: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"사용법: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"옵션:\n"
+" -D name=value ì´ë¦„ì´ ì •í•´ì§„ 변수를 값으로 설정합니다.\n"
+" -I include-dir í¬í•¨ 디렉토리를 검색 ê²½ë¡œì— ì¶”ê°€í•©ë‹ˆë‹¤.\n"
+" -c catalog.po ì§€ì •ëœ ë©”ì‹œì§€ 카탈로그를 로드합니다.\n"
+" -d output-dir 출력 디렉토리를 지정합니다.\n"
+" -l lang[,lang,...] 출력 언어를 지정합니다(로컬).\n"
+" -m íŒŒì¼ ì´ë¦„으로 ModelName ê°’ì„ ì‚¬ìš©í•©ë‹ˆë‹¤.\n"
+" -t PPD를 ìƒì„±í•˜ëŠ” 대신 테스트합니다.\n"
+" -v ìžì„¸í•˜ê²Œ(ë” ìžì„¸í•˜ê²Œ 하려면 v 추가).\n"
+" -z GNU zipì„ ì‚¬ìš©í•˜ì—¬ PPD 파ì¼ì„ 압축합니다.\n"
+" --cr CRë¡œ ì¤„ì„ ë냅니다(Mac OS 9).\n"
+" --crlf CR + LFë¡œ ì¤„ì„ ë냅니다(Windows).\n"
+" --lf LFë¡œ ì¤„ì„ ë냅니다(UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"사용법: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value ì´ë¦„ì´ ì •í•´ì§„ 변수를 값으로 설정합니다.\n"
+"옵션:\n"
+" -I include-dir í¬í•¨ 디렉토리를 검색 ê²½ë¡œì— ì¶”ê°€í•©ë‹ˆë‹¤.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"사용법: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"옵션:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"사용법: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"옵션:\n"
+" -o filename.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"사용법: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"옵션:\n"
+" -D name=value ì´ë¦„ì´ ì •í•´ì§„ 변수를 값으로 설정합니다.\n"
+" -I include-dir í¬í•¨ 디렉토리를 검색 ê²½ë¡œì— ì¶”ê°€í•©ë‹ˆë‹¤.\n"
+" -v ìžì„¸í•˜ê²Œ(ë” ìžì„¸í•˜ê²Œ 하려면 v 추가).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "사용법: snmp [host-or-ip-address]\n"
+
+msgid "Value uses indefinite length"
+msgstr "ê°’ì˜ ê¸¸ì´ê°€ 무제한입니다"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBindì˜ ê¸¸ì´ê°€ 무제한입니다"
+
+msgid "Version uses indefinite length"
+msgstr "버전 길ì´ê°€ 무제한입니다"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: ë°œê²¬ëœ ì²«ë²ˆì§¸ %dê°œ 프린터만 추가 중"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: ë¶ˆë¦¬ì–¸ì´ waiteof ì˜µì…˜ì„ ì˜ˆìƒí•¨ \"%s\"\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: 프린터가 ì‘답하지 ì•ŠìŒ\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: 프린터가 예기치 ì•Šì€ EOF를 보냄\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: \"%s:%s\"ì„(를) ì—´ 수 없습니다: %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: PAP ìƒíƒœ ìš”ì²­ì„ ë³´ë‚¼ 수 없습니다"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: %d ìœ í˜•ì˜ ì˜ˆê¸°ì¹˜ ì•Šì€ PAP 패킷\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: %d ìœ í˜•ì˜ ì•Œ 수 없는 PAP 패킷\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: \"%s\" ìƒíƒœ ì˜µì…˜ì— ëŒ€í•œ 예ìƒë˜ëŠ” 번호\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "예"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"<A HREF=\"https://%s:%d%s\">https://%s:%d%s</A> URLì„ ì‚¬ìš©í•˜ì—¬ ì´ íŽ˜ì´ì§€ì— ì—°"
+"결해야 합니다."
+
+msgid "You4 Envelope"
+msgstr "You4 봉투"
+
+msgid "ZPL Label Printer"
+msgstr "ZPL ë ˆì´ë¸” 프린터"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "중단ë¨"
+
+msgid "canceled"
+msgstr "취소ë¨"
+
+msgid "completed"
+msgstr "완료ë¨"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr "convert: 변환할 파ì¼ì„ 지정하려면 -f ì˜µì…˜ì„ ì‚¬ìš©í•©ë‹ˆë‹¤.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "cups-deviced ì‹¤í–‰ì— ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤."
+
+msgid "cups-driverd failed to execute."
+msgstr "cups-driverd ì‹¤í–‰ì— ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: \"%s\" í”„ë¦°í„°ì— ëŒ€í•œ PPD 파ì¼ì´ ì—†ìŒ - %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: ë‹¤ìŒ ì„œë²„ì— ì—°ê²°í•  수 없습니다: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr "cupsd: launchd(8) 지ì›ì´ 컴파ì¼ë˜ì§€ ì•Šì•„ì„œ, ì¼ë°˜ 모드로 실행합니다.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: ìž‘ì—… 파ì¼ì„ ì–»ì„ ìˆ˜ ì—†ìŒ - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd: -q ì˜µì…˜ì€ -v 옵션과 호환ë˜ì§€ 않습니다.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd: -v ì˜µì…˜ì€ -q 옵션과 호환ë˜ì§€ 않습니다.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "%s/%sì— ëŒ€í•œ 장비: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "%sì— ëŒ€í•œ 장비: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "error-index 길ì´ê°€ 무제한입니다"
+
+msgid "error-status uses indefinite length"
+msgstr "error-status 길ì´ê°€ 무제한입니다"
+
+msgid "held"
+msgstr "유지ë¨"
+
+msgid "help\t\tget help on commands\n"
+msgstr "help\t\tëª…ë ¹ì— ëŒ€í•œ ë„ì›€ë§ ì–»ê¸°\n"
+
+msgid "idle"
+msgstr "대기"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: %s í”„ë¦°í„°ì— ì´ë¯¸ %s í´ëž˜ìŠ¤ 회ì›ì´ 있습니다.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: %s í”„ë¦°í„°ì— %s í´ëž˜ìŠ¤ 회ì›ì´ 없습니다.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: ì„œë²„ì— ì—°ê²°í•  수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: \"%s\" PPD 파ì¼ì„ ì—´ 수 ì—†ìŒ - %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: \"%s\" 파ì¼ì„ ì—´ 수 ì—†ìŒ: %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: ì„œë²„ì— ì—°ê²°í•  수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: 프린터 ë˜ëŠ” ì¸ìŠ¤í„´ìŠ¤ë¥¼ 추가할 수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: %sì— ëŒ€í•œ PPD 파ì¼ì„ ì–»ì„ ìˆ˜ ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: 죄송합니다, 암호가 거부ë˜ì—ˆìŠµë‹ˆë‹¤.\n"
+"암호는 최소한 6ìž ì´ìƒì´ì–´ì•¼ 하고, ì‚¬ìš©ìž ì´ë¦„ì„ í¬í•¨í•´ì„œëŠ” 안ë˜ë©°, \n"
+"최소 하나 ì´ìƒì˜ ë¬¸ìž ë° ìˆ«ìžë¥¼ í¬í•¨í•´ì•¼ 합니다.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: 암호 스트ë§ì„ 복사할 수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: 암호 파ì¼ì„ ì—´ 수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: 암호 파ì¼ì— 쓸 수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr "lppasswd: ì´ì „ 암호 파ì¼ì„ ë°±ì—…í•˜ëŠ”ë° ì‹¤íŒ¨í•¨: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: 암호 íŒŒì¼ ì´ë¦„ì„ ìž¬ì„¤ì •í•˜ëŠ”ë° ì‹¤íŒ¨í•¨: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: \"%s\" ì‚¬ìš©ìž ë° \"%s\" ê·¸ë£¹ì´ ì¡´ìž¬í•˜ì§€ 않습니다.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "%s í´ëž˜ìŠ¤ 회ì›:\n"
+
+msgid "no entries\n"
+msgstr "엔트리 ì—†ìŒ\n"
+
+msgid "no system default destination\n"
+msgstr "시스템 기본 ëŒ€ìƒ ì—†ìŒ\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "보류 중"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: \"%s\" í¬í•¨ 디렉토리 추가 중...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: %sì—ì„œ UI í…스트 추가/ì—…ë°ì´íŠ¸ 중...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: ìž˜ëª»ëœ ë¶ˆë¦¬ì–¸ ê°’(%1$s)ì´ %3$sì˜ %2$d번째 ì¤„ì— ìžˆìŒ.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: ìž˜ëª»ëœ ë³€ìˆ˜ 대체항목($%1$c)ì´ %3$sì˜ %2$d번째 ì¤„ì— ìžˆìŒ.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— ë¶ˆë¦¬ì–¸ ê°’ì´ ì˜ˆìƒë¨.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— ì„ íƒì‚¬í•­ 코드가 예ìƒë¨.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— ì„ íƒì‚¬í•­ ì´ë¦„/í…스트가 예ìƒë¨.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: \"%s\" ë“œë¼ì´ë²„ ì •ë³´ íŒŒì¼ ë¡œë“œ 중...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: 로컬 \"%s\"ì— ëŒ€í•œ 메시지 로드 중...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: \"%s\"ì—ì„œ 메시지 로드 중...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: \"%s\" PPD 파ì¼ì„ ìƒì„±í•  수 ì—†ìŒ - %s.\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: %s 출력 디렉토리를 ìƒì„±í•  수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: 출력 파ì´í”„를 ìƒì„±í•  수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: cupstestppd를 실행할 수 ì—†ìŒ: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: \"%s\"ì— ëŒ€í•œ 현지화를 ì°¾ì„ ìˆ˜ ì—†ìŒ - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: \"%s\"ì— ëŒ€í•œ 현지화 파ì¼ì„ 로드할 수 ì—†ìŒ - %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: %3$sì˜ %2$d번째 ì¤„ì— ë³€ìˆ˜(%1$s)ê°€ ì •ì˜ë˜ì§€ ì•ŠìŒ.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: %s 쓰는 중...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: \"%s\" ë””ë ‰í† ë¦¬ì— PPD íŒŒì¼ ì“°ëŠ” 중...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: %s PPD íŒŒì¼ ë¬´ì‹œ 중...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: %sì„(를) %s(으)ë¡œ 백업할 수 ì—†ìŒ- %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "%2$s ì´í›„ë¡œ %1$s 프린터가 ë¹„í™œì„±í™”ë¨ -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "%s 프린터가 대기 중. %s ì´í›„ì— í™œì„±í™”ë¨\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "%s 프린터가 현재 %s-%dì„(를) 프린트 중입니다. %s ì´í›„ì— í™œì„±í™”ë¨\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "%s/%s 프린터가 %s ì´í›„ì— ë¹„í™œì„±í™”ë¨ -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "%s/%s 프린터가 대기 중. %s ì´í›„ì— í™œì„±í™”ë¨\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "%s/%s 프린터가 현재 %s-%dì„(를) 프린트 중입니다. %s ì´í›„ì— í™œì„±í™”ë¨\n"
+
+msgid "processing"
+msgstr "처리 중"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "요청 id는 %s-%d(%dê°œì˜ íŒŒì¼)\n"
+
+msgid "request-id uses indefinite length"
+msgstr "request-id 길ì´ê°€ 무제한입니다"
+
+msgid "scheduler is not running\n"
+msgstr "ì¼ì •ì´ 실행ë˜ì§€ ì•ŠìŒ\n"
+
+msgid "scheduler is running\n"
+msgstr "ì¼ì •ì´ 실행 중\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "%s í†µê³„ì— ì‹¤íŒ¨í•¨: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "ìƒíƒœ\t\të°ëª¬ ë° ëŒ€ê¸°ì—´ ìƒíƒœ 보기\n"
+
+msgid "stopped"
+msgstr "중단ë¨"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "시스템 기본 대ìƒ: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "시스템 기본 대ìƒ: %s/%s\n"
+
+msgid "unknown"
+msgstr "ì•Œ 수 ì—†ìŒ"
+
+msgid "untitled"
+msgstr "무제"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindingsì˜ ê¸¸ì´ê°€ 무제한입니다"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " WARN %sì— ì¼ì¹˜í•˜ëŠ” ì˜µì…˜ì´ ì—†ìŠµë‹ˆë‹¤!\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " WARN 기본 ì„ íƒì‚¬í•­ 충ëŒ!\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " WARN ì–‘ë©´ 옵션 키워드 %sì´(ê°€) 예ìƒëŒ€ë¡œ ë™ìž‘하지 ì•Šì„ ìˆ˜ 있으"
+#~ "ë©° ì´ë¦„ì„ ì–‘ë©´ìœ¼ë¡œ 해야 합니다!\n"
+#~ " REF: 122페ì´ì§€, 섹션 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr " WARN 파ì¼ì´ CR, LF ë° CR LF 줄 ëì„ í¬í•¨í•©ë‹ˆë‹¤!\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " WARN %d번째 줄ì—는 여백만 있습니다!\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " WARN \"%s\" APDialogExtension íŒŒì¼ ìœ ì‹¤ë¨\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " WARN \"%s\" APPrinterIconPath íŒŒì¼ ìœ ì‹¤ë¨\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " WARN 비 Windows PPD 파ì¼ì€ 줄 ëì„ CR LFê°€ ì•„ë‹Œ LF만 있는 줄 ë"
+#~ "ì„ ì‚¬ìš©í•´ì•¼ 합니다!\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " WARN ì´ì „ PPD 버전 %.1f!\n"
+#~ " REF: 42페ì´ì§€, 섹션 5.2.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %sì´(ê°€) 존재하지 않습니다!\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s ìž˜ëª»ëœ %s - ì„ íƒì‚¬í•­ %s!\n"
+#~ " REF: 122페ì´ì§€, 섹션 5.17\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr " %1$s %3$s ì˜µì…˜ì— ëŒ€í•œ ìž˜ëª»ëœ UTF-8 \"%2$s\" 번역 스트ë§!\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %1$s %3$s 옵션, %4$s ì„ íƒì‚¬í•­ì— 대한 ìž˜ëª»ëœ UTF-8 \"%2$s\" 번역 스"
+#~ "트ë§!\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s ìž˜ëª»ëœ \"%s\" cupsFilter ê°’!\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s ìž˜ëª»ëœ %s cupsICCProfile!\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s ìž˜ëª»ëœ \"%s\" cupsPreFilter ê°’!\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s ìž˜ëª»ëœ cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s ìž˜ëª»ëœ \"%s\" 언어!\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s cupsUIConstraints %sì´(ê°€) 비어있ìŒ!\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %1$s %3$s ì˜µì…˜ì— ëŒ€í•œ \"%2$s\" 번역 ìŠ¤íŠ¸ë§ ìœ ì‹¤ë¨!\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %1$s %3$s 옵션, %4$s ì„ íƒì‚¬í•­ì— 대한 \"%2$s\" 번역 ìŠ¤íŠ¸ë§ ìœ ì‹¤ë¨!\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %1$s \"*%4$s %5$s *%6$s %7$s\" UIConstraintsì— ìžˆëŠ” *%2$s %3$s ì„ íƒ"
+#~ "사항 유실ë¨!\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr ""
+#~ " %1$s %4$s cupsUIConstraintsì— ìžˆëŠ” *%2$s %3$s ì„ íƒì‚¬í•­ 유실ë¨: \"%5"
+#~ "$s\"!\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s \"%s\" cupsICCProfile 파ì¼ì´ 유실ë¨!\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s %s cupsUIResolver 유실ë¨!\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %1$s \"*%3$s %4$s *%5$s %6$s\" UIConstraintsì— ìžˆëŠ” %2$s 옵션 유실"
+#~ "ë¨!\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr ""
+#~ " %1$s %3$s cupsUIConstraintsì— ìžˆëŠ” %2$s 옵션 유실ë¨: \"%4$s\"!\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr " %s 파ì¼ì— \"%s\" 기초 ë²ˆì—­ì´ í¬í•¨ë˜ì–´ 있지 않습니다!\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s ì„ íƒì‚¬í•­ ì—†ìŒì„ ì •ì˜í•˜ì§€ ì•Šì€ %sì´(ê°€) í•„ìš”!\n"
+#~ " REF: 122페ì´ì§€, 섹션 5.17\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " %s 불필요한 %s cupsICCProfile ê°’ì´ %s와(ê³¼) 충ëŒí•¨!\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s %s cupsUIResolver가 루프를 유발함!\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr " **FAIL** %s ì„ íƒì‚¬í•­ ì´ë¦„ %s ë° %sì´(ê°€) 경우별로만 다름!\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **FAIL** %sì€(는) 1284DeviceIDì´ì–´ì•¼ 합니다!\n"
+#~ " REF: 72페ì´ì§€, 섹션 5.5\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** ìž˜ëª»ëœ DefaultImageableArea %s!\n"
+#~ " REF: 102페ì´ì§€, 섹션 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** ìž˜ëª»ëœ DefaultPaperDimension %s!\n"
+#~ " REF: 103페ì´ì§€, 섹션 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **FAIL** ìž˜ëª»ëœ %s - ì„ íƒì‚¬í•­ %s!\n"
+#~ " REF: 84페ì´ì§€, 섹션 5.9\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr ""
+#~ " **FAIL** ìž˜ëª»ëœ LanguageEncoding %s - ISOLatin1ì´ì–´ì•¼ 합니다!\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr " **FAIL** ìž˜ëª»ëœ LanguageVersion %s - ì˜ì–´ì—¬ì•¼ 합니다!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **FAIL** %s 옵션 %s ì„ íƒì‚¬í•­ì— 대한 기본 번역 스트ë§ì´ 8비트 문ìž"
+#~ "를 í¬í•¨í•©ë‹ˆë‹¤!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **FAIL** %s ì˜µì…˜ì— ëŒ€í•œ 기본 번역 스트ë§ì´ 8비트 문ìžë¥¼ í¬í•¨í•©ë‹ˆ"
+#~ "다!\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr " **FAIL** %s ë° %s 그룹 ì´ë¦„ì´ ê²½ìš°ë³„ë¡œë§Œ 다름!\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **FAIL** 다중 %s í•­ëª©ì´ %s ì´ë¦„ì„ ì„ íƒ!\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr " **FAIL** %s ë° %s 옵션 ì´ë¦„ì´ ê²½ìš°ë³„ë¡œë§Œ 다름!\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " ìž˜ëª»ëœ %%%%BoundingBox: %d번째 줄!\n"
+#~ " REF: 39페ì´ì§€, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " ìž˜ëª»ëœ %%%%Page: %d번째 줄!\n"
+#~ " REF: 53페ì´ì§€, %%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " ìž˜ëª»ëœ %%%%Pages: %d번째 줄!\n"
+#~ " REF: 43페ì´ì§€, %%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " %d번째 ì¤„ì´ 255ìžë³´ë‹¤ ê¹ë‹ˆë‹¤(%d)!\n"
+#~ " REF: 25페ì´ì§€, 줄 길ì´\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " 첫번째 ì¤„ì— ìžˆëŠ” %!PS-Adobe-3.0ì´ ìœ ì‹¤ë¨!\n"
+#~ " REF: 17페ì´ì§€, 3.1 ë„í멘트 구성하기\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " %%EndComments 설명 유실ë¨!\n"
+#~ " REF: 41페ì´ì§€, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " 유실ë˜ì—ˆê±°ë‚˜ ìž˜ëª»ëœ %%BoundingBox: 설명!\n"
+#~ " REF: 39페ì´ì§€, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " 유실ë˜ì—ˆê±°ë‚˜ ìž˜ëª»ëœ %%Page: 설명!\n"
+#~ " REF: 53페ì´ì§€, %%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " 유실ë˜ì—ˆê±°ë‚˜ ìž˜ëª»ëœ %%Page: 설명!\n"
+#~ " REF: 43페ì´ì§€, %%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " 255ìžë¥¼ 초과하는 %dê°œì˜ ì¤„ 발견!\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " 너무 ë§Žì€ %%BeginDocument 설명!\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " 너무 ë§Žì€ %%EndDocument 설명!\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " 경고: 파ì¼ì— ë°”ì´ë„ˆë¦¬ ë°ì´í„°ê°€ í¬í•¨ë˜ì–´ 있습니다!\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " 경고: 파ì¼ì— %%EndComments ì„¤ëª…ì´ ì—†ìŠµë‹ˆë‹¤!\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " 경고: 파ì¼ì— ì´ì „ DSC 버전 %.1fê°€ 있습니다!\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%sì´(ê°€) 지ì›ë˜ì§€ ì•ŠìŒ!"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: 해야할 ì¼ì„ 모르겠ìŒ!\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr "%1$s: 오류 - \"%3$s\" 대ìƒì— 존재하지 않는 %2$s 환경 변수 ì´ë¦„!\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: 오류 - ìž˜ëª»ëœ ìž‘ì—… ID!\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr "%s: 오류 - 파ì¼ì„ 프린트할 수 없고 ìž‘ì—…ì„ ë™ì‹œì— 대체할 수 ì—†ìŒ!\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: 오류 - íŒŒì¼ ë˜ëŠ” ìž‘ì—… IDê°€ 제공ë˜ì—ˆë‹¤ë©´ stdinì—ì„œ 프린트할 수 ì—†ìŒ!\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: 오류 - '-S' 옵션 ë’¤ì— ë¬¸ìž ì„¸íŠ¸ê°€ 예ìƒë¨!\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: 오류 - '-T' 옵션 ë’¤ì— ì½˜í…츠 ìœ í˜•ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: 오류 - '-n' 옵션 ë’¤ì— ë³µì‚¬ 매수가 예ìƒë¨!\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s: 오류 - '-#' 옵션 ë’¤ì— ë³µì‚¬ë³¸ 수가 예ìƒë¨!\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: 오류 - '-P' 옵션 ë’¤ì— ëŒ€ìƒì´ 예ìƒë¨!\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: 오류 - '-b' 옵션 ë’¤ì— ëŒ€ìƒì´ 예ìƒë¨!\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: 오류 - '-d' 옵션 ë’¤ì— ëŒ€ìƒì´ 예ìƒë¨!\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: 오류 - '-f' 옵션 ë’¤ì— êµ¬ì„±ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: 오류 - '-H' 옵션 ë’¤ì— ìœ ì§€ ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: 오류 - '-H' 옵션 ë’¤ì— í˜¸ìŠ¤íŠ¸ ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: 오류 - '-h' 옵션 ë’¤ì— í˜¸ìŠ¤íŠ¸ ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: 오류 - '-y' 옵션 ë’¤ì— ëª¨ë“œ 목ë¡ì´ 예ìƒë¨!\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: 오류 - '-%c' 옵션 ë’¤ì— ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s: 오류 - '-o' 옵션 ë’¤ì— ì˜µì…˜ 스트ë§ì´ 예ìƒë¨!\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: 오류 - '-P' 옵션 ë’¤ì— íŽ˜ì´ì§€ 목ë¡ì´ 예ìƒë¨!\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: 오류 - '-%c' 옵션 ë’¤ì— ìš°ì„ ìˆœìœ„ê°€ 예ìƒë¨!\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s: 오류 - '-r' 옵션 ë’¤ì— ì´ìœ  í…스트가 예ìƒë¨!\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: 오류 - '-t' 옵션 ë’¤ì— ì œëª©ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s: 오류 - '-U' 옵션 ë’¤ì— ì‚¬ìš©ìž ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s: 오류 - '-u' 옵션 ë’¤ì— ì‚¬ìš©ìž ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: 오류 - '-%c' 옵션 ë’¤ì— ê°’ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: 오류 - '-W' 옵션 ë’¤ì— \"completed\", \"not-completed\" ë˜ëŠ” \"all\"ì´ "
+#~ "í•„ìš”!\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: 오류 - ì¼ì •ì´ ì‘답하지 ì•ŠìŒ!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: 오류 - ì•Œ 수 없는 ëŒ€ìƒ \"%s\"!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: 오류 - ì•Œ 수 없는 ëŒ€ìƒ \"%s/%s\"!\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: 오류 - 알 수 없는 옵션 '%c'!\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: 오류 - 알 수 없는 옵션 '%s'!\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: '-i' 옵션 ë’¤ì— ìž‘ì—… IDê°€ 예ìƒë¨!\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: \"%s\" 목ë¡ì— 유효하지 ì•Šì€ ëŒ€ìƒ ì´ë¦„!\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr "%s: '-H restart' ì•žì— ìž‘ì—… ID('-i jobid') í•„ìš”!\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: %s/%sì—ì„œ %s/%s까지 변환할 í•„í„°ê°€ ì—†ìŒ!\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s: 죄송합니다, 컴파ì¼ëœ 암호화 지ì›ì´ 없습니다!\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: ì„œë²„ì— ì—°ê²°í•  수 ì—†ìŒ!\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: MIME ìœ í˜•ì˜ \"%s\"ì„(를) ê²°ì •í•  수 ì—†ìŒ!\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s: %sì„(를) ì—´ 수 ì—†ìŒ - %s\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s: %sì„(를) ì—´ 수 ì—†ìŒ - %s, %d번째 줄\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s: \"%s\" ë˜ëŠ” \"%s\"ì—ì„œ MIME ë°ì´í„°ë² ì´ìŠ¤ë¥¼ ì½ì„ 수 ì—†ìŒ!\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: ì•Œ 수 없는 ëŒ€ìƒ \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: ì•Œ 수 없는 ëŒ€ìƒ MIME 유형 %s/%s!\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: 알 수 없는 옵션 '%c'!\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: 알 수 없는 소스 MIME 유형 %s/%s!\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: 경고 - '%c' í¬ë§· ì¡°í•© 키가 지ì›ë˜ì§€ ì•ŠìŒ - ì¶œë ¥ì´ ì˜¬ë°”ë¥´ì§€ ì•Šì„ ìˆ˜ 있"
+#~ "습니다!\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: 경고 - ë¬¸ìž ì„¸íŠ¸ ì˜µì…˜ì´ ë¬´ì‹œë¨!\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: 경고 - 콘í…츠 유형 ì˜µì…˜ì´ ë¬´ì‹œë¨!\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: 경고 - 구성 ì˜µì…˜ì´ ë¬´ì‹œë¨!\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: 경고 - 모드 ì˜µì…˜ì´ ë¬´ì‹œë¨!\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr "%1$s: 오류 - \"%3$s\" 대ìƒì— 존재하지 않는 %2$s 환경 변수 ì´ë¦„!\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: 오류 - '-o' 옵션 ë’¤ì— option=valueê°€ 예ìƒë¨!\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "600 DPI ê·¸ë ˆì´ ìŠ¤ì¼€ì¼"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr "프린터 ë“œë¼ì´ë²„를 보내려면 Samba 암호가 필요함!"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr "프린터 ë“œë¼ì´ë²„를 보내려면 Samba ì‚¬ìš©ìž ì´ë¦„ì´ í•„ìš”í•¨!"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "\"%s\"(ì´)ë¼ëŠ” ì´ë¦„ì˜ í´ëž˜ìŠ¤ê°€ ì´ë¯¸ 존재합니다!"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "\"%s\"(ì´)ë¼ëŠ” ì´ë¦„ì˜ í”„ë¦°í„°ê°€ ì´ë¯¸ 존재합니다!"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr "%s 프린터 ìƒíƒœë¥¼ ìž˜ëª»ëœ %d 값으로 설정하려고 합니다!"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "ì†ì„± ê·¸ë£¹ì´ ì˜¬ë°”ë¥´ì§€ 않습니다(%x < %x)!"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "ìž˜ëª»ëœ ìž¥ë¹„ URI \"%s\"!\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "ìž˜ëª»ëœ device-uri \"%s\"!"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "ìž˜ëª»ëœ device-uri 설계 \"%s\"!"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "ìž˜ëª»ëœ document-format \"%s\"!"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "ìž˜ëª»ëœ íŒŒì¼ ì´ë¦„ 버í¼!"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "ìž˜ëª»ëœ job-priority ê°’!"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "ìž˜ëª»ëœ job-sheets ê°’\"%s\"!"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "ìž˜ëª»ëœ job-sheets ê°’ 유형!"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "ìž˜ëª»ëœ job-state ê°’!"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "ìž˜ëª»ëœ job-uri ì†ì„± \"%s\"!"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "ìž˜ëª»ëœ notify-pull-method \"%s\"!"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "ìž˜ëª»ëœ notify-recipient-uri URI \"%s\"!"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "%d번째 ì¤„ì— ìžˆëŠ” ìž˜ëª»ëœ ì˜µì…˜ + ì„ íƒì‚¬í•­!"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "ìž˜ëª»ëœ port-monitor \"%s\"!"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "ìž˜ëª»ëœ printer-state ê°’ %d!"
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "ìž˜ëª»ëœ ìš”ì²­ 버전 ìˆ«ìž %d.%d!"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "ìž˜ëª»ëœ êµ¬ë… ID!"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "\"%s\" ë¬¸ìž ì„¸íŠ¸ê°€ 지ì›ë˜ì§€ ì•ŠìŒ!"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "\"%s\" ìœ í˜•ì„ ê²€ìƒ‰í•  수 ì—†ìŒ!"
+
+#~ msgid "Cover open."
+#~ msgstr "ë®ê°œê°€ ì—´ë ¤ 있ìŒ."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "현ìƒì•¡ì´ ê±°ì˜ ë¹„ì—ˆìŠµë‹ˆë‹¤."
+
+#~ msgid "Developer empty!"
+#~ msgstr "현ìƒì•¡ì´ 비어 있ìŒ!"
+
+#~ msgid "Door open."
+#~ msgstr "ë¬¸ì´ ì—´ë ¤ 있ìŒ."
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: ìž˜ëª»ëœ %%BoundingBox: ì„¤ëª…ì´ ë³´ìž„!\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: ìž˜ëª»ëœ %%IncludeFeature: 설명!\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: ìž˜ëª»ëœ %%Page: 파ì¼ì— 있는 설명!\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: ìž˜ëª»ëœ %%PageBoundingBox: 파ì¼ì— 있는 설명!\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: ìž˜ëª»ëœ SCSI 장비 íŒŒì¼ \"%s\"!\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: ìž˜ëª»ëœ ì—´ ê°’ %d!\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: ìž˜ëª»ëœ cpi ê°’ %f!\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: ìž˜ëª»ëœ lpi ê°’ %f!\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: ìž˜ëª»ëœ íŽ˜ì´ì§€ 설정!\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: ëŒ€ìƒ í”„ë¦°í„°ê°€ 없습니다!\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: %%BoundingBox 복제: ì„¤ëª…ì´ ë³´ìž„!\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: %%Pages 복제: ì„¤ëª…ì´ ë³´ìž„!\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: 빈 프린트 파ì¼!\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr "ERROR: %2$sì˜ %1$d번째 ì¤„ì— ì¸ìš© 스트ë§ì´ 예ìƒë¨!\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: 심ê°í•œ USB 오류!\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr ""
+#~ "ERROR: 파ì¼ì„ 프린트할 수 없는, 유효하지 ì•Šì€ HP-GL/2 ëª…ë ¹ì´ ë³´ìž„!\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: %%EndPrologê°€ 유실ë¨!\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: %%EndSetupì´ ìœ ì‹¤ë¨!\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: 명령 ë¼ì¸ì˜ 장비 URIê°€ 유실ë˜ì—ˆê³  DEVICE_URI 환경 변수가 ì—†ìŒ!\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: 배너 파ì¼ì˜ %d번째 줄 ê°’ì´ ìœ ì‹¤ë¨!\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: %2$sì˜ %1$d번째 ì¤„ì— ìžˆëŠ” 모든 번역 ìŠ¤íŠ¸ë§ ì•žì— msgid 줄 í•„ìš”!\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: %%BoundingBoxê°€ ì—†ìŒ: 머리ë§ì— 설명!\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: %%Pagesê°€ ì—†ìŒ: 머리ë§ì— 설명!\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: argv[0] ë˜ëŠ” DEVICE_URI 환경 변수ì—ì„œ ë°œê²¬ëœ ìž¥ë¹„ URIê°€ ì—†ìŒ!\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: 페ì´ì§€ ì—†ìŒ!\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: ì¢…ì´ ì—†ìŒ!\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: PRINTER 환경 변수가 ì •ì˜ë˜ì§€ ì•ŠìŒ!\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: 프린트 파ì¼ì´ 허용ë˜ì§€ ì•ŠìŒ(%s)!\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: 프린터가 ì‘답하지 ì•ŠìŒ!\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: ìž„ì‹œ 파ì¼ì„ ìƒì„±í•  수 ì—†ìŒ - %s.\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: ìž„ì‹œ 파ì¼ì„ ìƒì„±í•  수 ì—†ìŒ: %s\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: ìž‘ì—… %d ì†ì„±ì„ ì–»ì„ ìˆ˜ ì—†ìŒ(%s)!\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: 프린터 ìƒíƒœë¥¼ ì•Œ 수 ì—†ìŒ(%s)!\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: '%s' 프린터를 ì°¾ì„ ìˆ˜ ì—†ìŒ!\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: ì´ë¯¸ì§€ 파ì¼ì„ ì—´ì–´ì„œ 프린트할 수 ì—†ìŒ!\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: ìž„ì‹œ 파ì¼ì„ ì—´ 수 ì—†ìŒ"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: %dê°œì˜ í…스트 ì—´ì„ í”„ë¦°íŠ¸í•  수 ì—†ìŒ!\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: %dx%d í…스트 페ì´ì§€ë¥¼ 프린트할 수 ì—†ìŒ!\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: 프린트 ë°ì´í„°ë¥¼ ì½ì„ 수 ì—†ìŒ!\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: 프린트 ë°ì´í„°ë¥¼ 보낼 수 ì—†ìŒ(%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: 프린트 ë°ì´í„°ë¥¼ 보낼 수 ì—†ìŒ!\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: í”„ë¦°í„°ì— %dë°”ì´íŠ¸ë¥¼ 쓸 수 ì—†ìŒ!\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr "ERROR: ë“œë¼ì´ë²„ì— ëž˜ìŠ¤í„° ë°ì´í„°ë¥¼ 쓸 수 ì—†ìŒ!\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: ìž„ì‹œ 파ì¼ì„ 쓸 수 ì—†ìŒ"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: %2$sì˜ %1$d번째 ì¤„ì— ì˜ˆê¸°ì¹˜ ì•Šì€ í…스트!\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: 알 수 없는 암호화 옵션 값 \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: \"%s\"ì— ëŒ€í•œ ì•Œ 수 없는 메시지 카탈로그 í¬ë§·!\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: \"%2$s\" ê°’ì´ ìžˆëŠ” ì•Œ 수 없는 \"%1$s\" 옵션!\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: 알 수 없는 \"%s\" 버전 옵션 값!\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr "ERROR: brightness=100ì„ ì‚¬ìš©í•˜ëŠ”, 지ì›ë˜ì§€ 않는 ë°ê¸° ê°’ %s!\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: gamma=1000ì„ ì‚¬ìš©í•˜ëŠ”, 지ì›ë˜ì§€ 않는 ê°ë§ˆ ê°’ %s!\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr "ERROR: number-up=1ì„ ì‚¬ìš©í•˜ëŠ”, 지ì›ë˜ì§€ 않는 number-up ê°’ %d!\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: number-up-layout=lrtbì„ ì‚¬ìš©í•˜ëŠ”, 지ì›ë˜ì§€ 않는 number-up-layout "
+#~ "ê°’ %s!\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: page-border=noneì„ ì‚¬ìš©í•˜ëŠ”, 지ì›ë˜ì§€ 않는 page-border ê°’ %s!\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr "ERROR: doc_printf 오버플로우(%dë°”ì´íŠ¸)ê°€ 발견ë¨, 중단 중!\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr "ERROR: pdftops í•„í„°ê°€ 신호 %dì—ì„œ 충ëŒí•¨!\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr "ERROR: pdftops í•„í„°ê°€ ìƒíƒœ %d(으)ë¡œ 종료ë¨!\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstopsê°€ 신호 %dì—ì„œ 종료ë¨!\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstopsê°€ ìƒíƒœ %d(으)ë¡œ 종료ë¨!\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr "ERROR: ë³µì› ê°€ëŠ¥: í”„ë¦°í„°ì— ì—°ê²°í•  수 ì—†ìŒ; 30ì´ˆ í›„ì— ë‹¤ì‹œ ì‹œë„...\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "PPD 파ì¼ì´ 비어있ìŒ!"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "오류: '-h' 옵션 ë’¤ì— í˜¸ìŠ¤íŠ¸ ì´ë¦„ì´ í•„ìš”!\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "퓨저 온ë„ê°€ 높ìŒ!"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "퓨저 온ë„ê°€ ë‚®ìŒ!"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "printer-uri ì†ì„±ì„ 얻었지만, job-idê°€ 없습니다!"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "잉í¬/토너가 ê±°ì˜ ë¹„ì—ˆìŠµë‹ˆë‹¤."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "잉í¬/토너가 비었ìŒ!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "잉í¬/토너 í기소가 ê±°ì˜ ì°¼ìŠµë‹ˆë‹¤."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "잉í¬/토너 í기소가 ì°¼ìŒ!"
+
+#~ msgid "Interlock open."
+#~ msgstr "ì—°ë™ ìž¥ì¹˜ê°€ ì—´ë ¤ 있ìŒ."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "#%d ìž‘ì—…ì„ ë‹¤ì‹œ 시작할 수 ì—†ìŒ - íŒŒì¼ ì—†ìŒ!"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "#%d ìž‘ì—…ì´ ì—†ìŒ!"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "#%d ìž‘ì—…ì´ ì¢…ë£Œë˜ì—ˆê³  대체할 수 ì—†ìŒ!"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "#%d ìž‘ì—…ì´ ì™¼ë£Œë˜ì§€ ì•ŠìŒ!"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "#%d ìž‘ì—…ì´ ì¸ì¦ì„ 위해 유지ë˜ì§€ ì•ŠìŒ!"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "#%d ìž‘ì—…ì´ ìœ ì§€ë˜ì§€ ì•ŠìŒ!"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "#%s ìž‘ì—…ì´ ì¡´ìž¬í•˜ì§€ ì•ŠìŒ!"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "%d ìž‘ì—…ì´ ë°œê²¬ë˜ì§€ ì•ŠìŒ!"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "ìž‘ì—… 구ë…ì„ ê°±ì‹ í•  수 ì—†ìŒ!"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "\"%s\" 언어가 지ì›ë˜ì§€ ì•ŠìŒ!"
+
+#~ msgid "Media jam!"
+#~ msgstr "미디어가 걸림!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "미디어 트레ì´ê°€ ê±°ì˜ ë¹„ì—ˆìŠµë‹ˆë‹¤."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "미디어 트레ì´ê°€ 비어 있ìŒ!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "미디어 트레ì´ê°€ 유실ë¨!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "미디어 트레ì´ë¥¼ 채워야 합니다."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "document-number ì†ì„±ì´ 유실ë¨!"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "%d번째 ì¤„ì— ìžˆëŠ” í° ë”°ì˜´í‘œê°€ 유실ë¨!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "구성 변수가 유실ë¨!"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "notify-subscription-ids ì†ì„±ì´ 유실ë¨!"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "requesting-user-name ì†ì„±ì´ 유실ë¨!"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "필요한 ì†ì„±ì´ 유실ë¨!"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "%d번째 ì¤„ì— ìžˆëŠ” ê°’ì´ ìœ ì‹¤ë¨!"
+
+#~ msgid "No PPD name!"
+#~ msgstr "PPD ì´ë¦„ ì—†ìŒ!"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "ì„¤ì¹˜ëœ Windows 프린터 ë“œë¼ì´ë²„ê°€ ì—†ìŒ!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "%sì— í™œì„± ìž‘ì—…ì´ ì—†ìŒ!"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "ìš”ì²­ì— ì†ì„±ì´ ì—†ìŒ!"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "ì œê³µëœ ì¸ì¦ ì •ë³´ê°€ ì—†ìŒ!"
+
+#~ msgid "No file!?!"
+#~ msgstr "파ì¼ì´ ì—†ìŒ!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "수정 시간 ì—†ìŒ!"
+
+#~ msgid "No printer name!"
+#~ msgstr "프린터 ì´ë¦„ ì—†ìŒ!"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "í´ëž˜ìŠ¤ì— 대한 printer-uri ì—†ìŒ!"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "printer-uri ì—†ìŒ!"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "ìš”ì²­ì— printer-uri ì—†ìŒ!"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "ìš”ì²­ì— êµ¬ë… ì†ì„±ì´ ì—†ìŒ!"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC ìˆ˜ëª…ì´ ê±°ì˜ ë‹¤ ë˜ì—ˆìŠµë‹ˆë‹¤."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC ìˆ˜ëª…ì´ ë‹¤ ë˜ì—ˆìŒ!"
+
+#~ msgid "Out of toner!"
+#~ msgstr "토너가 ì—†ìŒ!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "출력소 ê±°ì˜ ì°¼ìŠµë‹ˆë‹¤."
+
+#~ msgid "Output bin full!"
+#~ msgstr "출력소가 찼습니다!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "출력 트레ì´ê°€ 유실ë¨!"
+
+#~ msgid "Printer offline."
+#~ msgstr "프린터가 오프ë¼ì¸ìž…니다."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "SCSI 프린터"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "notify-user-data ê°’ì´ ë„ˆë¬´ í¼!(%d > 63í–‰)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "프린터 ë˜ëŠ” í´ëž˜ìŠ¤ë¥¼ 공유할 수 ì—†ìŒ!"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "printer-uri ì†ì„±ì´ 필요함!"
+
+#~ msgid "Toner low."
+#~ msgstr "토너가 부족합니다."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "job-sheets ê°’ì´ ë„ˆë¬´ 많습니다(%d > 2)!"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "printer-state-reasons ê°’ì´ ë„ˆë¬´ 많습니다(%d > %d)!"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "\"%s\" 대ìƒì— 대한 ìž‘ì—…ì„ ì¶”ê°€í•  수 없습니다!"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "íŒŒì¼ ìœ í˜•ì— ëŒ€í•œ 메모리를 할당할 수 없습니다!"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr "64비트 CUPS 프린터 ë“œë¼ì´ë²„ 파ì¼ì„ 복사할 수 없습니다(%d)!"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr "64비트 Windows 프린터 ë“œë¼ì´ë²„ 파ì¼ì„ 복사할 수 없습니다(%d)!"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr "CUPS 프린터 ë“œë¼ì´ë²„ 파ì¼ì„ 복사할 수 없습니다(%d)!"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "PPD 파ì¼ì„ 복사할 수 ì—†ìŒ - %s!"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "PPD 파ì¼ì„ 복사할 수 없습니다!"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr "Windows 2000 프린터 ë“œë¼ì´ë²„ 파ì¼ì„ 복사할 수 없습니다(%d)!"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr "Windows 9x 프린터 ë“œë¼ì´ë²„ 파ì¼ì„ 복사할 수 없습니다(%d)!"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "ì¸í„°íŽ˜ì´ìŠ¤ 스í¬ë¦½íŠ¸ë¥¼ 복사할 수 ì—†ìŒ - %s!"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "printer-uri를 ìƒì„±í•  수 없습니다!"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr "1MB보다 í° cupsd.conf 파ì¼ì€ 편집할 수 없습니다!"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "ìž‘ì—…ì— ëŒ€í•œ 대ìƒì„ ì°¾ì„ ìˆ˜ 없습니다!"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "프린터를 ì°¾ì„ ìˆ˜ 없습니다!\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr "Windows 2000 프린터 ë“œë¼ì´ë²„ 파ì¼ì„ 설치할 수 없습니다(%d)!"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr "Windows 9x 프린터 ë“œë¼ì´ë²„ 파ì¼ì„ 설치할 수 없습니다(%d)!"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "ë„í멘트 %dì„(를) ìž‘ì—… %dì—ì„œ ì—´ 수 없습니다!"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "프린터 ë“œë¼ì´ë²„ë¡œ ëª…ë ¹ì„ ë³´ë‚¼ 수 없습니다!"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Windows 프린터 ë“œë¼ì´ë²„를 설정할 수 없습니다(%d)!"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "레거시 USB í´ëž˜ìŠ¤ ë“œë¼ì´ë²„를 사용할 수 ì—†ìŒ!\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "알 수 없는 프린터 오류(%s)!"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "지ì›ë˜ì§€ 않는 ë¬¸ìž ì„¸íŠ¸ \"%s\"!"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "지ì›ë˜ì§€ 않는 압축 \"%s\"!"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "지ì›ë˜ì§€ 않는 압축 ì†ì„± %s!"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "지ì›ë˜ì§€ 않는 í¬ë§· \"%s\"!"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "지ì›ë˜ì§€ 않는 í¬ë§· '%s'!"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "지ì›ë˜ì§€ 않는 í¬ë§· '%s/%s'!"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "사용법: convert [ options ]\n"
+#~ "\n"
+#~ "옵션:\n"
+#~ "\n"
+#~ " -f filename 변환할 íŒŒì¼ ì„¤ì •(ë˜ëŠ” stdin)\n"
+#~ " -o filename ìƒì„±í•  íŒŒì¼ ì„¤ì •(ë˜ëŠ” stdout)\n"
+#~ " -i mime/type ìž…ë ¥ MIME 유형 설정(ë˜ëŠ” ìžë™ 유형 설정)\n"
+#~ " -j mime/type 출력 MIME 유형 설정(ë˜ëŠ” ì‘ìš© 프로그램/pdf)\n"
+#~ " -P filename.ppd PPD íŒŒì¼ ì„¤ì •\n"
+#~ " -a 'name=value ...' 옵션 설정(s)\n"
+#~ " -U username ìž‘ì—…ì— ëŒ€í•œ ì‚¬ìš©ìž ì´ë¦„ 설정\n"
+#~ " -J title 제목 설정\n"
+#~ " -c copies 복사 장 수 설정\n"
+#~ " -u 종료 ì‹œ PPD íŒŒì¼ ì œê±°\n"
+#~ " -D 종료 ì‹œ ìž…ë ¥ íŒŒì¼ ì œê±°\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "사용법: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "옵션:\n"
+#~ "\n"
+#~ " -c cupsd.conf cupsd.conf 파ì¼ì„ 설정하여 사용\n"
+#~ " -j job-id[,N] 특정 작업으로부터 íŒŒì¼ N í•„í„°(ê¸°ë³¸ì€ íŒŒì¼ 1)\n"
+#~ " -n copies 복사 장 수 설정\n"
+#~ " -o name=value 옵션 설정\n"
+#~ " -p filename.ppd PPD íŒŒì¼ ì„¤ì •\n"
+#~ " -t title 제목 설정\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "사용법: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[."
+#~ "gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "옵션:\n"
+#~ "\n"
+#~ " -R root-directory 대체 루트 설정\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " 오류대신 문제 경고\n"
+#~ " -q 조용히 실행\n"
+#~ " -r 'relaxed' 오픈 모드 사용\n"
+#~ " -v 약간 ìžì„¸í•˜ê²Œ\n"
+#~ " -vv 매우 ìžì„¸í•˜ê²Œ\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: ì½ê¸° side-channel ìš”ì²­ì— ì‹¤íŒ¨í•¨!\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr "WARNING: IncludeFeature를 통해 \"%s\" ì˜µì…˜ì„ í¬í•¨í•  수 ì—†ìŒ!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: %dì´ˆ í›„ì— ì›ê²© 호스트가 명령 ìƒíƒœ ë°”ì´íŠ¸ì— ì‘답하지 ì•ŠìŒ!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: %dì´ˆ í›„ì— ì›ê²© 호스트가 제어 ìƒíƒœ ë°”ì´íŠ¸ì— ì‘답하지 ì•ŠìŒ!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: %dì´ˆ í›„ì— ì›ê²© 호스트가 ë°ì´í„° ìƒíƒœ ë°”ì´íŠ¸ì— ì‘답하지 ì•ŠìŒ!\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr "WARNING: SCSI 명령 시간 초과(%d); ìž¬ì‹œë„ ì¤‘...\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: ì´ ë„í멘트는 Adobe Document Structuring Conventionsì„ ì‹¤í–‰í•˜ì§€ "
+#~ "않기 ë•Œë¬¸ì— ì˜¬ë°”ë¥´ê²Œ 프린트ë˜ì§€ ì•Šì„ ìˆ˜ 있ìŒ!\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: \"%2$s\" ì˜µì…˜ì— ëŒ€í•œ ì•Œ 수 없는 \"%1$s\" ì„ íƒì‚¬í•­!\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: 알 수 없는 \"%s\" 옵션!\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: 지ì›ë˜ì§€ 않는 보드율 %s!\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: ë³µì› ê°€ëŠ¥: '%s' ë„¤íŠ¸ì›Œí¬ í˜¸ìŠ¤íŠ¸ê°€ 사용 중; %dì´ˆ í›„ì— ë‹¤ì‹œ ì‹œ"
+#~ "ë„...\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr "경고, ì„¤ì¹˜ëœ Windows 2000 프린터 ë“œë¼ì´ë²„ê°€ ì—†ìŒ!"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: 알 수 없는 옵션 \"%s\"!\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: 알 수 없는 옵션 \"-%c\"!\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr "cupsd: \"-c\" 옵션 ë’¤ì— êµ¬ì„± íŒŒì¼ ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: 현재 디렉토리를 ì–»ì„ ìˆ˜ ì—†ìŒ!\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: 알 수 없는 \"%s\" 변수 - 중단 중!\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: 알 수 없는 \"%c\" 옵션 - 중단 중!\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: 유효하지 ì•Šì€ ë„í멘트 번호 %d!\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: 유효하지 ì•Šì€ ìž‘ì—… ID %d!\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: í•˜ë‚˜ì˜ ì‚¬ìš©ìž ì´ë¦„만 지정ë¨!\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter: ë‹¤ìŒ ìž„ì‹œ 파ì¼ì„ ìƒì„±í•  수 없습니다: %s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "job-printer-uri ì†ì„±ì´ 유실ë¨!"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr "lpadmin: í´ëž˜ìŠ¤ ì´ë¦„ì€ í”„ë¦°íŠ¸ 가능한 문ìžë§Œ í¬í•¨í•  수 있ìŒ!\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: '-P' 옵션 ë’¤ì— PPDê°€ 예ìƒë¨!\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr "lpadmin: '-u' 옵션 ë’¤ì— allow/deny:userlistê°€ 예ìƒë¨!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: '-r' 옵션 ë’¤ì— í´ëž˜ìŠ¤ê°€ 예ìƒë¨!\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: '-c' 옵션 ë’¤ì— í´ëž˜ìŠ¤ ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: '-D' 옵션 ë’¤ì— ì„¤ëª…ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: '-v' 옵션 ë’¤ì— ìž¥ë¹„ URIê°€ 예ìƒë¨!\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: '-I' 옵션 ë’¤ì— íŒŒì¼ ìœ í˜•ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: '-h' 옵션 ë’¤ì— í˜¸ìŠ¤íŠ¸ ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: '-i' 옵션 ë’¤ì— ì¸í„°íŽ˜ì´ìŠ¤ê°€ 예ìƒë¨!\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: '-L' 옵션 ë’¤ì— ìœ„ì¹˜ê°€ 예ìƒë¨!\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: '-m' 옵션 ë’¤ì— ëª¨ë¸ì´ 예ìƒë¨!\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: '-o' 옵션 ë’¤ì— name=valueê°€ 예ìƒë¨!\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: '-p' 옵션 ë’¤ì— í”„ë¦°í„°ê°€ 예ìƒë¨!\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: '-d' 옵션 ë’¤ì— í”„ë¦°í„° ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin: '-x' 옵션 ë’¤ì— í”„ë¦°í„° ë˜ëŠ” í´ëž˜ìŠ¤ê°€ 예ìƒë¨!\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: íšŒì› ì´ë¦„ì´ ë³´ì´ì§€ ì•ŠìŒ!\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr "lpadmin: 프린터 ì´ë¦„ì€ í”„ë¦°íŠ¸ 가능한 문ìžë§Œ í¬í•¨í•  수 있ìŒ!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: í´ëž˜ìŠ¤ì— 프린터를 추가할 수 ì—†ìŒ:\n"
+#~ " 먼저 프린터 ì´ë¦„ì„ ì§€ì •í•´ì•¼ 합니다!\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin: ìž„ì‹œ 파ì¼ì„ ìƒì„±í•  수 ì—†ìŒ - %s\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin: ìž„ì‹œ 파ì¼ì„ ìƒì„±í•  수 ì—†ìŒ: %s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: í´ëž˜ìŠ¤ì—ì„œ 프린터를 제거할 수 ì—†ìŒ:\n"
+#~ " 먼저 프린터 ì´ë¦„ì„ ì§€ì •í•´ì•¼ 합니다!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: PPD 파ì¼ì„ 설정할 수 ì—†ìŒ:\n"
+#~ " 먼저 프린터 ì´ë¦„ì„ ì§€ì •í•´ì•¼ 합니다!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: 장비 URI를 설정할 수 ì—†ìŒ:\n"
+#~ " 먼저 프린터 ì´ë¦„ì„ ì§€ì •í•´ì•¼ 합니다!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: ì¸í„°íŽ˜ì´ìŠ¤ 스í¬ë¦½íŠ¸ ë˜ëŠ” PPD 파ì¼ì„ 설정할 수 ì—†ìŒ:\n"
+#~ " 먼저 프린터 ì´ë¦„ì„ ì§€ì •í•´ì•¼ 합니다!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: ì¸í„°íŽ˜ì´ìŠ¤ 스í¬ë¦½íŠ¸ë¥¼ 설정할 수 ì—†ìŒ:\n"
+#~ " 먼저 프린터 ì´ë¦„ì„ ì§€ì •í•´ì•¼ 합니다!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: 프린터 ì„¤ëª…ì„ ì„¤ì •í•  수 ì—†ìŒ:\n"
+#~ " 먼저 프린터 ì´ë¦„ì„ ì§€ì •í•´ì•¼ 합니다!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: 프린터 위치를 설정할 수 ì—†ìŒ:\n"
+#~ " 먼저 프린터 ì´ë¦„ì„ ì§€ì •í•´ì•¼ 합니다!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: 프린터 ì˜µì…˜ì„ ì„¤ì •í•  수 ì—†ìŒ:\n"
+#~ " 먼저 프린터 ì´ë¦„ì„ ì§€ì •í•´ì•¼ 합니다!\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: 알 수 없는 allow/deny 옵션 \"%s\"!\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: 알 수 없는 '%s' 변수!\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: 알 수 없는 '%c' 옵션!\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin: 경고 - 콘í…츠 유형 ëª©ë¡ ë¬´ì‹œë¨!\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr "lpinfo: --device-id ë’¤ì— 1284 장비 ID 스트ë§ì´ 예ìƒë¨!\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: --language ë’¤ì— ì–¸ì–´ê°€ 예ìƒë¨!\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo: --make-and-model ë’¤ì— ì œì¡°ì‚¬ ë° ëª¨ë¸ì´ 예ìƒë¨!\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo: --product ë’¤ì— ì œí’ˆ 스트ë§ì´ 예ìƒë¨!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo: --exclude-schemes ë’¤ì— ì„¤ê³„ 목ë¡ì´ 예ìƒë¨!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo: --include-schemess ë’¤ì— ì„¤ê³„ 목ë¡ì´ 예ìƒë¨!\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: --timeout ë’¤ì— ì œí•œ ì‹œê°„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: 알 수 없는 '%s' 변수!\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: 알 수 없는 '%c' 옵션!\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: 알 수 없는 '%s' 옵션!\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: 알 수 없는 '%s' 변수!\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: 알 수 없는 '%c' 옵션!\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: 프린터가 없습니까!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: %sì— ëŒ€í•œ PPD 파ì¼ì„ ì—´ 수 ì—†ìŒ!\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: ì•Œ 수 없는 프린터 ë˜ëŠ” í´ëž˜ìŠ¤!\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: root만 암호를 추가 ë˜ëŠ” 제거할 수 있ìŒ!\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: 암호 íŒŒì¼ ì‚¬ìš© 중!\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: 암호 파ì¼ì´ ì—…ë°ì´íŠ¸ë˜ì§€ ì•ŠìŒ!\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: 죄송합니다, 암호가 ì¼ì¹˜í•˜ì§€ 않습니다!\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: 죄송합니다, 암호가 ì¼ì¹˜í•˜ì§€ 않습니다!\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: 오류 - %s 환경 변수 ì´ë¦„ì´ ì¡´ìž¬í•˜ì§€ 않는 ëŒ€ìƒ \"%s\" ì´ë¦„ìž„!\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-eventsê°€ 지정ë˜ì§€ ì•ŠìŒ!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "notify-recipient-uri \"%s\" URIê°€ ì´ë¯¸ 사용 중임!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "notify-recipient-uri \"%s\" URI가 알 수 없는 설계를 사용함!"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "%d notify-subscription-id가 좋지 않습니다!"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: ìž˜ëª»ëœ \"%1$s\" í•´ìƒë„ ì´ë¦„ì´ %3$sì˜ %2$d번째 ì¤„ì— ìžˆìŒ!\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: ìž˜ëª»ëœ %1$s ìƒíƒœ 키워드가 %3$sì˜ %2$d번째 ì¤„ì— ìžˆìŒ!\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc: ì„ íƒì‚¬í•­ì´ %2$sì˜ %1$d번째 줄ì—ì„œ 옵션 ì—†ì´ ë°œê²¬ë¨!\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc: 로컬 %1$sì— ëŒ€í•œ ì¤‘ë³µëœ #poê°€ %3$sì˜ %2$d번째 ì¤„ì— ìžˆìŒ!\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— í•„í„° ì •ì˜ê°€ 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— í”„ë¡œê·¸ëž¨ ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, Font ë’¤ì— ë¬¸ìž ì„¸íŠ¸ê°€ 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— ColorModelì— ëŒ€í•œ ìƒ‰ìƒ ìˆœì„œê°€ 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— ColorModelì— ëŒ€í•œ ìƒ‰ìƒ ê³µê°„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— ColorModelì— ëŒ€í•œ ì••ì¶•ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %2$sì˜ %1$d번째 ì¤„ì— UIConstraintsì— ëŒ€í•œ 제한 스트ë§ì´ 예ìƒë¨!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: %2$sì˜ %1$d번째 줄, DriverType ë’¤ì— ë“œë¼ì´ë²„ 유형 키워드가 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, Duplex ë’¤ì— ì–‘ë©´ ìœ í˜•ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, Font ë’¤ì— ì¸ì½”ë”©ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc: %3$sì˜ %2$d번째 줄, #po %1$s ë’¤ì— íŒŒì¼ ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— ê·¸ë£¹ ì´ë¦„/í…스트가 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— í¬í•¨ íŒŒì¼ ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— ì •ìˆ˜ê°€ 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, #po ë’¤ì— ë¡œì»¬ 위치가 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: %3$sì˜ %2$d번째 줄, %1$s ë’¤ì— ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, FileName ë’¤ì— ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, Font ë’¤ì— ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, Manufacturer ë’¤ì— ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, MediaSize ë’¤ì— ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, ModelName ë’¤ì— ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, PCFileName ë’¤ì— ì´ë¦„ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: %3$sì˜ %2$d번째 줄, %1$s ë’¤ì— ì´ë¦„/í…스트가 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, Installable ë’¤ì— ì´ë¦„/í…스트 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, Resolution ë’¤ì— ì´ë¦„/í…스트 예ìƒë¨!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %2$sì˜ %1$d번째 줄, ColorModelì— ëŒ€í•´ ì´ë¦„/í…스트 ì¡°í•©ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— ì˜µì…˜ ì´ë¦„/í…스트가 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— ì˜µì…˜ ì„¹ì…˜ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì˜ ì˜µì…˜ ìœ í˜•ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %2$sì˜ %1$d번째 줄, Resolution ë’¤ì— ì˜¤ë²„ë¼ì´ë“œ 필드가 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— ì‹¤ì œ 번호가 예ìƒë¨!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: %2$sì˜ %1$d번째 줄, ColorProfile ë’¤ì— í•´ìƒë„/미디어 ìœ í˜•ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %2$sì˜ %1$d번째 줄, SimpleColorProfile ë’¤ì— í•´ìƒë„/미디어 ìœ í˜•ì´ ì˜ˆ"
+#~ "ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: %3$sì˜ %2$d번째 줄, %1$s ë’¤ì— ì„ íƒìžê°€ 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, Font ë’¤ì— ìƒíƒœê°€ 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, Copyright ë’¤ì— ìŠ¤íŠ¸ë§ì´ 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, Version ë’¤ì— ìŠ¤íŠ¸ë§ì´ 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— ì˜µì…˜ ì´ë¦„ 2개가 예ìƒë¨!\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: %3$sì˜ %2$d번째 줄, %1$s ë’¤ì— ê°’ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄, Font ë’¤ì— ë²„ì „ì´ ì˜ˆìƒë¨!\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: 유효하지 ì•Šì€ #include/#po íŒŒì¼ ì´ë¦„ \"%s\"!\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì˜ í•„í„°ì— ëŒ€í•´ 유효하지 ì•Šì€ ë¹„ìš©!\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %2$sì˜ %1$d번째 ì¤„ì˜ í•„í„°ì— ëŒ€í•´ 유효하지 ì•Šì€ ë¹ˆ MIME 유형!\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %2$sì˜ %1$d번째 ì¤„ì˜ í•„í„°ì— ëŒ€í•´ 유효하지 ì•Šì€ ë¹ˆ 프로그램 ì´ë¦„!\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: %3$sì˜ %2$d번째 ì¤„ì— ìœ íš¨í•˜ì§€ ì•Šì€ \"%1$s\" 옵션 섹션!\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: %3$sì˜ %2$d번째 ì¤„ì— ìœ íš¨í•˜ì§€ ì•Šì€ \"%1$s\" 옵션 유형!\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: \"%s\" ëì—ì„œ #endif 유실ë¨!\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 줄ì—ì„œ #if 유실ë¨!\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc: 로컬 %sì— ëŒ€í•´ ì œê³µëœ ë©”ì‹œì§€ 카탈로그 ì—†ìŒ!\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr "ppdc: %3$sì˜ %2$d번째 ì¤„ì— %1$s ì˜µì…˜ì´ ë‹¤ë¥¸ 유형으로 재정ì˜ë¨!\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— ìžˆëŠ” 옵션 ì œí•œì€ *nameì´ì–´ì•¼ 함!\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: %2$sì˜ %1$d번째 ì¤„ì— ë„ˆë¬´ ë§Žì´ ì¤‘ì²©ëœ #ifê°€ 있ìŒ!\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: %3$sì˜ %2$d번째 줄ì—ì„œ #po íŒŒì¼ %1$sì„(를) ì°¾ì„ ìˆ˜ ì—†ìŒ!\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %3$sì˜ %2$d번째 줄ì—ì„œ í¬í•¨ íŒŒì¼ \"%1$s\"ì„(를) ì°¾ì„ ìˆ˜ ì—†ìŒ!\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: %3$sì˜ %2$d번째 ì¤„ì— ì•Œ 수 없는 %1$s ë“œë¼ì´ë¸Œ 유형!\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: %3$sì˜ %2$d번째 ì¤„ì— ì•Œ 수 없는 \"%1$s\" ì–‘ë©´ 유형!\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: %3$sì˜ %2$d번째 ì¤„ì— ì•Œ 수 없는 \"%1$s\" 미디어 í¬ê¸°!\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: %3$sì˜ %2$d번째 ì¤„ì— ë³´ì´ëŠ” ì•Œ 수 없는 \"%1$s\" 토í°!\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: %3$sì˜ %2$d번째 ì¤„ì— ìžˆëŠ” \"%1$s\" ì‹¤ìˆ˜ì— ì•Œ 수 없는 마지막 문ìž!\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: %3$sì˜ %2$d번째 ì¤„ì— %1$c(으)ë¡œ 시작하는 ë나지 않는 스트ë§!\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: %2$sì— ìž˜ëª»ëœ \"%1$s\" LanguageVersion!\n"
diff --git a/locale/cups_nl.po b/locale/cups_nl.po
new file mode 100644
index 000000000..447febbea
--- /dev/null
+++ b/locale/cups_nl.po
@@ -0,0 +1,7175 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-16 12:00-0800\n"
+"Last-Translator: Apple Inc.\n"
+"Language-Team: Apple Inc.\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(alle)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(geen)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d onderdelen\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tNa storing: doorgaan\n"
+
+msgid "\tAlerts:"
+msgstr "\tWaarschuwingen:"
+
+msgid "\tBanner required\n"
+msgstr "\tBanner vereist\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tCharset-sets:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tVerbinding: direct\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tVerbinding: niet-lokaal\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tStandaard paginagrootte:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tStandaardpitch:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tStandaard poortinstellingen:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tOmschrijving: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tFormulier geactiveerd:\n"
+"\tInhoudstypes: alle\n"
+"\tPrintertypes: onbekend\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tFormulieren toegestaan:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tInterface: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tInterface: %s/interfaces/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tInterface: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tLocatie: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tBij storing: geen waarschuwing\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tGebruikers toegelaten:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tGebruikers geweigerd:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tdaemon aanwezig\n"
+
+msgid "\tno entries\n"
+msgstr "\tgeen onderdelen\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\tprinter bevindt zich op apparaat &aops;%s&aops; snelheid -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\tafdrukken is uitgeschakeld\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\tafdrukken is ingeschakeld\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\tgeplaatst in wachtrij voor %s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tverplaatsen naar wachtrij is uitgeschakeld\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tverplaatsen naar wachtrij is ingeschakeld\n"
+
+msgid "\treason unknown\n"
+msgstr "\tonbekende oorzaak\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" GEDETAILLEERDE RESULTATEN VOOR CONFORMANTIETEST\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " REF: Pagina 15, sectie 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " REF: Pagina 15, sectie 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " REF: Pagina 19, sectie 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " REF: Pagina 20, sectie 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " REF: Pagina 27, sectie 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " REF: Pagina 42, sectie 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " REF: Pagina 16-17, sectie 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " REF: Pagina 42-45, sectie 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " REF: Pagina 45-46, sectie 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " REF: Pagina 48-49, sectie 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " REF: Pagina 52-54, sectie 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f bytes\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " PASS Default%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " PASS DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " PASS DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " PASS FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " PASS FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " PASS LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " PASS LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " PASS Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " PASS ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " PASS NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " PASS PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " PASS PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " PASS PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " PASS PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " PASS Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " PASS ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" WARN \"%s %s\" conflicteert met \"%s %s\"\n"
+" (beperking=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" WARN %s deelt een gemeenschappelijke prefix met %s\n"
+" REF: Pagina 15, sectie 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" WARN &aops;LanguageEncoding&aops; vereist door PPD 4.3-"
+"specificatie.\n"
+" REF: Pagina 56-57, sectie 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" WARN &aops;Manufacturer&aops; vereist door PPD 4.3-specificatie.\n"
+" REF: Pagina 58-59, sectie 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" WARN PCFileName langer dan 8.3 komt niet overeen met PPD-"
+"specificatie.\n"
+" REF: Pagina 61-62, sectie 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protocols bevat PJL, maar JCL-attributen zijn niet "
+"ingesteld.\n"
+" REF: Pagina 78-79, sectie 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protocols bevat zowel PJL als BCP; verwachtte TBCP.\n"
+" REF: Pagina 78-79, sectie 5.7.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" WARN &aops;ShortNickName&aops; vereist door PPD 4.3-"
+"specificatie.\n"
+" REF: Pagina 64-65, sectie 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s Ontbrekend cupsFilter-bestand \"%s\"\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s Ontbrekend cupsPreFilter-bestand \"%s\"\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** ONGELDIGE Default%s %s\n"
+" REF: Pagina 40, sectie 4.5.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **FAIL** ONGELDIG JobPatchFile-attribuut in bestand\n"
+" REF: Pagina 24, sectie 3.4.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** ONGELDIGE Manufacturer (moet zijn \"HP\")\n"
+" REF: Pagina 211, tabel D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** ONGELDIGE Manufacturer (moet zijn \"Oki\")\n"
+" REF: Pagina 211, tabel D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** ONGELDIGE ModelName - \"%c\" niet toegestaan in tekenreeks.\n"
+" REF: Pagina 59-60, sectie 5.3.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** ONGELDIGE PSVersion - niet \"(tekenreeks) int\".\n"
+" REF: Pagina 62-64, sectie 5.3.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** ONGELDIG Product - niet \"(tekenreeks)\".\n"
+" REF: Pagina 62, sectie 5.3.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** ONGELDIGE ShortNickName - langer dan 31 tekens.\n"
+" REF: Pagina 64-65, sectie 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** Ongeldige FileVersion \"%s\"\n"
+" REF: Pagina 56, sectie 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** Ongeldige FormatVersion \"%s\"\n"
+" REF: Pagina 56, sectie 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr ""
+" **FAIL** Code voor standaardoptie kan niet worden geïnterpreteerd: %"
+"s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Pagina 40, sectie 4.5.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Pagina 102, sectie 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Pagina 103, sectie 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Pagina 56, sectie 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Pagina 56, sectie 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** REQUIRED ImageableArea voor PageSize %s\n"
+" REF: Pagina 41, sectie 5.\n"
+" REF: Pagina 102, sectie 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pagina 56-57, sectie 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pagina 57-58, sectie 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pagina 58-59, sectie 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pagina 59-60, sectie 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Pagina 60, sectie 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pagina 61-62, sectie 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pagina 62-64, sectie 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Pagina 100, sectie 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pagina 41, sectie 5.\n"
+" REF: Pagina 99, sectie 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pagina 99-100, sectie 5.14.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** REQUIRED PaperDimension voor PageSize %s\n"
+" REF: Pagina 41, sectie 5.\n"
+" REF: Pagina 103, sectie 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED Product\n"
+" REF: Pagina 62, sectie 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Pagina 64-65, sectie 5.3.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " %d FOUTEN GEVONDEN"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " GEEN FOUTEN GEVONDEN\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " FAIL\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** Kan PPD-bestand niet openen - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** Kan PPD-bestand niet openen - %s op regel %d.\n"
+
+msgid " PASS\n"
+msgstr " PASS\n"
+
+msgid "#10 Envelope"
+msgstr "#10-envelop"
+
+msgid "#11 Envelope"
+msgstr "#11-envelop"
+
+msgid "#12 Envelope"
+msgstr "#12-envelop"
+
+msgid "#14 Envelope"
+msgstr "#14-envelop"
+
+msgid "#9 Envelope"
+msgstr "#9-envelop"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f millimeter"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f tot %.0f x %.0f millimeter"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f inch"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f tot %.2f x %.2f inch"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s accepteert verzoeken sinds %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%s kan niet worden gewijzigd."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s is niet geïmplementeerd in de CUPS-versie van lpc.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s is niet gereed\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s is gereed\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s is gereed en bezig met afdrukken\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s accepteert geen verzoeken sinds %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s accepteert verzoeken sinds %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s accepteert geen verzoeken sinds %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [taak %d localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s niet gelukt: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: Fout - geen standaardbestemming beschikbaar.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: Fout - prioriteit moet tussen 1 en 100 liggen.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: Fout - te veel bestanden - \"%s\"\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: Fout - niet mogelijk om \"%s\" te benaderen - %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s: Fout - in wachtrij plaatsen vanaf stdin is niet mogelijk - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: Filter \"%s\" niet beschikbaar: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: Ongeldige filtertekenreeks \"%s\"\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: Bewerking mislukt: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: Kan geen verbinding tot stand brengen met server\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: Niet mogelijk om %s te openen: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: Niet mogelijk om PPD-bestand %s in regel %d te openen\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: fout - geen standaardbestemming beschikbaar.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 inch/sec."
+
+msgid "1.25x0.25\""
+msgstr "1,25x0,25\""
+
+msgid "1.25x2.25\""
+msgstr "1,25x2,25\""
+
+msgid "1.5 inch/sec."
+msgstr "1,5 inch/sec."
+
+msgid "1.50x0.25\""
+msgstr "1,50x0,25\""
+
+msgid "1.50x0.50\""
+msgstr "1,50x0,50\""
+
+msgid "1.50x1.00\""
+msgstr "1,50x1,00\""
+
+msgid "1.50x2.00\""
+msgstr "1,50x2,00\""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 inch/sec."
+
+msgid "10 x 11\""
+msgstr "10 x 11\""
+
+msgid "10 x 13\""
+msgstr "10 x 13\""
+
+msgid "10 x 14\""
+msgstr "10 x 14\""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 mm/sec."
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 inch/sec."
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 inch/sec."
+
+msgid "12 x 11\""
+msgstr "12 x 11\""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 mm/sec."
+
+msgid "120x60dpi"
+msgstr "120x60dpi"
+
+msgid "120x72dpi"
+msgstr "120x72dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 mm/sec."
+
+msgid "15 x 11\""
+msgstr "15 x 11\""
+
+msgid "150 mm/sec."
+msgstr "150 mm/sec."
+
+msgid "150dpi"
+msgstr "150dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 inch/sec."
+
+msgid "2-Sided Printing"
+msgstr "Dubbelzijdig afdrukken"
+
+msgid "2.00x0.37\""
+msgstr "2,00x0,37\""
+
+msgid "2.00x0.50\""
+msgstr "2,00x0,50\""
+
+msgid "2.00x1.00\""
+msgstr "2,00x1,00\""
+
+msgid "2.00x1.25\""
+msgstr "2,00x1,25\""
+
+msgid "2.00x2.00\""
+msgstr "2,00x2,00\""
+
+msgid "2.00x3.00\""
+msgstr "2,00x3,00\""
+
+msgid "2.00x4.00\""
+msgstr "2,00x4,00\""
+
+msgid "2.00x5.50\""
+msgstr "2,00x5,50\""
+
+msgid "2.25x0.50\""
+msgstr "2,25x0,50\""
+
+msgid "2.25x1.25\""
+msgstr "2,25x1,25\""
+
+msgid "2.25x4.00\""
+msgstr "2,25x4,00\""
+
+msgid "2.25x5.50\""
+msgstr "2,25x5,50\""
+
+msgid "2.38x5.50\""
+msgstr "2,38x5,50\""
+
+msgid "2.5 inches/sec."
+msgstr "2,5 inch/sec."
+
+msgid "2.50x1.00\""
+msgstr "2,50x1,00\""
+
+msgid "2.50x2.00\""
+msgstr "2,50x2,00\""
+
+msgid "2.75x1.25\""
+msgstr "2,75x1,25\""
+
+msgid "2.9 x 1\""
+msgstr "2,9 x 1\""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 mm/sec."
+
+msgid "200 mm/sec."
+msgstr "200 mm/sec."
+
+msgid "203dpi"
+msgstr "203dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "24-pens serie"
+
+msgid "240x72dpi"
+msgstr "240x72dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 mm/sec."
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 inch/sec."
+
+msgid "3.00x1.00\""
+msgstr "3,00x1,00\""
+
+msgid "3.00x1.25\""
+msgstr "3,00x1,25\""
+
+msgid "3.00x2.00\""
+msgstr "3,00x2,00\""
+
+msgid "3.00x3.00\""
+msgstr "3,00x3,00\""
+
+msgid "3.00x5.00\""
+msgstr "3,00x5,00\""
+
+msgid "3.25x2.00\""
+msgstr "3,25x2,00\""
+
+msgid "3.25x5.00\""
+msgstr "3,25x5,00\""
+
+msgid "3.25x5.50\""
+msgstr "3,25x5,50\""
+
+msgid "3.25x5.83\""
+msgstr "3,25x5,83\""
+
+msgid "3.25x7.83\""
+msgstr "3,25x7,83\""
+
+msgid "3.5\" Disk"
+msgstr "3,5-inch diskette"
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "3,5-inch diskette - 2 1/8 x 2 3/4\""
+
+msgid "3.50x1.00\""
+msgstr "3,50x1,00\""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 mm/sec."
+
+msgid "300 mm/sec."
+msgstr "300 mm/sec."
+
+msgid "300dpi"
+msgstr "300dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360dpi"
+
+msgid "360x180dpi"
+msgstr "360x180dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 inch/sec."
+
+msgid "4.00x1.00\""
+msgstr "4,00x1,00\""
+
+msgid "4.00x13.00\""
+msgstr "4,00x13,00\""
+
+msgid "4.00x2.00\""
+msgstr "4,00x2,00\""
+
+msgid "4.00x2.50\""
+msgstr "4,00x2,50\""
+
+msgid "4.00x3.00\""
+msgstr "4,00x3,00\""
+
+msgid "4.00x4.00\""
+msgstr "4,00x4,00\""
+
+msgid "4.00x5.00\""
+msgstr "4,00x5,00\""
+
+msgid "4.00x6.00\""
+msgstr "4,00x6,00\""
+
+msgid "4.00x6.50\""
+msgstr "4,00x6,50\""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 mm/sec."
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 inch/sec."
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 inch/sec."
+
+msgid "6.00x1.00\""
+msgstr "6,00x1,00\""
+
+msgid "6.00x2.00\""
+msgstr "6,00x2,00\""
+
+msgid "6.00x3.00\""
+msgstr "6,00x3,00\""
+
+msgid "6.00x4.00\""
+msgstr "6,00x4,00\""
+
+msgid "6.00x5.00\""
+msgstr "6,00x5,00\""
+
+msgid "6.00x6.00\""
+msgstr "6,00x6,00\""
+
+msgid "6.00x6.50\""
+msgstr "6,00x6,50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/sec."
+
+msgid "600dpi"
+msgstr "600dpi"
+
+msgid "60dpi"
+msgstr "60dpi"
+
+msgid "60x720dpi"
+msgstr "60x720dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 inch/sec."
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 inch/sec."
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8,00x1,00\""
+
+msgid "8.00x2.00\""
+msgstr "8,00x2,00\""
+
+msgid "8.00x3.00\""
+msgstr "8,00x3,00\""
+
+msgid "8.00x4.00\""
+msgstr "8,00x4,00\""
+
+msgid "8.00x5.00\""
+msgstr "8,00x5,00\""
+
+msgid "8.00x6.00\""
+msgstr "8,00x6,00\""
+
+msgid "8.00x6.50\""
+msgstr "8,00x6,50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/sec."
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 inch/sec."
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "9-pens serie"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?Ongeldig en onbekend helpcommando\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (oversize)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (oversize)"
+
+msgid "A4 (Small)"
+msgstr "A4 (klein)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (oversize)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "Accepteer taken"
+
+msgid "Accepted"
+msgstr "Geaccepteerd"
+
+msgid "Add Class"
+msgstr "Voeg klasse toe"
+
+msgid "Add Printer"
+msgstr "Voeg printer toe"
+
+msgid "Add RSS Subscription"
+msgstr "Voeg RSS-abonnement toe"
+
+msgid "Address"
+msgstr "Adres"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "Adres - 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "Beheer"
+
+msgid "Always"
+msgstr "Altijd"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "Applicator"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "Ongeldige NULL-bestemmingspointer"
+
+msgid "Bad OpenGroup"
+msgstr "Ongeldige OpenGroup"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "Ongeldige OpenUI/JCLOpenUI"
+
+msgid "Bad OrderDependency"
+msgstr "Ongeldige OrderDependency"
+
+msgid "Bad Request"
+msgstr "Ongeldig verzoek"
+
+msgid "Bad SNMP version number"
+msgstr "Ongeldig SNMP-versienummer"
+
+msgid "Bad UIConstraints"
+msgstr "Ongeldige UIConstraints"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Ongeldige waarde voor aantal exemplaren %d."
+
+msgid "Bad custom parameter"
+msgstr "Ongeldige zelfingestelde parameter"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Ongeldig lettertypeattribuut: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Ongeldige waarde voor number-up %d."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Ongeldige waarden voor paginabereik %d-%d."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Banners"
+
+msgid "Billing Information: "
+msgstr "Factuurgegevens: "
+
+msgid "Bond Paper"
+msgstr "Bankpost"
+
+msgid "C0 Envelope"
+msgstr "C0-envelop"
+
+msgid "C1 Envelope"
+msgstr "C1-envelop"
+
+msgid "C2 Envelope"
+msgstr "C2-envelop"
+
+msgid "C3 Envelope"
+msgstr "C3-envelop"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "C4-envelop"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "C5-envelop"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "C6-envelop"
+
+msgid "C65 Envelope"
+msgstr "C65-envelop"
+
+msgid "C7 Envelope"
+msgstr "C7-envelop"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "CPCL-etikettenprinter"
+
+msgid "Cancel RSS Subscription"
+msgstr "Zeg RSS-abonnement op"
+
+msgid "Change Settings"
+msgstr "Wijzig instellingen"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Chou3-envelop"
+
+msgid "Chou4 Envelope"
+msgstr "Chou4-envelop"
+
+msgid "Classes"
+msgstr "Klassen"
+
+msgid "Clean Print Heads"
+msgstr "Reinig printerkoppen"
+
+msgid "Color"
+msgstr "Kleur"
+
+msgid "Color Mode"
+msgstr "Kleurenmodus"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"Commando&aops;s kunnen worden afgekort. Commando&aops;s zijn:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "Onbepaalde lengte gebruikt voor community-naam"
+
+msgid "Continue"
+msgstr "Ga door"
+
+msgid "Continuous"
+msgstr "Doorlopend"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Aangemaakt"
+
+msgid "Created On: "
+msgstr "Aangemaakt op: "
+
+msgid "Custom"
+msgstr "Zelfingesteld"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Afsnijden"
+
+msgid "Cutter"
+msgstr "Snijmachine"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "DL-envelop"
+
+msgid "Dark"
+msgstr "Donker"
+
+msgid "Darkness"
+msgstr "Donkerte"
+
+msgid "Delete Class"
+msgstr "Verwijder klasse"
+
+msgid "Delete Printer"
+msgstr "Verwijder printer"
+
+msgid "Description: "
+msgstr "Beschrijving: "
+
+msgid "DeskJet Series"
+msgstr "DeskJet-serie"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "Bestemming \"%s\" accepteert geen opdrachten."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"Apparaat: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "Direct Thermal-materiaal"
+
+msgid "Disabled"
+msgstr "Uitgeschakeld"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "Document %d is niet gevonden in taak %d."
+
+msgid "Double Postcard"
+msgstr "Dubbele briefkaart"
+
+msgid "Driver Name: "
+msgstr "Naam stuurprogramma: "
+
+msgid "Driver Version: "
+msgstr "Versie stuurprogramma: "
+
+msgid "Duplexer"
+msgstr "Duplexer"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: Niet mogelijk geheugen toe te kennen voor pagina-info: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: Niet mogelijk geheugen toe te kennen voor paginareeks: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "EPL1-etikettenprinter"
+
+msgid "EPL2 Label Printer"
+msgstr "EPL2-etikettenprinter"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: Ongeldig tekensetbestand %s\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: Ongeldig tekensettype %s\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: Ongeldige regel voor lettertypeomschrijving: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: Ongeldige tekstrichting %s\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: Ongeldige tekstbreedte %s\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: Fout %d bij versturen PAPSendData-verzoek: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: Geen lettertypen in tekensetbestand %s\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: Printer reageert niet\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: Printer heeft onverwacht einde-bestandteken verstuurd\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: Niet-lokale host heeft stuurbestand niet geaccepteerd (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: Niet-lokale host heeft gegevensbestand niet geaccepteerd (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr ""
+"ERROR: Time-out-fout tijdens het versturen van gegevens naar de printer\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: Niet mogelijk om bestand %d toe te voegen aan taak: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: Niet mogelijk om afdruktaak %d te annuleren: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: Niet mogelijk om PDF-bestand te kopiëren"
+
+msgid "ERROR: Unable to create pipe"
+msgstr ""
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: Niet mogelijk om socket aan te maken"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: Niet mogelijk om tijdelijk gecomprimeerd afdrukbestand te maken: %s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: Niet mogelijk om tijdelijk bestand aan te maken"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: Niet mogelijk om pictwpstops uit te voeren: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: Niet mogelijk om gs-programma uit te voeren"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: Niet mogelijk om pdftops-programma uit te voeren"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: Niet mogelijk om pictwpstops te splitsen: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: Niet mogelijk om PAP-verzoek op te vragen"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: Niet mogelijk om PAP-reactie op te vragen"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr ""
+"ERROR: Niet mogelijk om PPD-bestand voor printer \"%s\" op te vragen - %s.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: Niet mogelijk om standaard-AppleTalk-zone op te vragen"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: Niet mogelijk om naar PAP-reactie te zoeken"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: Niet mogelijk om naar AppleTalk-printers te zoeken"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: Niet mogelijk om AppleTalk-adres aan te maken"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: Niet mogelijk om \"%s\" te openen - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: Niet mogelijk om %s te openen: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: Niet mogelijk om bannerbestand \"%s\" te openen - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: Niet mogelijk om apparaatbestand \"%s\" te openen: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: Niet mogelijk om bestand \"%s\" te openen - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: Niet mogelijk om bestand \"%s\" te openen: %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: Niet mogelijk om afdrukbestand \"%s\" te openen: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: Niet mogelijk om afdrukbestand %s te openen - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: Niet mogelijk om afdrukbestand %s te openen: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: Niet mogelijk om tijdelijk gecomprimeerd afdrukbestand te openen: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: Niet mogelijk om afdrukgegevens te lezen"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: Niet mogelijk om poort te reserveren"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr ""
+"ERROR: Niet mogelijk om te proberen %ld in bestand te positioneren - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr ""
+"ERROR: Niet mogelijk om te proberen %lld in bestand te positioneren - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: Niet mogelijk om LPD-commando te versturen"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: Niet mogelijk om PAP-tickleverzoek te versturen"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr ""
+"ERROR: Niet mogelijk om initieel PAP-verzoek voor versturen gegevens te "
+"versturen"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: Niet mogelijk om afdrukbestand naar printer te versturen"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr ""
+"ERROR: Niet mogelijk om afsluitende lege tekens naar printer te versturen"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: Niet mogelijk om te wachten op pictwpstops: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: Niet mogelijk om %d bytes te schrijven naar \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: Niet mogelijk om stuurbestand weg te schrijven"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: Niet mogelijk om afdrukgegevens weg te schrijven"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: Niet mogelijk om afdrukgegevens weg te schrijven: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr ""
+"ERROR: Niet mogelijk om ongecomprimeerde documentgegevens weg te schrijven: %"
+"s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: Onbekende bestandsvolgorde \"%s\"\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: Onbekend opmaakteken \"%c\"\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: Onbekende afdrukmodus \"%s\"\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: select() mislukt"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: stat van afdrukbestand niet mogelijk"
+
+msgid "Edit Configuration File"
+msgstr "Bewerk configuratiebestand"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Eindebanner"
+
+msgid "English"
+msgstr "Dutch"
+
+msgid "Enter old password:"
+msgstr "Voer oude wachtwoord in:"
+
+msgid "Enter password again:"
+msgstr "Voer wachtwoord opnieuw in:"
+
+msgid "Enter password:"
+msgstr "Voer wachtwoord in:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Voer uw gebruikersnaam en wachtwoord of de $%$root-gebruikersnaam en "
+"bijbehorend wachtwoord in om deze pagina te benaderen. Maakt u gebruik van "
+"Kerberos-toegangscontrole, controleer dan of u over een geldig Kerberos-"
+"ticket beschikt."
+
+msgid "Envelope Feed"
+msgstr "Envelopinvoer"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Foutenbeleid"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "Elke 10 etiketten"
+
+msgid "Every 2 Labels"
+msgstr "Elke 2 etiketten"
+
+msgid "Every 3 Labels"
+msgstr "Elke 3 etiketten"
+
+msgid "Every 4 Labels"
+msgstr "Elke 4 etiketten"
+
+msgid "Every 5 Labels"
+msgstr "Elke 5 etiketten"
+
+msgid "Every 6 Labels"
+msgstr "Elke 6 etiketten"
+
+msgid "Every 7 Labels"
+msgstr "Elke 7 etiketten"
+
+msgid "Every 8 Labels"
+msgstr "Elke 8 etiketten"
+
+msgid "Every 9 Labels"
+msgstr "Elke 9 etiketten"
+
+msgid "Every Label"
+msgstr "Elk etiket"
+
+msgid "Expectation Failed"
+msgstr "Verwachting mislukt"
+
+msgid "Export Printers to Samba"
+msgstr "Exporteer printers naar Samba"
+
+msgid "FAIL\n"
+msgstr "FAIL\n"
+
+msgid "File Folder"
+msgstr "Dossiermap"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Dossiermap - 9/16 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"File device-URI&aops;s zijn uitgeschakeld! Raadpleeg als u de URI&aops;s "
+"weer wilt inschakelen de richtlijn voor FileDevice in \"%s/cupsd.conf\"."
+
+msgid "Folio"
+msgstr "Folio"
+
+msgid "Forbidden"
+msgstr "Verboden"
+
+msgid "General"
+msgstr "Algemeen"
+
+msgid "Generic"
+msgstr "Generiek"
+
+msgid "German FanFold"
+msgstr "German FanFold"
+
+msgid "German FanFold Legal"
+msgstr "German FanFold Legal"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Onbepaalde lengte gebruikt voor Get-Response-PDU"
+
+msgid "Glossy Paper"
+msgstr "Glanzend papier"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Grijstinten"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Hangmap"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Hangmap - 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk uitgeschakeld in Systeemvoorkeuren\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk uitgeschakeld in Systeemvoorkeuren.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: Afdrukopdracht wordt geannuleerd...\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: Verbonden met printer...\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: Verbinden met printer...\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: Stuurbestand succesvol verzonden\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr ""
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: Gegevensbestand succesvol verzonden\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: Bezig met indelen van pagina %d...\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: Bezig met laden van beeldbestand...\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: Zoeken naar printer...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: Verbinding wordt geopend\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr "INFO: Afdrukbestand verzonden, wacht tot printer gereed is...\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: Printer is bezig; nieuwe poging over 10 seconden...\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: Printer is bezig; nieuwe poging over 30 seconden...\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: Printer is bezig; nieuwe poging over 5 seconden...\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr ""
+"INFO: Printer biedt geen ondersteuning voor IPP/%d.%d, probeert nu "
+"IPP/1.0...\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: Printer is bezig; nieuwe poging over 5 seconden...\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: Printer is momenteel offline.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: Printer is momenteel offline.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: Printer is nu online.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: Printer is offline.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: Geen verbinding met printer; nieuwe poging over 30 seconden...\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: Bezig met afdrukken van pagina %d, %d%% gereed...\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: Bezig met afdrukken van pagina %d...\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: Klaar om af te drukken.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: Bezig met verzending van stuurbestand (%lu bytes)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: Bezig met verzending van stuurbestand (%u bytes)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: Bezig met verzenden van gegevens\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: Bezig met verzenden van gegevensbestand (%ld bytes)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: Bezig met verzenden van gegevensbestand (%lld bytes)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: Afdrukgegevens worden verstuurd...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: Afdrukbestand is verzonden, %ld bytes...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: Afdrukbestand is verzonden, %lld bytes...\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: Bezig met spoolen van LPR-taak, %.0f%% gereed...\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr ""
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: Kan geen contact maken met printer, taak wordt overgebracht naar "
+"volgende printer in klasse...\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: Standaard-AppleTalk-zone \"%s\" wordt gebruikt\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: Wacht tot afdrukopdracht is afgerond...\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: Wacht tot printer beschikbaar is...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "ISO B4-envelop"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (oversize)"
+
+msgid "ISO B5 Envelope"
+msgstr "ISO B5-envelop"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "ISO B6-envelop"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "Ongeldig besturingsteken"
+
+msgid "Illegal main keyword string"
+msgstr "Ongeldige tekenreeks voor hoofdsleutelwoord"
+
+msgid "Illegal option keyword string"
+msgstr "Ongeldige tekenreeks voor optiesleutelwoord"
+
+msgid "Illegal translation string"
+msgstr "Ongeldige tekenreeks voor vertaling"
+
+msgid "Illegal whitespace character"
+msgstr "Ongeldig teken voor witruimte"
+
+msgid "Installable Options"
+msgstr "Uitbreidingsmogelijkheden"
+
+msgid "Installed"
+msgstr "Geïnstalleerd"
+
+msgid "IntelliBar Label Printer"
+msgstr "IntelliBar-etikettenprinter"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr ""
+
+msgid "Internal error"
+msgstr "Interne fout"
+
+msgid "Internet Postage 2-Part"
+msgstr "Internet Postage 2-Part"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "Internet Postage 3-Part"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Internet Postage 3-Part - 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "Internet Printing Protocol"
+
+msgid "Invite Envelope"
+msgstr "Invite-envelop"
+
+msgid "Italian Envelope"
+msgstr "Italian-envelop"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "Taak #%d is al afgebroken - kan niet worden geannuleerd."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "Taak #%d is al geannuleerd - kan niet worden geannuleerd."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "Taak #%d is al gereed - kan niet worden geannuleerd."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "Taak gereed"
+
+msgid "Job Created"
+msgstr "Taak aangemaakt"
+
+msgid "Job ID: "
+msgstr "Taak-ID: "
+
+msgid "Job Options Changed"
+msgstr "Taakopties gewijzigd"
+
+msgid "Job Stopped"
+msgstr "Taak gestopt"
+
+msgid "Job UUID: "
+msgstr "Taak-UUID: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "Taak is gereed en kan niet worden gewijzigd."
+
+msgid "Job operation failed:"
+msgstr "Verwerking van taak is mislukt:"
+
+msgid "Job state cannot be changed."
+msgstr "Status van taak kan niet worden gewijzigd."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "Taken"
+
+msgid "Kaku2 Envelope"
+msgstr "Kaku2-envelop"
+
+msgid "Kaku3 Envelope"
+msgstr "Kaku3-envelop"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "LPD/LPR-host of -printer"
+
+msgid "Label Printer"
+msgstr "Etikettenprinter"
+
+msgid "Label Top"
+msgstr "Bovenkant etiket"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Groot adres"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Groot adres - 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet-serie PCL 4/5"
+
+msgid "Light"
+msgstr "Licht"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Regel is langer dan toegestane maximum (255 tekens)"
+
+msgid "List Available Printers"
+msgstr "Toon beschikbare printers"
+
+msgid "Location: "
+msgstr "Locatie: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "Lange kant (staand)"
+
+msgid "Make and Model: "
+msgstr "Merk en model: "
+
+msgid "Manual Feed"
+msgstr "Handmatige invoer"
+
+msgid "Media Dimensions: "
+msgstr "Afmetingen materiaal: "
+
+msgid "Media Limits: "
+msgstr "Min. en max. afmetingen: "
+
+msgid "Media Name: "
+msgstr "Materiaalnaam: "
+
+msgid "Media Size"
+msgstr "Materiaalgrootte"
+
+msgid "Media Source"
+msgstr "Bron voor materiaal"
+
+msgid "Media Tracking"
+msgstr "Materiaaldetectie"
+
+msgid "Media Type"
+msgstr "Materiaaltype"
+
+msgid "Medium"
+msgstr "Materiaal"
+
+msgid "Memory allocation error"
+msgstr "Geheugentoewijzingsfout"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "Ontbrekende PPD-Adobe-4.x-kopregel"
+
+msgid "Missing asterisk in column 1"
+msgstr "Ontbrekende asterisk in kolom 1"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "Ontbrekende tekenreeks voor waarde"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "Wijzig klasse"
+
+msgid "Modify Printer"
+msgstr "Wijzig printer"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Monarch-envelop"
+
+msgid "Move All Jobs"
+msgstr "Verplaats alle taken"
+
+msgid "Move Job"
+msgstr "Verplaats taak"
+
+msgid "Moved Permanently"
+msgstr "Definitief verplaatst"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: Afdrukbestand geaccepteerd - taak-ID %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: Afdrukbestand geaccepteerd - taak-ID onbekend.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "NULL-pointer voor PPD-bestand"
+
+msgid "Name OID uses indefinite length"
+msgstr "Onbepaalde lengte gebruikt voor naam-OID"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Nooit"
+
+msgid "New Stylus Color Series"
+msgstr "Nieuwe Stylus Color-serie"
+
+msgid "New Stylus Photo Series"
+msgstr "Nieuwe Stylus Photo-serie"
+
+msgid "No"
+msgstr "Nee"
+
+msgid "No Content"
+msgstr "Geen inhoud"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "Geen VarBind-SEQUENCE"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "Geen actieve verbinding"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "Geen community-naam"
+
+msgid "No default printer"
+msgstr "Geen standaardprinter"
+
+msgid "No destinations added."
+msgstr "Geen bestemmingen toegevoegd."
+
+msgid "No error-index"
+msgstr "Geen error-index"
+
+msgid "No error-status"
+msgstr "Geen error-status"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "Geen naam-OID"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "Geen verzoek-ID"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "Geen abonnementen gevonden."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "Geen variable-bindings-SEQUENCE"
+
+msgid "No version number"
+msgstr "Geen versienummer"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "Niet-doorlopend (markeringssensor)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "Niet-doorlopend (afstandssensor)"
+
+msgid "Normal"
+msgstr "Normaal"
+
+msgid "Not Found"
+msgstr "Niet gevonden"
+
+msgid "Not Implemented"
+msgstr "Niet geïmplementeerd"
+
+msgid "Not Installed"
+msgstr "Niet geïnstalleerd"
+
+msgid "Not Modified"
+msgstr "Niet gewijzigd"
+
+msgid "Not Supported"
+msgstr "Niet ondersteund"
+
+msgid "Not allowed to print."
+msgstr "Afdrukken niet toegestaan."
+
+msgid "Note"
+msgstr "Opmerking"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Off (1-Sided)"
+msgstr "Uit (enkelzijdig)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Online Help"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "Openen van %s mislukt: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup zonder eerst een CloseGroup"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI zonder eerst een CloseUI/JCLCloseUI"
+
+msgid "Operation Policy"
+msgstr "Gebruiksbeleid"
+
+msgid "Options Installed"
+msgstr "Geïnstalleerde opties"
+
+msgid "Options: "
+msgstr "Opties: "
+
+msgid "Output Mode"
+msgstr "Uitvoermodus"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "Uitvoer voor printer %s wordt gestuurd naar %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr ""
+"Uitvoer voor printer %s wordt gestuurd naar niet-lokale printer %s op %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "Uitvoer voor printer %s/%s wordt gestuurd naar %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr ""
+"Uitvoer voor printer %s/%s wordt gestuurd naar niet-lokale printer %s op %s\n"
+
+msgid "PASS\n"
+msgstr "PASS\n"
+
+msgid "PCL Laser Printer"
+msgstr "PCL-laserprinter"
+
+msgid "PRC1 Envelope"
+msgstr "PRC1-envelop"
+
+msgid "PRC10 Envelope"
+msgstr "PRC10-envelop"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "PRC2-envelop"
+
+msgid "PRC3 Envelope"
+msgstr "PRC3-envelop"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (oversize)"
+
+msgid "PRC4 Envelope"
+msgstr "PRC4-envelop"
+
+msgid "PRC5 Envelope"
+msgstr "PRC5-envelop"
+
+msgid "PRC6 Envelope"
+msgstr "PRC6-envelop"
+
+msgid "PRC7 Envelope"
+msgstr "PRC7-envelop"
+
+msgid "PRC8 Envelope"
+msgstr "PRC8-envelop"
+
+msgid "PRC9 Envelope"
+msgstr "PRC9-envelop"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "Pakket bevat geen Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "Pakket begint niet met SEQUENCE"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "Wachtwoord voor %s op %s? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "Wachtwoord voor %s vereist om %s te benaderen via SAMBA: "
+
+msgid "Pause Class"
+msgstr "Onderbreek klasse"
+
+msgid "Pause Printer"
+msgstr "Onderbreek printer"
+
+msgid "Peel-Off"
+msgstr "Zelfklevend"
+
+msgid "Personal Envelope"
+msgstr "Personal-envelop"
+
+msgid "Photo"
+msgstr "Foto"
+
+msgid "Photo Labels"
+msgstr "Foto-etiketten"
+
+msgid "Plain Paper"
+msgstr "Gewoon papier"
+
+msgid "Policies"
+msgstr "Beleid"
+
+msgid "Port Monitor"
+msgstr "Poortmonitor"
+
+msgid "PostScript Printer"
+msgstr "PostScript-printer"
+
+msgid "Postcard"
+msgstr "Briefkaart"
+
+msgid "Print Density"
+msgstr "Afdrukdichtheid"
+
+msgid "Print Job:"
+msgstr "Afdruktaak:"
+
+msgid "Print Mode"
+msgstr "Afdrukmodus"
+
+msgid "Print Rate"
+msgstr "Afdrukdoorvoer"
+
+msgid "Print Self-Test Page"
+msgstr "Druk zelftestpagina af"
+
+msgid "Print Speed"
+msgstr "Afdruksnelheid"
+
+msgid "Print Test Page"
+msgstr "Druk testpagina af"
+
+msgid "Print and Cut"
+msgstr "Afdrukken en afsnijden"
+
+msgid "Print and Tear"
+msgstr "Afdrukken en afscheuren"
+
+msgid "Printed For: "
+msgstr "Afgedrukt voor: "
+
+msgid "Printed From: "
+msgstr "Afgedrukt vanaf: "
+
+msgid "Printed On: "
+msgstr "Afgedrukt op: "
+
+msgid "Printer Added"
+msgstr "Printer toegevoegd"
+
+msgid "Printer Default"
+msgstr "Printerstandaard"
+
+msgid "Printer Deleted"
+msgstr "Printer verwijderd"
+
+msgid "Printer Modified"
+msgstr "Printer gewijzigd"
+
+msgid "Printer Name: "
+msgstr "Printernaam: "
+
+msgid "Printer Paused"
+msgstr "Printer onderbroken"
+
+msgid "Printer Settings"
+msgstr "Printerinstellingen"
+
+msgid "Printer:"
+msgstr "Printer:"
+
+msgid "Printers"
+msgstr "Printers"
+
+msgid "Purge Jobs"
+msgstr "Maak takenlijst leeg"
+
+msgid "Quarto"
+msgstr "Quarto"
+
+msgid "Quota limit reached."
+msgstr "Quotumlimiet bereikt."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr ""
+"Positie Eigenaar Taak Bestand(en) Totale "
+"grootte\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"Positie Eigenaar Prioriteit Taak "
+"Bestanden Totale grootte\n"
+
+msgid "Reject Jobs"
+msgstr "Weiger taken"
+
+msgid "Reprint After Error"
+msgstr "Druk opnieuw af na fout"
+
+msgid "Request Entity Too Large"
+msgstr "Request Entity te groot"
+
+msgid "Resolution"
+msgstr "Resolutie"
+
+msgid "Resume Class"
+msgstr "Hervat klasse"
+
+msgid "Resume Printer"
+msgstr "Hervat printer"
+
+msgid "Return Address"
+msgstr "Adres afzender"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Adres afzender - 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "Oprollen"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Commando wordt uitgevoerd: %s %s -N -A %s -c &aops;%s&aops;\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "Onbepaalde lengte gebruikt voor SEQUENCE"
+
+msgid "See Other"
+msgstr "Zie andere"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "Seriële poort #%d"
+
+msgid "Server Restarted"
+msgstr "Server herstart"
+
+msgid "Server Security Auditing"
+msgstr "Serverbeveiligingscontrole"
+
+msgid "Server Started"
+msgstr "Server gestart"
+
+msgid "Server Stopped"
+msgstr "Server gestopt"
+
+msgid "Service Unavailable"
+msgstr "Voorziening niet beschikbaar"
+
+msgid "Set Allowed Users"
+msgstr "Stel aantal toegestane gebruikers in"
+
+msgid "Set As Server Default"
+msgstr "Stel in als serverstandaard"
+
+msgid "Set Class Options"
+msgstr "Stel klasseopties in"
+
+msgid "Set Printer Options"
+msgstr "Stel printeropties in"
+
+msgid "Set Publishing"
+msgstr "Stel publicatie in"
+
+msgid "Shipping Address"
+msgstr "Afleveradres"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "Afleveradres - 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "Korte kant (liggend)"
+
+msgid "Special Paper"
+msgstr "Speciaal papier"
+
+msgid "Standard"
+msgstr "Standaard"
+
+msgid "Starting Banner"
+msgstr "Startbanner"
+
+msgid "Statement"
+msgstr "Statement"
+
+msgid "Stylus Color Series"
+msgstr "Stylus Color-serie"
+
+msgid "Stylus Photo Series"
+msgstr "Stylus Photo-serie"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "Schakelen tussen protocollen"
+
+msgid "Tabloid"
+msgstr "Tabloid"
+
+msgid "Tabloid (Oversize)"
+msgstr "Tabloid (oversize)"
+
+msgid "Tear"
+msgstr "Scheuren"
+
+msgid "Tear-Off"
+msgstr "Afscheuren"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Pas positie voor afscheuren aan"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "Het PPD-bestand \"%s\" kon niet worden gevonden."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "Het PPD-bestand \"%s\" kon niet worden geopend: %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"De klassenaam mag maximaal 127 afdrukbare tekens en geen spaties, schuine "
+"strepen (/) of hekjes (#) bevatten."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+"Het attribuut &aops;notify-lease-duration&aops; kan niet worden gebruikt bij "
+"taakabonnementen."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"De printernaam mag maximaal 127 afdrukbare tekens en geen spaties, schuine "
+"strepen (/) of hekjes (#) bevatten."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "De printer of klasse kon niet worden gevonden."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "De printer-uri \"%s\" bevat ongeldige tekens."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr ""
+"De printer-uri moet de vorm \"ipp://HOSTNAAM/klassen/KLASSENAAM\" hebben."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+"De printer-uri moet de vorm \"ipp://HOSTNAAM/printers/PRINTERNAAM\" hebben."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"De abonnementsnaam mag geen spaties, schuine strepen (/), vraagtekens (?) of "
+"hekjes (#) bevatten."
+
+msgid "There are too many subscriptions."
+msgstr "Er zijn te veel abonnementen."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "Thermal Transfer-materiaal"
+
+msgid "Title: "
+msgstr "Titel: "
+
+msgid "Too many active jobs."
+msgstr "Te veel actieve taken."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "Transparantie"
+
+msgid "Tray"
+msgstr "Lade"
+
+msgid "Tray 1"
+msgstr "Lade 1"
+
+msgid "Tray 2"
+msgstr "Lade 2"
+
+msgid "Tray 3"
+msgstr "Lade 3"
+
+msgid "Tray 4"
+msgstr "Lade 4"
+
+msgid "URI Too Long"
+msgstr "URI te lang"
+
+msgid "US Executive"
+msgstr "US Executive"
+
+msgid "US Fanfold"
+msgstr "US Fanfold"
+
+msgid "US Ledger"
+msgstr "US Ledger"
+
+msgid "US Legal"
+msgstr "US Legal"
+
+msgid "US Legal (Oversize)"
+msgstr "US Legal (oversize)"
+
+msgid "US Letter"
+msgstr "US Letter"
+
+msgid "US Letter (Oversize)"
+msgstr "US Letter (oversize)"
+
+msgid "US Letter (Small)"
+msgstr "US Letter (klein)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "USB-seriële poort #%d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "Niet mogelijk om toegang te krijgen tot cupsd.conf-bestand:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "Niet mogelijk om RSS-abonnement toe te voegen:"
+
+msgid "Unable to add class:"
+msgstr "Niet mogelijk om klasse toe te voegen:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "Niet mogelijk om printer toe te voegen:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "Niet mogelijk om RSS-abonnement op te zeggen:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "Niet mogelijk om attribuut &aops;printer-is-shared&aops; te wijzigen:"
+
+msgid "Unable to change printer:"
+msgstr "Niet mogelijk om printer te wijzigen:"
+
+msgid "Unable to change server settings:"
+msgstr "Niet mogelijk om serverinstellingen te wijzigen:"
+
+msgid "Unable to connect to host."
+msgstr "Niet mogelijk om verbinding met host te maken."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "Niet mogelijk om tijdelijk bestand aan te maken:"
+
+msgid "Unable to delete class:"
+msgstr "Niet mogelijk om klasse te verwijderen:"
+
+msgid "Unable to delete printer:"
+msgstr "Niet mogelijk om printer te verwijderen:"
+
+msgid "Unable to do maintenance command:"
+msgstr "Niet mogelijk om onderhoudscommando op te geven:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "Niet mogelijk om klasselijst weer te geven:"
+
+msgid "Unable to get class status:"
+msgstr "Niet mogelijk om klassestatus weer te geven:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "Niet mogelijk om lijst van printerstuurprogramma&aops;s weer te geven:"
+
+msgid "Unable to get printer attributes:"
+msgstr "Niet mogelijk om printerattributen weer te geven:"
+
+msgid "Unable to get printer list:"
+msgstr "Niet mogelijk om printerlijst weer te geven:"
+
+msgid "Unable to get printer status:"
+msgstr "Niet mogelijk om printerstatus weer te geven:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "Niet mogelijk om klasse te wijzigen:"
+
+msgid "Unable to modify printer:"
+msgstr "Niet mogelijk om printer te wijzigen:"
+
+msgid "Unable to move job"
+msgstr "Niet mogelijk om taak te verplaatsen"
+
+msgid "Unable to move jobs"
+msgstr "Niet mogelijk om taken te verplaatsen"
+
+msgid "Unable to open PPD file"
+msgstr "Niet mogelijk om PPD-bestand te openen"
+
+msgid "Unable to open PPD file:"
+msgstr "Niet mogelijk om PPD-bestand te openen:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "Niet mogelijk om cupsd.conf-bestand te openen:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "Niet mogelijk om testpagina af te drukken:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "Niet mogelijk om \"%s\" uit te voeren: %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "Niet mogelijk om opties in te stellen:"
+
+msgid "Unable to set server default:"
+msgstr "Niet mogelijk om serverstandaard in te stellen:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "Niet mogelijk om cupsd.conf file-bestand te uploaden:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "Onbevoegd"
+
+msgid "Units"
+msgstr "Eenheden"
+
+msgid "Unknown"
+msgstr "Onbekend"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "Onbekend printerfoutbeleid \"%s\"."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "Onbekend printergebruiksbeleid \"%s\"."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Niet-ondersteund waardetype"
+
+msgid "Upgrade Required"
+msgstr "Upgrade vereist"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Gebruik:\n"
+"\n"
+" lpadmin [-h server] -d bestemming\n"
+" lpadmin [-h server] -x bestemming\n"
+" lpadmin [-h server] -p printer [-c voeg klasse toe] [-i interface] [-m "
+"model]\n"
+" [-r verwijder klasse] [-v apparaat] [-D "
+"omschrijving]\n"
+" [-P ppd-bestand] [-o naam=waarde]\n"
+" [-u sta toe:gebruiker,gebruiker] [-u weiger:gebruiker,"
+"gebruiker]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "Gebruik: %s job user title copies options [bestandsnaam]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "Gebruik: %s job-id user title copies options [bestand]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "Gebruik: %s job-id user title copies options file\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Gebruik: cupsaddsmb [opties] printer1 ... printerN\n"
+" cupsaddsmb [opties] -a\n"
+"\n"
+"Opties:\n"
+" -E Gebruik encryptie voor verbinding met server\n"
+" -H samba-server Gebruik genoemde SAMBA-server\n"
+" -U samba-gebruiker Controleer toegang via genoemde SAMBA-gebruiker\n"
+" -a Exporteer alle printers\n"
+" -h cups-server Gebruik genoemde CUPS-server\n"
+" -v Gebruik verbose-modus (toon commando&aops;s)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Gebruik: cupsctl [opties] [param=waarde ... paramN=waardeN]\n"
+"\n"
+"Opties:\n"
+"\n"
+" -E Schakel encryptie in\n"
+" -U gebruikersnaam Geef gebruikersnaam op\n"
+" -h server[:poort] Geef serveradres op\n"
+"\n"
+" --[no-]debug-logging Schakel debug-logging in/uit\n"
+" --[no-]remote-admin Schakel beheer op afstand in/uit\n"
+" --[no-]remote-any Maak toegang via het internet mogelijk/"
+"onmogelijk\n"
+" --[no-]remote-printers Toon/verberg niet-lokale printers\n"
+" --[no-]share-printers Schakel gemeenschappelijk printergebruik in/uit\n"
+" --[no-]user-cancel-any Maak annuleren van taken door gebruikers "
+"mogelijk/onmogelijk\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Gebruik: cupsd [-c config-bestand] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Laad alternatief configuratiebestand\n"
+"-f Voer uit op voorgrond\n"
+"-F Voer uit op voorgrond, losgekoppeld\n"
+"-h Toon dit gebruiksbericht\n"
+"-l Voer cupsd uit vanaf launchd(8)\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Gebruik: cupstestdsc [opties] bestandsnaam.ps [... bestandsnaam.ps]\n"
+" cupstestdsc [opties] -\n"
+"\n"
+"Opties:\n"
+"\n"
+" -h Toon programmagebruik\n"
+"\n"
+" Opmerking: dit programma valideert alleen het DSC-commentaar, niet de "
+"PostScript-code.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Gebruik: lpmove job/src dest\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Gebruik: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o optie[=waarde] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Gebruik: lppasswd [-g groepsnaam]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Gebruik: lppasswd [-g groepsnaam] [gebruikersnaam]\n"
+" lppasswd [-g groepsnaam] -a [gebruikersnaam]\n"
+" lppasswd [-g groepsnaam] -x [gebruikersnaam]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Gebruik: lpq [-P bestemming] [-U gebruikersnaam] [-h hostnaam[:poort]] [-l] "
+"[+interval]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Gebruik: ppdc [opties] bestandsnaam.drv [ ... bestandsnaamN.drv ]\n"
+"Opties:\n"
+" -D naam=waarde Stel benoemde variabele in op waarde.\n"
+" -I include-dir Voeg include-directory toe aan zoekpad.\n"
+" -c catalogus.po Laad de opgegeven berichtencatalogus.\n"
+" -d uitvoer-dir Geef de uitvoerdirectory op.\n"
+" -l taal[,taal,...] Geef de uitvoertaal/-talen (taalversie) op.\n"
+" -m Gebruik de ModelName-waarde als bestandsnaam.\n"
+" -t Test PPD&aops;s in plaats van ze te genereren.\n"
+" -v Gebruik verbose-modus (meer v's voor uitgebreidere "
+"modus).\n"
+" -z Comprimeer PPD-bestanden met GNU-zip.\n"
+" --cr Sluit regels af met CR (Mac OS 9).\n"
+" --crlf Sluit regels af met CR + LF (Windows).\n"
+" --lf Sluit regels af met LF (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"Gebruik: ppdhtml [opties] bestandsnaam.drv >bestandsnaam.html\n"
+" -D naam=waarde Stel benoemde variabele in op waarde.\n"
+"Opties:\n"
+" -I include-dir Voeg include-directory toe aan zoekpad.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Gebruik: ppdi [opties] bestandsnaam.ppd [ ... bestandsnaamN.ppd ]\n"
+"Opties:\n"
+" -I include-dir\n"
+" -o bestandsnaam.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Gebruik: ppdmerge [opties] bestandsnaam.ppd [ ... bestandsnaamN.ppd ]\n"
+"Opties:\n"
+" -o bestandsnaam.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"Gebruik: ppdpo [opties] -o bestandsnaam.po bestandsnaam.drv [ ... "
+"bestandsnaamN.drv ]\n"
+"Opties:\n"
+" -D naam=waarde Stel benoemde variabele in op waarde.\n"
+" -I include-dir Voeg include-directory toe aan zoekpad.\n"
+" -v Gebruik verbose-modus (meer v's voor uitgebreidere "
+"modus).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Gebruik: snmp [host- of ip-adres]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Onbepaalde lengte gebruikt voor waarde"
+
+msgid "VarBind uses indefinite length"
+msgstr "Onbepaalde lengte gebruikt voor VarBind"
+
+msgid "Version uses indefinite length"
+msgstr "Onbepaalde lengte gebruikt voor versie"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: Alleen de eerste %d gevonden printers worden toegevoegd"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: Verwachtte Boolean voor optie &aops;waiteof&aops; \"%s\"\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: Printer reageert niet\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: Printer heeft onverwacht einde-bestandteken verstuurd\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: Niet mogelijk om \"%s:%s\" te openen: %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: Niet mogelijk om PAP-statusverzoek te versturen"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: Onverwacht PAP-pakket van type %d\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: Onbekend PAP-pakket van type %d\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: Verwachtte getal voor statusoptie \"%s\"\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Ja"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"U dient deze pagina te benaderen via de URL <A HREF=\"https://%s:%d%s"
+"\">https://%s:%d%s</A>."
+
+msgid "You4 Envelope"
+msgstr "You4-envelop"
+
+msgid "ZPL Label Printer"
+msgstr "ZPL-etikettenprinter"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "afgebroken"
+
+msgid "canceled"
+msgstr "geannuleerd"
+
+msgid "completed"
+msgstr "gereed"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr ""
+"convert: Gebruik de optie -f om het bestand op te geven dat u wilt "
+"converteren.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "cups-deviced niet uitgevoerd."
+
+msgid "cups-driverd failed to execute."
+msgstr "cups-driverd niet uitgevoerd."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: Geen PPD-bestand voor printer \"%s\" - %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr ""
+"cupsctl: Niet mogelijk om verbinding met server tot stand te brengen: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr ""
+"cupsd: Geen ondersteuning voor launchd(8) opgenomen, bewerking wordt "
+"uitgevoerd in normale modus.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: Niet mogelijk om taakbestand op te vragen - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr ""
+"cupstestppd: De optie -q kan niet worden gebruikt in combinatie met de optie "
+"-v.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr ""
+"cupstestppd: De optie -v kan niet worden gebruikt in combinatie met de optie "
+"-q.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "apparaat voor %s/%s: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "apparaat voor %s: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "Onbepaalde lengte gebruikt voor error-index"
+
+msgid "error-status uses indefinite length"
+msgstr "Onbepaalde lengte gebruikt voor error-status"
+
+msgid "held"
+msgstr "vastgehouden"
+
+msgid "help\t\tget help on commands\n"
+msgstr "help\t\thulpinformatie voor commando&aops;s opvragen\n"
+
+msgid "idle"
+msgstr "niet in gebruik"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: Printer %s is al lid van klasse %s.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: Printer %s is geen lid van klasse %s.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr ""
+"lpadmin: Niet mogelijk om verbinding tot stand te brengen met server: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: Niet mogelijk om PPD-bestand \"%s\" te openen - %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: Niet mogelijk om bestand \"%s\" te openen: %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr ""
+"lpmove: Niet mogelijk om verbinding met server tot stand te brengen: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: Niet mogelijk om printer of instance toe te voegen: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: Niet mogelijk om PPD-bestand voor %s op te vragen: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: Dit wachtwoord is helaas niet toegestaan.\n"
+"Uw wachtwoord moet uit minimaal 6 tekens bestaan, waarvan minimaal één "
+"letter en één cijfer, en mag niet uw gebruikersnaam bevatten.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: Niet mogelijk om wachtwoordreeks te kopiëren: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: Niet mogelijk om wachtwoordbestand te openen: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: Niet mogelijk om wachtwoordbestand weg te schrijven: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr "lppasswd: Kon geen reservekopie maken van oude wachtwoordbestand: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: Kon wachtwoordbestand geen andere naam geven: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: Gebruiker \"%s\" en groep \"%s\" bestaan niet.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "leden van klasse %s:\n"
+
+msgid "no entries\n"
+msgstr "geen onderdelen\n"
+
+msgid "no system default destination\n"
+msgstr "geen bestemming voor systeemstandaard\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "in bewerking"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: Include-directory \"%s\" wordt toegevoegd...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: Interfacetekst van %s wordt toegevoegd/bijgewerkt...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: Ongeldige Booleaanse waarde (%s) in regel %d van %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: Ongeldige variabelevervanging ($%c) in regel %d van %s.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: Verwachtte Booleaanse waarde in regel %d van %s.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: Verwachtte keuzecode in regel %d van %s.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: Verwachtte keuzenaam/-tekst in regel %d van %s.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: Bestand met stuurprogrammagegevens \"%s\" wordt geladen...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: Berichten voor taalversie \"%s\" worden geladen...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: Berichten worden geladen uit \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: Niet mogelijk om PPD-bestand \"%s\" aan te maken - %s.\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: Niet mogelijk om uitvoerdirectory %s aan te maken: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: Niet mogelijk om uitvoerpipes aan te maken: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: Niet mogelijk om cupstestppd uit te voeren: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: geen lokalisatie gevonden voor \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: Niet mogelijk om lokalisatiebestand \"%s\" te laden - %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: Niet-gedefinieerde variabele (%s) in regel %d van %s.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: %s wordt weggeschreven...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: PPD-bestanden worden naar directory \"%s\" geschreven...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: PPD-bestand %s wordt genegeerd...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: Niet mogelijk om reservekopie van %s te bewaren als %s- %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "printer %s uitgeschakeld sinds %s -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "printer %s is niet in gebruik. ingeschakeld sinds %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "printer %s is bezig met afdrukken %s-%d. ingeschakeld sinds %s\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "printer %s/%s uitgeschakeld sinds %s -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "printer %s/%s is niet in gebruik. ingeschakeld sinds %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "printer %s/%s is bezig met afdrukken %s-%d. ingeschakeld sinds %s\n"
+
+msgid "processing"
+msgstr "taak wordt verwerkt"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "verzoek-ID is %s-%d (%d bestand(en))\n"
+
+msgid "request-id uses indefinite length"
+msgstr "onbepaalde lengte gebruikt voor request-id"
+
+msgid "scheduler is not running\n"
+msgstr "taakplanner is niet actief\n"
+
+msgid "scheduler is running\n"
+msgstr "taakplanner is actief\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "stat van %s mislukt: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "status\t\ttoon status van daemon en wachtrij\n"
+
+msgid "stopped"
+msgstr "gestopt"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "bestemming voor systeemstandaard: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "bestemming voor systeemstandaard: %s/%s\n"
+
+msgid "unknown"
+msgstr "onbekend"
+
+msgid "untitled"
+msgstr "naamloos"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "onbepaalde lengte gebruikt voor variable-bindings"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " WARN %s heeft geen bijbehorende opties!\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " WARN Standaardkeuzen conflicteren!\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " WARN Sleutelwoord %s voor duplexoptie werkt mogelijk niet "
+#~ "zoals verwacht. Gebruik Duplex als sleutelwoord.\n"
+#~ " REF: Pagina 122, sectie 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " WARN Bestand bevat een combinatie van CR-, LF- en CR LF-"
+#~ "regeleinden!\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " WARN Regel %d bevat alleen witruimte!\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " WARN APDialogExtension-bestand \"%s\" ontbreekt\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " WARN APPrinterIconPath-bestand \"%s\" ontbreekt\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " WARN PPD-bestanden voor andere systemen dan Windows mogen "
+#~ "uitsluitend LF als regeleinde gebruiken, niet CR LF!\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " WARN Verouderde PPD-versie %.1f!\n"
+#~ " REF: Pagina 42, sectie 5.2.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s bestaat niet!\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s Ongeldige %s keuze %s!\n"
+#~ " REF: Pagina 122, sectie 5.17\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr " %s Ongeldige UTF-8 \"%s\" vertaalreeks voor optie %s!\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Ongeldige UTF-8 \"%s\" vertaalreeks voor optie %s, keuze %s!\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Ongeldige waarde voor cupsFilter \"%s\"!\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s Ongeldig cupsICCProfile %s!\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Ongeldige waarde voor cupsPreFilter \"%s\"!\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Ongeldige cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s Ongeldige taal \"%s\"!\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s Lege cupsUIConstraints %s!\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s Ontbrekende \"%s\" vertaalreeks voor optie %s!\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Ontbrekende \"%s\" vertaalreeks voor optie %s, keuze %s!\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Ontbrekende keuze *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr ""
+#~ " %s Ontbrekende keuze *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s Ontbrekend cupsICCProfile-bestand \"%s\"!\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s Ontbrekende cupsUIResolver %s!\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Ontbrekende optie %s in UIConstraints \"*%s %s *%s %s\"!\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Ontbrekende optie %s in cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr " %s Geen basisvertaling \"%s\" opgenomen in bestand!\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s REQUIRED %s bevat geen definitie voor keuze None!\n"
+#~ " REF: Pagina 122, sectie 5.17\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " %s cupsICCProfile %s hash-waarde conflicteert met %s!\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver %s veroorzaakt een lus!\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** %s keuzenamen %s en %s verschillen alleen in "
+#~ "hoofdlettergebruik!\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **FAIL** %s moet 1284DeviceID zijn!\n"
+#~ " REF: Pagina 72, sectie 5.5\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** ONGELDIGE DefaultImageableArea %s!\n"
+#~ " REF: Pagina 102, sectie 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** ONGELDIGE DefaultPaperDimension %s!\n"
+#~ " REF: Pagina 103, sectie 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **FAIL** Ongeldige %s keuze %s!\n"
+#~ " REF: Pagina 84, sectie 5.9\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr ""
+#~ " **FAIL** Ongeldige LanguageEncoding %s - moet ISOLatin1 zijn!\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr " **FAIL** Ongeldige LanguageVersion %s - moet Engels zijn!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **FAIL** Standaardvertaalreeks voor optie %s keuze %s bevat 8-bits "
+#~ "tekens!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **FAIL** Standaardvertaalreeks voor optie %s bevat 8-bits tekens!\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Groepsnamen %s en %s verschillen alleen in "
+#~ "hoofdlettergebruik!\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **FAIL** %s keuzenaam %s komt meerdere keren voor!\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Optienamen %s en %s verschillen alleen in "
+#~ "hoofdlettergebruik!\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " Ongeldige %%%%BoundingBox: op regel %d!\n"
+#~ " REF: Pagina 39, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " Ongeldige %%%%Page: op regel %d!\n"
+#~ " REF: Pagina 53, %%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " Ongeldige %%%%Pages: op regel %d!\n"
+#~ " REF: Pagina 43, %%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " Regel %d bevat meer dan 255 tekens (%d)!\n"
+#~ " REF: Pagina 25, Line Length\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " Ontbrekende %!PS-Adobe-3.0 op eerste regel!\n"
+#~ " REF: Pagina 17, 3.1 Conforming Documents\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " Ontbrekend %%EndComments-commentaar!\n"
+#~ " REF: Pagina 41, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " Ontbrekend of ongeldig %%BoundingBox-commentaar!\n"
+#~ " REF: Pagina 39, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " Ontbrekend of ongeldig %%Page-commentaar!\n"
+#~ " REF: Pagina 53, %%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " Ontbrekend of ongeldig %%Pages-commentaar!\n"
+#~ " REF: Pagina 43, %%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " %d Regels gevonden met meer dan 255 tekens!\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " Te veel %%BeginDocument-commentaren!\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " Te veel %%EndDocument-commentaren!\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " Waarschuwing: bestand bevat binaire gegevens!\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " Waarschuwing: bestand bevat geen %%EndComments-commentaar!\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " Waarschuwing: bestand bevat verouderde DSC versie %.1f!\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s niet ondersteund!"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: Ik weet niet wat ik moet doen!\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: Fout - %s niet-bestaande bestemming voor variabelenamen van omgeving "
+#~ "\"%s\"!\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: Fout - ongeldige taak-ID!\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr ""
+#~ "%s: Fout - niet mogelijk om gelijktijdig bestanden af te drukken en taken "
+#~ "te wijzigen!\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: Fout - niet mogelijk om af te drukken vanuit stdin als bestanden of "
+#~ "een taak-ID zijn aangeleverd!\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: Fout - verwachtte tekenset na optie &aops;-S&aops;!\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: Fout - verwachtte inhoudstype na optie &aops;-T&aops;!\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: Fout - verwachtte aantal afdrukken na optie &aops;-n&aops;!\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s: Fout - verwachtte aantal exemplaren na optie &aops;-#&aops;!\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: Fout - verwachtte bestemming na optie &aops;-P&aops;!\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: Fout - verwachtte bestemming na optie &aops;-b&aops;!\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: Fout - verwachtte bestemming na optie &aops;-d&aops;!\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: Fout - verwachtte formulier na optie &aops;-f&aops;!\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: Fout - verwachtte hold-naam na optie &aops;-H&aops;!\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: Fout - verwachtte hostnaam na optie &aops;-H&aops;!\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: Fout - verwachtte hostnaam na optie &aops;-h&aops;!\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: Fout - verwachtte moduslijst na optie &aops;-y&aops;!\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: Fout - verwachtte naam na optie &aops;-%c&aops;!\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s: Fout - verwachtte optietekenreeks na optie &aops;-o&aops;!\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: Fout - verwachtte paginalijst na optie &aops;-P&aops;!\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: Fout - verwachtte prioriteit na optie &aops;-%c&aops;!\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s: Fout - verwachtte verklaring na optie &aops;-r&aops;!\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: Fout - verwachtte titel na optie &aops;-t&aops;!\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s: Fout - verwachtte gebruikersnaam na optie &aops;-U&aops;!\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s: Fout - verwachtte gebruikersnaam na optie &aops;-u&aops;!\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: Fout - verwachtte waarde na optie &aops;-%c&aops;!\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: Fout - optie &aops;-W&aops; moet worden gevolgd door \"gereed\", "
+#~ "\"niet gereed\" of \"alle\"!\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: Fout - taakplanner reageert niet!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: Fout - onbekende bestemming \"%s\"!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: Fout - onbekende bestemming \"%s/%s\"!\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: Fout - onbekende optie &aops;%c&aops;!\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: Fout - onbekende optie '%s'!\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: Verwachtte taak-ID na optie &aops;-i&aops;!\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: Ongeldige bestemmingsnaam in lijst \"%s\"!\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr ""
+#~ "%s: Taak-ID (&aops;-i jobid&aops;) nodig voor &aops;-H restart&aops;!\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: Geen filter beschikbaar voor conversie van %s/%s naar %s/%s!\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s: Sorry, geen ondersteuning voor encryptie opgenomen!\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: Kan geen contact maken met server!\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: Niet mogelijk om MIME-type van \"%s\" vast te stellen!\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s: Niet mogelijk om %s - %s te openen\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s: Niet mogelijk om %s - %s in regel %d te openen.\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s: Niet mogelijk om MIME-database van \"%s\" of \"%s\" te lezen!\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: Onbekende bestemming \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: Onbekend MIME-type voor bestemming %s/%s!\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: Onbekende optie &aops;%c&aops;!\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: Onbekend MIME-type voor bron %s/%s!\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: Waarschuwing - &aops;%c&aops; format modifier niet ondersteund - "
+#~ "uitvoer is mogelijk niet correct!\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: Waarschuwing - tekensetoptie genegeerd!\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: Waarschuwing - inhoudstype-optie genegeerd!\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: Waarschuwing - formulieroptie genegeerd!\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: Waarschuwing - modusoptie genegeerd!\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: fout - %s niet-bestaande bestemming voor variabelenamen van omgeving "
+#~ "\"%s\"!\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: fout - verwachtte optie=waarde na optie &aops;-o&aops;!\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "600-DPI grijstinten"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr ""
+#~ "Voor het exporteren van printerstuurprogramma&aops;s is een Samba-"
+#~ "wachtwoord vereist!"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr ""
+#~ "Voor het exporteren van printerstuurprogramma&aops;s is een Samba-"
+#~ "gebruikersnaam vereist!"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "Er is al een klasse met de naam \"%s\"!"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "Er is al een printer met de naam \"%s\"!"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr "Poging om %s printer-state in te stellen op ongeldige waarde %d!"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "Attribuutgroepen hebben verkeerde volgorde (%x < %x)!"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "Ongeldige apparaat-URI \"%s\"!\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "Ongeldige device-uri \"%s\"!"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "Ongeldig device-uri-schema \"%s\"!"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "Ongeldige documentindeling \"%s\"!"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Ongeldige bestandsnaambuffer!"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Ongeldige waarde voor job-priority!"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Ongeldige waarde voor job-sheets \"%s\"!"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Ongeldig waardetype voor job-sheets!"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Ongeldige waarde voor job-state!"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Ongeldig job-uri-attribuut \"%s\"!"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "Ongeldige notify-pull-method \"%s\"!"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "Ongeldige URI voor notify-recipient-uri \"%s\"!"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "Ongeldige optie + keuze op regel %d!"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "Ongeldige port-monitor \"%s\"!"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Ongeldige waarde voor printer-state %d!"
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "Ongeldig versienummer voor verzoek %d.%d!"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "Ongeldig abonnement-ID!"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "Tekenset \"%s\" niet ondersteund!"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "Kon type \"%s\" niet scannen!"
+
+#~ msgid "Cover open."
+#~ msgstr "Printklep open."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "Ontwikkelaar bijna op."
+
+#~ msgid "Developer empty!"
+#~ msgstr "Ontwikkelaar op!"
+
+#~ msgid "Door open."
+#~ msgstr "Deur open."
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Ongeldige %%BoundingBox: opmerking ontdekt!\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: Ongeldige %%IncludeFeature: opmerking!\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: Ongeldige %%Page: opmerking in bestand!\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: Ongeldige %%PageBoundingBox: opmerking in bestand!\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: Ongeldig SCSI-apparaatbestand \"%s\"!\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: Ongeldige kolomwaarde %d!\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: Ongeldige cpi-waarde %f!\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: Ongeldige lpi-waarde %f!\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: Ongeldige pagina-instelling!\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: Printer die is gekozen als bestemming bestaat niet!\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Dubbele %%BoundingBox: opmerking ontdekt!\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: Dubbele %%Pages: opmerking ontdekt!\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: Leeg afdrukbestand!\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr ""
+#~ "ERROR: Verwachtte tekenreeks met aanhalingstekens in regel %d van %s!\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: Fatale USB-fout!\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr ""
+#~ "ERROR: Ongeldig HP-GL/2-commando ontdekt, kan afdrukbestand niet openen!\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: Ontbrekende %%EndProlog!\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: Ontbrekende %%EndSetup!\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Ontbrekende apparaat-URI op commandoregel en geen DEVICE_URI-"
+#~ "omgevingsvariabele!\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: Ontbrekende waarde in regel %d van bannerbestand!\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: msgid-regel vereist voorafgaand aan vertaalreeksen in regel %d van "
+#~ "%s!\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: Geen %%BoundingBox: opmerking in kopregel!\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: Geen %%Pages: opmerking in kopregel!\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Geen apparaat-URI gevonden in argv[0] of in DEVICE_URI-"
+#~ "omgevingsvariabele!\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: Geen pagina&aops;s gevonden!\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: Papier is op!\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: PRINTER-omgevingsvariabele niet gedefinieerd!\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: Afdrukbestand niet geaccepteerd (%s)!\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: Printer reageert niet!\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: Niet mogelijk om tijdelijk bestand - %s te maken.\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: Niet mogelijk om tijdelijk bestand te maken: %s\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: Niet mogelijk om taakattributen %d op te vragen (%s)!\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: Niet mogelijk om printerstatus op te vragen (%s)!\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: Niet mogelijk om printer &aops;%s&aops; te vinden!\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: Niet mogelijk om beeldbestand te openen voor afdrukken!\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: Niet mogelijk om tijdelijk bestand te openen"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: Niet mogelijk om %d tekstkolommen af te drukken!\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: Niet mogelijk om %dx%d tekstpagina af te drukken!\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: Niet mogelijk om afdrukgegevens te lezen!\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: Niet mogelijk om afdrukgegevens te verzenden (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: Niet mogelijk om afdrukgegevens te versturen!\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: Niet mogelijk om %d bytes naar printer te schrijven!\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr ""
+#~ "ERROR: Niet mogelijk om rastergegevens weg te schrijven naar "
+#~ "stuurprogramma!\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: Niet mogelijk om naar tijdelijk bestand te schrijven"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: Onverwachte tekst in regel %d van %s!\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: Onbekende waarde voor encryptie-optie \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: Onbekende berichtencatalogusstructuur voor \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: Onbekende optie \"%s\" met waarde \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: Onbekende waarde voor versie-optie \"%s\"!\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr ""
+#~ "ERROR: Niet-ondersteunde waarde voor helderheid %s, gebruikt "
+#~ "helderheid=100!\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr ""
+#~ "ERROR: Niet-ondersteunde waarde voor gamma %s, gebruikt gamma=1000!\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr ""
+#~ "ERROR: Niet-ondersteunde waarde voor number-up %d, gebruikt number-up=1!\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: Niet-ondersteunde waarde voor number-up-layout %s, gebruikt number-"
+#~ "up-layout=lrtb!\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: Niet-ondersteunde waarde voor page-border %s, gebruikt page-"
+#~ "border=none!\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr ""
+#~ "ERROR: doc_printf-overflow (%d bytes) ontdekt, afdrukken wordt "
+#~ "geannuleerd!\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr "ERROR: pdftops-filter vastgelopen op signaal %d!\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr "ERROR: pdftops-filter gestopt met status %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops gestopt na signaal %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops gestopt met status %d!\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: kan worden hersteld: niet mogelijk om verbinding te maken met "
+#~ "printer; nieuwe poging over 30 seconden...\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "Leeg PPD-bestand!"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "Fout: hostnaam nodig na optie &aops;-h&aops;!\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Fusertemperatuur te hoog!"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "Fusertemperatuur te laag!"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "Printer-uri-attribuut gevonden, maar geen job-id!"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Inkt/toner bijna op."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Inkt/toner op!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Opvangbak voor inkt/toner bijna vol."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Opvangbak voor inkt/toner vol!"
+
+#~ msgid "Interlock open."
+#~ msgstr "Interlock open."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "Taak #%d kan niet worden herstart - geen bestanden!"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "Taak #%d bestaat niet!"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "Taak #%d is gereed en kan niet worden gewijzigd!"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "Taak #%d is nog niet gereed!"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "Taak #%d wordt niet vastgehouden voor controle!"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "Taak #%d wordt niet vastgehouden!"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "Taak #%s bestaat niet!"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "Taak %d niet gevonden!"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "Taakabonnementen kunnen niet worden verlengd!"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "Taal \"%s\" wordt niet ondersteund!"
+
+#~ msgid "Media jam!"
+#~ msgstr "Materiaal is vastgelopen!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Materiaallade is bijna leeg."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Materiaallade is leeg!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Materiaallade ontbreekt!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "Materiaallade moet worden bijgevuld."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "Document-number-attribuut ontbreekt!"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "Ontbrekend dubbel aanhalingsteken op regel %d!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "Ontbrekende formuliervariabele!"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "Notify-subscription-ids-attribuut ontbreekt!"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "Requesting-user-name-attribuut ontbreekt!"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "Vereiste attributen ontbreken!"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "Ontbrekende waarde op regel %d!"
+
+#~ msgid "No PPD name!"
+#~ msgstr "Geen PPD-naam!"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Er zijn geen Windows-printerstuurprogramma&aops;s geïnstalleerd!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "Geen actieve taken op %s!"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "Verzoek bevat geen attributen!"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "Geen informatie verstrekt voor toegangscontrole!"
+
+#~ msgid "No file!?!"
+#~ msgstr "Geen bestand!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "Geen bewerkingstijdstip!"
+
+#~ msgid "No printer name!"
+#~ msgstr "Geen printernaam!"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "Geen printer-uri gevonden voor klasse!"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "Geen printer-uri gevonden!"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "Verzoek bevat geen printer-uri!"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "Verzoek bevat geen attributen voor abonnement!"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC bijna aan einde levensduur."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC aan einde levensduur!"
+
+#~ msgid "Out of toner!"
+#~ msgstr "Toner is op!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Uitvoerbak is bijna vol."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Uitvoerbak is vol!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Uitvoerbak ontbreekt!"
+
+#~ msgid "Printer offline."
+#~ msgstr "Printer offline."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "SCSI-printer"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "De waarde voor notify-user-data is te groot (%d > 63 octetten)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr ""
+#~ "De printer of klasse is niet toegankelijk voor gemeenschappelijk gebruik!"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "Het attribuut &aops;printer-uri&aops; is vereist!"
+
+#~ msgid "Toner low."
+#~ msgstr "Toner is bijna op."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "Te veel waarden voor job-sheets (%d > 2)!"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "Te veel waarden voor printer-state-reasons (%d > %d)!"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "Niet mogelijk om taak toe te voegen voor bestemming \"%s\"!"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "Niet mogelijk om geheugen toe te wijzen voor bestandstypen!"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "Niet mogelijk om 64-bits CUPS-printerstuurprogramma&aops;s te kopiëren (%"
+#~ "d)!"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr ""
+#~ "Niet mogelijk om 64-bits Windows-printerstuurprogramma&aops;s te kopiëren "
+#~ "(%d)!"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "Niet mogelijk om CUPS-printerstuurprogramma&aops;s te kopiëren (%d)!"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "Niet mogelijk om PPD-bestand te kopiëren - %s!"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "Niet mogelijk om PPD-bestand te kopiëren!"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Niet mogelijk om Windows 2000-printerstuurprogramma&aops;s te kopiëren (%"
+#~ "d)!"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "Niet mogelijk om Windows 9x-printerstuurprogramma&aops;s te kopiëren (%d)!"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "Niet mogelijk om interfacescript te kopiëren - %s!"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "Niet mogelijk om printer-uri aan te maken!"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr ""
+#~ "Niet mogelijk om cupsd.conf-bestanden van meer dan 1 MB te bewerken!"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "Bestemming voor taak kon niet worden gevonden!"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "Printer is niet gevonden!\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Niet mogelijk om Windows 2000-printerstuurprogramma&aops;s te installeren "
+#~ "(%d)!"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "Niet mogelijk om Windows 9x-printerstuurprogramma&aops;s te installeren (%"
+#~ "d)!"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "Niet mogelijk om document %d in taak %d te openen!"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "Niet mogelijk om commando naar printerstuurprogramma te versturen!"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Niet mogelijk om Windows-printerstuurprogramma in te stellen (%d)!"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "Niet mogelijk om verouderd USB-stuurprogramma te gebruiken!\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "Onbekende printerfout (%s)!"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Niet-ondersteunde tekenset \"%s\"!"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "Niet-ondersteunde compressie \"%s\"!"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "Niet-ondersteund compressie-attribuut %s!"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "Niet-ondersteunde indeling \"%s\"!"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "Niet-ondersteunde indeling '%s'!"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "Niet-ondersteunde indeling '%s/%s'!"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "Gebruik: convert [ opties ]\n"
+#~ "\n"
+#~ "Opties:\n"
+#~ "\n"
+#~ " -f bestandsnaam Stel te converteren bestand in (anders stdin)\n"
+#~ " -o bestandsnaam Stel te genereren bestand in (anders stdout)\n"
+#~ " -i mime/type Stel MIME-type voor invoer in (anders auto-typed)\n"
+#~ " -j mime/type Stel MIME-type voor uitvoer in (anders application/"
+#~ "pdf)\n"
+#~ " -P bestandsnaam.ppd Stel PPD-bestand in\n"
+#~ " -a 'naam=waarde ...' Stel optie(s) in\n"
+#~ " -U gebruikersnaam Stel gebruikersnaam voor taak in\n"
+#~ " -J titel Stel titel in\n"
+#~ " -c aantal Stel aantal exemplaren in\n"
+#~ " -u Verwijder het PPD-bestand na conversie\n"
+#~ " -D Verwijder het invoerbestand na conversie\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "Gebruik: cupsfilter -m mime/type [ opties ] bestandsnaam\n"
+#~ "\n"
+#~ "Opties:\n"
+#~ "\n"
+#~ " -c cupsd.conf Stel in welk cupsd.conf-bestand moet worden gebruikt\n"
+#~ " -j taak-ID[,N] Filter bestand N uit opgegeven taak (standaard is "
+#~ "bestand 1)\n"
+#~ " -n aantal Stel aantal exemplaren in\n"
+#~ " -o naam=waarde Stel optie(s) in\n"
+#~ " -p bestandsnaam.ppd Stel PPD-bestand in\n"
+#~ " -t titel Stel titel in\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Gebruik: cupstestppd [opties] bestandsnaam1.ppd[.gz] [... bestandsnaamN."
+#~ "ppd[.gz]]\n"
+#~ " program | cupstestppd [opties] -\n"
+#~ "\n"
+#~ "Opties:\n"
+#~ "\n"
+#~ " -R root-directory Stel alternatieve root in\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Toon waarschuwingen in plaats van fouten\n"
+#~ " -q Voer uit zonder meldingen\n"
+#~ " -r Gebruik &aops;relaxed&aops; open modus\n"
+#~ " -v Gebruik beperkte verbose-modus\n"
+#~ " -vv Gebruik uitgebreide verbose-modus\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: Kon zijkanaalverzoek niet lezen!\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr ""
+#~ "WARNING: Optie \"%s\" kan niet worden ingevoegd met behulp van "
+#~ "IncludeFeature!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Niet-lokale host heeft niet binnen %d seconden gereageerd met "
+#~ "commandostatusbyte!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Niet-lokale host heeft niet binnen %d seconden gereageerd met "
+#~ "besturingsstatusbyte!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Niet-lokale host heeft niet binnen %d seconden gereageerd met "
+#~ "gegevensstatusbyte!\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr ""
+#~ "WARNING: SCSI-commando niet tijdig verwerkt (%d); nieuwe poging...\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: Dit document beantwoordt niet aan de Adobe Document Structuring "
+#~ "Conventions en wordt mogelijk niet goed afgedrukt!\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: Onbekende keuze \"%s\" voor optie \"%s\"!\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: Onbekende optie \"%s\"!\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: Niet-ondersteunde baudsnelheid %s!\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: Herstelbare fout: netwerkhost &aops;%s&aops; is bezig; nieuwe "
+#~ "poging over %d seconden...\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr ""
+#~ "Let op: geen Windows 2000-printerstuurprogramma&aops;s geïnstalleerd!"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: Onbekende optie \"%s\"!\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: Onbekende optie \"-%c\"!\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr "cupsd: Verwachtte config-bestandsnaam na optie \"-c\"!\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: Niet mogelijk om huidige directory op te vragen!\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: Onbekend argument \"%s\" - bewerking wordt afgebroken!\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: Onbekende optie \"%c\" - bewerking wordt afgebroken!\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: Ongeldig documentnummer %d!\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: Ongeldige taak-ID %d!\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: U kunt slechts één bestandsnaam opgeven!\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter: Niet mogelijk om tijdelijk bestand aan te maken: %s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "Job-printer-uri-attribuut ontbreekt!"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Klassenaam mag alleen afdrukbare tekens bevatten!\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: Verwachtte PPD na optie &aops;-P&aops;!\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr "lpadmin: Verwachtte allow/deny:userlist na optie &aops;-u&aops;!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: Verwachtte klasse na optie &aops;-r&aops;!\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: Verwachtte klassenaam na optie &aops;-c&aops;!\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: Verwachtte omschrijving na optie &aops;-D&aops;!\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: Verwachtte apparaat-URI na optie &aops;-v&aops;!\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: Verwachtte bestandstype(n) na optie &aops;-I&aops;!\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: Verwachtte hostnaam na optie &aops;-h&aops;!\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: Verwachtte interface na optie &aops;-i&aops;!\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: Verwachtte locatie na optie &aops;-L&aops;!\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: Verwachtte model na optie &aops;-m&aops;!\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: Verwachtte naam=waarde na optie &aops;-o&aops;!\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: Verwachtte printer na optie &aops;-p&aops;!\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: Verwachtte printernaam na optie &aops;-d&aops;!\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin: Verwachtte printer of klasse na optie &aops;-x&aops;!\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: Geen lidnamen ontdekt!\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Printernaam mag alleen afdrukbare tekens bevatten!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Niet mogelijk om printer aan klasse toe te voegen:\n"
+#~ " U moet eerst een printernaam opgeven!\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin: Niet mogelijk om tijdelijk bestand aan te maken - %s\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin: Niet mogelijk om tijdelijk bestand aan te maken: %s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Niet mogelijk om printer uit klasse te verwijderen:\n"
+#~ " U moet eerst een printernaam opgeven!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Niet mogelijk om het PPD-bestand in te stellen:\n"
+#~ " U moet eerst een printernaam opgeven!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Niet mogelijk om de apparaat-URI in te stellen:\n"
+#~ " U moet eerst een printernaam opgeven!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Niet mogelijk om het interfacescript of het PPD-bestand in te "
+#~ "stellen:\n"
+#~ " U moet eerst een printernaam opgeven!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Niet mogelijk om het interfacescript in te stellen:\n"
+#~ " U moet eerst een printernaam opgeven!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Niet mogelijk om de printerbeschrijving in te stellen:\n"
+#~ " U moet eerst een printernaam opgeven!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Niet mogelijk om de printerlocatie in te stellen:\n"
+#~ " U moet eerst een printernaam opgeven!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Niet mogelijk om de printeropties in te stellen:\n"
+#~ " U moet eerst een printernaam opgeven!\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: Onbekende optie voor toestaan/weigeren \"%s\"!\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: Onbekend argument &aops;%s&aops;!\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: Onbekende optie &aops;%c&aops;!\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin: Waarschuwing - inhoudstypelijst genegeerd!\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr ""
+#~ "lpinfo: Verwachtte tekenreeks met 1284-apparaat-ID na --device-id!\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: Verwachtte taal na --language!\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo: Verwachtte merk en model na --make-and-model!\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo: Verwachtte producttekenreeks na --product!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo: Verwachtte schemalijst na --exclude-schemes!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo: Verwachtte schemalijst na --include-schemes!\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: Verwachtte time-out na --timeout!\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: Onbekend argument &aops;%s&aops;!\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: Onbekende optie &aops;%c&aops;!\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: Onbekende optie &aops;%s&aops;!\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: Onbekend argument &aops;%s&aops;!\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: Onbekende optie &aops;%c&aops;!\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: Geen printers!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: Niet mogelijk om PPD-bestand voor %s te openen!\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: Onbekende printer of klasse!\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: Alleen root kan wachtwoorden toevoegen of verwijderen!\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: Wachtwoordbestand is in gebruik!\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: Wachtwoordbestand niet bijgewerkt!\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: Wachtwoord komt helaas niet overeen!\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: Wachtwoorden komen helaas niet overeen!\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: fout - %s niet-bestaande bestemming voor variabelenamen van "
+#~ "omgeving \"%s\"!\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-events niet gespecificeerd!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "notify-recipient-uri URI \"%s\" wordt al gebruikt!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "notify-recipient-uri URI \"%s\" gebruikt onbekend schema!"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d niet goed!"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ongeldige resolutienaam \"%s\" in regel %d van %s!\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: Ongeldig statussleutelwoord %s in regel %d van %s!\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc: Keuze gevonden in regel %d van %s zonder optie!\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc: Dubbele #po voor taalversie %s in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte een filterdefinitie in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte een programmanaam in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte tekenset na Font in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Verwachtte kleurvolgorde voor ColorModel in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte kleurruimte voor ColorModel in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte compressie voor ColorModel in regel %d van %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Verwachtte beperkingenreeks voor UIConstraints in regel %d van %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Verwachtte sleutelwoord voor stuurprogrammatype na DriverType in "
+#~ "regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte duplextype na Duplex in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte codering na Font in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte bestandsnaam na #po %s in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte groepsnaam/-tekst in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte include-bestandsnaam in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte geheel getal in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte taalversie na #po in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte naam na %s in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte naam na FileName in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte naam na Font in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte naam na Manufacturer in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte naam na MediaSize in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte naam na ModelName in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte naam na PCFileName in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte naam/tekst na %s in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte naam/tekst na Installable in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte naam/tekst na Resolution in regel %d van %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Verwachtte naam/tekst-combinatie voor ColorModel in regel %d van %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte optienaam/-tekst in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte optiesectie in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte optietype in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte override-veld na Resolution in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte reëel getal in regel %d van %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Verwachtte resolutie/materiaaltype na ColorProfile in regel %d van %"
+#~ "s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Verwachtte resolutie/materiaaltype na SimpleColorProfile in regel %"
+#~ "d van %s!\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte selector na %s in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte status na Font in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte tekenreeks na Copyright in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte tekenreeks na Version in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte twee optienamen in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte waarde na %s in regel %d van %s!\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Verwachtte versie na Font in regel %d van %s!\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: Ongeldige #include/#po-bestandsnaam \"%s\"!\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Ongeldige kosten voor filter in regel %d van %s!\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Ongeldig leeg MIME-type voor filter in regel %d van %s!\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Ongeldige lege programmanaam voor filter in regel %d van %s!\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ongeldige optiesectie \"%s\" in regel %d van %s!\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ongeldig optietype \"%s\" in regel %d van %s!\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: #endif ontbreekt aan einde van \"%s\"!\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: #if ontbreekt in regel %d van %s!\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc: Geen berichtencatalogus opgegeven voor taalversie %s!\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Optie %s opnieuw gedefinieerd met een ander type in regel %d van %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr "ppdc: Optiebeperking moet *name in regel %d van %s!\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: Te veel geneste #if's in regel %d van %s!\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: #po-bestand %s niet gevonden in regel %d van %s!\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: include-bestand \"%s\" niet gevonden in regel %d van %s!\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: Onbekend type stuurprogramma %s in regel %d van %s!\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Onbekend duplextype \"%s\" in regel %d van %s!\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Onbekende materiaalgrootte \"%s\" in regel %d van %s!\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: Onbekend token \"%s\" in regel %d van %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Onbekende afsluitende tekens in reëel getal \"%s\" in regel %d van %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Niet-afgesloten tekenreeks die begint met %c in regel %d van %s!\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: Ongeldige LanguageVersion \"%s\" in %s!\n"
diff --git a/locale/cups_no.po b/locale/cups_no.po
new file mode 100644
index 000000000..6171ae640
--- /dev/null
+++ b/locale/cups_no.po
@@ -0,0 +1,7082 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-16 12:00-0800\n"
+"Last-Translator: Apple Inc.\n"
+"Language-Team: Apple Inc.\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(alle)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(ingen)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d oppføringer\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tEtter feil: fortsett\n"
+
+msgid "\tAlerts:"
+msgstr "\tVarsling:"
+
+msgid "\tBanner required\n"
+msgstr "\tKrever banner\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tTegnsettsamlinger:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tTilkobling: direkte\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tTilkobling: ekstern\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tStandard sidestørrelse:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tStandard avstand:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tStandard portinnstillinger:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tBeskrivelse: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tAktivert skjema:\n"
+"\tInnholdstyper: alle\n"
+"\tSkrivertyper: ukjent\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tTillatte skjemaer:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tGrensesnitt: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tGrensesnitt: %s/interfaces/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tGrensesnitt: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tPlassering: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tVed feil: ingen varsling\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tBrukere tillatt:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tBrukere avslått:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tdaemon til stede\n"
+
+msgid "\tno entries\n"
+msgstr "\tingen oppføringer\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\tskriver er på enhet «%s», hastighet -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\tutskrift er deaktivert\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\tutskrift er aktivert\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\ti kø for %s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tutskriftskø er deaktivert\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tutskriftskø er aktivert\n"
+
+msgid "\treason unknown\n"
+msgstr "\tukjent grunn\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" DETALJERTE RESULTATER FRA SAMSVARSTEST\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " REF: Side 15, del 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " REF: Side 15, del 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " REF: Side 19, del 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " REF: Side 20, del 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " REF: Side 27, del 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " REF: Side 42, del 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " REF: Sider 16–17, del 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " REF: Sider 42–45, del 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " REF: Sider 45–46, del 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " REF: Sider 48–49, del 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " REF: Sider 52–54, del 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f byte\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " PASS Default%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " PASS DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " PASS DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " PASS FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " PASS FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " PASS LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " PASS LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " PASS Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " PASS ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " PASS NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " PASS PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " PASS PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " PASS PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " PASS PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " PASS Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " PASS ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" WARN «%s %s» er i strid med «%s %s»\n"
+" (constraint=«%s %s %s %s»)\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" WARN %s har samme prefiks som %s\n"
+" REF: Side 15, del 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" WARN LanguageEncoding kreves av PPD 4.3-spesifikasjonen.\n"
+" REF: Sider 56–57, del 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" WARN Manufacturer kreves av PPD 4.3-spesifikasjonen.\n"
+" REF: Sider 58–59, del 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" WARN PCFileName er lengre enn 8.3, noe som er et brudd på PPD-"
+"spesifikasjonen.\n"
+" REF: Sider 61–62, del 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protokoller inneholder PJL, men JCL-attributter er ikke "
+"angitt.\n"
+" REF: Sider 78–79, del 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protokoller inneholder både PJL og BCP. Forventet TBCP.\n"
+" REF: Sider 78–79, del 5.7.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" WARN ShortNickName kreves av PPD 4.3-spesifikasjonen.\n"
+" REF: Sider 64–65, del 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s cupsFilter-filen «%s» mangler\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s cupsPreFilter-filen «%s» mangler\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FEIL** UGYLDIG Default%s %s\n"
+" REF: Side 40, del 4.5.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **FEIL** UGYLDIG JobPatchFile-attributt i fil\n"
+" REF: Side 24, del 3.4.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FEIL** UGYLDIG Manufacturer (skal være «HP»)\n"
+" REF: Side 211, tabell D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FEIL** UGYLDIG Manufacturer (skal være «Oki»)\n"
+" REF: Side 211, tabell D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FEIL** UGYLDIG ModelName – «%c» er ikke tillatt i strengen.\n"
+" REF: Sider 59–60, del 5.3.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FEIL** UGYLDIG PSVersion – er ikke «(string) int».\n"
+" REF: Sider 62–64, del 5.3.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FEIL** UGYLDIG Product – er ikke «(string)».\n"
+" REF: Side 62, del 5.3.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **FEIL** UGYLDIG ShortNickName – mer enn 31 tegn.\n"
+" REF: Sider 64–65, del 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FEIL** Ugyldig FileVersion «%s»\n"
+" REF: Side 56, del 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FEIL** Ugyldig FormatVersion «%s»\n"
+" REF: Side 56, del 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr " **FEIL** Kan ikke tolke standard valgkode: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK Default%s\n"
+" REF: Side 40, del 4.5.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK DefaultImageableArea\n"
+" REF: Side 102, del 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK DefaultPaperDimension\n"
+" REF: Side 103, del 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK FileVersion\n"
+" REF: Side 56, del 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK FormatVersion\n"
+" REF: Side 56, del 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK ImageableArea for PageSize %s\n"
+" REF: Side 41, del 5.\n"
+" REF: Side 102, del 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK LanguageEncoding\n"
+" REF: Sider 56–57, del 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK LanguageVersion\n"
+" REF: Sider 57–58, del 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK Manufacturer\n"
+" REF: Sider 58–59, del 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK ModelName\n"
+" REF: Sider 59–60, del 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK NickName\n"
+" REF: Side 60, del 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK PCFileName\n"
+" REF: Sider 61–62, del 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK PSVersion\n"
+" REF: Sider 62–64, del 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK PageRegion\n"
+" REF: Side 100, del 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK PageSize\n"
+" REF: Side 41, del 5.\n"
+" REF: Side 99, del 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK PageSize\n"
+" REF: Sider 99–100, del 5.14.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK PaperDimension for PageSize %s\n"
+" REF: Side 41, del 5.\n"
+" REF: Side 103, del 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK Product\n"
+" REF: Side 62, del 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **FEIL** OBLIGATORISK ShortNickName\n"
+" REF: Sider 64–65, del 5.3.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " FANT %d FEIL\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " FANT INGEN FEIL\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " FEIL\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" FEIL\n"
+" **FEIL** Kan ikke åpne PPD-fil – %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" FEIL\n"
+" **FEIL** Kan ikke åpne PPD-fil – %s på linje %d.\n"
+
+msgid " PASS\n"
+msgstr " PASS\n"
+
+msgid "#10 Envelope"
+msgstr "#10-konvolutt"
+
+msgid "#11 Envelope"
+msgstr "#11-konvolutt"
+
+msgid "#12 Envelope"
+msgstr "#12-konvolutt"
+
+msgid "#14 Envelope"
+msgstr "#14-konvolutt"
+
+msgid "#9 Envelope"
+msgstr "#9-konvolutt"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f byte\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f byte\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f millimeter"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f til %.0f x %.0f millimeter"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f tommer"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f til %.2f x %.2f tommer"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s mottar forespørsler siden %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%s kan ikke endres."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s er ikke implementert av CUPS-versjonen av lpc.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s er ikke klar\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s er klar\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s er klar og skriver ut\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s mottar ikke forespørsler siden %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s mottar forespørsler siden %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s mottar ikke forespørsler siden %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [jobb %d lokal vert]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s mislyktes: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: Feil – ingen standardmål tilgjengelig.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: Feil – prioritet må være mellom 1 og 100.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: Feil – for mange filer – «%s»\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: Feil – får ikke tilgang til «%s» – %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s: Feil – kan ikke legge i kø fra stdin – %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: Filteret «%s» er ikke tilgjengelig: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: Ugyldig filterstreng «%s»\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: Handling mislyktes: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: Kan ikke koble til tjener\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: Kan ikke åpne %s: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: Kan ikke åpne PDF-fil: %s på linje %d\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: feil – ingen standardmål tilgjengelig.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 tomme/sek"
+
+msgid "1.25x0.25\""
+msgstr "1,25 x 0,25\""
+
+msgid "1.25x2.25\""
+msgstr "1,25 x 2,25\""
+
+msgid "1.5 inch/sec."
+msgstr "1,5 tommer/sek"
+
+msgid "1.50x0.25\""
+msgstr "1,50 x 0,25\""
+
+msgid "1.50x0.50\""
+msgstr "1,50 x 0,50\""
+
+msgid "1.50x1.00\""
+msgstr "1,50 x 1,00\""
+
+msgid "1.50x2.00\""
+msgstr "1,50 x 2,00\""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 tommer/sek"
+
+msgid "10 x 11\""
+msgstr "10 x 11\""
+
+msgid "10 x 13\""
+msgstr "10 x 13\""
+
+msgid "10 x 14\""
+msgstr "10 x 14\""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 mm/sek"
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 tommer/sek"
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 tommer/sek"
+
+msgid "12 x 11\""
+msgstr "12 x 11\""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 mm/sek"
+
+msgid "120x60dpi"
+msgstr "120 x 60 dpi"
+
+msgid "120x72dpi"
+msgstr "120 x 72 dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136 dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 mm/sek"
+
+msgid "15 x 11\""
+msgstr "15 x 11\""
+
+msgid "150 mm/sec."
+msgstr "150 mm/sek"
+
+msgid "150dpi"
+msgstr "150 dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180 dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 tommer/sek"
+
+msgid "2-Sided Printing"
+msgstr "Tosidig utskrift"
+
+msgid "2.00x0.37\""
+msgstr "2,00 x 0,37\""
+
+msgid "2.00x0.50\""
+msgstr "2,00 x 0,50\""
+
+msgid "2.00x1.00\""
+msgstr "2,00 x 1,00\""
+
+msgid "2.00x1.25\""
+msgstr "2,00 x 1,25\""
+
+msgid "2.00x2.00\""
+msgstr "2,00 x 2,00\""
+
+msgid "2.00x3.00\""
+msgstr "2,00 x 3,00\""
+
+msgid "2.00x4.00\""
+msgstr "2,00 x 4,00\""
+
+msgid "2.00x5.50\""
+msgstr "2,00 x 5,50\""
+
+msgid "2.25x0.50\""
+msgstr "2,25 x 0,50\""
+
+msgid "2.25x1.25\""
+msgstr "2,25 x 1,25\""
+
+msgid "2.25x4.00\""
+msgstr "2,25 x 4,00\""
+
+msgid "2.25x5.50\""
+msgstr "2,25 x 5,50\""
+
+msgid "2.38x5.50\""
+msgstr "2,38 x 5,50\""
+
+msgid "2.5 inches/sec."
+msgstr "2,5 tommer/sek"
+
+msgid "2.50x1.00\""
+msgstr "2,50 x 1,00\""
+
+msgid "2.50x2.00\""
+msgstr "2,50 x 2,00\""
+
+msgid "2.75x1.25\""
+msgstr "2,75 x 1,25\""
+
+msgid "2.9 x 1\""
+msgstr "2,9 x 1\""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 mm/sek"
+
+msgid "200 mm/sec."
+msgstr "200 mm/sek"
+
+msgid "203dpi"
+msgstr "203 dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "24-pinners serie"
+
+msgid "240x72dpi"
+msgstr "240 x 72 dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 mm/sek"
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 tommer/sek"
+
+msgid "3.00x1.00\""
+msgstr "3,00 x 1,00\""
+
+msgid "3.00x1.25\""
+msgstr "3,00 x 1,25\""
+
+msgid "3.00x2.00\""
+msgstr "3,00 x 2,00\""
+
+msgid "3.00x3.00\""
+msgstr "3,00 x 3,00\""
+
+msgid "3.00x5.00\""
+msgstr "3,00 x 5,00\""
+
+msgid "3.25x2.00\""
+msgstr "3,25 x 2,00\""
+
+msgid "3.25x5.00\""
+msgstr "3,25 x 5,00\""
+
+msgid "3.25x5.50\""
+msgstr "3,25 x 5,50\""
+
+msgid "3.25x5.83\""
+msgstr "3,25 x 5,83\""
+
+msgid "3.25x7.83\""
+msgstr "3,25 x 7,83\""
+
+msgid "3.5\" Disk"
+msgstr "3,5-tommers disk"
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "3,5-tommers disk – 2 1/8 x 2 3/4\""
+
+msgid "3.50x1.00\""
+msgstr "3,50 x 1,00\""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 mm/sek"
+
+msgid "300 mm/sec."
+msgstr "300 mm/sek"
+
+msgid "300dpi"
+msgstr "300 dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360 dpi"
+
+msgid "360x180dpi"
+msgstr "360 x 180 dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 tommer/sek"
+
+msgid "4.00x1.00\""
+msgstr "4,00 x 1,00\""
+
+msgid "4.00x13.00\""
+msgstr "4,00 x 13,00\""
+
+msgid "4.00x2.00\""
+msgstr "4,00 x 2,00\""
+
+msgid "4.00x2.50\""
+msgstr "4,00 x 2,50\""
+
+msgid "4.00x3.00\""
+msgstr "4,00 x 3,00\""
+
+msgid "4.00x4.00\""
+msgstr "4,00 x 4,00\""
+
+msgid "4.00x5.00\""
+msgstr "4,00 x 5,00\""
+
+msgid "4.00x6.00\""
+msgstr "4,00 x 6,00\""
+
+msgid "4.00x6.50\""
+msgstr "4,00 x 6,50\""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 mm/sek"
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 tommer/sek"
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 tommer/sek"
+
+msgid "6.00x1.00\""
+msgstr "6,00 x 1,00\""
+
+msgid "6.00x2.00\""
+msgstr "6,00 x 2,00\""
+
+msgid "6.00x3.00\""
+msgstr "6,00 x 3,00\""
+
+msgid "6.00x4.00\""
+msgstr "6,00 x 4,00\""
+
+msgid "6.00x5.00\""
+msgstr "6,00 x 5,00\""
+
+msgid "6.00x6.00\""
+msgstr "6,00 x 6,00\""
+
+msgid "6.00x6.50\""
+msgstr "6,00 x 6,50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/sek"
+
+msgid "600dpi"
+msgstr "600 dpi"
+
+msgid "60dpi"
+msgstr "60 dpi"
+
+msgid "60x720dpi"
+msgstr "60 x 720 dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 tommer/sek"
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720 dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 tommer/sek"
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8,00 x 1,00\""
+
+msgid "8.00x2.00\""
+msgstr "8,00 x 2,00\""
+
+msgid "8.00x3.00\""
+msgstr "8,00 x 3,00\""
+
+msgid "8.00x4.00\""
+msgstr "8,00 x 4,00\""
+
+msgid "8.00x5.00\""
+msgstr "8,00 x 5,00\""
+
+msgid "8.00x6.00\""
+msgstr "8,00 x 6,00\""
+
+msgid "8.00x6.50\""
+msgstr "8,00 x 6,50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/sek"
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 tommer/sek"
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "9-pinners serie"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?Ugyldig hjelpekommando ukjent\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (overdimensjonert)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (overdimensjonert)"
+
+msgid "A4 (Small)"
+msgstr "A4 (lite)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (overdimensjonert)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "Motta jobber"
+
+msgid "Accepted"
+msgstr "Mottatt"
+
+msgid "Add Class"
+msgstr "Legg til klasse"
+
+msgid "Add Printer"
+msgstr "Legg til skriver"
+
+msgid "Add RSS Subscription"
+msgstr "Legg til RSS-abonnement"
+
+msgid "Address"
+msgstr "Adresse"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "Adresse – 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "Administrering"
+
+msgid "Always"
+msgstr "Alltid"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "Applikator"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "Ugyldig NULL-målpeker"
+
+msgid "Bad OpenGroup"
+msgstr "Ugyldig OpenGroup"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "Ugyldig ad OpenUI/JCLOpenUI"
+
+msgid "Bad OrderDependency"
+msgstr "Ugyldig OrderDependency"
+
+msgid "Bad Request"
+msgstr "Ugyldig forespørsel"
+
+msgid "Bad SNMP version number"
+msgstr "Ugyldig SNMP-versjonsnummer"
+
+msgid "Bad UIConstraints"
+msgstr "Ugyldig UIConstraints"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Ugyldig kopiverdi %d."
+
+msgid "Bad custom parameter"
+msgstr "Ugyldig, tilpasset parameter"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Ugyldig fontattributt: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Ugyldig number-up-verdi %d."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Ugyldig page-ranges-verdier %d–%d."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Bannere"
+
+msgid "Billing Information: "
+msgstr "Faktureringsinformasjon: "
+
+msgid "Bond Paper"
+msgstr "Tykt papir"
+
+msgid "C0 Envelope"
+msgstr "C0-konvolutt"
+
+msgid "C1 Envelope"
+msgstr "C1-konvolutt"
+
+msgid "C2 Envelope"
+msgstr "C2-konvolutt"
+
+msgid "C3 Envelope"
+msgstr "C3-konvolutt"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "C4-konvolutt"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "C5-konvolutt"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "C6-konvolutt"
+
+msgid "C65 Envelope"
+msgstr "C65-konvolutt"
+
+msgid "C7 Envelope"
+msgstr "C7-konvolutt"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "CPCL-etikettskriver"
+
+msgid "Cancel RSS Subscription"
+msgstr "Avbryt RSS-abonnement"
+
+msgid "Change Settings"
+msgstr "Endre innstillinger"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Chou3-konvolutt"
+
+msgid "Chou4 Envelope"
+msgstr "Chou4-konvolutt"
+
+msgid "Classes"
+msgstr "Klasser"
+
+msgid "Clean Print Heads"
+msgstr "Rengjør skrivehoder"
+
+msgid "Color"
+msgstr "Farge"
+
+msgid "Color Mode"
+msgstr "Fargemodus"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"Kommandoer kan være forkortet. Kommandoer er :\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "Gruppenavn bruker uendelig lengde"
+
+msgid "Continue"
+msgstr "Fortsett"
+
+msgid "Continuous"
+msgstr "Kontinuerlig"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Opprettet"
+
+msgid "Created On: "
+msgstr "Opprettet på: "
+
+msgid "Custom"
+msgstr "Tilpasset"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Klipp"
+
+msgid "Cutter"
+msgstr "Kutter"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "DL-konvolutt"
+
+msgid "Dark"
+msgstr "Mørk"
+
+msgid "Darkness"
+msgstr "Mørkhet"
+
+msgid "Delete Class"
+msgstr "Slett klasse"
+
+msgid "Delete Printer"
+msgstr "Slett skriver"
+
+msgid "Description: "
+msgstr "Beskrivelse: "
+
+msgid "DeskJet Series"
+msgstr "DeskJet-serie"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "Målet «%s» mottar ikke jobber."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"Enhet: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "Direkte varme-medium"
+
+msgid "Disabled"
+msgstr "Deaktivert"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "Fant ikke dokumentet %d i jobben %d."
+
+msgid "Double Postcard"
+msgstr "Dobbelt postkort"
+
+msgid "Driver Name: "
+msgstr "Drivernavn: "
+
+msgid "Driver Version: "
+msgstr "Driverversjon: "
+
+msgid "Duplexer"
+msgstr "Duplekser"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: Kan ikke tildele hukommelse for sideinfo: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: Kan ikke tildele hukommelse for sidesett: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "EPL1-etikettskriver"
+
+msgid "EPL2 Label Printer"
+msgstr "EPL2-etikettskriver"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: Ugyldig tegnsettfil %s\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: Ugyldig tegnsettype %s\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: Ugyldig fontbeskrivelseslinje: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: Ugyldig tekstretning %s\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: Ugyldig tekstbredde %s\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: Feil %d ved sending av PAPSendData-forespørsel: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: Ingen fonter i tegnsettfil %s\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: Skriver svarer ikke\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: Skriver sendte uventet EOF\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: Ekstern vert godtok ikke kontrollfil (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: Ekstern vert godtok ikke datafil (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr ""
+"ERROR: Det oppsto en tidsavbruddfeil under sending av data til skriveren\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: Kan ikke legge til filen %d i jobb: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: Kan ikke avbryte jobb %d: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: Kan ikke kopiere PDF-fil"
+
+msgid "ERROR: Unable to create pipe"
+msgstr ""
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: Kan ikke opprette socket"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr "ERROR: Kan ikke opprette midlertidig, komprimert utskriftsfil: %s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: Kan ikke opprette midlertidig fil"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: Kan ikke utføre pictwpstops: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: Kan ikke utføre gs-program"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: Kan ikke utføre pdftops-program"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: Kan ikke forgrene pictwpstops: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: Kan ikke hente PAP-forespørsel"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: Kan ikke hente PAP-svar"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr "ERROR: Kan ikke hente PPD-fil for skriveren «%s» – %s.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: Kan ikke hente standard AppleTalk-sone"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: Kan ikke søke etter PAP-svar"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: Kan ikke søke etter AppleTalk-skrivere"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: Kan ikke lage AppleTalk-adresse"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: Kan ikke åpne «%s» – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: Kan ikke åpne %s: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: Kan ikke åpne bannerfilen «%s» – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: Kan ikke åpne enhetsfilen «%s»: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: Kan ikke åpne filen «%s» – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: Kan ikke åpne filen «%s»: %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: Kan ikke åpne utskriftsfilen «%s»: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: Kan ikke åpne utskriftsfilen %s – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: Kan ikke åpne utskriftsfilen %s: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr "ERROR: Kan ikke åpne midlertidig, komprimert utskriftsfil: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: Kan ikke lese utskriftsdata"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: Kan ikke reservere port"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: Kan ikke søke for å forskyve %ld i fil – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: Kan ikke søke for å forskyve %lld i fil – %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: Kan ikke sende LPD-kommando"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: Kan ikke sende PAP-tickleforespørsel"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: Kan ikke sende innledende PAP-forespørsel om sending av data"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: Kan ikke sende utskriftsfil til skriver"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: Kan ikke sende «trailing nul» til skriver"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: Kan ikke vente på pictwpstops: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: Kan ikke skrive %d byte til «%s»: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: Kan ikke skrive kontrollfil"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: Kan ikke skrive utskriftsdata"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: Kan ikke skrive utskriftsdata: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr "ERROR: Kan ikke skrive ukomprimert dokumentdata: %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: Ukjent filrekkefølge «%s»\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: Ukjent formattegn «%c»\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: Ukjent utskriftsmodus «%s»\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: select() mislyktes"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: kan ikke statte utskriftsfilen"
+
+msgid "Edit Configuration File"
+msgstr "Rediger konfigurasjonsfil"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Sluttbanner"
+
+msgid "English"
+msgstr "Norwegian"
+
+msgid "Enter old password:"
+msgstr "Oppgi det gamle passordet:"
+
+msgid "Enter password again:"
+msgstr "Oppgi passordet igjen:"
+
+msgid "Enter password:"
+msgstr "Oppgi passordet:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Oppgi brukernavnet og passordet ditt eller rotbrukernavnet og -passordet for "
+"å få tilgang til denne siden. Hvis du bruker Kerberos-godkjenning, forsikrer "
+"du deg om at du har en gyldig Kerberos-billett."
+
+msgid "Envelope Feed"
+msgstr "Konvoluttmating"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Feilkriterier"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "Hver 10. etikett"
+
+msgid "Every 2 Labels"
+msgstr "Hver 2. etikett"
+
+msgid "Every 3 Labels"
+msgstr "Hver 3. etikett"
+
+msgid "Every 4 Labels"
+msgstr "Hver 4. etikett"
+
+msgid "Every 5 Labels"
+msgstr "Hver 5. etikett"
+
+msgid "Every 6 Labels"
+msgstr "Hver 6. etikett"
+
+msgid "Every 7 Labels"
+msgstr "Hver 7. etikett"
+
+msgid "Every 8 Labels"
+msgstr "Hver 8. etikett"
+
+msgid "Every 9 Labels"
+msgstr "Hver 9. etikett"
+
+msgid "Every Label"
+msgstr "Hver etikett"
+
+msgid "Expectation Failed"
+msgstr "Forventning mislyktes"
+
+msgid "Export Printers to Samba"
+msgstr "Eksporter skrivere til Samba"
+
+msgid "FAIL\n"
+msgstr "FEIL\n"
+
+msgid "File Folder"
+msgstr "Filmappe"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Filmappe – 9/16 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"Enhets-URIer for filer er deaktivert! Hvis du vil aktivere funksjonen, leser "
+"du FileDevice-direktivet i «%s/cupsd.conf»."
+
+msgid "Folio"
+msgstr "Folio"
+
+msgid "Forbidden"
+msgstr "Forbudt"
+
+msgid "General"
+msgstr "Generelt"
+
+msgid "Generic"
+msgstr "Generisk"
+
+msgid "German FanFold"
+msgstr "Tysk FanFold"
+
+msgid "German FanFold Legal"
+msgstr "Tysk FanFold Legal"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU bruker uendelig lengde"
+
+msgid "Glossy Paper"
+msgstr "Glanset papir"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Gråskala"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Hengende mappe"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Hengende mappe – 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk deaktivert i Systemvalg\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk deaktivert i Systemvalg.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: Avbryter utskriftsjobb...\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: Koblet til skriver...\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: Kobler til skriver...\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: Kontrollfil sendt\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr ""
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: Datafil sendt\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: Formaterer side %d...\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: Laster inn bildefil...\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: Søker etter skriver...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: Ã…pner forbindelse\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr "INFO: Utskriftsfil sendt, venter på at skriveren skal bli ferdig...\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: Skriveren er opptatt. Prøver på nytt om 10 sekunder...\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: Skriveren er opptatt. Prøver på nytt om 30 sekunder...\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: Skriveren er opptatt. Prøver på nytt om 5 sekunder...\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr "INFO: Skriveren støtter ikke IPP/%d.%d, prøver IPP/1.0...\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: Skriveren er opptatt. Prøver på nytt om 5 sekunder...\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: Skriveren er ikke tilgjengelig.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: Skriveren er ikke tilgjengelig.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: Skriveren er tilgjengelig.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: Skriveren er ikke tilgjengelig.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr ""
+"INFO: Skriveren er ikke tilgjengelig. Prøver på nytt om 30 sekunder...\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: Skriver ut side %d, %d%% fullført...\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: Skriver ut side %d...\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: Klar til utskrift.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: Sender kontrollfil (%lu byte)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: Sender kontrollfil (%u byte)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: Sender data\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: Sender datafil (%ld byte)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: Sender datafil (%lld byte)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: Sender utskriftsdata...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: Utskriftsfil sendt, %ld byte...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: Utskriftsfil sendt, %lld byte...\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: Legger LPR-jobb i utskriftskø, %.0f%% fullført...\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr ""
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: Får ikke kontakt med skriver, legger i kø på neste skriver i "
+"klassen...\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: Bruker standard AppleTalk-sone «%s»\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: Venter på at jobben skal bli ferdig...\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: Venter på at skriveren skal bli tilgjengelig...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "ISO B4-konvolutt"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (overdimensjonert)"
+
+msgid "ISO B5 Envelope"
+msgstr "ISO B5-konvolutt"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "ISO B6-konvolutt"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "Ulovlig kontrolltegn"
+
+msgid "Illegal main keyword string"
+msgstr "Ulovlig streng for hovednøkkelord"
+
+msgid "Illegal option keyword string"
+msgstr "Ulovlig streng for valgnøkkelord"
+
+msgid "Illegal translation string"
+msgstr "Ulovlig oversettelsesstreng"
+
+msgid "Illegal whitespace character"
+msgstr "Ulovlig mellomromstegn"
+
+msgid "Installable Options"
+msgstr "Installerbare valg"
+
+msgid "Installed"
+msgstr "Installert"
+
+msgid "IntelliBar Label Printer"
+msgstr "IntelliBar-etikettskriver"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr ""
+
+msgid "Internal error"
+msgstr "Intern feil"
+
+msgid "Internet Postage 2-Part"
+msgstr "Internet Postage 2 deler"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Internet Postage 2 deler – 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "Internet Postage 3 deler"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Internet Postage 3 deler – 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "Internett-utskriftsprotokoll"
+
+msgid "Invite Envelope"
+msgstr "Invitasjonskonvolutt"
+
+msgid "Italian Envelope"
+msgstr "Italiensk konvolutt"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "Jobb nr. %d er allerede kansellert – kan ikke avbryte."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "Jobb nr. %d er allerede avbrutt – kan ikke avbryte."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "Jobb nr. %d er allerede fullført – kan ikke avbryte."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "Jobb fullført"
+
+msgid "Job Created"
+msgstr "Jobb opprettet"
+
+msgid "Job ID: "
+msgstr "Jobb-ID: "
+
+msgid "Job Options Changed"
+msgstr "Jobbvalg endret"
+
+msgid "Job Stopped"
+msgstr "Jobb stoppet"
+
+msgid "Job UUID: "
+msgstr "Jobb-UUID: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "Jobben er fullført og kan ikke endres."
+
+msgid "Job operation failed:"
+msgstr "Jobbhandling mislyktes:"
+
+msgid "Job state cannot be changed."
+msgstr "Jobbstatus kan ikke endres."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "Jobber"
+
+msgid "Kaku2 Envelope"
+msgstr "Kaku2-konvolutt"
+
+msgid "Kaku3 Envelope"
+msgstr "Kaku3-konvolutt"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "LPD/LPR-vert eller -skriver"
+
+msgid "Label Printer"
+msgstr "Etikettskriver"
+
+msgid "Label Top"
+msgstr "Etikettopp"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Stor adresse"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Stor adresse – 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet-serie PCL 4/5"
+
+msgid "Light"
+msgstr "Lys"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Linjen er lengre enn det som er tillatt (255 tegn)"
+
+msgid "List Available Printers"
+msgstr "Vis tilgjengelige skrivere"
+
+msgid "Location: "
+msgstr "Plassering: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "Langside (stående)"
+
+msgid "Make and Model: "
+msgstr "Merke og modell: "
+
+msgid "Manual Feed"
+msgstr "Manuell mating"
+
+msgid "Media Dimensions: "
+msgstr "Mediestørrelse: "
+
+msgid "Media Limits: "
+msgstr "Mediebegrensninger: "
+
+msgid "Media Name: "
+msgstr "Medienavn: "
+
+msgid "Media Size"
+msgstr "Papirstørrelse"
+
+msgid "Media Source"
+msgstr "Papirkilde"
+
+msgid "Media Tracking"
+msgstr "Mediesporing"
+
+msgid "Media Type"
+msgstr "Papirtype"
+
+msgid "Medium"
+msgstr "Medium"
+
+msgid "Memory allocation error"
+msgstr "Feil med hukommelsestildeling"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "PPD-Adobe-4.x-header mangler"
+
+msgid "Missing asterisk in column 1"
+msgstr "Stjerne mangler i kolonne 1"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "Verdistreng mangler"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Modell: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "Endre klasse"
+
+msgid "Modify Printer"
+msgstr "Endre skriver"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Monarch-konvolutt"
+
+msgid "Move All Jobs"
+msgstr "Flytt alle jobber"
+
+msgid "Move Job"
+msgstr "Flytt jobb"
+
+msgid "Moved Permanently"
+msgstr "Flyttet permanent"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: Utskriftsfil godtatt – jobb-ID %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: Utskriftsfil godtatt – jobb-ID ukjent.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "NULL PPD-filpeker"
+
+msgid "Name OID uses indefinite length"
+msgstr "Navn-OID bruker uendelig lengde"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Aldri"
+
+msgid "New Stylus Color Series"
+msgstr "Ny Stylus Color-serie"
+
+msgid "New Stylus Photo Series"
+msgstr "Ny Stylus Photo-serie"
+
+msgid "No"
+msgstr "Nei"
+
+msgid "No Content"
+msgstr "Uten innhold"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "Ingen VarBind SEQUENCE"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "Ingen aktive tilkoblinger"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "Ingen gruppenavn"
+
+msgid "No default printer"
+msgstr "Ingen standardskriver"
+
+msgid "No destinations added."
+msgstr "Ingen mål lagt til."
+
+msgid "No error-index"
+msgstr "Ingen error-index"
+
+msgid "No error-status"
+msgstr "Ingen error-status"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "Uten navn-OID"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "Ingen request-id"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "Fant ingen abonnementer."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "Ingen variable-bindings SEQUENCE"
+
+msgid "No version number"
+msgstr "Uten versjonsnummer"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "Ikke fortløpende (merkeregistrering)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "Ikke fortløpende (webregistrering)"
+
+msgid "Normal"
+msgstr "Vanlig"
+
+msgid "Not Found"
+msgstr "Ikke funnet"
+
+msgid "Not Implemented"
+msgstr "Ikke implementert"
+
+msgid "Not Installed"
+msgstr "Ikke installert"
+
+msgid "Not Modified"
+msgstr "Ikke modifisert"
+
+msgid "Not Supported"
+msgstr "Ikke støttet"
+
+msgid "Not allowed to print."
+msgstr "Utskrift ikke tillatt."
+
+msgid "Note"
+msgstr "Merk"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Off (1-Sided)"
+msgstr "Av (énsidig)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Internett-basert hjelp"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "Ã…pning av %s mislyktes: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup uten CloseGroup først"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI uten CloseUI/JCLCloseUI først"
+
+msgid "Operation Policy"
+msgstr "Handlingskriterier"
+
+msgid "Options Installed"
+msgstr "Valg installert"
+
+msgid "Options: "
+msgstr "Valg: "
+
+msgid "Output Mode"
+msgstr "Utdatamodus"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "Utdata for skriveren %s er sendt til %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr "Utdata for skriveren %s er sendt til den eksterne skriveren %s på %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "Utdata for skriveren %s/%s er sendt til %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr ""
+"Utdata for skriveren %s/%s er sendt til den eksterne skriveren %s på %s\n"
+
+msgid "PASS\n"
+msgstr "PASS\n"
+
+msgid "PCL Laser Printer"
+msgstr "PCL-laserskriver"
+
+msgid "PRC1 Envelope"
+msgstr "PRC1-konvolutt"
+
+msgid "PRC10 Envelope"
+msgstr "PRC10-konvolutt"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "PRC2-konvolutt"
+
+msgid "PRC3 Envelope"
+msgstr "PRC3-konvolutt"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (overdimensjonert)"
+
+msgid "PRC4 Envelope"
+msgstr "PRC4-konvolutt"
+
+msgid "PRC5 Envelope"
+msgstr "PRC5-konvolutt"
+
+msgid "PRC6 Envelope"
+msgstr "PRC6-konvolutt"
+
+msgid "PRC7 Envelope"
+msgstr "PRC7-konvolutt"
+
+msgid "PRC8 Envelope"
+msgstr "PRC8-konvolutt"
+
+msgid "PRC9 Envelope"
+msgstr "PRC9-konvolutt"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "Pakken inneholder ikke en Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "Pakken begynner ikke med SEQUENCE"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "Passord for %s på %s? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "Passord for %s kreves for å få tilgang til %s via SAMBA: "
+
+msgid "Pause Class"
+msgstr "Sett klasse på pause"
+
+msgid "Pause Printer"
+msgstr "Sett skriver på pause"
+
+msgid "Peel-Off"
+msgstr "Fjern papir"
+
+msgid "Personal Envelope"
+msgstr "Personlig konvolutt"
+
+msgid "Photo"
+msgstr "Foto"
+
+msgid "Photo Labels"
+msgstr "Fotoetiketter"
+
+msgid "Plain Paper"
+msgstr "Vanlig papir"
+
+msgid "Policies"
+msgstr "Kriterier"
+
+msgid "Port Monitor"
+msgstr "Portovervåking"
+
+msgid "PostScript Printer"
+msgstr "PostScript-skriver"
+
+msgid "Postcard"
+msgstr "Postkort"
+
+msgid "Print Density"
+msgstr "Utskriftstetthet"
+
+msgid "Print Job:"
+msgstr "Utskriftsjobb:"
+
+msgid "Print Mode"
+msgstr "Utskriftsmodus"
+
+msgid "Print Rate"
+msgstr "Utskriftshastighet"
+
+msgid "Print Self-Test Page"
+msgstr "Skriv ut testside"
+
+msgid "Print Speed"
+msgstr "Utskriftshastighet"
+
+msgid "Print Test Page"
+msgstr "Skriv ut testside"
+
+msgid "Print and Cut"
+msgstr "Skriv ut og klipp"
+
+msgid "Print and Tear"
+msgstr "Skriv ut og riv"
+
+msgid "Printed For: "
+msgstr "Skrevet ut for: "
+
+msgid "Printed From: "
+msgstr "Skrevet ut fra: "
+
+msgid "Printed On: "
+msgstr "Skrevet ut på: "
+
+msgid "Printer Added"
+msgstr "Skriver lagt til"
+
+msgid "Printer Default"
+msgstr "Skriverstandard"
+
+msgid "Printer Deleted"
+msgstr "Skriver slettet"
+
+msgid "Printer Modified"
+msgstr "Skriver endret"
+
+msgid "Printer Name: "
+msgstr "Skrivernavn: "
+
+msgid "Printer Paused"
+msgstr "Skriver satt på pause"
+
+msgid "Printer Settings"
+msgstr "Skriverinnstillinger"
+
+msgid "Printer:"
+msgstr "Skriver:"
+
+msgid "Printers"
+msgstr "Skrivere"
+
+msgid "Purge Jobs"
+msgstr "Tøm jobber"
+
+msgid "Quarto"
+msgstr "Quarto"
+
+msgid "Quota limit reached."
+msgstr "Begrensning nådd."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr ""
+"Rangering Eier Jobb Fil(er) Samlet "
+"størrelse\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"Rangering Eier Prioritet Jobb Filer "
+"Samlet størrelse\n"
+
+msgid "Reject Jobs"
+msgstr "Avslå jobber"
+
+msgid "Reprint After Error"
+msgstr "Skriv ut på nytt etter feil"
+
+msgid "Request Entity Too Large"
+msgstr "Forespørselsobjektet er for stort"
+
+msgid "Resolution"
+msgstr "Oppløsning"
+
+msgid "Resume Class"
+msgstr "Fortsett med klasse"
+
+msgid "Resume Printer"
+msgstr "Fortsett med skriver"
+
+msgid "Return Address"
+msgstr "Avsenderadresse"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Avsenderadresse – 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "Spol tilbake"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Utfører kommando: %s %s -N -A %s -c «%s»\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE bruker uendelig lengde"
+
+msgid "See Other"
+msgstr "Se andre"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "Serieport nr. %d"
+
+msgid "Server Restarted"
+msgstr "Tjener startet på nytt"
+
+msgid "Server Security Auditing"
+msgstr "Sikkerhetsgjennomgang for tjener"
+
+msgid "Server Started"
+msgstr "Tjener startet"
+
+msgid "Server Stopped"
+msgstr "Tjener stoppet"
+
+msgid "Service Unavailable"
+msgstr "Tjeneste ikke tilgjengelig"
+
+msgid "Set Allowed Users"
+msgstr "Angi tillatte brukere"
+
+msgid "Set As Server Default"
+msgstr "Bruk som tjenerstandard"
+
+msgid "Set Class Options"
+msgstr "Angi klassevalg"
+
+msgid "Set Printer Options"
+msgstr "Angi skrivervalg"
+
+msgid "Set Publishing"
+msgstr "Angi publisering"
+
+msgid "Shipping Address"
+msgstr "Leveringsadresse"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "Leveringsadresse – 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "Kortside (liggende)"
+
+msgid "Special Paper"
+msgstr "Spesialpapir"
+
+msgid "Standard"
+msgstr "Standard"
+
+msgid "Starting Banner"
+msgstr "Startbanner"
+
+msgid "Statement"
+msgstr "Melding"
+
+msgid "Stylus Color Series"
+msgstr "Stylus Color-serie"
+
+msgid "Stylus Photo Series"
+msgstr "Stylus Photo-serie"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "Bytter protokoll"
+
+msgid "Tabloid"
+msgstr "Tabloid"
+
+msgid "Tabloid (Oversize)"
+msgstr "Tabloid (overdimensjonert)"
+
+msgid "Tear"
+msgstr "Riv"
+
+msgid "Tear-Off"
+msgstr "Riv av"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Riv av, juster plassering"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "Fant ikke PPD-filen «%s»."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "Kunne ikke åpne PPD-filen «%s»: %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Klassenavnet kan kun inneholde opptil 127 tegn som kan skrives ut, og kan "
+"ikke inneholde mellomrom, skråstrek (/) eller firkanttegn (#)."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+"Notify-lease-duration-attributtet kan ikke brukes med jobbabonnementer."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Skrivernavnet kan kun inneholde opptil 127 tegn som kan skrives ut, og kan "
+"ikke inneholde mellomrom, skråstrek (/) eller firkanttegn (#)."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "Fant ikke skriveren eller klassen."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "Printer-uri «%s» inneholder ugyldige tegn."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr "Printer-uri må ha formatet «ipp://VERTSNAVN/klasser/KLASSENAVN»."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr "Printer-uri må ha formatet «ipp://VERTSNAVN/skrivere/SKRIVERNAVN»."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"Abonnementsnavnet kan ikke inneholde mellomrom, skråstrek (/), spørsmålstegn "
+"(?) eller firkanttegn (#)."
+
+msgid "There are too many subscriptions."
+msgstr "For mange abonnementer."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "Varmeoverføringsmedium"
+
+msgid "Title: "
+msgstr "Tittel: "
+
+msgid "Too many active jobs."
+msgstr "For mange aktive jobber."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "Gjennomsiktighet"
+
+msgid "Tray"
+msgstr "Skuff"
+
+msgid "Tray 1"
+msgstr "Skuff 1"
+
+msgid "Tray 2"
+msgstr "Skuff 2"
+
+msgid "Tray 3"
+msgstr "Skuff 3"
+
+msgid "Tray 4"
+msgstr "Skuff 4"
+
+msgid "URI Too Long"
+msgstr "URI for lang"
+
+msgid "US Executive"
+msgstr "US Executive"
+
+msgid "US Fanfold"
+msgstr "US Fanfold"
+
+msgid "US Ledger"
+msgstr "US Ledger"
+
+msgid "US Legal"
+msgstr "US Legal"
+
+msgid "US Legal (Oversize)"
+msgstr "US Legal (overdimensjonert)"
+
+msgid "US Letter"
+msgstr "US Letter"
+
+msgid "US Letter (Oversize)"
+msgstr "US Letter (overdimensjonert)"
+
+msgid "US Letter (Small)"
+msgstr "US Letter (lite)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "USB-serieport nr. %d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "FÃ¥r ikke tilgang til cupsd.conf-fil:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "Kan ikke legge til RSS-abonnement:"
+
+msgid "Unable to add class:"
+msgstr "Kan ikke legge til klasse:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "Kan ikke legge til skriver:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "Kan ikke avslutte RSS-abonnement:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "Kan ikke endre printer-is-shared-attributt:"
+
+msgid "Unable to change printer:"
+msgstr "Kan ikke endre skriver:"
+
+msgid "Unable to change server settings:"
+msgstr "Kan ikke endre tjenerinnstillinger:"
+
+msgid "Unable to connect to host."
+msgstr "Kan ikke koble til vert"
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "Kan ikke opprette midlertidig fil:"
+
+msgid "Unable to delete class:"
+msgstr "Kan ikke slette klasse:"
+
+msgid "Unable to delete printer:"
+msgstr "Kan ikke slette skriver:"
+
+msgid "Unable to do maintenance command:"
+msgstr "Kan ikke utføre vedlikeholdskommando:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "Kan ikke hente klasseliste:"
+
+msgid "Unable to get class status:"
+msgstr "Kan ikke hente klassestatus:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "Kan ikke hente liste over skriverdrivere:"
+
+msgid "Unable to get printer attributes:"
+msgstr "Kan ikke hente skriverattributter:"
+
+msgid "Unable to get printer list:"
+msgstr "Kan ikke hente skriverliste:"
+
+msgid "Unable to get printer status:"
+msgstr "Kan ikke hente skriverstatus:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "Kan ikke endre klasse:"
+
+msgid "Unable to modify printer:"
+msgstr "Kan ikke endre skriver:"
+
+msgid "Unable to move job"
+msgstr "Kan ikke flytte jobb"
+
+msgid "Unable to move jobs"
+msgstr "Kan ikke flytte jobber"
+
+msgid "Unable to open PPD file"
+msgstr "Kan ikke åpne PPD-fil"
+
+msgid "Unable to open PPD file:"
+msgstr "Kan ikke åpne PPD-fil:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "Kan ikke åpne cupsd.conf-fil:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "Kan ikke skrive ut testside:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "Kan ikke starte «%s»: %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "Kan ikke angi valg:"
+
+msgid "Unable to set server default:"
+msgstr "Kan ikke angi tjenerstandard:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "Kan ikke laste opp cupsd.conf-fil:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "Uautorisert"
+
+msgid "Units"
+msgstr "Enheter"
+
+msgid "Unknown"
+msgstr "Ukjent"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "Ukjent printer-error-policy «%s»."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "Ukjent printer-op-policy «%s»."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Verditypen støttes ikke"
+
+msgid "Upgrade Required"
+msgstr "Oppgradering kreves"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Bruk:\n"
+"\n"
+" lpadmin [-h tjener] -d mål\n"
+" lpadmin [-h tjener] -x mål\n"
+" lpadmin [-h tjener] -p skriver [-c legg til klasse] [-i grensesnitt] [-m "
+"modell]\n"
+" [-r fjern klasse] [-v enhet] [-D beskrivelse]\n"
+" [-P ppd-fil] [-o navn=verdi]\n"
+" [-u tillat:bruker,bruker] [-u avslå:bruker,bruker]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "Bruk: %s jobb-id bruker tittel kopier valg [filnavn]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "Bruk: %s jobb-id bruker tittel kopier valg [fil]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "Bruk: %s jobb-id bruker tittel kopier valg fil\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Bruk: cupsaddsmb [valg] printer1 ... printerN\n"
+" cupsaddsmb [valg] -a\n"
+"\n"
+"Valg:\n"
+" -E Krypter forbindelsen til tjeneren\n"
+" -H samba-tjener Bruk den angitte SAMBA-tjeneren\n"
+" -U samba-bruker Godkjenn ved hjelp av den angitte SAMBA-brukeren\n"
+" -a Eksporter alle skrivere\n"
+" -h cups-tjener Bruk den angitte CUPS-tjeneren\n"
+" -v Vær detaljert (vis kommandoer)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Bruk: cupsctl [valg] [param=value ... paramN=valueN]\n"
+"\n"
+"Valg:\n"
+"\n"
+" -E Aktiver kryptering\n"
+" -U brukernavn Angi brukernavn\n"
+" -h tjener[:port] Angi tjeneradresse\n"
+"\n"
+" --[no-]debug-logging Aktiver eller deaktiver feilsøkingslogging\n"
+" --[no-]remote-admin Aktiver eller deaktiver ekstern administrering\n"
+" --[no-]remote-any Tillat eller forhindre tilgang fra Internett\n"
+" --[no-]remote-printers Vis eller skjul eksterne skrivere\n"
+" --[no-]share-printers Aktiver eller deaktiver skriverdeling\n"
+" --[no-]user-cancel-any Tillat eller forhindre at brukere kan avbryte en "
+"hvilken som helst jobb\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Bruk: cupsd [-c konfigurasjonsfil] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c konfigurasjonsfil Last inn alternativ konfigurasjonsfil\n"
+"-f Kjør i forgrunnen\n"
+"-F Kjør i forgrunnen, men skill\n"
+"-h Vis denne bruksmeldingen\n"
+"-l Kjør cupsd fra launchd(8)\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Bruk: cupstestdsc [valg] filename.ps [... filename.ps]\n"
+" cupstestdsc [valg] -\n"
+"\n"
+"Valg:\n"
+"\n"
+" -h Vis programbruk\n"
+"\n"
+" Merk: dette programmet validerer DSC-kommentarer, ikke selve PostScript-"
+"innholdet.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Bruk: lpmove job/src dest\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Bruk: lpoptions [-h tjener] [-E] -d skriver\n"
+" lpoptions [-h tjener] [-E] [-p skriver] -l\n"
+" lpoptions [-h tjener] [-E] -p skriver -o valg[=verdi] ...\n"
+" lpoptions [-h tjener] [-E] -x skriver\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Bruk: lppasswd [-g gruppenavn]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Bruk: lppasswd [-g gruppenavn] [brukernavn]\n"
+" lppasswd [-g gruppenavn] -a [brukernavn]\n"
+" lppasswd [-g gruppenavn] -x [brukernavn]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Bruk: lpq [-P mål] [-U brukernavn] [-h vertsnavn[:port]] [-l] [+intervall]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Bruk: ppdc [valg] filename.drv [ ... filenameN.drv ]\n"
+"Valg:\n"
+" -D navn=verdi Bruk verdi for angitt variabel.\n"
+" -I include-dir Legg til inkluderingskatalog i søkebane.\n"
+" -c catalog.po Last inn angitt meldingskatalog.\n"
+" -d output-dir Angi utdatakatalog.\n"
+" -l lang[,lang,...] Angi utdataspråk (nasjonal innstilling).\n"
+" -m Bruk ModelName-verdi som filnavn.\n"
+" -t Test PPD-er i stedet for å generere dem.\n"
+" -v Vær detaljert (flere v-er gir høyere detaljnivå).\n"
+" -z Komprimer PPD-filer ved hjelp av GNU zip.\n"
+" --cr Bruk CR-linjeskift (Mac OS 9).\n"
+" --crlf Bruk CR + LF-linjeskift (Windows).\n"
+" --lf Bruk LF-linjeskift (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"Bruk: ppdhtml [valg] filename.drv >filename.html\n"
+" -D navn=verdi Bruk verdi for angitt variabel.\n"
+"Valg:\n"
+" -I include-dir Legg til inkluderingskatalog i søkebane.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Bruk: ppdi [valg] filename.ppd [ ... filenameN.ppd ]\n"
+"Valg:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Bruk: ppdmerge [valg] filename.ppd [ ... filenameN.ppd ]\n"
+"Valg:\n"
+" -o filename.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"Bruk: ppdpo [valg] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Valg:\n"
+" -D navn=verdi Bruk verdi for angitt variabel.\n"
+" -I include-dir Legg til inkluderingskatalog i søkebane.\n"
+" -v Vær detaljert (flere v-er gir høyere detaljnivå).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Bruk: snmp [vert eller ip-adresse]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Verdi bruker uendelig lengde"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind bruker uendelig lengde"
+
+msgid "Version uses indefinite length"
+msgstr "Versjon bruker uendelig lengde"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: Legger til kun de %d første skriverne som ble funnet"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: Boolsk forventet for waiteof-valget «%s»\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: Skriver svarer ikke\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: Skriver sendte uventet EOF\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: Kan ikke åpne «%s:%s»: %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: Kan ikke sende PAP-statusforespørsel"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: Uventet PAP-pakke av typen %d\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: Ukjent PAP-pakke av typen %d\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: tall forventet for statusvalget «%s»\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Ja"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"Du må få tilgang til denne siden ved hjelp av URLen <A HREF=\"https://%s:%d%s"
+"\">https://%s:%d%s</A>."
+
+msgid "You4 Envelope"
+msgstr "You4-konvolutt"
+
+msgid "ZPL Label Printer"
+msgstr "ZPL-etikettskriver"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "kansellert"
+
+msgid "canceled"
+msgstr "avbrutt"
+
+msgid "completed"
+msgstr "fullført"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr "konverter: Bruk valget -f for å angi en fil som skal konverteres.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "cups-deviced ble ikke utført."
+
+msgid "cups-driverd failed to execute."
+msgstr "cups-driverd ble ikke utført."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: Ingen PPD-fil for skriveren «%s» – %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: Kan ikke koble til tjener: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr "cupsd: launchd(8)-støtte er ikke kompilert inn, bruker vanlig modus.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: Kan ikke hente jobbfil – %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd: Valget -q er ikke kompatibelt med valget -v.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd: Valget -v er ikke kompatibelt med valget -q.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "enhet for %s/%s: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "enhet for %s: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "error-index bruker uendelig lengde"
+
+msgid "error-status uses indefinite length"
+msgstr "error-status bruker uendelig lengde"
+
+msgid "held"
+msgstr "holdt"
+
+msgid "help\t\tget help on commands\n"
+msgstr "hjelp\t\thent hjelp ved kommandoer\n"
+
+msgid "idle"
+msgstr "inaktiv"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: Skriveren %s er allerede medlem av klassen %s.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: Skriveren %s er ikke medlem av klassen %s.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: Kan ikke koble til tjener: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: Kan ikke åpne PPD-filen «%s» – %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: Kan ikke åpne filen «%s»: %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: Kan ikke koble til tjener: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: Kan ikke legge til skriver eller forekomst: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: Kan ikke hente PPD-fil for %s: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: Beklager. Passordet ble ikke godtatt.\n"
+"Passordet må være på minst 6 tegn og kan ikke inneholde\n"
+"brukernavet ditt. Det må også inneholde must én bokstav og ett tall.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: Kan ikke kopiere passordstreng: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: Kan ikke åpne passordfil: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: Kan ikke skrive til passordfil: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr "lppasswd: kunne ikke sikkerhetskopiere gammel passordfil: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: kunne ikke endre navn på passordfil: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: brukeren «%s» og gruppen «%s» finnes ikke.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "medlemmer av klassen %s:\n"
+
+msgid "no entries\n"
+msgstr "ingen oppføringer\n"
+
+msgid "no system default destination\n"
+msgstr "ingen standardmål for system\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "ventende"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: Legger til inkluderingskatalog «%s»...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: Legger til / oppdaterer UI-tekst fra %s...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: Ugyldig boolsk verdi (%s) på linje %d av %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: Ugyldig variabelutskifting ($%c) på linje %d av %s.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: Forventet boolsk verdi på linje %d av %s.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: Forventet valgkode på linje %d av %s.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: Forventet valgnavn/-tekst på linje %d av %s.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: Laster inn driverinformasjonsfil «%s»...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: Laster inn meldinger for nasjonal innstilling «%s»...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: Laster inn meldinger fra «%s»...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: Kan ikke opprette PPD-filen «%s» – %s.\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: Kan ikke opprette utdatakatalog %s: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: Kan ikke opprette utdatakanaler: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: Kan ikke utføre cupstestppd: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: Finner ikke lokalisering for «%s» – %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: Finner ikke lokaliseringsfilen «%s» – %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: Udefinert variabel (%s) på linje %d av %s.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: Skriver %s...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: Skriver PPD-filer til katalog «%s»...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: Ignorerer PPD-fil %s...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: Kan ikke sikkerhetskopiere %s til %s – %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "skriveren %s er deaktivert siden %s –\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "skriveren %s er inaktiv. aktivert siden %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "skriveren %s skriver nå ut %s–%d. aktivert siden %s\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "skriveren %s/%s er deaktivert siden %s –\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "skriveren %s/%s er inaktiv. aktivert siden %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "skriveren %s/%s skriver nå ut %s–%d. aktivert siden %s\n"
+
+msgid "processing"
+msgstr "behandler"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "request-id er %s–%d (%d fil(er))\n"
+
+msgid "request-id uses indefinite length"
+msgstr "request-id bruker uendelig lengde"
+
+msgid "scheduler is not running\n"
+msgstr "planlegger er ikke i gang\n"
+
+msgid "scheduler is running\n"
+msgstr "planlegger er i gang\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "status for %s mislyktes: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "status\t\tvis status for daemon og kø\n"
+
+msgid "stopped"
+msgstr "stoppet"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "standardmål for system: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "standardmål for system: %s/%s\n"
+
+msgid "unknown"
+msgstr "ukjent"
+
+msgid "untitled"
+msgstr "uten navn"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindings bruker uendelig lengde"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " WARN %s har ingen relaterte valg!\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " WARN Standardinnstillinger stemmer ikke overens!\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " WARN Det er mulig at dupleksvalgnøkkelordet %s ikke fungerer "
+#~ "som forventet og skal ha navnet Duplex!\n"
+#~ " REF: Side 122, del 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr " WARN Filen inneholder CR-, LF- og CR LF-linjeskift!\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " WARN Linjen %d inneholder kun mellomrom!\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " WARN APDialogExtension-filen «%s» mangler\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " WARN APPrinterIconPath-filen «%s» mangler\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " WARN PPD-filer som ikke er i Windows-format, bør kun bruke "
+#~ "linjeskift med LF, ikke CR LF!\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " WARN Foreldet PPD-versjon %.1f!\n"
+#~ " REF: Side 42, del 5.2.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s finnes ikke!\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s Ugyldig %s-valg %s!\n"
+#~ " REF: Side 122, del 5.17\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr " %s Ugyldig UTF-8 «%s»-oversettelsesstreng for valget %s!\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Ugyldig UTF-8 «%s»-oversettelsesstreng for valget %s, "
+#~ "innstillingen %s!\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Ugyldig cupsFilter-verdi «%s»!\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s Ugyldig cupsICCProfile %s!\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Ugyldig cupsPreFilter-verdi «%s»!\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Ugyldig cupsUIConstraints %s: «%s»!\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s Ugyldig språk «%s»!\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s Tom cupsUIConstraints %s!\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s «%s»-oversettelsesstreng for valget %s mangler!\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s «%s»-oversettelsesstreng for valget %s, innstillingen %s "
+#~ "mangler!\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr " %s Valget *%s %s i UIConstraints «*%s %s *%s %s» mangler!\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Valget *%s %s i cupsUIConstraints %s mangler: «%s»!\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s cupsICCProfile-filen «%s» mangler!\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s cupsUIResolver %s mangler!\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr " %s Valget %s i UIConstraints «*%s %s *%s %s» mangler!\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Valget %s i cupsUIConstraints %s mangler: «%s»!\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr " %s Filen inneholder ingen grunnoversettelse «%s»!\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s OBLIGATORISK %s definerer ikke innstillingen Ingen!\n"
+#~ " REF: Side 122, del 5.17\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " %s cupsICCProfile %s-hashverdi er i konflikt med %s!\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver %s forårsaker en sløyfe!\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FEIL** Den eneste forskjellen mellom %s-valgnavnene %s og %s er "
+#~ "store og små bokstaver!\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **FEIL** %s må være 1284DeviceID!\n"
+#~ " REF: Side 72, del 5.5\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **FEIL** UGYLDIG DefaultImageableArea %s!\n"
+#~ " REF: Side 102, del 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **FEIL** UGYLDIG DefaultPaperDimension %s!\n"
+#~ " REF: Side 103, del 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **FEIL** Ugyldig %s-valg %s!\n"
+#~ " REF: Side 84, del 5.9\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr " **FEIL** Ugyldig LanguageEncoding %s – må være ISOLatin1!\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr " **FEIL** Ugyldig LanguageVersion %s – må være English!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **FEIL** Standard oversettelsesstreng for valget %s, innstillingen "
+#~ "%s inneholder 8-bitstegn!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **FEIL** Standard oversettelsesstreng for valget %s inneholder 8-"
+#~ "bitstegn!\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FEIL** Den eneste forskjellen mellom gruppenavnene %s og %s er "
+#~ "store og små bokstaver!\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **FEIL** Flere forekomster av %s-valgnavnet %s!\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FEIL** Den eneste forskjellen mellom valgnavnene %s og %s er "
+#~ "store og små bokstaver!\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " Ugyldig %%%%BoundingBox: på linje %d!\n"
+#~ " REF: Side 39, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " Ugyldig %%%%Page: på linje %d!\n"
+#~ " REF: Side 53, %%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " Ugyldig %%%%Pages: på linje %d!\n"
+#~ " REF: Side 43, %%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " Linje %d inneholder mer enn 255 tegn (%d)!\n"
+#~ " REF: Side 25, Line Length\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " %!PS-Adobe-3.0 mangler på første linje!\n"
+#~ " REF: Side 17, 3.1 Conforming Documents\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " %%EndComments-kommentar mangler!\n"
+#~ " REF: Side 41, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " %%BoundingBox:-kommentar mangler eller er ugyldig!\n"
+#~ " REF: Side 39, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " %%Page-kommentarer mangler eller er ugyldig!\n"
+#~ " REF: Side 53, %%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " %%Pages-kommentar mangler eller er ugyldig!\n"
+#~ " REF: Side 43, %%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " Fant %d linjer som er lengre enn 255 tegn!\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " For mange %%BeginDocument-kommentarer!\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " For mange %%EndDocument-kommentarer!\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " Advarsel: filen inneholder binærdata!\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " Advarsel: ingen %%EndComments-kommentar i fil!\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " Advarsel: foreldet DSC-versjon %.1f i fil!\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s støttes ikke!"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: Vet ikke hva som skal gjøres!\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr "%s: Feil – %s-miljøvariabel oppgir målet «%s» som ikke eksisterer!\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: Feil – ugyldig jobb-ID!\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr "%s: Feil – kan ikke skrive ut filer og endre jobber samtidig!\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: Feil – kan ikke skrive ut fra stdin hvis det er oppgitt filer eller "
+#~ "en jobb-ID!\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: Feil – forventet tegnsett etter «-S»-valg!\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: Feil – forventet innholdstype etter «-T»-valg!\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: Feil – forventet eksemplarer etter «-n»-valg!\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s: Feil – forventet antall eksemplarer etter «-#»-valg!\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: Feil – forventet mål etter «-P»-valg!\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: Feil – forventet mål etter «-b»-valg!\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: Feil – forventet mål etter «-d»-valg!\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: Feil – forventet skjema etter «-f»-valg!\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: Feil – forventet holdnavn etter «-H»-valg!\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: Feil – forventet vertsnavn etter «-H»-valg!\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: Feil – forventet vertsnavn etter «-h»-valg!\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: Feil – forventet modusliste etter «-y»-valg!\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: Feil – forventet navn etter «%c»-valg!\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s: Feil – forventet valgstreng etter «-o»-valg!\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: Feil – forventet sideliste etter «-P»-valg!\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: Feil – forventet prioritet etter «%c»-valg!\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s: Feil – forventet begrunnelsestekst etter «-r»-valg!\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: Feil – forventet tittel etter «-t»-valg!\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s: Feil – forventet brukernavn etter «-U»-valg!\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s: Feil – forventet brukernavn etter «-u»-valg!\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: Feil – forventet verdi etter «%c»-valg!\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: Feil – trenger «completed», «not-completed» eller «all» etter «-W»-valg!\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: Feil – planlegger svarer ikke!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: Feil – ukjent mål «%s»!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: Feil – ukjent mål «%s/%s»!\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: Feil – ukjent valg «%c»!\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: Feil – ukjent valg «%s»!\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: Forventet jobb-ID etter «-i»-valg!\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: Ugyldig målnavn i liste «%s»!\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr "%s: Trenger jobb-ID («-i jobid») før «-H restart»!\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: Mangler filter for å konvertere fra %s/%s til %s/%s!\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s: Støtte for kryptering er ikke kompilert inn!\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: FÃ¥r ikke kontakt med tjener!\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: Kan ikke bestemme MIME-typen til «%s»!\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s: Kan ikke åpne %s – %s\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s: Kan ikke åpne %s – %s på linje %d.\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s: Kan ikke lese MIME-database fra «%s» eller «%s»!\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: Ukjent mål «%s»!\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: Ukjent MIME-type for mål %s/%s!\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: Ukjent valg «%c»!\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: Ukjent kilde-MIME-type for mål %s/%s!\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: Advarsel «%c»-formatmodifikator støttes ikke – det er mulig at utdata "
+#~ "ikke er korrekt!\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: Advarsel – ignorerte tegnsettvalg!\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: Advarsel – ignorerte innholdstypevalg!\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: Advarsel – ignorerte skjemavalg!\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: Advarsel – ignorerte modusvalg!\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr "%s: feil – %s-miljøvariabel oppgir målet «%s» som ikke eksisterer!\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: feil – forventet option=value etter «-o»-valg!\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "600 DPI gråskala"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr "Et Samba-passord kreves for å eksportere skriverdrivere!"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr "Et Samba-brukernavn kreves for å eksportere skriverdrivere!"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "Det finnes allerede en klasse med navnet «%s»!"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "Det finnes allerede en skriver med navnet «%s»!"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr "Prøv å sette %s printer-state til den ugyldige verdien %d!"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "Attributtgrupper er ikke i rekkefølge (%x < %x)!"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "Ugyldig device-URI «%s»!\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "Ugyldig device-uri «%s»!"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "Ugyldig device-uri-oppsett «%s»!\n"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "Ugyldig document-format «%s»!"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Ugyldig filnavnbuffer!"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Ugyldig job-priority-verdi!"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Ugyldig job-sheets-verdi «%s»!"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Ugyldig job-sheets-verditype!"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Ugyldig job-state-verdi!"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Ugyldig job-uri-attributt «%s»!"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "Ugyldig notify-pull-method «%s»!"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "Ugyldig notify-recipient-uri-URI «%s»!"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "Ugyldig valg og alternativ på linje %d!"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "Ugyldig port-monitor «%s»!"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Ugyldig printer-state-verdi %d!"
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "Ugyldig versjonsnummer for forespørsel %d.%d!"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "Ugyldig abonnements-ID!"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "Tegnsett «%s» støttes ikke!"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "Kunne ikke skanne type «%s»!"
+
+#~ msgid "Cover open."
+#~ msgstr "Deksel åpent."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "Fremkaller nesten tom."
+
+#~ msgid "Developer empty!"
+#~ msgstr "Fremkaller tom!"
+
+#~ msgid "Door open."
+#~ msgstr "Dør åpen."
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Fant ugyldig %%BoundingBox:-kommentar!\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: Ugyldig %%IncludeFeature:-kommentar!\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: Ugyldig %%Page:-kommentar i fil!\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: Ugyldig %%PageBoundingBox:-kommentar i fil!\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: Ugyldig SCSI-enhetsfil «%s»!\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: Ugyldig kolonneverdi %d!\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: Ugyldig cpi-verdi %f!\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: Ugyldig lpi-verdi %f!\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: Ugyldig sideoppsett!\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: MÃ¥lskriver finnes ikke!\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Fant duplisert %%BoundingBox:-kommentar!\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: Fant duplisert %%Pages:-kommentar!\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: Tom utskriftsfil!\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr "ERROR: Forventet streng i anførselstegn på linje %d av %s!\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: Kritisk USB-feil!\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr "ERROR: Fant ugyldig HP-GL/2-kommando, kan ikke skrive ut fil!\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: %%EndProlog mangler!\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: %%EndSetup mangler!\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Mangler enhets-URI på kommandolinje, og ingen DEVICE_URI-"
+#~ "miljøvariabel!\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: Mangler verdi på linje %d i bannerfil!\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: Krever en msgid-linje før oversettelsesstreng på linje %d av %s!\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: Ingen %%BoundingBox:-kommentar i header!\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: Ingen %%Pages:-kommentar i header!\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Fant ingen enhets-URI i argv[0] eller i DEVICE_URI-miljøvariabel!\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: Fant ingen sider!\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: Tom for papir!\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: PRINTER-miljøvariabel er ikke definert!\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: Utskriftsfil ble ikke akseptert (%s)!\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: Skriver svarer ikke!\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: Kan ikke opprette midlertidig fil – %s.\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: Kan ikke opprette midlertidig fil: %s\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: Kan ikke hente %d-attributter for jobb (%s)!\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: Kan ikke hente skriverstatus (%s)!\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: Finner ikke skriveren «%s»!\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: Kan ikke åpne bildefil for utskrift!\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: Kan ikke åpne midlertidig fil"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: Kan ikke skrive ut %d tekstkolonner!\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: Kan ikke skrive ut %d x %d tekstside!\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: Kan ikke lese utskriftsdata!\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: Kan ikke sende utskriftsdata (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: Kan ikke sende utskriftsdata!\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: Kan ikke skrive %d byte til skriver!\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr "ERROR: Kan ikke skrive rasterdata til driver!\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: Kan ikke skrive til midlertidig fil "
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: Uventet tekst på linje %d av %s!\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: Ukjent krypteringsvalgverdi «%s»!\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: Ukjent meldingskatalogformat for «%s»!\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: Ukjent valg «%s» med verdien «%s»!\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: Ukjent versjonsvalgverdi «%s»!\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr "ERROR: Lysstyrkeverdien %s støttes ikke, bruker brightness=100!\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: Gammaverdien %s støttes ikke, bruker gamma=1000!\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr "ERROR: Number-up-verdien %d støttes ikke, bruker number-up=1!\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: Number-up-layout-verdien %s støttes ikke, bruker number-up-"
+#~ "layout=lrtb!\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: Page-border-verdien %s støttes ikke, bruker page-border=none!\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr "ERROR: fant doc_printf-overflyt (%d byte), avbryter!\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr "ERROR: pdftops-filter krasjet på signal %d!\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr "ERROR: pdftops-filter avsluttet med statusen %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops avsluttet på signalet %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops avsluttet med statusen %d!\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: gjenopprettbar: Kan ikke koble til skriver. Prøver på nytt om 30 "
+#~ "sekunder...\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "Tom PPD-fil!"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "Feil: krever vertsnavn etter «-h»-valg!\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Fikseringsenhetens temperatur er høy!"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "Fikseringsenhetens temperatur er lav!"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "Fikk et printer-uri-attributt, men ingen jobb-ID!"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Blekk/toner nesten tom."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Blekk/toner tom!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Avfallsbeholder for blekk/toner nesten full."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Avfallsbeholder for blekk/toner full!"
+
+#~ msgid "Interlock open."
+#~ msgstr "Sikkerhetsenhet åpen."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "Kan ikke starte jobb nr. %d på nytt – ingen filer!"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "Jobb nr. %d finnes ikke!"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "Jobb nr. %d er fullført og kan ikke endres!"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "Jobb nr. %d er ikke fullført!"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "Jobb nr. %d holdes ikke for godkjenning!"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "Jobb nr. %d holdes ikke!"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "Jobben #%s finnes ikke!"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "Fant ikke jobben %d!"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "Jobbabonnementer kan ikke fornyes!"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "Språket «%s» støttes ikke!"
+
+#~ msgid "Media jam!"
+#~ msgstr "Papirstopp!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Arkskuff nesten tom."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Arkskuff tom!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Arkskuff mangler!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "Arkskuffen må fylles."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "document-number-attributt mangler!"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "Dobbelt anførselstegn mangler på linje %d!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "Skjemavariabel mangler!"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "Notify-subscription-ids-attributt mangler!"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "Requesting-user-name-attributt mangler!"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "Nødvendige attributter mangler!"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "Verdi mangler på linje %d!"
+
+#~ msgid "No PPD name!"
+#~ msgstr "Uten PPD-navn!"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Ingen Windows-skriverdrivere er installert!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "Ingen aktive jobber på %s!"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "Ingen attributter i forespørsel!"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "Ingen godkjenningsinformasjon oppgitt!"
+
+#~ msgid "No file!?!"
+#~ msgstr "Ingen fil!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "Uten endringstidspunkt!"
+
+#~ msgid "No printer name!"
+#~ msgstr "Ingen skrivernavn!"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "Fant ikke printer-uri for klasse!"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "Fant ikke printer-uri!"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "Ingen printer-uri i forespørsel!"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "Ingen abonnementsattributter i forespørsel!"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC er nesten oppbrukt."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC oppbrukt!"
+
+#~ msgid "Out of toner!"
+#~ msgstr "Tomt for toner!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Ut-beholder nesten full."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Ut-beholder full!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Utmatingsbrett mangler!"
+
+#~ msgid "Printer offline."
+#~ msgstr "Skriver ikke tilgjengelig."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "SCSI-skriver"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "Notify-user-data-verdien er for stor (%d > 63 oktetter)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "Skriveren eller klassen er ikke delt!"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "Printer-uri-attributtet kreves!"
+
+#~ msgid "Toner low."
+#~ msgstr "Lite toner."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "For mange job-sheets-verdier (%d > 2)!"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "For mange printer-state-reasons-verdier (%d > %d)!"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "Kan ikke legge til jobb for målet «%s»!"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "Kan ikke tildele hukommelse for filtyper!"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr "Kan ikke kopiere 64-bits CUPS-skriverdriverfiler (%d)!"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr "Kan ikke kopiere 64-bits Windows-skriverdriverfiler (%d)!"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr "Kan ikke kopiere CUPS-skriverdriverfiler (%d)!"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "Kan ikke kopiere PPD-fil – %s!"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "Kan ikke kopiere PPD-fil!"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr "Kan ikke kopiere Windows 2000-skriverdriverfiler (%d)!"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr "Kan ikke kopiere Windows 9x-skriverdriverfiler (%d)!"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "Kan ikke kopiere grensesnittsprosedyre – %s!"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "Kan ikke opprette printer-uri!"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr "Kan ikke redigere cupsd.conf-filer som er større enn 1 MB!"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "Finner ikke mål for jobb!"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "Finner ikke skriver!\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr "Kan ikke installere Windows 2000-skriverdriverfiler (%d)!"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr "Kan ikke installere Windows 9x-skriverdriverfiler (%d)!"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "Kan ikke åpne dokumentet %d i jobben %d!"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "Kan ikke sende kommando til skriverdriver!"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Kan ikke angi Windows-skriverdriver (%d)!"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "Kan ikke bruke eldre driver for USB-klasse!\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "Ukjent skriverfeil (%s)!"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Tegnsettet «%s» støttes ikke!"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "Komprimeringen «%s» støttes ikke!"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "Komprimeringsattributtet %s støttes ikke!"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "Formatet «%s» støttes ikke!"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "Formatet «%s» støttes ikke!"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "Formatet «%s/%s» støttes ikke!"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "Bruk: konverter [ valg ]\n"
+#~ "\n"
+#~ "Valg:\n"
+#~ "\n"
+#~ " -f filnavn Angi at fil skal konverteres (stdin hvis ikke)\n"
+#~ " -o filnavn Angi at fil skal genereres (stdout hvis ikke)\n"
+#~ " -i mime/type Angi MIME-type for inndata (auto-typed hvis ikke)\n"
+#~ " -j mime/type Angi MIME-type for utdata (application/pdf hvis "
+#~ "ikke)\n"
+#~ " -P filename.ppd Angi PPD-fil\n"
+#~ " -a 'navn=verdi ...' Angi valg\n"
+#~ " -U brukernavn Angi brukernavn for jobb\n"
+#~ " -J tittel Angi tittel\n"
+#~ " -c eksemplarer Angi antall eksemplarer\n"
+#~ " -u Fjern PPD-fil når ferdig\n"
+#~ " -D Fjern inndatafil når ferdig\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "Bruk: cupsfilter -m mime/type [ valg ] filnavn\n"
+#~ "\n"
+#~ "Valg:\n"
+#~ "\n"
+#~ " -c cupsd.conf Angi hvilken cupsd.conf-fil som skal brukes\n"
+#~ " -j jobb-id[,N] Filtrer filen N fra angitt jobb (standard er fil 1)\n"
+#~ " -n eksemplarer Angi antall eksemplarer\n"
+#~ " -o navn=verdi Angi valg\n"
+#~ " -p filename.ppd Angi PPD-fil\n"
+#~ " -t tittel Angi tittel\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Bruk: cupstestppd [valg] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [valg] -\n"
+#~ "\n"
+#~ "Valg:\n"
+#~ "\n"
+#~ " -R rotkatalog Angi alternativ rot\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Gi advarsler i stedet for feil\n"
+#~ " -q Kjør stille\n"
+#~ " -r Bruk «avslappet» åpen modus\n"
+#~ " -v Vær litt detaljert\n"
+#~ " -vv Vær veldig detaljert\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: Kunne ikke lese sidekanalforspørsel!\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr "WARNING: Valget «%s» kan ikke inkluderes via IncludeFeature!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Ekstern vert svarte ikke med kommandostatusbyte etter %d "
+#~ "sekunder!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Ekstern vert svarte ikke med kontrollstatusbyte etter %d "
+#~ "sekunder!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Ekstern vert svarte ikke med datastatusbyte etter %d sekunder!\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr "WARNING: SCSI-kommando ble tidsavbrutt (%d). Prøver på nytt...\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: Dette dokumentet er ikke i overensstemmelse med Adobes "
+#~ "konvensjoner for dokumentstruktur, og det er mulig at dokumentet ikke "
+#~ "skrives ut riktig!\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: Ukjent innstilling «%s» for valget «%s»!\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: Ukjent valg «%s»!\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: Modulasjonshastigheten %s støttes ikke!\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: gjenopprettbar: Nettverksverten «%s» er opptatt. Prøver på nytt "
+#~ "om %d sekunder...\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr "Advarsel: Ingen Windows 2000-skriverdrivere er installert!"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: Ukjent valg «%s»!\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: Ukjent valg «-%c»!\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr "cupsd: Forventet config-filnavn etter «-c»-valg!\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: Kan ikke hente nåværende katalog!\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: Ukjent argument «%s» – avbryter!\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: Ukjent valg «%c» – avbryter!\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: Ugyldig dokumentnummer %d!\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: Ugyldig jobb-ID %d!\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: Kun ett filnavn kan spesifiseres!\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter: Kan ikke opprette midlertidig fil: %s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "job-printer-uri-attributt mangler!"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Klassenavn kan kun inneholde tegn som kan skrives ut!\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: Forventet PPD etter «-P»-valg!\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr "lpadmin: Forventet tillat/avslå:brukerliste etter «-u»-valg!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: Forventet klasse etter «-r»-valg!\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: Forventet klassenavn etter «-c»-valg!\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: Forventet beskrivelse etter «-D»-valg!\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: Forventet enhets-URI etter «-v»-valg!\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: Forventet filtype etter «-I»-valg!\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: Forventet vertsnavn etter «-h»-valg!\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: Forventet grensesnitt etter «-i»-valg!\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: Forventet sted etter «-L»-valg!\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: Forventet modell etter «-m»-valg!\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: Forventet navn=verdi etter «-o»-valg!\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: Forventet skriver etter «-p»-valg!\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: Forventet skrivernavn etter «-d»-valg!\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin: Forventet skriver eller klasse etter «-x»-valg!\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: Fant ingen medlemsnavn!\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Skrivernavn kan kun inneholde tegn som kan skrives ut!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke legge til skriver i klassen:\n"
+#~ " Du må angi et skrivernavn først!\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin: Kan ikke opprette midlertidig fil – %s\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin: Kan ikke opprette midlertidig fil: %s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke fjerne en skriver fra klassen:\n"
+#~ " Du må angi et skrivernavn først!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke angi PPD-fil:\n"
+#~ " Du må angi et skrivernavn først!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke angi enhets-URI:\n"
+#~ " Du må angi et skrivernavn først!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke angi grensesnittsprosedyre eller PPD-fil:\n"
+#~ " Du må angi et skrivernavn først!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke angi grensesnittsprosedyre:\n"
+#~ " Du må angi et skrivernavn først!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke angi beskrivelse av skriver:\n"
+#~ " Du må angi et skrivernavn først!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke angi skriverplassering:\n"
+#~ " Du må angi et skrivernavn først!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kan ikke angi skrivervalg:\n"
+#~ " Du må angi et skrivernavn først!\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: Ukjent tillat/avslå-valg «%s»!\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: Ukjent argument «%s»!\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: Ukjent valg «%c»!\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin: Advarsel – ignorerte innholdstypeliste!\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr "lpinfo: Forventet 1284-enhets-ID-streng etter --device-id!\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: Forventet språk etter --language!\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo: Forventet merke og modell etter --make-and-model!\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo: Forventet produktstreng etter --product!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo: Forventet oppsettliste etter --exclude-schemes!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo: Forventet oppsettliste etter --include-schemes!\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: Forventet tisdsavbrudd etter --timeout!\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: Ukjent argument «%s»!\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: Ukjent valg «%c»!\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: Ukjent valg «%s»!\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: Ukjent argument «%s»!\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: Ukjent valg «%c»!\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: Ingen skrivere!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: Kan ikke åpne PPD-fil for %s!\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: Ukjent skriver eller klasse!\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: Kun rot kan legge til og slette passord!\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: Passordfil er opptatt!\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: Passordfil er ikke oppdatert!\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: Beklager. Passordet stemmer ikke!\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: Beklager. Passordene er ikke like!\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: feil – %s-miljøvariabel oppgir målet «%s» som ikke eksisterer!\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-events ikke angitt!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "notify-recipient-uri-URI «%s» er i bruk!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "notify-recipient-uri-URI «%s» bruker et ukjent oppsett!"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d er ubrukelig!"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ugyldig oppløsningsnavn «%s» på linje %d av %s!\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: Ugyldig statusnøkkelord %s på linje %d av %s!\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc: Fant alternativ på linje %d av %s uten valg!\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc: Duplikat #po for nasjonal innstilling %s på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet filterdefinisjon på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet programnavn på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet tegnsett etter Font på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet fargerekkefølge for ColorModel på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet fargeområde for ColorModel på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet komprimering for ColorModel på linje %d av %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Forventet restriksjoner for UIConstraints på linje %d av %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Forventet nøkkelord for drivertype etter DriverType på linje %d av %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet duplekstype etter Duplex på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet koding etter Font på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet filnavn etter #po %s på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet gruppenavn/-tekst på linje %d av %s.\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet inkluderingsfilnavn på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet heltall på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet nasjonal innstilling etter #po på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet navn etter %s på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet navn etter FileName på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet navn etter Font på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet navn etter Manufacturer på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet navn etter MediaSize på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet navn etter ModelName på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet navn etter PCFileName på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet navn/tekst etter %s på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet navn/tekst etter Installable på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet navn/tekst etter Resolution på linje %d av %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Forventet navn/tekst-kombinasjon for ColorModel på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet valgnavn/-tekst på linje %d av %s.\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet valgdel på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet valgtype på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Forventet overstyringsfelt etter Resolution på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet reelt tall på linje %d av %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Forventet oppløsning/papirtype etter ColorProfile på linje %d av %"
+#~ "s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Forventet oppløsning/papirtype etter SimpleColorProfile på linje %d "
+#~ "av %s!\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet velger etter %s på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet status etter Font på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet streng etter Copyright på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet streng etter Version på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet to valgnavn på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet verdi etter %s på linje %d av %s!\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Forventet versjon etter Font på linje %d av %s!\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: Ugyldig #include/#po filnavn «%s»!\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Ugyldig kostnad for filter på linje %d av %s!\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Ugyldig, tom MIME-type for filter på linje %d av %s!\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Ugyldig, tomt programnavn for filter på linje %d av %s!\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ugyldig valgdel «%s» på linje %d av %s!\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ugyldig valgtype «%s» på linje %d av %s!\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: Mangler #endif ved slutten av «%s»!\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: Mangler #if på linje %d av %s!\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc: Ingen meldingskatalog oppgitt for nasjonal innstilling %s!\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Valg %s definert på nytt med forskjellig type på linje %d av %s!\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr "ppdc: Valgrestriksjon må *navn på linje %d av %s!\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: For mange nestede #if-er på linje %d av %s!\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: Finner ikke #po-filen %s på linje %d av %s!\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Finner ikke inkluderingsfilen «%s» på linje %d av %s!\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: Ukjent drivertype %s på linje %d av %s!\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ukjent duplekstype «%s» på linje %d av %s!\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ukjent papirstørrelse «%s» på linje %d av %s!\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: Ukjent kjennetegn «%s» funnet på linje %d av %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Ukjente etterfølgende tegn i det reelle tallet «%s» på linje %d av %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr "ppdc: Uavsluttet streng begynner med %c på linje %d av %s!\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: Ugyldig LanguageVersion «%s» i %s!\n"
diff --git a/locale/cups_pl.po b/locale/cups_pl.po
new file mode 100644
index 000000000..c49a11e45
--- /dev/null
+++ b/locale/cups_pl.po
@@ -0,0 +1,7143 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-16 12:00-0800\n"
+"Last-Translator: Apple Inc.\n"
+"Language-Team: Apple Inc.\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(wszystko)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(brak)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d wpisów\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tPo niepowodzeniu: kontynuuj\n"
+
+msgid "\tAlerts:"
+msgstr "\tAlarmy:"
+
+msgid "\tBanner required\n"
+msgstr "\tBanner jest wymagany\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tZestawy znaków:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tPołączenie: bezpośrednie\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tPołączenie: zdalne\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tDomyślny rozmiar strony:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tDomyślny stopień:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tDomyślne ustawienia portu:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tOpis: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tFormularz zamontowany od:\n"
+"\tRodzaje zawartości: dowolne\n"
+"\tRodzaje drukarek: nieznane\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tDozwolone formularze:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tInterfejs: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tInterfejs: %s/interfejsy/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tInterfejs: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tPołożenie: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tPrzy niepowodzeniu: brak alarmu\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tDozwoleni użytkownicy:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tZabronieni użytkownicy:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tdemon jest obecny\n"
+
+msgid "\tno entries\n"
+msgstr "\tbrak wpisów\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\tdrukarka jest urządzeniem \"%s\" prędkość -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\tdrukowanie jest wyłączone"
+
+msgid "\tprinting is enabled\n"
+msgstr "\tdrukowanie jest włączone\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\tw kolejce dla%s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tkolejka jest wyłączona\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tkolejka jest włączona\n"
+
+msgid "\treason unknown\n"
+msgstr "\tnieznana przyczyna\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" SZCZEGÓÅOWE WYNIKI TESTU ZGODNOÅšCI\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " REF: strona 15, sekcja 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " REF: strona 15, sekcja 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " REF: strona 19, sekcja 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " REF: strona 20, sekcja 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " REF: strona 27, sekcja 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " REF: strona 42, sekcja 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " REF: strony 16-17, sekcja 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " REF: strony 42-45, sekcja 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " REF: strony 45-46, sekcja 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " REF: strony 48-49, sekcja 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " REF: strony 52-54, sekcja 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f bajtów\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " SUKCES Default%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " SUKCES DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " SUKCES DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " SUKCES FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " SUKCES FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " SUKCES LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " SUKCES LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " SUKCES Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " SUKCES ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " SUKCES NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " SUKCES PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " SUKCES PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " SUKCES PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " SUKCES PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " SUKCES Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " SUKCES ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" OSTRZEŻENIE \"%s %s\" jest w konflikcie z \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" OSTRZEŻENIE %s współdzieli wspólny przedrostek z %s\n"
+" REF: strona 15, sekcja 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" OSTRZEŻENIE LanguageEncoding jest wymagane przez specyfikację PPD "
+"4.3.\n"
+" REF: strony 56-57, sekcja 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" OSTRZEŻENIE Manufacturer jest wymagane przez specyfikację PPD "
+"4.3.\n"
+" REF: strony 58-59, sekcja 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" OSTRZEŻENIE PCFileName dłuższa niż 8.3 narusza specyfikację PPD.\n"
+" REF: strony 61-62, sekcja 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" OSTRZEŻENIE Protokoły zawierają PJL, ale cechy JCL nie są "
+"ustawione.\n"
+" REF: strony 78-79, sekcja 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" OSTRZEŻENIE Protokoły zawierają zarówno PJL jak i BCP, oczekiwano "
+"TBCP.\n"
+" REF: strony 78-79, sekcja 5.7.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" OSTRZEŻENIE ShortNickName jest wymagana przez specyfikację PPD "
+"4.3.\n"
+" REF: strony 64-65, sekcja 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s BrakujÄ…cy plik cupsFilter \"%s\"!\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s BrakujÄ…cy plik cupsPreFilter \"%s\"!\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **PROBLEM** BÅĘDNA wartość Default%s %s\n"
+" REF: strona 40, sekcja 4.5.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **PROBLEM** BÅĘDNA wartość wÅ‚aÅ›ciwoÅ›ci JobPatchFile w pliku\n"
+" REF: strona 24, sekcja 3.4.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **PROBLEM** BÅĘDNA wartość Manufacturer (powinno być \"HP\")\n"
+" REF: strona 211, tablica D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **PROBLEM** BÅĘDNA wartość Manufacturer (powinno być \"Oki\")\n"
+" REF: strona 211, tablica D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **PROBLEM** BÅĘDNA wartość ModelName - \"%c\" nie jest zezwolone w "
+"ciągu znaków.\n"
+" REF: strony 59-60, sekcja 5.3.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **PROBLEM** BÅĘDNE PSVersion - nie jest \"(string) int\".\n"
+" REF: strony 62-64, sekcja 5.3.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **PROBLEM** BÅĘDNE Product - nie jest \"(string)\".\n"
+" REF: strona 62, sekcja 5.3.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **PROBLEM** BÅĘDNE ShortNickName - dÅ‚uższe niż 31 znaków.\n"
+" REF: strony 64-65, sekcja 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **PROBLEM** Nieprawidłowe FileVersion \"%s\"\n"
+" REF: strona 56, sekcja 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **PROBLEM** Nieprawidłowe FormatVersion \"%s\"\n"
+" REF: strona 56, sekcja 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr ""
+" **PROBLEM** Nie można zinterpretować domyślnego kodu opcji: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE Default%s\n"
+" REF: strona 40, sekcja 4.5.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE DefaultImageableArea\n"
+" REF: strona 102, sekcja 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE DefaultPaperDimension\n"
+" REF: strona 103, sekcja 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE FileVersion\n"
+" REF: strona 56, sekcja 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE FormatVersion\n"
+" REF: strona 56, sekcja 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE ImageableArea for PageSize %s\n"
+" REF: strona 41, sekcja 5.\n"
+" REF: strona 102, sekcja 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE LanguageEncoding\n"
+" REF: strony 56-57, sekcja 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE LanguageVersion\n"
+" REF: strony 57-58, sekcja 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **FAIL** WYMAGANE Manufacturer\n"
+" REF: strony 58-59, sekcja 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** WYMAGANE ModelName\n"
+" REF: strony 59-60, sekcja 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE NickName\n"
+" REF: strona 60, sekcja 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE PCFileName\n"
+" REF: strony 61-62, sekcja 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE PSVersion\n"
+" REF: strony 62-64, sekcja 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE PageRegion\n"
+" REF: strona 100, sekcja 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE PageSize\n"
+" REF: strona 41, sekcja 5.\n"
+" REF: strona 99, sekcja 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE PageSize\n"
+" REF: strony 99-100, sekcja 5.14.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE PaperDimension dla PageSize %s\n"
+" REF: strona 41, sekcja 5.\n"
+" REF: strona 103, sekcja 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE Product\n"
+" REF: strona 62, sekcja 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **PROBLEM** WYMAGANE ShortNickName\n"
+" REF: strony 64-65, sekcja 5.3.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " ZNALEZIONO %d BÅĘDÓW\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " NIE ZNALEZIONO BÅĘDÓW\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " FAIL\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" FAIL\n"
+" **PROBLEM** Nie można otworzyć pliku PPD - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" PROBLEM\n"
+" **PROBLEM** Nie można otworzyć pliku PPD - %s w wierszu %d.\n"
+
+msgid " PASS\n"
+msgstr " SUKCES\n"
+
+msgid "#10 Envelope"
+msgstr "Koperta #10"
+
+msgid "#11 Envelope"
+msgstr "Koperta #11"
+
+msgid "#12 Envelope"
+msgstr "Koperta #12"
+
+msgid "#14 Envelope"
+msgstr "Koperta #14"
+
+msgid "#9 Envelope"
+msgstr "Koperta #9"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bajtów"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f bajtów\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f mm"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f do %.0f x %.0f mm"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f cali"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f do %.2f x %.2f cali"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s akceptuje żądania od %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%s nie może zostać zmienione."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s nie jest zaimplementowane przez lpc w wersji CUPS.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s nie jest gotowe\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s jest gotowe\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s jest gotowe i drukuje\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s nie akceptuje żądań od %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s akceptuje żądania od %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s nie akceptuje żądań od %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [zlecenie %d localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s nie powiodło się: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: błąd - brak dostępnego domyślnego celu.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: błąd - priorytet musi być między 1 a 100.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: błąd - za dużo plików - \"%s\"\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: błąd - nie można uzyskać dostępu do \"%s\" - %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s: błąd - nie można wykonać kolejki z stdin - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: filtr \"%s\" jest niedostępny: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: nieprawidłowy łańcuch filtra \"%s\"\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: operacja nie powiodła się: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: nie można połączyć się z serwerem\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: nie można otworzyć %s: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: nie można otworzyć pliku PPD: %s on line %d\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: błąd - brak dostępnego domyślnego celu.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 cal/sek."
+
+msgid "1.25x0.25\""
+msgstr "1,25x0,25\""
+
+msgid "1.25x2.25\""
+msgstr "1,25x2,25\""
+
+msgid "1.5 inch/sec."
+msgstr "1,5 cala/sek."
+
+msgid "1.50x0.25\""
+msgstr "1,50x0,25\""
+
+msgid "1.50x0.50\""
+msgstr "1,50x0,50\""
+
+msgid "1.50x1.00\""
+msgstr "1,50x1,00\""
+
+msgid "1.50x2.00\""
+msgstr "1,50x2,00\""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 cali/sek."
+
+msgid "10 x 11\""
+msgstr "10 x 11\""
+
+msgid "10 x 13\""
+msgstr "10 x 13\""
+
+msgid "10 x 14\""
+msgstr "10 x 14\""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 mm/sek."
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 cali/sek."
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 cali/sek."
+
+msgid "12 x 11\""
+msgstr "12 x 11\""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 mm/sek."
+
+msgid "120x60dpi"
+msgstr "120x60dpi"
+
+msgid "120x72dpi"
+msgstr "120x72dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 mm/sek."
+
+msgid "15 x 11\""
+msgstr "15 x 11\""
+
+msgid "150 mm/sec."
+msgstr "150 mm/sek."
+
+msgid "150dpi"
+msgstr "150dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 cale/sek."
+
+msgid "2-Sided Printing"
+msgstr "druk obustronny"
+
+msgid "2.00x0.37\""
+msgstr "2,00x0,37\""
+
+msgid "2.00x0.50\""
+msgstr "2,00x0,50\""
+
+msgid "2.00x1.00\""
+msgstr "2,00x1,00\""
+
+msgid "2.00x1.25\""
+msgstr "2,00x1,25\""
+
+msgid "2.00x2.00\""
+msgstr "2,00x2,00\""
+
+msgid "2.00x3.00\""
+msgstr "2,00x3,00\""
+
+msgid "2.00x4.00\""
+msgstr "2,00x4,00\""
+
+msgid "2.00x5.50\""
+msgstr "2,00x5,50\""
+
+msgid "2.25x0.50\""
+msgstr "2,25x0,50\""
+
+msgid "2.25x1.25\""
+msgstr "2,25x1,25\""
+
+msgid "2.25x4.00\""
+msgstr "2,25x4,00\""
+
+msgid "2.25x5.50\""
+msgstr "2,25x5,50\""
+
+msgid "2.38x5.50\""
+msgstr "2,38x5,50\""
+
+msgid "2.5 inches/sec."
+msgstr "2,5 cala/sek."
+
+msgid "2.50x1.00\""
+msgstr "2,50x1,00\""
+
+msgid "2.50x2.00\""
+msgstr "2,50x2,00\""
+
+msgid "2.75x1.25\""
+msgstr "2,75x1,25\""
+
+msgid "2.9 x 1\""
+msgstr "2,9 x 1\""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 mm/sek."
+
+msgid "200 mm/sec."
+msgstr "200 mm/sek."
+
+msgid "203dpi"
+msgstr "203dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "24 igłowa"
+
+msgid "240x72dpi"
+msgstr "240x72dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 mm/sek."
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 cale/sek."
+
+msgid "3.00x1.00\""
+msgstr "3,00x1,00\""
+
+msgid "3.00x1.25\""
+msgstr "3,00x1,25\""
+
+msgid "3.00x2.00\""
+msgstr "3,00x2,00\""
+
+msgid "3.00x3.00\""
+msgstr "3,00x3,00\""
+
+msgid "3.00x5.00\""
+msgstr "3,00x5,00\""
+
+msgid "3.25x2.00\""
+msgstr "3,25x2,00\""
+
+msgid "3.25x5.00\""
+msgstr "3,25x5,00\""
+
+msgid "3.25x5.50\""
+msgstr "3,25x5,50\""
+
+msgid "3.25x5.83\""
+msgstr "3,25x5,83\""
+
+msgid "3.25x7.83\""
+msgstr "3,25x7,83\""
+
+msgid "3.5\" Disk"
+msgstr "dysk 3.5\""
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "dysk 3.5\" - 2 1/8 x 2 3/4\""
+
+msgid "3.50x1.00\""
+msgstr "3,50x1,00\""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 mm/sek."
+
+msgid "300 mm/sec."
+msgstr "300 mm/sek."
+
+msgid "300dpi"
+msgstr "300dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360dpi"
+
+msgid "360x180dpi"
+msgstr "360x180dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 cale/sek."
+
+msgid "4.00x1.00\""
+msgstr "4,00x1,00\""
+
+msgid "4.00x13.00\""
+msgstr "4,00x13,00\""
+
+msgid "4.00x2.00\""
+msgstr "4,00x2,00\""
+
+msgid "4.00x2.50\""
+msgstr "4,00x2,50\""
+
+msgid "4.00x3.00\""
+msgstr "4,00x3,00\""
+
+msgid "4.00x4.00\""
+msgstr "4,00x4,00\""
+
+msgid "4.00x5.00\""
+msgstr "4,00x5,00\""
+
+msgid "4.00x6.00\""
+msgstr "4,00x6,00\""
+
+msgid "4.00x6.50\""
+msgstr "4,00x6,50\""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 mm/sek."
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 cali/sek."
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 cali/sek."
+
+msgid "6.00x1.00\""
+msgstr "6,00x1,00\""
+
+msgid "6.00x2.00\""
+msgstr "6,00x2,00\""
+
+msgid "6.00x3.00\""
+msgstr "6,00x3,00\""
+
+msgid "6.00x4.00\""
+msgstr "6,00x4,00\""
+
+msgid "6.00x5.00\""
+msgstr "6,00x5,00\""
+
+msgid "6.00x6.00\""
+msgstr "6,00x6,00\""
+
+msgid "6.00x6.50\""
+msgstr "6,00x6,50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/sek."
+
+msgid "600dpi"
+msgstr "600dpi"
+
+msgid "60dpi"
+msgstr "60dpi"
+
+msgid "60x720dpi"
+msgstr "60x720dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 cali/sek."
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 cali/sek."
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8,00x1,00\""
+
+msgid "8.00x2.00\""
+msgstr "8,00x2,00\""
+
+msgid "8.00x3.00\""
+msgstr "8,00x3,00\""
+
+msgid "8.00x4.00\""
+msgstr "8,00x4,00\""
+
+msgid "8.00x5.00\""
+msgstr "8,00x5,00\""
+
+msgid "8.00x6.00\""
+msgstr "8,00x6,00\""
+
+msgid "8.00x6.50\""
+msgstr "8,00x6,50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/sek."
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 cali/sek."
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "9 igłowa"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?Nieprawidłowe, nieznane polecenie pomocy\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (oversize)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (oversize)"
+
+msgid "A4 (Small)"
+msgstr "A4 (mały)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (oversize)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "Zaakceptuj zlecenia"
+
+msgid "Accepted"
+msgstr "Zaakceptowane"
+
+msgid "Add Class"
+msgstr "Dodaj klasÄ™"
+
+msgid "Add Printer"
+msgstr "Dodaj drukarkÄ™"
+
+msgid "Add RSS Subscription"
+msgstr "Dodaj subskrypcjÄ™ RSS"
+
+msgid "Address"
+msgstr "Adres"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "Adres - 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "Administracja"
+
+msgid "Always"
+msgstr "Zawsze"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "Aplikator"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "Błędny PUSTY wskaźnik dests"
+
+msgid "Bad OpenGroup"
+msgstr "Błędne OpenGroup"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "Błędne OpenUI/JCLOpenUI"
+
+msgid "Bad OrderDependency"
+msgstr "Błędne OrderDependency"
+
+msgid "Bad Request"
+msgstr "Błędne żądanie"
+
+msgid "Bad SNMP version number"
+msgstr "Błędny numer wersji SNMP"
+
+msgid "Bad UIConstraints"
+msgstr "Błędne OrderDependency"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Błędna wartość kopii %d."
+
+msgid "Bad custom parameter"
+msgstr "Błędny własny parametr"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Błędny atrybut czcionki: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Błędna wartość kopii %d."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Błędne wartości %d-%d page-ranges."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Bannery"
+
+msgid "Billing Information: "
+msgstr "Fakturowanie: "
+
+msgid "Bond Paper"
+msgstr "Papier uszlachetniony"
+
+msgid "C0 Envelope"
+msgstr "Koperta C0"
+
+msgid "C1 Envelope"
+msgstr "Koperta C1"
+
+msgid "C2 Envelope"
+msgstr "Koperta C2"
+
+msgid "C3 Envelope"
+msgstr "Koperta C3"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "Koperta C4"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "Koperta C5"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "Koperta C6"
+
+msgid "C65 Envelope"
+msgstr "Koperta C65"
+
+msgid "C7 Envelope"
+msgstr "Koperta C7"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "Drukarka etykiet CPCL"
+
+msgid "Cancel RSS Subscription"
+msgstr "Wycofaj subskrypcjÄ™ RSS"
+
+msgid "Change Settings"
+msgstr "Zmień ustawienia"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Koperta Chou3"
+
+msgid "Chou4 Envelope"
+msgstr "Koperta Chou4"
+
+msgid "Classes"
+msgstr "Klasy"
+
+msgid "Clean Print Heads"
+msgstr "Czyść głowice drukarki"
+
+msgid "Color"
+msgstr "Kolor"
+
+msgid "Color Mode"
+msgstr "Tryb koloru"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"Polecenia mogą być skracane. Poleceniami są:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "Community name używa nieograniczonej długości"
+
+msgid "Continue"
+msgstr "Dalej"
+
+msgid "Continuous"
+msgstr "Ciągły"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Utworzono"
+
+msgid "Created On: "
+msgstr "Utworzono: "
+
+msgid "Custom"
+msgstr "WÅ‚asne"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Wytnij"
+
+msgid "Cutter"
+msgstr "Do cięcia"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "Koperta DL"
+
+msgid "Dark"
+msgstr "Ciemne"
+
+msgid "Darkness"
+msgstr "Ciemność"
+
+msgid "Delete Class"
+msgstr "Usuń klasę"
+
+msgid "Delete Printer"
+msgstr "Usuń drukarkę"
+
+msgid "Description: "
+msgstr "Opis: "
+
+msgid "DeskJet Series"
+msgstr "Seria DeskJet"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "Cel \"%s\" nie akceptuje zadań."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"UrzÄ…dzenie: uri = %s\n"
+" klasa = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" lokalizacja = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "Materiał bezpośredni termiczny"
+
+msgid "Disabled"
+msgstr "Wyłączone"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "Dokument %d nie znaleziony w zleceniu %d."
+
+msgid "Double Postcard"
+msgstr "Podwójna pocztówka"
+
+msgid "Driver Name: "
+msgstr "Nazwa sterownika: "
+
+msgid "Driver Version: "
+msgstr "Wersja sterownika: "
+
+msgid "Duplexer"
+msgstr "Do druku obustronnego"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: Nie można przydzielić pamięci dla informacji strony: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: Nie można przydzielić pamięci dla tablicy stron: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "Drukarka etykiet EPL1"
+
+msgid "EPL2 Label Printer"
+msgstr "Drukarka etykiet EPL2"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: nieprawidłowy plik zestawu znaków %s\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: nieprawidłowy rodzaj zestawu znaków %s\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: nieprawidłowy wiersz opisu czcionki: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: nieprawidłowy kierunek tekstu %s\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: nieprawidłowa szerokość tekstu %s\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: błąd %d podczas wysyłania żądania PAPSendData: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: brak czcionek w pliku zestawu znaków %s\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: drukarka nie odpowiada\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: drukarka wysłała niespodziewany EOF\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: serwer zdalny nie zaakceptował pliku kontrolnego (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: serwer zdalny nie zaakceptował pliku danych (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr ""
+"ERROR: wystąpił błąd upływu limitu czasu podczas wysyłania danych do "
+"drukarki\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: nie można dodać pliku %d do zlecenia: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: nie można anulować zlecenia %d: %s/n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: nie można skopiować pliku PDF"
+
+msgid "ERROR: Unable to create pipe"
+msgstr ""
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: nie można utworzyć gniazda"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: nie można utworzyć skompresowanego tymczasowego pliku wydruku: %s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: nie można utworzyć pliku tymczasowego"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: nie można wykonać pictwpstops: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: nie można wykonać programu gs"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: nie można wykonać programu pdftops"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: nie można rozdzielić pictwpstops: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: nie można uzyskać żądania PAP"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: nie można uzyskać odpowiedzi PAP"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr "ERROR: brak pliku PPD dla drukarki \"%s\" - %s\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: nie można uzyskać domyślnej strefy AppleTalk"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: nie można wyszukać odpowiedzi PAP"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: nie można znaleźć drukarek AppleTalk"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: nie można utworzyć adresu AppleTalk"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: nie można otworzyć \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: nie można otworzyć %s: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: nie można otworzyć pliku bannera \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: nie można otworzyć pliku urządzenia \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: nie można otworzyć pliku \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: nie można otworzyć pliku \"%s\": %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: nie można otworzyć pliku wydruku \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: nie można otworzyć pliku wydruku %s - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: nie można otworzyć pliku wydruku %s: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: nie można otworzyć tymczasowego skompresowanego pliku wydruku: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: nie można odczytać danych druku"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: nie można zarezerwować portu"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: nie można przejść do wiersza %ld w pliku - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: nie można przejść do wiersza %lld w pliku - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: nie można wysłać polecenia LPD"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: nie można wysłać żądania PAP tickle"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: nie można wysłać początkowego żądania wysyłania danych PAP"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: nie można wysłać pliku do drukarki"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: nie można wysłać początkowego zera do drukarki"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: nie można czekać na pictwpstops: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: nie można zapisać %d bajtów do \"%s\":%s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: nie można zapisać pliku kontrolnego"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: nie można zapisać danych druku"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: nie można zapisać danych druku: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr "ERROR: nie można zapisać nieskompresowanych danych dokumentu: %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: nieznany porządek plików \"%s\"\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: nieznany znak formatujÄ…cy \"%c\"\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: nieznany tryb druku \"%s\"\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: nieudane select()"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: nie można utworzyć statusu pliku drukowania"
+
+msgid "Edit Configuration File"
+msgstr "Edytuj plik konfiguracji"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Baner końcowy"
+
+msgid "English"
+msgstr "Polish"
+
+msgid "Enter old password:"
+msgstr "Podaj stare hasło:"
+
+msgid "Enter password again:"
+msgstr "Powtórz hasło:"
+
+msgid "Enter password:"
+msgstr "Podaj hasło:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Wprowadź swoje nazwę użytkownika i hasło lub nazwę i hasło użytkownika root, "
+"aby uzyskać dostęp do tej strony. Jeżeli korzystasz z uwierzytelnienia "
+"Kerberos, upewnij się, że posiadasz prawidłowy bilet Kerberos."
+
+msgid "Envelope Feed"
+msgstr "Podajnik kopert"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Zasady obsługi błędów"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "Co 10 etykiet"
+
+msgid "Every 2 Labels"
+msgstr "Co 2 etykiety"
+
+msgid "Every 3 Labels"
+msgstr "Co 3 etykiety"
+
+msgid "Every 4 Labels"
+msgstr "Co 4 etykiety"
+
+msgid "Every 5 Labels"
+msgstr "Co 5 etykiet"
+
+msgid "Every 6 Labels"
+msgstr "Co 6 etykiet"
+
+msgid "Every 7 Labels"
+msgstr "Co 7 etykiet"
+
+msgid "Every 8 Labels"
+msgstr "Co 8 etykiet"
+
+msgid "Every 9 Labels"
+msgstr "Co 9 etykiet"
+
+msgid "Every Label"
+msgstr "Co etykietÄ™"
+
+msgid "Expectation Failed"
+msgstr "Oczekiwana wartość nie do zwrócenia"
+
+msgid "Export Printers to Samba"
+msgstr "Wyeksportuj drukarki do Samby"
+
+msgid "FAIL\n"
+msgstr "PROBLEM\n"
+
+msgid "File Folder"
+msgstr "Folder"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Folder - 9/16 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"URI pliku urządzenia zostało wyłączone! Aby włączyć, zobacz dyrektywę "
+"FileDevice w \"%s/cupsd.conf\"."
+
+msgid "Folio"
+msgstr "Folio"
+
+msgid "Forbidden"
+msgstr "Zabronione"
+
+msgid "General"
+msgstr "Ogólne"
+
+msgid "Generic"
+msgstr "Ogólne"
+
+msgid "German FanFold"
+msgstr "German FanFold"
+
+msgid "German FanFold Legal"
+msgstr "German FanFold Legal"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU używa nieskończonej długości"
+
+msgid "Glossy Paper"
+msgstr "Papier błyszczący"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Szarości"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "WiszÄ…cy folder"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "WiszÄ…cy folder - 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk wyłączone w Preferencjach systemowych\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk wyłączone w Preferencjach systemowych.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: przerywam zlecenie drukowania…\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: połączony z drukarką...\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: Å‚Ä…czÄ™ z drukarkÄ…...\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: udane wysłanie pliku kontrolnego\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr ""
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: udane wysłanie pliku danych\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: formatuję stronę %d…\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: wczytuję plik obrazka…\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: szukam drukarki...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: otwieram połączenie\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr "INFO: wysłano plik drukowania, czekam na zakończenie pracy drukarki…\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: drukarka jest zajęta; ponowię próbę za 10 sekund…\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: drukarka jest zajęta; ponowię próbę za 30 sekund…\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: drukarka jest zajęta; ponowę próbę za 5 sekund…\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr "INFO: drukarka nie obsługuje IPP/%d.%d, próbuję IPP/1.0...\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: drukarka jest zajęta; ponowię próbę za 5 sekund…\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: drukarka jest wyłączona.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: drukarka nie jest obecnie w trybie gotowości.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: drukarka jest w trybie gotowości.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: drukarka nie jest w trybie gotowości.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: drukarka nie jest podłączona; ponowię próbę za 30 sekund…\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: drukuję stronę %d, %d%% zakończonych…\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: drukuję stronę %d…\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: gotowy do drukowania.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: wysyłam plik kontrolny (%lu bajtów)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: wysyłam plik kontrolny (%u bajtów)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: wysyłam dane\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: wysyłam plik danych (%ld bajtów)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: wysyłam plik danych (%lld bajtów)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: wysyłam dane wydruku...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: wysyłam plik drukowania, %ld bajtów…\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: wysyłam plik drukowania, %lld bajtów…\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: Składuję zlecenie LPR, %.0f%% zakończono…\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr ""
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: nie można skontaktować się z drukarką, ustawiam w kolejce następnej "
+"drukarki tej klasy…\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: używam domyślnej strefy AppleTalk \"%s\"\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: czekam na zakończenie zlecenia…\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: czekam, aż drukarka stanie się dostępna...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "Koperta ISO B4"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (Oversize)"
+
+msgid "ISO B5 Envelope"
+msgstr "Koperta ISO B5"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "Koperta ISO B6"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "Polish"
+
+msgid "Illegal control character"
+msgstr "Niedozwolony znak kontrolny"
+
+msgid "Illegal main keyword string"
+msgstr "Niedozwolony główny łańcuch słowa kluczowego"
+
+msgid "Illegal option keyword string"
+msgstr "Niedozwolony łańcuch słowa kluczowego opcji"
+
+msgid "Illegal translation string"
+msgstr "Niedozwolony łańcuch tłumaczenia"
+
+msgid "Illegal whitespace character"
+msgstr "Niedozwolony biały znak"
+
+msgid "Installable Options"
+msgstr "Opcje instalowane"
+
+msgid "Installed"
+msgstr "Zainstalowane"
+
+msgid "IntelliBar Label Printer"
+msgstr "Drukarka etykiet IntelliBar"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr ""
+
+msgid "Internal error"
+msgstr "Błąd wewnętrzny"
+
+msgid "Internet Postage 2-Part"
+msgstr "Etykieta Internet Postage, dwuczęściowa"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Etykieta Internet Postage, dwuczęściowa - 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "Etykieta Internet Postage, trzyczęściowa"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Etykieta Internet Postage, trzyczęściowa - 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "Internetowy protokół druku"
+
+msgid "Invite Envelope"
+msgstr "Koperta zaproszenia"
+
+msgid "Italian Envelope"
+msgstr "Koperta włoska"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "Zlecenie #%d zostało już przerwane - nie można anulować."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "Zlecenie #%d zostało już anulowane - nie można anulować."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "Zlecenie #%d zostało już zakończone - nie można anulować."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "zlecenie zakończone"
+
+msgid "Job Created"
+msgstr "utworzono zlecenie"
+
+msgid "Job ID: "
+msgstr "ID zlecenia: "
+
+msgid "Job Options Changed"
+msgstr "zmieniono opcje zlecenia"
+
+msgid "Job Stopped"
+msgstr "zlecenie zatrzymane"
+
+msgid "Job UUID: "
+msgstr "UUID zlecenia: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "Zlecenie zostało zakończone i nie może zostać zmienione."
+
+msgid "Job operation failed:"
+msgstr "Operacja zlecenia nie powiodła się:"
+
+msgid "Job state cannot be changed."
+msgstr "Stan zlecenia nie może zostać zmieniony."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "Zlecenia"
+
+msgid "Kaku2 Envelope"
+msgstr "Koperta Kaku2"
+
+msgid "Kaku3 Envelope"
+msgstr "Koperta Kaku3"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "Host lub drukarka LPD/LPR"
+
+msgid "Label Printer"
+msgstr "Drukarka etykiet"
+
+msgid "Label Top"
+msgstr "Wierzch etykiety"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Duży adres"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Duży adres - 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet Series PCL 4/5"
+
+msgid "Light"
+msgstr "Lekki"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Wiersz dłuższy niż maksymalnie dozwolony (255 znaków)"
+
+msgid "List Available Printers"
+msgstr "Pokaż dostępne drukarki"
+
+msgid "Location: "
+msgstr "Miejsce: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "Portretowy"
+
+msgid "Make and Model: "
+msgstr "Marka i model: "
+
+msgid "Manual Feed"
+msgstr "Ręczne podawanie papieru"
+
+msgid "Media Dimensions: "
+msgstr "Wymiary nośnika: "
+
+msgid "Media Limits: "
+msgstr "Ograniczenia nośnika: "
+
+msgid "Media Name: "
+msgstr "Nazwa nośnika: "
+
+msgid "Media Size"
+msgstr "Rozmiar nośnika"
+
+msgid "Media Source"
+msgstr "Źródło nośnika"
+
+msgid "Media Tracking"
+msgstr "Śledzenie nośnika"
+
+msgid "Media Type"
+msgstr "Rodzaj nośnika"
+
+msgid "Medium"
+msgstr "Åšredni"
+
+msgid "Memory allocation error"
+msgstr "Błąd przydziału pamięci"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "Brakujący nagłówek PPD-Adobe-4.x"
+
+msgid "Missing asterisk in column 1"
+msgstr "BrakujÄ…ca gwiazdka w kolumnie 1"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "Brakujący łańcuch wartości"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "Zmień klasę"
+
+msgid "Modify Printer"
+msgstr "Zmień drukarkę"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Koperta Monarch"
+
+msgid "Move All Jobs"
+msgstr "PrzenieÅ› wszystkie zlecenia"
+
+msgid "Move Job"
+msgstr "PrzenieÅ› zlecenie"
+
+msgid "Moved Permanently"
+msgstr "Trwale przeniesione"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: zaakceptowano plik druku - ID zlecenia %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: zaakceptowano plik drukowania - nieznane ID zlecenia.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "PUSTY wskaźnik pliku PPD"
+
+msgid "Name OID uses indefinite length"
+msgstr "OID nazwy używa nieskończonej długości"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Nigdy"
+
+msgid "New Stylus Color Series"
+msgstr "New Stylus Color Series"
+
+msgid "New Stylus Photo Series"
+msgstr "New Stylus Photo Series"
+
+msgid "No"
+msgstr "Nie"
+
+msgid "No Content"
+msgstr "Brak zawartości"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "Brak VarBind SEQUENCE"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "Brak aktywnego połączenia"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "Brak community name"
+
+msgid "No default printer"
+msgstr "Brak domyślnej drukarki"
+
+msgid "No destinations added."
+msgstr "Nie dodano celów."
+
+msgid "No error-index"
+msgstr "Brak error-index"
+
+msgid "No error-status"
+msgstr "Brak error-status"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "Brak OID nazwy"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "Brak request-id"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "Błędne ID subskrypcji."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "Brak variable-bindings SEQUENCE"
+
+msgid "No version number"
+msgstr "Brak nazwy wersji"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "Nieciągły (Mark sensing)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "Nieciągły (Web sensing)"
+
+msgid "Normal"
+msgstr "Zwykły"
+
+msgid "Not Found"
+msgstr "Nie znaleziono"
+
+msgid "Not Implemented"
+msgstr "Niezaimplementowane"
+
+msgid "Not Installed"
+msgstr "Niezainstalowane"
+
+msgid "Not Modified"
+msgstr "Niezmienione"
+
+msgid "Not Supported"
+msgstr "Nieobsługiwane"
+
+msgid "Not allowed to print."
+msgstr "Brak zgody na druk."
+
+msgid "Note"
+msgstr "Notatka"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Off (1-Sided)"
+msgstr "Jednostronny"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Pomoc internetowa"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "Otwarcie %s nie powiodło się: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup nie poprzedzony przez CloseGroup"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI nie poprzedzony przez CloseUI/JCLCloseUI"
+
+msgid "Operation Policy"
+msgstr "Polityka operacji"
+
+msgid "Options Installed"
+msgstr "Zainstalowane opcje"
+
+msgid "Options: "
+msgstr "Opcje: "
+
+msgid "Output Mode"
+msgstr "Tryb wyjścia"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "Wyjście dla drukarki %s zostało wysłane do %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr "Wyjście dla drukarki %s zostało wysłane do zdalnej drukarki %s na %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "Wyjście dla drukarki %s/%s zostało wysłane do %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr ""
+"Wyjście dla drukarki %s/%s zostało wysłane do zdalnej drukarki %s na %s\n"
+
+msgid "PASS\n"
+msgstr "SUKCES\n"
+
+msgid "PCL Laser Printer"
+msgstr "Drukarka laserowa PCL"
+
+msgid "PRC1 Envelope"
+msgstr "Koperta PRC1"
+
+msgid "PRC10 Envelope"
+msgstr "Koperta PRC10"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "Koperta PRC2"
+
+msgid "PRC3 Envelope"
+msgstr "Koperta PRC3"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (oversize)"
+
+msgid "PRC4 Envelope"
+msgstr "Koperta PRC4"
+
+msgid "PRC5 Envelope"
+msgstr "Koperta PRC5"
+
+msgid "PRC6 Envelope"
+msgstr "Koperta PRC6"
+
+msgid "PRC7 Envelope"
+msgstr "Koperta PRC7"
+
+msgid "PRC8 Envelope"
+msgstr "Koperta PRC8"
+
+msgid "PRC9 Envelope"
+msgstr "Koperta PRC9"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "Pakiet nie zawiera Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "Pakiet nie rozpoczyna siÄ™ od SEQUENCE"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "Hasło dla %s na %s? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "Wymagane jest hasło dla %s, aby uzyskać dostęp do %s przez Sambę:"
+
+msgid "Pause Class"
+msgstr "Wstrzymanie klasy"
+
+msgid "Pause Printer"
+msgstr "Wstrzymanie drukarki"
+
+msgid "Peel-Off"
+msgstr "Peel-Off"
+
+msgid "Personal Envelope"
+msgstr "Koperta osobista"
+
+msgid "Photo"
+msgstr "Zdjęcie"
+
+msgid "Photo Labels"
+msgstr "Etykiety zdjęć"
+
+msgid "Plain Paper"
+msgstr "Zwykły papier"
+
+msgid "Policies"
+msgstr "Zasady"
+
+msgid "Port Monitor"
+msgstr "Monitor portów"
+
+msgid "PostScript Printer"
+msgstr "Drukarka PostScriptowa"
+
+msgid "Postcard"
+msgstr "Kartka pocztowa"
+
+msgid "Print Density"
+msgstr "Gęstość druku"
+
+msgid "Print Job:"
+msgstr "Zlecenie drukowania:"
+
+msgid "Print Mode"
+msgstr "Tryb drukowania"
+
+msgid "Print Rate"
+msgstr "Prędkość drukowania"
+
+msgid "Print Self-Test Page"
+msgstr "Drukuj stronÄ™ testowÄ…"
+
+msgid "Print Speed"
+msgstr "Prędkość druku"
+
+msgid "Print Test Page"
+msgstr "Wydrukuj stronę próbną"
+
+msgid "Print and Cut"
+msgstr "Drukuj i obetnij"
+
+msgid "Print and Tear"
+msgstr "Drukuj i oderwij"
+
+msgid "Printed For: "
+msgstr "Druk dla: "
+
+msgid "Printed From: "
+msgstr "Druk z: "
+
+msgid "Printed On: "
+msgstr "Druk na: "
+
+msgid "Printer Added"
+msgstr "Dodano drukarkÄ™"
+
+msgid "Printer Default"
+msgstr "Domyślna drukarka"
+
+msgid "Printer Deleted"
+msgstr "Usunięto drukarkę"
+
+msgid "Printer Modified"
+msgstr "Zmieniono drukarkÄ™"
+
+msgid "Printer Name: "
+msgstr "Nazwa drukarki: "
+
+msgid "Printer Paused"
+msgstr "Drukarka wstrzymana"
+
+msgid "Printer Settings"
+msgstr "Ustawienia drukarki"
+
+msgid "Printer:"
+msgstr "Drukarka:"
+
+msgid "Printers"
+msgstr "Drukarki"
+
+msgid "Purge Jobs"
+msgstr "Wyczyść zlecenia"
+
+msgid "Quarto"
+msgstr "Quarto"
+
+msgid "Quota limit reached."
+msgstr "Przekroczono limit miejsca."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr ""
+"Kolejność Właściciel Zlecenie Pliki "
+"Całkowity rozmiar\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"Kolejność Właściciel Drukowanie Zlecenie "
+"Pliki Całkowity rozmiar\n"
+
+msgid "Reject Jobs"
+msgstr "Odrzuć zlecenia"
+
+msgid "Reprint After Error"
+msgstr "Drukuj ponownie po błędzie"
+
+msgid "Request Entity Too Large"
+msgstr "Encja zapytania zbyt długa"
+
+msgid "Resolution"
+msgstr "Rozdzielczość"
+
+msgid "Resume Class"
+msgstr "Wznowienie klasy"
+
+msgid "Resume Printer"
+msgstr "Wznowienie drukarki"
+
+msgid "Return Address"
+msgstr "Adres nadawcy"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Adres nadawcy - 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "Przewiń"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Uruchamiam polecenie: %s %s -N -A %s -c \"%s\"\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE używa nieskończonej długości"
+
+msgid "See Other"
+msgstr "Zobacz inne"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "Port szeregowy #%d"
+
+msgid "Server Restarted"
+msgstr "Uruchomiono serwer ponownie"
+
+msgid "Server Security Auditing"
+msgstr "Sprawdzenie bezpieczeństwa serwera"
+
+msgid "Server Started"
+msgstr "Uruchomiono serwer"
+
+msgid "Server Stopped"
+msgstr "Zatrzymano serwer"
+
+msgid "Service Unavailable"
+msgstr "Usługa niedostępna"
+
+msgid "Set Allowed Users"
+msgstr "Ustaw dozwolonych użytkowników"
+
+msgid "Set As Server Default"
+msgstr "Ustaw jako domyślne serwera"
+
+msgid "Set Class Options"
+msgstr "Ustaw opcje klasy"
+
+msgid "Set Printer Options"
+msgstr "Ustaw opcje drukarki"
+
+msgid "Set Publishing"
+msgstr "Ustaw publikowanie"
+
+msgid "Shipping Address"
+msgstr "Adres wysyłki"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "Adres wysyłki - 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "Poziome"
+
+msgid "Special Paper"
+msgstr "Papier specjalny"
+
+msgid "Standard"
+msgstr "Standardowy"
+
+msgid "Starting Banner"
+msgstr "Uruchamiam baner"
+
+msgid "Statement"
+msgstr "Stwierdzenie"
+
+msgid "Stylus Color Series"
+msgstr "Stylus Color Series"
+
+msgid "Stylus Photo Series"
+msgstr "Stylus Photo Series"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "Przełączanie protokołów"
+
+msgid "Tabloid"
+msgstr "Tabloid"
+
+msgid "Tabloid (Oversize)"
+msgstr "Tabloid (oversize)"
+
+msgid "Tear"
+msgstr "Tear"
+
+msgid "Tear-Off"
+msgstr "Tear-Off"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Korekcja pozycji odrywania"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "Nie można znaleźć pliku PPD \"%s\"."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "Nie można otworzyć pliku PPD \"%s\": %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Nazwa klasy może zawierać tylko do 127 drukowalnych znaków i nie może "
+"zawierać spacji, ukośników (/) lub znaku #."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+"Cecha notify-lease-duration nie może być używana z subskrypcjami zadań."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Nazwa drukarki może zawierać tylko do 127 drukowalnych znaków i nie może "
+"zawierać spacji, ukośników (/) lub znaku #."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "Drukarka lub klasa nie została znaleziona."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "printer-uri \"%s\" zawiera nieprawidłowe znaki."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr ""
+"printer-uri musi być w formie \"ipp://NAZWA_KOMPUTERA/classes/NAZWA_KLASY\"."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+"printer-uri musi być w formie \"ipp://NAZWA_KOMPUTERA/printers/NAZWA_DRUKARKI"
+"\"."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"Nazwa subskrypcji nie może zawierać spacji, ukośników (/), pytajników (?) "
+"lub znaku #."
+
+msgid "There are too many subscriptions."
+msgstr "Jest zbyt wiele subskrypcji."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "Nośnik druku termicznego"
+
+msgid "Title: "
+msgstr "Tytuł: "
+
+msgid "Too many active jobs."
+msgstr "Za dużo aktywnych zadań."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "Przezroczystość"
+
+msgid "Tray"
+msgstr "Podajnik"
+
+msgid "Tray 1"
+msgstr "Podajnik 1"
+
+msgid "Tray 2"
+msgstr "Podajnik 2"
+
+msgid "Tray 3"
+msgstr "Podajnik 3"
+
+msgid "Tray 4"
+msgstr "Podajnik 4"
+
+msgid "URI Too Long"
+msgstr "Zbyt długi URI"
+
+msgid "US Executive"
+msgstr "US Executive"
+
+msgid "US Fanfold"
+msgstr "US Fanfold"
+
+msgid "US Ledger"
+msgstr "US Ledger"
+
+msgid "US Legal"
+msgstr "US Legal"
+
+msgid "US Legal (Oversize)"
+msgstr "US Legal (Oversize)"
+
+msgid "US Letter"
+msgstr "US Letter"
+
+msgid "US Letter (Oversize)"
+msgstr "US Letter (Oversize)"
+
+msgid "US Letter (Small)"
+msgstr "US Letter (Small)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "Port szeregowy USB #%d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "Nie można uzyskać dostępu do pliku cupsd.conf:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "Nie można dodać subskrypcji RSS:"
+
+msgid "Unable to add class:"
+msgstr "Nie można dodać klasy:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "Nie można dodać drukarki:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "Nie można wycofać subskrypcji RSS:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "Nie można zmienić cechy printer-is-shared:"
+
+msgid "Unable to change printer:"
+msgstr "Nie można zmienić drukarki:"
+
+msgid "Unable to change server settings:"
+msgstr "Nie można zmienić ustawień serwera:"
+
+msgid "Unable to connect to host."
+msgstr "Nie można połączyć się z hostem."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "Nie można utworzyć pliku tymczasowego:"
+
+msgid "Unable to delete class:"
+msgstr "Nie można usunąć klasy:"
+
+msgid "Unable to delete printer:"
+msgstr "Nie można usunąć drukarki:"
+
+msgid "Unable to do maintenance command:"
+msgstr "Nie można wykonać polecenia konserwacji:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "Nie można uzyskać listy klas:"
+
+msgid "Unable to get class status:"
+msgstr "Nie można uzyskać statusu klasy:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "Nie można uzyskać listy sterowników drukarek:"
+
+msgid "Unable to get printer attributes:"
+msgstr "Nie można uzyskać cech drukarki:"
+
+msgid "Unable to get printer list:"
+msgstr "Nie można uzyskać listy drukarek:"
+
+msgid "Unable to get printer status:"
+msgstr "Nie można uzyskać statusu drukarki:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "Nie można zmienić klasy:"
+
+msgid "Unable to modify printer:"
+msgstr "Nie można zmienić drukarki:"
+
+msgid "Unable to move job"
+msgstr "Nie można przenieść zlecenia"
+
+msgid "Unable to move jobs"
+msgstr "Nie można przenieść zadań"
+
+msgid "Unable to open PPD file"
+msgstr "Nie można otworzyć pliku PPD"
+
+msgid "Unable to open PPD file:"
+msgstr "Nie można otworzyć pliku PPD:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "Nie można otworzyć pliku cupsd.conf:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "Nie można wydrukować strony testowej:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "Nie można uruchomić \"%s\": %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "Nie można ustawić opcji:"
+
+msgid "Unable to set server default:"
+msgstr "Nie można ustalić domyślnych parametrów serwera:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "Nie można wysłać pliku cupsd.conf:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "Brak uwierzytelnienia"
+
+msgid "Units"
+msgstr "Jednostki"
+
+msgid "Unknown"
+msgstr "Nieznane"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "Nieznane printer-error-policy \"%s\"!"
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "Nieznane printer-op-policy \"%s\"."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Nieobsługiwany rodzaj wartości"
+
+msgid "Upgrade Required"
+msgstr "Wymagane uaktualnienie"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Użycie:\n"
+"\n"
+" lpadmin [-h serwer] -d cel\n"
+" lpadmin [-h serwer] -x cel\n"
+" lpadmin [-h serwer] -p drukarka [-c dodaj-klasÄ™] [-i interfejs] [-m "
+"model]\n"
+" [-r usuń-klasę] [-v urządzenie] [-D opis]\n"
+" [-P plik-ppd] [-o nazwa=wartość]\n"
+" [-u zezwól:użytkownik,użytkownik] [-u zabroń:"
+"użytkownik,użytkownik]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "Użycie: %s zlecenie użytkownik tytuł liczba_kopii opcje [plik]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "Użycie: %s id_zlecenia użytkownik tytuł liczba_kopii opcje [plik]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "Użycie: %s id_zlecenia użytkownik tytuł liczba_kopii opcje plik\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Użycie: cupsaddsmb [opcje] drukarka1 ... drukarkaN\n"
+" cupsaddsmb [opcje] -a\n"
+"\n"
+"Opcje:\n"
+" -E Szyfruj połączenie z serwerem\n"
+" -H serwer_samba Użyj nazwy serwera SAMBA\n"
+" -U użytkownik_samba Uwierzytelnienie nazwą użytkownika SAMBA\n"
+" -a Eksportuj wszystkie drukarki\n"
+" -h serwer_cups Użyj nazwy serwera CUPS\n"
+" -v Podgląd (wyświetla polecenia)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Użycie: cupsctl [opcje] [param=wartość ... paramN=wartośćN]\n"
+"\n"
+"Opcje:\n"
+"\n"
+" -E WÅ‚Ä…cz szyfrowanie\n"
+" -U nazwa_użytkownika Określ nazwę użytkownika\n"
+" -h serwer[:port] Określ adres serwera\n"
+"\n"
+" --[no-]debug-logging Włącz lub wyłącz dziennik błędów\n"
+" --[no-]remote-admin Włącz lub wyłącz zdalną administrację\n"
+" --[no-]remote-any Pozwól lub zabroń dostęp przez Internet\n"
+" --[no-]remote-printers Pokaż lub ukryj zdalne drukarki\n"
+" --[no-]share-printers Włącz lub wyłącz udostępnianie drukarek\n"
+" --[no-]user-cancel-any Pozwól lub zabroń użytkownikom anulowanie "
+"dowolnego zlecenia\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Użycie: cupsd [-c plik-konfiguracji] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c plik-konfiguracji Wczytuje alternatywny plik konfiguracji\n"
+"-f Uruchamia na pierwszym planie\n"
+"-F Uruchamia na pierwszym planie, ale odłączone\n"
+"-h Wyświetla wiadomości o użyciu\n"
+"-l Uruchamia cupsd z launchd(8)\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Użycie: cupstestdsc [opcje] nazwapliku.ps [... nazwapliku.ps]\n"
+" cupstestdsc [opcje] -\n"
+"\n"
+"Opcje:\n"
+"\n"
+" -h Wyświetla użycie programu\n"
+"\n"
+" Uwaga: ten program sprawdza tylko komentarze DSC, nie PostScriptowe.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Użycie: lpmove zlecenie/źródło cel\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Użycie: lpoptions [-h serwer] [-E] -d drukarka\n"
+" lpoptions [-h serwer] [-E] [-p drukarka] -l\n"
+" lpoptions [-h serwer] [-E] -p drukarka -o opcja[=wartość] ...\n"
+" lpoptions [-h serwer] [-E] -x drukarka\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Użycie: lppasswd [-g nazwagrupy]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Użycie: lppasswd [-g nazwagrupy] [nazwaużytkownika]\n"
+" lppasswd [-g nazwagrupy] -a [nazwaużytkownika]\n"
+" lppasswd [-g nazwagrupy] -x [nazwaużytkownika]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Użycie: lpq [-P cel] [-U nazwaużytkownika] [-h nazwakomputera[:port]] [-l] "
+"[+przerwanie]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Użycie: ppdc [opcje] plik.drv [ ... plikN.drv ]\n"
+"Opcje:\n"
+" -D nazwa=wartość Przypisuje wartość nazwanej zmiennej.\n"
+" -I katalog-dołączeń Dodaje katalog do ścieżki wyszukiwania.\n"
+" -c katalog.po Wczytuje podany katalog komunikatów.\n"
+" -d katalog-wyjściowy Wybiera katalog wyjściowy.\n"
+" -l język[,język,...] Ustala języki wyjścia (locale).\n"
+" -m Używa nazwy ModelName jako nazwy pliku.\n"
+" -t Testuje pliki PPD zamiast je generować.\n"
+" -v Dodatkowe informacje (im więcej opcji v, tym więcej "
+"informacji).\n"
+" -z Kompresuje plik PPD za pomocÄ… GNU zip.\n"
+" --cr Znaki końca wiersza to CR (Mac OS 9).\n"
+" --crlf Znaki końca wiersza to CR+LF (Windows).\n"
+" --lf Znaki końca wiersza to LF (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"Użycie: ppdhtml [opcje] plik.drv >plik.html\n"
+" -D nazwa=wartość Przypisuje wartość nazwanej zmiennej.\n"
+"Opcje:\n"
+" -I katalog-dołączeń Dodaje katalog do ścieżki wyszukiwania.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Użycie: ppdi [opcje] plik.ppd [ ... plikN.ppd ]\n"
+"Opcje:\n"
+" -I katalog-dołączeń\n"
+" -o plik.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Użycie: ppdmerge [opcje] plik.ppd [ ... plikN.ppd ]\n"
+"Opcje:\n"
+" -o plik.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"Użycie: ppdpo [opcje] -o plik.po plik.drv [ ... plikN.drv ]\n"
+"Opcje:\n"
+" -D nazwa=wartość Przypisuje nazwanej zmiennej podaną wartość.\n"
+" -I katalog-dołączeń Dodaje katalog do ścieżki wyszukiwania.\n"
+" -v Dodatkowe informacje (im więcej opcji v, tym więcej "
+"informacji).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Użycie: snmp [serwer_lub_adres_ip]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Wartość używa nieskończonej długości"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind używa nieskończonej długości"
+
+msgid "Version uses indefinite length"
+msgstr "Version używa nieskończonej długości"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: dodajÄ™ tylko pierwszych %d znalezionych drukarek"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: dla opcji waiteof oczekiwano wartości logicznej \"%s\"\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: drukarka nie odpowiada\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: drukarka wysłała niespodziewany EOF\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: nie można otworzyć \"%s:%s\": %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: nie da się wysłać żądania statusu PAP"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: niespodziewany pakiet PAP typu %d\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: nieznany pakiet PAP typu %d\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: spodziewana liczba dla opcji statusu \"%s\"\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Tak"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"Aby uzyskać dostęp do tej strony, użyj URL <A HREF=\"https://%s:%d%s"
+"\">https://%s:%d%s</A>."
+
+msgid "You4 Envelope"
+msgstr "Koperta You4"
+
+msgid "ZPL Label Printer"
+msgstr "Drukarka etykiet ZPL"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "przerwane"
+
+msgid "canceled"
+msgstr "anulowane"
+
+msgid "completed"
+msgstr "zakończone"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr "convert: użyj opcji -f, aby wskazać plik do konwersji.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "Nie powiodło się wykonanie cups-deviced."
+
+msgid "cups-driverd failed to execute."
+msgstr "Nie powiodło się wykonanie cups-driverd."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: brak pliku PPD dla drukarki \"%s\" - %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: nie można się połączyć z serwerem: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr ""
+"cupsd: obsługa launchd(8) nie została wkompilowana, uruchamianie w normalnym "
+"trybie.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: nie da się uzyskać pliku zlecenia - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd: opcja -q jest niezgodna z opcjÄ… -v.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd: opcja -v jest niezgodna z opcjÄ… -q.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "urzÄ…dzenie dla %s/%s: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "urzÄ…dzenie dla %s: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "error-index używa nieskończonej długości"
+
+msgid "error-status uses indefinite length"
+msgstr "error-status używa nieskończonej długości"
+
+msgid "held"
+msgstr "wstrzymane"
+
+msgid "help\t\tget help on commands\n"
+msgstr "help\t\tpomoc na temat poleceń\n"
+
+msgid "idle"
+msgstr "bezczynna"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: drukarka %s jest już elementem klasy %s.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: drukarka %s nie jest elementem klasy %s.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: nie można połączyć się do serwera: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: nie można otworzyć pliku PPD \"%s\" - %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: nie można otworzyć pliku \"%s\": %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: nie można połączyć się z serwerem: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: nie można dodać drukarki lub przykładu: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: nie można otworzyć pliku PPD dla %s: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: przepraszam, hasło zostało odrzucone.\n"
+"Hasło musi mieć co najmniej 6 znaków, nie może zawierać nazwy\n"
+"użytkownika i musi zawierać co najmniej jedną literę i liczbę.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: nie można skopiować łańcucha hasła: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: nie można otworzyć pliku hasła: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: nie można zapisać do pliku hasła: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr ""
+"lppasswd: utworzenie kopii zapasowej starego pliku hasła nie powiodło się: %"
+"s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: zmiana nazwy pliku hasła nie powiodła się: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: użytkownik \"%s\" i grupa \"%s\" nie istnieją.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "elementy klasy %s:\n"
+
+msgid "no entries\n"
+msgstr "brak wpisów\n"
+
+msgid "no system default destination\n"
+msgstr "brak domyślnego celu systemowego\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "oczekujÄ…ce"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: dodaję katalog dołączeń \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: dodajÄ™/uaktualniam tekst UI z %s...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: nieprawidłowa wartość logiczna (%s), linia %d w %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: nieprawidłowe zastąpienie zmiennej ($%c), linia %d w %s.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: w linii %d %s spodziewana jest wartość logiczna.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: w linii %d %s spodziewany jest kod wyboru.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: w linii %d %s spodziewana jest nazwa/tekst wyboru.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: wczytujÄ™ plik informacyjny sterownika \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: wczytujÄ™ komunikaty locale \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: wczytujÄ™ komunikaty z \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: nie można utworzyć pliku PPD \"%s\" - %s.\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: nie można utworzyć katalogu wyjścia %s: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: nie można utworzyć potoku wyjścia: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: nie można wykonać cupstestppd: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: nie można znaleźć lokalizacji dla \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: nie można wczytać lokalizacji dla \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: niezdefiniowana zmienna (%s), linia %d w %s.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: zapisujÄ™ %s...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: zapisujÄ™ pliki PPD do katalogu \"%s\"...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: ignorujÄ™ plik PPD %s...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: nie można wykonać kopii zapasowej %s w %s- %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "drukarka %s jest wyłączona od %s -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "drukarka %s jest bezczynna. włączona od %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "drukarka %s drukuje teraz %s-%d. włączona od %s\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "drukarka %s/%s jest wyłączona od %s -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "drukarka %s/%s jest bezczynna. włączona od %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "drukarka %s/%s drukuje teraz %s-%d. włączona od %s\n"
+
+msgid "processing"
+msgstr "przetwarzane"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "ID żądania to %s-%d (%d plików)\n"
+
+msgid "request-id uses indefinite length"
+msgstr "request-id używa nieskończonej długości"
+
+msgid "scheduler is not running\n"
+msgstr "planista nie jest uruchomiony"
+
+msgid "scheduler is running\n"
+msgstr "planista jest uruchomiony\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "użycie stat z %s nie powiodło się: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "status\t\twyświetla stan demonów i kolejki\n"
+
+msgid "stopped"
+msgstr "zlecenie zatrzymane"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "domyślny cel systemowy: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "domyślny cel systemowy: %s/%s\n"
+
+msgid "unknown"
+msgstr "nieznane"
+
+msgid "untitled"
+msgstr "nienazwane"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindings używa nieskończonej długości"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " OSTRZEŻENIE %s nie posiada odpowiadających opcji!\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " OSTRZEŻENIE Konflikt domyślnych wyborów!\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " OSTRZEŻENIE Podwójna opcja słowo kluczowe %s może nie działać "
+#~ "w spodziewany sposób i powinno nosić nazwę Podwójne!\n"
+#~ " REF: strona 122, sekcja 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " OSTRZEŻENIE Plik zawiera mieszaninę zakończeń wierszy CR, LF i "
+#~ "CR LF!\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " OSTRZEŻENIE Wiersz %d zawiera wyłącznie białe spacje!\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " OSTRZEŻENIE Brakujący plik APDialogExtension \"%s\"\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " OSTRZEŻENIE Brakujący plik APPrinterIconPath \"%s\"\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " OSTRZEŻENIE Pliki PPD nie przeznaczone dla Windows powinny "
+#~ "używać tylko zakończeń wierszy LF, nie CR LF!"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " OSTRZEŻENIE Przestarzała wersja PPD %.1f!\n"
+#~ " REF: strona 42, sekcja 5.2.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s nie istnieje!\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s Zły wybór %s, %s!\n"
+#~ " REF: strona 122, sekcja 5.17\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr ""
+#~ " %s Nieprawidłowy UTF-8 łańcucha tekstowegi tłumaczenia \"%s\" dla "
+#~ "opcji %s!\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Nieprawidłowy UTF-8 łańcucha tekstowego tłumaczenia \"%s\" dla "
+#~ "opcji %s, wybór %s!\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Błędna wartość cupsFilter \"%s\"!\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s Nieprawidłowy profil cupsICCProfile %s!\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Błędna wartość cupsPreFilter \"%s\"!\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Błędna wartość cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s Błędny język \"%s\"!\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s Puste cupsUIConstraints %s!\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr ""
+#~ " %s Brakujący łańcuch tekstowy tłumaczenia \"%s\" dla opcji %s!\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Brakujący łańcuch tekstowy tłumaczenia \"%s\" dla opcji %s, "
+#~ "wybór %s!\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Brakujący wybór *%s %s w UIConstraints \"*%s %s *%s %s\"!\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Brakujący wybór *%s %s w cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s BrakujÄ…cy plik cupsICCProfile \"%s\"!\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s BrakujÄ…cy cupsUIResolver %s!\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr " %s BrakujÄ…ca opcja %s w UIConstraints \"*%s %s *%s %s\"!\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s BrakujÄ…ca opcja %s w cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr " %s Brak podstawowego tłumaczenia \"%s\" zawartego w pliku!\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s WYMAGANE %s nie defuniuje wyboru Brak!\n"
+#~ " REF: strona 122, sekcja 5.17\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " %s cupsICCProfile %s skrót koliduje z %s!\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver %s powoduje pętlę!\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **PROBLEM** %s nazwy wyborów %s i %s różnią się tylko wielkością "
+#~ "liter!\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **PROBLEM** %s musi być 1284DeviceID!\n"
+#~ " REF: strona 72, sekcja 5.5\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **PROBLEM** BÅĘDNA wartość DefaultImageableArea %s!\n"
+#~ " REF: strona 102, sekcja 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **PROBLEM** BÅĘDNA wartość DefaultPaperDimension %s!\n"
+#~ " REF: strona 103, sekcja 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **PROBLEM** Błędny %s wybór %s!\n"
+#~ " REF: strona 84, sekcja 5.9\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr ""
+#~ " **PROBLEM** Błędna wartość LanguageEncoding %s - musi być "
+#~ "ISOLatin1!\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr ""
+#~ " **PROBLEM** Błędna wartość LanguageVersion %s - musi być "
+#~ "angielski!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **PROBLEM** Domyślny łańcuch tekstowy tłumaczenia dla opcji %s "
+#~ "wyboru %s zawiera 8 bitowe znaki!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **PROBLEM** Nie można zinterpretować domyślnego kodu opcji: %s\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **PROBLEM** Nazwy grup %s i %s różnią się tylko wielkością liter!\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **FAIL** Wielokrotne wystÄ…pienia nazwy wyboru %s, %s!\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **PROBLEM** Nazwy opcji %s i %s różnią się tylko wielkością "
+#~ "liter!\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " Błędna wartość %%%%BoundingBox: w wierszu %d!\n"
+#~ " REF: strona 39, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " Błędna wartość %%%%Page: w wierszu %d!\n"
+#~ " REF: strona 53, %%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " Błędna wartość %%%%Pages: w wierszu %d!\n"
+#~ " REF: strona 43, %%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " Wiersz %d jest dłuższy niż 255 znaków (%d)!\n"
+#~ " REF: strona 25, Długość wiersza\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " BrakujÄ…ce %!PS-Adobe-3.0 w pierwszym wierszu!\n"
+#~ " REF: strona 17, 3.1 Podporządkowywanie dokumentów\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " BrakujÄ…cy komentarz %%EndComments!\n"
+#~ " REF: strona 41, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " Brakujący lub błędny komentarz %%BoundingBox:!\n"
+#~ " REF: strona 39, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " Brakujące lub błędne komentarze %%Page:!\n"
+#~ " REF: strona 53, %%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " Brakujący lub błędny komentarz %%Pages:!\n"
+#~ " REF: strona 43, %%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " Znaleziono %d wierszy przekraczających 255 znaków!\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " Zbyt wiele komentarzy %%BeginDocument!\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " Zbyt wiele komentarzy %%EndDocument!\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " Ostrzeżenie: plik zawiera dane binarne!\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " Ostrzeżenie: brak komentarza %%EndComments w pliku!\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " Ostrzeżenie: przestarzała wersja DSC %.1f w pliku!\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s jest nieobsługiwane!"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: nie wiem co robić!\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: błąd - %s nazw zmiennych środowiskowych z nieistniejącym celem \"%s"
+#~ "\"!\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: błąd - błędny ID zlecenia!\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr ""
+#~ "%s: błąd - nie można jednocześnie drukować plików i zmieniać zlecenia!\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: błąd - nie można drukować ze standardowego wejścia, jeśli dostarczone "
+#~ "sÄ… pliki lub ID zlecenia!\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: błąd - oczekiwany zestaw znaków po opcji \"-S\"!\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: błąd - oczekiwany typ zawartości po opcji \"-T\"!\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: błąd - oczekiwane kopie po opcji \"-n\"!\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s: błąd - oczekiwany licznik kopii po opcji \"-#\"!\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: błąd - oczekiwany cel po opcji \"-P\"!\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: błąd - oczekiwany cel po opcji \"-b\"!\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: błąd - oczekiwany cel po opcji \"-d\"!\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: błąd - oczekiwana forma po opcji \"-f\"!\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: błąd - oczekiwana wstrzymana nazwa po opcji \"-H\"!\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: błąd - oczekiwana nazwa komputera po opcji \"-H\"!\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: błąd - oczekiwana nazwa komputera po opcji \"-h\"!\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: błąd - oczekiwana lista trybów po opcji \"-y\"!\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: błąd - oczekiwana nazwa po opcji \"-%c\"!\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s: błąd - oczekiwany łańcuch tekstowy opcji po opcji \"-o\"!\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: błąd - oczekiwana lista stron po opcji \"-P\"!\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: błąd - oczekiwany priorytet po opcji \"-%c\"!\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s: błąd - oczekiwany tekst przyczyny po opcji \"-r\"!\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: błąd - oczekiwany tytuł po opcji \"-t\"!\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s: błąd - oczekiwana nazwa użytkownika po opcji \"-U\"!\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s: błąd - oczekiwana nazwa komputera po opcji \"-u\"!\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: błąd - oczekiwana wartość po opcji \"-%c\"!\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: błąd - wymagane jest \"completed\", \"not-completed\" lub \"all\" po -"
+#~ "W!\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: błąd - planista nie odpowiada!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: błąd - nieznany cel \"%s\"!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: błąd - nieznany cel \"%s/%s\"!\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: błąd - nieznana opcja \"%c\"!\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: błąd - nieznana opcja '%s'!\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: oczekiwany ID zlecenia po opcji \"-i\"!\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: nieprawidłowa nazwa celu na liście \"%s\"!\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr ""
+#~ "%s: wymagany jest ID zlecenia (\"-i id_zlecenia\") po \"-H restart\"!"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: brak filtra do konwersji z %s/%s na %s/%s!\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s: niestety, nie wkompilowano obsługi szyfowania!\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: nie można skontaktować się z serwerem!\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: nie można określić typu MIME \"%s\"!\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s: nie można otworzyć %s - %s\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s: nie można otworzyć %s - %s on line %d.\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s: nie można odczytać bazy danych MIME z \"%s\" lub \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: nieznany cel \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: nieznany cel rodzaju MIME %s/%s!\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: nieznana opcja \"%c\"!\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: nieznane źródło rodzaju MIME %s/%s!\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: ostrzeżenie - modyfikator formatu \"%c\" jest nieobsługiwany - "
+#~ "wyjście może nie być prawidłowe!\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: ostrzeżenie - opcja zestawu znaków została zignorowana!\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: ostrzeżenie - opcja rodzaju zawartości została zignorowana!\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: ostrzeżenie - opcja formularza została zignorowana!\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: ostrzeżenie - opcja trybu została zignorowana!\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: błąd - %s nazw zmiennych środowiskowych z nieistniejącym celem \"%s"
+#~ "\"!\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: błąd - oczekiwana opcja=wartość po opcji \"-o\"!\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "600 DPI (szarości)"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr "Hasło Samby jest wymagany, aby wyeksportować sterowniki drukarek!"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr ""
+#~ "Nazwa użytkownika Samby jest wymagana, aby wyeksportować sterowniki "
+#~ "drukarek!"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "Klasa o nazwie \"%s\" już istnieje!"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "Drukarka o nazwie \"%s\" już istnieje!"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr "Próba ustawienia błędnej wartości %2$d printer-state %1$s!"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "Grupy właściwości są nieuporządkowane (%x < %x)!"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "Błędny URI urządzenia \"%s\"!\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "Błędne device-uri \"%s\"!"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "Błędny schemat device-uri \"%s\"!"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "Błędne document-format \"%s\"!"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Błędny bufor nazwy pliku!"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Błędna wartość job-priority!"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Błędna wartość job-sheets \"%s\"!"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Błędny rodzaj wartości job-sheets!"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Błędna wartość job-state!"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Błędna właściwość job-uri \"%s\"!"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "Błędne notify-pull-method \"%s\"!"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "Błędne notify-recipient-uri URI \"%s\"!"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "Błędna opcja + wybór w wierszu %d!\n"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "Błędne port-monitor \"%s\"!"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Błędna wartość printer-state %d!"
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "Błędny numer wersji żądania %d.%d!"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "Błędne ID subskrypcji."
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "Zestaw znaków \"%s\" jest nieobsługiwany!"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "Nie można przeskanować rodzaju \"%s\"!"
+
+#~ msgid "Cover open."
+#~ msgstr "Pokrywa jest otwarta."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "Wywoływacz jest niemal pusty."
+
+#~ msgid "Developer empty!"
+#~ msgstr "Wywoływacz jest pusty!"
+
+#~ msgid "Door open."
+#~ msgstr "Drzwi otwarte."
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: znaleziono nieprawidłowy komentarz %%BoundingBox:!\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: nieprawidłowy komentarz %%IncludeFeature:!\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: nieprawidłowy komentrza %%Page: w pliku!\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: nieprawidłowy komentarz %%PageBoundingBox: w pliku!\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: Błędny plik urządzenia SCSI \"%s\"!\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: nieprawidłowa wartość kolumn %d!\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: nieprawidłowa wartość cpi %f!\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: nieprawidłowa wartość lpi %f!\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: nieprawidłowe ustawienie strony!\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: docelowa drukarka nie istnieje!\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: znaleziono wielokrotny komentarz %%BoundingBox:!\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: znaleziono wielokrotny komentarz %%Pages:!\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: pusty plik druku!\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr "ERROR: spodziewany cytowany znak w linii %d w %s!\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: błąd krytyczny USB!\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr ""
+#~ "ERROR: znaleziono nieprawidłowy komentarz HP-GL/2, nie można wydrukować "
+#~ "pliku!\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: brakujÄ…cy %%EndProlog!\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: brakujÄ…cy %%EndSetup!\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: brak URI urządzenia w wierszu poleceń i zmiennej środowiska "
+#~ "DEVICE_URI!\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: brakująca wartość w linii %d pliku bannera!\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: potrzebna linia msgid przed ciągami tłumaczeń w linii %d w %s!\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: brak komentarza %%BoundingBox: w nagłówku!\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: brak komentarza %%Pages: w nagłówku!\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: nie znaleziono URI urządzenia w argv[0] lub w zmiennej środowiska "
+#~ "DEVICE_URI!\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: nie znaleziono żadnych stron!\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: brak papieru!\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: zmienna środowiska PRINTER nie została określona!\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: plik wydruku nie został zaakceptowany (%s)!\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: drukarka nie odpowiada!\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: nie można utworzyć pliku tymczasowego - %s\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: nie można utworzyć pliku tymczasowego: %s\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: nie można uzyskać cech zlecenia %d (%s)!\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: nie można uzyskać stanu drukarki (%s)!\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: nie można znaleźć drukarki \"%s\"!\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: nie można otworzyć do druku pliku obrazka!\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: nie można otworzyć pliku tymczasowego"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: nie można wydrukować %d łamów tekstu!\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: nie można wydrukować %dx%d strony tekstu!\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: nie można odczytać danych druku!\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: nie można wysłać danych drukowania (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: nie można wysłać danych druku!\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: nie można zapisać %d bajtów do drukarki!\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr "ERROR: nie można zapisać zrastrowanych danych do sterownika!\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: nie można zapisać do pliku tymczasowego"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: niespodziewany tekst w linii %d w %s!\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: nieznana wartość opcji szyfrowania \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: nieznany format katalogu wiadomości \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: nieznana opcja \"%s\" o wartości \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: nieznana wartość opcji wersji \"%s\"!\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr ""
+#~ "ERROR: nieobsługiwana wartość jasności %s, korzystam z jasności=100!\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: nieobsługiwana wartość gamma %s, korzystam z gamma=1000!\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr ""
+#~ "ERROR: nieobsługiwana wartość liczby kopii %d, korzystam z liczby "
+#~ "kopii=1!\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: nieobsługiwana liczba powtórzeń makiety %s, korzystam z liczby "
+#~ "powtórzeń makiety=lrtb!\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: nieobsługiwana wartość ramki strony %s, korzystam z ramki "
+#~ "strony=brak!\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr "ERROR: wykryto przepełnienie doc_printf (%d bajtów), przerywam!\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr "ERROR: filtr pdftops przerwał działanie po sygnale %d!\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr "ERROR: filtr pdftops zakończył działanie ze stanem %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: zakończono pictwpstops po sygnale %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: zakończono pictwpstops ze stanem %d!\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: usuwalny: nie można się połączyć z drukarką; ponowienie próby "
+#~ "nastąpi za 30 sekund…\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "Pusty plik PPD!"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "BÅ‚Ä…d: wymagana jest nazwa serwera po opcji \"-h\"!\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Wysoka temperatura wygrzewacza!"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "Niska temperatura wygrzewacza!"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "Otrzymano właściwość printer-uri, ale bez job-id!"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Tusz lub toner jest niemal pusty."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Tusz lub toner skończył się!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Zbiornik zużytego atramentu lub tonera jest niemal pełny."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Zbiornik zużytego atramentu lub tonera jest pełny!"
+
+#~ msgid "Interlock open."
+#~ msgstr "Rygiel jest otwarty."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "Zlecenie #%d nie może zostać ponownie uruchomione - brak plików!"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "Zlecenie #%d nie istnieje!"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "Zlecenie #%d zostało zakończone i nie może zostać zmienione!"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "Zlecenie #%d nie zostało zakończone!"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "Zlecenie #%d nie zostało wstrzymane do uwierzytelnienia!"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "Zlecenie #%d nie zostało wstrzymane!"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "Zlecenie #%s nie istnieje!"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "Nie znaleziono zlecenia %d!"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "Subskrypcje zlecenia nie mogą zostać ponowione!"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "Język \"%s\" jest nieobsługiwany!"
+
+#~ msgid "Media jam!"
+#~ msgstr "Zacięcie nośnika!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Podajnik nośnika jest niemal pusty."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Podajnik nośnika jest pusty!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Brak podajnika nośnika!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "Trzeba napełnić podajnik nośnika."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "BrakujÄ…cy atrybut document-number!"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "Brakujący cudzysłów w wierszu %d!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "BrakujÄ…ca zmienna formularza!"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "BrakujÄ…ca cecha notify-subscription-ids!"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "Brakuje cecha requesting-user-name!"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "Brakuje wymaganych cech!"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "Brakująca wartość w wierszu %d!"
+
+#~ msgid "No PPD name!"
+#~ msgstr "Brak nazwy PPD!"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Brak zainstalowanych sterowników drukarek dla Windows!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "Brak aktywnych zadań na %s!"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "Brak cech w żądaniu!"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "Nie dostarczono informacji o uwierzytelnianiu!"
+
+#~ msgid "No file!?!"
+#~ msgstr "Brak pliku?!?"
+
+#~ msgid "No modification time!"
+#~ msgstr "Brak czasu zmiany!"
+
+#~ msgid "No printer name!"
+#~ msgstr "Brak nazwy drukarki!"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "Nie znaleziono printer-uri dla tej klasy!"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "Nie znaleziono printer-uri!"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "Żądanie nie zawiera printer-uri!"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "Brak cech subskrypcji w żądaniu!"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC jest niemal zużyty."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC jest zużyty!"
+
+#~ msgid "Out of toner!"
+#~ msgstr "Brak tonera!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Odbiornik jest niemal pełny."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Odbiornik jest pełny!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Brak odbiornika!"
+
+#~ msgid "Printer offline."
+#~ msgstr "Drukarka nie gotowa."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "Drukarka SCSI"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "Wartość notify-user-data jest za duża (%d > 63 oktety)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "Drukarka lub klasa nie jest udostępniana!"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "Wymagana jest cecha printer-uri!"
+
+#~ msgid "Toner low."
+#~ msgstr "Niski poziom tonera."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "Zbyt wiele wartości job-sheets (%d > 2)!"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "Zbyt wiele wartości printer-state-reasons (%d > %d)!"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "Nie można dodać zlecenia do celu \"%s\"!"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "Nie można przydzielić pamięci dla rodzaju plików!"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "Nie można skopiować 64 bitowych plików sterowników drukarek CUPS (%d)!"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr ""
+#~ "Nie można skopiować 64 bitowych plików sterowników drukarek Windows (%d)!"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr "Nie można skopiować plików sterowników drukarek CUPS (%d)!"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "Nie można skopiować pliku PPD - %s!"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "Nie można skopiować pliku PPD!"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr "Nie można skopiować plików sterowników drukarek Windows 2000 (%d)!"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr "Nie można skopiować plików sterowników drukarek Windows 9x (%d)!"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "Nie można skopiować skryptu interfejsu - %s!"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "Nie można utworzyć printer-uri!"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr "Nie można zmienić plików cupsd.conf większych niż 1MB!"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "Nie można znaleźć celu dla zlecenia!"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "Nie można znaleźć drukarki!\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Nie można zainstalować plików sterowników drukarek Windows 2000 (%d)!"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr "Nie można zainstalować plików sterowników drukarek Windows 9x (%d)!"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "Nie można otworzyć dokumentu %d w zleceniu %d!"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "Nie można wysłać polecenia do sterownika drukarki!"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Nie można ustawić sterownika drukarki Windows (%d)!"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "Nie można użyć starszego sterownika USB!\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "Nieznany błąd drukarki (%s)!"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Nieobsługiwany zestaw znaków \"%s\"!"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "Nieobsługiwana kompresja \"%s\"!"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "Nieobsługiwana cecha kompresji %s!"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "Nieobsługiwany format \"%s\"!"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "Nieobsługiwany format \"%s\"!"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "Nieobsługiwany format \"%s/%s\"!"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "Użycie: convert [ opcje ]\n"
+#~ "\n"
+#~ "Opcje:\n"
+#~ "\n"
+#~ " -f plik Wybiera plik do konwersji (gdy pominięte, przyjmuje "
+#~ "stdin)\n"
+#~ " -o plik Wybiera plik do wygenerowania (gdy pominięte, "
+#~ "przyjmuje stdout)\n"
+#~ " -i typ/MIME Typ MIME na wejściu (gdy pominięte, przyjmowany "
+#~ "automatycznie)\n"
+#~ " -j typ/MIME Typ MIME na wyjściu (gdy pominięte, przyjmowany "
+#~ "application/pdf)\n"
+#~ " -P plik.ppd Plik PPD\n"
+#~ " -a 'nazwa=wartość ...' Wybiera opcje\n"
+#~ " -U użytkownik Wybiera nazwę użytkownika dla zlecenia\n"
+#~ " -J tytuł Ustala tytuł\n"
+#~ " -c kopie Ustala liczbÄ™ kopii\n"
+#~ " -u Usuń plik PPD po zakończeniu\n"
+#~ " -D Usuń plik wejściowy po zakończeniu\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "Użycie: cupsfilter -m typ/mime [ opcje ] plik\n"
+#~ "\n"
+#~ "Opcje:\n"
+#~ "\n"
+#~ " -c cupsd.conf Wybiera plik cupsd.conf do użycia\n"
+#~ " -j job-id[,N] Filtruje plik N z podanego zlecenia (domyślnie plik "
+#~ "1)\n"
+#~ " -n kopie Ustala liczbÄ™ kopii\n"
+#~ " -o nazwa=wartość Ustala opcje\n"
+#~ " -p plik.ppd Wybiera plik PPD\n"
+#~ " -t tytuł Ustala tytuł\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Użycie: cupstestppd [options] plik1.ppd[.gz] [... plikN.ppd[.gz]]\n"
+#~ " program | cupstestppd [opcje] -\n"
+#~ "\n"
+#~ "Opcje:\n"
+#~ "\n"
+#~ " -R katalog-główny Ustala inny katalog główny\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Zwraca ostrzeżenia zamiast błędów\n"
+#~ " -q Działa bez komunikatów\n"
+#~ " -r Używaj trybu otwarcia relaxed\n"
+#~ " -v Mniej komunikatów\n"
+#~ " -vv Dużo komunikatów\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: nie można odczytać żądania z kanału bocznego!\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr ""
+#~ "WARNING: Opcja \"%s\" nie może zostać dołączona za pomocą "
+#~ "IncludeFeature!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Serwer zdalny nie odpowiada bajtem statusu polecenia po %d "
+#~ "sekundach!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: zdalny serwer nie odpowiada bajtem statusu kontroli po %d "
+#~ "sekundach!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: zdalny serwer nie odpowiada bajtem statusu danych po %d "
+#~ "sekundach!\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr "WARNING: Upłynął czas oczekiwania polecenia SCSI (%d); ponawiam…\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: Ten dokument nie jest zgodny z KonwencjÄ… struktury dokumentu "
+#~ "Adobe i może nie zostać wydrukowany prawidłowo!\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: Nieznany wybór \"%s\" dla opcji \"%s\"!\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: Nieznana opcja \"%s\"!\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: Nieobsługiwana częstotliwość bodów %s!\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: usuwalny: Serwer sieciowy '%s' jest zajęty; ponowię za %d "
+#~ "sekund...\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr ""
+#~ "Ostrzeżenie, brak zainstalowanych sterowników drukarek Windows 2000!"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: Nieznana opcja \"%s\"!\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: Nieznana opcja \"-%c\"!\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr "cupsd: oczekiwana nazwa pliku konfiguracji po opcji \"-c\"!\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: nie da się uzyskać bieżącego katalogu!\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: nieznany argument \"%s\" - przerywam!\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: nieznana opcja \"%c\" - przerywam!\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: nieprawidłowy numer dokumentu %d!\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: nieprawidłowy kod zlecenia %d!\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: Może być określona tylko jedna nazwa pliku!\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter: nie udało się utworzyć pliku tymczasowego: %s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "Brakuje cechy job-printer-uri!"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr "lpadmin: nazwa klasy może zawierać tylko drukowalne znaki!\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: oczekiwany PPD po opcji \"-P\"!\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr "lpadmin: oczekiwane allow/deny:userlist po opcji \"-u\"!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: oczekiwana klasa po opcji \"-r\"!\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: oczekiwana nazwa klasy po opcji \"-c\"!\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: oczekiwany opis po pocji \"-D\"!\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: oczekiwane URI urzÄ…dzenia po opcji \"-v\"!\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: oczekiwane typy plików po opcji \"-I\"!\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: oczekiwana nazwa komputera po opcji \"-h\"!\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: oczekiwany interfejs po opcji \"-i\"!\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: oczekiwane położenie po opcji \"-L\"!\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: oczekiwany model po opcji \"-m\"!\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: oczekiwana nazwa=wartość po opcji \"-o\"!\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: oczekiwana drukarka po opcji \"-p\"!\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: oczekiwana nazw drukarki po opcji \"-d\"!\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin: oczekiwana drukarka lub klasa po opcji \"-x\"!\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: nie zobaczono żadnych nazw elementów!\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr "lpadmin: nazwa drukarki może zawierać tylko drukowalne znaki!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: nie można dodać drukarki do klasy:\n"
+#~ " Najpierw musi zostać określona nazwa drukarki!\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin: nie można utworzyć pliku tymczasowego - %s\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin: nie można utworzyć pliku tymczasowego: %s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: nie można usunąć drukarki z klasy:\n"
+#~ " Najpierw musi zostać określona nazwa drukarki!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: nie można ustawić pliku PPD:\n"
+#~ " Najpierw musi zostać określona nazwa drukarki!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: nie można ustawić URI urządzenia:\n"
+#~ " Najpierw musi zostać określona nazwa drukarki!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: nie można ustawić skryptu interfejsu lub pliku PPD:\n"
+#~ " Najpierw musi zostać określona nazwa drukarki!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: nie można ustawić skryptu interfejsu:\n"
+#~ " Najpierw musi zostać określona nazwa drukarki!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " Najpierw musi zostać określona nazwa drukarki!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: nie można ustawić położenia drukarki:\n"
+#~ " Najpierw musi zostać określona nazwa drukarki!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: nie można ustawić opcji drukarki:\n"
+#~ " Najpierw musi zostać określona nazwa drukarki!\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: nieznana opcja zezwól/zabroń \"%s\"!\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: nieznany argument \"%s\"!\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: nieznana opcja \"%c\"!\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr ""
+#~ "lpadmin: ostrzeżenie - lista rodzajów zawartości została zignorowana!\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr "lpinfo: po --device-id spodziewany jest ciÄ…g ID urzÄ…dzenia 1284!\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: po --language spodziewany jest język!\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo: po --make-and-model spodziewana jest marka i model!\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr ""
+#~ "lpinfo: po --product spodziewany jest ciÄ…g identyfikujÄ…cy producenta!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo: po --exclude-schemes spodziewana jest lista schematów!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo: po --include-schemes spodziewana jest lista schematów!\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: po --timeout spodziewany jest limit czasu!\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: nieznany argument \"%s\"!\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: nieznana opcja \"%c\"!\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: nieznana opcja '%s'!\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: nieznany argument \"%s\"!\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: nieznana opcja \"%c\"!\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: brak drukarek?!?\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: nie można otworzyć pliku PPD dla %s!\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: nieznana drukarka lub klasa!\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: tylko root może dodać lub usunąć hasła!\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: plik hasła jest zajęty!\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: plik hasła nie został zaktualizowany!\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: przepraszam, hasła się nie zgadzają!\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: przepraszam, hasła się nie zgadzają!\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: błąd - %s nazw zmiennych środowiskowych z nieistniejącym celem \"%"
+#~ "s\"!\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-even jest nieokreślone!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "notify-recipient-uri URI \"%s\" jest już użyte!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "URI notify-recipient-uri \"%s\" wykorzystuje nieznany schemat!"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "%d notify-subscription-id nie dobre!"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: nieprawidłowa nazwa rozdzielczości \"%s\", linia %d w %s!\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: nieprawidłowe słowo kluczowe statusu %s, linia %d w %s!\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc: w linii %d %s jest wybór bez opcji!\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc: powielone #po dla %s, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s spodziewana jest definicja filtra!\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s spodziewana jest nazwa programu!\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s spodziewany jest zestaw znaków po Font!\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: w linii %d %s spodziewana jest kolejność kolorów dla ColorModel!\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: w linii %d %s spodziewana jest przestrzeń kolorów dla ColorModel!\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s spodziewana jest kompresja dla ColorModel!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: w linii %d %s spodziewany ciÄ…g ograniczenia dla UIConstraints!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: w linii %d %s spodziewane słowo kluczowe określające typ sterownika "
+#~ "po DriverType!\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: w linii %d %s spodziewany jest typ druku obustronnego po Duplex!\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s spodziewane jest kodowanie po Font!\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewana jest nazwa pliku po #po dla %s, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s spodziewana jest nazwa grupy/tekst.\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s spodziewana jest nazwa dołączanego pliku.\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s spodziewana jest liczba całkowita.\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewane jest locale po #po dla, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewana jest nazwa po %s, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewana jest nazwa po FileName, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewana jest nazwa po Font, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewana jest nazwa po Manufacturer, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewana jest nazwa po MediaSize, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewana jest nazwa po ModelName, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewana jest nazwa po PCFileName, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewana jest nazwa/tekst po %s, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewana jest nazwa/tekst po Installable, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewana jest nazwa/tekst po Resolution, linia %d w %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: w linii %d %s spodziewana jest kombinacja nazwa/tekst dla "
+#~ "ColorModel!\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s spodziewana jest nazwa opcji/tekst.\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s spodziewana jest nazwa opcji/tekst.\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s spodziewany jest typ opcji/tekst.\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: spodziewane jest pole zastÄ…pienia po Resolution, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s spodziewana jest liczba rzeczywista.\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: w linii %d %s spodziwana jest rozdzielczość/typ nośnika po "
+#~ "ColorProfile!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: w linii %d %s spodziwana jest rozdzielczość/typ nośnika po "
+#~ "SimpleColorProfile!\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewany jest wybieracz po %s, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewany jest status po Font, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewany jest ciąg znaków po Copyright, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewany jest ciąg znaków po Version, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s spodziewane sÄ… dwie nazwy opcji!\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewana jest wartość po %s, linia %d w %s!\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: spodziewana jest wersja po Fon, linia %d w %s!\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: nieprawidłowa nazwa pliku #include/#po \"%s\"!\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: nieprawidłowy koszt filtru w linii %d %s!\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr "ppdc: nieprawidłowy typ MIME dla filtru w linii %d %s!\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: nieprawidłowa pusta nazwa programu dla filtru w linii %d %s!\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: nieprawidłowy wybór opcji \"%s\", linia %d w %s!\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: nieprawidłowy typ opcji \"%s\", linia %d w %s!\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: na końcu \"%s\" brakuje #endif!\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s brakuje #if!\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc: brak katalogu komunikatów w locale %s!\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: opcja %s zdefiniowana ponownie jako inny typ, linia %d w %s!\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr "ppdc: ograniczenie opcji wymaga *name w linii %d %s!\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: w linii %d %s jest zbyt dużo zagnieżdżonych instrukcji #if!\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: nie można znaleźć pliku #po %s, linia %d w %s!\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: nie można znaleźć pliku dołączenia \"%s\", linia %d w %s!\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: nieznany typ sterownika %s, linia %d w %s!\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: nieznany typ obustronny \"%s\", linia %d w %s!\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: nieznana wielkość nośnika \"%s\", linia %d w %s!\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: nieznany znacznik \"%s\", linia %d w %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: nieznane znaki wiodÄ…ce w liczbie rzeczywistej \"%s\", linia %d w %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: niezakończony ciąg znaków, rozpoczynający się od %c, linia %d w %"
+#~ "s!\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: nieprawidłowa wersja LanguageVersion \"%s\" w %s!\n"
diff --git a/locale/cups_pt.po b/locale/cups_pt.po
new file mode 100644
index 000000000..3e22b7f16
--- /dev/null
+++ b/locale/cups_pt.po
@@ -0,0 +1,7151 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-16 12:00-0800\n"
+"Last-Translator: Apple Inc.\n"
+"Language-Team: Apple Inc.\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(tudo)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(sem)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d entradas\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tApós falha: continuar\n"
+
+msgid "\tAlerts:"
+msgstr "\tAlertas:"
+
+msgid "\tBanner required\n"
+msgstr "\tFaixa publicitária requerida\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tConjuntos charset:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tLigação: directa\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tLigação: remota\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tTamanho de página predefinido:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tPitch predefinido:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tPredefinições de porta:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tDescrição: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tFormato montado:\n"
+"\tTipos de conteúdo: qualquer\n"
+"\tTipos de impressora: desconhecido\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tFormatos permitidos:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tInterface: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tInterface: %s/interfaces/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tInterface: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tLocalização: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tEm falha: sem alerta\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tUtilizadores permitidos:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tUtilizadores negados:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tdaemon presente\n"
+
+msgid "\tno entries\n"
+msgstr "\tsem entradas\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\timpressora está no periférico '%s' velocidade -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\timpressão desactivada\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\timpressão activada\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\tem fila para %s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tcolocação em fila desactivada\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tcolocação em fila activada\n"
+
+msgid "\treason unknown\n"
+msgstr "\tmotivo desconhecido\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" RESULTADOS DETALHADOS DO TESTE DE CONFORMIDADE\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " REF: Página 15, secção 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " REF: Página 15, secção 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " REF: Página 19, secção 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " REF: Página 20, secção 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " REF: Página 27, secção 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " REF: Página 42, secção 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " REF: Páginas 16-17, secção 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " REF: Páginas 42-45, secção 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " REF: Páginas 45-46, secção 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " REF: Páginas 48-49, secção 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " REF: Páginas 52-54, secção 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f bytes\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " PASS Predefinição%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " PASS DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " PASS DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " PASS FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " PASS FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " PASS LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " PASS LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " PASS Fabricante\n"
+
+msgid " PASS ModelName\n"
+msgstr " PASS ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " PASS NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " PASS PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " PASS PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " PASS PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " PASS PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " PASS Produto\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " PASS ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" WARN \"%s %s\" em conflito com \"%s %s\"\n"
+" (restrição=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" WARN %s partilha um prefixo comum com %s\n"
+" REF: Página 15, secção 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" WARN LanguageEncoding requerido por espec. de PPD 4.3\n"
+" REF: Páginas 56-57, secção 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" WARN Fabricante requerido por espec. de PPD 4.3\n"
+" REF: Páginas 58-59, secção 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" WARN PCFileName superior a 8.3 viola espec. de PPD\n"
+" REF: Páginas 61-62, secção 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protocolos contêm PJL, mas atributos JCL não estão "
+"especificados.\n"
+" REF: Páginas 78-79, secção 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protocolos contêm PJL e BCP; TBCP esperados.\n"
+" REF: Páginas 78-79, secção 5.7.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" WARN ShortNickName requerido por espec. de PPD 4.3\n"
+" REF: Páginas 64-65, secção 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s Ficheiro cupsFilter inexistente \"%s\"!\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s Ficheiro cupsPreFilter inexistente \"%s\"!\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** Predefinição%s %s inválida\n"
+" REF: Página 40, secção 4.5\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **FAIL** Atributo JobPatchFile inválido no ficheiro!\n"
+" REF: Página 24, secção 3.4\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** Fabricante inválido (deve ser \"HP\")\n"
+" REF: Página 211, tabela D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** Fabricante inválido (deve ser \"Oki\")\n"
+" REF: Página 211, tabela D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** ModelName inválido - \"%c\" não permitido na cadeia.\n"
+" REF: Páginas 59-60, secção 5.3\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** PSVersion inválida - não \"(cadeia) int\".\n"
+" REF: Páginas 62-64, secção 5.3\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** Produto inválido - não \"(cadeia)\".\n"
+" REF: Página 62, secção 5.3\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** ShortNickName inválido - superior a 31 car.\n"
+" REF: Páginas 64-65, secção 5.3\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** Versão de ficheiro inválida \"%s\"\n"
+" REF: Página 56, secção 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** Versão de formato inválida \"%s\"\n"
+" REF: Página 56, secção 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr ""
+" **FAIL** Impossível interpretar código de opção predefinida: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** Predefinição%s requerida\n"
+" REF: Página 40, secção 4.5\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** DefaultImageableArea requerida\n"
+" REF: Página 102, secção 5.15\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** DefaultPaperDimension requerida\n"
+" REF: Página 103, secção 5.15\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** FileVersion requerida\n"
+" REF: Página 56, secção 5.3\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** FormatVersion requerida\n"
+" REF: Página 56, secção 5.3\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** ImageableArea requerida para PageSize %s\n"
+" REF: Página 41, secção 5.\n"
+" REF: Página 102, secção 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **FAIL** LanguageEncoding requerida\n"
+" REF: Páginas 56-57, secção 5.3\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **FAIL** LanguageVersion requerida\n"
+" REF: Páginas 57-58, secção 5.3\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **FAIL** Fabricante requerido\n"
+" REF: Páginas 58-59, secção 5.3\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** ModelName requerido\n"
+" REF: Páginas 59-60, secção 5.3\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **FAIL** NickName requerido\n"
+" REF: Página 60, secção 5.3\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **FAIL** PCFileName requerido\n"
+" REF: Páginas 61-62, secção 5.3\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** PSVersion requerida\n"
+" REF: Páginas 62-64, secção 5.3\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **FAIL** PageRegion requerida\n"
+" REF: Página 100, secção 5.14\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **FAIL** PageSize requerido\n"
+" REF: Página 41, secção 5.\n"
+" REF: Página 99, secção 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **FAIL** PageSize requerido\n"
+" REF: Páginas 99-100, secção 5.14\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** PaperDimension requerida para PageSize %s\n"
+" REF: Página 41, secção 5.\n"
+" REF: Página 103, secção 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** Produto requerido\n"
+" REF: Página 62, secção 5.3\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** ShortNickName requerido\n"
+" REF: Páginas 64-65, secção 5.3\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " %d ERROS ENCONTRADOS\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " SEM ERROS\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " FAIL\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** Impossível abrir ficheiro PPD - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** Impossível abrir ficheiro PPD - %s na linha %d.\n"
+
+msgid " PASS\n"
+msgstr " PASS\n"
+
+msgid "#10 Envelope"
+msgstr "Envelope n.º 10"
+
+msgid "#11 Envelope"
+msgstr "Envelope n.º 11"
+
+msgid "#12 Envelope"
+msgstr "Envelope n.º 12"
+
+msgid "#14 Envelope"
+msgstr "Envelope n.º 14"
+
+msgid "#9 Envelope"
+msgstr "Envelope n.º 9"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f milímetros"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f a %.0f x %.0f milímetros"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f polegadas"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f a %.2f x %.2f polegadas"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s aceita pedidos desde %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "Não é possível alterar %s."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s não é implementado pela versão CUPS de lpc.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s não está preparada\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s está preparada\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s está preparada e a imprimir\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s não aceita pedidos desde %s-\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s aceita pedidos desde %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s não aceita pedidos desde %s-\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [trabalho %d localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s falhou: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: Erro - sem destino predefinido disponível.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: Erro - prioridade deve ser entre 1 e 100.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: Erro - demasiados ficheiros - \"%s\"\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: Erro - não é possível aceder a \"%s\" - %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr ""
+"%s: Erro - não é possível criar fila de espera a partir de stdin - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: Filtro \"%s\" não disponível: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: Cadeia de filtro inválida \"%s\"\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: Operação falhou: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: Não é possível ligar ao servidor\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: Não é possível abrir %s: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: Não é possível abrir o ficheiro PDF: %s na linha %d\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: Erro - sem destino predefinido disponível.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 pol./seg."
+
+msgid "1.25x0.25\""
+msgstr "1,25x0,25\""
+
+msgid "1.25x2.25\""
+msgstr "1,25x2,25\""
+
+msgid "1.5 inch/sec."
+msgstr "1,5 pol./seg."
+
+msgid "1.50x0.25\""
+msgstr "1,50x0,25\""
+
+msgid "1.50x0.50\""
+msgstr "1,50x0,50\""
+
+msgid "1.50x1.00\""
+msgstr "1,50x1,00\""
+
+msgid "1.50x2.00\""
+msgstr "1,50x2,00\""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 pol./seg."
+
+msgid "10 x 11\""
+msgstr "10 x 11\""
+
+msgid "10 x 13\""
+msgstr "10 x 13\""
+
+msgid "10 x 14\""
+msgstr "10 x 14\""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 mm/seg."
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 pol./seg."
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 pol./seg."
+
+msgid "12 x 11\""
+msgstr "12 x 11\""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 mm/seg."
+
+msgid "120x60dpi"
+msgstr "120x60dpi"
+
+msgid "120x72dpi"
+msgstr "120x72dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 mm/seg."
+
+msgid "15 x 11\""
+msgstr "15 x 11\""
+
+msgid "150 mm/sec."
+msgstr "150 mm/seg."
+
+msgid "150dpi"
+msgstr "150dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 pol./seg."
+
+msgid "2-Sided Printing"
+msgstr "Impressão dos 2 lados"
+
+msgid "2.00x0.37\""
+msgstr "2,00x0,37\""
+
+msgid "2.00x0.50\""
+msgstr "2,00x0,50\""
+
+msgid "2.00x1.00\""
+msgstr "2,00x1,00\""
+
+msgid "2.00x1.25\""
+msgstr "2,00x1,25\""
+
+msgid "2.00x2.00\""
+msgstr "2,00x2,00\""
+
+msgid "2.00x3.00\""
+msgstr "2,00x3,00\""
+
+msgid "2.00x4.00\""
+msgstr "2,00x4,00\""
+
+msgid "2.00x5.50\""
+msgstr "2,00x5,50\""
+
+msgid "2.25x0.50\""
+msgstr "2,25x0,50\""
+
+msgid "2.25x1.25\""
+msgstr "2,25x1,25\""
+
+msgid "2.25x4.00\""
+msgstr "2,25x4,00\""
+
+msgid "2.25x5.50\""
+msgstr "2,25x5,50\""
+
+msgid "2.38x5.50\""
+msgstr "2,38x5,50\""
+
+msgid "2.5 inches/sec."
+msgstr "2,5 pol./seg."
+
+msgid "2.50x1.00\""
+msgstr "2,50x1,00\""
+
+msgid "2.50x2.00\""
+msgstr "2,50x2,00\""
+
+msgid "2.75x1.25\""
+msgstr "2,75x1,25\""
+
+msgid "2.9 x 1\""
+msgstr "2,9 x 1\""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 mm/seg."
+
+msgid "200 mm/sec."
+msgstr "200 mm/seg."
+
+msgid "203dpi"
+msgstr "203dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "Série de 24 pinos"
+
+msgid "240x72dpi"
+msgstr "240x72dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 mm/seg."
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 pol./seg."
+
+msgid "3.00x1.00\""
+msgstr "3,00x1,00\""
+
+msgid "3.00x1.25\""
+msgstr "3,00x1,25\""
+
+msgid "3.00x2.00\""
+msgstr "3,00x2,00\""
+
+msgid "3.00x3.00\""
+msgstr "3,00x3,00\""
+
+msgid "3.00x5.00\""
+msgstr "3,00x5,00\""
+
+msgid "3.25x2.00\""
+msgstr "3,25x2,00\""
+
+msgid "3.25x5.00\""
+msgstr "3,25x5,00\""
+
+msgid "3.25x5.50\""
+msgstr "3,25x5,50\""
+
+msgid "3.25x5.83\""
+msgstr "3,25x5,83\""
+
+msgid "3.25x7.83\""
+msgstr "3,25x7,83\""
+
+msgid "3.5\" Disk"
+msgstr "Disco de 3,5\""
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "Disco de 3,5\" - 2 1/8 x 2 3/4\""
+
+msgid "3.50x1.00\""
+msgstr "3,50x1,00\""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 mm/seg."
+
+msgid "300 mm/sec."
+msgstr "300 mm/seg."
+
+msgid "300dpi"
+msgstr "300dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360dpi"
+
+msgid "360x180dpi"
+msgstr "360x180dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 pol./seg."
+
+msgid "4.00x1.00\""
+msgstr "4,00x1,00\""
+
+msgid "4.00x13.00\""
+msgstr "4,00x13,00\""
+
+msgid "4.00x2.00\""
+msgstr "4,00x2,00\""
+
+msgid "4.00x2.50\""
+msgstr "4,00x2,50\""
+
+msgid "4.00x3.00\""
+msgstr "4,00x3,00\""
+
+msgid "4.00x4.00\""
+msgstr "4,00x4,00\""
+
+msgid "4.00x5.00\""
+msgstr "4,00x5,00\""
+
+msgid "4.00x6.00\""
+msgstr "4,00x6,00\""
+
+msgid "4.00x6.50\""
+msgstr "4,00x6,50\""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 mm/seg."
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 pol./seg."
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 pol./seg."
+
+msgid "6.00x1.00\""
+msgstr "6,00x1,00\""
+
+msgid "6.00x2.00\""
+msgstr "6,00x2,00\""
+
+msgid "6.00x3.00\""
+msgstr "6,00x3,00\""
+
+msgid "6.00x4.00\""
+msgstr "6,00x4,00\""
+
+msgid "6.00x5.00\""
+msgstr "6,00x5,00\""
+
+msgid "6.00x6.00\""
+msgstr "6,00x6,00\""
+
+msgid "6.00x6.50\""
+msgstr "6,00x6,50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/seg."
+
+msgid "600dpi"
+msgstr "600dpi"
+
+msgid "60dpi"
+msgstr "60dpi"
+
+msgid "60x720dpi"
+msgstr "60x720dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 pol./seg."
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 pol./seg."
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8,00x1,00\""
+
+msgid "8.00x2.00\""
+msgstr "8,00x2,00\""
+
+msgid "8.00x3.00\""
+msgstr "8,00x3,00\""
+
+msgid "8.00x4.00\""
+msgstr "8,00x4,00\""
+
+msgid "8.00x5.00\""
+msgstr "8,00x5,00\""
+
+msgid "8.00x6.00\""
+msgstr "8,00x6,00\""
+
+msgid "8.00x6.50\""
+msgstr "8,00x6,50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/seg."
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 pol./seg."
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "Série de 9 pinos"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?Comando de ajuda inválido desconhecido\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (extra grande)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (extra grande)"
+
+msgid "A4 (Small)"
+msgstr "A4 (pequeno)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (extra grande)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "Aceitar trabalhos"
+
+msgid "Accepted"
+msgstr "Aceite(s)"
+
+msgid "Add Class"
+msgstr "Adicionar classe"
+
+msgid "Add Printer"
+msgstr "Adicionar impressora"
+
+msgid "Add RSS Subscription"
+msgstr "Adicionar subscrição RSS"
+
+msgid "Address"
+msgstr "Endereço"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "Endereço - 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "Administração"
+
+msgid "Always"
+msgstr "Sempre"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "Aplicador"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "Ponteiro dests NULL inválido"
+
+msgid "Bad OpenGroup"
+msgstr "OpenGroup inválido"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "OpenUI/JCLOpenUI inválidos"
+
+msgid "Bad OrderDependency"
+msgstr "OrderDependency inválida"
+
+msgid "Bad Request"
+msgstr "Pedido inválido"
+
+msgid "Bad SNMP version number"
+msgstr "Número de versão SNMP inválido"
+
+msgid "Bad UIConstraints"
+msgstr "UIConstraints inválidas"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Valor de cópias inválido %d."
+
+msgid "Bad custom parameter"
+msgstr "Parâmetro personalizado inválido"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Atributo de tipo de letra inválido: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Valor number-up inválido %d."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Valores page-ranges inválidos %d-%d."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Faixas publicitárias"
+
+msgid "Billing Information: "
+msgstr "Informação de facturação: "
+
+msgid "Bond Paper"
+msgstr "Papel de escritura"
+
+msgid "C0 Envelope"
+msgstr "Envelope C0"
+
+msgid "C1 Envelope"
+msgstr "Envelope C1"
+
+msgid "C2 Envelope"
+msgstr "Envelope C2"
+
+msgid "C3 Envelope"
+msgstr "Envelope C3"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "Envelope C4"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "Envelope C5"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "Envelope C6"
+
+msgid "C65 Envelope"
+msgstr "Envelope C65"
+
+msgid "C7 Envelope"
+msgstr "Envelope C7"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "Impressora de etiquetas CPCL"
+
+msgid "Cancel RSS Subscription"
+msgstr "Cancelar subscrição RSS"
+
+msgid "Change Settings"
+msgstr "Alterar definições"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Envelope Chou3"
+
+msgid "Chou4 Envelope"
+msgstr "Envelope Chou4"
+
+msgid "Classes"
+msgstr "Classes"
+
+msgid "Clean Print Heads"
+msgstr "Limpar cabeças de impressão"
+
+msgid "Color"
+msgstr "Cor"
+
+msgid "Color Mode"
+msgstr "Modo de cor"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"É possível abreviar comandos. Comandos são:\n"
+"\n"
+"sair ajuda sair estado ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "Nome comunitário com comprimento indefinido"
+
+msgid "Continue"
+msgstr "Continuar"
+
+msgid "Continuous"
+msgstr "Contínuo"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Criação"
+
+msgid "Created On: "
+msgstr "Criação: "
+
+msgid "Custom"
+msgstr "Personalizar"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Cortar"
+
+msgid "Cutter"
+msgstr "Cortador"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "Envelope DL"
+
+msgid "Dark"
+msgstr "Escuro"
+
+msgid "Darkness"
+msgstr "Escurecimento"
+
+msgid "Delete Class"
+msgstr "Apagar classe"
+
+msgid "Delete Printer"
+msgstr "Apagar impressora"
+
+msgid "Description: "
+msgstr "Descrição: "
+
+msgid "DeskJet Series"
+msgstr "Série DeskJet"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "Destino \"%s\" não está a aceitar trabalhos."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"Periférico: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "Suporte térmico directo"
+
+msgid "Disabled"
+msgstr "Inactivo"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "O documento %d não foi encontrado no trabalho %d."
+
+msgid "Double Postcard"
+msgstr "Postal duplo"
+
+msgid "Driver Name: "
+msgstr "Nome do controlador: "
+
+msgid "Driver Version: "
+msgstr "Versão do controlador: "
+
+msgid "Duplexer"
+msgstr "Duplexer"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: Não é possível alocar memória para info de página: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: Não é possível alocar memória para matriz de páginas: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "Impressora de etiquetas EPL1"
+
+msgid "EPL2 Label Printer"
+msgstr "Impressora de etiquetas EPL2"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: Ficheiro charset inválido %s\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: Tipo charset inválido %s\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: Linha de descrição de tipo de letra inválida: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: Orientação de texto inválida %s\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: Largura de texto inválida %s\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: Erro %d ao enviar o pedido PAPSendData: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: Tipos de letra inexistentes no ficheiro charset %s\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: A impressora não responde\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: A impressora enviou um EOF inesperado\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: O host remoto não aceitou ficheiro de controlo (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: O host remoto não aceitou o ficheiro de dados (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr ""
+"ERROR: Ocorreu um erro de tempo limite excedido ao enviar dados para a "
+"impressora\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: Não é possível adicionar o ficheiro %d ao trabalho: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: Não é possível cancelar o trabalho %d: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: Não é possível copiar o ficheiro PDF"
+
+msgid "ERROR: Unable to create pipe"
+msgstr ""
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: Não é possível criar o socket"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: Não é possível criar o ficheiro de impressão comprimido temporário: %"
+"s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: Não é possível criar o ficheiro temporário"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: Não é possível executar pictwpstops: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: Não é possível executar o programa gs"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: Não é possível executar o programa pdftops"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: Não é possível separar pictwpstops: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: Não é possível obter pedidos PAP"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: Não é possível obter a resposta PAP"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr ""
+"ERROR: Não é possível obter o ficheiro PPD para a impressora \"%s\" - %s.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: Não é possível obter a zona AppleTalk predefinida"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: Não é possível procurar a resposta PAP"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: Não é possível procurar impressoras AppleTalk"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: Não é possível criar o endereço AppleTalk"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: Não é possível abrir \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: Não é possível abrir %s: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr ""
+"ERROR: Não é possível abrir o ficheiro da faixa publicitária \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: Não é possível abrir o ficheiro de periférico \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: Não é possível abrir o ficheiro \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: Não é possível abrir o ficheiro \"%s\": %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: Não é possível abrir o ficheiro de impressão \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: Não é possível abrir o ficheiro de impressão %s - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: Não é possível abrir o ficheiro de impressão %s: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: Não é possível abrir o ficheiro de impressão comprimido temporário: %"
+"s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: Não é possível ler os dados de impressão"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: Não é possível reservar a porta"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: Não é possível atingir offset %ld no ficheiro - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: Não é possível atingir offset %lld no ficheiro - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: Não é possível enviar o comando LPD"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: Não é possível enviar o pedido de carga PAP"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: Não é possível enviar o pedido de dados PAP inicial"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: Não é possível enviar o ficheiro de impressão para a impressora"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: Não é possível enviar trailing nul para a impressora"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: Não é possível aguardar por pictwpstops: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: Não é possível escrever %d bytes em \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: Não é possível escrever o ficheiro de controlo"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: Não é possível escrever os dados de impressão"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: Não é possível escrever dados de impressão: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr ""
+"ERROR: Não é possível escrever dados de documento não comprimidos: %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: Ordem de ficheiro desconhecida \"%s\"\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: Caracteres de formato desconhecido \"%c\"\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: Modo de impressão desconhecido \"%s\"\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: select() falhou"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: Não é possível fazer stat do ficheiro de impressão"
+
+msgid "Edit Configuration File"
+msgstr "Editar ficheiro de configuração"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Terminar faixa publicitária"
+
+msgid "English"
+msgstr "Portuguese"
+
+msgid "Enter old password:"
+msgstr "Introduza palavra-passe antiga:"
+
+msgid "Enter password again:"
+msgstr "Introduza palavra-passe novamente:"
+
+msgid "Enter password:"
+msgstr "Introduza palavra-passe:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Introduza o seu nome de utilizador e palavra-passe ou o nome de utilizador e "
+"palavra-passe da raiz para aceder a esta página. Se utilizar a autenticação "
+"Kerberos, certifique-se que tem um ticket de Kerberos válido."
+
+msgid "Envelope Feed"
+msgstr "Alimentação de envelopes"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Política de Erros"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "A cada 10 etiquetas"
+
+msgid "Every 2 Labels"
+msgstr "A cada 2 etiquetas"
+
+msgid "Every 3 Labels"
+msgstr "A cada 3 etiquetas"
+
+msgid "Every 4 Labels"
+msgstr "A cada 4 etiquetas"
+
+msgid "Every 5 Labels"
+msgstr "A cada 5 etiquetas"
+
+msgid "Every 6 Labels"
+msgstr "A cada 6 etiquetas"
+
+msgid "Every 7 Labels"
+msgstr "A cada 7 etiquetas"
+
+msgid "Every 8 Labels"
+msgstr "A cada 8 etiquetas"
+
+msgid "Every 9 Labels"
+msgstr "A cada 9 etiquetas"
+
+msgid "Every Label"
+msgstr "Todas as etiquetas"
+
+msgid "Expectation Failed"
+msgstr "A expectativa não se concretizou"
+
+msgid "Export Printers to Samba"
+msgstr "Exportar Impressoras para Samba"
+
+msgid "FAIL\n"
+msgstr "FAIL\n"
+
+msgid "File Folder"
+msgstr "Pasta de ficheiros"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Pasta de ficheiros - 9/16 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"URIs do periférico do ficheiro foram desactivados! Para activar, consulte a "
+"directiva FileDevice em \"%s/cupsd.conf\"."
+
+msgid "Folio"
+msgstr "Fólio"
+
+msgid "Forbidden"
+msgstr "Proibido"
+
+msgid "General"
+msgstr "Geral"
+
+msgid "Generic"
+msgstr "Genérico"
+
+msgid "German FanFold"
+msgstr "FanFold alemão"
+
+msgid "German FanFold Legal"
+msgstr "FanFold legal alemão"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU com comprimento indefinido"
+
+msgid "Glossy Paper"
+msgstr "Papel brilhante"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Níveis de cinzento"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Pasta suspensa"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Pasta suspensa - 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk inactivo nas Preferências do Sistema\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk inactivo nas Preferências do Sistema.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: A cancelar trabalho de impressão...\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: Ligado à impressora...\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: A ligar à impressora...\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: Ficheiro de controlo enviado com êxito\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr ""
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: Ficheiro de dados enviado com êxito\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: A formatar página %d...\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: A carregar ficheiro de imagem...\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: A procurar a impressora...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: A abrir a ligação\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr ""
+"INFO: Ficheiro de impressão enviado; a aguardar conclusão da impressora...\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: Impressora ocupada; nova tentativa dentro de 10 segundos...\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: Impressora ocupada; nova tentativa dentro de 30 segundos...\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: Impressora ocupada; nova tentativa dentro de 5 segundos...\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr "INFO: A impressora não suporta IPP/%d.%d, a tentar IPP/1.0...\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr ""
+"INFO: A impressora está ocupada; nova tentativa dentro de 5 segundos...\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: A impressora está actualmente sem ligação.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: A impressora está actualmente sem ligação.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: A impressora tem agora ligação.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: A impressora está sem ligação.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr ""
+"INFO: Impressora sem ligação; nova tentativa dentro de 30 segundos...\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: A imprimir página %d, %d%% concluído...\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: A imprimir página %d...\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: Preparada para imprimir.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: A enviar ficheiro de controlo (%lu bytes)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: A enviar ficheiro de controlo (%u bytes)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: A enviar dados\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: A enviar ficheiro de dados (%ld bytes)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: A enviar ficheiro de dados (%lld bytes)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: A enviar dados de impressão...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: Ficheiro de impressão enviado, %ld bytes...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: Ficheiro de impressão enviado, %lld bytes...\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: A processar trabalho LPR, %.0f%% concluído...\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr ""
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: Não é possível contactar a impressora; a colocar em fila na próxima "
+"impressora na classe...\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: A utilizar a zona AppleTalk predefinida \"%s\"\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: A aguardar conclusão do trabalho...\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: A aguardar até que a impressora fique disponível...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "ISO Envelope B4"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (extra grande)"
+
+msgid "ISO B5 Envelope"
+msgstr "ISO Envelope B5"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "ISO Envelope B6"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "Carácter de controlo ilegal"
+
+msgid "Illegal main keyword string"
+msgstr "Cadeia de palavra-chave principal ilegal"
+
+msgid "Illegal option keyword string"
+msgstr "Cadeia de palavra-chave de opção ilegal"
+
+msgid "Illegal translation string"
+msgstr "Cadeia de tradução ilegal"
+
+msgid "Illegal whitespace character"
+msgstr "Carácter de espaço em branco ilegal"
+
+msgid "Installable Options"
+msgstr "Opções instaláveis"
+
+msgid "Installed"
+msgstr "Instalado"
+
+msgid "IntelliBar Label Printer"
+msgstr "Impressora de etiquetas IntelliBar"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr ""
+
+msgid "Internal error"
+msgstr "Erro interno"
+
+msgid "Internet Postage 2-Part"
+msgstr "Envio pela Internet em 2 partes"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Envio pela Internet em 2 partes - 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "Envio pela Internet em 3 partes"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Envio pela Internet em 3 partes - 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "Protocolo de impressão via Internet"
+
+msgid "Invite Envelope"
+msgstr "Envelope de convite"
+
+msgid "Italian Envelope"
+msgstr "Envelope italiano"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "Trabalho #%d já interrompido - impossível cancelar."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "Trabalho #%d já cancelado - impossível cancelar."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "Trabalho #%d já concluído - impossível cancelar."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "Trabalho concluído"
+
+msgid "Job Created"
+msgstr "Trabalho criado"
+
+msgid "Job ID: "
+msgstr "ID do trabalho: "
+
+msgid "Job Options Changed"
+msgstr "Opções de trabalho alteradas"
+
+msgid "Job Stopped"
+msgstr "Trabalho parado"
+
+msgid "Job UUID: "
+msgstr "UUID do trabalho: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "Trabalho concluído; não é possível alterar."
+
+msgid "Job operation failed:"
+msgstr "Operação de trabalho falhou:"
+
+msgid "Job state cannot be changed."
+msgstr "Não é possível alterar o estado do trabalho."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "Trabalhos"
+
+msgid "Kaku2 Envelope"
+msgstr "Envelope Kaku2"
+
+msgid "Kaku3 Envelope"
+msgstr "Envelope Kaku3"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "Host ou impressora LPD/LPR"
+
+msgid "Label Printer"
+msgstr "Impressora de etiquetas"
+
+msgid "Label Top"
+msgstr "Parte superior da etiqueta"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Endereço grande"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Endereço grande - 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet Série PCL 4/5"
+
+msgid "Light"
+msgstr "Claro"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Linha excede máximo permitido (255 caracteres)"
+
+msgid "List Available Printers"
+msgstr "Apresentar impressoras disponíveis"
+
+msgid "Location: "
+msgstr "Localização: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "Margem longa (vertical)"
+
+msgid "Make and Model: "
+msgstr "Marca e modelo: "
+
+msgid "Manual Feed"
+msgstr "Alimentação manual"
+
+msgid "Media Dimensions: "
+msgstr "Dimensões do suporte: "
+
+msgid "Media Limits: "
+msgstr "Limites do suporte: "
+
+msgid "Media Name: "
+msgstr "Nome do suporte: "
+
+msgid "Media Size"
+msgstr "Tamanho do suporte"
+
+msgid "Media Source"
+msgstr "Origem do suporte"
+
+msgid "Media Tracking"
+msgstr "Controlo do suporte"
+
+msgid "Media Type"
+msgstr "Tipo de suporte"
+
+msgid "Medium"
+msgstr "Médio"
+
+msgid "Memory allocation error"
+msgstr "Erro de alocação de memória"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "Cabeçalho PPD-Adobe-4.x inexistente"
+
+msgid "Missing asterisk in column 1"
+msgstr "Asterisco inexistente na coluna 1"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "Cadeia de valor inexistente"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Modelo: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "Modificar classe"
+
+msgid "Modify Printer"
+msgstr "Modificar impressora"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Envelope Monarch"
+
+msgid "Move All Jobs"
+msgstr "Mover todos os trabalhos"
+
+msgid "Move Job"
+msgstr "Mover trabalho"
+
+msgid "Moved Permanently"
+msgstr "Mudou-se permanentemente"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: Ficheiro de impressão aceite - ID do trabalho %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: Ficheiro de impressão aceite - ID do trabalho desconhecido.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "Ponteiro do ficheiro PPD NULL"
+
+msgid "Name OID uses indefinite length"
+msgstr "Nome OID com comprimento indefinido"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Nunca"
+
+msgid "New Stylus Color Series"
+msgstr "Nova série a cores Stylus"
+
+msgid "New Stylus Photo Series"
+msgstr "Nova série fotográfica Stylus"
+
+msgid "No"
+msgstr "Não"
+
+msgid "No Content"
+msgstr "Sem conteúdo"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "Sem SEQUÊNCIA VarBind"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "Nenhuma ligação activa"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "Sem nome comunitário"
+
+msgid "No default printer"
+msgstr "Sem impressora predefinida"
+
+msgid "No destinations added."
+msgstr "Sem destinos adicionados."
+
+msgid "No error-index"
+msgstr "Sem error-index"
+
+msgid "No error-status"
+msgstr "Sem error-status"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "Sem OID de nome"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "Sem request-id"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "Sem subscrições."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "Sem SEQUÊNCIA variable-bindings"
+
+msgid "No version number"
+msgstr "Sem número de versão"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "Não contínuo (leitura de marcas)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "Não contínuo (leitura Web)"
+
+msgid "Normal"
+msgstr "Normal"
+
+msgid "Not Found"
+msgstr "Não encontrado"
+
+msgid "Not Implemented"
+msgstr "Não implementado"
+
+msgid "Not Installed"
+msgstr "Não instalado"
+
+msgid "Not Modified"
+msgstr "Não modificado"
+
+msgid "Not Supported"
+msgstr "Não suportado"
+
+msgid "Not allowed to print."
+msgstr "Sem permissão para imprimir."
+
+msgid "Note"
+msgstr "Nota"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Off (1-Sided)"
+msgstr "Inactivo (1 lado)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Ajuda online"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "abertura de %s falhou: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup sem um CloseGroup primeiro"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI sem um CloseUI/JCLCloseUI primeiro"
+
+msgid "Operation Policy"
+msgstr "Política de Operação"
+
+msgid "Options Installed"
+msgstr "Opções instaladas"
+
+msgid "Options: "
+msgstr "Opções: "
+
+msgid "Output Mode"
+msgstr "Modo de saída"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "Saída de impressora %s enviada para %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr "Saída de impressora %s enviada para impressora remota %s em %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "Saída de impressora %s/%s enviada para %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr "Saída de impressora %s/%s enviada para impressora remota %s em %s\n"
+
+msgid "PASS\n"
+msgstr "PASS\n"
+
+msgid "PCL Laser Printer"
+msgstr "Impressora Laser PCL"
+
+msgid "PRC1 Envelope"
+msgstr "Envelope PRC1"
+
+msgid "PRC10 Envelope"
+msgstr "Envelope PRC10"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "Envelope PRC2"
+
+msgid "PRC3 Envelope"
+msgstr "Envelope PRC3"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (extra grande)"
+
+msgid "PRC4 Envelope"
+msgstr "Envelope PRC4"
+
+msgid "PRC5 Envelope"
+msgstr "Envelope PRC5"
+
+msgid "PRC6 Envelope"
+msgstr "Envelope PRC6"
+
+msgid "PRC7 Envelope"
+msgstr "Envelope PRC7"
+
+msgid "PRC8 Envelope"
+msgstr "Envelope PRC8"
+
+msgid "PRC9 Envelope"
+msgstr "Envelope PRC9"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "O pacote não contém Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "O pacote não começa por SEQUENCE"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "Palavra-passe para %s em %s? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "Palavra-passe para %s requerida para aceder a %s via SAMBA: "
+
+msgid "Pause Class"
+msgstr "Colocar a classe em pausa"
+
+msgid "Pause Printer"
+msgstr "Colocar a impressora em pausa"
+
+msgid "Peel-Off"
+msgstr "Destacar"
+
+msgid "Personal Envelope"
+msgstr "Envelope pessoal"
+
+msgid "Photo"
+msgstr "Fotografia"
+
+msgid "Photo Labels"
+msgstr "Etiquetas de fotografias"
+
+msgid "Plain Paper"
+msgstr "Papel normal"
+
+msgid "Policies"
+msgstr "Políticas"
+
+msgid "Port Monitor"
+msgstr "Monitor da porta"
+
+msgid "PostScript Printer"
+msgstr "Impressora PostScript"
+
+msgid "Postcard"
+msgstr "Postal"
+
+msgid "Print Density"
+msgstr "Densidade de impressão"
+
+msgid "Print Job:"
+msgstr "Imprimir trabalho:"
+
+msgid "Print Mode"
+msgstr "Modo de impressão"
+
+msgid "Print Rate"
+msgstr "Taxa de impressão"
+
+msgid "Print Self-Test Page"
+msgstr "Imprimir página de teste automático"
+
+msgid "Print Speed"
+msgstr "Velocidade de impressão"
+
+msgid "Print Test Page"
+msgstr "Imprimir página de teste"
+
+msgid "Print and Cut"
+msgstr "Imprimir e cortar"
+
+msgid "Print and Tear"
+msgstr "Imprimir e rasgar"
+
+msgid "Printed For: "
+msgstr "Impresso para: "
+
+msgid "Printed From: "
+msgstr "Impresso a partir de: "
+
+msgid "Printed On: "
+msgstr "Impresso a: "
+
+msgid "Printer Added"
+msgstr "Impressora adicionada"
+
+msgid "Printer Default"
+msgstr "Impressora predefinida"
+
+msgid "Printer Deleted"
+msgstr "Impressora apagada"
+
+msgid "Printer Modified"
+msgstr "Impressora modificada"
+
+msgid "Printer Name: "
+msgstr "Nome da impressora: "
+
+msgid "Printer Paused"
+msgstr "Impressora em pausa"
+
+msgid "Printer Settings"
+msgstr "Definições da impressora"
+
+msgid "Printer:"
+msgstr "Impressora:"
+
+msgid "Printers"
+msgstr "Impressoras"
+
+msgid "Purge Jobs"
+msgstr "Limpar trabalhos"
+
+msgid "Quarto"
+msgstr "Quarto"
+
+msgid "Quota limit reached."
+msgstr "Quota atingida."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr ""
+"Classificação Proprietário Trabalho Ficheiro"
+"(s) Tamanho total\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"Classificação Proprietário Pri Trabalho "
+"Ficheiros Tamanho total\n"
+
+msgid "Reject Jobs"
+msgstr "Rejeitar trabalhos"
+
+msgid "Reprint After Error"
+msgstr "Voltar a imprimir após o erro"
+
+msgid "Request Entity Too Large"
+msgstr "Entidade do pedido demasiado extensa"
+
+msgid "Resolution"
+msgstr "Resolução"
+
+msgid "Resume Class"
+msgstr "Retomar classe"
+
+msgid "Resume Printer"
+msgstr "Retomar impressora"
+
+msgid "Return Address"
+msgstr "Endereço de devolução"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Endereço de devolução - 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "Retroceder"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Comando em execução: %s %s -N -A %s -c '%s'\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE com comprimento indefinido"
+
+msgid "See Other"
+msgstr "Ver outros"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "Porta de série n.º %d"
+
+msgid "Server Restarted"
+msgstr "Servidor reiniciado"
+
+msgid "Server Security Auditing"
+msgstr "Auditoria de segurança do servidor"
+
+msgid "Server Started"
+msgstr "Servidor iniciado"
+
+msgid "Server Stopped"
+msgstr "Servidor parado"
+
+msgid "Service Unavailable"
+msgstr "Serviço indisponível"
+
+msgid "Set Allowed Users"
+msgstr "Definir utilizadores permitidos"
+
+msgid "Set As Server Default"
+msgstr "Definir como servidor predefinido"
+
+msgid "Set Class Options"
+msgstr "Definir opções de classe"
+
+msgid "Set Printer Options"
+msgstr "Definir opções de impressora"
+
+msgid "Set Publishing"
+msgstr "Definir publicação"
+
+msgid "Shipping Address"
+msgstr "Endereço de envio"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "Endereço de envio - 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "Margem estreita (horizontal)"
+
+msgid "Special Paper"
+msgstr "Papel especial"
+
+msgid "Standard"
+msgstr "Padrão"
+
+msgid "Starting Banner"
+msgstr "Iniciar faixa publicitária"
+
+msgid "Statement"
+msgstr "Declaração"
+
+msgid "Stylus Color Series"
+msgstr "Série a cores Stylus"
+
+msgid "Stylus Photo Series"
+msgstr "Série fotográfica Stylus"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "A mudar de protocolo"
+
+msgid "Tabloid"
+msgstr "Tablóide"
+
+msgid "Tabloid (Oversize)"
+msgstr "Tablóide (extra grande)"
+
+msgid "Tear"
+msgstr "Rasgar"
+
+msgid "Tear-Off"
+msgstr "Descartar"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Descartar posição de ajuste"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "Não é possível localizar o ficheiro PPD \"%s\"."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "Não é possível abrir o ficheiro PPD \"%s\": %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"O nome de classe pode ter o máximo de 127 caracteres imprimíveis e não pode "
+"ter espaços, barras (/) ou cardinal (#)."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+"Não é possível utilizar o atributo notify-lease-duration com subscrições de "
+"trabalho."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"O nome de impressora pode ter o máximo de 127 caracteres imprimíveis e não "
+"pode ter espaços, barras (/) ou cardinal (#)."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "Impressora ou classe não localizadas."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "O atributo printer-uri \"%s\" contém caracteres inválidos."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr ""
+"O atributo printer-uri deve ser do formato \"ipp://HOSTNAME/classes/CLASSNAME"
+"\"."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+"O atributo printer-uri deve ser do formato \"ipp://HOSTNAME/printers/"
+"PRINTERNAME\"."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"O nome de subscrição não pode ter espaços, barras (/), pontos de "
+"interrogação (?) ou cardinal (#)."
+
+msgid "There are too many subscriptions."
+msgstr "Existem demasiadas subscrições."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "Suporte de transferência térmica"
+
+msgid "Title: "
+msgstr "Título: "
+
+msgid "Too many active jobs."
+msgstr "Demasiados trabalhos activos."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "Transparência"
+
+msgid "Tray"
+msgstr "Bandeja"
+
+msgid "Tray 1"
+msgstr "Bandeja 1"
+
+msgid "Tray 2"
+msgstr "Bandeja 2"
+
+msgid "Tray 3"
+msgstr "Bandeja 3"
+
+msgid "Tray 4"
+msgstr "Bandeja 4"
+
+msgid "URI Too Long"
+msgstr "URI demasiado longo"
+
+msgid "US Executive"
+msgstr "Executivo EUA"
+
+msgid "US Fanfold"
+msgstr "Fanfold EUA"
+
+msgid "US Ledger"
+msgstr "Livro de contas EUA"
+
+msgid "US Legal"
+msgstr "Legal EUA"
+
+msgid "US Legal (Oversize)"
+msgstr "Legal EUA (extra grande)"
+
+msgid "US Letter"
+msgstr "Carta EUA"
+
+msgid "US Letter (Oversize)"
+msgstr "Carta EUA (extra grande)"
+
+msgid "US Letter (Small)"
+msgstr "Carta EUA (pequena)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "Porta de série USB n.º %d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "Não é possível aceder ao ficheiro cupsd.conf:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "Não é possível adicionar a subscrição RSS:"
+
+msgid "Unable to add class:"
+msgstr "Não é possível adicionar a classe:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "Não é possível adicionar a impressora:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "Não é possível cancelar a subscrição RSS:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "Não é possível alterar o atributo printer-is-shared:"
+
+msgid "Unable to change printer:"
+msgstr "Não é possível alterar a impressora:"
+
+msgid "Unable to change server settings:"
+msgstr "Não é possível alterar as definições do servidor:"
+
+msgid "Unable to connect to host."
+msgstr "Não é possível ligar ao host."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "Não é possível criar o ficheiro temporário:"
+
+msgid "Unable to delete class:"
+msgstr "Não é possível apagar a classe:"
+
+msgid "Unable to delete printer:"
+msgstr "Não é possível apagar a impressora:"
+
+msgid "Unable to do maintenance command:"
+msgstr "Não é possível executar o comando de manutenção:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "Não é possível obter a lista de classes:"
+
+msgid "Unable to get class status:"
+msgstr "Não é possível obter o estado da classe:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "Não é possível obter a lista de recursos da impressora:"
+
+msgid "Unable to get printer attributes:"
+msgstr "Não é possível obter os atributos da impressora:"
+
+msgid "Unable to get printer list:"
+msgstr "Não é possível obter a lista de impressoras:"
+
+msgid "Unable to get printer status:"
+msgstr "Não é possível obter o estado da impressora:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "Não é possível modificar a classe:"
+
+msgid "Unable to modify printer:"
+msgstr "Não é possível modificar a impressora:"
+
+msgid "Unable to move job"
+msgstr "Não é possível mover o trabalho"
+
+msgid "Unable to move jobs"
+msgstr "Não é possível mover os trabalhos"
+
+msgid "Unable to open PPD file"
+msgstr "Não é possível abrir o ficheiro PPD"
+
+msgid "Unable to open PPD file:"
+msgstr "Não é possível abrir o ficheiro PPD:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "Não é possível abrir o ficheiro cupsd.conf:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "Não é possível imprimir a página de teste:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "Não é possível executar \"%s\": %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "Não é possível definir opções:"
+
+msgid "Unable to set server default:"
+msgstr "Não é possível definir como servidor predefinido:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "Não é possível carregar o ficheiro cupsd.conf:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "Não autorizado"
+
+msgid "Units"
+msgstr "Unidades"
+
+msgid "Unknown"
+msgstr "Desconhecido"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "Printer-error-policy desconhecida \"%s\"."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "Printer-op-policy desconhecida \"%s\"."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Tipo de valor não suportado"
+
+msgid "Upgrade Required"
+msgstr "Requer actualização"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Utilização:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr ""
+"Utilização: opções de cópias de título de utilizador %s job-id [nome do "
+"ficheiro]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr ""
+"Utilização: opções de cópias de título de utilizador %s job-id [ficheiro]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr ""
+"Utilização: ficheiro de opções de cópias de título de utilizador %s job-id\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Utilização: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Opções:\n"
+" -E Encriptar a ligação ao servidor\n"
+" -H samba-server Utilizar o servidor SAMBA\n"
+" -U samba-user Autenticar utilizando utilizador SAMBA\n"
+" -a Exportar todas as impressoras\n"
+" -h cups-server Utilizar o servidor CUPS\n"
+" -v Verboso (mostrar comandos)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Utilização: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Opções:\n"
+"\n"
+" -E Activar encriptação\n"
+" -U username Especificar nome de utilizador\n"
+" -h server[:port] Especificar endereço de servidor\n"
+"\n"
+" --[no-]debug-logging Activar/desactivar registo da depuração\n"
+" --[no-]remote-admin Activar/desactivar administração remota\n"
+" --[no-]remote-any Permitir/impedir acesso a partir da Internet\n"
+" --[no-]remote-printers Mostrar/ocultar impressoras remotas\n"
+" --[no-]share-printers Activar/desactivar partilha de impressora\n"
+" --[no-]user-cancel-any Permitir/impedir utilizadores de cancelar "
+"trabalhos\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Utilização: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Carregar ficheiro de configuração alternativa\n"
+"-f Executar em primeiro plano\n"
+"-F Executar em primeiro plano, mas separar\n"
+"-h Mostrar esta mensagem de utilização\n"
+"-l Executar cupsd a partir de launchd(8)\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Utilização: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Opções:\n"
+"\n"
+" -h Mostrar utilização de programa\n"
+"\n"
+" Nota: este programa só valida comentários DSC, não o próprio "
+"PostScript.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Utilização: lpmove job/src dest\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Utilização: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Utilização: lppasswd [-g groupname]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Utilização: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Utilização: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] "
+"[+interval]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Utilização: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Opções:\n"
+" -D name=value Definir variável designada como valor.\n"
+" -I include-dir Adicionar incluir directório ao caminho de pesquisa.\n"
+" -c catalog.po Carregar o catálogo de mensagens especificado.\n"
+" -d output-dir Especificar o directório de saída.\n"
+" -l lang[,lang,...] Especificar o(s) idioma(s) (locale).\n"
+" -m Utilizar o valor ModelName como nome de ficheiro.\n"
+" -t Testar PPDs em vez de os gerar.\n"
+" -v Ser verboso (mais \"v\" para mais verbosidade).\n"
+" -z Comprimir ficheiros PPD utilizando o zip GNU.\n"
+" --cr Terminar linhas em CR (Mac OS 9).\n"
+" --crlf Terminar linhas em CR + LF (Windows).\n"
+" --lf Terminar linhas em LF (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"Utilização: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Definir variável designada como valor.\n"
+"Opções:\n"
+" -I include-dir Adicionar incluir directório ao caminho de pesquisa.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Utilização: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Opções:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Utilização: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Opções:\n"
+" -o filename.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"Utilização: ppdpo [options] -o filename.po filename.drv [ ... filenameN."
+"drv ]\n"
+"Opções:\n"
+" -D name=value Definir variável designada como valor.\n"
+" -I include-dir Adicionar incluir directório ao caminho de pesquisa.\n"
+" -v Ser verboso (mais \"v\" para mais verbosidade).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Utilização: snmp [host-or-ip-address]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Valor com comprimento indefinido"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind com comprimento indefinido"
+
+msgid "Version uses indefinite length"
+msgstr "Versão com comprimento indefinido"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: A adicionar apenas as primeiras %d impressoras encontradas"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: Booleano esperado para opção waiteof \"%s\"\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: a impressora não responde\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: A impressora enviou um EOF inesperado\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: Não é possível abrir o ficheiro \"%s:%s\": %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: Não é possível enviar o pedido de estado PAP"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: Pacote PAP inesperado do tipo %d\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: Pacote PAP desconhecido do tipo %d\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: número esperado para opção status \"%s\"\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Sim"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"Deve aceder a esta página utilizando o URL <A HREF=\"https://%s:%d%s"
+"\">https://%s:%d%s</A>."
+
+msgid "You4 Envelope"
+msgstr "Envelope You4"
+
+msgid "ZPL Label Printer"
+msgstr "Impressora de etiquetas ZPL"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "interrompido"
+
+msgid "canceled"
+msgstr "cancelado"
+
+msgid "completed"
+msgstr "concluído"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr ""
+"convert: Utilize a opção -f para especificar um ficheiro para converter.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "cups-deviced falhou a execução."
+
+msgid "cups-driverd failed to execute."
+msgstr "cups-driverd falhou a execução."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: Sem ficheiro PPD para impressora \"%s\" - %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: Não é possível ligar ao servidor: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr "cupsd: suporte launchd(8) não compilado; execução em modo normal.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: Não é possível obter o ficheiro do trabalho - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd: Opção -q incompatível com opção -v.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd: Opção -v incompatível com opção -q.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "periférico para %s/%s: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "periférico para %s: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "error-index com comprimento indefinido"
+
+msgid "error-status uses indefinite length"
+msgstr "error-status com comprimento indefinido"
+
+msgid "held"
+msgstr "reter"
+
+msgid "help\t\tget help on commands\n"
+msgstr "help\t\tobter ajuda sobre comandos\n"
+
+msgid "idle"
+msgstr "inactivo"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: Impressora %s já é membro da classe %s.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: Impressora %s não é membro da classe %s.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: Não é possível ligar ao servidor: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: Não é possível abrir o ficheiro PPD \"%s\" - %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: Não é possível abrir o ficheiro \"%s\": %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: Não é possível ligar ao servidor: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: Não é possível adicionar impressora ou instância: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: Não é possível obter o ficheiro PPD para %s: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: Palavra-passe rejeitada.\n"
+"A palavra-passe deve ter o mínimo de 6 caracteres, sem conter\n"
+"o nome de utilizador, e deve ter pelo menos uma letra e um número.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: Não é possível copiar a cadeia de palavra-passe: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: Não é possível abrir o ficheiro de palavra-passe: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: Não é possível escrever no ficheiro de palavra-passe: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr ""
+"lppasswd: falha ao efectuar cópia de segurança de ficheiro de palavra-passe "
+"antigo: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: falha ao alterar nome de ficheiro de palavra-passe: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: utilizador \"%s\" e grupo \"%s\" não existem.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "membros da classe %s:\n"
+
+msgid "no entries\n"
+msgstr "sem entradas\n"
+
+msgid "no system default destination\n"
+msgstr "sem destino predefinido de sistema\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "pendente"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: A adicionar incluir directório \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: A adicionar/actualizar texto UI de %s...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: Valor boolean inválido (%s) na linha %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: Substituição de variável inválida ($%c) na linha %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: Esperado valor boolean na linha %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: Esperado código de escolha na linha %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: Esperado nome/texto de escolha na linha %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: A carregar ficheiro de informação de controlador \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: A carregar mensagens do locale \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: A carregar mensagens de \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: Não é possível criar o ficheiro PPD \"%s\" - %s.\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: Não é possível criar o directório de saída %s: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: Não é possível criar dutos de saída de dados: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: Não é possível executar cupstestppd: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: Não é possível encontrar a localização de \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: Não é possível carregar o ficheiro de localização \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: Variável indefinida (%s) na linha %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: A escrever %s...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: A escrever ficheiros PPD no directório \"%s\"...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: A ignorar o ficheiro PPD %s...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: Não é possível efectuar a cópia de segurança %s em %s- %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "impressora %s desactivada desde %s -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "impressora %s inactiva. activada desde %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "impressora %s agora a imprimir %s-%d. activada desde %s\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "impressora %s/%s desactivada desde %s -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "impressora %s/%s inactiva. activada desde %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "impressora %s/%s agora a imprimir %s-%d. activada desde %s\n"
+
+msgid "processing"
+msgstr "a processar"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "id de pedido é %s-%d (%d ficheiro(s))\n"
+
+msgid "request-id uses indefinite length"
+msgstr "request-id com comprimento indefinido"
+
+msgid "scheduler is not running\n"
+msgstr "programador não está em execução\n"
+
+msgid "scheduler is running\n"
+msgstr "programador em execução\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "estatística de %s falhou: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "status\t\tmostra estado de daemon e fila\n"
+
+msgid "stopped"
+msgstr "parado"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "destino predefinido de sistema: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "destino predefinido de sistema: %s/%s\n"
+
+msgid "unknown"
+msgstr "desconhecido"
+
+msgid "untitled"
+msgstr "sem nome"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindings com comprimento indefinido"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " WARN %s não tem opções correspondentes!\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " WARN Escolhas predefinidas em conflito!\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " WARN Palavra-chave de opção de frente e verso %s pode não "
+#~ "funcionar como previsto e deve ter o nome Duplex!\n"
+#~ " REF: Página 122, secção 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " WARN Ficheiro contém um misto de fins de linha CR, LF e CR "
+#~ "LF!\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " WARN Linha %d só contém espaço em branco!\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " WARN Ficheiro APDialogExtension inexistente \"%s\"\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " WARN Ficheiro APPrinterIconPath inexistente \"%s\"\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " WARN Ficheiros PPD não Windows devem utilizar fins de linha "
+#~ "com LF, e não CR LF!\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " WARN Versão de PPD obsoleta %.1f!\n"
+#~ " REF: Página 42, secção 5.2"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s não existe!\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s Escolha %s inválida %s!\n"
+#~ " REF: Página 122, secção 5.17\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr " %s Cadeia de tradução UTF-8 \"%s\" inválida para opção %s!\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Cadeia de tradução UTF-8 \"%s\" inválida para opção %s, escolha "
+#~ "%s!\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Valor cupsFilter inválido \"%s\"!\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s CupsICCProfile inválido %s!\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Valor cupsPreFilter inválido \"%s\"!\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s CupsUIConstraints inválido %s: \"%s\"!\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s Idioma inválido \"%s\"!\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s CupsUIConstraints vazio %s!\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s Cadeia de tradução inexistente \"%s\" para opção %s!\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Cadeia de tradução inexistente \"%s\" para opção %s, escolha %"
+#~ "s!\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Escolha inexistente *%s %s em UIConstraints \"*%s %s *%s %s\"!\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr ""
+#~ " %s Escolha inexistente *%s %s em cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s Ficheiro cupsICCProfile inexistente \"%s\"!\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s CupsUIResolver inexistente %s!\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Opção inexistente %s em UIConstraints \"*%s %s *%s %s\"!\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Opção inexistente %s em cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr " %s Sem tradução base \"%s\" incluída no ficheiro!\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s REQUERIDO %s não define a escolha Sem!\n"
+#~ " REF: Página 122, secção 5.17\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " %s cupsICCProfile %s valor hash colide com %s!\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver %s causa um loop!\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** %s os nomes da escolha %s e %s divergem apenas pela "
+#~ "utilização de maiúsculas/minúsculas!\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **FAIL** %s deve ser 1284DeviceID!\n"
+#~ " REF: Página 72, secção 5.5\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** DefaultImageableArea %s inválida!\n"
+#~ " REF: Página 102, secção 5.15\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** DefaultPaperDimension %s inválida!\n"
+#~ " REF: Página 103, secção 5.15\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **FAIL** Escolha %s inválida %s!\n"
+#~ " REF: Página 84, secção 5.9\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr ""
+#~ " **FAIL** LanguageEncoding %s inválida - deve ser ISOLatin1!\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr " **FAIL** LanguageVersion %s inválida - deve ser Inglês!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **FAIL** Cadeia de tradução predefinida para opção %s escolha %s "
+#~ "contém caracteres de 8 bits!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **FAIL** Cadeia de tradução predefinida para opção %s contém "
+#~ "caracteres de 8 bits!\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Os nomes dos grupos%s e %s divergem apenas pela "
+#~ "utilização de maiúsculas/minúsculas!\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **FAIL** Múltiplos casos de %s nome da escolha %s!\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Os nomes das opções %s e %s divergem apenas pela "
+#~ "utilização de maiúsculas/minúsculas!\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " %%%%BoundingBox: inválida na linha %d!\n"
+#~ " REF: Página 39, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " %%%%Page: inválida na linha %d!\n"
+#~ " REF: Página 53, %%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " %%%%Pages: inválidas na linha %d!\n"
+#~ " REF: Página 43, %%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " Linha %d tem mais de 255 caracteres (%d)!\n"
+#~ " REF: Página 25, Comprimento da Linha\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " %!PS-Adobe-3.0 inexistente na primeira linha!\n"
+#~ " REF: Página 17, 3.1 Documentos de Conformidade\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " Comentário %%EndComments inexistente!\n"
+#~ " REF: Página 41, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " Comentário %%BoundingBox: inexistente ou inválido!\n"
+#~ " REF: Página 39, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " Comentários %%Page: inexistentes ou inválidos!\n"
+#~ " REF: Página 53, %%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " Comentário %%Pages: inexistente ou inválido!\n"
+#~ " REF: Página 43, %%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " Detectadas %d linhas que excedem 255 caracteres!\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " Demasiados comentários %%BeginDocument!\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " Demasiados comentários %%EndDocument!\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " Aviso: ficheiro contém dados binários!\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " Aviso: sem comentário %%EndComments no ficheiro!\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " Aviso: versão obsoleta de DSC %.1f no ficheiro!\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s não suportado!"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: Não sei que fazer!\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: Erro - nomes de variáveis de ambiente %s inexistentes no destino \"%s"
+#~ "\"!\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: Erro - ID de trabalho inválido!\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr ""
+#~ "%s: Erro - não é possível imprimir ficheiros e alterar trabalhos em "
+#~ "simultâneo!\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: Erro - não é possível imprimir a partir de stdin se fornecidos "
+#~ "ficheiros ou ID do trabalho!\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: Erro - conjunto de caracteres esperado após opção '-S'!\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: Erro - tipo de conteúdo esperado após opção '-T'!\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: Erro - cópias esperadas após opção '-n'!\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s: Erro - contagem de cópias esperadas após opção '-#'!\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: Erro - destino esperado após opção '-P'!\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: Erro - destino esperado após opção '-b'!\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: Erro - destino esperado após opção '-d'!\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: Erro - formato esperado após opção '-f'!\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: Erro - nome para reter esperado após opção '-H'!\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: Erro - nome de host esperado após opção '-h'!\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: Erro - nome de host esperado após opção '-h'!\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: Erro - lista de modo esperada após opção '-y'!\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: Erro - nome esperado após opção '-%c'!\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s: Erro - cadeia de opção esperada após opção '-o'!\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: Erro - lista de página esperada após opção '-P'!\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: Erro - prioridade esperada após opção '-%c'!\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s: Erro - texto de motivo esperado após opção '-r'!\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: Erro - título esperado após opção '-t'!\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s: Erro - nome de utilizador esperado após opção '-u'!\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s: Erro - nome de utilizador esperado após opção '-u'!\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: Erro - valor esperado após opção '-%c'!\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: Erro - necessário \"concluído\", \"não concluído\" ou \"tudo\" após "
+#~ "opção '-W'!\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: Erro - programador não responde!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: Erro - destino desconhecido \"%s\"!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: Erro - destino desconhecido \"%s/%s\"!\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: Erro - opção desconhecida '%c'!\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: Erro - opção desconhecida '%s'!\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: ID de trabalho esperado após opção '-i'!\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: Nome de destino inválido na lista \"%s\"!\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr ""
+#~ "%s: Necessário ID do trabalho ('-i jobid') antes de '-H reiniciar'!\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: Sem filtro para converter de %s/%s para %s/%s!\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s: Sem suporte de encriptação compilado!\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: Não é possível contactar o servidor!\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: Não é possível determinar tipo MIME de \"%s\"!\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s: Não é possível abrir %s - %s\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s: Não é possível abrir %s - %s na linha %d.\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr ""
+#~ "%s: Não é possível ler a base de dados MIME a partir de \"%s\" ou \"%s"
+#~ "\"!\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: Destino desconhecido \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: Destino desconhecido de tipo MIME %s/%s!\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: Opção desconhecida '%c'!\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: Origem desconhecida de tipo MIME %s/%s!\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: Aviso - modificador de formato '%c' não suportado - saída pode ser "
+#~ "incorrecta!\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: Aviso - opção de conjunto de caracteres ignorada!\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: Aviso - opção de tipo de conteúdo ignorada!\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: Aviso - opção de formato ignorada!\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: Aviso - opção de modo ignorada!\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: Erro - nomes de variáveis de ambiente %s inexistentes no destino \"%s"
+#~ "\"!\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: Erro - opção=valor esperada após opção '-o'!\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "Níveis de cinzento 600 DPI"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr "Palavra-passe Samba requerida para exportar recursos de impressora!"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr ""
+#~ "Nome de utilizador Samba requerido para exportar recursos de impressora!"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "Já existe uma classe com o nome \"%s\"!"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "Já existe uma impressora com o nome \"%s\"!"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr "Tentativa de definir %s printer-state como valor inválido %d!"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "Grupos de atributos desordenados (%x < %x)!"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "URI de periférico inválido \"%s\"!\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "Device-uri \"%s\" inválido!"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "Esquema uri de periférico inválido \"%s\"!\n"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "Document-format \"%s\" inválido!"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Buffer de nome de ficheiro inválido!"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Valor job-priority inválido!"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Valor job-sheets \"%s\" inválido!"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Tipo de valor job-sheets inválido!"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Valor job-state inválido!"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Atributo job-uri \"%s\" inválido!"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "Notify-pull-method \"%s\" inválido!"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "Notify-recipient-uri URI \"%s\" inválido!"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "Opção + escolha inválidas na linha %d!"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "Port-monitor \"%s\" inválido!"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Valor printer-state inválido %d!"
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "Número de versão pedido inválido %d.%d!"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "ID de subscrição inválido!"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "Conjunto de caracteres \"%s\" não suportado!"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "Não é possível procurar o tipo \"%s\"!"
+
+#~ msgid "Cover open."
+#~ msgstr "Tampa aberta."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "Programador quase vazio."
+
+#~ msgid "Developer empty!"
+#~ msgstr "Programador vazio!"
+
+#~ msgid "Door open."
+#~ msgstr "Porta aberta."
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Detectado comentário %%BoundingBox: inválido!\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: Detectado comentário %%IncludeFeature: inválido!\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: Comentário %%Page: inválido no ficheiro!\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: Comentário %%PageBoundingBox: inválido no ficheiro!\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: Ficheiro de periférico SCSI inválido \"%s\"!\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: Valor de colunas inválido %d!\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: Valor cpi inválido %f!\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: Valor lpi inválido %f!\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: Configuração de página inválida!\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: A impressora de destino não existe!\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Detectado comentário %%BoundingBox: em duplicado!\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: Detectado comentário %%Pages: em duplicado!\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: Ficheiro de impressão vazio!\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr "ERROR: Esperada cadeia entre aspas na linha %d de %s!\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: Erro fatal de USB!\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr ""
+#~ "ERROR: Detectado comando HP-GL/2 inválido; impossível imprimir ficheiro!\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: %%EndProlog inexistente!\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: %%EndSetup inexistente!\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: URI de periférico inexistente em command-line e sem variável de "
+#~ "ambiente DEVICE_URI!\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr ""
+#~ "ERROR: Valor inexistente na linha %d do ficheiro da faixa publicitária!\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: É necessária uma linha msgid antes de quaisquer cadeias de "
+#~ "tradução na linha %d de %s!\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: Sem comentário %%BoundingBox: no cabeçalho!\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: Sem comentário %%Pages: no cabeçalho!\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Sem URI de periférico em argv[0] ou na variável de ambiente "
+#~ "DEVICE_URI!\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: Sem páginas!\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: Sem papel!\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: Variável de ambiente PRINTER não definida!\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: O ficheiro de impressão não foi aceite (%s)!\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: A impressora não responde!\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: Não é possível criar ficheiro o temporário - %s.\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: Não é possível criar o ficheiro temporário: %s.\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: Não é possível obter os atributos do trabalho %d (%s)!\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: Não é possível obter o estado da impressora (%s)!\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: Não é possível localizar a impressora '%s'!\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: Não é possível abrir o ficheiro de imagem para impressão!\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: Não é possível abrir o ficheiro temporário"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: Não é possível imprimir %d colunas de texto!\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: Não é possível imprimir %dx%d página de texto!\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: Não é possível ler os dados de impressão!\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: Não é possível enviar dados de impressão (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: Não é possível enviar os dados de impressão!\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: Não é possível escrever %d bytes na impressora!\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr "ERROR: Não é possível escrever dados de retícula no recurso!\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: Não é possível escrever no ficheiro temporário"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: Texto inesperado na linha %d de %s!\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: Valor de opção de encriptação desconhecido \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: Formato desconhecido do catálogo de mensagens para \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: Opção desconhecida \"%s\" com valor \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: Valor de opção de versão desconhecido \"%s\"!\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr "ERROR: Valor de brilho não suportado %s ao utilizar brilho=100!\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: Valor gama não suportado %s ao utilizar gama=1000!\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr "ERROR: Valor number-up não suportado %d ao utilizar number-up=1!\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: Valor number-up-layout não suportado %s ao utilizar number-up-"
+#~ "layout=lrtb!\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: Valor page-border não suportado %s ao utilizar page-border=none!\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr "ERROR: Detectado excesso doc_printf (%d bytes); a interromper!\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr "ERROR: Filtro pdftops falhou ao sinal %d!\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr "ERROR: Filtro pdftops saiu com o estado %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops saiu ao sinal %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops saiu com o estado %d!\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: recuperável: Não é possível ligar à impressora; nova tentativa "
+#~ "dentro de 30 segundos...\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "Ficheiro PPD vazio!"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "Erro: necessário nome de host após opção '-h'!\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Temperatura do fusor elevada!"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "Temperatura do fusor baixa!"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "Obtive um atributo printer-uri, mas não job-id!"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Tinta/toner quase vazio."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Tinta/toner vazio!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Receptáculo de tinta/toner quase cheio."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Receptáculo de tinta/toner cheio!"
+
+#~ msgid "Interlock open."
+#~ msgstr "Bloqueio aberto."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "Não é possível reiniciar o trabalho #%d - sem ficheiros!"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "Trabalho #%d não existe!"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "Trabalho #%d concluído; não é possível alterar!"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "Trabalho #%d não concluído!"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "Trabalho #%d não retido para autenticação!"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "Trabalho #%d não retido!"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "Trabalho #%s não existe!"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "Trabalho %d não encontrado!"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "Não é possível renovar as subscrições do trabalho!"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "Idioma \"%s\" não suportado!"
+
+#~ msgid "Media jam!"
+#~ msgstr "Suporte encravado!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Tabuleiro de suporte quase vazio."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Tabuleiro de suporte vazio!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Tabuleiro de suporte inexistente!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "É necessário encher o tabuleiro de suporte."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "Atributo document-number inexistente!"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "Aspas inexistentes na linha %d!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "Variável de formato inexistente!"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "Atributo notify-subscription-ids inexistente!"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "Atributo requesting-user-name inexistente!"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "Atributos necessários inexistentes!"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "Valor inexistente na linha %d!"
+
+#~ msgid "No PPD name!"
+#~ msgstr "Sem nome PPD!"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Sem controladores de impressora Windows instalados!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "Sem trabalhos activos em %s!"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "Sem atributos no pedido!"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "Sem informações de autenticação fornecidas!"
+
+#~ msgid "No file!?!"
+#~ msgstr "Sem ficheiro?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "Tempo de modificação inexistente!"
+
+#~ msgid "No printer name!"
+#~ msgstr "Nome de impressão inexistente!"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "Nenhum printer-uri para a classe!"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "Nenhum printer-uri encontrado!"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "Nenhum printer-uri no pedido!"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "Sem atributos de subscrição no pedido!"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC quase em fim de vida."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC em fim de vida!"
+
+#~ msgid "Out of toner!"
+#~ msgstr "Sem toner!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Receptáculo de saída quase cheio."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Receptáculo de saída cheio!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Tabuleiro de saída inexistente!"
+
+#~ msgid "Printer offline."
+#~ msgstr "Impressora sem ligação."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "Impressora SCSI"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "O valor notify-user-data é demasiado grande (%d > 63 octetos)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "Impressora ou classe não partilhadas!"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "Necessário atributo printer-uri!"
+
+#~ msgid "Toner low."
+#~ msgstr "Pouco toner."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "Demasiados valores job-sheets (%d > 2)!"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "Demasiados valores printer-state-reasons (%d > %d)!"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "Não é possível adicionar o trabalho ao destino \"%s\"!"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "Não é possível alocar memória para tipos de ficheiros!"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "Não é possível copiar os ficheiros de controladores de impressora CUPS de "
+#~ "64 bits (%d)!"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr ""
+#~ "Não é possível copiar os ficheiros de controladores de impressora Windows "
+#~ "de 64 bits (%d)!"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr "Não é possível copiar ficheiros de recurso de impressora CUPS (%d)!"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "Não é possível copiar o ficheiro PPD - %s!"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "Não é possível copiar o ficheiro PPD!"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Não é possível copiar os ficheiros de controladores de impressora Windows "
+#~ "2000 (%d)!"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "Não é possível copiar os ficheiros de controladores de impressora Windows "
+#~ "9x (%d)!"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "Não é possível copiar o script de interface - %s!"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "Não é possível criar printer-uri!"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr "Não é possível editar ficheiros cupsd.conf com mais de 1MB!"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "Não é possível localizar o destino para o trabalho!"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "Não é possível encontrar a impressora!\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Não é possível instalar os ficheiros de controladores de impressora "
+#~ "Windows 2000 (%d)!"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "Não é possível instalar os ficheiros de controladores de impressora "
+#~ "Windows 9x (%d)!"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "Não é possível abrir o documento %d no trabalho %d!"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "Não é possível enviar o comando para o controlador de impressora!"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Não é possível definir o controlador de impressora Windows (%d)!"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "Não é possível usar o controlador de classe USB!\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "Erro de impressora desconhecido (%s)!"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Conjunto de caracteres \"%s\" não suportado!"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "Compressão não suportada \"%s\"!"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "Atributo de compressão não suportado %s!"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "Formato não suportado \"%s\"!"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "Formato não suportado '%s'!"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "Formato não suportado %s/%s'!"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "Utilização: convert [ options ]\n"
+#~ "\n"
+#~ "Opções:\n"
+#~ "\n"
+#~ " -f filename Definir ficheiro a ser convertido (caso contrário "
+#~ "stdin)\n"
+#~ " -o filename Definir ficheiro a ser gerado (caso contrário "
+#~ "stdout)\n"
+#~ " -i mime/type Definir tipo MIME de entrada (caso contrário auto-"
+#~ "typed)\n"
+#~ " -j mime/type Definir tipo MIME de saída (caso contrário "
+#~ "application/pdf)\n"
+#~ " -P filename.ppd Definir ficheiro PPD\n"
+#~ " -a 'name=value ...' Definir opção(ões)\n"
+#~ " -U username Definir nome de utilizador do trabalho\n"
+#~ " -J title Definir título\n"
+#~ " -c copies Definir número de cópias\n"
+#~ " -u Remover o ficheiro PPD ao terminar\n"
+#~ " -D Remover o ficheiro de entrada ao terminar\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "Utilização: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Opções:\n"
+#~ "\n"
+#~ " -c cupsd.conf Definir ficheiro cupsd.conf a utilizar\n"
+#~ " -j job-id[,N] Filtrar ficheiro N do trabalho especificado (a "
+#~ "predefinição é ficheiro 1)\n"
+#~ " -n copies Definir número de cópias\n"
+#~ " -o name=value Definir opção(ões)\n"
+#~ " -p filename.ppd Definir ficheiro PPD\n"
+#~ " -t title Definir título\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Utilização: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[."
+#~ "gz]]\n"
+#~ " programa | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Opções:\n"
+#~ "\n"
+#~ " -R root-directory Especificar raiz alternativa\n"
+#~ " -W {tudo, sem, restrições, predefinições, duplex, filtros, "
+#~ "traduções}\n"
+#~ " Emitir avisos em vez de erros\n"
+#~ " -q Executar silenciosamente\n"
+#~ " -r Utilizar modo aberto 'descontraído'\n"
+#~ " -v Ligeiramente verboso\n"
+#~ " -vv Muito verboso\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: Falha ao ler pedido de side-channel!\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr ""
+#~ "WARNING: Não é possível incluir a opção \"%s\" via IncludeFeature!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Host remoto não respondeu com byte de estado de comando após %d "
+#~ "segundos!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Host remoto não respondeu com byte de estado de controlo após %d "
+#~ "segundos!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Host remoto não respondeu com byte de estado de dados após %d "
+#~ "segundos!\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr "WARNING: Comando SCSI sem resposta (%d); a tentar de novo...\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: Este documento não está de acordo com ADSC e pode não ser "
+#~ "impresso correctamente!\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: Escolha desconhecida \"%s\" para opção \"%s\"!\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: Opção desconhecida \"%s\"!\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: Taxa baud não suportada %s!\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: recuperável: host de rede '%s' ocupado; nova tentativa dentro de "
+#~ "%d segundos...\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr "Aviso, sem controladores de impressora Windows 2000 instalados!"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: Opção desconhecida \"%s\"!\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: Opção desconhecida \"-%c\"!\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr "cupsd: Nome de ficheiro config esperado após opção \"-c\"!\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: Não é possível obter o directório actual!\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: Argumento desconhecido \"%s\" - a interromper!\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: Opção desconhecida \"%c\" - a interromper!\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: Número de documento inválido %d!\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: ID de trabalho inválido %d!\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: Só pode ser especificado um nome de ficheiro!\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter: Não é possível criar o ficheiro temporário: %s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "atributo job-printer-uri inexistente!"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Nome de classe só pode ter caracteres imprimíveis!\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: PPD esperado após opção '-P'!\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr ""
+#~ "lpadmin: Permitir/negar:lista de utilizadores esperado após opção '-u'!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: Classe esperada após opção '-r'!\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: Nome de classe esperado após opção '-c'!\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: Descrição esperada após opção '-D'!\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: URI de periférico esperado após opção '-v'!\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: Tipo(s) de ficheiro esperados após opção '-I'!\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: Nome de host esperado após opção '-h'!\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: Interface esperada após opção '-i'!\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: Localização esperada após opção '-L'!\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: Modelo esperado após opção '-m'!\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: Nome=valor esperado após opção '-o'!\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: Impressora esperada após opção '-p'!\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: Nome de impressora esperado após opção '-d'!\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin: Impressora ou classe esperadas após opção '-x'!\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: Sem nomes de membro detectados!\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Nome de impressora só pode ter caracteres imprimíveis!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível adicionar impressora à classe:\n"
+#~ " Especifique primeiro um nome de impressora!\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin: Não é possível criar o ficheiro temporário - %s\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin: Não é possível criar o ficheiro temporário: %s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível remover a impressora da classe:\n"
+#~ " Especifique primeiro um nome de impressora!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível definir o ficheiro PPD:\n"
+#~ " Especifique primeiro um nome de impressora!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível definir o URI do periférico:\n"
+#~ " Especifique primeiro um nome de impressora!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível definir o script de interface ou ficheiro PPD:\n"
+#~ " Especifique primeiro um nome de impressora!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível definir o script de interface:\n"
+#~ " Especifique primeiro um nome de impressora!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível definir a descrição da impressora:\n"
+#~ " Especifique primeiro um nome de impressora!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível definir a localização da impressora:\n"
+#~ " Especifique primeiro um nome de impressora!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível definir as opções da impressora:\n"
+#~ " Especifique primeiro um nome de impressora!\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: Opção permitir/negar desconhecida \"%s\"!\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: Argumento desconhecido '%s'!\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: Opção desconhecida '%c'!\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin: Aviso - lista de tipo de conteúdo ignorada!\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr "lpinfo: Esperada cadeia ID de periférico 1284 após --device-id!\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: Esperado idioma após --language!\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo: Esperados marca e modelo após --make-and-model!\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo: Esperada cadeia de produto após --product!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo: Esperada lista de esquema após --exclude-schemes!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo: Esperada lista de esquema após --include-schemes!\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: Esperado limite de tempo excedido após --timeout!\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: Argumento desconhecido '%s'!\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: Opção desconhecida '%c'!\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: Opção desconhecida '%s'!\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: Argumento desconhecido '%s'!\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: Opção desconhecida '%c'!\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: Sem impressoras!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: Não é possível abrir o ficheiro PPD para %s!\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: Impressora ou classe desconhecidas!\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: Só raiz pode adicionar ou apagar palavras-passe!\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: Ficheiro de palavra-passe ocupado!\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: Ficheiro de palavra-passe não actualizado!\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: Palavra-passe não corresponde!\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: Palavras-passe não correspondem!\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: erro - nomes de variáveis de ambiente %s inexistentes no destino "
+#~ "\"%s\"!\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-events não especificados!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "notify-recipient-uri URI \"%s\" já está em utilização!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "notify-recipient-uri URI \"%s\" utiliza esquema desconhecido!"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d incorrecto!"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Nome de resolução inválido \"%s\" na linha %d de %s!\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: Palavra-chave de estado inválida %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc: Encontrada escolha na linha %d de %s sem Opção!\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc: Duplicar #po para o locale %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: Esperada uma definição de filtro na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado um nome de programa na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado charset após Tipo de Letra na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Esperada ordem de cor para ColorModel na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado espaço de cor para ColorModel na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Esperada compressão para ColorModel na linha %d de %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Esperada cadeia de restrições para UIConstraints na linha %d de %"
+#~ "s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Esperada palavra-chave do tipo de controlador após DriverType na "
+#~ "linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado tipo duplex após Duplex na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Esperada codificação após Tipo de Letra na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado nome de ficheiro após #po %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado nome/texto de grupo na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado incluir nome de ficheiro na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado número inteiro na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado locale após #po na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado nome após %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado nome após FileName na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado nome após Tipo de Letra na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado nome após Fabricante na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado nome após MediaSize na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado nome após ModelName na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado nome após PCFileName na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado nome/texto após %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado nome/texto após Instalável na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado nome/texto após Resolução na linha %d de %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Esperada combinação nome/texto para ColorModel na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado nome/texto da opção na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: Esperada secção de opção na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado tipo de opção na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado substituir campo após Resolução na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado número real na linha %d de %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Esperada resolução/tipo de suporte após ColorProfile na linha %d de "
+#~ "%s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Esperada resolução/tipo de suporte após SimpleColorProfile na linha "
+#~ "%d de %s!\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado selector após %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado estado Tipo de Letra na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc: Esperada cadeia após Copyright na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc: Esperada cadeia após Versão na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: Esperados dois nomes de opção na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Esperado valor após %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Esperada versão após Tipo de Letra na linha %d de %s!\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: Nome de ficheiro #include/#po inválido \"%s\"!\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Custo inválido de filtro na linha %d de %s!\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Tipo MIME vazio inválido de filtro na linha %d de %s!\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Nome de programa vazio inválido de filtro na linha %d de %s!\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Secção de opção inválida \"%s\" na linha %d de %s!\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Tipo de opção inválido \"%s\" na linha %d de %s!\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: #endif inexistente no final de \"%s\"!\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: #if inexistente na linha %d de %s!\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr ""
+#~ "ppdc: Não foi fornecido qualquer catálogo de mensagem para o locale %s!\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Opção %s redefinida com um tipo diferente na linha %d de %s!\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr "ppdc: Restrição de opção tem *name na linha %d de %s!\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: Demasiados #if aninhados na linha %d de %s!\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: Não é possível encontrar #po ficheiro %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Não é possível encontrar incluir ficheiro \"%s\" na linha %d de %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: Tipo de controlador desconhecido %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Tipo de duplex desconhecido \"%s\" na linha %d de %s!\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Tamanho de suporte desconhecido \"%s\" na linha %d de %s!\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: Token desconhecido \"%s\" visto na linha %d de %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Caracteres de controlo desconhecidos no número real \"%s\" na linha "
+#~ "%d de %s!\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr "ppdc: Cadeia não terminada começando por %c na linha %d de %s!\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: LanguageVersion inválida \"%s\" em %s!\n"
diff --git a/locale/cups_pt_BR.po b/locale/cups_pt_BR.po
new file mode 100644
index 000000000..43325dd6c
--- /dev/null
+++ b/locale/cups_pt_BR.po
@@ -0,0 +1,7156 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-16 12:00-0800\n"
+"Last-Translator: Apple Inc.\n"
+"Language-Team: Apple Inc.\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(todos)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(nenhum)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d entradas\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tApós falha: continuar\n"
+
+msgid "\tAlerts:"
+msgstr "\tAlertas:"
+
+msgid "\tBanner required\n"
+msgstr "\tBanner requisitado\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tConjunto de caracteres:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tConexão: direta\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tConexão: remota\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tTamanho de página padrão:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tTom padrão:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tAjustes de porta padrão:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tDescrição: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tFormato montado:\n"
+"\tTipos de conteúdo: qualquer\n"
+"\tTipos de impressora: desconhecido\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tFormatos permitidos:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tInterface: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tInterface: %s/interfaces/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tInterface: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tLocalização: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tNa falha: nenhum alerta\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tUsuários permitidos:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tUsuários negados:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tapresentação de daemon\n"
+
+msgid "\tno entries\n"
+msgstr "\tnenhuma entrada\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\ta impressora está no dispositivo '%s' velocidade -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\ta impressão está desativada\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\ta impressão está ativada\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\tenfileirado para %s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\to enfileiramento está desativado\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\to enfileiramento está ativado\n"
+
+msgid "\treason unknown\n"
+msgstr "\tmotivo desconhecido\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " REF: Página 15, seção 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " REF: Página 15, seção 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " REF: Página 19, seção 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " REF: Página 20, seção 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " REF: Página 27, seção 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " REF: Página 42, seção 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " REF: Página 16-17, seção 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " REF: Página 42-45, seção 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " REF: Página 45-46, seção 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " REF: Página 48-49, seção 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " REF: Página 52-54, seção 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f bytes\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " PASS Padrão%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " PASS DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " PASS DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " PASS FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " PASS FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " PASS LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " PASS LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " PASS Fabricante\n"
+
+msgid " PASS ModelName\n"
+msgstr " PASS ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " PASS NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " PASS PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " PASS PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " PASS PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " PASS PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " PASS Produto\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " PASS ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" WARN \"%s %s\" entra em conflito com \"%s %s\"\n"
+" (restrição=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" WARN %s compartilha um prefixo comum com %s\n"
+" REF: Página 15, seção 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" WARN LanguageEncoding solicitado por PPD 4.3 spec.\n"
+" REF: Páginas 56-57, seção 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" WARN Fabricante solicitado por PPD 4.3 spec.\n"
+" REF: Páginas 58-59, seção 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" WARN PCFileName maior que 8.3 em violação de PPD spec.\n"
+" REF: Páginas 61-62, seção 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Os protocolos contém PJL, mas os atributos JCL não estão "
+"definidos.\n"
+" REF: Páginas 78-79, seção 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Os protocolos contêm PJL e BCP; TBCP esperado.\n"
+" REF: Páginas 78-79, seção 5.7.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" WARN ShortNickName solicitado por PPD 4.3 spec.\n"
+" REF: Páginas 64-65, seção 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s Arquivo cupsFilter ausente \"%s\"\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s Arquivo cupsPreFilter ausente \"%s\"\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** BAD Padrão%s %s\n"
+" REF: Página 40, seção 4.5.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **FAIL** BAD atributo JobPatchFile no arquivo\n"
+" REF: Página 24, seção 3.4.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** BAD Fabricante (deve ser \"HP\")\n"
+" REF: Página 211, tabela D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** BAD Fabricante (deve ser \"Oki\")\n"
+" REF: Página 211, tabela D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** BAD ModelName - \"%c\" não permitido na seqüência de "
+"caracteres.\n"
+" REF: Páginas 59-60, seção 5.3.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** BAD PSVersion - não \"(seqüência de caracteres) int\".\n"
+" REF: Páginas 62-64, seção 5.3.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** BAD Produto - não \"(seqüência de caracteres)\".\n"
+" REF: Página 62, seção 5.3.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** BAD ShortNickName - maior que 31 caracteres.\n"
+" REF: Páginas 64-65, seção 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** FileVersion Inválida \"%s\"\n"
+" REF: Página 56, seção 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** FormatVersion Inválido \"%s\"\n"
+" REF: Página 56, seção 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr ""
+" **FAIL** O código de opção padrão não pode ser interpretado: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** REQUIRED Padrão%s\n"
+" REF: Página 40, seção 4.5.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Página 102, seção 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Página 103, seção 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Página 56, seção 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Página 56, seção 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** REQUIRED ImageableArea para PageSize %s\n"
+" REF: Página 41, seção 5.\n"
+" REF: Página 102, seção 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Páginas 56-57, seção 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Páginas 57-58, seção 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED Fabricante\n"
+" REF: Páginas 58-59, seção 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Páginas 59-60, seção 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Página 60, seção 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Páginas 61-62, seção 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Páginas 62-64, seção 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Página 100, seção 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Página 41, seção 5.\n"
+" REF: Página 99, seção 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Páginas 99-100, seção 5.14.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** REQUIRED PaperDimension para PageSize %s\n"
+" REF: Página 41, seção 5.\n"
+" REF: Página 103, seção 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED Produto\n"
+" REF: Página 62, seção 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Página 64-65, seção 5.3.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " %d ERROS ENCONTRADOS\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " NENHUM ERRO ENCONTRADO\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " FAIL\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** Não é possível abrir o arquivo - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** Não é possível abrir o arquivo PPD - %s na linha %d.\n"
+
+msgid " PASS\n"
+msgstr " PASS\n"
+
+msgid "#10 Envelope"
+msgstr "#10 Envelope"
+
+msgid "#11 Envelope"
+msgstr "#11 Envelope"
+
+msgid "#12 Envelope"
+msgstr "#12 Envelope"
+
+msgid "#14 Envelope"
+msgstr "#14 Envelope"
+
+msgid "#9 Envelope"
+msgstr "#9 Envelope"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f milímetros"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f a %.0f x %.0f milímetros"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f polegadas"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f a %.2f x %.2f polegadas"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s aceitando solicitações desde %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%s não pode ser alterado."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s não está implementado pela versão CUPS de lpc.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s não está pronto\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s está pronto\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s está pronto e imprimindo\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s não está aceitando solicitações desde %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s está aceitando solicitações desde %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s não está aceitando solicitações desde %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [trabalho %d localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s falhou: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: Erro - nenhum destino padrão disponível.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: Erro - prioridade deve estar entre 1 e 100.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: Erro - muitos arquivos - \"%s\"\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: Erro - não foi possível acessar \"%s\" - %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr ""
+"%s: Erro - não foi possível fazer a fila a partir da mensagem padrão - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: Filtro \"%s\" não disponível: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: Seqüência de caracteres inválida \"%s\"\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: Falha de operação: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: Não é possível conectar ao servidor\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: Não é possível abrir %s: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: Não é possível abrir um arquivo PPD: %s on-line %d\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: erro - nenhum destino padrão disponível.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 polegada/s"
+
+msgid "1.25x0.25\""
+msgstr "1.25x0.25\""
+
+msgid "1.25x2.25\""
+msgstr "1.25x2.25\""
+
+msgid "1.5 inch/sec."
+msgstr "1.5 polegada/s"
+
+msgid "1.50x0.25\""
+msgstr "1.50x0.25\""
+
+msgid "1.50x0.50\""
+msgstr "1.50x0.50\""
+
+msgid "1.50x1.00\""
+msgstr "1.50x1.00\""
+
+msgid "1.50x2.00\""
+msgstr "1.50x2.00\""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 polegadas/s"
+
+msgid "10 x 11\""
+msgstr "10 x 11\""
+
+msgid "10 x 13\""
+msgstr "10 x 13\""
+
+msgid "10 x 14\""
+msgstr "10 x 14\""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 mm/s"
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 polegadas/s"
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 polegadas/s"
+
+msgid "12 x 11\""
+msgstr "12 x 11\""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 mm/s"
+
+msgid "120x60dpi"
+msgstr "120x60ppp"
+
+msgid "120x72dpi"
+msgstr "120x72ppp"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136ppp"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 mm/s"
+
+msgid "15 x 11\""
+msgstr "15 x 11\""
+
+msgid "150 mm/sec."
+msgstr "150 mm/s"
+
+msgid "150dpi"
+msgstr "150ppp"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180ppp"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 polegadas/s"
+
+msgid "2-Sided Printing"
+msgstr "Impressão Frente e Verso"
+
+msgid "2.00x0.37\""
+msgstr "2.00x0.37\""
+
+msgid "2.00x0.50\""
+msgstr "2.00x0.50\""
+
+msgid "2.00x1.00\""
+msgstr "2.00x1.00\""
+
+msgid "2.00x1.25\""
+msgstr "2.00x1.25\""
+
+msgid "2.00x2.00\""
+msgstr "2.00x2.00\""
+
+msgid "2.00x3.00\""
+msgstr "2.00x3.00\""
+
+msgid "2.00x4.00\""
+msgstr "2.00x4.00\""
+
+msgid "2.00x5.50\""
+msgstr "2.00x5.50\""
+
+msgid "2.25x0.50\""
+msgstr "2.25x0.50\""
+
+msgid "2.25x1.25\""
+msgstr "2.25x1.25\""
+
+msgid "2.25x4.00\""
+msgstr "2.25x4.00\""
+
+msgid "2.25x5.50\""
+msgstr "2.25x5.50\""
+
+msgid "2.38x5.50\""
+msgstr "2.38x5.50\""
+
+msgid "2.5 inches/sec."
+msgstr "2.5 polegadas/s"
+
+msgid "2.50x1.00\""
+msgstr "2.50x1.00\""
+
+msgid "2.50x2.00\""
+msgstr "2.50x2.00\""
+
+msgid "2.75x1.25\""
+msgstr "2.75x1.25\""
+
+msgid "2.9 x 1\""
+msgstr "2.9 x 1\""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 mm/s"
+
+msgid "200 mm/sec."
+msgstr "200 mm/s"
+
+msgid "203dpi"
+msgstr "203ppp"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "Séries de 24 pinos"
+
+msgid "240x72dpi"
+msgstr "240x72ppp"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 mm/s"
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 polegadas/s"
+
+msgid "3.00x1.00\""
+msgstr "3.00x1.00\""
+
+msgid "3.00x1.25\""
+msgstr "3.00x1.25\""
+
+msgid "3.00x2.00\""
+msgstr "3.00x2.00\""
+
+msgid "3.00x3.00\""
+msgstr "3.00x3.00\""
+
+msgid "3.00x5.00\""
+msgstr "3.00x5.00\""
+
+msgid "3.25x2.00\""
+msgstr "3.25x2.00\""
+
+msgid "3.25x5.00\""
+msgstr "3.25x5.00\""
+
+msgid "3.25x5.50\""
+msgstr "3.25x5.50\""
+
+msgid "3.25x5.83\""
+msgstr "3.25x5.83\""
+
+msgid "3.25x7.83\""
+msgstr "3.25x7.83\""
+
+msgid "3.5\" Disk"
+msgstr "Disco de 3.5\""
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "Disco de 3.5\" - 2 1/8 x 2 3/4\""
+
+msgid "3.50x1.00\""
+msgstr "3.50x1.00\""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 mm/s"
+
+msgid "300 mm/sec."
+msgstr "300 mm/s"
+
+msgid "300dpi"
+msgstr "300ppp"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360ppp"
+
+msgid "360x180dpi"
+msgstr "360x180ppp"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 polegadas/s"
+
+msgid "4.00x1.00\""
+msgstr "4.00x1.00\""
+
+msgid "4.00x13.00\""
+msgstr "4.00x13.00\""
+
+msgid "4.00x2.00\""
+msgstr "4.00x2.00\""
+
+msgid "4.00x2.50\""
+msgstr "4.00x2.50\""
+
+msgid "4.00x3.00\""
+msgstr "4.00x3.00\""
+
+msgid "4.00x4.00\""
+msgstr "4.00x4.00\""
+
+msgid "4.00x5.00\""
+msgstr "4.00x5.00\""
+
+msgid "4.00x6.00\""
+msgstr "4.00x6.00\""
+
+msgid "4.00x6.50\""
+msgstr "4.00x6.50\""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 mm/s"
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 polegadas/s"
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 polegadas/s"
+
+msgid "6.00x1.00\""
+msgstr "6.00x1.00\""
+
+msgid "6.00x2.00\""
+msgstr "6.00x2.00\""
+
+msgid "6.00x3.00\""
+msgstr "6.00x3.00\""
+
+msgid "6.00x4.00\""
+msgstr "6.00x4.00\""
+
+msgid "6.00x5.00\""
+msgstr "6.00x5.00\""
+
+msgid "6.00x6.00\""
+msgstr "6.00x6.00\""
+
+msgid "6.00x6.50\""
+msgstr "6.00x6.50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/s"
+
+msgid "600dpi"
+msgstr "600ppp"
+
+msgid "60dpi"
+msgstr "60ppp"
+
+msgid "60x720dpi"
+msgstr "60x720ppp"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 polegadas/s"
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720ppp"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 polegadas/s"
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8.00x1.00\""
+
+msgid "8.00x2.00\""
+msgstr "8.00x2.00\""
+
+msgid "8.00x3.00\""
+msgstr "8.00x3.00\""
+
+msgid "8.00x4.00\""
+msgstr "8.00x4.00\""
+
+msgid "8.00x5.00\""
+msgstr "8.00x5.00\""
+
+msgid "8.00x6.00\""
+msgstr "8.00x6.00\""
+
+msgid "8.00x6.50\""
+msgstr "8.00x6.50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/s"
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 polegadas/s"
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "Séries de 9 pinos"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?Comando de ajuda inválido desconhecido\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (Excessivamente grande)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (Excessivamente grande)"
+
+msgid "A4 (Small)"
+msgstr "A4 (Pequeno)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (Excessivamente grande)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCO A"
+
+msgid "ARCH B"
+msgstr "ARCO B"
+
+msgid "ARCH C"
+msgstr "ARCO C"
+
+msgid "ARCH D"
+msgstr "ARCO D"
+
+msgid "ARCH E"
+msgstr "ARCO E"
+
+msgid "Accept Jobs"
+msgstr "Aceitar Trabalhos"
+
+msgid "Accepted"
+msgstr "Aceito"
+
+msgid "Add Class"
+msgstr "Adicionar Classe"
+
+msgid "Add Printer"
+msgstr "Adicionar Impressora"
+
+msgid "Add RSS Subscription"
+msgstr "Adicionar Inscrição RSS"
+
+msgid "Address"
+msgstr "Endereço"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "Endereço - 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "Administração"
+
+msgid "Always"
+msgstr "Sempre"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "Aplicador"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "Cursor NULL dests inválido"
+
+msgid "Bad OpenGroup"
+msgstr "OpenGroup Inválido"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "OpenUI/JCLOpenUI Inválido"
+
+msgid "Bad OrderDependency"
+msgstr "OrderDependency Inválido"
+
+msgid "Bad Request"
+msgstr "Pedido Inválido"
+
+msgid "Bad SNMP version number"
+msgstr "Número de versão SNMP inválido"
+
+msgid "Bad UIConstraints"
+msgstr "UIConstraints Inválido"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Valor de cópias inválidas %d."
+
+msgid "Bad custom parameter"
+msgstr "Parâmetro personalizado inválido"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Atributo de fonte inválido: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Valor de number-up inválido %d."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Valores de page-ranges inválidos %d-%d."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Banners"
+
+msgid "Billing Information: "
+msgstr "Informações de Cobrança: "
+
+msgid "Bond Paper"
+msgstr "Papel Bond"
+
+msgid "C0 Envelope"
+msgstr "Envelope C0"
+
+msgid "C1 Envelope"
+msgstr "Envelope C1"
+
+msgid "C2 Envelope"
+msgstr "Envelope C2"
+
+msgid "C3 Envelope"
+msgstr "Envelope C3"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "Envelope C4"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "Envelope C5"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "Envelope C6"
+
+msgid "C65 Envelope"
+msgstr "Envelope C65"
+
+msgid "C7 Envelope"
+msgstr "Envelope C7"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "Impressora de Etiqueta CPCL"
+
+msgid "Cancel RSS Subscription"
+msgstr "Cancelar Inscrição RSS"
+
+msgid "Change Settings"
+msgstr "Alterar Configurações"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Envelope Chou3"
+
+msgid "Chou4 Envelope"
+msgstr "Envelope Chou4"
+
+msgid "Classes"
+msgstr "Classes"
+
+msgid "Clean Print Heads"
+msgstr "Limpar Cabeçotes de Impressão"
+
+msgid "Color"
+msgstr "Cor"
+
+msgid "Color Mode"
+msgstr "Modo de Cor"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"Os comandos podem ser abreviados. Os comandos são:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "Nome de comunidade usa comprimento indefinido"
+
+msgid "Continue"
+msgstr "Continuar"
+
+msgid "Continuous"
+msgstr "Contínuo"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Criado"
+
+msgid "Created On: "
+msgstr "Criado em: "
+
+msgid "Custom"
+msgstr "Personalizar"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Cortar"
+
+msgid "Cutter"
+msgstr "Guilhotina"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "Envelope DL"
+
+msgid "Dark"
+msgstr "Escuro"
+
+msgid "Darkness"
+msgstr "Escuridão"
+
+msgid "Delete Class"
+msgstr "Apagar Classe"
+
+msgid "Delete Printer"
+msgstr "Apagar Impressora"
+
+msgid "Description: "
+msgstr "Descrição: "
+
+msgid "DeskJet Series"
+msgstr "DeskJet Series"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "O destino \"%s\" não está aceitando trabalhos."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"Dispositivo: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "Mídia Termal Direta"
+
+msgid "Disabled"
+msgstr "Desativado"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "Documento %d não encontrado no trabalho %d."
+
+msgid "Double Postcard"
+msgstr "Cartão-Postal Duplo"
+
+msgid "Driver Name: "
+msgstr "Nome do Driver: "
+
+msgid "Driver Version: "
+msgstr "Versão do Driver: "
+
+msgid "Duplexer"
+msgstr "Duplexer"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: Não é possível alocar memória para informação de página: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: Não é possível alocar memória para matriz de páginas: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "Impressora de Etiquetas EPL1"
+
+msgid "EPL2 Label Printer"
+msgstr "Impressora de Etiquetas EPL2"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: Arquivo de conjunto de caracteres inválido %s\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: Tipo de conjunto de caracteres inválido %s\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: Linha de descrição de fonte inválida: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: Direção de texto inválida %s\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: Largura de texto inválida %s\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: Erro %d ao enviar pedido PAPSendData: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: Nenhuma fonte no arquivo de conjunto de caracteres %s\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: A impressora não responde\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: A impressora enviou um EOF inesperado\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: Host remoto não aceitou o arquivo de controle (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: Host remoto não aceitou o arquivo de dados (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr ""
+"ERROR: Houve um erro de tempo esgotado ao enviar os dados à impressora\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: Não é possível adicionar o arquivo %d ao trabalho: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: Não é possível cancelar o trabalho %d: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: Não foi possível copiar o arquivo PDF"
+
+msgid "ERROR: Unable to create pipe"
+msgstr ""
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: Não foi possível criar soquete"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: Não é possível criar o arquivo de impressão comprimido temporário: %"
+"s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: Não é possível criar o arquivo temporário"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: Não é possível executar pictwpstops: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: Não é possível executar o programa gs"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: Não é possível executar o programa pdftops"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: Não é possível forçar pictwpstops: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: Não é possível obter o pedido PAP"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: Não é possível obter a resposta PAP"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr ""
+"ERROR: Não é possível obter o arquivo PPD para a impressora \"%s\" - %s.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: Não é possível obter a zona AppleTalk"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: Não é possível procurar a resposta PAP"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: Não é possível buscar impressoras AppleTalk"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: Não é possível criar o endereço AppleTalk"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: Não é possível abrir \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: Não é possível abrir %s: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: Não é possível abrir o arquivo de banner \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: Não é possível abrir o arquivo de dispositivo \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: Não é possível abrir o arquivo \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: Não é possível abrir o arquivo \"%s\": %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: Não é possível abrir o arquivo de impressão \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: Não é possível abrir o arquivo de impressão %s - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: Não é possível abrir o arquivo de impressão %s: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr ""
+"ERROR: Não é possível abrir o arquivo de impressão comprimido temporário: %"
+"s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: Não é possível ler os dados de impressão"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: Não é possível reservar porta"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: Não é possível localizar o deslocamento %ld no arquivo- %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: Não é possível localizar o deslocamento %lld no arquivo - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: Não é possível enviar um comando LPD"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: Não é possível enviar um pedido tickle de PAP"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: Não é possível enviar o pedido de dados de envio PAP inicial"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: Não é possível enviar o arquivo de impressão à impressora"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr ""
+"ERROR: Não é possível enviar o valor nulo do fim da seqüência à impressora"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: Não é possível aguardar pictwpstops: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: Não é possível gravar %d bytes para \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: Não é possível gravar no arquivo de controle"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: Não é possível gravar dados de impressão"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: Não é possível gravar os dados de impressão: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr ""
+"ERROR: Não é possível gravar os dados de documentos não comprimidos: %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: Ordem de arquivo desconhecida \"%s\"\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: Caractere de formato desconhecido \"%c\"\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: Modo de impressão desconhecido \"%s\"\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: Seleção() falhou"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: Não foi possível iniciar o arquivo de impressão"
+
+msgid "Edit Configuration File"
+msgstr "Editar Arquivo de Configuração"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Finalizando Banner"
+
+msgid "English"
+msgstr "Portuguese"
+
+msgid "Enter old password:"
+msgstr "Digite a senha antiga:"
+
+msgid "Enter password again:"
+msgstr "Digite a senha novamente:"
+
+msgid "Enter password:"
+msgstr "Digite a senha:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Digite o seu nome de usuário e a sua senha ou o nome de usuário e a senha de "
+"root para acessar esta página. Se estiver usando a autenticação Kerberos, "
+"certifique-se de possuir uma entrada Kerberos válida."
+
+msgid "Envelope Feed"
+msgstr "Alimentação de Envelopes"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Política de Erro"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "A cada 10 etiquetas"
+
+msgid "Every 2 Labels"
+msgstr "A cada 2 etiquetas"
+
+msgid "Every 3 Labels"
+msgstr "A cada 3 etiquetas"
+
+msgid "Every 4 Labels"
+msgstr "A cada 4 etiquetas"
+
+msgid "Every 5 Labels"
+msgstr "A cada 5 etiquetas"
+
+msgid "Every 6 Labels"
+msgstr "A cada 6 etiquetas"
+
+msgid "Every 7 Labels"
+msgstr "A cada 7 etiquetas"
+
+msgid "Every 8 Labels"
+msgstr "A cada 8 etiquetas"
+
+msgid "Every 9 Labels"
+msgstr "A cada 9 etiquetas"
+
+msgid "Every Label"
+msgstr "Todas as Etiquetas"
+
+msgid "Expectation Failed"
+msgstr "Falha de Expectativa"
+
+msgid "Export Printers to Samba"
+msgstr "Exportar Impressoras para Samba"
+
+msgid "FAIL\n"
+msgstr "FAIL\n"
+
+msgid "File Folder"
+msgstr "Pasta de Arquivo"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Pasta de Arquivo - 9/16 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"URIs de dispositivo de arquivo foram desativados! Para ativá-los, consulte a "
+"diretiva FileDevice em \"%s/cupsd.conf\"."
+
+msgid "Folio"
+msgstr "Fólio"
+
+msgid "Forbidden"
+msgstr "Esquecido"
+
+msgid "General"
+msgstr "Geral"
+
+msgid "Generic"
+msgstr "Genérico"
+
+msgid "German FanFold"
+msgstr "German FanFold"
+
+msgid "German FanFold Legal"
+msgstr "German FanFold Legal"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU usa comprimento indefinido"
+
+msgid "Glossy Paper"
+msgstr "Papel Brilhante"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Escala de Cinzas"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Pasta Suspensa"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Pasta Suspensa - 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk desativado nas Preferências do Sistema\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk desativado nas Preferências do Sistema.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: Cancelando trabalho de impressão...\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: Conectado à impressora...\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: Conectando à impressora...\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: Arquivo de controle enviado com êxito\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr ""
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: Arquivo de dados enviado com êxito\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: Formatando página %d...\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: Carregando arquivo de imagem...\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: Buscando impressora...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: Abrindo conexão\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr ""
+"INFO: Arquivo de impressão enviado, aguardando conclusão da impressora...\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: Impressora ocupada; nova tentativa em 10 segundos...\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: Impressora ocupada; nova tentativa em 30 segundos...\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: Impressora ocupada; nova tentativa em 5 segundos...\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr ""
+"INFO: A impressora não é compatível com IPP/%d.%d, tentando IPP/1.0...\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: A impressora está ocupada; nova tentativa em 5 segundos...\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: A impressora está atualmente desligada.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: A impressora está desligada atualmente.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: A impressora está conectada agora.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: A impressora está desligada.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: Impressora não conectada; nova tentativa em 30 segundos...\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: Imprimindo página %d, %d%% concluído...\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: Imprimindo página %d...\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: Pronta para imprimir.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: Enviando arquivo de controle (%lu bytes)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: Enviando arquivo de controle (%u bytes)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: Enviando dados\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: Enviando arquivo de dados (%ld bytes)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: Enviando arquivo de dados (%lld bytes)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: Enviando dados de impressão...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: Arquivo de impressão enviado, %ld bytes...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: Arquivo de impressão enviado, %lld bytes...\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: Armazenando trabalho LPR, %.0f%% concluído...\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr ""
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: Não foi possível contactar a impressora, enfileirando na próxima "
+"impressora na classe...\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: Usando zona AppleTalk padrão \"%s\"\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: Aguardando conclusão do trabalho...\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: Esperando que a impressora esteja disponível...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "Envelope ISO B4"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (Exces. grande)"
+
+msgid "ISO B5 Envelope"
+msgstr "Envelope ISO B5"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "Envelope ISO B6"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "Caractere de controle ilegal"
+
+msgid "Illegal main keyword string"
+msgstr "Seqüência de caracteres de palavra-chave principal ilegal"
+
+msgid "Illegal option keyword string"
+msgstr "Seqüência de caracteres de palavra-chave de opção ilegal"
+
+msgid "Illegal translation string"
+msgstr "Seqüência de caracteres de tradução ilegal"
+
+msgid "Illegal whitespace character"
+msgstr "Seqüência de caracteres de espaço em branco ilegal"
+
+msgid "Installable Options"
+msgstr "Opções Instaláveis"
+
+msgid "Installed"
+msgstr "Instalado"
+
+msgid "IntelliBar Label Printer"
+msgstr "Impressora de Etiquetas IntelliBar"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr ""
+
+msgid "Internal error"
+msgstr "Erro interno"
+
+msgid "Internet Postage 2-Part"
+msgstr "Porte de Internet 2-Part"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Porte de Internet 2-Part - 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "Porte de Internet 3-Part"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Porte de Internet 3-Part - 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "Protocolo de Impressão da Internet"
+
+msgid "Invite Envelope"
+msgstr "Envelope de Convite"
+
+msgid "Italian Envelope"
+msgstr "Envelope Italiano"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "O trabalho #%d já foi anulado - não é possível cancelar."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "O trabalho #%d já foi cancelado - não é possível cancelar."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "O trabalho #%d já está concluído - não é possível cancelar."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "Trabalho Concluído"
+
+msgid "Job Created"
+msgstr "Trabalho Criado"
+
+msgid "Job ID: "
+msgstr "ID de Trabalho: "
+
+msgid "Job Options Changed"
+msgstr "Opções de Trabalho Alteradas"
+
+msgid "Job Stopped"
+msgstr "Trabalho Parado"
+
+msgid "Job UUID: "
+msgstr "UUID de Trabalho: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "O trabalho está concluído e não pode ser alterado."
+
+msgid "Job operation failed:"
+msgstr "Falha de operação de trabalho:"
+
+msgid "Job state cannot be changed."
+msgstr "O estado do trabalho não pode ser alterado."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "Trabalhos"
+
+msgid "Kaku2 Envelope"
+msgstr "Envelope Kaku2"
+
+msgid "Kaku3 Envelope"
+msgstr "Envelope Kaku3"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "Host ou Impressora LPD/LPR"
+
+msgid "Label Printer"
+msgstr "Impressora de Etiquetas"
+
+msgid "Label Top"
+msgstr "Parte Superior da Etiqueta"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Endereço Grande"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Endereço Grande - 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet Series PCL 4/5"
+
+msgid "Light"
+msgstr "Claro"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Linha maior do que o máximo permitido (255 caracteres)"
+
+msgid "List Available Printers"
+msgstr "Listar Impressoras Disponíveis"
+
+msgid "Location: "
+msgstr "Localização: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "Margem Grande (Vertical)"
+
+msgid "Make and Model: "
+msgstr "Fazer e Modelar: "
+
+msgid "Manual Feed"
+msgstr "Alimentação Manual"
+
+msgid "Media Dimensions: "
+msgstr "Dimensões dos Meios: "
+
+msgid "Media Limits: "
+msgstr "Limites dos Meios: "
+
+msgid "Media Name: "
+msgstr "Nome dos Meios: "
+
+msgid "Media Size"
+msgstr "Tamanho de Mídia"
+
+msgid "Media Source"
+msgstr "Fonte de Mídia"
+
+msgid "Media Tracking"
+msgstr "Rastreamento dos Meios"
+
+msgid "Media Type"
+msgstr "Tipo de Mídia"
+
+msgid "Medium"
+msgstr "Médio"
+
+msgid "Memory allocation error"
+msgstr "Erro de alocação de memória"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "Cabeçalho PPD-Adobe-4.x ausente"
+
+msgid "Missing asterisk in column 1"
+msgstr "Asterisco ausente na coluna 1"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "Seqüência de caracteres de valor ausente"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Modelo: nome = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "Modificar Classe"
+
+msgid "Modify Printer"
+msgstr "Modificar Impressora"
+
+msgid "Monarch"
+msgstr "Monarca"
+
+msgid "Monarch Envelope"
+msgstr "Envelope Monarca"
+
+msgid "Move All Jobs"
+msgstr "Mover Todos os Trabalhos"
+
+msgid "Move Job"
+msgstr "Mover Trabalho"
+
+msgid "Moved Permanently"
+msgstr "Movido Permanentemente"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: Arquivo de impressão aceito - ID de trabalho %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: Arquivo de impressão aceito - ID de trabalho desconhecido.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "Ponteiro de arquivo NULL PPD"
+
+msgid "Name OID uses indefinite length"
+msgstr "OID do nome usa comprimento indefinido"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Nunca"
+
+msgid "New Stylus Color Series"
+msgstr "New Stylus Color Series"
+
+msgid "New Stylus Photo Series"
+msgstr "New Stylus Photo Series"
+
+msgid "No"
+msgstr "Não"
+
+msgid "No Content"
+msgstr "Sem Conteúdo"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "Nenhuma VarBind SEQUENCE"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "Nenhuma conexão ativa"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "Nenhum nome de comunidade"
+
+msgid "No default printer"
+msgstr "Nenhuma impressora padrão"
+
+msgid "No destinations added."
+msgstr "Nenhum destino adicionado."
+
+msgid "No error-index"
+msgstr "Nenhum error-index"
+
+msgid "No error-status"
+msgstr "Nenhum error-status"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "Nenhum OID de nome"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "Nenhum request-id"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "Nenhuma inscrição encontrada."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "Nenhuma variable-bindings SEQUENCE"
+
+msgid "No version number"
+msgstr "Nenhum número de versão"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "Descontínuo (Leitura de marcas)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "Descontínuo (Leitura Web)"
+
+msgid "Normal"
+msgstr "Normal"
+
+msgid "Not Found"
+msgstr "Não Encontrado"
+
+msgid "Not Implemented"
+msgstr "Não Implementado"
+
+msgid "Not Installed"
+msgstr "Não Instalado"
+
+msgid "Not Modified"
+msgstr "Não Modificado"
+
+msgid "Not Supported"
+msgstr "Incompatível"
+
+msgid "Not allowed to print."
+msgstr "Não permitido para impressão."
+
+msgid "Note"
+msgstr "Nota"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Off (1-Sided)"
+msgstr "Desligado (Frente)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Ajuda On-line"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "falha na abertura de %s: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup sem um CloseGroup primeiro"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI sem um CloseUI/JCLCloseUI primeiro"
+
+msgid "Operation Policy"
+msgstr "Política de Operação"
+
+msgid "Options Installed"
+msgstr "Opções Instaladas"
+
+msgid "Options: "
+msgstr "Opções: "
+
+msgid "Output Mode"
+msgstr "Modo de Saída"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "A saída para impressora %s foi enviada a %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr "A saída para impressora %s foi enviada à impressora remota %s em %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "A saída para impressora %s/%s foi enviada a %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr ""
+"A saída para impressora %s/%s foi enviada para a impressora remota %s em %s\n"
+
+msgid "PASS\n"
+msgstr "PASS\n"
+
+msgid "PCL Laser Printer"
+msgstr "Impressora Laser PCL"
+
+msgid "PRC1 Envelope"
+msgstr "Envelope PRC1"
+
+msgid "PRC10 Envelope"
+msgstr "Envelope PRC10"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "Envelope PRC2"
+
+msgid "PRC3 Envelope"
+msgstr "Envelope PRC3"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (Exces. grande)"
+
+msgid "PRC4 Envelope"
+msgstr "Envelope PRC4"
+
+msgid "PRC5 Envelope"
+msgstr "Envelope PRC5"
+
+msgid "PRC6 Envelope"
+msgstr "Envelope PRC6"
+
+msgid "PRC7 Envelope"
+msgstr "Envelope PRC7"
+
+msgid "PRC8 Envelope"
+msgstr "Envelope PRC8"
+
+msgid "PRC9 Envelope"
+msgstr "Envelope PRC9"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "O pacote não contém uma Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "O pacote não começa com SEQUENCE"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "Senha para %s em %s? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "A senha para %s requerida para acessar %s através do SAMBA: "
+
+msgid "Pause Class"
+msgstr "Interromper Classe"
+
+msgid "Pause Printer"
+msgstr "Colocar Impressora em Pausa"
+
+msgid "Peel-Off"
+msgstr "Soltar"
+
+msgid "Personal Envelope"
+msgstr "Envelope Pessoal"
+
+msgid "Photo"
+msgstr "Foto"
+
+msgid "Photo Labels"
+msgstr "Etiquetas de Foto"
+
+msgid "Plain Paper"
+msgstr "Papel Normal"
+
+msgid "Policies"
+msgstr "Políticas"
+
+msgid "Port Monitor"
+msgstr "Monitor da Porta"
+
+msgid "PostScript Printer"
+msgstr "Impressora PostScript"
+
+msgid "Postcard"
+msgstr "Cartão-Postal"
+
+msgid "Print Density"
+msgstr "Densidade da Impressão"
+
+msgid "Print Job:"
+msgstr "Imprimir Trabalho:"
+
+msgid "Print Mode"
+msgstr "Modo de Impressão"
+
+msgid "Print Rate"
+msgstr "Taxa de Impressão"
+
+msgid "Print Self-Test Page"
+msgstr "Imprimir Página de Autoteste"
+
+msgid "Print Speed"
+msgstr "Velocidade de Impressão"
+
+msgid "Print Test Page"
+msgstr "Imprimir Página de Teste"
+
+msgid "Print and Cut"
+msgstr "Imprimir e Cortar"
+
+msgid "Print and Tear"
+msgstr "Imprimir e Romper"
+
+msgid "Printed For: "
+msgstr "Impresso para: "
+
+msgid "Printed From: "
+msgstr "Impresso de: "
+
+msgid "Printed On: "
+msgstr "Impresso em: "
+
+msgid "Printer Added"
+msgstr "Impressora Adicionada"
+
+msgid "Printer Default"
+msgstr "Padrão de Impressora"
+
+msgid "Printer Deleted"
+msgstr "Impressora Apagada"
+
+msgid "Printer Modified"
+msgstr "Impressora Modificada"
+
+msgid "Printer Name: "
+msgstr "Nome de Impressora: "
+
+msgid "Printer Paused"
+msgstr "Impressora em Pausa"
+
+msgid "Printer Settings"
+msgstr "Ajustes da Impressora"
+
+msgid "Printer:"
+msgstr "Impressora:"
+
+msgid "Printers"
+msgstr "Impressoras"
+
+msgid "Purge Jobs"
+msgstr "Ignorar Trabalhos"
+
+msgid "Quarto"
+msgstr "Quarto"
+
+msgid "Quota limit reached."
+msgstr "Limite de quota alcançado."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr ""
+"Rank Proprietário Trabalho Arquivo(s) "
+"Tamanho Total\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"Rank Proprietário Imp Trabalho Arquivos "
+"Tamanho Total\n"
+
+msgid "Reject Jobs"
+msgstr "Rejeitar Trabalhos"
+
+msgid "Reprint After Error"
+msgstr "Imprimir Novamente Após Erro"
+
+msgid "Request Entity Too Large"
+msgstr "Entidade do Pedido Muito Grande"
+
+msgid "Resolution"
+msgstr "Resolução"
+
+msgid "Resume Class"
+msgstr "Retomar Classe"
+
+msgid "Resume Printer"
+msgstr "Retomar Impressora"
+
+msgid "Return Address"
+msgstr "Endereço de Devolução"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Endereço de Devolução - 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "Retroceder"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Executando comando: %s %s -N -A %s -c '%s'\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE usa comprimento indefinido"
+
+msgid "See Other"
+msgstr "Ver Outro"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "Porta serial nº%d"
+
+msgid "Server Restarted"
+msgstr "Servidor Reiniciado"
+
+msgid "Server Security Auditing"
+msgstr "Auditoria de Segurança de Servidor"
+
+msgid "Server Started"
+msgstr "Servidor Iniciado"
+
+msgid "Server Stopped"
+msgstr "Servidor Parado"
+
+msgid "Service Unavailable"
+msgstr "Serviço Não Disponível"
+
+msgid "Set Allowed Users"
+msgstr "Definir Usuários Permitidos"
+
+msgid "Set As Server Default"
+msgstr "Definir como Padrão de Servidor"
+
+msgid "Set Class Options"
+msgstr "Definir Opções de Classe"
+
+msgid "Set Printer Options"
+msgstr "Definir Opções de Impressão"
+
+msgid "Set Publishing"
+msgstr "Definir Publicação"
+
+msgid "Shipping Address"
+msgstr "Endereço de Remessa"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "Endereço de Remessa - 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "Margem Pequena (Horizontal)"
+
+msgid "Special Paper"
+msgstr "Papel Especial"
+
+msgid "Standard"
+msgstr "Padrão"
+
+msgid "Starting Banner"
+msgstr "Iniciando Banner"
+
+msgid "Statement"
+msgstr "Instrução"
+
+msgid "Stylus Color Series"
+msgstr "Stylus Color Series"
+
+msgid "Stylus Photo Series"
+msgstr "Stylus Photo Series"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "Alternando Protocolos"
+
+msgid "Tabloid"
+msgstr "Tablóide"
+
+msgid "Tabloid (Oversize)"
+msgstr "Tablóide (Exces. grande)"
+
+msgid "Tear"
+msgstr "Rasgar"
+
+msgid "Tear-Off"
+msgstr "Remover"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Remover Posição de Ajuste"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "O arquivo PPD \"%s\" não pôde ser encontrado."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "O arquivo PPD \"%s\" não pôde ser aberto: %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"O nome de classe pode conter apenas até 127 caracteres imprimíveis e não "
+"pode conter espaços, barras (/) ou o sinal de quadrado (#)."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+"O atributo notify-lease-duration não pode ser usado com as inscrições de "
+"trabalho."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"O nome da impressora somente pode conter até 127 caracteres imprimíveis e "
+"não pode conter espaços, barras (/) ou o sinal de quadrado (#)."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "A impressora ou a classe não foram encontradas."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "O printer-uri \"%s\" contém caracteres inválidos."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr ""
+"O printer-uri deve ser do formato \"ipp://HOSTNAME/classes/CLASSNAME\"."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+"O printer-uri deve ser do formato \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"O nome de inscrição pode não conter espaços, barras (/), pontos de "
+"interrogação (?) ou o sinal de quadrado (#)."
+
+msgid "There are too many subscriptions."
+msgstr "Há muitas assinaturas."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "Mídia de Transferência Termal"
+
+msgid "Title: "
+msgstr "Título: "
+
+msgid "Too many active jobs."
+msgstr "Muitos trabalhos ativos."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "Transparência"
+
+msgid "Tray"
+msgstr "Bandeja"
+
+msgid "Tray 1"
+msgstr "Bandeja 1"
+
+msgid "Tray 2"
+msgstr "Bandeja 2"
+
+msgid "Tray 3"
+msgstr "Bandeja 3"
+
+msgid "Tray 4"
+msgstr "Bandeja 4"
+
+msgid "URI Too Long"
+msgstr "URI Muito Extenso"
+
+msgid "US Executive"
+msgstr "Executivo EUA"
+
+msgid "US Fanfold"
+msgstr "US Fanfold"
+
+msgid "US Ledger"
+msgstr "Duplo Carta EUA"
+
+msgid "US Legal"
+msgstr "Legal EUA"
+
+msgid "US Legal (Oversize)"
+msgstr "Legal EUA (Muito Grande)"
+
+msgid "US Letter"
+msgstr "Carta EUA"
+
+msgid "US Letter (Oversize)"
+msgstr "Carta EUA (Muito Grande)"
+
+msgid "US Letter (Small)"
+msgstr "Carta EUA (Pequeno)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "Porta Serial USB nº%d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "Não é possível acessar cupsd.conf file:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "Não é possível adicionar a inscrição RSS:"
+
+msgid "Unable to add class:"
+msgstr "Não é possível adicionar a classe:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "Não é possível adicionar a impressora:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "Não é possível cancelar a inscrição RSS:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "Não é possível alterar o atributo printer-is-shared:"
+
+msgid "Unable to change printer:"
+msgstr "Não é possível alterar a impressora:"
+
+msgid "Unable to change server settings:"
+msgstr "Não é possível alterar as configurações do servidor:"
+
+msgid "Unable to connect to host."
+msgstr "Não é possível conectar ao host."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "Não é possível criar o arquivo temporário:"
+
+msgid "Unable to delete class:"
+msgstr "Não é possível apagar a classe:"
+
+msgid "Unable to delete printer:"
+msgstr "Não é possível apagar a impressora:"
+
+msgid "Unable to do maintenance command:"
+msgstr "Não é possível fazer um comando de manutenção:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "Não é possível obter a lista de classe:"
+
+msgid "Unable to get class status:"
+msgstr "Não é possível obter o estado de classe:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "Não é possível obter uma lista de drivers de impressora:"
+
+msgid "Unable to get printer attributes:"
+msgstr "Não é possível obter os atributos de impressora:"
+
+msgid "Unable to get printer list:"
+msgstr "Não é possível obter a lista de impressão:"
+
+msgid "Unable to get printer status:"
+msgstr "Não é possível obter o estado da impressora:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "Não é possível modificar a classe:"
+
+msgid "Unable to modify printer:"
+msgstr "Não é possível modificar a impressora:"
+
+msgid "Unable to move job"
+msgstr "Não é possível mover o trabalho"
+
+msgid "Unable to move jobs"
+msgstr "Não é possível mover os trabalhos"
+
+msgid "Unable to open PPD file"
+msgstr "Não é possível abrir o arquivo PPD"
+
+msgid "Unable to open PPD file:"
+msgstr "Não é possível abrir o arquivo PPD:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "Não é possível abrir o arquivo cupsd.conf:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "Não é possível imprimir uma página de teste:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "Não é possível executar \"%s\": %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "Não é possível definir as opções:"
+
+msgid "Unable to set server default:"
+msgstr "Não é possível definir o padrão do servidor:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "Não é possível carregar o arquivo cupsd.conf:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "Não autorizado"
+
+msgid "Units"
+msgstr "Unidades"
+
+msgid "Unknown"
+msgstr "desconhecido"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "printer-error-policy desconhecido \"%s\"."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "printer-op-policy desconhecido \"%s\"."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Tipo de valor incompatível"
+
+msgid "Upgrade Required"
+msgstr "Atualização Requerida"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr ""
+"Usage: %s opções de cópias de título do usuário do trabalho [filename]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "Usage: opções de cópias de título de usuário %s job-id [file]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "Usage: arquivo de opções de cópias de título de usuário %s job-id \n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Opções:\n"
+" -E Encriptar a conexão ao servidor\n"
+" -H samba-server Usar o servidor SAMBA denominado\n"
+" -U samba-user Autenticar usando o usuário do SAMBA denominado\n"
+" -a Exportar todas as impressoras\n"
+" -h cups-server Usar o servidor CUPS denominado\n"
+" -v Ser detalhado (mostrar comandos)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Opções:\n"
+"\n"
+" -E Ativar encriptação\n"
+" -U username Especificar username\n"
+" -h server[:port] Especificar endereço do servidor\n"
+"\n"
+" --[no-]debug-logging Ativar/desativar registro de depuração\n"
+" --[no-]remote-admin Ativar/desativar administração remota\n"
+" --[no-]remote-any Permitir/evitar acesso a partir da Internet\n"
+" --[no-]remote-printers Mostrar/ocultar impressoras remotas\n"
+" --[no-]share-printers Ativar/desativar compartilhamento de impressora\n"
+" --[no-]user-cancel-any Permitir/evitar que usuários cancelem qualquer "
+"trabalho\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Carregar arquivo de configuração alternativa\n"
+"-f Executar em segundo plano\n"
+"-F Executar em segundo plano, porém destacar\n"
+"-h Mostrar esta mensagem de uso\n"
+"-l Executar cupsd a partir de launchd(8)\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Opções:\n"
+"\n"
+" -h Mostrar utilização do programa\n"
+"\n"
+" Nota: este programa apenas valida os comentários DSC, não o próprio "
+"PostScript.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Usage: lpmove job/src dest\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Usage: lppasswd [-g groupname]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Opções:\n"
+" -D name=value Definir variável denominada ao valor.\n"
+" -I include-dir Adicionar diretório de inclusão ao caminho da busca.\n"
+" -c catalog.po Carregar o catálogo da mensagem especificada.\n"
+" -d output-dir Especificar o diretório de saída.\n"
+" -l lang[,lang,...] Especificar o(s) idioma(s) de saída (local).\n"
+" -m Usar o valor ModelName como nome de arquivo.\n"
+" -t Testar PPDs em vez de gerá-los.\n"
+" -v Ser detalhado (mais v's para maior detalhamento).\n"
+" -z Comprimir arquivos PPD usando GNU zip.\n"
+" --cr Terminar linhas com CR (Mac OS 9).\n"
+" --crlf Terminar linhas com CR + LF (Windows).\n"
+" --lf Terminar linhas com LF (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Definir variável denominada ao valor.\n"
+"Options:\n"
+" -I include-dir Adicionar diretório de inclusão ao caminho da busca.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Opções:\n"
+" -o filename.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Opções:\n"
+" -D name=value Definir variável denominada ao valor.\n"
+" -I include-dir Adicionar diretório de inclusão ao caminho da busca.\n"
+" -v Ser detalhado (mais v's para maior detalhamento).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Usage: snmp [host-or-ip-address]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Valor usa comprimento indefinido"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind usa comprimento indefinido"
+
+msgid "Version uses indefinite length"
+msgstr "Versão usa comprimento indefinido"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: Adicionando somente as primeiras %d impressoras encontradas"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: Boleano esperado para opção waiteof \"%s\"\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: A impressora não responde\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: A impressora enviou um EOF inesperado\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: Não é possível abrir \"%s:%s\": %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: Não é possível enviar o pedido de estado PAP"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: Pacote PAP do tipo %d\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: Pacote PAP desconhecido do tipo %d\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: número esperado para a opção de estado \"%s\"\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Sim"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"Você deve acessar esta página usando a URL <A HREF=\"https://%s:%d%s"
+"\">https://%s:%d%s</A>."
+
+msgid "You4 Envelope"
+msgstr "Envelope You4"
+
+msgid "ZPL Label Printer"
+msgstr "Impressora de Etiquetas ZPL"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "anulado"
+
+msgid "canceled"
+msgstr "cancelado"
+
+msgid "completed"
+msgstr "concluído"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr "convert: use a opção -f para especificar um arquivo para converter.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "falha de cups-deviced ao executar."
+
+msgid "cups-driverd failed to execute."
+msgstr "falha de cups-driverd ao executar."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: Nenhum arquivo PPD para a impressora \"%s\" - %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: não é possível conectar ao servidor: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr "cupsd: suporte launchd(8) não compilado, executando em modo normal.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: não é possível obter o arquivo de trabalho - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd: A opção -q é incompatível com a opção -v.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd: A opção -v é incompatível com a opção -q.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "dispositivo para %s/%s: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "dispositivo para %s: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "error-index usa comprimento indefinido"
+
+msgid "error-status uses indefinite length"
+msgstr "error-status usa comprimento indefinido"
+
+msgid "held"
+msgstr "mantido"
+
+msgid "help\t\tget help on commands\n"
+msgstr "ajuda\t\tobter ajuda sobre os comandos\n"
+
+msgid "idle"
+msgstr "ocioso"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: A impressora %s já é um membro de classe %s.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: A impressora %s não é um membro de classe %s.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: Não é possível conectar-se ao servidor: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: Não é possível abrir um arquivo PPD \"%s\" - %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: Não é possível abrir o arquivo \"%s\": %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: Não é possível conectar-se ao servidor: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: Não é possível adicionar impressora ou instância: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: Não é possível obter o arquivo PPD para %s: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: Desculpe, senha rejeitada.\n"
+"A sua senha deve ter pelo menos 6 caracteres, não pode conter\n"
+"o seu nome de usuário e deve possuir pelo menos uma letra e um número.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr ""
+"lppasswd: Não é possível copiar a seqüência de caracteres da senha: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: Não é possível abrir o arquivo de senha: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: Não é possível gravar para o arquivo de senha: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr "lppasswd: falha ao fazer backup do arquivo de senha antigo: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: falha ao renomear o arquivo de senha: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: usuário \"%s\" e grupo \"%s\" não existem.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "membros de classe %s:\n"
+
+msgid "no entries\n"
+msgstr "nenhuma entrada\n"
+
+msgid "no system default destination\n"
+msgstr "nenhum destino padrão de sistema\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "pendente"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: adicionando diretório de inclusão \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: adicionando/atualizando texto UI de %s...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: valor booleano inválido (%s) na linha %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: substituição de variável inválida ($%c) na linha %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: valor booleano esperado na linha %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: código de escolha esperado na linha %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: nome/texto de escolha esperado na linha %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: carregando arquivo de informações de driver \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: carregando mensagens para localidade \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: carregando mensagens de \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: não é possível criar um arquivo PPD \"%s\" - %s.\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: não é possível criar o diretório de saída %s: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: não é possível criar canais de saída: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: não é possível executar cupstestppd: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: Não é possível buscar a localização para \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: Não é possível carregar o arquivo de localização \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: Variável indefinida (%s) na linha %d de %s.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: gravando %s...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: gravando arquivos PPD no diretório \"%s\"...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: ignorando arquivo PPD %s...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: não é possível fazer o backup de %s em %s- %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "impressora %s desativada desde %s -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "impressora %s está ociosa. ativada desde %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "impressora %s agora está imprimindo %s-%d. ativada desde %s\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "impressora %s/%s desativada desde %s -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "impressora %s/%s está ociosa. ativada desde %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "impressora %s/%s agora está imprimindo %s-%d. ativada desde %s\n"
+
+msgid "processing"
+msgstr "processando"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "id solicitado é %s-%d (%d arquivo(s))\n"
+
+msgid "request-id uses indefinite length"
+msgstr "request-id usa comprimento indefinido"
+
+msgid "scheduler is not running\n"
+msgstr "o programador não está executando\n"
+
+msgid "scheduler is running\n"
+msgstr "o programador está executando\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "falha de stat de %s: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "estado status\t\tshow de daemon e da fila\n"
+
+msgid "stopped"
+msgstr "parado"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "destino padrão de sistema: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "destino padrão de sistema: %s/%s\n"
+
+msgid "unknown"
+msgstr "desconhecido"
+
+msgid "untitled"
+msgstr "sem título"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindings usa comprimento indefinido"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " WARN %s não possui opções correspondentes!\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " WARN Conflito de opções padrão!\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " WARN Talvez a opção dúplex do teclado %s não funcione como "
+#~ "esperado e deve ser denominada Dúplex!\n"
+#~ " REF: Página 122, seção 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " WARN O arquivo contém um mix de terminações de linha CR, LF e "
+#~ "CR LF!\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " WARN A linha %d contém apenas espaços em branco!\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " WARN Arquivo APDialogExtension ausente \"%s\"\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " WARN Arquivo APPrinterIconPath ausente \"%s\"\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " WARN Os arquivos PPD que não sejam do Windows devem usar "
+#~ "linhas que terminem apenas com LF, e não com CR LF!\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " WARN Versão PPD obsoleta%.1f!\n"
+#~ " REF: Página 42, seção 5.2.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s não existe!\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s Escolha %s inválida %s!\n"
+#~ " REF: Página 122, seção 5.17\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr ""
+#~ " %s UTF-8 Inválido \"%s\" seqüência de caracteres de tradução para "
+#~ "a opção %s!\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s UTF-8 Inválido \"%s\" seqüência de caracteres de tradução para "
+#~ "opção %s, escolha %s!\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Valor de cupsFilter inválido \"%s\"!\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s cupsICCProfile Inválido %s!\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Valor de cupsPreFilter inválido \"%s\"!\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s cupsUIConstraints Inválido %s: \"%s\"!\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s Idioma inválido \"%s\"!\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s cupsUIConstraints Vazio %s!\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr ""
+#~ " %s Ausente \"%s\" seqüência de caracteres de tradução para a opção "
+#~ "%s!\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Ausente \"%s\" seqüência de caracteres de tradução para a opção "
+#~ "%s, escolha %s!\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Escolha ausente *%s %s em UIConstraints \"*%s %s *%s %s\"!\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Escolha ausente *%s %s em cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s Arquivo cupsICCProfile ausente \"%s\"!\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s cupsUIResolver ausente %s!\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr " %s Opção ausente %s em UIConstraints \"*%s %s *%s %s\"!\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Opção ausente %s em cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr ""
+#~ " %s Nenhuma tradução base de \"%s\" está incluída no arquivo!\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s REQUIRED %s não define a opção Nenhum!\n"
+#~ " REF: Página 122, seção 5.17\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " %s o valor hash de cupsICCProfile %s colide com %s!\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver %s provoca um loop!\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** %s os nomes de seleção %s e %s se diferenciam apenas por "
+#~ "maiúscula ou minúscula!\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **FAIL** %s deve ser 1284DeviceID!\n"
+#~ " REF: Página 72, seção 5.5\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Página 102, seção 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Página 103, seção 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **FAIL** Escolha %s inválida %s!\n"
+#~ " REF: Página 84, seção 5.9\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr ""
+#~ " **FAIL** LanguageEncoding %s inválido - deve ser ISOLatin1!\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr " **FAIL** LanguageVersion %s inválido - deve ser inglês!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **FAIL** Seqüência de caracteres de tradução padrão para opção %s "
+#~ "escolha %s contém caracteres de 8 bits!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **FAIL** Seqüência de caracteres de tradução padrão para opção %s "
+#~ "contém caracteres de 8 bits!\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Os nomes dos grupos %s e %s se diferenciam apenas por "
+#~ "maiúscula ou minúscula!\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **FAIL** Ocorrências múltiplas de %s nome de seleção %s!\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Os nomes das opções %s e %s se diferenciam apenas por "
+#~ "maiúscula ou minúscula!\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " %%%%BoundingBox inválido: na linha %d!\n"
+#~ " REF: Página 39, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " %%%%Página inválida: na linha %d!\n"
+#~ " REF: Página 53, %%%%Página:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " %%%%Páginas inválidas: na linha %d!\n"
+#~ " REF: Página 43, %%%%Páginas:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " A linha %d é maior do que 255 caracteres (%d)!\n"
+#~ " REF: Página 25, Comprimento de Linha\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " %!PS-Adobe-3.0 ausente na primeira linha!\n"
+#~ " REF: Página 17, 3.1 Documentos Conformes\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " Comentário %%EndComments ausente!\n"
+#~ " REF: Página 41, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " %%BoundingBox ausente ou inválido: comentário!\n"
+#~ " REF: Página 39, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " %%Página ausente ou inválida: comentários!\n"
+#~ " REF: Página 53, %%Página:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " %%Páginas ausentes ou inválidas: comentário!\n"
+#~ " REF: Página 43, %%Páginas:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " Visualizadas %d linhas que excedem 255 caracteres!\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " Muitos comentários %%BeginDocument!\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " Muitos comentários %%EndDocument!\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " Aviso: o arquivo contém dados binários!\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " Aviso: nenhum comentário %%EndComments no arquivo!\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " Aviso: versão DSC obsoleta %.1f no arquivo!\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s não é compatível!"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: Não sei o que fazer!\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: Erro - %s nomes de variáveis de ambiente de destino não existente \"%s"
+#~ "\"!\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: Erro - ID de trabalho inválido!\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr ""
+#~ "%s: Erro - não é possível imprimir arquivos e alterar trabalhos "
+#~ "simultaneamente!\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: Erro - não é possível imprimir a partir de stdin se os arquivos ou um "
+#~ "ID de trabalho forem fornecidos!\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: Erro - conjunto de caracteres esperado após opção '-S'!\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: Erro - tipo de conteúdo esperado após opção '-T'!\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: Erro - cópias esperadas após opção '-n'!\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s: Erro - contagem de cópias esperadas após opção '-#'!\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: Erro - destino esperado após opção '-P'!\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: Erro - destino esperado após opção '-b'!\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: Erro - destino esperado após opção '-d'!\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: Erro - formulário esperado após opção '-f'!\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: Erro - nome mantido esperado após opção '-H'!\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: Erro - nome de host esperado após opção '-H'!\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: Erro - nome de host esperado após opção '-H'!\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: Erro - lista de modo esperado após opção '-y'!\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: Erro - nome esperado após opção '-%c'!\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr ""
+#~ "%s: Erro - seqüência de caracteres de opção esperada após opção '-o'!\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: Erro - lista de página esperada após opção '-P'!\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: Erro - prioridade esperada após opção '-%c'!\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s: Erro - texto de motivo esperado após opção '-r'!\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: Erro - título esperado após opção '-t'!\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s: Erro - nome de usuário esperado após opção '-U'!\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s: Erro - nome de usuário esperado após opção '-U'!\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: Erro - valor esperado após opção '-%c'!\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: Erro - necessária opções \"completo\", \"incompleto\" ou \"todos\" "
+#~ "após opção '-W'!\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: Erro - programador não responde!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: Erro - destino desconhecido \"%s\"!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: Erro - destino desconhecido \"%s/%s\"!\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: Erro - opção desconhecida '%c'!\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: Erro - opção desconhecida '%s'!\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: ID de trabalho esperada após opção '-i'!\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: Nome de destino inválido na lista \"%s\"!\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr ""
+#~ "%s: ID de trabalho necessária ('-i jobid') antes de 'reinício -H'!\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: Nenhum filtro para converter de %s/%s para %s/%s!\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s: Desculpe, não há compatibilidade de encriptação compilada!\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: Não é possível contactar ao servidor!\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: Não é possível determinar o tipo MIME de \"%s\"!\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s: Não é possível abrir %s - %s\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s: Não é possível abrir %s - %s on-line %d.\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s: Não é possível ler o banco de dados MIME de \"%s\" ou \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: Destino desconhecido \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: Tipo MIME de destino desconhecido %s/%s!\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: Opção desconhecida '%c'!\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: Tipo MIME de fonte desconhecida %s/%s!\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: Aviso - '%c' modificador de formato não compatível - a saída pode não "
+#~ "ser correta!\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: Aviso - opção de conjunto de caracteres foi ignorada!\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: Aviso - opção de tipo de conteúdo foi ignorada!\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: Aviso - opção de formulário foi ignorada!\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: Aviso - opção de modo foi ignorada!\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: erro - %s nomes de variáveis de ambiente de destino não existente \"%s"
+#~ "\"!\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: erro - option=value esperado após opção '-o'!\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "600 ppp da escala de cinza"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr ""
+#~ "Uma senha do Samba é solicitada para exportar os drivers da impressora!"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr ""
+#~ "Um nome de usuário do Samba é solicitado para exportar os drivers da "
+#~ "impressora!"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "Uma classe chamada \"%s\" já existe!"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "Uma impressora chamada \"%s\" já existe!"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr ""
+#~ "Tentativa de configurar o estado da impressora %s para valor inválido %d!"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "Os grupos de atributos estão fora de ordem (%x < %x)!"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "Dispositivo URI inválido \"%s\"!\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "dispositivo uri inválido \"%s\"!"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "Esquema device-uri inválido \"%s\"!"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "formato de documento inválido \"%s\"!"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Armazenamento intermediário do nome do arquivo inválido!"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Valor de job-priority inválido!"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Valor job-sheets inválido \"%s\"!"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Tipo de valor job-sheets inválido!"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Valor de job-state inválido!"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Atributo de job-uri inválido \"%s\"!"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "notify-pull-method inválido \"%s\"!"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "notify-recipient-uri URI inválido \"%s\"!"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "opção + escolha inválida na linha %d!"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "port-monitor inválido \"%s\"!"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Valor de printer-state inválido %d!"
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "Número de versão de solicitação inválido %d.%d!"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "ID de inscrição inválido!"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "Conjunto de caracteres \"%s\" não compatível!"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "Não foi possível escanear tipo \"%s\"!"
+
+#~ msgid "Cover open."
+#~ msgstr "Tampa aberta."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "Desenvolvedor quase vazio."
+
+#~ msgid "Developer empty!"
+#~ msgstr "Desenvolvedor vazio!"
+
+#~ msgid "Door open."
+#~ msgstr "Porta aberta."
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: %%BoundingBox inválido: comentário visto!\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: %%IncludeFeature inválido: comentário!\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: %%Página inválido: comentário no arquivo!\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: %%PageBoundingBox inválido: comentário no arquivo!\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: Arquivo de dispositivo SCSI inválido \"%s\"!\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: Valor de colunas inválido %d!\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: Valor cpi inválido %f!\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: Valor lpi inválido %f!\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: Configuração de página inválida!\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: Impressora de destino inexistente!\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Duplicar %%BoundingBox: comentário visto!\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: Duplicar %%Páginas: comentário visto!\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: Arquivo de impressão vazio!\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr "ERROR: Seqüência de caracteres on-line esperada %d de %s!\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: Erro grave de USB!\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr ""
+#~ "ERROR: Comentário visto HP-GL/2 inválido, não é possível imprimir o "
+#~ "arquivo!\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: %%EndProlog ausente!\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: %%EndSetup ausente!\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: URI de dispositivo ausente URI em command-line e nenhuma variável "
+#~ "de ambiente DEVICE_URI!\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: Valor ausente na linha %d do arquivo de banner!\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: Necessária uma linha msgid antes de quaisquer seqüências de "
+#~ "caracteres na linha %d de %s!\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: Nenhum %%BoundingBox: comentário no cabeçalho!\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: Nenhum %%Pages: comentário no cabeçalho!\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Nenhum dispositivo URI encontrado em argv[0] ou em variável de "
+#~ "ambiente DEVICE_URI!\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: Nenhuma página encontrada!\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: Sem papel!\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: Variável de ambiente PRINTER não definido!\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: O arquivo de impressão não foi aceito (%s)!\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: A impressora não responde!\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: Não é possível criar o arquivo temporário - %s.\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: Não é possível criar o arquivo temporário: %s\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: Não é possível obter os atributos %d do trabalho (%s)!\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: Não é possível obter o estado de impressão (%s)!\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: Não é possível localizar a impressora '%s'!\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: Não é possível abrir o arquivo de imagem para impressão!\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: Não é possível abrir o arquivo temporário"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: Não é possível imprimir %d colunas de texto!\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: Não é possível imprimir %dx%d página de texto!\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: Não é possível ler os dados de impressão!\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: Não é possível enviar dados de impressão (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: Não é possível enviar dados de impressão!\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: Não é possível gravar %d bytes na impressora!\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr "ERROR: Não é possível gravar os dados brutos para o driver!\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: Não é possível gravar no arquivo temporário"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: Texto inesperado na linha %d de %s!\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: Valor de opção de encriptação desconhecido \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: Formato de catálogo de mensagem desconhecida para \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: Opção desconhecida \"%s\" com valor \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: Valor de opção de versão desconhecido \"%s\"!\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr "ERROR: Valor de brilho não compatível %s, usando brilho=100!\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: Valor de gama não compatível %s, usando gama=1000!\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr "ERROR: Valor de number-up não compatível %d, usando number-up=1!\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: Valor de number-up-layout não compatível %s, usando number-up-"
+#~ "layout=lrtb!\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: Valor de page-border não compatível %s, usando page-border=none!\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr "ERROR: Sobrecarga de doc_printf (%d bytes) detectado, anulando!\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr "ERROR: O filtro pdftops bloqueou no sinal %d!\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr "ERROR: O filtro pdftops saiu com estado %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops saíram no sinal %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops saíram com estado %d!\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: recuperável: Não é possível conectar-se à impressora; nova "
+#~ "tentativa em 30 segundos...\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "Arquivo PPD vazio!"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "Error: necessário um nome de host após a opção '-h'!\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Temperatura do fuser alta!"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "Temperatura do fuser baixa!"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "Obtido um atributo printer-uri, mas não um job-id!"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Tinta/toner quase vazios."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Tinta/toner vazios!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Recipiente de tinta/toner quase cheio."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Recipiente de tinta/toner cheio!"
+
+#~ msgid "Interlock open."
+#~ msgstr "Conexão aberta."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "O trabalho #%d não pode ser reiniciado - nenhum arquivo!"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "O trabalho #%d não existe!"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "O trabalho #%d está finalizado e não pode ser alterado!"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "O trabalho #%d não está concluído!"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "O trabalho #%d não está parado para autenticação!"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "O trabalho #%d não está parado!"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "O trabalho #%s não existe!"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "Trabalho %d não encontrado!"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "As inscrições do trabalho não podem ser renovadas!"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "Idioma \"%s\" não compatível!"
+
+#~ msgid "Media jam!"
+#~ msgstr "Atolamento de mídia!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Bandeja de mídia quase vazia."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Bandeja de mídia vazia!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Bandeja de mídia ausente!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "A bandeja de mídia necessita ser preenchida."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "Atributo document-number ausente!"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "Aspas ausentes na linha %d!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "Variável de formato ausente!"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "Atributo notify-subscription-ids ausente!"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "Atributo requesting-user-name ausente!"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "Atributos necessários ausentes!"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "Valor ausente na linha %d!"
+
+#~ msgid "No PPD name!"
+#~ msgstr "Nenhum nome PPD!"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Nenhum driver de impressora do Windows instalado!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "Nenhum trabalho ativo em %s!"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "Nenhum atributo na solicitação!"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "Nenhuma informação de autenticação fornecida!"
+
+#~ msgid "No file!?!"
+#~ msgstr "Nenhum arquivo!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "Nenhuma hora de modificação!"
+
+#~ msgid "No printer name!"
+#~ msgstr "Nenhum nome de impressora!"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "Nenhum printer-uri encontrado para a classe!"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "Nenhum printer-uri encontrado!"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "Nenhum printer-uri em pedido!"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "Nenhum atributo de inscrição na solicitação!"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC quase no final."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC no final!"
+
+#~ msgid "Out of toner!"
+#~ msgstr "Sem toner!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Recipiente de saída quase cheio."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Recipiente de saída cheio!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Bandeja de saída ausente!"
+
+#~ msgid "Printer offline."
+#~ msgstr "Impressora desconectada."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "Impressora SCSI"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "O valor notify-user-data é muito grande (%d > 63 octetos)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "A impressora ou a classe não estão compartilhadas!"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "O atributo printer-uri é necessário!"
+
+#~ msgid "Toner low."
+#~ msgstr "Toner baixo."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "Muitos valores de job-sheets (%d > 2)!"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "Muitos valores de printer-state-reasons (%d > %d)!"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "Não é possível adicionar o trabalho para o destino \"%s\"!"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "Não é possível alocar memória para os tipos de arquivo!"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "Não é possível copiar arquivos de driver de impressora CUPS de 64-bit (%"
+#~ "d)!"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr ""
+#~ "Não é possível copiar arquivos do driver da impressora Windows de 64-bit "
+#~ "(%d)!"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr ""
+#~ "Não é possível copiar os arquivos do driver de impressora CUPS (%d)!"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "Não é possível copiar o arquivo PPD - %s!"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "Não é possível copiar o arquivo PPD!"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Não é possível copiar os arquivos do driver de impressora do Windows 2000 "
+#~ "(%d)!"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "Não é possível copiar os arquivos do driver de impressora do Windows 9x (%"
+#~ "d)!"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "Não é possível copiar o roteiro de interface - %s!"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "Não é possível criar printer-uri!"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr "Não é possível editar os arquivos cupsd.conf maiores que 1MB!"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "Não é possível buscar o destino para o trabalho!"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "Não é possível encontrar a impressora!\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Não é possível instalar os arquivos de drivers de impressora do Windows "
+#~ "2000 (%d)!"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr ""
+#~ "Não é possível instalar os arquivos de drivers de impressora do Windows "
+#~ "9x (%d)!"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "Não é possível abrir o documento %d no trabalho %d!"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "Não é possível enviar o comando ao driver da impressora!"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Não é possível configurar o driver de impressora do Windows (%d)!"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "Não é possível usar o driver de classe USB de legado!\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "Erro de impressora desconhecido (%s)!"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Conjunto de caracteres incompatíveis \"%s\"!"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "Compressão não compatível \"%s\"!"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "Atributo de compressão não compatível %s!"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "Formato não compatível \"%s\"!"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "Formato não compatível '%s'!"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "Formato não compatível '%s/%s'!"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "Usage: converter [ options ]\n"
+#~ "\n"
+#~ "Opções:\n"
+#~ "\n"
+#~ " -f filename Definir arquivo para conversão (senão stdin)\n"
+#~ " -o filename Definir para ser gerado (senão stdout)\n"
+#~ " -i mime/type Definir tipo MIME de entrada (senão auto-typed)\n"
+#~ " -j mime/type Definir tipo MIME de saída (senão application/"
+#~ "pdf)\n"
+#~ " -P filename.ppd Definir arquivo PPD\n"
+#~ " -a 'name=value ...' Definir opção(ões)\n"
+#~ " -U username Definir nome do usuário para trabalho\n"
+#~ " -J title Definir título\n"
+#~ " -c copies Definir número de cópias\n"
+#~ " -u Remover o arquivo PPD ao terminar\n"
+#~ " -D Remover o arquivo de entrada ao terminar\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Opções:\n"
+#~ "\n"
+#~ " -c cupsd.conf Definir arquivo cupsd.conf para uso\n"
+#~ " -j job-id[,N] Arquivo de filtro N do trabalho especificado (o padrão "
+#~ "é o arquivo 1)\n"
+#~ " -n cópias Definir número de cópias\n"
+#~ " -o name=value Definir opção(ões)\n"
+#~ " -p filename.ppd Definir arquivo PPD\n"
+#~ " -t title Definir título\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Opções:\n"
+#~ "\n"
+#~ " -R root-directory Definir raiz alternada\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Expedir avisos em vez de erros\n"
+#~ " -q Executar silenciosamente\n"
+#~ " -r Usar modo aberto 'relaxed'\n"
+#~ " -v Ser levemente detalhado\n"
+#~ " -vv Ser bastante detalhado\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: Falha ao ler o pedido side-channel!\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr ""
+#~ "WARNING: A opção \"%s\" não pode ser incluída através de IncludeFeature!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: O host remoto não repondeu com o byte de estado de comando após %"
+#~ "d segundos!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: O host remoto não repondeu com o byte de estado de controle após "
+#~ "%d segundos!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: O host remoto não repondeu com o byte de estado de dados após %d "
+#~ "segundos!\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr ""
+#~ "WARNING: Tempo esgotado para comando SCSI (%d); tentando novamente...\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: Este documento não está de acordo com o Adobe Document "
+#~ "Structuring Conventions e pode não ser impresso corretamente!\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: Escolha desconhecida \"%s\" para a opção \"%s\"!\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: Opção desconhecida \"%s\"!\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: Taxa de transmissão não compatível %s!\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: recuperável: O host de rede '%s' está ocupado; tentará novamente "
+#~ "em %d segundos...\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr ""
+#~ "Warning, nenhum driver de impressora do Windows 2000 está instalado!"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: Opção desconhecida \"%s\"!\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: Opção desconhecida \"-%c\"!\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr ""
+#~ "cupsd: Nome de arquivo de configuração esperado após a opção \"-c\"!\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: não é possível obter o diretório atual!\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: Argumento desconhecido \"%s\" - anulando!\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: Opção desconhecida \"%c\" - anulando!\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: número de documento inválido %d!\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: ID de trabalho inválido %d!\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: Apenas um filename pode ser especificado!\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter: não é possível criar um arquivo temporário: %s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "Atributo job-printer-uri ausente!"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr ""
+#~ "lpadmin: O nome de classe pode conter apenas caracteres imprimíveis!\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: PPD esperado após a opção '-P'!\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr "lpadmin: Permitir/negar esperado:userlist após a opção '-u'!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: Classe esperada após opção '-r'!\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: Nome de classe esperado após a opção '-c'!\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: Descrição esperada após a opção '-D'!\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: URI de dispositivo esperado após a opção '-v'!\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: Tipo(s) de arquivo esperado após a opção '-I'!\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: Hostname esperado após a opção '-h'!\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: Interface esperada após a opção '-i'!\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: Localização esperada após a opção '-L'!\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: Modelo esperado após a opção '-m'!\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: name=value esperado após a opção '-o'!\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: Impressora esperada após a opção '-p'!\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: Nome de impressora esperada após a opção '-d'!\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin: Impressora ou classe esperada após a opção '-x'!\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: Nenhum nome de membro foi visto!\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr ""
+#~ "lpadmin: O nome da impressora pode conter apenas caracteres imprimíveis!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível adicionar uma impressora à classe:\n"
+#~ " Você deve especificar um nome de impressora primeiro!\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin: Não é possível criar um arquivo temporário - %s\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin: Não é possível criar um arquivo temporário: %s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível remover uma impressora da classe:\n"
+#~ " Você deve especificar um nome de impressora primeiro!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível configurar o arquivo PPD:\n"
+#~ " Você deve especificar um nome de impressora primeiro!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível configurar o URI de dispositivo:\n"
+#~ " Você deve especificar um nome de impressora primeiro!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível configurar o roteiro de interface ou arquivo "
+#~ "PPD:\n"
+#~ " Você deve especificar um nome de impressora primeiro!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível configurar o roteiro de interface:\n"
+#~ " Você deve especificar um nome de impressora primeiro!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível configurar a descrição da impressora:\n"
+#~ " Você deve especificar um nome de impressora primeiro!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível configurar a localização da impressora:\n"
+#~ " Você deve especificar um nome de impressora primeiro!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Não é possível configurar as opções da impressora:\n"
+#~ " Você deve especificar um nome de impressora primeiro!\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: Opção permitir/negar desconhecida \"%s\"!\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: Argumento desconhecido '%s'!\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: Opção desconhecida '%c'!\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin: Aviso - lista de tipo de conteúdo ignorada!\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr ""
+#~ "lpinfo: seqüência de caracteres de ID de dispositivo 1284 esperada após --"
+#~ "device-id!\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: idioma esperado após --language!\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo: modelar e fazer esperado após --make-and-model!\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr ""
+#~ "lpinfo: seqüência de caracteres de produto esperada após --product!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo: lista de esquema esperada após --exclude-schemes!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo: lista de esquema esperada após --include-schemes!\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: tempo esgotado esperado após --timeout!\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: Argumento desconhecido '%s'!\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: Opção desconhecida '%c'!\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: opção desconhecida '%s'!\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: Argumento desconhecido '%s'!\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: Opção desconhecida '%c'!\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: Nenhuma impressora!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: Não é possível abrir o arquivo PPD para %s!\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: Impressora ou classe desconhecidas!\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: Apenas o root pode adicionar ou apagar senhas!\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: Arquivo de senha ocupado!\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: Arquivo de senha não atualizado!\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: Desculpe, a senha não coincide!\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: Desculpe, as senhas não coincidem!\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: erro - %s destino não existente de nomes de variáveis de ambiente "
+#~ "\"%s\"!\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-events não especificado!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "URI notify-recipient-uri \"%s\" já foi usado!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "notify-recipient-uri URI \"%s\" usa um esquema desconhecido!"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d não confiável!"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: nome de resolução inválido \"%s\" na linha %d de %s!\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: palavra-chave de estado inválido %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc: escolha encontrada na linha %d de %s com nenhuma Opção!\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc: duplicar #po para local %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: definição de filtro esperada na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: nome de programa esperado na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr "ppdc: conjunto de caracteres depois de Font na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: ordem de cor esperada para ColorModel na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: colorspace esperada para ColorModel na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: compressão esperada para ColorModel na linha %d de %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: seqüência de caracteres de restrição esperada para UIConstraints na "
+#~ "linha %d de %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: palavra-chave do tipo de driver esperado após DriverType na linha %"
+#~ "d de %s!\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr "ppdc: tipo de dúplex esperado após Duplex na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc: codificação esperada após Font na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc: nome de arquivo esperado após #po %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: nome/texto de grupo esperado na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc: nome de arquivo de inclusão esperado na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: número inteiro esperado na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc: localidade esperada após #po na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Nome esperado após %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: Nome esperado após FileName na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Nome esperado após Font na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc: Nome esperado após Manufacturer na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: nome esperado após MediaSize na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: nome esperado após ModelName na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: nome esperado após PCFileName na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: nome/texto esperado após %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr "ppdc: nome/texto esperado após Installable na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: nome/texto esperado após Resolution na linha %d de %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: combinação de nome/texto esperado para ColorModel na linha %d de %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc: nome/texto de opção esperado na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: seção de opção esperada na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: tipo de opção esperada na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: campo de substituição esperado após Resolution na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: número real esperado na linha %d de %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: resolução/tipo de mídia esperado após ColorProfile na linha %d de %"
+#~ "s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: resolução/tipo de mídia esperado após SimpleColorProfile na linha %"
+#~ "d de %s!\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: seletor esperado após %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: estado esperado após Font na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: seqüência de caracteres esperada após Copyright na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: seqüência de caracteres esperada após Version na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: dois nomes de opção esperados na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: valor esperado após %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: versão esperada após Font na linha %d de %s!\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: nome de arquivo #include/#po inválido \"%s\"!\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: custo inválido para filtro na linha %d de %s!\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr "ppdc: tipo MIME vazio inválido para filtro na linha %d de %s!\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: nome de programa vazio inválido para filtro na linha %d de %s!\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: seção de opção inválida \"%s\" na linha %d de %s!\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: tipo de opção inválida \"%s\" na linha %d de %s!\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: #endif ausente no final de \"%s\"!\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: #if ausente na linha %d de %s!\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc: nenhum catálogo de mensagem fornecido para a localidade %s!\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: opção %s redefinida com um tipo diferente na linha %d de %s!\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr "ppdc: a restrição da opção deve *name na linha %d de %s!\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: muitos aninhados #if's na linha %d de %s!\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: Não é possível buscar o arquivo #po %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Não é possível buscar o arquivo de inclusão \"%s\" na linha %d de %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: tipo de driver desconhecido %s na linha %d de %s!\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: tipo de dúplex desconhecido \"%s\" na linha %d de %s!\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: tamanho de mídia desconhecido \"%s\" na linha %d de %s!\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: token desconhecido \"%s\" visto na linha %d de %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: caracteres delimitadores desconhecidos em número real \"%s\" na "
+#~ "linha %d de %s!\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: seqüência de caracteres não finalizados começando com %c na linha %"
+#~ "d de %s!\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: LanguageVersion inválido \"%s\" em %s!\n"
diff --git a/locale/cups_ru.po b/locale/cups_ru.po
new file mode 100644
index 000000000..465884728
--- /dev/null
+++ b/locale/cups_ru.po
@@ -0,0 +1,7133 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-16 12:00-0800\n"
+"Last-Translator: Apple Inc.\n"
+"Language-Team: Apple Inc.\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(вÑе)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(нет)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\tзапиÑей: %d\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tПоÑле ошибки: продолжить\n"
+
+msgid "\tAlerts:"
+msgstr "\tПредупреждениÑ:"
+
+msgid "\tBanner required\n"
+msgstr "\tТребуетÑÑ Ð±Ð°Ð½Ð½ÐµÑ€\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tÐабор Ñимволов уÑтанавливает:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tПодключение: прÑмое\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tПодключение: удаленное\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tРазмер Ñтраницы по умолчанию:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tÐ’Ñ‹Ñота по умолчанию:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tÐаÑтройки порта по умолчанию:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tОпиÑание: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tФорма подключениÑ:\n"
+"\tТипы контента: любые\n"
+"\tТипы принтеров: неизвеÑтно\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tРазрешенные формы:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tИнтерфейÑ: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tИнтерфейÑ: %s/интерфейÑÑ‹/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tИнтерфейÑ: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tРаÑположение: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tПри ошибке: не выводить предупреждение\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tРазрешенные пользователи:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tЗапрещенные пользователи:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tдемон приÑутÑтвует\n"
+
+msgid "\tno entries\n"
+msgstr "\tнет запиÑей\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\tпринтер на ÑкороÑти -1 уÑтройÑтва «%s»\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\tпечать отключена\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\tпечать включена\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\tочередь Ð´Ð»Ñ %s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tочередь отключена\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tочередь включена\n"
+
+msgid "\treason unknown\n"
+msgstr "\tпричина неизвеÑтна\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" ПОДРОБÐЫЕ РЕЗУЛЬТÐТЫ ТЕСТРСООТВЕТСТВИЯ\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " REF: Стр. 15, раздел 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " REF: Стр. 15, раздел 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " REF: Стр. 19, раздел 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " REF: Стр. 20, раздел 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " REF: Стр. 27, раздел 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " REF: Стр. 42, раздел 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " REF: Стр. 16-17, раздел 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " REF: Стр. 42-45, раздел 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " REF: Стр. 45-46, раздел 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " REF: Стр. 48-49, раздел 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " REF: Стр. 52-54, раздел 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f байт\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " PASS Default%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " PASS DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " PASS DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " PASS FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " PASS FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " PASS LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " PASS LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " PASS Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " PASS ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " PASS NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " PASS PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " PASS PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " PASS PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " PASS PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " PASS Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " PASS ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" WARN «%s %s» конфликтует Ñ Â«%s %s»\n"
+" (constraint=«%s %s %s %s»)\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" WARN %s иÑпользует общий Ð¿Ñ€ÐµÑ„Ð¸ÐºÑ ÑовмеÑтно Ñ %s\n"
+" REF: Стр. 15, раздел 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" WARN LanguageEncoding требуетÑÑ Ñпецификацией PPD 4.3.\n"
+" REF: Стр. 56-57, раздел 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" WARN LanguageEncoding требуетÑÑ Ñпецификацией PPD 4.3.\n"
+" REF: Стр. 58-59, раздел 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" WARN PCFileName длиннее чем 8.3 нарушает Ñпецификацию PPD.\n"
+" REF: Стр. 61-62, раздел 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN Protocols Ñодержит PJL, но атрибуты JCL не наÑтроены.\n"
+" REF: Стр. 78-79, раздел 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" WARN ShortNickName требуетÑÑ Ñпецификацией PPD 4.3.\n"
+" REF: Стр. 64-65, раздел 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s Файл cupsFilter отÑутÑтвует «%s»\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s Файл cupsFilter «%s» отÑутÑтвует\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** ÐЕВЕРÐЫЙ Default%s %s\n"
+" REF: Стр. 40, раздел 4.5.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **FAIL** ÐЕВЕРÐЫЙ JobPatchFile атрибут в файле\n"
+" REF: Стр. 24, раздел 3.4.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** ÐЕВЕРÐЫЙ Manufacturer (должен быть «HP»)\n"
+" REF: Стр. 211, таблица D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FAIL** ÐЕВЕРÐЫЙ Manufacturer (должен быть «Oki»)\n"
+" REF: Стр. 211, таблица D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** ÐЕВЕРÐОЕ ModelName – «%c» не разрешено в Ñтроке.\n"
+" REF: Стр. 59-60, раздел 5.3.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** ÐЕВЕРÐÐЯ PSVersion – не «(string) int».\n"
+" REF: Стр. 62-64, раздел 5.3.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** ÐЕВЕРÐЫЙ Product – не «(string)».\n"
+" REF: Стр. 62, раздел 5.3.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** ÐЕВЕРÐЫЙ ShortNickName – длиннее чем 31 Ñимв.\n"
+" REF: Стр. 64-65, раздел 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ FileVersion \"%s\"\n"
+" REF: Стр. 56, раздел 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ FormatVersion \"%s\"\n"
+" REF: Стр. 56, раздел 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr ""
+" **FAIL** Ðе удаетÑÑ Ð¸Ð½Ñ‚ÐµÑ€Ð¿Ñ€ÐµÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ñ‚ÑŒ код параметра по умолчанию: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ Default%s\n"
+" REF: Стр. 40, раздел 4.5.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ DefaultImageableArea\n"
+" REF: Стр. 102, раздел 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ DefaultPaperDimension\n"
+" REF: Стр. 103, раздел 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ FileVersion\n"
+" REF: Стр. 56, раздел 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ FormatVersion\n"
+" REF: Стр. 56, раздел 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ ImageableArea Ð´Ð»Ñ PageSize %s\n"
+" REF: Стр. 41, раздел 5.\n"
+" REF: Стр. 102, раздел 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ LanguageEncoding\n"
+" REF: Стр. 56-57, раздел 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ LanguageVersion\n"
+" REF: Стр. 57-58, раздел 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ Manufacturer\n"
+" REF: Стр. 58-59, раздел 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ ModelName\n"
+" REF: Стр. 59-60, раздел 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ NickName\n"
+" REF: Стр. 60, раздел 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ PCFileName\n"
+" REF: Стр. 61-62, раздел 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ PSVersion\n"
+" REF: Стр. 62-64, раздел 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ PageRegion\n"
+" REF: Стр. 100, раздел 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ PageSize\n"
+" REF: Стр. 41, раздел 5.\n"
+" REF: Стр. 99, раздел 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ PageSize\n"
+" REF: Стр. 99-100, раздел 5.14.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ PaperDimension Ð´Ð»Ñ PageSize %s\n"
+" REF: Стр. 41, раздел 5.\n"
+" REF: Стр. 103, раздел 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ Product\n"
+" REF: Стр. 62, раздел 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **FAIL** ТРЕБУЕТСЯ ShortNickName\n"
+" REF: Стр. 64-65, раздел 5.3.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " ОБÐÐРУЖЕÐО ОШИБОК: %d\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " ОШИБОК ÐЕ ОБÐÐРУЖЕÐО\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " FAIL\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ PPD-файл – %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" FAIL\n"
+" **FAIL** Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ PPD-файл – %s в Ñтроке %d.\n"
+
+msgid " PASS\n"
+msgstr " PASS\n"
+
+msgid "#10 Envelope"
+msgstr "#10 Envelope"
+
+msgid "#11 Envelope"
+msgstr "#11 Envelope"
+
+msgid "#12 Envelope"
+msgstr "#12 Envelope"
+
+msgid "#14 Envelope"
+msgstr "#14 Envelope"
+
+msgid "#9 Envelope"
+msgstr "#9 Envelope"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f байт\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f байт\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f мм"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f — %.0f x %.0f мм"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f дюймов"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f-%.2f x %.2f дюймов"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s принимает запроÑÑ‹ Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%s не может быть изменен."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s не выполнено верÑией CUPS Ð´Ð»Ñ lpc.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s не готов\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s готов\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s готов и печатает\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s не принимает запроÑÑ‹ Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s принимает запроÑÑ‹ Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s не принимает запроÑÑ‹ Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [задание %d localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: ошибка %s: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: Ошибка – нет доÑтупного Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: Ошибка – приоритет должен быть от 1 до 100.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: Ошибка – Ñлишком много файлов – «%s»\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: Ошибка – не удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ доÑтуп к «%s» – %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s: Ошибка – не удаетÑÑ Ð¿Ð¾Ñтавить в очередь из stdin - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: Фильтр «%s» недоÑтупен: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñтрока фильтра «%s»\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð½Ðµ удалаÑÑŒ: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: Ðе удаетÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÑŒÑÑ Ðº Ñерверу\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ %s: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ PPD-файл: %s в Ñтроке %d.\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: ошибка – нет доÑтупного Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 дюйм/Ñ"
+
+msgid "1.25x0.25\""
+msgstr "1,25x0,25\""
+
+msgid "1.25x2.25\""
+msgstr "1,25x2,25\""
+
+msgid "1.5 inch/sec."
+msgstr "1,5 дюйма/Ñ"
+
+msgid "1.50x0.25\""
+msgstr "1,50x0,25\""
+
+msgid "1.50x0.50\""
+msgstr "1,50x0,50\""
+
+msgid "1.50x1.00\""
+msgstr "1,50x1,00\""
+
+msgid "1.50x2.00\""
+msgstr "1,50x2,00\""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 дюймов/Ñ"
+
+msgid "10 x 11\""
+msgstr "10 x 11\""
+
+msgid "10 x 13\""
+msgstr "10 x 13\""
+
+msgid "10 x 14\""
+msgstr "10 x 14\""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 мм/Ñ"
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 дюймов/Ñ"
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 дюймов/Ñ"
+
+msgid "12 x 11\""
+msgstr "12 x 11\""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 мм/Ñ"
+
+msgid "120x60dpi"
+msgstr "120x60dpi"
+
+msgid "120x72dpi"
+msgstr "120x72dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 мм/Ñ"
+
+msgid "15 x 11\""
+msgstr "15 x 11\""
+
+msgid "150 mm/sec."
+msgstr "150 мм/Ñ"
+
+msgid "150dpi"
+msgstr "150dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 дюйма/Ñ"
+
+msgid "2-Sided Printing"
+msgstr "двуÑтороннÑÑ Ð¿ÐµÑ‡Ð°Ñ‚ÑŒ"
+
+msgid "2.00x0.37\""
+msgstr "2,00x0,37\""
+
+msgid "2.00x0.50\""
+msgstr "2,00x0,50\""
+
+msgid "2.00x1.00\""
+msgstr "2,00x1,00\""
+
+msgid "2.00x1.25\""
+msgstr "2,00x1,25\""
+
+msgid "2.00x2.00\""
+msgstr "2,00x2,00\""
+
+msgid "2.00x3.00\""
+msgstr "2,00x3,00\""
+
+msgid "2.00x4.00\""
+msgstr "2,00x4,00\""
+
+msgid "2.00x5.50\""
+msgstr "2,00x5,50\""
+
+msgid "2.25x0.50\""
+msgstr "2,25x0,50\""
+
+msgid "2.25x1.25\""
+msgstr "2,25x1,25\""
+
+msgid "2.25x4.00\""
+msgstr "2,25x4,00\""
+
+msgid "2.25x5.50\""
+msgstr "2,25x5,50\""
+
+msgid "2.38x5.50\""
+msgstr "2,38x5,50\""
+
+msgid "2.5 inches/sec."
+msgstr "2,5 дюйма/Ñ"
+
+msgid "2.50x1.00\""
+msgstr "2,50x1,00\""
+
+msgid "2.50x2.00\""
+msgstr "2,50x2,00\""
+
+msgid "2.75x1.25\""
+msgstr "2,75x1,25\""
+
+msgid "2.9 x 1\""
+msgstr "2,9 x 1\""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 мм/Ñ"
+
+msgid "200 mm/sec."
+msgstr "200 мм/Ñ"
+
+msgid "203dpi"
+msgstr "203dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "Тип 24-Pin"
+
+msgid "240x72dpi"
+msgstr "240x72dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 мм/Ñ"
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 дюйма/Ñ"
+
+msgid "3.00x1.00\""
+msgstr "3,00x1,00\""
+
+msgid "3.00x1.25\""
+msgstr "3,00x1,25\""
+
+msgid "3.00x2.00\""
+msgstr "3,00x2,00\""
+
+msgid "3.00x3.00\""
+msgstr "3,00x3,00\""
+
+msgid "3.00x5.00\""
+msgstr "3,00x5,00\""
+
+msgid "3.25x2.00\""
+msgstr "3,25x2,00\""
+
+msgid "3.25x5.00\""
+msgstr "3,25x5,00\""
+
+msgid "3.25x5.50\""
+msgstr "3,25x5,50\""
+
+msgid "3.25x5.83\""
+msgstr "3,25x5,83\""
+
+msgid "3.25x7.83\""
+msgstr "3,25x7,83\""
+
+msgid "3.5\" Disk"
+msgstr "ДиÑк 3.5\""
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "ДиÑк 3.5\" - 2 1/8 x 2 3/4\""
+
+msgid "3.50x1.00\""
+msgstr "3,50x1,00\""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 мм/Ñ"
+
+msgid "300 mm/sec."
+msgstr "300 мм/Ñ"
+
+msgid "300dpi"
+msgstr "300dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360dpi"
+
+msgid "360x180dpi"
+msgstr "360x180dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 дюйма/Ñ"
+
+msgid "4.00x1.00\""
+msgstr "4,00x1,00\""
+
+msgid "4.00x13.00\""
+msgstr "4,00x13,00\""
+
+msgid "4.00x2.00\""
+msgstr "4,00x2,00\""
+
+msgid "4.00x2.50\""
+msgstr "4,00x2,50\""
+
+msgid "4.00x3.00\""
+msgstr "4,00x3,00\""
+
+msgid "4.00x4.00\""
+msgstr "4,00x4,00\""
+
+msgid "4.00x5.00\""
+msgstr "4,00x5,00\""
+
+msgid "4.00x6.00\""
+msgstr "4,00x6,00\""
+
+msgid "4.00x6.50\""
+msgstr "4,00x6,50\""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 мм/Ñ"
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 дюймов/Ñ"
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 дюймов/Ñ"
+
+msgid "6.00x1.00\""
+msgstr "6,00x1,00\""
+
+msgid "6.00x2.00\""
+msgstr "6,00x2,00\""
+
+msgid "6.00x3.00\""
+msgstr "6,00x3,00\""
+
+msgid "6.00x4.00\""
+msgstr "6,00x4,00\""
+
+msgid "6.00x5.00\""
+msgstr "6,00x5,00\""
+
+msgid "6.00x6.00\""
+msgstr "6,00x6,00\""
+
+msgid "6.00x6.50\""
+msgstr "6,00x6,50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 мм/Ñ"
+
+msgid "600dpi"
+msgstr "600dpi"
+
+msgid "60dpi"
+msgstr "60dpi"
+
+msgid "60x720dpi"
+msgstr "60x720dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 дюймов/Ñ"
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 дюймов/Ñ"
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8,00x1,00\""
+
+msgid "8.00x2.00\""
+msgstr "8,00x2,00\""
+
+msgid "8.00x3.00\""
+msgstr "8,00x3,00\""
+
+msgid "8.00x4.00\""
+msgstr "8,00x4,00\""
+
+msgid "8.00x5.00\""
+msgstr "8,00x5,00\""
+
+msgid "8.00x6.00\""
+msgstr "8,00x6,00\""
+
+msgid "8.00x6.50\""
+msgstr "8,00x6,50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 мм/Ñ"
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 дюймов/Ñ"
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "Тип 9-Pin"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° Ñправки неизвеÑтна\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (раÑширенный)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (раÑширенный)"
+
+msgid "A4 (Small)"
+msgstr "A4 (уменьшенный)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (раÑширенный)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "ПринÑÑ‚ÑŒ заданиÑ"
+
+msgid "Accepted"
+msgstr "ПринÑто"
+
+msgid "Add Class"
+msgstr "Добавить клаÑÑ"
+
+msgid "Add Printer"
+msgstr "Добавить принтер"
+
+msgid "Add RSS Subscription"
+msgstr "Добавить подпиÑку на RSS"
+
+msgid "Address"
+msgstr "ÐдреÑ"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "ÐÐ´Ñ€ÐµÑ - 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "ÐдминиÑтрациÑ"
+
+msgid "Always"
+msgstr "Ð’Ñегда"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "ИÑполнительное уÑтройÑтво"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "Ðеверный указатель NULL dests"
+
+msgid "Bad OpenGroup"
+msgstr "Ðеверное значение OpenGroup"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "Ðеверное значение OpenUI/JCLOpenUI"
+
+msgid "Bad OrderDependency"
+msgstr "Ðеверное значение OrderDependency"
+
+msgid "Bad Request"
+msgstr "Ðеверный запроÑ"
+
+msgid "Bad SNMP version number"
+msgstr "Ðеверный номер верÑии SNMP"
+
+msgid "Bad UIConstraints"
+msgstr "Ðеверное значение UIConstraints"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Ðеверное значение количеÑтва копий %d."
+
+msgid "Bad custom parameter"
+msgstr "Ðеверный индивидуальный параметр"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Ðеверный атрибут шрифта: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Ðеверное значение number-up %d."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Ðеверные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ page-ranges %d-%d."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Баннеры"
+
+msgid "Billing Information: "
+msgstr "Реквизиты Ð´Ð»Ñ Ð²Ñ‹ÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñчета: "
+
+msgid "Bond Paper"
+msgstr "Ð”Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð½Ð°Ñ Ð±ÑƒÐ¼Ð°Ð³Ð°"
+
+msgid "C0 Envelope"
+msgstr "Конверт C0"
+
+msgid "C1 Envelope"
+msgstr "Конверт C1"
+
+msgid "C2 Envelope"
+msgstr "Конверт C2"
+
+msgid "C3 Envelope"
+msgstr "Конверт C3"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "Конверт C4"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "Конверт C5"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "Конверт C6"
+
+msgid "C65 Envelope"
+msgstr "Конверт C65"
+
+msgid "C7 Envelope"
+msgstr "Конверт C7"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "Принтер Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ Ñтикеток CPCL"
+
+msgid "Cancel RSS Subscription"
+msgstr "Отменить подпиÑку на RSS"
+
+msgid "Change Settings"
+msgstr "Изменить наÑтройки"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Конверт Chou3"
+
+msgid "Chou4 Envelope"
+msgstr "Конверт Chou4"
+
+msgid "Classes"
+msgstr "КлаÑÑÑ‹"
+
+msgid "Clean Print Heads"
+msgstr "ОчиÑтить головки принтера"
+
+msgid "Color"
+msgstr "Цвет"
+
+msgid "Color Mode"
+msgstr "Цветной режим"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"Команды могут быть Ñокращены. Команды:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "Ð”Ð»Ñ Ð¸Ð¼ÐµÐ½Ð¸ ÑообщеÑтва длина не уÑтановлена"
+
+msgid "Continue"
+msgstr "Продолжить"
+
+msgid "Continuous"
+msgstr "Ðепрерывно"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Создано"
+
+msgid "Created On: "
+msgstr "Дата ÑозданиÑ: "
+
+msgid "Custom"
+msgstr "Индивидуальный"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Обрезать"
+
+msgid "Cutter"
+msgstr "Резак"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "Конверт DL"
+
+msgid "Dark"
+msgstr "Темный"
+
+msgid "Darkness"
+msgstr "ЗатемненноÑÑ‚ÑŒ"
+
+msgid "Delete Class"
+msgstr "Удалить клаÑÑ"
+
+msgid "Delete Printer"
+msgstr "Удалить принтер"
+
+msgid "Description: "
+msgstr "ОпиÑание: "
+
+msgid "DeskJet Series"
+msgstr "Ð¡ÐµÑ€Ð¸Ñ DeskJet"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "Ðазначение «%s» не принимает заданиÑ."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"УÑтройÑтво: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "ÐоÑитель Ð´Ð»Ñ Ð¿Ñ€Ñмой термопечати"
+
+msgid "Disabled"
+msgstr "Отключено"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "Документ %d в задании %d не найден."
+
+msgid "Double Postcard"
+msgstr "Ð”Ð²Ð¾Ð¹Ð½Ð°Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÐºÐ°"
+
+msgid "Driver Name: "
+msgstr "Ð˜Ð¼Ñ Ð´Ñ€Ð°Ð¹Ð²ÐµÑ€Ð°: "
+
+msgid "Driver Version: "
+msgstr "ВерÑÐ¸Ñ Ð´Ñ€Ð°Ð¹Ð²ÐµÑ€Ð°: "
+
+msgid "Duplexer"
+msgstr "ДуплекÑер"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: Ðе удаетÑÑ Ð²Ñ‹Ð´ÐµÐ»Ð¸Ñ‚ÑŒ памÑÑ‚ÑŒ Ð´Ð»Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¸ Ñтраницы: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: Ðе удаетÑÑ Ð²Ñ‹Ð´ÐµÐ»Ð¸Ñ‚ÑŒ памÑÑ‚ÑŒ Ð´Ð»Ñ Ð¼Ð°ÑÑива Ñтраниц: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "Принтер Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ Ñтикеток EPL1"
+
+msgid "EPL2 Label Printer"
+msgstr "Принтер Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ Ñтикеток EPL2"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: Ðеверный файл набора Ñимволов %s\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: Ðеверный тип набора Ñимволов %s\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñтрока опиÑÐ°Ð½Ð¸Ñ ÑˆÑ€Ð¸Ñ„Ñ‚Ð°: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: Ðеверное направление текÑта %s\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ ÑˆÐ¸Ñ€Ð¸Ð½Ð° текÑта %s\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: Ошибка %d при отправке запроÑа PAPSendData: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: ОтÑутÑтвуют шрифты в файле набора Ñимволов %s\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: Принтер не отвечает\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: Принтер преждевременно передал индикатор EOF\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: Удаленный хоÑÑ‚ не принÑл контрольный файл (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: Удаленный хоÑÑ‚ не принÑл файл данных (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr ""
+"ERROR: Сбой, ÑвÑзанный Ñо временем Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¸ отправке данных на принтер\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸Ñ‚ÑŒ файл %d к заданию: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ задание %d: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: Ðе удаетÑÑ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ñ‚ÑŒ файл PDF"
+
+msgid "ERROR: Unable to create pipe"
+msgstr ""
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: Ðе удаетÑÑ Ñоздать Ñокет"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ñоздать временный Ñжатый файл печати: %s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: Ðе удаетÑÑ Ñоздать временный файл"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð²Ñ‹Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÑŒ pictwpstops: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: Ðе удаетÑÑ Ð·Ð°Ð¿ÑƒÑтить программу gs"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: Ðе удаетÑÑ Ð·Ð°Ð¿ÑƒÑтить программу pdftops"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ñ€Ð°Ð·Ð²ÐµÑ‚Ð²Ð¸Ñ‚ÑŒ pictwpstops: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ Ð·Ð°Ð¿Ñ€Ð¾Ñ PAP"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ ответ PAP"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ PPD-файл Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð° «%s» – %s.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»Ð¸Ñ‚ÑŒ Ñтандартную зону AppleTalk"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: Ðе удаетÑÑ Ð¿Ñ€Ð¾Ð²ÐµÑти поиÑк ответа PAP"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: Ðе удаетÑÑ Ð¿Ñ€Ð¾Ð²ÐµÑти поиÑк принтеров AppleTalk"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: Ðе удаетÑÑ Ñтавить Ð°Ð´Ñ€ÐµÑ AppleTalk"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ «%s» – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ %s: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ файл баннера «%s» – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ файл уÑтройÑтва «%s»: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ файл «%s» – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ файл «%s»: %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ файл печати «%s»: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ файл печати %s – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ файл печати %s: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ временный Ñжатый файл печати: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: Ðе удаетÑÑ Ñчитать данные печати"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: Ðе удаетÑÑ Ð·Ð°Ñ€ÐµÐ·ÐµÑ€Ð²Ð¸Ñ€Ð¾Ð²Ð°Ñ‚ÑŒ порт"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¿ÐµÑ€ÐµÐ¹Ñ‚Ð¸ к Ñмещению %ld в файле – %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¿ÐµÑ€ÐµÐ¹Ñ‚Ð¸ к Ñмещению %lld в файле – %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð¸Ñ‚ÑŒ команду LPD"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð¸Ñ‚ÑŒ контрольный Ð·Ð°Ð¿Ñ€Ð¾Ñ PAP"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð¸Ñ‚ÑŒ иÑходный Ð·Ð°Ð¿Ñ€Ð¾Ñ PAP на отправку данных"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð¸Ñ‚ÑŒ файл печати на принтер"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð¸Ñ‚ÑŒ конечное нулевое значение на принтер"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð¿Ð¾Ð´Ð¾Ð¶Ð´Ð°Ñ‚ÑŒ pictwpstops: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð·Ð°Ð¿Ð¸Ñать %d байт на «%s»: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: Ðе удаетÑÑ Ð·Ð°Ð¿Ð¸Ñать контрольный файл"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: Ðе удаетÑÑ Ð·Ð°Ð¿Ð¸Ñать данные печати"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð·Ð°Ð¿Ð¸Ñать данные печати: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr "ERROR: Ðе удаетÑÑ Ð·Ð°Ð¿Ð¸Ñать неÑжатые данные документа: %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: ÐеизвеÑтный порÑдок файлов «%s»\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: Символ неизвеÑтного формата «%c»\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: ÐеизвеÑтный режим печати «%s»\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: Сбой оператора select()"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: Ðе удаетÑÑ ÑƒÑтановить файл печати"
+
+msgid "Edit Configuration File"
+msgstr "Редактировать файл конфигурации"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Конечный баннер"
+
+msgid "English"
+msgstr "Russian"
+
+msgid "Enter old password:"
+msgstr "Введите Ñтарый пароль:"
+
+msgid "Enter password again:"
+msgstr "Введите пароль Ñнова:"
+
+msgid "Enter password:"
+msgstr "Введите пароль:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Введите Ñвое Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ пароль или данные учетной запиÑи root, чтобы "
+"получить доÑтуп к Ñтой Ñтранице. ЕÑли иÑпользуетÑÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ° подлинноÑти "
+"Kerberos, необходимо также иметь дейÑтвительный билет Kerberos."
+
+msgid "Envelope Feed"
+msgstr "Подача конвертов"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Политика ошибок"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "Каждые 10 Ñтикеток"
+
+msgid "Every 2 Labels"
+msgstr "Каждые 2 Ñтикетки"
+
+msgid "Every 3 Labels"
+msgstr "Каждые 3 Ñтикетки"
+
+msgid "Every 4 Labels"
+msgstr "Каждые 4 Ñтикетки"
+
+msgid "Every 5 Labels"
+msgstr "Каждые 5 Ñтикеток"
+
+msgid "Every 6 Labels"
+msgstr "Каждые 6 Ñтикеток"
+
+msgid "Every 7 Labels"
+msgstr "Каждые 7 Ñтикеток"
+
+msgid "Every 8 Labels"
+msgstr "Каждые 8 Ñтикеток"
+
+msgid "Every 9 Labels"
+msgstr "Каждые 9 Ñтикеток"
+
+msgid "Every Label"
+msgstr "ÐšÐ°Ð¶Ð´Ð°Ñ Ñтикетка"
+
+msgid "Expectation Failed"
+msgstr "Сбой ожиданиÑ"
+
+msgid "Export Printers to Samba"
+msgstr "ЭкÑпортировать принтеры в Samba"
+
+msgid "FAIL\n"
+msgstr "FAIL\n"
+
+msgid "File Folder"
+msgstr "Каталог файла"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Каталог файла - 9 16/8 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"URI-адреÑа файлового уÑтройÑтва отключены! Чтобы включить их, иÑпользуйте "
+"директиву FileDevice в «%s/cupsd.conf»."
+
+msgid "Folio"
+msgstr "Фолио"
+
+msgid "Forbidden"
+msgstr "Запрещено"
+
+msgid "General"
+msgstr "ОÑновные"
+
+msgid "Generic"
+msgstr "Общее"
+
+msgid "German FanFold"
+msgstr "German FanFold"
+
+msgid "German FanFold Legal"
+msgstr "German FanFold Legal"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Ð”Ð»Ñ Get-Response-PDU длина не уÑтановлена"
+
+msgid "Glossy Paper"
+msgstr "ГлÑÐ½Ñ†ÐµÐ²Ð°Ñ Ð±ÑƒÐ¼Ð°Ð³Ð°"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Оттенки Ñерого"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Папка подвеÑного хранениÑ"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Папка подвеÑного Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ - 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk отключен в СиÑтемных наÑтройках\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk отключен в СиÑтемных наÑтройках.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: Отмена Ð·Ð°Ð´Ð°Ð½Ð¸Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸â€¦\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: Подключен к принтеру…\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: Подключение к принтеру…\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: Контрольный файл уÑпешно отправлен\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr ""
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: Файл данных уÑпешно отправлен\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: Форматирование Ñтраницы %d…\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: Загрузка файла изображениÑ…\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: ПоиÑк принтера...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: УÑтановка ÑоединениÑ\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr "INFO: Файл печати отправлен, ожидание Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ принтера…\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: Принтер занÑÑ‚; попытка будет повторена через 10 Ñекунд…\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: Принтер занÑÑ‚; попытка будет повторена через 30 Ñекунд…\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: Принтер занÑÑ‚; попытка будет повторена через 5 Ñекунд…\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr ""
+"INFO: Принтер не поддерживает IPP/%d.%d; попытка иÑпользовать IPP/1.0…\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: Принтер занÑÑ‚; попытка будет повторена через 5 Ñекунд…\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: Ð’ данный момент принтер не подключен к Ñети.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: Ð’ данный момент принтер не подключен к Ñети.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: Принтер подключен к Ñети.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: Принтер не подключен к Ñети.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: Принтер не подключен; попытка будет повторена через 30 Ñекунд…\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: Печать Ñтраницы %d, %d%% завершена…\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: Печать Ñтраницы %d…\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: Готов к печати.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: Отправка контрольного файла (%lu байт)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: Отправка контрольного файла (%u байт)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: Отправка данных\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: Отправка файла данных (%ld байт)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: Отправка файла данных (%lld байт)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: Отправка данных печати…\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: Отправлен файл печати, %ld байт…\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: Отправлен файл печати, %lld байт…\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: Спулинг Ð·Ð°Ð´Ð°Ð½Ð¸Ñ LPR, %.0f%% выполнено…\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr ""
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: Ðе удаетÑÑ ÑƒÑтановить ÑвÑзь Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð¾Ð¼, поÑтановка в очередь на "
+"Ñледующем принтере в клаÑÑе…\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: ИÑпользуетÑÑ ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð°Ñ Ð·Ð¾Ð½Ð° AppleTalk «%s»\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: Ожидание Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð·Ð°Ð´Ð°Ð½Ð¸Ñ…\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: Ожидание доÑтупа к принтеру...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "Конверт ISO B4"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (раÑширенный)"
+
+msgid "ISO B5 Envelope"
+msgstr "Конверт ISO B5"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "Конверт ISO B6"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "ÐедейÑтвительный контрольный Ñимвол"
+
+msgid "Illegal main keyword string"
+msgstr "ÐедейÑÑ‚Ð²Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¾ÑÐ½Ð¾Ð²Ð½Ð°Ñ Ñтрока ключевых Ñлов"
+
+msgid "Illegal option keyword string"
+msgstr "ÐедейÑÑ‚Ð²Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ñтрока ключевых Ñлов параметра"
+
+msgid "Illegal translation string"
+msgstr "ÐедейÑтвительный перевод"
+
+msgid "Illegal whitespace character"
+msgstr "ÐедейÑтвительный Ñимвол пробела"
+
+msgid "Installable Options"
+msgstr "Параметры, разрешенные к уÑтановке"
+
+msgid "Installed"
+msgstr "УÑтановлено"
+
+msgid "IntelliBar Label Printer"
+msgstr "Принтер Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ Ñтикеток IntelliBar"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr ""
+
+msgid "Internal error"
+msgstr "ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°"
+
+msgid "Internet Postage 2-Part"
+msgstr "Ðаклейки Internet Postage 2-Part"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Ðаклейки Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "Ðаклейки Internet Postage 3-Part"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Ðаклейки Internet Postage 3-Part - 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "Протокол интернет-печати"
+
+msgid "Invite Envelope"
+msgstr "Конверт Invite Envelope"
+
+msgid "Italian Envelope"
+msgstr "Конверт Italian Envelope"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "Задание #%d уже прервано – не удаетÑÑ Ð¾Ñ‚Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "Задание #%d уже отменено – не удаетÑÑ Ð¾Ñ‚Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "Задание #%d уже завершено – не удаетÑÑ Ð¾Ñ‚Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "Задание завершено"
+
+msgid "Job Created"
+msgstr "Задание Ñоздано"
+
+msgid "Job ID: "
+msgstr "ID заданиÑ: "
+
+msgid "Job Options Changed"
+msgstr "Параметры Ð·Ð°Ð´Ð°Ð½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ñ‹"
+
+msgid "Job Stopped"
+msgstr "Задание оÑтановлено"
+
+msgid "Job UUID: "
+msgstr "UUID заданиÑ: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "Задание завершено и не может быть изменено."
+
+msgid "Job operation failed:"
+msgstr "Сбой операции заданиÑ:"
+
+msgid "Job state cannot be changed."
+msgstr "СоÑтоÑние Ð·Ð°Ð´Ð°Ð½Ð¸Ñ Ð½Ðµ может быть изменено."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "ЗаданиÑ"
+
+msgid "Kaku2 Envelope"
+msgstr "Конверт Kaku2"
+
+msgid "Kaku3 Envelope"
+msgstr "Конверт Kaku3"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "ХоÑÑ‚ или принтер LPD/LPR"
+
+msgid "Label Printer"
+msgstr "Принтер Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ Ñтикеток"
+
+msgid "Label Top"
+msgstr "Верхний край Ñтикетки"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Полный адреÑ"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Полный Ð°Ð´Ñ€ÐµÑ - 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "Ð¡ÐµÑ€Ð¸Ñ LaserJet, PCL 4/5"
+
+msgid "Light"
+msgstr "Светлый"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Строка длиннее разрешенного предела (255 Ñимволов)"
+
+msgid "List Available Printers"
+msgstr "СпиÑок доÑтупных принтеров"
+
+msgid "Location: "
+msgstr "МеÑтоположение: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "По длинной Ñтороне (книжнаÑ)"
+
+msgid "Make and Model: "
+msgstr "Марка и модель: "
+
+msgid "Manual Feed"
+msgstr "Ð ÑƒÑ‡Ð½Ð°Ñ Ð¿Ð¾Ð´Ð°Ñ‡Ð°"
+
+msgid "Media Dimensions: "
+msgstr "Размеры бумаги: "
+
+msgid "Media Limits: "
+msgstr "ÐžÐ³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð±ÑƒÐ¼Ð°Ð³Ð¸: "
+
+msgid "Media Name: "
+msgstr "Ðазвание бумаги: "
+
+msgid "Media Size"
+msgstr "Размер бумаги"
+
+msgid "Media Source"
+msgstr "ИÑточник бумаги"
+
+msgid "Media Tracking"
+msgstr "Контроль подачи бумаги"
+
+msgid "Media Type"
+msgstr "Тип бумаги"
+
+msgid "Medium"
+msgstr "Средний"
+
+msgid "Memory allocation error"
+msgstr "Ошибка раÑÐ¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¿Ð°Ð¼Ñти"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "ОтÑутÑтвует заголовок PPD-Adobe-4.x"
+
+msgid "Missing asterisk in column 1"
+msgstr "ОтÑутÑтвует звездочка в колонке 1"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "ОтÑутÑтвует Ñтрока значениÑ"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "Изменить клаÑÑ"
+
+msgid "Modify Printer"
+msgstr "Изменить принтер"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Конверт Monarch"
+
+msgid "Move All Jobs"
+msgstr "ПеремеÑтить вÑе заданиÑ"
+
+msgid "Move Job"
+msgstr "ПеремеÑтить задание"
+
+msgid "Moved Permanently"
+msgstr "Перемещено окончательно"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: Файл печати принÑÑ‚ – ID Ð·Ð°Ð´Ð°Ð½Ð¸Ñ %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: Файл печати принÑÑ‚ – ID Ð·Ð°Ð´Ð°Ð½Ð¸Ñ Ð½ÐµÐ¸Ð·Ð²ÐµÑтен.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "Указатель PPD-файла уÑтановлен на NULL"
+
+msgid "Name OID uses indefinite length"
+msgstr "Ð”Ð»Ñ Ð¸Ð¼ÐµÐ½Ð¸ OID длина не уÑтановлена"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Ðикогда"
+
+msgid "New Stylus Color Series"
+msgstr "Ð¡ÐµÑ€Ð¸Ñ Stylus Color нового поколениÑ"
+
+msgid "New Stylus Photo Series"
+msgstr "Ð¡ÐµÑ€Ð¸Ñ Stylus Photo нового поколениÑ"
+
+msgid "No"
+msgstr "Ðет"
+
+msgid "No Content"
+msgstr "Ðет контента"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "Ðет поÑледовательноÑти VarBind"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "Ðет рабочего подключениÑ"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "Ðет имени ÑообщеÑтва"
+
+msgid "No default printer"
+msgstr "Ðет принтера по умолчанию"
+
+msgid "No destinations added."
+msgstr "Ðет добавленных назначений."
+
+msgid "No error-index"
+msgstr "Ðет Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ error-index"
+
+msgid "No error-status"
+msgstr "Ðет Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ error-status"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "Ðет имени OID"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "Ðет идентификатора request-id"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "ПодпиÑки не найдены."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "Ðет поÑледовательноÑти variable-bindings"
+
+msgid "No version number"
+msgstr "Ðет номера верÑии"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "С прерыванием (опознавание маркеров)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "С прерыванием (опознавание Ñети)"
+
+msgid "Normal"
+msgstr "Ðормальный"
+
+msgid "Not Found"
+msgstr "Ðе найдено"
+
+msgid "Not Implemented"
+msgstr "Ðе реализовано"
+
+msgid "Not Installed"
+msgstr "Ðе уÑтановлено"
+
+msgid "Not Modified"
+msgstr "Ðе изменено"
+
+msgid "Not Supported"
+msgstr "Ðе поддерживаетÑÑ"
+
+msgid "Not allowed to print."
+msgstr "Ðе разрешено печатать."
+
+msgid "Note"
+msgstr "Примечание"
+
+msgid "OK"
+msgstr "ОК"
+
+msgid "Off (1-Sided)"
+msgstr "Выкл. (одноÑтороннÑÑ Ð¿ÐµÑ‡Ð°Ñ‚ÑŒ)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Ð˜Ð½Ñ‚ÐµÑ€Ð°ÐºÑ‚Ð¸Ð²Ð½Ð°Ñ Ñправка"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "Ðе удалоÑÑŒ открыть %s: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup без предыдущего CloseGroup"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI без предыдущего CloseUI/JCLCloseUI"
+
+msgid "Operation Policy"
+msgstr "Политика операций"
+
+msgid "Options Installed"
+msgstr "Параметры уÑтановлены"
+
+msgid "Options: "
+msgstr "Параметры: "
+
+msgid "Output Mode"
+msgstr "Режим вывода"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "Вывод Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð° %s отправлен на %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr "Вывод Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð° %s отправлен на удаленный принтер %s на %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "Вывод Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð° %s/%s отправлен на %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr "Вывод Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð° %s/%s отправлен на удаленный принтер %s на %s\n"
+
+msgid "PASS\n"
+msgstr "PASS\n"
+
+msgid "PCL Laser Printer"
+msgstr "Лазерный принтер PCL"
+
+msgid "PRC1 Envelope"
+msgstr "Конверт PRC1"
+
+msgid "PRC10 Envelope"
+msgstr "Конверт PRC10"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "Конверт PRC2"
+
+msgid "PRC3 Envelope"
+msgstr "Конверт PRC3"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (раÑширенный)"
+
+msgid "PRC4 Envelope"
+msgstr "Конверт PRC4"
+
+msgid "PRC5 Envelope"
+msgstr "Конверт PRC5"
+
+msgid "PRC6 Envelope"
+msgstr "Конверт PRC6"
+
+msgid "PRC7 Envelope"
+msgstr "Конверт PRC7"
+
+msgid "PRC8 Envelope"
+msgstr "Конверт PRC8"
+
+msgid "PRC9 Envelope"
+msgstr "Конверт PRC9"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "В пакете нет Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "Ðет индикатора SEQUENCE в начале пакета"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "Пароль Ð´Ð»Ñ %s на %s? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "Ð”Ð»Ñ Ð´Ð¾Ñтупа к %s через SAMBA требуетÑÑ Ð¿Ð°Ñ€Ð¾Ð»ÑŒ Ð´Ð»Ñ %s: "
+
+msgid "Pause Class"
+msgstr "ПриоÑтановить клаÑÑ"
+
+msgid "Pause Printer"
+msgstr "ПриоÑтановить принтер"
+
+msgid "Peel-Off"
+msgstr "Съемный Ñлой"
+
+msgid "Personal Envelope"
+msgstr "Индивидуальный конверт"
+
+msgid "Photo"
+msgstr "Фото"
+
+msgid "Photo Labels"
+msgstr "ФотоÑтикетки"
+
+msgid "Plain Paper"
+msgstr "ÐžÐ±Ñ‹Ñ‡Ð½Ð°Ñ Ð±ÑƒÐ¼Ð°Ð³Ð°"
+
+msgid "Policies"
+msgstr "Политики"
+
+msgid "Port Monitor"
+msgstr "Мониторинг порта"
+
+msgid "PostScript Printer"
+msgstr "Принтер PostScript"
+
+msgid "Postcard"
+msgstr "Открытка"
+
+msgid "Print Density"
+msgstr "ПлотноÑÑ‚ÑŒ печати"
+
+msgid "Print Job:"
+msgstr "Задание печати:"
+
+msgid "Print Mode"
+msgstr "Режим печати"
+
+msgid "Print Rate"
+msgstr "СкороÑÑ‚ÑŒ печати"
+
+msgid "Print Self-Test Page"
+msgstr "Ðапечатать пробную Ñтраницу"
+
+msgid "Print Speed"
+msgstr "СкороÑÑ‚ÑŒ печати"
+
+msgid "Print Test Page"
+msgstr "Ðапечатать пробную Ñтраницу"
+
+msgid "Print and Cut"
+msgstr "Ðапечатать и обрезать"
+
+msgid "Print and Tear"
+msgstr "Ðапечатать и оборвать"
+
+msgid "Printed For: "
+msgstr "Ðапечатано длÑ: "
+
+msgid "Printed From: "
+msgstr "Ðапечатано из: "
+
+msgid "Printed On: "
+msgstr "Дата печати: "
+
+msgid "Printer Added"
+msgstr "Принтер добавлен"
+
+msgid "Printer Default"
+msgstr "Принтер выбран по умолчанию"
+
+msgid "Printer Deleted"
+msgstr "Принтер удален"
+
+msgid "Printer Modified"
+msgstr "Принтер изменен"
+
+msgid "Printer Name: "
+msgstr "Ð˜Ð¼Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð°: "
+
+msgid "Printer Paused"
+msgstr "Принтер приоÑтановлен"
+
+msgid "Printer Settings"
+msgstr "Параметры принтера"
+
+msgid "Printer:"
+msgstr "Принтер:"
+
+msgid "Printers"
+msgstr "Принтеры"
+
+msgid "Purge Jobs"
+msgstr "Удалить заданиÑ"
+
+msgid "Quarto"
+msgstr "Кватро"
+
+msgid "Quota limit reached."
+msgstr "Предел квоты доÑтигнут."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr ""
+"Ранг Владелец Задание Файл(ы) Общий размер\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"Ранг Владелец Задание печати Файл(ы) Общий "
+"размер\n"
+
+msgid "Reject Jobs"
+msgstr "Отклонить заданиÑ"
+
+msgid "Reprint After Error"
+msgstr "Повторить печать поÑле ошибки"
+
+msgid "Request Entity Too Large"
+msgstr "Слишком большое Ñодержимое запроÑа"
+
+msgid "Resolution"
+msgstr "Разрешение"
+
+msgid "Resume Class"
+msgstr "Возобновить работу клаÑÑа"
+
+msgid "Resume Printer"
+msgstr "Возобновить работу принтера"
+
+msgid "Return Address"
+msgstr "Обратный адреÑ"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Обратный Ð°Ð´Ñ€ÐµÑ - 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "ВернутьÑÑ Ð² начало"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Ð—Ð°Ð¿ÑƒÑ‰ÐµÐ½Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°: %s %s -N -A %s -c «%s»\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "Ð”Ð»Ñ SEQUENCE длина не уÑтановлена"
+
+msgid "See Other"
+msgstr "ПоÑмотреть другие"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "ПоÑледовательный порт #%d"
+
+msgid "Server Restarted"
+msgstr "Сервер перезагружен"
+
+msgid "Server Security Auditing"
+msgstr "Проверка безопаÑноÑти Ñервера"
+
+msgid "Server Started"
+msgstr "Сервер загружен"
+
+msgid "Server Stopped"
+msgstr "Сервер оÑтановлен"
+
+msgid "Service Unavailable"
+msgstr "Служба недоÑтупна"
+
+msgid "Set Allowed Users"
+msgstr "Указать допущенных пользователей"
+
+msgid "Set As Server Default"
+msgstr "ИÑпользовать данный Ñервер по умолчанию"
+
+msgid "Set Class Options"
+msgstr "ÐаÑтроить параметры клаÑÑа"
+
+msgid "Set Printer Options"
+msgstr "ÐаÑтроить параметры принтера"
+
+msgid "Set Publishing"
+msgstr "ÐаÑтроить публикацию"
+
+msgid "Shipping Address"
+msgstr "ÐÐ´Ñ€ÐµÑ Ð´Ð¾Ñтавки"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "ÐÐ´Ñ€ÐµÑ Ð´Ð¾Ñтавки - 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "По короткой Ñтороне (альбомнаÑ)"
+
+msgid "Special Paper"
+msgstr "ОÑÐ¾Ð±Ð°Ñ Ð±ÑƒÐ¼Ð°Ð³Ð°"
+
+msgid "Standard"
+msgstr "Стандартный"
+
+msgid "Starting Banner"
+msgstr "ЗапуÑк баннера"
+
+msgid "Statement"
+msgstr "Оператор"
+
+msgid "Stylus Color Series"
+msgstr "Ð¡ÐµÑ€Ð¸Ñ Stylus Color"
+
+msgid "Stylus Photo Series"
+msgstr "Ð¡ÐµÑ€Ð¸Ñ Stylus Photo"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "Протоколы переключениÑ"
+
+msgid "Tabloid"
+msgstr "Tabloid"
+
+msgid "Tabloid (Oversize)"
+msgstr "Tabloid (раÑширенный)"
+
+msgid "Tear"
+msgstr "Оборвать"
+
+msgid "Tear-Off"
+msgstr "МеÑто отрыва"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Откорректировать положение меÑта отрыва"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "Ðе удаетÑÑ Ð½Ð°Ð¹Ñ‚Ð¸ PPD-файл «%s»."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "Ðе удалоÑÑŒ открыть PPD-файл «%s»: %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Ð˜Ð¼Ñ ÐºÐ»Ð°ÑÑа может Ñодержать макÑимально 127 печатных Ñимволов и не может "
+"Ñодержать пробелы, дроби (/) или знак «решетки» (#)."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+"Ðтрибут notify-lease-duration не может иÑпользоватьÑÑ Ñ Ð¿Ð¾Ð´Ð¿Ð¸Ñками на "
+"задание."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Ð˜Ð¼Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð° может Ñодержать макÑимально 127 печатных Ñимволов и не может "
+"Ñодержать пробелы, дроби (/) или знак «решетки» (#)."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "Принтер или клаÑÑ Ð½Ðµ найден."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "printer-uri «%s» Ñодержит недопуÑтимые Ñимволы."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr "printer-uri должен иметь форму «ipp://HOSTNAME/classes/CLASSNAME»."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr "printer-uri должен иметь форму «ipp://HOSTNAME/printers/PRINTERNAME»."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"Ð˜Ð¼Ñ Ð¿Ð¾Ð´Ð¿Ð¸Ñки не может Ñодержать пробелы, дроби (/), вопроÑительные знаки (?) "
+"или знак «решетки» (#)."
+
+msgid "There are too many subscriptions."
+msgstr "Слишком много подпиÑок."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "ÐоÑитель Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ методом термопереноÑа"
+
+msgid "Title: "
+msgstr "Заголовок: "
+
+msgid "Too many active jobs."
+msgstr "Слишком много активных заданий."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "ПрозрачноÑÑ‚ÑŒ"
+
+msgid "Tray"
+msgstr "Лоток"
+
+msgid "Tray 1"
+msgstr "Лоток 1"
+
+msgid "Tray 2"
+msgstr "Лоток 2"
+
+msgid "Tray 3"
+msgstr "Лоток 3"
+
+msgid "Tray 4"
+msgstr "Лоток 4"
+
+msgid "URI Too Long"
+msgstr "Слишком длинный Ð°Ð´Ñ€ÐµÑ URI"
+
+msgid "US Executive"
+msgstr "US Executive"
+
+msgid "US Fanfold"
+msgstr "US Fanfold"
+
+msgid "US Ledger"
+msgstr "US Ledger"
+
+msgid "US Legal"
+msgstr "US Legal"
+
+msgid "US Legal (Oversize)"
+msgstr "US Legal (раÑширенный)"
+
+msgid "US Letter"
+msgstr "US Letter"
+
+msgid "US Letter (Oversize)"
+msgstr "US Letter (раÑширенный)"
+
+msgid "US Letter (Small)"
+msgstr "US Letter (уменьшенный)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "ПоÑледовательный порт USB #%d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ доÑтуп к файлу «cupsd.conf»:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "Ðе удаетÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸Ñ‚ÑŒ подпиÑку RSS:"
+
+msgid "Unable to add class:"
+msgstr "Ðе удаетÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸Ñ‚ÑŒ клаÑÑ:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "Ðе удаетÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸Ñ‚ÑŒ принтер:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "Ðе удаетÑÑ Ð¾Ñ‚Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ подпиÑку RSS:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "Ðе удаетÑÑ Ð¸Ð·Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ атрибут printer-is-shared:"
+
+msgid "Unable to change printer:"
+msgstr "Ðе удаетÑÑ Ð¸Ð·Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ принтер:"
+
+msgid "Unable to change server settings:"
+msgstr "Ðе удаетÑÑ Ð¸Ð·Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ наÑтройки Ñервера:"
+
+msgid "Unable to connect to host."
+msgstr "Ðе удаетÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÑŒÑÑ Ðº хоÑту."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "Ðе удаетÑÑ Ñоздать временный файл:"
+
+msgid "Unable to delete class:"
+msgstr "Ðе удаетÑÑ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ клаÑÑ:"
+
+msgid "Unable to delete printer:"
+msgstr "Ðе удаетÑÑ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ принтер:"
+
+msgid "Unable to do maintenance command:"
+msgstr "Ðе удаетÑÑ Ð²Ñ‹Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÑŒ команду обÑлуживаниÑ:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ ÑпиÑок клаÑÑа:"
+
+msgid "Unable to get class status:"
+msgstr "Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ ÑÑ‚Ð°Ñ‚ÑƒÑ ÐºÐ»Ð°ÑÑа:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ ÑпиÑок драйверов принтера:"
+
+msgid "Unable to get printer attributes:"
+msgstr "Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ атрибуты принтера:"
+
+msgid "Unable to get printer list:"
+msgstr "Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ ÑпиÑок принтеров:"
+
+msgid "Unable to get printer status:"
+msgstr "Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ ÑÑ‚Ð°Ñ‚ÑƒÑ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð°:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "Ðе удаетÑÑ Ð¸Ð·Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ клаÑÑ:"
+
+msgid "Unable to modify printer:"
+msgstr "Ðе удаетÑÑ Ð¸Ð·Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ принтер:"
+
+msgid "Unable to move job"
+msgstr "Ðе удаетÑÑ Ð¿ÐµÑ€ÐµÐ¼ÐµÑтить задание"
+
+msgid "Unable to move jobs"
+msgstr "Ðе удаетÑÑ Ð¿ÐµÑ€ÐµÐ¼ÐµÑтить заданиÑ"
+
+msgid "Unable to open PPD file"
+msgstr "Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ PPD-файл"
+
+msgid "Unable to open PPD file:"
+msgstr "Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ PPD-файл:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ файл «cupsd.conf»:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "Ðе удаетÑÑ Ð½Ð°Ð¿ÐµÑ‡Ð°Ñ‚Ð°Ñ‚ÑŒ пробную Ñтраницу:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "Ðе удаетÑÑ Ð·Ð°Ð¿ÑƒÑтить «%s»: %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "Ðе удаетÑÑ Ð½Ð°Ñтроить параметры:"
+
+msgid "Unable to set server default:"
+msgstr "Ðе удаетÑÑ Ð½Ð°Ð·Ð½Ð°Ñ‡Ð¸Ñ‚ÑŒ Ñервер иÑпользуемым по умолчанию:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "Ðе удаетÑÑ Ð·Ð°Ð³Ñ€ÑƒÐ·Ð¸Ñ‚ÑŒ файл «cupsd.conf»:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "Ðе Ñанкционировано"
+
+msgid "Units"
+msgstr "Единицы"
+
+msgid "Unknown"
+msgstr "ÐеизвеÑтный"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¿Ð¾Ð»Ð¸Ñ‚Ð¸ÐºÐ° printer-error-policy «%s»."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¿Ð¾Ð»Ð¸Ñ‚Ð¸ÐºÐ° printer-op-policy «%s»."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Ðеподдерживаемый тип значениÑ"
+
+msgid "Upgrade Required"
+msgstr "ТребуетÑÑ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ðµ"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"СинтакÑиÑ:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "СинтакÑиÑ: %s job user title copies options [filename]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "СинтакÑиÑ: %s job-id user title copies options [file]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "СинтакÑиÑ: %s job-id user title copies options file\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"СинтакÑиÑ: cupsaddsmb [options] принтер1 ... принтерN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Параметры:\n"
+" -E Подключение к Ñерверу шифруетÑÑ\n"
+" -H samba-server ИÑпользуетÑÑ Ð½Ð°Ð·Ð²Ð°Ð½Ð½Ñ‹Ð¹ Ñервер SAMBA\n"
+" -U samba-user ВыполнÑетÑÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ° подлинноÑти Ñ Ð¸Ñпользованием "
+"указанного Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ SAMBA\n"
+" -a ЭкÑпортируютÑÑ Ð²Ñе принтеры\n"
+" -h cups-server ИÑпользуетÑÑ Ð½Ð°Ð·Ð²Ð°Ð½Ð½Ñ‹Ð¹ Ñервер CUPS\n"
+" -v Подробное отображение (показать команды)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"СинтакÑиÑ: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Параметры:\n"
+"\n"
+" -E ВключаетÑÑ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ðµ\n"
+" -U username УказываетÑÑ Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ\n"
+" -h server[:port] УказываетÑÑ Ð°Ð´Ñ€ÐµÑ Ñервера\n"
+"\n"
+" --[no-]debug-logging ВключаетÑÑ/отключаетÑÑ Ð²ÐµÐ´ÐµÐ½Ð¸Ðµ журнала отладки\n"
+" --[no-]remote-admin ВключаетÑÑ/отключаетÑÑ ÑƒÐ´Ð°Ð»ÐµÐ½Ð½Ð¾Ðµ "
+"админиÑтрирование\n"
+" --[no-]remote-any РазрешаетÑÑ/запрещаетÑÑ Ð´Ð¾Ñтуп из Интернета\n"
+" --[no-]remote-printers ОтображаютÑÑ/ÑкрываютÑÑ ÑƒÐ´Ð°Ð»ÐµÐ½Ð½Ñ‹Ðµ принтеры\n"
+" --[no-]share-printers ВключаетÑÑ/отключаетÑÑ ÑовмеÑтное иÑпользование "
+"принтеров\n"
+" --[no-]user-cancel-any ПользователÑм разрешаетÑÑ/запрещаетÑÑ Ð¾Ñ‚Ð¼ÐµÐ½ÑÑ‚ÑŒ "
+"заданиÑ\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"СинтакÑиÑ: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file ЗагружаетÑÑ Ð°Ð»ÑŒÑ‚ÐµÑ€Ð½Ð°Ñ‚Ð¸Ð²Ð½Ñ‹Ð¹ файл конфигурации\n"
+"-f Задание имеет выÑокий приоритет\n"
+"-F Задание имеет выÑокий приоритет и выделÑетÑÑ\n"
+"-h ОтображаетÑÑ Ð´Ð°Ð½Ð½Ð¾Ðµ Ñообщение\n"
+"-l cupsd запуÑкаетÑÑ Ð¸Ð· launchd(8)\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"СинтакÑиÑ: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Параметры:\n"
+"\n"
+" -h ОтображаетÑÑ Ñправка по иÑпользованию программы\n"
+"\n"
+" Примечание: Ð´Ð°Ð½Ð½Ð°Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð° проверÑет только комментарии DSC, а не Ñам "
+"PostScript.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "СинтакÑиÑ: lpmove job/src dest\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "СинтакÑиÑ: lppasswd [-g groupname]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"{>СинтакÑиÑ: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"СинтакÑиÑ: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] "
+"[+interval]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"СинтакÑиÑ: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Параметры:\n"
+" -D name=value Указанной переменной приÑваиваетÑÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ðµ.\n"
+" -I include-dir ДобавлÑетÑÑ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³ в путь поиÑка.\n"
+" -c catalog.po ЗагружаетÑÑ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¹ каталог Ñообщений.\n"
+" -d output-dir УказываетÑÑ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³ Ð´Ð»Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð½Ñ‹Ñ… данных.\n"
+" -l lang[,lang,...] УказываетÑÑ Ñзык (регион) Ð´Ð»Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð½Ñ‹Ñ… данных.\n"
+" -m Ð’ качеÑтве имени файла иÑпользуетÑÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ðµ "
+"ModelName.\n"
+" -t ВмеÑто ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ PPD-файлов выполнÑетÑÑ Ð¸Ñ… проверка.\n"
+" -v Режим подробного Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ (чем больше букв v, тем "
+"выше уровень детализации).\n"
+" -z Файлы PPD ÑжимаютÑÑ Ñ Ð¸Ñпользованием GNU zip.\n"
+" --cr Строки заканчиваютÑÑ Ð½Ð° CR (Mac OS 9).\n"
+" --crlf Строки заканчиваютÑÑ Ð½Ð° CR + LF (Windows).\n"
+" --lf Строки заканчиваютÑÑ Ð½Ð° LF (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"СинтакÑиÑ: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Указанной переменной приÑваиваетÑÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ðµ.\n"
+"Параметры:\n"
+" -I include-dir ДобавлÑетÑÑ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³ в путь поиÑка.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"СинтакÑиÑ: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Параметры:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"СинтакÑиÑ: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Параметры:\n"
+" -o filename.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"СинтакÑиÑ: ppdpo [options] -o filename.po filename.drv [ ... filenameN."
+"drv ]\n"
+"Параметры:\n"
+" -D name=value Указанной переменной приÑваиваетÑÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ðµ.\n"
+" -I include-dir ДобавлÑетÑÑ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³ в путь поиÑка.\n"
+" -v Подробный режим (чем больше букв v, тем выше уровень "
+"детализации).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "СинтакÑиÑ: snmp [host-or-ip-address]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Ð”Ð»Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð´Ð»Ð¸Ð½Ð° не уÑтановлена"
+
+msgid "VarBind uses indefinite length"
+msgstr "Ð”Ð»Ñ VarBind длина не уÑтановлена"
+
+msgid "Version uses indefinite length"
+msgstr "Ð”Ð»Ñ Version длина не уÑтановлена"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: Будут добавлены только первые найденные принтеры (%d)"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: Параметр waiteof «%s» должен иметь булево значение\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: Принтер не отвечает\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: Принтер преждевременно передал индикатор EOF\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ «%s:%s»: %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: Ðе удаетÑÑ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð¸Ñ‚ÑŒ Ð·Ð°Ð¿Ñ€Ð¾Ñ ÑтатуÑа PAP"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: Ðепредвиденный PAP-пакет типа %d\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: ÐеизвеÑтный PAP-пакет типа %d\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: Параметр ÑтатуÑа «%s» должен иметь чиÑловое значение\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Да"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"Ð’Ñ‹ должны получить доÑтуп к Ñтой Ñтранице Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ URL <A HREF=«https://%s:%d"
+"%s»>https://%s:%d%s</A>."
+
+msgid "You4 Envelope"
+msgstr "Конверт You4"
+
+msgid "ZPL Label Printer"
+msgstr "Принтер Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ Ñтикеток ZPL"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "отменено"
+
+msgid "canceled"
+msgstr "отменено"
+
+msgid "completed"
+msgstr "завершено"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr "convert: ИÑпользуйте параметр -f Ð´Ð»Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ ÐºÐ¾Ð½Ð²ÐµÑ€Ñ‚Ð¸Ñ€ÑƒÐµÐ¼Ð¾Ð³Ð¾ файла.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "Ðе удалоÑÑŒ выполнить cups-deviced."
+
+msgid "cups-driverd failed to execute."
+msgstr "Ðе удалоÑÑŒ выполнить cups-driverd."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: Ðет PPD-файла Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð° «%s» – %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: Ðе удаетÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÑŒÑÑ Ðº Ñерверу: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr ""
+"cupsd: Поддержка launchd(8) не Ñкомпилирована, работа в нормальном режиме.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ файл Ð·Ð°Ð´Ð°Ð½Ð¸Ñ - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd: Параметр «-q» неÑовмеÑтим Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð¼ «-v».\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd: Параметр «-v» неÑовмеÑтим Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð¼ «-q».\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "уÑтройÑтво Ð´Ð»Ñ %s/%s: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "уÑтройÑтво Ð´Ð»Ñ %s: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "Ð”Ð»Ñ error-index длина не уÑтановлена"
+
+msgid "error-status uses indefinite length"
+msgstr "Ð”Ð»Ñ error-status длина не уÑтановлена"
+
+msgid "held"
+msgstr "задержано"
+
+msgid "help\t\tget help on commands\n"
+msgstr "Ñправка\t\tполучить Ñправку о командах\n"
+
+msgid "idle"
+msgstr "Ñвободен"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: Принтер %s уже ÑвлÑетÑÑ Ñ‡Ð»ÐµÐ½Ð¾Ð¼ клаÑÑа %s.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: Принтер %s не ÑвлÑетÑÑ Ñ‡Ð»ÐµÐ½Ð¾Ð¼ клаÑÑа %s.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: Ðе удаетÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÑŒÑÑ Ðº Ñерверу: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ PPD-файл «%s» – %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ файл «%s»: %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: Ðе удаетÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÑŒÑÑ Ðº Ñерверу: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: Ðе удаетÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸Ñ‚ÑŒ принтер или предÑтавитель клаÑÑа: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ PPD-файл Ð´Ð»Ñ %s: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: Пароль отклонен.\n"
+"Пароль должен ÑоÑтоÑÑ‚ÑŒ как минимум из 6 Ñимволов, не может Ñодержать\n"
+"Ваше Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ должен Ñодержать по крайней мере одну букву и "
+"цифру.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: Ðе удаетÑÑ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ñ‚ÑŒ Ñтроку паролÑ: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ файл паролÑ: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: Ðе удаетÑÑ Ð·Ð°Ð¿Ð¸Ñать файл паролÑ: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr "lppasswd: Ðе удалоÑÑŒ Ñоздать рез. копию Ñтарого файла паролÑ: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: Ðе удалоÑÑŒ переименовать файл паролÑ: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: Пользователь «%s» и группа «%s» не ÑущеÑтвуют.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "члены клаÑÑа %s:\n"
+
+msgid "no entries\n"
+msgstr "нет запиÑей\n"
+
+msgid "no system default destination\n"
+msgstr "нет Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ ÑиÑтемы по умолчанию\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "задержка"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: ДобавлÑÑŽ каталог «%s»...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: ДобавлÑÑŽ/обновлÑÑŽ текÑÑ‚ интерфейÑа из %s...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: ÐедопуÑтимое булево значение (%s) в Ñтроке %d из %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ð·Ð°Ð¼ÐµÐ½Ð° переменной ($%c) в Ñтроке %d из %s.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: Ð’ Ñтроке %d из %s должно быть булево значение.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: Ð’ Ñтроке %d из %s должен быть код выбора.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: Ð’ Ñтроке %d из %s должно быть имÑ/текÑÑ‚ выбора.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: Загружаю файл Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸ÐµÐ¹ о драйвере «%s»...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: Загружаю ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ñ€ÐµÐ³Ð¸Ð¾Ð½Ð° «%s»...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: Загружаю ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð· «%s»...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "lpadmin: Ðе удаетÑÑ Ñоздать PPD-файл «%s» – %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: Ðе удаетÑÑ Ñоздать каталог Ð´Ð»Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð½Ñ‹Ñ… данных %s: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: Ðе удаетÑÑ Ñоздать конвейеры Ð´Ð»Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð½Ñ‹Ñ… данных: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: Ðе удаетÑÑ Ð²Ñ‹Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÑŒ cupstestppd: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: Ðе удаетÑÑ Ð½Ð°Ð¹Ñ‚Ð¸ локализацию Ð´Ð»Ñ Â«%s» - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: Ðе удаетÑÑ Ð·Ð°Ð³Ñ€ÑƒÐ·Ð¸Ñ‚ÑŒ файл локализации «%s» - %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: Ðе определена Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ (%s) в Ñтроке %d из %s.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: ЗапиÑываю %s...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: ЗапиÑываю PPD-файлы в каталог «%s»...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: ПропуÑкаю PPD-файл %s...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: Ðевозможно Ñоздать резервную копию %s на %s- %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "принтер %s отключен Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° %s -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "принтер %s Ñвободен. Включен Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "принтер %s ÑÐµÐ¹Ñ‡Ð°Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð°ÐµÑ‚ %s-%d. Включен Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° %s\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "принтер %s/%s отключен Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° %s -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "принтер %s/%s Ñвободен. Включен Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "принтер %s/%s ÑÐµÐ¹Ñ‡Ð°Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð°ÐµÑ‚ %s-%d. Включен Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° %s\n"
+
+msgid "processing"
+msgstr "обработка"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "id запроÑа %s-%d (%d файл.)\n"
+
+msgid "request-id uses indefinite length"
+msgstr "Ð”Ð»Ñ request-id длина не определена"
+
+msgid "scheduler is not running\n"
+msgstr "планировщик не запущен\n"
+
+msgid "scheduler is running\n"
+msgstr "планировщик запущен\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "не удалоÑÑŒ уÑтановить %s: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "ÑтатуÑ\t\tпоказать ÑÑ‚Ð°Ñ‚ÑƒÑ Ð´ÐµÐ¼Ð¾Ð½Ð° и очереди\n"
+
+msgid "stopped"
+msgstr "оÑтановлен"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "назначение ÑиÑтемы по умолчанию: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "назначение ÑиÑтемы по умолчанию: %s/%s\n"
+
+msgid "unknown"
+msgstr "неизвеÑтный"
+
+msgid "untitled"
+msgstr "новый"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "Ð”Ð»Ñ variable-bindings длина не уÑтановлена"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " WARN %s не Ñодержит ÑоответÑтвующих параметров!\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " WARN ЗначениÑ, иÑпользуемые по умолчанию, конфликтуют!\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " WARN Ключевое Ñлово параметра дуплекÑа %s может привеÑти к "
+#~ "некорректным результатам. ИÑпользуйте Ð¸Ð¼Ñ Â«Duplex»!\n"
+#~ " REF: Стр. 122, раздел 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " WARN Файл Ñодержит комбинацию окончаний Ñтроки CR, LF и CR "
+#~ "LF!\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " WARN Строка %d Ñодержит только пробелы!\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " WARN Файл APDialogExtension отÑутÑтвует «%s»\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " WARN Файл APPrinterIconPath отÑутÑтвует «%s»\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " WARN PPD-файлы не из Windows должны иÑпользовать Ñтроки только "
+#~ "Ñ Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸ÐµÐ¼ LF, а не Ñ CR LF!\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " WARN УÑÑ‚Ð°Ñ€ÐµÐ²ÑˆÐ°Ñ Ð²ÐµÑ€ÑÐ¸Ñ PPD %.1f!\n"
+#~ " REF: Стр. 42, раздел 5.2.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s не ÑущеÑтвует!\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s Ðеверный %s выбор %s!\n"
+#~ " REF: Стр. 122, раздел 5.17\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr " %s Ðеверный перевод UTF-8 «%s» Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° %s!\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr " %s Ðеверный перевод UTF-8 «%s» Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° %s, выбора %s!\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Ðеверное значение cupsFilter «%s»!\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s Ðеверный cupsICCProfile %s!\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Ðеверное значение cupsPreFilter «%s»!\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Ðеверный cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s Ðеверный Ñзык «%s»!\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s ПуÑтой cupsUIConstraints %s!\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s Перевод «%s» отÑутÑтвует Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° %s!\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr " %s Перевод «%s» отÑутÑтвует Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° %s, выбора %s!\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Выбор *%s %s отÑутÑтвует в UIConstraints «*%s %s *%s %s»!\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr ""
+#~ " %s Выбор *%s %s отÑутÑтвует в cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s Файл cupsICCProfile отÑутÑтвует «%s»!\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s ОтÑутÑтвует cupsUIResolver %s!\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr " %s Параметр %s отÑутÑтвует в UIConstraints «*%s %s *%s %s»!\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Параметр %s отÑутÑтвует в cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr " %s ОÑновной перевод «%s» не включен в файл!\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " ТРЕБУЕТСЯ %s: %s не определÑет выбор «Ðет»!\n"
+#~ " REF: Стр. 122, раздел 5.17\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " Хеш-значение %s cupsICCProfile %s конфликтует Ñ %s!\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver %s Ñоздает цикл!\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Ð”Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° %s имена %s и %s различаютÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ региÑтром "
+#~ "Ñимволов!\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **FAIL** %s должно ÑоответÑтвовать 1284DeviceID!\n"
+#~ " REF: Стр. 72, раздел 5.5\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** ÐЕВЕРÐЫЙ DefaultImageableArea %s!\n"
+#~ " REF: Стр. 102, раздел 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **FAIL** ÐЕВЕРÐЫЙ DefaultPaperDimension %s!\n"
+#~ " REF: Стр. 103, раздел 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **FAIL** Ðеверный %s выбор %s!\n"
+#~ " REF: Стр. 84, раздел 5,9\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr ""
+#~ " **FAIL** Ðеверный LanguageEncoding %s – должно быть ISOLatin1!\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr ""
+#~ " **FAIL** Ðеверный LanguageVersion %s – должен быть английÑкий!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **FAIL** Стандартный перевод Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° %s выбора %s Ñодержит 8-"
+#~ "битовые Ñимволы!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **FAIL** Стандартный перевод Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° %s Ñодержит 8-битовые "
+#~ "Ñимволы!\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Имена групп %s и %s различаютÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ региÑтром "
+#~ "Ñимволов!\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **FAIL** Ð”Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° %s Ð¸Ð¼Ñ %s вÑтречаетÑÑ Ð½ÐµÑколько раз!\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FAIL** Имена параметров %s и %s различаютÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ региÑтром "
+#~ "Ñимволов!\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " Ðеверный %%%%BoundingBox: в Ñтроке %d!\n"
+#~ " REF: Стр. 39, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ %%%%Page: в Ñтроке %d!\n"
+#~ " REF: Стр. 53, %%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " Ðеверные %%%%Pages: в Ñтроке %d!\n"
+#~ " REF: Стр. 43, %%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " Строка %d длиннее 255 Ñимволов (%d)!\n"
+#~ " REF: Стр. 25, Длина Ñтроки\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " %!PS-Adobe-3.0 отÑутÑтвует в первой Ñтроке!\n"
+#~ " REF: Стр. 17, 3.1 СоответÑтвующие документы\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " Комментарий %%EndComments отÑутÑтвует!\n"
+#~ " REF: Стр. 41, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " ОтÑутÑтвующий или неверный %%BoundingBox: комментарий!\n"
+#~ " REF: Стр. 39, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " ОтÑутÑÑ‚Ð²ÑƒÑŽÑ‰Ð°Ñ Ð¸Ð»Ð¸ Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ %%Page: комментарий!\n"
+#~ " REF: Стр. 53, %%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " ОтÑутÑтвующие или неверные %%Pages: комментарий!\n"
+#~ " REF: Стр. 43, %%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " Обнаружено Ñтрок длиннее 255 Ñимволов: %d!\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " Слишком много комментариев %%BeginDocument!\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " Слишком много комментариев %%EndDocument!\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " WARNING: файл Ñодержит бинарные данные!\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " WARNING: нет ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ð¸Ñ %%EndComments в файле!\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " WARNING: уÑÑ‚Ð°Ñ€ÐµÐ²ÑˆÐ°Ñ Ð²ÐµÑ€ÑÐ¸Ñ DSC %.1f в файле!\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s не поддерживаетÑÑ!"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: Дальнейшие дейÑÑ‚Ð²Ð¸Ñ Ð½ÐµÐ¸Ð·Ð²ÐµÑтны!\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: Ошибка – %s Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ ÑƒÐºÐ°Ð·Ñ‹Ð²Ð°ÐµÑ‚ неÑущеÑтвующее назначение «%"
+#~ "s»!\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: Ошибка – неверный ID заданиÑ!\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr ""
+#~ "%s: Ошибка – невозможно одновременно печатать файлы и изменÑÑ‚ÑŒ заданиÑ!\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: Ошибка – не удаетÑÑ Ð¿ÐµÑ‡Ð°Ñ‚Ð°Ñ‚ÑŒ из stdin, еÑли предоÑтавлены файлы или "
+#~ "ID заданиÑ!\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-S» должен идти набор Ñимволов!\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-T» должен быть указан тип контента!\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr ""
+#~ "%s: Ошибка – поÑле параметра «-n» должно быть указано количеÑтво копий!\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-#» должен быть указан номер копии!\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-P» должно быть указано назначение!\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-b» должно быть указано назначение!\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-d» должно быть указано назначение!\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-f» должна быть указана форма!\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-H» должно быть указано Ð¸Ð¼Ñ Ñ…Ð¾Ñта!\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-H» должно быть указано Ð¸Ð¼Ñ Ñ…Ð¾Ñта!\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-h» должно быть указано Ð¸Ð¼Ñ Ñ…Ð¾Ñта!\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr ""
+#~ "%s: Ошибка – поÑле параметра «-y» должен быть указан ÑпиÑок режимов!\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-%c» должно быть указано имÑ!\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr ""
+#~ "%s: Ошибка – поÑле параметра «-o» должна быть указана Ñтрока параметра!\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-P» должен идти ÑпиÑок Ñтраниц!\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-%c» должен быть указан приоритет!\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-r» должен идти текÑÑ‚ причины!\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-t» должен быть указан заголовок!\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr ""
+#~ "%s: Ошибка – поÑле параметра «-U» должно быть указано Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ!\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr ""
+#~ "%s: Ошибка – поÑле параметра «-u» должно быть указано Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ!\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: Ошибка – поÑле параметра «-%c» должно быть указано значение!\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: Ошибка – требуетÑÑ Â«Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¾Â», «не завершено» или «вÑе» поÑле параметра "
+#~ "«-W»!\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: Ошибка – планировщик не отвечает!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: Ошибка – неизвеÑтное назначение «%s»!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: Ошибка – неизвеÑтное назначение «%s/%s»!\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: Ошибка – неизвеÑтный параметр «%c»!\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: Ошибка – неизвеÑтный параметр «%s»!\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: ПоÑле параметра «-i» должен быть указан ID заданиÑ!\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: Ðеверное Ð¸Ð¼Ñ Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð² ÑпиÑке «%s»!\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr "%s: ТребуетÑÑ ID Ð·Ð°Ð´Ð°Ð½Ð¸Ñ («-i jobid») перед «-H restart»!\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: Ðет фильтра Ð´Ð»Ñ Ð¿Ñ€ÐµÐ¾Ð±Ñ€Ð°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸Ð· %s/%s в %s/%s!\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s: Ðет Ñкомпилированной поддержки шифрованиÑ!\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: Ðе удаетÑÑ ÑƒÑтановить ÑвÑзь Ñ Ñервером!\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: Ðе удаетÑÑ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»Ð¸Ñ‚ÑŒ тип MIME «%s»!\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ %s – %s\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ %s – %s в Ñтроке %d.\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s: Ðе удаетÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚ÑŒ базу данных MIME в «%s» или «%s»!\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: ÐеизвеÑтное назначение «%s»!\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: ÐеизвеÑтный MIME-тип Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ %s/%s!\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: ÐеизвеÑтный параметр «%c»!\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: ÐеизвеÑтный MIME-тип иÑточника %s/%s!\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: Внимание – модификатор формата «%c» не поддерживаетÑÑ â€“ вывод может "
+#~ "быть неправильным!\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: Внимание – параметр набора Ñимволов пропущен!\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: Внимание – параметр типа контента пропущен!\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: Внимание – параметр формы пропущен!\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: Внимание – параметр режима пропущен!\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr ""
+#~ "%s: ошибка – Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ %s указывает неÑущеÑтвующее назначение «%"
+#~ "s»!\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr ""
+#~ "%s: ошибка – поÑле параметра «-o» должна идти запиÑÑŒ вида option=value!\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "600dpi, оттенки Ñерого"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr "Ð”Ð»Ñ ÑкÑпорта драйверов принтера требуетÑÑ Ð¿Ð°Ñ€Ð¾Ð»ÑŒ Samba!"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr "Ð”Ð»Ñ ÑкÑпорта драйверов принтера требуетÑÑ Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Samba!"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "КлаÑÑ Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ «%s» уже ÑущеÑтвует!"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "Принтер Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ «%s» уже ÑущеÑтвует!"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr "Попытка уÑтановить %s printer-state на неверное значение %d!"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "Группы атрибутов не дейÑтвуют (%x < %x)!"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "Ðеверный URI уÑтройÑтва «%s»!\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "Ðеверное значение device-uri «%s»!"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñхема device-uri «%s»!"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "Ðеверное значение document-format «%s»!"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Ошибка в буфере filename!"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Ðеверное значение job-priority!"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Ðеверное значение job-sheets «%s»!"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Ðеверный тип Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ job-sheets!"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Ðеверное значение job-state!"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Ðеверный атрибут job-uri «%s»!"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "Ðеверное значение notify-pull-method «%s»!"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "Ðеверный URI notify-recipient-uri «%s»!"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "Ðеверный параметр + выбор в Ñтроке %d!"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "Ðеверное значение port-monitor «%s»!"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Ðеверное значение printer-state %d!"
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "Ðеверный номер верÑии запроÑа %d.%d!"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "Ðеверный ID подпиÑки!"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "Ðабор Ñимволов «%s» не поддерживаетÑÑ!"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "Ðе удалоÑÑŒ Ñканировать тип «%s»!"
+
+#~ msgid "Cover open."
+#~ msgstr "Крышка открыта."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "ПроÑвитель почти закончилÑÑ."
+
+#~ msgid "Developer empty!"
+#~ msgstr "ПроÑвитель закончилÑÑ!"
+
+#~ msgid "Door open."
+#~ msgstr "Дверца открыта."
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Ðеверный %%BoundingBox: комментарий проÑмотрен!\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: Ðеверный %%IncludeFeature: комментарий!\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ %%Page: комментарий в файле!\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: Ðеверный %%PageBoundingBox: комментарий в файле!\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: Ðеверный файл уÑтройÑтва SCSI «%s»!\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: Ðеверное значение количеÑтва Ñтолбцов %d!\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: Ðеверное значение cpi %f!\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: Ðеверное значение lpi %f!\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: Ðеверные параметры Ñтраницы!\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: Целевой принтер не ÑущеÑтвует!\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Дубликат %%BoundingBox: комментарий проÑмотрен!\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: Дубликат %%Pages: комментарий проÑмотрен!\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: ПуÑтой файл печати!\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr "ERROR: Ð’ Ñтроке %d из %s должна быть Ñтрока в кавычках!\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: КритичеÑкий Ñбой USB!\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr ""
+#~ "ERROR: Обнаружена Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° HP-GL/2, не удаетÑÑ Ð½Ð°Ð¿ÐµÑ‡Ð°Ñ‚Ð°Ñ‚ÑŒ файл!\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: ОтÑутÑтвует %%EndProlog!\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: ОтÑутÑтвует %%EndSetup!\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: ОтÑутÑтвует идентификатор URI уÑтройÑтва в командной Ñтроке и "
+#~ "Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ DEVICE_URI!\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: ОтÑутÑтвует значение в Ñтроке %d в файле баннера!\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: ТребуетÑÑ Ñтрока msgid перед Ñтрокой перевода в Ñтроке %d из %s!\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: Ðет %%BoundingBox: комментарий в заголовке!\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: Ðет %%Pages: комментарий в заголовке!\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Ðе обнаружено URI уÑтройÑтва в argv[0] или переменной Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ "
+#~ "DEVICE_URI!\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: Страницы не найдены!\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: Ðет бумаги!\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: ÐŸÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ PRINTER не указана!\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: Файл печати не принÑÑ‚ (%s)!\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: Принтер не отвечает!\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ñоздать временный файл – %s.\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ñоздать временный файл: %s\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ атрибуты Ð·Ð°Ð´Ð°Ð½Ð¸Ñ %d (%s)!\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ ÑÑ‚Ð°Ñ‚ÑƒÑ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð° (%s)!\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ð¾Ð±Ð½Ð°Ñ€ÑƒÐ¶Ð¸Ñ‚ÑŒ принтер «%s»!\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ файл Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸!\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ временный файл"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ð½Ð°Ð¿ÐµÑ‡Ð°Ñ‚Ð°Ñ‚ÑŒ Ñтолбцы Ñ Ñ‚ÐµÐºÑтом (%d)!\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ð½Ð°Ð¿ÐµÑ‡Ð°Ñ‚Ð°Ñ‚ÑŒ Ñтраницу Ñ Ñ‚ÐµÐºÑтом %dx%d!\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ñчитать данные печати!\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð¸Ñ‚ÑŒ данные печати (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð¸Ñ‚ÑŒ данные печати!\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ð·Ð°Ð¿Ð¸Ñать %d байт на принтер!\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ð·Ð°Ð¿Ð¸Ñать раÑтровые данные на драйвер!\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: Ðе удаетÑÑ Ð·Ð°Ð¿Ð¸Ñать данные во временный файл"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: Ðепредвиденный текÑÑ‚ в Ñтроке %d из %s!\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: ÐеизвеÑтное значение параметра ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Â«%s»!\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: ÐеизвеÑтный формат каталога Ñообщений Ð´Ð»Ñ Â«%s»!\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: ÐеизвеÑтный параметр «%s» Ñо значением «%s»!\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: ÐеизвеÑтное значение параметра верÑии «%s»!\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr ""
+#~ "ERROR: Ðеподдерживаемое значение ÑркоÑти %s, иÑпользуетÑÑ "
+#~ "brightness=100!\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr ""
+#~ "ERROR: Ðеподдерживаемое значение гаммы %s, иÑпользуетÑÑ gamma=1000!\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr ""
+#~ "ERROR: Ðеподдерживаемое значение number-up %d, иÑпользуетÑÑ number-up=1!\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: Ðеподдерживаемое значение number-up-layout %s, иÑпользуетÑÑ number-"
+#~ "up-layout=lrtb!\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: Ðеподдерживаемое значение page-border %s, иÑпользуетÑÑ page-"
+#~ "border=none!\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr "ERROR: Обнаружено переполнение doc_printf (%d байт), отменÑÑŽ!\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr "ERROR: Сбой фильтра pdftops при Ñигнале %d!\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr "ERROR: Фильтр pictwpstops закрыт Ñо ÑтатуÑом %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: Фильтр pictwpstops закрыт по Ñигналу %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: Фильтр pictwpstops закрыт Ñо ÑтатуÑом %d!\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: ВоÑÑтанавливаемо: не удаетÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÑŒÑÑ Ðº принтеру; попытка "
+#~ "будет повторена через 30 Ñекунд…\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "ПуÑтой PPD-файл!"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "ERROR: ТребуетÑÑ Ð¸Ð¼Ñ Ñ…Ð¾Ñта поÑле параметра «-h»!\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Ð’Ñ‹ÑÐ¾ÐºÐ°Ñ Ñ‚ÐµÐ¼Ð¿ÐµÑ€Ð°Ñ‚ÑƒÑ€Ð° термофикÑатора!"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "ÐÐ¸Ð·ÐºÐ°Ñ Ñ‚ÐµÐ¼Ð¿ÐµÑ€Ð°Ñ‚ÑƒÑ€Ð° термофикÑатора!"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "Получен атрибут printer-uri, но не job-id!"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Чернила/тонер заканчиваютÑÑ."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Чернила/тонер закончилиÑÑŒ!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Корзина чернил/тонера почти полный."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Корзина чернил/тонера полнаÑ!"
+
+#~ msgid "Interlock open."
+#~ msgstr "Открыт замок."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "Задание #%d не может быть перезапущено – нет файлов!"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "Задание #%d не ÑущеÑтвует!"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "Задание #%d завершено и не может быть изменено!"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "Задание #%d не завершено!"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "Задание #%d не задержано Ð´Ð»Ñ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ð¸!"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "Задание #%d не задержано!"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "Задание #%s не ÑущеÑтвует!"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "Задание #%d не найдено!"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "ПодпиÑки на задание не могут быть обновлены!"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "Язык «%s» не поддерживаетÑÑ!"
+
+#~ msgid "Media jam!"
+#~ msgstr "Затор бумаги!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Лоток Ñ Ð±ÑƒÐ¼Ð°Ð³Ð¾Ð¹ почти пуÑÑ‚."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Лоток Ñ Ð±ÑƒÐ¼Ð°Ð³Ð¾Ð¹ пуÑÑ‚!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Лоток Ñ Ð±ÑƒÐ¼Ð°Ð³Ð¾Ð¹ отÑутÑтвует!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "Ðеобходимо вÑтавить бумагу в лоток."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "ОтÑутÑтвует атрибут document-number!"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "ОтÑутÑтвуют двойные кавычки в Ñтроке %d!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "ОтÑутÑтвует Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ñ„Ð¾Ñ€Ð¼Ñ‹!"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "ОтÑутÑтвует атрибут notify-subscription-ids!"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "ОтÑутÑтвует атрибут requesting-user-name!"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "ОтÑутÑтвуют обÑзательные атрибуты!"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "ОтÑутÑтвует значение в Ñтроке %d!"
+
+#~ msgid "No PPD name!"
+#~ msgstr "Ðет имени PPD!"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Ðет уÑтановленных драйверов принтера Windows!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "Ðет активных заданий на %s!"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "Ðет атрибутов в запроÑе!"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "Ðет информации Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ подлинноÑти!"
+
+#~ msgid "No file!?!"
+#~ msgstr "Ðет файла!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "Ðе указано Ð²Ñ€ÐµÐ¼Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ!"
+
+#~ msgid "No printer name!"
+#~ msgstr "Ðет имени принтера!"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "Ðе указан Ð°Ð´Ñ€ÐµÑ printer-uri Ð´Ð»Ñ ÐºÐ»Ð°ÑÑа!"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "Ðе указан Ð°Ð´Ñ€ÐµÑ printer-uri!"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "Ðет адреÑа printer-uri в запроÑе!"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "Ðет атрибутов подпиÑки в запроÑе!"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC почти в end-of-life."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC в end-of-life!"
+
+#~ msgid "Out of toner!"
+#~ msgstr "ÐедоÑтаточно тонера!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Выходной лоток почти заполнен."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Выходной лоток заполнен!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Выходной лоток отÑутÑтвует!"
+
+#~ msgid "Printer offline."
+#~ msgstr "Принтер в режиме не подключен к Ñети."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "Принтер SCSI"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "Значение notify-user-data Ñлишком длинное (%d > 63 октетов)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "Ðет общего доÑтупа к принтеру или клаÑÑу!"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "ТребуетÑÑ Ð°Ñ‚Ñ€Ð¸Ð±ÑƒÑ‚ printer-uri!"
+
+#~ msgid "Toner low."
+#~ msgstr "Тонер заканчиваетÑÑ."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "Слишком много значений job-sheets (%d > 2)!"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "Слишком много значений printer-state-reasons (%d > %d)!"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "Ðе удаетÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸Ñ‚ÑŒ задание Ð´Ð»Ñ Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Â«%s»!"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "Ðе удаетÑÑ Ð²Ñ‹Ð´ÐµÐ»Ð¸Ñ‚ÑŒ памÑÑ‚ÑŒ Ð´Ð»Ñ Ñ‚Ð¸Ð¿Ð¾Ð² файлов!"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr "Ðе удаетÑÑ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ñ‚ÑŒ 64-битовые файлы драйвера принтера CUPS (%d)!"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr ""
+#~ "Ðе удаетÑÑ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ñ‚ÑŒ 64-битовые файлы драйвера принтера Ð´Ð»Ñ Windows (%d)!"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr "Ðе удаетÑÑ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ñ‚ÑŒ файлы драйвера принтера CUPS (%d)!"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "Ðе удаетÑÑ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ñ‚ÑŒ PPD-файл – %s!"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "Ðе удаетÑÑ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ñ‚ÑŒ PPD-файл!"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr "Ðе удаетÑÑ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ñ‚ÑŒ файлы драйвера принтера Windows 2000 (%d)!"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr "Ðе удаетÑÑ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ñ‚ÑŒ файлы драйвера принтера Windows 9x (%d)!"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "Ðе удаетÑÑ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ñ‚ÑŒ Ñкрипт интерфейÑа – %s!"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "Ðе удаетÑÑ Ñоздать printer-uri!"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr "Ðевозможно редактировать файлы «cupsd.conf» больше 1 МБ!"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "Ðе удаетÑÑ Ð½Ð°Ð¹Ñ‚Ð¸ назначение Ð´Ð»Ñ Ð·Ð°Ð´Ð°Ð½Ð¸Ñ!"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "Ðе удаетÑÑ Ð½Ð°Ð¹Ñ‚Ð¸ принтер!\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr "Ðе удаетÑÑ ÑƒÑтановить файлы драйвера принтера Windows 2000 (%d)!"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr "Ðе удаетÑÑ ÑƒÑтановить файлы драйвера принтера Windows 9x (%d)!"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ документ %d в задании %d!"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "Ðе удаетÑÑ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð¸Ñ‚ÑŒ команду драйверу принтера!"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Ðе удаетÑÑ Ð½Ð°Ñтроить драйвер принтера Windows (%d)!"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "Ðе удаетÑÑ Ð¸Ñпользовать уÑтаревший драйвер клаÑÑа USB!\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° принтера (%s)!"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Ðеподдерживаемый набор Ñимволов «%s»!"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "Ðеподдерживаемое Ñжатие «%s»!"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "Ðеподдерживаемый атрибут ÑÐ¶Ð°Ñ‚Ð¸Ñ %s!"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "Ðеподдерживаемый формат «%s»!"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "Ðеподдерживаемый формат «%s»!"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "Ðеподдерживаемый формат «%s/%s»!"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "СинтакÑиÑ: convert [ options ]\n"
+#~ "\n"
+#~ "Параметры:\n"
+#~ "\n"
+#~ " -f filename УказываетÑÑ ÐºÐ¾Ð½Ð²ÐµÑ€Ñ‚Ð¸Ñ€ÑƒÐµÐ¼Ñ‹Ð¹ файл (в противном "
+#~ "Ñлучае stdin)\n"
+#~ " -o filename УказываетÑÑ Ñоздаваемый файл (в противном Ñлучае "
+#~ "stdout)\n"
+#~ " -i mime/type УказываетÑÑ MIME-тип данных на входе (в противном "
+#~ "Ñлучае auto-typed)\n"
+#~ " -j mime/type УказываетÑÑ MIME-тип данных на выходе (в противном "
+#~ "Ñлучае application/pdf)\n"
+#~ " -P filename.ppd УказываетÑÑ PPD-файл\n"
+#~ " -a 'name=value ...' УказываютÑÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ñ‹\n"
+#~ " -U username УказываетÑÑ Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð´Ð»Ñ Ð·Ð°Ð´Ð°Ð½Ð¸Ñ\n"
+#~ " -J title УказываетÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ðº\n"
+#~ " -c copies УказываетÑÑ ÐºÐ¾Ð»Ð¸Ñ‡ÐµÑтво копий\n"
+#~ " -u PPD-файл удалÑетÑÑ Ð¿Ð¾Ñле Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ‹\n"
+#~ " -D Файл, поÑтупивший на вход, удалÑетÑÑ Ð¿Ð¾Ñле "
+#~ "Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ‹\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "СинтакÑиÑ: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Параметры:\n"
+#~ "\n"
+#~ " -c cupsd.conf ИÑпользуетÑÑ Ñ„Ð°Ð¹Ð» cupsd.conf\n"
+#~ " -j job-id[,N] Из указанного Ð·Ð°Ð´Ð°Ð½Ð¸Ñ Ð²Ñ‹Ð±Ð¸Ñ€Ð°ÐµÑ‚ÑÑ Ñ„Ð°Ð¹Ð» N (по умолчанию "
+#~ "файл 1)\n"
+#~ " -n copies ЗадаетÑÑ ÐºÐ¾Ð»Ð¸Ñ‡ÐµÑтво копий\n"
+#~ " -o name=value ЗадаютÑÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ñ‹\n"
+#~ " -p filename.ppd ЗадаетÑÑ PPD-файл\n"
+#~ " -t title ЗадаетÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ðº\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "СинтакÑиÑ: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[."
+#~ "gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Параметры:\n"
+#~ "\n"
+#~ " -R root-directory ЗадаетÑÑ Ð°Ð»ÑŒÑ‚ÐµÑ€Ð½Ð°Ñ‚Ð¸Ð²Ð½Ñ‹Ð¹ корневой каталог\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " ВмеÑто ошибок выдаютÑÑ Ð¿Ñ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ\n"
+#~ " -q Команда выполнÑетÑÑ Ð² «тихом» режиме\n"
+#~ " -r ИÑпользуетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¹ режим\n"
+#~ " -v Режим более подробного отображениÑ\n"
+#~ " -vv Режим макÑимально подробного отображениÑ\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: Ðе удалоÑÑŒ прочитать Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð±Ð¾ÐºÐ¾Ð²Ð¾Ð³Ð¾ канала!\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr "WARNING: Параметр «%s» не может быть включен через IncludeFeature!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Удаленный хоÑÑ‚ не ответил байтом command-ÑтатуÑа поÑле %d "
+#~ "Ñекунд!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Удаленный хоÑÑ‚ не ответил байтом control-ÑтатуÑа поÑле %d "
+#~ "Ñекунд!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Удаленный хоÑÑ‚ не ответил байтом data-ÑтатуÑа поÑле %d Ñекунд!\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr "WARNING: Ð’Ñ€ÐµÐ¼Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ‹ SCSI иÑтекло (%d). Повтор попытки…\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: Этот документ не ÑоответÑтвует Adobe Document Structuring "
+#~ "Conventions и может быть напечатан неправильно!\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: ÐеизвеÑтный выбор «%s» Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° «%s»!\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: ÐеизвеÑтный параметр «%s»!\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: ÐÐµÐ¿Ð¾Ð´Ð´ÐµÑ€Ð¶Ð¸Ð²Ð°ÐµÐ¼Ð°Ñ ÑкороÑÑ‚ÑŒ передачи данных в бодах %s!\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: ВоÑÑтанавливаемо. ХоÑÑ‚ Ñети «%s» занÑÑ‚. Попытка будет повторена "
+#~ "через %d Ñек…\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr "Внимание! Ðет уÑтановленных драйверов принтера Windows 2000!"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: ÐеизвеÑтный параметр «%s»!\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: ÐеизвеÑтный параметр «-%c»!\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr "cupsd: Ожидаемое Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° конфигурации поÑле параметра «-c»!\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: Ðе удаетÑÑ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»Ð¸Ñ‚ÑŒ текущий каталог!\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: ÐеизвеÑтный аргумент «%s» – отмена!\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: ÐеизвеÑтный параметр «%c» – отмена!\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: ÐедопуÑтимый номер документа %d!\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: ÐедопуÑтимый ID Ð·Ð°Ð´Ð°Ð½Ð¸Ñ %d!\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: Только одно Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° может быть указано!\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter: Ðе удаетÑÑ Ñоздать временный файл: %s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "Ðтрибут job-printer-uri отÑутÑтвует!"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Ð˜Ð¼Ñ ÐºÐ»Ð°ÑÑа может Ñодержать только печатные Ñимволы!\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: ПоÑле параметра «-P» должен быть указан PPD!\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr ""
+#~ "lpadmin: ПоÑле параметра «-u» должен быть указан allow/deny:userlist!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: ПоÑле параметра «-r» должен быть указан клаÑÑ!\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: ПоÑле параметра «-c» должно быть указано Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа!\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: ПоÑле параметра «-D» должно идти опиÑание!\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: ПоÑле параметра «-v» должен быть указан URI уÑтройÑтва!\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: ПоÑле параметра «-I» должны быть указаны типы файлов!\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: ПоÑле параметра «-h» должно быть указано Ð¸Ð¼Ñ Ñ…Ð¾Ñта!\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: ПоÑле параметра «-i» должен быть указан интерфейÑ!\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: ПоÑле параметра «-L» должно быть указано меÑтоположение!\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: ПоÑле параметра «-m» должна быть указана модель!\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr ""
+#~ "lpadmin: ПоÑле параметра «-o» должно быть указано значение вида "
+#~ "name=value!\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: ПоÑле параметра «-p» должен быть указан принтер!\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: ПоÑле параметра «-d» должно быть указано Ð¸Ð¼Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð°!\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr ""
+#~ "lpadmin: ПоÑле параметра «-x» должен быть указан принтер или клаÑÑ!\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: Имена учаÑтников не обнаружены!\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Ð˜Ð¼Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð° может Ñодержать только печатные Ñимволы!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Ðе удаетÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸Ñ‚ÑŒ принтер к клаÑÑу:\n"
+#~ " Ðеобходимо Ñначала указать Ð¸Ð¼Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð°!\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin: Ðе удаетÑÑ Ñоздать временный файл – %s\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin: Ðе удаетÑÑ Ñоздать временный файл: %s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Ðе удаетÑÑ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ принтер из клаÑÑа:\n"
+#~ " Ðеобходимо Ñначала указать Ð¸Ð¼Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð°!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Ðе удаетÑÑ Ð½Ð°Ñтроить PPD-файл:\n"
+#~ " Ðеобходимо Ñначала указать Ð¸Ð¼Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð°!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Ðе удаетÑÑ Ð½Ð°Ñтроить URI уÑтройÑтва:\n"
+#~ " Ðеобходимо Ñначала указать Ð¸Ð¼Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð°!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Ðе удаетÑÑ Ð½Ð°Ñтроить Ñкрипт интерфейÑа или PPD-файл:\n"
+#~ " Ðеобходимо Ñначала указать Ð¸Ð¼Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð°!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Ðе удаетÑÑ Ð½Ð°Ñтроить Ñкрипт интерфейÑа:\n"
+#~ " Ðеобходимо Ñначала указать Ð¸Ð¼Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð°!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Ðе удаетÑÑ Ð½Ð°Ñтроить опиÑание принтера:\n"
+#~ " Ðеобходимо Ñначала указать Ð¸Ð¼Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð°!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Ðе удаетÑÑ Ð½Ð°Ñтроить размещение принтера:\n"
+#~ " Ðеобходимо Ñначала указать Ð¸Ð¼Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð°!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Ðе удаетÑÑ Ð½Ð°Ñтроить параметры принтера:\n"
+#~ " Ðеобходимо Ñначала указать Ð¸Ð¼Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð°!\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: ÐеизвеÑтный параметр allow/deny «%s»!\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: ÐеизвеÑтный аргумент «%s»!\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: ÐеизвеÑтный параметр «%c»!\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin: Внимание – ÑпиÑок типов контента пропущен!\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr "lpinfo: ПоÑле --device-id должна идти Ñтрока ID уÑтройÑтва 1284!\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: ПоÑле –language должен быть указан Ñзык!\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr ""
+#~ "lpinfo: ПоÑле --make-and-model должна быть указана марка и модель!\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo: ПоÑле –product должна идти Ñтрока продукта!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo: ПоÑле --exclude-schemes должен идти ÑпиÑок Ñхем!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo: ПоÑле --ixclude-schemes должен идти ÑпиÑок Ñхем!\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: ПоÑле –timeout должно быть указано Ð²Ñ€ÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ!\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: ÐеизвеÑтный аргумент «%s»!\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: ÐеизвеÑтный параметр «%c»!\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: ÐеизвеÑтный параметр «%s»!\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: ÐеизвеÑтный аргумент «%s»!\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: ÐеизвеÑтный параметр «%c»!\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: Ðет принтеров!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: Ðе удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ PPD-файл Ð´Ð»Ñ %s!\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: ÐеизвеÑтный принтер или клаÑÑ!\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr ""
+#~ "lppasswd: Только пользователь root может добавлÑÑ‚ÑŒ или удалÑÑ‚ÑŒ пароли!\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: Файл Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð·Ð°Ð½ÑÑ‚!\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: Файл Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð½Ðµ обновлен!\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: Пароль не подходит!\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: Пароль не подходит!\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: Ошибка – %s Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ ÑƒÐºÐ°Ð·Ñ‹Ð²Ð°ÐµÑ‚ неÑущеÑтвующее "
+#~ "назначение «%s»!\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-events не указаны!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "URI-Ð°Ð´Ñ€ÐµÑ notify-recipient-uri «%s» уже иÑпользуетÑÑ!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "URI-Ð°Ð´Ñ€ÐµÑ notify-recipient-uri «%s» иÑпользует неизвеÑтную Ñхему!"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d неверный!"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: ÐедопуÑтимое Ð¸Ð¼Ñ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Â«%s» в Ñтроке %d из %s.\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: ÐедопуÑтимое ключевое Ñлово ÑтатуÑа %s в Ñтроке %d из %s.\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr ""
+#~ "ppdc: Ð’ Ñтроке %d из %s обнаружено значение, не привÑзанное к параметру!\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc: Дубликат #po Ð´Ð»Ñ Ñ€ÐµÐ³Ð¸Ð¾Ð½Ð° %s в Ñтроке %d из %s!\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: Ð’ Ñтроке %d из %s должно быть определение фильтра!\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: Ð’ Ñтроке %d из %s должно быть Ð¸Ð¼Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ñ‹!\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: ПоÑле Font в Ñтроке %d из %s должен быть указан набор Ñимволов!\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: ПоÑле ColorModel в Ñтроке %d из %s должна быть указана Ñ†Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ "
+#~ "Ñхема!\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Ð”Ð»Ñ ColorModel в Ñтроке %d из %s должно быть указано проÑтранÑтво "
+#~ "цветов!\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Ð”Ð»Ñ ColorModel в Ñтроке %d из %s должно быть указано Ñжатие!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Ð”Ð»Ñ UIConstraints в Ñтроке %d из %s должна быть указана Ñтрока "
+#~ "ограничений!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: ПоÑле DriverType в Ñтроке %d из %s должно быть указано ключевое "
+#~ "Ñлово типа драйвера!\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: ПоÑле Duplex в Ñтроке %d из %s должен быть указан тип дуплекÑа!\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле Font в Ñтроке %d из %s должна быть указана кодировка!\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: ПоÑле #po %s в Ñтроке %d из %s должно быть указано Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°!\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Ð’ Ñтроке %d из %s должно быть указано Ð¸Ð¼Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ñ‹/текÑÑ‚!\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc: Ð’ Ñтроке %d из %s должно быть указано Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°!\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: Ð’ Ñтроке %d из %s должно быть целое чиÑло!\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле #po в Ñтроке %d из %s должен быть указан регион!\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле %s в Ñтроке %d из %s должно быть имÑ!\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле FileName в Ñтроке %d из %s должно быть имÑ!\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле Font в Ñтроке %d из %s должно быть имÑ!\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле Manufacturer в Ñтроке %d из %s должно быть имÑ!\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле MediaSize в Ñтроке %d из %s должно быть имÑ!\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле ModelName в Ñтроке %d из %s должно быть имÑ!\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле PCFileName в Ñтроке %d из %s должно быть имÑ!\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле %s в Ñтроке %d из %s должно быть имÑ/текÑÑ‚!\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле Installable в Ñтроке %d из %s должно быть имÑ/текÑÑ‚!\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле Resolution в Ñтроке %d из %s должно быть имÑ/текÑÑ‚!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле ColorModel в Ñтроке %d из %s должно быть имÑ/текÑÑ‚!\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Ð’ Ñтроке %d из %s должно быть указано Ð¸Ð¼Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°/текÑÑ‚!\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: Ð’ Ñтроке %d из %s должен быть раздел параметров!\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: Ð’ Ñтроке %d из %s должен быть указан тип параметра!\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: ПоÑле Resolution в Ñтроке %d из %s должно быть поле "
+#~ "переопределениÑ!\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: Ð’ Ñтроке %d из %s должно быть дейÑтвительное чиÑло!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: ПоÑле ColorProfile в Ñтроке %d из %s должно быть указано разрешение/"
+#~ "тип ноÑителÑ!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: ПоÑле SimpleColorProfile в Ñтроке %d из %s должно быть указано "
+#~ "разрешение/тип ноÑителÑ!\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле %s в Ñтроке %d из %s должен быть Ñелектор!\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле Font в Ñтроке %d из %s должен быть указан ÑтатуÑ!\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле Copyright в Ñтроке %d из %s должна быть Ñтрока!\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле Version в Ñтроке %d из %s должна быть Ñтрока!\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: Ð’ Ñтроке %d из %s должны быть два имени параметра!\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле %s в Ñтроке %d из %s должно быть значение!\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: ПоÑле Font в Ñтроке %d из %s должна быть указана верÑиÑ!\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: Ðеверное Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° #include/#po «%s»!\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Затраты на фильтр в Ñтроке %d из %s указаны неверно!\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr "ppdc: ÐедопуÑтимый пуÑтой MIME-тип Ð´Ð»Ñ Ñ„Ð¸Ð»ÑŒÑ‚Ñ€Ð° в Ñтроке %d из %s!\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: ÐедопуÑтимое пуÑтое Ð¸Ð¼Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ñ‹ Ð´Ð»Ñ Ñ„Ð¸Ð»ÑŒÑ‚Ñ€Ð° в Ñтроке %d из %s!\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ðеверный раздел параметров «%s» в Ñтроке %d из %s!\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ðеверный тип параметра «%s» в Ñтроке %d из %s!\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: ОтÑутÑтвует #endif в конце «%s»!\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: ОтÑутÑтвует #if в Ñтроке %d из %s!\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc: Ðе указан каталог Ñообщений Ð´Ð»Ñ Ñ€ÐµÐ³Ð¸Ð¾Ð½Ð° %s!\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr "ppdc: Ð”Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° %s определен другой тип в Ñтроке %d из %s!\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Ð”Ð»Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° должно быть указано *name в Ñтроке %d из %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: Слишком много вложенных операторов #if в Ñтроке %d из %s!\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: Ðе удаетÑÑ Ð½Ð°Ð¹Ñ‚Ð¸ файл #po %s в Ñтроке %d из %s!\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ðе удаетÑÑ Ð½Ð°Ð¹Ñ‚Ð¸ файл «%s» в Ñтроке %d из %s!\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: ÐеизвеÑтный тип драйвера %s в Ñтроке %d из %s!\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: ÐеизвеÑтный тип дуплекÑа «%s» в Ñтроке %d из %s!\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: ÐеизвеÑтный размер ноÑÐ¸Ñ‚ÐµÐ»Ñ Â«%s» в Ñтроке %d из %s!\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: ÐеизвеÑтный маркер «%s» в Ñтроке %d из %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: ÐеизвеÑтные конечные Ñимволы в вещеÑтвенном чиÑле «%s» в Ñтроке %d "
+#~ "из %s!\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr "ppdc: Ðе завершена Ñтрока, начинающаÑÑÑ Ñ %c в Ñтроке %d из %s!\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: Ðеверное значение LanguageVersion «%s» в %s!\n"
diff --git a/locale/cups_sv.po b/locale/cups_sv.po
new file mode 100644
index 000000000..ecee081e4
--- /dev/null
+++ b/locale/cups_sv.po
@@ -0,0 +1,7098 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-16 12:00-0800\n"
+"Last-Translator: Apple Inc.\n"
+"Language-Team: Apple Inc.\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(alla)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(ingen)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d poster\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tEfter fel: fortsätt\n"
+
+msgid "\tAlerts:"
+msgstr "\tVarningar:"
+
+msgid "\tBanner required\n"
+msgstr "\tBanner krävs\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\tTeckenkodningar:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\tAnslutning: direkt\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\tAnslutning: fjärr\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\tFörvalt pappersformat:\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\tStandardavstånd mellan bildpunkter:\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\tStandardportinställningar:\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tBeskrivning: %s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tAktiv skrivarmall:\n"
+"\tInnehållstyper: alla\n"
+"\tSkrivartyper: okänt\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tTillåtna format:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\tGränssnitt: %s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\tGränssnitt: %s/interfaces/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\tGränssnitt: %s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tPlats: %s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tVid fel: ingen varning\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tTillåtna användare:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tNekade användare:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tdemon närvarande\n"
+
+msgid "\tno entries\n"
+msgstr "\tinga poster\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\tskrivare finns pÃ¥ enheten â€%s†hastighet -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\tutskrifter är avaktiverade\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\tutskrifter är aktiverade\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\tköad för %s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tköläggning är avaktiverad\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\tköläggning är aktiverad\n"
+
+msgid "\treason unknown\n"
+msgstr "\tokänd anledning\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" DETALJERADE TESTRESULTAT\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " REF: Sida 15, sektion 3.1.\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " REF: Sida 15, sektion 3.2.\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " REF: Sida 19, sektion 3.3.\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " REF: Sida 20, sektion 3.4.\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " REF: Sida 27, sektion 3.5.\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " REF: Sida 42, sektion 5.2.\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " REF: Sidorna 16-17, sektion 3.2.\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " REF: Sidorna 42-45, sektion 5.2.\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " REF: Sidorna 45-46, sektion 5.2.\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " REF: Sidorna 48-49, sektion 5.2.\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " REF: Sidorna 52-54, sektion 5.2.\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f byte\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " OK Standard%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " OK DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " OK DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " OK FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " OK FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " OK LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " OK LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " OK Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " OK ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " OK NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " OK PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " OK PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " OK PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " OK PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " OK Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " OK ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" VARN \"%s %s\" är i konflikt med \"%s %s\"\n"
+" (begränsare=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" VARN %s delar ett vanligt prefix med %s\n"
+" REF: Sida 15, sektion 3.2.\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" VARN LanguageEncoding krävs av PPD 4.3-spec.\n"
+" REF: Sidorna 56-57, sektion 5.3.\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" VARN Manufacturer krävs av PPD 4.3-spec.\n"
+" REF: Sidorna 58-59, sektion 5.3.\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" VARN PCFileName längre än 8.3 i strid med PPD-spec.\n"
+" REF: Sidorna 61-62, sektion 5.3.\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" VARN Protokollen innehåller PJL men JCL-attributen är inte "
+"inställda.\n"
+" REF: Sidorna 78-79, sektion 5.7.\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" VARN Protokollen innehåller både PJL och BCP, förväntade TBCP.\n"
+" REF: Sidorna 78-79, sektion 5.7.\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" VARN ShortNickName krävs av PPD 4.3-spec.\n"
+" REF: Sidorna 64-65, sektion 5.3.\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s Felaktigt cupsFilter-värde \"%s\"\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s Saknad cupsPreFilter-fil \"%s\"\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FEL** FELAKTIG standard%s %s\n"
+" REF: Sida 40, sektion 4.5.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **FEL** FELAKTIGT JobPatchFile-attribut i fil\n"
+" REF: Sida 24, sektion 3.4.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FEL** FELAKTIG Manufacturer (ska vara \"HP\")\n"
+" REF: Sida 211, tabell D.1.\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **FEL** FELAKTIG Manufacturer (ska vara \"Oki\")\n"
+" REF: Sida 211, tabell D.1.\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FEL** FELAKTIG ModelName- \"%c\" tillåts inte i sträng.\n"
+" REF: Sidorna 59-60, sektion 5.3.\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FEL** FELAKTIG PSVersion - inte \"(string) int\".\n"
+" REF: Sidorna 62-64, sektion 5.3.\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FEL** FELAKTIG Product - inte \"(string)\".\n"
+" REF: Sida 62, sektion 5.3.\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **FEL** FELAKTIG ShortNickName - längre än 31 tecken.\n"
+" REF: Sidorna 64-65, sektion 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FEL** Felaktig FileVersion \"%s\"\n"
+" REF: Sida 56, sektion 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FEL** Felaktig FormatVersion \"%s\"\n"
+" REF: Sida 56, sektion 5.3.\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr " **FEL** Förvald alternativkod kan inte tolkas: %s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **FEL** Standard%s KRÄVS\n"
+" REF: Sida 40, sektion 4.5.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FEL** KRÄVER DefaultImageableArea\n"
+" REF: Sida 102, sektion 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FEL** KRÄVER DefaultPaperDimension\n"
+" REF: Sida 103, sektion 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FEL** KRÄVER FileVersion\n"
+" REF: Sida 56, sektion 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **FEL** KRÄVER FormatVersion\n"
+" REF: Sida 56, sektion 5.3.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **FEL** KRÄVER ImageableArea för PageSize %s\n"
+" REF: Sida 41, sektion 5.\n"
+" REF: Sida 102, sektion 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **FEL** KRÄVER LanguageEncoding\n"
+" REF: Sidorna 56-57, sektion 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **FEL** KRÄVER LanguageVersion\n"
+" REF: Sidorna 57-58, sektion 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **FEL** KRÄVER Manufacturer\n"
+" REF: Sidorna 58-59, sektion 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **FEL** KRÄVER ModelName\n"
+" REF: Sidorna 59-60, sektion 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **FEL** KRÄVER NickName\n"
+" REF: Sida 60, sektion 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **FEL** KRÄVER PCFileName\n"
+" REF: Sidorna 61-62, sektion 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **FEL** KRÄVER PSVersion\n"
+" REF: Sidorna 62-64, sektion 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **FEL** KRÄVER PageRegion\n"
+" REF: Sida 100, sektion 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **FEL** KRÄVER PageSize\n"
+" REF: Sida 41, sektion 5.\n"
+" REF: Sida 99, sektion 5.14.\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **FEL** KRÄVER PageSize\n"
+" REF: Sidorna 99-100, sektion 5.14.\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **FEL** KRÄVER PaperDimension för PageSize %s\n"
+" REF: Sida 41, sektion 5.\n"
+" REF: Sida 103, sektion 5.15.\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **FEL** KRÄVER Product\n"
+" REF: Sida 62, sektion 5.3.\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **FEL** KRÄVER ShortNickName\n"
+" REF: Sidorna 64-65, sektion 5.3.\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " %d FEL HITTADES\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " INGA FEL HITTADES\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " FEL\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" FEL\n"
+" **FEL** Kunde inte öppna PPD-fil - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" FEL\n"
+" **FEL** Kunde inte öppna PPD-fil - %s på rad %d.\n"
+
+msgid " PASS\n"
+msgstr " OK\n"
+
+msgid "#10 Envelope"
+msgstr "#10 Envelope"
+
+msgid "#11 Envelope"
+msgstr "#11 Envelope"
+
+msgid "#12 Envelope"
+msgstr "#12 Envelope"
+
+msgid "#14 Envelope"
+msgstr "#14 Envelope"
+
+msgid "#9 Envelope"
+msgstr "#9 Envelope"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f byte\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f byte\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f millimeter"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f to %.0f x %.0f millimeter"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f tum"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f to %.2f x %.2f tum"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s accepterar begäran sedan %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%s kan inte ändras."
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s är inte införd i CUPS-versionen av lpc.\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s är inte klar\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s är klar\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s är klar och skriver ut\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s accepterar inte begäran sedan %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s accepterar begäran sedan %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s accepterar inte begäran sedan %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s: %-33.33s [utskrift %d localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s: %s misslyckades: %s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s: Fel - inget standardmål tillgängligt.\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s: Fel - prioritet måste vara mellan 1 och 100.\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s: Fel - för många filer - \"%s\"\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s: Fel - kunde inte komma åt \"%s\" - %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s: Fel - kunde inte köa från standard in - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s: Filter \"%s\" inte tillgängligt: %s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s: Ogiltig filtersträng \"%s\"\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s: Åtgärd misslyckades: %s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s: Kunde inte ansluta till server\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s: Kan inte öppna %s: %s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s: Kan inte öppna PPD-fil: %s på rad %d\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s: Fel - inget standardmål tillgängligt.\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 tum/sek."
+
+msgid "1.25x0.25\""
+msgstr "1,25 x 0,25"
+
+msgid "1.25x2.25\""
+msgstr "1,25 x 2,25\""
+
+msgid "1.5 inch/sec."
+msgstr "1,5 tum/sek."
+
+msgid "1.50x0.25\""
+msgstr "1,50 x 0,25\""
+
+msgid "1.50x0.50\""
+msgstr "1,50 x 0,50"
+
+msgid "1.50x1.00\""
+msgstr "1,50 x 1,00\""
+
+msgid "1.50x2.00\""
+msgstr "1,50 x 2,00\""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 tum/sek."
+
+msgid "10 x 11\""
+msgstr "10 x 11\""
+
+msgid "10 x 13\""
+msgstr "10 x 13\""
+
+msgid "10 x 14\""
+msgstr "10 x 14\""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 mm/sek."
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 tum/sek."
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 tum/sek."
+
+msgid "12 x 11\""
+msgstr "12 x 11\""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 mm/sek."
+
+msgid "120x60dpi"
+msgstr "120 x 60 dpi"
+
+msgid "120x72dpi"
+msgstr "120 x 72 dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136 dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 mm/sek."
+
+msgid "15 x 11\""
+msgstr "15 x 11\""
+
+msgid "150 mm/sec."
+msgstr "150 mm/sek."
+
+msgid "150dpi"
+msgstr "150 dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180 dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 tum/sek."
+
+msgid "2-Sided Printing"
+msgstr "Dubbelsidig utskrift"
+
+msgid "2.00x0.37\""
+msgstr "2,00 x 0,37\""
+
+msgid "2.00x0.50\""
+msgstr "2,00 x 0,50\""
+
+msgid "2.00x1.00\""
+msgstr "2,00 x 1,00\""
+
+msgid "2.00x1.25\""
+msgstr "2,00 x 1,25\""
+
+msgid "2.00x2.00\""
+msgstr "2,00 x 2,00\""
+
+msgid "2.00x3.00\""
+msgstr "2,00 x 3,00\""
+
+msgid "2.00x4.00\""
+msgstr "2,00 x 4,00\""
+
+msgid "2.00x5.50\""
+msgstr "2,00 x 5,50\""
+
+msgid "2.25x0.50\""
+msgstr "2,25 x 0,50\""
+
+msgid "2.25x1.25\""
+msgstr "2,25 x 1,25\""
+
+msgid "2.25x4.00\""
+msgstr "2,25 x 4,00\""
+
+msgid "2.25x5.50\""
+msgstr "2,25 x 5,50\""
+
+msgid "2.38x5.50\""
+msgstr "2,38 x 5,50\""
+
+msgid "2.5 inches/sec."
+msgstr "2.5 tum/sek."
+
+msgid "2.50x1.00\""
+msgstr "2,50 x 1,00\""
+
+msgid "2.50x2.00\""
+msgstr "2,50 x 2,00\""
+
+msgid "2.75x1.25\""
+msgstr "2,75 x 1,25\""
+
+msgid "2.9 x 1\""
+msgstr "2,9 x 1\""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 mm/sek."
+
+msgid "200 mm/sec."
+msgstr "200 mm/sek."
+
+msgid "203dpi"
+msgstr "203 dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "Serier med 24 pin"
+
+msgid "240x72dpi"
+msgstr "240 x 72 dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 mm/sek."
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 tum/sek."
+
+msgid "3.00x1.00\""
+msgstr "3,00 x 1,00\""
+
+msgid "3.00x1.25\""
+msgstr "3,00 x 1,25\""
+
+msgid "3.00x2.00\""
+msgstr "3,00 x 2,00\""
+
+msgid "3.00x3.00\""
+msgstr "3,00 x 3,00\""
+
+msgid "3.00x5.00\""
+msgstr "3,00 x 5,00\""
+
+msgid "3.25x2.00\""
+msgstr "3,25 x 2,00\""
+
+msgid "3.25x5.00\""
+msgstr "3,25 x 5,00\""
+
+msgid "3.25x5.50\""
+msgstr "3,25 x 5,50\""
+
+msgid "3.25x5.83\""
+msgstr "3,25 x 5,83\""
+
+msgid "3.25x7.83\""
+msgstr "3,25 x 7,83\""
+
+msgid "3.5\" Disk"
+msgstr "3.5\" Disk"
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "3,5\" Disk - 2 1/8 x 2 3/4\""
+
+msgid "3.50x1.00\""
+msgstr "3,50 x 1,00\""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 mm/sek."
+
+msgid "300 mm/sec."
+msgstr "300 mm/sek."
+
+msgid "300dpi"
+msgstr "300 dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360 dpi"
+
+msgid "360x180dpi"
+msgstr "360 x 180 dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 tum/sek."
+
+msgid "4.00x1.00\""
+msgstr "4,00 x 1,00\""
+
+msgid "4.00x13.00\""
+msgstr "4,00 x 13,00\""
+
+msgid "4.00x2.00\""
+msgstr "4,00 x 2,00\""
+
+msgid "4.00x2.50\""
+msgstr "4,00 x 2,50\""
+
+msgid "4.00x3.00\""
+msgstr "4,00 x 3,00\""
+
+msgid "4.00x4.00\""
+msgstr "4,00 x 4,00\""
+
+msgid "4.00x5.00\""
+msgstr "4,00 x 5,00\""
+
+msgid "4.00x6.00\""
+msgstr "4,00 x 6,00\""
+
+msgid "4.00x6.50\""
+msgstr "4,00 x 6,50\""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 mm/sek."
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 tum/sek."
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 tum/sek."
+
+msgid "6.00x1.00\""
+msgstr "6,00 x 1,00\""
+
+msgid "6.00x2.00\""
+msgstr "6,00 x 2,00\""
+
+msgid "6.00x3.00\""
+msgstr "6,00 x 3,00\""
+
+msgid "6.00x4.00\""
+msgstr "6,00 x 4,00\""
+
+msgid "6.00x5.00\""
+msgstr "6,00 x 5,00\""
+
+msgid "6.00x6.00\""
+msgstr "6,00 x 6,00\""
+
+msgid "6.00x6.50\""
+msgstr "6,00 x 6,50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 mm/sek."
+
+msgid "600dpi"
+msgstr "600 dpi"
+
+msgid "60dpi"
+msgstr "60 dpi"
+
+msgid "60x720dpi"
+msgstr "60 x 720 dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 tum/sek."
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720 dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 tum/sek."
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8,00 x 1,00\""
+
+msgid "8.00x2.00\""
+msgstr "8,00 x 2,00\""
+
+msgid "8.00x3.00\""
+msgstr "8,00 x 3,00\""
+
+msgid "8.00x4.00\""
+msgstr "8,00 x 4,00\""
+
+msgid "8.00x5.00\""
+msgstr "8,00 x 5,00\""
+
+msgid "8.00x6.00\""
+msgstr "8,00 x 6,00\""
+
+msgid "8.00x6.50\""
+msgstr "8,00 x 6,50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 mm/sek."
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 tum/sek."
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "Serier med 9 pin"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?Ogiltigt hjälpkommando okänt\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3 (större)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4 (större)"
+
+msgid "A4 (Small)"
+msgstr "A4 (mindre)"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5 (större)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "Acceptera utskrifter"
+
+msgid "Accepted"
+msgstr "Accepterade"
+
+msgid "Add Class"
+msgstr "Lägg till klass"
+
+msgid "Add Printer"
+msgstr "Lägg till skrivare"
+
+msgid "Add RSS Subscription"
+msgstr "Lägg till RSS-prenumeration"
+
+msgid "Address"
+msgstr "Adress"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "Adress - 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "Administration"
+
+msgid "Always"
+msgstr "Alltid"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "Applikator"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "Felaktig NULL- destinationspekare"
+
+msgid "Bad OpenGroup"
+msgstr "Felaktig OpenGroup"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "Felaktig OpenUI/JCLOpenUI"
+
+msgid "Bad OrderDependency"
+msgstr "Felaktig OrderDependency"
+
+msgid "Bad Request"
+msgstr "Felaktig begäran"
+
+msgid "Bad SNMP version number"
+msgstr "Felaktigt SNMP-versionsnummer"
+
+msgid "Bad UIConstraints"
+msgstr "Felaktig UIConstraints"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "Felaktigt värde för exemplar %d."
+
+msgid "Bad custom parameter"
+msgstr "Felaktig anpassad parameter"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "Felaktigt teckensnittsattribut: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "Felaktigt värde för exemplar %d."
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "Felaktiga värden för sidintervall %d-%d."
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "Banners"
+
+msgid "Billing Information: "
+msgstr "Faktureringsinformation: "
+
+msgid "Bond Paper"
+msgstr "Fint papperr"
+
+msgid "C0 Envelope"
+msgstr "Kuvert C0"
+
+msgid "C1 Envelope"
+msgstr "Kuvert C1"
+
+msgid "C2 Envelope"
+msgstr "Kuvert C2"
+
+msgid "C3 Envelope"
+msgstr "Kuvert C3"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "Kuvert C4"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "Kuvert C5"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "Kuvert C6"
+
+msgid "C65 Envelope"
+msgstr "Kuvert C65"
+
+msgid "C7 Envelope"
+msgstr "Kuvert C7"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "Etikettskrivare CPCL"
+
+msgid "Cancel RSS Subscription"
+msgstr "Avbryt RSS-prenumeration"
+
+msgid "Change Settings"
+msgstr "Ändra inställningar"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Chou3-kuvert"
+
+msgid "Chou4 Envelope"
+msgstr "Chou4-kuvert"
+
+msgid "Classes"
+msgstr "Klasser"
+
+msgid "Clean Print Heads"
+msgstr "Rengör skrivarhuvuden"
+
+msgid "Color"
+msgstr "Färg"
+
+msgid "Color Mode"
+msgstr "Färgläge"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"Kommandon kan förkortas. Kommandon är:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "Gruppnamn använder obegränsad längd"
+
+msgid "Continue"
+msgstr "Fortsätt"
+
+msgid "Continuous"
+msgstr "Kontinuerlig"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "Skapad"
+
+msgid "Created On: "
+msgstr "Skapad den: "
+
+msgid "Custom"
+msgstr "Anpassad"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "Beskär"
+
+msgid "Cutter"
+msgstr "Beskärare"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "DL-kuvert"
+
+msgid "Dark"
+msgstr "Mörk"
+
+msgid "Darkness"
+msgstr "Mörkhet"
+
+msgid "Delete Class"
+msgstr "Ta bort klass"
+
+msgid "Delete Printer"
+msgstr "Ta bort skrivare"
+
+msgid "Description: "
+msgstr "Beskrivning: "
+
+msgid "DeskJet Series"
+msgstr "DeskJet-serier"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "MÃ¥l \"%s\" tar inte emot utskrifter."
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"Enhet: uri = %s\n"
+" klass = %s\n"
+" info = %s\n"
+" tillverkning-och-modell = %s\n"
+" enhets-id = %s\n"
+" plats = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "Termiska direktmedia"
+
+msgid "Disabled"
+msgstr "Avaktiverad"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "Dokument %d hittades inte i utskrift %d."
+
+msgid "Double Postcard"
+msgstr "Dubbelt vykort"
+
+msgid "Driver Name: "
+msgstr "Drivrutinnamn: "
+
+msgid "Driver Version: "
+msgstr "Drivrutinversion: "
+
+msgid "Duplexer"
+msgstr "Duplexr"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: Kunde inte tilldela minne för sidinfo: %s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: Kunde inte tilldela minne för sidordning: %s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "Etikettskrivare EPL1"
+
+msgid "EPL2 Label Printer"
+msgstr "Etikettskrivare EPL2"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: Felaktig teckenkodningsfil %s\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: Felaktig teckenkodningstyp %s\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: Felaktig typsnittsbeskrivning rad: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: Felaktig textriktning %s\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: Felaktig textbredd %s\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: Fel %d vid sändning av PAPSendData- begäran: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: Inga typsnitt i teckenkodningsfil %s\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: Skrivaren svarar inte\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: Skrivare skickade oväntat EOF\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: Fjärrvärden accepterade inte styrfilen (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: Fjärrvärden accepterade inte datafilen (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr "ERROR: Ett tidsgränsfel uppstod vid sändning av data till skrivare\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: Kunde inte lägga till filen %d i utskriften: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: Kunde inte avbryta utskriften %d: %s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: Kunde inte kopiera PDF-fil"
+
+msgid "ERROR: Unable to create pipe"
+msgstr ""
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: Kunde inte skapa sockel"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr "ERROR: Kunde inte skapa en temporär komprimerad utskriftsfil: %s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: Kunde inte skapa temporär fil"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: Kunde inte utföra pictwpstops: %s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: Kunde inte exekvera gs-program"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: Kunde inte exekvera pdftops-program"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: Kunde inte grena process: %s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: Kunde inte hämta PAP-förfrågan"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: Kunde inte hämta PAP-svar"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr "ERROR: Ingen PPD-fil för skrivaren \"%s\" - %s.\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: Kunde inte hämta förvald AppleTalk-zon"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: Kunde inte söka PAP-svar"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: Kunde inte söka AppleTalk-skrivare"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: Kunde inte göra AppleTalk-adress"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: Kunde inte öppna \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: Kunde inte öppna %s: %s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: Kunde inte öppna bannerfil \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: Kunde inte öppna enhetsfil \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: Kunde inte öppna fil \"%s\" - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: Kunde inte öppna fil \"%s\": %s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: Kunde inte öppna utskriftsfilen \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: Kunde inte öppna utskriftsfilen %s - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: Kunde inte öppna utskriftsfilen %s: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr "ERROR: Kunde inte öppna temporär komprimerad utskriftsfil: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: Kunde inte läsa utskriftsdata"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: Kunde inte reservera porten"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: Kunde inte skapa offset %ld i fil - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: Kunde inte skapa offset %lld i fil - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: Kunde inte skicka LPD-kommando"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: Kunde inte skicka PAP-tickle-förfrågan"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: Kunde inte skicka första PAP-send-data-förfrågan"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: Kunde inte skicka utskriftsfil till skrivare"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: Kunde inte skicka avslutande nullvärden till skrivare"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: Kunde inte vänta på pictwpstops: %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: Kunde inte skriva %d byte till \"%s\": %s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: Kunde inte skriva styrfil"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: Kunde inte skriva utskriftsdata"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: Kunde inte skriva utskriftsdata: %s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr "ERROR: Kunde inte skriva okomprimerade dokumentdata: %s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: Okänd filordning \"%s\"\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: Okänt formattecken \"%c\"\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: Okänt utskriftsläge \"%s\"\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: select() kunde inte utföras"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: kan inte få status för utskriftsfilen"
+
+msgid "Edit Configuration File"
+msgstr "Redigera konfigurationsfil"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "Slutbanner"
+
+msgid "English"
+msgstr "Swedish"
+
+msgid "Enter old password:"
+msgstr "Ange gammalt lösenord:"
+
+msgid "Enter password again:"
+msgstr "Ange lösenord igen:"
+
+msgid "Enter password:"
+msgstr "Ange lösenord:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"Ange ditt användarnamn och lösenord eller root-användarnamnet och lösenord "
+"för att komma åt denna sida. Om du använder Kerberos-autentisering, "
+"kontrollera att du har en giltig Kerberos-biljett."
+
+msgid "Envelope Feed"
+msgstr "Kuvertmatare"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "Felpolicy"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "Var tionde etikett"
+
+msgid "Every 2 Labels"
+msgstr "Varannan etikett"
+
+msgid "Every 3 Labels"
+msgstr "Var tredje etikett"
+
+msgid "Every 4 Labels"
+msgstr "Var fjärde etikett"
+
+msgid "Every 5 Labels"
+msgstr "Var femte etikett"
+
+msgid "Every 6 Labels"
+msgstr "Var sjätte etikett"
+
+msgid "Every 7 Labels"
+msgstr "Var sjunde etikett"
+
+msgid "Every 8 Labels"
+msgstr "Var åttonde etikett"
+
+msgid "Every 9 Labels"
+msgstr "Var nionde etikett"
+
+msgid "Every Label"
+msgstr "Alla etiketter"
+
+msgid "Expectation Failed"
+msgstr "Ej förväntad respons"
+
+msgid "Export Printers to Samba"
+msgstr "Exportera skrivare till Samba"
+
+msgid "FAIL\n"
+msgstr "FEL\n"
+
+msgid "File Folder"
+msgstr "Filmapp"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "Filmapp - 9/16 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"Filenhets URI:er har blivit avaktiverade! För att aktivera, se direktivet "
+"FileDevice i \"%s/cupsd.conf\"."
+
+msgid "Folio"
+msgstr "Folio"
+
+msgid "Forbidden"
+msgstr "Förbjudet"
+
+msgid "General"
+msgstr "Allmänt"
+
+msgid "Generic"
+msgstr "Generisk"
+
+msgid "German FanFold"
+msgstr "German FanFold"
+
+msgid "German FanFold Legal"
+msgstr "German FanFold Legal"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU använder obegränsad längd"
+
+msgid "Glossy Paper"
+msgstr "Blankt papper"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "Gråskala"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "Hängmapp"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "Hängmapp- 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk avaktiverat i Systeminställningar\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk avaktiverat i Systeminställningar.\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: Avbryter utskrift...\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: Ansluten till skrivare...\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: Ansluter till skrivare...\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: Styrfil har skickats\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr ""
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: Datafil har skickats\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: Formaterar sidan %d...\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: Läser in bildfil...\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: Söker skrivare...\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: Öppnar anslutning\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr "INFO: Utskriftsfil skickad, väntar på skrivaren...\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: Skrivaren är upptagen, försöker igen om 10 sekunder...\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: Skrivaren är upptagen, försöker igen om 30 sekunder...\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: Skrivaren är upptagen, försöker igen om 5 sekunder...\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr "INFO: Skrivaren stöder inte IPP/%d.%d, försöker med IPP/1.0...\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: Skrivaren är upptagen, försöker igen om 5 sekunder...\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: Skrivaren är frånkopplad just nu.\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: Skrivaren är frånkopplad just nu.\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: Skrivaren är online nu.\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: Skrivaren är frånkopplad.\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: Skrivaren är inte ansluten, försöker igen om 30 sekunder...\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: Skriver ut sidan %d, %d %% klart...\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: Skriver ut sidan %d...\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: Klar för utskrifter.\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: Skickar styrfil (%lu byte)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: Skickar styrfil (%u byte)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: Skickar data\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: Skickar datafil (%ld byte)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: Skickar datafil (%lld byte)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: Skickar utskriftsdata...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: Skickar utskriftsfil, %ld byte...\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: Skickar utskriftsfil, %lld byte...\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: Buffrar LPR-utskrift, %.0f %% klart...\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr ""
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr ""
+"INFO: Kan inte kontakta skrivaren, köar för nästa skrivare i klassen...\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: Använder förvald AppleTalk-zon \"%s\"\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: Väntar på att utskrift ska bli klar...\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: Väntar på att skrivaren ska bli tillgänglig...\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "Kuvert ISO B4"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5 (större)"
+
+msgid "ISO B5 Envelope"
+msgstr "Kuvert ISO B5"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "Kuvert ISO B6"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "Otillåtet styrtecken"
+
+msgid "Illegal main keyword string"
+msgstr "Otillåten huvudnyckelordssträng"
+
+msgid "Illegal option keyword string"
+msgstr "Otillåten alternativnyckelordssträng"
+
+msgid "Illegal translation string"
+msgstr "Otillåten översättningssträng"
+
+msgid "Illegal whitespace character"
+msgstr "Otillåtet blanktecken"
+
+msgid "Installable Options"
+msgstr "Installerbara alternativ"
+
+msgid "Installed"
+msgstr "Installerad"
+
+msgid "IntelliBar Label Printer"
+msgstr "Eikettskrivare från IntelliBar"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr ""
+
+msgid "Internal error"
+msgstr "Internt fel"
+
+msgid "Internet Postage 2-Part"
+msgstr "Internet Postage 2-Part"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "Internet Postage 3-Part"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Internet Postage 3-Part - 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "Internet Printing Protocol"
+
+msgid "Invite Envelope"
+msgstr "Invite-kuvert"
+
+msgid "Italian Envelope"
+msgstr "Italienskt kuvert"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "Utskrift #%d är redan avbruten - kan inte avbryta."
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "Utskrift #%d är redan avbruten - kan inte avbryta."
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "Utskrift #%d är redan klar - kan inte avbryta."
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "Utskriften är klar"
+
+msgid "Job Created"
+msgstr "Utskrift skapad"
+
+msgid "Job ID: "
+msgstr "Uskrifts-ID: "
+
+msgid "Job Options Changed"
+msgstr "Utskriftsalternativ ändrades"
+
+msgid "Job Stopped"
+msgstr "Utskriften har stoppats"
+
+msgid "Job UUID: "
+msgstr "Utskriftens UUID: "
+
+msgid "Job is completed and cannot be changed."
+msgstr "Utskriften är klar och kan inte ändras."
+
+msgid "Job operation failed:"
+msgstr "Utskriftsåtgärd misslyckades:"
+
+msgid "Job state cannot be changed."
+msgstr "Utskriftsstatus kan inte ändras."
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "Utskrifter"
+
+msgid "Kaku2 Envelope"
+msgstr "Kaku2-kuvert"
+
+msgid "Kaku3 Envelope"
+msgstr "Kaku3-kuvert"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "LPD/LPR-värd eller skrivare"
+
+msgid "Label Printer"
+msgstr "Etikettskrivare"
+
+msgid "Label Top"
+msgstr "Etikettens överdel"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "Large Address"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "Large Address - 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet Series PCL 4/5"
+
+msgid "Light"
+msgstr "Lätt"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "Rad överskrider maxlängd (255 tecken)"
+
+msgid "List Available Printers"
+msgstr "Senast tillgängliga skrivare"
+
+msgid "Location: "
+msgstr "Plats: "
+
+msgid "Long-Edge (Portrait)"
+msgstr "Långsida (porträtt)"
+
+msgid "Make and Model: "
+msgstr "Tillverkning och modell: "
+
+msgid "Manual Feed"
+msgstr "Manuell matning"
+
+msgid "Media Dimensions: "
+msgstr "Mediemått: "
+
+msgid "Media Limits: "
+msgstr "Mediegränser: "
+
+msgid "Media Name: "
+msgstr "Medienamn: "
+
+msgid "Media Size"
+msgstr "Mediestorlek"
+
+msgid "Media Source"
+msgstr "Mediekälla"
+
+msgid "Media Tracking"
+msgstr "Mediespårning"
+
+msgid "Media Type"
+msgstr "Medietyp"
+
+msgid "Medium"
+msgstr "Medium"
+
+msgid "Memory allocation error"
+msgstr "Minnestilldelningsfel"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "Saknar PPD-Adobe-4.x-huvud"
+
+msgid "Missing asterisk in column 1"
+msgstr "Saknar asterisk i kolumn 1"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "Saknar värdesträng"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"Modell: namn = %s\n"
+" natural_language = %s\n"
+" tillverkare-och-modell = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "Ändra klass"
+
+msgid "Modify Printer"
+msgstr "Ändra skrivare"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Monarch-kuvert"
+
+msgid "Move All Jobs"
+msgstr "Flytta alla utskrifter"
+
+msgid "Move Job"
+msgstr "Flytta utskrift"
+
+msgid "Moved Permanently"
+msgstr "Flyttad permanent"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: Utskriftsfil accepterad - utskrifts-ID %d.\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: Utskriftsfil accepterad - utskrifts-ID okänt.\n"
+
+msgid "NULL PPD file pointer"
+msgstr "NULL PPD-filspekare"
+
+msgid "Name OID uses indefinite length"
+msgstr "OID-namn använder obegränsad längd"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "Aldrig"
+
+msgid "New Stylus Color Series"
+msgstr "Nya Stylus Color-serier"
+
+msgid "New Stylus Photo Series"
+msgstr "Nya Stylus Photo-serier"
+
+msgid "No"
+msgstr "Nej"
+
+msgid "No Content"
+msgstr "Inget innehåll"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "Ingen VarBind SEQUENCE"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "Ingen aktiv anslutning"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "Inget gruppnamn"
+
+msgid "No default printer"
+msgstr "Ingen förvald skrivare"
+
+msgid "No destinations added."
+msgstr "Inga mål tillagda."
+
+msgid "No error-index"
+msgstr "Inget felindex"
+
+msgid "No error-status"
+msgstr "Ingen felstatus"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "Inget OID-namn"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "Inget order-ID"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "Inga prenumerationer hittades."
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "Ingen variable-bindings SEQUENCE"
+
+msgid "No version number"
+msgstr "Inget versionsnummer"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "Non-continuous (Mark sensing)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "Non-continuous (Web sensing)"
+
+msgid "Normal"
+msgstr "Normal"
+
+msgid "Not Found"
+msgstr "Hittades inte"
+
+msgid "Not Implemented"
+msgstr "Inte implementerad"
+
+msgid "Not Installed"
+msgstr "Inte installerad"
+
+msgid "Not Modified"
+msgstr "Inte ändrad"
+
+msgid "Not Supported"
+msgstr "Stöds inte"
+
+msgid "Not allowed to print."
+msgstr "Ingen förvald skrivare."
+
+msgid "Note"
+msgstr "Anm"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Off (1-Sided)"
+msgstr "Av (1-sidig)"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "Hjälp på webben"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "Kunde inte öppna %s: %s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup utan en CloseGroup först"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI utan en CloseUI/JCLCloseUI först"
+
+msgid "Operation Policy"
+msgstr "Åtgärdspolicy"
+
+msgid "Options Installed"
+msgstr "Alternativ installerade"
+
+msgid "Options: "
+msgstr "Alternativ: "
+
+msgid "Output Mode"
+msgstr "Utmatningsläge"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "Utmatning för skrivaren %s skickas till %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr "Utmatning för skrivaren %s skickas till fjärrskrivaren %s på %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "Utmatning för skrivaren %s/%s skickas till %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr "Utmatning för skrivaren %s/%s skickas till fjärrskrivaren %s på %s\n"
+
+msgid "PASS\n"
+msgstr "OK\n"
+
+msgid "PCL Laser Printer"
+msgstr "Laserskrivare PCL"
+
+msgid "PRC1 Envelope"
+msgstr "Kuvert PRC1"
+
+msgid "PRC10 Envelope"
+msgstr "Kuvert PRC10"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "Kuvert PRC2"
+
+msgid "PRC3 Envelope"
+msgstr "Kuvert PRC3"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K (större)"
+
+msgid "PRC4 Envelope"
+msgstr "Kuvert PRC4"
+
+msgid "PRC5 Envelope"
+msgstr "Kuvert PRC5"
+
+msgid "PRC6 Envelope"
+msgstr "Kuvert PRC6"
+
+msgid "PRC7 Envelope"
+msgstr "Kuvert PRC7"
+
+msgid "PRC8 Envelope"
+msgstr "Kuvert PRC8"
+
+msgid "PRC9 Envelope"
+msgstr "Kuvert PRC9"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "Paket innehåller inte Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "Paket börjar inte med SEQUENCE"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "Lösenord för %s på %s? "
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "Lösenord för %s krävs för att nå %s via SAMBA: "
+
+msgid "Pause Class"
+msgstr "Pausa klass"
+
+msgid "Pause Printer"
+msgstr "Pausa skrivare"
+
+msgid "Peel-Off"
+msgstr "Peel-Off"
+
+msgid "Personal Envelope"
+msgstr "Personligt kuvert"
+
+msgid "Photo"
+msgstr "Foto"
+
+msgid "Photo Labels"
+msgstr "Fotoetiketter"
+
+msgid "Plain Paper"
+msgstr "Vanligt papper"
+
+msgid "Policies"
+msgstr "Policier"
+
+msgid "Port Monitor"
+msgstr "Portövervakare"
+
+msgid "PostScript Printer"
+msgstr "PostScript-skrivare"
+
+msgid "Postcard"
+msgstr "Vykort"
+
+msgid "Print Density"
+msgstr "Svärta"
+
+msgid "Print Job:"
+msgstr "Utskrift:"
+
+msgid "Print Mode"
+msgstr "Utskriftsläge"
+
+msgid "Print Rate"
+msgstr "Utskriftshastighet"
+
+msgid "Print Self-Test Page"
+msgstr "Skriv ut självtestsida"
+
+msgid "Print Speed"
+msgstr "Utskriftshastighet"
+
+msgid "Print Test Page"
+msgstr "Skriv ut testsida"
+
+msgid "Print and Cut"
+msgstr "Skriv ut och beskär"
+
+msgid "Print and Tear"
+msgstr "Skriv ut riv"
+
+msgid "Printed For: "
+msgstr "Utskriven för: "
+
+msgid "Printed From: "
+msgstr "Utskriven från: "
+
+msgid "Printed On: "
+msgstr "Utskriven den: "
+
+msgid "Printer Added"
+msgstr "Skrivare tillagd"
+
+msgid "Printer Default"
+msgstr "Skrivarstandard"
+
+msgid "Printer Deleted"
+msgstr "Skrivare borttagen"
+
+msgid "Printer Modified"
+msgstr "Skrivare ändrad"
+
+msgid "Printer Name: "
+msgstr "Skrivarnamn: "
+
+msgid "Printer Paused"
+msgstr "Utskrift pausad"
+
+msgid "Printer Settings"
+msgstr "Skrivarinställningar"
+
+msgid "Printer:"
+msgstr "Skrivare:"
+
+msgid "Printers"
+msgstr "Skrivare"
+
+msgid "Purge Jobs"
+msgstr "Rensa utskrifter"
+
+msgid "Quarto"
+msgstr "Kvartsark"
+
+msgid "Quota limit reached."
+msgstr "Kvotgräns nådd."
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr ""
+"Prioritet Ägare Utskrift Fil(er) Total "
+"storlek\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"Prioritet Ägare Utskrift Filer Total "
+"storlek\n"
+
+msgid "Reject Jobs"
+msgstr "Neka utskrifter"
+
+msgid "Reprint After Error"
+msgstr "Skriv ut igen efter fel"
+
+msgid "Request Entity Too Large"
+msgstr "Enheten är för stor"
+
+msgid "Resolution"
+msgstr "Upplösning"
+
+msgid "Resume Class"
+msgstr "Ã…teruppta klass"
+
+msgid "Resume Printer"
+msgstr "Ã…teruppta skrivare"
+
+msgid "Return Address"
+msgstr "Returadress"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "Returadress- 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "Bakåt"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "Kör kommando: %s %s -N -A %s -c â€%sâ€\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE använder obegränsad längd"
+
+msgid "See Other"
+msgstr "Visa andra"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "Serieport #%d"
+
+msgid "Server Restarted"
+msgstr "Servern har startats om"
+
+msgid "Server Security Auditing"
+msgstr "Säkerhetskontroll av servern"
+
+msgid "Server Started"
+msgstr "Servern har startat"
+
+msgid "Server Stopped"
+msgstr "Servern har stoppats"
+
+msgid "Service Unavailable"
+msgstr "Tjänst otillgänglig"
+
+msgid "Set Allowed Users"
+msgstr "Ställ in tillåtna användare"
+
+msgid "Set As Server Default"
+msgstr "Ställ in som serverförval"
+
+msgid "Set Class Options"
+msgstr "Ställ in klassalternativ"
+
+msgid "Set Printer Options"
+msgstr "Ställ in skrivaralternativ"
+
+msgid "Set Publishing"
+msgstr "Ställ in publicering"
+
+msgid "Shipping Address"
+msgstr "Leveransadress"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "Leveransadress - 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "Kortsida (landskap)"
+
+msgid "Special Paper"
+msgstr "Specialpapper"
+
+msgid "Standard"
+msgstr "Standard"
+
+msgid "Starting Banner"
+msgstr "Startbanner"
+
+msgid "Statement"
+msgstr "Utsaga"
+
+msgid "Stylus Color Series"
+msgstr "Stylus Color-serier"
+
+msgid "Stylus Photo Series"
+msgstr "Stylus Photo-serier"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "Byter protokoll"
+
+msgid "Tabloid"
+msgstr "Tabloid"
+
+msgid "Tabloid (Oversize)"
+msgstr "Tabloid (större)"
+
+msgid "Tear"
+msgstr "Riv"
+
+msgid "Tear-Off"
+msgstr "Riv-av"
+
+msgid "Tear-Off Adjust Position"
+msgstr "Justeringsposition för avrivning"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "PPD-filen \"%s\" hittades inte."
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "PPD-filen \"%s\" kunde inte öppnas: %s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Klassnamnet får endast innehålla upp till 127 skrivbara tecken och får inte "
+"innehålla blanksteg, snedstreck (/) eller fyrkantstecknet (#)."
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr ""
+"Attributet notify-lease-duration kan inte användas med "
+"utskriftsprenumerationer."
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"Skrivarnamnet får endast innehålla upp till 127 skrivbara tecken och får "
+"inte innehålla blanksteg, snedstreck (/) eller fyrkantstecknet (#)."
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "Skrivaren eller klassen hittades inte."
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "Printer-uri \"%s\" innehåller ogiltiga tecken."
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr ""
+"Printer-uri måste vara i formatet \"ipp://VÄRDNAMN/classes/KLASSNAMN\"."
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr ""
+"Printer-uri måste vara i formatet \"ipp://VÄRDNAMN/printers/SKRIVARNAMN\"."
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr ""
+"&quot;Klassnamnet får endast innehålla upp till 127 skrivbara tecken och får "
+"inte innehålla blanksteg, snedstreck (/), frågetecken (?) eller "
+"fyrkantstecknet (#)."
+
+msgid "There are too many subscriptions."
+msgstr "Det finns för många prenumerationer."
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "Termiska överföringsmedia"
+
+msgid "Title: "
+msgstr "Titel: "
+
+msgid "Too many active jobs."
+msgstr "För många aktiva utskrifter."
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "Genomskinlighet"
+
+msgid "Tray"
+msgstr "Fack"
+
+msgid "Tray 1"
+msgstr "Fack 1"
+
+msgid "Tray 2"
+msgstr "Fack 2"
+
+msgid "Tray 3"
+msgstr "Fack 3"
+
+msgid "Tray 4"
+msgstr "Fack 4"
+
+msgid "URI Too Long"
+msgstr "För lång URI"
+
+msgid "US Executive"
+msgstr "US Executive"
+
+msgid "US Fanfold"
+msgstr "US Fanfold"
+
+msgid "US Ledger"
+msgstr "US Ledger"
+
+msgid "US Legal"
+msgstr "US Legal"
+
+msgid "US Legal (Oversize)"
+msgstr "US Legal (större)"
+
+msgid "US Letter"
+msgstr "US Letter"
+
+msgid "US Letter (Oversize)"
+msgstr "US Letter (större)"
+
+msgid "US Letter (Small)"
+msgstr "US Letter (mindre)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "USB-serieport #%d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "Kunde inte nå filen cupsd.conf:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "Kunde inte lägga till RSS-prenumeration:"
+
+msgid "Unable to add class:"
+msgstr "Kunde inte lägga till klass:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "Kunde inte lägga till skrivare:"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "Kunde inte avbryta RSS-prenumeration:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "Kunde inte ändra attributet printer-is-shared:"
+
+msgid "Unable to change printer:"
+msgstr "Kunde inte ändra skrivare:"
+
+msgid "Unable to change server settings:"
+msgstr "Kunde inte ändra serverinställningar:"
+
+msgid "Unable to connect to host."
+msgstr "Kunde inte ansluta till värd."
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "Kunde inte skapa temporär fil:"
+
+msgid "Unable to delete class:"
+msgstr "Kunde inte ta bort klass:"
+
+msgid "Unable to delete printer:"
+msgstr "Kunde inte ta bort skrivare:"
+
+msgid "Unable to do maintenance command:"
+msgstr "Kunde inte utföra underhållskommando:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "Kunde inte hämta klasslista:"
+
+msgid "Unable to get class status:"
+msgstr "Kunde inte hämta klasstatus:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "Kunde inte hämta listan med skrivardrivrutiner:"
+
+msgid "Unable to get printer attributes:"
+msgstr "Kunde inte hämta skrivarattribut:"
+
+msgid "Unable to get printer list:"
+msgstr "Kunde inte hämta skrivarlista:"
+
+msgid "Unable to get printer status:"
+msgstr "Kunde inte hämta skrivarstatus:"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "Kunde inte ändra klass:"
+
+msgid "Unable to modify printer:"
+msgstr "Kunde inte ändra skrivare:"
+
+msgid "Unable to move job"
+msgstr "Kunde inte flytta utskrift"
+
+msgid "Unable to move jobs"
+msgstr "Kunde inte flytta utskrifter"
+
+msgid "Unable to open PPD file"
+msgstr "Kunde inte öppna PPD-fil"
+
+msgid "Unable to open PPD file:"
+msgstr "Kunde inte öppna PPD-fil:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "Kunde inte öppna filen cupsd.conf:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "Kunde inte skriva ut testsida:"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "Kunde inte köra \"%s\": %s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "Kunde inte ställa in alternativ:"
+
+msgid "Unable to set server default:"
+msgstr "Kunde inte ställa in serverstandard:"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "Kunde inte skicka upp filen cupsd.conf:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "Ej auktoriserad"
+
+msgid "Units"
+msgstr "Enheter"
+
+msgid "Unknown"
+msgstr "Okänd"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "Okänd printer-error-policy \"%s\"."
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "Okänd printer-op-policy \"%s\"."
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "Ogiltig värdetyp"
+
+msgid "Upgrade Required"
+msgstr "Uppgradering krävs"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Användning:\n"
+"\n"
+" lpadmin [-h server] -d mål\n"
+" lpadmin [-h server] -x mål\n"
+" lpadmin [-h server] -p skrivare [-c lägg-till-klass] [-i gränssnitt] [-m "
+"modell]\n"
+" [-r radera-klass] [-v enhet] [-D beskrivning]\n"
+" [-P ppd-fil] [-o name=value]\n"
+" [-u tillåt:användare,användare] [-u neka:användare,"
+"användare]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "Användning: %s job user title copies options [filename]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "Användning: %s job-id user title copies options [file]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "Användning: %s job-id user title copies options file\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Användning: cupsaddsmb [alternativ] printer1 ... printerN\n"
+" cupsaddsmb [alternativ] -a\n"
+"\n"
+"Alternativ:\n"
+" -E Kryptera anslutningen till servernr\n"
+" -H samba-server Använd den som heter SAMBA server\n"
+" -U samba-användare Autentisera med den som heter SAMBA användare \n"
+" -a Exportera alla skrivare\n"
+" -h cups-server Använd den som heter CUPS server\n"
+" -v Visa utförligt (visa kommandon)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Användning: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Alternativ:\n"
+"\n"
+" -E Aktivera kryptering\n"
+" -U username Ange användarnamn\n"
+" -h server[:port] Ange serveradress\n"
+"\n"
+" --[no-]debug-logging Slå av/på loggning vid felsökning\n"
+" --[no-]remote-admin Slå av/på fjärradministrering\n"
+" --[no-]remote-any Tillåt/förhindra åtkomst från Internet\n"
+" --[no-]remote-printers Visa/göm fjärrskrivare\n"
+" --[no-]share-printers Slå av/på skrivardelning\n"
+" --[no-]user-cancel-any Tillåt/förhindra att användare kan avbryta "
+"utskrifter\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Användning: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Läs upp alternativ konfigurationsfil\n"
+"-f Kör i förgrunden\n"
+"-F Kör i förgrunden men koppla bort\n"
+"-h Visa det här användningsmeddelandet\n"
+"-l Kör cupsd från launchd(8)\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Användning: cupstestdsc [alternativ] filnamn.ps [... filnamn.ps]\n"
+" cupstestdsc [alternativ] -\n"
+"\n"
+"Alternativ:\n"
+"\n"
+" -h Visa programanvändning\n"
+"\n"
+" Obs: det här programmet verifierar DSC-kommentarer, men inte "
+"PostScript.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Användning: lpmove job/src dest\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Användning: lpoptions [-h server] [-E] -d skrivare\n"
+" lpoptions [-h server] [-E] [-p skrivare] -l\n"
+" lpoptions [-h server] [-E] -p skrivare -o alternativ[=value] ...\n"
+" lpoptions [-h server] [-E] -x skrivare\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Användning: lppasswd [-g gruppnamn]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Användning: lppasswd [-g gruppnamn] [användarnamn]\n"
+" lppasswd [-g gruppnamn] -a [användarnamn]\n"
+" lppasswd [-g gruppnamn] -x [användarnamn]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Användning: lpq [-P dest] [-U användarnamn] [-h värdnamn[:port]] [-l] "
+"[+interval]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Användning: ppdc [alternativ] filnamn.drv [ ... filnamnN.drv ]\n"
+"Alternativ:\n"
+" -D name=value Ange namngiven variabel till värde.\n"
+" -I include-dir Lägg till inkluderingsfiler till sökväg.\n"
+" -c catalog.po Läs upp angiven meddelandekatalog.\n"
+" -d output-dir Ange utdatakatalog.\n"
+" -l lang[,lang,...] Ange språk för utdata (språkversion).\n"
+" -m Använd värdet för modellnamn som filnamn.\n"
+" -t Testa PPD-filer istället för att skapa fler.\n"
+" -v Visa utförligt (ju fler v:n desto mer detaljerat).\n"
+" -z Komprimera PPD-filer med GNU zip.\n"
+" --cr Avsluta rader med CR (Mac OS 9).\n"
+" --crlf Avsluta rader med CR + LF (Windows).\n"
+" --lf Avsluta rader med LF (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"Användning: ppdhtml [alternativ] filnamn.drv >filnamn.html\n"
+" -D name=value Ange namngiven variabel till värde.\n"
+"Alternativ:\n"
+" -I include-dir Lägg till inkluderingsfiler till sökväg.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Användning: ppdi [alternativ] filnamn.ppd [ ... filnamnN.ppd ]\n"
+"Alternativ:\n"
+" -I include-dir\n"
+" -o filnamn.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Användning: ppdmerge [alternativ] filnamn.ppd [ ... filnamnN.ppd ]\n"
+"Alternativ:\n"
+" -o filnamn.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"Användning: ppdpo [alternativ] -o filnamn.po filnamn.drv [ ... filnamnN."
+"drv ]\n"
+"Alternativ:\n"
+" -D name=value Ange namngiven variabel till värde.\n"
+" -I include-dir Lägg till inkluderingsfiler till sökväg.\n"
+" -v Visa utförligt (ju fler v:n desto mer detaljerat).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Användning: snmp [host-or-ip-address]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Värde använder obegränsad längd"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind använder obegränsad längd"
+
+msgid "Version uses indefinite length"
+msgstr "Version använder obegränsad längd"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: Lägger endast till de första %d som hittas"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: Boolesk förväntat för alternativet waiteof \"%s\"\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: Skrivaren svarar inte\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: Skrivare skickade oväntat EOF\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: Kunde inte öppna \"%s:%s\": %s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: Kunde inte skicka begäran för PAP-status"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: Oväntat PAP-paket av typen %d\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: Okänt PAP-paket av typen %d\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: siffra förväntad för statusalternativ \"%s\"\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "Ja"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"Du måste öppna sidan med url:en <A HREF=\"https://%s:%d%s\">https://%s:%d%s</"
+"A>."
+
+msgid "You4 Envelope"
+msgstr "You4-kuvert"
+
+msgid "ZPL Label Printer"
+msgstr "Etikettskrivare ZPL"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "stoppad"
+
+msgid "canceled"
+msgstr "stoppad"
+
+msgid "completed"
+msgstr "klar"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr ""
+"konvertera: Använd alternativet -f till att ange den fil som ska "
+"konverteras.\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "cups-deviced misslyckades med att starta."
+
+msgid "cups-driverd failed to execute."
+msgstr "cups-driverd misslyckades med att starta."
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb: Ingen PPD-fil för skrivaren \"%s\" - %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl: Kunde inte ansluta till server: %s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr "cupsd: Stöd för launchd(8) inte inbyggt, kör i normalt läge.\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter: Kunde inte hämta utskriftsfil - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr ""
+"cupstestppd: Alternativet -q är inte kompatibelt med alternativet -v.\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr ""
+"cupstestppd: Alternativet -v är inte kompatibelt med alternativet -q.\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "enhet för %s/%s: %s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "enhet för %s: %s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "felindex använder obegränsad längd"
+
+msgid "error-status uses indefinite length"
+msgstr "felstatus använder obegränsad längd"
+
+msgid "held"
+msgstr "hålls kvar"
+
+msgid "help\t\tget help on commands\n"
+msgstr "help\t\tfå hjälp om kommandon\n"
+
+msgid "idle"
+msgstr "overksam"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: Skrivaren %s är redan medlem av klassen %s.\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: Skrivaren %s är inte en medlem av klassen %s.\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: Kunde inte ansluta till server: %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: Kunde inte öppna PPD-fil \"%s\" - %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: Kunde inte öppna filen \"%s\": %s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove: Kunde inte ansluta till server: %s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions: Kunde inte lägga till skrivare eller instans: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions: Kunde inte hämta PPD-fil för %s: %s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: Tyvärr, lösenord stämmer inte.\n"
+"Lösenordet måste vara minst 6 tecken långt, får inte innehålla\n"
+"ditt användarnamn, och måste innehålla åtminstone en bokstav och siffra.\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: Kunde inte kopiera lösenordssträng: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: Kunde inte öppna lösenordsfil: %s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: Kunde inte skriva till lösenordsfil: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr ""
+"lppasswd: misslyckades med att säkerhetskopiera gamla lösenordsfilen: %s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: misslyckades med att byta namn på lösenordsfilen: %s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: användare \"%s\" och grupp \"%s\" finns inte.\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "medlemmar av klassen %s:\n"
+
+msgid "no entries\n"
+msgstr "inga objekt\n"
+
+msgid "no system default destination\n"
+msgstr "inget systemstandardmål\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "väntar"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc: Lägger till inkluderingskatalog \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc: Lägger till/uppdaterar UI-text från %s...\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc: Felaktigt booleskt värde (%s) på rad %d av %s.\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc: Felaktig variabelersättning ($%c) på rad %d av %s.\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc: Förväntat booleskt värde på rad %d av %s.\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc: Förväntad valkod på rad %d av %s.\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc: Förväntad namn-/textkod på rad %d av %s.\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc: Läser in fil med drivrutinsinformation \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc: Läser in meddelanden för språk \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc: Läser in meddelanden från \"%s\"...\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc: Kunde inte skapa PPD-fil \"%s\" - %s.\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc: Kunde inte skapa utdatakatalog %s: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc: Kunde inte skapa utdatarör: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc: Kunde inte köra cupstestppd: %s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc: Kunde inte hitta lokalisering för \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc: Kunde inte läsa in lokaliseringsfil för \"%s\" - %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc: Odefinierad variabel (%s) på rad %d av %s.\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc: Skriver %s...\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc: Skriver PPD-filer till katalogen \"%s\"...\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge: Ignorerar PPD-fil %s...\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge: Kan inte säkerhetskopiera %s till %s- %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "skrivare %s avaktiverad sedan %s -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "skrivare %s är overksam. aktiverad sedan %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "skrivare %s skriver ut %s-%d. avaktiverad sedan %s\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "skrivare %s/%s avaktiverad sedan %s -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "skrivare %s/%s är overksam. aktiverad sedan %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "skrivare %s/%s skriver ut %s-%d. aktiverad sedan %s\n"
+
+msgid "processing"
+msgstr "bearbetar"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "ID för begäran är %s-%d (%d fil(er))\n"
+
+msgid "request-id uses indefinite length"
+msgstr "order-ID använder obegränsad längd"
+
+msgid "scheduler is not running\n"
+msgstr "schemaläggare körs inte\n"
+
+msgid "scheduler is running\n"
+msgstr "schemaläggare körs\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "status för %s misslyckades: %s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "status\t\tvisa status för demon och kö\n"
+
+msgid "stopped"
+msgstr "stoppad"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "systemstandardmål: %s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "systemstandardmål: %s/%s\n"
+
+msgid "unknown"
+msgstr "okänd"
+
+msgid "untitled"
+msgstr "namnlös"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variabelbindningar använder obegränsad längd"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " VARN %s har inga motsvarande alternativ!\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " VARN Standardval är i konflikt!\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " VARN Nyckelordet %s för duplexalternativet kanske inte "
+#~ "fungerar som det ska och bör vara Duplex!\n"
+#~ " REF: Sida 122, sektion 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr ""
+#~ " VARN Filen innehåller en blandning av radslut med CR, LF och "
+#~ "CR LF!\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " VARN Rad %d innehåller endast mellanslag!\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " VARN Saknad APDialogExtension-fil â€%sâ€\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " VARN Saknad APPrinterIconPath-fil â€%sâ€\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " VARN Icke-Windows PPD-filer bör använda radslut med endast LF, "
+#~ "inte CR LF!\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " VARN Föråldrad PPD-version %.1f!\n"
+#~ " REF: Sida 42, sektion 5.2.\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s finns inte!\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s Felaktigt %s val %s!\n"
+#~ " REF: Sida 122, sektion 5.17\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr ""
+#~ " %s Felaktig UTF-8-översättningssträng â€%s†för alternativet %s!\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Felaktig UTF-8-översättningssträng â€%s†för alternativet %s, "
+#~ "valet %s!\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s Felaktigt cupsFilter-värde \"%s\"!\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s Felaktig cupsICCProfile %s!\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s Felaktigt cupsFilter-värde \"%s\"!\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Felaktig cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s Felaktigt språk \"%s\"!\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s Tom cupsUIConstraints %s!\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s Saknad översättningssträng â€%s†för alternativet %s!\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr ""
+#~ " %s Saknad översättningssträng â€%s†för alternativet %s, valet %s!\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr " %s Valet *%s %s saknas i UIConstraints \"*%s %s *%s %sâ€!\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Valet *%s %s saknas i cupsUIConstraints %s: \"%sâ€!\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s Saknad cupsICCProfile-fil \"%s\"!\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s Saknad cupsUIResolver %s!\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s Alternativet %s saknas i UIConstraints \"*%s %s *%s %s\"!\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s Alternativet %s saknas i cupsUIConstraints %s: \"%s\"!\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr " %s Ingen grundöversättning \"%s\" finns i filen!\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s KRÄVER %s definierar inte valet None!\n"
+#~ " REF: Sida 122, sektion 5.17\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " %s cupsICCProfile %s hashvärde står i konflikt med %s!\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver %s orsakade en loop!\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FEL** %s namnen %s och %s skiljer sig endast i fråga om stor "
+#~ "eller liten bokstav!\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **FEL** %s måste vara 1284DeviceID!\n"
+#~ " REF: Sida 72, sektion 5.5\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **FEL** FELAKTIG DefaultImageableArea %s!\n"
+#~ " REF: Sida 102, sektion 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **FEL** FELAKTIG DefaultPaperDimension %s!\n"
+#~ " REF: Sida 103, sektion 5.15.\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **FEL** Felaktigt %s-val %s!\n"
+#~ " REF: Sida 84, sektion 5.9\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr " **FEL** Felaktig språkkodning %s - måste vara ISOLatin1!\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr " **FEL** Felaktigt språk %s - måste vara engelska!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr ""
+#~ " **FEL** Standardöversättningssträng för alternativet %s val %s "
+#~ "innehåller 8-bitars tecken!\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr ""
+#~ " **FEL** Standardöversättningssträng för alternativet %s innehåller "
+#~ "8-bitars tecken!\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FEL** Gruppnamnen %s och %s skiljer sig endast i fråga om stor "
+#~ "eller liten bokstav!\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **FEL** Flera förekomster av %s namn %s!\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr ""
+#~ " **FEL** Alternativnamnen %s och %s skiljer sig endast i fråga om "
+#~ "stor eller liten bokstav!\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " Felaktig %%%%BoundingBox: på rad %d!\n"
+#~ " REF: Sida 39, %%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " Felaktig %%%%Page: på rad %d!\n"
+#~ " REF: Sida 53, %%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " Felaktiga %%%%Pages: på rad %d!\n"
+#~ " REF: Sida 43, %%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " Rad %d är längre än 255 tecken (%d)!\n"
+#~ " REF: Sida 25, Line Length\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " Saknar %!PS-Adobe-3.0 på första raden!\n"
+#~ " REF: Sida 17, 3.1 Conforming Documents\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " Saknar %%EndComments-kommentar!\n"
+#~ " REF: Sida 41, %%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " Saknad eller felaktig %%BoundingBox: kommentar!\n"
+#~ " REF: Sida 39, %%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " Saknad eller felaktig %%Page: kommentar!\n"
+#~ " REF: Sida 53, %%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " Saknad eller felaktig %%Pages: kommentar!\n"
+#~ " REF: Sida 43, %%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " Såg %d rader som översteg 255 tecken!\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " För många %%BeginDocument-kommentarer!\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " För många %%EndDocument-kommentarer!\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " Varning: filen innehåller binärdata!\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " Varning: ingen %%EndComments-kommentar i fil!\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " Varning: föråldrad DSC-version %.1f i fil!\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s stöds inte!"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s: Vet inte vad som ska göras!\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr "%s: Fel - miljövariabeln %s namnger icke-existerande mål \"%s\"!\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s: Fel - felaktigt utskrifts-ID!\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr ""
+#~ "%s: Fel - kan inte skriva ut filer och ändra utskrifter samtidigt!\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr ""
+#~ "%s: Fel - kan inte skriva ut från standard in om filer eller ett "
+#~ "utskrifts-ID anges!\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s: Fel - förväntade teckenkodning efter alternativet â€-Sâ€!\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s: Fel - förväntade innehÃ¥llstyp efter alternativet â€-Tâ€!\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s: Fel - förväntade exemplar efter alternativet â€-nâ€!\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s: Fel - förväntade antal exemplar efter alternativet â€-#â€!\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s: Fel - förväntade mÃ¥l efter alternativet â€-Pâ€!\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s: Fel - förväntade mÃ¥l efter alternativet â€-bâ€!\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s: Fel - förväntade mÃ¥l efter alternativet â€-dâ€!\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s: Fel - förväntade format efter alternativet â€-fâ€!\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s: Fel - förväntade kvarhÃ¥llningsnamn efter alternativet â€-Hâ€!\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s: Fel - förväntade värdnamn efter alternativet â€-Hâ€!\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s: Fel - förväntade värdnamn efter alternativet â€-hâ€!\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s: Fel - förväntade lägeslista efter alternativet â€-yâ€!\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s: Fel - förväntade namn efter alternativet â€-%câ€!\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s: Fel - förväntade alternativsträng efter alternativet â€-oâ€!\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s: Fel - förväntade sidlista efter alternativet â€-Pâ€!\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s: Fel - förväntade prioritet efter alternativet â€-%câ€!\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s: Fel - förväntade anledningstext efter alternativet â€-râ€!\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s: Fel - förväntade titel efter alternativet â€-tâ€!\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s: Fel - förväntade användarnamn efter alternativet â€-Uâ€!\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s: Fel - förväntade användarnamn efter alternativet â€-Uâ€!\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s: Fel - förväntade värde efter alternativet â€-%câ€!\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s: Fel - behöver â€completedâ€, â€not-completed†eller â€all†efter "
+#~ "alternativet â€-Wâ€!\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s: Fel - schemaläggare svarar inte!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s: Fel - okänt mål \"%s\"!\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s: Fel - okänt mål \"%s/%s\"!\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s: Fel - okänt alternativ â€%câ€!\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s: Fel - okänt alternativ â€%sâ€!\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s: Förväntade utskrifts-ID efter alternativet â€-iâ€!\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s: Ogiltigt målnamn i listan \"%s\"!\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr "%s: Behöver utskrifts-ID (â€-i jobidâ€) före â€-H restartâ€!\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s: Filter saknas för konvertering från %s/%s till %s/%s!\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s: Tyvärr, inget stöd för kryptering har byggts in!\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s: Kunde inte kontakta server!\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s: Kan inte avgöra MIME-typ hos \"%s\"!\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s: Kan inte öppna %s - %s\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s: Kan inte öppna %s - %s på rad %d.\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s: Kan inte läsa MIME-databas från \"%s\" eller \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s: Okänt mål \"%s\"!\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s: Okänd mål-MIME-typ %s/%s!\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s: Okänt alternativ â€%câ€!\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%s: Okänd käll-MIME-typ %s/%s!\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr ""
+#~ "%s: Varning - â€%c†formatmodifieraren stöds inte - utmatning kanske inte "
+#~ "blir korrekt!\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s: Varning - alternativet för teckenkodning ignorerades!\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s: Varning - alternativet för innehållstyp ignorerades!"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s: Varning - formuläralternativ ignorerades!\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s: Varning - lägesalternativ ignorerades!\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr "%s: fel - miljövariabeln %s namnger icke-existerande mål \"%s\"!\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s: förväntade option=value efter alternativet â€-oâ€!\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "600 DPI gråskala"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr "Ett Samba-lösenord krävs för att exportera skrivardrivrutiner"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr "Ett Samba-användarnamn krävs för att exportera skrivardrivrutiner!"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "En klass med namnet \"%s\" finns redan!"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "En skrivare med namnet \"%s\" finns redan!"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr "Försök att ställa in %s printer-state till felaktigt värde %d!"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "Attributgrupper har fel ordning (%x < %x)!"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "Felaktig device URI \"%s\"!\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "Felaktig device-uri \"%s\"!"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "Felaktigt device-uri-system\"%s\"!"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "Felaktigt document-format \"%s\"!"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "Felaktig buffring av filnamn!"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "Felaktigt värde för utskriftsprioritet!"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "Felaktigt värde för utskriftsark \"%s\"!"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "Felaktigt värde för typ av utskriftsark!"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "Felaktigt värde för utskriftsstatus!"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "Felaktigt attribut för job-uri \"%s\"!"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "Felaktig notify-pull-method \"%s\"!"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "Felaktig URI för notify-recipient \"%s\"!"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "Felaktigt alternativ + val på rad %d!"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "Felaktig portövervakare \"%s\"!"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "Felaktigt värde för skrivarstatus %d!"
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "Felaktigt versionsnummer %d.%d för begäran!"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "Felaktigt prenumerations-ID!"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "Teckenkodningen \"%s\" stöds inte!"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "Kunde inte skanna typen \"%s\"!"
+
+#~ msgid "Cover open."
+#~ msgstr "Lock öppet."
+
+#~ msgid "Developer almost empty."
+#~ msgstr "Tonern nästan slut."
+
+#~ msgid "Developer empty!"
+#~ msgstr "Tonern är slut!"
+
+#~ msgid "Door open."
+#~ msgstr "Lucka öppen."
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Felaktig %%BoundingBox: kommentar sedd!\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: Felaktig %%IncludeFeature: kommentar!\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: Felaktig %%Page: kommentar i fil!\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: Felaktig %%PageBoundingBox: kommentar i fil!\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: Felaktig SCSI-enhetsfil \"%s\"!\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: Felaktigt kolumnvärde %d!\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: Felaktigt cpi-värde %f!\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: Felaktigt lpi-värde %f!\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: Felaktigt utskriftsformat!\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: MÃ¥lskrivaren finns inte!\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: Duplikat av %%BoundingBox: kommentar sedd!\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: Duplikat av %%Pages: kommentar sedd!\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: Tom utskriftsfil!\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr "ERROR: Förväntad sträng inom citationstecken på rad %d av %s!\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: Allvarligt USB-fel!\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr "ERROR: Ogiltigt HP-GL/2-kommando sett, kan inte skriva ut filen!\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: Saknad %%EndProlog!\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: Saknad %%EndSetup!\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Saknad enhets-URI i kommandoraden och ingen miljövariabel för "
+#~ "DEVICE_URI!\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: Saknar värde på rad %d i bannerfil!\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: Ingen %%BoundingBox: kommentar i sidhuvud!\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: Inga %%Pages: kommentar i sidhuvud!\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr ""
+#~ "ERROR: Ingen enhets-URI hittades i argv[0] eller i miljövariabeln "
+#~ "DEVICE_URI!\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: Inga sidor hittades!\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: Slut på papper!\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: PRINTER-miljövariabeln är inte definierad!\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: Utskriftsfilen accepterades inte (%s)!\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: Skrivaren svarar inte\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: Kunde inte skapa temporär fil - %s.\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: Kunde inte skapa temporär fil: %s\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: Kunde inte hämta utskriftsattribut %d (%s)!\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: Kunde inte hämta skrivarstatus (%s)!\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: Kunde inte hitta skrivaren â€%sâ€!\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: Kunde inte öppna bildfilen för utskrift!\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: Kunde inte öppna temporär fil"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: Kunde inte skriva ut %d textkolumner!\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: Kunde inte skriva ut %dx%d textsida!\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: Kunde inte läsa utskriftsdata!"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: Kunde inte skicka utskriftsdata (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: Kunde inte skicka utskriftsdata!"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: Kunde inte skriva %d byte till skrivare!\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr "ERROR: Kunde skriva rasterdata till skrivaren!\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: Kunde inte skriva till temporär fil"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: Oväntad text på rad %d av %s!\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: Okänt krypteringsalternativvärde \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: Okänt meddelandekatalogformat för \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: Okänt alternativ \"%s\" med värde \"%s\"!\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: Okänt versionsalternativvärde \"%s\"!\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr ""
+#~ "ERROR: Värdet %s för ljusstyrka stöds inte, använder ljusstyrka=100!\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: Värdet %s för gamma stöds inte, använder gamma=1000!\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr "ERROR: Värdet %d för number-up stöds inte, använder number-up=1!\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: Värdet %s för number-up-layout stöds inte, använder number-up-"
+#~ "layout=lrtb!\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr ""
+#~ "ERROR: Värdet %s för sidmarginal stöds inte, använder page-border=none!\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr "ERROR: doc_printf overflow (%d byte) upptäckt, stoppar!\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr "ERROR: pdftops-filter kraschade på signal %d!\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr "ERROR: pdftops-filter avslutades med status %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops avslutade med signalen %d!\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops avslutades med status %d!\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "ERROR: kan återställas: Kan inte ansluta till skrivaren, försöker igen om "
+#~ "30 sekunder...\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "Tom PPD-fil!"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "Fel: behöver värdnamn efter alternativet â€-hâ€!\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "Hög fixeringstemperatur!"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "LÃ¥g fixeringstemperatur!"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "Attribut för printer-uri finns, men inget utskrifts-ID!"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "Bläck/toner är nästan slut."
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "Bläck/toner är slut!"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "Avfallsbehållaren för bläck/toner nästan full."
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "Avfallsbehållaren för bläck/toner är full!"
+
+#~ msgid "Interlock open."
+#~ msgstr "Spärrmekanism öppen."
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "Utskrift #%d kan inte startas om - inga filer!"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "Utskrift #%d finns inte!"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "Utskrift #%d är klar och kan inte ändras!"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "Utskrift #%d är inte klar!"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "Utskrift #%d hålls inte kvar för autentisering!"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "Utskrift #%d hålls inte kvar"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "Utskrift #%s finns inte!"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "Utskrift %d hittades inte!"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "Utskriftsprenumerationer kan inte förnyas!"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "Språket \"%s\" stöds inte!"
+
+#~ msgid "Media jam!"
+#~ msgstr "Medietrassel!"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "Mediefack nästan tomt."
+
+#~ msgid "Media tray empty!"
+#~ msgstr "Mediefack tomt!"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "Mediefack saknas!"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "Mediefacket måste fyllas på."
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "Saknar attribut för dokumentnummer!"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "Saknar dubbla citationstecken på rad %d!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "Saknar formatvariabel!"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "Saknar attributet notify-subscription-ids!"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "Saknar attributet requesting-user-name!"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "Saknar nödvändiga attribut!"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "Saknar värde på rad %d!"
+
+#~ msgid "No PPD name!"
+#~ msgstr "Inget PPD-namn!"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "Inga skrivardrivrutiner för Windows är installerade!"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "Inga aktiva utskrifter på %s!"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "Inga attribut i begäran!"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "Ingen autentiseringsinformation angiven!"
+
+#~ msgid "No file!?!"
+#~ msgstr "Ingen fil!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "Ingen ändringstid!"
+
+#~ msgid "No printer name!"
+#~ msgstr "Inget skrivarnamn!"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "Ingen printer-uri hittades för klass!"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "Inget printer-uri hittades!"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "Inga printer-uri i begäran!"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "Inga prenumerationsattribut i begäran!"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC nästan vid slutpunkten."
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC vid slutpunkten!"
+
+#~ msgid "Out of toner!"
+#~ msgstr "Slut på toner!"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "Utmatningsfack nästan fullt."
+
+#~ msgid "Output bin full!"
+#~ msgstr "Utmatningsfack fullt!"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "Utmatningsfack saknas!"
+
+#~ msgid "Printer offline."
+#~ msgstr "Skrivare frånkopplad."
+
+#~ msgid "SCSI Printer"
+#~ msgstr "Skrivare SCSI"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "Värdet för notify-user-data är för stort (%d &gt; 63 oktetter)!"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "Skrivaren eller klassen är inte delad!"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "Attributet printer-uri krävs!"
+
+#~ msgid "Toner low."
+#~ msgstr "Toner låg."
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "För många värden för utskriftsark (%d > 2)!"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "För många värden för skrivarstatus (%d > %d)!"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "Kunde inte lägga till utskrift för målet \"%s\"!"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "Kunde inte tilldela minne för filtyper!"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr "Kunde inte kopiera filer för 64-bitars CUPS-skrivardrivrutin (%d)!"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr ""
+#~ "Kunde inte kopiera filer för 64-bitars Windows-skrivardrivrutin (%d)!"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr "Kunde inte kopiera filer för CUPS-skrivardrivrutin (%d)!"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "Kunde inte kopiera PPD-fil - %s!"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "Kunde inte kopiera PPD-fil!"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Kunde inte kopiera filer för skrivardrivrutiner till 2000 Windows (%d)!"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr "Kunde inte kopiera filer för Windows 9x-skrivardrivrutin (%d)!"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "Kunde inte kopiera gränssnittsskript - %s!"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "Kunde inte skapa printer-uri!"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr "Kunde inte redigera cupsd.conf-filer större än 1 MB!"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "Kunde inte hitta mål för utskrift!"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "Kunde inte hitta skrivare!\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr ""
+#~ "Kunde inte installera filer för skrivardrivrutiner till 2000 Windows (%d)!"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr "Kunde inte installera filer för Windows 9x-skrivardrivrutin (%d)!"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "Kunde inte öppna dokument %d i utskrift %d!"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "Kunde inte skicka kommando till skrivardrivrutin!"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "Kunde inte ställa in Windows-skrivardrivrutin (%d)!"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "Kunde inte använda tidigare USB-klassdrivrutin!\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "Okänt skrivarfel (%s)!"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "Ogiltig teckenuppsättning \"%s\"!"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "Ogiltig komprimering \"%s\"!"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "Ogiltigt komprimeringsattribut %s!"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "Formatet \"%s\" stöds inte!"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr " Formatet â€%s†stöds inte!"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "Formatet â€%s/%s†stöds inte!"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "Användning: konvertera [ alternativ ]\n"
+#~ "\n"
+#~ "Alternativ:\n"
+#~ "\n"
+#~ " -f filnamn Ange fil att konvertera (annars standard in)\n"
+#~ " -o filnamn Ange fil att generera (annars standard ut)\n"
+#~ " -i MIME/typ Ange MIME-typ för indata (annars automatiskt)\n"
+#~ " -j MIME/typ Ange MIME-typ för utdata (annars program/pdf)\n"
+#~ " -P filnamn.ppd Ange PPD-fil\n"
+#~ " -a â€name=value ...†Ange alternativ\n"
+#~ " -U användarnamn Ange användarnamn för utskrift\n"
+#~ " -J titel Ange titel\n"
+#~ " -c kopior Ange antal kopior\n"
+#~ " -u Radera PPD-filen när det är klart\n"
+#~ " -D Radera indatafilen när det är klart\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "Användning: cupsfilter -m MIME/typ [ alternativ ] filnamn\n"
+#~ "\n"
+#~ "Alternativ:\n"
+#~ "\n"
+#~ " -c cupsd.conf Ange cupsd.conf-fil för användning\n"
+#~ " -j utskrifts-ID[,N] Filtrera fil N från angiven utskrift (fil 1 är "
+#~ "förvald)\n"
+#~ " -n kopior Ange antal kopior\n"
+#~ " -o name=value Ange alternativ)\n"
+#~ " -p filnamn.ppd Ange PPD-fil\n"
+#~ " -t titel Ange titel\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Användning: cupstestppd [alternativ] filnamn1.ppd[.gz] [... filnamnN.ppd[."
+#~ "gz]]\n"
+#~ " program | cupstestppd [alternativ] -\n"
+#~ "\n"
+#~ "Alternativ:\n"
+#~ "\n"
+#~ " -R root-directory Ange alternativ rot\n"
+#~ " -W {alla,ingen,regler,standard,duplex,filter,översättningar}\n"
+#~ " Skicka varningar istället för fel\n"
+#~ " -q Kör ljudlöst\n"
+#~ " -r Använd öppet läge\n"
+#~ " -v Visa mindre utförligt\n"
+#~ " -vv Visa mycket utförligt\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: Kunde inte läsa sidkanalsbegäran!\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr ""
+#~ "WARNING: Alternativet \"%s\" kan inte inkluderas via IncludeFeature!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Fjärrvärden svarade inte med kommandostatusbyte efter %d "
+#~ "sekunder!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Fjärrvärden svarade inte med kontrollstatusbyte efter %d "
+#~ "sekunder!\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr ""
+#~ "WARNING: Fjärrvärden svarade inte med datastatusbyte efter %d sekunder!\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr ""
+#~ "WARNING: SCSI-kommando nådde en maxtidsgräns (%d), försöker igen...\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: Det här dokumentet följer inte Adobes dokumentspecifikationer "
+#~ "och kanske inte skrivs ut på rätt sätt!\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: Okänt val \"%s\" för alternativet \"%s\"!\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: Okänt alternativ \"%s\"!\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: Formatet %s stöds inte!\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr ""
+#~ "WARNING: kan Ã¥terställas: Nätverksvärden â€%s†är upptagen, försöker igen "
+#~ "om %d sekunder...\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr "Varning, inga skrivardrivrutiner för Windows 2000 är installerade!"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl: Okänt alternativ \"%s\"!\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl: Okänt alternativ \"-%c\"!\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr "cupsd: Förväntat konfigurationsfilnamn efter alternativet \"-c\"!\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd: Kunde inte hämta aktuell katalog!\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd: Okänt argument \"%s\" - stoppar!\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd: Okänt alternativ \"%c\" - stoppar!\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter: Ogiltigt dokumentnummer %d!\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter: Ogiltigt utskrifts-ID %d!\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter: Bara ett filnamn kan anges!\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter: Kunde inte skapa temporär fil: %s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "Attributet job-printer-uri saknas!"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Klassnamn kan endast innehålla skrivbara tecken!\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: Förväntat PPD efter alternativet â€-Pâ€!\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr "lpadmin: Förväntad allow/deny:userlist efter alternativet â€-uâ€!\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: Förväntad klass efter alternativet â€-râ€!\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: Förväntat klassnamn efter alternativet â€-câ€!\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: Förväntad beskrivning efter alternativet â€-Dâ€!\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: Förväntad enhets-URI efter alternativet â€-vâ€!\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: Förväntade filtyp(er) efter alternativet â€-Iâ€!\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: Förväntat värdnamn efter alternativet â€-hâ€!\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: Förväntat gränssnitt efter alternativet â€-iâ€!\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: Förväntad plats efter alternativet â€-Lâ€!\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: Förväntad modell efter alternativet â€-mâ€!\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: Förväntad name=value efter alternativet â€-oâ€!\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: Förväntad skrivare efter alternativet â€-pâ€!\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: Förväntat skrivarnamn efter alternativet â€-dâ€!\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin: Förväntad skrivare eller klass efter alternativet â€-xâ€!\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: Inga medlemsnamn sågs!\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr "lpadmin: Skrivarnamn kan endast innehålla skrivbara tecken!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kunde inte lägga till en skrivare till klassen:\n"
+#~ " Du måste ange ett skrivarnamn först!\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin: Kunde inte skapa tempfil - %s\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin: Kunde inte skapa tempfil: %s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kunde inte ta bort en skrivare från klassen:\n"
+#~ " Du måste ange ett skrivarnamn först!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kunde inte ställa in PPD-filen:\n"
+#~ " Du måste ange ett skrivarnamn först!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kunde inte ställa in enhets-URI:\n"
+#~ " Du måste ange ett skrivarnamn först!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kunde inte ställa in gränssnittsskriptet eller PPD-fil:\n"
+#~ " Du måste ange ett skrivarnamn först!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kunde inte ställa in gränssnittsskriptet:\n"
+#~ " Du måste ange ett skrivarnamn först!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kunde inte ställa in skrivarbeskrivningen:\n"
+#~ " Du måste ange ett skrivarnamn först!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kunde inte ställa in skrivarens plats:\n"
+#~ " Du måste ange ett skrivarnamn först!\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: Kunde inte ställa in skrivaralternativen:\n"
+#~ " Du måste ange ett skrivarnamn först!\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: : Okänt tillåta/neka-alternativ \"%s\"!\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: Okänt argument â€%sâ€!\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: Okänt alternativ â€%câ€!\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin: Varning - innehållstyplista ignorerades!\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr "lpinfo: Förväntad 1284 device ID string efter--device-id!\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo: Förväntat språk efter --language!\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo: Förväntad tillverkning och modell efter --make-and-model!\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo: Förväntad produktsträng efter --product!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo: Förväntad schemalista efter --exclude-schemes!\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo: Förväntad schemalista efter --include-schemes!\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo: Förväntat tidsgränsfel efter --timeout!\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo: Okänt argument â€%sâ€!\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo: Okänt alternativ â€%câ€!\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo: Okänt alternativ â€%sâ€!\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove: Okänt argument â€%sâ€!\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove: Okänt alternativ â€%câ€!\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions: Inga skrivare!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions: Kunde inte öppna PPD-fil för %s!\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions: Okänd skrivare eller klass!\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: Endast rot kan lägga till eller ta bort lösenord!\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: Lösenordsfil upptagen!\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: Lösenordsfil inte uppdaterad!\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: Tyvärr, lösenord stämmer inte!\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: Tyvärr, lösenorden stämmer inte överens!\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr ""
+#~ "lpstat: fel - miljövariabeln %s namnger icke-existerande mål \"%s\"!\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-events inte angivet!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "URI för notify-recipient-uri \"%s\" används redan!"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "URI för notify-recipient-uri \"%s\" använder okänt schema!"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d inte bra!"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Felaktigt upplösningsnamn \"%s\" på rad %d av %s!\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc: Felaktigt statuslösenord %s på rad %d av %s!\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc: Val hittades på rad %d of %s utan alternativ!\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc: Dublicera #po för språk %s på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad filterdefinition på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat programnamn på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad teckenkodning efter typsnitt på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad färgordning för ColorModel på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad färgrymd för ColorModel på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad komprimering för ColorModel på rad %d av %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad regelsträng för UIConstraints på rad %d av %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Förväntat lösenord för drivrutinstyp efter DriverType på rad %d av %"
+#~ "s!\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad duplextyp efter Duplex på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad kodning efter typsnitt på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat filnamn efter #po %s på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat gruppnamn/-text på rad %d av %s.\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat inkluderingsfilnamn på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat heltal på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad språkversion #po på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat namn efter %s på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat namn efter filnamn på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat namn efter typsnitt på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat namn efter tillverkare på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat namn efter mediestorlek på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat namn efter modellnamn på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat namn efter PC-filnamn på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat namn/text efter %s på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat namn/text efter installerbart på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat namn/text efter upplösning på rad %d av %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Förväntat namn-/textkombination för ColorModel på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat alternativnamn/-text på rad %d av %s.\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat alternativavsnitt på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad alternativtyp på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat ersättningsfält efter upplösning på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat reellt tal på rad %d av %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Förväntad upplösning/medietyp efter ColorProfile på rad %d av %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Förväntad upplösning/medietyp efter SimpleColorProfile på rad %d av "
+#~ "%s!\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad väljare efter %s på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad status efter typsnitt på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad sträng efter upphovsrätt på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad sträng efter version på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntade två alternativnamn på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntat värde efter %s på rad %d av %s!\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc: Förväntad version efter typsnitt på rad %d av %s!\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc: Ogiltigt #include/#po filnamn \"%s\"!\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Ogiltig kostnad för filter på rad %d av %s!\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Ogiltig tom MIME-typ för filter på rad %d av %s!\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr "ppdc: Ogiltigt tomt programnamn för filter på rad %d av %s!\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ogiltigt alternativavsnitt \"%s\" på rad %d av %s!\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Ogiltig alternativtyp \"%s\" på rad %d av %s!\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc: Saknad #endif i slutet av \"%s\"!\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc: Saknad #if på rad %d av %s!\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc: Ingen meddelandekatalog angiven för språkversionen %s!\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr ""
+#~ "ppdc: Alternativ %s definieras om med en annan typ på rad %d av %s!\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr "ppdc: Alternativregel måste *name på rad %d av %s!\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc: För mÃ¥nga nästlade #ifâ€s pÃ¥ rad %d av %s!\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc: Kunde inte hitta #po fil %s på rad %d av %s!\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Kunde inte hitta inkluderingsfil \"%s\" på rad %d av %s!\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc: Okänd drivrutinstyp %s på rad %d av %s!\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Okänd duplextyp \"%s\" på rad %d av %s!\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc: Okänd mediestorlek \"%s\" på rad %d of %s!\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc: Okänd symbol \"%s\" sågs på rad %d av %s!\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc: Okända avslutande tecken i reellt tal \"%s\" på rad %d av %s!\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr "ppdc: Oavslutad sträng börjar med %c på rad %d av %s!\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge: Felaktig LanguageVersion \"%s\" i %s!\n"
diff --git a/locale/cups_zh.po b/locale/cups_zh.po
new file mode 100644
index 000000000..4055d1736
--- /dev/null
+++ b/locale/cups_zh.po
@@ -0,0 +1,7020 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-16 12:00-0800\n"
+"Last-Translator: Apple Inc.\n"
+"Language-Team: Apple Inc.\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(全部)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(无)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d 个æ¡ç›®\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\tå‘生故障åŽï¼šç»§ç»­\n"
+
+msgid "\tAlerts:"
+msgstr "\t警报:"
+
+msgid "\tBanner required\n"
+msgstr "\t需è¦æ ‡é¢˜\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\t字符集集åˆï¼š\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\t连接:直接\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\t连接:远程\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\t默认页é¢å¤§å°ï¼š\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\t默认间è·ï¼š\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\t默认端å£è®¾ç½®ï¼š\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tæ述:%s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\t已装载的表格:\n"
+"\t内容类型:任何\n"
+"\t打å°æœºç±»åž‹ï¼šæœªçŸ¥\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tå…许的形å¼ï¼š\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\t接å£ï¼š%s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\t接å£ï¼š%s/interfaces/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\t接å£ï¼š%s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tä½ç½®ï¼š%s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\tå‘生故障时:无警报\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tå…许的用户:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\tæ‹’ç»çš„用户:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\t监控程åºå·²å­˜åœ¨\n"
+
+msgid "\tno entries\n"
+msgstr "\tæ— æ¡ç›®\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\t打å°æœºåœ¨è®¾å¤‡ &apos;%s&apos; 上,速度 -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\t打å°å·²åœç”¨\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\t打å°å·²å¯ç”¨\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\t已排队进行%s\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\t队列已åœç”¨\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\t队列已å¯ç”¨\n"
+
+msgid "\treason unknown\n"
+msgstr "\t原因未知\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" 详细的一致性测试结果\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " REF: 页 15,节 3.1。\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " REF: 页 15,节 3.2。\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " REF: 页 19,节 3.3。\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " REF: 页 20,节 3.4。\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " REF: 页 27,节 3.5。\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " REF: 页 42,节 5.2。\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " REF: 页 16-17,节 3.2。\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " REF: 页 42-45,节 5.2。\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " REF: 页 45-46,节 5.2。\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " REF: 页 48-49,节 5.2。\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " REF: 页 52-54,节 5.2。\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f 字节\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " 通过 Default%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " 通过 DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " 通过 DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " 通过 FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " 通过 FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " 通过 LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " 通过 LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " 通过 Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " 通过 ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " 通过 NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " 通过 PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " 通过 PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " 通过 PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " 通过 PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " 通过 Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " 通过 ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" WARN “%s %sâ€ä¸Žâ€œ%s %sâ€æœ‰å†²çª\n"
+" (constraint=\"%s %s %s %s\")\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" WARN %s 与 %s 共享一个公共å‰ç¼€\n"
+" REF: 第 15 页,第 3.2 节。\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" WARN PPD 4.3 规范è¦æ±‚ LanguageEncoding。\n"
+" REF: 页 56-57,节 5.3。\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" WARN PPD 4.3 规范è¦æ±‚ Manufacturer。\n"
+" REF: 第 58-59 页,第 5.3 节。\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" WARN PCFileName 长于 8.3,ä¸ç¬¦åˆ PPD 规范。\n"
+" REF: 页 61-62,节 5.3。\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN åè®®å«æœ‰ PJL,但 JCL 属性未设定。\n"
+" REF: 页 78-79,节 5.7。\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" WARN åè®®å«æœ‰ PJL å’Œ BCP;还期待 TBCP。\n"
+" REF: 页 78-79,节 5.7。\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" WARN PPD 4.3 规范è¦æ±‚ ShortNickName。\n"
+" REF: 页 64-65,节 5.3。\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s 缺少 cupsFilter 文件“%sâ€\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s 缺少 cupsPreFilter 文件“%sâ€\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **失败** 错误的 Default%s %s\n"
+" REF: 第 40 页,第 4.5 节。\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **失败** 文件中错误的 JobPatchFile 属性\n"
+" REF: 第 24 页,第 3.4 节。\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **失败** 错误的 Manufacturer(应该是“HPâ€ï¼‰\n"
+" REF: 第 211 页,表 D.1。\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **失败** 错误的 Manufacturer(应该是“Okiâ€ï¼‰\n"
+" REF: 第 211 页,表 D.1。\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **失败** 错误的 ModelName -“%câ€ï¼Œå­—符串中ä¸å…许。\n"
+" REF: 页 59-60,节 5.3。\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **失败** 错误的 PSVersion - ä¸æ˜¯â€œ(string) intâ€ã€‚\n"
+" REF: 页 62-64,节 5.3。\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **失败** 错误的 Product - ä¸æ˜¯â€œ(string) intâ€ã€‚\n"
+" REF: 页 62,节 5.3。\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **失败** 错误的 ShortNickName - 多于 31 个字符。\n"
+" REF: 页 64-65,节 5.3。\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **失败** 错误的 FileVersion“%sâ€\n"
+" REF: 第 56 页,第 5.3 节。\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **失败** 错误的 FormatVersion“%sâ€\n"
+" REF: 第 56 页,第 5.3 节。\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr " **失败** ä¸èƒ½è§£é‡Šé»˜è®¤é€‰é¡¹ç¼–ç ï¼š%s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **失败** è¦æ±‚ Default%s\n"
+" REF: 页 40,节 4.5。\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **失败** è¦æ±‚ DefaultImageableArea\n"
+" REF: 页 102,节 5.15。\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **失败** è¦æ±‚ DefaultPaperDimension\n"
+" REF: 页 103,节 5.15。\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **失败** è¦æ±‚ FileVersion\n"
+" REF: 页 56,节 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **失败** è¦æ±‚ FormatVersion\n"
+" REF: 页 56,节 5.3。\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **失败** è¦æ±‚ PageSize %s çš„ ImageableArea\n"
+" REF: 第 41 页,第 5 节。\n"
+" REF: 页 102,节 5.15。\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **失败** è¦æ±‚ LanguageEncoding\n"
+" REF: 页 56-57,节 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **失败** è¦æ±‚ LanguageVersion\n"
+" REF: 页 57-58,节 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **失败** è¦æ±‚ Manufacturer\n"
+" REF: 页 58-59,节 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **失败** è¦æ±‚ ModelName\n"
+" REF: 页 59-60,节 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **失败** è¦æ±‚ NickName\n"
+" REF: 页 60,节 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **失败** è¦æ±‚ PCFileName\n"
+" REF: 页 61-62,节 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **失败** è¦æ±‚ PSVersion\n"
+" REF: 页 62-64,节 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **失败** è¦æ±‚ PageRegion\n"
+" REF: 页 100,节 5.14。\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **失败** è¦æ±‚ PageSize\n"
+" REF: 第 41 页,第 5 节。\n"
+" REF: 页 99,节 5.14。\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **失败** è¦æ±‚ PageSize\n"
+" REF: 页 99-100,节 5.14。\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **失败** è¦æ±‚ PageSize %s çš„ PaperDimension\n"
+" REF: 第 41 页,第 5 节。\n"
+" REF: 页 103,节 5.15。\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **失败** è¦æ±‚ Product\n"
+" REF: 页 62,节 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **失败** è¦æ±‚ ShortNickName\n"
+" REF: 页 64-65,节 5.3。\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " å‘现 %d 个错误\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " 未å‘现错误\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " 失败\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" 失败\n"
+" **失败** 无法打开 PPD 文件 - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" 失败\n"
+" **失败** 无法打开 PPD 文件 - %s 在第 %d 行。\n"
+
+msgid " PASS\n"
+msgstr " 通过\n"
+
+msgid "#10 Envelope"
+msgstr "10 å·ä¿¡å°"
+
+msgid "#11 Envelope"
+msgstr "11 å·ä¿¡å°"
+
+msgid "#12 Envelope"
+msgstr "12 å·ä¿¡å°"
+
+msgid "#14 Envelope"
+msgstr "14 å·ä¿¡å°"
+
+msgid "#9 Envelope"
+msgstr "9 å·ä¿¡å°"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f 字节\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f 字节\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f 亳米"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f 至 %.0f x %.0f 亳米"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f 英寸"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f 至 %.2f x %.2f 英寸"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s 正在接å—请求,时间从 %s\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "%s ä¸èƒ½æ›´æ”¹ã€‚"
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s 未被 lpc 的 CUPS 版本实施。\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s 未准备就绪\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s 准备就绪\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s 已准备就绪,正在打å°\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s 没有在接å—请求,时间从 %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s 正在接å—请求,时间从 %s\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s 没有在接å—请求,时间从 %s -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s:%-33.33s [作业 %d 本地主机]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s:%s 失败:%s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s:错误 - 没有默认目的ä½ç½®ã€‚\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s:错误 - 优先级必须在 1 到 100 之间。\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s:错误 - 太多文件 -“%sâ€\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s:错误 - 无法访问“%sâ€- %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s:错误 - 无法从 stdin 排队 - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s:滤镜“%sâ€ä¸å¯ç”¨ï¼š%s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s:无效的滤镜字符串“%sâ€\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s:æ“作失败:%s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s:无法连接到æœåŠ¡å™¨\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s:无法打开 %s:%s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s:无法打开 PPD 文件:%s 在第 %d 行\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s:错误 - 没有默认目的ä½ç½®ã€‚\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 英寸/秒"
+
+msgid "1.25x0.25\""
+msgstr "1.25x0.25 英寸"
+
+msgid "1.25x2.25\""
+msgstr "1.25x2.25 英寸"
+
+msgid "1.5 inch/sec."
+msgstr "1.5 英寸/秒"
+
+msgid "1.50x0.25\""
+msgstr "1.50x0.25 英寸"
+
+msgid "1.50x0.50\""
+msgstr "1.50x0.50 英寸"
+
+msgid "1.50x1.00\""
+msgstr "1.50x1.00 英寸"
+
+msgid "1.50x2.00\""
+msgstr "1.50x2.00 英寸"
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 英寸/秒"
+
+msgid "10 x 11\""
+msgstr "10 x 11 英寸"
+
+msgid "10 x 13\""
+msgstr "10 x 13 英寸"
+
+msgid "10 x 14\""
+msgstr "10 x 14 英寸"
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 毫米/秒"
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 英寸/秒"
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 英寸/秒"
+
+msgid "12 x 11\""
+msgstr "12 x 11 英寸"
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 毫米/秒"
+
+msgid "120x60dpi"
+msgstr "120x60dpi"
+
+msgid "120x72dpi"
+msgstr "120x72dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 毫米/秒"
+
+msgid "15 x 11\""
+msgstr "15 x 11 英寸"
+
+msgid "150 mm/sec."
+msgstr "150 毫米/秒"
+
+msgid "150dpi"
+msgstr "150dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 英寸/秒"
+
+msgid "2-Sided Printing"
+msgstr "åŒé¢æ‰“å°"
+
+msgid "2.00x0.37\""
+msgstr "2.00x0.37 英寸"
+
+msgid "2.00x0.50\""
+msgstr "2.00x0.50 英寸"
+
+msgid "2.00x1.00\""
+msgstr "2.00x1.00 英寸"
+
+msgid "2.00x1.25\""
+msgstr "2.00x1.25 英寸"
+
+msgid "2.00x2.00\""
+msgstr "2.00x2.00 英寸"
+
+msgid "2.00x3.00\""
+msgstr "2.00x3.00 英寸"
+
+msgid "2.00x4.00\""
+msgstr "2.00x4.00 英寸"
+
+msgid "2.00x5.50\""
+msgstr "2.00x5.50 英寸"
+
+msgid "2.25x0.50\""
+msgstr "2.25x0.50 英寸"
+
+msgid "2.25x1.25\""
+msgstr "2.25x1.25 英寸"
+
+msgid "2.25x4.00\""
+msgstr "2.25x4.00 英寸"
+
+msgid "2.25x5.50\""
+msgstr "2.25x5.50 英寸"
+
+msgid "2.38x5.50\""
+msgstr "2.38x5.50 英寸"
+
+msgid "2.5 inches/sec."
+msgstr "2.5 英寸/秒"
+
+msgid "2.50x1.00\""
+msgstr "2.50x1.00 英寸"
+
+msgid "2.50x2.00\""
+msgstr "2.50x2.00 英寸"
+
+msgid "2.75x1.25\""
+msgstr "2.75x1.25 英寸"
+
+msgid "2.9 x 1\""
+msgstr "2.9 x 1 英寸"
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 毫米/秒"
+
+msgid "200 mm/sec."
+msgstr "200 毫米/秒"
+
+msgid "203dpi"
+msgstr "203dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "24 针系列"
+
+msgid "240x72dpi"
+msgstr "240x72dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 毫米/秒"
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 英寸/秒"
+
+msgid "3.00x1.00\""
+msgstr "3.00x1.00 英寸"
+
+msgid "3.00x1.25\""
+msgstr "3.00x1.25 英寸"
+
+msgid "3.00x2.00\""
+msgstr "3.00x2.00 英寸"
+
+msgid "3.00x3.00\""
+msgstr "3.00x3.00 英寸"
+
+msgid "3.00x5.00\""
+msgstr "3.00x5.00 英寸"
+
+msgid "3.25x2.00\""
+msgstr "3.25x2.00 英寸"
+
+msgid "3.25x5.00\""
+msgstr "3.25x5.00 英寸"
+
+msgid "3.25x5.50\""
+msgstr "3.25x5.50 英寸"
+
+msgid "3.25x5.83\""
+msgstr "3.25x5.83 英寸"
+
+msgid "3.25x7.83\""
+msgstr "3.25x7.83 英寸"
+
+msgid "3.5\" Disk"
+msgstr "3.5 英寸ç£ç›˜"
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "3.5 英寸ç£ç›˜ - 2 1/8 x 2 3/4 英寸"
+
+msgid "3.50x1.00\""
+msgstr "3.50x1.00 英寸"
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 毫米/秒"
+
+msgid "300 mm/sec."
+msgstr "300 毫米/秒"
+
+msgid "300dpi"
+msgstr "300dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360dpi"
+
+msgid "360x180dpi"
+msgstr "360x180dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 英寸/秒"
+
+msgid "4.00x1.00\""
+msgstr "4.00x1.00 英寸"
+
+msgid "4.00x13.00\""
+msgstr "4.00x13.00 英寸"
+
+msgid "4.00x2.00\""
+msgstr "4.00x2.00 英寸"
+
+msgid "4.00x2.50\""
+msgstr "4.00x2.50 英寸"
+
+msgid "4.00x3.00\""
+msgstr "4.00x3.00 英寸"
+
+msgid "4.00x4.00\""
+msgstr "4.00x4.00 英寸"
+
+msgid "4.00x5.00\""
+msgstr "4.00x5.00 英寸"
+
+msgid "4.00x6.00\""
+msgstr "4.00x6.00 英寸"
+
+msgid "4.00x6.50\""
+msgstr "4.00x6.50 英寸"
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 毫米/秒"
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 英寸/秒"
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 英寸/秒"
+
+msgid "6.00x1.00\""
+msgstr "6.00x1.00 英寸"
+
+msgid "6.00x2.00\""
+msgstr "6.00x2.00 英寸"
+
+msgid "6.00x3.00\""
+msgstr "6.00x3.00 英寸"
+
+msgid "6.00x4.00\""
+msgstr "6.00x4.00 英寸"
+
+msgid "6.00x5.00\""
+msgstr "6.00x5.00 英寸"
+
+msgid "6.00x6.00\""
+msgstr "6.00x6.00 英寸"
+
+msgid "6.00x6.50\""
+msgstr "6.00x6.50 英寸"
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 毫米/秒"
+
+msgid "600dpi"
+msgstr "600dpi"
+
+msgid "60dpi"
+msgstr "60dpi"
+
+msgid "60x720dpi"
+msgstr "60x720dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 英寸/秒"
+
+msgid "7 x 9\""
+msgstr "7 x 9 英寸"
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 英寸/秒"
+
+msgid "8 x 10\""
+msgstr "8 x 10 英寸"
+
+msgid "8.00x1.00\""
+msgstr "8.00x1.00 英寸"
+
+msgid "8.00x2.00\""
+msgstr "8.00x2.00 英寸"
+
+msgid "8.00x3.00\""
+msgstr "8.00x3.00 英寸"
+
+msgid "8.00x4.00\""
+msgstr "8.00x4.00 英寸"
+
+msgid "8.00x5.00\""
+msgstr "8.00x5.00 英寸"
+
+msgid "8.00x6.00\""
+msgstr "8.00x6.00 英寸"
+
+msgid "8.00x6.50\""
+msgstr "8.00x6.50 英寸"
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 毫米/秒"
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 英寸/秒"
+
+msgid "9 x 11\""
+msgstr "9 x 11 英寸"
+
+msgid "9 x 12\""
+msgstr "9 x 12 英寸"
+
+msgid "9-Pin Series"
+msgstr "9 针系列"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?未知的无效帮助命令\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3(大å·ï¼‰"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4(大å·ï¼‰"
+
+msgid "A4 (Small)"
+msgstr "A4(å°å·ï¼‰"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5(大å·ï¼‰"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "接å—作业"
+
+msgid "Accepted"
+msgstr "已接å—"
+
+msgid "Add Class"
+msgstr "添加类"
+
+msgid "Add Printer"
+msgstr "添加打å°æœº"
+
+msgid "Add RSS Subscription"
+msgstr "添加 RSS 订阅"
+
+msgid "Address"
+msgstr "地å€"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "åœ°å€ - 1 1/8 x 3 1/2 英寸"
+
+msgid "Administration"
+msgstr "管ç†"
+
+msgid "Always"
+msgstr "始终"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "涂敷器"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "错误的 NULL dests 指针"
+
+msgid "Bad OpenGroup"
+msgstr "错误的 OpenGroup"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "错误的 OpenUI/JCLOpenUI"
+
+msgid "Bad OrderDependency"
+msgstr "错误的 OrderDependency"
+
+msgid "Bad Request"
+msgstr "错误的请求"
+
+msgid "Bad SNMP version number"
+msgstr "错误的 SNMP 版本å·"
+
+msgid "Bad UIConstraints"
+msgstr "错误的 UIConstraints"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "错误的份数值 %d。"
+
+msgid "Bad custom parameter"
+msgstr "错误的自定å‚æ•°"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "错误的字体属性:%s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "错误的 number-up 值 %d。"
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "错误的 page-ranges 值 %d-%d。"
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "标题"
+
+msgid "Billing Information: "
+msgstr "å¸å•ä¿¡æ¯ï¼š"
+
+msgid "Bond Paper"
+msgstr "åŠé€æ˜Žçº¸"
+
+msgid "C0 Envelope"
+msgstr "C0 ä¿¡å°"
+
+msgid "C1 Envelope"
+msgstr "C1 ä¿¡å°"
+
+msgid "C2 Envelope"
+msgstr "C2 ä¿¡å°"
+
+msgid "C3 Envelope"
+msgstr "C3 ä¿¡å°"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "C4 ä¿¡å°"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "C5 ä¿¡å°"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "C6 ä¿¡å°"
+
+msgid "C65 Envelope"
+msgstr "C65 ä¿¡å°"
+
+msgid "C7 Envelope"
+msgstr "C7 ä¿¡å°"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "CPCL 标签打å°æœº"
+
+msgid "Cancel RSS Subscription"
+msgstr "å–消 RSS 订阅"
+
+msgid "Change Settings"
+msgstr "更改设置"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Chou3 ä¿¡å°"
+
+msgid "Chou4 Envelope"
+msgstr "Chou4 ä¿¡å°"
+
+msgid "Classes"
+msgstr "ç±»"
+
+msgid "Clean Print Heads"
+msgstr "清æ´æ‰“å°å¤´"
+
+msgid "Color"
+msgstr "彩色"
+
+msgid "Color Mode"
+msgstr "彩色模å¼"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"命令å¯èƒ½æ˜¯ç¼©å†™ã€‚命令是:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "团体å称使用ä¸å®šé•¿åº¦"
+
+msgid "Continue"
+msgstr "继续"
+
+msgid "Continuous"
+msgstr "è¿žç»­"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "创建"
+
+msgid "Created On: "
+msgstr "创建于:"
+
+msgid "Custom"
+msgstr "自定"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "切纸"
+
+msgid "Cutter"
+msgstr "切纸器"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "DL ä¿¡å°"
+
+msgid "Dark"
+msgstr "æš—"
+
+msgid "Darkness"
+msgstr "æš—"
+
+msgid "Delete Class"
+msgstr "删除类"
+
+msgid "Delete Printer"
+msgstr "删除打å°æœº"
+
+msgid "Description: "
+msgstr "æ述:"
+
+msgid "DeskJet Series"
+msgstr "DeskJet 系列"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "目的ä½ç½®â€œ%sâ€æ²¡æœ‰æŽ¥å—作业。"
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"设备:uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "热æ•ä»‹è´¨"
+
+msgid "Disabled"
+msgstr "åœç”¨"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "找ä¸åˆ°æ–‡ç¨¿ %d(在作业 %d 中)。"
+
+msgid "Double Postcard"
+msgstr "åŒé¢æ˜Žä¿¡ç‰‡"
+
+msgid "Driver Name: "
+msgstr "驱动程åºå称:"
+
+msgid "Driver Version: "
+msgstr "驱动程åºç‰ˆæœ¬ï¼š"
+
+msgid "Duplexer"
+msgstr "åŒé¢æ‰“å°å™¨"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: 无法为页é¢ä¿¡æ¯åˆ†é…内存:%s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: 无法为页é¢åºåˆ—分é…内存:%s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "EPL1 标签打å°æœº"
+
+msgid "EPL2 Label Printer"
+msgstr "EPL2 标签打å°æœº"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: 错误的字符集文件 %s\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: 错误的字符集类型 %s\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: 错误的字体æ述行:%s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: é”™è¯¯çš„æ–‡æœ¬æ–¹å‘ %s\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: 错误的文本宽度 %s\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: å‘é€ PAPSendData 请求时å‘生错误 %d:%s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: 字符集文件 %s 中没有字体\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: 打å°æœºæ²¡æœ‰å“应\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: 打å°æœºå‘é€äº†æ„外的 EOF\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: 远程主机ä¸æŽ¥å—控制文件 (%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: 远程主机ä¸æŽ¥å—æ•°æ®æ–‡ä»¶ (%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr "ERROR: 将数æ®å‘é€åˆ°æ‰“å°æœºæ—¶å‘生了超时错误\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: 无法将文件 %d 添加到作业:%s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: 无法å–消作业 %d:%s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: æ— æ³•æ‹·è´ PDF 文件"
+
+msgid "ERROR: Unable to create pipe"
+msgstr ""
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: 无法创建套接字"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr "ERROR: 无法创建临时的压缩打å°æ–‡ä»¶ï¼š%s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: 无法创建临时文件"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: 无法执行 pictwpstops:%s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: 无法执行 gs 程åº"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: 无法执行 pdftops 程åº"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: 无法 fork pictwpstops:%s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: 无法获得 PAP 请求"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: 无法获得 PAP å“应"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr "ERROR: 无法获得用于打å°æœºâ€œ%sâ€çš„ PPD 文件 - %s。\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: 无法获得默认的 AppleTalk 区域"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: 无法查找 PAP å“应"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: 无法查找 AppleTalk 打å°æœº"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: 无法确定 AppleTalk 地å€"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: 无法打开“%sâ€- %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: 无法打开 %s:%s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: 无法打开标题文件“%s†- %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: 无法打开设备文件“%sâ€ï¼š%s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: 无法打开文件“%sâ€- %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: 无法打开文件“%sâ€ï¼š%s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: 无法打开打å°æ–‡ä»¶â€œ%sâ€ï¼š%s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: 无法打开打å°æ–‡ä»¶ %s - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: 无法打开打å°æ–‡ä»¶ %s:%s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr "ERROR: 无法打开临时的压缩打å°æ–‡ä»¶ï¼š%s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: 无法读å–打å°æ•°æ®"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: 无法ä¿ç•™ç«¯å£"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: 无法æœå¯»åˆ°æ–‡ä»¶ä¸­çš„å移 %ld - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: 无法æœå¯»åˆ°æ–‡ä»¶ä¸­çš„å移 %lld - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: 无法å‘é€ LPD 命令"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: 无法å‘é€ PAP å馈请求"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: 无法å‘é€åˆå§‹ PAP å‘é€æ•°æ®è¯·æ±‚"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: 无法将打å°æ–‡ä»¶å‘é€åˆ°æ‰“å°æœº"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: 无法将尾空å‘é€åˆ°æ‰“å°æœº"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: 无法等待 pictwpstops:%s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: 无法将 %d 字节写入“%sâ€ï¼š%s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: 无法写入控制文件"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: 无法写入打å°æ•°æ®"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: 无法写入打å°æ•°æ®ï¼š%s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr "ERROR: 无法写入未压缩的文稿数æ®ï¼š%s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: 未知的文件顺åºâ€œ%sâ€\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: 未知的格å¼å­—符“%câ€\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: 未知打å°æ¨¡å¼â€œ%sâ€\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: select() 失败"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: 无法获得打å°æ–‡ä»¶çš„状æ€"
+
+msgid "Edit Configuration File"
+msgstr "编辑é…置文件"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "结æŸæ ‡é¢˜"
+
+msgid "English"
+msgstr "Chinese"
+
+msgid "Enter old password:"
+msgstr "输入旧密ç ï¼š"
+
+msgid "Enter password again:"
+msgstr "å†æ¬¡è¾“入密ç ï¼š"
+
+msgid "Enter password:"
+msgstr "输入密ç ï¼š"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"请输入您的用户å称和密ç æˆ–者 root 用户的用户å称和密ç æ¥è®¿é—®æ­¤é¡µé¢ã€‚如果您正"
+"在使用 Kerberos 鉴定,请确定您拥有的 Kerberos 票æ®æ˜¯æœ‰æ•ˆçš„。"
+
+msgid "Envelope Feed"
+msgstr "ä¿¡å°é€çº¸"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "错误策略"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "æ¯ 10 个标签"
+
+msgid "Every 2 Labels"
+msgstr "æ¯ 2 个标签"
+
+msgid "Every 3 Labels"
+msgstr "æ¯ 3 个标签"
+
+msgid "Every 4 Labels"
+msgstr "æ¯ 4 个标签"
+
+msgid "Every 5 Labels"
+msgstr "æ¯ 5 个标签"
+
+msgid "Every 6 Labels"
+msgstr "æ¯ 6 个标签"
+
+msgid "Every 7 Labels"
+msgstr "æ¯ 7 个标签"
+
+msgid "Every 8 Labels"
+msgstr "æ¯ 8 个标签"
+
+msgid "Every 9 Labels"
+msgstr "æ¯ 9 个标签"
+
+msgid "Every Label"
+msgstr "æ¯ä¸ªæ ‡ç­¾"
+
+msgid "Expectation Failed"
+msgstr "预期失败"
+
+msgid "Export Printers to Samba"
+msgstr "将打å°æœºå¯¼å‡ºä¸º Samba"
+
+msgid "FAIL\n"
+msgstr "失败\n"
+
+msgid "File Folder"
+msgstr "文件夹"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "文件夹 - 9/16 x 3 7/16 英寸"
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"文件设备 URI 已被åœç”¨ï¼è¦å¯ç”¨ï¼Œè¯·å‚阅“%s/cupsd.confâ€ä¸­çš„ FileDevice 指令。"
+
+msgid "Folio"
+msgstr "对开本"
+
+msgid "Forbidden"
+msgstr "ç¦æ­¢"
+
+msgid "General"
+msgstr "通用"
+
+msgid "Generic"
+msgstr "通用"
+
+msgid "German FanFold"
+msgstr "德国 FanFold"
+
+msgid "German FanFold Legal"
+msgstr "德国 FanFold 法定用纸"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU 使用ä¸å®šé•¿åº¦"
+
+msgid "Glossy Paper"
+msgstr "å…‰é¢çº¸"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "ç°åº¦"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "åŠå¤¹"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "åŠå¤¹ - 9/16 x 2 英寸"
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: AppleTalk 已在“系统å好设置â€ä¸­åœç”¨\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: AppleTalk 已在“系统å好设置â€ä¸­åœç”¨ã€‚\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: 正在å–消打å°ä½œä¸šâ€¦\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: 已连接到打å°æœºâ€¦\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: 正在连接到打å°æœºâ€¦\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: 控制文件已æˆåŠŸå‘é€\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr ""
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: æ•°æ®æ–‡ä»¶å·²æˆåŠŸå‘é€\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: 正在格å¼åŒ–é¡µé¢ %d…\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: 正在载入图åƒæ–‡ä»¶â€¦\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: 正在查找打å°æœºâ€¦\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: 正在打开连接\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr "INFO: 打å°æ–‡ä»¶å·²å‘é€ï¼Œæ­£åœ¨ç­‰ä¾æ‰“å°æœºç»“æŸæ‰“å°â€¦\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: 打å°æœºæ­£å¿™ï¼›å°†åœ¨ 10 秒钟åŽé‡è¯•â€¦\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: 打å°æœºæ­£å¿™ï¼›å°†åœ¨ 30 秒钟åŽé‡è¯•â€¦\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: 打å°æœºæ­£å¿™ï¼›å°†åœ¨ 5 秒钟åŽé‡è¯•â€¦\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr "INFO: 打å°æœºä¸æ”¯æŒ IPP/%d.%d,正在å°è¯• IPP/1.0…\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: 打å°æœºæ­£å¿™ï¼›å°†åœ¨ 5 秒钟åŽé‡è¯•â€¦\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: 打å°æœºå½“å‰å·²è„±æœºã€‚\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: 打å°æœºå½“å‰å·²è„±æœºã€‚\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: 打å°æœºçŽ°åœ¨è”机。\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: 打å°æœºå·²è„±æœºã€‚\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: 打å°æœºæœªè¿žæŽ¥ï¼›å°†åœ¨ 30 秒钟åŽé‡è¯•â€¦\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: 正在打å°ç¬¬ %d é¡µï¼Œå·²å®Œæˆ %d%%…\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: 正在打å°ç¬¬ %d 页…\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: 准备打å°ã€‚\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: 正在å‘é€æŽ§åˆ¶æ–‡ä»¶ï¼ˆ%lu 字节)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: 正在å‘é€æŽ§åˆ¶æ–‡ä»¶ï¼ˆ%u 字节)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: 正在å‘é€æ•°æ®\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: 正在å‘é€æ•°æ®æ–‡ä»¶ï¼ˆ%ld 字节)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: 正在å‘é€æ•°æ®æ–‡ä»¶ï¼ˆ%lld 字节)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: 正在å‘é€æ‰“å°æ•°æ®â€¦\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: å·²å‘é€æ‰“å°æ–‡ä»¶ï¼Œ%ld 字节…\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: å·²å‘é€æ‰“å°æ–‡ä»¶ï¼Œ%lld 字节…\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: 正在缓冲 LPR ä½œä¸šï¼Œå·²å®Œæˆ %.0f%%…\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr ""
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr "INFO: 无法è”系打å°æœºï¼Œæ­£åœ¨æŽ’队等待类中的下一个打å°æœºâ€¦\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: 正在使用默认的 AppleTalk 区域“%sâ€\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: 正在等待作业完æˆâ€¦\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: 正在等待打å°æœºå¯ç”¨â€¦\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "ISO B4 ä¿¡å°"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5(大å·ï¼‰"
+
+msgid "ISO B5 Envelope"
+msgstr "ISO B5 ä¿¡å°"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "ISO B6 ä¿¡å°"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "éžæ³•æŽ§åˆ¶å­—符"
+
+msgid "Illegal main keyword string"
+msgstr "éžæ³•ä¸»å…³é”®è¯å­—符串"
+
+msgid "Illegal option keyword string"
+msgstr "éžæ³•é€‰é¡¹å…³é”®è¯å­—符串"
+
+msgid "Illegal translation string"
+msgstr "éžæ³•è½¬æ¢å­—符串"
+
+msgid "Illegal whitespace character"
+msgstr "éžæ³•ç©ºç™½å­—符"
+
+msgid "Installable Options"
+msgstr "å¯å®‰è£…的选项"
+
+msgid "Installed"
+msgstr "已安装"
+
+msgid "IntelliBar Label Printer"
+msgstr "IntelliBar 标签打å°æœº"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr ""
+
+msgid "Internal error"
+msgstr "内部错误"
+
+msgid "Internet Postage 2-Part"
+msgstr "Internet 邮寄 2 部分"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Internet 邮寄 2 部分 - 2 1/4 x 7 1/2 英寸"
+
+msgid "Internet Postage 3-Part"
+msgstr "Internet 邮寄 3 部分"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Internet 邮寄 3 部分 - 2 1/4 x 7 英寸"
+
+msgid "Internet Printing Protocol"
+msgstr "Internet 打å°åè®®"
+
+msgid "Invite Envelope"
+msgstr "邀请信å°"
+
+msgid "Italian Envelope"
+msgstr "æ„大利信å°"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "作业 #%d å·²ç»ä¸­æ­¢ - ä¸èƒ½å–消。"
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "作业 #%d å·²ç»å–消 - ä¸èƒ½å–消。"
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "作业 #%d å·²ç»å®Œæˆ - ä¸èƒ½å–消。"
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "作业已完æˆ"
+
+msgid "Job Created"
+msgstr "作业已创建"
+
+msgid "Job ID: "
+msgstr "作业 ID:"
+
+msgid "Job Options Changed"
+msgstr "作业选项已更改"
+
+msgid "Job Stopped"
+msgstr "作业已åœæ­¢"
+
+msgid "Job UUID: "
+msgstr "作业 UUID:"
+
+msgid "Job is completed and cannot be changed."
+msgstr "作业已完æˆï¼Œä¸èƒ½æ›´æ”¹ã€‚"
+
+msgid "Job operation failed:"
+msgstr "作业æ“作失败:"
+
+msgid "Job state cannot be changed."
+msgstr "作业状æ€ä¸èƒ½æ›´æ”¹ã€‚"
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "作业"
+
+msgid "Kaku2 Envelope"
+msgstr "Kaku2 ä¿¡å°"
+
+msgid "Kaku3 Envelope"
+msgstr "Kaku3 ä¿¡å°"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "LPD/LPR 主机或打å°æœº"
+
+msgid "Label Printer"
+msgstr "标签打å°æœº"
+
+msgid "Label Top"
+msgstr "标签顶部"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "长地å€"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "é•¿åœ°å€ - 1 4/10 x 3 1/2 英寸"
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet 系列 PCL 4/5"
+
+msgid "Light"
+msgstr "指示ç¯"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "行多于所å…许的最大字符数(255 个字符)"
+
+msgid "List Available Printers"
+msgstr "列出å¯ç”¨çš„打å°æœº"
+
+msgid "Location: "
+msgstr "ä½ç½®ï¼š"
+
+msgid "Long-Edge (Portrait)"
+msgstr "长边(纵å‘)"
+
+msgid "Make and Model: "
+msgstr "制造和型å·ï¼š"
+
+msgid "Manual Feed"
+msgstr "手动é€çº¸"
+
+msgid "Media Dimensions: "
+msgstr "介质尺寸:"
+
+msgid "Media Limits: "
+msgstr "介质é™åˆ¶ï¼š"
+
+msgid "Media Name: "
+msgstr "介质å称:"
+
+msgid "Media Size"
+msgstr "介质大å°"
+
+msgid "Media Source"
+msgstr "介质æ¥æº"
+
+msgid "Media Tracking"
+msgstr "介质跟踪"
+
+msgid "Media Type"
+msgstr "介质类型"
+
+msgid "Medium"
+msgstr "中等"
+
+msgid "Memory allocation error"
+msgstr "内存分é…错误"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "缺少 PPD-Adobe-4.x 标头"
+
+msgid "Missing asterisk in column 1"
+msgstr "æ  1 缺少星å·"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "缺少值字符串"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"åž‹å·ï¼šname = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "修改类"
+
+msgid "Modify Printer"
+msgstr "修改打å°æœº"
+
+msgid "Monarch"
+msgstr "皇家用纸"
+
+msgid "Monarch Envelope"
+msgstr "皇家信å°"
+
+msgid "Move All Jobs"
+msgstr "移动所有作业"
+
+msgid "Move Job"
+msgstr "移动作业"
+
+msgid "Moved Permanently"
+msgstr "永久移动"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: 打å°æ–‡ä»¶å·²æŽ¥å— - 作业 ID %d。\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: 打å°æ–‡ä»¶å·²æŽ¥å— - 作业 ID 未知。\n"
+
+msgid "NULL PPD file pointer"
+msgstr "空 PPD 文件指针"
+
+msgid "Name OID uses indefinite length"
+msgstr "å称 OID 使用ä¸å®šé•¿åº¦"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "æ°¸ä¸"
+
+msgid "New Stylus Color Series"
+msgstr "新 Stylus Color 系列"
+
+msgid "New Stylus Photo Series"
+msgstr "新 Stylus Photo 系列"
+
+msgid "No"
+msgstr "å¦"
+
+msgid "No Content"
+msgstr "无内容"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "æ—  VarBind SEQUENCE"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "无活跃连接"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "无团体å称"
+
+msgid "No default printer"
+msgstr "无默认打å°æœº"
+
+msgid "No destinations added."
+msgstr "未添加目的ä½ç½®ã€‚"
+
+msgid "No error-index"
+msgstr "无错误索引"
+
+msgid "No error-status"
+msgstr "无错误状æ€"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "æ— å称 OID"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "æ—  request-id"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "找ä¸åˆ°è®¢é˜…。"
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "æ—  variable-bindings SEQUENCE"
+
+msgid "No version number"
+msgstr "无版本å·"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "éžè¿žç»­ï¼ˆæ ‡è®°æ„Ÿåº”)"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "éžè¿žç»­ï¼ˆWeb 感应)"
+
+msgid "Normal"
+msgstr "正常"
+
+msgid "Not Found"
+msgstr "找ä¸åˆ°"
+
+msgid "Not Implemented"
+msgstr "未完æˆ"
+
+msgid "Not Installed"
+msgstr "未安装"
+
+msgid "Not Modified"
+msgstr "未修改"
+
+msgid "Not Supported"
+msgstr "ä¸æ”¯æŒ"
+
+msgid "Not allowed to print."
+msgstr "ä¸å…许打å°ã€‚"
+
+msgid "Note"
+msgstr "注释"
+
+msgid "OK"
+msgstr "好"
+
+msgid "Off (1-Sided)"
+msgstr "关闭(å•é¢ï¼‰"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "网上帮助"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "打开 %s 失败:%s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup 没有 CloseGroup 优先"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI 没有 CloseUI/JCLCloseUI 优先"
+
+msgid "Operation Policy"
+msgstr "æ“作策略"
+
+msgid "Options Installed"
+msgstr "选项已安装"
+
+msgid "Options: "
+msgstr "Options: "
+
+msgid "Output Mode"
+msgstr "输出模å¼"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "打å°æœº %s 的输出已å‘é€åˆ° %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr "打å°æœº %s 的输出已å‘é€åˆ°è¿œç¨‹æ‰“å°æœº %s(在 %s 上)\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "打å°æœº %s 的输出已å‘é€åˆ° %s/%s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr "打å°æœº %s/%s 的输出已å‘é€åˆ°è¿œç¨‹æ‰“å°æœº %s(在 %s 上)\n"
+
+msgid "PASS\n"
+msgstr "通过\n"
+
+msgid "PCL Laser Printer"
+msgstr "PCL 激光打å°æœº"
+
+msgid "PRC1 Envelope"
+msgstr "PRC1 ä¿¡å°"
+
+msgid "PRC10 Envelope"
+msgstr "PRC10 ä¿¡å°"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "PRC2 ä¿¡å°"
+
+msgid "PRC3 Envelope"
+msgstr "PRC3 ä¿¡å°"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K(大å·ï¼‰"
+
+msgid "PRC4 Envelope"
+msgstr "PRC4 ä¿¡å°"
+
+msgid "PRC5 Envelope"
+msgstr "PRC5 ä¿¡å°"
+
+msgid "PRC6 Envelope"
+msgstr "PRC6 ä¿¡å°"
+
+msgid "PRC7 Envelope"
+msgstr "PRC7 ä¿¡å°"
+
+msgid "PRC8 Envelope"
+msgstr "PRC8 ä¿¡å°"
+
+msgid "PRC9 Envelope"
+msgstr "PRC9 ä¿¡å°"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "包ä¸åŒ…å« Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "包ä¸ä»¥ SEQUENCE 开始"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "%s(在 %s 上)的密ç ï¼Ÿ"
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "éœ€è¦ %s 的密ç æ‰èƒ½é€šè¿‡ SAMBA 访问 %s:"
+
+msgid "Pause Class"
+msgstr "æš‚åœç±»"
+
+msgid "Pause Printer"
+msgstr "打å°æœºæš‚åœæ‰“å°"
+
+msgid "Peel-Off"
+msgstr "剥离"
+
+msgid "Personal Envelope"
+msgstr "个人信å°"
+
+msgid "Photo"
+msgstr "照片"
+
+msgid "Photo Labels"
+msgstr "照片标签"
+
+msgid "Plain Paper"
+msgstr "普通纸张"
+
+msgid "Policies"
+msgstr "ç­–ç•¥"
+
+msgid "Port Monitor"
+msgstr "端å£ç›‘视器"
+
+msgid "PostScript Printer"
+msgstr "PostScript 打å°æœº"
+
+msgid "Postcard"
+msgstr "明信片"
+
+msgid "Print Density"
+msgstr "打å°å¯†åº¦"
+
+msgid "Print Job:"
+msgstr "打å°ä½œä¸šï¼š"
+
+msgid "Print Mode"
+msgstr "打å°æ¨¡å¼"
+
+msgid "Print Rate"
+msgstr "打å°é€ŸçŽ‡"
+
+msgid "Print Self-Test Page"
+msgstr "打å°è‡ªæµ‹è¯•é¡µé¢"
+
+msgid "Print Speed"
+msgstr "打å°é€Ÿåº¦"
+
+msgid "Print Test Page"
+msgstr "打å°æµ‹è¯•é¡µ"
+
+msgid "Print and Cut"
+msgstr "打å°å’Œåˆ‡çº¸"
+
+msgid "Print and Tear"
+msgstr "打å°å’Œæ’•çº¸"
+
+msgid "Printed For: "
+msgstr "打å°äººï¼š"
+
+msgid "Printed From: "
+msgstr "打å°è‡ªï¼š"
+
+msgid "Printed On: "
+msgstr "打å°äºŽï¼š"
+
+msgid "Printer Added"
+msgstr "打å°æœºå·²æ·»åŠ "
+
+msgid "Printer Default"
+msgstr "打å°æœºé»˜è®¤"
+
+msgid "Printer Deleted"
+msgstr "打å°æœºå·²åˆ é™¤"
+
+msgid "Printer Modified"
+msgstr "打å°æœºå·²ä¿®æ”¹"
+
+msgid "Printer Name: "
+msgstr "打å°æœºå称:"
+
+msgid "Printer Paused"
+msgstr "打å°æœºå·²æš‚åœ"
+
+msgid "Printer Settings"
+msgstr "打å°æœºè®¾ç½®"
+
+msgid "Printer:"
+msgstr "打å°æœºï¼š"
+
+msgid "Printers"
+msgstr "打å°æœº"
+
+msgid "Purge Jobs"
+msgstr "消除作业"
+
+msgid "Quarto"
+msgstr "四开"
+
+msgid "Quota limit reached."
+msgstr "已达到é…é¢é™åˆ¶ã€‚"
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr "é¡ºåº æ‰€æœ‰è€… 作业 文件 总大å°\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"é¡ºåº æ‰€æœ‰è€… 优先级 作业 文件 总大å°\n"
+
+msgid "Reject Jobs"
+msgstr "æ‹’ç»ä½œä¸š"
+
+msgid "Reprint After Error"
+msgstr "出错åŽé‡æ–°æ‰“å°"
+
+msgid "Request Entity Too Large"
+msgstr "请求实体太大"
+
+msgid "Resolution"
+msgstr "分辨率"
+
+msgid "Resume Class"
+msgstr "继续类"
+
+msgid "Resume Printer"
+msgstr "打å°æœºç»§ç»­æ‰“å°"
+
+msgid "Return Address"
+msgstr "寄信人地å€"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "å¯„ä¿¡äººåœ°å€ - 3/4 x 2 英寸"
+
+msgid "Rewind"
+msgstr "倒回"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "è¿è¡Œå‘½ä»¤ï¼š%s %s -N -A %s -c &apos;%s&apos;\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE 使用ä¸å®šé•¿åº¦"
+
+msgid "See Other"
+msgstr "请å‚阅其他"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "ä¸²å£ #%d"
+
+msgid "Server Restarted"
+msgstr "æœåŠ¡å™¨å·²é‡æ–°å¯åŠ¨"
+
+msgid "Server Security Auditing"
+msgstr "æœåŠ¡å™¨å®‰å…¨æ€§å®¡æ ¸"
+
+msgid "Server Started"
+msgstr "æœåŠ¡å™¨å·²å¯åŠ¨"
+
+msgid "Server Stopped"
+msgstr "æœåŠ¡å™¨å·²åœæ­¢"
+
+msgid "Service Unavailable"
+msgstr "æœåŠ¡ä¸å¯ç”¨"
+
+msgid "Set Allowed Users"
+msgstr "设定å…许的用户"
+
+msgid "Set As Server Default"
+msgstr "设定为æœåŠ¡å™¨é»˜è®¤"
+
+msgid "Set Class Options"
+msgstr "设定类选项"
+
+msgid "Set Printer Options"
+msgstr "设定打å°æœºé€‰é¡¹"
+
+msgid "Set Publishing"
+msgstr "设定出版"
+
+msgid "Shipping Address"
+msgstr "é€è´§åœ°å€"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "é€è´§åœ°å€ - 2 5/16 x 4 英寸"
+
+msgid "Short-Edge (Landscape)"
+msgstr "短边(横å‘)"
+
+msgid "Special Paper"
+msgstr "专用纸张"
+
+msgid "Standard"
+msgstr "标准"
+
+msgid "Starting Banner"
+msgstr "å¯åŠ¨æ ‡é¢˜"
+
+msgid "Statement"
+msgstr "报表"
+
+msgid "Stylus Color Series"
+msgstr "Stylus Color 系列"
+
+msgid "Stylus Photo Series"
+msgstr "Stylus Photo 系列"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "交æ¢åè®®"
+
+msgid "Tabloid"
+msgstr "å°æŠ¥ç”¨çº¸"
+
+msgid "Tabloid (Oversize)"
+msgstr "å°æŠ¥ç”¨çº¸ï¼ˆå¤§å·ï¼‰"
+
+msgid "Tear"
+msgstr "撕纸"
+
+msgid "Tear-Off"
+msgstr "撕纸"
+
+msgid "Tear-Off Adjust Position"
+msgstr "撕纸调整ä½ç½®"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "PPD 文件“%sâ€æœªèƒ½æ‰¾åˆ°ã€‚"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "PPD 文件“%sâ€æœªèƒ½æ‰“开。%s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"ç±»å称å¯èƒ½æœ€å¤šåŒ…å« 127 个å¯æ‰“å°çš„字符,且ä¸èƒ½åŒ…å«ç©ºæ ¼ã€æ–œçº¿ (/) æˆ–ç£…ç¬¦å· "
+"(#)。"
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr "notify-lease-duration 属性ä¸èƒ½é…åˆä½œä¸šè®¢é˜…使用。"
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"打å°æœºå称å¯èƒ½æœ€å¤šåŒ…å« 127 个å¯æ‰“å°çš„字符,且ä¸èƒ½åŒ…å«ç©ºæ ¼ã€æ–œçº¿ (/) æˆ–ç£…ç¬¦å· "
+"(#)。"
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "打å°æœºæˆ–类找ä¸åˆ°ã€‚"
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "printer-uri“%sâ€å«æœ‰æ— æ•ˆå­—符。"
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr "printer-uri 必须是“ipp://HOSTNAME/classes/CLASSNAMEâ€å½¢å¼ã€‚"
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr "printer-uri 必须是“ipp://HOSTNAME/classes/PRINTERNAMEâ€å½¢å¼ã€‚"
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr "订阅å称å¯èƒ½ä¸åŒ…å«ç©ºæ ¼ã€æ–œçº¿ (/)ã€é—®å· (?) æˆ–ç£…ç¬¦å· (#)。"
+
+msgid "There are too many subscriptions."
+msgstr "有太多订阅。"
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "热转å°ä»‹è´¨"
+
+msgid "Title: "
+msgstr "标题:"
+
+msgid "Too many active jobs."
+msgstr "太多活跃的作业。"
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "é€æ˜Žåº¦"
+
+msgid "Tray"
+msgstr "纸盒"
+
+msgid "Tray 1"
+msgstr "纸盒 1"
+
+msgid "Tray 2"
+msgstr "纸盒 2"
+
+msgid "Tray 3"
+msgstr "纸盒 3"
+
+msgid "Tray 4"
+msgstr "纸盒 4"
+
+msgid "URI Too Long"
+msgstr "URI 太长"
+
+msgid "US Executive"
+msgstr "美国行政用纸"
+
+msgid "US Fanfold"
+msgstr "美国 Fanfold"
+
+msgid "US Ledger"
+msgstr "美国总å¸ç”¨çº¸"
+
+msgid "US Legal"
+msgstr "美国法定用纸"
+
+msgid "US Legal (Oversize)"
+msgstr "美国法定用纸(大å·ï¼‰"
+
+msgid "US Letter"
+msgstr "美国信纸"
+
+msgid "US Letter (Oversize)"
+msgstr "美国信纸(大å·ï¼‰"
+
+msgid "US Letter (Small)"
+msgstr "美国信纸(å°å·ï¼‰"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "USB ä¸²å£ #%d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "无法访问 cupsd.conf 文件:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "无法添加 RSS 订阅:"
+
+msgid "Unable to add class:"
+msgstr "无法添加类:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "无法添加打å°æœºï¼š"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "无法å–消 RSS 订阅:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "无法更改 printer-is-shared 属性:"
+
+msgid "Unable to change printer:"
+msgstr "无法更改打å°æœºï¼š"
+
+msgid "Unable to change server settings:"
+msgstr "无法更改æœåŠ¡å™¨è®¾ç½®ï¼š"
+
+msgid "Unable to connect to host."
+msgstr "无法连接到主机。"
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "无法创建临时文件:"
+
+msgid "Unable to delete class:"
+msgstr "无法删除类:"
+
+msgid "Unable to delete printer:"
+msgstr "无法删除打å°æœºï¼š"
+
+msgid "Unable to do maintenance command:"
+msgstr "无法执行维护命令:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "无法获得类列表:"
+
+msgid "Unable to get class status:"
+msgstr "无法获得类状æ€ï¼š"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "无法获得打å°æœºé©±åŠ¨ç¨‹åºçš„列表:"
+
+msgid "Unable to get printer attributes:"
+msgstr "无法获得打å°æœºå±žæ€§ï¼š"
+
+msgid "Unable to get printer list:"
+msgstr "无法获得打å°æœºåˆ—表:"
+
+msgid "Unable to get printer status:"
+msgstr "无法获得打å°æœºçŠ¶æ€ï¼š"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "无法修改类:"
+
+msgid "Unable to modify printer:"
+msgstr "无法修改打å°æœºï¼š"
+
+msgid "Unable to move job"
+msgstr "无法移动作业"
+
+msgid "Unable to move jobs"
+msgstr "无法移动作业"
+
+msgid "Unable to open PPD file"
+msgstr "无法打开 PPD 文件"
+
+msgid "Unable to open PPD file:"
+msgstr "无法打开 PPD 文件:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "无法打开 cupsd.conf 文件:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "无法打å°æµ‹è¯•é¡µï¼š"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "无法è¿è¡Œâ€œ%sâ€ï¼š%s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "无法设定选项:"
+
+msgid "Unable to set server default:"
+msgstr "无法设定æœåŠ¡å™¨é»˜è®¤å€¼ï¼š"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "无法上传 cupsd.conf 文件:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "未授æƒ"
+
+msgid "Units"
+msgstr "å•ä½"
+
+msgid "Unknown"
+msgstr "未知"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "未知 printer-error-policy“%sâ€ã€‚"
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "未知 printer-op-policy“%sâ€ã€‚"
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "ä¸æ”¯æŒçš„值类型"
+
+msgid "Upgrade Required"
+msgstr "è¦æ±‚å‡çº§"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "Usage: %s job user title copies options [filename]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "Usage: %s job-id user title copies options [file]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "Usage: %s job-id user title copies options file\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "Usage: lpmove job/src dest\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "Usage: lppasswd [-g groupname]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "Usage: snmp [host-or-ip-address]\n"
+
+msgid "Value uses indefinite length"
+msgstr "Value 使用ä¸å®šé•¿åº¦"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind 使用ä¸å®šé•¿åº¦"
+
+msgid "Version uses indefinite length"
+msgstr "Version 使用ä¸å®šé•¿åº¦"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: ä»…æ·»åŠ æ‰¾åˆ°çš„å‰ %d å°æ‰“å°æœº"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: Boolean 期望 waiteof 选项“%sâ€\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: 打å°æœºæ²¡æœ‰å“应\n"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: 打å°æœºå‘é€äº†æ„外的 EOF\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: 无法打开“%s:%sâ€ï¼š%s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: 无法å‘é€ PAP 状æ€è¯·æ±‚"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: æ„外的 PAP 包(类型 %d)\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: 未知的 PAP 包(类型 %d)\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: 状æ€é€‰é¡¹â€œ%sâ€æœŸæœ›æ•°å­—\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "是"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"您必须使用 URL <A HREF=\"https://%s:%d%s\">https://%s:%d%s</A> 访问此页é¢ã€‚"
+
+msgid "You4 Envelope"
+msgstr "You4 ä¿¡å°"
+
+msgid "ZPL Label Printer"
+msgstr "ZPL 标签打å°æœº"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "已中止"
+
+msgid "canceled"
+msgstr "å·²å–消"
+
+msgid "completed"
+msgstr "已完æˆ"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr "转æ¢ï¼šä½¿ç”¨ -f 选项æ¥æŒ‡å®šè¦è½¬æ¢çš„文件。\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "cups-deviced 执行失败。"
+
+msgid "cups-driverd failed to execute."
+msgstr "cups-driverd 执行失败。"
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb:无 PPD 文件å¯ç”¨äºŽæ‰“å°æœºâ€œ%sâ€- %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl:无法连接到æœåŠ¡å™¨ï¼š%s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr "cupsd:launchd(8) 支æŒæœªç¼–译,正在以正常模å¼è¿è¡Œã€‚\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter:无法获得作业文件 - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd:-q 选项与 -v 选项ä¸å…¼å®¹ã€‚\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd:-v 选项与 -q 选项ä¸å…¼å®¹ã€‚\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "用于 %s/%s 设备:%s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "用于 %s 的设备:%s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "error-index 使用ä¸å®šé•¿åº¦"
+
+msgid "error-status uses indefinite length"
+msgstr "error-status 使用ä¸å®šé•¿åº¦"
+
+msgid "held"
+msgstr "ä¿ç•™"
+
+msgid "help\t\tget help on commands\n"
+msgstr "帮助\t\t获得命令帮助\n"
+
+msgid "idle"
+msgstr "闲置"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin: 打å°æœº %s å·²ç»æ˜¯ç±» %s çš„æˆå‘˜ã€‚\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin: 打å°æœº %s ä¸æ˜¯ç±» %s çš„æˆå‘˜ã€‚\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin: 无法连接到æœåŠ¡å™¨ï¼š%s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin: 无法打开 PPD 文件“%sâ€- %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin: 无法打开文件“%sâ€ï¼š%s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc&gt; "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove:无法连接到æœåŠ¡å™¨ï¼š%s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions:无法添加打å°æœºæˆ–实例:%s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions:无法获得 %s 的 PPD 文件:%s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd: 对ä¸èµ·ï¼Œå¯†ç è¢«æ‹’ç»ã€‚\n"
+"您的密ç å¿…须至少有 6 个字符长,ä¸èƒ½åŒ…å«\n"
+"您的用户åç§°ï¼Œå¹¶ä¸”å¿…é¡»è‡³å°‘åŒ…å« 1 个字æ¯å’Œ 1 个数字。\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd: 无法拷è´å¯†ç å­—符串:%s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd: 无法打开密ç æ–‡ä»¶ï¼š%s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd: 无法写入密ç æ–‡ä»¶ï¼š%s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr "lppasswd: 备份旧密ç æ–‡ä»¶å¤±è´¥ï¼š%s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd: 给密ç æ–‡ä»¶é‡æ–°å‘½å失败:%s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd: 用户“%sâ€å’Œç»„“%sâ€ä¸å­˜åœ¨ã€‚\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "ç±» %s çš„æˆå‘˜ï¼š\n"
+
+msgid "no entries\n"
+msgstr "æ— æ¡ç›®\n"
+
+msgid "no system default destination\n"
+msgstr "无系统默认目的ä½ç½®\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "挂起"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc:正在添加包括目录“%sâ€â€¦\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc:正在从 %s 添加/更新 UI 文本…\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc:错误的布尔值 (%1$s),在 %3$s 的第 %2$d 行。\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc:错误的å˜é‡æ›¿æ¢ ($%1$c),在 %3$s 的第 %2$d 行。\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc:%2$s 的第 %1$d 行期望布尔值。\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc:%2$s 的第 %1$d 行期望选择代ç ã€‚\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc:%2$s 的第 %1$d 行期望选择å称/文本。\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc:正在载入驱动程åºä¿¡æ¯æ–‡ä»¶â€œ%sâ€â€¦\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc:正在载入地点“%sâ€çš„ä¿¡æ¯â€¦\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc:正在从“%sâ€è½½å…¥ä¿¡æ¯â€¦\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc:无法创建 PPD 文件“%s†- %s。\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc:无法创建输出目录 %s:%s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc:无法创建输出管é“:%s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc:无法执行 cupstestppd:%s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc:找ä¸åˆ°â€œ%sâ€çš„本地化文件 - %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc:无法载入本地化文件“%s†- %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc:未定义的å˜é‡ (%1$s),在 %3$s 的第 %2$d 行。\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc:正在写入 %s…\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc:正在将 PPD 文件写入目录“%sâ€â€¦\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge:正在忽略 PPD 文件 %s…\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge:无法将 %s 备份到 %s- %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "打å°æœº %s å·²åœç”¨ï¼Œæ—¶é—´ä»Ž %s -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "打å°æœº %s 闲置,å¯ç”¨æ—¶é—´ä»Ž %s\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "打å°æœº %s çŽ°åœ¨æ­£åœ¨æ‰“å° %s-%d,å¯ç”¨æ—¶é—´ä»Ž %s\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "打å°æœº %s/%s å·²åœç”¨ï¼Œæ—¶é—´ä»Ž %s -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "打å°æœº %s/%s 闲置,å¯ç”¨æ—¶é—´ä»Ž %s\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "打å°æœº %s/%s çŽ°åœ¨æ­£åœ¨æ‰“å° %s-%d,å¯ç”¨æ—¶é—´ä»Ž %s\n"
+
+msgid "processing"
+msgstr "正在处ç†"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "请求 id 是 %s-%d(%d 个文件)\n"
+
+msgid "request-id uses indefinite length"
+msgstr "request-id 使用ä¸å®šé•¿åº¦"
+
+msgid "scheduler is not running\n"
+msgstr "调度程åºæ²¡æœ‰è¿è¡Œ\n"
+
+msgid "scheduler is running\n"
+msgstr "调度程åºæ­£åœ¨è¿è¡Œ\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "获得 %s 的状æ€å¤±è´¥ï¼š%s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "状æ€\t\t显示监控程åºå’Œé˜Ÿåˆ—的状æ€\n"
+
+msgid "stopped"
+msgstr "å·²åœæ­¢"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "系统默认目的ä½ç½®ï¼š%s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "系统默认目的ä½ç½®ï¼š%s/%s\n"
+
+msgid "unknown"
+msgstr "未知"
+
+msgid "untitled"
+msgstr "未命å"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindings 使用ä¸å®šé•¿åº¦"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " WARN %s 没有相应的选项ï¼\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " WARN 默认选择有冲çªï¼\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " WARN Duplex é€‰é¡¹å…³é”®è¯ %s å¯èƒ½æ— æ³•åƒæœŸæœ›é‚£æ ·å·¥ä½œï¼Œä¸”应当命å为 "
+#~ "Duplexï¼\n"
+#~ " REF: 页 122,节 5.17。\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr " WARN 文件混有 CRã€LF å’Œ CR LF 行尾ï¼\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " WARN è¡Œ %d 仅包å«ç©ºç™½ï¼\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " WARN 缺少 APDialogExtension 文件“%sâ€\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " WARN 缺少 APPrinterIconPath 文件“%sâ€\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " WARN éž Windows PPD 文件应当仅使用以 LF 结尾的行,而ä¸æ˜¯ä»¥ CR "
+#~ "LF 结尾的行ï¼\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " WARN 过时的 PPD 版本 %.1fï¼\n"
+#~ " REF: 页 42,节 5.2。\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s ä¸å­˜åœ¨ï¼\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s 错误的 %s 选择 %sï¼\n"
+#~ " REF: 第 122 页,第 5.17 节。\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr " %s 错误的 UTF-8“%sâ€è½¬æ¢å­—符串(用于选项“%sâ€ï¼‰ï¼\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr " %s 错误的 UTF-8“%sâ€è½¬æ¢å­—符串(用于选项“%sâ€ï¼‰ï¼Œé€‰æ‹©â€œ%sâ€ï¼\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s 错误的 cupsFilter 值“%sâ€ï¼\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s 错误的 cupsICCProfile %sï¼\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s 错误的 cupsPreFilter 值“%sâ€ï¼\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s 错误的 cupsUIConstraints %s:“%sâ€ï¼\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s 错误的语言“%sâ€ï¼\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s 空的 cupsUIConstraints %sï¼\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s 缺少“%sâ€è½¬æ¢å­—符串(用于选项“%sâ€ï¼‰ï¼\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr " %s 缺少“%sâ€è½¬æ¢å­—符串(用于选项“%sâ€ï¼‰ï¼Œé€‰æ‹©â€œ%sâ€ï¼\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr " %s 缺少选择 *%s %s(在 UIConstraints“*%s %s *%s %sâ€ä¸­ï¼‰ï¼\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s 缺少选择 *%s %s(在 cupsUIConstraints“%sâ€ä¸­ï¼‰ï¼šâ€œ%sâ€ï¼\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s 缺少 cupsICCProfile 文件“%sâ€ï¼\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s 缺少 cupsUIResolver %sï¼\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr " %s 缺少选项 %s(在 UIConstraints“*%s %s *%s %sâ€ä¸­ï¼‰ï¼\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s 缺少选项 %s(在 cupsUIConstraints“%sâ€ä¸­ï¼‰ï¼šâ€œ%sâ€ï¼\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr " %s 文件中ä¸åŒ…括基本转æ¢â€œ%sâ€ï¼\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s 所请求的 %s 没有定义选择 Noneï¼\n"
+#~ " REF: 第 122 页,第 5.17 节。\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " %s cupsICCProfile %s 散列值与 %s 冲çªï¼\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver %s 导致了一个循环ï¼\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr " **失败** %s 选择å称 %s å’Œ %s åªä¼šæ ¹æ®æƒ…况而ä¸åŒï¼\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **失败** %s 必须是 1284DeviceIDï¼\n"
+#~ " REF: 页 72,节 5.5。\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **失败** 错误的 DefaultImageableArea %sï¼\n"
+#~ " REF: 页 102,节 5.15。\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **失败** 错误的 DefaultPaperDimension %sï¼\n"
+#~ " REF: 页 103,节 5.15。\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **失败** 错误的 %s 选择 %sï¼\n"
+#~ " REF: 第 84 页,第 5.9 节。\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr " **失败** 错误的 LanguageEncoding %s - 必须是 ISOLatin1ï¼\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr " **失败** 错误的 LanguageVersion %s - 必须是 Englishï¼\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr " **失败** 选项 %s 选择 %s 的默认转æ¢å­—符串å«æœ‰ 8 ä½å­—符ï¼\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr " **失败** 选项 %s 的默认转æ¢å­—符串å«æœ‰ 8 ä½å­—符ï¼\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr " **失败** 组别å称 %s å’Œ %s åªä¼šæ ¹æ®æƒ…况而ä¸åŒï¼\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **失败** 多次出现 %s 选择å称 %sï¼\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr " **失败** 选项å称 %s å’Œ %s åªä¼šæ ¹æ®æƒ…况而ä¸åŒï¼\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " 错误的 %%%%BoundingBox:在行 %dï¼\n"
+#~ " REF: 页 39,%%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " 错误的 %%%%Page:在行 %dï¼\n"
+#~ " REF: 页 53,%%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " 错误的 %%%%Pages:在行 %dï¼\n"
+#~ " REF: 页 43,%%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " è¡Œ %d 多于 255 个字符 (%d)ï¼\n"
+#~ " REF: 页 25,行长度\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " 首行缺少 %!PS-Adobe-3.0ï¼\n"
+#~ " REF: 页 17,3.1 符åˆæ–‡ç¨¿\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " 缺少 %%EndComments 批注ï¼\n"
+#~ " REF: 页 41,%%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " 缺少或错误的 %%%%BoundingBox:批注ï¼\n"
+#~ " REF: 页 39,%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " 缺少或错误的 %%Page:批注ï¼\n"
+#~ " REF: 页 53,%%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " 缺少或错误的 %%Pages:批注ï¼\n"
+#~ " REF: 页 43,%%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " å‘现 %d 行超过 255 个字符ï¼\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " 太多 %%BeginDocument 批注ï¼\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " 太多 %%EndDocument 批注ï¼\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " WARNING: 文件å«æœ‰äºŒè¿›åˆ¶æ•°æ®ï¼\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " WARNING: 文件中没有 %%EndComments 批注ï¼\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " WARNING: 文件中的 DSC 版本 %.1f 过时ï¼\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "%s ä¸è¢«æ”¯æŒï¼"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s:ä¸çŸ¥é“è¦åšä»€ä¹ˆï¼\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr "%s:错误 - %s 个环境å˜é‡å称ä¸å­˜åœ¨ç›®çš„ä½ç½®â€œ%sâ€ï¼\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s:错误 - 错误的作业 IDï¼\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr "%s:错误 - ä¸èƒ½åŒæ—¶æ‰“å°æ–‡ä»¶å’Œæ›´æ”¹ä½œä¸šï¼\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr "%s:错误 - 如果文件或作业 ID å·²æ供,则ä¸èƒ½ä»Ž stdin 打å°ï¼\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s:错误 - &apos;-S&apos; 选项åŽæœŸæœ›å­—符集ï¼\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s:错误 - &apos;-T&apos; 选项åŽæœŸæœ›å†…容类型ï¼\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s:错误 - &apos;-n&apos; 选项åŽæœŸæœ›ä»½æ•°ï¼\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s:错误 - &apos;-#&apos; 选项åŽæœŸæœ›ä»½æ•°ï¼\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s:错误 - &apos;-P&apos; 选项åŽæœŸæœ›ç›®çš„ä½ç½®ï¼\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s:错误 - &apos;-b&apos; 选项åŽæœŸæœ›ç›®çš„ä½ç½®ï¼\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s:错误 - &apos;-d&apos; 选项åŽæœŸæœ›ç›®çš„ä½ç½®ï¼\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s:错误 - &apos;-f&apos; 选项åŽæœŸæœ›å½¢å¼ï¼\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s:错误 - &apos;-H&apos; 选项åŽæœŸæœ›ä¿ç•™å称ï¼\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s:错误 - &apos;-H&apos; 选项åŽæœŸæœ›ä¸»æœºå称ï¼\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s:错误 - &apos;-H&apos; 选项åŽæœŸæœ›ä¸»æœºå称ï¼\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s:错误 - &apos;-y&apos; 选项åŽæœŸæœ›æ¨¡å¼åˆ—表ï¼\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s:错误 - &apos;-%c&apos; 选项åŽæœŸæœ›å称ï¼\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s:错误 - &apos;-o&apos; 选项åŽæœŸæœ›é€‰é¡¹å­—符串ï¼\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s:错误 - &apos;-P&apos; 选项åŽæœŸæœ›é¡µé¢åˆ—表ï¼\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s:错误 - &apos;-%c&apos; 选项åŽæœŸæœ›ä¼˜å…ˆçº§ï¼\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s:错误 - &apos;-r&apos; 选项åŽæœŸæœ›åŽŸå› æ–‡æœ¬ï¼\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s:错误 - &apos;-t&apos; 选项åŽæœŸæœ›æ ‡é¢˜ï¼\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s:错误 - &apos;-U&apos; 选项åŽæœŸæœ›ç”¨æˆ·å称ï¼\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s:错误 - &apos;-U&apos; 选项åŽæœŸæœ›ç”¨æˆ·å称ï¼\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s:错误 - &apos;-%c&apos; 选项åŽæœŸæœ›å€¼ï¼\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr "%s:错误 -“-Wâ€é€‰é¡¹åŽéœ€è¦â€œcompletedâ€ã€â€œnot-completedâ€æˆ–“allâ€\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s:错误 - 调度程åºæ— å“应ï¼\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s:错误 - 未知目的ä½ç½®â€œ%sâ€ï¼\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s:错误 - 未知目的ä½ç½®â€œ%s/%sâ€ï¼\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s:错误 - 未知选项 &apos;%c&apos;ï¼\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s:错误 - 未知选项“%sâ€ï¼\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s:&apos;-i&apos; 选项åŽæœŸæœ›ä½œä¸š IDï¼\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s:列表“%sâ€ä¸­çš„目的ä½ç½®å称无效ï¼\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr ""
+#~ "%s:&apos;-H restart&apos; 之å‰éœ€è¦ä½œä¸š ID (&apos;-i jobid&apos;)ï¼\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s:无滤镜å¯ä»Ž %s/%s 转æ¢æˆ %s/%sï¼\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s:对ä¸èµ·ï¼Œæœªç¼–译加密支æŒï¼\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s:无法è”ç³»æœåŠ¡å™¨ï¼\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s:无法确定“%sâ€çš„ MIME 类型ï¼\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s:无法打开 %s - %s\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s:无法打开 %s - %s(在第 %d 行)。\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s:无法从“%sâ€æˆ–“%sâ€è¯»å– MIME æ•°æ®åº“ï¼\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s:未知目的ä½ç½®â€œ%sâ€ï¼\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s:未知目的 MIME 类型 %s/%sï¼\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s:未知选项 &apos;%c&apos;ï¼\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%sï¼šæœªçŸ¥çš„æº MIME 类型 %s/%sï¼\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr "%s:警告 - “%câ€æ ¼å¼ä¿®é¥°ç¬¦ä¸æ”¯æŒ - 输出å¯èƒ½ä¸æ­£ç¡®ï¼\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s:警告 - 字符集选项被忽略ï¼\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s:警告 - 内容类型选项被忽略ï¼\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s:警告 - å½¢å¼é€‰é¡¹è¢«å¿½ç•¥ï¼\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s:警告 - 模å¼é€‰é¡¹è¢«å¿½ç•¥ï¼\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr "%s:错误 - %s 个环境å˜é‡å称ä¸å­˜åœ¨ç›®çš„ä½ç½®â€œ%sâ€ï¼\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s:错误 - &apos;-o&apos; 选项åŽæœŸæœ› option=valueï¼\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "600 DPI ç°åº¦"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr "导出打å°æœºé©±åŠ¨ç¨‹åºéœ€è¦ Samba 密ç ï¼"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr "导出打å°æœºé©±åŠ¨ç¨‹åºéœ€è¦ Samba 用户å称ï¼"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "å称为“%sâ€çš„类已ç»å­˜åœ¨ï¼"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "å称为“%sâ€çš„打å°æœºå·²ç»å­˜åœ¨ï¼"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr "å°è¯•å°† %s 打å°æœºçŠ¶æ€è®¾å®šä¸ºé”™è¯¯å€¼ %dï¼"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "属性组顺åºæ··ä¹± (%x &lt; %x)ï¼"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "错误的设备 URI“%sâ€ï¼\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "错误的 device-uri“%sâ€ï¼"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "错误的 device-uri 方案“%sâ€ï¼"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "错误的 document-format“%sâ€ï¼"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "错误的文件å称缓冲区ï¼"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "错误的 job-priority 值ï¼"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "错误的 job-sheets 值“%sâ€ï¼"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "错误的 job-sheets 值类型ï¼"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "错误的 job-state 值ï¼"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "错误的 job-uri 属性“%sâ€ï¼"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "错误的 notify-pull-method“%sâ€ï¼"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "错误的 notify-recipient-uri URI“%sâ€ï¼"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "è¡Œ %d 中错误的 option + choiceï¼"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "错误的 port-monitor“%sâ€ï¼"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "错误的 printer-state 值 %dï¼"
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "é”™è¯¯çš„è¯·æ±‚ç‰ˆæœ¬å· %d.%dï¼"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "错误的订阅 IDï¼"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "字符集“%sâ€ä¸è¢«æ”¯æŒï¼"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "未能扫æ类型“%sâ€ï¼"
+
+#~ msgid "Cover open."
+#~ msgstr "机盖打开。"
+
+#~ msgid "Developer almost empty."
+#~ msgstr "显影剂差ä¸å¤šå¿«è¦ç©ºäº†ã€‚"
+
+#~ msgid "Developer empty!"
+#~ msgstr "显影剂已空ï¼"
+
+#~ msgid "Door open."
+#~ msgstr "打å°æœºé—¨æ‰“开。"
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: 错误的 %%BoundingBox:å‘现批注ï¼\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: 错误的 %%IncludeFeature:批注ï¼\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: 错误的 %%Page:文件中的批注ï¼\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: 错误的 %%PageBoundingBox:文件中的批注ï¼\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: 错误的 SCSI 设备文件“%sâ€ï¼\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: 错误的列值 %dï¼\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: 错误的 cpi 值 %fï¼\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: 错误的 lpi 值 %fï¼\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: 错误的页é¢è®¾ç½®ï¼\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: 目的ä½ç½®æ‰“å°æœºä¸å­˜åœ¨ï¼\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: é‡å¤çš„ %%BoundingBox:å‘现批注ï¼\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: é‡å¤çš„ %%Pagesï¼å‘现批注ï¼\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: 空打å°æ–‡ä»¶ï¼\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr "ERROR: %2$s 的第 %1$d 行期望引å·å­—符串ï¼\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: 致命的 USB 错误ï¼\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr "ERROR: å‘现无效的 HP-GL/2 命令,无法打å°æ–‡ä»¶ï¼\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: 缺少 %%EndPrologï¼\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: 缺少 %%EndSetupï¼\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr "ERROR: 命令行上缺少设备 URI,且无 DEVICE_URI 环境å˜é‡ï¼\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: 标题文件的第 %d 行缺少值ï¼\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr "ERROR: %2$s 的第 %1$d 行上的任何转æ¢å­—符串å‰é¢å‡éœ€è¦æœ‰ msgid è¡Œï¼\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: æ—  %%BoundingBox:标头中的批注ï¼\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: æ—  %%Pages:标头中的批注ï¼\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr "ERROR: 在 argv[0] 或 DEVICE_URI 环境å˜é‡ä¸­æ‰¾ä¸åˆ°è®¾å¤‡ URIï¼\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: 找ä¸åˆ°é¡µé¢ï¼\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: 缺纸ï¼\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: PRINTER 环境å˜é‡æœªå®šä¹‰ï¼\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: 打å°æ–‡ä»¶ä¸è¢«æŽ¥å— (%s)ï¼\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: 打å°æœºæ²¡æœ‰å“应ï¼\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: 无法创建临时文件 - %s。\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: 无法创建临时文件:%s\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: 无法获得作业 %d 属性 (%s)ï¼\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: 无法获得打å°æœºçŠ¶æ€ (%s)ï¼\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: 找ä¸åˆ°æ‰“å°æœº &apos;%s&apos; çš„ä½ç½®ï¼\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: 无法打开图åƒæ–‡ä»¶è¿›è¡Œæ‰“å°ï¼\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: 无法打开临时文件"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: æ— æ³•æ‰“å° %d 个文本æ ï¼\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: æ— æ³•æ‰“å° %dx%d 页文本页é¢ï¼\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: 无法读å–打å°æ•°æ®ï¼\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: 无法å‘é€æ‰“å°æ•°æ® (%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: 无法å‘é€æ‰“å°æ•°æ®ï¼\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: 无法将 %d 字节写入打å°æœºï¼\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr "ERROR: 无法将光栅数æ®å†™å…¥é©±åŠ¨ç¨‹åºï¼\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: 无法写入到临时文件"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: %2$s 的第 %1$d 行有æ„外的文本ï¼\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: 未知的加密选项值“%sâ€ï¼\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: “%sâ€çš„ä¿¡æ¯ç›®å½•æ ¼å¼æœªçŸ¥ï¼\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: 未知选项“%sâ€ï¼Œå…¶å€¼ä¸ºâ€œ%sâ€ï¼\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: 未知的版本选项值“%sâ€ï¼\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr "ERROR: ä¸è¢«æ”¯æŒçš„亮度值 %s,使用 brightness=100ï¼\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: ä¸è¢«æ”¯æŒçš„ç°åº¦ç³»æ•°å€¼ %s,使用 gamma=1000ï¼\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr "ERROR: ä¸è¢«æ”¯æŒçš„ number-up 值 %d,使用 number-up=1ï¼\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: ä¸è¢«æ”¯æŒçš„ number-up-layout 值 %s,使用 number-up-layout=lrtbï¼\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr "ERROR: ä¸è¢«æ”¯æŒçš„ page-border 值 %s,使用 page-border=noneï¼\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr "ERROR: 检测到 doc_printf 溢出(%d 字节),正在中止ï¼\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr "ERROR: pdftops æ»¤é•œåœ¨ä¿¡å· %d 处崩溃ï¼\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr "ERROR: pdftops 滤镜退出,状æ€ä¸º %dï¼\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops å› ä¿¡å· %d 退出ï¼\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops å› çŠ¶æ€ %d 退出ï¼\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr "ERROR: å¯æ¢å¤ï¼šæ— æ³•è¿žæŽ¥åˆ°æ‰“å°æœºï¼›å°†åœ¨ 30 秒钟åŽé‡è¯•â€¦\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "空 PPD 文件ï¼"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "ERROR: &apos;-h&apos; 选项åŽéœ€è¦ä¸»æœºå称ï¼\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "加热鼓温度过高ï¼"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "加热鼓温度过低ï¼"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "获得 printer-uri 属性而ä¸æ˜¯ job-idï¼"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "墨水/碳粉差ä¸å¤šå¿«è¦ç©ºäº†ã€‚"
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "墨水/碳粉已空ï¼"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "墨水/碳粉废物箱差ä¸å¤šå¿«è¦æ»¡äº†ã€‚"
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "墨水/碳粉废物箱已满ï¼"
+
+#~ msgid "Interlock open."
+#~ msgstr "互é”打开。"
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "作业 #%d ä¸èƒ½é‡æ–°å¼€å§‹ - 无文件ï¼"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "作业 #%d ä¸å­˜åœ¨ï¼"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "作业 #%d 已结æŸï¼Œä¸èƒ½æ›´æ”¹ï¼"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "作业 #%d 没有完æˆï¼"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "作业 #%d 没有等待进行签定ï¼"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "作业 #%d 没有等待ï¼"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "作业 #%s ä¸å­˜åœ¨ï¼"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "作业 %d 找ä¸åˆ°ï¼"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "作业订阅ä¸èƒ½ç»­è®¢ï¼"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "语言“%sâ€ä¸è¢«æ”¯æŒï¼"
+
+#~ msgid "Media jam!"
+#~ msgstr "å¡çº¸ï¼"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "介质盒差ä¸å¤šå¿«è¦ç©ºäº†ã€‚"
+
+#~ msgid "Media tray empty!"
+#~ msgstr "介质盒已空ï¼"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "缺少介质盒ï¼"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "介质盒需è¦è£…纸。"
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "缺少 document-number 属性ï¼"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "è¡Œ %d 缺少åŒå¼•å·ï¼"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "缺少形å¼å˜é‡ï¼"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "缺少 notify-subscription-ids 属性ï¼"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "缺少 requesting-user-name 属性ï¼"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "缺少è¦æ±‚的属性ï¼"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "è¡Œ %d 缺少值ï¼"
+
+#~ msgid "No PPD name!"
+#~ msgstr "æ—  PPD å称ï¼"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "未安装 Windows 打å°æœºé©±åŠ¨ç¨‹åºï¼"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "%s 上没有活跃的作业ï¼"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "请求中没有属性ï¼"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "未æ供鉴定信æ¯ï¼"
+
+#~ msgid "No file!?!"
+#~ msgstr "无文件!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "无修改时间ï¼"
+
+#~ msgid "No printer name!"
+#~ msgstr "无打å°æœºå称ï¼"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "找ä¸åˆ°ç±»çš„ printer-uriï¼"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "找ä¸åˆ° printer-uriï¼"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "请求中没有 printer-uriï¼"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "请求中没有订阅属性ï¼"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC 的使用寿命差ä¸å¤šå¿«è¦åˆ°äº†ã€‚"
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC 的使用寿命已到ï¼"
+
+#~ msgid "Out of toner!"
+#~ msgstr "碳粉ä¸è¶³ï¼"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "出纸箱差ä¸å¤šå¿«è¦æ»¡äº†ã€‚"
+
+#~ msgid "Output bin full!"
+#~ msgstr "出纸箱已满ï¼"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "缺少输出盒ï¼"
+
+#~ msgid "Printer offline."
+#~ msgstr "打å°æœºå·²è„±æœºã€‚"
+
+#~ msgid "SCSI Printer"
+#~ msgstr "SCSI 打å°æœº"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "notify-user-data 值太大(%d &gt; 63 个八ä½å­—节)ï¼"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "打å°æœºæˆ–类没有共享ï¼"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "éœ€è¦ printer-uri 属性。"
+
+#~ msgid "Toner low."
+#~ msgstr "碳粉ä¸è¶³ã€‚"
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "太多 job-sheets 值 (%d > 2)ï¼"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "太多 printer-state-reasons 值 (%d > %d)ï¼"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "无法为目的ä½ç½®â€œ%sâ€æ·»åŠ ä½œä¸šï¼"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "无法为文件类型分é…内存ï¼"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr "æ— æ³•æ‹·è´ 64 ä½ CUPS 打å°æœºé©±åŠ¨ç¨‹åºæ–‡ä»¶ (%d)ï¼"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr "æ— æ³•æ‹·è´ 64 ä½ Windows 打å°æœºé©±åŠ¨ç¨‹åºæ–‡ä»¶ (%d)ï¼"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr "æ— æ³•æ‹·è´ CUPS 打å°æœºé©±åŠ¨ç¨‹åºæ–‡ä»¶ (%d)!"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "æ— æ³•æ‹·è´ PPD 文件 - %sï¼"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "æ— æ³•æ‹·è´ PPD 文件ï¼"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr "æ— æ³•æ‹·è´ Windows 2000 打å°æœºé©±åŠ¨ç¨‹åºæ–‡ä»¶ (%d)ï¼"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr "æ— æ³•æ‹·è´ Windows 9x 打å°æœºé©±åŠ¨ç¨‹åºæ–‡ä»¶ (%d)ï¼"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "无法拷è´æŽ¥å£è„šæœ¬ - %sï¼"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "无法创建 printer-uriï¼"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr "无法编辑大于 1MB çš„ cupsd.conf 文件ï¼"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "找ä¸åˆ°ä½œä¸šçš„目的ä½ç½®ï¼"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "找ä¸åˆ°æ‰“å°æœº\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr "无法安装 Windows 2000 打å°æœºé©±åŠ¨ç¨‹åºæ–‡ä»¶ (%d)ï¼"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr "无法安装 Windows 9x 打å°æœºé©±åŠ¨ç¨‹åºæ–‡ä»¶ (%d)ï¼"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "无法打开文稿 %d(在作业 %d 中)ï¼"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "无法将命令å‘é€åˆ°æ‰“å°æœºé©±åŠ¨ç¨‹åºï¼"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "无法获得 Windows 打å°æœºé©±åŠ¨ç¨‹åº (%d)ï¼"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "无法使用传统 USB 类驱动程åºï¼\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "未知打å°æœºé”™è¯¯ (%s)ï¼"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "ä¸æ”¯æŒçš„字符集“%sâ€ï¼"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "ä¸è¢«æ”¯æŒçš„压缩“%sâ€ï¼"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "ä¸è¢«æ”¯æŒçš„压缩属性 %sï¼"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "ä¸è¢«æ”¯æŒçš„æ ¼å¼â€œ%sâ€ï¼"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "ä¸è¢«æ”¯æŒçš„æ ¼å¼ &apos;%s&apos;ï¼"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "ä¸è¢«æ”¯æŒçš„æ ¼å¼ &apos;%s/%s&apos;ï¼"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: 读å–é¢é€šé“请求失败ï¼\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr "WARNING: ä¸èƒ½é€šè¿‡ IncludeFeature 包括选项“%sâ€ï¼\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr "WARNING: %d 秒钟åŽï¼Œè¿œç¨‹ä¸»æœºæ²¡æœ‰å“应命令状æ€å­—节ï¼\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr "WARNING: %d 秒钟åŽï¼Œè¿œç¨‹ä¸»æœºæ²¡æœ‰å“应控制状æ€å­—节ï¼\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr "WARNING: %d 秒钟åŽï¼Œè¿œç¨‹ä¸»æœºæ²¡æœ‰å“应数æ®çŠ¶æ€å­—节ï¼\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr "WARNING: SCSI 命令超时 (%d);正在é‡è¯•â€¦\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr ""
+#~ "WARNING: 此文稿ä¸ç¬¦åˆ Adobe Document Structuring Conventions çš„è¦æ±‚,å¯èƒ½"
+#~ "无法正确打å°ï¼\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: 未知选择“%sâ€ï¼ˆç”¨äºŽé€‰é¡¹â€œ%sâ€ï¼‰ï¼\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: 未知选项“%sâ€ï¼\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: ä¸è¢«æ”¯æŒçš„波特率 %sï¼\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr "WARNING: å¯æ¢å¤ï¼šç½‘络主机“%sâ€æ­£å¿™ï¼›å°†åœ¨ %d 秒钟åŽé‡è¯•â€¦\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr "警告,未安装 Windows 2000 打å°æœºé©±åŠ¨ç¨‹åºï¼"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl:未知选项“%sâ€ï¼\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl:未知选项“-%câ€ï¼\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr "cupsd:“-câ€é€‰é¡¹åŽæœŸæœ›é…置文件å称ï¼\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd:无法获得当å‰ç›®å½•ï¼\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd:未知自å˜é‡â€œ%sâ€- 正在中止ï¼\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd:未知选项“%câ€- 正在中止ï¼\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilterï¼šæ— æ•ˆçš„æ–‡ç¨¿ç¼–å· %dï¼\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter:无效的作业 ID %dï¼\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter:åªèƒ½æŒ‡å®šä¸€ä¸ªæ–‡ä»¶å称ï¼\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter:无法创建临时文件:%s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "job-printer-uri 属性丢失ï¼"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr "lpadmin: ç±»å称åªèƒ½å«æœ‰å¯æ‰“å°å­—符ï¼\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin: &apos;-P&apos; 选项åŽæœŸæœ› PPDï¼\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr "lpadmin: &apos;-u&apos; 选项åŽæœŸæœ› allow/deny:userlistï¼\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin: &apos;-r&apos; 选项åŽæœŸæœ›ç±»ã€‚\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin: &apos;-c&apos; 选项åŽæœŸæœ›ç±»å称ï¼\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin: &apos;-D&apos; 选项åŽæœŸæœ›æè¿°ï¼\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin: &apos;-v&apos; 选项åŽæœŸæœ›è®¾å¤‡ URIï¼\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin: &apos;-I&apos; 选项åŽæœŸæœ›æ–‡ä»¶ç±»åž‹ï¼\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin: &apos;-h&apos; 选项åŽæœŸæœ›ä¸»æœºå称ï¼\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin: &apos;-i&apos; 选项åŽæœŸæœ›æŽ¥å£ï¼\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin: &apos;-L&apos; 选项åŽæœŸæœ›ä½ç½®ï¼\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin: &apos;-m&apos; 选项åŽæœŸæœ›åž‹å·ï¼\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin: &apos;-o&apos; 选项åŽæœŸæœ› name=valueï¼\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin: &apos;-p&apos; 选项åŽæœŸæœ›æ‰“å°æœºï¼\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin: &apos;-d&apos; 选项åŽæœŸæœ›æ‰“å°æœºå称ï¼\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin: &apos;-x&apos; 选项åŽæœŸæœ›æ‰“å°æœºæˆ–ç±»ï¼\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin: 会å‘现æˆå‘˜å称ï¼\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr "lpadmin: 打å°æœºå称åªèƒ½å«æœ‰å¯æ‰“å°å­—符ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: 无法将打å°æœºæ·»åŠ åˆ°ç±»ï¼š\n"
+#~ " 您必须先指定一个打å°æœºå称ï¼\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin: 无法创建临时文件 - %s\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin: 无法创建临时文件:%s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: 无法从类中去掉打å°æœºï¼š\n"
+#~ " 您必须先指定一个打å°æœºå称ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: 无法设定 PPD 文件:\n"
+#~ " 您必须先指定一个打å°æœºå称ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: 无法设定设备 URI:\n"
+#~ " 您必须先指定一个打å°æœºå称ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: 无法设定接å£è„šæœ¬æˆ– PPD 文件:\n"
+#~ " 您必须先指定一个打å°æœºå称ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: 无法设定接å£è„šæœ¬ï¼š\n"
+#~ " 您必须先指定一个打å°æœºå称ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: 无法设定打å°æœºæ述:\n"
+#~ " 您必须先指定一个打å°æœºå称ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: 无法设定打å°æœºä½ç½®ï¼š\n"
+#~ " 您必须先指定一个打å°æœºå称ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin: 无法设定打å°æœºé€‰é¡¹ï¼š\n"
+#~ " 您必须先指定一个打å°æœºå称ï¼\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin: 未知的å…许/æ‹’ç»é€‰é¡¹â€œ%sâ€ï¼\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin: 未知自å˜é‡ &apos;%s&apos;ï¼\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin: 未知选项 &apos;%c&apos;ï¼\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin: 警告 - 内容类型列表被忽略ï¼\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr "lpinfo:--device-id åŽæœŸæœ›çš„ 1284 设备 ID 字符串ï¼\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo:--language åŽæœŸæœ›çš„语言ï¼\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo:--make-and-model åŽæœŸæœ›çš„制造和型å·ï¼\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo:--product åŽæœŸæœ›çš„产å“字符串ï¼\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo:--exclude-schemes åŽæœŸæœ›çš„方案列表ï¼\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo:--include-schemes åŽæœŸæœ›çš„方案列表ï¼\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo:--timeout åŽæœŸæœ›çš„超时ï¼\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo:未知自å˜é‡ &apos;%s&apos;ï¼\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo:未知选项 &apos;%c&apos;ï¼\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo:未知选项“%sâ€ï¼\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove:未知自å˜é‡ &apos;%s&apos;ï¼\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove:未知选项 &apos;%c&apos;ï¼\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions:无打å°æœº!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions:无法打开 %s çš„ PPD 文件ï¼\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions:未知打å°æœºæˆ–ç±»ï¼\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd: 仅根用户æ‰å¯ä»¥æ·»åŠ æˆ–删除密ç ï¼\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd: 密ç æ–‡ä»¶æ­£å¿™ï¼\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd: 密ç æ–‡ä»¶æœªæ›´æ–°ï¼\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd: 对ä¸èµ·ï¼Œå¯†ç ä¸åŒ¹é…ï¼\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd: 对ä¸èµ·ï¼Œå¯†ç ä¸åŒ¹é…ï¼\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr "lpstat: 错误 - %s 个环境å˜é‡å称ä¸å­˜åœ¨ç›®çš„ä½ç½®â€œ%sâ€ï¼\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "notify-events 未指定ï¼"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "notify-recipient-uri URI“%sâ€å·²ç»åœ¨ä½¿ç”¨ï¼"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "notify-recipient-uri URI“%sâ€ä½¿ç”¨æœªçŸ¥æ–¹æ¡ˆï¼"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d ä¸å¥½ï¼"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc:错误的分辨率å称“%1$sâ€ï¼Œåœ¨ %3$s 的第 %2$d 行。\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdcï¼šé”™è¯¯çš„å…³é”®è¯ %1$s,在 %3$s 的第 %2$d 行。\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc:在 %2$s 的第 %1$d 行找到选择,但没有选项ï¼\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc:地点 %1$s çš„ #po é‡å¤ï¼ˆåœ¨ %3$s 的第 %2$d 行)ï¼\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望滤镜定义ï¼\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望程åºå称ï¼\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 Font åŽé¢æœŸæœ›å­—符集ï¼\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望 ColorModel 的颜色顺åºï¼\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望 ColorModel 的颜色空间ï¼\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望 ColorModel 的压缩ï¼\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望 UIConstraints 的约æŸå­—符串ï¼\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc:%2$s 的第 %1$d 行上的 DriverType åŽé¢æœŸæœ›é©±åŠ¨ç¨‹åºç±»åž‹å…³é”®è¯ï¼\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 Duplex åŽé¢æœŸæœ›åŒé¢ç±»åž‹ï¼\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 Font åŽé¢æœŸæœ›ç¼–ç ï¼\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc:#po %1$s åŽé¢æœŸæœ›æ–‡ä»¶å称(在 %3$s 的第 %2$d 行)ï¼\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望组别å称/文本。\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望包括文件å称ï¼\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望整数ï¼\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 #po åŽé¢æœŸæœ›åœ°ç‚¹ï¼\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc:%1$s åŽé¢æœŸæœ›å称(在 %3$s 的第 %2$d 行)ï¼\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 FileName åŽé¢æœŸæœ›å称ï¼\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 Font åŽé¢æœŸæœ›å称ï¼\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 Manufacturer åŽé¢æœŸæœ›å称ï¼\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 MediaSize åŽé¢æœŸæœ›å称ï¼\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 ModelName åŽé¢æœŸæœ›å称ï¼\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 PCFileName åŽé¢æœŸæœ›å称ï¼\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc:%1$s åŽé¢æœŸæœ›å称/文本(在 %3$s 的第 %2$d 行)ï¼\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 Installable åŽé¢æœŸæœ›å称/文本ï¼\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 Resolution åŽé¢æœŸæœ›å称/文本ï¼\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望 ColorModel çš„å称/文本组åˆï¼\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望选项å称/文本ï¼\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望选项区ï¼\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望选项类型ï¼\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 Resolution åŽé¢æœŸæœ›è¦†ç›–字段ï¼\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望实数ï¼\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc:%2$s 的第 %1$d 行上的 ColorProfile åŽé¢æœŸæœ›åˆ†è¾¨çŽ‡/介质类型ï¼\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc:%2$s 的第 %1$d 行上的 SimpleColorProfile åŽé¢æœŸæœ›åˆ†è¾¨çŽ‡/介质类型ï¼\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc:%1$s åŽé¢æœŸæœ›é€‰æ‹©å™¨ï¼ˆåœ¨ %3$s 的第 %2$d 行)ï¼\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 Font åŽé¢æœŸæœ›çŠ¶æ€ï¼\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 Copyright åŽé¢æœŸæœ›å­—符串ï¼\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 Version åŽé¢æœŸæœ›å­—符串ï¼\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行期望两个选项å称ï¼\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc:%1$s åŽé¢æœŸæœ›å€¼ï¼ˆåœ¨ %3$s 的第 %2$d 行)ï¼\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上的 Font åŽé¢æœŸæœ›ç‰ˆæœ¬ï¼\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc:无效的 #include/#po 文件å称“%sâ€ï¼\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行有无效的滤镜æˆæœ¬ï¼\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行有无效的滤镜空 MIME 类型ï¼\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行有无效的滤镜空程åºå称ï¼\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc:无效的选项区“%1$sâ€ï¼Œåœ¨ %3$s 的第 %2$d è¡Œï¼\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc:无效的选项类型“%1$sâ€ï¼Œåœ¨ %3$s 的第 %2$d è¡Œï¼\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc:“%sâ€çš„末尾丢失 #endifï¼\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行丢失 #ifï¼\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc:没有为地点 %s æ供信æ¯ç›®å½•ï¼\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr "ppdc:选项 %1$s 被é‡æ–°å®šä¹‰ä¸ºä¸åŒçš„类型(在 %3$s 的第 %2$d 行)ï¼\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr "ppdc:选项约æŸå¿…须在 %2$s 的第 %1$d 行上指定的 *name 中ï¼\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行嵌套的 #if 太多ï¼\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc:找ä¸åˆ° #po 文件 %1$s(在 %3$s 的第 %2$d 行)ï¼\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc:找ä¸åˆ°åŒ…括文件“%1$sâ€ï¼ˆåœ¨ %3$s 的第 %2$d 行)ï¼\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc:未知的驱动程åºç±»åž‹ %1$s,在 %3$s 的第 %2$d è¡Œï¼\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc:未知的åŒé¢ç±»åž‹â€œ%1$sâ€ï¼Œåœ¨ %3$s 的第 %2$d è¡Œï¼\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc:未知的介质大å°â€œ%1$sâ€ï¼Œåœ¨ %3$s 的第 %2$d è¡Œï¼\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc:未知的令牌“%1$sâ€ï¼Œå‡ºçŽ°åœ¨ %3$s 的第 %2$d è¡Œï¼\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr "ppdc:实数“%1$sâ€ä¸­æœ‰æœªçŸ¥çš„末尾字符(在 %3$s 的第 %2$d 行)ï¼\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr "ppdc:未结æŸçš„字符串以 %1$c 开头(在 %3$s 的第 %2$d 行)ï¼\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge:错误的 LanguageVersion“%sâ€ï¼ˆåœ¨ %s 中)ï¼\n"
diff --git a/locale/cups_zh_TW.po b/locale/cups_zh_TW.po
new file mode 100644
index 000000000..d4a9352cc
--- /dev/null
+++ b/locale/cups_zh_TW.po
@@ -0,0 +1,7018 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: CUPS 1.4\n"
+"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n"
+"POT-Creation-Date: 2010-03-03 10:36-0800\n"
+"PO-Revision-Date: 2009-02-16 12:00-0800\n"
+"Last-Translator: Apple Inc.\n"
+"Language-Team: Apple Inc.\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "\t\t(all)\n"
+msgstr "\t\t(全部)\n"
+
+msgid "\t\t(none)\n"
+msgstr "\t\t(無)\n"
+
+#, c-format
+msgid "\t%d entries\n"
+msgstr "\t%d 個項目\n"
+
+msgid "\tAfter fault: continue\n"
+msgstr "\t出錯後:繼續\n"
+
+msgid "\tAlerts:"
+msgstr "\tWARNING: "
+
+msgid "\tBanner required\n"
+msgstr "\t需è¦æ¨™èªžï¼š\n"
+
+msgid "\tCharset sets:\n"
+msgstr "\t字元集:\n"
+
+msgid "\tConnection: direct\n"
+msgstr "\t連線:直接\n"
+
+msgid "\tConnection: remote\n"
+msgstr "\t連線:é ç«¯\n"
+
+msgid "\tDefault page size:\n"
+msgstr "\té è¨­é é¢å¤§å°ï¼š\n"
+
+msgid "\tDefault pitch:\n"
+msgstr "\té è¨­éŸ³é«˜ï¼š\n"
+
+msgid "\tDefault port settings:\n"
+msgstr "\té è¨­é€£æŽ¥åŸ è¨­å®šï¼š\n"
+
+#, c-format
+msgid "\tDescription: %s\n"
+msgstr "\tæ述:%s\n"
+
+msgid ""
+"\tForm mounted:\n"
+"\tContent types: any\n"
+"\tPrinter types: unknown\n"
+msgstr ""
+"\tå·²è£è¼‰çš„表單:\n"
+"\t內容類型:任æ„\n"
+"\tå°è¡¨æ©Ÿé¡žåž‹ï¼šæœªçŸ¥\n"
+
+msgid "\tForms allowed:\n"
+msgstr "\tå…許的表單:\n"
+
+#, c-format
+msgid "\tInterface: %s.ppd\n"
+msgstr "\t介é¢ï¼š%s.ppd\n"
+
+#, c-format
+msgid "\tInterface: %s/interfaces/%s\n"
+msgstr "\t介é¢ï¼š%s/interfaces/%s\n"
+
+#, c-format
+msgid "\tInterface: %s/ppd/%s.ppd\n"
+msgstr "\t介é¢ï¼š%s/ppd/%s.ppd\n"
+
+#, c-format
+msgid "\tLocation: %s\n"
+msgstr "\tä½ç½®ï¼š%s\n"
+
+msgid "\tOn fault: no alert\n"
+msgstr "\t出錯時:無æ示\n"
+
+msgid "\tUsers allowed:\n"
+msgstr "\tå…許的使用者:\n"
+
+msgid "\tUsers denied:\n"
+msgstr "\t拒絕的使用者:\n"
+
+msgid "\tdaemon present\n"
+msgstr "\tç¾æœ‰çš„æœå‹™ç¨‹å¼\n"
+
+msgid "\tno entries\n"
+msgstr "\tç„¡é …ç›®\n"
+
+#, c-format
+msgid "\tprinter is on device '%s' speed -1\n"
+msgstr "\tå°è¡¨æ©Ÿç‚ºè¨­å‚™ '%s' 的速度 -1\n"
+
+msgid "\tprinting is disabled\n"
+msgstr "\tå·²åœç”¨åˆ—å°\n"
+
+msgid "\tprinting is enabled\n"
+msgstr "\t已啟用列å°\n"
+
+#, c-format
+msgid "\tqueued for %s\n"
+msgstr "\t%s 已佇列\n"
+
+msgid "\tqueuing is disabled\n"
+msgstr "\tå·²åœç”¨ä½‡åˆ—\n"
+
+msgid "\tqueuing is enabled\n"
+msgstr "\t已啟用佇列\n"
+
+msgid "\treason unknown\n"
+msgstr "\t原因未知\n"
+
+msgid ""
+"\n"
+" DETAILED CONFORMANCE TEST RESULTS\n"
+msgstr ""
+"\n"
+" 詳細的相似度測試çµæžœ\n"
+
+msgid " REF: Page 15, section 3.1.\n"
+msgstr " åƒè€ƒï¼šç¬¬ 15 é ï¼Œç« ç¯€ 3.1。\n"
+
+msgid " REF: Page 15, section 3.2.\n"
+msgstr " åƒè€ƒï¼šç¬¬ 15 é ï¼Œç« ç¯€ 3.2。\n"
+
+msgid " REF: Page 19, section 3.3.\n"
+msgstr " åƒè€ƒï¼šç¬¬ 19 é ï¼Œç« ç¯€ 3.3。\n"
+
+msgid " REF: Page 20, section 3.4.\n"
+msgstr " åƒè€ƒï¼šç¬¬ 20 é ï¼Œç« ç¯€ 3.4。\n"
+
+msgid " REF: Page 27, section 3.5.\n"
+msgstr " åƒè€ƒï¼šç¬¬ 27 é ï¼Œç« ç¯€ 3.5。\n"
+
+msgid " REF: Page 42, section 5.2.\n"
+msgstr " åƒè€ƒï¼šç¬¬ 42 é ï¼Œç« ç¯€ 5.2。\n"
+
+msgid " REF: Pages 16-17, section 3.2.\n"
+msgstr " åƒè€ƒï¼šç¬¬ 16-17 é ï¼Œç« ç¯€ 3.2。\n"
+
+msgid " REF: Pages 42-45, section 5.2.\n"
+msgstr " åƒè€ƒï¼šç¬¬ 42-45 é ï¼Œç« ç¯€ 5.2。\n"
+
+msgid " REF: Pages 45-46, section 5.2.\n"
+msgstr " åƒè€ƒï¼šç¬¬ 45-46 é ï¼Œç« ç¯€ 5.2。\n"
+
+msgid " REF: Pages 48-49, section 5.2.\n"
+msgstr " åƒè€ƒï¼šç¬¬ 48-49 é ï¼Œç« ç¯€ 5.2。\n"
+
+msgid " REF: Pages 52-54, section 5.2.\n"
+msgstr " åƒè€ƒï¼šç¬¬ 52-54 é ï¼Œç« ç¯€ 5.2。\n"
+
+#, c-format
+msgid " %-39.39s %.0f bytes\n"
+msgstr " %-39.39s %.0f byte\n"
+
+#, c-format
+msgid " PASS Default%s\n"
+msgstr " é€šéŽ Default%s\n"
+
+msgid " PASS DefaultImageableArea\n"
+msgstr " é€šéŽ DefaultImageableArea\n"
+
+msgid " PASS DefaultPaperDimension\n"
+msgstr " é€šéŽ DefaultPaperDimension\n"
+
+msgid " PASS FileVersion\n"
+msgstr " é€šéŽ FileVersion\n"
+
+msgid " PASS FormatVersion\n"
+msgstr " é€šéŽ FormatVersion\n"
+
+msgid " PASS LanguageEncoding\n"
+msgstr " é€šéŽ LanguageEncoding\n"
+
+msgid " PASS LanguageVersion\n"
+msgstr " é€šéŽ LanguageVersion\n"
+
+msgid " PASS Manufacturer\n"
+msgstr " é€šéŽ Manufacturer\n"
+
+msgid " PASS ModelName\n"
+msgstr " é€šéŽ ModelName\n"
+
+msgid " PASS NickName\n"
+msgstr " é€šéŽ NickName\n"
+
+msgid " PASS PCFileName\n"
+msgstr " é€šéŽ PCFileName\n"
+
+msgid " PASS PSVersion\n"
+msgstr " é€šéŽ PSVersion\n"
+
+msgid " PASS PageRegion\n"
+msgstr " é€šéŽ PageRegion\n"
+
+msgid " PASS PageSize\n"
+msgstr " é€šéŽ PageSize\n"
+
+msgid " PASS Product\n"
+msgstr " é€šéŽ Product\n"
+
+msgid " PASS ShortNickName\n"
+msgstr " é€šéŽ ShortNickName\n"
+
+#, c-format
+msgid ""
+" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+" (constraint=\"%s %s %s %s\")\n"
+msgstr ""
+" 警告 “%s %sâ€èˆ‡â€œ%s %sâ€è¡çª\n"
+" (é™åˆ¶=“%s %s %s %sâ€ï¼‰\n"
+
+#, c-format
+msgid " WARN %s has no corresponding options\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN %s shares a common prefix with %s\n"
+" REF: Page 15, section 3.2.\n"
+msgstr ""
+" 警告 %s 與 %s 共用一般的å‰ç½®ç¢¼\n"
+" åƒè€ƒï¼šç¬¬ 15 é ï¼Œç« ç¯€ 3.2。\n"
+
+msgid " WARN Default choices conflicting\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Duplex option keyword %s may not work as expected and should "
+"be named Duplex\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+msgid " WARN File contains a mix of CR, LF, and CR LF line endings\n"
+msgstr ""
+
+msgid ""
+" WARN LanguageEncoding required by PPD 4.3 spec.\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" 警告 PPD 4.3 è¦æ ¼è¦æ±‚有 LanguageEncoding\n"
+" åƒè€ƒï¼šç¬¬ 56-57 é ï¼Œç« ç¯€ 5.3。\n"
+
+#, c-format
+msgid " WARN Line %d only contains whitespace\n"
+msgstr ""
+
+msgid ""
+" WARN Manufacturer required by PPD 4.3 spec.\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" 警告 PD 4.3 è¦æ ¼è¦æ±‚有 Manufacturer\n"
+" åƒè€ƒï¼šç¬¬ 58-59 é ï¼Œç« ç¯€ 5.3。\n"
+
+msgid ""
+" WARN Non-Windows PPD files should use lines ending with only LF, "
+"not CR LF\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" WARN Obsolete PPD version %.1f\n"
+" REF: Page 42, section 5.2.\n"
+msgstr ""
+
+msgid ""
+" WARN PCFileName longer than 8.3 in violation of PPD spec.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" 警告 PCFileName 長度大於 8.3,這é•å了 PPD è¦æ ¼ã€‚\n"
+" åƒè€ƒï¼šç¬¬ 61-62 é ï¼Œç« ç¯€ 5.3。\n"
+
+msgid ""
+" WARN PCFileName should contain a unique filename.\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+
+msgid ""
+" WARN Protocols contains PJL but JCL attributes are not set.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" 警告 通訊å”å®šåŒ…å« PJL,但未設定 JCL 屬性。\n"
+" åƒè€ƒï¼šç¬¬ 78-79 é ï¼Œç« ç¯€ 5.7。\n"
+
+msgid ""
+" WARN Protocols contains both PJL and BCP; expected TBCP.\n"
+" REF: Pages 78-79, section 5.7.\n"
+msgstr ""
+" 警告 通訊å”定åŒæ™‚åŒ…å« PJL å’Œ BCP;應該為 TBCP。\n"
+" åƒè€ƒï¼šç¬¬ 78-79 é ï¼Œç« ç¯€ 5.7。\n"
+
+msgid ""
+" WARN ShortNickName required by PPD 4.3 spec.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" 警告 PPD 4.3 è¦æ ¼è¦æ±‚有 ShortNickName\n"
+" åƒè€ƒï¼šç¬¬ 64-65 é ï¼Œç« ç¯€ 5.3。\n"
+
+#, c-format
+msgid " %s %s %s does not exist\n"
+msgstr ""
+
+#, c-format
+msgid " %s %s file \"%s\" has the wrong capitalization\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad %s choice %s\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad UTF-8 \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Bad UTF-8 \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsICCProfile %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsPreFilter value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad language \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad permissions on cupsPreFilter file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Bad spelling of %s - should be %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Cannot provide both APScanAppPath and APScanAppBundleID\n"
+msgstr ""
+
+#, c-format
+msgid " %s Empty cupsUIConstraints %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing \"%s\" translation string for option %s, choice %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APDialogExtension file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterIconPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterLowInkTool file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APPrinterUtilityPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing APScanAppPath file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageRegion option\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Missing REQUIRED PageSize option\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsFilter file \"%s\"\n"
+msgstr " %s éºå¤± cupsFilter 檔案“%sâ€\n"
+
+#, c-format
+msgid " %s Missing cupsICCProfile file \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing cupsPreFilter file \"%s\"\n"
+msgstr " %s éºå¤± cupsPreFilter 檔案“%sâ€\n"
+
+#, c-format
+msgid " %s Missing cupsUIResolver %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid " %s No base translation \"%s\" is included in file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s Non-standard size name \"%s\"\n"
+" REF: Page 187, section B.2.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s REQUIRED %s does not define choice None\n"
+" REF: Page 122, section 5.17\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" defined for %s but not for %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s Size \"%s\" has unexpected dimensions (%gx%g)\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsICCProfile %s hash value collides with %s\n"
+msgstr ""
+
+#, c-format
+msgid " %s cupsUIResolver %s causes a loop\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" %s cupsUIResolver %s does not list at least two different options\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** %s choice names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** %s must be 1284DeviceID\n"
+" REF: Page 72, section 5.5\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD Default%s %s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **失敗** Default%s %s 錯誤\n"
+" åƒè€ƒï¼šç¬¬ 40 é ï¼Œç« ç¯€ 4.5。\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultImageableArea %s\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** BAD DefaultPaperDimension %s\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+
+msgid ""
+" **FAIL** BAD JobPatchFile attribute in file\n"
+" REF: Page 24, section 3.4.\n"
+msgstr ""
+" **失敗** 檔案中的 JobPatchFile 屬性錯誤\n"
+" åƒè€ƒï¼šç¬¬ 24 é ï¼Œç« ç¯€ 3.4。\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"HP\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **失敗** Manufacturer 錯誤(應該為“HPâ€ï¼‰\n"
+" åƒè€ƒï¼šç¬¬ 211 é ï¼Œè¡¨æ ¼ D.1。\n"
+
+msgid ""
+" **FAIL** BAD Manufacturer (should be \"Oki\")\n"
+" REF: Page 211, table D.1.\n"
+msgstr ""
+" **失敗** Manufacturer 錯誤(應該為“Okiâ€ï¼‰\n"
+" åƒè€ƒï¼šç¬¬ 211 é ï¼Œè¡¨æ ¼ D.1。\n"
+
+#, c-format
+msgid ""
+" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **失敗** ModelName 錯誤 - 字串中ä¸å…許“%câ€ã€‚\n"
+" åƒè€ƒï¼šç¬¬ 59-60 é ï¼Œç« ç¯€ 5.3。\n"
+
+msgid ""
+" **FAIL** BAD PSVersion - not \"(string) int\".\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **失敗** PSVersion 錯誤 - ä¸æ˜¯â€œ(string) intâ€ã€‚\n"
+" åƒè€ƒï¼šç¬¬ 62-64 é ï¼Œç« ç¯€ 5.3。\n"
+
+msgid ""
+" **FAIL** BAD Product - not \"(string)\".\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **失敗** Product 錯誤 - ä¸æ˜¯â€œ(string)â€ã€‚\n"
+" åƒè€ƒï¼šç¬¬ 62 é ï¼Œç« ç¯€ 5.3。\n"
+
+msgid ""
+" **FAIL** BAD ShortNickName - longer than 31 chars.\n"
+" REF: Pages 64-65, section 5.3.\n"
+msgstr ""
+" **失敗** ShortNickName 錯誤 - 長度大於 31 個字元。\n"
+" åƒè€ƒï¼šç¬¬ 64-65 é ï¼Œç« ç¯€ 5.3。\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad %s choice %s\n"
+" REF: Page 84, section 5.9\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Bad FileVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **失敗** FileVersion“%sâ€éŒ¯èª¤\n"
+" åƒè€ƒï¼šç¬¬ 56 é ï¼Œç« ç¯€ 5.3。\n"
+
+#, c-format
+msgid ""
+" **FAIL** Bad FormatVersion \"%s\"\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **失敗** FormatVersion“%sâ€éŒ¯èª¤\n"
+" åƒè€ƒï¼šç¬¬ 56 é ï¼Œç« ç¯€ 5.3。\n"
+
+#, c-format
+msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Bad LanguageVersion %s - must be English\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Default option code cannot be interpreted: %s\n"
+msgstr " **失敗** 無法解譯é è¨­é¸é …代碼:%s\n"
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s choice %s contains "
+"8-bit characters\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** Default translation string for option %s contains 8-bit "
+"characters\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Group names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Multiple occurrences of %s choice name %s\n"
+msgstr ""
+
+#, c-format
+msgid " **FAIL** Option names %s and %s differ only by case\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED Default%s\n"
+" REF: Page 40, section 4.5.\n"
+msgstr ""
+" **失敗** éœ€è¦ Default%s\n"
+" åƒè€ƒï¼šç¬¬ 40 é ï¼Œç« ç¯€ 4.5。\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultImageableArea\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **失敗** éœ€è¦ DefaultImageableArea\n"
+" åƒè€ƒï¼šç¬¬ 102 é ï¼Œç« ç¯€ 5.15。\n"
+
+msgid ""
+" **FAIL** REQUIRED DefaultPaperDimension\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **失敗** éœ€è¦ DefaultPaperDimension\n"
+" åƒè€ƒï¼šç¬¬ 103 é ï¼Œç« ç¯€ 5.15。\n"
+
+msgid ""
+" **FAIL** REQUIRED FileVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **失敗** éœ€è¦ FileVersion\n"
+" åƒè€ƒï¼šç¬¬ 56 é ï¼Œç« ç¯€ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED FormatVersion\n"
+" REF: Page 56, section 5.3.\n"
+msgstr ""
+" **失敗** éœ€è¦ FormatVersion\n"
+" åƒè€ƒï¼šç¬¬ 56 é ï¼Œç« ç¯€ 5.3。\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED ImageableArea for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 102, section 5.15.\n"
+msgstr ""
+" **失敗** PageSize %s éœ€è¦ ImageableArea\n"
+" åƒè€ƒï¼šç¬¬ 41 é ï¼Œç« ç¯€ 5。\n"
+" åƒè€ƒï¼šç¬¬ 102 é ï¼Œç« ç¯€ 5.15。\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageEncoding\n"
+" REF: Pages 56-57, section 5.3.\n"
+msgstr ""
+" **失敗** éœ€è¦ LanguageEncoding\n"
+" åƒè€ƒï¼šç¬¬ 56-57 é ï¼Œç« ç¯€ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED LanguageVersion\n"
+" REF: Pages 57-58, section 5.3.\n"
+msgstr ""
+" **失敗** éœ€è¦ LanguageVersion\n"
+" åƒè€ƒï¼šç¬¬ 57-58 é ï¼Œç« ç¯€ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED Manufacturer\n"
+" REF: Pages 58-59, section 5.3.\n"
+msgstr ""
+" **失敗** éœ€è¦ Manufacturer\n"
+" åƒè€ƒï¼šç¬¬ 58-59 é ï¼Œç« ç¯€ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED ModelName\n"
+" REF: Pages 59-60, section 5.3.\n"
+msgstr ""
+" **失敗** éœ€è¦ ModelName\n"
+" åƒè€ƒï¼šç¬¬ 59-60 é ï¼Œç« ç¯€ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED NickName\n"
+" REF: Page 60, section 5.3.\n"
+msgstr ""
+" **失敗** éœ€è¦ NickName\n"
+" åƒè€ƒï¼šç¬¬ 60 é ï¼Œç« ç¯€ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED PCFileName\n"
+" REF: Pages 61-62, section 5.3.\n"
+msgstr ""
+" **失敗** éœ€è¦ PCFileName\n"
+" åƒè€ƒï¼šç¬¬ 61-62 é ï¼Œç« ç¯€ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED PSVersion\n"
+" REF: Pages 62-64, section 5.3.\n"
+msgstr ""
+" **失敗** éœ€è¦ PSVersion\n"
+" åƒè€ƒï¼šç¬¬ 62-64 é ï¼Œç« ç¯€ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED PageRegion\n"
+" REF: Page 100, section 5.14.\n"
+msgstr ""
+" **失敗** éœ€è¦ PageRegion\n"
+" åƒè€ƒï¼šç¬¬ 100 é ï¼Œç« ç¯€ 5.14。\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 99, section 5.14.\n"
+msgstr ""
+" **失敗** éœ€è¦ PageSize\n"
+" åƒè€ƒï¼šç¬¬ 41 é ï¼Œç« ç¯€ 5。\n"
+" åƒè€ƒï¼šç¬¬ 99 é ï¼Œç« ç¯€ 5.14。\n"
+
+msgid ""
+" **FAIL** REQUIRED PageSize\n"
+" REF: Pages 99-100, section 5.14.\n"
+msgstr ""
+" **失敗** éœ€è¦ PageSize\n"
+" åƒè€ƒï¼šç¬¬ 99-100 é ï¼Œç« ç¯€ 5.14。\n"
+
+#, c-format
+msgid ""
+" **FAIL** REQUIRED PaperDimension for PageSize %s\n"
+" REF: Page 41, section 5.\n"
+" REF: Page 103, section 5.15.\n"
+msgstr ""
+" **失敗** PageSize %s éœ€è¦ PaperDimension\n"
+" åƒè€ƒï¼šç¬¬ 41 é ï¼Œç« ç¯€ 5。\n"
+" åƒè€ƒï¼šç¬¬ 103 é ï¼Œç« ç¯€ 5.15。\n"
+
+msgid ""
+" **FAIL** REQUIRED Product\n"
+" REF: Page 62, section 5.3.\n"
+msgstr ""
+" **失敗** éœ€è¦ Product\n"
+" åƒè€ƒï¼šç¬¬ 62 é ï¼Œç« ç¯€ 5.3。\n"
+
+msgid ""
+" **FAIL** REQUIRED ShortNickName\n"
+" REF: Page 64-65, section 5.3.\n"
+msgstr ""
+" **失敗** éœ€è¦ ShortNickName\n"
+" åƒè€ƒï¼šç¬¬ 64-65 é ï¼Œç« ç¯€ 5.3。\n"
+
+#, c-format
+msgid " %d ERRORS FOUND\n"
+msgstr " ç™¼ç¾ %d 個錯誤\n"
+
+#, c-format
+msgid ""
+" Bad %%%%BoundingBox: on line %d\n"
+" REF: Page 39, %%%%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Page: on line %d\n"
+" REF: Page 53, %%%%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Bad %%%%Pages: on line %d\n"
+" REF: Page 43, %%%%Pages:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Line %d is longer than 255 characters (%d)\n"
+" REF: Page 25, Line Length\n"
+msgstr ""
+
+msgid ""
+" Missing %!PS-Adobe-3.0 on first line\n"
+" REF: Page 17, 3.1 Conforming Documents\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing %%EndComments comment\n"
+" REF: Page 41, %%EndComments\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%BoundingBox: comment\n"
+" REF: Page 39, %%BoundingBox:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Page: comments\n"
+" REF: Page 53, %%Page:\n"
+msgstr ""
+
+#, c-format
+msgid ""
+" Missing or bad %%Pages: comment\n"
+" REF: Page 43, %%Pages:\n"
+msgstr ""
+
+msgid " NO ERRORS FOUND\n"
+msgstr " 未發ç¾éŒ¯èª¤\n"
+
+#, c-format
+msgid " Saw %d lines that exceeded 255 characters\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%BeginDocument comments\n"
+msgstr ""
+
+#, c-format
+msgid " Too many %%EndDocument comments\n"
+msgstr ""
+
+msgid " Warning: file contains binary data\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: no %%EndComments comment in file\n"
+msgstr ""
+
+#, c-format
+msgid " Warning: obsolete DSC version %.1f in file\n"
+msgstr ""
+
+msgid " FAIL\n"
+msgstr " 失敗\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s\n"
+msgstr ""
+" 失敗\n"
+" **失敗** 無法打開 PPD 檔案 - %s\n"
+
+#, c-format
+msgid ""
+" FAIL\n"
+" **FAIL** Unable to open PPD file - %s on line %d.\n"
+msgstr ""
+" 失敗\n"
+" **失敗** 無法打開 PPD 檔案 - 第 %2$d 行的 %1$s。\n"
+
+msgid " PASS\n"
+msgstr " 通éŽ\n"
+
+msgid "#10 Envelope"
+msgstr "#10 ä¿¡å°"
+
+msgid "#11 Envelope"
+msgstr "#11 ä¿¡å°"
+
+msgid "#12 Envelope"
+msgstr "#12 ä¿¡å°"
+
+msgid "#14 Envelope"
+msgstr "#14 ä¿¡å°"
+
+msgid "#9 Envelope"
+msgstr "#9 ä¿¡å°"
+
+#, c-format
+msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"
+msgstr "%-6s %-10.10s %-4d %-10d %-27.27s %.0f byte\n"
+
+#, c-format
+msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"
+msgstr "%-7s %-7.7s %-7d %-31.31s %.0f byte\n"
+
+#, c-format
+msgid "%.0f x %.0f millimeters"
+msgstr "%.0f x %.0f å…¬é‡"
+
+#, c-format
+msgid "%.0f x %.0f to %.0f x %.0f millimeters"
+msgstr "%.0f x %.0f to %.0f x %.0f å…¬é‡"
+
+#, c-format
+msgid "%.2f x %.2f inches"
+msgstr "%.2f x %.2f 英å‹"
+
+#, c-format
+msgid "%.2f x %.2f to %.2f x %.2f inches"
+msgstr "%.2f x %.2f to %.2f x %.2f 英å‹"
+
+#, c-format
+msgid "%s accepting requests since %s\n"
+msgstr "%s 自 %s 後接å—請求\n"
+
+#, c-format
+msgid "%s cannot be changed."
+msgstr "無法更改 %s。"
+
+#, c-format
+msgid "%s is not implemented by the CUPS version of lpc.\n"
+msgstr "%s 未由 CUPS 版本 lpc 執行。\n"
+
+#, c-format
+msgid "%s is not ready\n"
+msgstr "%s 尚未備妥\n"
+
+#, c-format
+msgid "%s is ready\n"
+msgstr "%s 已備妥\n"
+
+#, c-format
+msgid "%s is ready and printing\n"
+msgstr "%s 已備妥列å°\n"
+
+#, c-format
+msgid ""
+"%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s 自 %s 後ä¸æŽ¥å—請求 -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s not supported"
+msgstr ""
+
+#, c-format
+msgid "%s/%s accepting requests since %s\n"
+msgstr "%s/%s 自 %s 後接å—請求\n"
+
+#, c-format
+msgid ""
+"%s/%s not accepting requests since %s -\n"
+"\t%s\n"
+msgstr ""
+"%s/%s 自 %s 後ä¸æŽ¥å—請求 -\n"
+"\t%s\n"
+
+#, c-format
+msgid "%s: %-33.33s [job %d localhost]\n"
+msgstr "%s:%-33.33s [作業 %d localhost]\n"
+
+#, c-format
+msgid "%s: %s failed: %s\n"
+msgstr "%s:%s 失敗:%s\n"
+
+#, c-format
+msgid "%s: Don't know what to do\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - bad job ID\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print files and alter jobs simultaneously\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - cannot print from stdin if files or a job ID are provided\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected character set after '-S' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected content type after '-T' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copies after '-n' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected copy count after '-#' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-b' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected destination after '-d' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected form after '-f' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hold name after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-H' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected hostname after '-h' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected mode list after '-y' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected name after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected option string after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected page list after '-P' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected priority after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected reason text after '-r' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected title after '-t' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-U' option!n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected username after '-u' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - expected value after '-%c' option\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+"option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - no default destination available.\n"
+msgstr "%s:錯誤 - ç„¡å¯ç”¨çš„é è¨­ç›®çš„地。\n"
+
+#, c-format
+msgid "%s: Error - priority must be between 1 and 100.\n"
+msgstr "%s:錯誤 - 優先順åºå¿…須介於 1 å’Œ 100 之間。\n"
+
+#, c-format
+msgid "%s: Error - scheduler not responding\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - too many files - \"%s\"\n"
+msgstr "%s:錯誤 - 檔案太多 -“%sâ€\n"
+
+#, c-format
+msgid "%s: Error - unable to access \"%s\" - %s\n"
+msgstr "%s:錯誤 - 無法存å–“%sâ€- %s\n"
+
+#, c-format
+msgid "%s: Error - unable to queue from stdin - %s\n"
+msgstr "%s:錯誤 - 無法從 stdin 佇列 - %s\n"
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown destination \"%s/%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Error - unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Expected job ID after '-i' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Filter \"%s\" not available: %s\n"
+msgstr "%s:無法使用濾é¡â€œ%sâ€ï¼š%s\n"
+
+#, c-format
+msgid "%s: Invalid destination name in list \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Invalid filter string \"%s\"\n"
+msgstr "%s:éŽæ¿¾å­—串“%sâ€ç„¡æ•ˆ\n"
+
+#, c-format
+msgid "%s: Need job ID ('-i jobid') before '-H restart'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: No filter to convert from %s/%s to %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Operation failed: %s\n"
+msgstr "%s:作業失敗:%s\n"
+
+#, c-format
+msgid "%s: Sorry, no encryption support compiled in\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to connect to server\n"
+msgstr "%s:無法連接伺æœå™¨\n"
+
+#, c-format
+msgid "%s: Unable to contact server\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to determine MIME type of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to open %s: %s\n"
+msgstr "%s:無法打開 %s:%s\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d\n"
+msgstr "%s:無法打開 PPD 檔案:%s 在第 %d 行\n"
+
+#, c-format
+msgid "%s: Unable to open PPD file: %s on line %d.\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown destination MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Unknown source MIME type %s/%s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: Warning - '%c' format modifier not supported - output may not be "
+"correct\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - character set option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - content type option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - form option ignored\n"
+msgstr ""
+
+#, c-format
+msgid "%s: Warning - mode option ignored\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"%s: error - %s environment variable names non-existent destination \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - expected option=value after '-o' option\n"
+msgstr ""
+
+#, c-format
+msgid "%s: error - no default destination available.\n"
+msgstr "%s:錯誤 - 沒有å¯ç”¨çš„é è¨­ç›®çš„地。\n"
+
+msgid "-1"
+msgstr "-1"
+
+msgid "-10"
+msgstr "-10"
+
+msgid "-100"
+msgstr "-100"
+
+msgid "-105"
+msgstr "-105"
+
+msgid "-11"
+msgstr "-11"
+
+msgid "-110"
+msgstr "-110"
+
+msgid "-115"
+msgstr "-115"
+
+msgid "-12"
+msgstr "-12"
+
+msgid "-120"
+msgstr "-120"
+
+msgid "-13"
+msgstr "-13"
+
+msgid "-14"
+msgstr "-14"
+
+msgid "-15"
+msgstr "-15"
+
+msgid "-2"
+msgstr "-2"
+
+msgid "-20"
+msgstr "-20"
+
+msgid "-25"
+msgstr "-25"
+
+msgid "-3"
+msgstr "-3"
+
+msgid "-30"
+msgstr "-30"
+
+msgid "-35"
+msgstr "-35"
+
+msgid "-4"
+msgstr "-4"
+
+msgid "-40"
+msgstr "-40"
+
+msgid "-45"
+msgstr "-45"
+
+msgid "-5"
+msgstr "-5"
+
+msgid "-50"
+msgstr "-50"
+
+msgid "-55"
+msgstr "-55"
+
+msgid "-6"
+msgstr "-6"
+
+msgid "-60"
+msgstr "-60"
+
+msgid "-65"
+msgstr "-65"
+
+msgid "-7"
+msgstr "-7"
+
+msgid "-70"
+msgstr "-70"
+
+msgid "-75"
+msgstr "-75"
+
+msgid "-8"
+msgstr "-8"
+
+msgid "-80"
+msgstr "-80"
+
+msgid "-85"
+msgstr "-85"
+
+msgid "-9"
+msgstr "-9"
+
+msgid "-90"
+msgstr "-90"
+
+msgid "-95"
+msgstr "-95"
+
+msgid "0"
+msgstr "0"
+
+msgid "1"
+msgstr "1"
+
+msgid "1 inch/sec."
+msgstr "1 英å‹âˆ•ç§’"
+
+msgid "1.25x0.25\""
+msgstr "1.25x0.25\""
+
+msgid "1.25x2.25\""
+msgstr "1.25x2.25\""
+
+msgid "1.5 inch/sec."
+msgstr "1.5 英å‹âˆ•ç§’"
+
+msgid "1.50x0.25\""
+msgstr "1.50x0.25\""
+
+msgid "1.50x0.50\""
+msgstr "1.50x0.50\""
+
+msgid "1.50x1.00\""
+msgstr "1.50x1.00\""
+
+msgid "1.50x2.00\""
+msgstr "1.50x2.00\""
+
+msgid "10"
+msgstr "10"
+
+msgid "10 inches/sec."
+msgstr "10 英å‹âˆ•ç§’"
+
+msgid "10 x 11\""
+msgstr "10 x 11\""
+
+msgid "10 x 13\""
+msgstr "10 x 13\""
+
+msgid "10 x 14\""
+msgstr "10 x 14\""
+
+msgid "100"
+msgstr "100"
+
+msgid "100 mm/sec."
+msgstr "100 å…¬é‡âˆ•ç§’"
+
+msgid "105"
+msgstr "105"
+
+msgid "11"
+msgstr "11"
+
+msgid "11 inches/sec."
+msgstr "11 英å‹âˆ•ç§’"
+
+msgid "110"
+msgstr "110"
+
+msgid "115"
+msgstr "115"
+
+msgid "12"
+msgstr "12"
+
+msgid "12 inches/sec."
+msgstr "12 英å‹âˆ•ç§’"
+
+msgid "12 x 11\""
+msgstr "12 x 11\""
+
+msgid "120"
+msgstr "120"
+
+msgid "120 mm/sec."
+msgstr "120 å…¬é‡âˆ•ç§’"
+
+msgid "120x60dpi"
+msgstr "120x60dpi"
+
+msgid "120x72dpi"
+msgstr "120x72dpi"
+
+msgid "13"
+msgstr "13"
+
+msgid "136dpi"
+msgstr "136dpi"
+
+msgid "14"
+msgstr "14"
+
+msgid "15"
+msgstr "15"
+
+msgid "15 mm/sec."
+msgstr "15 å…¬é‡âˆ•ç§’"
+
+msgid "15 x 11\""
+msgstr "15 x 11\""
+
+msgid "150 mm/sec."
+msgstr "150 å…¬é‡âˆ•ç§’"
+
+msgid "150dpi"
+msgstr "150dpi"
+
+msgid "16"
+msgstr "16"
+
+msgid "17"
+msgstr "17"
+
+msgid "18"
+msgstr "18"
+
+msgid "180dpi"
+msgstr "180dpi"
+
+msgid "19"
+msgstr "19"
+
+msgid "2"
+msgstr "2"
+
+msgid "2 inches/sec."
+msgstr "2 英å‹âˆ•ç§’"
+
+msgid "2-Sided Printing"
+msgstr "é›™é¢åˆ—å°"
+
+msgid "2.00x0.37\""
+msgstr "2.00x0.37\""
+
+msgid "2.00x0.50\""
+msgstr "2.00x0.50\""
+
+msgid "2.00x1.00\""
+msgstr "2.00x1.00\""
+
+msgid "2.00x1.25\""
+msgstr "2.00x1.25\""
+
+msgid "2.00x2.00\""
+msgstr "2.00x2.00\""
+
+msgid "2.00x3.00\""
+msgstr "2.00x3.00\""
+
+msgid "2.00x4.00\""
+msgstr "2.00x4.00\""
+
+msgid "2.00x5.50\""
+msgstr "2.00x5.50\""
+
+msgid "2.25x0.50\""
+msgstr "2.25x0.50\""
+
+msgid "2.25x1.25\""
+msgstr "2.25x1.25\""
+
+msgid "2.25x4.00\""
+msgstr "2.25x4.00\""
+
+msgid "2.25x5.50\""
+msgstr "2.25x5.50\""
+
+msgid "2.38x5.50\""
+msgstr "2.38x5.50\""
+
+msgid "2.5 inches/sec."
+msgstr "2.5 英å‹âˆ•ç§’"
+
+msgid "2.50x1.00\""
+msgstr "2.50x1.00\""
+
+msgid "2.50x2.00\""
+msgstr "2.50x2.00\""
+
+msgid "2.75x1.25\""
+msgstr "2.75x1.25\""
+
+msgid "2.9 x 1\""
+msgstr "2.9 x 1\""
+
+msgid "20"
+msgstr "20"
+
+msgid "20 mm/sec."
+msgstr "20 å…¬é‡âˆ•ç§’"
+
+msgid "200 mm/sec."
+msgstr "200 å…¬é‡âˆ•ç§’"
+
+msgid "203dpi"
+msgstr "203dpi"
+
+msgid "21"
+msgstr "21"
+
+msgid "22"
+msgstr "22"
+
+msgid "23"
+msgstr "23"
+
+msgid "24"
+msgstr "24"
+
+msgid "24-Pin Series"
+msgstr "24-Pin 系列"
+
+msgid "240x72dpi"
+msgstr "240x72dpi"
+
+msgid "25"
+msgstr "25"
+
+msgid "250 mm/sec."
+msgstr "250 å…¬é‡âˆ•ç§’"
+
+msgid "26"
+msgstr "26"
+
+msgid "27"
+msgstr "27"
+
+msgid "28"
+msgstr "28"
+
+msgid "29"
+msgstr "29"
+
+msgid "3"
+msgstr "3"
+
+msgid "3 inches/sec."
+msgstr "3 英å‹âˆ•ç§’"
+
+msgid "3.00x1.00\""
+msgstr "3.00x1.00\""
+
+msgid "3.00x1.25\""
+msgstr "3.00x1.25\""
+
+msgid "3.00x2.00\""
+msgstr "3.00x2.00\""
+
+msgid "3.00x3.00\""
+msgstr "3.00x3.00\""
+
+msgid "3.00x5.00\""
+msgstr "3.00x5.00\""
+
+msgid "3.25x2.00\""
+msgstr "3.25x2.00\""
+
+msgid "3.25x5.00\""
+msgstr "3.25x5.00\""
+
+msgid "3.25x5.50\""
+msgstr "3.25x5.50\""
+
+msgid "3.25x5.83\""
+msgstr "3.25x5.83\""
+
+msgid "3.25x7.83\""
+msgstr "3.25x7.83\""
+
+msgid "3.5\" Disk"
+msgstr "3.5 å‹ç£ç¢Ÿ"
+
+msgid "3.5\" Disk - 2 1/8 x 2 3/4\""
+msgstr "3.5 å‹ç£ç¢Ÿ - 2 1/8 x 2 3/4\""
+
+msgid "3.50x1.00\""
+msgstr "3.50x1.00\""
+
+msgid "30"
+msgstr "30"
+
+msgid "30 mm/sec."
+msgstr "30 å…¬é‡âˆ•ç§’"
+
+msgid "300 mm/sec."
+msgstr "300 å…¬é‡âˆ•ç§’"
+
+msgid "300dpi"
+msgstr "300dpi"
+
+msgid "35"
+msgstr "35"
+
+msgid "360dpi"
+msgstr "360dpi"
+
+msgid "360x180dpi"
+msgstr "360x180dpi"
+
+msgid "4"
+msgstr "4"
+
+msgid "4 inches/sec."
+msgstr "4 英å‹âˆ•ç§’"
+
+msgid "4.00x1.00\""
+msgstr "4.00x1.00\""
+
+msgid "4.00x13.00\""
+msgstr "4.00x13.00\""
+
+msgid "4.00x2.00\""
+msgstr "4.00x2.00\""
+
+msgid "4.00x2.50\""
+msgstr "4.00x2.50\""
+
+msgid "4.00x3.00\""
+msgstr "4.00x3.00\""
+
+msgid "4.00x4.00\""
+msgstr "4.00x4.00\""
+
+msgid "4.00x5.00\""
+msgstr "4.00x5.00\""
+
+msgid "4.00x6.00\""
+msgstr "4.00x6.00\""
+
+msgid "4.00x6.50\""
+msgstr "4.00x6.50\""
+
+msgid "40"
+msgstr "40"
+
+msgid "40 mm/sec."
+msgstr "40 å…¬é‡âˆ•ç§’"
+
+msgid "45"
+msgstr "45"
+
+msgid "5"
+msgstr "5"
+
+msgid "5 inches/sec."
+msgstr "5 英å‹âˆ•ç§’"
+
+msgid "50"
+msgstr "50"
+
+msgid "55"
+msgstr "55"
+
+msgid "6"
+msgstr "6"
+
+msgid "6 inches/sec."
+msgstr "6 英å‹âˆ•ç§’"
+
+msgid "6.00x1.00\""
+msgstr "6.00x1.00\""
+
+msgid "6.00x2.00\""
+msgstr "6.00x2.00\""
+
+msgid "6.00x3.00\""
+msgstr "6.00x3.00\""
+
+msgid "6.00x4.00\""
+msgstr "6.00x4.00\""
+
+msgid "6.00x5.00\""
+msgstr "6.00x5.00\""
+
+msgid "6.00x6.00\""
+msgstr "6.00x6.00\""
+
+msgid "6.00x6.50\""
+msgstr "6.00x6.50\""
+
+msgid "60"
+msgstr "60"
+
+msgid "60 mm/sec."
+msgstr "60 å…¬é‡âˆ•ç§’"
+
+msgid "600dpi"
+msgstr "600dpi"
+
+msgid "60dpi"
+msgstr "60dpi"
+
+msgid "60x720dpi"
+msgstr "60x720dpi"
+
+msgid "65"
+msgstr "65"
+
+msgid "7"
+msgstr "7"
+
+msgid "7 inches/sec."
+msgstr "7 英å‹âˆ•ç§’"
+
+msgid "7 x 9\""
+msgstr "7 x 9\""
+
+msgid "70"
+msgstr "70"
+
+msgid "720dpi"
+msgstr "720dpi"
+
+msgid "75"
+msgstr "75"
+
+msgid "8"
+msgstr "8"
+
+msgid "8 inches/sec."
+msgstr "8 英å‹âˆ•ç§’"
+
+msgid "8 x 10\""
+msgstr "8 x 10\""
+
+msgid "8.00x1.00\""
+msgstr "8.00x1.00\""
+
+msgid "8.00x2.00\""
+msgstr "8.00x2.00\""
+
+msgid "8.00x3.00\""
+msgstr "8.00x3.00\""
+
+msgid "8.00x4.00\""
+msgstr "8.00x4.00\""
+
+msgid "8.00x5.00\""
+msgstr "8.00x5.00\""
+
+msgid "8.00x6.00\""
+msgstr "8.00x6.00\""
+
+msgid "8.00x6.50\""
+msgstr "8.00x6.50\""
+
+msgid "80"
+msgstr "80"
+
+msgid "80 mm/sec."
+msgstr "80 å…¬é‡âˆ•ç§’"
+
+msgid "85"
+msgstr "85"
+
+msgid "9"
+msgstr "9"
+
+msgid "9 inches/sec."
+msgstr "9 英å‹âˆ•ç§’"
+
+msgid "9 x 11\""
+msgstr "9 x 11\""
+
+msgid "9 x 12\""
+msgstr "9 x 12\""
+
+msgid "9-Pin Series"
+msgstr "9-Pin 系列"
+
+msgid "90"
+msgstr "90"
+
+msgid "95"
+msgstr "95"
+
+msgid "?Invalid help command unknown\n"
+msgstr "?無效的輔助說明指令未知\n"
+
+msgid "A Samba password is required to export printer drivers"
+msgstr ""
+
+msgid "A Samba username is required to export printer drivers"
+msgstr ""
+
+#, c-format
+msgid "A class named \"%s\" already exists"
+msgstr ""
+
+#, c-format
+msgid "A printer named \"%s\" already exists"
+msgstr ""
+
+msgid "A0"
+msgstr "A0"
+
+msgid "A1"
+msgstr "A1"
+
+msgid "A10"
+msgstr "A10"
+
+msgid "A2"
+msgstr "A2"
+
+msgid "A3"
+msgstr "A3"
+
+msgid "A3 (Oversize)"
+msgstr "A3(超大型)"
+
+msgid "A4"
+msgstr "A4"
+
+msgid "A4 (Oversize)"
+msgstr "A4(超大型)"
+
+msgid "A4 (Small)"
+msgstr "A4(å°åž‹ï¼‰"
+
+msgid "A5"
+msgstr "A5"
+
+msgid "A5 (Oversize)"
+msgstr "A5(超大型)"
+
+msgid "A6"
+msgstr "A6"
+
+msgid "A7"
+msgstr "A7"
+
+msgid "A8"
+msgstr "A8"
+
+msgid "A9"
+msgstr "A9"
+
+msgid "ANSI A"
+msgstr "ANSI A"
+
+msgid "ANSI B"
+msgstr "ANSI B"
+
+msgid "ANSI C"
+msgstr "ANSI C"
+
+msgid "ANSI D"
+msgstr "ANSI D"
+
+msgid "ANSI E"
+msgstr "ANSI E"
+
+msgid "ARCH A"
+msgstr "ARCH A"
+
+msgid "ARCH B"
+msgstr "ARCH B"
+
+msgid "ARCH C"
+msgstr "ARCH C"
+
+msgid "ARCH D"
+msgstr "ARCH D"
+
+msgid "ARCH E"
+msgstr "ARCH E"
+
+msgid "Accept Jobs"
+msgstr "接å—作業"
+
+msgid "Accepted"
+msgstr "已接å—"
+
+msgid "Add Class"
+msgstr "加入類別"
+
+msgid "Add Printer"
+msgstr "新增å°è¡¨æ©Ÿ"
+
+msgid "Add RSS Subscription"
+msgstr "新增 RSS 訂閱"
+
+msgid "Address"
+msgstr "地å€"
+
+msgid "Address - 1 1/8 x 3 1/2\""
+msgstr "åœ°å€ - 1 1/8 x 3 1/2\""
+
+msgid "Administration"
+msgstr "管ç†"
+
+msgid "Always"
+msgstr "總是"
+
+msgid "AppSocket/HP JetDirect"
+msgstr "AppSocket/HP JetDirect"
+
+msgid "Applicator"
+msgstr "å™´é ­"
+
+#, c-format
+msgid "Attempt to set %s printer-state to bad value %d"
+msgstr ""
+
+#, c-format
+msgid "Attribute groups are out of order (%x < %x)"
+msgstr ""
+
+msgid "B0"
+msgstr "B0"
+
+msgid "B1"
+msgstr "B1"
+
+msgid "B10"
+msgstr "B10"
+
+msgid "B2"
+msgstr "B2"
+
+msgid "B3"
+msgstr "B3"
+
+msgid "B4"
+msgstr "B4"
+
+msgid "B5"
+msgstr "B5"
+
+msgid "B6"
+msgstr "B6"
+
+msgid "B7"
+msgstr "B7"
+
+msgid "B8"
+msgstr "B8"
+
+msgid "B9"
+msgstr "B9"
+
+msgid "Bad NULL dests pointer"
+msgstr "NULL dests 指標錯誤"
+
+msgid "Bad OpenGroup"
+msgstr "OpenGroup 錯誤"
+
+msgid "Bad OpenUI/JCLOpenUI"
+msgstr "OpenUI/JCLOpenUI 錯誤"
+
+msgid "Bad OrderDependency"
+msgstr "OrderDependency 錯誤"
+
+msgid "Bad Request"
+msgstr "請求錯誤"
+
+msgid "Bad SNMP version number"
+msgstr "SNMP 版本號碼錯誤"
+
+msgid "Bad UIConstraints"
+msgstr "UIConstraints 錯誤"
+
+#, c-format
+msgid "Bad copies value %d."
+msgstr "列å°ä»½æ•¸å€¼ %d 錯誤。"
+
+msgid "Bad custom parameter"
+msgstr "自定åƒæ•¸éŒ¯èª¤"
+
+#, c-format
+msgid "Bad device URI \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad device-uri scheme \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad document-format \"%s\""
+msgstr ""
+
+msgid "Bad filename buffer"
+msgstr ""
+
+#, c-format
+msgid "Bad font attribute: %s\n"
+msgstr "字體屬性ERROR: %s\n"
+
+msgid "Bad job-priority value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-sheets value \"%s\""
+msgstr ""
+
+msgid "Bad job-sheets value type"
+msgstr ""
+
+msgid "Bad job-state value"
+msgstr ""
+
+#, c-format
+msgid "Bad job-uri attribute \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-pull-method \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad notify-recipient-uri URI \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad number-up value %d."
+msgstr "number-up 值 %d 錯誤。"
+
+#, c-format
+msgid "Bad option + choice on line %d"
+msgstr ""
+
+#, c-format
+msgid "Bad page-ranges values %d-%d."
+msgstr "page-ranges 值 %d-%d 錯誤。"
+
+#, c-format
+msgid "Bad port-monitor \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Bad printer-state value %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request ID %d"
+msgstr ""
+
+#, c-format
+msgid "Bad request version number %d.%d"
+msgstr ""
+
+msgid "Bad subscription ID"
+msgstr ""
+
+msgid "Bad value string"
+msgstr ""
+
+msgid "Banners"
+msgstr "標語"
+
+msgid "Billing Information: "
+msgstr "帳單資訊:"
+
+msgid "Bond Paper"
+msgstr "證券紙"
+
+msgid "C0 Envelope"
+msgstr "C0 ä¿¡å°"
+
+msgid "C1 Envelope"
+msgstr "C1 ä¿¡å°"
+
+msgid "C2 Envelope"
+msgstr "C2 ä¿¡å°"
+
+msgid "C3 Envelope"
+msgstr "C3 ä¿¡å°"
+
+msgid "C4"
+msgstr "C4"
+
+msgid "C4 Envelope"
+msgstr "C4 ä¿¡å°"
+
+msgid "C5"
+msgstr "C5"
+
+msgid "C5 Envelope"
+msgstr "C5 ä¿¡å°"
+
+msgid "C6"
+msgstr "C6"
+
+msgid "C6 Envelope"
+msgstr "C6 ä¿¡å°"
+
+msgid "C65 Envelope"
+msgstr "C65 ä¿¡å°"
+
+msgid "C7 Envelope"
+msgstr "C7 ä¿¡å°"
+
+msgid "CMYK"
+msgstr "CMYK"
+
+msgid "CPCL Label Printer"
+msgstr "CPCL 標籤å°è¡¨æ©Ÿ"
+
+msgid "Cancel RSS Subscription"
+msgstr "å–消 RSS 訂閱"
+
+msgid "Change Settings"
+msgstr "更改設定"
+
+#, c-format
+msgid "Character set \"%s\" not supported"
+msgstr ""
+
+msgid "Chou3 Envelope"
+msgstr "Chou3 ä¿¡å°"
+
+msgid "Chou4 Envelope"
+msgstr "Chou4 ä¿¡å°"
+
+msgid "Classes"
+msgstr "類別"
+
+msgid "Clean Print Heads"
+msgstr "乾淨的列å°é ­"
+
+msgid "Color"
+msgstr "é¡è‰²"
+
+msgid "Color Mode"
+msgstr "é¡è‰²æ¨¡å¼"
+
+msgid ""
+"Commands may be abbreviated. Commands are:\n"
+"\n"
+"exit help quit status ?\n"
+msgstr ""
+"指令å¯ä»¥ç°¡å¯«ã€‚指令為:\n"
+"\n"
+"exit help quit status ?\n"
+
+msgid "Community name uses indefinite length"
+msgstr "社群å稱使用的長度ä¸ç¢ºå®š"
+
+msgid "Continue"
+msgstr "繼續"
+
+msgid "Continuous"
+msgstr "連續"
+
+#, c-format
+msgid "Could not scan type \"%s\""
+msgstr ""
+
+msgid "Created"
+msgstr "已製作"
+
+msgid "Created On: "
+msgstr "製作日期:"
+
+msgid "Custom"
+msgstr "自定"
+
+msgid "CustominCutInterval"
+msgstr "CustominCutInterval"
+
+msgid "CustominTearInterval"
+msgstr "CustominTearInterval"
+
+msgid "Cut"
+msgstr "剪下"
+
+msgid "Cutter"
+msgstr "剪下程å¼"
+
+msgid "DL"
+msgstr "DL"
+
+msgid "DL Envelope"
+msgstr "DL ä¿¡å°"
+
+msgid "Dark"
+msgstr "æš—"
+
+msgid "Darkness"
+msgstr "æš—"
+
+msgid "Delete Class"
+msgstr "刪除類別"
+
+msgid "Delete Printer"
+msgstr "刪除å°è¡¨æ©Ÿ"
+
+msgid "Description: "
+msgstr "æ述:"
+
+msgid "DeskJet Series"
+msgstr "DeskJet 系列"
+
+#, c-format
+msgid "Destination \"%s\" is not accepting jobs."
+msgstr "目的地“%sâ€ä¸æŽ¥å—作業。"
+
+#, c-format
+msgid ""
+"Device: uri = %s\n"
+" class = %s\n"
+" info = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+" location = %s\n"
+msgstr ""
+"設備:uri = %s\n"
+" 類別 = %s\n"
+" 資訊 = %s\n"
+" 製造和型號 = %s\n"
+" 設備 ID = %s\n"
+" ä½ç½® = %s\n"
+
+msgid "Direct Thermal Media"
+msgstr "直接熱感媒體"
+
+msgid "Disabled"
+msgstr "å·²åœç”¨"
+
+#, c-format
+msgid "Document %d not found in job %d."
+msgstr "文件 %d 在作業 %d 中找ä¸åˆ°ã€‚"
+
+msgid "Double Postcard"
+msgstr "雙明信片"
+
+msgid "Driver Name: "
+msgstr "驅動程å¼å稱:"
+
+msgid "Driver Version: "
+msgstr "驅動程å¼ç‰ˆæœ¬ï¼š"
+
+msgid "Duplexer"
+msgstr "Duplexer"
+
+msgid "Dymo"
+msgstr "Dymo"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for page info: %s\n"
+msgstr "EMERG: 無法為é é¢è³‡è¨Šåˆ†é…記憶體:%s\n"
+
+#, c-format
+msgid "EMERG: Unable to allocate memory for pages array: %s\n"
+msgstr "EMERG: 無法為é é¢é™£åˆ—分é…記憶體:%s\n"
+
+msgid "EPL1 Label Printer"
+msgstr "EPL1 標籤å°è¡¨æ©Ÿ"
+
+msgid "EPL2 Label Printer"
+msgstr "EPL2 標籤å°è¡¨æ©Ÿ"
+
+#, c-format
+msgid "ERROR: %s job-id user title copies options [file]\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%IncludeFeature: comment\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%Page: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad %%PageBoundingBox: comment in file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad charset file %s\n"
+msgstr "ERROR: 字元集檔案 %s 錯誤\n"
+
+#, c-format
+msgid "ERROR: Bad charset type %s\n"
+msgstr "ERROR: 字元集類型 %s 錯誤\n"
+
+#, c-format
+msgid "ERROR: Bad columns value %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad cpi value %f\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad font description line: %s\n"
+msgstr "ERROR: å­—é«”æè¿°è¡ŒERROR: %s\n"
+
+#, c-format
+msgid "ERROR: Bad lpi value %f\n"
+msgstr ""
+
+msgid "ERROR: Bad page setup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Bad text direction %s\n"
+msgstr "ERROR: æ–‡å­—æ–¹å‘ %s 錯誤\n"
+
+#, c-format
+msgid "ERROR: Bad text width %s\n"
+msgstr "ERROR: 文字寬度 %s 錯誤\n"
+
+msgid "ERROR: Destination printer does not exist\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%BoundingBox: comment seen\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Duplicate %%Pages: comment seen\n"
+msgstr ""
+
+msgid "ERROR: Empty print file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Error %d sending PAPSendData request: %s\n"
+msgstr "ERROR: %d å‚³é€ PAPSendData 請求時發生ERROR: %s\n"
+
+#, c-format
+msgid "ERROR: Expected quoted string on line %d of %s\n"
+msgstr ""
+
+msgid "ERROR: Fatal USB error\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndProlog\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing %%EndSetup\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Missing value on line %d of banner file\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Need a msgid line before any translation strings on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%BoundingBox: comment in header\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No %%Pages: comment in header\n"
+msgstr ""
+
+msgid ""
+"ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: No fonts in charset file %s\n"
+msgstr "ERROR: 字元集檔案 %s 中沒有字體\n"
+
+msgid "ERROR: No pages found\n"
+msgstr ""
+
+msgid "ERROR: Out of paper\n"
+msgstr ""
+
+msgid "ERROR: PRINTER environment variable not defined\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Print file was not accepted (%s)\n"
+msgstr ""
+
+msgid "ERROR: Printer not responding\n"
+msgstr "ERROR: å°è¡¨æ©Ÿæœªå›žæ‡‰\n"
+
+msgid "ERROR: Printer sent unexpected EOF\n"
+msgstr "ERROR: å°è¡¨æ©Ÿå‚³é€äº†éžé æœŸçš„ EOF\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept control file (%d)\n"
+msgstr "ERROR: é ç«¯ä¸»æ©ŸæœªæŽ¥å—控制檔案(%d)\n"
+
+#, c-format
+msgid "ERROR: Remote host did not accept data file (%d)\n"
+msgstr "ERROR: é ç«¯ä¸»æ©ŸæœªæŽ¥å—資料檔(%d)\n"
+
+msgid "ERROR: There was a timeout error while sending data to the printer\n"
+msgstr "ERROR: 將資料傳é€åˆ°å°è¡¨æ©Ÿæ™‚發生逾時錯誤\n"
+
+#, c-format
+msgid "ERROR: Unable to add file %d to job: %s\n"
+msgstr "ERROR: 無法將檔案 %d 加入作業:%s\n"
+
+#, c-format
+msgid "ERROR: Unable to cancel job %d: %s\n"
+msgstr "ERROR: 無法å–消作業 %d:%s\n"
+
+msgid "ERROR: Unable to connect to printer; will retry in 30 seconds...\n"
+msgstr ""
+
+msgid "ERROR: Unable to copy PDF file"
+msgstr "ERROR: ç„¡æ³•æ‹·è² PDF 檔案"
+
+msgid "ERROR: Unable to create pipe"
+msgstr ""
+
+msgid "ERROR: Unable to create socket"
+msgstr "ERROR: 無法製作 socket"
+
+#, c-format
+msgid "ERROR: Unable to create temporary compressed print file: %s\n"
+msgstr "ERROR: 無法製作暫時的壓縮列å°æª”案:%s\n"
+
+msgid "ERROR: Unable to create temporary file"
+msgstr "ERROR: 無法製作暫存檔"
+
+#, c-format
+msgid "ERROR: Unable to exec pictwpstops: %s\n"
+msgstr "ERROR: 無法執行 pictwpstops:%s\n"
+
+msgid "ERROR: Unable to execute gs program"
+msgstr "ERROR: 無法執行 gs 程å¼"
+
+msgid "ERROR: Unable to execute pdftops program"
+msgstr "ERROR: 無法執行 pdftops 程å¼"
+
+msgid "ERROR: Unable to execute pstops program"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to fork pictwpstops: %s\n"
+msgstr "ERROR: 無法分開 pictwpstops:%s\n"
+
+msgid "ERROR: Unable to get PAP request"
+msgstr "ERROR: 無法å–å¾— PAP 請求"
+
+msgid "ERROR: Unable to get PAP response"
+msgstr "ERROR: 無法å–å¾— PAP 回應"
+
+#, c-format
+msgid "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n"
+msgstr "ERROR: 無法å–å¾—å°è¡¨æ©Ÿâ€œ%sâ€çš„ PPD 檔案 - %s。\n"
+
+msgid "ERROR: Unable to get default AppleTalk zone"
+msgstr "ERROR: 無法å–å¾—é è¨­çš„ AppleTalk å€åŸŸ"
+
+#, c-format
+msgid "ERROR: Unable to get job %d attributes (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to get printer status (%s)\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to locate printer '%s'\n"
+msgstr ""
+
+msgid "ERROR: Unable to look for PAP response"
+msgstr "ERROR: 無法尋找 PAP 回應"
+
+msgid "ERROR: Unable to lookup AppleTalk printers"
+msgstr "ERROR: 無法尋找 AppleTalk å°è¡¨æ©Ÿ"
+
+msgid "ERROR: Unable to make AppleTalk address"
+msgstr "ERROR: 無法設定 AppleTalk 地å€"
+
+#, c-format
+msgid "ERROR: Unable to open \"%s\" - %s\n"
+msgstr "ERROR: 無法打開“%sâ€- %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open %s: %s\n"
+msgstr "ERROR: 無法打開 %s:%s\n"
+
+msgid "ERROR: Unable to open PPD file\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open banner file \"%s\" - %s\n"
+msgstr "ERROR: 無法打開標語檔案“%sâ€- %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open device file \"%s\": %s\n"
+msgstr "ERROR: 無法打開設備檔案“%sâ€ï¼š%s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\" - %s\n"
+msgstr "ERROR: 無法打開檔案“%sâ€- %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open file \"%s\": %s\n"
+msgstr "ERROR: 無法打開檔案“%sâ€ï¼š%s\n"
+
+msgid "ERROR: Unable to open image file for printing\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open print file \"%s\": %s\n"
+msgstr "ERROR: 無法打開列å°æª”案“%sâ€ï¼š%s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s - %s\n"
+msgstr "ERROR: 無法打開列å°æª”案 %s - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to open print file %s: %s\n"
+msgstr "ERROR: 無法打開列å°æª”案 %s:%s\n"
+
+#, c-format
+msgid "ERROR: Unable to open raster file - %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to open temporary compressed print file: %s\n"
+msgstr "ERROR: 無法打開暫時的壓縮列å°æª”案:%s\n"
+
+#, c-format
+msgid "ERROR: Unable to print %d text columns\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to print %dx%d text page\n"
+msgstr ""
+
+msgid "ERROR: Unable to read print data"
+msgstr "ERROR: 無法讀å–列å°è³‡æ–™"
+
+msgid "ERROR: Unable to read print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to reserve port"
+msgstr "ERROR: 無法ä¿ç•™é€£æŽ¥åŸ "
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %ld in file - %s\n"
+msgstr "ERROR: 無法在檔案中尋找å移 %ld - %s\n"
+
+#, c-format
+msgid "ERROR: Unable to seek to offset %lld in file - %s\n"
+msgstr "ERROR: 無法在檔案中尋找å移 %lld - %s\n"
+
+msgid "ERROR: Unable to send LPD command"
+msgstr "ERROR: ç„¡æ³•å‚³é€ LPD 指令"
+
+msgid "ERROR: Unable to send PAP tickle request"
+msgstr "ERROR: ç„¡æ³•å‚³é€ PAP tickle 請求"
+
+msgid "ERROR: Unable to send initial PAP send data request"
+msgstr "ERROR: 無法傳é€åˆå§‹ PAP 傳é€è³‡æ–™è«‹æ±‚"
+
+msgid "ERROR: Unable to send print data\n"
+msgstr ""
+
+msgid "ERROR: Unable to send print file to printer"
+msgstr "ERROR: 無法將列å°æª”案傳é€è‡³å°è¡¨æ©Ÿ"
+
+msgid "ERROR: Unable to send trailing nul to printer"
+msgstr "ERROR: 無法將 trailing nul 傳é€è‡³å°è¡¨æ©Ÿ"
+
+#, c-format
+msgid "ERROR: Unable to wait for pictwpstops: %s\n"
+msgstr "ERROR: 無法等待 pictwpstops:%s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to \"%s\": %s\n"
+msgstr "ERROR: 無法將 %d ä½å…ƒçµ„寫入至“%sâ€ï¼š%s\n"
+
+#, c-format
+msgid "ERROR: Unable to write %d bytes to printer\n"
+msgstr ""
+
+msgid "ERROR: Unable to write control file"
+msgstr "ERROR: 無法寫入控制檔案"
+
+msgid "ERROR: Unable to write print data"
+msgstr "ERROR: 無法寫入列å°è³‡æ–™"
+
+#, c-format
+msgid "ERROR: Unable to write print data: %s\n"
+msgstr "ERROR: 無法寫入列å°è³‡æ–™ï¼š%s\n"
+
+msgid "ERROR: Unable to write raster data to driver\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unable to write uncompressed document data: %s\n"
+msgstr "ERROR: 無法寫入未壓縮的文件資料:%s\n"
+
+#, c-format
+msgid "ERROR: Unexpected text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown encryption option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown file order \"%s\"\n"
+msgstr "ERROR: 未知的檔案順åºâ€œ%sâ€\n"
+
+#, c-format
+msgid "ERROR: Unknown format character \"%c\"\n"
+msgstr "ERROR: 未知的格å¼å­—元“%câ€\n"
+
+#, c-format
+msgid "ERROR: Unknown message catalog format for \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown option \"%s\" with value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unknown print mode \"%s\"\n"
+msgstr "ERROR: 未知的列å°æ¨¡å¼â€œ%sâ€\n"
+
+#, c-format
+msgid "ERROR: Unknown version option value \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported brightness value %s, using brightness=100\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported gamma value %s, using gamma=1000\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported number-up value %d, using number-up=1\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ERROR: Unsupported number-up-layout value %s, using number-up-layout=lrtb\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: Unsupported page-border value %s, using page-border=none\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited on signal %d\n"
+msgstr ""
+
+#, c-format
+msgid "ERROR: pictwpstops exited with status %d\n"
+msgstr ""
+
+msgid "ERROR: select() failed"
+msgstr "ERROR: select() 失敗"
+
+msgid "ERROR: unable to stat print file"
+msgstr "ERROR: 無法開始列å°æª”案"
+
+msgid "Edit Configuration File"
+msgstr "編輯é…置檔案"
+
+msgid "Empty PPD file"
+msgstr ""
+
+msgid "Ending Banner"
+msgstr "çµæŸæ¨™èªž"
+
+msgid "English"
+msgstr ""
+
+msgid "Enter old password:"
+msgstr "輸入新密碼:"
+
+msgid "Enter password again:"
+msgstr "è«‹å†è¼¸å…¥å¯†ç¢¼ï¼š"
+
+msgid "Enter password:"
+msgstr "輸入密碼:"
+
+msgid ""
+"Enter your username and password or the root username and password to access "
+"this page. If you are using Kerberos authentication, make sure you have a "
+"valid Kerberos ticket."
+msgstr ""
+"請輸入您的使用者å稱和密碼或 root 使用者å稱和密碼來存å–æ­¤é é¢ã€‚如果您是使用 "
+"Kerberos èªè­‰ï¼Œè«‹ç¢ºå®šå…·å‚™æœ‰æ•ˆçš„ Kerberos 票券。"
+
+msgid "Envelope Feed"
+msgstr "ä¿¡å°é€ç´™å™¨"
+
+msgid "Epson"
+msgstr "Epson"
+
+msgid "Error Policy"
+msgstr "錯誤的原則"
+
+msgid "Error: need hostname after '-h' option\n"
+msgstr ""
+
+msgid "Every 10 Labels"
+msgstr "æ¯ 10 個標籤"
+
+msgid "Every 2 Labels"
+msgstr "æ¯ 2 個標籤"
+
+msgid "Every 3 Labels"
+msgstr "æ¯ 3 個標籤"
+
+msgid "Every 4 Labels"
+msgstr "æ¯ 4 個標籤"
+
+msgid "Every 5 Labels"
+msgstr "æ¯ 5 個標籤"
+
+msgid "Every 6 Labels"
+msgstr "æ¯ 6 個標籤"
+
+msgid "Every 7 Labels"
+msgstr "æ¯ 7 個標籤"
+
+msgid "Every 8 Labels"
+msgstr "æ¯ 8 個標籤"
+
+msgid "Every 9 Labels"
+msgstr "æ¯ 9 個標籤"
+
+msgid "Every Label"
+msgstr "æ¯ä¸€å€‹æ¨™ç±¤"
+
+msgid "Expectation Failed"
+msgstr "與é æœŸä¸ç¬¦"
+
+msgid "Export Printers to Samba"
+msgstr "å°‡å°è¡¨æ©Ÿè¼¸å‡ºè‡³ Samba"
+
+msgid "FAIL\n"
+msgstr "失敗\n"
+
+msgid "File Folder"
+msgstr "檔案夾"
+
+msgid "File Folder - 9/16 x 3 7/16\""
+msgstr "檔案夾 - 9/16 x 3 7/16\""
+
+#, c-format
+msgid ""
+"File device URIs have been disabled! To enable, see the FileDevice directive "
+"in \"%s/cupsd.conf\"."
+msgstr ""
+"å·²åœç”¨æª”案設備 URIï¼è‹¥è¦å•Ÿç”¨ï¼Œè«‹åƒé–±â€œ%s/cupsd.confâ€ä¸­çš„ FileDevice 指示。"
+
+msgid "Folio"
+msgstr "å°é–‹ç´™"
+
+msgid "Forbidden"
+msgstr "å·²ç¦æ­¢"
+
+msgid "General"
+msgstr "一般"
+
+msgid "Generic"
+msgstr "通用"
+
+msgid "German FanFold"
+msgstr "å¾·å¼æŠ˜ç–Šå¼å ±è¡¨ç´™ï¼ˆGerman FanFold)"
+
+msgid "German FanFold Legal"
+msgstr "å¾·å¼æŠ˜ç–Šå¼æ³•å®šå ±è¡¨ç´™ï¼ˆGerman FanFold Legal)"
+
+msgid "Get-Response-PDU uses indefinite length"
+msgstr "Get-Response-PDU 使用的長度ä¸ç¢ºå®š"
+
+msgid "Glossy Paper"
+msgstr "é¡é¢ç´™"
+
+msgid "Got a printer-uri attribute but no job-id"
+msgstr ""
+
+msgid "Grayscale"
+msgstr "ç°éšŽ"
+
+msgid "HP"
+msgstr "HP"
+
+msgid "Hanging Folder"
+msgstr "懸掛的檔案夾"
+
+msgid "Hanging Folder - 9/16 x 2\""
+msgstr "懸掛的檔案夾 - 9/16 x 2\""
+
+msgid "INFO: AppleTalk disabled in System Preferences\n"
+msgstr "INFO: 已在“系統å好設定â€ä¸­åœç”¨ AppleTalk\n"
+
+msgid "INFO: AppleTalk disabled in System Preferences.\n"
+msgstr "INFO: 已在“系統å好設定â€ä¸­åœç”¨ AppleTalk。\n"
+
+msgid "INFO: Canceling print job...\n"
+msgstr "INFO: 正在å–消列å°ä½œæ¥­â‹¯\n"
+
+msgid "INFO: Connected to printer...\n"
+msgstr "INFO: 已連接å°è¡¨æ©Ÿâ‹¯\n"
+
+msgid "INFO: Connecting to printer...\n"
+msgstr "INFO: 正在連接å°è¡¨æ©Ÿâ‹¯\n"
+
+msgid "INFO: Control file sent successfully\n"
+msgstr "INFO: å·²æˆåŠŸå‚³é€æŽ§åˆ¶æª”案\n"
+
+msgid "INFO: Copying print data...\n"
+msgstr ""
+
+msgid "INFO: Data file sent successfully\n"
+msgstr "INFO: å·²æˆåŠŸå‚³é€è³‡æ–™æª”\n"
+
+#, c-format
+msgid "INFO: Finished page %d...\n"
+msgstr ""
+
+#, c-format
+msgid "INFO: Formatting page %d...\n"
+msgstr "INFO: 正在格å¼åŒ–é é¢ %d⋯\n"
+
+msgid "INFO: Loading image file...\n"
+msgstr "INFO: 正在載入影åƒæª”⋯\n"
+
+msgid "INFO: Looking for printer...\n"
+msgstr "INFO: 正在尋找å°è¡¨æ©Ÿâ‹¯\n"
+
+msgid "INFO: Opening connection\n"
+msgstr "INFO: 正在打開連線\n"
+
+msgid "INFO: Print file sent, waiting for printer to finish...\n"
+msgstr "INFO: 已傳é€åˆ—å°æª”案,正在等待å°è¡¨æ©Ÿå®Œæˆå·¥ä½œâ‹¯\n"
+
+msgid "INFO: Printer busy; will retry in 10 seconds...\n"
+msgstr "INFO: å°è¡¨æ©Ÿå¿™ç¢Œä¸­ï¼›10 秒內將é‡è©¦â‹¯\n"
+
+msgid "INFO: Printer busy; will retry in 30 seconds...\n"
+msgstr "INFO: å°è¡¨æ©Ÿå¿™ç¢Œä¸­ï¼›30 秒內將é‡è©¦â‹¯\n"
+
+msgid "INFO: Printer busy; will retry in 5 seconds...\n"
+msgstr "INFO: å°è¡¨æ©Ÿå¿™ç¢Œä¸­ï¼›5 秒內將é‡è©¦â‹¯\n"
+
+#, c-format
+msgid "INFO: Printer does not support IPP/%d.%d, trying IPP/1.0...\n"
+msgstr "INFO: å°è¡¨æ©Ÿä¸æ”¯æ´ IPP/%d.%d,正在嘗試 IPP/1.0⋯\n"
+
+msgid "INFO: Printer is busy; will retry in 5 seconds...\n"
+msgstr "INFO: å°è¡¨æ©Ÿå¿™ç¢Œä¸­ï¼›5 秒內將é‡è©¦â‹¯\n"
+
+msgid "INFO: Printer is currently off-line.\n"
+msgstr "INFO: å°è¡¨æ©Ÿç›®å‰å·²é›¢ç·šã€‚\n"
+
+msgid "INFO: Printer is currently offline.\n"
+msgstr "INFO: å°è¡¨æ©Ÿç›®å‰å·²é›¢ç·šã€‚\n"
+
+msgid "INFO: Printer is now online.\n"
+msgstr "INFO: å°è¡¨æ©Ÿå·²å›žåˆ°ç·šä¸Šã€‚\n"
+
+msgid "INFO: Printer is offline.\n"
+msgstr "INFO: å°è¡¨æ©Ÿå·²é›¢ç·šã€‚\n"
+
+msgid "INFO: Printer not connected; will retry in 30 seconds...\n"
+msgstr "INFO: 未連接å°è¡¨æ©Ÿï¼›30 秒內將é‡è©¦â‹¯\n"
+
+#, c-format
+msgid "INFO: Printing page %d, %d%% complete...\n"
+msgstr "INFO: 正在列å°é é¢ %d,%d%% 已完æˆâ‹¯\n"
+
+#, c-format
+msgid "INFO: Printing page %d...\n"
+msgstr "INFO: 正在列å°é é¢ %d⋯\n"
+
+msgid "INFO: Ready to print.\n"
+msgstr "INFO: 準備好進行列å°ã€‚\n"
+
+#, c-format
+msgid "INFO: Sending control file (%lu bytes)\n"
+msgstr "INFO: 正在傳é€æŽ§åˆ¶æª”案(%lu ä½å…ƒçµ„)\n"
+
+#, c-format
+msgid "INFO: Sending control file (%u bytes)\n"
+msgstr "INFO: 正在傳é€æŽ§åˆ¶æª”案(%u ä½å…ƒçµ„)\n"
+
+msgid "INFO: Sending data\n"
+msgstr "INFO: 正在傳é€è³‡æ–™\n"
+
+#, c-format
+msgid "INFO: Sending data file (%ld bytes)\n"
+msgstr "INFO: 正在傳é€è³‡æ–™æª”(%ld ä½å…ƒçµ„)\n"
+
+#, c-format
+msgid "INFO: Sending data file (%lld bytes)\n"
+msgstr "INFO: 正在傳é€è³‡æ–™æª”(%lld ä½å…ƒçµ„)\n"
+
+msgid "INFO: Sending print data...\n"
+msgstr "INFO: 正在傳é€åˆ—å°è³‡æ–™â‹¯\n"
+
+#, c-format
+msgid "INFO: Sent print file, %ld bytes...\n"
+msgstr "INFO: 已傳é€åˆ—å°æª”案,%ld ä½å…ƒçµ„⋯\n"
+
+#, c-format
+msgid "INFO: Sent print file, %lld bytes...\n"
+msgstr "INFO: 已傳é€åˆ—å°æª”案,%lld ä½å…ƒçµ„⋯\n"
+
+#, c-format
+msgid "INFO: Spooling LPR job, %.0f%% complete...\n"
+msgstr "INFO: 正在緩è¡åˆ—å°ä½œæ¥­ï¼Œ%.0f%% 已完æˆâ‹¯\n"
+
+#, c-format
+msgid "INFO: Starting page %d...\n"
+msgstr ""
+
+msgid "INFO: Unable to contact printer, queuing on next printer in class...\n"
+msgstr "INFO: 無法è¯çµ¡å°è¡¨æ©Ÿï¼Œæ­£åœ¨ä½‡åˆ—等待類別中的下一個å°è¡¨æ©Ÿâ‹¯\n"
+
+#, c-format
+msgid "INFO: Using default AppleTalk zone \"%s\"\n"
+msgstr "INFO: 使用é è¨­çš„ AppleTalk å€åŸŸâ€œ%sâ€\n"
+
+msgid "INFO: Waiting for job to complete...\n"
+msgstr "INFO: 正在等待作業完æˆâ‹¯\n"
+
+msgid "INFO: Waiting for printer to become available...\n"
+msgstr "INFO: 正在等待å°è¡¨æ©Ÿæˆç‚ºå¯ç”¨ç‹€æ…‹â‹¯\n"
+
+msgid "ISO B0"
+msgstr "ISO B0"
+
+msgid "ISO B1"
+msgstr "ISO B1"
+
+msgid "ISO B10"
+msgstr "ISO B10"
+
+msgid "ISO B2"
+msgstr "ISO B2"
+
+msgid "ISO B3"
+msgstr "ISO B3"
+
+msgid "ISO B4"
+msgstr "ISO B4"
+
+msgid "ISO B4 Envelope"
+msgstr "ISO B4 ä¿¡å°"
+
+msgid "ISO B5"
+msgstr "ISO B5"
+
+msgid "ISO B5 (Oversize)"
+msgstr "ISO B5(超大型)"
+
+msgid "ISO B5 Envelope"
+msgstr "ISO B5 ä¿¡å°"
+
+msgid "ISO B6"
+msgstr "ISO B6"
+
+msgid "ISO B6 Envelope"
+msgstr "ISO B6 ä¿¡å°"
+
+msgid "ISO B7"
+msgstr "ISO B7"
+
+msgid "ISO B8"
+msgstr "ISO B8"
+
+msgid "ISO B9"
+msgstr "ISO B9"
+
+msgid "ISOLatin1"
+msgstr "UTF-8"
+
+msgid "Illegal control character"
+msgstr "ä¸åˆæ³•çš„控制字元"
+
+msgid "Illegal main keyword string"
+msgstr "ä¸åˆæ³•çš„主è¦é—œéµå­—串"
+
+msgid "Illegal option keyword string"
+msgstr "ä¸åˆæ³•çš„é¸é …é—œéµå­—串"
+
+msgid "Illegal translation string"
+msgstr "ä¸åˆæ³•çš„轉æ›å­—串"
+
+msgid "Illegal whitespace character"
+msgstr "ä¸åˆæ³•çš„空白字元"
+
+msgid "Installable Options"
+msgstr "å¯å®‰è£çš„é¸é …"
+
+msgid "Installed"
+msgstr "已安è£"
+
+msgid "IntelliBar Label Printer"
+msgstr "IntelliBar 標籤å°è¡¨æ©Ÿ"
+
+msgid "Intellitech"
+msgstr "Intellitech"
+
+msgid "Internal Server Error"
+msgstr ""
+
+msgid "Internal error"
+msgstr "內部錯誤"
+
+msgid "Internet Postage 2-Part"
+msgstr "Internet Postage 2-Part"
+
+msgid "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+msgstr "Internet Postage 2-Part - 2 1/4 x 7 1/2\""
+
+msgid "Internet Postage 3-Part"
+msgstr "Internet Postage 3-Part"
+
+msgid "Internet Postage 3-Part - 2 1/4 x 7\""
+msgstr "Internet Postage 3-Part - 2 1/4 x 7\""
+
+msgid "Internet Printing Protocol"
+msgstr "Internet 列å°é€šè¨Šå”定"
+
+msgid "Invite Envelope"
+msgstr "邀請信å°"
+
+msgid "Italian Envelope"
+msgstr "義大利信å°"
+
+msgid "JCL"
+msgstr "JCL"
+
+#, c-format
+msgid "Job #%d cannot be restarted - no files"
+msgstr ""
+
+#, c-format
+msgid "Job #%d does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is already aborted - can't cancel."
+msgstr "已中止作業 #%d - 無法å–消。"
+
+#, c-format
+msgid "Job #%d is already canceled - can't cancel."
+msgstr "å·²å–消作業 #%d - 無法å–消。"
+
+#, c-format
+msgid "Job #%d is already completed - can't cancel."
+msgstr "已完æˆä½œæ¥­ #%d - 無法å–消。"
+
+#, c-format
+msgid "Job #%d is finished and cannot be altered"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not complete"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held"
+msgstr ""
+
+#, c-format
+msgid "Job #%d is not held for authentication"
+msgstr ""
+
+#, c-format
+msgid "Job #%s does not exist"
+msgstr ""
+
+#, c-format
+msgid "Job %d not found"
+msgstr ""
+
+msgid "Job Completed"
+msgstr "已完æˆä½œæ¥­"
+
+msgid "Job Created"
+msgstr "已建立作業"
+
+msgid "Job ID: "
+msgstr "作業 ID:"
+
+msgid "Job Options Changed"
+msgstr "已更改作業é¸é …"
+
+msgid "Job Stopped"
+msgstr "å·²åœæ­¢ä½œæ¥­"
+
+msgid "Job UUID: "
+msgstr "作業 UUID:"
+
+msgid "Job is completed and cannot be changed."
+msgstr "作業已完æˆä¸”無法更改。"
+
+msgid "Job operation failed:"
+msgstr "作業æ“作失敗:"
+
+msgid "Job state cannot be changed."
+msgstr "無法更改作業狀態。"
+
+msgid "Job subscriptions cannot be renewed"
+msgstr ""
+
+msgid "Jobs"
+msgstr "作業"
+
+msgid "Kaku2 Envelope"
+msgstr "Kaku2 ä¿¡å°"
+
+msgid "Kaku3 Envelope"
+msgstr "Kaku3 ä¿¡å°"
+
+msgid "LPD/LPR Host or Printer"
+msgstr "LPD/LPR 主機或å°è¡¨æ©Ÿ"
+
+msgid "Label Printer"
+msgstr "標籤å°è¡¨æ©Ÿ"
+
+msgid "Label Top"
+msgstr "標籤頂端"
+
+#, c-format
+msgid "Language \"%s\" not supported"
+msgstr ""
+
+msgid "Large Address"
+msgstr "大型地å€"
+
+msgid "Large Address - 1 4/10 x 3 1/2\""
+msgstr "å¤§åž‹åœ°å€ - 1 4/10 x 3 1/2\""
+
+msgid "LaserJet Series PCL 4/5"
+msgstr "LaserJet 系列 PCL 4/5"
+
+msgid "Light"
+msgstr "ä¸æ˜Žé¡¯"
+
+msgid "Line longer than the maximum allowed (255 characters)"
+msgstr "å…許行長度大於最大值(255 個字元)"
+
+msgid "List Available Printers"
+msgstr "列出å¯ç”¨å°è¡¨æ©Ÿ"
+
+msgid "Location: "
+msgstr "ä½ç½®ï¼š"
+
+msgid "Long-Edge (Portrait)"
+msgstr "沿長邊(直å¼ï¼‰"
+
+msgid "Make and Model: "
+msgstr "製造和型號:"
+
+msgid "Manual Feed"
+msgstr "手動é€ç´™"
+
+msgid "Media Dimensions: "
+msgstr "媒體尺寸:"
+
+msgid "Media Limits: "
+msgstr "媒體é™åˆ¶ï¼š"
+
+msgid "Media Name: "
+msgstr "媒體å稱:"
+
+msgid "Media Size"
+msgstr "媒體大å°"
+
+msgid "Media Source"
+msgstr "媒體來æº"
+
+msgid "Media Tracking"
+msgstr "媒體軌跡"
+
+msgid "Media Type"
+msgstr "媒體類型"
+
+msgid "Medium"
+msgstr "中"
+
+msgid "Memory allocation error"
+msgstr "記憶體分é…錯誤"
+
+msgid "Missing PPD-Adobe-4.x header"
+msgstr "éºå¤± PPD-Adobe-4.x 標題"
+
+msgid "Missing asterisk in column 1"
+msgstr "直欄 1 中éºå¤±æ˜Ÿè™Ÿ"
+
+msgid "Missing document-number attribute"
+msgstr ""
+
+#, c-format
+msgid "Missing double quote on line %d"
+msgstr ""
+
+msgid "Missing form variable"
+msgstr ""
+
+msgid "Missing notify-subscription-ids attribute"
+msgstr ""
+
+msgid "Missing option keyword"
+msgstr ""
+
+msgid "Missing requesting-user-name attribute"
+msgstr ""
+
+msgid "Missing required attributes"
+msgstr ""
+
+#, c-format
+msgid "Missing value on line %d"
+msgstr ""
+
+msgid "Missing value string"
+msgstr "éºå¤±å€¼å­—串"
+
+#, c-format
+msgid ""
+"Model: name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+msgstr ""
+"型號:name = %s\n"
+" natural_language = %s\n"
+" make-and-model = %s\n"
+" device-id = %s\n"
+
+msgid "Modify Class"
+msgstr "修改類別"
+
+msgid "Modify Printer"
+msgstr "修改å°è¡¨æ©Ÿ"
+
+msgid "Monarch"
+msgstr "Monarch"
+
+msgid "Monarch Envelope"
+msgstr "Monarch ä¿¡å°"
+
+msgid "Move All Jobs"
+msgstr "移動所有作業"
+
+msgid "Move Job"
+msgstr "移動作業"
+
+msgid "Moved Permanently"
+msgstr "永久地移動"
+
+#, c-format
+msgid "NOTICE: Print file accepted - job ID %d.\n"
+msgstr "NOTICE: 已接å—列å°æª”案 - 作業 ID %d。\n"
+
+msgid "NOTICE: Print file accepted - job ID unknown.\n"
+msgstr "NOTICE: 已接å—列å°æª”案 - 作業 ID 未知。\n"
+
+msgid "NULL PPD file pointer"
+msgstr "NULL PPD 檔案指標"
+
+msgid "Name OID uses indefinite length"
+msgstr "å稱 OID 使用的長度ä¸ç¢ºå®š"
+
+msgid "Nested classes are not allowed"
+msgstr ""
+
+msgid "Never"
+msgstr "æ°¸ä¸"
+
+msgid "New Stylus Color Series"
+msgstr "新 Stylus Color 系列"
+
+msgid "New Stylus Photo Series"
+msgstr "新 Stylus Photo 系列"
+
+msgid "No"
+msgstr "å¦"
+
+msgid "No Content"
+msgstr "無內容"
+
+msgid "No PPD name"
+msgstr ""
+
+msgid "No VarBind SEQUENCE"
+msgstr "沒有 VarBind SEQUENCE"
+
+msgid "No Windows printer drivers are installed"
+msgstr ""
+
+msgid "No active connection"
+msgstr "沒有已啟用的連線"
+
+#, c-format
+msgid "No active jobs on %s"
+msgstr ""
+
+msgid "No attributes in request"
+msgstr ""
+
+msgid "No authentication information provided"
+msgstr ""
+
+msgid "No community name"
+msgstr "沒有社群å稱"
+
+msgid "No default printer"
+msgstr "沒有é è¨­å°è¡¨æ©Ÿ"
+
+msgid "No destinations added."
+msgstr "未加入目的地。"
+
+msgid "No error-index"
+msgstr "沒有錯誤索引"
+
+msgid "No error-status"
+msgstr "沒有錯誤狀態"
+
+msgid "No file!?"
+msgstr ""
+
+msgid "No modification time"
+msgstr ""
+
+msgid "No name OID"
+msgstr "沒有å稱 OID"
+
+msgid "No printer name"
+msgstr ""
+
+msgid "No printer-uri found"
+msgstr ""
+
+msgid "No printer-uri found for class"
+msgstr ""
+
+msgid "No printer-uri in request"
+msgstr ""
+
+msgid "No request-id"
+msgstr "沒有 request-id"
+
+msgid "No subscription attributes in request"
+msgstr ""
+
+msgid "No subscriptions found."
+msgstr "找ä¸åˆ°è¨‚閱。"
+
+msgid "No variable-bindings SEQUENCE"
+msgstr "沒有 variable-bindings SEQUENCE"
+
+msgid "No version number"
+msgstr "沒有版本號碼"
+
+msgid "Non-continuous (Mark sensing)"
+msgstr "ä¸é€£çºŒï¼ˆæ¨™ç¤ºæ„Ÿæ‡‰ï¼‰"
+
+msgid "Non-continuous (Web sensing)"
+msgstr "ä¸é€£çºŒï¼ˆWeb 感應)"
+
+msgid "Normal"
+msgstr "正常"
+
+msgid "Not Found"
+msgstr "找ä¸åˆ°"
+
+msgid "Not Implemented"
+msgstr "尚未完æˆ"
+
+msgid "Not Installed"
+msgstr "尚未安è£"
+
+msgid "Not Modified"
+msgstr "尚未修改"
+
+msgid "Not Supported"
+msgstr "ä¸å—支æ´"
+
+msgid "Not allowed to print."
+msgstr "ä¸å…許列å°ã€‚"
+
+msgid "Note"
+msgstr "注æ„"
+
+msgid "OK"
+msgstr "確定"
+
+msgid "Off (1-Sided)"
+msgstr "關(單é¢ï¼‰"
+
+msgid "Oki"
+msgstr "Oki"
+
+msgid "Online Help"
+msgstr "線上輔助說明"
+
+#, c-format
+msgid "Open of %s failed: %s"
+msgstr "打開 %s 失敗:%s"
+
+msgid "OpenGroup without a CloseGroup first"
+msgstr "OpenGroup 之å‰æ²’有先 CloseGroup"
+
+msgid "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"
+msgstr "OpenUI/JCLOpenUI 之å‰æ²’有先 CloseUI/JCLCloseUI"
+
+msgid "Operation Policy"
+msgstr "æ“作政策"
+
+msgid "Options Installed"
+msgstr "已安è£çš„é¸é …"
+
+msgid "Options: "
+msgstr "é¸é …:"
+
+msgid "Output Mode"
+msgstr "輸出模å¼"
+
+#, c-format
+msgid "Output for printer %s is sent to %s\n"
+msgstr "已將å°è¡¨æ©Ÿ %s 的輸出傳é€è‡³ %s\n"
+
+#, c-format
+msgid "Output for printer %s is sent to remote printer %s on %s\n"
+msgstr "已將å°è¡¨æ©Ÿ %s 的輸出傳é€è‡³é ç«¯å°è¡¨æ©Ÿ %s(ä½æ–¼ %s 上)\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to %s\n"
+msgstr "已將å°è¡¨æ©Ÿ %s/%s 的輸出傳é€è‡³ %s\n"
+
+#, c-format
+msgid "Output for printer %s/%s is sent to remote printer %s on %s\n"
+msgstr "已將å°è¡¨æ©Ÿ %s/%s 的輸出傳é€è‡³é ç«¯å°è¡¨æ©Ÿ %s(ä½æ–¼ %s 上)\n"
+
+msgid "PASS\n"
+msgstr "通éŽ\n"
+
+msgid "PCL Laser Printer"
+msgstr "PCL é›·å°„å°è¡¨æ©Ÿ"
+
+msgid "PRC1 Envelope"
+msgstr "PRC1 ä¿¡å°"
+
+msgid "PRC10 Envelope"
+msgstr "PRC10 ä¿¡å°"
+
+msgid "PRC16K"
+msgstr "PRC16K"
+
+msgid "PRC2 Envelope"
+msgstr "PRC2 ä¿¡å°"
+
+msgid "PRC3 Envelope"
+msgstr "PRC3 ä¿¡å°"
+
+msgid "PRC32K"
+msgstr "PRC32K"
+
+msgid "PRC32K (Oversize)"
+msgstr "PRC32K(超大型)"
+
+msgid "PRC4 Envelope"
+msgstr "PRC4 ä¿¡å°"
+
+msgid "PRC5 Envelope"
+msgstr "PRC5 ä¿¡å°"
+
+msgid "PRC6 Envelope"
+msgstr "PRC6 ä¿¡å°"
+
+msgid "PRC7 Envelope"
+msgstr "PRC7 ä¿¡å°"
+
+msgid "PRC8 Envelope"
+msgstr "PRC8 ä¿¡å°"
+
+msgid "PRC9 Envelope"
+msgstr "PRC9 ä¿¡å°"
+
+msgid "Packet does not contain a Get-Response-PDU"
+msgstr "å°åŒ…ä¸åŒ…å« Get-Response-PDU"
+
+msgid "Packet does not start with SEQUENCE"
+msgstr "å°åŒ…ä¸æ˜¯ä»¥ SEQUENCE é–‹é ­"
+
+msgid "ParamCustominCutInterval"
+msgstr "ParamCustominCutInterval"
+
+msgid "ParamCustominTearInterval"
+msgstr "ParamCustominTearInterval"
+
+#, c-format
+msgid "Password for %s on %s? "
+msgstr "éœ€è¦ %s(ä½æ–¼ %s 上)的密碼?"
+
+#, c-format
+msgid "Password for %s required to access %s via SAMBA: "
+msgstr "éœ€è¦ %s 的密碼æ‰èƒ½é€éŽ SAMBA å­˜å– %s:"
+
+msgid "Pause Class"
+msgstr "æš«åœé¡žåˆ¥"
+
+msgid "Pause Printer"
+msgstr "æš«åœå°è¡¨æ©Ÿ"
+
+msgid "Peel-Off"
+msgstr "去皮"
+
+msgid "Personal Envelope"
+msgstr "個人信å°"
+
+msgid "Photo"
+msgstr "照片"
+
+msgid "Photo Labels"
+msgstr "照片標籤"
+
+msgid "Plain Paper"
+msgstr "一般紙張"
+
+msgid "Policies"
+msgstr "政策"
+
+msgid "Port Monitor"
+msgstr "連接埠監視器"
+
+msgid "PostScript Printer"
+msgstr "PostScript å°è¡¨æ©Ÿ"
+
+msgid "Postcard"
+msgstr "明信片"
+
+msgid "Print Density"
+msgstr "列å°å¯†åº¦"
+
+msgid "Print Job:"
+msgstr "列å°ä½œæ¥­ï¼š"
+
+msgid "Print Mode"
+msgstr "列å°æ¨¡å¼"
+
+msgid "Print Rate"
+msgstr "列å°é€ŸçŽ‡"
+
+msgid "Print Self-Test Page"
+msgstr "列å°è‡ªæˆ‘測試é é¢"
+
+msgid "Print Speed"
+msgstr "列å°é€Ÿåº¦"
+
+msgid "Print Test Page"
+msgstr "列å°æ¸¬è©¦é é¢"
+
+msgid "Print and Cut"
+msgstr "列å°ä¸¦å‰ªä¸‹"
+
+msgid "Print and Tear"
+msgstr "列å°ä¸¦æ’•é–‹"
+
+msgid "Printed For: "
+msgstr "列å°å°è±¡ï¼š"
+
+msgid "Printed From: "
+msgstr "列å°è‡ªï¼š"
+
+msgid "Printed On: "
+msgstr "列å°æ—¥æœŸï¼š"
+
+msgid "Printer Added"
+msgstr "已加入å°è¡¨æ©Ÿ"
+
+msgid "Printer Default"
+msgstr "é è¨­å°è¡¨æ©Ÿ"
+
+msgid "Printer Deleted"
+msgstr "已刪除å°è¡¨æ©Ÿ"
+
+msgid "Printer Modified"
+msgstr "已修改å°è¡¨æ©Ÿ"
+
+msgid "Printer Name: "
+msgstr "å°è¡¨æ©Ÿå稱:"
+
+msgid "Printer Paused"
+msgstr "å°è¡¨æ©Ÿå·²æš«åœ"
+
+msgid "Printer Settings"
+msgstr "å°è¡¨æ©Ÿè¨­å®š"
+
+msgid "Printer:"
+msgstr "å°è¡¨æ©Ÿï¼š"
+
+msgid "Printers"
+msgstr "å°è¡¨æ©Ÿ"
+
+msgid "Purge Jobs"
+msgstr "清除作業"
+
+msgid "Quarto"
+msgstr "四開紙"
+
+msgid "Quota limit reached."
+msgstr "å·²é”到四開紙é™åˆ¶ã€‚"
+
+msgid "Rank Owner Job File(s) Total Size\n"
+msgstr "等級 æŒæœ‰äºº 作業 檔案 大å°ç¸½è¨ˆ\n"
+
+msgid ""
+"Rank Owner Pri Job Files Total Size\n"
+msgstr ""
+"等級 æŒæœ‰äºº 優先作業 檔案 大å°ç¸½è¨ˆ\n"
+
+msgid "Reject Jobs"
+msgstr "退出作業"
+
+msgid "Reprint After Error"
+msgstr "發生錯誤後é‡æ–°åˆ—å°"
+
+msgid "Request Entity Too Large"
+msgstr "請求的實體éŽå¤§"
+
+msgid "Resolution"
+msgstr "解æžåº¦"
+
+msgid "Resume Class"
+msgstr "繼續類別"
+
+msgid "Resume Printer"
+msgstr "繼續å°è¡¨æ©Ÿ"
+
+msgid "Return Address"
+msgstr "寄件人地å€"
+
+msgid "Return Address - 3/4 x 2\""
+msgstr "å¯„ä»¶äººåœ°å€ - 3/4 x 2\""
+
+msgid "Rewind"
+msgstr "倒轉"
+
+#, c-format
+msgid "Running command: %s %s -N -A %s -c '%s'\n"
+msgstr "執行指令:%s %s -N -A %s -c '%s'\n"
+
+msgid "SEQUENCE uses indefinite length"
+msgstr "SEQUENCE 使用的長度ä¸ç¢ºå®š"
+
+msgid "See Other"
+msgstr "åƒé–±å…¶ä»–"
+
+#, c-format
+msgid "Serial Port #%d"
+msgstr "åºåˆ—埠 #%d"
+
+msgid "Server Restarted"
+msgstr "é‡æ–°å•Ÿå‹•ä¼ºæœå™¨"
+
+msgid "Server Security Auditing"
+msgstr "伺æœå™¨å®‰å…¨æ€§å¯©å®š"
+
+msgid "Server Started"
+msgstr "已啟動伺æœå™¨"
+
+msgid "Server Stopped"
+msgstr "å·²åœæ­¢ä¼ºæœå™¨"
+
+msgid "Service Unavailable"
+msgstr "æœå‹™ç„¡æ³•ä½¿ç”¨"
+
+msgid "Set Allowed Users"
+msgstr "設定å…許的使用者"
+
+msgid "Set As Server Default"
+msgstr "設為伺æœå™¨é è¨­å€¼"
+
+msgid "Set Class Options"
+msgstr "設定類別é¸é …"
+
+msgid "Set Printer Options"
+msgstr "設定å°è¡¨æ©Ÿé¸é …"
+
+msgid "Set Publishing"
+msgstr "設定發佈"
+
+msgid "Shipping Address"
+msgstr "é‹é€åœ°å€"
+
+msgid "Shipping Address - 2 5/16 x 4\""
+msgstr "é‹é€åœ°å€ - 2 5/16 x 4\""
+
+msgid "Short-Edge (Landscape)"
+msgstr "沿短邊(橫å¼ï¼‰"
+
+msgid "Special Paper"
+msgstr "特殊紙張"
+
+msgid "Standard"
+msgstr "標準"
+
+msgid "Starting Banner"
+msgstr "起始標語"
+
+msgid "Statement"
+msgstr "敘述"
+
+msgid "Stylus Color Series"
+msgstr "Stylus Color 系列"
+
+msgid "Stylus Photo Series"
+msgstr "Stylus Photo 系列"
+
+msgid "Super A"
+msgstr "Super A"
+
+msgid "Super B"
+msgstr "Super B"
+
+msgid "Super B/A3"
+msgstr "Super B/A3"
+
+msgid "Switching Protocols"
+msgstr "切æ›é€šè¨Šå”定"
+
+msgid "Tabloid"
+msgstr "å°å ±ç”¨ç´™ï¼ˆTabloid)"
+
+msgid "Tabloid (Oversize)"
+msgstr "å°å ±ç”¨ç´™ï¼è¶…大型(Tabloidï¼Oversize)"
+
+msgid "Tear"
+msgstr "æ’•é–‹"
+
+msgid "Tear-Off"
+msgstr "撕下"
+
+msgid "Tear-Off Adjust Position"
+msgstr "撕下調整ä½ç½®"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be found."
+msgstr "找ä¸åˆ° PPD 檔案“%sâ€ã€‚"
+
+#, c-format
+msgid "The PPD file \"%s\" could not be opened: %s"
+msgstr "無法打開 PPD 檔案“%sâ€ï¼š%s"
+
+msgid ""
+"The class name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"類別å稱åªèƒ½åŒ…å«æœ€å¤š 127 個å¯åˆ—å°å­—元,而且ä¸èƒ½åŒ…å«ç©ºæ ¼ã€æ–œç·šï¼ˆ/)或井字號"
+"(#)。"
+
+msgid "The developer unit needs to be replaced."
+msgstr ""
+
+msgid "The developer unit will need to be replaced soon."
+msgstr ""
+
+msgid "The fuser's temperature is high."
+msgstr ""
+
+msgid "The fuser's temperature is low."
+msgstr ""
+
+msgid ""
+"The notify-lease-duration attribute cannot be used with job subscriptions."
+msgstr "notify-lease-duration 屬性ä¸èƒ½èˆ‡ä½œæ¥­è¨‚é–±æ­é…使用。"
+
+#, c-format
+msgid "The notify-user-data value is too large (%d > 63 octets)"
+msgstr ""
+
+msgid "The optical photoconductor needs to be replaced."
+msgstr ""
+
+msgid "The optical photoconductor will need to be replaced soon."
+msgstr ""
+
+msgid "The output bin is almost full."
+msgstr ""
+
+msgid "The output bin is full."
+msgstr ""
+
+msgid "The output bin is missing."
+msgstr ""
+
+msgid "The paper tray is almost empty."
+msgstr ""
+
+msgid "The paper tray is empty."
+msgstr ""
+
+msgid "The paper tray is missing."
+msgstr ""
+
+msgid "The paper tray needs to be filled."
+msgstr ""
+
+msgid "The printer is almost out of ink."
+msgstr ""
+
+msgid "The printer is low on toner."
+msgstr ""
+
+msgid "The printer is offline."
+msgstr ""
+
+msgid "The printer is out of ink."
+msgstr ""
+
+msgid "The printer is out of toner."
+msgstr ""
+
+msgid ""
+"The printer name may only contain up to 127 printable characters and may not "
+"contain spaces, slashes (/), or the pound sign (#)."
+msgstr ""
+"å°è¡¨æ©Ÿå稱åªèƒ½åŒ…å«æœ€å¤š 127 個å¯åˆ—å°çš„字元,而且ä¸èƒ½åŒ…å«ç©ºæ ¼ã€æ–œç·šï¼ˆ/)或井字"
+"號(#)。"
+
+msgid "The printer or class is not shared"
+msgstr ""
+
+msgid "The printer or class was not found."
+msgstr "找ä¸åˆ°å°è¡¨æ©Ÿæˆ–類別。"
+
+msgid "The printer's cover is open."
+msgstr ""
+
+msgid "The printer's door is open."
+msgstr ""
+
+msgid "The printer's interlock is open."
+msgstr ""
+
+msgid "The printer's waste bin is almost full."
+msgstr ""
+
+msgid "The printer's waste bin is full."
+msgstr ""
+
+#, c-format
+msgid "The printer-uri \"%s\" contains invalid characters."
+msgstr "printer-uri“%sâ€åŒ…å«ç„¡æ•ˆçš„字元。"
+
+msgid "The printer-uri attribute is required"
+msgstr ""
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"."
+msgstr "printer-uri æ ¼å¼å¿…須為“ipp://HOSTNAME/classes/CLASSNAMEâ€ã€‚"
+
+msgid ""
+"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"."
+msgstr "printer-uri æ ¼å¼å¿…須為“ipp://HOSTNAME/printers/PRINTERNAMEâ€ã€‚"
+
+msgid ""
+"The subscription name may not contain spaces, slashes (/), question marks "
+"(?), or the pound sign (#)."
+msgstr "訂閱å稱ä¸èƒ½åŒ…å«ç©ºæ ¼ã€æ–œç·šï¼ˆ/)ã€å•è™Ÿï¼ˆ?)或井字號(#)。"
+
+msgid "There are too many subscriptions."
+msgstr "訂閱數é‡å¤ªå¤šã€‚"
+
+msgid "There is a paper jam."
+msgstr ""
+
+msgid "Thermal Transfer Media"
+msgstr "熱感傳é€åª’é«”"
+
+msgid "Title: "
+msgstr "標題:"
+
+msgid "Too many active jobs."
+msgstr "已啟用的作業太多。"
+
+#, c-format
+msgid "Too many job-sheets values (%d > 2)"
+msgstr ""
+
+#, c-format
+msgid "Too many printer-state-reasons values (%d > %d)"
+msgstr ""
+
+msgid "Transparency"
+msgstr "é€æ˜Žåº¦"
+
+msgid "Tray"
+msgstr "è£ç´™åŒ£"
+
+msgid "Tray 1"
+msgstr "è£ç´™åŒ£ 1"
+
+msgid "Tray 2"
+msgstr "è£ç´™åŒ£ 2"
+
+msgid "Tray 3"
+msgstr "è£ç´™åŒ£ 3"
+
+msgid "Tray 4"
+msgstr "è£ç´™åŒ£ 4"
+
+msgid "URI Too Long"
+msgstr "URI 太長"
+
+msgid "US Executive"
+msgstr "美å¼è¡Œæ”¿ç”¨ç´™ï¼ˆUS Executive)"
+
+msgid "US Fanfold"
+msgstr "美å¼æŠ˜ç–Šå¼å ±è¡¨ç´™ï¼ˆUS Fanfold)"
+
+msgid "US Ledger"
+msgstr "美å¼å¸³ç›®å ±è¡¨ç´™ï¼ˆUS Ledger)"
+
+msgid "US Legal"
+msgstr "美å¼æ³•å®šç´™ï¼ˆUS Legal)"
+
+msgid "US Legal (Oversize)"
+msgstr "美å¼æ³•å®šç´™ï¼è¶…大型(US Legalï¼Oversize)"
+
+msgid "US Letter"
+msgstr "美å¼ä¿¡ç´™ï¼ˆUS Letter)"
+
+msgid "US Letter (Oversize)"
+msgstr "美å¼ä¿¡ç´™ï¼è¶…大型(US Letterï¼Oversize)"
+
+msgid "US Letter (Small)"
+msgstr "美å¼ä¿¡ç´™ï¼å°åž‹ï¼ˆUS Letterï¼Small)"
+
+#, c-format
+msgid "USB Serial Port #%d"
+msgstr "USB åºåˆ—埠 #%d"
+
+msgid "Unable to access cupsd.conf file:"
+msgstr "ç„¡æ³•å­˜å– cupsd.conf 檔案:"
+
+msgid "Unable to add RSS subscription:"
+msgstr "無法加入 RSS 訂閱:"
+
+msgid "Unable to add class:"
+msgstr "無法加入類別:"
+
+#, c-format
+msgid "Unable to add job for destination \"%s\""
+msgstr ""
+
+msgid "Unable to add printer:"
+msgstr "無法新增å°è¡¨æ©Ÿï¼š"
+
+msgid "Unable to allocate memory for file types"
+msgstr ""
+
+msgid "Unable to cancel RSS subscription:"
+msgstr "無法å–消 RSS 訂閱:"
+
+msgid "Unable to change printer-is-shared attribute:"
+msgstr "無法更改 printer-is-shared 屬性:"
+
+msgid "Unable to change printer:"
+msgstr "無法更改å°è¡¨æ©Ÿï¼š"
+
+msgid "Unable to change server settings:"
+msgstr "無法更改伺æœå™¨è¨­å®šï¼š"
+
+msgid "Unable to connect to host."
+msgstr "無法連接主機。"
+
+#, c-format
+msgid "Unable to copy 64-bit CUPS printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy 64-bit Windows printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy CUPS printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to copy PPD file"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy PPD file - %s"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy Windows 9x printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to copy interface script - %s"
+msgstr ""
+
+msgid "Unable to create printer-uri"
+msgstr ""
+
+msgid "Unable to create temporary file:"
+msgstr "無法製作暫存檔:"
+
+msgid "Unable to delete class:"
+msgstr "無法刪除類別:"
+
+msgid "Unable to delete printer:"
+msgstr "無法刪除å°è¡¨æ©Ÿï¼š"
+
+msgid "Unable to do maintenance command:"
+msgstr "無法執行維護指令:"
+
+msgid "Unable to edit cupsd.conf files larger than 1MB"
+msgstr ""
+
+msgid "Unable to find destination for job"
+msgstr ""
+
+msgid "Unable to find printer\n"
+msgstr ""
+
+msgid "Unable to get class list:"
+msgstr "無法å–得類別列表:"
+
+msgid "Unable to get class status:"
+msgstr "無法å–得類別狀態:"
+
+msgid "Unable to get list of printer drivers:"
+msgstr "無法å–å¾—å°è¡¨æ©Ÿé©…動程å¼çš„列表:"
+
+msgid "Unable to get printer attributes:"
+msgstr "無法å–å¾—å°è¡¨æ©Ÿå±¬æ€§ï¼š"
+
+msgid "Unable to get printer list:"
+msgstr "無法å–å¾—å°è¡¨æ©Ÿåˆ—表:"
+
+msgid "Unable to get printer status:"
+msgstr "無法å–å¾—å°è¡¨æ©Ÿç‹€æ…‹ï¼š"
+
+#, c-format
+msgid "Unable to install Windows 2000 printer driver files (%d)"
+msgstr ""
+
+#, c-format
+msgid "Unable to install Windows 9x printer driver files (%d)"
+msgstr ""
+
+msgid "Unable to modify class:"
+msgstr "無法修改類別:"
+
+msgid "Unable to modify printer:"
+msgstr "無法修改å°è¡¨æ©Ÿï¼š"
+
+msgid "Unable to move job"
+msgstr "無法移動作業"
+
+msgid "Unable to move jobs"
+msgstr "無法移動作業"
+
+msgid "Unable to open PPD file"
+msgstr "無法打開 PPD 檔案"
+
+msgid "Unable to open PPD file:"
+msgstr "無法打開 PPD 檔案:"
+
+msgid "Unable to open cupsd.conf file:"
+msgstr "無法打開 cupsd.conf 檔案:"
+
+#, c-format
+msgid "Unable to open document %d in job %d"
+msgstr ""
+
+msgid "Unable to print test page:"
+msgstr "無法列å°æ¸¬è©¦é é¢ï¼š"
+
+#, c-format
+msgid "Unable to run \"%s\": %s\n"
+msgstr "無法執行“%sâ€ï¼š%s\n"
+
+msgid "Unable to send command to printer driver"
+msgstr ""
+
+#, c-format
+msgid "Unable to set Windows printer driver (%d)"
+msgstr ""
+
+msgid "Unable to set options:"
+msgstr "無法設定é¸é …:"
+
+msgid "Unable to set server default:"
+msgstr "無法設定伺æœå™¨é è¨­å€¼ï¼š"
+
+msgid "Unable to upload cupsd.conf file:"
+msgstr "無法上傳 cupsd.conf 檔案:"
+
+msgid "Unable to use legacy USB class driver\n"
+msgstr ""
+
+msgid "Unauthorized"
+msgstr "未授權"
+
+msgid "Units"
+msgstr "å–®ä½"
+
+msgid "Unknown"
+msgstr "未知"
+
+#, c-format
+msgid "Unknown printer-error-policy \"%s\"."
+msgstr "未知的 printer-error-policy“%sâ€ã€‚"
+
+#, c-format
+msgid "Unknown printer-op-policy \"%s\"."
+msgstr "未知的 printer-op-policy“%sâ€ã€‚"
+
+#, c-format
+msgid "Unsupported character set \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported compression attribute %s"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format \"%s\""
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s'"
+msgstr ""
+
+#, c-format
+msgid "Unsupported format '%s/%s'"
+msgstr ""
+
+msgid "Unsupported value type"
+msgstr "ä¸å—支æ´çš„值類型"
+
+msgid "Upgrade Required"
+msgstr "需è¦å‡ç´š"
+
+msgid ""
+"Usage:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+msgstr ""
+"使用:\n"
+"\n"
+" lpadmin [-h server] -d destination\n"
+" lpadmin [-h server] -x destination\n"
+" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n"
+" [-r remove-class] [-v device] [-D description]\n"
+" [-P ppd-file] [-o name=value]\n"
+" [-u allow:user,user] [-u deny:user,user]\n"
+"\n"
+
+#, c-format
+msgid "Usage: %s job user title copies options [filename]\n"
+msgstr "使用:%s 作業使用者標題拷è²é¸é … [檔å]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options [file]\n"
+msgstr "使用:%s job-id 使用者標題拷è²é¸é … [檔案]\n"
+
+#, c-format
+msgid "Usage: %s job-id user title copies options file\n"
+msgstr "使用:%s job-id 使用者標題拷è²é¸é …檔案\n"
+
+msgid ""
+"Usage: convert [ options ]\n"
+"\n"
+"Options:\n"
+"\n"
+" -e Use every filter from the PPD file\n"
+" -f filename Set file to be converted (otherwise stdin)\n"
+" -o filename Set file to be generated (otherwise stdout)\n"
+" -i mime/type Set input MIME type (otherwise auto-typed)\n"
+" -j mime/type Set output MIME type (otherwise application/pdf)\n"
+" -P filename.ppd Set PPD file\n"
+" -a 'name=value ...' Set option(s)\n"
+" -U username Set username for job\n"
+" -J title Set title\n"
+" -c copies Set number of copies\n"
+" -u Remove the PPD file when finished\n"
+" -D Remove the input file when finished\n"
+msgstr ""
+
+msgid ""
+"Usage: cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"Options:\n"
+" -E Encrypt the connection to the server\n"
+" -H samba-server Use the named SAMBA server\n"
+" -U samba-user Authenticate using the named SAMBA user\n"
+" -a Export all printers\n"
+" -h cups-server Use the named CUPS server\n"
+" -v Be verbose (show commands)\n"
+msgstr ""
+"使用:cupsaddsmb [options] printer1 ... printerN\n"
+" cupsaddsmb [options] -a\n"
+"\n"
+"é¸é …:\n"
+" -E 加密與伺æœå™¨çš„連線\n"
+" -H samba-server 使用已命åçš„ SAMBA 伺æœå™¨\n"
+" -U samba-user 使用已命åçš„ SAMBA 使用者進行èªè­‰\n"
+" -a 輸出所有å°è¡¨æ©Ÿ\n"
+" -h cups-server 使用已命åçš„ CUPS 伺æœå™¨\n"
+" -v 列出明細(顯示指令)\n"
+
+msgid ""
+"Usage: cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"Options:\n"
+"\n"
+" -E Enable encryption\n"
+" -U username Specify username\n"
+" -h server[:port] Specify server address\n"
+"\n"
+" --[no-]debug-logging Turn debug logging on/off\n"
+" --[no-]remote-admin Turn remote administration on/off\n"
+" --[no-]remote-any Allow/prevent access from the Internet\n"
+" --[no-]remote-printers Show/hide remote printers\n"
+" --[no-]share-printers Turn printer sharing on/off\n"
+" --[no-]user-cancel-any Allow/prevent users to cancel any job\n"
+msgstr ""
+"使用:cupsctl [options] [param=value ... paramN=valueN]\n"
+"\n"
+"é¸é …:\n"
+"\n"
+" -E 啟用加密\n"
+" -U username 指定使用者å稱\n"
+" -h server[:port] 指定伺æœå™¨ä½å€\n"
+"\n"
+" --[no-]debug-logging 開啟/關閉除錯記錄\n"
+" --[no-]remote-admin é–‹å•Ÿ/關閉é ç«¯ç®¡ç†\n"
+" --[no-]remote-any å…許∕ä¸å…許從 Internet å­˜å–\n"
+" --[no-]remote-printers 顯示∕隱è—é ç«¯å°è¡¨æ©Ÿ\n"
+" --[no-]share-printers é–‹å•Ÿ/關閉å°è¡¨æ©Ÿå…±äº«\n"
+" --[no-]user-cancel-any å…許∕ä¸å…許使用者å–消任何作業\n"
+
+msgid ""
+"Usage: cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file Load alternate configuration file\n"
+"-f Run in the foreground\n"
+"-F Run in the foreground but detach\n"
+"-h Show this usage message\n"
+"-l Run cupsd from launchd(8)\n"
+msgstr ""
+"使用:cupsd [-c config-file] [-f] [-F] [-h] [-l]\n"
+"\n"
+"-c config-file 載入替用é…置檔案\n"
+"-f 在å‰æ™¯åŸ·è¡Œ\n"
+"-F 在å‰æ™¯åŸ·è¡Œä½†èˆ‡ä¹‹åˆ†é›¢\n"
+"-h 顯示本用法訊æ¯\n"
+"-l 從 launchd(8) 執行 cupsd\n"
+
+msgid ""
+"Usage: cupsfilter -m mime/type [ options ] filename\n"
+"\n"
+"Options:\n"
+"\n"
+" -c cupsd.conf Set cupsd.conf file to use\n"
+" -e Use every filter from the PPD file\n"
+" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
+" -n copies Set number of copies\n"
+" -o name=value Set option(s)\n"
+" -p filename.ppd Set PPD file\n"
+" -t title Set title\n"
+msgstr ""
+
+msgid ""
+"Usage: cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -h Show program usage\n"
+"\n"
+" Note: this program only validates the DSC comments, not the PostScript "
+"itself.\n"
+msgstr ""
+"使用:cupstestdsc [options] filename.ps [... filename.ps]\n"
+" cupstestdsc [options] -\n"
+"\n"
+"é¸é …:\n"
+"\n"
+" -h 顯示程å¼ç”¨æ³•\n"
+"\n"
+" NOTICE: 此程å¼åƒ…é©—è­‰ DSC 註解,而ä¸æ˜¯ PostScript 本身。\n"
+
+msgid ""
+"Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+" program | cupstestppd [options] -\n"
+"\n"
+"Options:\n"
+"\n"
+" -I {filename,filters,none,profiles}\n"
+" Ignore specific warnings\n"
+" -R root-directory Set alternate root\n"
+" -W {all,none,constraints,defaults,duplex,filters,profiles,sizes,"
+"translations}\n"
+" Issue warnings instead of errors\n"
+" -q Run silently\n"
+" -r Use 'relaxed' open mode\n"
+" -v Be slightly verbose\n"
+" -vv Be very verbose\n"
+msgstr ""
+
+msgid ""
+"Usage: ipptest [options] URI filename.test [ ... filenameN.test ]\n"
+"\n"
+"Options:\n"
+"\n"
+"-E Test with encryption.\n"
+"-V version Set default IPP version.\n"
+"-X Produce XML instead of plain text.\n"
+"-c Send requests using chunking (default)\n"
+"-d name=value Define variable.\n"
+"-f filename Set default test file.\n"
+"-i seconds Repeat the last test file with the given interval.\n"
+"-l Send requests using content-length\n"
+"-v Show all attributes sent and received.\n"
+msgstr ""
+
+msgid "Usage: lpmove job/src dest\n"
+msgstr "使用:lpmove job/src dest\n"
+
+msgid ""
+"Usage: lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+msgstr ""
+"使用:lpoptions [-h server] [-E] -d printer\n"
+" lpoptions [-h server] [-E] [-p printer] -l\n"
+" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n"
+" lpoptions [-h server] [-E] -x printer\n"
+
+msgid "Usage: lppasswd [-g groupname]\n"
+msgstr "使用:lppasswd [-g groupname]\n"
+
+msgid ""
+"Usage: lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+msgstr ""
+"使用:lppasswd [-g groupname] [username]\n"
+" lppasswd [-g groupname] -a [username]\n"
+" lppasswd [-g groupname] -x [username]\n"
+
+msgid ""
+"Usage: lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+msgstr ""
+"使用:lpq [-P dest] [-U username] [-h hostname[:port]] [-l] [+interval]\n"
+
+msgid ""
+"Usage: ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -c catalog.po Load the specified message catalog.\n"
+" -d output-dir Specify the output directory.\n"
+" -l lang[,lang,...] Specify the output language(s) (locale).\n"
+" -m Use the ModelName value as the filename.\n"
+" -t Test PPDs instead of generating them.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+" -z Compress PPD files using GNU zip.\n"
+" --cr End lines with CR (Mac OS 9).\n"
+" --crlf End lines with CR + LF (Windows).\n"
+" --lf End lines with LF (UNIX/Linux/Mac OS X).\n"
+msgstr ""
+"使用:ppdc [options] filename.drv [ ... filenameN.drv ]\n"
+"é¸é …:\n"
+" -D name=value 為已命å的變數設定值。\n"
+" -I include-dir 將包å«çš„目錄加入æœå°‹è·¯å¾‘。\n"
+" -c catalog.po 載入指定的訊æ¯ç›®éŒ„。\n"
+" -d output-dir 指定輸出目錄。\n"
+" -l lang[,lang,...] 指定輸出語言(å€åŸŸç’°å¢ƒè¨­å®šï¼‰ã€‚\n"
+" -m 使用 ModelName 值作為檔å。\n"
+" -t 測試而ä¸æ˜¯ç”¢ç”Ÿ PPD。\n"
+" -v 列出明細(v 越多就越詳盡)。\n"
+" -z 使用 GNU zip 壓縮 PPD 檔案。\n"
+" --cr 以 CR 作為行çµå°¾ï¼ˆMac OS 9)。\n"
+" --crlf 以 CR + LF 作為行çµå°¾ï¼ˆWindows)。\n"
+" --lf 以 LF 作為行çµå°¾ï¼ˆUNIX/Linux/Mac OS X)。\n"
+
+msgid ""
+"Usage: ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value Set named variable to value.\n"
+"Options:\n"
+" -I include-dir Add include directory to search path.\n"
+msgstr ""
+"使用:ppdhtml [options] filename.drv >filename.html\n"
+" -D name=value 為已命å的變數設定值。\n"
+"é¸é …:\n"
+" -I include-dir 將包å«çš„目錄加入æœå°‹è·¯å¾‘。\n"
+
+msgid ""
+"Usage: ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+msgstr ""
+"使用:ppdi [options] filename.ppd [ ... filenameN.ppd ]\n"
+"é¸é …:\n"
+" -I include-dir\n"
+" -o filename.drv\n"
+
+msgid ""
+"Usage: ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"Options:\n"
+" -o filename.ppd[.gz]\n"
+msgstr ""
+"使用:ppdmerge [options] filename.ppd [ ... filenameN.ppd ]\n"
+"é¸é …:\n"
+" -o filename.ppd[.gz]\n"
+
+msgid ""
+"Usage: ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"Options:\n"
+" -D name=value Set named variable to value.\n"
+" -I include-dir Add include directory to search path.\n"
+" -v Be verbose (more v's for more verbosity).\n"
+msgstr ""
+"使用:ppdpo [options] -o filename.po filename.drv [ ... filenameN.drv ]\n"
+"é¸é …:\n"
+" -D name=value 為已命å的變數設定值。\n"
+" -I include-dir 將包å«çš„目錄加入æœå°‹è·¯å¾‘。\n"
+" -v 列出明細(v 越多就越詳盡)。\n"
+
+msgid "Usage: snmp [host-or-ip-address]\n"
+msgstr "使用:snmp [host-or-ip-address]\n"
+
+msgid "Value uses indefinite length"
+msgstr "值使用的長度ä¸ç¢ºå®š"
+
+msgid "VarBind uses indefinite length"
+msgstr "VarBind 使用的長度ä¸ç¢ºå®š"
+
+msgid "Version uses indefinite length"
+msgstr "版本使用的長度ä¸ç¢ºå®š"
+
+#, c-format
+msgid "WARNING: Adding only the first %d printers found"
+msgstr "WARNING: åƒ…åŠ å…¥æ‰¾åˆ°çš„å‰ %d 個å°è¡¨æ©Ÿ"
+
+#, c-format
+msgid "WARNING: Boolean expected for waiteof option \"%s\"\n"
+msgstr "WARNING: waiteof é¸é …“%sâ€é æœŸç‚ºå¸ƒæž—é¡žåž‹\n"
+
+#, c-format
+msgid "WARNING: Network host '%s' is busy; will retry in %d seconds...\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature\n"
+msgstr ""
+
+msgid "WARNING: Printer not responding\n"
+msgstr "WARNING: å°è¡¨æ©Ÿæœªå›žæ‡‰ï¼"
+
+msgid "WARNING: Printer sent unexpected EOF\n"
+msgstr "WARNING: å°è¡¨æ©Ÿå‚³é€äº†éžé æœŸçš„ EOF\n"
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with command status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with control status byte after %d "
+"seconds\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"WARNING: Remote host did not respond with data status byte after %d seconds\n"
+msgstr ""
+
+msgid ""
+"WARNING: This document does not conform to the Adobe Document Structuring "
+"Conventions and may not print correctly\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unable to open \"%s:%s\": %s\n"
+msgstr "WARNING: 無法打開“%s:%sâ€ï¼š%s\n"
+
+msgid "WARNING: Unable to send PAP status request"
+msgstr "WARNING: ç„¡æ³•å‚³é€ PAP 狀態請求ï¼"
+
+#, c-format
+msgid "WARNING: Unexpected PAP packet of type %d\n"
+msgstr "WARNING: é¡žåž‹ %d çš„éžé æœŸ PAP å°åŒ…\n"
+
+#, c-format
+msgid "WARNING: Unknown PAP packet of type %d\n"
+msgstr "WARNING: é¡žåž‹ %d 的未知 PAP å°åŒ…\n"
+
+#, c-format
+msgid "WARNING: Unknown choice \"%s\" for option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: Unsupported baud rate %s\n"
+msgstr ""
+
+#, c-format
+msgid "WARNING: number expected for status option \"%s\"\n"
+msgstr "WARNING: 狀態é¸é …“%sâ€é æœŸç‚ºæ•¸å­—\n"
+
+msgid "Warning, no Windows 2000 printer drivers are installed"
+msgstr ""
+
+msgid "Yes"
+msgstr "是"
+
+#, c-format
+msgid ""
+"You must access this page using the URL <A HREF=\"https://%s:%d%s\">https://%"
+"s:%d%s</A>."
+msgstr ""
+"您必須使用 URL <A HREF=\"https://%s:%d%s\">https://%s:%d%s</A> å­˜å–æ­¤é é¢ã€‚"
+
+msgid "You4 Envelope"
+msgstr "You4 ä¿¡å°"
+
+msgid "ZPL Label Printer"
+msgstr "ZPL 標籤å°è¡¨æ©Ÿ"
+
+msgid "Zebra"
+msgstr "Zebra"
+
+msgid "aborted"
+msgstr "已中止"
+
+msgid "canceled"
+msgstr "å·²å–消"
+
+msgid "completed"
+msgstr "已完æˆ"
+
+msgid "convert: Use the -f option to specify a file to convert.\n"
+msgstr "convert:使用 -f é¸é …來指定è¦è½‰æ›çš„檔案。\n"
+
+msgid "cups-deviced failed to execute."
+msgstr "無法執行 cups-deviced。"
+
+msgid "cups-driverd failed to execute."
+msgstr "無法執行 cups-driverd。"
+
+#, c-format
+msgid "cupsaddsmb: No PPD file for printer \"%s\" - %s\n"
+msgstr "cupsaddsmb:沒有é©ç”¨æ–¼å°è¡¨æ©Ÿâ€œ%sâ€çš„ PPD 檔案 - %s\n"
+
+#, c-format
+msgid "cupsctl: Unable to connect to server: %s\n"
+msgstr "cupsctl:無法連接伺æœå™¨ï¼š%s\n"
+
+#, c-format
+msgid "cupsctl: Unknown option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "cupsctl: Unknown option \"-%c\"\n"
+msgstr ""
+
+msgid "cupsd: Expected config filename after \"-c\" option\n"
+msgstr ""
+
+msgid "cupsd: Unable to get current directory\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown argument \"%s\" - aborting\n"
+msgstr ""
+
+#, c-format
+msgid "cupsd: Unknown option \"%c\" - aborting\n"
+msgstr ""
+
+msgid "cupsd: launchd(8) support not compiled in, running in normal mode.\n"
+msgstr "cupsd:未編譯入 launchd(8) 支æ´ï¼Œåœ¨æ­£å¸¸æ¨¡å¼ä¸‹åŸ·è¡Œã€‚\n"
+
+#, c-format
+msgid "cupsfilter: Invalid document number %d\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Invalid job ID %d\n"
+msgstr ""
+
+msgid "cupsfilter: Only one filename can be specified\n"
+msgstr ""
+
+#, c-format
+msgid "cupsfilter: Unable to get job file - %s\n"
+msgstr "cupsfilter:無法å–得作業檔案 - %s\n"
+
+msgid "cupstestppd: The -q option is incompatible with the -v option.\n"
+msgstr "cupstestppd:-q é¸é …與 -v é¸é …ä¸ç›¸å®¹ã€‚\n"
+
+msgid "cupstestppd: The -v option is incompatible with the -q option.\n"
+msgstr "cupstestppd:-v é¸é …與 -q é¸é …ä¸ç›¸å®¹ã€‚\n"
+
+#, c-format
+msgid "device for %s/%s: %s\n"
+msgstr "%s/%s 的設備:%s\n"
+
+#, c-format
+msgid "device for %s: %s\n"
+msgstr "%s 的設備:%s\n"
+
+msgid "error-index uses indefinite length"
+msgstr "error-index 使用的長度ä¸ç¢ºå®š"
+
+msgid "error-status uses indefinite length"
+msgstr "error-status 使用的長度ä¸ç¢ºå®š"
+
+msgid "held"
+msgstr "æš«åœ"
+
+msgid "help\t\tget help on commands\n"
+msgstr "輔助說明\t\tå–得指令的輔助說明\n"
+
+msgid "idle"
+msgstr "é–’ç½®"
+
+msgid "ipptest: \"-i\" is incompatible with \"-x\".\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad URI - %s.\n"
+msgstr ""
+
+#, c-format
+msgid "ipptest: Bad version %s for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: May only specify a single URI.\n"
+msgstr ""
+
+msgid "ipptest: Missing filename for \"-f\".\n"
+msgstr ""
+
+msgid "ipptest: Missing name=value for \"-d\".\n"
+msgstr ""
+
+msgid "ipptest: Missing seconds for \"-i\".\n"
+msgstr ""
+
+msgid "ipptest: Missing version for \"-V\".\n"
+msgstr ""
+
+msgid "ipptest: Only http, https, and ipp URIs are supported."
+msgstr ""
+
+msgid "ipptest: URI required before test file."
+msgstr ""
+
+#, c-format
+msgid "ipptest: Unknown option \"-%c\".\n"
+msgstr ""
+
+msgid "job-printer-uri attribute missing"
+msgstr ""
+
+msgid "lpadmin: Class name can only contain printable characters\n"
+msgstr ""
+
+msgid "lpadmin: Expected PPD after '-P' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected allow/deny:userlist after '-u' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class after '-r' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected class name after '-c' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected description after '-D' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected device URI after '-v' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected file type(s) after '-I' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected hostname after '-h' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected interface after '-i' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected location after '-L' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected model after '-m' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected name=value after '-o' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer after '-p' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer name after '-d' option\n"
+msgstr ""
+
+msgid "lpadmin: Expected printer or class after '-x' option\n"
+msgstr ""
+
+msgid "lpadmin: No member names were seen\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Printer %s is already a member of class %s.\n"
+msgstr "lpadmin:å°è¡¨æ©Ÿ %s 已經是類別 %s çš„æˆå“¡ã€‚\n"
+
+#, c-format
+msgid "lpadmin: Printer %s is not a member of class %s.\n"
+msgstr "lpadmin:å°è¡¨æ©Ÿ %s ä¸æ˜¯é¡žåˆ¥ %s çš„æˆå“¡ã€‚\n"
+
+msgid "lpadmin: Printer name can only contain printable characters\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to add a printer to the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unable to connect to server: %s\n"
+msgstr "lpadmin:無法連接伺æœå™¨ï¼š%s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n"
+msgstr "lpadmin:無法打開 PPD 檔案“%sâ€- %s\n"
+
+#, c-format
+msgid "lpadmin: Unable to open file \"%s\": %s\n"
+msgstr "lpadmin:無法打開檔案“%sâ€ï¼š%s\n"
+
+msgid ""
+"lpadmin: Unable to remove a printer from the class:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the device URI:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script or PPD file:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the interface script:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer description:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer location:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+msgid ""
+"lpadmin: Unable to set the printer options:\n"
+" You must specify a printer name first\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown allow/deny option \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpadmin: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpadmin: Warning - content type list ignored\n"
+msgstr ""
+
+msgid "lpc> "
+msgstr "lpc> "
+
+msgid "lpinfo: Expected 1284 device ID string after --device-id\n"
+msgstr ""
+
+msgid "lpinfo: Expected language after --language\n"
+msgstr ""
+
+msgid "lpinfo: Expected make and model after --make-and-model\n"
+msgstr ""
+
+msgid "lpinfo: Expected product string after --product\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --exclude-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected scheme list after --include-schemes\n"
+msgstr ""
+
+msgid "lpinfo: Expected timeout after --timeout\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%c'\n"
+msgstr ""
+
+#, c-format
+msgid "lpinfo: Unknown option '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unable to connect to server: %s\n"
+msgstr "lpmove:無法連接伺æœå™¨ï¼š%s\n"
+
+#, c-format
+msgid "lpmove: Unknown argument '%s'\n"
+msgstr ""
+
+#, c-format
+msgid "lpmove: Unknown option '%c'\n"
+msgstr ""
+
+msgid "lpoptions: No printers\n"
+msgstr ""
+
+#, c-format
+msgid "lpoptions: Unable to add printer or instance: %s\n"
+msgstr "lpoptions:無法新增å°è¡¨æ©Ÿæˆ–實例:%s\n"
+
+#, c-format
+msgid "lpoptions: Unable to get PPD file for %s: %s\n"
+msgstr "lpoptions:無法å–å¾— %s çš„ PPD 檔案:%s\n"
+
+#, c-format
+msgid "lpoptions: Unable to open PPD file for %s\n"
+msgstr ""
+
+msgid "lpoptions: Unknown printer or class\n"
+msgstr ""
+
+msgid "lppasswd: Only root can add or delete passwords\n"
+msgstr ""
+
+msgid "lppasswd: Password file busy\n"
+msgstr ""
+
+msgid "lppasswd: Password file not updated\n"
+msgstr ""
+
+msgid "lppasswd: Sorry, password doesn't match\n"
+msgstr ""
+
+msgid ""
+"lppasswd: Sorry, password rejected.\n"
+"Your password must be at least 6 characters long, cannot contain\n"
+"your username, and must contain at least one letter and number.\n"
+msgstr ""
+"lppasswd:抱歉,密碼é­åˆ°æ‹’絕。\n"
+"您的密碼長度至少必須為 6 個字元,ä¸èƒ½åŒ…å«\n"
+"使用者å稱,而且至少必須包å«ä¸€å€‹å­—æ¯å’Œæ•¸å­—。\n"
+
+msgid "lppasswd: Sorry, passwords don't match\n"
+msgstr ""
+
+#, c-format
+msgid "lppasswd: Unable to copy password string: %s\n"
+msgstr "lppasswd:無法拷è²å¯†ç¢¼å­—串:%s\n"
+
+#, c-format
+msgid "lppasswd: Unable to open password file: %s\n"
+msgstr "lppasswd:無法打開密碼檔案:%s\n"
+
+#, c-format
+msgid "lppasswd: Unable to write to password file: %s\n"
+msgstr "lppasswd:無法寫入密碼檔案:%s\n"
+
+#, c-format
+msgid "lppasswd: failed to backup old password file: %s\n"
+msgstr "lppasswd:無法備份舊的密碼檔案:%s\n"
+
+#, c-format
+msgid "lppasswd: failed to rename password file: %s\n"
+msgstr "lppasswd:無法é‡æ–°å‘½å密碼檔案:%s\n"
+
+#, c-format
+msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n"
+msgstr "lppasswd:使用者“%sâ€å’Œç¾¤çµ„“%sâ€ä¸å­˜åœ¨ã€‚\n"
+
+#, c-format
+msgid ""
+"lpstat: error - %s environment variable names non-existent destination \"%s"
+"\"\n"
+msgstr ""
+
+#, c-format
+msgid "members of class %s:\n"
+msgstr "類別 %s çš„æˆå“¡ï¼š\n"
+
+msgid "no entries\n"
+msgstr "沒有項目\n"
+
+msgid "no system default destination\n"
+msgstr "沒有系統é è¨­ç›®çš„地\n"
+
+msgid "notify-events not specified"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" is already used"
+msgstr ""
+
+#, c-format
+msgid "notify-recipient-uri URI \"%s\" uses unknown scheme"
+msgstr ""
+
+#, c-format
+msgid "notify-subscription-id %d no good"
+msgstr ""
+
+msgid "pending"
+msgstr "等待中"
+
+#, c-format
+msgid "ppdc: Adding include directory \"%s\"...\n"
+msgstr "ppdc:正在加入包å«çš„目錄“%sâ€â‹¯\n"
+
+#, c-format
+msgid "ppdc: Adding/updating UI text from %s...\n"
+msgstr "ppdc:正在從 %s 加入/更新 UI 文字⋯\n"
+
+#, c-format
+msgid "ppdc: Bad boolean value (%s) on line %d of %s.\n"
+msgstr "ppdc:錯誤的布林值(%1$s),在 %3$s 的第 %2$d 行。\n"
+
+#, c-format
+msgid "ppdc: Bad resolution name \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad status keyword %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Bad variable substitution ($%c) on line %d of %s.\n"
+msgstr "ppdc:錯誤的變數替代($%1$c),在 %3$s 的第 %2$d 行。\n"
+
+#, c-format
+msgid "ppdc: Choice found on line %d of %s with no Option\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Duplicate #po for locale %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a filter definition on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected a program name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected boolean value on line %d of %s.\n"
+msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰å¸ƒæž—值。\n"
+
+#, c-format
+msgid "ppdc: Expected charset after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected choice code on line %d of %s.\n"
+msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰é¸é …代碼。\n"
+
+#, c-format
+msgid "ppdc: Expected choice name/text on line %d of %s.\n"
+msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰é¸é …å稱/文字。\n"
+
+#, c-format
+msgid "ppdc: Expected color order for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected colorspace for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected compression for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected constraints string for UIConstraints on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected driver type keyword following DriverType on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected duplex type after Duplex on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected encoding after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected filename after #po %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected group name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected include filename on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected integer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected locale after #po on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after FileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after Manufacturer on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after MediaSize on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after ModelName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name after PCFileName on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Installable on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected name/text combination for ColorModel on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option name/text on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option section on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected option type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected override field after Resolution on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected real number on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following ColorProfile on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Expected resolution/mediatype following SimpleColorProfile on line %d "
+"of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected selector after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected status after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Copyright on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected string after Version on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected two option names on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected value after %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Expected version after Font on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid #include/#po filename \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid cost for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty MIME type for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid empty program name for filter on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option section \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Invalid option type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Loading driver information file \"%s\"...\n"
+msgstr "ppdc:正在載入驅動程å¼è³‡è¨Šæª”案“%sâ€â‹¯\n"
+
+#, c-format
+msgid "ppdc: Loading messages for locale \"%s\"...\n"
+msgstr "ppdc:正在為環境變數“%sâ€è¼‰å…¥è¨Šæ¯â‹¯\n"
+
+#, c-format
+msgid "ppdc: Loading messages from \"%s\"...\n"
+msgstr "ppdc:正在從“%sâ€è¼‰å…¥è¨Šæ¯â‹¯\n"
+
+#, c-format
+msgid "ppdc: Missing #endif at end of \"%s\"\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Missing #if on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: No message catalog provided for locale %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s defined in two different groups on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option %s redefined with a different type on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Option constraint must *name on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Too many nested #if's on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to create PPD file \"%s\" - %s.\n"
+msgstr "ppdc:無法製作 PPD 檔案“%sâ€- %s。\n"
+
+#, c-format
+msgid "ppdc: Unable to create output directory %s: %s\n"
+msgstr "ppdc:無法製作輸出目錄 %s:%s\n"
+
+#, c-format
+msgid "ppdc: Unable to create output pipes: %s\n"
+msgstr "ppdc:無法製作輸出路徑:%s\n"
+
+#, c-format
+msgid "ppdc: Unable to execute cupstestppd: %s\n"
+msgstr "ppdc:無法執行 cupstestppd:%s\n"
+
+#, c-format
+msgid "ppdc: Unable to find #po file %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find include file \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unable to find localization for \"%s\" - %s\n"
+msgstr "ppdc:找ä¸åˆ°æœ¬åœ°åŒ–的“%sâ€- %s\n"
+
+#, c-format
+msgid "ppdc: Unable to load localization file \"%s\" - %s\n"
+msgstr "ppdc:無法載入本地化檔案“%sâ€- %s\n"
+
+#, c-format
+msgid "ppdc: Undefined variable (%s) on line %d of %s.\n"
+msgstr "ppdc:未定義的變數(%1$s),在 %3$s 的第 %2$d 行上。\n"
+
+#, c-format
+msgid "ppdc: Unknown driver type %s on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown media size \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unknown token \"%s\" seen on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid ""
+"ppdc: Unknown trailing characters in real number \"%s\" on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Unterminated string starting with %c on line %d of %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Warning - overlapping filename \"%s\".\n"
+msgstr ""
+
+#, c-format
+msgid "ppdc: Writing %s...\n"
+msgstr "ppdc:正在寫入 %s⋯\n"
+
+#, c-format
+msgid "ppdc: Writing PPD files to directory \"%s\"...\n"
+msgstr "ppdc:正在將 PPD 檔案寫入目錄“%sâ€â‹¯\n"
+
+#, c-format
+msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s\n"
+msgstr ""
+
+#, c-format
+msgid "ppdmerge: Ignoring PPD file %s...\n"
+msgstr "ppdmerge:正在忽略 PPD 檔案 %s⋯\n"
+
+#, c-format
+msgid "ppdmerge: Unable to backup %s to %s- %s\n"
+msgstr "ppdmerge:無法將 %s 備份到 %s- %s\n"
+
+#, c-format
+msgid "printer %s disabled since %s -\n"
+msgstr "å°è¡¨æ©Ÿ %s å·²åœç”¨ï¼Œè‡ª %s 後 -\n"
+
+#, c-format
+msgid "printer %s is idle. enabled since %s\n"
+msgstr "å°è¡¨æ©Ÿ %s 處於閒置狀態,自 %s 後啟用\n"
+
+#, c-format
+msgid "printer %s now printing %s-%d. enabled since %s\n"
+msgstr "å°è¡¨æ©Ÿ %s æ­£åœ¨åˆ—å° %s-%d。自 %s 後啟用\n"
+
+#, c-format
+msgid "printer %s/%s disabled since %s -\n"
+msgstr "å°è¡¨æ©Ÿ %s/%s 自 %s 後åœç”¨ -\n"
+
+#, c-format
+msgid "printer %s/%s is idle. enabled since %s\n"
+msgstr "å°è¡¨æ©Ÿ %s/%s 處於閑置狀態。自 %s 後啟用\n"
+
+#, c-format
+msgid "printer %s/%s now printing %s-%d. enabled since %s\n"
+msgstr "å°è¡¨æ©Ÿ %s/%s æ­£åœ¨åˆ—å° %s-%d。自 %s 後啟用\n"
+
+msgid "processing"
+msgstr "正在處ç†"
+
+#, c-format
+msgid "request id is %s-%d (%d file(s))\n"
+msgstr "請求 ID 為 %s-%d(%d 個檔案)\n"
+
+msgid "request-id uses indefinite length"
+msgstr "request-id 使用的長度ä¸ç¢ºå®š"
+
+msgid "scheduler is not running\n"
+msgstr "排程器並沒有執行\n"
+
+msgid "scheduler is running\n"
+msgstr "排程器正在執行中\n"
+
+#, c-format
+msgid "stat of %s failed: %s"
+msgstr "啟動 %s 失敗:%s"
+
+msgid "status\t\tshow status of daemon and queue\n"
+msgstr "狀態\t\t顯示æœå‹™ç¨‹å¼å’Œä½‡åˆ—的狀態\n"
+
+msgid "stopped"
+msgstr "å·²åœæ­¢"
+
+#, c-format
+msgid "system default destination: %s\n"
+msgstr "系統é è¨­ç›®çš„地:%s\n"
+
+#, c-format
+msgid "system default destination: %s/%s\n"
+msgstr "系統é è¨­ç›®çš„地:%s/%s\n"
+
+msgid "unknown"
+msgstr "未知"
+
+msgid "untitled"
+msgstr "未命å"
+
+msgid "variable-bindings uses indefinite length"
+msgstr "variable-bindings 使用的長度ä¸ç¢ºå®š"
+
+#~ msgid " WARN %s has no corresponding options!\n"
+#~ msgstr " 警告 %s 沒有å°æ‡‰çš„é¸é …ï¼\n"
+
+#~ msgid " WARN Default choices conflicting!\n"
+#~ msgstr " 警告 é è¨­çš„é¸é …è¡çªï¼\n"
+
+#~ msgid ""
+#~ " WARN Duplex option keyword %s may not work as expected and "
+#~ "should be named Duplex!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " 警告 兩用è£ç´™åŒ£é¸é …çš„é—œéµå­— %s ä¸èƒ½å¦‚é æœŸé‹ä½œï¼Œè€Œæ‡‰è©²å‘½å為 "
+#~ "Duplexï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 122 é ï¼Œç« ç¯€ 5.17\n"
+
+#~ msgid ""
+#~ " WARN File contains a mix of CR, LF, and CR LF line endings!\n"
+#~ msgstr " 警告 æª”æ¡ˆåŒ…å« CRã€LF å’Œ CR LF çš„è¡Œçµå°¾ï¼\n"
+
+#~ msgid " WARN Line %d only contains whitespace!\n"
+#~ msgstr " 警告 第 %d è¡ŒåªåŒ…å«ç©ºç™½ï¼\n"
+
+#~ msgid " WARN Missing APDialogExtension file \"%s\"\n"
+#~ msgstr " 警告 éºå¤± APDialogExtension 檔案“%sâ€\n"
+
+#~ msgid " WARN Missing APPrinterIconPath file \"%s\"\n"
+#~ msgstr " 警告 éºå¤± APPrinterIconPath 檔案“%sâ€\n"
+
+#~ msgid ""
+#~ " WARN Non-Windows PPD files should use lines ending with only "
+#~ "LF, not CR LF!\n"
+#~ msgstr ""
+#~ " 警告 éž Windows PPD 檔案應該使用僅å«æœ‰ LF çš„è¡Œçµå°¾ï¼Œè€Œä¸æ˜¯ CR "
+#~ "LFï¼\n"
+
+#~ msgid ""
+#~ " WARN Obsolete PPD version %.1f!\n"
+#~ " REF: Page 42, section 5.2.\n"
+#~ msgstr ""
+#~ " 警告 PPD 版本 %.1f å·²éŽæ™‚ï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 42 é ï¼Œç« ç¯€ 5.2。\n"
+
+#~ msgid " %s %s %s does not exist!\n"
+#~ msgstr " %s %s %s ä¸å­˜åœ¨ï¼\n"
+
+#~ msgid ""
+#~ " %s Bad %s choice %s!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s %s é¸é … %s 錯誤ï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 122 é ï¼Œç« ç¯€ 5.17\n"
+
+#~ msgid " %s Bad UTF-8 \"%s\" translation string for option %s!\n"
+#~ msgstr " %s 下列項目的 UTF-8“%sâ€è½‰æ›å­—串ERROR: é¸é … %sï¼\n"
+
+#~ msgid ""
+#~ " %s Bad UTF-8 \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr " %s 下列項目的 UTF-8“%sâ€è½‰æ›å­—串ERROR: é¸é … %s,é¸é … %sï¼\n"
+
+#~ msgid " %s Bad cupsFilter value \"%s\"!\n"
+#~ msgstr " %s cupsFilter 值“%sâ€éŒ¯èª¤ï¼\n"
+
+#~ msgid " %s Bad cupsICCProfile %s!\n"
+#~ msgstr " %s cupsICCProfile %s 錯誤ï¼\n"
+
+#~ msgid " %s Bad cupsPreFilter value \"%s\"!\n"
+#~ msgstr " %s cupsPreFilter 值“%sâ€éŒ¯èª¤ï¼\n"
+
+#~ msgid " %s Bad cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s cupsUIConstraints %s:“%sâ€éŒ¯èª¤ï¼\n"
+
+#~ msgid " %s Bad language \"%s\"!\n"
+#~ msgstr " %s 語言“%sâ€éŒ¯èª¤ï¼\n"
+
+#~ msgid " %s Empty cupsUIConstraints %s!\n"
+#~ msgstr " %s cupsUIConstraints %s 為空白ï¼\n"
+
+#~ msgid " %s Missing \"%s\" translation string for option %s!\n"
+#~ msgstr " %s 下列項目的“%sâ€è½‰æ›å­—串éºå¤±ï¼šé¸é … %sï¼\n"
+
+#~ msgid ""
+#~ " %s Missing \"%s\" translation string for option %s, choice %s!\n"
+#~ msgstr " %s 下列項目的“%sâ€è½‰æ›å­—串éºå¤±ï¼šé¸é … %s,é¸é … %sï¼\n"
+
+#~ msgid ""
+#~ " %s Missing choice *%s %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr ""
+#~ " %s 下列項目中éºå¤±é¸é … *%s %s:UIConstraints“*%s %s *%s %sâ€ï¼\n"
+
+#~ msgid " %s Missing choice *%s %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s 下列項目中éºå¤±é¸é … *%s %s:cupsUIConstraints %s:“%sâ€ï¼\n"
+
+#~ msgid " %s Missing cupsICCProfile file \"%s\"!\n"
+#~ msgstr " %s éºå¤± cupsICCProfile 檔案“%sâ€ï¼\n"
+
+#~ msgid " %s Missing cupsUIResolver %s!\n"
+#~ msgstr " %s éºå¤± cupsUIResolver %sï¼\n"
+
+#~ msgid " %s Missing option %s in UIConstraints \"*%s %s *%s %s\"!\n"
+#~ msgstr " %s 下列項目中éºå¤±é¸é … %s:UIConstraints“*%s %s *%s %sâ€ï¼\n"
+
+#~ msgid " %s Missing option %s in cupsUIConstraints %s: \"%s\"!\n"
+#~ msgstr " %s 下列項目中éºå¤±é¸é … %s:cupsUIConstraints %s:“%sâ€ï¼\n"
+
+#~ msgid " %s No base translation \"%s\" is included in file!\n"
+#~ msgstr " %s 檔案中ä¸åŒ…括基礎轉æ›â€œ%sâ€ï¼\n"
+
+#~ msgid ""
+#~ " %s REQUIRED %s does not define choice None!\n"
+#~ " REF: Page 122, section 5.17\n"
+#~ msgstr ""
+#~ " %s REQUIRED %s 未定義é¸é … Noneï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 122 é ï¼Œç« ç¯€ 5.17\n"
+
+#~ msgid " %s cupsICCProfile %s hash value collides with %s!\n"
+#~ msgstr " %s cupsICCProfile %s 雜湊值與 %s è¡çªï¼\n"
+
+#~ msgid " %s cupsUIResolver %s causes a loop!\n"
+#~ msgstr " %s cupsUIResolver %s 造æˆè¿´åœˆï¼\n"
+
+#~ msgid " **FAIL** %s choice names %s and %s differ only by case!\n"
+#~ msgstr " **失敗** %s é¸é …å稱 %s å’Œ %s 僅在æŸäº›æƒ…æ³ä¸‹ä¸åŒï¼\n"
+
+#~ msgid ""
+#~ " **FAIL** %s must be 1284DeviceID!\n"
+#~ " REF: Page 72, section 5.5\n"
+#~ msgstr ""
+#~ " **失敗** %s 必須為 1284DeviceIDï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 72 é ï¼Œç« ç¯€ 5.5\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultImageableArea %s!\n"
+#~ " REF: Page 102, section 5.15.\n"
+#~ msgstr ""
+#~ " **失敗** DefaultImageableArea %s 錯誤ï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 102 é ï¼Œç« ç¯€ 5.15。\n"
+
+#~ msgid ""
+#~ " **FAIL** BAD DefaultPaperDimension %s!\n"
+#~ " REF: Page 103, section 5.15.\n"
+#~ msgstr ""
+#~ " **失敗** DefaultPaperDimension %s 錯誤ï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 103 é ï¼Œç« ç¯€ 5.15。\n"
+
+#~ msgid ""
+#~ " **FAIL** Bad %s choice %s!\n"
+#~ " REF: Page 84, section 5.9\n"
+#~ msgstr ""
+#~ " **失敗** %s é¸é … %s 錯誤ï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 84 é ï¼Œç« ç¯€ 5.9\n"
+
+#~ msgid " **FAIL** Bad LanguageEncoding %s - must be ISOLatin1!\n"
+#~ msgstr " **失敗** LanguageEncoding %s 錯誤 - 必須為 ISOLatin1ï¼\n"
+
+#~ msgid " **FAIL** Bad LanguageVersion %s - must be English!\n"
+#~ msgstr " **失敗** LanguageVersion %s 錯誤 - 必須為英語ï¼\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s choice %s "
+#~ "contains 8-bit characters!\n"
+#~ msgstr " **失敗** é¸é … %s é¸é … %s çš„é è¨­è½‰æ›å­—ä¸²åŒ…å« 8 ä½å…ƒå­—å…ƒï¼\n"
+
+#~ msgid ""
+#~ " **FAIL** Default translation string for option %s contains 8-bit "
+#~ "characters!\n"
+#~ msgstr " **失敗** é¸é … %s çš„é è¨­è½‰æ›å­—ä¸²åŒ…å« 8 ä½å…ƒå­—å…ƒï¼\n"
+
+#~ msgid " **FAIL** Group names %s and %s differ only by case!\n"
+#~ msgstr " **失敗** 群組å稱 %s å’Œ %s 僅在æŸäº›æƒ…æ³ä¸‹ä¸åŒï¼\n"
+
+#~ msgid " **FAIL** Multiple occurrences of %s choice name %s!\n"
+#~ msgstr " **失敗** 出ç¾äº†å¤šå€‹ %s é¸é …å稱 %sï¼\n"
+
+#~ msgid " **FAIL** Option names %s and %s differ only by case!\n"
+#~ msgstr " **失敗** é¸é …å稱 %s å’Œ %s 僅在æŸäº›æƒ…æ³ä¸‹ä¸åŒï¼\n"
+
+#~ msgid ""
+#~ " Bad %%%%BoundingBox: on line %d!\n"
+#~ " REF: Page 39, %%%%BoundingBox:\n"
+#~ msgstr ""
+#~ " 第 %d 行的 %%%%BoundingBox: 錯誤ï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 39 é ï¼Œ%%%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Page: on line %d!\n"
+#~ " REF: Page 53, %%%%Page:\n"
+#~ msgstr ""
+#~ " 第 %d 行的 %%%%Page: 錯誤ï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 53 é ï¼Œ%%%%Page:\n"
+
+#~ msgid ""
+#~ " Bad %%%%Pages: on line %d!\n"
+#~ " REF: Page 43, %%%%Pages:\n"
+#~ msgstr ""
+#~ " 第 %d 行的 %%%%Pages: 錯誤ï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 43 é ï¼Œ%%%%Pages:\n"
+
+#~ msgid ""
+#~ " Line %d is longer than 255 characters (%d)!\n"
+#~ " REF: Page 25, Line Length\n"
+#~ msgstr ""
+#~ " 第 %d 行長度大於 255 個字元(%d)ï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 25 é ï¼Œè¡Œé•·åº¦\n"
+
+#~ msgid ""
+#~ " Missing %!PS-Adobe-3.0 on first line!\n"
+#~ " REF: Page 17, 3.1 Conforming Documents\n"
+#~ msgstr ""
+#~ " 第一行éºå¤± %!PS-Adobe-3.0ï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 17 é ï¼Œ3.1 確èªæ–‡ä»¶\n"
+
+#~ msgid ""
+#~ " Missing %%EndComments comment!\n"
+#~ " REF: Page 41, %%EndComments\n"
+#~ msgstr ""
+#~ " éºå¤± %%EndComments 註解ï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 41 é ï¼Œ%%EndComments\n"
+
+#~ msgid ""
+#~ " Missing or bad %%BoundingBox: comment!\n"
+#~ " REF: Page 39, %%BoundingBox:\n"
+#~ msgstr ""
+#~ " %%BoundingBox﹕ 註解éºå¤±æˆ–錯誤ï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 39 é ï¼Œ%%BoundingBox:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Page: comments!\n"
+#~ " REF: Page 53, %%Page:\n"
+#~ msgstr ""
+#~ " %%Page: 註解éºå¤±æˆ–錯誤ï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 53 é ï¼Œ%%Page:\n"
+
+#~ msgid ""
+#~ " Missing or bad %%Pages: comment!\n"
+#~ " REF: Page 43, %%Pages:\n"
+#~ msgstr ""
+#~ " %%Pages: 註解éºå¤±æˆ–錯誤ï¼\n"
+#~ " åƒè€ƒï¼šç¬¬ 43 é ï¼Œ%%Pages:\n"
+
+#~ msgid " Saw %d lines that exceeded 255 characters!\n"
+#~ msgstr " ç™¼ç¾ %d 行超出 255 個字元ï¼\n"
+
+#~ msgid " Too many %%BeginDocument comments!\n"
+#~ msgstr " %%BeginDocument 註解太多ï¼\n"
+
+#~ msgid " Too many %%EndDocument comments!\n"
+#~ msgstr " %%EndDocument 註解太多ï¼\n"
+
+#~ msgid " Warning: file contains binary data!\n"
+#~ msgstr " WARNING: 檔案包å«äºŒé€²ä½è³‡æ–™ï¼\n"
+
+#~ msgid " Warning: no %%EndComments comment in file!\n"
+#~ msgstr " WARNING: 檔案中沒有 %%EndComments 註解ï¼\n"
+
+#~ msgid " Warning: obsolete DSC version %.1f in file!\n"
+#~ msgstr " WARNING: 檔案中的 DSC 版本 %.1f å·²éŽæ™‚ï¼\n"
+
+#~ msgid "%s not supported!"
+#~ msgstr "ä¸æ”¯æ´ %sï¼"
+
+#~ msgid "%s: Don't know what to do!\n"
+#~ msgstr "%s:ä¸çŸ¥é“è¦åŸ·è¡Œçš„動作ï¼\n"
+
+#~ msgid ""
+#~ "%s: Error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr "%s:錯誤 - %s 環境變數å稱中有ä¸å­˜åœ¨çš„目的地“%sâ€ï¼\n"
+
+#~ msgid "%s: Error - bad job ID!\n"
+#~ msgstr "%s:錯誤 - 作業 ID 錯誤ï¼\n"
+
+#~ msgid "%s: Error - cannot print files and alter jobs simultaneously!\n"
+#~ msgstr "%s:錯誤 - 無法列å°æª”案並åŒæ™‚更改作業ï¼\n"
+
+#~ msgid ""
+#~ "%s: Error - cannot print from stdin if files or a job ID are provided!\n"
+#~ msgstr "%s:錯誤 - 在æ供檔案或作業 ID 的情æ³ä¸‹ç„¡æ³•å¾ž stdin 進行列å°ï¼\n"
+
+#~ msgid "%s: Error - expected character set after '-S' option!\n"
+#~ msgstr "%s:錯誤 - '-S' é¸é …後é¢é æœŸç‚ºå­—元集ï¼\n"
+
+#~ msgid "%s: Error - expected content type after '-T' option!\n"
+#~ msgstr "%s:錯誤 - '-T' é¸é …後é¢é æœŸç‚ºå…§å®¹é¡žåž‹ï¼\n"
+
+#~ msgid "%s: Error - expected copies after '-n' option!\n"
+#~ msgstr "%s:錯誤 - '-n' é¸é …後é¢é æœŸç‚ºä»½æ•¸ï¼\n"
+
+#~ msgid "%s: Error - expected copy count after '-#' option!\n"
+#~ msgstr "%s:錯誤 - '-#' é¸é …後é¢é æœŸç‚ºè¤‡æœ¬è¨ˆæ•¸ï¼\n"
+
+#~ msgid "%s: Error - expected destination after '-P' option!\n"
+#~ msgstr "%s:錯誤 - '-P' é¸é …後é¢é æœŸç‚ºç›®çš„地ï¼\n"
+
+#~ msgid "%s: Error - expected destination after '-b' option!\n"
+#~ msgstr "%s:錯誤 - '-b' é¸é …後é¢é æœŸç‚ºç›®çš„地ï¼\n"
+
+#~ msgid "%s: Error - expected destination after '-d' option!\n"
+#~ msgstr "%s:錯誤 - '-d' é¸é …後é¢é æœŸç‚ºç›®çš„地ï¼\n"
+
+#~ msgid "%s: Error - expected form after '-f' option!\n"
+#~ msgstr "%s:錯誤 - '-f' é¸é …後é¢é æœŸç‚ºè¡¨å–®ï¼\n"
+
+#~ msgid "%s: Error - expected hold name after '-H' option!\n"
+#~ msgstr "%s:錯誤 - '-H' é¸é …後é¢é æœŸç‚ºä¿ç•™å稱ï¼\n"
+
+#~ msgid "%s: Error - expected hostname after '-H' option!\n"
+#~ msgstr "%s:錯誤 - '-H' é¸é …後é¢é æœŸç‚ºä¸»æ©Ÿå稱ï¼\n"
+
+#~ msgid "%s: Error - expected hostname after '-h' option!\n"
+#~ msgstr "%s:錯誤 - '-h' é¸é …後é¢é æœŸç‚ºä¸»æ©Ÿå稱ï¼\n"
+
+#~ msgid "%s: Error - expected mode list after '-y' option!\n"
+#~ msgstr "%s:錯誤 - '-y' é¸é …後é¢é æœŸç‚ºæ¨¡å¼åˆ—表ï¼\n"
+
+#~ msgid "%s: Error - expected name after '-%c' option!\n"
+#~ msgstr "%s:錯誤 - '-%c' é¸é …後é¢é æœŸç‚ºå稱ï¼\n"
+
+#~ msgid "%s: Error - expected option string after '-o' option!\n"
+#~ msgstr "%s:錯誤 - '-o' é¸é …後é¢é æœŸç‚ºé¸é …字串ï¼\n"
+
+#~ msgid "%s: Error - expected page list after '-P' option!\n"
+#~ msgstr "%s:錯誤 - '-P' é¸é …後é¢é æœŸç‚ºé é¢åˆ—表ï¼\n"
+
+#~ msgid "%s: Error - expected priority after '-%c' option!\n"
+#~ msgstr "%s:錯誤 - '-%c' é¸é …後é¢é æœŸç‚ºå„ªå…ˆé †åºï¼\n"
+
+#~ msgid "%s: Error - expected reason text after '-r' option!\n"
+#~ msgstr "%s:錯誤 - '-r' é¸é …後é¢é æœŸç‚ºåŽŸå› æ–‡å­—ï¼\n"
+
+#~ msgid "%s: Error - expected title after '-t' option!\n"
+#~ msgstr "%s:錯誤 - '-t' é¸é …後é¢é æœŸç‚ºæ¨™é¡Œï¼\n"
+
+#~ msgid "%s: Error - expected username after '-U' option!\n"
+#~ msgstr "%s:錯誤 - '-U' é¸é …後é¢é æœŸç‚ºä½¿ç”¨è€…å稱ï¼\n"
+
+#~ msgid "%s: Error - expected username after '-u' option!\n"
+#~ msgstr "%s:錯誤 - '-u' é¸é …後é¢é æœŸç‚ºä½¿ç”¨è€…å稱ï¼\n"
+
+#~ msgid "%s: Error - expected value after '-%c' option!\n"
+#~ msgstr "%s:錯誤 - '-%c' é¸é …後é¢é æœŸç‚ºå€¼ï¼\n"
+
+#~ msgid ""
+#~ "%s: Error - need \"completed\", \"not-completed\", or \"all\" after '-W' "
+#~ "option!\n"
+#~ msgstr ""
+#~ "%s:錯誤 - &aops;-W&aops; é¸é …後é¢éœ€è¦â€œcompletedâ€ã€â€œnot-"
+#~ "completedâ€æˆ–“allâ€ï¼\n"
+
+#~ msgid "%s: Error - scheduler not responding!\n"
+#~ msgstr "%s:錯誤 - 排程器沒有回應ï¼\n"
+
+#~ msgid "%s: Error - unknown destination \"%s\"!\n"
+#~ msgstr "%s:錯誤 - 未知的目的地“%sâ€ï¼\n"
+
+#~ msgid "%s: Error - unknown destination \"%s/%s\"!\n"
+#~ msgstr "%s:錯誤 - 未知的目的地“%s/%sâ€ï¼\n"
+
+#~ msgid "%s: Error - unknown option '%c'!\n"
+#~ msgstr "%s:錯誤 - 未知的é¸é … '%c'ï¼\n"
+
+#~ msgid "%s: Error - unknown option '%s'!\n"
+#~ msgstr "%s:錯誤 - 未知的é¸é … '%s'ï¼\n"
+
+#~ msgid "%s: Expected job ID after '-i' option!\n"
+#~ msgstr "%s:'-i' é¸é …後é¢é æœŸç‚ºä½œæ¥­ IDï¼\n"
+
+#~ msgid "%s: Invalid destination name in list \"%s\"!\n"
+#~ msgstr "%s:列表“%sâ€ä¸­çš„目的地å稱無效ï¼\n"
+
+#~ msgid "%s: Need job ID ('-i jobid') before '-H restart'!\n"
+#~ msgstr "%s:&aops;-H restart&aops; å‰é¢éœ€è¦ä½œæ¥­ ID('-i jobid')ï¼\n"
+
+#~ msgid "%s: No filter to convert from %s/%s to %s/%s!\n"
+#~ msgstr "%s:沒有濾é¡è¦å¾ž %s/%s 轉æ›ç‚º %s/%sï¼\n"
+
+#~ msgid "%s: Sorry, no encryption support compiled in!\n"
+#~ msgstr "%s:抱歉,未編譯入加密支æ´ï¼\n"
+
+#~ msgid "%s: Unable to contact server!\n"
+#~ msgstr "%s:無法è¯çµ¡ä¼ºæœå™¨ï¼\n"
+
+#~ msgid "%s: Unable to determine MIME type of \"%s\"!\n"
+#~ msgstr "%s:無法確定“%sâ€çš„ MIME é¡žåž‹ï¼\n"
+
+#~ msgid "%s: Unable to open %s - %s\n"
+#~ msgstr "%s:無法打開 %s - %s\n"
+
+#~ msgid "%s: Unable to open %s - %s on line %d.\n"
+#~ msgstr "%s:無法打開 %s - %s 在第 %d 行。\n"
+
+#~ msgid "%s: Unable to read MIME database from \"%s\" or \"%s\"!\n"
+#~ msgstr "%s:無法從“%sâ€æˆ–“%sâ€è®€å– MIME 資料庫ï¼\n"
+
+#~ msgid "%s: Unknown destination \"%s\"!\n"
+#~ msgstr "%s:未知的目的地“%sâ€ï¼\n"
+
+#~ msgid "%s: Unknown destination MIME type %s/%s!\n"
+#~ msgstr "%s:未知的目的地 MIME é¡žåž‹ %s/%sï¼\n"
+
+#~ msgid "%s: Unknown option '%c'!\n"
+#~ msgstr "%s:未知的é¸é … '%c'ï¼\n"
+
+#~ msgid "%s: Unknown source MIME type %s/%s!\n"
+#~ msgstr "%sï¼šæœªçŸ¥çš„ä¾†æº MIME é¡žåž‹ %s/%sï¼\n"
+
+#~ msgid ""
+#~ "%s: Warning - '%c' format modifier not supported - output may not be "
+#~ "correct!\n"
+#~ msgstr "%s:警告 - ä¸æ”¯æ´ '%c' æ ¼å¼ä¿®é£¾ç¬¦ - 輸出å¯èƒ½ä¸æ­£ç¢ºï¼\n"
+
+#~ msgid "%s: Warning - character set option ignored!\n"
+#~ msgstr "%s:警告 - 已忽略字元集é¸é …ï¼\n"
+
+#~ msgid "%s: Warning - content type option ignored!\n"
+#~ msgstr "%s:警告 - 已忽略內容類型é¸é …ï¼\n"
+
+#~ msgid "%s: Warning - form option ignored!\n"
+#~ msgstr "%s:警告 - 已忽略表單é¸é …ï¼\n"
+
+#~ msgid "%s: Warning - mode option ignored!\n"
+#~ msgstr "%s:警告 - 已忽略模å¼é¸é …ï¼\n"
+
+#~ msgid ""
+#~ "%s: error - %s environment variable names non-existent destination \"%s"
+#~ "\"!\n"
+#~ msgstr "%s:錯誤 - %s 環境變數å稱中有ä¸å­˜åœ¨çš„目的地“%sâ€ï¼\n"
+
+#~ msgid "%s: error - expected option=value after '-o' option!\n"
+#~ msgstr "%s:錯誤 - &aops;-o&aops; é¸é …後é¢é æœŸç‚º option=valueï¼\n"
+
+#~ msgid "600 DPI Grayscale"
+#~ msgstr "600 DPI ç°éšŽ"
+
+#~ msgid "A Samba password is required to export printer drivers!"
+#~ msgstr "éœ€è¦ Samba 密碼,æ‰èƒ½è¼¸å‡ºå°è¡¨æ©Ÿé©…動程å¼ï¼"
+
+#~ msgid "A Samba username is required to export printer drivers!"
+#~ msgstr "éœ€è¦ Samba 使用者å稱,æ‰èƒ½è¼¸å‡ºå°è¡¨æ©Ÿé©…動程å¼ï¼"
+
+#~ msgid "A class named \"%s\" already exists!"
+#~ msgstr "å為“%sâ€çš„類別已存在ï¼"
+
+#~ msgid "A printer named \"%s\" already exists!"
+#~ msgstr "å為“%sâ€çš„å°è¡¨æ©Ÿå·²å­˜åœ¨ï¼"
+
+#~ msgid "Attempt to set %s printer-state to bad value %d!"
+#~ msgstr "嘗試將 %s å°è¡¨æ©Ÿç‹€æ…‹è¨­ç‚ºéŒ¯èª¤çš„值 %dï¼"
+
+#~ msgid "Attribute groups are out of order (%x < %x)!"
+#~ msgstr "屬性群組有å•é¡Œï¼ˆ%x < %x)ï¼"
+
+#~ msgid "Bad device URI \"%s\"!\n"
+#~ msgstr "設備 URI“%sâ€éŒ¯èª¤ï¼\n"
+
+#~ msgid "Bad device-uri \"%s\"!"
+#~ msgstr "device-uri“%sâ€éŒ¯èª¤ï¼"
+
+#~ msgid "Bad device-uri scheme \"%s\"!"
+#~ msgstr "device-uri 架構“%sâ€éŒ¯èª¤ï¼"
+
+#~ msgid "Bad document-format \"%s\"!"
+#~ msgstr "document-format“%sâ€éŒ¯èª¤ï¼"
+
+#~ msgid "Bad filename buffer!"
+#~ msgstr "檔åç·©è¡å€éŒ¯èª¤ï¼"
+
+#~ msgid "Bad job-priority value!"
+#~ msgstr "job-priority 值錯誤ï¼"
+
+#~ msgid "Bad job-sheets value \"%s\"!"
+#~ msgstr "job-sheets 值“%sâ€éŒ¯èª¤ï¼"
+
+#~ msgid "Bad job-sheets value type!"
+#~ msgstr "job-sheets 值類型錯誤ï¼"
+
+#~ msgid "Bad job-state value!"
+#~ msgstr "job-state 值錯誤ï¼"
+
+#~ msgid "Bad job-uri attribute \"%s\"!"
+#~ msgstr "job-uri 屬性“%sâ€éŒ¯èª¤ï¼"
+
+#~ msgid "Bad notify-pull-method \"%s\"!"
+#~ msgstr "notify-pull-method“%sâ€éŒ¯èª¤ï¼"
+
+#~ msgid "Bad notify-recipient-uri URI \"%s\"!"
+#~ msgstr "notify-recipient-uri URI“%sâ€éŒ¯èª¤ï¼"
+
+#~ msgid "Bad option + choice on line %d!"
+#~ msgstr "第 %d 行的 option + choice 錯誤ï¼"
+
+#~ msgid "Bad port-monitor \"%s\"!"
+#~ msgstr "port-monitor“%sâ€éŒ¯èª¤ï¼"
+
+#~ msgid "Bad printer-state value %d!"
+#~ msgstr "printer-state 值 %d 錯誤ï¼"
+
+#~ msgid "Bad request version number %d.%d!"
+#~ msgstr "請求版本號碼 %d.%d 錯誤ï¼"
+
+#~ msgid "Bad subscription ID!"
+#~ msgstr "訂閱 ID 錯誤ï¼"
+
+#~ msgid "Character set \"%s\" not supported!"
+#~ msgstr "ä¸æ”¯æ´å­—元集“%sâ€ï¼"
+
+#~ msgid "Could not scan type \"%s\"!"
+#~ msgstr "無法掃æ類型“%sâ€ï¼"
+
+#~ msgid "Cover open."
+#~ msgstr "機蓋已打開。"
+
+#~ msgid "Developer almost empty."
+#~ msgstr "顯åƒåŠ‘å³å°‡è€—盡。"
+
+#~ msgid "Developer empty!"
+#~ msgstr "顯åƒåŠ‘已耗盡ï¼"
+
+#~ msgid "Door open."
+#~ msgstr "機門已打開。"
+
+#~ msgid "ERROR: Bad %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: %%BoundingBox ERROR: 發ç¾æœ‰è¨»è§£ï¼\n"
+
+#~ msgid "ERROR: Bad %%IncludeFeature: comment!\n"
+#~ msgstr "ERROR: %%IncludeFeature ERROR: 註解ï¼\n"
+
+#~ msgid "ERROR: Bad %%Page: comment in file!\n"
+#~ msgstr "ERROR: %%Page ERROR: 檔案中的註解ï¼\n"
+
+#~ msgid "ERROR: Bad %%PageBoundingBox: comment in file!\n"
+#~ msgstr "ERROR: %%PageBoundingBox ERROR: 檔案中的註解ï¼\n"
+
+#~ msgid "ERROR: Bad SCSI device file \"%s\"!\n"
+#~ msgstr "ERROR: SCSI 設備檔案“%sâ€éŒ¯èª¤ï¼\n"
+
+#~ msgid "ERROR: Bad columns value %d!\n"
+#~ msgstr "ERROR: 直欄值 %d 錯誤ï¼\n"
+
+#~ msgid "ERROR: Bad cpi value %f!\n"
+#~ msgstr "ERROR: cpi 值 %f 錯誤ï¼\n"
+
+#~ msgid "ERROR: Bad lpi value %f!\n"
+#~ msgstr "ERROR: lpi 值 %f 錯誤ï¼\n"
+
+#~ msgid "ERROR: Bad page setup!\n"
+#~ msgstr "ERROR: é é¢è¨­å®šéŒ¯èª¤ï¼\n"
+
+#~ msgid "ERROR: Destination printer does not exist!\n"
+#~ msgstr "ERROR: 目的å°è¡¨æ©Ÿä¸å­˜åœ¨ï¼\n"
+
+#~ msgid "ERROR: Duplicate %%BoundingBox: comment seen!\n"
+#~ msgstr "ERROR: é‡è¤‡çš„ %%BoundingBox:發ç¾æœ‰è¨»è§£ï¼\n"
+
+#~ msgid "ERROR: Duplicate %%Pages: comment seen!\n"
+#~ msgstr "ERROR: é‡è¤‡çš„ %%Pages:發ç¾æœ‰è¨»è§£ï¼\n"
+
+#~ msgid "ERROR: Empty print file!\n"
+#~ msgstr "ERROR: 列å°æª”案為空ï¼\n"
+
+#~ msgid "ERROR: Expected quoted string on line %d of %s!\n"
+#~ msgstr "ERROR: %2$s 的第 %1$d è¡Œé æœŸç‚ºå¼•è¨€å­—串ï¼\n"
+
+#~ msgid "ERROR: Fatal USB error!\n"
+#~ msgstr "ERROR: åš´é‡çš„ USB 錯誤ï¼\n"
+
+#~ msgid "ERROR: Invalid HP-GL/2 command seen, unable to print file!\n"
+#~ msgstr "ERROR: 發ç¾ç„¡æ•ˆçš„ HP-GL/2 指令,無法列å°æª”案ï¼\n"
+
+#~ msgid "ERROR: Missing %%EndProlog!\n"
+#~ msgstr "ERROR: éºå¤± %%EndPrologï¼\n"
+
+#~ msgid "ERROR: Missing %%EndSetup!\n"
+#~ msgstr "ERROR: éºå¤± %%EndSetupï¼\n"
+
+#~ msgid ""
+#~ "ERROR: Missing device URI on command-line and no DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr "ERROR: 指令行éºå¤±è¨­å‚™ URI 且沒有 DEVICE_URI 環境變數ï¼\n"
+
+#~ msgid "ERROR: Missing value on line %d of banner file!\n"
+#~ msgstr "ERROR: 標語檔案的第 %d è¡Œéºå¤±å€¼ï¼\n"
+
+#~ msgid ""
+#~ "ERROR: Need a msgid line before any translation strings on line %d of %"
+#~ "s!\n"
+#~ msgstr "ERROR: 在 %2$s 第 %1$d 行的任何轉æ›å­—串å‰é¢éƒ½éœ€è¦ msgid è¡Œï¼\n"
+
+#~ msgid "ERROR: No %%BoundingBox: comment in header!\n"
+#~ msgstr "ERROR: 沒有 %%BoundingBox:標題中的註解ï¼\n"
+
+#~ msgid "ERROR: No %%Pages: comment in header!\n"
+#~ msgstr "ERROR: 沒有 %%Pages:標題中的註解ï¼\n"
+
+#~ msgid ""
+#~ "ERROR: No device URI found in argv[0] or in DEVICE_URI environment "
+#~ "variable!\n"
+#~ msgstr "ERROR: 在 argv[0] 或 DEVICE_URI 環境變數中找ä¸åˆ°è¨­å‚™ URIï¼\n"
+
+#~ msgid "ERROR: No pages found!\n"
+#~ msgstr "ERROR: 找ä¸åˆ°é é¢ï¼\n"
+
+#~ msgid "ERROR: Out of paper!\n"
+#~ msgstr "ERROR: 缺紙ï¼\n"
+
+#~ msgid "ERROR: PRINTER environment variable not defined!\n"
+#~ msgstr "ERROR: 未定義 PRINTER 環境變數ï¼\n"
+
+#~ msgid "ERROR: Print file was not accepted (%s)!\n"
+#~ msgstr "ERROR: ä¸æŽ¥å—列å°æª”案(%s)ï¼\n"
+
+#~ msgid "ERROR: Printer not responding!\n"
+#~ msgstr "ERROR: å°è¡¨æ©Ÿæœªå›žæ‡‰ï¼\n"
+
+#~ msgid "ERROR: Unable to create temporary file - %s.\n"
+#~ msgstr "ERROR: 無法製作暫存檔 - %s。\n"
+
+#~ msgid "ERROR: Unable to create temporary file: %s\n"
+#~ msgstr "ERROR: 無法製作暫存檔:%s\n"
+
+#~ msgid "ERROR: Unable to get job %d attributes (%s)!\n"
+#~ msgstr "ERROR: 無法å–得作業 %d 屬性(%s)ï¼\n"
+
+#~ msgid "ERROR: Unable to get printer status (%s)!\n"
+#~ msgstr "ERROR: 無法å–å¾—å°è¡¨æ©Ÿç‹€æ…‹ï¼ˆ%s)ï¼\n"
+
+#~ msgid "ERROR: Unable to locate printer '%s'!\n"
+#~ msgstr "ERROR: 找ä¸åˆ°å°è¡¨æ©Ÿ '%s'ï¼\n"
+
+#~ msgid "ERROR: Unable to open image file for printing!\n"
+#~ msgstr "ERROR: 無法打開è¦åˆ—å°çš„å½±åƒæª”ï¼\n"
+
+#~ msgid "ERROR: Unable to open temporary file"
+#~ msgstr "ERROR: 無法打開暫存檔"
+
+#~ msgid "ERROR: Unable to print %d text columns!\n"
+#~ msgstr "ERROR: ç„¡æ³•åˆ—å° %d 文字直欄ï¼\n"
+
+#~ msgid "ERROR: Unable to print %dx%d text page!\n"
+#~ msgstr "ERROR: ç„¡æ³•åˆ—å° %dx%d 文字é é¢ï¼\n"
+
+#~ msgid "ERROR: Unable to read print data!\n"
+#~ msgstr "ERROR: 無法讀å–列å°è³‡æ–™ï¼\n"
+
+#~ msgid "ERROR: Unable to send print data (%d)\n"
+#~ msgstr "ERROR: 無法傳é€åˆ—å°è³‡æ–™ï¼ˆ%d)\n"
+
+#~ msgid "ERROR: Unable to send print data!\n"
+#~ msgstr "ERROR: 無法傳é€åˆ—å°è³‡æ–™ï¼\n"
+
+#~ msgid "ERROR: Unable to write %d bytes to printer!\n"
+#~ msgstr "ERROR: 無法將 %d ä½å…ƒçµ„寫入至å°è¡¨æ©Ÿï¼\n"
+
+#~ msgid "ERROR: Unable to write raster data to driver!\n"
+#~ msgstr "ERROR: 無法將水平掃瞄線資料寫入驅動程å¼ï¼\n"
+
+#~ msgid "ERROR: Unable to write to temporary file"
+#~ msgstr "ERROR: 無法寫入暫存檔"
+
+#~ msgid "ERROR: Unexpected text on line %d of %s!\n"
+#~ msgstr "ERROR: %2$s 的第 %1$d 行有éžé æœŸçš„文字ï¼\n"
+
+#~ msgid "ERROR: Unknown encryption option value \"%s\"!\n"
+#~ msgstr "ERROR: 未知的加密é¸é …值“%sâ€ï¼\n"
+
+#~ msgid "ERROR: Unknown message catalog format for \"%s\"!\n"
+#~ msgstr "ERROR: “%sâ€çš„訊æ¯ç›®éŒ„æ ¼å¼æœªçŸ¥ï¼\n"
+
+#~ msgid "ERROR: Unknown option \"%s\" with value \"%s\"!\n"
+#~ msgstr "ERROR: 未知的é¸é …“%sâ€ï¼Œå€¼ç‚ºâ€œ%sâ€ï¼\n"
+
+#~ msgid "ERROR: Unknown version option value \"%s\"!\n"
+#~ msgstr "ERROR: 未知的版本é¸é …值“%sâ€ï¼\n"
+
+#~ msgid "ERROR: Unsupported brightness value %s, using brightness=100!\n"
+#~ msgstr "ERROR: ä¸å—支æ´çš„亮度值 %s,使用 brightness=100ï¼\n"
+
+#~ msgid "ERROR: Unsupported gamma value %s, using gamma=1000!\n"
+#~ msgstr "ERROR: ä¸å—支æ´çš„ gamma 值 %s,使用 gamma=1000ï¼\n"
+
+#~ msgid "ERROR: Unsupported number-up value %d, using number-up=1!\n"
+#~ msgstr "ERROR: ä¸å—支æ´çš„ number-up 值 %d,使用 number-up=1ï¼\n"
+
+#~ msgid ""
+#~ "ERROR: Unsupported number-up-layout value %s, using number-up-"
+#~ "layout=lrtb!\n"
+#~ msgstr ""
+#~ "ERROR: ä¸å—支æ´çš„ number-up-layout 值 %s,使用 number-up-layout=lrtbï¼\n"
+
+#~ msgid "ERROR: Unsupported page-border value %s, using page-border=none!\n"
+#~ msgstr "ERROR: ä¸å—支æ´çš„ page-border 值 %s,使用 page-border=noneï¼\n"
+
+#~ msgid "ERROR: doc_printf overflow (%d bytes) detected, aborting!\n"
+#~ msgstr "ERROR: åµæ¸¬åˆ° doc_printf 溢ä½ï¼ˆ%d ä½å…ƒçµ„),正在中斷ï¼\n"
+
+#~ msgid "ERROR: pdftops filter crashed on signal %d!\n"
+#~ msgstr "ERROR: pdftops 濾é¡åœ¨é‡åˆ°è¨Šè™Ÿ %d 時當機ï¼\n"
+
+#~ msgid "ERROR: pdftops filter exited with status %d!\n"
+#~ msgstr "ERROR: pdftops 濾é¡ä»¥ç‹€æ…‹ %d çµæŸï¼\n"
+
+#~ msgid "ERROR: pictwpstops exited on signal %d!\n"
+#~ msgstr "ERROR: pictwpstops 在é‡åˆ°è¨Šè™Ÿ %d 時çµæŸï¼\n"
+
+#~ msgid "ERROR: pictwpstops exited with status %d!\n"
+#~ msgstr "ERROR: pictwpstops 以狀態 %d çµæŸï¼\n"
+
+#~ msgid ""
+#~ "ERROR: recoverable: Unable to connect to printer; will retry in 30 "
+#~ "seconds...\n"
+#~ msgstr "ERROR: å¯å›žå¾©ï¼šç„¡æ³•é€£æŽ¥å°è¡¨æ©Ÿï¼›30 秒內將é‡è©¦â‹¯\n"
+
+#~ msgid "Empty PPD file!"
+#~ msgstr "PPD 檔案為空ï¼"
+
+#~ msgid "Error: need hostname after '-h' option!\n"
+#~ msgstr "ERROR: '-h' é¸é …後é¢éœ€è¦ä¸»æ©Ÿå稱ï¼\n"
+
+#~ msgid "Fuser temperature high!"
+#~ msgstr "加熱器溫度高ï¼"
+
+#~ msgid "Fuser temperature low!"
+#~ msgstr "加熱器溫度低ï¼"
+
+#~ msgid "Got a printer-uri attribute but no job-id!"
+#~ msgstr "å·²å–å¾— printer-uri 屬性,但沒有 job-idï¼"
+
+#~ msgid "Ink/toner almost empty."
+#~ msgstr "墨水或碳粉å³å°‡è€—盡。"
+
+#~ msgid "Ink/toner empty!"
+#~ msgstr "墨水或碳粉已耗盡ï¼"
+
+#~ msgid "Ink/toner waste bin almost full."
+#~ msgstr "墨水或碳粉廢料槽將滿。"
+
+#~ msgid "Ink/toner waste bin full!"
+#~ msgstr "墨水或碳粉廢料槽已滿ï¼"
+
+#~ msgid "Interlock open."
+#~ msgstr "Interlock 已打開。"
+
+#~ msgid "Job #%d cannot be restarted - no files!"
+#~ msgstr "無法é‡æ–°å•Ÿå‹•ä½œæ¥­ #%d - 沒有檔案ï¼"
+
+#~ msgid "Job #%d does not exist!"
+#~ msgstr "作業 #%d ä¸å­˜åœ¨ï¼"
+
+#~ msgid "Job #%d is finished and cannot be altered!"
+#~ msgstr "已完æˆä½œæ¥­ #%d 且無法更改ï¼"
+
+#~ msgid "Job #%d is not complete!"
+#~ msgstr "未完æˆä½œæ¥­ #%dï¼"
+
+#~ msgid "Job #%d is not held for authentication!"
+#~ msgstr "未暫åœä½œæ¥­ #%d 進行èªè­‰ï¼"
+
+#~ msgid "Job #%d is not held!"
+#~ msgstr "未暫åœä½œæ¥­ #%dï¼"
+
+#~ msgid "Job #%s does not exist!"
+#~ msgstr "作業 #%s ä¸å­˜åœ¨ï¼"
+
+#~ msgid "Job %d not found!"
+#~ msgstr "找ä¸åˆ°ä½œæ¥­ %dï¼"
+
+#~ msgid "Job subscriptions cannot be renewed!"
+#~ msgstr "無法更新作業訂閱ï¼"
+
+#~ msgid "Language \"%s\" not supported!"
+#~ msgstr "ä¸æ”¯æ´èªžè¨€â€œ%sâ€ï¼"
+
+#~ msgid "Media jam!"
+#~ msgstr "媒體å¡ç´™ï¼"
+
+#~ msgid "Media tray almost empty."
+#~ msgstr "媒體é€ç´™åŒ£å³å°‡ç”¨å®Œã€‚"
+
+#~ msgid "Media tray empty!"
+#~ msgstr "媒體é€ç´™åŒ£ç‚ºç©ºï¼"
+
+#~ msgid "Media tray missing!"
+#~ msgstr "找ä¸åˆ°åª’é«”é€ç´™åŒ£ï¼"
+
+#~ msgid "Media tray needs to be filled."
+#~ msgstr "媒體é€ç´™åŒ£éœ€è¦æ·»åŠ ç´™å¼µã€‚"
+
+#~ msgid "Missing document-number attribute!"
+#~ msgstr "éºå¤± document-number 屬性ï¼"
+
+#~ msgid "Missing double quote on line %d!"
+#~ msgstr "第 %d è¡Œéºå¤±é›™å¼•è™Ÿï¼!"
+
+#~ msgid "Missing form variable!"
+#~ msgstr "éºå¤±è¡¨å–®è®Šæ•¸ï¼"
+
+#~ msgid "Missing notify-subscription-ids attribute!"
+#~ msgstr "éºå¤± notify-subscription-ids 屬性ï¼"
+
+#~ msgid "Missing requesting-user-name attribute!"
+#~ msgstr "éºå¤± requesting-user-name 屬性ï¼"
+
+#~ msgid "Missing required attributes!"
+#~ msgstr "éºå¤±å¿…è¦çš„屬性ï¼"
+
+#~ msgid "Missing value on line %d!"
+#~ msgstr "第 %d è¡Œéºå¤±å€¼ï¼"
+
+#~ msgid "No PPD name!"
+#~ msgstr "沒有 PPD å稱ï¼"
+
+#~ msgid "No Windows printer drivers are installed!"
+#~ msgstr "æœªå®‰è£ Windows å°è¡¨æ©Ÿé©…動程å¼ï¼"
+
+#~ msgid "No active jobs on %s!"
+#~ msgstr "%s 上沒有已啟用的作業ï¼"
+
+#~ msgid "No attributes in request!"
+#~ msgstr "請求中沒有屬性ï¼"
+
+#~ msgid "No authentication information provided!"
+#~ msgstr "未æä¾›èªè­‰è³‡è¨Šï¼"
+
+#~ msgid "No file!?!"
+#~ msgstr "沒有檔案!?!"
+
+#~ msgid "No modification time!"
+#~ msgstr "沒有修改時間ï¼"
+
+#~ msgid "No printer name!"
+#~ msgstr "沒有å°è¡¨æ©Ÿå稱ï¼"
+
+#~ msgid "No printer-uri found for class!"
+#~ msgstr "找ä¸åˆ°é¡žåˆ¥çš„ printer-uriï¼"
+
+#~ msgid "No printer-uri found!"
+#~ msgstr "找ä¸åˆ° printer-uriï¼"
+
+#~ msgid "No printer-uri in request!"
+#~ msgstr "請求中沒有 printer-uriï¼"
+
+#~ msgid "No subscription attributes in request!"
+#~ msgstr "請求中沒有訂閱屬性ï¼"
+
+#~ msgid "OPC almost at end-of-life."
+#~ msgstr "OPC 壽命å³å°‡è€—盡。"
+
+#~ msgid "OPC at end-of-life!"
+#~ msgstr "OPC 壽命耗盡。"
+
+#~ msgid "Out of toner!"
+#~ msgstr "碳粉已耗盡ï¼"
+
+#~ msgid "Output bin almost full."
+#~ msgstr "輸出槽將滿。"
+
+#~ msgid "Output bin full!"
+#~ msgstr "輸出槽已滿ï¼"
+
+#~ msgid "Output tray missing!"
+#~ msgstr "找ä¸åˆ°è¼¸å‡ºç´™åŒ£ï¼"
+
+#~ msgid "Printer offline."
+#~ msgstr "å°è¡¨æ©Ÿå·²é›¢ç·šã€‚"
+
+#~ msgid "SCSI Printer"
+#~ msgstr "SCSI å°è¡¨æ©Ÿ"
+
+#~ msgid "The notify-user-data value is too large (%d > 63 octets)!"
+#~ msgstr "notify-user-data 值太大(%d > 63 å…«ä½å…ƒçµ„)ï¼"
+
+#~ msgid "The printer or class is not shared!"
+#~ msgstr "未共享å°è¡¨æ©Ÿæˆ–類別ï¼"
+
+#~ msgid "The printer-uri attribute is required!"
+#~ msgstr "éœ€è¦ printer-uri 屬性ï¼"
+
+#~ msgid "Toner low."
+#~ msgstr "碳粉éŽå°‘。"
+
+#~ msgid "Too many job-sheets values (%d > 2)!"
+#~ msgstr "太多 job-sheets 值(%d > 2)ï¼"
+
+#~ msgid "Too many printer-state-reasons values (%d > %d)!"
+#~ msgstr "太多 printer-state-reasons 值(%d > %d)ï¼"
+
+#~ msgid "Unable to add job for destination \"%s\"!"
+#~ msgstr "無法為目的地“%sâ€åŠ å…¥ä½œæ¥­ï¼"
+
+#~ msgid "Unable to allocate memory for file types!"
+#~ msgstr "無法為檔案類型分é…記憶體ï¼"
+
+#~ msgid "Unable to copy 64-bit CUPS printer driver files (%d)!"
+#~ msgstr "ç„¡æ³•æ‹·è² 64 ä½å…ƒ CUPS å°è¡¨æ©Ÿé©…動程å¼æª”案(%d)ï¼"
+
+#~ msgid "Unable to copy 64-bit Windows printer driver files (%d)!"
+#~ msgstr "ç„¡æ³•æ‹·è² 64 ä½å…ƒ Windows å°è¡¨æ©Ÿé©…動程å¼æª”案(%d)ï¼"
+
+#~ msgid "Unable to copy CUPS printer driver files (%d)!"
+#~ msgstr "ç„¡æ³•æ‹·è² CUPS å°è¡¨æ©Ÿé©…動程å¼æª”案(%d)ï¼"
+
+#~ msgid "Unable to copy PPD file - %s!"
+#~ msgstr "ç„¡æ³•æ‹·è² PPD 檔案 - %sï¼"
+
+#~ msgid "Unable to copy PPD file!"
+#~ msgstr "ç„¡æ³•æ‹·è² PPD 檔案ï¼"
+
+#~ msgid "Unable to copy Windows 2000 printer driver files (%d)!"
+#~ msgstr "ç„¡æ³•æ‹·è² Windows 2000 å°è¡¨æ©Ÿé©…動程å¼æª”案(%d)ï¼"
+
+#~ msgid "Unable to copy Windows 9x printer driver files (%d)!"
+#~ msgstr "ç„¡æ³•æ‹·è² Windows 9x å°è¡¨æ©Ÿé©…動程å¼æª”案(%d)ï¼"
+
+#~ msgid "Unable to copy interface script - %s!"
+#~ msgstr "無法拷è²ä»‹é¢å·¥åºæŒ‡ä»¤ - %sï¼"
+
+#~ msgid "Unable to create printer-uri!"
+#~ msgstr "無法製作 printer-uriï¼"
+
+#~ msgid "Unable to edit cupsd.conf files larger than 1MB!"
+#~ msgstr "無法編輯大å°è¶…éŽ 1MB çš„ cupsd.conf 檔案ï¼"
+
+#~ msgid "Unable to find destination for job!"
+#~ msgstr "找ä¸åˆ°ä½œæ¥­çš„目的地ï¼"
+
+#~ msgid "Unable to find printer!\n"
+#~ msgstr "找ä¸åˆ°å°è¡¨æ©Ÿï¼\n"
+
+#~ msgid "Unable to install Windows 2000 printer driver files (%d)!"
+#~ msgstr "ç„¡æ³•å®‰è£ Windows 2000 å°è¡¨æ©Ÿé©…動程å¼æª”案(%d)ï¼"
+
+#~ msgid "Unable to install Windows 9x printer driver files (%d)!"
+#~ msgstr "ç„¡æ³•å®‰è£ Windows 9x å°è¡¨æ©Ÿé©…動程å¼æª”案(%d)ï¼"
+
+#~ msgid "Unable to open document %d in job %d!"
+#~ msgstr "無法打開文件 %d(在作業 %d 中)ï¼"
+
+#~ msgid "Unable to send command to printer driver!"
+#~ msgstr "無法將指令傳é€è‡³å°è¡¨æ©Ÿé©…動程å¼ï¼"
+
+#~ msgid "Unable to set Windows printer driver (%d)!"
+#~ msgstr "無法設定 Windows å°è¡¨æ©Ÿé©…動程å¼ï¼ˆ%d)ï¼"
+
+#~ msgid "Unable to use legacy USB class driver!\n"
+#~ msgstr "無法使用繼承的 USB 類別驅動程å¼ï¼\n"
+
+#~ msgid "Unknown printer error (%s)!"
+#~ msgstr "未知的å°è¡¨æ©ŸéŒ¯èª¤ï¼ˆ%s)ï¼"
+
+#~ msgid "Unsupported character set \"%s\"!"
+#~ msgstr "ä¸å—支æ´çš„字元集“%sâ€ï¼"
+
+#~ msgid "Unsupported compression \"%s\"!"
+#~ msgstr "ä¸å—支æ´çš„壓縮“%sâ€ï¼"
+
+#~ msgid "Unsupported compression attribute %s!"
+#~ msgstr "ä¸å—支æ´çš„壓縮屬性 %sï¼"
+
+#~ msgid "Unsupported format \"%s\"!"
+#~ msgstr "ä¸å—支æ´çš„æ ¼å¼â€œ%sâ€ï¼"
+
+#~ msgid "Unsupported format '%s'!"
+#~ msgstr "ä¸å—支æ´çš„æ ¼å¼ '%s'ï¼"
+
+#~ msgid "Unsupported format '%s/%s'!"
+#~ msgstr "ä¸å—支æ´çš„æ ¼å¼ '%s/%s'ï¼"
+
+#~ msgid ""
+#~ "Usage: convert [ options ]\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -f filename Set file to be converted (otherwise stdin)\n"
+#~ " -o filename Set file to be generated (otherwise stdout)\n"
+#~ " -i mime/type Set input MIME type (otherwise auto-typed)\n"
+#~ " -j mime/type Set output MIME type (otherwise application/pdf)\n"
+#~ " -P filename.ppd Set PPD file\n"
+#~ " -a 'name=value ...' Set option(s)\n"
+#~ " -U username Set username for job\n"
+#~ " -J title Set title\n"
+#~ " -c copies Set number of copies\n"
+#~ " -u Remove the PPD file when finished\n"
+#~ " -D Remove the input file when finished\n"
+#~ msgstr ""
+#~ "使用:convert [ options ]\n"
+#~ "\n"
+#~ "é¸é …:\n"
+#~ "\n"
+#~ " -f filename 設定è¦è½‰æ›çš„檔案(å¦å‰‡ç‚º stdin)\n"
+#~ " -o filename 設定è¦ç”¢ç”Ÿçš„檔案(å¦å‰‡ç‚º stdout)\n"
+#~ " -i mime/type 設定輸入 MIME 類型(å¦å‰‡ç‚º auto-typed)\n"
+#~ " -j mime/type 設定輸出 MIME 類型(å¦å‰‡ç‚º application/pdf)\n"
+#~ " -P filename.ppd 設定 PPD 檔案\n"
+#~ " -a 'name=value ...' 設定é¸é …\n"
+#~ " -U username 設定作業的使用者å稱\n"
+#~ " -J title 設定標題\n"
+#~ " -c copies 設定份數\n"
+#~ " -u 完æˆæ™‚移除 PPD 檔案\n"
+#~ " -D 完æˆæ™‚移除輸入檔案\n"
+
+#~ msgid ""
+#~ "Usage: cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -c cupsd.conf Set cupsd.conf file to use\n"
+#~ " -j job-id[,N] Filter file N from the specified job (default is file "
+#~ "1)\n"
+#~ " -n copies Set number of copies\n"
+#~ " -o name=value Set option(s)\n"
+#~ " -p filename.ppd Set PPD file\n"
+#~ " -t title Set title\n"
+#~ msgstr ""
+#~ "使用:cupsfilter -m mime/type [ options ] filename\n"
+#~ "\n"
+#~ "é¸é …:\n"
+#~ "\n"
+#~ " -c cupsd.conf 設定è¦ä½¿ç”¨çš„ cupsd.conf 檔案\n"
+#~ " -j job-id[,N] 從指定的作業éŽæ¿¾æª”案 N(é è¨­ç‚ºæª”案 1)\n"
+#~ " -n copies 設定份數\n"
+#~ " -o name=value 設定é¸é …\n"
+#~ " -p filename.ppd 設定 PPD 檔案\n"
+#~ " -t title 設定標題\n"
+
+#~ msgid ""
+#~ "Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "Options:\n"
+#~ "\n"
+#~ " -R root-directory Set alternate root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " Issue warnings instead of errors\n"
+#~ " -q Run silently\n"
+#~ " -r Use 'relaxed' open mode\n"
+#~ " -v Be slightly verbose\n"
+#~ " -vv Be very verbose\n"
+#~ msgstr ""
+#~ "使用:cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
+#~ " program | cupstestppd [options] -\n"
+#~ "\n"
+#~ "é¸é …:\n"
+#~ "\n"
+#~ " -R root-directory 設定替用 root\n"
+#~ " -W {all,none,constraints,defaults,duplex,filters,translations}\n"
+#~ " 發出警告而ä¸æ˜¯éŒ¯èª¤\n"
+#~ " -q éœéŸ³åŸ·è¡Œ\n"
+#~ " -r 使用 'relaxed' 打開模å¼\n"
+#~ " -v 列出明細\n"
+#~ " -vv 列出詳盡明細\n"
+
+#~ msgid "WARNING: Failed to read side-channel request!\n"
+#~ msgstr "WARNING: ç„¡æ³•è®€å– side-channel 請求ï¼\n"
+
+#~ msgid "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n"
+#~ msgstr "WARNING: 無法é€éŽ IncludeFeature 併入é¸é …“%sâ€ï¼\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with command status byte after %d "
+#~ "seconds!\n"
+#~ msgstr "WARNING: é ç«¯ä¸»æ©Ÿæœªåœ¨ %d 秒後å°æŒ‡ä»¤ç‹€æ…‹ä½å…ƒçµ„產生回應ï¼\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with control status byte after %d "
+#~ "seconds!\n"
+#~ msgstr "WARNING: é ç«¯ä¸»æ©Ÿæœªåœ¨ %d 秒後å°æŽ§åˆ¶ç‹€æ…‹ä½å…ƒçµ„產生回應ï¼\n"
+
+#~ msgid ""
+#~ "WARNING: Remote host did not respond with data status byte after %d "
+#~ "seconds!\n"
+#~ msgstr "WARNING: é ç«¯ä¸»æ©Ÿæœªåœ¨ %d 秒後å°è³‡æ–™ç‹€æ…‹ä½å…ƒçµ„產生回應ï¼\n"
+
+#~ msgid "WARNING: SCSI command timed out (%d); retrying...\n"
+#~ msgstr "WARNING: SCSI 指令逾時(%d);正在é‡è©¦â‹¯\n"
+
+#~ msgid ""
+#~ "WARNING: This document does not conform to the Adobe Document Structuring "
+#~ "Conventions and may not print correctly!\n"
+#~ msgstr "WARNING: 此文件未éµå¾ªâ€œAdobe 文件çµæ§‹æ…£ä¾‹â€ï¼Œè€Œä¸”ä¸èƒ½æ­£ç¢ºåœ°åˆ—å°ï¼\n"
+
+#~ msgid "WARNING: Unknown choice \"%s\" for option \"%s\"!\n"
+#~ msgstr "WARNING: 未知的é¸é …“%sâ€ï¼ˆé‡å°é¸é …“%sâ€ï¼‰ï¼\n"
+
+#~ msgid "WARNING: Unknown option \"%s\"!\n"
+#~ msgstr "WARNING: 未知的é¸é …“%sâ€ï¼\n"
+
+#~ msgid "WARNING: Unsupported baud rate %s!\n"
+#~ msgstr "WARNING: ä¸å—支æ´çš„傳輸速率 %sï¼\n"
+
+#~ msgid ""
+#~ "WARNING: recoverable: Network host '%s' is busy; will retry in %d "
+#~ "seconds...\n"
+#~ msgstr "WARNING: å¯å›žå¾©ï¼šç¶²è·¯ä¸»æ©Ÿ '%s' 忙碌中;%d 內將é‡è©¦â‹¯\n"
+
+#~ msgid "Warning, no Windows 2000 printer drivers are installed!"
+#~ msgstr "è­¦å‘Šï¼Œæœªå®‰è£ Windows 2000 å°è¡¨æ©Ÿé©…動程å¼ï¼"
+
+#~ msgid "cupsctl: Unknown option \"%s\"!\n"
+#~ msgstr "cupsctl:未知的é¸é …“%sâ€ï¼\n"
+
+#~ msgid "cupsctl: Unknown option \"-%c\"!\n"
+#~ msgstr "cupsctl:未知的é¸é …“-%câ€ï¼\n"
+
+#~ msgid "cupsd: Expected config filename after \"-c\" option!\n"
+#~ msgstr "cupsd:“-câ€é¸é …後é¢é æœŸç‚ºé…置檔案å稱ï¼\n"
+
+#~ msgid "cupsd: Unable to get current directory!\n"
+#~ msgstr "cupsd:無法å–å¾—ç›®å‰çš„目錄ï¼\n"
+
+#~ msgid "cupsd: Unknown argument \"%s\" - aborting!\n"
+#~ msgstr "cupsd:未知的åƒæ•¸â€œ%sâ€- 正在中止ï¼\n"
+
+#~ msgid "cupsd: Unknown option \"%c\" - aborting!\n"
+#~ msgstr "cupsd:未知的é¸é …“%câ€- 正在中止ï¼\n"
+
+#~ msgid "cupsfilter: Invalid document number %d!\n"
+#~ msgstr "cupsfilter:無效的文件編號 %dï¼\n"
+
+#~ msgid "cupsfilter: Invalid job ID %d!\n"
+#~ msgstr "cupsfilter:無效的作業 ID %dï¼\n"
+
+#~ msgid "cupsfilter: Only one filename can be specified!\n"
+#~ msgstr "cupsfilter:åªèƒ½æŒ‡å®šä¸€å€‹æª”åï¼\n"
+
+#~ msgid "cupsfilter: Unable to create temporary file: %s\n"
+#~ msgstr "cupsfilter:無法製作暫存檔:%s\n"
+
+#~ msgid "job-printer-uri attribute missing!"
+#~ msgstr "job-printer-uri 屬性éºå¤±ï¼"
+
+#~ msgid "lpadmin: Class name can only contain printable characters!\n"
+#~ msgstr "lpadmin:類別å稱åªèƒ½åŒ…å«å¯åˆ—å°çš„å­—å…ƒï¼\n"
+
+#~ msgid "lpadmin: Expected PPD after '-P' option!\n"
+#~ msgstr "lpadmin:'-P' é¸é …後é¢é æœŸç‚º PPDï¼\n"
+
+#~ msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n"
+#~ msgstr "lpadmin:&aops;-u&aops; é¸é …後é¢é æœŸç‚º allow/deny:userlistï¼\n"
+
+#~ msgid "lpadmin: Expected class after '-r' option!\n"
+#~ msgstr "lpadmin:&aops;-r&aops; é¸é …後é¢é æœŸç‚ºé¡žåˆ¥ï¼\n"
+
+#~ msgid "lpadmin: Expected class name after '-c' option!\n"
+#~ msgstr "lpadmin:&aops;-c&aops; é¸é …後é¢é æœŸç‚ºé¡žåˆ¥å稱ï¼\n"
+
+#~ msgid "lpadmin: Expected description after '-D' option!\n"
+#~ msgstr "lpadmin:&aops;-D&aops; é¸é …後é¢é æœŸç‚ºæè¿°ï¼\n"
+
+#~ msgid "lpadmin: Expected device URI after '-v' option!\n"
+#~ msgstr "lpadmin:&aops;-v&aops; é¸é …後é¢é æœŸç‚ºè¨­å‚™ URIï¼\n"
+
+#~ msgid "lpadmin: Expected file type(s) after '-I' option!\n"
+#~ msgstr "lpadmin:&aops;-I&aops; é¸é …後é¢é æœŸç‚ºæª”案類型ï¼\n"
+
+#~ msgid "lpadmin: Expected hostname after '-h' option!\n"
+#~ msgstr "lpadmin:&aops;-h&aops; é¸é …後é¢é æœŸç‚ºä¸»æ©Ÿå稱ï¼\n"
+
+#~ msgid "lpadmin: Expected interface after '-i' option!\n"
+#~ msgstr "lpadmin:&aops;-i&aops; é¸é …後é¢é æœŸç‚ºä»‹é¢ï¼\n"
+
+#~ msgid "lpadmin: Expected location after '-L' option!\n"
+#~ msgstr "lpadmin:'-L' é¸é …後é¢é æœŸç‚ºä½ç½®ï¼\n"
+
+#~ msgid "lpadmin: Expected model after '-m' option!\n"
+#~ msgstr "lpadmin:'-m' é¸é …後é¢é æœŸç‚ºåž‹è™Ÿï¼\n"
+
+#~ msgid "lpadmin: Expected name=value after '-o' option!\n"
+#~ msgstr "lpadmin:&aops;-o&aops; é¸é …後é¢é æœŸç‚º name=valueï¼\n"
+
+#~ msgid "lpadmin: Expected printer after '-p' option!\n"
+#~ msgstr "lpadmin:'-p' é¸é …後é¢é æœŸç‚ºå°è¡¨æ©Ÿï¼\n"
+
+#~ msgid "lpadmin: Expected printer name after '-d' option!\n"
+#~ msgstr "lpadmin:'-d' é¸é …後é¢é æœŸç‚ºå°è¡¨æ©Ÿå稱ï¼\n"
+
+#~ msgid "lpadmin: Expected printer or class after '-x' option!\n"
+#~ msgstr "lpadmin:'-x' é¸é …後é¢é æœŸç‚ºå°è¡¨æ©Ÿæˆ–類別ï¼\n"
+
+#~ msgid "lpadmin: No member names were seen!\n"
+#~ msgstr "lpadmin:未發ç¾æœƒå“¡å稱ï¼\n"
+
+#~ msgid "lpadmin: Printer name can only contain printable characters!\n"
+#~ msgstr "lpadmin:å°è¡¨æ©Ÿå稱åªèƒ½åŒ…å«å¯åˆ—å°çš„å­—å…ƒï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to add a printer to the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin:無法將å°è¡¨æ©ŸåŠ å…¥åˆ°é¡žåˆ¥ï¼š\n"
+#~ " 您必須ç¾æŒ‡å®šå°è¡¨æ©Ÿå稱ï¼\n"
+
+#~ msgid "lpadmin: Unable to create temporary file - %s\n"
+#~ msgstr "lpadmin:無法製作暫存檔 - %s\n"
+
+#~ msgid "lpadmin: Unable to create temporary file: %s\n"
+#~ msgstr "lpadmin:無法製作暫存檔:%s\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to remove a printer from the class:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin:無法從類別中移除å°è¡¨æ©Ÿï¼š\n"
+#~ " 您必須先指定å°è¡¨æ©Ÿå稱ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin:無法設定 PPD 檔案:\n"
+#~ " 您必須先指定å°è¡¨æ©Ÿå稱ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the device URI:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin:無法設定設備 URI:\n"
+#~ " 您必須先指定å°è¡¨æ©Ÿå稱ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script or PPD file:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin:無法設定 PPD 檔案的介é¢å·¥åºæŒ‡ä»¤ï¼š\n"
+#~ " 您必須先指定å°è¡¨æ©Ÿå稱ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the interface script:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin:無法設定介é¢å·¥åºæŒ‡ä»¤ï¼š\n"
+#~ " 您必須先指定å°è¡¨æ©Ÿå稱ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer description:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin:無法設定å°è¡¨æ©Ÿæ述:\n"
+#~ " 您必須先指定å°è¡¨æ©Ÿå稱ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer location:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin:無法設定å°è¡¨æ©Ÿä½ç½®ï¼š\n"
+#~ " 您必須先指定å°è¡¨æ©Ÿå稱ï¼\n"
+
+#~ msgid ""
+#~ "lpadmin: Unable to set the printer options:\n"
+#~ " You must specify a printer name first!\n"
+#~ msgstr ""
+#~ "lpadmin:無法設定å°è¡¨æ©Ÿé¸é …:\n"
+#~ " 您必須先指定å°è¡¨æ©Ÿå稱ï¼\n"
+
+#~ msgid "lpadmin: Unknown allow/deny option \"%s\"!\n"
+#~ msgstr "lpadmin:未知的 allow/deny é¸é …“%sâ€ï¼\n"
+
+#~ msgid "lpadmin: Unknown argument '%s'!\n"
+#~ msgstr "lpadmin:未知的åƒæ•¸ '%s'ï¼\n"
+
+#~ msgid "lpadmin: Unknown option '%c'!\n"
+#~ msgstr "lpadmin:未知的é¸é … '%c'ï¼\n"
+
+#~ msgid "lpadmin: Warning - content type list ignored!\n"
+#~ msgstr "lpadmin:警告 - 已忽略內容類型列表ï¼\n"
+
+#~ msgid "lpinfo: Expected 1284 device ID string after --device-id!\n"
+#~ msgstr "lpinfo:--device-id 後é¢é æœŸç‚º 1284 設備 ID 字串ï¼\n"
+
+#~ msgid "lpinfo: Expected language after --language!\n"
+#~ msgstr "lpinfo:--language 後é¢é æœŸç‚ºèªžè¨€ï¼\n"
+
+#~ msgid "lpinfo: Expected make and model after --make-and-model!\n"
+#~ msgstr "lpinfo:--make-and-model 後é¢é æœŸç‚ºè£½é€ å’Œåž‹è™Ÿï¼\n"
+
+#~ msgid "lpinfo: Expected product string after --product!\n"
+#~ msgstr "lpinfo:--product 後é¢é æœŸç‚ºç”¢å“字串ï¼\n"
+
+#~ msgid "lpinfo: Expected scheme list after --exclude-schemes!\n"
+#~ msgstr "lpinfo:--exclude-schemes 後é¢é æœŸç‚ºæž¶æ§‹åˆ—表ï¼\n"
+
+#~ msgid "lpinfo: Expected scheme list after --include-schemes!\n"
+#~ msgstr "lpinfo:--include-schemes 後é¢é æœŸç‚ºæž¶æ§‹åˆ—表ï¼\n"
+
+#~ msgid "lpinfo: Expected timeout after --timeout!\n"
+#~ msgstr "lpinfo:--timeout 後é¢é æœŸç‚ºé€¾æ™‚ï¼\n"
+
+#~ msgid "lpinfo: Unknown argument '%s'!\n"
+#~ msgstr "lpinfo:未知的åƒæ•¸ '%s'ï¼\n"
+
+#~ msgid "lpinfo: Unknown option '%c'!\n"
+#~ msgstr "lpinfo:未知的é¸é … '%c'ï¼\n"
+
+#~ msgid "lpinfo: Unknown option '%s'!\n"
+#~ msgstr "lpinfo:未知的é¸é … '%s'ï¼\n"
+
+#~ msgid "lpmove: Unknown argument '%s'!\n"
+#~ msgstr "lpmove:未知的åƒæ•¸ '%s'ï¼\n"
+
+#~ msgid "lpmove: Unknown option '%c'!\n"
+#~ msgstr "lpmove:未知的é¸é … '%c'ï¼\n"
+
+#~ msgid "lpoptions: No printers!?!\n"
+#~ msgstr "lpoptions:沒有å°è¡¨æ©Ÿ!?!\n"
+
+#~ msgid "lpoptions: Unable to open PPD file for %s!\n"
+#~ msgstr "lpoptions:無法打開 %s çš„ PPD 檔案ï¼\n"
+
+#~ msgid "lpoptions: Unknown printer or class!\n"
+#~ msgstr "lpoptions:未知的å°è¡¨æ©Ÿæˆ–類別ï¼\n"
+
+#~ msgid "lppasswd: Only root can add or delete passwords!\n"
+#~ msgstr "lppasswd:åªæœ‰ root 使用者æ‰èƒ½åŠ å…¥æˆ–刪除密碼ï¼\n"
+
+#~ msgid "lppasswd: Password file busy!\n"
+#~ msgstr "lppasswd:密碼檔案忙碌中ï¼\n"
+
+#~ msgid "lppasswd: Password file not updated!\n"
+#~ msgstr "lppasswd:未更新密碼檔案ï¼\n"
+
+#~ msgid "lppasswd: Sorry, password doesn't match!\n"
+#~ msgstr "lppasswd:抱歉,密碼ä¸ç›¸ç¬¦ï¼\n"
+
+#~ msgid "lppasswd: Sorry, passwords don't match!\n"
+#~ msgstr "lppasswd:抱歉,密碼ä¸ç›¸ç¬¦ï¼\n"
+
+#~ msgid ""
+#~ "lpstat: error - %s environment variable names non-existent destination \"%"
+#~ "s\"!\n"
+#~ msgstr "lpstat:錯誤 - %s 環境變數å稱中有ä¸å­˜åœ¨çš„目的地“%sâ€ï¼\n"
+
+#~ msgid "notify-events not specified!"
+#~ msgstr "未指定 notify-eventsï¼"
+
+#~ msgid "notify-recipient-uri URI \"%s\" is already used!"
+#~ msgstr "notify-recipient-uri URI“%sâ€å·²è¢«ä½¿ç”¨ï¼"
+
+#~ msgid "notify-recipient-uri URI \"%s\" uses unknown scheme!"
+#~ msgstr "notify-recipient-uri URI“%sâ€ä½¿ç”¨çš„是未知的架構ï¼"
+
+#~ msgid "notify-subscription-id %d no good!"
+#~ msgstr "notify-subscription-id %d ä¸åˆé©ï¼"
+
+#~ msgid "ppdc: Bad resolution name \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc:錯誤的解æžåº¦å稱“%1$sâ€ï¼Œåœ¨ %3$s 的第 %2$d è¡Œï¼\n"
+
+#~ msgid "ppdc: Bad status keyword %s on line %d of %s!\n"
+#~ msgstr "ppdc:錯誤的狀態關éµå­— %1$s,在 %3$s 的第 %2$d è¡Œï¼\n"
+
+#~ msgid "ppdc: Choice found on line %d of %s with no Option!\n"
+#~ msgstr "ppdc:在 %2$s 的第 %1$d 行發ç¾æ²’有“é¸é …â€çš„é¸æ“‡ï¼\n"
+
+#~ msgid "ppdc: Duplicate #po for locale %s on line %d of %s!\n"
+#~ msgstr "ppdc:環境變數 %1$s çš„ #po é‡è¤‡ï¼Œåœ¨ %3$s 的第 %2$d è¡Œï¼\n"
+
+#~ msgid "ppdc: Expected a filter definition on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰éŽæ¿¾å®šç¾©ï¼\n"
+
+#~ msgid "ppdc: Expected a program name on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰ç¨‹å¼å稱ï¼\n"
+
+#~ msgid "ppdc: Expected charset after Font on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 Font 後é¢é æœŸç‚ºå­—元集ï¼\n"
+
+#~ msgid "ppdc: Expected color order for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰ ColorModel çš„é¡è‰²é«”ç³»ï¼\n"
+
+#~ msgid "ppdc: Expected colorspace for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰ ColorModel 的色彩空間ï¼\n"
+
+#~ msgid "ppdc: Expected compression for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰ ColorModel 的壓縮度ï¼\n"
+
+#~ msgid ""
+#~ "ppdc: Expected constraints string for UIConstraints on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰ UIConstraints çš„é™åˆ¶å­—串ï¼\n"
+
+#~ msgid ""
+#~ "ppdc: Expected driver type keyword following DriverType on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc:%2$s 的第 %1$d 行上 DriverType 後é¢é æœŸæœ‰é©…動程å¼é¡žåž‹é—œéµå­—ï¼\n"
+
+#~ msgid "ppdc: Expected duplex type after Duplex on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 Duplex 後é¢é æœŸæœ‰å…©ç”¨è£ç´™åŒ£é¡žåž‹ï¼\n"
+
+#~ msgid "ppdc: Expected encoding after Font on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 Font 後é¢é æœŸç‚ºç·¨ç¢¼ï¼\n"
+
+#~ msgid "ppdc: Expected filename after #po %s on line %d of %s!\n"
+#~ msgstr "ppdc:#po %1$s 後é¢é æœŸç‚ºæª”å,在 %3$s 的第 %2$d 行上ï¼\n"
+
+#~ msgid "ppdc: Expected group name/text on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰ç¾¤çµ„å稱/文字ï¼\n"
+
+#~ msgid "ppdc: Expected include filename on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰åŒ…å«çš„檔åï¼\n"
+
+#~ msgid "ppdc: Expected integer on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰æ•´æ•¸ï¼\n"
+
+#~ msgid "ppdc: Expected locale after #po on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 #po 後é¢é æœŸæœ‰ç’°å¢ƒè®Šæ•¸ï¼\n"
+
+#~ msgid "ppdc: Expected name after %s on line %d of %s!\n"
+#~ msgstr "ppdc:%1$s 後é¢é æœŸæœ‰å稱,在 %3$s 的第 %2$d 行上ï¼\n"
+
+#~ msgid "ppdc: Expected name after FileName on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 FileName 後é¢é æœŸç‚ºå稱ï¼\n"
+
+#~ msgid "ppdc: Expected name after Font on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 Font 後é¢é æœŸç‚ºå稱ï¼\n"
+
+#~ msgid "ppdc: Expected name after Manufacturer on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 Manufacturer 後é¢é æœŸç‚ºå稱ï¼\n"
+
+#~ msgid "ppdc: Expected name after MediaSize on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 MediaSize 後é¢é æœŸç‚ºå稱ï¼\n"
+
+#~ msgid "ppdc: Expected name after ModelName on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 ModelName 後é¢é æœŸç‚ºå稱ï¼\n"
+
+#~ msgid "ppdc: Expected name after PCFileName on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 PCFileName 後é¢é æœŸç‚ºå稱ï¼\n"
+
+#~ msgid "ppdc: Expected name/text after %s on line %d of %s!\n"
+#~ msgstr "ppdc:%1$s 後é¢é æœŸç‚ºå稱/文字,在 %3$s 的第 %2$d 行上。\n"
+
+#~ msgid "ppdc: Expected name/text after Installable on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 Installable 後é¢é æœŸç‚ºå稱/文字ï¼\n"
+
+#~ msgid "ppdc: Expected name/text after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 Resolution 後é¢é æœŸç‚ºå稱/文字ï¼\n"
+
+#~ msgid ""
+#~ "ppdc: Expected name/text combination for ColorModel on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰ ColorModel çš„å稱/文字組åˆï¼\n"
+
+#~ msgid "ppdc: Expected option name/text on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰é¸é …å稱/文字ï¼\n"
+
+#~ msgid "ppdc: Expected option section on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰é¸é …部分ï¼\n"
+
+#~ msgid "ppdc: Expected option type on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰é¸é …é¡žåž‹ï¼\n"
+
+#~ msgid "ppdc: Expected override field after Resolution on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 Resolution 後é¢é æœŸæœ‰è¦†è“‹æ¬„ä½ï¼\n"
+
+#~ msgid "ppdc: Expected real number on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰å¯¦æ•¸ï¼\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following ColorProfile on line %d of %"
+#~ "s!\n"
+#~ msgstr ""
+#~ "ppdc:%2$s 的第 %1$d 行上 ColorProfile 後é¢é æœŸæœ‰è§£æžåº¦âˆ•åª’體類型ï¼\n"
+
+#~ msgid ""
+#~ "ppdc: Expected resolution/mediatype following SimpleColorProfile on line %"
+#~ "d of %s!\n"
+#~ msgstr ""
+#~ "ppdc:%2$s 的第 %1$d 行上 SimpleColorProfile 後é¢é æœŸæœ‰è§£æžåº¦âˆ•åª’體類型ï¼\n"
+
+#~ msgid "ppdc: Expected selector after %s on line %d of %s!\n"
+#~ msgstr "ppdc:%1$s 後é¢é æœŸæœ‰é¸æ“‡å™¨ï¼Œåœ¨ %3$s 的第 %2$d 行上ï¼\n"
+
+#~ msgid "ppdc: Expected status after Font on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 Font 後é¢é æœŸç‚ºç‹€æ…‹ï¼\n"
+
+#~ msgid "ppdc: Expected string after Copyright on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 Copyright 後é¢é æœŸæœ‰å­—串ï¼\n"
+
+#~ msgid "ppdc: Expected string after Version on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 Version 後é¢é æœŸæœ‰å­—串ï¼\n"
+
+#~ msgid "ppdc: Expected two option names on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上é æœŸæœ‰å…©å€‹é¸é …å稱ï¼\n"
+
+#~ msgid "ppdc: Expected value after %s on line %d of %s!\n"
+#~ msgstr "ppdc:%1$s 後é¢é æœŸæœ‰å€¼ï¼Œåœ¨ %3$s 的第 %2$d 行上ï¼\n"
+
+#~ msgid "ppdc: Expected version after Font on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上 Font 後é¢é æœŸæœ‰ç‰ˆæœ¬ï¼\n"
+
+#~ msgid "ppdc: Invalid #include/#po filename \"%s\"!\n"
+#~ msgstr "ppdc:無效的 #include/#po 檔å“%sâ€ï¼\n"
+
+#~ msgid "ppdc: Invalid cost for filter on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 第 %1$d 行上的éŽæ¿¾æˆæœ¬ç„¡æ•ˆï¼\n"
+
+#~ msgid "ppdc: Invalid empty MIME type for filter on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上用於éŽæ¿¾çš„空 MIME 類型無效ï¼\n"
+
+#~ msgid "ppdc: Invalid empty program name for filter on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行上用於éŽæ¿¾çš„空程å¼å稱無效ï¼\n"
+
+#~ msgid "ppdc: Invalid option section \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc:無效的é¸é …部分“%1$sâ€ï¼Œåœ¨ %3$s 的第 %2$d 行上ï¼\n"
+
+#~ msgid "ppdc: Invalid option type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc:無效的é¸é …類型“%1$sâ€ï¼Œåœ¨ %3$s 的第 %2$d 行上ï¼\n"
+
+#~ msgid "ppdc: Missing #endif at end of \"%s\"!\n"
+#~ msgstr "ppdc:“%sâ€æœ«ç«¯éºå¤± #endifï¼\n"
+
+#~ msgid "ppdc: Missing #if on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 的第 %1$d 行中éºå¤± #ifï¼\n"
+
+#~ msgid "ppdc: No message catalog provided for locale %s!\n"
+#~ msgstr "ppdc:沒有é‡å°ç’°å¢ƒè®Šæ•¸ %s æ供的訊æ¯ç›®éŒ„ï¼\n"
+
+#~ msgid "ppdc: Option %s redefined with a different type on line %d of %s!\n"
+#~ msgstr "ppdc:在 %3$s 的第 %2$d: 行上,以ä¸åŒçš„é¡žåž‹é‡è¤‡å®šç¾©äº†é¸é … %1$sï¼\n"
+
+#~ msgid "ppdc: Option constraint must *name on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 第 %1$d 行上的é¸é …é™åˆ¶å½¢å¼å¿…須為 *nameï¼\n"
+
+#~ msgid "ppdc: Too many nested #if's on line %d of %s!\n"
+#~ msgstr "ppdc:%2$s 第 %1$d 行上的巢狀 #if 太多ï¼\n"
+
+#~ msgid "ppdc: Unable to find #po file %s on line %d of %s!\n"
+#~ msgstr "ppdc:在下列行中找ä¸åˆ° #po 檔案 %1$s:%3$s 的第 %2$d è¡Œï¼\n"
+
+#~ msgid "ppdc: Unable to find include file \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc:在下列行中找ä¸åˆ°åŒ…å«æª”案“%1$sâ€ï¼š%3$s 的第 %2$d è¡Œï¼\n"
+
+#~ msgid "ppdc: Unknown driver type %s on line %d of %s!\n"
+#~ msgstr "ppdc:未知的驅動程å¼é¡žåž‹ %1$s,在 %3$s 的第 %2$d 行上ï¼\n"
+
+#~ msgid "ppdc: Unknown duplex type \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc:未知的兩用類型“%1$sâ€ï¼Œåœ¨ %3$s 的第 %2$d 行上ï¼\n"
+
+#~ msgid "ppdc: Unknown media size \"%s\" on line %d of %s!\n"
+#~ msgstr "ppdc:未知的媒體大å°â€œ%1$sâ€ï¼Œåœ¨ %3$s 的第 %2$d 行上ï¼\n"
+
+#~ msgid "ppdc: Unknown token \"%s\" seen on line %d of %s!\n"
+#~ msgstr "ppdc:發ç¾æœªçŸ¥çš„代號“%1$sâ€ï¼Œåœ¨ %3$s 的第 %2$d 行上ï¼\n"
+
+#~ msgid ""
+#~ "ppdc: Unknown trailing characters in real number \"%s\" on line %d of %"
+#~ "s!\n"
+#~ msgstr "ppdc:實數“%1$sâ€ä¸­æœ‰æœªçŸ¥çš„尾字元,在 %3$s 的第 %2$d 行上ï¼\n"
+
+#~ msgid "ppdc: Unterminated string starting with %c on line %d of %s!\n"
+#~ msgstr "ppdc:%3$s 的第 %2$d 行上有以 %1$c 開頭的未終止字串ï¼\n"
+
+#~ msgid "ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"
+#~ msgstr "ppdmerge:錯誤的 LanguageVersion“%sâ€ï¼Œåœ¨ %s 中ï¼\n"
diff --git a/locale/locale.txt b/locale/locale.txt
new file mode 100644
index 000000000..f9abe72d6
--- /dev/null
+++ b/locale/locale.txt
@@ -0,0 +1,32 @@
+This directory contains the message strings used by CUPS for various
+languages. Each subdirectory corresponds to a different locale, and
+the cups_xx and cups_xx_YY files contain the messages for the locales
+named "xx" or "xx_YY".
+
+Each message file starts with a character set identifier, which can be
+one of the following:
+
+ us-ascii
+ iso-8859-1
+ iso-8859-2
+ iso-8859-3
+ iso-8859-4
+ iso-8859-5
+ iso-8859-6
+ iso-8859-7
+ iso-8859-8
+ iso-8859-9
+ utf-8
+
+After that, all non-blank lines are treated as messages, with any
+leading whitespace removed. If a line starts with a number then the
+message index is updated to the number. Otherwise, the next message
+number is used.
+
+The message indices are defined in the include file <cups/language.h>.
+The HTTP status messages use the status codes defined in <cups/http.h>.
+
+If you would like to contribute a new message file for your locale, or
+have corrections to the current ones, please send them to:
+
+ cups-support@cups.org
diff --git a/locale/po2strings.c b/locale/po2strings.c
new file mode 100644
index 000000000..430ace499
--- /dev/null
+++ b/locale/po2strings.c
@@ -0,0 +1,281 @@
+/*
+ * "$Id$"
+ *
+ * Convert a GNU gettext .po file to an Apple .strings file.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Usage:
+ *
+ * po2strings filename.strings filename.po
+ *
+ * Compile with:
+ *
+ * gcc -o po2strings po2strings.c `cups-config --libs`
+ *
+ * Contents:
+ *
+ * main() - Convert .po file to .strings.
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * The .strings file format is simple:
+ *
+ * // comment
+ * "msgid" = "msgstr";
+ *
+ * The GNU gettext .po format is also fairly simple:
+ *
+ * #. comment
+ * msgid "some text"
+ * msgstr "localized text"
+ *
+ * The comment, msgid, and msgstr text can span multiple lines using the form:
+ *
+ * #. comment
+ * #. more comments
+ * msgid ""
+ * "some long text"
+ * msgstr ""
+ * "localized text spanning "
+ * "multiple lines"
+ *
+ * Both the msgid and msgstr strings use standard C quoting for special
+ * characters like newline and the double quote character.
+ */
+
+/*
+ * main() - Convert .po file to .strings.
+ */
+
+int /* O - Exit code */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ const char *pofile, /* .po filename */
+ *stringsfile; /* .strings filename */
+ cups_file_t *po, /* .po file */
+ *strings; /* .strings file */
+ char s[4096], /* String buffer */
+ *ptr, /* Pointer into buffer */
+ *temp, /* New string */
+ *msgid, /* msgid string */
+ *msgstr; /* msgstr string */
+ int length; /* Length of combined strings */
+ int use_msgid; /* Use msgid strings for msgstr? */
+
+
+ /*
+ * Process command-line arguments...
+ */
+
+ pofile = NULL;
+ stringsfile = NULL;
+ use_msgid = 0;
+
+ for (i = 1; i < argc; i ++)
+ {
+ if (!strcmp(argv[i], "-m"))
+ use_msgid = 1;
+ else if (argv[i][0] == '-')
+ {
+ puts("Usage: po2strings [-m] filename.po filename.strings");
+ return (1);
+ }
+ else if (!pofile)
+ pofile = argv[i];
+ else if (!stringsfile)
+ stringsfile = argv[i];
+ else
+ {
+ puts("Usage: po2strings [-m] filename.po filename.strings");
+ return (1);
+ }
+ }
+
+ if (!pofile || !stringsfile)
+ {
+ puts("Usage: po2strings [-m] filename.po filename.strings");
+ return (1);
+ }
+
+ /*
+ * Read strings from the .po file and write to the .strings file...
+ */
+
+ if ((po = cupsFileOpen(pofile, "r")) == NULL)
+ {
+ perror(pofile);
+ return (1);
+ }
+
+ if ((strings = cupsFileOpen(stringsfile, "w")) == NULL)
+ {
+ perror(stringsfile);
+ cupsFileClose(po);
+ return (1);
+ }
+
+ msgid = msgstr = NULL;
+
+ while (cupsFileGets(po, s, sizeof(s)) != NULL)
+ {
+ if (s[0] == '#' && s[1] == '.')
+ {
+ /*
+ * Copy comment string...
+ */
+
+ if (msgid && msgstr)
+ {
+ /*
+ * First output the last localization string...
+ */
+
+ if (*msgid)
+ cupsFilePrintf(strings, "\"%s\" = \"%s\";\n", msgid,
+ (use_msgid || !*msgstr) ? msgid : msgstr);
+
+ free(msgid);
+ free(msgstr);
+ msgid = msgstr = NULL;
+ }
+
+ cupsFilePrintf(strings, "//%s\n", s + 2);
+ }
+ else if (s[0] == '#' || !s[0])
+ {
+ /*
+ * Skip blank and file comment lines...
+ */
+
+ continue;
+ }
+ else
+ {
+ /*
+ * Strip the trailing quote...
+ */
+
+ if ((ptr = strrchr(s, '\"')) == NULL)
+ continue;
+
+ *ptr = '\0';
+
+ /*
+ * Find start of value...
+ */
+
+ if ((ptr = strchr(s, '\"')) == NULL)
+ continue;
+
+ ptr ++;
+
+ /*
+ * Create or add to a message...
+ */
+
+ if (!strncmp(s, "msgid", 5))
+ {
+ /*
+ * Output previous message as needed...
+ */
+
+ if (msgid && msgstr)
+ {
+ if (*msgid)
+ cupsFilePrintf(strings, "\"%s\" = \"%s\";\n", msgid,
+ (use_msgid || !*msgstr) ? msgid : msgstr);
+
+ free(msgid);
+ free(msgstr);
+ }
+
+ msgid = strdup(ptr);
+ msgstr = NULL;
+ }
+ else if (s[0] == '\"' )
+ {
+ /*
+ * Append to current string...
+ */
+
+ length = (int)strlen(msgstr ? msgstr : msgid);
+
+ if ((temp = realloc(msgstr ? msgstr : msgid,
+ length + strlen(ptr) + 1)) == NULL)
+ {
+ perror("Unable to allocate string");
+ return (1);
+ }
+
+ if (msgstr)
+ {
+ /*
+ * Copy the new portion to the end of the msgstr string - safe
+ * to use strcpy because the buffer is allocated to the correct
+ * size...
+ */
+
+ msgstr = temp;
+
+ strcpy(msgstr + length, ptr);
+ }
+ else
+ {
+ /*
+ * Copy the new portion to the end of the msgid string - safe
+ * to use strcpy because the buffer is allocated to the correct
+ * size...
+ */
+
+ msgid = temp;
+
+ strcpy(msgid + length, ptr);
+ }
+ }
+ else if (!strncmp(s, "msgstr", 6) && msgid)
+ {
+ /*
+ * Set the string...
+ */
+
+ if ((msgstr = strdup(ptr)) == NULL)
+ {
+ perror("Unable to allocate msgstr");
+ return (1);
+ }
+ }
+ }
+ }
+
+ if (msgid && msgstr)
+ {
+ if (*msgid)
+ cupsFilePrintf(strings, "\"%s\" = \"%s\";\n", msgid,
+ (use_msgid || !*msgstr) ? msgid : msgstr);
+
+ free(msgid);
+ free(msgstr);
+ }
+
+ cupsFileClose(po);
+ cupsFileClose(strings);
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/locale/strings2po.c b/locale/strings2po.c
new file mode 100644
index 000000000..8df9059be
--- /dev/null
+++ b/locale/strings2po.c
@@ -0,0 +1,175 @@
+/*
+ * "$Id$"
+ *
+ * Convert Apple .strings file (UTF-16 BE text file) to GNU gettext .po files.
+ *
+ * Usage:
+ *
+ * strings2po filename.strings filename.po
+ *
+ * Compile with:
+ *
+ * gcc -o strings2po strings2po.c
+ *
+ * Contents:
+ *
+ * main() - Convert .strings file to .po.
+ * read_strings() - Read a line from a .strings file.
+ * write_po() - Write a line to the .po file.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+/*
+ * The .strings file format is simple:
+ *
+ * // comment
+ * "id" = "str";
+ *
+ * Both the id and str strings use standard C quoting for special characters
+ * like newline and the double quote character.
+ */
+
+/*
+ * Local functions...
+ */
+
+static int read_strings(FILE *strings, char *buffer, size_t bufsize,
+ char **id, char **str);
+static void write_po(FILE *po, const char *what, const char *s);
+
+
+/*
+ * main() - Convert .strings file to .po.
+ */
+
+int /* O - Exit code */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ FILE *strings, /* .strings file */
+ *po; /* .po file */
+ char iconv[1024], /* iconv command */
+ buffer[8192], /* Line buffer */
+ *id, /* ID string */
+ *str; /* Translation string */
+ int count; /* Number of messages converted */
+
+
+ if (argc != 3)
+ {
+ puts("Usage: strings2po filename.strings filename.po");
+ return (1);
+ }
+
+ /*
+ * Cheat by using iconv to convert the .strings file from UTF-16 to UTF-8
+ * which is what we need for the .po file (and it makes things a lot
+ * simpler...)
+ */
+
+ snprintf(iconv, sizeof(iconv), "iconv -f utf-16 -t utf-8 '%s'", argv[1]);
+ if ((strings = popen(iconv, "r")) == NULL)
+ {
+ perror(argv[1]);
+ return (1);
+ }
+
+ if ((po = fopen(argv[2], "w")) == NULL)
+ {
+ perror(argv[2]);
+ pclose(strings);
+ return (1);
+ }
+
+ count = 0;
+
+ while (read_strings(strings, buffer, sizeof(buffer), &id, &str))
+ {
+ count ++;
+ write_po(po, "msgid", id);
+ write_po(po, "msgstr", str);
+ }
+
+ pclose(strings);
+ fclose(po);
+
+ printf("%s: %d messages.\n", argv[2], count);
+
+ return (0);
+}
+
+
+/*
+ * 'read_strings()' - Read a line from a .strings file.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+read_strings(FILE *strings, /* I - .strings file */
+ char *buffer, /* I - Line buffer */
+ size_t bufsize, /* I - Size of line buffer */
+ char **id, /* O - Pointer to ID string */
+ char **str) /* O - Pointer to translation string */
+{
+ char *bufptr; /* Pointer into buffer */
+
+
+ while (fgets(buffer, bufsize, strings))
+ {
+ if (buffer[0] != '\"')
+ continue;
+
+ *id = buffer + 1;
+
+ for (bufptr = buffer + 1; *bufptr && *bufptr != '\"'; bufptr ++)
+ if (*bufptr == '\\')
+ bufptr ++;
+
+ if (*bufptr != '\"')
+ continue;
+
+ *bufptr++ = '\0';
+
+ while (*bufptr && *bufptr != '\"')
+ bufptr ++;
+
+ if (!*bufptr)
+ continue;
+
+ bufptr ++;
+ *str = bufptr;
+
+ for (; *bufptr && *bufptr != '\"'; bufptr ++)
+ if (*bufptr == '\\')
+ bufptr ++;
+
+ if (*bufptr != '\"')
+ continue;
+
+ *bufptr = '\0';
+
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'write_po()' - Write a line to the .po file.
+ */
+
+static void
+write_po(FILE *po, /* I - .po file */
+ const char *what, /* I - Type of string */
+ const char *s) /* I - String to write */
+{
+ fprintf(po, "%s \"%s\"\n", what, s);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/locale/translate.c b/locale/translate.c
new file mode 100644
index 000000000..13228d27a
--- /dev/null
+++ b/locale/translate.c
@@ -0,0 +1,439 @@
+/*
+ * "$Id$"
+ *
+ * HTTP-based translation program for CUPS.
+ *
+ * This program uses Google to translate the CUPS template (cups.pot) to
+ * several different languages. The translation isn't perfect, but it's
+ * a start (better than working from scratch.)
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Main entry.
+ * save_messages() - Save messages to a .po file.
+ * translate_messages() - Translate messages using Google.
+ * write_string() - Write a quoted string to a file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include <unistd.h>
+
+
+/*
+ * Local functions...
+ */
+
+int save_messages(cups_array_t *cat, const char *filename);
+int translate_messages(cups_array_t *cat, const char *lang);
+int write_string(cups_file_t *fp, const char *s);
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ cups_array_t *cat; /* Message catalog */
+
+
+ if (argc != 3)
+ {
+ fputs("Usage: translate cups_language.po language\n", stderr);
+ return (1);
+ }
+
+ if (access(argv[1], 0))
+ cat = _cupsMessageLoad("cups.pot", 1);
+ else
+ cat = _cupsMessageLoad(argv[1], 1);
+
+ if (!cat)
+ {
+ puts("Unable to load message catalog.");
+ return (1);
+ }
+
+ if (!translate_messages(cat, argv[2]))
+ {
+ puts("Unable to translate message catalog.");
+ return (1);
+ }
+
+ if (!save_messages(cat, argv[1]))
+ {
+ puts("Unable to save message catalog.");
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'save_messages()' - Save messages to a .po file.
+ */
+
+int /* O - 1 on success, 0 on error */
+save_messages(cups_array_t *cat, /* I - Message catalog */
+ const char *filename) /* I - File to save to */
+{
+ _cups_message_t *m; /* Current message */
+ cups_file_t *fp; /* File pointer */
+
+
+ /*
+ * Open the message catalog...
+ */
+
+ if ((fp = cupsFileOpen(filename, "w")) == NULL)
+ return (0);
+
+ /*
+ * Save the messages to a file...
+ */
+
+ for (m = (_cups_message_t *)cupsArrayFirst(cat);
+ m;
+ m = (_cups_message_t *)cupsArrayNext(cat))
+ {
+ if (cupsFilePuts(fp, "msgid \"") < 0)
+ break;
+
+ if (!write_string(fp, m->id))
+ break;
+
+ if (cupsFilePuts(fp, "\"\nmsgstr \"") < 0)
+ break;
+
+ if (m->str)
+ {
+ if (!write_string(fp, m->str))
+ break;
+ }
+
+ if (cupsFilePuts(fp, "\"\n") < 0)
+ break;
+ }
+
+ cupsFileClose(fp);
+
+ return (!m);
+}
+
+
+/*
+ * 'translate_messages()' - Translate messages using Google.
+ */
+
+int /* O - 1 on success, 0 on error */
+translate_messages(cups_array_t *cat, /* I - Message catalog */
+ const char *lang) /* I - Output language... */
+{
+ /*
+ * Google provides a simple translation/language tool for translating
+ * from one language to another. It is far from perfect, however it
+ * can be used to get a basic translation done or update an existing
+ * translation when no other resources are available.
+ *
+ * Translation requests are sent as HTTP POSTs to
+ * "http://translate.google.com/translate_t" with the following form
+ * variables:
+ *
+ * Name Description Value
+ * -------- ---------------------------------- ----------------
+ * hl Help language? "en"
+ * ie Input encoding "UTF8"
+ * langpair Language pair "en|" + language
+ * oe Output encoding "UTF8"
+ * text Text to translate translation string
+ */
+
+ int ret; /* Return value */
+ _cups_message_t *m; /* Current message */
+ int tries; /* Number of tries... */
+ http_t *http; /* HTTP connection */
+ http_status_t status; /* Status of POST request */
+ char *idptr, /* Pointer into msgid */
+ buffer[65536], /* Input/output buffer */
+ *bufptr, /* Pointer into buffer */
+ *bufend, /* Pointer to end of buffer */
+ length[16]; /* Content length */
+ int bytes; /* Number of bytes read */
+
+
+ /*
+ * Connect to translate.google.com...
+ */
+
+ puts("Connecting to translate.google.com...");
+
+ if ((http = httpConnect("translate.google.com", 80)) == NULL)
+ {
+ perror("Unable to connect to translate.google.com");
+ return (0);
+ }
+
+ /*
+ * Scan the current messages, requesting a translation of any untranslated
+ * messages...
+ */
+
+ for (m = (_cups_message_t *)cupsArrayFirst(cat), ret = 1;
+ m;
+ m = (_cups_message_t *)cupsArrayNext(cat))
+ {
+ /*
+ * Skip messages that are already translated...
+ */
+
+ if (m->str && m->str[0])
+ continue;
+
+ /*
+ * Encode the form data into the buffer...
+ */
+
+ snprintf(buffer, sizeof(buffer),
+ "hl=en&ie=UTF8&langpair=en|%s&oe=UTF8&text=", lang);
+ bufptr = buffer + strlen(buffer);
+ bufend = buffer + sizeof(buffer) - 5;
+
+ for (idptr = m->id; *idptr && bufptr < bufend; idptr ++)
+ if (*idptr == ' ')
+ *bufptr++ = '+';
+ else if (*idptr < ' ' || *idptr == '%')
+ {
+ sprintf(bufptr, "%%%02X", *idptr & 255);
+ bufptr += 3;
+ }
+ else if (*idptr != '&')
+ *bufptr++ = *idptr;
+
+ *bufptr++ = '&';
+ *bufptr = '\0';
+
+ sprintf(length, "%d", (int)(bufptr - buffer));
+
+ /*
+ * Send the request...
+ */
+
+ printf("\"%s\" = ", m->id);
+ fflush(stdout);
+
+ tries = 0;
+
+ do
+ {
+ httpClearFields(http);
+ httpSetField(http, HTTP_FIELD_CONTENT_TYPE,
+ "application/x-www-form-urlencoded");
+ httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length);
+
+ if (httpPost(http, "/translate_t"))
+ {
+ httpReconnect(http);
+ httpPost(http, "/translate_t");
+ }
+
+ httpWrite2(http, buffer, bufptr - buffer);
+
+ while ((status = httpUpdate(http)) == HTTP_CONTINUE);
+
+ if (status != HTTP_OK && status != HTTP_ERROR)
+ httpFlush(http);
+
+ tries ++;
+ }
+ while (status == HTTP_ERROR && tries < 10);
+
+ if (status == HTTP_OK)
+ {
+ /*
+ * OK, read the translation back...
+ */
+
+ bufptr = buffer;
+ bufend = buffer + sizeof(buffer) - 1;
+
+ while ((bytes = httpRead2(http, bufptr, bufend - bufptr)) > 0)
+ bufptr += bytes;
+
+ if (bytes < 0)
+ {
+ /*
+ * Read error, abort!
+ */
+
+ puts("READ ERROR!");
+ ret = 0;
+ break;
+ }
+
+ *bufptr = '\0';
+
+ /*
+ * Find the div containing translation
+ */
+
+ if ((bufptr = strstr(buffer, "<div id=result_box")) == NULL)
+ {
+ /*
+ * No textarea, abort!
+ */
+
+ puts("NO div id=result_box!");
+ ret = 0;
+ break;
+ }
+
+ if ((bufptr = strchr(bufptr, '>')) == NULL)
+ {
+ /*
+ * textarea doesn't end, abort!
+ */
+
+ puts("DIV SHORT DATA!");
+ ret = 0;
+ break;
+ }
+
+ bufptr ++;
+
+ if ((bufend = strstr(bufptr, "</div>")) == NULL)
+ {
+ /*
+ * textarea doesn't close, abort!
+ */
+
+ puts("/DIV SHORT DATA!");
+ ret = 0;
+ break;
+ }
+
+ *bufend = '\0';
+
+ /*
+ * Copy the translation...
+ */
+
+ m->str = strdup(bufptr);
+
+ /*
+ * Convert character entities to regular chars...
+ */
+
+ for (bufptr = strchr(m->str, '&');
+ bufptr;
+ bufptr = strchr(bufptr + 1, '&'))
+ {
+ if (!strncmp(bufptr, "&lt;", 4))
+ {
+ *bufptr = '<';
+ _cups_strcpy(bufptr + 1, bufptr + 4);
+ }
+ else if (!strncmp(bufptr, "&gt;", 4))
+ {
+ *bufptr = '>';
+ _cups_strcpy(bufptr + 1, bufptr + 4);
+ }
+ else if (!strncmp(bufptr, "&amp;", 5))
+ _cups_strcpy(bufptr + 1, bufptr + 5);
+ }
+
+ printf("\"%s\"\n", m->str);
+ }
+ else if (status == HTTP_ERROR)
+ {
+ printf("NETWORK ERROR (%s)!\n", strerror(httpError(http)));
+ ret = 0;
+ break;
+ }
+ else
+ {
+ printf("HTTP ERROR %d!\n", status);
+ ret = 0;
+ break;
+ }
+ }
+
+ httpClose(http);
+
+ return (ret);
+}
+
+
+/*
+ * 'write_string()' - Write a quoted string to a file.
+ */
+
+int /* O - 1 on success, 0 on failure */
+write_string(cups_file_t *fp, /* I - File to write to */
+ const char *s) /* I - String */
+{
+ while (*s)
+ {
+ switch (*s)
+ {
+ case '\n' :
+ if (cupsFilePuts(fp, "\\n") < 0)
+ return (0);
+ break;
+
+ case '\r' :
+ if (cupsFilePuts(fp, "\\r") < 0)
+ return (0);
+ break;
+
+ case '\t' :
+ if (cupsFilePuts(fp, "\\t") < 0)
+ return (0);
+ break;
+
+ case '\\' :
+ if (cupsFilePuts(fp, "\\\\") < 0)
+ return (0);
+ break;
+
+ case '\"' :
+ if (cupsFilePuts(fp, "\\\"") < 0)
+ return (0);
+ break;
+
+ default :
+ if ((*s & 255) < ' ')
+ {
+ if (cupsFilePrintf(fp, "\\%o", *s) < 0)
+ return (0);
+ }
+ else if (cupsFilePutChar(fp, *s) < 0)
+ return (0);
+ break;
+ }
+
+ s ++;
+ }
+
+ return (1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/man/Makefile b/man/Makefile
new file mode 100644
index 000000000..ef59a1687
--- /dev/null
+++ b/man/Makefile
@@ -0,0 +1,236 @@
+#
+# "$Id$"
+#
+# Man page makefile for CUPS.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 1993-2006 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+
+#
+# Man pages...
+#
+
+MAN1 = cancel.$(MAN1EXT) \
+ cups-config.$(MAN1EXT) \
+ cupstestdsc.$(MAN1EXT) \
+ cupstestppd.$(MAN1EXT) \
+ ipptool.$(MAN1EXT) \
+ lp.$(MAN1EXT) \
+ lpoptions.$(MAN1EXT) \
+ lppasswd.$(MAN1EXT) \
+ lpq.$(MAN1EXT) \
+ lprm.$(MAN1EXT) \
+ lpr.$(MAN1EXT) \
+ lpstat.$(MAN1EXT) \
+ ppdc.$(MAN1EXT) \
+ ppdhtml.$(MAN1EXT) \
+ ppdi.$(MAN1EXT) \
+ ppdmerge.$(MAN1EXT) \
+ ppdpo.$(MAN1EXT)
+MAN5 = classes.conf.$(MAN5EXT) \
+ client.conf.$(MAN5EXT) \
+ cups-snmp.conf.$(MAN5EXT) \
+ cupsd.conf.$(MAN5EXT) \
+ ipptoolfile.$(MAN5EXT) \
+ mailto.conf.$(MAN5EXT) \
+ mime.convs.$(MAN5EXT) \
+ mime.types.$(MAN5EXT) \
+ ppdcfile.$(MAN5EXT) \
+ printers.conf.$(MAN5EXT) \
+ subscriptions.conf.$(MAN5EXT)
+MAN7 = backend.$(MAN7EXT) \
+ filter.$(MAN7EXT) \
+ notifier.$(MAN7EXT)
+MAN8 = cupsaccept.$(MAN8EXT) \
+ cupsaddsmb.$(MAN8EXT) \
+ cupsctl.$(MAN8EXT) \
+ cupsfilter.$(MAN8EXT) \
+ cups-deviced.$(MAN8EXT) \
+ cups-driverd.$(MAN8EXT) \
+ cups-lpd.$(MAN8EXT) \
+ cups-polld.$(MAN8EXT) \
+ cupsd.$(MAN8EXT) \
+ cupsenable.$(MAN8EXT) \
+ lpadmin.$(MAN8EXT) \
+ lpinfo.$(MAN8EXT) \
+ lpmove.$(MAN8EXT) \
+ lpc.$(MAN8EXT)
+
+
+#
+# Make everything...
+#
+
+all: $(MAN1) $(MAN5) $(MAN7) $(MAN8) html
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Clean all config and object files...
+#
+
+clean:
+ $(RM) mantohtml mantohtml.o
+ $(RM) $(MAN1) $(MAN5) $(MAN7) $(MAN8)
+ for file in $(MAN1); do \
+ $(RM) ../doc/help/man-`basename $$file .$(MAN1EXT)`.html; \
+ done
+ for file in $(MAN5); do \
+ $(RM) ../doc/help/man-`basename $$file .$(MAN5EXT)`.html; \
+ done
+ for file in $(MAN7); do \
+ $(RM) ../doc/help/man-`basename $$file .$(MAN7EXT)`.html; \
+ done
+ for file in $(MAN8); do \
+ $(RM) ../doc/help/man-`basename $$file .$(MAN8EXT)`.html; \
+ done
+
+
+#
+# Dummy depend target...
+#
+
+depend:
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data: all
+ $(INSTALL_DIR) -m 755 $(MANDIR)/man1
+ for file in $(MAN1); do \
+ echo Installing $$file in $(MANDIR)/man1...; \
+ $(INSTALL_MAN) $$file $(MANDIR)/man1; \
+ done
+ $(INSTALL_DIR) -m 755 $(MANDIR)/man5
+ for file in $(MAN5); do \
+ echo Installing $$file in $(MANDIR)/man5...; \
+ $(INSTALL_MAN) $$file $(MANDIR)/man5; \
+ done
+ $(INSTALL_DIR) -m 755 $(MANDIR)/man7
+ for file in $(MAN7); do \
+ echo Installing $$file in $(MANDIR)/man7...; \
+ $(INSTALL_MAN) $$file $(MANDIR)/man7; \
+ done
+ $(INSTALL_DIR) -m 755 $(AMANDIR)/man$(MAN8DIR)
+ for file in $(MAN8); do \
+ echo Installing $$file in $(AMANDIR)/man$(MAN8DIR)...; \
+ $(INSTALL_MAN) $$file $(AMANDIR)/man$(MAN8DIR); \
+ done
+ for file in accept cupsreject reject; do \
+ $(RM) $(AMANDIR)/man$(MAN8DIR)/$$file.$(MAN8EXT); \
+ $(LN) cupsaccept.$(MAN8EXT) $(AMANDIR)/man$(MAN8DIR)/$$file.$(MAN8EXT); \
+ done
+ $(RM) $(AMANDIR)/man$(MAN8DIR)/cupsdisable.$(MAN8EXT)
+ $(LN) cupsenable.$(MAN8EXT) $(AMANDIR)/man$(MAN8DIR)/cupsdisable.$(MAN8EXT)
+
+
+#
+# Install programs...
+#
+
+install-exec:
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall files...
+#
+
+uninstall:
+ for file in $(MAN1); do \
+ $(RM) $(MANDIR)/man1/$$file; \
+ done
+ -$(RMDIR) $(MANDIR)/man1
+ for file in $(MAN5); do \
+ $(RM) $(MANDIR)/man5/$$file; \
+ done
+ -$(RMDIR) $(MANDIR)/man5
+ for file in $(MAN7); do \
+ $(RM) $(MANDIR)/man7/$$file; \
+ done
+ -$(RMDIR) $(MANDIR)/man7
+ for file in $(MAN8); do \
+ $(RM) $(AMANDIR)/man$(MAN8DIR)/$$file; \
+ done
+ $(RM) $(AMANDIR)/man$(MAN8DIR)/accept.$(MAN8EXT)
+ $(RM) $(AMANDIR)/man$(MAN8DIR)/cupsreject.$(MAN8EXT)
+ $(RM) $(AMANDIR)/man$(MAN8DIR)/reject.$(MAN8EXT)
+ $(RM) $(AMANDIR)/man$(MAN8DIR)/cupsdisable.$(MAN8EXT)
+ -$(RMDIR) $(AMANDIR)/man$(MAN8DIR)
+
+
+#
+# Make html versions of man pages...
+#
+
+html: $(MAN1) $(MAN5) $(MAN7) $(MAN8) mantohtml
+ echo Converting man pages to HTML...
+ for file in $(MAN1); do \
+ echo " $$file..."; \
+ ./mantohtml `basename $$file .$(MAN1EXT)`.man >../doc/help/man-`basename $$file .$(MAN1EXT)`.html; \
+ done
+ for file in $(MAN5); do \
+ echo " $$file..."; \
+ ./mantohtml `basename $$file .$(MAN5EXT)`.man >../doc/help/man-`basename $$file .$(MAN5EXT)`.html; \
+ done
+ for file in $(MAN7); do \
+ echo " $$file..."; \
+ ./mantohtml `basename $$file .$(MAN7EXT)`.man >../doc/help/man-`basename $$file .$(MAN7EXT)`.html; \
+ done
+ for file in $(MAN8); do \
+ echo " $$file..."; \
+ ./mantohtml `basename $$file .$(MAN8EXT)`.man >../doc/help/man-`basename $$file .$(MAN8EXT)`.html; \
+ done
+
+mantohtml: mantohtml.o
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ mantohtml.o
+
+
+#
+# End of "$Id$".
+#
diff --git a/man/backend.man b/man/backend.man
new file mode 100644
index 000000000..644d85dd4
--- /dev/null
+++ b/man/backend.man
@@ -0,0 +1,196 @@
+.\"
+.\" "$Id: backend.man 9693 2011-04-16 02:51:22Z mike $"
+.\"
+.\" Backend man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH backend 7 "CUPS" "15 April 2011" "Apple Inc."
+
+.SH NAME
+backend \- cups backend transmission interfaces
+
+.SH SYNOPSIS
+.B backend
+.br
+.B backend
+job user title num-copies options [
+.I filename
+]
+
+.SH DESCRIPTION
+Backends are a special type of \fIfilter(7)\fR which is used to
+send print data to and discover different devices on the system.
+
+.LP
+Like filters, backends must be capable of reading from a filename
+on the command-line or from the standard input, copying the
+standard input to a temporary file as required by the physical
+interface.
+
+.LP
+The command name (argv[0]) is set to the device URI of the destination printer.
+Starting with CUPS 1.1.22, any authentication information in argv[0] is removed,
+so backend developers are urged to use the DEVICE_URI environment variable
+whenever authentication information is required. The CUPS API includes a
+\fIcupsBackendDeviceURI\fR function for retrieving the correct device URI.
+
+.LP
+Back-channel data from the device should be relayed to the job
+filters by writing to file descriptor 3. The CUPS API includes
+the \fIcupsBackChannelWrite\fR function for this purpose.
+
+.SH DEVICE DISCOVERY
+When run with no arguments, the backend should list the devices
+and schemes it supports or is advertising to stdout. The output
+consists of zero or more lines consisting of any of the following
+forms:
+
+.nf
+ device-class scheme "Unknown" "device-info"
+ device-class device-uri "device-make-and-model" "device-info"
+ device-class device-uri "device-make-and-model" "device-info" "device-id"
+ device-class device-uri "device-make-and-model" "device-info" "device-id" "device-location"
+.fi
+
+.LP
+The \fIdevice-class\fR field is one of the following values:
+
+.TP 5
+direct
+.br
+The device-uri refers to a specific direct-access device with no
+options, such as a parallel, USB, or SCSI device.
+
+.TP 5
+file
+.br
+The device-uri refers to a file on disk.
+
+.TP 5
+network
+.br
+The device-uri refers to a networked device and conforms to the
+general form for network URIs.
+
+.TP 5
+serial
+.br
+The device-uri refers to a serial device with configurable baud
+rate and other options. If the device-uri contains a baud value,
+it represents the maximum baud rate supported by the device.
+
+.LP
+The \fIscheme\fR field provides the URI scheme that is supported
+by the backend. Backends should use this form only when the
+backend supports any URI using that scheme. The \fIdevice-uri\fR
+field specifies the full URI to use when communicating with the
+device.
+
+.LP
+The \fIdevice-make-and-model\fR field specifies the make and
+model of the device, e.g. "Acme Foojet 2000". If the make and
+model is not known, you must report "Unknown".
+
+.LP
+The \fIdevice-info\fR field specifies additional information
+about the device. Typically this includes the make and model
+along with the port number or network address, e.g. "Acme Foojet
+2000 USB #1".
+
+.LP
+The optional \fIdevice-id\fR field specifies the IEEE-1284 device
+ID string for the device, which is used to select a matching
+driver.
+
+.LP
+The optional \fIdevice-location\fR field specifies the physical location of
+the device, which is often used to pre-populate the printer-location attribute
+when adding a printer.
+
+.SH PERMISSIONS
+Backends without world execute permissions are run as the root
+user. Otherwise, the backend is run using the unprivileged user
+account, typically "lp".
+
+.SH EXIT CODES
+The following exit codes are defined for backends; C API
+constants defined in the <cups/backend.h> header file are defined
+in parenthesis:
+
+.TP 5
+0 (CUPS_BACKEND_OK)
+.br
+The print file was successfully transmitted to the device or
+remote server.
+
+.TP 5
+1 (CUPS_BACKEND_FAILED)
+.br
+The print file was not successfully transmitted to the device or
+remote server. The scheduler will respond to this by canceling
+the job, retrying the job, or stopping the queue depending on the
+state of the error-policy attribute.
+
+.TP 5
+2 (CUPS_BACKEND_AUTH_REQUIRED)
+.br
+The print file was not successfully transmitted because valid
+authentication information is required. The scheduler will
+respond to this by holding the job and adding the
+authentication-required job-reasons keyword.
+
+.TP 5
+3 (CUPS_BACKEND_HOLD)
+.br
+The print file was not successfully transmitted because it cannot
+be printed at this time. The scheduler will respond to this by
+holding the job.
+
+.TP 5
+4 (CUPS_BACKEND_STOP)
+.br
+The print file was not successfully transmitted because it cannot
+be printed at this time. The scheduler will respond to this by
+stopping the queue.
+
+.TP 5
+5 (CUPS_BACKEND_CANCEL)
+.br
+The print file was not successfully transmitted because one or
+more attributes are not supported. The scheduler will respond to
+this by canceling the job.
+
+.TP 5
+6 (CUPS_BACKEND_RETRY)
+.br
+The print file was not successfully transmitted because of a temporary issue.
+The scheduler will retry the job at a future time - other jobs may print before
+this one.
+
+.TP 5
+7 (CUPS_BACKEND_RETRY_CURRENT)
+.br
+The print file was not successfully transmitted because of a temporary issue.
+The scheduler will retry the job immediately without allowing intervening jobs.
+
+.PP
+All other exit code values are reserved.
+
+.SH SEE ALSO
+\fIcupsd(8)\fR, \fIcupsd.conf(5)\fR, \fIfilter(7)\fR,
+.br
+http://localhost:631/help
+
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: backend.man 9693 2011-04-16 02:51:22Z mike $".
+.\"
diff --git a/man/cancel.man b/man/cancel.man
new file mode 100644
index 000000000..eda61eb1f
--- /dev/null
+++ b/man/cancel.man
@@ -0,0 +1,75 @@
+.\"
+.\" "$Id: cancel.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" cancel man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cancel 1 "CUPS" "20 March 2006" "Apple Inc."
+.SH NAME
+cancel - cancel jobs
+.SH SYNOPSIS
+.B cancel
+[ -E ] [ -U
+.I username
+] [ -a ] [ -h
+.I hostname[:port]
+] [ -u
+.I username
+] [
+.I id
+] [
+.I destination
+] [
+.I destination-id
+]
+.SH DESCRIPTION
+\fIcancel\fR cancels existing print jobs. The \fI-a\fR option will remove
+all jobs from the specified destination.
+.SH OPTIONS
+The following options are recognized by \fIcancel\fR:
+.TP 5
+-E
+.br
+Forces encryption when connecting to the server.
+.TP 5
+-U username
+.br
+Specifies the username to use when connecting to the server.
+.TP 5
+-a
+.br
+Cancel all jobs on the named destination, or all jobs on all
+destinations if none is provided.
+.TP 5
+-h hostname[:port]
+.br
+Chooses an alternate server.
+.TP 5
+-u username
+.br
+Cancels jobs owned by \fIusername\fR.
+.SH COMPATIBILITY
+Unlike the System V printing system, CUPS allows printer names to
+contain any printable character except SPACE, TAB, "/", or "#".
+Also, printer and class names are \fInot\fR case-sensitive.
+.SH NOTES
+Administrators wishing to prevent unauthorized cancellation of
+jobs via the \fI-u\fR option should require authentication for
+Cancel-Jobs operations in \fIcupsd.conf(5)\fR.
+.SH SEE ALSO
+\fIlp(1)\fR, \fIlpmove(8)\fR, \fIlpstat(1)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: cancel.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/classes.conf.man b/man/classes.conf.man
new file mode 100644
index 000000000..0664442d4
--- /dev/null
+++ b/man/classes.conf.man
@@ -0,0 +1,110 @@
+.\"
+.\" "$Id: classes.conf.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" classes.conf man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH classes.conf 5 "CUPS" "29 April 2009" "Apple Inc."
+.SH NAME
+classes.conf \- class configuration file for cups
+.SH DESCRIPTION
+The \fIclasses.conf\fR file defines the local printer classes that are
+available. It is normally located in the \fI/etc/cups\fR directory and
+is generated automatically by the \fIcupsd(8)\fR program when printer
+classes are added or deleted.
+.LP
+Each line in the file can be a configuration directive, a blank line,
+or a comment. Comment lines start with the # character.
+.SH DIRECTIVES
+.TP 5
+<Class name> ... </Class>
+.br
+Defines a specific printer class.
+.TP 5
+<DefaultClass name> ... </Class>
+.br
+Defines a default printer class.
+.TP 5
+Accepting Yes
+.TP 5
+Accepting No
+.br
+Specifies whether the printer is accepting new jobs.
+.TP 5
+AllowUser [ user @group ... ]
+.br
+Allows specific users and groups to print to the printer.
+.TP 5
+DenyUser [ user @group ... ]
+.br
+Prevents specific users and groups from printing to the printer.
+.TP 5
+Info text
+.br
+Specifies human-readable text describing the printer.
+.TP 5
+JobSheets banner banner
+.br
+Specifies the banner pages to use for the printer.
+.TP 5
+KLimit number
+.br
+Specifies the job-k-limit value for the printer.
+.TP 5
+Location text
+.br
+Specifies human-readable text describing the location of the printer.
+.TP 5
+OpPolicy name
+.br
+Specifies the operation policy for the printer.
+.TP 5
+PageLimit number
+.br
+Specifies the job-page-limit value for the printer.
+.TP 5
+Printer
+.br
+Specifies a printer that is a member of the printer class.
+.TP 5
+QuotaPeriod seconds
+.br
+Specifies the job-quota-period value for the printer.
+.TP 5
+Shared Yes
+.TP 5
+Shared No
+.br
+Specifies whether the printer is shared.
+.TP 5
+State idle
+.TP 5
+State stopped
+.br
+Specifies the initial state of the printer (Idle or Stopped)
+.TP 5
+StateMessage text
+.br
+Specifies the message associated with the state.
+.TP 5
+StateTime seconds
+.br
+Specifies the date/time associated with the state.
+.SH SEE ALSO
+\fIcupsd(8)\fR, \fIcupsd.conf(5)\fR, \fImime.convs(5)\fR,
+\fImime.types(5)\fR, \fIprinters.conf(5)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: classes.conf.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/client.conf.man.in b/man/client.conf.man.in
new file mode 100644
index 000000000..abcf3bcab
--- /dev/null
+++ b/man/client.conf.man.in
@@ -0,0 +1,55 @@
+.\"
+.\" "$Id$"
+.\"
+.\" client.conf man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH client.conf 5 "CUPS" "28 March 2011" "Apple Inc."
+.SH NAME
+client.conf \- client configuration file for cups
+.SH DESCRIPTION
+The \fIclient.conf\fR file configures the CUPS client and is
+normally located in the \fI@CUPS_SERVERROOT@\fR or \fI~/.cups\fR
+directory. Each line in the file can be a configuration
+directive, a blank line, or a comment. Comment lines start with
+the # character.
+.SH DIRECTIVES
+The following directives are understood by the client. Consult the
+on-line help for detailed descriptions:
+.TP 5
+Encryption IfRequested
+.TP 5
+Encryption Never
+.TP 5
+Encryption Required
+.br
+Specifies the level of encryption that is required for a particular
+location.
+.TP 5
+GSSServiceName name
+Specifies the Kerberos service name that is used for authentication, typically
+"host", "http", or "ipp". CUPS adds the remote hostname
+("name@server.example.com") for you. The default name is
+"@CUPS_DEFAULT_GSSSERVICENAME@".
+.TP 5
+ServerName hostname-or-ip-address[:port]
+.TP 5
+ServerName /domain/socket
+.br
+Specifies the address and optionally the port to use when connecting to the
+server.
+.SH SEE ALSO
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id$".
+.\"
diff --git a/man/cups-config.man b/man/cups-config.man
new file mode 100644
index 000000000..577dd44ff
--- /dev/null
+++ b/man/cups-config.man
@@ -0,0 +1,117 @@
+.\"
+.\" "$Id: cups-config.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" cups-config man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cups-config 1 "CUPS" "23 October 2008" "Apple Inc."
+.SH NAME
+cups-config \- get cups api, compiler, directory, and link information.
+.SH SYNOPSIS
+.B cups-config
+--api-version
+.br
+.B cups-config
+--build
+.br
+.B cups-config
+--cflags
+.br
+.B cups-config
+--datadir
+.br
+.B cups-config
+--help
+.br
+.B cups-config
+--ldflags
+.br
+.B cups-config
+[
+.I --image
+] [
+.I --static
+] --libs
+.br
+.B cups-config
+--serverbin
+.br
+.B cups-config
+--serverroot
+.br
+.B cups-config
+--version
+.br
+.SH DESCRIPTION
+\fBcups-config\fR is the CUPS program configuration utility. It should be
+used by application developers to determine the necessary command-line
+options for the compiler and linker, as well as determining installation
+directories for filters, configuration files, and drivers.
+.SH OPTIONS
+.TP 5
+--api-version
+.br
+Displays the current API version (major.minor).
+.TP 5
+--build
+.br
+Displays a system-specific build number.
+.TP 5
+--cflags
+.br
+Displays the necessary compiler options.
+.TP 5
+--datadir
+.br
+Displays the default CUPS data directory.
+.TP 5
+--help
+.br
+Displays the program usage message.
+.TP 5
+--image
+.br
+When used with \fI--libs\fR, adds the CUPS imaging library to the
+list of displayed libraries.
+.TP 5
+--ldflags
+.br
+Displays the necessary linker options.
+.TP 5
+--libs
+.br
+Displays the necessary librarys to link to.
+.TP 5
+--serverbin
+.br
+Displays the default CUPS binary directory,
+where filters and backends are stored.
+.TP 5
+--serverroot
+.br
+Displays the default CUPS configuration file directory.
+.TP 5
+--static
+.br
+When used with \fI--libs\fR, shows the static libraries instead
+of the default (shared) libraries.
+.TP 5
+--version
+.br
+Displays the full version number of the CUPS installation
+(major.minor.patch).
+.SH SEE ALSO
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: cups-config.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/cups-deviced.man.in b/man/cups-deviced.man.in
new file mode 100644
index 000000000..7e410bc4c
--- /dev/null
+++ b/man/cups-deviced.man.in
@@ -0,0 +1,44 @@
+.\"
+.\" "$Id$"
+.\"
+.\" cups-deviced man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cups-deviced 8 "CUPS" "16 June 2008" "Apple Inc."
+.SH NAME
+cups-deviced \- cups device daemon
+.SH SYNOPSIS
+.B cups-deviced
+.I request-id limit user-id options
+.SH DESCRIPTION
+\fIcups-deviced\fR polls the backends in
+\fI@CUPS_SERVERBIN@/backend\fR for a list of available devices.
+It is run by \fIcupsd(8)\fR in response to a
+\fICUPS-Get-Devices\fR request. The output format is an IPP
+response message. The \fIrequest-id\fR argument is the request ID
+from the original IPP request, typically 1. The \fIlimit\fR
+argument is the limit value from the original IPP request - 0
+means no limit. The \fIuser-id\fR argument is the
+requesting-user-name value from the original IPP request.
+Finally, the \fIoptions\fR argument is a space-delimited list of
+attributes ("name=value name=value \...") that were passed in
+with the request. Currently \fIcups-deviced\fR looks for the
+\fIrequested-attributes\fR attribute and tailors the output
+accordingly.
+.SH SEE ALSO
+backend(7), cupsd(8), cupsd.conf(5),
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id$".
+.\"
diff --git a/man/cups-driverd.man.in b/man/cups-driverd.man.in
new file mode 100644
index 000000000..ddef4ae4b
--- /dev/null
+++ b/man/cups-driverd.man.in
@@ -0,0 +1,122 @@
+.\"
+.\" "$Id$"
+.\"
+.\" cups-driverd man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cups-driverd 8 "CUPS" "6 January 2011" "Apple Inc."
+.SH NAME
+cups-driverd \- cups driver daemon
+.SH SYNOPSIS
+.B cups-driverd
+cat
+.I ppd-name
+.br
+.B cups-driverd
+list
+.I request_id limit options
+.SH DESCRIPTION
+\fIcups-driverd\fR shows or lists PPD files. It is run in
+response to CUPS-Add-Modify-Printer or CUPS-Get-Devices requests.
+The first form ("cups-driverd cat ppd-name") writes the named PPD
+file to stdout. The output format is an uncompressed PPD file.
+.LP
+The second form lists the available manufacturers or PPD files to
+stdout as indicated by the \fIoptions\fR argument. The output
+format is an IPP response message. The \fIrequest_id\fR argument
+is the request ID from the original IPP request, typically 1. The
+\fIlimit\fR argument is the limit value from the original IPP
+request - 0 means no limit. Finally, the \fIoptions\fR argument
+is a space-delimited list of attributes ("name=value name=value
+\&...") that were passed in with the request. Currently
+\fIcups-driverd\fR looks for the \fIppd-make\fR and
+\fIrequested-attributes\fR attributes and tailors the output
+accordingly.
+.SH DRIVERS
+Drivers can be static PPD files under the
+\fI@CUPS_DATADIR@/model\fR directory or programs under the
+\fI@CUPS_SERVERBIN@/driver\fR directory. Static PPD files must
+conform to the Adobe PPD File Format Specification version 4.3
+and may be compressed using the \fIgzip(1)\fR program. Driver
+programs must implement the command-line interface shown in the
+next section.
+.SS DRIVER PROGRAMS
+Driver programs provide a interface to dynamically-generated PPD
+files. The following arguments are currently defined:
+.TP 5
+drivername list
+.br
+Lists the supported PPD files to stdout.
+.TP 5
+drivername cat ppdname
+.br
+Writes the named PPD file to stdout.
+.PP
+Driver programs MUST NOT query hardware or make other long-term operations that
+would delay the return of a driver list. See the NOTES section below for
+specific recommendations.
+.SS LISTING FILES (drivername list)
+When run with the single argument "list", the program must list
+the available PPD files it can generate to stdout using the
+following format:
+.nf
+ "drivername:ppdname" language "make" "make and model"
+ "drivername:ppdname" language "make" "make and model" "1284 device id"
+ "drivername:ppdname" language "make" "make and model" "1284 device id" "(PPD product)"
+ "drivername:ppdname" language "make" "make and model" "1284 device id" "(PPD product)" "PostScript version"
+ "drivername:ppdname" language "make" "make and model" "1284 device id" "(PPD product)" "PostScript version" "type"
+.fi
+.LP
+\fIDrivername\fR is the name of the driver program. \fIPpdname\fR
+is the name used to select the given driver. \fILanguage\fR is
+the locale associated with the default language of the PPD file,
+typically "en". \fIMake\fR is the Manufacturer name from the PPD
+file. \fIMake and model\fR is the NickName name from the PPD
+file. \fI1284 device id\fR is the 1284DeviceId from the PPD file,
+if any. \fI(PPD product)\fR is the Product string as it would appear in the PPD
+file or from a PostScript query. \fIPostScript version\fR is the PSVersion
+string as it would appear in the PPD file or from a PostScript query. \fIType\fR
+is "postscript" for PostScript printers, "pdf" for PDF printers, "raster" for
+raster printers, or "fax" for facsimile devices.
+.SS WRITING FILES (drivername cat ppdname)
+When the driver program is run with the "cat ppdname" arguments,
+it must write the named PPD file to stdout, uncompressed. If the
+named PPD file does not exist, the driver program must not write
+any output to stdout and report the error to stderr instead.
+.SS DRIVER ERROR MESSAGES
+Error messages can be relayed back to \fIcupsd\fR by writing them
+to stderr. The following prefixes are recognized:
+.TP 5
+DEBUG: [drivername]
+.br
+Debugging messages
+.TP 5
+ERROR: [drivername]
+.br
+Error messages
+.TP 5
+INFO: [drivername]
+.br
+Informational messages
+.SH NOTES
+Due to performance considerations, driver programs have been officially
+deprecated and should not be used for new development. Currently only the
+CUPS web interface and \fIlpinfo(8)\fR command will request lists from all
+driver programs.
+.SH SEE ALSO
+cupsd(8), cupsd.conf(5), cupstestppd(1), lpinfo(8),
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id$".
+.\"
diff --git a/man/cups-lpd.man.in b/man/cups-lpd.man.in
new file mode 100644
index 000000000..e24571251
--- /dev/null
+++ b/man/cups-lpd.man.in
@@ -0,0 +1,124 @@
+.\"
+.\" "$Id$"
+.\"
+.\" cups-lpd man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cups-lpd 8 "CUPS" "4 August 2008" "Apple Inc."
+.SH NAME
+cups-lpd \- receive print jobs and report printer status to lpd clients
+.SH SYNOPSIS
+.B cups-lpd
+[ -h
+.I hostname[:port]
+] [ -n ] [ -o
+.I option=value
+]
+.SH DESCRIPTION
+\fIcups-lpd\fR is the CUPS Line Printer Daemon ("LPD")
+mini-server that supports legacy client systems that use the LPD
+protocol. \fIcups-lpd\fR does not act as a standalone network
+daemon but instead operates using the Internet "super-server"
+\fIinetd(8)\fR or \fIxinetd(8)\fR. If you are using \fIinetd\fR,
+add the following line to the \fIinetd.conf\fR file to enable the
+\fIcups-lpd\fR mini-server:
+.br
+.nf
+
+ printer stream tcp nowait lp @CUPS_SERVERBIN@/daemon/cups-lpd cups-lpd \\
+ -o document-format=application/octet-stream
+.fi
+.LP
+.LP
+\fBNote:\fR If you are using Solaris 10 or higher, you must run
+the \fIinetdconv(1m)\fR program to register the changes to the
+inetd.conf file.
+.LP
+If you are using the newer \fIxinetd(8)\fR daemon, create a file
+named \fI/etc/xinetd.d/cups\fR containing the following lines:
+.br
+.nf
+
+ service printer
+ {
+ socket_type = stream
+ protocol = tcp
+ wait = no
+ user = lp
+ group = sys
+ passenv =
+ server = @CUPS_SERVERBIN@/daemon/cups-lpd
+ server_args = -o document-format=application/octet-stream
+ }
+.fi
+.SH OPTIONS
+.TP 5
+-h hostname[:port]
+.br
+Sets the CUPS server (and port) to use.
+.TP 5
+-n
+.br
+Disables reverse address lookups; normally \fIcups-lpd\fR will
+try to discover the hostname of the client via a reverse DNS
+lookup.
+.TP 5
+-o name=value
+.br
+Inserts options for all print queues. Most often this is used to
+disable the "l" filter so that remote print jobs are filtered as
+needed for printing; the examples in the previous section set the
+"document-format" option to "application/octet-stream" which
+forces autodetection of the print file format.
+.SH PERFORMANCE
+\fIcups-lpd\fR performs well with small numbers of clients and
+printers. However, since a new process is created for each
+connection and since each process must query the printing system
+before each job submission, it does not scale to larger
+configurations. We highly recommend that large configurations
+use the native IPP support provided by CUPS instead.
+.SH SECURITY
+\fIcups-lpd\fR currently does not perform any access control
+based on the settings in \fIcupsd.conf(5)\fR or in the
+\fIhosts.allow(5)\fR or \fIhosts.deny(5)\fR files used by TCP
+wrappers. Therefore, running \fIcups-lpd\fR on your server will
+allow any computer on your network (and perhaps the entire
+Internet) to print to your server.
+.LP
+While \fIxinetd\fR has built-in access control support, you
+should use the TCP wrappers package with \fIinetd\fR to limit
+access to only those computers that should be able to print
+through your server.
+.LP
+\fIcups-lpd\fR is not enabled by the standard CUPS distribution.
+Please consult with your operating system vendor to determine
+whether it is enabled on your system.
+.SH COMPATIBILITY
+\fIcups-lpd\fR does not enforce the restricted source port
+number specified in RFC 1179, as using restricted ports does not
+prevent users from submitting print jobs. While this behavior is
+different than standard Berkeley LPD implementations, it should
+not affect normal client operations.
+.LP
+The output of the status requests follows RFC 2569, Mapping
+between LPD and IPP Protocols. Since many LPD implementations
+stray from this definition, remote status reporting to LPD
+clients may be unreliable.
+.SH SEE ALSO
+\fIcups(1)\fR, \fIcupsd(8)\fR, \fIinetconv(1m)\fR,
+\fIinetd(8)\fR, \fIxinetd(8)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id$".
+.\"
diff --git a/man/cups-polld.man b/man/cups-polld.man
new file mode 100644
index 000000000..aee706873
--- /dev/null
+++ b/man/cups-polld.man
@@ -0,0 +1,38 @@
+.\"
+.\" "$Id: cups-polld.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" cups-polld man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cups-polld 8 "CUPS" "12 February 2006" "Apple Inc."
+.SH NAME
+cups-polld \- cups printer polling daemon
+.SH SYNOPSIS
+.B cups-polld
+.I address ipp-port interval browse-port
+.SH DESCRIPTION
+\fIcups-polld\fR polls remote servers for a list of available
+printers and printer classes every \fIinterval\fR seconds.
+Printer and class information is then broadcast to the localhost
+interface (127.0.0.1) on the specified browse port for reception
+by \fIcupsd(8)\fR.
+.PP
+This program is started automatically by \fIcupsd\fR for every
+\fIBrowsePoll\fR directive found in the \fIcupsd.conf(5)\fR file.
+.SH SEE ALSO
+\fIcupsd(8)\fR, \fIcupsd.conf(5)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: cups-polld.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/cups-snmp.conf.man b/man/cups-snmp.conf.man
new file mode 100644
index 000000000..1c778bc84
--- /dev/null
+++ b/man/cups-snmp.conf.man
@@ -0,0 +1,73 @@
+.\"
+.\" "$Id: cups-snmp.conf.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" snmp.conf man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH snmp.conf 5 "CUPS" "31 July 2006" "Apple Inc."
+.SH NAME
+snmp.conf \- snmp configuration file for cups
+.SH DESCRIPTION
+The \fIsnmp.conf\fR file configures the CUPS SNMP printer
+discovery backend and is normally located in the \fI/etc/cups\fR
+directory. Each line in the file can be a configuration
+directive, a blank line, or a comment. Comment lines start with
+the # character.
+.LP
+The SNMP backend uses the SNMPv1 protocol to discover network
+printers, collecting information from the Host MIB along with
+intelligent port probes to determine the correct device URI and
+make and model for each printer. Future versions of CUPS will
+likely support the new Port Monitor MIB as well.
+.SH DIRECTIVES
+The following directives are understood by the SNMP backend.
+Consult the on-line help for detailed descriptions:
+.TP 5
+Address @IF(\fIname\fR)
+.TP 5
+Address @LOCAL
+.TP 5
+Address \fIaddress\fR
+.br
+Sends SNMP broadcast queries to the specified address(es). The
+default address is "@LOCAL" which broadcasts to all LAN
+interfaces.
+.TP 5
+Community \fIname\fR
+.br
+Specifies a SNMP community to query. The default community is
+"public".
+.TP 5
+DebugLevel \fIN\fR
+.br
+Sets the debug logging level to \fIN\fR; 0 disables debug
+logging, 1 enables basic logging, 2 displays SNMP values, and 3
+displays raw hex data.
+.TP 5
+HostNameLookups on
+.TP 5
+HostNameLookups off
+.br
+Specifies whether the addresses of printers should be converted
+to hostnames or left as numeric IP addresses. The default is
+"off".
+.TP 5
+MaxRunTime \fIseconds\fR
+.br
+Specifies the maximum number of seconds that the SNMP backend
+will scan the network for printers.
+.SH SEE ALSO
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: cups-snmp.conf.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/cupsaccept.man b/man/cupsaccept.man
new file mode 100644
index 000000000..7c53d862e
--- /dev/null
+++ b/man/cupsaccept.man
@@ -0,0 +1,79 @@
+.\"
+.\" "$Id: cupsaccept.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" accept/reject man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cupsaccept 8 "CUPS" "12 February 2006" "Apple Inc."
+.SH NAME
+cupsaccept/cupsreject \- accept/reject jobs sent to a destination
+.SH SYNOPSIS
+.B cupsaccept
+[ -E ] [ -U
+.I username
+] [ -h
+.I hostname[:port]
+] destination(s)
+.br
+.B cupsreject
+[ -E ] [ -U
+.I username
+] [ -h
+.I hostname[:port]
+] [ -r
+.I reason
+] destination(s)
+.SH DESCRIPTION
+\fIcupsaccept\fR instructs the printing system to accept print jobs to the
+specified destinations.
+.LP
+\fIcupsreject\fR instructs the printing system to reject print jobs to the
+specified destinations. The \fI-r\fR option sets the reason for rejecting
+print jobs. If not specified the reason defaults to "Reason Unknown".
+.SH OPTIONS
+The following options are supported by both \fIcupsaccept\fR and
+\fIcupsreject\fR:
+.TP 5
+-E
+.br
+Forces encryption when connecting to the server.
+.TP 5
+-U username
+.br
+Sets the username that is sent when connecting to the server.
+.TP 5
+-h hostname[:port]
+.br
+Chooses an alternate server.
+.TP 5
+-r "reason"
+.br
+Sets the reason string that is shown for a printer that is
+rejecting jobs.
+.SH COMPATIBILITY
+Unlike the System V printing system, CUPS allows printer names to
+contain any printable character except SPACE, TAB, "/", or "#".
+Also, printer and class names are \fInot\fR case-sensitive.
+.LP
+The CUPS versions of \fIaccept\fR and \fIreject\fR may ask the
+user for an access password depending on the printing system
+configuration. This differs from the System V versions which
+require the root user to execute these commands.
+.SH SEE ALSO
+\fIcancel(1)\fR, \fIcupsenable(8)\fR, \fIlp(1)\fR,
+\fIlpadmin(8)\fR, \fIlpstat(1)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: cupsaccept.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/cupsaddsmb.man.in b/man/cupsaddsmb.man.in
new file mode 100644
index 000000000..dc02cedb8
--- /dev/null
+++ b/man/cupsaddsmb.man.in
@@ -0,0 +1,214 @@
+.\"
+.\" "$Id$"
+.\"
+.\" cupsaddsmb man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cupsaddsmb 8 "CUPS" "25 July 2007" "Apple Inc."
+.SH NAME
+cupsaddsmb \- export printers to samba for windows clients
+
+.SH SYNOPSIS
+.B cupsaddsmb
+[ -H
+.I samba-server
+] [ -U
+.I samba-user[%samba-password]
+] [ -h
+.I cups-server[:port]
+] [ -v ] -a
+.br
+.B cupsaddsmb
+[ -H
+.I samba-server
+] [ -U
+.I samba-user[%samba-password]
+] [ -h
+.I cups-server[:port]
+] [ -v ] printer [ ... printer ]
+
+.SH DESCRIPTION
+\fIcupsaddsmb\fR exports printers to the SAMBA software (version
+2.2.0 or higher) for use with Windows clients. Depending on the
+SAMBA configuration, you may need to provide a password to
+export the printers. This program requires the Windows printer
+driver files described below.
+
+.SH OPTIONS
+\fIcupsaddsmb\fR supports the following options:
+.TP 5
+-H samba-server
+.br
+Specifies the SAMBA server which defaults to the CUPS server.
+.TP 5
+-U samba-user[%samba-password]
+.br
+Specifies the SAMBA print admin username which defaults to your
+current username. If the username contains a percent (%)
+character, then the text following the percent is treated as the
+SAMBA password to use.
+.TP 5
+-a
+.br
+Exports all known printers. Otherwise only the named printers are
+exported.
+.TP 5
+-h cups-server[:port]
+.br
+Specifies a different CUPS server to use.
+.TP 5
+-v
+.br
+Specifies that verbose information should be shown. This is
+useful for debugging SAMBA configuration problems.
+
+.SH SAMBA CONFIGURATION
+\fIcupsaddsmb\fR uses the new RPC-based printing support in
+SAMBA 2.2.x to provide printer drivers and PPD files to Windows
+client machines. In order to use this functionality, you must
+first configure the SAMBA \fIsmb.conf(5)\fR file to support
+printing through CUPS and provide a printer driver download
+share, as follows:
+.nf
+
+ [global]
+ load printers = yes
+ printing = cups
+ printcap name = cups
+
+ [printers]
+ comment = All Printers
+ path = /var/spool/samba
+ browseable = no
+ public = yes
+ guest ok = yes
+ writable = no
+ printable = yes
+
+ [print$]
+ comment = Printer Drivers
+ path = /etc/samba/drivers
+ browseable = yes
+ guest ok = no
+ read only = yes
+ write list = root
+.fi
+.LP
+This configuration assumes a FHS-compliant installation of
+SAMBA; adjust the [printers] and [print$] share paths
+accordingly on your system as needed.
+
+.SH MICROSOFT POSTSCRIPT DRIVERS FOR WINDOWS
+The base driver for Windows 2000 and higher is the Microsoft
+PostScript driver, which is available on any system running
+Windows 2000 or higher in the
+%WINDIR%\\SYSTEM32\\SPOOL\\DRIVERS\\W32X86\\3 folder for 32-bit
+drivers and
+%WINDIR%\\SYSTEM32\\SPOOL\\DRIVERS\\X64\\3 folder for 64-bit
+drivers.
+.LP
+The CUPS printer driver is preferred over the Microsoft driver
+since it supports the page-label, job-billing, and
+job-hold-until options fully on all printers. However, currently
+only Windows 2000 and higher is supported by the Microsoft
+driver, so you will also need to get the Adobe driver to support
+Windows 95, 98, and Me clients. The Adobe and Microsoft drivers
+for Windows 2000 are identical.
+.LP
+Once you have extracted the driver files, copy the 32-bit drivers
+to the \fI@CUPS_DATADIR@/drivers\fR directory and the 64-bit
+drivers to the \fI@CUPS_DATADIR@/drivers/x64\fR directory exactly
+as named below:
+.nf
+
+ [Windows 2000 and higher]
+ ps5ui.dll
+ pscript.hlp
+ pscript.ntf
+ pscript5.dll
+.fi
+.LP
+\fBNote:\fR Unlike Windows, case is significant - make sure that
+you use the lowercase filenames shown above, otherwise
+\fIcupsaddsmb\fR will fail to export the drivers.
+
+.SH CUPS POSTSCRIPT DRIVERS FOR WINDOWS
+\fIcupsaddsmb\fR can use the CUPS v6 PostScript printer driver
+for Windows, which is available for download from the CUPS web
+site.
+.LP
+The CUPS printer driver is preferred over the Adobe and
+Microsoft drivers since it supports the page-label, job-billing,
+and job-hold-until options fully on all printers. However,
+currently only Windows 2000 and higher is supported by the CUPS
+driver, so you will also need to get the Adobe driver to support
+Windows 95, 98, and Me clients.
+.LP
+Once you have extracted the driver files, copy the 32-bit drivers
+to the \fI@CUPS_DATADIR@/drivers\fR directory and the 64-bit
+drivers to the \fI@CUPS_DATADIR@/drivers/x64\fR directory exactly
+as named below:
+.nf
+
+ [Windows 2000 and higher]
+ cups6.inf (from www.cups.org)
+ cups6.ini (from www.cups.org)
+ cupsps6.dll (from www.cups.org)
+ cupsui6.dll (from www.cups.org)
+ ps5ui.dll (from your Windows system)
+ pscript.hlp (from your Windows system)
+ pscript.ntf (from your Windows system)
+ pscript5.dll (from your Windows system)
+.fi
+.LP
+\fBNote:\fR Unlike Windows, case is significant - make sure that
+you use the lowercase filenames shown above, otherwise
+\fIcupsaddsmb\fR will fail to export the drivers.
+
+.SH ADOBE POSTSCRIPT DRIVERS FOR WINDOWS 95, 98, AND ME
+\fIcupsaddsmb\fR can use the Adobe PostScript printer driver for
+Windows 95, 98, and ME, which are available for download from the
+Adobe web site (http://www.adobe.com).
+.LP
+The Adobe driver does not support the page-label, job-billing, or
+job-hold-until options.
+.LP
+Once you have installed the driver on a Windows system, copy the
+following files to the \fI@CUPS_DATADIR@/drivers\fR directory
+exactly as named below:
+.nf
+
+ [Windows 95, 98, and Me]
+ ADFONTS.MFM
+ ADOBEPS4.DRV
+ ADOBEPS4.HLP
+ ICONLIB.DLL
+ PSMON.DLL
+.fi
+.LP
+\fBNote:\fR Unlike Windows, case is significant - make sure that
+you use the UPPERCASE filenames shown above, otherwise
+\fIcupsaddsmb\fR will fail to export the drivers.
+
+.SH KNOWN ISSUES
+Getting the full set of Windows driver files should be easier.
+
+.SH SEE ALSO
+\fIsmbd(8)\fR, \fIsmb.conf(5)\fR,
+http://localhost:631/help
+.br
+http://www.cups.org/windows/
+
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id$".
+.\"
diff --git a/man/cupsctl.man b/man/cupsctl.man
new file mode 100644
index 000000000..411ada83f
--- /dev/null
+++ b/man/cupsctl.man
@@ -0,0 +1,107 @@
+.\"
+.\" "$Id: cupsctl.man 9457 2011-01-11 03:04:04Z mike $"
+.\"
+.\" cupsctl man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 2007 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cupsctl 8 "CUPS" "10 January 2011" "Apple Inc."
+.SH NAME
+cupsctl \- configure cupsd.conf options
+.SH SYNOPSIS
+.B cupsctl
+[ -E ] [-U
+.I username
+] [ -h
+.I server[:port]
+] [ --[no-]debug-logging ] [ --[no-]remote-admin ] [ --[no-]remote-any ]
+[ --[no-]remote-printers ] [ --[no-]share-printers ] [ --[no-]user-cancel-any ]
+[
+.I name=value
+]
+.SH DESCRIPTION
+\fIcupsctl\fR updates or queries the \fBcupsd.conf\fR file for a server. When
+no changes are requested, the current configuration values are written to the
+standard output in the format "name=value", one per line.
+.SH OPTIONS
+The following options are recognized:
+.TP 5
+-E
+.br
+Enables encryption on the connection to the scheduler.
+.TP 5
+-U \fIusername\fR
+.br
+Specifies an alternate username to use when authenticating with the scheduler.
+.TP 5
+-h \fIserver[:port]\fR
+.br
+Specifies the server address.
+.TP 5
+--[no-]debug-logging
+.br
+Enables or disables debug logging in the \fBerror_log\fR file.
+.TP 5
+--[no-]remote-admin
+.br
+Enables or disables remote administration.
+.TP 5
+--[no-]remote-any
+.br
+Enables or disables printing from any address, e.g. the Internet.
+.TP 5
+--[no-]remote-printers
+.br
+Enables or disables the display of remote printers shared via the CUPS, LDAP,
+or SLP protocols.
+.TP 5
+--[no-]share-printers
+.br
+Enables or disables sharing of local printers with other computers.
+.TP 5
+--[no-]user-cancel-any
+.br
+Allows or prevents users from canceling jobs owned by others.
+.SH EXAMPLES
+Display the current settings:
+.nf
+ cupsctl
+.fi
+.LP
+Enable debug logging:
+.nf
+ cupsctl --debug-logging
+.fi
+.LP
+Get the current debug logging state:
+.nf
+ cupsctl | grep '^_debug_logging' | awk -F= '{print $2}'
+.fi
+.LP
+Disable printer sharing:
+.nf
+ cupsctl --no-shared-printers
+.fi
+.LP
+Enable printing using the file: pseudo-device:
+.nf
+ cupsctl FileDevice=Yes
+.fi
+.SH KNOWN ISSUES
+You cannot set the Listen or Port directives using \fIcupsctl\fR.
+.SH SEE ALSO
+\fIcupsd.conf(5)\fR, \fIcupsd(8)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: cupsctl.man 9457 2011-01-11 03:04:04Z mike $".
+.\"
diff --git a/man/cupsd.conf.man.in b/man/cupsd.conf.man.in
new file mode 100644
index 000000000..d3e2d6334
--- /dev/null
+++ b/man/cupsd.conf.man.in
@@ -0,0 +1,762 @@
+.\"
+.\" "$Id$"
+.\"
+.\" cupsd.conf man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cupsd.conf 5 "CUPS" "18 May 2011" "Apple Inc."
+.SH NAME
+cupsd.conf \- server configuration file for cups
+.SH DESCRIPTION
+The \fIcupsd.conf\fR file configures the CUPS scheduler, \fIcupsd(8)\fR. It
+is normally located in the \fI@CUPS_SERVERROOT@\fR directory.
+.LP
+Each line in the file can be a configuration directive, a blank line,
+or a comment. Comment lines start with the # character. The
+configuration directives are intentionally similar to those used by the
+popular Apache web server software and are described below.
+.SH DIRECTIVES
+The following directives are understood by \fIcupsd(8)\fR. Consult the
+on-line help for detailed descriptions:
+.TP 5
+AccessLog filename
+.TP 5
+AccessLog syslog
+.br
+Defines the access log filename.
+.TP 5
+AccessLogLevel config
+.TP 5
+AccessLogLevel actions
+.TP 5
+AccessLogLevel all
+.br
+Specifies the logging level for the AccessLog file.
+.TP 5
+Allow all
+.TP 5
+Allow none
+.TP 5
+Allow host.domain.com
+.TP 5
+Allow *.domain.com
+.TP 5
+Allow ip-address
+.TP 5
+Allow ip-address/netmask
+.TP 5
+Allow ip-address/mm
+.TP 5
+Allow @IF(name)
+.TP 5
+Allow @LOCAL
+.br
+Allows access from the named hosts or addresses.
+.TP 5
+AuthClass User
+.TP 5
+AuthClass Group
+.TP 5
+AuthClass System
+.br
+Specifies the authentication class (User, Group, System) -
+\fBthis directive is deprecated\fR.
+.TP 5
+AuthGroupName group-name
+.br
+Specifies the authentication group - \fBthis directive is
+deprecated\fR.
+.TP 5
+AuthType None
+.TP 5
+AuthType Basic
+.TP 5
+AuthType BasicDigest
+.TP 5
+AuthType Digest
+.TP 5
+AuthType Negotiate
+.br
+Specifies the authentication type (None, Basic, BasicDigest, Digest, Negotiate)
+.TP 5
+AutoPurgeJobs Yes
+.TP 5
+AutoPurgeJobs No
+.br
+Specifies whether to purge job history data automatically when
+it is no longer required for quotas.
+.TP 5
+BrowseAddress ip-address
+.TP 5
+BrowseAddress @IF(name)
+.TP 5
+BrowseAddress @LOCAL
+.br
+Specifies a broadcast address for outgoing printer information packets.
+.TP 5
+BrowseAllow all
+.TP 5
+BrowseAllow none
+.TP 5
+BrowseAllow host.domain.com
+.TP 5
+BrowseAllow *.domain.com
+.TP 5
+BrowseAllow ip-address
+.TP 5
+BrowseAllow ip-address/netmask
+.TP 5
+BrowseAllow ip-address/mm
+.TP 5
+BrowseAllow @IF(name)
+.TP 5
+BrowseAllow @LOCAL
+.br
+Allows incoming printer information packets from the named host or address.
+.TP 5
+BrowseDeny all
+.TP 5
+BrowseDeny none
+.TP 5
+BrowseDeny host.domain.com
+.TP 5
+BrowseDeny *.domain.com
+.TP 5
+BrowseDeny ip-address
+.TP 5
+BrowseDeny ip-address/netmask
+.TP 5
+BrowseDeny ip-address/mm
+.TP 5
+BrowseDeny @IF(name)
+.TP 5
+BrowseDeny @LOCAL
+.br
+Denies incoming printer information packets from the named host or address.
+.TP 5
+BrowseInterval seconds
+.br
+Specifies the maximum interval between printer information broadcasts.
+.TP 5
+BrowseLDAPBindDN
+.br
+Specifies the LDAP domain name to use when registering printers.
+.TP 5
+BrowseLDAPCACertFile
+.br
+Specifies the SSL certificate authority file to use.
+.TP 5
+BrowseLDAPDN
+.br
+Specifies the LDAP domain name to use when discovering printers.
+.TP 5
+BrowseLDAPPassword
+.br
+Specifies the password to use when accessing the LDAP server.
+.TP 5
+BrowseLDAPServer
+.br
+Specifies the LDAP server to use.
+.TP 5
+BrowseOrder allow,deny
+.TP 5
+BrowseOrder deny,allow
+.br
+Specifies the order of printer information access control (allow,deny or deny,allow)
+.TP 5
+BrowsePoll host-or-ip-address
+.br
+Specifies a server to poll for printer information.
+.TP 5
+BrowsePort port
+.br
+Specifies the port to listen to for printer information packets.
+.TP 5
+BrowseProtocols [All] [CUPS] [DNSSD] [LDAP] [SLP]
+.br
+Specifies the protocols to use for printer browsing.
+.TP 5
+BrowseLocalProtocols [All] [CUPS] [DNSSD] [LDAP] [SLP]
+.br
+Specifies the protocols to use for local printer browsing.
+.TP 5
+BrowseRemoteProtocols [All] [CUPS] [DNSSD] [LDAP] [SLP]
+.br
+Specifies the protocols to use for remote printer browsing.
+.TP 5
+BrowseRelay from-address to-address
+.br
+Specifies that printer information packets should be relayed from one host or
+network to another.
+.TP 5
+BrowseShortNames Yes
+.TP 5
+BrowseShortNames No
+.br
+Specifies whether remote printers will use short names ("printer") or not
+("printer@server"). This option is ignored if more than one remote printer
+exists with the same name.
+.TP 5
+BrowseTimeout seconds
+.br
+Specifies the maximum interval between printer information updates before
+remote printers will be removed from the list of available printers.
+.TP 5
+BrowseWebIF Yes
+.TP 5
+BrowseWebIF No
+.br
+Specifies whether the CUPS web interface is advertised via DNS-SD.
+.TP 5
+Browsing Yes
+.TP 5
+Browsing No
+.br
+Specifies whether or not remote printer browsing should be enabled.
+.TP 5
+Classification banner
+.br
+Specifies the security classification of the server.
+.TP 5
+ClassifyOverride Yes
+.TP 5
+ClassifyOverride No
+.br
+Specifies whether to allow users to override the classification
+of individual print jobs.
+.TP 5
+ConfigFilePerm mode
+.br
+Specifies the permissions for all configuration files that the scheduler
+writes.
+.TP 5
+DataDir path
+.br
+Specified the directory where data files can be found.
+.TP 5
+DefaultAuthType Basic
+.TP 5
+DefaultAuthType BasicDigest
+.TP 5
+DefaultAuthType Digest
+.TP 5
+DefaultAuthType Negotiate
+.br
+Specifies the default type of authentication to use.
+.TP 5
+DefaultEncryption Never
+.TP 5
+DefaultEncryption IfRequested
+.TP 5
+DefaultEncryption Required
+.br
+Specifies the type of encryption to use for authenticated requests.
+.TP 5
+DefaultLanguage locale
+.br
+Specifies the default language to use for text and web content.
+.TP 5
+DefaultPaperSize Auto
+.TP 5
+DefaultPaperSize None
+.TP 5
+DefaultPaperSize sizename
+.br
+Specifies the default paper size for new print queues. "Auto" uses a locale-
+specific default, while "None" specifies there is no default paper size.
+.TP 5
+DefaultPolicy policy-name
+.br
+Specifies the default access policy to use.
+.TP 5
+DefaultShared Yes
+.TP 5
+DefaultShared No
+.br
+Specifies whether local printers are shared by default.
+.TP 5
+Deny all
+.TP 5
+Deny none
+.TP 5
+Deny host.domain.com
+.TP 5
+Deny *.domain.com
+.TP 5
+Deny ip-address
+.TP 5
+Deny ip-address/netmask
+.TP 5
+Deny ip-address/mm
+.TP 5
+Deny @IF(name)
+.TP 5
+Deny @LOCAL
+.br
+Denies access to the named host or address.
+.TP 5
+DirtyCleanInterval seconds
+.br
+Specifies the delay for updating of configuration and state files. A value of 0
+causes the update to happen as soon as possible, typically within a few
+milliseconds.
+.TP 5
+DocumentRoot directory
+.br
+Specifies the root directory for the internal web server documents.
+.TP 5
+Encryption IfRequested
+.TP 5
+Encryption Never
+.TP 5
+Encryption Required
+.br
+Specifies the level of encryption that is required for a particular
+location.
+.TP 5
+ErrorLog filename
+.TP 5
+ErrorLog syslog
+.br
+Specifies the error log filename.
+.TP 5
+FatalErrors none
+.TP 5
+FatalErrors all -kind [... -kind]
+.TP 5
+FatalErrors kind [... kind]
+.br
+Specifies which errors are fatal, causing the scheduler to exit. "Kind" is
+"browse", "config", "listen", "log", or "permissions".
+.TP 5
+FileDevice Yes
+.TP 5
+FileDevice No
+.br
+Specifies whether the file pseudo-device can be used for new
+printer queues.
+.TP 5
+FilterLimit limit
+.br
+Specifies the maximum cost of filters that are run concurrently.
+.TP 5
+FilterNice nice-value
+.br
+Specifies the scheduling priority ("nice" value) of filters that
+are run to print a job.
+.TP 5
+FontPath directory[:directory:...]
+.br
+Specifies the search path for fonts.
+.TP 5
+Group group-name-or-number
+.br
+Specifies the group name or ID that will be used when executing
+external programs.
+.TP 5
+HideImplicitMembers Yes
+.TP 5
+HideImplicitMembers No
+.br
+Specifies whether to hide members of implicit classes.
+.TP 5
+HostNameLookups On
+.TP 5
+HostNameLookups Off
+.TP 5
+HostNameLookups Double
+.br
+Specifies whether or not to do reverse lookups on client addresses.
+.TP 5
+ImplicitAnyClasses Yes
+.TP 5
+ImplicitAnyClasses No
+.br
+Specifies whether or not to create implicit classes for local and
+remote printers, e.g. "AnyPrinter" from "Printer", "Printer@server1",
+and "Printer@server2".
+.TP 5
+ImplicitClasses Yes
+.TP 5
+ImplicitClasses No
+.br
+Specifies whether or not to create implicit classes from identical
+remote printers.
+.TP 5
+Include filename
+.br
+Includes the named file.
+.TP 5
+JobKillDelay seconds
+.br
+Specifies the number of seconds to wait before killing the filters and backend
+associated with a canceled or held job.
+.TP 5
+JobPrivateAccess all
+.TP 5
+JobPrivateAccess default
+.TP 5
+JobPrivateAccess {user|@group|@ACL|@OWNER|@SYSTEM}+
+.br
+Specifies an access list for a job's private values. The "default" access list
+is "@OWNER @SYSTEM". "@ACL" maps to the printer's requesting-user-name-allowed
+or requesting-user-name-denied values.
+.TP 5
+JobPrivateValues all
+.TP 5
+JobPrivateValues default
+.TP 5
+JobPrivateValues none
+.TP 5
+JobPrivateValues attribute-name-1 [ ... attribute-name-N ]
+Specifies the list of job values to make private. The "default" values are
+"job-name", "job-originating-host-name", and "job-originating-user-name".
+.TP 5
+JobRetryInterval seconds
+.br
+Specifies the interval between retries of jobs in seconds.
+.TP 5
+JobRetryLimit count
+.br
+Specifies the number of retries that are done for jobs.
+.TP 5
+KeepAlive Yes
+.TP 5
+KeepAlive No
+.br
+Specifies whether to support HTTP keep-alive connections.
+.TP 5
+KeepAliveTimeout seconds
+.br
+Specifies the amount of time that connections are kept alive.
+.TP 5
+<Limit operations> ... </Limit>
+.br
+Specifies the IPP operations that are being limited inside a policy.
+.TP 5
+<Limit methods> ... </Limit>
+.TP 5
+<LimitExcept methods> ... </LimitExcept>
+.br
+Specifies the HTTP methods that are being limited inside a location.
+.TP 5
+LimitRequestBody
+.br
+Specifies the maximum size of any print job request.
+.TP 5
+Listen ip-address:port
+.TP 5
+Listen *:port
+.TP 5
+Listen /path/to/domain/socket
+.br
+Listens to the specified address and port or domain socket path.
+.TP 5
+<Location /path> ... </Location>
+.br
+Specifies access control for the named location.
+.TP 5
+LogDebugHistory #-messages
+.br
+Specifies the number of debugging messages that are logged when an error
+occurs in a print job.
+.TP 5
+LogFilePerm mode
+.br
+Specifies the permissions for all log files that the scheduler writes.
+.TP 5
+LogLevel alert
+.TP 5
+LogLevel crit
+.TP 5
+LogLevel debug2
+.TP 5
+LogLevel debug
+.TP 5
+LogLevel emerg
+.TP 5
+LogLevel error
+.TP 5
+LogLevel info
+.TP 5
+LogLevel none
+.TP 5
+LogLevel notice
+.TP 5
+LogLevel warn
+.br
+Specifies the logging level for the ErrorLog file.
+.TP 5
+LogTimeFormat standard
+.TP 5
+LogTimeFormat usecs
+.br
+Specifies the format of the date and time in the log files.
+.TP 5
+MaxClients number
+.br
+Specifies the maximum number of simultaneous clients to support.
+.TP 5
+MaxClientsPerHost number
+.br
+Specifies the maximum number of simultaneous clients to support from a
+single address.
+.TP 5
+MaxCopies number
+.br
+Specifies the maximum number of copies that a user can print of each job.
+.TP 5
+MaxJobs number
+.br
+Specifies the maximum number of simultaneous jobs to support.
+.TP 5
+MaxJobsPerPrinter number
+.br
+Specifies the maximum number of simultaneous jobs per printer to support.
+.TP 5
+MaxJobsPerUser number
+.br
+Specifies the maximum number of simultaneous jobs per user to support.
+.TP 5
+MaxLogSize number-bytes
+.br
+Specifies the maximum size of the log files before they are
+rotated (0 to disable rotation)
+.TP 5
+MaxRequestSize number-bytes
+.br
+Specifies the maximum request/file size in bytes (0 for no limit)
+.TP 5
+MultipleOperationTimeout seconds
+.br
+Specifies the maximum amount of time to allow between files in a multiple file
+print job.
+.TP 5
+Order allow,deny
+.TP 5
+Order deny,allow
+.br
+Specifies the order of HTTP access control (allow,deny or deny,allow)
+.TP 5
+PageLog filename
+.TP 5
+PageLog syslog
+.br
+Specifies the page log filename.
+.TP 5
+PageLogFormat format string
+.br
+Specifies the format of page log lines.
+.TP 5
+PassEnv variable [... variable]
+.br
+Passes the specified environment variable(s) to child processes.
+.TP 5
+<Policy name> ... </Policy>
+.br
+Specifies access control for the named policy.
+.TP 5
+Port number
+.br
+Specifies a port number to listen to for HTTP requests.
+.TP 5
+PreserveJobFiles Yes
+.TP 5
+PreserveJobFiles No
+.br
+Specifies whether or not to preserve job files after they are printed.
+.TP 5
+PreserveJobHistory Yes
+.TP 5
+PreserveJobHistory No
+.br
+Specifies whether or not to preserve the job history after they are
+printed.
+.TP 5
+Printcap
+.TP 5
+Printcap filename
+.br
+Specifies the filename for a printcap file that is updated
+automatically with a list of available printers (needed for
+legacy applications); specifying Printcap with no filename
+disables printcap generation.
+.TP 5
+PrintcapFormat bsd
+.TP 5
+PrintcapFormat plist
+.TP 5
+PrintcapFormat solaris
+.br
+Specifies the format of the printcap file.
+.TP 5
+PrintcapGUI
+.TP 5
+PrintcapGUI gui-program-filename
+.br
+Specifies whether to generate option panel definition files on
+some operating systems. When provided with no program filename,
+disables option panel definition files.
+.TP 5
+ReloadTimeout seconds
+.br
+Specifies the amount of time to wait for job completion before
+restarting the scheduler.
+.TP 5
+RemoteRoot user-name
+.br
+Specifies the username that is associated with unauthenticated root
+accesses.
+.TP 5
+RequestRoot directory
+.br
+Specifies the directory to store print jobs and other HTTP request
+data.
+.TP 5
+Require group group-name-list
+.TP 5
+Require user user-name-list
+.TP 5
+Require valid-user
+.br
+Specifies that user or group authentication is required.
+.TP 5
+RIPCache bytes
+.br
+Specifies the maximum amount of memory to use when converting images
+and PostScript files to bitmaps for a printer.
+.TP 5
+Satisfy all
+.TP 5
+Satisfy any
+.br
+Specifies whether all or any limits set for a Location must be
+satisfied to allow access.
+.TP 5
+ServerAdmin user@domain.com
+.br
+Specifies the email address of the server administrator.
+.TP 5
+ServerAlias hostname [... hostname]
+.TP 5
+ServerAlias *
+.br
+Specifies an alternate name that the server is known by. The special name "*"
+allows any name to be used.
+.TP 5
+ServerBin directory
+.br
+Specifies the directory where backends, CGIs, daemons, and filters may
+be found.
+.TP 5
+ServerCertificate filename
+.br
+Specifies the encryption certificate to use.
+.TP 5
+ServerKey filename
+.br
+Specifies the encryption key to use.
+.TP 5
+ServerName hostname-or-ip-address
+.br
+Specifies the fully-qualified hostname of the server.
+.TP 5
+ServerRoot directory
+.br
+Specifies the directory where the server configuration files can be found.
+.TP 5
+ServerTokens Full
+.TP 5
+ServerTokens Major
+.TP 5
+ServerTokens Minimal
+.TP 5
+ServerTokens Minor
+.TP 5
+ServerTokens None
+.TP 5
+ServerTokens OS
+.TP 5
+ServerTokens ProductOnly
+.br
+Specifies what information is included in the Server header of HTTP
+responses.
+.TP 5
+SetEnv variable value
+.br
+Set the specified environment variable to be passed to child processes.
+.TP 5
+SSLListen
+.br
+Listens on the specified address and port for encrypted connections.
+.TP 5
+SSLOptions None
+.TP 5
+SSLOptions NoEmptyFragments
+.br
+Sets SSL/TLS protocol options for encrypted connections.
+.TP 5
+SSLPort
+.br
+Listens on the specified port for encrypted connections.
+.TP 5
+SubscriptionPrivateAccess all
+.TP 5
+SubscriptionPrivateAccess default
+.TP 5
+SubscriptionPrivateAccess {user|@group|@ACL|@OWNER|@SYSTEM}+
+.br
+Specifies an access list for a subscription's private values. The "default"
+access list is "@OWNER @SYSTEM". "@ACL" maps to the printer's
+requesting-user-name-allowed or requesting-user-name-denied values.
+.TP 5
+SubscriptionPrivateValues all
+.TP 5
+SubscriptionPrivateValues default
+.TP 5
+SubscriptionPrivateValues none
+.TP 5
+SubscriptionPrivateValues attribute-name-1 [ ... attribute-name-N ]
+Specifies the list of job values to make private. The "default" values are
+"notify-events", "notify-pull-method", "notify-recipient-uri",
+"notify-subscriber-user-name", and "notify-user-data".
+.TP 5
+SystemGroup group-name [group-name ...]
+.br
+Specifies the group(s) to use for System class authentication.
+.TP 5
+TempDir directory
+.br
+Specifies the directory where temporary files are stored.
+.TP 5
+Timeout seconds
+.br
+Specifies the HTTP request timeout in seconds.
+.TP 5
+User user-name
+.br
+Specifies the user name or ID that is used when running external programs.
+.TP 5
+WebInterface yes
+.TP 5
+WebInterface no
+Specifies whether the web interface is enabled.
+.SH SEE ALSO
+\fIclasses.conf(5)\fR, \fIcupsd(8)\fR, \fImime.convs(5)\fR,
+\fImime.types(5)\fR, \fIprinters.conf(5)\fR,
+\fIsubscriptions.conf(5)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id$".
+.\"
diff --git a/man/cupsd.man.in b/man/cupsd.man.in
new file mode 100644
index 000000000..fb9ab007d
--- /dev/null
+++ b/man/cupsd.man.in
@@ -0,0 +1,72 @@
+.\"
+.\" "$Id$"
+.\"
+.\" cupsd man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cupsd 8 "CUPS" "9 March 2009" "Apple Inc."
+.SH NAME
+cupsd \- cups scheduler
+.SH SYNOPSIS
+.B cupsd
+[ -c
+.I config-file
+] [ -f ] [ -F ] [ -h ] [ -l ] [ -t ]
+.SH DESCRIPTION
+\fIcupsd\fR is the scheduler for CUPS. It implements a printing system based
+upon the Internet Printing Protocol, version 2.1. If no options are specified
+on the command-line then the default configuration file
+\fI@CUPS_SERVERROOT@/cupsd.conf\fR will be used.
+.SH OPTIONS
+.TP 5
+-c config-file
+.br
+Uses the named configuration file.
+.TP 5
+-f
+.br
+Run \fIcupsd\fR in the foreground; the default is to run in the
+background as a "daemon".
+.TP 5
+-F
+.br
+Run \fIcupsd\fR in the foreground but detach the process from the
+controlling terminal and current directory. This is useful for
+running \fIcupsd\fR from \fIinit(8)\fR.
+.TP 5
+-h
+.br
+Shows the program usage.
+.TP 5
+-l
+.br
+This option is passed to \fIcupsd\fR when it is run from
+\fIlaunchd(8)\fR.
+.TP 5
+-t
+.br
+Test the configuration file for syntax errors.
+.SH COMPATIBILITY
+\fIcupsd\fR implements all of the required IPP/2.1 attributes and
+operations. It also implements several CUPS-specific administration
+operations.
+.SH SEE ALSO
+\fIbackend(7)\fR, \fIclasses.conf(5)\fR, \fIcups-deviced(8)\fR,
+\fIcups-driverd(8)\fR, \fIcups-lpd(8)\fR, \fIcups-polld(8)\fR,
+\fIcupsd.conf(5)\fR, \fIfilter(7)\fR, \fIlaunchd(8)\fR,
+\fImime.convs(5)\fR, \fImime.types(5)\fR, \fIprinters.conf(5)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id$".
+.\"
diff --git a/man/cupsenable.man b/man/cupsenable.man
new file mode 100644
index 000000000..0552f4271
--- /dev/null
+++ b/man/cupsenable.man
@@ -0,0 +1,93 @@
+.\"
+.\" "$Id: cupsenable.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" cupsenable/cupsdisable man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cupsenable 8 "CUPS" "9 October 2008" "Apple Inc."
+.SH NAME
+cupsdisable, cupsenable \- stop/start printers and classes
+.SH SYNOPSIS
+.B cupsdisable
+[ -E ] [-U
+.I username
+] [ -c ] [ -h
+.I server[:port]
+] [ -r
+.I reason
+] [ --hold ] destination(s)
+.br
+.B cupsenable
+[ -E ] [-U
+.I username
+] [ -c ] [ -h
+.I server[:port]
+] [ --release ] destination(s)
+.SH DESCRIPTION
+\fIcupsenable\fR starts the named printers or classes.
+.LP
+\fIcupsdisable\fR stops the named printers or classes. The
+following options may be used:
+.TP 5
+-E
+.br
+Forces encryption of the connection to the server.
+.TP 5
+-U username
+.br
+Uses the specified username when connecting to the server.
+.TP 5
+-c
+.br
+Cancels all jobs on the named destination.
+.TP 5
+-h server[:port]
+.br
+Uses the specified server and port.
+.TP 5
+--hold
+.br
+Holds remaining jobs on the named printer. Useful for allowing the current
+job to complete before performing maintenance.
+.TP 5
+-r "reason"
+.br
+Sets the message associated with the stopped state. If no reason is specified
+then the message is set to "Reason Unknown".
+.TP 5
+--release
+.br
+Releases pending jobs for printing. Use after running \fIcupsdisable\fR with
+the \fI--hold\fR option to resume printing.
+.SH COMPATIBILITY
+Unlike the System V printing system, CUPS allows printer names to
+contain any printable character except SPACE, TAB, "/", or "#".
+Also, printer and class names are \fInot\fR case-sensitive.
+.LP
+The System V versions of these commands are \fIdisable\fR and
+\fIenable\fR. They have been renamed to avoid conflicts with the
+\fIbash(1)\fR build-in commands of the same name.
+.LP
+The CUPS versions of \fIdisable\fR and \fIenable\fR may ask the
+user for an access password depending on the printing system
+configuration. This differs from the System V versions which
+require the root user to execute these commands.
+.SH SEE ALSO
+\fIcupsaccept(8)\fR, \fIcupsreject(8)\fR, \fIcancel(1)\fR, \fIlp(1)\fR,
+\fIlpadmin(8)\fR, \fIlpstat(1)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+
+.\"
+.\" End of "$Id: cupsenable.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/cupsfilter.man b/man/cupsfilter.man
new file mode 100644
index 000000000..7aa9c83e4
--- /dev/null
+++ b/man/cupsfilter.man
@@ -0,0 +1,91 @@
+.\"
+.\" "$Id: cupsfilter.man 9030 2010-03-05 03:55:56Z mike $"
+.\"
+.\" cupsfilter man page for CUPS.
+.\"
+.\" Copyright 2007-2010 by Apple Inc.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cupsfilter 8 "CUPS" "4 March 2010" "Apple Inc."
+.SH NAME
+cupsfilter \- convert a file to another format using cups filters
+.SH SYNOPSIS
+.B cupsfilter
+[ -c
+.I config-file
+] [ -d
+.I printer
+] [ -e ] -j
+.I job-id[,N]
+[ -m
+.I mime/type
+] [ -n
+.I copies
+] [ -o
+.I name=value
+] [ -p
+.I filename.ppd
+] [ -t
+.I title
+]
+.I filename
+.SH DESCRIPTION
+\fIcupsfilter\fR is a front-end to the CUPS filter subsystem which allows you
+to convert a file to a specific format, just as if you had printed the file
+through CUPS. By default, \fIcupsfilter\fR generates a PDF file.
+.SH OPTIONS
+.TP 5
+-c config-file
+.br
+Uses the named cupsd.conf configuration file.
+.TP 5
+-d printer
+Uses information from the named printer.
+.TP 5
+-e
+.br
+Use every filter from the PPD file.
+.TP 5
+-j job-id[,N]
+.br
+Converts document N from the specified job. If N is omitted, document 1 is
+converted.
+.TP 5
+-m mime/type
+.br
+Specifies the destination file type. The default file type is application/pdf.
+Use printer/foo to convert to the printer format defined by the filters in the
+PPD file.
+.TP 5
+-n copies
+.br
+Specifies the number of copies to generate.
+.TP 5
+-o name=value
+.br
+Specifies options to pass to the CUPS filters.
+.TP 5
+-p filename.ppd
+.br
+Specifies the PPD file to use.
+.TP 5
+-t title
+.br
+Specifies the document title.
+.SH KNOWN ISSUES
+\fIcupsfilter\fR currently does not use the filters defined in the PPD file.
+This will be addressed in a future CUPS release.
+.SH SEE ALSO
+\fIcupsd.conf(5)\fR
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2010 by Apple Inc.
+.\"
+.\" End of "$Id: cupsfilter.man 9030 2010-03-05 03:55:56Z mike $".
+.\"
diff --git a/man/cupstestdsc.man b/man/cupstestdsc.man
new file mode 100644
index 000000000..781c5efe0
--- /dev/null
+++ b/man/cupstestdsc.man
@@ -0,0 +1,50 @@
+.\"
+.\" "$Id: cupstestdsc.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" cupstestdsc man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cupstestdsc 1 "CUPS" "20 March 2006" "Apple Inc."
+.SH NAME
+cupstestdsc \- test conformance of postscript files
+.SH SYNOPSIS
+.B cupstestdsc
+[ -h ] filename.ps [ ...
+.I filenameN.ps
+]
+.br
+.B cupstestdsc
+[ -h ] -
+.SH DESCRIPTION
+\fIcupstestdsc\fR tests the conformance of PostScript files to
+the Adobe PostScript Language Document Structuring Conventions
+Specification version 3.0. The results of testing and any other
+output are sent to the standard output. The second form of the
+command reads PostScript from the standard input.
+.SH LIMITATIONS
+\fIcupstestdsc\fR only validates the DSC comments in a PostScript
+file and does not attempt to validate the PostScript code itself.
+Developers must ensure that the PostScript they generate follows
+the rules defined by Adobe. Specifically, all pages must be
+independent of each other, code outside page descriptions may not
+affect the graphics state (current font, color, transform matrix,
+etc.), and device-specific commands such as setpagedevice should
+not be used.
+.SH SEE ALSO
+http://localhost:631/help
+.br
+Adobe PostScript Language Document Structuring Conventions
+Specification, Version 3.0.
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: cupstestdsc.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/cupstestppd.man b/man/cupstestppd.man
new file mode 100644
index 000000000..042f4c291
--- /dev/null
+++ b/man/cupstestppd.man
@@ -0,0 +1,165 @@
+.\"
+.\" "$Id: cupstestppd.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" cupstestppd man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH cupstestppd 1 "CUPS" "19 November 2009" "Apple Inc."
+.SH NAME
+cupstestppd \- test conformance of ppd files
+.SH SYNOPSIS
+.B cupstestppd
+[ -I
+.I category
+] [ -R
+.I rootdir
+] [ -W
+.I category
+] [ -q ] [-r] [ -v[v] ] filename.ppd[.gz] [ ... filenameN.ppd[.gz] ]
+.br
+.B cupstestppd
+[ -R
+.I rootdir
+] [ -W
+.I category
+] [ -q ] [-r] [ -v[v] ] -
+.SH DESCRIPTION
+\fIcupstestppd\fR tests the conformance of PPD files to the
+Adobe PostScript Printer Description file format specification
+version 4.3. It can also be used to list the supported options
+and available fonts in a PPD file. The results of testing and
+any other output are sent to the standard output.
+.LP
+The first form of \fIcupstestppd\fR tests one or more PPD files
+on the command-line. The second form tests the PPD file provided
+on the standard input.
+.SH OPTIONS
+\fIcupstestppd\fR supports the following options:
+.TP 5
+-I filename
+.br
+Ignores all PCFileName warnings.
+.TP 5
+-I filters
+.br
+Ignores all filter errors.
+.TP 5
+-I profiles
+.br
+Ignores all profile errors.
+.TP 5
+-R rootdir
+.br
+Specifies an alternate root directory for the filter, pre-filter,
+and other support file checks.
+.TP 5
+-W constraints
+.br
+Report all UIConstraint errors as warnings.
+.TP 5
+-W defaults
+.br
+Except for size-related options, report all default option errors as warnings.
+.TP 5
+-W filters
+.br
+Report all filter errors as warnings.
+.TP 5
+-W profiles
+.br
+Report all profile errors as warnings.
+.TP 5
+-W sizes
+.br
+Report all media size errors as warnings.
+.TP 5
+-W translations
+.br
+Report all translation errors as warnings.
+.TP 5
+-W all
+.br
+Report all of the previous errors as warnings.
+.TP 5
+-W none
+.br
+Report all of the previous errors as errors.
+.TP 5
+-q
+.br
+Specifies that no information should be displayed.
+.TP 5
+-r
+.br
+Relaxes the PPD conformance requirements so that common
+whitespace, control character, and formatting problems are not
+treated as hard errors.
+.TP 5
+-v
+.br
+Specifies that detailed conformance testing results should be
+displayed rather than the concise PASS/FAIL/ERROR status.
+.TP 5
+-vv
+.br
+Specifies that all information in the PPD file should be
+displayed in addition to the detailed conformance testing
+results.
+.LP
+The \fI-q\fR, \fI-v\fR, and \fI-vv\fR options are mutually exclusive.
+.SH EXIT STATUS
+\fIcupstestppd\fR returns zero on success and non-zero on error. The
+error codes are as follows:
+.TP 5
+1
+.br
+Bad command-line arguments or missing PPD filename.
+.TP 5
+2
+.br
+Unable to open or read PPD file.
+.TP 5
+3
+.br
+The PPD file contains format errors that cannot be skipped.
+.TP 5
+4
+.br
+The PPD file does not conform to the Adobe PPD specification.
+.SH EXAMPLES
+The following command will test all PPD files under the current
+directory and print the names of each file that does not
+conform:
+.nf
+
+ find . -name \\*.ppd \\! -exec cupstestppd -q '{}' \\; -print
+
+.fi
+The next command tests all PPD files under the current directory
+and print detailed conformance testing results for the files
+that do not conform:
+.nf
+
+ find . -name \\*.ppd \\! -exec cupstestppd -q '{}' \\; \\
+ -exec cupstestppd -v '{}' \\;
+
+.fi
+.SH SEE ALSO
+\fIlpadmin(8)\fR,
+.br
+http://localhost:631/help
+.br
+Adobe PostScript Printer Description File Format Specification, Version 4.3.
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: cupstestppd.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/filter.man b/man/filter.man
new file mode 100644
index 000000000..eef66bab0
--- /dev/null
+++ b/man/filter.man
@@ -0,0 +1,256 @@
+.\"
+.\" "$Id: filter.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" filter man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2007 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH filter 7 "CUPS" "13 May 2009" "Apple Inc."
+.SH NAME
+filter \- cups file conversion filter interface
+.SH SYNOPSIS
+.B filter
+job user title num-copies options [
+.I filename
+]
+.SH DESCRIPTION
+The CUPS filter interface provides a standard method for adding support for
+new document types to CUPS. Each filter is capable of converting from one
+or more input formats to another format that can either be printed directly
+or piped into another filter to get it to a printable format.
+.LP
+Filters \fBmust\fR be capable of reading from a filename on the command-line
+or from the standard input, copying the standard input to a temporary
+file as required by the file format. All output \fBmust\fR be sent to the
+standard output.
+.LP
+The command name (argv[0]) is set to the name of the destination printer but is
+also available in the PRINTER environment variable.
+
+.SH OPTIONS
+Options passed on the command-line typically do not include the default choices
+the printer's PPD file. In addition, some options may be specified in multiple
+ways - "landscape" is a synonym for "orientation-requested=4", "media" is a
+synonym for "PageSize", "PageRegion", "InputSlot", and "MediaType", and "sides"
+is a synonym for the various "Duplex" options. Non-raster filters \fBmust\fR
+support both explicit and implicit specification of PPD options - use the
+ppdMarkDefaults and cupsMarkOptions functions in the CUPS library to use the
+correct mapping, and ppdFindMarkedChoice to get the user-selected choice.
+.LP
+Raster filters should use option choices set through the raster page header, as
+those reflect the options in effect for a given page. Options specified on the
+command-line determine the default values for the entire job, which can be
+overridden on a per-page basis.
+
+.SH LOG MESSAGES
+Messages sent to stderr are generally logged to
+printer-state-message attribute and the current \fIErrorLog\fR.
+Each line begins with a standard prefix:
+
+.TP 5
+ALERT: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "alert" log level.
+
+.TP 5
+ATTR: attribute=value [attribute=value]
+.br
+Sets the named job attribute(s). Typically this will be used to
+set the job-remote-id attribute.
+
+.TP 5
+CRIT: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "critical" log level.
+
+.TP 5
+DEBUG: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "debug" log level.
+
+.TP 5
+DEBUG2: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "debug2" log level.
+
+.TP 5
+EMERG: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "emergency" log level.
+
+.TP 5
+ERROR: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "error" log level.
+
+.TP 5
+INFO: message
+.br
+Sets the printer-state-message attribute. If the current \fILogLevel\fR
+is set to "debug2", also adds the specified message to the
+current \fIErrorLog\fR using the "info" log level.
+
+.TP 5
+NOTICE: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "notice" log level.
+
+.TP 5
+PAGE: page-number #-copies
+.TP 5
+PAGE: total #-pages
+.br
+Adds an entry to the current \fIPageLog\fR. The first form adds
+#-copies to the job-media-sheets-completed attribute. The second
+form sets the job-media-sheets-completed attribute to #-pages.
+
+.TP 5
+PPD: Keyword=Value ... KeywordN=Value
+.br
+Sets the named keywords in the printer's PPD file. This is typically
+used to update default option keywords such as DefaultPageSize and
+the various installable options in the PPD file.
+
+.TP 5
+STATE: printer-state-reason [printer-state-reason ...]
+.TP 5
+STATE: + printer-state-reason [printer-state-reason ...]
+.TP 5
+STATE: - printer-state-reason [printer-state-reason ...]
+.br
+Sets, adds, or removes printer-state-reason keywords to the
+current queue. Typically this is used to indicate media, ink, and
+toner conditions on a printer.
+
+.TP 5
+WARNING: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "warning" log level.
+
+.SH ENVIRONMENT VARIABLES
+The following environment variables are defined by the CUPS
+server when executing the filter:
+
+.TP 5
+CHARSET
+.br
+The default text character set, typically utf-8.
+
+.TP 5
+CLASS
+.br
+When a job is submitted to a printer class, contains the name of
+the destination printer class. Otherwise this environment
+variable will not be set.
+
+.TP 5
+CONTENT_TYPE
+.br
+The MIME type associated with the file (e.g.
+application/postscript).
+
+.TP 5
+CUPS_CACHEDIR
+.br
+The directory for semi-persistent cache files can be found.
+
+.TP 5
+CUPS_DATADIR
+.br
+The directory where data files can be found.
+
+.TP 5
+CUPS_FILETYPE
+.br
+The type of file being printed: "job-sheet" for a banner page and "document"
+for a regular print file.
+
+.TP 5
+CUPS_SERVERROOT
+.br
+The root directory of the server.
+
+.TP 5
+DEVICE_URI
+.br
+The device-uri associated with the printer.
+
+.TP 5
+FINAL_CONTENT_TYPE
+.br
+The MIME type associated with the printer (e.g.
+application/vnd.cups-postscript).
+
+.TP 5
+LANG
+.br
+The default language locale (typically C or en).
+
+.TP 5
+PATH
+.br
+The standard execution path for external programs that may be run by
+the filter.
+
+.TP 5
+PPD
+.br
+The full pathname of the PostScript Printer Description (PPD)
+file for this printer.
+
+.TP 5
+PRINTER
+.br
+The name of the printer.
+
+.TP 5
+RIP_CACHE
+.br
+The recommended amount of memory to use for Raster Image
+Processors (RIPs).
+
+.TP 5
+SOFTWARE
+.br
+The name and version number of the server (typically CUPS/1.2).
+
+.TP 5
+TZ
+.br
+The timezone of the server.
+
+.TP 5
+USER
+.br
+The user executing the filter, typically "lp" or "root"; consult the
+\fIcupsd.conf(5)\fR file for the current setting.
+
+.SH COMPATIBILITY
+While the filter interface is compatible with System V interface
+scripts, it will only work with the System V interface script as the
+only filter. Typically the interface script will be provided via the
+\fIlpadmin(8)\fR command using the \fI-i\fR option.
+.SH SEE ALSO
+\fIbackend(7)\fR, \fIcupsd(8)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: filter.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/ipptool.man b/man/ipptool.man
new file mode 100644
index 000000000..6cf845090
--- /dev/null
+++ b/man/ipptool.man
@@ -0,0 +1,130 @@
+.\"
+.\" "$Id: ipptool.man 9354 2010-11-10 06:48:19Z mike $"
+.\"
+.\" ipptool man page for CUPS.
+.\"
+.\" Copyright 2010 by Apple Inc.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH ipptool 1 "CUPS" "9 November 2010" "Apple Inc."
+.SH NAME
+ipptool - perform internet printing protocol requests
+.SH SYNOPSIS
+.B ipptool
+[ -4 ] [ -6 ] [ -C ] [ -E ] [ -I ] [ -L ] [ -S ] [ -T
+.I seconds
+] [ -V
+.I version
+] [ -X ] [ -c ] [ -d
+.I name=value
+] [ -f
+.I filename
+] [ -i
+.I seconds
+] [ -n
+.I repeat-count
+] [ -q ] [ -t ] [ -v ]
+.I URI
+.I filename
+[
+.I ... filenameN
+]
+.SH DESCRIPTION
+\fIipptool\fR sends IPP requests to the specified URI and tests and/or displays the results. Each named file defines one or more requests, including the expected response status, attributes, and values. Output is either a plain text, formatted text, CSV, or XML report on the standard output, with a non-zero exit status indicating that one or more tests have failed. The file format is described in \fIipptoolfile(5)\fR.
+.SH OPTIONS
+The following options are recognized by \fIipptool\fR:
+.TP 5
+-4
+Specifies that \fIipptool\fR must connect to the printer or server using IPv4.
+.TP 5
+-6
+Specifies that \fIipptool\fR must connect to the printer or server using IPv6.
+.TP 5
+-C
+Specifies that requests should be sent using the HTTP/1.1 "Transfer-Encoding: chunked" header, which is required for conformance by all versions of IPP. The default is to use "Transfer-Encoding: chunked" for requests with attached files and "Content-Length:" for requests without attached files.
+.TP 5
+-E
+Forces TLS encryption when connecting to the server using the HTTP "Upgrade" header.
+.TP 5
+-I
+Specifies that \fIipptool\fR will continue past errors.
+.TP 5
+-L
+Specifies that requests should be sent using the HTTP/1.0 "Content-Length:" header, which is required for conformance by all versions of IPP. The default is to use "Transfer-Encoding: chunked" for requests with attached files and "Content-Length:" for requests without attached files.
+.TP 5
+-S
+Forces (dedicated) SSL encryption when connecting to the server.
+.TP 5
+-T seconds
+Specifies a timeout for IPP requests in seconds.
+.TP 5
+-V version
+Specifies the default IPP version to use: 1.0, 1.1, 2.0, 2.1, or 2.2. If not specified, version 1.1 is used.
+.TP 5
+-X
+Specifies that XML (Apple plist) output is desired instead of the plain text report. This option is incompatible with the \fI-i\fR (interval) and \fI-n\fR (repeat-count) options.
+.TP 5
+-c
+Specifies that CSV (comma-separated values) output is desired instead of the plain text output.
+.TP 5
+-d name=value
+Defines the named variable.
+.TP 5
+-f filename
+Defines the default request filename for tests.
+.TP 5
+-i seconds
+Specifies that the (last) file should be repeated at the specified interval. This option is incompatible with the \fI-X\fR (XML plist output) option.
+.TP 5
+-l
+Specifies that plain text output is desired.
+.TP 5
+-n repeat-count
+Specifies that the (last) file should be repeated the specified number of times. This option is incompatible with the \fI-X\fR (XML plist output) option.
+.TP 5
+-t
+Specifies that CUPS test report output is desired instead of the plain text output.
+.TP 5
+-v
+Specifies that all request and response attributes should be output in CUPS test mode (\fI-t\fR). This is the default for XML output.
+.SH COMPATIBILITY
+The \fIipptool\fR program is unique to CUPS.
+.SH EXAMPLES
+Get a list of completed jobs for "myprinter":
+.nf
+ ipptool ipp://localhost/printers/myprinter get-completed-jobs.test
+.fi
+.LP
+Send email notifications to "user@example.com" when "myprinter" changes:
+.nf
+ ipptool -d recipient=mailto:user@example.com \
+ ipp://localhost/printers/myprinter create-printer-subscription.test
+.fi
+.SH STANDARD FILES
+The following standard files are available:
+.nf
+ create-printer-subscription.test
+ get-completed-jobs.test
+ get-jobs.test
+ ipp-1.1.test
+ ipp-2.0.test
+ ipp-2.1.test
+ testfile.jpg
+ testfile.pdf
+ testfile.ps
+ testfile.txt
+.fi
+.SH SEE ALSO
+\fIipptoolfile(5)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2010 by Apple Inc.
+.\"
+.\" End of "$Id: ipptool.man 9354 2010-11-10 06:48:19Z mike $".
+.\"
diff --git a/man/ipptoolfile.man b/man/ipptoolfile.man
new file mode 100644
index 000000000..4abb2f503
--- /dev/null
+++ b/man/ipptoolfile.man
@@ -0,0 +1,511 @@
+.\"
+.\" "$Id: ipptoolfile.man 9769 2011-05-12 04:24:17Z mike $"
+.\"
+.\" ipptoolfile man page for CUPS.
+.\"
+.\" Copyright 2010-2011 by Apple Inc.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH ipptoolfile 5 "CUPS" "11 May 2011" "Apple Inc."
+.SH NAME
+ipptoolfile \- ipptool file format
+
+.SH DESCRIPTION
+The \fIipptool(1)\fR program accepts free-form plain text files that describe one or more IPP requests. Comments start with the "#" character and continue to the end of the line. Each request is enclosed by curley braces, for example:
+.nf
+
+ # This is a comment
+ {
+ # The name of the test
+ NAME "Print PostScript Job"
+
+ # The request to send
+ OPERATION Print-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ FILE testfile.ps
+
+ # The response to expect
+ STATUS successful-ok
+ EXPECT attributes-charset OF-TYPE charset
+ EXPECT attributes-natural-language OF-TYPE naturalLanguage
+ EXPECT job-id OF-TYPE integer
+ EXPECT job-uri OF-TYPE uri
+ }
+ {
+ # The name of the test
+ NAME "Get Attributes of PostScript Job"
+
+ # The request to send
+ OPERATION Get-Job-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ # The response to expect
+ STATUS successful-ok
+ EXPECT attributes-charset OF-TYPE charset
+ EXPECT attributes-natural-language OF-TYPE naturalLanguage
+ EXPECT job-id OF-TYPE integer
+ EXPECT job-uri OF-TYPE uri
+ EXPECT job-state OF-TYPE enum
+ EXPECT job-originating-user-name OF-TYPE name WITH-VALUE "$user"
+ }
+.fi
+
+.SH TOP-LEVEL DIRECTIVES
+The following directives can be used outside of a test:
+.TP 5
+{ test }
+Defines a test.
+.TP 5
+DEFINE variable-name value
+Defines the named variable to the given value. This is equivalent to specifying
+"-d variable-name=value" on the \fIipptool\fR command-line.
+.TP 5
+DEFINE-DEFAULT variable-name value
+Defines the named variable to the given value if it does not already have a
+value.
+.TP 5
+IGNORE-ERRORS yes
+.TP 5
+IGNORE-ERRORS no
+Specifies whether, by default, \fIipptool\fR will ignore errors and continue with
+subsequent tests.
+.TP 5
+INCLUDE "filename"
+.TP 5
+INCLUDE <filename>
+Includes another test file. The first form includes a file relative to the
+current test file, while the second form includes a file from the \fIipptool\fR
+include directory.
+.TP 5
+INCLUDE-IF-DEFINED name "filename"
+.TP 5
+INCLUDE-IF-DEFINED name <filename>
+Includes another test file if the named variable is defined. The first form
+includes a file relative to the current test file, while the second form
+includes a file from the \fIipptool\fR include directory.
+.TP 5
+INCLUDE-IF-NOT-DEFINED name "filename"
+.TP 5
+INCLUDE-IF-NOT-DEFINED name <filename>
+Includes another test file if the named variable is not defined. The first form
+includes a file relative to the current test file, while the second form
+includes a file from the \fIipptool\fR include directory.
+.TP 5
+SKIP-IF-DEFINED variable-name
+.TP 5
+SKIP-IF-NOT-DEFINED variable-name
+Specifies that the remainder of the test file should be skipped when the
+variable is or is not defined.
+.TP 5
+TRANSFER auto
+Specifies that tests will, by default, use "Transfer-Encoding: chunked" for
+requests with attached files and "Content-Length:" for requests without attached
+files.
+.TP 5
+TRANSFER chunked
+Specifies that tests will, by default, use the HTTP/1.1 "Transfer-Encoding:
+chunked" header. This is the default and is equivalent to specifying "-c" on the
+\fIipptool\fR command-line. Support for chunked requests is required for
+conformance with all versions of IPP.
+.TP 5
+TRANSFER length
+Specifies that tests will, by default, use the HTTP/1.0 "Content-Length:"
+header. This is equivalent to specifying "-l" on the \fIipptool\fR command-line.
+Support for content length requests is required for conformance with all
+versions of IPP.
+.TP 5
+VERSION 1.0
+.TP 5
+VERSION 1.1
+.TP 5
+VERSION 2.0
+.TP 5
+VERSION 2.1
+.TP 5
+VERSION 2.2
+Specifies the default IPP version number to use for the tests that follow.
+
+.SH TEST DIRECTIVES
+The following directives are understood in a test:
+.TP 5
+ATTR tag attribute-name value(s)
+Adds an attribute to the test request. Values are separated by the comma (",")
+character - escape commas using the "\" character.
+.TP 5
+ATTR collection attribute-name { MEMBER tag member-name value(s) ... } [ ... { ... } ]
+Adds a collection attribute to the test request. Member attributes follow the
+same syntax as regular attributes and can themselves be nested collections.
+Multiple collection values can be supplied as needed.
+.TP 5
+DELAY seconds
+Specifies a delay before this test will be run.
+.TP 5
+DISPLAY attribute-name
+Specifies that value of the named attribute should be output as part of the
+test report.
+.TP 5
+EXPECT attribute-name [ predicate(s) ]
+.TP 5
+EXPECT ?attribute-name predicate(s)
+.TP 5
+EXPECT !attribute-name
+Specifies that the response must/may/must not include the named attribute.
+Additional requirements can be added as predicates - see the "EXPECT PREDICATES"
+section for more information on predicates.
+.TP 5
+FILE filename
+Specifies a file to include at the end of the request. This is typically used
+when sending a test print file.
+.TP 5
+GROUP tag
+Specifies the group tag for subsequent attributes in the request.
+.TP 5
+IGNORE-ERRORS yes
+.TP 5
+IGNORE-ERRORS no
+Specifies whether \fIipptool\fR will ignore errors and continue with subsequent
+tests.
+.TP 5
+NAME "literal string"
+Specifies the human-readable name of the test.
+.TP 5
+OPERATION operation-code
+Specifies the operation to be performed.
+.TP 5
+REQUEST-ID number
+.TP 5
+REQUEST-ID random
+Specifies the request-id value to use in the request, either an integer or the
+word "random" to use a randomly generated value (the default).
+.TP 5
+RESOURCE path
+Specifies an alternate resource path that is used for the HTTP POST request.
+The default is the resource from the URI provided to the \fIipptool\fR program.
+.TP 5
+SKIP-IF-DEFINED variable-name
+.TP 5
+SKIP-IF-NOT-DEFINED variable-name
+Specifies that the current test should be skipped when the variable is or is not
+defined.
+.TP 5
+SKIP-PREVIOUS-ERROR yes
+.TP 5
+SKIP-PREVIOUS-ERROR no
+Specifies whether \fIipptool\fR will skip the current test if the previous test
+resulted in an error/failure.
+.TP 5
+STATUS status-code [ predicate ]
+Specifies an expected response status-code value. Additional requirements can be
+added as predicates - see the "STATUS PREDICATES" section for more information
+on predicates.
+.TP 5
+TRANSFER auto
+Specifies that this test will use "Transfer-Encoding: chunked" if it has an
+attached file or "Content-Length:" otherwise.
+.TP 5
+TRANSFER chunked
+Specifies that this test will use the HTTP/1.1 "Transfer-Encoding: chunked"
+header.
+.TP 5
+TRANSFER length
+Specifies that this test will use the HTTP/1.0 "Content-Length:" header.
+.TP 5
+VERSION 1.0
+.TP 5
+VERSION 1.1
+.TP 5
+VERSION 2.0
+.TP 5
+VERSION 2.1
+.TP 5
+VERSION 2.2
+Specifies the IPP version number to use for this test.
+
+.SH EXPECT PREDICATES
+The following predicates are understood following the EXPECT test directive:
+.TP 5
+COUNT number
+Requires the EXPECT attribute to have the specified number of values.
+.TP 5
+DEFINE-MATCH variable-name
+Defines the variable to "1" when the EXPECT condition matches. A side-effect of
+this predicate is that this EXPECT will never fail a test.
+.TP 5
+DEFINE-NO-MATCH variable-name
+Defines the variable to "1" when the EXPECT condition does not match. A side-
+effect of this predicate is that this EXPECT will never fail a test.
+.TP 5
+DEFINE-VALUE variable-name
+Defines the variable to the value of the attribute when the EXPECT condition
+matches.
+.TP 5
+IF-DEFINED variable-name
+Makes the EXPECT conditions apply only if the specified variable is defined.
+.TP 5
+IF-NOT-DEFINED variable-name
+Makes the EXPECT conditions apply only if the specified variable is not
+defined.
+.TP 5
+IN-GROUP tag
+Requires the EXPECT attribute to be in the specified group tag.
+.TP 5
+OF-TYPE tag[,tag,...]
+Requires the EXPECT attribute to use the specified value tag(s).
+.TP 5
+SAME-COUNT-AS attribute-name
+Requires the EXPECT attribute to have the same number of values as the specified
+parallel attribute.
+.TP 5
+WITH-VALUE "literal string"
+Requires at least one value of the EXPECT attribute to match the literal string.
+Comparisons are case-sensitive.
+.TP 5
+WITH-VALUE "/regular expression/"
+Requires that all values of the EXPECT attribute match the regular expression,
+which must conform to the POSIX regular expression syntax.
+Comparisons are case-sensitive.
+
+.SH STATUS PREDICATES
+The following predicates are understood following the STATUS test directive:
+.TP 5
+IF-DEFINED variable-name
+Makes the STATUS apply only if the specified variable is defined.
+.TP 5
+IF-NOT-DEFINED variable-name
+Makes the STATUS apply only if the specified variable is not defined.
+
+.SH OPERATION CODES
+Operation codes correspond to the hexadecimal numbers (0xHHHH) and names from
+RFC 2911 and other IPP extension specifications. Here is a complete list:
+.nf
+ Activate-Printer
+ CUPS-Accept-Jobs
+ CUPS-Add-Modify-Class
+ CUPS-Add-Modify-Printer
+ CUPS-Authenticate-Job
+ CUPS-Delete-Class
+ CUPS-Delete-Printer
+ CUPS-Get-Classes
+ CUPS-Get-Default
+ CUPS-Get-Devices
+ CUPS-Get-Document
+ CUPS-Get-PPD
+ CUPS-Get-PPDs
+ CUPS-Get-Printers
+ CUPS-Move-Job
+ CUPS-Reject-Jobs
+ CUPS-Set-Default
+ Cancel-Current-Job
+ Cancel-Job
+ Cancel-Jobs
+ Cancel-My-Jobs
+ Cancel-Subscription
+ Close-Job
+ Create-Job
+ Create-Job-Subscription
+ Create-Printer-Subscription
+ Deactivate-Printer
+ Disable-Printer
+ Enable-Printer
+ Get-Job-Attributes
+ Get-Jobs
+ Get-Notifications
+ Get-Printer-Attributes
+ Get-Printer-Support-Files
+ Get-Printer-Supported-Values
+ Get-Subscription-Attributes
+ Get-Subscriptions
+ Hold-Job
+ Hold-New-Jobs
+ Pause-Printer
+ Pause-Printer-After-Current-Job
+ Print-Job
+ Print-URI
+ Promote-Job
+ Purge-Jobs
+ Release-Held-New-Jobs
+ Release-Job
+ Renew-Subscription
+ Reprocess-Job
+ Restart-Job
+ Restart-Printer
+ Resubmit-Job
+ Resume-Job
+ Resume-Printer
+ Schedule-Job-After
+ Send-Document
+ Send-Notifications
+ Send-URI
+ Set-Job-Attributes
+ Set-Printer-Attributes
+ Shutdown-Printer
+ Startup-Printer
+ Suspend-Current-Job
+ Validate-Job
+.fi
+
+.SH STATUS CODES
+Status codes correspond to the hexadecimal numbers (0xHHHH) and names from RFC
+2911 and other IPP extension specifications. Here is a complete list:
+.nf
+ client-error-attributes-not-settable
+ client-error-attributes-or-values-not-supported
+ client-error-bad-request
+ client-error-charset-not-supported
+ client-error-compression-error
+ client-error-compression-not-supported
+ client-error-conflicting-attributes
+ client-error-document-access-error
+ client-error-document-format-error
+ client-error-document-format-not-supported
+ client-error-forbidden
+ client-error-gone
+ client-error-ignored-all-notifications
+ client-error-ignored-all-subscriptions
+ client-error-not-authenticated
+ client-error-not-authorized
+ client-error-not-found
+ client-error-not-possible
+ client-error-print-support-file-not-found
+ client-error-request-entity-too-large
+ client-error-request-value-too-long
+ client-error-timeout
+ client-error-too-many-subscriptions
+ client-error-uri-scheme-not-supported
+ cups-see-other
+ redirection-other-site
+ server-error-busy
+ server-error-device-error
+ server-error-internal-error
+ server-error-job-canceled
+ server-error-multiple-document-jobs-not-supported
+ server-error-not-accepting-jobs
+ server-error-operation-not-supported
+ server-error-printer-is-deactivated
+ server-error-service-unavailable
+ server-error-temporary-error
+ server-error-version-not-supported
+ successful-ok
+ successful-ok-but-cancel-subscription
+ successful-ok-conflicting-attributes
+ successful-ok-events-complete
+ successful-ok-ignored-notifications
+ successful-ok-ignored-or-substituted-attributes
+ successful-ok-ignored-subscriptions
+ successful-ok-too-many-events
+.fi
+
+.SH TAGS
+Value and group tags correspond to the names from RFC 2911 and other IPP
+extension specifications. Here are the group tags:
+.nf
+ event-notification-attributes-tag
+ job-attributes-tag
+ operation-attributes-tag
+ printer-attributes-tag
+ subscription-attributes-tag
+ unsupported-attributes-tag
+.fi
+.LP
+Here are the value tags:
+.nf
+ admin-define
+ boolean
+ charset
+ collection
+ dateTime
+ default
+ delete-attribute
+ enum
+ integer
+ keyword
+ mimeMediaType
+ nameWithLanguage
+ nameWithoutLanguage
+ naturalLanguage
+ no-value
+ not-settable
+ octetString
+ rangeOfInteger
+ resolution
+ textWithLanguage
+ textWithoutLanguage
+ unknown
+ unsupported
+ uri
+ uriScheme
+.fi
+
+.SH VARIABLES
+The \fIipptool\fR program maintains a list of variables that can be used in any
+literal string or attribute value by specifying "$variable-name". Aside from
+variables defined using the "-d" option or "DEFINE" directive, the following
+pre-defined variables are available:
+.TP 5
+$$
+Inserts a single "$" character.
+.TP 5
+$ENV[name]
+Inserts the value of the named environment variable, or an empty string if the
+environment variable is not defined.
+.TP 5
+$filename
+Inserts the filename provided to \fIipptool\fR with the "-f" option.
+.TP 5
+$hostname
+Inserts the hostname from the URI provided to \fIipptool\fR.
+.TP 5
+$job-id
+Inserts the last job-id value returned in a test response or 0 if no job-id has
+been seen.
+.TP 5
+$job-uri
+Inserts the last job-uri value returned in a test response or an empty string if
+no job-uri has been seen.
+.TP 5
+$scheme
+Inserts the scheme from the URI provided to \fIipptool\fR.
+.TP 5
+$notify-subscription-id
+Inserts the last notify-subscription-id value returnd in a test response or 0 if
+no notify-subscription-id has been seen.
+.TP 5
+$port
+Inserts the port number from the URI provided to \fIipptool\fR.
+.TP 5
+$resource
+Inserts the resource path from the URI provided to \fIipptool\fR.
+.TP 5
+$uri
+Inserts the URI provided to \fIipptool\fR.
+.TP 5
+$user
+Inserts the current user's login name.
+.TP 5
+$username
+Inserts the username from the URI provided to \fIipptool\fR, if any.
+
+.SH SEE ALSO
+\fIipptool(1)\fR,
+.br
+http://localhost:631/help
+
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: ipptoolfile.man 9769 2011-05-12 04:24:17Z mike $".
+.\"
diff --git a/man/lp.man b/man/lp.man
new file mode 100644
index 000000000..c19c3cd83
--- /dev/null
+++ b/man/lp.man
@@ -0,0 +1,262 @@
+.\"
+.\" "$Id: lp.man 9664 2011-03-31 18:53:52Z mike $"
+.\"
+.\" lp man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH lp 1 "CUPS" "31 March 2011" "Apple Inc."
+.SH NAME
+lp - print files
+.SH SYNOPSIS
+.B lp
+[ -E ] [ -U
+.I username
+] [ -c ] [ -d
+.I destination[/instance]
+] [ -h
+.I hostname[:port]
+] [ -m ] [ -n
+.I num-copies
+] [ -o
+.I option[=value]
+] [ -q
+.I priority
+] [ -s ] [ -t
+.I title
+] [ -H
+.I handling
+] [ -P
+.I page-list
+] [ -- ] [
+.I file(s)
+]
+.br
+.B lp
+[ -E ] [ -U
+.I username
+] [ -c ] [ -h
+.I hostname[:port]
+] [ -i
+.I job-id
+] [ -n
+.I num-copies
+] [ -o
+.I option[=value]
+] [ -q
+.I priority
+] [ -t
+.I title
+] [ -H
+.I handling
+] [ -P
+.I page-list
+]
+.SH DESCRIPTION
+\fIlp\fR submits files for printing or alters a pending job. Use
+a filename of "-" to force printing from the standard input.
+.SH THE DEFAULT DESTINATION
+CUPS provides many ways to set the default destination. The "LPDEST" and
+"PRINTER" environment variables are consulted first. If neither are set,
+the current default set using the \fIlpoptions(1)\fR command is used,
+followed by the default set using the \fIlpadmin(8)\fR command.
+.SH OPTIONS
+The following options are recognized by \fIlp\fR:
+.TP 5
+--
+.br
+Marks the end of options; use this to print a file whose name
+begins with a dash (-).
+.TP 5
+-E
+.br
+Forces encryption when connecting to the server.
+.TP 5
+-U username
+.br
+Specifies the username to use when connecting to the server.
+.TP 5
+-c
+.br
+This option is provided for backwards-compatibility only. On
+systems that support it, this option forces the print file to be
+copied to the spool directory before printing. In CUPS, print
+files are always sent to the scheduler via IPP which has the
+same effect.
+.TP 5
+-d destination
+.br
+Prints files to the named printer.
+.TP 5
+-h hostname[:port]
+.br
+Chooses an alternate server.
+.TP 5
+-i job-id
+.br
+Specifies an existing job to modify.
+.TP 5
+-m
+.br
+Sends an email when the job is completed.
+.TP 5
+-n copies
+.br
+Sets the number of copies to print from 1 to 100.
+.TP 5
+-o "name=value [name=value ...]"
+.br
+Sets one or more job options.
+.TP 5
+-q priority
+.br
+Sets the job priority from 1 (lowest) to 100 (highest). The
+default priority is 50.
+.TP 5
+-s
+.br
+Do not report the resulting job IDs (silent mode.)
+.TP 5
+-t "name"
+.br
+Sets the job name.
+.TP 5
+-u username
+.br
+Submits jobs as \fIusername\fR.
+.TP 5
+-H hh:mm
+.TP 5
+-H hold
+.TP 5
+-H immediate
+.TP 5
+-H restart
+.TP 5
+-H resume
+.br
+Specifies when the job should be printed. A value of \fIimmediate\fR will print
+the file immediately, a value of \fIhold\fR will hold the job indefinitely, and
+a UTC time value (HH:MM) will hold the job until the specified UTC (not local)
+time. Use a value of \fIresume\fR with the \fI-i\fR option to resume a held job.
+Use a value of \fIrestart\fR with the \fI-i\fR option to restart
+a completed job.
+.TP 5
+-P page-list
+.br
+Specifies which pages to print in the document. The list can
+contain a list of numbers and ranges (#-#) separated by commas
+(e.g. 1,3-5,16). The page numbers refer to the output pages and
+not the document's original pages - options like "number-up" can
+affect the numbering of the pages.
+.SH COMMON JOB OPTIONS
+Aside from the printer-specific options reported by the
+\fIlpoptions(1)\fR command, the following generic options are
+available:
+.TP 5
+-o media=size
+.br
+Sets the page size to \fIsize\fR. Most printers support at least
+the size names "a4", "letter", and "legal".
+.TP 5
+-o landscape
+.TP 5
+-o orientation-requested=4
+.br
+Prints the job in landscape (rotated 90 degrees).
+.TP 5
+-o sides=one-sided
+.TP 5
+-o sides=two-sided-long-edge
+.TP 5
+-o sides=two-sided-short-edge
+.br
+Prints on one or two sides of the paper. The value
+"two-sided-long-edge" is normally used when printing portrait
+(unrotated) pages, while "two-sided-short-edge" is used for
+landscape pages.
+.TP 5
+-o fitplot
+.br
+Scales the print file to fit on the page.
+.TP 5
+-o number-up=2
+.TP 5
+-o number-up=4
+.TP 5
+-o number-up=6
+.TP 5
+-o number-up=9
+.TP 5
+-o number-up=16
+.br
+Prints multiple document pages on each output page.
+.TP 5
+-o scaling=number
+.br
+Scales image files to use up to \fInumber\fR percent of the page.
+Values greater than 100 cause the image file to be printed across
+multiple pages.
+.TP 5
+-o cpi=N
+.br
+Sets the number of characters per inch to use when printing a
+text file. The default is 10.
+.TP 5
+-o lpi=N
+.br
+Sets the number of lines per inch to use when printing a text
+file. The default is 6.
+.TP 5
+-o page-bottom=N
+.TP 5
+-o page-left=N
+.TP 5
+-o page-right=N
+.TP 5
+-o page-top=N
+.br
+Sets the page margins when printing text files. The values are in
+points - there are 72 points to the inch.
+.SH EXAMPLES
+Print a double-sided legal document to a printer called "foo":
+.nf
+ lp -d foo -o media=legal -o sides=two-sided-long-edge filename
+.fi
+.LP
+Print an image across 4 pages:
+.nf
+ lp -d bar -o scaling=200 filename
+.fi
+.LP
+Print a text file with 12 characters per inch, 8 lines per inch, and
+a 1 inch left margin:
+.nf
+ lp -d bar -o cpi=12 -o lpi=8 -o page-left=72 filename
+.fi
+.SH COMPATIBILITY
+Unlike the System V printing system, CUPS allows printer names to
+contain any printable character except SPACE, TAB, "/", or "#".
+Also, printer and class names are \fInot\fR case-sensitive.
+.LP
+The "q" option accepts a different range of values than the
+Solaris lp command, matching the IPP job priority values (1-100,
+100 is highest priority) instead of the Solaris values (0-39, 0
+is highest priority).
+.SH SEE ALSO
+\fIcancel(1)\fR, \fIlpadmin(8)\fR, \fIlpmove(8)\fR, \fIlpoptions(1)\fR,
+\fIlpstat(1)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: lp.man 9664 2011-03-31 18:53:52Z mike $".
+.\"
diff --git a/man/lpadmin.man b/man/lpadmin.man
new file mode 100644
index 000000000..c388f03b7
--- /dev/null
+++ b/man/lpadmin.man
@@ -0,0 +1,228 @@
+.\"
+.\" "$Id: lpadmin.man 9762 2011-05-11 05:30:50Z mike $"
+.\"
+.\" lpadmin man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH lpadmin 8 "CUPS" "10 May 2011" "Apple Inc."
+.SH NAME
+lpadmin \- configure cups printers and classes
+.SH SYNOPSIS
+.B lpadmin
+[ -E ] [-U
+.I username
+] [ -h
+.I server[:port]
+] -d
+.I destination
+.br
+.B lpadmin
+[ -E ] [-U
+.I username
+] [ -h
+.I server[:port]
+] -p
+.I destination
+[ -R
+.I name-default
+]
+.I option(s)
+.br
+.B lpadmin
+[ -E ] [-U
+.I username
+] [ -h
+.I server[:port]
+] -x
+.I destination
+.SH DESCRIPTION
+\fIlpadmin\fR configures printer and class queues provided by
+CUPS. It can also be used to set the server default printer or
+class.
+.LP
+When specified before the \fI-d\fR, \fI-p\fR, or \fI-x\fR
+options, the \fI-E\fR option forces encryption when connecting to
+the server.
+.LP
+The first form of the command (\fI-d\fR) sets the default printer
+or class to \fIdestination\fR. Subsequent print jobs submitted
+via the \fIlp(1)\fR or \fIlpr(1)\fR commands will use this
+destination unless the user specifies otherwise with the
+\fIlpoptions(1)\fR command.
+.LP
+The second form of the command (\fI-p\fR) configures the named
+printer or class. The additional options are described below.
+.LP
+The third form of the command (\fI-x\fR) deletes the printer or
+class \fIdestination\fR. Any jobs that are pending for the
+destination will be removed and any job that is currently printed
+will be aborted.
+.SH CONFIGURATION OPTIONS
+The following options are recognized when configuring a printer
+queue:
+.TP 5
+-c class
+.br
+Adds the named \fIprinter\fR to \fIclass\fR. If \fIclass\fR does
+not exist it is created automatically.
+.TP 5
+-i interface
+.br
+Sets a System V style interface script for the printer. This
+option cannot be specified with the \fI-P\fR option (PPD file)
+and is intended for providing support for legacy printer drivers.
+.TP 5
+-m model
+.br
+Sets a standard System V interface script or PPD file for the printer from the
+\fImodel\fR directory or using one of the driver interfaces. Use the \fI-m\fR
+option with the \fIlpinfo(8)\fR command to get a list of supported models.
+.TP 5
+-o cupsIPPSupplies=true
+.TP 5
+-o cupsIPPSupplies=false
+.br
+Specifies whether IPP supply level values should be reported.
+.TP 5
+-o cupsSNMPSupplies=true
+.TP 5
+-o cupsSNMPSupplies=false
+.br
+Specifies whether SNMP supply level (RFC 3805) values should be reported.
+.TP 5
+-o job-k-limit=value
+.br
+Sets the kilobyte limit for per-user quotas. The value is an
+integer number of kilobytes; one kilobyte is 1024 bytes.
+.TP 5
+-o job-page-limit=value
+.br
+Sets the page limit for per-user quotas. The value is the integer
+number of pages that can be printed; double-sided pages are
+counted as two pages.
+.TP 5
+-o job-quota-period=value
+.br
+Sets the accounting period for per-user quotas. The value is an
+integer number of seconds; 86,400 seconds are in one day.
+.TP 5
+-o job-sheets-default=banner
+.TP 5
+-o job-sheets-default=banner,banner
+.br
+Sets the default banner page(s) to use for print jobs.
+.TP 5
+-o name=value
+.br
+Sets a PPD option for the printer. PPD options can be listed using the \fI-l\fR
+option with the \fIlpoptions(1)\fR command.
+.TP 5
+-o name-default=value
+.br
+Sets a default server-side option for the destination. Any print-time
+option can be defaulted, e.g. "-o cpi-default=17" to set the default
+"cpi" option value to 17.
+.TP 5
+-o port-monitor=name
+.br
+Sets the binary communications program to use when printing,
+"none", "bcp", or "tbcp". The default program is "none". The
+specified port monitor must be listed in the printer's PPD file.
+.TP 5
+-o printer-error-policy=name
+.br
+Sets the error policy to be used when the printer backend is
+unable to send the job to the printer. The name must be one of
+"abort-job", "retry-job", "retry-current-job", or "stop-printer". The default
+error policy is "stop-printer" for printers and "retry-current-job" for
+classes.
+.TP 5
+-o printer-is-shared=true/false
+.br
+Sets the destination to shared/published or unshared/unpublished.
+Shared/published destinations are publicly announced by the server
+on the LAN based on the browsing configuration in
+\fBcupsd.conf\fR, while unshared/unpublished destinations are not
+announced. The default value is "true".
+.TP 5
+-o printer-op-policy=name
+.br
+Sets the IPP operation policy associated with the destination. The
+name must be defined in the \fBcupsd.conf\fR in a Policy section.
+The default operation policy is "default".
+.TP 5
+-R name-default
+.br
+Deletes the named option from \fIprinter\fR.
+.TP 5
+-r class
+.br
+Removes the named \fIprinter\fR from \fIclass\fR. If the
+resulting class becomes empty it is removed.
+.TP 5
+-u allow:user,user,@group
+.TP 5
+-u deny:user,user,@group
+.TP 5
+-u allow:all
+.TP 5
+-u deny:none
+.br
+Sets user-level access control on a destination. Names starting with
+"@" are interpreted as UNIX groups. The latter two forms turn
+user-level access control off.
+.TP 5
+-v "device-uri"
+.br
+Sets the \fIdevice-uri\fR attribute of the printer queue. If
+\fIdevice-uri\fR is a filename it is automatically converted to
+the form \fIfile:///file/name\fR. Use the \fI-v\fR option with the
+\fIlpinfo(8)\fR command to get a list of supported device URIs and schemes.
+.TP 5
+-D "info"
+.br
+Provides a textual description of the destination.
+.TP 5
+-E
+.br
+Enables the destination and accepts jobs; this is the same as running the
+\fIcupsaccept(8)\fR and \fIcupsenable(8)\fR programs on the destination.
+.TP 5
+-L "location"
+.br
+Provides a textual location of the destination.
+.TP 5
+-P ppd-file
+.br
+Specifies a PostScript Printer Description file to use with the
+printer. If specified, this option overrides the \fI-i\fR option
+(interface script).
+.SH COMPATIBILITY
+Unlike the System V printing system, CUPS allows printer names to
+contain any printable character except SPACE, TAB, "/", or "#".
+Also, printer and class names are \fInot\fR case-sensitive.
+Finally, the CUPS version of \fIlpadmin\fR may ask the user for
+an access password depending on the printing system
+configuration. This differs from the System V version which
+requires the root user to execute this command.
+.SH LIMITATIONS
+The CUPS version of \fIlpadmin\fR does not support all of the
+System V or Solaris printing system configuration options.
+.SH SEE ALSO
+\fIcupsaccept(8)\fR, \fIcupsenable(8)\fR, \fIlpinfo(8)\fR,
+\fIlpoptions(1)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: lpadmin.man 9762 2011-05-11 05:30:50Z mike $".
+.\"
diff --git a/man/lpc.man b/man/lpc.man
new file mode 100644
index 000000000..8e5c7101a
--- /dev/null
+++ b/man/lpc.man
@@ -0,0 +1,71 @@
+.\"
+.\" "$Id: lpc.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" lpc man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH lpc 8 "CUPS" "3 November 2008" "Apple Inc."
+.SH NAME
+lpc \- line printer control program
+.SH SYNOPSIS
+.B lpc
+[
+.I command
+[
+.I parameter(s)
+] ]
+.SH DESCRIPTION
+\fIlpc\fR provides limited control over printer and class queues
+provided by CUPS. It can also be used to query the state of
+queues.
+.LP
+If no command is specified on the command-line, \fRlpc\fR will
+display a prompt and accept commands from the standard input.
+.SH COMMANDS
+The \fIlpc\fR program accepts a subset of commands accepted by
+the Berkeley \fIlpc\fR program of the same name:
+.TP 5
+exit
+.br
+Exits the command interpreter.
+.TP 5
+help [command]
+.TP 5
+? [command]
+.br
+Displays a short help message.
+.TP 5
+quit
+.br
+Exits the command interpreter.
+.TP 5
+status [queue]
+.br
+Displays the status of one or more printer or class queues.
+.SH LIMITATIONS
+Since \fIlpc\fR is geared towards the Berkeley printing system,
+it is impossible to use \fIlpc\fR to configure printer or class
+queues provided by CUPS. To configure printer or class queues
+you must use the \fIlpadmin(8)\fR command or another
+CUPS-compatible client with that functionality.
+.SH COMPATIBILITY
+The CUPS version of \fIlpc\fR does not implement all of the
+standard Berkeley or LPRng commands.
+.SH SEE ALSO
+\fIcancel(1)\fR, \fIcupsaccept(8)\fR, \fIcupsenable(8)\fR,
+\fIlp(1)\fR, \fIlpr(1)\fR, \fIlprm(1)\fR, \fIlpstat(1)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: lpc.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/lpinfo.man b/man/lpinfo.man
new file mode 100644
index 000000000..42bda480f
--- /dev/null
+++ b/man/lpinfo.man
@@ -0,0 +1,115 @@
+.\"
+.\" "$Id: lpinfo.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" lpinfo man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH lpinfo 8 "CUPS" "5 December 2008" "Apple Inc."
+.SH NAME
+lpinfo \- show available devices or drivers
+.SH SYNOPSIS
+.B lpinfo
+[ -E ] [ -U
+.I username
+] [ -h
+.I server[:port]
+] [ -l ] [ --device-id
+.I device-id-string
+] [ --exclude-schemes
+.I scheme-list
+] [ --include-schemes
+.I scheme-list
+] [ --language
+.I locale
+] [ --make-and-model
+.I name
+] [ --product
+.I name
+] -m
+.br
+.B lpinfo
+[ -E ] [ -U
+.I username
+] [ -h
+.I server[:port]
+] [ -l ] [ --exclude-schemes
+.I scheme-list
+] [ --include-schemes
+.I scheme-list
+] [ --timeout
+.I seconds
+] -v
+.SH DESCRIPTION
+\fIlpinfo\fR lists the available devices or drivers known to the
+CUPS server. The first form (\fI-m\fR) lists the available
+drivers, while the second form (\fI-v\fR) lists the available
+devices.
+.SH OPTIONS
+\fIlpinfo\fR accepts the following options:
+.TP 5
+-E
+.br
+Forces encryption when connecting to the server.
+.TP 5
+-U username
+.br
+Sets the username to use when connecting to the server.
+.TP 5
+-h server[:port]
+.br
+Selects an alternate server.
+.TP 5
+-l
+.br
+Shows a "long" listing of devices or drivers.
+.TP 5
+--device-id device-id-string
+.br
+Specifies the IEEE-1284 device ID to match when listing drivers with the
+\fI-m\fR option.
+.TP 5
+--exclude-schemes scheme-list
+.br
+Specifies a comma-separated list of device or PPD schemes that should be
+excluded from the results. Static PPD files use the "file" scheme.
+.TP 5
+--include-schemes scheme-list
+.br
+Specifies a comma-separated list of device or PPD schemes that should be
+included in the results. Static PPD files use the "file" scheme.
+.TP 5
+--language locale
+.br
+Specifies the language to match when listing drivers with the \fI-m\fR option.
+.TP 5
+--make-and-model name
+.br
+Specifies the make and model to match when listing drivers with the \fI-m\fR
+option.
+.TP 5
+--product name
+.br
+Specifies the product to match when listing drivers with the \fI-m\fR option.
+.TP 5
+--timeout seconds
+.br
+Specifies the timeout when listing devices with the \fI-v\fR option.
+.SH COMPATIBILITY
+The \fIlpinfo\fR command is unique to CUPS.
+.SH SEE ALSO
+\fIlpadmin(8)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: lpinfo.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/lpmove.man b/man/lpmove.man
new file mode 100644
index 000000000..b5688f416
--- /dev/null
+++ b/man/lpmove.man
@@ -0,0 +1,66 @@
+.\"
+.\" "$Id: lpmove.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" lpmove man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH lpmove 8 "CUPS" "12 February 2006" "Apple Inc."
+.SH NAME
+lpmove \- move a job or all jobs to a new destination
+.SH SYNOPSIS
+.B lpmove
+[ -E ] [ -h
+.I server[:port]
+] [ -U
+.I username
+]
+.I job destination
+.br
+.B lpmove
+[ -E ] [ -h
+.I server[:port]
+] [ -U
+.I username
+]
+.I source destination
+.SH DESCRIPTION
+\fBlpmove\fR moves the specified \fIjob\fR or all jobs from
+\fIsource\fR to \fIdestination\fR. \fIjob\fR can be the job ID
+number or the old destination and job ID:
+.br
+.nf
+
+ lpmove 123 newprinter
+ lpmove oldprinter-123 newprinter
+.fi
+.SH OPTIONS
+The \fIlpmove\fR command supports the following options:
+.TP 5
+-E
+.br
+Forces encryption when connecting to the server.
+.TP 5
+-U username
+.br
+Specifies an alternate username.
+.TP 5
+-h server[:port]
+.br
+Specifies an alternate server.
+.SH SEE ALSO
+\fIcancel(1)\fR, \fIlp(1)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: lpmove.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/lpoptions.man.in b/man/lpoptions.man.in
new file mode 100644
index 000000000..3573ba0ee
--- /dev/null
+++ b/man/lpoptions.man.in
@@ -0,0 +1,135 @@
+.\"
+.\" "$Id$"
+.\"
+.\" lpoptions man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH lpoptions 1 "CUPS" "29 August 2008" "Apple Inc."
+.SH NAME
+lpoptions \- display or set printer options and defaults
+.SH SYNOPSIS
+.B lpoptions
+[ -E ] [ -U
+.I username
+] [ -h
+.I server[:port]
+] -d
+.I destination[/instance]
+[ -o
+.I option[=value]
+] ... [ -o
+.I option[=value]
+]
+.br
+.B lpoptions
+[ -E ] [ -U
+.I username
+] [ -h
+.I server[:port]
+] [ -p
+.I destination[/instance]
+] -l
+.br
+.B lpoptions
+[ -E ] [ -U
+.I username
+] [ -h
+.I server[:port]
+] [ -o
+.I option[=value]
+] ... [ -o
+.I option[=value]
+] [ -p
+.I destination[/instance]
+] -r
+.I option
+.br
+.B lpoptions
+[ -E ] [ -U
+.I username
+] [ -h
+.I server[:port]
+] -x
+.I destination[/instance]
+.SH DESCRIPTION
+\fIlpoptions\fR displays or sets printer options and defaults.
+\fIlpoptions\fR shows the default printer options when run with no
+arguments. Other options include:
+.TP 5
+-E
+.br
+Enables encryption when communicating with the CUPS server.
+.TP 5
+-U username
+.br
+Uses an alternate username.
+.TP 5
+-d destination[/instance]
+.br
+Sets the user default printer to \fIdestination\fR. If \fIinstance\fR
+is supplied then that particular instance is used. This option
+overrides the system default printer for the current user.
+.TP 5
+-h server[:port]
+.br
+Uses an alternate server.
+.TP 5
+-l
+.br
+Lists the printer specific options and their current settings.
+.TP 5
+-o option[=value]
+.br
+Specifies a new option for the named destination.
+.TP 5
+-p destination[/instance]
+.br
+Sets the destination and instance, if specified, for any options
+that follow. If the named instance does not exist then it is
+created.
+.TP 5
+-r option
+.br
+Removes the specified option for the named destination.
+.TP 5
+-x destination[/instance]
+.br
+Removes the options for the named destination and instance, if
+specified. If the named instance does not exist then this does
+nothing.
+.LP
+If no options are specified using the \fI-o\fR option, then the
+current options for the named printer are reported on the
+standard output.
+.LP
+Options set with the \fIlpoptions\fR command are used by the
+\fIlp(1)\fR and \fIlpr(1)\fR commands when submitting jobs.
+.SH ROOT ACCOUNT OPTIONS
+When run by the root user, \fIlpoptions\fR gets and sets default
+options and instances for \fIall users\fR in the
+@CUPS_SERVERROOT@/lpoptions file.
+.SH COMPATIBILITY
+The \fIlpoptions\fR command is unique to CUPS.
+.SH FILES
+~/.cups/lpoptions - user defaults and instances created by non-root
+users.
+.br
+@CUPS_SERVERROOT@/lpoptions - system-wide defaults and instances
+created by the root user.
+.SH SEE ALSO
+\fIcancel(1)\fR, \fIlp(1)\fR, \fIlpadmin(8)\fR, \fIlpr(1)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id$".
+.\"
diff --git a/man/lppasswd.man b/man/lppasswd.man
new file mode 100644
index 000000000..87ade67b8
--- /dev/null
+++ b/man/lppasswd.man
@@ -0,0 +1,68 @@
+.\"
+.\" "$Id: lppasswd.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" lpadmin man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH lppasswd 1 "CUPS" "22 February 2008" "Apple Inc."
+.SH NAME
+lppasswd \- add, change, or delete digest passwords.
+.SH SYNOPSIS
+.B lppasswd
+[
+.I username
+]
+.br
+.B lppasswd
+-a [ -g
+.I groupname
+]
+.I username
+.br
+.B lppasswd
+-x
+.I username
+.SH DESCRIPTION
+\fIlppasswd\fR adds, changes, or deletes passwords in the CUPS
+digest password file, \fIpasswd.md5\fR. When run by a normal
+user, \fIlppasswd\fR will prompt for the old and new passwords.
+When run by the super-user, \fIlppasswd\fR can add new accounts
+(\fI-a username\fR), change existing accounts (\fIusername\fR),
+or delete accounts (\fI-x username\fR) in the digest password
+file. Digest usernames do not have to match local UNIX usernames.
+.SH OPTIONS
+\fIlppasswd\fR supports the following options:
+.TP 5
+-g groupname
+.br
+Specifies a group other than the default system group.
+.SH SECURITY ISSUES
+By default, the \fIlppasswd\fR program is not installed to allow ordinary
+users to change their passwords. To enable this, the \fIlppasswd\fR command
+must be made setuid to root with the command:
+.br
+.nf
+chmod u+s lppasswd
+.fi
+.PP
+While every attempt has been made to make \fIlppasswd\fR secure against
+exploits that could grant super-user privileges to unprivileged users,
+paranoid system administrators may wish to use Basic authentication with
+accounts managed by PAM instead.
+.SH SEE ALSO
+\fIlp(1)\fR, \fIlpr(1)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: lppasswd.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/lpq.man b/man/lpq.man
new file mode 100644
index 000000000..502d45a08
--- /dev/null
+++ b/man/lpq.man
@@ -0,0 +1,72 @@
+.\"
+.\" "$Id: lpq.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" lpq man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH lpq 1 "CUPS" "16 June 2008" "Apple Inc."
+.SH NAME
+lpq \- show printer queue status
+.SH SYNOPSIS
+.B lpq
+[ -E ] [ -U
+.I username
+] [ -h
+.I server[:port]
+] [ -P
+.I destination[/instance]
+] [ -a ] [ -l ] [
+.I +interval
+]
+.SH DESCRIPTION
+\fIlpq\fR shows the current print queue status on the named
+printer. Jobs queued on the default destination will be shown if
+no printer or class is specified on the command-line.
+.LP
+The \fI+interval\fR option allows you to continuously report the
+jobs in the queue until the queue is empty; the list of jobs is
+shown once every \fIinterval\fR seconds.
+.SH OPTIONS
+\fIlpq\fR supports the following options:
+.TP 5
+-E
+.br
+Forces encryption when connecting to the server.
+.TP 5
+-P destination[/instance]
+.br
+Specifies an alternate printer or class name.
+.TP 5
+-U username
+.br
+Specifies an alternate username.
+.TP 5
+-a
+.br
+Reports jobs on all printers.
+.TP 5
+-h server[:port]
+.br
+Specifies an alternate server.
+.TP 5
+-l
+.br
+Requests a more verbose (long) reporting format.
+.SH SEE ALSO
+\fIcancel(1)\fR, \fIlp(1)\fR, \fIlpr(1)\fR, \fIlprm(1)\fR,
+\fIlpstat(1)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: lpq.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/lpr.man b/man/lpr.man
new file mode 100644
index 000000000..b60a265e4
--- /dev/null
+++ b/man/lpr.man
@@ -0,0 +1,122 @@
+.\"
+.\" "$Id: lpr.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" lpr man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH lpr 1 "CUPS" "29 August 2008" "Apple Inc."
+.SH NAME
+lpr \- print files
+.SH SYNOPSIS
+.B lpr
+[ -E ] [ -H
+.I server[:port]
+] [ -U
+.I username
+] [ -P
+.I destination[/instance]
+] [ -#
+.I num-copies
+[ -h ] [ -l ] [ -m ] [ -o
+.I option[=value]
+] [ -p] [ -q ] [ -r ] [ -C/J/T
+.I title
+] [
+.I file(s)
+]
+.SH DESCRIPTION
+\fIlpr\fR submits files for printing. Files named on the command
+line are sent to the named printer (or the default destination if no
+destination is specified). If no files are listed on the command-line,
+\fIlpr\fR reads the print file from the standard input.
+.SH THE DEFAULT DESTINATION
+CUPS provides many ways to set the default destination. The "LPDEST" and
+"PRINTER" environment variables are consulted first. If neither are set,
+the current default set using the \fIlpoptions(1)\fR command is used,
+followed by the default set using the \fIlpadmin(8)\fR command.
+.SH OPTIONS
+The following options are recognized by \fIlpr\fR:
+.TP 5
+-E
+.br
+Forces encryption when connecting to the server.
+.TP 5
+-H server[:port]
+.br
+Specifies an alternate server.
+.TP 5
+-C "name"
+.TP 5
+-J "name"
+.TP 5
+-T "name"
+.br
+Sets the job name.
+.TP 5
+-P destination[/instance]
+.br
+Prints files to the named printer.
+.TP 5
+-U username
+.br
+Specifies an alternate username.
+.TP 5
+-# \fIcopies\fR
+.br
+Sets the number of copies to print from 1 to 100.
+.TP 5
+-h
+.br
+Disables banner printing. This option is equivalent to "-o
+job-sheets=none".
+.TP 5
+-l
+.br
+Specifies that the print file is already formatted for the
+destination and should be sent without filtering. This option is
+equivalent to "-o raw".
+.TP 5
+-m
+.br
+Send an email on job completion.
+.TP 5
+-o option[=value]
+.br
+Sets a job option.
+.TP 5
+-p
+.br
+Specifies that the print file should be formatted with a shaded
+header with the date, time, job name, and page number. This
+option is equivalent to "-o prettyprint" and is only useful when
+printing text files.
+.TP 5
+-q
+.br
+Hold job for printing.
+.TP 5
+-r
+.br
+Specifies that the named print files should be deleted after
+printing them.
+.SH COMPATIBILITY
+The "c", "d", "f", "g", "i", "n", "t", "v", and "w" options
+are not supported by CUPS and produce a warning message if used.
+.SH SEE ALSO
+\fIcancel(1)\fR, \fIlp(1)\fR, \fIlpadmin(8)\fR, \fIlpoptions(1)\fR,
+\fIlpq(1)\fR, \fIlprm(1)\fR, \fIlpstat(1)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: lpr.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/lprm.man b/man/lprm.man
new file mode 100644
index 000000000..d64ac03da
--- /dev/null
+++ b/man/lprm.man
@@ -0,0 +1,65 @@
+.\"
+.\" "$Id: lprm.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" lprm man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH lprm 1 "CUPS" "28 August 2009" "Apple Inc."
+.SH NAME
+lprm \- cancel print jobs
+.SH SYNOPSIS
+.B lprm
+[ -E ] [ -U
+.I username
+] [ -h
+.I server[:port]
+] [ -P
+.I destination[/instance]
+] [ - ] [
+.I job ID(s)
+]
+.SH DESCRIPTION
+\fIlprm\fR cancels print jobs that have been queued for printing.
+If no arguments are supplied, the current job on the default
+destination is cancelled. You can specify one or more job ID
+numbers to cancel those jobs or use the \fI-\fR option to cancel
+all jobs.
+.SH OPTIONS
+The \fIlprm\fR command supports the following options:
+.TP 5
+-E
+.br
+Forces encryption when connecting to the server.
+.TP 5
+-P destination[/instance]
+.br
+Specifies the destination printer or class.
+.TP 5
+-U username
+.br
+Specifies an alternate username.
+.TP 5
+-h server[:port]
+.br
+Specifies an alternate server.
+.SH COMPATIBILITY
+The CUPS version of \fIlprm\fR is compatible with the standard
+Berkeley \fIlprm\fR command.
+.SH SEE ALSO
+\fIcancel(1)\fR, \fIlp(1)\fR, \fIlpq(1)\fR, \fIlpr(1)\fR,
+\fIlpstat(1)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: lprm.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/lpstat.man b/man/lpstat.man
new file mode 100644
index 000000000..c51c44ad9
--- /dev/null
+++ b/man/lpstat.man
@@ -0,0 +1,143 @@
+.\"
+.\" "$Id: lpstat.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" lpstat man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH lpstat 1 "CUPS" "10 September 2008" "Apple Inc."
+.SH NAME
+lpstat \- print cups status information
+.SH SYNOPSIS
+.B lpstat
+[ -E ] [ -H ] [ -U
+.I username
+] [ -h
+.I hostname[:port]
+] [ -l ] [ -W
+.I which-jobs
+] [ -a [
+.I destination(s)
+] ] [ -c [
+.I class(es)
+] ] [ -d ] [ -o [
+.I destination(s)
+] ] [ -p [
+.I printer(s)
+] ] [ -r ] [ -R ] [ -s ] [ -t ] [ -u [
+.I user(s)
+] ] [ -v [
+.I printer(s)
+] ]
+.SH DESCRIPTION
+\fIlpstat\fR displays status information about the current
+classes, jobs, and printers. When run with no arguments,
+\fIlpstat\fR will list jobs queued by the current user.
+.SH OPTIONS
+The \fIlpstat\fR command supports the following options:
+.TP 5
+-E
+.br
+Forces encryption when connecting to the server.
+.TP 5
+-H
+.br
+Shows the server hostname and port.
+.TP 5
+-R
+.br
+Shows the ranking of print jobs.
+.TP 5
+-U username
+.br
+Specifies an alternate username.
+.TP 5
+-W which-jobs
+.br
+Specifies which jobs to show, \fIcompleted\fR or
+\fInot-completed\fR (the default). This option \fImust\fR appear
+before the \fI-o\fR option and/or any printer names, otherwise
+the default (not-completed) value will be used in the request to
+the scheduler.
+.TP 5
+-a [printer(s)]
+.br
+Shows the accepting state of printer queues. If no printers are
+specified then all printers are listed.
+.TP 5
+-c [class(es)]
+.br
+Shows the printer classes and the printers that belong to them.
+If no classes are specified then all classes are listed.
+.TP 5
+-d
+.br
+Shows the current default destination.
+.TP 5
+-h server[:port]
+.br
+Specifies an alternate server.
+.TP 5
+-l
+.br
+Shows a long listing of printers, classes, or jobs.
+.TP 5
+-o [destination(s)]
+.br
+Shows the jobs queue on the specified destinations. If no destinations are
+specified all jobs are shown.
+.TP 5
+-p [printer(s)]
+.br
+Shows the printers and whether or not they are enabled for printing. If
+no printers are specified then all printers are listed.
+.TP 5
+-r
+.br
+Shows whether the CUPS server is running.
+.TP 5
+-s
+.br
+Shows a status summary, including the default destination, a
+list of classes and their member printers, and a list of printers and
+their associated devices. This is equivalent to using the "-d", "-c",
+and "-v" options.
+.TP 5
+-t
+.br
+Shows all status information. This is equivalent to using the "-r",
+"-d", "-c", "-v", "-a", "-p", and "-o" options.
+.TP 5
+-u [user(s)]
+.br
+Shows a list of print jobs queued by the specified users. If no users
+are specified, lists the jobs queued by the current user.
+.TP 5
+-v [printer(s)]
+.br
+Shows the printers and what device they are attached to. If no printers
+are specified then all printers are listed.
+.SH COMPATIBILITY
+Unlike the System V printing system, CUPS allows printer names to
+contain any printable character except SPACE, TAB, "/", and "#".
+Also, printer and class names are \fInot\fR case-sensitive.
+.LP
+The "-h", "-E", "-U", and "-W" options are unique to CUPS.
+.LP
+The Solaris "-f", "-P", and "-S" options are silently ignored.
+.SH SEE ALSO
+\fIcancel(1)\fR, \fIlp(1)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: lpstat.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/mailto.conf.man b/man/mailto.conf.man
new file mode 100644
index 000000000..7f9e30d5e
--- /dev/null
+++ b/man/mailto.conf.man
@@ -0,0 +1,60 @@
+.\"
+.\" "$Id: mailto.conf.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" mailto.conf man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH mailto.conf 5 "CUPS" "12 July 2006" "Apple Inc."
+.SH NAME
+mailto.conf \- configuration file for cups email notifier
+.SH DESCRIPTION
+The \fImailto.conf\fR file defines the local mail server and
+email notification preferences for CUPS.
+.LP
+Each line in the file can be a configuration directive, a blank line,
+or a comment. Comment lines start with the # character.
+.SH DIRECTIVES
+.TP 5
+Cc \fIcc-address@domain.com\fR
+.br
+Specifies an additional recipient for all email notifications.
+.TP 5
+From \fIfrom-address@domain.com\fR
+.br
+Specifies the sender of email notifications.
+.TP 5
+Sendmail \fIsendmail command and options\fR
+.br
+Specifies the sendmail command to use when sending email
+notifications. Only one \fISendmail\fR or \fISMTPServer\fR line
+may be present in the \fImailto.conf\fR file. If multiple lines
+are present, only the last one is used.
+.TP 5
+SMTPServer \fIservername\fR
+.br
+Specifies a SMTP server to send email notifications to. Only one
+\fISendmail\fR or \fISMTPServer\fR line may be present in the
+\fImailto.conf\fR file. If multiple lines are present, only the
+last one is used.
+.TP 5
+Subject \fIsubject-prefix\fR
+.br
+Specifies a prefix string for the subject line of an email notification.
+.SH SEE ALSO
+\fIclasses.conf(5)\fR, \fIcupsd(8)\fR, \fIcupsd.conf(5)\fR,
+\fImime.convs(5)\fR, \fImime.types(5)\fR, \fIprinters.conf(5)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: mailto.conf.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/mantohtml.c b/man/mantohtml.c
new file mode 100644
index 000000000..13e733697
--- /dev/null
+++ b/man/mantohtml.c
@@ -0,0 +1,720 @@
+/*
+ * "$Id$"
+ *
+ * Man page to HTML conversion program.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2004-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Convert a man page to HTML.
+ * putc_entity() - Put a single character, using entities as needed.
+ * strmove() - Move characters within a string.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <cups/string-private.h>
+#include <unistd.h>
+
+
+/*
+ * Local functions...
+ */
+
+static void putc_entity(int ch, FILE *fp);
+static void strmove(char *d, const char *s);
+
+
+/*
+ * 'main()' - Convert a man page to HTML.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ FILE *infile, /* Input file */
+ *outfile; /* Output file */
+ char line[1024], /* Line from file */
+ *lineptr, /* Pointer into line */
+ *endptr, /* Pointer to end of current */
+ endchar, /* End character */
+ *paren, /* Pointer to parenthesis */
+ name[1024]; /* Man page name */
+ int section, /* Man page section */
+ pre, /* Preformatted */
+ font, /* Current font */
+ blist, /* In a bullet list? */
+ list, /* In a list? */
+ linenum; /* Current line number */
+ const char *post; /* Text to add after the current line */
+ static const char /* Start/end tags for fonts */
+ * const start_fonts[] = { "", "<b>", "<i>" },
+ * const end_fonts[] = { "", "</b>", "</i>" };
+
+ /*
+ * Check arguments...
+ */
+
+ if (argc > 3)
+ {
+ fputs("Usage: mantohtml [filename.man [filename.html]]\n", stderr);
+ return (1);
+ }
+
+ /*
+ * Open files as needed...
+ */
+
+ if (argc > 1)
+ {
+ if ((infile = fopen(argv[1], "r")) == NULL)
+ {
+ perror(argv[1]);
+ return (1);
+ }
+ }
+ else
+ infile = stdin;
+
+ if (argc > 2)
+ {
+ if ((outfile = fopen(argv[2], "w")) == NULL)
+ {
+ perror(argv[2]);
+ fclose(infile);
+ return (1);
+ }
+ }
+ else
+ outfile = stdout;
+
+ /*
+ * Read from input and write the output...
+ */
+
+ fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" "
+ "\"http://www.w3.org/TR/html4/loose.dtd\">\n"
+ "<html>\n"
+ "<!-- SECTION: Man Pages -->\n"
+ "<head>\n"
+ "\t<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"../cups-printable.css\">\n", outfile);
+
+ blist = 0;
+ font = 0;
+ list = 0;
+ linenum = 0;
+ pre = 0;
+ post = NULL;
+ section = -1;
+
+ while (fgets(line, sizeof(line), infile))
+ {
+ linenum ++;
+
+ if (line[0] == '.')
+ {
+ /*
+ * Strip leading whitespace...
+ */
+
+ while (line[1] == ' ' || line[1] == '\t')
+ strmove(line + 1, line + 2);
+
+ /*
+ * Process man page commands...
+ */
+
+ if (!strncmp(line, ".TH ", 4) && section < 0)
+ {
+ /*
+ * Grab man page title...
+ */
+
+ sscanf(line + 4, "%s%d", name, &section);
+
+ fprintf(outfile,
+ "\t<title>%s(%d)</title>\n"
+ "</head>\n"
+ "<body>\n"
+ "<h1 class=\"title\">%s(%d)</h1>\n"
+ "%s",
+ name, section, name, section, start_fonts[font]);
+ }
+ else if (section < 0)
+ continue;
+ else if (!strncmp(line, ".SH ", 4) || !strncmp(line, ".SS ", 4))
+ {
+ /*
+ * Grab heading...
+ */
+
+ int first = 1;
+
+ fputs(end_fonts[font], outfile);
+
+ if (blist)
+ {
+ fputs("</li>\n</ul>\n", outfile);
+ blist = 0;
+ }
+
+ if (list)
+ {
+ if (list == 1)
+ fputs("</dt>\n", outfile);
+ else if (list)
+ fputs("</dd>\n", outfile);
+
+ fputs("</dl>\n", outfile);
+ list = 0;
+ }
+
+ line[strlen(line) - 1] = '\0'; /* Strip LF */
+
+ if (line[2] == 'H')
+ fputs("<h2 class=\"title\"><a name=\"", outfile);
+ else
+ fputs("<h3><a name=\"", outfile);
+
+ for (lineptr = line + 4; *lineptr; lineptr ++)
+ if (*lineptr == '\"')
+ continue;
+ else if (*lineptr == ' ')
+ putc_entity('_', outfile);
+ else
+ putc_entity(*lineptr, outfile);
+
+ fputs("\">", outfile);
+
+ for (lineptr = line + 4; *lineptr; lineptr ++)
+ if (*lineptr == '\"')
+ continue;
+ else if (*lineptr == ' ')
+ {
+ putc_entity(' ', outfile);
+
+ first = 1;
+ }
+ else
+ {
+ if (first)
+ putc_entity(*lineptr, outfile);
+ else
+ putc_entity(tolower(*lineptr), outfile);
+
+ first = 0;
+ }
+
+ if (line[2] == 'H')
+ fprintf(outfile, "</a></h2>\n%s", start_fonts[font]);
+ else
+ fprintf(outfile, "</a></h3>\n%s", start_fonts[font]);
+ }
+ else if (!strncmp(line, ".LP", 3) || !strncmp(line, ".PP", 3))
+ {
+ /*
+ * New paragraph...
+ */
+
+ fputs(end_fonts[font], outfile);
+
+ if (blist)
+ {
+ fputs("</li>\n</ul>\n", outfile);
+ blist = 0;
+ }
+
+ if (list)
+ {
+ if (list == 1)
+ fputs("</dt>\n", outfile);
+ else if (list)
+ fputs("</dd>\n", outfile);
+
+ fputs("</dl>\n", outfile);
+ list = 0;
+ }
+
+ fputs("<p>", outfile);
+ font = 0;
+ }
+ else if (!strncmp(line, ".TP ", 4))
+ {
+ /*
+ * Grab list...
+ */
+
+ fputs(end_fonts[font], outfile);
+
+ if (blist)
+ {
+ fputs("</li>\n</ul>\n", outfile);
+ blist = 0;
+ }
+
+ if (!list)
+ fputs("<dl>\n", outfile);
+ else if (list == 1)
+ fputs("</dt>\n", outfile);
+ else if (list)
+ fputs("</dd>\n", outfile);
+
+ fputs("<dt>", outfile);
+ list = 1;
+ font = 0;
+ }
+ else if (!strncmp(line, ".br", 3))
+ {
+ /*
+ * Grab line break...
+ */
+
+ if (list == 1)
+ {
+ fputs("</dt>\n<dd>", outfile);
+ list = 2;
+ }
+ else if (list)
+ fputs("</dd>\n<dd>", outfile);
+ else
+ fputs("<br>\n", outfile);
+ }
+ else if (!strncmp(line, ".de ", 4))
+ {
+ /*
+ * Define macro - ignore...
+ */
+
+ while (fgets(line, sizeof(line), infile))
+ {
+ linenum ++;
+
+ if (!strncmp(line, "..", 2))
+ break;
+ }
+ }
+ else if (!strncmp(line, ".RS", 3))
+ {
+ /*
+ * Indent...
+ */
+
+ fputs("<div style='margin-left: 3em;'>\n", outfile);
+ }
+ else if (!strncmp(line, ".RE", 3))
+ {
+ /*
+ * Unindent...
+ */
+
+ fputs("</div>\n", outfile);
+ }
+ else if (!strncmp(line, ".ds ", 4) || !strncmp(line, ".rm ", 4) ||
+ !strncmp(line, ".tr ", 4) || !strncmp(line, ".hy ", 4) ||
+ !strncmp(line, ".IX ", 4) || !strncmp(line, ".PD", 3) ||
+ !strncmp(line, ".Sp", 3))
+ {
+ /*
+ * Ignore unused commands...
+ */
+ }
+ else if (!strncmp(line, ".Vb", 3) || !strncmp(line, ".nf", 3))
+ {
+ /*
+ * Start preformatted...
+ */
+
+ pre = 1;
+ fputs("<pre>\n", outfile);
+ }
+ else if (!strncmp(line, ".Ve", 3) || !strncmp(line, ".fi", 3))
+ {
+ /*
+ * End preformatted...
+ */
+
+ if (pre)
+ {
+ pre = 0;
+ fputs("</pre>\n", outfile);
+ }
+ }
+ else if (!strncmp(line, ".IP \\(bu", 8))
+ {
+ /*
+ * Bullet list...
+ */
+
+ if (blist)
+ fputs("</li>\n", outfile);
+ else
+ {
+ fputs("<ul>\n", outfile);
+ blist = 1;
+ }
+
+ fputs("<li>", outfile);
+ }
+ else if (!strncmp(line, ".IP ", 4))
+ {
+ /*
+ * Indented paragraph...
+ */
+
+ if (blist)
+ {
+ fputs("</li>\n</ul>\n", outfile);
+ blist = 0;
+ }
+
+ fputs("<p style='margin-left: 3em;'>", outfile);
+
+ for (lineptr = line + 4; isspace(*lineptr); lineptr ++);
+
+ if (*lineptr == '\"')
+ {
+ strmove(line, lineptr + 1);
+
+ if ((lineptr = strchr(line, '\"')) != NULL)
+ *lineptr = '\0';
+ }
+ else
+ {
+ strmove(line, lineptr);
+
+ if ((lineptr = strchr(line, ' ')) != NULL)
+ *lineptr = '\0';
+ }
+
+ /*
+ * Process the text as if it was in-line...
+ */
+
+ post = "\n<br>\n<br>";
+ goto process_text;
+ }
+ else if (!strncmp(line, ".\\}", 3))
+ {
+ /*
+ * Ignore close block...
+ */
+ }
+ else if (!strncmp(line, ".ie", 3) || !strncmp(line, ".if", 3) ||
+ !strncmp(line, ".el", 3))
+ {
+ /*
+ * If/else - ignore...
+ */
+
+ if (strchr(line, '{') != NULL)
+ {
+ /*
+ * Skip whole block...
+ */
+
+ while (fgets(line, sizeof(line), infile))
+ {
+ linenum ++;
+
+ if (strchr(line, '}') != NULL)
+ break;
+ }
+ }
+ }
+#if 0
+ else if (!strncmp(line, ". ", 4))
+ {
+ /*
+ * Grab ...
+ */
+ }
+#endif /* 0 */
+ else if (!strncmp(line, ".B ", 3))
+ {
+ /*
+ * Grab bold text...
+ */
+
+ fprintf(outfile, "%s<b>%s</b>%s", end_fonts[font], line + 3,
+ start_fonts[font]);
+ }
+ else if (!strncmp(line, ".I ", 3))
+ {
+ /*
+ * Grab italic text...
+ */
+
+ fprintf(outfile, "%s<i>%s</i>%s", end_fonts[font], line + 3,
+ start_fonts[font]);
+ }
+ else if (strncmp(line, ".\\\"", 3))
+ {
+ /*
+ * Unknown...
+ */
+
+ if ((lineptr = strchr(line, ' ')) != NULL)
+ *lineptr = '\0';
+ else if ((lineptr = strchr(line, '\n')) != NULL)
+ *lineptr = '\0';
+
+ fprintf(stderr, "mantohtml: Unknown man page command \'%s\' on line %d!\n",
+ line, linenum);
+ }
+
+ /*
+ * Skip continuation lines...
+ */
+
+ lineptr = line + strlen(line) - 2;
+ if (lineptr >= line && *lineptr == '\\')
+ {
+ while (fgets(line, sizeof(line), infile))
+ {
+ linenum ++;
+ lineptr = line + strlen(line) - 2;
+
+ if (lineptr < line || *lineptr != '\\')
+ break;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Process man page text...
+ */
+
+process_text:
+
+ for (lineptr = line; *lineptr; lineptr ++)
+ {
+ if (!strncmp(lineptr, "http://", 7))
+ {
+ /*
+ * Embed URL...
+ */
+
+ for (endptr = lineptr + 7;
+ *endptr && !isspace(*endptr & 255);
+ endptr ++);
+
+ endchar = *endptr;
+ *endptr = '\0';
+
+ fprintf(outfile, "<a href='%s'>%s</a>", lineptr, lineptr);
+ *endptr = endchar;
+ lineptr = endptr - 1;
+ }
+ else if (!strncmp(lineptr, "\\fI", 3) &&
+ (endptr = strstr(lineptr, "\\fR")) != NULL &&
+ (paren = strchr(lineptr, '(')) != NULL &&
+ paren < endptr)
+ {
+ /*
+ * Link to man page?
+ */
+
+ char manfile[1024], /* Man page filename */
+ manurl[1024]; /* Man page URL */
+
+
+ /*
+ * See if the man file is available locally...
+ */
+
+ lineptr += 3;
+ endchar = *paren;
+ *paren = '\0';
+
+ snprintf(manfile, sizeof(manfile), "%s.man", lineptr);
+ snprintf(manurl, sizeof(manurl), "man-%s.html?TOPIC=Man+Pages",
+ lineptr);
+
+ *paren = endchar;
+ endchar = *endptr;
+ *endptr = '\0';
+
+ if (access(manfile, 0))
+ {
+ /*
+ * Not a local man page, just do it italic...
+ */
+
+ fputs("<i>", outfile);
+ while (*lineptr)
+ putc_entity(*lineptr++, outfile);
+ fputs("</i>", outfile);
+ }
+ else
+ {
+ /*
+ * Local man page, do a link...
+ */
+
+ fprintf(outfile, "<a href='%s'>", manurl);
+ while (*lineptr)
+ putc_entity(*lineptr++, outfile);
+ fputs("</a>", outfile);
+ }
+
+ *endptr = endchar;
+ lineptr = endptr + 2;
+ }
+ else if (*lineptr == '\\')
+ {
+ lineptr ++;
+ if (!*lineptr)
+ break;
+ else if (isdigit(lineptr[0]) && isdigit(lineptr[1]) &&
+ isdigit(lineptr[2]))
+ {
+ fprintf(outfile, "&#%d;", ((lineptr[0] - '0') * 8 +
+ lineptr[1] - '0') * 8 +
+ lineptr[2] - '0');
+ lineptr += 2;
+ }
+ else if (*lineptr == '&')
+ continue;
+ else if (*lineptr == 's')
+ {
+ while (lineptr[1] == '-' || isdigit(lineptr[1]))
+ lineptr ++;
+ }
+ else if (*lineptr == '*')
+ {
+ lineptr += 2;
+ }
+ else if (*lineptr != 'f')
+ putc_entity(*lineptr, outfile);
+ else
+ {
+ lineptr ++;
+ if (!*lineptr)
+ break;
+ else
+ {
+ fputs(end_fonts[font], outfile);
+
+ switch (*lineptr)
+ {
+ default : /* Regular */
+ font = 0;
+ break;
+ case 'B' : /* Bold */
+ case 'b' :
+ font = 1;
+ break;
+ case 'I' : /* Italic */
+ case 'i' :
+ font = 2;
+ break;
+ }
+
+ fputs(start_fonts[font], outfile);
+ }
+ }
+ }
+ else
+ putc_entity(*lineptr, outfile);
+ }
+
+ if (post)
+ {
+ fputs(post, outfile);
+ post = NULL;
+ }
+
+ if (list == 1)
+ {
+ fputs("</dt>\n<dd>", outfile);
+ list = 2;
+ }
+ }
+ }
+
+ fprintf(outfile, "%s\n", end_fonts[font]);
+
+ if (blist)
+ {
+ fputs("</li>\n</ul>\n", outfile);
+ }
+
+ if (list)
+ {
+ if (list == 1)
+ fputs("</dt>\n", outfile);
+ else if (list)
+ fputs("</dd>\n", outfile);
+
+ fputs("</dl>\n", outfile);
+ }
+
+ fputs("</body>\n"
+ "</html>\n", outfile);
+
+ /*
+ * Close files...
+ */
+
+ if (infile != stdin)
+ fclose(infile);
+
+ if (outfile != stdout)
+ fclose(outfile);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'putc_entity()' - Put a single character, using entities as needed.
+ */
+
+static void
+putc_entity(int ch, /* I - Character */
+ FILE *fp) /* I - File */
+{
+ if (ch == '&')
+ fputs("&amp;", fp);
+ else if (ch == '<')
+ fputs("&lt;", fp);
+ else
+ putc(ch, fp);
+}
+
+
+/*
+ * 'strmove()' - Move characters within a string.
+ */
+
+static void
+strmove(char *d, /* I - Destination */
+ const char *s) /* I - Source */
+{
+ while (*s)
+ *d++ = *s++;
+
+ *d = '\0';
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/man/mime.convs.man b/man/mime.convs.man
new file mode 100644
index 000000000..d55cad47b
--- /dev/null
+++ b/man/mime.convs.man
@@ -0,0 +1,46 @@
+.\"
+.\" "$Id: mime.convs.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" mime.convs man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH mime.convs 5 "CUPS" "20 March 2006" "Apple Inc."
+.SH NAME
+mime.convs \- mime type conversion file for cups
+.SH DESCRIPTION
+The \fImime.convs\fR file defines the filters that are available
+for converting files from one format to another. The standard
+filters support text, PDF, PostScript, HP-GL/2, and many types of
+image files.
+.LP
+Additional filters can be added to the \fImime.convs\fR file or
+(preferably) to other files in the CUPS configuration directory.
+.LP
+Each line in the \fImime.convs\fR file is a comment, blank, or filter
+line. Comment lines start with the # character. Filter lines specify
+the source and destination MIME types along with a relative cost
+associated with the filter and the filter to run:
+.br
+.nf
+
+super/type super/type cost filter
+application/postscript application/vnd.cups-raster 50 pstoraster
+.fi
+.SH SEE ALSO
+\fIclasses.conf(5)\fR, \fIcupsd(8)\fR, \fIcupsd.conf(5)\fR,
+\fImime.types(5)\fR, \fIprinters.conf(5)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: mime.convs.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/mime.types.man b/man/mime.types.man
new file mode 100644
index 000000000..9c695660f
--- /dev/null
+++ b/man/mime.types.man
@@ -0,0 +1,115 @@
+.\"
+.\" "$Id: mime.types.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" mime.types man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH mime.types 5 "CUPS" "16 May 2009" "Apple Inc."
+.SH NAME
+mime.types \- mime type description file for cups
+.SH DESCRIPTION
+The \fImime.types\fR file defines the recognized file types.
+.LP
+Additional file types can be added to \fImime.types\fR or
+(preferably) in additional files in the CUPS configuration
+directory with the extension ".types".
+.LP
+Each line in the \fImime.types\fR file is a comment, blank, or
+rule line. Comment lines start with the # character. Rule lines
+start with the MIME type name and are optionally followed by a
+series of file recognition rules that are used to automatically
+identify print and web files:
+.br
+.nf
+
+ super/type rule [ ... ruleN]
+.fi
+MIME type names are case-insensitive and are sorted in ascending alphanumeric
+order for the purposes of matching. See the "TYPE MATCHING AND PRIORITY"
+section for more information.
+.LP
+The rules may be grouped using parenthesis, joined using "+" for a
+logical AND and "," or whitespace for a logical OR, and negated using
+"!".
+.SH RULES
+Rules take two forms - a filename extension by itself and functions with test
+values inside parenthesis. The following functions are available:
+.TP 5
+match("pattern")
+.br
+Pattern match on filename
+.TP 5
+ascii(offset,length)
+.br
+True if bytes are valid printable ASCII (CR, NL, TAB, BS, 32-126)
+.TP 5
+printable(offset,length)
+.br
+True if bytes are printable 8-bit chars (CR, NL, TAB, BS, 32-126, 128-254)
+.TP 5
+priority(number)
+.br
+Specifies the relative priority of this MIME type. The default priority is 100.
+Larger values have higher priority while smaller values have lower priority.
+.TP 5
+string(offset,"string")
+.br
+True if bytes are identical to string
+.TP 5
+istring(offset,"string")
+.br
+True if a case-insensitive comparison of the bytes is identical
+.TP 5
+char(offset,value)
+.br
+True if byte is identical
+.TP 5
+short(offset,value)
+.br
+True if 16-bit integer is identical
+.TP 5
+int(offset,value)
+.br
+True if 32-bit integer is identical
+.TP 5
+locale("string")
+.br
+True if current locale matches string
+.TP 5
+contains(offset,range,"string")
+.br
+True if the range contains the string
+.SH STRING CONSTANTS
+String constants can be specified inside quotes ("") for strings
+containing whitespace and angle brackets (<>) for hexadecimal
+strings.
+.SH TYPE MATCHING AND PRIORITY
+When CUPS needs to determine the MIME type of a given file, it checks every
+MIME type defined in the .types files. When two types have the same matching
+rules, the type chosen will depend on the type name and priority, with higher-
+priority types being used over lower-priority ones. If the types have the same
+priority, the type names are sorted alphanumerically in ascending order and the
+first type is chosen.
+.LP
+For example, if two types "text/bar" and "text/foo" are defined as matching the
+extension "doc", normally the type "text/bar" will be chosen since its name is
+alphanumerically smaller than "text/foo". However, if "text/foo" also defines a
+higher priority than "text/bar", "text/foo" will be chosen instead.
+.SH SEE ALSO
+\fIclasses.conf(5)\fR, \fIcupsd(8)\fR, \fIcupsd.conf(5)\fR,
+\fImime.convs(5)\fR, \fIprinters.conf(5)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: mime.types.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/notifier.man b/man/notifier.man
new file mode 100644
index 000000000..498dfd59a
--- /dev/null
+++ b/man/notifier.man
@@ -0,0 +1,157 @@
+.\"
+.\" "$Id: notifier.man 8999 2010-02-24 01:01:04Z mike $"
+.\"
+.\" notifier man page for CUPS.
+.\"
+.\" Copyright 2007-2009 by Apple Inc.
+.\" Copyright 1997-2007 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH notifier 7 "CUPS" "12 May 2009" "Apple Inc."
+.SH NAME
+notifier \- cups notification interface
+.SH SYNOPSIS
+.B notifier
+.I recipient
+[
+.I user-data
+]
+.SH DESCRIPTION
+The CUPS notifier interface provides a standard method for adding support for
+new event notification methods to CUPS. Each notifier delivers one or more IPP
+events from the standard input to the specified recipient.
+.LP
+Notifiers \fBmust\fR read IPP messages from the standard input using the
+ippNew and ippReadFile functions and exit on error. Notifiers are encouraged to
+exit after a suitable period of inactivity, however they may exit after reading
+the first message or stay running until an error is seen.
+.SH LOG MESSAGES
+Messages sent to stderr are generally logged to the current \fIErrorLog\fR.
+Each line begins with a standard prefix:
+
+.TP 5
+ALERT: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "alert" log level.
+
+.TP 5
+CRIT: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "critical" log level.
+
+.TP 5
+DEBUG: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "debug" log level.
+
+.TP 5
+DEBUG2: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "debug2" log level.
+
+.TP 5
+EMERG: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "emergency" log level.
+
+.TP 5
+ERROR: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "error" log level.
+
+.TP 5
+INFO: message
+.br
+Sets the printer-state-message attribute. If the current \fILogLevel\fR
+is set to "debug2", also adds the specified message to the
+current \fIErrorLog\fR using the "info" log level.
+
+.TP 5
+NOTICE: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "notice" log level.
+
+.TP 5
+WARNING: message
+.br
+Sets the printer-state-message attribute and adds the specified
+message to the current \fIErrorLog\fR using the "warning" log level.
+
+.SH ENVIRONMENT VARIABLES
+The following environment variables are defined by the CUPS server when
+executing the notifier:
+
+.TP 5
+CHARSET
+.br
+The default text character set, typically utf-8.
+
+.TP 5
+CUPS_CACHEDIR
+.br
+The directory for semi-persistent cache files can be found.
+
+.TP 5
+CUPS_DATADIR
+.br
+The directory where data files can be found.
+
+.TP 5
+CUPS_FILETYPE
+.br
+The type of file being printed: "job-sheet" for a banner page and "document"
+for a regular print file.
+
+.TP 5
+CUPS_SERVERROOT
+.br
+The root directory of the server.
+
+.TP 5
+LANG
+.br
+The default language locale (typically C or en).
+
+.TP 5
+PATH
+.br
+The standard execution path for external programs that may be run by
+the filter.
+
+.TP 5
+SOFTWARE
+.br
+The name and version number of the server (typically CUPS/1.2).
+
+.TP 5
+TZ
+.br
+The timezone of the server.
+
+.TP 5
+USER
+.br
+The user executing the filter, typically "lp"; consult the \fIcupsd.conf(5)\fR
+file for the current setting.
+
+.SH SEE ALSO
+\fIbackend(7)\fR, \fIcupsd(8)\fR, \fIfilter(7)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2009 by Apple Inc.
+.\"
+.\" End of "$Id: notifier.man 8999 2010-02-24 01:01:04Z mike $".
+.\"
diff --git a/man/ppdc.man b/man/ppdc.man
new file mode 100644
index 000000000..b613d4299
--- /dev/null
+++ b/man/ppdc.man
@@ -0,0 +1,80 @@
+.\"
+.\" "$Id: ppdc.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" ppdc man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2007 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH ppdc 1 "CUPS" "10 October 2008" "Apple Inc."
+.SH NAME
+ppdc \- cups ppd compiler
+.SH SYNOPSIS
+.B ppdc
+[ -D
+.I name[=value]
+] [ -I
+.I include-directory
+] [ -c
+.I message-catalog
+] [ -d
+.I output-directory
+] [ -l
+.I language(s)
+] [-m] [-t] [ -v ] [ -z ] [ --cr ] [ --crlf ] [ --lf ]
+.I source-file
+.SH DESCRIPTION
+\fIppdc\fR compiles PPDC source files into one or more PPD
+files.
+.PP
+The \fI-D\fR option sets the named variable for use in the
+source file. It is equivalent to using the #define directive
+in the source file.
+.PP
+The \fI-I\fR option specifies an alternate include directory;
+multiple \fI-I\fR options can be supplied to add additional
+directories.
+.PP
+The \fI-c\fR option specifies a single message catalog file in GNU
+gettext source format (filename.po) to be used for localization.
+.PP
+The \fI-d\fR option specifies the output directory for PPD
+files. The default output directory is "ppd".
+.PP
+The \fI-l\fR option specifies one or more languages to use when
+localizing the PPD file(s). The default language is "en"
+(English). Separate multiple languages with commas, for example
+"de_DE,en_UK,es_ES,es_MX,es_US,fr_CA,fr_FR,it_IT" will create PPD
+files with German, UK English, Spanish (Spain, Mexico, and US),
+French (France and Canada), and Italian languages in each file.
+.PP
+The \fI-m\fR option specifies that the output filename should be
+based on the ModelName value instead of FileName or PCFilenName.
+.PP
+The \fI-t\fR option specifies that PPD files should be tested instead
+of generated.
+.PP
+The \fI-v\fR option provides more verbose output, basically a
+running status of which files are being loaded or written.
+.PP
+The \fI-z\fR option generates compressed PPD files (filename.ppd.gz).
+The default is to generate uncompressed PPD files.
+.PP
+The \fI--cr\fR, \fI--crlf\fR, and \fI--lf\fR options specify the
+line ending to use - carriage return, carriage return and line feed,
+or line feed. The default is to use the line feed character alone.
+.SH SEE ALSO
+ppdhtml(1), ppdi(1), ppdmerge(1), ppdpo(1), ppdcfile(5)
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: ppdc.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/ppdcfile.man b/man/ppdcfile.man
new file mode 100644
index 000000000..fbd635866
--- /dev/null
+++ b/man/ppdcfile.man
@@ -0,0 +1,171 @@
+.\"
+.\" "$Id: ppdcfile.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" ppdcfile man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2007 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH ppdcfile 5 "CUPS" "20 May 2008" "Apple Inc."
+.SH NAME
+ppdcfile \- cups ppd compiler source file format
+.SH DESCRIPTION
+The CUPS PPD compiler reads meta files that contain descriptions
+of one or more PPD files to be generated by \fIppdc\fR. This man
+page provides a quick reference to the supported keywords and
+should be used in conjuction with the Common UNIX Printing System
+Developers Manual.
+.PP
+The source file format is plain ASCII text that can be edited
+using your favorite text editor. Comments are supported using
+the C (/* ... */) and C++ (// ...) comment mechanisms.
+.PP
+Printer driver information can be grouped and shared using
+curley braces ({ ... }); PPD files are written when a close
+brace or end-of-file is seen and a PCFileName directive has been
+defined.
+.PP
+Directives may be placed anywhere on a line and are followed by
+one or more values. The following is a list of the available
+directives and the values they accept:
+.TP 5
+\fB#define\fR name value
+.TP 5
+\fB#elif\fR {name | value}
+.TP 5
+\fB#else\fR
+.TP 5
+\fB#endif\fR
+.TP 5
+\fB#font\fR name encoding "version" charset status
+.TP 5
+\fB#if\fR {name | value}
+.TP 5
+\fB#include\fR <filename>
+.TP 5
+\fB#include\fR "filename"
+.TP 5
+\fB#media\fR name width length
+.TP 5
+\fB#media\fR "name/text" width length
+.TP 5
+\fB#po\fR locale "filename.po"
+.TP 5
+\fBAttribute\fR name "" value
+.TP 5
+\fBAttribute\fR name keyword value
+.TP 5
+\fBAttribute\fR name "keyword/text" value
+.TP 5
+\fBChoice\fR name "code"
+.TP 5
+\fBChoice\fR "name/text" "code"
+.TP 5
+\fBColorDevice\fR boolean-value
+.TP 5
+\fBColorModel\fR name colorspace colororder compression
+.TP 5
+\fBColorModel\fR "name/text" colorspace colororder compression
+.TP 5
+\fBColorProfile\fR resolution/mediatype gamma density matrix
+.TP 5
+\fBCopyright\fR "text"
+.TP 5
+\fBCustomMedia\fR name width length left bottom right top "size-code" "region-code"
+.TP 5
+\fBCustomMedia\fR "name/text" width length left bottom right top "size-code" "region-code"
+.TP 5
+\fBCutter\fR boolean-value
+.TP 5
+\fBDarkness\fR temperature name
+.TP 5
+\fBDarkness\fR temperature "name/text"
+.TP 5
+\fBDriverType\fR type
+.TP 5
+\fBDuplex\fR type
+.TP 5
+\fBFilter\fR mime-type cost program
+.TP 5
+\fBFinishing\fR name
+.TP 5
+\fBFinishing\fR "name/text"
+.TP 5
+\fBFont\fR *
+.TP 5
+\fBFont\fR name encoding "version" charset status
+.TP 5
+\fBGroup\fR name
+.TP 5
+\fBGroup\fR "name/text"
+.TP 5
+\fBHWMargins\fR left bottom right top
+.TP 5
+\fBInputSlot\fR position name
+.TP 5
+\fBInputSlot\fR position "name/text"
+.TP 5
+\fBInstallable\fR name
+.TP 5
+\fBInstallable\fR "name/text"
+.TP 5
+\fBLocAttribute\fR name "keyword/text" value
+.TP 5
+\fBManualCopies\fR boolean-value
+.TP 5
+\fBManufacturer\fR "name"
+.TP 5
+\fBMaxSize\fR width length
+.TP 5
+\fBMediaSize\fR name
+.TP 5
+\fBMediaType\fR type name
+.TP 5
+\fBMediaType\fR type "name/text"
+.TP 5
+\fBMinSize\fR width length
+.TP 5
+\fBModelName\fR "name"
+.TP 5
+\fBModelNumber\fR number
+.TP 5
+\fBOption\fR name type section order
+.TP 5
+\fBOption\fR "name/text" type section order
+.TP 5
+\fBPCFileName\fR "filename.ppd"
+.TP 5
+\fBResolution\fR colorspace bits-per-color row-count row-feed row-step name
+.TP 5
+\fBResolution\fR colorspace bits-per-color row-count row-feed row-step "name/text"
+.TP 5
+\fBSimpleColorProfile\fR resolution/mediatype density yellow-density red-density gamma red-adjust green-adjust blue-adjust
+.TP 5
+\fBThroughput\fR pages-per-minute
+.TP 5
+\fBUIConstraints\fR "*Option1 *Option2"
+.TP 5
+\fBUIConstraints\fR "*Option1 Choice1 *Option2"
+.TP 5
+\fBUIConstraints\fR "*Option1 *Option2 Choice2"
+.TP 5
+\fBUIConstraints\fR "*Option1 Choice1 *Option2 Choice2"
+.TP 5
+\fBVariablePaperSize\fR boolean-value
+.TP 5
+\fBVersion\fR number
+.SH SEE ALSO
+ppdc(1), ppdhtml(1), ppdi(1), ppdmerge(1), ppdpo(1)
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: ppdcfile.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/ppdhtml.man b/man/ppdhtml.man
new file mode 100644
index 000000000..bebf4e1e9
--- /dev/null
+++ b/man/ppdhtml.man
@@ -0,0 +1,46 @@
+.\"
+.\" "$Id: ppdhtml.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" ppdhtml man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2007 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH ppdhtml 1 "CUPS" "10 October 2008" "Apple Inc."
+.SH NAME
+ppdhtml \- cups html summary generator
+.SH SYNOPSIS
+.B ppdhtml
+[ -D
+.I name[=value]
+] [ -I
+.I include-directory
+]
+.I source-file
+.SH DESCRIPTION
+\fIppdhtml\fR reads a driver information file and produces a
+HTML summary page that lists all of the drivers in a file and
+the supported options.
+.PP
+The \fI-D\fR option sets the named variable for use in the
+source file. It is equivalent to using the #define directive
+in the source file.
+.PP
+The \fI-I\fR option specifies an alternate include directory;
+multiple \fI-I\fR options can be supplied to add additional
+directories.
+.SH SEE ALSO
+ppdc(1), ppdcfile(5), ppdi(1), ppdmerge(1), ppdpo(1)
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: ppdhtml.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/ppdi.man b/man/ppdi.man
new file mode 100644
index 000000000..610d91cd6
--- /dev/null
+++ b/man/ppdi.man
@@ -0,0 +1,46 @@
+.\"
+.\" "$Id: ppdi.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" ppdi man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2007 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH ppdi 1 "CUPS" "20 May 2008" "Apple Inc."
+.SH NAME
+ppdi \- import ppd files
+.SH SYNOPSIS
+.B ppdi
+[ \-I
+.I include-directory
+] [ \-o
+.I source-file
+]
+.I ppd-file
+[
+.I ppd-file2 ... ppd-fileN
+]
+.SH DESCRIPTION
+\fIppdi\fR imports one or more PPD files into a PPD compiler source file.
+Multiple languages of the same PPD file are merged into a single printer
+definition to facilitate accurate changes for all localizations.
+.PP
+The \fI-o\fR option specifies the PPD source file to update. If the source
+file does not exist, a new source file is created. Otherwise the existing
+file is merged with the new PPD file(s) on the command-line. If no source
+file is specified, the filename "ppdi.drv" is used.
+.SH SEE ALSO
+ppdc(1), ppdhtml(1), ppdmerge(1), ppdpo(1), ppdcfile(5)
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: ppdi.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/ppdmerge.man b/man/ppdmerge.man
new file mode 100644
index 000000000..90fee820c
--- /dev/null
+++ b/man/ppdmerge.man
@@ -0,0 +1,47 @@
+.\"
+.\" "$Id: ppdmerge.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" ppdmerge man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2007 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH ppdmerge 1 "CUPS" "20 May 2008" "Apple Inc."
+.SH NAME
+ppdmerge \- merge ppd files
+.SH SYNOPSIS
+.B ppdmerge
+[ \-o
+.I output-ppd-file
+]
+.I ppd-file
+.I ppd-file2
+[
+.I ... ppd-fileN
+]
+.SH DESCRIPTION
+\fIppdmerge\fR merges two or more PPD files into a single, multi-language
+PPD file.
+.PP
+The \fI-o\fR option specifies the PPD file to create. If not specified,
+the merged PPD file is written to the standard output. If the output file
+already exists, the new
+.SH NOTES
+\fIppdmerge\fR does not check whether the merged PPD files are for the
+same device. Merging of different device PPDs will yield unpredictable
+results.
+.SH SEE ALSO
+cupsprofile(1), ppdc(1), ppdhtml(1), ppdi(1), ppdpo(1), ppdcfile(5)
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: ppdmerge.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/ppdpo.man b/man/ppdpo.man
new file mode 100644
index 000000000..a3f9ac9b2
--- /dev/null
+++ b/man/ppdpo.man
@@ -0,0 +1,52 @@
+.\"
+.\" "$Id: ppdpo.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" ppdpo man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2007 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH ppdpo 1 "CUPS" "10 October 2008" "Apple Inc."
+.SH NAME
+ppdpo \- ppd message catalog generator
+.SH SYNOPSIS
+.B ppdpo
+[ -D
+.I name[=value]
+] [ -I
+.I include-directory
+] [ -o
+.I output-file
+]
+.I source-file
+.SH DESCRIPTION
+\fIppdpo\fR extracts UI strings from PPDC source files and updates either
+a GNU gettext or Mac OS X strings format message catalog source file for
+translation.
+.PP
+The \fI-D\fR option sets the named variable for use in the
+source file. It is equivalent to using the #define directive
+in the source file.
+.PP
+The \fI-I\fR option specifies an alternate include directory;
+multiple \fI-I\fR options can be supplied to add additional
+directories.
+.PP
+The \fI-o\fR option specifies the output file. The supported extensions are
+".po" or ".po.gz" for GNU gettext format message catalogs and ".strings" for
+Mac OS X strings files.
+.SH SEE ALSO
+ppdc(1), ppdhtml(1), ppdi(1), ppdmerge(1), ppdcfile(5)
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: ppdpo.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/printers.conf.man b/man/printers.conf.man
new file mode 100644
index 000000000..abda49b26
--- /dev/null
+++ b/man/printers.conf.man
@@ -0,0 +1,124 @@
+.\"
+.\" "$Id: printers.conf.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" printers.conf man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 1997-2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH printers.conf 5 "CUPS" "29 April 2009" "Apple Inc."
+.SH NAME
+printers.conf \- printer configuration file for cups
+.SH DESCRIPTION
+The \fIprinters.conf\fR file defines the local printers that are
+available. It is normally located in the \fI/etc/cups\fR directory and
+is generated automatically by the \fIcupsd(8)\fR program when printers
+are added or deleted.
+.LP
+Each line in the file can be a configuration directive, a blank line,
+or a comment. Comment lines start with the # character.
+.SH DIRECTIVES
+.TP 5
+<Printer name> ... </Printer>
+.br
+Defines a specific printer.
+.TP 5
+<DefaultPrinter name> ... </Printer>
+.br
+Defines a default printer.
+.TP 5
+Accepting Yes
+.TP 5
+Accepting No
+.br
+Specifies whether the printer is accepting new jobs.
+.TP 5
+AllowUser [ user @group ... ]
+.br
+Allows specific users and groups to print to the printer.
+.TP 5
+DenyUser [ user @group ... ]
+.br
+Prevents specific users and groups from printing to the printer.
+.TP 5
+DeviceURI uri
+.br
+Specifies the device URI for a printer.
+.TP 5
+ErrorPolicy abort-job
+.TP 5
+ErrorPolicy retry-current-job
+.TP 5
+ErrorPolicy retry-job
+.TP 5
+ErrorPolicy stop-printer
+.br
+Specifies the error policy for the printer.
+.TP 5
+Info text
+.br
+Specifies human-readable text describing the printer.
+.TP 5
+JobSheets banner banner
+.br
+Specifies the banner pages to use for the printer.
+.TP 5
+KLimit number
+.br
+Specifies the job-k-limit value for the printer.
+.TP 5
+Location text
+.br
+Specifies human-readable text describing the location of the printer.
+.TP 5
+OpPolicy name
+.br
+Specifies the operation policy for the printer.
+.TP 5
+PageLimit number
+.br
+Specifies the job-page-limit value for the printer.
+.TP 5
+PortMonitor monitor
+.br
+Specifies the port monitor for a printer.
+.TP 5
+QuotaPeriod seconds
+.br
+Specifies the job-quota-period value for the printer.
+.TP 5
+Shared Yes
+.TP 5
+Shared No
+.br
+Specifies whether the printer is shared.
+.TP 5
+State idle
+.TP 5
+State stopped
+.br
+Specifies the initial state of the printer (Idle or Stopped)
+.TP 5
+StateMessage text
+.br
+Specifies the message associated with the state.
+.TP 5
+StateTime seconds
+.br
+Specifies the date/time associated with the state.
+.SH SEE ALSO
+\fIclasses.conf(5)\fR, \fIcupsd(8)\fR, \fIcupsd.conf(5)\fR,
+\fImime.convs(5)\fR, \fImime.types(5)\fR,
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: printers.conf.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/man/subscriptions.conf.man b/man/subscriptions.conf.man
new file mode 100644
index 000000000..4ff851cb9
--- /dev/null
+++ b/man/subscriptions.conf.man
@@ -0,0 +1,89 @@
+.\"
+.\" "$Id: subscriptions.conf.man 9771 2011-05-12 05:21:56Z mike $"
+.\"
+.\" subscriptions.conf man page for CUPS.
+.\"
+.\" Copyright 2007-2011 by Apple Inc.
+.\" Copyright 2006 by Easy Software Products.
+.\"
+.\" These coded instructions, statements, and computer programs are the
+.\" property of Apple Inc. 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
+.\" file is missing or damaged, see the license at "http://www.cups.org/".
+.\"
+.TH subscriptions.conf 5 "CUPS" "30 April 2006" "Apple Inc."
+.SH NAME
+subscriptions.conf \- subscriptions file for cups
+.SH DESCRIPTION
+The \fIsubscriptions.conf\fR file defines the local subscriptions
+that are active. It is normally located in the \fI/etc/cups\fR
+directory and is generated automatically by the \fIcupsd(8)\fR
+program when subscriptions are created, renewed, or cancelled.
+.LP
+Each line in the file can be a configuration directive, a blank line,
+or a comment. Comment lines start with the # character.
+.SH DIRECTIVES
+.TP 5
+<Subscription NNN> ... </Subscription>
+.br
+Defines a subscription.
+.TP 5
+Events name [ ... name ]
+.br
+Specifies the events that are subscribed.
+.TP 5
+ExpirationTime unix-time
+.br
+Specifies the expiration time of a subscription as a UNIX time
+value in seconds since January 1st, 1970.
+.TP 5
+Interval seconds
+.br
+Specifies the preferred time interval for event notifications in
+seconds.
+.TP 5
+JobId job-id
+.br
+Specifies the job ID associated with the subscription.
+.TP 5
+LeaseDuration seconds
+.br
+Specifies the number of seconds that the subscription is valid
+for. If 0, the subscription does not expire.
+.TP 5
+NextEventId number
+.br
+Specifies the next notify-sequence-number to use for the
+subscription.
+.TP 5
+NextSubscriptionId number
+.br
+Specifies the next subscription-id to use.
+.TP 5
+Owner username
+.br
+Specifies the user that owns the subscription.
+.TP 5
+PrinterName printername
+.br
+Specifies the printer or class associated with the subscription.
+.TP 5
+Recipient uri
+.br
+Specifies the notify-recipient-uri value for push-type notifications.
+.TP 5
+UserData hex-escaped-data
+.br
+Specifies user data to be included in event notifications. This
+is typically the "from" address in mailto: notifications.
+.SH SEE ALSO
+\fIclasses.conf(5)\fR, \fIcupsd(8)\fR, \fIcupsd.conf(5)\fR,
+\fImime.convs(5)\fR, \fImime.types(5)\fR, \fRprinters.conf(5)\fR
+.br
+http://localhost:631/help
+.SH COPYRIGHT
+Copyright 2007-2011 by Apple Inc.
+.\"
+.\" End of "$Id: subscriptions.conf.man 9771 2011-05-12 05:21:56Z mike $".
+.\"
diff --git a/monitor/Dependencies b/monitor/Dependencies
new file mode 100644
index 000000000..005e3eb1e
--- /dev/null
+++ b/monitor/Dependencies
@@ -0,0 +1,18 @@
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+bcp.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+bcp.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+bcp.o: ../cups/language.h ../cups/string-private.h ../config.h
+bcp.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+bcp.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+bcp.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+bcp.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+bcp.o: ../cups/thread-private.h
+tbcp.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+tbcp.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+tbcp.o: ../cups/language.h ../cups/string-private.h ../config.h
+tbcp.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+tbcp.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+tbcp.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+tbcp.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+tbcp.o: ../cups/thread-private.h
diff --git a/monitor/Makefile b/monitor/Makefile
new file mode 100644
index 000000000..92ee413bd
--- /dev/null
+++ b/monitor/Makefile
@@ -0,0 +1,146 @@
+#
+# "$Id$"
+#
+# Port monitor makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 2006 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# This file is subject to the Apple OS-Developed Software exception.
+#
+
+include ../Makedefs
+
+TARGETS = bcp tbcp
+
+OBJS = bcp.o tbcp.o
+
+
+#
+# Make all targets...
+#
+
+all: $(TARGETS)
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# 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-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+
+
+#
+# Install programs...
+#
+
+install-exec:
+ $(INSTALL_DIR) -m 755 $(SERVERBIN)/monitor
+ for file in $(TARGETS); do \
+ $(INSTALL_BIN) $$file $(SERVERBIN)/monitor; \
+ done
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ for file in $(TARGETS); do \
+ cp $$file $(SYMROOT); \
+ done \
+ fi
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall all targets...
+#
+
+uninstall:
+ for file in $(TARGETS); do \
+ $(RM) $(SERVERBIN)/monitor/$$file; \
+ done
+ -$(RMDIR) $(SERVERBIN)/monitor
+ -$(RMDIR) $(SERVERBIN)
+
+
+#
+# bcp
+#
+
+bcp: bcp.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ bcp.o $(LIBS)
+
+
+#
+# tbcp
+#
+
+tbcp: tbcp.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ tbcp.o $(LIBS)
+
+
+#
+# Dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id$".
+#
diff --git a/monitor/bcp.c b/monitor/bcp.c
new file mode 100644
index 000000000..2354d102d
--- /dev/null
+++ b/monitor/bcp.c
@@ -0,0 +1,292 @@
+/*
+ * "$Id$"
+ *
+ * TBCP port monitor for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry...
+ * psgets() - Get a line from a file.
+ * pswrite() - Write data from a file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include <cups/ppd.h>
+
+
+/*
+ * Local functions...
+ */
+
+static char *psgets(char *buf, size_t *bytes, FILE *fp);
+static size_t pswrite(const char *buf, size_t bytes, FILE *fp);
+
+
+/*
+ * 'main()' - Main entry...
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ FILE *fp; /* File to print */
+ int copies; /* Number of copies left */
+ char line[1024]; /* Line/buffer from stream/file */
+ size_t linelen; /* Length of line */
+ ppd_file_t *ppd; /* PPD file */
+
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options [file]"),
+ argv[0]);
+ return (1);
+ }
+
+ if (argc == 6)
+ {
+ copies = 1;
+ fp = stdin;
+ }
+ else
+ {
+ copies = atoi(argv[4]);
+ fp = fopen(argv[6], "rb");
+
+ if (!fp)
+ {
+ perror(argv[6]);
+ return (1);
+ }
+ }
+
+ /*
+ * Open the PPD file as needed...
+ */
+
+ ppd = ppdOpenFile(getenv("PPD"));
+
+ /*
+ * Copy the print file to stdout...
+ */
+
+ while (copies > 0)
+ {
+ copies --;
+
+ if (ppd && ppd->jcl_begin)
+ fputs(ppd->jcl_begin, stdout);
+ if (ppd && ppd->jcl_ps)
+ fputs(ppd->jcl_ps, stdout);
+
+ if (!ppd || ppd->language_level == 1)
+ {
+ /*
+ * Use setsoftwareiomode for BCP mode...
+ */
+
+ puts("%!PS-Adobe-3.0 ExitServer");
+ puts("%%Title: (BCP - Level 1)");
+ puts("%%EndComments");
+ puts("%%BeginExitServer: 0");
+ puts("serverdict begin 0 exitserver");
+ puts("%%EndExitServer");
+ puts("statusdict begin");
+ puts("/setsoftwareiomode known {100 setsoftwareiomode}");
+ puts("end");
+ puts("%EOF");
+ }
+ else
+ {
+ /*
+ * Use setdevparams for BCP mode...
+ */
+
+ puts("%!PS-Adobe-3.0");
+ puts("%%Title: (BCP - Level 2)");
+ puts("%%EndComments");
+ puts("currentsysparams");
+ puts("/CurInputDevice 2 copy known {");
+ puts("get");
+ puts("<</Protocol /Binary>> setdevparams");
+ puts("}{");
+ puts("pop pop");
+ puts("} ifelse");
+ puts("%EOF");
+ }
+
+ if (ppd && ppd->jcl_end)
+ fputs(ppd->jcl_end, stdout);
+ else if (!ppd || ppd->num_filters == 0)
+ putchar(0x04);
+
+ /*
+ * Loop until we see end-of-file...
+ */
+
+ do
+ {
+ linelen = sizeof(line);
+ if (psgets(line, &linelen, fp) == NULL)
+ break;
+ }
+ while (pswrite(line, linelen, stdout) > 0);
+
+ fflush(stdout);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'psgets()' - Get a line from a file.
+ *
+ * Note:
+ *
+ * This function differs from the gets() function in that it
+ * handles any combination of CR, LF, or CR LF to end input
+ * lines.
+ */
+
+static char * /* O - String or NULL if EOF */
+psgets(char *buf, /* I - Buffer to read into */
+ size_t *bytes, /* IO - Length of buffer */
+ FILE *fp) /* I - File to read from */
+{
+ char *bufptr; /* Pointer into buffer */
+ int ch; /* Character from file */
+ size_t len; /* Max length of string */
+
+
+ len = *bytes - 1;
+ bufptr = buf;
+ ch = EOF;
+
+ while ((bufptr - buf) < len)
+ {
+ if ((ch = getc(fp)) == EOF)
+ break;
+
+ if (ch == '\r')
+ {
+ /*
+ * Got a CR; see if there is a LF as well...
+ */
+
+ ch = getc(fp);
+
+ if (ch != EOF && ch != '\n')
+ {
+ ungetc(ch, fp); /* Nope, save it for later... */
+ ch = '\r';
+ }
+ else
+ *bufptr++ = '\r';
+ break;
+ }
+ else if (ch == '\n')
+ break;
+ else
+ *bufptr++ = ch;
+ }
+
+ /*
+ * Add a trailing newline if it is there...
+ */
+
+ if (ch == '\n' || ch == '\r')
+ {
+ if ((bufptr - buf) < len)
+ *bufptr++ = ch;
+ else
+ ungetc(ch, fp);
+ }
+
+ /*
+ * Nul-terminate the string and return it (or NULL for EOF).
+ */
+
+ *bufptr = '\0';
+ *bytes = bufptr - buf;
+
+ if (ch == EOF && bufptr == buf)
+ return (NULL);
+ else
+ return (buf);
+}
+
+
+/*
+ * 'pswrite()' - Write data from a file.
+ */
+
+static size_t /* O - Number of bytes written */
+pswrite(const char *buf, /* I - Buffer to write */
+ size_t bytes, /* I - Bytes to write */
+ FILE *fp) /* I - File to write to */
+{
+ size_t count; /* Remaining bytes */
+
+
+ for (count = bytes; count > 0; count --, buf ++)
+ switch (*buf)
+ {
+ case 0x04 : /* CTRL-D */
+ if (bytes == 1)
+ {
+ /*
+ * Don't quote the last CTRL-D...
+ */
+
+ putchar(0x04);
+ break;
+ }
+
+ case 0x01 : /* CTRL-A */
+ case 0x03 : /* CTRL-C */
+ case 0x05 : /* CTRL-E */
+ case 0x11 : /* CTRL-Q */
+ case 0x13 : /* CTRL-S */
+ case 0x14 : /* CTRL-T */
+ case 0x1c : /* CTRL-\ */
+ if (putchar(0x01) < 0)
+ return (-1);
+ if (putchar(*buf ^ 0x40) < 0)
+ return (-1);
+ break;
+
+ default :
+ if (putchar(*buf) < 0)
+ return (-1);
+ break;
+ }
+
+ return (bytes);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/monitor/tbcp.c b/monitor/tbcp.c
new file mode 100644
index 000000000..250a00302
--- /dev/null
+++ b/monitor/tbcp.c
@@ -0,0 +1,285 @@
+/*
+ * "$Id$"
+ *
+ * TBCP port monitor for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1993-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry...
+ * psgets() - Get a line from a file.
+ * pswrite() - Write data from a file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include <cups/ppd.h>
+
+
+/*
+ * Local functions...
+ */
+
+static char *psgets(char *buf, size_t *bytes, FILE *fp);
+static size_t pswrite(const char *buf, size_t bytes, FILE *fp);
+
+
+/*
+ * 'main()' - Main entry...
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ FILE *fp; /* File to print */
+ int copies; /* Number of copies left */
+ char line[1024]; /* Line/buffer from stream/file */
+ size_t linelen; /* Length of line */
+
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options [file]"),
+ argv[0]);
+ return (1);
+ }
+
+ if (argc == 6)
+ {
+ copies = 1;
+ fp = stdin;
+ }
+ else
+ {
+ copies = atoi(argv[4]);
+ fp = fopen(argv[6], "rb");
+
+ if (!fp)
+ {
+ perror(argv[6]);
+ return (1);
+ }
+ }
+
+ /*
+ * Copy the print file to stdout...
+ */
+
+ while (copies > 0)
+ {
+ copies --;
+
+ /*
+ * Read the first line...
+ */
+
+ linelen = sizeof(line);
+ if (psgets(line, &linelen, fp) == NULL)
+ {
+ fputs("ERROR: Empty print file!\n", stderr);
+ return (1);
+ }
+
+ /*
+ * Handle leading PJL fun...
+ */
+
+ if (!strncmp(line, "\033%-12345X", 9) || !strncmp(line, "@PJL ", 5))
+ {
+ /*
+ * Yup, we have leading PJL fun, so copy it until we hit a line
+ * with "ENTER LANGUAGE"...
+ */
+
+ while (strstr(line, "ENTER LANGUAGE") == NULL)
+ {
+ fwrite(line, 1, linelen, stdout);
+
+ linelen = sizeof(line);
+ if (psgets(line, &linelen, fp) == NULL)
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * No PJL stuff, just add the UEL...
+ */
+
+ fputs("\033%-12345X", stdout);
+ }
+
+ /*
+ * Switch to TBCP mode...
+ */
+
+ fputs("\001M", stdout);
+
+ /*
+ * Loop until we see end-of-file...
+ */
+
+ while (pswrite(line, linelen, stdout) > 0)
+ {
+ linelen = sizeof(line);
+ if (psgets(line, &linelen, fp) == NULL)
+ break;
+ }
+
+ fflush(stdout);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'psgets()' - Get a line from a file.
+ *
+ * Note:
+ *
+ * This function differs from the gets() function in that it
+ * handles any combination of CR, LF, or CR LF to end input
+ * lines.
+ */
+
+static char * /* O - String or NULL if EOF */
+psgets(char *buf, /* I - Buffer to read into */
+ size_t *bytes, /* IO - Length of buffer */
+ FILE *fp) /* I - File to read from */
+{
+ char *bufptr; /* Pointer into buffer */
+ int ch; /* Character from file */
+ size_t len; /* Max length of string */
+
+
+ len = *bytes - 1;
+ bufptr = buf;
+ ch = EOF;
+
+ while ((bufptr - buf) < len)
+ {
+ if ((ch = getc(fp)) == EOF)
+ break;
+
+ if (ch == '\r')
+ {
+ /*
+ * Got a CR; see if there is a LF as well...
+ */
+
+ ch = getc(fp);
+
+ if (ch != EOF && ch != '\n')
+ {
+ ungetc(ch, fp); /* Nope, save it for later... */
+ ch = '\r';
+ }
+ else
+ *bufptr++ = '\r';
+ break;
+ }
+ else if (ch == '\n')
+ break;
+ else
+ *bufptr++ = ch;
+ }
+
+ /*
+ * Add a trailing newline if it is there...
+ */
+
+ if (ch == '\n' || ch == '\r')
+ {
+ if ((bufptr - buf) < len)
+ *bufptr++ = ch;
+ else
+ ungetc(ch, fp);
+ }
+
+ /*
+ * Nul-terminate the string and return it (or NULL for EOF).
+ */
+
+ *bufptr = '\0';
+ *bytes = bufptr - buf;
+
+ if (ch == EOF && bufptr == buf)
+ return (NULL);
+ else
+ return (buf);
+}
+
+
+/*
+ * 'pswrite()' - Write data from a file.
+ */
+
+static size_t /* O - Number of bytes written */
+pswrite(const char *buf, /* I - Buffer to write */
+ size_t bytes, /* I - Bytes to write */
+ FILE *fp) /* I - File to write to */
+{
+ size_t count; /* Remaining bytes */
+
+
+ for (count = bytes; count > 0; count --, buf ++)
+ switch (*buf)
+ {
+ case 0x04 : /* CTRL-D */
+ if (bytes == 1)
+ {
+ /*
+ * Don't quote the last CTRL-D...
+ */
+
+ putchar(0x04);
+ break;
+ }
+
+ case 0x01 : /* CTRL-A */
+ case 0x03 : /* CTRL-C */
+ case 0x05 : /* CTRL-E */
+ case 0x11 : /* CTRL-Q */
+ case 0x13 : /* CTRL-S */
+ case 0x14 : /* CTRL-T */
+ case 0x1b : /* CTRL-[ (aka ESC) */
+ case 0x1c : /* CTRL-\ */
+ if (putchar(0x01) < 0)
+ return (-1);
+ if (putchar(*buf ^ 0x40) < 0)
+ return (-1);
+ break;
+
+ default :
+ if (putchar(*buf) < 0)
+ return (-1);
+ break;
+ }
+
+ return (bytes);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/notifier/Dependencies b/notifier/Dependencies
new file mode 100644
index 000000000..5f48964f6
--- /dev/null
+++ b/notifier/Dependencies
@@ -0,0 +1,24 @@
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+dbus.o: ../cups/cups.h ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+dbus.o: ../cups/http.h ../cups/array.h ../cups/language.h
+dbus.o: ../cups/string-private.h ../config.h
+mailto.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+mailto.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+mailto.o: ../cups/language.h ../cups/string-private.h ../config.h
+mailto.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+mailto.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+mailto.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+mailto.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+mailto.o: ../cups/thread-private.h
+rss.o: ../cups/cups.h ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+rss.o: ../cups/http.h ../cups/array.h ../cups/language.h ../cups/language.h
+rss.o: ../cups/string-private.h ../config.h ../cups/array.h
+testnotify.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+testnotify.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+testnotify.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+testnotify.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+testnotify.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+testnotify.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+testnotify.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+testnotify.o: ../cups/transcode.h ../cups/thread-private.h
diff --git a/notifier/Makefile b/notifier/Makefile
new file mode 100644
index 000000000..cfbff5e1e
--- /dev/null
+++ b/notifier/Makefile
@@ -0,0 +1,162 @@
+#
+# "$Id$"
+#
+# Notifier makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2007 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+
+NOTIFIERS = $(DBUS_NOTIFIER) mailto rss
+TARGETS = $(NOTIFIERS) testnotify
+OBJS = dbus.o mailto.o rss.o testnotify.o
+
+
+#
+# Make all targets...
+#
+
+all: $(TARGETS)
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Clean all object files...
+#
+
+clean:
+ $(RM) $(OBJS) $(TARGETS) dbus.h
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+ $(INSTALL_DIR) -m 775 -g $(CUPS_GROUP) $(CACHEDIR)/rss
+
+
+#
+# Install programs...
+#
+
+install-exec:
+ echo Installing notifiers in $(SERVERBIN)/notifier...
+ $(INSTALL_DIR) -m 755 $(SERVERBIN)/notifier
+ for file in $(NOTIFIERS); do \
+ $(INSTALL_BIN) $$file $(SERVERBIN)/notifier; \
+ done
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ cp $(NOTIFIERS) $(SYMROOT); \
+ fi
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall all targets...
+#
+
+uninstall:
+ for file in $(NOTIFIERS); do \
+ $(RM) $(SERVERBIN)/notifier/$$file; \
+ done
+ -$(RMDIR) $(SERVERBIN)/notifier
+ -$(RMDIR) $(SERVERBIN)
+ -$(RMDIR) $(CACHEDIR)/rss
+
+
+#
+# Update dependencies (without system header dependencies...)
+#
+
+depend:
+ makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1
+
+
+#
+# dbus
+#
+
+dbus: dbus.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o dbus dbus.o $(DBUS_NOTIFIERLIBS) $(LIBS)
+
+
+#
+# mailto
+#
+
+mailto: mailto.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o mailto mailto.o $(LIBS)
+
+
+#
+# rss
+#
+
+rss: rss.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o rss rss.o $(LIBS)
+
+
+#
+# testnotify
+#
+
+testnotify: testnotify.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o testnotify testnotify.o $(LIBS)
+
+
+$(OBJS): ../Makedefs
+
+include Dependencies
+
+
+#
+# End of "$Id$".
+#
diff --git a/notifier/dbus.c b/notifier/dbus.c
new file mode 100644
index 000000000..542a929da
--- /dev/null
+++ b/notifier/dbus.c
@@ -0,0 +1,552 @@
+/*
+ * "$Id$"
+ *
+ * D-Bus notifier for CUPS.
+ *
+ * Copyright 2008-2010 by Apple Inc.
+ * Copyright (C) 2007 Red Hat, Inc.
+ * Copyright (C) 2007 Tim Waugh <twaugh@redhat.com>
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Read events and send DBUS notifications.
+ * acquire_lock() - Acquire a lock so we only have a single notifier running.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <cups/string-private.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <dbus/dbus.h>
+#ifdef HAVE_DBUS_MESSAGE_ITER_INIT_APPEND
+# define dbus_message_append_iter_init dbus_message_iter_init_append
+# define dbus_message_iter_append_string(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, v)
+# define dbus_message_iter_append_uint32(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, v)
+# define dbus_message_iter_append_boolean(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, v)
+#endif /* HAVE_DBUS_MESSAGE_ITER_INIT_APPEND */
+
+
+/*
+ * D-Bus object: org.cups.cupsd.Notifier
+ * D-Bus object path: /org/cups/cupsd/Notifier
+ *
+ * D-Bus interface name: org.cups.cupsd.Notifier
+ *
+ * Signals:
+ *
+ * ServerRestarted(STRING text)
+ * Server has restarted.
+ *
+ * ServerStarted(STRING text)
+ * Server has started.
+ *
+ * ServerStopped(STRING text)
+ * Server has stopped.
+ *
+ * ServerAudit(STRING text)
+ * Security-related event.
+ *
+ * PrinterRestarted(STRING text,
+ * STRING printer-uri,
+ * STRING printer-name,
+ * UINT32 printer-state,
+ * STRING printer-state-reasons,
+ * BOOLEAN printer-is-accepting-jobs)
+ * Printer has restarted.
+ *
+ * PrinterShutdown(STRING text,
+ * STRING printer-uri,
+ * STRING printer-name,
+ * UINT32 printer-state,
+ * STRING printer-state-reasons,
+ * BOOLEAN printer-is-accepting-jobs)
+ * Printer has shutdown.
+ *
+ * PrinterStopped(STRING text,
+ * STRING printer-uri,
+ * STRING printer-name,
+ * UINT32 printer-state,
+ * STRING printer-state-reasons,
+ * BOOLEAN printer-is-accepting-jobs)
+ * Printer has stopped.
+ *
+ * PrinterStateChanged(STRING text,
+ * STRING printer-uri,
+ * STRING printer-name,
+ * UINT32 printer-state,
+ * STRING printer-state-reasons,
+ * BOOLEAN printer-is-accepting-jobs)
+ * Printer state has changed.
+ *
+ * PrinterFinishingsChanged(STRING text,
+ * STRING printer-uri,
+ * STRING printer-name,
+ * UINT32 printer-state,
+ * STRING printer-state-reasons,
+ * BOOLEAN printer-is-accepting-jobs)
+ * Printer's finishings-supported attribute has changed.
+ *
+ * PrinterMediaChanged(STRING text,
+ * STRING printer-uri,
+ * STRING printer-name,
+ * UINT32 printer-state,
+ * STRING printer-state-reasons,
+ * BOOLEAN printer-is-accepting-jobs)
+ * Printer's media-supported attribute has changed.
+ *
+ * PrinterAdded(STRING text,
+ * STRING printer-uri,
+ * STRING printer-name,
+ * UINT32 printer-state,
+ * STRING printer-state-reasons,
+ * BOOLEAN printer-is-accepting-jobs)
+ * Printer has been added.
+ *
+ * PrinterDeleted(STRING text,
+ * STRING printer-uri,
+ * STRING printer-name,
+ * UINT32 printer-state,
+ * STRING printer-state-reasons,
+ * BOOLEAN printer-is-accepting-jobs)
+ * Printer has been deleted.
+ *
+ * PrinterModified(STRING text,
+ * STRING printer-uri,
+ * STRING printer-name,
+ * UINT32 printer-state,
+ * STRING printer-state-reasons,
+ * BOOLEAN printer-is-accepting-jobs)
+ * Printer has been modified.
+ *
+ * text describes the event.
+ * printer-state-reasons is a comma-separated list.
+ * If printer-uri is "" in a Job* signal, the other printer-* parameters
+ * must be ignored.
+ * If the job name is not know, job-name will be "".
+ */
+
+/*
+ * Constants...
+ */
+
+enum
+{
+ PARAMS_NONE,
+ PARAMS_PRINTER,
+ PARAMS_JOB
+};
+
+
+/*
+ * Local functions...
+ */
+
+static int acquire_lock(int *fd, char *lockfile, size_t locksize);
+
+
+/*
+ * 'main()' - Read events and send DBUS notifications.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ ipp_t *msg; /* Event message from scheduler */
+ ipp_state_t state; /* IPP event state */
+ struct sigaction action; /* POSIX sigaction data */
+ DBusConnection *con = NULL; /* Connection to DBUS server */
+ DBusError error; /* Error, if any */
+ DBusMessage *message; /* Message to send */
+ DBusMessageIter iter; /* Iterator for message data */
+ int lock_fd = -1; /* Lock file descriptor */
+ char lock_filename[1024];
+ /* Lock filename */
+
+
+ /*
+ * Don't buffer stderr...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Ignore SIGPIPE signals...
+ */
+
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+
+ /*
+ * Validate command-line options...
+ */
+
+ if (argc != 3)
+ {
+ fputs("Usage: dbus dbus:/// notify-user-data\n", stderr);
+ return (1);
+ }
+
+ if (strncmp(argv[1], "dbus:", 5))
+ {
+ fprintf(stderr, "ERROR: Bad URI \"%s\"!\n", argv[1]);
+ return (1);
+ }
+
+ /*
+ * Loop forever until we run out of events...
+ */
+
+ for (;;)
+ {
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *event; /* Event name */
+ const char *signame = NULL;/* DBUS signal name */
+ char *printer_reasons = NULL;
+ /* Printer reasons string */
+ const char *nul = ""; /* Empty string value */
+ int no = 0; /* Boolean "no" value */
+ int params = PARAMS_NONE;
+ /* What parameters to include? */
+
+
+ /*
+ * Get the next event...
+ */
+
+ msg = ippNew();
+ while ((state = ippReadFile(0, msg)) != IPP_DATA)
+ {
+ if (state <= IPP_IDLE)
+ break;
+ }
+
+ fprintf(stderr, "DEBUG: state=%d\n", state);
+
+ if (state == IPP_ERROR)
+ fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr);
+
+ if (state <= IPP_IDLE)
+ {
+ /*
+ * Out of messages, free memory and then exit...
+ */
+
+ ippDelete(msg);
+ break;
+ }
+
+ /*
+ * Verify connection to DBUS server...
+ */
+
+ if (con && !dbus_connection_get_is_connected(con))
+ {
+ dbus_connection_unref(con);
+ con = NULL;
+ }
+
+ if (!con)
+ {
+ dbus_error_init(&error);
+
+ con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+ if (!con)
+ dbus_error_free(&error);
+ else
+ fputs("DEBUG: Connected to D-BUS\n", stderr);
+ }
+
+ if (!con)
+ continue;
+
+ if (lock_fd == -1 &&
+ acquire_lock(&lock_fd, lock_filename, sizeof(lock_filename)))
+ continue;
+
+ attr = ippFindAttribute(msg, "notify-subscribed-event",
+ IPP_TAG_KEYWORD);
+ if (!attr)
+ continue;
+
+ event = attr->values[0].string.text;
+ if (!strncmp(event, "server-", 7))
+ {
+ const char *word2 = event + 7; /* Second word */
+
+ if (!strcmp(word2, "restarted"))
+ signame = "ServerRestarted";
+ else if (!strcmp(word2, "started"))
+ signame = "ServerStarted";
+ else if (!strcmp(word2, "stopped"))
+ signame = "ServerStopped";
+ else if (!strcmp(word2, "audit"))
+ signame = "ServerAudit";
+ else
+ continue;
+ }
+ else if (!strncmp(event, "printer-", 8))
+ {
+ const char *word2 = event + 8; /* Second word */
+
+ params = PARAMS_PRINTER;
+ if (!strcmp(word2, "restarted"))
+ signame = "PrinterRestarted";
+ else if (!strcmp(word2, "shutdown"))
+ signame = "PrinterShutdown";
+ else if (!strcmp(word2, "stopped"))
+ signame = "PrinterStopped";
+ else if (!strcmp(word2, "state-changed"))
+ signame = "PrinterStateChanged";
+ else if (!strcmp(word2, "finishings-changed"))
+ signame = "PrinterFinishingsChanged";
+ else if (!strcmp(word2, "media-changed"))
+ signame = "PrinterMediaChanged";
+ else if (!strcmp(word2, "added"))
+ signame = "PrinterAdded";
+ else if (!strcmp(word2, "deleted"))
+ signame = "PrinterDeleted";
+ else if (!strcmp(word2, "modified"))
+ signame = "PrinterModified";
+ else
+ continue;
+ }
+ else if (!strncmp(event, "job-", 4))
+ {
+ const char *word2 = event + 4; /* Second word */
+
+ params = PARAMS_JOB;
+ if (!strcmp(word2, "state-changed"))
+ signame = "JobState";
+ else if (!strcmp(word2, "created"))
+ signame = "JobCreated";
+ else if (!strcmp(word2, "completed"))
+ signame = "JobCompleted";
+ else if (!strcmp(word2, "stopped"))
+ signame = "JobStopped";
+ else if (!strcmp(word2, "config-changed"))
+ signame = "JobConfigChanged";
+ else if (!strcmp(word2, "progress"))
+ signame = "JobProgress";
+ else
+ continue;
+ }
+ else
+ continue;
+
+ /*
+ * Create and send the new message...
+ */
+
+ fprintf(stderr, "DEBUG: %s\n", signame);
+ message = dbus_message_new_signal("/org/cups/cupsd/Notifier",
+ "org.cups.cupsd.Notifier",
+ signame);
+
+ dbus_message_append_iter_init(message, &iter);
+ attr = ippFindAttribute(msg, "notify-text", IPP_TAG_TEXT);
+ if (!attr)
+ goto bail;
+ dbus_message_iter_append_string(&iter, &(attr->values[0].string.text));
+
+ if (params >= PARAMS_PRINTER)
+ {
+ char *p; /* Pointer into printer_reasons */
+ size_t reasons_length; /* Required size of printer_reasons */
+ int i; /* Looping var */
+ int have_printer_params = 1;/* Do we have printer URI? */
+
+ /* STRING printer-uri or "" */
+ attr = ippFindAttribute(msg, "notify-printer-uri", IPP_TAG_URI);
+ if (attr)
+ dbus_message_iter_append_string(&iter, &(attr->values[0].string.text));
+ else
+ {
+ have_printer_params = 0;
+ dbus_message_iter_append_string(&iter, &nul);
+ }
+
+ /* STRING printer-name */
+ if (have_printer_params)
+ {
+ attr = ippFindAttribute(msg, "printer-name", IPP_TAG_NAME);
+ if (attr)
+ dbus_message_iter_append_string(&iter,
+ &(attr->values[0].string.text));
+ else
+ goto bail;
+ }
+ else
+ dbus_message_iter_append_string(&iter, &nul);
+
+ /* UINT32 printer-state */
+ if (have_printer_params)
+ {
+ attr = ippFindAttribute(msg, "printer-state", IPP_TAG_ENUM);
+ if (attr)
+ dbus_message_iter_append_uint32(&iter, &(attr->values[0].integer));
+ else
+ goto bail;
+ }
+ else
+ dbus_message_iter_append_uint32(&iter, &no);
+
+ /* STRING printer-state-reasons */
+ if (have_printer_params)
+ {
+ attr = ippFindAttribute(msg, "printer-state-reasons",
+ IPP_TAG_KEYWORD);
+ if (attr)
+ {
+ for (reasons_length = 0, i = 0; i < attr->num_values; i++)
+ /* All need commas except the last, which needs a nul byte. */
+ reasons_length += 1 + strlen(attr->values[i].string.text);
+ printer_reasons = malloc(reasons_length);
+ if (!printer_reasons)
+ goto bail;
+ p = printer_reasons;
+ for (i = 0; i < attr->num_values; i++)
+ {
+ strcpy(p, attr->values[i].string.text);
+ p += strlen(p);
+ if (i)
+ *p++ = ',';
+ }
+ dbus_message_iter_append_string(&iter, &printer_reasons);
+ }
+ else
+ goto bail;
+ }
+ else
+ dbus_message_iter_append_string(&iter, &nul);
+
+ /* BOOL printer-is-accepting-jobs */
+ if (have_printer_params)
+ {
+ attr = ippFindAttribute(msg, "printer-is-accepting-jobs",
+ IPP_TAG_BOOLEAN);
+ if (attr)
+ dbus_message_iter_append_boolean(&iter, &(attr->values[0].boolean));
+ else
+ goto bail;
+ }
+ else
+ dbus_message_iter_append_boolean(&iter, &no);
+ }
+
+ if (params >= PARAMS_JOB)
+ {
+ /* UINT32 job-id */
+ attr = ippFindAttribute(msg, "notify-job-id", IPP_TAG_INTEGER);
+ if (!attr)
+ goto bail;
+ dbus_message_iter_append_uint32(&iter, &(attr->values[0].integer));
+
+ /* UINT32 job-state */
+ attr = ippFindAttribute(msg, "job-state", IPP_TAG_ENUM);
+ if (!attr)
+ goto bail;
+ dbus_message_iter_append_uint32(&iter, &(attr->values[0].integer));
+
+ /* STRING job-state-reasons */
+ attr = ippFindAttribute(msg, "job-state-reasons", IPP_TAG_KEYWORD);
+ if (!attr)
+ goto bail;
+ dbus_message_iter_append_string(&iter, &(attr->values[0].string.text));
+
+ /* STRING job-name or "" */
+ attr = ippFindAttribute(msg, "job-name", IPP_TAG_NAME);
+ if (attr)
+ dbus_message_iter_append_string(&iter, &(attr->values[0].string.text));
+ else
+ dbus_message_iter_append_string(&iter, &nul);
+
+ /* UINT32 job-impressions-completed */
+ attr = ippFindAttribute(msg, "job-impressions-completed",
+ IPP_TAG_INTEGER);
+ if (!attr)
+ goto bail;
+ dbus_message_iter_append_uint32(&iter, &(attr->values[0].integer));
+ }
+
+ dbus_connection_send(con, message, NULL);
+ dbus_connection_flush(con);
+
+ /*
+ * Cleanup...
+ */
+
+ bail:
+
+ if (printer_reasons)
+ free(printer_reasons);
+
+ dbus_message_unref(message);
+ ippDelete(msg);
+ }
+
+ /*
+ * Remove lock file...
+ */
+
+ if (lock_fd >= 0)
+ {
+ close(lock_fd);
+ unlink(lock_filename);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'acquire_lock()' - Acquire a lock so we only have a single notifier running.
+ */
+
+static int /* O - 0 on success, -1 on failure */
+acquire_lock(int *fd, /* O - Lock file descriptor */
+ char *lockfile, /* I - Lock filename buffer */
+ size_t locksize) /* I - Size of filename buffer */
+{
+ const char *tmpdir; /* Temporary directory */
+
+
+ /*
+ * Figure out where to put the lock file...
+ */
+
+ if ((tmpdir = getenv("TMPDIR")) == NULL)
+ tmpdir = "/tmp";
+
+ snprintf(lockfile, locksize, "%s/cups-dbus-notifier-lockfile", tmpdir);
+
+ /*
+ * Create the lock file and fail if it already exists...
+ */
+
+ if ((*fd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0)
+ return (-1);
+ else
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/notifier/mailto.c b/notifier/mailto.c
new file mode 100644
index 000000000..9c7e40d85
--- /dev/null
+++ b/notifier/mailto.c
@@ -0,0 +1,646 @@
+/*
+ * "$Id$"
+ *
+ * "mailto" notifier for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Main entry for the mailto notifier.
+ * email_message() - Email a notification message.
+ * load_configuration() - Load the mailto.conf file.
+ * pipe_sendmail() - Open a pipe to sendmail...
+ * print_attributes() - Print the attributes in a request...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+
+/*
+ * Globals...
+ */
+
+char mailtoCc[1024]; /* Cc email address */
+char mailtoFrom[1024]; /* From email address */
+char mailtoReplyTo[1024]; /* Reply-To email address */
+char mailtoSubject[1024]; /* Subject prefix */
+char mailtoSMTPServer[1024]; /* SMTP server to use */
+char mailtoSendmail[1024]; /* Sendmail program to use */
+
+
+/*
+ * Local functions...
+ */
+
+void email_message(const char *to, const char *subject,
+ const char *text);
+int load_configuration(void);
+cups_file_t *pipe_sendmail(const char *to);
+void print_attributes(ipp_t *ipp, int indent);
+
+
+/*
+ * 'main()' - Main entry for the mailto notifier.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ ipp_t *msg; /* Event message from scheduler */
+ ipp_state_t state; /* IPP event state */
+ char *subject, /* Subject for notification message */
+ *text; /* Text for notification message */
+ cups_lang_t *lang; /* Language info */
+ char temp[1024]; /* Temporary string */
+ int templen; /* Length of temporary string */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* POSIX sigaction data */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Don't buffer stderr...
+ */
+
+ 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 */
+
+ /*
+ * Validate command-line options...
+ */
+
+ if (argc != 3)
+ {
+ fputs("Usage: mailto mailto:user@domain.com notify-user-data\n", stderr);
+ return (1);
+ }
+
+ if (strncmp(argv[1], "mailto:", 7))
+ {
+ fprintf(stderr, "ERROR: Bad recipient \"%s\"!\n", argv[1]);
+ return (1);
+ }
+
+ fprintf(stderr, "DEBUG: argc=%d\n", argc);
+ for (i = 0; i < argc; i ++)
+ fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);
+
+ /*
+ * Load configuration data...
+ */
+
+ if ((lang = cupsLangDefault()) == NULL)
+ return (1);
+
+ if (!load_configuration())
+ return (1);
+
+ /*
+ * Get the reply-to address...
+ */
+
+ templen = sizeof(temp);
+ httpDecode64_2(temp, &templen, argv[2]);
+
+ if (!strncmp(temp, "mailto:", 7))
+ strlcpy(mailtoReplyTo, temp + 7, sizeof(mailtoReplyTo));
+ else if (temp[0])
+ fprintf(stderr, "WARNING: Bad notify-user-data value (%d bytes) ignored!\n",
+ templen);
+
+ /*
+ * Loop forever until we run out of events...
+ */
+
+ for (;;)
+ {
+ /*
+ * Get the next event...
+ */
+
+ msg = ippNew();
+ while ((state = ippReadFile(0, msg)) != IPP_DATA)
+ {
+ if (state <= IPP_IDLE)
+ break;
+ }
+
+ fprintf(stderr, "DEBUG: state=%d\n", state);
+
+ if (state == IPP_ERROR)
+ fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr);
+
+ if (state <= IPP_IDLE)
+ {
+ /*
+ * Out of messages, free memory and then exit...
+ */
+
+ ippDelete(msg);
+ return (0);
+ }
+
+ /*
+ * Get the subject and text for the message, then email it...
+ */
+
+ subject = cupsNotifySubject(lang, msg);
+ text = cupsNotifyText(lang, msg);
+
+ fprintf(stderr, "DEBUG: subject=\"%s\"\n", subject);
+ fprintf(stderr, "DEBUG: text=\"%s\"\n", text);
+
+ if (subject && text)
+ email_message(argv[1] + 7, subject, text);
+ else
+ {
+ fputs("ERROR: Missing attributes in event notification!\n", stderr);
+ print_attributes(msg, 4);
+ }
+
+ /*
+ * Free the memory used for this event...
+ */
+
+ if (subject)
+ free(subject);
+
+ if (text)
+ free(text);
+
+ ippDelete(msg);
+ }
+}
+
+
+/*
+ * 'email_message()' - Email a notification message.
+ */
+
+void
+email_message(const char *to, /* I - Recipient of message */
+ const char *subject, /* I - Subject of message */
+ const char *text) /* I - Text of message */
+{
+ cups_file_t *fp; /* Pipe/socket to mail server */
+ const char *nl; /* Newline to use */
+ char response[1024]; /* SMTP response buffer */
+
+
+ /*
+ * Connect to the mail server...
+ */
+
+ if (mailtoSendmail[0])
+ {
+ /*
+ * Use the sendmail command...
+ */
+
+ fp = pipe_sendmail(to);
+
+ if (!fp)
+ return;
+
+ nl = "\n";
+ }
+ else
+ {
+ /*
+ * Use an SMTP server...
+ */
+
+ char hostbuf[1024]; /* Local hostname */
+
+
+ if (strchr(mailtoSMTPServer, ':'))
+ fp = cupsFileOpen(mailtoSMTPServer, "s");
+ else
+ {
+ char spec[1024]; /* Host:service spec */
+
+
+ snprintf(spec, sizeof(spec), "%s:smtp", mailtoSMTPServer);
+ fp = cupsFileOpen(spec, "s");
+ }
+
+ if (!fp)
+ {
+ fprintf(stderr, "ERROR: Unable to connect to SMTP server \"%s\"!\n",
+ mailtoSMTPServer);
+ return;
+ }
+
+ fprintf(stderr, "DEBUG: Connected to \"%s\"...\n", mailtoSMTPServer);
+
+ cupsFilePrintf(fp, "HELO %s\r\n",
+ httpGetHostname(NULL, hostbuf, sizeof(hostbuf)));
+ fprintf(stderr, "DEBUG: >>> HELO %s\n", hostbuf);
+
+ if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
+ goto smtp_error;
+ fprintf(stderr, "DEBUG: <<< %s\n", response);
+
+ cupsFilePrintf(fp, "MAIL FROM:%s\r\n", mailtoFrom);
+ fprintf(stderr, "DEBUG: >>> MAIL FROM:%s\n", mailtoFrom);
+
+ if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
+ goto smtp_error;
+ fprintf(stderr, "DEBUG: <<< %s\n", response);
+
+ cupsFilePrintf(fp, "RCPT TO:%s\r\n", to);
+ fprintf(stderr, "DEBUG: >>> RCPT TO:%s\n", to);
+
+ if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
+ goto smtp_error;
+ fprintf(stderr, "DEBUG: <<< %s\n", response);
+
+ cupsFilePuts(fp, "DATA\r\n");
+ fputs("DEBUG: DATA\n", stderr);
+
+ if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
+ goto smtp_error;
+ fprintf(stderr, "DEBUG: <<< %s\n", response);
+
+ nl = "\r\n";
+ }
+
+ /*
+ * Send the message...
+ */
+
+ cupsFilePrintf(fp, "Date: %s%s", httpGetDateString(time(NULL)), nl);
+ cupsFilePrintf(fp, "From: %s%s", mailtoFrom, nl);
+ cupsFilePrintf(fp, "Subject: %s %s%s", mailtoSubject, subject, nl);
+ if (mailtoReplyTo[0])
+ {
+ cupsFilePrintf(fp, "Sender: %s%s", mailtoReplyTo, nl);
+ cupsFilePrintf(fp, "Reply-To: %s%s", mailtoReplyTo, nl);
+ }
+ cupsFilePrintf(fp, "To: %s%s", to, nl);
+ if (mailtoCc[0])
+ cupsFilePrintf(fp, "Cc: %s%s", mailtoCc, nl);
+ cupsFilePrintf(fp, "Content-Type: text/plain%s", nl);
+ cupsFilePuts(fp, nl);
+ cupsFilePrintf(fp, "%s%s", text, nl);
+ cupsFilePrintf(fp, ".%s", nl);
+
+ /*
+ * Close the connection to the mail server...
+ */
+
+ if (mailtoSendmail[0])
+ {
+ /*
+ * Close the pipe and wait for the sendmail command to finish...
+ */
+
+ int status; /* Exit status */
+
+
+ cupsFileClose(fp);
+
+ while (wait(&status))
+ {
+ if (errno != EINTR)
+ {
+ fprintf(stderr, "DEBUG: Unable to get child status: %s\n",
+ strerror(errno));
+ status = 0;
+ break;
+ }
+ }
+
+ /*
+ * Report any non-zero status...
+ */
+
+ if (status)
+ {
+ if (WIFEXITED(status))
+ fprintf(stderr, "ERROR: Sendmail command returned status %d!\n",
+ WEXITSTATUS(status));
+ else
+ fprintf(stderr, "ERROR: Sendmail command crashed on signal %d!\n",
+ WTERMSIG(status));
+ }
+ }
+ else
+ {
+ /*
+ * Finish up the SMTP submission and close the connection...
+ */
+
+ if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
+ goto smtp_error;
+ fprintf(stderr, "DEBUG: <<< %s\n", response);
+
+ /*
+ * Process SMTP errors here...
+ */
+
+ smtp_error:
+
+ cupsFilePuts(fp, "QUIT\r\n");
+ fputs("DEBUG: QUIT\n", stderr);
+
+ if (!cupsFileGets(fp, response, sizeof(response)) || atoi(response) >= 500)
+ fprintf(stderr, "ERROR: Got \"%s\" trying to QUIT connection.\n",
+ response);
+ else
+ fprintf(stderr, "DEBUG: <<< %s\n", response);
+
+ cupsFileClose(fp);
+
+ fprintf(stderr, "DEBUG: Closed connection to \"%s\"...\n",
+ mailtoSMTPServer);
+ }
+}
+
+
+/*
+ * 'load_configuration()' - Load the mailto.conf file.
+ */
+
+int /* I - 1 on success, 0 on failure */
+load_configuration(void)
+{
+ cups_file_t *fp; /* mailto.conf file */
+ const char *server_root, /* CUPS_SERVERROOT environment variable */
+ *server_admin; /* SERVER_ADMIN environment variable */
+ char line[1024], /* Line from file */
+ *value; /* Value for directive */
+ int linenum; /* Line number in file */
+
+
+ /*
+ * Initialize defaults...
+ */
+
+ mailtoCc[0] = '\0';
+
+ if ((server_admin = getenv("SERVER_ADMIN")) != NULL)
+ strlcpy(mailtoFrom, server_admin, sizeof(mailtoFrom));
+ else
+ snprintf(mailtoFrom, sizeof(mailtoFrom), "root@%s",
+ httpGetHostname(NULL, line, sizeof(line)));
+
+ strlcpy(mailtoSendmail, "/usr/sbin/sendmail", sizeof(mailtoSendmail));
+
+ mailtoSMTPServer[0] = '\0';
+
+ mailtoSubject[0] = '\0';
+
+ /*
+ * Try loading the config file...
+ */
+
+ if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
+ server_root = CUPS_SERVERROOT;
+
+ snprintf(line, sizeof(line), "%s/mailto.conf", server_root);
+
+ if ((fp = cupsFileOpen(line, "r")) == NULL)
+ {
+ if (errno != ENOENT)
+ {
+ fprintf(stderr, "ERROR: Unable to open \"%s\" - %s\n", line,
+ strerror(errno));
+ return (1);
+ }
+ else
+ return (0);
+ }
+
+ linenum = 0;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ if (!value)
+ {
+ fprintf(stderr, "ERROR: No value found for %s directive on line %d!\n",
+ line, linenum);
+ cupsFileClose(fp);
+ return (0);
+ }
+
+ if (!_cups_strcasecmp(line, "Cc"))
+ strlcpy(mailtoCc, value, sizeof(mailtoCc));
+ else if (!_cups_strcasecmp(line, "From"))
+ strlcpy(mailtoFrom, value, sizeof(mailtoFrom));
+ else if (!_cups_strcasecmp(line, "Sendmail"))
+ {
+ strlcpy(mailtoSendmail, value, sizeof(mailtoSendmail));
+ mailtoSMTPServer[0] = '\0';
+ }
+ else if (!_cups_strcasecmp(line, "SMTPServer"))
+ {
+ mailtoSendmail[0] = '\0';
+ strlcpy(mailtoSMTPServer, value, sizeof(mailtoSMTPServer));
+ }
+ else if (!_cups_strcasecmp(line, "Subject"))
+ strlcpy(mailtoSubject, value, sizeof(mailtoSubject));
+ else
+ {
+ fprintf(stderr,
+ "ERROR: Unknown configuration directive \"%s\" on line %d!\n",
+ line, linenum);
+ }
+ }
+
+ /*
+ * Close file and return...
+ */
+
+ cupsFileClose(fp);
+
+ return (1);
+}
+
+
+/*
+ * 'pipe_sendmail()' - Open a pipe to sendmail...
+ */
+
+cups_file_t * /* O - CUPS file */
+pipe_sendmail(const char *to) /* I - To: address */
+{
+ cups_file_t *fp; /* CUPS file */
+ int pid; /* Process ID */
+ int pipefds[2]; /* Pipe file descriptors */
+ int argc; /* Number of arguments */
+ char *argv[100], /* Argument array */
+ line[1024], /* Sendmail command + args */
+ *lineptr; /* Pointer into line */
+
+
+ /*
+ * First break the mailtoSendmail string into arguments...
+ */
+
+ strlcpy(line, mailtoSendmail, sizeof(line));
+ argv[0] = line;
+ argc = 1;
+
+ for (lineptr = strchr(line, ' '); lineptr; lineptr = strchr(lineptr, ' '))
+ {
+ while (*lineptr == ' ')
+ *lineptr++ = '\0';
+
+ if (*lineptr)
+ {
+ /*
+ * Point to the next argument...
+ */
+
+ argv[argc ++] = lineptr;
+
+ /*
+ * Stop if we have too many...
+ */
+
+ if (argc >= (int)(sizeof(argv) / sizeof(argv[0]) - 2))
+ break;
+ }
+ }
+
+ argv[argc ++] = (char *)to;
+ argv[argc] = NULL;
+
+ /*
+ * Create the pipe...
+ */
+
+ if (pipe(pipefds))
+ {
+ perror("ERROR: Unable to create pipe");
+ return (NULL);
+ }
+
+ /*
+ * Then run the command...
+ */
+
+ if ((pid = fork()) == 0)
+ {
+ /*
+ * Child goes here - redirect stdin to the input side of the pipe,
+ * redirect stdout to stderr, and exec...
+ */
+
+ close(0);
+ dup(pipefds[0]);
+
+ close(1);
+ dup(2);
+
+ close(pipefds[0]);
+ close(pipefds[1]);
+
+ execvp(argv[0], argv);
+ exit(errno);
+ }
+ else if (pid < 0)
+ {
+ /*
+ * Unable to fork - error out...
+ */
+
+ perror("ERROR: Unable to fork command");
+
+ close(pipefds[0]);
+ close(pipefds[1]);
+
+ return (NULL);
+ }
+
+ /*
+ * Create a CUPS file using the output side of the pipe and close the
+ * input side...
+ */
+
+ close(pipefds[0]);
+
+ if ((fp = cupsFileOpenFd(pipefds[1], "w")) == NULL)
+ {
+ int status; /* Status of command */
+
+
+ close(pipefds[1]);
+ wait(&status);
+ }
+
+ return (fp);
+}
+
+
+/*
+ * 'print_attributes()' - Print the attributes in a request...
+ */
+
+void
+print_attributes(ipp_t *ipp, /* I - IPP request */
+ int indent) /* I - Indentation */
+{
+ ipp_tag_t group; /* Current group */
+ ipp_attribute_t *attr; /* Current attribute */
+ char buffer[1024]; /* Value buffer */
+
+
+ for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next)
+ {
+ if ((attr->group_tag == IPP_TAG_ZERO && indent <= 8) || !attr->name)
+ {
+ group = IPP_TAG_ZERO;
+ fputc('\n', stderr);
+ continue;
+ }
+
+ if (group != attr->group_tag)
+ {
+ group = attr->group_tag;
+
+ fprintf(stderr, "DEBUG: %*s%s:\n\n", indent - 4, "", ippTagString(group));
+ }
+
+ _ippAttrString(attr, buffer, sizeof(buffer));
+
+ fprintf(stderr, "DEBUG: %*s%s (%s%s) %s", indent, "", attr->name,
+ attr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attr->value_tag), buffer);
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/notifier/rss.c b/notifier/rss.c
new file mode 100644
index 000000000..1094a3853
--- /dev/null
+++ b/notifier/rss.c
@@ -0,0 +1,731 @@
+/*
+ * "$Id$"
+ *
+ * RSS notifier for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Main entry for the test notifier.
+ * compare_rss() - Compare two messages.
+ * delete_message() - Free all memory used by a message.
+ * load_rss() - Load an existing RSS feed file.
+ * new_message() - Create a new RSS message.
+ * password_cb() - Return the cached password.
+ * save_rss() - Save messages to a RSS file.
+ * xml_escape() - Copy a string, escaping &, <, and > as needed.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <cups/language.h>
+#include <cups/string-private.h>
+#include <cups/array.h>
+#include <sys/select.h>
+
+
+/*
+ * Structures...
+ */
+
+typedef struct _cups_rss_s /**** RSS message data ****/
+{
+ int sequence_number; /* notify-sequence-number */
+ char *subject, /* Message subject/summary */
+ *text, /* Message text */
+ *link_url; /* Link to printer */
+ time_t event_time; /* When the event occurred */
+} _cups_rss_t;
+
+
+/*
+ * Local globals...
+ */
+
+static char *rss_password; /* Password for remote RSS */
+
+
+/*
+ * Local functions...
+ */
+
+static int compare_rss(_cups_rss_t *a, _cups_rss_t *b);
+static void delete_message(_cups_rss_t *rss);
+static void load_rss(cups_array_t *rss, const char *filename);
+static _cups_rss_t *new_message(int sequence_number, char *subject,
+ char *text, char *link_url,
+ time_t event_time);
+static const char *password_cb(const char *prompt);
+static int save_rss(cups_array_t *rss, const char *filename,
+ const char *baseurl);
+static char *xml_escape(const char *s);
+
+
+/*
+ * 'main()' - Main entry for the test notifier.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ ipp_t *event; /* Event from scheduler */
+ ipp_state_t state; /* IPP event state */
+ char scheme[32], /* URI scheme ("rss") */
+ username[256], /* Username for remote RSS */
+ host[1024], /* Hostname for remote RSS */
+ resource[1024], /* RSS file */
+ *options; /* Options */
+ int port, /* Port number for remote RSS */
+ max_events; /* Maximum number of events */
+ http_t *http; /* Connection to remote server */
+ http_status_t status; /* HTTP GET/PUT status code */
+ char filename[1024], /* Local filename */
+ newname[1024]; /* filename.N */
+ cups_lang_t *language; /* Language information */
+ ipp_attribute_t *printer_up_time, /* Timestamp on event */
+ *notify_sequence_number,/* Sequence number */
+ *notify_printer_uri; /* Printer URI */
+ char *subject, /* Subject for notification message */
+ *text, /* Text for notification message */
+ link_url[1024], /* Link to printer */
+ link_scheme[32], /* Scheme for link */
+ link_username[256], /* Username for link */
+ link_host[1024], /* Host for link */
+ link_resource[1024]; /* Resource for link */
+ int link_port; /* Link port */
+ cups_array_t *rss; /* RSS message array */
+ _cups_rss_t *msg; /* RSS message */
+ char baseurl[1024]; /* Base URL */
+ fd_set input; /* Input set for select() */
+ struct timeval timeout; /* Timeout for select() */
+ int changed; /* Has the RSS data changed? */
+ int exit_status; /* Exit status */
+
+
+ fprintf(stderr, "DEBUG: argc=%d\n", argc);
+ for (i = 0; i < argc; i ++)
+ fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);
+
+ /*
+ * See whether we are publishing this RSS feed locally or remotely...
+ */
+
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, argv[1], scheme, sizeof(scheme),
+ username, sizeof(username), host, sizeof(host), &port,
+ resource, sizeof(resource)) < HTTP_URI_OK)
+ {
+ fprintf(stderr, "ERROR: Bad RSS URI \"%s\"!\n", argv[1]);
+ return (1);
+ }
+
+ max_events = 20;
+
+ if ((options = strchr(resource, '?')) != NULL)
+ {
+ *options++ = '\0';
+
+ if (!strncmp(options, "max_events=", 11))
+ {
+ max_events = atoi(options + 11);
+
+ if (max_events <= 0)
+ max_events = 20;
+ }
+ }
+
+ rss = cupsArrayNew((cups_array_func_t)compare_rss, NULL);
+
+ if (host[0])
+ {
+ /*
+ * Remote feed, see if we can get the current file...
+ */
+
+ int fd; /* Temporary file */
+
+
+ if ((rss_password = strchr(username, ':')) != NULL)
+ *rss_password++ = '\0';
+
+ cupsSetPasswordCB(password_cb);
+ cupsSetUser(username);
+
+ if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
+ {
+ fprintf(stderr, "ERROR: Unable to create temporary file: %s\n",
+ strerror(errno));
+
+ return (1);
+ }
+
+ if ((http = httpConnect(host, port)) == NULL)
+ {
+ fprintf(stderr, "ERROR: Unable to connect to %s on port %d: %s\n",
+ host, port, strerror(errno));
+
+ close(fd);
+ unlink(filename);
+
+ return (1);
+ }
+
+ status = cupsGetFd(http, resource, fd);
+
+ close(fd);
+
+ if (status != HTTP_OK && status != HTTP_NOT_FOUND)
+ {
+ fprintf(stderr, "ERROR: Unable to GET %s from %s on port %d: %d %s\n",
+ resource, host, port, status, httpStatus(status));
+
+ httpClose(http);
+ unlink(filename);
+
+ return (1);
+ }
+
+ strlcpy(newname, filename, sizeof(newname));
+
+ httpAssembleURI(HTTP_URI_CODING_ALL, baseurl, sizeof(baseurl), "http",
+ NULL, host, port, resource);
+ }
+ else
+ {
+ const char *cachedir, /* CUPS_CACHEDIR */
+ *server_name, /* SERVER_NAME */
+ *server_port; /* SERVER_PORT */
+
+
+ http = NULL;
+
+ if ((cachedir = getenv("CUPS_CACHEDIR")) == NULL)
+ cachedir = CUPS_CACHEDIR;
+
+ if ((server_name = getenv("SERVER_NAME")) == NULL)
+ server_name = "localhost";
+
+ if ((server_port = getenv("SERVER_PORT")) == NULL)
+ server_port = "631";
+
+ snprintf(filename, sizeof(filename), "%s/rss%s", cachedir, resource);
+ snprintf(newname, sizeof(newname), "%s.N", filename);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, baseurl, sizeof(baseurl), "http",
+ NULL, server_name, atoi(server_port), "/rss%s", resource);
+ }
+
+ /*
+ * Load the previous RSS file, if any...
+ */
+
+ load_rss(rss, filename);
+
+ changed = cupsArrayCount(rss) == 0;
+
+ /*
+ * Localize for the user's chosen language...
+ */
+
+ language = cupsLangDefault();
+
+ /*
+ * Read events and update the RSS file until we are out of events.
+ */
+
+ for (exit_status = 0, event = NULL;;)
+ {
+ if (changed)
+ {
+ /*
+ * Save the messages to the file again, uploading as needed...
+ */
+
+ if (save_rss(rss, newname, baseurl))
+ {
+ if (http)
+ {
+ /*
+ * Upload the RSS file...
+ */
+
+ if ((status = cupsPutFile(http, resource, filename)) != HTTP_CREATED)
+ fprintf(stderr, "ERROR: Unable to PUT %s from %s on port %d: %d %s\n",
+ resource, host, port, status, httpStatus(status));
+ }
+ else
+ {
+ /*
+ * Move the new RSS file over top the old one...
+ */
+
+ if (rename(newname, filename))
+ fprintf(stderr, "ERROR: Unable to rename %s to %s: %s\n",
+ newname, filename, strerror(errno));
+ }
+
+ changed = 0;
+ }
+ }
+
+ /*
+ * Wait up to 30 seconds for an event...
+ */
+
+ timeout.tv_sec = 30;
+ timeout.tv_usec = 0;
+
+ FD_ZERO(&input);
+ FD_SET(0, &input);
+
+ if (select(1, &input, NULL, NULL, &timeout) < 0)
+ continue;
+ else if (!FD_ISSET(0, &input))
+ {
+ fprintf(stderr, "DEBUG: %s is bored, exiting...\n", argv[1]);
+ break;
+ }
+
+ /*
+ * Read the next event...
+ */
+
+ event = ippNew();
+ while ((state = ippReadFile(0, event)) != IPP_DATA)
+ {
+ if (state <= IPP_IDLE)
+ break;
+ }
+
+ if (state == IPP_ERROR)
+ fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr);
+
+ if (state <= IPP_IDLE)
+ break;
+
+ /*
+ * Collect the info from the event...
+ */
+
+ printer_up_time = ippFindAttribute(event, "printer-up-time",
+ IPP_TAG_INTEGER);
+ notify_sequence_number = ippFindAttribute(event, "notify-sequence-number",
+ IPP_TAG_INTEGER);
+ notify_printer_uri = ippFindAttribute(event, "notify-printer-uri",
+ IPP_TAG_URI);
+ subject = cupsNotifySubject(language, event);
+ text = cupsNotifyText(language, event);
+
+ if (printer_up_time && notify_sequence_number && subject && text)
+ {
+ /*
+ * Create a new RSS message...
+ */
+
+ if (notify_printer_uri)
+ {
+ httpSeparateURI(HTTP_URI_CODING_ALL,
+ notify_printer_uri->values[0].string.text,
+ link_scheme, sizeof(link_scheme),
+ link_username, sizeof(link_username),
+ link_host, sizeof(link_host), &link_port,
+ link_resource, sizeof(link_resource));
+ httpAssembleURI(HTTP_URI_CODING_ALL, link_url, sizeof(link_url),
+ "http", link_username, link_host, link_port,
+ link_resource);
+ }
+
+ msg = new_message(notify_sequence_number->values[0].integer,
+ xml_escape(subject), xml_escape(text),
+ notify_printer_uri ? xml_escape(link_url) : NULL,
+ printer_up_time->values[0].integer);
+
+ if (!msg)
+ {
+ fprintf(stderr, "ERROR: Unable to create message: %s\n",
+ strerror(errno));
+ exit_status = 1;
+ break;
+ }
+
+ /*
+ * Add it to the array...
+ */
+
+ cupsArrayAdd(rss, msg);
+
+ changed = 1;
+
+ /*
+ * Trim the array as needed...
+ */
+
+ while (cupsArrayCount(rss) > max_events)
+ {
+ msg = cupsArrayFirst(rss);
+
+ cupsArrayRemove(rss, msg);
+
+ delete_message(msg);
+ }
+ }
+
+ if (subject)
+ free(subject);
+
+ if (text)
+ free(text);
+
+ ippDelete(event);
+ event = NULL;
+ }
+
+ /*
+ * We only get here when idle or error...
+ */
+
+ ippDelete(event);
+
+ if (http)
+ {
+ unlink(filename);
+ httpClose(http);
+ }
+
+ return (exit_status);
+}
+
+
+/*
+ * 'compare_rss()' - Compare two messages.
+ */
+
+static int /* O - Result of comparison */
+compare_rss(_cups_rss_t *a, /* I - First message */
+ _cups_rss_t *b) /* I - Second message */
+{
+ return (a->sequence_number - b->sequence_number);
+}
+
+
+/*
+ * 'delete_message()' - Free all memory used by a message.
+ */
+
+static void
+delete_message(_cups_rss_t *msg) /* I - RSS message */
+{
+ if (msg->subject)
+ free(msg->subject);
+
+ if (msg->text)
+ free(msg->text);
+
+ if (msg->link_url)
+ free(msg->link_url);
+
+ free(msg);
+}
+
+
+/*
+ * 'load_rss()' - Load an existing RSS feed file.
+ */
+
+static void
+load_rss(cups_array_t *rss, /* I - RSS messages */
+ const char *filename) /* I - File to load */
+{
+ FILE *fp; /* File pointer */
+ char line[4096], /* Line from file */
+ *subject, /* Subject */
+ *text, /* Text */
+ *link_url, /* Link URL */
+ *start, /* Start of element */
+ *end; /* End of element */
+ time_t event_time; /* Event time */
+ int sequence_number; /* Sequence number */
+ int in_item; /* In an item */
+ _cups_rss_t *msg; /* New message */
+
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ {
+ if (errno != ENOENT)
+ fprintf(stderr, "ERROR: Unable to open %s: %s\n", filename,
+ strerror(errno));
+
+ return;
+ }
+
+ subject = NULL;
+ text = NULL;
+ link_url = NULL;
+ event_time = 0;
+ sequence_number = 0;
+ in_item = 0;
+
+ while (fgets(line, sizeof(line), fp))
+ {
+ if (strstr(line, "<item>"))
+ in_item = 1;
+ else if (strstr(line, "</item>") && in_item)
+ {
+ if (subject && text)
+ {
+ msg = new_message(sequence_number, subject, text, link_url,
+ event_time);
+
+ if (msg)
+ cupsArrayAdd(rss, msg);
+
+ }
+ else
+ {
+ if (subject)
+ free(subject);
+
+ if (text)
+ free(text);
+
+ if (link_url)
+ free(link_url);
+ }
+
+ subject = NULL;
+ text = NULL;
+ link_url = NULL;
+ event_time = 0;
+ sequence_number = 0;
+ in_item = 0;
+ }
+ else if (!in_item)
+ continue;
+ else if ((start = strstr(line, "<title>")) != NULL)
+ {
+ start += 7;
+ if ((end = strstr(start, "</title>")) != NULL)
+ {
+ *end = '\0';
+ subject = strdup(start);
+ }
+ }
+ else if ((start = strstr(line, "<description>")) != NULL)
+ {
+ start += 13;
+ if ((end = strstr(start, "</description>")) != NULL)
+ {
+ *end = '\0';
+ text = strdup(start);
+ }
+ }
+ else if ((start = strstr(line, "<link>")) != NULL)
+ {
+ start += 6;
+ if ((end = strstr(start, "</link>")) != NULL)
+ {
+ *end = '\0';
+ link_url = strdup(start);
+ }
+ }
+ else if ((start = strstr(line, "<pubDate>")) != NULL)
+ {
+ start += 9;
+ if ((end = strstr(start, "</pubDate>")) != NULL)
+ {
+ *end = '\0';
+ event_time = httpGetDateTime(start);
+ }
+ }
+ else if ((start = strstr(line, "<guid>")) != NULL)
+ sequence_number = atoi(start + 6);
+ }
+
+ fclose(fp);
+}
+
+
+/*
+ * 'new_message()' - Create a new RSS message.
+ */
+
+static _cups_rss_t * /* O - New message */
+new_message(int sequence_number, /* I - notify-sequence-number */
+ char *subject, /* I - Subject/summary */
+ char *text, /* I - Text */
+ char *link_url, /* I - Link to printer */
+ time_t event_time) /* I - Date/time of event */
+{
+ _cups_rss_t *msg; /* New message */
+
+
+ if ((msg = calloc(1, sizeof(_cups_rss_t))) == NULL)
+ return (NULL);
+
+ msg->sequence_number = sequence_number;
+ msg->subject = subject;
+ msg->text = text;
+ msg->link_url = link_url;
+ msg->event_time = event_time;
+
+ return (msg);
+}
+
+
+/*
+ * 'password_cb()' - Return the cached password.
+ */
+
+static const char * /* O - Cached password */
+password_cb(const char *prompt) /* I - Prompt string, unused */
+{
+ (void)prompt;
+
+ return (rss_password);
+}
+
+
+/*
+ * 'save_rss()' - Save messages to a RSS file.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+save_rss(cups_array_t *rss, /* I - RSS messages */
+ const char *filename, /* I - File to save to */
+ const char *baseurl) /* I - Base URL */
+{
+ FILE *fp; /* File pointer */
+ _cups_rss_t *msg; /* Current message */
+ char date[1024]; /* Current date */
+ char *href; /* Escaped base URL */
+
+
+ if ((fp = fopen(filename, "w")) == NULL)
+ {
+ fprintf(stderr, "ERROR: Unable to create %s: %s\n", filename,
+ strerror(errno));
+ return (0);
+ }
+
+ fputs("<?xml version=\"1.0\"?>\n", fp);
+ fputs("<rss version=\"2.0\">\n", fp);
+ fputs(" <channel>\n", fp);
+ fputs(" <title>CUPS RSS Feed</title>\n", fp);
+
+ href = xml_escape(baseurl);
+ fprintf(fp, " <link>%s</link>\n", href);
+ free(href);
+
+ fputs(" <description>CUPS RSS Feed</description>\n", fp);
+ fputs(" <generator>" CUPS_SVERSION "</generator>\n", fp);
+ fputs(" <ttl>1</ttl>\n", fp);
+
+ fprintf(fp, " <pubDate>%s</pubDate>\n",
+ httpGetDateString2(time(NULL), date, sizeof(date)));
+
+ for (msg = (_cups_rss_t *)cupsArrayLast(rss);
+ msg;
+ msg = (_cups_rss_t *)cupsArrayPrev(rss))
+ {
+ fputs(" <item>\n", fp);
+ fprintf(fp, " <title>%s</title>\n", msg->subject);
+ fprintf(fp, " <description>%s</description>\n", msg->text);
+ if (msg->link_url)
+ fprintf(fp, " <link>%s</link>\n", msg->link_url);
+ fprintf(fp, " <pubDate>%s</pubDate>\n",
+ httpGetDateString2(msg->event_time, date, sizeof(date)));
+ fprintf(fp, " <guid>%d</guid>\n", msg->sequence_number);
+ fputs(" </item>\n", fp);
+ }
+
+ fputs(" </channel>\n", fp);
+ fputs("</rss>\n", fp);
+
+ return (!fclose(fp));
+}
+
+
+/*
+ * 'xml_escape()' - Copy a string, escaping &, <, and > as needed.
+ */
+
+static char * /* O - Escaped string */
+xml_escape(const char *s) /* I - String to escape */
+{
+ char *e, /* Escaped string */
+ *eptr; /* Pointer into escaped string */
+ const char *sptr; /* Pointer into string */
+ size_t bytes; /* Bytes needed for string */
+
+
+ /*
+ * First figure out how many extra bytes we need...
+ */
+
+ for (bytes = 0, sptr = s; *sptr; sptr ++)
+ if (*sptr == '&')
+ bytes += 4; /* &amp; */
+ else if (*sptr == '<' || *sptr == '>')
+ bytes += 3; /* &lt; and &gt; */
+
+ /*
+ * If there is nothing to escape, just strdup() it...
+ */
+
+ if (bytes == 0)
+ return (strdup(s));
+
+ /*
+ * Otherwise allocate memory and copy...
+ */
+
+ if ((e = malloc(bytes + 1 + strlen(s))) == NULL)
+ return (NULL);
+
+ for (eptr = e, sptr = s; *sptr; sptr ++)
+ if (*sptr == '&')
+ {
+ *eptr++ = '&';
+ *eptr++ = 'a';
+ *eptr++ = 'm';
+ *eptr++ = 'p';
+ *eptr++ = ';';
+ }
+ else if (*sptr == '<')
+ {
+ *eptr++ = '&';
+ *eptr++ = 'l';
+ *eptr++ = 't';
+ *eptr++ = ';';
+ }
+ else if (*sptr == '>')
+ {
+ *eptr++ = '&';
+ *eptr++ = 'g';
+ *eptr++ = 't';
+ *eptr++ = ';';
+ }
+ else
+ *eptr++ = *sptr;
+
+ *eptr = '\0';
+
+ return (e);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/notifier/testnotify.c b/notifier/testnotify.c
new file mode 100644
index 000000000..9b675743d
--- /dev/null
+++ b/notifier/testnotify.c
@@ -0,0 +1,127 @@
+/*
+ * "$Id$"
+ *
+ * Test notifier for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Main entry for the test notifier.
+ * print_attributes() - Print the attributes in a request...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * Local functions...
+ */
+
+void print_attributes(ipp_t *ipp, int indent);
+
+
+/*
+ * 'main()' - Main entry for the test notifier.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ ipp_t *event; /* Event from scheduler */
+ ipp_state_t state; /* IPP event state */
+
+
+ setbuf(stderr, NULL);
+
+ fprintf(stderr, "DEBUG: argc=%d\n", argc);
+ for (i = 0; i < argc; i ++)
+ fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);
+ fprintf(stderr, "DEBUG: TMPDIR=\"%s\"\n", getenv("TMPDIR"));
+
+ for (;;)
+ {
+ event = ippNew();
+ while ((state = ippReadFile(0, event)) != IPP_DATA)
+ {
+ if (state <= IPP_IDLE)
+ break;
+ }
+
+ if (state == IPP_ERROR)
+ fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr);
+
+ if (state <= IPP_IDLE)
+ {
+ ippDelete(event);
+ return (0);
+ }
+
+ print_attributes(event, 4);
+ ippDelete(event);
+
+ /*
+ * If the recipient URI is "testnotify://nowait", then we exit after each
+ * event...
+ */
+
+ if (!strcmp(argv[1], "testnotify://nowait"))
+ return (0);
+ }
+}
+
+
+/*
+ * 'print_attributes()' - Print the attributes in a request...
+ */
+
+void
+print_attributes(ipp_t *ipp, /* I - IPP request */
+ int indent) /* I - Indentation */
+{
+ ipp_tag_t group; /* Current group */
+ ipp_attribute_t *attr; /* Current attribute */
+ char buffer[1024]; /* Value buffer */
+
+
+ for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next)
+ {
+ if ((attr->group_tag == IPP_TAG_ZERO && indent <= 8) || !attr->name)
+ {
+ group = IPP_TAG_ZERO;
+ fputc('\n', stderr);
+ continue;
+ }
+
+ if (group != attr->group_tag)
+ {
+ group = attr->group_tag;
+
+ fprintf(stderr, "DEBUG: %*s%s:\n\n", indent - 4, "", ippTagString(group));
+ }
+
+ _ippAttrString(attr, buffer, sizeof(buffer));
+
+ fprintf(stderr, "DEBUG: %*s%s (%s%s) %s", indent, "", attr->name,
+ attr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attr->value_tag), buffer);
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/packaging/InstallationCheck b/packaging/InstallationCheck
new file mode 100755
index 000000000..4e3405caa
--- /dev/null
+++ b/packaging/InstallationCheck
@@ -0,0 +1,11 @@
+#!/bin/sh
+case `uname -r` in
+ # Mac OS X 10.4.x
+ 8.*) exit 0;;
+
+ # Mac OS X 10.5.x
+ 9.*) exit 0;;
+
+ # Older Mac OS X...
+ *) exit 97;;
+esac
diff --git a/packaging/LICENSE.rtf b/packaging/LICENSE.rtf
new file mode 100644
index 000000000..b348f6b08
--- /dev/null
+++ b/packaging/LICENSE.rtf
@@ -0,0 +1,434 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1011
+{\fonttbl\f0\froman\fcharset0 Times-Roman;\f1\fnil\fcharset0 LucidaGrande;\f2\fmodern\fcharset0 Courier;
+\f3\fmodern\fcharset0 Courier-Oblique;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue238;}
+{\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid1\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid1}
+{\list\listtemplateid2\listhybrid{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid101\'02\'00.;}{\levelnumbers\'01;}\fi-360\li720\lin720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid102\'02\'01.;}{\levelnumbers\'01;}\fi-360\li1440\lin1440 }{\listname ;}\listid2}
+{\list\listtemplateid3\listhybrid{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid201\'02\'00.;}{\levelnumbers\'01;}\fi-360\li720\lin720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid202\'02\'01.;}{\levelnumbers\'01;}\fi-360\li1440\lin1440 }{\listname ;}\listid3}
+{\list\listtemplateid4\listhybrid{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid301\'02\'00.;}{\levelnumbers\'01;}\fi-360\li720\lin720 }{\listname ;}\listid4}
+{\list\listtemplateid5\listhybrid{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid401\'02\'00.;}{\levelnumbers\'01;}\fi-360\li720\lin720 }{\listname ;}\listid5}
+{\list\listtemplateid6\listhybrid{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid501\'02\'00.;}{\levelnumbers\'01;}\fi-360\li720\lin720 }{\listname ;}\listid6}
+{\list\listtemplateid7\listhybrid{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid601\'02\'00.;}{\levelnumbers\'01;}\fi-360\li720\lin720 }{\listname ;}\listid7}}
+{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}{\listoverride\listid2\listoverridecount0\ls2}{\listoverride\listid3\listoverridecount0\ls3}{\listoverride\listid4\listoverridecount0\ls4}{\listoverride\listid5\listoverridecount0\ls5}{\listoverride\listid6\listoverridecount0\ls6}{\listoverride\listid7\listoverridecount0\ls7}}
+\margl1440\margr1440\margb1800\margt1800\vieww9000\viewh8400\viewkind0
+\deftab720
+\pard\pardeftab720\sa280\qc
+
+\f0\b\fs36 \cf0 CUPS License Agreement\
+\pard\pardeftab720\sa240\qc
+
+\b0\fs24 \cf0 Copyright 2007-2009 by Apple Inc.
+\f1 \uc0\u8232
+\f0 1 Infinite Loop
+\f1 \uc0\u8232
+\f0 Cupertino, CA 95014 USA
+\f1 \uc0\u8232 \u8232
+\f0 WWW: {\field{\*\fldinst{HYPERLINK "http://www.cups.org/"}}{\fldrslt \cf2 \ul \ulc2 http://www.cups.org}}\
+\pard\pardeftab720\sa280\ql\qnatural
+
+\b\fs28 \cf0 Introduction\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\b0\fs24 \cf0 CUPS
+\fs20 \super TM
+\fs24 \nosupersub 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:\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls1\ilvl0\cf0 {\listtext \'95 }Use the CUPS software at no charge.\
+{\listtext \'95 }Distribute verbatim copies of the software in source or binary form.\
+{\listtext \'95 }Sell verbatim copies of the software for a media fee, or sell support for the software.\
+{\listtext \'95 }Distribute or sell printer drivers and filters that use CUPS so long as source code is made available under the GPL.\
+\pard\pardeftab720\sa240\ql\qnatural
+\cf0 What this license
+\b does not
+\b0 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.\
+\pard\pardeftab720\sa280\ql\qnatural
+
+\b\fs28 \cf0 License Exceptions\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\b0\fs24 \cf0 In addition, as the copyright holder of CUPS, Apple Inc. grants the following special exceptions:\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls2\ilvl0
+\b \cf0 {\listtext 1. }Apple Operating System Development License Exception
+\b0 ;\
+\pard\tx940\tx1440\pardeftab720\li1440\fi-1440\ql\qnatural
+\ls2\ilvl1\cf0 {\listtext 1. }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.\
+{\listtext 2. }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.\
+{\listtext 3. }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.\
+{\listtext 4. }All CUPS software that falls under this license exception have the following text at the top of each source file:\
+{\listtext 5. }This file is subject to the Apple OS-Developed Software exception.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls2\ilvl0
+\b \cf0 {\listtext 2. }OpenSSL Toolkit License Exception
+\b0 ;\
+\pard\tx940\tx1440\pardeftab720\li1440\fi-1440\ql\qnatural
+\ls2\ilvl1\cf0 {\listtext 1. }Apple Inc. explicitly allows the compilation and distribution of the CUPS software with the OpenSSL Toolkit.\
+\pard\pardeftab720\sa240\ql\qnatural
+\cf0 No developer is required to provide these exceptions in a derived work.\
+\pard\pardeftab720\sa280\ql\qnatural
+
+\b\fs28 \cf0 Trademarks\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\b0\fs24 \cf0 CUPS and the CUPS logo (the "CUPS Marks") are trademarks of Apple Inc. Apple grants you a non-exclusive and non-transferable right to use the CUPS Marks in any direct port or binary distribution incorporating CUPS software and in any promotional material therefor. You agree that your products will meet the highest levels of quality and integrity for similar goods, not be unlawful, and be developed, manufactured, and distributed in compliance with this license. You will not interfere with Apple's rights in the CUPS Marks, and all use of the CUPS Marks shall inure to the benefit of Apple. This license does not apply to use of the CUPS Marks in a derivative products, which requires prior written permission from Apple Inc.\
+\pard\pardeftab720\sa280\ql\qnatural
+
+\b\fs28 \cf0 \page \pard\pardeftab720\sa280\ql\qnatural
+
+\fs36 \cf0 GNU GENERAL PUBLIC LICENSE\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\b0\fs24 \cf0 Version 2, June 1991\
+\pard\pardeftab720\ql\qnatural
+
+\f2 \cf0 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.\
+\pard\pardeftab720\sa300\ql\qnatural
+
+\f0\b \cf0 Preamble\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\b0 \cf0 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.\
+\pard\pardeftab720\sa300\ql\qnatural
+
+\b \cf0 GNU GENERAL PUBLIC LICENSE
+\f1 \uc0\u8232
+\f0 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls3\ilvl0
+\b0 \cf0 {\listtext 1. }This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural
+\ls3\ilvl0\cf0 {\listtext 2. }Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls3\ilvl0\cf0 {\listtext 3. }You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural
+\ls3\ilvl0\cf0 {\listtext 4. }You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls3\ilvl0\cf0 {\listtext 5. }You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:\
+\pard\tx940\tx1440\pardeftab720\li1440\fi-1440\ql\qnatural
+\ls3\ilvl1\cf0 {\listtext 1. }You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.\
+{\listtext 2. }You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.\
+{\listtext 3. }if the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural
+\ls3\ilvl0\cf0 {\listtext 6. }These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.\
+{\listtext 7. }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.\
+{\listtext 8. }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.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls3\ilvl0\cf0 {\listtext 9. }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:\
+\pard\tx940\tx1440\pardeftab720\li1440\fi-1440\ql\qnatural
+\ls3\ilvl1\cf0 {\listtext 1. }Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,\
+{\listtext 2. }Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,\
+{\listtext 3. }Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural
+\ls3\ilvl0\cf0 {\listtext 10. }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.\
+{\listtext 11. }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.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls3\ilvl0\cf0 {\listtext 12. }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.\
+{\listtext 13. }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.\
+{\listtext 14. }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.\
+{\listtext 15. }If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural
+\ls3\ilvl0\cf0 {\listtext 16. }If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.\
+{\listtext 17. }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.\
+{\listtext 18. }This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls3\ilvl0\cf0 {\listtext 19. }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.\
+{\listtext 20. }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.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural
+\ls3\ilvl0\cf0 {\listtext 21. }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.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls3\ilvl0\cf0 {\listtext 22. }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.\
+\pard\pardeftab720\sa300\ql\qnatural
+
+\b \cf0 NO WARRANTY\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls4\ilvl0
+\b0 \cf0 {\listtext 1. }BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\
+{\listtext 2. }IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\
+\pard\pardeftab720\sa300\ql\qnatural
+
+\b \cf0 END OF TERMS AND CONDITIONS\
+How to Apply These Terms to Your New Programs\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\b0 \cf0 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.\
+\pard\pardeftab720\ql\qnatural
+
+\f3\i \cf0 one line to give the program's name and an idea of what it does.
+\f2\i0 \
+Copyright (C)
+\f3\i yyyy
+\f2\i0
+\f3\i name of author
+\f2\i0 \
+\
+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.\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\f0 \cf0 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:\
+\pard\pardeftab720\ql\qnatural
+
+\f2 \cf0 Gnomovision version 69, Copyright (C)
+\f3\i year
+\f2\i0
+\f3\i name of author
+\f2\i0 \
+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.\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\f0 \cf0 The hypothetical commands
+\f2 `show w'
+\f0 and
+\f2 `show c'
+\f0 should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than
+\f2 `show w'
+\f0 and
+\f2 `show c'
+\f0 ; 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:\
+\pard\pardeftab720\ql\qnatural
+
+\f2 \cf0 Yoyodyne, Inc., hereby disclaims all copyright\
+interest in the program `Gnomovision'\
+(which makes passes at compilers) written \
+by James Hacker.\
+\
+\pard\pardeftab720\ql\qnatural
+
+\f3\i \cf0 signature of Ty Coon
+\f2\i0 , 1 April 1989\
+Ty Coon, President of Vice\
+\pard\pardeftab720\sa280\ql\qnatural
+
+\f0\b\fs36 \cf0 GNU LIBRARY GENERAL PUBLIC LICENSE\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\b0\fs24 \cf0 Version 2, June 1991\
+\pard\pardeftab720\ql\qnatural
+
+\f2 \cf0 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.]\
+\pard\pardeftab720\sa300\ql\qnatural
+
+\f0\b \cf0 Preamble\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\b0 \cf0 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.\
+\pard\pardeftab720\sa300\ql\qnatural
+
+\b \cf0 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\
+\pard\pardeftab720\sa240\ql\qnatural
+\cf0 0.
+\b0 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.\
+
+\b 1.
+\b0 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.\
+
+\b 2.
+\b0 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:\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls5\ilvl0\cf0 {\listtext 1. }The modified work must itself be a software library.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural
+\ls5\ilvl0\cf0 {\listtext 2. }\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls5\ilvl0\cf0 {\listtext 3. }You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural
+\ls5\ilvl0\cf0 {\listtext 4. }\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls5\ilvl0\cf0 {\listtext 5. }You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural
+\ls5\ilvl0\cf0 {\listtext 6. }\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls5\ilvl0\cf0 {\listtext 7. }If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural
+\ls5\ilvl0\cf0 {\listtext 8. }(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.)\
+\pard\pardeftab720\sa240\ql\qnatural
+\cf0 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.\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\b \cf0 3.
+\b0 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.\
+
+\b 4.
+\b0 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.\
+
+\b 5.
+\b0 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.\
+
+\b 6.
+\b0 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:\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls6\ilvl0\cf0 {\listtext 1. }Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.)\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural
+\ls6\ilvl0\cf0 {\listtext 2. }\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls6\ilvl0\cf0 {\listtext 3. }Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural
+\ls6\ilvl0\cf0 {\listtext 4. }\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls6\ilvl0\cf0 {\listtext 5. }If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural
+\ls6\ilvl0\cf0 {\listtext 6. }\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls6\ilvl0\cf0 {\listtext 7. }Verify that the user has already received a copy of these materials or that you have already sent this user a copy.\
+\pard\pardeftab720\sa240\ql\qnatural
+\cf0 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.\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\b \cf0 7.
+\b0 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:\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls7\ilvl0\cf0 {\listtext 1. }Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above.\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural
+\ls7\ilvl0\cf0 {\listtext 2. }\
+\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural
+\ls7\ilvl0\cf0 {\listtext 3. }Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\b \cf0 8.
+\b0 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.\
+
+\b 9.
+\b0 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.\
+
+\b 10.
+\b0 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.\
+
+\b 11.
+\b0 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.\
+
+\b 12.
+\b0 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.\
+
+\b 13.
+\b0 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.\
+
+\b 14.
+\b0 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.\
+
+\b NO WARRANTY
+\b0 \
+
+\b 15.
+\b0 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.\
+
+\b 16.
+\b0 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.\
+\pard\pardeftab720\sa300\ql\qnatural
+
+\b \cf0 END OF TERMS AND CONDITIONS\
+How to Apply These Terms to Your New Libraries\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\b0 \cf0 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.\
+\pard\pardeftab720\ql\qnatural
+
+\f3\i \cf0 one line to give the library's name and an idea of what it does.
+\f2\i0 \
+Copyright (C)
+\f3\i year
+\f2\i0
+\f3\i name of author
+\f2\i0 \
+\
+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\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\f0 \cf0 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:\
+\pard\pardeftab720\ql\qnatural
+
+\f2 \cf0 Yoyodyne, Inc., hereby disclaims all copyright interest in\
+the library `Frob' (a library for tweaking knobs) written\
+by James Random Hacker.\
+\
+\pard\pardeftab720\ql\qnatural
+
+\f3\i \cf0 signature of Ty Coon
+\f2\i0 , 1 April 1990\
+Ty Coon, President of Vice\
+\pard\pardeftab720\sa240\ql\qnatural
+
+\f0 \cf0 That's all there is to it!\
+} \ No newline at end of file
diff --git a/packaging/WELCOME.rtf b/packaging/WELCOME.rtf
new file mode 100644
index 000000000..aae117479
--- /dev/null
+++ b/packaging/WELCOME.rtf
@@ -0,0 +1,24 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1009\cocoasubrtf300
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\margl1440\margr1440\margb1800\margt1800\vieww9000\viewh8400\viewkind0
+\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
+
+\f0\fs24 \cf0 This program will install CUPS @CUPS_VERSION@, replacing the CUPS software that is included with Mac OS X.\
+\
+
+\b WARNING\
+
+\b0 \
+This is pre-release software and should not be used in production environments. Because Mac OS X packages cannot be uninstalled, you will need to reinstall Mac OS X to revert to the original CUPS software.\
+\
+Please report all problems using the Bugs & Features page on the CUPS home page:\
+\
+ {\field{\*\fldinst{HYPERLINK "http://www.cups.org/str.php"}}{\fldrslt http://www.cups.org/str.php}}\
+\
+
+\b NO WARRANTY\
+
+\b0 \
+CUPS is provided under the terms of the GNU General Public License and GNU Library General Public License versions 2. 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.\
+} \ No newline at end of file
diff --git a/packaging/cups-desc.plist.in b/packaging/cups-desc.plist.in
new file mode 100644
index 000000000..4d1d29688
--- /dev/null
+++ b/packaging/cups-desc.plist.in
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IFPkgDescriptionDeleteWarning</key>
+ <string></string>
+ <key>IFPkgDescriptionDescription</key>
+ <string>CUPS provides a portable printing layer for UNIX(r) operating systems.</string>
+ <key>IFPkgDescriptionTitle</key>
+ <string>CUPS</string>
+ <key>IFPkgDescriptionVersion</key>
+ <string>@CUPS_RELEASE@</string>
+</dict>
+</plist>
diff --git a/packaging/cups-info.plist.in b/packaging/cups-info.plist.in
new file mode 100644
index 000000000..d1f61348b
--- /dev/null
+++ b/packaging/cups-info.plist.in
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IFPkgFlagAuthorizationAction</key>
+ <string>RootAuthorization</string>
+ <key>IFPkgFlagBackgroundAlignment</key>
+ <string>bottomleft</string>
+ <key>IFPkgFlagBackgroundScaling</key>
+ <string>none</string>
+ <key>IFPkgFormatVersion</key>
+ <real>0.1</real>
+ <key>CFBundleIdentifier</key>
+ <string>org.cups.cups</string>
+ <key>CFBundleName</key>
+ <string>CUPS</string>
+ <key>CFBundleGetInfoString</key>
+ <string>CUPS, @CUPS_VERSION@</string>
+ <key>CFBundleShortVersionString</key>
+ <string>@CUPS_RELEASE@</string>
+ <key>IFPkgFlagAllowBackRev</key>
+ <true/>
+ <key>IFPkgFlagRootVolumeOnly</key>
+ <true/>
+</dict>
+</plist>
diff --git a/packaging/cups.list.in b/packaging/cups.list.in
new file mode 100644
index 000000000..e83e73a0b
--- /dev/null
+++ b/packaging/cups.list.in
@@ -0,0 +1,800 @@
+#
+# "$Id$"
+#
+# ESP Package Manager (EPM) file list for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2007 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+# Product information
+%product CUPS
+%copyright 2007-2011 by Apple Inc.
+%vendor Apple Inc.
+#%license LICENSE.txt
+%readme LICENSE.txt
+%format rpm
+# Red Hat and their epochs...
+%version 1:@CUPS_VERSION@
+%format !rpm
+%version @CUPS_VERSION@
+%format all
+%description CUPS is the standards-based, open source printing system developed by
+%description Apple Inc. for Mac OS® X and other UNIX®-like operating systems.
+
+%format rpm
+%provides lpd
+%provides lpr
+%provides LPRng
+%replaces lpd
+%replaces lpr
+%replaces LPRng
+%requires cups-libs 1:@CUPS_VERSION@
+
+# Replace all of the old localization subpackages from CUPS 1.2/1.3
+%replaces cups-da
+%replaces cups-de
+%replaces cups-es
+%replaces cups-et
+%replaces cups-fi
+%replaces cups-fr
+%replaces cups-he
+%replaces cups-id
+%replaces cups-it
+%replaces cups-ja
+%replaces cups-ko
+%replaces cups-nl
+%replaces cups-no
+%replaces cups-pl
+%replaces cups-pt
+%replaces cups-ru
+%replaces cups-sv
+%replaces cups-zh
+
+
+%format deb
+%provides cupsys
+%provides cupsys-client
+%provides cupsys-bsd
+%requires cups-libs
+
+# Replace all of the old localization subpackages from CUPS 1.2/1.3
+%replaces cups-da
+%replaces cups-de
+%replaces cups-es
+%replaces cups-et
+%replaces cups-fi
+%replaces cups-fr
+%replaces cups-he
+%replaces cups-id
+%replaces cups-it
+%replaces cups-ja
+%replaces cups-ko
+%replaces cups-nl
+%replaces cups-no
+%replaces cups-pl
+%replaces cups-pt
+%replaces cups-ru
+%replaces cups-sv
+%replaces cups-zh
+
+
+%format pkg
+%replaces SUNWlpmsg LP Alerts
+%replaces SUNWlpr LP Print Service, (Root)
+%replaces SUNWlps LP Print Service - Server, (Usr)
+%replaces SUNWlpu LP Print Service - Client, (Usr)
+%replaces SUNWpsu LP Print Server, (Usr)
+%replaces SUNWpsr LP Print Server, (Root)
+%replaces SUNWpcu LP Print Client, (Usr)
+%replaces SUNWpcr LP Print Client, (Root)
+%replaces SUNWppm
+%replaces SUNWmp
+%replaces SUNWscplp SunOS Print Compatibility
+
+%format inst
+%replaces patch*.print_*.* 0 0 1289999999 1289999999
+%replaces maint*.print_*.* 0 0 1289999999 1289999999
+%replaces print 0 0 1289999999 1289999999
+%replaces fw_cups 0 0 1289999999 1289999999
+%incompat patch*.print_*.* 0 0 1289999999 1289999999
+%incompat maint*.print_*.* 0 0 1289999999 1289999999
+%incompat print 0 0 1289999999 1289999999
+%incompat fw_cups 0 0 1289999999 1289999999
+%requires cups.sw.libs
+
+# Replace all of the old localization subpackages from CUPS 1.2/1.3
+%replaces cups.sw.da
+%replaces cups.sw.de
+%replaces cups.sw.es
+%replaces cups.sw.et
+%replaces cups.sw.fi
+%replaces cups.sw.fr
+%replaces cups.sw.he
+%replaces cups.sw.id
+%replaces cups.sw.it
+%replaces cups.sw.ja
+%replaces cups.sw.ko
+%replaces cups.sw.nl
+%replaces cups.sw.no
+%replaces cups.sw.pl
+%replaces cups.sw.pt
+%replaces cups.sw.ru
+%replaces cups.sw.sv
+%replaces cups.sw.zh
+
+%format portable
+%requires cups-libs
+
+# Replace all of the old localization subpackages from CUPS 1.2/1.3
+%replaces cups-da
+%replaces cups-de
+%replaces cups-es
+%replaces cups-et
+%replaces cups-fi
+%replaces cups-fr
+%replaces cups-he
+%replaces cups-id
+%replaces cups-it
+%replaces cups-ja
+%replaces cups-ko
+%replaces cups-nl
+%replaces cups-no
+%replaces cups-pl
+%replaces cups-pt
+%replaces cups-ru
+%replaces cups-sv
+%replaces cups-zh
+
+%format all
+
+%subpackage libs
+%description Shared libraries
+%format deb
+%provides libcups1
+%provides libcupsys2
+%provides libcupsys2-gnutls10
+%provides libcupsimage2
+%format all
+
+%subpackage devel
+%description Development environment
+%format deb
+%provides libcupsys2-dev
+%provides libcupsimage2-dev
+%format all
+
+%subpackage lpd
+%description LPD support
+
+%subpackage
+
+
+#
+# GNU variables...
+#
+
+$prefix=@prefix@
+$exec_prefix=@exec_prefix@
+$bindir=@bindir@
+$datarootdir=@datarootdir@
+$datadir=@datadir@
+$includedir=@includedir@
+$infodir=@infodir@
+$libdir=@libdir@
+$libexecdir=@libexecdir@
+$localstatedir=@localstatedir@
+$mandir=@mandir@
+$oldincludedir=@oldincludedir@
+$sbindir=@sbindir@
+$sharedstatedir=@sharedstatedir@
+$srcdir=@srcdir@
+$sysconfdir=@sysconfdir@
+$top_srcdir=@top_srcdir@
+
+#
+# ESP variables...
+#
+
+$AMANDIR=@AMANDIR@
+$BINDIR=@bindir@
+$CACHEDIR=@CUPS_CACHEDIR@
+$DATADIR=@CUPS_DATADIR@
+$DOCDIR=@CUPS_DOCROOT@
+$INCLUDEDIR=${includedir}
+$INITDIR=@INITDIR@
+$INITDDIR=@INITDDIR@
+$LIBDIR=${libdir}
+$LOCALEDIR=@CUPS_LOCALEDIR@
+$LOGDIR=@CUPS_LOGDIR@
+$MANDIR=@mandir@
+$PAMDIR=@PAMDIR@
+$PMANDIR=@PMANDIR@
+$REQUESTS=@CUPS_REQUESTS@
+$SBINDIR=@sbindir@
+$SERVERBIN=@CUPS_SERVERBIN@
+$SERVERROOT=@CUPS_SERVERROOT@
+$STATEDIR=@CUPS_STATEDIR@
+$XINETD=@XINETD@
+$LIB32DIR=@LIB32DIR@
+$LIB64DIR=@LIB64DIR@
+
+$IMGFILTERS=@IMGFILTERS@
+$MDNS=@MDNS@
+$PDFTOPS=@PDFTOPS@
+
+$CUPS_USER=@CUPS_USER@
+$CUPS_GROUP=@CUPS_GROUP@
+$CUPS_PRIMARY_SYSTEM_GROUP=@CUPS_PRIMARY_SYSTEM_GROUP@
+$CUPS_PERM=0@CUPS_CONFIG_FILE_PERM@
+
+$INSTALLSTATIC=@INSTALLSTATIC@
+
+$MAN1EXT=@MAN1EXT@
+$MAN3EXT=@MAN3EXT@
+$MAN5EXT=@MAN5EXT@
+$MAN7EXT=@MAN7EXT@
+$MAN8EXT=@MAN8EXT@
+$MAN8DIR=@MAN8DIR@
+
+$DSOLIBS=@DSOLIBS@
+
+# Make sure the MD5 password file is now owned by CUPS_USER...
+%postinstall if test -f $SERVERROOT/passwd.md5; then
+%postinstall chown $CUPS_USER $SERVERROOT/passwd.md5
+%postinstall fi
+
+# Make sure the shared libraries are refreshed...
+%subpackage libs
+%system linux
+%postinstall ldconfig
+%system all
+%subpackage
+
+# Server programs
+%system all
+# Server files
+f 0555 root sys $SBINDIR/cupsd scheduler/cupsd
+
+d 0755 root sys $SERVERBIN -
+%system darwin
+d 0755 root sys $SERVERBIN/apple -
+f 0555 root sys $SERVERBIN/apple/ipp backend/ipp
+l 0755 root sys $SERVERBIN/apple/http ipp
+l 0755 root sys $SERVERBIN/apple/https ipp
+l 0755 root sys $SERVERBIN/apple/ipps ipp
+%system all
+d 0755 root sys $SERVERBIN/backend -
+f 0500 root sys $SERVERBIN/backend/ipp backend/ipp
+l 0700 root sys $SERVERBIN/backend/http ipp
+l 0700 root sys $SERVERBIN/backend/https ipp
+l 0700 root sys $SERVERBIN/backend/ipps ipp
+f 0500 root sys $SERVERBIN/backend/lpd backend/lpd
+%if DNSSD_BACKEND
+f 0500 root sys $SERVERBIN/backend/dnssd backend/dnssd
+l 0700 root sys $SERVERBIN/backend/mdns dnssd
+%endif
+%system !darwin
+f 0555 root sys $SERVERBIN/backend/parallel backend/parallel
+%system all
+f 0555 root sys $SERVERBIN/backend/serial backend/serial
+f 0555 root sys $SERVERBIN/backend/snmp backend/snmp
+f 0555 root sys $SERVERBIN/backend/socket backend/socket
+f 0555 root sys $SERVERBIN/backend/usb backend/usb
+d 0755 root sys $SERVERBIN/cgi-bin -
+f 0555 root sys $SERVERBIN/cgi-bin/admin.cgi cgi-bin/admin.cgi
+f 0555 root sys $SERVERBIN/cgi-bin/classes.cgi cgi-bin/classes.cgi
+f 0555 root sys $SERVERBIN/cgi-bin/help.cgi cgi-bin/help.cgi
+f 0555 root sys $SERVERBIN/cgi-bin/jobs.cgi cgi-bin/jobs.cgi
+f 0555 root sys $SERVERBIN/cgi-bin/printers.cgi cgi-bin/printers.cgi
+d 0755 root sys $SERVERBIN/daemon -
+f 0555 root sys $SERVERBIN/daemon/cups-deviced scheduler/cups-deviced
+f 0555 root sys $SERVERBIN/daemon/cups-driverd scheduler/cups-driverd
+f 0555 root sys $SERVERBIN/daemon/cups-polld scheduler/cups-polld
+d 0755 root sys $SERVERBIN/driver -
+d 0755 root sys $SERVERBIN/filter -
+f 0555 root sys $SERVERBIN/filter/bannertops filter/bannertops
+f 0555 root sys $SERVERBIN/filter/commandtoespcx driver/commandtoescpx
+f 0555 root sys $SERVERBIN/filter/commandtopclx driver/commandtopclx
+f 0555 root sys $SERVERBIN/filter/commandtops filter/commandtops
+f 0555 root sys $SERVERBIN/filter/gziptoany filter/gziptoany
+%if IMGFILTERS
+f 0555 root sys $SERVERBIN/filter/imagetops filter/imagetops
+f 0555 root sys $SERVERBIN/filter/imagetoraster filter/imagetoraster
+%endif
+%if PDFTOPS
+f 0555 root sys $SERVERBIN/filter/pdftops filter/pdftops
+%endif
+f 0555 root sys $SERVERBIN/filter/pstops filter/pstops
+f 0555 root sys $SERVERBIN/filter/rastertoespcx driver/rastertoescpx
+f 0555 root sys $SERVERBIN/filter/rastertolabel filter/rastertolabel
+l 0755 root sys $SERVERBIN/filter/rastertodymo rastertolabel
+f 0555 root sys $SERVERBIN/filter/rastertoepson filter/rastertoepson
+f 0555 root sys $SERVERBIN/filter/rastertohp filter/rastertohp
+f 0555 root sys $SERVERBIN/filter/rastertopclx driver/rastertopclx
+f 0555 root sys $SERVERBIN/filter/rastertopwg filter/rastertopwg
+f 0555 root sys $SERVERBIN/filter/texttops filter/texttops
+d 0755 root sys $SERVERBIN/notifier -
+f 0555 root sys $SERVERBIN/notifier/mailto notifier/mailto
+
+%subpackage lpd
+d 0755 root sys $SERVERBIN/daemon -
+f 0555 root sys $SERVERBIN/daemon/cups-lpd scheduler/cups-lpd
+%subpackage
+
+# Admin commands
+d 0755 root sys $BINDIR -
+l 0755 root sys $BINDIR/enable $SBINDIR/cupsaccept
+l 0755 root sys $BINDIR/disable $SBINDIR/cupsaccept
+d 0755 root sys $LIBDIR -
+l 0755 root sys $LIBDIR/accept $SBINDIR/cupsaccept
+l 0755 root sys $LIBDIR/lpadmin $SBINDIR/lpadmin
+l 0755 root sys $LIBDIR/reject $SBINDIR/cupsaccept
+d 0755 root sys $SBINDIR -
+l 0755 root sys $SBINDIR/accept cupsaccept
+f 0555 root sys $SBINDIR/cupsaccept systemv/cupsaccept
+f 0555 root sys $SBINDIR/cupsaddsmb systemv/cupsaddsmb
+f 0555 root sys $SBINDIR/cupsctl systemv/cupsctl
+l 0755 root sys $SBINDIR/cupsdisable accept
+l 0755 root sys $SBINDIR/cupsenable accept
+l 0755 root sys $SBINDIR/cupsreject accept
+f 0555 root sys $SBINDIR/lpadmin systemv/lpadmin
+f 0555 root sys $SBINDIR/lpc berkeley/lpc
+f 0555 root sys $SBINDIR/lpinfo systemv/lpinfo
+f 0555 root sys $SBINDIR/lpmove systemv/lpmove
+l 0755 root sys $SBINDIR/reject cupsaccept
+
+%system irix
+l 0755 root sys /usr/etc/lpc $SBINDIR/lpc
+%system all
+
+# User commands
+d 0755 root sys $BINDIR -
+f 0555 root sys $BINDIR/cancel systemv/cancel
+f 0555 root sys $BINDIR/cupstestdsc systemv/cupstestdsc
+f 0555 root sys $BINDIR/cupstestppd systemv/cupstestppd
+f 0555 root sys $BINDIR/ipptool test/ipptool
+f 0555 root sys $BINDIR/lp systemv/lp
+f 0555 root sys $BINDIR/lpoptions systemv/lpoptions
+f 0555 root sys $BINDIR/lppasswd systemv/lppasswd
+f 0555 root sys $BINDIR/lpq berkeley/lpq
+f 0555 root sys $BINDIR/lpr berkeley/lpr
+f 0555 root sys $BINDIR/lprm berkeley/lprm
+f 0555 root sys $BINDIR/lpstat systemv/lpstat
+
+%system irix
+l 0755 root sys /usr/bsd/lpq $BINDIR/lpq
+l 0755 root sys /usr/bsd/lpr $BINDIR/lpr
+l 0755 root sys /usr/bsd/lprm $BINDIR/lprm
+%system all
+
+# DSOs
+%if DSOLIBS
+%subpackage libs
+%system hpux
+f 0555 root sys $LIBDIR/libcups.sl.2 cups/libcups.sl.2 nostrip()
+l 0755 root sys $LIBDIR/libcups.sl libcups.sl.2
+f 0555 root sys $LIBDIR/libcupscgi.sl.1 cgi-bin/libcupscgi.sl.1 nostrip()
+l 0755 root sys $LIBDIR/libcupscgi.sl libcupscgi.sl.1
+f 0555 root sys $LIBDIR/libcupsdriver.sl.1 driver/libcupsdriver.sl.1 nostrip()
+l 0755 root sys $LIBDIR/libcupsdriver.sl libcupsdriver.sl.1
+f 0555 root sys $LIBDIR/libcupsimage.sl.2 filter/libcupsimage.sl.2 nostrip()
+l 0755 root sys $LIBDIR/libcupsimage.sl libcupsimage.sl.2
+f 0555 root sys $LIBDIR/libcupsmime.sl.1 scheduler/libcupsmime.sl.1 nostrip()
+l 0755 root sys $LIBDIR/libcupsmime.sl libcupsmime.sl.1
+f 0555 root sys $LIBDIR/libcupsppdc.sl.1 ppdc/libcupsppdc.sl.1 nostrip()
+l 0755 root sys $LIBDIR/libcupsppdc.sl libcupsppdc.sl.1
+%system aix
+f 0555 root sys $LIBDIR/libcups_s.a cups/libcups_s.a nostrip()
+f 0555 root sys $LIBDIR/libcupscgi_s.a cgi-bin/libcupscgi_s.a nostrip()
+f 0555 root sys $LIBDIR/libcupsdriver_s.a driver/libcupsdriver_s.a nostrip()
+f 0555 root sys $LIBDIR/libcupsimage_s.a filter/libcupsimage_s.a nostrip()
+f 0555 root sys $LIBDIR/libcupsmime_s.a scheduler/libcupsmime_s.a nostrip()
+f 0555 root sys $LIBDIR/libcupsppdc_s.a ppdc/libcupsppdc_s.a nostrip()
+%system darwin
+f 0555 root sys $LIBDIR/libcups.2.dylib cups/libcups.2.dylib nostrip()
+l 0755 root sys $LIBDIR/libcups.dylib libcups.2.dylib
+f 0555 root sys $LIBDIR/libcupscgi.1.dylib cgi-bin/libcupscgi.1.dylib nostrip()
+l 0755 root sys $LIBDIR/libcupscgi.dylib libcupscgi.1.dylib
+f 0555 root sys $LIBDIR/libcupsdriver.1.dylib driver/libcupsdriver.1.dylib nostrip()
+l 0755 root sys $LIBDIR/libcupsdriver.dylib libcupsdriver.1.dylib
+f 0555 root sys $LIBDIR/libcupsimage.2.dylib filter/libcupsimage.2.dylib nostrip()
+l 0755 root sys $LIBDIR/libcupsimage.dylib libcupsimage.2.dylib
+f 0555 root sys $LIBDIR/libcupsmime.1.dylib scheduler/libcupsmime.1.dylib nostrip()
+l 0755 root sys $LIBDIR/libcupsmime.dylib libcupsmime.1.dylib
+f 0555 root sys $LIBDIR/libcupsppdc.1.dylib ppdc/libcupsppdc.1.dylib nostrip()
+l 0755 root sys $LIBDIR/libcupsppdc.dylib libcupsppdc.1.dylib
+%system !hpux !aix !darwin
+f 0555 root sys $LIBDIR/libcups.so.2 cups/libcups.so.2 nostrip()
+l 0755 root sys $LIBDIR/libcups.so libcups.so.2
+f 0555 root sys $LIBDIR/libcupscgi.so.1 cgi-bin/libcupscgi.so.1 nostrip()
+l 0755 root sys $LIBDIR/libcupscgi.so libcupscgi.so.1
+f 0555 root sys $LIBDIR/libcupsdriver.so.1 driver/libcupsdriver.so.1 nostrip()
+l 0755 root sys $LIBDIR/libcupsdriver.so libcupsdriver.so.1
+f 0555 root sys $LIBDIR/libcupsimage.so.2 filter/libcupsimage.so.2 nostrip()
+l 0755 root sys $LIBDIR/libcupsimage.so libcupsimage.so.2
+f 0555 root sys $LIBDIR/libcupsmime.so.1 scheduler/libcupsmime.so.1 nostrip()
+l 0755 root sys $LIBDIR/libcupsmime.so libcupsmime.so.1
+f 0555 root sys $LIBDIR/libcupsppdc.so.1 ppdc/libcupsppdc.so.1 nostrip()
+l 0755 root sys $LIBDIR/libcupsppdc.so libcupsppdc.so.1
+%system all
+%subpackage
+%endif
+
+%if LIB32DIR
+%subpackage libs
+f 0555 root sys $LIB32DIR/libcups.so.2 cups/libcups.32.so.2 nostrip()
+l 0755 root sys $LIB32DIR/libcups.so libcups.so.2
+f 0555 root sys $LIB32DIR/libcupscgi.so.1 cgi-bin/libcupscgi.32.so.1 nostrip()
+l 0755 root sys $LIB32DIR/libcupscgi.so libcupscgi.so.1
+f 0555 root sys $LIB32DIR/libcupsdriver.so.1 driver/libcupsdriver.32.so.1 nostrip()
+l 0755 root sys $LIB32DIR/libcupsdriver.so libcupsdriver.so.1
+f 0555 root sys $LIB32DIR/libcupsimage.so.2 filter/libcupsimage.32.so.2 nostrip()
+l 0755 root sys $LIB32DIR/libcupsimage.so libcupsimage.so.2
+f 0555 root sys $LIB32DIR/libcupsmime.so.1 scheduler/libcupsmime.32.so.1 nostrip()
+l 0755 root sys $LIB32DIR/libcupsmime.so libcupsmime.so.1
+f 0555 root sys $LIB32DIR/libcupsppdc.so.1 ppdc/libcupsppdc.32.so.1 nostrip()
+l 0755 root sys $LIB32DIR/libcupsppdc.so libcupsppdc.so.1
+%system all
+%subpackage
+%endif
+
+%if LIB64DIR
+%subpackage libs
+f 0555 root sys $LIB64DIR/libcups.so.2 cups/libcups.64.so.2 nostrip()
+l 0755 root sys $LIB64DIR/libcups.so libcups.so.2
+f 0555 root sys $LIB64DIR/libcupscgi.so.1 cgi-bin/libcupscgi.64.so.1 nostrip()
+l 0755 root sys $LIB64DIR/libcupscgi.so libcupscgi.so.1
+f 0555 root sys $LIB64DIR/libcupsdriver.so.1 driver/libcupsdriver.64.so.1 nostrip()
+l 0755 root sys $LIB64DIR/libcupsdriver.so libcupsdriver.so.1
+f 0555 root sys $LIB64DIR/libcupsimage.so.2 filter/libcupsimage.64.so.2 nostrip()
+l 0755 root sys $LIB64DIR/libcupsimage.so libcupsimage.so.2
+f 0555 root sys $LIB64DIR/libcupsmime.so.1 scheduler/libcupsmime.64.so.1 nostrip()
+l 0755 root sys $LIB64DIR/libcupsmime.so libcupsmime.so.1
+f 0555 root sys $LIB64DIR/libcupsppdc.so.1 ppdc/libcupsppdc.64.so.1 nostrip()
+l 0755 root sys $LIB64DIR/libcupsppdc.so libcupsppdc.so.1
+%system all
+%subpackage
+%endif
+
+# Directories
+d 0755 root sys $LOGDIR -
+d 0710 root $CUPS_GROUP $REQUESTS -
+d 1770 root $CUPS_GROUP $REQUESTS/tmp -
+d 0775 root $CUPS_GROUP $CACHEDIR -
+d 0775 root $CUPS_GROUP $CACHEDIR/rss -
+#d 0755 root $CUPS_GROUP $CACHEDIR/ppd -
+d 0755 root $CUPS_GROUP $STATEDIR -
+d 0511 root $CUPS_PRIMARY_SYSTEM_GROUP $STATEDIR/certs -
+
+# Data files
+f 0444 root sys $LOCALEDIR/da/cups_da.po locale/cups_da.po
+f 0444 root sys $LOCALEDIR/de/cups_de.po locale/cups_de.po
+f 0444 root sys $LOCALEDIR/es/cups_es.po locale/cups_es.po
+#f 0444 root sys $LOCALEDIR/et/cups_et.po locale/cups_et.po
+f 0444 root sys $LOCALEDIR/eu/cups_eu.po locale/cups_eu.po
+f 0444 root sys $LOCALEDIR/fi/cups_fi.po locale/cups_fi.po
+f 0444 root sys $LOCALEDIR/fr/cups_fr.po locale/cups_fr.po
+#f 0444 root sys $LOCALEDIR/he/cups_he.po locale/cups_he.po
+f 0444 root sys $LOCALEDIR/id/cups_id.po locale/cups_id.po
+f 0444 root sys $LOCALEDIR/it/cups_it.po locale/cups_it.po
+f 0444 root sys $LOCALEDIR/ja/cups_ja.po locale/cups_ja.po
+f 0444 root sys $LOCALEDIR/ko/cups_ko.po locale/cups_ko.po
+f 0444 root sys $LOCALEDIR/nl/cups_nl.po locale/cups_nl.po
+f 0444 root sys $LOCALEDIR/no/cups_no.po locale/cups_no.po
+f 0444 root sys $LOCALEDIR/pl/cups_pl.po locale/cups_pl.po
+f 0444 root sys $LOCALEDIR/pt/cups_pt.po locale/cups_pt.po
+f 0444 root sys $LOCALEDIR/pt_BR/cups_pt_BR.po locale/cups_pt_BR.po
+f 0444 root sys $LOCALEDIR/ru/cups_ru.po locale/cups_ru.po
+f 0444 root sys $LOCALEDIR/sv/cups_sv.po locale/cups_sv.po
+f 0444 root sys $LOCALEDIR/zh/cups_zh.po locale/cups_zh.po
+f 0444 root sys $LOCALEDIR/zh_TW/cups_zh_TW.po locale/cups_zh_TW.po
+
+d 0755 root sys $DATADIR -
+
+d 0755 root sys $DATADIR/banners -
+f 0444 root sys $DATADIR/banners/classified data/classified
+f 0444 root sys $DATADIR/banners/confidential data/confidential
+f 0444 root sys $DATADIR/banners/secret data/secret
+f 0444 root sys $DATADIR/banners/standard data/standard
+f 0444 root sys $DATADIR/banners/topsecret data/topsecret
+f 0444 root sys $DATADIR/banners/unclassified data/unclassified
+
+d 0755 root sys $DATADIR/charsets -
+f 0444 root sys $DATADIR/charsets/utf-8 data/utf-8
+
+d 0755 root sys $DATADIR/data -
+f 0444 root sys $DATADIR/data/psglyphs data/psglyphs
+f 0444 root sys $DATADIR/data/testprint data/testprint
+
+d 0755 root sys $DATADIR/drv -
+f 0444 root sys $DATADIR/drv/sample.drv ppdc/sample.drv
+
+d 0755 root sys $DATADIR/examples -
+f 0444 root sys $DATADIR/examples examples/*.drv
+
+d 0755 root sys $DATADIR/fonts -
+f 0444 root sys $DATADIR/fonts fonts/Monospace*
+
+d 0755 root sys $DATADIR/ipptool -
+f 0444 root sys $DATADIR/ipptool/create-printer-subscription.test test/create-printer-subscription.test
+f 0444 root sys $DATADIR/ipptool/get-completed-jobs.test test/get-completed-jobs.test
+f 0444 root sys $DATADIR/ipptool/get-jobs.test test/get-jobs.test
+f 0444 root sys $DATADIR/ipptool test/ipp-*.test
+f 0444 root sys $DATADIR/ipptool test/testfile.*
+
+d 0755 root sys $DATADIR/mime -
+f 0444 root sys $DATADIR/mime/mime.convs conf/mime.convs
+f 0444 root sys $DATADIR/mime/mime.types conf/mime.types
+
+d 0755 root sys $DATADIR/model -
+
+d 0755 root sys $DATADIR/ppdc -
+f 0444 root sys $DATADIR/ppdc data/*.defs
+f 0444 root sys $DATADIR/ppdc data/*.h
+
+d 0755 root sys $DATADIR/templates -
+f 0444 root sys $DATADIR/templates templates/*.tmpl
+
+## Template files
+d 0755 root sys $DATADIR/templates/de
+f 0444 root sys $DATADIR/templates/de templates/de/*.tmpl
+
+d 0755 root sys $DATADIR/templates/es
+f 0444 root sys $DATADIR/templates/es templates/es/*.tmpl
+
+#d 0755 root sys $DATADIR/templates/et
+#f 0444 root sys $DATADIR/templates/et templates/et/*.tmpl
+
+d 0755 root sys $DATADIR/templates/eu
+f 0444 root sys $DATADIR/templates/eu templates/eu/*.tmpl
+
+#d 0755 root sys $DATADIR/templates/fr
+#f 0444 root sys $DATADIR/templates/fr templates/fr/*.tmpl
+
+#d 0755 root sys $DATADIR/templates/he
+#f 0444 root sys $DATADIR/templates/he templates/he/*.tmpl
+
+d 0755 root sys $DATADIR/templates/id
+f 0444 root sys $DATADIR/templates/id templates/id/*.tmpl
+
+d 0755 root sys $DATADIR/templates/it
+f 0444 root sys $DATADIR/templates/it templates/it/*.tmpl
+
+d 0755 root sys $DATADIR/templates/ja
+f 0444 root sys $DATADIR/templates/ja templates/ja/*.tmpl
+
+d 0755 root sys $DATADIR/templates/pl
+f 0444 root sys $DATADIR/templates/pl templates/pl/*.tmpl
+
+d 0755 root sys $DATADIR/templates/ru
+f 0444 root sys $DATADIR/templates/ru templates/ru/*.tmpl
+
+#d 0755 root sys $DATADIR/templates/sv
+#f 0444 root sys $DATADIR/templates/sv templates/sv/*.tmpl
+
+#d 0755 root sys $DATADIR/templates/zh_TW
+#f 0444 root sys $DATADIR/templates/zh_TW templates/zh_TW/*.tmpl
+
+# Config files
+d 0755 root sys $SERVERROOT -
+d 0755 root $CUPS_GROUP $SERVERROOT/interfaces -
+d 0755 root $CUPS_GROUP $SERVERROOT/ppd -
+d 0700 root $CUPS_GROUP $SERVERROOT/ssl -
+c $CUPS_PERM root $CUPS_GROUP $SERVERROOT/ conf/*.conf
+f $CUPS_PERM root $CUPS_GROUP $SERVERROOT/cupsd.conf.default conf/cupsd.conf
+
+%if PAMDIR
+d 0755 root sys $PAMDIR -
+c 0644 root sys $PAMDIR/cups conf/@PAMFILE@
+%endif
+
+%subpackage devel
+# Developer files
+f 0555 root sys $BINDIR/cups-config cups-config
+d 0755 root sys $INCLUDEDIR/cups -
+f 0444 root sys $INCLUDEDIR/cups/adminutil.h cups/adminutil.h
+f 0444 root sys $INCLUDEDIR/cups/array.h cups/array.h
+f 0444 root sys $INCLUDEDIR/cups/backend.h cups/backend.h
+f 0444 root sys $INCLUDEDIR/cups/cups.h cups/cups.h
+f 0444 root sys $INCLUDEDIR/cups/dir.h cups/dir.h
+f 0444 root sys $INCLUDEDIR/cups/driver.h driver/driver.h
+f 0444 root sys $INCLUDEDIR/cups/file.h cups/file.h
+f 0444 root sys $INCLUDEDIR/cups/http.h cups/http.h
+f 0444 root sys $INCLUDEDIR/cups/image.h filter/image.h
+f 0444 root sys $INCLUDEDIR/cups/ipp.h cups/ipp.h
+f 0444 root sys $INCLUDEDIR/cups/mime.h scheduler/mime.h
+f 0444 root sys $INCLUDEDIR/cups/language.h cups/language.h
+f 0444 root sys $INCLUDEDIR/cups/ppd.h cups/ppd.h
+f 0444 root sys $INCLUDEDIR/cups/raster.h cups/raster.h
+f 0444 root sys $INCLUDEDIR/cups/transcode.h cups/transcode.h
+
+%if INSTALLSTATIC
+f 0444 root sys $LIBDIR/libcups.a cups/libcups.a
+f 0444 root sys $LIBDIR/libcupscgi.a cgi-bin/libcupscgi.a
+f 0444 root sys $LIBDIR/libcupsdriver.a driver/libcupsdriver.a
+f 0444 root sys $LIBDIR/libcupsimage.a filter/libcupsimage.a
+f 0444 root sys $LIBDIR/libcupsmime.a scheduler/libcupsmime.a
+f 0444 root sys $LIBDIR/libcupsppdc.a ppdc/libcupsppdc.a
+%endif
+
+d 0755 root sys $DOCDIR/help -
+f 0444 root sys $DOCDIR/help doc/help/api*.html
+f 0444 root sys $DOCDIR/help/postscript-driver.html doc/help/postscript-driver.html
+f 0444 root sys $DOCDIR/help/ppd-compiler.html doc/help/ppd-compiler.html
+f 0444 root sys $DOCDIR/help/raster-driver.html doc/help/raster-driver.html
+f 0444 root sys $DOCDIR/help doc/help/spec*.html
+%subpackage
+
+# Documentation files
+d 0755 root sys $DOCDIR -
+f 0444 root sys $DOCDIR doc/*.css
+f 0444 root sys $DOCDIR doc/*.html
+d 0755 root sys $DOCDIR/help -
+f 0444 root sys $DOCDIR/help/accounting.html doc/help/accounting.html
+f 0444 root sys $DOCDIR/help/cgi.html doc/help/cgi.html
+f 0444 root sys $DOCDIR/help/glossary.html doc/help/glossary.html
+f 0444 root sys $DOCDIR/help/kerberos.html doc/help/kerberos.html
+f 0444 root sys $DOCDIR/help/license.html doc/help/license.html
+f 0444 root sys $DOCDIR/help/network.html doc/help/network.html
+f 0444 root sys $DOCDIR/help/options.html doc/help/options.html
+f 0444 root sys $DOCDIR/help/overview.html doc/help/overview.html
+f 0444 root sys $DOCDIR/help/policies.html doc/help/policies.html
+f 0444 root sys $DOCDIR/help/security.html doc/help/security.html
+f 0444 root sys $DOCDIR/help/sharing.html doc/help/sharing.html
+f 0444 root sys $DOCDIR/help/standard.html doc/help/standard.html
+f 0444 root sys $DOCDIR/help/translation.html doc/help/translation.html
+f 0444 root sys $DOCDIR/help/whatsnew.html doc/help/whatsnew.html
+f 0444 root sys $DOCDIR/help doc/help/man-*.html
+f 0444 root sys $DOCDIR/help doc/help/ref-*.html
+d 0755 root sys $DOCDIR/images -
+f 0444 root sys $DOCDIR/images doc/images/*.gif
+f 0444 root sys $DOCDIR/images doc/images/*.jpg
+f 0444 root sys $DOCDIR/images doc/images/*.png
+f 0444 root sys $DOCDIR/robots.txt doc/robots.txt
+
+# Localized documentation files
+d 0755 root sys $DOCDIR/de
+f 0444 root sys $DOCDIR/de doc/de/*.html
+
+d 0755 root sys $DOCDIR/es
+f 0444 root sys $DOCDIR/es doc/es/*.html
+
+#d 0755 root sys $DOCDIR/et
+#f 0444 root sys $DOCDIR/et doc/et/*.html
+
+d 0755 root sys $DOCDIR/eu
+f 0444 root sys $DOCDIR/eu doc/eu/*.html
+
+#d 0755 root sys $DOCDIR/fr
+#f 0444 root sys $DOCDIR/fr doc/fr/*.html
+
+#d 0755 root sys $DOCDIR/he
+#f 0444 root sys $DOCDIR/he doc/he/*.html
+#f 0444 root sys $DOCDIR/he/cups.css doc/he/cups.css
+
+d 0755 root sys $DOCDIR/id
+f 0444 root sys $DOCDIR/id doc/id/*.html
+
+d 0755 root sys $DOCDIR/it
+f 0444 root sys $DOCDIR/it doc/it/*.html
+
+d 0755 root sys $DOCDIR/ja
+f 0444 root sys $DOCDIR/ja doc/ja/*.html
+
+d 0755 root sys $DOCDIR/pl
+f 0444 root sys $DOCDIR/pl doc/pl/*.html
+
+d 0755 root sys $DOCDIR/ru
+f 0444 root sys $DOCDIR/ru doc/ru/*.html
+
+#d 0755 root sys $DOCDIR/sv
+#f 0444 root sys $DOCDIR/sv doc/sv/*.html
+
+#d 0755 root sys $DOCDIR/zh_TW
+#f 0444 root sys $DOCDIR/zh_TW doc/zh_TW/*.html
+
+# Man pages
+d 0755 root sys $AMANDIR -
+d 0755 root sys $AMANDIR/man$MAN8DIR -
+d 0755 root sys $MANDIR -
+d 0755 root sys $MANDIR/man1 -
+d 0755 root sys $MANDIR/man5 -
+d 0755 root sys $MANDIR/man7 -
+
+f 0444 root sys $MANDIR/man1/cancel.$MAN1EXT man/cancel.$MAN1EXT
+f 0444 root sys $MANDIR/man1/cupstestdsc.$MAN1EXT man/cupstestdsc.$MAN1EXT
+f 0444 root sys $MANDIR/man1/cupstestppd.$MAN1EXT man/cupstestppd.$MAN1EXT
+f 0444 root sys $MANDIR/man1/ipptool.$MAN1EXT man/ipptool.$MAN1EXT
+f 0444 root sys $MANDIR/man1/lpoptions.$MAN1EXT man/lpoptions.$MAN1EXT
+f 0444 root sys $MANDIR/man1/lppasswd.$MAN1EXT man/lppasswd.$MAN1EXT
+f 0444 root sys $MANDIR/man1/lpq.$MAN1EXT man/lpq.$MAN1EXT
+f 0444 root sys $MANDIR/man1/lprm.$MAN1EXT man/lprm.$MAN1EXT
+f 0444 root sys $MANDIR/man1/lpr.$MAN1EXT man/lpr.$MAN1EXT
+f 0444 root sys $MANDIR/man1/lpstat.$MAN1EXT man/lpstat.$MAN1EXT
+f 0444 root sys $MANDIR/man1/lp.$MAN1EXT man/lp.$MAN1EXT
+
+f 0444 root sys $MANDIR/man5/classes.conf.$MAN5EXT man/classes.conf.$MAN5EXT
+f 0444 root sys $MANDIR/man5/cupsd.conf.$MAN5EXT man/cupsd.conf.$MAN5EXT
+f 0444 root sys $MANDIR/man5/ipptoolfile.$MAN5EXT man/ipptoolfile.$MAN5EXT
+f 0444 root sys $MANDIR/man5/mailto.conf.$MAN5EXT man/mailto.conf.$MAN5EXT
+f 0444 root sys $MANDIR/man5/mime.convs.$MAN5EXT man/mime.convs.$MAN5EXT
+f 0444 root sys $MANDIR/man5/mime.types.$MAN5EXT man/mime.types.$MAN5EXT
+f 0444 root sys $MANDIR/man5/printers.conf.$MAN5EXT man/printers.conf.$MAN5EXT
+
+l 0644 root sys $AMANDIR/man$MAN8DIR/accept.$MAN8EXT cupsaccept.$MAN8EXT
+f 0444 root sys $AMANDIR/man$MAN8DIR/cupsaccept.$MAN8EXT man/cupsaccept.$MAN8EXT
+l 0644 root sys $AMANDIR/man$MAN8DIR/cupsreject.$MAN8EXT cupsaccept.$MAN8EXT
+f 0444 root sys $AMANDIR/man$MAN8DIR/cupsaddsmb.$MAN8EXT man/cupsaddsmb.$MAN8EXT
+f 0444 root sys $AMANDIR/man$MAN8DIR/cupsctl.$MAN8EXT man/cupsctl.$MAN8EXT
+f 0444 root sys $AMANDIR/man$MAN8DIR/cupsfilter.$MAN8EXT man/cupsfilter.$MAN8EXT
+f 0444 root sys $AMANDIR/man$MAN8DIR/cups-polld.$MAN8EXT man/cups-polld.$MAN8EXT
+f 0444 root sys $AMANDIR/man$MAN8DIR/cupsd.$MAN8EXT man/cupsd.$MAN8EXT
+f 0444 root sys $AMANDIR/man$MAN8DIR/cupsenable.$MAN8EXT man/cupsenable.$MAN8EXT
+l 0644 root sys $AMANDIR/man$MAN8DIR/cupsdisable.$MAN8EXT cupsenable.$MAN8EXT
+l 0644 root sys $AMANDIR/man$MAN8DIR/disable.$MAN8EXT cupsenable.$MAN8EXT
+l 0644 root sys $AMANDIR/man$MAN8DIR/enable.$MAN8EXT cupsenable.$MAN8EXT
+f 0444 root sys $AMANDIR/man$MAN8DIR/lpadmin.$MAN8EXT man/lpadmin.$MAN8EXT
+f 0444 root sys $AMANDIR/man$MAN8DIR/lpc.$MAN8EXT man/lpc.$MAN8EXT
+f 0444 root sys $AMANDIR/man$MAN8DIR/lpinfo.$MAN8EXT man/lpinfo.$MAN8EXT
+f 0444 root sys $AMANDIR/man$MAN8DIR/lpmove.$MAN8EXT man/lpmove.$MAN8EXT
+l 0644 root sys $AMANDIR/man$MAN8DIR/reject.$MAN8EXT cupsaccept.$MAN8EXT
+
+%subpackage devel
+f 0444 root sys $MANDIR/man1/cups-config.$MAN1EXT man/cups-config.$MAN1EXT
+f 0444 root sys $MANDIR/man1/ man/ppd*.$MAN1EXT
+f 0444 root sys $MANDIR/man5/ppdcfile.$MAN5EXT man/ppdcfile.$MAN5EXT
+f 0444 root sys $MANDIR/man7/backend.$MAN7EXT man/backend.$MAN7EXT
+f 0444 root sys $MANDIR/man7/filter.$MAN7EXT man/filter.$MAN7EXT
+f 0444 root sys $MANDIR/man7/notifier.$MAN7EXT man/notifier.$MAN7EXT
+
+%subpackage lpd
+d 0755 root sys $AMANDIR/man$MAN8DIR -
+f 0444 root sys $AMANDIR/man$MAN8DIR/cups-lpd.$MAN8EXT man/cups-lpd.$MAN8EXT
+%subpackage
+
+# Startup scripts
+%system darwin
+f 0444 root sys /System/Library/LaunchDaemons/org.cups.cupsd.plist scheduler/org.cups.cupsd.plist
+%preremove <<EOF
+launchctl unload /System/Library/LaunchDaemons/org.cups.cupsd.plist || exit 0
+killall cupsd || exit 0
+EOF
+%preinstall <<EOF
+launchctl unload /System/Library/LaunchDaemons/org.cups.cupsd.plist || exit 0
+killall cupsd || exit 0
+EOF
+%postinstall <<EOF
+launchctl load -D system /System/Library/LaunchDaemons/org.cups.cupsd.plist
+EOF
+%subpackage lpd
+f 0444 root sys /System/Library/LaunchDaemons/org.cups.cups-lpd.plist scheduler/org.cups.cups-lpd.plist
+%preremove <<EOF
+launchctl unload /System/Library/LaunchDaemons/org.cups.cups-lpd.plist || exit 0
+EOF
+%preinstall <<EOF
+launchctl unload /System/Library/LaunchDaemons/org.cups.cups-lpd.plist || exit 0
+EOF
+%postinstall <<EOF
+rm -f /etc/xinetd.d/cups-lpd
+launchctl load -D system /System/Library/LaunchDaemons/org.cups.cupsd-lpd.plist
+EOF
+%subpackage
+
+%system !darwin
+i 0755 root sys cups scheduler/cups.sh start(@RCSTART@) stop(@RCSTOP) runlevels(@RCLEVELS@)
+%subpackage lpd
+%if XINETD
+f 0444 root sys $XINETD/cups-lpd scheduler/cups-lpd.xinetd
+%endif
+%subpackage
+
+#
+# End of "$Id$".
+#
diff --git a/packaging/cups.spec.in b/packaging/cups.spec.in
new file mode 100644
index 000000000..ceffd78a8
--- /dev/null
+++ b/packaging/cups.spec.in
@@ -0,0 +1,376 @@
+#
+# "$Id$"
+#
+# RPM "spec" file for CUPS.
+#
+# Original version by Jason McMullan <jmcc@ontv.com>.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 1999-2007 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+# Conditional build options (--with name/--without name):
+#
+# dbus - Enable/disable DBUS support (default = enable)
+# php - Enable/disable PHP support (default = enable)
+
+%{!?_with_dbus: %{!?_without_dbus: %define _with_dbus --with-dbus}}
+%{?_with_dbus: %define _dbus --enable-dbus}
+%{!?_with_dbus: %define _dbus --disable-dbus}
+
+%{!?_with_php: %{!?_without_php: %define _with_php --with-php}}
+%{?_with_php: %define _php --with-php}
+%{!?_with_php: %define _php --without-php}
+
+%{!?_with_static: %{!?_without_static: %define _without_static --without-static}}
+%{?_with_static: %define _static --enable-static}
+%{!?_with_static: %define _static --disable-static}
+
+Summary: CUPS
+Name: cups
+Version: @CUPS_VERSION@
+Release: 0
+Epoch: 1
+License: GPL
+Group: System Environment/Daemons
+Source: http://ftp.easysw.com/pub/cups/%{version}/cups-%{version}-source.tar.bz2
+Url: http://www.cups.org
+Packager: Anonymous <anonymous@foo.com>
+Vendor: Apple Inc.
+
+# Use buildroot so as not to disturb the version already installed
+BuildRoot: /tmp/%{name}-root
+
+# Dependencies...
+Requires: %{name}-libs = %{epoch}:%{version}
+Obsoletes: lpd, lpr, LPRng
+Provides: lpd, lpr, LPRng
+Obsoletes: cups-da, cups-de, cups-es, cups-et, cups-fi, cups-fr, cups-he
+Obsoletes: cups-id, cups-it, cups-ja, cups-ko, cups-nl, cups-no, cups-pl
+Obsoletes: cups-pt, cups-ru, cups-sv, cups-zh
+
+%package devel
+Summary: CUPS - development environment
+Group: Development/Libraries
+Requires: %{name}-libs = %{epoch}:%{version}
+
+%package libs
+Summary: CUPS - shared libraries
+Group: System Environment/Libraries
+Provides: libcups1
+
+%package lpd
+Summary: CUPS - LPD support
+Group: System Environment/Daemons
+Requires: %{name} = %{epoch}:%{version} xinetd
+
+%if %{?_with_php:1}%{!?_with_php:0}
+%package php
+Summary: CUPS - PHP support
+Group: Development/Languages
+Requires: %{name}-libs = %{epoch}:%{version}
+%endif
+
+%description
+CUPS is the standards-based, open source printing system developed by
+Apple Inc. for Mac OS¨ X and other UNIX¨-like operating systems.
+
+%description devel
+This package provides the CUPS headers and development environment.
+
+%description libs
+This package provides the CUPS shared libraries.
+
+%description lpd
+This package provides LPD client support.
+
+%if %{?_with_php:1}%{!?_with_php:0}
+%description php
+This package provides PHP support for CUPS.
+%endif
+
+%prep
+%setup
+
+%build
+CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_OPT_FLAGS" \
+ ./configure %{_dbus} %{_php} %{_static}
+# If we got this far, all prerequisite libraries must be here.
+make
+
+%install
+# Make sure the RPM_BUILD_ROOT directory exists.
+rm -rf $RPM_BUILD_ROOT
+
+make BUILDROOT=$RPM_BUILD_ROOT install
+
+%post
+/sbin/chkconfig --add cups
+/sbin/chkconfig cups on
+
+# Restart cupsd if we are upgrading...
+if test $1 -gt 1; then
+ /sbin/service cups stop
+ /sbin/service cups start
+fi
+
+%post libs
+/sbin/ldconfig
+
+%preun
+if test $1 = 0; then
+ /sbin/service cups stop
+ /sbin/chkconfig --del cups
+fi
+
+%postun
+if test $1 -ge 1; then
+ /sbin/service cups stop
+ /sbin/service cups start
+fi
+
+%postun libs
+/sbin/ldconfig
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%docdir /usr/share/doc/cups
+%defattr(-,root,root)
+%dir /etc/cups
+%config(noreplace) /etc/cups/*.conf
+/etc/cups/cupsd.conf.default
+%dir /etc/cups/interfaces
+%dir /etc/cups/ppd
+%attr(0700,root,root) %dir /etc/cups/ssl
+
+%if %{?_with_dbus:1}%{!?_with_dbus:0}
+# DBUS
+/etc/dbus-1/system.d/*
+%endif
+
+# PAM
+%dir /etc/pam.d
+/etc/pam.d/*
+
+# RC dirs are a pain under Linux... Uncomment the appropriate ones if you
+# don't use Red Hat or Mandrake...
+
+/etc/init.d/*
+/etc/rc0.d/*
+/etc/rc2.d/*
+/etc/rc3.d/*
+/etc/rc5.d/*
+
+# OLD RedHat/Mandrake
+#/etc/rc.d/init.d/*
+#/etc/rc.d/rc0.d/*
+#/etc/rc.d/rc2.d/*
+#/etc/rc.d/rc3.d/*
+#/etc/rc.d/rc5.d/*
+
+#/sbin/rc.d/*
+#/sbin/rc.d/rc0.d/*
+#/sbin/rc.d/rc2.d/*
+#/sbin/rc.d/rc3.d/*
+#/sbin/rc.d/rc5.d/*
+
+/usr/bin/cancel
+/usr/bin/cupstestdsc
+/usr/bin/cupstestppd
+/usr/bin/ipptool
+/usr/bin/lp*
+%dir /usr/lib/cups
+%dir /usr/lib/cups/backend
+/usr/lib/cups/backend/http
+%attr(0700,root,root) /usr/lib/cups/backend/ipp
+%attr(0700,root,root) /usr/lib/cups/backend/lpd
+/usr/lib/cups/backend/parallel
+/usr/lib/cups/backend/scsi
+/usr/lib/cups/backend/serial
+/usr/lib/cups/backend/snmp
+/usr/lib/cups/backend/socket
+/usr/lib/cups/backend/usb
+%dir /usr/lib/cups/cgi-bin
+/usr/lib/cups/cgi-bin/*
+%dir /usr/lib/cups/daemon
+/usr/lib/cups/daemon/cups-deviced
+/usr/lib/cups/daemon/cups-driverd
+/usr/lib/cups/daemon/cups-polld
+%dir /usr/lib/cups/driver
+%dir /usr/lib/cups/filter
+/usr/lib/cups/filter/*
+%dir /usr/lib/cups/monitor
+/usr/lib/cups/monitor/*
+%dir /usr/lib/cups/notifier
+/usr/lib/cups/notifier/*
+
+/usr/sbin/*
+%dir /usr/share/cups
+%dir /usr/share/cups/banners
+/usr/share/cups/banners/*
+%dir /usr/share/cups/charsets
+/usr/share/cups/charsets/*
+%dir /usr/share/cups/data
+/usr/share/cups/data/*
+%dir /usr/share/cups/drv
+/usr/share/cups/drv/*
+%dir /usr/share/cups/fonts
+/usr/share/cups/fonts/*
+%dir /usr/share/cups/ipptool
+/usr/share/cups/ipptool/*
+%dir /usr/share/cups/mime
+/usr/share/cups/mime/*
+%dir /usr/share/cups/model
+%dir /usr/share/cups/ppdc
+/usr/share/cups/ppdc/*
+%dir /usr/share/cups/templates
+/usr/share/cups/templates/*
+%dir /usr/share/doc/cups
+/usr/share/doc/cups/*.*
+%dir /usr/share/doc/cups/de
+/usr/share/doc/cups/de/*
+%dir /usr/share/doc/cups/es
+/usr/share/doc/cups/es/*
+%dir /usr/share/doc/cups/eu
+/usr/share/doc/cups/eu/*
+%dir /usr/share/doc/cups/id
+/usr/share/doc/cups/id/*
+%dir /usr/share/doc/cups/it
+/usr/share/doc/cups/it/*
+%dir /usr/share/doc/cups/ja
+/usr/share/doc/cups/ja/*
+%dir /usr/share/doc/cups/pl
+/usr/share/doc/cups/pl/*
+%dir /usr/share/doc/cups/ru
+/usr/share/doc/cups/ru/*
+%dir /usr/share/doc/cups/help
+/usr/share/doc/cups/help/accounting.html
+/usr/share/doc/cups/help/cgi.html
+/usr/share/doc/cups/help/glossary.html
+/usr/share/doc/cups/help/kerberos.html
+/usr/share/doc/cups/help/license.html
+/usr/share/doc/cups/help/man-*.html
+/usr/share/doc/cups/help/network.html
+/usr/share/doc/cups/help/options.html
+/usr/share/doc/cups/help/overview.html
+/usr/share/doc/cups/help/policies.html
+/usr/share/doc/cups/help/ref-*.html
+/usr/share/doc/cups/help/security.html
+/usr/share/doc/cups/help/sharing.html
+/usr/share/doc/cups/help/standard.html
+/usr/share/doc/cups/help/translation.html
+/usr/share/doc/cups/help/whatsnew.html
+%dir /usr/share/doc/cups/images
+/usr/share/doc/cups/images/*
+/usr/share/locale/*
+
+%dir /usr/share/man/man1
+/usr/share/man/man1/cancel.1.gz
+/usr/share/man/man1/cupstestdsc.1.gz
+/usr/share/man/man1/cupstestppd.1.gz
+/usr/share/man/man1/ipptool.1.gz
+/usr/share/man/man1/lp.1.gz
+/usr/share/man/man1/lpoptions.1.gz
+/usr/share/man/man1/lppasswd.1.gz
+/usr/share/man/man1/lpq.1.gz
+/usr/share/man/man1/lpr.1.gz
+/usr/share/man/man1/lprm.1.gz
+/usr/share/man/man1/lpstat.1.gz
+%dir /usr/share/man/man5
+/usr/share/man/man5/*.conf.5.gz
+/usr/share/man/man5/ipptoolfile.5.gz
+/usr/share/man/man5/mime.*.5.gz
+%dir /usr/share/man/man7
+/usr/share/man/man7/drv*
+%dir /usr/share/man/man8
+/usr/share/man/man8/accept.8.gz
+/usr/share/man/man8/cupsaddsmb.8.gz
+/usr/share/man/man8/cupsaccept.8.gz
+/usr/share/man/man8/cupsctl.8.gz
+/usr/share/man/man8/cupsfilter.8.gz
+/usr/share/man/man8/cupsd.8.gz
+/usr/share/man/man8/cupsdisable.8.gz
+/usr/share/man/man8/cupsenable.8.gz
+/usr/share/man/man8/cupsreject.8.gz
+/usr/share/man/man8/cups-deviced.8.gz
+/usr/share/man/man8/cups-driverd.8.gz
+/usr/share/man/man8/cups-polld.8.gz
+/usr/share/man/man8/lpadmin.8.gz
+/usr/share/man/man8/lpc.8.gz
+/usr/share/man/man8/lpinfo.8.gz
+/usr/share/man/man8/lpmove.8.gz
+/usr/share/man/man8/reject.8.gz
+
+%dir /var/cache/cups
+%attr(0775,root,sys) %dir /var/cache/cups/rss
+%dir /var/log/cups
+%dir /var/run/cups
+%attr(0711,lp,sys) %dir /var/run/cups/certs
+%attr(0710,lp,sys) %dir /var/spool/cups
+%attr(1770,lp,sys) %dir /var/spool/cups/tmp
+
+# Desktop files
+/usr/share/applications/*
+/usr/share/icons/*
+
+%files devel
+%defattr(-,root,root)
+%dir /usr/share/cups/examples
+/usr/share/cups/examples/*
+%dir /usr/share/man/man1
+/usr/share/man/man1/cups-config.1.gz
+/usr/share/man/man1/ppd*.1.gz
+%dir /usr/share/man/man5
+/usr/share/man/man5/ppdcfile.5.gz
+/usr/share/man/man7/backend.7.gz
+/usr/share/man/man7/filter.7.gz
+/usr/share/man/man7/notifier.7.gz
+
+/usr/bin/cups-config
+/usr/bin/ppd*
+%dir /usr/include/cups
+/usr/include/cups/*
+/usr/lib*/*.so
+
+%if %{?_with_static:1}%{!?_with_static:0}
+/usr/lib*/*.a
+%endif
+
+%dir /usr/share/doc/cups/help
+/usr/share/doc/cups/help/api*.html
+/usr/share/doc/cups/help/postscript-driver.html
+/usr/share/doc/cups/help/ppd-compiler.html
+/usr/share/doc/cups/help/raster-driver.html
+/usr/share/doc/cups/help/spec*.html
+
+%files libs
+%defattr(-,root,root)
+/usr/lib*/*.so.*
+
+%files lpd
+%defattr(-,root,root)
+/etc/xinetd.d/cups-lpd
+%dir /usr/lib/cups
+%dir /usr/lib/cups/daemon
+/usr/lib/cups/daemon/cups-lpd
+%dir /usr/share/man/man8
+/usr/share/man/man8/cups-lpd.8.gz
+
+%if %{?_with_php:1}%{!?_with_php:0}
+%files php
+# PHP
+/usr/lib*/php*
+%endif
+
+
+#
+# End of "$Id$".
+#
diff --git a/packaging/installer.gif b/packaging/installer.gif
new file mode 100644
index 000000000..3ae6ea77a
--- /dev/null
+++ b/packaging/installer.gif
Binary files differ
diff --git a/packaging/installer.tif b/packaging/installer.tif
new file mode 100644
index 000000000..cc52bc65a
--- /dev/null
+++ b/packaging/installer.tif
Binary files differ
diff --git a/ppdc/Dependencies b/ppdc/Dependencies
new file mode 100644
index 000000000..8d49d5843
--- /dev/null
+++ b/ppdc/Dependencies
@@ -0,0 +1,238 @@
+# DO NOT DELETE
+
+ppdc-array.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-array.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-array.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+ppdc-array.o: ../cups/string-private.h ../config.h ../cups/debug-private.h
+ppdc-array.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+ppdc-array.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+ppdc-array.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+ppdc-array.o: ../cups/language-private.h ../cups/transcode.h
+ppdc-array.o: ../cups/thread-private.h
+ppdc-attr.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-attr.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-attr.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+ppdc-attr.o: ../cups/string-private.h ../config.h ../cups/debug-private.h
+ppdc-attr.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+ppdc-attr.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+ppdc-attr.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+ppdc-attr.o: ../cups/language-private.h ../cups/transcode.h
+ppdc-attr.o: ../cups/thread-private.h
+ppdc-catalog.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-catalog.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-catalog.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+ppdc-catalog.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdc-catalog.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ppdc-catalog.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ppdc-catalog.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ppdc-catalog.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ppdc-catalog.o: ../cups/thread-private.h
+ppdc-choice.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-choice.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-choice.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+ppdc-choice.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdc-choice.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ppdc-choice.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ppdc-choice.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ppdc-choice.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ppdc-choice.o: ../cups/thread-private.h
+ppdc-constraint.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-constraint.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-constraint.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+ppdc-constraint.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdc-constraint.o: ../cups/debug-private.h ../cups/ppd-private.h
+ppdc-constraint.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+ppdc-constraint.o: ../cups/http-private.h ../cups/http.h
+ppdc-constraint.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+ppdc-constraint.o: ../cups/language-private.h ../cups/transcode.h
+ppdc-constraint.o: ../cups/thread-private.h
+ppdc-driver.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-driver.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-driver.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+ppdc-driver.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdc-driver.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ppdc-driver.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ppdc-driver.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ppdc-driver.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ppdc-driver.o: ../cups/thread-private.h
+ppdc-file.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-file.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-file.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+ppdc-file.o: ../cups/string-private.h ../config.h ../cups/debug-private.h
+ppdc-file.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+ppdc-file.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+ppdc-file.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+ppdc-file.o: ../cups/language-private.h ../cups/transcode.h
+ppdc-file.o: ../cups/thread-private.h
+ppdc-filter.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-filter.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-filter.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+ppdc-filter.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdc-filter.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ppdc-filter.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ppdc-filter.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ppdc-filter.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ppdc-filter.o: ../cups/thread-private.h
+ppdc-font.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-font.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-font.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+ppdc-font.o: ../cups/string-private.h ../config.h ../cups/debug-private.h
+ppdc-font.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+ppdc-font.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+ppdc-font.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+ppdc-font.o: ../cups/language-private.h ../cups/transcode.h
+ppdc-font.o: ../cups/thread-private.h
+ppdc-group.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-group.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-group.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+ppdc-group.o: ../cups/string-private.h ../config.h ../cups/debug-private.h
+ppdc-group.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+ppdc-group.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+ppdc-group.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+ppdc-group.o: ../cups/language-private.h ../cups/transcode.h
+ppdc-group.o: ../cups/thread-private.h
+ppdc-import.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-import.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-import.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+ppdc-import.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdc-import.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ppdc-import.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ppdc-import.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ppdc-import.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ppdc-import.o: ../cups/thread-private.h
+ppdc-mediasize.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-mediasize.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-mediasize.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+ppdc-mediasize.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdc-mediasize.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ppdc-mediasize.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ppdc-mediasize.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ppdc-mediasize.o: ../cups/ipp.h ../cups/language-private.h
+ppdc-mediasize.o: ../cups/transcode.h ../cups/thread-private.h
+ppdc-message.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-message.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-message.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+ppdc-message.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdc-message.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ppdc-message.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ppdc-message.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ppdc-message.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ppdc-message.o: ../cups/thread-private.h
+ppdc-option.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-option.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-option.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+ppdc-option.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdc-option.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ppdc-option.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ppdc-option.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ppdc-option.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ppdc-option.o: ../cups/thread-private.h
+ppdc-profile.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-profile.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-profile.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+ppdc-profile.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdc-profile.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ppdc-profile.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ppdc-profile.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ppdc-profile.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ppdc-profile.o: ../cups/thread-private.h
+ppdc-shared.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-shared.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-shared.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+ppdc-shared.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdc-shared.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ppdc-shared.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ppdc-shared.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ppdc-shared.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ppdc-shared.o: ../cups/thread-private.h
+ppdc-source.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-source.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-source.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+ppdc-source.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdc-source.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ppdc-source.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ppdc-source.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ppdc-source.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ppdc-source.o: ../cups/thread-private.h ../cups/raster.h ../cups/ppd.h
+ppdc-source.o: ../data/epson.h ../data/escp.h ../data/hp.h ../data/label.h
+ppdc-source.o: ../data/pcl.h
+ppdc-string.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-string.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-string.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+ppdc-string.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdc-string.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ppdc-string.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ppdc-string.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ppdc-string.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ppdc-string.o: ../cups/thread-private.h
+ppdc-variable.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc-variable.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdc-variable.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+ppdc-variable.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdc-variable.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ppdc-variable.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ppdc-variable.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ppdc-variable.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ppdc-variable.o: ../cups/thread-private.h
+genstrings.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+genstrings.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+genstrings.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+genstrings.o: ../cups/string-private.h ../config.h ../cups/debug-private.h
+genstrings.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+genstrings.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+genstrings.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+genstrings.o: ../cups/language-private.h ../cups/transcode.h
+genstrings.o: ../cups/thread-private.h
+ppdc.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdc.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h ../cups/ipp.h
+ppdc.o: ../cups/http.h ../cups/array.h ../cups/language.h
+ppdc.o: ../cups/string-private.h ../config.h ../cups/debug-private.h
+ppdc.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+ppdc.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+ppdc.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+ppdc.o: ../cups/language-private.h ../cups/transcode.h
+ppdc.o: ../cups/thread-private.h
+ppdhtml.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdhtml.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h ../cups/ipp.h
+ppdhtml.o: ../cups/http.h ../cups/array.h ../cups/language.h
+ppdhtml.o: ../cups/string-private.h ../config.h ../cups/debug-private.h
+ppdhtml.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+ppdhtml.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+ppdhtml.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+ppdhtml.o: ../cups/language-private.h ../cups/transcode.h
+ppdhtml.o: ../cups/thread-private.h
+ppdi.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdi.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h ../cups/ipp.h
+ppdi.o: ../cups/http.h ../cups/array.h ../cups/language.h
+ppdi.o: ../cups/string-private.h ../config.h ../cups/debug-private.h
+ppdi.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+ppdi.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+ppdi.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+ppdi.o: ../cups/language-private.h ../cups/transcode.h
+ppdi.o: ../cups/thread-private.h
+ppdmerge.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ppdmerge.o: ../cups/ipp.h ../cups/http.h ../cups/versioning.h ../cups/array.h
+ppdmerge.o: ../cups/language.h ../cups/string-private.h ../config.h
+ppdmerge.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ppdmerge.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ppdmerge.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ppdmerge.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ppdmerge.o: ../cups/thread-private.h ../cups/ppd-private.h ../cups/array.h
+ppdpo.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+ppdpo.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h ../cups/ipp.h
+ppdpo.o: ../cups/http.h ../cups/array.h ../cups/language.h
+ppdpo.o: ../cups/string-private.h ../config.h ../cups/debug-private.h
+ppdpo.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+ppdpo.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+ppdpo.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+ppdpo.o: ../cups/language-private.h ../cups/transcode.h
+ppdpo.o: ../cups/thread-private.h
+testcatalog.o: ppdc-private.h ppdc.h ../cups/file.h ../cups/versioning.h
+testcatalog.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+testcatalog.o: ../cups/ipp.h ../cups/http.h ../cups/array.h
+testcatalog.o: ../cups/language.h ../cups/string-private.h ../config.h
+testcatalog.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+testcatalog.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+testcatalog.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+testcatalog.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+testcatalog.o: ../cups/thread-private.h
diff --git a/ppdc/Makefile b/ppdc/Makefile
new file mode 100644
index 000000000..ea03fd581
--- /dev/null
+++ b/ppdc/Makefile
@@ -0,0 +1,404 @@
+#
+# "$Id$"
+#
+# Makefile for the CUPS PPD Compiler.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 2002-2006 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+#
+# Include standard definitions...
+#
+
+include ../Makedefs
+
+
+#
+# Object files...
+#
+
+LIBOBJS = \
+ ppdc-array.o \
+ ppdc-attr.o \
+ ppdc-catalog.o \
+ ppdc-choice.o \
+ ppdc-constraint.o \
+ ppdc-driver.o \
+ ppdc-file.o \
+ ppdc-filter.o \
+ ppdc-font.o \
+ ppdc-group.o \
+ ppdc-import.o \
+ ppdc-mediasize.o \
+ ppdc-message.o \
+ ppdc-option.o \
+ ppdc-profile.o \
+ ppdc-shared.o \
+ ppdc-source.o \
+ ppdc-string.o \
+ ppdc-variable.o
+OBJS = \
+ $(LIBOBJS) \
+ genstrings.o \
+ ppdc.o \
+ ppdhtml.o \
+ ppdi.o \
+ ppdmerge.o \
+ ppdpo.o \
+ testcatalog.o
+LIBTARGETS = \
+ $(LIBCUPSPPDC) \
+ libcupsppdc.a
+UNITTARGETS = \
+ ppdc-static \
+ ppdi-static \
+ testcatalog
+EXECTARGETS = \
+ ppdc \
+ ppdhtml \
+ ppdi \
+ ppdmerge \
+ ppdpo
+
+TARGETS = \
+ $(LIBTARGETS) \
+ $(EXECTARGETS) \
+ genstrings
+
+
+#
+# Make everything...
+#
+
+all: $(TARGETS)
+
+
+#
+# Make library targets...
+#
+
+libs: $(LIBTARGETS)
+
+
+#
+# Make unit tests...
+#
+
+unittests: $(UNITTARGETS)
+
+
+#
+# Clean everything...
+#
+
+clean:
+ $(RM) $(OBJS) core
+ $(RM) *.bak *.bck core.*
+ $(RM) $(TARGETS) $(UNITTARGETS)
+ $(RM) -r ppd ppd2
+ $(RM) sample-import.drv sample.c test.drv
+ $(RM) libcupsppdc.so libcupsppdc.sl libcupsppdc.dylib
+
+
+#
+# Update dependencies...
+#
+
+depend:
+ makedepend -Y -I.. -fDependencies $(OBJS:.o=.cxx) >/dev/null 2>&1
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+ $(INSTALL_DIR) $(DATADIR)/drv
+ $(INSTALL_DATA) sample.drv $(DATADIR)/drv
+
+
+#
+# Install programs...
+#
+
+install-exec:
+ echo Installing PPD compiler programs...
+ $(INSTALL_DIR) $(BINDIR)
+ for file in $(EXECTARGETS); do \
+ $(INSTALL_BIN) $$file $(BINDIR); \
+ done
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ for file in $(EXECTARGETS); do \
+ cp $$file $(SYMROOT); \
+ done \
+ fi
+
+
+#
+# Install headers...
+#
+
+install-headers:
+ echo Installing header files in $(INCLUDEDIR)/cups...
+ $(INSTALL_DIR) -m 755 $(INCLUDEDIR)/cups
+ $(INSTALL_DATA) ppdc.h $(INCLUDEDIR)/cups
+
+
+#
+# Install libraries...
+#
+
+install-libs: $(INSTALLSTATIC)
+ echo Installing libraries in $(LIBDIR)...
+ $(INSTALL_DIR) -m 755 $(LIBDIR)
+ $(INSTALL_LIB) $(LIBCUPSPPDC) $(LIBDIR)
+ if test $(LIBCUPSPPDC) = "libcupsppdc.so.1" -o $(LIBCUPSPPDC) = "libcupsppdc.sl.1"; then \
+ $(RM) $(LIBDIR)/`basename $(LIBCUPSPPDC) .1`; \
+ $(LN) $(LIBCUPSPPDC) $(LIBDIR)/`basename $(LIBCUPSPPDC) .1`; \
+ fi
+ if test $(LIBCUPSPPDC) = "libcupsppdc.1.dylib"; then \
+ $(RM) $(LIBDIR)/libcupsppdc.dylib; \
+ $(LN) $(LIBCUPSPPDC) $(LIBDIR)/libcupsppdc.dylib; \
+ fi
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ cp $(LIBCUPSPPDC) $(SYMROOT); \
+ fi
+
+installstatic:
+ $(INSTALL_DIR) -m 755 $(LIBDIR)
+ $(INSTALL_LIB) -m 755 libcupsppdc.a $(LIBDIR)
+ $(RANLIB) $(LIBDIR)/libcupsppdc.a
+ $(CHMOD) 555 $(LIBDIR)/libcupsppdc.a
+
+
+#
+# Uninstall...
+#
+
+uninstall:
+ for file in $(EXECTARGETS); do \
+ $(RM) $(BINDIR)/$$file; \
+ done
+ $(RM) $(DATADIR)/drv/sample.drv
+ $(RMDIR) $(DATADIR)/drv
+ $(RM) $(LIBDIR)/libcupsppdc.1.dylib
+ $(RM) $(LIBDIR)/libcupsppdc.a
+ $(RM) $(LIBDIR)/libcupsppdc.dylib
+ $(RM) $(LIBDIR)/libcupsppdc_s.a
+ $(RM) $(LIBDIR)/libcupsppdc.sl
+ $(RM) $(LIBDIR)/libcupsppdc.sl.1
+ $(RM) $(LIBDIR)/libcupsppdc.so
+ $(RM) $(LIBDIR)/libcupsppdc.so.1
+ -$(RMDIR) $(LIBDIR)
+ $(RM) $(INCLUDEDIR)/cups/ppdc.h
+ -$(RMDIR) $(INCLUDEDIR)/cups
+
+
+#
+# Automatic API help files...
+#
+
+apihelp:
+ mxmldoc --section "Programming" \
+ --title "PPD Compiler API" \
+ --css ../doc/cups-printable.css \
+ --header api-ppdc.header --intro api-ppdc.shtml \
+ api-ppdc.xml \
+ ppdc.h $(LIBOBJS:.o=.cxx) >../doc/help/api-ppdc.html
+ mxmldoc --tokens help/api-ppdc.html api-ppdc.xml >../doc/help/api-ppdc.tokens
+ $(RM) api-ppdc.xml
+
+framedhelp:
+ mxmldoc --framed api-ppdc \
+ --section "Programming" \
+ --title "PPD Compiler API" \
+ --css ../doc/cups-printable.css \
+ --header api-ppdc.header --intro api-ppdc.shtml \
+ ppdc.h $(LIBOBJS:.o=.cxx)
+
+
+#
+# genstrings - generate GNU gettext strings.
+#
+
+genstrings: genstrings.o libcupsppdc.a ../cups/$(LIBCUPSSTATIC) \
+ sample.drv ../data/media.defs
+ echo Linking $@...
+ $(CXX) $(ARCHFLAGS) $(LDFLAGS) -o genstrings genstrings.o \
+ libcupsppdc.a ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) \
+ $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+ echo Generating localization strings...
+ ./genstrings >sample.c
+
+
+#
+# ppdc, the PPD compiler.
+#
+
+ppdc: ppdc.o $(LIBCUPSPPDC) ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CXX) $(LDFLAGS) -o $@ ppdc.o -L. -lcupsppdc $(LIBS)
+
+
+ppdc-static: ppdc.o libcupsppdc.a ../cups/$(LIBCUPSSTATIC) foo.drv foo-fr.po
+ echo Linking $@...
+ $(CXX) $(ARCHFLAGS) $(LDFLAGS) -o ppdc-static ppdc.o libcupsppdc.a \
+ ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ $(COMMONLIBS) $(LIBZ)
+ echo Testing PPD compiler...
+ ./ppdc-static -l en,fr -I ../data foo.drv
+ ./ppdc-static -l en,fr -z -I ../data foo.drv
+
+
+#
+# ppdhtml, the PPD to HTML utility.
+#
+
+ppdhtml: ppdhtml.o $(LIBCUPSPPDC) ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CXX) $(LDFLAGS) -o $@ ppdhtml.o -L. -lcupsppdc $(LIBS)
+
+
+#
+# ppdi, import PPD files.
+#
+
+ppdi: ppdi.o $(LIBCUPSPPDC) ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CXX) $(LDFLAGS) -o $@ ppdi.o -L. -lcupsppdc $(LIBS)
+
+
+ppdi-static: ppdc-static ppdi.o libcupsppdc.a ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CXX) $(ARCHFLAGS) $(LDFLAGS) -o ppdi-static ppdi.o libcupsppdc.a \
+ ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ $(COMMONLIBS) $(LIBZ)
+ echo Testing PPD importer...
+ $(RM) -r ppd ppd2 sample-import.drv
+ ./ppdc-static -I ../data sample.drv
+ ./ppdi-static -I ../data -o sample-import.drv ppd/*
+ ./ppdc-static -I ../data -d ppd2 sample-import.drv
+ if diff -r ppd ppd2 >/dev/null; then \
+ echo PPD import OK; \
+ else \
+ echo PPD import FAILED; \
+ exit 1; \
+ fi
+
+
+#
+# ppdmerge, merge PPD files.
+#
+
+ppdmerge: ppdmerge.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CXX) $(LDFLAGS) -o $@ ppdmerge.o $(LIBS)
+
+
+#
+# ppdpo, create message catalog files.
+#
+
+ppdpo: ppdpo.o $(LIBCUPSPPDC) ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CXX) $(LDFLAGS) -o $@ ppdpo.o -L. -lcupsppdc $(LIBS)
+
+
+#
+# testcatalog, test ppdcCatalog class.
+#
+
+testcatalog: testcatalog.o libcupsppdc.a ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CXX) $(LDFLAGS) -o $@ testcatalog.o libcupsppdc.a \
+ ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
+ $(COMMONLIBS) $(LIBZ)
+
+
+#
+# libcupsppdc.so.1, libcupsppdc.sl.1
+#
+
+libcupsppdc.so.1 libcupsppdc.sl.1: $(LIBOBJS) ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(DSOXX) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS) $(LINKCUPS)
+ $(RM) `basename $@ .1`
+ $(LN) $@ `basename $@ .1`
+
+
+#
+# libcupsppdc.1.dylib
+#
+
+libcupsppdc.1.dylib: $(LIBOBJS) ../cups/$(LIBCUPS)
+ echo Creating export list for $@...
+ nm $(LIBOBJS) | grep "T __" | awk '{print $$3}' | sort >t.exp
+ echo Linking $@...
+ $(DSOXX) $(ARCHFLAGS) $(DSOFLAGS) -o $@ \
+ -install_name $(libdir)/$@ \
+ -current_version 1.0.0 \
+ -compatibility_version 1.0.0 \
+ -exported_symbols_list t.exp \
+ $(LIBOBJS) $(LINKCUPS)
+ $(RM) libcupsppdc.dylib t.exp
+ $(LN) $@ libcupsppdc.dylib
+
+
+#
+# libcupsppdc_s.a
+#
+
+libcupsppdc_s.a: $(LIBOBJS) ../cups/$(LIBCUPS)
+ echo Creating $@...
+ $(DSOXX) $(DSOFLAGS) -o libcupsppdc_s.o $(LIBOBJS) $(LINKCUPS)
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ libcupsppdc_s.o
+
+
+#
+# libcupsppdc.la
+#
+
+libcupsppdc.la: $(LIBOBJS) ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS:.o=.lo) -rpath $(LIBDIR) \
+ -version-info 1:0 $(LINKCUPS)
+
+
+#
+# libcupsppdc.a
+#
+
+libcupsppdc.a: $(LIBOBJS)
+ echo Archiving $@...
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ $(LIBOBJS)
+ $(RANLIB) $@
+
+
+#
+# Include dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id$".
+#
diff --git a/ppdc/api-ppdc.header b/ppdc/api-ppdc.header
new file mode 100644
index 000000000..418686560
--- /dev/null
+++ b/ppdc/api-ppdc.header
@@ -0,0 +1,34 @@
+<!--
+ "$Id: api-array.header 8087 2008-10-27 21:37:05Z mike $"
+
+ PPD Compiler API header for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>PPD Compiler API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/ppdc.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcupsppdc</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/ppdc/api-ppdc.shtml b/ppdc/api-ppdc.shtml
new file mode 100644
index 000000000..e305dcb9d
--- /dev/null
+++ b/ppdc/api-ppdc.shtml
@@ -0,0 +1,18 @@
+<!--
+ "$Id: api-array.shtml 7616 2008-05-28 00:34:13Z mike $"
+
+ PPD Compiler API introduction for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>The PPD Compiler API provides access to CUPS driver information files and
+methods for generating and importing PPD files.</p>
diff --git a/ppdc/foo-fr.po b/ppdc/foo-fr.po
new file mode 100644
index 000000000..1b1561b39
--- /dev/null
+++ b/ppdc/foo-fr.po
@@ -0,0 +1,11 @@
+msgid "A Serious Error"
+msgstr "La Error Serious"
+
+msgid "http://foo.com/serious.html"
+msgstr "http://foo.com/fr/serious.html"
+
+msgid "Foo Letter"
+msgstr "La Foo Letter"
+
+msgid "Foo Photo"
+msgstr "La Foo Photo"
diff --git a/ppdc/foo.drv b/ppdc/foo.drv
new file mode 100644
index 000000000..24a7e04bb
--- /dev/null
+++ b/ppdc/foo.drv
@@ -0,0 +1,547 @@
+//
+// "$Id$"
+//
+// PPD file compiler test data file for CUPS.
+//
+// Copyright 2007-2011 by Apple Inc.
+// Copyright 1997-2003 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+
+/*
+ * C-style comments are supported.
+ */
+
+//
+// C++-style comments are supported.
+//
+
+//
+// Include the common media size definitions...
+//
+// #include directives support both <name> to include a standard file
+// and "name" or just name without the quotes for a local file. Local
+// files resolve relative to the current file's path. Unlike C/C++,
+// #include <name> does not look in multiple directories, and
+// #include "name" does not look in the standard directory.
+//
+
+#include <media.defs>
+
+
+//
+// Include the CUPS raster definitions...
+//
+
+#include <raster.defs>
+
+
+//
+// Include the standard CUPS fonts...
+//
+
+#include <font.defs>
+
+
+//
+// Define variables using the #define directive. In this case we
+// are defining constants for the model number, which is used by
+// our imaginary rastertofoo filter to determine which model-specific
+// features to use/support.
+//
+
+#define MODEL_BW 0
+#define MODEL_COLOR 1
+
+#define MODEL_LASER 0
+#define MODEL_PHOTO 2
+
+
+//
+// Media sizes are defined using the #media directive. The order of
+// values is: size name/text, width, length.
+//
+// "Size name" is an alphanumeric string of up to 40 characters as
+// defined by the Adobe PPD specification.
+//
+// "Size text" is a text string of up to 80 characters as defined by
+// the Adobe PPD specification.
+//
+// "Width" and "length" are the width and length of the media size.
+// Numbers by themselves represent points (72 points = 1 inch). The
+// suffixes "cm", "ft", "in", "m", "mm", and "pt" are recognized to
+// specify centimeters, feet, inches, meters, millimeters, and points,
+// respectively.
+//
+
+#media "FooLetter/Foo Letter" 8in 10in
+#media "FooPhoto/Foo Photo" 200mm 300mm
+
+
+//
+// Message catalogs can be included using #po...
+//
+
+#po fr foo-fr.po
+
+
+//
+// Specify that the drivers use all of the standard base fonts...
+//
+
+Font *
+
+
+//
+// All copyright lines are put at the top of the PPD file in order
+// of their appearance. Copyright text can span multiple lines and
+// will be properly included in the PPD file with comment prefixes
+// on each line.
+//
+// First an MIT-style copyright/license notice...
+//
+
+Copyright "Copyright 2007 by Foo Industries."
+Copyright "
+Permission is granted for redistribution of this file as long as
+this copyright notice is intact and the contents of the file are
+not altered in any way from their original form.
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the \"Software\"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+"
+
+//
+// Then a GPL notice...
+//
+
+Copyright "Copyright 2007 by Foo Industries."
+Copyright "
+This software 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 software 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 software; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+MA 02111 USA
+"
+
+
+//
+// All printer drivers must define the manufacturer, model, PC
+// filename, and version strings; since this test file contains
+// drivers for an imaginary manufacturer "Foo", all of the drivers
+// listed in this file share common manufacturer and version
+// strings.
+//
+
+Manufacturer "Foo"
+Version 1.0
+
+
+//
+// Printer drivers can access driver-specific attributes in a PPD
+// file; these attributes are specified using lines of the form:
+//
+// Attribute name selector value
+//
+// "Name" is the name of the attribute and should start with either
+// the "cups" prefix or the name of the vendor, e.g. "hpFoo",
+// "epsonBar", etc. The name can be any alphanumeric character (a-z,
+// A-Z, and 0-9) and cannot be a common prefix of another attribute,
+// e.g. "fooLines" and "fooLinesPerInch" cannot be in the same file.
+//
+// "Selector" is a selector string containing any characters except
+// colon (:). Typically this will be one or more keywords separated
+// by the forward slash (/), however the empty string ("") can be used
+// to omit the selector.
+//
+// "Value" is a quoted value string that can contain any printable
+// characters except the double quote ("). Hexadecimal numbers
+// inside angle brackets (<xx>) can be used to substitute escape
+// codes and other special characters.
+//
+
+Attribute fooOutputFormat "" "PCL"
+Attribute fooPJL Begin "<1B>%-12345X@PJL<0D0A>"
+Attribute fooPJL Enter/PCL "@PJL ENTER LANGUAGE=PCL<0D0A>"
+Attribute fooPJL End "<1B>%-12345X@PJL END JOB<0D0A>"
+
+//
+// Most printer drivers use filters; exceptions include PostScript
+// printers and PPD files for software RIPs.
+//
+// The format is:
+//
+// Filter mime-type cost program
+//
+// The "mime-type" field defines the MIME type that the filter program
+// accepts; for CUPS raster printer drivers, this will be
+// "application/vnd.cups-raster".
+//
+// The "cost" field defines the relative cost of the filter in terms of
+// both CPU and memory usage, and is used to limit the number of
+// simultaneous jobs in some configurations. Most raster filters should
+// have a cost of 100, unless the filter does no dithering - then a cost
+// of 33 is more appropriate.
+//
+// The "program" field defined the filter program to run; use the null
+// filter "-" to define a MIME type that the printer accepts directly.
+// If no path information is provided, then the program will be run
+// from the standard CUPS filter directory, usually
+// /usr/lib/cups/filter.
+//
+// When compiling PPD files for PostScript capable devices that use
+// additional filters, add a null filter for the MIME type
+// "application/vnd.cups-postscript" so that printer commands, user
+// job filters, and page markings can be added to the PostScript
+// output that is sent to the printer.
+//
+
+Filter application/vnd.cups-raster 100 rastertofoo
+
+
+//
+// Attributes are included thusly...
+//
+
+Attribute cupsIPPReason "com.foo-serious-error/A Serious Error" "http://foo.com/serious.html"
+
+
+//
+// Curley braces are used for grouping common data and for isolating
+// individual printer models. All data values are inherited *except*
+// for the PCFilename and ModelName strings.
+//
+
+{
+ //
+ // Define two printer drivers that support only the FooLetter and
+ // FooPhoto media size. One is color, the other is black-and-white.
+ //
+ // Both printers share two MediaSize definitions; the name listed
+ // after the MediaSize keyword must be one of the Adobe standard
+ // names listed in the PPD specification or any named size defined
+ // using the #media directive.
+ //
+ // Default options are indicated by placing an asterisk (*) before
+ // the keyword.
+ //
+ // For custom size and margin specification, see the next group of
+ // printer drivers.
+ //
+
+ MediaSize FooLetter
+ *MediaSize FooPhoto
+
+
+ //
+ // These imaginary printers support printing at 300, 600x300,
+ // and 600 DPI. We'll use the old-style Resolution convenience
+ // keyword which accepts the following parameters: colorspace/
+ // order, bits-per-color, row count, row feed, row step, and
+ // name/text.
+ //
+ // The name must be of the form NNNsuffix or NNNxMMMsuffix,
+ // where NNN and MMM represent the X and Y resolution in dots
+ // per inch.
+ //
+
+ Resolution - 8 0 0 0 "300dpi/300 DPI"
+ Resolution - 8 0 0 0 "600x300dpi/600 x 300 DPI"
+ *Resolution - 8 0 0 0 "600dpi/600 DPI"
+
+
+ //
+ // One printer is grayscale only, and the other does grayscale
+ // and color. Define the grayscale color model for both printers
+ // using the old-style ColorModel convenience keyword which
+ // accepts the name/text, colorspace, color order, and compression
+ // parameters.
+ //
+
+ ColorModel Gray/Grayscale w chunked 0
+
+
+ {
+ //
+ // The first sub-group contains the grayscale printer, which
+ // only needs the model name, PC filename, and model number
+ // values set...
+ //
+ // The ModelName keyword defines the string that is shown to
+ // the user.
+ //
+
+ ModelName "Mono Photo Printer"
+
+
+ //
+ // The ModelNumber keyword defines the cupsModelNumber
+ // attribute value. We use the "(name name)" notation
+ // to perform a bitwise OR of the #define'd constants.
+ //
+
+ ModelNumber ($MODEL_BW $MODEL_PHOTO)
+
+
+ //
+ // The PCFileName keyword defines the filename of the PPD
+ // file and should be 8 characters or less + the .ppd
+ // extension.
+ //
+
+ PCFileName "foogphot.ppd"
+ }
+
+
+ {
+ //
+ // The second sub-group contains the color printer, which
+ // needs another ColorModel definition along with the model
+ // name, PC filename, and model number values. For fun, we'll
+ // add some input slots (paper trays) as well.
+ //
+ // The ModelName keyword defines the string that is shown to
+ // the user.
+ //
+
+ ModelName "Color Photo Printer"
+
+
+ //
+ // The ModelNumber keyword defines the cupsModelNumber
+ // attribute value. We use the "(name name)" notation
+ // to perform a bitwise OR of the #define'd constants.
+ //
+
+ ModelNumber ($MODEL_COLOR $MODEL_PHOTO)
+
+
+ //
+ // The PCFileName keyword defines the filename of the PPD
+ // file and should be 8 characters or less + the .ppd
+ // extension.
+ //
+
+ PCFileName "foocphot.ppd"
+
+
+ //
+ // This printer does color printing, too, so add it and make
+ // RGB the default...
+ //
+
+ ColorDevice Yes
+
+ *ColorModel RGB/Color rgb chunked 0
+
+
+ //
+ // The old-style InputSlot keyword accepts tray definitions
+ // of the form:
+ //
+ // InputSlot position name/text
+ //
+
+ InputSlot 0 "Upper/Main Paper Tray"
+ InputSlot 1 "LargeCapacity/Large Paper Tray"
+ }
+}
+
+
+{
+ //
+ // Define two printer drivers that support two typical laser
+ // printers with custom page sizes. One is color, the other is
+ // black-and-white.
+ //
+ // Both printers share several MediaSize definitions and support
+ // custom page sizes from 3x5 to 13x19 inches.
+ //
+ // All US media sizes use hardware margins of 0.25 inches on the sides
+ // and 12 points (1/6th inch) at the top and bottom. European sizes
+ // and custom sizes use margins of 12 points all around.
+ //
+ // The order of the HWMargins numbers are left, bottom, right, and top.
+ // The current HWMargins values are used when defining each media size.
+ // The last HWMargins values are used for custom page size margins.
+ //
+
+ HWMargins 0.25in 12pt 0.25in 12pt
+
+ *MediaSize Letter
+ MediaSize Legal
+ MediaSize Tabloid
+ MediaSize TabloidExtra
+
+ HWMargins 12pt 12pt 12pt 12pt
+ MediaSize A4
+ MediaSize A3
+
+ //
+ // Specify that custom/variable paper sizes are supported, and the
+ // range of sizes that are supported...
+ //
+
+ VariablePaperSize Yes
+ MinSize 3in 5in
+ MaxSize 13in 19in
+
+
+ //
+ // These imaginary printers support printing at 600 and 1200 DPI.
+ // We'll use the new Option and Choice keywords to define the
+ // Resolution options...
+ //
+ // Option option-name option-text option-type
+ // Choice choice-name choice-text code
+ //
+ // "Option-type" is the type of option: boolean, pickone, or pickmany.
+ //
+
+ Option Resolution PickOne AnySetup 10
+ Choice "600dpi/600 DPI" "<</HWResolution[600 600]/cupsBitsPerColor 8>>setpagedevice"
+ Choice "1200dpi/1200 DPI" "<</HWResolution[1200 1200]/cupsBitsPerColor 8>>setpagedevice"
+
+
+ //
+ // One printer is grayscale only, and the other does grayscale
+ // and color. Define the grayscale color model for both printers
+ // using the new Option and Choice keywords.
+ //
+
+ Option "ColorModel/Color Mode" PickOne AnySetup 10
+ Choice Gray/Grayscale "<</cupsColorSpace $CUPS_CSPACE_W>>setpagedevice"
+
+
+ //
+ // Both printers provide two paper trays, which we'll define using
+ // the new Option and Choice keywords...
+ //
+
+ Option "InputSlot/Input Slot" PickOne AnySetup 10
+ Choice "Upper/Main Paper Tray" "<</MediaPosition 0>>setpagedevice"
+ Choice "LargeCapacity/Large Paper Tray" "<</MediaPosition 1>>setpagedevice"
+
+
+ //
+ // Both printers support duplexing...
+ //
+ // The Duplex keyword accepts values of "none" (no duplexing capability),
+ // "normal" (standard duplexing capability), and "flip" (auto-duplex that
+ // requires the back side to be flipped by the RIP...)
+ //
+
+ Duplex normal
+
+
+ {
+ //
+ // The first sub-group contains the grayscale printer, which
+ // only needs the model name, PC filename, and model number
+ // values set...
+ //
+ // The ModelName keyword defines the string that is shown to
+ // the user.
+ //
+
+ ModelName "Mono Laser Printer"
+
+
+ //
+ // The ModelNumber keyword defines the cupsModelNumber
+ // attribute value. We use the "(name name)" notation
+ // to perform a bitwise OR of the #define'd constants.
+ //
+
+ ModelNumber ($MODEL_BW $MODEL_LASER)
+
+
+ //
+ // The PCFileName keyword defines the filename of the PPD
+ // file and should be 8 characters or less + the .ppd
+ // extension.
+ //
+
+ PCFileName "fooglasr.ppd"
+ }
+
+
+ {
+ //
+ // The second sub-group contains the color printer, which
+ // needs another ColorModel definition along with the model
+ // name, PC filename, and model number values.
+ //
+ // The ModelName keyword defines the string that is shown to
+ // the user.
+ //
+
+ ModelName "Color Laser Printer"
+
+
+ //
+ // The ModelNumber keyword defines the cupsModelNumber
+ // attribute value. We use the "(name name)" notation
+ // to perform a bitwise OR of the #define'd constants.
+ //
+
+ ModelNumber ($MODEL_COLOR $MODEL_LASER)
+
+
+ //
+ // The PCFileName keyword defines the filename of the PPD
+ // file and should be 8 characters or less + the .ppd
+ // extension.
+ //
+
+ PCFileName "fooclasr.ppd"
+
+
+ //
+ // This printer does color printing, too, so add it and make
+ // RGB the default...
+ //
+
+ ColorDevice Yes
+
+ Option "ColorModel/Color Mode" PickOne AnySetup 10
+ *Choice RGB/Color "<</cupsColorSpace $CUPS_CSPACE_RGB>>setpagedevice"
+ }
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/genstrings.cxx b/ppdc/genstrings.cxx
new file mode 100644
index 000000000..d08416d32
--- /dev/null
+++ b/ppdc/genstrings.cxx
@@ -0,0 +1,215 @@
+//
+// "$Id$"
+//
+// GNU gettext message generator for the CUPS PPD Compiler.
+//
+// This program is used to generate a dummy source file containing all of
+// the standard media and sample driver strings. The results are picked up
+// by GNU gettext and placed in the CUPS message catalog.
+//
+// Copyright 2008-2011 by Apple Inc.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Usage:
+//
+// ./genstrings >sample.c
+//
+// Contents:
+//
+// main() - Main entry for the PPD compiler.
+// add_ui_strings() - Add all UI strings from the driver.
+// write_cstring() - Write a translation string as a valid C string to
+// stdout.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+#include <unistd.h>
+
+
+//
+// Local functions...
+//
+
+static void add_ui_strings(ppdcDriver *d, ppdcCatalog *catalog);
+static void write_cstring(const char *s);
+
+
+//
+// 'main()' - Main entry for the PPD compiler.
+//
+
+int // O - Exit status
+main(void)
+{
+ ppdcSource *src; // PPD source file data
+ ppdcCatalog *catalog; // Catalog to hold all of the UI strings
+
+
+ // Make sure we are in the right place...
+ if (access("../data", 0) || access("sample.drv", 0))
+ {
+ puts("You must run genstrings from the ppdc directory.");
+ return (1);
+ }
+
+ // Load the sample drivers...
+ ppdcSource::add_include("../data");
+
+ src = new ppdcSource("sample.drv");
+ catalog = new ppdcCatalog(NULL);
+
+ catalog->add_message("ISOLatin1");
+ catalog->add_message("English");
+
+ // Add the media size strings...
+ ppdcMediaSize *size; // Current media size
+
+ for (size = (ppdcMediaSize *)src->sizes->first();
+ size;
+ size = (ppdcMediaSize *)src->sizes->next())
+ catalog->add_message(size->text->value);
+
+ // Then collect all of the UI strings from the sample drivers...
+ ppdcDriver *d; // Current driver
+
+ for (d = (ppdcDriver *)src->drivers->first();
+ d;
+ d = (ppdcDriver *)src->drivers->next())
+ add_ui_strings(d, catalog);
+
+ // Finally, write all of the strings...
+ ppdcMessage *message;
+
+ for (message = (ppdcMessage *)catalog->messages->first();
+ message;
+ message = (ppdcMessage *)catalog->messages->next())
+ write_cstring(message->id->value);
+
+ src->release();
+ catalog->release();
+
+ // Return with no errors.
+ return (0);
+}
+
+
+//
+// 'add_ui_strings()' - Add all UI strings from the driver.
+//
+
+static void
+add_ui_strings(ppdcDriver *d, // I - Driver data
+ ppdcCatalog *catalog) // I - Message catalog
+{
+ // Add the make/model/language strings...
+ catalog->add_message(d->manufacturer->value);
+ catalog->add_message(d->model_name->value);
+
+ // Add the group/option/choice strings...
+ ppdcGroup *g; // Current group
+ ppdcOption *o; // Current option
+ ppdcChoice *c; // Current choice
+
+ for (g = (ppdcGroup *)d->groups->first();
+ g;
+ g = (ppdcGroup *)d->groups->next())
+ {
+ if (!g->options->count)
+ continue;
+
+ if (_cups_strcasecmp(g->name->value, "General"))
+ catalog->add_message(g->text->value);
+
+ for (o = (ppdcOption *)g->options->first();
+ o;
+ o = (ppdcOption *)g->options->next())
+ {
+ if (!o->choices->count)
+ continue;
+
+ if (o->text->value && strcmp(o->name->value, o->text->value))
+ catalog->add_message(o->text->value);
+ else
+ catalog->add_message(o->name->value);
+
+ for (c = (ppdcChoice *)o->choices->first();
+ c;
+ c = (ppdcChoice *)o->choices->next())
+ if (c->text->value && strcmp(c->name->value, c->text->value))
+ catalog->add_message(c->text->value);
+ else
+ catalog->add_message(c->name->value);
+ }
+ }
+
+ // Add profile and preset strings...
+ ppdcAttr *a; // Current attribute
+ for (a = (ppdcAttr *)d->attrs->first();
+ a;
+ a = (ppdcAttr *)d->attrs->next())
+ {
+ if (a->text->value && a->text->value[0] &&
+ (a->localizable ||
+ !strncmp(a->name->value, "Custom", 6) ||
+ !strncmp(a->name->value, "ParamCustom", 11) ||
+ !strcmp(a->name->value, "APCustomColorMatchingName") ||
+ !strcmp(a->name->value, "APPrinterPreset") ||
+ !strcmp(a->name->value, "cupsICCProfile") ||
+ !strcmp(a->name->value, "cupsIPPReason") ||
+ !strcmp(a->name->value, "cupsMarkerName")))
+ {
+ catalog->add_message(a->text->value);
+
+ if ((a->localizable && a->value->value[0]) ||
+ !strcmp(a->name->value, "cupsIPPReason"))
+ catalog->add_message(a->value->value);
+ }
+ else if (!strncmp(a->name->value, "Custom", 6) ||
+ !strncmp(a->name->value, "ParamCustom", 11))
+ catalog->add_message(a->name->value);
+ }
+}
+
+
+//
+// 'write_cstring()' - Write a translation string as a valid C string to stdout.
+//
+
+static void
+write_cstring(const char *s) /* I - String to write */
+{
+ fputs("_(\"", stdout);
+ if (s)
+ {
+ while (*s)
+ {
+ if (*s == '\\')
+ fputs("\\\\", stdout);
+ else if (*s == '\"')
+ fputs("\\\"", stdout);
+ else if (*s == '\t')
+ fputs("\\t", stdout);
+ else if (*s == '\n')
+ fputs("\\n", stdout);
+ else
+ putchar(*s);
+
+ s ++;
+ }
+ }
+ puts("\");");
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-array.cxx b/ppdc/ppdc-array.cxx
new file mode 100644
index 000000000..33d8bf773
--- /dev/null
+++ b/ppdc/ppdc-array.cxx
@@ -0,0 +1,168 @@
+//
+// "$Id$"
+//
+// Array class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2009 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcArray::ppdcArray() - Create a new array.
+// ppdcArray::~ppdcArray() - Destroy an array.
+// ppdcArray::add() - Add an element to an array.
+// ppdcArray::first() - Return the first element in the array.
+// ppdcArray::next() - Return the next element in the array.
+// ppdcArray::remove() - Remove an element from the array.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcArray::ppdcArray()' - Create a new array.
+//
+
+ppdcArray::ppdcArray(ppdcArray *a)
+ : ppdcShared()
+{
+ PPDC_NEW;
+
+ if (a)
+ {
+ count = a->count;
+ alloc = count;
+
+ if (count)
+ {
+ // Make a copy of the array...
+ data = new ppdcShared *[count];
+
+ memcpy(data, a->data, count * sizeof(ppdcShared *));
+
+ for (int i = 0; i < count; i ++)
+ data[i]->retain();
+ }
+ else
+ data = 0;
+ }
+ else
+ {
+ count = 0;
+ alloc = 0;
+ data = 0;
+ }
+
+ current = 0;
+}
+
+
+//
+// 'ppdcArray::~ppdcArray()' - Destroy an array.
+//
+
+ppdcArray::~ppdcArray()
+{
+ PPDC_DELETE;
+
+ for (int i = 0; i < count; i ++)
+ data[i]->release();
+
+ if (alloc)
+ delete[] data;
+}
+
+
+//
+// 'ppdcArray::add()' - Add an element to an array.
+//
+
+void
+ppdcArray::add(ppdcShared *d)
+{
+ ppdcShared **temp;
+
+
+ if (count >= alloc)
+ {
+ alloc += 10;
+ temp = new ppdcShared *[alloc];
+
+ memcpy(temp, data, count * sizeof(ppdcShared *));
+
+ delete[] data;
+ data = temp;
+ }
+
+ data[count++] = d;
+}
+
+
+//
+// 'ppdcArray::first()' - Return the first element in the array.
+//
+
+ppdcShared *
+ppdcArray::first()
+{
+ current = 0;
+
+ if (current >= count)
+ return (0);
+ else
+ return (data[current ++]);
+}
+
+
+//
+// 'ppdcArray::next()' - Return the next element in the array.
+//
+
+ppdcShared *
+ppdcArray::next()
+{
+ if (current >= count)
+ return (0);
+ else
+ return (data[current ++]);
+}
+
+
+//
+// 'ppdcArray::remove()' - Remove an element from the array.
+//
+
+void
+ppdcArray::remove(ppdcShared *d) // I - Data element
+{
+ int i; // Looping var
+
+
+ for (i = 0; i < count; i ++)
+ if (d == data[i])
+ break;
+
+ if (i >= count)
+ return;
+
+ count --;
+ d->release();
+
+ if (i < count)
+ memmove(data + i, data + i + 1, (count - i) * sizeof(ppdcShared *));
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-attr.cxx b/ppdc/ppdc-attr.cxx
new file mode 100644
index 000000000..1ea0337a9
--- /dev/null
+++ b/ppdc/ppdc-attr.cxx
@@ -0,0 +1,66 @@
+//
+// "$Id$"
+//
+// Attribute class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2009 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcAttr::ppdcAttr() - Create an attribute.
+// ppdcAttr::~ppdcAttr() - Destroy an attribute.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcAttr::ppdcAttr()' - Create an attribute.
+//
+
+ppdcAttr::ppdcAttr(const char *n, // I - Name
+ const char *s, // I - Spec string
+ const char *t, // I - Human-readable text
+ const char *v, // I - Value
+ bool loc) // I - Localize this attribute?
+ : ppdcShared()
+{
+ PPDC_NEW;
+
+ name = new ppdcString(n);
+ selector = new ppdcString(s);
+ text = new ppdcString(t);
+ value = new ppdcString(v);
+ localizable = loc;
+}
+
+
+//
+// 'ppdcAttr::~ppdcAttr()' - Destroy an attribute.
+//
+
+ppdcAttr::~ppdcAttr()
+{
+ PPDC_DELETE;
+
+ name->release();
+ selector->release();
+ text->release();
+ value->release();
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-catalog.cxx b/ppdc/ppdc-catalog.cxx
new file mode 100644
index 000000000..acf178b29
--- /dev/null
+++ b/ppdc/ppdc-catalog.cxx
@@ -0,0 +1,897 @@
+//
+// "$Id$"
+//
+// Shared message catalog class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2010 by Apple Inc.
+// Copyright 2002-2006 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcCatalog::ppdcCatalog() - Create a shared message catalog.
+// ppdcCatalog::~ppdcCatalog() - Destroy a shared message catalog.
+// ppdcCatalog::add_message() - Add a new message.
+// ppdcCatalog::find_message() - Find a message in a catalog...
+// ppdcCatalog::load_messages() - Load messages from a .po file.
+// ppdcCatalog::save_messages() - Save the messages to a .po file.
+// get_utf8() - Get a UTF-8 character.
+// get_utf16() - Get a UTF-16 character...
+// put_utf8() - Add a UTF-8 character to a string.
+// put_utf16() - Write a UTF-16 character to a file.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// Character encodings...
+//
+
+typedef enum
+{
+ PPDC_CS_AUTO,
+ PPDC_CS_UTF8,
+ PPDC_CS_UTF16BE,
+ PPDC_CS_UTF16LE
+} ppdc_cs_t;
+
+
+//
+// Local functions...
+//
+
+static int get_utf8(char *&ptr);
+static int get_utf16(cups_file_t *fp, ppdc_cs_t &cs);
+static int put_utf8(int ch, char *&ptr, char *end);
+static int put_utf16(cups_file_t *fp, int ch);
+
+
+//
+// 'ppdcCatalog::ppdcCatalog()' - Create a shared message catalog.
+//
+
+ppdcCatalog::ppdcCatalog(const char *l, // I - Locale
+ const char *f) // I - Message catalog file
+ : ppdcShared()
+{
+ _cups_globals_t *cg = _cupsGlobals();
+ // Global information
+
+
+ PPDC_NEW;
+
+ locale = new ppdcString(l);
+ filename = new ppdcString(f);
+ messages = new ppdcArray();
+
+ if (l)
+ {
+ // Try loading the base messages for this locale...
+ char pofile[1024]; // Message catalog file
+
+
+ snprintf(pofile, sizeof(pofile), "%s/%s/cups_%s.po", cg->localedir, l, l);
+
+ if (load_messages(pofile) && strchr(l, '_'))
+ {
+ // Try the base locale...
+ char baseloc[3]; // Base locale...
+
+
+ strlcpy(baseloc, l, sizeof(baseloc));
+ snprintf(pofile, sizeof(pofile), "%s/%s/cups_%s.po", cg->localedir,
+ baseloc, baseloc);
+
+ load_messages(pofile);
+ }
+ }
+
+ if (f)
+ load_messages(f);
+}
+
+
+//
+// 'ppdcCatalog::~ppdcCatalog()' - Destroy a shared message catalog.
+//
+
+ppdcCatalog::~ppdcCatalog()
+{
+ PPDC_DELETE;
+
+ locale->release();
+ filename->release();
+ messages->release();
+}
+
+
+//
+// 'ppdcCatalog::add_message()' - Add a new message.
+//
+
+void
+ppdcCatalog::add_message(
+ const char *id, // I - Message ID to add
+ const char *string) // I - Translation string
+{
+ ppdcMessage *m; // Current message
+ char text[1024]; // Text to translate
+
+
+ // Range check input...
+ if (!id)
+ return;
+
+ // Verify that we don't already have the message ID...
+ for (m = (ppdcMessage *)messages->first();
+ m;
+ m = (ppdcMessage *)messages->next())
+ if (!strcmp(m->id->value, id))
+ {
+ if (string)
+ {
+ m->string->release();
+ m->string = new ppdcString(string);
+ }
+ return;
+ }
+
+ // Add the message...
+ if (!string)
+ {
+ snprintf(text, sizeof(text), "TRANSLATE %s", id);
+ string = text;
+ }
+
+ messages->add(new ppdcMessage(id, string));
+}
+
+
+//
+// 'ppdcCatalog::find_message()' - Find a message in a catalog...
+//
+
+const char * // O - Message text
+ppdcCatalog::find_message(
+ const char *id) // I - Message ID
+{
+ ppdcMessage *m; // Current message
+
+
+ if (!*id)
+ return (id);
+
+ for (m = (ppdcMessage *)messages->first();
+ m;
+ m = (ppdcMessage *)messages->next())
+ if (!strcmp(m->id->value, id))
+ return (m->string->value);
+
+ return (id);
+}
+
+
+//
+// 'ppdcCatalog::load_messages()' - Load messages from a .po file.
+//
+
+int // O - 0 on success, -1 on failure
+ppdcCatalog::load_messages(
+ const char *f) // I - Message catalog file
+{
+ cups_file_t *fp; // Message file
+ char line[4096], // Line buffer
+ *ptr, // Pointer into buffer
+ id[4096], // Translation ID
+ str[4096]; // Translation string
+ int linenum; // Line number
+
+
+ // Open the message catalog file...
+ if ((fp = cupsFileOpen(f, "r")) == NULL)
+ return (-1);
+
+ if ((ptr = (char *)strrchr(f, '.')) == NULL)
+ goto unknown_load_format;
+ else if (!strcmp(ptr, ".strings"))
+ {
+ /*
+ * Read messages in Mac OS X ".strings" format, which are UTF-16 text
+ * files of the format:
+ *
+ * "id" = "str";
+ *
+ * Strings files can also contain C-style comments.
+ */
+
+ ppdc_cs_t cs = PPDC_CS_AUTO; // Character set for file
+ int ch; // Current character from file
+ char *end; // End of buffer
+
+
+ id[0] = '\0';
+ str[0] = '\0';
+ ptr = NULL;
+ end = NULL;
+
+ while ((ch = get_utf16(fp, cs)) != 0)
+ {
+ if (ptr)
+ {
+ if (ch == '\\')
+ {
+ if ((ch = get_utf16(fp, cs)) == 0)
+ break;
+
+ if (ch == 'n')
+ ch = '\n';
+ else if (ch == 't')
+ ch = '\t';
+ }
+ else if (ch == '\"')
+ {
+ *ptr = '\0';
+ ptr = NULL;
+ }
+
+ if (ptr)
+ put_utf8(ch, ptr, end);
+ }
+ else if (ch == '/')
+ {
+ // Start of a comment?
+ if ((ch = get_utf16(fp, cs)) == 0)
+ break;
+
+ if (ch == '*')
+ {
+ // Skip C comment...
+ int lastch = 0;
+
+ while ((ch = get_utf16(fp, cs)) != 0)
+ {
+ if (ch == '/' && lastch == '*')
+ break;
+
+ lastch = ch;
+ }
+ }
+ else if (ch == '/')
+ {
+ // Skip C++ comment...
+ while ((ch = get_utf16(fp, cs)) != 0)
+ if (ch == '\n')
+ break;
+ }
+ }
+ else if (ch == '\"')
+ {
+ // Start quoted string...
+ if (id[0])
+ {
+ ptr = str;
+ end = str + sizeof(str) - 1;
+ }
+ else
+ {
+ ptr = id;
+ end = id + sizeof(id) - 1;
+ }
+ }
+ else if (ch == ';')
+ {
+ // Add string...
+ add_message(id, str);
+ id[0] = '\0';
+ }
+ }
+ }
+ else if (!strcmp(ptr, ".po") || !strcmp(ptr, ".gz"))
+ {
+ /*
+ * Read messages from the catalog file until EOF...
+ *
+ * The format is the GNU gettext .po format, which is fairly simple:
+ *
+ * msgid "some text"
+ * msgstr "localized text"
+ *
+ * The ID and localized text can span multiple lines using the form:
+ *
+ * msgid ""
+ * "some long text"
+ * msgstr ""
+ * "localized text spanning "
+ * "multiple lines"
+ */
+
+ int which, // In msgid?
+ haveid, // Did we get a msgid string?
+ havestr; // Did we get a msgstr string?
+
+ linenum = 0;
+ id[0] = '\0';
+ str[0] = '\0';
+ haveid = 0;
+ havestr = 0;
+ which = 0;
+
+ while (cupsFileGets(fp, line, sizeof(line)))
+ {
+ linenum ++;
+
+ // Skip blank and comment lines...
+ if (line[0] == '#' || !line[0])
+ continue;
+
+ // Strip the trailing quote...
+ if ((ptr = (char *)strrchr(line, '\"')) == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected quoted string on line %d of %s."),
+ linenum, f);
+ cupsFileClose(fp);
+ return (-1);
+ }
+
+ *ptr = '\0';
+
+ // Find start of value...
+ if ((ptr = strchr(line, '\"')) == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected quoted string on line %d of %s."),
+ linenum, f);
+ cupsFileClose(fp);
+ return (-1);
+ }
+
+ ptr ++;
+
+ // Unquote the text...
+ char *sptr, *dptr; // Source/destination pointers
+
+ for (sptr = ptr, dptr = ptr; *sptr;)
+ {
+ if (*sptr == '\\')
+ {
+ sptr ++;
+ if (isdigit(*sptr))
+ {
+ *dptr = 0;
+
+ while (isdigit(*sptr))
+ {
+ *dptr = *dptr * 8 + *sptr - '0';
+ sptr ++;
+ }
+
+ dptr ++;
+ }
+ else
+ {
+ if (*sptr == 'n')
+ *dptr++ = '\n';
+ else if (*sptr == 'r')
+ *dptr++ = '\r';
+ else if (*sptr == 't')
+ *dptr++ = '\t';
+ else
+ *dptr++ = *sptr;
+
+ sptr ++;
+ }
+ }
+ else
+ *dptr++ = *sptr++;
+ }
+
+ *dptr = '\0';
+
+ // Create or add to a message...
+ if (!strncmp(line, "msgid", 5))
+ {
+ if (haveid && havestr)
+ add_message(id, str);
+
+ strlcpy(id, ptr, sizeof(id));
+ str[0] = '\0';
+ haveid = 1;
+ havestr = 0;
+ which = 1;
+ }
+ else if (!strncmp(line, "msgstr", 6))
+ {
+ if (!haveid)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Need a msgid line before any "
+ "translation strings on line %d of %s."),
+ linenum, f);
+ cupsFileClose(fp);
+ return (-1);
+ }
+
+ strlcpy(str, ptr, sizeof(str));
+ havestr = 1;
+ which = 2;
+ }
+ else if (line[0] == '\"' && which == 2)
+ strlcat(str, ptr, sizeof(str));
+ else if (line[0] == '\"' && which == 1)
+ strlcat(id, ptr, sizeof(id));
+ else
+ {
+ _cupsLangPrintf(stderr, _("ppdc: Unexpected text on line %d of %s."),
+ linenum, f);
+ cupsFileClose(fp);
+ return (-1);
+ }
+ }
+
+ if (haveid && havestr)
+ add_message(id, str);
+ }
+ else
+ goto unknown_load_format;
+
+ /*
+ * Close the file and return...
+ */
+
+ cupsFileClose(fp);
+
+ return (0);
+
+ /*
+ * Unknown format error...
+ */
+
+ unknown_load_format:
+
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unknown message catalog format for \"%s\"."), f);
+ cupsFileClose(fp);
+ return (-1);
+}
+
+
+//
+// 'ppdcCatalog::save_messages()' - Save the messages to a .po file.
+//
+
+int // O - 0 on success, -1 on error
+ppdcCatalog::save_messages(
+ const char *f) // I - File to save to
+{
+ cups_file_t *fp; // Message file
+ ppdcMessage *m; // Current message
+ char *ptr; // Pointer into string
+ int utf16; // Output UTF-16 .strings file?
+ int ch; // Current character
+
+
+ // Open the file...
+ if ((ptr = (char *)strrchr(f, '.')) == NULL)
+ return (-1);
+
+ if (!strcmp(ptr, ".gz"))
+ fp = cupsFileOpen(f, "w9");
+ else
+ fp = cupsFileOpen(f, "w");
+
+ if (!fp)
+ return (-1);
+
+ // For .strings files, write a BOM for big-endian output...
+ utf16 = !strcmp(ptr, ".strings");
+
+ if (utf16)
+ put_utf16(fp, 0xfeff);
+
+ // Loop through all of the messages...
+ for (m = (ppdcMessage *)messages->first();
+ m;
+ m = (ppdcMessage *)messages->next())
+ {
+ if (utf16)
+ {
+ put_utf16(fp, '\"');
+
+ ptr = m->id->value;
+ while ((ch = get_utf8(ptr)) != 0)
+ switch (ch)
+ {
+ case '\n' :
+ put_utf16(fp, '\\');
+ put_utf16(fp, 'n');
+ break;
+ case '\\' :
+ put_utf16(fp, '\\');
+ put_utf16(fp, '\\');
+ break;
+ case '\"' :
+ put_utf16(fp, '\\');
+ put_utf16(fp, '\"');
+ break;
+ default :
+ put_utf16(fp, ch);
+ break;
+ }
+
+ put_utf16(fp, '\"');
+ put_utf16(fp, ' ');
+ put_utf16(fp, '=');
+ put_utf16(fp, ' ');
+ put_utf16(fp, '\"');
+
+ ptr = m->string->value;
+ while ((ch = get_utf8(ptr)) != 0)
+ switch (ch)
+ {
+ case '\n' :
+ put_utf16(fp, '\\');
+ put_utf16(fp, 'n');
+ break;
+ case '\\' :
+ put_utf16(fp, '\\');
+ put_utf16(fp, '\\');
+ break;
+ case '\"' :
+ put_utf16(fp, '\\');
+ put_utf16(fp, '\"');
+ break;
+ default :
+ put_utf16(fp, ch);
+ break;
+ }
+
+ put_utf16(fp, '\"');
+ put_utf16(fp, ';');
+ put_utf16(fp, '\n');
+ }
+ else
+ {
+ cupsFilePuts(fp, "msgid \"");
+ for (ptr = m->id->value; *ptr; ptr ++)
+ switch (*ptr)
+ {
+ case '\n' :
+ cupsFilePuts(fp, "\\n");
+ break;
+ case '\\' :
+ cupsFilePuts(fp, "\\\\");
+ break;
+ case '\"' :
+ cupsFilePuts(fp, "\\\"");
+ break;
+ default :
+ cupsFilePutChar(fp, *ptr);
+ break;
+ }
+ cupsFilePuts(fp, "\"\n");
+
+ cupsFilePuts(fp, "msgstr \"");
+ for (ptr = m->string->value; *ptr; ptr ++)
+ switch (*ptr)
+ {
+ case '\n' :
+ cupsFilePuts(fp, "\\n");
+ break;
+ case '\\' :
+ cupsFilePuts(fp, "\\\\");
+ break;
+ case '\"' :
+ cupsFilePuts(fp, "\\\"");
+ break;
+ default :
+ cupsFilePutChar(fp, *ptr);
+ break;
+ }
+ cupsFilePuts(fp, "\"\n");
+
+ cupsFilePutChar(fp, '\n');
+ }
+ }
+
+ cupsFileClose(fp);
+
+ return (0);
+}
+
+
+//
+// 'get_utf8()' - Get a UTF-8 character.
+//
+
+static int // O - Unicode character or 0 on EOF
+get_utf8(char *&ptr) // IO - Pointer to character
+{
+ int ch; // Current character
+
+
+ if ((ch = *ptr++ & 255) < 0xc0)
+ return (ch);
+
+ if ((ch & 0xe0) == 0xc0)
+ {
+ // Two-byte UTF-8...
+ if ((*ptr & 0xc0) != 0x80)
+ return (0);
+
+ ch = ((ch & 0x1f) << 6) | (*ptr++ & 0x3f);
+ }
+ else if ((ch & 0xf0) == 0xe0)
+ {
+ // Three-byte UTF-8...
+ if ((*ptr & 0xc0) != 0x80)
+ return (0);
+
+ ch = ((ch & 0x0f) << 6) | (*ptr++ & 0x3f);
+
+ if ((*ptr & 0xc0) != 0x80)
+ return (0);
+
+ ch = (ch << 6) | (*ptr++ & 0x3f);
+ }
+ else if ((ch & 0xf8) == 0xf0)
+ {
+ // Four-byte UTF-8...
+ if ((*ptr & 0xc0) != 0x80)
+ return (0);
+
+ ch = ((ch & 0x07) << 6) | (*ptr++ & 0x3f);
+
+ if ((*ptr & 0xc0) != 0x80)
+ return (0);
+
+ ch = (ch << 6) | (*ptr++ & 0x3f);
+
+ if ((*ptr & 0xc0) != 0x80)
+ return (0);
+
+ ch = (ch << 6) | (*ptr++ & 0x3f);
+ }
+
+ return (ch);
+}
+
+
+//
+// 'get_utf16()' - Get a UTF-16 character...
+//
+
+static int // O - Unicode character or 0 on EOF
+get_utf16(cups_file_t *fp, // I - File to read from
+ ppdc_cs_t &cs) // IO - Character set of file
+{
+ int ch; // Current character
+ unsigned char buffer[3]; // Bytes
+
+
+ if (cs == PPDC_CS_AUTO)
+ {
+ // Get byte-order-mark, if present...
+ if (cupsFileRead(fp, (char *)buffer, 2) != 2)
+ return (0);
+
+ if (buffer[0] == 0xfe && buffer[1] == 0xff)
+ {
+ // Big-endian UTF-16...
+ cs = PPDC_CS_UTF16BE;
+
+ if (cupsFileRead(fp, (char *)buffer, 2) != 2)
+ return (0);
+ }
+ else if (buffer[0] == 0xff && buffer[1] == 0xfe)
+ {
+ // Little-endian UTF-16...
+ cs = PPDC_CS_UTF16LE;
+
+ if (cupsFileRead(fp, (char *)buffer, 2) != 2)
+ return (0);
+ }
+ else if (buffer[0] == 0x00 && buffer[1] != 0x00)
+ {
+ // No BOM, assume big-endian UTF-16...
+ cs = PPDC_CS_UTF16BE;
+ }
+ else if (buffer[0] != 0x00 && buffer[1] == 0x00)
+ {
+ // No BOM, assume little-endian UTF-16...
+ cs = PPDC_CS_UTF16LE;
+ }
+ else
+ {
+ // No BOM, assume UTF-8...
+ cs = PPDC_CS_UTF8;
+
+ cupsFileRewind(fp);
+ }
+ }
+ else if (cs != PPDC_CS_UTF8)
+ {
+ if (cupsFileRead(fp, (char *)buffer, 2) != 2)
+ return (0);
+ }
+
+ if (cs == PPDC_CS_UTF8)
+ {
+ // UTF-8 character...
+ if ((ch = cupsFileGetChar(fp)) < 0)
+ return (0);
+
+ if ((ch & 0xe0) == 0xc0)
+ {
+ // Two-byte UTF-8...
+ if (cupsFileRead(fp, (char *)buffer, 1) != 1)
+ return (0);
+
+ if ((buffer[0] & 0xc0) != 0x80)
+ return (0);
+
+ ch = ((ch & 0x1f) << 6) | (buffer[0] & 0x3f);
+ }
+ else if ((ch & 0xf0) == 0xe0)
+ {
+ // Three-byte UTF-8...
+ if (cupsFileRead(fp, (char *)buffer, 2) != 2)
+ return (0);
+
+ if ((buffer[0] & 0xc0) != 0x80 ||
+ (buffer[1] & 0xc0) != 0x80)
+ return (0);
+
+ ch = ((((ch & 0x0f) << 6) | (buffer[0] & 0x3f)) << 6) |
+ (buffer[1] & 0x3f);
+ }
+ else if ((ch & 0xf8) == 0xf0)
+ {
+ // Four-byte UTF-8...
+ if (cupsFileRead(fp, (char *)buffer, 3) != 3)
+ return (0);
+
+ if ((buffer[0] & 0xc0) != 0x80 ||
+ (buffer[1] & 0xc0) != 0x80 ||
+ (buffer[2] & 0xc0) != 0x80)
+ return (0);
+
+ ch = ((((((ch & 0x07) << 6) | (buffer[0] & 0x3f)) << 6) |
+ (buffer[1] & 0x3f)) << 6) | (buffer[2] & 0x3f);
+ }
+ }
+ else
+ {
+ // UTF-16 character...
+ if (cs == PPDC_CS_UTF16BE)
+ ch = (buffer[0] << 8) | buffer[1];
+ else
+ ch = (buffer[1] << 8) | buffer[0];
+
+ if (ch >= 0xd800 && ch <= 0xdbff)
+ {
+ // Handle multi-word encoding...
+ int lch;
+
+ if (cupsFileRead(fp, (char *)buffer, 2) != 2)
+ return (0);
+
+ if (cs == PPDC_CS_UTF16BE)
+ lch = (buffer[0] << 8) | buffer[1];
+ else
+ lch = (buffer[1] << 8) | buffer[0];
+
+ if (lch < 0xdc00 || lch >= 0xdfff)
+ return (0);
+
+ ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
+ }
+ }
+
+ return (ch);
+}
+
+
+//
+// 'put_utf8()' - Add a UTF-8 character to a string.
+//
+
+static int // O - 0 on success, -1 on failure
+put_utf8(int ch, // I - Unicode character
+ char *&ptr, // IO - String pointer
+ char *end) // I - End of buffer
+{
+ if (ch < 0x80)
+ {
+ // One-byte ASCII...
+ if (ptr >= end)
+ return (-1);
+
+ *ptr++ = ch;
+ }
+ else if (ch < 0x800)
+ {
+ // Two-byte UTF-8...
+ if ((ptr + 1) >= end)
+ return (-1);
+
+ *ptr++ = 0xc0 | (ch >> 6);
+ *ptr++ = 0x80 | (ch & 0x3f);
+ }
+ else if (ch < 0x10000)
+ {
+ // Three-byte UTF-8...
+ if ((ptr + 2) >= end)
+ return (-1);
+
+ *ptr++ = 0xe0 | (ch >> 12);
+ *ptr++ = 0x80 | ((ch >> 6) & 0x3f);
+ *ptr++ = 0x80 | (ch & 0x3f);
+ }
+ else
+ {
+ // Four-byte UTF-8...
+ if ((ptr + 3) >= end)
+ return (-1);
+
+ *ptr++ = 0xf0 | (ch >> 18);
+ *ptr++ = 0x80 | ((ch >> 12) & 0x3f);
+ *ptr++ = 0x80 | ((ch >> 6) & 0x3f);
+ *ptr++ = 0x80 | (ch & 0x3f);
+ }
+
+ return (0);
+}
+
+
+//
+// 'put_utf16()' - Write a UTF-16 character to a file.
+//
+
+static int // O - 0 on success, -1 on failure
+put_utf16(cups_file_t *fp, // I - File to write to
+ int ch) // I - Unicode character
+{
+ unsigned char buffer[4]; // Output buffer
+
+
+ if (ch < 0x10000)
+ {
+ // One-word UTF-16 big-endian...
+ buffer[0] = ch >> 8;
+ buffer[1] = ch;
+
+ if (cupsFileWrite(fp, (char *)buffer, 2) == 2)
+ return (0);
+ }
+ else
+ {
+ // Two-word UTF-16 big-endian...
+ ch -= 0x10000;
+
+ buffer[0] = 0xd8 | (ch >> 18);
+ buffer[1] = ch >> 10;
+ buffer[2] = 0xdc | ((ch >> 8) & 0x03);
+ buffer[3] = ch;
+
+ if (cupsFileWrite(fp, (char *)buffer, 4) == 4)
+ return (0);
+ }
+
+ return (-1);
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-choice.cxx b/ppdc/ppdc-choice.cxx
new file mode 100644
index 000000000..2c12de2b9
--- /dev/null
+++ b/ppdc/ppdc-choice.cxx
@@ -0,0 +1,61 @@
+//
+// "$Id$"
+//
+// Option choice class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2009 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcChoice::ppdcChoice() - Create a new option choice.
+// ppdcChoice::~ppdcChoice() - Destroy an option choice.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcChoice::ppdcChoice()' - Create a new option choice.
+//
+
+ppdcChoice::ppdcChoice(const char *n, // I - Name of choice
+ const char *t, // I - Text of choice
+ const char *c) // I - Code of choice
+ : ppdcShared()
+{
+ PPDC_NEW;
+
+ name = new ppdcString(n);
+ text = new ppdcString(t);
+ code = new ppdcString(c);
+}
+
+
+//
+// 'ppdcChoice::~ppdcChoice()' - Destroy an option choice.
+//
+
+ppdcChoice::~ppdcChoice()
+{
+ PPDC_DELETE;
+
+ name->release();
+ text->release();
+ code->release();
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-constraint.cxx b/ppdc/ppdc-constraint.cxx
new file mode 100644
index 000000000..6e6f0241e
--- /dev/null
+++ b/ppdc/ppdc-constraint.cxx
@@ -0,0 +1,64 @@
+//
+// "$Id$"
+//
+// Contraint class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2009 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcConstraint::ppdcConstraint() - Create a constraint.
+// ppdcConstraint::~ppdcConstraint() - Destroy a constraint.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcConstraint::ppdcConstraint()' - Create a constraint.
+//
+
+ppdcConstraint::ppdcConstraint(const char *o1, // I - First option
+ const char *c1, // I - First choice
+ const char *o2, // I - Second option
+ const char *c2) // I - Second choice
+ : ppdcShared()
+{
+ PPDC_NEW;
+
+ option1 = new ppdcString(o1);
+ choice1 = new ppdcString(c1);
+ option2 = new ppdcString(o2);
+ choice2 = new ppdcString(c2);
+}
+
+
+//
+// 'ppdcConstraint::~ppdcConstraint()' - Destroy a constraint.
+//
+
+ppdcConstraint::~ppdcConstraint()
+{
+ PPDC_DELETE;
+
+ option1->release();
+ choice1->release();
+ option2->release();
+ choice2->release();
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-driver.cxx b/ppdc/ppdc-driver.cxx
new file mode 100644
index 000000000..c9a7a1c96
--- /dev/null
+++ b/ppdc/ppdc-driver.cxx
@@ -0,0 +1,1339 @@
+//
+// "$Id$"
+//
+// PPD file compiler definitions for the CUPS PPD Compiler.
+//
+// Copyright 2007-2011 by Apple Inc.
+// Copyright 2002-2006 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcDriver::ppdcDriver() - Create a new printer driver.
+// ppdcDriver::~ppdcDriver() - Destroy a printer driver.
+// ppdcDriver::find_attr() - Find an attribute.
+// ppdcDriver::find_group() - Find a group.
+// ppdcDriver::find_option() - Find an option.
+// ppdcDriver::find_option_group() - Find an option and its group.
+// ppdcDriver::set_custom_size_code() - Set the custom page size code.
+// ppdcDriver::set_default_font() - Set the default font name.
+// ppdcDriver::set_default_size() - Set the default size name.
+// ppdcDriver::set_file_name() - Set the full filename.
+// ppdcDriver::set_manufacturer() - Set the manufacturer name.
+// ppdcDriver::set_model_name() - Set the model name.
+// ppdcDriver::set_pc_file_name() - Set the PC filename.
+// ppdcDriver::set_version() - Set the version string.
+// ppdcDriver::write_ppd_file() - Write a PPD file...
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcDriver::ppdcDriver()' - Create a new printer driver.
+//
+
+ppdcDriver::ppdcDriver(ppdcDriver *d) // I - Printer driver template
+ : ppdcShared()
+{
+ ppdcGroup *g; // Current group
+
+
+ PPDC_NEW;
+
+ if (d)
+ {
+ // Bump the use count of any strings we inherit...
+ if (d->manufacturer)
+ d->manufacturer->retain();
+ if (d->version)
+ d->version->retain();
+ if (d->default_font)
+ d->default_font->retain();
+ if (d->default_size)
+ d->default_size->retain();
+ if (d->custom_size_code)
+ d->custom_size_code->retain();
+
+ // Copy all of the data from the driver template...
+ copyright = new ppdcArray(d->copyright);
+ manufacturer = d->manufacturer;
+ model_name = 0;
+ file_name = 0;
+ pc_file_name = 0;
+ type = d->type;
+ version = d->version;
+ model_number = d->model_number;
+ manual_copies = d->manual_copies;
+ color_device = d->color_device;
+ throughput = d->throughput;
+ attrs = new ppdcArray(d->attrs);
+ constraints = new ppdcArray(d->constraints);
+ filters = new ppdcArray(d->filters);
+ fonts = new ppdcArray(d->fonts);
+ profiles = new ppdcArray(d->profiles);
+ sizes = new ppdcArray(d->sizes);
+ default_font = d->default_font;
+ default_size = d->default_size;
+ variable_paper_size = d->variable_paper_size;
+ custom_size_code = d->custom_size_code;
+ left_margin = d->left_margin;
+ bottom_margin = d->bottom_margin;
+ right_margin = d->right_margin;
+ top_margin = d->top_margin;
+ max_width = d->max_width;
+ max_length = d->max_length;
+ min_width = d->min_width;
+ min_length = d->min_length;
+
+ // Then copy the groups manually, since we want separate copies
+ // of the groups and options...
+ groups = new ppdcArray();
+
+ for (g = (ppdcGroup *)d->groups->first(); g; g = (ppdcGroup *)d->groups->next())
+ groups->add(new ppdcGroup(g));
+ }
+ else
+ {
+ // Zero all of the data in the driver...
+ copyright = new ppdcArray();
+ manufacturer = 0;
+ model_name = 0;
+ file_name = 0;
+ pc_file_name = 0;
+ version = 0;
+ type = PPDC_DRIVER_CUSTOM;
+ model_number = 0;
+ manual_copies = 0;
+ color_device = 0;
+ throughput = 1;
+ attrs = new ppdcArray();
+ constraints = new ppdcArray();
+ fonts = new ppdcArray();
+ filters = new ppdcArray();
+ groups = new ppdcArray();
+ profiles = new ppdcArray();
+ sizes = new ppdcArray();
+ default_font = 0;
+ default_size = 0;
+ variable_paper_size = 0;
+ custom_size_code = 0;
+ left_margin = 0;
+ bottom_margin = 0;
+ right_margin = 0;
+ top_margin = 0;
+ max_width = 0;
+ max_length = 0;
+ min_width = 0;
+ min_length = 0;
+ }
+}
+
+
+//
+// 'ppdcDriver::~ppdcDriver()' - Destroy a printer driver.
+//
+
+ppdcDriver::~ppdcDriver()
+{
+ PPDC_DELETE;
+
+ copyright->release();
+
+ if (manufacturer)
+ manufacturer->release();
+ if (model_name)
+ model_name->release();
+ if (file_name)
+ file_name->release();
+ if (pc_file_name)
+ pc_file_name->release();
+ if (version)
+ version->release();
+ if (default_font)
+ default_font->release();
+ if (default_size)
+ default_size->release();
+ if (custom_size_code)
+ custom_size_code->release();
+
+ attrs->release();
+ constraints->release();
+ filters->release();
+ fonts->release();
+ groups->release();
+ profiles->release();
+ sizes->release();
+}
+
+
+//
+// 'ppdcDriver::find_attr()' - Find an attribute.
+//
+
+ppdcAttr * // O - Attribute or NULL
+ppdcDriver::find_attr(const char *k, // I - Keyword string
+ const char *s) // I - Spec string
+{
+ ppdcAttr *a; // Current attribute
+
+
+ for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
+ if (!strcmp(a->name->value, k) &&
+ ((!s && (!a->selector->value || !a->selector->value[0])) ||
+ (s && a->selector->value && !strcmp(a->selector->value, s))))
+ return (a);
+
+ return (NULL);
+}
+
+
+//
+// 'ppdcDriver::find_group()' - Find a group.
+//
+
+ppdcGroup * // O - Matching group or NULL
+ppdcDriver::find_group(const char *n) // I - Group name
+{
+ ppdcGroup *g; // Current group
+
+
+ for (g = (ppdcGroup *)groups->first(); g; g = (ppdcGroup *)groups->next())
+ if (!_cups_strcasecmp(n, g->name->value))
+ return (g);
+
+ return (0);
+}
+
+
+//
+// 'ppdcDriver::find_option()' - Find an option.
+//
+
+ppdcOption * // O - Matching option or NULL
+ppdcDriver::find_option(const char *n) // I - Option name
+{
+ return (find_option_group(n, (ppdcGroup **)0));
+}
+
+
+//
+// 'ppdcDriver::find_option_group()' - Find an option and its group.
+//
+
+ppdcOption * // O - Matching option or NULL
+ppdcDriver::find_option_group(
+ const char *n, // I - Option name
+ ppdcGroup **mg) // O - Matching group or NULL
+{
+ ppdcGroup *g; // Current group
+ ppdcOption *o; // Current option
+
+
+ for (g = (ppdcGroup *)groups->first(); g; g = (ppdcGroup *)groups->next())
+ for (o = (ppdcOption *)g->options->first(); o; o = (ppdcOption *)g->options->next())
+ if (!_cups_strcasecmp(n, o->name->value))
+ {
+ if (mg)
+ *mg = g;
+
+ return (o);
+ }
+
+ if (mg)
+ *mg = (ppdcGroup *)0;
+
+ return (0);
+}
+
+
+//
+// 'ppdcDriver::set_custom_size_code()' - Set the custom page size code.
+//
+
+void
+ppdcDriver::set_custom_size_code(
+ const char *c) // I - CustomPageSize code
+{
+ if (custom_size_code)
+ custom_size_code->release();
+
+ custom_size_code = new ppdcString(c);
+}
+
+
+//
+// 'ppdcDriver::set_default_font()' - Set the default font name.
+//
+
+void
+ppdcDriver::set_default_font(
+ ppdcFont *f) // I - Font
+{
+ if (default_font)
+ default_font->release();
+
+ if (f)
+ {
+ f->name->retain();
+ default_font = f->name;
+ }
+ else
+ default_font = 0;
+}
+
+
+//
+// 'ppdcDriver::set_default_size()' - Set the default size name.
+//
+
+void
+ppdcDriver::set_default_size(
+ ppdcMediaSize *m) // I - Media size
+{
+ if (default_size)
+ default_size->release();
+
+ if (m)
+ {
+ m->name->retain();
+ default_size = m->name;
+ }
+ else
+ default_size = 0;
+}
+
+
+//
+// 'ppdcDriver::set_file_name()' - Set the full filename.
+//
+
+void
+ppdcDriver::set_file_name(const char *f)// I - Filename
+{
+ if (file_name)
+ file_name->release();
+
+ file_name = new ppdcString(f);
+}
+
+
+//
+// 'ppdcDriver::set_manufacturer()' - Set the manufacturer name.
+//
+
+void
+ppdcDriver::set_manufacturer(
+ const char *m) // I - Model name
+{
+ if (manufacturer)
+ manufacturer->release();
+
+ manufacturer = new ppdcString(m);
+}
+
+
+//
+// 'ppdcDriver::set_model_name()' - Set the model name.
+//
+
+void
+ppdcDriver::set_model_name(
+ const char *m) // I - Model name
+{
+ if (model_name)
+ model_name->release();
+
+ model_name = new ppdcString(m);
+}
+
+
+//
+// 'ppdcDriver::set_pc_file_name()' - Set the PC filename.
+//
+
+void
+ppdcDriver::set_pc_file_name(
+ const char *f) // I - Filename
+{
+ if (pc_file_name)
+ pc_file_name->release();
+
+ pc_file_name = new ppdcString(f);
+}
+
+
+//
+// 'ppdcDriver::set_version()' - Set the version string.
+//
+
+void
+ppdcDriver::set_version(const char *v) // I - Version
+{
+ if (version)
+ version->release();
+
+ version = new ppdcString(v);
+}
+
+
+//
+// 'ppdcDriver::write_ppd_file()' - Write a PPD file...
+//
+
+int // O - 0 on success, -1 on failure
+ppdcDriver::write_ppd_file(
+ cups_file_t *fp, // I - PPD file
+ ppdcCatalog *catalog, // I - Message catalog
+ ppdcArray *locales, // I - Additional languages to add
+ ppdcSource *src, // I - Driver source
+ ppdcLineEnding le) // I - Line endings to use
+{
+ bool delete_cat; // Delete the catalog when we are done?
+ char query[42], // Query attribute
+ custom[42]; // Custom attribute
+ ppdcString *s; // Copyright string
+ ppdcGroup *g; // Current group
+ ppdcOption *o; // Current option
+ ppdcChoice *c; // Current choice
+ ppdcMediaSize *m; // Current media size
+ ppdcProfile *p; // Current color profile
+ ppdcFilter *f; // Current filter
+ ppdcFont *fn, // Current font
+ *bfn; // Current base font
+ ppdcConstraint *cn; // Current constraint
+ ppdcAttr *a; // Current attribute
+ const char *lf; // Linefeed character to use
+
+
+ // If we don't have a message catalog, use an empty (English) one...
+ if (!catalog)
+ {
+ catalog = new ppdcCatalog("en");
+ delete_cat = true;
+ }
+ else
+ delete_cat = false;
+
+ // Figure out the end-of-line string...
+ if (le == PPDC_LFONLY)
+ lf = "\n";
+ else if (le == PPDC_CRONLY)
+ lf = "\r";
+ else
+ lf = "\r\n";
+
+ // Write the standard header stuff...
+ cupsFilePrintf(fp, "*PPD-Adobe: \"4.3\"%s", lf);
+ cupsFilePrintf(fp, "*%%%%%%%% PPD file for %s with CUPS.%s",
+ model_name->value, lf);
+ cupsFilePrintf(fp,
+ "*%%%%%%%% Created by the CUPS PPD Compiler " CUPS_SVERSION
+ ".%s", lf);
+ for (s = (ppdcString *)copyright->first();
+ s;
+ s = (ppdcString *)copyright->next())
+ cupsFilePrintf(fp, "*%% %s%s", catalog->find_message(s->value), lf);
+ cupsFilePrintf(fp, "*FormatVersion: \"4.3\"%s", lf);
+ cupsFilePrintf(fp, "*FileVersion: \"%s\"%s", version->value, lf);
+
+ a = find_attr("LanguageVersion", NULL);
+ cupsFilePrintf(fp, "*LanguageVersion: %s%s",
+ catalog->find_message(a ? a->value->value : "English"), lf);
+
+ a = find_attr("LanguageEncoding", NULL);
+ cupsFilePrintf(fp, "*LanguageEncoding: %s%s",
+ catalog->find_message(a ? a->value->value : "ISOLatin1"), lf);
+
+ cupsFilePrintf(fp, "*PCFileName: \"%s\"%s", pc_file_name->value, lf);
+
+ for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
+ if (!strcmp(a->name->value, "Product"))
+ break;
+
+ if (a)
+ {
+ for (; a; a = (ppdcAttr *)attrs->next())
+ if (!strcmp(a->name->value, "Product"))
+ cupsFilePrintf(fp, "*Product: \"%s\"%s", a->value->value, lf);
+ }
+ else
+ cupsFilePrintf(fp, "*Product: \"(%s)\"%s", model_name->value, lf);
+
+ cupsFilePrintf(fp, "*Manufacturer: \"%s\"%s",
+ catalog->find_message(manufacturer->value), lf);
+
+ if ((a = find_attr("ModelName", NULL)) != NULL)
+ cupsFilePrintf(fp, "*ModelName: \"%s\"%s",
+ catalog->find_message(a->value->value), lf);
+ else if (_cups_strncasecmp(model_name->value, manufacturer->value,
+ strlen(manufacturer->value)))
+ cupsFilePrintf(fp, "*ModelName: \"%s %s\"%s",
+ catalog->find_message(manufacturer->value),
+ catalog->find_message(model_name->value), lf);
+ else
+ cupsFilePrintf(fp, "*ModelName: \"%s\"%s",
+ catalog->find_message(model_name->value), lf);
+
+ if ((a = find_attr("ShortNickName", NULL)) != NULL)
+ cupsFilePrintf(fp, "*ShortNickName: \"%s\"%s",
+ catalog->find_message(a->value->value), lf);
+ else if (_cups_strncasecmp(model_name->value, manufacturer->value,
+ strlen(manufacturer->value)))
+ cupsFilePrintf(fp, "*ShortNickName: \"%s %s\"%s",
+ catalog->find_message(manufacturer->value),
+ catalog->find_message(model_name->value), lf);
+ else
+ cupsFilePrintf(fp, "*ShortNickName: \"%s\"%s",
+ catalog->find_message(model_name->value), lf);
+
+ if ((a = find_attr("NickName", NULL)) != NULL)
+ cupsFilePrintf(fp, "*NickName: \"%s\"%s",
+ catalog->find_message(a->value->value), lf);
+ else if (_cups_strncasecmp(model_name->value, manufacturer->value,
+ strlen(manufacturer->value)))
+ cupsFilePrintf(fp, "*NickName: \"%s %s, %s\"%s",
+ catalog->find_message(manufacturer->value),
+ catalog->find_message(model_name->value), version->value,
+ lf);
+ else
+ cupsFilePrintf(fp, "*NickName: \"%s, %s\"%s",
+ catalog->find_message(model_name->value), version->value,
+ lf);
+
+ for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
+ if (!strcmp(a->name->value, "PSVersion"))
+ break;
+
+ if (a)
+ {
+ for (; a; a = (ppdcAttr *)attrs->next())
+ if (!strcmp(a->name->value, "PSVersion"))
+ cupsFilePrintf(fp, "*PSVersion: \"%s\"%s", a->value->value, lf);
+ }
+ else
+ cupsFilePrintf(fp, "*PSVersion: \"(3010.000) 0\"%s", lf);
+
+ if ((a = find_attr("LanguageLevel", NULL)) != NULL)
+ cupsFilePrintf(fp, "*LanguageLevel: \"%s\"%s", a->value->value, lf);
+ else
+ cupsFilePrintf(fp, "*LanguageLevel: \"3\"%s", lf);
+
+ cupsFilePrintf(fp, "*ColorDevice: %s%s", color_device ? "True" : "False", lf);
+
+ if ((a = find_attr("DefaultColorSpace", NULL)) != NULL)
+ cupsFilePrintf(fp, "*DefaultColorSpace: %s%s", a->value->value, lf);
+ else
+ cupsFilePrintf(fp, "*DefaultColorSpace: %s%s",
+ color_device ? "RGB" : "Gray", lf);
+
+ if ((a = find_attr("FileSystem", NULL)) != NULL)
+ cupsFilePrintf(fp, "*FileSystem: %s%s", a->value->value, lf);
+ else
+ cupsFilePrintf(fp, "*FileSystem: False%s", lf);
+
+ cupsFilePrintf(fp, "*Throughput: \"%d\"%s", throughput, lf);
+
+ if ((a = find_attr("LandscapeOrientation", NULL)) != NULL)
+ cupsFilePrintf(fp, "*LandscapeOrientation: %s%s", a->value->value, lf);
+ else
+ cupsFilePrintf(fp, "*LandscapeOrientation: Plus90%s", lf);
+
+ if ((a = find_attr("TTRasterizer", NULL)) != NULL)
+ cupsFilePrintf(fp, "*TTRasterizer: %s%s", a->value->value, lf);
+ else if (type != PPDC_DRIVER_PS)
+ cupsFilePrintf(fp, "*TTRasterizer: Type42%s", lf);
+
+ struct lconv *loc = localeconv();
+
+ if (attrs->count)
+ {
+ // Write driver-defined attributes...
+ cupsFilePrintf(fp, "*%% Driver-defined attributes...%s", lf);
+ for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
+ {
+ if (!strcmp(a->name->value, "Product") ||
+ !strcmp(a->name->value, "PSVersion") ||
+ !strcmp(a->name->value, "LanguageLevel") ||
+ !strcmp(a->name->value, "DefaultColorSpace") ||
+ !strcmp(a->name->value, "FileSystem") ||
+ !strcmp(a->name->value, "LandscapeOrientation") ||
+ !strcmp(a->name->value, "TTRasterizer") ||
+ !strcmp(a->name->value, "LanguageVersion") ||
+ !strcmp(a->name->value, "LanguageEncoding") ||
+ !strcmp(a->name->value, "ModelName") ||
+ !strcmp(a->name->value, "NickName") ||
+ !strcmp(a->name->value, "ShortNickName") ||
+ !strcmp(a->name->value, "cupsVersion"))
+ continue;
+
+ if (a->name->value[0] == '?' &&
+ (find_option(a->name->value + 1) ||
+ !strcmp(a->name->value, "?ImageableArea") ||
+ !strcmp(a->name->value, "?PageRegion") ||
+ !strcmp(a->name->value, "?PageSize") ||
+ !strcmp(a->name->value, "?PaperDimension")))
+ continue;
+
+ if (!strncmp(a->name->value, "Custom", 6) &&
+ find_option(a->name->value + 6))
+ continue;
+
+ if (!strncmp(a->name->value, "ParamCustom", 11) &&
+ find_option(a->name->value + 11))
+ continue;
+
+ if (!a->selector->value || !a->selector->value[0])
+ cupsFilePrintf(fp, "*%s", a->name->value);
+ else if (!a->text->value || !a->text->value[0])
+ cupsFilePrintf(fp, "*%s %s", a->name->value, a->selector->value);
+ else
+ cupsFilePrintf(fp, "*%s %s/%s", a->name->value, a->selector->value,
+ a->text->value);
+
+ if (strcmp(a->value->value, "False") &&
+ strcmp(a->value->value, "True") &&
+ strcmp(a->name->value, "1284Modes") &&
+ strcmp(a->name->value, "InkName") &&
+ strcmp(a->name->value, "PageStackOrder") &&
+ strncmp(a->name->value, "ParamCustom", 11) &&
+ strcmp(a->name->value, "Protocols") &&
+ strcmp(a->name->value, "ReferencePunch") &&
+ strncmp(a->name->value, "Default", 7))
+ {
+ cupsFilePrintf(fp, ": \"%s\"%s", a->value->value, lf);
+
+ if (strchr(a->value->value, '\n') || strchr(a->value->value, '\r'))
+ cupsFilePrintf(fp, "*End%s", lf);
+ }
+ else
+ cupsFilePrintf(fp, ": %s%s", a->value->value, lf);
+ }
+ }
+
+ if (type != PPDC_DRIVER_PS || filters->count)
+ {
+ if ((a = find_attr("cupsVersion", NULL)) != NULL)
+ cupsFilePrintf(fp, "*cupsVersion: %s%s", a->value->value, lf);
+ else
+ cupsFilePrintf(fp, "*cupsVersion: %d.%d%s", CUPS_VERSION_MAJOR,
+ CUPS_VERSION_MINOR, lf);
+ cupsFilePrintf(fp, "*cupsModelNumber: %d%s", model_number, lf);
+ cupsFilePrintf(fp, "*cupsManualCopies: %s%s",
+ manual_copies ? "True" : "False", lf);
+
+ if (filters->count)
+ {
+ for (f = (ppdcFilter *)filters->first();
+ f;
+ f = (ppdcFilter *)filters->next())
+ cupsFilePrintf(fp, "*cupsFilter: \"%s %d %s\"%s", f->mime_type->value,
+ f->cost, f->program->value, lf);
+ }
+ else
+ {
+ switch (type)
+ {
+ case PPDC_DRIVER_LABEL :
+ cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
+ "rastertolabel\"%s", lf);
+ break;
+
+ case PPDC_DRIVER_EPSON :
+ cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
+ "rastertoepson\"%s", lf);
+ break;
+
+ case PPDC_DRIVER_ESCP :
+ cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-command 50 "
+ "commandtoescpx\"%s", lf);
+ cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
+ "rastertoescpx\"%s", lf);
+ break;
+
+ case PPDC_DRIVER_HP :
+ cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
+ "rastertohp\"%s", lf);
+ break;
+
+ case PPDC_DRIVER_PCL :
+ cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-command 50 "
+ "commandtopclx\"%s", lf);
+ cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
+ "rastertopclx\"%s", lf);
+ break;
+
+ default :
+ break;
+ }
+ }
+
+ for (p = (ppdcProfile *)profiles->first();
+ p;
+ p = (ppdcProfile *)profiles->next())
+ {
+ char density[255], gamma[255], profile[9][255];
+
+ _cupsStrFormatd(density, density + sizeof(density), p->density, loc);
+ _cupsStrFormatd(gamma, gamma + sizeof(gamma), p->gamma, loc);
+
+ for (int i = 0; i < 9; i ++)
+ _cupsStrFormatd(profile[i], profile[i] + sizeof(profile[0]),
+ p->profile[i], loc);
+
+ cupsFilePrintf(fp,
+ "*cupsColorProfile %s/%s: \"%s %s %s %s %s %s %s %s %s %s "
+ "%s\"%s", p->resolution->value, p->media_type->value,
+ density, gamma, profile[0], profile[1], profile[2],
+ profile[3], profile[4], profile[5], profile[6], profile[7],
+ profile[8], lf);
+ }
+ }
+
+ if (locales)
+ {
+ // Add localizations for additional languages...
+ ppdcString *locale; // Locale name
+ ppdcCatalog *locatalog; // Message catalog for locale
+
+
+ // Write the list of languages...
+ cupsFilePrintf(fp, "*cupsLanguages: \"en");
+
+ for (locale = (ppdcString *)locales->first();
+ locale;
+ locale = (ppdcString *)locales->next())
+ {
+ // Skip (US) English...
+ if (!strcmp(locale->value, "en") || !strcmp(locale->value, "en_US"))
+ continue;
+
+ // See if we have a po file for this language...
+ if (!src->find_po(locale->value))
+ {
+ // No, see if we can use the base file?
+ locatalog = new ppdcCatalog(locale->value);
+
+ if (locatalog->messages->count == 0)
+ {
+ // No, skip this one...
+ _cupsLangPrintf(stderr,
+ _("ppdc: No message catalog provided for locale "
+ "%s."), locale->value);
+ continue;
+ }
+
+ // Add the base file to the list...
+ src->po_files->add(locatalog);
+ }
+
+ cupsFilePrintf(fp, " %s", locale->value);
+ }
+
+ cupsFilePrintf(fp, "\"%s", lf);
+ }
+
+ for (cn = (ppdcConstraint *)constraints->first();
+ cn;
+ cn = (ppdcConstraint *)constraints->next())
+ {
+ // First constrain 1 against 2...
+ if (!strncmp(cn->option1->value, "*Custom", 7) ||
+ !strncmp(cn->option2->value, "*Custom", 7))
+ cupsFilePuts(fp, "*NonUIConstraints: ");
+ else
+ cupsFilePuts(fp, "*UIConstraints: ");
+
+ if (cn->option1->value[0] != '*')
+ cupsFilePutChar(fp, '*');
+
+ cupsFilePuts(fp, cn->option1->value);
+
+ if (cn->choice1->value)
+ cupsFilePrintf(fp, " %s", cn->choice1->value);
+
+ cupsFilePutChar(fp, ' ');
+
+ if (cn->option2->value[0] != '*')
+ cupsFilePutChar(fp, '*');
+
+ cupsFilePuts(fp, cn->option2->value);
+
+ if (cn->choice2->value)
+ cupsFilePrintf(fp, " %s", cn->choice2->value);
+
+ cupsFilePuts(fp, lf);
+
+ // Then constrain 2 against 1...
+ if (!strncmp(cn->option1->value, "*Custom", 7) ||
+ !strncmp(cn->option2->value, "*Custom", 7))
+ cupsFilePuts(fp, "*NonUIConstraints: ");
+ else
+ cupsFilePuts(fp, "*UIConstraints: ");
+
+ if (cn->option2->value[0] != '*')
+ cupsFilePutChar(fp, '*');
+
+ cupsFilePuts(fp, cn->option2->value);
+
+ if (cn->choice2->value)
+ cupsFilePrintf(fp, " %s", cn->choice2->value);
+
+ cupsFilePutChar(fp, ' ');
+
+ if (cn->option1->value[0] != '*')
+ cupsFilePutChar(fp, '*');
+
+ cupsFilePuts(fp, cn->option1->value);
+
+ if (cn->choice1->value)
+ cupsFilePrintf(fp, " %s", cn->choice1->value);
+
+ cupsFilePuts(fp, lf);
+ }
+
+ // PageSize option...
+ cupsFilePrintf(fp, "*OpenUI *PageSize/Media Size: PickOne%s", lf);
+ cupsFilePrintf(fp, "*OrderDependency: 10 AnySetup *PageSize%s", lf);
+ cupsFilePrintf(fp, "*DefaultPageSize: %s%s",
+ default_size ? default_size->value : "Letter", lf);
+
+ for (m = (ppdcMediaSize *)sizes->first();
+ m;
+ m = (ppdcMediaSize *)sizes->next())
+ if (m->size_code->value)
+ {
+ cupsFilePrintf(fp, "*PageSize %s/%s: \"%s\"%s",
+ m->name->value, catalog->find_message(m->text->value),
+ m->size_code->value, lf);
+
+ if (strchr(m->size_code->value, '\n') ||
+ strchr(m->size_code->value, '\r'))
+ cupsFilePrintf(fp, "*End%s", lf);
+ }
+ else
+ cupsFilePrintf(fp,
+ "*PageSize %s/%s: \"<</PageSize[%.0f %.0f]"
+ "/ImagingBBox null>>setpagedevice\"%s",
+ m->name->value, catalog->find_message(m->text->value),
+ m->width, m->length, lf);
+
+ if ((a = find_attr("?PageSize", NULL)) != NULL)
+ {
+ cupsFilePrintf(fp, "*?PageSize: \"%s\"%s", a->value->value, lf);
+
+ if (strchr(a->value->value, '\n') ||
+ strchr(a->value->value, '\r'))
+ cupsFilePrintf(fp, "*End%s", lf);
+ }
+
+ cupsFilePrintf(fp, "*CloseUI: *PageSize%s", lf);
+
+ // PageRegion option...
+ cupsFilePrintf(fp, "*OpenUI *PageRegion/Media Size: PickOne%s", lf);
+ cupsFilePrintf(fp, "*OrderDependency: 10 AnySetup *PageRegion%s", lf);
+ cupsFilePrintf(fp, "*DefaultPageRegion: %s%s",
+ default_size ? default_size->value : "Letter", lf);
+
+ for (m = (ppdcMediaSize *)sizes->first();
+ m;
+ m = (ppdcMediaSize *)sizes->next())
+ if (m->region_code->value)
+ {
+ cupsFilePrintf(fp, "*PageRegion %s/%s: \"%s\"%s",
+ m->name->value, catalog->find_message(m->text->value),
+ m->region_code->value, lf);
+
+ if (strchr(m->region_code->value, '\n') ||
+ strchr(m->region_code->value, '\r'))
+ cupsFilePrintf(fp, "*End%s", lf);
+ }
+ else
+ cupsFilePrintf(fp,
+ "*PageRegion %s/%s: \"<</PageSize[%.0f %.0f]"
+ "/ImagingBBox null>>setpagedevice\"%s",
+ m->name->value, catalog->find_message(m->text->value),
+ m->width, m->length, lf);
+
+ if ((a = find_attr("?PageRegion", NULL)) != NULL)
+ {
+ cupsFilePrintf(fp, "*?PageRegion: \"%s\"%s", a->value->value, lf);
+
+ if (strchr(a->value->value, '\n') ||
+ strchr(a->value->value, '\r'))
+ cupsFilePrintf(fp, "*End%s", lf);
+ }
+
+ cupsFilePrintf(fp, "*CloseUI: *PageRegion%s", lf);
+
+ // ImageableArea info...
+ cupsFilePrintf(fp, "*DefaultImageableArea: %s%s",
+ default_size ? default_size->value : "Letter", lf);
+
+ char left[255], right[255], bottom[255], top[255];
+
+ for (m = (ppdcMediaSize *)sizes->first();
+ m;
+ m = (ppdcMediaSize *)sizes->next())
+ {
+ _cupsStrFormatd(left, left + sizeof(left), m->left, loc);
+ _cupsStrFormatd(bottom, bottom + sizeof(bottom), m->bottom, loc);
+ _cupsStrFormatd(right, right + sizeof(right), m->width - m->right, loc);
+ _cupsStrFormatd(top, top + sizeof(top), m->length - m->top, loc);
+
+ cupsFilePrintf(fp, "*ImageableArea %s/%s: \"%s %s %s %s\"%s",
+ m->name->value, catalog->find_message(m->text->value),
+ left, bottom, right, top, lf);
+ }
+
+ if ((a = find_attr("?ImageableArea", NULL)) != NULL)
+ {
+ cupsFilePrintf(fp, "*?ImageableArea: \"%s\"%s", a->value->value, lf);
+
+ if (strchr(a->value->value, '\n') ||
+ strchr(a->value->value, '\r'))
+ cupsFilePrintf(fp, "*End%s", lf);
+ }
+
+ // PaperDimension info...
+ cupsFilePrintf(fp, "*DefaultPaperDimension: %s%s",
+ default_size ? default_size->value : "Letter", lf);
+
+ char width[255], length[255];
+
+ for (m = (ppdcMediaSize *)sizes->first();
+ m;
+ m = (ppdcMediaSize *)sizes->next())
+ {
+ _cupsStrFormatd(width, width + sizeof(width), m->width, loc);
+ _cupsStrFormatd(length, length + sizeof(length), m->length, loc);
+
+ cupsFilePrintf(fp, "*PaperDimension %s/%s: \"%s %s\"%s",
+ m->name->value, catalog->find_message(m->text->value),
+ width, length, lf);
+ }
+
+ if ((a = find_attr("?PaperDimension", NULL)) != NULL)
+ {
+ cupsFilePrintf(fp, "*?PaperDimension: \"%s\"%s", a->value->value, lf);
+
+ if (strchr(a->value->value, '\n') ||
+ strchr(a->value->value, '\r'))
+ cupsFilePrintf(fp, "*End%s", lf);
+ }
+
+ // Custom size support...
+ if (variable_paper_size)
+ {
+ _cupsStrFormatd(width, width + sizeof(width), max_width, loc);
+ _cupsStrFormatd(length, length + sizeof(length), max_length, loc);
+
+ _cupsStrFormatd(left, left + sizeof(left), left_margin, loc);
+ _cupsStrFormatd(bottom, bottom + sizeof(bottom), bottom_margin, loc);
+ _cupsStrFormatd(right, right + sizeof(right), right_margin, loc);
+ _cupsStrFormatd(top, top + sizeof(top), top_margin, loc);
+
+ cupsFilePrintf(fp, "*MaxMediaWidth: \"%s\"%s", width, lf);
+ cupsFilePrintf(fp, "*MaxMediaHeight: \"%s\"%s", length, lf);
+ cupsFilePrintf(fp, "*HWMargins: %s %s %s %s%s", left, bottom, right, top,
+ lf);
+
+ if (custom_size_code && custom_size_code->value)
+ {
+ cupsFilePrintf(fp, "*CustomPageSize True: \"%s\"%s",
+ custom_size_code->value, lf);
+
+ if (strchr(custom_size_code->value, '\n') ||
+ strchr(custom_size_code->value, '\r'))
+ cupsFilePrintf(fp, "*End%s", lf);
+ }
+ else
+ cupsFilePrintf(fp,
+ "*CustomPageSize True: \"pop pop pop <</PageSize[5 -2 roll]"
+ "/ImagingBBox null>>setpagedevice\"%s", lf);
+
+ if ((a = find_attr("ParamCustomPageSize", "Width")) != NULL)
+ cupsFilePrintf(fp, "*ParamCustomPageSize Width: %s%s", a->value->value,
+ lf);
+ else
+ {
+ char width0[255];
+
+ _cupsStrFormatd(width0, width0 + sizeof(width0), min_width, loc);
+ _cupsStrFormatd(width, width + sizeof(width), max_width, loc);
+
+ cupsFilePrintf(fp, "*ParamCustomPageSize Width: 1 points %s %s%s",
+ width0, width, lf);
+ }
+
+ if ((a = find_attr("ParamCustomPageSize", "Height")) != NULL)
+ cupsFilePrintf(fp, "*ParamCustomPageSize Height: %s%s", a->value->value,
+ lf);
+ else
+ {
+ char length0[255];
+
+ _cupsStrFormatd(length0, length0 + sizeof(length0), min_length, loc);
+ _cupsStrFormatd(length, length + sizeof(length), max_length, loc);
+
+ cupsFilePrintf(fp, "*ParamCustomPageSize Height: 2 points %s %s%s",
+ length0, length, lf);
+ }
+
+ if ((a = find_attr("ParamCustomPageSize", "WidthOffset")) != NULL)
+ cupsFilePrintf(fp, "*ParamCustomPageSize WidthOffset: %s%s",
+ a->value->value, lf);
+ else
+ cupsFilePrintf(fp, "*ParamCustomPageSize WidthOffset: 3 points 0 0%s", lf);
+
+ if ((a = find_attr("ParamCustomPageSize", "HeightOffset")) != NULL)
+ cupsFilePrintf(fp, "*ParamCustomPageSize HeightOffset: %s%s",
+ a->value->value, lf);
+ else
+ cupsFilePrintf(fp, "*ParamCustomPageSize HeightOffset: 4 points 0 0%s", lf);
+
+ if ((a = find_attr("ParamCustomPageSize", "Orientation")) != NULL)
+ cupsFilePrintf(fp, "*ParamCustomPageSize Orientation: %s%s",
+ a->value->value, lf);
+ else
+ cupsFilePrintf(fp, "*ParamCustomPageSize Orientation: 5 int 0 0%s", lf);
+ }
+
+ // All other options...
+ for (g = (ppdcGroup *)groups->first(); g; g = (ppdcGroup *)groups->next())
+ {
+ if (!g->options->count)
+ continue;
+
+ if (_cups_strcasecmp(g->name->value, "General"))
+ cupsFilePrintf(fp, "*OpenGroup: %s/%s%s", g->name->value,
+ catalog->find_message(g->text->value), lf);
+
+ for (o = (ppdcOption *)g->options->first();
+ o;
+ o = (ppdcOption *)g->options->next())
+ {
+ if (!o->choices->count)
+ continue;
+
+ if (!o->text->value)
+ cupsFilePrintf(fp, "*OpenUI *%s/%s: ", o->name->value,
+ catalog->find_message(o->name->value));
+ else
+ cupsFilePrintf(fp, "*OpenUI *%s/%s: ", o->name->value,
+ catalog->find_message(o->text->value));
+
+ switch (o->type)
+ {
+ case PPDC_BOOLEAN :
+ cupsFilePrintf(fp, "Boolean%s", lf);
+ break;
+ default :
+ cupsFilePrintf(fp, "PickOne%s", lf);
+ break;
+ case PPDC_PICKMANY :
+ cupsFilePrintf(fp, "PickMany%s", lf);
+ break;
+ }
+
+ char order[255];
+ _cupsStrFormatd(order, order + sizeof(order), o->order, loc);
+
+ cupsFilePrintf(fp, "*OrderDependency: %s ", order);
+ switch (o->section)
+ {
+ default :
+ cupsFilePrintf(fp, "AnySetup");
+ break;
+ case PPDC_SECTION_DOCUMENT :
+ cupsFilePrintf(fp, "DocumentSetup");
+ break;
+ case PPDC_SECTION_EXIT :
+ cupsFilePrintf(fp, "ExitServer");
+ break;
+ case PPDC_SECTION_JCL :
+ cupsFilePrintf(fp, "JCLSetup");
+ break;
+ case PPDC_SECTION_PAGE :
+ cupsFilePrintf(fp, "PageSetup");
+ break;
+ case PPDC_SECTION_PROLOG :
+ cupsFilePrintf(fp, "Prolog");
+ break;
+ }
+
+ cupsFilePrintf(fp, " *%s%s", o->name->value, lf);
+
+ if (o->defchoice)
+ {
+ // Use the programmer-supplied default...
+ cupsFilePrintf(fp, "*Default%s: %s%s", o->name->value,
+ o->defchoice->value, lf);
+ }
+ else
+ {
+ // Make the first choice the default...
+ c = (ppdcChoice *)o->choices->first();
+ cupsFilePrintf(fp, "*Default%s: %s%s", o->name->value, c->name->value,
+ lf);
+ }
+
+ for (c = (ppdcChoice *)o->choices->first();
+ c;
+ c = (ppdcChoice *)o->choices->next())
+ {
+ // Write this choice...
+ if (!c->text->value)
+ cupsFilePrintf(fp, "*%s %s/%s: \"%s\"%s", o->name->value,
+ c->name->value, catalog->find_message(c->name->value),
+ c->code->value, lf);
+ else
+ cupsFilePrintf(fp, "*%s %s/%s: \"%s\"%s", o->name->value,
+ c->name->value, catalog->find_message(c->text->value),
+ c->code->value, lf);
+
+ // Multi-line commands need a *End line to terminate them.
+ if (strchr(c->code->value, '\n') ||
+ strchr(c->code->value, '\r'))
+ cupsFilePrintf(fp, "*End%s", lf);
+ }
+
+ snprintf(query, sizeof(query), "?%s", o->name->value);
+
+ if ((a = find_attr(query, NULL)) != NULL)
+ {
+ cupsFilePrintf(fp, "*%s: \"%s\"%s", query, a->value->value, lf);
+
+ if (strchr(a->value->value, '\n') ||
+ strchr(a->value->value, '\r'))
+ cupsFilePrintf(fp, "*End%s", lf);
+ }
+
+ cupsFilePrintf(fp, "*CloseUI: *%s%s", o->name->value, lf);
+
+ snprintf(custom, sizeof(custom), "Custom%s", o->name->value);
+ if ((a = find_attr(custom, "True")) != NULL)
+ {
+ // Output custom option information...
+ cupsFilePrintf(fp, "*%s True: \"%s\"%s", custom, a->value->value, lf);
+ if (strchr(a->value->value, '\n') || strchr(a->value->value, '\r'))
+ cupsFilePrintf(fp, "*End%s", lf);
+
+ snprintf(custom, sizeof(custom), "ParamCustom%s", o->name->value);
+ for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
+ {
+ if (strcmp(a->name->value, custom))
+ continue;
+
+ if (!a->selector->value || !a->selector->value[0])
+ cupsFilePrintf(fp, "*%s", a->name->value);
+ else if (!a->text->value || !a->text->value[0])
+ cupsFilePrintf(fp, "*%s %s/%s", a->name->value, a->selector->value,
+ catalog->find_message(a->selector->value));
+ else
+ cupsFilePrintf(fp, "*%s %s/%s", a->name->value, a->selector->value,
+ catalog->find_message(a->text->value));
+
+ cupsFilePrintf(fp, ": %s%s", a->value->value, lf);
+ }
+ }
+ }
+
+ if (_cups_strcasecmp(g->name->value, "General"))
+ cupsFilePrintf(fp, "*CloseGroup: %s%s", g->name->value, lf);
+ }
+
+ if (locales)
+ {
+ // Add localizations for additional languages...
+ ppdcString *locale; // Locale name
+ ppdcCatalog *locatalog; // Message catalog for locale
+
+
+ // Write the translation strings for each language...
+ for (locale = (ppdcString *)locales->first();
+ locale;
+ locale = (ppdcString *)locales->next())
+ {
+ // Skip (US) English...
+ if (!strcmp(locale->value, "en") || !strcmp(locale->value, "en_US"))
+ continue;
+
+ // Skip missing languages...
+ if ((locatalog = src->find_po(locale->value)) == NULL)
+ continue;
+
+ // Do the core stuff first...
+ cupsFilePrintf(fp, "*%s.Translation Manufacturer/%s: \"\"%s",
+ locale->value,
+ locatalog->find_message(manufacturer->value), lf);
+
+ if ((a = find_attr("ModelName", NULL)) != NULL)
+ cupsFilePrintf(fp, "*%s.Translation ModelName/%s: \"\"%s",
+ locale->value,
+ locatalog->find_message(a->value->value), lf);
+ else if (_cups_strncasecmp(model_name->value, manufacturer->value,
+ strlen(manufacturer->value)))
+ cupsFilePrintf(fp, "*%s.Translation ModelName/%s %s: \"\"%s",
+ locale->value,
+ locatalog->find_message(manufacturer->value),
+ locatalog->find_message(model_name->value), lf);
+ else
+ cupsFilePrintf(fp, "*%s.Translation ModelName/%s: \"\"%s",
+ locale->value,
+ locatalog->find_message(model_name->value), lf);
+
+ if ((a = find_attr("ShortNickName", NULL)) != NULL)
+ cupsFilePrintf(fp, "*%s.Translation ShortNickName/%s: \"\"%s",
+ locale->value,
+ locatalog->find_message(a->value->value), lf);
+ else if (_cups_strncasecmp(model_name->value, manufacturer->value,
+ strlen(manufacturer->value)))
+ cupsFilePrintf(fp, "*%s.Translation ShortNickName/%s %s: \"\"%s",
+ locale->value,
+ locatalog->find_message(manufacturer->value),
+ locatalog->find_message(model_name->value), lf);
+ else
+ cupsFilePrintf(fp, "*%s.Translation ShortNickName/%s: \"\"%s",
+ locale->value,
+ locatalog->find_message(model_name->value), lf);
+
+ if ((a = find_attr("NickName", NULL)) != NULL)
+ cupsFilePrintf(fp, "*%s.Translation NickName/%s: \"\"%s",
+ locale->value,
+ locatalog->find_message(a->value->value), lf);
+ else if (_cups_strncasecmp(model_name->value, manufacturer->value,
+ strlen(manufacturer->value)))
+ cupsFilePrintf(fp, "*%s.Translation NickName/%s %s, %s: \"\"%s",
+ locale->value,
+ locatalog->find_message(manufacturer->value),
+ locatalog->find_message(model_name->value),
+ version->value, lf);
+ else
+ cupsFilePrintf(fp, "*%s.Translation NickName/%s, %s: \"\"%s",
+ locale->value,
+ locatalog->find_message(model_name->value),
+ version->value, lf);
+
+ // Then the page sizes...
+ cupsFilePrintf(fp, "*%s.Translation PageSize/%s: \"\"%s", locale->value,
+ locatalog->find_message("Media Size"), lf);
+
+ for (m = (ppdcMediaSize *)sizes->first();
+ m;
+ m = (ppdcMediaSize *)sizes->next())
+ {
+ cupsFilePrintf(fp, "*%s.PageSize %s/%s: \"\"%s", locale->value,
+ m->name->value, locatalog->find_message(m->text->value),
+ lf);
+ }
+
+ // Next the groups and options...
+ for (g = (ppdcGroup *)groups->first(); g; g = (ppdcGroup *)groups->next())
+ {
+ if (!g->options->count)
+ continue;
+
+ if (_cups_strcasecmp(g->name->value, "General"))
+ cupsFilePrintf(fp, "*%s.Translation %s/%s: \"\"%s", locale->value,
+ g->name->value,
+ locatalog->find_message(g->text->value), lf);
+
+ for (o = (ppdcOption *)g->options->first();
+ o;
+ o = (ppdcOption *)g->options->next())
+ {
+ if (!o->choices->count)
+ continue;
+
+ cupsFilePrintf(fp, "*%s.Translation %s/%s: \"\"%s", locale->value,
+ o->name->value,
+ locatalog->find_message(o->text->value ?
+ o->text->value :
+ o->name->value), lf);
+
+ for (c = (ppdcChoice *)o->choices->first();
+ c;
+ c = (ppdcChoice *)o->choices->next())
+ {
+ // Write this choice...
+ cupsFilePrintf(fp, "*%s.%s %s/%s: \"\"%s", locale->value,
+ o->name->value, c->name->value,
+ locatalog->find_message(c->text->value ?
+ c->text->value :
+ c->name->value), lf);
+ }
+ }
+ }
+
+ // Finally the localizable attributes...
+ for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
+ {
+ if (!a->localizable &&
+ (!a->text || !a->text->value || !a->text->value[0]) &&
+ strcmp(a->name->value, "APCustomColorMatchingName") &&
+ strcmp(a->name->value, "APPrinterPreset") &&
+ strcmp(a->name->value, "cupsICCProfile") &&
+ strcmp(a->name->value, "cupsIPPReason") &&
+ strcmp(a->name->value, "cupsMarkerName") &&
+ strncmp(a->name->value, "Custom", 6) &&
+ strncmp(a->name->value, "ParamCustom", 11))
+ continue;
+
+ cupsFilePrintf(fp, "*%s.%s %s/%s: \"%s\"%s", locale->value,
+ a->name->value, a->selector->value,
+ locatalog->find_message(a->text && a->text->value ?
+ a->text->value : a->name->value),
+ ((a->localizable && a->value->value[0]) ||
+ !strcmp(a->name->value, "cupsIPPReason")) ?
+ locatalog->find_message(a->value->value) : "",
+ lf);
+ }
+ }
+ }
+
+ if (default_font && default_font->value)
+ cupsFilePrintf(fp, "*DefaultFont: %s%s", default_font->value, lf);
+ else
+ cupsFilePrintf(fp, "*DefaultFont: Courier%s", lf);
+
+ for (fn = (ppdcFont *)fonts->first(); fn; fn = (ppdcFont *)fonts->next())
+ if (!strcmp(fn->name->value, "*"))
+ {
+ for (bfn = (ppdcFont *)src->base_fonts->first();
+ bfn;
+ bfn = (ppdcFont *)src->base_fonts->next())
+ cupsFilePrintf(fp, "*Font %s: %s \"%s\" %s %s%s",
+ bfn->name->value, bfn->encoding->value,
+ bfn->version->value, bfn->charset->value,
+ bfn->status == PPDC_FONT_ROM ? "ROM" : "Disk", lf);
+ }
+ else
+ cupsFilePrintf(fp, "*Font %s: %s \"%s\" %s %s%s",
+ fn->name->value, fn->encoding->value, fn->version->value,
+ fn->charset->value,
+ fn->status == PPDC_FONT_ROM ? "ROM" : "Disk", lf);
+
+ cupsFilePrintf(fp, "*%% End of %s, %05d bytes.%s", pc_file_name->value,
+ (int)(cupsFileTell(fp) + 25 + strlen(pc_file_name->value)),
+ lf);
+
+ if (delete_cat)
+ catalog->release();
+
+ return (0);
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-file.cxx b/ppdc/ppdc-file.cxx
new file mode 100644
index 000000000..3d4520eb0
--- /dev/null
+++ b/ppdc/ppdc-file.cxx
@@ -0,0 +1,109 @@
+//
+// "$Id$"
+//
+// File class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2010 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcFile::ppdcFile() - Create (open) a file.
+// ppdcFile::~ppdcFile() - Delete (close) a file.
+// ppdcFile::get() - Get a character from a file.
+// ppdcFile::peek() - Look at the next character from a file.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcFile::ppdcFile()' - Create (open) a file.
+//
+
+ppdcFile::ppdcFile(const char *f, // I - File to open
+ cups_file_t *ffp) // I - File pointer to use
+{
+ if (ffp)
+ {
+ fp = ffp;
+ cupsFileRewind(fp);
+ }
+ else
+ fp = cupsFileOpen(f, "r");
+
+ filename = f;
+ line = 1;
+
+ if (!fp)
+ _cupsLangPrintf(stderr, _("ppdc: Unable to open %s: %s"), f,
+ strerror(errno));
+}
+
+
+//
+// 'ppdcFile::~ppdcFile()' - Delete (close) a file.
+//
+
+ppdcFile::~ppdcFile()
+{
+ if (fp)
+ cupsFileClose(fp);
+}
+
+
+//
+// 'ppdcFile::get()' - Get a character from a file.
+//
+
+int
+ppdcFile::get()
+{
+ int ch; // Character from file
+
+
+ // Return EOF if there is no open file...
+ if (!fp)
+ return (EOF);
+
+ // Get the character...
+ ch = cupsFileGetChar(fp);
+
+ // Update the line number as needed...
+ if (ch == '\n')
+ line ++;
+
+ // Return the character...
+ return (ch);
+}
+
+
+//
+// 'ppdcFile::peek()' - Look at the next character from a file.
+//
+
+int // O - Next character in file
+ppdcFile::peek()
+{
+ // Return immediaely if there is no open file...
+ if (!fp)
+ return (EOF);
+
+ // Otherwise return the next character without advancing...
+ return (cupsFilePeekChar(fp));
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-filter.cxx b/ppdc/ppdc-filter.cxx
new file mode 100644
index 000000000..33994849b
--- /dev/null
+++ b/ppdc/ppdc-filter.cxx
@@ -0,0 +1,60 @@
+//
+// "$Id$"
+//
+// Filter class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2009 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcFilter::ppdcFilter() - Create a filter.
+// ppdcFilter::~ppdcFilter() - Destroy a filter.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcFilter::ppdcFilter()' - Create a filter.
+//
+
+ppdcFilter::ppdcFilter(const char *t, // I - MIME type
+ const char *p, // I - Filter program
+ int c) // I - Relative cost
+ : ppdcShared()
+{
+ PPDC_NEW;
+
+ mime_type = new ppdcString(t);
+ program = new ppdcString(p);
+ cost = c;
+}
+
+
+//
+// 'ppdcFilter::~ppdcFilter()' - Destroy a filter.
+//
+
+ppdcFilter::~ppdcFilter()
+{
+ PPDC_DELETE;
+
+ mime_type->release();
+ program->release();
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-font.cxx b/ppdc/ppdc-font.cxx
new file mode 100644
index 000000000..b6d9bcb2a
--- /dev/null
+++ b/ppdc/ppdc-font.cxx
@@ -0,0 +1,66 @@
+//
+// "$Id$"
+//
+// Shared font class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2009 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcFont::ppdcFont() - Create a shared font.
+// ppdcFont::~ppdcFont() - Destroy a shared font.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcFont::ppdcFont()' - Create a shared font.
+//
+
+ppdcFont::ppdcFont(const char *n, // I - Name of font
+ const char *e, // I - Font encoding
+ const char *v, // I - Font version
+ const char *c, // I - Font charset
+ ppdcFontStatus s) // I - Font status
+ : ppdcShared()
+{
+ PPDC_NEW;
+
+ name = new ppdcString(n);
+ encoding = new ppdcString(e);
+ version = new ppdcString(v);
+ charset = new ppdcString(c);
+ status = s;
+}
+
+
+//
+// 'ppdcFont::~ppdcFont()' - Destroy a shared font.
+//
+
+ppdcFont::~ppdcFont()
+{
+ PPDC_DELETE;
+
+ name->release();
+ encoding->release();
+ version->release();
+ charset->release();
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-group.cxx b/ppdc/ppdc-group.cxx
new file mode 100644
index 000000000..cc0ab280a
--- /dev/null
+++ b/ppdc/ppdc-group.cxx
@@ -0,0 +1,103 @@
+//
+// "$Id$"
+//
+// Group class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2011 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcGroup::ppdcGroup() - Copy a new group.
+// ppdcGroup::~ppdcGroup() - Destroy a group.
+// ppdcGroup::find_option() - Find an option in a group.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcGroup::ppdcGroup()' - Create a new group.
+//
+
+ppdcGroup::ppdcGroup(const char *n, // I - Name of group
+ const char *t) // I - Text of group
+{
+ PPDC_NEWVAL(n);
+
+ name = new ppdcString(n);
+ text = new ppdcString(t);
+ options = new ppdcArray();
+}
+
+
+//
+// 'ppdcGroup::ppdcGroup()' - Copy a new group.
+//
+
+ppdcGroup::ppdcGroup(ppdcGroup *g) // I - Group template
+{
+ PPDC_NEWVAL(g->name->value);
+
+ g->name->retain();
+ g->text->retain();
+
+ name = g->name;
+ text = g->text;
+
+ options = new ppdcArray();
+ for (ppdcOption *o = (ppdcOption *)g->options->first();
+ o;
+ o = (ppdcOption *)g->options->next())
+ options->add(new ppdcOption(o));
+}
+
+
+//
+// 'ppdcGroup::~ppdcGroup()' - Destroy a group.
+//
+
+ppdcGroup::~ppdcGroup()
+{
+ PPDC_DELETEVAL(name ? name->value : NULL);
+
+ name->release();
+ text->release();
+ options->release();
+
+ name = text = 0;
+ options = 0;
+}
+
+
+//
+// 'ppdcGroup::find_option()' - Find an option in a group.
+//
+
+ppdcOption *
+ppdcGroup::find_option(const char *n) // I - Name of option
+{
+ ppdcOption *o; // Current option
+
+
+ for (o = (ppdcOption *)options->first(); o; o = (ppdcOption *)options->next())
+ if (!_cups_strcasecmp(n, o->name->value))
+ return (o);
+
+ return (0);
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-import.cxx b/ppdc/ppdc-import.cxx
new file mode 100644
index 000000000..4794e7715
--- /dev/null
+++ b/ppdc/ppdc-import.cxx
@@ -0,0 +1,343 @@
+//
+// "$Id$"
+//
+// PPD file import methods for the CUPS PPD Compiler.
+//
+// Copyright 2007-2011 by Apple Inc.
+// Copyright 2002-2006 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcSource::import_ppd() - Import a PPD file.
+// ppd_gets() - Get a line from a PPD file.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+#include <cups/ppd.h>
+
+
+//
+// 'ppdcSource::import_ppd()' - Import a PPD file.
+//
+
+int // O - 1 on success, 0 on failure
+ppdcSource::import_ppd(const char *f) // I - Filename
+{
+ int i, j, k; // Looping vars
+ cups_file_t *fp; // File
+ char line[256], // Comment line
+ *ptr; // Pointer into line
+ int cost; // Cost for filter
+ ppd_file_t *ppd; // PPD file data
+ ppd_group_t *group; // PPD group
+ ppd_option_t *option; // PPD option
+ ppd_choice_t *choice; // PPD choice
+ ppd_attr_t *attr; // PPD attribute
+ ppd_const_t *constraint; // PPD UI constraint
+ ppd_const_t *constraint2; // Temp PPD UI constraint
+ ppd_size_t *size; // PPD page size
+ ppdcDriver *driver; // Driver
+ ppdcFilter *filter; // Current filter
+ ppdcFont *font; // Font
+ ppdcGroup *cgroup; // UI group
+ ppdcOption *coption; // UI option
+ ppdcChoice *cchoice; // UI choice
+ ppdcConstraint *cconstraint; // UI constraint
+ ppdcMediaSize *csize; // Media size
+
+
+ // Try opening the PPD file...
+ if ((ppd = ppdOpenFile(f)) == NULL)
+ return (0);
+
+ // All PPD files need a PCFileName attribute...
+ if (!ppd->pcfilename)
+ {
+ ppdClose(ppd);
+ return (0);
+ }
+
+ // See if the driver has already been imported...
+ if ((driver = find_driver(ppd->pcfilename)) == NULL)
+ {
+ // Create a new PPD file...
+ if ((fp = cupsFileOpen(f, "r")) == NULL)
+ {
+ ppdClose(ppd);
+ return (0);
+ }
+
+ driver = new ppdcDriver();
+ driver->type = PPDC_DRIVER_PS;
+
+ drivers->add(driver);
+
+ // Read the initial comments from the PPD file and use them as the
+ // copyright/license text...
+ cupsFileGets(fp, line, sizeof(line));
+ // Skip *PPD-Adobe-M.m
+
+ while (cupsFileGets(fp, line, sizeof(line)))
+ if (strncmp(line, "*%", 2))
+ break;
+ else if (strncmp(line, "*%%%% ", 6))
+ {
+ for (ptr = line + 2; isspace(*ptr); ptr ++);
+
+ driver->add_copyright(ptr);
+ }
+
+ cupsFileClose(fp);
+
+ // Then add the stuff from the PPD file...
+ if (ppd->modelname && ppd->manufacturer &&
+ !_cups_strncasecmp(ppd->modelname, ppd->manufacturer,
+ strlen(ppd->manufacturer)))
+ {
+ ptr = ppd->modelname + strlen(ppd->manufacturer);
+
+ while (isspace(*ptr))
+ ptr ++;
+ }
+ else
+ ptr = ppd->modelname;
+
+ if (ppd->nickname)
+ driver->add_attr(new ppdcAttr("NickName", NULL, NULL, ppd->nickname));
+
+ if (ppd->shortnickname)
+ driver->add_attr(new ppdcAttr("ShortNickName", NULL, NULL,
+ ppd->shortnickname));
+
+ driver->manufacturer = new ppdcString(ppd->manufacturer);
+ driver->model_name = new ppdcString(ptr);
+ driver->pc_file_name = new ppdcString(ppd->pcfilename);
+ attr = ppdFindAttr(ppd, "FileVersion", NULL);
+ driver->version = new ppdcString(attr ? attr->value : NULL);
+ driver->model_number = ppd->model_number;
+ driver->manual_copies = ppd->manual_copies;
+ driver->color_device = ppd->color_device;
+ driver->throughput = ppd->throughput;
+ driver->variable_paper_size = ppd->variable_sizes;
+ driver->max_width = ppd->custom_max[0];
+ driver->max_length = ppd->custom_max[1];
+ driver->min_width = ppd->custom_min[0];
+ driver->min_length = ppd->custom_min[1];
+ driver->left_margin = ppd->custom_margins[0];
+ driver->bottom_margin = ppd->custom_margins[1];
+ driver->right_margin = ppd->custom_margins[2];
+ driver->top_margin = ppd->custom_margins[3];
+
+ for (i = 0; i < ppd->num_filters; i ++)
+ {
+ strlcpy(line, ppd->filters[i], sizeof(line));
+
+ for (ptr = line; *ptr; ptr ++)
+ if (isspace(*ptr & 255))
+ break;
+ *ptr++ = '\0';
+
+ cost = strtol(ptr, &ptr, 10);
+
+ while (isspace(*ptr & 255))
+ ptr ++;
+
+ filter = new ppdcFilter(line, ptr, cost);
+ driver->add_filter(filter);
+ }
+
+ attr = ppdFindAttr(ppd, "DefaultFont", NULL);
+ driver->default_font = new ppdcString(attr ? attr->value : NULL);
+
+ // Collect media sizes...
+ ppd_option_t *region_option, // PageRegion option
+ *size_option; // PageSize option
+ ppd_choice_t *region_choice, // PageRegion choice
+ *size_choice; // PageSize choice
+
+ region_option = ppdFindOption(ppd, "PageRegion");
+ size_option = ppdFindOption(ppd, "PageSize");
+
+ for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
+ {
+ // Don't do custom size here...
+ if (!_cups_strcasecmp(size->name, "Custom"))
+ continue;
+
+ // Get the code for the PageSize and PageRegion options...
+ region_choice = ppdFindChoice(region_option, size->name);
+ size_choice = ppdFindChoice(size_option, size->name);
+
+ // Create a new media size record and add it to the driver...
+ csize = new ppdcMediaSize(size->name, size_choice->text, size->width,
+ size->length, size->left, size->bottom,
+ size->width - size->right,
+ size->length - size->top,
+ size_choice->code, region_choice->code);
+
+ driver->add_size(csize);
+
+ if (!_cups_strcasecmp(size_option->defchoice, size->name))
+ driver->set_default_size(csize);
+ }
+
+ // Now all of the options...
+ for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
+ {
+ cgroup = new ppdcGroup(group->name, group->text);
+ driver->add_group(cgroup);
+
+ for (j = group->num_options, option = group->options; j > 0; j --, option ++)
+ {
+ if (!strcmp(option->keyword, "PageSize") || !strcmp(option->keyword, "PageRegion"))
+ continue;
+
+ coption = new ppdcOption((ppdcOptType)option->ui, option->keyword,
+ option->text, (ppdcOptSection)option->section,
+ option->order);
+ cgroup->add_option(coption);
+
+ for (k = option->num_choices, choice = option->choices; k > 0; k --, choice ++)
+ {
+ if (!strcmp(choice->choice, "Custom"))
+ continue;
+
+ cchoice = new ppdcChoice(choice->choice, choice->text, choice->code);
+ coption->add_choice(cchoice);
+
+ if (!_cups_strcasecmp(option->defchoice, choice->choice))
+ coption->set_defchoice(cchoice);
+ }
+ }
+ }
+
+ // Now the constraints...
+ for (i = ppd->num_consts, constraint = ppd->consts;
+ i > 0;
+ i --, constraint ++)
+ {
+ // Look for mirrored constraints...
+ for (j = i - 1, constraint2 = constraint + 1;
+ j > 0;
+ j --, constraint2 ++)
+ if (!strcmp(constraint->option1, constraint2->option2) &&
+ !strcmp(constraint->choice1, constraint2->choice2) &&
+ !strcmp(constraint->option2, constraint2->option1) &&
+ !strcmp(constraint->choice2, constraint2->choice1))
+ break;
+
+ if (j)
+ continue;
+
+ cconstraint = new ppdcConstraint(constraint->option2, constraint->choice2,
+ constraint->option1, constraint->choice1);
+ driver->add_constraint(cconstraint);
+ }
+
+ for (i = 0; i < ppd->num_attrs; i ++)
+ {
+ attr = ppd->attrs[i];
+
+ if (!strcmp(attr->name, "Font"))
+ {
+ // Font...
+ char encoding[256], // Encoding string
+ version[256], // Version string
+ charset[256], // Charset string
+ status[256]; // Status string
+ ppdcFontStatus fstatus; // Status enumeration
+
+
+ if (sscanf(attr->value, "%s%*[^\"]\"%[^\"]\"%s%s", encoding, version,
+ charset, status) != 4)
+ {
+ _cupsLangPrintf(stderr, _("ppdc: Bad font attribute: %s"),
+ attr->value);
+ continue;
+ }
+
+ if (!strcmp(status, "ROM"))
+ fstatus = PPDC_FONT_ROM;
+ else
+ fstatus = PPDC_FONT_DISK;
+
+ font = new ppdcFont(attr->spec, encoding, version, charset, fstatus);
+
+ driver->add_font(font);
+ }
+ else if (!strcmp(attr->name, "CustomPageSize"))
+ {
+ driver->set_custom_size_code(attr->value);
+ }
+ else if ((strncmp(attr->name, "Default", 7) ||
+ !strcmp(attr->name, "DefaultColorSpace")) &&
+ strcmp(attr->name, "ColorDevice") &&
+ strcmp(attr->name, "Manufacturer") &&
+ strcmp(attr->name, "ModelName") &&
+ strcmp(attr->name, "MaxMediaHeight") &&
+ strcmp(attr->name, "MaxMediaWidth") &&
+ strcmp(attr->name, "NickName") &&
+ strcmp(attr->name, "ParamCustomPageSize") &&
+ strcmp(attr->name, "ShortNickName") &&
+ strcmp(attr->name, "Throughput") &&
+ strcmp(attr->name, "PCFileName") &&
+ strcmp(attr->name, "FileVersion") &&
+ strcmp(attr->name, "FormatVersion") &&
+ strcmp(attr->name, "HWMargins") &&
+ strcmp(attr->name, "VariablePaperSize") &&
+ strcmp(attr->name, "LanguageEncoding") &&
+ strcmp(attr->name, "LanguageVersion") &&
+ strcmp(attr->name, "cupsFilter") &&
+ strcmp(attr->name, "cupsFlipDuplex") &&
+ strcmp(attr->name, "cupsLanguages") &&
+ strcmp(attr->name, "cupsManualCopies") &&
+ strcmp(attr->name, "cupsModelNumber") &&
+ strcmp(attr->name, "cupsVersion"))
+ {
+ if ((ptr = strchr(attr->name, '.')) != NULL &&
+ ((ptr - attr->name) == 2 || (ptr - attr->name) == 5))
+ {
+ // Might be a localization attribute; test further...
+ if (isalpha(attr->name[0] & 255) &&
+ isalpha(attr->name[1] & 255) &&
+ (attr->name[2] == '.' ||
+ (attr->name[2] == '_' && isalpha(attr->name[3] & 255) &&
+ isalpha(attr->name[4] & 255))))
+ continue;
+ }
+
+ // Attribute...
+ driver->add_attr(new ppdcAttr(attr->name, attr->spec, attr->text,
+ attr->value));
+ }
+ else if (!strncmp(attr->name, "Default", 7) &&
+ !ppdFindOption(ppd, attr->name + 7) &&
+ strcmp(attr->name, "DefaultFont") &&
+ strcmp(attr->name, "DefaultImageableArea") &&
+ strcmp(attr->name, "DefaultPaperDimension") &&
+ strcmp(attr->name, "DefaultFont"))
+ {
+ // Default attribute...
+ driver->add_attr(new ppdcAttr(attr->name, attr->spec, attr->text,
+ attr->value));
+ }
+ }
+ }
+
+ return (1);
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-mediasize.cxx b/ppdc/ppdc-mediasize.cxx
new file mode 100644
index 000000000..844028a39
--- /dev/null
+++ b/ppdc/ppdc-mediasize.cxx
@@ -0,0 +1,85 @@
+//
+// "$Id$"
+//
+// Shared media size class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2009 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcMediaSize::ppdcMediaSize() - Create a new media size.
+// ppdcMediaSize::~ppdcMediaSize() - Destroy a media size.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcMediaSize::ppdcMediaSize()' - Create a new media size.
+//
+
+ppdcMediaSize::ppdcMediaSize(const char *n, // I - Name of media size
+ const char *t, // I - Text of media size
+ float w, // I - Width in points
+ float l, // I - Length in points
+ float lm, // I - Left margin in points
+ float bm, // I - Bottom margin in points
+ float rm, // I - Right margin in points
+ float tm, // I - Top margin in points
+ const char *sc, // I - PageSize code, if any
+ const char *rc) // I - PageRegion code, if any
+ : ppdcShared()
+{
+ PPDC_NEW;
+
+ name = new ppdcString(n);
+ text = new ppdcString(t);
+ width = w;
+ length = l;
+ left = lm;
+ bottom = bm;
+ right = rm;
+ top = tm;
+ size_code = new ppdcString(sc);
+ region_code = new ppdcString(rc);
+
+ if (left < 0.0f)
+ left = 0.0f;
+ if (bottom < 0.0f)
+ bottom = 0.0f;
+ if (right < 0.0f)
+ right = 0.0f;
+ if (top < 0.0f)
+ top = 0.0f;
+}
+
+
+//
+// 'ppdcMediaSize::~ppdcMediaSize()' - Destroy a media size.
+//
+
+ppdcMediaSize::~ppdcMediaSize()
+{
+ PPDC_DELETE;
+
+ name->release();
+ text->release();
+ size_code->release();
+ region_code->release();
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-message.cxx b/ppdc/ppdc-message.cxx
new file mode 100644
index 000000000..11e5e3eaa
--- /dev/null
+++ b/ppdc/ppdc-message.cxx
@@ -0,0 +1,58 @@
+//
+// "$Id$"
+//
+// Shared message class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2009 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcMessage::ppdcMessage() - Create a shared message.
+// ppdcMessage::~ppdcMessage() - Destroy a shared message.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcMessage::ppdcMessage()' - Create a shared message.
+//
+
+ppdcMessage::ppdcMessage(const char *i, // I - ID
+ const char *s) // I - Text
+ : ppdcShared()
+{
+ PPDC_NEW;
+
+ id = new ppdcString(i);
+ string = new ppdcString(s);
+}
+
+
+//
+// 'ppdcMessage::~ppdcMessage()' - Destroy a shared message.
+//
+
+ppdcMessage::~ppdcMessage()
+{
+ PPDC_DELETE;
+
+ id->release();
+ string->release();
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-option.cxx b/ppdc/ppdc-option.cxx
new file mode 100644
index 000000000..e80df3c87
--- /dev/null
+++ b/ppdc/ppdc-option.cxx
@@ -0,0 +1,129 @@
+//
+// "$Id$"
+//
+// Option class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2011 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcOption::ppdcOption() - Copy a new option.
+// ppdcOption::~ppdcOption() - Destroy an option.
+// ppdcOption::find_choice() - Find an option choice.
+// ppdcOption::set_defchoice() - Set the default choice.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcOption::ppdcOption()' - Create a new option.
+//
+
+ppdcOption::ppdcOption(ppdcOptType ot, // I - Option type
+ const char *n, // I - Option name
+ const char *t, // I - Option text
+ ppdcOptSection s, // I - Section
+ float o) // I - Ordering number
+ : ppdcShared()
+{
+ PPDC_NEW;
+
+ type = ot;
+ name = new ppdcString(n);
+ text = new ppdcString(t);
+ section = s;
+ order = o;
+ choices = new ppdcArray();
+ defchoice = 0;
+}
+
+
+//
+// 'ppdcOption::ppdcOption()' - Copy a new option.
+//
+
+ppdcOption::ppdcOption(ppdcOption *o) // I - Template option
+{
+ PPDC_NEW;
+
+ o->name->retain();
+ o->text->retain();
+ if (o->defchoice)
+ o->defchoice->retain();
+
+ type = o->type;
+ name = o->name;
+ text = o->text;
+ section = o->section;
+ order = o->order;
+ choices = new ppdcArray(o->choices);
+ defchoice = o->defchoice;
+}
+
+
+//
+// 'ppdcOption::~ppdcOption()' - Destroy an option.
+//
+
+ppdcOption::~ppdcOption()
+{
+ PPDC_DELETE;
+
+ name->release();
+ text->release();
+ if (defchoice)
+ defchoice->release();
+ choices->release();
+}
+
+
+//
+// 'ppdcOption::find_choice()' - Find an option choice.
+//
+
+ppdcChoice * // O - Choice or NULL
+ppdcOption::find_choice(const char *n) // I - Name of choice
+{
+ ppdcChoice *c; // Current choice
+
+
+ for (c = (ppdcChoice *)choices->first(); c; c = (ppdcChoice *)choices->next())
+ if (!_cups_strcasecmp(n, c->name->value))
+ return (c);
+
+ return (0);
+}
+
+
+//
+// 'ppdcOption::set_defchoice()' - Set the default choice.
+//
+
+void
+ppdcOption::set_defchoice(ppdcChoice *c) // I - Choice
+{
+ if (defchoice)
+ defchoice->release();
+
+ if (c->name)
+ c->name->retain();
+
+ defchoice = c->name;
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-private.h b/ppdc/ppdc-private.h
new file mode 100644
index 000000000..2bf5a24e7
--- /dev/null
+++ b/ppdc/ppdc-private.h
@@ -0,0 +1,40 @@
+//
+// "$Id$"
+//
+// Private definitions for the CUPS PPD Compiler.
+//
+// Copyright 2009-2010 by Apple Inc.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+
+#ifndef _PPDC_PRIVATE_H_
+# define _PPDC_PRIVATE_H_
+
+//
+// Include necessary headers...
+//
+
+# include "ppdc.h"
+# include <cups/cups-private.h>
+
+
+//
+// Macros...
+//
+
+# define PPDC_NEW DEBUG_printf(("%s: %p new", class_name(), this))
+# define PPDC_NEWVAL(s) DEBUG_printf(("%s(\"%s\"): %p new", class_name(), s, this))
+# define PPDC_DELETE DEBUG_printf(("%s: %p delete", class_name(), this))
+# define PPDC_DELETEVAL(s) DEBUG_printf(("%s(\"%s\"): %p delete", class_name(), s, this))
+
+
+#endif // !_PPDC_PRIVATE_H_
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-profile.cxx b/ppdc/ppdc-profile.cxx
new file mode 100644
index 000000000..90625f423
--- /dev/null
+++ b/ppdc/ppdc-profile.cxx
@@ -0,0 +1,65 @@
+//
+// "$Id$"
+//
+// Color profile class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2009 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcProfile::ppdcProfile() - Create a color profile.
+// ppdcProfile::~ppdcProfile() - Destroy a color profile.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcProfile::ppdcProfile()' - Create a color profile.
+//
+
+ppdcProfile::ppdcProfile(const char *r, // I - Resolution name
+ const char *m, // I - Media type name
+ float d, // I - Density
+ float g, // I - Gamma
+ const float *p) // I - 3x3 transform matrix
+ : ppdcShared()
+{
+ PPDC_NEW;
+
+ resolution = new ppdcString(r);
+ media_type = new ppdcString(m);
+ density = d;
+ gamma = g;
+
+ memcpy(profile, p, sizeof(profile));
+}
+
+
+//
+// 'ppdcProfile::~ppdcProfile()' - Destroy a color profile.
+//
+
+ppdcProfile::~ppdcProfile()
+{
+ PPDC_DELETE;
+
+ resolution->release();
+ media_type->release();
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-shared.cxx b/ppdc/ppdc-shared.cxx
new file mode 100644
index 000000000..0c99c0859
--- /dev/null
+++ b/ppdc/ppdc-shared.cxx
@@ -0,0 +1,88 @@
+//
+// "$Id$"
+//
+// Shared data class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2009 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcShared::ppdcShared() - Create shared data.
+// ppdcShared::~ppdcShared() - Destroy shared data.
+// ppdcShared::release() - Decrement the use count and delete as needed.
+// ppdcShared::retain() - Increment the use count for this data.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcShared::ppdcShared()' - Create shared data.
+//
+
+ppdcShared::ppdcShared()
+{
+ use = 1;
+}
+
+
+//
+// 'ppdcShared::~ppdcShared()' - Destroy shared data.
+//
+
+ppdcShared::~ppdcShared()
+{
+}
+
+
+//
+// 'ppdcShared::release()' - Decrement the use count and delete as needed.
+//
+
+void
+ppdcShared::release(void)
+{
+ DEBUG_printf(("%s: %p release use=%d", class_name(), this, use));
+
+ use --;
+
+#ifdef DEBUG
+ if (use < 0)
+ {
+ fprintf(stderr, "ERROR: Over-release of %s: %p\n", class_name(), this);
+ abort();
+ }
+#endif /* DEBUG */
+
+ if (use == 0)
+ delete this;
+}
+
+
+//
+// 'ppdcShared::retain()' - Increment the use count for this data.
+//
+
+void
+ppdcShared::retain()
+{
+ use ++;
+
+ DEBUG_printf(("%s: %p retain use=%d", class_name(), this, use));
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-source.cxx b/ppdc/ppdc-source.cxx
new file mode 100644
index 000000000..43084498b
--- /dev/null
+++ b/ppdc/ppdc-source.cxx
@@ -0,0 +1,3900 @@
+//
+// "$Id$"
+//
+// Source class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2011 by Apple Inc.
+// Copyright 2002-2007 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcSource::ppdcSource() - Load a driver source file.
+// ppdcSource::~ppdcSource() - Free a driver source file.
+// ppdcSource::add_include() - Add an include directory.
+// ppdcSource::find_driver() - Find a driver.
+// ppdcSource::find_include() - Find an include file.
+// ppdcSource::find_po() - Find a message catalog for the given
+// locale...
+// ppdcSource::find_size() - Find a media size.
+// ppdcSource::find_variable() - Find a variable.
+// ppdcSource::get_attr() - Get an attribute.
+// ppdcSource::get_boolean() - Get a boolean value.
+// ppdcSource::get_choice() - Get a choice.
+// ppdcSource::get_color_model() - Get an old-style color model option.
+// ppdcSource::get_color_order() - Get an old-style color order value.
+// ppdcSource::get_color_profile() - Get a color profile definition.
+// ppdcSource::get_color_space() - Get an old-style colorspace value.
+// ppdcSource::get_constraint() - Get a constraint.
+// ppdcSource::get_custom_size() - Get a custom media size definition from
+// a file.
+// ppdcSource::get_duplex() - Get a duplex option.
+// ppdcSource::get_filter() - Get a filter.
+// ppdcSource::get_float() - Get a single floating-point number.
+// ppdcSource::get_font() - Get a font definition.
+// ppdcSource::get_generic() - Get a generic old-style option.
+// ppdcSource::get_group() - Get an option group.
+// ppdcSource::get_installable() - Get an installable option.
+// ppdcSource::get_integer() - Get an integer value from a file.
+// ppdcSource::get_measurement() - Get a measurement value.
+// ppdcSource::get_option() - Get an option definition.
+// ppdcSource::get_po() - Get a message catalog.
+// ppdcSource::get_resolution() - Get an old-style resolution option.
+// ppdcSource::get_simple_profile() - Get a simple color profile definition.
+// ppdcSource::get_size() - Get a media size definition from a file.
+// ppdcSource::get_token() - Get a token from a file.
+// ppdcSource::get_variable() - Get a variable definition.
+// ppdcSource::quotef() - Write a formatted, quoted string...
+// ppdcSource::read_file() - Read a driver source file.
+// ppdcSource::scan_file() - Scan a driver source file.
+// ppdcSource::set_variable() - Set a variable.
+// ppdcSource::write_file() - Write the current source data to a file.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+#include <limits.h>
+#include <math.h>
+#include <unistd.h>
+#include <cups/raster.h>
+#include "data/epson.h"
+#include "data/escp.h"
+#include "data/hp.h"
+#include "data/label.h"
+#include "data/pcl.h"
+#ifndef WIN32
+# include <sys/utsname.h>
+#endif // !WIN32
+
+
+//
+// Class globals...
+//
+
+ppdcArray *ppdcSource::includes = 0;
+const char *ppdcSource::driver_types[] =
+ {
+ "custom",
+ "ps",
+ "escp",
+ "pcl",
+ "label",
+ "epson",
+ "hp"
+ };
+
+
+//
+// 'ppdcSource::ppdcSource()' - Load a driver source file.
+//
+
+ppdcSource::ppdcSource(const char *f, // I - File to read
+ cups_file_t *ffp)// I - File pointer to use
+ : ppdcShared()
+{
+ PPDC_NEW;
+
+ filename = new ppdcString(f);
+ base_fonts = new ppdcArray();
+ drivers = new ppdcArray();
+ po_files = new ppdcArray();
+ sizes = new ppdcArray();
+ vars = new ppdcArray();
+ cond_state = PPDC_COND_NORMAL;
+ cond_current = cond_stack;
+ cond_stack[0] = PPDC_COND_NORMAL;
+
+ // Add standard #define variables...
+#define MAKE_STRING(x) #x
+
+ vars->add(new ppdcVariable("CUPS_VERSION", MAKE_STRING(CUPS_VERSION)));
+ vars->add(new ppdcVariable("CUPS_VERSION_MAJOR", MAKE_STRING(CUPS_VERSION_MAJOR)));
+ vars->add(new ppdcVariable("CUPS_VERSION_MINOR", MAKE_STRING(CUPS_VERSION_MINOR)));
+ vars->add(new ppdcVariable("CUPS_VERSION_PATCH", MAKE_STRING(CUPS_VERSION_PATCH)));
+
+#ifdef WIN32
+ vars->add(new ppdcVariable("PLATFORM_NAME", "Windows"));
+ vars->add(new ppdcVariable("PLATFORM_ARCH", "X86"));
+
+#else
+ struct utsname name; // uname information
+
+ if (!uname(&name))
+ {
+ vars->add(new ppdcVariable("PLATFORM_NAME", name.sysname));
+ vars->add(new ppdcVariable("PLATFORM_ARCH", name.machine));
+ }
+ else
+ {
+ vars->add(new ppdcVariable("PLATFORM_NAME", "unknown"));
+ vars->add(new ppdcVariable("PLATFORM_ARCH", "unknown"));
+ }
+#endif // WIN32
+
+ if (f)
+ read_file(f, ffp);
+}
+
+
+//
+// 'ppdcSource::~ppdcSource()' - Free a driver source file.
+//
+
+ppdcSource::~ppdcSource()
+{
+ PPDC_DELETE;
+
+ filename->release();
+ base_fonts->release();
+ drivers->release();
+ po_files->release();
+ sizes->release();
+ vars->release();
+}
+
+
+//
+// 'ppdcSource::add_include()' - Add an include directory.
+//
+
+void
+ppdcSource::add_include(const char *d) // I - Include directory
+{
+ if (!d)
+ return;
+
+ if (!includes)
+ includes = new ppdcArray();
+
+ includes->add(new ppdcString(d));
+}
+
+
+//
+// 'ppdcSource::find_driver()' - Find a driver.
+//
+
+ppdcDriver * // O - Driver
+ppdcSource::find_driver(const char *f) // I - Driver file name
+{
+ ppdcDriver *d; // Current driver
+
+
+ for (d = (ppdcDriver *)drivers->first(); d; d = (ppdcDriver *)drivers->next())
+ if (!_cups_strcasecmp(f, d->pc_file_name->value))
+ return (d);
+
+ return (NULL);
+}
+
+
+//
+// 'ppdcSource::find_include()' - Find an include file.
+//
+
+char * // O - Found path or NULL
+ppdcSource::find_include(
+ const char *f, // I - Include filename
+ const char *base, // I - Current directory
+ char *n, // I - Path buffer
+ int nlen) // I - Path buffer length
+{
+ ppdcString *dir; // Include directory
+ char temp[1024], // Temporary path
+ *ptr; // Pointer to end of path
+
+
+ // Range check input...
+ if (!f || !*f || !n || nlen < 2)
+ return (0);
+
+ // Check the first character to see if we have <name> or "name"...
+ if (*f == '<')
+ {
+ // Remove the surrounding <> from the name...
+ strlcpy(temp, f + 1, sizeof(temp));
+ ptr = temp + strlen(temp) - 1;
+
+ if (*ptr != '>')
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Invalid #include/#po filename \"%s\"."), n);
+ return (0);
+ }
+
+ *ptr = '\0';
+ f = temp;
+ }
+ else
+ {
+ // Check for the local file relative to the current directory...
+ if (base && *base && f[0] != '/')
+ snprintf(n, nlen, "%s/%s", base, f);
+ else
+ strlcpy(n, f, nlen);
+
+ if (!access(n, 0))
+ return (n);
+ else if (*f == '/')
+ {
+ // Absolute path that doesn't exist...
+ return (0);
+ }
+ }
+
+ // Search the include directories, if any...
+ if (includes)
+ {
+ for (dir = (ppdcString *)includes->first(); dir; dir = (ppdcString *)includes->next())
+ {
+ snprintf(n, nlen, "%s/%s", dir->value, f);
+ if (!access(n, 0))
+ return (n);
+ }
+ }
+
+ // Search the standard include directories...
+ _cups_globals_t *cg = _cupsGlobals(); // Global data
+
+ snprintf(n, nlen, "%s/ppdc/%s", cg->cups_datadir, f);
+ if (!access(n, 0))
+ return (n);
+
+ snprintf(n, nlen, "%s/po/%s", cg->cups_datadir, f);
+ if (!access(n, 0))
+ return (n);
+ else
+ return (0);
+}
+
+
+//
+// 'ppdcSource::find_po()' - Find a message catalog for the given locale...
+//
+
+ppdcCatalog * // O - Message catalog or NULL
+ppdcSource::find_po(const char *l) // I - Locale name
+{
+ ppdcCatalog *cat; // Current message catalog
+
+
+ for (cat = (ppdcCatalog *)po_files->first();
+ cat;
+ cat = (ppdcCatalog *)po_files->next())
+ if (!_cups_strcasecmp(l, cat->locale->value))
+ return (cat);
+
+ return (NULL);
+}
+
+
+//
+// 'ppdcSource::find_size()' - Find a media size.
+//
+
+ppdcMediaSize * // O - Size
+ppdcSource::find_size(const char *s) // I - Size name
+{
+ ppdcMediaSize *m; // Current media size
+
+
+ for (m = (ppdcMediaSize *)sizes->first(); m; m = (ppdcMediaSize *)sizes->next())
+ if (!_cups_strcasecmp(s, m->name->value))
+ return (m);
+
+ return (NULL);
+}
+
+
+//
+// 'ppdcSource::find_variable()' - Find a variable.
+//
+
+ppdcVariable * // O - Variable
+ppdcSource::find_variable(const char *n)// I - Variable name
+{
+ ppdcVariable *v; // Current variable
+
+
+ for (v = (ppdcVariable *)vars->first(); v; v = (ppdcVariable *)vars->next())
+ if (!_cups_strcasecmp(n, v->name->value))
+ return (v);
+
+ return (NULL);
+}
+
+
+//
+// 'ppdcSource::get_attr()' - Get an attribute.
+//
+
+ppdcAttr * // O - Attribute
+ppdcSource::get_attr(ppdcFile *fp, // I - File to read
+ bool loc) // I - Localize this attribute?
+{
+ char name[1024], // Name string
+ selector[1024], // Selector string
+ *text, // Text string
+ value[1024]; // Value string
+
+
+ // Get the attribute parameters:
+ //
+ // Attribute name selector value
+ if (!get_token(fp, name, sizeof(name)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected name after %s on line %d of %s."),
+ loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
+ return (0);
+ }
+
+ if (!get_token(fp, selector, sizeof(selector)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected selector after %s on line %d of %s."),
+ loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
+ return (0);
+ }
+
+ if ((text = strchr(selector, '/')) != NULL)
+ *text++ = '\0';
+
+ if (!get_token(fp, value, sizeof(value)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected value after %s on line %d of %s."),
+ loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
+ return (0);
+ }
+
+ return (new ppdcAttr(name, selector, text, value, loc));
+}
+
+
+//
+// 'ppdcSource::get_boolean()' - Get a boolean value.
+//
+
+int // O - Boolean value
+ppdcSource::get_boolean(ppdcFile *fp) // I - File to read
+{
+ char buffer[256]; // String buffer
+
+
+ if (!get_token(fp, buffer, sizeof(buffer)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected boolean value on line %d of %s."),
+ fp->line, fp->filename);
+ return (-1);
+ }
+
+ if (!_cups_strcasecmp(buffer, "on") ||
+ !_cups_strcasecmp(buffer, "yes") ||
+ !_cups_strcasecmp(buffer, "true"))
+ return (1);
+ else if (!_cups_strcasecmp(buffer, "off") ||
+ !_cups_strcasecmp(buffer, "no") ||
+ !_cups_strcasecmp(buffer, "false"))
+ return (0);
+ else
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Bad boolean value (%s) on line %d of %s."),
+ buffer, fp->line, fp->filename);
+ return (-1);
+ }
+}
+
+
+//
+// 'ppdcSource::get_choice()' - Get a choice.
+//
+
+ppdcChoice * // O - Choice data
+ppdcSource::get_choice(ppdcFile *fp) // I - File to read
+{
+ char name[1024], // Name
+ *text, // Text
+ code[10240]; // Code
+
+
+ // Read a choice from the file:
+ //
+ // Choice name/text code
+ if (!get_token(fp, name, sizeof(name)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected choice name/text on line %d of %s."),
+ fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if ((text = strchr(name, '/')) != NULL)
+ *text++ = '\0';
+ else
+ text = name;
+
+ if (!get_token(fp, code, sizeof(code)))
+ {
+ _cupsLangPrintf(stderr, _("ppdc: Expected choice code on line %d of %s."),
+ fp->line, fp->filename);
+ return (NULL);
+ }
+
+ // Return the new choice
+ return (new ppdcChoice(name, text, code));
+}
+
+
+//
+// 'ppdcSource::get_color_model()' - Get an old-style color model option.
+//
+
+ppdcChoice * // O - Choice data
+ppdcSource::get_color_model(ppdcFile *fp)
+ // I - File to read
+{
+ char name[1024], // Option name
+ *text, // Text option
+ temp[256]; // Temporary string
+ int color_space, // Colorspace
+ color_order, // Color order
+ compression; // Compression mode
+
+
+ // Get the ColorModel parameters:
+ //
+ // ColorModel name/text colorspace colororder compression
+ if (!get_token(fp, name, sizeof(name)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected name/text combination for ColorModel on "
+ "line %d of %s."), fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if ((text = strchr(name, '/')) != NULL)
+ *text++ = '\0';
+ else
+ text = name;
+
+ if (!get_token(fp, temp, sizeof(temp)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected colorspace for ColorModel on line %d of "
+ "%s."), fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if ((color_space = get_color_space(temp)) < 0)
+ color_space = get_integer(temp);
+
+ if (!get_token(fp, temp, sizeof(temp)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected color order for ColorModel on line %d of "
+ "%s."), fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if ((color_order = get_color_order(temp)) < 0)
+ color_order = get_integer(temp);
+
+ if (!get_token(fp, temp, sizeof(temp)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected compression for ColorModel on line %d of "
+ "%s."), fp->line, fp->filename);
+ return (NULL);
+ }
+
+ compression = get_integer(temp);
+
+ snprintf(temp, sizeof(temp),
+ "<</cupsColorSpace %d/cupsColorOrder %d/cupsCompression %d>>"
+ "setpagedevice",
+ color_space, color_order, compression);
+
+ return (new ppdcChoice(name, text, temp));
+}
+
+
+//
+// 'ppdcSource::get_color_order()' - Get an old-style color order value.
+//
+
+int // O - Color order value
+ppdcSource::get_color_order(
+ const char *co) // I - Color order string
+{
+ if (!_cups_strcasecmp(co, "chunked") ||
+ !_cups_strcasecmp(co, "chunky"))
+ return (CUPS_ORDER_CHUNKED);
+ else if (!_cups_strcasecmp(co, "banded"))
+ return (CUPS_ORDER_BANDED);
+ else if (!_cups_strcasecmp(co, "planar"))
+ return (CUPS_ORDER_PLANAR);
+ else
+ return (-1);
+}
+
+
+//
+// 'ppdcSource::get_color_profile()' - Get a color profile definition.
+//
+
+ppdcProfile * // O - Color profile
+ppdcSource::get_color_profile(
+ ppdcFile *fp) // I - File to read
+{
+ char resolution[1024], // Resolution/media type
+ *media_type; // Media type
+ int i; // Looping var
+ float g, // Gamma value
+ d, // Density value
+ m[9]; // Transform matrix
+
+
+ // Get the ColorProfile parameters:
+ //
+ // ColorProfile resolution/mediatype gamma density m00 m01 m02 ... m22
+ if (!get_token(fp, resolution, sizeof(resolution)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected resolution/mediatype following "
+ "ColorProfile on line %d of %s."),
+ fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if ((media_type = strchr(resolution, '/')) != NULL)
+ *media_type++ = '\0';
+ else
+ media_type = resolution;
+
+ g = get_float(fp);
+ d = get_float(fp);
+ for (i = 0; i < 9; i ++)
+ m[i] = get_float(fp);
+
+ return (new ppdcProfile(resolution, media_type, g, d, m));
+}
+
+
+//
+// 'ppdcSource::get_color_space()' - Get an old-style colorspace value.
+//
+
+int // O - Colorspace value
+ppdcSource::get_color_space(
+ const char *cs) // I - Colorspace string
+{
+ if (!_cups_strcasecmp(cs, "w"))
+ return (CUPS_CSPACE_W);
+ else if (!_cups_strcasecmp(cs, "rgb"))
+ return (CUPS_CSPACE_RGB);
+ else if (!_cups_strcasecmp(cs, "rgba"))
+ return (CUPS_CSPACE_RGBA);
+ else if (!_cups_strcasecmp(cs, "k"))
+ return (CUPS_CSPACE_K);
+ else if (!_cups_strcasecmp(cs, "cmy"))
+ return (CUPS_CSPACE_CMY);
+ else if (!_cups_strcasecmp(cs, "ymc"))
+ return (CUPS_CSPACE_YMC);
+ else if (!_cups_strcasecmp(cs, "cmyk"))
+ return (CUPS_CSPACE_CMYK);
+ else if (!_cups_strcasecmp(cs, "ymck"))
+ return (CUPS_CSPACE_YMCK);
+ else if (!_cups_strcasecmp(cs, "kcmy"))
+ return (CUPS_CSPACE_KCMY);
+ else if (!_cups_strcasecmp(cs, "kcmycm"))
+ return (CUPS_CSPACE_KCMYcm);
+ else if (!_cups_strcasecmp(cs, "gmck"))
+ return (CUPS_CSPACE_GMCK);
+ else if (!_cups_strcasecmp(cs, "gmcs"))
+ return (CUPS_CSPACE_GMCS);
+ else if (!_cups_strcasecmp(cs, "white"))
+ return (CUPS_CSPACE_WHITE);
+ else if (!_cups_strcasecmp(cs, "gold"))
+ return (CUPS_CSPACE_GOLD);
+ else if (!_cups_strcasecmp(cs, "silver"))
+ return (CUPS_CSPACE_SILVER);
+ else if (!_cups_strcasecmp(cs, "CIEXYZ"))
+ return (CUPS_CSPACE_CIEXYZ);
+ else if (!_cups_strcasecmp(cs, "CIELab"))
+ return (CUPS_CSPACE_CIELab);
+ else if (!_cups_strcasecmp(cs, "RGBW"))
+ return (CUPS_CSPACE_RGBW);
+ else if (!_cups_strcasecmp(cs, "ICC1"))
+ return (CUPS_CSPACE_ICC1);
+ else if (!_cups_strcasecmp(cs, "ICC2"))
+ return (CUPS_CSPACE_ICC2);
+ else if (!_cups_strcasecmp(cs, "ICC3"))
+ return (CUPS_CSPACE_ICC3);
+ else if (!_cups_strcasecmp(cs, "ICC4"))
+ return (CUPS_CSPACE_ICC4);
+ else if (!_cups_strcasecmp(cs, "ICC5"))
+ return (CUPS_CSPACE_ICC5);
+ else if (!_cups_strcasecmp(cs, "ICC6"))
+ return (CUPS_CSPACE_ICC6);
+ else if (!_cups_strcasecmp(cs, "ICC7"))
+ return (CUPS_CSPACE_ICC7);
+ else if (!_cups_strcasecmp(cs, "ICC8"))
+ return (CUPS_CSPACE_ICC8);
+ else if (!_cups_strcasecmp(cs, "ICC9"))
+ return (CUPS_CSPACE_ICC9);
+ else if (!_cups_strcasecmp(cs, "ICCA"))
+ return (CUPS_CSPACE_ICCA);
+ else if (!_cups_strcasecmp(cs, "ICCB"))
+ return (CUPS_CSPACE_ICCB);
+ else if (!_cups_strcasecmp(cs, "ICCC"))
+ return (CUPS_CSPACE_ICCC);
+ else if (!_cups_strcasecmp(cs, "ICCD"))
+ return (CUPS_CSPACE_ICCD);
+ else if (!_cups_strcasecmp(cs, "ICCE"))
+ return (CUPS_CSPACE_ICCE);
+ else if (!_cups_strcasecmp(cs, "ICCF"))
+ return (CUPS_CSPACE_ICCF);
+ else
+ return (-1);
+}
+
+
+//
+// 'ppdcSource::get_constraint()' - Get a constraint.
+//
+
+ppdcConstraint * // O - Constraint
+ppdcSource::get_constraint(ppdcFile *fp)// I - File to read
+{
+ char temp[1024], // One string to rule them all
+ *ptr, // Pointer into string
+ *option1, // Constraint option 1
+ *choice1, // Constraint choice 1
+ *option2, // Constraint option 2
+ *choice2; // Constraint choice 2
+
+
+ // Read the UIConstaints parameter in one of the following forms:
+ //
+ // UIConstraints "*Option1 *Option2"
+ // UIConstraints "*Option1 Choice1 *Option2"
+ // UIConstraints "*Option1 *Option2 Choice2"
+ // UIConstraints "*Option1 Choice1 *Option2 Choice2"
+ if (!get_token(fp, temp, sizeof(temp)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected constraints string for UIConstraints on "
+ "line %d of %s."), fp->line, fp->filename);
+ return (NULL);
+ }
+
+ for (ptr = temp; isspace(*ptr); ptr ++);
+
+ if (*ptr != '*')
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Option constraint must *name on line %d of %s."),
+ fp->line, fp->filename);
+ return (NULL);
+ }
+
+ option1 = ptr;
+
+ for (; *ptr && !isspace(*ptr); ptr ++);
+ for (; isspace(*ptr); *ptr++ = '\0');
+
+ if (*ptr != '*')
+ {
+ choice1 = ptr;
+
+ for (; *ptr && !isspace(*ptr); ptr ++);
+ for (; isspace(*ptr); *ptr++ = '\0');
+ }
+ else
+ choice1 = NULL;
+
+ if (*ptr != '*')
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected two option names on line %d of %s."),
+ fp->line, fp->filename);
+ return (NULL);
+ }
+
+ option2 = ptr;
+
+ for (; *ptr && !isspace(*ptr); ptr ++);
+ for (; isspace(*ptr); *ptr++ = '\0');
+
+ if (*ptr)
+ choice2 = ptr;
+ else
+ choice2 = NULL;
+
+ return (new ppdcConstraint(option1, choice1, option2, choice2));
+}
+
+
+//
+// 'ppdcSource::get_custom_size()' - Get a custom media size definition from a file.
+//
+
+ppdcMediaSize * // O - Media size
+ppdcSource::get_custom_size(ppdcFile *fp)
+ // I - File to read
+{
+ char name[1024], // Name
+ *text, // Text
+ size_code[10240], // PageSize code
+ region_code[10240]; // PageRegion
+ float width, // Width
+ length, // Length
+ left, // Left margin
+ bottom, // Bottom margin
+ right, // Right margin
+ top; // Top margin
+
+
+ // Get the name, text, width, length, margins, and code:
+ //
+ // CustomMedia name/text width length left bottom right top size-code region-code
+ if (!get_token(fp, name, sizeof(name)))
+ return (NULL);
+
+ if ((text = strchr(name, '/')) != NULL)
+ *text++ = '\0';
+ else
+ text = name;
+
+ if ((width = get_measurement(fp)) < 0.0f)
+ return (NULL);
+
+ if ((length = get_measurement(fp)) < 0.0f)
+ return (NULL);
+
+ if ((left = get_measurement(fp)) < 0.0f)
+ return (NULL);
+
+ if ((bottom = get_measurement(fp)) < 0.0f)
+ return (NULL);
+
+ if ((right = get_measurement(fp)) < 0.0f)
+ return (NULL);
+
+ if ((top = get_measurement(fp)) < 0.0f)
+ return (NULL);
+
+ if (!get_token(fp, size_code, sizeof(size_code)))
+ return (NULL);
+
+ if (!get_token(fp, region_code, sizeof(region_code)))
+ return (NULL);
+
+ // Return the new media size...
+ return (new ppdcMediaSize(name, text, width, length, left, bottom,
+ right, top, size_code, region_code));
+}
+
+
+//
+// 'ppdcSource::get_duplex()' - Get a duplex option.
+//
+
+void
+ppdcSource::get_duplex(ppdcFile *fp, // I - File to read from
+ ppdcDriver *d) // I - Current driver
+{
+ char temp[256]; // Duplex keyword
+ ppdcAttr *attr; // cupsFlipDuplex attribute
+ ppdcGroup *g; // Current group
+ ppdcOption *o; // Duplex option
+
+
+ // Duplex {boolean|none|normal|flip}
+ if (!get_token(fp, temp, sizeof(temp)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected duplex type after Duplex on line %d of "
+ "%s."), fp->line, fp->filename);
+ return;
+ }
+
+ if (cond_state)
+ return;
+
+ if (!_cups_strcasecmp(temp, "none") || !_cups_strcasecmp(temp, "false") ||
+ !_cups_strcasecmp(temp, "no") || !_cups_strcasecmp(temp, "off"))
+ {
+ g = d->find_group("General");
+ if ((o = g->find_option("Duplex")) != NULL)
+ g->options->remove(o);
+
+ for (attr = (ppdcAttr *)d->attrs->first();
+ attr;
+ attr = (ppdcAttr *)d->attrs->next())
+ if (!strcmp(attr->name->value, "cupsFlipDuplex"))
+ {
+ d->attrs->remove(attr);
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "normal") || !_cups_strcasecmp(temp, "true") ||
+ !_cups_strcasecmp(temp, "yes") || !_cups_strcasecmp(temp, "on") ||
+ !_cups_strcasecmp(temp, "flip") || !_cups_strcasecmp(temp, "rotated") ||
+ !_cups_strcasecmp(temp, "manualtumble"))
+ {
+ g = d->find_group("General");
+ o = g->find_option("Duplex");
+
+ if (!o)
+ {
+ o = new ppdcOption(PPDC_PICKONE, "Duplex", "2-Sided Printing",
+ !_cups_strcasecmp(temp, "flip") ? PPDC_SECTION_PAGE :
+ PPDC_SECTION_ANY, 10.0f);
+ o->add_choice(new ppdcChoice("None", "Off (1-Sided)",
+ "<</Duplex false>>setpagedevice"));
+ o->add_choice(new ppdcChoice("DuplexNoTumble", "Long-Edge (Portrait)",
+ "<</Duplex true/Tumble false>>setpagedevice"));
+ o->add_choice(new ppdcChoice("DuplexTumble", "Short-Edge (Landscape)",
+ "<</Duplex true/Tumble true>>setpagedevice"));
+
+ g->add_option(o);
+ }
+
+ for (attr = (ppdcAttr *)d->attrs->first();
+ attr;
+ attr = (ppdcAttr *)d->attrs->next())
+ if (!strcmp(attr->name->value, "cupsFlipDuplex"))
+ {
+ if (_cups_strcasecmp(temp, "flip"))
+ d->attrs->remove(attr);
+ break;
+ }
+
+ if (!_cups_strcasecmp(temp, "flip") && !attr)
+ d->add_attr(new ppdcAttr("cupsFlipDuplex", NULL, NULL, "true"));
+
+ for (attr = (ppdcAttr *)d->attrs->first();
+ attr;
+ attr = (ppdcAttr *)d->attrs->next())
+ if (!strcmp(attr->name->value, "cupsBackSide"))
+ {
+ d->attrs->remove(attr);
+ break;
+ }
+
+ if (!_cups_strcasecmp(temp, "flip"))
+ d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "Flipped"));
+ else if (!_cups_strcasecmp(temp, "rotated"))
+ d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "Rotated"));
+ else if (!_cups_strcasecmp(temp, "manualtumble"))
+ d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "ManualTumble"));
+ else
+ d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "Normal"));
+ }
+ else
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unknown duplex type \"%s\" on line %d of %s."),
+ temp, fp->line, fp->filename);
+}
+
+
+//
+// 'ppdcSource::get_filter()' - Get a filter.
+//
+
+ppdcFilter * // O - Filter
+ppdcSource::get_filter(ppdcFile *fp) // I - File to read
+{
+ char type[1024], // MIME type
+ program[1024], // Filter program
+ *ptr; // Pointer into MIME type
+ int cost; // Relative cost
+
+
+ // Read filter parameters in one of the following formats:
+ //
+ // Filter "type cost program"
+ // Filter type cost program
+
+ if (!get_token(fp, type, sizeof(type)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected a filter definition on line %d of %s."),
+ fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if ((ptr = strchr(type, ' ')) != NULL)
+ {
+ // Old-style filter definition in one string...
+ *ptr++ = '\0';
+ cost = strtol(ptr, &ptr, 10);
+
+ while (isspace(*ptr))
+ ptr ++;
+
+ strcpy(program, ptr);
+ }
+ else
+ {
+ cost = get_integer(fp);
+
+ if (!get_token(fp, program, sizeof(program)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected a program name on line %d of %s."),
+ fp->line, fp->filename);
+ return (NULL);
+ }
+ }
+
+ if (!type[0])
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Invalid empty MIME type for filter on line %d of "
+ "%s."), fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if (cost < 0 || cost > 200)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Invalid cost for filter on line %d of %s."),
+ fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if (!program[0])
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Invalid empty program name for filter on line %d "
+ "of %s."), fp->line, fp->filename);
+ return (NULL);
+ }
+
+ return (new ppdcFilter(type, program, cost));
+}
+
+
+//
+// 'ppdcSource::get_float()' - Get a single floating-point number.
+//
+
+float // O - Number
+ppdcSource::get_float(ppdcFile *fp) // I - File to read
+{
+ char temp[256], // String buffer
+ *ptr; // Pointer into buffer
+ float val; // Floating point value
+
+
+ // Get the number from the file and range-check...
+ if (!get_token(fp, temp, sizeof(temp)))
+ {
+ _cupsLangPrintf(stderr, _("ppdc: Expected real number on line %d of %s."),
+ fp->line, fp->filename);
+ return (-1.0f);
+ }
+
+ val = (float)strtod(temp, &ptr);
+
+ if (*ptr)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unknown trailing characters in real number \"%s\" "
+ "on line %d of %s."), temp, fp->line, fp->filename);
+ return (-1.0f);
+ }
+ else
+ return (val);
+}
+
+
+//
+// 'ppdcSource::get_font()' - Get a font definition.
+//
+
+ppdcFont * // O - Font data
+ppdcSource::get_font(ppdcFile *fp) // I - File to read
+{
+ char name[256], // Font name
+ encoding[256], // Font encoding
+ version[256], // Font version
+ charset[256], // Font charset
+ temp[256]; // Font status string
+ ppdcFontStatus status; // Font status enumeration
+
+
+ // Read font parameters as follows:
+ //
+ // Font *
+ // Font name encoding version charset status
+ // %font name encoding version charset status
+ //
+ // "Name" is the PostScript font name.
+ //
+ // "Encoding" is the default encoding of the font: Standard, ISOLatin1,
+ // Special, Expert, ExpertSubset, etc.
+ //
+ // "Version" is the version number string.
+ //
+ // "Charset" specifies the characters that are included in the font:
+ // Standard, Special, Expert, Adobe-Identity, etc.
+ //
+ // "Status" is the keyword ROM or Disk.
+ if (!get_token(fp, name, sizeof(name)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected name after Font on line %d of %s."),
+ fp->line, fp->filename);
+ return (0);
+ }
+
+ if (!strcmp(name, "*"))
+ {
+ // Include all base fonts...
+ encoding[0] = '\0';
+ version[0] = '\0';
+ charset[0] = '\0';
+ status = PPDC_FONT_ROM;
+ }
+ else
+ {
+ // Load a full font definition...
+ if (!get_token(fp, encoding, sizeof(encoding)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected encoding after Font on line %d of "
+ "%s."), fp->line, fp->filename);
+ return (0);
+ }
+
+ if (!get_token(fp, version, sizeof(version)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected version after Font on line %d of "
+ "%s."), fp->line, fp->filename);
+ return (0);
+ }
+
+ if (!get_token(fp, charset, sizeof(charset)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected charset after Font on line %d of "
+ "%s."), fp->line, fp->filename);
+ return (0);
+ }
+
+ if (!get_token(fp, temp, sizeof(temp)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected status after Font on line %d of %s."),
+ fp->line, fp->filename);
+ return (0);
+ }
+
+ if (!_cups_strcasecmp(temp, "ROM"))
+ status = PPDC_FONT_ROM;
+ else if (!_cups_strcasecmp(temp, "Disk"))
+ status = PPDC_FONT_DISK;
+ else
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Bad status keyword %s on line %d of %s."),
+ temp, fp->line, fp->filename);
+ return (0);
+ }
+ }
+
+// printf("Font %s %s %s %s %s\n", name, encoding, version, charset, temp);
+
+ return (new ppdcFont(name, encoding, version, charset, status));
+}
+
+
+//
+// 'ppdcSource::get_generic()' - Get a generic old-style option.
+//
+
+ppdcChoice * // O - Choice data
+ppdcSource::get_generic(ppdcFile *fp, // I - File to read
+ const char *keyword,
+ // I - Keyword name
+ const char *tattr,
+ // I - Text attribute
+ const char *nattr)
+ // I - Numeric attribute
+{
+ char name[1024], // Name
+ *text, // Text
+ command[256]; // Command string
+ int val; // Numeric value
+
+
+ // Read one of the following parameters:
+ //
+ // Foo name/text
+ // Foo integer name/text
+ if (nattr)
+ val = get_integer(fp);
+ else
+ val = 0;
+
+ if (!get_token(fp, name, sizeof(name)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected name/text after %s on line %d of %s."),
+ keyword, fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if ((text = strchr(name, '/')) != NULL)
+ *text++ = '\0';
+ else
+ text = name;
+
+ if (nattr)
+ {
+ if (tattr)
+ snprintf(command, sizeof(command),
+ "<</%s(%s)/%s %d>>setpagedevice",
+ tattr, name, nattr, val);
+ else
+ snprintf(command, sizeof(command),
+ "<</%s %d>>setpagedevice",
+ nattr, val);
+ }
+ else
+ snprintf(command, sizeof(command),
+ "<</%s(%s)>>setpagedevice",
+ tattr, name);
+
+ return (new ppdcChoice(name, text, command));
+}
+
+
+//
+// 'ppdcSource::get_group()' - Get an option group.
+//
+
+ppdcGroup * // O - Group
+ppdcSource::get_group(ppdcFile *fp, // I - File to read
+ ppdcDriver *d) // I - Printer driver
+{
+ char name[1024], // UI name
+ *text; // UI text
+ ppdcGroup *g; // Group
+
+
+ // Read the Group parameters:
+ //
+ // Group name/text
+ if (!get_token(fp, name, sizeof(name)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected group name/text on line %d of %s."),
+ fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if ((text = strchr(name, '/')) != NULL)
+ *text++ = '\0';
+ else
+ text = name;
+
+ // See if the group already exists...
+ if ((g = d->find_group(name)) == NULL)
+ {
+ // Nope, add a new one...
+ g = new ppdcGroup(name, text);
+ }
+
+ return (g);
+}
+
+
+//
+// 'ppdcSource::get_installable()' - Get an installable option.
+//
+
+ppdcOption * // O - Option
+ppdcSource::get_installable(ppdcFile *fp)
+ // I - File to read
+{
+ char name[1024], // Name for installable option
+ *text; // Text for installable option
+ ppdcOption *o; // Option
+
+
+ // Read the parameter for an installable option:
+ //
+ // Installable name/text
+ if (!get_token(fp, name, sizeof(name)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected name/text after Installable on line %d "
+ "of %s."), fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if ((text = strchr(name, '/')) != NULL)
+ *text++ = '\0';
+ else
+ text = name;
+
+ // Create the option...
+ o = new ppdcOption(PPDC_BOOLEAN, name, text, PPDC_SECTION_ANY, 10.0f);
+
+ // Add the false and true choices...
+ o->add_choice(new ppdcChoice("False", "Not Installed", ""));
+ o->add_choice(new ppdcChoice("True", "Installed", ""));
+
+ return (o);
+}
+
+
+//
+// 'ppdcSource::get_integer()' - Get an integer value from a string.
+//
+
+#define PPDC_XX -1 // Bad
+#define PPDC_EQ 0 // ==
+#define PPDC_NE 1 // !=
+#define PPDC_LT 2 // <
+#define PPDC_LE 3 // <=
+#define PPDC_GT 4 // >
+#define PPDC_GE 5 // >=
+
+int // O - Integer value
+ppdcSource::get_integer(const char *v) // I - Value string
+{
+ long val; // Value
+ long temp, // Temporary value
+ temp2; // Second temporary value
+ char *newv, // New value string pointer
+ ch; // Temporary character
+ ppdcVariable *var; // #define variable
+ int compop; // Comparison operator
+
+
+ // Parse the value string...
+ if (!v)
+ return (-1);
+
+ if (isdigit(*v & 255) || *v == '-' || *v == '+')
+ {
+ // Return a simple integer value
+ val = strtol(v, (char **)&v, 0);
+ if (*v || val == LONG_MIN)
+ return (-1);
+ else
+ return ((int)val);
+ }
+ else if (*v == '(')
+ {
+ // Evaluate and expression in any of the following formats:
+ //
+ // (number number ... number) Bitwise OR of all numbers
+ // (NAME == value) 1 if equal, 0 otherwise
+ // (NAME != value) 1 if not equal, 0 otherwise
+ // (NAME < value) 1 if less than, 0 otherwise
+ // (NAME <= value) 1 if less than or equal, 0 otherwise
+ // (NAME > value) 1 if greater than, 0 otherwise
+ // (NAME >= value) 1 if greater than or equal, 0 otherwise
+
+ v ++;
+ val = 0;
+
+ while (*v && *v != ')')
+ {
+ // Skip leading whitespace...
+ while (*v && isspace(*v & 255))
+ v ++;
+
+ if (!*v || *v == ')')
+ break;
+
+ if (isdigit(*v & 255) || *v == '-' || *v == '+')
+ {
+ // Bitwise OR a number...
+ temp = strtol(v, &newv, 0);
+
+ if (!*newv || newv == v || !(isspace(*newv) || *newv == ')') ||
+ temp == LONG_MIN)
+ return (-1);
+ }
+ else
+ {
+ // NAME logicop value
+ for (newv = (char *)v + 1;
+ *newv && (isalnum(*newv & 255) || *newv == '_');
+ newv ++);
+
+ ch = *newv;
+ *newv = '\0';
+
+ if ((var = find_variable(v)) != NULL)
+ {
+ if (!var->value || !var->value->value || !var->value->value[0])
+ temp = 0;
+ else if (isdigit(var->value->value[0] & 255) ||
+ var->value->value[0] == '-' ||
+ var->value->value[0] == '+')
+ temp = strtol(var->value->value, NULL, 0);
+ else
+ temp = 1;
+ }
+ else
+ temp = 0;
+
+ *newv = ch;
+ while (isspace(*newv & 255))
+ newv ++;
+
+ if (!strncmp(newv, "==", 2))
+ {
+ compop = PPDC_EQ;
+ newv += 2;
+ }
+ else if (!strncmp(newv, "!=", 2))
+ {
+ compop = PPDC_NE;
+ newv += 2;
+ }
+ else if (!strncmp(newv, "<=", 2))
+ {
+ compop = PPDC_LE;
+ newv += 2;
+ }
+ else if (*newv == '<')
+ {
+ compop = PPDC_LT;
+ newv ++;
+ }
+ else if (!strncmp(newv, ">=", 2))
+ {
+ compop = PPDC_GE;
+ newv += 2;
+ }
+ else if (*newv == '>')
+ {
+ compop = PPDC_GT;
+ newv ++;
+ }
+ else
+ compop = PPDC_XX;
+
+ if (compop != PPDC_XX)
+ {
+ while (isspace(*newv & 255))
+ newv ++;
+
+ if (*newv == ')' || !*newv)
+ return (-1);
+
+ if (isdigit(*newv & 255) || *newv == '-' || *newv == '+')
+ {
+ // Get the second number...
+ temp2 = strtol(newv, &newv, 0);
+ if (!*newv || newv == v || !(isspace(*newv) || *newv == ')') ||
+ temp == LONG_MIN)
+ return (-1);
+ }
+ else
+ {
+ // Lookup the second name...
+ for (v = newv, newv ++;
+ *newv && (isalnum(*newv & 255) || *newv == '_');
+ newv ++);
+
+ ch = *newv;
+ *newv = '\0';
+
+ if ((var = find_variable(v)) != NULL)
+ {
+ if (!var->value || !var->value->value || !var->value->value[0])
+ temp2 = 0;
+ else if (isdigit(var->value->value[0] & 255) ||
+ var->value->value[0] == '-' ||
+ var->value->value[0] == '+')
+ temp2 = strtol(var->value->value, NULL, 0);
+ else
+ temp2 = 1;
+ }
+ else
+ temp2 = 0;
+
+ *newv = ch;
+ }
+
+ // Do the comparison...
+ switch (compop)
+ {
+ case PPDC_EQ :
+ temp = temp == temp2;
+ break;
+ case PPDC_NE :
+ temp = temp != temp2;
+ break;
+ case PPDC_LT :
+ temp = temp < temp2;
+ break;
+ case PPDC_LE :
+ temp = temp <= temp2;
+ break;
+ case PPDC_GT :
+ temp = temp > temp2;
+ break;
+ case PPDC_GE :
+ temp = temp >= temp2;
+ break;
+ }
+ }
+ }
+
+ val |= temp;
+ v = newv;
+ }
+
+ if (*v == ')' && !v[1])
+ return ((int)val);
+ else
+ return (-1);
+ }
+ else if ((var = find_variable(v)) != NULL)
+ {
+ // NAME by itself returns 1 if the #define variable is not blank and
+ // not "0"...
+ return (var->value->value && var->value->value[0] &&
+ strcmp(var->value->value, "0"));
+ }
+ else
+ {
+ // Anything else is an error...
+ return (-1);
+ }
+}
+
+
+//
+// 'ppdcSource::get_integer()' - Get an integer value from a file.
+//
+
+int // O - Integer value
+ppdcSource::get_integer(ppdcFile *fp) // I - File to read
+{
+ char temp[1024]; // String buffer
+
+
+ if (!get_token(fp, temp, sizeof(temp)))
+ {
+ _cupsLangPrintf(stderr, _("ppdc: Expected integer on line %d of %s."),
+ fp->line, fp->filename);
+ return (-1);
+ }
+ else
+ return (get_integer(temp));
+}
+
+
+//
+// 'ppdcSource::get_measurement()' - Get a measurement value.
+//
+
+float // O - Measurement value in points
+ppdcSource::get_measurement(ppdcFile *fp)
+ // I - File to read
+{
+ char buffer[256], // Number buffer
+ *ptr; // Pointer into buffer
+ float val; // Measurement value
+
+
+ // Grab a token from the file...
+ if (!get_token(fp, buffer, sizeof(buffer)))
+ return (-1.0f);
+
+ // Get the floating point value of "s" and skip all digits and decimal points.
+ val = (float)strtod(buffer, &ptr);
+
+ // Check for a trailing unit specifier...
+ if (!_cups_strcasecmp(ptr, "mm"))
+ val *= 72.0f / 25.4f;
+ else if (!_cups_strcasecmp(ptr, "cm"))
+ val *= 72.0f / 2.54f;
+ else if (!_cups_strcasecmp(ptr, "m"))
+ val *= 72.0f / 0.0254f;
+ else if (!_cups_strcasecmp(ptr, "in"))
+ val *= 72.0f;
+ else if (!_cups_strcasecmp(ptr, "ft"))
+ val *= 72.0f * 12.0f;
+ else if (_cups_strcasecmp(ptr, "pt") && *ptr)
+ return (-1.0f);
+
+ return (val);
+}
+
+
+//
+// 'ppdcSource::get_option()' - Get an option definition.
+//
+
+ppdcOption * // O - Option
+ppdcSource::get_option(ppdcFile *fp, // I - File to read
+ ppdcDriver *d, // I - Printer driver
+ ppdcGroup *g) // I - Current group
+{
+ char name[1024], // UI name
+ *text, // UI text
+ type[256]; // UI type string
+ ppdcOptType ot; // Option type value
+ ppdcOptSection section; // Option section
+ float order; // Option order
+ ppdcOption *o; // Option
+ ppdcGroup *mg; // Matching group, if any
+
+
+ // Read the Option parameters:
+ //
+ // Option name/text type section order
+ if (!get_token(fp, name, sizeof(name)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected option name/text on line %d of %s."),
+ fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if ((text = strchr(name, '/')) != NULL)
+ *text++ = '\0';
+ else
+ text = name;
+
+ if (!get_token(fp, type, sizeof(type)))
+ {
+ _cupsLangPrintf(stderr, _("ppdc: Expected option type on line %d of %s."),
+ fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if (!_cups_strcasecmp(type, "boolean"))
+ ot = PPDC_BOOLEAN;
+ else if (!_cups_strcasecmp(type, "pickone"))
+ ot = PPDC_PICKONE;
+ else if (!_cups_strcasecmp(type, "pickmany"))
+ ot = PPDC_PICKMANY;
+ else
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Invalid option type \"%s\" on line %d of %s."),
+ type, fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if (!get_token(fp, type, sizeof(type)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected option section on line %d of %s."),
+ fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if (!_cups_strcasecmp(type, "AnySetup"))
+ section = PPDC_SECTION_ANY;
+ else if (!_cups_strcasecmp(type, "DocumentSetup"))
+ section = PPDC_SECTION_DOCUMENT;
+ else if (!_cups_strcasecmp(type, "ExitServer"))
+ section = PPDC_SECTION_EXIT;
+ else if (!_cups_strcasecmp(type, "JCLSetup"))
+ section = PPDC_SECTION_JCL;
+ else if (!_cups_strcasecmp(type, "PageSetup"))
+ section = PPDC_SECTION_PAGE;
+ else if (!_cups_strcasecmp(type, "Prolog"))
+ section = PPDC_SECTION_PROLOG;
+ else
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Invalid option section \"%s\" on line %d of "
+ "%s."), type, fp->line, fp->filename);
+ return (NULL);
+ }
+
+ order = get_float(fp);
+
+ // See if the option already exists...
+ if ((o = d->find_option_group(name, &mg)) == NULL)
+ {
+ // Nope, add a new one...
+ o = new ppdcOption(ot, name, text, section, order);
+ }
+ else if (o->type != ot)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Option %s redefined with a different type on line "
+ "%d of %s."), name, fp->line, fp->filename);
+ return (NULL);
+ }
+ else if (g != mg)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Option %s defined in two different groups on line "
+ "%d of %s."), name, fp->line, fp->filename);
+ return (NULL);
+ }
+
+ return (o);
+}
+
+
+//
+// 'ppdcSource::get_po()' - Get a message catalog.
+//
+
+ppdcCatalog * // O - Message catalog
+ppdcSource::get_po(ppdcFile *fp) // I - File to read
+{
+ char locale[32], // Locale name
+ poname[1024], // Message catalog filename
+ basedir[1024], // Base directory
+ *baseptr, // Pointer into directory
+ pofilename[1024]; // Full filename of message catalog
+ ppdcCatalog *cat; // Message catalog
+
+
+ // Read the #po parameters:
+ //
+ // #po locale "filename.po"
+ if (!get_token(fp, locale, sizeof(locale)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected locale after #po on line %d of %s."),
+ fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if (!get_token(fp, poname, sizeof(poname)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected filename after #po %s on line %d of "
+ "%s."), locale, fp->line, fp->filename);
+ return (NULL);
+ }
+
+ // See if the locale is already loaded...
+ if (find_po(locale))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Duplicate #po for locale %s on line %d of %s."),
+ locale, fp->line, fp->filename);
+ return (NULL);
+ }
+
+ // Figure out the current directory...
+ strlcpy(basedir, fp->filename, sizeof(basedir));
+
+ if ((baseptr = strrchr(basedir, '/')) != NULL)
+ *baseptr = '\0';
+ else
+ strcpy(basedir, ".");
+
+ // Find the po file...
+ pofilename[0] = '\0';
+
+ if (!poname[0] ||
+ find_include(poname, basedir, pofilename, sizeof(pofilename)))
+ {
+ // Found it, so load it...
+ cat = new ppdcCatalog(locale, pofilename);
+
+ // Reset the filename to the name supplied by the user...
+ cat->filename->release();
+ cat->filename = new ppdcString(poname);
+
+ // Return the catalog...
+ return (cat);
+ }
+ else
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unable to find #po file %s on line %d of %s."),
+ poname, fp->line, fp->filename);
+ return (NULL);
+ }
+}
+
+
+//
+// 'ppdcSource::get_resolution()' - Get an old-style resolution option.
+//
+
+ppdcChoice * // O - Choice data
+ppdcSource::get_resolution(ppdcFile *fp)// I - File to read
+{
+ char name[1024], // Name
+ *text, // Text
+ temp[256], // Temporary string
+ command[256], // Command string
+ *commptr; // Pointer into command
+ int xdpi, ydpi, // X + Y resolution
+ color_order, // Color order
+ color_space, // Colorspace
+ compression, // Compression mode
+ depth, // Bits per color
+ row_count, // Row count
+ row_feed, // Row feed
+ row_step; // Row step/interval
+
+
+ // Read the resolution parameters:
+ //
+ // Resolution colorspace bits row-count row-feed row-step name/text
+ if (!get_token(fp, temp, sizeof(temp)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected override field after Resolution on line "
+ "%d of %s."), fp->line, fp->filename);
+ return (NULL);
+ }
+
+ color_order = get_color_order(temp);
+ color_space = get_color_space(temp);
+ compression = get_integer(temp);
+
+ depth = get_integer(fp);
+ row_count = get_integer(fp);
+ row_feed = get_integer(fp);
+ row_step = get_integer(fp);
+
+ if (!get_token(fp, name, sizeof(name)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected name/text after Resolution on line %d of "
+ "%s."), fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if ((text = strchr(name, '/')) != NULL)
+ *text++ = '\0';
+ else
+ text = name;
+
+ switch (sscanf(name, "%dx%d", &xdpi, &ydpi))
+ {
+ case 0 :
+ _cupsLangPrintf(stderr,
+ _("ppdc: Bad resolution name \"%s\" on line %d of "
+ "%s."), name, fp->line, fp->filename);
+ break;
+ case 1 :
+ ydpi = xdpi;
+ break;
+ }
+
+ // Create the necessary PS commands...
+ snprintf(command, sizeof(command),
+ "<</HWResolution[%d %d]/cupsBitsPerColor %d/cupsRowCount %d"
+ "/cupsRowFeed %d/cupsRowStep %d",
+ xdpi, ydpi, depth, row_count, row_feed, row_step);
+ commptr = command + strlen(command);
+
+ if (color_order >= 0)
+ {
+ snprintf(commptr, sizeof(command) - (commptr - command),
+ "/cupsColorOrder %d", color_order);
+ commptr += strlen(commptr);
+ }
+
+ if (color_space >= 0)
+ {
+ snprintf(commptr, sizeof(command) - (commptr - command),
+ "/cupsColorSpace %d", color_space);
+ commptr += strlen(commptr);
+ }
+
+ if (compression >= 0)
+ {
+ snprintf(commptr, sizeof(command) - (commptr - command),
+ "/cupsCompression %d", compression);
+ commptr += strlen(commptr);
+ }
+
+ snprintf(commptr, sizeof(command) - (commptr - command), ">>setpagedevice");
+
+ // Return the new choice...
+ return (new ppdcChoice(name, text, command));
+}
+
+
+//
+// 'ppdcSource::get_simple_profile()' - Get a simple color profile definition.
+//
+
+ppdcProfile * // O - Color profile
+ppdcSource::get_simple_profile(ppdcFile *fp)
+ // I - File to read
+{
+ char resolution[1024], // Resolution/media type
+ *media_type; // Media type
+ float m[9]; // Transform matrix
+ float kd, rd, g; // Densities and gamma
+ float red, green, blue; // RGB adjustments
+ float yellow; // Yellow density
+ float color; // Color density values
+
+
+ // Get the SimpleColorProfile parameters:
+ //
+ // SimpleColorProfile resolution/mediatype black-density yellow-density
+ // red-density gamma red-adjust green-adjust blue-adjust
+ if (!get_token(fp, resolution, sizeof(resolution)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected resolution/mediatype following "
+ "SimpleColorProfile on line %d of %s."),
+ fp->line, fp->filename);
+ return (NULL);
+ }
+
+ if ((media_type = strchr(resolution, '/')) != NULL)
+ *media_type++ = '\0';
+ else
+ media_type = resolution;
+
+ // Collect the profile parameters...
+ kd = get_float(fp);
+ yellow = get_float(fp);
+ rd = get_float(fp);
+ g = get_float(fp);
+ red = get_float(fp);
+ green = get_float(fp);
+ blue = get_float(fp);
+
+ // Build the color profile...
+ color = 0.5f * rd / kd - kd;
+ m[0] = 1.0f; // C
+ m[1] = color + blue; // C + M (blue)
+ m[2] = color - green; // C + Y (green)
+ m[3] = color - blue; // M + C (blue)
+ m[4] = 1.0f; // M
+ m[5] = color + red; // M + Y (red)
+ m[6] = yellow * (color + green); // Y + C (green)
+ m[7] = yellow * (color - red); // Y + M (red)
+ m[8] = yellow; // Y
+
+ if (m[1] > 0.0f)
+ {
+ m[3] -= m[1];
+ m[1] = 0.0f;
+ }
+ else if (m[3] > 0.0f)
+ {
+ m[1] -= m[3];
+ m[3] = 0.0f;
+ }
+
+ if (m[2] > 0.0f)
+ {
+ m[6] -= m[2];
+ m[2] = 0.0f;
+ }
+ else if (m[6] > 0.0f)
+ {
+ m[2] -= m[6];
+ m[6] = 0.0f;
+ }
+
+ if (m[5] > 0.0f)
+ {
+ m[7] -= m[5];
+ m[5] = 0.0f;
+ }
+ else if (m[7] > 0.0f)
+ {
+ m[5] -= m[7];
+ m[7] = 0.0f;
+ }
+
+ // Return the new profile...
+ return (new ppdcProfile(resolution, media_type, g, kd, m));
+}
+
+
+//
+// 'ppdcSource::get_size()' - Get a media size definition from a file.
+//
+
+ppdcMediaSize * // O - Media size
+ppdcSource::get_size(ppdcFile *fp) // I - File to read
+{
+ char name[1024], // Name
+ *text; // Text
+ float width, // Width
+ length; // Length
+
+
+ // Get the name, text, width, and length:
+ //
+ // #media name/text width length
+ if (!get_token(fp, name, sizeof(name)))
+ return (NULL);
+
+ if ((text = strchr(name, '/')) != NULL)
+ *text++ = '\0';
+ else
+ text = name;
+
+ if ((width = get_measurement(fp)) < 0.0f)
+ return (NULL);
+
+ if ((length = get_measurement(fp)) < 0.0f)
+ return (NULL);
+
+ // Return the new media size...
+ return (new ppdcMediaSize(name, text, width, length, 0.0f, 0.0f, 0.0f, 0.0f));
+}
+
+
+//
+// 'ppdcSource::get_token()' - Get a token from a file.
+//
+
+char * // O - Token string or NULL
+ppdcSource::get_token(ppdcFile *fp, // I - File to read
+ char *buffer, // I - Buffer
+ int buflen) // I - Length of buffer
+{
+ char *bufptr, // Pointer into string buffer
+ *bufend; // End of string buffer
+ int ch, // Character from file
+ nextch, // Next char in file
+ quote, // Quote character used...
+ empty, // Empty input?
+ startline; // Start line for quote
+ char name[256], // Name string
+ *nameptr; // Name pointer
+ ppdcVariable *var; // Variable pointer
+
+
+ // Mark the beginning and end of the buffer...
+ bufptr = buffer;
+ bufend = buffer + buflen - 1;
+
+ // Loop intil we've read a token...
+ quote = 0;
+ startline = 0;
+ empty = 1;
+
+ while ((ch = fp->get()) != EOF)
+ {
+ if (isspace(ch) && !quote)
+ {
+ if (empty)
+ continue;
+ else
+ break;
+ }
+ else if (ch == '$')
+ {
+ // Variable substitution
+ empty = 0;
+
+ for (nameptr = name; (ch = fp->peek()) != EOF;)
+ {
+ if (!isalnum(ch) && ch != '_')
+ break;
+ else if (nameptr < (name + sizeof(name) - 1))
+ *nameptr++ = fp->get();
+ }
+
+ if (nameptr == name)
+ {
+ // Just substitute this character...
+ if (ch == '$')
+ {
+ // $$ = $
+ if (bufptr < bufend)
+ *bufptr++ = fp->get();
+ }
+ else
+ {
+ // $ch = $ch
+ _cupsLangPrintf(stderr,
+ _("ppdc: Bad variable substitution ($%c) on line %d "
+ "of %s."), ch, fp->line, fp->filename);
+
+ if (bufptr < bufend)
+ *bufptr++ = '$';
+ }
+ }
+ else
+ {
+ // Substitute the variable value...
+ *nameptr = '\0';
+ var = find_variable(name);
+ if (var)
+ {
+ strlcpy(bufptr, var->value->value, bufend - bufptr + 1);
+ bufptr += strlen(bufptr);
+ }
+ else
+ {
+ if (!(cond_state & PPDC_COND_SKIP))
+ _cupsLangPrintf(stderr,
+ _("ppdc: Undefined variable (%s) on line %d of "
+ "%s."), name, fp->line, fp->filename);
+
+ snprintf(bufptr, bufend - bufptr + 1, "$%s", name);
+ bufptr += strlen(bufptr);
+ }
+ }
+ }
+ else if (ch == '/' && !quote)
+ {
+ // Possibly a comment...
+ nextch = fp->peek();
+
+ if (nextch == '*')
+ {
+ // C comment...
+ fp->get();
+ ch = fp->get();
+ while ((nextch = fp->get()) != EOF)
+ {
+ if (ch == '*' && nextch == '/')
+ break;
+
+ ch = nextch;
+ }
+
+ if (nextch == EOF)
+ break;
+ }
+ else if (nextch == '/')
+ {
+ // C++ comment...
+ while ((nextch = fp->get()) != EOF)
+ if (nextch == '\n')
+ break;
+
+ if (nextch == EOF)
+ break;
+ }
+ else
+ {
+ // Not a comment...
+ empty = 0;
+
+ if (bufptr < bufend)
+ *bufptr++ = ch;
+ }
+ }
+ else if (ch == '\'' || ch == '\"')
+ {
+ empty = 0;
+
+ if (quote == ch)
+ {
+ // Ending the current quoted string...
+ quote = 0;
+ }
+ else if (quote)
+ {
+ // Insert the opposing quote char...
+ if (bufptr < bufend)
+ *bufptr++ = ch;
+ }
+ else
+ {
+ // Start a new quoted string...
+ startline = fp->line;
+ quote = ch;
+ }
+ }
+ else if ((ch == '(' || ch == '<') && !quote)
+ {
+ empty = 0;
+ quote = ch;
+ startline = fp->line;
+
+ if (bufptr < bufend)
+ *bufptr++ = ch;
+ }
+ else if ((ch == ')' && quote == '(') || (ch == '>' && quote == '<'))
+ {
+ quote = 0;
+
+ if (bufptr < bufend)
+ *bufptr++ = ch;
+ }
+ else if (ch == '\\')
+ {
+ empty = 0;
+
+ if ((ch = fp->get()) == EOF)
+ break;
+
+ if (bufptr < bufend)
+ *bufptr++ = ch;
+ }
+ else if (bufptr < bufend)
+ {
+ empty = 0;
+
+ *bufptr++ = ch;
+
+ if ((ch == '{' || ch == '}') && !quote)
+ break;
+ }
+ }
+
+ if (quote)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unterminated string starting with %c on line %d "
+ "of %s."), quote, startline, fp->filename);
+ return (NULL);
+ }
+
+ if (empty)
+ return (NULL);
+ else
+ {
+ *bufptr = '\0';
+// puts(buffer);
+ return (buffer);
+ }
+}
+
+
+//
+// 'ppdcSource::get_variable()' - Get a variable definition.
+//
+
+ppdcVariable * // O - Variable
+ppdcSource::get_variable(ppdcFile *fp) // I - File to read
+{
+ char name[1024], // Name
+ value[1024]; // Value
+
+
+ // Get the name and value:
+ //
+ // #define name value
+ if (!get_token(fp, name, sizeof(name)))
+ return (NULL);
+
+ if (!get_token(fp, value, sizeof(value)))
+ return (NULL);
+
+ // Set the variable...
+ return (set_variable(name, value));
+}
+
+
+//
+// 'ppdcSource::quotef()' - Write a formatted, quoted string...
+//
+
+int // O - Number bytes on success, -1 on failure
+ppdcSource::quotef(cups_file_t *fp, // I - File to write to
+ const char *format, // I - Printf-style format string
+ ...) // I - Additional args as needed
+{
+ va_list ap; // Pointer to additional arguments
+ int bytes; // Bytes written
+ char sign, // Sign of format width
+ size, // Size character (h, l, L)
+ type; // Format type character
+ const char *bufformat; // Start of format
+ int width, // Width of field
+ prec; // Number of characters of precision
+ char tformat[100]; // Temporary format string for fprintf()
+ char *s; // Pointer to string
+ int slen; // Length of string
+ int i; // Looping var
+
+
+ // Range check input...
+ if (!fp || !format)
+ return (-1);
+
+ // Loop through the format string, formatting as needed...
+ va_start(ap, format);
+
+ bytes = 0;
+
+ while (*format)
+ {
+ if (*format == '%')
+ {
+ bufformat = format;
+ format ++;
+
+ if (*format == '%')
+ {
+ cupsFilePutChar(fp, *format++);
+ bytes ++;
+ continue;
+ }
+ else if (strchr(" -+#\'", *format))
+ sign = *format++;
+ else
+ sign = 0;
+
+ width = 0;
+ while (isdigit(*format))
+ width = width * 10 + *format++ - '0';
+
+ if (*format == '.')
+ {
+ format ++;
+ prec = 0;
+
+ while (isdigit(*format))
+ prec = prec * 10 + *format++ - '0';
+ }
+ else
+ prec = -1;
+
+ if (*format == 'l' && format[1] == 'l')
+ {
+ size = 'L';
+ format += 2;
+ }
+ else if (*format == 'h' || *format == 'l' || *format == 'L')
+ size = *format++;
+
+ if (!*format)
+ break;
+
+ type = *format++;
+
+ switch (type)
+ {
+ case 'E' : // Floating point formats
+ case 'G' :
+ case 'e' :
+ case 'f' :
+ case 'g' :
+ if ((format - bufformat + 1) > (int)sizeof(tformat))
+ break;
+
+ strncpy(tformat, bufformat, format - bufformat);
+ tformat[format - bufformat] = '\0';
+
+ bytes += cupsFilePrintf(fp, tformat, va_arg(ap, double));
+ break;
+
+ case 'B' : // Integer formats
+ case 'X' :
+ case 'b' :
+ case 'd' :
+ case 'i' :
+ case 'o' :
+ case 'u' :
+ case 'x' :
+ if ((format - bufformat + 1) > (int)sizeof(tformat))
+ break;
+
+ strncpy(tformat, bufformat, format - bufformat);
+ tformat[format - bufformat] = '\0';
+
+ bytes += cupsFilePrintf(fp, tformat, va_arg(ap, int));
+ break;
+
+ case 'p' : // Pointer value
+ if ((format - bufformat + 1) > (int)sizeof(tformat))
+ break;
+
+ strncpy(tformat, bufformat, format - bufformat);
+ tformat[format - bufformat] = '\0';
+
+ bytes += cupsFilePrintf(fp, tformat, va_arg(ap, void *));
+ break;
+
+ case 'c' : // Character or character array
+ if (width <= 1)
+ {
+ bytes ++;
+ cupsFilePutChar(fp, va_arg(ap, int));
+ }
+ else
+ {
+ cupsFileWrite(fp, va_arg(ap, char *), width);
+ bytes += width;
+ }
+ break;
+
+ case 's' : // String
+ if ((s = va_arg(ap, char *)) == NULL)
+ s = (char *)"(nil)";
+
+ slen = strlen(s);
+ if (slen > width && prec != width)
+ width = slen;
+
+ if (slen > width)
+ slen = width;
+
+ if (sign != '-')
+ {
+ for (i = width - slen; i > 0; i --, bytes ++)
+ cupsFilePutChar(fp, ' ');
+ }
+
+ for (i = slen; i > 0; i --, s ++, bytes ++)
+ {
+ if (*s == '\\' || *s == '\"')
+ {
+ cupsFilePutChar(fp, '\\');
+ bytes ++;
+ }
+
+ cupsFilePutChar(fp, *s);
+ }
+
+ if (sign == '-')
+ {
+ for (i = width - slen; i > 0; i --, bytes ++)
+ cupsFilePutChar(fp, ' ');
+ }
+ break;
+ }
+ }
+ else
+ {
+ cupsFilePutChar(fp, *format++);
+ bytes ++;
+ }
+ }
+
+ va_end(ap);
+
+ // Return the number of characters written.
+ return (bytes);
+}
+
+
+//
+// 'ppdcSource::read_file()' - Read a driver source file.
+//
+
+void
+ppdcSource::read_file(const char *f, // I - File to read
+ cups_file_t *ffp) // I - File pointer to use
+{
+ ppdcFile *fp = new ppdcFile(f, ffp);
+ scan_file(fp);
+ delete fp;
+
+ if (cond_current != cond_stack)
+ _cupsLangPrintf(stderr, _("ppdc: Missing #endif at end of \"%s\"."), f);
+}
+
+
+//
+// 'ppdcSource::scan_file()' - Scan a driver source file.
+//
+
+void
+ppdcSource::scan_file(ppdcFile *fp, // I - File to read
+ ppdcDriver *td, // I - Driver template
+ bool inc) // I - Including?
+{
+ ppdcDriver *d; // Current driver
+ ppdcGroup *g, // Current group
+ *mg, // Matching group
+ *general, // General options group
+ *install; // Installable options group
+ ppdcOption *o; // Current option
+ ppdcChoice *c; // Current choice
+ char temp[256], // Token from file...
+ *ptr; // Pointer into token
+ int isdefault; // Default option?
+
+
+ // Initialize things as needed...
+ if (inc && td)
+ {
+ d = td;
+ d->retain();
+ }
+ else
+ d = new ppdcDriver(td);
+
+ if ((general = d->find_group("General")) == NULL)
+ {
+ general = new ppdcGroup("General", NULL);
+ d->add_group(general);
+ }
+
+ if ((install = d->find_group("InstallableOptions")) == NULL)
+ {
+ install = new ppdcGroup("InstallableOptions", "Installable Options");
+ d->add_group(install);
+ }
+
+ // Loop until EOF or }
+ o = 0;
+ g = general;
+
+ while (get_token(fp, temp, sizeof(temp)))
+ {
+ if (temp[0] == '*')
+ {
+ // Mark the next choice as the default
+ isdefault = 1;
+
+ for (ptr = temp; ptr[1]; ptr ++)
+ *ptr = ptr[1];
+
+ *ptr = '\0';
+ }
+ else
+ {
+ // Don't mark the next choice as the default
+ isdefault = 0;
+ }
+
+ if (!_cups_strcasecmp(temp, "}"))
+ {
+ // Close this one out...
+ break;
+ }
+ else if (!_cups_strcasecmp(temp, "{"))
+ {
+ // Open a new child...
+ scan_file(fp, d);
+ }
+ else if (!_cups_strcasecmp(temp, "#if"))
+ {
+ if ((cond_current - cond_stack) >= 100)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Too many nested #if's on line %d of %s."),
+ fp->line, fp->filename);
+ break;
+ }
+
+ cond_current ++;
+ if (get_integer(fp) > 0)
+ *cond_current = PPDC_COND_SATISFIED;
+ else
+ {
+ *cond_current = PPDC_COND_SKIP;
+ cond_state |= PPDC_COND_SKIP;
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "#elif"))
+ {
+ if (cond_current == cond_stack)
+ {
+ _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s."),
+ fp->line, fp->filename);
+ break;
+ }
+
+ if (*cond_current & PPDC_COND_SATISFIED)
+ {
+ get_integer(fp);
+ *cond_current |= PPDC_COND_SKIP;
+ }
+ else if (get_integer(fp) > 0)
+ {
+ *cond_current |= PPDC_COND_SATISFIED;
+ *cond_current &= ~PPDC_COND_SKIP;
+ }
+ else
+ *cond_current |= PPDC_COND_SKIP;
+
+ // Update the current state
+ int *cond_temp = cond_current; // Temporary stack pointer
+
+ cond_state = PPDC_COND_NORMAL;
+ while (cond_temp > cond_stack)
+ if (*cond_temp & PPDC_COND_SKIP)
+ {
+ cond_state = PPDC_COND_SKIP;
+ break;
+ }
+ else
+ cond_temp --;
+ }
+ else if (!_cups_strcasecmp(temp, "#else"))
+ {
+ if (cond_current == cond_stack)
+ {
+ _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s."),
+ fp->line, fp->filename);
+ break;
+ }
+
+ if (*cond_current & PPDC_COND_SATISFIED)
+ *cond_current |= PPDC_COND_SKIP;
+ else
+ {
+ *cond_current |= PPDC_COND_SATISFIED;
+ *cond_current &= ~PPDC_COND_SKIP;
+ }
+
+ // Update the current state
+ int *cond_temp = cond_current; // Temporary stack pointer
+
+ cond_state = PPDC_COND_NORMAL;
+ while (cond_temp > cond_stack)
+ if (*cond_temp & PPDC_COND_SKIP)
+ {
+ cond_state = PPDC_COND_SKIP;
+ break;
+ }
+ else
+ cond_temp --;
+ }
+ else if (!_cups_strcasecmp(temp, "#endif"))
+ {
+ if (cond_current == cond_stack)
+ {
+ _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s."),
+ fp->line, fp->filename);
+ break;
+ }
+
+ cond_current --;
+
+ // Update the current state
+ int *cond_temp = cond_current; // Temporary stack pointer
+
+ cond_state = PPDC_COND_NORMAL;
+ while (cond_temp > cond_stack)
+ if (*cond_temp & PPDC_COND_SKIP)
+ {
+ cond_state = PPDC_COND_SKIP;
+ break;
+ }
+ else
+ cond_temp --;
+ }
+ else if (!_cups_strcasecmp(temp, "#define"))
+ {
+ // Get the variable...
+ get_variable(fp);
+ }
+ else if (!_cups_strcasecmp(temp, "#include"))
+ {
+ // #include filename
+ char basedir[1024], // Base directory
+ *baseptr, // Pointer into directory
+ inctemp[1024], // Initial filename
+ incname[1024]; // Include filename
+ ppdcFile *incfile; // Include file
+ int *old_current = cond_current;
+ // Previous current stack
+
+
+ // Get the include name...
+ if (!get_token(fp, inctemp, sizeof(inctemp)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected include filename on line %d of "
+ "%s."), fp->line, fp->filename);
+ break;
+ }
+
+ if (cond_state)
+ continue;
+
+ // Figure out the current directory...
+ strlcpy(basedir, fp->filename, sizeof(basedir));
+
+ if ((baseptr = strrchr(basedir, '/')) != NULL)
+ *baseptr = '\0';
+ else
+ strcpy(basedir, ".");
+
+ // Find the include file...
+ if (find_include(inctemp, basedir, incname, sizeof(incname)))
+ {
+ // Open the include file, scan it, and then close it...
+ incfile = new ppdcFile(incname);
+ scan_file(incfile, d, true);
+ delete incfile;
+
+ if (cond_current != old_current)
+ _cupsLangPrintf(stderr, _("ppdc: Missing #endif at end of \"%s\"."),
+ incname);
+ }
+ else
+ {
+ // Can't find it!
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unable to find include file \"%s\" on line %d "
+ "of %s."), inctemp, fp->line, fp->filename);
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "#media"))
+ {
+ ppdcMediaSize *m; // Media size
+
+
+ // Get a media size...
+ m = get_size(fp);
+ if (m)
+ {
+ if (cond_state)
+ m->release();
+ else
+ sizes->add(m);
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "#po"))
+ {
+ ppdcCatalog *cat; // Message catalog
+
+
+ // Get a message catalog...
+ cat = get_po(fp);
+ if (cat)
+ {
+ if (cond_state)
+ cat->release();
+ else
+ po_files->add(cat);
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "Attribute") ||
+ !_cups_strcasecmp(temp, "LocAttribute"))
+ {
+ ppdcAttr *a; // Attribute
+
+
+ // Get an attribute...
+ a = get_attr(fp, !_cups_strcasecmp(temp, "LocAttribute"));
+ if (a)
+ {
+ if (cond_state)
+ a->release();
+ else
+ d->add_attr(a);
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "Choice"))
+ {
+ // Get a choice...
+ c = get_choice(fp);
+ if (!c)
+ break;
+
+ if (cond_state)
+ {
+ c->release();
+ continue;
+ }
+
+ // Add it to the current option...
+ if (!o)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Choice found on line %d of %s with no "
+ "Option."), fp->line, fp->filename);
+ break;
+ }
+
+ o->add_choice(c);
+
+ if (isdefault)
+ o->set_defchoice(c);
+ }
+ else if (!_cups_strcasecmp(temp, "ColorDevice"))
+ {
+ // ColorDevice boolean
+ if (cond_state)
+ get_boolean(fp);
+ else
+ d->color_device = get_boolean(fp);
+ }
+ else if (!_cups_strcasecmp(temp, "ColorModel"))
+ {
+ // Get the color model
+ c = get_color_model(fp);
+ if (!c)
+ continue;
+
+ if (cond_state)
+ {
+ c->release();
+ continue;
+ }
+
+ // Add the choice to the ColorModel option...
+ if ((o = d->find_option("ColorModel")) == NULL)
+ {
+ // Create the ColorModel option...
+ o = new ppdcOption(PPDC_PICKONE, "ColorModel", "Color Mode", PPDC_SECTION_ANY, 10.0f);
+ g = general;
+ g->add_option(o);
+ }
+
+ o->add_choice(c);
+
+ if (isdefault)
+ o->set_defchoice(c);
+
+ o = NULL;
+ }
+ else if (!_cups_strcasecmp(temp, "ColorProfile"))
+ {
+ ppdcProfile *p; // Color profile
+
+
+ // Get the color profile...
+ p = get_color_profile(fp);
+
+ if (p)
+ {
+ if (cond_state)
+ p->release();
+ else
+ d->profiles->add(p);
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "Copyright"))
+ {
+ // Copyright string
+ char copytemp[8192], // Copyright string
+ *copyptr, // Pointer into string
+ *copyend; // Pointer to end of string
+
+
+ // Get the copyright string...
+ if (!get_token(fp, copytemp, sizeof(temp)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected string after Copyright on line %d "
+ "of %s."), fp->line, fp->filename);
+ break;
+ }
+
+ if (cond_state)
+ continue;
+
+ // Break it up into individual lines...
+ for (copyptr = copytemp; copyptr; copyptr = copyend)
+ {
+ if ((copyend = strchr(copyptr, '\n')) != NULL)
+ *copyend++ = '\0';
+
+ d->copyright->add(new ppdcString(copyptr));
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "CustomMedia"))
+ {
+ ppdcMediaSize *m; // Media size
+
+
+ // Get a custom media size...
+ m = get_custom_size(fp);
+
+ if (cond_state)
+ {
+ m->release();
+ continue;
+ }
+
+ if (m)
+ d->sizes->add(m);
+
+ if (isdefault)
+ d->set_default_size(m);
+ }
+ else if (!_cups_strcasecmp(temp, "Cutter"))
+ {
+ // Cutter boolean
+ int have_cutter; // Have a paper cutter?
+
+
+ have_cutter = get_boolean(fp);
+ if (have_cutter <= 0 || cond_state)
+ continue;
+
+ if ((o = d->find_option("CutMedia")) == NULL)
+ {
+ o = new ppdcOption(PPDC_BOOLEAN, "CutMedia", "Cut Media", PPDC_SECTION_ANY, 10.0f);
+
+ g = general;
+ g->add_option(o);
+
+ c = new ppdcChoice("False", NULL, "<</CutMedia 0>>setpagedevice");
+ o->add_choice(c);
+ o->set_defchoice(c);
+
+ c = new ppdcChoice("True", NULL, "<</CutMedia 4>>setpagedevice");
+ o->add_choice(c);
+ }
+
+ o = NULL;
+ }
+ else if (!_cups_strcasecmp(temp, "Darkness"))
+ {
+ // Get the darkness choice...
+ c = get_generic(fp, "Darkness", NULL, "cupsCompression");
+ if (!c)
+ continue;
+
+ if (cond_state)
+ {
+ c->release();
+ continue;
+ }
+
+ // Add the choice to the cupsDarkness option...
+ if ((o = d->find_option_group("cupsDarkness", &mg)) == NULL)
+ {
+ // Create the cupsDarkness option...
+ o = new ppdcOption(PPDC_PICKONE, "cupsDarkness", "Darkness", PPDC_SECTION_ANY, 10.0f);
+ g = general;
+ g->add_option(o);
+ }
+ else if (mg != general)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Option %s defined in two different groups on "
+ "line %d of %s."), "cupsDarkness", fp->line,
+ fp->filename);
+ c->release();
+ continue;
+ }
+
+ o->add_choice(c);
+
+ if (isdefault)
+ o->set_defchoice(c);
+
+ o = NULL;
+ }
+ else if (!_cups_strcasecmp(temp, "DriverType"))
+ {
+ int i; // Looping var
+
+
+ // DriverType keyword
+ if (!get_token(fp, temp, sizeof(temp)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected driver type keyword following "
+ "DriverType on line %d of %s."),
+ fp->line, fp->filename);
+ continue;
+ }
+
+ if (cond_state)
+ continue;
+
+ for (i = 0; i < (int)(sizeof(driver_types) / sizeof(driver_types[0])); i ++)
+ if (!_cups_strcasecmp(temp, driver_types[i]))
+ break;
+
+ if (i < (int)(sizeof(driver_types) / sizeof(driver_types[0])))
+ d->type = (ppdcDrvType)i;
+ else if (!_cups_strcasecmp(temp, "dymo"))
+ d->type = PPDC_DRIVER_LABEL;
+ else
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unknown driver type %s on line %d of %s."),
+ temp, fp->line, fp->filename);
+ }
+ else if (!_cups_strcasecmp(temp, "Duplex"))
+ get_duplex(fp, d);
+ else if (!_cups_strcasecmp(temp, "Filter"))
+ {
+ ppdcFilter *f; // Filter
+
+
+ // Get the filter value...
+ f = get_filter(fp);
+ if (f)
+ {
+ if (cond_state)
+ f->release();
+ else
+ d->filters->add(f);
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "Finishing"))
+ {
+ // Get the finishing choice...
+ c = get_generic(fp, "Finishing", "OutputType", NULL);
+ if (!c)
+ continue;
+
+ if (cond_state)
+ {
+ c->release();
+ continue;
+ }
+
+ // Add the choice to the cupsFinishing option...
+ if ((o = d->find_option_group("cupsFinishing", &mg)) == NULL)
+ {
+ // Create the cupsFinishing option...
+ o = new ppdcOption(PPDC_PICKONE, "cupsFinishing", "Finishing", PPDC_SECTION_ANY, 10.0f);
+ g = general;
+ g->add_option(o);
+ }
+ else if (mg != general)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Option %s defined in two different groups on "
+ "line %d of %s."), "cupsFinishing", fp->line,
+ fp->filename);
+ c->release();
+ continue;
+ }
+
+ o->add_choice(c);
+
+ if (isdefault)
+ o->set_defchoice(c);
+
+ o = NULL;
+ }
+ else if (!_cups_strcasecmp(temp, "Font") ||
+ !_cups_strcasecmp(temp, "#font"))
+ {
+ ppdcFont *f; // Font
+
+
+ // Get a font...
+ f = get_font(fp);
+ if (f)
+ {
+ if (cond_state)
+ f->release();
+ else
+ {
+ if (!_cups_strcasecmp(temp, "#font"))
+ base_fonts->add(f);
+ else
+ d->add_font(f);
+
+ if (isdefault)
+ d->set_default_font(f);
+ }
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "Group"))
+ {
+ // Get a group...
+ ppdcGroup *tempg = get_group(fp, d);
+
+ if (!tempg)
+ break;
+
+ if (cond_state)
+ {
+ if (!d->find_group(tempg->name->value))
+ tempg->release();
+ }
+ else
+ {
+ if (!d->find_group(tempg->name->value))
+ d->add_group(tempg);
+
+ g = tempg;
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "HWMargins"))
+ {
+ // HWMargins left bottom right top
+ d->left_margin = get_measurement(fp);
+ d->bottom_margin = get_measurement(fp);
+ d->right_margin = get_measurement(fp);
+ d->top_margin = get_measurement(fp);
+ }
+ else if (!_cups_strcasecmp(temp, "InputSlot"))
+ {
+ // Get the input slot choice...
+ c = get_generic(fp, "InputSlot", NULL, "MediaPosition");
+ if (!c)
+ continue;
+
+ if (cond_state)
+ {
+ c->release();
+ continue;
+ }
+
+ // Add the choice to the InputSlot option...
+
+ if ((o = d->find_option_group("InputSlot", &mg)) == NULL)
+ {
+ // Create the InputSlot option...
+ o = new ppdcOption(PPDC_PICKONE, "InputSlot", "Media Source",
+ PPDC_SECTION_ANY, 10.0f);
+ g = general;
+ g->add_option(o);
+ }
+ else if (mg != general)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Option %s defined in two different groups on "
+ "line %d of %s."), "InputSlot", fp->line,
+ fp->filename);
+ c->release();
+ continue;
+ }
+
+ o->add_choice(c);
+
+ if (isdefault)
+ o->set_defchoice(c);
+
+ o = NULL;
+ }
+ else if (!_cups_strcasecmp(temp, "Installable"))
+ {
+ // Get the installable option...
+ o = get_installable(fp);
+
+ // Add it as needed...
+ if (o)
+ {
+ if (cond_state)
+ o->release();
+ else
+ install->add_option(o);
+
+ o = NULL;
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "ManualCopies"))
+ {
+ // ManualCopies boolean
+ if (cond_state)
+ get_boolean(fp);
+ else
+ d->manual_copies = get_boolean(fp);
+ }
+ else if (!_cups_strcasecmp(temp, "Manufacturer"))
+ {
+ // Manufacturer name
+ char name[256]; // Model name string
+
+
+ if (!get_token(fp, name, sizeof(name)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected name after Manufacturer on line %d "
+ "of %s."), fp->line, fp->filename);
+ break;
+ }
+
+ if (!cond_state)
+ d->set_manufacturer(name);
+ }
+ else if (!_cups_strcasecmp(temp, "MaxSize"))
+ {
+ // MaxSize width length
+ if (cond_state)
+ {
+ get_measurement(fp);
+ get_measurement(fp);
+ }
+ else
+ {
+ d->max_width = get_measurement(fp);
+ d->max_length = get_measurement(fp);
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "MediaSize"))
+ {
+ // MediaSize keyword
+ char name[41]; // Media size name
+ ppdcMediaSize *m, // Matching media size...
+ *dm; // Driver media size...
+
+
+ if (get_token(fp, name, sizeof(name)) == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected name after MediaSize on line %d of "
+ "%s."), fp->line, fp->filename);
+ break;
+ }
+
+ if (cond_state)
+ continue;
+
+ m = find_size(name);
+
+ if (!m)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unknown media size \"%s\" on line %d of "
+ "%s."), name, fp->line, fp->filename);
+ break;
+ }
+
+ // Add this size to the driver...
+ dm = new ppdcMediaSize(m->name->value, m->text->value,
+ m->width, m->length, d->left_margin,
+ d->bottom_margin, d->right_margin,
+ d->top_margin);
+ d->sizes->add(dm);
+
+ if (isdefault)
+ d->set_default_size(dm);
+ }
+ else if (!_cups_strcasecmp(temp, "MediaType"))
+ {
+ // Get the media type choice...
+ c = get_generic(fp, "MediaType", "MediaType", "cupsMediaType");
+ if (!c)
+ continue;
+
+ if (cond_state)
+ {
+ c->release();
+ continue;
+ }
+
+ // Add the choice to the MediaType option...
+ if ((o = d->find_option_group("MediaType", &mg)) == NULL)
+ {
+ // Create the MediaType option...
+ o = new ppdcOption(PPDC_PICKONE, "MediaType", "Media Type",
+ PPDC_SECTION_ANY, 10.0f);
+ g = general;
+ g->add_option(o);
+ }
+ else if (mg != general)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Option %s defined in two different groups on "
+ "line %d of %s."), "MediaType", fp->line,
+ fp->filename);
+ c->release();
+ continue;
+ }
+
+ o->add_choice(c);
+
+ if (isdefault)
+ o->set_defchoice(c);
+
+ o = NULL;
+ }
+ else if (!_cups_strcasecmp(temp, "MinSize"))
+ {
+ // MinSize width length
+ if (cond_state)
+ {
+ get_measurement(fp);
+ get_measurement(fp);
+ }
+ else
+ {
+ d->min_width = get_measurement(fp);
+ d->min_length = get_measurement(fp);
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "ModelName"))
+ {
+ // ModelName name
+ char name[256]; // Model name string
+
+
+ if (!get_token(fp, name, sizeof(name)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected name after ModelName on line %d of "
+ "%s."), fp->line, fp->filename);
+ break;
+ }
+
+ if (!cond_state)
+ d->set_model_name(name);
+ }
+ else if (!_cups_strcasecmp(temp, "ModelNumber"))
+ {
+ // ModelNumber number
+ if (cond_state)
+ get_integer(fp);
+ else
+ d->model_number = get_integer(fp);
+ }
+ else if (!_cups_strcasecmp(temp, "Option"))
+ {
+ // Get an option...
+ ppdcOption *tempo = get_option(fp, d, g);
+
+ if (!tempo)
+ break;
+
+ if (cond_state)
+ {
+ if (!g->find_option(tempo->name->value))
+ tempo->release();
+ }
+ else
+ {
+ if (!g->find_option(tempo->name->value))
+ g->add_option(tempo);
+
+ o = tempo;
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "FileName"))
+ {
+ // FileName name
+ char name[256]; // Filename string
+
+
+ if (!get_token(fp, name, sizeof(name)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected name after FileName on line %d of "
+ "%s."), fp->line, fp->filename);
+ break;
+ }
+
+ if (!cond_state)
+ d->set_file_name(name);
+ }
+ else if (!_cups_strcasecmp(temp, "PCFileName"))
+ {
+ // PCFileName name
+ char name[256]; // PC filename string
+
+
+ if (!get_token(fp, name, sizeof(name)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected name after PCFileName on line %d of "
+ "%s."), fp->line, fp->filename);
+ break;
+ }
+
+ if (!cond_state)
+ d->set_pc_file_name(name);
+ }
+ else if (!_cups_strcasecmp(temp, "Resolution"))
+ {
+ // Get the resolution choice...
+ c = get_resolution(fp);
+ if (!c)
+ continue;
+
+ if (cond_state)
+ {
+ c->release();
+ continue;
+ }
+
+ // Add the choice to the Resolution option...
+ if ((o = d->find_option_group("Resolution", &mg)) == NULL)
+ {
+ // Create the Resolution option...
+ o = new ppdcOption(PPDC_PICKONE, "Resolution", NULL, PPDC_SECTION_ANY,
+ 10.0f);
+ g = general;
+ g->add_option(o);
+ }
+ else if (mg != general)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Option %s defined in two different groups on "
+ "line %d of %s."), "Resolution", fp->line,
+ fp->filename);
+ c->release();
+ continue;
+ }
+
+ o->add_choice(c);
+
+ if (isdefault)
+ o->set_defchoice(c);
+
+ o = NULL;
+ }
+ else if (!_cups_strcasecmp(temp, "SimpleColorProfile"))
+ {
+ ppdcProfile *p; // Color profile
+
+
+ // Get the color profile...
+ p = get_simple_profile(fp);
+
+ if (p)
+ {
+ if (cond_state)
+ p->release();
+ else
+ d->profiles->add(p);
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "Throughput"))
+ {
+ // Throughput number
+ if (cond_state)
+ get_integer(fp);
+ else
+ d->throughput = get_integer(fp);
+ }
+ else if (!_cups_strcasecmp(temp, "UIConstraints"))
+ {
+ ppdcConstraint *con; // Constraint
+
+
+ con = get_constraint(fp);
+
+ if (con)
+ {
+ if (cond_state)
+ con->release();
+ else
+ d->constraints->add(con);
+ }
+ }
+ else if (!_cups_strcasecmp(temp, "VariablePaperSize"))
+ {
+ // VariablePaperSize boolean
+ if (cond_state)
+ get_boolean(fp);
+ else
+ d->variable_paper_size = get_boolean(fp);
+ }
+ else if (!_cups_strcasecmp(temp, "Version"))
+ {
+ // Version string
+ char name[256]; // Model name string
+
+
+ if (!get_token(fp, name, sizeof(name)))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Expected string after Version on line %d of "
+ "%s."), fp->line, fp->filename);
+ break;
+ }
+
+ if (!cond_state)
+ d->set_version(name);
+ }
+ else
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unknown token \"%s\" seen on line %d of %s."),
+ temp, fp->line, fp->filename);
+ break;
+ }
+ }
+
+ // Done processing this block, is there anything to save?
+ if (!inc)
+ {
+ if (!d->pc_file_name || !d->model_name || !d->manufacturer || !d->version ||
+ !d->sizes->count)
+ {
+ // Nothing to save...
+ d->release();
+ }
+ else
+ {
+ // Got a driver, save it...
+ drivers->add(d);
+ }
+ }
+ else if (inc && td)
+ td->release();
+}
+
+
+//
+// 'ppdcSource::set_variable()' - Set a variable.
+//
+
+ppdcVariable * // O - Variable
+ppdcSource::set_variable(
+ const char *name, // I - Name
+ const char *value) // I - Value
+{
+ ppdcVariable *v; // Variable
+
+
+ // See if the variable exists already...
+ v = find_variable(name);
+ if (v)
+ {
+ // Change the variable value...
+ v->set_value(value);
+ }
+ else
+ {
+ // Create a new variable and add it...
+ v = new ppdcVariable(name, value);
+ vars->add(v);
+ }
+
+ return (v);
+}
+
+
+//
+// 'ppdcSource::write_file()' - Write the current source data to a file.
+//
+
+int // O - 0 on success, -1 on error
+ppdcSource::write_file(const char *f) // I - File to write
+{
+ cups_file_t *fp; // Output file
+ char bckname[1024]; // Backup file
+ ppdcDriver *d; // Current driver
+ ppdcString *st; // Current string
+ ppdcAttr *a; // Current attribute
+ ppdcConstraint *co; // Current constraint
+ ppdcFilter *fi; // Current filter
+ ppdcFont *fo; // Current font
+ ppdcGroup *g; // Current group
+ ppdcOption *o; // Current option
+ ppdcChoice *ch; // Current choice
+ ppdcProfile *p; // Current color profile
+ ppdcMediaSize *si; // Current media size
+ float left, // Current left margin
+ bottom, // Current bottom margin
+ right, // Current right margin
+ top; // Current top margin
+ int dtused[PPDC_DRIVER_MAX];// Driver type usage...
+
+
+ // Rename the current file, if any, to .bck...
+ snprintf(bckname, sizeof(bckname), "%s.bck", f);
+ rename(f, bckname);
+
+ // Open the output file...
+ fp = cupsFileOpen(f, "w");
+
+ if (!fp)
+ {
+ // Can't create file; restore backup and return...
+ rename(bckname, f);
+ return (-1);
+ }
+
+ cupsFilePuts(fp, "// CUPS PPD Compiler " CUPS_SVERSION "\n\n");
+
+ // Include standard files...
+ cupsFilePuts(fp, "// Include necessary files...\n");
+ cupsFilePuts(fp, "#include <font.defs>\n");
+ cupsFilePuts(fp, "#include <media.defs>\n");
+
+ memset(dtused, 0, sizeof(dtused));
+
+ for (d = (ppdcDriver *)drivers->first(); d; d = (ppdcDriver *)drivers->next())
+ if (d->type > PPDC_DRIVER_PS && !dtused[d->type])
+ {
+ cupsFilePrintf(fp, "#include <%s.h>\n", driver_types[d->type]);
+ dtused[d->type] = 1;
+ }
+
+ // Output each driver...
+ for (d = (ppdcDriver *)drivers->first(); d; d = (ppdcDriver *)drivers->next())
+ {
+ // Start the driver...
+ cupsFilePrintf(fp, "\n// %s %s\n", d->manufacturer->value,
+ d->model_name->value);
+ cupsFilePuts(fp, "{\n");
+
+ // Write the copyright stings...
+ for (st = (ppdcString *)d->copyright->first();
+ st;
+ st = (ppdcString *)d->copyright->next())
+ quotef(fp, " Copyright \"%s\"\n", st->value);
+
+ // Write other strings and values...
+ if (d->manufacturer && d->manufacturer->value)
+ quotef(fp, " Manufacturer \"%s\"\n", d->manufacturer->value);
+ if (d->model_name->value)
+ quotef(fp, " ModelName \"%s\"\n", d->model_name->value);
+ if (d->file_name && d->file_name->value)
+ quotef(fp, " FileName \"%s\"\n", d->file_name->value);
+ if (d->pc_file_name && d->pc_file_name->value)
+ quotef(fp, " PCFileName \"%s\"\n", d->pc_file_name->value);
+ if (d->version && d->version->value)
+ quotef(fp, " Version \"%s\"\n", d->version->value);
+
+ cupsFilePrintf(fp, " DriverType %s\n", driver_types[d->type]);
+
+ if (d->model_number)
+ {
+ switch (d->type)
+ {
+ case PPDC_DRIVER_ESCP :
+ cupsFilePuts(fp, " ModelNumber (");
+
+ if (d->model_number & ESCP_DOTMATRIX)
+ cupsFilePuts(fp, " $ESCP_DOTMATRIX");
+ if (d->model_number & ESCP_MICROWEAVE)
+ cupsFilePuts(fp, " $ESCP_MICROWEAVE");
+ if (d->model_number & ESCP_STAGGER)
+ cupsFilePuts(fp, " $ESCP_STAGGER");
+ if (d->model_number & ESCP_ESCK)
+ cupsFilePuts(fp, " $ESCP_ESCK");
+ if (d->model_number & ESCP_EXT_UNITS)
+ cupsFilePuts(fp, " $ESCP_EXT_UNITS");
+ if (d->model_number & ESCP_EXT_MARGINS)
+ cupsFilePuts(fp, " $ESCP_EXT_MARGINS");
+ if (d->model_number & ESCP_USB)
+ cupsFilePuts(fp, " $ESCP_USB");
+ if (d->model_number & ESCP_PAGE_SIZE)
+ cupsFilePuts(fp, " $ESCP_PAGE_SIZE");
+ if (d->model_number & ESCP_RASTER_ESCI)
+ cupsFilePuts(fp, " $ESCP_RASTER_ESCI");
+ if (d->model_number & ESCP_REMOTE)
+ cupsFilePuts(fp, " $ESCP_REMOTE");
+
+ cupsFilePuts(fp, ")\n");
+ break;
+
+ case PPDC_DRIVER_PCL :
+ cupsFilePuts(fp, " ModelNumber (");
+
+ if (d->model_number & PCL_PAPER_SIZE)
+ cupsFilePuts(fp, " $PCL_PAPER_SIZE");
+ if (d->model_number & PCL_INKJET)
+ cupsFilePuts(fp, " $PCL_INKJET");
+ if (d->model_number & PCL_RASTER_END_COLOR)
+ cupsFilePuts(fp, " $PCL_RASTER_END_COLOR");
+ if (d->model_number & PCL_RASTER_CID)
+ cupsFilePuts(fp, " $PCL_RASTER_CID");
+ if (d->model_number & PCL_RASTER_CRD)
+ cupsFilePuts(fp, " $PCL_RASTER_CRD");
+ if (d->model_number & PCL_RASTER_SIMPLE)
+ cupsFilePuts(fp, " $PCL_RASTER_SIMPLE");
+ if (d->model_number & PCL_RASTER_RGB24)
+ cupsFilePuts(fp, " $PCL_RASTER_RGB24");
+ if (d->model_number & PCL_PJL)
+ cupsFilePuts(fp, " $PCL_PJL");
+ if (d->model_number & PCL_PJL_PAPERWIDTH)
+ cupsFilePuts(fp, " $PCL_PJL_PAPERWIDTH");
+ if (d->model_number & PCL_PJL_HPGL2)
+ cupsFilePuts(fp, " $PCL_PJL_HPGL2");
+ if (d->model_number & PCL_PJL_PCL3GUI)
+ cupsFilePuts(fp, " $PCL_PJL_PCL3GUI");
+ if (d->model_number & PCL_PJL_RESOLUTION)
+ cupsFilePuts(fp, " $PCL_PJL_RESOLUTION");
+
+ cupsFilePuts(fp, ")\n");
+ break;
+
+ case PPDC_DRIVER_LABEL :
+ cupsFilePuts(fp, " ModelNumber ");
+
+ switch (d->model_number)
+ {
+ case DYMO_3x0 :
+ cupsFilePuts(fp, "$DYMO_3x0\n");
+ break;
+
+ case ZEBRA_EPL_LINE :
+ cupsFilePuts(fp, "$ZEBRA_EPL_LINE\n");
+ break;
+
+ case ZEBRA_EPL_PAGE :
+ cupsFilePuts(fp, "$ZEBRA_EPL_PAGE\n");
+ break;
+
+ case ZEBRA_ZPL :
+ cupsFilePuts(fp, "$ZEBRA_ZPL\n");
+ break;
+
+ case ZEBRA_CPCL :
+ cupsFilePuts(fp, "$ZEBRA_CPCL\n");
+ break;
+
+ case INTELLITECH_PCL :
+ cupsFilePuts(fp, "$INTELLITECH_PCL\n");
+ break;
+
+ default :
+ cupsFilePrintf(fp, "%d\n", d->model_number);
+ break;
+ }
+ break;
+
+ case PPDC_DRIVER_EPSON :
+ cupsFilePuts(fp, " ModelNumber ");
+
+ switch (d->model_number)
+ {
+ case EPSON_9PIN :
+ cupsFilePuts(fp, "$EPSON_9PIN\n");
+ break;
+
+ case EPSON_24PIN :
+ cupsFilePuts(fp, "$EPSON_24PIN\n");
+ break;
+
+ case EPSON_COLOR :
+ cupsFilePuts(fp, "$EPSON_COLOR\n");
+ break;
+
+ case EPSON_PHOTO :
+ cupsFilePuts(fp, "$EPSON_PHOTO\n");
+ break;
+
+ case EPSON_ICOLOR :
+ cupsFilePuts(fp, "$EPSON_ICOLOR\n");
+ break;
+
+ case EPSON_IPHOTO :
+ cupsFilePuts(fp, "$EPSON_IPHOTO\n");
+ break;
+
+ default :
+ cupsFilePrintf(fp, "%d\n", d->model_number);
+ break;
+ }
+ break;
+
+ case PPDC_DRIVER_HP :
+ cupsFilePuts(fp, " ModelNumber ");
+ switch (d->model_number)
+ {
+ case HP_LASERJET :
+ cupsFilePuts(fp, "$HP_LASERJET\n");
+ break;
+
+ case HP_DESKJET :
+ cupsFilePuts(fp, "$HP_DESKJET\n");
+ break;
+
+ case HP_DESKJET2 :
+ cupsFilePuts(fp, "$HP_DESKJET2\n");
+ break;
+
+ default :
+ cupsFilePrintf(fp, "%d\n", d->model_number);
+ break;
+ }
+
+ cupsFilePuts(fp, ")\n");
+ break;
+
+ default :
+ cupsFilePrintf(fp, " ModelNumber %d\n", d->model_number);
+ break;
+ }
+ }
+
+ if (d->manual_copies)
+ cupsFilePuts(fp, " ManualCopies Yes\n");
+
+ if (d->color_device)
+ cupsFilePuts(fp, " ColorDevice Yes\n");
+
+ if (d->throughput)
+ cupsFilePrintf(fp, " Throughput %d\n", d->throughput);
+
+ // Output all of the attributes...
+ for (a = (ppdcAttr *)d->attrs->first();
+ a;
+ a = (ppdcAttr *)d->attrs->next())
+ if (a->text->value && a->text->value[0])
+ quotef(fp, " Attribute \"%s\" \"%s/%s\" \"%s\"\n",
+ a->name->value, a->selector->value ? a->selector->value : "",
+ a->text->value, a->value->value ? a->value->value : "");
+ else
+ quotef(fp, " Attribute \"%s\" \"%s\" \"%s\"\n",
+ a->name->value, a->selector->value ? a->selector->value : "",
+ a->value->value ? a->value->value : "");
+
+ // Output all of the constraints...
+ for (co = (ppdcConstraint *)d->constraints->first();
+ co;
+ co = (ppdcConstraint *)d->constraints->next())
+ {
+ if (co->option1->value[0] == '*')
+ cupsFilePrintf(fp, " UIConstraints \"%s %s", co->option1->value,
+ co->choice1->value ? co->choice1->value : "");
+ else
+ cupsFilePrintf(fp, " UIConstraints \"*%s %s", co->option1->value,
+ co->choice1->value ? co->choice1->value : "");
+
+ if (co->option2->value[0] == '*')
+ cupsFilePrintf(fp, " %s %s\"\n", co->option2->value,
+ co->choice2->value ? co->choice2->value : "");
+ else
+ cupsFilePrintf(fp, " *%s %s\"\n", co->option2->value,
+ co->choice2->value ? co->choice2->value : "");
+ }
+
+ // Output all of the filters...
+ for (fi = (ppdcFilter *)d->filters->first();
+ fi;
+ fi = (ppdcFilter *)d->filters->next())
+ cupsFilePrintf(fp, " Filter \"%s %d %s\"\n",
+ fi->mime_type->value, fi->cost, fi->program->value);
+
+ // Output all of the fonts...
+ for (fo = (ppdcFont *)d->fonts->first();
+ fo;
+ fo = (ppdcFont *)d->fonts->next())
+ if (!strcmp(fo->name->value, "*"))
+ cupsFilePuts(fp, " Font *\n");
+ else
+ cupsFilePrintf(fp, " Font \"%s\" \"%s\" \"%s\" \"%s\" %s\n",
+ fo->name->value, fo->encoding->value,
+ fo->version->value, fo->charset->value,
+ fo->status == PPDC_FONT_ROM ? "ROM" : "Disk");
+
+ // Output all options...
+ for (g = (ppdcGroup *)d->groups->first();
+ g;
+ g = (ppdcGroup *)d->groups->next())
+ {
+ if (g->options->count == 0)
+ continue;
+
+ if (g->text->value && g->text->value[0])
+ quotef(fp, " Group \"%s/%s\"\n", g->name->value, g->text->value);
+ else
+ cupsFilePrintf(fp, " Group \"%s\"\n", g->name->value);
+
+ for (o = (ppdcOption *)g->options->first();
+ o;
+ o = (ppdcOption *)g->options->next())
+ {
+ if (o->choices->count == 0)
+ continue;
+
+ if (o->text->value && o->text->value[0])
+ quotef(fp, " Option \"%s/%s\"", o->name->value, o->text->value);
+ else
+ cupsFilePrintf(fp, " Option \"%s\"", o->name->value);
+
+ cupsFilePrintf(fp, " %s %s %.1f\n",
+ o->type == PPDC_BOOLEAN ? "Boolean" :
+ o->type == PPDC_PICKONE ? "PickOne" : "PickMany",
+ o->section == PPDC_SECTION_ANY ? "AnySetup" :
+ o->section == PPDC_SECTION_DOCUMENT ? "DocumentSetup" :
+ o->section == PPDC_SECTION_EXIT ? "ExitServer" :
+ o->section == PPDC_SECTION_JCL ? "JCLSetup" :
+ o->section == PPDC_SECTION_PAGE ? "PageSetup" :
+ "Prolog",
+ o->order);
+
+ for (ch = (ppdcChoice *)o->choices->first();
+ ch;
+ ch = (ppdcChoice *)o->choices->next())
+ {
+ if (ch->text->value && ch->text->value[0])
+ quotef(fp, " %sChoice \"%s/%s\" \"%s\"\n",
+ o->defchoice == ch->name ? "*" : "",
+ ch->name->value, ch->text->value,
+ ch->code->value ? ch->code->value : "");
+ else
+ quotef(fp, " %sChoice \"%s\" \"%s\"\n",
+ o->defchoice == ch->name ? "*" : "",
+ ch->name->value,
+ ch->code->value ? ch->code->value : "");
+ }
+ }
+ }
+
+ // Output all of the color profiles...
+ for (p = (ppdcProfile *)d->profiles->first();
+ p;
+ p = (ppdcProfile *)d->profiles->next())
+ cupsFilePrintf(fp, " ColorProfile \"%s/%s\" %.3f %.3f "
+ "%.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n",
+ p->resolution->value, p->media_type->value,
+ p->density, p->gamma,
+ p->profile[0], p->profile[1], p->profile[2],
+ p->profile[3], p->profile[4], p->profile[5],
+ p->profile[6], p->profile[7], p->profile[8]);
+
+ // Output all of the media sizes...
+ left = 0.0;
+ bottom = 0.0;
+ right = 0.0;
+ top = 0.0;
+
+ for (si = (ppdcMediaSize *)d->sizes->first();
+ si;
+ si = (ppdcMediaSize *)d->sizes->next())
+ if (si->size_code->value && si->region_code->value)
+ {
+ // Output a custom media size...
+ quotef(fp, " %sCustomMedia \"%s/%s\" %.2f %.2f %.2f %.2f %.2f %.2f \"%s\" \"%s\"\n",
+ si->name == d->default_size ? "*" : "", si->name->value,
+ si->text->value, si->width, si->length, si->left, si->bottom,
+ si->right, si->top, si->size_code->value,
+ si->region_code->value);
+ }
+ else
+ {
+ // Output a standard media size...
+ if (fabs(left - si->left) > 0.1 ||
+ fabs(bottom - si->bottom) > 0.1 ||
+ fabs(right - si->right) > 0.1 ||
+ fabs(top - si->top) > 0.1)
+ {
+ cupsFilePrintf(fp, " HWMargins %.2f %.2f %.2f %.2f\n",
+ si->left, si->bottom, si->right, si->top);
+
+ left = si->left;
+ bottom = si->bottom;
+ right = si->right;
+ top = si->top;
+ }
+
+ cupsFilePrintf(fp, " %sMediaSize %s\n",
+ si->name == d->default_size ? "*" : "",
+ si->name->value);
+ }
+
+ if (d->variable_paper_size)
+ {
+ cupsFilePuts(fp, " VariablePaperSize Yes\n");
+
+ if (fabs(left - d->left_margin) > 0.1 ||
+ fabs(bottom - d->bottom_margin) > 0.1 ||
+ fabs(right - d->right_margin) > 0.1 ||
+ fabs(top - d->top_margin) > 0.1)
+ {
+ cupsFilePrintf(fp, " HWMargins %.2f %.2f %.2f %.2f\n",
+ d->left_margin, d->bottom_margin, d->right_margin,
+ d->top_margin);
+ }
+
+ cupsFilePrintf(fp, " MinSize %.2f %.2f\n", d->min_width, d->min_length);
+ cupsFilePrintf(fp, " MaxSize %.2f %.2f\n", d->max_width, d->max_length);
+ }
+
+ // End the driver...
+ cupsFilePuts(fp, "}\n");
+ }
+
+ // Close the file and return...
+ cupsFileClose(fp);
+
+ return (0);
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-string.cxx b/ppdc/ppdc-string.cxx
new file mode 100644
index 000000000..caf8f8015
--- /dev/null
+++ b/ppdc/ppdc-string.cxx
@@ -0,0 +1,62 @@
+//
+// "$Id$"
+//
+// Shared string class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2009 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcString::ppdcString() - Create a shared string.
+// ppdcString::~ppdcString() - Destroy a shared string.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcString::ppdcString()' - Create a shared string.
+//
+
+ppdcString::ppdcString(const char *v) // I - String
+ : ppdcShared()
+{
+ PPDC_NEWVAL(v);
+
+ if (v)
+ {
+ value = new char[strlen(v) + 1];
+ strcpy(value, v);
+ }
+ else
+ value = 0;
+}
+
+
+//
+// 'ppdcString::~ppdcString()' - Destroy a shared string.
+//
+
+ppdcString::~ppdcString()
+{
+ PPDC_DELETEVAL(value);
+
+ if (value)
+ delete[] value;
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc-variable.cxx b/ppdc/ppdc-variable.cxx
new file mode 100644
index 000000000..22a175ad4
--- /dev/null
+++ b/ppdc/ppdc-variable.cxx
@@ -0,0 +1,71 @@
+//
+// "$Id$"
+//
+// Variable class for the CUPS PPD Compiler.
+//
+// Copyright 2007-2009 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// ppdcVariable::ppdcVariable() - Create a variable.
+// ppdcVariable::~ppdcVariable() - Destroy a variable.
+// ppdcVariable::set_value() - Set the value of a variable.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'ppdcVariable::ppdcVariable()' - Create a variable.
+//
+
+ppdcVariable::ppdcVariable(const char *n, // I - Name of variable
+ const char *v) // I - Value of variable
+ : ppdcShared()
+{
+ PPDC_NEW;
+
+ name = new ppdcString(n);
+ value = new ppdcString(v);
+}
+
+
+//
+// 'ppdcVariable::~ppdcVariable()' - Destroy a variable.
+//
+
+ppdcVariable::~ppdcVariable()
+{
+ PPDC_DELETE;
+
+ name->release();
+ value->release();
+}
+
+
+//
+// 'ppdcVariable::set_value()' - Set the value of a variable.
+//
+
+void
+ppdcVariable::set_value(const char *v)
+{
+ value->release();
+ value = new ppdcString(v);
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc.cxx b/ppdc/ppdc.cxx
new file mode 100644
index 000000000..d8d128db8
--- /dev/null
+++ b/ppdc/ppdc.cxx
@@ -0,0 +1,469 @@
+//
+// "$Id$"
+//
+// PPD file compiler main entry for the CUPS PPD Compiler.
+//
+// Copyright 2007-2011 by Apple Inc.
+// Copyright 2002-2007 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// main() - Main entry for the PPD compiler.
+// usage() - Show usage and exit.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+
+//
+// Local functions...
+//
+
+static void usage(void);
+
+
+//
+// 'main()' - Main entry for the PPD compiler.
+//
+
+int // O - Exit status
+main(int argc, // I - Number of command-line arguments
+ char *argv[]) // I - Command-line arguments
+{
+ int i, j; // Looping vars
+ ppdcCatalog *catalog; // Message catalog
+ const char *outdir; // Output directory
+ ppdcSource *src; // PPD source file data
+ ppdcDriver *d; // Current driver
+ cups_file_t *fp; // PPD file
+ char *opt, // Current option
+ *value, // Value in option
+ *outname, // Output filename
+ make_model[1024],
+ // Make and model
+ pcfilename[1024],
+ // Lowercase pcfilename
+ filename[1024]; // PPD filename
+ int comp, // Compress
+ do_test, // Test PPD files
+ single_language,// Generate single-language files
+ use_model_name, // Use ModelName for filename
+ verbose; // Verbosity
+ ppdcLineEnding le; // Line ending to use
+ ppdcArray *locales; // List of locales
+ cups_array_t *filenames; // List of generated filenames
+
+
+ _cupsSetLocale(argv);
+
+ // Scan the command-line...
+ catalog = NULL;
+ comp = 0;
+ do_test = 0;
+ le = PPDC_LFONLY;
+ locales = NULL;
+ outdir = "ppd";
+ single_language = 0;
+ src = new ppdcSource();
+ use_model_name = 0;
+ verbose = 0;
+ filenames = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL);
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ {
+ for (opt = argv[i] + 1; *opt; opt ++)
+ switch (*opt)
+ {
+ case 'D' : // Define variable
+ i ++;
+ if (i >= argc)
+ usage();
+
+ if ((value = strchr(argv[i], '=')) != NULL)
+ {
+ *value++ = '\0';
+
+ src->set_variable(argv[i], value);
+ }
+ else
+ src->set_variable(argv[i], "1");
+ break;
+
+ case 'I' : // Include directory...
+ i ++;
+ if (i >= argc)
+ usage();
+
+ if (verbose > 1)
+ _cupsLangPrintf(stdout,
+ _("ppdc: Adding include directory \"%s\"."),
+ argv[i]);
+
+ ppdcSource::add_include(argv[i]);
+ break;
+
+ case 'c' : // Message catalog...
+ i ++;
+ if (i >= argc)
+ usage();
+
+ if (verbose > 1)
+ _cupsLangPrintf(stdout,
+ _("ppdc: Loading messages from \"%s\"."),
+ argv[i]);
+
+ if (!catalog)
+ catalog = new ppdcCatalog("en");
+
+ if (catalog->load_messages(argv[i]))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unable to load localization file "
+ "\"%s\" - %s"), argv[i], strerror(errno));
+ return (1);
+ }
+ break;
+
+ case 'd' : // Output directory...
+ i ++;
+ if (i >= argc)
+ usage();
+
+ if (verbose > 1)
+ _cupsLangPrintf(stdout,
+ _("ppdc: Writing PPD files to directory "
+ "\"%s\"."), argv[i]);
+
+ outdir = argv[i];
+ break;
+
+ case 'l' : // Language(s)...
+ i ++;
+ if (i >= argc)
+ usage();
+
+ if (strchr(argv[i], ','))
+ {
+ // Comma-delimited list of languages...
+ char temp[1024], // Copy of language list
+ *start, // Start of current locale name
+ *end; // End of current locale name
+
+
+ locales = new ppdcArray();
+
+ strlcpy(temp, argv[i], sizeof(temp));
+ for (start = temp; *start; start = end)
+ {
+ if ((end = strchr(start, ',')) != NULL)
+ *end++ = '\0';
+ else
+ end = start + strlen(start);
+
+ if (end > start)
+ locales->add(new ppdcString(start));
+ }
+ }
+ else
+ {
+ single_language = 1;
+
+ if (verbose > 1)
+ _cupsLangPrintf(stdout,
+ _("ppdc: Loading messages for locale "
+ "\"%s\"."), argv[i]);
+
+ if (catalog)
+ catalog->release();
+
+ catalog = new ppdcCatalog(argv[i]);
+
+ if (catalog->messages->count == 0)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unable to find localization for "
+ "\"%s\" - %s"), argv[i], strerror(errno));
+ return (1);
+ }
+ }
+ break;
+
+ case 'm' : // Use ModelName for filename
+ use_model_name = 1;
+ break;
+
+ case 't' : // Test PPDs instead of generating them
+ do_test = 1;
+ break;
+
+ case 'v' : // Be verbose...
+ verbose ++;
+ break;
+
+ case 'z' : // Compress files...
+ comp = 1;
+ break;
+
+ case '-' : // --option
+ if (!strcmp(opt, "-lf"))
+ {
+ le = PPDC_LFONLY;
+ opt += strlen(opt) - 1;
+ break;
+ }
+ else if (!strcmp(opt, "-cr"))
+ {
+ le = PPDC_CRONLY;
+ opt += strlen(opt) - 1;
+ break;
+ }
+ else if (!strcmp(opt, "-crlf"))
+ {
+ le = PPDC_CRLF;
+ opt += strlen(opt) - 1;
+ break;
+ }
+
+ default : // Unknown
+ usage();
+ break;
+ }
+ }
+ else
+ {
+ // Open and load the driver info file...
+ if (verbose > 1)
+ _cupsLangPrintf(stdout,
+ _("ppdc: Loading driver information file \"%s\"."),
+ argv[i]);
+
+ src->read_file(argv[i]);
+ }
+
+
+ if (src->drivers->count > 0)
+ {
+ // Create the output directory...
+ if (mkdir(outdir, 0777))
+ {
+ if (errno != EEXIST)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unable to create output directory %s: %s"),
+ outdir, strerror(errno));
+ return (1);
+ }
+ }
+
+ // Write PPD files...
+ for (d = (ppdcDriver *)src->drivers->first();
+ d;
+ d = (ppdcDriver *)src->drivers->next())
+ {
+ if (do_test)
+ {
+ // Test the PPD file for this driver...
+ int pid, // Process ID
+ fds[2]; // Pipe file descriptors
+
+
+ if (pipe(fds))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unable to create output pipes: %s"),
+ strerror(errno));
+ return (1);
+ }
+
+ if ((pid = fork()) == 0)
+ {
+ // Child process comes here...
+ dup2(fds[0], 0);
+
+ close(fds[0]);
+ close(fds[1]);
+
+ execlp("cupstestppd", "cupstestppd", "-", (char *)0);
+
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unable to execute cupstestppd: %s"),
+ strerror(errno));
+ return (errno);
+ }
+ else if (pid < 0)
+ {
+ _cupsLangPrintf(stderr, _("ppdc: Unable to execute cupstestppd: %s"),
+ strerror(errno));
+ return (errno);
+ }
+
+ close(fds[0]);
+ fp = cupsFileOpenFd(fds[1], "w");
+ }
+ else
+ {
+ // Write the PPD file for this driver...
+ if (use_model_name)
+ {
+ if (!_cups_strncasecmp(d->model_name->value, d->manufacturer->value,
+ strlen(d->manufacturer->value)))
+ {
+ // Model name already starts with the manufacturer...
+ outname = d->model_name->value;
+ }
+ else
+ {
+ // Add manufacturer to the front of the model name...
+ snprintf(make_model, sizeof(make_model), "%s %s",
+ d->manufacturer->value, d->model_name->value);
+ outname = make_model;
+ }
+ }
+ else if (d->file_name)
+ outname = d->file_name->value;
+ else
+ outname = d->pc_file_name->value;
+
+ if (strstr(outname, ".PPD"))
+ {
+ // Convert PCFileName to lowercase...
+ for (j = 0;
+ outname[j] && j < (int)(sizeof(pcfilename) - 1);
+ j ++)
+ pcfilename[j] = tolower(outname[j] & 255);
+
+ pcfilename[j] = '\0';
+ }
+ else
+ {
+ // Leave PCFileName as-is...
+ strlcpy(pcfilename, outname, sizeof(pcfilename));
+ }
+
+ // Open the PPD file for writing...
+ if (comp)
+ snprintf(filename, sizeof(filename), "%s/%s.gz", outdir, pcfilename);
+ else
+ snprintf(filename, sizeof(filename), "%s/%s", outdir, pcfilename);
+
+ if (cupsArrayFind(filenames, filename))
+ _cupsLangPrintf(stderr,
+ _("ppdc: Warning - overlapping filename \"%s\"."),
+ filename);
+ else
+ cupsArrayAdd(filenames, strdup(filename));
+
+ fp = cupsFileOpen(filename, comp ? "w9" : "w");
+ if (!fp)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdc: Unable to create PPD file \"%s\" - %s."),
+ filename, strerror(errno));
+ return (1);
+ }
+
+ if (verbose)
+ _cupsLangPrintf(stdout, _("ppdc: Writing %s."), filename);
+ }
+
+ /*
+ * Write the PPD file...
+ */
+
+ ppdcArray *templocales = locales;
+
+ if (!templocales && !single_language)
+ {
+ templocales = new ppdcArray();
+ for (ppdcCatalog *tempcatalog = (ppdcCatalog *)src->po_files->first();
+ tempcatalog;
+ tempcatalog = (ppdcCatalog *)src->po_files->next())
+ {
+ tempcatalog->locale->retain();
+ templocales->add(tempcatalog->locale);
+ }
+ }
+
+ if (d->write_ppd_file(fp, catalog, templocales, src, le))
+ {
+ cupsFileClose(fp);
+ return (1);
+ }
+
+ if (templocales != locales)
+ templocales->release();
+
+ cupsFileClose(fp);
+ }
+ }
+ else
+ usage();
+
+ // Delete the printer driver information...
+ src->release();
+
+ // Message catalog...
+ if (catalog)
+ catalog->release();
+
+ // Return with no errors.
+ return (0);
+}
+
+
+//
+// 'usage()' - Show usage and exit.
+//
+
+static void
+usage(void)
+{
+ _cupsLangPuts(stdout, _("Usage: ppdc [options] filename.drv [ ... "
+ "filenameN.drv ]"));
+ _cupsLangPuts(stdout, _("Options:"));
+ _cupsLangPuts(stdout, _(" -D name=value Set named variable to "
+ "value."));
+ _cupsLangPuts(stdout, _(" -I include-dir Add include directory to "
+ "search path."));
+ _cupsLangPuts(stdout, _(" -c catalog.po Load the specified "
+ "message catalog."));
+ _cupsLangPuts(stdout, _(" -d output-dir Specify the output "
+ "directory."));
+ _cupsLangPuts(stdout, _(" -l lang[,lang,...] Specify the output "
+ "language(s) (locale)."));
+ _cupsLangPuts(stdout, _(" -m Use the ModelName value "
+ "as the filename."));
+ _cupsLangPuts(stdout, _(" -t Test PPDs instead of "
+ "generating them."));
+ _cupsLangPuts(stdout, _(" -v Be verbose (more v's for "
+ "more verbosity)."));
+ _cupsLangPuts(stdout, _(" -z Compress PPD files using "
+ "GNU zip."));
+ _cupsLangPuts(stdout, _(" --cr End lines with CR (Mac "
+ "OS 9)."));
+ _cupsLangPuts(stdout, _(" --crlf End lines with CR + LF "
+ "(Windows)."));
+ _cupsLangPuts(stdout, _(" --lf End lines with LF "
+ "(UNIX/Linux/Mac OS X)."));
+
+ exit(1);
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdc.h b/ppdc/ppdc.h
new file mode 100644
index 000000000..24c9f2c26
--- /dev/null
+++ b/ppdc/ppdc.h
@@ -0,0 +1,532 @@
+//
+// "$Id$"
+//
+// Definitions for the CUPS PPD Compiler.
+//
+// Copyright 2007-2009 by Apple Inc.
+// Copyright 2002-2007 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+
+#ifndef _PPDC_H_
+# define _PPDC_H_
+
+//
+// Include necessary headers...
+//
+
+# include <cups/file.h>
+# include <stdlib.h>
+
+
+//
+// Macros...
+//
+
+# define PPDC_NAME(s) const char *class_name() { return (s); }
+
+
+//
+// Enumerations...
+//
+
+enum ppdcDrvType //// Driver type
+{
+ PPDC_DRIVER_CUSTOM, // Custom driver
+ PPDC_DRIVER_PS, // PostScript driver
+ PPDC_DRIVER_ESCP, // rastertoescpx driver
+ PPDC_DRIVER_PCL, // rastertopclx driver
+ PPDC_DRIVER_LABEL, // rastertolabel/rastertodymo driver
+ PPDC_DRIVER_EPSON, // rastertoepson driver
+ PPDC_DRIVER_HP, // rastertohp driver
+ PPDC_DRIVER_MAX // Number of driver types defined
+};
+
+enum ppdcFontStatus //// Load status of font
+{
+ PPDC_FONT_ROM, // Font is in ROM
+ PPDC_FONT_DISK // Font is on disk
+};
+
+enum ppdcOptSection //// Option section
+{
+ PPDC_SECTION_ANY, // AnySetup
+ PPDC_SECTION_DOCUMENT, // DocumentSetup
+ PPDC_SECTION_EXIT, // ExitServer
+ PPDC_SECTION_JCL, // JCLSetup
+ PPDC_SECTION_PAGE, // PageSetup
+ PPDC_SECTION_PROLOG // Prolog
+};
+
+enum ppdcOptType //// Option type
+{
+ PPDC_BOOLEAN, // True/false option
+ PPDC_PICKONE, // Single choice from list
+ PPDC_PICKMANY // Multiple choices from list
+};
+
+enum ppdcLineEnding //// Line endings
+{
+ PPDC_LFONLY, // LF only
+ PPDC_CRONLY, // CR only
+ PPDC_CRLF // CR + LF
+};
+
+enum ppdcCondFlags //// Condition flags
+{
+ PPDC_COND_NORMAL = 0, // Normal state
+ PPDC_COND_SKIP = 1, // Skip state
+ PPDC_COND_SATISFIED = 2 // At least one condition satisfied
+};
+
+
+//
+// Printer description data...
+//
+
+class ppdcShared //// Shared Data Value
+{
+ private:
+
+ int use; // Use count (delete when 0)
+
+ public:
+
+ ppdcShared();
+ virtual ~ppdcShared();
+
+ virtual const char *class_name() = 0;
+
+ void retain();
+ void release();
+};
+
+class ppdcArray //// Shared Array
+ : public ppdcShared
+{
+ public:
+
+ int count, // Number of elements
+ alloc, // Allocated elements
+ current; // Current element
+ ppdcShared **data; // Elements
+
+ ppdcArray(ppdcArray *a = 0);
+ ~ppdcArray();
+
+ PPDC_NAME("ppdcArray")
+
+ void add(ppdcShared *d);
+ ppdcShared *first();
+ ppdcShared *next();
+ void remove(ppdcShared *d);
+};
+
+class ppdcString //// Shared String
+ : public ppdcShared
+{
+ public:
+
+ char *value; // String value
+
+ ppdcString(const char *v);
+ ~ppdcString();
+
+ PPDC_NAME("ppdcString")
+};
+
+class ppdcInteger //// Shared integer
+ : public ppdcShared
+{
+ public:
+
+ int *value; // Integer value
+
+ ppdcInteger(int *v) { value = v; }
+
+ PPDC_NAME("ppdcInteger")
+};
+
+class ppdcMessage //// Translation message
+ : public ppdcShared
+{
+ public:
+
+ ppdcString *id, // Translation ID
+ *string; // Translation string
+
+ ppdcMessage(const char *i, const char *s);
+ ~ppdcMessage();
+
+ PPDC_NAME("ppdcMessage")
+};
+
+class ppdcCatalog //// Translation catalog
+ : public ppdcShared
+{
+ public:
+
+ ppdcString *locale; // Name of locale
+ ppdcString *filename; // Name of translation file
+ ppdcArray *messages; // Array of translation messages
+
+ ppdcCatalog(const char *l, const char *f = 0);
+ ~ppdcCatalog();
+
+ PPDC_NAME("ppdcCatalog")
+
+ void add_message(const char *id, const char *string = NULL);
+ const char *find_message(const char *id);
+ int load_messages(const char *f);
+ int save_messages(const char *f);
+};
+
+class ppdcAttr //// Attribute
+ : public ppdcShared
+{
+ public:
+
+ ppdcString *name, // Name of attribute
+ *selector, // Selector string
+ *text, // Text string
+ *value; // Value string
+ bool localizable; // Should this attribute be localized?
+
+ ppdcAttr(const char *n, const char *s, const char *t, const char *v,
+ bool loc = false);
+ ~ppdcAttr();
+
+ PPDC_NAME("ppdcAttr")
+};
+
+class ppdcFont //// Shared Font
+ : public ppdcShared
+{
+ public:
+
+ ppdcString *name, // Font name
+ *encoding, // Font base encoding
+ *version, // Font version
+ *charset; // Font charset
+ ppdcFontStatus status; // Font status (ROM or Disk)
+
+ ppdcFont(const char *n, const char *e, const char *v, const char *c,
+ ppdcFontStatus s);
+ ~ppdcFont();
+
+ PPDC_NAME("ppdcFont")
+};
+
+class ppdcChoice //// Option Choice
+ : public ppdcShared
+{
+ public:
+
+ ppdcString *name, // Name of choice
+ *text, // Human-readable text of choice
+ *code; // PS code of choice
+
+ ppdcChoice(const char *n, const char *t, const char *c);
+ ~ppdcChoice();
+
+ PPDC_NAME("ppdcChoice")
+};
+
+class ppdcOption //// Option
+ : public ppdcShared
+{
+ public:
+
+ ppdcOptType type; // Type of option
+ ppdcString *name, // Name of option
+ *text; // Human-readable text of option
+ ppdcOptSection section; // Section for option code
+ float order; // Order number
+ ppdcArray *choices; // Choices
+ ppdcString *defchoice; // Default choice
+
+ ppdcOption(ppdcOptType ot, const char *n, const char *t, ppdcOptSection s,
+ float o);
+ ppdcOption(ppdcOption *o);
+ ~ppdcOption();
+
+ PPDC_NAME("ppdcOption")
+
+ void add_choice(ppdcChoice *c) { choices->add(c); }
+ ppdcChoice *find_choice(const char *n);
+ void set_defchoice(ppdcChoice *c);
+};
+
+class ppdcGroup //// Group of Options
+ : public ppdcShared
+{
+ public:
+
+ ppdcString *name, // Name of option
+ *text; // Human-readable text of option
+ ppdcArray *options; // Options
+
+ ppdcGroup(const char *n, const char *t);
+ ppdcGroup(ppdcGroup *g);
+ ~ppdcGroup();
+
+ PPDC_NAME("ppdcGroup")
+
+ void add_option(ppdcOption *o) { options->add(o); }
+ ppdcOption *find_option(const char *n);
+};
+
+class ppdcConstraint //// Constraint
+ : public ppdcShared
+{
+ public:
+
+ ppdcString *option1, // First option
+ *choice1, // First choice
+ *option2, // Second option
+ *choice2; // Second choice
+
+ ppdcConstraint(const char *o1, const char *c1, const char *o2,
+ const char *c2);
+ ~ppdcConstraint();
+
+ PPDC_NAME("ppdcConstraint")
+};
+
+class ppdcFilter //// Filter Program
+ : public ppdcShared
+{
+ public:
+
+ ppdcString *mime_type, // MIME type
+ *program; // Filter program
+ int cost; // Relative cost of filter
+
+ ppdcFilter(const char *t, const char *p, int c);
+ ~ppdcFilter();
+
+ PPDC_NAME("ppdcFilter")
+};
+
+class ppdcMediaSize //// Media Size
+ : public ppdcShared
+{
+ public:
+
+ ppdcString *name, // Name of size
+ *text; // Human-readable text
+ float width, // Width in points
+ length, // Length in points
+ left, // Left limit in points
+ bottom, // Bottom limit in points
+ right, // Right limit in points
+ top; // Top limit in points
+ ppdcString *size_code, // PageSize code, if any
+ *region_code; // PageRegion code, if any
+
+ ppdcMediaSize(const char *n, const char *t, float w, float l,
+ float lm, float bm, float rm, float tm,
+ const char *sc = 0, const char *rc = 0);
+ ~ppdcMediaSize();
+
+ PPDC_NAME("ppdcMediaSize")
+};
+
+class ppdcProfile //// Color Profile
+ : public ppdcShared
+{
+ public:
+
+ ppdcString *resolution, // Resolution name
+ *media_type; // Media type name
+ float density, // Color profile density
+ gamma, // Color profile gamma
+ profile[9]; // Color profile matrix
+
+ ppdcProfile(const char *r, const char *m, float d, float g, const float *p);
+ ~ppdcProfile();
+
+ PPDC_NAME("ppdcProfile")
+};
+
+class ppdcSource;
+
+class ppdcDriver //// Printer Driver Data
+ : public ppdcShared
+{
+ public:
+
+ ppdcDrvType type; // Driver type
+ ppdcArray *copyright; // Copyright strings
+ ppdcString *manufacturer, // Manufacturer
+ *model_name, // Name of printer model
+ *file_name, // Output filename for PPD
+ *pc_file_name, // 8 character PC filename for PPD
+ *version; // Version number
+ int model_number, // Model number for driver
+ manual_copies, // Do manual copies?
+ color_device, // Support color?
+ throughput; // Throughput in pages per minute
+ ppdcArray *attrs, // Attributes
+ *constraints, // Constraints
+ *filters, // Filters
+ *fonts, // Fonts
+ *groups, // Option groups
+ *profiles, // Color profiles
+ *sizes; // Fixed sizes
+ ppdcString *default_font, // Default font
+ *default_size; // Default size option
+ int variable_paper_size; // Support variable sizes?
+ ppdcString *custom_size_code; // Custom page size code, if any
+ float left_margin, // Margins for device in points
+ bottom_margin,
+ right_margin,
+ top_margin,
+ max_width, // Maximum width (points)
+ max_length, // Maximum length (points)
+ min_width, // Minimum width (points)
+ min_length; // Minimum length (points)
+
+ ppdcDriver(ppdcDriver *d = 0);
+ ~ppdcDriver();
+
+ PPDC_NAME("ppdcDriver")
+
+ void add_attr(ppdcAttr *a) { attrs->add(a); }
+ void add_constraint(ppdcConstraint *c) { constraints->add(c); }
+ void add_copyright(const char *c) {
+ copyright->add(new ppdcString(c));
+ }
+ void add_filter(ppdcFilter *f) { filters->add(f); }
+ void add_font(ppdcFont *f) { fonts->add(f); }
+ void add_group(ppdcGroup *g) { groups->add(g); }
+ void add_profile(ppdcProfile *p) { profiles->add(p); }
+ void add_size(ppdcMediaSize *m) { sizes->add(m); }
+
+ ppdcAttr *find_attr(const char *k, const char *s);
+ ppdcGroup *find_group(const char *n);
+ ppdcOption *find_option(const char *n);
+ ppdcOption *find_option_group(const char *n, ppdcGroup **mg);
+
+ void set_custom_size_code(const char *c);
+ void set_default_font(ppdcFont *f);
+ void set_default_size(ppdcMediaSize *m);
+ void set_file_name(const char *f);
+ void set_manufacturer(const char *m);
+ void set_model_name(const char *m);
+ void set_pc_file_name(const char *f);
+ void set_version(const char *v);
+
+ int write_ppd_file(cups_file_t *fp, ppdcCatalog *catalog,
+ ppdcArray *locales, ppdcSource *src,
+ ppdcLineEnding le);
+};
+
+class ppdcVariable //// Variable Definition
+ : public ppdcShared
+{
+ public:
+
+ ppdcString *name, // Name of variable
+ *value; // Value of variable
+
+ ppdcVariable(const char *n, const char *v);
+ ~ppdcVariable();
+
+ PPDC_NAME("ppdcVariable")
+
+ void set_value(const char *v);
+};
+
+class ppdcFile //// File
+{
+ public:
+
+ cups_file_t *fp; // File pointer
+ const char *filename; // Filename
+ int line; // Line in file
+
+ ppdcFile(const char *f, cups_file_t *ffp = (cups_file_t *)0);
+ ~ppdcFile();
+
+ int get();
+ int peek();
+};
+
+class ppdcSource //// Source File
+ : public ppdcShared
+{
+ public:
+
+ static ppdcArray *includes; // Include directories
+ static const char *driver_types[]; // Driver types
+
+ ppdcString *filename; // Filename
+ ppdcArray *base_fonts, // Base fonts
+ *drivers, // Printer drivers
+ *po_files, // Message catalogs
+ *sizes, // Predefined media sizes
+ *vars; // Defined variables
+ int cond_state, // Cummulative conditional state
+ *cond_current, // Current #if state
+ cond_stack[101]; // #if state stack
+
+
+ ppdcSource(const char *f = 0, cups_file_t *ffp = (cups_file_t *)0);
+ ~ppdcSource();
+
+ PPDC_NAME("ppdcSource")
+
+ static void add_include(const char *d);
+ ppdcDriver *find_driver(const char *f);
+ static char *find_include(const char *f, const char *base, char *n,
+ int nlen);
+ ppdcCatalog *find_po(const char *l);
+ ppdcMediaSize *find_size(const char *s);
+ ppdcVariable *find_variable(const char *n);
+ ppdcAttr *get_attr(ppdcFile *fp, bool loc = false);
+ int get_boolean(ppdcFile *fp);
+ ppdcChoice *get_choice(ppdcFile *fp);
+ ppdcChoice *get_color_model(ppdcFile *fp);
+ int get_color_order(const char *co);
+ ppdcProfile *get_color_profile(ppdcFile *fp);
+ int get_color_space(const char *cs);
+ ppdcConstraint *get_constraint(ppdcFile *fp);
+ ppdcMediaSize *get_custom_size(ppdcFile *fp);
+ void get_duplex(ppdcFile *fp, ppdcDriver *d);
+ ppdcFilter *get_filter(ppdcFile *fp);
+ float get_float(ppdcFile *fp);
+ ppdcFont *get_font(ppdcFile *fp);
+ ppdcChoice *get_generic(ppdcFile *fp, const char *keyword,
+ const char *tattr, const char *nattr);
+ ppdcGroup *get_group(ppdcFile *fp, ppdcDriver *d);
+ ppdcOption *get_installable(ppdcFile *fp);
+ int get_integer(const char *v);
+ int get_integer(ppdcFile *fp);
+ float get_measurement(ppdcFile *fp);
+ ppdcOption *get_option(ppdcFile *fp, ppdcDriver *d, ppdcGroup *g);
+ ppdcCatalog *get_po(ppdcFile *fp);
+ ppdcChoice *get_resolution(ppdcFile *fp);
+ ppdcProfile *get_simple_profile(ppdcFile *fp);
+ ppdcMediaSize *get_size(ppdcFile *fp);
+ char *get_token(ppdcFile *fp, char *buffer, int buflen);
+ ppdcVariable *get_variable(ppdcFile *fp);
+ int import_ppd(const char *f);
+ int quotef(cups_file_t *fp, const char *format, ...);
+ void read_file(const char *f, cups_file_t *ffp = (cups_file_t *)0);
+ void scan_file(ppdcFile *fp, ppdcDriver *td = 0, bool inc = false);
+ ppdcVariable *set_variable(const char *name, const char *value);
+ int write_file(const char *f);
+};
+
+
+#endif // !_PPDC_H_
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdhtml.cxx b/ppdc/ppdhtml.cxx
new file mode 100644
index 000000000..d5678898d
--- /dev/null
+++ b/ppdc/ppdhtml.cxx
@@ -0,0 +1,186 @@
+//
+// "$Id$"
+//
+// PPD to HTML utility for the CUPS PPD Compiler.
+//
+// Copyright 2007-2011 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// main() - Main entry for the PPD to HTML utility.
+// usage() - Show usage and exit.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+#include <sys/stat.h>
+#include <sys/types.h>
+
+
+//
+// Local functions...
+//
+
+static void usage(void);
+
+
+//
+// 'main()' - Main entry for the PPD compiler.
+//
+
+int // O - Exit status
+main(int argc, // I - Number of command-line arguments
+ char *argv[]) // I - Command-line arguments
+{
+ int i; // Looping var
+ ppdcSource *src; // PPD source file data
+ ppdcDriver *d; // Current driver
+ ppdcGroup *g, // Current group
+ *composite; // Composite of all drivers
+ ppdcOption *o, // Current option
+ *compo; // Composite option
+ ppdcChoice *c; // Current choice
+ char *opt; // Current option char
+ ppdcMediaSize *size; // Current media size
+ char *value; // Value in option
+
+
+ _cupsSetLocale(argv);
+
+ // Scan the command-line...
+ src = 0;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ {
+ for (opt = argv[i] + 1; *opt; opt ++)
+ switch (*opt)
+ {
+ case 'D' : // Define variable
+ i ++;
+ if (i >= argc)
+ usage();
+
+ if ((value = strchr(argv[i], '=')) != NULL)
+ {
+ *value++ = '\0';
+
+ src->set_variable(argv[i], value);
+ }
+ else
+ src->set_variable(argv[i], "1");
+ break;
+
+ case 'I' : // Include directory...
+ i ++;
+ if (i >= argc)
+ usage();
+
+ ppdcSource::add_include(argv[i]);
+ break;
+
+ default : // Unknown
+ usage();
+ break;
+ }
+ }
+ else
+ {
+ // Open and load the driver info file...
+ src = new ppdcSource(argv[i]);
+
+ // Create a composite group with all of the features from the
+ // drivers in the info file...
+ composite = new ppdcGroup("", "");
+
+ for (d = (ppdcDriver *)src->drivers->first(); d; d = (ppdcDriver *)src->drivers->next())
+ for (g = (ppdcGroup *)d->groups->first(); g; g = (ppdcGroup *)d->groups->next())
+ for (o = (ppdcOption *)g->options->first(); o; o = (ppdcOption *)g->options->next())
+ {
+ if ((compo = composite->find_option(o->name->value)) == NULL)
+ composite->add_option(new ppdcOption(o));
+ }
+
+ puts("<html>");
+ printf("<head><title>Driver Summary for %s</title></head>\n", argv[i]);
+ printf("<body><h1>Driver Summary for %s</h1>\n", argv[i]);
+ printf("<p><table border='1'><thead><tr><th>Printer</th><th>Media Size</th>");
+ for (compo = (ppdcOption *)composite->options->first(); compo; compo = (ppdcOption *)composite->options->next())
+ printf("<th>%s</th>", compo->text->value);
+ puts("</tr></thead><tbody>");
+
+ // Write HTML summary...
+ for (d = (ppdcDriver *)src->drivers->first(); d; d = (ppdcDriver *)src->drivers->next())
+ {
+ // Write the summary for this driver...
+ printf("<tr valign='top'><td nowrap>%s</td><td nowrap>", d->model_name->value);
+ for (size = (ppdcMediaSize *)d->sizes->first(); size;
+ size = (ppdcMediaSize *)d->sizes->next())
+ printf("%s<br>", size->text->value);
+ printf("</td>");
+
+ for (compo = (ppdcOption *)composite->options->first(); compo;
+ compo = (ppdcOption *)composite->options->next())
+ if ((o = d->find_option(compo->name->value)) != NULL)
+ {
+ printf("<td nowrap>");
+ for (c = (ppdcChoice *)o->choices->first(); c;
+ c = (ppdcChoice *)o->choices->next())
+ printf("%s<br>", c->text->value);
+ printf("</td>");
+ }
+ else
+ printf("<td>N/A</td>");
+
+ puts("</tr>");
+ }
+
+ puts("</tbody></table></p>");
+ puts("</body>");
+ puts("</html>");
+ // Delete the printer driver information...
+ composite->release();
+ src->release();
+ }
+
+ // If no drivers have been loaded, display the program usage message.
+ if (!src)
+ usage();
+
+ // Return with no errors.
+ return (0);
+}
+
+
+//
+// 'usage()' - Show usage and exit.
+//
+
+static void
+usage(void)
+{
+ _cupsLangPuts(stdout, _("Usage: ppdhtml [options] filename.drv "
+ ">filename.html"));
+ _cupsLangPuts(stdout, _("Options:"));
+ _cupsLangPuts(stdout, _(" -D name=value Set named variable to "
+ "value."));
+ _cupsLangPuts(stdout, _(" -I include-dir Add include directory "
+ "to search path."));
+
+ exit(1);
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdi.cxx b/ppdc/ppdi.cxx
new file mode 100644
index 000000000..a411bfef5
--- /dev/null
+++ b/ppdc/ppdi.cxx
@@ -0,0 +1,142 @@
+//
+// "$Id$"
+//
+// PPD file import utility for the CUPS PPD Compiler.
+//
+// Copyright 2007-2011 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// main() - Main entry for the PPD import utility.
+// usage() - Show usage and exit.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+
+//
+// Local functions...
+//
+
+static void usage(void);
+
+
+//
+// 'main()' - Main entry for the PPD import utility.
+//
+
+int // O - Exit status
+main(int argc, // I - Number of command-line arguments
+ char *argv[]) // I - Command-line arguments
+{
+ int i; // Looping var
+ char *opt; // Current option
+ const char *srcfile; // Output file
+ ppdcSource *src; // PPD source file data
+
+
+ _cupsSetLocale(argv);
+
+ // Scan the command-line...
+ srcfile = NULL;
+ src = NULL;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ {
+ for (opt = argv[i] + 1; *opt; opt ++)
+ switch (*opt)
+ {
+ case 'o' : // Output file
+ if (srcfile || src)
+ usage();
+
+ i ++;
+ if (i >= argc)
+ usage();
+
+ srcfile = argv[i];
+ break;
+
+ case 'I' : // Include dir
+ i ++;
+ if (i >= argc)
+ usage();
+
+ ppdcSource::add_include(argv[i]);
+ break;
+
+ default : // Unknown
+ usage();
+ break;
+ }
+ }
+ else
+ {
+ // Open and load the driver info file...
+ if (!srcfile)
+ srcfile = "ppdi.drv";
+
+ if (!src)
+ {
+ if (access(srcfile, 0))
+ src = new ppdcSource();
+ else
+ src = new ppdcSource(srcfile);
+ }
+
+ // Import the PPD file...
+ src->import_ppd(argv[i]);
+ }
+
+ // If no drivers have been loaded, display the program usage message.
+ if (!src)
+ usage();
+
+ // Write the driver info file back to disk...
+ src->write_file(srcfile);
+
+ // Delete the printer driver information...
+ src->release();
+
+ // Return with no errors.
+ return (0);
+}
+
+
+//
+// 'usage()' - Show usage and exit.
+//
+
+static void
+usage(void)
+{
+ _cupsLangPuts(stdout, _("Usage: ppdi [options] filename.ppd [ ... "
+ "filenameN.ppd ]"));
+ _cupsLangPuts(stdout, _("Options:"));
+ _cupsLangPuts(stdout, _(" -I include-dir Add include directory to "
+ "search path."));
+ _cupsLangPuts(stdout, _(" -o filename.drv Set driver information "
+ "file (otherwise ppdi.drv)."));
+
+ exit(1);
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdmerge.cxx b/ppdc/ppdmerge.cxx
new file mode 100644
index 000000000..68f291673
--- /dev/null
+++ b/ppdc/ppdmerge.cxx
@@ -0,0 +1,379 @@
+//
+// "$Id$"
+//
+// PPD file merge utility for the CUPS PPD Compiler.
+//
+// Copyright 2007-2011 by Apple Inc.
+// Copyright 2002-2007 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// main() - Main entry for the PPD merge utility.
+// ppd_locale() - Return the locale associated with a PPD file.
+// usage() - Show usage and exit.
+//
+
+//
+// Include necessary headers...
+//
+
+#include <cups/cups-private.h>
+#include <cups/ppd-private.h>
+#include <cups/array.h>
+
+
+//
+// Local functions...
+//
+
+static const char *ppd_locale(ppd_file_t *ppd);
+static void usage(void);
+
+
+//
+// 'main()' - Main entry for the PPD merge utility.
+//
+
+int // O - Exit status
+main(int argc, // I - Number of command-line arguments
+ char *argv[]) // I - Command-line arguments
+{
+ int i; // Looping var
+ char *opt; // Current option
+ ppd_file_t *ppd; // PPD file
+ cups_array_t *ppds; // Array of PPD files
+ const char *inname, // First input filename
+ *outname; // Output filename (if any)
+ cups_file_t *infile, // Input file
+ *outfile; // Output file
+ cups_array_t *languages; // Languages in file
+ const char *locale; // Current locale
+ char line[1024]; // Line from file
+
+
+ _cupsSetLocale(argv);
+
+ // Scan the command-line...
+ inname = NULL;
+ outname = NULL;
+ outfile = NULL;
+ languages = NULL;
+ ppds = cupsArrayNew(NULL, NULL);
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ {
+ for (opt = argv[i] + 1; *opt; opt ++)
+ switch (*opt)
+ {
+ case 'o' : // Output file
+ if (outname)
+ usage();
+
+ i ++;
+ if (i >= argc)
+ usage();
+
+ outname = argv[i];
+ break;
+
+ default : // Unknown
+ usage();
+ break;
+ }
+ }
+ else
+ {
+ // Open and load the PPD file...
+ if ((infile = cupsFileOpen(argv[i], "r")) == NULL)
+ {
+ _cupsLangPrintf(stderr, _("%s: Unable to open %s: %s"), "ppdmerge",
+ argv[i], strerror(errno));
+ return (1);
+ }
+
+ // Open the PPD file...
+ if ((ppd = ppdOpen2(infile)) == NULL)
+ {
+ ppd_status_t status; // PPD open status
+ int curline, // Current line
+ linenum; // Line number
+
+
+ status = ppdLastError(&linenum);
+
+ _cupsLangPrintf(stderr,
+ _("%s: Unable to open PPD file: %s on line %d."),
+ "ppdmerge", ppdErrorString(status), linenum);
+ cupsFileRewind(infile);
+
+ line[0] = '\0';
+ curline = 0;
+
+ while (cupsFileGets(infile, line, sizeof(line)))
+ {
+ curline ++;
+ if (curline >= linenum)
+ break;
+ }
+
+ _cupsLangPrintf(stderr, "%d: %s", linenum, line);
+
+ cupsFileClose(infile);
+ return (1);
+ }
+
+ // Figure out the locale...
+ if ((locale = ppd_locale(ppd)) == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdmerge: Bad LanguageVersion \"%s\" in %s."),
+ ppd->lang_version, argv[i]);
+ cupsFileClose(infile);
+ ppdClose(ppd);
+ return (1);
+ }
+
+ if (!strcmp(locale, "en") && !inname && !outfile)
+ {
+ // Set the English PPD's filename...
+ inname = argv[i];
+ languages = _ppdGetLanguages(ppd);
+
+ if (outname && !strcmp(inname, outname))
+ {
+ // Rename input filename so that we don't overwrite it...
+ char bckname[1024]; // Backup filename
+
+
+ snprintf(bckname, sizeof(bckname), "%s.bck", inname);
+
+ if (rename(inname, bckname))
+ {
+ _cupsLangPrintf(stderr,
+ _("ppdmerge: Unable to backup %s to %s - %s"),
+ inname, bckname, strerror(errno));
+ return (1);
+ }
+
+ inname = bckname;
+ }
+ }
+ else if (strcmp(locale, "en"))
+ {
+ // Save this PPD for later processing...
+ cupsArrayAdd(ppds, ppd);
+ }
+ else
+ {
+ // Don't need this PPD...
+ _cupsLangPrintf(stderr, _("ppdmerge: Ignoring PPD file %s."),
+ argv[i]);
+ ppdClose(ppd);
+ }
+
+ // Close and move on...
+ cupsFileClose(infile);
+ }
+
+ // If no PPDs have been loaded, display the program usage message.
+ if (!inname)
+ usage();
+
+ // Loop through the PPD files we loaded to generate a new language list...
+ if (!languages)
+ languages = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+
+ for (ppd = (ppd_file_t *)cupsArrayFirst(ppds);
+ ppd;
+ ppd = (ppd_file_t *)cupsArrayNext(ppds))
+ {
+ locale = ppd_locale(ppd);
+
+ if (cupsArrayFind(languages, (void *)locale))
+ {
+ // Already have this language, remove the PPD from the list.
+ ppdClose(ppd);
+ cupsArrayRemove(ppds, ppd);
+ }
+ else
+ cupsArrayAdd(languages, (void *)locale);
+ }
+
+ // Copy the English PPD starting with a cupsLanguages line...
+ infile = cupsFileOpen(inname, "r");
+
+ if (outname)
+ {
+ const char *ext = strrchr(outname, '.');
+ if (ext && !strcmp(ext, ".gz"))
+ outfile = cupsFileOpen(outname, "w9");
+ else
+ outfile = cupsFileOpen(outname, "w");
+ }
+ else
+ outfile = cupsFileStdout();
+
+ cupsFileGets(infile, line, sizeof(line));
+ cupsFilePrintf(outfile, "%s\n", line);
+ if ((locale = (char *)cupsArrayFirst(languages)) != NULL)
+ {
+ cupsFilePrintf(outfile, "*cupsLanguages: \"%s", locale);
+ while ((locale = (char *)cupsArrayNext(languages)) != NULL)
+ cupsFilePrintf(outfile, " %s", locale);
+ cupsFilePuts(outfile, "\"\n");
+ }
+
+ while (cupsFileGets(infile, line, sizeof(line)))
+ {
+ if (strncmp(line, "*cupsLanguages:", 15))
+ cupsFilePrintf(outfile, "%s\n", line);
+ }
+
+ // Loop through the other PPD files we loaded to provide the translations...
+ for (ppd = (ppd_file_t *)cupsArrayFirst(ppds);
+ ppd;
+ ppd = (ppd_file_t *)cupsArrayNext(ppds))
+ {
+ // Output all of the UI text for this language...
+ int j, k, l; // Looping vars
+ ppd_group_t *g; // Option group
+ ppd_option_t *o; // Option
+ ppd_choice_t *c; // Choice
+ ppd_coption_t *co; // Custom option
+ ppd_cparam_t *cp; // Custom parameter
+ ppd_attr_t *attr; // PPD attribute
+
+ locale = ppd_locale(ppd);
+
+ cupsFilePrintf(outfile, "*%% %s localization\n", ppd->lang_version);
+ cupsFilePrintf(outfile, "*%s.Translation ModelName/%s: \"\"\n", locale,
+ ppd->modelname);
+
+ for (j = ppd->num_groups, g = ppd->groups; j > 0; j --, g ++)
+ {
+ cupsFilePrintf(outfile, "*%s.Translation %s/%s: \"\"\n", locale,
+ g->name, g->text);
+
+ for (k = g->num_options, o = g->options; k > 0; k --, o ++)
+ {
+ cupsFilePrintf(outfile, "*%s.Translation %s/%s: \"\"\n", locale,
+ o->keyword, o->text);
+
+ for (l = o->num_choices, c = o->choices; l > 0; l --, c ++)
+ cupsFilePrintf(outfile, "*%s.%s %s/%s: \"\"\n", locale,
+ o->keyword, c->choice, c->text);
+
+ if ((co = ppdFindCustomOption(ppd, o->keyword)) != NULL)
+ {
+ snprintf(line, sizeof(line), "Custom%s", o->keyword);
+ attr = ppdFindAttr(ppd, line, "True");
+ cupsFilePrintf(outfile, "*%s.Custom%s True/%s: \"\"\n", locale,
+ o->keyword, attr->text);
+ for (cp = ppdFirstCustomParam(co); cp; cp = ppdNextCustomParam(co))
+ cupsFilePrintf(outfile, "*%s.ParamCustom%s %s/%s: \"\"\n", locale,
+ o->keyword, cp->name, cp->text);
+ }
+ }
+ }
+
+ ppdClose(ppd);
+ }
+
+ cupsArrayDelete(ppds);
+
+ cupsFileClose(outfile);
+
+ // Return with no errors.
+ return (0);
+}
+
+
+//
+// 'ppd_locale()' - Return the locale associated with a PPD file.
+//
+
+static const char * // O - Locale string
+ppd_locale(ppd_file_t *ppd) // I - PPD file
+{
+ int i, // Looping var
+ vlen; // Length of LanguageVersion string
+ static char locale[255]; // Locale string
+ static struct // LanguageVersion translation table
+ {
+ const char *version, // LanguageVersion string */
+ *language; // Language code */
+ } languages[] =
+ {
+ { "chinese", "zh" },
+ { "czech", "cs" },
+ { "danish", "da" },
+ { "dutch", "nl" },
+ { "english", "en" },
+ { "finnish", "fi" },
+ { "french", "fr" },
+ { "german", "de" },
+ { "greek", "el" },
+ { "hungarian", "hu" },
+ { "italian", "it" },
+ { "japanese", "ja" },
+ { "korean", "ko" },
+ { "norwegian", "no" },
+ { "polish", "pl" },
+ { "portuguese", "pt" },
+ { "russian", "ru" },
+ { "simplified chinese", "zh_CN" },
+ { "slovak", "sk" },
+ { "spanish", "es" },
+ { "swedish", "sv" },
+ { "traditional chinese", "zh_TW" },
+ { "turkish", "tr" }
+ };
+
+
+ for (i = 0; i < (int)(sizeof(languages) / sizeof(languages[0])); i ++)
+ {
+ vlen = strlen(languages[i].version);
+
+ if (!_cups_strncasecmp(ppd->lang_version, languages[i].version, vlen))
+ {
+ if (ppd->lang_version[vlen] == '-' ||
+ ppd->lang_version[vlen] == '_')
+ snprintf(locale, sizeof(locale), "%s_%s", languages[i].language,
+ ppd->lang_version + vlen + 1);
+ else
+ strlcpy(locale, languages[i].language, sizeof(locale));
+
+ return (locale);
+ }
+ }
+
+ return (NULL);
+}
+
+//
+// 'usage()' - Show usage and exit.
+//
+
+static void
+usage(void)
+{
+ _cupsLangPuts(stdout, _("Usage: ppdmerge [options] filename.ppd [ ... "
+ "filenameN.ppd ]"));
+ _cupsLangPuts(stdout, _("Options:"));
+ _cupsLangPuts(stdout, _(" -o filename.ppd[.gz] Set output file "
+ "(otherwise stdout)."));
+
+ exit(1);
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/ppdpo.cxx b/ppdc/ppdpo.cxx
new file mode 100644
index 000000000..bdf0f7c05
--- /dev/null
+++ b/ppdc/ppdpo.cxx
@@ -0,0 +1,268 @@
+//
+// "$Id$"
+//
+// PPD file message catalog program for the CUPS PPD Compiler.
+//
+// Copyright 2007-2011 by Apple Inc.
+// Copyright 2002-2005 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// main() - Main entry for the PPD compiler.
+// add_ui_strings() - Add all UI strings from the driver.
+// usage() - Show usage and exit.
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+#include <sys/stat.h>
+#include <sys/types.h>
+
+
+//
+// Local functions...
+//
+
+static void add_ui_strings(ppdcDriver *d, ppdcCatalog *catalog);
+static void usage(void);
+
+
+//
+// 'main()' - Main entry for the PPD compiler.
+//
+
+int // O - Exit status
+main(int argc, // I - Number of command-line arguments
+ char *argv[]) // I - Command-line arguments
+{
+ int i; // Looping var
+ ppdcCatalog *catalog; // Message catalog
+ ppdcSource *src; // PPD source file data
+ ppdcDriver *d; // Current driver
+ char *opt; // Current option
+ int verbose; // Verbosity
+ const char *outfile; // Output file
+ char *value; // Value in option
+
+
+ _cupsSetLocale(argv);
+
+ // Scan the command-line...
+ catalog = new ppdcCatalog("en");
+ src = 0;
+ verbose = 0;
+ outfile = 0;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ {
+ for (opt = argv[i] + 1; *opt; opt ++)
+ switch (*opt)
+ {
+ case 'D' : // Define variable
+ i ++;
+ if (i >= argc)
+ usage();
+
+ if ((value = strchr(argv[i], '=')) != NULL)
+ {
+ *value++ = '\0';
+
+ src->set_variable(argv[i], value);
+ }
+ else
+ src->set_variable(argv[i], "1");
+ break;
+
+ case 'I' : // Include directory...
+ i ++;
+ if (i >= argc)
+ usage();
+
+ if (verbose > 1)
+ _cupsLangPrintf(stdout,
+ _("ppdc: Adding include directory \"%s\"."),
+ argv[i]);
+
+ ppdcSource::add_include(argv[i]);
+ break;
+
+ case 'o' : // Output file...
+ i ++;
+ if (i >= argc || outfile)
+ usage();
+
+ outfile = argv[i];
+
+ catalog->load_messages(outfile);
+ break;
+
+ case 'v' : // Be verbose...
+ verbose ++;
+ break;
+
+ default : // Unknown
+ usage();
+ break;
+ }
+ }
+ else
+ {
+ // Open and load the driver info file...
+ if (verbose > 1)
+ _cupsLangPrintf(stdout,
+ _("ppdc: Loading driver information file \"%s\"."),
+ argv[i]);
+
+ src = new ppdcSource(argv[i]);
+
+ // Add UI strings...
+ for (d = (ppdcDriver *)src->drivers->first();
+ d;
+ d = (ppdcDriver *)src->drivers->next())
+ {
+ if (verbose)
+ _cupsLangPrintf(stderr, _("ppdc: Adding/updating UI text from %s."),
+ argv[i]);
+
+ add_ui_strings(d, catalog);
+ }
+
+ // Delete the printer driver information...
+ src->release();
+ }
+
+ // Write the message catalog...
+ if (!outfile)
+ usage();
+ else
+ catalog->save_messages(outfile);
+
+ catalog->release();
+
+ // If no drivers have been loaded, display the program usage message.
+ if (!src)
+ usage();
+
+ // Return with no errors.
+ return (0);
+}
+
+
+//
+// 'add_ui_strings()' - Add all UI strings from the driver.
+//
+
+static void
+add_ui_strings(ppdcDriver *d, // I - Driver data
+ ppdcCatalog *catalog) // I - Message catalog
+{
+ // Add the make/model/language strings...
+ catalog->add_message(d->manufacturer->value);
+ catalog->add_message(d->model_name->value);
+
+ // Add the media size strings...
+ ppdcMediaSize *m; // Current media size
+
+ for (m = (ppdcMediaSize *)d->sizes->first();
+ m;
+ m = (ppdcMediaSize *)d->sizes->next())
+ catalog->add_message(m->text->value);
+
+ // Add the group/option/choice strings...
+ ppdcGroup *g; // Current group
+ ppdcOption *o; // Current option
+ ppdcChoice *c; // Current choice
+
+ for (g = (ppdcGroup *)d->groups->first();
+ g;
+ g = (ppdcGroup *)d->groups->next())
+ {
+ if (!g->options->count)
+ continue;
+
+ if (_cups_strcasecmp(g->name->value, "General"))
+ catalog->add_message(g->text->value);
+
+ for (o = (ppdcOption *)g->options->first();
+ o;
+ o = (ppdcOption *)g->options->next())
+ {
+ if (!o->choices->count)
+ continue;
+
+ if (o->text->value)
+ catalog->add_message(o->text->value);
+ else
+ catalog->add_message(o->name->value);
+
+ for (c = (ppdcChoice *)o->choices->first();
+ c;
+ c = (ppdcChoice *)o->choices->next())
+ if (c->text->value)
+ catalog->add_message(c->text->value);
+ else
+ catalog->add_message(c->name->value);
+ }
+ }
+
+ // Add profile and preset strings...
+ ppdcAttr *a; // Current attribute
+ for (a = (ppdcAttr *)d->attrs->first();
+ a;
+ a = (ppdcAttr *)d->attrs->next())
+ if (a->text->value && a->text->value[0] &&
+ (a->localizable ||
+ !strncmp(a->name->value, "Custom", 6) ||
+ !strncmp(a->name->value, "ParamCustom", 11) ||
+ !strcmp(a->name->value, "APCustomColorMatchingName") ||
+ !strcmp(a->name->value, "APPrinterPreset") ||
+ !strcmp(a->name->value, "cupsICCProfile") ||
+ !strcmp(a->name->value, "cupsIPPReason") ||
+ !strcmp(a->name->value, "cupsMarkerName")))
+ {
+ catalog->add_message(a->text->value);
+
+ if ((a->localizable && a->value->value[0]) ||
+ !strcmp(a->name->value, "cupsIPPReason"))
+ catalog->add_message(a->value->value);
+ }
+ else if (!strncmp(a->name->value, "Custom", 6) ||
+ !strncmp(a->name->value, "ParamCustom", 11))
+ catalog->add_message(a->name->value);
+}
+
+
+//
+// 'usage()' - Show usage and exit.
+//
+
+static void
+usage(void)
+{
+ _cupsLangPuts(stdout, _("Usage: ppdpo [options] -o filename.po filename.drv "
+ "[ ... filenameN.drv ]"));
+ _cupsLangPuts(stdout, _("Options:"));
+ _cupsLangPuts(stdout, _(" -D name=value Set named variable to "
+ "value."));
+ _cupsLangPuts(stdout, _(" -I include-dir Add include directory to "
+ "search path."));
+ _cupsLangPuts(stdout, _(" -v Be verbose (more v's for "
+ "more verbosity)."));
+
+ exit(1);
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/sample.drv b/ppdc/sample.drv
new file mode 100644
index 000000000..9410cd787
--- /dev/null
+++ b/ppdc/sample.drv
@@ -0,0 +1,1254 @@
+//
+// "$Id$"
+//
+// Driver info file for CUPS-supplied PPDs.
+//
+// Copyright 2007-2011 by Apple Inc.
+// Copyright 1993-2006 by Easy Software Products.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+
+// Include necessary files...
+#include <font.defs>
+#include <media.defs>
+#include <hp.h>
+#include <epson.h>
+#include <label.h>
+
+// Localizations are provided for all of the base languages supported by
+// CUPS...
+//#po da ""
+//#po de ""
+//#po es ""
+//#po et ""
+//#po fi ""
+//#po fr ""
+//#po he ""
+//#po id ""
+//#po it ""
+//#po ja ""
+//#po ko ""
+//#po nl ""
+//#po no ""
+//#po pl ""
+//#po pt ""
+//#po pt_BR ""
+//#po ru ""
+//#po sv ""
+//#po zh ""
+//#po zh_TW ""
+
+// MediaSize sizes used by label drivers...
+#media "w81h252/Address - 1 1/8 x 3 1/2\"" 81 252
+#media "w101h252/Large Address - 1 4/10 x 3 1/2\"" 101 252
+#media "w54h144/Return Address - 3/4 x 2\"" 54 144
+#media "w167h288/Shipping Address - 2 5/16 x 4\"" 167 288
+#media "w162h540/Internet Postage 2-Part - 2 1/4 x 7 1/2\"" 162 540
+#media "w162h504/Internet Postage 3-Part - 2 1/4 x 7\"" 162 504
+#media "w41h248/File Folder - 9/16 x 3 7/16\"" 41 248
+#media "w41h144/Hanging Folder - 9/16 x 2\"" 41 144
+#media "w153h198/3.5\" Disk - 2 1/8 x 2 3/4\"" 153 198
+#media "w90h18/1.25x0.25\"" 90 18
+#media "w90h162/1.25x2.25\"" 90 162
+#media "w108h18/1.50x0.25\"" 108 18
+#media "w108h36/1.50x0.50\"" 108 36
+#media "w108h72/1.50x1.00\"" 108 72
+#media "w108h144/1.50x2.00\"" 108 144
+#media "w144h26/2.00x0.37\"" 144 26
+#media "w144h36/2.00x0.50\"" 144 36
+#media "w144h72/2.00x1.00\"" 144 72
+#media "w144h90/2.00x1.25\"" 144 90
+#media "w144h144/2.00x2.00\"" 144 144
+#media "w144h216/2.00x3.00\"" 144 216
+#media "w144h288/2.00x4.00\"" 144 288
+#media "w144h396/2.00x5.50\"" 144 396
+#media "w162h36/2.25x0.50\"" 162 36
+#media "w162h90/2.25x1.25\"" 162 90
+#media "w162h288/2.25x4.00\"" 162 288
+#media "w162h396/2.25x5.50\"" 162 396
+#media "w171h396/2.38x5.50\"" 171 396
+#media "w180h72/2.50x1.00\"" 180 72
+#media "w180h144/2.50x2.00\"" 180 144
+#media "w198h90/2.75x1.25\"" 198 90
+#media "w209h72/2.9 x 1\"" 209 72
+#media "w216h72/3.00x1.00\"" 216 72
+#media "w216h90/3.00x1.25\"" 216 90
+#media "w216h144/3.00x2.00\"" 216 144
+#media "w216h216/3.00x3.00\"" 216 216
+#media "w216h360/3.00x5.00\"" 216 360
+#media "w234h144/3.25x2.00\"" 234 144
+#media "w234h360/3.25x5.00\"" 234 360
+#media "w234h396/3.25x5.50\"" 234 396
+#media "w234h419/3.25x5.83\"" 234 419
+#media "w234h563/3.25x7.83\"" 234 563
+#media "w252h72/3.50x1.00\"" 252 72
+#media "w288h72/4.00x1.00\"" 288 72
+#media "w288h144/4.00x2.00\"" 288 144
+#media "w288h180/4.00x2.50\"" 288 180
+#media "w288h216/4.00x3.00\"" 288 216
+#media "w288h288/4.00x4.00\"" 288 288
+#media "w288h360/4.00x5.00\"" 288 360
+#media "w288h432/4.00x6.00\"" 288 432
+#media "w288h468/4.00x6.50\"" 288 468
+#media "w288h936/4.00x13.00\"" 288 936
+#media "w432h72/6.00x1.00\"" 432 72
+#media "w432h144/6.00x2.00\"" 432 144
+#media "w432h216/6.00x3.00\"" 432 216
+#media "w432h288/6.00x4.00\"" 432 288
+#media "w432h360/6.00x5.00\"" 432 360
+#media "w432h432/6.00x6.00\"" 432 432
+#media "w432h468/6.00x6.50\"" 432 468
+#media "w576h72/8.00x1.00\"" 576 72
+#media "w576h144/8.00x2.00\"" 576 144
+#media "w576h216/8.00x3.00\"" 576 216
+#media "w576h288/8.00x4.00\"" 576 288
+#media "w576h360/8.00x5.00\"" 576 360
+#media "w576h432/8.00x6.00\"" 576 432
+#media "w576h468/8.00x6.50\"" 576 468
+
+// Common stuff for all drivers...
+Attribute "cupsVersion" "" "1.5"
+Attribute "FileSystem" "" "False"
+Attribute "LandscapeOrientation" "" "Plus90"
+Attribute "TTRasterizer" "" "Type42"
+
+Copyright "Copyright 2007-2011 by Apple Inc."
+Copyright "Copyright 1997-2007 by Easy Software Products."
+Copyright ""
+Copyright "These coded instructions, statements, and computer programs are the"
+Copyright "property of Apple Inc. and are protected by Federal copyright"
+Copyright "law. Distribution and use rights are outlined in the file \"LICENSE.txt\""
+Copyright "which should have been included with this file. If this file is"
+Copyright "file is missing or damaged, see the license at \"http://www.cups.org/\"."
+
+Font *
+
+Version "1.5"
+
+// Dymo Label Printer
+{
+ Manufacturer "Dymo"
+ ModelName "Label Printer"
+ Attribute NickName "" "Dymo Label Printer"
+ PCFileName "dymo.ppd"
+ DriverType label
+ ModelNumber $DYMO_3x0
+ Throughput 8
+ ManualCopies Yes
+ ColorDevice No
+
+ HWMargins 2 14.9 2 14.9
+
+ *MediaSize w81h252
+ MediaSize w101h252
+ MediaSize w54h144
+ MediaSize w167h288
+ MediaSize w162h540
+ MediaSize w162h504
+ MediaSize w41h248
+ MediaSize w41h144
+ MediaSize w153h198
+
+ Resolution k 1 0 0 0 136dpi
+ Resolution k 1 0 0 0 203dpi
+ *Resolution k 1 0 0 0 300dpi
+
+ Darkness 0 Light
+ Darkness 1 Medium
+ *Darkness 2 Normal
+ Darkness 3 Dark
+}
+
+// Epson
+{
+ Manufacturer "Epson"
+ DriverType epson
+ ManualCopies Yes
+ ColorDevice No
+ Throughput 1
+
+ HWMargins 0 0 0 0
+ VariablePaperSize Yes
+ MinSize 36 36
+ MaxSize 1080 86400
+
+ // Epson 24-Pin Series
+ {
+ ModelName "24-Pin Series"
+ Attribute NickName "" "Epson 24-Pin Series"
+ PCFileName "epson24.ppd"
+ ModelNumber $EPSON_24PIN
+
+ HWMargins 18 18 18 18
+ *MediaSize Letter
+ MediaSize Legal
+ MediaSize A4
+ MediaSize FanFoldUS
+
+ Resolution k 1 8 0 0 60dpi
+ *Resolution k 1 8 0 0 120x60dpi
+ Resolution k 1 24 0 0 180dpi
+ Resolution k 1 24 0 0 360x180dpi
+ Resolution k 1 48 0 0 360dpi
+ }
+
+ // Epson 9-Pin Series
+ {
+ ModelName "9-Pin Series"
+ Attribute NickName "" "Epson 9-Pin Series"
+ PCFileName "epson9.ppd"
+ ModelNumber $EPSON_9PIN
+ ColorDevice No
+
+ HWMargins 18 18 18 18
+ *MediaSize Letter
+ MediaSize Legal
+ MediaSize A4
+ MediaSize FanFoldUS
+
+ Resolution k 1 8 0 0 60x72dpi
+ *Resolution k 1 8 0 0 120x72dpi
+ Resolution k 1 8 0 0 240x72dpi
+ }
+
+ // Epson Stylus Color Series
+ {
+ ModelName "Stylus Color Series"
+ Attribute NickName "" "Epson Stylus Color Series"
+ PCFileName "stcolor.ppd"
+ ModelNumber $EPSON_COLOR
+ ColorDevice Yes
+
+ HWMargins 8.6 39.6 8.6 25.51
+ *MediaSize Letter
+ MediaSize Legal
+ MediaSize A4
+
+ Resolution - 1 0 0 0 180dpi
+ *Resolution - 1 0 0 0 360dpi
+ Resolution - 1 0 0 0 720dpi
+
+ *ColorModel CMYK cmyk banded 1
+ ColorModel Gray/Grayscale k chunky 1
+ }
+
+ // Epson New Stylus Color Series
+ {
+ ModelName "New Stylus Color Series"
+ Attribute NickName "" "Epson New Stylus Color Series"
+ PCFileName "stcolor2.ppd"
+ ModelNumber $EPSON_ICOLOR
+ ColorDevice Yes
+
+ HWMargins 8.6 39.6 8.6 25.51
+ *MediaSize Letter
+ MediaSize Legal
+ MediaSize A4
+
+ Resolution - 1 0 0 0 180dpi
+ *Resolution - 1 0 0 0 360dpi
+ Resolution - 1 0 0 0 720dpi
+
+ *ColorModel CMYK cmyk banded 1
+ ColorModel Gray/Grayscale k chunky 1
+ }
+
+ // Epson Stylus Color Series
+ {
+ ModelName "Stylus Photo Series"
+ Attribute NickName "" "Epson Stylus Photo Series"
+ PCFileName "stphoto.ppd"
+ ModelNumber $EPSON_PHOTO
+ ColorDevice Yes
+
+ HWMargins 8.6 39.6 8.6 25.51
+ *MediaSize Letter
+ MediaSize Legal
+ MediaSize A4
+
+ Resolution - 1 0 0 0 180dpi
+ *Resolution - 1 0 0 0 360dpi
+ Resolution - 1 0 0 0 720dpi
+
+ *ColorModel CMYK cmykcm banded 1
+ ColorModel Gray/Grayscale k chunky 1
+ }
+
+ // Epson New Stylus Color Series
+ {
+ ModelName "New Stylus Photo Series"
+ Attribute NickName "" "Epson New Stylus Photo Series"
+ PCFileName "stphoto2.ppd"
+ ModelNumber $EPSON_IPHOTO
+ ColorDevice Yes
+
+ HWMargins 8.6 39.6 8.6 25.51
+ *MediaSize Letter
+ MediaSize Legal
+ MediaSize A4
+
+ Resolution - 1 0 0 0 180dpi
+ *Resolution - 1 0 0 0 360dpi
+ Resolution - 1 0 0 0 720dpi
+
+ *ColorModel CMYK cmykcm banded 1
+ ColorModel Gray/Grayscale k chunky 1
+ }
+}
+
+// Generic drivers
+{
+ Manufacturer "Generic"
+
+ // Generic PCL Laser Printer
+ {
+ DriverType hp
+
+ ModelName "PCL Laser Printer"
+ Attribute NickName "" "Generic PCL Laser Printer"
+ PCFileName "generpcl.ppd"
+ Throughput 8
+ ModelNumber $HP_LASERJET
+ ColorDevice No
+ Attribute 1284DeviceID "" "CMD:PCL;"
+
+ UIConstraints "*Duplex *Option1 False"
+ UIConstraints "*PageSize A3 *InputSlot Envelope"
+ UIConstraints "*PageSize A4 *InputSlot Envelope"
+ UIConstraints "*PageSize A5 *InputSlot Envelope"
+ UIConstraints "*PageSize B5 *InputSlot Envelope"
+ UIConstraints "*PageSize Executive *InputSlot Envelope"
+ UIConstraints "*PageSize Legal *InputSlot Envelope"
+ UIConstraints "*PageSize Letter *InputSlot Envelope"
+ UIConstraints "*PageSize Tabloid *InputSlot Envelope"
+
+ HWMargins 18 12 18 12
+ *MediaSize Letter
+ MediaSize Legal
+ MediaSize Executive
+ MediaSize Tabloid
+ MediaSize A3
+ MediaSize A4
+ MediaSize A5
+ MediaSize B5
+ MediaSize EnvISOB5
+ MediaSize Env10
+ MediaSize EnvC5
+ MediaSize EnvDL
+ MediaSize EnvMonarch
+
+ *Resolution k 1 0 0 0 300dpi
+ Resolution k 1 0 0 0 600dpi
+
+ *InputSlot 0 "Default/Printer Default"
+ InputSlot 8 "Tray1/Tray 1"
+ InputSlot 1 "Tray2/Tray 2"
+ InputSlot 4 "Tray3/Tray 3"
+ InputSlot 5 "Tray4/Tray 4"
+ InputSlot 2 "Manual/Manual Feed"
+ InputSlot 3 "Envelope/Envelope Feed"
+
+ Duplex Yes
+ Installable "Option1/Duplexer"
+ }
+
+ // Generic PostScript Printer
+ {
+ DriverType ps
+
+ ModelName "PostScript Printer"
+ Attribute NickName "" "Generic PostScript Printer"
+ PCFileName "generic.ppd"
+ Throughput 8
+ ColorDevice Yes
+ Attribute PSVersion "" "(2016.0) 0"
+ Attribute LanguageLevel "" 2
+ Attribute 1284DeviceID "" "CMD:PS;"
+
+ UIConstraints "*Duplex *Option1 False"
+
+ HWMargins 12 12 12 12
+ *MediaSize Letter
+ MediaSize Legal
+ MediaSize Executive
+ MediaSize Tabloid
+ MediaSize A3
+ MediaSize A4
+ MediaSize A5
+ MediaSize B5
+ MediaSize EnvISOB5
+ MediaSize Env10
+ MediaSize EnvC5
+ MediaSize EnvDL
+ MediaSize EnvMonarch
+
+ Option "InputSlot/Media Source" PickOne AnySetup 10
+ *Choice "Default/Printer Default" ""
+ Choice "Upper/Cassette" "<</ManualFeed false>>setpagedevice"
+ Choice "Manual/Manual Feed" "<</ManualFeed true>>setpagedevice"
+
+ Duplex Yes
+ Installable "Option1/Duplexer"
+ Attribute "?Option1" "" "save currentpagedevice/Duplex known{(True)}{(False)}ifelse = flush restore"
+ }
+}
+
+// HP
+{
+ Manufacturer "HP"
+ DriverType hp
+
+ // HP DeskJet Series
+ {
+ ModelName "DeskJet Series"
+ Attribute NickName "" "HP DeskJet Series"
+ PCFileName "deskjet.ppd"
+ ModelNumber $HP_DESKJET
+ ManualCopies Yes
+ ColorDevice Yes
+ Throughput 1
+ Attribute 1284DeviceID "" "MFG:HP;MDL:HP DeskJet;CMD:PCL;"
+
+ UIConstraints "*PageSize A3 *InputSlot Envelope"
+ UIConstraints "*PageSize A4 *InputSlot Envelope"
+ UIConstraints "*PageSize A5 *InputSlot Envelope"
+ UIConstraints "*PageSize B5 *InputSlot Envelope"
+ UIConstraints "*PageSize Executive *InputSlot Envelope"
+ UIConstraints "*PageSize Legal *InputSlot Envelope"
+ UIConstraints "*PageSize Letter *InputSlot Envelope"
+ UIConstraints "*PageSize Tabloid *InputSlot Envelope"
+
+ HWMargins 18 36 18 36
+ *MediaSize Letter
+ MediaSize Legal
+ MediaSize Executive
+ MediaSize Tabloid
+ MediaSize A3
+ MediaSize A4
+ MediaSize A5
+ MediaSize B5
+ MediaSize EnvISOB5
+ MediaSize Env10
+ MediaSize EnvC5
+ MediaSize EnvDL
+ MediaSize EnvMonarch
+
+ ColorModel Gray/Grayscale k chunky 2
+ ColorModel RGB/Color cmy banded 2
+ *ColorModel CMYK kcmy banded 2
+
+ Resolution - 1 0 0 0 150dpi
+ *Resolution - 1 0 0 0 300dpi
+ Resolution - 1 0 0 0 600dpi
+
+ *InputSlot 1 Tray
+ InputSlot 2 "Manual/Manual Feed"
+ InputSlot 3 "Envelope/Envelope Feed"
+
+ *MediaType 0 "Plain/Plain Paper"
+ MediaType 1 "Bond/Bond Paper"
+ MediaType 2 "Special/Special Paper"
+ MediaType 3 Transparency
+ MediaType 4 "Glossy/Glossy Paper"
+ }
+
+ // HP LaserJet Series PCL 4/5
+ {
+ ModelName "LaserJet Series PCL 4/5"
+ Attribute NickName "" "HP LaserJet Series PCL 4/5"
+ PCFileName "laserjet.ppd"
+ Throughput 8
+ ModelNumber $HP_LASERJET
+ ColorDevice No
+ Attribute 1284DeviceID "" "MFG:HP;MDL:HP LaserJet;CMD:PCL;"
+
+ UIConstraints "*Duplex *Option1 False"
+ UIConstraints "*PageSize A3 *InputSlot Envelope"
+ UIConstraints "*PageSize A4 *InputSlot Envelope"
+ UIConstraints "*PageSize A5 *InputSlot Envelope"
+ UIConstraints "*PageSize B5 *InputSlot Envelope"
+ UIConstraints "*PageSize Executive *InputSlot Envelope"
+ UIConstraints "*PageSize Legal *InputSlot Envelope"
+ UIConstraints "*PageSize Letter *InputSlot Envelope"
+ UIConstraints "*PageSize Tabloid *InputSlot Envelope"
+
+ HWMargins 18 36 18 36
+ *MediaSize Letter
+ MediaSize Legal
+ MediaSize Executive
+ MediaSize Tabloid
+ MediaSize A3
+ MediaSize A4
+ MediaSize A5
+ MediaSize B5
+ MediaSize EnvISOB5
+ MediaSize Env10
+ MediaSize EnvC5
+ MediaSize EnvDL
+ MediaSize EnvMonarch
+
+ Resolution k 1 0 0 0 150dpi
+ *Resolution k 1 0 0 0 300dpi
+ Resolution k 1 0 0 0 600dpi
+
+ *InputSlot 0 "Default/Printer Default"
+ InputSlot 8 "Tray1/Tray 1"
+ InputSlot 1 "Tray2/Tray 2"
+ InputSlot 4 "Tray3/Tray 3"
+ InputSlot 5 "Tray4/Tray 4"
+ InputSlot 2 "Manual/Manual Feed"
+ InputSlot 3 "Envelope/Envelope Feed"
+
+ Duplex Yes
+ Installable "Option1/Duplexer"
+ }
+}
+
+// Intellitech IntelliBar Series Label Printer
+{
+ Manufacturer "Intellitech"
+ ModelName "IntelliBar Label Printer"
+ Attribute ShortNickName "" "IntelliBar Label Printer"
+ PCFileName "intelbar.ppd"
+ DriverType label
+ ModelNumber $INTELLITECH_PCL
+ Throughput 8
+ ColorDevice No
+
+ HWMargins 0 5.76 0 5.76
+ VariablePaperSize Yes
+ MinSize 36 36
+ MaxSize 630 7128
+
+ UIConstraints "*inPrintMode Standard *inCutInterval"
+ UIConstraints "*inPrintMode Tear *inCutInterval"
+ UIConstraints "*inPrintMode Standard *inTearInterval"
+ UIConstraints "*inPrintMode Cut *inTearInterval"
+
+ *MediaSize w288h432
+
+ *Resolution k 1 0 0 0 300dpi
+
+ Group "PrinterSettings/Printer Settings"
+ Option "inPrintDensity/Print Density" PickOne DocumentSetup 20.0
+ *Choice "Default/Printer Default" "<</cupsCompression -1>>setpagedevice"
+ Choice "-15/-15" "<</cupsCompression 0>>setpagedevice"
+ Choice "-14/-14" "<</cupsCompression 3>>setpagedevice"
+ Choice "-13/-13" "<</cupsCompression 6>>setpagedevice"
+ Choice "-12/-12" "<</cupsCompression 10>>setpagedevice"
+ Choice "-11/-11" "<</cupsCompression 13>>setpagedevice"
+ Choice "-10/-10" "<</cupsCompression 16>>setpagedevice"
+ Choice "-9/-9" "<</cupsCompression 20>>setpagedevice"
+ Choice "-8/-8" "<</cupsCompression 23>>setpagedevice"
+ Choice "-7/-7" "<</cupsCompression 26>>setpagedevice"
+ Choice "-6/-6" "<</cupsCompression 30>>setpagedevice"
+ Choice "-5/-5" "<</cupsCompression 33>>setpagedevice"
+ Choice "-4/-4" "<</cupsCompression 36>>setpagedevice"
+ Choice "-3/-3" "<</cupsCompression 40>>setpagedevice"
+ Choice "-2/-2" "<</cupsCompression 43>>setpagedevice"
+ Choice "-1/-1" "<</cupsCompression 46>>setpagedevice"
+ Choice "0/0" "<</cupsCompression 50>>setpagedevice"
+ Choice "1/1" "<</cupsCompression 53>>setpagedevice"
+ Choice "2/2" "<</cupsCompression 56>>setpagedevice"
+ Choice "3/3" "<</cupsCompression 60>>setpagedevice"
+ Choice "4/4" "<</cupsCompression 63>>setpagedevice"
+ Choice "5/5" "<</cupsCompression 66>>setpagedevice"
+ Choice "6/6" "<</cupsCompression 70>>setpagedevice"
+ Choice "7/7" "<</cupsCompression 73>>setpagedevice"
+ Choice "8/8" "<</cupsCompression 76>>setpagedevice"
+ Choice "9/9" "<</cupsCompression 80>>setpagedevice"
+ Choice "10/10" "<</cupsCompression 83>>setpagedevice"
+ Choice "11/11" "<</cupsCompression 86>>setpagedevice"
+ Choice "12/12" "<</cupsCompression 90>>setpagedevice"
+ Choice "13/13" "<</cupsCompression 93>>setpagedevice"
+ Choice "14/14" "<</cupsCompression 96>>setpagedevice"
+ Choice "15/15" "<</cupsCompression 100>>setpagedevice"
+ Option "inPrintRate/Print Speed" PickOne DocumentSetup 20.0
+ *Choice "Default/Printer Default" "<</cupsRowFeed 0>>setpagedevice"
+ Choice "15/15 mm/sec." "<</cupsRowFeed 15>>setpagedevice"
+ Choice "20/20 mm/sec." "<</cupsRowFeed 20>>setpagedevice"
+ Choice "30/30 mm/sec." "<</cupsRowFeed 30>>setpagedevice"
+ Choice "40/40 mm/sec." "<</cupsRowFeed 40>>setpagedevice"
+ Choice "60/60 mm/sec." "<</cupsRowFeed 60>>setpagedevice"
+ Choice "80/80 mm/sec." "<</cupsRowFeed 80>>setpagedevice"
+ Choice "100/100 mm/sec." "<</cupsRowFeed 100>>setpagedevice"
+ Choice "120/120 mm/sec." "<</cupsRowFeed 120>>setpagedevice"
+ Choice "150/150 mm/sec." "<</cupsRowFeed 150>>setpagedevice"
+ Choice "200/200 mm/sec." "<</cupsRowFeed 200>>setpagedevice"
+ Choice "250/250 mm/sec." "<</cupsRowFeed 250>>setpagedevice"
+ Choice "300/300 mm/sec." "<</cupsRowFeed 300>>setpagedevice"
+ Option "inPrintMode/Print Mode" PickOne DocumentSetup 20.0
+ *Choice "Standard/Standard" ""
+ Choice "Tear/Tear" ""
+ Choice "Cut/Cut" ""
+ Option "inTearInterval/Print and Tear" PickOne DocumentSetup 20.0
+ *Choice "None/Disabled" "<</cupsRowCount 0>>setpagedevice"
+ Choice "1/Every Label" "<</cupsRowCount 1>>setpagedevice"
+ Choice "2/Every 2 Labels" "<</cupsRowCount 2>>setpagedevice"
+ Choice "3/Every 3 Labels" "<</cupsRowCount 3>>setpagedevice"
+ Choice "4/Every 4 Labels" "<</cupsRowCount 4>>setpagedevice"
+ Choice "5/Every 5 Labels" "<</cupsRowCount 5>>setpagedevice"
+ Choice "6/Every 6 Labels" "<</cupsRowCount 6>>setpagedevice"
+ Choice "7/Every 7 Labels" "<</cupsRowCount 7>>setpagedevice"
+ Choice "8/Every 8 Labels" "<</cupsRowCount 8>>setpagedevice"
+ Choice "9/Every 9 Labels" "<</cupsRowCount 9>>setpagedevice"
+ Choice "10/Every 10 Labels" "<</cupsRowCount 10>>setpagedevice"
+ Attribute CustominTearInterval True "<</cupsRowCount 2 1 roll>>setpagedevice"
+ Attribute ParamCustominTearInterval Interval "1 int 1 99"
+ Option "inCutInterval/Print and Cut" PickOne DocumentSetup 20.0
+ *Choice "None/Disabled" "<</cupsRowStep 0>>setpagedevice"
+ Choice "1/Every Label" "<</cupsRowStep 1>>setpagedevice"
+ Choice "2/Every 2 Labels" "<</cupsRowStep 2>>setpagedevice"
+ Choice "3/Every 3 Labels" "<</cupsRowStep 3>>setpagedevice"
+ Choice "4/Every 4 Labels" "<</cupsRowStep 4>>setpagedevice"
+ Choice "5/Every 5 Labels" "<</cupsRowStep 5>>setpagedevice"
+ Choice "6/Every 6 Labels" "<</cupsRowStep 6>>setpagedevice"
+ Choice "7/Every 7 Labels" "<</cupsRowStep 7>>setpagedevice"
+ Choice "8/Every 8 Labels" "<</cupsRowStep 8>>setpagedevice"
+ Choice "9/Every 9 Labels" "<</cupsRowStep 9>>setpagedevice"
+ Choice "10/Every 10 Labels" "<</cupsRowStep 10>>setpagedevice"
+ Attribute CustominCutInterval True "<</cupsRowStep 2 1 roll>>setpagedevice"
+ Attribute ParamCustominCutInterval Interval "1 int 1 99"
+}
+
+// Oki
+{
+ Manufacturer "Oki"
+ DriverType epson
+ ManualCopies Yes
+ ColorDevice No
+ Throughput 1
+
+ HWMargins 18 18 18 18
+ *MediaSize Letter
+ MediaSize Legal
+ MediaSize A4
+ MediaSize FanFoldUS
+
+ HWMargins 0 0 0 0
+ VariablePaperSize Yes
+ MinSize 36 36
+ MaxSize 1080 86400
+
+ // Oki 24-Pin Series
+ {
+ ModelName "24-Pin Series"
+ Attribute NickName "" "Oki 24-Pin Series"
+ PCFileName "okidat24.ppd"
+ ModelNumber $EPSON_24PIN
+
+ Resolution k 1 8 0 0 60dpi
+ *Resolution k 1 8 0 0 120x60dpi
+ Resolution k 1 24 0 0 180dpi
+ Resolution k 1 24 0 0 360x180dpi
+ Resolution k 1 48 0 0 360dpi
+ }
+
+ // Oki 9-Pin Series
+ {
+ ModelName "9-Pin Series"
+ Attribute NickName "" "Oki 9-Pin Series"
+ PCFileName "okidata9.ppd"
+ ModelNumber $EPSON_9PIN
+ ColorDevice No
+
+ Resolution k 1 8 0 0 60x72dpi
+ *Resolution k 1 8 0 0 120x72dpi
+ Resolution k 1 8 0 0 240x72dpi
+ }
+}
+
+
+// Zebra
+{
+ Manufacturer "Zebra"
+ DriverType label
+ Throughput 8
+ ColorDevice False
+
+ // Zebra CPCL Label Printer
+ {
+ ModelName "CPCL Label Printer"
+ Attribute NickName "" "Zebra CPCL Label Printer"
+ PCFileName "zebracpl.ppd"
+ ModelNumber $ZEBRA_CPCL
+
+ HWMargins 0 0 0 0
+ MediaSize w144h72
+ MediaSize w144h90
+ MediaSize w144h144
+ MediaSize w144h216
+ MediaSize w209h72
+
+ HWMargins 0 0 1 0
+ MediaSize w288h144
+ MediaSize w288h216
+ MediaSize w288h288
+ *MediaSize w288h360
+ MediaSize w288h432
+
+ VariablePaperSize Yes
+ HWMargins 0 0 1 0
+ MinSize 36 36
+ MaxSize 288 3600
+
+ *Resolution k 1 0 0 0 203dpi
+
+ Group "General/General"
+ Option "zeMediaTracking/Media Tracking" PickOne AnySetup 20.0
+ Choice "Continuous/Continuous" ""
+ *Choice "Web/Non-continuous (Web sensing)" ""
+ Choice "Mark/Non-continuous (Mark sensing)" ""
+
+ Group "PrinterSettings/Printer Settings"
+ Option "Darkness" PickOne AnySetup 20.0
+ *Choice "-1/Printer Default" "<</cupsCompression -1>>setpagedevice"
+ Choice "1/1" "<</cupsCompression 4>>setpagedevice"
+ Choice "2/2" "<</cupsCompression 7>>setpagedevice"
+ Choice "3/3" "<</cupsCompression 10>>setpagedevice"
+ Choice "4/4" "<</cupsCompression 14>>setpagedevice"
+ Choice "5/5" "<</cupsCompression 17>>setpagedevice"
+ Choice "6/6" "<</cupsCompression 20>>setpagedevice"
+ Choice "7/7" "<</cupsCompression 24>>setpagedevice"
+ Choice "8/8" "<</cupsCompression 27>>setpagedevice"
+ Choice "9/9" "<</cupsCompression 30>>setpagedevice"
+ Choice "10/10" "<</cupsCompression 34>>setpagedevice"
+ Choice "11/11" "<</cupsCompression 37>>setpagedevice"
+ Choice "12/12" "<</cupsCompression 40>>setpagedevice"
+ Choice "13/13" "<</cupsCompression 44>>setpagedevice"
+ Choice "14/14" "<</cupsCompression 47>>setpagedevice"
+ Choice "15/15" "<</cupsCompression 50>>setpagedevice"
+ Choice "16/16" "<</cupsCompression 54>>setpagedevice"
+ Choice "17/17" "<</cupsCompression 57>>setpagedevice"
+ Choice "18/18" "<</cupsCompression 60>>setpagedevice"
+ Choice "19/19" "<</cupsCompression 64>>setpagedevice"
+ Choice "20/20" "<</cupsCompression 67>>setpagedevice"
+ Choice "21/21" "<</cupsCompression 70>>setpagedevice"
+ Choice "22/22" "<</cupsCompression 74>>setpagedevice"
+ Choice "23/23" "<</cupsCompression 77>>setpagedevice"
+ Choice "24/24" "<</cupsCompression 80>>setpagedevice"
+ Choice "25/25" "<</cupsCompression 84>>setpagedevice"
+ Choice "26/26" "<</cupsCompression 87>>setpagedevice"
+ Choice "27/27" "<</cupsCompression 90>>setpagedevice"
+ Choice "28/28" "<</cupsCompression 94>>setpagedevice"
+ Choice "29/29" "<</cupsCompression 97>>setpagedevice"
+ Choice "30/30" "<</cupsCompression 100>>setpagedevice"
+ Option "zePrintRate/Print Rate" PickOne AnySetup 20.0
+ *Choice "Default/Printer Default" ""
+ Choice "1/1 inch/sec." ""
+ Choice "2/2 inches/sec." ""
+ Choice "3/3 inches/sec." ""
+ Choice "4/4 inches/sec." ""
+ Option "zeTearOffPosition/Tear-Off Adjust Position" PickOne AnySetup 20.0
+ *Choice "1000/Printer Default" "<</AdvanceDistance 1000>>setpagedevice"
+ Choice "-120/-120" "<</AdvanceDistance -120>>setpagedevice"
+ Choice "-115/-115" "<</AdvanceDistance -115>>setpagedevice"
+ Choice "-110/-110" "<</AdvanceDistance -110>>setpagedevice"
+ Choice "-105/-105" "<</AdvanceDistance -105>>setpagedevice"
+ Choice "-100/-100" "<</AdvanceDistance -100>>setpagedevice"
+ Choice "-95/-95" "<</AdvanceDistance -95>>setpagedevice"
+ Choice "-90/-90" "<</AdvanceDistance -90>>setpagedevice"
+ Choice "-85/-85" "<</AdvanceDistance -85>>setpagedevice"
+ Choice "-80/-80" "<</AdvanceDistance -80>>setpagedevice"
+ Choice "-75/-75" "<</AdvanceDistance -75>>setpagedevice"
+ Choice "-70/-70" "<</AdvanceDistance -70>>setpagedevice"
+ Choice "-65/-65" "<</AdvanceDistance -65>>setpagedevice"
+ Choice "-60/-60" "<</AdvanceDistance -60>>setpagedevice"
+ Choice "-55/-55" "<</AdvanceDistance -55>>setpagedevice"
+ Choice "-50/-50" "<</AdvanceDistance -50>>setpagedevice"
+ Choice "-45/-45" "<</AdvanceDistance -45>>setpagedevice"
+ Choice "-40/-40" "<</AdvanceDistance -40>>setpagedevice"
+ Choice "-35/-35" "<</AdvanceDistance -35>>setpagedevice"
+ Choice "-30/-30" "<</AdvanceDistance -30>>setpagedevice"
+ Choice "-25/-25" "<</AdvanceDistance -25>>setpagedevice"
+ Choice "-20/-20" "<</AdvanceDistance -20>>setpagedevice"
+ Choice "-15/-15" "<</AdvanceDistance -15>>setpagedevice"
+ Choice "-10/-10" "<</AdvanceDistance -10>>setpagedevice"
+ Choice "-5/-5" "<</AdvanceDistance -5>>setpagedevice"
+ Choice "0/0" "<</AdvanceDistance 0>>setpagedevice"
+ Choice "5/5" "<</AdvanceDistance 5>>setpagedevice"
+ Choice "10/10" "<</AdvanceDistance 10>>setpagedevice"
+ Choice "15/15" "<</AdvanceDistance 15>>setpagedevice"
+ Choice "20/20" "<</AdvanceDistance 20>>setpagedevice"
+ Choice "25/25" "<</AdvanceDistance 25>>setpagedevice"
+ Choice "30/30" "<</AdvanceDistance 30>>setpagedevice"
+ Choice "35/35" "<</AdvanceDistance 35>>setpagedevice"
+ Choice "40/40" "<</AdvanceDistance 40>>setpagedevice"
+ Choice "45/45" "<</AdvanceDistance 45>>setpagedevice"
+ Choice "50/50" "<</AdvanceDistance 50>>setpagedevice"
+ Choice "55/55" "<</AdvanceDistance 55>>setpagedevice"
+ Choice "60/60" "<</AdvanceDistance 60>>setpagedevice"
+ Choice "65/65" "<</AdvanceDistance 65>>setpagedevice"
+ Choice "70/70" "<</AdvanceDistance 70>>setpagedevice"
+ Choice "75/75" "<</AdvanceDistance 75>>setpagedevice"
+ Choice "80/80" "<</AdvanceDistance 80>>setpagedevice"
+ Choice "85/85" "<</AdvanceDistance 85>>setpagedevice"
+ Choice "90/90" "<</AdvanceDistance 90>>setpagedevice"
+ Choice "95/95" "<</AdvanceDistance 95>>setpagedevice"
+ Choice "100/100" "<</AdvanceDistance 100>>setpagedevice"
+ Choice "105/105" "<</AdvanceDistance 105>>setpagedevice"
+ Choice "110/110" "<</AdvanceDistance 110>>setpagedevice"
+ Choice "115/115" "<</AdvanceDistance 115>>setpagedevice"
+ Choice "120/120" "<</AdvanceDistance 120>>setpagedevice"
+ Option "zeErrorReprint/Reprint After Error" PickOne AnySetup 20.0
+ *Choice "Saved/Printer Default" ""
+ Choice "Always/Always" ""
+ Choice "Never/Never" ""
+ }
+
+ // Zebra EPL1 Label Printer
+ {
+ ModelName "EPL1 Label Printer"
+ Attribute NickName "" "Zebra EPL1 Label Printer"
+ PCFileName "zebraep1.ppd"
+ ModelNumber $ZEBRA_EPL_LINE
+
+ HWMargins 0 0 0 0
+ VariablePaperSize Yes
+ MinSize 36 36
+ MaxSize 288 3600
+
+ MediaSize w90h18
+ MediaSize w90h162
+ MediaSize w108h18
+ MediaSize w108h36
+ MediaSize w108h72
+ MediaSize w108h144
+ MediaSize w144h26
+ MediaSize w144h36
+ MediaSize w144h72
+ MediaSize w144h90
+ MediaSize w144h288
+ MediaSize w144h396
+ MediaSize w162h36
+ MediaSize w162h90
+ MediaSize w162h288
+ MediaSize w162h396
+ MediaSize w171h396
+ MediaSize w180h72
+ MediaSize w180h144
+ MediaSize w198h90
+ MediaSize w216h72
+ MediaSize w216h90
+ MediaSize w216h144
+ MediaSize w216h216
+ MediaSize w216h360
+ MediaSize w234h144
+ MediaSize w234h360
+ MediaSize w234h396
+ MediaSize w234h419
+ MediaSize w234h563
+ MediaSize w252h72
+ MediaSize w288h72
+ MediaSize w288h144
+ MediaSize w288h180
+ MediaSize w288h216
+ MediaSize w288h288
+ *MediaSize w288h360
+ MediaSize w288h432
+ MediaSize w288h468
+ MediaSize w288h936
+
+ *Resolution k 1 0 0 0 203dpi
+ Resolution k 1 0 0 0 300dpi
+ Resolution k 1 0 0 0 600dpi
+
+ Group "PrinterSettings/Printer Settings"
+ Option "Darkness" PickOne AnySetup 20.0
+ *Choice "-1/Printer Default" "<</cupsCompression -1>>setpagedevice"
+ Choice "1/1" "<</cupsCompression 4>>setpagedevice"
+ Choice "2/2" "<</cupsCompression 7>>setpagedevice"
+ Choice "3/3" "<</cupsCompression 10>>setpagedevice"
+ Choice "4/4" "<</cupsCompression 14>>setpagedevice"
+ Choice "5/5" "<</cupsCompression 17>>setpagedevice"
+ Choice "6/6" "<</cupsCompression 20>>setpagedevice"
+ Choice "7/7" "<</cupsCompression 24>>setpagedevice"
+ Choice "8/8" "<</cupsCompression 27>>setpagedevice"
+ Choice "9/9" "<</cupsCompression 30>>setpagedevice"
+ Choice "10/10" "<</cupsCompression 34>>setpagedevice"
+ Choice "11/11" "<</cupsCompression 37>>setpagedevice"
+ Choice "12/12" "<</cupsCompression 40>>setpagedevice"
+ Choice "13/13" "<</cupsCompression 44>>setpagedevice"
+ Choice "14/14" "<</cupsCompression 47>>setpagedevice"
+ Choice "15/15" "<</cupsCompression 50>>setpagedevice"
+ Choice "16/16" "<</cupsCompression 54>>setpagedevice"
+ Choice "17/17" "<</cupsCompression 57>>setpagedevice"
+ Choice "18/18" "<</cupsCompression 60>>setpagedevice"
+ Choice "19/19" "<</cupsCompression 64>>setpagedevice"
+ Choice "20/20" "<</cupsCompression 67>>setpagedevice"
+ Choice "21/21" "<</cupsCompression 70>>setpagedevice"
+ Choice "22/22" "<</cupsCompression 74>>setpagedevice"
+ Choice "23/23" "<</cupsCompression 77>>setpagedevice"
+ Choice "24/24" "<</cupsCompression 80>>setpagedevice"
+ Choice "25/25" "<</cupsCompression 84>>setpagedevice"
+ Choice "26/26" "<</cupsCompression 87>>setpagedevice"
+ Choice "27/27" "<</cupsCompression 90>>setpagedevice"
+ Choice "28/28" "<</cupsCompression 94>>setpagedevice"
+ Choice "29/29" "<</cupsCompression 97>>setpagedevice"
+ Choice "30/30" "<</cupsCompression 100>>setpagedevice"
+ Option "zePrintRate/Print Rate" PickOne AnySetup 20.0
+ *Choice "Default/Printer Default" ""
+ Choice "1/1 inch/sec." ""
+ Choice "1.5/1.5 inch/sec." ""
+ Choice "2/2 inches/sec." ""
+ Choice "2.5/2.5 inches/sec." ""
+ }
+
+ // Zebra EPL2 Label Printer
+ {
+ ModelName "EPL2 Label Printer"
+ Attribute NickName "" "Zebra EPL2 Label Printer"
+ PCFileName "zebraep2.ppd"
+ ModelNumber $ZEBRA_EPL_PAGE
+
+ HWMargins 0 0 0 0
+ VariablePaperSize Yes
+ MinSize 36 36
+ MaxSize 288 3600
+
+ MediaSize w90h18
+ MediaSize w90h162
+ MediaSize w108h18
+ MediaSize w108h36
+ MediaSize w108h72
+ MediaSize w108h144
+ MediaSize w144h26
+ MediaSize w144h36
+ MediaSize w144h72
+ MediaSize w144h90
+ MediaSize w144h288
+ MediaSize w144h396
+ MediaSize w162h36
+ MediaSize w162h90
+ MediaSize w162h288
+ MediaSize w162h396
+ MediaSize w171h396
+ MediaSize w180h72
+ MediaSize w180h144
+ MediaSize w198h90
+ MediaSize w216h72
+ MediaSize w216h90
+ MediaSize w216h144
+ MediaSize w216h216
+ MediaSize w216h360
+ MediaSize w234h144
+ MediaSize w234h360
+ MediaSize w234h396
+ MediaSize w234h419
+ MediaSize w234h563
+ MediaSize w252h72
+ MediaSize w288h72
+ MediaSize w288h144
+ MediaSize w288h180
+ MediaSize w288h216
+ MediaSize w288h288
+ *MediaSize w288h360
+ MediaSize w288h432
+ MediaSize w288h468
+ MediaSize w288h936
+
+ *Resolution k 1 0 0 0 203dpi
+ Resolution k 1 0 0 0 300dpi
+ Resolution k 1 0 0 0 600dpi
+
+ Group "General/General"
+ Option "MediaType/Media Type" PickOne AnySetup 20.0
+ *Choice "Saved/Printer Default" ""
+ Choice "Thermal/Thermal Transfer Media" "<</MediaType(Thermal)>>setpagedevice"
+ Choice "Direct/Direct Thermal Media" "<</MediaType(Direct)>>setpagedevice"
+ Group "PrinterSettings/Printer Settings"
+ Option "Darkness" PickOne AnySetup 20.0
+ *Choice "-1/Printer Default" "<</cupsCompression -1>>setpagedevice"
+ Choice "1/1" "<</cupsCompression 4>>setpagedevice"
+ Choice "2/2" "<</cupsCompression 7>>setpagedevice"
+ Choice "3/3" "<</cupsCompression 10>>setpagedevice"
+ Choice "4/4" "<</cupsCompression 14>>setpagedevice"
+ Choice "5/5" "<</cupsCompression 17>>setpagedevice"
+ Choice "6/6" "<</cupsCompression 20>>setpagedevice"
+ Choice "7/7" "<</cupsCompression 24>>setpagedevice"
+ Choice "8/8" "<</cupsCompression 27>>setpagedevice"
+ Choice "9/9" "<</cupsCompression 30>>setpagedevice"
+ Choice "10/10" "<</cupsCompression 34>>setpagedevice"
+ Choice "11/11" "<</cupsCompression 37>>setpagedevice"
+ Choice "12/12" "<</cupsCompression 40>>setpagedevice"
+ Choice "13/13" "<</cupsCompression 44>>setpagedevice"
+ Choice "14/14" "<</cupsCompression 47>>setpagedevice"
+ Choice "15/15" "<</cupsCompression 50>>setpagedevice"
+ Choice "16/16" "<</cupsCompression 54>>setpagedevice"
+ Choice "17/17" "<</cupsCompression 57>>setpagedevice"
+ Choice "18/18" "<</cupsCompression 60>>setpagedevice"
+ Choice "19/19" "<</cupsCompression 64>>setpagedevice"
+ Choice "20/20" "<</cupsCompression 67>>setpagedevice"
+ Choice "21/21" "<</cupsCompression 70>>setpagedevice"
+ Choice "22/22" "<</cupsCompression 74>>setpagedevice"
+ Choice "23/23" "<</cupsCompression 77>>setpagedevice"
+ Choice "24/24" "<</cupsCompression 80>>setpagedevice"
+ Choice "25/25" "<</cupsCompression 84>>setpagedevice"
+ Choice "26/26" "<</cupsCompression 87>>setpagedevice"
+ Choice "27/27" "<</cupsCompression 90>>setpagedevice"
+ Choice "28/28" "<</cupsCompression 94>>setpagedevice"
+ Choice "29/29" "<</cupsCompression 97>>setpagedevice"
+ Choice "30/30" "<</cupsCompression 100>>setpagedevice"
+ Option "zePrintRate/Print Rate" PickOne AnySetup 20.0
+ *Choice "Default/Printer Default" ""
+ Choice "1/1 inch/sec." ""
+ Choice "1.5/1.5 inch/sec." ""
+ Choice "2/2 inches/sec." ""
+ Choice "2.5/2.5 inches/sec." ""
+ Choice "3/3 inches/sec." ""
+ Choice "4/4 inches/sec." ""
+ Choice "5/5 inches/sec." ""
+ Choice "6/6 inches/sec." ""
+ }
+
+ // Zebra ZPL Label Printer
+ {
+ ModelName "ZPL Label Printer"
+ Attribute NickName "" "Zebra ZPL Label Printer"
+ PCFileName "zebra.ppd"
+ ModelNumber $ZEBRA_ZPL
+
+ HWMargins 0 0 0 0
+ VariablePaperSize Yes
+ MinSize 36 36
+ MaxSize 576 3600
+
+ MediaSize w90h18
+ MediaSize w90h162
+ MediaSize w108h18
+ MediaSize w108h36
+ MediaSize w108h72
+ MediaSize w108h144
+ MediaSize w144h26
+ MediaSize w144h36
+ MediaSize w144h72
+ MediaSize w144h90
+ MediaSize w144h288
+ MediaSize w144h396
+ MediaSize w162h36
+ MediaSize w162h90
+ MediaSize w162h288
+ MediaSize w162h396
+ MediaSize w171h396
+ MediaSize w180h72
+ MediaSize w180h144
+ MediaSize w198h90
+ MediaSize w216h72
+ MediaSize w216h90
+ MediaSize w216h144
+ MediaSize w216h216
+ MediaSize w216h360
+ MediaSize w234h144
+ MediaSize w234h360
+ MediaSize w234h396
+ MediaSize w234h419
+ MediaSize w234h563
+ MediaSize w252h72
+ MediaSize w288h72
+ MediaSize w288h144
+ MediaSize w288h180
+ MediaSize w288h216
+ MediaSize w288h288
+ *MediaSize w288h360
+ MediaSize w288h432
+ MediaSize w288h468
+ MediaSize w288h936
+ MediaSize w432h72
+ MediaSize w432h144
+ MediaSize w432h216
+ MediaSize w432h288
+ MediaSize w432h360
+ MediaSize w432h432
+ MediaSize w432h468
+ MediaSize w576h72
+ MediaSize w576h144
+ MediaSize w576h216
+ MediaSize w576h288
+ MediaSize w576h360
+ MediaSize w576h432
+ MediaSize w576h468
+
+ *Resolution k 1 0 0 0 203dpi
+ Resolution k 1 0 0 0 300dpi
+ Resolution k 1 0 0 0 600dpi
+
+ Group "General/General"
+ Option "zeMediaTracking/Media Tracking" PickOne AnySetup 20.0
+ Choice "Continuous/Continuous" ""
+ *Choice "Web/Non-continuous (Web sensing)" ""
+ Choice "Mark/Non-continuous (Mark sensing)" ""
+ Option "MediaType/Media Type" PickOne AnySetup 20.0
+ *Choice "Saved/Printer Default" ""
+ Choice "Thermal/Thermal Transfer Media" "<</MediaType(Thermal)>>setpagedevice"
+ Choice "Direct/Direct Thermal Media" "<</MediaType(Direct)>>setpagedevice"
+ Group "PrinterSettings/Printer Settings"
+ Option "Darkness" PickOne AnySetup 20.0
+ *Choice "-1/Printer Default" "<</cupsCompression -1>>setpagedevice"
+ Choice "1/1" "<</cupsCompression 4>>setpagedevice"
+ Choice "2/2" "<</cupsCompression 7>>setpagedevice"
+ Choice "3/3" "<</cupsCompression 10>>setpagedevice"
+ Choice "4/4" "<</cupsCompression 14>>setpagedevice"
+ Choice "5/5" "<</cupsCompression 17>>setpagedevice"
+ Choice "6/6" "<</cupsCompression 20>>setpagedevice"
+ Choice "7/7" "<</cupsCompression 24>>setpagedevice"
+ Choice "8/8" "<</cupsCompression 27>>setpagedevice"
+ Choice "9/9" "<</cupsCompression 30>>setpagedevice"
+ Choice "10/10" "<</cupsCompression 34>>setpagedevice"
+ Choice "11/11" "<</cupsCompression 37>>setpagedevice"
+ Choice "12/12" "<</cupsCompression 40>>setpagedevice"
+ Choice "13/13" "<</cupsCompression 44>>setpagedevice"
+ Choice "14/14" "<</cupsCompression 47>>setpagedevice"
+ Choice "15/15" "<</cupsCompression 50>>setpagedevice"
+ Choice "16/16" "<</cupsCompression 54>>setpagedevice"
+ Choice "17/17" "<</cupsCompression 57>>setpagedevice"
+ Choice "18/18" "<</cupsCompression 60>>setpagedevice"
+ Choice "19/19" "<</cupsCompression 64>>setpagedevice"
+ Choice "20/20" "<</cupsCompression 67>>setpagedevice"
+ Choice "21/21" "<</cupsCompression 70>>setpagedevice"
+ Choice "22/22" "<</cupsCompression 74>>setpagedevice"
+ Choice "23/23" "<</cupsCompression 77>>setpagedevice"
+ Choice "24/24" "<</cupsCompression 80>>setpagedevice"
+ Choice "25/25" "<</cupsCompression 84>>setpagedevice"
+ Choice "26/26" "<</cupsCompression 87>>setpagedevice"
+ Choice "27/27" "<</cupsCompression 90>>setpagedevice"
+ Choice "28/28" "<</cupsCompression 94>>setpagedevice"
+ Choice "29/29" "<</cupsCompression 97>>setpagedevice"
+ Choice "30/30" "<</cupsCompression 100>>setpagedevice"
+ Option "zePrintRate/Print Rate" PickOne AnySetup 20.0
+ *Choice "Default/Printer Default" ""
+ Choice "1/1 inch/sec." ""
+ Choice "2/2 inches/sec." ""
+ Choice "3/3 inches/sec." ""
+ Choice "4/4 inches/sec." ""
+ Choice "5/5 inches/sec." ""
+ Choice "6/6 inches/sec." ""
+ Choice "7/7 inches/sec." ""
+ Choice "8/8 inches/sec." ""
+ Choice "9/9 inches/sec." ""
+ Choice "10/10 inches/sec." ""
+ Choice "11/11 inches/sec." ""
+ Choice "12/12 inches/sec." ""
+ Option "zeLabelTop/Label Top" PickOne AnySetup 20.0
+ *Choice "200/Printer Default" "<</cupsRowStep 200>>setpagedevice"
+ Choice "-120/-120" "<</cupsRowStep -120>>setpagedevice"
+ Choice "-115/-115" "<</cupsRowStep -115>>setpagedevice"
+ Choice "-110/-110" "<</cupsRowStep -110>>setpagedevice"
+ Choice "-105/-105" "<</cupsRowStep -105>>setpagedevice"
+ Choice "-100/-100" "<</cupsRowStep -100>>setpagedevice"
+ Choice "-95/-95" "<</cupsRowStep -95>>setpagedevice"
+ Choice "-90/-90" "<</cupsRowStep -90>>setpagedevice"
+ Choice "-85/-85" "<</cupsRowStep -85>>setpagedevice"
+ Choice "-80/-80" "<</cupsRowStep -80>>setpagedevice"
+ Choice "-75/-75" "<</cupsRowStep -75>>setpagedevice"
+ Choice "-70/-70" "<</cupsRowStep -70>>setpagedevice"
+ Choice "-65/-65" "<</cupsRowStep -65>>setpagedevice"
+ Choice "-60/-60" "<</cupsRowStep -60>>setpagedevice"
+ Choice "-55/-55" "<</cupsRowStep -55>>setpagedevice"
+ Choice "-50/-50" "<</cupsRowStep -50>>setpagedevice"
+ Choice "-45/-45" "<</cupsRowStep -45>>setpagedevice"
+ Choice "-40/-40" "<</cupsRowStep -40>>setpagedevice"
+ Choice "-35/-35" "<</cupsRowStep -35>>setpagedevice"
+ Choice "-30/-30" "<</cupsRowStep -30>>setpagedevice"
+ Choice "-25/-25" "<</cupsRowStep -25>>setpagedevice"
+ Choice "-20/-20" "<</cupsRowStep -20>>setpagedevice"
+ Choice "-15/-15" "<</cupsRowStep -15>>setpagedevice"
+ Choice "-10/-10" "<</cupsRowStep -10>>setpagedevice"
+ Choice "-5/-5" "<</cupsRowStep -5>>setpagedevice"
+ Choice "0/0" "<</cupsRowStep 0>>setpagedevice"
+ Choice "5/5" "<</cupsRowStep 5>>setpagedevice"
+ Choice "10/10" "<</cupsRowStep 10>>setpagedevice"
+ Choice "15/15" "<</cupsRowStep 15>>setpagedevice"
+ Choice "20/20" "<</cupsRowStep 20>>setpagedevice"
+ Choice "25/25" "<</cupsRowStep 25>>setpagedevice"
+ Choice "30/30" "<</cupsRowStep 30>>setpagedevice"
+ Choice "35/35" "<</cupsRowStep 35>>setpagedevice"
+ Choice "40/40" "<</cupsRowStep 40>>setpagedevice"
+ Choice "45/45" "<</cupsRowStep 45>>setpagedevice"
+ Choice "50/50" "<</cupsRowStep 50>>setpagedevice"
+ Choice "55/55" "<</cupsRowStep 55>>setpagedevice"
+ Choice "60/60" "<</cupsRowStep 60>>setpagedevice"
+ Choice "65/65" "<</cupsRowStep 65>>setpagedevice"
+ Choice "70/70" "<</cupsRowStep 70>>setpagedevice"
+ Choice "75/75" "<</cupsRowStep 75>>setpagedevice"
+ Choice "80/80" "<</cupsRowStep 80>>setpagedevice"
+ Choice "85/85" "<</cupsRowStep 85>>setpagedevice"
+ Choice "90/90" "<</cupsRowStep 90>>setpagedevice"
+ Choice "95/95" "<</cupsRowStep 95>>setpagedevice"
+ Choice "100/100" "<</cupsRowStep 100>>setpagedevice"
+ Choice "105/105" "<</cupsRowStep 105>>setpagedevice"
+ Choice "110/110" "<</cupsRowStep 110>>setpagedevice"
+ Choice "115/115" "<</cupsRowStep 115>>setpagedevice"
+ Choice "120/120" "<</cupsRowStep 120>>setpagedevice"
+ Option "zePrintMode/Print Mode" PickOne AnySetup 20.0
+ *Choice "Saved/Printer Default" ""
+ Choice "Tear/Tear-Off" ""
+ Choice "Peel/Peel-Off" ""
+ Choice "Rewind/Rewind" ""
+ Choice "Applicator/Applicator" ""
+ Choice "Cutter/Cutter" ""
+ Option "zeTearOffPosition/Tear-Off Adjust Position" PickOne AnySetup 20.0
+ *Choice "1000/Printer Default" "<</AdvanceDistance 1000>>setpagedevice"
+ Choice "-120/-120" "<</AdvanceDistance -120>>setpagedevice"
+ Choice "-115/-115" "<</AdvanceDistance -115>>setpagedevice"
+ Choice "-110/-110" "<</AdvanceDistance -110>>setpagedevice"
+ Choice "-105/-105" "<</AdvanceDistance -105>>setpagedevice"
+ Choice "-100/-100" "<</AdvanceDistance -100>>setpagedevice"
+ Choice "-95/-95" "<</AdvanceDistance -95>>setpagedevice"
+ Choice "-90/-90" "<</AdvanceDistance -90>>setpagedevice"
+ Choice "-85/-85" "<</AdvanceDistance -85>>setpagedevice"
+ Choice "-80/-80" "<</AdvanceDistance -80>>setpagedevice"
+ Choice "-75/-75" "<</AdvanceDistance -75>>setpagedevice"
+ Choice "-70/-70" "<</AdvanceDistance -70>>setpagedevice"
+ Choice "-65/-65" "<</AdvanceDistance -65>>setpagedevice"
+ Choice "-60/-60" "<</AdvanceDistance -60>>setpagedevice"
+ Choice "-55/-55" "<</AdvanceDistance -55>>setpagedevice"
+ Choice "-50/-50" "<</AdvanceDistance -50>>setpagedevice"
+ Choice "-45/-45" "<</AdvanceDistance -45>>setpagedevice"
+ Choice "-40/-40" "<</AdvanceDistance -40>>setpagedevice"
+ Choice "-35/-35" "<</AdvanceDistance -35>>setpagedevice"
+ Choice "-30/-30" "<</AdvanceDistance -30>>setpagedevice"
+ Choice "-25/-25" "<</AdvanceDistance -25>>setpagedevice"
+ Choice "-20/-20" "<</AdvanceDistance -20>>setpagedevice"
+ Choice "-15/-15" "<</AdvanceDistance -15>>setpagedevice"
+ Choice "-10/-10" "<</AdvanceDistance -10>>setpagedevice"
+ Choice "-5/-5" "<</AdvanceDistance -5>>setpagedevice"
+ Choice "0/0" "<</AdvanceDistance 0>>setpagedevice"
+ Choice "5/5" "<</AdvanceDistance 5>>setpagedevice"
+ Choice "10/10" "<</AdvanceDistance 10>>setpagedevice"
+ Choice "15/15" "<</AdvanceDistance 15>>setpagedevice"
+ Choice "20/20" "<</AdvanceDistance 20>>setpagedevice"
+ Choice "25/25" "<</AdvanceDistance 25>>setpagedevice"
+ Choice "30/30" "<</AdvanceDistance 30>>setpagedevice"
+ Choice "35/35" "<</AdvanceDistance 35>>setpagedevice"
+ Choice "40/40" "<</AdvanceDistance 40>>setpagedevice"
+ Choice "45/45" "<</AdvanceDistance 45>>setpagedevice"
+ Choice "50/50" "<</AdvanceDistance 50>>setpagedevice"
+ Choice "55/55" "<</AdvanceDistance 55>>setpagedevice"
+ Choice "60/60" "<</AdvanceDistance 60>>setpagedevice"
+ Choice "65/65" "<</AdvanceDistance 65>>setpagedevice"
+ Choice "70/70" "<</AdvanceDistance 70>>setpagedevice"
+ Choice "75/75" "<</AdvanceDistance 75>>setpagedevice"
+ Choice "80/80" "<</AdvanceDistance 80>>setpagedevice"
+ Choice "85/85" "<</AdvanceDistance 85>>setpagedevice"
+ Choice "90/90" "<</AdvanceDistance 90>>setpagedevice"
+ Choice "95/95" "<</AdvanceDistance 95>>setpagedevice"
+ Choice "100/100" "<</AdvanceDistance 100>>setpagedevice"
+ Choice "105/105" "<</AdvanceDistance 105>>setpagedevice"
+ Choice "110/110" "<</AdvanceDistance 110>>setpagedevice"
+ Choice "115/115" "<</AdvanceDistance 115>>setpagedevice"
+ Choice "120/120" "<</AdvanceDistance 120>>setpagedevice"
+ Option "zeErrorReprint/Reprint After Error" PickOne AnySetup 20.0
+ *Choice "Saved/Printer Default" ""
+ Choice "Always/Always" ""
+ Choice "Never/Never" ""
+ }
+}
+
+//
+// End of "$Id$".
+//
diff --git a/ppdc/testcatalog.cxx b/ppdc/testcatalog.cxx
new file mode 100644
index 000000000..a9e2e8655
--- /dev/null
+++ b/ppdc/testcatalog.cxx
@@ -0,0 +1,63 @@
+//
+// "$Id$"
+//
+// Test program for message catalog class.
+//
+// Copyright 2008 by Apple Inc.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+// Contents:
+//
+// main() - Open a message catalog
+//
+
+//
+// Include necessary headers...
+//
+
+#include "ppdc-private.h"
+
+
+//
+// 'main()' - Open a message catalog
+//
+
+int // O - Exit status
+main(int argc, // I - Number of command-line arguments
+ char *argv[]) // I - Command-line arguments
+{
+ ppdcCatalog *catalog; // Message catalog
+ ppdcMessage *m; // Current message
+
+
+ if (argc != 2)
+ {
+ puts("Usage: testcatalog filename");
+ return (1);
+ }
+
+ // Scan the command-line...
+ catalog = new ppdcCatalog(NULL, argv[1]);
+
+ printf("%s: %d messages\n", argv[1], catalog->messages->count);
+
+ for (m = (ppdcMessage *)catalog->messages->first();
+ m;
+ m = (ppdcMessage *)catalog->messages->next())
+ printf("%s: %s\n", m->id->value, m->string->value);
+
+ catalog->release();
+
+ // Return with no errors.
+ return (0);
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/scheduler/Dependencies b/scheduler/Dependencies
new file mode 100644
index 000000000..1cbb24ae1
--- /dev/null
+++ b/scheduler/Dependencies
@@ -0,0 +1,352 @@
+# DO NOT DELETE
+
+auth.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+auth.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+auth.o: ../cups/language.h ../cups/string-private.h ../config.h
+auth.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+auth.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+auth.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+auth.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+auth.o: ../cups/thread-private.h ../cups/file-private.h
+auth.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h sysman.h
+auth.o: statbuf.h cert.h auth.h client.h policy.h printers.h
+auth.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+auth.o: network.h subscriptions.h
+banners.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+banners.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+banners.o: ../cups/language.h ../cups/string-private.h ../config.h
+banners.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+banners.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+banners.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+banners.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+banners.o: ../cups/thread-private.h ../cups/file-private.h
+banners.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+banners.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h
+banners.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+banners.o: network.h subscriptions.h ../cups/dir.h
+cert.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+cert.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+cert.o: ../cups/language.h ../cups/string-private.h ../config.h
+cert.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+cert.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+cert.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+cert.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+cert.o: ../cups/thread-private.h ../cups/file-private.h
+cert.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h sysman.h
+cert.o: statbuf.h cert.h auth.h client.h policy.h printers.h
+cert.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+cert.o: network.h subscriptions.h
+classes.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+classes.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+classes.o: ../cups/language.h ../cups/string-private.h ../config.h
+classes.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+classes.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+classes.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+classes.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+classes.o: ../cups/thread-private.h ../cups/file-private.h
+classes.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+classes.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h
+classes.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+classes.o: network.h subscriptions.h
+client.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+client.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+client.o: ../cups/language.h ../cups/string-private.h ../config.h
+client.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+client.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+client.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+client.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+client.o: ../cups/thread-private.h ../cups/file-private.h
+client.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+client.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h
+client.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+client.o: network.h subscriptions.h
+conf.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+conf.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+conf.o: ../cups/language.h ../cups/string-private.h ../config.h
+conf.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+conf.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+conf.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+conf.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+conf.o: ../cups/thread-private.h ../cups/file-private.h
+conf.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h sysman.h
+conf.o: statbuf.h cert.h auth.h client.h policy.h printers.h
+conf.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+conf.o: network.h subscriptions.h
+dirsvc.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+dirsvc.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+dirsvc.o: ../cups/language.h ../cups/string-private.h ../config.h
+dirsvc.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+dirsvc.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+dirsvc.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+dirsvc.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+dirsvc.o: ../cups/thread-private.h ../cups/file-private.h
+dirsvc.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+dirsvc.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h
+dirsvc.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+dirsvc.o: network.h subscriptions.h
+env.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+env.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+env.o: ../cups/language.h ../cups/string-private.h ../config.h
+env.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+env.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+env.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+env.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+env.o: ../cups/thread-private.h ../cups/file-private.h ../cups/cups-private.h
+env.o: mime.h ../cups/array.h ../cups/file.h sysman.h statbuf.h cert.h auth.h
+env.o: client.h policy.h printers.h ../cups/pwg-private.h classes.h job.h
+env.o: conf.h banners.h dirsvc.h network.h subscriptions.h
+file.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+file.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+file.o: ../cups/language.h ../cups/string-private.h ../config.h
+file.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+file.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+file.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+file.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+file.o: ../cups/thread-private.h ../cups/file-private.h
+file.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h sysman.h
+file.o: statbuf.h cert.h auth.h client.h policy.h printers.h
+file.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+file.o: network.h subscriptions.h ../cups/dir.h
+main.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+main.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+main.o: ../cups/language.h ../cups/string-private.h ../config.h
+main.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+main.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+main.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+main.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+main.o: ../cups/thread-private.h ../cups/file-private.h
+main.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h sysman.h
+main.o: statbuf.h cert.h auth.h client.h policy.h printers.h
+main.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+main.o: network.h subscriptions.h
+ipp.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ipp.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+ipp.o: ../cups/language.h ../cups/string-private.h ../config.h
+ipp.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ipp.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ipp.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ipp.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ipp.o: ../cups/thread-private.h ../cups/file-private.h ../cups/cups-private.h
+ipp.o: mime.h ../cups/array.h ../cups/file.h sysman.h statbuf.h cert.h auth.h
+ipp.o: client.h policy.h printers.h ../cups/pwg-private.h classes.h job.h
+ipp.o: conf.h banners.h dirsvc.h network.h subscriptions.h
+ipp.o: ../cups/ppd-private.h
+listen.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+listen.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+listen.o: ../cups/language.h ../cups/string-private.h ../config.h
+listen.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+listen.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+listen.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+listen.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+listen.o: ../cups/thread-private.h ../cups/file-private.h
+listen.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+listen.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h
+listen.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+listen.o: network.h subscriptions.h
+job.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+job.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+job.o: ../cups/language.h ../cups/string-private.h ../config.h
+job.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+job.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+job.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+job.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+job.o: ../cups/thread-private.h ../cups/file-private.h ../cups/cups-private.h
+job.o: mime.h ../cups/array.h ../cups/file.h sysman.h statbuf.h cert.h auth.h
+job.o: client.h policy.h printers.h ../cups/pwg-private.h classes.h job.h
+job.o: conf.h banners.h dirsvc.h network.h subscriptions.h ../cups/backend.h
+job.o: ../cups/dir.h
+log.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+log.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+log.o: ../cups/language.h ../cups/string-private.h ../config.h
+log.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+log.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+log.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+log.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+log.o: ../cups/thread-private.h ../cups/file-private.h ../cups/cups-private.h
+log.o: mime.h ../cups/array.h ../cups/file.h sysman.h statbuf.h cert.h auth.h
+log.o: client.h policy.h printers.h ../cups/pwg-private.h classes.h job.h
+log.o: conf.h banners.h dirsvc.h network.h subscriptions.h
+network.o: ../cups/http-private.h ../config.h ../cups/http.h
+network.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h cupsd.h
+network.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+network.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+network.o: ../cups/language.h ../cups/string-private.h
+network.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+network.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+network.o: ../cups/language-private.h ../cups/transcode.h
+network.o: ../cups/thread-private.h ../cups/file-private.h
+network.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+network.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h
+network.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+network.o: network.h subscriptions.h
+policy.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+policy.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+policy.o: ../cups/language.h ../cups/string-private.h ../config.h
+policy.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+policy.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+policy.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+policy.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+policy.o: ../cups/thread-private.h ../cups/file-private.h
+policy.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+policy.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h
+policy.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+policy.o: network.h subscriptions.h
+printers.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+printers.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+printers.o: ../cups/language.h ../cups/string-private.h ../config.h
+printers.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+printers.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+printers.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+printers.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+printers.o: ../cups/thread-private.h ../cups/file-private.h
+printers.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+printers.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h
+printers.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+printers.o: network.h subscriptions.h ../cups/dir.h
+process.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+process.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+process.o: ../cups/language.h ../cups/string-private.h ../config.h
+process.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+process.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+process.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+process.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+process.o: ../cups/thread-private.h ../cups/file-private.h
+process.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+process.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h
+process.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+process.o: network.h subscriptions.h
+quotas.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+quotas.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+quotas.o: ../cups/language.h ../cups/string-private.h ../config.h
+quotas.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+quotas.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+quotas.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+quotas.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+quotas.o: ../cups/thread-private.h ../cups/file-private.h
+quotas.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+quotas.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h
+quotas.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+quotas.o: network.h subscriptions.h
+select.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+select.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+select.o: ../cups/language.h ../cups/string-private.h ../config.h
+select.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+select.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+select.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+select.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+select.o: ../cups/thread-private.h ../cups/file-private.h
+select.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+select.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h
+select.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+select.o: network.h subscriptions.h
+server.o: ../cups/http-private.h ../config.h ../cups/http.h
+server.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h cupsd.h
+server.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+server.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+server.o: ../cups/language.h ../cups/string-private.h ../cups/debug-private.h
+server.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+server.o: ../cups/pwg-private.h ../cups/http-private.h
+server.o: ../cups/language-private.h ../cups/transcode.h
+server.o: ../cups/thread-private.h ../cups/file-private.h
+server.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+server.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h
+server.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+server.o: network.h subscriptions.h
+statbuf.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+statbuf.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+statbuf.o: ../cups/language.h ../cups/string-private.h ../config.h
+statbuf.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+statbuf.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+statbuf.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+statbuf.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+statbuf.o: ../cups/thread-private.h ../cups/file-private.h
+statbuf.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+statbuf.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h
+statbuf.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+statbuf.o: network.h subscriptions.h
+subscriptions.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+subscriptions.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+subscriptions.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+subscriptions.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+subscriptions.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+subscriptions.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+subscriptions.o: ../cups/ipp-private.h ../cups/ipp.h
+subscriptions.o: ../cups/language-private.h ../cups/transcode.h
+subscriptions.o: ../cups/thread-private.h ../cups/file-private.h
+subscriptions.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+subscriptions.o: sysman.h statbuf.h cert.h auth.h client.h policy.h
+subscriptions.o: printers.h ../cups/pwg-private.h classes.h job.h conf.h
+subscriptions.o: banners.h dirsvc.h network.h subscriptions.h
+sysman.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+sysman.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+sysman.o: ../cups/language.h ../cups/string-private.h ../config.h
+sysman.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+sysman.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+sysman.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+sysman.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+sysman.o: ../cups/thread-private.h ../cups/file-private.h
+sysman.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h
+sysman.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h
+sysman.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h
+sysman.o: network.h subscriptions.h
+filter.o: ../cups/string-private.h ../config.h ../cups/debug-private.h mime.h
+filter.o: ../cups/array.h ../cups/ipp.h ../cups/file.h
+mime.o: ../cups/string-private.h ../config.h ../cups/debug-private.h
+mime.o: ../cups/dir.h ../cups/versioning.h mime-private.h mime.h
+mime.o: ../cups/array.h ../cups/ipp.h ../cups/file.h
+type.o: ../cups/string-private.h ../config.h ../cups/debug-private.h mime.h
+type.o: ../cups/array.h ../cups/ipp.h ../cups/file.h
+cupsfilter.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+cupsfilter.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+cupsfilter.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+cupsfilter.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+cupsfilter.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+cupsfilter.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+cupsfilter.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+cupsfilter.o: ../cups/transcode.h ../cups/thread-private.h
+cupsfilter.o: ../cups/file-private.h ../cups/cups-private.h
+cupsfilter.o: ../cups/ppd-private.h mime.h ../cups/array.h ../cups/file.h
+cups-deviced.o: util.h ../cups/array-private.h ../cups/array.h
+cups-deviced.o: ../cups/versioning.h ../cups/file-private.h
+cups-deviced.o: ../cups/cups-private.h ../cups/array.h ../cups/dir.h
+cups-exec.o: ../cups/string-private.h ../config.h
+cups-lpd.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+cups-lpd.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+cups-lpd.o: ../cups/language.h ../cups/string-private.h ../config.h
+cups-lpd.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+cups-lpd.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+cups-lpd.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+cups-lpd.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+cups-lpd.o: ../cups/thread-private.h
+cups-polld.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+cups-polld.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+cups-polld.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+cups-polld.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+cups-polld.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+cups-polld.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+cups-polld.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+cups-polld.o: ../cups/transcode.h ../cups/thread-private.h
+testdirsvc.o: ../cups/cups.h ../cups/file.h ../cups/versioning.h
+testdirsvc.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h
+testdirsvc.o: ../cups/string-private.h ../config.h
+testlpd.o: ../cups/cups.h ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+testlpd.o: ../cups/http.h ../cups/array.h ../cups/language.h
+testlpd.o: ../cups/string-private.h ../config.h
+testmime.o: ../cups/string-private.h ../config.h ../cups/dir.h
+testmime.o: ../cups/versioning.h ../cups/debug-private.h
+testmime.o: ../cups/ppd-private.h mime.h ../cups/array.h ../cups/ipp.h
+testmime.o: ../cups/file.h
+testspeed.o: ../cups/string-private.h ../config.h ../cups/cups.h
+testspeed.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+testspeed.o: ../cups/array.h ../cups/language.h ../cups/language.h
+testspeed.o: ../cups/debug-private.h
+testsub.o: ../cups/cups.h ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+testsub.o: ../cups/http.h ../cups/array.h ../cups/language.h
+testsub.o: ../cups/debug-private.h ../cups/string-private.h ../config.h
+util.o: util.h ../cups/array-private.h ../cups/array.h ../cups/versioning.h
+util.o: ../cups/file-private.h ../cups/cups-private.h
+cups-driverd.o: util.h ../cups/array-private.h ../cups/array.h
+cups-driverd.o: ../cups/versioning.h ../cups/file-private.h
+cups-driverd.o: ../cups/cups-private.h ../cups/dir.h ../cups/transcode.h
+cups-driverd.o: ../cups/language.h ../cups/ppd-private.h ../ppdc/ppdc.h
+cups-driverd.o: ../cups/file.h
diff --git a/scheduler/Makefile b/scheduler/Makefile
new file mode 100644
index 000000000..3c7da8e28
--- /dev/null
+++ b/scheduler/Makefile
@@ -0,0 +1,579 @@
+#
+# "$Id$"
+#
+# Scheduler Makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2007 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+CUPSDOBJS = \
+ auth.o \
+ banners.o \
+ cert.o \
+ classes.o \
+ client.o \
+ conf.o \
+ dirsvc.o \
+ env.o \
+ file.o \
+ main.o \
+ ipp.o \
+ listen.o \
+ job.o \
+ log.o \
+ network.o \
+ policy.o \
+ printers.o \
+ process.o \
+ quotas.o \
+ select.o \
+ server.o \
+ statbuf.o \
+ subscriptions.o \
+ sysman.o
+LIBOBJS = \
+ filter.o \
+ mime.o \
+ type.o
+COBJS = \
+ $(CUPSDOBJS) \
+ $(LIBOBJS) \
+ cupsfilter.o \
+ cups-deviced.o \
+ cups-exec.o \
+ cups-lpd.o \
+ cups-polld.o \
+ testdirsvc.o \
+ testlpd.o \
+ testmime.o \
+ testspeed.o \
+ testsub.o \
+ util.o
+CXXOBJS = \
+ cups-driverd.o
+OBJS = \
+ $(COBJS) \
+ $(CXXOBJS)
+LIBTARGETS = \
+ $(LIBCUPSMIME) \
+ libcupsmime.a
+
+UNITTARGETS = \
+ testdirsvc \
+ testlpd \
+ testmime \
+ testspeed \
+ testsub
+
+PROGRAMS = \
+ cupsd \
+ cupsfilter \
+ cups-deviced \
+ cups-driverd \
+ cups-exec \
+ cups-lpd \
+ cups-polld
+
+TARGETS = \
+ $(LIBTARGETS) \
+ $(PROGRAMS)
+
+
+#
+# Make everything...
+#
+
+all: $(TARGETS)
+
+
+#
+# Make library targets...
+#
+
+libs: $(LIBTARGETS)
+
+
+#
+# Make unit tests...
+#
+
+unittests: $(UNITTARGETS)
+
+
+#
+# Clean all object files...
+#
+
+clean:
+ $(RM) $(OBJS)
+ $(RM) $(TARGETS) $(UNITTARGETS) convert
+ $(RM) libcupsmime.so libcupsmime.sl libcupsmime.dylib
+
+
+#
+# Update dependencies (without system header dependencies...)
+#
+
+depend:
+ makedepend -Y -I.. -fDependencies $(COBJS:.o=.c) \
+ $(CXXOBJS:.o=.cxx) >/dev/null 2>&1
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+ echo Creating $(SERVERBIN)/driver...
+ $(INSTALL_DIR) -m 755 $(SERVERBIN)/driver
+ echo Creating $(SERVERROOT)...
+ $(INSTALL_DIR) -m 755 -g $(CUPS_GROUP) $(SERVERROOT)
+ echo Creating $(SERVERROOT)/interfaces...
+ $(INSTALL_DIR) -m 755 -g $(CUPS_GROUP) $(SERVERROOT)/interfaces
+ echo Creating $(SERVERROOT)/ppd...
+ $(INSTALL_DIR) -m 755 -g $(CUPS_GROUP) $(SERVERROOT)/ppd
+ if test "x`uname`" != xDarwin; then \
+ echo Creating $(SERVERROOT)/ssl...; \
+ $(INSTALL_DIR) -m 700 -g $(CUPS_GROUP) $(SERVERROOT)/ssl; \
+ fi
+ if test "$(STATEDIR)" != "$(SERVERROOT)"; then \
+ echo Creating $(STATEDIR)...; \
+ $(INSTALL_DIR) -m 755 $(STATEDIR); \
+ fi
+ echo Creating $(STATEDIR)/certs...
+ $(INSTALL_DIR) -m 511 -o $(CUPS_USER) -g $(CUPS_PRIMARY_SYSTEM_GROUP) \
+ $(STATEDIR)/certs
+ echo Creating $(LOGDIR)...
+ $(INSTALL_DIR) -m 755 $(LOGDIR)
+ echo Creating $(REQUESTS)...
+ $(INSTALL_DIR) -m 710 -g $(CUPS_GROUP) $(REQUESTS)
+ echo Creating $(REQUESTS)/tmp...
+ $(INSTALL_DIR) -m 1770 -g $(CUPS_GROUP) $(REQUESTS)/tmp
+ echo Creating $(CACHEDIR)...
+ $(INSTALL_DIR) -m 775 -g $(CUPS_GROUP) $(CACHEDIR)
+ if test "x$(INITDIR)" != x; then \
+ echo Installing init scripts...; \
+ $(INSTALL_DIR) -m 755 $(BUILDROOT)$(INITDIR)/init.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/init.d/cups; \
+ for level in $(RCLEVELS); do \
+ $(INSTALL_DIR) -m 755 $(BUILDROOT)$(INITDIR)/rc$${level}.d; \
+ $(LN) ../init.d/cups $(BUILDROOT)$(INITDIR)/rc$${level}.d/S$(RCSTART)cups; \
+ if test `uname` = HP-UX; then \
+ level=`expr $$level - 1`; \
+ $(INSTALL_DIR) -m 755 $(BUILDROOT)$(INITDIR)/rc$${level}.d; \
+ fi; \
+ $(LN) ../init.d/cups $(BUILDROOT)$(INITDIR)/rc$${level}.d/K$(RCSTOP)cups; \
+ done; \
+ $(INSTALL_DIR) -m 755 $(BUILDROOT)$(INITDIR)/rc0.d; \
+ $(LN) ../init.d/cups $(BUILDROOT)$(INITDIR)/rc0.d/K$(RCSTOP)cups; \
+ fi
+ if test "x$(INITDIR)" = x -a "x$(INITDDIR)" != x; then \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDDIR); \
+ if test "$(INITDDIR)" = "/System/Library/LaunchDaemons"; then \
+ echo Installing LaunchDaemons configuration files...; \
+ $(INSTALL_DATA) org.cups.cupsd.plist $(BUILDROOT)$(DEFAULT_LAUNCHD_CONF); \
+ $(INSTALL_DATA) org.cups.cups-lpd.plist $(BUILDROOT)/System/Library/LaunchDaemons; \
+ else \
+ echo Installing RC script...; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDDIR)/cups; \
+ fi \
+ fi
+ if test "x$(SMFMANIFESTDIR)" != x; then \
+ echo Installing SMF manifest in $(SMFMANIFESTDIR)...;\
+ $(INSTALL_DIR) $(BUILDROOT)/$(SMFMANIFESTDIR); \
+ $(INSTALL_SCRIPT) cups.xml $(BUILDROOT)$(SMFMANIFESTDIR)/cups.xml; \
+ fi
+ if test "x$(XINETD)" != x; then \
+ echo Installing xinetd configuration file for cups-lpd...; \
+ $(INSTALL_DIR) -m 755 $(BUILDROOT)$(XINETD); \
+ $(INSTALL_DATA) cups-lpd.xinetd $(BUILDROOT)$(XINETD)/cups-lpd; \
+ fi
+
+
+#
+# Install programs...
+#
+
+install-exec:
+ echo Installing programs in $(SBINDIR)...
+ $(INSTALL_DIR) -m 755 $(SBINDIR)
+ $(INSTALL_BIN) -m 500 cupsd $(SBINDIR)
+ $(INSTALL_BIN) cupsfilter $(SBINDIR)
+ -if test "x`uname`" = xDarwin; then \
+ $(INSTALL_DIR) $(BUILDROOT)/System/Library/Printers/Libraries; \
+ $(LN) $(sbindir)/cupsfilter $(BUILDROOT)/System/Library/Printers/Libraries/convert; \
+ fi
+ echo Installing programs in $(SERVERBIN)/daemon...
+ $(INSTALL_DIR) -m 755 $(SERVERBIN)
+ $(INSTALL_DIR) -m 755 $(SERVERBIN)/daemon
+ $(INSTALL_BIN) cups-deviced $(SERVERBIN)/daemon
+ $(INSTALL_BIN) cups-driverd $(SERVERBIN)/daemon
+ $(INSTALL_BIN) cups-exec $(SERVERBIN)/daemon
+ $(INSTALL_BIN) cups-lpd $(SERVERBIN)/daemon
+ $(INSTALL_BIN) cups-polld $(SERVERBIN)/daemon
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ for file in $(PROGRAMS); do \
+ cp $$file $(SYMROOT); \
+ done \
+ fi
+
+
+#
+# Install headers...
+#
+
+install-headers:
+ echo Installing header files in $(INCLUDEDIR)/cups...
+ $(INSTALL_DIR) -m 755 $(INCLUDEDIR)/cups
+ $(INSTALL_DATA) mime.h $(INCLUDEDIR)/cups
+
+
+#
+# Install libraries...
+#
+
+install-libs: $(INSTALLSTATIC)
+ echo Installing libraries in $(LIBDIR)...
+ $(INSTALL_DIR) -m 755 $(LIBDIR)
+ $(INSTALL_LIB) $(LIBCUPSMIME) $(LIBDIR)
+ if test $(LIBCUPSMIME) = "libcupsmime.so.1" -o $(LIBCUPSMIME) = "libcupsmime.sl.1"; then \
+ $(RM) $(LIBDIR)/`basename $(LIBCUPSMIME) .1`; \
+ $(LN) $(LIBCUPSMIME) $(LIBDIR)/`basename $(LIBCUPSMIME) .1`; \
+ fi
+ if test $(LIBCUPSMIME) = "libcupsmime.1.dylib"; then \
+ $(RM) $(LIBDIR)/libcupsmime.dylib; \
+ $(LN) $(LIBCUPSMIME) $(LIBDIR)/libcupsmime.dylib; \
+ fi
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ cp $(LIBCUPSMIME) $(SYMROOT); \
+ fi
+
+installstatic:
+ $(INSTALL_DIR) -m 755 $(LIBDIR)
+ $(INSTALL_LIB) -m 755 libcupsmime.a $(LIBDIR)
+ $(RANLIB) $(LIBDIR)/libcupsmime.a
+ $(CHMOD) 555 $(LIBDIR)/libcupsmime.a
+
+
+#
+# Uninstall the scheduler...
+#
+
+uninstall:
+ $(RM) $(SBINDIR)/cupsd
+ $(RM) $(SBINDIR)/cupsfilter
+ $(RM) $(SERVERBIN)/daemon/cups-deviced
+ $(RM) $(SERVERBIN)/daemon/cups-driverd
+ $(RM) $(SERVERBIN)/daemon/cups-exec
+ $(RM) $(SERVERBIN)/daemon/cups-lpd
+ $(RM) $(SERVERBIN)/daemon/cups-polld
+ $(RM) $(BUILDROOT)/System/Library/Printers/Libraries/convert
+ -$(RMDIR) $(STATEDIR)/certs
+ -$(RMDIR) $(STATEDIR)
+ -$(RMDIR) $(SERVERROOT)/ppd
+ -$(RMDIR) $(SERVERROOT)/interfaces
+ -$(RMDIR) $(SERVERROOT)
+ -$(RMDIR) $(SERVERBIN)/driver
+ -$(RMDIR) $(SERVERBIN)/daemon
+ -$(RMDIR) $(SERVERBIN)
+ -$(RMDIR) $(SBINDIR)
+ -$(RMDIR) $(REQUESTS)/tmp
+ -$(RMDIR) $(REQUESTS)
+ -$(RMDIR) $(LOGDIR)
+ -$(RMDIR) $(CACHEDIR)
+ $(RM) $(LIBDIR)/libcupsmime.1.dylib
+ $(RM) $(LIBDIR)/libcupsmime.a
+ $(RM) $(LIBDIR)/libcupsmime.dylib
+ $(RM) $(LIBDIR)/libcupsmime_s.a
+ $(RM) $(LIBDIR)/libcupsmime.sl
+ $(RM) $(LIBDIR)/libcupsmime.sl.1
+ $(RM) $(LIBDIR)/libcupsmime.so
+ $(RM) $(LIBDIR)/libcupsmime.so.1
+ -$(RMDIR) $(LIBDIR)
+ $(RM) $(INCLUDEDIR)/cups/mime.h
+ -$(RMDIR) $(INCLUDEDIR)/cups
+ echo Uninstalling startup script...
+ if test "x$(INITDIR)" != x; then \
+ $(RM) $(BUILDROOT)$(INITDIR)/init.d/cups; \
+ $(RMDIR) $(BUILDROOT)$(INITDIR)/init.d; \
+ $(RM) $(BUILDROOT)$(INITDIR)/rc0.d/K00cups; \
+ $(RMDIR) $(BUILDROOT)$(INITDIR)/rc0.d; \
+ $(RM) $(BUILDROOT)$(INITDIR)/rc2.d/S99cups; \
+ $(RMDIR) $(BUILDROOT)$(INITDIR)/rc2.d; \
+ $(RM) $(BUILDROOT)$(INITDIR)/rc3.d/S99cups; \
+ $(RMDIR) $(BUILDROOT)$(INITDIR)/rc3.d; \
+ $(RM) $(BUILDROOT)$(INITDIR)/rc5.d/S99cups; \
+ $(RMDIR) $(BUILDROOT)$(INITDIR)/rc5.d; \
+ fi
+ if test "x$(INITDIR)" = x -a "x$(INITDDIR)" != x; then \
+ if test "$(INITDDIR)" = "/System/Library/StartupItems/PrintingServices"; then \
+ $(RM) $(BUILDROOT)$(INITDDIR)/PrintingServices; \
+ $(RM) $(BUILDROOT)$(INITDDIR)/StartupParameters.plist; \
+ $(RM) $(BUILDROOT)$(INITDDIR)/Resources/English.lproj/Localizable.strings; \
+ $(RMDIR) $(BUILDROOT)$(INITDDIR)/Resources/English.lproj; \
+ elif test "$(INITDDIR)" = "/System/Library/LaunchDaemons"; then \
+ $(RM) $(BUILDROOT)$(INITDDIR)/org.cups.cupsd.plist; \
+ $(RM) $(BUILDROOT)$(INITDDIR)/org.cups.cups-lpd.plist; \
+ $(RMDIR) $(BUILDROOT)/System/Library/StartupItems/PrintingServices; \
+ else \
+ $(INSTALL_SCRIPT) init/cups.sh $(BUILDROOT)$(INITDDIR)/cups; \
+ fi \
+ $(RMDIR) $(BUILDROOT)$(INITDDIR); \
+ fi
+ if test "x$(SMFMANIFESTDIR)" != x; then \
+ echo Uninstalling SMF manifest in $(SMFMANIFESTDIR)...;\
+ $(RM) $(BUILDROOT)$(SMFMANIFESTDIR)/cups.xml; \
+ fi
+ if test "x$(XINETD)" != x; then \
+ echo Uninstalling xinetd configuration file for cups-lpd...; \
+ $(RM) $(BUILDROOT)$(XINETD)/cups-lpd; \
+ fi
+
+
+#
+# Automatic API help files...
+#
+
+apihelp:
+ mxmldoc --section "Programming" \
+ --title "MIME API" \
+ --css ../doc/cups-printable.css \
+ --header api-mime.header --intro api-mime.shtml \
+ mime.h $(LIBOBJS:.o=.c) >../doc/help/api-mime.html
+ mxmldoc --tokens help/api-mime.html api-mime.xml >../doc/help/api-mime.tokens
+ $(RM) api-mime.xml
+
+framedhelp:
+ mxmldoc --framed api-mime \
+ --section "Programming" \
+ --title "MIME API" \
+ --css ../doc/cups-printable.css \
+ --header api-mime.header --intro api-mime.shtml \
+ mime.h $(LIBOBJS:.o=.c)
+
+
+#
+# Make the scheduler executable, "cupsd".
+#
+
+cupsd: $(CUPSDOBJS) $(LIBCUPSMIME) ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cupsd $(CUPSDOBJS) -L. -lcupsmime \
+ $(LIBZ) $(SSLLIBS) $(LIBSLP) $(LIBLDAP) $(PAMLIBS) \
+ $(LIBPAPER) $(LIBMALLOC) $(SERVERLIBS) $(DNSSDLIBS) $(LIBS) \
+ $(LIBGSSAPI) $(LIBWRAP)
+
+cupsd-static: $(CUPSDOBJS) libcupsmime.a ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cupsd-static $(CUPSDOBJS) libcupsmime.a \
+ $(LIBZ) $(SSLLIBS) $(LIBSLP) $(LIBLDAP) $(PAMLIBS) \
+ ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(LIBZ) $(LIBPAPER) \
+ $(LIBMALLOC) $(SERVERLIBS) $(DNSSDLIBS) $(LIBGSSAPI) \
+ $(LIBWRAP)
+
+
+#
+# Make the cupsfilter utility.
+#
+
+cupsfilter: cupsfilter.o $(LIBCUPSMIME) ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cupsfilter cupsfilter.o -L. -lcupsmime $(LIBS)
+ $(RM) convert
+ $(LN) cupsfilter convert
+
+
+#
+# Make the device daemon, "cups-deviced".
+#
+
+cups-deviced: cups-deviced.o util.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cups-deviced cups-deviced.o util.o $(LIBS)
+
+
+#
+# Make the driver daemon, "cups-driverd".
+#
+
+cups-driverd: cups-driverd.o util.o ../cups/$(LIBCUPS) ../ppdc/$(LIBCUPSPPDC)
+ echo Linking $@...
+ $(CXX) $(LDFLAGS) -o cups-driverd cups-driverd.o util.o \
+ -L../ppdc -lcupsppdc $(LIBS)
+
+
+#
+# Make the sandbox execution helper, "cups-exec".
+#
+
+cups-exec: cups-exec.o
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cups-exec cups-exec.o $(LIBS)
+
+
+#
+# Make the line printer daemon, "cups-lpd".
+#
+
+cups-lpd: cups-lpd.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cups-lpd cups-lpd.o $(LIBS)
+
+
+#
+# Make the polling daemon, "cups-polld".
+#
+
+cups-polld: cups-polld.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cups-polld cups-polld.o $(LIBS)
+
+
+#
+# libcupsmime.so.1, libcupsmime.sl.1
+#
+
+libcupsmime.so.1 libcupsmime.sl.1: $(LIBOBJS)
+ echo Linking $@...
+ $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS) $(LIBS)
+ $(RM) `basename $@ .1`
+ $(LN) $@ `basename $@ .1`
+
+
+#
+# libcupsmime.1.dylib
+#
+
+libcupsmime.1.dylib: $(LIBOBJS) libcupsmime.exp
+ echo Linking $@...
+ $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ \
+ -install_name $(libdir)/$@ \
+ -current_version 1.0.0 \
+ -compatibility_version 1.0.0 \
+ -exported_symbols_list libcupsmime.exp \
+ $(LIBOBJS) $(LIBS)
+ $(RM) libcupsmime.dylib
+ $(LN) $@ libcupsmime.dylib
+
+
+#
+# libcupsmime_s.a
+#
+
+libcupsmime_s.a: $(LIBOBJS)
+ echo Creating $@...
+ $(DSO) $(DSOFLAGS) -o libcupsmime_s.o $(LIBOBJS) $(LIBS)
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ libcupsmime_s.o
+
+
+#
+# libcupsmime.la
+#
+
+libcupsmime.la: $(LIBOBJS)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS:.o=.lo) -rpath $(LIBDIR) \
+ -version-info 1:0 $(LIBS)
+
+
+#
+# libcupsmime.a
+#
+
+libcupsmime.a: $(LIBOBJS)
+ echo Archiving $@...
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ $(LIBOBJS)
+ $(RANLIB) $@
+
+
+#
+# Make the test program, "testdirsvc".
+#
+
+testdirsvc: testdirsvc.o
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o testdirsvc testdirsvc.o $(COMMONLIBS) $(NETLIBS)
+
+
+#
+# Make the test program, "testlpd".
+#
+
+testlpd: testlpd.o ../cups/$(LIBCUPSSTATIC) cups-lpd
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o testlpd testlpd.o ../cups/$(LIBCUPSSTATIC) \
+ $(COMMONLIBS) $(LIBZ) $(SSLLIBS) $(DNSSDLIBS) $(LIBGSSAPI)
+
+
+#
+# testmime
+#
+
+testmime: testmime.o libcupsmime.a ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testmime.o libcupsmime.a \
+ ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(LIBZ) $(SSLLIBS) \
+ $(DNSSDLIBS) $(LIBGSSAPI)
+ echo Running MIME tests...
+ ./testmime
+
+
+#
+# Make the test program, "testspeed".
+#
+
+testspeed: testspeed.o ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o testspeed testspeed.o ../cups/$(LIBCUPSSTATIC) \
+ $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) $(LIBGSSAPI)
+
+
+#
+# Make the test program, "testsub".
+#
+
+testsub: testsub.o ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o testsub testsub.o ../cups/$(LIBCUPSSTATIC) \
+ $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) $(LIBGSSAPI)
+
+
+#
+# Lines of code computation...
+#
+
+sloc:
+ echo "cupsd: \c"
+ sloccount $(CUPSDOBJS:.o=.c) $(LIBOBJS:.o=.c) cups-driverd.cxx cups-polld.c cups-lpd.c 2>/dev/null | grep "Total Physical" | awk '{print $$9}'
+
+
+#
+# Dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id$".
+#
diff --git a/scheduler/api-mime.header b/scheduler/api-mime.header
new file mode 100644
index 000000000..8d5db2ad6
--- /dev/null
+++ b/scheduler/api-mime.header
@@ -0,0 +1,34 @@
+<!--
+ "$Id: api-array.header 8087 2008-10-27 21:37:05Z mike $"
+
+ MIME API header for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h1 class='title'>MIME API</h1>
+
+<div class='summary'><table summary='General Information'>
+<thead>
+<tr>
+ <th>Header</th>
+ <th>cups/mime.h</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <th>Library</th>
+ <td>-lcupsmime</td>
+</tr>
+<tr>
+ <th>See Also</th>
+ <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/scheduler/api-mime.shtml b/scheduler/api-mime.shtml
new file mode 100644
index 000000000..7d3125fad
--- /dev/null
+++ b/scheduler/api-mime.shtml
@@ -0,0 +1,17 @@
+<!--
+ "$Id: api-array.shtml 7616 2008-05-28 00:34:13Z mike $"
+
+ MIME API introduction for CUPS.
+
+ Copyright 2009 by Apple Inc.
+
+ These coded instructions, statements, and computer programs are the
+ property of Apple Inc. 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
+ file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<h2 class='title'><a name='OVERVIEW'>Overview</a></h2>
+
+<p>The MIME API provides file typing and conversion services for CUPS.</p>
diff --git a/scheduler/auth.c b/scheduler/auth.c
new file mode 100644
index 000000000..b319d2341
--- /dev/null
+++ b/scheduler/auth.c
@@ -0,0 +1,2586 @@
+/*
+ * "$Id$"
+ *
+ * Authorization routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * This file contains Kerberos support code, copyright 2006 by
+ * Jelmer Vernooij.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdAddIPMask() - Add an IP address authorization mask.
+ * cupsdAddLocation() - Add a location for authorization.
+ * cupsdAddName() - Add a name to a location...
+ * cupsdAddNameMask() - Add a host or interface name authorization
+ * mask.
+ * cupsdAuthorize() - Validate any authorization credentials.
+ * cupsdCheckAccess() - Check whether the given address is allowed to
+ * access a location.
+ * cupsdCheckAuth() - Check authorization masks.
+ * cupsdCheckGroup() - Check for a user's group membership.
+ * cupsdCopyLocation() - Make a copy of a location...
+ * cupsdDeleteAllLocations() - Free all memory used for location
+ * authorization.
+ * cupsdFindBest() - Find the location entry that best matches the
+ * resource.
+ * cupsdFindLocation() - Find the named location.
+ * cupsdFreeLocation() - Free all memory used by a location.
+ * cupsdIsAuthorized() - Check to see if the user is authorized...
+ * cupsdNewLocation() - Create a new location for authorization.
+ * check_authref() - Check if an authorization services reference
+ * has the supplied right.
+ * compare_locations() - Compare two locations.
+ * copy_authmask() - Copy function for auth masks.
+ * cups_crypt() - Encrypt the password using the DES or MD5
+ * algorithms, as needed.
+ * free_authmask() - Free function for auth masks.
+ * get_md5_password() - Get an MD5 password.
+ * pam_func() - PAM conversation function.
+ * to64() - Base64-encode an integer value...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <grp.h>
+#ifdef HAVE_SHADOW_H
+# include <shadow.h>
+#endif /* HAVE_SHADOW_H */
+#ifdef HAVE_CRYPT_H
+# include <crypt.h>
+#endif /* HAVE_CRYPT_H */
+#if HAVE_LIBPAM
+# ifdef HAVE_PAM_PAM_APPL_H
+# include <pam/pam_appl.h>
+# else
+# include <security/pam_appl.h>
+# endif /* HAVE_PAM_PAM_APPL_H */
+#endif /* HAVE_LIBPAM */
+#ifdef HAVE_USERSEC_H
+# include <usersec.h>
+#endif /* HAVE_USERSEC_H */
+#ifdef HAVE_MEMBERSHIP_H
+# include <membership.h>
+#endif /* HAVE_MEMBERSHIP_H */
+#ifdef HAVE_AUTHORIZATION_H
+# include <Security/AuthorizationTags.h>
+# ifdef HAVE_SECBASEPRIV_H
+# include <Security/SecBasePriv.h>
+# else
+extern const char *cssmErrorString(int error);
+# endif /* HAVE_SECBASEPRIV_H */
+#endif /* HAVE_AUTHORIZATION_H */
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif /* HAVE_SYS_PARAM_H */
+#ifdef HAVE_SYS_UCRED_H
+# include <sys/ucred.h>
+typedef struct xucred cupsd_ucred_t;
+# define CUPSD_UCRED_UID(c) (c).cr_uid
+#else
+typedef struct ucred cupsd_ucred_t;
+# define CUPSD_UCRED_UID(c) (c).uid
+#endif /* HAVE_SYS_UCRED_H */
+#ifdef HAVE_KRB5_IPC_CLIENT_SET_TARGET_UID
+/* Not in public headers... */
+extern void krb5_ipc_client_set_target_uid(uid_t);
+extern void krb5_ipc_client_clear_target(void);
+#endif /* HAVE_KRB5_IPC_CLIENT_SET_TARGET_UID */
+
+
+/*
+ * Local functions...
+ */
+
+#ifdef HAVE_AUTHORIZATION_H
+static int check_authref(cupsd_client_t *con, const char *right);
+#endif /* HAVE_AUTHORIZATION_H */
+static int compare_locations(cupsd_location_t *a,
+ cupsd_location_t *b);
+static cupsd_authmask_t *copy_authmask(cupsd_authmask_t *am, void *data);
+#if !HAVE_LIBPAM && !defined(HAVE_USERSEC_H)
+static char *cups_crypt(const char *pw, const char *salt);
+#endif /* !HAVE_LIBPAM && !HAVE_USERSEC_H */
+static void free_authmask(cupsd_authmask_t *am, void *data);
+static char *get_md5_password(const char *username,
+ const char *group, char passwd[33]);
+#if HAVE_LIBPAM
+static int pam_func(int, const struct pam_message **,
+ struct pam_response **, void *);
+#elif !defined(HAVE_USERSEC_H)
+static void to64(char *s, unsigned long v, int n);
+#endif /* HAVE_LIBPAM */
+
+
+/*
+ * Local structures...
+ */
+
+#if HAVE_LIBPAM
+typedef struct cupsd_authdata_s /**** Authentication data ****/
+{
+ char username[33], /* Username string */
+ password[33]; /* Password string */
+} cupsd_authdata_t;
+#endif /* HAVE_LIBPAM */
+
+
+/*
+ * Local globals...
+ */
+
+#if defined(__hpux) && HAVE_LIBPAM
+static cupsd_authdata_t *auth_data; /* Current client being authenticated */
+#endif /* __hpux && HAVE_LIBPAM */
+
+
+/*
+ * 'cupsdAddIPMask()' - Add an IP address authorization mask.
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsdAddIPMask(
+ cups_array_t **masks, /* IO - Masks array (created as needed) */
+ const unsigned address[4], /* I - IP address */
+ const unsigned netmask[4]) /* I - IP netmask */
+{
+ cupsd_authmask_t temp; /* New host/domain mask */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdAddIPMask(masks=%p(%p), address=%x:%x:%x:%x, "
+ "netmask=%x:%x:%x:%x)",
+ masks, *masks,
+ address[0], address[1], address[2], address[3],
+ netmask[0], netmask[1], netmask[2], netmask[3]);
+
+ temp.type = CUPSD_AUTH_IP;
+ memcpy(temp.mask.ip.address, address, sizeof(temp.mask.ip.address));
+ memcpy(temp.mask.ip.netmask, netmask, sizeof(temp.mask.ip.netmask));
+
+ /*
+ * Create the masks array as needed and add...
+ */
+
+ if (!*masks)
+ *masks = cupsArrayNew3(NULL, NULL, NULL, 0,
+ (cups_acopy_func_t)copy_authmask,
+ (cups_afree_func_t)free_authmask);
+
+ return (cupsArrayAdd(*masks, &temp));
+}
+
+
+/*
+ * 'cupsdAddLocation()' - Add a location for authorization.
+ */
+
+void
+cupsdAddLocation(cupsd_location_t *loc) /* I - Location to add */
+{
+ /*
+ * Make sure the locations array is created...
+ */
+
+ if (!Locations)
+ Locations = cupsArrayNew3((cups_array_func_t)compare_locations, NULL,
+ (cups_ahash_func_t)NULL, 0,
+ (cups_acopy_func_t)NULL,
+ (cups_afree_func_t)cupsdFreeLocation);
+
+ if (Locations)
+ {
+ cupsArrayAdd(Locations, loc);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddLocation: Added location \"%s\"",
+ loc->location ? loc->location : "(null)");
+ }
+}
+
+
+/*
+ * 'cupsdAddName()' - Add a name to a location...
+ */
+
+void
+cupsdAddName(cupsd_location_t *loc, /* I - Location to add to */
+ char *name) /* I - Name to add */
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddName(loc=%p, name=\"%s\")",
+ loc, name);
+
+ if (!loc->names)
+ loc->names = cupsArrayNew3(NULL, NULL, NULL, 0,
+ (cups_acopy_func_t)_cupsStrAlloc,
+ (cups_afree_func_t)_cupsStrFree);
+
+ if (!cupsArrayAdd(loc->names, name))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to duplicate name for location %s: %s",
+ loc->location ? loc->location : "nil", strerror(errno));
+ return;
+ }
+}
+
+
+/*
+ * 'cupsdAddNameMask()' - Add a host or interface name authorization mask.
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsdAddNameMask(cups_array_t **masks, /* IO - Masks array (created as needed) */
+ char *name) /* I - Host or interface name */
+{
+ cupsd_authmask_t temp; /* New host/domain mask */
+ char ifname[32], /* Interface name */
+ *ifptr; /* Pointer to end of name */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdAddNameMask(masks=%p(%p), name=\"%s\")",
+ masks, *masks, name);
+
+ if (!_cups_strcasecmp(name, "@LOCAL"))
+ {
+ /*
+ * Deny *interface*...
+ */
+
+ temp.type = CUPSD_AUTH_INTERFACE;
+ temp.mask.name.name = (char *)"*";
+ }
+ else if (!_cups_strncasecmp(name, "@IF(", 4))
+ {
+ /*
+ * Deny *interface*...
+ */
+
+ strlcpy(ifname, name + 4, sizeof(ifname));
+
+ ifptr = ifname + strlen(ifname) - 1;
+
+ if (ifptr >= ifname && *ifptr == ')')
+ {
+ ifptr --;
+ *ifptr = '\0';
+ }
+
+ temp.type = CUPSD_AUTH_INTERFACE;
+ temp.mask.name.name = ifname;
+ }
+ else
+ {
+ /*
+ * Deny name...
+ */
+
+ if (*name == '*')
+ name ++;
+
+ temp.type = CUPSD_AUTH_NAME;
+ temp.mask.name.name = (char *)name;
+ }
+
+ /*
+ * Set the name length...
+ */
+
+ temp.mask.name.length = strlen(temp.mask.name.name);
+
+ /*
+ * Create the masks array as needed and add...
+ */
+
+ if (!*masks)
+ *masks = cupsArrayNew3(NULL, NULL, NULL, 0,
+ (cups_acopy_func_t)copy_authmask,
+ (cups_afree_func_t)free_authmask);
+
+ return (cupsArrayAdd(*masks, &temp));
+}
+
+
+/*
+ * 'cupsdAuthorize()' - Validate any authorization credentials.
+ */
+
+void
+cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
+{
+ int type; /* Authentication type */
+ const char *authorization; /* Pointer into Authorization string */
+ char *ptr, /* Pointer into string */
+ username[256], /* Username string */
+ password[33]; /* Password string */
+ cupsd_cert_t *localuser; /* Certificate username */
+ char nonce[HTTP_MAX_VALUE], /* Nonce value from client */
+ md5[33], /* MD5 password */
+ basicmd5[33]; /* MD5 of Basic password */
+ static const char * const states[] = /* HTTP client states... */
+ {
+ "WAITING",
+ "OPTIONS",
+ "GET",
+ "GET",
+ "HEAD",
+ "POST",
+ "POST",
+ "POST",
+ "PUT",
+ "PUT",
+ "DELETE",
+ "TRACE",
+ "CLOSE",
+ "STATUS"
+ };
+
+
+ /*
+ * Locate the best matching location so we know what kind of
+ * authentication to expect...
+ */
+
+ con->best = cupsdFindBest(con->uri, con->http.state);
+ con->type = CUPSD_AUTH_NONE;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdAuthorize: con->uri=\"%s\", con->best=%p(%s)",
+ con->uri, con->best, con->best ? con->best->location : "");
+
+ if (con->best && con->best->type != CUPSD_AUTH_NONE)
+ {
+ if (con->best->type == CUPSD_AUTH_DEFAULT)
+ type = DefaultAuthType;
+ else
+ type = con->best->type;
+ }
+ else
+ type = DefaultAuthType;
+
+ /*
+ * Decode the Authorization string...
+ */
+
+ authorization = httpGetField(&con->http, HTTP_FIELD_AUTHORIZATION);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAuthorize: Authorization=\"%s\"",
+ authorization);
+
+ username[0] = '\0';
+ password[0] = '\0';
+
+#ifdef HAVE_GSSAPI
+ con->gss_uid = 0;
+#endif /* HAVE_GSSAPI */
+
+#ifdef HAVE_AUTHORIZATION_H
+ if (con->authref)
+ {
+ AuthorizationFree(con->authref, kAuthorizationFlagDefaults);
+ con->authref = NULL;
+ }
+#endif /* HAVE_AUTHORIZATION_H */
+
+ if (!*authorization)
+ {
+ /*
+ * No authorization data provided, return early...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: No authentication data provided.");
+ return;
+ }
+#ifdef HAVE_AUTHORIZATION_H
+ else if (!strncmp(authorization, "AuthRef ", 8) &&
+ !_cups_strcasecmp(con->http.hostname, "localhost"))
+ {
+ OSStatus status; /* Status */
+ int authlen; /* Auth string length */
+ AuthorizationItemSet *authinfo; /* Authorization item set */
+
+ /*
+ * Get the Authorization Services data...
+ */
+
+ authorization += 8;
+ while (isspace(*authorization & 255))
+ authorization ++;
+
+ authlen = sizeof(nonce);
+ httpDecode64_2(nonce, &authlen, authorization);
+
+ if (authlen != kAuthorizationExternalFormLength)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "External Authorization reference size is incorrect!");
+ return;
+ }
+
+ if ((status = AuthorizationCreateFromExternalForm(
+ (AuthorizationExternalForm *)nonce, &con->authref)) != 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "AuthorizationCreateFromExternalForm returned %d (%s)",
+ (int)status, cssmErrorString(status));
+ return;
+ }
+
+ username[0] = '\0';
+
+ if (!AuthorizationCopyInfo(con->authref, kAuthorizationEnvironmentUsername,
+ &authinfo))
+ {
+ if (authinfo->count == 1 && authinfo->items[0].value &&
+ authinfo->items[0].valueLength >= 2)
+ {
+ strlcpy(username, authinfo->items[0].value, sizeof(username));
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as \"%s\" using AuthRef",
+ username);
+ }
+
+ AuthorizationFreeItemSet(authinfo);
+ }
+
+ if (!username[0])
+ {
+ /*
+ * No username in AuthRef, grab username using peer credentials...
+ */
+
+ struct passwd *pwd; /* Password entry for this user */
+ cupsd_ucred_t peercred; /* Peer credentials */
+ socklen_t peersize; /* Size of peer credentials */
+
+ peersize = sizeof(peercred);
+
+ if (getsockopt(con->http.fd, 0, LOCAL_PEERCRED, &peercred, &peersize))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get peer credentials - %s",
+ strerror(errno));
+ return;
+ }
+
+ if ((pwd = getpwuid(CUPSD_UCRED_UID(peercred))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to find UID %d for peer credentials.",
+ (int)CUPSD_UCRED_UID(peercred));
+ return;
+ }
+
+ strlcpy(username, pwd->pw_name, sizeof(username));
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as \"%s\" using "
+ "AuthRef + PeerCred", username);
+ }
+
+ con->type = CUPSD_AUTH_BASIC;
+ }
+#endif /* HAVE_AUTHORIZATION_H */
+#if defined(SO_PEERCRED) && defined(AF_LOCAL)
+ else if (!strncmp(authorization, "PeerCred ", 9) &&
+ con->http.hostaddr->addr.sa_family == AF_LOCAL)
+ {
+ /*
+ * Use peer credentials from domain socket connection...
+ */
+
+ struct passwd *pwd; /* Password entry for this user */
+ cupsd_ucred_t peercred; /* Peer credentials */
+ socklen_t peersize; /* Size of peer credentials */
+#ifdef HAVE_AUTHORIZATION_H
+ const char *name; /* Authorizing name */
+
+ for (name = (char *)cupsArrayFirst(con->best->names);
+ name;
+ name = (char *)cupsArrayNext(con->best->names))
+ if (!_cups_strncasecmp(name, "@AUTHKEY(", 9) || !_cups_strcasecmp(name, "@SYSTEM"))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "PeerCred authentication not allowed for resource.");
+ return;
+ }
+#endif /* HAVE_AUTHORIZATION_H */
+
+ if ((pwd = getpwnam(authorization + 9)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "User \"%s\" does not exist.",
+ authorization + 9);
+ return;
+ }
+
+ peersize = sizeof(peercred);
+
+# ifdef __APPLE__
+ if (getsockopt(con->http.fd, 0, LOCAL_PEERCRED, &peercred, &peersize))
+# else
+ if (getsockopt(con->http.fd, SOL_SOCKET, SO_PEERCRED, &peercred, &peersize))
+# endif /* __APPLE__ */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get peer credentials - %s",
+ strerror(errno));
+ return;
+ }
+
+ if (pwd->pw_uid != CUPSD_UCRED_UID(peercred))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Invalid peer credentials for \"%s\" - got %d, "
+ "expected %d!", authorization + 9,
+ CUPSD_UCRED_UID(peercred), pwd->pw_uid);
+# ifdef HAVE_SYS_UCRED_H
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: cr_version=%d",
+ peercred.cr_version);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: cr_uid=%d",
+ peercred.cr_uid);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: cr_ngroups=%d",
+ peercred.cr_ngroups);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: cr_groups[0]=%d",
+ peercred.cr_groups[0]);
+# endif /* HAVE_SYS_UCRED_H */
+ return;
+ }
+
+ strlcpy(username, authorization + 9, sizeof(username));
+
+# ifdef HAVE_GSSAPI
+ con->gss_uid = CUPSD_UCRED_UID(peercred);
+# endif /* HAVE_GSSAPI */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as %s using PeerCred",
+ username);
+
+ con->type = CUPSD_AUTH_BASIC;
+ }
+#endif /* SO_PEERCRED && AF_LOCAL */
+ else if (!strncmp(authorization, "Local", 5) &&
+ !_cups_strcasecmp(con->http.hostname, "localhost"))
+ {
+ /*
+ * Get Local certificate authentication data...
+ */
+
+ authorization += 5;
+ while (isspace(*authorization & 255))
+ authorization ++;
+
+ if ((localuser = cupsdFindCert(authorization)) != NULL)
+ {
+ strlcpy(username, localuser->username, sizeof(username));
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as %s using Local",
+ username);
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Local authentication certificate not "
+ "found!");
+ return;
+ }
+
+#ifdef HAVE_GSSAPI
+ if (localuser->ccache)
+ con->type = CUPSD_AUTH_NEGOTIATE;
+ else
+#endif /* HAVE_GSSAPI */
+ con->type = CUPSD_AUTH_BASIC;
+ }
+ else if (!strncmp(authorization, "Basic", 5))
+ {
+ /*
+ * Get the Basic authentication data...
+ */
+
+ int userlen; /* Username:password length */
+
+
+ authorization += 5;
+ while (isspace(*authorization & 255))
+ authorization ++;
+
+ userlen = sizeof(username);
+ httpDecode64_2(username, &userlen, authorization);
+
+ /*
+ * Pull the username and password out...
+ */
+
+ if ((ptr = strchr(username, ':')) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Missing Basic password!");
+ return;
+ }
+
+ *ptr++ = '\0';
+
+ if (!username[0])
+ {
+ /*
+ * Username must not be empty...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Empty Basic username!");
+ return;
+ }
+
+ if (!*ptr)
+ {
+ /*
+ * Password must not be empty...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Empty Basic password!");
+ return;
+ }
+
+ strlcpy(password, ptr, sizeof(password));
+
+ /*
+ * Validate the username and password...
+ */
+
+ switch (type)
+ {
+ default :
+ case CUPSD_AUTH_BASIC :
+ {
+#if HAVE_LIBPAM
+ /*
+ * Only use PAM to do authentication. This supports MD5
+ * passwords, among other things...
+ */
+
+ pam_handle_t *pamh; /* PAM authentication handle */
+ int pamerr; /* PAM error code */
+ struct pam_conv pamdata;/* PAM conversation data */
+ cupsd_authdata_t data; /* Authentication data */
+
+
+ strlcpy(data.username, username, sizeof(data.username));
+ strlcpy(data.password, password, sizeof(data.password));
+
+# if defined(__sun) || defined(__hpux)
+ pamdata.conv = (int (*)(int, struct pam_message **,
+ struct pam_response **,
+ void *))pam_func;
+# else
+ pamdata.conv = pam_func;
+# endif /* __sun || __hpux */
+ pamdata.appdata_ptr = &data;
+
+# ifdef __hpux
+ /*
+ * Workaround for HP-UX bug in pam_unix; see pam_func() below for
+ * more info...
+ */
+
+ auth_data = &data;
+# endif /* __hpux */
+
+ pamerr = pam_start("cups", username, &pamdata, &pamh);
+ if (pamerr != PAM_SUCCESS)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: pam_start() returned %d (%s)!",
+ pamerr, pam_strerror(pamh, pamerr));
+ return;
+ }
+
+# ifdef HAVE_PAM_SET_ITEM
+# ifdef PAM_RHOST
+ pamerr = pam_set_item(pamh, PAM_RHOST, con->http.hostname);
+ if (pamerr != PAM_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "cupsdAuthorize: pam_set_item(PAM_RHOST) "
+ "returned %d (%s)!", pamerr,
+ pam_strerror(pamh, pamerr));
+# endif /* PAM_RHOST */
+
+# ifdef PAM_TTY
+ pamerr = pam_set_item(pamh, PAM_TTY, "cups");
+ if (pamerr != PAM_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "cupsdAuthorize: pam_set_item(PAM_TTY) "
+ "returned %d (%s)!", pamerr,
+ pam_strerror(pamh, pamerr));
+# endif /* PAM_TTY */
+# endif /* HAVE_PAM_SET_ITEM */
+
+ pamerr = pam_authenticate(pamh, PAM_SILENT);
+ if (pamerr != PAM_SUCCESS)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: pam_authenticate() returned %d "
+ "(%s)!",
+ pamerr, pam_strerror(pamh, pamerr));
+ pam_end(pamh, 0);
+ return;
+ }
+
+# ifdef HAVE_PAM_SETCRED
+ pamerr = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT);
+ if (pamerr != PAM_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "cupsdAuthorize: pam_setcred() "
+ "returned %d (%s)!", pamerr,
+ pam_strerror(pamh, pamerr));
+# endif /* HAVE_PAM_SETCRED */
+
+ pamerr = pam_acct_mgmt(pamh, PAM_SILENT);
+ if (pamerr != PAM_SUCCESS)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: pam_acct_mgmt() returned %d "
+ "(%s)!",
+ pamerr, pam_strerror(pamh, pamerr));
+ pam_end(pamh, 0);
+ return;
+ }
+
+ pam_end(pamh, PAM_SUCCESS);
+
+#elif defined(HAVE_USERSEC_H)
+ /*
+ * Use AIX authentication interface...
+ */
+
+ char *authmsg; /* Authentication message */
+ int reenter; /* ??? */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: AIX authenticate of username "
+ "\"%s\"", username);
+
+ reenter = 1;
+ if (authenticate(username, password, &reenter, &authmsg) != 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Unable to authenticate username "
+ "\"%s\": %s",
+ username, strerror(errno));
+ return;
+ }
+
+#else
+ /*
+ * Use normal UNIX password file-based authentication...
+ */
+
+ char *pass; /* Encrypted password */
+ struct passwd *pw; /* User password data */
+# ifdef HAVE_SHADOW_H
+ struct spwd *spw; /* Shadow password data */
+# endif /* HAVE_SHADOW_H */
+
+
+ pw = getpwnam(username); /* Get the current password */
+ endpwent(); /* Close the password file */
+
+ if (!pw)
+ {
+ /*
+ * No such user...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Unknown username \"%s\"!",
+ username);
+ return;
+ }
+
+# ifdef HAVE_SHADOW_H
+ spw = getspnam(username);
+ endspent();
+
+ if (!spw && !strcmp(pw->pw_passwd, "x"))
+ {
+ /*
+ * Don't allow blank passwords!
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Username \"%s\" has no shadow "
+ "password!", username);
+ return;
+ }
+
+ if (spw && !spw->sp_pwdp[0] && !pw->pw_passwd[0])
+# else
+ if (!pw->pw_passwd[0])
+# endif /* HAVE_SHADOW_H */
+ {
+ /*
+ * Don't allow blank passwords!
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Username \"%s\" has no password!",
+ username);
+ return;
+ }
+
+ /*
+ * OK, the password isn't blank, so compare with what came from the
+ * client...
+ */
+
+ pass = cups_crypt(password, pw->pw_passwd);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdAuthorize: pw_passwd=\"%s\", crypt=\"%s\"",
+ pw->pw_passwd, pass);
+
+ if (!pass || strcmp(pw->pw_passwd, pass))
+ {
+# ifdef HAVE_SHADOW_H
+ if (spw)
+ {
+ pass = cups_crypt(password, spw->sp_pwdp);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdAuthorize: sp_pwdp=\"%s\", crypt=\"%s\"",
+ spw->sp_pwdp, pass);
+
+ if (pass == NULL || strcmp(spw->sp_pwdp, pass))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Authentication failed for "
+ "user \"%s\"!",
+ username);
+ return;
+ }
+ }
+ else
+# endif /* HAVE_SHADOW_H */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Authentication failed for "
+ "user \"%s\"!",
+ username);
+ return;
+ }
+ }
+#endif /* HAVE_LIBPAM */
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as %s using Basic",
+ username);
+ break;
+
+ case CUPSD_AUTH_BASICDIGEST :
+ /*
+ * Do Basic authentication with the Digest password file...
+ */
+
+ if (!get_md5_password(username, NULL, md5))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Unknown MD5 username \"%s\"!",
+ username);
+ return;
+ }
+
+ httpMD5(username, "CUPS", password, basicmd5);
+
+ if (strcmp(md5, basicmd5))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Authentication failed for \"%s\"!",
+ username);
+ return;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as %s using BasicDigest",
+ username);
+ break;
+ }
+
+ con->type = type;
+ }
+ else if (!strncmp(authorization, "Digest", 6))
+ {
+ /*
+ * Get the username, password, and nonce from the Digest attributes...
+ */
+
+ if (!httpGetSubField2(&(con->http), HTTP_FIELD_AUTHORIZATION, "username",
+ username, sizeof(username)) || !username[0])
+ {
+ /*
+ * Username must not be empty...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Empty or missing Digest username!");
+ return;
+ }
+
+ if (!httpGetSubField2(&(con->http), HTTP_FIELD_AUTHORIZATION, "response",
+ password, sizeof(password)) || !password[0])
+ {
+ /*
+ * Password must not be empty...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Empty or missing Digest password!");
+ return;
+ }
+
+ if (!httpGetSubField(&(con->http), HTTP_FIELD_AUTHORIZATION, "nonce",
+ nonce))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: No nonce value for Digest "
+ "authentication!");
+ return;
+ }
+
+ if (strcmp(con->http.hostname, nonce))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Bad nonce value, expected \"%s\", "
+ "got \"%s\"!", con->http.hostname, nonce);
+ return;
+ }
+
+ /*
+ * Validate the username and password...
+ */
+
+ if (!get_md5_password(username, NULL, md5))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Unknown MD5 username \"%s\"!",
+ username);
+ return;
+ }
+
+ httpMD5Final(nonce, states[con->http.state], con->uri, md5);
+
+ if (strcmp(md5, password))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdAuthorize: Authentication failed for \"%s\"!",
+ username);
+ return;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as %s using Digest",
+ username);
+
+ con->type = CUPSD_AUTH_DIGEST;
+ }
+#ifdef HAVE_GSSAPI
+ else if (!strncmp(authorization, "Negotiate", 9))
+ {
+ int len; /* Length of authorization string */
+ gss_ctx_id_t context; /* Authorization context */
+ OM_uint32 major_status, /* Major status code */
+ minor_status; /* Minor status code */
+ gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER,
+ /* Input token from string */
+ output_token = GSS_C_EMPTY_BUFFER;
+ /* Output token for username */
+ gss_name_t client_name; /* Client name */
+
+
+# ifdef __APPLE__
+ /*
+ * If the weak-linked GSSAPI/Kerberos library is not present, don't try
+ * to use it...
+ */
+
+ if (gss_init_sec_context == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "GSSAPI/Kerberos authentication failed because the "
+ "Kerberos framework is not present.");
+ return;
+ }
+# endif /* __APPLE__ */
+
+ /*
+ * Find the start of the Kerberos input token...
+ */
+
+ authorization += 9;
+ while (isspace(*authorization & 255))
+ authorization ++;
+
+ if (!*authorization)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdAuthorize: No authentication data specified.");
+ return;
+ }
+
+ /*
+ * Decode the authorization string to get the input token...
+ */
+
+ len = strlen(authorization);
+ input_token.value = malloc(len);
+ input_token.value = httpDecode64_2(input_token.value, &len,
+ authorization);
+ input_token.length = len;
+
+ /*
+ * Accept the input token to get the authorization info...
+ */
+
+ context = GSS_C_NO_CONTEXT;
+ client_name = GSS_C_NO_NAME;
+ major_status = gss_accept_sec_context(&minor_status,
+ &context,
+ GSS_C_NO_CREDENTIAL,
+ &input_token,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &client_name,
+ NULL,
+ &output_token,
+ NULL,
+ NULL,
+ NULL);
+
+ if (output_token.length > 0)
+ gss_release_buffer(&minor_status, &output_token);
+
+ if (GSS_ERROR(major_status))
+ {
+ cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status,
+ "cupsdAuthorize: Error accepting GSSAPI security "
+ "context");
+
+ if (context != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
+ return;
+ }
+
+ con->have_gss = 1;
+
+ /*
+ * Get the username associated with the client's credentials...
+ */
+
+ if (major_status == GSS_S_CONTINUE_NEEDED)
+ cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status,
+ "cupsdAuthorize: Credentials not complete");
+ else if (major_status == GSS_S_COMPLETE)
+ {
+ major_status = gss_display_name(&minor_status, client_name,
+ &output_token, NULL);
+
+ if (GSS_ERROR(major_status))
+ {
+ cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status,
+ "cupsdAuthorize: Error getting username");
+ gss_release_name(&minor_status, &client_name);
+ gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
+ return;
+ }
+
+ strlcpy(username, output_token.value, sizeof(username));
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Authorized as %s using Negotiate",
+ username);
+
+ gss_release_name(&minor_status, &client_name);
+ gss_release_buffer(&minor_status, &output_token);
+
+ con->type = CUPSD_AUTH_NEGOTIATE;
+ }
+
+ gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
+
+# if defined(SO_PEERCRED) && defined(AF_LOCAL)
+ /*
+ * Get the client's UID if we are printing locally - that allows a backend
+ * to run as the correct user to get Kerberos credentials of its own.
+ */
+
+ if (_httpAddrFamily(con->http.hostaddr) == AF_LOCAL)
+ {
+ cupsd_ucred_t peercred; /* Peer credentials */
+ socklen_t peersize; /* Size of peer credentials */
+
+ peersize = sizeof(peercred);
+
+# ifdef __APPLE__
+ if (getsockopt(con->http.fd, 0, LOCAL_PEERCRED, &peercred, &peersize))
+# else
+ if (getsockopt(con->http.fd, SOL_SOCKET, SO_PEERCRED, &peercred,
+ &peersize))
+# endif /* __APPLE__ */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get peer credentials - %s",
+ strerror(errno));
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAuthorize: Using credentials for UID %d...",
+ CUPSD_UCRED_UID(peercred));
+ con->gss_uid = CUPSD_UCRED_UID(peercred);
+ }
+ }
+# endif /* SO_PEERCRED && AF_LOCAL */
+ }
+#endif /* HAVE_GSSAPI */
+ else
+ {
+ char scheme[256]; /* Auth scheme... */
+
+
+ if (sscanf(authorization, "%255s", scheme) != 1)
+ strcpy(scheme, "UNKNOWN");
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad authentication data \"%s ...\"",
+ scheme);
+ return;
+ }
+
+ /*
+ * If we get here, then we were able to validate the username and
+ * password - copy the validated username and password to the client
+ * data and return...
+ */
+
+ strlcpy(con->username, username, sizeof(con->username));
+ strlcpy(con->password, password, sizeof(con->password));
+}
+
+
+/*
+ * 'cupsdCheckAccess()' - Check whether the given address is allowed to
+ * access a location.
+ */
+
+int /* O - 1 if allowed, 0 otherwise */
+cupsdCheckAccess(
+ unsigned ip[4], /* I - Client address */
+ char *name, /* I - Client hostname */
+ int namelen, /* I - Length of hostname */
+ cupsd_location_t *loc) /* I - Location to check */
+{
+ int allow; /* 1 if allowed, 0 otherwise */
+
+
+ if (!_cups_strcasecmp(name, "localhost"))
+ {
+ /*
+ * Access from localhost (127.0.0.1 or ::1) is always allowed...
+ */
+
+ return (1);
+ }
+ else
+ {
+ /*
+ * Do authorization checks on the domain/address...
+ */
+
+ switch (loc->order_type)
+ {
+ default :
+ allow = 0; /* anti-compiler-warning-code */
+ break;
+
+ case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
+ allow = 1;
+
+ if (cupsdCheckAuth(ip, name, namelen, loc->deny))
+ allow = 0;
+
+ if (cupsdCheckAuth(ip, name, namelen, loc->allow))
+ allow = 1;
+ break;
+
+ case CUPSD_AUTH_DENY : /* Order Allow,Deny */
+ allow = 0;
+
+ if (cupsdCheckAuth(ip, name, namelen, loc->allow))
+ allow = 1;
+
+ if (cupsdCheckAuth(ip, name, namelen, loc->deny))
+ allow = 0;
+ break;
+ }
+ }
+
+ return (allow);
+}
+
+
+/*
+ * 'cupsdCheckAuth()' - Check authorization masks.
+ */
+
+int /* O - 1 if mask matches, 0 otherwise */
+cupsdCheckAuth(unsigned ip[4], /* I - Client address */
+ char *name, /* I - Client hostname */
+ int name_len, /* I - Length of hostname */
+ cups_array_t *masks) /* I - Masks */
+{
+ int i; /* Looping var */
+ cupsd_authmask_t *mask; /* Current mask */
+ cupsd_netif_t *iface; /* Network interface */
+ unsigned netip4; /* IPv4 network address */
+#ifdef AF_INET6
+ unsigned netip6[4]; /* IPv6 network address */
+#endif /* AF_INET6 */
+
+
+ for (mask = (cupsd_authmask_t *)cupsArrayFirst(masks);
+ mask;
+ mask = (cupsd_authmask_t *)cupsArrayNext(masks))
+ {
+ switch (mask->type)
+ {
+ case CUPSD_AUTH_INTERFACE :
+ /*
+ * Check for a match with a network interface...
+ */
+
+ netip4 = htonl(ip[3]);
+
+#ifdef AF_INET6
+ netip6[0] = htonl(ip[0]);
+ netip6[1] = htonl(ip[1]);
+ netip6[2] = htonl(ip[2]);
+ netip6[3] = htonl(ip[3]);
+#endif /* AF_INET6 */
+
+ if (!strcmp(mask->mask.name.name, "*"))
+ {
+#ifdef __APPLE__
+ /*
+ * Allow Back-to-My-Mac addresses...
+ */
+
+ if ((ip[0] & 0xff000000) == 0xfd000000)
+ return (1);
+#endif /* __APPLE__ */
+
+ /*
+ * Check against all local interfaces...
+ */
+
+ cupsdNetIFUpdate();
+
+ for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
+ iface;
+ iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
+ {
+ /*
+ * Only check local interfaces...
+ */
+
+ if (!iface->is_local)
+ continue;
+
+ if (iface->address.addr.sa_family == AF_INET)
+ {
+ /*
+ * Check IPv4 address...
+ */
+
+ if ((netip4 & iface->mask.ipv4.sin_addr.s_addr) ==
+ (iface->address.ipv4.sin_addr.s_addr &
+ iface->mask.ipv4.sin_addr.s_addr))
+ return (1);
+ }
+#ifdef AF_INET6
+ else
+ {
+ /*
+ * Check IPv6 address...
+ */
+
+ for (i = 0; i < 4; i ++)
+ if ((netip6[i] & iface->mask.ipv6.sin6_addr.s6_addr32[i]) !=
+ (iface->address.ipv6.sin6_addr.s6_addr32[i] &
+ iface->mask.ipv6.sin6_addr.s6_addr32[i]))
+ break;
+
+ if (i == 4)
+ return (1);
+ }
+#endif /* AF_INET6 */
+ }
+ }
+ else
+ {
+ /*
+ * Check the named interface...
+ */
+
+ for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
+ iface;
+ iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
+ {
+ if (strcmp(mask->mask.name.name, iface->name))
+ continue;
+
+ if (iface->address.addr.sa_family == AF_INET)
+ {
+ /*
+ * Check IPv4 address...
+ */
+
+ if ((netip4 & iface->mask.ipv4.sin_addr.s_addr) ==
+ (iface->address.ipv4.sin_addr.s_addr &
+ iface->mask.ipv4.sin_addr.s_addr))
+ return (1);
+ }
+#ifdef AF_INET6
+ else
+ {
+ /*
+ * Check IPv6 address...
+ */
+
+ for (i = 0; i < 4; i ++)
+ if ((netip6[i] & iface->mask.ipv6.sin6_addr.s6_addr32[i]) !=
+ (iface->address.ipv6.sin6_addr.s6_addr32[i] &
+ iface->mask.ipv6.sin6_addr.s6_addr32[i]))
+ break;
+
+ if (i == 4)
+ return (1);
+ }
+#endif /* AF_INET6 */
+ }
+ }
+ break;
+
+ case CUPSD_AUTH_NAME :
+ /*
+ * Check for exact name match...
+ */
+
+ if (!_cups_strcasecmp(name, mask->mask.name.name))
+ return (1);
+
+ /*
+ * Check for domain match...
+ */
+
+ if (name_len >= mask->mask.name.length &&
+ mask->mask.name.name[0] == '.' &&
+ !_cups_strcasecmp(name + name_len - mask->mask.name.length,
+ mask->mask.name.name))
+ return (1);
+ break;
+
+ case CUPSD_AUTH_IP :
+ /*
+ * Check for IP/network address match...
+ */
+
+ for (i = 0; i < 4; i ++)
+ if ((ip[i] & mask->mask.ip.netmask[i]) !=
+ mask->mask.ip.address[i])
+ break;
+
+ if (i == 4)
+ return (1);
+ break;
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'cupsdCheckGroup()' - Check for a user's group membership.
+ */
+
+int /* O - 1 if user is a member, 0 otherwise */
+cupsdCheckGroup(
+ const char *username, /* I - User name */
+ struct passwd *user, /* I - System user info */
+ const char *groupname) /* I - Group name */
+{
+ int i; /* Looping var */
+ struct group *group; /* System group info */
+ char junk[33]; /* MD5 password (not used) */
+#ifdef HAVE_MBR_UID_TO_UUID
+ uuid_t useruuid, /* UUID for username */
+ groupuuid; /* UUID for groupname */
+ int is_member; /* True if user is a member of group */
+#endif /* HAVE_MBR_UID_TO_UUID */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")",
+ username, user, groupname);
+
+ /*
+ * Validate input...
+ */
+
+ if (!username || !groupname)
+ return (0);
+
+ /*
+ * Check to see if the user is a member of the named group...
+ */
+
+ group = getgrnam(groupname);
+ endgrent();
+
+ if (group != NULL)
+ {
+ /*
+ * Group exists, check it...
+ */
+
+ for (i = 0; group->gr_mem[i]; i ++)
+ if (!_cups_strcasecmp(username, group->gr_mem[i]))
+ return (1);
+ }
+
+ /*
+ * Group doesn't exist or user not in group list, check the group ID
+ * against the user's group ID...
+ */
+
+ if (user && group && group->gr_gid == user->pw_gid)
+ return (1);
+
+#ifdef HAVE_MBR_UID_TO_UUID
+ /*
+ * Check group membership through MacOS X membership API...
+ */
+
+ if (user && !mbr_uid_to_uuid(user->pw_uid, useruuid))
+ {
+ if (group)
+ {
+ /*
+ * Map group name to UUID and check membership...
+ */
+
+ if (!mbr_gid_to_uuid(group->gr_gid, groupuuid))
+ if (!mbr_check_membership(useruuid, groupuuid, &is_member))
+ if (is_member)
+ return (1);
+ }
+ else if (groupname[0] == '#')
+ {
+ /*
+ * Use UUID directly and check for equality (user UUID) and
+ * membership (group UUID)...
+ */
+
+ if (!uuid_parse((char *)groupname + 1, groupuuid))
+ {
+ if (!uuid_compare(useruuid, groupuuid))
+ return (1);
+ else if (!mbr_check_membership(useruuid, groupuuid, &is_member))
+ if (is_member)
+ return (1);
+ }
+
+ return (0);
+ }
+ }
+ else if (groupname[0] == '#')
+ return (0);
+#endif /* HAVE_MBR_UID_TO_UUID */
+
+ /*
+ * Username not found, group not found, or user is not part of the
+ * system group... Check for a user and group in the MD5 password
+ * file...
+ */
+
+ if (get_md5_password(username, groupname, junk) != NULL)
+ return (1);
+
+ /*
+ * If we get this far, then the user isn't part of the named group...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'cupsdCopyLocation()' - Make a copy of a location...
+ */
+
+cupsd_location_t * /* O - New location */
+cupsdCopyLocation(
+ cupsd_location_t *loc) /* I - Original location */
+{
+ cupsd_location_t *temp; /* New location */
+
+
+ /*
+ * Make a copy of the original location...
+ */
+
+ if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
+ return (NULL);
+
+ /*
+ * Copy the information from the original location to the new one.
+ */
+
+ if (!loc)
+ return (temp);
+
+ if (loc->location)
+ temp->location = _cupsStrAlloc(loc->location);
+
+ temp->limit = loc->limit;
+ temp->order_type = loc->order_type;
+ temp->type = loc->type;
+ temp->level = loc->level;
+ temp->satisfy = loc->satisfy;
+ temp->encryption = loc->encryption;
+
+ if (loc->names)
+ {
+ if ((temp->names = cupsArrayDup(loc->names)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for %d names: %s",
+ cupsArrayCount(loc->names), strerror(errno));
+
+ cupsdFreeLocation(temp);
+ return (NULL);
+ }
+ }
+
+ if (loc->allow)
+ {
+ /*
+ * Copy allow rules...
+ */
+
+ if ((temp->allow = cupsArrayDup(loc->allow)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for %d allow rules: %s",
+ cupsArrayCount(loc->allow), strerror(errno));
+ cupsdFreeLocation(temp);
+ return (NULL);
+ }
+ }
+
+ if (loc->deny)
+ {
+ /*
+ * Copy deny rules...
+ */
+
+ if ((temp->deny = cupsArrayDup(loc->deny)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for %d deny rules: %s",
+ cupsArrayCount(loc->deny), strerror(errno));
+ cupsdFreeLocation(temp);
+ return (NULL);
+ }
+ }
+
+ return (temp);
+}
+
+
+/*
+ * 'cupsdDeleteAllLocations()' - Free all memory used for location authorization.
+ */
+
+void
+cupsdDeleteAllLocations(void)
+{
+ /*
+ * Free the location array, which will free all of the locations...
+ */
+
+ cupsArrayDelete(Locations);
+ Locations = NULL;
+}
+
+
+/*
+ * 'cupsdFindBest()' - Find the location entry that best matches the resource.
+ */
+
+cupsd_location_t * /* O - Location that matches */
+cupsdFindBest(const char *path, /* I - Resource path */
+ http_state_t state) /* I - HTTP state/request */
+{
+ char uri[HTTP_MAX_URI],
+ /* URI in request... */
+ *uriptr; /* Pointer into URI */
+ cupsd_location_t *loc, /* Current location */
+ *best; /* Best match for location so far */
+ int bestlen; /* Length of best match */
+ int limit; /* Limit field */
+ static const int limits[] = /* Map http_status_t to CUPSD_AUTH_LIMIT_xyz */
+ {
+ CUPSD_AUTH_LIMIT_ALL,
+ CUPSD_AUTH_LIMIT_OPTIONS,
+ CUPSD_AUTH_LIMIT_GET,
+ CUPSD_AUTH_LIMIT_GET,
+ CUPSD_AUTH_LIMIT_HEAD,
+ CUPSD_AUTH_LIMIT_POST,
+ CUPSD_AUTH_LIMIT_POST,
+ CUPSD_AUTH_LIMIT_POST,
+ CUPSD_AUTH_LIMIT_PUT,
+ CUPSD_AUTH_LIMIT_PUT,
+ CUPSD_AUTH_LIMIT_DELETE,
+ CUPSD_AUTH_LIMIT_TRACE,
+ CUPSD_AUTH_LIMIT_ALL,
+ CUPSD_AUTH_LIMIT_ALL
+ };
+
+
+ /*
+ * First copy the connection URI to a local string so we have drop
+ * any .ppd extension from the pathname in /printers or /classes
+ * URIs...
+ */
+
+ strlcpy(uri, path, sizeof(uri));
+
+ if (!strncmp(uri, "/printers/", 10) ||
+ !strncmp(uri, "/classes/", 9))
+ {
+ /*
+ * Check if the URI has .ppd on the end...
+ */
+
+ uriptr = uri + strlen(uri) - 4; /* len > 4 if we get here... */
+
+ if (!strcmp(uriptr, ".ppd"))
+ *uriptr = '\0';
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: uri = \"%s\"...", uri);
+
+ /*
+ * Loop through the list of locations to find a match...
+ */
+
+ limit = limits[state];
+ best = NULL;
+ bestlen = 0;
+
+ for (loc = (cupsd_location_t *)cupsArrayFirst(Locations);
+ loc;
+ loc = (cupsd_location_t *)cupsArrayNext(Locations))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: Location %s Limit %x",
+ loc->location ? loc->location : "nil", loc->limit);
+
+ if (!strncmp(uri, "/printers/", 10) || !strncmp(uri, "/classes/", 9))
+ {
+ /*
+ * Use case-insensitive comparison for queue names...
+ */
+
+ if (loc->length > bestlen && loc->location &&
+ !_cups_strncasecmp(uri, loc->location, loc->length) &&
+ loc->location[0] == '/' &&
+ (limit & loc->limit) != 0)
+ {
+ best = loc;
+ bestlen = loc->length;
+ }
+ }
+ else
+ {
+ /*
+ * Use case-sensitive comparison for other URIs...
+ */
+
+ if (loc->length > bestlen && loc->location &&
+ !strncmp(uri, loc->location, loc->length) &&
+ loc->location[0] == '/' &&
+ (limit & loc->limit) != 0)
+ {
+ best = loc;
+ bestlen = loc->length;
+ }
+ }
+ }
+
+ /*
+ * Return the match, if any...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: best = %s",
+ best ? best->location : "NONE");
+
+ return (best);
+}
+
+
+/*
+ * 'cupsdFindLocation()' - Find the named location.
+ */
+
+cupsd_location_t * /* O - Location that matches */
+cupsdFindLocation(const char *location) /* I - Connection */
+{
+ cupsd_location_t key; /* Search key */
+
+
+ key.location = (char *)location;
+
+ return ((cupsd_location_t *)cupsArrayFind(Locations, &key));
+}
+
+
+/*
+ * 'cupsdFreeLocation()' - Free all memory used by a location.
+ */
+
+void
+cupsdFreeLocation(cupsd_location_t *loc)/* I - Location to free */
+{
+ cupsArrayDelete(loc->names);
+ cupsArrayDelete(loc->allow);
+ cupsArrayDelete(loc->deny);
+
+ _cupsStrFree(loc->location);
+ free(loc);
+}
+
+
+/*
+ * 'cupsdIsAuthorized()' - Check to see if the user is authorized...
+ */
+
+http_status_t /* O - HTTP_OK if authorized or error code */
+cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */
+ const char *owner)/* I - Owner of object */
+{
+ int i, /* Looping vars */
+ auth, /* Authorization status */
+ type; /* Type of authentication */
+ unsigned address[4]; /* Authorization address */
+ cupsd_location_t *best; /* Best match for location so far */
+ int hostlen; /* Length of hostname */
+ char *name, /* Current username */
+ username[256], /* Username to authorize */
+ ownername[256], /* Owner name to authorize */
+ *ptr; /* Pointer into username */
+ struct passwd *pw; /* User password data */
+ static const char * const levels[] = /* Auth levels */
+ {
+ "ANON",
+ "USER",
+ "GROUP"
+ };
+ static const char * const types[] = /* Auth types */
+ {
+ "None",
+ "Basic",
+ "Digest",
+ "BasicDigest",
+ "Negotiate"
+ };
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdIsAuthorized: con->uri=\"%s\", con->best=%p(%s)",
+ con->uri, con->best, con->best ? con->best->location ?
+ con->best->location : "(null)" : "");
+ if (owner)
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdIsAuthorized: owner=\"%s\"", owner);
+
+ /*
+ * If there is no "best" authentication rule for this request, then
+ * access is allowed from the local system and denied from other
+ * addresses...
+ */
+
+ if (!con->best)
+ {
+ if (!strcmp(con->http.hostname, "localhost") ||
+ !strcmp(con->http.hostname, ServerName))
+ return (HTTP_OK);
+ else
+ return (HTTP_FORBIDDEN);
+ }
+
+ best = con->best;
+
+ if ((type = best->type) == CUPSD_AUTH_DEFAULT)
+ type = DefaultAuthType;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdIsAuthorized: level=CUPSD_AUTH_%s, type=%s, "
+ "satisfy=CUPSD_AUTH_SATISFY_%s, num_names=%d",
+ levels[best->level], types[type],
+ best->satisfy ? "ANY" : "ALL", cupsArrayCount(best->names));
+
+ if (best->limit == CUPSD_AUTH_LIMIT_IPP)
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: op=%x(%s)",
+ best->op, ippOpString(best->op));
+
+ /*
+ * Check host/ip-based accesses...
+ */
+
+#ifdef AF_INET6
+ if (con->http.hostaddr->addr.sa_family == AF_INET6)
+ {
+ /*
+ * Copy IPv6 address...
+ */
+
+ address[0] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[0]);
+ address[1] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[1]);
+ address[2] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2]);
+ address[3] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[3]);
+ }
+ else
+#endif /* AF_INET6 */
+ if (con->http.hostaddr->addr.sa_family == AF_INET)
+ {
+ /*
+ * Copy IPv4 address...
+ */
+
+ address[0] = 0;
+ address[1] = 0;
+ address[2] = 0;
+ address[3] = ntohl(con->http.hostaddr->ipv4.sin_addr.s_addr);
+ }
+ else
+ memset(address, 0, sizeof(address));
+
+ hostlen = strlen(con->http.hostname);
+
+ auth = cupsdCheckAccess(address, con->http.hostname, hostlen, best)
+ ? CUPSD_AUTH_ALLOW : CUPSD_AUTH_DENY;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: auth=CUPSD_AUTH_%s...",
+ auth ? "DENY" : "ALLOW");
+
+ if (auth == CUPSD_AUTH_DENY && best->satisfy == CUPSD_AUTH_SATISFY_ALL)
+ return (HTTP_FORBIDDEN);
+
+#ifdef HAVE_SSL
+ /*
+ * See if encryption is required...
+ */
+
+ if ((best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls &&
+ _cups_strcasecmp(con->http.hostname, "localhost") &&
+ best->satisfy == CUPSD_AUTH_SATISFY_ALL) &&
+ !(type == CUPSD_AUTH_NEGOTIATE ||
+ (type == CUPSD_AUTH_NONE && DefaultAuthType == CUPSD_AUTH_NEGOTIATE)))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdIsAuthorized: Need upgrade to TLS...");
+ return (HTTP_UPGRADE_REQUIRED);
+ }
+#endif /* HAVE_SSL */
+
+ /*
+ * Now see what access level is required...
+ */
+
+ if (best->level == CUPSD_AUTH_ANON || /* Anonymous access - allow it */
+ (type == CUPSD_AUTH_NONE && cupsArrayCount(best->names) == 0))
+ return (HTTP_OK);
+
+ if (!con->username[0] && type == CUPSD_AUTH_NONE &&
+ best->limit == CUPSD_AUTH_LIMIT_IPP)
+ {
+ /*
+ * Check for unauthenticated username...
+ */
+
+ ipp_attribute_t *attr; /* requesting-user-name attribute */
+
+
+ attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
+ if (attr)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdIsAuthorized: requesting-user-name=\"%s\"",
+ attr->values[0].string.text);
+ strlcpy(username, attr->values[0].string.text, sizeof(username));
+ }
+ else if (best->satisfy == CUPSD_AUTH_SATISFY_ALL || auth == CUPSD_AUTH_DENY)
+ return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
+ else
+ return (HTTP_OK); /* unless overridden with Satisfy */
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdIsAuthorized: username=\"%s\"",
+ con->username);
+
+#ifdef HAVE_AUTHORIZATION_H
+ if (!con->username[0] && !con->authref)
+#else
+ if (!con->username[0])
+#endif /* HAVE_AUTHORIZATION_H */
+ {
+ if (best->satisfy == CUPSD_AUTH_SATISFY_ALL || auth == CUPSD_AUTH_DENY)
+ return (HTTP_UNAUTHORIZED); /* Non-anonymous needs user/pass */
+ else
+ return (HTTP_OK); /* unless overridden with Satisfy */
+ }
+
+
+ if (con->type != type && type != CUPSD_AUTH_NONE &&
+#ifdef HAVE_GSSAPI
+ (type != CUPSD_AUTH_NEGOTIATE || con->gss_uid <= 0) &&
+#endif /* HAVE_GSSAPI */
+ (con->type != CUPSD_AUTH_BASIC || type != CUPSD_AUTH_BASICDIGEST))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Authorized using %s, expected %s!",
+ types[con->type], types[type]);
+
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ strlcpy(username, con->username, sizeof(username));
+ }
+
+ /*
+ * OK, got a username. See if we need normal user access, or group
+ * access... (root always matches)
+ */
+
+ if (!strcmp(username, "root"))
+ return (HTTP_OK);
+
+ /*
+ * Strip any @domain or @KDC from the username and owner...
+ */
+
+ if ((ptr = strchr(username, '@')) != NULL)
+ *ptr = '\0';
+
+ if (owner)
+ {
+ strlcpy(ownername, owner, sizeof(ownername));
+
+ if ((ptr = strchr(ownername, '@')) != NULL)
+ *ptr = '\0';
+ }
+ else
+ ownername[0] = '\0';
+
+ /*
+ * Get the user info...
+ */
+
+ if (username[0])
+ {
+ pw = getpwnam(username);
+ endpwent();
+ }
+ else
+ pw = NULL;
+
+ if (best->level == CUPSD_AUTH_USER)
+ {
+ /*
+ * If there are no names associated with this location, then
+ * any valid user is OK...
+ */
+
+ if (cupsArrayCount(best->names) == 0)
+ return (HTTP_OK);
+
+ /*
+ * Otherwise check the user list and return OK if this user is
+ * allowed...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdIsAuthorized: Checking user membership...");
+
+#ifdef HAVE_AUTHORIZATION_H
+ /*
+ * If an authorization reference was supplied it must match a right name...
+ */
+
+ if (con->authref)
+ {
+ for (name = (char *)cupsArrayFirst(best->names);
+ name;
+ name = (char *)cupsArrayNext(best->names))
+ {
+ if (!_cups_strncasecmp(name, "@AUTHKEY(", 9) && check_authref(con, name + 9))
+ return (HTTP_OK);
+ else if (!_cups_strcasecmp(name, "@SYSTEM") && SystemGroupAuthKey &&
+ check_authref(con, SystemGroupAuthKey))
+ return (HTTP_OK);
+ }
+
+ return (HTTP_FORBIDDEN);
+ }
+#endif /* HAVE_AUTHORIZATION_H */
+
+ for (name = (char *)cupsArrayFirst(best->names);
+ name;
+ name = (char *)cupsArrayNext(best->names))
+ {
+ if (!_cups_strcasecmp(name, "@OWNER") && owner &&
+ !_cups_strcasecmp(username, ownername))
+ return (HTTP_OK);
+ else if (!_cups_strcasecmp(name, "@SYSTEM"))
+ {
+ for (i = 0; i < NumSystemGroups; i ++)
+ if (cupsdCheckGroup(username, pw, SystemGroups[i]))
+ return (HTTP_OK);
+ }
+ else if (name[0] == '@')
+ {
+ if (cupsdCheckGroup(username, pw, name + 1))
+ return (HTTP_OK);
+ }
+ else if (!_cups_strcasecmp(username, name))
+ return (HTTP_OK);
+ }
+
+ return (HTTP_FORBIDDEN);
+ }
+
+ /*
+ * Check to see if this user is in any of the named groups...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdIsAuthorized: Checking group membership...");
+
+ /*
+ * Check to see if this user is in any of the named groups...
+ */
+
+ for (name = (char *)cupsArrayFirst(best->names);
+ name;
+ name = (char *)cupsArrayNext(best->names))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdIsAuthorized: Checking group \"%s\" membership...",
+ name);
+
+ if (!_cups_strcasecmp(name, "@SYSTEM"))
+ {
+ for (i = 0; i < NumSystemGroups; i ++)
+ if (cupsdCheckGroup(username, pw, SystemGroups[i]))
+ return (HTTP_OK);
+ }
+ else if (cupsdCheckGroup(username, pw, name))
+ return (HTTP_OK);
+ }
+
+ /*
+ * The user isn't part of the specified group, so deny access...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdIsAuthorized: User not in group(s)!");
+
+ return (HTTP_FORBIDDEN);
+}
+
+
+/*
+ * 'cupsdNewLocation()' - Create a new location for authorization.
+ *
+ * Note: Still need to call cupsdAddLocation() to add it to the list of global
+ * locations.
+ */
+
+cupsd_location_t * /* O - Pointer to new location record */
+cupsdNewLocation(const char *location) /* I - Location path */
+{
+ cupsd_location_t *temp; /* New location */
+
+
+ /*
+ * Try to allocate memory for the new location.
+ */
+
+ if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
+ return (NULL);
+
+ /*
+ * Initialize the record and copy the name over...
+ */
+
+ if ((temp->location = _cupsStrAlloc(location)) == NULL)
+ {
+ free(temp);
+ return (NULL);
+ }
+
+ temp->length = strlen(temp->location);
+
+ /*
+ * Return the new record...
+ */
+
+ return (temp);
+}
+
+
+#ifdef HAVE_AUTHORIZATION_H
+/*
+ * 'check_authref()' - Check if an authorization services reference has the
+ * supplied right.
+ */
+
+static int /* O - 1 if right is valid, 0 otherwise */
+check_authref(cupsd_client_t *con, /* I - Connection */
+ const char *right) /* I - Right name */
+{
+ OSStatus status; /* OS Status */
+ AuthorizationItem authright; /* Authorization right */
+ AuthorizationRights authrights; /* Authorization rights */
+ AuthorizationFlags authflags; /* Authorization flags */
+
+
+ /*
+ * Check to see if the user is allowed to perform the task...
+ */
+
+ if (!con->authref)
+ return (0);
+
+ authright.name = right;
+ authright.valueLength = 0;
+ authright.value = NULL;
+ authright.flags = 0;
+
+ authrights.count = 1;
+ authrights.items = &authright;
+
+ authflags = kAuthorizationFlagDefaults |
+ kAuthorizationFlagExtendRights;
+
+ if ((status = AuthorizationCopyRights(con->authref, &authrights,
+ kAuthorizationEmptyEnvironment,
+ authflags, NULL)) != 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "AuthorizationCopyRights(\"%s\") returned %d (%s)",
+ authright.name, (int)status, cssmErrorString(status));
+ return (0);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "AuthorizationCopyRights(\"%s\") succeeded!",
+ authright.name);
+
+ return (1);
+}
+#endif /* HAVE_AUTHORIZATION_H */
+
+
+/*
+ * 'compare_locations()' - Compare two locations.
+ */
+
+static int /* O - Result of comparison */
+compare_locations(cupsd_location_t *a, /* I - First location */
+ cupsd_location_t *b) /* I - Second location */
+{
+ return (strcmp(b->location, a->location));
+}
+
+
+/*
+ * 'copy_authmask()' - Copy function for auth masks.
+ */
+
+static cupsd_authmask_t * /* O - New auth mask */
+copy_authmask(cupsd_authmask_t *mask, /* I - Existing auth mask */
+ void *data) /* I - User data (unused) */
+{
+ cupsd_authmask_t *temp; /* New auth mask */
+
+
+ (void)data;
+
+ if ((temp = malloc(sizeof(cupsd_authmask_t))) != NULL)
+ {
+ memcpy(temp, mask, sizeof(cupsd_authmask_t));
+
+ if (temp->type == CUPSD_AUTH_NAME || temp->type == CUPSD_AUTH_INTERFACE)
+ {
+ /*
+ * Make a copy of the name...
+ */
+
+ if ((temp->mask.name.name = _cupsStrAlloc(temp->mask.name.name)) == NULL)
+ {
+ /*
+ * Failed to make copy...
+ */
+
+ free(temp);
+ temp = NULL;
+ }
+ }
+ }
+
+ return (temp);
+}
+
+
+#if !HAVE_LIBPAM && !defined(HAVE_USERSEC_H)
+/*
+ * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms,
+ * as needed.
+ */
+
+static char * /* O - Encrypted password */
+cups_crypt(const char *pw, /* I - Password string */
+ const char *salt) /* I - Salt (key) string */
+{
+ if (!strncmp(salt, "$1$", 3))
+ {
+ /*
+ * Use MD5 passwords without the benefit of PAM; this is for
+ * Slackware Linux, and the algorithm was taken from the
+ * old shadow-19990827/lib/md5crypt.c source code... :(
+ */
+
+ int i; /* Looping var */
+ unsigned long n; /* Output number */
+ int pwlen; /* Length of password string */
+ const char *salt_end; /* End of "salt" data for MD5 */
+ char *ptr; /* Pointer into result string */
+ _cups_md5_state_t state; /* Primary MD5 state info */
+ _cups_md5_state_t state2; /* Secondary MD5 state info */
+ unsigned char digest[16]; /* MD5 digest result */
+ static char result[120]; /* Final password string */
+
+
+ /*
+ * Get the salt data between dollar signs, e.g. $1$saltdata$md5.
+ * Get a maximum of 8 characters of salt data after $1$...
+ */
+
+ for (salt_end = salt + 3; *salt_end && (salt_end - salt) < 11; salt_end ++)
+ if (*salt_end == '$')
+ break;
+
+ /*
+ * Compute the MD5 sum we need...
+ */
+
+ pwlen = strlen(pw);
+
+ _cupsMD5Init(&state);
+ _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
+ _cupsMD5Append(&state, (unsigned char *)salt, salt_end - salt);
+
+ _cupsMD5Init(&state2);
+ _cupsMD5Append(&state2, (unsigned char *)pw, pwlen);
+ _cupsMD5Append(&state2, (unsigned char *)salt + 3, salt_end - salt - 3);
+ _cupsMD5Append(&state2, (unsigned char *)pw, pwlen);
+ _cupsMD5Finish(&state2, digest);
+
+ for (i = pwlen; i > 0; i -= 16)
+ _cupsMD5Append(&state, digest, i > 16 ? 16 : i);
+
+ for (i = pwlen; i > 0; i >>= 1)
+ _cupsMD5Append(&state, (unsigned char *)((i & 1) ? "" : pw), 1);
+
+ _cupsMD5Finish(&state, digest);
+
+ for (i = 0; i < 1000; i ++)
+ {
+ _cupsMD5Init(&state);
+
+ if (i & 1)
+ _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
+ else
+ _cupsMD5Append(&state, digest, 16);
+
+ if (i % 3)
+ _cupsMD5Append(&state, (unsigned char *)salt + 3, salt_end - salt - 3);
+
+ if (i % 7)
+ _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
+
+ if (i & 1)
+ _cupsMD5Append(&state, digest, 16);
+ else
+ _cupsMD5Append(&state, (unsigned char *)pw, pwlen);
+
+ _cupsMD5Finish(&state, digest);
+ }
+
+ /*
+ * Copy the final sum to the result string and return...
+ */
+
+ memcpy(result, salt, salt_end - salt);
+ ptr = result + (salt_end - salt);
+ *ptr++ = '$';
+
+ for (i = 0; i < 5; i ++, ptr += 4)
+ {
+ n = (((digest[i] << 8) | digest[i + 6]) << 8);
+
+ if (i < 4)
+ n |= digest[i + 12];
+ else
+ n |= digest[5];
+
+ to64(ptr, n, 4);
+ }
+
+ to64(ptr, digest[11], 2);
+ ptr += 2;
+ *ptr = '\0';
+
+ return (result);
+ }
+ else
+ {
+ /*
+ * Use the standard crypt() function...
+ */
+
+ return (crypt(pw, salt));
+ }
+}
+#endif /* !HAVE_LIBPAM && !HAVE_USERSEC_H */
+
+
+/*
+ * 'free_authmask()' - Free function for auth masks.
+ */
+
+static void
+free_authmask(cupsd_authmask_t *mask, /* I - Auth mask to free */
+ void *data) /* I - User data (unused) */
+{
+ (void)data;
+
+ if (mask->type == CUPSD_AUTH_NAME || mask->type == CUPSD_AUTH_INTERFACE)
+ _cupsStrFree(mask->mask.name.name);
+
+ free(mask);
+}
+
+
+/*
+ * 'get_md5_password()' - Get an MD5 password.
+ */
+
+static char * /* O - MD5 password string */
+get_md5_password(const char *username, /* I - Username */
+ const char *group, /* I - Group */
+ char passwd[33]) /* O - MD5 password string */
+{
+ cups_file_t *fp; /* passwd.md5 file */
+ char filename[1024], /* passwd.md5 filename */
+ line[256], /* Line from file */
+ tempuser[33], /* User from file */
+ tempgroup[33]; /* Group from file */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "get_md5_password(username=\"%s\", group=\"%s\", passwd=%p)",
+ username, group ? group : "(null)", passwd);
+
+ snprintf(filename, sizeof(filename), "%s/passwd.md5", ServerRoot);
+ if ((fp = cupsFileOpen(filename, "r")) == NULL)
+ {
+ if (errno != ENOENT)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open %s - %s", filename,
+ strerror(errno));
+
+ return (NULL);
+ }
+
+ while (cupsFileGets(fp, line, sizeof(line)) != NULL)
+ {
+ if (sscanf(line, "%32[^:]:%32[^:]:%32s", tempuser, tempgroup, passwd) != 3)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad MD5 password line: %s", line);
+ continue;
+ }
+
+ if (!strcmp(username, tempuser) &&
+ (group == NULL || !strcmp(group, tempgroup)))
+ {
+ /*
+ * Found the password entry!
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "Found MD5 user %s, group %s...",
+ username, tempgroup);
+
+ cupsFileClose(fp);
+ return (passwd);
+ }
+ }
+
+ /*
+ * Didn't find a password entry - return NULL!
+ */
+
+ cupsFileClose(fp);
+ return (NULL);
+}
+
+
+#if HAVE_LIBPAM
+/*
+ * 'pam_func()' - PAM conversation function.
+ */
+
+static int /* O - Success or failure */
+pam_func(
+ int num_msg, /* I - Number of messages */
+ const struct pam_message **msg, /* I - Messages */
+ struct pam_response **resp, /* O - Responses */
+ void *appdata_ptr)
+ /* I - Pointer to connection */
+{
+ int i; /* Looping var */
+ struct pam_response *replies; /* Replies */
+ cupsd_authdata_t *data; /* Pointer to auth data */
+
+
+ /*
+ * Allocate memory for the responses...
+ */
+
+ if ((replies = malloc(sizeof(struct pam_response) * num_msg)) == NULL)
+ return (PAM_CONV_ERR);
+
+ /*
+ * Answer all of the messages...
+ */
+
+ DEBUG_printf(("pam_func: appdata_ptr = %p\n", appdata_ptr));
+
+#ifdef __hpux
+ /*
+ * Apparently some versions of HP-UX 11 have a broken pam_unix security
+ * module. This is a workaround...
+ */
+
+ data = auth_data;
+ (void)appdata_ptr;
+#else
+ data = (cupsd_authdata_t *)appdata_ptr;
+#endif /* __hpux */
+
+ for (i = 0; i < num_msg; i ++)
+ {
+ DEBUG_printf(("pam_func: Message = \"%s\"\n", msg[i]->msg));
+
+ switch (msg[i]->msg_style)
+ {
+ case PAM_PROMPT_ECHO_ON:
+ DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_ON, returning \"%s\"...\n",
+ data->username));
+ replies[i].resp_retcode = PAM_SUCCESS;
+ replies[i].resp = strdup(data->username);
+ break;
+
+ case PAM_PROMPT_ECHO_OFF:
+ DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n",
+ data->password));
+ replies[i].resp_retcode = PAM_SUCCESS;
+ replies[i].resp = strdup(data->password);
+ break;
+
+ case PAM_TEXT_INFO:
+ DEBUG_puts("pam_func: PAM_TEXT_INFO...");
+ replies[i].resp_retcode = PAM_SUCCESS;
+ replies[i].resp = NULL;
+ break;
+
+ case PAM_ERROR_MSG:
+ DEBUG_puts("pam_func: PAM_ERROR_MSG...");
+ replies[i].resp_retcode = PAM_SUCCESS;
+ replies[i].resp = NULL;
+ break;
+
+ default:
+ DEBUG_printf(("pam_func: Unknown PAM message %d...\n",
+ msg[i]->msg_style));
+ free(replies);
+ return (PAM_CONV_ERR);
+ }
+ }
+
+ /*
+ * Return the responses back to PAM...
+ */
+
+ *resp = replies;
+
+ return (PAM_SUCCESS);
+}
+#elif !defined(HAVE_USERSEC_H)
+
+
+/*
+ * 'to64()' - Base64-encode an integer value...
+ */
+
+static void
+to64(char *s, /* O - Output string */
+ unsigned long v, /* I - Value to encode */
+ int n) /* I - Number of digits */
+{
+ const char *itoa64 = "./0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+
+
+ for (; n > 0; n --, v >>= 6)
+ *s++ = itoa64[v & 0x3f];
+}
+#endif /* HAVE_LIBPAM */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/auth.h b/scheduler/auth.h
new file mode 100644
index 000000000..8af0d0bd4
--- /dev/null
+++ b/scheduler/auth.h
@@ -0,0 +1,152 @@
+/*
+ * "$Id$"
+ *
+ * Authorization definitions for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <pwd.h>
+
+
+/*
+ * HTTP authorization types and levels...
+ */
+
+#define CUPSD_AUTH_DEFAULT -1 /* Use DefaultAuthType */
+#define CUPSD_AUTH_NONE 0 /* No authentication */
+#define CUPSD_AUTH_BASIC 1 /* Basic authentication */
+#define CUPSD_AUTH_DIGEST 2 /* Digest authentication */
+#define CUPSD_AUTH_BASICDIGEST 3 /* Basic authentication w/passwd.md5 */
+#define CUPSD_AUTH_NEGOTIATE 4 /* Kerberos authentication */
+
+#define CUPSD_AUTH_ANON 0 /* Anonymous access */
+#define CUPSD_AUTH_USER 1 /* Must have a valid username/password */
+#define CUPSD_AUTH_GROUP 2 /* Must also be in a named group */
+
+#define CUPSD_AUTH_ALLOW 0 /* Allow access */
+#define CUPSD_AUTH_DENY 1 /* Deny access */
+
+#define CUPSD_AUTH_NAME 0 /* Authorize host by name */
+#define CUPSD_AUTH_IP 1 /* Authorize host by IP */
+#define CUPSD_AUTH_INTERFACE 2 /* Authorize host by interface */
+
+#define CUPSD_AUTH_SATISFY_ALL 0 /* Satisfy both address and auth */
+#define CUPSD_AUTH_SATISFY_ANY 1 /* Satisfy either address or auth */
+
+#define CUPSD_AUTH_LIMIT_DELETE 1 /* Limit DELETE requests */
+#define CUPSD_AUTH_LIMIT_GET 2 /* Limit GET requests */
+#define CUPSD_AUTH_LIMIT_HEAD 4 /* Limit HEAD requests */
+#define CUPSD_AUTH_LIMIT_OPTIONS 8 /* Limit OPTIONS requests */
+#define CUPSD_AUTH_LIMIT_POST 16 /* Limit POST requests */
+#define CUPSD_AUTH_LIMIT_PUT 32 /* Limit PUT requests */
+#define CUPSD_AUTH_LIMIT_TRACE 64 /* Limit TRACE requests */
+#define CUPSD_AUTH_LIMIT_ALL 127 /* Limit all requests */
+#define CUPSD_AUTH_LIMIT_IPP 128 /* Limit IPP requests */
+
+#define IPP_ANY_OPERATION (ipp_op_t)0
+ /* Any IPP operation */
+#define IPP_BAD_OPERATION (ipp_op_t)-1
+ /* No IPP operation */
+
+
+/*
+ * HTTP access control structures...
+ */
+
+typedef struct
+{
+ unsigned address[4], /* IP address */
+ netmask[4]; /* IP netmask */
+} cupsd_ipmask_t;
+
+typedef struct
+{
+ int length; /* Length of name */
+ char *name; /* Name string */
+} cupsd_namemask_t;
+
+typedef struct
+{
+ int type; /* Mask type */
+ union
+ {
+ cupsd_namemask_t name; /* Host/Domain name */
+ cupsd_ipmask_t ip; /* IP address/network */
+ } mask; /* Mask data */
+} cupsd_authmask_t;
+
+typedef struct
+{
+ char *location; /* Location of resource */
+ ipp_op_t op; /* IPP operation */
+ int limit, /* Limit for these types of requests */
+ length, /* Length of location string */
+ order_type, /* Allow or Deny */
+ type, /* Type of authentication */
+ level, /* Access level required */
+ satisfy; /* Satisfy any or all limits? */
+ cups_array_t *names, /* User or group names */
+ *allow, /* Allow lines */
+ *deny; /* Deny lines */
+ http_encryption_t encryption; /* To encrypt or not to encrypt... */
+} cupsd_location_t;
+
+typedef struct cupsd_client_s cupsd_client_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR cups_array_t *Locations VALUE(NULL);
+ /* Authorization locations */
+VAR int DefaultAuthType VALUE(CUPSD_AUTH_BASIC);
+ /* Default AuthType, if not specified */
+#ifdef HAVE_SSL
+VAR http_encryption_t DefaultEncryption VALUE(HTTP_ENCRYPT_REQUIRED);
+ /* Default encryption for authentication */
+#endif /* HAVE_SSL */
+
+
+/*
+ * Prototypes...
+ */
+
+extern int cupsdAddIPMask(cups_array_t **masks,
+ const unsigned address[4],
+ const unsigned netmask[4]);
+extern void cupsdAddLocation(cupsd_location_t *loc);
+extern void cupsdAddName(cupsd_location_t *loc, char *name);
+extern int cupsdAddNameMask(cups_array_t **masks, char *name);
+extern void cupsdAuthorize(cupsd_client_t *con);
+extern int cupsdCheckAccess(unsigned ip[4], char *name,
+ int namelen, cupsd_location_t *loc);
+extern int cupsdCheckAuth(unsigned ip[4], char *name, int namelen,
+ cups_array_t *masks);
+extern int cupsdCheckGroup(const char *username,
+ struct passwd *user,
+ const char *groupname);
+extern cupsd_location_t *cupsdCopyLocation(cupsd_location_t *loc);
+extern void cupsdDeleteAllLocations(void);
+extern cupsd_location_t *cupsdFindBest(const char *path, http_state_t state);
+extern cupsd_location_t *cupsdFindLocation(const char *location);
+extern void cupsdFreeLocation(cupsd_location_t *loc);
+extern http_status_t cupsdIsAuthorized(cupsd_client_t *con, const char *owner);
+extern cupsd_location_t *cupsdNewLocation(const char *location);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/banners.c b/scheduler/banners.c
new file mode 100644
index 000000000..77ae797ae
--- /dev/null
+++ b/scheduler/banners.c
@@ -0,0 +1,224 @@
+/*
+ * "$Id$"
+ *
+ * Banner routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdFindBanner() - Find a named banner.
+ * cupsdLoadBanners() - Load all available banner files...
+ * add_banner() - Add a banner to the array.
+ * compare_banners() - Compare two banners.
+ * free_banners() - Free all banners.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <cups/dir.h>
+
+
+/*
+ * Local functions...
+ */
+
+static void add_banner(const char *name, const char *filename);
+static int compare_banners(const cupsd_banner_t *b0,
+ const cupsd_banner_t *b1);
+static void free_banners(void);
+
+
+/*
+ * 'cupsdFindBanner()' - Find a named banner.
+ */
+
+cupsd_banner_t * /* O - Pointer to banner or NULL */
+cupsdFindBanner(const char *name) /* I - Name of banner */
+{
+ cupsd_banner_t key; /* Search key */
+
+
+ key.name = (char *)name;
+
+ return ((cupsd_banner_t *)cupsArrayFind(Banners, &key));
+}
+
+
+/*
+ * 'cupsdLoadBanners()' - Load all available banner files...
+ */
+
+void
+cupsdLoadBanners(const char *d) /* I - Directory to search */
+{
+ cups_dir_t *dir; /* Directory pointer */
+ cups_dentry_t *dent; /* Directory entry */
+ char filename[1024], /* Name of banner */
+ *ext; /* Pointer to extension */
+
+
+ /*
+ * Free old banner info...
+ */
+
+ free_banners();
+
+ /*
+ * Try opening the banner directory...
+ */
+
+ if ((dir = cupsDirOpen(d)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "cupsdLoadBanners: Unable to open banner directory \"%s\": %s",
+ d, strerror(errno));
+ return;
+ }
+
+ /*
+ * Read entries, skipping directories and backup files.
+ */
+
+ Banners = cupsArrayNew((cups_array_func_t)compare_banners, NULL);
+
+ while ((dent = cupsDirRead(dir)) != NULL)
+ {
+ /*
+ * Check the file to make sure it isn't a directory or a backup
+ * file of some sort...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/%s", d, dent->filename);
+
+ if (S_ISDIR(dent->fileinfo.st_mode))
+ continue;
+
+ if (dent->filename[0] == '~' ||
+ dent->filename[strlen(dent->filename) - 1] == '~')
+ continue;
+
+ if ((ext = strrchr(dent->filename, '.')) != NULL)
+ if (!strcmp(ext, ".bck") ||
+ !strcmp(ext, ".bak") ||
+ !strcmp(ext, ".sav"))
+ continue;
+
+ /*
+ * Must be a valid file; add it!
+ */
+
+ add_banner(dent->filename, filename);
+ }
+
+ /*
+ * Close the directory...
+ */
+
+ cupsDirClose(dir);
+}
+
+
+/*
+ * 'add_banner()' - Add a banner to the array.
+ */
+
+static void
+add_banner(const char *name, /* I - Name of banner */
+ const char *filename) /* I - Filename for banner */
+{
+ mime_type_t *filetype; /* Filetype */
+ cupsd_banner_t *temp; /* New banner data */
+
+
+ /*
+ * See what the filetype is...
+ */
+
+ if ((filetype = mimeFileType(MimeDatabase, filename, NULL, NULL)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "add_banner: Banner \"%s\" (\"%s\") is of an unknown file "
+ "type - skipping!", name, filename);
+ return;
+ }
+
+ /*
+ * Allocate memory...
+ */
+
+ if ((temp = calloc(1, sizeof(cupsd_banner_t))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "add_banner: Unable to allocate memory for banner \"%s\" - "
+ "skipping!", name);
+ return;
+ }
+
+ /*
+ * Copy the new banner data over...
+ */
+
+ if ((temp->name = strdup(name)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "add_banner: Unable to allocate memory for banner \"%s\" - "
+ "skipping!", name);
+ free(temp);
+ return;
+ }
+
+ temp->filetype = filetype;
+
+ cupsArrayAdd(Banners, temp);
+}
+
+
+/*
+ * 'compare_banners()' - Compare two banners.
+ */
+
+static int /* O - -1 if name0 < name1, etc. */
+compare_banners(
+ const cupsd_banner_t *b0, /* I - First banner */
+ const cupsd_banner_t *b1) /* I - Second banner */
+{
+ return (_cups_strcasecmp(b0->name, b1->name));
+}
+
+
+/*
+ * 'free_banners()' - Free all banners.
+ */
+
+static void
+free_banners(void)
+{
+ cupsd_banner_t *temp; /* Current banner */
+
+
+ for (temp = (cupsd_banner_t *)cupsArrayFirst(Banners);
+ temp;
+ temp = (cupsd_banner_t *)cupsArrayNext(Banners))
+ {
+ free(temp->name);
+ free(temp);
+ }
+
+ cupsArrayDelete(Banners);
+ Banners = NULL;
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/banners.h b/scheduler/banners.h
new file mode 100644
index 000000000..fb933aaae
--- /dev/null
+++ b/scheduler/banners.h
@@ -0,0 +1,45 @@
+/*
+ * "$Id$"
+ *
+ * Banner definitions for the CUPS scheduler.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/*
+ * Banner information structure...
+ */
+
+typedef struct /**** Banner file information ****/
+{
+ char *name; /* Name of banner */
+ mime_type_t *filetype; /* Filetype for banner */
+} cupsd_banner_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR cups_array_t *Banners VALUE(NULL);
+ /* Available banner files */
+
+
+/*
+ * Prototypes...
+ */
+
+extern cupsd_banner_t *cupsdFindBanner(const char *name);
+extern void cupsdLoadBanners(const char *d);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/cert.c b/scheduler/cert.c
new file mode 100644
index 000000000..d3ef7fdb6
--- /dev/null
+++ b/scheduler/cert.c
@@ -0,0 +1,442 @@
+/*
+ * "$Id$"
+ *
+ * Authentication certificate routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdAddCert() - Add a certificate.
+ * cupsdDeleteCert() - Delete a single certificate.
+ * cupsdDeleteAllCerts() - Delete all certificates...
+ * cupsdFindCert() - Find a certificate.
+ * cupsdInitCerts() - Initialize the certificate "system" and root
+ * certificate.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#ifdef HAVE_ACL_INIT
+# include <sys/acl.h>
+# ifdef HAVE_MEMBERSHIP_H
+# include <membership.h>
+# endif /* HAVE_MEMBERSHIP_H */
+#endif /* HAVE_ACL_INIT */
+
+
+/*
+ * 'cupsdAddCert()' - Add a certificate.
+ */
+
+void
+cupsdAddCert(int pid, /* I - Process ID */
+ const char *username, /* I - Username */
+ void *ccache) /* I - Kerberos credentials or NULL */
+{
+ int i; /* Looping var */
+ cupsd_cert_t *cert; /* Current certificate */
+ int fd; /* Certificate file */
+ char filename[1024]; /* Certificate filename */
+ static const char hex[] = "0123456789ABCDEF";
+ /* Hex constants... */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdAddCert: Adding certificate for PID %d", pid);
+
+ /*
+ * Allocate memory for the certificate...
+ */
+
+ if ((cert = calloc(sizeof(cupsd_cert_t), 1)) == NULL)
+ return;
+
+ /*
+ * Fill in the certificate information...
+ */
+
+ cert->pid = pid;
+ strlcpy(cert->username, username, sizeof(cert->username));
+
+ for (i = 0; i < 32; i ++)
+ cert->certificate[i] = hex[CUPS_RAND() & 15];
+
+ /*
+ * Save the certificate to a file readable only by the User and Group
+ * (or root and SystemGroup for PID == 0)...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
+ unlink(filename);
+
+ if ((fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create certificate file %s - %s",
+ filename, strerror(errno));
+ free(cert);
+ return;
+ }
+
+ if (pid == 0)
+ {
+#ifdef HAVE_ACL_INIT
+ acl_t acl; /* ACL information */
+ acl_entry_t entry; /* ACL entry */
+ acl_permset_t permset; /* Permissions */
+# ifdef HAVE_MBR_UID_TO_UUID
+ uuid_t group; /* Group ID */
+# endif /* HAVE_MBR_UID_TO_UUID */
+ static int acls_not_supported = 0;
+ /* Only warn once */
+#endif /* HAVE_ACL_INIT */
+
+
+ /*
+ * Root certificate...
+ */
+
+ fchmod(fd, 0440);
+ fchown(fd, RunUser, SystemGroupIDs[0]);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: NumSystemGroups=%d",
+ NumSystemGroups);
+
+#ifdef HAVE_ACL_INIT
+ if (NumSystemGroups > 1)
+ {
+ /*
+ * Set POSIX ACLs for the root certificate so that all system
+ * groups can access it...
+ */
+
+# ifdef HAVE_MBR_UID_TO_UUID
+ /*
+ * On MacOS X, ACLs use UUIDs instead of GIDs...
+ */
+
+ acl = acl_init(NumSystemGroups - 1);
+
+ for (i = 1; i < NumSystemGroups; i ++)
+ {
+ /*
+ * Add each group ID to the ACL...
+ */
+
+ acl_create_entry(&acl, &entry);
+ acl_get_permset(entry, &permset);
+ acl_add_perm(permset, ACL_READ_DATA);
+ acl_set_tag_type(entry, ACL_EXTENDED_ALLOW);
+ mbr_gid_to_uuid((gid_t)SystemGroupIDs[i], group);
+ acl_set_qualifier(entry, &group);
+ acl_set_permset(entry, permset);
+ }
+# else
+ /*
+ * POSIX ACLs need permissions for owner, group, other, and mask
+ * in addition to the rest of the system groups...
+ */
+
+ acl = acl_init(NumSystemGroups + 3);
+
+ /* Owner */
+ acl_create_entry(&acl, &entry);
+ acl_get_permset(entry, &permset);
+ acl_add_perm(permset, ACL_READ);
+ acl_set_tag_type(entry, ACL_USER_OBJ);
+ acl_set_permset(entry, permset);
+
+ /* Group */
+ acl_create_entry(&acl, &entry);
+ acl_get_permset(entry, &permset);
+ acl_add_perm(permset, ACL_READ);
+ acl_set_tag_type(entry, ACL_GROUP_OBJ);
+ acl_set_permset(entry, permset);
+
+ /* Others */
+ acl_create_entry(&acl, &entry);
+ acl_get_permset(entry, &permset);
+ acl_add_perm(permset, 0);
+ acl_set_tag_type(entry, ACL_OTHER);
+ acl_set_permset(entry, permset);
+
+ /* Mask */
+ acl_create_entry(&acl, &entry);
+ acl_get_permset(entry, &permset);
+ acl_add_perm(permset, ACL_READ);
+ acl_set_tag_type(entry, ACL_MASK);
+ acl_set_permset(entry, permset);
+
+ for (i = 1; i < NumSystemGroups; i ++)
+ {
+ /*
+ * Add each group ID to the ACL...
+ */
+
+ acl_create_entry(&acl, &entry);
+ acl_get_permset(entry, &permset);
+ acl_add_perm(permset, ACL_READ);
+ acl_set_tag_type(entry, ACL_GROUP);
+ acl_set_qualifier(entry, SystemGroupIDs + i);
+ acl_set_permset(entry, permset);
+ }
+
+ if (acl_valid(acl))
+ {
+ char *text, *textptr; /* Temporary string */
+
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "ACL did not validate: %s",
+ strerror(errno));
+ text = acl_to_text(acl, NULL);
+ for (textptr = strchr(text, '\n');
+ textptr;
+ textptr = strchr(textptr + 1, '\n'))
+ *textptr = ',';
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "ACL: %s", text);
+ free(text);
+ }
+# endif /* HAVE_MBR_UID_TO_UUID */
+
+ if (acl_set_fd(fd, acl))
+ {
+ if (errno != EOPNOTSUPP || !acls_not_supported)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to set ACLs on root certificate \"%s\" - %s",
+ filename, strerror(errno));
+
+ if (errno == EOPNOTSUPP)
+ acls_not_supported = 1;
+ }
+
+ acl_free(acl);
+ }
+#endif /* HAVE_ACL_INIT */
+
+ RootCertTime = time(NULL);
+ }
+ else
+ {
+ /*
+ * CGI certificate...
+ */
+
+ fchmod(fd, 0400);
+ fchown(fd, User, Group);
+ }
+
+ DEBUG_printf(("ADD pid=%d, username=%s, cert=%s\n", pid, username,
+ cert->certificate));
+
+ write(fd, cert->certificate, strlen(cert->certificate));
+ close(fd);
+
+ /*
+ * Add Kerberos credentials as needed...
+ */
+
+#ifdef HAVE_GSSAPI
+ cert->ccache = (krb5_ccache)ccache;
+#else
+ (void)ccache;
+#endif /* HAVE_GSSAPI */
+
+ /*
+ * Insert the certificate at the front of the list...
+ */
+
+ cert->next = Certs;
+ Certs = cert;
+}
+
+
+/*
+ * 'cupsdDeleteCert()' - Delete a single certificate.
+ */
+
+void
+cupsdDeleteCert(int pid) /* I - Process ID */
+{
+ cupsd_cert_t *cert, /* Current certificate */
+ *prev; /* Previous certificate */
+ char filename[1024]; /* Certificate file */
+
+
+ for (prev = NULL, cert = Certs; cert != NULL; prev = cert, cert = cert->next)
+ if (cert->pid == pid)
+ {
+ /*
+ * Remove this certificate from the list...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdDeleteCert: Removing certificate for PID %d", pid);
+
+ DEBUG_printf(("DELETE pid=%d, username=%s, cert=%s\n", cert->pid,
+ cert->username, cert->certificate));
+
+ if (prev == NULL)
+ Certs = cert->next;
+ else
+ prev->next = cert->next;
+
+#ifdef HAVE_GSSAPI
+ /*
+ * Release Kerberos credentials as needed...
+ */
+
+ if (cert->ccache)
+ krb5_cc_destroy(KerberosContext, cert->ccache);
+#endif /* HAVE_GSSAPI */
+
+ free(cert);
+
+ /*
+ * Delete the file and return...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
+ if (unlink(filename))
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
+
+ return;
+ }
+}
+
+
+/*
+ * 'cupsdDeleteAllCerts()' - Delete all certificates...
+ */
+
+void
+cupsdDeleteAllCerts(void)
+{
+ cupsd_cert_t *cert, /* Current certificate */
+ *next; /* Next certificate */
+ char filename[1024]; /* Certificate file */
+
+
+ /*
+ * Loop through each certificate, deleting them...
+ */
+
+ for (cert = Certs; cert != NULL; cert = next)
+ {
+ /*
+ * Delete the file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, cert->pid);
+ if (unlink(filename))
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove %s!", filename);
+
+ /*
+ * Free memory...
+ */
+
+ next = cert->next;
+ free(cert);
+ }
+
+ Certs = NULL;
+ RootCertTime = 0;
+}
+
+
+/*
+ * 'cupsdFindCert()' - Find a certificate.
+ */
+
+cupsd_cert_t * /* O - Matching certificate or NULL */
+cupsdFindCert(const char *certificate) /* I - Certificate */
+{
+ cupsd_cert_t *cert; /* Current certificate */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert(certificate=%s)",
+ certificate);
+ for (cert = Certs; cert != NULL; cert = cert->next)
+ if (!_cups_strcasecmp(certificate, cert->certificate))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Returning %s...",
+ cert->username);
+ return (cert);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindCert: Certificate not found!");
+
+ return (NULL);
+}
+
+
+/*
+ * 'cupsdInitCerts()' - Initialize the certificate "system" and root
+ * certificate.
+ */
+
+void
+cupsdInitCerts(void)
+{
+#ifndef HAVE_ARC4RANDOM
+ cups_file_t *fp; /* /dev/random file */
+
+
+ /*
+ * Initialize the random number generator using the random device or
+ * the current time, as available...
+ */
+
+ if ((fp = cupsFileOpen("/dev/urandom", "rb")) == NULL)
+ {
+ struct timeval tod; /* Time of day */
+
+ /*
+ * Get the time in usecs and use it as the initial seed...
+ */
+
+ gettimeofday(&tod, NULL);
+
+ CUPS_SRAND((unsigned)(tod.tv_sec + tod.tv_usec));
+ }
+ else
+ {
+ unsigned seed; /* Seed for random number generator */
+
+ /*
+ * Read 4 random characters from the random device and use
+ * them as the seed...
+ */
+
+ seed = cupsFileGetChar(fp);
+ seed = (seed << 8) | cupsFileGetChar(fp);
+ seed = (seed << 8) | cupsFileGetChar(fp);
+ CUPS_SRAND((seed << 8) | cupsFileGetChar(fp));
+
+ cupsFileClose(fp);
+ }
+#endif /* !HAVE_ARC4RANDOM */
+
+ /*
+ * Create a root certificate and return...
+ */
+
+ if (!RunUser)
+ cupsdAddCert(0, "root", NULL);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/cert.h b/scheduler/cert.h
new file mode 100644
index 000000000..a8206b142
--- /dev/null
+++ b/scheduler/cert.h
@@ -0,0 +1,56 @@
+/*
+ * "$Id$"
+ *
+ * Authentication certificate definitions for the CUPS scheduler.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/*
+ * Certificate structure...
+ */
+
+typedef struct cupsd_cert_s
+{
+ struct cupsd_cert_s *next; /* Next certificate in list */
+ int pid; /* Process ID (0 for root certificate) */
+ char certificate[33]; /* 32 hex characters, or 128 bits */
+ char username[33]; /* Authenticated username */
+#ifdef HAVE_GSSAPI
+ krb5_ccache ccache; /* Kerberos credential cache */
+#endif /* HAVE_GSSAPI */
+} cupsd_cert_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR cupsd_cert_t *Certs /* List of certificates */
+ VALUE(NULL);
+VAR time_t RootCertTime /* Root certificate update time */
+ VALUE(0);
+
+
+/*
+ * Prototypes...
+ */
+
+extern void cupsdAddCert(int pid, const char *username,
+ void *ccache);
+extern void cupsdDeleteCert(int pid);
+extern void cupsdDeleteAllCerts(void);
+extern cupsd_cert_t *cupsdFindCert(const char *certificate);
+extern void cupsdInitCerts(void);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/classes.c b/scheduler/classes.c
new file mode 100644
index 000000000..b76faaa17
--- /dev/null
+++ b/scheduler/classes.c
@@ -0,0 +1,868 @@
+/*
+ * "$Id$"
+ *
+ * Printer class routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdAddClass() - Add a class to the system.
+ * cupsdAddPrinterToClass() - Add a printer to a class...
+ * cupsdDeletePrinterFromClass() - Delete a printer from a class.
+ * cupsdDeletePrinterFromClasses() - Delete a printer from all classes.
+ * cupsdFindAvailablePrinter() - Find an available printer in a class.
+ * cupsdFindClass() - Find the named class.
+ * cupsdLoadAllClasses() - Load classes from the classes.conf file.
+ * cupsdSaveAllClasses() - Save classes to the classes.conf file.
+ * cupsdUpdateImplicitClasses() - Update the accepting state of implicit
+ * classes.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+
+/*
+ * 'cupsdAddClass()' - Add a class to the system.
+ */
+
+cupsd_printer_t * /* O - New class */
+cupsdAddClass(const char *name) /* I - Name of class */
+{
+ cupsd_printer_t *c; /* New class */
+ char uri[1024]; /* Class URI */
+
+
+ /*
+ * Add the printer and set the type to "class"...
+ */
+
+ if ((c = cupsdAddPrinter(name)) != NULL)
+ {
+ /*
+ * Change from a printer to a class...
+ */
+
+ c->type = CUPS_PRINTER_CLASS;
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ ServerName, RemotePort, "/classes/%s", name);
+ cupsdSetString(&c->uri, uri);
+
+ cupsdSetString(&c->error_policy, "retry-current-job");
+ }
+
+ return (c);
+}
+
+
+/*
+ * 'cupsdAddPrinterToClass()' - Add a printer to a class...
+ */
+
+void
+cupsdAddPrinterToClass(
+ cupsd_printer_t *c, /* I - Class to add to */
+ cupsd_printer_t *p) /* I - Printer to add */
+{
+ int i; /* Looping var */
+ cupsd_printer_t **temp; /* Pointer to printer array */
+
+
+ /*
+ * See if this printer is already a member of the class...
+ */
+
+ for (i = 0; i < c->num_printers; i ++)
+ if (c->printers[i] == p)
+ return;
+
+ /*
+ * Allocate memory as needed...
+ */
+
+ if (c->num_printers == 0)
+ temp = malloc(sizeof(cupsd_printer_t *));
+ else
+ temp = realloc(c->printers, sizeof(cupsd_printer_t *) * (c->num_printers + 1));
+
+ if (temp == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add printer %s to class %s!",
+ p->name, c->name);
+ return;
+ }
+
+ /*
+ * Add the printer to the end of the array and update the number of printers.
+ */
+
+ c->printers = temp;
+ temp += c->num_printers;
+ c->num_printers ++;
+
+ *temp = p;
+}
+
+
+/*
+ * 'cupsdDeletePrinterFromClass()' - Delete a printer from a class.
+ */
+
+int /* O - 1 if class changed, 0 otherwise */
+cupsdDeletePrinterFromClass(
+ cupsd_printer_t *c, /* I - Class to delete from */
+ cupsd_printer_t *p) /* I - Printer to delete */
+{
+ int i; /* Looping var */
+
+
+ /*
+ * See if the printer is in the class...
+ */
+
+ for (i = 0; i < c->num_printers; i ++)
+ if (p == c->printers[i])
+ break;
+
+ /*
+ * If it is, remove it from the list...
+ */
+
+ if (i < c->num_printers)
+ {
+ /*
+ * Yes, remove the printer...
+ */
+
+ c->num_printers --;
+ if (i < c->num_printers)
+ memmove(c->printers + i, c->printers + i + 1,
+ (c->num_printers - i) * sizeof(cupsd_printer_t *));
+ }
+ else
+ return (0);
+
+ /*
+ * Update the IPP attributes (have to do this for member-names)...
+ */
+
+ cupsdSetPrinterAttrs(c);
+
+ return (1);
+}
+
+
+/*
+ * 'cupsdDeletePrinterFromClasses()' - Delete a printer from all classes.
+ */
+
+int /* O - 1 if class changed, 0 otherwise */
+cupsdDeletePrinterFromClasses(
+ cupsd_printer_t *p) /* I - Printer to delete */
+{
+ int changed = 0; /* Any class changed? */
+ cupsd_printer_t *c; /* Pointer to current class */
+
+
+ /*
+ * Loop through the printer/class list and remove the printer
+ * from each class listed...
+ */
+
+ for (c = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ c;
+ c = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ changed |= cupsdDeletePrinterFromClass(c, p);
+
+ /*
+ * Then clean out any empty implicit classes...
+ */
+
+ for (c = (cupsd_printer_t *)cupsArrayFirst(ImplicitPrinters);
+ c;
+ c = (cupsd_printer_t *)cupsArrayNext(ImplicitPrinters))
+ if (c->num_printers == 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Deleting implicit class \"%s\"...",
+ c->name);
+ cupsdDeletePrinter(c, 0);
+ changed = 1;
+ }
+
+ return (changed);
+}
+
+
+/*
+ * 'cupsdFindAvailablePrinter()' - Find an available printer in a class.
+ */
+
+cupsd_printer_t * /* O - Available printer or NULL */
+cupsdFindAvailablePrinter(
+ const char *name) /* I - Class to check */
+{
+ int i; /* Looping var */
+ cupsd_printer_t *c; /* Printer class */
+
+
+ /*
+ * Find the class...
+ */
+
+ if ((c = cupsdFindClass(name)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to find class \"%s\"!", name);
+ return (NULL);
+ }
+
+ if (c->num_printers == 0)
+ return (NULL);
+
+ /*
+ * Make sure that the last printer is also a valid index into the printer
+ * array. If not, reset the last printer to 0...
+ */
+
+ if (c->last_printer >= c->num_printers)
+ c->last_printer = 0;
+
+ /*
+ * Loop through the printers in the class and return the first idle
+ * printer... We keep track of the last printer that we used so that
+ * a "round robin" type of scheduling is realized (otherwise the first
+ * server might be saturated with print jobs...)
+ *
+ * Thanks to Joel Fredrikson for helping us get this right!
+ */
+
+ for (i = c->last_printer + 1; ; i ++)
+ {
+ if (i >= c->num_printers)
+ i = 0;
+
+ if (c->printers[i]->accepting &&
+ (c->printers[i]->state == IPP_PRINTER_IDLE ||
+ ((c->printers[i]->type & CUPS_PRINTER_REMOTE) && !c->printers[i]->job)))
+ {
+ c->last_printer = i;
+ return (c->printers[i]);
+ }
+
+ if (i == c->last_printer)
+ break;
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * 'cupsdFindClass()' - Find the named class.
+ */
+
+cupsd_printer_t * /* O - Matching class or NULL */
+cupsdFindClass(const char *name) /* I - Name of class */
+{
+ cupsd_printer_t *c; /* Current class/printer */
+
+
+ if ((c = cupsdFindDest(name)) != NULL &&
+ (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)))
+ return (c);
+ else
+ return (NULL);
+}
+
+
+/*
+ * 'cupsdLoadAllClasses()' - Load classes from the classes.conf file.
+ */
+
+void
+cupsdLoadAllClasses(void)
+{
+ int i; /* Looping var */
+ cups_file_t *fp; /* classes.conf file */
+ int linenum; /* Current line number */
+ char line[4096], /* Line from file */
+ *value, /* Pointer to value */
+ *valueptr; /* Pointer into value */
+ cupsd_printer_t *p, /* Current printer class */
+ *temp; /* Temporary pointer to printer */
+
+
+ /*
+ * Open the classes.conf file...
+ */
+
+ snprintf(line, sizeof(line), "%s/classes.conf", ServerRoot);
+ if ((fp = cupsdOpenConfFile(line)) == NULL)
+ return;
+
+ /*
+ * Read class configurations until we hit EOF...
+ */
+
+ linenum = 0;
+ p = NULL;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ /*
+ * Decode the directive...
+ */
+
+ if (!_cups_strcasecmp(line, "<Class") ||
+ !_cups_strcasecmp(line, "<DefaultClass"))
+ {
+ /*
+ * <Class name> or <DefaultClass name>
+ */
+
+ if (p == NULL && value)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading class %s...", value);
+
+ /*
+ * Since prior classes may have implicitly defined this class,
+ * see if it already exists...
+ */
+
+ if ((p = cupsdFindDest(value)) != NULL)
+ {
+ p->type = CUPS_PRINTER_CLASS;
+ cupsdSetStringf(&p->uri, "ipp://%s:%d/classes/%s", ServerName,
+ LocalPort, value);
+ cupsdSetString(&p->error_policy, "retry-job");
+ }
+ else
+ p = cupsdAddClass(value);
+
+ p->accepting = 1;
+ p->state = IPP_PRINTER_IDLE;
+
+ if (!_cups_strcasecmp(line, "<DefaultClass"))
+ DefaultPrinter = p;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "</Class>"))
+ {
+ if (p != NULL)
+ {
+ cupsdSetPrinterAttrs(p);
+ p = NULL;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.", linenum);
+ }
+ else if (!p)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "UUID"))
+ {
+ if (value && !strncmp(value, "urn:uuid:", 9))
+ cupsdSetString(&(p->uuid), value);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad UUID on line %d of classes.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "AuthInfoRequired"))
+ {
+ if (!cupsdSetAuthInfoRequired(p, value, NULL))
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad AuthInfoRequired on line %d of classes.conf.",
+ linenum);
+ }
+ else if (!_cups_strcasecmp(line, "Info"))
+ {
+ if (value)
+ cupsdSetString(&p->info, value);
+ }
+ else if (!_cups_strcasecmp(line, "Location"))
+ {
+ if (value)
+ cupsdSetString(&p->location, value);
+ }
+ else if (!_cups_strcasecmp(line, "Option") && value)
+ {
+ /*
+ * Option name value
+ */
+
+ for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
+
+ if (!*valueptr)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.", linenum);
+ else
+ {
+ for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
+
+ p->num_options = cupsAddOption(value, valueptr, p->num_options,
+ &(p->options));
+ }
+ }
+ else if (!_cups_strcasecmp(line, "Printer"))
+ {
+ if (!value)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.", linenum);
+ continue;
+ }
+ else if ((temp = cupsdFindPrinter(value)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Unknown printer %s on line %d of classes.conf.",
+ value, linenum);
+
+ /*
+ * Add the missing remote printer...
+ */
+
+ if ((temp = cupsdAddPrinter(value)) != NULL)
+ {
+ cupsdSetString(&temp->make_model, "Remote Printer on unknown");
+
+ temp->state = IPP_PRINTER_STOPPED;
+ temp->type |= CUPS_PRINTER_REMOTE;
+ temp->browse_time = 2147483647;
+
+ cupsdSetString(&temp->location, "Location Unknown");
+ cupsdSetString(&temp->info, "No Information Available");
+ temp->hostname[0] = '\0';
+
+ cupsdSetPrinterAttrs(temp);
+ }
+ }
+
+ if (temp)
+ cupsdAddPrinterToClass(p, temp);
+ }
+ else if (!_cups_strcasecmp(line, "State"))
+ {
+ /*
+ * Set the initial queue state...
+ */
+
+ if (!_cups_strcasecmp(value, "idle"))
+ p->state = IPP_PRINTER_IDLE;
+ else if (!_cups_strcasecmp(value, "stopped"))
+ {
+ p->state = IPP_PRINTER_STOPPED;
+
+ for (i = 0 ; i < p->num_reasons; i ++)
+ if (!strcmp("paused", p->reasons[i]))
+ break;
+
+ if (i >= p->num_reasons &&
+ p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
+ {
+ p->reasons[p->num_reasons] = _cupsStrAlloc("paused");
+ p->num_reasons ++;
+ }
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.",
+ linenum);
+ }
+ else if (!_cups_strcasecmp(line, "StateMessage"))
+ {
+ /*
+ * Set the initial queue state message...
+ */
+
+ if (value)
+ strlcpy(p->state_message, value, sizeof(p->state_message));
+ }
+ else if (!_cups_strcasecmp(line, "StateTime"))
+ {
+ /*
+ * Set the state time...
+ */
+
+ if (value)
+ p->state_time = atoi(value);
+ }
+ else if (!_cups_strcasecmp(line, "Accepting"))
+ {
+ /*
+ * Set the initial accepting state...
+ */
+
+ if (value &&
+ (!_cups_strcasecmp(value, "yes") ||
+ !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "true")))
+ p->accepting = 1;
+ else if (value &&
+ (!_cups_strcasecmp(value, "no") ||
+ !_cups_strcasecmp(value, "off") ||
+ !_cups_strcasecmp(value, "false")))
+ p->accepting = 0;
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.",
+ linenum);
+ }
+ else if (!_cups_strcasecmp(line, "Shared"))
+ {
+ /*
+ * Set the initial shared state...
+ */
+
+ if (value &&
+ (!_cups_strcasecmp(value, "yes") ||
+ !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "true")))
+ p->shared = 1;
+ else if (value &&
+ (!_cups_strcasecmp(value, "no") ||
+ !_cups_strcasecmp(value, "off") ||
+ !_cups_strcasecmp(value, "false")))
+ p->shared = 0;
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.",
+ linenum);
+ }
+ else if (!_cups_strcasecmp(line, "JobSheets"))
+ {
+ /*
+ * Set the initial job sheets...
+ */
+
+ if (value)
+ {
+ for (valueptr = value;
+ *valueptr && !isspace(*valueptr & 255);
+ valueptr ++);
+
+ if (*valueptr)
+ *valueptr++ = '\0';
+
+ cupsdSetString(&p->job_sheets[0], value);
+
+ while (isspace(*valueptr & 255))
+ valueptr ++;
+
+ if (*valueptr)
+ {
+ for (value = valueptr;
+ *valueptr && !isspace(*valueptr & 255);
+ valueptr ++);
+
+ if (*valueptr)
+ *valueptr = '\0';
+
+ cupsdSetString(&p->job_sheets[1], value);
+ }
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "AllowUser"))
+ {
+ if (value)
+ {
+ p->deny_users = 0;
+ cupsdAddString(&(p->users), value);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "DenyUser"))
+ {
+ if (value)
+ {
+ p->deny_users = 1;
+ cupsdAddString(&(p->users), value);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "QuotaPeriod"))
+ {
+ if (value)
+ p->quota_period = atoi(value);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "PageLimit"))
+ {
+ if (value)
+ p->page_limit = atoi(value);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "KLimit"))
+ {
+ if (value)
+ p->k_limit = atoi(value);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "OpPolicy"))
+ {
+ if (value)
+ {
+ cupsd_policy_t *pol; /* Policy */
+
+
+ if ((pol = cupsdFindPolicy(value)) != NULL)
+ {
+ cupsdSetString(&p->op_policy, value);
+ p->op_policy_ptr = pol;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad policy \"%s\" on line %d of classes.conf",
+ value, linenum);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "ErrorPolicy"))
+ {
+ if (value)
+ {
+ if (strcmp(value, "retry-current-job") && strcmp(value, "retry-job"))
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "ErrorPolicy %s ignored on line %d of classes.conf",
+ value, linenum);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of classes.conf.", linenum);
+ }
+ else
+ {
+ /*
+ * Something else we don't understand...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown configuration directive %s on line %d of classes.conf.",
+ line, linenum);
+ }
+ }
+
+ cupsFileClose(fp);
+}
+
+
+/*
+ * 'cupsdSaveAllClasses()' - Save classes to the classes.conf file.
+ */
+
+void
+cupsdSaveAllClasses(void)
+{
+ cups_file_t *fp; /* classes.conf file */
+ char filename[1024], /* classes.conf filename */
+ temp[1024], /* Temporary string */
+ value[2048], /* Value string */
+ *name; /* Current user name */
+ cupsd_printer_t *pclass; /* Current printer class */
+ int i; /* Looping var */
+ time_t curtime; /* Current time */
+ struct tm *curdate; /* Current date */
+ cups_option_t *option; /* Current option */
+
+
+ /*
+ * Create the classes.conf file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/classes.conf", ServerRoot);
+
+ if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm)) == NULL)
+ return;
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Saving classes.conf...");
+
+ /*
+ * Write a small header to the file...
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+ strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
+
+ cupsFilePuts(fp, "# Class configuration file for " CUPS_SVERSION "\n");
+ cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
+ cupsFilePuts(fp, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n");
+
+ /*
+ * Write each local class known to the system...
+ */
+
+ for (pclass = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ pclass;
+ pclass = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ /*
+ * Skip remote destinations and regular printers...
+ */
+
+ if ((pclass->type & CUPS_PRINTER_REMOTE) ||
+ (pclass->type & CUPS_PRINTER_IMPLICIT) ||
+ !(pclass->type & CUPS_PRINTER_CLASS))
+ continue;
+
+ /*
+ * Write printers as needed...
+ */
+
+ if (pclass == DefaultPrinter)
+ cupsFilePrintf(fp, "<DefaultClass %s>\n", pclass->name);
+ else
+ cupsFilePrintf(fp, "<Class %s>\n", pclass->name);
+
+ cupsFilePrintf(fp, "UUID %s\n", pclass->uuid);
+
+ if (pclass->num_auth_info_required > 0)
+ {
+ switch (pclass->num_auth_info_required)
+ {
+ case 1 :
+ strlcpy(value, pclass->auth_info_required[0], sizeof(value));
+ break;
+
+ case 2 :
+ snprintf(value, sizeof(value), "%s,%s",
+ pclass->auth_info_required[0],
+ pclass->auth_info_required[1]);
+ break;
+
+ case 3 :
+ default :
+ snprintf(value, sizeof(value), "%s,%s,%s",
+ pclass->auth_info_required[0],
+ pclass->auth_info_required[1],
+ pclass->auth_info_required[2]);
+ break;
+ }
+
+ cupsFilePutConf(fp, "AuthInfoRequired", value);
+ }
+
+ if (pclass->info)
+ cupsFilePutConf(fp, "Info", pclass->info);
+
+ if (pclass->location)
+ cupsFilePutConf(fp, "Location", pclass->location);
+
+ if (pclass->state == IPP_PRINTER_STOPPED)
+ cupsFilePuts(fp, "State Stopped\n");
+ else
+ cupsFilePuts(fp, "State Idle\n");
+
+ cupsFilePrintf(fp, "StateTime %d\n", (int)pclass->state_time);
+
+ if (pclass->accepting)
+ cupsFilePuts(fp, "Accepting Yes\n");
+ else
+ cupsFilePuts(fp, "Accepting No\n");
+
+ if (pclass->shared)
+ cupsFilePuts(fp, "Shared Yes\n");
+ else
+ cupsFilePuts(fp, "Shared No\n");
+
+ snprintf(value, sizeof(value), "%s %s", pclass->job_sheets[0],
+ pclass->job_sheets[1]);
+ cupsFilePutConf(fp, "JobSheets", value);
+
+ for (i = 0; i < pclass->num_printers; i ++)
+ cupsFilePrintf(fp, "Printer %s\n", pclass->printers[i]->name);
+
+ cupsFilePrintf(fp, "QuotaPeriod %d\n", pclass->quota_period);
+ cupsFilePrintf(fp, "PageLimit %d\n", pclass->page_limit);
+ cupsFilePrintf(fp, "KLimit %d\n", pclass->k_limit);
+
+ for (name = (char *)cupsArrayFirst(pclass->users);
+ name;
+ name = (char *)cupsArrayNext(pclass->users))
+ cupsFilePutConf(fp, pclass->deny_users ? "DenyUser" : "AllowUser", name);
+
+ if (pclass->op_policy)
+ cupsFilePutConf(fp, "OpPolicy", pclass->op_policy);
+ if (pclass->error_policy)
+ cupsFilePutConf(fp, "ErrorPolicy", pclass->error_policy);
+
+ for (i = pclass->num_options, option = pclass->options;
+ i > 0;
+ i --, option ++)
+ {
+ snprintf(value, sizeof(value), "%s %s", option->name, option->value);
+ cupsFilePutConf(fp, "Option", value);
+ }
+
+ cupsFilePuts(fp, "</Class>\n");
+ }
+
+ cupsdCloseCreatedConfFile(fp, filename);
+}
+
+
+/*
+ * 'cupsdUpdateImplicitClasses()' - Update the accepting state of implicit
+ * classes.
+ */
+
+void
+cupsdUpdateImplicitClasses(void)
+{
+ int i; /* Looping var */
+ cupsd_printer_t *pclass; /* Current class */
+ int accepting; /* printer-is-accepting-jobs value */
+
+
+ for (pclass = (cupsd_printer_t *)cupsArrayFirst(ImplicitPrinters);
+ pclass;
+ pclass = (cupsd_printer_t *)cupsArrayNext(ImplicitPrinters))
+ {
+ /*
+ * Loop through the printers to come up with a composite state...
+ */
+
+ for (i = 0, accepting = 0; i < pclass->num_printers; i ++)
+ if ((accepting = pclass->printers[i]->accepting) != 0)
+ break;
+
+ pclass->accepting = accepting;
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/classes.h b/scheduler/classes.h
new file mode 100644
index 000000000..423a959cd
--- /dev/null
+++ b/scheduler/classes.h
@@ -0,0 +1,36 @@
+/*
+ * "$Id$"
+ *
+ * Printer class definitions for the CUPS scheduler.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+
+/*
+ * Prototypes...
+ */
+
+extern cupsd_printer_t *cupsdAddClass(const char *name);
+extern void cupsdAddPrinterToClass(cupsd_printer_t *c,
+ cupsd_printer_t *p);
+extern int cupsdDeletePrinterFromClass(cupsd_printer_t *c,
+ cupsd_printer_t *p);
+extern int cupsdDeletePrinterFromClasses(cupsd_printer_t *p);
+extern cupsd_printer_t *cupsdFindAvailablePrinter(const char *name);
+extern cupsd_printer_t *cupsdFindClass(const char *name);
+extern void cupsdLoadAllClasses(void);
+extern void cupsdSaveAllClasses(void);
+extern void cupsdUpdateImplicitClasses(void);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/client.c b/scheduler/client.c
new file mode 100644
index 000000000..e645a782d
--- /dev/null
+++ b/scheduler/client.c
@@ -0,0 +1,5188 @@
+/*
+ * "$Id$"
+ *
+ * Client routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * This file contains Kerberos support code, copyright 2006 by
+ * Jelmer Vernooij.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdAcceptClient() - Accept a new client.
+ * cupsdCloseAllClients() - Close all remote clients immediately.
+ * cupsdCloseClient() - Close a remote client.
+ * cupsdFlushHeader() - Flush the header fields to the client.
+ * cupsdReadClient() - Read data from a client.
+ * cupsdSendCommand() - Send output from a command via HTTP.
+ * cupsdSendError() - Send an error message via HTTP.
+ * cupsdSendHeader() - Send an HTTP request.
+ * cupsdUpdateCGI() - Read status messages from CGI scripts and
+ * programs.
+ * cupsdWriteClient() - Write data to a client as needed.
+ * check_if_modified() - Decode an "If-Modified-Since" line.
+ * compare_clients() - Compare two client connections.
+ * data_ready() - Check whether data is available from a client.
+ * encrypt_client() - Enable encryption for the client...
+ * get_cdsa_certificate() - Get a SSL/TLS certificate from the System
+ * keychain.
+ * get_file() - Get a filename and state info.
+ * install_conf_file() - Install a configuration file.
+ * is_cgi() - Is the resource a CGI script/program?
+ * is_path_absolute() - Is a path absolute and free of relative elements
+ * (i.e. "..").
+ * make_certificate() - Make a self-signed SSL/TLS certificate.
+ * pipe_command() - Pipe the output of a command to the remote client.
+ * valid_host() - Is the Host: field valid?
+ * write_file() - Send a file via HTTP.
+ * write_pipe() - Flag that data is available on the CGI pipe.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+#ifdef HAVE_TCPD_H
+# include <tcpd.h>
+#endif /* HAVE_TCPD_H */
+
+
+/*
+ * Local functions...
+ */
+
+static int check_if_modified(cupsd_client_t *con,
+ struct stat *filestats);
+static int compare_clients(cupsd_client_t *a, cupsd_client_t *b,
+ void *data);
+static int data_ready(cupsd_client_t *con);
+#ifdef HAVE_SSL
+static int encrypt_client(cupsd_client_t *con);
+#endif /* HAVE_SSL */
+#ifdef HAVE_CDSASSL
+static CFArrayRef get_cdsa_certificate(cupsd_client_t *con);
+#endif /* HAVE_CDSASSL */
+static char *get_file(cupsd_client_t *con, struct stat *filestats,
+ char *filename, int len);
+static http_status_t install_conf_file(cupsd_client_t *con);
+static int is_cgi(cupsd_client_t *con, const char *filename,
+ struct stat *filestats, mime_type_t *type);
+static int is_path_absolute(const char *path);
+#ifdef HAVE_SSL
+static int make_certificate(cupsd_client_t *con);
+#endif /* HAVE_SSL */
+static int pipe_command(cupsd_client_t *con, int infile, int *outfile,
+ char *command, char *options, int root);
+static int valid_host(cupsd_client_t *con);
+static int write_file(cupsd_client_t *con, http_status_t code,
+ char *filename, char *type,
+ struct stat *filestats);
+static void write_pipe(cupsd_client_t *con);
+
+
+/*
+ * 'cupsdAcceptClient()' - Accept a new client.
+ */
+
+void
+cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
+{
+ int count; /* Count of connections on a host */
+ int val; /* Parameter value */
+ cupsd_client_t *con, /* New client pointer */
+ *tempcon; /* Temporary client pointer */
+ http_addrlist_t *addrlist, /* List of adddresses for host */
+ *addr; /* Current address */
+ socklen_t addrlen; /* Length of address */
+ char *hostname; /* Hostname for address */
+ http_addr_t temp; /* Temporary address variable */
+ static time_t last_dos = 0; /* Time of last DoS attack */
+#ifdef HAVE_TCPD_H
+ struct request_info wrap_req; /* TCP wrappers request information */
+#endif /* HAVE_TCPD_H */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdAcceptClient(lis=%p(%d)) Clients=%d",
+ lis, lis->fd, cupsArrayCount(Clients));
+
+ /*
+ * Make sure we don't have a full set of clients already...
+ */
+
+ if (cupsArrayCount(Clients) == MaxClients)
+ return;
+
+ /*
+ * Get a pointer to the next available client...
+ */
+
+ if (!Clients)
+ Clients = cupsArrayNew(NULL, NULL);
+
+ if (!Clients)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for clients array!");
+ cupsdPauseListening();
+ return;
+ }
+
+ if (!ActiveClients)
+ ActiveClients = cupsArrayNew((cups_array_func_t)compare_clients, NULL);
+
+ if (!ActiveClients)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for active clients array!");
+ cupsdPauseListening();
+ return;
+ }
+
+ if ((con = calloc(1, sizeof(cupsd_client_t))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate memory for client!");
+ cupsdPauseListening();
+ return;
+ }
+
+ con->http.activity = time(NULL);
+ con->file = -1;
+ con->http.hostaddr = &(con->clientaddr);
+
+ /*
+ * Accept the client and get the remote address...
+ */
+
+ addrlen = sizeof(http_addr_t);
+
+ if ((con->http.fd = accept(lis->fd, (struct sockaddr *)con->http.hostaddr,
+ &addrlen)) < 0)
+ {
+ if (errno == ENFILE || errno == EMFILE)
+ cupsdPauseListening();
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to accept client connection - %s.",
+ strerror(errno));
+ free(con);
+
+ return;
+ }
+
+ /*
+ * Save the connected port number...
+ */
+
+ _httpAddrSetPort(con->http.hostaddr, _httpAddrPort(&(lis->address)));
+
+#ifdef AF_INET6
+ /*
+ * Convert IPv4 over IPv6 addresses (::ffff:n.n.n.n) to IPv4 forms we
+ * can more easily use...
+ */
+
+ if (lis->address.addr.sa_family == AF_INET6 &&
+ con->http.hostaddr->ipv6.sin6_addr.s6_addr32[0] == 0 &&
+ con->http.hostaddr->ipv6.sin6_addr.s6_addr32[1] == 0 &&
+ ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2]) == 0xffff)
+ con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2] = 0;
+#endif /* AF_INET6 */
+
+ /*
+ * Check the number of clients on the same address...
+ */
+
+ for (count = 0, tempcon = (cupsd_client_t *)cupsArrayFirst(Clients);
+ tempcon;
+ tempcon = (cupsd_client_t *)cupsArrayNext(Clients))
+ if (httpAddrEqual(tempcon->http.hostaddr, con->http.hostaddr))
+ {
+ count ++;
+ if (count >= MaxClientsPerHost)
+ break;
+ }
+
+ if (count >= MaxClientsPerHost)
+ {
+ if ((time(NULL) - last_dos) >= 60)
+ {
+ last_dos = time(NULL);
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Possible DoS attack - more than %d clients connecting "
+ "from %s!",
+ MaxClientsPerHost,
+ httpAddrString(con->http.hostaddr, con->http.hostname,
+ sizeof(con->http.hostname)));
+ }
+
+#ifdef WIN32
+ closesocket(con->http.fd);
+#else
+ close(con->http.fd);
+#endif /* WIN32 */
+
+ free(con);
+ return;
+ }
+
+ /*
+ * Get the hostname or format the IP address as needed...
+ */
+
+ if (httpAddrLocalhost(con->http.hostaddr))
+ {
+ /*
+ * Map accesses from the loopback interface to "localhost"...
+ */
+
+ strlcpy(con->http.hostname, "localhost", sizeof(con->http.hostname));
+ hostname = con->http.hostname;
+ }
+ else
+ {
+ /*
+ * Map accesses from the same host to the server name.
+ */
+
+ if (HostNameLookups)
+ hostname = httpAddrLookup(con->http.hostaddr, con->http.hostname,
+ sizeof(con->http.hostname));
+ else
+ {
+ hostname = NULL;
+ httpAddrString(con->http.hostaddr, con->http.hostname,
+ sizeof(con->http.hostname));
+ }
+ }
+
+ if (hostname == NULL && HostNameLookups == 2)
+ {
+ /*
+ * Can't have an unresolved IP address with double-lookups enabled...
+ */
+
+#ifdef WIN32
+ closesocket(con->http.fd);
+#else
+ close(con->http.fd);
+#endif /* WIN32 */
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Name lookup failed - connection from %s closed!",
+ con->http.hostname);
+
+ free(con);
+ return;
+ }
+
+ if (HostNameLookups == 2)
+ {
+ /*
+ * Do double lookups as needed...
+ */
+
+ if ((addrlist = httpAddrGetList(con->http.hostname, AF_UNSPEC, NULL))
+ != NULL)
+ {
+ /*
+ * See if the hostname maps to the same IP address...
+ */
+
+ for (addr = addrlist; addr; addr = addr->next)
+ if (httpAddrEqual(con->http.hostaddr, &(addr->addr)))
+ break;
+ }
+ else
+ addr = NULL;
+
+ httpAddrFreeList(addrlist);
+
+ if (!addr)
+ {
+ /*
+ * Can't have a hostname that doesn't resolve to the same IP address
+ * with double-lookups enabled...
+ */
+
+#ifdef WIN32
+ closesocket(con->http.fd);
+#else
+ close(con->http.fd);
+#endif /* WIN32 */
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "IP lookup failed - connection from %s closed!",
+ con->http.hostname);
+ free(con);
+ return;
+ }
+ }
+
+#ifdef HAVE_TCPD_H
+ /*
+ * See if the connection is denied by TCP wrappers...
+ */
+
+ request_init(&wrap_req, RQ_DAEMON, "cupsd", RQ_FILE, con->http.fd, NULL);
+ fromhost(&wrap_req);
+
+ if (!hosts_access(&wrap_req))
+ {
+#ifdef WIN32
+ closesocket(con->http.fd);
+#else
+ close(con->http.fd);
+#endif /* WIN32 */
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Connection from %s refused by /etc/hosts.allow and "
+ "/etc/hosts.deny rules.", con->http.hostname);
+ free(con);
+ return;
+ }
+#endif /* HAVE_TCPD_H */
+
+#ifdef AF_LOCAL
+ if (con->http.hostaddr->addr.sa_family == AF_LOCAL)
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s (Domain)",
+ con->http.fd, con->http.hostname);
+ else
+#endif /* AF_LOCAL */
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s:%d (IPv%d)",
+ con->http.fd, con->http.hostname,
+ _httpAddrPort(con->http.hostaddr),
+ _httpAddrFamily(con->http.hostaddr) == AF_INET ? 4 : 6);
+
+ /*
+ * Get the local address the client connected to...
+ */
+
+ addrlen = sizeof(temp);
+ if (getsockname(con->http.fd, (struct sockaddr *)&temp, &addrlen))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get local address - %s",
+ strerror(errno));
+
+ strcpy(con->servername, "localhost");
+ con->serverport = LocalPort;
+ }
+#ifdef AF_LOCAL
+ else if (_httpAddrFamily(&temp) == AF_LOCAL)
+ {
+ strcpy(con->servername, "localhost");
+ con->serverport = LocalPort;
+ }
+#endif /* AF_LOCAL */
+ else
+ {
+ if (httpAddrLocalhost(&temp))
+ strlcpy(con->servername, "localhost", sizeof(con->servername));
+ else if (HostNameLookups || RemotePort)
+ httpAddrLookup(&temp, con->servername, sizeof(con->servername));
+ else
+ httpAddrString(&temp, con->servername, sizeof(con->servername));
+
+ con->serverport = _httpAddrPort(&(lis->address));
+ }
+
+ cupsArrayAdd(Clients, con);
+
+ /*
+ * Using TCP_NODELAY improves responsiveness, especially on systems with a slow
+ * loopback interface. Since we write large buffers when sending print files
+ * and requests there shouldn't be any performance penalty for this...
+ */
+
+ val = 1;
+ setsockopt(con->http.fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+
+ /*
+ * Close this file on all execs...
+ */
+
+ fcntl(con->http.fd, F_SETFD, fcntl(con->http.fd, F_GETFD) | FD_CLOEXEC);
+
+ /*
+ * Add the socket to the server select.
+ */
+
+ cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con);
+
+ /*
+ * Temporarily suspend accept()'s until we lose a client...
+ */
+
+ if (cupsArrayCount(Clients) == MaxClients)
+ cupsdPauseListening();
+
+#ifdef HAVE_SSL
+ /*
+ * See if we are connecting on a secure port...
+ */
+
+ if (lis->encryption == HTTP_ENCRYPT_ALWAYS)
+ {
+ /*
+ * https connection; go secure...
+ */
+
+ con->http.encryption = HTTP_ENCRYPT_ALWAYS;
+
+ if (!encrypt_client(con))
+ cupsdCloseClient(con);
+ }
+ else
+ con->auto_ssl = 1;
+#endif /* HAVE_SSL */
+}
+
+
+/*
+ * 'cupsdCloseAllClients()' - Close all remote clients immediately.
+ */
+
+void
+cupsdCloseAllClients(void)
+{
+ cupsd_client_t *con; /* Current client */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCloseAllClients() Clients=%d",
+ cupsArrayCount(Clients));
+
+ for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
+ con;
+ con = (cupsd_client_t *)cupsArrayNext(Clients))
+ if (cupsdCloseClient(con))
+ cupsdCloseClient(con);
+}
+
+
+/*
+ * 'cupsdCloseClient()' - Close a remote client.
+ */
+
+int /* O - 1 if partial close, 0 if fully closed */
+cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */
+{
+ int partial; /* Do partial close for SSL? */
+#ifdef HAVE_LIBSSL
+ SSL_CTX *context; /* Context for encryption */
+ unsigned long error; /* Error code */
+#elif defined(HAVE_GNUTLS)
+ int error; /* Error code */
+ gnutls_certificate_server_credentials *credentials;
+ /* TLS credentials */
+# elif defined(HAVE_CDSASSL)
+#endif /* HAVE_LIBSSL */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdCloseClient: %d", con->http.fd);
+
+ /*
+ * Flush pending writes before closing...
+ */
+
+ httpFlushWrite(HTTP(con));
+
+ partial = 0;
+
+#ifdef HAVE_SSL
+ /*
+ * Shutdown encryption as needed...
+ */
+
+ if (con->http.tls)
+ {
+ partial = 1;
+
+# ifdef HAVE_LIBSSL
+ context = SSL_get_SSL_CTX(con->http.tls);
+
+ switch (SSL_shutdown(con->http.tls))
+ {
+ case 1 :
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "SSL shutdown successful!");
+ break;
+ case -1 :
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Fatal error during SSL shutdown!");
+ default :
+ while ((error = ERR_get_error()) != 0)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "SSL shutdown failed: %s",
+ ERR_error_string(error, NULL));
+ break;
+ }
+
+ SSL_CTX_free(context);
+ SSL_free(con->http.tls);
+
+# elif defined(HAVE_GNUTLS)
+ credentials = (gnutls_certificate_server_credentials *)(con->http.tls_credentials);
+
+ error = gnutls_bye(con->http.tls, GNUTLS_SHUT_WR);
+ switch (error)
+ {
+ case GNUTLS_E_SUCCESS:
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "SSL shutdown successful!");
+ break;
+ default:
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "SSL shutdown failed: %s", gnutls_strerror(error));
+ break;
+ }
+
+ gnutls_deinit(con->http.tls);
+ gnutls_certificate_free_credentials(*credentials);
+ free(credentials);
+
+# elif defined(HAVE_CDSASSL)
+ while (SSLClose(con->http.tls) == errSSLWouldBlock)
+ usleep(1000);
+
+ SSLDisposeContext(con->http.tls);
+
+ if (con->http.tls_credentials)
+ CFRelease(con->http.tls_credentials);
+
+# endif /* HAVE_LIBSSL */
+
+ con->http.tls = NULL;
+ }
+#endif /* HAVE_SSL */
+
+ if (con->pipe_pid != 0)
+ {
+ /*
+ * Stop any CGI process...
+ */
+
+ cupsdEndProcess(con->pipe_pid, 1);
+ con->pipe_pid = 0;
+ }
+
+ if (con->file >= 0)
+ {
+ cupsdRemoveSelect(con->file);
+
+ close(con->file);
+ con->file = -1;
+ }
+
+ /*
+ * Close the socket and clear the file from the input set for select()...
+ */
+
+ if (con->http.fd >= 0)
+ {
+ cupsArrayRemove(ActiveClients, con);
+ cupsdSetBusyState();
+
+ if (partial)
+ {
+ /*
+ * Only do a partial close so that the encrypted client gets everything.
+ */
+
+ shutdown(con->http.fd, 0);
+ cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con);
+ }
+ else
+ {
+ /*
+ * Shut the socket down fully...
+ */
+
+ cupsdRemoveSelect(con->http.fd);
+ close(con->http.fd);
+ con->http.fd = -1;
+ }
+ }
+
+ if (!partial)
+ {
+ /*
+ * Free memory...
+ */
+
+ if (con->http.input_set)
+ free(con->http.input_set);
+
+ httpClearCookie(HTTP(con));
+ httpClearFields(HTTP(con));
+
+ cupsdClearString(&con->filename);
+ cupsdClearString(&con->command);
+ cupsdClearString(&con->options);
+ cupsdClearString(&con->query_string);
+
+ if (con->request)
+ {
+ ippDelete(con->request);
+ con->request = NULL;
+ }
+
+ if (con->response)
+ {
+ ippDelete(con->response);
+ con->response = NULL;
+ }
+
+ if (con->language)
+ {
+ cupsLangFree(con->language);
+ con->language = NULL;
+ }
+
+#ifdef HAVE_AUTHORIZATION_H
+ if (con->authref)
+ {
+ AuthorizationFree(con->authref, kAuthorizationFlagDefaults);
+ con->authref = NULL;
+ }
+#endif /* HAVE_AUTHORIZATION_H */
+
+ /*
+ * Re-enable new client connections if we are going back under the
+ * limit...
+ */
+
+ if (cupsArrayCount(Clients) == MaxClients)
+ cupsdResumeListening();
+
+ /*
+ * Compact the list of clients as necessary...
+ */
+
+ cupsArrayRemove(Clients, con);
+
+ free(con);
+ }
+
+ return (partial);
+}
+
+
+/*
+ * 'cupsdFlushHeader()' - Flush the header fields to the client.
+ */
+
+int /* I - Bytes written or -1 on error */
+cupsdFlushHeader(cupsd_client_t *con) /* I - Client to flush to */
+{
+ int bytes = httpFlushWrite(HTTP(con));
+
+ con->http.data_encoding = HTTP_ENCODE_LENGTH;
+
+ return (bytes);
+}
+
+
+/*
+ * 'cupsdReadClient()' - Read data from a client.
+ */
+
+void
+cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */
+{
+ char line[32768], /* Line from client... */
+ operation[64], /* Operation code from socket */
+ version[64], /* HTTP version number string */
+ locale[64], /* Locale */
+ *ptr; /* Pointer into strings */
+ int major, minor; /* HTTP version numbers */
+ http_status_t status; /* Transfer status */
+ ipp_state_t ipp_state; /* State of IPP transfer */
+ int bytes; /* Number of bytes to POST */
+ char *filename; /* Name of file for GET/HEAD */
+ char buf[1024]; /* Buffer for real filename */
+ struct stat filestats; /* File information */
+ mime_type_t *type; /* MIME type of file */
+ cupsd_printer_t *p; /* Printer */
+ static unsigned request_id = 0; /* Request ID for temp files */
+
+
+ status = HTTP_CONTINUE;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdReadClient(con=%p(%d)) "
+ "con->http.error=%d "
+ "con->http.used=%d, "
+ "con->http.state=%d "
+ "con->data_encoding=HTTP_ENCODE_%s, "
+ "con->data_remaining=" CUPS_LLFMT ", "
+ "con->file=%d",
+ con, con->http.fd, con->http.error, con->http.used,
+ con->http.state,
+ con->http.data_encoding == HTTP_ENCODE_CHUNKED ?
+ "CHUNKED" : "LENGTH",
+ CUPS_LLCAST con->http.data_remaining, con->file);
+
+#ifdef HAVE_SSL
+ if (con->auto_ssl)
+ {
+ /*
+ * Automatically check for a SSL/TLS handshake...
+ */
+
+ con->auto_ssl = 0;
+
+ if (recv(con->http.fd, buf, 1, MSG_PEEK) == 1 &&
+ (!buf[0] || !strchr("DGHOPT", buf[0])))
+ {
+ /*
+ * Encrypt this connection...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdReadClient: Saw first byte %02X, auto-negotiating "
+ "SSL/TLS session...", buf[0] & 255);
+
+ if (!encrypt_client(con))
+ cupsdCloseClient(con);
+
+ return;
+ }
+ }
+#endif /* HAVE_SSL */
+
+ switch (con->http.state)
+ {
+ case HTTP_WAITING :
+ /*
+ * See if we've received a request line...
+ */
+
+ if (httpGets(line, sizeof(line) - 1, HTTP(con)) == NULL)
+ {
+ if (con->http.error && con->http.error != EPIPE)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d WAITING Closing for error %d "
+ "(%s)", con->http.fd, con->http.error,
+ strerror(con->http.error));
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d WAITING Closing on EOF",
+ con->http.fd);
+
+ cupsdCloseClient(con);
+ return;
+ }
+
+ /*
+ * Ignore blank request lines...
+ */
+
+ if (line[0] == '\0')
+ break;
+
+ /*
+ * Clear other state variables...
+ */
+
+ httpClearFields(HTTP(con));
+
+ con->http.activity = time(NULL);
+ con->http.version = HTTP_1_0;
+ con->http.keep_alive = HTTP_KEEPALIVE_OFF;
+ con->http.data_encoding = HTTP_ENCODE_LENGTH;
+ con->http.data_remaining = 0;
+ con->http._data_remaining = 0;
+ con->operation = HTTP_WAITING;
+ con->bytes = 0;
+ con->file = -1;
+ con->file_ready = 0;
+ con->pipe_pid = 0;
+ con->username[0] = '\0';
+ con->password[0] = '\0';
+ con->uri[0] = '\0';
+
+ cupsdClearString(&con->command);
+ cupsdClearString(&con->options);
+ cupsdClearString(&con->query_string);
+
+ if (con->request)
+ {
+ ippDelete(con->request);
+ con->request = NULL;
+ }
+
+ if (con->response)
+ {
+ ippDelete(con->response);
+ con->response = NULL;
+ }
+
+ if (con->language)
+ {
+ cupsLangFree(con->language);
+ con->language = NULL;
+ }
+
+#ifdef HAVE_GSSAPI
+ con->have_gss = 0;
+ con->gss_uid = 0;
+#endif /* HAVE_GSSAPI */
+
+ /*
+ * Grab the request line...
+ */
+
+ switch (sscanf(line, "%63s%1023s%63s", operation, con->uri, version))
+ {
+ case 1 :
+ if (line[0])
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad request line \"%s\" from %s!",
+ _httpEncodeURI(buf, line, sizeof(buf)),
+ con->http.hostname);
+ cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
+ cupsdCloseClient(con);
+ }
+ return;
+ case 2 :
+ con->http.version = HTTP_0_9;
+ break;
+ case 3 :
+ if (sscanf(version, "HTTP/%d.%d", &major, &minor) != 2)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad request line \"%s\" from %s!",
+ _httpEncodeURI(buf, line, sizeof(buf)),
+ con->http.hostname);
+ cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
+ cupsdCloseClient(con);
+ return;
+ }
+
+ if (major < 2)
+ {
+ con->http.version = (http_version_t)(major * 100 + minor);
+ if (con->http.version == HTTP_1_1 && KeepAlive)
+ con->http.keep_alive = HTTP_KEEPALIVE_ON;
+ else
+ con->http.keep_alive = HTTP_KEEPALIVE_OFF;
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unsupported request line \"%s\" from %s!",
+ _httpEncodeURI(buf, line, sizeof(buf)),
+ con->http.hostname);
+ cupsdSendError(con, HTTP_NOT_SUPPORTED, CUPSD_AUTH_NONE);
+ cupsdCloseClient(con);
+ return;
+ }
+ break;
+ }
+
+ /*
+ * Handle full URLs in the request line...
+ */
+
+ if (strcmp(con->uri, "*"))
+ {
+ char scheme[HTTP_MAX_URI], /* Method/scheme */
+ userpass[HTTP_MAX_URI], /* Username:password */
+ hostname[HTTP_MAX_URI], /* Hostname */
+ resource[HTTP_MAX_URI]; /* Resource path */
+ int port; /* Port number */
+
+
+ /*
+ * Separate the URI into its components...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_MOST, con->uri,
+ scheme, sizeof(scheme),
+ userpass, sizeof(userpass),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(resource));
+
+ /*
+ * Only allow URIs with the servername, localhost, or an IP
+ * address...
+ */
+
+ if (strcmp(scheme, "file") &&
+ _cups_strcasecmp(hostname, ServerName) &&
+ _cups_strcasecmp(hostname, "localhost") &&
+ !isdigit(hostname[0]) && hostname[0] != '[')
+ {
+ /*
+ * Nope, we don't do proxies...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad URI \"%s\" in request!",
+ con->uri);
+ cupsdSendError(con, HTTP_METHOD_NOT_ALLOWED, CUPSD_AUTH_NONE);
+ cupsdCloseClient(con);
+ return;
+ }
+
+ /*
+ * Copy the resource portion back into the URI; both resource and
+ * con->uri are HTTP_MAX_URI bytes in size...
+ */
+
+ strcpy(con->uri, resource);
+ }
+
+ /*
+ * Process the request...
+ */
+
+ if (!strcmp(operation, "GET"))
+ con->http.state = HTTP_GET;
+ else if (!strcmp(operation, "PUT"))
+ con->http.state = HTTP_PUT;
+ else if (!strcmp(operation, "POST"))
+ con->http.state = HTTP_POST;
+ else if (!strcmp(operation, "DELETE"))
+ con->http.state = HTTP_DELETE;
+ else if (!strcmp(operation, "TRACE"))
+ con->http.state = HTTP_TRACE;
+ else if (!strcmp(operation, "OPTIONS"))
+ con->http.state = HTTP_OPTIONS;
+ else if (!strcmp(operation, "HEAD"))
+ con->http.state = HTTP_HEAD;
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad operation \"%s\"!", operation);
+ cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
+ cupsdCloseClient(con);
+ return;
+ }
+
+ gettimeofday(&(con->start), NULL);
+ con->operation = con->http.state;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdReadClient: %d %s %s HTTP/%d.%d",
+ con->http.fd, operation, con->uri,
+ con->http.version / 100, con->http.version % 100);
+
+ con->http.status = HTTP_OK;
+
+ if (!cupsArrayFind(ActiveClients, con))
+ {
+ cupsArrayAdd(ActiveClients, con);
+ cupsdSetBusyState();
+ }
+
+ case HTTP_OPTIONS :
+ case HTTP_DELETE :
+ case HTTP_GET :
+ case HTTP_HEAD :
+ case HTTP_POST :
+ case HTTP_PUT :
+ case HTTP_TRACE :
+ /*
+ * Parse incoming parameters until the status changes...
+ */
+
+ while ((status = httpUpdate(HTTP(con))) == HTTP_CONTINUE)
+ if (!data_ready(con))
+ break;
+
+ if (status != HTTP_OK && status != HTTP_CONTINUE)
+ {
+ if (con->http.error && con->http.error != EPIPE)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d FIELDS Closing for error %d "
+ "(%s)", con->http.fd, con->http.error,
+ strerror(con->http.error));
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d FIELDS Closing on EOF",
+ con->http.fd);
+
+ cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
+ cupsdCloseClient(con);
+ return;
+ }
+ break;
+
+ default :
+ if (!data_ready(con) && recv(con->http.fd, buf, 1, MSG_PEEK) < 1)
+ {
+ /*
+ * Connection closed...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d Closing on EOF", con->http.fd);
+ cupsdCloseClient(con);
+ return;
+ }
+ break; /* Anti-compiler-warning-code */
+ }
+
+ /*
+ * Handle new transfers...
+ */
+
+ if (status == HTTP_OK)
+ {
+ if (con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE][0])
+ {
+ /*
+ * Figure out the locale from the Accept-Language and Content-Type
+ * fields...
+ */
+
+ if ((ptr = strchr(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE],
+ ',')) != NULL)
+ *ptr = '\0';
+
+ if ((ptr = strchr(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE],
+ ';')) != NULL)
+ *ptr = '\0';
+
+ if ((ptr = strstr(con->http.fields[HTTP_FIELD_CONTENT_TYPE],
+ "charset=")) != NULL)
+ {
+ /*
+ * Combine language and charset, and trim any extra params in the
+ * content-type.
+ */
+
+ snprintf(locale, sizeof(locale), "%s.%s",
+ con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE], ptr + 8);
+
+ if ((ptr = strchr(locale, ',')) != NULL)
+ *ptr = '\0';
+ }
+ else
+ snprintf(locale, sizeof(locale), "%s.UTF-8",
+ con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE]);
+
+ con->language = cupsLangGet(locale);
+ }
+ else
+ con->language = cupsLangGet(DefaultLocale);
+
+ cupsdAuthorize(con);
+
+ if (!_cups_strncasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Keep-Alive",
+ 10) && KeepAlive)
+ con->http.keep_alive = HTTP_KEEPALIVE_ON;
+ else if (!_cups_strncasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "close", 5))
+ con->http.keep_alive = HTTP_KEEPALIVE_OFF;
+
+ if (!con->http.fields[HTTP_FIELD_HOST][0] &&
+ con->http.version >= HTTP_1_1)
+ {
+ /*
+ * HTTP/1.1 and higher require the "Host:" field...
+ */
+
+ if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Missing Host: field in request!");
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ else if (!valid_host(con))
+ {
+ /*
+ * Access to localhost must use "localhost" or the corresponding IPv4
+ * or IPv6 values in the Host: field.
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Request from \"%s\" using invalid Host: field \"%s\"",
+ con->http.hostname, con->http.fields[HTTP_FIELD_HOST]);
+
+ if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ else if (con->operation == HTTP_OPTIONS)
+ {
+ /*
+ * Do OPTIONS command...
+ */
+
+ if (con->best && con->best->type != CUPSD_AUTH_NONE)
+ {
+ if (!cupsdSendHeader(con, HTTP_UNAUTHORIZED, NULL, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+
+ if (!_cups_strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") &&
+ con->http.tls == NULL)
+ {
+#ifdef HAVE_SSL
+ /*
+ * Do encryption stuff...
+ */
+
+ if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
+ httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
+ httpPrintf(HTTP(con), "Content-Length: 0\r\n");
+ httpPrintf(HTTP(con), "\r\n");
+
+ if (cupsdFlushHeader(con) < 0)
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ if (!encrypt_client(con))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+#else
+ if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+#endif /* HAVE_SSL */
+ }
+
+ if (!cupsdSendHeader(con, HTTP_OK, NULL, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST, PUT\r\n");
+ httpPrintf(HTTP(con), "Content-Length: 0\r\n");
+ httpPrintf(HTTP(con), "\r\n");
+
+ if (cupsdFlushHeader(con) < 0)
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ else if (!is_path_absolute(con->uri))
+ {
+ /*
+ * Protect against malicious users!
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Request for non-absolute resource \"%s\"!", con->uri);
+
+ if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ else
+ {
+ if (!_cups_strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") &&
+ con->http.tls == NULL)
+ {
+#ifdef HAVE_SSL
+ /*
+ * Do encryption stuff...
+ */
+
+ if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
+ httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
+ httpPrintf(HTTP(con), "Content-Length: 0\r\n");
+ httpPrintf(HTTP(con), "\r\n");
+
+ if (cupsdFlushHeader(con) < 0)
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ if (!encrypt_client(con))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+#else
+ if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+#endif /* HAVE_SSL */
+ }
+
+ if ((status = cupsdIsAuthorized(con, NULL)) != HTTP_OK)
+ {
+ cupsdSendError(con, status, CUPSD_AUTH_NONE);
+ cupsdCloseClient(con);
+ return;
+ }
+
+ if (con->http.expect &&
+ (con->operation == HTTP_POST || con->operation == HTTP_PUT))
+ {
+ if (con->http.expect == HTTP_CONTINUE)
+ {
+ /*
+ * Send 100-continue header...
+ */
+
+ if (!cupsdSendHeader(con, HTTP_CONTINUE, NULL, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ else
+ {
+ /*
+ * Send 417-expectation-failed header...
+ */
+
+ if (!cupsdSendHeader(con, HTTP_EXPECTATION_FAILED, NULL,
+ CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ httpPrintf(HTTP(con), "Content-Length: 0\r\n");
+ httpPrintf(HTTP(con), "\r\n");
+
+ if (cupsdFlushHeader(con) < 0)
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ }
+
+ switch (con->http.state)
+ {
+ case HTTP_GET_SEND :
+ if (!strncmp(con->uri, "/printers/", 10) &&
+ !strcmp(con->uri + strlen(con->uri) - 4, ".ppd"))
+ {
+ /*
+ * Send PPD file - get the real printer name since printer
+ * names are not case sensitive but filenames can be...
+ */
+
+ con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".ppd" */
+
+ if ((p = cupsdFindPrinter(con->uri + 10)) != NULL)
+ snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name);
+ else
+ {
+ if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+ }
+ else if ((!strncmp(con->uri, "/printers/", 10) ||
+ !strncmp(con->uri, "/classes/", 9)) &&
+ !strcmp(con->uri + strlen(con->uri) - 4, ".png"))
+ {
+ /*
+ * Send icon file - get the real queue name since queue names are
+ * not case sensitive but filenames can be...
+ */
+
+ con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".png" */
+
+ if (!strncmp(con->uri, "/printers/", 10))
+ p = cupsdFindPrinter(con->uri + 10);
+ else
+ p = cupsdFindClass(con->uri + 9);
+
+ if (p)
+ snprintf(con->uri, sizeof(con->uri), "/icons/%s.png", p->name);
+ else
+ {
+ if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+ }
+ else if (!WebInterface)
+ {
+ /*
+ * Web interface is disabled. Show an appropriate message...
+ */
+
+ if (!cupsdSendError(con, HTTP_WEBIF_DISABLED, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+
+ if ((!strncmp(con->uri, "/admin", 6) &&
+ strncmp(con->uri, "/admin/conf/", 12) &&
+ strncmp(con->uri, "/admin/log/", 11)) ||
+ !strncmp(con->uri, "/printers", 9) ||
+ !strncmp(con->uri, "/classes", 8) ||
+ !strncmp(con->uri, "/help", 5) ||
+ !strncmp(con->uri, "/jobs", 5))
+ {
+ /*
+ * Send CGI output...
+ */
+
+ if (!strncmp(con->uri, "/admin", 6))
+ {
+ cupsdSetStringf(&con->command, "%s/cgi-bin/admin.cgi",
+ ServerBin);
+
+ cupsdSetString(&con->options, strchr(con->uri + 6, '?'));
+ }
+ else if (!strncmp(con->uri, "/printers", 9))
+ {
+ cupsdSetStringf(&con->command, "%s/cgi-bin/printers.cgi",
+ ServerBin);
+
+ if (con->uri[9] && con->uri[10])
+ cupsdSetString(&con->options, con->uri + 9);
+ else
+ cupsdSetString(&con->options, NULL);
+ }
+ else if (!strncmp(con->uri, "/classes", 8))
+ {
+ cupsdSetStringf(&con->command, "%s/cgi-bin/classes.cgi",
+ ServerBin);
+
+ if (con->uri[8] && con->uri[9])
+ cupsdSetString(&con->options, con->uri + 8);
+ else
+ cupsdSetString(&con->options, NULL);
+ }
+ else if (!strncmp(con->uri, "/jobs", 5))
+ {
+ cupsdSetStringf(&con->command, "%s/cgi-bin/jobs.cgi",
+ ServerBin);
+
+ if (con->uri[5] && con->uri[6])
+ cupsdSetString(&con->options, con->uri + 5);
+ else
+ cupsdSetString(&con->options, NULL);
+ }
+ else
+ {
+ cupsdSetStringf(&con->command, "%s/cgi-bin/help.cgi",
+ ServerBin);
+
+ if (con->uri[5] && con->uri[6])
+ cupsdSetString(&con->options, con->uri + 5);
+ else
+ cupsdSetString(&con->options, NULL);
+ }
+
+ if (!cupsdSendCommand(con, con->command, con->options, 0))
+ {
+ if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ else
+ cupsdLogRequest(con, HTTP_OK);
+
+ if (con->http.version <= HTTP_1_0)
+ con->http.keep_alive = HTTP_KEEPALIVE_OFF;
+ }
+ else if ((!strncmp(con->uri, "/admin/conf/", 12) &&
+ (strchr(con->uri + 12, '/') ||
+ strlen(con->uri) == 12)) ||
+ (!strncmp(con->uri, "/admin/log/", 11) &&
+ (strchr(con->uri + 11, '/') ||
+ strlen(con->uri) == 11)))
+ {
+ /*
+ * GET can only be done to configuration files directly under
+ * /admin/conf...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Request for subdirectory \"%s\"!", con->uri);
+
+ if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+ else
+ {
+ /*
+ * Serve a file...
+ */
+
+ if ((filename = get_file(con, &filestats, buf,
+ sizeof(buf))) == NULL)
+ {
+ if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+
+ type = mimeFileType(MimeDatabase, filename, NULL, NULL);
+
+ if (is_cgi(con, filename, &filestats, type))
+ {
+ /*
+ * Note: con->command and con->options were set by
+ * is_cgi()...
+ */
+
+ if (!cupsdSendCommand(con, con->command, con->options, 0))
+ {
+ if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ else
+ cupsdLogRequest(con, HTTP_OK);
+
+ if (con->http.version <= HTTP_1_0)
+ con->http.keep_alive = HTTP_KEEPALIVE_OFF;
+ break;
+ }
+
+ if (!check_if_modified(con, &filestats))
+ {
+ if (!cupsdSendError(con, HTTP_NOT_MODIFIED, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ else
+ {
+ if (type == NULL)
+ strcpy(line, "text/plain");
+ else
+ snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
+
+ if (!write_file(con, HTTP_OK, filename, line, &filestats))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ }
+ break;
+
+ case HTTP_POST_RECV :
+ /*
+ * See if the POST request includes a Content-Length field, and if
+ * so check the length against any limits that are set...
+ */
+
+ if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
+ MaxRequestSize > 0 &&
+ con->http.data_remaining > MaxRequestSize)
+ {
+ /*
+ * Request too large...
+ */
+
+ if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+ else if (con->http.data_remaining < 0 ||
+ (!con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
+ con->http.data_encoding == HTTP_ENCODE_LENGTH))
+ {
+ /*
+ * Negative content lengths are invalid!
+ */
+
+ if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+
+ /*
+ * See what kind of POST request this is; for IPP requests the
+ * content-type field will be "application/ipp"...
+ */
+
+ if (!strcmp(con->http.fields[HTTP_FIELD_CONTENT_TYPE],
+ "application/ipp"))
+ con->request = ippNew();
+ else if (!WebInterface)
+ {
+ /*
+ * Web interface is disabled. Show an appropriate message...
+ */
+
+ if (!cupsdSendError(con, HTTP_WEBIF_DISABLED, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+ else if ((!strncmp(con->uri, "/admin", 6) &&
+ strncmp(con->uri, "/admin/conf/", 12) &&
+ strncmp(con->uri, "/admin/log/", 11)) ||
+ !strncmp(con->uri, "/printers", 9) ||
+ !strncmp(con->uri, "/classes", 8) ||
+ !strncmp(con->uri, "/help", 5) ||
+ !strncmp(con->uri, "/jobs", 5))
+ {
+ /*
+ * CGI request...
+ */
+
+ if (!strncmp(con->uri, "/admin", 6))
+ {
+ cupsdSetStringf(&con->command, "%s/cgi-bin/admin.cgi",
+ ServerBin);
+
+ cupsdSetString(&con->options, strchr(con->uri + 6, '?'));
+ }
+ else if (!strncmp(con->uri, "/printers", 9))
+ {
+ cupsdSetStringf(&con->command, "%s/cgi-bin/printers.cgi",
+ ServerBin);
+
+ if (con->uri[9] && con->uri[10])
+ cupsdSetString(&con->options, con->uri + 9);
+ else
+ cupsdSetString(&con->options, NULL);
+ }
+ else if (!strncmp(con->uri, "/classes", 8))
+ {
+ cupsdSetStringf(&con->command, "%s/cgi-bin/classes.cgi",
+ ServerBin);
+
+ if (con->uri[8] && con->uri[9])
+ cupsdSetString(&con->options, con->uri + 8);
+ else
+ cupsdSetString(&con->options, NULL);
+ }
+ else if (!strncmp(con->uri, "/jobs", 5))
+ {
+ cupsdSetStringf(&con->command, "%s/cgi-bin/jobs.cgi",
+ ServerBin);
+
+ if (con->uri[5] && con->uri[6])
+ cupsdSetString(&con->options, con->uri + 5);
+ else
+ cupsdSetString(&con->options, NULL);
+ }
+ else
+ {
+ cupsdSetStringf(&con->command, "%s/cgi-bin/help.cgi",
+ ServerBin);
+
+ if (con->uri[5] && con->uri[6])
+ cupsdSetString(&con->options, con->uri + 5);
+ else
+ cupsdSetString(&con->options, NULL);
+ }
+
+ if (con->http.version <= HTTP_1_0)
+ con->http.keep_alive = HTTP_KEEPALIVE_OFF;
+ }
+ else
+ {
+ /*
+ * POST to a file...
+ */
+
+ if ((filename = get_file(con, &filestats, buf,
+ sizeof(buf))) == NULL)
+ {
+ if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+
+ type = mimeFileType(MimeDatabase, filename, NULL, NULL);
+
+ if (!is_cgi(con, filename, &filestats, type))
+ {
+ /*
+ * Only POST to CGI's...
+ */
+
+ if (!cupsdSendError(con, HTTP_UNAUTHORIZED, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ }
+ break;
+
+ case HTTP_PUT_RECV :
+ /*
+ * Validate the resource name...
+ */
+
+ if (strncmp(con->uri, "/admin/conf/", 12) ||
+ strchr(con->uri + 12, '/') ||
+ strlen(con->uri) == 12)
+ {
+ /*
+ * PUT can only be done to configuration files under
+ * /admin/conf...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Request for subdirectory \"%s\"!", con->uri);
+
+ if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+
+ /*
+ * See if the PUT request includes a Content-Length field, and if
+ * so check the length against any limits that are set...
+ */
+
+ if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
+ MaxRequestSize > 0 &&
+ con->http.data_remaining > MaxRequestSize)
+ {
+ /*
+ * Request too large...
+ */
+
+ if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+ else if (con->http.data_remaining < 0)
+ {
+ /*
+ * Negative content lengths are invalid!
+ */
+
+ if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+
+ /*
+ * Open a temporary file to hold the request...
+ */
+
+ cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot,
+ request_id ++);
+ con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
+
+ if (con->file < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create request file %s: %s",
+ con->filename, strerror(errno));
+
+ if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+
+ fchmod(con->file, 0640);
+ fchown(con->file, RunUser, Group);
+ fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+ break;
+
+ case HTTP_DELETE :
+ case HTTP_TRACE :
+ cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE);
+ cupsdCloseClient(con);
+ return;
+
+ case HTTP_HEAD :
+ if (!strncmp(con->uri, "/printers/", 10) &&
+ !strcmp(con->uri + strlen(con->uri) - 4, ".ppd"))
+ {
+ /*
+ * Send PPD file - get the real printer name since printer
+ * names are not case sensitive but filenames can be...
+ */
+
+ con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".ppd" */
+
+ if ((p = cupsdFindPrinter(con->uri + 10)) != NULL)
+ snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name);
+ else
+ {
+ if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+ }
+ else if (!strncmp(con->uri, "/printers/", 10) &&
+ !strcmp(con->uri + strlen(con->uri) - 4, ".png"))
+ {
+ /*
+ * Send PNG file - get the real printer name since printer
+ * names are not case sensitive but filenames can be...
+ */
+
+ con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".ppd" */
+
+ if ((p = cupsdFindPrinter(con->uri + 10)) != NULL)
+ snprintf(con->uri, sizeof(con->uri), "/icons/%s.png", p->name);
+ else
+ {
+ if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+ }
+ else if (!WebInterface)
+ {
+ if (!cupsdSendHeader(con, HTTP_OK, line, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ if (httpPrintf(HTTP(con), "\r\n") < 0)
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ if (cupsdFlushHeader(con) < 0)
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ con->http.state = HTTP_WAITING;
+ break;
+ }
+
+ if ((!strncmp(con->uri, "/admin", 6) &&
+ strncmp(con->uri, "/admin/conf/", 12) &&
+ strncmp(con->uri, "/admin/log/", 11)) ||
+ !strncmp(con->uri, "/printers", 9) ||
+ !strncmp(con->uri, "/classes", 8) ||
+ !strncmp(con->uri, "/help", 5) ||
+ !strncmp(con->uri, "/jobs", 5))
+ {
+ /*
+ * CGI output...
+ */
+
+ if (!cupsdSendHeader(con, HTTP_OK, "text/html", CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ if (httpPrintf(HTTP(con), "\r\n") < 0)
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ if (cupsdFlushHeader(con) < 0)
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ cupsdLogRequest(con, HTTP_OK);
+ }
+ else if ((!strncmp(con->uri, "/admin/conf/", 12) &&
+ (strchr(con->uri + 12, '/') ||
+ strlen(con->uri) == 12)) ||
+ (!strncmp(con->uri, "/admin/log/", 11) &&
+ (strchr(con->uri + 11, '/') ||
+ strlen(con->uri) == 11)))
+ {
+ /*
+ * HEAD can only be done to configuration files under
+ * /admin/conf...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Request for subdirectory \"%s\"!", con->uri);
+
+ if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+ else if ((filename = get_file(con, &filestats, buf,
+ sizeof(buf))) == NULL)
+ {
+ if (!cupsdSendHeader(con, HTTP_NOT_FOUND, "text/html",
+ CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ cupsdLogRequest(con, HTTP_NOT_FOUND);
+ }
+ else if (!check_if_modified(con, &filestats))
+ {
+ if (!cupsdSendError(con, HTTP_NOT_MODIFIED, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ cupsdLogRequest(con, HTTP_NOT_MODIFIED);
+ }
+ else
+ {
+ /*
+ * Serve a file...
+ */
+
+ type = mimeFileType(MimeDatabase, filename, NULL, NULL);
+ if (type == NULL)
+ strcpy(line, "text/plain");
+ else
+ snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
+
+ if (!cupsdSendHeader(con, HTTP_OK, line, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n",
+ httpGetDateString(filestats.st_mtime)) < 0)
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n",
+ (unsigned long)filestats.st_size) < 0)
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ cupsdLogRequest(con, HTTP_OK);
+ }
+
+ if (httpPrintf(HTTP(con), "\r\n") < 0)
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ if (cupsdFlushHeader(con) < 0)
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ con->http.state = HTTP_WAITING;
+ break;
+
+ default :
+ break; /* Anti-compiler-warning-code */
+ }
+ }
+ }
+
+ /*
+ * Handle any incoming data...
+ */
+
+ switch (con->http.state)
+ {
+ case HTTP_PUT_RECV :
+ do
+ {
+ if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
+ {
+ if (con->http.error && con->http.error != EPIPE)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d PUT_RECV Closing for error "
+ "%d (%s)", con->http.fd, con->http.error,
+ strerror(con->http.error));
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d PUT_RECV Closing on EOF",
+ con->http.fd);
+
+ cupsdCloseClient(con);
+ return;
+ }
+ else if (bytes > 0)
+ {
+ con->bytes += bytes;
+
+ if (write(con->file, line, bytes) < bytes)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdReadClient: Unable to write %d bytes to %s: %s",
+ bytes, con->filename, strerror(errno));
+
+ close(con->file);
+ con->file = -1;
+ unlink(con->filename);
+ cupsdClearString(&con->filename);
+
+ if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ }
+ }
+ while (con->http.state == HTTP_PUT_RECV && data_ready(con));
+
+ if (con->http.state == HTTP_WAITING)
+ {
+ /*
+ * End of file, see how big it is...
+ */
+
+ fstat(con->file, &filestats);
+
+ close(con->file);
+ con->file = -1;
+
+ if (filestats.st_size > MaxRequestSize &&
+ MaxRequestSize > 0)
+ {
+ /*
+ * Request is too big; remove it and send an error...
+ */
+
+ unlink(con->filename);
+ cupsdClearString(&con->filename);
+
+ if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+
+ /*
+ * Install the configuration file...
+ */
+
+ status = install_conf_file(con);
+
+ /*
+ * Return the status to the client...
+ */
+
+ if (!cupsdSendError(con, status, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ break;
+
+ case HTTP_POST_RECV :
+ do
+ {
+ if (con->request && con->file < 0)
+ {
+ /*
+ * Grab any request data from the connection...
+ */
+
+ if ((ipp_state = ippRead(&(con->http), con->request)) == IPP_ERROR)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdReadClient: %d IPP Read Error!",
+ con->http.fd);
+
+ cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
+ cupsdCloseClient(con);
+ return;
+ }
+ else if (ipp_state != IPP_DATA)
+ {
+ if (con->http.state == HTTP_POST_SEND)
+ {
+ cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
+ cupsdCloseClient(con);
+ return;
+ }
+
+ break;
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdReadClient: %d %d.%d %s %d",
+ con->http.fd, con->request->request.op.version[0],
+ con->request->request.op.version[1],
+ ippOpString(con->request->request.op.operation_id),
+ con->request->request.op.request_id);
+ con->bytes += ippLength(con->request);
+ }
+ }
+
+ if (con->file < 0 && con->http.state != HTTP_POST_SEND)
+ {
+ /*
+ * Create a file as needed for the request data...
+ */
+
+ cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot,
+ request_id ++);
+ con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
+
+ if (con->file < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create request file %s: %s",
+ con->filename, strerror(errno));
+
+ if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+
+ fchmod(con->file, 0640);
+ fchown(con->file, RunUser, Group);
+ fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+ }
+
+ if (con->http.state != HTTP_POST_SEND)
+ {
+ if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
+ {
+ if (con->http.error && con->http.error != EPIPE)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d POST_SEND Closing for "
+ "error %d (%s)", con->http.fd, con->http.error,
+ strerror(con->http.error));
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d POST_SEND Closing on EOF",
+ con->http.fd);
+
+ cupsdCloseClient(con);
+ return;
+ }
+ else if (bytes > 0)
+ {
+ con->bytes += bytes;
+
+ if (write(con->file, line, bytes) < bytes)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdReadClient: Unable to write %d bytes to "
+ "%s: %s", bytes, con->filename,
+ strerror(errno));
+
+ close(con->file);
+ con->file = -1;
+ unlink(con->filename);
+ cupsdClearString(&con->filename);
+
+ if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE,
+ CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ }
+ else if (con->http.state == HTTP_POST_RECV)
+ return;
+ else if (con->http.state != HTTP_POST_SEND)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d Closing on unknown HTTP "
+ "state %d", con->http.fd, con->http.state);
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ }
+ while (con->http.state == HTTP_POST_RECV && data_ready(con));
+
+ if (con->http.state == HTTP_POST_SEND)
+ {
+ if (con->file >= 0)
+ {
+ fstat(con->file, &filestats);
+
+ close(con->file);
+ con->file = -1;
+
+ if (filestats.st_size > MaxRequestSize &&
+ MaxRequestSize > 0)
+ {
+ /*
+ * Request is too big; remove it and send an error...
+ */
+
+ unlink(con->filename);
+ cupsdClearString(&con->filename);
+
+ if (con->request)
+ {
+ /*
+ * Delete any IPP request data...
+ */
+
+ ippDelete(con->request);
+ con->request = NULL;
+ }
+
+ if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ else if (filestats.st_size == 0)
+ {
+ /*
+ * Don't allow empty file...
+ */
+
+ unlink(con->filename);
+ cupsdClearString(&con->filename);
+ }
+
+ if (con->command)
+ {
+ if (!cupsdSendCommand(con, con->command, con->options, 0))
+ {
+ if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ else
+ cupsdLogRequest(con, HTTP_OK);
+ }
+ }
+
+ if (con->request)
+ {
+ cupsdProcessIPPRequest(con);
+
+ if (con->filename)
+ {
+ unlink(con->filename);
+ cupsdClearString(&con->filename);
+ }
+
+ return;
+ }
+ }
+ break;
+
+ default :
+ break; /* Anti-compiler-warning-code */
+ }
+
+ if (con->http.state == HTTP_WAITING)
+ {
+ if (!con->http.keep_alive)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d Closing because Keep-Alive disabled",
+ con->http.fd);
+ cupsdCloseClient(con);
+ }
+ else
+ {
+ cupsArrayRemove(ActiveClients, con);
+ cupsdSetBusyState();
+ }
+ }
+}
+
+
+/*
+ * 'cupsdSendCommand()' - Send output from a command via HTTP.
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsdSendCommand(
+ cupsd_client_t *con, /* I - Client connection */
+ char *command, /* I - Command to run */
+ char *options, /* I - Command-line options */
+ int root) /* I - Run as root? */
+{
+ int fd; /* Standard input file descriptor */
+
+
+ if (con->filename)
+ {
+ fd = open(con->filename, O_RDONLY);
+
+ if (fd < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdSendCommand: %d Unable to open \"%s\" for reading: %s",
+ con->http.fd, con->filename ? con->filename : "/dev/null",
+ strerror(errno));
+ return (0);
+ }
+
+ fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+ }
+ else
+ fd = -1;
+
+ con->pipe_pid = pipe_command(con, fd, &(con->file), command, options, root);
+
+ if (fd >= 0)
+ close(fd);
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Started \"%s\" (pid=%d)", command,
+ con->pipe_pid);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSendCommand: %d file=%d",
+ con->http.fd, con->file);
+
+ if (con->pipe_pid == 0)
+ return (0);
+
+ fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+
+ cupsdAddSelect(con->file, (cupsd_selfunc_t)write_pipe, NULL, con);
+
+ con->sent_header = 0;
+ con->file_ready = 0;
+ con->got_fields = 0;
+ con->header_used = 0;
+
+ return (1);
+}
+
+
+/*
+ * 'cupsdSendError()' - Send an error message via HTTP.
+ */
+
+int /* O - 1 if successful, 0 otherwise */
+cupsdSendError(cupsd_client_t *con, /* I - Connection */
+ http_status_t code, /* I - Error code */
+ int auth_type)/* I - Authentication type */
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdSendError(con=%p(%d), code=%d, auth_type=%d", con,
+ con->http.fd, code, auth_type);
+
+#ifdef HAVE_SSL
+ /*
+ * Force client to upgrade for authentication if that is how the
+ * server is configured...
+ */
+
+ if (code == HTTP_UNAUTHORIZED &&
+ DefaultEncryption == HTTP_ENCRYPT_REQUIRED &&
+ _cups_strcasecmp(con->http.hostname, "localhost") &&
+ !con->http.tls)
+ {
+ code = HTTP_UPGRADE_REQUIRED;
+ }
+#endif /* HAVE_SSL */
+
+ /*
+ * Put the request in the access_log file...
+ */
+
+ cupsdLogRequest(con, code);
+
+ /*
+ * To work around bugs in some proxies, don't use Keep-Alive for some
+ * error messages...
+ *
+ * Kerberos authentication doesn't work without Keep-Alive, so
+ * never disable it in that case.
+ */
+
+ if (code >= HTTP_BAD_REQUEST && con->http.auth_type != CUPSD_AUTH_NEGOTIATE)
+ con->http.keep_alive = HTTP_KEEPALIVE_OFF;
+
+ /*
+ * Send an error message back to the client. If the error code is a
+ * 400 or 500 series, make sure the message contains some text, too!
+ */
+
+ if (!cupsdSendHeader(con, code, NULL, auth_type))
+ return (0);
+
+#ifdef HAVE_SSL
+ if (code == HTTP_UPGRADE_REQUIRED)
+ if (httpPrintf(HTTP(con), "Connection: Upgrade\r\n") < 0)
+ return (0);
+
+ if (httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n") < 0)
+ return (0);
+#endif /* HAVE_SSL */
+
+ if (con->http.version >= HTTP_1_1 &&
+ con->http.keep_alive == HTTP_KEEPALIVE_OFF)
+ {
+ if (httpPrintf(HTTP(con), "Connection: close\r\n") < 0)
+ return (0);
+ }
+
+ if (code >= HTTP_BAD_REQUEST)
+ {
+ /*
+ * Send a human-readable error message.
+ */
+
+ char message[4096], /* Message for user */
+ urltext[1024], /* URL redirection text */
+ redirect[1024]; /* Redirection link */
+ const char *text; /* Status-specific text */
+
+
+ redirect[0] = '\0';
+
+ if (code == HTTP_UNAUTHORIZED)
+ text = _cupsLangString(con->language,
+ _("Enter your username and password or the "
+ "root username and password to access this "
+ "page. If you are using Kerberos authentication, "
+ "make sure you have a valid Kerberos ticket."));
+ else if (code == HTTP_UPGRADE_REQUIRED)
+ {
+ text = urltext;
+
+ snprintf(urltext, sizeof(urltext),
+ _cupsLangString(con->language,
+ _("You must access this page using the URL "
+ "<A HREF=\"https://%s:%d%s\">"
+ "https://%s:%d%s</A>.")),
+ con->servername, con->serverport, con->uri,
+ con->servername, con->serverport, con->uri);
+
+ snprintf(redirect, sizeof(redirect),
+ "<META HTTP-EQUIV=\"Refresh\" "
+ "CONTENT=\"3;URL=https://%s:%d%s\">\n",
+ con->servername, con->serverport, con->uri);
+ }
+ else if (code == HTTP_WEBIF_DISABLED)
+ text = _cupsLangString(con->language,
+ _("The web interface is currently disabled. Run "
+ "\"cupsctl WebInterface=yes\" to enable it."));
+ else
+ text = "";
+
+ snprintf(message, sizeof(message),
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" "
+ "\"http://www.w3.org/TR/html4/loose.dtd\">\n"
+ "<HTML>\n"
+ "<HEAD>\n"
+ "\t<META HTTP-EQUIV=\"Content-Type\" "
+ "CONTENT=\"text/html; charset=utf-8\">\n"
+ "\t<TITLE>%s - " CUPS_SVERSION "</TITLE>\n"
+ "\t<LINK REL=\"STYLESHEET\" TYPE=\"text/css\" "
+ "HREF=\"/cups.css\">\n"
+ "%s"
+ "</HEAD>\n"
+ "<BODY>\n"
+ "<H1>%s</H1>\n"
+ "<P>%s</P>\n"
+ "</BODY>\n"
+ "</HTML>\n",
+ httpStatus(code), redirect, httpStatus(code), text);
+
+ if (httpPrintf(HTTP(con), "Content-Type: text/html; charset=utf-8\r\n") < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "Content-Length: %d\r\n",
+ (int)strlen(message)) < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "\r\n") < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "%s", message) < 0)
+ return (0);
+ }
+ else if (httpPrintf(HTTP(con), "\r\n") < 0)
+ return (0);
+
+ if (cupsdFlushHeader(con) < 0)
+ return (0);
+
+ con->http.state = HTTP_WAITING;
+
+ return (1);
+}
+
+
+/*
+ * 'cupsdSendHeader()' - Send an HTTP request.
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsdSendHeader(
+ cupsd_client_t *con, /* I - Client to send to */
+ http_status_t code, /* I - HTTP status code */
+ char *type, /* I - MIME type of document */
+ int auth_type) /* I - Type of authentication */
+{
+ char auth_str[1024]; /* Authorization string */
+#if 0 /* def HAVE_GSSAPI */
+ static char *gss_buf = NULL; /* Kerberos auth data buffer */
+ static int gss_bufsize = 0; /* Size of Kerberos auth data buffer */
+#endif /* HAVE_GSSAPI */
+
+
+ /*
+ * Send the HTTP status header...
+ */
+
+ if (code == HTTP_CONTINUE)
+ {
+ /*
+ * 100-continue doesn't send any headers...
+ */
+
+ return (httpPrintf(HTTP(con), "HTTP/%d.%d 100 Continue\r\n\r\n",
+ con->http.version / 100, con->http.version % 100) > 0);
+ }
+ else if (code == HTTP_WEBIF_DISABLED)
+ {
+ /*
+ * Treat our special "web interface is disabled" status as "200 OK" for web
+ * browsers.
+ */
+
+ code = HTTP_OK;
+ }
+
+ httpFlushWrite(HTTP(con));
+
+ con->http.data_encoding = HTTP_ENCODE_FIELDS;
+
+ if (httpPrintf(HTTP(con), "HTTP/%d.%d %d %s\r\n", con->http.version / 100,
+ con->http.version % 100, code, httpStatus(code)) < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "Date: %s\r\n", httpGetDateString(time(NULL))) < 0)
+ return (0);
+ if (ServerHeader)
+ if (httpPrintf(HTTP(con), "Server: %s\r\n", ServerHeader) < 0)
+ return (0);
+ if (con->http.keep_alive && con->http.version >= HTTP_1_0)
+ {
+ if (httpPrintf(HTTP(con), "Connection: Keep-Alive\r\n") < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "Keep-Alive: timeout=%d\r\n",
+ KeepAliveTimeout) < 0)
+ return (0);
+ }
+ if (code == HTTP_METHOD_NOT_ALLOWED)
+ if (httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST, PUT\r\n") < 0)
+ return (0);
+
+ if (code == HTTP_UNAUTHORIZED)
+ {
+ if (auth_type == CUPSD_AUTH_NONE)
+ {
+ if (!con->best || con->best->type <= CUPSD_AUTH_NONE)
+ auth_type = DefaultAuthType;
+ else
+ auth_type = con->best->type;
+ }
+
+ auth_str[0] = '\0';
+
+ if (auth_type == CUPSD_AUTH_BASIC || auth_type == CUPSD_AUTH_BASICDIGEST)
+ strlcpy(auth_str, "Basic realm=\"CUPS\"", sizeof(auth_str));
+ else if (auth_type == CUPSD_AUTH_DIGEST)
+ snprintf(auth_str, sizeof(auth_str), "Digest realm=\"CUPS\", nonce=\"%s\"",
+ con->http.hostname);
+#ifdef HAVE_GSSAPI
+ else if (auth_type == CUPSD_AUTH_NEGOTIATE)
+ {
+# ifdef AF_LOCAL
+ if (_httpAddrFamily(con->http.hostaddr) == AF_LOCAL)
+ strlcpy(auth_str, "Basic realm=\"CUPS\"", sizeof(auth_str));
+ else
+# endif /* AF_LOCAL */
+ strlcpy(auth_str, "Negotiate", sizeof(auth_str));
+ }
+#endif /* HAVE_GSSAPI */
+
+ if (con->best && auth_type != CUPSD_AUTH_NEGOTIATE &&
+ !_cups_strcasecmp(con->http.hostname, "localhost"))
+ {
+ /*
+ * Add a "trc" (try root certification) parameter for local non-Kerberos
+ * requests when the request requires system group membership - then the
+ * client knows the root certificate can/should be used.
+ *
+ * Also, for Mac OS X we also look for @AUTHKEY and add an "authkey"
+ * parameter as needed...
+ */
+
+ char *name, /* Current user name */
+ *auth_key; /* Auth key buffer */
+ size_t auth_size; /* Size of remaining buffer */
+
+ auth_key = auth_str + strlen(auth_str);
+ auth_size = sizeof(auth_str) - (auth_key - auth_str);
+
+ for (name = (char *)cupsArrayFirst(con->best->names);
+ name;
+ name = (char *)cupsArrayNext(con->best->names))
+ {
+#ifdef HAVE_AUTHORIZATION_H
+ if (!_cups_strncasecmp(name, "@AUTHKEY(", 9))
+ {
+ snprintf(auth_key, auth_size, ", authkey=\"%s\"", name + 9);
+ /* end parenthesis is stripped in conf.c */
+ break;
+ }
+ else
+#endif /* HAVE_AUTHORIZATION_H */
+ if (!_cups_strcasecmp(name, "@SYSTEM"))
+ {
+#ifdef HAVE_AUTHORIZATION_H
+ if (SystemGroupAuthKey)
+ snprintf(auth_key, auth_size,
+ ", authkey=\"%s\"",
+ SystemGroupAuthKey);
+ else
+#else
+ strlcpy(auth_key, ", trc=\"y\"", auth_size);
+#endif /* HAVE_AUTHORIZATION_H */
+ break;
+ }
+ }
+ }
+
+ if (auth_str[0])
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdSendHeader: %d WWW-Authenticate: %s", con->http.fd,
+ auth_str);
+
+ if (httpPrintf(HTTP(con), "WWW-Authenticate: %s\r\n", auth_str) < 0)
+ return (0);
+ }
+ }
+
+ if (con->language && strcmp(con->language->language, "C"))
+ {
+ if (httpPrintf(HTTP(con), "Content-Language: %s\r\n",
+ con->language->language) < 0)
+ return (0);
+ }
+
+ if (type)
+ {
+ if (!strcmp(type, "text/html"))
+ {
+ if (httpPrintf(HTTP(con),
+ "Content-Type: text/html; charset=utf-8\r\n") < 0)
+ return (0);
+ }
+ else if (httpPrintf(HTTP(con), "Content-Type: %s\r\n", type) < 0)
+ return (0);
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'cupsdUpdateCGI()' - Read status messages from CGI scripts and programs.
+ */
+
+void
+cupsdUpdateCGI(void)
+{
+ char *ptr, /* Pointer to end of line in buffer */
+ message[1024]; /* Pointer to message text */
+ int loglevel; /* Log level for message */
+
+
+ while ((ptr = cupsdStatBufUpdate(CGIStatusBuffer, &loglevel,
+ message, sizeof(message))) != NULL)
+ {
+ if (loglevel == CUPSD_LOG_INFO)
+ cupsdLogMessage(CUPSD_LOG_INFO, "%s", message);
+
+ if (!strchr(CGIStatusBuffer->buffer, '\n'))
+ break;
+ }
+
+ if (ptr == NULL && !CGIStatusBuffer->bufused)
+ {
+ /*
+ * Fatal error on pipe - should never happen!
+ */
+
+ cupsdLogMessage(CUPSD_LOG_CRIT,
+ "cupsdUpdateCGI: error reading from CGI error pipe - %s",
+ strerror(errno));
+ }
+}
+
+
+/*
+ * 'cupsdWriteClient()' - Write data to a client as needed.
+ */
+
+void
+cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */
+{
+ int bytes, /* Number of bytes written */
+ field_col; /* Current column */
+ char *bufptr, /* Pointer into buffer */
+ *bufend; /* Pointer to end of buffer */
+ ipp_state_t ipp_state; /* IPP state value */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdWriteClient(con=%p(%d)) response=%p(%d), file=%d "
+ "pipe_pid=%d state=%d",
+ con, con->http.fd, con->response,
+ con->response ? con->response->state : -1,
+ con->file, con->pipe_pid, con->http.state);
+
+ if (con->http.state != HTTP_GET_SEND &&
+ con->http.state != HTTP_POST_SEND)
+ {
+ /*
+ * If we get called in the wrong state, then something went wrong with the
+ * connection and we need to shut it down...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdWriteClient: %d Closing on unknown HTTP state %d",
+ con->http.fd, con->http.state);
+ cupsdCloseClient(con);
+ return;
+ }
+
+ if (con->pipe_pid)
+ {
+ /*
+ * Make sure we select on the CGI output...
+ */
+
+ cupsdAddSelect(con->file, (cupsd_selfunc_t)write_pipe, NULL, con);
+
+ if (!con->file_ready)
+ {
+ /*
+ * Try again later when there is CGI output available...
+ */
+
+ cupsdRemoveSelect(con->http.fd);
+ return;
+ }
+
+ con->file_ready = 0;
+ }
+
+ if (con->response && con->response->state != IPP_DATA)
+ {
+ ipp_state = ippWrite(HTTP(con), con->response);
+ bytes = ipp_state != IPP_ERROR &&
+ (con->file >= 0 || ipp_state != IPP_DATA);
+ }
+ else if ((bytes = read(con->file, con->header,
+ sizeof(con->header) - con->header_used)) > 0)
+ {
+ con->header_used += bytes;
+
+ if (con->pipe_pid && !con->got_fields)
+ {
+ /*
+ * Inspect the data for Content-Type and other fields.
+ */
+
+ for (bufptr = con->header, bufend = con->header + con->header_used,
+ field_col = 0;
+ !con->got_fields && bufptr < bufend;
+ bufptr ++)
+ {
+ if (*bufptr == '\n')
+ {
+ /*
+ * Send line to client...
+ */
+
+ if (bufptr > con->header && bufptr[-1] == '\r')
+ bufptr[-1] = '\0';
+ *bufptr++ = '\0';
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Script header: %s", con->header);
+
+ if (!con->sent_header)
+ {
+ /*
+ * Handle redirection and CGI status codes...
+ */
+
+ if (!_cups_strncasecmp(con->header, "Location:", 9))
+ {
+ if (!cupsdSendHeader(con, HTTP_SEE_OTHER, NULL, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ con->sent_header = 2;
+
+ if (httpPrintf(HTTP(con), "Content-Length: 0\r\n") < 0)
+ return;
+ }
+ else if (!_cups_strncasecmp(con->header, "Status:", 7))
+ {
+ cupsdSendError(con, (http_status_t)atoi(con->header + 7),
+ CUPSD_AUTH_NONE);
+ con->sent_header = 2;
+ }
+ else
+ {
+ if (!cupsdSendHeader(con, HTTP_OK, NULL, CUPSD_AUTH_NONE))
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ con->sent_header = 1;
+
+ if (con->http.version == HTTP_1_1)
+ {
+ if (httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n") < 0)
+ return;
+ }
+ }
+ }
+
+ if (_cups_strncasecmp(con->header, "Status:", 7))
+ httpPrintf(HTTP(con), "%s\r\n", con->header);
+
+ /*
+ * Update buffer...
+ */
+
+ con->header_used -= bufptr - con->header;
+
+ if (con->header_used > 0)
+ memmove(con->header, bufptr, con->header_used);
+
+ bufptr = con->header - 1;
+
+ /*
+ * See if the line was empty...
+ */
+
+ if (field_col == 0)
+ {
+ con->got_fields = 1;
+
+ if (cupsdFlushHeader(con) < 0)
+ {
+ cupsdCloseClient(con);
+ return;
+ }
+
+ if (con->http.version == HTTP_1_1)
+ con->http.data_encoding = HTTP_ENCODE_CHUNKED;
+ }
+ else
+ field_col = 0;
+ }
+ else if (*bufptr != '\r')
+ field_col ++;
+ }
+
+ if (!con->got_fields)
+ {
+ con->http.activity = time(NULL);
+ return;
+ }
+ }
+
+ if (con->header_used > 0)
+ {
+ if (httpWrite2(HTTP(con), con->header, con->header_used) < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdWriteClient: %d Closing for error %d (%s)",
+ con->http.fd, con->http.error,
+ strerror(con->http.error));
+ cupsdCloseClient(con);
+ return;
+ }
+
+ if (con->http.data_encoding == HTTP_ENCODE_CHUNKED)
+ httpFlushWrite(HTTP(con));
+
+ con->bytes += con->header_used;
+
+ if (con->http.state == HTTP_WAITING)
+ bytes = 0;
+ else
+ bytes = con->header_used;
+
+ con->header_used = 0;
+ }
+ }
+
+ if (bytes <= 0 ||
+ (con->http.state != HTTP_GET_SEND && con->http.state != HTTP_POST_SEND))
+ {
+ if (!con->sent_header && con->pipe_pid)
+ cupsdSendError(con, HTTP_SERVER_ERROR, CUPSD_AUTH_NONE);
+ else
+ {
+ cupsdLogRequest(con, HTTP_OK);
+
+ httpFlushWrite(HTTP(con));
+
+ if (con->http.data_encoding == HTTP_ENCODE_CHUNKED && con->sent_header == 1)
+ {
+ if (httpWrite2(HTTP(con), "", 0) < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdWriteClient: %d Closing for error %d (%s)",
+ con->http.fd, con->http.error,
+ strerror(con->http.error));
+ cupsdCloseClient(con);
+ return;
+ }
+ }
+ }
+
+ con->http.state = HTTP_WAITING;
+
+ cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con);
+
+ if (con->file >= 0)
+ {
+ cupsdRemoveSelect(con->file);
+
+ if (con->pipe_pid)
+ cupsdEndProcess(con->pipe_pid, 0);
+
+ close(con->file);
+ con->file = -1;
+ con->pipe_pid = 0;
+ }
+
+ if (con->filename)
+ {
+ unlink(con->filename);
+ cupsdClearString(&con->filename);
+ }
+
+ if (con->request)
+ {
+ ippDelete(con->request);
+ con->request = NULL;
+ }
+
+ if (con->response)
+ {
+ ippDelete(con->response);
+ con->response = NULL;
+ }
+
+ cupsdClearString(&con->command);
+ cupsdClearString(&con->options);
+ cupsdClearString(&con->query_string);
+
+ if (!con->http.keep_alive)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdWriteClient: %d Closing because Keep-Alive disabled",
+ con->http.fd);
+ cupsdCloseClient(con);
+ return;
+ }
+ else
+ {
+ cupsArrayRemove(ActiveClients, con);
+ cupsdSetBusyState();
+ }
+ }
+
+ con->http.activity = time(NULL);
+}
+
+
+/*
+ * 'check_if_modified()' - Decode an "If-Modified-Since" line.
+ */
+
+static int /* O - 1 if modified since */
+check_if_modified(
+ cupsd_client_t *con, /* I - Client connection */
+ struct stat *filestats) /* I - File information */
+{
+ char *ptr; /* Pointer into field */
+ time_t date; /* Time/date value */
+ off_t size; /* Size/length value */
+
+
+ size = 0;
+ date = 0;
+ ptr = con->http.fields[HTTP_FIELD_IF_MODIFIED_SINCE];
+
+ if (*ptr == '\0')
+ return (1);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "check_if_modified(con=%p(%d), "
+ "filestats=%p(" CUPS_LLFMT ", %d)) If-Modified-Since=\"%s\"",
+ con, con->http.fd, filestats, CUPS_LLCAST filestats->st_size,
+ (int)filestats->st_mtime, ptr);
+
+ while (*ptr != '\0')
+ {
+ while (isspace(*ptr) || *ptr == ';')
+ ptr ++;
+
+ if (_cups_strncasecmp(ptr, "length=", 7) == 0)
+ {
+ ptr += 7;
+ size = strtoll(ptr, NULL, 10);
+
+ while (isdigit(*ptr))
+ ptr ++;
+ }
+ else if (isalpha(*ptr))
+ {
+ date = httpGetDateTime(ptr);
+ while (*ptr != '\0' && *ptr != ';')
+ ptr ++;
+ }
+ else
+ ptr ++;
+ }
+
+ return ((size != filestats->st_size && size != 0) ||
+ (date < filestats->st_mtime && date != 0) ||
+ (size == 0 && date == 0));
+}
+
+
+/*
+ * 'compare_clients()' - Compare two client connections.
+ */
+
+static int /* O - Result of comparison */
+compare_clients(cupsd_client_t *a, /* I - First client */
+ cupsd_client_t *b, /* I - Second client */
+ void *data) /* I - User data (not used) */
+{
+ (void)data;
+
+ if (a == b)
+ return (0);
+ else if (a < b)
+ return (-1);
+ else
+ return (1);
+}
+
+
+/*
+ * 'data_ready()' - Check whether data is available from a client.
+ */
+
+static int /* O - 1 if data is ready, 0 otherwise */
+data_ready(cupsd_client_t *con) /* I - Client */
+{
+ if (con->http.used > 0)
+ return (1);
+#ifdef HAVE_SSL
+ else if (con->http.tls)
+ {
+# ifdef HAVE_LIBSSL
+ if (SSL_pending((SSL *)(con->http.tls)))
+ return (1);
+# elif defined(HAVE_GNUTLS)
+ if (gnutls_record_check_pending(con->http.tls))
+ return (1);
+# elif defined(HAVE_CDSASSL)
+ size_t bytes; /* Bytes that are available */
+
+ if (!SSLGetBufferedReadSize(con->http.tls, &bytes) && bytes > 0)
+ return (1);
+# endif /* HAVE_LIBSSL */
+ }
+#endif /* HAVE_SSL */
+
+ return (0);
+}
+
+
+#ifdef HAVE_SSL
+/*
+ * 'encrypt_client()' - Enable encryption for the client...
+ */
+
+static int /* O - 1 on success, 0 on error */
+encrypt_client(cupsd_client_t *con) /* I - Client to encrypt */
+{
+# ifdef HAVE_LIBSSL
+ SSL_CTX *context; /* Context for encryption */
+ BIO *bio; /* BIO data */
+ unsigned long error; /* Error code */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "encrypt_client(con=%p(%d))", con,
+ con->http.fd);
+
+ /*
+ * Verify that we have a certificate...
+ */
+
+ if (access(ServerKey, 0) || access(ServerCertificate, 0))
+ {
+ /*
+ * Nope, make a self-signed certificate...
+ */
+
+ if (!make_certificate(con))
+ return (0);
+ }
+
+ /*
+ * Create the SSL context and accept the connection...
+ */
+
+ context = SSL_CTX_new(SSLv23_server_method());
+
+ SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */
+ if (SSLOptions & CUPSD_SSL_NOEMPTY)
+ SSL_CTX_set_options(context, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
+ SSL_CTX_use_PrivateKey_file(context, ServerKey, SSL_FILETYPE_PEM);
+ SSL_CTX_use_certificate_chain_file(context, ServerCertificate);
+
+ bio = BIO_new(_httpBIOMethods());
+ BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)HTTP(con));
+
+ con->http.tls = SSL_new(context);
+ SSL_set_bio(con->http.tls, bio, bio);
+
+ if (SSL_accept(con->http.tls) != 1)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to encrypt connection from %s!",
+ con->http.hostname);
+
+ while ((error = ERR_get_error()) != 0)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s", ERR_error_string(error, NULL));
+
+ SSL_CTX_free(context);
+ SSL_free(con->http.tls);
+ con->http.tls = NULL;
+ return (0);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
+ con->http.hostname);
+
+ return (1);
+
+# elif defined(HAVE_GNUTLS)
+ int error; /* Error code */
+ gnutls_certificate_server_credentials *credentials;
+ /* TLS credentials */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "encrypt_client(con=%p(%d))", con,
+ con->http.fd);
+
+ /*
+ * Verify that we have a certificate...
+ */
+
+ if (access(ServerKey, 0) || access(ServerCertificate, 0))
+ {
+ /*
+ * Nope, make a self-signed certificate...
+ */
+
+ if (!make_certificate(con))
+ return (0);
+ }
+
+ /*
+ * Create the SSL object and perform the SSL handshake...
+ */
+
+ credentials = (gnutls_certificate_server_credentials *)
+ malloc(sizeof(gnutls_certificate_server_credentials));
+ if (credentials == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to encrypt connection from %s - %s",
+ con->http.hostname, strerror(errno));
+
+ return (0);
+ }
+
+ gnutls_certificate_allocate_credentials(credentials);
+ gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate,
+ ServerKey, GNUTLS_X509_FMT_PEM);
+
+ gnutls_init(&con->http.tls), GNUTLS_SERVER);
+ gnutls_set_default_priority(con->http.tls);
+ gnutls_credentials_set(con->http.tls, GNUTLS_CRD_CERTIFICATE, *credentials);
+ gnutls_transport_set_ptr(con->http.tls, (gnutls_transport_ptr)HTTP(con));
+ gnutls_transport_set_pull_function(con->http.tls, _httpReadGNUTLS);
+ gnutls_transport_set_push_function(con->http.tls, _httpWriteGNUTLS);
+
+ error = gnutls_handshake(con->http.tls);
+
+ if (error != GNUTLS_E_SUCCESS)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to encrypt connection from %s - %s",
+ con->http.hostname, gnutls_strerror(error));
+
+ gnutls_deinit(con->http.tls);
+ gnutls_certificate_free_credentials(*credentials);
+ con->http.tls = NULL;
+ free(credentials);
+ return (0);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
+ con->http.hostname);
+
+ con->http.tls_credentials = credentials;
+ return (1);
+
+# elif defined(HAVE_CDSASSL)
+ OSStatus error = 0; /* Error code */
+ CFArrayRef peerCerts; /* Peer certificates */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "encrypt_client(con=%p(%d))", con,
+ con->http.fd);
+
+ con->http.tls_credentials = get_cdsa_certificate(con);
+
+ if (!con->http.tls_credentials)
+ {
+ /*
+ * No keychain (yet), make a self-signed certificate...
+ */
+
+ if (make_certificate(con))
+ con->http.tls_credentials = get_cdsa_certificate(con);
+ }
+
+ if (!con->http.tls_credentials)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Could not find signing key in keychain \"%s\"",
+ ServerCertificate);
+ error = errSSLBadCert; /* errSSLBadConfiguration is a better choice, but not available on 10.2.x */
+ }
+
+ if (!error)
+ error = SSLNewContext(true, &con->http.tls);
+
+ if (!error)
+ error = SSLSetIOFuncs(con->http.tls, _httpReadCDSA, _httpWriteCDSA);
+
+ if (!error)
+ error = SSLSetProtocolVersionEnabled(con->http.tls, kSSLProtocol2, false);
+
+ if (!error)
+ error = SSLSetConnection(con->http.tls, HTTP(con));
+
+ if (!error)
+ error = SSLSetAllowsExpiredCerts(con->http.tls, true);
+
+ if (!error)
+ error = SSLSetAllowsAnyRoot(con->http.tls, true);
+
+ if (!error)
+ error = SSLSetCertificate(con->http.tls, con->http.tls_credentials);
+
+ if (!error)
+ {
+ /*
+ * Perform SSL/TLS handshake
+ */
+
+ while ((error = SSLHandshake(con->http.tls)) == errSSLWouldBlock)
+ usleep(1000);
+ }
+
+ if (error)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to encrypt connection from %s - %s (%d)",
+ con->http.hostname, cssmErrorString(error), (int)error);
+
+ con->http.error = error;
+ con->http.status = HTTP_ERROR;
+
+ if (con->http.tls)
+ {
+ SSLDisposeContext(con->http.tls);
+ con->http.tls = NULL;
+ }
+
+ if (con->http.tls_credentials)
+ {
+ CFRelease(con->http.tls_credentials);
+ con->http.tls_credentials = NULL;
+ }
+
+ return (0);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
+ con->http.hostname);
+
+ if (!SSLCopyPeerCertificates(con->http.tls, &peerCerts) && peerCerts)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Received %d peer certificates!",
+ (int)CFArrayGetCount(peerCerts));
+ CFRelease(peerCerts);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Received NO peer certificates!");
+
+ return (1);
+
+# endif /* HAVE_LIBSSL */
+}
+#endif /* HAVE_SSL */
+
+
+#ifdef HAVE_CDSASSL
+/*
+ * 'get_cdsa_certificate()' - Get a SSL/TLS certificate from the System keychain.
+ */
+
+static CFArrayRef /* O - Array of certificates */
+get_cdsa_certificate(
+ cupsd_client_t *con) /* I - Client connection */
+{
+ OSStatus err; /* Error info */
+ SecKeychainRef keychain = NULL;/* Keychain reference */
+ SecIdentitySearchRef search = NULL; /* Search reference */
+ SecIdentityRef identity = NULL;/* Identity */
+ CFArrayRef certificates = NULL;
+ /* Certificate array */
+# if HAVE_SECPOLICYCREATESSL
+ SecPolicyRef policy = NULL; /* Policy ref */
+ CFStringRef servername = NULL;
+ /* Server name */
+ CFMutableDictionaryRef query = NULL; /* Query qualifiers */
+ char localname[1024];/* Local hostname */
+# elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY)
+ SecPolicyRef policy = NULL; /* Policy ref */
+ SecPolicySearchRef policy_search = NULL;
+ /* Policy search ref */
+ CSSM_DATA options; /* Policy options */
+ CSSM_APPLE_TP_SSL_OPTIONS
+ ssl_options; /* SSL Option for hostname */
+ char localname[1024];/* Local hostname */
+# endif /* HAVE_SECPOLICYCREATESSL */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "get_cdsa_certificate: Looking for certs for \"%s\"...",
+ con->servername);
+
+ if ((err = SecKeychainOpen(ServerCertificate, &keychain)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot open keychain \"%s\" - %s (%d)",
+ ServerCertificate, cssmErrorString(err), (int)err);
+ goto cleanup;
+ }
+
+# if HAVE_SECPOLICYCREATESSL
+ servername = CFStringCreateWithCString(kCFAllocatorDefault, con->servername,
+ kCFStringEncodingUTF8);
+
+ policy = SecPolicyCreateSSL(1, servername);
+
+ if (servername)
+ CFRelease(servername);
+
+ if (!policy)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference");
+ goto cleanup;
+ }
+
+ if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create query dictionary");
+ goto cleanup;
+ }
+
+ CFDictionaryAddValue(query, kSecClass, kSecClassIdentity);
+ CFDictionaryAddValue(query, kSecMatchPolicy, policy);
+ CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
+ CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne);
+
+ err = SecItemCopyMatching(query, (CFTypeRef *)&identity);
+
+ if (err && DNSSDHostName)
+ {
+ /*
+ * Search for the connection server name failed; try the DNS-SD .local
+ * hostname instead...
+ */
+
+ snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "get_cdsa_certificate: Looking for certs for \"%s\"...",
+ localname);
+
+ servername = CFStringCreateWithCString(kCFAllocatorDefault, localname,
+ kCFStringEncodingUTF8);
+
+ CFRelease(policy);
+
+ policy = SecPolicyCreateSSL(1, servername);
+
+ if (servername)
+ CFRelease(servername);
+
+ if (!policy)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference");
+ goto cleanup;
+ }
+
+ CFDictionarySetValue(query, kSecMatchPolicy, policy);
+
+ err = SecItemCopyMatching(query, (CFTypeRef *)&identity);
+ }
+
+ if (err)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Cannot find signing key in keychain \"%s\": %s (%d)",
+ ServerCertificate, cssmErrorString(err), (int)err);
+ goto cleanup;
+ }
+
+# elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY)
+ /*
+ * Use a policy to search for valid certificates whose common name matches the
+ * servername...
+ */
+
+ if (SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_TP_SSL,
+ NULL, &policy_search))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create a policy search reference");
+ goto cleanup;
+ }
+
+ if (SecPolicySearchCopyNext(policy_search, &policy))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Cannot find a policy to use for searching");
+ goto cleanup;
+ }
+
+ memset(&ssl_options, 0, sizeof(ssl_options));
+ ssl_options.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
+ ssl_options.ServerName = con->servername;
+ ssl_options.ServerNameLen = strlen(con->servername);
+
+ options.Data = (uint8 *)&ssl_options;
+ options.Length = sizeof(ssl_options);
+
+ if (SecPolicySetValue(policy, &options))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Cannot set policy value to use for searching");
+ goto cleanup;
+ }
+
+ if ((err = SecIdentitySearchCreateWithPolicy(policy, NULL, CSSM_KEYUSE_SIGN,
+ keychain, FALSE, &search)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Cannot create identity search reference: %s (%d)",
+ cssmErrorString(err), (int)err);
+ goto cleanup;
+ }
+
+ err = SecIdentitySearchCopyNext(search, &identity);
+
+ if (err && DNSSDHostName)
+ {
+ /*
+ * Search for the connection server name failed; try the DNS-SD .local
+ * hostname instead...
+ */
+
+ snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName);
+
+ ssl_options.ServerName = localname;
+ ssl_options.ServerNameLen = strlen(localname);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "get_cdsa_certificate: Looking for certs for \"%s\"...",
+ localname);
+
+ if (SecPolicySetValue(policy, &options))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Cannot set policy value to use for searching");
+ goto cleanup;
+ }
+
+ CFRelease(search);
+ search = NULL;
+ if ((err = SecIdentitySearchCreateWithPolicy(policy, NULL, CSSM_KEYUSE_SIGN,
+ keychain, FALSE, &search)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Cannot create identity search reference: %s (%d)",
+ cssmErrorString(err), (int)err);
+ goto cleanup;
+ }
+
+ err = SecIdentitySearchCopyNext(search, &identity);
+
+ }
+
+ if (err)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Cannot find signing key in keychain \"%s\": %s (%d)",
+ ServerCertificate, cssmErrorString(err), (int)err);
+ goto cleanup;
+ }
+
+# else
+ /*
+ * Assume there is exactly one SecIdentity in the keychain...
+ */
+
+ if ((err = SecIdentitySearchCreate(keychain, CSSM_KEYUSE_SIGN, &search)))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Cannot create identity search reference (%d)", (int)err);
+ goto cleanup;
+ }
+
+ if ((err = SecIdentitySearchCopyNext(search, &identity)))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Cannot find signing key in keychain \"%s\": %s (%d)",
+ ServerCertificate, cssmErrorString(err), (int)err);
+ goto cleanup;
+ }
+# endif /* HAVE_SECPOLICYCREATESSL */
+
+ if (CFGetTypeID(identity) != SecIdentityGetTypeID())
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "SecIdentity CFTypeID failure!");
+ goto cleanup;
+ }
+
+ if ((certificates = CFArrayCreate(NULL, (const void **)&identity,
+ 1, &kCFTypeArrayCallBacks)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create certificate array");
+ goto cleanup;
+ }
+
+ cleanup :
+
+ if (keychain)
+ CFRelease(keychain);
+ if (search)
+ CFRelease(search);
+ if (identity)
+ CFRelease(identity);
+
+# if HAVE_SECPOLICYCREATESSL
+ if (policy)
+ CFRelease(policy);
+ if (query)
+ CFRelease(query);
+# elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY)
+ if (policy)
+ CFRelease(policy);
+ if (policy_search)
+ CFRelease(policy_search);
+# endif /* HAVE_SECPOLICYCREATESSL */
+
+ return (certificates);
+}
+#endif /* HAVE_CDSASSL */
+
+
+/*
+ * 'get_file()' - Get a filename and state info.
+ */
+
+static char * /* O - Real filename */
+get_file(cupsd_client_t *con, /* I - Client connection */
+ struct stat *filestats, /* O - File information */
+ char *filename, /* IO - Filename buffer */
+ int len) /* I - Buffer length */
+{
+ int status; /* Status of filesystem calls */
+ char *ptr; /* Pointer info filename */
+ int plen; /* Remaining length after pointer */
+ char language[7]; /* Language subdirectory, if any */
+
+
+ /*
+ * Figure out the real filename...
+ */
+
+ language[0] = '\0';
+
+ if (!strncmp(con->uri, "/ppd/", 5) && !strchr(con->uri + 5, '/'))
+ snprintf(filename, len, "%s%s", ServerRoot, con->uri);
+ else if (!strncmp(con->uri, "/icons/", 7) && !strchr(con->uri + 7, '/'))
+ {
+ snprintf(filename, len, "%s/%s", CacheDir, con->uri + 7);
+ if (access(filename, F_OK) < 0)
+ snprintf(filename, len, "%s/images/generic.png", DocumentRoot);
+ }
+ else if (!strncmp(con->uri, "/rss/", 5) && !strchr(con->uri + 5, '/'))
+ snprintf(filename, len, "%s/rss/%s", CacheDir, con->uri + 5);
+ else if (!strncmp(con->uri, "/admin/conf/", 12))
+ snprintf(filename, len, "%s%s", ServerRoot, con->uri + 11);
+ else if (!strncmp(con->uri, "/admin/log/", 11))
+ {
+ if (!strncmp(con->uri + 11, "access_log", 10) && AccessLog[0] == '/')
+ strlcpy(filename, AccessLog, len);
+ else if (!strncmp(con->uri + 11, "error_log", 9) && ErrorLog[0] == '/')
+ strlcpy(filename, ErrorLog, len);
+ else if (!strncmp(con->uri + 11, "page_log", 8) && PageLog[0] == '/')
+ strlcpy(filename, PageLog, len);
+ else
+ return (NULL);
+ }
+ else if (con->language)
+ {
+ snprintf(language, sizeof(language), "/%s", con->language->language);
+ snprintf(filename, len, "%s%s%s", DocumentRoot, language, con->uri);
+ }
+ else
+ snprintf(filename, len, "%s%s", DocumentRoot, con->uri);
+
+ if ((ptr = strchr(filename, '?')) != NULL)
+ *ptr = '\0';
+
+ /*
+ * Grab the status for this language; if there isn't a language-specific file
+ * then fallback to the default one...
+ */
+
+ if ((status = stat(filename, filestats)) != 0 && language[0] &&
+ strncmp(con->uri, "/icons/", 7) &&
+ strncmp(con->uri, "/ppd/", 5) &&
+ strncmp(con->uri, "/rss/", 5) &&
+ strncmp(con->uri, "/admin/conf/", 12) &&
+ strncmp(con->uri, "/admin/log/", 11))
+ {
+ /*
+ * Drop the country code...
+ */
+
+ language[3] = '\0';
+ snprintf(filename, len, "%s%s%s", DocumentRoot, language, con->uri);
+
+ if ((ptr = strchr(filename, '?')) != NULL)
+ *ptr = '\0';
+
+ if ((status = stat(filename, filestats)) != 0)
+ {
+ /*
+ * Drop the language prefix and try the root directory...
+ */
+
+ language[0] = '\0';
+ snprintf(filename, len, "%s%s", DocumentRoot, con->uri);
+
+ if ((ptr = strchr(filename, '?')) != NULL)
+ *ptr = '\0';
+
+ status = stat(filename, filestats);
+ }
+ }
+
+ /*
+ * If we're found a directory, get the index.html file instead...
+ */
+
+ if (!status && S_ISDIR(filestats->st_mode))
+ {
+ /*
+ * Make sure the URI ends with a slash...
+ */
+
+ if (con->uri[strlen(con->uri) - 1] != '/')
+ strlcat(con->uri, "/", sizeof(con->uri));
+
+ /*
+ * Find the directory index file, trying every language...
+ */
+
+ do
+ {
+ if (status && language[0])
+ {
+ /*
+ * Try a different language subset...
+ */
+
+ if (language[3])
+ language[0] = '\0'; /* Strip country code */
+ else
+ language[0] = '\0'; /* Strip language */
+ }
+
+ /*
+ * Look for the index file...
+ */
+
+ snprintf(filename, len, "%s%s%s", DocumentRoot, language, con->uri);
+
+ if ((ptr = strchr(filename, '?')) != NULL)
+ *ptr = '\0';
+
+ ptr = filename + strlen(filename);
+ plen = len - (ptr - filename);
+
+ strlcpy(ptr, "index.html", plen);
+ status = stat(filename, filestats);
+
+#ifdef HAVE_JAVA
+ if (status)
+ {
+ strlcpy(ptr, "index.class", plen);
+ status = stat(filename, filestats);
+ }
+#endif /* HAVE_JAVA */
+
+#ifdef HAVE_PERL
+ if (status)
+ {
+ strlcpy(ptr, "index.pl", plen);
+ status = stat(filename, filestats);
+ }
+#endif /* HAVE_PERL */
+
+#ifdef HAVE_PHP
+ if (status)
+ {
+ strlcpy(ptr, "index.php", plen);
+ status = stat(filename, filestats);
+ }
+#endif /* HAVE_PHP */
+
+#ifdef HAVE_PYTHON
+ if (status)
+ {
+ strlcpy(ptr, "index.pyc", plen);
+ status = stat(filename, filestats);
+ }
+
+ if (status)
+ {
+ strlcpy(ptr, "index.py", plen);
+ status = stat(filename, filestats);
+ }
+#endif /* HAVE_PYTHON */
+
+ }
+ while (status && language[0]);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "get_file(con=%p(%d), filestats=%p, filename=%p, len=%d) = "
+ "%s", con, con->http.fd, filestats, filename, len,
+ status ? "(null)" : filename);
+
+ if (status)
+ return (NULL);
+ else
+ return (filename);
+}
+
+
+/*
+ * 'install_conf_file()' - Install a configuration file.
+ */
+
+static http_status_t /* O - Status */
+install_conf_file(cupsd_client_t *con) /* I - Connection */
+{
+ char filename[1024]; /* Configuration filename */
+ mode_t mode; /* Permissions */
+ cups_file_t *in, /* Input file */
+ *out; /* Output file */
+ char buffer[16384]; /* Copy buffer */
+ ssize_t bytes; /* Number of bytes */
+
+
+ /*
+ * Open the request file...
+ */
+
+ if ((in = cupsFileOpen(con->filename, "rb")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open request file \"%s\": %s",
+ con->filename, strerror(errno));
+ return (HTTP_SERVER_ERROR);
+ }
+
+ /*
+ * Open the new config file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s%s", ServerRoot, con->uri + 11);
+ if (!strcmp(con->uri, "/admin/conf/printers.conf"))
+ mode = ConfigFilePerm & 0600;
+ else
+ mode = ConfigFilePerm;
+
+ if ((out = cupsdCreateConfFile(filename, mode)) == NULL)
+ {
+ cupsFileClose(in);
+ return (HTTP_SERVER_ERROR);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Installing config file \"%s\"...", filename);
+
+ /*
+ * Copy from the request to the new config file...
+ */
+
+ while ((bytes = cupsFileRead(in, buffer, sizeof(buffer))) > 0)
+ if (cupsFileWrite(out, buffer, bytes) < bytes)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to copy to config file \"%s\": %s",
+ filename, strerror(errno));
+
+ cupsFileClose(in);
+ cupsFileClose(out);
+
+ snprintf(filename, sizeof(filename), "%s%s.N", ServerRoot, con->uri + 11);
+ cupsdRemoveFile(filename);
+
+ return (HTTP_SERVER_ERROR);
+ }
+
+ /*
+ * Close the files...
+ */
+
+ cupsFileClose(in);
+
+ if (cupsdCloseCreatedConfFile(out, filename))
+ return (HTTP_SERVER_ERROR);
+
+ /*
+ * Remove the request file...
+ */
+
+ cupsdRemoveFile(con->filename);
+ cupsdClearString(&con->filename);
+
+ /*
+ * If the cupsd.conf file was updated, set the NeedReload flag...
+ */
+
+ if (!strcmp(con->uri, "/admin/conf/cupsd.conf"))
+ NeedReload = RELOAD_CUPSD;
+ else
+ NeedReload = RELOAD_ALL;
+
+ ReloadTime = time(NULL);
+
+ /*
+ * Return that the file was created successfully...
+ */
+
+ return (HTTP_CREATED);
+}
+
+
+/*
+ * 'is_cgi()' - Is the resource a CGI script/program?
+ */
+
+static int /* O - 1 = CGI, 0 = file */
+is_cgi(cupsd_client_t *con, /* I - Client connection */
+ const char *filename, /* I - Real filename */
+ struct stat *filestats, /* I - File information */
+ mime_type_t *type) /* I - MIME type */
+{
+ const char *options; /* Options on URL */
+
+
+ /*
+ * Get the options, if any...
+ */
+
+ if ((options = strchr(con->uri, '?')) != NULL)
+ {
+ options ++;
+ cupsdSetStringf(&(con->query_string), "QUERY_STRING=%s", options);
+ }
+
+ /*
+ * Check for known types...
+ */
+
+ if (!type || _cups_strcasecmp(type->super, "application"))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, "
+ "type=%s/%s) = 0", con, con->http.fd, filename, filestats,
+ type ? type->super : "unknown",
+ type ? type->type : "unknown");
+ return (0);
+ }
+
+ if (!_cups_strcasecmp(type->type, "x-httpd-cgi") &&
+ (filestats->st_mode & 0111))
+ {
+ /*
+ * "application/x-httpd-cgi" is a CGI script.
+ */
+
+ cupsdSetString(&con->command, filename);
+
+ if (options)
+ cupsdSetStringf(&con->options, " %s", options);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, "
+ "type=%s/%s) = 1", con, con->http.fd, filename, filestats,
+ type->super, type->type);
+ return (1);
+ }
+#ifdef HAVE_JAVA
+ else if (!_cups_strcasecmp(type->type, "x-httpd-java"))
+ {
+ /*
+ * "application/x-httpd-java" is a Java servlet.
+ */
+
+ cupsdSetString(&con->command, CUPS_JAVA);
+
+ if (options)
+ cupsdSetStringf(&con->options, " %s %s", filename, options);
+ else
+ cupsdSetStringf(&con->options, " %s", filename);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, "
+ "type=%s/%s) = 1", con, con->http.fd, filename, filestats,
+ type->super, type->type);
+ return (1);
+ }
+#endif /* HAVE_JAVA */
+#ifdef HAVE_PERL
+ else if (!_cups_strcasecmp(type->type, "x-httpd-perl"))
+ {
+ /*
+ * "application/x-httpd-perl" is a Perl page.
+ */
+
+ cupsdSetString(&con->command, CUPS_PERL);
+
+ if (options)
+ cupsdSetStringf(&con->options, " %s %s", filename, options);
+ else
+ cupsdSetStringf(&con->options, " %s", filename);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, "
+ "type=%s/%s) = 1", con, con->http.fd, filename, filestats,
+ type->super, type->type);
+ return (1);
+ }
+#endif /* HAVE_PERL */
+#ifdef HAVE_PHP
+ else if (!_cups_strcasecmp(type->type, "x-httpd-php"))
+ {
+ /*
+ * "application/x-httpd-php" is a PHP page.
+ */
+
+ cupsdSetString(&con->command, CUPS_PHP);
+
+ if (options)
+ cupsdSetStringf(&con->options, " %s %s", filename, options);
+ else
+ cupsdSetStringf(&con->options, " %s", filename);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, "
+ "type=%s/%s) = 1", con, con->http.fd, filename, filestats,
+ type->super, type->type);
+ return (1);
+ }
+#endif /* HAVE_PHP */
+#ifdef HAVE_PYTHON
+ else if (!_cups_strcasecmp(type->type, "x-httpd-python"))
+ {
+ /*
+ * "application/x-httpd-python" is a Python page.
+ */
+
+ cupsdSetString(&con->command, CUPS_PYTHON);
+
+ if (options)
+ cupsdSetStringf(&con->options, " %s %s", filename, options);
+ else
+ cupsdSetStringf(&con->options, " %s", filename);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, "
+ "type=%s/%s) = 1", con, con->http.fd, filename, filestats,
+ type->super, type->type);
+ return (1);
+ }
+#endif /* HAVE_PYTHON */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, "
+ "type=%s/%s) = 0", con, con->http.fd, filename, filestats,
+ type->super, type->type);
+ return (0);
+}
+
+
+/*
+ * 'is_path_absolute()' - Is a path absolute and free of relative elements (i.e. "..").
+ */
+
+static int /* O - 0 if relative, 1 if absolute */
+is_path_absolute(const char *path) /* I - Input path */
+{
+ /*
+ * Check for a leading slash...
+ */
+
+ if (path[0] != '/')
+ return (0);
+
+ /*
+ * Check for "/.." in the path...
+ */
+
+ while ((path = strstr(path, "/..")) != NULL)
+ {
+ if (!path[3] || path[3] == '/')
+ return (0);
+
+ path ++;
+ }
+
+ /*
+ * If we haven't found any relative paths, return 1 indicating an
+ * absolute path...
+ */
+
+ return (1);
+}
+
+
+#ifdef HAVE_SSL
+/*
+ * 'make_certificate()' - Make a self-signed SSL/TLS certificate.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+make_certificate(cupsd_client_t *con) /* I - Client connection */
+{
+#if defined(HAVE_LIBSSL) && defined(HAVE_WAITPID)
+ int pid, /* Process ID of command */
+ status; /* Status of command */
+ char command[1024], /* Command */
+ *argv[12], /* Command-line arguments */
+ *envp[MAX_ENV + 1], /* Environment variables */
+ infofile[1024], /* Type-in information for cert */
+ seedfile[1024]; /* Random number seed file */
+ int envc, /* Number of environment variables */
+ bytes; /* Bytes written */
+ cups_file_t *fp; /* Seed/info file */
+ int infofd; /* Info file descriptor */
+
+
+ /*
+ * Run the "openssl" command to seed the random number generator and
+ * generate a self-signed certificate that is good for 10 years:
+ *
+ * openssl rand -rand seedfile 1
+ *
+ * openssl req -new -x509 -keyout ServerKey \
+ * -out ServerCertificate -days 3650 -nodes
+ *
+ * The seeding step is crucial in ensuring that the openssl command
+ * does not block on systems without sufficient entropy...
+ */
+
+ if (!cupsFileFind("openssl", getenv("PATH"), 1, command, sizeof(command)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "No SSL certificate and openssl command not found!");
+ return (0);
+ }
+
+ if (access("/dev/urandom", 0))
+ {
+ /*
+ * If the system doesn't provide /dev/urandom, then any random source
+ * will probably be blocking-style, so generate some random data to
+ * use as a seed for the certificate. Note that we have already
+ * seeded the random number generator in cupsdInitCerts()...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Seeding the random number generator...");
+
+ /*
+ * Write the seed file...
+ */
+
+ if ((fp = cupsTempFile2(seedfile, sizeof(seedfile))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create seed file %s - %s",
+ seedfile, strerror(errno));
+ return (0);
+ }
+
+ for (bytes = 0; bytes < 262144; bytes ++)
+ cupsFilePutChar(fp, random());
+
+ cupsFileClose(fp);
+
+ /*
+ * Run the openssl command to seed its random number generator...
+ */
+
+ argv[0] = "openssl";
+ argv[1] = "rand";
+ argv[2] = "-rand";
+ argv[3] = seedfile;
+ argv[4] = "1";
+ argv[5] = NULL;
+
+ envc = cupsdLoadEnv(envp, MAX_ENV);
+ envp[envc] = NULL;
+
+ if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, NULL,
+ NULL, &pid))
+ {
+ unlink(seedfile);
+ return (0);
+ }
+
+ while (waitpid(pid, &status, 0) < 0)
+ if (errno != EINTR)
+ {
+ status = 1;
+ break;
+ }
+
+ cupsdFinishProcess(pid, command, sizeof(command), NULL);
+
+ /*
+ * Remove the seed file, as it is no longer needed...
+ */
+
+ unlink(seedfile);
+
+ if (status)
+ {
+ if (WIFEXITED(status))
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to seed random number generator - "
+ "the openssl command stopped with status %d!",
+ WEXITSTATUS(status));
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to seed random number generator - "
+ "the openssl command crashed on signal %d!",
+ WTERMSIG(status));
+
+ return (0);
+ }
+ }
+
+ /*
+ * Create a file with the certificate information fields...
+ *
+ * Note: This assumes that the default questions are asked by the openssl
+ * command...
+ */
+
+ if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create certificate information file %s - %s",
+ infofile, strerror(errno));
+ return (0);
+ }
+
+ cupsFilePrintf(fp, ".\n.\n.\n%s\n.\n%s\n%s\n",
+ ServerName, ServerName, ServerAdmin);
+ cupsFileClose(fp);
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Generating SSL server key and certificate...");
+
+ argv[0] = "openssl";
+ argv[1] = "req";
+ argv[2] = "-new";
+ argv[3] = "-x509";
+ argv[4] = "-keyout";
+ argv[5] = ServerKey;
+ argv[6] = "-out";
+ argv[7] = ServerCertificate;
+ argv[8] = "-days";
+ argv[9] = "3650";
+ argv[10] = "-nodes";
+ argv[11] = NULL;
+
+ cupsdLoadEnv(envp, MAX_ENV);
+
+ infofd = open(infofile, O_RDONLY);
+
+ if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL,
+ NULL, &pid))
+ {
+ close(infofd);
+ unlink(infofile);
+ return (0);
+ }
+
+ close(infofd);
+ unlink(infofile);
+
+ while (waitpid(pid, &status, 0) < 0)
+ if (errno != EINTR)
+ {
+ status = 1;
+ break;
+ }
+
+ cupsdFinishProcess(pid, command, sizeof(command), NULL);
+
+ if (status)
+ {
+ if (WIFEXITED(status))
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create SSL server key and certificate - "
+ "the openssl command stopped with status %d!",
+ WEXITSTATUS(status));
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create SSL server key and certificate - "
+ "the openssl command crashed on signal %d!",
+ WTERMSIG(status));
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...",
+ ServerKey);
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Created SSL server certificate file \"%s\"...",
+ ServerCertificate);
+ }
+
+ return (!status);
+
+#elif defined(HAVE_GNUTLS)
+ gnutls_x509_crt crt; /* Self-signed certificate */
+ gnutls_x509_privkey key; /* Encryption key */
+ cups_lang_t *language; /* Default language info */
+ cups_file_t *fp; /* Key/cert file */
+ unsigned char buffer[8192]; /* Buffer for x509 data */
+ size_t bytes; /* Number of bytes of data */
+ unsigned char serial[4]; /* Serial number buffer */
+ time_t curtime; /* Current time */
+ int result; /* Result of GNU TLS calls */
+
+
+ /*
+ * Create the encryption key...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key...");
+
+ gnutls_x509_privkey_init(&key);
+ gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0);
+
+ /*
+ * Save it...
+ */
+
+ bytes = sizeof(buffer);
+
+ if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM,
+ buffer, &bytes)) < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to export SSL server key - %s",
+ gnutls_strerror(result));
+ gnutls_x509_privkey_deinit(key);
+ return (0);
+ }
+ else if ((fp = cupsFileOpen(ServerKey, "w")) != NULL)
+ {
+ cupsFileWrite(fp, (char *)buffer, bytes);
+ cupsFileClose(fp);
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...",
+ ServerKey);
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create SSL server key file \"%s\" - %s",
+ ServerKey, strerror(errno));
+ gnutls_x509_privkey_deinit(key);
+ return (0);
+ }
+
+ /*
+ * Create the self-signed certificate...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Generating self-signed SSL certificate...");
+
+ language = cupsLangDefault();
+ curtime = time(NULL);
+ serial[0] = curtime >> 24;
+ serial[1] = curtime >> 16;
+ serial[2] = curtime >> 8;
+ serial[3] = curtime;
+
+ gnutls_x509_crt_init(&crt);
+ if (strlen(language->language) == 5)
+ gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
+ language->language + 3, 2);
+ else
+ gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
+ "US", 2);
+ gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0,
+ ServerName, strlen(ServerName));
+ gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
+ ServerName, strlen(ServerName));
+ gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME,
+ 0, "Unknown", 7);
+ gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0,
+ "Unknown", 7);
+ gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0,
+ "Unknown", 7);
+ gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0,
+ ServerAdmin, strlen(ServerAdmin));
+ gnutls_x509_crt_set_key(crt, key);
+ gnutls_x509_crt_set_serial(crt, serial, sizeof(serial));
+ gnutls_x509_crt_set_activation_time(crt, curtime);
+ gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400);
+ gnutls_x509_crt_set_ca_status(crt, 0);
+ gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME,
+ ServerName);
+ gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0);
+ gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT);
+ gnutls_x509_crt_set_version(crt, 3);
+
+ bytes = sizeof(buffer);
+ if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0)
+ gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes);
+
+ gnutls_x509_crt_sign(crt, crt, key);
+
+ /*
+ * Save it...
+ */
+
+ bytes = sizeof(buffer);
+ if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM,
+ buffer, &bytes)) < 0)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to export SSL server certificate - %s",
+ gnutls_strerror(result));
+ else if ((fp = cupsFileOpen(ServerCertificate, "w")) != NULL)
+ {
+ cupsFileWrite(fp, (char *)buffer, bytes);
+ cupsFileClose(fp);
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Created SSL server certificate file \"%s\"...",
+ ServerCertificate);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create SSL server certificate file \"%s\" - %s",
+ ServerCertificate, strerror(errno));
+
+ /*
+ * Cleanup...
+ */
+
+ gnutls_x509_crt_deinit(crt);
+ gnutls_x509_privkey_deinit(key);
+
+ return (1);
+
+#elif defined(HAVE_CDSASSL) && defined(HAVE_WAITPID)
+ int pid, /* Process ID of command */
+ status; /* Status of command */
+ char command[1024], /* Command */
+ *argv[4], /* Command-line arguments */
+ *envp[MAX_ENV + 1], /* Environment variables */
+ keychain[1024], /* Keychain argument */
+ infofile[1024], /* Type-in information for cert */
+ localname[1024], /* Local hostname */
+ *servername; /* Name of server in cert */
+ cups_file_t *fp; /* Seed/info file */
+ int infofd; /* Info file descriptor */
+
+
+ if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName)
+ {
+ snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName);
+ servername = localname;
+ }
+ else
+ servername = con->servername;
+
+ /*
+ * Run the "certtool" command to generate a self-signed certificate...
+ */
+
+ if (!cupsFileFind("certtool", getenv("PATH"), 1, command, sizeof(command)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "No SSL certificate and certtool command not found!");
+ return (0);
+ }
+
+ /*
+ * Create a file with the certificate information fields...
+ *
+ * Note: This assumes that the default questions are asked by the certtool
+ * command...
+ */
+
+ if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create certificate information file %s - %s",
+ infofile, strerror(errno));
+ return (0);
+ }
+
+ cupsFilePrintf(fp, "%s\nr\n\ny\nb\ns\ny\n%s\n\n\n\n\n%s\ny\n",
+ servername, servername, ServerAdmin);
+ cupsFileClose(fp);
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Generating SSL server key and certificate...");
+
+ snprintf(keychain, sizeof(keychain), "k=%s", ServerCertificate);
+
+ argv[0] = "certtool";
+ argv[1] = "c";
+ argv[2] = keychain;
+ argv[3] = NULL;
+
+ cupsdLoadEnv(envp, MAX_ENV);
+
+ infofd = open(infofile, O_RDONLY);
+
+ if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL,
+ NULL, &pid))
+ {
+ close(infofd);
+ unlink(infofile);
+ return (0);
+ }
+
+ close(infofd);
+ unlink(infofile);
+
+ while (waitpid(pid, &status, 0) < 0)
+ if (errno != EINTR)
+ {
+ status = 1;
+ break;
+ }
+
+ cupsdFinishProcess(pid, command, sizeof(command), NULL);
+
+ if (status)
+ {
+ if (WIFEXITED(status))
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create SSL server key and certificate - "
+ "the certtool command stopped with status %d!",
+ WEXITSTATUS(status));
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create SSL server key and certificate - "
+ "the certtool command crashed on signal %d!",
+ WTERMSIG(status));
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Created SSL server certificate file \"%s\"...",
+ ServerCertificate);
+ }
+
+ return (!status);
+
+#else
+ return (0);
+#endif /* HAVE_LIBSSL && HAVE_WAITPID */
+}
+#endif /* HAVE_SSL */
+
+
+/*
+ * 'pipe_command()' - Pipe the output of a command to the remote client.
+ */
+
+static int /* O - Process ID */
+pipe_command(cupsd_client_t *con, /* I - Client connection */
+ int infile, /* I - Standard input for command */
+ int *outfile, /* O - Standard output for command */
+ char *command, /* I - Command to run */
+ char *options, /* I - Options for command */
+ int root) /* I - Run as root? */
+{
+ int i; /* Looping var */
+ int pid; /* Process ID */
+ char *commptr, /* Command string pointer */
+ commch; /* Command string character */
+ char *uriptr; /* URI string pointer */
+ int fds[2]; /* Pipe FDs */
+ int argc; /* Number of arguments */
+ int envc; /* Number of environment variables */
+ char argbuf[10240], /* Argument buffer */
+ *argv[100], /* Argument strings */
+ *envp[MAX_ENV + 20]; /* Environment variables */
+ char auth_type[256], /* AUTH_TYPE environment variable */
+ content_length[1024], /* CONTENT_LENGTH environment variable */
+ content_type[1024], /* CONTENT_TYPE environment variable */
+ http_cookie[32768], /* HTTP_COOKIE environment variable */
+ http_referer[1024], /* HTTP_REFERER environment variable */
+ http_user_agent[1024], /* HTTP_USER_AGENT environment variable */
+ lang[1024], /* LANG environment variable */
+ path_info[1024], /* PATH_INFO environment variable */
+ remote_addr[1024], /* REMOTE_ADDR environment variable */
+ remote_host[1024], /* REMOTE_HOST environment variable */
+ remote_user[1024], /* REMOTE_USER environment variable */
+ script_filename[1024], /* SCRIPT_FILENAME environment variable */
+ script_name[1024], /* SCRIPT_NAME environment variable */
+ server_name[1024], /* SERVER_NAME environment variable */
+ server_port[1024]; /* SERVER_PORT environment variable */
+ ipp_attribute_t *attr; /* attributes-natural-language attribute */
+ void *ccache = NULL; /* Kerberos credentials */
+
+
+ /*
+ * Parse a copy of the options string, which is of the form:
+ *
+ * argument+argument+argument
+ * ?argument+argument+argument
+ * param=value&param=value
+ * ?param=value&param=value
+ * /name?argument+argument+argument
+ * /name?param=value&param=value
+ *
+ * If the string contains an "=" character after the initial name,
+ * then we treat it as a HTTP GET form request and make a copy of
+ * the remaining string for the environment variable.
+ *
+ * The string is always parsed out as command-line arguments, to
+ * be consistent with Apache...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "pipe_command(con=%p(%d), infile=%d, outfile=%p, "
+ "command=\"%s\", options=\"%s\", root=%d)",
+ con, con->http.fd, infile, outfile, command,
+ options ? options : "(null)", root);
+
+ argv[0] = command;
+
+ if (options)
+ {
+ commptr = options;
+ if (*commptr == ' ')
+ commptr ++;
+ strlcpy(argbuf, commptr, sizeof(argbuf));
+ }
+ else
+ argbuf[0] = '\0';
+
+ if (argbuf[0] == '/')
+ {
+ /*
+ * Found some trailing path information, set PATH_INFO...
+ */
+
+ if ((commptr = strchr(argbuf, '?')) == NULL)
+ commptr = argbuf + strlen(argbuf);
+
+ commch = *commptr;
+ *commptr = '\0';
+ snprintf(path_info, sizeof(path_info), "PATH_INFO=%s", argbuf);
+ *commptr = commch;
+ }
+ else
+ {
+ commptr = argbuf;
+ path_info[0] = '\0';
+
+ if (*commptr == ' ')
+ commptr ++;
+ }
+
+ if (*commptr == '?' && con->operation == HTTP_GET && !con->query_string)
+ {
+ commptr ++;
+ cupsdSetStringf(&(con->query_string), "QUERY_STRING=%s", commptr);
+ }
+
+ argc = 1;
+
+ if (*commptr)
+ {
+ argv[argc ++] = commptr;
+
+ for (; *commptr && argc < 99; commptr ++)
+ {
+ /*
+ * Break arguments whenever we see a + or space...
+ */
+
+ if (*commptr == ' ' || *commptr == '+')
+ {
+ while (*commptr == ' ' || *commptr == '+')
+ *commptr++ = '\0';
+
+ /*
+ * If we don't have a blank string, save it as another argument...
+ */
+
+ if (*commptr)
+ {
+ argv[argc] = commptr;
+ argc ++;
+ }
+ else
+ break;
+ }
+ else if (*commptr == '%' && isxdigit(commptr[1] & 255) &&
+ isxdigit(commptr[2] & 255))
+ {
+ /*
+ * Convert the %xx notation to the individual character.
+ */
+
+ if (commptr[1] >= '0' && commptr[1] <= '9')
+ *commptr = (commptr[1] - '0') << 4;
+ else
+ *commptr = (tolower(commptr[1]) - 'a' + 10) << 4;
+
+ if (commptr[2] >= '0' && commptr[2] <= '9')
+ *commptr |= commptr[2] - '0';
+ else
+ *commptr |= tolower(commptr[2]) - 'a' + 10;
+
+ _cups_strcpy(commptr + 1, commptr + 3);
+
+ /*
+ * Check for a %00 and break if that is the case...
+ */
+
+ if (!*commptr)
+ break;
+ }
+ }
+ }
+
+ argv[argc] = NULL;
+
+ /*
+ * Setup the environment variables as needed...
+ */
+
+ if (con->username[0])
+ {
+ snprintf(auth_type, sizeof(auth_type), "AUTH_TYPE=%s",
+ httpGetField(HTTP(con), HTTP_FIELD_AUTHORIZATION));
+
+ if ((uriptr = strchr(auth_type + 10, ' ')) != NULL)
+ *uriptr = '\0';
+ }
+ else
+ auth_type[0] = '\0';
+
+ if (con->request &&
+ (attr = ippFindAttribute(con->request, "attributes-natural-language",
+ IPP_TAG_LANGUAGE)) != NULL)
+ {
+ switch (strlen(attr->values[0].string.text))
+ {
+ default :
+ /*
+ * This is an unknown or badly formatted language code; use
+ * the POSIX locale...
+ */
+
+ strcpy(lang, "LANG=C");
+ break;
+
+ case 2 :
+ /*
+ * Just the language code (ll)...
+ */
+
+ snprintf(lang, sizeof(lang), "LANG=%s.UTF8",
+ attr->values[0].string.text);
+ break;
+
+ case 5 :
+ /*
+ * Language and country code (ll-cc)...
+ */
+
+ snprintf(lang, sizeof(lang), "LANG=%c%c_%c%c.UTF8",
+ attr->values[0].string.text[0],
+ attr->values[0].string.text[1],
+ toupper(attr->values[0].string.text[3] & 255),
+ toupper(attr->values[0].string.text[4] & 255));
+ break;
+ }
+ }
+ else if (con->language)
+ snprintf(lang, sizeof(lang), "LANG=%s.UTF8", con->language->language);
+ else
+ strcpy(lang, "LANG=C");
+
+ strcpy(remote_addr, "REMOTE_ADDR=");
+ httpAddrString(con->http.hostaddr, remote_addr + 12,
+ sizeof(remote_addr) - 12);
+
+ snprintf(remote_host, sizeof(remote_host), "REMOTE_HOST=%s",
+ con->http.hostname);
+
+ snprintf(script_name, sizeof(script_name), "SCRIPT_NAME=%s", con->uri);
+ if ((uriptr = strchr(script_name, '?')) != NULL)
+ *uriptr = '\0';
+
+ snprintf(script_filename, sizeof(script_filename), "SCRIPT_FILENAME=%s%s",
+ DocumentRoot, script_name + 12);
+
+ sprintf(server_port, "SERVER_PORT=%d", con->serverport);
+
+ if (con->http.fields[HTTP_FIELD_HOST][0])
+ {
+ char *nameptr; /* Pointer to ":port" */
+
+ snprintf(server_name, sizeof(server_name), "SERVER_NAME=%s",
+ con->http.fields[HTTP_FIELD_HOST]);
+ if ((nameptr = strrchr(server_name, ':')) != NULL && !strchr(nameptr, ']'))
+ *nameptr = '\0'; /* Strip trailing ":port" */
+ }
+ else
+ snprintf(server_name, sizeof(server_name), "SERVER_NAME=%s",
+ con->servername);
+
+ envc = cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
+
+ if (auth_type[0])
+ envp[envc ++] = auth_type;
+
+ envp[envc ++] = lang;
+ envp[envc ++] = "REDIRECT_STATUS=1";
+ envp[envc ++] = "GATEWAY_INTERFACE=CGI/1.1";
+ envp[envc ++] = server_name;
+ envp[envc ++] = server_port;
+ envp[envc ++] = remote_addr;
+ envp[envc ++] = remote_host;
+ envp[envc ++] = script_name;
+ envp[envc ++] = script_filename;
+
+ if (path_info[0])
+ envp[envc ++] = path_info;
+
+ if (con->username[0])
+ {
+ snprintf(remote_user, sizeof(remote_user), "REMOTE_USER=%s", con->username);
+
+ envp[envc ++] = remote_user;
+ }
+
+ if (con->http.version == HTTP_1_1)
+ envp[envc ++] = "SERVER_PROTOCOL=HTTP/1.1";
+ else if (con->http.version == HTTP_1_0)
+ envp[envc ++] = "SERVER_PROTOCOL=HTTP/1.0";
+ else
+ envp[envc ++] = "SERVER_PROTOCOL=HTTP/0.9";
+
+ if (con->http.cookie)
+ {
+ snprintf(http_cookie, sizeof(http_cookie), "HTTP_COOKIE=%s",
+ con->http.cookie);
+ envp[envc ++] = http_cookie;
+ }
+
+ if (con->http.fields[HTTP_FIELD_USER_AGENT][0])
+ {
+ snprintf(http_user_agent, sizeof(http_user_agent), "HTTP_USER_AGENT=%s",
+ con->http.fields[HTTP_FIELD_USER_AGENT]);
+ envp[envc ++] = http_user_agent;
+ }
+
+ if (con->http.fields[HTTP_FIELD_REFERER][0])
+ {
+ snprintf(http_referer, sizeof(http_referer), "HTTP_REFERER=%s",
+ con->http.fields[HTTP_FIELD_REFERER]);
+ envp[envc ++] = http_referer;
+ }
+
+ if (con->operation == HTTP_GET)
+ {
+ envp[envc ++] = "REQUEST_METHOD=GET";
+
+ if (con->query_string)
+ {
+ /*
+ * Add GET form variables after ?...
+ */
+
+ envp[envc ++] = con->query_string;
+ }
+ else
+ envp[envc ++] = "QUERY_STRING=";
+ }
+ else
+ {
+ sprintf(content_length, "CONTENT_LENGTH=" CUPS_LLFMT,
+ CUPS_LLCAST con->bytes);
+ snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s",
+ con->http.fields[HTTP_FIELD_CONTENT_TYPE]);
+
+ envp[envc ++] = "REQUEST_METHOD=POST";
+ envp[envc ++] = content_length;
+ envp[envc ++] = content_type;
+ }
+
+ /*
+ * Tell the CGI if we are using encryption...
+ */
+
+ if (con->http.tls)
+ envp[envc ++] = "HTTPS=ON";
+
+ /*
+ * Terminate the environment array...
+ */
+
+ envp[envc] = NULL;
+
+ if (LogLevel >= CUPSD_LOG_DEBUG)
+ {
+ for (i = 0; i < argc; i ++)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "[CGI] argv[%d] = \"%s\"", i, argv[i]);
+ for (i = 0; i < envc; i ++)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "[CGI] envp[%d] = \"%s\"", i, envp[i]);
+ }
+
+ /*
+ * Create a pipe for the output...
+ */
+
+ if (cupsdOpenPipe(fds))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "[CGI] Unable to create pipe for %s - %s",
+ argv[0], strerror(errno));
+ return (0);
+ }
+
+ /*
+ * Then execute the command...
+ */
+
+ if (cupsdStartProcess(command, argv, envp, infile, fds[1], CGIPipes[1],
+ -1, -1, root, DefaultProfile, NULL, &pid) < 0)
+ {
+ /*
+ * Error - can't fork!
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "[CGI] Unable to start %s - %s", argv[0],
+ strerror(errno));
+
+ cupsdClosePipe(fds);
+ pid = 0;
+ }
+ else
+ {
+ /*
+ * Fork successful - return the PID...
+ */
+
+ if (con->username[0])
+ cupsdAddCert(pid, con->username, ccache);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "[CGI] Started %s (PID %d)", command, pid);
+
+ *outfile = fds[0];
+ close(fds[1]);
+ }
+
+ return (pid);
+}
+
+
+/*
+ * 'valid_host()' - Is the Host: field valid?
+ */
+
+static int /* O - 1 if valid, 0 if not */
+valid_host(cupsd_client_t *con) /* I - Client connection */
+{
+ cupsd_alias_t *a; /* Current alias */
+ cupsd_netif_t *netif; /* Current network interface */
+ const char *host, /* Host field */
+ *end; /* End character */
+
+
+ host = con->http.fields[HTTP_FIELD_HOST];
+
+ if (httpAddrLocalhost(con->http.hostaddr))
+ {
+ /*
+ * Only allow "localhost" or the equivalent IPv4 or IPv6 numerical
+ * addresses when accessing CUPS via the loopback interface...
+ */
+
+ return (!_cups_strcasecmp(host, "localhost") ||
+ !_cups_strncasecmp(host, "localhost:", 10) ||
+ !_cups_strcasecmp(host, "localhost.") ||
+ !_cups_strncasecmp(host, "localhost.:", 11) ||
+#ifdef __linux
+ !_cups_strcasecmp(host, "localhost.localdomain") ||
+ !_cups_strncasecmp(host, "localhost.localdomain:", 22) ||
+#endif /* __linux */
+ !strcmp(host, "127.0.0.1") ||
+ !strncmp(host, "127.0.0.1:", 10) ||
+ !strcmp(host, "[::1]") ||
+ !strncmp(host, "[::1]:", 6));
+ }
+
+#ifdef HAVE_DNSSD
+ /*
+ * Check if the hostname is something.local (Bonjour); if so, allow it.
+ */
+
+ if ((end = strrchr(host, '.')) != NULL &&
+ (!_cups_strcasecmp(end, ".local") || !_cups_strncasecmp(end, ".local:", 7) ||
+ !_cups_strcasecmp(end, ".local.") || !_cups_strncasecmp(end, ".local.:", 8)))
+ return (1);
+#endif /* HAVE_DNSSD */
+
+ /*
+ * Check if the hostname is an IP address...
+ */
+
+ if (isdigit(*host & 255) || *host == '[')
+ {
+ /*
+ * Possible IPv4/IPv6 address...
+ */
+
+ char temp[1024], /* Temporary string */
+ *ptr; /* Pointer into temporary string */
+ http_addrlist_t *addrlist; /* List of addresses */
+
+
+ strlcpy(temp, host, sizeof(temp));
+ if ((ptr = strrchr(temp, ':')) != NULL && !strchr(ptr, ']'))
+ *ptr = '\0'; /* Strip :port from host value */
+
+ if ((addrlist = httpAddrGetList(temp, AF_UNSPEC, NULL)) != NULL)
+ {
+ /*
+ * Good IPv4/IPv6 address...
+ */
+
+ httpAddrFreeList(addrlist);
+ return (1);
+ }
+ }
+
+ /*
+ * Check for (alias) name matches...
+ */
+
+ for (a = (cupsd_alias_t *)cupsArrayFirst(ServerAlias);
+ a;
+ a = (cupsd_alias_t *)cupsArrayNext(ServerAlias))
+ {
+ /*
+ * "ServerAlias *" allows all host values through...
+ */
+
+ if (!strcmp(a->name, "*"))
+ return (1);
+
+ if (!_cups_strncasecmp(host, a->name, a->namelen))
+ {
+ /*
+ * Prefix matches; check the character at the end - it must be ":", ".",
+ * ".:", or nul...
+ */
+
+ end = host + a->namelen;
+
+ if (!*end || *end == ':' || (*end == '.' && (!end[1] || end[1] == ':')))
+ return (1);
+ }
+ }
+
+#ifdef HAVE_DNSSD
+ for (a = (cupsd_alias_t *)cupsArrayFirst(DNSSDAlias);
+ a;
+ a = (cupsd_alias_t *)cupsArrayNext(DNSSDAlias))
+ {
+ /*
+ * "ServerAlias *" allows all host values through...
+ */
+
+ if (!strcmp(a->name, "*"))
+ return (1);
+
+ if (!_cups_strncasecmp(host, a->name, a->namelen))
+ {
+ /*
+ * Prefix matches; check the character at the end - it must be ":", ".",
+ * ".:", or nul...
+ */
+
+ end = host + a->namelen;
+
+ if (!*end || *end == ':' || (*end == '.' && (!end[1] || end[1] == ':')))
+ return (1);
+ }
+ }
+#endif /* HAVE_DNSSD */
+
+ /*
+ * Check for interface hostname matches...
+ */
+
+ for (netif = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
+ netif;
+ netif = (cupsd_netif_t *)cupsArrayNext(NetIFList))
+ {
+ if (!_cups_strncasecmp(host, netif->hostname, netif->hostlen))
+ {
+ /*
+ * Prefix matches; check the character at the end - it must be ":", ".",
+ * ".:", or nul...
+ */
+
+ end = host + netif->hostlen;
+
+ if (!*end || *end == ':' || (*end == '.' && (!end[1] || end[1] == ':')))
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'write_file()' - Send a file via HTTP.
+ */
+
+static int /* O - 0 on failure, 1 on success */
+write_file(cupsd_client_t *con, /* I - Client connection */
+ http_status_t code, /* I - HTTP status */
+ char *filename, /* I - Filename */
+ char *type, /* I - File type */
+ struct stat *filestats) /* O - File information */
+{
+ con->file = open(filename, O_RDONLY);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "write_file(con=%p(%d), code=%d, filename=\"%s\" (%d), "
+ "type=\"%s\", filestats=%p)", con, con->http.fd,
+ code, filename, con->file, type ? type : "(null)", filestats);
+
+ if (con->file < 0)
+ return (0);
+
+ fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+
+ con->pipe_pid = 0;
+
+ if (!cupsdSendHeader(con, code, type, CUPSD_AUTH_NONE))
+ return (0);
+
+ if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n",
+ httpGetDateString(filestats->st_mtime)) < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "Content-Length: " CUPS_LLFMT "\r\n",
+ CUPS_LLCAST filestats->st_size) < 0)
+ return (0);
+ if (httpPrintf(HTTP(con), "\r\n") < 0)
+ return (0);
+
+ if (cupsdFlushHeader(con) < 0)
+ return (0);
+
+ con->http.data_encoding = HTTP_ENCODE_LENGTH;
+ con->http.data_remaining = filestats->st_size;
+
+ if (con->http.data_remaining <= INT_MAX)
+ con->http._data_remaining = con->http.data_remaining;
+ else
+ con->http._data_remaining = INT_MAX;
+
+ cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient,
+ (cupsd_selfunc_t)cupsdWriteClient, con);
+
+ return (1);
+}
+
+
+/*
+ * 'write_pipe()' - Flag that data is available on the CGI pipe.
+ */
+
+static void
+write_pipe(cupsd_client_t *con) /* I - Client connection */
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "write_pipe(con=%p(%d)) CGI output on fd %d",
+ con, con->http.fd, con->file);
+
+ con->file_ready = 1;
+
+ cupsdRemoveSelect(con->file);
+ cupsdAddSelect(con->http.fd, NULL, (cupsd_selfunc_t)cupsdWriteClient, con);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/client.h b/scheduler/client.h
new file mode 100644
index 000000000..08dcdf190
--- /dev/null
+++ b/scheduler/client.h
@@ -0,0 +1,137 @@
+/*
+ * "$Id$"
+ *
+ * Client definitions for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifdef HAVE_AUTHORIZATION_H
+# include <Security/Authorization.h>
+#endif /* HAVE_AUTHORIZATION_H */
+
+
+/*
+ * HTTP client structure...
+ */
+
+struct cupsd_client_s
+{
+ http_t http; /* HTTP client connection */
+ ipp_t *request, /* IPP request information */
+ *response; /* IPP response information */
+ cupsd_location_t *best; /* Best match for AAA */
+ struct timeval start; /* Request start time */
+ http_state_t operation; /* Request operation */
+ off_t bytes; /* Bytes transferred for this request */
+ int type; /* AuthType for username */
+ char username[256], /* Username from Authorization: line */
+ password[33], /* Password from Authorization: line */
+ uri[HTTP_MAX_URI],
+ /* Localized URL/URI for GET/PUT */
+ *filename, /* Filename of output file */
+ *command, /* Command to run */
+ *options, /* Options for command */
+ *query_string; /* QUERY_STRING environment variable */
+ int file; /* Input/output file */
+ int file_ready; /* Input ready on file/pipe? */
+ int pipe_pid; /* Pipe process ID (or 0 if not a pipe) */
+ int sent_header, /* Non-zero if sent HTTP header */
+ got_fields, /* Non-zero if all fields seen */
+ header_used; /* Number of header bytes used */
+ char header[2048]; /* Header from CGI program */
+ cups_lang_t *language; /* Language to use */
+#ifdef HAVE_SSL
+ int auto_ssl; /* Automatic test for SSL/TLS */
+#endif /* HAVE_SSL */
+ http_addr_t clientaddr; /* Client address */
+ char servername[256];/* Server name for connection */
+ int serverport; /* Server port for connection */
+#ifdef HAVE_GSSAPI
+ int have_gss; /* Have GSS credentials? */
+ uid_t gss_uid; /* User ID for local prints */
+#endif /* HAVE_GSSAPI */
+#ifdef HAVE_AUTHORIZATION_H
+ AuthorizationRef authref; /* Authorization ref */
+#endif /* HAVE_AUTHORIZATION_H */
+};
+
+#define HTTP(con) &((con)->http)
+
+
+/*
+ * HTTP listener structure...
+ */
+
+typedef struct
+{
+ int fd; /* File descriptor for this server */
+ http_addr_t address; /* Bind address of socket */
+ http_encryption_t encryption; /* To encrypt or not to encrypt... */
+} cupsd_listener_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR int ListenBackLog VALUE(SOMAXCONN),
+ /* Max backlog of pending connections */
+ LocalPort VALUE(631),
+ /* Local port to use */
+ RemotePort VALUE(0);
+ /* Remote port to use */
+VAR http_encryption_t LocalEncryption VALUE(HTTP_ENCRYPT_IF_REQUESTED);
+ /* Local port encryption to use */
+VAR cups_array_t *Listeners VALUE(NULL);
+ /* Listening sockets */
+VAR time_t ListeningPaused VALUE(0);
+ /* Time when listening was paused */
+VAR cups_array_t *Clients VALUE(NULL),
+ /* HTTP clients */
+ *ActiveClients VALUE(NULL);
+ /* Active HTTP clients */
+VAR char *ServerHeader VALUE(NULL);
+ /* Server header in requests */
+VAR int CGIPipes[2] VALUE2(-1,-1);
+ /* Pipes for CGI error/debug output */
+VAR cupsd_statbuf_t *CGIStatusBuffer VALUE(NULL);
+ /* Status buffer for pipes */
+
+
+/*
+ * Prototypes...
+ */
+
+extern void cupsdAcceptClient(cupsd_listener_t *lis);
+extern void cupsdCloseAllClients(void);
+extern int cupsdCloseClient(cupsd_client_t *con);
+extern void cupsdDeleteAllListeners(void);
+extern int cupsdFlushHeader(cupsd_client_t *con);
+extern void cupsdPauseListening(void);
+extern int cupsdProcessIPPRequest(cupsd_client_t *con);
+extern void cupsdReadClient(cupsd_client_t *con);
+extern void cupsdResumeListening(void);
+extern int cupsdSendCommand(cupsd_client_t *con, char *command,
+ char *options, int root);
+extern int cupsdSendError(cupsd_client_t *con, http_status_t code,
+ int auth_type);
+extern int cupsdSendHeader(cupsd_client_t *con, http_status_t code,
+ char *type, int auth_type);
+extern void cupsdShutdownClient(cupsd_client_t *con);
+extern void cupsdStartListening(void);
+extern void cupsdStopListening(void);
+extern void cupsdUpdateCGI(void);
+extern void cupsdWriteClient(cupsd_client_t *con);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/conf.c b/scheduler/conf.c
new file mode 100644
index 000000000..c9901d031
--- /dev/null
+++ b/scheduler/conf.c
@@ -0,0 +1,4202 @@
+/*
+ * "$Id$"
+ *
+ * Configuration routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdAddAlias() - Add a host alias.
+ * cupsdCheckPermissions() - Fix the mode and ownership of a file or
+ * directory.
+ * cupsdFreeAliases() - Free all of the alias entries.
+ * cupsdReadConfiguration() - Read the cupsd.conf file.
+ * get_address() - Get an address + port number from a line.
+ * get_addr_and_mask() - Get an IP address and netmask.
+ * mime_error_cb() - Log a MIME error.
+ * parse_aaa() - Parse authentication, authorization, and access
+ * control lines.
+ * parse_fatal_errors() - Parse FatalErrors values in a string.
+ * parse_groups() - Parse system group names in a string.
+ * parse_protocols() - Parse browse protocols in a string.
+ * read_configuration() - Read a configuration file.
+ * read_location() - Read a <Location path> definition.
+ * read_policy() - Read a <Policy name> definition.
+ * set_policy_defaults() - Set default policy values as needed.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <stdarg.h>
+#include <grp.h>
+#include <sys/utsname.h>
+#include <syslog.h>
+
+#ifdef HAVE_LIBPAPER
+# include <paper.h>
+#endif /* HAVE_LIBPAPER */
+
+
+/*
+ * Possibly missing network definitions...
+ */
+
+#ifndef INADDR_NONE
+# define INADDR_NONE 0xffffffff
+#endif /* !INADDR_NONE */
+
+
+/*
+ * Configuration variable structure...
+ */
+
+typedef enum
+{
+ CUPSD_VARTYPE_INTEGER, /* Integer option */
+ CUPSD_VARTYPE_STRING, /* String option */
+ CUPSD_VARTYPE_BOOLEAN, /* Boolean option */
+ CUPSD_VARTYPE_PATHNAME /* File/directory name option */
+} cupsd_vartype_t;
+
+typedef struct
+{
+ char *name; /* Name of variable */
+ void *ptr; /* Pointer to variable */
+ cupsd_vartype_t type; /* Type (int, string, address) */
+} cupsd_var_t;
+
+
+/*
+ * Local globals...
+ */
+
+static const cupsd_var_t variables[] =
+{
+ { "AccessLog", &AccessLog, CUPSD_VARTYPE_STRING },
+ { "AutoPurgeJobs", &JobAutoPurge, CUPSD_VARTYPE_BOOLEAN },
+#ifdef HAVE_DNSSD
+ { "BrowseDNSSDRegType", &DNSSDRegType, CUPSD_VARTYPE_STRING },
+#endif /* HAVE_DNSSD */
+ { "BrowseInterval", &BrowseInterval, CUPSD_VARTYPE_INTEGER },
+#ifdef HAVE_LDAP
+ { "BrowseLDAPBindDN", &BrowseLDAPBindDN, CUPSD_VARTYPE_STRING },
+# ifdef HAVE_LDAP_SSL
+ { "BrowseLDAPCACertFile", &BrowseLDAPCACertFile, CUPSD_VARTYPE_PATHNAME },
+# endif /* HAVE_LDAP_SSL */
+ { "BrowseLDAPDN", &BrowseLDAPDN, CUPSD_VARTYPE_STRING },
+ { "BrowseLDAPPassword", &BrowseLDAPPassword, CUPSD_VARTYPE_STRING },
+ { "BrowseLDAPServer", &BrowseLDAPServer, CUPSD_VARTYPE_STRING },
+#endif /* HAVE_LDAP */
+ { "BrowseLocalOptions", &BrowseLocalOptions, CUPSD_VARTYPE_STRING },
+ { "BrowsePort", &BrowsePort, CUPSD_VARTYPE_INTEGER },
+ { "BrowseRemoteOptions", &BrowseRemoteOptions, CUPSD_VARTYPE_STRING },
+ { "BrowseShortNames", &BrowseShortNames, CUPSD_VARTYPE_BOOLEAN },
+ { "BrowseTimeout", &BrowseTimeout, CUPSD_VARTYPE_INTEGER },
+ { "BrowseWebIF", &BrowseWebIF, CUPSD_VARTYPE_BOOLEAN },
+ { "Browsing", &Browsing, CUPSD_VARTYPE_BOOLEAN },
+ { "CacheDir", &CacheDir, CUPSD_VARTYPE_STRING },
+ { "Classification", &Classification, CUPSD_VARTYPE_STRING },
+ { "ClassifyOverride", &ClassifyOverride, CUPSD_VARTYPE_BOOLEAN },
+ { "ConfigFilePerm", &ConfigFilePerm, CUPSD_VARTYPE_INTEGER },
+ { "DataDir", &DataDir, CUPSD_VARTYPE_STRING },
+ { "DefaultLanguage", &DefaultLanguage, CUPSD_VARTYPE_STRING },
+ { "DefaultLeaseDuration", &DefaultLeaseDuration, CUPSD_VARTYPE_INTEGER },
+ { "DefaultPaperSize", &DefaultPaperSize, CUPSD_VARTYPE_STRING },
+ { "DefaultPolicy", &DefaultPolicy, CUPSD_VARTYPE_STRING },
+ { "DefaultShared", &DefaultShared, CUPSD_VARTYPE_BOOLEAN },
+ { "DirtyCleanInterval", &DirtyCleanInterval, CUPSD_VARTYPE_INTEGER },
+ { "DocumentRoot", &DocumentRoot, CUPSD_VARTYPE_STRING },
+ { "ErrorLog", &ErrorLog, CUPSD_VARTYPE_STRING },
+ { "ErrorPolicy", &ErrorPolicy, CUPSD_VARTYPE_STRING },
+ { "FileDevice", &FileDevice, CUPSD_VARTYPE_BOOLEAN },
+ { "FilterLimit", &FilterLimit, CUPSD_VARTYPE_INTEGER },
+ { "FilterNice", &FilterNice, CUPSD_VARTYPE_INTEGER },
+ { "FontPath", &FontPath, CUPSD_VARTYPE_STRING },
+ { "HideImplicitMembers", &HideImplicitMembers, CUPSD_VARTYPE_BOOLEAN },
+ { "ImplicitClasses", &ImplicitClasses, CUPSD_VARTYPE_BOOLEAN },
+ { "ImplicitAnyClasses", &ImplicitAnyClasses, CUPSD_VARTYPE_BOOLEAN },
+ { "JobKillDelay", &JobKillDelay, CUPSD_VARTYPE_INTEGER },
+ { "JobRetryLimit", &JobRetryLimit, CUPSD_VARTYPE_INTEGER },
+ { "JobRetryInterval", &JobRetryInterval, CUPSD_VARTYPE_INTEGER },
+ { "KeepAliveTimeout", &KeepAliveTimeout, CUPSD_VARTYPE_INTEGER },
+ { "KeepAlive", &KeepAlive, CUPSD_VARTYPE_BOOLEAN },
+#ifdef HAVE_LAUNCHD
+ { "LaunchdTimeout", &LaunchdTimeout, CUPSD_VARTYPE_INTEGER },
+#endif /* HAVE_LAUNCHD */
+ { "LimitRequestBody", &MaxRequestSize, CUPSD_VARTYPE_INTEGER },
+ { "ListenBackLog", &ListenBackLog, CUPSD_VARTYPE_INTEGER },
+ { "LogDebugHistory", &LogDebugHistory, CUPSD_VARTYPE_INTEGER },
+ { "LogFilePerm", &LogFilePerm, CUPSD_VARTYPE_INTEGER },
+ { "LPDConfigFile", &LPDConfigFile, CUPSD_VARTYPE_STRING },
+ { "MaxActiveJobs", &MaxActiveJobs, CUPSD_VARTYPE_INTEGER },
+ { "MaxClients", &MaxClients, CUPSD_VARTYPE_INTEGER },
+ { "MaxClientsPerHost", &MaxClientsPerHost, CUPSD_VARTYPE_INTEGER },
+ { "MaxCopies", &MaxCopies, CUPSD_VARTYPE_INTEGER },
+ { "MaxEvents", &MaxEvents, CUPSD_VARTYPE_INTEGER },
+ { "MaxJobs", &MaxJobs, CUPSD_VARTYPE_INTEGER },
+ { "MaxJobsPerPrinter", &MaxJobsPerPrinter, CUPSD_VARTYPE_INTEGER },
+ { "MaxJobsPerUser", &MaxJobsPerUser, CUPSD_VARTYPE_INTEGER },
+ { "MaxLeaseDuration", &MaxLeaseDuration, CUPSD_VARTYPE_INTEGER },
+ { "MaxLogSize", &MaxLogSize, CUPSD_VARTYPE_INTEGER },
+ { "MaxRequestSize", &MaxRequestSize, CUPSD_VARTYPE_INTEGER },
+ { "MaxSubscriptions", &MaxSubscriptions, CUPSD_VARTYPE_INTEGER },
+ { "MaxSubscriptionsPerJob", &MaxSubscriptionsPerJob, CUPSD_VARTYPE_INTEGER },
+ { "MaxSubscriptionsPerPrinter",&MaxSubscriptionsPerPrinter, CUPSD_VARTYPE_INTEGER },
+ { "MaxSubscriptionsPerUser", &MaxSubscriptionsPerUser, CUPSD_VARTYPE_INTEGER },
+ { "MultipleOperationTimeout", &MultipleOperationTimeout, CUPSD_VARTYPE_INTEGER },
+ { "PageLog", &PageLog, CUPSD_VARTYPE_STRING },
+ { "PageLogFormat", &PageLogFormat, CUPSD_VARTYPE_STRING },
+ { "PreserveJobFiles", &JobFiles, CUPSD_VARTYPE_BOOLEAN },
+ { "PreserveJobHistory", &JobHistory, CUPSD_VARTYPE_BOOLEAN },
+ { "Printcap", &Printcap, CUPSD_VARTYPE_STRING },
+ { "PrintcapGUI", &PrintcapGUI, CUPSD_VARTYPE_STRING },
+ { "ReloadTimeout", &ReloadTimeout, CUPSD_VARTYPE_INTEGER },
+ { "RemoteRoot", &RemoteRoot, CUPSD_VARTYPE_STRING },
+ { "RequestRoot", &RequestRoot, CUPSD_VARTYPE_STRING },
+ { "RIPCache", &RIPCache, CUPSD_VARTYPE_STRING },
+ { "RootCertDuration", &RootCertDuration, CUPSD_VARTYPE_INTEGER },
+ { "ServerAdmin", &ServerAdmin, CUPSD_VARTYPE_STRING },
+ { "ServerBin", &ServerBin, CUPSD_VARTYPE_PATHNAME },
+#ifdef HAVE_SSL
+ { "ServerCertificate", &ServerCertificate, CUPSD_VARTYPE_PATHNAME },
+# if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
+ { "ServerKey", &ServerKey, CUPSD_VARTYPE_PATHNAME },
+# endif /* HAVE_LIBSSL || HAVE_GNUTLS */
+#endif /* HAVE_SSL */
+ { "ServerName", &ServerName, CUPSD_VARTYPE_STRING },
+ { "ServerRoot", &ServerRoot, CUPSD_VARTYPE_PATHNAME },
+ { "SMBConfigFile", &SMBConfigFile, CUPSD_VARTYPE_STRING },
+ { "StateDir", &StateDir, CUPSD_VARTYPE_STRING },
+#ifdef HAVE_AUTHORIZATION_H
+ { "SystemGroupAuthKey", &SystemGroupAuthKey, CUPSD_VARTYPE_STRING },
+#endif /* HAVE_AUTHORIZATION_H */
+ { "TempDir", &TempDir, CUPSD_VARTYPE_PATHNAME },
+ { "Timeout", &Timeout, CUPSD_VARTYPE_INTEGER },
+ { "UseNetworkDefault", &UseNetworkDefault, CUPSD_VARTYPE_BOOLEAN },
+ { "WebInterface", &WebInterface, CUPSD_VARTYPE_BOOLEAN }
+};
+#define NUM_VARS (sizeof(variables) / sizeof(variables[0]))
+
+
+static const unsigned ones[4] =
+ {
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
+ };
+static const unsigned zeros[4] =
+ {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000
+ };
+
+
+/*
+ * Local functions...
+ */
+
+static http_addrlist_t *get_address(const char *value, int defport);
+static int get_addr_and_mask(const char *value, unsigned *ip,
+ unsigned *mask);
+static void mime_error_cb(void *ctx, const char *message);
+static int parse_aaa(cupsd_location_t *loc, char *line,
+ char *value, int linenum);
+static int parse_fatal_errors(const char *s);
+static int parse_groups(const char *s);
+static int parse_protocols(const char *s);
+static int read_configuration(cups_file_t *fp);
+static int read_location(cups_file_t *fp, char *name, int linenum);
+static int read_policy(cups_file_t *fp, char *name, int linenum);
+static void set_policy_defaults(cupsd_policy_t *pol);
+
+
+/*
+ * 'cupsdAddAlias()' - Add a host alias.
+ */
+
+void
+cupsdAddAlias(cups_array_t *aliases, /* I - Array of aliases */
+ const char *name) /* I - Name to add */
+{
+ cupsd_alias_t *a; /* New alias */
+ size_t namelen; /* Length of name */
+
+
+ namelen = strlen(name);
+
+ if ((a = (cupsd_alias_t *)malloc(sizeof(cupsd_alias_t) + namelen)) == NULL)
+ return;
+
+ a->namelen = namelen;
+ strcpy(a->name, name); /* OK since a->name is allocated */
+
+ cupsArrayAdd(aliases, a);
+}
+
+
+/*
+ * 'cupsdCheckPermissions()' - Fix the mode and ownership of a file or directory.
+ */
+
+int /* O - 0 on success, -1 on error, 1 on warning */
+cupsdCheckPermissions(
+ const char *filename, /* I - File/directory name */
+ const char *suffix, /* I - Additional file/directory name */
+ int mode, /* I - Permissions */
+ int user, /* I - Owner */
+ int group, /* I - Group */
+ int is_dir, /* I - 1 = directory, 0 = file */
+ int create_dir) /* I - 1 = create directory, -1 = create w/o logging, 0 = not */
+{
+ int dir_created = 0; /* Did we create a directory? */
+ char pathname[1024]; /* File name with prefix */
+ struct stat fileinfo; /* Stat buffer */
+ int is_symlink; /* Is "filename" a symlink? */
+
+
+ /*
+ * Prepend the given root to the filename before testing it...
+ */
+
+ if (suffix)
+ {
+ snprintf(pathname, sizeof(pathname), "%s/%s", filename, suffix);
+ filename = pathname;
+ }
+
+ /*
+ * See if we can stat the file/directory...
+ */
+
+ if (lstat(filename, &fileinfo))
+ {
+ if (errno == ENOENT && create_dir)
+ {
+ if (create_dir > 0)
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Creating missing directory \"%s\"",
+ filename);
+
+ if (mkdir(filename, mode))
+ {
+ if (create_dir > 0)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create directory \"%s\" - %s", filename,
+ strerror(errno));
+ else
+ syslog(LOG_ERR, "Unable to create directory \"%s\" - %s", filename,
+ strerror(errno));
+
+ return (-1);
+ }
+
+ dir_created = 1;
+ fileinfo.st_mode = mode | S_IFDIR;
+ }
+ else
+ return (create_dir ? -1 : 1);
+ }
+
+ if ((is_symlink = S_ISLNK(fileinfo.st_mode)) != 0)
+ {
+ if (stat(filename, &fileinfo))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is a bad symlink - %s",
+ filename, strerror(errno));
+ return (-1);
+ }
+ }
+
+ /*
+ * Make sure it's a regular file or a directory as needed...
+ */
+
+ if (!dir_created && !is_dir && !S_ISREG(fileinfo.st_mode))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is not a regular file.", filename);
+ return (-1);
+ }
+
+ if (!dir_created && is_dir && !S_ISDIR(fileinfo.st_mode))
+ {
+ if (create_dir >= 0)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is not a directory.", filename);
+ else
+ syslog(LOG_ERR, "\"%s\" is not a directory.", filename);
+
+ return (-1);
+ }
+
+ /*
+ * If the filename is a symlink, do not change permissions (STR #2937)...
+ */
+
+ if (is_symlink)
+ return (0);
+
+ /*
+ * Fix owner, group, and mode as needed...
+ */
+
+ if (dir_created || fileinfo.st_uid != user || fileinfo.st_gid != group)
+ {
+ if (create_dir >= 0)
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Repairing ownership of \"%s\"",
+ filename);
+
+ if (chown(filename, user, group) && !getuid())
+ {
+ if (create_dir >= 0)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to change ownership of \"%s\" - %s", filename,
+ strerror(errno));
+ else
+ syslog(LOG_ERR, "Unable to change ownership of \"%s\" - %s", filename,
+ strerror(errno));
+
+ return (1);
+ }
+ }
+
+ if (dir_created || (fileinfo.st_mode & 07777) != mode)
+ {
+ if (create_dir >= 0)
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Repairing access permissions of \"%s\"",
+ filename);
+
+ if (chmod(filename, mode))
+ {
+ if (create_dir >= 0)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to change permissions of \"%s\" - %s", filename,
+ strerror(errno));
+ else
+ syslog(LOG_ERR, "Unable to change permissions of \"%s\" - %s", filename,
+ strerror(errno));
+
+ return (1);
+ }
+ }
+
+ /*
+ * Everything is OK...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'cupsdFreeAliases()' - Free all of the alias entries.
+ */
+
+void
+cupsdFreeAliases(cups_array_t *aliases) /* I - Array of aliases */
+{
+ cupsd_alias_t *a; /* Current alias */
+
+
+ for (a = (cupsd_alias_t *)cupsArrayFirst(aliases);
+ a;
+ a = (cupsd_alias_t *)cupsArrayNext(aliases))
+ free(a);
+
+ cupsArrayDelete(aliases);
+}
+
+
+/*
+ * 'cupsdReadConfiguration()' - Read the cupsd.conf file.
+ */
+
+int /* O - 1 on success, 0 otherwise */
+cupsdReadConfiguration(void)
+{
+ int i; /* Looping var */
+ cups_file_t *fp; /* Configuration file */
+ int status; /* Return status */
+ char temp[1024], /* Temporary buffer */
+ mimedir[1024], /* MIME directory */
+ *slash; /* Directory separator */
+ cups_lang_t *language; /* Language */
+ struct passwd *user; /* Default user */
+ struct group *group; /* Default group */
+ char *old_serverroot, /* Old ServerRoot */
+ *old_requestroot; /* Old RequestRoot */
+ int old_remote_port; /* Old RemotePort */
+ const char *tmpdir; /* TMPDIR environment variable */
+ struct stat tmpinfo; /* Temporary directory info */
+ cupsd_policy_t *p; /* Policy */
+
+
+ /*
+ * Save the old root paths...
+ */
+
+ old_serverroot = NULL;
+ cupsdSetString(&old_serverroot, ServerRoot);
+ old_requestroot = NULL;
+ cupsdSetString(&old_requestroot, RequestRoot);
+
+ /*
+ * Reset the server configuration data...
+ */
+
+ cupsdDeleteAllLocations();
+
+ if (NumBrowsers > 0)
+ {
+ free(Browsers);
+ Browsers = NULL;
+
+ NumBrowsers = 0;
+ }
+
+ if (NumPolled > 0)
+ {
+ free(Polled);
+
+ NumPolled = 0;
+ }
+
+ if (NumRelays > 0)
+ {
+ for (i = 0; i < NumRelays; i ++)
+ cupsArrayDelete(Relays[i].from);
+
+ free(Relays);
+
+ NumRelays = 0;
+ }
+
+ cupsdDeleteAllListeners();
+
+ old_remote_port = RemotePort;
+ RemotePort = 0;
+
+ /*
+ * String options...
+ */
+
+ cupsdFreeAliases(ServerAlias);
+ ServerAlias = NULL;
+
+ cupsdClearString(&ServerName);
+ cupsdClearString(&ServerAdmin);
+ cupsdSetString(&ServerBin, CUPS_SERVERBIN);
+ cupsdSetString(&RequestRoot, CUPS_REQUESTS);
+ cupsdSetString(&CacheDir, CUPS_CACHEDIR);
+ cupsdSetString(&DataDir, CUPS_DATADIR);
+ cupsdSetString(&DocumentRoot, CUPS_DOCROOT);
+ cupsdSetString(&AccessLog, CUPS_LOGDIR "/access_log");
+ cupsdSetString(&ErrorLog, CUPS_LOGDIR "/error_log");
+ cupsdSetString(&PageLog, CUPS_LOGDIR "/page_log");
+ cupsdSetString(&PageLogFormat,
+ "%p %u %j %T %P %C %{job-billing} "
+ "%{job-originating-host-name} %{job-name} %{media} %{sides}");
+ cupsdSetString(&Printcap, CUPS_DEFAULT_PRINTCAP);
+ cupsdSetString(&PrintcapGUI, "/usr/bin/glpoptions");
+ cupsdSetString(&FontPath, CUPS_FONTPATH);
+ cupsdSetString(&RemoteRoot, "remroot");
+ cupsdSetString(&ServerHeader, "CUPS/1.4");
+ cupsdSetString(&StateDir, CUPS_STATEDIR);
+
+ if (!strcmp(CUPS_DEFAULT_PRINTCAP, "/etc/printers.conf"))
+ PrintcapFormat = PRINTCAP_SOLARIS;
+ else if (!strcmp(CUPS_DEFAULT_PRINTCAP,
+ "/Library/Preferences/org.cups.printers.plist"))
+ PrintcapFormat = PRINTCAP_PLIST;
+ else
+ PrintcapFormat = PRINTCAP_BSD;
+
+ strlcpy(temp, ConfigurationFile, sizeof(temp));
+ if ((slash = strrchr(temp, '/')) != NULL)
+ *slash = '\0';
+
+ cupsdSetString(&ServerRoot, temp);
+
+ cupsdClearString(&Classification);
+ ClassifyOverride = 0;
+
+#ifdef HAVE_SSL
+# ifdef HAVE_CDSASSL
+ cupsdSetString(&ServerCertificate, "/Library/Keychains/System.keychain");
+# else
+ cupsdSetString(&ServerCertificate, "ssl/server.crt");
+ cupsdSetString(&ServerKey, "ssl/server.key");
+# endif /* HAVE_CDSASSL */
+#endif /* HAVE_SSL */
+
+ language = cupsLangDefault();
+
+ if (!strcmp(language->language, "C") || !strcmp(language->language, "POSIX"))
+ cupsdSetString(&DefaultLanguage, "en");
+ else
+ cupsdSetString(&DefaultLanguage, language->language);
+
+ cupsdClearString(&DefaultPaperSize);
+
+ cupsdSetString(&RIPCache, "128m");
+
+ cupsdSetString(&TempDir, NULL);
+
+ /*
+ * Find the default user...
+ */
+
+ if ((user = getpwnam(CUPS_DEFAULT_USER)) != NULL)
+ User = user->pw_uid;
+ else
+ {
+ /*
+ * Use the (historical) NFS nobody user ID (-2 as a 16-bit twos-
+ * complement number...)
+ */
+
+ User = 65534;
+ }
+
+ endpwent();
+
+ /*
+ * Find the default group...
+ */
+
+ group = getgrnam(CUPS_DEFAULT_GROUP);
+ endgrent();
+
+ if (group)
+ Group = group->gr_gid;
+ else
+ {
+ /*
+ * Fallback to group "nobody"...
+ */
+
+ group = getgrnam("nobody");
+ endgrent();
+
+ if (group)
+ Group = group->gr_gid;
+ else
+ {
+ /*
+ * Use the (historical) NFS nobody group ID (-2 as a 16-bit twos-
+ * complement number...)
+ */
+
+ Group = 65534;
+ }
+ }
+
+ /*
+ * Numeric options...
+ */
+
+ AccessLogLevel = CUPSD_ACCESSLOG_ACTIONS;
+ ConfigFilePerm = CUPS_DEFAULT_CONFIG_FILE_PERM;
+ FatalErrors = parse_fatal_errors(CUPS_DEFAULT_FATAL_ERRORS);
+ DefaultAuthType = CUPSD_AUTH_BASIC;
+#ifdef HAVE_SSL
+ DefaultEncryption = HTTP_ENCRYPT_REQUIRED;
+ SSLOptions = CUPSD_SSL_NONE;
+#endif /* HAVE_SSL */
+ DirtyCleanInterval = DEFAULT_KEEPALIVE;
+ JobKillDelay = DEFAULT_TIMEOUT;
+ JobRetryLimit = 5;
+ JobRetryInterval = 300;
+ FileDevice = FALSE;
+ FilterLevel = 0;
+ FilterLimit = 0;
+ FilterNice = 0;
+ HostNameLookups = FALSE;
+ ImplicitClasses = CUPS_DEFAULT_IMPLICIT_CLASSES;
+ ImplicitAnyClasses = FALSE;
+ HideImplicitMembers = TRUE;
+ KeepAlive = TRUE;
+ KeepAliveTimeout = DEFAULT_KEEPALIVE;
+ ListenBackLog = SOMAXCONN;
+ LogDebugHistory = 200;
+ LogFilePerm = CUPS_DEFAULT_LOG_FILE_PERM;
+ LogLevel = CUPSD_LOG_WARN;
+ LogTimeFormat = CUPSD_TIME_STANDARD;
+ MaxClients = 100;
+ MaxClientsPerHost = 0;
+ MaxLogSize = 1024 * 1024;
+ MaxRequestSize = 0;
+ MultipleOperationTimeout = DEFAULT_TIMEOUT;
+ ReloadTimeout = DEFAULT_KEEPALIVE;
+ RootCertDuration = 300;
+ Timeout = DEFAULT_TIMEOUT;
+ NumSystemGroups = 0;
+ WebInterface = CUPS_DEFAULT_WEBIF;
+
+ BrowseInterval = DEFAULT_INTERVAL;
+ BrowsePort = ippPort();
+ BrowseLocalProtocols = parse_protocols(CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS);
+ BrowseRemoteProtocols = parse_protocols(CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS);
+ BrowseShortNames = CUPS_DEFAULT_BROWSE_SHORT_NAMES;
+ BrowseTimeout = DEFAULT_TIMEOUT;
+ BrowseWebIF = FALSE;
+ Browsing = CUPS_DEFAULT_BROWSING;
+ DefaultShared = CUPS_DEFAULT_DEFAULT_SHARED;
+
+#ifdef HAVE_DNSSD
+ cupsdSetString(&DNSSDRegType, "_ipp._tcp,_cups");
+#endif /* HAVE_DNSSD */
+
+ cupsdSetString(&LPDConfigFile, CUPS_DEFAULT_LPD_CONFIG_FILE);
+ cupsdSetString(&SMBConfigFile, CUPS_DEFAULT_SMB_CONFIG_FILE);
+
+ cupsdClearString(&BrowseLocalOptions);
+ cupsdClearString(&BrowseRemoteOptions);
+
+ cupsdSetString(&ErrorPolicy, "stop-printer");
+
+#ifdef HAVE_LDAP
+ cupsdClearString(&BrowseLDAPBindDN);
+ cupsdClearString(&BrowseLDAPDN);
+ cupsdClearString(&BrowseLDAPPassword);
+ cupsdClearString(&BrowseLDAPServer);
+# ifdef HAVE_LDAP_SSL
+ cupsdClearString(&BrowseLDAPCACertFile);
+# endif /* HAVE_LDAP_SSL */
+#endif /* HAVE_LDAP */
+
+ JobHistory = DEFAULT_HISTORY;
+ JobFiles = DEFAULT_FILES;
+ JobAutoPurge = 0;
+ MaxJobs = 500;
+ MaxActiveJobs = 0;
+ MaxJobsPerUser = 0;
+ MaxJobsPerPrinter = 0;
+ MaxCopies = CUPS_DEFAULT_MAX_COPIES;
+
+ cupsdDeleteAllPolicies();
+ cupsdClearString(&DefaultPolicy);
+
+#ifdef HAVE_AUTHORIZATION_H
+ cupsdClearString(&SystemGroupAuthKey);
+#endif /* HAVE_AUTHORIZATION_H */
+
+ MaxSubscriptions = 100;
+ MaxSubscriptionsPerJob = 0;
+ MaxSubscriptionsPerPrinter = 0;
+ MaxSubscriptionsPerUser = 0;
+ DefaultLeaseDuration = 86400;
+ MaxLeaseDuration = 0;
+
+#ifdef HAVE_LAUNCHD
+ LaunchdTimeout = DEFAULT_TIMEOUT + 10;
+#endif /* HAVE_LAUNCHD */
+
+ /*
+ * Setup environment variables...
+ */
+
+ cupsdInitEnv();
+
+ /*
+ * Read the configuration file...
+ */
+
+ if ((fp = cupsFileOpen(ConfigurationFile, "r")) == NULL)
+ return (0);
+
+ status = read_configuration(fp);
+
+ cupsFileClose(fp);
+
+ if (!status)
+ return (0);
+
+ RunUser = getuid();
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Remote access is %s.",
+ RemotePort ? "enabled" : "disabled");
+
+ if (!RemotePort)
+ BrowseLocalProtocols = 0; /* Disable sharing - no remote access */
+
+ /*
+ * See if the ServerName is an IP address...
+ */
+
+ if (ServerName)
+ {
+ if (!ServerAlias)
+ ServerAlias = cupsArrayNew(NULL, NULL);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s", ServerName);
+ }
+ else
+ {
+ if (gethostname(temp, sizeof(temp)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get hostname: %s",
+ strerror(errno));
+ strlcpy(temp, "localhost", sizeof(temp));
+ }
+
+ cupsdSetString(&ServerName, temp);
+
+ if (!ServerAlias)
+ ServerAlias = cupsArrayNew(NULL, NULL);
+
+ cupsdAddAlias(ServerAlias, temp);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s", temp);
+
+ if (HostNameLookups || RemotePort)
+ {
+ struct hostent *host; /* Host entry to get FQDN */
+
+ if ((host = gethostbyname(temp)) != NULL)
+ {
+ if (_cups_strcasecmp(temp, host->h_name))
+ {
+ cupsdSetString(&ServerName, host->h_name);
+ cupsdAddAlias(ServerAlias, host->h_name);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s",
+ host->h_name);
+ }
+
+ if (host->h_aliases)
+ {
+ for (i = 0; host->h_aliases[i]; i ++)
+ if (_cups_strcasecmp(temp, host->h_aliases[i]))
+ {
+ cupsdAddAlias(ServerAlias, host->h_aliases[i]);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s",
+ host->h_aliases[i]);
+ }
+ }
+ }
+ }
+
+ /*
+ * Make sure we have the base hostname added as an alias, too!
+ */
+
+ if ((slash = strchr(temp, '.')) != NULL)
+ {
+ *slash = '\0';
+ cupsdAddAlias(ServerAlias, temp);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s", temp);
+ }
+ }
+
+ for (slash = ServerName; isdigit(*slash & 255) || *slash == '.'; slash ++);
+
+ ServerNameIsIP = !*slash;
+
+ /*
+ * Make sure ServerAdmin is initialized...
+ */
+
+ if (!ServerAdmin)
+ cupsdSetStringf(&ServerAdmin, "root@%s", ServerName);
+
+ /*
+ * Use the default system group if none was supplied in cupsd.conf...
+ */
+
+ if (NumSystemGroups == 0)
+ {
+ if (!parse_groups(CUPS_DEFAULT_SYSTEM_GROUPS))
+ {
+ /*
+ * Find the group associated with GID 0...
+ */
+
+ group = getgrgid(0);
+ endgrent();
+
+ if (group != NULL)
+ cupsdSetString(&SystemGroups[0], group->gr_name);
+ else
+ cupsdSetString(&SystemGroups[0], "unknown");
+
+ SystemGroupIDs[0] = 0;
+ NumSystemGroups = 1;
+ }
+ }
+
+ /*
+ * Get the access control list for browsing...
+ */
+
+ BrowseACL = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL");
+
+ /*
+ * Open the system log for cupsd if necessary...
+ */
+
+#ifdef HAVE_VSYSLOG
+ if (!strcmp(AccessLog, "syslog") ||
+ !strcmp(ErrorLog, "syslog") ||
+ !strcmp(PageLog, "syslog"))
+ openlog("cupsd", LOG_PID | LOG_NOWAIT | LOG_NDELAY, LOG_LPR);
+#endif /* HAVE_VSYSLOG */
+
+ /*
+ * Make sure each of the log files exists and gets rotated as necessary...
+ */
+
+ if (strcmp(AccessLog, "syslog"))
+ cupsdCheckLogFile(&AccessFile, AccessLog);
+
+ if (strcmp(ErrorLog, "syslog"))
+ cupsdCheckLogFile(&ErrorFile, ErrorLog);
+
+ if (strcmp(PageLog, "syslog"))
+ cupsdCheckLogFile(&PageFile, PageLog);
+
+ /*
+ * Log the configuration file that was used...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Loaded configuration file \"%s\"",
+ ConfigurationFile);
+
+ /*
+ * Validate the Group and SystemGroup settings - they cannot be the same,
+ * otherwise the CGI programs will be able to authenticate as root without
+ * a password!
+ */
+
+ if (!RunUser)
+ {
+ for (i = 0; i < NumSystemGroups; i ++)
+ if (Group == SystemGroupIDs[i])
+ break;
+
+ if (i < NumSystemGroups)
+ {
+ /*
+ * Log the error and reset the group to a safe value...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_NOTICE,
+ "Group and SystemGroup cannot use the same groups.");
+ cupsdLogMessage(CUPSD_LOG_INFO, "Resetting Group to \"nobody\"...");
+
+ group = getgrnam("nobody");
+ endgrent();
+
+ if (group != NULL)
+ Group = group->gr_gid;
+ else
+ {
+ /*
+ * Use the (historical) NFS nobody group ID (-2 as a 16-bit twos-
+ * complement number...)
+ */
+
+ Group = 65534;
+ }
+ }
+ }
+
+ /*
+ * Check that we have at least one listen/port line; if not, report this
+ * as an error and exit!
+ */
+
+ if (cupsArrayCount(Listeners) == 0)
+ {
+ /*
+ * No listeners!
+ */
+
+ cupsdLogMessage(CUPSD_LOG_EMERG,
+ "No valid Listen or Port lines were found in the "
+ "configuration file.");
+
+ /*
+ * Commit suicide...
+ */
+
+ cupsdEndProcess(getpid(), 0);
+ }
+
+ /*
+ * Set the default locale using the language and charset...
+ */
+
+ cupsdSetStringf(&DefaultLocale, "%s.UTF-8", DefaultLanguage);
+
+ /*
+ * Update all relative filenames to include the full path from ServerRoot...
+ */
+
+ if (DocumentRoot[0] != '/')
+ cupsdSetStringf(&DocumentRoot, "%s/%s", ServerRoot, DocumentRoot);
+
+ if (RequestRoot[0] != '/')
+ cupsdSetStringf(&RequestRoot, "%s/%s", ServerRoot, RequestRoot);
+
+ if (ServerBin[0] != '/')
+ cupsdSetStringf(&ServerBin, "%s/%s", ServerRoot, ServerBin);
+
+ if (StateDir[0] != '/')
+ cupsdSetStringf(&StateDir, "%s/%s", ServerRoot, StateDir);
+
+ if (CacheDir[0] != '/')
+ cupsdSetStringf(&CacheDir, "%s/%s", ServerRoot, CacheDir);
+
+#ifdef HAVE_SSL
+ if (ServerCertificate[0] != '/')
+ cupsdSetStringf(&ServerCertificate, "%s/%s", ServerRoot, ServerCertificate);
+
+ if (!strncmp(ServerRoot, ServerCertificate, strlen(ServerRoot)) &&
+ cupsdCheckPermissions(ServerCertificate, NULL, 0600, RunUser, Group,
+ 0, 0) < 0 &&
+ (FatalErrors & CUPSD_FATAL_PERMISSIONS))
+ return (0);
+
+# if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
+ if (ServerKey[0] != '/')
+ cupsdSetStringf(&ServerKey, "%s/%s", ServerRoot, ServerKey);
+
+ if (!strncmp(ServerRoot, ServerKey, strlen(ServerRoot)) &&
+ cupsdCheckPermissions(ServerKey, NULL, 0600, RunUser, Group, 0, 0) < 0 &&
+ (FatalErrors & CUPSD_FATAL_PERMISSIONS))
+ return (0);
+# endif /* HAVE_LIBSSL || HAVE_GNUTLS */
+#endif /* HAVE_SSL */
+
+ /*
+ * Make sure that directories and config files are owned and
+ * writable by the user and group in the cupsd.conf file...
+ */
+
+ snprintf(temp, sizeof(temp), "%s/rss", CacheDir);
+
+ if ((cupsdCheckPermissions(RequestRoot, NULL, 0710, RunUser,
+ Group, 1, 1) < 0 ||
+ cupsdCheckPermissions(CacheDir, NULL, 0775, RunUser,
+ Group, 1, 1) < 0 ||
+ cupsdCheckPermissions(temp, NULL, 0775, RunUser,
+ Group, 1, 1) < 0 ||
+ cupsdCheckPermissions(StateDir, NULL, 0755, RunUser,
+ Group, 1, 1) < 0 ||
+ cupsdCheckPermissions(StateDir, "certs", RunUser ? 0711 : 0511, User,
+ SystemGroupIDs[0], 1, 1) < 0 ||
+ cupsdCheckPermissions(ServerRoot, NULL, 0755, RunUser,
+ Group, 1, 0) < 0 ||
+ cupsdCheckPermissions(ServerRoot, "ppd", 0755, RunUser,
+ Group, 1, 1) < 0 ||
+ cupsdCheckPermissions(ServerRoot, "ssl", 0700, RunUser,
+ Group, 1, 0) < 0 ||
+ cupsdCheckPermissions(ServerRoot, "cupsd.conf", ConfigFilePerm, RunUser,
+ Group, 0, 0) < 0 ||
+ cupsdCheckPermissions(ServerRoot, "classes.conf", 0600, RunUser,
+ Group, 0, 0) < 0 ||
+ cupsdCheckPermissions(ServerRoot, "printers.conf", 0600, RunUser,
+ Group, 0, 0) < 0 ||
+ cupsdCheckPermissions(ServerRoot, "passwd.md5", 0600, User,
+ Group, 0, 0) < 0) &&
+ (FatalErrors & CUPSD_FATAL_PERMISSIONS))
+ return (0);
+
+ /*
+ * Update TempDir to the default if it hasn't been set already...
+ */
+
+ if (!TempDir)
+ {
+ if ((tmpdir = getenv("TMPDIR")) != NULL)
+ {
+ /*
+ * TMPDIR is defined, see if it is OK for us to use...
+ */
+
+ if (stat(tmpdir, &tmpinfo))
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to access TMPDIR (%s): %s",
+ tmpdir, strerror(errno));
+ else if (!S_ISDIR(tmpinfo.st_mode))
+ cupsdLogMessage(CUPSD_LOG_ERROR, "TMPDIR (%s) is not a directory.",
+ tmpdir);
+ else if ((tmpinfo.st_uid != User || !(tmpinfo.st_mode & S_IWUSR)) &&
+ (tmpinfo.st_gid != Group || !(tmpinfo.st_mode & S_IWGRP)) &&
+ !(tmpinfo.st_mode & S_IWOTH))
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "TMPDIR (%s) has the wrong permissions.", tmpdir);
+ else
+ cupsdSetString(&TempDir, tmpdir);
+ }
+
+ if (!TempDir)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "Using default TempDir of %s/tmp...",
+ RequestRoot);
+ cupsdSetStringf(&TempDir, "%s/tmp", RequestRoot);
+ }
+ }
+
+ /*
+ * Make sure the temporary directory has the right permissions...
+ */
+
+ if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)) ||
+ access(TempDir, 0))
+ {
+ /*
+ * Update ownership and permissions if the CUPS temp directory
+ * is under the spool directory or does not exist...
+ */
+
+ if (cupsdCheckPermissions(TempDir, NULL, 01770, RunUser, Group, 1, 1) < 0 &&
+ (FatalErrors & CUPSD_FATAL_PERMISSIONS))
+ return (0);
+ }
+
+ /*
+ * Update environment variables...
+ */
+
+ cupsdUpdateEnv();
+
+ /*
+ * Update default paper size setting as needed...
+ */
+
+ if (!DefaultPaperSize)
+ {
+#ifdef HAVE_LIBPAPER
+ char *paper_result; /* Paper size name from libpaper */
+
+ if ((paper_result = systempapername()) != NULL)
+ cupsdSetString(&DefaultPaperSize, paper_result);
+ else
+#endif /* HAVE_LIBPAPER */
+ if (!DefaultLanguage ||
+ !_cups_strcasecmp(DefaultLanguage, "C") ||
+ !_cups_strcasecmp(DefaultLanguage, "POSIX") ||
+ !_cups_strcasecmp(DefaultLanguage, "en") ||
+ !_cups_strncasecmp(DefaultLanguage, "en.", 3) ||
+ !_cups_strncasecmp(DefaultLanguage, "en_US", 5) ||
+ !_cups_strncasecmp(DefaultLanguage, "en_CA", 5) ||
+ !_cups_strncasecmp(DefaultLanguage, "fr_CA", 5))
+ {
+ /*
+ * These are the only locales that will default to "letter" size...
+ */
+
+ cupsdSetString(&DefaultPaperSize, "Letter");
+ }
+ else
+ cupsdSetString(&DefaultPaperSize, "A4");
+ }
+
+ /*
+ * Update classification setting as needed...
+ */
+
+ if (Classification && !_cups_strcasecmp(Classification, "none"))
+ cupsdClearString(&Classification);
+
+ if (Classification)
+ cupsdLogMessage(CUPSD_LOG_INFO, "Security set to \"%s\"", Classification);
+
+ /*
+ * Check the MaxClients setting, and then allocate memory for it...
+ */
+
+ if (MaxClients > (MaxFDs / 3) || MaxClients <= 0)
+ {
+ if (MaxClients > 0)
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "MaxClients limited to 1/3 (%d) of the file descriptor "
+ "limit (%d)...",
+ MaxFDs / 3, MaxFDs);
+
+ MaxClients = MaxFDs / 3;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Configured for up to %d clients.",
+ MaxClients);
+
+ /*
+ * Check the MaxActiveJobs setting; limit to 1/3 the available
+ * file descriptors, since we need a pipe for each job...
+ */
+
+ if (MaxActiveJobs > (MaxFDs / 3))
+ MaxActiveJobs = MaxFDs / 3;
+
+ /*
+ * Update the MaxClientsPerHost value, as needed...
+ */
+
+ if (MaxClientsPerHost <= 0)
+ MaxClientsPerHost = MaxClients;
+
+ if (MaxClientsPerHost > MaxClients)
+ MaxClientsPerHost = MaxClients;
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Allowing up to %d client connections per host.",
+ MaxClientsPerHost);
+
+ /*
+ * Make sure that BrowseTimeout is at least twice the interval...
+ */
+
+ if (BrowseTimeout < (2 * BrowseInterval) || BrowseTimeout <= 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ALERT, "Invalid BrowseTimeout value %d.",
+ BrowseTimeout);
+
+ if (BrowseInterval)
+ BrowseTimeout = BrowseInterval * 2;
+ else
+ BrowseTimeout = DEFAULT_TIMEOUT;
+
+ cupsdLogMessage(CUPSD_LOG_ALERT, "Reset BrowseTimeout to %d.",
+ BrowseTimeout);
+ }
+
+ /*
+ * Update the default policy, as needed...
+ */
+
+ if (DefaultPolicy)
+ DefaultPolicyPtr = cupsdFindPolicy(DefaultPolicy);
+ else
+ DefaultPolicyPtr = NULL;
+
+ if (!DefaultPolicyPtr)
+ {
+ cupsd_location_t *po; /* New policy operation */
+
+
+ if (DefaultPolicy)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Default policy \"%s\" not found.",
+ DefaultPolicy);
+
+ cupsdSetString(&DefaultPolicy, "default");
+
+ if ((DefaultPolicyPtr = cupsdFindPolicy("default")) != NULL)
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Using policy \"default\" as the default.");
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Creating CUPS default administrative policy:");
+
+ DefaultPolicyPtr = p = cupsdAddPolicy("default");
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "<Policy default>");
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "JobPrivateAccess default");
+ cupsdAddString(&(p->job_access), "@OWNER");
+ cupsdAddString(&(p->job_access), "@SYSTEM");
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "JobPrivateValues default");
+ cupsdAddString(&(p->job_attrs), "job-name");
+ cupsdAddString(&(p->job_attrs), "job-originating-host-name");
+ cupsdAddString(&(p->job_attrs), "job-originating-user-name");
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "SubscriptionPrivateAccess default");
+ cupsdAddString(&(p->sub_access), "@OWNER");
+ cupsdAddString(&(p->sub_access), "@SYSTEM");
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "SubscriptionPrivateValues default");
+ cupsdAddString(&(p->job_attrs), "notify-events");
+ cupsdAddString(&(p->job_attrs), "notify-pull-method");
+ cupsdAddString(&(p->job_attrs), "notify-recipient-uri");
+ cupsdAddString(&(p->job_attrs), "notify-subscriber-user-name");
+ cupsdAddString(&(p->job_attrs), "notify-user-data");
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "<Limit Create-Job Print-Job Print-URI Validate-Job>");
+ cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
+
+ po = cupsdAddPolicyOp(p, NULL, IPP_CREATE_JOB);
+ po->order_type = CUPSD_AUTH_ALLOW;
+
+ cupsdAddPolicyOp(p, po, IPP_PRINT_JOB);
+ cupsdAddPolicyOp(p, po, IPP_PRINT_URI);
+ cupsdAddPolicyOp(p, po, IPP_VALIDATE_JOB);
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "<Limit Send-Document Send-URI Cancel-Job Hold-Job "
+ "Release-Job Restart-Job Purge-Jobs "
+ "Set-Job-Attributes Create-Job-Subscription "
+ "Renew-Subscription Cancel-Subscription "
+ "Get-Notifications Reprocess-Job Cancel-Current-Job "
+ "Suspend-Current-Job Resume-Job "
+ "Cancel-My-Jobs Close-Job CUPS-Move-Job "
+ "CUPS-Authenticate-Job CUPS-Get-Document>");
+ cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
+
+ po = cupsdAddPolicyOp(p, NULL, IPP_SEND_DOCUMENT);
+ po->order_type = CUPSD_AUTH_ALLOW;
+ po->level = CUPSD_AUTH_USER;
+
+ cupsdAddName(po, "@OWNER");
+ cupsdAddName(po, "@SYSTEM");
+ cupsdLogMessage(CUPSD_LOG_INFO, "Require user @OWNER @SYSTEM");
+
+ cupsdAddPolicyOp(p, po, IPP_SEND_URI);
+ cupsdAddPolicyOp(p, po, IPP_CANCEL_JOB);
+ cupsdAddPolicyOp(p, po, IPP_HOLD_JOB);
+ cupsdAddPolicyOp(p, po, IPP_RELEASE_JOB);
+ cupsdAddPolicyOp(p, po, IPP_RESTART_JOB);
+ cupsdAddPolicyOp(p, po, IPP_PURGE_JOBS);
+ cupsdAddPolicyOp(p, po, IPP_SET_JOB_ATTRIBUTES);
+ cupsdAddPolicyOp(p, po, IPP_CREATE_JOB_SUBSCRIPTION);
+ cupsdAddPolicyOp(p, po, IPP_RENEW_SUBSCRIPTION);
+ cupsdAddPolicyOp(p, po, IPP_CANCEL_SUBSCRIPTION);
+ cupsdAddPolicyOp(p, po, IPP_GET_NOTIFICATIONS);
+ cupsdAddPolicyOp(p, po, IPP_REPROCESS_JOB);
+ cupsdAddPolicyOp(p, po, IPP_CANCEL_CURRENT_JOB);
+ cupsdAddPolicyOp(p, po, IPP_SUSPEND_CURRENT_JOB);
+ cupsdAddPolicyOp(p, po, IPP_RESUME_JOB);
+ cupsdAddPolicyOp(p, po, IPP_CANCEL_MY_JOBS);
+ cupsdAddPolicyOp(p, po, IPP_CLOSE_JOB);
+ cupsdAddPolicyOp(p, po, CUPS_MOVE_JOB);
+ cupsdAddPolicyOp(p, po, CUPS_AUTHENTICATE_JOB);
+ cupsdAddPolicyOp(p, po, CUPS_GET_DOCUMENT);
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "<Limit Pause-Printer Resume-Printer "
+ "Set-Printer-Attributes Enable-Printer "
+ "Disable-Printer Pause-Printer-After-Current-Job "
+ "Hold-New-Jobs Release-Held-New-Jobs "
+ "Deactivate-Printer Activate-Printer Restart-Printer "
+ "Shutdown-Printer Startup-Printer Promote-Job "
+ "Schedule-Job-After Cancel-Jobs CUPS-Add-Printer "
+ "CUPS-Delete-Printer CUPS-Add-Class CUPS-Delete-Class "
+ "CUPS-Accept-Jobs CUPS-Reject-Jobs CUPS-Set-Default>");
+ cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
+ cupsdLogMessage(CUPSD_LOG_INFO, "AuthType Default");
+
+ po = cupsdAddPolicyOp(p, NULL, IPP_PAUSE_PRINTER);
+ po->order_type = CUPSD_AUTH_ALLOW;
+ po->type = CUPSD_AUTH_DEFAULT;
+ po->level = CUPSD_AUTH_USER;
+
+ cupsdAddName(po, "@SYSTEM");
+ cupsdLogMessage(CUPSD_LOG_INFO, "Require user @SYSTEM");
+
+ cupsdAddPolicyOp(p, po, IPP_RESUME_PRINTER);
+ cupsdAddPolicyOp(p, po, IPP_SET_PRINTER_ATTRIBUTES);
+ cupsdAddPolicyOp(p, po, IPP_ENABLE_PRINTER);
+ cupsdAddPolicyOp(p, po, IPP_DISABLE_PRINTER);
+ cupsdAddPolicyOp(p, po, IPP_PAUSE_PRINTER_AFTER_CURRENT_JOB);
+ cupsdAddPolicyOp(p, po, IPP_HOLD_NEW_JOBS);
+ cupsdAddPolicyOp(p, po, IPP_RELEASE_HELD_NEW_JOBS);
+ cupsdAddPolicyOp(p, po, IPP_DEACTIVATE_PRINTER);
+ cupsdAddPolicyOp(p, po, IPP_ACTIVATE_PRINTER);
+ cupsdAddPolicyOp(p, po, IPP_RESTART_PRINTER);
+ cupsdAddPolicyOp(p, po, IPP_SHUTDOWN_PRINTER);
+ cupsdAddPolicyOp(p, po, IPP_STARTUP_PRINTER);
+ cupsdAddPolicyOp(p, po, IPP_PROMOTE_JOB);
+ cupsdAddPolicyOp(p, po, IPP_SCHEDULE_JOB_AFTER);
+ cupsdAddPolicyOp(p, po, IPP_CANCEL_JOBS);
+ cupsdAddPolicyOp(p, po, CUPS_ADD_PRINTER);
+ cupsdAddPolicyOp(p, po, CUPS_DELETE_PRINTER);
+ cupsdAddPolicyOp(p, po, CUPS_ADD_CLASS);
+ cupsdAddPolicyOp(p, po, CUPS_DELETE_CLASS);
+ cupsdAddPolicyOp(p, po, CUPS_ACCEPT_JOBS);
+ cupsdAddPolicyOp(p, po, CUPS_REJECT_JOBS);
+ cupsdAddPolicyOp(p, po, CUPS_SET_DEFAULT);
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "<Limit All>");
+ cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
+
+ po = cupsdAddPolicyOp(p, NULL, IPP_ANY_OPERATION);
+ po->order_type = CUPSD_AUTH_ALLOW;
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
+ cupsdLogMessage(CUPSD_LOG_INFO, "</Policy>");
+ }
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadConfiguration: NumPolicies=%d",
+ cupsArrayCount(Policies));
+ for (i = 0, p = (cupsd_policy_t *)cupsArrayFirst(Policies);
+ p;
+ i ++, p = (cupsd_policy_t *)cupsArrayNext(Policies))
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdReadConfiguration: Policies[%d]=\"%s\"", i, p->name);
+
+ /*
+ * If we are doing a full reload or the server root has changed, flush
+ * the jobs, printers, etc. and start from scratch...
+ */
+
+ if (NeedReload == RELOAD_ALL ||
+ old_remote_port != RemotePort ||
+ !old_serverroot || !ServerRoot || strcmp(old_serverroot, ServerRoot) ||
+ !old_requestroot || !RequestRoot || strcmp(old_requestroot, RequestRoot))
+ {
+ mime_type_t *type; /* Current type */
+ char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE];
+ /* MIME type name */
+
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Full reload is required.");
+
+ /*
+ * Free all memory...
+ */
+
+ cupsdDeleteAllSubscriptions();
+ cupsdFreeAllJobs();
+ cupsdDeleteAllPrinters();
+
+ DefaultPrinter = NULL;
+
+ if (MimeDatabase != NULL)
+ mimeDelete(MimeDatabase);
+
+ if (NumMimeTypes)
+ {
+ for (i = 0; i < NumMimeTypes; i ++)
+ _cupsStrFree(MimeTypes[i]);
+
+ free(MimeTypes);
+ }
+
+ /*
+ * Read the MIME type and conversion database...
+ */
+
+ snprintf(temp, sizeof(temp), "%s/filter", ServerBin);
+ snprintf(mimedir, sizeof(mimedir), "%s/mime", DataDir);
+
+ MimeDatabase = mimeNew();
+ mimeSetErrorCallback(MimeDatabase, mime_error_cb, NULL);
+
+ MimeDatabase = mimeLoadTypes(MimeDatabase, mimedir);
+ MimeDatabase = mimeLoadTypes(MimeDatabase, ServerRoot);
+ MimeDatabase = mimeLoadFilters(MimeDatabase, mimedir, temp);
+ MimeDatabase = mimeLoadFilters(MimeDatabase, ServerRoot, temp);
+
+ if (!MimeDatabase)
+ {
+ cupsdLogMessage(CUPSD_LOG_EMERG,
+ "Unable to load MIME database from \"%s\" or \"%s\".",
+ mimedir, ServerRoot);
+ if (FatalErrors & CUPSD_FATAL_CONFIG)
+ return (0);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Loaded MIME database from \"%s\" and \"%s\": %d types, "
+ "%d filters...", mimedir, ServerRoot,
+ mimeNumTypes(MimeDatabase), mimeNumFilters(MimeDatabase));
+
+ /*
+ * Create a list of MIME types for the document-format-supported
+ * attribute...
+ */
+
+ NumMimeTypes = mimeNumTypes(MimeDatabase);
+ if (!mimeType(MimeDatabase, "application", "octet-stream"))
+ NumMimeTypes ++;
+
+ if ((MimeTypes = calloc(NumMimeTypes, sizeof(const char *))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for %d MIME types.",
+ NumMimeTypes);
+ NumMimeTypes = 0;
+ }
+ else
+ {
+ for (i = 0, type = mimeFirstType(MimeDatabase);
+ type;
+ i ++, type = mimeNextType(MimeDatabase))
+ {
+ snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
+
+ MimeTypes[i] = _cupsStrAlloc(mimetype);
+ }
+
+ if (i < NumMimeTypes)
+ MimeTypes[i] = _cupsStrAlloc("application/octet-stream");
+ }
+
+ if (LogLevel == CUPSD_LOG_DEBUG2)
+ {
+ mime_filter_t *filter; /* Current filter */
+
+
+ for (type = mimeFirstType(MimeDatabase);
+ type;
+ type = mimeNextType(MimeDatabase))
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadConfiguration: type %s/%s",
+ type->super, type->type);
+
+ for (filter = mimeFirstFilter(MimeDatabase);
+ filter;
+ filter = mimeNextFilter(MimeDatabase))
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdReadConfiguration: filter %s/%s to %s/%s %d %s",
+ filter->src->super, filter->src->type,
+ filter->dst->super, filter->dst->type,
+ filter->cost, filter->filter);
+ }
+
+ /*
+ * Load banners...
+ */
+
+ snprintf(temp, sizeof(temp), "%s/banners", DataDir);
+ cupsdLoadBanners(temp);
+
+ /*
+ * Load printers and classes...
+ */
+
+ cupsdLoadAllPrinters();
+ cupsdLoadAllClasses();
+ cupsdLoadRemoteCache();
+
+ cupsdCreateCommonData();
+
+ /*
+ * Update the printcap file as needed...
+ */
+
+ if (Printcap && *Printcap && access(Printcap, 0))
+ cupsdWritePrintcap();
+
+ /*
+ * Load queued jobs...
+ */
+
+ cupsdLoadAllJobs();
+
+ /*
+ * Load subscriptions...
+ */
+
+ cupsdLoadAllSubscriptions();
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Full reload complete.");
+ }
+ else
+ {
+ /*
+ * Not a full reload, so recreate the common printer attributes...
+ */
+
+ cupsdCreateCommonData();
+
+ /*
+ * Update all printers as needed...
+ */
+
+ cupsdUpdatePrinters();
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Partial reload complete.");
+ }
+
+ /*
+ * Reset the reload state...
+ */
+
+ NeedReload = RELOAD_NONE;
+
+ cupsdClearString(&old_serverroot);
+ cupsdClearString(&old_requestroot);
+
+ return (1);
+}
+
+
+/*
+ * 'get_address()' - Get an address + port number from a line.
+ */
+
+static http_addrlist_t * /* O - Pointer to list if address good, NULL if bad */
+get_address(const char *value, /* I - Value string */
+ int defport) /* I - Default port */
+{
+ char buffer[1024], /* Hostname + port number buffer */
+ defpname[255], /* Default port name */
+ *hostname, /* Hostname or IP */
+ *portname; /* Port number or name */
+ http_addrlist_t *addrlist; /* Address list */
+
+
+ /*
+ * Check for an empty value...
+ */
+
+ if (!*value)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad (empty) address.");
+ return (NULL);
+ }
+
+ /*
+ * Grab a hostname and port number; if there is no colon and the port name
+ * is only digits, then we have a port number by itself...
+ */
+
+ strlcpy(buffer, value, sizeof(buffer));
+
+ if ((portname = strrchr(buffer, ':')) != NULL && !strchr(portname, ']'))
+ {
+ *portname++ = '\0';
+ hostname = buffer;
+ }
+ else
+ {
+ for (portname = buffer; isdigit(*portname & 255); portname ++);
+
+ if (*portname)
+ {
+ /*
+ * Use the default port...
+ */
+
+ sprintf(defpname, "%d", defport);
+ portname = defpname;
+ hostname = buffer;
+ }
+ else
+ {
+ /*
+ * The buffer contains just a port number...
+ */
+
+ portname = buffer;
+ hostname = NULL;
+ }
+ }
+
+ if (hostname && !strcmp(hostname, "*"))
+ hostname = NULL;
+
+ /*
+ * Now lookup the address using httpAddrGetList()...
+ */
+
+ if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Hostname lookup for \"%s\" failed.",
+ hostname ? hostname : "(nil)");
+
+ return (addrlist);
+}
+
+
+/*
+ * 'get_addr_and_mask()' - Get an IP address and netmask.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+get_addr_and_mask(const char *value, /* I - String from config file */
+ unsigned *ip, /* O - Address value */
+ unsigned *mask) /* O - Mask value */
+{
+ int i, j, /* Looping vars */
+ family, /* Address family */
+ ipcount; /* Count of fields in address */
+ unsigned ipval; /* Value */
+ const char *maskval, /* Pointer to start of mask value */
+ *ptr, /* Pointer into value */
+ *ptr2; /* ... */
+
+
+ /*
+ * Get the address...
+ */
+
+ ip[0] = ip[1] = ip[2] = ip[3] = 0x00000000;
+ mask[0] = mask[1] = mask[2] = mask[3] = 0xffffffff;
+
+ if ((maskval = strchr(value, '/')) != NULL)
+ maskval ++;
+ else
+ maskval = value + strlen(value);
+
+#ifdef AF_INET6
+ /*
+ * Check for an IPv6 address...
+ */
+
+ if (*value == '[')
+ {
+ /*
+ * Parse hexadecimal IPv6/IPv4 address...
+ */
+
+ family = AF_INET6;
+
+ for (i = 0, ptr = value + 1; *ptr && i < 8; i ++)
+ {
+ if (*ptr == ']')
+ break;
+ else if (!strncmp(ptr, "::", 2))
+ {
+ for (ptr2 = strchr(ptr + 2, ':'), j = 0;
+ ptr2;
+ ptr2 = strchr(ptr2 + 1, ':'), j ++);
+
+ i = 6 - j;
+ ptr += 2;
+ }
+ else if (isdigit(*ptr & 255) && strchr(ptr + 1, '.') && i >= 6)
+ {
+ /*
+ * Read IPv4 dotted quad...
+ */
+
+ unsigned val[4] = { 0, 0, 0, 0 };
+ /* IPv4 address values */
+
+ ipcount = sscanf(ptr, "%u.%u.%u.%u", val + 0, val + 1, val + 2,
+ val + 3);
+
+ /*
+ * Range check the IP numbers...
+ */
+
+ for (i = 0; i < ipcount; i ++)
+ if (val[i] > 255)
+ return (0);
+
+ /*
+ * Merge everything into a 32-bit IPv4 address in ip[3]...
+ */
+
+ ip[3] = (((((val[0] << 8) | val[1]) << 8) | val[2]) << 8) | val[3];
+
+ if (ipcount < 4)
+ mask[3] = (0xffffffff << (32 - 8 * ipcount)) & 0xffffffff;
+
+ /*
+ * If the leading words are all 0's then this is an IPv4 address...
+ */
+
+ if (!val[0] && !val[1] && !val[2])
+ family = AF_INET;
+
+ while (isdigit(*ptr & 255) || *ptr == '.')
+ ptr ++;
+ break;
+ }
+ else if (isxdigit(*ptr & 255))
+ {
+ ipval = strtoul(ptr, (char **)&ptr, 16);
+
+ if (*ptr == ':' && ptr[1] != ':')
+ ptr ++;
+
+ if (ipval > 0xffff)
+ return (0);
+
+ if (i & 1)
+ ip[i / 2] |= ipval;
+ else
+ ip[i / 2] |= ipval << 16;
+ }
+ else
+ return (0);
+ }
+
+ if (*ptr != ']')
+ return (0);
+
+ ptr ++;
+
+ if (*ptr && *ptr != '/')
+ return (0);
+ }
+ else
+#endif /* AF_INET6 */
+ {
+ /*
+ * Parse dotted-decimal IPv4 address...
+ */
+
+ unsigned val[4] = { 0, 0, 0, 0 }; /* IPv4 address values */
+
+
+ family = AF_INET;
+ ipcount = sscanf(value, "%u.%u.%u.%u", val + 0, val + 1, val + 2, val + 3);
+
+ /*
+ * Range check the IP numbers...
+ */
+
+ for (i = 0; i < ipcount; i ++)
+ if (val[i] > 255)
+ return (0);
+
+ /*
+ * Merge everything into a 32-bit IPv4 address in ip[3]...
+ */
+
+ ip[3] = (((((val[0] << 8) | val[1]) << 8) | val[2]) << 8) | val[3];
+
+ if (ipcount < 4)
+ mask[3] = (0xffffffff << (32 - 8 * ipcount)) & 0xffffffff;
+ }
+
+ if (*maskval)
+ {
+ /*
+ * Get the netmask value(s)...
+ */
+
+ memset(mask, 0, sizeof(unsigned) * 4);
+
+ if (strchr(maskval, '.'))
+ {
+ /*
+ * Get dotted-decimal mask...
+ */
+
+ if (family != AF_INET)
+ return (0);
+
+ if (sscanf(maskval, "%u.%u.%u.%u", mask + 0, mask + 1, mask + 2,
+ mask + 3) != 4)
+ return (0);
+
+ mask[3] |= ((((mask[0] << 8) | mask[1]) << 8) | mask[2]) << 8;
+ mask[0] = mask[1] = mask[2] = 0;
+ }
+ else
+ {
+ /*
+ * Get address/bits format...
+ */
+
+ i = atoi(maskval);
+
+#ifdef AF_INET6
+ if (family == AF_INET6)
+ {
+ if (i > 128)
+ return (0);
+
+ i = 128 - i;
+
+ if (i <= 96)
+ mask[0] = 0xffffffff;
+ else
+ mask[0] = (0xffffffff << (i - 96)) & 0xffffffff;
+
+ if (i <= 64)
+ mask[1] = 0xffffffff;
+ else if (i >= 96)
+ mask[1] = 0;
+ else
+ mask[1] = (0xffffffff << (i - 64)) & 0xffffffff;
+
+ if (i <= 32)
+ mask[2] = 0xffffffff;
+ else if (i >= 64)
+ mask[2] = 0;
+ else
+ mask[2] = (0xffffffff << (i - 32)) & 0xffffffff;
+
+ if (i == 0)
+ mask[3] = 0xffffffff;
+ else if (i >= 32)
+ mask[3] = 0;
+ else
+ mask[3] = (0xffffffff << i) & 0xffffffff;
+ }
+ else
+#endif /* AF_INET6 */
+ {
+ if (i > 32)
+ return (0);
+
+ mask[0] = 0xffffffff;
+ mask[1] = 0xffffffff;
+ mask[2] = 0xffffffff;
+
+ if (i < 32)
+ mask[3] = (0xffffffff << (32 - i)) & 0xffffffff;
+ else
+ mask[3] = 0xffffffff;
+ }
+ }
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "get_addr_and_mask(value=\"%s\", "
+ "ip=[%08x:%08x:%08x:%08x], mask=[%08x:%08x:%08x:%08x])",
+ value, ip[0], ip[1], ip[2], ip[3], mask[0], mask[1], mask[2],
+ mask[3]);
+
+ /*
+ * Check for a valid netmask; no fallback like in CUPS 1.1.x!
+ */
+
+ if ((ip[0] & ~mask[0]) != 0 ||
+ (ip[1] & ~mask[1]) != 0 ||
+ (ip[2] & ~mask[2]) != 0 ||
+ (ip[3] & ~mask[3]) != 0)
+ return (0);
+
+ return (1);
+}
+
+
+/*
+ * 'mime_error_cb()' - Log a MIME error.
+ */
+
+static void
+mime_error_cb(void *ctx, /* I - Context pointer (unused) */
+ const char *message) /* I - Message */
+{
+ (void)ctx;
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s", message);
+}
+
+
+/*
+ * 'parse_aaa()' - Parse authentication, authorization, and access control lines.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+parse_aaa(cupsd_location_t *loc, /* I - Location */
+ char *line, /* I - Line from file */
+ char *value, /* I - Start of value data */
+ int linenum) /* I - Current line number */
+{
+ char *valptr; /* Pointer into value */
+ unsigned ip[4], /* IP address components */
+ mask[4]; /* IP netmask components */
+
+
+ if (!_cups_strcasecmp(line, "Encryption"))
+ {
+ /*
+ * "Encryption xxx" - set required encryption level...
+ */
+
+ if (!_cups_strcasecmp(value, "never"))
+ loc->encryption = HTTP_ENCRYPT_NEVER;
+ else if (!_cups_strcasecmp(value, "always"))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Encryption value \"%s\" on line %d is invalid in this "
+ "context. Using \"required\" instead.", value, linenum);
+
+ loc->encryption = HTTP_ENCRYPT_REQUIRED;
+ }
+ else if (!_cups_strcasecmp(value, "required"))
+ loc->encryption = HTTP_ENCRYPT_REQUIRED;
+ else if (!_cups_strcasecmp(value, "ifrequested"))
+ loc->encryption = HTTP_ENCRYPT_IF_REQUESTED;
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown Encryption value %s on line %d.", value, linenum);
+ return (0);
+ }
+ }
+ else if (!_cups_strcasecmp(line, "Order"))
+ {
+ /*
+ * "Order Deny,Allow" or "Order Allow,Deny"...
+ */
+
+ if (!_cups_strncasecmp(value, "deny", 4))
+ loc->order_type = CUPSD_AUTH_ALLOW;
+ else if (!_cups_strncasecmp(value, "allow", 5))
+ loc->order_type = CUPSD_AUTH_DENY;
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown Order value %s on line %d.",
+ value, linenum);
+ return (0);
+ }
+ }
+ else if (!_cups_strcasecmp(line, "Allow") || !_cups_strcasecmp(line, "Deny"))
+ {
+ /*
+ * Allow [From] host/ip...
+ * Deny [From] host/ip...
+ */
+
+ while (*value)
+ {
+ if (!_cups_strncasecmp(value, "from", 4))
+ {
+ /*
+ * Strip leading "from"...
+ */
+
+ value += 4;
+
+ while (_cups_isspace(*value))
+ value ++;
+
+ if (!*value)
+ break;
+ }
+
+ /*
+ * Find the end of the value...
+ */
+
+ for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++);
+
+ while (_cups_isspace(*valptr))
+ *valptr++ = '\0';
+
+ /*
+ * Figure out what form the allow/deny address takes:
+ *
+ * All
+ * None
+ * *.domain.com
+ * .domain.com
+ * host.domain.com
+ * nnn.*
+ * nnn.nnn.*
+ * nnn.nnn.nnn.*
+ * nnn.nnn.nnn.nnn
+ * nnn.nnn.nnn.nnn/mm
+ * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
+ */
+
+ if (!_cups_strcasecmp(value, "all"))
+ {
+ /*
+ * All hosts...
+ */
+
+ if (!_cups_strcasecmp(line, "Allow"))
+ cupsdAddIPMask(&(loc->allow), zeros, zeros);
+ else
+ cupsdAddIPMask(&(loc->deny), zeros, zeros);
+ }
+ else if (!_cups_strcasecmp(value, "none"))
+ {
+ /*
+ * No hosts...
+ */
+
+ if (!_cups_strcasecmp(line, "Allow"))
+ cupsdAddIPMask(&(loc->allow), ones, zeros);
+ else
+ cupsdAddIPMask(&(loc->deny), ones, zeros);
+ }
+#ifdef AF_INET6
+ else if (value[0] == '*' || value[0] == '.' ||
+ (!isdigit(value[0] & 255) && value[0] != '['))
+#else
+ else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0] & 255))
+#endif /* AF_INET6 */
+ {
+ /*
+ * Host or domain name...
+ */
+
+ if (value[0] == '*')
+ value ++;
+
+ if (!_cups_strcasecmp(line, "Allow"))
+ cupsdAddNameMask(&(loc->allow), value);
+ else
+ cupsdAddNameMask(&(loc->deny), value);
+ }
+ else
+ {
+ /*
+ * One of many IP address forms...
+ */
+
+ if (!get_addr_and_mask(value, ip, mask))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.",
+ value, linenum);
+ return (0);
+ }
+
+ if (!_cups_strcasecmp(line, "Allow"))
+ cupsdAddIPMask(&(loc->allow), ip, mask);
+ else
+ cupsdAddIPMask(&(loc->deny), ip, mask);
+ }
+
+ /*
+ * Advance to next value...
+ */
+
+ value = valptr;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "AuthType"))
+ {
+ /*
+ * AuthType {none,basic,digest,basicdigest,negotiate,default}
+ */
+
+ if (!_cups_strcasecmp(value, "none"))
+ {
+ loc->type = CUPSD_AUTH_NONE;
+ loc->level = CUPSD_AUTH_ANON;
+ }
+ else if (!_cups_strcasecmp(value, "basic"))
+ {
+ loc->type = CUPSD_AUTH_BASIC;
+
+ if (loc->level == CUPSD_AUTH_ANON)
+ loc->level = CUPSD_AUTH_USER;
+ }
+ else if (!_cups_strcasecmp(value, "digest"))
+ {
+ loc->type = CUPSD_AUTH_DIGEST;
+
+ if (loc->level == CUPSD_AUTH_ANON)
+ loc->level = CUPSD_AUTH_USER;
+ }
+ else if (!_cups_strcasecmp(value, "basicdigest"))
+ {
+ loc->type = CUPSD_AUTH_BASICDIGEST;
+
+ if (loc->level == CUPSD_AUTH_ANON)
+ loc->level = CUPSD_AUTH_USER;
+ }
+ else if (!_cups_strcasecmp(value, "default"))
+ {
+ loc->type = CUPSD_AUTH_DEFAULT;
+
+ if (loc->level == CUPSD_AUTH_ANON)
+ loc->level = CUPSD_AUTH_USER;
+ }
+#ifdef HAVE_GSSAPI
+ else if (!_cups_strcasecmp(value, "negotiate"))
+ {
+ loc->type = CUPSD_AUTH_NEGOTIATE;
+
+ if (loc->level == CUPSD_AUTH_ANON)
+ loc->level = CUPSD_AUTH_USER;
+ }
+#endif /* HAVE_GSSAPI */
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Unknown authorization type %s on line %d.",
+ value, linenum);
+ return (0);
+ }
+ }
+ else if (!_cups_strcasecmp(line, "AuthClass"))
+ {
+ /*
+ * AuthClass anonymous, user, system, group
+ */
+
+ if (!_cups_strcasecmp(value, "anonymous"))
+ {
+ loc->type = CUPSD_AUTH_NONE;
+ loc->level = CUPSD_AUTH_ANON;
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "\"AuthClass %s\" is deprecated; consider removing "
+ "it from line %d.",
+ value, linenum);
+ }
+ else if (!_cups_strcasecmp(value, "user"))
+ {
+ loc->level = CUPSD_AUTH_USER;
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "\"AuthClass %s\" is deprecated; consider using "
+ "\"Require valid-user\" on line %d.",
+ value, linenum);
+ }
+ else if (!_cups_strcasecmp(value, "group"))
+ {
+ loc->level = CUPSD_AUTH_GROUP;
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "\"AuthClass %s\" is deprecated; consider using "
+ "\"Require user @groupname\" on line %d.",
+ value, linenum);
+ }
+ else if (!_cups_strcasecmp(value, "system"))
+ {
+ loc->level = CUPSD_AUTH_GROUP;
+
+ cupsdAddName(loc, "@SYSTEM");
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "\"AuthClass %s\" is deprecated; consider using "
+ "\"Require user @SYSTEM\" on line %d.",
+ value, linenum);
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Unknown authorization class %s on line %d.",
+ value, linenum);
+ return (0);
+ }
+ }
+ else if (!_cups_strcasecmp(line, "AuthGroupName"))
+ {
+ cupsdAddName(loc, value);
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "\"AuthGroupName %s\" directive is deprecated; consider "
+ "using \"Require user @%s\" on line %d.",
+ value, value, linenum);
+ }
+ else if (!_cups_strcasecmp(line, "Require"))
+ {
+ /*
+ * Apache synonym for AuthClass and AuthGroupName...
+ *
+ * Get initial word:
+ *
+ * Require valid-user
+ * Require group names
+ * Require user names
+ */
+
+ for (valptr = value; !_cups_isspace(*valptr) && *valptr; valptr ++);
+
+ if (*valptr)
+ *valptr++ = '\0';
+
+ if (!_cups_strcasecmp(value, "valid-user") ||
+ !_cups_strcasecmp(value, "user"))
+ loc->level = CUPSD_AUTH_USER;
+ else if (!_cups_strcasecmp(value, "group"))
+ loc->level = CUPSD_AUTH_GROUP;
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN, "Unknown Require type %s on line %d.",
+ value, linenum);
+ return (0);
+ }
+
+ /*
+ * Get the list of names from the line...
+ */
+
+ for (value = valptr; *value;)
+ {
+ while (_cups_isspace(*value))
+ value ++;
+
+#ifdef HAVE_AUTHORIZATION_H
+ if (!strncmp(value, "@AUTHKEY(", 9))
+ {
+ /*
+ * Grab "@AUTHKEY(name)" value...
+ */
+
+ for (valptr = value + 9; *valptr != ')' && *valptr; valptr ++);
+
+ if (*valptr)
+ *valptr++ = '\0';
+ }
+ else
+#endif /* HAVE_AUTHORIZATION_H */
+ if (*value == '\"' || *value == '\'')
+ {
+ /*
+ * Grab quoted name...
+ */
+
+ for (valptr = value + 1; *valptr != *value && *valptr; valptr ++);
+
+ value ++;
+ }
+ else
+ {
+ /*
+ * Grab literal name.
+ */
+
+ for (valptr = value; !_cups_isspace(*valptr) && *valptr; valptr ++);
+ }
+
+ if (*valptr)
+ *valptr++ = '\0';
+
+ cupsdAddName(loc, value);
+
+ for (value = valptr; _cups_isspace(*value); value ++);
+ }
+ }
+ else if (!_cups_strcasecmp(line, "Satisfy"))
+ {
+ if (!_cups_strcasecmp(value, "all"))
+ loc->satisfy = CUPSD_AUTH_SATISFY_ALL;
+ else if (!_cups_strcasecmp(value, "any"))
+ loc->satisfy = CUPSD_AUTH_SATISFY_ANY;
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN, "Unknown Satisfy value %s on line %d.",
+ value, linenum);
+ return (0);
+ }
+ }
+ else
+ return (0);
+
+ return (1);
+}
+
+
+/*
+ * 'parse_fatal_errors()' - Parse FatalErrors values in a string.
+ */
+
+static int /* O - FatalErrors bits */
+parse_fatal_errors(const char *s) /* I - FatalErrors string */
+{
+ int fatal; /* FatalErrors bits */
+ char value[1024], /* Value string */
+ *valstart, /* Pointer into value */
+ *valend; /* End of value */
+
+
+ /*
+ * Empty FatalErrors line yields NULL pointer...
+ */
+
+ if (!s)
+ return (CUPSD_FATAL_NONE);
+
+ /*
+ * Loop through the value string,...
+ */
+
+ strlcpy(value, s, sizeof(value));
+
+ fatal = CUPSD_FATAL_NONE;
+
+ for (valstart = value; *valstart;)
+ {
+ /*
+ * Get the current space/comma-delimited kind name...
+ */
+
+ for (valend = valstart; *valend; valend ++)
+ if (_cups_isspace(*valend) || *valend == ',')
+ break;
+
+ if (*valend)
+ *valend++ = '\0';
+
+ /*
+ * Add the error to the bitmask...
+ */
+
+ if (!_cups_strcasecmp(valstart, "all"))
+ fatal = CUPSD_FATAL_ALL;
+ else if (!_cups_strcasecmp(valstart, "browse"))
+ fatal |= CUPSD_FATAL_BROWSE;
+ else if (!_cups_strcasecmp(valstart, "-browse"))
+ fatal &= ~CUPSD_FATAL_BROWSE;
+ else if (!_cups_strcasecmp(valstart, "config"))
+ fatal |= CUPSD_FATAL_CONFIG;
+ else if (!_cups_strcasecmp(valstart, "-config"))
+ fatal &= ~CUPSD_FATAL_CONFIG;
+ else if (!_cups_strcasecmp(valstart, "listen"))
+ fatal |= CUPSD_FATAL_LISTEN;
+ else if (!_cups_strcasecmp(valstart, "-listen"))
+ fatal &= ~CUPSD_FATAL_LISTEN;
+ else if (!_cups_strcasecmp(valstart, "log"))
+ fatal |= CUPSD_FATAL_LOG;
+ else if (!_cups_strcasecmp(valstart, "-log"))
+ fatal &= ~CUPSD_FATAL_LOG;
+ else if (!_cups_strcasecmp(valstart, "permissions"))
+ fatal |= CUPSD_FATAL_PERMISSIONS;
+ else if (!_cups_strcasecmp(valstart, "-permissions"))
+ fatal &= ~CUPSD_FATAL_PERMISSIONS;
+ else if (_cups_strcasecmp(valstart, "none"))
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown FatalErrors kind \"%s\" ignored.", valstart);
+
+ for (valstart = valend; *valstart; valstart ++)
+ if (!_cups_isspace(*valstart) || *valstart != ',')
+ break;
+ }
+
+ return (fatal);
+}
+
+
+/*
+ * 'parse_groups()' - Parse system group names in a string.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+parse_groups(const char *s) /* I - Space-delimited groups */
+{
+ int status; /* Return status */
+ char value[1024], /* Value string */
+ *valstart, /* Pointer into value */
+ *valend, /* End of value */
+ quote; /* Quote character */
+ struct group *group; /* Group */
+
+
+ /*
+ * Make a copy of the string and parse out the groups...
+ */
+
+ strlcpy(value, s, sizeof(value));
+
+ status = 1;
+ valstart = value;
+
+ while (*valstart && NumSystemGroups < MAX_SYSTEM_GROUPS)
+ {
+ if (*valstart == '\'' || *valstart == '\"')
+ {
+ /*
+ * Scan quoted name...
+ */
+
+ quote = *valstart++;
+
+ for (valend = valstart; *valend; valend ++)
+ if (*valend == quote)
+ break;
+ }
+ else
+ {
+ /*
+ * Scan space or comma-delimited name...
+ */
+
+ for (valend = valstart; *valend; valend ++)
+ if (_cups_isspace(*valend) || *valend == ',')
+ break;
+ }
+
+ if (*valend)
+ *valend++ = '\0';
+
+ group = getgrnam(valstart);
+ if (group)
+ {
+ cupsdSetString(SystemGroups + NumSystemGroups, valstart);
+ SystemGroupIDs[NumSystemGroups] = group->gr_gid;
+
+ NumSystemGroups ++;
+ }
+ else
+ status = 0;
+
+ endgrent();
+
+ valstart = valend;
+
+ while (*valstart == ',' || _cups_isspace(*valstart))
+ valstart ++;
+ }
+
+ return (status);
+}
+
+
+/*
+ * 'parse_protocols()' - Parse browse protocols in a string.
+ */
+
+static int /* O - Browse protocol bits */
+parse_protocols(const char *s) /* I - Space-delimited protocols */
+{
+ int protocols; /* Browse protocol bits */
+ char value[1024], /* Value string */
+ *valstart, /* Pointer into value */
+ *valend; /* End of value */
+
+
+ /*
+ * Empty protocol line yields NULL pointer...
+ */
+
+ if (!s)
+ return (0);
+
+ /*
+ * Loop through the value string,...
+ */
+
+ strlcpy(value, s, sizeof(value));
+
+ protocols = 0;
+
+ for (valstart = value; *valstart;)
+ {
+ /*
+ * Get the current space/comma-delimited protocol name...
+ */
+
+ for (valend = valstart; *valend; valend ++)
+ if (_cups_isspace(*valend) || *valend == ',')
+ break;
+
+ if (*valend)
+ *valend++ = '\0';
+
+ /*
+ * Add the protocol to the bitmask...
+ */
+
+ if (!_cups_strcasecmp(valstart, "cups"))
+ protocols |= BROWSE_CUPS;
+ else if (!_cups_strcasecmp(valstart, "slp"))
+ protocols |= BROWSE_SLP;
+ else if (!_cups_strcasecmp(valstart, "ldap"))
+ protocols |= BROWSE_LDAP;
+ else if (!_cups_strcasecmp(valstart, "dnssd") ||
+ !_cups_strcasecmp(valstart, "dns-sd") ||
+ !_cups_strcasecmp(valstart, "bonjour"))
+ protocols |= BROWSE_DNSSD;
+ else if (!_cups_strcasecmp(valstart, "lpd"))
+ protocols |= BROWSE_LPD;
+ else if (!_cups_strcasecmp(valstart, "smb"))
+ protocols |= BROWSE_SMB;
+ else if (!_cups_strcasecmp(valstart, "all"))
+ protocols |= BROWSE_ALL;
+ else if (_cups_strcasecmp(valstart, "none"))
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown browse protocol \"%s\" ignored.", valstart);
+
+ for (valstart = valend; *valstart; valstart ++)
+ if (!_cups_isspace(*valstart) || *valstart != ',')
+ break;
+ }
+
+ return (protocols);
+}
+
+
+/*
+ * 'read_configuration()' - Read a configuration file.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+read_configuration(cups_file_t *fp) /* I - File to read from */
+{
+ int i; /* Looping var */
+ int linenum; /* Current line number */
+ char line[HTTP_MAX_BUFFER],
+ /* Line from file */
+ temp[HTTP_MAX_BUFFER],
+ /* Temporary buffer for value */
+ *ptr, /* Pointer into line/temp */
+ *value, /* Pointer to value */
+ *valueptr; /* Pointer into value */
+ int valuelen; /* Length of value */
+ cupsd_var_t const *var; /* Current variable */
+ http_addrlist_t *addrlist, /* Address list */
+ *addr; /* Current address */
+ unsigned ip[4], /* Address value */
+ mask[4]; /* Netmask value */
+ cupsd_dirsvc_relay_t *relay; /* Relay data */
+ cupsd_dirsvc_poll_t *pollp; /* Polling data */
+ cupsd_location_t *location; /* Browse location */
+ cups_file_t *incfile; /* Include file */
+ char incname[1024]; /* Include filename */
+ struct group *group; /* Group */
+
+
+ /*
+ * Loop through each line in the file...
+ */
+
+ linenum = 0;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ /*
+ * Decode the directive...
+ */
+
+ if (!_cups_strcasecmp(line, "Include") && value)
+ {
+ /*
+ * Include filename
+ */
+
+ if (value[0] == '/')
+ strlcpy(incname, value, sizeof(incname));
+ else
+ snprintf(incname, sizeof(incname), "%s/%s", ServerRoot, value);
+
+ if ((incfile = cupsFileOpen(incname, "rb")) == NULL)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to include config file \"%s\" - %s",
+ incname, strerror(errno));
+ else
+ {
+ read_configuration(incfile);
+ cupsFileClose(incfile);
+ }
+ }
+ else if (!_cups_strcasecmp(line, "<Location") && value)
+ {
+ /*
+ * <Location path>
+ */
+
+ linenum = read_location(fp, value, linenum);
+ if (linenum == 0)
+ return (0);
+ }
+ else if (!_cups_strcasecmp(line, "<Policy") && value)
+ {
+ /*
+ * <Policy name>
+ */
+
+ linenum = read_policy(fp, value, linenum);
+ if (linenum == 0)
+ return (0);
+ }
+ else if (!_cups_strcasecmp(line, "FatalErrors"))
+ FatalErrors = parse_fatal_errors(value);
+ else if (!_cups_strcasecmp(line, "FaxRetryInterval") && value)
+ {
+ JobRetryInterval = atoi(value);
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "FaxRetryInterval is deprecated; use "
+ "JobRetryInterval on line %d.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "FaxRetryLimit") && value)
+ {
+ JobRetryLimit = atoi(value);
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "FaxRetryLimit is deprecated; use "
+ "JobRetryLimit on line %d.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")
+#ifdef HAVE_SSL
+ || !_cups_strcasecmp(line, "SSLPort") || !_cups_strcasecmp(line, "SSLListen")
+#endif /* HAVE_SSL */
+ )
+ {
+ /*
+ * Add listening address(es) to the list...
+ */
+
+ cupsd_listener_t *lis; /* New listeners array */
+
+
+ /*
+ * Get the address list...
+ */
+
+ addrlist = get_address(value, IPP_PORT);
+
+ if (!addrlist)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad %s address %s at line %d.", line,
+ value, linenum);
+ continue;
+ }
+
+ /*
+ * Add each address...
+ */
+
+ for (addr = addrlist; addr; addr = addr->next)
+ {
+ /*
+ * See if this address is already present...
+ */
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ if (httpAddrEqual(&(addr->addr), &(lis->address)) &&
+ _httpAddrPort(&(addr->addr)) == _httpAddrPort(&(lis->address)))
+ break;
+
+ if (lis)
+ {
+ httpAddrString(&lis->address, temp, sizeof(temp));
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Duplicate listen address \"%s\" ignored.", temp);
+ continue;
+ }
+
+ /*
+ * Allocate another listener...
+ */
+
+ if (!Listeners)
+ Listeners = cupsArrayNew(NULL, NULL);
+
+ if (!Listeners)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate %s at line %d - %s.",
+ line, linenum, strerror(errno));
+ break;
+ }
+
+ if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate %s at line %d - %s.",
+ line, linenum, strerror(errno));
+ break;
+ }
+
+ cupsArrayAdd(Listeners, lis);
+
+ /*
+ * Copy the current address and log it...
+ */
+
+ memcpy(&(lis->address), &(addr->addr), sizeof(lis->address));
+ lis->fd = -1;
+
+#ifdef HAVE_SSL
+ if (!_cups_strcasecmp(line, "SSLPort") || !_cups_strcasecmp(line, "SSLListen"))
+ lis->encryption = HTTP_ENCRYPT_ALWAYS;
+#endif /* HAVE_SSL */
+
+ httpAddrString(&lis->address, temp, sizeof(temp));
+
+#ifdef AF_LOCAL
+ if (lis->address.addr.sa_family == AF_LOCAL)
+ cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s (Domain)", temp);
+ else
+#endif /* AF_LOCAL */
+ cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d (IPv%d)", temp,
+ _httpAddrPort(&(lis->address)),
+ _httpAddrFamily(&(lis->address)) == AF_INET ? 4 : 6);
+
+ if (!httpAddrLocalhost(&(lis->address)))
+ RemotePort = _httpAddrPort(&(lis->address));
+ }
+
+ /*
+ * Free the list...
+ */
+
+ httpAddrFreeList(addrlist);
+ }
+ else if (!_cups_strcasecmp(line, "BrowseAddress") && value)
+ {
+ /*
+ * Add a browse address to the list...
+ */
+
+ cupsd_dirsvc_addr_t *dira; /* New browse address array */
+
+
+ if (NumBrowsers == 0)
+ dira = malloc(sizeof(cupsd_dirsvc_addr_t));
+ else
+ dira = realloc(Browsers, (NumBrowsers + 1) * sizeof(cupsd_dirsvc_addr_t));
+
+ if (!dira)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate BrowseAddress at line %d - %s.",
+ linenum, strerror(errno));
+ continue;
+ }
+
+ Browsers = dira;
+ dira += NumBrowsers;
+
+ memset(dira, 0, sizeof(cupsd_dirsvc_addr_t));
+
+ if (!_cups_strcasecmp(value, "@LOCAL"))
+ {
+ /*
+ * Send browse data to all local interfaces...
+ */
+
+ strcpy(dira->iface, "*");
+ NumBrowsers ++;
+ }
+ else if (!_cups_strncasecmp(value, "@IF(", 4))
+ {
+ /*
+ * Send browse data to the named interface...
+ */
+
+ strlcpy(dira->iface, value + 4, sizeof(Browsers[0].iface));
+
+ ptr = dira->iface + strlen(dira->iface) - 1;
+ if (*ptr == ')')
+ *ptr = '\0';
+
+ NumBrowsers ++;
+ }
+ else if ((addrlist = get_address(value, BrowsePort)) != NULL)
+ {
+ /*
+ * Only IPv4 addresses are supported...
+ */
+
+ for (addr = addrlist; addr; addr = addr->next)
+ if (_httpAddrFamily(&(addr->addr)) == AF_INET)
+ break;
+
+ if (addr)
+ {
+ memcpy(&(dira->to), &(addrlist->addr), sizeof(dira->to));
+ httpAddrString(&(dira->to), temp, sizeof(temp));
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Sending browsing info to %s:%d (IPv4)",
+ temp, _httpAddrPort(&(dira->to)));
+
+ NumBrowsers ++;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad BrowseAddress %s at line %d.",
+ value, linenum);
+
+ httpAddrFreeList(addrlist);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad BrowseAddress %s at line %d.",
+ value, linenum);
+ }
+ else if (!_cups_strcasecmp(line, "BrowseOrder") && value)
+ {
+ /*
+ * "BrowseOrder Deny,Allow" or "BrowseOrder Allow,Deny"...
+ */
+
+ if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL)
+ if ((location = cupsdNewLocation("CUPS_INTERNAL_BROWSE_ACL")) != NULL)
+ cupsdAddLocation(location);
+
+ if (location == NULL)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to initialize browse access control list.");
+ else if (!_cups_strncasecmp(value, "deny", 4))
+ location->order_type = CUPSD_AUTH_ALLOW;
+ else if (!_cups_strncasecmp(value, "allow", 5))
+ location->order_type = CUPSD_AUTH_DENY;
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown BrowseOrder value %s on line %d.",
+ value, linenum);
+ }
+ else if (!_cups_strcasecmp(line, "BrowseProtocols") ||
+ !_cups_strcasecmp(line, "BrowseLocalProtocols") ||
+ !_cups_strcasecmp(line, "BrowseRemoteProtocols"))
+ {
+ /*
+ * "BrowseProtocols name [... name]"
+ * "BrowseLocalProtocols name [... name]"
+ * "BrowseRemoteProtocols name [... name]"
+ */
+
+ int protocols = parse_protocols(value);
+
+ if (protocols < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown browse protocol \"%s\" on line %d.",
+ value, linenum);
+ break;
+ }
+
+ if (_cups_strcasecmp(line, "BrowseLocalProtocols"))
+ BrowseRemoteProtocols = protocols;
+ if (_cups_strcasecmp(line, "BrowseRemoteProtocols"))
+ BrowseLocalProtocols = protocols;
+ }
+ else if ((!_cups_strcasecmp(line, "BrowseAllow") ||
+ !_cups_strcasecmp(line, "BrowseDeny")) && value)
+ {
+ /*
+ * BrowseAllow [From] host/ip...
+ * BrowseDeny [From] host/ip...
+ */
+
+ if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL)
+ if ((location = cupsdNewLocation("CUPS_INTERNAL_BROWSE_ACL")) != NULL)
+ cupsdAddLocation(location);
+
+
+ if (location == NULL)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to initialize browse access control list.");
+ else
+ {
+ if (!_cups_strncasecmp(value, "from", 4))
+ {
+ /*
+ * Skip leading "from"...
+ */
+
+ value += 4;
+ }
+
+ while (*value)
+ {
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (_cups_isspace(*value))
+ value ++;
+
+ if (!*value)
+ break;
+
+ /*
+ * Find the end of the value...
+ */
+
+ for (valueptr = value;
+ *valueptr && !_cups_isspace(*valueptr);
+ valueptr ++);
+
+ while (_cups_isspace(*valueptr))
+ *valueptr++ = '\0';
+
+ /*
+ * Figure out what form the allow/deny address takes:
+ *
+ * All
+ * None
+ * *.domain.com
+ * .domain.com
+ * host.domain.com
+ * nnn.*
+ * nnn.nnn.*
+ * nnn.nnn.nnn.*
+ * nnn.nnn.nnn.nnn
+ * nnn.nnn.nnn.nnn/mm
+ * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
+ */
+
+ if (!_cups_strcasecmp(value, "all"))
+ {
+ /*
+ * All hosts...
+ */
+
+ if (!_cups_strcasecmp(line, "BrowseAllow"))
+ cupsdAddIPMask(&(location->allow), zeros, zeros);
+ else
+ cupsdAddIPMask(&(location->deny), zeros, zeros);
+ }
+ else if (!_cups_strcasecmp(value, "none"))
+ {
+ /*
+ * No hosts...
+ */
+
+ if (!_cups_strcasecmp(line, "BrowseAllow"))
+ cupsdAddIPMask(&(location->allow), ones, zeros);
+ else
+ cupsdAddIPMask(&(location->deny), ones, zeros);
+ }
+#ifdef AF_INET6
+ else if (value[0] == '*' || value[0] == '.' ||
+ (!isdigit(value[0] & 255) && value[0] != '['))
+#else
+ else if (value[0] == '*' || value[0] == '.' ||
+ !isdigit(value[0] & 255))
+#endif /* AF_INET6 */
+ {
+ /*
+ * Host or domain name...
+ */
+
+ if (!_cups_strcasecmp(line, "BrowseAllow"))
+ cupsdAddNameMask(&(location->allow), value);
+ else
+ cupsdAddNameMask(&(location->deny), value);
+ }
+ else
+ {
+ /*
+ * One of many IP address forms...
+ */
+
+ if (!get_addr_and_mask(value, ip, mask))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.",
+ value, linenum);
+ break;
+ }
+
+ if (!_cups_strcasecmp(line, "BrowseAllow"))
+ cupsdAddIPMask(&(location->allow), ip, mask);
+ else
+ cupsdAddIPMask(&(location->deny), ip, mask);
+ }
+
+ /*
+ * Advance to next value...
+ */
+
+ value = valueptr;
+ }
+ }
+ }
+ else if (!_cups_strcasecmp(line, "BrowseRelay") && value)
+ {
+ /*
+ * BrowseRelay [from] source [to] destination
+ */
+
+ if (NumRelays == 0)
+ relay = malloc(sizeof(cupsd_dirsvc_relay_t));
+ else
+ relay = realloc(Relays, (NumRelays + 1) * sizeof(cupsd_dirsvc_relay_t));
+
+ if (!relay)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate BrowseRelay at line %d - %s.",
+ linenum, strerror(errno));
+ continue;
+ }
+
+ Relays = relay;
+ relay += NumRelays;
+
+ memset(relay, 0, sizeof(cupsd_dirsvc_relay_t));
+
+ if (!_cups_strncasecmp(value, "from ", 5))
+ {
+ /*
+ * Skip leading "from"...
+ */
+
+ value += 5;
+
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (_cups_isspace(*value))
+ value ++;
+ }
+
+ /*
+ * Find the end of the from value...
+ */
+
+ for (valueptr = value;
+ *valueptr && !_cups_isspace(*valueptr);
+ valueptr ++);
+
+ while (_cups_isspace(*valueptr))
+ *valueptr++ = '\0';
+
+ /*
+ * Figure out what form the from address takes:
+ *
+ * *.domain.com
+ * .domain.com
+ * host.domain.com
+ * nnn.*
+ * nnn.nnn.*
+ * nnn.nnn.nnn.*
+ * nnn.nnn.nnn.nnn
+ * nnn.nnn.nnn.nnn/mm
+ * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
+ */
+
+#ifdef AF_INET6
+ if (value[0] == '*' || value[0] == '.' ||
+ (!isdigit(value[0] & 255) && value[0] != '['))
+#else
+ if (value[0] == '*' || value[0] == '.' || !isdigit(value[0] & 255))
+#endif /* AF_INET6 */
+ {
+ /*
+ * Host or domain name...
+ */
+
+ if (!cupsdAddNameMask(&(relay->from), value))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate BrowseRelay name at line %d - %s.",
+ linenum, strerror(errno));
+ continue;
+ }
+ }
+ else
+ {
+ /*
+ * One of many IP address forms...
+ */
+
+ if (!get_addr_and_mask(value, ip, mask))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.",
+ value, linenum);
+ break;
+ }
+
+ if (!cupsdAddIPMask(&(relay->from), ip, mask))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate BrowseRelay IP at line %d - %s.",
+ linenum, strerror(errno));
+ continue;
+ }
+ }
+
+ /*
+ * Get "to" address and port...
+ */
+
+ if (!_cups_strncasecmp(valueptr, "to ", 3))
+ {
+ /*
+ * Strip leading "to"...
+ */
+
+ valueptr += 3;
+
+ while (_cups_isspace(*valueptr))
+ valueptr ++;
+ }
+
+ if ((addrlist = get_address(valueptr, BrowsePort)) != NULL)
+ {
+ /*
+ * Only IPv4 addresses are supported...
+ */
+
+ for (addr = addrlist; addr; addr = addr->next)
+ if (addr->addr.addr.sa_family == AF_INET)
+ break;
+
+ if (addr)
+ {
+ memcpy(&(relay->to), &(addrlist->addr), sizeof(relay->to));
+
+ httpAddrString(&(relay->to), temp, sizeof(temp));
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Relaying from %s to %s:%d (IPv4)",
+ value, temp, _httpAddrPort(&(relay->to)));
+
+ NumRelays ++;
+ }
+ else
+ {
+ cupsArrayDelete(relay->from);
+ relay->from = NULL;
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.",
+ valueptr, linenum);
+ }
+
+ httpAddrFreeList(addrlist);
+ }
+ else
+ {
+ cupsArrayDelete(relay->from);
+ relay->from = NULL;
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.",
+ valueptr, linenum);
+ }
+ }
+ else if (!_cups_strcasecmp(line, "BrowsePoll") && value)
+ {
+ /*
+ * BrowsePoll address[:port]
+ */
+
+ char *portname; /* Port name */
+ int portnum; /* Port number */
+ struct servent *service; /* Service */
+
+
+ /*
+ * Extract the port name from the address...
+ */
+
+ if ((portname = strrchr(value, ':')) != NULL && !strchr(portname, ']'))
+ {
+ *portname++ = '\0';
+
+ if (isdigit(*portname & 255))
+ portnum = atoi(portname);
+ else if ((service = getservbyname(portname, NULL)) != NULL)
+ portnum = ntohs(service->s_port);
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Lookup of service \"%s\" failed.",
+ portname);
+ continue;
+ }
+ }
+ else
+ portnum = ippPort();
+
+ /*
+ * Add the poll entry...
+ */
+
+ if (NumPolled == 0)
+ pollp = malloc(sizeof(cupsd_dirsvc_poll_t));
+ else
+ pollp = realloc(Polled, (NumPolled + 1) * sizeof(cupsd_dirsvc_poll_t));
+
+ if (!pollp)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate BrowsePoll at line %d - %s.",
+ linenum, strerror(errno));
+ continue;
+ }
+
+ Polled = pollp;
+ pollp += NumPolled;
+
+ NumPolled ++;
+ memset(pollp, 0, sizeof(cupsd_dirsvc_poll_t));
+
+ strlcpy(pollp->hostname, value, sizeof(pollp->hostname));
+ pollp->port = portnum;
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Polling %s:%d", pollp->hostname,
+ pollp->port);
+ }
+ else if (!_cups_strcasecmp(line, "DefaultAuthType") && value)
+ {
+ /*
+ * DefaultAuthType {basic,digest,basicdigest,negotiate}
+ */
+
+ if (!_cups_strcasecmp(value, "none"))
+ DefaultAuthType = CUPSD_AUTH_NONE;
+ else if (!_cups_strcasecmp(value, "basic"))
+ DefaultAuthType = CUPSD_AUTH_BASIC;
+ else if (!_cups_strcasecmp(value, "digest"))
+ DefaultAuthType = CUPSD_AUTH_DIGEST;
+ else if (!_cups_strcasecmp(value, "basicdigest"))
+ DefaultAuthType = CUPSD_AUTH_BASICDIGEST;
+#ifdef HAVE_GSSAPI
+ else if (!_cups_strcasecmp(value, "negotiate"))
+ DefaultAuthType = CUPSD_AUTH_NEGOTIATE;
+#endif /* HAVE_GSSAPI */
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Unknown default authorization type %s on line %d.",
+ value, linenum);
+ if (FatalErrors & CUPSD_FATAL_CONFIG)
+ return (0);
+ }
+ }
+#ifdef HAVE_SSL
+ else if (!_cups_strcasecmp(line, "DefaultEncryption"))
+ {
+ /*
+ * DefaultEncryption {Never,IfRequested,Required}
+ */
+
+ if (!value || !_cups_strcasecmp(value, "never"))
+ DefaultEncryption = HTTP_ENCRYPT_NEVER;
+ else if (!_cups_strcasecmp(value, "required"))
+ DefaultEncryption = HTTP_ENCRYPT_REQUIRED;
+ else if (!_cups_strcasecmp(value, "ifrequested"))
+ DefaultEncryption = HTTP_ENCRYPT_IF_REQUESTED;
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Unknown default encryption %s on line %d.",
+ value, linenum);
+ if (FatalErrors & CUPSD_FATAL_CONFIG)
+ return (0);
+ }
+ }
+#endif /* HAVE_SSL */
+ else if (!_cups_strcasecmp(line, "User") && value)
+ {
+ /*
+ * User ID to run as...
+ */
+
+ if (isdigit(value[0] & 255))
+ {
+ int uid = atoi(value);
+
+ if (!uid)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Will not use User 0 as specified on line %d "
+ "for security reasons. You must use a non-"
+ "privileged account instead.",
+ linenum);
+ else
+ User = atoi(value);
+ }
+ else
+ {
+ struct passwd *p; /* Password information */
+
+ endpwent();
+ p = getpwnam(value);
+
+ if (p)
+ {
+ if (!p->pw_uid)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Will not use User %s (UID=0) as specified on line "
+ "%d for security reasons. You must use a non-"
+ "privileged account instead.",
+ value, linenum);
+ else
+ User = p->pw_uid;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown User \"%s\" on line %d, ignoring.",
+ value, linenum);
+ }
+ }
+ else if (!_cups_strcasecmp(line, "Group") && value)
+ {
+ /*
+ * Group ID to run as...
+ */
+
+ if (isdigit(value[0]))
+ Group = atoi(value);
+ else
+ {
+ endgrent();
+ group = getgrnam(value);
+
+ if (group != NULL)
+ Group = group->gr_gid;
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown Group \"%s\" on line %d, ignoring.",
+ value, linenum);
+ }
+ }
+ else if (!_cups_strcasecmp(line, "SystemGroup") && value)
+ {
+ /*
+ * SystemGroup (admin) group(s)...
+ */
+
+ if (!parse_groups(value))
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown SystemGroup \"%s\" on line %d, ignoring.",
+ value, linenum);
+ }
+ else if (!_cups_strcasecmp(line, "HostNameLookups") && value)
+ {
+ /*
+ * Do hostname lookups?
+ */
+
+ if (!_cups_strcasecmp(value, "off") || !_cups_strcasecmp(value, "no") ||
+ !_cups_strcasecmp(value, "false"))
+ HostNameLookups = 0;
+ else if (!_cups_strcasecmp(value, "on") || !_cups_strcasecmp(value, "yes") ||
+ !_cups_strcasecmp(value, "true"))
+ HostNameLookups = 1;
+ else if (!_cups_strcasecmp(value, "double"))
+ HostNameLookups = 2;
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN, "Unknown HostNameLookups %s on line %d.",
+ value, linenum);
+ }
+ else if (!_cups_strcasecmp(line, "AccessLogLevel") && value)
+ {
+ /*
+ * Amount of logging to do to access log...
+ */
+
+ if (!_cups_strcasecmp(value, "all"))
+ AccessLogLevel = CUPSD_ACCESSLOG_ALL;
+ else if (!_cups_strcasecmp(value, "actions"))
+ AccessLogLevel = CUPSD_ACCESSLOG_ACTIONS;
+ else if (!_cups_strcasecmp(value, "config"))
+ AccessLogLevel = CUPSD_ACCESSLOG_CONFIG;
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN, "Unknown AccessLogLevel %s on line %d.",
+ value, linenum);
+ }
+ else if (!_cups_strcasecmp(line, "LogLevel") && value)
+ {
+ /*
+ * Amount of logging to do to error log...
+ */
+
+ if (!_cups_strcasecmp(value, "debug2"))
+ LogLevel = CUPSD_LOG_DEBUG2;
+ else if (!_cups_strcasecmp(value, "debug"))
+ LogLevel = CUPSD_LOG_DEBUG;
+ else if (!_cups_strcasecmp(value, "info"))
+ LogLevel = CUPSD_LOG_INFO;
+ else if (!_cups_strcasecmp(value, "notice"))
+ LogLevel = CUPSD_LOG_NOTICE;
+ else if (!_cups_strcasecmp(value, "warn"))
+ LogLevel = CUPSD_LOG_WARN;
+ else if (!_cups_strcasecmp(value, "error"))
+ LogLevel = CUPSD_LOG_ERROR;
+ else if (!_cups_strcasecmp(value, "crit"))
+ LogLevel = CUPSD_LOG_CRIT;
+ else if (!_cups_strcasecmp(value, "alert"))
+ LogLevel = CUPSD_LOG_ALERT;
+ else if (!_cups_strcasecmp(value, "emerg"))
+ LogLevel = CUPSD_LOG_EMERG;
+ else if (!_cups_strcasecmp(value, "none"))
+ LogLevel = CUPSD_LOG_NONE;
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN, "Unknown LogLevel %s on line %d.",
+ value, linenum);
+ }
+ else if (!_cups_strcasecmp(line, "LogTimeFormat") && value)
+ {
+ /*
+ * Amount of logging to do to error log...
+ */
+
+ if (!_cups_strcasecmp(value, "standard"))
+ LogTimeFormat = CUPSD_TIME_STANDARD;
+ else if (!_cups_strcasecmp(value, "usecs"))
+ LogTimeFormat = CUPSD_TIME_USECS;
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN, "Unknown LogTimeFormat %s on line %d.",
+ value, linenum);
+ }
+ else if (!_cups_strcasecmp(line, "PrintcapFormat") && value)
+ {
+ /*
+ * Format of printcap file?
+ */
+
+ if (!_cups_strcasecmp(value, "bsd"))
+ PrintcapFormat = PRINTCAP_BSD;
+ else if (!_cups_strcasecmp(value, "plist"))
+ PrintcapFormat = PRINTCAP_PLIST;
+ else if (!_cups_strcasecmp(value, "solaris"))
+ PrintcapFormat = PRINTCAP_SOLARIS;
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN, "Unknown PrintcapFormat %s on line %d.",
+ value, linenum);
+ }
+ else if (!_cups_strcasecmp(line, "ServerTokens") && value)
+ {
+ /*
+ * Set the string used for the Server header...
+ */
+
+ struct utsname plat; /* Platform info */
+
+
+ uname(&plat);
+
+ if (!_cups_strcasecmp(value, "ProductOnly"))
+ cupsdSetString(&ServerHeader, "CUPS");
+ else if (!_cups_strcasecmp(value, "Major"))
+ cupsdSetString(&ServerHeader, "CUPS/1");
+ else if (!_cups_strcasecmp(value, "Minor"))
+ cupsdSetString(&ServerHeader, "CUPS/1.4");
+ else if (!_cups_strcasecmp(value, "Minimal"))
+ cupsdSetString(&ServerHeader, CUPS_MINIMAL);
+ else if (!_cups_strcasecmp(value, "OS"))
+ cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s)", plat.sysname);
+ else if (!_cups_strcasecmp(value, "Full"))
+ cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s) IPP/1.1",
+ plat.sysname);
+ else if (!_cups_strcasecmp(value, "None"))
+ cupsdClearString(&ServerHeader);
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN, "Unknown ServerTokens %s on line %d.",
+ value, linenum);
+ }
+ else if (!_cups_strcasecmp(line, "PassEnv") && value)
+ {
+ /*
+ * PassEnv variable [... variable]
+ */
+
+ for (; *value;)
+ {
+ for (valuelen = 0; value[valuelen]; valuelen ++)
+ if (_cups_isspace(value[valuelen]) || value[valuelen] == ',')
+ break;
+
+ if (value[valuelen])
+ {
+ value[valuelen] = '\0';
+ valuelen ++;
+ }
+
+ cupsdSetEnv(value, NULL);
+
+ for (value += valuelen; *value; value ++)
+ if (!_cups_isspace(*value) || *value != ',')
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "ServerAlias") && value)
+ {
+ /*
+ * ServerAlias name [... name]
+ */
+
+ if (!ServerAlias)
+ ServerAlias = cupsArrayNew(NULL, NULL);
+
+ for (; *value;)
+ {
+ for (valuelen = 0; value[valuelen]; valuelen ++)
+ if (_cups_isspace(value[valuelen]) || value[valuelen] == ',')
+ break;
+
+ if (value[valuelen])
+ {
+ value[valuelen] = '\0';
+ valuelen ++;
+ }
+
+ cupsdAddAlias(ServerAlias, value);
+
+ for (value += valuelen; *value; value ++)
+ if (!_cups_isspace(*value) || *value != ',')
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "SetEnv") && value)
+ {
+ /*
+ * SetEnv variable value
+ */
+
+ for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
+
+ if (*valueptr)
+ {
+ /*
+ * Found a value...
+ */
+
+ while (isspace(*valueptr & 255))
+ *valueptr++ = '\0';
+
+ cupsdSetEnv(value, valueptr);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Missing value for SetEnv directive on line %d.",
+ linenum);
+ }
+#ifdef HAVE_SSL
+ else if (!_cups_strcasecmp(line, "SSLOptions"))
+ {
+ /*
+ * SSLOptions options
+ */
+
+ if (!value || !_cups_strcasecmp(value, "none"))
+ SSLOptions = CUPSD_SSL_NONE;
+ else if (!_cups_strcasecmp(value, "noemptyfragments"))
+ SSLOptions = CUPSD_SSL_NOEMPTY;
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown value \"%s\" for SSLOptions directive on "
+ "line %d.", value, linenum);
+ }
+#endif /* HAVE_SSL */
+ else
+ {
+ /*
+ * Find a simple variable in the list...
+ */
+
+ for (i = NUM_VARS, var = variables; i > 0; i --, var ++)
+ if (!_cups_strcasecmp(line, var->name))
+ break;
+
+ if (i == 0)
+ {
+ /*
+ * Unknown directive! Output an error message and continue...
+ */
+
+ if (!value)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value for %s on line %d.",
+ line, linenum);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown directive %s on line %d.",
+ line, linenum);
+ continue;
+ }
+
+ switch (var->type)
+ {
+ case CUPSD_VARTYPE_INTEGER :
+ if (!value)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Missing integer value for %s on line %d.",
+ line, linenum);
+ else
+ {
+ int n; /* Number */
+ char *units; /* Units */
+
+
+ n = strtol(value, &units, 0);
+
+ if (units && *units)
+ {
+ if (tolower(units[0] & 255) == 'g')
+ n *= 1024 * 1024 * 1024;
+ else if (tolower(units[0] & 255) == 'm')
+ n *= 1024 * 1024;
+ else if (tolower(units[0] & 255) == 'k')
+ n *= 1024;
+ else if (tolower(units[0] & 255) == 't')
+ n *= 262144;
+ }
+
+ if (n < 0)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad negative integer value for %s on line %d.",
+ line, linenum);
+ else
+ *((int *)var->ptr) = n;
+ }
+ break;
+
+ case CUPSD_VARTYPE_BOOLEAN :
+ if (!value)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Missing boolean value for %s on line %d.",
+ line, linenum);
+ else if (!_cups_strcasecmp(value, "true") ||
+ !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "enabled") ||
+ !_cups_strcasecmp(value, "yes") ||
+ atoi(value) != 0)
+ *((int *)var->ptr) = TRUE;
+ else if (!_cups_strcasecmp(value, "false") ||
+ !_cups_strcasecmp(value, "off") ||
+ !_cups_strcasecmp(value, "disabled") ||
+ !_cups_strcasecmp(value, "no") ||
+ !_cups_strcasecmp(value, "0"))
+ *((int *)var->ptr) = FALSE;
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown boolean value %s on line %d.",
+ value, linenum);
+ break;
+
+ case CUPSD_VARTYPE_PATHNAME :
+ if (!value)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Missing pathname value for %s on line %d.",
+ line, linenum);
+ break;
+ }
+
+ if (value[0] == '/')
+ strlcpy(temp, value, sizeof(temp));
+ else
+ snprintf(temp, sizeof(temp), "%s/%s", ServerRoot, value);
+
+ if (access(temp, 0))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "File or directory for \"%s %s\" on line %d "
+ "does not exist.", line, value, linenum);
+ break;
+ }
+
+ case CUPSD_VARTYPE_STRING :
+ cupsdSetString((char **)var->ptr, value);
+ break;
+ }
+ }
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'read_location()' - Read a <Location path> definition.
+ */
+
+static int /* O - New line number or 0 on error */
+read_location(cups_file_t *fp, /* I - Configuration file */
+ char *location, /* I - Location name/path */
+ int linenum) /* I - Current line number */
+{
+ cupsd_location_t *loc, /* New location */
+ *parent; /* Parent location */
+ char line[HTTP_MAX_BUFFER],
+ /* Line buffer */
+ *value, /* Value for directive */
+ *valptr; /* Pointer into value */
+
+
+ if ((parent = cupsdFindLocation(location)) != NULL)
+ cupsdLogMessage(CUPSD_LOG_WARN, "Duplicate <Location %s> on line %d.",
+ location, linenum);
+ else if ((parent = cupsdNewLocation(location)) == NULL)
+ return (0);
+ else
+ {
+ cupsdAddLocation(parent);
+
+ parent->limit = CUPSD_AUTH_LIMIT_ALL;
+ }
+
+ loc = parent;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ /*
+ * Decode the directive...
+ */
+
+ if (!_cups_strcasecmp(line, "</Location>"))
+ return (linenum);
+ else if (!_cups_strcasecmp(line, "<Limit") ||
+ !_cups_strcasecmp(line, "<LimitExcept"))
+ {
+ if (!value)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum);
+ if (FatalErrors & CUPSD_FATAL_CONFIG)
+ return (0);
+ else
+ continue;
+ }
+
+ if ((loc = cupsdCopyLocation(parent)) == NULL)
+ return (0);
+
+ cupsdAddLocation(loc);
+
+ loc->limit = 0;
+ while (*value)
+ {
+ for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
+
+ if (*valptr)
+ *valptr++ = '\0';
+
+ if (!strcmp(value, "ALL"))
+ loc->limit = CUPSD_AUTH_LIMIT_ALL;
+ else if (!strcmp(value, "GET"))
+ loc->limit |= CUPSD_AUTH_LIMIT_GET;
+ else if (!strcmp(value, "HEAD"))
+ loc->limit |= CUPSD_AUTH_LIMIT_HEAD;
+ else if (!strcmp(value, "OPTIONS"))
+ loc->limit |= CUPSD_AUTH_LIMIT_OPTIONS;
+ else if (!strcmp(value, "POST"))
+ loc->limit |= CUPSD_AUTH_LIMIT_POST;
+ else if (!strcmp(value, "PUT"))
+ loc->limit |= CUPSD_AUTH_LIMIT_PUT;
+ else if (!strcmp(value, "TRACE"))
+ loc->limit |= CUPSD_AUTH_LIMIT_TRACE;
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN, "Unknown request type %s on line %d.",
+ value, linenum);
+
+ for (value = valptr; isspace(*value & 255); value ++);
+ }
+
+ if (!_cups_strcasecmp(line, "<LimitExcept"))
+ loc->limit = CUPSD_AUTH_LIMIT_ALL ^ loc->limit;
+
+ parent->limit &= ~loc->limit;
+ }
+ else if (!_cups_strcasecmp(line, "</Limit>") ||
+ !_cups_strcasecmp(line, "</LimitExcept>"))
+ loc = parent;
+ else if (!parse_aaa(loc, line, value, linenum))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown Location directive %s on line %d.",
+ line, linenum);
+ if (FatalErrors & CUPSD_FATAL_CONFIG)
+ return (0);
+ }
+ }
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unexpected end-of-file at line %d while reading location.",
+ linenum);
+
+ return ((FatalErrors & CUPSD_FATAL_CONFIG) ? 0 : linenum);
+}
+
+
+/*
+ * 'read_policy()' - Read a <Policy name> definition.
+ */
+
+static int /* O - New line number or 0 on error */
+read_policy(cups_file_t *fp, /* I - Configuration file */
+ char *policy, /* I - Location name/path */
+ int linenum) /* I - Current line number */
+{
+ int i; /* Looping var */
+ cupsd_policy_t *pol; /* Policy */
+ cupsd_location_t *op; /* Policy operation */
+ int num_ops; /* Number of IPP operations */
+ ipp_op_t ops[100]; /* Operations */
+ char line[HTTP_MAX_BUFFER],
+ /* Line buffer */
+ *value, /* Value for directive */
+ *valptr; /* Pointer into value */
+
+
+ /*
+ * Create the policy...
+ */
+
+ if ((pol = cupsdFindPolicy(policy)) != NULL)
+ cupsdLogMessage(CUPSD_LOG_WARN, "Duplicate <Policy %s> on line %d.",
+ policy, linenum);
+ else if ((pol = cupsdAddPolicy(policy)) == NULL)
+ return (0);
+
+ /*
+ * Read from the file...
+ */
+
+ op = NULL;
+ num_ops = 0;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ /*
+ * Decode the directive...
+ */
+
+ if (!_cups_strcasecmp(line, "</Policy>"))
+ {
+ if (op)
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Missing </Limit> before </Policy> on line %d.",
+ linenum);
+
+ set_policy_defaults(pol);
+
+ return (linenum);
+ }
+ else if (!_cups_strcasecmp(line, "<Limit") && !op)
+ {
+ if (!value)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum);
+ if (FatalErrors & CUPSD_FATAL_CONFIG)
+ return (0);
+ else
+ continue;
+ }
+
+ /*
+ * Scan for IPP operation names...
+ */
+
+ num_ops = 0;
+
+ while (*value)
+ {
+ for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
+
+ if (*valptr)
+ *valptr++ = '\0';
+
+ if (num_ops < (int)(sizeof(ops) / sizeof(ops[0])))
+ {
+ if (!_cups_strcasecmp(value, "All"))
+ ops[num_ops] = IPP_ANY_OPERATION;
+ else if ((ops[num_ops] = ippOpValue(value)) == IPP_BAD_OPERATION)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad IPP operation name \"%s\" on line %d.",
+ value, linenum);
+ else
+ num_ops ++;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Too many operations listed on line %d.",
+ linenum);
+
+ for (value = valptr; isspace(*value & 255); value ++);
+ }
+
+ /*
+ * If none are specified, apply the policy to all operations...
+ */
+
+ if (num_ops == 0)
+ {
+ ops[0] = IPP_ANY_OPERATION;
+ num_ops = 1;
+ }
+
+ /*
+ * Add a new policy for the first operation...
+ */
+
+ op = cupsdAddPolicyOp(pol, NULL, ops[0]);
+ }
+ else if (!_cups_strcasecmp(line, "</Limit>") && op)
+ {
+ /*
+ * Finish the current operation limit...
+ */
+
+ if (num_ops > 1)
+ {
+ /*
+ * Copy the policy to the other operations...
+ */
+
+ for (i = 1; i < num_ops; i ++)
+ cupsdAddPolicyOp(pol, op, ops[i]);
+ }
+
+ op = NULL;
+ }
+ else if (!_cups_strcasecmp(line, "JobPrivateAccess") ||
+ !_cups_strcasecmp(line, "JobPrivateValues") ||
+ !_cups_strcasecmp(line, "SubscriptionPrivateAccess") ||
+ !_cups_strcasecmp(line, "SubscriptionPrivateValues"))
+ {
+ if (op)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "%s directive must appear outside <Limit>...</Limit> "
+ "on line %d.", line, linenum);
+ if (FatalErrors & CUPSD_FATAL_CONFIG)
+ return (0);
+ }
+ else
+ {
+ /*
+ * Pull out whitespace-delimited values...
+ */
+
+ while (*value)
+ {
+ /*
+ * Find the end of the current value...
+ */
+
+ for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
+
+ if (*valptr)
+ *valptr++ = '\0';
+
+ /*
+ * Save it appropriately...
+ */
+
+ if (!_cups_strcasecmp(line, "JobPrivateAccess"))
+ {
+ /*
+ * JobPrivateAccess {all|default|user/group list|@@ACL}
+ */
+
+ if (!_cups_strcasecmp(value, "default"))
+ {
+ cupsdAddString(&(pol->job_access), "@OWNER");
+ cupsdAddString(&(pol->job_access), "@SYSTEM");
+ }
+ else
+ cupsdAddString(&(pol->job_access), value);
+ }
+ else if (!_cups_strcasecmp(line, "JobPrivateValues"))
+ {
+ /*
+ * JobPrivateValues {all|none|default|attribute list}
+ */
+
+ if (!_cups_strcasecmp(value, "default"))
+ {
+ cupsdAddString(&(pol->job_attrs), "job-name");
+ cupsdAddString(&(pol->job_attrs), "job-originating-host-name");
+ cupsdAddString(&(pol->job_attrs), "job-originating-user-name");
+ }
+ else
+ cupsdAddString(&(pol->job_attrs), value);
+ }
+ else if (!_cups_strcasecmp(line, "SubscriptionPrivateAccess"))
+ {
+ /*
+ * SubscriptionPrivateAccess {all|default|user/group list|@@ACL}
+ */
+
+ if (!_cups_strcasecmp(value, "default"))
+ {
+ cupsdAddString(&(pol->sub_access), "@OWNER");
+ cupsdAddString(&(pol->sub_access), "@SYSTEM");
+ }
+ else
+ cupsdAddString(&(pol->sub_access), value);
+ }
+ else /* if (!_cups_strcasecmp(line, "SubscriptionPrivateValues")) */
+ {
+ /*
+ * SubscriptionPrivateValues {all|none|default|attribute list}
+ */
+
+ if (!_cups_strcasecmp(value, "default"))
+ {
+ cupsdAddString(&(pol->sub_attrs), "notify-events");
+ cupsdAddString(&(pol->sub_attrs), "notify-pull-method");
+ cupsdAddString(&(pol->sub_attrs), "notify-recipient-uri");
+ cupsdAddString(&(pol->sub_attrs), "notify-subscriber-user-name");
+ cupsdAddString(&(pol->sub_attrs), "notify-user-data");
+ }
+ else
+ cupsdAddString(&(pol->sub_attrs), value);
+ }
+
+ /*
+ * Find the next string on the line...
+ */
+
+ for (value = valptr; isspace(*value & 255); value ++);
+ }
+ }
+ }
+ else if (!op)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Missing <Limit ops> directive before %s on line %d.",
+ line, linenum);
+ if (FatalErrors & CUPSD_FATAL_CONFIG)
+ return (0);
+ }
+ else if (!parse_aaa(op, line, value, linenum))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown Policy Limit directive %s on line %d.",
+ line, linenum);
+
+ if (FatalErrors & CUPSD_FATAL_CONFIG)
+ return (0);
+ }
+ }
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unexpected end-of-file at line %d while reading policy "
+ "\"%s\".", linenum, policy);
+
+ return ((FatalErrors & CUPSD_FATAL_CONFIG) ? 0 : linenum);
+}
+
+
+/*
+ * 'set_policy_defaults()' - Set default policy values as needed.
+ */
+
+static void
+set_policy_defaults(cupsd_policy_t *pol)/* I - Policy */
+{
+ cupsd_location_t *op; /* Policy operation */
+
+
+ /*
+ * Verify that we have an explicit policy for Validate-Job, Cancel-Jobs,
+ * Cancel-My-Jobs, Close-Job, and CUPS-Get-Document, which ensures that
+ * upgrades do not introduce new security issues...
+ */
+
+ if ((op = cupsdFindPolicyOp(pol, IPP_VALIDATE_JOB)) == NULL ||
+ op->op == IPP_ANY_OPERATION)
+ {
+ if ((op = cupsdFindPolicyOp(pol, IPP_PRINT_JOB)) != NULL &&
+ op->op != IPP_ANY_OPERATION)
+ {
+ /*
+ * Add a new limit for Validate-Job using the Print-Job limit as a
+ * template...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No limit for Validate-Job defined in policy %s "
+ "- using Print-Job's policy.", pol->name);
+
+ cupsdAddPolicyOp(pol, op, IPP_VALIDATE_JOB);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No limit for Validate-Job defined in policy %s "
+ "and no suitable template found.", pol->name);
+ }
+
+ if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_JOBS)) == NULL ||
+ op->op == IPP_ANY_OPERATION)
+ {
+ if ((op = cupsdFindPolicyOp(pol, IPP_PAUSE_PRINTER)) != NULL &&
+ op->op != IPP_ANY_OPERATION)
+ {
+ /*
+ * Add a new limit for Cancel-Jobs using the Pause-Printer limit as a
+ * template...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No limit for Cancel-Jobs defined in policy %s "
+ "- using Pause-Printer's policy.", pol->name);
+
+ cupsdAddPolicyOp(pol, op, IPP_CANCEL_JOBS);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No limit for Cancel-Jobs defined in policy %s "
+ "and no suitable template found.", pol->name);
+ }
+
+ if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_MY_JOBS)) == NULL ||
+ op->op == IPP_ANY_OPERATION)
+ {
+ if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
+ op->op != IPP_ANY_OPERATION)
+ {
+ /*
+ * Add a new limit for Cancel-My-Jobs using the Send-Document limit as
+ * a template...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No limit for Cancel-My-Jobs defined in policy %s "
+ "- using Send-Document's policy.", pol->name);
+
+ cupsdAddPolicyOp(pol, op, IPP_CANCEL_MY_JOBS);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No limit for Cancel-My-Jobs defined in policy %s "
+ "and no suitable template found.", pol->name);
+ }
+
+ if ((op = cupsdFindPolicyOp(pol, IPP_CLOSE_JOB)) == NULL ||
+ op->op == IPP_ANY_OPERATION)
+ {
+ if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
+ op->op != IPP_ANY_OPERATION)
+ {
+ /*
+ * Add a new limit for Close-Job using the Send-Document limit as a
+ * template...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No limit for Close-Job defined in policy %s "
+ "- using Send-Document's policy.", pol->name);
+
+ cupsdAddPolicyOp(pol, op, IPP_CLOSE_JOB);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No limit for Close-Job defined in policy %s "
+ "and no suitable template found.", pol->name);
+ }
+
+ if ((op = cupsdFindPolicyOp(pol, CUPS_GET_DOCUMENT)) == NULL ||
+ op->op == IPP_ANY_OPERATION)
+ {
+ if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
+ op->op != IPP_ANY_OPERATION)
+ {
+ /*
+ * Add a new limit for CUPS-Get-Document using the Send-Document
+ * limit as a template...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No limit for CUPS-Get-Document defined in policy %s "
+ "- using Send-Document's policy.", pol->name);
+
+ cupsdAddPolicyOp(pol, op, CUPS_GET_DOCUMENT);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No limit for CUPS-Get-Document defined in policy %s "
+ "and no suitable template found.", pol->name);
+ }
+
+ /*
+ * Verify we have JobPrivateAccess, JobPrivateValues,
+ * SubscriptionPrivateAccess, and SubscriptionPrivateValues in the policy.
+ */
+
+ if (!pol->job_access)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No JobPrivateAccess defined in policy %s "
+ "- using defaults.", pol->name);
+ cupsdAddString(&(pol->job_access), "@OWNER");
+ cupsdAddString(&(pol->job_access), "@SYSTEM");
+ }
+
+ if (!pol->job_attrs)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No JobPrivateValues defined in policy %s "
+ "- using defaults.", pol->name);
+ cupsdAddString(&(pol->job_attrs), "job-name");
+ cupsdAddString(&(pol->job_attrs), "job-originating-host-name");
+ cupsdAddString(&(pol->job_attrs), "job-originating-user-name");
+ }
+
+ if (!pol->sub_access)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No SubscriptionPrivateAccess defined in policy %s "
+ "- using defaults.", pol->name);
+ cupsdAddString(&(pol->sub_access), "@OWNER");
+ cupsdAddString(&(pol->sub_access), "@SYSTEM");
+ }
+
+ if (!pol->sub_attrs)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No SubscriptionPrivateValues defined in policy %s "
+ "- using defaults.", pol->name);
+ cupsdAddString(&(pol->sub_attrs), "notify-events");
+ cupsdAddString(&(pol->sub_attrs), "notify-pull-method");
+ cupsdAddString(&(pol->sub_attrs), "notify-recipient-uri");
+ cupsdAddString(&(pol->sub_attrs), "notify-subscriber-user-name");
+ cupsdAddString(&(pol->sub_attrs), "notify-user-data");
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/conf.h b/scheduler/conf.h
new file mode 100644
index 000000000..1166328a5
--- /dev/null
+++ b/scheduler/conf.h
@@ -0,0 +1,299 @@
+/*
+ * "$Id$"
+ *
+ * Configuration file definitions for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+
+/*
+ * Log levels...
+ */
+
+typedef enum
+{
+ CUPSD_LOG_PPD = -4, /* Used internally for PPD keywords */
+ CUPSD_LOG_ATTR, /* Used internally for attributes */
+ CUPSD_LOG_STATE, /* Used internally for state-reasons */
+ CUPSD_LOG_PAGE, /* Used internally for page logging */
+ CUPSD_LOG_NONE,
+ CUPSD_LOG_EMERG, /* Emergency issues */
+ CUPSD_LOG_ALERT, /* Something bad happened that needs attention */
+ CUPSD_LOG_CRIT, /* Critical error but server continues */
+ CUPSD_LOG_ERROR, /* Error condition */
+ CUPSD_LOG_WARN, /* Warning */
+ CUPSD_LOG_NOTICE, /* Normal condition that needs logging */
+ CUPSD_LOG_INFO, /* General information */
+ CUPSD_LOG_DEBUG, /* General debugging */
+ CUPSD_LOG_DEBUG2 /* Detailed debugging */
+} cupsd_loglevel_t;
+
+typedef enum
+{
+ CUPSD_ACCESSLOG_CONFIG, /* Log config requests */
+ CUPSD_ACCESSLOG_ACTIONS, /* Log config, print, and job management requests */
+ CUPSD_ACCESSLOG_ALL /* Log everything */
+} cupsd_accesslog_t;
+
+typedef enum
+{
+ CUPSD_TIME_STANDARD, /* "Standard" Apache/CLF format */
+ CUPSD_TIME_USECS /* Standard format with microseconds */
+} cupsd_time_t;
+
+
+/*
+ * FatalErrors flags...
+ */
+
+#define CUPSD_FATAL_NONE 0 /* No errors are fatal */
+#define CUPSD_FATAL_BROWSE 1 /* Browse bind errors are fatal */
+#define CUPSD_FATAL_CONFIG 2 /* Config file syntax errors are fatal */
+#define CUPSD_FATAL_LISTEN 4 /* Listen/Port bind errors are fatal */
+#define CUPSD_FATAL_LOG 8 /* Log file errors are fatal */
+#define CUPSD_FATAL_PERMISSIONS 16 /* File permission errors are fatal */
+#define CUPSD_FATAL_ALL ~0 /* All errors are fatal */
+
+
+/*
+ * Printcap formats...
+ */
+
+#define PRINTCAP_BSD 0 /* Berkeley LPD format */
+#define PRINTCAP_SOLARIS 1 /* Solaris lpsched format */
+#define PRINTCAP_PLIST 2 /* Mac OS X plist format */
+
+
+/*
+ * SSL options (bits)...
+ */
+
+#define CUPSD_SSL_NONE 0 /* No special options */
+#define CUPSD_SSL_NOEMPTY 1 /* Do not insert empty fragments */
+
+
+/*
+ * ServerAlias data...
+ */
+
+typedef struct
+{
+ size_t namelen; /* Length of alias name */
+ char name[1]; /* Alias name */
+} cupsd_alias_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR char *ConfigurationFile VALUE(NULL),
+ /* Configuration file to use */
+ *ServerName VALUE(NULL),
+ /* FQDN for server */
+ *ServerAdmin VALUE(NULL),
+ /* Administrator's email */
+ *ServerRoot VALUE(NULL),
+ /* Root directory for scheduler */
+ *ServerBin VALUE(NULL),
+ /* Root directory for binaries */
+ *StateDir VALUE(NULL),
+ /* Root directory for state data */
+ *RequestRoot VALUE(NULL),
+ /* Directory for request files */
+ *DocumentRoot VALUE(NULL);
+ /* Root directory for documents */
+VAR cups_array_t *ServerAlias VALUE(NULL);
+ /* Alias names for server */
+VAR int ServerNameIsIP VALUE(0);
+ /* Is the ServerName an IP address? */
+VAR int NumSystemGroups VALUE(0);
+ /* Number of system group names */
+VAR char *SystemGroups[MAX_SYSTEM_GROUPS]
+ VALUE({0});
+ /* System group names */
+VAR gid_t SystemGroupIDs[MAX_SYSTEM_GROUPS]
+ VALUE({0});
+ /* System group IDs */
+VAR char *AccessLog VALUE(NULL),
+ /* Access log filename */
+ *ErrorLog VALUE(NULL),
+ /* Error log filename */
+ *PageLog VALUE(NULL),
+ /* Page log filename */
+ *CacheDir VALUE(NULL),
+ /* Cache file directory */
+ *DataDir VALUE(NULL),
+ /* Data file directory */
+ *DefaultLanguage VALUE(NULL),
+ /* Default language encoding */
+ *DefaultLocale VALUE(NULL),
+ /* Default locale */
+ *DefaultPaperSize VALUE(NULL),
+ /* Default paper size */
+ *ErrorPolicy VALUE(NULL),
+ /* Default printer-error-policy */
+ *RIPCache VALUE(NULL),
+ /* Amount of memory for RIPs */
+ *TempDir VALUE(NULL),
+ /* Temporary directory */
+ *Printcap VALUE(NULL),
+ /* Printcap file */
+ *PrintcapGUI VALUE(NULL),
+ /* GUI program to use for IRIX */
+ *FontPath VALUE(NULL),
+ /* Font search path */
+ *RemoteRoot VALUE(NULL),
+ /* Remote root user */
+ *Classification VALUE(NULL);
+ /* Classification of system */
+VAR uid_t User VALUE(1);
+ /* User ID for server */
+VAR gid_t Group VALUE(0);
+ /* Group ID for server */
+VAR cupsd_accesslog_t AccessLogLevel VALUE(CUPSD_ACCESSLOG_ACTIONS);
+ /* Access log level */
+VAR int ClassifyOverride VALUE(0),
+ /* Allow overrides? */
+ ConfigFilePerm VALUE(0640),
+ /* Permissions for config files */
+ LogDebugHistory VALUE(200),
+ /* Amount of automatic debug history */
+ FatalErrors VALUE(CUPSD_FATAL_CONFIG),
+ /* Which errors are fatal? */
+ LogFilePerm VALUE(0644);
+ /* Permissions for log files */
+VAR cupsd_loglevel_t LogLevel VALUE(CUPSD_LOG_WARN);
+ /* Error log level */
+VAR cupsd_time_t LogTimeFormat VALUE(CUPSD_TIME_STANDARD);
+ /* Log file time format */
+VAR int MaxClients VALUE(100),
+ /* Maximum number of clients */
+ MaxClientsPerHost VALUE(0),
+ /* Maximum number of clients per host */
+ MaxCopies VALUE(CUPS_DEFAULT_MAX_COPIES),
+ /* Maximum number of copies per job */
+ MaxLogSize VALUE(1024 * 1024),
+ /* Maximum size of log files */
+ MaxRequestSize VALUE(0),
+ /* Maximum size of IPP requests */
+ HostNameLookups VALUE(FALSE),
+ /* Do we do reverse lookups? */
+ Timeout VALUE(DEFAULT_TIMEOUT),
+ /* Timeout during requests */
+ KeepAlive VALUE(TRUE),
+ /* Support the Keep-Alive option? */
+ KeepAliveTimeout VALUE(DEFAULT_KEEPALIVE),
+ /* Timeout between requests */
+ ImplicitClasses VALUE(TRUE),
+ /* Are classes implicitly created? */
+ ImplicitAnyClasses VALUE(FALSE),
+ /* Create AnyPrinter classes? */
+ HideImplicitMembers VALUE(TRUE),
+ /* Hide implicit class members? */
+ FileDevice VALUE(FALSE),
+ /* Allow file: devices? */
+ FilterLimit VALUE(0),
+ /* Max filter cost at any time */
+ FilterLevel VALUE(0),
+ /* Current filter level */
+ FilterNice VALUE(0),
+ /* Nice value for filters */
+ ReloadTimeout VALUE(DEFAULT_KEEPALIVE),
+ /* Timeout before reload from SIGHUP */
+ RootCertDuration VALUE(300),
+ /* Root certificate update interval */
+ RunUser VALUE(0),
+ /* User to run as, used for files */
+ PrintcapFormat VALUE(PRINTCAP_BSD),
+ /* Format of printcap file? */
+ DefaultShared VALUE(TRUE),
+ /* Share printers by default? */
+ MultipleOperationTimeout VALUE(DEFAULT_TIMEOUT),
+ /* multiple-operation-time-out value */
+ WebInterface VALUE(CUPS_DEFAULT_WEBIF);
+ /* Enable the web interface? */
+VAR cups_file_t *AccessFile VALUE(NULL),
+ /* Access log file */
+ *ErrorFile VALUE(NULL),
+ /* Error log file */
+ *PageFile VALUE(NULL);
+ /* Page log file */
+VAR char *PageLogFormat VALUE(NULL);
+ /* Page log format */
+VAR mime_t *MimeDatabase VALUE(NULL);
+ /* MIME type database */
+VAR int NumMimeTypes VALUE(0);
+ /* Number of MIME types */
+VAR const char **MimeTypes VALUE(NULL);
+ /* Array of MIME types */
+
+#ifdef HAVE_SSL
+VAR char *ServerCertificate VALUE(NULL);
+ /* Server certificate file */
+# if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
+VAR char *ServerKey VALUE(NULL);
+ /* Server key file */
+# endif /* HAVE_LIBSSL || HAVE_GNUTLS */
+VAR int SSLOptions VALUE(CUPSD_SSL_NONE);
+ /* SSL/TLS options */
+#endif /* HAVE_SSL */
+
+#ifdef HAVE_LAUNCHD
+VAR int LaunchdTimeout VALUE(DEFAULT_KEEPALIVE);
+ /* Time after which an idle cupsd will exit */
+#endif /* HAVE_LAUNCHD */
+
+#ifdef HAVE_AUTHORIZATION_H
+VAR char *SystemGroupAuthKey VALUE(NULL);
+ /* System group auth key */
+#endif /* HAVE_AUTHORIZATION_H */
+
+
+/*
+ * Prototypes...
+ */
+
+extern void cupsdAddAlias(cups_array_t *aliases, const char *name);
+extern int cupsdCheckLogFile(cups_file_t **lf, const char *logname);
+extern int cupsdCheckPermissions(const char *filename,
+ const char *suffix, int mode,
+ int user, int group, int is_dir,
+ int create_dir);
+extern int cupsdCheckProgram(const char *filename, cupsd_printer_t *p);
+extern void cupsdFreeAliases(cups_array_t *aliases);
+extern char *cupsdGetDateTime(struct timeval *t, cupsd_time_t format);
+extern void cupsdLogFCMessage(void *context, _cups_fc_result_t result,
+ const char *message);
+#ifdef HAVE_GSSAPI
+extern int cupsdLogGSSMessage(int level, int major_status,
+ int minor_status,
+ const char *message, ...);
+#endif /* HAVE_GSSAPI */
+extern int cupsdLogJob(cupsd_job_t *job, int level, const char *message, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 3, 4)))
+#endif /* __GNUC__ */
+;
+extern int cupsdLogMessage(int level, const char *message, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+#endif /* __GNUC__ */
+;
+extern int cupsdLogPage(cupsd_job_t *job, const char *page);
+extern int cupsdLogRequest(cupsd_client_t *con, http_status_t code);
+extern int cupsdReadConfiguration(void);
+extern int cupsdWriteErrorLog(int level, const char *message);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/cups-deviced.c b/scheduler/cups-deviced.c
new file mode 100644
index 000000000..0cd5b8ea8
--- /dev/null
+++ b/scheduler/cups-deviced.c
@@ -0,0 +1,810 @@
+/*
+ * "$Id$"
+ *
+ * Device scanning mini-daemon for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Scan for devices and return an IPP response.
+ * add_device() - Add a new device to the list.
+ * compare_devices() - Compare device names to eliminate duplicates.
+ * get_current_time() - Get the current time as a double value in seconds.
+ * get_device() - Get a device from a backend.
+ * process_children() - Process all dead children...
+ * sigchld_handler() - Handle 'child' signals from old processes.
+ * start_backend() - Run a backend to gather the available devices.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "util.h"
+#include <cups/array.h>
+#include <cups/dir.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <poll.h>
+
+
+/*
+ * Constants...
+ */
+
+#define MAX_BACKENDS 200 /* Maximum number of backends we'll run */
+
+
+/*
+ * Backend information...
+ */
+
+typedef struct
+{
+ char *name; /* Name of backend */
+ int pid, /* Process ID */
+ status; /* Exit status */
+ cups_file_t *pipe; /* Pipe from backend stdout */
+ int count; /* Number of devices found */
+} cupsd_backend_t;
+
+
+/*
+ * Device information structure...
+ */
+
+typedef struct
+{
+ char device_class[128], /* Device class */
+ device_info[128], /* Device info/description */
+ device_uri[1024]; /* Device URI */
+} cupsd_device_t;
+
+
+/*
+ * Local globals...
+ */
+
+static int num_backends = 0,
+ /* Total backends */
+ active_backends = 0;
+ /* Active backends */
+static cupsd_backend_t backends[MAX_BACKENDS];
+ /* Array of backends */
+static struct pollfd backend_fds[MAX_BACKENDS];
+ /* Array for poll() */
+static cups_array_t *devices; /* Array of devices */
+static int normal_user; /* Normal user ID */
+static int device_limit; /* Maximum number of devices */
+static int send_class, /* Send device-class attribute? */
+ send_info, /* Send device-info attribute? */
+ send_make_and_model,
+ /* Send device-make-and-model attribute? */
+ send_uri, /* Send device-uri attribute? */
+ send_id, /* Send device-id attribute? */
+ send_location; /* Send device-location attribute? */
+static int dead_children = 0;
+ /* Dead children? */
+
+
+/*
+ * Local functions...
+ */
+
+static int add_device(const char *device_class,
+ const char *device_make_and_model,
+ const char *device_info,
+ const char *device_uri,
+ const char *device_id,
+ const char *device_location);
+static int compare_devices(cupsd_device_t *p0,
+ cupsd_device_t *p1);
+static double get_current_time(void);
+static int get_device(cupsd_backend_t *backend);
+static void process_children(void);
+static void sigchld_handler(int sig);
+static int start_backend(const char *backend, int root);
+
+
+/*
+ * 'main()' - Scan for devices and return an IPP response.
+ *
+ * Usage:
+ *
+ * cups-deviced request_id limit options
+ */
+
+int /* O - Exit code */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ int request_id; /* Request ID */
+ int timeout; /* Timeout in seconds */
+ const char *server_bin; /* CUPS_SERVERBIN environment variable */
+ char filename[1024]; /* Backend directory filename */
+ cups_dir_t *dir; /* Directory pointer */
+ cups_dentry_t *dent; /* Directory entry */
+ double current_time, /* Current time */
+ end_time; /* Ending time */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ cups_array_t *requested, /* requested-attributes values */
+ *exclude, /* exclude-schemes values */
+ *include; /* include-schemes values */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Check the command-line...
+ */
+
+ if (argc != 6)
+ {
+ fputs("Usage: cups-deviced request-id limit timeout user-id options\n", stderr);
+
+ return (1);
+ }
+
+ request_id = atoi(argv[1]);
+ if (request_id < 1)
+ {
+ fprintf(stderr, "ERROR: [cups-deviced] Bad request ID %d!\n", request_id);
+
+ return (1);
+ }
+
+ device_limit = atoi(argv[2]);
+ if (device_limit < 0)
+ {
+ fprintf(stderr, "ERROR: [cups-deviced] Bad limit %d!\n", device_limit);
+
+ return (1);
+ }
+
+ timeout = atoi(argv[3]);
+ if (timeout < 1)
+ {
+ fprintf(stderr, "ERROR: [cups-deviced] Bad timeout %d!\n", timeout);
+
+ return (1);
+ }
+
+ normal_user = atoi(argv[4]);
+ if (normal_user <= 0)
+ {
+ fprintf(stderr, "ERROR: [cups-deviced] Bad user %d!\n", normal_user);
+
+ return (1);
+ }
+
+ num_options = cupsParseOptions(argv[5], 0, &options);
+ requested = cupsdCreateStringsArray(cupsGetOption("requested-attributes",
+ num_options, options));
+ exclude = cupsdCreateStringsArray(cupsGetOption("exclude-schemes",
+ num_options, options));
+ include = cupsdCreateStringsArray(cupsGetOption("include-schemes",
+ num_options, options));
+
+ if (!requested || cupsArrayFind(requested, "all") != NULL)
+ {
+ send_class = send_info = send_make_and_model = send_uri = send_id =
+ send_location = 1;
+ }
+ else
+ {
+ send_class = cupsArrayFind(requested, "device-class") != NULL;
+ send_info = cupsArrayFind(requested, "device-info") != NULL;
+ send_make_and_model = cupsArrayFind(requested, "device-make-and-model") != NULL;
+ send_uri = cupsArrayFind(requested, "device-uri") != NULL;
+ send_id = cupsArrayFind(requested, "device-id") != NULL;
+ send_location = cupsArrayFind(requested, "device-location") != NULL;
+ }
+
+ /*
+ * Listen to child signals...
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGCHLD, sigchld_handler);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGCHLD);
+ action.sa_handler = sigchld_handler;
+ sigaction(SIGCHLD, &action, NULL);
+#else
+ signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Try opening the backend directory...
+ */
+
+ if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL)
+ server_bin = CUPS_SERVERBIN;
+
+ snprintf(filename, sizeof(filename), "%s/backend", server_bin);
+
+ if ((dir = cupsDirOpen(filename)) == NULL)
+ {
+ fprintf(stderr, "ERROR: [cups-deviced] Unable to open backend directory "
+ "\"%s\": %s", filename, strerror(errno));
+
+ return (1);
+ }
+
+ /*
+ * Setup the devices array...
+ */
+
+ devices = cupsArrayNew((cups_array_func_t)compare_devices, NULL);
+
+ /*
+ * Loop through all of the device backends...
+ */
+
+ while ((dent = cupsDirRead(dir)) != NULL)
+ {
+ /*
+ * Skip entries that are not executable files...
+ */
+
+ if (!S_ISREG(dent->fileinfo.st_mode) ||
+ !isalnum(dent->filename[0] & 255) ||
+ (dent->fileinfo.st_mode & (S_IRUSR | S_IXUSR)) != (S_IRUSR | S_IXUSR))
+ continue;
+
+ /*
+ * Skip excluded or not included backends...
+ */
+
+ if (cupsArrayFind(exclude, dent->filename) ||
+ (include && !cupsArrayFind(include, dent->filename)))
+ continue;
+
+ /*
+ * Backends without permissions for normal users run as root,
+ * all others run as the unprivileged user...
+ */
+
+ start_backend(dent->filename,
+ !(dent->fileinfo.st_mode & (S_IRWXG | S_IRWXO)));
+ }
+
+ cupsDirClose(dir);
+
+ /*
+ * Collect devices...
+ */
+
+ if (getenv("SOFTWARE"))
+ puts("Content-Type: application/ipp\n");
+
+ cupsdSendIPPHeader(IPP_OK, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US");
+
+ end_time = get_current_time() + timeout;
+
+ while (active_backends > 0 && (current_time = get_current_time()) < end_time)
+ {
+ /*
+ * Collect the output from the backends...
+ */
+
+ timeout = (int)(1000 * (end_time - current_time));
+
+ if (poll(backend_fds, num_backends, timeout) > 0)
+ {
+ for (i = 0; i < num_backends; i ++)
+ if (backend_fds[i].revents && backends[i].pipe)
+ {
+ cups_file_t *bpipe = backends[i].pipe;
+ /* Copy of pipe for backend... */
+
+ do
+ {
+ if (get_device(backends + i))
+ {
+ backend_fds[i].fd = 0;
+ backend_fds[i].events = 0;
+ break;
+ }
+ }
+ while (bpipe->ptr &&
+ memchr(bpipe->ptr, '\n', bpipe->end - bpipe->ptr));
+ }
+ }
+
+ /*
+ * Get exit status from children...
+ */
+
+ if (dead_children)
+ process_children();
+ }
+
+ cupsdSendIPPTrailer();
+
+ /*
+ * Terminate any remaining backends and exit...
+ */
+
+ if (active_backends > 0)
+ {
+ for (i = 0; i < num_backends; i ++)
+ if (backends[i].pid)
+ kill(backends[i].pid, SIGTERM);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'add_device()' - Add a new device to the list.
+ */
+
+static int /* O - 0 on success, -1 on error */
+add_device(
+ const char *device_class, /* I - Device class */
+ const char *device_make_and_model, /* I - Device make and model */
+ const char *device_info, /* I - Device information */
+ const char *device_uri, /* I - Device URI */
+ const char *device_id, /* I - 1284 device ID */
+ const char *device_location) /* I - Physical location */
+{
+ cupsd_device_t *device; /* New device */
+
+
+ /*
+ * Allocate memory for the device record...
+ */
+
+ if ((device = calloc(1, sizeof(cupsd_device_t))) == NULL)
+ {
+ fputs("ERROR: [cups-deviced] Ran out of memory allocating a device!\n",
+ stderr);
+ return (-1);
+ }
+
+ /*
+ * Copy the strings over...
+ */
+
+ strlcpy(device->device_class, device_class, sizeof(device->device_class));
+ strlcpy(device->device_info, device_info, sizeof(device->device_info));
+ strlcpy(device->device_uri, device_uri, sizeof(device->device_uri));
+
+ /*
+ * Add the device to the array and return...
+ */
+
+ if (cupsArrayFind(devices, device))
+ {
+ /*
+ * Avoid duplicates!
+ */
+
+ free(device);
+ }
+ else
+ {
+ cupsArrayAdd(devices, device);
+
+ if (device_limit <= 0 || cupsArrayCount(devices) < device_limit)
+ {
+ /*
+ * Send device info...
+ */
+
+ cupsdSendIPPGroup(IPP_TAG_PRINTER);
+ if (send_class)
+ cupsdSendIPPString(IPP_TAG_KEYWORD, "device-class",
+ device_class);
+ if (send_info)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-info", device_info);
+ if (send_make_and_model)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-make-and-model",
+ device_make_and_model);
+ if (send_uri)
+ cupsdSendIPPString(IPP_TAG_URI, "device-uri", device_uri);
+ if (send_id)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-id",
+ device_id ? device_id : "");
+ if (send_location)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-location",
+ device_location ? device_location : "");
+
+ fflush(stdout);
+ fputs("DEBUG: Flushed attributes...\n", stderr);
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'compare_devices()' - Compare device names to eliminate duplicates.
+ */
+
+static int /* O - Result of comparison */
+compare_devices(cupsd_device_t *d0, /* I - First device */
+ cupsd_device_t *d1) /* I - Second device */
+{
+ int diff; /* Difference between strings */
+
+
+ /*
+ * Sort devices by device-info, device-class, and device-uri...
+ */
+
+ if ((diff = cupsdCompareNames(d0->device_info, d1->device_info)) != 0)
+ return (diff);
+ else if ((diff = _cups_strcasecmp(d0->device_class, d1->device_class)) != 0)
+ return (diff);
+ else
+ return (_cups_strcasecmp(d0->device_uri, d1->device_uri));
+}
+
+
+/*
+ * 'get_current_time()' - Get the current time as a double value in seconds.
+ */
+
+static double /* O - Time in seconds */
+get_current_time(void)
+{
+ struct timeval curtime; /* Current time */
+
+
+ gettimeofday(&curtime, NULL);
+
+ return (curtime.tv_sec + 0.000001 * curtime.tv_usec);
+}
+
+
+/*
+ * 'get_device()' - Get a device from a backend.
+ */
+
+static int /* O - 0 on success, -1 on error */
+get_device(cupsd_backend_t *backend) /* I - Backend to read from */
+{
+ char line[2048], /* Line from backend */
+ temp[2048], /* Copy of line */
+ *ptr, /* Pointer into line */
+ *dclass, /* Device class */
+ *uri, /* Device URI */
+ *make_model, /* Make and model */
+ *info, /* Device info */
+ *device_id, /* 1284 device ID */
+ *location; /* Physical location */
+
+
+ if (cupsFileGets(backend->pipe, line, sizeof(line)))
+ {
+ /*
+ * Each line is of the form:
+ *
+ * class URI "make model" "name" ["1284 device ID"] ["location"]
+ */
+
+ strlcpy(temp, line, sizeof(temp));
+
+ /*
+ * device-class
+ */
+
+ dclass = temp;
+
+ for (ptr = temp; *ptr; ptr ++)
+ if (isspace(*ptr & 255))
+ break;
+
+ while (isspace(*ptr & 255))
+ *ptr++ = '\0';
+
+ /*
+ * device-uri
+ */
+
+ if (!*ptr)
+ goto error;
+
+ for (uri = ptr; *ptr; ptr ++)
+ if (isspace(*ptr & 255))
+ break;
+
+ while (isspace(*ptr & 255))
+ *ptr++ = '\0';
+
+ /*
+ * device-make-and-model
+ */
+
+ if (*ptr != '\"')
+ goto error;
+
+ for (ptr ++, make_model = ptr; *ptr && *ptr != '\"'; ptr ++)
+ {
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+ }
+
+ if (*ptr != '\"')
+ goto error;
+
+ for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
+
+ /*
+ * device-info
+ */
+
+ if (*ptr != '\"')
+ goto error;
+
+ for (ptr ++, info = ptr; *ptr && *ptr != '\"'; ptr ++)
+ {
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+ }
+
+ if (*ptr != '\"')
+ goto error;
+
+ for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
+
+ /*
+ * device-id
+ */
+
+ if (*ptr == '\"')
+ {
+ for (ptr ++, device_id = ptr; *ptr && *ptr != '\"'; ptr ++)
+ {
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+ }
+
+ if (*ptr != '\"')
+ goto error;
+
+ for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
+
+ /*
+ * device-location
+ */
+
+ if (*ptr == '\"')
+ {
+ for (ptr ++, location = ptr; *ptr && *ptr != '\"'; ptr ++)
+ {
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+ }
+
+ if (*ptr != '\"')
+ goto error;
+
+ *ptr = '\0';
+ }
+ else
+ location = NULL;
+ }
+ else
+ {
+ device_id = NULL;
+ location = NULL;
+ }
+
+ /*
+ * Add the device to the array of available devices...
+ */
+
+ if (!add_device(dclass, make_model, info, uri, device_id, location))
+ fprintf(stderr, "DEBUG: [cups-deviced] Found device \"%s\"...\n", uri);
+
+ return (0);
+ }
+
+ /*
+ * End of file...
+ */
+
+ cupsFileClose(backend->pipe);
+ backend->pipe = NULL;
+
+ return (-1);
+
+ /*
+ * Bad format; strip trailing newline and write an error message.
+ */
+
+ error:
+
+ if (line[strlen(line) - 1] == '\n')
+ line[strlen(line) - 1] = '\0';
+
+ fprintf(stderr, "ERROR: [cups-deviced] Bad line from \"%s\": %s\n",
+ backend->name, line);
+ return (0);
+}
+
+
+/*
+ * 'process_children()' - Process all dead children...
+ */
+
+static void
+process_children(void)
+{
+ int i; /* Looping var */
+ int status; /* Exit status of child */
+ int pid; /* Process ID of child */
+ cupsd_backend_t *backend; /* Current backend */
+ const char *name; /* Name of process */
+
+
+ /*
+ * Reset the dead_children flag...
+ */
+
+ dead_children = 0;
+
+ /*
+ * Collect the exit status of some children...
+ */
+
+#ifdef HAVE_WAITPID
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+#elif defined(HAVE_WAIT3)
+ while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
+#else
+ if ((pid = wait(&status)) > 0)
+#endif /* HAVE_WAITPID */
+ {
+ if (status == SIGTERM)
+ status = 0;
+
+ for (i = num_backends, backend = backends; i > 0; i --, backend ++)
+ if (backend->pid == pid)
+ break;
+
+ if (i > 0)
+ {
+ name = backend->name;
+ backend->pid = 0;
+ backend->status = status;
+
+ active_backends --;
+ }
+ else
+ name = "Unknown";
+
+ if (status)
+ {
+ if (WIFEXITED(status))
+ fprintf(stderr,
+ "ERROR: [cups-deviced] PID %d (%s) stopped with status %d!\n",
+ pid, name, WEXITSTATUS(status));
+ else
+ fprintf(stderr,
+ "ERROR: [cups-deviced] PID %d (%s) crashed on signal %d!\n",
+ pid, name, WTERMSIG(status));
+ }
+ else
+ fprintf(stderr,
+ "DEBUG: [cups-deviced] PID %d (%s) exited with no errors.\n",
+ pid, name);
+ }
+}
+
+
+/*
+ * 'sigchld_handler()' - Handle 'child' signals from old processes.
+ */
+
+static void
+sigchld_handler(int sig) /* I - Signal number */
+{
+ (void)sig;
+
+ /*
+ * Flag that we have dead children...
+ */
+
+ dead_children = 1;
+
+ /*
+ * Reset the signal handler as needed...
+ */
+
+#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
+ signal(SIGCLD, sigchld_handler);
+#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
+}
+
+
+/*
+ * 'start_backend()' - Run a backend to gather the available devices.
+ */
+
+static int /* O - 0 on success, -1 on error */
+start_backend(const char *name, /* I - Backend to run */
+ int root) /* I - Run as root? */
+{
+ const char *server_bin; /* CUPS_SERVERBIN environment variable */
+ char program[1024]; /* Full path to backend */
+ cupsd_backend_t *backend; /* Current backend */
+ char *argv[2]; /* Command-line arguments */
+
+
+ if (num_backends >= MAX_BACKENDS)
+ {
+ fprintf(stderr, "ERROR: Too many backends (%d)!\n", num_backends);
+ return (-1);
+ }
+
+ if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL)
+ server_bin = CUPS_SERVERBIN;
+
+ snprintf(program, sizeof(program), "%s/backend/%s", server_bin, name);
+
+ if (_cupsFileCheck(program, _CUPS_FILE_CHECK_PROGRAM, !geteuid(),
+ _cupsFileCheckFilter, NULL))
+ return (-1);
+
+ backend = backends + num_backends;
+
+ argv[0] = (char *)name;
+ argv[1] = NULL;
+
+ if ((backend->pipe = cupsdPipeCommand(&(backend->pid), program, argv,
+ root ? 0 : normal_user)) == NULL)
+ {
+ fprintf(stderr, "ERROR: [cups-deviced] Unable to execute \"%s\" - %s\n",
+ program, strerror(errno));
+ return (-1);
+ }
+
+ /*
+ * Fill in the rest of the backend information...
+ */
+
+ fprintf(stderr, "DEBUG: [cups-deviced] Started backend %s (PID %d)\n",
+ program, backend->pid);
+
+ backend_fds[num_backends].fd = cupsFileNumber(backend->pipe);
+ backend_fds[num_backends].events = POLLIN;
+
+ backend->name = strdup(name);
+ backend->status = 0;
+ backend->count = 0;
+
+ active_backends ++;
+ num_backends ++;
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/cups-driverd.cxx b/scheduler/cups-driverd.cxx
new file mode 100644
index 000000000..9e0e02005
--- /dev/null
+++ b/scheduler/cups-driverd.cxx
@@ -0,0 +1,2569 @@
+/*
+ * "$Id$"
+ *
+ * PPD/driver support for CUPS.
+ *
+ * This program handles listing and installing static PPD files, PPD files
+ * created from driver information files, and dynamically generated PPD files
+ * using driver helper programs.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Scan for drivers and return an IPP response.
+ * add_ppd() - Add a PPD file.
+ * cat_drv() - Generate a PPD from a driver info file.
+ * cat_ppd() - Copy a PPD file to stdout.
+ * copy_static() - Copy a static PPD file to stdout.
+ * compare_inodes() - Compare two inodes.
+ * compare_matches() - Compare PPD match scores for sorting.
+ * compare_names() - Compare PPD filenames for sorting.
+ * compare_ppds() - Compare PPD file make and model names for sorting.
+ * dump_ppds_dat() - Dump the contents of the ppds.dat file.
+ * free_array() - Free an array of strings.
+ * list_ppds() - List PPD files.
+ * load_drv() - Load the PPDs from a driver information file.
+ * load_drivers() - Load driver-generated PPD files.
+ * load_ppds() - Load PPD files recursively.
+ * load_ppds_dat() - Load the ppds.dat file.
+ * regex_device_id() - Compile a regular expression based on the 1284 device
+ * ID.
+ * regex_string() - Construct a regular expression to compare a simple
+ * string.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "util.h"
+#include <cups/dir.h>
+#include <cups/transcode.h>
+#include <cups/ppd-private.h>
+#include <ppdc/ppdc.h>
+#include <regex.h>
+
+
+/*
+ * Constants...
+ */
+
+#define PPD_SYNC 0x50504437 /* Sync word for ppds.dat (PPD7) */
+#define PPD_MAX_LANG 32 /* Maximum languages */
+#define PPD_MAX_PROD 32 /* Maximum products */
+#define PPD_MAX_VERS 32 /* Maximum versions */
+
+#define PPD_TYPE_POSTSCRIPT 0 /* PostScript PPD */
+#define PPD_TYPE_PDF 1 /* PDF PPD */
+#define PPD_TYPE_RASTER 2 /* CUPS raster PPD */
+#define PPD_TYPE_FAX 3 /* Facsimile/MFD PPD */
+#define PPD_TYPE_UNKNOWN 4 /* Other/hybrid PPD */
+#define PPD_TYPE_DRV 5 /* Driver info file */
+
+static const char * const ppd_types[] = /* ppd-type values */
+{
+ "postscript",
+ "pdf",
+ "raster",
+ "fax",
+ "unknown",
+ "drv"
+};
+
+
+/*
+ * PPD information structures...
+ */
+
+typedef struct /**** PPD record ****/
+{
+ time_t mtime; /* Modification time */
+ off_t size; /* Size in bytes */
+ int model_number; /* cupsModelNumber */
+ int type; /* ppd-type */
+ char filename[512], /* Filename */
+ name[512], /* PPD name */
+ languages[PPD_MAX_LANG][6],
+ /* LanguageVersion/cupsLanguages */
+ products[PPD_MAX_PROD][128],
+ /* Product strings */
+ psversions[PPD_MAX_VERS][32],
+ /* PSVersion strings */
+ make[128], /* Manufacturer */
+ make_and_model[128], /* NickName/ModelName */
+ device_id[256], /* IEEE 1284 Device ID */
+ scheme[128]; /* PPD scheme */
+} ppd_rec_t;
+
+typedef struct /**** In-memory record ****/
+{
+ int found; /* 1 if PPD is found */
+ int matches; /* Match count */
+ ppd_rec_t record; /* PPDs.dat record */
+} ppd_info_t;
+
+
+/*
+ * Globals...
+ */
+
+cups_array_t *Inodes = NULL, /* Inodes of directories we've visited */
+ *PPDsByName = NULL, /* PPD files sorted by filename and name */
+ *PPDsByMakeModel = NULL;/* PPD files sorted by make and model */
+int ChangedPPD; /* Did we change the PPD database? */
+
+
+/*
+ * Local functions...
+ */
+
+static ppd_info_t *add_ppd(const char *filename, const char *name,
+ const char *language, const char *make,
+ const char *make_and_model,
+ const char *device_id, const char *product,
+ const char *psversion, time_t mtime,
+ size_t size, int model_number, int type,
+ const char *scheme);
+static int cat_drv(const char *name, int request_id);
+static int cat_ppd(const char *name, int request_id);
+static int cat_static(const char *name, int request_id);
+static int compare_inodes(struct stat *a, struct stat *b);
+static int compare_matches(const ppd_info_t *p0,
+ const ppd_info_t *p1);
+static int compare_names(const ppd_info_t *p0,
+ const ppd_info_t *p1);
+static int compare_ppds(const ppd_info_t *p0,
+ const ppd_info_t *p1);
+static int dump_ppds_dat(void);
+static void free_array(cups_array_t *a);
+static int list_ppds(int request_id, int limit, const char *opt);
+static int load_drivers(cups_array_t *include,
+ cups_array_t *exclude);
+static int load_drv(const char *filename, const char *name,
+ cups_file_t *fp, time_t mtime, off_t size);
+static int load_ppds(const char *d, const char *p, int descend);
+static void load_ppds_dat(char *filename, size_t filesize,
+ int verbose);
+static regex_t *regex_device_id(const char *device_id);
+static regex_t *regex_string(const char *s);
+
+
+/*
+ * 'main()' - Scan for drivers and return an IPP response.
+ *
+ * Usage:
+ *
+ * cups-driverd request_id limit options
+ */
+
+int /* O - Exit code */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ /*
+ * Install or list PPDs...
+ */
+
+ if (argc == 3 && !strcmp(argv[1], "cat"))
+ return (cat_ppd(argv[2], 0));
+ else if (argc == 2 && !strcmp(argv[1], "dump"))
+ return (dump_ppds_dat());
+ else if (argc == 4 && !strcmp(argv[1], "get"))
+ return (cat_ppd(argv[3], atoi(argv[2])));
+ else if (argc == 5 && !strcmp(argv[1], "list"))
+ return (list_ppds(atoi(argv[2]), atoi(argv[3]), argv[4]));
+ else
+ {
+ fputs("Usage: cups-driverd cat ppd-name\n", stderr);
+ fputs("Usage: cups-driverd dump\n", stderr);
+ fputs("Usage: cups-driverd get request_id ppd-name\n", stderr);
+ fputs("Usage: cups-driverd list request_id limit options\n", stderr);
+ return (1);
+ }
+}
+
+
+/*
+ * 'add_ppd()' - Add a PPD file.
+ */
+
+static ppd_info_t * /* O - PPD */
+add_ppd(const char *filename, /* I - PPD filename */
+ const char *name, /* I - PPD name */
+ const char *language, /* I - LanguageVersion */
+ const char *make, /* I - Manufacturer */
+ const char *make_and_model, /* I - NickName/ModelName */
+ const char *device_id, /* I - 1284DeviceID */
+ const char *product, /* I - Product */
+ const char *psversion, /* I - PSVersion */
+ time_t mtime, /* I - Modification time */
+ size_t size, /* I - File size */
+ int model_number, /* I - Model number */
+ int type, /* I - Driver type */
+ const char *scheme) /* I - PPD scheme */
+{
+ ppd_info_t *ppd; /* PPD */
+ char *recommended; /* Foomatic driver string */
+
+
+ /*
+ * Add a new PPD file...
+ */
+
+ if ((ppd = (ppd_info_t *)calloc(1, sizeof(ppd_info_t))) == NULL)
+ {
+ fprintf(stderr,
+ "ERROR: [cups-driverd] Ran out of memory for %d PPD files!\n",
+ cupsArrayCount(PPDsByName));
+ return (NULL);
+ }
+
+ /*
+ * Zero-out the PPD data and copy the values over...
+ */
+
+ ppd->found = 1;
+ ppd->record.mtime = mtime;
+ ppd->record.size = size;
+ ppd->record.model_number = model_number;
+ ppd->record.type = type;
+
+ strlcpy(ppd->record.filename, filename, sizeof(ppd->record.filename));
+ strlcpy(ppd->record.name, name, sizeof(ppd->record.name));
+ strlcpy(ppd->record.languages[0], language,
+ sizeof(ppd->record.languages[0]));
+ strlcpy(ppd->record.products[0], product, sizeof(ppd->record.products[0]));
+ strlcpy(ppd->record.psversions[0], psversion,
+ sizeof(ppd->record.psversions[0]));
+ strlcpy(ppd->record.make, make, sizeof(ppd->record.make));
+ strlcpy(ppd->record.make_and_model, make_and_model,
+ sizeof(ppd->record.make_and_model));
+ strlcpy(ppd->record.device_id, device_id, sizeof(ppd->record.device_id));
+ strlcpy(ppd->record.scheme, scheme, sizeof(ppd->record.scheme));
+
+ /*
+ * Strip confusing (and often wrong) "recommended" suffix added by
+ * Foomatic drivers...
+ */
+
+ if ((recommended = strstr(ppd->record.make_and_model,
+ " (recommended)")) != NULL)
+ *recommended = '\0';
+
+ /*
+ * Add the PPD to the PPD arrays...
+ */
+
+ cupsArrayAdd(PPDsByName, ppd);
+ cupsArrayAdd(PPDsByMakeModel, ppd);
+
+ /*
+ * Return the new PPD pointer...
+ */
+
+ return (ppd);
+}
+
+
+/*
+ * 'cat_drv()' - Generate a PPD from a driver info file.
+ */
+
+static int /* O - Exit code */
+cat_drv(const char *name, /* I - PPD name */
+ int request_id) /* I - Request ID for response? */
+{
+ const char *datadir; // CUPS_DATADIR env var
+ ppdcSource *src; // PPD source file data
+ ppdcDriver *d; // Current driver
+ cups_file_t *out; // Stdout via CUPS file API
+ char message[2048], // status-message
+ filename[1024], // Full path to .drv file(s)
+ scheme[32], // URI scheme ("drv")
+ userpass[256], // User/password info (unused)
+ host[2], // Hostname (unused)
+ resource[1024], // Resource path (/dir/to/filename.drv)
+ *pc_file_name; // Filename portion of URI
+ int port; // Port number (unused)
+
+
+ // Determine where CUPS has installed the data files...
+ if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+
+ // Pull out the path to the .drv file...
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, name, scheme, sizeof(scheme),
+ userpass, sizeof(userpass), host, sizeof(host), &port,
+ resource, sizeof(resource)) < HTTP_URI_OK ||
+ strstr(resource, "../") ||
+ (pc_file_name = strrchr(resource, '/')) == NULL ||
+ pc_file_name == resource)
+ {
+ fprintf(stderr, "ERROR: Bad PPD name \"%s\"!\n", name);
+
+ if (request_id)
+ {
+ snprintf(message, sizeof(message), "Bad PPD name \"%s\"!", name);
+
+ cupsdSendIPPHeader(IPP_NOT_FOUND, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+ "en-US");
+ cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message);
+ cupsdSendIPPTrailer();
+ }
+
+ return (1);
+ }
+
+ *pc_file_name++ = '\0';
+
+#ifdef __APPLE__
+ if (!strncmp(resource, "/Library/Printers/PPDs/Contents/Resources/", 42) ||
+ !strncmp(resource, "/System/Library/Printers/PPDs/Contents/Resources/", 49))
+ strlcpy(filename, resource, sizeof(filename));
+ else
+#endif // __APPLE__
+ {
+ snprintf(filename, sizeof(filename), "%s/drv%s", datadir, resource);
+ if (access(filename, 0))
+ snprintf(filename, sizeof(filename), "%s/model%s", datadir, resource);
+ }
+
+ src = new ppdcSource(filename);
+
+ for (d = (ppdcDriver *)src->drivers->first();
+ d;
+ d = (ppdcDriver *)src->drivers->next())
+ if (!strcmp(pc_file_name, d->pc_file_name->value) ||
+ (d->file_name && !strcmp(pc_file_name, d->file_name->value)))
+ break;
+
+ if (d)
+ {
+ ppdcArray *locales; // Locale names
+ ppdcCatalog *catalog; // Message catalog in .drv file
+
+
+ fprintf(stderr, "DEBUG2: [cups-driverd] %d locales defined in \"%s\"...\n",
+ src->po_files->count, filename);
+
+ locales = new ppdcArray();
+ for (catalog = (ppdcCatalog *)src->po_files->first();
+ catalog;
+ catalog = (ppdcCatalog *)src->po_files->next())
+ {
+ fprintf(stderr, "DEBUG2: [cups-driverd] Adding locale \"%s\"...\n",
+ catalog->locale->value);
+ catalog->locale->retain();
+ locales->add(catalog->locale);
+ }
+
+ if (request_id)
+ {
+ cupsdSendIPPHeader(IPP_OK, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+ "en-US");
+ cupsdSendIPPTrailer();
+ fflush(stdout);
+ }
+
+ out = cupsFileStdout();
+ d->write_ppd_file(out, NULL, locales, src, PPDC_LFONLY);
+ cupsFileClose(out);
+
+ locales->release();
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: PPD \"%s\" not found!\n", name);
+
+ if (request_id)
+ {
+ snprintf(message, sizeof(message), "PPD \"%s\" not found!", name);
+
+ cupsdSendIPPHeader(IPP_NOT_FOUND, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+ "en-US");
+ cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message);
+ cupsdSendIPPTrailer();
+ }
+ }
+
+ src->release();
+
+ return (!d);
+}
+
+
+/*
+ * 'cat_ppd()' - Copy a PPD file to stdout.
+ */
+
+static int /* O - Exit code */
+cat_ppd(const char *name, /* I - PPD name */
+ int request_id) /* I - Request ID for response? */
+{
+ char scheme[256], /* Scheme from PPD name */
+ *sptr, /* Pointer into scheme */
+ line[1024], /* Line/filename */
+ message[2048]; /* status-message */
+
+
+ /*
+ * Figure out if this is a static or dynamic PPD file...
+ */
+
+ strlcpy(scheme, name, sizeof(scheme));
+ if ((sptr = strchr(scheme, ':')) != NULL)
+ {
+ *sptr = '\0';
+
+ if (!strcmp(scheme, "file"))
+ {
+ /*
+ * "file:name" == "name"...
+ */
+
+ name += 5;
+ scheme[0] = '\0';
+ }
+ }
+ else
+ scheme[0] = '\0';
+
+ if (request_id > 0)
+ puts("Content-Type: application/ipp\n");
+
+ if (!scheme[0])
+ return (cat_static(name, request_id));
+ else if (!strcmp(scheme, "drv"))
+ return (cat_drv(name, request_id));
+ else
+ {
+ /*
+ * Dynamic PPD, see if we have a driver program to support it...
+ */
+
+ const char *serverbin; /* CUPS_SERVERBIN env var */
+ char *argv[4]; /* Arguments for program */
+
+
+ if ((serverbin = getenv("CUPS_SERVERBIN")) == NULL)
+ serverbin = CUPS_SERVERBIN;
+
+ snprintf(line, sizeof(line), "%s/driver/%s", serverbin, scheme);
+ if (access(line, X_OK))
+ {
+ /*
+ * File does not exist or is not executable...
+ */
+
+ fprintf(stderr, "ERROR: [cups-driverd] Unable to access \"%s\" - %s\n",
+ line, strerror(errno));
+
+ if (request_id > 0)
+ {
+ snprintf(message, sizeof(message), "Unable to access \"%s\" - %s",
+ line, strerror(errno));
+
+ cupsdSendIPPHeader(IPP_NOT_FOUND, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+ "en-US");
+ cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message);
+ cupsdSendIPPTrailer();
+ }
+
+ return (1);
+ }
+
+ /*
+ * Yes, let it cat the PPD file...
+ */
+
+ if (request_id)
+ {
+ cupsdSendIPPHeader(IPP_OK, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+ "en-US");
+ cupsdSendIPPTrailer();
+ }
+
+ argv[0] = scheme;
+ argv[1] = (char *)"cat";
+ argv[2] = (char *)name;
+ argv[3] = NULL;
+
+ if (cupsdExec(line, argv))
+ {
+ /*
+ * Unable to execute driver...
+ */
+
+ fprintf(stderr, "ERROR: [cups-driverd] Unable to execute \"%s\" - %s\n",
+ line, strerror(errno));
+ return (1);
+ }
+ }
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'copy_static()' - Copy a static PPD file to stdout.
+ */
+
+static int /* O - Exit code */
+cat_static(const char *name, /* I - PPD name */
+ int request_id) /* I - Request ID for response? */
+{
+ cups_file_t *fp; /* PPD file */
+ const char *datadir; /* CUPS_DATADIR env var */
+ char line[1024], /* Line/filename */
+ message[2048]; /* status-message */
+#ifdef __APPLE__
+ const char *printerDriver, /* Pointer to .printerDriver extension */
+ *slash; /* Pointer to next slash */
+#endif /* __APPLE__ */
+
+
+ if (name[0] == '/' || strstr(name, "../") || strstr(name, "/.."))
+ {
+ /*
+ * Bad name...
+ */
+
+ fprintf(stderr, "ERROR: [cups-driverd] Bad PPD name \"%s\"!\n", name);
+
+ if (request_id)
+ {
+ snprintf(message, sizeof(message), "Bad PPD name \"%s\"!", name);
+
+ cupsdSendIPPHeader(IPP_NOT_FOUND, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+ "en-US");
+ cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message);
+ cupsdSendIPPTrailer();
+ }
+
+ return (1);
+ }
+
+ /*
+ * Try opening the file...
+ */
+
+#ifdef __APPLE__
+ if (!strncmp(name, "System/Library/Printers/PPDs/Contents/Resources/", 48) ||
+ !strncmp(name, "Library/Printers/PPDs/Contents/Resources/", 41) ||
+ (!strncmp(name, "System/Library/Printers/", 24) &&
+ (printerDriver =
+ strstr(name + 24,
+ ".printerDriver/Contents/Resources/PPDs")) != NULL &&
+ (slash = strchr(name + 24, '/')) != NULL &&
+ slash > printerDriver) ||
+ (!strncmp(name, "Library/Printers/", 17) &&
+ (printerDriver =
+ strstr(name + 17,
+ ".printerDriver/Contents/Resources/PPDs")) != NULL &&
+ (slash = strchr(name + 17, '/')) != NULL &&
+ slash > printerDriver))
+ {
+ /*
+ * Map ppd-name to Mac OS X standard locations...
+ */
+
+ snprintf(line, sizeof(line), "/%s", name);
+ }
+ else
+
+#elif defined(__linux)
+ if (!strncmp(name, "lsb/usr/", 8))
+ {
+ /*
+ * Map ppd-name to LSB standard /usr/share/ppd location...
+ */
+
+ snprintf(line, sizeof(line), "/usr/share/ppd/%s", name + 8);
+ }
+ else if (!strncmp(name, "lsb/opt/", 8))
+ {
+ /*
+ * Map ppd-name to LSB standard /opt/share/ppd location...
+ */
+
+ snprintf(line, sizeof(line), "/opt/share/ppd/%s", name + 8);
+ }
+ else if (!strncmp(name, "lsb/local/", 10))
+ {
+ /*
+ * Map ppd-name to LSB standard /usr/local/share/ppd location...
+ */
+
+ snprintf(line, sizeof(line), "/usr/local/share/ppd/%s", name + 10);
+ }
+ else
+
+#endif /* __APPLE__ */
+ {
+ if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+
+ snprintf(line, sizeof(line), "%s/model/%s", datadir, name);
+ }
+
+ if ((fp = cupsFileOpen(line, "r")) == NULL)
+ {
+ fprintf(stderr, "ERROR: [cups-driverd] Unable to open \"%s\" - %s\n",
+ line, strerror(errno));
+
+ if (request_id)
+ {
+ snprintf(message, sizeof(message), "Unable to open \"%s\" - %s",
+ line, strerror(errno));
+
+ cupsdSendIPPHeader(IPP_NOT_FOUND, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+ "en-US");
+ cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message);
+ cupsdSendIPPTrailer();
+ }
+
+ return (1);
+ }
+
+ if (request_id)
+ {
+ cupsdSendIPPHeader(IPP_OK, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+ "en-US");
+ cupsdSendIPPTrailer();
+ }
+
+ /*
+ * Now copy the file to stdout...
+ */
+
+ while (cupsFileGets(fp, line, sizeof(line)))
+ puts(line);
+
+ cupsFileClose(fp);
+
+ return (0);
+}
+
+
+/*
+ * 'compare_inodes()' - Compare two inodes.
+ */
+
+static int /* O - Result of comparison */
+compare_inodes(struct stat *a, /* I - First inode */
+ struct stat *b) /* I - Second inode */
+{
+ if (a->st_dev != b->st_dev)
+ return (a->st_dev - b->st_dev);
+ else
+ return (a->st_ino - b->st_ino);
+}
+
+
+/*
+ * 'compare_matches()' - Compare PPD match scores for sorting.
+ */
+
+static int
+compare_matches(const ppd_info_t *p0, /* I - First PPD */
+ const ppd_info_t *p1) /* I - Second PPD */
+{
+ if (p1->matches != p0->matches)
+ return (p1->matches - p0->matches);
+ else
+ return (cupsdCompareNames(p0->record.make_and_model,
+ p1->record.make_and_model));
+}
+
+
+/*
+ * 'compare_names()' - Compare PPD filenames for sorting.
+ */
+
+static int /* O - Result of comparison */
+compare_names(const ppd_info_t *p0, /* I - First PPD file */
+ const ppd_info_t *p1) /* I - Second PPD file */
+{
+ int diff; /* Difference between strings */
+
+
+ if ((diff = strcmp(p0->record.filename, p1->record.filename)) != 0)
+ return (diff);
+ else
+ return (strcmp(p0->record.name, p1->record.name));
+}
+
+
+/*
+ * 'compare_ppds()' - Compare PPD file make and model names for sorting.
+ */
+
+static int /* O - Result of comparison */
+compare_ppds(const ppd_info_t *p0, /* I - First PPD file */
+ const ppd_info_t *p1) /* I - Second PPD file */
+{
+ int diff; /* Difference between strings */
+
+
+ /*
+ * First compare manufacturers...
+ */
+
+ if ((diff = _cups_strcasecmp(p0->record.make, p1->record.make)) != 0)
+ return (diff);
+ else if ((diff = cupsdCompareNames(p0->record.make_and_model,
+ p1->record.make_and_model)) != 0)
+ return (diff);
+ else
+ return (strcmp(p0->record.languages[0], p1->record.languages[0]));
+}
+
+
+/*
+ * 'dump_ppds_dat()' - Dump the contents of the ppds.dat file.
+ */
+
+static int /* O - Exit status */
+dump_ppds_dat(void)
+{
+ char filename[1024]; /* ppds.dat filename */
+ ppd_info_t *ppd; /* Current PPD */
+
+
+ /*
+ * See if we a PPD database file...
+ */
+
+ load_ppds_dat(filename, sizeof(filename), 0);
+
+ puts("mtime,size,model_number,type,filename,name,languages0,products0,"
+ "psversions0,make,make_and_model,device_id,scheme");
+ for (ppd = (ppd_info_t *)cupsArrayFirst(PPDsByName);
+ ppd;
+ ppd = (ppd_info_t *)cupsArrayNext(PPDsByName))
+ printf("%d,%ld,%d,%d,\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\","
+ "\"%s\",\"%s\"\n",
+ (int)ppd->record.mtime, (long)ppd->record.size,
+ ppd->record.model_number, ppd->record.type, ppd->record.filename,
+ ppd->record.name, ppd->record.languages[0], ppd->record.products[0],
+ ppd->record.psversions[0], ppd->record.make,
+ ppd->record.make_and_model, ppd->record.device_id,
+ ppd->record.scheme);
+
+ return (0);
+}
+
+
+/*
+ * 'free_array()' - Free an array of strings.
+ */
+
+static void
+free_array(cups_array_t *a) /* I - Array to free */
+{
+ char *ptr; /* Pointer to string */
+
+
+ for (ptr = (char *)cupsArrayFirst(a);
+ ptr;
+ ptr = (char *)cupsArrayNext(a))
+ free(ptr);
+
+ cupsArrayDelete(a);
+}
+
+
+/*
+ * 'list_ppds()' - List PPD files.
+ */
+
+static int /* O - Exit code */
+list_ppds(int request_id, /* I - Request ID */
+ int limit, /* I - Limit */
+ const char *opt) /* I - Option argument */
+{
+ int i; /* Looping vars */
+ int count; /* Number of PPDs to send */
+ ppd_info_t *ppd; /* Current PPD file */
+ cups_file_t *fp; /* ppds.dat file */
+ char filename[1024], /* ppds.dat filename */
+ model[1024]; /* Model directory */
+ const char *cups_datadir; /* CUPS_DATADIR environment variable */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ cups_array_t *requested, /* requested-attributes values */
+ *include, /* PPD schemes to include */
+ *exclude; /* PPD schemes to exclude */
+ const char *device_id, /* ppd-device-id option */
+ *language, /* ppd-natural-language option */
+ *make, /* ppd-make option */
+ *make_and_model, /* ppd-make-and-model option */
+ *model_number_str, /* ppd-model-number option */
+ *product, /* ppd-product option */
+ *psversion, /* ppd-psversion option */
+ *type_str; /* ppd-type option */
+ int model_number, /* ppd-model-number value */
+ type, /* ppd-type value */
+ make_and_model_len, /* Length of ppd-make-and-model */
+ product_len, /* Length of ppd-product */
+ send_device_id, /* Send ppd-device-id? */
+ send_make, /* Send ppd-make? */
+ send_make_and_model, /* Send ppd-make-and-model? */
+ send_model_number, /* Send ppd-model-number? */
+ send_name, /* Send ppd-name? */
+ send_natural_language, /* Send ppd-natural-language? */
+ send_product, /* Send ppd-product? */
+ send_psversion, /* Send ppd-psversion? */
+ send_type, /* Send ppd-type? */
+ sent_header; /* Sent the IPP header? */
+ regex_t *device_id_re, /* Regular expression for matching device ID */
+ *make_and_model_re; /* Regular expression for matching make and model */
+ regmatch_t re_matches[6]; /* Regular expression matches */
+ cups_array_t *matches; /* Matching PPDs */
+
+
+ fprintf(stderr,
+ "DEBUG2: [cups-driverd] list_ppds(request_id=%d, limit=%d, "
+ "opt=\"%s\"\n", request_id, limit, opt);
+
+ /*
+ * See if we a PPD database file...
+ */
+
+ load_ppds_dat(filename, sizeof(filename), 1);
+
+ /*
+ * Load all PPDs in the specified directory and below...
+ */
+
+ if ((cups_datadir = getenv("CUPS_DATADIR")) == NULL)
+ cups_datadir = CUPS_DATADIR;
+
+ Inodes = cupsArrayNew((cups_array_func_t)compare_inodes, NULL);
+
+ snprintf(model, sizeof(model), "%s/model", cups_datadir);
+ load_ppds(model, "", 1);
+
+ snprintf(model, sizeof(model), "%s/drv", cups_datadir);
+ load_ppds(model, "", 1);
+
+#ifdef __APPLE__
+ /*
+ * Load PPDs from standard Mac OS X locations...
+ */
+
+ load_ppds("/Library/Printers",
+ "Library/Printers", 0);
+ load_ppds("/Library/Printers/PPDs/Contents/Resources",
+ "Library/Printers/PPDs/Contents/Resources", 0);
+ load_ppds("/Library/Printers/PPDs/Contents/Resources/en.lproj",
+ "Library/Printers/PPDs/Contents/Resources/en.lproj", 0);
+ load_ppds("/System/Library/Printers",
+ "System/Library/Printers", 0);
+ load_ppds("/System/Library/Printers/PPDs/Contents/Resources",
+ "System/Library/Printers/PPDs/Contents/Resources", 0);
+ load_ppds("/System/Library/Printers/PPDs/Contents/Resources/en.lproj",
+ "System/Library/Printers/PPDs/Contents/Resources/en.lproj", 0);
+
+#elif defined(__linux)
+ /*
+ * Load PPDs from LSB-defined locations...
+ */
+
+ if (!access("/usr/local/share/ppd", 0))
+ load_ppds("/usr/local/share/ppd", "lsb/local", 1);
+ if (!access("/usr/share/ppd", 0))
+ load_ppds("/usr/share/ppd", "lsb/usr", 1);
+ if (!access("/opt/share/ppd", 0))
+ load_ppds("/opt/share/ppd", "lsb/opt", 1);
+#endif /* __APPLE__ */
+
+ /*
+ * Cull PPD files that are no longer present...
+ */
+
+ for (ppd = (ppd_info_t *)cupsArrayFirst(PPDsByName);
+ ppd;
+ ppd = (ppd_info_t *)cupsArrayNext(PPDsByName))
+ if (!ppd->found)
+ {
+ /*
+ * Remove this PPD file from the list...
+ */
+
+ cupsArrayRemove(PPDsByName, ppd);
+ cupsArrayRemove(PPDsByMakeModel, ppd);
+ free(ppd);
+
+ ChangedPPD = 1;
+ }
+
+ /*
+ * Write the new ppds.dat file...
+ */
+
+ fprintf(stderr, "DEBUG: [cups-driverd] ChangedPPD=%d\n", ChangedPPD);
+
+ if (ChangedPPD)
+ {
+ char newname[1024]; /* New filename */
+
+ snprintf(newname, sizeof(newname), "%s.%d", filename, (int)getpid());
+
+ if ((fp = cupsFileOpen(newname, "w")) != NULL)
+ {
+ unsigned ppdsync = PPD_SYNC; /* Sync word */
+
+ cupsFileWrite(fp, (char *)&ppdsync, sizeof(ppdsync));
+
+ for (ppd = (ppd_info_t *)cupsArrayFirst(PPDsByName);
+ ppd;
+ ppd = (ppd_info_t *)cupsArrayNext(PPDsByName))
+ cupsFileWrite(fp, (char *)&(ppd->record), sizeof(ppd_rec_t));
+
+ cupsFileClose(fp);
+
+ if (rename(newname, filename))
+ fprintf(stderr, "ERROR: [cups-driverd] Unable to rename \"%s\" - %s\n",
+ newname, strerror(errno));
+ else
+ fprintf(stderr, "INFO: [cups-driverd] Wrote \"%s\", %d PPDs...\n",
+ filename, cupsArrayCount(PPDsByName));
+ }
+ else
+ fprintf(stderr, "ERROR: [cups-driverd] Unable to write \"%s\" - %s\n",
+ filename, strerror(errno));
+ }
+ else
+ fputs("INFO: [cups-driverd] No new or changed PPDs...\n", stderr);
+
+ /*
+ * Scan for dynamic PPD files...
+ */
+
+ num_options = cupsParseOptions(opt, 0, &options);
+ exclude = cupsdCreateStringsArray(cupsGetOption("exclude-schemes",
+ num_options, options));
+ include = cupsdCreateStringsArray(cupsGetOption("include-schemes",
+ num_options, options));
+
+ load_drivers(include, exclude);
+
+ /*
+ * Add the raw driver...
+ */
+
+ add_ppd("", "raw", "en", "Raw", "Raw Queue", "", "", "", 0, 0, 0,
+ PPD_TYPE_UNKNOWN, "raw");
+
+ /*
+ * Send IPP attributes...
+ */
+
+ requested = cupsdCreateStringsArray(
+ cupsGetOption("requested-attributes", num_options,
+ options));
+ device_id = cupsGetOption("ppd-device-id", num_options, options);
+ language = cupsGetOption("ppd-natural-language", num_options, options);
+ make = cupsGetOption("ppd-make", num_options, options);
+ make_and_model = cupsGetOption("ppd-make-and-model", num_options, options);
+ model_number_str = cupsGetOption("ppd-model-number", num_options, options);
+ product = cupsGetOption("ppd-product", num_options, options);
+ psversion = cupsGetOption("ppd-psversion", num_options, options);
+ type_str = cupsGetOption("ppd-type", num_options, options);
+
+ if (make_and_model)
+ make_and_model_len = strlen(make_and_model);
+ else
+ make_and_model_len = 0;
+
+ if (product)
+ product_len = strlen(product);
+ else
+ product_len = 0;
+
+ if (model_number_str)
+ model_number = atoi(model_number_str);
+ else
+ model_number = 0;
+
+ if (type_str)
+ {
+ for (type = 0;
+ type < (int)(sizeof(ppd_types) / sizeof(ppd_types[0]));
+ type ++)
+ if (!strcmp(type_str, ppd_types[type]))
+ break;
+
+ if (type >= (int)(sizeof(ppd_types) / sizeof(ppd_types[0])))
+ {
+ fprintf(stderr, "ERROR: [cups-driverd] Bad ppd-type=\"%s\" ignored!\n",
+ type_str);
+ type_str = NULL;
+ }
+ }
+ else
+ type = 0;
+
+ for (i = 0; i < num_options; i ++)
+ fprintf(stderr, "DEBUG2: [cups-driverd] %s=\"%s\"\n", options[i].name,
+ options[i].value);
+
+ if (!requested || cupsArrayFind(requested, (void *)"all") != NULL)
+ {
+ send_name = 1;
+ send_make = 1;
+ send_make_and_model = 1;
+ send_model_number = 1;
+ send_natural_language = 1;
+ send_device_id = 1;
+ send_product = 1;
+ send_psversion = 1;
+ send_type = 1;
+ }
+ else
+ {
+ send_name = cupsArrayFind(requested,
+ (void *)"ppd-name") != NULL;
+ send_make = cupsArrayFind(requested,
+ (void *)"ppd-make") != NULL;
+ send_make_and_model = cupsArrayFind(requested,
+ (void *)"ppd-make-and-model") != NULL;
+ send_model_number = cupsArrayFind(requested,
+ (void *)"ppd-model-number") != NULL;
+ send_natural_language = cupsArrayFind(requested,
+ (void *)"ppd-natural-language") != NULL;
+ send_device_id = cupsArrayFind(requested,
+ (void *)"ppd-device-id") != NULL;
+ send_product = cupsArrayFind(requested,
+ (void *)"ppd-product") != NULL;
+ send_psversion = cupsArrayFind(requested,
+ (void *)"ppd-psversion") != NULL;
+ send_type = cupsArrayFind(requested,
+ (void *)"ppd-type") != NULL;
+ }
+
+ /*
+ * Send the content type header to the scheduler; request_id can only be
+ * 0 when run manually since the scheduler enforces the IPP requirement for
+ * a request ID from 1 to 2^31-1...
+ */
+
+ if (request_id > 0)
+ puts("Content-Type: application/ipp\n");
+
+ sent_header = 0;
+
+ if (limit <= 0 || limit > cupsArrayCount(PPDsByMakeModel))
+ count = cupsArrayCount(PPDsByMakeModel);
+ else
+ count = limit;
+
+ if (device_id || language || make || make_and_model || model_number_str ||
+ product)
+ {
+ matches = cupsArrayNew((cups_array_func_t)compare_matches, NULL);
+
+ if (device_id)
+ device_id_re = regex_device_id(device_id);
+ else
+ device_id_re = NULL;
+
+ if (make_and_model)
+ make_and_model_re = regex_string(make_and_model);
+ else
+ make_and_model_re = NULL;
+
+ for (ppd = (ppd_info_t *)cupsArrayFirst(PPDsByMakeModel);
+ ppd;
+ ppd = (ppd_info_t *)cupsArrayNext(PPDsByMakeModel))
+ {
+ /*
+ * Filter PPDs based on make, model, product, language, model number,
+ * and/or device ID using the "matches" score value. An exact match
+ * for product, make-and-model, or device-id adds 3 to the score.
+ * Partial matches for make-and-model yield 1 or 2 points, and matches
+ * for the make and language add a single point. Results are then sorted
+ * by score, highest score first.
+ */
+
+ if (ppd->record.type < PPD_TYPE_POSTSCRIPT ||
+ ppd->record.type >= PPD_TYPE_DRV)
+ continue;
+
+ if (cupsArrayFind(exclude, ppd->record.scheme) ||
+ (include && !cupsArrayFind(include, ppd->record.scheme)))
+ continue;
+
+ ppd->matches = 0;
+
+ if (device_id_re &&
+ !regexec(device_id_re, ppd->record.device_id,
+ (int)(sizeof(re_matches) / sizeof(re_matches[0])),
+ re_matches, 0))
+ {
+ /*
+ * Add the number of matching values from the device ID - it will be
+ * at least 2 (manufacturer and model), and as much as 3 (command set).
+ */
+
+ for (i = 1; i < (int)(sizeof(re_matches) / sizeof(re_matches[0])); i ++)
+ if (re_matches[i].rm_so >= 0)
+ ppd->matches ++;
+ }
+
+ if (language)
+ {
+ for (i = 0; i < PPD_MAX_LANG; i ++)
+ if (!ppd->record.languages[i][0])
+ break;
+ else if (!strcmp(ppd->record.languages[i], language))
+ {
+ ppd->matches ++;
+ break;
+ }
+ }
+
+ if (make && !_cups_strcasecmp(ppd->record.make, make))
+ ppd->matches ++;
+
+ if (make_and_model_re &&
+ !regexec(make_and_model_re, ppd->record.make_and_model,
+ (int)(sizeof(re_matches) / sizeof(re_matches[0])),
+ re_matches, 0))
+ {
+ // See how much of the make-and-model string we matched...
+ if (re_matches[0].rm_so == 0)
+ {
+ if (re_matches[0].rm_eo == make_and_model_len)
+ ppd->matches += 3; // Exact match
+ else
+ ppd->matches += 2; // Prefix match
+ }
+ else
+ ppd->matches ++; // Infix match
+ }
+
+ if (model_number_str && ppd->record.model_number == model_number)
+ ppd->matches ++;
+
+ if (product)
+ {
+ for (i = 0; i < PPD_MAX_PROD; i ++)
+ if (!ppd->record.products[i][0])
+ break;
+ else if (!_cups_strcasecmp(ppd->record.products[i], product))
+ {
+ ppd->matches += 3;
+ break;
+ }
+ }
+
+ if (psversion)
+ {
+ for (i = 0; i < PPD_MAX_VERS; i ++)
+ if (!ppd->record.psversions[i][0])
+ break;
+ else if (!_cups_strcasecmp(ppd->record.psversions[i], psversion))
+ {
+ ppd->matches ++;
+ break;
+ }
+ }
+
+ if (type_str && ppd->record.type == type)
+ ppd->matches ++;
+
+ if (ppd->matches)
+ {
+ fprintf(stderr, "DEBUG2: [cups-driverd] %s matches with score %d!\n",
+ ppd->record.name, ppd->matches);
+ cupsArrayAdd(matches, ppd);
+ }
+ }
+ }
+ else if (include || exclude)
+ {
+ matches = cupsArrayNew((cups_array_func_t)compare_ppds, NULL);
+
+ for (ppd = (ppd_info_t *)cupsArrayFirst(PPDsByMakeModel);
+ ppd;
+ ppd = (ppd_info_t *)cupsArrayNext(PPDsByMakeModel))
+ {
+ /*
+ * Filter PPDs based on the include/exclude lists.
+ */
+
+ if (ppd->record.type < PPD_TYPE_POSTSCRIPT ||
+ ppd->record.type >= PPD_TYPE_DRV)
+ continue;
+
+ if (cupsArrayFind(exclude, ppd->record.scheme) ||
+ (include && !cupsArrayFind(include, ppd->record.scheme)))
+ continue;
+
+ cupsArrayAdd(matches, ppd);
+ }
+ }
+ else
+ matches = PPDsByMakeModel;
+
+ for (ppd = (ppd_info_t *)cupsArrayFirst(matches);
+ count > 0 && ppd;
+ ppd = (ppd_info_t *)cupsArrayNext(matches))
+ {
+ /*
+ * Skip invalid PPDs...
+ */
+
+ if (ppd->record.type < PPD_TYPE_POSTSCRIPT ||
+ ppd->record.type >= PPD_TYPE_DRV)
+ continue;
+
+ /*
+ * Send this PPD...
+ */
+
+ if (!sent_header)
+ {
+ sent_header = 1;
+
+ cupsdSendIPPHeader(IPP_OK, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+ "en-US");
+ }
+
+ fprintf(stderr, "DEBUG2: [cups-driverd] Sending %s (%s)...\n",
+ ppd->record.name, ppd->record.make_and_model);
+
+ count --;
+
+ cupsdSendIPPGroup(IPP_TAG_PRINTER);
+
+ if (send_name)
+ cupsdSendIPPString(IPP_TAG_NAME, "ppd-name", ppd->record.name);
+
+ if (send_natural_language)
+ {
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "ppd-natural-language",
+ ppd->record.languages[0]);
+
+ for (i = 1; i < PPD_MAX_LANG && ppd->record.languages[i][0]; i ++)
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "", ppd->record.languages[i]);
+ }
+
+ if (send_make)
+ cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make", ppd->record.make);
+
+ if (send_make_and_model)
+ cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make-and-model",
+ ppd->record.make_and_model);
+
+ if (send_device_id)
+ cupsdSendIPPString(IPP_TAG_TEXT, "ppd-device-id",
+ ppd->record.device_id);
+
+ if (send_product)
+ {
+ cupsdSendIPPString(IPP_TAG_TEXT, "ppd-product",
+ ppd->record.products[0]);
+
+ for (i = 1; i < PPD_MAX_PROD && ppd->record.products[i][0]; i ++)
+ cupsdSendIPPString(IPP_TAG_TEXT, "", ppd->record.products[i]);
+ }
+
+ if (send_psversion)
+ {
+ cupsdSendIPPString(IPP_TAG_TEXT, "ppd-psversion",
+ ppd->record.psversions[0]);
+
+ for (i = 1; i < PPD_MAX_VERS && ppd->record.psversions[i][0]; i ++)
+ cupsdSendIPPString(IPP_TAG_TEXT, "", ppd->record.psversions[i]);
+ }
+
+ if (send_type)
+ cupsdSendIPPString(IPP_TAG_KEYWORD, "ppd-type",
+ ppd_types[ppd->record.type]);
+
+ if (send_model_number)
+ cupsdSendIPPInteger(IPP_TAG_INTEGER, "ppd-model-number",
+ ppd->record.model_number);
+
+ /*
+ * If we have only requested the ppd-make attribute, then skip
+ * the remaining PPDs with this make...
+ */
+
+ if (cupsArrayFind(requested, (void *)"ppd-make") &&
+ cupsArrayCount(requested) == 1)
+ {
+ const char *this_make; /* This ppd-make */
+
+
+ for (this_make = ppd->record.make,
+ ppd = (ppd_info_t *)cupsArrayNext(matches);
+ ppd;
+ ppd = (ppd_info_t *)cupsArrayNext(matches))
+ if (_cups_strcasecmp(this_make, ppd->record.make))
+ break;
+
+ cupsArrayPrev(matches);
+ }
+ }
+
+ if (!sent_header)
+ {
+ cupsdSendIPPHeader(IPP_NOT_FOUND, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US");
+ }
+
+ cupsdSendIPPTrailer();
+
+ return (0);
+}
+
+
+/*
+ * 'load_drv()' - Load the PPDs from a driver information file.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+load_drv(const char *filename, /* I - Actual filename */
+ const char *name, /* I - Name to the rest of the world */
+ cups_file_t *fp, /* I - File to read from */
+ time_t mtime, /* I - Mod time of driver info file */
+ off_t size) /* I - Size of driver info file */
+{
+ ppdcSource *src; // Driver information file
+ ppdcDriver *d; // Current driver
+ ppdcAttr *device_id, // 1284DeviceID attribute
+ *product, // Current product value
+ *ps_version, // PSVersion attribute
+ *cups_fax, // cupsFax attribute
+ *nick_name; // NickName attribute
+ ppdcFilter *filter; // Current filter
+ ppd_info_t *ppd; // Current PPD
+ int products_found; // Number of products found
+ char uri[1024], // Driver URI
+ make_model[1024]; // Make and model
+ int type; // Driver type
+
+
+ /*
+ * Load the driver info file...
+ */
+
+ src = new ppdcSource(filename, fp);
+
+ if (src->drivers->count == 0)
+ {
+ fprintf(stderr,
+ "ERROR: [cups-driverd] Bad driver information file \"%s\"!\n",
+ filename);
+ src->release();
+ return (0);
+ }
+
+ /*
+ * Add a dummy entry for the file...
+ */
+
+ add_ppd(name, name, "", "", "", "", "", "", mtime, size, 0,
+ PPD_TYPE_DRV, "drv");
+ ChangedPPD = 1;
+
+ /*
+ * Then the drivers in the file...
+ */
+
+ for (d = (ppdcDriver *)src->drivers->first();
+ d;
+ d = (ppdcDriver *)src->drivers->next())
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "drv", "", "", 0,
+ "/%s/%s", name,
+ d->file_name ? d->file_name->value :
+ d->pc_file_name->value);
+
+ device_id = d->find_attr("1284DeviceID", NULL);
+ ps_version = d->find_attr("PSVersion", NULL);
+ nick_name = d->find_attr("NickName", NULL);
+
+ if (nick_name)
+ strlcpy(make_model, nick_name->value->value, sizeof(make_model));
+ else if (_cups_strncasecmp(d->model_name->value, d->manufacturer->value,
+ strlen(d->manufacturer->value)))
+ snprintf(make_model, sizeof(make_model), "%s %s, %s",
+ d->manufacturer->value, d->model_name->value,
+ d->version->value);
+ else
+ snprintf(make_model, sizeof(make_model), "%s, %s", d->model_name->value,
+ d->version->value);
+
+ if ((cups_fax = d->find_attr("cupsFax", NULL)) != NULL &&
+ !_cups_strcasecmp(cups_fax->value->value, "true"))
+ type = PPD_TYPE_FAX;
+ else if (d->type == PPDC_DRIVER_PS)
+ type = PPD_TYPE_POSTSCRIPT;
+ else if (d->type != PPDC_DRIVER_CUSTOM)
+ type = PPD_TYPE_RASTER;
+ else
+ {
+ for (filter = (ppdcFilter *)d->filters->first(),
+ type = PPD_TYPE_POSTSCRIPT;
+ filter;
+ filter = (ppdcFilter *)d->filters->next())
+ if (_cups_strcasecmp(filter->mime_type->value, "application/vnd.cups-raster"))
+ type = PPD_TYPE_RASTER;
+ else if (_cups_strcasecmp(filter->mime_type->value,
+ "application/vnd.cups-pdf"))
+ type = PPD_TYPE_PDF;
+ }
+
+ for (product = (ppdcAttr *)d->attrs->first(), products_found = 0,
+ ppd = NULL;
+ product;
+ product = (ppdcAttr *)d->attrs->next())
+ if (!strcmp(product->name->value, "Product"))
+ {
+ if (!products_found)
+ ppd = add_ppd(name, uri, "en", d->manufacturer->value, make_model,
+ device_id ? device_id->value->value : "",
+ product->value->value,
+ ps_version ? ps_version->value->value : "(3010) 0",
+ mtime, size, d->model_number, type, "drv");
+ else if (products_found < PPD_MAX_PROD)
+ strlcpy(ppd->record.products[products_found], product->value->value,
+ sizeof(ppd->record.products[0]));
+ else
+ break;
+
+ products_found ++;
+ }
+
+ if (!products_found)
+ add_ppd(name, uri, "en", d->manufacturer->value, make_model,
+ device_id ? device_id->value->value : "",
+ d->model_name->value,
+ ps_version ? ps_version->value->value : "(3010) 0",
+ mtime, size, d->model_number, type, "drv");
+ }
+
+ src->release();
+
+ return (1);
+}
+
+
+/*
+ * 'load_drivers()' - Load driver-generated PPD files.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+load_drivers(cups_array_t *include, /* I - Drivers to include */
+ cups_array_t *exclude) /* I - Drivers to exclude */
+{
+ int i; /* Looping var */
+ char *start, /* Start of value */
+ *ptr; /* Pointer into string */
+ const char *server_bin, /* CUPS_SERVERBIN env variable */
+ *scheme, /* Scheme for this driver */
+ *scheme_end; /* Pointer to end of scheme */
+ char drivers[1024]; /* Location of driver programs */
+ int pid; /* Process ID for driver program */
+ cups_file_t *fp; /* Pipe to driver program */
+ cups_dir_t *dir; /* Directory pointer */
+ cups_dentry_t *dent; /* Directory entry */
+ char *argv[3], /* Arguments for command */
+ filename[1024], /* Name of driver */
+ line[2048], /* Line from driver */
+ name[512], /* ppd-name */
+ make[128], /* ppd-make */
+ make_and_model[128], /* ppd-make-and-model */
+ device_id[128], /* ppd-device-id */
+ languages[128], /* ppd-natural-language */
+ product[128], /* ppd-product */
+ psversion[128], /* ppd-psversion */
+ type_str[128]; /* ppd-type */
+ int type; /* PPD type */
+ ppd_info_t *ppd; /* Newly added PPD */
+
+
+ /*
+ * Try opening the driver directory...
+ */
+
+ if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL)
+ server_bin = CUPS_SERVERBIN;
+
+ snprintf(drivers, sizeof(drivers), "%s/driver", server_bin);
+
+ if ((dir = cupsDirOpen(drivers)) == NULL)
+ {
+ fprintf(stderr, "ERROR: [cups-driverd] Unable to open driver directory "
+ "\"%s\": %s\n",
+ drivers, strerror(errno));
+ return (0);
+ }
+
+ /*
+ * Loop through all of the device drivers...
+ */
+
+ argv[1] = (char *)"list";
+ argv[2] = NULL;
+
+ while ((dent = cupsDirRead(dir)) != NULL)
+ {
+ /*
+ * Only look at executable files...
+ */
+
+ if (!(dent->fileinfo.st_mode & 0111) || !S_ISREG(dent->fileinfo.st_mode))
+ continue;
+
+ /*
+ * Include/exclude specific drivers...
+ */
+
+ if (exclude)
+ {
+ /*
+ * Look for "scheme" or "scheme*" (prefix match), and skip any matches.
+ */
+
+ for (scheme = (char *)cupsArrayFirst(exclude);
+ scheme;
+ scheme = (char *)cupsArrayNext(exclude))
+ {
+ fprintf(stderr, "DEBUG: [cups-driverd] Exclude \"%s\" with \"%s\"?\n",
+ dent->filename, scheme);
+ scheme_end = scheme + strlen(scheme) - 1;
+
+ if ((scheme_end > scheme && *scheme_end == '*' &&
+ !strncmp(scheme, dent->filename, scheme_end - scheme)) ||
+ !strcmp(scheme, dent->filename))
+ {
+ fputs("DEBUG: [cups-driverd] Yes, exclude!\n", stderr);
+ break;
+ }
+ }
+
+ if (scheme)
+ continue;
+ }
+
+ if (include)
+ {
+ /*
+ * Look for "scheme" or "scheme*" (prefix match), and skip any non-matches.
+ */
+
+ for (scheme = (char *)cupsArrayFirst(include);
+ scheme;
+ scheme = (char *)cupsArrayNext(include))
+ {
+ fprintf(stderr, "DEBUG: [cups-driverd] Include \"%s\" with \"%s\"?\n",
+ dent->filename, scheme);
+ scheme_end = scheme + strlen(scheme) - 1;
+
+ if ((scheme_end > scheme && *scheme_end == '*' &&
+ !strncmp(scheme, dent->filename, scheme_end - scheme)) ||
+ !strcmp(scheme, dent->filename))
+ {
+ fputs("DEBUG: [cups-driverd] Yes, include!\n", stderr);
+ break;
+ }
+ }
+
+ if (!scheme)
+ continue;
+ }
+ else
+ scheme = dent->filename;
+
+ /*
+ * Run the driver with no arguments and collect the output...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/%s", drivers, dent->filename);
+
+ if (_cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !geteuid(),
+ _cupsFileCheckFilter, NULL))
+ continue;
+
+ argv[0] = dent->filename;
+
+ if ((fp = cupsdPipeCommand(&pid, filename, argv, 0)) != NULL)
+ {
+ while (cupsFileGets(fp, line, sizeof(line)))
+ {
+ /*
+ * Each line is of the form:
+ *
+ * "ppd-name" ppd-natural-language "ppd-make" "ppd-make-and-model" \
+ * "ppd-device-id" "ppd-product" "ppd-psversion"
+ */
+
+ device_id[0] = '\0';
+ product[0] = '\0';
+ psversion[0] = '\0';
+ strcpy(type_str, "postscript");
+
+ if (sscanf(line, "\"%511[^\"]\"%127s%*[ \t]\"%127[^\"]\""
+ "%*[ \t]\"%127[^\"]\"%*[ \t]\"%127[^\"]\""
+ "%*[ \t]\"%127[^\"]\"%*[ \t]\"%127[^\"]\""
+ "%*[ \t]\"%127[^\"]\"",
+ name, languages, make, make_and_model,
+ device_id, product, psversion, type_str) < 4)
+ {
+ /*
+ * Bad format; strip trailing newline and write an error message.
+ */
+
+ if (line[strlen(line) - 1] == '\n')
+ line[strlen(line) - 1] = '\0';
+
+ fprintf(stderr, "ERROR: [cups-driverd] Bad line from \"%s\": %s\n",
+ dent->filename, line);
+ break;
+ }
+ else
+ {
+ /*
+ * Add the device to the array of available devices...
+ */
+
+ if ((start = strchr(languages, ',')) != NULL)
+ *start++ = '\0';
+
+ for (type = 0;
+ type < (int)(sizeof(ppd_types) / sizeof(ppd_types[0]));
+ type ++)
+ if (!strcmp(type_str, ppd_types[type]))
+ break;
+
+ if (type >= (int)(sizeof(ppd_types) / sizeof(ppd_types[0])))
+ {
+ fprintf(stderr,
+ "ERROR: [cups-driverd] Bad ppd-type \"%s\" ignored!\n",
+ type_str);
+ type = PPD_TYPE_UNKNOWN;
+ }
+
+ ppd = add_ppd(filename, name, languages, make, make_and_model,
+ device_id, product, psversion, 0, 0, 0, type, scheme);
+
+ if (!ppd)
+ {
+ cupsDirClose(dir);
+ cupsFileClose(fp);
+ return (0);
+ }
+
+ if (start && *start)
+ {
+ for (i = 1; i < PPD_MAX_LANG && *start; i ++)
+ {
+ if ((ptr = strchr(start, ',')) != NULL)
+ *ptr++ = '\0';
+ else
+ ptr = start + strlen(start);
+
+ strlcpy(ppd->record.languages[i], start,
+ sizeof(ppd->record.languages[0]));
+
+ start = ptr;
+ }
+ }
+
+ fprintf(stderr, "DEBUG2: [cups-driverd] Added dynamic PPD \"%s\"...\n",
+ name);
+ }
+ }
+
+ cupsFileClose(fp);
+ }
+ else
+ fprintf(stderr, "WARNING: [cups-driverd] Unable to execute \"%s\": %s\n",
+ filename, strerror(errno));
+ }
+
+ cupsDirClose(dir);
+
+ return (1);
+}
+
+
+/*
+ * 'load_ppds()' - Load PPD files recursively.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+load_ppds(const char *d, /* I - Actual directory */
+ const char *p, /* I - Virtual path in name */
+ int descend) /* I - Descend into directories? */
+{
+ struct stat dinfo, /* Directory information */
+ *dinfoptr; /* Pointer to match */
+ int i; /* Looping var */
+ cups_file_t *fp; /* Pointer to file */
+ cups_dir_t *dir; /* Directory pointer */
+ cups_dentry_t *dent; /* Directory entry */
+ char filename[1024], /* Name of PPD or directory */
+ line[256], /* Line from backend */
+ *ptr, /* Pointer into name */
+ name[128], /* Name of PPD file */
+ lang_version[64], /* PPD LanguageVersion */
+ lang_encoding[64], /* PPD LanguageEncoding */
+ country[64], /* Country code */
+ manufacturer[256], /* Manufacturer */
+ make_model[256], /* Make and Model */
+ model_name[256], /* ModelName */
+ nick_name[256], /* NickName */
+ device_id[256], /* 1284DeviceID */
+ product[256], /* Product */
+ psversion[256], /* PSVersion */
+ temp[512]; /* Temporary make and model */
+ int model_number, /* cupsModelNumber */
+ type; /* ppd-type */
+ cups_array_t *products, /* Product array */
+ *psversions, /* PSVersion array */
+ *cups_languages; /* cupsLanguages array */
+ ppd_info_t *ppd, /* New PPD file */
+ key; /* Search key */
+ int new_ppd; /* Is this a new PPD? */
+ struct /* LanguageVersion translation table */
+ {
+ const char *version, /* LanguageVersion string */
+ *language; /* Language code */
+ } languages[] =
+ {
+ { "chinese", "zh" },
+ { "czech", "cs" },
+ { "danish", "da" },
+ { "dutch", "nl" },
+ { "english", "en" },
+ { "finnish", "fi" },
+ { "french", "fr" },
+ { "german", "de" },
+ { "greek", "el" },
+ { "hungarian", "hu" },
+ { "italian", "it" },
+ { "japanese", "ja" },
+ { "korean", "ko" },
+ { "norwegian", "no" },
+ { "polish", "pl" },
+ { "portuguese", "pt" },
+ { "russian", "ru" },
+ { "simplified chinese", "zh_CN" },
+ { "slovak", "sk" },
+ { "spanish", "es" },
+ { "swedish", "sv" },
+ { "traditional chinese", "zh_TW" },
+ { "turkish", "tr" }
+ };
+
+
+ /*
+ * See if we've loaded this directory before...
+ */
+
+ if (stat(d, &dinfo))
+ {
+ if (errno != ENOENT)
+ fprintf(stderr, "ERROR: [cups-driverd] Unable to stat \"%s\": %s\n", d,
+ strerror(errno));
+
+ return (0);
+ }
+ else if (cupsArrayFind(Inodes, &dinfo))
+ {
+ fprintf(stderr, "ERROR: [cups-driverd] Skipping \"%s\": loop detected!\n",
+ d);
+ return (0);
+ }
+
+ /*
+ * Nope, add it to the Inodes array and continue...
+ */
+
+ dinfoptr = (struct stat *)malloc(sizeof(struct stat));
+ memcpy(dinfoptr, &dinfo, sizeof(struct stat));
+ cupsArrayAdd(Inodes, dinfoptr);
+
+ /*
+ * Check permissions...
+ */
+
+ if (_cupsFileCheck(d, _CUPS_FILE_CHECK_DIRECTORY, !geteuid(),
+ _cupsFileCheckFilter, NULL))
+ return (0);
+
+ if ((dir = cupsDirOpen(d)) == NULL)
+ {
+ if (errno != ENOENT)
+ fprintf(stderr,
+ "ERROR: [cups-driverd] Unable to open PPD directory \"%s\": %s\n",
+ d, strerror(errno));
+
+ return (0);
+ }
+
+ fprintf(stderr, "DEBUG: [cups-driverd] Loading \"%s\"...\n", d);
+
+ while ((dent = cupsDirRead(dir)) != NULL)
+ {
+ /*
+ * Skip files/directories starting with "."...
+ */
+
+ if (dent->filename[0] == '.')
+ continue;
+
+ /*
+ * See if this is a file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/%s", d, dent->filename);
+
+ if (p[0])
+ snprintf(name, sizeof(name), "%s/%s", p, dent->filename);
+ else
+ strlcpy(name, dent->filename, sizeof(name));
+
+ if (S_ISDIR(dent->fileinfo.st_mode))
+ {
+ /*
+ * Do subdirectory...
+ */
+
+ if (descend)
+ {
+ if (!load_ppds(filename, name, 1))
+ {
+ cupsDirClose(dir);
+ return (1);
+ }
+ }
+ else if ((ptr = filename + strlen(filename) - 14) > filename &&
+ !strcmp(ptr, ".printerDriver"))
+ {
+ /*
+ * Load PPDs in a printer driver bundle.
+ */
+
+ if (_cupsFileCheck(filename, _CUPS_FILE_CHECK_DIRECTORY, !geteuid(),
+ _cupsFileCheckFilter, NULL))
+ continue;
+
+ strlcat(filename, "/Contents/Resources/PPDs", sizeof(filename));
+ strlcat(name, "/Contents/Resources/PPDs", sizeof(name));
+
+ load_ppds(filename, name, 0);
+ }
+
+ continue;
+ }
+ else if ((ptr = filename + strlen(filename) - 6) > filename &&
+ !strcmp(ptr, ".plist"))
+ {
+ /*
+ * Skip plist files in the PPDs directory...
+ */
+
+ continue;
+ }
+ else if (_cupsFileCheck(filename, _CUPS_FILE_CHECK_FILE_ONLY, !geteuid(),
+ _cupsFileCheckFilter, NULL))
+ continue;
+
+ /*
+ * See if this file has been scanned before...
+ */
+
+ strcpy(key.record.filename, name);
+ strcpy(key.record.name, name);
+
+ ppd = (ppd_info_t *)cupsArrayFind(PPDsByName, &key);
+
+ if (ppd &&
+ ppd->record.size == dent->fileinfo.st_size &&
+ ppd->record.mtime == dent->fileinfo.st_mtime)
+ {
+ /*
+ * Rewind to the first entry for this file...
+ */
+
+ while ((ppd = (ppd_info_t *)cupsArrayPrev(PPDsByName)) != NULL &&
+ !strcmp(ppd->record.filename, name));
+
+ /*
+ * Then mark all of the matches for this file as found...
+ */
+
+ while ((ppd = (ppd_info_t *)cupsArrayNext(PPDsByName)) != NULL &&
+ !strcmp(ppd->record.filename, name))
+ ppd->found = 1;
+
+ continue;
+ }
+
+ /*
+ * No, file is new/changed, so re-scan it...
+ */
+
+ if ((fp = cupsFileOpen(filename, "r")) == NULL)
+ continue;
+
+ /*
+ * Now see if this is a PPD file...
+ */
+
+ line[0] = '\0';
+ cupsFileGets(fp, line, sizeof(line));
+
+ if (strncmp(line, "*PPD-Adobe:", 11))
+ {
+ /*
+ * Nope, treat it as a driver information file...
+ */
+
+ load_drv(filename, name, fp, dent->fileinfo.st_mtime,
+ dent->fileinfo.st_size);
+ continue;
+ }
+
+ /*
+ * Now read until we get the NickName field...
+ */
+
+ cups_languages = cupsArrayNew(NULL, NULL);
+ products = cupsArrayNew(NULL, NULL);
+ psversions = cupsArrayNew(NULL, NULL);
+
+ model_name[0] = '\0';
+ nick_name[0] = '\0';
+ manufacturer[0] = '\0';
+ device_id[0] = '\0';
+ lang_encoding[0] = '\0';
+ strcpy(lang_version, "en");
+ model_number = 0;
+ type = PPD_TYPE_POSTSCRIPT;
+
+ while (cupsFileGets(fp, line, sizeof(line)) != NULL)
+ {
+ if (!strncmp(line, "*Manufacturer:", 14))
+ sscanf(line, "%*[^\"]\"%255[^\"]", manufacturer);
+ else if (!strncmp(line, "*ModelName:", 11))
+ sscanf(line, "%*[^\"]\"%127[^\"]", model_name);
+ else if (!strncmp(line, "*LanguageEncoding:", 18))
+ sscanf(line, "%*[^:]:%63s", lang_encoding);
+ else if (!strncmp(line, "*LanguageVersion:", 17))
+ sscanf(line, "%*[^:]:%63s", lang_version);
+ else if (!strncmp(line, "*NickName:", 10))
+ sscanf(line, "%*[^\"]\"%255[^\"]", nick_name);
+ else if (!_cups_strncasecmp(line, "*1284DeviceID:", 14))
+ {
+ sscanf(line, "%*[^\"]\"%255[^\"]", device_id);
+
+ // Make sure device ID ends with a semicolon...
+ if (device_id[0] && device_id[strlen(device_id) - 1] != ';')
+ strlcat(device_id, ";", sizeof(device_id));
+ }
+ else if (!strncmp(line, "*Product:", 9))
+ {
+ if (sscanf(line, "%*[^\"]\"(%255[^\"]", product) == 1)
+ {
+ /*
+ * Make sure the value ends with a right parenthesis - can't stop at
+ * the first right paren since the product name may contain escaped
+ * parenthesis...
+ */
+
+ ptr = product + strlen(product) - 1;
+ if (ptr > product && *ptr == ')')
+ {
+ /*
+ * Yes, ends with a parenthesis, so remove it from the end and
+ * add the product to the list...
+ */
+
+ *ptr = '\0';
+ cupsArrayAdd(products, strdup(product));
+ }
+ }
+ }
+ else if (!strncmp(line, "*PSVersion:", 11))
+ {
+ sscanf(line, "%*[^\"]\"%255[^\"]", psversion);
+ cupsArrayAdd(psversions, strdup(psversion));
+ }
+ else if (!strncmp(line, "*cupsLanguages:", 15))
+ {
+ char *start; /* Start of language */
+
+
+ for (start = line + 15; *start && isspace(*start & 255); start ++);
+
+ if (*start++ == '\"')
+ {
+ while (*start)
+ {
+ for (ptr = start + 1;
+ *ptr && *ptr != '\"' && !isspace(*ptr & 255);
+ ptr ++);
+
+ if (*ptr)
+ {
+ *ptr++ = '\0';
+
+ while (isspace(*ptr & 255))
+ *ptr++ = '\0';
+ }
+
+ cupsArrayAdd(cups_languages, strdup(start));
+ start = ptr;
+ }
+ }
+ }
+ else if (!strncmp(line, "*cupsFax:", 9))
+ {
+ for (ptr = line + 9; isspace(*ptr & 255); ptr ++);
+
+ if (!_cups_strncasecmp(ptr, "true", 4))
+ type = PPD_TYPE_FAX;
+ }
+ else if (!strncmp(line, "*cupsFilter:", 12) && type == PPD_TYPE_POSTSCRIPT)
+ {
+ if (strstr(line + 12, "application/vnd.cups-raster"))
+ type = PPD_TYPE_RASTER;
+ else if (strstr(line + 12, "application/vnd.cups-pdf"))
+ type = PPD_TYPE_PDF;
+ }
+ else if (!strncmp(line, "*cupsModelNumber:", 17))
+ sscanf(line, "*cupsModelNumber:%d", &model_number);
+ else if (!strncmp(line, "*OpenUI", 7))
+ {
+ /*
+ * Stop early if we have a NickName or ModelName attributes
+ * before the first OpenUI...
+ */
+
+ if ((model_name[0] || nick_name[0]) && cupsArrayCount(products) > 0 &&
+ cupsArrayCount(psversions) > 0)
+ break;
+ }
+ }
+
+ /*
+ * Close the file...
+ */
+
+ cupsFileClose(fp);
+
+ /*
+ * See if we got all of the required info...
+ */
+
+ if (nick_name[0])
+ cupsCharsetToUTF8((cups_utf8_t *)make_model, nick_name,
+ sizeof(make_model), _ppdGetEncoding(lang_encoding));
+ else
+ strcpy(make_model, model_name);
+
+ while (isspace(make_model[0] & 255))
+ _cups_strcpy(make_model, make_model + 1);
+
+ if (!make_model[0] || cupsArrayCount(products) == 0 ||
+ cupsArrayCount(psversions) == 0)
+ {
+ /*
+ * We don't have all the info needed, so skip this file...
+ */
+
+ if (!make_model[0])
+ fprintf(stderr, "WARNING: Missing NickName and ModelName in %s!\n",
+ filename);
+
+ if (cupsArrayCount(products) == 0)
+ fprintf(stderr, "WARNING: Missing Product in %s!\n", filename);
+
+ if (cupsArrayCount(psversions) == 0)
+ fprintf(stderr, "WARNING: Missing PSVersion in %s!\n", filename);
+
+ free_array(products);
+ free_array(psversions);
+ free_array(cups_languages);
+
+ continue;
+ }
+
+ if (model_name[0])
+ cupsArrayAdd(products, strdup(model_name));
+
+ /*
+ * Normalize the make and model string...
+ */
+
+ while (isspace(manufacturer[0] & 255))
+ _cups_strcpy(manufacturer, manufacturer + 1);
+
+ if (!_cups_strncasecmp(make_model, manufacturer, strlen(manufacturer)))
+ strlcpy(temp, make_model, sizeof(temp));
+ else
+ snprintf(temp, sizeof(temp), "%s %s", manufacturer, make_model);
+
+ _ppdNormalizeMakeAndModel(temp, make_model, sizeof(make_model));
+
+ /*
+ * See if we got a manufacturer...
+ */
+
+ if (!manufacturer[0] || !strcmp(manufacturer, "ESP"))
+ {
+ /*
+ * Nope, copy the first part of the make and model then...
+ */
+
+ strlcpy(manufacturer, make_model, sizeof(manufacturer));
+
+ /*
+ * Truncate at the first space, dash, or slash, or make the
+ * manufacturer "Other"...
+ */
+
+ for (ptr = manufacturer; *ptr; ptr ++)
+ if (*ptr == ' ' || *ptr == '-' || *ptr == '/')
+ break;
+
+ if (*ptr && ptr > manufacturer)
+ *ptr = '\0';
+ else
+ strcpy(manufacturer, "Other");
+ }
+ else if (!_cups_strncasecmp(manufacturer, "LHAG", 4) ||
+ !_cups_strncasecmp(manufacturer, "linotype", 8))
+ strcpy(manufacturer, "LHAG");
+ else if (!_cups_strncasecmp(manufacturer, "Hewlett", 7))
+ strcpy(manufacturer, "HP");
+
+ /*
+ * Fix the lang_version as needed...
+ */
+
+ if ((ptr = strchr(lang_version, '-')) != NULL)
+ *ptr++ = '\0';
+ else if ((ptr = strchr(lang_version, '_')) != NULL)
+ *ptr++ = '\0';
+
+ if (ptr)
+ {
+ /*
+ * Setup the country suffix...
+ */
+
+ country[0] = '_';
+ _cups_strcpy(country + 1, ptr);
+ }
+ else
+ {
+ /*
+ * No country suffix...
+ */
+
+ country[0] = '\0';
+ }
+
+ for (i = 0; i < (int)(sizeof(languages) / sizeof(languages[0])); i ++)
+ if (!_cups_strcasecmp(languages[i].version, lang_version))
+ break;
+
+ if (i < (int)(sizeof(languages) / sizeof(languages[0])))
+ {
+ /*
+ * Found a known language...
+ */
+
+ snprintf(lang_version, sizeof(lang_version), "%s%s",
+ languages[i].language, country);
+ }
+ else
+ {
+ /*
+ * Unknown language; use "xx"...
+ */
+
+ strcpy(lang_version, "xx");
+ }
+
+ /*
+ * Record the PPD file...
+ */
+
+ new_ppd = !ppd;
+
+ if (new_ppd)
+ {
+ /*
+ * Add new PPD file...
+ */
+
+ fprintf(stderr, "DEBUG2: [cups-driverd] Adding ppd \"%s\"...\n", name);
+
+ ppd = add_ppd(name, name, lang_version, manufacturer, make_model,
+ device_id, (char *)cupsArrayFirst(products),
+ (char *)cupsArrayFirst(psversions),
+ dent->fileinfo.st_mtime, dent->fileinfo.st_size,
+ model_number, type, "file");
+
+ if (!ppd)
+ {
+ cupsDirClose(dir);
+ return (0);
+ }
+ }
+ else
+ {
+ /*
+ * Update existing record...
+ */
+
+ fprintf(stderr, "DEBUG2: [cups-driverd] Updating ppd \"%s\"...\n", name);
+
+ memset(ppd, 0, sizeof(ppd_info_t));
+
+ ppd->found = 1;
+ ppd->record.mtime = dent->fileinfo.st_mtime;
+ ppd->record.size = dent->fileinfo.st_size;
+ ppd->record.model_number = model_number;
+ ppd->record.type = type;
+
+ strlcpy(ppd->record.name, name, sizeof(ppd->record.name));
+ strlcpy(ppd->record.make, manufacturer, sizeof(ppd->record.make));
+ strlcpy(ppd->record.make_and_model, make_model,
+ sizeof(ppd->record.make_and_model));
+ strlcpy(ppd->record.languages[0], lang_version,
+ sizeof(ppd->record.languages[0]));
+ strlcpy(ppd->record.products[0], (char *)cupsArrayFirst(products),
+ sizeof(ppd->record.products[0]));
+ strlcpy(ppd->record.psversions[0], (char *)cupsArrayFirst(psversions),
+ sizeof(ppd->record.psversions[0]));
+ strlcpy(ppd->record.device_id, device_id, sizeof(ppd->record.device_id));
+ }
+
+ /*
+ * Add remaining products, versions, and languages...
+ */
+
+ for (i = 1;
+ i < PPD_MAX_PROD && (ptr = (char *)cupsArrayNext(products)) != NULL;
+ i ++)
+ strlcpy(ppd->record.products[i], ptr,
+ sizeof(ppd->record.products[0]));
+
+ for (i = 1;
+ i < PPD_MAX_VERS && (ptr = (char *)cupsArrayNext(psversions)) != NULL;
+ i ++)
+ strlcpy(ppd->record.psversions[i], ptr,
+ sizeof(ppd->record.psversions[0]));
+
+ for (i = 1, ptr = (char *)cupsArrayFirst(cups_languages);
+ i < PPD_MAX_LANG && ptr;
+ i ++, ptr = (char *)cupsArrayNext(cups_languages))
+ strlcpy(ppd->record.languages[i], ptr,
+ sizeof(ppd->record.languages[0]));
+
+ /*
+ * Free products, versions, and languages...
+ */
+
+ free_array(cups_languages);
+ free_array(products);
+ free_array(psversions);
+
+ ChangedPPD = 1;
+ }
+
+ cupsDirClose(dir);
+
+ return (1);
+}
+
+
+/*
+ * 'load_ppds_dat()' - Load the ppds.dat file.
+ */
+
+static void
+load_ppds_dat(char *filename, /* I - Filename buffer */
+ size_t filesize, /* I - Size of filename buffer */
+ int verbose) /* I - Be verbose? */
+{
+ ppd_info_t *ppd; /* Current PPD file */
+ cups_file_t *fp; /* ppds.dat file */
+ struct stat fileinfo; /* ppds.dat information */
+ const char *cups_cachedir; /* CUPS_CACHEDIR environment variable */
+
+
+ PPDsByName = cupsArrayNew((cups_array_func_t)compare_names, NULL);
+ PPDsByMakeModel = cupsArrayNew((cups_array_func_t)compare_ppds, NULL);
+ ChangedPPD = 0;
+
+ if ((cups_cachedir = getenv("CUPS_CACHEDIR")) == NULL)
+ cups_cachedir = CUPS_CACHEDIR;
+
+ snprintf(filename, filesize, "%s/ppds.dat", cups_cachedir);
+ if ((fp = cupsFileOpen(filename, "r")) != NULL)
+ {
+ /*
+ * See if we have the right sync word...
+ */
+
+ unsigned ppdsync; /* Sync word */
+ int num_ppds; /* Number of PPDs */
+
+ if (cupsFileRead(fp, (char *)&ppdsync, sizeof(ppdsync))
+ == sizeof(ppdsync) &&
+ ppdsync == PPD_SYNC &&
+ !stat(filename, &fileinfo) &&
+ ((fileinfo.st_size - sizeof(ppdsync)) % sizeof(ppd_rec_t)) == 0 &&
+ (num_ppds = (fileinfo.st_size - sizeof(ppdsync)) /
+ sizeof(ppd_rec_t)) > 0)
+ {
+ /*
+ * We have a ppds.dat file, so read it!
+ */
+
+ for (; num_ppds > 0; num_ppds --)
+ {
+ if ((ppd = (ppd_info_t *)calloc(1, sizeof(ppd_info_t))) == NULL)
+ {
+ if (verbose)
+ fputs("ERROR: [cups-driverd] Unable to allocate memory for PPD!\n",
+ stderr);
+ exit(1);
+ }
+
+ if (cupsFileRead(fp, (char *)&(ppd->record), sizeof(ppd_rec_t)) > 0)
+ {
+ cupsArrayAdd(PPDsByName, ppd);
+ cupsArrayAdd(PPDsByMakeModel, ppd);
+ }
+ else
+ {
+ free(ppd);
+ break;
+ }
+ }
+
+ if (verbose)
+ fprintf(stderr, "INFO: [cups-driverd] Read \"%s\", %d PPDs...\n",
+ filename, cupsArrayCount(PPDsByName));
+ }
+
+ cupsFileClose(fp);
+ }
+}
+
+
+/*
+ * 'regex_device_id()' - Compile a regular expression based on the 1284 device
+ * ID.
+ */
+
+static regex_t * /* O - Regular expression */
+regex_device_id(const char *device_id) /* I - IEEE-1284 device ID */
+{
+ char res[2048], /* Regular expression string */
+ *ptr; /* Pointer into string */
+ regex_t *re; /* Regular expression */
+ int cmd; /* Command set string? */
+
+
+ fprintf(stderr, "DEBUG: [cups-driverd] regex_device_id(\"%s\")\n", device_id);
+
+ /*
+ * Scan the device ID string and insert class, command set, manufacturer, and
+ * model attributes to match. We assume that the device ID in the PPD and the
+ * device ID reported by the device itself use the same attribute names and
+ * order of attributes.
+ */
+
+ ptr = res;
+
+ while (*device_id && ptr < (res + sizeof(res) - 6))
+ {
+ cmd = !_cups_strncasecmp(device_id, "COMMAND SET:", 12) ||
+ !_cups_strncasecmp(device_id, "CMD:", 4);
+
+ if (cmd || !_cups_strncasecmp(device_id, "MANUFACTURER:", 13) ||
+ !_cups_strncasecmp(device_id, "MFG:", 4) ||
+ !_cups_strncasecmp(device_id, "MFR:", 4) ||
+ !_cups_strncasecmp(device_id, "MODEL:", 6) ||
+ !_cups_strncasecmp(device_id, "MDL:", 4))
+ {
+ if (ptr > res)
+ {
+ *ptr++ = '.';
+ *ptr++ = '*';
+ }
+
+ *ptr++ = '(';
+
+ while (*device_id && *device_id != ';' && ptr < (res + sizeof(res) - 8))
+ {
+ if (strchr("[]{}().*\\|", *device_id))
+ *ptr++ = '\\';
+ if (*device_id == ':')
+ {
+ /*
+ * KEY:.*value
+ */
+
+ *ptr++ = *device_id++;
+ *ptr++ = '.';
+ *ptr++ = '*';
+ }
+ else
+ *ptr++ = *device_id++;
+ }
+
+ if (*device_id == ';' || !*device_id)
+ {
+ /*
+ * KEY:.*value.*;
+ */
+
+ *ptr++ = '.';
+ *ptr++ = '*';
+ *ptr++ = ';';
+ }
+ *ptr++ = ')';
+ if (cmd)
+ *ptr++ = '?';
+ }
+ else if ((device_id = strchr(device_id, ';')) == NULL)
+ break;
+ else
+ device_id ++;
+ }
+
+ *ptr = '\0';
+
+ fprintf(stderr, "DEBUG: [cups-driverd] regex_device_id: \"%s\"\n", res);
+
+ /*
+ * Compile the regular expression and return...
+ */
+
+ if (res[0] && (re = (regex_t *)calloc(1, sizeof(regex_t))) != NULL)
+ {
+ if (!regcomp(re, res, REG_EXTENDED | REG_ICASE))
+ {
+ fputs("DEBUG: [cups-driverd] regex_device_id: OK\n", stderr);
+ return (re);
+ }
+
+ free(re);
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * 'regex_string()' - Construct a regular expression to compare a simple string.
+ */
+
+static regex_t * /* O - Regular expression */
+regex_string(const char *s) /* I - String to compare */
+{
+ char res[2048], /* Regular expression string */
+ *ptr; /* Pointer into string */
+ regex_t *re; /* Regular expression */
+
+
+ fprintf(stderr, "DEBUG: [cups-driverd] regex_string(\"%s\")\n", s);
+
+ /*
+ * Convert the string to a regular expression, escaping special characters
+ * as needed.
+ */
+
+ ptr = res;
+
+ while (*s && ptr < (res + sizeof(res) - 2))
+ {
+ if (strchr("[]{}().*\\", *s))
+ *ptr++ = '\\';
+
+ *ptr++ = *s++;
+ }
+
+ *ptr = '\0';
+
+ fprintf(stderr, "DEBUG: [cups-driverd] regex_string: \"%s\"\n", res);
+
+ /*
+ * Create a case-insensitive regular expression...
+ */
+
+ if (res[0] && (re = (regex_t *)calloc(1, sizeof(regex_t))) != NULL)
+ {
+ if (!regcomp(re, res, REG_ICASE))
+ {
+ fputs("DEBUG: [cups-driverd] regex_string: OK\n", stderr);
+ return (re);
+ }
+
+ free(re);
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/cups-exec.c b/scheduler/cups-exec.c
new file mode 100644
index 000000000..0081fb4c2
--- /dev/null
+++ b/scheduler/cups-exec.c
@@ -0,0 +1,106 @@
+/*
+ * "$Id$"
+ *
+ * Sandbox helper for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Usage:
+ *
+ * cups-exec /path/to/profile /path/to/program argv0 argv1 ... argvN
+ *
+ * Contents:
+ *
+ * main() - Apply sandbox profile and execute program.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/string-private.h>
+#include <unistd.h>
+#ifdef HAVE_SANDBOX_H
+# define __APPLE_API_PRIVATE
+# include <sandbox.h>
+#endif /* HAVE_SANDBOX_H */
+
+
+/*
+ * 'main()' - Apply sandbox profile and execute program.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+#ifdef HAVE_SANDBOX_H
+ char *sandbox_error = NULL; /* Sandbox error, if any */
+#endif /* HAVE_SANDBOX_H */
+
+
+ /*
+ * Check that we have enough arguments...
+ */
+
+ if (argc < 4)
+ {
+ puts("Usage: cups-exec /path/to/profile /path/to/program argv0 argv1 ... "
+ "argvN");
+ return (1);
+ }
+
+#ifdef HAVE_SANDBOX_H
+ /*
+ * Run in a separate security profile...
+ */
+
+ if (strcmp(argv[1], "none") &&
+ sandbox_init(argv[1], SANDBOX_NAMED_EXTERNAL, &sandbox_error))
+ {
+ fprintf(stderr, "DEBUG: sandbox_init failed: %s (%s)\n", sandbox_error,
+ strerror(errno));
+ sandbox_free_error(sandbox_error);
+ return (1);
+ }
+#endif /* HAVE_SANDBOX_H */
+
+ /*
+ * Close file descriptors we don't need (insurance):
+ *
+ * 0 = stdin
+ * 1 = stdout
+ * 2 = stderr
+ * 3 = back-channel
+ * 4 = side-channel
+ * 5-N = unused
+ */
+
+ for (i = 5; i < 1024; i ++)
+ close(i);
+
+ /*
+ * Execute the program...
+ */
+
+ execv(argv[2], argv + 3);
+
+ /*
+ * If we get here, execv() failed...
+ */
+
+ fprintf(stderr, "DEBUG: execv failed: %s\n", strerror(errno));
+ return (1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/cups-lpd.c b/scheduler/cups-lpd.c
new file mode 100644
index 000000000..b8224d42b
--- /dev/null
+++ b/scheduler/cups-lpd.c
@@ -0,0 +1,1627 @@
+/*
+ * "$Id$"
+ *
+ * Line Printer Daemon interface for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Process an incoming LPD request...
+ * create_job() - Create a new print job.
+ * get_printer() - Get the named printer and its options.
+ * print_file() - Add a file to the current job.
+ * recv_print_job() - Receive a print job from the client.
+ * remove_jobs() - Cancel one or more jobs.
+ * send_state() - Send the queue state.
+ * smart_gets() - Get a line of text, removing the trailing CR and/or LF.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif /* HAVE_INTTYPES_H */
+
+
+/*
+ * LPD "mini-daemon" for CUPS. This program must be used in conjunction
+ * with inetd or another similar program that monitors ports and starts
+ * daemons for each client connection. A typical configuration is:
+ *
+ * printer stream tcp nowait lp /usr/lib/cups/daemon/cups-lpd cups-lpd
+ *
+ * This daemon implements most of RFC 1179 (the unofficial LPD specification)
+ * except for:
+ *
+ * - This daemon does not check to make sure that the source port is
+ * between 721 and 731, since it isn't necessary for proper
+ * functioning and port-based security is no security at all!
+ *
+ * - The "Print any waiting jobs" command is a no-op.
+ *
+ * The LPD-to-IPP mapping is as defined in RFC 2569. The report formats
+ * currently match the Solaris LPD mini-daemon.
+ */
+
+/*
+ * Prototypes...
+ */
+
+static int create_job(http_t *http, const char *dest, const char *title,
+ const char *docname, const char *user,
+ int num_options, cups_option_t *options);
+static int get_printer(http_t *http, const char *name, char *dest,
+ int destsize, cups_option_t **options,
+ int *accepting, int *shared, ipp_pstate_t *state);
+static int print_file(http_t *http, int id, const char *filename,
+ const char *docname, const char *user,
+ const char *format, int last);
+static int recv_print_job(const char *name, int num_defaults,
+ cups_option_t *defaults);
+static int remove_jobs(const char *name, const char *agent,
+ const char *list);
+static int send_state(const char *name, const char *list,
+ int longstatus);
+static char *smart_gets(char *s, int len, FILE *fp);
+
+
+/*
+ * 'main()' - Process an incoming LPD request...
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ int num_defaults; /* Number of default options */
+ cups_option_t *defaults; /* Default options */
+ char line[256], /* Command string */
+ command, /* Command code */
+ *dest, /* Pointer to destination */
+ *list, /* Pointer to list */
+ *agent, /* Pointer to user */
+ status; /* Status for client */
+ socklen_t hostlen; /* Size of client address */
+ http_addr_t hostaddr; /* Address of client */
+ char hostname[256], /* Name of client */
+ hostip[256], /* IP address */
+ *hostfamily; /* Address family */
+ int hostlookups; /* Do hostname lookups? */
+
+
+ /*
+ * Don't buffer the output...
+ */
+
+ setbuf(stdout, NULL);
+
+ /*
+ * Log things using the "cups-lpd" name...
+ */
+
+ openlog("cups-lpd", LOG_PID, LOG_LPR);
+
+ /*
+ * Scan the command-line for options...
+ */
+
+ num_defaults = 0;
+ defaults = NULL;
+ hostlookups = 1;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'h' : /* -h hostname[:port] */
+ if (argv[i][2])
+ cupsSetServer(argv[i] + 2);
+ else
+ {
+ i ++;
+ if (i < argc)
+ cupsSetServer(argv[i]);
+ else
+ syslog(LOG_WARNING, "Expected hostname string after -h option!");
+ }
+ break;
+
+ case 'o' : /* Option */
+ if (argv[i][2])
+ num_defaults = cupsParseOptions(argv[i] + 2, num_defaults,
+ &defaults);
+ else
+ {
+ i ++;
+ if (i < argc)
+ num_defaults = cupsParseOptions(argv[i], num_defaults,
+ &defaults);
+ else
+ syslog(LOG_WARNING, "Expected option string after -o option!");
+ }
+ break;
+
+ case 'n' : /* Don't do hostname lookups */
+ hostlookups = 0;
+ break;
+
+ default :
+ syslog(LOG_WARNING, "Unknown option \"%c\" ignored!", argv[i][1]);
+ break;
+ }
+ }
+ else
+ syslog(LOG_WARNING, "Unknown command-line option \"%s\" ignored!",
+ argv[i]);
+
+ /*
+ * Get the address of the client...
+ */
+
+ hostlen = sizeof(hostaddr);
+
+ if (getpeername(0, (struct sockaddr *)&hostaddr, &hostlen))
+ {
+ syslog(LOG_WARNING, "Unable to get client address - %s", strerror(errno));
+ strcpy(hostname, "unknown");
+ }
+ else
+ {
+ httpAddrString(&hostaddr, hostip, sizeof(hostip));
+
+ if (hostlookups)
+ httpAddrLookup(&hostaddr, hostname, sizeof(hostname));
+ else
+ strlcpy(hostname, hostip, sizeof(hostname));
+
+#ifdef AF_INET6
+ if (hostaddr.addr.sa_family == AF_INET6)
+ hostfamily = "IPv6";
+ else
+#endif /* AF_INET6 */
+ hostfamily = "IPv4";
+
+ syslog(LOG_INFO, "Connection from %s (%s %s)", hostname, hostfamily,
+ hostip);
+ }
+
+ num_defaults = cupsAddOption("job-originating-host-name", hostname,
+ num_defaults, &defaults);
+
+ /*
+ * RFC1179 specifies that only 1 daemon command can be received for
+ * every connection.
+ */
+
+ if (smart_gets(line, sizeof(line), stdin) == NULL)
+ {
+ /*
+ * Unable to get command from client! Send an error status and return.
+ */
+
+ syslog(LOG_ERR, "Unable to get command line from client!");
+ putchar(1);
+ return (1);
+ }
+
+ /*
+ * The first byte is the command byte. After that will be the queue name,
+ * resource list, and/or user name.
+ */
+
+ command = line[0];
+ dest = line + 1;
+
+ if (command == 0x02)
+ list = NULL;
+ else
+ {
+ for (list = dest + 1; *list && !isspace(*list & 255); list ++);
+
+ while (isspace(*list & 255))
+ *list++ = '\0';
+ }
+
+ /*
+ * Do the command...
+ */
+
+ switch (command)
+ {
+ default : /* Unknown command */
+ syslog(LOG_ERR, "Unknown LPD command 0x%02X!", command);
+ syslog(LOG_ERR, "Command line = %s", line + 1);
+ putchar(1);
+
+ status = 1;
+ break;
+
+ case 0x01 : /* Print any waiting jobs */
+ syslog(LOG_INFO, "Print waiting jobs (no-op)");
+ putchar(0);
+
+ status = 0;
+ break;
+
+ case 0x02 : /* Receive a printer job */
+ syslog(LOG_INFO, "Receive print job for %s", dest);
+ /* recv_print_job() sends initial status byte */
+
+ status = recv_print_job(dest, num_defaults, defaults);
+ break;
+
+ case 0x03 : /* Send queue state (short) */
+ syslog(LOG_INFO, "Send queue state (short) for %s %s", dest, list);
+ /* no status byte for this command */
+
+ status = send_state(dest, list, 0);
+ break;
+
+ case 0x04 : /* Send queue state (long) */
+ syslog(LOG_INFO, "Send queue state (long) for %s %s", dest, list);
+ /* no status byte for this command */
+
+ status = send_state(dest, list, 1);
+ break;
+
+ case 0x05 : /* Remove jobs */
+ if (list)
+ {
+ /*
+ * Grab the agent and skip to the list of users and/or jobs.
+ */
+
+ agent = list;
+
+ for (; *list && !isspace(*list & 255); list ++);
+ while (isspace(*list & 255))
+ *list++ = '\0';
+
+ syslog(LOG_INFO, "Remove jobs %s on %s by %s", list, dest, agent);
+
+ status = remove_jobs(dest, agent, list);
+ }
+ else
+ status = 1;
+
+ putchar(status);
+ break;
+ }
+
+ syslog(LOG_INFO, "Closing connection");
+ closelog();
+
+ return (status);
+}
+
+
+/*
+ * 'create_job()' - Create a new print job.
+ */
+
+static int /* O - Job ID or -1 on error */
+create_job(http_t *http, /* I - HTTP connection */
+ const char *dest, /* I - Destination name */
+ const char *title, /* I - job-name */
+ const char *docname, /* I - Name of job file */
+ const char *user, /* I - requesting-user-name */
+ int num_options, /* I - Number of options for job */
+ cups_option_t *options) /* I - Options for job */
+{
+ ipp_t *request; /* IPP request */
+ ipp_t *response; /* IPP response */
+ ipp_attribute_t *attr; /* IPP attribute */
+ char uri[HTTP_MAX_URI]; /* Printer URI */
+ int id; /* Job ID */
+
+
+ /*
+ * Setup the Create-Job request...
+ */
+
+ request = ippNewRequest(IPP_CREATE_JOB);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/printers/%s", dest);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+
+ if (title[0])
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
+ NULL, title);
+
+ if (docname[0])
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name",
+ NULL, docname);
+
+ cupsEncodeOptions(request, num_options, options);
+
+ /*
+ * Do the request...
+ */
+
+ snprintf(uri, sizeof(uri), "/printers/%s", dest);
+
+ response = cupsDoRequest(http, request, uri);
+
+ if (!response || cupsLastError() > IPP_OK_CONFLICT)
+ {
+ syslog(LOG_ERR, "Unable to create job - %s", cupsLastErrorString());
+
+ ippDelete(response);
+
+ return (-1);
+ }
+
+ /*
+ * Get the job-id value from the response and return it...
+ */
+
+ if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL)
+ {
+ id = -1;
+
+ syslog(LOG_ERR, "No job-id attribute found in response from server!");
+ }
+ else
+ {
+ id = attr->values[0].integer;
+
+ syslog(LOG_INFO, "Print file - job ID = %d", id);
+ }
+
+ ippDelete(response);
+
+ return (id);
+}
+
+
+/*
+ * 'get_printer()' - Get the named printer and its options.
+ */
+
+static int /* O - Number of options or -1 on error */
+get_printer(http_t *http, /* I - HTTP connection */
+ const char *name, /* I - Printer name from request */
+ char *dest, /* I - Destination buffer */
+ int destsize, /* I - Size of destination buffer */
+ cups_option_t **options, /* O - Printer options */
+ int *accepting, /* O - printer-is-accepting-jobs value */
+ int *shared, /* O - printer-is-shared value */
+ ipp_pstate_t *state) /* O - printer-state value */
+{
+ int num_options; /* Number of options */
+ cups_file_t *fp; /* lpoptions file */
+ char line[1024], /* Line from lpoptions file */
+ *value, /* Pointer to value on line */
+ *optptr; /* Pointer to options on line */
+ int linenum; /* Line number in file */
+ const char *cups_serverroot; /* CUPS_SERVERROOT env var */
+ ipp_t *request; /* IPP request */
+ ipp_t *response; /* IPP response */
+ ipp_attribute_t *attr; /* IPP attribute */
+ char uri[HTTP_MAX_URI]; /* Printer URI */
+ static const char * const requested[] =
+ { /* Requested attributes */
+ "printer-info",
+ "printer-is-accepting-jobs",
+ "printer-is-shared",
+ "printer-name",
+ "printer-state"
+ };
+
+
+ /*
+ * Initialize everything...
+ */
+
+ if (accepting)
+ *accepting = 0;
+ if (shared)
+ *shared = 0;
+ if (state)
+ *state = IPP_PRINTER_STOPPED;
+ if (options)
+ *options = NULL;
+
+ /*
+ * See if the name is a queue name optionally with an instance name.
+ */
+
+ strlcpy(dest, name, destsize);
+ if ((value = strchr(dest, '/')) != NULL)
+ *value = '\0';
+
+ /*
+ * Setup the Get-Printer-Attributes request...
+ */
+
+ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/printers/%s", dest);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ (int)(sizeof(requested) / sizeof(requested[0])),
+ NULL, requested);
+
+ /*
+ * Do the request...
+ */
+
+ response = cupsDoRequest(http, request, "/");
+
+ if (!response || cupsLastError() > IPP_OK_CONFLICT)
+ {
+ /*
+ * If we can't find the printer by name, look up the printer-name
+ * using the printer-info values...
+ */
+
+ ipp_attribute_t *accepting_attr,/* printer-is-accepting-jobs */
+ *info_attr, /* printer-info */
+ *name_attr, /* printer-name */
+ *shared_attr, /* printer-is-shared */
+ *state_attr; /* printer-state */
+
+
+ ippDelete(response);
+
+ /*
+ * Setup the CUPS-Get-Printers request...
+ */
+
+ request = ippNewRequest(CUPS_GET_PRINTERS);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ (int)(sizeof(requested) / sizeof(requested[0])),
+ NULL, requested);
+
+ /*
+ * Do the request...
+ */
+
+ response = cupsDoRequest(http, request, "/");
+
+ if (!response || cupsLastError() > IPP_OK_CONFLICT)
+ {
+ syslog(LOG_ERR, "Unable to get list of printers - %s",
+ cupsLastErrorString());
+
+ ippDelete(response);
+
+ return (-1);
+ }
+
+ /*
+ * Scan the response for printers...
+ */
+
+ *dest = '\0';
+ attr = response->attrs;
+
+ while (attr)
+ {
+ /*
+ * Skip to the next printer...
+ */
+
+ while (attr && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (!attr)
+ break;
+
+ /*
+ * Get all of the attributes for the current printer...
+ */
+
+ accepting_attr = NULL;
+ info_attr = NULL;
+ name_attr = NULL;
+ shared_attr = NULL;
+ state_attr = NULL;
+
+ while (attr && attr->group_tag == IPP_TAG_PRINTER)
+ {
+ if (!strcmp(attr->name, "printer-is-accepting-jobs") &&
+ attr->value_tag == IPP_TAG_BOOLEAN)
+ accepting_attr = attr;
+ else if (!strcmp(attr->name, "printer-info") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ info_attr = attr;
+ else if (!strcmp(attr->name, "printer-name") &&
+ attr->value_tag == IPP_TAG_NAME)
+ name_attr = attr;
+ else if (!strcmp(attr->name, "printer-is-shared") &&
+ attr->value_tag == IPP_TAG_BOOLEAN)
+ shared_attr = attr;
+ else if (!strcmp(attr->name, "printer-state") &&
+ attr->value_tag == IPP_TAG_ENUM)
+ state_attr = attr;
+
+ attr = attr->next;
+ }
+
+ if (info_attr && name_attr &&
+ !_cups_strcasecmp(name, info_attr->values[0].string.text))
+ {
+ /*
+ * Found a match, use this one!
+ */
+
+ strlcpy(dest, name_attr->values[0].string.text, destsize);
+
+ if (accepting && accepting_attr)
+ *accepting = accepting_attr->values[0].boolean;
+
+ if (shared && shared_attr)
+ *shared = shared_attr->values[0].boolean;
+
+ if (state && state_attr)
+ *state = (ipp_pstate_t)state_attr->values[0].integer;
+
+ break;
+ }
+ }
+
+ ippDelete(response);
+
+ if (!*dest)
+ {
+ syslog(LOG_ERR, "Unable to find \"%s\" in list of printers!", name);
+
+ return (-1);
+ }
+
+ name = dest;
+ }
+ else
+ {
+ /*
+ * Get values from the response...
+ */
+
+ if (accepting)
+ {
+ if ((attr = ippFindAttribute(response, "printer-is-accepting-jobs",
+ IPP_TAG_BOOLEAN)) == NULL)
+ syslog(LOG_ERR, "No printer-is-accepting-jobs attribute found in "
+ "response from server!");
+ else
+ *accepting = attr->values[0].boolean;
+ }
+
+ if (shared)
+ {
+ if ((attr = ippFindAttribute(response, "printer-is-shared",
+ IPP_TAG_BOOLEAN)) == NULL)
+ {
+ syslog(LOG_ERR, "No printer-is-shared attribute found in "
+ "response from server!");
+ *shared = 1;
+ }
+ else
+ *shared = attr->values[0].boolean;
+ }
+
+ if (state)
+ {
+ if ((attr = ippFindAttribute(response, "printer-state",
+ IPP_TAG_ENUM)) == NULL)
+ syslog(LOG_ERR, "No printer-state attribute found in "
+ "response from server!");
+ else
+ *state = (ipp_pstate_t)attr->values[0].integer;
+ }
+
+ ippDelete(response);
+ }
+
+ /*
+ * Next look for the printer in the lpoptions file...
+ */
+
+ num_options = 0;
+
+ if (options && shared && accepting)
+ {
+ if ((cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL)
+ cups_serverroot = CUPS_SERVERROOT;
+
+ snprintf(line, sizeof(line), "%s/lpoptions", cups_serverroot);
+ if ((fp = cupsFileOpen(line, "r")) != NULL)
+ {
+ linenum = 0;
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ /*
+ * Make sure we have "Dest name options" or "Default name options"...
+ */
+
+ if ((_cups_strcasecmp(line, "Dest") && _cups_strcasecmp(line, "Default")) || !value)
+ continue;
+
+ /*
+ * Separate destination name from options...
+ */
+
+ for (optptr = value; *optptr && !isspace(*optptr & 255); optptr ++);
+
+ while (*optptr == ' ')
+ *optptr++ = '\0';
+
+ /*
+ * If this is our destination, parse the options and break out of
+ * the loop - we're done!
+ */
+
+ if (!_cups_strcasecmp(value, name))
+ {
+ num_options = cupsParseOptions(optptr, num_options, options);
+ break;
+ }
+ }
+
+ cupsFileClose(fp);
+ }
+ }
+ else if (options)
+ *options = NULL;
+
+ /*
+ * Return the number of options for this destination...
+ */
+
+ return (num_options);
+}
+
+
+/*
+ * 'print_file()' - Add a file to the current job.
+ */
+
+static int /* O - 0 on success, -1 on failure */
+print_file(http_t *http, /* I - HTTP connection */
+ int id, /* I - Job ID */
+ const char *filename, /* I - File to print */
+ const char *docname, /* I - document-name */
+ const char *user, /* I - requesting-user-name */
+ const char *format, /* I - document-format */
+ int last) /* I - 1 = last file in job */
+{
+ ipp_t *request; /* IPP request */
+ char uri[HTTP_MAX_URI]; /* Printer URI */
+
+
+ /*
+ * Setup the Send-Document request...
+ */
+
+ request = ippNewRequest(IPP_SEND_DOCUMENT);
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", 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, user);
+
+ if (docname)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "document-name", NULL, docname);
+
+ if (format)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
+ "document-format", NULL, format);
+
+ if (last)
+ ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
+
+ /*
+ * Do the request...
+ */
+
+ snprintf(uri, sizeof(uri), "/jobs/%d", id);
+
+ ippDelete(cupsDoFileRequest(http, request, uri, filename));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ syslog(LOG_ERR, "Unable to send document - %s", cupsLastErrorString());
+
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'recv_print_job()' - Receive a print job from the client.
+ */
+
+static int /* O - Command status */
+recv_print_job(
+ const char *queue, /* I - Printer name */
+ int num_defaults, /* I - Number of default options */
+ cups_option_t *defaults) /* I - Default options */
+{
+ http_t *http; /* HTTP connection */
+ int i; /* Looping var */
+ int status; /* Command status */
+ int fd; /* Temporary file */
+ FILE *fp; /* File pointer */
+ char filename[1024]; /* Temporary filename */
+ int bytes; /* Bytes received */
+ char line[256], /* Line from file/stdin */
+ command, /* Command from line */
+ *count, /* Number of bytes */
+ *name; /* Name of file */
+ const char *job_sheets; /* Job sheets */
+ int num_data; /* Number of data files */
+ char control[1024], /* Control filename */
+ data[100][256], /* Data files */
+ temp[100][1024]; /* Temporary files */
+ char user[1024], /* User name */
+ title[1024], /* Job title */
+ docname[1024], /* Document name */
+ dest[256]; /* Printer/class queue */
+ int accepting, /* printer-is-accepting */
+ shared, /* printer-is-shared */
+ num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ int id; /* Job ID */
+ int docnumber, /* Current document number */
+ doccount; /* Count of documents */
+
+
+ /*
+ * Connect to the server...
+ */
+
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+ if (!http)
+ {
+ syslog(LOG_ERR, "Unable to connect to server: %s", strerror(errno));
+
+ putchar(1);
+
+ return (1);
+ }
+
+ /*
+ * See if the printer is available...
+ */
+
+ num_options = get_printer(http, queue, dest, sizeof(dest), &options,
+ &accepting, &shared, NULL);
+
+ if (num_options < 0 || !accepting || !shared)
+ {
+ if (dest[0])
+ syslog(LOG_INFO, "Rejecting job because \"%s\" is not %s", dest,
+ !accepting ? "accepting jobs" : "shared");
+ else
+ syslog(LOG_ERR, "Unable to get printer information for \"%s\"", queue);
+
+ httpClose(http);
+
+ putchar(1);
+
+ return (1);
+ }
+
+ putchar(0); /* OK so far... */
+
+ /*
+ * Read the request...
+ */
+
+ status = 0;
+ num_data = 0;
+ fd = -1;
+
+ control[0] = '\0';
+
+ while (smart_gets(line, sizeof(line), stdin) != NULL)
+ {
+ if (strlen(line) < 2)
+ {
+ status = 1;
+ break;
+ }
+
+ command = line[0];
+ count = line + 1;
+
+ for (name = count + 1; *name && !isspace(*name & 255); name ++);
+ while (isspace(*name & 255))
+ *name++ = '\0';
+
+ switch (command)
+ {
+ default :
+ case 0x01 : /* Abort */
+ status = 1;
+ break;
+
+ case 0x02 : /* Receive control file */
+ if (strlen(name) < 2)
+ {
+ syslog(LOG_ERR, "Bad control file name \"%s\"", name);
+ putchar(1);
+ status = 1;
+ break;
+ }
+
+ if (control[0])
+ {
+ /*
+ * Append to the existing control file - the LPD spec is
+ * not entirely clear, but at least the OS/2 LPD code sends
+ * multiple control files per connection...
+ */
+
+ if ((fd = open(control, O_WRONLY)) < 0)
+ {
+ syslog(LOG_ERR,
+ "Unable to append to temporary control file \"%s\" - %s",
+ control, strerror(errno));
+ putchar(1);
+ status = 1;
+ break;
+ }
+
+ lseek(fd, 0, SEEK_END);
+ }
+ else
+ {
+ if ((fd = cupsTempFd(control, sizeof(control))) < 0)
+ {
+ syslog(LOG_ERR, "Unable to open temporary control file \"%s\" - %s",
+ control, strerror(errno));
+ putchar(1);
+ status = 1;
+ break;
+ }
+
+ strcpy(filename, control);
+ }
+ break;
+
+ case 0x03 : /* Receive data file */
+ if (strlen(name) < 2)
+ {
+ syslog(LOG_ERR, "Bad data file name \"%s\"", name);
+ putchar(1);
+ status = 1;
+ break;
+ }
+
+ if (num_data >= (int)(sizeof(data) / sizeof(data[0])))
+ {
+ /*
+ * Too many data files...
+ */
+
+ syslog(LOG_ERR, "Too many data files (%d)", num_data);
+ putchar(1);
+ status = 1;
+ break;
+ }
+
+ strlcpy(data[num_data], name, sizeof(data[0]));
+
+ if ((fd = cupsTempFd(temp[num_data], sizeof(temp[0]))) < 0)
+ {
+ syslog(LOG_ERR, "Unable to open temporary data file \"%s\" - %s",
+ temp[num_data], strerror(errno));
+ putchar(1);
+ status = 1;
+ break;
+ }
+
+ strcpy(filename, temp[num_data]);
+
+ num_data ++;
+ break;
+ }
+
+ putchar(status);
+
+ if (status)
+ break;
+
+ /*
+ * Copy the data or control file from the client...
+ */
+
+ for (i = atoi(count); i > 0; i -= bytes)
+ {
+ if (i > sizeof(line))
+ bytes = sizeof(line);
+ else
+ bytes = i;
+
+ if ((bytes = fread(line, 1, bytes, stdin)) > 0)
+ bytes = write(fd, line, bytes);
+
+ if (bytes < 1)
+ {
+ syslog(LOG_ERR, "Error while reading file - %s",
+ strerror(errno));
+ status = 1;
+ break;
+ }
+ }
+
+ /*
+ * Read trailing nul...
+ */
+
+ if (!status)
+ {
+ if (fread(line, 1, 1, stdin) < 1)
+ {
+ status = 1;
+ syslog(LOG_ERR, "Error while reading trailing nul - %s",
+ strerror(errno));
+ }
+ else if (line[0])
+ {
+ status = 1;
+ syslog(LOG_ERR, "Trailing character after file is not nul (%02X)!",
+ line[0]);
+ }
+ }
+
+ /*
+ * Close the file and send an acknowledgement...
+ */
+
+ close(fd);
+
+ putchar(status);
+
+ if (status)
+ break;
+ }
+
+ if (!status)
+ {
+ /*
+ * Process the control file and print stuff...
+ */
+
+ if ((fp = fopen(control, "rb")) == NULL)
+ status = 1;
+ else
+ {
+ /*
+ * Copy the default options...
+ */
+
+ for (i = 0; i < num_defaults; i ++)
+ num_options = cupsAddOption(defaults[i].name,
+ defaults[i].value,
+ num_options, &options);
+
+ /*
+ * Grab the job information...
+ */
+
+ title[0] = '\0';
+ user[0] = '\0';
+ docname[0] = '\0';
+ doccount = 0;
+
+ while (smart_gets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Process control lines...
+ */
+
+ switch (line[0])
+ {
+ case 'J' : /* Job name */
+ strlcpy(title, line + 1, sizeof(title));
+ break;
+
+ case 'N' : /* Document name */
+ strlcpy(docname, line + 1, sizeof(docname));
+ break;
+
+ case 'P' : /* User identification */
+ strlcpy(user, line + 1, sizeof(user));
+ break;
+
+ case 'L' : /* Print banner page */
+ /*
+ * If a banner was requested and it's not overridden by a
+ * command line option and the destination's default is none
+ * then add the standard banner...
+ */
+
+ if (cupsGetOption("job-sheets", num_defaults, defaults) == NULL &&
+ ((job_sheets = cupsGetOption("job-sheets", num_options,
+ options)) == NULL ||
+ !strcmp(job_sheets, "none,none")))
+ {
+ num_options = cupsAddOption("job-sheets", "standard",
+ num_options, &options);
+ }
+ break;
+
+ case 'c' : /* Plot CIF file */
+ case 'd' : /* Print DVI file */
+ case 'f' : /* Print formatted file */
+ case 'g' : /* Plot file */
+ case 'l' : /* Print file leaving control characters (raw) */
+ case 'n' : /* Print ditroff output file */
+ case 'o' : /* Print PostScript output file */
+ case 'p' : /* Print file with 'pr' format (prettyprint) */
+ case 'r' : /* File to print with FORTRAN carriage control */
+ case 't' : /* Print troff output file */
+ case 'v' : /* Print raster file */
+ doccount ++;
+
+ if (line[0] == 'l' &&
+ !cupsGetOption("document-format", num_options, options))
+ num_options = cupsAddOption("raw", "", num_options, &options);
+
+ if (line[0] == 'p')
+ num_options = cupsAddOption("prettyprint", "", num_options,
+ &options);
+ break;
+ }
+
+ if (status)
+ break;
+ }
+
+ /*
+ * Check that we have a username...
+ */
+
+ if (!user[0])
+ {
+ syslog(LOG_WARNING, "No username specified by client! "
+ "Using \"anonymous\"...");
+ strcpy(user, "anonymous");
+ }
+
+ /*
+ * Create the job...
+ */
+
+ if ((id = create_job(http, dest, title, docname, user, num_options,
+ options)) < 0)
+ status = 1;
+ else
+ {
+ /*
+ * Then print the job files...
+ */
+
+ rewind(fp);
+
+ docname[0] = '\0';
+ docnumber = 0;
+
+ while (smart_gets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Process control lines...
+ */
+
+ switch (line[0])
+ {
+ case 'N' : /* Document name */
+ strlcpy(docname, line + 1, sizeof(docname));
+ break;
+
+ case 'c' : /* Plot CIF file */
+ case 'd' : /* Print DVI file */
+ case 'f' : /* Print formatted file */
+ case 'g' : /* Plot file */
+ case 'l' : /* Print file leaving control characters (raw) */
+ case 'n' : /* Print ditroff output file */
+ case 'o' : /* Print PostScript output file */
+ case 'p' : /* Print file with 'pr' format (prettyprint) */
+ case 'r' : /* File to print with FORTRAN carriage control */
+ case 't' : /* Print troff output file */
+ case 'v' : /* Print raster file */
+ /*
+ * Figure out which file we are printing...
+ */
+
+ for (i = 0; i < num_data; i ++)
+ if (!strcmp(data[i], line + 1))
+ break;
+
+ if (i >= num_data)
+ {
+ status = 1;
+ break;
+ }
+
+ /*
+ * Send the print file...
+ */
+
+ docnumber ++;
+
+ if (print_file(http, id, temp[i], docname, user,
+ cupsGetOption("document-format", num_options,
+ options),
+ docnumber == doccount))
+ status = 1;
+ else
+ status = 0;
+
+ break;
+ }
+
+ if (status)
+ break;
+ }
+ }
+
+ fclose(fp);
+ }
+ }
+
+ cupsFreeOptions(num_options, options);
+
+ httpClose(http);
+
+ /*
+ * Clean up all temporary files and return...
+ */
+
+ unlink(control);
+
+ for (i = 0; i < num_data; i ++)
+ unlink(temp[i]);
+
+ return (status);
+}
+
+
+/*
+ * 'remove_jobs()' - Cancel one or more jobs.
+ */
+
+static int /* O - Command status */
+remove_jobs(const char *dest, /* I - Destination */
+ const char *agent, /* I - User agent */
+ const char *list) /* I - List of jobs or users */
+{
+ int id; /* Job ID */
+ http_t *http; /* HTTP server connection */
+ ipp_t *request; /* IPP Request */
+ char uri[HTTP_MAX_URI]; /* Job URI */
+
+
+ (void)dest; /* Suppress compiler warnings... */
+
+ /*
+ * Try connecting to the local server...
+ */
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ syslog(LOG_ERR, "Unable to connect to server %s: %s", cupsServer(),
+ strerror(errno));
+ return (1);
+ }
+
+ /*
+ * Loop for each job...
+ */
+
+ while ((id = atoi(list)) > 0)
+ {
+ /*
+ * Skip job ID in list...
+ */
+
+ while (isdigit(*list & 255))
+ list ++;
+ while (isspace(*list & 255))
+ list ++;
+
+ /*
+ * Build an IPP_CANCEL_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * job-uri
+ * requesting-user-name
+ */
+
+ request = ippNewRequest(IPP_CANCEL_JOB);
+
+ sprintf(uri, "ipp://localhost/jobs/%d", 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, agent);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ippDelete(cupsDoRequest(http, request, "/jobs"));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ syslog(LOG_WARNING, "Cancel of job ID %d failed: %s\n", id,
+ cupsLastErrorString());
+ httpClose(http);
+ return (1);
+ }
+ else
+ syslog(LOG_INFO, "Job ID %d canceled", id);
+ }
+
+ httpClose(http);
+
+ return (0);
+}
+
+
+/*
+ * 'send_state()' - Send the queue state.
+ */
+
+static int /* O - Command status */
+send_state(const char *queue, /* I - Destination */
+ const char *list, /* I - Job or user */
+ int longstatus) /* I - List of jobs or users */
+{
+ int id; /* Job ID from list */
+ http_t *http; /* HTTP server connection */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_pstate_t state; /* Printer state */
+ 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 */
+ jobcount, /* Number of jobs */
+ jobcopies, /* Number of copies */
+ rank; /* Rank of job */
+ char rankstr[255]; /* Rank string */
+ char namestr[1024]; /* Job name string */
+ char uri[HTTP_MAX_URI]; /* Printer URI */
+ char dest[256]; /* Printer/class queue */
+ static const char * const ranks[10] = /* Ranking strings */
+ {
+ "th",
+ "st",
+ "nd",
+ "rd",
+ "th",
+ "th",
+ "th",
+ "th",
+ "th",
+ "th"
+ };
+ static const char * const requested[] =
+ { /* Requested attributes */
+ "job-id",
+ "job-k-octets",
+ "job-state",
+ "job-printer-uri",
+ "job-originating-user-name",
+ "job-name",
+ "copies"
+ };
+
+
+ /*
+ * Try connecting to the local server...
+ */
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ syslog(LOG_ERR, "Unable to connect to server %s: %s", cupsServer(),
+ strerror(errno));
+ printf("Unable to connect to server %s: %s", cupsServer(), strerror(errno));
+ return (1);
+ }
+
+ /*
+ * Get the actual destination name and printer state...
+ */
+
+ if (get_printer(http, queue, dest, sizeof(dest), NULL, NULL, NULL, &state))
+ {
+ syslog(LOG_ERR, "Unable to get printer %s: %s", queue,
+ cupsLastErrorString());
+ printf("Unable to get printer %s: %s", queue, cupsLastErrorString());
+ return (1);
+ }
+
+ /*
+ * Show the queue state...
+ */
+
+ switch (state)
+ {
+ case IPP_PRINTER_IDLE :
+ printf("%s is ready\n", dest);
+ break;
+ case IPP_PRINTER_PROCESSING :
+ printf("%s is ready and printing\n", dest);
+ break;
+ case IPP_PRINTER_STOPPED :
+ printf("%s is not ready\n", dest);
+ break;
+ }
+
+ /*
+ * 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
+ */
+
+ id = atoi(list);
+
+ request = ippNewRequest(id ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/printers/%s", dest);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ if (id)
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", id);
+ else
+ {
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, list);
+ ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
+ }
+
+ 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...
+ */
+
+ jobcount = 0;
+ response = cupsDoRequest(http, request, "/");
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ printf("get-jobs failed: %s\n", cupsLastErrorString());
+ ippDelete(response);
+ return (1);
+ }
+
+ /*
+ * Loop through the job list and display them...
+ */
+
+ for (attr = response->attrs, rank = 1; attr; attr = attr->next)
+ {
+ /*
+ * Skip leading attributes until we hit a job...
+ */
+
+ while (attr && (attr->group_tag != IPP_TAG_JOB || !attr->name))
+ attr = attr->next;
+
+ if (!attr)
+ break;
+
+ /*
+ * Pull the needed attributes from this job...
+ */
+
+ jobid = 0;
+ jobsize = 0;
+ jobstate = IPP_JOB_PENDING;
+ jobname = "untitled";
+ jobuser = NULL;
+ jobdest = NULL;
+ jobcopies = 1;
+
+ while (attr && attr->group_tag == IPP_TAG_JOB)
+ {
+ if (!strcmp(attr->name, "job-id") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ jobid = attr->values[0].integer;
+
+ if (!strcmp(attr->name, "job-k-octets") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ jobsize = attr->values[0].integer;
+
+ if (!strcmp(attr->name, "job-state") &&
+ attr->value_tag == IPP_TAG_ENUM)
+ jobstate = (ipp_jstate_t)attr->values[0].integer;
+
+ if (!strcmp(attr->name, "job-printer-uri") &&
+ attr->value_tag == IPP_TAG_URI)
+ if ((jobdest = strrchr(attr->values[0].string.text, '/')) != NULL)
+ jobdest ++;
+
+ if (!strcmp(attr->name, "job-originating-user-name") &&
+ attr->value_tag == IPP_TAG_NAME)
+ jobuser = attr->values[0].string.text;
+
+ if (!strcmp(attr->name, "job-name") &&
+ attr->value_tag == IPP_TAG_NAME)
+ jobname = attr->values[0].string.text;
+
+ if (!strcmp(attr->name, "copies") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ jobcopies = attr->values[0].integer;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (!jobdest || !jobid)
+ {
+ if (!attr)
+ break;
+ else
+ continue;
+ }
+
+ if (!longstatus && jobcount == 0)
+ puts("Rank Owner Job File(s) Total Size");
+
+ jobcount ++;
+
+ /*
+ * Display the job...
+ */
+
+ if (jobstate == IPP_JOB_PROCESSING)
+ strcpy(rankstr, "active");
+ else
+ {
+ snprintf(rankstr, sizeof(rankstr), "%d%s", rank, ranks[rank % 10]);
+ rank ++;
+ }
+
+ if (longstatus)
+ {
+ puts("");
+
+ if (jobcopies > 1)
+ snprintf(namestr, sizeof(namestr), "%d copies of %s", jobcopies,
+ jobname);
+ else
+ strlcpy(namestr, jobname, sizeof(namestr));
+
+ printf("%s: %-33.33s [job %d localhost]\n", jobuser, rankstr, jobid);
+ printf(" %-39.39s %.0f bytes\n", namestr, 1024.0 * jobsize);
+ }
+ else
+ printf("%-7s %-7.7s %-7d %-31.31s %.0f bytes\n", rankstr, jobuser,
+ jobid, jobname, 1024.0 * jobsize);
+
+ if (!attr)
+ break;
+ }
+
+ ippDelete(response);
+
+ if (jobcount == 0)
+ puts("no entries");
+
+ httpClose(http);
+
+ return (0);
+}
+
+
+/*
+ * 'smart_gets()' - Get a line of text, removing the trailing CR and/or LF.
+ */
+
+static char * /* O - Line read or NULL */
+smart_gets(char *s, /* I - Pointer to line buffer */
+ int len, /* I - Size of line buffer */
+ FILE *fp) /* I - File to read from */
+{
+ char *ptr, /* Pointer into line */
+ *end; /* End of line */
+ int ch; /* Character from file */
+
+
+ /*
+ * Read the line; unlike fgets(), we read the entire line but dump
+ * characters that go past the end of the buffer. Also, we accept
+ * CR, LF, or CR LF for the line endings to be "safe", although
+ * RFC 1179 specifically says "just use LF".
+ */
+
+ ptr = s;
+ end = s + len - 1;
+
+ while ((ch = getc(fp)) != EOF)
+ {
+ if (ch == '\n')
+ break;
+ else if (ch == '\r')
+ {
+ /*
+ * See if a LF follows...
+ */
+
+ ch = getc(fp);
+
+ if (ch != '\n')
+ ungetc(ch, fp);
+
+ break;
+ }
+ else if (ptr < end)
+ *ptr++ = ch;
+ }
+
+ *ptr = '\0';
+
+ if (ch == EOF && ptr == s)
+ return (NULL);
+ else
+ return (s);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/cups-lpd.xinetd.in b/scheduler/cups-lpd.xinetd.in
new file mode 100644
index 000000000..05fbba754
--- /dev/null
+++ b/scheduler/cups-lpd.xinetd.in
@@ -0,0 +1,12 @@
+service printer
+{
+ disable = yes
+ socket_type = stream
+ protocol = tcp
+ wait = no
+ user = @CUPS_USER@
+ group = @CUPS_GROUP@
+ passenv =
+ server = @CUPS_SERVERBIN@/daemon/cups-lpd
+ server_args = -o document-format=application/octet-stream
+}
diff --git a/scheduler/cups-polld.c b/scheduler/cups-polld.c
new file mode 100644
index 000000000..24e312ef5
--- /dev/null
+++ b/scheduler/cups-polld.c
@@ -0,0 +1,469 @@
+/*
+ * "$Id$"
+ *
+ * Polling daemon for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Open sockets and poll until we are killed...
+ * dequote() - Remote quotes from a string.
+ * poll_server() - Poll the server for the given set of printers or
+ * classes.
+ * sighup_handler() - Handle 'hangup' signals to restart polling.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include <signal.h>
+
+
+/*
+ * Local globals...
+ */
+
+static int restart_polling = 1;
+
+
+/*
+ * Local functions...
+ */
+
+static char *dequote(char *d, const char *s, int dlen);
+static int poll_server(http_t *http, int sock, int port, int interval,
+ const char *prefix);
+static void sighup_handler(int sig);
+
+
+/*
+ * 'main()' - Open sockets and poll until we are killed...
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ http_t *http; /* HTTP connection */
+ int interval; /* Polling interval */
+ int sock; /* Browser sock */
+ int port; /* Browser port */
+ int val; /* Socket option value */
+ int seconds, /* Seconds left from poll */
+ remain; /* Total remaining time to sleep */
+ char prefix[1024]; /* Prefix for log messages */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Catch hangup signals for when the network changes...
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGHUP, sighup_handler);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGHUP);
+ action.sa_handler = sighup_handler;
+ sigaction(SIGHUP, &action, NULL);
+#else
+ signal(SIGHUP, sighup_handler);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Don't buffer log messages...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * The command-line must contain the following:
+ *
+ * cups-polld server server-port interval port
+ */
+
+ if (argc != 5)
+ {
+ fputs("Usage: cups-polld server server-port interval port\n", stderr);
+ return (1);
+ }
+
+ interval = atoi(argv[3]);
+ port = atoi(argv[4]);
+
+ if (interval < 2)
+ interval = 2;
+
+ snprintf(prefix, sizeof(prefix), "[cups-polld %s:%d]", argv[1], atoi(argv[2]));
+
+ /*
+ * Open a broadcast socket...
+ */
+
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ fprintf(stderr, "ERROR: %s Unable to open broadcast socket: %s\n", prefix,
+ strerror(errno));
+ return (1);
+ }
+
+ /*
+ * Set the "broadcast" flag...
+ */
+
+ val = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
+ {
+ fprintf(stderr, "ERROR: %s Unable to put socket in broadcast mode: %s\n",
+ prefix, strerror(errno));
+
+ close(sock);
+ return (1);
+ }
+
+ /*
+ * Loop forever, asking for available printers and classes...
+ */
+
+ for (http = NULL; !ferror(stderr);)
+ {
+ /*
+ * Open a connection to the server...
+ */
+
+ if (restart_polling || !http)
+ {
+ restart_polling = 0;
+ httpClose(http);
+
+ if ((http = httpConnectEncrypt(argv[1], atoi(argv[2]),
+ cupsEncryption())) == NULL)
+ {
+ fprintf(stderr, "ERROR: %s Unable to connect to %s on port %s.\n",
+ prefix, argv[1], argv[2]);
+ }
+ }
+
+ /*
+ * Get the printers and classes...
+ */
+
+ remain = interval;
+
+ if (http && (seconds = poll_server(http, sock, port, interval, prefix)) > 0)
+ remain -= seconds;
+
+ /*
+ * Sleep for any remaining time...
+ */
+
+ if (remain > 0 && !restart_polling)
+ sleep(remain);
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'dequote()' - Remote quotes from a string.
+ */
+
+static char * /* O - Dequoted string */
+dequote(char *d, /* I - Destination string */
+ const char *s, /* I - Source string */
+ int dlen) /* I - Destination length */
+{
+ char *dptr; /* Pointer into destination */
+
+
+ if (s)
+ {
+ for (dptr = d, dlen --; *s && dlen > 0; s ++)
+ if (*s != '\"')
+ {
+ *dptr++ = *s;
+ dlen --;
+ }
+
+ *dptr = '\0';
+ }
+ else
+ *d = '\0';
+
+ return (d);
+}
+
+
+/*
+ * 'poll_server()' - Poll the server for the given set of printers or classes.
+ */
+
+static int /* O - Number of seconds or -1 on error */
+poll_server(http_t *http, /* I - HTTP connection */
+ int sock, /* I - Broadcast sock */
+ int port, /* I - Broadcast port */
+ int interval, /* I - Polling interval */
+ const char *prefix) /* I - Prefix for log messages */
+{
+ int seconds; /* Number of seconds */
+ int count, /* Current number of printers/classes */
+ max_count; /* Maximum printers/classes per second */
+ ipp_t *request, /* Request data */
+ *response; /* Response data */
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *uri; /* printer-uri */
+ char info[1024], /* printer-info */
+ job_sheets[1024],/* job-sheets-default */
+ location[1024], /* printer-location */
+ make_model[1024];
+ /* printer-make-and-model */
+ cups_ptype_t type; /* printer-type */
+ ipp_pstate_t state; /* printer-state */
+ int accepting; /* printer-is-accepting-jobs */
+ struct sockaddr_in addr; /* Broadcast address */
+ char packet[1540]; /* Data packet */
+ static const char * const attrs[] = /* Requested attributes */
+ {
+ "job-sheets-default",
+ "printer-info",
+ "printer-is-accepting-jobs",
+ "printer-location",
+ "printer-make-and-model",
+ "printer-name",
+ "printer-state",
+ "printer-type",
+ "printer-uri-supported"
+ };
+
+
+ /*
+ * Broadcast to 127.0.0.1 (localhost)
+ */
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_addr.s_addr = htonl(0x7f000001);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+
+ /*
+ * Build a CUPS_GET_PRINTERS request and pass along a list of the
+ * attributes we are interested in along with the types of printers
+ * (and classes) we want.
+ */
+
+ request = ippNewRequest(CUPS_GET_PRINTERS);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(attrs) / sizeof(attrs[0]),
+ NULL, attrs);
+
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
+ "printer-type", 0);
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
+ "printer-type-mask",
+ CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_NOT_SHARED);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ seconds = time(NULL);
+ response = cupsDoRequest(http, request, "/");
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ fprintf(stderr, "ERROR: %s CUPS-Get-Printers failed: %s\n", prefix,
+ cupsLastErrorString());
+ ippDelete(response);
+ return (-1);
+ }
+
+ if (response)
+ {
+ /*
+ * Figure out how many printers/classes we have...
+ */
+
+ for (attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME),
+ max_count = 0;
+ attr != NULL;
+ attr = ippFindNextAttribute(response, "printer-name", IPP_TAG_NAME),
+ max_count ++);
+
+ fprintf(stderr, "DEBUG: %s Found %d printers.\n", prefix, max_count);
+
+ count = 0;
+ max_count = 2 * max_count / interval + 1;
+
+ /*
+ * Loop through the printers or classes returned in the list...
+ */
+
+ for (attr = response->attrs; attr; attr = attr->next)
+ {
+ /*
+ * Skip leading attributes until we hit a printer...
+ */
+
+ while (attr && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (!attr)
+ break;
+
+ /*
+ * Pull the needed attributes from this printer...
+ */
+
+ uri = NULL;
+ info[0] = '\0';
+ job_sheets[0] = '\0';
+ location[0] = '\0';
+ make_model[0] = '\0';
+ type = CUPS_PRINTER_REMOTE;
+ accepting = 1;
+ state = IPP_PRINTER_IDLE;
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
+ {
+ if (!strcmp(attr->name, "job-sheets-default") &&
+ (attr->value_tag == IPP_TAG_NAME ||
+ attr->value_tag == IPP_TAG_KEYWORD))
+ {
+ if (attr->num_values == 1)
+ snprintf(job_sheets, sizeof(job_sheets), " job-sheets=%s",
+ attr->values[0].string.text);
+ else
+ snprintf(job_sheets, sizeof(job_sheets), " job-sheets=%s,%s",
+ attr->values[0].string.text,
+ attr->values[1].string.text);
+ }
+ else if (!strcmp(attr->name, "printer-uri-supported") &&
+ attr->value_tag == IPP_TAG_URI)
+ uri = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "printer-info") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ dequote(info, attr->values[0].string.text, sizeof(info));
+ else if (!strcmp(attr->name, "printer-is-accepting-jobs") &&
+ attr->value_tag == IPP_TAG_BOOLEAN)
+ accepting = attr->values[0].boolean;
+ else if (!strcmp(attr->name, "printer-location") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ dequote(location, attr->values[0].string.text, sizeof(location));
+ else if (!strcmp(attr->name, "printer-make-and-model") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ dequote(make_model, attr->values[0].string.text, sizeof(location));
+ else if (!strcmp(attr->name, "printer-state") &&
+ attr->value_tag == IPP_TAG_ENUM)
+ state = (ipp_pstate_t)attr->values[0].integer;
+ else if (!strcmp(attr->name, "printer-type") &&
+ attr->value_tag == IPP_TAG_ENUM)
+ type = (cups_ptype_t)attr->values[0].integer;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (uri == NULL)
+ {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ /*
+ * Send the printer information...
+ */
+
+ type |= CUPS_PRINTER_REMOTE;
+
+ if (!accepting)
+ type |= CUPS_PRINTER_REJECTING;
+
+ snprintf(packet, sizeof(packet),
+ "%x %x %s \"%s\" \"%s\" \"%s\" lease-duration=%d%s\n",
+ type, state, uri, location, info, make_model, interval * 2,
+ job_sheets);
+
+ fprintf(stderr, "DEBUG2: %s Sending %s", prefix, packet);
+
+ if (sendto(sock, packet, strlen(packet), 0,
+ (struct sockaddr *)&addr, sizeof(addr)) <= 0)
+ {
+ ippDelete(response);
+ perror("cups-polld");
+ return (-1);
+ }
+
+ /*
+ * Throttle the local broadcasts as needed so that we don't
+ * overwhelm the local server...
+ */
+
+ count ++;
+ if (count >= max_count)
+ {
+ /*
+ * Sleep for a second...
+ */
+
+ count = 0;
+
+ sleep(1);
+ }
+
+ if (!attr || restart_polling)
+ break;
+ }
+
+ ippDelete(response);
+ }
+
+ /*
+ * Return the number of seconds we used...
+ */
+
+ return (time(NULL) - seconds);
+}
+
+
+/*
+ * 'sighup_handler()' - Handle 'hangup' signals to restart polling.
+ */
+
+static void
+sighup_handler(int sig) /* I - Signal number */
+{
+ (void)sig;
+
+ restart_polling = 1;
+
+#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
+ signal(SIGHUP, sighup_handler);
+#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/cups.sh.in b/scheduler/cups.sh.in
new file mode 100644
index 000000000..9215c6bef
--- /dev/null
+++ b/scheduler/cups.sh.in
@@ -0,0 +1,233 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Startup/shutdown script for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2007 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+#### OS-Dependent Information
+
+#
+# Linux chkconfig stuff:
+#
+# chkconfig: 235 99 00
+# description: Startup/shutdown script for 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
+
+#
+# Don't use TMPDIR environment variable from init script, as that can
+# cause cupsd to set TempDir to a user's temporary directory instead
+# of the default...
+#
+
+unset TMPDIR
+
+
+#
+# Make sure we have the standard program directories in the path
+# since some operating systems (this means YOU HP-UX!) don't
+# provide a standard path on boot-up...
+#
+
+if test "x$PATH" = x; then
+ PATH="/bin:/usr/bin:/sbin:/usr/sbin"
+else
+ PATH="/bin:/usr/bin:/sbin:/usr/sbin:$PATH"
+fi
+
+export PATH
+
+#
+# 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
+ ;;
+
+ start_msg)
+ # HP-UX non-standard...
+ echo "Starting CUPS Server"
+ ;;
+
+ stop_msg)
+ # HP-UX non-standard...
+ echo "Starting CUPS Server"
+ ;;
+
+ *)
+ echo "Usage: cups {reload|restart|start|status|stop}"
+ exit 1
+ ;;
+esac
+
+#
+# Exit with no errors.
+#
+
+exit 0
+
+
+#
+# End of "$Id$".
+#
diff --git a/scheduler/cups.xml.in b/scheduler/cups.xml.in
new file mode 100644
index 000000000..211c086b7
--- /dev/null
+++ b/scheduler/cups.xml.in
@@ -0,0 +1,214 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ $Id$
+
+ Service manifest for CUPS.
+
+ This service manifest introduces smf(5) services for CUPS. The services
+ described in this file are as follows:
+
+ svc:/application/cups/scheduler:default
+ svc:/application/cups/in-lpd:default
+
+ NOTE: This service manifest is not editable; its contents will be
+ overwritten by package or patch operations, including operating system
+ upgrade. Make customizations in a different file.
+
+ Norm.Jacobs@Sun.COM
+
+ CUPS data files in @datarootdir@...
+-->
+
+<service_bundle type='manifest' name='SUNWcups:services'>
+
+<service
+ name='application/cups/scheduler'
+ type='service'
+ version='1'>
+
+ <dependency
+ name='filesystem_minimal'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/minimal' />
+ </dependency>
+
+ <dependency
+ name='loopback'
+ grouping='optional_all'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/network/loopback' />
+ </dependency>
+
+
+ <dependency
+ name='network'
+ grouping='optional_all'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/milestone/network' />
+ </dependency>
+
+ <dependency
+ name='lpsched'
+ grouping='exclude_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/application/print/server' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='60' />
+
+ <instance name='default' enabled='false' >
+
+ <dependency
+ name='config_data'
+ grouping='require_all'
+ restart_on='none'
+ type='path'>
+ <service_fmri value='file://localhost@sysconfdir@/cups/cupsd.conf' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='@sbindir@/cupsd'
+ timeout_seconds='60' >
+ <method_context>
+ <method_credential user='root' group='@CUPS_GROUP@' />
+ </method_context>
+ </exec_method>
+
+ <property_group name='general' type='framework'>
+ <propval name='action_authorization' type='astring'
+ value='solaris.smf.manage.cups' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.value.cups' />
+ </property_group>
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ CUPS Print Spooler
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='cupsd' section='8'
+ manpath='@mandir@' />
+ </documentation>
+ </template>
+
+ </instance>
+
+ <stability value='Stable' />
+
+</service>
+
+<service
+ name='application/cups/in-lpd'
+ type='service'
+ version='1'>
+
+ <restarter>
+ <service_fmri value='svc:/network/inetd:default' />
+ </restarter>
+
+ <dependency
+ name='filesystem_minimal'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/minimal' />
+ </dependency>
+
+ <dependency
+ name='loopback'
+ grouping='require_any'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/network/loopback' />
+ </dependency>
+
+ <dependency
+ name='network'
+ grouping='optional_all'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/milestone/network' />
+ </dependency>
+
+ <dependency
+ name='in-lpd'
+ grouping='exclude_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/application/print/rfc1179' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='60' />
+
+ <instance name='default' enabled='false' >
+ <dependency
+ name='cupsd'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/application/cups/scheduler' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='inetd_start'
+ exec='@CUPS_SERVERBIN@/daemon/cups-lpd -o document-format=application/octet-stream'
+ timeout_seconds='0'>
+ <method_context>
+ <method_credential user='@CUPS_USER@' group='@CUPS_GROUP@' />
+ </method_context>
+ </exec_method>
+
+ <property_group name='inetd' type='framework'>
+ <stability value='Evolving' />
+ <propval name='endpoint_type' type='astring' value='stream' />
+ <propval name='name' type='astring' value='printer' />
+ <propval name='wait' type='boolean' value='false' />
+ <propval name='isrpc' type='boolean' value='false' />
+ <propval name='proto' type='astring' value='tcp6' />
+ </property_group>
+
+ <property_group name='general' type='framework'>
+ <propval name='action_authorization' type='astring'
+ value='solaris.smf.manage.cups' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.value.cups' />
+ </property_group>
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ CUPS Line Printer Daemon mini-server
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='cups-lpd' section='8'
+ manpath='@mandir@' />
+ </documentation>
+ </template>
+
+ </instance>
+
+ <stability value='Stable' />
+
+</service>
+
+</service_bundle>
diff --git a/scheduler/cupsd.h b/scheduler/cupsd.h
new file mode 100644
index 000000000..5d7229d55
--- /dev/null
+++ b/scheduler/cupsd.h
@@ -0,0 +1,248 @@
+/*
+ * "$Id$"
+ *
+ * Main header file for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+
+/*
+ * Include necessary headers.
+ */
+
+#include <cups/cups-private.h>
+#include <cups/file-private.h>
+
+#include <limits.h>
+#include <time.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#ifdef WIN32
+# include <direct.h>
+#else
+# include <unistd.h>
+#endif /* WIN32 */
+
+#include "mime.h"
+
+#if defined(HAVE_CDSASSL)
+# include <CoreFoundation/CoreFoundation.h>
+#endif /* HAVE_CDSASSL */
+
+
+/*
+ * Some OS's don't have hstrerror(), most notably Solaris...
+ */
+
+#ifndef HAVE_HSTRERROR
+# ifdef hstrerror
+# undef hstrerror
+# endif /* hstrerror */
+# define hstrerror cups_hstrerror
+
+extern const char *cups_hstrerror(int);
+#endif /* !HAVE_HSTRERROR */
+
+
+/*
+ * Common constants.
+ */
+
+#ifndef FALSE
+# define FALSE 0
+# define TRUE (!FALSE)
+#endif /* !FALSE */
+
+
+/*
+ * Implementation limits...
+ */
+
+#define MAX_ENV 100 /* Maximum number of environment strings */
+#define MAX_USERPASS 33 /* Maximum size of username/password */
+#define MAX_FILTERS 20 /* Maximum number of filters */
+#define MAX_SYSTEM_GROUPS 32 /* Maximum number of system groups */
+
+
+/*
+ * Defaults...
+ */
+
+#define DEFAULT_HISTORY 1 /* Preserve job history? */
+#define DEFAULT_FILES 0 /* Preserve job files? */
+#define DEFAULT_TIMEOUT 300 /* Timeout during requests/updates */
+#define DEFAULT_KEEPALIVE 30 /* Timeout between requests */
+#define DEFAULT_INTERVAL 30 /* Interval between browse updates */
+#define DEFAULT_CHARSET "utf-8" /* Default charset */
+
+
+/*
+ * Global variable macros...
+ */
+
+#ifdef _MAIN_C_
+# define VAR
+# define VALUE(x) =x
+# define VALUE2(x,y) ={x,y}
+#else
+# define VAR extern
+# define VALUE(x)
+# define VALUE2(x,y)
+#endif /* _MAIN_C */
+
+
+/*
+ * Other stuff for the scheduler...
+ */
+
+#include "sysman.h"
+#include "statbuf.h"
+#include "cert.h"
+#include "auth.h"
+#include "client.h"
+#include "policy.h"
+#include "printers.h"
+#include "classes.h"
+#include "job.h"
+#include "conf.h"
+#include "banners.h"
+#include "dirsvc.h"
+#include "network.h"
+#include "subscriptions.h"
+
+
+/*
+ * Reload types...
+ */
+
+#define RELOAD_NONE 0 /* No reload needed */
+#define RELOAD_ALL 1 /* Reload everything */
+#define RELOAD_CUPSD 2 /* Reload only cupsd.conf */
+
+
+/*
+ * Select callback function type...
+ */
+
+typedef void (*cupsd_selfunc_t)(void *data);
+
+
+/*
+ * Globals...
+ */
+
+VAR int TestConfigFile VALUE(0),
+ /* Test the cupsd.conf file? */
+ UseProfiles VALUE(1);
+ /* Use security profiles for child procs? */
+VAR int MaxFDs VALUE(0);
+ /* Maximum number of files */
+
+VAR time_t ReloadTime VALUE(0);
+ /* Time of reload request... */
+VAR int NeedReload VALUE(RELOAD_ALL),
+ /* Need to load configuration? */
+ DoingShutdown VALUE(0);
+ /* Shutting down the scheduler? */
+VAR void *DefaultProfile VALUE(0);
+ /* Default security profile */
+
+#ifdef HAVE_GSSAPI
+VAR int KerberosInitialized VALUE(0);
+ /* Has Kerberos been initialized? */
+VAR krb5_context KerberosContext VALUE(NULL);
+ /* Kerberos context for credentials */
+#endif /* HAVE_GSSAPI */
+
+#ifdef HAVE_LAUNCH_H
+VAR int Launchd VALUE(0);
+ /* Running from launchd */
+#endif /* HAVE_LAUNCH_H */
+
+
+/*
+ * Prototypes...
+ */
+
+/* env.c */
+extern void cupsdInitEnv(void);
+extern int cupsdLoadEnv(char *envp[], int envmax);
+extern void cupsdSetEnv(const char *name, const char *value);
+extern void cupsdSetEnvf(const char *name, const char *value, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+#endif /* __GNUC__ */
+;
+extern void cupsdUpdateEnv(void);
+
+/* file.c */
+extern void cupsdCleanFiles(const char *path, const char *pattern);
+extern int cupsdCloseCreatedConfFile(cups_file_t *fp,
+ const char *filename);
+extern void cupsdClosePipe(int *fds);
+extern cups_file_t *cupsdCreateConfFile(const char *filename, mode_t mode);
+extern cups_file_t *cupsdOpenConfFile(const char *filename);
+extern int cupsdOpenPipe(int *fds);
+extern int cupsdRemoveFile(const char *filename);
+
+/* main.c */
+extern int cupsdAddString(cups_array_t **a, const char *s);
+extern void cupsdCheckProcess(void);
+extern void cupsdClearString(char **s);
+extern void cupsdFreeStrings(cups_array_t **a);
+extern void cupsdHoldSignals(void);
+extern char *cupsdMakeUUID(const char *name, int number,
+ char *buffer, size_t bufsize);
+extern void cupsdReleaseSignals(void);
+extern void cupsdSetString(char **s, const char *v);
+extern void cupsdSetStringf(char **s, const char *f, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+#endif /* __GNUC__ */
+;
+
+/* process.c */
+extern void *cupsdCreateProfile(int job_id);
+extern void cupsdDestroyProfile(void *profile);
+extern int cupsdEndProcess(int pid, int force);
+extern const char *cupsdFinishProcess(int pid, char *name, int namelen,
+ int *job_id);
+extern int cupsdStartProcess(const char *command, char *argv[],
+ char *envp[], int infd, int outfd,
+ int errfd, int backfd, int sidefd,
+ int root, void *profile,
+ cupsd_job_t *job, int *pid);
+
+/* select.c */
+extern int cupsdAddSelect(int fd, cupsd_selfunc_t read_cb,
+ cupsd_selfunc_t write_cb, void *data);
+extern int cupsdDoSelect(long timeout);
+#ifdef CUPSD_IS_SELECTING
+extern int cupsdIsSelecting(int fd);
+#endif /* CUPSD_IS_SELECTING */
+extern void cupsdRemoveSelect(int fd);
+extern void cupsdStartSelect(void);
+extern void cupsdStopSelect(void);
+
+/* server.c */
+extern void cupsdStartServer(void);
+extern void cupsdStopServer(void);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/cupsfilter.c b/scheduler/cupsfilter.c
new file mode 100644
index 000000000..ea10c3ac2
--- /dev/null
+++ b/scheduler/cupsfilter.c
@@ -0,0 +1,1497 @@
+/*
+ * "$Id$"
+ *
+ * Filtering program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Main entry for the test program.
+ * add_printer_filter() - Add a single filters from a PPD file.
+ * add_printer_filters() - Add filters from a PPD file.
+ * check_cb() - Callback function for _cupsFileCheck.
+ * compare_pids() - Compare two filter PIDs...
+ * escape_options() - Convert an options array to a string.
+ * exec_filter() - Execute a single filter.
+ * exec_filters() - Execute filters for the given file and options.
+ * get_job_file() - Get the specified job file.
+ * open_pipe() - Create a pipe which is closed on exec.
+ * read_cupsd_conf() - Read the cupsd.conf file to get the filter
+ * settings.
+ * set_string() - Copy and set a string.
+ * sighandler() - Signal catcher for when we print from stdin...
+ * usage() - Show program usage...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include <cups/file-private.h>
+#include <cups/ppd-private.h>
+#include "mime.h"
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/wait.h>
+#if defined(__APPLE__)
+# include <libgen.h>
+#endif /* __APPLE__ */
+
+
+/*
+ * Local globals...
+ */
+
+static char *DataDir = NULL;/* CUPS_DATADIR environment variable */
+static char *FontPath = NULL;
+ /* CUPS_FONTPATH environment variable */
+static mime_filter_t GZIPFilter = /* gziptoany filter */
+{
+ NULL, /* Source type */
+ NULL, /* Destination type */
+ 0, /* Cost */
+ "gziptoany" /* Filter program to run */
+};
+static char *Path = NULL; /* PATH environment variable */
+static char *ServerBin = NULL;
+ /* CUPS_SERVERBIN environment variable */
+static char *ServerRoot = NULL;
+ /* CUPS_SERVERROOT environment variable */
+static char *RIPCache = NULL;
+ /* RIP_MAX_CACHE environment variable */
+static char TempFile[1024] = "";
+ /* Temporary file */
+
+
+/*
+ * Local functions...
+ */
+
+static void add_printer_filter(const char *command, mime_t *mime,
+ mime_type_t *printer_type,
+ const char *filter);
+static mime_type_t *add_printer_filters(const char *command,
+ mime_t *mime, const char *printer,
+ const char *ppdfile,
+ mime_type_t **prefilter_type);
+static void check_cb(void *context, _cups_fc_result_t result,
+ const char *message);
+static int compare_pids(mime_filter_t *a, mime_filter_t *b);
+static char *escape_options(int num_options, cups_option_t *options);
+static int exec_filter(const char *filter, char **argv,
+ char **envp, int infd, int outfd);
+static int exec_filters(mime_type_t *srctype,
+ cups_array_t *filters, const char *infile,
+ const char *outfile, const char *ppdfile,
+ const char *printer, const char *user,
+ const char *title, int num_options,
+ cups_option_t *options);
+static void get_job_file(const char *job);
+static int open_pipe(int *fds);
+static int read_cupsd_conf(const char *filename);
+static void set_string(char **s, const char *val);
+static void sighandler(int sig);
+static void usage(const char *command, const char *opt);
+
+
+/*
+ * 'main()' - Main entry for the test program.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping vars */
+ const char *command, /* Command name */
+ *opt, /* Current option */
+ *printer; /* Printer name */
+ mime_type_t *printer_type, /* Printer MIME type */
+ *prefilter_type; /* Printer prefilter MIME type */
+ char *srctype, /* Source type */
+ *dsttype, /* Destination type */
+ super[MIME_MAX_SUPER], /* Super-type name */
+ type[MIME_MAX_TYPE]; /* Type name */
+ int compression; /* Compression of file */
+ int cost; /* Cost of filters */
+ mime_t *mime; /* MIME database */
+ char mimedir[1024]; /* MIME directory */
+ char *infile, /* File to filter */
+ *outfile; /* File to create */
+ char cupsdconf[1024]; /* cupsd.conf file */
+ const char *server_root; /* CUPS_SERVERROOT environment variable */
+ mime_type_t *src, /* Source type */
+ *dst; /* Destination type */
+ cups_array_t *filters; /* Filters for the file */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ const char *ppdfile; /* PPD file */
+ const char *title, /* Title string */
+ *user; /* Username */
+ int all_filters, /* Use all filters */
+ removeppd, /* Remove PPD file */
+ removeinfile; /* Remove input file */
+ int status; /* Execution status */
+
+
+ /*
+ * Setup defaults...
+ */
+
+ if ((command = strrchr(argv[0], '/')) != NULL)
+ command ++;
+ else
+ command = argv[0];
+
+ printer = !strcmp(command, "convert") ? "tofile" : "cupsfilter";
+ mime = NULL;
+ srctype = NULL;
+ compression = 0;
+ dsttype = "application/pdf";
+ infile = NULL;
+ outfile = NULL;
+ num_options = 0;
+ options = NULL;
+ ppdfile = NULL;
+ title = NULL;
+ user = cupsUser();
+ all_filters = 0;
+ removeppd = 0;
+ removeinfile = 0;
+
+ if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
+ server_root = CUPS_SERVERROOT;
+
+ snprintf(cupsdconf, sizeof(cupsdconf), "%s/cupsd.conf", server_root);
+
+ /*
+ * Process command-line arguments...
+ */
+
+ _cupsSetLocale(argv);
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ {
+ for (opt = argv[i] + 1; *opt; opt ++)
+ switch (*opt)
+ {
+ case '-' : /* Next argument is a filename... */
+ i ++;
+ if (i < argc && !infile)
+ infile = argv[i];
+ else
+ usage(command, opt);
+ break;
+
+ case 'a' : /* Specify option... */
+ i ++;
+ if (i < argc)
+ num_options = cupsParseOptions(argv[i], num_options, &options);
+ else
+ usage(command, opt);
+ break;
+
+ case 'c' : /* Specify cupsd.conf file location... */
+ i ++;
+ if (i < argc)
+ {
+ if (!strcmp(command, "convert"))
+ num_options = cupsAddOption("copies", argv[i], num_options,
+ &options);
+ else
+ strlcpy(cupsdconf, argv[i], sizeof(cupsdconf));
+ }
+ else
+ usage(command, opt);
+ break;
+
+ case 'd' : /* Specify the real printer name */
+ i ++;
+ if (i < argc)
+ printer = argv[i];
+ else
+ usage(command, opt);
+ break;
+
+ case 'D' : /* Delete input file after conversion */
+ removeinfile = 1;
+ break;
+
+ case 'e' : /* Use every filter from the PPD file */
+ all_filters = 1;
+ break;
+
+ case 'f' : /* Specify input file... */
+ i ++;
+ if (i < argc && !infile)
+ infile = argv[i];
+ else
+ usage(command, opt);
+ break;
+
+ case 'i' : /* Specify source MIME type... */
+ i ++;
+ if (i < argc)
+ {
+ if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
+ usage(command, opt);
+
+ srctype = argv[i];
+ }
+ else
+ usage(command, opt);
+ break;
+
+ case 'j' : /* Get job file or specify destination MIME type... */
+ if (strcmp(command, "convert"))
+ {
+ i ++;
+ if (i < argc)
+ {
+ get_job_file(argv[i]);
+ infile = TempFile;
+ }
+ else
+ usage(command, opt);
+
+ break;
+ }
+
+ case 'm' : /* Specify destination MIME type... */
+ i ++;
+ if (i < argc)
+ {
+ if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
+ usage(command, opt);
+
+ dsttype = argv[i];
+ }
+ else
+ usage(command, opt);
+ break;
+
+ case 'n' : /* Specify number of copies... */
+ i ++;
+ if (i < argc)
+ num_options = cupsAddOption("copies", argv[i], num_options,
+ &options);
+ else
+ usage(command, opt);
+ break;
+
+ case 'o' : /* Specify option(s) or output filename */
+ i ++;
+ if (i < argc)
+ {
+ if (!strcmp(command, "convert"))
+ {
+ if (outfile)
+ usage(command, NULL);
+ else
+ outfile = argv[i];
+ }
+ else
+ num_options = cupsParseOptions(argv[i], num_options,
+ &options);
+ }
+ else
+ usage(command, opt);
+ break;
+
+ case 'p' : /* Specify PPD file... */
+ case 'P' : /* Specify PPD file... */
+ i ++;
+ if (i < argc)
+ ppdfile = argv[i];
+ else
+ usage(command, opt);
+ break;
+
+ case 't' : /* Specify title... */
+ case 'J' : /* Specify title... */
+ i ++;
+ if (i < argc)
+ title = argv[i];
+ else
+ usage(command, opt);
+ break;
+
+ case 'u' : /* Delete PPD file after conversion */
+ removeinfile = 1;
+ break;
+
+ case 'U' : /* Specify username... */
+ i ++;
+ if (i < argc)
+ user = argv[i];
+ else
+ usage(command, opt);
+ break;
+
+ default : /* Something we don't understand... */
+ usage(command, opt);
+ break;
+ }
+ }
+ else if (!infile)
+ {
+ if (strcmp(command, "convert"))
+ infile = argv[i];
+ else
+ {
+ _cupsLangPuts(stderr,
+ _("convert: Use the -f option to specify a file to "
+ "convert."));
+ usage(command, NULL);
+ }
+ }
+ else
+ {
+ _cupsLangPuts(stderr,
+ _("cupsfilter: Only one filename can be specified."));
+ usage(command, NULL);
+ }
+
+ if (!infile && !srctype)
+ usage(command, NULL);
+
+ if (!title)
+ {
+ if (!infile)
+ title = "(stdin)";
+ else if ((title = strrchr(infile, '/')) != NULL)
+ title ++;
+ else
+ title = infile;
+ }
+
+ /*
+ * Load the cupsd.conf file and create the MIME database...
+ */
+
+ if (read_cupsd_conf(cupsdconf))
+ return (1);
+
+ snprintf(mimedir, sizeof(mimedir), "%s/mime", DataDir);
+
+ mime = mimeLoadTypes(NULL, mimedir);
+ mime = mimeLoadTypes(mime, ServerRoot);
+ mime = mimeLoadFilters(mime, mimedir, Path);
+ mime = mimeLoadFilters(mime, ServerRoot, Path);
+
+ if (!mime)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Unable to read MIME database from \"%s\" or "
+ "\"%s\"."),
+ command, mimedir, ServerRoot);
+ return (1);
+ }
+
+ if (all_filters)
+ {
+ printer_type = add_printer_filters(command, mime, printer, ppdfile,
+ &prefilter_type);
+ }
+ else
+ {
+ printer_type = mimeType(mime, "application", "vnd.cups-postscript");
+ prefilter_type = NULL;
+ }
+
+ /*
+ * Get the source and destination types...
+ */
+
+ if (srctype)
+ {
+ sscanf(srctype, "%15[^/]/%255s", super, type);
+ if ((src = mimeType(mime, super, type)) == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Unknown source MIME type %s/%s."),
+ command, super, type);
+ return (1);
+ }
+ }
+ else if ((src = mimeFileType(mime, infile, infile, &compression)) == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Unable to determine MIME type of \"%s\"."),
+ command, infile);
+ return (1);
+ }
+
+ sscanf(dsttype, "%15[^/]/%255s", super, type);
+ if (!_cups_strcasecmp(super, "printer"))
+ dst = printer_type;
+ else if ((dst = mimeType(mime, super, type)) == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Unknown destination MIME type %s/%s."),
+ command, super, type);
+ return (1);
+ }
+
+ /*
+ * Figure out how to filter the file...
+ */
+
+ if (src == dst)
+ {
+ /*
+ * Special case - no filtering needed...
+ */
+
+ filters = cupsArrayNew(NULL, NULL);
+ cupsArrayAdd(filters, &GZIPFilter);
+ GZIPFilter.src = src;
+ GZIPFilter.dst = dst;
+ }
+ else if ((filters = mimeFilter(mime, src, dst, &cost)) == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: No filter to convert from %s/%s to %s/%s."),
+ command, src->super, src->type, dst->super, dst->type);
+ return (1);
+ }
+ else if (compression)
+ cupsArrayInsert(filters, &GZIPFilter);
+
+ if (prefilter_type)
+ {
+ /*
+ * Add pre-filters...
+ */
+
+ mime_filter_t *filter, /* Current filter */
+ *prefilter; /* Current pre-filter */
+ cups_array_t *prefilters = cupsArrayNew(NULL, NULL);
+ /* New filters array */
+
+
+ for (filter = (mime_filter_t *)cupsArrayFirst(filters);
+ filter;
+ filter = (mime_filter_t *)cupsArrayNext(filters))
+ {
+ if ((prefilter = mimeFilterLookup(mime, filter->src,
+ prefilter_type)) != NULL)
+ cupsArrayAdd(prefilters, prefilter);
+
+ cupsArrayAdd(prefilters, filter);
+ }
+
+ cupsArrayDelete(filters);
+ filters = prefilters;
+ }
+
+ /*
+ * Do it!
+ */
+
+ status = exec_filters(src, filters, infile, outfile, ppdfile, printer, user,
+ title, num_options, options);
+
+ /*
+ * Remove files as needed, then exit...
+ */
+
+ if (TempFile[0])
+ unlink(TempFile);
+
+ if (removeppd && ppdfile)
+ unlink(ppdfile);
+
+ if (removeinfile && infile)
+ unlink(infile);
+
+ return (status);
+}
+
+
+/*
+ * 'add_printer_filter()' - Add a single filters from a PPD file.
+ */
+
+static void
+add_printer_filter(
+ const char *command, /* I - Command name */
+ mime_t *mime, /* I - MIME database */
+ mime_type_t *filtertype, /* I - Printer or prefilter MIME type */
+ const char *filter) /* I - Filter to add */
+{
+ char super[MIME_MAX_SUPER], /* Super-type for filter */
+ type[MIME_MAX_TYPE], /* Type for filter */
+ dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */
+ dtype[MIME_MAX_TYPE], /* Destination type for filter */
+ dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2],
+ /* Destination super/type */
+ program[1024]; /* Program/filter name */
+ int cost; /* Cost of filter */
+ size_t maxsize = 0; /* Maximum supported file size */
+ mime_type_t *temptype, /* MIME type looping var */
+ *desttype; /* Destination MIME type */
+ mime_filter_t *filterptr; /* MIME filter */
+
+
+ /*
+ * Parse the filter string; it should be in one of the following formats:
+ *
+ * source/type cost program
+ * source/type cost maxsize(nnnn) program
+ * source/type dest/type cost program
+ * source/type dest/type cost maxsize(nnnn) program
+ */
+
+ if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
+ super, type, dsuper, dtype, &cost, program) == 6)
+ {
+ snprintf(dest, sizeof(dest), "%s/%s/%s", filtertype->type, dsuper, dtype);
+
+ if ((desttype = mimeType(mime, "printer", dest)) == NULL)
+ desttype = mimeAddType(mime, "printer", dest);
+ }
+ else
+ {
+ if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost,
+ program) == 4)
+ {
+ desttype = filtertype;
+ }
+ else
+ {
+ _cupsLangPrintf(stderr, _("%s: Invalid filter string \"%s\"."), command,
+ filter);
+ return;
+ }
+ }
+
+ if (!strncmp(program, "maxsize(", 8))
+ {
+ char *ptr; /* Pointer into maxsize(nnnn) program */
+
+ maxsize = strtoll(program + 8, &ptr, 10);
+
+ if (*ptr != ')')
+ {
+ printf("testmime: Invalid filter string \"%s\".\n", filter);
+ return;
+ }
+
+ ptr ++;
+ while (_cups_isspace(*ptr))
+ ptr ++;
+
+ _cups_strcpy(program, ptr);
+ }
+
+ /*
+ * See if the filter program exists; if not, stop the printer and flag
+ * the error!
+ */
+
+ if (strcmp(program, "-"))
+ {
+ char filename[1024]; /* Full path to program */
+
+ if (program[0] == '/')
+ strlcpy(filename, program, sizeof(filename));
+ else
+ snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program);
+
+ if (_cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !geteuid(), check_cb,
+ (void *)command))
+ return;
+ }
+
+ /*
+ * Add the filter to the MIME database, supporting wildcards as needed...
+ */
+
+ for (temptype = mimeFirstType(mime);
+ temptype;
+ temptype = mimeNextType(mime))
+ if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) ||
+ !_cups_strcasecmp(temptype->super, super)) &&
+ (type[0] == '*' || !_cups_strcasecmp(temptype->type, type)))
+ {
+ if (desttype != filtertype)
+ {
+ filterptr = mimeAddFilter(mime, temptype, desttype, cost, program);
+
+ if (!mimeFilterLookup(mime, desttype, filtertype))
+ mimeAddFilter(mime, desttype, filtertype, cost, "-");
+ }
+ else
+ filterptr = mimeAddFilter(mime, temptype, filtertype, cost, program);
+
+ if (filterptr)
+ filterptr->maxsize = maxsize;
+ }
+}
+
+
+/*
+ * 'add_printer_filters()' - Add filters from a PPD file.
+ */
+
+static mime_type_t * /* O - Printer type or NULL on error */
+add_printer_filters(
+ const char *command, /* I - Command name */
+ mime_t *mime, /* I - MIME database */
+ const char *printer, /* I - Printer name */
+ const char *ppdfile, /* I - PPD file */
+ mime_type_t **prefilter_type) /* O - Prefilter type */
+{
+ ppd_file_t *ppd; /* PPD file data */
+ _ppd_cache_t *pc; /* Cache data for PPD */
+ const char *value; /* Filter definition value */
+ mime_type_t *printer_type; /* Printer filter type */
+
+
+ if ((ppd = ppdOpenFile(ppdfile)) == NULL)
+ {
+ ppd_status_t status; /* PPD load status */
+ int linenum; /* Line number */
+
+ status = ppdLastError(&linenum);
+ _cupsLangPrintf(stderr, _("%s: Unable to open PPD file: %s on line %d."),
+ command, ppdErrorString(status), linenum);
+ return (NULL);
+ }
+
+ pc = _ppdCacheCreateWithPPD(ppd);
+ if (!pc)
+ return (NULL);
+
+ printer_type = mimeAddType(mime, "printer", printer);
+ *prefilter_type = NULL;
+
+ if (pc->filters)
+ {
+ for (value = (const char *)cupsArrayFirst(pc->filters);
+ value;
+ value = (const char *)cupsArrayNext(pc->filters))
+ add_printer_filter(command, mime, printer_type, value);
+ }
+ else
+ {
+ add_printer_filter(command, mime, printer_type,
+ "application/vnd.cups-raw 0 -");
+ add_printer_filter(command, mime, printer_type,
+ "application/vnd.cups-postscript 0 -");
+ }
+
+ if (pc->prefilters)
+ {
+ *prefilter_type = mimeAddType(mime, "prefilter", printer);
+
+ for (value = (const char *)cupsArrayFirst(pc->prefilters);
+ value;
+ value = (const char *)cupsArrayNext(pc->prefilters))
+ add_printer_filter(command, mime, *prefilter_type, value);
+ }
+
+ return (printer_type);
+}
+
+
+/*
+ * 'check_cb()' - Callback function for _cupsFileCheck.
+ */
+
+static void
+check_cb(void *context, /* I - Context (command name) */
+ _cups_fc_result_t result, /* I - Result of check */
+ const char *message) /* I - Localized message */
+{
+ (void)result;
+
+ _cupsLangPrintf(stderr, _("%s: %s"), (char *)context, message);
+}
+
+
+/*
+ * 'compare_pids()' - Compare two filter PIDs...
+ */
+
+static int /* O - Result of comparison */
+compare_pids(mime_filter_t *a, /* I - First filter */
+ mime_filter_t *b) /* I - Second filter */
+{
+ /*
+ * Because we're particularly lazy, we store the process ID in the "cost"
+ * variable...
+ */
+
+ return (a->cost - b->cost);
+}
+
+
+/*
+ * 'escape_options()' - Convert an options array to a string.
+ */
+
+static char * /* O - Option string */
+escape_options(
+ int num_options, /* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ int i; /* Looping var */
+ cups_option_t *option; /* Current option */
+ int bytes; /* Number of bytes needed */
+ char *s, /* Option string */
+ *sptr, /* Pointer into string */
+ *vptr; /* Pointer into value */
+
+
+ /*
+ * Figure out the worst-case number of bytes we need for the option string.
+ */
+
+ for (i = num_options, option = options, bytes = 1; i > 0; i --, option ++)
+ bytes += 2 * (strlen(option->name) + strlen(option->value)) + 2;
+
+ if ((s = malloc(bytes)) == NULL)
+ return (NULL);
+
+ /*
+ * Copy the options to the string...
+ */
+
+ for (i = num_options, option = options, sptr = s; i > 0; i --, option ++)
+ {
+ if (!strcmp(option->name, "copies"))
+ continue;
+
+ if (sptr > s)
+ *sptr++ = ' ';
+
+ strcpy(sptr, option->name);
+ sptr += strlen(sptr);
+ *sptr++ = '=';
+
+ for (vptr = option->value; *vptr;)
+ {
+ if (strchr("\\ \t\n", *vptr))
+ *sptr++ = '\\';
+
+ *sptr++ = *vptr++;
+ }
+ }
+
+ *sptr = '\0';
+
+ return (s);
+}
+
+
+/*
+ * 'exec_filter()' - Execute a single filter.
+ */
+
+static int /* O - Process ID or -1 on error */
+exec_filter(const char *filter, /* I - Filter to execute */
+ char **argv, /* I - Argument list */
+ char **envp, /* I - Environment list */
+ int infd, /* I - Stdin file descriptor */
+ int outfd) /* I - Stdout file descriptor */
+{
+ int pid, /* Process ID */
+ fd; /* Temporary file descriptor */
+#if defined(__APPLE__)
+ char processPath[1024], /* CFProcessPath environment variable */
+ linkpath[1024]; /* Link path for symlinks... */
+ int linkbytes; /* Bytes for link path */
+
+
+ /*
+ * Add special voodoo magic for MacOS X - this allows MacOS X
+ * programs to access their bundle resources properly...
+ */
+
+ if ((linkbytes = readlink(filter, linkpath, sizeof(linkpath) - 1)) > 0)
+ {
+ /*
+ * Yes, this is a symlink to the actual program, nul-terminate and
+ * use it...
+ */
+
+ linkpath[linkbytes] = '\0';
+
+ if (linkpath[0] == '/')
+ snprintf(processPath, sizeof(processPath), "CFProcessPath=%s",
+ linkpath);
+ else
+ snprintf(processPath, sizeof(processPath), "CFProcessPath=%s/%s",
+ dirname((char *)filter), linkpath);
+ }
+ else
+ snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", filter);
+
+ envp[0] = processPath; /* Replace <CFProcessPath> string */
+#endif /* __APPLE__ */
+
+ if ((pid = fork()) == 0)
+ {
+ /*
+ * Child process goes here...
+ *
+ * Update stdin/stdout/stderr as needed...
+ */
+
+ if (infd != 0)
+ {
+ if (infd < 0)
+ infd = open("/dev/null", O_RDONLY);
+
+ if (infd > 0)
+ {
+ dup2(infd, 0);
+ close(infd);
+ }
+ }
+
+ if (outfd != 1)
+ {
+ if (outfd < 0)
+ outfd = open("/dev/null", O_WRONLY);
+
+ if (outfd > 1)
+ {
+ dup2(outfd, 1);
+ close(outfd);
+ }
+ }
+
+ if ((fd = open("/dev/null", O_RDWR)) > 3)
+ {
+ dup2(fd, 3);
+ close(fd);
+ }
+ fcntl(3, F_SETFL, O_NDELAY);
+
+ if ((fd = open("/dev/null", O_RDWR)) > 4)
+ {
+ dup2(fd, 4);
+ close(fd);
+ }
+ fcntl(4, F_SETFL, O_NDELAY);
+
+ /*
+ * Execute command...
+ */
+
+ execve(filter, argv, envp);
+
+ perror(filter);
+
+ exit(errno);
+ }
+
+ return (pid);
+}
+
+
+/*
+ * 'exec_filters()' - Execute filters for the given file and options.
+ */
+
+static int /* O - 0 on success, 1 on error */
+exec_filters(mime_type_t *srctype, /* I - Source type */
+ cups_array_t *filters, /* I - Array of filters to run */
+ const char *infile, /* I - File to filter */
+ const char *outfile, /* I - File to create */
+ const char *ppdfile, /* I - PPD file, if any */
+ const char *printer, /* I - Printer name */
+ const char *user, /* I - Username */
+ const char *title, /* I - Job title */
+ int num_options, /* I - Number of filter options */
+ cups_option_t *options) /* I - Filter options */
+{
+ int i; /* Looping var */
+ const char *argv[8], /* Command-line arguments */
+ *envp[15], /* Environment variables */
+ *temp; /* Temporary string */
+ char *optstr, /* Filter options */
+ content_type[1024], /* CONTENT_TYPE */
+ cups_datadir[1024], /* CUPS_DATADIR */
+ cups_fontpath[1024], /* CUPS_FONTPATH */
+ cups_serverbin[1024], /* CUPS_SERVERBIN */
+ cups_serverroot[1024], /* CUPS_SERVERROOT */
+ lang[1024], /* LANG */
+ path[1024], /* PATH */
+ ppd[1024], /* PPD */
+ printer_info[255], /* PRINTER_INFO env variable */
+ printer_location[255], /* PRINTER_LOCATION env variable */
+ printer_name[255], /* PRINTER env variable */
+ rip_max_cache[1024], /* RIP_MAX_CACHE */
+ userenv[1024], /* USER */
+ program[1024]; /* Program to run */
+ mime_filter_t *filter, /* Current filter */
+ *next; /* Next filter */
+ int current, /* Current filter */
+ filterfds[2][2], /* Pipes for filters */
+ pid, /* Process ID of filter */
+ status, /* Exit status */
+ retval; /* Return value */
+ cups_array_t *pids; /* Executed filters array */
+ mime_filter_t key; /* Search key for filters */
+ cups_lang_t *language; /* Current language */
+ cups_dest_t *dest; /* Destination information */
+
+
+ /*
+ * Setup the filter environment and command-line...
+ */
+
+ optstr = escape_options(num_options, options);
+
+ snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s",
+ srctype->super, srctype->type);
+ snprintf(cups_datadir, sizeof(cups_datadir), "CUPS_DATADIR=%s", DataDir);
+ snprintf(cups_fontpath, sizeof(cups_fontpath), "CUPS_FONTPATH=%s", FontPath);
+ snprintf(cups_serverbin, sizeof(cups_serverbin), "CUPS_SERVERBIN=%s",
+ ServerBin);
+ snprintf(cups_serverroot, sizeof(cups_serverroot), "CUPS_SERVERROOT=%s",
+ ServerRoot);
+ language = cupsLangDefault();
+ snprintf(lang, sizeof(lang), "LANG=%s.UTF8", language->language);
+ snprintf(path, sizeof(path), "PATH=%s", Path);
+ if (ppdfile)
+ snprintf(ppd, sizeof(ppd), "PPD=%s", ppdfile);
+ else if ((temp = getenv("PPD")) != NULL)
+ snprintf(ppd, sizeof(ppd), "PPD=%s", temp);
+ else
+#ifdef __APPLE__
+ if (!access("/System/Library/Frameworks/ApplicationServices.framework/"
+ "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
+ "Resources/English.lproj/Generic.ppd", 0))
+ strlcpy(ppd, "PPD=/System/Library/Frameworks/ApplicationServices.framework/"
+ "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
+ "Resources/English.lproj/Generic.ppd", sizeof(ppd));
+ else
+ strlcpy(ppd, "PPD=/System/Library/Frameworks/ApplicationServices.framework/"
+ "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
+ "Resources/Generic.ppd", sizeof(ppd));
+#else
+ snprintf(ppd, sizeof(ppd), "PPD=%s/model/laserjet.ppd", DataDir);
+#endif /* __APPLE__ */
+ snprintf(rip_max_cache, sizeof(rip_max_cache), "RIP_MAX_CACHE=%s", RIPCache);
+ snprintf(userenv, sizeof(userenv), "USER=%s", user);
+
+ if (printer &&
+ (dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, printer, NULL)) != NULL)
+ {
+ if ((temp = cupsGetOption("printer-info", dest->num_options,
+ dest->options)) != NULL)
+ snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s", temp);
+ else
+ snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s", printer);
+
+ if ((temp = cupsGetOption("printer-location", dest->num_options,
+ dest->options)) != NULL)
+ snprintf(printer_location, sizeof(printer_location),
+ "PRINTER_LOCATION=%s", temp);
+ else
+ strlcpy(printer_location, "PRINTER_LOCATION=Unknown",
+ sizeof(printer_location));
+ }
+ else
+ {
+ snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s",
+ printer ? printer : "Unknown");
+ strlcpy(printer_location, "PRINTER_LOCATION=Unknown",
+ sizeof(printer_location));
+ }
+
+ snprintf(printer_name, sizeof(printer_name), "PRINTER=%s",
+ printer ? printer : "Unknown");
+
+ argv[0] = (char *)printer;
+ argv[1] = "1";
+ argv[2] = user;
+ argv[3] = title;
+ argv[4] = cupsGetOption("copies", num_options, options);
+ argv[5] = optstr;
+ argv[6] = infile;
+ argv[7] = NULL;
+
+ if (!argv[4])
+ argv[4] = "1";
+
+ envp[0] = "<CFProcessPath>";
+ envp[1] = content_type;
+ envp[2] = cups_datadir;
+ envp[3] = cups_fontpath;
+ envp[4] = cups_serverbin;
+ envp[5] = cups_serverroot;
+ envp[6] = lang;
+ envp[7] = path;
+ envp[8] = ppd;
+ envp[9] = printer_info;
+ envp[10] = printer_location;
+ envp[11] = printer_name;
+ envp[12] = rip_max_cache;
+ envp[13] = userenv;
+ envp[14] = NULL;
+
+ for (i = 0; argv[i]; i ++)
+ fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);
+
+ for (i = 0; envp[i]; i ++)
+ fprintf(stderr, "DEBUG: envp[%d]=\"%s\"\n", i, envp[i]);
+
+ /*
+ * Execute all of the filters...
+ */
+
+ pids = cupsArrayNew((cups_array_func_t)compare_pids, NULL);
+ current = 0;
+ filterfds[0][0] = -1;
+ filterfds[0][1] = -1;
+ filterfds[1][0] = -1;
+ filterfds[1][1] = -1;
+
+ if (!infile)
+ filterfds[0][0] = 0;
+
+ for (filter = (mime_filter_t *)cupsArrayFirst(filters);
+ filter;
+ filter = next, current = 1 - current)
+ {
+ next = (mime_filter_t *)cupsArrayNext(filters);
+
+ if (filter->filter[0] == '/')
+ strlcpy(program, filter->filter, sizeof(program));
+ else
+ snprintf(program, sizeof(program), "%s/filter/%s", ServerBin,
+ filter->filter);
+
+ if (filterfds[!current][1] > 1)
+ {
+ close(filterfds[1 - current][0]);
+ close(filterfds[1 - current][1]);
+
+ filterfds[1 - current][0] = -1;
+ filterfds[1 - current][0] = -1;
+ }
+
+ if (next)
+ open_pipe(filterfds[1 - current]);
+ else if (outfile)
+ {
+ filterfds[1 - current][1] = open(outfile, O_CREAT | O_TRUNC | O_WRONLY,
+ 0666);
+
+ if (filterfds[1 - current][1] < 0)
+ fprintf(stderr, "ERROR: Unable to create \"%s\" - %s\n", outfile,
+ strerror(errno));
+ }
+ else
+ filterfds[1 - current][1] = 1;
+
+ pid = exec_filter(program, (char **)argv, (char **)envp,
+ filterfds[current][0], filterfds[1 - current][1]);
+
+ if (pid > 0)
+ {
+ fprintf(stderr, "INFO: %s (PID %d) started.\n", filter->filter, pid);
+
+ filter->cost = pid;
+ cupsArrayAdd(pids, filter);
+ }
+ else
+ break;
+
+ argv[6] = NULL;
+ }
+
+ /*
+ * Close remaining pipes...
+ */
+
+ if (filterfds[0][1] > 1)
+ {
+ close(filterfds[0][0]);
+ close(filterfds[0][1]);
+ }
+
+ if (filterfds[1][1] > 1)
+ {
+ close(filterfds[1][0]);
+ close(filterfds[1][1]);
+ }
+
+ /*
+ * Wait for the children to exit...
+ */
+
+ retval = 0;
+
+ while (cupsArrayCount(pids) > 0)
+ {
+ if ((pid = wait(&status)) < 0)
+ continue;
+
+ key.cost = pid;
+ if ((filter = (mime_filter_t *)cupsArrayFind(pids, &key)) != NULL)
+ {
+ cupsArrayRemove(pids, filter);
+
+ if (status)
+ {
+ if (WIFEXITED(status))
+ fprintf(stderr, "ERROR: %s (PID %d) stopped with status %d\n",
+ filter->filter, pid, WEXITSTATUS(status));
+ else
+ fprintf(stderr, "ERROR: %s (PID %d) crashed on signal %d\n",
+ filter->filter, pid, WTERMSIG(status));
+
+ retval = 1;
+ }
+ else
+ fprintf(stderr, "INFO: %s (PID %d) exited with no errors.\n",
+ filter->filter, pid);
+ }
+ }
+
+ cupsArrayDelete(pids);
+
+ return (retval);
+}
+
+
+/*
+ * 'get_job_file()' - Get the specified job file.
+ */
+
+static void
+get_job_file(const char *job) /* I - Job ID */
+{
+ long jobid, /* Job ID */
+ docnum; /* Document number */
+ const char *jobptr; /* Pointer into job ID string */
+ char uri[1024]; /* job-uri */
+ http_t *http; /* Connection to server */
+ ipp_t *request; /* Request data */
+ int tempfd; /* Temporary file */
+
+
+ /*
+ * Get the job ID and document number, if any...
+ */
+
+ if ((jobptr = strrchr(job, '-')) != NULL)
+ jobptr ++;
+ else
+ jobptr = job;
+
+ jobid = strtol(jobptr, (char **)&jobptr, 10);
+
+ if (*jobptr == ',')
+ docnum = strtol(jobptr + 1, NULL, 10);
+ else
+ docnum = 1;
+
+ if (jobid < 1 || jobid > INT_MAX)
+ {
+ _cupsLangPrintf(stderr, _("cupsfilter: Invalid job ID %d."), (int)jobid);
+ exit(1);
+ }
+
+ if (docnum < 1 || docnum > INT_MAX)
+ {
+ _cupsLangPrintf(stderr, _("cupsfilter: Invalid document number %d."),
+ (int)docnum);
+ exit(1);
+ }
+
+ /*
+ * Ask the server for the document file...
+ */
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ _cupsLangPrintf(stderr, _("%s: Unable to connect to server."),
+ "cupsfilter");
+ exit(1);
+ }
+
+ request = ippNewRequest(CUPS_GET_DOCUMENT);
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", (int)jobid);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "document-number",
+ (int)docnum);
+
+ if ((tempfd = cupsTempFd(TempFile, sizeof(TempFile))) == -1)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to create temporary file"));
+ httpClose(http);
+ exit(1);
+ }
+
+ signal(SIGTERM, sighandler);
+
+ ippDelete(cupsDoIORequest(http, request, "/", -1, tempfd));
+
+ close(tempfd);
+
+ httpClose(http);
+
+ if (cupsLastError() != IPP_OK)
+ {
+ _cupsLangPrintf(stderr, _("cupsfilter: Unable to get job file - %s"),
+ cupsLastErrorString());
+ unlink(TempFile);
+ exit(1);
+ }
+}
+
+
+/*
+ * 'open_pipe()' - Create a pipe which is closed on exec.
+ */
+
+static int /* O - 0 on success, -1 on error */
+open_pipe(int *fds) /* O - Pipe file descriptors (2) */
+{
+ /*
+ * Create the pipe...
+ */
+
+ if (pipe(fds))
+ {
+ fds[0] = -1;
+ fds[1] = -1;
+
+ return (-1);
+ }
+
+ /*
+ * Set the "close on exec" flag on each end of the pipe...
+ */
+
+ if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
+ {
+ close(fds[0]);
+ close(fds[1]);
+
+ fds[0] = -1;
+ fds[1] = -1;
+
+ return (-1);
+ }
+
+ if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
+ {
+ close(fds[0]);
+ close(fds[1]);
+
+ fds[0] = -1;
+ fds[1] = -1;
+
+ return (-1);
+ }
+
+ /*
+ * Return 0 indicating success...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'read_cupsd_conf()' - Read the cupsd.conf file to get the filter settings.
+ */
+
+static int /* O - 0 on success, 1 on error */
+read_cupsd_conf(const char *filename) /* I - File to read */
+{
+ cups_file_t *fp; /* cupsd.conf file */
+ const char *temp; /* Temporary string */
+ char line[1024], /* Line from file */
+ *ptr; /* Pointer into line */
+ int linenum; /* Current line number */
+
+
+ if ((temp = getenv("CUPS_DATADIR")) != NULL)
+ set_string(&DataDir, temp);
+ else
+ set_string(&DataDir, CUPS_DATADIR);
+
+ if ((temp = getenv("CUPS_FONTPATH")) != NULL)
+ set_string(&FontPath, temp);
+ else
+ set_string(&FontPath, CUPS_FONTPATH);
+
+ set_string(&RIPCache, "128m");
+
+ if ((temp = getenv("CUPS_SERVERBIN")) != NULL)
+ set_string(&ServerBin, temp);
+ else
+ set_string(&ServerBin, CUPS_SERVERBIN);
+
+ strlcpy(line, filename, sizeof(line));
+ if ((ptr = strrchr(line, '/')) != NULL)
+ *ptr = '\0';
+ else
+ getcwd(line, sizeof(line));
+
+ set_string(&ServerRoot, line);
+
+ if ((fp = cupsFileOpen(filename, "r")) != NULL)
+ {
+ linenum = 0;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &ptr, &linenum))
+ {
+ if (!_cups_strcasecmp(line, "DataDir"))
+ set_string(&DataDir, ptr);
+ else if (!_cups_strcasecmp(line, "FontPath"))
+ set_string(&FontPath, ptr);
+ else if (!_cups_strcasecmp(line, "RIPCache"))
+ set_string(&RIPCache, ptr);
+ else if (!_cups_strcasecmp(line, "ServerBin"))
+ set_string(&ServerBin, ptr);
+ else if (!_cups_strcasecmp(line, "ServerRoot"))
+ set_string(&ServerRoot, ptr);
+ }
+
+ cupsFileClose(fp);
+ }
+
+ snprintf(line, sizeof(line),
+ "%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR ":/bin:/usr/bin",
+ ServerBin);
+ set_string(&Path, line);
+
+ return (0);
+}
+
+
+/*
+ * 'set_string()' - Copy and set a string.
+ */
+
+static void
+set_string(char **s, /* O - Copy of string */
+ const char *val) /* I - String to copy */
+{
+ if (*s)
+ free(*s);
+
+ *s = strdup(val);
+}
+
+
+/*
+ * 'sighandler()' - Signal catcher for when we print from stdin...
+ */
+
+static void
+sighandler(int s) /* I - Signal number */
+{
+ /*
+ * Remove the temporary file we're using to print a job file...
+ */
+
+ if (TempFile[0])
+ unlink(TempFile);
+
+ /*
+ * Exit...
+ */
+
+ exit(s);
+}
+
+
+/*
+ * 'usage()' - Show program usage...
+ */
+
+static void
+usage(const char *command, /* I - Command name */
+ const char *opt) /* I - Incorrect option, if any */
+{
+ if (opt)
+ _cupsLangPrintf(stderr, _("%s: Unknown option \"%c\"."), command, *opt);
+
+ if (!strcmp(command, "cupsfilter"))
+ {
+ _cupsLangPuts(stdout, _("Usage: cupsfilter [ options ] filename"));
+ _cupsLangPuts(stdout, _("Options:"));
+ _cupsLangPuts(stdout, _(" -D Remove the input file "
+ "when finished."));
+ _cupsLangPuts(stdout, _(" -P filename.ppd Set PPD file."));
+ _cupsLangPuts(stdout, _(" -U username Set username for job."));
+ _cupsLangPuts(stdout, _(" -c cupsd.conf Set cupsd.conf file to "
+ "use."));
+ _cupsLangPuts(stdout, _(" -d printer Use the named "
+ "printer."));
+ _cupsLangPuts(stdout, _(" -e Use every filter from "
+ "the PPD file."));
+ _cupsLangPuts(stdout, _(" -i mime/type Set input MIME type "
+ "(otherwise auto-typed)."));
+ _cupsLangPuts(stdout, _(" -j job-id[,N] Filter file N from the "
+ "specified job (default is file 1)."));
+ _cupsLangPuts(stdout, _(" -m mime/type Set output MIME type "
+ "(otherwise application/pdf)."));
+ _cupsLangPuts(stdout, _(" -n copies Set number of copies."));
+ _cupsLangPuts(stdout, _(" -o name=value Set option(s)."));
+ _cupsLangPuts(stdout, _(" -p filename.ppd Set PPD file."));
+ _cupsLangPuts(stdout, _(" -t title Set title."));
+ _cupsLangPuts(stdout, _(" -u Remove the PPD file "
+ "when finished."));
+ }
+ else
+ {
+ _cupsLangPuts(stdout, _("Usage: convert [ options ]"));
+ _cupsLangPuts(stdout, _("Options:"));
+ _cupsLangPuts(stdout, _(" -D Remove the input file "
+ "when finished."));
+ _cupsLangPuts(stdout, _(" -J title Set title."));
+ _cupsLangPuts(stdout, _(" -P filename.ppd Set PPD file."));
+ _cupsLangPuts(stdout, _(" -U username Set username for job."));
+ _cupsLangPuts(stdout, _(" -a 'name=value ...' Set option(s)."));
+ _cupsLangPuts(stdout, _(" -c copies Set number of copies."));
+ _cupsLangPuts(stdout, _(" -d printer Use the named "
+ "printer."));
+ _cupsLangPuts(stdout, _(" -e Use every filter from "
+ "the PPD file."));
+ _cupsLangPuts(stdout, _(" -f filename Set file to be "
+ "converted (otherwise stdin)."));
+ _cupsLangPuts(stdout, _(" -i mime/type Set input MIME type "
+ "(otherwise auto-typed)."));
+ _cupsLangPuts(stdout, _(" -j mime/type Set output MIME type "
+ "(otherwise application/pdf)."));
+ _cupsLangPuts(stdout, _(" -o filename Set file to be "
+ "generated (otherwise stdout)."));
+ _cupsLangPuts(stdout, _(" -u Remove the PPD file "
+ "when finished."));
+ }
+
+ exit(1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/dirsvc.c b/scheduler/dirsvc.c
new file mode 100644
index 000000000..eb3c862be
--- /dev/null
+++ b/scheduler/dirsvc.c
@@ -0,0 +1,5579 @@
+/*
+ * "$Id$"
+ *
+ * Directory services routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdDeregisterPrinter() - Stop sending broadcast information for a local
+ * printer and remove any pending references to
+ * remote printers.
+ * cupsdLoadRemoteCache() - Load the remote printer cache.
+ * cupsdRegisterPrinter() - Start sending broadcast information for a
+ * printer or update the broadcast contents.
+ * cupsdRestartPolling() - Restart polling servers as needed.
+ * cupsdSaveRemoteCache() - Save the remote printer cache.
+ * cupsdSendBrowseList() - Send new browsing information as necessary.
+ * ldap_rebind_proc() - Callback function for LDAP rebind
+ * ldap_connect() - Start new LDAP connection
+ * ldap_reconnect() - Reconnect to LDAP Server
+ * ldap_disconnect() - Disconnect from LDAP Server
+ * cupsdStartBrowsing() - Start sending and receiving broadcast
+ * information.
+ * cupsdStartPolling() - Start polling servers as needed.
+ * cupsdStopBrowsing() - Stop sending and receiving broadcast
+ * information.
+ * cupsdStopPolling() - Stop polling servers as needed.
+ * cupsdUpdateDNSSDName() - Update the computer name we use for
+ * browsing...
+ * cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP...
+ * cupsdUpdateSLPBrowse() - Get browsing information via SLP.
+ * dequote() - Remote quotes from a string.
+ * dnssdAddAlias() - Add a DNS-SD alias name.
+ * dnssdBuildTxtRecord() - Build a TXT record from printer info.
+ * dnssdComparePrinters() - Compare the registered names of two printers.
+ * dnssdDeregisterPrinter() - Stop sending broadcast information for a
+ * printer.
+ * dnssdPackTxtRecord() - Pack an array of key/value pairs into the TXT
+ * record format.
+ * dnssdRegisterCallback() - DNSServiceRegister callback.
+ * dnssdRegisterPrinter() - Start sending broadcast information for a
+ * printer or update the broadcast contents.
+ * dnssdStop() - Stop all DNS-SD registrations.
+ * dnssdUpdate() - Handle DNS-SD queries.
+ * get_auth_info_required() - Get the auth-info-required value to advertise.
+ * get_hostconfig() - Get an /etc/hostconfig service setting.
+ * is_local_queue() - Determine whether the URI points at a local
+ * queue.
+ * process_browse_data() - Process new browse data.
+ * process_implicit_classes() - Create/update implicit classes as needed.
+ * send_cups_browse() - Send new browsing information using the CUPS
+ * protocol.
+ * ldap_search_rec() - LDAP Search with reconnect
+ * ldap_freeres() - Free LDAPMessage
+ * ldap_getval_char() - Get first LDAP value and convert to string
+ * send_ldap_ou() - Send LDAP ou registrations.
+ * send_ldap_browse() - Send LDAP printer registrations.
+ * ldap_dereg_printer() - Delete printer from directory
+ * ldap_dereg_ou() - Remove the organizational unit.
+ * send_slp_browse() - Register the specified printer with SLP.
+ * slp_attr_callback() - SLP attribute callback
+ * slp_dereg_printer() - SLPDereg() the specified printer
+ * slp_get_attr() - Get an attribute from an SLP registration.
+ * slp_reg_callback() - Empty SLPRegReport.
+ * slp_url_callback() - SLP service url callback
+ * update_cups_browse() - Update the browse lists using the CUPS
+ * protocol.
+ * update_lpd() - Update the LPD configuration as needed.
+ * update_polling() - Read status messages from the poll daemons.
+ * update_smb() - Update the SMB configuration as needed.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <grp.h>
+
+#ifdef HAVE_DNSSD
+# include <dns_sd.h>
+# ifdef __APPLE__
+# include <nameser.h>
+# ifdef HAVE_COREFOUNDATION
+# include <CoreFoundation/CoreFoundation.h>
+# endif /* HAVE_COREFOUNDATION */
+# ifdef HAVE_SYSTEMCONFIGURATION
+# include <SystemConfiguration/SystemConfiguration.h>
+# endif /* HAVE_SYSTEMCONFIGURATION */
+# endif /* __APPLE__ */
+#endif /* HAVE_DNSSD */
+
+
+/*
+ * Local functions...
+ */
+
+static char *dequote(char *d, const char *s, int dlen);
+static char *get_auth_info_required(cupsd_printer_t *p, char *buffer,
+ size_t bufsize);
+#ifdef __APPLE__
+static int get_hostconfig(const char *name);
+#endif /* __APPLE__ */
+static int is_local_queue(const char *uri, char *host, int hostlen,
+ char *resource, int resourcelen);
+static void process_browse_data(const char *uri, const char *host,
+ const char *resource, cups_ptype_t type,
+ ipp_pstate_t state, const char *location,
+ const char *info, const char *make_model,
+ int num_attrs, cups_option_t *attrs);
+static void process_implicit_classes(void);
+static void send_cups_browse(cupsd_printer_t *p);
+#ifdef HAVE_LDAP
+static LDAP *ldap_connect(void);
+static LDAP *ldap_reconnect(void);
+static void ldap_disconnect(LDAP *ld);
+static int ldap_search_rec(LDAP *ld, char *base, int scope,
+ char *filter, char *attrs[],
+ int attrsonly, LDAPMessage **res);
+static int ldap_getval_firststring(LDAP *ld, LDAPMessage *entry,
+ char *attr, char *retval,
+ unsigned long maxsize);
+static void ldap_freeres(LDAPMessage *entry);
+static void send_ldap_ou(char *ou, char *basedn, char *descstring);
+static void send_ldap_browse(cupsd_printer_t *p);
+static void ldap_dereg_printer(cupsd_printer_t *p);
+static void ldap_dereg_ou(char *ou, char *basedn);
+# ifdef HAVE_LDAP_REBIND_PROC
+# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+static int ldap_rebind_proc(LDAP *RebindLDAPHandle,
+ LDAP_CONST char *refsp,
+ ber_tag_t request,
+ ber_int_t msgid,
+ void *params);
+# else
+static int ldap_rebind_proc(LDAP *RebindLDAPHandle,
+ char **dnp,
+ char **passwdp,
+ int *authmethodp,
+ int freeit,
+ void *arg);
+# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
+# endif /* HAVE_LDAP_REBIND_PROC */
+#endif /* HAVE_LDAP */
+#ifdef HAVE_LIBSLP
+static void send_slp_browse(cupsd_printer_t *p);
+#endif /* HAVE_LIBSLP */
+static void update_cups_browse(void);
+static void update_lpd(int onoff);
+static void update_polling(void);
+static void update_smb(int onoff);
+
+
+#ifdef HAVE_DNSSD
+# ifdef HAVE_COREFOUNDATION
+static void dnssdAddAlias(const void *key, const void *value,
+ void *context);
+# endif /* HAVE_COREFOUNDATION */
+static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p,
+ int for_lpd);
+static int dnssdComparePrinters(cupsd_printer_t *a, cupsd_printer_t *b);
+static void dnssdDeregisterPrinter(cupsd_printer_t *p);
+static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2],
+ int count);
+static void dnssdRegisterCallback(DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ DNSServiceErrorType errorCode,
+ const char *name, const char *regtype,
+ const char *domain, void *context);
+static void dnssdRegisterPrinter(cupsd_printer_t *p);
+static void dnssdStop(void);
+static void dnssdUpdate(void);
+#endif /* HAVE_DNSSD */
+
+#ifdef HAVE_LDAP
+static const char * const ldap_attrs[] =/* CUPS LDAP attributes */
+ {
+ "printerDescription",
+ "printerLocation",
+ "printerMakeAndModel",
+ "printerType",
+ "printerURI",
+ NULL
+ };
+#endif /* HAVE_LDAP */
+
+#ifdef HAVE_LIBSLP
+/*
+ * SLP definitions...
+ */
+
+/*
+ * SLP service name for CUPS...
+ */
+
+# define SLP_CUPS_SRVTYPE "service:printer"
+# define SLP_CUPS_SRVLEN 15
+
+
+/*
+ * Printer service URL structure
+ */
+
+typedef struct _slpsrvurl_s /**** SLP URL list ****/
+{
+ struct _slpsrvurl_s *next; /* Next URL in list */
+ char url[HTTP_MAX_URI];
+ /* URL */
+} slpsrvurl_t;
+
+
+/*
+ * Local functions...
+ */
+
+static SLPBoolean slp_attr_callback(SLPHandle hslp, const char *attrlist,
+ SLPError errcode, void *cookie);
+static void slp_dereg_printer(cupsd_printer_t *p);
+static int slp_get_attr(const char *attrlist, const char *tag,
+ char **valbuf);
+static void slp_reg_callback(SLPHandle hslp, SLPError errcode,
+ void *cookie);
+static SLPBoolean slp_url_callback(SLPHandle hslp, const char *srvurl,
+ unsigned short lifetime,
+ SLPError errcode, void *cookie);
+#endif /* HAVE_LIBSLP */
+
+
+/*
+ * 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a
+ * local printer and remove any pending
+ * references to remote printers.
+ */
+
+void
+cupsdDeregisterPrinter(
+ cupsd_printer_t *p, /* I - Printer to register */
+ int removeit) /* I - Printer being permanently removed */
+{
+ /*
+ * Only deregister if browsing is enabled and it's a local printer...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdDeregisterPrinter(p=%p(%s), removeit=%d)", p, p->name,
+ removeit);
+
+ if (!Browsing || !p->shared ||
+ (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_SCANNER)))
+ return;
+
+ /*
+ * Announce the deletion...
+ */
+
+ if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
+ {
+ cups_ptype_t savedtype = p->type; /* Saved printer type */
+
+ p->type |= CUPS_PRINTER_DELETE;
+
+ send_cups_browse(p);
+
+ p->type = savedtype;
+ }
+
+#ifdef HAVE_LIBSLP
+ if (BrowseLocalProtocols & BROWSE_SLP)
+ slp_dereg_printer(p);
+#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_LDAP
+ if (BrowseLocalProtocols & BROWSE_LDAP)
+ ldap_dereg_printer(p);
+#endif /* HAVE_LDAP */
+
+#ifdef HAVE_DNSSD
+ if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
+ dnssdDeregisterPrinter(p);
+#endif /* HAVE_DNSSD */
+}
+
+
+/*
+ * 'cupsdLoadRemoteCache()' - Load the remote printer cache.
+ */
+
+void
+cupsdLoadRemoteCache(void)
+{
+ int i; /* Looping var */
+ cups_file_t *fp; /* remote.cache file */
+ int linenum; /* Current line number */
+ char line[4096], /* Line from file */
+ *value, /* Pointer to value */
+ *valueptr, /* Pointer into value */
+ scheme[32], /* Scheme portion of URI */
+ username[64], /* Username portion of URI */
+ host[HTTP_MAX_HOST],
+ /* Hostname portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port number */
+ cupsd_printer_t *p; /* Current printer */
+ time_t now; /* Current time */
+
+
+ /*
+ * Don't load the cache if the remote protocols are disabled...
+ */
+
+ if (!Browsing)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdLoadRemoteCache: Not loading remote cache.");
+ return;
+ }
+
+ /*
+ * Open the remote.cache file...
+ */
+
+ snprintf(line, sizeof(line), "%s/remote.cache", CacheDir);
+ if ((fp = cupsdOpenConfFile(line)) == NULL)
+ return;
+
+ /*
+ * Read printer configurations until we hit EOF...
+ */
+
+ linenum = 0;
+ p = NULL;
+ now = time(NULL);
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ /*
+ * Decode the directive...
+ */
+
+ if (!_cups_strcasecmp(line, "<Printer") ||
+ !_cups_strcasecmp(line, "<DefaultPrinter"))
+ {
+ /*
+ * <Printer name> or <DefaultPrinter name>
+ */
+
+ if (p == NULL && value)
+ {
+ /*
+ * Add the printer and a base file type...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdLoadRemoteCache: Loading printer %s...", value);
+
+ if ((p = cupsdFindDest(value)) != NULL)
+ {
+ if (p->type & CUPS_PRINTER_CLASS)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Cached remote printer \"%s\" conflicts with "
+ "existing class!",
+ value);
+ p = NULL;
+ continue;
+ }
+ }
+ else
+ p = cupsdAddPrinter(value);
+
+ p->accepting = 1;
+ p->state = IPP_PRINTER_IDLE;
+ p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
+ p->browse_time = now;
+ p->browse_expire = now + BrowseTimeout;
+
+ /*
+ * Set the default printer as needed...
+ */
+
+ if (!_cups_strcasecmp(line, "<DefaultPrinter"))
+ DefaultPrinter = p;
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "<Class") ||
+ !_cups_strcasecmp(line, "<DefaultClass"))
+ {
+ /*
+ * <Class name> or <DefaultClass name>
+ */
+
+ if (p == NULL && value)
+ {
+ /*
+ * Add the printer and a base file type...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdLoadRemoteCache: Loading class %s...", value);
+
+ if ((p = cupsdFindDest(value)) != NULL)
+ p->type = CUPS_PRINTER_CLASS;
+ else
+ p = cupsdAddClass(value);
+
+ p->accepting = 1;
+ p->state = IPP_PRINTER_IDLE;
+ p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
+ p->browse_time = now;
+ p->browse_expire = now + BrowseTimeout;
+
+ /*
+ * Set the default printer as needed...
+ */
+
+ if (!_cups_strcasecmp(line, "<DefaultClass"))
+ DefaultPrinter = p;
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "</Printer>") ||
+ !_cups_strcasecmp(line, "</Class>"))
+ {
+ if (p != NULL)
+ {
+ /*
+ * Close out the current printer...
+ */
+
+ cupsdSetPrinterAttrs(p);
+
+ p = NULL;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ }
+ else if (!p)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "UUID"))
+ {
+ if (value && !strncmp(value, "urn:uuid:", 9))
+ cupsdSetString(&(p->uuid), value);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad UUID on line %d of remote.cache.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "Info"))
+ {
+ if (value)
+ cupsdSetString(&p->info, value);
+ }
+ else if (!_cups_strcasecmp(line, "MakeModel"))
+ {
+ if (value)
+ cupsdSetString(&p->make_model, value);
+ }
+ else if (!_cups_strcasecmp(line, "Location"))
+ {
+ if (value)
+ cupsdSetString(&p->location, value);
+ }
+ else if (!_cups_strcasecmp(line, "DeviceURI"))
+ {
+ if (value)
+ {
+ httpSeparateURI(HTTP_URI_CODING_ALL, value, scheme, sizeof(scheme),
+ username, sizeof(username), host, sizeof(host), &port,
+ resource, sizeof(resource));
+
+ cupsdSetString(&p->hostname, host);
+ cupsdSetString(&p->uri, value);
+ cupsdSetDeviceURI(p, value);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "Option") && value)
+ {
+ /*
+ * Option name value
+ */
+
+ for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
+
+ if (!*valueptr)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ else
+ {
+ for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
+
+ p->num_options = cupsAddOption(value, valueptr, p->num_options,
+ &(p->options));
+ }
+ }
+ else if (!_cups_strcasecmp(line, "Reason"))
+ {
+ if (value)
+ {
+ for (i = 0 ; i < p->num_reasons; i ++)
+ if (!strcmp(value, p->reasons[i]))
+ break;
+
+ if (i >= p->num_reasons &&
+ p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
+ {
+ p->reasons[p->num_reasons] = _cupsStrAlloc(value);
+ p->num_reasons ++;
+ }
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "State"))
+ {
+ /*
+ * Set the initial queue state...
+ */
+
+ if (value && !_cups_strcasecmp(value, "idle"))
+ p->state = IPP_PRINTER_IDLE;
+ else if (value && !_cups_strcasecmp(value, "stopped"))
+ {
+ p->state = IPP_PRINTER_STOPPED;
+ cupsdSetPrinterReasons(p, "+paused");
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "StateMessage"))
+ {
+ /*
+ * Set the initial queue state message...
+ */
+
+ if (value)
+ strlcpy(p->state_message, value, sizeof(p->state_message));
+ }
+ else if (!_cups_strcasecmp(line, "Accepting"))
+ {
+ /*
+ * Set the initial accepting state...
+ */
+
+ if (value &&
+ (!_cups_strcasecmp(value, "yes") ||
+ !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "true")))
+ p->accepting = 1;
+ else if (value &&
+ (!_cups_strcasecmp(value, "no") ||
+ !_cups_strcasecmp(value, "off") ||
+ !_cups_strcasecmp(value, "false")))
+ p->accepting = 0;
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "Type"))
+ {
+ if (value)
+ p->type = atoi(value);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "BrowseTime"))
+ {
+ if (value)
+ {
+ time_t t = atoi(value);
+
+ if (t > p->browse_expire)
+ p->browse_expire = t;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "JobSheets"))
+ {
+ /*
+ * Set the initial job sheets...
+ */
+
+ if (value)
+ {
+ for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
+
+ if (*valueptr)
+ *valueptr++ = '\0';
+
+ cupsdSetString(&p->job_sheets[0], value);
+
+ while (isspace(*valueptr & 255))
+ valueptr ++;
+
+ if (*valueptr)
+ {
+ for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
+
+ if (*valueptr)
+ *valueptr = '\0';
+
+ cupsdSetString(&p->job_sheets[1], value);
+ }
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "AllowUser"))
+ {
+ if (value)
+ {
+ p->deny_users = 0;
+ cupsdAddString(&(p->users), value);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "DenyUser"))
+ {
+ if (value)
+ {
+ p->deny_users = 1;
+ cupsdAddString(&(p->users), value);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ }
+ else
+ {
+ /*
+ * Something else we don't understand...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown configuration directive %s on line %d of remote.cache.",
+ line, linenum);
+ }
+ }
+
+ cupsFileClose(fp);
+
+ /*
+ * Do auto-classing if needed...
+ */
+
+ process_implicit_classes();
+}
+
+
+/*
+ * 'cupsdRegisterPrinter()' - Start sending broadcast information for a
+ * printer or update the broadcast contents.
+ */
+
+void
+cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdRegisterPrinter(p=%p(%s))", p,
+ p->name);
+
+ if (!Browsing || !BrowseLocalProtocols ||
+ (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_SCANNER)))
+ return;
+
+#ifdef HAVE_LIBSLP
+/* if (BrowseLocalProtocols & BROWSE_SLP)
+ slpRegisterPrinter(p); */
+#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_DNSSD
+ if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
+ dnssdRegisterPrinter(p);
+#endif /* HAVE_DNSSD */
+}
+
+
+/*
+ * 'cupsdRestartPolling()' - Restart polling servers as needed.
+ */
+
+void
+cupsdRestartPolling(void)
+{
+ int i; /* Looping var */
+ cupsd_dirsvc_poll_t *pollp; /* Current polling server */
+
+
+ for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
+ if (pollp->pid)
+ kill(pollp->pid, SIGHUP);
+}
+
+
+/*
+ * 'cupsdSaveRemoteCache()' - Save the remote printer cache.
+ */
+
+void
+cupsdSaveRemoteCache(void)
+{
+ int i; /* Looping var */
+ cups_file_t *fp; /* remote.cache file */
+ char filename[1024], /* remote.cache filename */
+ temp[1024], /* Temporary string */
+ value[2048], /* Value string */
+ *name; /* Current user name */
+ cupsd_printer_t *printer; /* Current printer class */
+ time_t curtime; /* Current time */
+ struct tm *curdate; /* Current date */
+ cups_option_t *option; /* Current option */
+
+
+ /*
+ * Create the remote.cache file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/remote.cache", CacheDir);
+
+ if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm)) == NULL)
+ return;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Saving remote.cache...");
+
+ /*
+ * Write a small header to the file...
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+ strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
+
+ cupsFilePuts(fp, "# Remote cache file for " CUPS_SVERSION "\n");
+ cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
+
+ /*
+ * Write each local printer known to the system...
+ */
+
+ for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ printer;
+ printer = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ /*
+ * Skip local destinations...
+ */
+
+ if (!(printer->type & CUPS_PRINTER_DISCOVERED))
+ continue;
+
+ /*
+ * Write printers as needed...
+ */
+
+ if (printer == DefaultPrinter)
+ cupsFilePuts(fp, "<Default");
+ else
+ cupsFilePutChar(fp, '<');
+
+ if (printer->type & CUPS_PRINTER_CLASS)
+ cupsFilePrintf(fp, "Class %s>\n", printer->name);
+ else
+ cupsFilePrintf(fp, "Printer %s>\n", printer->name);
+
+ cupsFilePrintf(fp, "BrowseTime %d\n", (int)printer->browse_expire);
+
+ cupsFilePrintf(fp, "UUID %s\n", printer->uuid);
+
+ if (printer->info)
+ cupsFilePutConf(fp, "Info", printer->info);
+
+ if (printer->location)
+ cupsFilePutConf(fp, "Location", printer->location);
+
+ if (printer->make_model)
+ cupsFilePutConf(fp, "MakeModel", printer->make_model);
+
+ cupsFilePutConf(fp, "DeviceURI", printer->device_uri);
+
+ if (printer->state == IPP_PRINTER_STOPPED)
+ cupsFilePuts(fp, "State Stopped\n");
+ else
+ cupsFilePuts(fp, "State Idle\n");
+
+ for (i = 0; i < printer->num_reasons; i ++)
+ cupsFilePutConf(fp, "Reason", printer->reasons[i]);
+
+ cupsFilePrintf(fp, "Type %d\n", printer->type);
+
+ if (printer->accepting)
+ cupsFilePuts(fp, "Accepting Yes\n");
+ else
+ cupsFilePuts(fp, "Accepting No\n");
+
+ snprintf(value, sizeof(value), "%s %s", printer->job_sheets[0],
+ printer->job_sheets[1]);
+ cupsFilePutConf(fp, "JobSheets", value);
+
+ for (name = (char *)cupsArrayFirst(printer->users);
+ name;
+ name = (char *)cupsArrayNext(printer->users))
+ cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", name);
+
+ for (i = printer->num_options, option = printer->options;
+ i > 0;
+ i --, option ++)
+ {
+ snprintf(value, sizeof(value), "%s %s", option->name, option->value);
+ cupsFilePutConf(fp, "Option", value);
+ }
+
+ if (printer->type & CUPS_PRINTER_CLASS)
+ cupsFilePuts(fp, "</Class>\n");
+ else
+ cupsFilePuts(fp, "</Printer>\n");
+ }
+
+ cupsdCloseCreatedConfFile(fp, filename);
+}
+
+
+/*
+ * 'cupsdSendBrowseList()' - Send new browsing information as necessary.
+ */
+
+void
+cupsdSendBrowseList(void)
+{
+ int count; /* Number of dests to update */
+ cupsd_printer_t *p; /* Current printer */
+ time_t ut, /* Minimum update time */
+ to; /* Timeout time */
+
+
+ if (!Browsing || !Printers)
+ return;
+
+ /*
+ * Compute the update and timeout times...
+ */
+
+ to = time(NULL);
+ ut = to - BrowseInterval;
+
+ /*
+ * Figure out how many printers need an update...
+ */
+
+ if (BrowseInterval > 0 && BrowseLocalProtocols)
+ {
+ int max_count; /* Maximum number to update */
+
+
+ /*
+ * Throttle the number of printers we'll be updating this time
+ * around based on the number of queues that need updating and
+ * the maximum number of queues to update each second...
+ */
+
+ max_count = 2 * cupsArrayCount(Printers) / BrowseInterval + 1;
+
+ for (count = 0, p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ count < max_count && p != NULL;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_SCANNER)) &&
+ p->shared && p->browse_time < ut)
+ count ++;
+
+ /*
+ * Loop through all of the printers and send local updates as needed...
+ */
+
+ if (BrowseNext)
+ p = (cupsd_printer_t *)cupsArrayFind(Printers, BrowseNext);
+ else
+ p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+
+ for (;
+ count > 0;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ /*
+ * Check for wraparound...
+ */
+
+ if (!p)
+ p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+
+ if (!p)
+ break;
+ else if ((p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_SCANNER)) ||
+ !p->shared)
+ continue;
+ else if (p->browse_time < ut)
+ {
+ /*
+ * Need to send an update...
+ */
+
+ count --;
+
+ p->browse_time = time(NULL);
+
+ if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
+ send_cups_browse(p);
+
+#ifdef HAVE_LIBSLP
+ if (BrowseLocalProtocols & BROWSE_SLP)
+ send_slp_browse(p);
+#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_LDAP
+ if (BrowseLocalProtocols & BROWSE_LDAP)
+ send_ldap_browse(p);
+#endif /* HAVE_LDAP */
+ }
+ }
+
+ /*
+ * Save where we left off so that all printers get updated...
+ */
+
+ BrowseNext = p;
+ }
+
+ /*
+ * Loop through all of the printers and timeout old printers as needed...
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ /*
+ * If this is a remote queue, see if it needs to be timed out...
+ */
+
+ if ((p->type & CUPS_PRINTER_DISCOVERED) &&
+ !(p->type & CUPS_PRINTER_IMPLICIT) &&
+ p->browse_expire < to)
+ {
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
+ "%s \'%s\' deleted by directory services (timeout).",
+ (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
+ p->name);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Remote destination \"%s\" has timed out; "
+ "deleting it...",
+ p->name);
+
+ cupsArraySave(Printers);
+ cupsdDeletePrinter(p, 1);
+ cupsArrayRestore(Printers);
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+ }
+ }
+}
+
+
+#ifdef HAVE_LDAP_REBIND_PROC
+# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+/*
+ * 'ldap_rebind_proc()' - Callback function for LDAP rebind
+ */
+
+static int /* O - Result code */
+ldap_rebind_proc(
+ LDAP *RebindLDAPHandle, /* I - LDAP handle */
+ LDAP_CONST char *refsp, /* I - ??? */
+ ber_tag_t request, /* I - ??? */
+ ber_int_t msgid, /* I - ??? */
+ void *params) /* I - ??? */
+{
+ int rc; /* Result code */
+# if LDAP_API_VERSION > 3000
+ struct berval bval; /* Bind value */
+# endif /* LDAP_API_VERSION > 3000 */
+
+
+ (void)request;
+ (void)msgid;
+ (void)params;
+
+ /*
+ * Bind to new LDAP server...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_rebind_proc: Rebind to %s", refsp);
+
+# if LDAP_API_VERSION > 3000
+ bval.bv_val = BrowseLDAPPassword;
+ bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword);
+
+ rc = ldap_sasl_bind_s(RebindLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE,
+ &bval, NULL, NULL, NULL);
+# else
+ rc = ldap_bind_s(RebindLDAPHandle, BrowseLDAPBindDN, BrowseLDAPPassword,
+ LDAP_AUTH_SIMPLE);
+# endif /* LDAP_API_VERSION > 3000 */
+
+ return (rc);
+}
+
+
+# else /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
+/*
+ * 'ldap_rebind_proc()' - Callback function for LDAP rebind
+ */
+
+static int /* O - Result code */
+ldap_rebind_proc(
+ LDAP *RebindLDAPHandle, /* I - LDAP handle */
+ char **dnp, /* I - ??? */
+ char **passwdp, /* I - ??? */
+ int *authmethodp, /* I - ??? */
+ int freeit, /* I - ??? */
+ void *arg) /* I - ??? */
+{
+ switch (freeit)
+ {
+ case 1:
+ /*
+ * Free current values...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_rebind_proc: Free values...");
+
+ if (dnp && *dnp)
+ free(*dnp);
+
+ if (passwdp && *passwdp)
+ free(*passwdp);
+ break;
+
+ case 0:
+ /*
+ * Return credentials for LDAP referal...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "ldap_rebind_proc: Return necessary values...");
+
+ *dnp = strdup(BrowseLDAPBindDN);
+ *passwdp = strdup(BrowseLDAPPassword);
+ *authmethodp = LDAP_AUTH_SIMPLE;
+ break;
+
+ default:
+ /*
+ * Should never happen...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP rebind has been called with wrong freeit value!");
+ break;
+ }
+
+ return (LDAP_SUCCESS);
+}
+# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
+#endif /* HAVE_LDAP_REBIND_PROC */
+
+
+#ifdef HAVE_LDAP
+/*
+ * 'ldap_connect()' - Start new LDAP connection
+ */
+
+static LDAP * /* O - LDAP handle */
+ldap_connect(void)
+{
+ int rc; /* LDAP API status */
+ int version = 3; /* LDAP version */
+ struct berval bv = {0, ""}; /* SASL bind value */
+ LDAP *TempBrowseLDAPHandle=NULL;
+ /* Temporary LDAP Handle */
+# if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
+ int ldap_ssl = 0; /* LDAP SSL indicator */
+ int ssl_err = 0; /* LDAP SSL error value */
+# endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
+
+
+# ifdef HAVE_OPENLDAP
+# ifdef HAVE_LDAP_SSL
+ /*
+ * Set the certificate file to use for encrypted LDAP sessions...
+ */
+
+ if (BrowseLDAPCACertFile)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "ldap_connect: Setting CA certificate file \"%s\"",
+ BrowseLDAPCACertFile);
+
+ if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
+ (void *)BrowseLDAPCACertFile)) != LDAP_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to set CA certificate file for LDAP "
+ "connections: %d - %s", rc, ldap_err2string(rc));
+ }
+# endif /* HAVE_LDAP_SSL */
+
+ /*
+ * Initialize OPENLDAP connection...
+ * LDAP stuff currently only supports ldapi EXTERNAL SASL binds...
+ */
+
+ if (!BrowseLDAPServer || !_cups_strcasecmp(BrowseLDAPServer, "localhost"))
+ rc = ldap_initialize(&TempBrowseLDAPHandle, "ldapi:///");
+ else
+ rc = ldap_initialize(&TempBrowseLDAPHandle, BrowseLDAPServer);
+
+# else /* HAVE_OPENLDAP */
+
+ int ldap_port = 0; /* LDAP port */
+ char ldap_protocol[11], /* LDAP protocol */
+ ldap_host[255]; /* LDAP host */
+
+ /*
+ * Split LDAP URI into its components...
+ */
+
+ if (!BrowseLDAPServer)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "BrowseLDAPServer not configured!");
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
+ BrowseLocalProtocols &= ~BROWSE_LDAP;
+ BrowseRemoteProtocols &= ~BROWSE_LDAP;
+ return (NULL);
+ }
+
+ sscanf(BrowseLDAPServer, "%10[^:]://%254[^:/]:%d", ldap_protocol, ldap_host,
+ &ldap_port);
+
+ if (!strcmp(ldap_protocol, "ldap"))
+ ldap_ssl = 0;
+ else if (!strcmp(ldap_protocol, "ldaps"))
+ ldap_ssl = 1;
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unrecognized LDAP protocol (%s)!",
+ ldap_protocol);
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
+ BrowseLocalProtocols &= ~BROWSE_LDAP;
+ BrowseRemoteProtocols &= ~BROWSE_LDAP;
+ return (NULL);
+ }
+
+ if (ldap_port == 0)
+ {
+ if (ldap_ssl)
+ ldap_port = LDAPS_PORT;
+ else
+ ldap_port = LDAP_PORT;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "ldap_connect: PROT:%s HOST:%s PORT:%d",
+ ldap_protocol, ldap_host, ldap_port);
+
+ /*
+ * Initialize LDAP connection...
+ */
+
+ if (!ldap_ssl)
+ {
+ if ((TempBrowseLDAPHandle = ldap_init(ldap_host, ldap_port)) == NULL)
+ rc = LDAP_OPERATIONS_ERROR;
+ else
+ rc = LDAP_SUCCESS;
+
+# ifdef HAVE_LDAP_SSL
+ }
+ else
+ {
+ /*
+ * Initialize SSL LDAP connection...
+ */
+
+ if (BrowseLDAPCACertFile)
+ {
+ rc = ldapssl_client_init(BrowseLDAPCACertFile, (void *)NULL);
+ if (rc != LDAP_SUCCESS)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Failed to initialize LDAP SSL client!");
+ rc = LDAP_OPERATIONS_ERROR;
+ }
+ else
+ {
+ if ((TempBrowseLDAPHandle = ldapssl_init(ldap_host, ldap_port,
+ 1)) == NULL)
+ rc = LDAP_OPERATIONS_ERROR;
+ else
+ rc = LDAP_SUCCESS;
+ }
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP SSL certificate file/database not configured!");
+ rc = LDAP_OPERATIONS_ERROR;
+ }
+
+# else /* HAVE_LDAP_SSL */
+
+ /*
+ * Return error, because client libraries doesn't support SSL
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP client libraries do not support SSL");
+ rc = LDAP_OPERATIONS_ERROR;
+
+# endif /* HAVE_LDAP_SSL */
+ }
+# endif /* HAVE_OPENLDAP */
+
+ /*
+ * Check return code from LDAP initialize...
+ */
+
+ if (rc != LDAP_SUCCESS)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize LDAP!");
+
+ if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Temporarily disabling LDAP browsing...");
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
+
+ BrowseLocalProtocols &= ~BROWSE_LDAP;
+ BrowseRemoteProtocols &= ~BROWSE_LDAP;
+ }
+
+ ldap_disconnect(TempBrowseLDAPHandle);
+
+ return (NULL);
+ }
+
+ /*
+ * Upgrade LDAP version...
+ */
+
+ if (ldap_set_option(TempBrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION,
+ (const void *)&version) != LDAP_SUCCESS)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set LDAP protocol version %d!",
+ version);
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
+
+ BrowseLocalProtocols &= ~BROWSE_LDAP;
+ BrowseRemoteProtocols &= ~BROWSE_LDAP;
+ ldap_disconnect(TempBrowseLDAPHandle);
+
+ return (NULL);
+ }
+
+ /*
+ * Register LDAP rebind procedure...
+ */
+
+# ifdef HAVE_LDAP_REBIND_PROC
+# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+
+ rc = ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc,
+ (void *)NULL);
+ if (rc != LDAP_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Setting LDAP rebind function failed with status %d: %s",
+ rc, ldap_err2string(rc));
+
+# else
+
+ ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc, (void *)NULL);
+
+# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
+# endif /* HAVE_LDAP_REBIND_PROC */
+
+ /*
+ * Start LDAP bind...
+ */
+
+# if LDAP_API_VERSION > 3000
+ struct berval bval;
+ bval.bv_val = BrowseLDAPPassword;
+ bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword);
+
+ if (!BrowseLDAPServer || !_cups_strcasecmp(BrowseLDAPServer, "localhost"))
+ rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, NULL, "EXTERNAL", &bv, NULL,
+ NULL, NULL);
+ else
+ rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL);
+
+# else
+ rc = ldap_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN,
+ BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
+# endif /* LDAP_API_VERSION > 3000 */
+
+ if (rc != LDAP_SUCCESS)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "LDAP bind failed with error %d: %s",
+ rc, ldap_err2string(rc));
+
+# if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
+ if (ldap_ssl && (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR))
+ {
+ ssl_err = PORT_GetError();
+ if (ssl_err != 0)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "LDAP SSL error %d: %s", ssl_err,
+ ldapssl_err2string(ssl_err));
+ }
+# endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
+
+ ldap_disconnect(TempBrowseLDAPHandle);
+
+ return (NULL);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "LDAP connection established");
+
+ return (TempBrowseLDAPHandle);
+}
+
+
+/*
+ * 'ldap_reconnect()' - Reconnect to LDAP Server
+ */
+
+static LDAP * /* O - New LDAP handle */
+ldap_reconnect(void)
+{
+ LDAP *TempBrowseLDAPHandle = NULL; /* Temp Handle to LDAP server */
+
+
+ /*
+ * Get a new LDAP Handle and replace the global Handle
+ * if the new connection was successful.
+ */
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Try LDAP reconnect...");
+
+ TempBrowseLDAPHandle = ldap_connect();
+
+ if (TempBrowseLDAPHandle != NULL)
+ {
+ if (BrowseLDAPHandle != NULL)
+ ldap_disconnect(BrowseLDAPHandle);
+
+ BrowseLDAPHandle = TempBrowseLDAPHandle;
+ }
+
+ return (BrowseLDAPHandle);
+}
+
+
+/*
+ * 'ldap_disconnect()' - Disconnect from LDAP Server
+ */
+
+static void
+ldap_disconnect(LDAP *ld) /* I - LDAP handle */
+{
+ int rc; /* Return code */
+
+
+ /*
+ * Close LDAP handle...
+ */
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ rc = ldap_unbind_ext_s(ld, NULL, NULL);
+# else
+ rc = ldap_unbind_s(ld);
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+
+ if (rc != LDAP_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unbind from LDAP server failed with status %d: %s",
+ rc, ldap_err2string(rc));
+}
+#endif /* HAVE_LDAP */
+
+
+/*
+ * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
+ */
+
+void
+cupsdStartBrowsing(void)
+{
+ int val; /* Socket option value */
+ struct sockaddr_in addr; /* Broadcast address */
+ cupsd_printer_t *p; /* Current printer */
+
+
+ BrowseNext = NULL;
+
+ if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
+ return;
+
+ if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
+ {
+ if (BrowseSocket < 0)
+ {
+ /*
+ * Create the broadcast socket...
+ */
+
+ if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create broadcast socket - %s.",
+ strerror(errno));
+ BrowseLocalProtocols &= ~BROWSE_CUPS;
+ BrowseRemoteProtocols &= ~BROWSE_CUPS;
+
+ if (FatalErrors & CUPSD_FATAL_BROWSE)
+ cupsdEndProcess(getpid(), 0);
+ }
+ }
+
+ if (BrowseSocket >= 0)
+ {
+ /*
+ * Bind the socket to browse port...
+ */
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(BrowsePort);
+
+ if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to bind broadcast socket - %s.",
+ strerror(errno));
+
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
+
+ BrowseSocket = -1;
+ BrowseLocalProtocols &= ~BROWSE_CUPS;
+ BrowseRemoteProtocols &= ~BROWSE_CUPS;
+
+ if (FatalErrors & CUPSD_FATAL_BROWSE)
+ cupsdEndProcess(getpid(), 0);
+ }
+ }
+
+ if (BrowseSocket >= 0)
+ {
+ /*
+ * Set the "broadcast" flag...
+ */
+
+ val = 1;
+ if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set broadcast mode - %s.",
+ strerror(errno));
+
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
+
+ BrowseSocket = -1;
+ BrowseLocalProtocols &= ~BROWSE_CUPS;
+ BrowseRemoteProtocols &= ~BROWSE_CUPS;
+
+ if (FatalErrors & CUPSD_FATAL_BROWSE)
+ cupsdEndProcess(getpid(), 0);
+ }
+ }
+
+ if (BrowseSocket >= 0)
+ {
+ /*
+ * Close the socket on exec...
+ */
+
+ fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
+
+ /*
+ * Finally, add the socket to the input selection set as needed...
+ */
+
+ if (BrowseRemoteProtocols & BROWSE_CUPS)
+ {
+ /*
+ * We only listen if we want remote printers...
+ */
+
+ cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse,
+ NULL, NULL);
+ }
+ }
+ }
+ else
+ BrowseSocket = -1;
+
+#ifdef HAVE_DNSSD
+ if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD)
+ {
+ DNSServiceErrorType error; /* Error from service creation */
+ cupsd_listener_t *lis; /* Current listening socket */
+
+
+ /*
+ * First create a "master" connection for all registrations...
+ */
+
+ if ((error = DNSServiceCreateConnection(&DNSSDRef))
+ != kDNSServiceErr_NoError)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create master DNS-SD reference: %d", error);
+
+ if (FatalErrors & CUPSD_FATAL_BROWSE)
+ cupsdEndProcess(getpid(), 0);
+ }
+ else
+ {
+ /*
+ * Add the master connection to the select list...
+ */
+
+ int fd = DNSServiceRefSockFD(DNSSDRef);
+
+ fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+
+ cupsdAddSelect(fd, (cupsd_selfunc_t)dnssdUpdate, NULL, NULL);
+
+ /*
+ * Then get the port we use for registrations. If we are not listening
+ * on any non-local ports, there is no sense sharing local printers via
+ * Bonjour...
+ */
+
+ DNSSDPort = 0;
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ {
+ if (httpAddrLocalhost(&(lis->address)))
+ continue;
+
+ DNSSDPort = _httpAddrPort(&(lis->address));
+ break;
+ }
+
+ /*
+ * Create an array to track the printers we share...
+ */
+
+ if (BrowseRemoteProtocols & BROWSE_DNSSD)
+ DNSSDPrinters = cupsArrayNew((cups_array_func_t)dnssdComparePrinters,
+ NULL);
+
+ /*
+ * Set the computer name and register the web interface...
+ */
+
+ cupsdUpdateDNSSDName();
+ }
+ }
+#endif /* HAVE_DNSSD */
+
+#ifdef HAVE_LIBSLP
+ if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
+ {
+ /*
+ * Open SLP handle...
+ */
+
+ if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to open an SLP handle; disabling SLP browsing!");
+ BrowseLocalProtocols &= ~BROWSE_SLP;
+ BrowseRemoteProtocols &= ~BROWSE_SLP;
+ BrowseSLPHandle = NULL;
+
+ if (FatalErrors & CUPSD_FATAL_BROWSE)
+ cupsdEndProcess(getpid(), 0);
+ }
+
+ BrowseSLPRefresh = 0;
+ }
+ else
+ BrowseSLPHandle = NULL;
+#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_LDAP
+ if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP)
+ {
+ if (!BrowseLDAPDN)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Need to set BrowseLDAPDN to use LDAP browsing!");
+ BrowseLocalProtocols &= ~BROWSE_LDAP;
+ BrowseRemoteProtocols &= ~BROWSE_LDAP;
+
+ if (FatalErrors & CUPSD_FATAL_BROWSE)
+ cupsdEndProcess(getpid(), 0);
+ }
+ else
+ {
+ /*
+ * Open LDAP handle...
+ */
+
+ if ((BrowseLDAPHandle = ldap_connect()) == NULL &&
+ (FatalErrors & CUPSD_FATAL_BROWSE))
+ cupsdEndProcess(getpid(), 0);
+ }
+
+ BrowseLDAPRefresh = 0;
+ }
+#endif /* HAVE_LDAP */
+
+ /*
+ * Enable LPD and SMB printer sharing as needed through external programs...
+ */
+
+ if (BrowseLocalProtocols & BROWSE_LPD)
+ update_lpd(1);
+
+ if (BrowseLocalProtocols & BROWSE_SMB)
+ update_smb(1);
+
+ /*
+ * Register the individual printers
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_SCANNER)))
+ cupsdRegisterPrinter(p);
+}
+
+
+/*
+ * 'cupsdStartPolling()' - Start polling servers as needed.
+ */
+
+void
+cupsdStartPolling(void)
+{
+ int i; /* Looping var */
+ cupsd_dirsvc_poll_t *pollp; /* Current polling server */
+ char polld[1024]; /* Poll daemon path */
+ char sport[255]; /* Server port */
+ char bport[255]; /* Browser port */
+ char interval[255]; /* Poll interval */
+ int statusfds[2]; /* Status pipe */
+ char *argv[6]; /* Arguments */
+ char *envp[100]; /* Environment */
+
+
+ /*
+ * Don't do anything if we aren't polling...
+ */
+
+ if (NumPolled == 0 || BrowseSocket < 0)
+ {
+ PollPipe = -1;
+ PollStatusBuffer = NULL;
+ return;
+ }
+
+ /*
+ * Setup string arguments for polld, port and interval options.
+ */
+
+ snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin);
+
+ sprintf(bport, "%d", BrowsePort);
+
+ if (BrowseInterval)
+ sprintf(interval, "%d", BrowseInterval);
+ else
+ strcpy(interval, "30");
+
+ argv[0] = "cups-polld";
+ argv[2] = sport;
+ argv[3] = interval;
+ argv[4] = bport;
+ argv[5] = NULL;
+
+ cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
+
+ /*
+ * Create a pipe that receives the status messages from each
+ * polling daemon...
+ */
+
+ if (cupsdOpenPipe(statusfds))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create polling status pipes - %s.",
+ strerror(errno));
+ PollPipe = -1;
+ PollStatusBuffer = NULL;
+ return;
+ }
+
+ PollPipe = statusfds[0];
+ PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]");
+
+ /*
+ * Run each polling daemon, redirecting stderr to the polling pipe...
+ */
+
+ for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
+ {
+ sprintf(sport, "%d", pollp->port);
+
+ argv[1] = pollp->hostname;
+
+ if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1,
+ 0, DefaultProfile, NULL, &(pollp->pid)) < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdStartPolling: Unable to fork polling daemon - %s",
+ strerror(errno));
+ pollp->pid = 0;
+ break;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
+ pollp->hostname, pollp->port, pollp->pid);
+ }
+
+ close(statusfds[1]);
+
+ /*
+ * Finally, add the pipe to the input selection set...
+ */
+
+ cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL);
+}
+
+
+/*
+ * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
+ */
+
+void
+cupsdStopBrowsing(void)
+{
+ cupsd_printer_t *p; /* Current printer */
+
+
+ if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
+ return;
+
+ /*
+ * De-register the individual printers
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_SCANNER)))
+ cupsdDeregisterPrinter(p, 1);
+
+ /*
+ * Shut down browsing sockets...
+ */
+
+ if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
+ BrowseSocket >= 0)
+ {
+ /*
+ * Close the socket and remove it from the input selection set.
+ */
+
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
+
+ cupsdRemoveSelect(BrowseSocket);
+ BrowseSocket = -1;
+ }
+
+#ifdef HAVE_DNSSD
+ if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
+ dnssdStop();
+#endif /* HAVE_DNSSD */
+
+#ifdef HAVE_LIBSLP
+ if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
+ BrowseSLPHandle)
+ {
+ /*
+ * Close SLP handle...
+ */
+
+ SLPClose(BrowseSLPHandle);
+ BrowseSLPHandle = NULL;
+ }
+#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_LDAP
+ if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) &&
+ BrowseLDAPHandle)
+ {
+ ldap_dereg_ou(ServerName, BrowseLDAPDN);
+ ldap_disconnect(BrowseLDAPHandle);
+ BrowseLDAPHandle = NULL;
+ }
+#endif /* HAVE_OPENLDAP */
+
+ /*
+ * Disable LPD and SMB printer sharing as needed through external programs...
+ */
+
+ if (BrowseLocalProtocols & BROWSE_LPD)
+ update_lpd(0);
+
+ if (BrowseLocalProtocols & BROWSE_SMB)
+ update_smb(0);
+}
+
+
+/*
+ * 'cupsdStopPolling()' - Stop polling servers as needed.
+ */
+
+void
+cupsdStopPolling(void)
+{
+ int i; /* Looping var */
+ cupsd_dirsvc_poll_t *pollp; /* Current polling server */
+
+
+ if (PollPipe >= 0)
+ {
+ cupsdStatBufDelete(PollStatusBuffer);
+ close(PollPipe);
+
+ cupsdRemoveSelect(PollPipe);
+
+ PollPipe = -1;
+ PollStatusBuffer = NULL;
+ }
+
+ for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
+ if (pollp->pid)
+ cupsdEndProcess(pollp->pid, 0);
+}
+
+
+#ifdef HAVE_DNSSD
+/*
+ * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
+ */
+
+void
+cupsdUpdateDNSSDName(void)
+{
+ DNSServiceErrorType error; /* Error from service creation */
+ char webif[1024]; /* Web interface share name */
+# ifdef HAVE_SYSTEMCONFIGURATION
+ SCDynamicStoreRef sc; /* Context for dynamic store */
+ CFDictionaryRef btmm; /* Back-to-My-Mac domains */
+ CFStringEncoding nameEncoding; /* Encoding of computer name */
+ CFStringRef nameRef; /* Host name CFString */
+ char nameBuffer[1024]; /* C-string buffer */
+# endif /* HAVE_SYSTEMCONFIGURATION */
+
+
+ /*
+ * Only share the web interface and printers when non-local listening is
+ * enabled...
+ */
+
+
+ if (!DNSSDPort)
+ return;
+
+ /*
+ * Get the computer name as a c-string...
+ */
+
+# ifdef HAVE_SYSTEMCONFIGURATION
+ sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"), NULL, NULL);
+
+ if (sc)
+ {
+ /*
+ * Get the computer name from the dynamic store...
+ */
+
+ cupsdClearString(&DNSSDComputerName);
+
+ if ((nameRef = SCDynamicStoreCopyComputerName(sc, &nameEncoding)) != NULL)
+ {
+ if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
+ kCFStringEncodingUTF8))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Dynamic store computer name is \"%s\".", nameBuffer);
+ cupsdSetString(&DNSSDComputerName, nameBuffer);
+ }
+
+ CFRelease(nameRef);
+ }
+
+ if (!DNSSDComputerName)
+ {
+ /*
+ * Use the ServerName instead...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Using ServerName \"%s\" as computer name.", ServerName);
+ cupsdSetString(&DNSSDComputerName, ServerName);
+ }
+
+ /*
+ * Get the local hostname from the dynamic store...
+ */
+
+ cupsdClearString(&DNSSDHostName);
+
+ if ((nameRef = SCDynamicStoreCopyLocalHostName(sc)) != NULL)
+ {
+ if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
+ kCFStringEncodingUTF8))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Dynamic store host name is \"%s\".", nameBuffer);
+ cupsdSetString(&DNSSDHostName, nameBuffer);
+ }
+
+ CFRelease(nameRef);
+ }
+
+ if (!DNSSDHostName)
+ {
+ /*
+ * Use the ServerName instead...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Using ServerName \"%s\" as host name.", ServerName);
+ cupsdSetString(&DNSSDHostName, ServerName);
+ }
+
+ /*
+ * Get any Back-to-My-Mac domains and add them as aliases...
+ */
+
+ cupsdFreeAliases(DNSSDAlias);
+ DNSSDAlias = NULL;
+
+ btmm = SCDynamicStoreCopyValue(sc, CFSTR("Setup:/Network/BackToMyMac"));
+ if (btmm && CFGetTypeID(btmm) == CFDictionaryGetTypeID())
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "%d Back to My Mac aliases to add.",
+ (int)CFDictionaryGetCount(btmm));
+ CFDictionaryApplyFunction(btmm, dnssdAddAlias, NULL);
+ }
+ else if (btmm)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad Back to My Mac data in dynamic store!");
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "No Back to My Mac aliases to add.");
+
+ if (btmm)
+ CFRelease(btmm);
+
+ CFRelease(sc);
+ }
+ else
+# endif /* HAVE_SYSTEMCONFIGURATION */
+ {
+ cupsdSetString(&DNSSDComputerName, ServerName);
+ cupsdSetString(&DNSSDHostName, ServerName);
+ }
+
+ /*
+ * Then (re)register the web interface if enabled...
+ */
+
+ if (BrowseWebIF)
+ {
+ if (DNSSDComputerName)
+ snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDComputerName);
+ else
+ strlcpy(webif, "CUPS Web Interface", sizeof(webif));
+
+ if (WebIFRef)
+ DNSServiceRefDeallocate(WebIFRef);
+
+ WebIFRef = DNSSDRef;
+ if ((error = DNSServiceRegister(&WebIFRef,
+ kDNSServiceFlagsShareConnection,
+ 0, webif, "_http._tcp", NULL,
+ NULL, htons(DNSSDPort), 7,
+ "\006path=/", dnssdRegisterCallback,
+ NULL)) != kDNSServiceErr_NoError)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "DNS-SD web interface registration failed: %d", error);
+ }
+}
+#endif /* HAVE_DNSSD */
+
+
+#ifdef HAVE_LDAP
+/*
+ * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
+ */
+
+void
+cupsdUpdateLDAPBrowse(void)
+{
+ char uri[HTTP_MAX_URI], /* Printer URI */
+ host[HTTP_MAX_URI], /* Hostname */
+ resource[HTTP_MAX_URI], /* Resource path */
+ location[1024], /* Printer location */
+ info[1024], /* Printer information */
+ make_model[1024], /* Printer make and model */
+ type_num[30]; /* Printer type number */
+ int type; /* Printer type */
+ int rc; /* LDAP status */
+ int limit; /* Size limit */
+ LDAPMessage *res, /* LDAP search results */
+ *e; /* Current entry from search */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
+
+ BrowseLDAPRefresh = time(NULL) + BrowseInterval;
+
+ /*
+ * Reconnect if LDAP Handle is invalid...
+ */
+
+ if (! BrowseLDAPHandle)
+ {
+ ldap_reconnect();
+ return;
+ }
+
+ /*
+ * Search for cups printers in LDAP directory...
+ */
+
+ rc = ldap_search_rec(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
+ "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
+
+ /*
+ * If ldap search was successfull then exit function
+ * and temporary disable LDAP updates...
+ */
+
+ if (rc != LDAP_SUCCESS)
+ {
+ if (BrowseLDAPUpdate && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR)))
+ {
+ BrowseLDAPUpdate = FALSE;
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "LDAP update temporary disabled");
+ }
+ return;
+ }
+
+ /*
+ * If LDAP updates were disabled, we will reenable them...
+ */
+
+ if (! BrowseLDAPUpdate)
+ {
+ BrowseLDAPUpdate = TRUE;
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "LDAP update enabled");
+ }
+
+ /*
+ * Count LDAP entries and return if no entry exist...
+ */
+
+ limit = ldap_count_entries(BrowseLDAPHandle, res);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
+ if (limit < 1)
+ {
+ ldap_freeres(res);
+ return;
+ }
+
+ /*
+ * Loop through the available printers...
+ */
+
+ for (e = ldap_first_entry(BrowseLDAPHandle, res);
+ e;
+ e = ldap_next_entry(BrowseLDAPHandle, e))
+ {
+ /*
+ * Get the required values from this entry...
+ */
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e,
+ "printerDescription", info, sizeof(info)) == -1)
+ continue;
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e,
+ "printerLocation", location, sizeof(location)) == -1)
+ continue;
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e,
+ "printerMakeAndModel", make_model, sizeof(make_model)) == -1)
+ continue;
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e,
+ "printerType", type_num, sizeof(type_num)) == -1)
+ continue;
+
+ type = atoi(type_num);
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e,
+ "printerURI", uri, sizeof(uri)) == -1)
+ continue;
+
+ /*
+ * Process the entry as browse data...
+ */
+
+ if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
+ process_browse_data(uri, host, resource, type, IPP_PRINTER_IDLE,
+ location, info, make_model, 0, NULL);
+
+ }
+
+ ldap_freeres(res);
+}
+#endif /* HAVE_LDAP */
+
+
+#ifdef HAVE_LIBSLP
+/*
+ * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
+ */
+
+void
+cupsdUpdateSLPBrowse(void)
+{
+ slpsrvurl_t *s, /* Temporary list of service URLs */
+ *next; /* Next service in list */
+ cupsd_printer_t p; /* Printer information */
+ const char *uri; /* Pointer to printer URI */
+ char host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+
+
+ /*
+ * Reset the refresh time...
+ */
+
+ BrowseSLPRefresh = time(NULL) + BrowseInterval;
+
+ /*
+ * Poll for remote printers using SLP...
+ */
+
+ s = NULL;
+
+ SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
+ slp_url_callback, &s);
+
+ /*
+ * Loop through the list of available printers...
+ */
+
+ for (; s; s = next)
+ {
+ /*
+ * Save the "next" pointer...
+ */
+
+ next = s->next;
+
+ /*
+ * Load a cupsd_printer_t structure with the SLP service attributes...
+ */
+
+ SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
+
+ /*
+ * Process this printer entry...
+ */
+
+ uri = s->url + SLP_CUPS_SRVLEN + 1;
+
+ if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6))
+ {
+ /*
+ * Pull the URI apart to see if this is a local or remote printer...
+ */
+
+ if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
+ process_browse_data(uri, host, resource, p.type, IPP_PRINTER_IDLE,
+ p.location, p.info, p.make_model, 0, NULL);
+ }
+
+ /*
+ * Free this listing...
+ */
+
+ cupsdClearString(&p.info);
+ cupsdClearString(&p.location);
+ cupsdClearString(&p.make_model);
+
+ free(s);
+ }
+}
+#endif /* HAVE_LIBSLP */
+
+
+/*
+ * 'dequote()' - Remote quotes from a string.
+ */
+
+static char * /* O - Dequoted string */
+dequote(char *d, /* I - Destination string */
+ const char *s, /* I - Source string */
+ int dlen) /* I - Destination length */
+{
+ char *dptr; /* Pointer into destination */
+
+
+ if (s)
+ {
+ for (dptr = d, dlen --; *s && dlen > 0; s ++)
+ if (*s != '\"')
+ {
+ *dptr++ = *s;
+ dlen --;
+ }
+
+ *dptr = '\0';
+ }
+ else
+ *d = '\0';
+
+ return (d);
+}
+
+
+#ifdef HAVE_DNSSD
+# ifdef HAVE_COREFOUNDATION
+/*
+ * 'dnssdAddAlias()' - Add a DNS-SD alias name.
+ */
+
+static void
+dnssdAddAlias(const void *key, /* I - Key */
+ const void *value, /* I - Value (domain) */
+ void *context) /* I - Unused */
+{
+ char valueStr[1024], /* Domain string */
+ hostname[1024]; /* Complete hostname */
+
+
+ (void)key;
+ (void)context;
+
+ if (CFGetTypeID((CFStringRef)value) == CFStringGetTypeID() &&
+ CFStringGetCString((CFStringRef)value, valueStr, sizeof(valueStr),
+ kCFStringEncodingUTF8))
+ {
+ snprintf(hostname, sizeof(hostname), "%s.%s", DNSSDHostName, valueStr);
+ if (!DNSSDAlias)
+ DNSSDAlias = cupsArrayNew(NULL, NULL);
+
+ cupsdAddAlias(DNSSDAlias, hostname);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added Back to My Mac ServerAlias %s",
+ hostname);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad Back to My Mac domain in dynamic store!");
+}
+# endif /* HAVE_COREFOUNDATION */
+
+
+/*
+ * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
+ */
+
+static char * /* O - TXT record */
+dnssdBuildTxtRecord(
+ int *txt_len, /* O - TXT record length */
+ cupsd_printer_t *p, /* I - Printer information */
+ int for_lpd) /* I - 1 = LPD, 0 = IPP */
+{
+ int i; /* Looping var */
+ char admin_hostname[256], /* .local hostname for admin page */
+ adminurl_str[256], /* URL for the admin page */
+ type_str[32], /* Type to string buffer */
+ state_str[32], /* State to string buffer */
+ rp_str[1024], /* Queue name string buffer */
+ air_str[1024], /* auth-info-required string buffer */
+ *keyvalue[32][2]; /* Table of key/value pairs */
+
+
+ /*
+ * Load up the key value pairs...
+ */
+
+ i = 0;
+
+ keyvalue[i ][0] = "txtvers";
+ keyvalue[i++][1] = "1";
+
+ keyvalue[i ][0] = "qtotal";
+ keyvalue[i++][1] = "1";
+
+ keyvalue[i ][0] = "rp";
+ keyvalue[i++][1] = rp_str;
+ if (for_lpd)
+ strlcpy(rp_str, p->name, sizeof(rp_str));
+ else
+ snprintf(rp_str, sizeof(rp_str), "%s/%s",
+ (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
+
+ keyvalue[i ][0] = "ty";
+ keyvalue[i++][1] = p->make_model ? p->make_model : "Unknown";
+
+ snprintf(admin_hostname, sizeof(admin_hostname), "%s.local.", DNSSDHostName);
+ httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str),
+ "http", NULL, admin_hostname, DNSSDPort, "/%s/%s",
+ (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers",
+ p->name);
+ keyvalue[i ][0] = "adminurl";
+ keyvalue[i++][1] = adminurl_str;
+
+ keyvalue[i ][0] = "note";
+ keyvalue[i++][1] = p->location ? p->location : "";
+
+ keyvalue[i ][0] = "priority";
+ keyvalue[i++][1] = for_lpd ? "100" : "0";
+
+ keyvalue[i ][0] = "product";
+ keyvalue[i++][1] = p->pc && p->pc->product ? p->pc->product : "Unknown";
+
+ keyvalue[i ][0] = "pdl";
+ keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
+
+ if (get_auth_info_required(p, air_str, sizeof(air_str)))
+ {
+ keyvalue[i ][0] = "air";
+ keyvalue[i++][1] = air_str;
+ }
+
+ keyvalue[i ][0] = "UUID";
+ keyvalue[i++][1] = p->uuid + 9;
+
+#ifdef HAVE_SSL
+ keyvalue[i ][0] = "TLS";
+ keyvalue[i++][1] = "1.2";
+#endif /* HAVE_SSL */
+
+ keyvalue[i ][0] = "Transparent";
+ keyvalue[i++][1] = "F";
+
+ keyvalue[i ][0] = "Binary";
+ keyvalue[i++][1] = "F";
+
+ keyvalue[i ][0] = "Fax";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_FAX) ? "T" : "F";
+
+ keyvalue[i ][0] = "Color";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLOR) ? "T" : "F";
+
+ keyvalue[i ][0] = "Duplex";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_DUPLEX) ? "T" : "F";
+
+ keyvalue[i ][0] = "Staple";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_STAPLE) ? "T" : "F";
+
+ keyvalue[i ][0] = "Copies";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_COPIES) ? "T" : "F";
+
+ keyvalue[i ][0] = "Collate";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLLATE) ? "T" : "F";
+
+ keyvalue[i ][0] = "Punch";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_PUNCH) ? "T" : "F";
+
+ keyvalue[i ][0] = "Bind";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_BIND) ? "T" : "F";
+
+ keyvalue[i ][0] = "Sort";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_SORT) ? "T" : "F";
+
+ keyvalue[i ][0] = "Scan";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_MFP) ? "T" : "F";
+
+ snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
+ snprintf(state_str, sizeof(state_str), "%d", p->state);
+
+ keyvalue[i ][0] = "printer-state";
+ keyvalue[i++][1] = state_str;
+
+ keyvalue[i ][0] = "printer-type";
+ keyvalue[i++][1] = type_str;
+
+ /*
+ * Then pack them into a proper txt record...
+ */
+
+ return (dnssdPackTxtRecord(txt_len, keyvalue, i));
+}
+
+
+/*
+ * 'dnssdComparePrinters()' - Compare the registered names of two printers.
+ */
+
+static int /* O - Result of comparison */
+dnssdComparePrinters(cupsd_printer_t *a,/* I - First printer */
+ cupsd_printer_t *b)/* I - Second printer */
+{
+ return (_cups_strcasecmp(a->reg_name, b->reg_name));
+}
+
+
+/*
+ * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
+ * printer.
+ */
+
+static void
+dnssdDeregisterPrinter(
+ cupsd_printer_t *p) /* I - Printer */
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
+
+ /*
+ * Closing the socket deregisters the service
+ */
+
+ if (p->ipp_ref)
+ {
+ DNSServiceRefDeallocate(p->ipp_ref);
+ p->ipp_ref = NULL;
+ }
+
+ if (p->ipp_txt)
+ {
+ /*
+ * p->ipp_txt is malloc'd, not _cupsStrAlloc'd...
+ */
+
+ free(p->ipp_txt);
+ p->ipp_txt = NULL;
+ }
+
+ if (p->printer_ref)
+ {
+ DNSServiceRefDeallocate(p->printer_ref);
+ p->printer_ref = NULL;
+ }
+
+ if (p->printer_txt)
+ {
+ /*
+ * p->printer_txt is malloc'd, not _cupsStrAlloc'd...
+ */
+
+ free(p->printer_txt);
+ p->printer_txt = NULL;
+ }
+
+ /*
+ * Remove the printer from the array of DNS-SD printers, then clear the
+ * registered name...
+ */
+
+ cupsArrayRemove(DNSSDPrinters, p);
+ cupsdClearString(&p->reg_name);
+}
+
+
+/*
+ * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
+ * TXT record format.
+ */
+
+static char * /* O - TXT record */
+dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */
+ char *keyvalue[][2], /* I - Table of key value pairs */
+ int count) /* I - Items in table */
+{
+ int i; /* Looping var */
+ int length; /* Length of TXT record */
+ int length2; /* Length of value */
+ char *txtRecord; /* TXT record buffer */
+ char *cursor; /* Looping pointer */
+
+
+ /*
+ * Calculate the buffer size
+ */
+
+ if (count <= 0)
+ return (NULL);
+
+ for (length = i = 0; i < count; i++)
+ length += 1 + strlen(keyvalue[i][0]) +
+ (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
+
+ /*
+ * Allocate and fill it
+ */
+
+ txtRecord = malloc(length);
+ if (txtRecord)
+ {
+ *txt_len = length;
+
+ for (cursor = txtRecord, i = 0; i < count; i++)
+ {
+ /*
+ * Drop in the p-string style length byte followed by the data
+ */
+
+ length = strlen(keyvalue[i][0]);
+ length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
+
+ *cursor++ = (unsigned char)(length + length2);
+
+ memcpy(cursor, keyvalue[i][0], length);
+ cursor += length;
+
+ if (length2)
+ {
+ length2 --;
+ *cursor++ = '=';
+ memcpy(cursor, keyvalue[i][1], length2);
+ cursor += length2;
+ }
+ }
+ }
+
+ return (txtRecord);
+}
+
+
+/*
+ * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
+ */
+
+static void
+dnssdRegisterCallback(
+ DNSServiceRef sdRef, /* I - DNS Service reference */
+ DNSServiceFlags flags, /* I - Reserved for future use */
+ DNSServiceErrorType errorCode, /* I - Error code */
+ const char *name, /* I - Service name */
+ const char *regtype, /* I - Service type */
+ const char *domain, /* I - Domain. ".local" for now */
+ void *context) /* I - User-defined context */
+{
+ cupsd_printer_t *p = (cupsd_printer_t *)context;
+ /* Current printer */
+
+
+ (void)sdRef;
+ (void)flags;
+ (void)domain;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s (%s)",
+ name, regtype, p ? p->name : "Web Interface",
+ p ? (p->reg_name ? p->reg_name : "(null)") : "NA");
+
+ if (errorCode)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "DNSServiceRegister failed with error %d", (int)errorCode);
+ return;
+ }
+ else if (p && (!p->reg_name || _cups_strcasecmp(name, p->reg_name)))
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
+ name, p->name);
+
+ cupsArrayRemove(DNSSDPrinters, p);
+ cupsdSetString(&p->reg_name, name);
+ cupsArrayAdd(DNSSDPrinters, p);
+
+ LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
+ }
+}
+
+
+/*
+ * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
+ * or update the broadcast contents.
+ */
+
+static void
+dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
+{
+ DNSServiceErrorType se; /* dnssd errors */
+ char *ipp_txt, /* IPP TXT record buffer */
+ *printer_txt, /* LPD TXT record buffer */
+ name[1024], /* Service name */
+ *nameptr; /* Pointer into name */
+ int ipp_len, /* IPP TXT record length */
+ printer_len, /* LPD TXT record length */
+ printer_port; /* LPD port number */
+ const char *regtype; /* Registration type */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
+ !p->ipp_ref ? "new" : "update");
+
+ /*
+ * If per-printer sharing was just disabled make sure we're not
+ * registered before returning.
+ */
+
+ if (!p->shared)
+ {
+ dnssdDeregisterPrinter(p);
+ return;
+ }
+
+ /*
+ * The registered name takes the form of "<printer-info> @ <computer name>"...
+ */
+
+ if (p->info && strlen(p->info) > 0)
+ {
+ if (DNSSDComputerName)
+ snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDComputerName);
+ else
+ strlcpy(name, p->info, sizeof(name));
+ }
+ else if (DNSSDComputerName)
+ snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDComputerName);
+ else
+ strlcpy(name, p->name, sizeof(name));
+
+ /*
+ * If an existing printer was renamed, unregister it and start over...
+ */
+
+ if (p->reg_name && strcmp(p->reg_name, name))
+ dnssdDeregisterPrinter(p);
+
+ if (!p->reg_name)
+ {
+ cupsdSetString(&p->reg_name, name);
+ cupsArrayAdd(DNSSDPrinters, p);
+ }
+
+ /*
+ * Register IPP and (optionally) LPD...
+ */
+
+ ipp_len = 0; /* anti-compiler-warning-code */
+ ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0);
+
+ if (p->ipp_ref &&
+ (ipp_len != p->ipp_len || memcmp(ipp_txt, p->ipp_txt, ipp_len)))
+ {
+ /*
+ * Update the existing registration...
+ */
+
+ /* A TTL of 0 means use record's original value (Radar 3176248) */
+ if ((se = DNSServiceUpdateRecord(p->ipp_ref, NULL, 0, ipp_len, ipp_txt,
+ 0)) == kDNSServiceErr_NoError)
+ {
+ if (p->ipp_txt)
+ free(p->ipp_txt);
+
+ p->ipp_txt = ipp_txt;
+ p->ipp_len = ipp_len;
+ ipp_txt = NULL;
+ }
+ else
+ {
+ /*
+ * Failed to update record, lets close this reference and move on...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to update IPP DNS-SD record for %s - %d", p->name,
+ se);
+
+ DNSServiceRefDeallocate(p->ipp_ref);
+ p->ipp_ref = NULL;
+ }
+ }
+
+ if (!p->ipp_ref)
+ {
+ /*
+ * Initial registration. Use the _fax-ipp regtype for fax queues...
+ */
+
+ regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" : DNSSDRegType;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Registering DNS-SD printer %s with name \"%s\" and "
+ "type \"%s\"", p->name, name, regtype);
+
+ /*
+ * Register the queue, dropping characters as needed until we succeed...
+ */
+
+ nameptr = name + strlen(name);
+
+ do
+ {
+ p->ipp_ref = DNSSDRef;
+ if ((se = DNSServiceRegister(&p->ipp_ref, kDNSServiceFlagsShareConnection,
+ 0, name, regtype, NULL, NULL,
+ htons(DNSSDPort), ipp_len, ipp_txt,
+ dnssdRegisterCallback,
+ p)) == kDNSServiceErr_BadParam)
+ {
+ /*
+ * Name is too long, drop trailing characters, taking into account
+ * UTF-8 encoding...
+ */
+
+ nameptr --;
+
+ while (nameptr > name && (*nameptr & 0xc0) == 0x80)
+ nameptr --;
+
+ if (nameptr > name)
+ *nameptr = '\0';
+ }
+ }
+ while (se == kDNSServiceErr_BadParam && nameptr > name);
+
+ if (se == kDNSServiceErr_NoError)
+ {
+ p->ipp_txt = ipp_txt;
+ p->ipp_len = ipp_len;
+ ipp_txt = NULL;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "DNS-SD IPP registration of \"%s\" failed: %d",
+ p->name, se);
+ }
+
+ if (ipp_txt)
+ free(ipp_txt);
+
+ if (BrowseLocalProtocols & BROWSE_LPD)
+ {
+ printer_len = 0; /* anti-compiler-warning-code */
+ printer_port = 515;
+ printer_txt = dnssdBuildTxtRecord(&printer_len, p, 1);
+ }
+ else
+ {
+ printer_len = 0;
+ printer_port = 0;
+ printer_txt = NULL;
+ }
+
+ if (p->printer_ref &&
+ (printer_len != p->printer_len ||
+ memcmp(printer_txt, p->printer_txt, printer_len)))
+ {
+ /*
+ * Update the existing registration...
+ */
+
+ /* A TTL of 0 means use record's original value (Radar 3176248) */
+ if ((se = DNSServiceUpdateRecord(p->printer_ref, NULL, 0, printer_len,
+ printer_txt,
+ 0)) == kDNSServiceErr_NoError)
+ {
+ if (p->printer_txt)
+ free(p->printer_txt);
+
+ p->printer_txt = printer_txt;
+ p->printer_len = printer_len;
+ printer_txt = NULL;
+ }
+ else
+ {
+ /*
+ * Failed to update record, lets close this reference and move on...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to update LPD DNS-SD record for %s - %d",
+ p->name, se);
+
+ DNSServiceRefDeallocate(p->printer_ref);
+ p->printer_ref = NULL;
+ }
+ }
+
+ if (!p->printer_ref)
+ {
+ /*
+ * Initial registration...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Registering DNS-SD printer %s with name \"%s\" and "
+ "type \"_printer._tcp\"", p->name, name);
+
+ p->printer_ref = DNSSDRef;
+ if ((se = DNSServiceRegister(&p->printer_ref,
+ kDNSServiceFlagsShareConnection,
+ 0, name, "_printer._tcp", NULL, NULL,
+ htons(printer_port), printer_len, printer_txt,
+ dnssdRegisterCallback,
+ p)) == kDNSServiceErr_NoError)
+ {
+ p->printer_txt = printer_txt;
+ p->printer_len = printer_len;
+ printer_txt = NULL;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "DNS-SD LPD registration of \"%s\" failed: %d",
+ p->name, se);
+ }
+
+ if (printer_txt)
+ free(printer_txt);
+}
+
+
+/*
+ * 'dnssdStop()' - Stop all DNS-SD registrations.
+ */
+
+static void
+dnssdStop(void)
+{
+ cupsd_printer_t *p; /* Current printer */
+
+
+ /*
+ * De-register the individual printers
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ dnssdDeregisterPrinter(p);
+
+ /*
+ * Shutdown the rest of the service refs...
+ */
+
+ if (WebIFRef)
+ {
+ DNSServiceRefDeallocate(WebIFRef);
+ WebIFRef = NULL;
+ }
+
+ if (RemoteRef)
+ {
+ DNSServiceRefDeallocate(RemoteRef);
+ RemoteRef = NULL;
+ }
+
+ cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDRef));
+
+ DNSServiceRefDeallocate(DNSSDRef);
+ DNSSDRef = NULL;
+
+ cupsArrayDelete(DNSSDPrinters);
+ DNSSDPrinters = NULL;
+
+ DNSSDPort = 0;
+}
+
+
+/*
+ * 'dnssdUpdate()' - Handle DNS-SD queries.
+ */
+
+static void
+dnssdUpdate(void)
+{
+ DNSServiceErrorType sdErr; /* Service discovery error */
+
+
+ if ((sdErr = DNSServiceProcessResult(DNSSDRef)) != kDNSServiceErr_NoError)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "DNS Service Discovery registration error %d!",
+ sdErr);
+ dnssdStop();
+ }
+}
+#endif /* HAVE_DNSSD */
+
+
+/*
+ * 'get_auth_info_required()' - Get the auth-info-required value to advertise.
+ */
+
+static char * /* O - String or NULL if none */
+get_auth_info_required(
+ cupsd_printer_t *p, /* I - Printer */
+ char *buffer, /* I - Value buffer */
+ size_t bufsize) /* I - Size of value buffer */
+{
+ cupsd_location_t *auth; /* Pointer to authentication element */
+ char resource[1024]; /* Printer/class resource path */
+
+
+ /*
+ * If auth-info-required is set for this printer, return that...
+ */
+
+ if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none"))
+ {
+ int i; /* Looping var */
+ char *bufptr; /* Pointer into buffer */
+
+ for (i = 0, bufptr = buffer; i < p->num_auth_info_required; i ++)
+ {
+ if (bufptr >= (buffer + bufsize - 2))
+ break;
+
+ if (i)
+ *bufptr++ = ',';
+
+ strlcpy(bufptr, p->auth_info_required[i], bufsize - (bufptr - buffer));
+ bufptr += strlen(bufptr);
+ }
+
+ return (buffer);
+ }
+
+ /*
+ * Figure out the authentication data requirements to advertise...
+ */
+
+ if (p->type & CUPS_PRINTER_CLASS)
+ snprintf(resource, sizeof(resource), "/classes/%s", p->name);
+ else
+ snprintf(resource, sizeof(resource), "/printers/%s", p->name);
+
+ if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
+ auth->type == CUPSD_AUTH_NONE)
+ auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
+
+ if (auth)
+ {
+ int auth_type; /* Authentication type */
+
+ if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
+ auth_type = DefaultAuthType;
+
+ switch (auth_type)
+ {
+ case CUPSD_AUTH_NONE :
+ return (NULL);
+
+ case CUPSD_AUTH_NEGOTIATE :
+ strlcpy(buffer, "negotiate", bufsize);
+ break;
+
+ default :
+ strlcpy(buffer, "username,password", bufsize);
+ break;
+ }
+
+ return (buffer);
+ }
+
+ return ("none");
+}
+
+
+#ifdef __APPLE__
+/*
+ * 'get_hostconfig()' - Get an /etc/hostconfig service setting.
+ */
+
+static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
+get_hostconfig(const char *name) /* I - Name of service */
+{
+ cups_file_t *fp; /* Hostconfig file */
+ char line[1024], /* Line from file */
+ *ptr; /* Pointer to value */
+ int state = 1; /* State of service */
+
+
+ /*
+ * Try opening the /etc/hostconfig file; if we can't open it, assume that
+ * the service is enabled/auto.
+ */
+
+ if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL)
+ {
+ /*
+ * Read lines from the file until we find the service...
+ */
+
+ while (cupsFileGets(fp, line, sizeof(line)))
+ {
+ if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL)
+ continue;
+
+ *ptr++ = '\0';
+
+ if (!_cups_strcasecmp(line, name))
+ {
+ /*
+ * Found the service, see if it is set to "-NO-"...
+ */
+
+ if (!_cups_strncasecmp(ptr, "-NO-", 4))
+ state = 0;
+ break;
+ }
+ }
+
+ cupsFileClose(fp);
+ }
+
+ return (state);
+}
+#endif /* __APPLE__ */
+
+
+/*
+ * 'is_local_queue()' - Determine whether the URI points at a local queue.
+ */
+
+static int /* O - 1 = local, 0 = remote, -1 = bad URI */
+is_local_queue(const char *uri, /* I - Printer URI */
+ char *host, /* O - Host string */
+ int hostlen, /* I - Length of host buffer */
+ char *resource, /* O - Resource string */
+ int resourcelen) /* I - Length of resource buffer */
+{
+ char scheme[32], /* Scheme portion of URI */
+ username[HTTP_MAX_URI]; /* Username portion of URI */
+ int port; /* Port portion of URI */
+ cupsd_netif_t *iface; /* Network interface */
+
+
+ /*
+ * Pull the URI apart to see if this is a local or remote printer...
+ */
+
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
+ username, sizeof(username), host, hostlen, &port,
+ resource, resourcelen) < HTTP_URI_OK)
+ return (-1);
+
+ DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
+
+ /*
+ * Check for local server addresses...
+ */
+
+ if (!_cups_strcasecmp(host, ServerName) && port == LocalPort)
+ return (1);
+
+ cupsdNetIFUpdate();
+
+ for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
+ iface;
+ iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
+ if (!_cups_strcasecmp(host, iface->hostname) && port == iface->port)
+ return (1);
+
+ /*
+ * If we get here, the printer is remote...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'process_browse_data()' - Process new browse data.
+ */
+
+static void
+process_browse_data(
+ const char *uri, /* I - URI of printer/class */
+ const char *host, /* I - Hostname */
+ const char *resource, /* I - Resource path */
+ cups_ptype_t type, /* I - Printer type */
+ ipp_pstate_t state, /* I - Printer state */
+ const char *location, /* I - Printer location */
+ const char *info, /* I - Printer information */
+ const char *make_model, /* I - Printer make and model */
+ int num_attrs, /* I - Number of attributes */
+ cups_option_t *attrs) /* I - Attributes */
+{
+ int i; /* Looping var */
+ int update; /* Update printer attributes? */
+ char finaluri[HTTP_MAX_URI], /* Final URI for printer */
+ name[IPP_MAX_NAME], /* Name of printer */
+ newname[IPP_MAX_NAME], /* New name of printer */
+ *hptr, /* Pointer into hostname */
+ *sptr; /* Pointer into ServerName */
+ const char *shortname; /* Short queue name (queue) */
+ char local_make_model[IPP_MAX_NAME];
+ /* Local make and model */
+ cupsd_printer_t *p; /* Printer information */
+ const char *ipp_options, /* ipp-options value */
+ *lease_duration, /* lease-duration value */
+ *uuid; /* uuid value */
+ int is_class; /* Is this queue a class? */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "process_browse_data(uri=\"%s\", host=\"%s\", "
+ "resource=\"%s\", type=%x, state=%d, location=\"%s\", "
+ "info=\"%s\", make_model=\"%s\", num_attrs=%d, attrs=%p)",
+ uri, host, resource, type, state,
+ location ? location : "(nil)", info ? info : "(nil)",
+ make_model ? make_model : "(nil)", num_attrs, attrs);
+
+ /*
+ * Determine if the URI contains any illegal characters in it...
+ */
+
+ if (strncmp(uri, "ipp://", 6) || !host[0] ||
+ (strncmp(resource, "/printers/", 10) &&
+ strncmp(resource, "/classes/", 9)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad printer URI in browse data: %s", uri);
+ return;
+ }
+
+ if (strchr(resource, '?') ||
+ (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
+ (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad resource in browse data: %s",
+ resource);
+ return;
+ }
+
+ /*
+ * OK, this isn't a local printer; add any remote options...
+ */
+
+ ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
+
+ if (BrowseRemoteOptions)
+ {
+ if (BrowseRemoteOptions[0] == '?')
+ {
+ /*
+ * Override server-supplied options...
+ */
+
+ snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
+ }
+ else if (ipp_options)
+ {
+ /*
+ * Combine the server and local options...
+ */
+
+ snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
+ BrowseRemoteOptions);
+ }
+ else
+ {
+ /*
+ * Just use the local options...
+ */
+
+ snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
+ }
+
+ uri = finaluri;
+ }
+ else if (ipp_options)
+ {
+ /*
+ * Just use the server-supplied options...
+ */
+
+ snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
+ uri = finaluri;
+ }
+
+ /*
+ * See if we already have it listed in the Printers list, and add it if not...
+ */
+
+ type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
+ type &= ~CUPS_PRINTER_IMPLICIT;
+ update = 0;
+ hptr = strchr(host, '.');
+ sptr = strchr(ServerName, '.');
+ is_class = type & CUPS_PRINTER_CLASS;
+ uuid = cupsGetOption("uuid", num_attrs, attrs);
+
+ if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
+ {
+ /*
+ * Strip the common domain name components...
+ */
+
+ while (hptr != NULL)
+ {
+ if (!_cups_strcasecmp(hptr, sptr))
+ {
+ *hptr = '\0';
+ break;
+ }
+ else
+ hptr = strchr(hptr + 1, '.');
+ }
+ }
+
+ if (is_class)
+ {
+ /*
+ * Remote destination is a class...
+ */
+
+ if (!strncmp(resource, "/classes/", 9))
+ snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
+ else
+ return;
+
+ shortname = resource + 9;
+ }
+ else
+ {
+ /*
+ * Remote destination is a printer...
+ */
+
+ if (!strncmp(resource, "/printers/", 10))
+ snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
+ else
+ return;
+
+ shortname = resource + 10;
+ }
+
+ if (hptr && !*hptr)
+ *hptr = '.'; /* Resource FQDN */
+
+ if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
+ {
+ /*
+ * Long name doesn't exist, try short name...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "process_browse_data: %s not found...",
+ name);
+
+ if ((p = cupsdFindDest(shortname)) == NULL)
+ {
+ /*
+ * Short name doesn't exist, use it for this shared queue.
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_browse_data: %s not found...",
+ shortname);
+ strlcpy(name, shortname, sizeof(name));
+ }
+ else
+ {
+ /*
+ * Short name exists...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "process_browse_data: %s found, type=%x, hostname=%s...",
+ shortname, p->type, p->hostname ? p->hostname : "(nil)");
+
+ if (p->type & CUPS_PRINTER_IMPLICIT)
+ p = NULL; /* Don't replace implicit classes */
+ else if (p->hostname && _cups_strcasecmp(p->hostname, host))
+ {
+ /*
+ * Short name exists but is for a different host. If this is a remote
+ * queue, rename it and use the long name...
+ */
+
+ if (p->type & CUPS_PRINTER_REMOTE)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Renamed remote %s \"%s\" to \"%s@%s\"...",
+ is_class ? "class" : "printer", p->name, p->name,
+ p->hostname);
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
+ "%s \'%s\' deleted by directory services.",
+ is_class ? "Class" : "Printer", p->name);
+
+ snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
+ cupsdRenamePrinter(p, newname);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "%s \'%s\' added by directory services.",
+ is_class ? "Class" : "Printer", p->name);
+ }
+
+ /*
+ * Force creation with long name...
+ */
+
+ p = NULL;
+ }
+ }
+ }
+ else if (p)
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "process_browse_data: %s found, type=%x, hostname=%s...",
+ name, p->type, p->hostname ? p->hostname : "(nil)");
+
+ if (!p)
+ {
+ /*
+ * Queue doesn't exist; add it...
+ */
+
+ if (is_class)
+ p = cupsdAddClass(name);
+ else
+ p = cupsdAddPrinter(name);
+
+ if (!p)
+ return;
+
+ cupsdClearString(&(p->hostname));
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote %s \"%s\"...",
+ is_class ? "class" : "printer", name);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "%s \'%s\' added by directory services.",
+ is_class ? "Class" : "Printer", name);
+
+ /*
+ * Force the URI to point to the real server...
+ */
+
+ p->type = type & ~CUPS_PRINTER_REJECTING;
+ p->accepting = 1;
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+ }
+
+ if (!p->hostname)
+ {
+ /*
+ * Hostname not set, so this must be a cached remote printer
+ * that was created for a pending print job...
+ */
+
+ cupsdSetString(&p->hostname, host);
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
+ update = 1;
+
+ cupsdMarkDirty(CUPSD_DIRTY_REMOTE);
+ }
+
+ /*
+ * Update the state...
+ */
+
+ p->state = state;
+ p->browse_time = time(NULL);
+
+ if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
+ attrs)) != NULL)
+ {
+ /*
+ * Grab the lease-duration for the browse data; anything less then 1
+ * second or more than 1 week gets the default BrowseTimeout...
+ */
+
+ i = atoi(lease_duration);
+ if (i < 1 || i > 604800)
+ i = BrowseTimeout;
+
+ p->browse_expire = p->browse_time + i;
+ }
+ else
+ p->browse_expire = p->browse_time + BrowseTimeout;
+
+ if (type & CUPS_PRINTER_REJECTING)
+ {
+ type &= ~CUPS_PRINTER_REJECTING;
+
+ if (p->accepting)
+ {
+ update = 1;
+ p->accepting = 0;
+ }
+ }
+ else if (!p->accepting)
+ {
+ update = 1;
+ p->accepting = 1;
+ }
+
+ if (p->type != type)
+ {
+ p->type = type;
+ update = 1;
+ }
+
+ if (uuid && strcmp(p->uuid, uuid))
+ {
+ cupsdSetString(&p->uuid, uuid);
+ update = 1;
+ }
+
+ if (location && (!p->location || strcmp(p->location, location)))
+ {
+ cupsdSetString(&p->location, location);
+ update = 1;
+ }
+
+ if (info && (!p->info || strcmp(p->info, info)))
+ {
+ cupsdSetString(&p->info, info);
+ update = 1;
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+ }
+
+ if (!make_model || !make_model[0])
+ {
+ if (is_class)
+ snprintf(local_make_model, sizeof(local_make_model),
+ "Remote Class on %s", host);
+ else
+ snprintf(local_make_model, sizeof(local_make_model),
+ "Remote Printer on %s", host);
+ }
+ else
+ snprintf(local_make_model, sizeof(local_make_model),
+ "%s on %s", make_model, host);
+
+ if (!p->make_model || strcmp(p->make_model, local_make_model))
+ {
+ cupsdSetString(&p->make_model, local_make_model);
+ update = 1;
+ }
+
+ if (p->num_options)
+ {
+ if (!update && !(type & CUPS_PRINTER_DELETE))
+ {
+ /*
+ * See if we need to update the attributes...
+ */
+
+ if (p->num_options != num_attrs)
+ update = 1;
+ else
+ {
+ for (i = 0; i < num_attrs; i ++)
+ if (strcmp(attrs[i].name, p->options[i].name) ||
+ (!attrs[i].value != !p->options[i].value) ||
+ (attrs[i].value && strcmp(attrs[i].value, p->options[i].value)))
+ {
+ update = 1;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Free the old options...
+ */
+
+ cupsFreeOptions(p->num_options, p->options);
+ }
+
+ p->num_options = num_attrs;
+ p->options = attrs;
+
+ if (type & CUPS_PRINTER_DELETE)
+ {
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
+ "%s \'%s\' deleted by directory services.",
+ is_class ? "Class" : "Printer", p->name);
+
+ cupsdExpireSubscriptions(p, NULL);
+
+ cupsdDeletePrinter(p, 1);
+ cupsdUpdateImplicitClasses();
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+ }
+ else if (update)
+ {
+ cupsdSetPrinterAttrs(p);
+ cupsdUpdateImplicitClasses();
+ }
+
+ /*
+ * See if we have a default printer... If not, make the first network
+ * default printer the default.
+ */
+
+ if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
+ {
+ /*
+ * Find the first network default printer and use it...
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (p->type & CUPS_PRINTER_DEFAULT)
+ {
+ DefaultPrinter = p;
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+ break;
+ }
+ }
+
+ /*
+ * Do auto-classing if needed...
+ */
+
+ process_implicit_classes();
+}
+
+
+/*
+ * 'process_implicit_classes()' - Create/update implicit classes as needed.
+ */
+
+static void
+process_implicit_classes(void)
+{
+ int i; /* Looping var */
+ int update; /* Update printer attributes? */
+ char name[IPP_MAX_NAME], /* Name of printer */
+ *hptr; /* Pointer into hostname */
+ cupsd_printer_t *p, /* Printer information */
+ *pclass, /* Printer class */
+ *first; /* First printer in class */
+ int offset, /* Offset of name */
+ len; /* Length of name */
+
+
+ if (!ImplicitClasses || !Printers)
+ return;
+
+ /*
+ * Loop through all available printers and create classes as needed...
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
+ update = 0, pclass = NULL, first = NULL;
+ p != NULL;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ /*
+ * Skip implicit classes...
+ */
+
+ if (p->type & CUPS_PRINTER_IMPLICIT)
+ {
+ len = 0;
+ continue;
+ }
+
+ /*
+ * If len == 0, get the length of this printer name up to the "@"
+ * sign (if any).
+ */
+
+ cupsArraySave(Printers);
+
+ if (len > 0 &&
+ !_cups_strncasecmp(p->name, name + offset, len) &&
+ (p->name[len] == '\0' || p->name[len] == '@'))
+ {
+ /*
+ * We have more than one printer with the same name; see if
+ * we have a class, and if this printer is a member...
+ */
+
+ if (pclass && _cups_strcasecmp(pclass->name, name))
+ {
+ if (update)
+ cupsdSetPrinterAttrs(pclass);
+
+ update = 0;
+ pclass = NULL;
+ }
+
+ if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
+ {
+ /*
+ * Need to add the class...
+ */
+
+ pclass = cupsdAddPrinter(name);
+ cupsArrayAdd(ImplicitPrinters, pclass);
+
+ pclass->type |= CUPS_PRINTER_IMPLICIT;
+ pclass->accepting = 1;
+ pclass->state = IPP_PRINTER_IDLE;
+
+ cupsdSetString(&pclass->location, p->location);
+ cupsdSetString(&pclass->info, p->info);
+
+ cupsdSetString(&pclass->job_sheets[0], p->job_sheets[0]);
+ cupsdSetString(&pclass->job_sheets[1], p->job_sheets[1]);
+
+ update = 1;
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
+ name);
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "Implicit class \'%s\' added by directory services.",
+ name);
+ }
+
+ if (first != NULL)
+ {
+ for (i = 0; i < pclass->num_printers; i ++)
+ if (pclass->printers[i] == first)
+ break;
+
+ if (i >= pclass->num_printers)
+ {
+ first->in_implicit_class = 1;
+ cupsdAddPrinterToClass(pclass, first);
+ }
+
+ first = NULL;
+ }
+
+ for (i = 0; i < pclass->num_printers; i ++)
+ if (pclass->printers[i] == p)
+ break;
+
+ if (i >= pclass->num_printers)
+ {
+ p->in_implicit_class = 1;
+ cupsdAddPrinterToClass(pclass, p);
+ update = 1;
+ }
+ }
+ else
+ {
+ /*
+ * First time around; just get name length and mark it as first
+ * in the list...
+ */
+
+ if ((hptr = strchr(p->name, '@')) != NULL)
+ len = hptr - p->name;
+ else
+ len = strlen(p->name);
+
+ if (len >= sizeof(name))
+ {
+ /*
+ * If the printer name length somehow is greater than we normally allow,
+ * skip this printer...
+ */
+
+ len = 0;
+ cupsArrayRestore(Printers);
+ continue;
+ }
+
+ strncpy(name, p->name, len);
+ name[len] = '\0';
+ offset = 0;
+
+ if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL &&
+ !(first->type & CUPS_PRINTER_IMPLICIT))
+ {
+ /*
+ * Can't use same name as a local printer; add "Any" to the
+ * front of the name, unless we have explicitly disabled
+ * the "ImplicitAnyClasses"...
+ */
+
+ if (ImplicitAnyClasses && len < (sizeof(name) - 4))
+ {
+ /*
+ * Add "Any" to the class name...
+ */
+
+ strcpy(name, "Any");
+ strncpy(name + 3, p->name, len);
+ name[len + 3] = '\0';
+ offset = 3;
+ }
+ else
+ {
+ /*
+ * Don't create an implicit class if we have a local printer
+ * with the same name...
+ */
+
+ len = 0;
+ cupsArrayRestore(Printers);
+ continue;
+ }
+ }
+
+ first = p;
+ }
+
+ cupsArrayRestore(Printers);
+ }
+
+ /*
+ * Update the last printer class as needed...
+ */
+
+ if (pclass && update)
+ cupsdSetPrinterAttrs(pclass);
+}
+
+
+/*
+ * 'send_cups_browse()' - Send new browsing information using the CUPS
+ * protocol.
+ */
+
+static void
+send_cups_browse(cupsd_printer_t *p) /* I - Printer to send */
+{
+ int i; /* Looping var */
+ cups_ptype_t type; /* Printer type */
+ cupsd_dirsvc_addr_t *b; /* Browse address */
+ int bytes; /* Length of packet */
+ char packet[1453], /* Browse data packet */
+ uri[1024], /* Printer URI */
+ location[1024], /* printer-location */
+ info[1024], /* printer-info */
+ make_model[1024],
+ /* printer-make-and-model */
+ air[1024]; /* auth-info-required */
+ cupsd_netif_t *iface; /* Network interface */
+
+
+ /*
+ * Figure out the printer type value...
+ */
+
+ type = p->type | CUPS_PRINTER_REMOTE;
+
+ if (!p->accepting)
+ type |= CUPS_PRINTER_REJECTING;
+
+ if (p == DefaultPrinter)
+ type |= CUPS_PRINTER_DEFAULT;
+
+ /*
+ * Remove quotes from printer-info, printer-location, and
+ * printer-make-and-model attributes...
+ */
+
+ dequote(location, p->location, sizeof(location));
+ dequote(info, p->info, sizeof(info));
+
+ if (p->make_model)
+ dequote(make_model, p->make_model, sizeof(make_model));
+ else if (p->type & CUPS_PRINTER_CLASS)
+ {
+ if (p->num_printers > 0 && p->printers[0]->make_model)
+ strlcpy(make_model, p->printers[0]->make_model, sizeof(make_model));
+ else
+ strlcpy(make_model, "Local Printer Class", sizeof(make_model));
+ }
+ else if (p->raw)
+ strlcpy(make_model, "Local Raw Printer", sizeof(make_model));
+ else
+ strlcpy(make_model, "Local System V Printer", sizeof(make_model));
+
+ if (get_auth_info_required(p, packet, sizeof(packet)))
+ snprintf(air, sizeof(air), " auth-info-required=%s", packet);
+ else
+ air[0] = '\0';
+
+ /*
+ * Send a packet to each browse address...
+ */
+
+ for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
+ if (b->iface[0])
+ {
+ /*
+ * Send the browse packet to one or more interfaces...
+ */
+
+ if (!strcmp(b->iface, "*"))
+ {
+ /*
+ * Send to all local interfaces...
+ */
+
+ cupsdNetIFUpdate();
+
+ for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
+ iface;
+ iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
+ {
+ /*
+ * Only send to local, IPv4 interfaces...
+ */
+
+ if (!iface->is_local || !iface->port ||
+ iface->address.addr.sa_family != AF_INET)
+ continue;
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ iface->hostname, iface->port,
+ (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
+ "/printers/%s",
+ p->name);
+ snprintf(packet, sizeof(packet),
+ "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n",
+ type, p->state, uri, location, info, make_model,
+ p->browse_attrs ? p->browse_attrs : "", air, p->uuid);
+
+ bytes = strlen(packet);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
+ iface->name, packet);
+
+ iface->broadcast.ipv4.sin_port = htons(BrowsePort);
+
+ sendto(BrowseSocket, packet, bytes, 0,
+ (struct sockaddr *)&(iface->broadcast),
+ httpAddrLength(&(iface->broadcast)));
+ }
+ }
+ else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
+ {
+ /*
+ * Send to the named interface using the IPv4 address...
+ */
+
+ while (iface)
+ if (strcmp(b->iface, iface->name))
+ {
+ iface = NULL;
+ break;
+ }
+ else if (iface->address.addr.sa_family == AF_INET && iface->port)
+ break;
+ else
+ iface = (cupsd_netif_t *)cupsArrayNext(NetIFList);
+
+ if (iface)
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ iface->hostname, iface->port,
+ (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
+ "/printers/%s",
+ p->name);
+ snprintf(packet, sizeof(packet),
+ "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n",
+ type, p->state, uri, location, info, make_model,
+ p->browse_attrs ? p->browse_attrs : "", air, p->uuid);
+
+ bytes = strlen(packet);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
+ iface->name, packet);
+
+ iface->broadcast.ipv4.sin_port = htons(BrowsePort);
+
+ sendto(BrowseSocket, packet, bytes, 0,
+ (struct sockaddr *)&(iface->broadcast),
+ httpAddrLength(&(iface->broadcast)));
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Send the browse packet to the indicated address using
+ * the default server name...
+ */
+
+ snprintf(packet, sizeof(packet),
+ "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n",
+ type, p->state, p->uri, location, info, make_model,
+ p->browse_attrs ? p->browse_attrs : "", air, p->uuid);
+
+ bytes = strlen(packet);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
+
+ if (sendto(BrowseSocket, packet, bytes, 0,
+ (struct sockaddr *)&(b->to),
+ httpAddrLength(&(b->to))) <= 0)
+ {
+ /*
+ * Unable to send browse packet, so remove this address from the
+ * list...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdSendBrowseList: sendto failed for browser "
+ "%d - %s.",
+ (int)(b - Browsers + 1), strerror(errno));
+
+ if (i > 1)
+ memmove(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
+
+ b --;
+ NumBrowsers --;
+ }
+ }
+}
+
+
+#ifdef HAVE_LDAP
+/*
+ * 'ldap_search_rec()' - LDAP Search with reconnect
+ */
+
+static int /* O - Return code */
+ldap_search_rec(LDAP *ld, /* I - LDAP handler */
+ char *base, /* I - Base dn */
+ int scope, /* I - LDAP search scope */
+ char *filter, /* I - Filter string */
+ char *attrs[], /* I - Requested attributes */
+ int attrsonly, /* I - Return only attributes? */
+ LDAPMessage **res) /* I - LDAP handler */
+{
+ int rc; /* Return code */
+ LDAP *ldr; /* LDAP handler after reconnect */
+
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ rc = ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly, NULL, NULL,
+ NULL, LDAP_NO_LIMIT, res);
+# else
+ rc = ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res);
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+
+ /*
+ * If we have a connection problem try again...
+ */
+
+ if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP search failed with status %d: %s",
+ rc, ldap_err2string(rc));
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "We try the LDAP search once again after reconnecting to "
+ "the server");
+ ldap_freeres(*res);
+ ldr = ldap_reconnect();
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ rc = ldap_search_ext_s(ldr, base, scope, filter, attrs, attrsonly, NULL,
+ NULL, NULL, LDAP_NO_LIMIT, res);
+# else
+ rc = ldap_search_s(ldr, base, scope, filter, attrs, attrsonly, res);
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ }
+
+ if (rc == LDAP_NO_SUCH_OBJECT)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "ldap_search_rec: LDAP entry/object not found");
+ else if (rc != LDAP_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "ldap_search_rec: LDAP search failed with status %d: %s",
+ rc, ldap_err2string(rc));
+
+ if (rc != LDAP_SUCCESS)
+ ldap_freeres(*res);
+
+ return (rc);
+}
+
+
+/*
+ * 'ldap_freeres()' - Free LDAPMessage
+ */
+
+static void
+ldap_freeres(LDAPMessage *entry) /* I - LDAP handler */
+{
+ int rc; /* Return value */
+
+
+ rc = ldap_msgfree(entry);
+ if (rc == -1)
+ cupsdLogMessage(CUPSD_LOG_WARN, "Can't free LDAPMessage!");
+ else if (rc == 0)
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "Freeing LDAPMessage was unnecessary");
+}
+
+
+/*
+ * 'ldap_getval_char()' - Get first LDAP value and convert to string
+ */
+
+static int /* O - Return code */
+ldap_getval_firststring(
+ LDAP *ld, /* I - LDAP handler */
+ LDAPMessage *entry, /* I - LDAP message or search result */
+ char *attr, /* I - the wanted attribute */
+ char *retval, /* O - String to return */
+ unsigned long maxsize) /* I - Max string size */
+{
+ char *dn; /* LDAP DN */
+ int rc = 0; /* Return code */
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ struct berval **bval; /* LDAP value array */
+ unsigned long size; /* String size */
+
+
+ /*
+ * Get value from LDAPMessage...
+ */
+
+ if ((bval = ldap_get_values_len(ld, entry, attr)) == NULL)
+ {
+ rc = -1;
+ dn = ldap_get_dn(ld, entry);
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Failed to get LDAP value %s for %s!",
+ attr, dn);
+ ldap_memfree(dn);
+ }
+ else
+ {
+ /*
+ * Check size and copy value into our string...
+ */
+
+ size = maxsize;
+ if (size < (bval[0]->bv_len + 1))
+ {
+ rc = -1;
+ dn = ldap_get_dn(ld, entry);
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Attribute %s is too big! (dn: %s)",
+ attr, dn);
+ ldap_memfree(dn);
+ }
+ else
+ size = bval[0]->bv_len + 1;
+
+ strlcpy(retval, bval[0]->bv_val, size);
+ ldap_value_free_len(bval);
+ }
+# else
+ char **value; /* LDAP value */
+
+ /*
+ * Get value from LDAPMessage...
+ */
+
+ if ((value = (char **)ldap_get_values(ld, entry, attr)) == NULL)
+ {
+ rc = -1;
+ dn = ldap_get_dn(ld, entry);
+ cupsdLogMessage(CUPSD_LOG_WARN, "Failed to get LDAP value %s for %s!",
+ attr, dn);
+ ldap_memfree(dn);
+ }
+ else
+ {
+ strlcpy(retval, *value, maxsize);
+ ldap_value_free(value);
+ }
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+
+ return (rc);
+}
+
+
+/*
+ * 'send_ldap_ou()' - Send LDAP ou registrations.
+ */
+
+static void
+send_ldap_ou(char *ou, /* I - Servername/ou to register */
+ char *basedn, /* I - Our base dn */
+ char *descstring) /* I - Description for ou */
+{
+ int i; /* Looping var... */
+ LDAPMod mods[3]; /* The 3 attributes we will be adding */
+ LDAPMod *pmods[4]; /* Pointers to the 3 attributes + NULL */
+ LDAPMessage *res, /* Search result token */
+ *e; /* Current entry from search */
+ int rc; /* LDAP status */
+ int rcmod; /* LDAP status for modifications */
+ char dn[1024], /* DN of the organizational unit we are adding */
+ *desc[2], /* Change records */
+ *ou_value[2];
+ char old_desc[1024]; /* Old description */
+ static const char * const objectClass_values[] =
+ { /* The 2 objectClass's we use in */
+ "top", /* our LDAP entries */
+ "organizationalUnit",
+ NULL
+ };
+ static const char * const ou_attrs[] =/* CUPS LDAP attributes */
+ {
+ "description",
+ NULL
+ };
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: %s", ou);
+
+ /*
+ * Reconnect if LDAP Handle is invalid...
+ */
+
+ if (!BrowseLDAPHandle)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_ou: LDAP Handle is invalid. Try reconnecting...");
+ ldap_reconnect();
+ return;
+ }
+
+ /*
+ * Prepare ldap search...
+ */
+
+ snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: dn=\"%s\"", dn);
+
+ ou_value[0] = ou;
+ ou_value[1] = NULL;
+ desc[0] = descstring;
+ desc[1] = NULL;
+
+ mods[0].mod_type = "ou";
+ mods[0].mod_values = ou_value;
+ mods[1].mod_type = "description";
+ mods[1].mod_values = desc;
+ mods[2].mod_type = "objectClass";
+ mods[2].mod_values = (char **)objectClass_values;
+
+ rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
+ (char **)ou_attrs, 0, &res);
+
+ /*
+ * If ldap search was not successfull then exit function...
+ */
+
+ if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
+ return;
+
+ /*
+ * Check if we need to insert or update the LDAP entry...
+ */
+
+ if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
+ rc != LDAP_NO_SUCH_OBJECT)
+ {
+ /*
+ * Printserver has already been registered, check if
+ * modification is required...
+ */
+
+ e = ldap_first_entry(BrowseLDAPHandle, res);
+
+ /*
+ * Get the required values from this entry...
+ */
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "description", old_desc,
+ sizeof(old_desc)) == -1)
+ old_desc[0] = '\0';
+
+ /*
+ * Check if modification is required...
+ */
+
+ if ( strcmp(desc[0], old_desc) == 0 )
+ {
+ /*
+ * LDAP entry for the printer exists.
+ * Printer has already been registered,
+ * no modifications required...
+ */
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_ou: No updates required for %s", ou);
+ }
+ else
+ {
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_ou: Replace entry for %s", ou);
+
+ for (i = 0; i < 3; i ++)
+ {
+ pmods[i] = mods + i;
+ pmods[i]->mod_op = LDAP_MOD_REPLACE;
+ }
+ pmods[i] = NULL;
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rcmod = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rcmod = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP modify for %s failed with status %d: %s",
+ ou, rcmod, ldap_err2string(rcmod));
+ if (rcmod == LDAP_SERVER_DOWN)
+ ldap_reconnect();
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Printserver has never been registered,
+ * add registration...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_ou: Add entry for %s", ou);
+
+ for (i = 0; i < 3; i ++)
+ {
+ pmods[i] = mods + i;
+ pmods[i]->mod_op = LDAP_MOD_ADD;
+ }
+ pmods[i] = NULL;
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rcmod = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rcmod = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP add for %s failed with status %d: %s",
+ ou, rcmod, ldap_err2string(rcmod));
+ if (rcmod == LDAP_SERVER_DOWN)
+ ldap_reconnect();
+ }
+ }
+
+ if (rc == LDAP_SUCCESS)
+ ldap_freeres(res);
+}
+
+
+/*
+ * 'send_ldap_browse()' - Send LDAP printer registrations.
+ */
+
+static void
+send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */
+{
+ int i; /* Looping var... */
+ LDAPMod mods[7]; /* The 7 attributes we will be adding */
+ LDAPMod *pmods[8]; /* Pointers to the 7 attributes + NULL */
+ LDAPMessage *res, /* Search result token */
+ *e; /* Current entry from search */
+ char *cn_value[2], /* Change records */
+ *uri[2],
+ *info[2],
+ *location[2],
+ *make_model[2],
+ *type[2],
+ typestring[255], /* String to hold printer-type */
+ dn[1024]; /* DN of the printer we are adding */
+ int rc; /* LDAP status */
+ int rcmod; /* LDAP status for modifications */
+ char old_uri[HTTP_MAX_URI], /* Printer URI */
+ old_location[1024], /* Printer location */
+ old_info[1024], /* Printer information */
+ old_make_model[1024], /* Printer make and model */
+ old_type_string[30]; /* Temporary type number */
+ int old_type; /* Printer type */
+ static const char * const objectClass_values[] =
+ { /* The 3 objectClass's we use in */
+ "top", /* our LDAP entries */
+ "device",
+ "cupsPrinter",
+ NULL
+ };
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s", p->name);
+
+ /*
+ * Exit function if LDAP updates has been disabled...
+ */
+
+ if (!BrowseLDAPUpdate)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: Updates temporary disabled; "
+ "skipping...");
+ return;
+ }
+
+ /*
+ * Reconnect if LDAP Handle is invalid...
+ */
+
+ if (!BrowseLDAPHandle)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: LDAP Handle is invalid. Try "
+ "reconnecting...");
+ ldap_reconnect();
+ return;
+ }
+
+ /*
+ * Everything in ldap is ** so we fudge around it...
+ */
+
+ sprintf(typestring, "%u", p->type);
+
+ cn_value[0] = p->name;
+ cn_value[1] = NULL;
+ info[0] = p->info ? p->info : "Unknown";
+ info[1] = NULL;
+ location[0] = p->location ? p->location : "Unknown";
+ location[1] = NULL;
+ make_model[0] = p->make_model ? p->make_model : "Unknown";
+ make_model[1] = NULL;
+ type[0] = typestring;
+ type[1] = NULL;
+ uri[0] = p->uri;
+ uri[1] = NULL;
+
+ /*
+ * Get ldap entry for printer ...
+ */
+
+ snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
+ BrowseLDAPDN);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
+
+ rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
+ (char **)ldap_attrs, 0, &res);
+
+ /*
+ * If ldap search was not successfull then exit function
+ * and temporary disable LDAP updates...
+ */
+
+ if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
+ {
+ if (BrowseLDAPUpdate &&
+ (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR))
+ {
+ BrowseLDAPUpdate = FALSE;
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "LDAP update temporary disabled");
+ }
+
+ return;
+ }
+
+ /*
+ * Fill modification array...
+ */
+
+ mods[0].mod_type = "cn";
+ mods[0].mod_values = cn_value;
+ mods[1].mod_type = "printerDescription";
+ mods[1].mod_values = info;
+ mods[2].mod_type = "printerURI";
+ mods[2].mod_values = uri;
+ mods[3].mod_type = "printerLocation";
+ mods[3].mod_values = location;
+ mods[4].mod_type = "printerMakeAndModel";
+ mods[4].mod_values = make_model;
+ mods[5].mod_type = "printerType";
+ mods[5].mod_values = type;
+ mods[6].mod_type = "objectClass";
+ mods[6].mod_values = (char **)objectClass_values;
+
+ /*
+ * Check if we need to insert or update the LDAP entry...
+ */
+
+ if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
+ rc != LDAP_NO_SUCH_OBJECT)
+ {
+ /*
+ * Printer has already been registered, check if
+ * modification is required...
+ */
+
+ e = ldap_first_entry(BrowseLDAPHandle, res);
+
+ /*
+ * Get the required values from this entry...
+ */
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerDescription",
+ old_info, sizeof(old_info)) == -1)
+ old_info[0] = '\0';
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerLocation",
+ old_location, sizeof(old_location)) == -1)
+ old_info[0] = '\0';
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerMakeAndModel",
+ old_make_model, sizeof(old_make_model)) == -1)
+ old_info[0] = '\0';
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerType",
+ old_type_string, sizeof(old_type_string)) == -1)
+ old_info[0] = '\0';
+
+ old_type = atoi(old_type_string);
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerURI", old_uri,
+ sizeof(old_uri)) == -1)
+ old_info[0] = '\0';
+
+ /*
+ * Check if modification is required...
+ */
+
+ if (!strcmp(info[0], old_info) && !strcmp(uri[0], old_uri) &&
+ !strcmp(location[0], old_location) &&
+ !strcmp(make_model[0], old_make_model) && p->type == old_type)
+ {
+ /*
+ * LDAP entry for the printer exists. Printer has already been registered,
+ * no modifications required...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: No updates required for %s", p->name);
+ }
+ else
+ {
+ /*
+ * LDAP entry for the printer exists. Printer has already been registered,
+ * modify the current registration...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: Replace entry for %s", p->name);
+
+ for (i = 0; i < 7; i ++)
+ {
+ pmods[i] = mods + i;
+ pmods[i]->mod_op = LDAP_MOD_REPLACE;
+ }
+ pmods[i] = NULL;
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rcmod = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rcmod = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP modify for %s failed with status %d: %s",
+ p->name, rcmod, ldap_err2string(rcmod));
+ if (rcmod == LDAP_SERVER_DOWN)
+ ldap_reconnect();
+ }
+ }
+ }
+ else
+ {
+ /*
+ * No LDAP entry exists for the printer. Printer has never been registered,
+ * add the current registration...
+ */
+
+ send_ldap_ou(ServerName, BrowseLDAPDN, "CUPS Server");
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: Add entry for %s", p->name);
+
+ for (i = 0; i < 7; i ++)
+ {
+ pmods[i] = mods + i;
+ pmods[i]->mod_op = LDAP_MOD_ADD;
+ }
+ pmods[i] = NULL;
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rcmod = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rcmod = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP add for %s failed with status %d: %s",
+ p->name, rcmod, ldap_err2string(rcmod));
+ if (rcmod == LDAP_SERVER_DOWN)
+ ldap_reconnect();
+ }
+ }
+
+ if (rc == LDAP_SUCCESS)
+ ldap_freeres(res);
+}
+
+
+/*
+ * 'ldap_dereg_printer()' - Delete printer from directory
+ */
+
+static void
+ldap_dereg_printer(cupsd_printer_t *p) /* I - Printer to deregister */
+{
+ char dn[1024]; /* DN of the printer */
+ int rc; /* LDAP status */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: Remove entry for %s",
+ p->name);
+
+ /*
+ * Reconnect if LDAP Handle is invalid...
+ */
+
+ if (!BrowseLDAPHandle)
+ {
+ ldap_reconnect();
+ return;
+ }
+
+ /*
+ * Get dn for printer and delete LDAP entry...
+ */
+
+ snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
+ BrowseLDAPDN);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: dn=\"%s\"", dn);
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "LDAP delete for %s failed with status %d: %s",
+ p->name, rc, ldap_err2string(rc));
+
+ /*
+ * If we had a connection problem (connection timed out, etc.)
+ * we should reconnect and try again to delete the entry...
+ */
+
+ if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Retry deleting LDAP entry for %s after a reconnect...", p->name);
+ ldap_reconnect();
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "LDAP delete for %s failed with status %d: %s",
+ p->name, rc, ldap_err2string(rc));
+ }
+ }
+}
+
+
+/*
+ * 'ldap_dereg_ou()' - Remove the organizational unit.
+ */
+
+static void
+ldap_dereg_ou(char *ou, /* I - Organizational unit (servername) */
+ char *basedn) /* I - Dase dn */
+{
+ char dn[1024]; /* DN of the printer */
+ int rc; /* LDAP status */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: Remove entry for %s", ou);
+
+ /*
+ * Reconnect if LDAP Handle is invalid...
+ */
+
+ if (!BrowseLDAPHandle)
+ {
+ ldap_reconnect();
+ return;
+ }
+
+ /*
+ * Get dn for printer and delete LDAP entry...
+ */
+
+ snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: dn=\"%s\"", dn);
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "LDAP delete for %s failed with status %d: %s",
+ ou, rc, ldap_err2string(rc));
+
+ /*
+ * If we had a connection problem (connection timed out, etc.)
+ * we should reconnect and try again to delete the entry...
+ */
+
+ if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Retry deleting LDAP entry for %s after a reconnect...", ou);
+ ldap_reconnect();
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "LDAP delete for %s failed with status %d: %s",
+ ou, rc, ldap_err2string(rc));
+ }
+ }
+}
+#endif /* HAVE_LDAP */
+
+
+#ifdef HAVE_LIBSLP
+/*
+ * 'send_slp_browse()' - Register the specified printer with SLP.
+ */
+
+static void
+send_slp_browse(cupsd_printer_t *p) /* I - Printer to register */
+{
+ char srvurl[HTTP_MAX_URI], /* Printer service URI */
+ attrs[8192], /* Printer attributes */
+ finishings[1024], /* Finishings to support */
+ make_model[IPP_MAX_NAME * 2],
+ /* Make and model, quoted */
+ location[IPP_MAX_NAME * 2],
+ /* Location, quoted */
+ info[IPP_MAX_NAME * 2], /* Info, quoted */
+ *src, /* Pointer to original string */
+ *dst; /* Pointer to destination string */
+ ipp_attribute_t *authentication; /* uri-authentication-supported value */
+ SLPError error; /* SLP error, if any */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "send_slp_browse(%p = \"%s\")", p,
+ p->name);
+
+ /*
+ * Make the SLP service URL that conforms to the IANA
+ * 'printer:' template.
+ */
+
+ snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
+
+ /*
+ * Figure out the finishings string...
+ */
+
+ if (p->type & CUPS_PRINTER_STAPLE)
+ strcpy(finishings, "staple");
+ else
+ finishings[0] = '\0';
+
+ if (p->type & CUPS_PRINTER_BIND)
+ {
+ if (finishings[0])
+ strlcat(finishings, ",bind", sizeof(finishings));
+ else
+ strcpy(finishings, "bind");
+ }
+
+ if (p->type & CUPS_PRINTER_PUNCH)
+ {
+ if (finishings[0])
+ strlcat(finishings, ",punch", sizeof(finishings));
+ else
+ strcpy(finishings, "punch");
+ }
+
+ if (p->type & CUPS_PRINTER_COVER)
+ {
+ if (finishings[0])
+ strlcat(finishings, ",cover", sizeof(finishings));
+ else
+ strcpy(finishings, "cover");
+ }
+
+ if (p->type & CUPS_PRINTER_SORT)
+ {
+ if (finishings[0])
+ strlcat(finishings, ",sort", sizeof(finishings));
+ else
+ strcpy(finishings, "sort");
+ }
+
+ if (!finishings[0])
+ strcpy(finishings, "none");
+
+ /*
+ * Quote any commas in the make and model, location, and info strings...
+ */
+
+ for (src = p->make_model, dst = make_model;
+ src && *src && dst < (make_model + sizeof(make_model) - 2);)
+ {
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
+
+ *dst++ = *src++;
+ }
+
+ *dst = '\0';
+
+ if (!make_model[0])
+ strcpy(make_model, "Unknown");
+
+ for (src = p->location, dst = location;
+ src && *src && dst < (location + sizeof(location) - 2);)
+ {
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
+
+ *dst++ = *src++;
+ }
+
+ *dst = '\0';
+
+ if (!location[0])
+ strcpy(location, "Unknown");
+
+ for (src = p->info, dst = info;
+ src && *src && dst < (info + sizeof(info) - 2);)
+ {
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
+
+ *dst++ = *src++;
+ }
+
+ *dst = '\0';
+
+ if (!info[0])
+ strcpy(info, "Unknown");
+
+ /*
+ * Get the authentication value...
+ */
+
+ authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
+ IPP_TAG_KEYWORD);
+
+ /*
+ * Make the SLP attribute string list that conforms to
+ * the IANA 'printer:' template.
+ */
+
+ snprintf(attrs, sizeof(attrs),
+ "(printer-uri-supported=%s),"
+ "(uri-authentication-supported=%s>),"
+#ifdef HAVE_SSL
+ "(uri-security-supported=tls>),"
+#else
+ "(uri-security-supported=none>),"
+#endif /* HAVE_SSL */
+ "(printer-name=%s),"
+ "(printer-location=%s),"
+ "(printer-info=%s),"
+ "(printer-more-info=%s),"
+ "(printer-make-and-model=%s),"
+ "(printer-type=%d),"
+ "(charset-supported=utf-8),"
+ "(natural-language-configured=%s),"
+ "(natural-language-supported=de,en,es,fr,it),"
+ "(color-supported=%s),"
+ "(finishings-supported=%s),"
+ "(sides-supported=one-sided%s),"
+ "(multiple-document-jobs-supported=true)"
+ "(ipp-versions-supported=1.0,1.1)",
+ p->uri, authentication->values[0].string.text, p->name, location,
+ info, p->uri, make_model, p->type, DefaultLanguage,
+ p->type & CUPS_PRINTER_COLOR ? "true" : "false",
+ finishings,
+ p->type & CUPS_PRINTER_DUPLEX ?
+ ",two-sided-long-edge,two-sided-short-edge" : "");
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs);
+
+ /*
+ * Register the printer with the SLP server...
+ */
+
+ error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
+ SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0);
+
+ if (error != SLP_OK)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
+ error);
+}
+
+
+/*
+ * 'slp_attr_callback()' - SLP attribute callback
+ */
+
+static SLPBoolean /* O - SLP_TRUE for success */
+slp_attr_callback(
+ SLPHandle hslp, /* I - SLP handle */
+ const char *attrlist, /* I - Attribute list */
+ SLPError errcode, /* I - Parsing status for this attr */
+ void *cookie) /* I - Current printer */
+{
+ char *tmp = 0; /* Temporary string */
+ cupsd_printer_t *p = (cupsd_printer_t*)cookie;
+ /* Current printer */
+
+
+ (void)hslp; /* anti-compiler-warning-code */
+
+ /*
+ * Bail if there was an error
+ */
+
+ if (errcode != SLP_OK)
+ return (SLP_TRUE);
+
+ /*
+ * Parse the attrlist to obtain things needed to build CUPS browse packet
+ */
+
+ memset(p, 0, sizeof(cupsd_printer_t));
+
+ if (slp_get_attr(attrlist, "(printer-location=", &(p->location)))
+ return (SLP_FALSE);
+ if (slp_get_attr(attrlist, "(printer-info=", &(p->info)))
+ return (SLP_FALSE);
+ if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model)))
+ return (SLP_FALSE);
+ if (!slp_get_attr(attrlist, "(printer-type=", &tmp))
+ p->type = atoi(tmp);
+ else
+ p->type = CUPS_PRINTER_REMOTE;
+
+ cupsdClearString(&tmp);
+
+ return (SLP_TRUE);
+}
+
+
+/*
+ * 'slp_dereg_printer()' - SLPDereg() the specified printer
+ */
+
+static void
+slp_dereg_printer(cupsd_printer_t *p) /* I - Printer */
+{
+ char srvurl[HTTP_MAX_URI]; /* Printer service URI */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name);
+
+ if (!(p->type & CUPS_PRINTER_REMOTE))
+ {
+ /*
+ * Make the SLP service URL that conforms to the IANA
+ * 'printer:' template.
+ */
+
+ snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
+
+ /*
+ * Deregister the printer...
+ */
+
+ SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0);
+ }
+}
+
+
+/*
+ * 'slp_get_attr()' - Get an attribute from an SLP registration.
+ */
+
+static int /* O - 0 on success */
+slp_get_attr(const char *attrlist, /* I - Attribute list string */
+ const char *tag, /* I - Name of attribute */
+ char **valbuf) /* O - Value */
+{
+ char *ptr1, /* Pointer into string */
+ *ptr2; /* ... */
+
+
+ cupsdClearString(valbuf);
+
+ if ((ptr1 = strstr(attrlist, tag)) != NULL)
+ {
+ ptr1 += strlen(tag);
+
+ if ((ptr2 = strchr(ptr1,')')) != NULL)
+ {
+ /*
+ * Copy the value...
+ */
+
+ *valbuf = calloc(ptr2 - ptr1 + 1, 1);
+ strncpy(*valbuf, ptr1, ptr2 - ptr1);
+
+ /*
+ * Dequote the value...
+ */
+
+ for (ptr1 = *valbuf; *ptr1; ptr1 ++)
+ if (*ptr1 == '\\' && ptr1[1])
+ _cups_strcpy(ptr1, ptr1 + 1);
+
+ return (0);
+ }
+ }
+
+ return (-1);
+}
+
+
+/*
+ * 'slp_reg_callback()' - Empty SLPRegReport.
+ */
+
+static void
+slp_reg_callback(SLPHandle hslp, /* I - SLP handle */
+ SLPError errcode, /* I - Error code, if any */
+ void *cookie) /* I - App data */
+{
+ (void)hslp;
+ (void)errcode;
+ (void)cookie;
+
+ return;
+}
+
+
+/*
+ * 'slp_url_callback()' - SLP service url callback
+ */
+
+static SLPBoolean /* O - TRUE = OK, FALSE = error */
+slp_url_callback(
+ SLPHandle hslp, /* I - SLP handle */
+ const char *srvurl, /* I - URL of service */
+ unsigned short lifetime, /* I - Life of service */
+ SLPError errcode, /* I - Existing error code */
+ void *cookie) /* I - Pointer to service list */
+{
+ slpsrvurl_t *s, /* New service entry */
+ **head; /* Pointer to head of entry */
+
+
+ /*
+ * Let the compiler know we won't be using these vars...
+ */
+
+ (void)hslp;
+ (void)lifetime;
+
+ /*
+ * Bail if there was an error
+ */
+
+ if (errcode != SLP_OK)
+ return (SLP_TRUE);
+
+ /*
+ * Grab the head of the list...
+ */
+
+ head = (slpsrvurl_t**)cookie;
+
+ /*
+ * Allocate a *temporary* slpsrvurl_t to hold this entry.
+ */
+
+ if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
+ return (SLP_FALSE);
+
+ /*
+ * Copy the SLP service URL...
+ */
+
+ strlcpy(s->url, srvurl, sizeof(s->url));
+
+ /*
+ * Link the SLP service URL into the head of the list
+ */
+
+ if (*head)
+ s->next = *head;
+
+ *head = s;
+
+ return (SLP_TRUE);
+}
+#endif /* HAVE_LIBSLP */
+
+
+/*
+ * 'update_cups_browse()' - Update the browse lists using the CUPS protocol.
+ */
+
+static void
+update_cups_browse(void)
+{
+ int i; /* Looping var */
+ int auth; /* Authorization status */
+ int len; /* Length of name string */
+ int bytes; /* Number of bytes left */
+ char packet[1541], /* Broadcast packet */
+ *pptr; /* Pointer into packet */
+ socklen_t srclen; /* Length of source address */
+ http_addr_t srcaddr; /* Source address */
+ char srcname[1024]; /* Source hostname */
+ unsigned address[4]; /* Source address */
+ unsigned type; /* Printer type */
+ unsigned state; /* Printer state */
+ char uri[HTTP_MAX_URI], /* Printer URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI], /* Resource portion of URI */
+ info[IPP_MAX_NAME], /* Information string */
+ location[IPP_MAX_NAME], /* Location string */
+ make_model[IPP_MAX_NAME];/* Make and model string */
+ int num_attrs; /* Number of attributes */
+ cups_option_t *attrs; /* Attributes */
+
+
+ /*
+ * Read a packet from the browse socket...
+ */
+
+ srclen = sizeof(srcaddr);
+ if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
+ (struct sockaddr *)&srcaddr, &srclen)) < 0)
+ {
+ /*
+ * "Connection refused" is returned under Linux if the destination port
+ * or address is unreachable from a previous sendto(); check for the
+ * error here and ignore it for now...
+ */
+
+ if (errno != ECONNREFUSED && errno != EAGAIN)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
+ strerror(errno));
+ cupsdLogMessage(CUPSD_LOG_ERROR, "CUPS browsing turned off.");
+
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
+
+ cupsdRemoveSelect(BrowseSocket);
+ BrowseSocket = -1;
+
+ BrowseLocalProtocols &= ~BROWSE_CUPS;
+ BrowseRemoteProtocols &= ~BROWSE_CUPS;
+ }
+
+ return;
+ }
+
+ packet[bytes] = '\0';
+
+ /*
+ * If we're about to sleep, ignore incoming browse packets.
+ */
+
+ if (Sleeping)
+ return;
+
+ /*
+ * Figure out where it came from...
+ */
+
+#ifdef AF_INET6
+ if (srcaddr.addr.sa_family == AF_INET6)
+ {
+ address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
+ address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
+ address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
+ address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
+ }
+ else
+#endif /* AF_INET6 */
+ {
+ address[0] = 0;
+ address[1] = 0;
+ address[2] = 0;
+ address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
+ }
+
+ if (HostNameLookups)
+ httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
+ else
+ httpAddrString(&srcaddr, srcname, sizeof(srcname));
+
+ len = strlen(srcname);
+
+ /*
+ * Do ACL stuff...
+ */
+
+ if (BrowseACL)
+ {
+ if (httpAddrLocalhost(&srcaddr) || !_cups_strcasecmp(srcname, "localhost"))
+ {
+ /*
+ * Access from localhost (127.0.0.1) is always allowed...
+ */
+
+ auth = CUPSD_AUTH_ALLOW;
+ }
+ else
+ {
+ /*
+ * Do authorization checks on the domain/address...
+ */
+
+ switch (BrowseACL->order_type)
+ {
+ default :
+ auth = CUPSD_AUTH_DENY; /* anti-compiler-warning-code */
+ break;
+
+ case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
+ auth = CUPSD_AUTH_ALLOW;
+
+ if (cupsdCheckAuth(address, srcname, len, BrowseACL->deny))
+ auth = CUPSD_AUTH_DENY;
+
+ if (cupsdCheckAuth(address, srcname, len, BrowseACL->allow))
+ auth = CUPSD_AUTH_ALLOW;
+ break;
+
+ case CUPSD_AUTH_DENY : /* Order Allow,Deny */
+ auth = CUPSD_AUTH_DENY;
+
+ if (cupsdCheckAuth(address, srcname, len, BrowseACL->allow))
+ auth = CUPSD_AUTH_ALLOW;
+
+ if (cupsdCheckAuth(address, srcname, len, BrowseACL->deny))
+ auth = CUPSD_AUTH_DENY;
+ break;
+ }
+ }
+ }
+ else
+ auth = CUPSD_AUTH_ALLOW;
+
+ if (auth == CUPSD_AUTH_DENY)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "update_cups_browse: Refused %d bytes from %s", bytes,
+ srcname);
+ return;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "update_cups_browse: (%d bytes from %s) %s", bytes,
+ srcname, packet);
+
+ /*
+ * Parse packet...
+ */
+
+ if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "update_cups_browse: Garbled browse packet - %s", packet);
+ return;
+ }
+
+ strcpy(location, "Location Unknown");
+ strcpy(info, "No Information Available");
+ make_model[0] = '\0';
+ num_attrs = 0;
+ attrs = NULL;
+
+ if ((pptr = strchr(packet, '\"')) != NULL)
+ {
+ /*
+ * Have extended information; can't use sscanf for it because not all
+ * sscanf's allow empty strings with %[^\"]...
+ */
+
+ for (i = 0, pptr ++;
+ i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
+ i ++, pptr ++)
+ location[i] = *pptr;
+
+ if (i)
+ location[i] = '\0';
+
+ if (*pptr == '\"')
+ pptr ++;
+
+ while (*pptr && isspace(*pptr & 255))
+ pptr ++;
+
+ if (*pptr == '\"')
+ {
+ for (i = 0, pptr ++;
+ i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
+ i ++, pptr ++)
+ info[i] = *pptr;
+
+ info[i] = '\0';
+
+ if (*pptr == '\"')
+ pptr ++;
+
+ while (*pptr && isspace(*pptr & 255))
+ pptr ++;
+
+ if (*pptr == '\"')
+ {
+ for (i = 0, pptr ++;
+ i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
+ i ++, pptr ++)
+ make_model[i] = *pptr;
+
+ if (*pptr == '\"')
+ pptr ++;
+
+ make_model[i] = '\0';
+
+ if (*pptr)
+ num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
+ }
+ }
+ }
+
+ DEBUG_puts(packet);
+ DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
+ "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
+ type, state, uri, location, info, make_model));
+
+ /*
+ * Pull the URI apart to see if this is a local or remote printer...
+ */
+
+ if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
+ {
+ cupsFreeOptions(num_attrs, attrs);
+ return;
+ }
+
+ /*
+ * Do relaying...
+ */
+
+ for (i = 0; i < NumRelays; i ++)
+ if (cupsdCheckAuth(address, srcname, len, Relays[i].from))
+ if (sendto(BrowseSocket, packet, bytes, 0,
+ (struct sockaddr *)&(Relays[i].to),
+ httpAddrLength(&(Relays[i].to))) <= 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "update_cups_browse: sendto failed for relay %d - %s.",
+ i + 1, strerror(errno));
+ cupsFreeOptions(num_attrs, attrs);
+ return;
+ }
+
+ /*
+ * Process the browse data...
+ */
+
+ process_browse_data(uri, host, resource, (cups_ptype_t)type,
+ (ipp_pstate_t)state, location, info, make_model,
+ num_attrs, attrs);
+}
+
+
+/*
+ * 'update_lpd()' - Update the LPD configuration as needed.
+ */
+
+static void
+update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */
+{
+ if (!LPDConfigFile)
+ return;
+
+#ifdef __APPLE__
+ /*
+ * Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf
+ * setting for backwards-compatibility.
+ */
+
+ if (onoff && !get_hostconfig("CUPS_LPD"))
+ onoff = 0;
+#endif /* __APPLE__ */
+
+ if (!strncmp(LPDConfigFile, "xinetd:///", 10))
+ {
+ /*
+ * Enable/disable LPD via the xinetd.d config file for cups-lpd...
+ */
+
+ char newfile[1024]; /* New cups-lpd.N file */
+ cups_file_t *ofp, /* Original file pointer */
+ *nfp; /* New file pointer */
+ char line[1024]; /* Line from file */
+
+
+ snprintf(newfile, sizeof(newfile), "%s.N", LPDConfigFile + 9);
+
+ if ((ofp = cupsFileOpen(LPDConfigFile + 9, "r")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
+ LPDConfigFile + 9, strerror(errno));
+ return;
+ }
+
+ if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
+ newfile, strerror(errno));
+ cupsFileClose(ofp);
+ return;
+ }
+
+ /*
+ * Copy all of the lines from the cups-lpd file...
+ */
+
+ while (cupsFileGets(ofp, line, sizeof(line)))
+ {
+ if (line[0] == '{')
+ {
+ cupsFilePrintf(nfp, "%s\n", line);
+ snprintf(line, sizeof(line), "\tdisable = %s",
+ onoff ? "no" : "yes");
+ }
+ else if (!strstr(line, "disable ="))
+ cupsFilePrintf(nfp, "%s\n", line);
+ }
+
+ cupsFileClose(nfp);
+ cupsFileClose(ofp);
+ rename(newfile, LPDConfigFile + 9);
+ }
+#ifdef __APPLE__
+ else if (!strncmp(LPDConfigFile, "launchd:///", 11))
+ {
+ /*
+ * Enable/disable LPD via the launchctl command...
+ */
+
+ char *argv[5], /* Arguments for command */
+ *envp[MAX_ENV]; /* Environment for command */
+ int pid; /* Process ID */
+
+
+ cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
+ argv[0] = (char *)"launchctl";
+ argv[1] = (char *)(onoff ? "load" : "unload");
+ argv[2] = (char *)"-w";
+ argv[3] = LPDConfigFile + 10;
+ argv[4] = NULL;
+
+ cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1,
+ NULL, NULL, &pid);
+ }
+#endif /* __APPLE__ */
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO, "Unknown LPDConfigFile scheme!");
+}
+
+
+/*
+ * 'update_polling()' - Read status messages from the poll daemons.
+ */
+
+static void
+update_polling(void)
+{
+ char *ptr, /* Pointer to end of line in buffer */
+ message[1024]; /* Pointer to message text */
+ int loglevel; /* Log level for message */
+
+
+ while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
+ message, sizeof(message))) != NULL)
+ {
+ if (loglevel == CUPSD_LOG_INFO)
+ cupsdLogMessage(CUPSD_LOG_INFO, "%s", message);
+
+ if (!strchr(PollStatusBuffer->buffer, '\n'))
+ break;
+ }
+
+ if (ptr == NULL && !PollStatusBuffer->bufused)
+ {
+ /*
+ * All polling processes have died; stop polling...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "update_polling: all polling processes have exited!");
+ cupsdStopPolling();
+ }
+}
+
+
+/*
+ * 'update_smb()' - Update the SMB configuration as needed.
+ */
+
+static void
+update_smb(int onoff) /* I - 1 = turn on, 0 = turn off */
+{
+ if (!SMBConfigFile)
+ return;
+
+ if (!strncmp(SMBConfigFile, "samba:///", 9))
+ {
+ /*
+ * Enable/disable SMB via the specified smb.conf config file...
+ */
+
+ char newfile[1024]; /* New smb.conf.N file */
+ cups_file_t *ofp, /* Original file pointer */
+ *nfp; /* New file pointer */
+ char line[1024]; /* Line from file */
+ int in_printers; /* In [printers] section? */
+
+
+ snprintf(newfile, sizeof(newfile), "%s.N", SMBConfigFile + 8);
+
+ if ((ofp = cupsFileOpen(SMBConfigFile + 8, "r")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
+ SMBConfigFile + 8, strerror(errno));
+ return;
+ }
+
+ if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
+ newfile, strerror(errno));
+ cupsFileClose(ofp);
+ return;
+ }
+
+ /*
+ * Copy all of the lines from the smb.conf file...
+ */
+
+ in_printers = 0;
+
+ while (cupsFileGets(ofp, line, sizeof(line)))
+ {
+ if (in_printers && strstr(line, "printable ="))
+ snprintf(line, sizeof(line), " printable = %s",
+ onoff ? "yes" : "no");
+
+ cupsFilePrintf(nfp, "%s\n", line);
+
+ if (line[0] == '[')
+ in_printers = !strcmp(line, "[printers]");
+ }
+
+ cupsFileClose(nfp);
+ cupsFileClose(ofp);
+ rename(newfile, SMBConfigFile + 8);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO, "Unknown SMBConfigFile scheme!");
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/dirsvc.h b/scheduler/dirsvc.h
new file mode 100644
index 000000000..99079bd67
--- /dev/null
+++ b/scheduler/dirsvc.h
@@ -0,0 +1,213 @@
+/*
+ * "$Id$"
+ *
+ * Directory services definitions for the CUPS scheduler.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#ifdef HAVE_LIBSLP
+# include <slp.h>
+#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_LDAP
+# ifdef __sun
+# include <lber.h>
+# endif /* __sun */
+# include <ldap.h>
+# ifdef HAVE_LDAP_SSL_H
+# include <ldap_ssl.h>
+# endif /* HAVE_LDAP_SSL_H */
+#endif /* HAVE_LDAP */
+
+/*
+ * Browse protocols...
+ */
+
+#define BROWSE_CUPS 1 /* CUPS */
+#define BROWSE_SLP 2 /* SLPv2 */
+#define BROWSE_LDAP 4 /* LDAP */
+#define BROWSE_DNSSD 8 /* DNS Service Discovery (aka Bonjour) */
+#define BROWSE_SMB 16 /* SMB/Samba */
+#define BROWSE_LPD 32 /* LPD via xinetd or launchd */
+#define BROWSE_ALL 63 /* All protocols */
+
+
+/*
+ * Browse address...
+ */
+
+typedef struct
+{
+ char iface[32]; /* Destination interface */
+ http_addr_t to; /* Destination address */
+} cupsd_dirsvc_addr_t;
+
+
+/*
+ * Relay structure...
+ */
+
+typedef struct
+{
+ cups_array_t *from; /* Source address/name mask(s) */
+ http_addr_t to; /* Destination address */
+} cupsd_dirsvc_relay_t;
+
+
+/*
+ * Polling structure...
+ */
+
+typedef struct
+{
+ char hostname[64]; /* Hostname (actually, IP address) */
+ int port; /* Port number */
+ int pid; /* Current poll server PID */
+} cupsd_dirsvc_poll_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR int Browsing VALUE(TRUE),
+ /* Whether or not browsing is enabled */
+ BrowseWebIF VALUE(FALSE),
+ /* Whether the web interface is advertised */
+ BrowseLocalProtocols
+ VALUE(BROWSE_ALL),
+ /* Protocols to support for local printers */
+ BrowseRemoteProtocols
+ VALUE(BROWSE_ALL),
+ /* Protocols to support for remote printers */
+ BrowseShortNames VALUE(TRUE),
+ /* Short names for remote printers? */
+ BrowseSocket VALUE(-1),
+ /* Socket for browsing */
+ BrowsePort VALUE(IPP_PORT),
+ /* Port number for broadcasts */
+ BrowseInterval VALUE(DEFAULT_INTERVAL),
+ /* Broadcast interval in seconds */
+ BrowseTimeout VALUE(DEFAULT_TIMEOUT),
+ /* Time out for printers in seconds */
+ UseNetworkDefault VALUE(CUPS_DEFAULT_USE_NETWORK_DEFAULT),
+ /* Use the network default printer? */
+ NumBrowsers VALUE(0);
+ /* Number of broadcast addresses */
+VAR char *BrowseLocalOptions
+ VALUE(NULL),
+ /* Options to add to local printer URIs */
+ *BrowseRemoteOptions
+ VALUE(NULL);
+ /* Options to add to remote printer URIs */
+VAR cupsd_dirsvc_addr_t *Browsers VALUE(NULL);
+ /* Broadcast addresses */
+VAR cupsd_location_t *BrowseACL VALUE(NULL);
+ /* Browser access control list */
+VAR cupsd_printer_t *BrowseNext VALUE(NULL);
+ /* Next class/printer to broadcast */
+VAR int NumRelays VALUE(0);
+ /* Number of broadcast relays */
+VAR cupsd_dirsvc_relay_t *Relays VALUE(NULL);
+ /* Broadcast relays */
+VAR int NumPolled VALUE(0);
+ /* Number of polled servers */
+VAR cupsd_dirsvc_poll_t *Polled VALUE(NULL);
+ /* Polled servers */
+VAR int PollPipe VALUE(0);
+ /* Status pipe for pollers */
+VAR cupsd_statbuf_t *PollStatusBuffer VALUE(NULL);
+ /* Status buffer for pollers */
+
+#ifdef HAVE_DNSSD
+VAR char *DNSSDComputerName VALUE(NULL),
+ /* Computer/server name */
+ *DNSSDHostName VALUE(NULL),
+ /* Hostname */
+ *DNSSDRegType VALUE(NULL);
+ /* Bonjour registration type */
+VAR cups_array_t *DNSSDAlias VALUE(NULL);
+ /* List of dynamic ServerAlias's */
+VAR int DNSSDPort VALUE(0);
+ /* Port number to register */
+VAR cups_array_t *DNSSDPrinters VALUE(NULL);
+ /* Printers we have registered */
+VAR DNSServiceRef DNSSDRef VALUE(NULL),
+ /* Master DNS-SD service reference */
+ WebIFRef VALUE(NULL),
+ /* Service reference for the web interface */
+ RemoteRef VALUE(NULL);
+ /* Remote printer browse reference */
+#endif /* HAVE_DNSSD */
+
+#ifdef HAVE_LIBSLP
+VAR SLPHandle BrowseSLPHandle VALUE(NULL);
+ /* SLP API handle */
+VAR time_t BrowseSLPRefresh VALUE(0);
+ /* Next SLP refresh time */
+#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_LDAP
+VAR LDAP *BrowseLDAPHandle VALUE(NULL);
+ /* Handle to LDAP server */
+VAR time_t BrowseLDAPRefresh VALUE(0);
+ /* Next LDAP refresh time */
+VAR char *BrowseLDAPBindDN VALUE(NULL),
+ /* LDAP login DN */
+ *BrowseLDAPDN VALUE(NULL),
+ /* LDAP search DN */
+ *BrowseLDAPPassword VALUE(NULL),
+ /* LDAP login password */
+ *BrowseLDAPServer VALUE(NULL);
+ /* LDAP server to use */
+VAR int BrowseLDAPUpdate VALUE(TRUE);
+ /* enables LDAP updates */
+# ifdef HAVE_LDAP_SSL
+VAR char *BrowseLDAPCACertFile VALUE(NULL);
+ /* LDAP CA CERT file to use */
+# endif /* HAVE_LDAP_SSL */
+#endif /* HAVE_LDAP */
+VAR char *LPDConfigFile VALUE(NULL),
+ /* LPD configuration file */
+ *SMBConfigFile VALUE(NULL);
+ /* SMB configuration file */
+
+
+/*
+ * Prototypes...
+ */
+
+extern void cupsdDeregisterPrinter(cupsd_printer_t *p, int removeit);
+extern void cupsdLoadRemoteCache(void);
+extern void cupsdRegisterPrinter(cupsd_printer_t *p);
+extern void cupsdRestartPolling(void);
+extern void cupsdSaveRemoteCache(void);
+extern void cupsdSendBrowseList(void);
+extern void cupsdStartBrowsing(void);
+extern void cupsdStartPolling(void);
+extern void cupsdStopBrowsing(void);
+extern void cupsdStopPolling(void);
+#ifdef HAVE_DNSSD
+extern void cupsdUpdateDNSSDName(void);
+#endif /* HAVE_DNSSD */
+#ifdef HAVE_LDAP
+extern void cupsdUpdateLDAPBrowse(void);
+#endif /* HAVE_LDAP */
+extern void cupsdUpdateSLPBrowse(void);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/env.c b/scheduler/env.c
new file mode 100644
index 000000000..19a942a07
--- /dev/null
+++ b/scheduler/env.c
@@ -0,0 +1,271 @@
+/*
+ * "$Id$"
+ *
+ * Environment management routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdInitEnv() - Initialize the current environment with standard
+ * variables.
+ * cupsdLoadEnv() - Copy common environment variables into an array.
+ * cupsdSetEnv() - Set a common environment variable.
+ * cupsdSetEnvf() - Set a formatted common environment variable.
+ * cupsdUpdateEnv() - Update the environment for the configured directories.
+ * clear_env() - Clear common environment variables.
+ * find_env() - Find a common environment variable.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+
+/*
+ * Local globals...
+ */
+
+static int num_common_env = 0; /* Number of common env vars */
+static char *common_env[MAX_ENV]; /* Common env vars */
+
+
+/*
+ * Local functions...
+ */
+
+static void clear_env(void);
+static int find_env(const char *name);
+
+
+/*
+ * 'cupsdInitEnv()' - Initialize the current environment with standard variables.
+ */
+
+void
+cupsdInitEnv(void)
+{
+ /*
+ * Clear existing environment variables...
+ */
+
+ clear_env();
+
+#if defined(__APPLE__)
+ /*
+ * Add special voodoo magic for MacOS X - this allows MacOS X
+ * programs to access their bundle resources properly...
+ *
+ * This string is replaced in cupsdStartProcess()...
+ */
+
+ cupsdSetString(common_env, "<CFProcessPath>");
+ num_common_env = 1;
+#endif /* __APPLE__ */
+}
+
+
+/*
+ * 'cupsdLoadEnv()' - Copy common environment variables into an array.
+ */
+
+int /* O - Number of environment variables */
+cupsdLoadEnv(char *envp[], /* I - Environment array */
+ int envmax) /* I - Maximum number of elements */
+{
+ int i; /* Looping var */
+
+
+ /*
+ * Leave room for a NULL pointer at the end...
+ */
+
+ envmax --;
+
+ /*
+ * Copy pointers to the environment...
+ */
+
+ for (i = 0; i < num_common_env && i < envmax; i ++)
+ envp[i] = common_env[i];
+
+ /*
+ * NULL terminate the environment array and return the number of
+ * elements we added...
+ */
+
+ envp[i] = NULL;
+
+ return (i);
+}
+
+
+/*
+ * 'cupsdSetEnv()' - Set a common environment variable.
+ */
+
+void
+cupsdSetEnv(const char *name, /* I - Name of variable */
+ const char *value) /* I - Value of variable */
+{
+ int i; /* Index into environent array */
+
+
+ /*
+ * If "value" is NULL, try getting value from current environment...
+ */
+
+ if (!value)
+ value = getenv(name);
+
+ if (!value)
+ return;
+
+ /*
+ * See if this variable has already been defined...
+ */
+
+ if ((i = find_env(name)) < 0)
+ {
+ /*
+ * Check for room...
+ */
+
+ if (num_common_env >= (int)(sizeof(common_env) / sizeof(common_env[0])))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdSetEnv: Too many environment variables set!");
+ return;
+ }
+
+ i = num_common_env;
+ num_common_env ++;
+ }
+
+ /*
+ * Set the new environment variable...
+ */
+
+ cupsdSetStringf(common_env + i, "%s=%s", name, value);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSetEnv: %s", common_env[i]);
+}
+
+
+/*
+ * 'cupsdSetEnvf()' - Set a formatted common environment variable.
+ */
+
+void
+cupsdSetEnvf(const char *name, /* I - Name of variable */
+ const char *value, /* I - Printf-style value of variable */
+ ...) /* I - Additional args as needed */
+{
+ char v[4096]; /* Formatting string value */
+ va_list ap; /* Argument pointer */
+
+
+ /*
+ * Format the value string...
+ */
+
+ va_start(ap, value);
+ vsnprintf(v, sizeof(v), value, ap);
+ va_end(ap);
+
+ /*
+ * Set the env variable...
+ */
+
+ cupsdSetEnv(name, v);
+}
+
+
+/*
+ * 'cupsdUpdateEnv()' - Update the environment for the configured directories.
+ */
+
+void
+cupsdUpdateEnv(void)
+{
+ /*
+ * Set common variables...
+ */
+
+#define set_if_undefined(name,value) if (find_env(name) < 0) cupsdSetEnv(name,value)
+
+ set_if_undefined("CUPS_CACHEDIR", CacheDir);
+ set_if_undefined("CUPS_DATADIR", DataDir);
+ set_if_undefined("CUPS_DOCROOT", DocumentRoot);
+ set_if_undefined("CUPS_FONTPATH", FontPath);
+ set_if_undefined("CUPS_REQUESTROOT", RequestRoot);
+ set_if_undefined("CUPS_SERVERBIN", ServerBin);
+ set_if_undefined("CUPS_SERVERROOT", ServerRoot);
+ set_if_undefined("CUPS_STATEDIR", StateDir);
+ set_if_undefined("DYLD_LIBRARY_PATH", NULL);
+ set_if_undefined("HOME", TempDir);
+ set_if_undefined("LD_ASSUME_KERNEL", NULL);
+ set_if_undefined("LD_LIBRARY_PATH", NULL);
+ set_if_undefined("LD_PRELOAD", NULL);
+ set_if_undefined("NLSPATH", NULL);
+ if (find_env("PATH") < 0)
+ cupsdSetEnvf("PATH", "%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR
+ ":/bin:/usr/bin", ServerBin);
+ set_if_undefined("SERVER_ADMIN", ServerAdmin);
+ set_if_undefined("SHLIB_PATH", NULL);
+ set_if_undefined("SOFTWARE", CUPS_MINIMAL);
+ set_if_undefined("TMPDIR", TempDir);
+ set_if_undefined("TZ", NULL);
+ set_if_undefined("USER", "root");
+ set_if_undefined("VG_ARGS", NULL);
+}
+
+
+/*
+ * 'clear_env()' - Clear common environment variables.
+ */
+
+static void
+clear_env(void)
+{
+ int i; /* Looping var */
+
+
+ for (i = 0; i < num_common_env; i ++)
+ cupsdClearString(common_env + i);
+
+ num_common_env = 0;
+}
+
+
+/*
+ * 'find_env()' - Find a common environment variable.
+ */
+
+static int /* O - Index or -1 if not found */
+find_env(const char *name) /* I - Variable name */
+{
+ int i; /* Looping var */
+ size_t namelen; /* Length of name */
+
+
+ for (i = 0, namelen = strlen(name); i < num_common_env; i ++)
+ if (!strncmp(common_env[i], name, namelen) && common_env[i][namelen] == '=')
+ return (i);
+
+ return (-1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/file.c b/scheduler/file.c
new file mode 100644
index 000000000..8d33610c1
--- /dev/null
+++ b/scheduler/file.c
@@ -0,0 +1,450 @@
+/*
+ * "$Id$"
+ *
+ * File functions for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdCleanFiles() - Clean out old files.
+ * cupsdCloseCreatedConfFile() - Close a created configuration file and move
+ * into place.
+ * cupsdClosePipe() - Close a pipe as necessary.
+ * cupsdCreateConfFile() - Create a configuration file safely.
+ * cupsdOpenConfFile() - Open a configuration file.
+ * cupsdOpenPipe() - Create a pipe which is closed on exec.
+ * cupsdRemoveFile() - Remove a file using the 7-pass US DoD method.
+ * overwrite_data() - Overwrite the data in a file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <cups/dir.h>
+#include <fnmatch.h>
+#ifdef HAVE_REMOVEFILE
+# include <removefile.h>
+#else
+static int overwrite_data(int fd, const char *buffer, int bufsize,
+ int filesize);
+#endif /* HAVE_REMOVEFILE */
+
+
+/*
+ * 'cupsdCleanFiles()' - Clean out old files.
+ */
+
+void
+cupsdCleanFiles(const char *path, /* I - Directory to clean */
+ const char *pattern) /* I - Filename pattern or NULL */
+{
+ cups_dir_t *dir; /* Directory */
+ cups_dentry_t *dent; /* Directory entry */
+ char filename[1024]; /* Filename */
+ int status; /* Status from unlink/rmdir */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdCleanFiles(path=\"%s\", pattern=\"%s\")", path,
+ pattern ? pattern : "(null)");
+
+ if ((dir = cupsDirOpen(path)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open directory \"%s\" - %s",
+ path, strerror(errno));
+ return;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Cleaning out old files in \"%s\"...", path);
+
+ while ((dent = cupsDirRead(dir)) != NULL)
+ {
+ if (pattern && fnmatch(pattern, dent->filename, 0))
+ continue;
+
+ snprintf(filename, sizeof(filename), "%s/%s", path, dent->filename);
+
+ if (S_ISDIR(dent->fileinfo.st_mode))
+ {
+ cupsdCleanFiles(filename, pattern);
+
+ status = rmdir(filename);
+ }
+ else
+ status = unlink(filename);
+
+ if (status)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove \"%s\" - %s", filename,
+ strerror(errno));
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Removed \"%s\"...", filename);
+ }
+
+ cupsDirClose(dir);
+}
+
+
+/*
+ * 'cupsdCloseCreatedConfFile()' - Close a created configuration file and move
+ * into place.
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsdCloseCreatedConfFile(
+ cups_file_t *fp, /* I - File to close */
+ const char *filename) /* I - Filename */
+{
+ char newfile[1024], /* filename.N */
+ oldfile[1024]; /* filename.O */
+
+
+ /*
+ * First close the file...
+ */
+
+ if (cupsFileClose(fp))
+ return (-1);
+
+ /*
+ * Then remove "filename.O", rename "filename" to "filename.O", and rename
+ * "filename.N" to "filename".
+ */
+
+ snprintf(newfile, sizeof(newfile), "%s.N", filename);
+ snprintf(oldfile, sizeof(oldfile), "%s.O", filename);
+
+ if ((cupsdRemoveFile(oldfile) && errno != ENOENT) ||
+ (rename(filename, oldfile) && errno != ENOENT) ||
+ rename(newfile, filename))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to finalize \"%s\": %s",
+ filename, strerror(errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'cupsdClosePipe()' - Close a pipe as necessary.
+ */
+
+void
+cupsdClosePipe(int *fds) /* I - Pipe file descriptors (2) */
+{
+ /*
+ * Close file descriptors as needed...
+ */
+
+ if (fds[0] >= 0)
+ {
+ close(fds[0]);
+ fds[0] = -1;
+ }
+
+ if (fds[1] >= 0)
+ {
+ close(fds[1]);
+ fds[1] = -1;
+ }
+}
+
+
+/*
+ * 'cupsdCreateConfFile()' - Create a configuration file safely.
+ */
+
+cups_file_t * /* O - File pointer */
+cupsdCreateConfFile(
+ const char *filename, /* I - Filename */
+ mode_t mode) /* I - Permissions */
+{
+ cups_file_t *fp; /* File pointer */
+ char newfile[1024]; /* filename.N */
+
+
+ snprintf(newfile, sizeof(newfile), "%s.N", filename);
+ if ((fp = cupsFileOpen(newfile, "w")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\": %s", newfile,
+ strerror(errno));
+ }
+ else
+ {
+ if (!getuid() && fchown(cupsFileNumber(fp), getuid(), Group))
+ cupsdLogMessage(CUPSD_LOG_WARN, "Unable to change group for \"%s\": %s",
+ newfile, strerror(errno));
+
+ if (fchmod(cupsFileNumber(fp), mode))
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Unable to change permissions for \"%s\": %s",
+ newfile, strerror(errno));
+ }
+
+ return (fp);
+}
+
+
+/*
+ * 'cupsdOpenConfFile()' - Open a configuration file.
+ *
+ * This function looks for "filename.O" if "filename" does not exist and does
+ * a rename as needed.
+ */
+
+cups_file_t * /* O - File pointer */
+cupsdOpenConfFile(const char *filename) /* I - Filename */
+{
+ cups_file_t *fp; /* File pointer */
+
+
+ if ((fp = cupsFileOpen(filename, "r")) == NULL)
+ {
+ if (errno == ENOENT)
+ {
+ /*
+ * Try opening the backup file...
+ */
+
+ char oldfile[1024]; /* filename.O */
+
+ snprintf(oldfile, sizeof(oldfile), "%s.O", filename);
+ fp = cupsFileOpen(oldfile, "r");
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\": %s", filename,
+ strerror(errno));
+ }
+
+ return (fp);
+}
+
+
+/*
+ * 'cupsdOpenPipe()' - Create a pipe which is closed on exec.
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsdOpenPipe(int *fds) /* O - Pipe file descriptors (2) */
+{
+ /*
+ * Create the pipe...
+ */
+
+ if (pipe(fds))
+ {
+ fds[0] = -1;
+ fds[1] = -1;
+
+ return (-1);
+ }
+
+ /*
+ * Set the "close on exec" flag on each end of the pipe...
+ */
+
+ if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
+ {
+ close(fds[0]);
+ close(fds[1]);
+
+ fds[0] = -1;
+ fds[1] = -1;
+
+ return (-1);
+ }
+
+ if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
+ {
+ close(fds[0]);
+ close(fds[1]);
+
+ fds[0] = -1;
+ fds[1] = -1;
+
+ return (-1);
+ }
+
+ /*
+ * Return 0 indicating success...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'cupsdRemoveFile()' - Remove a file using the 7-pass US DoD method.
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsdRemoveFile(const char *filename) /* I - File to remove */
+{
+#ifdef HAVE_REMOVEFILE
+ return (removefile(filename, NULL, REMOVEFILE_SECURE_7_PASS));
+
+#else
+ int fd; /* File descriptor */
+ struct stat info; /* File information */
+ char buffer[512]; /* Data buffer */
+ int i; /* Looping var */
+
+
+ /*
+ * First open the file for writing in exclusive mode.
+ */
+
+ if ((fd = open(filename, O_WRONLY | O_EXCL)) < 0)
+ return (-1);
+
+ /*
+ * Delete the file now - it will still be around as long as the file is
+ * open...
+ */
+
+ if (unlink(filename))
+ {
+ close(fd);
+ return (-1);
+ }
+
+ /*
+ * Then get the file size...
+ */
+
+ if (fstat(fd, &info))
+ {
+ close(fd);
+ return (-1);
+ }
+
+ /*
+ * Overwrite the file 7 times with 0xF6, 0x00, 0xFF, random, 0x00, 0xFF,
+ * and more random data.
+ */
+
+ memset(buffer, 0xF6, sizeof(buffer));
+ if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
+ {
+ close(fd);
+ return (-1);
+ }
+
+ memset(buffer, 0x00, sizeof(buffer));
+ if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
+ {
+ close(fd);
+ return (-1);
+ }
+
+ memset(buffer, 0xFF, sizeof(buffer));
+ if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
+ {
+ close(fd);
+ return (-1);
+ }
+
+ CUPS_SRAND(time(NULL));
+
+ for (i = 0; i < sizeof(buffer); i ++)
+ buffer[i] = CUPS_RAND();
+ if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
+ {
+ close(fd);
+ return (-1);
+ }
+
+ memset(buffer, 0x00, sizeof(buffer));
+ if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
+ {
+ close(fd);
+ return (-1);
+ }
+
+ memset(buffer, 0xFF, sizeof(buffer));
+ if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
+ {
+ close(fd);
+ return (-1);
+ }
+
+ for (i = 0; i < sizeof(buffer); i ++)
+ buffer[i] = CUPS_RAND();
+ if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
+ {
+ close(fd);
+ return (-1);
+ }
+
+ /*
+ * Whew! Close the file (which will lead to the actual deletion) and
+ * return success...
+ */
+
+ close(fd);
+ return (0);
+#endif /* HAVE_REMOVEFILE */
+}
+
+
+#ifndef HAVE_REMOVEFILE
+/*
+ * 'overwrite_data()' - Overwrite the data in a file.
+ */
+
+static int /* O - 0 on success, -1 on error */
+overwrite_data(int fd, /* I - File descriptor */
+ const char *buffer, /* I - Buffer to write */
+ int bufsize, /* I - Size of buffer */
+ int filesize) /* I - Size of file */
+{
+ int bytes; /* Bytes to write/written */
+
+
+ /*
+ * Start at the beginning of the file...
+ */
+
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ return (-1);
+
+ /*
+ * Fill the file with the provided data...
+ */
+
+ while (filesize > 0)
+ {
+ if (filesize > bufsize)
+ bytes = bufsize;
+ else
+ bytes = filesize;
+
+ if ((bytes = write(fd, buffer, bytes)) < 0)
+ return (-1);
+
+ filesize -= bytes;
+ }
+
+ /*
+ * Force the changes to disk...
+ */
+
+ return (fsync(fd));
+}
+#endif /* HAVE_REMOVEFILE */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/filter.c b/scheduler/filter.c
new file mode 100644
index 000000000..d1446f654
--- /dev/null
+++ b/scheduler/filter.c
@@ -0,0 +1,504 @@
+/*
+ * "$Id$"
+ *
+ * File type conversion routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * mimeAddFilter() - Add a filter to the current MIME database.
+ * mimeFilter() - Find the fastest way to convert from one type to
+ * another.
+ * mimeFilter2() - Find the fastest way to convert from one type to
+ * another, including the file size.
+ * mimeFilterLookup() - Lookup a filter.
+ * mime_compare_filters() - Compare two filters.
+ * mime_compare_srcs() - Compare two filter source types.
+ * mime_find_filters() - Find the filters to convert from one type to
+ * another.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/string-private.h>
+#include <cups/debug-private.h>
+#include "mime.h"
+
+
+/*
+ * Local types...
+ */
+
+typedef struct _mime_typelist_s /**** List of source types ****/
+{
+ struct _mime_typelist_s *next; /* Next source type */
+ mime_type_t *src; /* Source type */
+} _mime_typelist_t;
+
+
+/*
+ * Local functions...
+ */
+
+static int mime_compare_filters(mime_filter_t *, mime_filter_t *);
+static int mime_compare_srcs(mime_filter_t *, mime_filter_t *);
+static cups_array_t *mime_find_filters(mime_t *mime, mime_type_t *src,
+ size_t srcsize, mime_type_t *dst,
+ int *cost, _mime_typelist_t *visited);
+
+
+/*
+ * 'mimeAddFilter()' - Add a filter to the current MIME database.
+ */
+
+mime_filter_t * /* O - New filter */
+mimeAddFilter(mime_t *mime, /* I - MIME database */
+ mime_type_t *src, /* I - Source type */
+ mime_type_t *dst, /* I - Destination type */
+ int cost, /* I - Relative time/resource cost */
+ const char *filter) /* I - Filter program to run */
+{
+ mime_filter_t *temp; /* New filter */
+
+
+ DEBUG_printf(("mimeAddFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), cost=%d, "
+ "filter=\"%s\")", mime,
+ src, src ? src->super : "???", src ? src->type : "???",
+ dst, dst ? dst->super : "???", dst ? dst->type : "???",
+ cost, filter));
+
+ /*
+ * Range-check the input...
+ */
+
+ if (!mime || !src || !dst || !filter)
+ {
+ DEBUG_puts("1mimeAddFilter: Returning NULL.");
+ return (NULL);
+ }
+
+ /*
+ * See if we already have an existing filter for the given source and
+ * destination...
+ */
+
+ if ((temp = mimeFilterLookup(mime, src, dst)) != NULL)
+ {
+ /*
+ * Yup, does the existing filter have a higher cost? If so, copy the
+ * filter and cost to the existing filter entry and return it...
+ */
+
+ if (temp->cost > cost)
+ {
+ DEBUG_printf(("1mimeAddFilter: Replacing filter \"%s\", cost %d.",
+ temp->filter, temp->cost));
+ temp->cost = cost;
+ strlcpy(temp->filter, filter, sizeof(temp->filter));
+ }
+ }
+ else
+ {
+ /*
+ * Nope, add a new one...
+ */
+
+ if (!mime->filters)
+ mime->filters = cupsArrayNew((cups_array_func_t)mime_compare_filters, NULL);
+
+ if (!mime->filters)
+ return (NULL);
+
+ if ((temp = calloc(1, sizeof(mime_filter_t))) == NULL)
+ return (NULL);
+
+ /*
+ * Copy the information over and sort if necessary...
+ */
+
+ temp->src = src;
+ temp->dst = dst;
+ temp->cost = cost;
+ strlcpy(temp->filter, filter, sizeof(temp->filter));
+
+ DEBUG_puts("1mimeAddFilter: Adding new filter.");
+ cupsArrayAdd(mime->filters, temp);
+ cupsArrayAdd(mime->srcs, temp);
+ }
+
+ /*
+ * Return the new/updated filter...
+ */
+
+ DEBUG_printf(("1mimeAddFilter: Returning %p.", temp));
+
+ return (temp);
+}
+
+
+/*
+ * 'mimeFilter()' - Find the fastest way to convert from one type to another.
+ */
+
+cups_array_t * /* O - Array of filters to run */
+mimeFilter(mime_t *mime, /* I - MIME database */
+ mime_type_t *src, /* I - Source file type */
+ mime_type_t *dst, /* I - Destination file type */
+ int *cost) /* O - Cost of filters */
+{
+ DEBUG_printf(("mimeFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), "
+ "cost=%p(%d))", mime,
+ src, src ? src->super : "???", src ? src->type : "???",
+ dst, dst ? dst->super : "???", dst ? dst->type : "???",
+ cost, cost ? *cost : 0));
+
+ return (mimeFilter2(mime, src, 0, dst, cost));
+}
+
+
+/*
+ * 'mimeFilter2()' - Find the fastest way to convert from one type to another,
+ * including file size.
+ */
+
+cups_array_t * /* O - Array of filters to run */
+mimeFilter2(mime_t *mime, /* I - MIME database */
+ mime_type_t *src, /* I - Source file type */
+ size_t srcsize, /* I - Size of source file */
+ mime_type_t *dst, /* I - Destination file type */
+ int *cost) /* O - Cost of filters */
+{
+ cups_array_t *filters; /* Array of filters to run */
+
+
+ /*
+ * Range-check the input...
+ */
+
+ DEBUG_printf(("mimeFilter2(mime=%p, src=%p(%s/%s), srcsize=" CUPS_LLFMT
+ ", dst=%p(%s/%s), cost=%p(%d))", mime,
+ src, src ? src->super : "???", src ? src->type : "???",
+ CUPS_LLCAST srcsize,
+ dst, dst ? dst->super : "???", dst ? dst->type : "???",
+ cost, cost ? *cost : 0));
+
+ if (cost)
+ *cost = 0;
+
+ if (!mime || !src || !dst)
+ return (NULL);
+
+ /*
+ * (Re)build the source lookup array as needed...
+ */
+
+ if (!mime->srcs)
+ {
+ mime_filter_t *current; /* Current filter */
+
+ mime->srcs = cupsArrayNew((cups_array_func_t)mime_compare_srcs, NULL);
+
+ for (current = mimeFirstFilter(mime);
+ current;
+ current = mimeNextFilter(mime))
+ cupsArrayAdd(mime->srcs, current);
+ }
+
+ /*
+ * Find the filters...
+ */
+
+ filters = mime_find_filters(mime, src, srcsize, dst, cost, NULL);
+
+ DEBUG_printf(("1mimeFilter2: Returning %d filter(s), cost %d:",
+ cupsArrayCount(filters), cost ? *cost : -1));
+#ifdef DEBUG
+ {
+ mime_filter_t *filter; /* Current filter */
+
+ for (filter = (mime_filter_t *)cupsArrayFirst(filters);
+ filter;
+ filter = (mime_filter_t *)cupsArrayNext(filters))
+ DEBUG_printf(("1mimeFilter2: %s/%s %s/%s %d %s", filter->src->super,
+ filter->src->type, filter->dst->super, filter->dst->type,
+ filter->cost, filter->filter));
+ }
+#endif /* DEBUG */
+
+ return (filters);
+}
+
+
+/*
+ * 'mimeFilterLookup()' - Lookup a filter.
+ */
+
+mime_filter_t * /* O - Filter for src->dst */
+mimeFilterLookup(mime_t *mime, /* I - MIME database */
+ mime_type_t *src, /* I - Source type */
+ mime_type_t *dst) /* I - Destination type */
+{
+ mime_filter_t key, /* Key record for filter search */
+ *filter; /* Matching filter */
+
+
+ DEBUG_printf(("2mimeFilterLookup(mime=%p, src=%p(%s/%s), dst=%p(%s/%s))", mime,
+ src, src ? src->super : "???", src ? src->type : "???",
+ dst, dst ? dst->super : "???", dst ? dst->type : "???"));
+
+ key.src = src;
+ key.dst = dst;
+
+ filter = (mime_filter_t *)cupsArrayFind(mime->filters, &key);
+ DEBUG_printf(("3mimeFilterLookup: Returning %p(%s).", filter,
+ filter ? filter->filter : "???"));
+ return (filter);
+}
+
+
+/*
+ * 'mime_compare_filters()' - Compare two filters.
+ */
+
+static int /* O - Comparison result */
+mime_compare_filters(mime_filter_t *f0, /* I - First filter */
+ mime_filter_t *f1) /* I - Second filter */
+{
+ int i; /* Result of comparison */
+
+
+ if ((i = strcmp(f0->src->super, f1->src->super)) == 0)
+ if ((i = strcmp(f0->src->type, f1->src->type)) == 0)
+ if ((i = strcmp(f0->dst->super, f1->dst->super)) == 0)
+ i = strcmp(f0->dst->type, f1->dst->type);
+
+ return (i);
+}
+
+
+/*
+ * 'mime_compare_srcs()' - Compare two filter source types.
+ */
+
+static int /* O - Comparison result */
+mime_compare_srcs(mime_filter_t *f0, /* I - First filter */
+ mime_filter_t *f1) /* I - Second filter */
+{
+ int i; /* Result of comparison */
+
+
+ if ((i = strcmp(f0->src->super, f1->src->super)) == 0)
+ i = strcmp(f0->src->type, f1->src->type);
+
+ return (i);
+}
+
+
+/*
+ * 'mime_find_filters()' - Find the filters to convert from one type to another.
+ */
+
+static cups_array_t * /* O - Array of filters to run */
+mime_find_filters(
+ mime_t *mime, /* I - MIME database */
+ mime_type_t *src, /* I - Source file type */
+ size_t srcsize, /* I - Size of source file */
+ mime_type_t *dst, /* I - Destination file type */
+ int *cost, /* O - Cost of filters */
+ _mime_typelist_t *list) /* I - Source types we've used */
+{
+ int tempcost, /* Temporary cost */
+ mincost; /* Current minimum */
+ cups_array_t *temp, /* Temporary filter */
+ *mintemp; /* Current minimum */
+ mime_filter_t *current, /* Current filter */
+ srckey; /* Source type key */
+ _mime_typelist_t listnode, /* New list node */
+ *listptr; /* Pointer in list */
+
+
+ DEBUG_printf(("2mime_find_filters(mime=%p, src=%p(%s/%s), srcsize=" CUPS_LLFMT
+ ", dst=%p(%s/%s), cost=%p, list=%p)", mime, src, src->super,
+ src->type, CUPS_LLCAST srcsize, dst, dst->super, dst->type,
+ cost, list));
+
+ /*
+ * See if there is a filter that can convert the files directly...
+ */
+
+ if ((current = mimeFilterLookup(mime, src, dst)) != NULL &&
+ (current->maxsize == 0 || srcsize <= current->maxsize))
+ {
+ /*
+ * Got a direct filter!
+ */
+
+ DEBUG_puts("3mime_find_filters: Direct filter found.");
+
+ if ((mintemp = cupsArrayNew(NULL, NULL)) == NULL)
+ {
+ DEBUG_puts("3mime_find_filters: Returning NULL (out of memory).");
+ return (NULL);
+ }
+
+ cupsArrayAdd(mintemp, current);
+
+ mincost = current->cost;
+
+ if (!cost)
+ {
+ DEBUG_printf(("3mime_find_filters: Returning 1 filter, cost %d:",
+ mincost));
+ DEBUG_printf(("3mime_find_filters: %s/%s %s/%s %d %s",
+ current->src->super, current->src->type,
+ current->dst->super, current->dst->type,
+ current->cost, current->filter));
+ return (mintemp);
+ }
+ }
+ else
+ {
+ /*
+ * No direct filter...
+ */
+
+ mintemp = NULL;
+ mincost = 9999999;
+ }
+
+ /*
+ * Initialize this node in the type list...
+ */
+
+ listnode.next = list;
+
+ /*
+ * OK, now look for filters from the source type to any other type...
+ */
+
+ srckey.src = src;
+
+ for (current = (mime_filter_t *)cupsArrayFind(mime->srcs, &srckey);
+ current && current->src == src;
+ current = (mime_filter_t *)cupsArrayNext(mime->srcs))
+ {
+ /*
+ * See if we have already tried the destination type as a source
+ * type (this avoids extra filter looping...)
+ */
+
+ mime_type_t *current_dst; /* Current destination type */
+
+ if (current->maxsize > 0 && srcsize > current->maxsize)
+ continue;
+
+ for (listptr = list, current_dst = current->dst;
+ listptr;
+ listptr = listptr->next)
+ if (current_dst == listptr->src)
+ break;
+
+ if (listptr)
+ continue;
+
+ /*
+ * See if we have any filters that can convert from the destination type
+ * of this filter to the final type...
+ */
+
+ listnode.src = current->src;
+
+ cupsArraySave(mime->srcs);
+ temp = mime_find_filters(mime, current->dst, srcsize, dst, &tempcost,
+ &listnode);
+ cupsArrayRestore(mime->srcs);
+
+ if (!temp)
+ continue;
+
+ if (!cost)
+ {
+ DEBUG_printf(("3mime_find_filters: Returning %d filter(s), cost %d:",
+ cupsArrayCount(temp), tempcost));
+
+#ifdef DEBUG
+ for (current = (mime_filter_t *)cupsArrayFirst(temp);
+ current;
+ current = (mime_filter_t *)cupsArrayNext(temp))
+ DEBUG_printf(("3mime_find_filters: %s/%s %s/%s %d %s",
+ current->src->super, current->src->type,
+ current->dst->super, current->dst->type,
+ current->cost, current->filter));
+#endif /* DEBUG */
+
+ return (temp);
+ }
+
+ /*
+ * Found a match; see if this one is less costly than the last (if
+ * any...)
+ */
+
+ tempcost += current->cost;
+
+ if (tempcost < mincost)
+ {
+ cupsArrayDelete(mintemp);
+
+ /*
+ * Hey, we got a match! Add the current filter to the beginning of the
+ * filter list...
+ */
+
+ mintemp = temp;
+ mincost = tempcost;
+ cupsArrayInsert(mintemp, current);
+ }
+ else
+ cupsArrayDelete(temp);
+ }
+
+ if (mintemp)
+ {
+ /*
+ * Hey, we got a match!
+ */
+
+ DEBUG_printf(("3mime_find_filters: Returning %d filter(s), cost %d:",
+ cupsArrayCount(mintemp), mincost));
+
+#ifdef DEBUG
+ for (current = (mime_filter_t *)cupsArrayFirst(mintemp);
+ current;
+ current = (mime_filter_t *)cupsArrayNext(mintemp))
+ DEBUG_printf(("3mime_find_filters: %s/%s %s/%s %d %s",
+ current->src->super, current->src->type,
+ current->dst->super, current->dst->type,
+ current->cost, current->filter));
+#endif /* DEBUG */
+
+ if (cost)
+ *cost = mincost;
+
+ return (mintemp);
+ }
+
+ DEBUG_puts("3mime_find_filters: Returning NULL (no matches).");
+
+ return (NULL);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/ipp.c b/scheduler/ipp.c
new file mode 100644
index 000000000..94b25cc26
--- /dev/null
+++ b/scheduler/ipp.c
@@ -0,0 +1,12256 @@
+/*
+ * "$Id$"
+ *
+ * IPP routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * This file contains Kerberos support code, copyright 2006 by
+ * Jelmer Vernooij.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdProcessIPPRequest() - Process an incoming IPP request.
+ * cupsdTimeoutJob() - Timeout a job waiting on job files.
+ * accept_jobs() - Accept print jobs to a printer.
+ * add_class() - Add a class to the system.
+ * add_file() - Add a file to a job.
+ * add_job() - Add a job to a print queue.
+ * add_job_state_reasons() - Add the "job-state-reasons" attribute based
+ * upon the job and printer state...
+ * add_job_subscriptions() - Add any subscriptions for a job.
+ * add_job_uuid() - Add job-uuid attribute to a job.
+ * add_printer() - Add a printer to the system.
+ * add_printer_state_reasons() - Add the "printer-state-reasons" attribute
+ * based upon the printer state...
+ * add_queued_job_count() - Add the "queued-job-count" attribute for the
+ * specified printer or class.
+ * apple_init_profile() - Initialize a color profile.
+ * apple_register_profiles() - Register color profiles for a printer.
+ * apple_unregister_profiles() - Remove color profiles for the specified
+ * printer.
+ * apply_printer_defaults() - Apply printer default options to a job.
+ * authenticate_job() - Set job authentication info.
+ * cancel_all_jobs() - Cancel all or selected print jobs.
+ * cancel_job() - Cancel a print job.
+ * cancel_subscription() - Cancel a subscription.
+ * check_rss_recipient() - Check that we do not have a duplicate RSS
+ * feed URI.
+ * check_quotas() - Check quotas for a printer and user.
+ * close_job() - Close a multi-file job.
+ * copy_attribute() - Copy a single attribute.
+ * copy_attrs() - Copy attributes from one request to another.
+ * copy_banner() - Copy a banner file to the requests directory
+ * for the specified job.
+ * copy_file() - Copy a PPD file or interface script...
+ * copy_model() - Copy a PPD model file, substituting default
+ * values as needed...
+ * copy_job_attrs() - Copy job attributes.
+ * copy_printer_attrs() - Copy printer attributes.
+ * copy_subscription_attrs() - Copy subscription attributes.
+ * create_job() - Print a file to a printer or class.
+ * create_requested_array() - Create an array for the requested-attributes.
+ * create_subscription() - Create a notification subscription.
+ * delete_printer() - Remove a printer or class from the system.
+ * get_default() - Get the default destination.
+ * get_devices() - Get the list of available devices on the
+ * local system.
+ * get_document() - Get a copy of a job file.
+ * get_job_attrs() - Get job attributes.
+ * get_jobs() - Get a list of jobs for the specified printer.
+ * get_notifications() - Get events for a subscription.
+ * get_ppd() - Get a named PPD from the local system.
+ * get_ppds() - Get the list of PPD files on the local
+ * system.
+ * get_printer_attrs() - Get printer attributes.
+ * get_printer_supported() - Get printer supported values.
+ * get_printers() - Get a list of printers or classes.
+ * get_subscription_attrs() - Get subscription attributes.
+ * get_subscriptions() - Get subscriptions.
+ * get_username() - Get the username associated with a request.
+ * hold_job() - Hold a print job.
+ * hold_new_jobs() - Hold pending/new jobs on a printer or class.
+ * move_job() - Move a job to a new destination.
+ * ppd_parse_line() - Parse a PPD default line.
+ * print_job() - Print a file to a printer or class.
+ * read_job_ticket() - Read a job ticket embedded in a print file.
+ * reject_jobs() - Reject print jobs to a printer.
+ * release_held_new_jobs() - Release pending/new jobs on a printer or
+ * class.
+ * release_job() - Release a held print job.
+ * renew_subscription() - Renew an existing subscription...
+ * restart_job() - Restart an old print job.
+ * save_auth_info() - Save authentication information for a job.
+ * send_document() - Send a file to a printer or class.
+ * send_http_error() - Send a HTTP error back to the IPP client.
+ * send_ipp_status() - Send a status back to the IPP client.
+ * set_default() - Set the default destination...
+ * set_job_attrs() - Set job attributes.
+ * set_printer_attrs() - Set printer attributes.
+ * set_printer_defaults() - Set printer default options from a request.
+ * start_printer() - Start a printer.
+ * stop_printer() - Stop a printer.
+ * url_encode_attr() - URL-encode a string attribute.
+ * url_encode_string() - URL-encode a string.
+ * user_allowed() - See if a user is allowed to print to a queue.
+ * validate_job() - Validate printer options and destination.
+ * validate_name() - Make sure the printer name only contains
+ * valid chars.
+ * validate_user() - Validate the user for the request.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <cups/ppd-private.h>
+
+#ifdef __APPLE__
+# include <ApplicationServices/ApplicationServices.h>
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+extern CFUUIDRef ColorSyncCreateUUIDFromUInt32(unsigned id);
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+# include <CoreFoundation/CoreFoundation.h>
+# ifdef HAVE_MEMBERSHIP_H
+# include <membership.h>
+# endif /* HAVE_MEMBERSHIP_H */
+# ifdef HAVE_MEMBERSHIPPRIV_H
+# include <membershipPriv.h>
+# else
+extern int mbr_user_name_to_uuid(const char* name, uuid_t uu);
+extern int mbr_group_name_to_uuid(const char* name, uuid_t uu);
+extern int mbr_check_membership_by_id(uuid_t user, gid_t group, int* ismember);
+# endif /* HAVE_MEMBERSHIPPRIV_H */
+#endif /* __APPLE__ */
+
+
+/*
+ * Local functions...
+ */
+
+static void accept_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
+static void add_class(cupsd_client_t *con, ipp_attribute_t *uri);
+static int add_file(cupsd_client_t *con, cupsd_job_t *job,
+ mime_type_t *filetype, int compression);
+static cupsd_job_t *add_job(cupsd_client_t *con, cupsd_printer_t *printer,
+ mime_type_t *filetype);
+static void add_job_state_reasons(cupsd_client_t *con, cupsd_job_t *job);
+static void add_job_subscriptions(cupsd_client_t *con, cupsd_job_t *job);
+static void add_job_uuid(cupsd_job_t *job);
+static void add_printer(cupsd_client_t *con, ipp_attribute_t *uri);
+static void add_printer_state_reasons(cupsd_client_t *con,
+ cupsd_printer_t *p);
+static void add_queued_job_count(cupsd_client_t *con, cupsd_printer_t *p);
+#ifdef __APPLE__
+static void apple_init_profile(ppd_file_t *ppd, cups_array_t *languages,
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+ CFMutableDictionaryRef profile,
+# else
+ CMDeviceProfileInfo *profile,
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+ unsigned id, const char *name,
+ const char *text, const char *iccfile);
+static void apple_register_profiles(cupsd_printer_t *p);
+static void apple_unregister_profiles(cupsd_printer_t *p);
+#endif /* __APPLE__ */
+static void apply_printer_defaults(cupsd_printer_t *printer,
+ cupsd_job_t *job);
+static void authenticate_job(cupsd_client_t *con, ipp_attribute_t *uri);
+static void cancel_all_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
+static void cancel_job(cupsd_client_t *con, ipp_attribute_t *uri);
+static void cancel_subscription(cupsd_client_t *con, int id);
+static int check_rss_recipient(const char *recipient);
+static int check_quotas(cupsd_client_t *con, cupsd_printer_t *p);
+static ipp_attribute_t *copy_attribute(ipp_t *to, ipp_attribute_t *attr,
+ int quickcopy);
+static void close_job(cupsd_client_t *con, ipp_attribute_t *uri);
+static void copy_attrs(ipp_t *to, ipp_t *from, cups_array_t *ra,
+ ipp_tag_t group, int quickcopy,
+ cups_array_t *exclude);
+static int copy_banner(cupsd_client_t *con, cupsd_job_t *job,
+ const char *name);
+static int copy_file(const char *from, const char *to);
+static int copy_model(cupsd_client_t *con, const char *from,
+ const char *to);
+static void copy_job_attrs(cupsd_client_t *con,
+ cupsd_job_t *job,
+ cups_array_t *ra, cups_array_t *exclude);
+static void copy_printer_attrs(cupsd_client_t *con,
+ cupsd_printer_t *printer,
+ cups_array_t *ra);
+static void copy_subscription_attrs(cupsd_client_t *con,
+ cupsd_subscription_t *sub,
+ cups_array_t *ra,
+ cups_array_t *exclude);
+static void create_job(cupsd_client_t *con, ipp_attribute_t *uri);
+static cups_array_t *create_requested_array(ipp_t *request);
+static void create_subscription(cupsd_client_t *con, ipp_attribute_t *uri);
+static void delete_printer(cupsd_client_t *con, ipp_attribute_t *uri);
+static void get_default(cupsd_client_t *con);
+static void get_devices(cupsd_client_t *con);
+static void get_document(cupsd_client_t *con, ipp_attribute_t *uri);
+static void get_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
+static void get_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
+static void get_notifications(cupsd_client_t *con);
+static void get_ppd(cupsd_client_t *con, ipp_attribute_t *uri);
+static void get_ppds(cupsd_client_t *con);
+static void get_printers(cupsd_client_t *con, int type);
+static void get_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
+static void get_printer_supported(cupsd_client_t *con, ipp_attribute_t *uri);
+static void get_subscription_attrs(cupsd_client_t *con, int sub_id);
+static void get_subscriptions(cupsd_client_t *con, ipp_attribute_t *uri);
+static const char *get_username(cupsd_client_t *con);
+static void hold_job(cupsd_client_t *con, ipp_attribute_t *uri);
+static void hold_new_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
+static void move_job(cupsd_client_t *con, ipp_attribute_t *uri);
+static int ppd_parse_line(const char *line, char *option, int olen,
+ char *choice, int clen);
+static void print_job(cupsd_client_t *con, ipp_attribute_t *uri);
+static void read_job_ticket(cupsd_client_t *con);
+static void reject_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
+static void release_held_new_jobs(cupsd_client_t *con,
+ ipp_attribute_t *uri);
+static void release_job(cupsd_client_t *con, ipp_attribute_t *uri);
+static void renew_subscription(cupsd_client_t *con, int sub_id);
+static void restart_job(cupsd_client_t *con, ipp_attribute_t *uri);
+static void save_auth_info(cupsd_client_t *con, cupsd_job_t *job,
+ ipp_attribute_t *auth_info);
+static void send_document(cupsd_client_t *con, ipp_attribute_t *uri);
+static void send_http_error(cupsd_client_t *con, http_status_t status,
+ cupsd_printer_t *printer);
+static void send_ipp_status(cupsd_client_t *con, ipp_status_t status,
+ const char *message, ...)
+# ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 3, 4)))
+# endif /* __GNUC__ */
+;
+static void set_default(cupsd_client_t *con, ipp_attribute_t *uri);
+static void set_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
+static void set_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
+static void set_printer_defaults(cupsd_client_t *con,
+ cupsd_printer_t *printer);
+static void start_printer(cupsd_client_t *con, ipp_attribute_t *uri);
+static void stop_printer(cupsd_client_t *con, ipp_attribute_t *uri);
+static void url_encode_attr(ipp_attribute_t *attr, char *buffer,
+ int bufsize);
+static char *url_encode_string(const char *s, char *buffer, int bufsize);
+static int user_allowed(cupsd_printer_t *p, const char *username);
+static void validate_job(cupsd_client_t *con, ipp_attribute_t *uri);
+static int validate_name(const char *name);
+static int validate_user(cupsd_job_t *job, cupsd_client_t *con,
+ const char *owner, char *username,
+ int userlen);
+
+
+/*
+ * 'cupsdProcessIPPRequest()' - Process an incoming IPP request.
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsdProcessIPPRequest(
+ cupsd_client_t *con) /* I - Client connection */
+{
+ ipp_tag_t group; /* Current group tag */
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_attribute_t *charset; /* Character set attribute */
+ ipp_attribute_t *language; /* Language attribute */
+ ipp_attribute_t *uri = NULL; /* Printer or job URI attribute */
+ ipp_attribute_t *username; /* requesting-user-name attr */
+ int sub_id; /* Subscription ID */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdProcessIPPRequest(%p[%d]): operation_id = %04x",
+ con, con->http.fd, con->request->request.op.operation_id);
+
+ /*
+ * First build an empty response message for this request...
+ */
+
+ con->response = ippNew();
+
+ con->response->request.status.version[0] =
+ con->request->request.op.version[0];
+ con->response->request.status.version[1] =
+ con->request->request.op.version[1];
+ con->response->request.status.request_id =
+ con->request->request.op.request_id;
+
+ /*
+ * Then validate the request header and required attributes...
+ */
+
+ if (con->request->request.any.version[0] != 1 &&
+ con->request->request.any.version[0] != 2)
+ {
+ /*
+ * Return an error, since we only support IPP 1.x and 2.x.
+ */
+
+ cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
+ "%04X %s Bad request version number %d.%d",
+ IPP_VERSION_NOT_SUPPORTED, con->http.hostname,
+ con->request->request.any.version[0],
+ con->request->request.any.version[1]);
+
+ send_ipp_status(con, IPP_VERSION_NOT_SUPPORTED,
+ _("Bad request version number %d.%d."),
+ con->request->request.any.version[0],
+ con->request->request.any.version[1]);
+ }
+ else if (con->request->request.any.request_id < 1)
+ {
+ /*
+ * Return an error, since request IDs must be between 1 and 2^31-1
+ */
+
+ cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
+ "%04X %s Bad request ID %d",
+ IPP_BAD_REQUEST, con->http.hostname,
+ con->request->request.any.request_id);
+
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad request ID %d."),
+ con->request->request.any.request_id);
+ }
+ else if (!con->request->attrs)
+ {
+ cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
+ "%04X %s No attributes in request",
+ IPP_BAD_REQUEST, con->http.hostname);
+
+ send_ipp_status(con, IPP_BAD_REQUEST, _("No attributes in request."));
+ }
+ else
+ {
+ /*
+ * Make sure that the attributes are provided in the correct order and
+ * don't repeat groups...
+ */
+
+ for (attr = con->request->attrs, group = attr->group_tag;
+ attr;
+ attr = attr->next)
+ if (attr->group_tag < group && attr->group_tag != IPP_TAG_ZERO)
+ {
+ /*
+ * Out of order; return an error...
+ */
+
+ cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
+ "%04X %s Attribute groups are out of order",
+ IPP_BAD_REQUEST, con->http.hostname);
+
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Attribute groups are out of order (%x < %x)."),
+ attr->group_tag, group);
+ break;
+ }
+ else
+ group = attr->group_tag;
+
+ if (!attr)
+ {
+ /*
+ * Then make sure that the first three attributes are:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri/job-uri
+ */
+
+ attr = con->request->attrs;
+ if (attr && attr->name &&
+ !strcmp(attr->name, "attributes-charset") &&
+ (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_CHARSET)
+ charset = attr;
+ else
+ charset = NULL;
+
+ if (attr)
+ attr = attr->next;
+
+ if (attr && attr->name &&
+ !strcmp(attr->name, "attributes-natural-language") &&
+ (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_LANGUAGE)
+ language = attr;
+ else
+ language = NULL;
+
+ if ((attr = ippFindAttribute(con->request, "printer-uri",
+ IPP_TAG_URI)) != NULL)
+ uri = attr;
+ else if ((attr = ippFindAttribute(con->request, "job-uri",
+ IPP_TAG_URI)) != NULL)
+ uri = attr;
+ else if (con->request->request.op.operation_id == CUPS_GET_PPD)
+ uri = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME);
+ else
+ uri = NULL;
+
+ if (charset)
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL,
+ charset->values[0].string.text);
+ else
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, "utf-8");
+
+ if (language)
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL,
+ language->values[0].string.text);
+ else
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, DefaultLanguage);
+
+ if (charset &&
+ _cups_strcasecmp(charset->values[0].string.text, "us-ascii") &&
+ _cups_strcasecmp(charset->values[0].string.text, "utf-8"))
+ {
+ /*
+ * Bad character set...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unsupported character set \"%s\"",
+ charset->values[0].string.text);
+ cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
+ "%04X %s Unsupported attributes-charset value \"%s\"",
+ IPP_CHARSET, con->http.hostname,
+ charset->values[0].string.text);
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Unsupported character set \"%s\"."),
+ charset->values[0].string.text);
+ }
+ else if (!charset || !language ||
+ (!uri &&
+ con->request->request.op.operation_id != CUPS_GET_DEFAULT &&
+ con->request->request.op.operation_id != CUPS_GET_PRINTERS &&
+ con->request->request.op.operation_id != CUPS_GET_CLASSES &&
+ con->request->request.op.operation_id != CUPS_GET_DEVICES &&
+ con->request->request.op.operation_id != CUPS_GET_PPDS))
+ {
+ /*
+ * Return an error, since attributes-charset,
+ * attributes-natural-language, and printer-uri/job-uri are required
+ * for all operations.
+ */
+
+ if (!charset)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Missing attributes-charset attribute");
+
+ cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
+ "%04X %s Missing attributes-charset attribute",
+ IPP_BAD_REQUEST, con->http.hostname);
+ }
+
+ if (!language)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Missing attributes-natural-language attribute");
+
+ cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
+ "%04X %s Missing attributes-natural-language attribute",
+ IPP_BAD_REQUEST, con->http.hostname);
+ }
+
+ if (!uri)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Missing printer-uri, job-uri, or ppd-name "
+ "attribute");
+
+ cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
+ "%04X %s Missing printer-uri, job-uri, or ppd-name "
+ "attribute", IPP_BAD_REQUEST, con->http.hostname);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Request attributes follow...");
+
+ for (attr = con->request->attrs; attr; attr = attr->next)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "attr \"%s\": group_tag = %x, value_tag = %x",
+ attr->name ? attr->name : "(null)", attr->group_tag,
+ attr->value_tag);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "End of attributes...");
+
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Missing required attributes."));
+ }
+ else
+ {
+ /*
+ * OK, all the checks pass so far; make sure requesting-user-name is
+ * not "root" from a remote host...
+ */
+
+ if ((username = ippFindAttribute(con->request, "requesting-user-name",
+ IPP_TAG_NAME)) != NULL)
+ {
+ /*
+ * Check for root user...
+ */
+
+ if (!strcmp(username->values[0].string.text, "root") &&
+ _cups_strcasecmp(con->http.hostname, "localhost") &&
+ strcmp(con->username, "root"))
+ {
+ /*
+ * Remote unauthenticated user masquerading as local root...
+ */
+
+ _cupsStrFree(username->values[0].string.text);
+ username->values[0].string.text = _cupsStrAlloc(RemoteRoot);
+ }
+ }
+
+ if ((attr = ippFindAttribute(con->request, "notify-subscription-id",
+ IPP_TAG_INTEGER)) != NULL)
+ sub_id = attr->values[0].integer;
+ else
+ sub_id = 0;
+
+ /*
+ * Then try processing the operation...
+ */
+
+ if (uri)
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s",
+ ippOpString(con->request->request.op.operation_id),
+ uri->values[0].string.text);
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "%s",
+ ippOpString(con->request->request.op.operation_id));
+
+ switch (con->request->request.op.operation_id)
+ {
+ case IPP_PRINT_JOB :
+ print_job(con, uri);
+ break;
+
+ case IPP_VALIDATE_JOB :
+ validate_job(con, uri);
+ break;
+
+ case IPP_CREATE_JOB :
+ create_job(con, uri);
+ break;
+
+ case IPP_SEND_DOCUMENT :
+ send_document(con, uri);
+ break;
+
+ case IPP_CANCEL_JOB :
+ cancel_job(con, uri);
+ break;
+
+ case IPP_GET_JOB_ATTRIBUTES :
+ get_job_attrs(con, uri);
+ break;
+
+ case IPP_GET_JOBS :
+ get_jobs(con, uri);
+ break;
+
+ case IPP_GET_PRINTER_ATTRIBUTES :
+ get_printer_attrs(con, uri);
+ break;
+
+ case IPP_GET_PRINTER_SUPPORTED_VALUES :
+ get_printer_supported(con, uri);
+ break;
+
+ case IPP_HOLD_JOB :
+ hold_job(con, uri);
+ break;
+
+ case IPP_RELEASE_JOB :
+ release_job(con, uri);
+ break;
+
+ case IPP_RESTART_JOB :
+ restart_job(con, uri);
+ break;
+
+ case IPP_PAUSE_PRINTER :
+ stop_printer(con, uri);
+ break;
+
+ case IPP_RESUME_PRINTER :
+ start_printer(con, uri);
+ break;
+
+ case IPP_PURGE_JOBS :
+ case IPP_CANCEL_JOBS :
+ case IPP_CANCEL_MY_JOBS :
+ cancel_all_jobs(con, uri);
+ break;
+
+ case IPP_SET_JOB_ATTRIBUTES :
+ set_job_attrs(con, uri);
+ break;
+
+ case IPP_SET_PRINTER_ATTRIBUTES :
+ set_printer_attrs(con, uri);
+ break;
+
+ case IPP_HOLD_NEW_JOBS :
+ hold_new_jobs(con, uri);
+ break;
+
+ case IPP_RELEASE_HELD_NEW_JOBS :
+ release_held_new_jobs(con, uri);
+ break;
+
+ case IPP_CLOSE_JOB :
+ close_job(con, uri);
+ break;
+
+ case CUPS_GET_DEFAULT :
+ get_default(con);
+ break;
+
+ case CUPS_GET_PRINTERS :
+ get_printers(con, 0);
+ break;
+
+ case CUPS_GET_CLASSES :
+ get_printers(con, CUPS_PRINTER_CLASS);
+ break;
+
+ case CUPS_ADD_PRINTER :
+ add_printer(con, uri);
+ break;
+
+ case CUPS_DELETE_PRINTER :
+ delete_printer(con, uri);
+ break;
+
+ case CUPS_ADD_CLASS :
+ add_class(con, uri);
+ break;
+
+ case CUPS_DELETE_CLASS :
+ delete_printer(con, uri);
+ break;
+
+ case CUPS_ACCEPT_JOBS :
+ case IPP_ENABLE_PRINTER :
+ accept_jobs(con, uri);
+ break;
+
+ case CUPS_REJECT_JOBS :
+ case IPP_DISABLE_PRINTER :
+ reject_jobs(con, uri);
+ break;
+
+ case CUPS_SET_DEFAULT :
+ set_default(con, uri);
+ break;
+
+ case CUPS_GET_DEVICES :
+ get_devices(con);
+ break;
+
+ case CUPS_GET_DOCUMENT :
+ get_document(con, uri);
+ break;
+
+ case CUPS_GET_PPD :
+ get_ppd(con, uri);
+ break;
+
+ case CUPS_GET_PPDS :
+ get_ppds(con);
+ break;
+
+ case CUPS_MOVE_JOB :
+ move_job(con, uri);
+ break;
+
+ case CUPS_AUTHENTICATE_JOB :
+ authenticate_job(con, uri);
+ break;
+
+ case IPP_CREATE_PRINTER_SUBSCRIPTION :
+ case IPP_CREATE_JOB_SUBSCRIPTION :
+ create_subscription(con, uri);
+ break;
+
+ case IPP_GET_SUBSCRIPTION_ATTRIBUTES :
+ get_subscription_attrs(con, sub_id);
+ break;
+
+ case IPP_GET_SUBSCRIPTIONS :
+ get_subscriptions(con, uri);
+ break;
+
+ case IPP_RENEW_SUBSCRIPTION :
+ renew_subscription(con, sub_id);
+ break;
+
+ case IPP_CANCEL_SUBSCRIPTION :
+ cancel_subscription(con, sub_id);
+ break;
+
+ case IPP_GET_NOTIFICATIONS :
+ get_notifications(con);
+ break;
+
+ default :
+ cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
+ "%04X %s Operation %04X (%s) not supported",
+ IPP_OPERATION_NOT_SUPPORTED, con->http.hostname,
+ con->request->request.op.operation_id,
+ ippOpString(con->request->request.op.operation_id));
+
+ send_ipp_status(con, IPP_OPERATION_NOT_SUPPORTED,
+ _("%s not supported."),
+ ippOpString(
+ con->request->request.op.operation_id));
+ break;
+ }
+ }
+ }
+ }
+
+ if (con->response)
+ {
+ /*
+ * Sending data from the scheduler...
+ */
+
+ cupsdLogMessage(con->response->request.status.status_code
+ >= IPP_BAD_REQUEST &&
+ con->response->request.status.status_code
+ != IPP_NOT_FOUND ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG,
+ "Returning IPP %s for %s (%s) from %s",
+ ippErrorString(con->response->request.status.status_code),
+ ippOpString(con->request->request.op.operation_id),
+ uri ? uri->values[0].string.text : "no URI",
+ con->http.hostname);
+
+ if (LogLevel == CUPSD_LOG_DEBUG2)
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdProcessIPPRequest: ippLength(response)=%ld",
+ (long)ippLength(con->response));
+
+ if (cupsdSendHeader(con, HTTP_OK, "application/ipp", CUPSD_AUTH_NONE))
+ {
+#ifdef CUPSD_USE_CHUNKING
+ /*
+ * Because older versions of CUPS (1.1.17 and older) and some IPP
+ * clients do not implement chunking properly, we cannot use
+ * chunking by default. This may become the default in future
+ * CUPS releases, or we might add a configuration directive for
+ * it.
+ */
+
+ if (con->http.version == HTTP_1_1)
+ {
+ if (httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n\r\n") < 0)
+ return (0);
+
+ if (cupsdFlushHeader(con) < 0)
+ return (0);
+
+ con->http.data_encoding = HTTP_ENCODE_CHUNKED;
+ }
+ else
+#endif /* CUPSD_USE_CHUNKING */
+ {
+ size_t length; /* Length of response */
+
+
+ length = ippLength(con->response);
+
+ if (con->file >= 0 && !con->pipe_pid)
+ {
+ struct stat fileinfo; /* File information */
+
+
+ if (!fstat(con->file, &fileinfo))
+ length += fileinfo.st_size;
+ }
+
+ if (httpPrintf(HTTP(con), "Content-Length: " CUPS_LLFMT "\r\n\r\n",
+ CUPS_LLCAST length) < 0)
+ return (0);
+
+ if (cupsdFlushHeader(con) < 0)
+ return (0);
+
+ con->http.data_encoding = HTTP_ENCODE_LENGTH;
+ con->http.data_remaining = length;
+
+ if (con->http.data_remaining <= INT_MAX)
+ con->http._data_remaining = con->http.data_remaining;
+ else
+ con->http._data_remaining = INT_MAX;
+ }
+
+ cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient,
+ (cupsd_selfunc_t)cupsdWriteClient, con);
+
+ /*
+ * Tell the caller the response header was sent successfully...
+ */
+
+ return (1);
+ }
+ else
+ {
+ /*
+ * Tell the caller the response header could not be sent...
+ */
+
+ return (0);
+ }
+ }
+ else
+ {
+ /*
+ * Sending data from a subprocess like cups-deviced; tell the caller
+ * everything is A-OK so far...
+ */
+
+ return (1);
+ }
+}
+
+
+/*
+ * 'cupsdTimeoutJob()' - Timeout a job waiting on job files.
+ */
+
+int /* O - 0 on success, -1 on error */
+cupsdTimeoutJob(cupsd_job_t *job) /* I - Job to timeout */
+{
+ cupsd_printer_t *printer; /* Destination printer or class */
+ ipp_attribute_t *attr; /* job-sheets attribute */
+ int kbytes; /* Kilobytes in banner */
+
+
+ job->pending_timeout = 0;
+
+ /*
+ * See if we need to add the ending sheet...
+ */
+
+ if (!cupsdLoadJob(job))
+ return (-1);
+
+ printer = cupsdFindDest(job->dest);
+ attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
+
+ if (printer &&
+ !(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) &&
+ attr && attr->num_values > 1)
+ {
+ /*
+ * Yes...
+ */
+
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Adding end banner page \"%s\".",
+ attr->values[1].string.text);
+
+ if ((kbytes = copy_banner(NULL, job, attr->values[1].string.text)) < 0)
+ return (-1);
+
+ cupsdUpdateQuota(printer, job->username, 0, kbytes);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'accept_jobs()' - Accept print jobs to a printer.
+ */
+
+static void
+accept_jobs(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer or class URI */
+{
+ http_status_t status; /* Policy status */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cupsd_printer_t *printer; /* Printer data */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "accept_jobs(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+
+ /*
+ * Accept jobs sent to the printer...
+ */
+
+ printer->accepting = 1;
+ printer->state_message[0] = '\0';
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
+ "Now accepting jobs.");
+
+ if (dtype & CUPS_PRINTER_CLASS)
+ {
+ cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" now accepting jobs (\"%s\").",
+ printer->name, get_username(con));
+ }
+ else
+ {
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Printer \"%s\" now accepting jobs (\"%s\").",
+ printer->name, get_username(con));
+ }
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'add_class()' - Add a class to the system.
+ */
+
+static void
+add_class(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - URI of class */
+{
+ http_status_t status; /* Policy status */
+ int i; /* Looping var */
+ char scheme[HTTP_MAX_URI], /* Method portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ cupsd_printer_t *pclass, /* Class */
+ *member; /* Member printer/class */
+ cups_ptype_t dtype; /* Destination type */
+ ipp_attribute_t *attr; /* Printer attribute */
+ int modify; /* Non-zero if we just modified */
+ char newname[IPP_MAX_NAME]; /* New class name */
+ int need_restart_job; /* Need to restart job? */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_class(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Do we have a valid URI?
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+
+ if (strncmp(resource, "/classes/", 9) || strlen(resource) == 9)
+ {
+ /*
+ * No, return an error...
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("The printer-uri must be of the form "
+ "\"ipp://HOSTNAME/classes/CLASSNAME\"."));
+ return;
+ }
+
+ /*
+ * Do we have a valid printer name?
+ */
+
+ if (!validate_name(resource + 9))
+ {
+ /*
+ * No, return an error...
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("The printer-uri \"%s\" contains invalid characters."),
+ uri->values[0].string.text);
+ return;
+ }
+
+ /*
+ * See if the class already exists; if not, create a new class...
+ */
+
+ if ((pclass = cupsdFindClass(resource + 9)) == NULL)
+ {
+ /*
+ * Class doesn't exist; see if we have a printer of the same name...
+ */
+
+ if ((pclass = cupsdFindPrinter(resource + 9)) != NULL &&
+ !(pclass->type & CUPS_PRINTER_DISCOVERED))
+ {
+ /*
+ * Yes, return an error...
+ */
+
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("A printer named \"%s\" already exists."),
+ resource + 9);
+ return;
+ }
+
+ /*
+ * No, check the default policy and then add the class...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ pclass = cupsdAddClass(resource + 9);
+ modify = 0;
+ }
+ else if (pclass->type & CUPS_PRINTER_IMPLICIT)
+ {
+ /*
+ * Check the default policy, then rename the implicit class to "AnyClass"
+ * or remove it...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ if (ImplicitAnyClasses)
+ {
+ snprintf(newname, sizeof(newname), "Any%s", resource + 9);
+ cupsdRenamePrinter(pclass, newname);
+ }
+ else
+ cupsdDeletePrinter(pclass, 1);
+
+ /*
+ * Add the class as a new local class...
+ */
+
+ pclass = cupsdAddClass(resource + 9);
+ modify = 0;
+ }
+ else if (pclass->type & CUPS_PRINTER_DISCOVERED)
+ {
+ /*
+ * Check the default policy, then rename the remote class to "Class"...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ snprintf(newname, sizeof(newname), "%s@%s", resource + 9, pclass->hostname);
+ cupsdRenamePrinter(pclass, newname);
+
+ /*
+ * Add the class as a new local class...
+ */
+
+ pclass = cupsdAddClass(resource + 9);
+ modify = 0;
+ }
+ else if ((status = cupsdCheckPolicy(pclass->op_policy_ptr, con,
+ NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, pclass);
+ return;
+ }
+ else
+ modify = 1;
+
+ /*
+ * Look for attributes and copy them over as needed...
+ */
+
+ need_restart_job = 0;
+
+ if ((attr = ippFindAttribute(con->request, "printer-location",
+ IPP_TAG_TEXT)) != NULL)
+ cupsdSetString(&pclass->location, attr->values[0].string.text);
+
+ if ((attr = ippFindAttribute(con->request, "printer-info",
+ IPP_TAG_TEXT)) != NULL)
+ cupsdSetString(&pclass->info, attr->values[0].string.text);
+
+ if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs",
+ IPP_TAG_BOOLEAN)) != NULL &&
+ attr->values[0].boolean != pclass->accepting)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Setting %s printer-is-accepting-jobs to %d (was %d.)",
+ pclass->name, attr->values[0].boolean, pclass->accepting);
+
+ pclass->accepting = attr->values[0].boolean;
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, pclass, NULL, "%s accepting jobs.",
+ pclass->accepting ? "Now" : "No longer");
+ }
+
+ if ((attr = ippFindAttribute(con->request, "printer-is-shared",
+ IPP_TAG_BOOLEAN)) != NULL)
+ {
+ if (pclass->shared && !attr->values[0].boolean)
+ cupsdDeregisterPrinter(pclass, 1);
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Setting %s printer-is-shared to %d (was %d.)",
+ pclass->name, attr->values[0].boolean, pclass->shared);
+
+ pclass->shared = attr->values[0].boolean;
+ }
+
+ if ((attr = ippFindAttribute(con->request, "printer-state",
+ IPP_TAG_ENUM)) != NULL)
+ {
+ if (attr->values[0].integer != IPP_PRINTER_IDLE &&
+ attr->values[0].integer != IPP_PRINTER_STOPPED)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Attempt to set %s printer-state to bad value %d."),
+ pclass->name, attr->values[0].integer);
+ return;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-state to %d (was %d.)",
+ pclass->name, attr->values[0].integer, pclass->state);
+
+ if (attr->values[0].integer == IPP_PRINTER_STOPPED)
+ cupsdStopPrinter(pclass, 0);
+ else
+ {
+ cupsdSetPrinterState(pclass, (ipp_pstate_t)(attr->values[0].integer), 0);
+ need_restart_job = 1;
+ }
+ }
+ if ((attr = ippFindAttribute(con->request, "printer-state-message",
+ IPP_TAG_TEXT)) != NULL)
+ {
+ strlcpy(pclass->state_message, attr->values[0].string.text,
+ sizeof(pclass->state_message));
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, pclass, NULL, "%s",
+ pclass->state_message);
+ }
+ if ((attr = ippFindAttribute(con->request, "member-uris",
+ IPP_TAG_URI)) != NULL)
+ {
+ /*
+ * Clear the printer array as needed...
+ */
+
+ need_restart_job = 1;
+
+ if (pclass->num_printers > 0)
+ {
+ free(pclass->printers);
+ pclass->num_printers = 0;
+ }
+
+ /*
+ * Add each printer or class that is listed...
+ */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ /*
+ * Search for the printer or class URI...
+ */
+
+ if (!cupsdValidateDest(attr->values[i].string.text, &dtype, &member))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+ else if (dtype & CUPS_PRINTER_CLASS)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Nested classes are not allowed."));
+ return;
+ }
+
+ /*
+ * Add it to the class...
+ */
+
+ cupsdAddPrinterToClass(pclass, member);
+ }
+ }
+
+ set_printer_defaults(con, pclass);
+
+ if ((attr = ippFindAttribute(con->request, "auth-info-required",
+ IPP_TAG_KEYWORD)) != NULL)
+ cupsdSetAuthInfoRequired(pclass, NULL, attr);
+
+ /*
+ * Update the printer class attributes and return...
+ */
+
+ cupsdSetPrinterAttrs(pclass);
+ cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
+
+ if (need_restart_job && pclass->job)
+ {
+ /*
+ * Reset the current job to a "pending" status...
+ */
+
+ cupsdSetJobState(pclass->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE,
+ "Job restarted because the class was modified.");
+ }
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+
+ if (modify)
+ {
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED,
+ pclass, NULL, "Class \"%s\" modified by \"%s\".",
+ pclass->name, get_username(con));
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" modified by \"%s\".",
+ pclass->name, get_username(con));
+ }
+ else
+ {
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED,
+ pclass, NULL, "New class \"%s\" added by \"%s\".",
+ pclass->name, get_username(con));
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "New class \"%s\" added by \"%s\".",
+ pclass->name, get_username(con));
+ }
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'add_file()' - Add a file to a job.
+ */
+
+static int /* O - 0 on success, -1 on error */
+add_file(cupsd_client_t *con, /* I - Connection to client */
+ cupsd_job_t *job, /* I - Job to add to */
+ mime_type_t *filetype, /* I - Type of file */
+ int compression) /* I - Compression */
+{
+ mime_type_t **filetypes; /* New filetypes array... */
+ int *compressions; /* New compressions array... */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "add_file(con=%p[%d], job=%d, filetype=%s/%s, "
+ "compression=%d)", con, con ? con->http.fd : -1, job->id,
+ filetype->super, filetype->type, compression);
+
+ /*
+ * Add the file to the job...
+ */
+
+ if (job->num_files == 0)
+ {
+ compressions = (int *)malloc(sizeof(int));
+ filetypes = (mime_type_t **)malloc(sizeof(mime_type_t *));
+ }
+ else
+ {
+ compressions = (int *)realloc(job->compressions,
+ (job->num_files + 1) * sizeof(int));
+ filetypes = (mime_type_t **)realloc(job->filetypes,
+ (job->num_files + 1) *
+ sizeof(mime_type_t *));
+ }
+
+ if (!compressions || !filetypes)
+ {
+ cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_PURGE,
+ "Job aborted because the scheduler ran out of memory.");
+
+ if (con)
+ send_ipp_status(con, IPP_INTERNAL_ERROR,
+ _("Unable to allocate memory for file types."));
+
+ return (-1);
+ }
+
+ job->compressions = compressions;
+ job->compressions[job->num_files] = compression;
+ job->filetypes = filetypes;
+ job->filetypes[job->num_files] = filetype;
+
+ job->num_files ++;
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+
+ return (0);
+}
+
+
+/*
+ * 'add_job()' - Add a job to a print queue.
+ */
+
+static cupsd_job_t * /* O - Job object */
+add_job(cupsd_client_t *con, /* I - Client connection */
+ cupsd_printer_t *printer, /* I - Destination printer */
+ mime_type_t *filetype) /* I - First print file type, if any */
+{
+ http_status_t status; /* Policy status */
+ ipp_attribute_t *attr, /* Current attribute */
+ *auth_info; /* auth-info attribute */
+ const char *val; /* Default option value */
+ int priority; /* Job priority */
+ cupsd_job_t *job; /* Current job */
+ char job_uri[HTTP_MAX_URI]; /* Job URI */
+ int kbytes; /* Size of print file */
+ int i; /* Looping var */
+ int lowerpagerange; /* Page range bound */
+ int exact; /* Did we have an exact match? */
+ ipp_attribute_t *media_col, /* media-col attribute */
+ *media_margin; /* media-*-margin attribute */
+ ipp_t *unsup_col; /* media-col in unsupported response */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %p(%s), %p(%s/%s))",
+ con, con->http.fd, printer, printer->name,
+ filetype, filetype ? filetype->super : "none",
+ filetype ? filetype->type : "none");
+
+ /*
+ * Check remote printing to non-shared printer...
+ */
+
+ if (!printer->shared &&
+ _cups_strcasecmp(con->http.hostname, "localhost") &&
+ _cups_strcasecmp(con->http.hostname, ServerName))
+ {
+ send_ipp_status(con, IPP_NOT_AUTHORIZED,
+ _("The printer or class is not shared."));
+ return (NULL);
+ }
+
+ /*
+ * Check policy...
+ */
+
+ auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT);
+
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return (NULL);
+ }
+ else if (printer->num_auth_info_required == 1 &&
+ !strcmp(printer->auth_info_required[0], "negotiate") &&
+ !con->username[0])
+ {
+ send_http_error(con, HTTP_UNAUTHORIZED, printer);
+ return (NULL);
+ }
+#ifdef HAVE_SSL
+ else if (auth_info && !con->http.tls &&
+ !httpAddrLocalhost(con->http.hostaddr))
+ {
+ /*
+ * Require encryption of auth-info over non-local connections...
+ */
+
+ send_http_error(con, HTTP_UPGRADE_REQUIRED, printer);
+ return (NULL);
+ }
+#endif /* HAVE_SSL */
+
+ /*
+ * See if the printer is accepting jobs...
+ */
+
+ if (!printer->accepting)
+ {
+ send_ipp_status(con, IPP_NOT_ACCEPTING,
+ _("Destination \"%s\" is not accepting jobs."),
+ printer->name);
+ return (NULL);
+ }
+
+ /*
+ * Validate job template attributes; for now just document-format,
+ * copies, number-up, and page-ranges...
+ */
+
+ if (filetype && printer->filetypes &&
+ !cupsArrayFind(printer->filetypes, filetype))
+ {
+ char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
+ /* MIME media type string */
+
+
+ snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
+ filetype->type);
+
+ send_ipp_status(con, IPP_DOCUMENT_FORMAT,
+ _("Unsupported format \"%s\"."), mimetype);
+
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
+ "document-format", NULL, mimetype);
+
+ return (NULL);
+ }
+
+ if ((attr = ippFindAttribute(con->request, "copies",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if (attr->values[0].integer < 1 || attr->values[0].integer > MaxCopies)
+ {
+ send_ipp_status(con, IPP_ATTRIBUTES, _("Bad copies value %d."),
+ attr->values[0].integer);
+ ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER,
+ "copies", attr->values[0].integer);
+ return (NULL);
+ }
+ }
+
+ if ((attr = ippFindAttribute(con->request, "job-sheets",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attr->value_tag != IPP_TAG_KEYWORD &&
+ attr->value_tag != IPP_TAG_NAME)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-sheets value type."));
+ return (NULL);
+ }
+
+ if (attr->num_values > 2)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Too many job-sheets values (%d > 2)."),
+ attr->num_values);
+ return (NULL);
+ }
+
+ for (i = 0; i < attr->num_values; i ++)
+ if (strcmp(attr->values[i].string.text, "none") &&
+ !cupsdFindBanner(attr->values[i].string.text))
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-sheets value \"%s\"."),
+ attr->values[i].string.text);
+ return (NULL);
+ }
+ }
+
+ if ((attr = ippFindAttribute(con->request, "number-up",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if (attr->values[0].integer != 1 &&
+ attr->values[0].integer != 2 &&
+ attr->values[0].integer != 4 &&
+ attr->values[0].integer != 6 &&
+ attr->values[0].integer != 9 &&
+ attr->values[0].integer != 16)
+ {
+ send_ipp_status(con, IPP_ATTRIBUTES, _("Bad number-up value %d."),
+ attr->values[0].integer);
+ ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER,
+ "number-up", attr->values[0].integer);
+ return (NULL);
+ }
+ }
+
+ if ((attr = ippFindAttribute(con->request, "page-ranges",
+ IPP_TAG_RANGE)) != NULL)
+ {
+ for (i = 0, lowerpagerange = 1; i < attr->num_values; i ++)
+ {
+ if (attr->values[i].range.lower < lowerpagerange ||
+ attr->values[i].range.lower > attr->values[i].range.upper)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Bad page-ranges values %d-%d."),
+ attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ return (NULL);
+ }
+
+ lowerpagerange = attr->values[i].range.upper + 1;
+ }
+ }
+
+ /*
+ * Do media selection as needed...
+ */
+
+ if (!ippFindAttribute(con->request, "PageRegion", IPP_TAG_ZERO) &&
+ !ippFindAttribute(con->request, "PageSize", IPP_TAG_ZERO) &&
+ _ppdCacheGetPageSize(printer->pc, con->request, NULL, &exact))
+ {
+ if (!exact &&
+ (media_col = ippFindAttribute(con->request, "media-col",
+ IPP_TAG_BEGIN_COLLECTION)) != NULL)
+ {
+ send_ipp_status(con, IPP_OK_SUBST, _("Unsupported margins."));
+
+ unsup_col = ippNew();
+ if ((media_margin = ippFindAttribute(media_col->values[0].collection,
+ "media-bottom-margin",
+ IPP_TAG_INTEGER)) != NULL)
+ ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "media-bottom-margin", media_margin->values[0].integer);
+
+ if ((media_margin = ippFindAttribute(media_col->values[0].collection,
+ "media-left-margin",
+ IPP_TAG_INTEGER)) != NULL)
+ ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "media-left-margin", media_margin->values[0].integer);
+
+ if ((media_margin = ippFindAttribute(media_col->values[0].collection,
+ "media-right-margin",
+ IPP_TAG_INTEGER)) != NULL)
+ ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "media-right-margin", media_margin->values[0].integer);
+
+ if ((media_margin = ippFindAttribute(media_col->values[0].collection,
+ "media-top-margin",
+ IPP_TAG_INTEGER)) != NULL)
+ ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
+ "media-top-margin", media_margin->values[0].integer);
+
+ ippAddCollection(con->response, IPP_TAG_UNSUPPORTED_GROUP, "media-col",
+ unsup_col);
+ ippDelete(unsup_col);
+ }
+ }
+
+ /*
+ * Make sure we aren't over our limit...
+ */
+
+ if (MaxJobs && cupsArrayCount(Jobs) >= MaxJobs)
+ cupsdCleanJobs();
+
+ if (MaxJobs && cupsArrayCount(Jobs) >= MaxJobs)
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE, _("Too many active jobs."));
+ return (NULL);
+ }
+
+ if ((i = check_quotas(con, printer)) < 0)
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE, _("Quota limit reached."));
+ return (NULL);
+ }
+ else if (i == 0)
+ {
+ send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Not allowed to print."));
+ return (NULL);
+ }
+
+ /*
+ * Create the job and set things up...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-priority",
+ IPP_TAG_INTEGER)) != NULL)
+ priority = attr->values[0].integer;
+ else
+ {
+ if ((val = cupsGetOption("job-priority", printer->num_options,
+ printer->options)) != NULL)
+ priority = atoi(val);
+ else
+ priority = 50;
+
+ ippAddInteger(con->request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority",
+ priority);
+ }
+
+ if (!ippFindAttribute(con->request, "job-name", IPP_TAG_NAME))
+ ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL,
+ "Untitled");
+
+ if ((job = cupsdAddJob(priority, printer->name)) == NULL)
+ {
+ send_ipp_status(con, IPP_INTERNAL_ERROR,
+ _("Unable to add job for destination \"%s\"."),
+ printer->name);
+ return (NULL);
+ }
+
+ job->dtype = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_REMOTE);
+ job->attrs = con->request;
+ job->dirty = 1;
+ con->request = ippNewRequest(job->attrs->request.op.operation_id);
+
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+
+ add_job_uuid(job);
+ apply_printer_defaults(printer, job);
+
+ attr = ippFindAttribute(job->attrs, "requesting-user-name", IPP_TAG_NAME);
+
+ if (con->username[0])
+ {
+ cupsdSetString(&job->username, con->username);
+
+ if (attr)
+ cupsdSetString(&attr->values[0].string.text, con->username);
+ }
+ else if (attr)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "add_job: requesting-user-name=\"%s\"",
+ attr->values[0].string.text);
+
+ cupsdSetString(&job->username, attr->values[0].string.text);
+ }
+ else
+ cupsdSetString(&job->username, "anonymous");
+
+ if (!attr)
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,
+ "job-originating-user-name", NULL, job->username);
+ else
+ {
+ attr->group_tag = IPP_TAG_JOB;
+ _cupsStrFree(attr->name);
+ attr->name = _cupsStrAlloc("job-originating-user-name");
+ }
+
+ if (con->username[0] || auth_info)
+ {
+ save_auth_info(con, job, auth_info);
+
+ /*
+ * Remove the auth-info attribute from the attribute data...
+ */
+
+ if (auth_info)
+ ippDeleteAttribute(job->attrs, auth_info);
+ }
+
+ if ((attr = ippFindAttribute(job->attrs, "job-originating-host-name",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ /*
+ * Request contains a job-originating-host-name attribute; validate it...
+ */
+
+ if (attr->value_tag != IPP_TAG_NAME ||
+ attr->num_values != 1 ||
+ strcmp(con->http.hostname, "localhost"))
+ {
+ /*
+ * Can't override the value if we aren't connected via localhost.
+ * Also, we can only have 1 value and it must be a name value.
+ */
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_STRING :
+ 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_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ /*
+ * Free old strings...
+ */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ _cupsStrFree(attr->values[i].string.text);
+ attr->values[i].string.text = NULL;
+ if (attr->values[i].string.charset)
+ {
+ _cupsStrFree(attr->values[i].string.charset);
+ attr->values[i].string.charset = NULL;
+ }
+ }
+
+ default :
+ break;
+ }
+
+ /*
+ * Use the default connection hostname instead...
+ */
+
+ attr->value_tag = IPP_TAG_NAME;
+ attr->num_values = 1;
+ attr->values[0].string.text = _cupsStrAlloc(con->http.hostname);
+ }
+
+ attr->group_tag = IPP_TAG_JOB;
+ }
+ else
+ {
+ /*
+ * No job-originating-host-name attribute, so use the hostname from
+ * the connection...
+ */
+
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME,
+ "job-originating-host-name", NULL, con->http.hostname);
+ }
+
+ ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation",
+ time(NULL));
+ attr = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "time-at-processing", 0);
+ attr->value_tag = IPP_TAG_NOVALUE;
+ attr = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "time-at-completed", 0);
+ attr->value_tag = IPP_TAG_NOVALUE;
+
+ /*
+ * Add remaining job attributes...
+ */
+
+ ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
+ job->state = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_ENUM,
+ "job-state", IPP_JOB_STOPPED);
+ job->state_value = (ipp_jstate_t)job->state->values[0].integer;
+ job->sheets = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "job-media-sheets-completed", 0);
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL,
+ printer->uri);
+
+ if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
+ IPP_TAG_INTEGER)) != NULL)
+ attr->values[0].integer = 0;
+ else
+ ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-k-octets", 0);
+
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
+ IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+ if (!attr)
+ {
+ if ((val = cupsGetOption("job-hold-until", printer->num_options,
+ printer->options)) == NULL)
+ val = "no-hold";
+
+ attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-hold-until", NULL, val);
+ }
+ if (attr && strcmp(attr->values[0].string.text, "no-hold"))
+ {
+ /*
+ * Hold job until specified time...
+ */
+
+ cupsdSetJobHoldUntil(job, attr->values[0].string.text, 0);
+
+ job->state->values[0].integer = IPP_JOB_HELD;
+ job->state_value = IPP_JOB_HELD;
+ }
+ else if (job->attrs->request.op.operation_id == IPP_CREATE_JOB)
+ {
+ job->hold_until = time(NULL) + MultipleOperationTimeout;
+ job->state->values[0].integer = IPP_JOB_HELD;
+ job->state_value = IPP_JOB_HELD;
+ }
+ else
+ {
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ job->state_value = IPP_JOB_PENDING;
+ }
+
+ if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) ||
+ Classification)
+ {
+ /*
+ * Add job sheets options...
+ */
+
+ if ((attr = ippFindAttribute(job->attrs, "job-sheets",
+ IPP_TAG_ZERO)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Adding default job-sheets values \"%s,%s\"...",
+ printer->job_sheets[0], printer->job_sheets[1]);
+
+ attr = ippAddStrings(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-sheets",
+ 2, NULL, NULL);
+ attr->values[0].string.text = _cupsStrRetain(printer->job_sheets[0]);
+ attr->values[1].string.text = _cupsStrRetain(printer->job_sheets[1]);
+ }
+
+ job->job_sheets = attr;
+
+ /*
+ * Enforce classification level if set...
+ */
+
+ if (Classification)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Classification=\"%s\", ClassifyOverride=%d",
+ Classification ? Classification : "(null)",
+ ClassifyOverride);
+
+ if (ClassifyOverride)
+ {
+ if (!strcmp(attr->values[0].string.text, "none") &&
+ (attr->num_values == 1 ||
+ !strcmp(attr->values[1].string.text, "none")))
+ {
+ /*
+ * Force the leading banner to have the classification on it...
+ */
+
+ cupsdSetString(&attr->values[0].string.text, Classification);
+
+ cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
+ "job-sheets=\"%s,none\", "
+ "job-originating-user-name=\"%s\"",
+ Classification, job->username);
+ }
+ else if (attr->num_values == 2 &&
+ strcmp(attr->values[0].string.text,
+ attr->values[1].string.text) &&
+ strcmp(attr->values[0].string.text, "none") &&
+ strcmp(attr->values[1].string.text, "none"))
+ {
+ /*
+ * Can't put two different security markings on the same document!
+ */
+
+ cupsdSetString(&attr->values[1].string.text, attr->values[0].string.text);
+
+ cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED "
+ "job-sheets=\"%s,%s\", "
+ "job-originating-user-name=\"%s\"",
+ attr->values[0].string.text,
+ attr->values[1].string.text, job->username);
+ }
+ else if (strcmp(attr->values[0].string.text, Classification) &&
+ strcmp(attr->values[0].string.text, "none") &&
+ (attr->num_values == 1 ||
+ (strcmp(attr->values[1].string.text, Classification) &&
+ strcmp(attr->values[1].string.text, "none"))))
+ {
+ if (attr->num_values == 1)
+ cupsdLogJob(job, CUPSD_LOG_NOTICE,
+ "CLASSIFICATION OVERRIDDEN "
+ "job-sheets=\"%s\", "
+ "job-originating-user-name=\"%s\"",
+ attr->values[0].string.text, job->username);
+ else
+ cupsdLogJob(job, CUPSD_LOG_NOTICE,
+ "CLASSIFICATION OVERRIDDEN "
+ "job-sheets=\"%s,%s\",fffff "
+ "job-originating-user-name=\"%s\"",
+ attr->values[0].string.text,
+ attr->values[1].string.text, job->username);
+ }
+ }
+ else if (strcmp(attr->values[0].string.text, Classification) &&
+ (attr->num_values == 1 ||
+ strcmp(attr->values[1].string.text, Classification)))
+ {
+ /*
+ * Force the banner to have the classification on it...
+ */
+
+ if (attr->num_values > 1 &&
+ !strcmp(attr->values[0].string.text, attr->values[1].string.text))
+ {
+ cupsdSetString(&(attr->values[0].string.text), Classification);
+ cupsdSetString(&(attr->values[1].string.text), Classification);
+ }
+ else
+ {
+ if (attr->num_values == 1 ||
+ strcmp(attr->values[0].string.text, "none"))
+ cupsdSetString(&(attr->values[0].string.text), Classification);
+
+ if (attr->num_values > 1 &&
+ strcmp(attr->values[1].string.text, "none"))
+ cupsdSetString(&(attr->values[1].string.text), Classification);
+ }
+
+ if (attr->num_values > 1)
+ cupsdLogJob(job, CUPSD_LOG_NOTICE,
+ "CLASSIFICATION FORCED "
+ "job-sheets=\"%s,%s\", "
+ "job-originating-user-name=\"%s\"",
+ attr->values[0].string.text,
+ attr->values[1].string.text, job->username);
+ else
+ cupsdLogJob(job, CUPSD_LOG_NOTICE,
+ "CLASSIFICATION FORCED "
+ "job-sheets=\"%s\", "
+ "job-originating-user-name=\"%s\"",
+ Classification, job->username);
+ }
+ }
+
+ /*
+ * See if we need to add the starting sheet...
+ */
+
+ if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
+ {
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Adding start banner page \"%s\".",
+ attr->values[0].string.text);
+
+ if ((kbytes = copy_banner(con, job, attr->values[0].string.text)) < 0)
+ {
+ cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_PURGE,
+ "Aborting job because the start banner could not be "
+ "copied.");
+ return (NULL);
+ }
+
+ cupsdUpdateQuota(printer, job->username, 0, kbytes);
+ }
+ }
+ else if ((attr = ippFindAttribute(job->attrs, "job-sheets",
+ IPP_TAG_ZERO)) != NULL)
+ job->job_sheets = attr;
+
+ /*
+ * Fill in the response info...
+ */
+
+ snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName,
+ LocalPort, job->id);
+
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL,
+ job_uri);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state",
+ job->state_value);
+ add_job_state_reasons(con, job);
+
+ con->response->request.status.status_code = IPP_OK;
+
+ /*
+ * Add any job subscriptions...
+ */
+
+ add_job_subscriptions(con, job);
+
+ /*
+ * Set all but the first two attributes to the job attributes group...
+ */
+
+ for (attr = job->attrs->attrs->next->next; attr; attr = attr->next)
+ attr->group_tag = IPP_TAG_JOB;
+
+ /*
+ * Fire the "job created" event...
+ */
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_CREATED, printer, job, "Job created.");
+
+ /*
+ * Return the new job...
+ */
+
+ return (job);
+}
+
+
+/*
+ * 'add_job_state_reasons()' - Add the "job-state-reasons" attribute based
+ * upon the job and printer state...
+ */
+
+static void
+add_job_state_reasons(
+ cupsd_client_t *con, /* I - Client connection */
+ cupsd_job_t *job) /* I - Job info */
+{
+ cupsd_printer_t *dest; /* Destination printer */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job_state_reasons(%p[%d], %d)",
+ con, con->http.fd, job ? job->id : 0);
+
+ switch (job ? job->state_value : IPP_JOB_CANCELED)
+ {
+ case IPP_JOB_PENDING :
+ dest = cupsdFindDest(job->dest);
+
+ if (dest && dest->state == IPP_PRINTER_STOPPED)
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "printer-stopped");
+ else
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "none");
+ break;
+
+ case IPP_JOB_HELD :
+ if (ippFindAttribute(job->attrs, "job-hold-until",
+ IPP_TAG_KEYWORD) != NULL ||
+ ippFindAttribute(job->attrs, "job-hold-until",
+ IPP_TAG_NAME) != NULL)
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "job-hold-until-specified");
+ else
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "job-incoming");
+ break;
+
+ case IPP_JOB_PROCESSING :
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "job-printing");
+ break;
+
+ case IPP_JOB_STOPPED :
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "job-stopped");
+ break;
+
+ case IPP_JOB_CANCELED :
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "job-canceled-by-user");
+ break;
+
+ case IPP_JOB_ABORTED :
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "aborted-by-system");
+ break;
+
+ case IPP_JOB_COMPLETED :
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-state-reasons", NULL, "job-completed-successfully");
+ break;
+ }
+}
+
+
+/*
+ * 'add_job_subscriptions()' - Add any subscriptions for a job.
+ */
+
+static void
+add_job_subscriptions(
+ cupsd_client_t *con, /* I - Client connection */
+ cupsd_job_t *job) /* I - Newly created job */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *prev, /* Previous attribute */
+ *next, /* Next attribute */
+ *attr; /* Current attribute */
+ cupsd_subscription_t *sub; /* Subscription object */
+ const char *recipient, /* notify-recipient-uri */
+ *pullmethod; /* notify-pull-method */
+ ipp_attribute_t *user_data; /* notify-user-data */
+ int interval; /* notify-time-interval */
+ unsigned mask; /* notify-events */
+
+
+ /*
+ * Find the first subscription group attribute; return if we have
+ * none...
+ */
+
+ for (attr = job->attrs->attrs; attr; attr = attr->next)
+ if (attr->group_tag == IPP_TAG_SUBSCRIPTION)
+ break;
+
+ if (!attr)
+ return;
+
+ /*
+ * Process the subscription attributes in the request...
+ */
+
+ while (attr)
+ {
+ recipient = NULL;
+ pullmethod = NULL;
+ user_data = NULL;
+ interval = 0;
+ mask = CUPSD_EVENT_NONE;
+
+ while (attr && attr->group_tag != IPP_TAG_ZERO)
+ {
+ if (!strcmp(attr->name, "notify-recipient-uri") &&
+ attr->value_tag == IPP_TAG_URI)
+ {
+ /*
+ * Validate the recipient scheme against the ServerBin/notifier
+ * directory...
+ */
+
+ char notifier[1024], /* Notifier filename */
+ scheme[HTTP_MAX_URI], /* Scheme portion of URI */
+ userpass[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+
+
+ recipient = attr->values[0].string.text;
+
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, recipient,
+ scheme, sizeof(scheme), userpass, sizeof(userpass),
+ host, sizeof(host), &port,
+ resource, sizeof(resource)) < HTTP_URI_OK)
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Bad notify-recipient-uri \"%s\"."), recipient);
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
+ "notify-status-code", IPP_URI_SCHEME);
+ return;
+ }
+
+ snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin,
+ scheme);
+ if (access(notifier, X_OK))
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("notify-recipient-uri URI \"%s\" uses unknown "
+ "scheme."), recipient);
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
+ "notify-status-code", IPP_URI_SCHEME);
+ return;
+ }
+
+ if (!strcmp(scheme, "rss") && !check_rss_recipient(recipient))
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("notify-recipient-uri URI \"%s\" is already used."),
+ recipient);
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
+ "notify-status-code", IPP_ATTRIBUTES);
+ return;
+ }
+ }
+ else if (!strcmp(attr->name, "notify-pull-method") &&
+ attr->value_tag == IPP_TAG_KEYWORD)
+ {
+ pullmethod = attr->values[0].string.text;
+
+ if (strcmp(pullmethod, "ippget"))
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Bad notify-pull-method \"%s\"."), pullmethod);
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
+ "notify-status-code", IPP_ATTRIBUTES);
+ return;
+ }
+ }
+ else if (!strcmp(attr->name, "notify-charset") &&
+ attr->value_tag == IPP_TAG_CHARSET &&
+ strcmp(attr->values[0].string.text, "us-ascii") &&
+ strcmp(attr->values[0].string.text, "utf-8"))
+ {
+ send_ipp_status(con, IPP_CHARSET,
+ _("Character set \"%s\" not supported."),
+ attr->values[0].string.text);
+ return;
+ }
+ else if (!strcmp(attr->name, "notify-natural-language") &&
+ (attr->value_tag != IPP_TAG_LANGUAGE ||
+ strcmp(attr->values[0].string.text, DefaultLanguage)))
+ {
+ send_ipp_status(con, IPP_CHARSET,
+ _("Language \"%s\" not supported."),
+ attr->values[0].string.text);
+ return;
+ }
+ else if (!strcmp(attr->name, "notify-user-data") &&
+ attr->value_tag == IPP_TAG_STRING)
+ {
+ if (attr->num_values > 1 || attr->values[0].unknown.length > 63)
+ {
+ send_ipp_status(con, IPP_REQUEST_VALUE,
+ _("The notify-user-data value is too large "
+ "(%d > 63 octets)."),
+ attr->values[0].unknown.length);
+ return;
+ }
+
+ user_data = attr;
+ }
+ else if (!strcmp(attr->name, "notify-events") &&
+ attr->value_tag == IPP_TAG_KEYWORD)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ mask |= cupsdEventValue(attr->values[i].string.text);
+ }
+ else if (!strcmp(attr->name, "notify-lease-duration"))
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("The notify-lease-duration attribute cannot be "
+ "used with job subscriptions."));
+ return;
+ }
+ else if (!strcmp(attr->name, "notify-time-interval") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ interval = attr->values[0].integer;
+
+ attr = attr->next;
+ }
+
+ if (!recipient && !pullmethod)
+ break;
+
+ if (mask == CUPSD_EVENT_NONE)
+ mask = CUPSD_EVENT_JOB_COMPLETED;
+
+ if ((sub = cupsdAddSubscription(mask, cupsdFindDest(job->dest), job,
+ recipient, 0)) != NULL)
+ {
+ sub->interval = interval;
+
+ cupsdSetString(&sub->owner, job->username);
+
+ if (user_data)
+ {
+ sub->user_data_len = user_data->values[0].unknown.length;
+ memcpy(sub->user_data, user_data->values[0].unknown.data,
+ sub->user_data_len);
+ }
+
+ ippAddSeparator(con->response);
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+ "notify-subscription-id", sub->id);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription %d for job %d",
+ sub->id, job->id);
+ }
+
+ if (attr)
+ attr = attr->next;
+ }
+
+ cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
+
+ /*
+ * Remove all of the subscription attributes from the job request...
+ *
+ * TODO: Optimize this since subscription groups have to come at the
+ * end of the request...
+ */
+
+ for (attr = job->attrs->attrs, prev = NULL; attr; attr = next)
+ {
+ next = attr->next;
+
+ if (attr->group_tag == IPP_TAG_SUBSCRIPTION ||
+ attr->group_tag == IPP_TAG_ZERO)
+ {
+ /*
+ * Free and remove this attribute...
+ */
+
+ _ippFreeAttr(attr);
+
+ if (prev)
+ prev->next = next;
+ else
+ job->attrs->attrs = next;
+ }
+ else
+ prev = attr;
+ }
+
+ job->attrs->last = prev;
+ job->attrs->current = prev;
+}
+
+
+/*
+ * 'add_job_uuid()' - Add job-uuid attribute to a job.
+ *
+ * See RFC 4122 for the definition of UUIDs and the format.
+ */
+
+static void
+add_job_uuid(cupsd_job_t *job) /* I - Job */
+{
+ char uuid[64]; /* job-uuid string */
+
+
+ /*
+ * Add a job-uuid attribute if none exists...
+ */
+
+ if (!ippFindAttribute(job->attrs, "job-uuid", IPP_TAG_URI))
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uuid", NULL,
+ _httpAssembleUUID(ServerName, RemotePort, job->dest, job->id,
+ uuid, sizeof(uuid)));
+}
+
+
+/*
+ * 'add_printer()' - Add a printer to the system.
+ */
+
+static void
+add_printer(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - URI of printer */
+{
+ http_status_t status; /* Policy status */
+ int i; /* Looping var */
+ char scheme[HTTP_MAX_URI], /* Method portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ cupsd_printer_t *printer; /* Printer/class */
+ ipp_attribute_t *attr; /* Printer attribute */
+ cups_file_t *fp; /* Script/PPD file */
+ char line[1024]; /* Line from file... */
+ char srcfile[1024], /* Source Script/PPD file */
+ dstfile[1024]; /* Destination Script/PPD file */
+ int modify; /* Non-zero if we are modifying */
+ char newname[IPP_MAX_NAME]; /* New printer name */
+ int changed_driver, /* Changed the PPD/interface script? */
+ need_restart_job, /* Need to restart job? */
+ set_device_uri, /* Did we set the device URI? */
+ set_port_monitor; /* Did we set the port monitor? */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Do we have a valid URI?
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (strncmp(resource, "/printers/", 10) || strlen(resource) == 10)
+ {
+ /*
+ * No, return an error...
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("The printer-uri must be of the form "
+ "\"ipp://HOSTNAME/printers/PRINTERNAME\"."));
+ return;
+ }
+
+ /*
+ * Do we have a valid printer name?
+ */
+
+ if (!validate_name(resource + 10))
+ {
+ /*
+ * No, return an error...
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("The printer-uri \"%s\" contains invalid characters."),
+ uri->values[0].string.text);
+ return;
+ }
+
+ /*
+ * See if the printer already exists; if not, create a new printer...
+ */
+
+ if ((printer = cupsdFindPrinter(resource + 10)) == NULL)
+ {
+ /*
+ * Printer doesn't exist; see if we have a class of the same name...
+ */
+
+ if ((printer = cupsdFindClass(resource + 10)) != NULL &&
+ !(printer->type & CUPS_PRINTER_DISCOVERED))
+ {
+ /*
+ * Yes, return an error...
+ */
+
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("A class named \"%s\" already exists."),
+ resource + 10);
+ return;
+ }
+
+ /*
+ * No, check the default policy then add the printer...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ printer = cupsdAddPrinter(resource + 10);
+ modify = 0;
+ }
+ else if (printer->type & CUPS_PRINTER_IMPLICIT)
+ {
+ /*
+ * Check the default policy, then rename the implicit printer to
+ * "AnyPrinter" or delete it...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ if (ImplicitAnyClasses)
+ {
+ snprintf(newname, sizeof(newname), "Any%s", resource + 10);
+ cupsdRenamePrinter(printer, newname);
+ }
+ else
+ cupsdDeletePrinter(printer, 1);
+
+ /*
+ * Add the printer as a new local printer...
+ */
+
+ printer = cupsdAddPrinter(resource + 10);
+ modify = 0;
+ }
+ else if (printer->type & CUPS_PRINTER_DISCOVERED)
+ {
+ /*
+ * Check the default policy, then rename the remote printer to
+ * "Printer@server"...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ snprintf(newname, sizeof(newname), "%s@%s", resource + 10,
+ printer->hostname);
+ cupsdRenamePrinter(printer, newname);
+
+ /*
+ * Add the printer as a new local printer...
+ */
+
+ printer = cupsdAddPrinter(resource + 10);
+ modify = 0;
+ }
+ else if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
+ NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+ else
+ modify = 1;
+
+ /*
+ * Look for attributes and copy them over as needed...
+ */
+
+ changed_driver = 0;
+ need_restart_job = 0;
+
+ if ((attr = ippFindAttribute(con->request, "printer-location",
+ IPP_TAG_TEXT)) != NULL)
+ cupsdSetString(&printer->location, attr->values[0].string.text);
+
+ if ((attr = ippFindAttribute(con->request, "printer-info",
+ IPP_TAG_TEXT)) != NULL)
+ cupsdSetString(&printer->info, attr->values[0].string.text);
+
+ set_device_uri = 0;
+
+ if ((attr = ippFindAttribute(con->request, "device-uri",
+ IPP_TAG_URI)) != NULL)
+ {
+ /*
+ * Do we have a valid device URI?
+ */
+
+ http_uri_status_t uri_status; /* URI separation status */
+ char old_device_uri[1024];
+ /* Old device URI */
+
+
+ need_restart_job = 1;
+
+ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL,
+ attr->values[0].string.text,
+ scheme, sizeof(scheme),
+ username, sizeof(username),
+ host, sizeof(host), &port,
+ resource, sizeof(resource));
+
+ if (uri_status < HTTP_URI_OK)
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad device-uri \"%s\"."),
+ attr->values[0].string.text);
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "add_printer: httpSeparateURI returned %d", uri_status);
+ return;
+ }
+
+ if (!strcmp(scheme, "file"))
+ {
+ /*
+ * See if the administrator has enabled file devices...
+ */
+
+ if (!FileDevice && strcmp(resource, "/dev/null"))
+ {
+ /*
+ * File devices are disabled and the URL is not file:/dev/null...
+ */
+
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("File device URIs have been disabled. "
+ "To enable, see the FileDevice directive in "
+ "\"%s/cupsd.conf\"."),
+ ServerRoot);
+ return;
+ }
+ }
+ else
+ {
+ /*
+ * See if the backend exists and is executable...
+ */
+
+ snprintf(srcfile, sizeof(srcfile), "%s/backend/%s", ServerBin, scheme);
+ if (access(srcfile, X_OK))
+ {
+ /*
+ * Could not find device in list!
+ */
+
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Bad device-uri scheme \"%s\"."), scheme);
+ return;
+ }
+ }
+
+ if (printer->sanitized_device_uri)
+ strlcpy(old_device_uri, printer->sanitized_device_uri,
+ sizeof(old_device_uri));
+ else
+ old_device_uri[0] = '\0';
+
+ cupsdSetDeviceURI(printer, attr->values[0].string.text);
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Setting %s device-uri to \"%s\" (was \"%s\".)",
+ printer->name, printer->sanitized_device_uri,
+ old_device_uri);
+
+ set_device_uri = 1;
+ }
+
+ set_port_monitor = 0;
+
+ if ((attr = ippFindAttribute(con->request, "port-monitor",
+ IPP_TAG_NAME)) != NULL)
+ {
+ ipp_attribute_t *supported; /* port-monitor-supported attribute */
+
+
+ need_restart_job = 1;
+
+ supported = ippFindAttribute(printer->ppd_attrs, "port-monitor-supported",
+ IPP_TAG_NAME);
+ if (supported)
+ {
+ for (i = 0; i < supported->num_values; i ++)
+ if (!strcmp(supported->values[i].string.text,
+ attr->values[0].string.text))
+ break;
+ }
+
+ if (!supported || i >= supported->num_values)
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad port-monitor \"%s\"."),
+ attr->values[0].string.text);
+ return;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Setting %s port-monitor to \"%s\" (was \"%s\".)",
+ printer->name, attr->values[0].string.text,
+ printer->port_monitor ? printer->port_monitor : "none");
+
+ if (strcmp(attr->values[0].string.text, "none"))
+ cupsdSetString(&printer->port_monitor, attr->values[0].string.text);
+ else
+ cupsdClearString(&printer->port_monitor);
+
+ set_port_monitor = 1;
+ }
+
+ if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs",
+ IPP_TAG_BOOLEAN)) != NULL &&
+ attr->values[0].boolean != printer->accepting)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Setting %s printer-is-accepting-jobs to %d (was %d.)",
+ printer->name, attr->values[0].boolean, printer->accepting);
+
+ printer->accepting = attr->values[0].boolean;
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
+ "%s accepting jobs.",
+ printer->accepting ? "Now" : "No longer");
+ }
+
+ if ((attr = ippFindAttribute(con->request, "printer-is-shared",
+ IPP_TAG_BOOLEAN)) != NULL)
+ {
+ if (attr->values[0].boolean &&
+ printer->num_auth_info_required == 1 &&
+ !strcmp(printer->auth_info_required[0], "negotiate"))
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Cannot share a remote Kerberized printer."));
+ return;
+ }
+
+ if (printer->shared && !attr->values[0].boolean)
+ cupsdDeregisterPrinter(printer, 1);
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Setting %s printer-is-shared to %d (was %d.)",
+ printer->name, attr->values[0].boolean, printer->shared);
+
+ printer->shared = attr->values[0].boolean;
+ }
+
+ if ((attr = ippFindAttribute(con->request, "printer-state",
+ IPP_TAG_ENUM)) != NULL)
+ {
+ if (attr->values[0].integer != IPP_PRINTER_IDLE &&
+ attr->values[0].integer != IPP_PRINTER_STOPPED)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad printer-state value %d."),
+ attr->values[0].integer);
+ return;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-state to %d (was %d.)",
+ printer->name, attr->values[0].integer, printer->state);
+
+ if (attr->values[0].integer == IPP_PRINTER_STOPPED)
+ cupsdStopPrinter(printer, 0);
+ else
+ {
+ need_restart_job = 1;
+ cupsdSetPrinterState(printer, (ipp_pstate_t)(attr->values[0].integer), 0);
+ }
+ }
+
+ if ((attr = ippFindAttribute(con->request, "printer-state-message",
+ IPP_TAG_TEXT)) != NULL)
+ {
+ strlcpy(printer->state_message, attr->values[0].string.text,
+ sizeof(printer->state_message));
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL, "%s",
+ printer->state_message);
+ }
+
+ if ((attr = ippFindAttribute(con->request, "printer-state-reasons",
+ IPP_TAG_KEYWORD)) != NULL)
+ {
+ if (attr->num_values >
+ (int)(sizeof(printer->reasons) / sizeof(printer->reasons[0])))
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Too many printer-state-reasons values (%d > %d)."),
+ attr->num_values,
+ (int)(sizeof(printer->reasons) /
+ sizeof(printer->reasons[0])));
+ return;
+ }
+
+ for (i = 0; i < printer->num_reasons; i ++)
+ _cupsStrFree(printer->reasons[i]);
+
+ printer->num_reasons = 0;
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (!strcmp(attr->values[i].string.text, "none"))
+ continue;
+
+ printer->reasons[printer->num_reasons] =
+ _cupsStrRetain(attr->values[i].string.text);
+ printer->num_reasons ++;
+
+ if (!strcmp(attr->values[i].string.text, "paused") &&
+ printer->state != IPP_PRINTER_STOPPED)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Setting %s printer-state to %d (was %d.)",
+ printer->name, IPP_PRINTER_STOPPED, printer->state);
+ cupsdStopPrinter(printer, 0);
+ }
+ }
+
+ if (PrintcapFormat == PRINTCAP_PLIST)
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
+ "Printer \"%s\" state changed.", printer->name);
+ }
+
+ set_printer_defaults(con, printer);
+
+ if ((attr = ippFindAttribute(con->request, "auth-info-required",
+ IPP_TAG_KEYWORD)) != NULL)
+ cupsdSetAuthInfoRequired(printer, NULL, attr);
+
+ /*
+ * See if we have all required attributes...
+ */
+
+ if (!printer->device_uri)
+ cupsdSetString(&printer->device_uri, "file:///dev/null");
+
+ /*
+ * See if we have an interface script or PPD file attached to the request...
+ */
+
+ if (con->filename)
+ {
+ need_restart_job = 1;
+ changed_driver = 1;
+
+ strlcpy(srcfile, con->filename, sizeof(srcfile));
+
+ if ((fp = cupsFileOpen(srcfile, "rb")))
+ {
+ /*
+ * Yes; get the first line from it...
+ */
+
+ line[0] = '\0';
+ cupsFileGets(fp, line, sizeof(line));
+ cupsFileClose(fp);
+
+ /*
+ * Then see what kind of file it is...
+ */
+
+ snprintf(dstfile, sizeof(dstfile), "%s/interfaces/%s", ServerRoot,
+ printer->name);
+
+ if (!strncmp(line, "*PPD-Adobe", 10))
+ {
+ /*
+ * The new file is a PPD file, so remove any old interface script
+ * that might be lying around...
+ */
+
+ unlink(dstfile);
+ }
+ else
+ {
+ /*
+ * This must be an interface script, so move the file over to the
+ * interfaces directory and make it executable...
+ */
+
+ if (copy_file(srcfile, dstfile))
+ {
+ send_ipp_status(con, IPP_INTERNAL_ERROR,
+ _("Unable to copy interface script - %s"),
+ strerror(errno));
+ return;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Copied interface script successfully");
+ chmod(dstfile, 0755);
+ }
+
+ snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot,
+ printer->name);
+
+ if (!strncmp(line, "*PPD-Adobe", 10))
+ {
+ /*
+ * The new file is a PPD file, so move the file over to the
+ * ppd directory and make it readable by all...
+ */
+
+ if (copy_file(srcfile, dstfile))
+ {
+ send_ipp_status(con, IPP_INTERNAL_ERROR,
+ _("Unable to copy PPD file - %s"),
+ strerror(errno));
+ return;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Copied PPD file successfully");
+ chmod(dstfile, 0644);
+ }
+ else
+ {
+ /*
+ * This must be an interface script, so remove any old PPD file that
+ * may be lying around...
+ */
+
+ unlink(dstfile);
+ }
+ }
+ }
+ else if ((attr = ippFindAttribute(con->request, "ppd-name",
+ IPP_TAG_NAME)) != NULL)
+ {
+ need_restart_job = 1;
+ changed_driver = 1;
+
+ if (!strcmp(attr->values[0].string.text, "raw"))
+ {
+ /*
+ * Raw driver, remove any existing PPD or interface script files.
+ */
+
+ snprintf(dstfile, sizeof(dstfile), "%s/interfaces/%s", ServerRoot,
+ printer->name);
+ unlink(dstfile);
+
+ snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot,
+ printer->name);
+ unlink(dstfile);
+ }
+ else
+ {
+ /*
+ * PPD model file...
+ */
+
+ snprintf(dstfile, sizeof(dstfile), "%s/interfaces/%s", ServerRoot,
+ printer->name);
+ unlink(dstfile);
+
+ snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot,
+ printer->name);
+
+ if (copy_model(con, attr->values[0].string.text, dstfile))
+ {
+ send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to copy PPD file."));
+ return;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Copied PPD file successfully");
+ chmod(dstfile, 0644);
+ }
+ }
+
+ if (changed_driver)
+ {
+ /*
+ * If we changed the PPD/interface script, then remove the printer's cache
+ * file and clear the printer-state-reasons...
+ */
+
+ char cache_name[1024]; /* Cache filename for printer attrs */
+
+ snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir,
+ printer->name);
+ unlink(cache_name);
+
+ cupsdSetPrinterReasons(printer, "none");
+
+#ifdef __APPLE__
+ /*
+ * (Re)register color profiles...
+ */
+
+ if (!RunUser)
+ {
+ apple_unregister_profiles(printer);
+ apple_register_profiles(printer);
+ }
+#endif /* __APPLE__ */
+ }
+
+ /*
+ * If we set the device URI but not the port monitor, check which port
+ * monitor to use by default...
+ */
+
+ if (set_device_uri && !set_port_monitor)
+ {
+ ppd_file_t *ppd; /* PPD file */
+ ppd_attr_t *ppdattr; /* cupsPortMonitor attribute */
+
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, printer->device_uri, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ snprintf(srcfile, sizeof(srcfile), "%s/ppd/%s.ppd", ServerRoot,
+ printer->name);
+ if ((ppd = ppdOpenFile(srcfile)) != NULL)
+ {
+ for (ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
+ ppdattr;
+ ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
+ if (!strcmp(scheme, ppdattr->spec))
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Setting %s port-monitor to \"%s\" (was \"%s\".)",
+ printer->name, ppdattr->value,
+ printer->port_monitor ? printer->port_monitor
+ : "none");
+
+ if (strcmp(ppdattr->value, "none"))
+ cupsdSetString(&printer->port_monitor, ppdattr->value);
+ else
+ cupsdClearString(&printer->port_monitor);
+
+ break;
+ }
+
+ ppdClose(ppd);
+ }
+ }
+
+ /*
+ * Update the printer attributes and return...
+ */
+
+ cupsdSetPrinterAttrs(printer);
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+
+ if (need_restart_job && printer->job)
+ {
+ /*
+ * Restart the current job...
+ */
+
+ cupsdSetJobState(printer->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE,
+ "Job restarted because the printer was modified.");
+ }
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+
+ if (modify)
+ {
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED,
+ printer, NULL, "Printer \"%s\" modified by \"%s\".",
+ printer->name, get_username(con));
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" modified by \"%s\".",
+ printer->name, get_username(con));
+ }
+ else
+ {
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED,
+ printer, NULL, "New printer \"%s\" added by \"%s\".",
+ printer->name, get_username(con));
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "New printer \"%s\" added by \"%s\".",
+ printer->name, get_username(con));
+ }
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute
+ * based upon the printer state...
+ */
+
+static void
+add_printer_state_reasons(
+ cupsd_client_t *con, /* I - Client connection */
+ cupsd_printer_t *p) /* I - Printer info */
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "add_printer_state_reasons(%p[%d], %p[%s])",
+ con, con->http.fd, p, p->name);
+
+ if (p->num_reasons == 0)
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "printer-state-reasons", NULL, "none");
+ else
+ ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "printer-state-reasons", p->num_reasons, NULL,
+ (const char * const *)p->reasons);
+}
+
+
+/*
+ * 'add_queued_job_count()' - Add the "queued-job-count" attribute for
+ * the specified printer or class.
+ */
+
+static void
+add_queued_job_count(
+ cupsd_client_t *con, /* I - Client connection */
+ cupsd_printer_t *p) /* I - Printer or class */
+{
+ int count; /* Number of jobs on destination */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_queued_job_count(%p[%d], %p[%s])",
+ con, con->http.fd, p, p->name);
+
+ count = cupsdGetPrinterJobCount(p->name);
+
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "queued-job-count", count);
+}
+
+
+#ifdef __APPLE__
+/*
+ * 'apple_init_profile()' - Initialize a color profile.
+ */
+
+static void
+apple_init_profile(
+ ppd_file_t *ppd, /* I - PPD file */
+ cups_array_t *languages, /* I - Languages in the PPD file */
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+ CFMutableDictionaryRef profile, /* I - Profile dictionary */
+# else
+ CMDeviceProfileInfo *profile, /* I - Profile record */
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+ unsigned id, /* I - Profile ID */
+ const char *name, /* I - Profile name */
+ const char *text, /* I - Profile UI text */
+ const char *iccfile) /* I - ICC filename */
+{
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+ CFURLRef url; /* URL for profile filename */
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+ CFMutableDictionaryRef dict; /* Dictionary for name */
+ char *language; /* Current language */
+ ppd_attr_t *attr; /* Profile attribute */
+ CFStringRef cflang, /* Language string */
+ cftext; /* Localized text */
+
+
+ (void)id;
+
+ /*
+ * Build the profile name dictionary...
+ */
+
+ dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ if (!dict)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize profile \"%s\".",
+ iccfile);
+ return;
+ }
+
+ cftext = CFStringCreateWithCString(kCFAllocatorDefault, text,
+ kCFStringEncodingUTF8);
+
+ if (cftext)
+ {
+ CFDictionarySetValue(dict, CFSTR("en_US"), cftext);
+ CFRelease(cftext);
+ }
+
+ if (languages)
+ {
+ /*
+ * Find localized names for the color profiles...
+ */
+
+ cupsArraySave(ppd->sorted_attrs);
+
+ for (language = (char *)cupsArrayFirst(languages);
+ language;
+ language = (char *)cupsArrayNext(languages))
+ {
+ if (iccfile)
+ {
+ if ((attr = _ppdLocalizedAttr(ppd, "cupsICCProfile", name,
+ language)) == NULL)
+ attr = _ppdLocalizedAttr(ppd, "APTiogaProfile", name, language);
+ }
+ else
+ attr = _ppdLocalizedAttr(ppd, "ColorModel", name, language);
+
+ if (attr && attr->text[0])
+ {
+ cflang = CFStringCreateWithCString(kCFAllocatorDefault, language,
+ kCFStringEncodingUTF8);
+ cftext = CFStringCreateWithCString(kCFAllocatorDefault, attr->text,
+ kCFStringEncodingUTF8);
+
+ if (cflang && cftext)
+ CFDictionarySetValue(dict, cflang, cftext);
+
+ if (cflang)
+ CFRelease(cflang);
+
+ if (cftext)
+ CFRelease(cftext);
+ }
+ }
+
+ cupsArrayRestore(ppd->sorted_attrs);
+ }
+
+ /*
+ * Fill in the profile data...
+ */
+
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+ if (iccfile)
+ {
+ url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
+ (const UInt8 *)iccfile,
+ strlen(iccfile), false);
+
+ if (url)
+ {
+ CFDictionarySetValue(profile, kColorSyncDeviceProfileURL, url);
+ CFRelease(url);
+ }
+ }
+
+ CFDictionarySetValue(profile, kColorSyncDeviceModeDescriptions, dict);
+ CFRelease(dict);
+
+# else
+ profile->dataVersion = cmDeviceProfileInfoVersion1;
+ profile->profileID = id;
+ profile->profileLoc.locType = iccfile ? cmPathBasedProfile : cmNoProfileBase;
+ profile->profileName = dict;
+
+ if (iccfile)
+ strlcpy(profile->profileLoc.u.pathLoc.path, iccfile,
+ sizeof(profile->profileLoc.u.pathLoc.path));
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+}
+
+
+/*
+ * 'apple_register_profiles()' - Register color profiles for a printer.
+ */
+
+static void
+apple_register_profiles(
+ cupsd_printer_t *p) /* I - Printer */
+{
+ int i; /* Looping var */
+ char ppdfile[1024], /* PPD filename */
+ iccfile[1024], /* ICC filename */
+ selector[PPD_MAX_NAME];
+ /* Profile selection string */
+ ppd_file_t *ppd; /* PPD file */
+ ppd_attr_t *attr, /* Profile attributes */
+ *profileid_attr,/* cupsProfileID attribute */
+ *q1_attr, /* ColorModel (or other) qualifier */
+ *q2_attr, /* MediaType (or other) qualifier */
+ *q3_attr; /* Resolution (or other) qualifier */
+ char q_keyword[PPD_MAX_NAME];
+ /* Qualifier keyword */
+ const char *q1_choice, /* ColorModel (or other) choice */
+ *q2_choice, /* MediaType (or other) choice */
+ *q3_choice; /* Resolution (or other) choice */
+ const char *profile_key; /* Profile keyword */
+ ppd_option_t *cm_option; /* Color model option */
+ ppd_choice_t *cm_choice; /* Color model choice */
+ int num_profiles; /* Number of profiles */
+ OSStatus error = 0; /* Last error */
+ unsigned device_id, /* Printer device ID */
+ profile_id, /* Profile ID */
+ default_profile_id = 0;
+ /* Default profile ID */
+ CFMutableDictionaryRef device_name; /* Printer device name dictionary */
+ CFStringRef printer_name; /* Printer name string */
+ cups_array_t *languages; /* Languages array */
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+ CFMutableDictionaryRef profiles, /* Dictionary of profiles */
+ profile; /* Current profile info dictionary */
+ CFStringRef dict_key; /* Key in factory profile dictionary */
+# else
+ CMDeviceScope scope = /* Scope of the registration */
+ {
+ kCFPreferencesAnyUser,
+ kCFPreferencesCurrentHost
+ };
+ CMDeviceProfileArrayPtr profiles; /* Profiles */
+ CMDeviceProfileInfo *profile; /* Current profile */
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+
+
+ /*
+ * Make sure ColorSync is available...
+ */
+
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+ if (ColorSyncRegisterDevice == NULL)
+ return;
+
+# else
+ if (CMRegisterColorDevice == NULL)
+ return;
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+
+ /*
+ * Try opening the PPD file for this printer...
+ */
+
+ snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
+ if ((ppd = ppdOpenFile(ppdfile)) == NULL)
+ return;
+
+ /*
+ * See if we have any profiles...
+ */
+
+ if ((attr = ppdFindAttr(ppd, "APTiogaProfile", NULL)) != NULL)
+ profile_key = "APTiogaProfile";
+ else
+ {
+ attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
+ profile_key = "cupsICCProfile";
+ }
+
+ for (num_profiles = 0; attr; attr = ppdFindNextAttr(ppd, profile_key, NULL))
+ if (attr->spec[0] && attr->value && attr->value[0])
+ {
+ if (attr->value[0] != '/')
+ snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
+ attr->value);
+ else
+ strlcpy(iccfile, attr->value, sizeof(iccfile));
+
+ if (access(iccfile, 0))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "%s: ICC Profile \"%s\" does not exist.", p->name,
+ iccfile);
+ continue;
+ }
+
+ num_profiles ++;
+ }
+
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+ /*
+ * Create a dictionary for the factory profiles...
+ */
+
+ profiles = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ if (!profiles)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for factory profiles.");
+ ppdClose(ppd);
+ return;
+ }
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+
+ /*
+ * If we have profiles, add them...
+ */
+
+ if (num_profiles > 0)
+ {
+ if (profile_key[0] == 'A')
+ {
+ /*
+ * For Tioga PPDs, get the default profile using the DefaultAPTiogaProfile
+ * attribute...
+ */
+
+ if ((attr = ppdFindAttr(ppd, "DefaultAPTiogaProfile", NULL)) != NULL &&
+ attr->value)
+ default_profile_id = atoi(attr->value);
+
+ q1_choice = q2_choice = q3_choice = NULL;
+ }
+ else
+ {
+ /*
+ * For CUPS PPDs, figure out the default profile selector values...
+ */
+
+ if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL &&
+ attr->value && attr->value[0])
+ {
+ snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
+ q1_attr = ppdFindAttr(ppd, q_keyword, NULL);
+ }
+ else if ((q1_attr = ppdFindAttr(ppd, "DefaultColorModel", NULL)) == NULL)
+ q1_attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL);
+
+ if (q1_attr && q1_attr->value && q1_attr->value[0])
+ q1_choice = q1_attr->value;
+ else
+ q1_choice = "";
+
+ if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL &&
+ attr->value && attr->value[0])
+ {
+ snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
+ q2_attr = ppdFindAttr(ppd, q_keyword, NULL);
+ }
+ else
+ q2_attr = ppdFindAttr(ppd, "DefaultMediaType", NULL);
+
+ if (q2_attr && q2_attr->value && q2_attr->value[0])
+ q2_choice = q2_attr->value;
+ else
+ q2_choice = NULL;
+
+ if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL &&
+ attr->value && attr->value[0])
+ {
+ snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
+ q3_attr = ppdFindAttr(ppd, q_keyword, NULL);
+ }
+ else
+ q3_attr = ppdFindAttr(ppd, "DefaultResolution", NULL);
+
+ if (q3_attr && q3_attr->value && q3_attr->value[0])
+ q3_choice = q3_attr->value;
+ else
+ q3_choice = NULL;
+ }
+
+# ifndef HAVE_COLORSYNCREGISTERDEVICE
+ /*
+ * Build the array of profiles...
+ *
+ * Note: This calloc actually requests slightly more memory than needed.
+ */
+
+ if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for factory profiles.");
+ ppdClose(ppd);
+ return;
+ }
+
+ profiles->profileCount = num_profiles;
+ profile = profiles->profiles;
+# endif /* !HAVE_COLORSYNCREGISTERDEVICE */
+
+ /*
+ * Loop through the profiles listed in the PPD...
+ */
+
+ languages = _ppdGetLanguages(ppd);
+
+ for (attr = ppdFindAttr(ppd, profile_key, NULL);
+ attr;
+ attr = ppdFindNextAttr(ppd, profile_key, NULL))
+ if (attr->spec[0] && attr->value && attr->value[0])
+ {
+ /*
+ * Add this profile...
+ */
+
+ if (attr->value[0] != '/')
+ snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
+ attr->value);
+ else
+ strlcpy(iccfile, attr->value, sizeof(iccfile));
+
+ if (_cupsFileCheck(iccfile, _CUPS_FILE_CHECK_FILE, !RunUser,
+ cupsdLogFCMessage, p))
+ continue;
+
+ if (profile_key[0] == 'c')
+ {
+ cupsArraySave(ppd->sorted_attrs);
+
+ if ((profileid_attr = ppdFindAttr(ppd, "cupsProfileID",
+ attr->spec)) != NULL &&
+ profileid_attr->value && isdigit(profileid_attr->value[0] & 255))
+ profile_id = (unsigned)strtoul(profileid_attr->value, NULL, 10);
+ else
+ profile_id = _ppdHashName(attr->spec);
+
+ cupsArrayRestore(ppd->sorted_attrs);
+ }
+ else
+ profile_id = atoi(attr->spec);
+
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+ profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ if (!profile)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for color profile.");
+ CFRelease(profiles);
+ ppdClose(ppd);
+ return;
+ }
+
+ apple_init_profile(ppd, languages, profile, profile_id, attr->spec,
+ attr->text[0] ? attr->text : attr->spec, iccfile);
+
+ dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
+ CFSTR("%u"), profile_id);
+ if (dict_key)
+ {
+ CFDictionarySetValue(profiles, dict_key, profile);
+ CFRelease(dict_key);
+ }
+
+ CFRelease(profile);
+
+# else
+ apple_init_profile(ppd, languages, profile, profile_id, attr->spec,
+ attr->text[0] ? attr->text : attr->spec, iccfile);
+
+ profile ++;
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+
+ /*
+ * See if this is the default profile...
+ */
+
+ if (!default_profile_id && q1_choice && q2_choice && q3_choice)
+ {
+ snprintf(selector, sizeof(selector), "%s.%s.%s", q1_choice, q2_choice,
+ q3_choice);
+ if (!strcmp(selector, attr->spec))
+ default_profile_id = profile_id;
+ }
+
+ if (!default_profile_id && q1_choice && q2_choice)
+ {
+ snprintf(selector, sizeof(selector), "%s.%s.", q1_choice, q2_choice);
+ if (!strcmp(selector, attr->spec))
+ default_profile_id = profile_id;
+ }
+
+ if (!default_profile_id && q1_choice && q3_choice)
+ {
+ snprintf(selector, sizeof(selector), "%s..%s", q1_choice, q3_choice);
+ if (!strcmp(selector, attr->spec))
+ default_profile_id = profile_id;
+ }
+
+ if (!default_profile_id && q1_choice)
+ {
+ snprintf(selector, sizeof(selector), "%s..", q1_choice);
+ if (!strcmp(selector, attr->spec))
+ default_profile_id = profile_id;
+ }
+
+ if (!default_profile_id && q2_choice && q3_choice)
+ {
+ snprintf(selector, sizeof(selector), ".%s.%s", q2_choice, q3_choice);
+ if (!strcmp(selector, attr->spec))
+ default_profile_id = profile_id;
+ }
+
+ if (!default_profile_id && q2_choice)
+ {
+ snprintf(selector, sizeof(selector), ".%s.", q2_choice);
+ if (!strcmp(selector, attr->spec))
+ default_profile_id = profile_id;
+ }
+
+ if (!default_profile_id && q3_choice)
+ {
+ snprintf(selector, sizeof(selector), "..%s", q3_choice);
+ if (!strcmp(selector, attr->spec))
+ default_profile_id = profile_id;
+ }
+ }
+
+ _ppdFreeLanguages(languages);
+ }
+ else if ((cm_option = ppdFindOption(ppd, "ColorModel")) != NULL)
+ {
+ /*
+ * Extract profiles from ColorModel option...
+ */
+
+ const char *profile_name; /* Name of generic profile */
+
+
+ num_profiles = cm_option->num_choices;
+
+# ifndef HAVE_COLORSYNCREGISTERDEVICE
+ /*
+ * Create an array for the factory profiles...
+ */
+
+ if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for factory profiles.");
+ ppdClose(ppd);
+ return;
+ }
+
+ profiles->profileCount = num_profiles;
+ profile = profiles->profiles;
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+
+ for (i = cm_option->num_choices, cm_choice = cm_option->choices;
+ i > 0;
+ i --, cm_choice ++)
+ {
+ if (!strcmp(cm_choice->choice, "Gray") ||
+ !strcmp(cm_choice->choice, "Black"))
+ profile_name = "Gray";
+ else if (!strcmp(cm_choice->choice, "RGB") ||
+ !strcmp(cm_choice->choice, "CMY"))
+ profile_name = "RGB";
+ else if (!strcmp(cm_choice->choice, "CMYK") ||
+ !strcmp(cm_choice->choice, "KCMY"))
+ profile_name = "CMYK";
+ else
+ profile_name = "DeviceN";
+
+ snprintf(selector, sizeof(selector), "%s..", profile_name);
+ profile_id = _ppdHashName(selector);
+
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+ profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ if (!profile)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for color profile.");
+ CFRelease(profiles);
+ ppdClose(ppd);
+ return;
+ }
+
+ apple_init_profile(ppd, NULL, profile, profile_id, cm_choice->choice,
+ cm_choice->text, NULL);
+
+ dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
+ CFSTR("%u"), profile_id);
+ if (dict_key)
+ {
+ CFDictionarySetValue(profiles, dict_key, profile);
+ CFRelease(dict_key);
+ }
+
+ CFRelease(profile);
+
+# else
+ apple_init_profile(ppd, NULL, profile, profile_id, cm_choice->choice,
+ cm_choice->text, NULL);
+ profile ++;
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+
+ if (cm_choice->marked)
+ default_profile_id = profile_id;
+ }
+ }
+ else
+ {
+ /*
+ * Use the default colorspace...
+ */
+
+ attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL);
+
+ num_profiles = (attr && ppd->colorspace == PPD_CS_GRAY) ? 1 : 2;
+
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+ /*
+ * Add the grayscale profile first. We always have a grayscale profile.
+ */
+
+ profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ if (!profile)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for color profile.");
+ CFRelease(profiles);
+ ppdClose(ppd);
+ return;
+ }
+
+ profile_id = _ppdHashName("Gray..");
+ apple_init_profile(ppd, NULL, profile, profile_id, "Gray", "Gray", NULL);
+
+ dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"),
+ profile_id);
+ if (dict_key)
+ {
+ CFDictionarySetValue(profiles, dict_key, profile);
+ CFRelease(dict_key);
+ }
+
+ CFRelease(profile);
+
+ /*
+ * Then add the RGB/CMYK/DeviceN color profile...
+ */
+
+ profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ if (!profile)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for color profile.");
+ CFRelease(profiles);
+ ppdClose(ppd);
+ return;
+ }
+
+ switch (ppd->colorspace)
+ {
+ case PPD_CS_RGB :
+ case PPD_CS_CMY :
+ profile_id = _ppdHashName("RGB..");
+ apple_init_profile(ppd, NULL, profile, profile_id, "RGB", "RGB",
+ NULL);
+ break;
+ case PPD_CS_RGBK :
+ case PPD_CS_CMYK :
+ profile_id = _ppdHashName("CMYK..");
+ apple_init_profile(ppd, NULL, profile, profile_id, "CMYK", "CMYK",
+ NULL);
+ break;
+
+ case PPD_CS_GRAY :
+ if (attr)
+ break;
+
+ case PPD_CS_N :
+ profile_id = _ppdHashName("DeviceN..");
+ apple_init_profile(ppd, NULL, profile, profile_id, "DeviceN",
+ "DeviceN", NULL);
+ break;
+ }
+
+ if (CFDictionaryGetCount(profile) > 0)
+ {
+ dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
+ CFSTR("%u"), profile_id);
+ if (dict_key)
+ {
+ CFDictionarySetValue(profiles, dict_key, profile);
+ CFRelease(dict_key);
+ }
+ }
+
+ CFRelease(profile);
+
+# else
+ /*
+ * Create an array for the factory profiles...
+ */
+
+ if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for factory profiles.");
+ ppdClose(ppd);
+ return;
+ }
+
+ profiles->profileCount = num_profiles;
+
+ /*
+ * Add the grayscale profile first. We always have a grayscale profile.
+ */
+
+ profile_id = _ppdHashName("Gray..");
+ apple_init_profile(ppd, NULL, profiles->profiles, profile_id, "Gray",
+ "Gray", NULL);
+
+ /*
+ * Then add the RGB/CMYK/DeviceN color profile...
+ */
+
+ switch (ppd->colorspace)
+ {
+ case PPD_CS_RGB :
+ case PPD_CS_CMY :
+ profile_id = _ppdHashName("RGB..");
+ apple_init_profile(ppd, NULL, profiles->profiles + 1, profile_id,
+ "RGB", "RGB", NULL);
+ break;
+ case PPD_CS_RGBK :
+ case PPD_CS_CMYK :
+ profile_id = _ppdHashName("CMYK..");
+ apple_init_profile(ppd, NULL, profiles->profiles + 1, profile_id,
+ "CMYK", "CMYK", NULL);
+ break;
+
+ case PPD_CS_GRAY :
+ if (attr)
+ break;
+
+ case PPD_CS_N :
+ profile_id = _ppdHashName("DeviceN..");
+ apple_init_profile(ppd, NULL, profiles->profiles + 1, profile_id,
+ "DeviceN", "DeviceN", NULL);
+ break;
+ }
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+ }
+
+ if (num_profiles > 0)
+ {
+ /*
+ * Make sure we have a default profile ID...
+ */
+
+ if (!default_profile_id)
+ default_profile_id = profile_id; /* Last profile */
+
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+ dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"),
+ default_profile_id);
+ if (dict_key)
+ {
+ CFDictionarySetValue(profiles, kColorSyncDeviceDefaultProfileID,
+ dict_key);
+ CFRelease(dict_key);
+ }
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+
+ /*
+ * Get the device ID hash and pathelogical name dictionary.
+ */
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\"",
+ p->name);
+
+ device_id = _ppdHashName(p->name);
+ device_name = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ printer_name = CFStringCreateWithCString(kCFAllocatorDefault,
+ p->name, kCFStringEncodingUTF8);
+
+ if (device_name && printer_name)
+ {
+ CFDictionarySetValue(device_name, CFSTR("en_US"), printer_name);
+
+ /*
+ * Register the device with ColorSync...
+ */
+
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+ CFTypeRef deviceDictKeys[] =
+ { /* Device keys */
+ kColorSyncDeviceDescriptions,
+ kColorSyncFactoryProfiles,
+ kColorSyncDeviceUserScope,
+ kColorSyncDeviceHostScope
+ };
+ CFTypeRef deviceDictVals[] =
+ { /* Device values */
+ device_name,
+ profiles,
+ kCFPreferencesAnyUser,
+ kCFPreferencesCurrentHost
+ };
+ CFDictionaryRef deviceDict; /* Device dictionary */
+ CFUUIDRef deviceUUID; /* Device UUID */
+
+ deviceDict = CFDictionaryCreate(kCFAllocatorDefault,
+ (const void **)deviceDictKeys,
+ (const void **)deviceDictVals,
+ sizeof(deviceDictKeys) /
+ sizeof(deviceDictKeys[0]),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ deviceUUID = ColorSyncCreateUUIDFromUInt32(device_id);
+
+ if (!deviceDict || !deviceUUID ||
+ !ColorSyncRegisterDevice(kColorSyncPrinterDeviceClass, deviceUUID,
+ deviceDict))
+ error = 1001;
+
+ if (deviceUUID)
+ CFRelease(deviceUUID);
+
+ if (deviceDict)
+ CFRelease(deviceDict);
+
+# else
+ error = CMRegisterColorDevice(cmPrinterDeviceClass, device_id,
+ device_name, &scope);
+
+ /*
+ * Register the profiles...
+ */
+
+ if (error == noErr)
+ error = CMSetDeviceFactoryProfiles(cmPrinterDeviceClass, device_id,
+ default_profile_id, profiles);
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+ }
+ else
+ error = 1000;
+
+ /*
+ * Clean up...
+ */
+
+ if (error != noErr)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to register ICC color profiles for \"%s\": %d",
+ p->name, (int)error);
+
+ if (printer_name)
+ CFRelease(printer_name);
+
+ if (device_name)
+ CFRelease(device_name);
+ }
+
+ /*
+ * Free any memory we used...
+ */
+
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+ CFRelease(profiles);
+
+# else
+ if (num_profiles > 0)
+ {
+ for (profile = profiles->profiles;
+ num_profiles > 0;
+ profile ++, num_profiles --)
+ CFRelease(profile->profileName);
+
+ free(profiles);
+ }
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+
+ ppdClose(ppd);
+}
+
+
+/*
+ * 'apple_unregister_profiles()' - Remove color profiles for the specified
+ * printer.
+ */
+
+static void
+apple_unregister_profiles(
+ cupsd_printer_t *p) /* I - Printer */
+{
+ /*
+ * Make sure ColorSync is available...
+ */
+
+# ifdef HAVE_COLORSYNCREGISTERDEVICE
+ if (ColorSyncUnregisterDevice != NULL)
+ {
+ /*
+ * Because we may have registered the printer profiles using a prior device
+ * ID-based UUID, remove both the old style UUID and current UUID for the
+ * printer.
+ */
+
+ CFUUIDRef deviceUUID; /* Device UUID */
+
+ deviceUUID = ColorSyncCreateUUIDFromUInt32(_ppdHashName(p->name));
+ if (deviceUUID)
+ {
+ ColorSyncUnregisterDevice(kColorSyncPrinterDeviceClass, deviceUUID);
+ CFRelease(deviceUUID);
+ }
+ }
+
+# else
+ if (CMUnregisterColorDevice != NULL)
+ CMUnregisterColorDevice(cmPrinterDeviceClass, _ppdHashName(p->name));
+# endif /* HAVE_COLORSYNCREGISTERDEVICE */
+}
+#endif /* __APPLE__ */
+
+
+/*
+ * 'apply_printer_defaults()' - Apply printer default options to a job.
+ */
+
+static void
+apply_printer_defaults(
+ cupsd_printer_t *printer, /* I - Printer */
+ cupsd_job_t *job) /* I - Job */
+{
+ int i, /* Looping var */
+ num_options; /* Number of default options */
+ cups_option_t *options, /* Default options */
+ *option; /* Current option */
+
+
+ /*
+ * Collect all of the default options and add the missing ones to the
+ * job object...
+ */
+
+ for (i = printer->num_options, num_options = 0, options = NULL,
+ option = printer->options;
+ i > 0;
+ i --, option ++)
+ if (!ippFindAttribute(job->attrs, option->name, IPP_TAG_ZERO))
+ {
+ num_options = cupsAddOption(option->name, option->value, num_options,
+ &options);
+ }
+
+ /*
+ * Encode these options as attributes in the job object...
+ */
+
+ cupsEncodeOptions2(job->attrs, num_options, options, IPP_TAG_JOB);
+ cupsFreeOptions(num_options, options);
+}
+
+
+/*
+ * 'authenticate_job()' - Set job authentication info.
+ */
+
+static void
+authenticate_job(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job URI */
+{
+ ipp_attribute_t *attr, /* job-id attribute */
+ *auth_info; /* auth-info attribute */
+ int jobid; /* Job ID */
+ cupsd_job_t *job; /* Current job */
+ char scheme[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "authenticate_job(%p[%d], %s)",
+ con, con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Start with "everything is OK" status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (!strcmp(uri->name, "printer-uri"))
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Got a printer-uri attribute but no job-id."));
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (strncmp(resource, "/jobs/", 6))
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
+ uri->values[0].string.text);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = cupsdFindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
+ return;
+ }
+
+ /*
+ * See if the job has been completed...
+ */
+
+ if (job->state_value != IPP_JOB_HELD)
+ {
+ /*
+ * Return a "not-possible" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Job #%d is not held for authentication."),
+ jobid);
+ return;
+ }
+
+ /*
+ * See if we have already authenticated...
+ */
+
+ auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT);
+
+ if (!con->username[0] && !auth_info)
+ {
+ cupsd_printer_t *printer; /* Job destination */
+
+
+ /*
+ * No auth data. If we need to authenticate via Kerberos, send a
+ * HTTP auth challenge, otherwise just return an IPP error...
+ */
+
+ printer = cupsdFindDest(job->dest);
+
+ if (printer && printer->num_auth_info_required > 0 &&
+ !strcmp(printer->auth_info_required[0], "negotiate"))
+ send_http_error(con, HTTP_UNAUTHORIZED, printer);
+ else
+ send_ipp_status(con, IPP_NOT_AUTHORIZED,
+ _("No authentication information provided."));
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(job, con, job->username, username, sizeof(username)))
+ {
+ send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
+ cupsdFindDest(job->dest));
+ return;
+ }
+
+ /*
+ * Save the authentication information for this job...
+ */
+
+ save_auth_info(con, job, auth_info);
+
+ /*
+ * Reset the job-hold-until value to "no-hold"...
+ */
+
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
+ IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+
+ if (attr)
+ {
+ attr->value_tag = IPP_TAG_KEYWORD;
+ cupsdSetString(&(attr->values[0].string.text), "no-hold");
+ }
+
+ /*
+ * Release the job and return...
+ */
+
+ cupsdReleaseJob(job);
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_STATE, NULL, job, "Job authenticated by user");
+
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Authenticated by \"%s\".", con->username);
+
+ cupsdCheckJobs();
+}
+
+
+/*
+ * 'cancel_all_jobs()' - Cancel all or selected print jobs.
+ */
+
+static void
+cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job or Printer URI */
+{
+ int i; /* Looping var */
+ http_status_t status; /* Policy status */
+ cups_ptype_t dtype; /* Destination type */
+ char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
+ userpass[HTTP_MAX_URI], /* Username portion of URI */
+ hostname[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ ipp_attribute_t *attr; /* Attribute in request */
+ const char *username = NULL; /* Username */
+ cupsd_jobaction_t purge = CUPSD_JOB_DEFAULT;
+ /* Purge? */
+ cupsd_printer_t *printer; /* Printer */
+ ipp_attribute_t *job_ids; /* job-ids attribute */
+ cupsd_job_t *job; /* Job */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_all_jobs(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Get the jobs to cancel/purge...
+ */
+
+ switch (con->request->request.op.operation_id)
+ {
+ case IPP_PURGE_JOBS :
+ /*
+ * Get the username (if any) for the jobs we want to cancel (only if
+ * "my-jobs" is specified...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "my-jobs",
+ IPP_TAG_BOOLEAN)) != NULL &&
+ attr->values[0].boolean)
+ {
+ if ((attr = ippFindAttribute(con->request, "requesting-user-name",
+ IPP_TAG_NAME)) != NULL)
+ username = attr->values[0].string.text;
+ else
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Missing requesting-user-name attribute."));
+ return;
+ }
+ }
+
+ /*
+ * Look for the "purge-jobs" attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "purge-jobs",
+ IPP_TAG_BOOLEAN)) != NULL)
+ purge = attr->values[0].boolean ? CUPSD_JOB_PURGE : CUPSD_JOB_DEFAULT;
+ else
+ purge = CUPSD_JOB_PURGE;
+ break;
+
+ case IPP_CANCEL_MY_JOBS :
+ if (con->username[0])
+ username = con->username;
+ else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
+ IPP_TAG_NAME)) != NULL)
+ username = attr->values[0].string.text;
+ else
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Missing requesting-user-name attribute."));
+ return;
+ }
+
+ default :
+ break;
+ }
+
+ job_ids = ippFindAttribute(con->request, "job-ids", IPP_TAG_INTEGER);
+
+ /*
+ * See if we have a printer URI...
+ */
+
+ if (strcmp(uri->name, "printer-uri"))
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("The printer-uri attribute is required."));
+ return;
+ }
+
+ /*
+ * And if the destination is valid...
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI?
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text,
+ scheme, sizeof(scheme), userpass, sizeof(userpass),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(resource));
+
+ if ((!strncmp(resource, "/printers/", 10) && resource[10]) ||
+ (!strncmp(resource, "/classes/", 9) && resource[9]))
+ {
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ if (job_ids)
+ {
+ for (i = 0; i < job_ids->num_values; i ++)
+ {
+ if (!cupsdFindJob(job_ids->values[i].integer))
+ break;
+ }
+
+ if (i < job_ids->num_values)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
+ job_ids->values[i].integer);
+ return;
+ }
+
+ for (i = 0; i < job_ids->num_values; i ++)
+ {
+ job = cupsdFindJob(job_ids->values[i].integer);
+
+ cupsdSetJobState(job, IPP_JOB_CANCELED, purge,
+ purge == CUPSD_JOB_PURGE ? "Job purged by user." :
+ "Job canceled by user.");
+ }
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Selected jobs were %s by \"%s\".",
+ purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
+ get_username(con));
+ }
+ else
+ {
+ /*
+ * Cancel all jobs on all printers...
+ */
+
+ cupsdCancelJobs(NULL, username, purge);
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "All jobs were %s by \"%s\".",
+ purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
+ get_username(con));
+ }
+ }
+ else
+ {
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
+ NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+
+ if (job_ids)
+ {
+ for (i = 0; i < job_ids->num_values; i ++)
+ {
+ if ((job = cupsdFindJob(job_ids->values[i].integer)) == NULL ||
+ _cups_strcasecmp(job->dest, printer->name))
+ break;
+ }
+
+ if (i < job_ids->num_values)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
+ job_ids->values[i].integer);
+ return;
+ }
+
+ for (i = 0; i < job_ids->num_values; i ++)
+ {
+ job = cupsdFindJob(job_ids->values[i].integer);
+
+ cupsdSetJobState(job, IPP_JOB_CANCELED, purge,
+ purge == CUPSD_JOB_PURGE ? "Job purged by user." :
+ "Job canceled by user.");
+ }
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Selected jobs were %s by \"%s\".",
+ purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
+ get_username(con));
+ }
+ else
+ {
+ /*
+ * Cancel all of the jobs on the named printer...
+ */
+
+ cupsdCancelJobs(printer->name, username, purge);
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "All jobs on \"%s\" were %s by \"%s\".",
+ printer->name,
+ purge == CUPSD_JOB_PURGE ? "purged" : "canceled",
+ get_username(con));
+ }
+ }
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'cancel_job()' - Cancel a print job.
+ */
+
+static void
+cancel_job(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job or Printer URI */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ int jobid; /* Job ID */
+ char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ cupsd_job_t *job; /* Job information */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cupsd_printer_t *printer; /* Printer data */
+ cupsd_jobaction_t purge; /* Purge the job? */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_job(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (!strcmp(uri->name, "printer-uri"))
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Got a printer-uri attribute but no job-id."));
+ return;
+ }
+
+ if ((jobid = attr->values[0].integer) == 0)
+ {
+ /*
+ * Find the current job on the specified printer...
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * See if there are any pending jobs...
+ */
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
+ if (job->state_value <= IPP_JOB_PROCESSING &&
+ !_cups_strcasecmp(job->dest, printer->name))
+ break;
+
+ if (job)
+ jobid = job->id;
+ else
+ {
+ /*
+ * No, try stopped jobs...
+ */
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
+ if (job->state_value == IPP_JOB_STOPPED &&
+ !_cups_strcasecmp(job->dest, printer->name))
+ break;
+
+ if (job)
+ jobid = job->id;
+ else
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE, _("No active jobs on %s."),
+ printer->name);
+ return;
+ }
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (strncmp(resource, "/jobs/", 6))
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
+ uri->values[0].string.text);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * Look for the "purge-job" attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "purge-job",
+ IPP_TAG_BOOLEAN)) != NULL)
+ purge = attr->values[0].boolean ? CUPSD_JOB_PURGE : CUPSD_JOB_DEFAULT;
+ else
+ purge = CUPSD_JOB_DEFAULT;
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = cupsdFindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(job, con, job->username, username, sizeof(username)))
+ {
+ send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
+ cupsdFindDest(job->dest));
+ return;
+ }
+
+ /*
+ * See if the job is already completed, canceled, or aborted; if so,
+ * we can't cancel...
+ */
+
+ if (job->state_value >= IPP_JOB_CANCELED && purge != CUPSD_JOB_PURGE)
+ {
+ switch (job->state_value)
+ {
+ case IPP_JOB_CANCELED :
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Job #%d is already canceled - can\'t cancel."),
+ jobid);
+ break;
+
+ case IPP_JOB_ABORTED :
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Job #%d is already aborted - can\'t cancel."),
+ jobid);
+ break;
+
+ default :
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Job #%d is already completed - can\'t cancel."),
+ jobid);
+ break;
+ }
+
+ return;
+ }
+
+ /*
+ * Cancel the job and return...
+ */
+
+ cupsdSetJobState(job, IPP_JOB_CANCELED, purge,
+ purge == CUPSD_JOB_PURGE ? "Job purged by \"%s\"" :
+ "Job canceled by \"%s\"",
+ username);
+ cupsdCheckJobs();
+
+ if (purge == CUPSD_JOB_PURGE)
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Purged by \"%s\".", jobid,
+ username);
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Canceled by \"%s\".", jobid,
+ username);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'cancel_subscription()' - Cancel a subscription.
+ */
+
+static void
+cancel_subscription(
+ cupsd_client_t *con, /* I - Client connection */
+ int sub_id) /* I - Subscription ID */
+{
+ http_status_t status; /* Policy status */
+ cupsd_subscription_t *sub; /* Subscription */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cancel_subscription(con=%p[%d], sub_id=%d)",
+ con, con->http.fd, sub_id);
+
+ /*
+ * Is the subscription ID valid?
+ */
+
+ if ((sub = cupsdFindSubscription(sub_id)) == NULL)
+ {
+ /*
+ * Bad subscription ID...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("Subscription #%d does not exist."), sub_id);
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr :
+ DefaultPolicyPtr,
+ con, sub->owner)) != HTTP_OK)
+ {
+ send_http_error(con, status, sub->dest);
+ return;
+ }
+
+ /*
+ * Cancel the subscription...
+ */
+
+ cupsdDeleteSubscription(sub, 1);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'check_rss_recipient()' - Check that we do not have a duplicate RSS feed URI.
+ */
+
+static int /* O - 1 if OK, 0 if not */
+check_rss_recipient(
+ const char *recipient) /* I - Recipient URI */
+{
+ cupsd_subscription_t *sub; /* Current subscription */
+
+
+ for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
+ sub;
+ sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
+ if (sub->recipient)
+ {
+ /*
+ * Compare the URIs up to the first ?...
+ */
+
+ const char *r1, *r2;
+
+ for (r1 = recipient, r2 = sub->recipient;
+ *r1 == *r2 && *r1 && *r1 != '?' && *r2 && *r2 != '?';
+ r1 ++, r2 ++);
+
+ if (*r1 == *r2)
+ return (0);
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'check_quotas()' - Check quotas for a printer and user.
+ */
+
+static int /* O - 1 if OK, 0 if forbidden,
+ -1 if limit reached */
+check_quotas(cupsd_client_t *con, /* I - Client connection */
+ cupsd_printer_t *p) /* I - Printer or class */
+{
+ char username[33], /* Username */
+ *name; /* Current user name */
+ cupsd_quota_t *q; /* Quota data */
+#ifdef HAVE_MBR_UID_TO_UUID
+ /*
+ * Use Apple membership APIs which require that all names represent
+ * valid user account or group records accessible by the server.
+ */
+
+ uuid_t usr_uuid; /* UUID for job requesting user */
+ uuid_t usr2_uuid; /* UUID for ACL user name entry */
+ uuid_t grp_uuid; /* UUID for ACL group name entry */
+ int mbr_err; /* Error from membership function */
+ int is_member; /* Is this user a member? */
+#else
+ /*
+ * Use standard POSIX APIs for checking users and groups...
+ */
+
+ struct passwd *pw; /* User password data */
+#endif /* HAVE_MBR_UID_TO_UUID */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "check_quotas(%p[%d], %p[%s])",
+ con, con->http.fd, p, p->name);
+
+ /*
+ * Figure out who is printing...
+ */
+
+ strlcpy(username, get_username(con), sizeof(username));
+
+ /*
+ * Check global active job limits for printers and users...
+ */
+
+ if (MaxJobsPerPrinter)
+ {
+ /*
+ * Check if there are too many pending jobs on this printer...
+ */
+
+ if (cupsdGetPrinterJobCount(p->name) >= MaxJobsPerPrinter)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "Too many jobs for printer \"%s\"...",
+ p->name);
+ return (-1);
+ }
+ }
+
+ if (MaxJobsPerUser)
+ {
+ /*
+ * Check if there are too many pending jobs for this user...
+ */
+
+ if (cupsdGetUserJobCount(username) >= MaxJobsPerUser)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "Too many jobs for user \"%s\"...",
+ username);
+ return (-1);
+ }
+ }
+
+ /*
+ * Check against users...
+ */
+
+ if (cupsArrayCount(p->users) == 0 && p->k_limit == 0 && p->page_limit == 0)
+ return (1);
+
+ if (cupsArrayCount(p->users))
+ {
+#ifdef HAVE_MBR_UID_TO_UUID
+ /*
+ * Get UUID for job requesting user...
+ */
+
+ if (mbr_user_name_to_uuid((char *)username, usr_uuid))
+ {
+ /*
+ * Unknown user...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "check_quotas: UUID lookup failed for user \"%s\"",
+ username);
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Denying user \"%s\" access to printer \"%s\" "
+ "(unknown user)...",
+ username, p->name);
+ return (0);
+ }
+#else
+ /*
+ * Get UID and GID of requesting user...
+ */
+
+ pw = getpwnam(username);
+ endpwent();
+#endif /* HAVE_MBR_UID_TO_UUID */
+
+ for (name = (char *)cupsArrayFirst(p->users);
+ name;
+ name = (char *)cupsArrayNext(p->users))
+ if (name[0] == '@')
+ {
+ /*
+ * Check group membership...
+ */
+
+#ifdef HAVE_MBR_UID_TO_UUID
+ if (name[1] == '#')
+ {
+ if (uuid_parse(name + 2, grp_uuid))
+ uuid_clear(grp_uuid);
+ }
+ else if ((mbr_err = mbr_group_name_to_uuid(name + 1, grp_uuid)) != 0)
+ {
+ /*
+ * Invalid ACL entries are ignored for matching; just record a
+ * warning in the log...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "check_quotas: UUID lookup failed for ACL entry "
+ "\"%s\" (err=%d)", name, mbr_err);
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Access control entry \"%s\" not a valid group name; "
+ "entry ignored", name);
+ }
+
+ if ((mbr_err = mbr_check_membership(usr_uuid, grp_uuid,
+ &is_member)) != 0)
+ {
+ /*
+ * At this point, there should be no errors, but check anyways...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "check_quotas: group \"%s\" membership check "
+ "failed (err=%d)", name + 1, mbr_err);
+ is_member = 0;
+ }
+
+ /*
+ * Stop if we found a match...
+ */
+
+ if (is_member)
+ break;
+
+#else
+ if (cupsdCheckGroup(username, pw, name + 1))
+ break;
+#endif /* HAVE_MBR_UID_TO_UUID */
+ }
+#ifdef HAVE_MBR_UID_TO_UUID
+ else
+ {
+ if (name[0] == '#')
+ {
+ if (uuid_parse(name + 1, usr2_uuid))
+ uuid_clear(usr2_uuid);
+ }
+ else if ((mbr_err = mbr_user_name_to_uuid(name, usr2_uuid)) != 0)
+ {
+ /*
+ * Invalid ACL entries are ignored for matching; just record a
+ * warning in the log...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "check_quotas: UUID lookup failed for ACL entry "
+ "\"%s\" (err=%d)", name, mbr_err);
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Access control entry \"%s\" not a valid user name; "
+ "entry ignored", name);
+ }
+
+ if (!uuid_compare(usr_uuid, usr2_uuid))
+ break;
+ }
+#else
+ else if (!_cups_strcasecmp(username, name))
+ break;
+#endif /* HAVE_MBR_UID_TO_UUID */
+
+ if ((name != NULL) == p->deny_users)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Denying user \"%s\" access to printer \"%s\"...",
+ username, p->name);
+ return (0);
+ }
+ }
+
+ /*
+ * Check quotas...
+ */
+
+ if (p->k_limit || p->page_limit)
+ {
+ if ((q = cupsdUpdateQuota(p, username, 0, 0)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate quota data for user \"%s\"",
+ username);
+ return (-1);
+ }
+
+ if ((q->k_count >= p->k_limit && p->k_limit) ||
+ (q->page_count >= p->page_limit && p->page_limit))
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "User \"%s\" is over the quota limit...",
+ username);
+ return (-1);
+ }
+ }
+
+ /*
+ * If we have gotten this far, we're done!
+ */
+
+ return (1);
+}
+
+
+/*
+ * 'close_job()' - Close a multi-file job.
+ */
+
+static void
+close_job(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ cupsd_job_t *job; /* Job */
+ ipp_attribute_t *attr; /* Attribute */
+ char job_uri[HTTP_MAX_URI],
+ /* Job URI */
+ username[256]; /* User name */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "close_job(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (strcmp(uri->name, "printer-uri"))
+ {
+ /*
+ * job-uri is not supported by Close-Job!
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Close-Job doesn't support the job-uri attribute."));
+ return;
+ }
+
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Got a printer-uri attribute but no job-id."));
+ return;
+ }
+
+ if ((job = cupsdFindJob(attr->values[0].integer)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
+ attr->values[0].integer);
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(job, con, job->username, username, sizeof(username)))
+ {
+ send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
+ cupsdFindDest(job->dest));
+ return;
+ }
+
+ /*
+ * Add any ending sheet...
+ */
+
+ if (cupsdTimeoutJob(job))
+ return;
+
+ if (job->state_value == IPP_JOB_STOPPED)
+ {
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ job->state_value = IPP_JOB_PENDING;
+ }
+ else if (job->state_value == IPP_JOB_HELD)
+ {
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
+ IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+
+ if (!attr || !strcmp(attr->values[0].string.text, "no-hold"))
+ {
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ job->state_value = IPP_JOB_PENDING;
+ }
+ }
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+
+ /*
+ * Fill in the response info...
+ */
+
+ snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName,
+ LocalPort, job->id);
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL,
+ job_uri);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state",
+ job->state_value);
+
+ add_job_state_reasons(con, job);
+
+ con->response->request.status.status_code = IPP_OK;
+
+ /*
+ * Start the job if necessary...
+ */
+
+ cupsdCheckJobs();
+}
+
+
+/*
+ * 'copy_attribute()' - Copy a single attribute.
+ */
+
+static ipp_attribute_t * /* O - New attribute */
+copy_attribute(
+ ipp_t *to, /* O - Destination request/response */
+ ipp_attribute_t *attr, /* I - Attribute to copy */
+ int quickcopy) /* I - Do a quick copy? */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *toattr; /* Destination attribute */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "copy_attribute(%p, %p[%s,%x,%x])", to, attr,
+ attr->name ? attr->name : "(null)", attr->group_tag,
+ attr->value_tag);
+
+ switch (attr->value_tag & ~IPP_TAG_COPY)
+ {
+ case IPP_TAG_ZERO :
+ toattr = ippAddSeparator(to);
+ break;
+
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ toattr = ippAddIntegers(to, attr->group_tag, attr->value_tag,
+ attr->name, attr->num_values, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].integer = attr->values[i].integer;
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ toattr = ippAddBooleans(to, attr->group_tag, attr->name,
+ attr->num_values, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].boolean = attr->values[i].boolean;
+ break;
+
+ case IPP_TAG_STRING :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ toattr = ippAddStrings(to, attr->group_tag,
+ (ipp_tag_t)(attr->value_tag | quickcopy),
+ attr->name, attr->num_values, NULL, NULL);
+
+ if (quickcopy)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].string.text = attr->values[i].string.text;
+ }
+ else if (attr->value_tag & IPP_TAG_COPY)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].string.text =
+ _cupsStrAlloc(attr->values[i].string.text);
+ }
+ else
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].string.text =
+ _cupsStrRetain(attr->values[i].string.text);
+ }
+ break;
+
+ case IPP_TAG_DATE :
+ toattr = ippAddDate(to, attr->group_tag, attr->name,
+ attr->values[0].date);
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ toattr = ippAddResolutions(to, attr->group_tag, attr->name,
+ attr->num_values, IPP_RES_PER_INCH,
+ NULL, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].resolution.xres = attr->values[i].resolution.xres;
+ toattr->values[i].resolution.yres = attr->values[i].resolution.yres;
+ toattr->values[i].resolution.units = attr->values[i].resolution.units;
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ toattr = ippAddRanges(to, attr->group_tag, attr->name,
+ attr->num_values, NULL, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].range.lower = attr->values[i].range.lower;
+ toattr->values[i].range.upper = attr->values[i].range.upper;
+ }
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ toattr = ippAddStrings(to, attr->group_tag,
+ (ipp_tag_t)(attr->value_tag | quickcopy),
+ attr->name, attr->num_values, NULL, NULL);
+
+ if (quickcopy)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].string.charset = attr->values[i].string.charset;
+ toattr->values[i].string.text = attr->values[i].string.text;
+ }
+ }
+ else if (attr->value_tag & IPP_TAG_COPY)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (!i)
+ toattr->values[i].string.charset =
+ _cupsStrAlloc(attr->values[i].string.charset);
+ else
+ toattr->values[i].string.charset =
+ toattr->values[0].string.charset;
+
+ toattr->values[i].string.text =
+ _cupsStrAlloc(attr->values[i].string.text);
+ }
+ }
+ else
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (!i)
+ toattr->values[i].string.charset =
+ _cupsStrRetain(attr->values[i].string.charset);
+ else
+ toattr->values[i].string.charset =
+ toattr->values[0].string.charset;
+
+ toattr->values[i].string.text =
+ _cupsStrRetain(attr->values[i].string.text);
+ }
+ }
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ toattr = ippAddCollections(to, attr->group_tag, attr->name,
+ attr->num_values, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].collection = attr->values[i].collection;
+ attr->values[i].collection->use ++;
+ }
+ break;
+
+ default :
+ toattr = ippAddIntegers(to, attr->group_tag, attr->value_tag,
+ attr->name, attr->num_values, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].unknown.length = attr->values[i].unknown.length;
+
+ if (toattr->values[i].unknown.length > 0)
+ {
+ if ((toattr->values[i].unknown.data =
+ malloc(toattr->values[i].unknown.length)) == NULL)
+ toattr->values[i].unknown.length = 0;
+ else
+ memcpy(toattr->values[i].unknown.data,
+ attr->values[i].unknown.data,
+ toattr->values[i].unknown.length);
+ }
+ }
+ break; /* anti-compiler-warning-code */
+ }
+
+ return (toattr);
+}
+
+
+/*
+ * 'copy_attrs()' - Copy attributes from one request to another.
+ */
+
+static void
+copy_attrs(ipp_t *to, /* I - Destination request */
+ ipp_t *from, /* I - Source request */
+ cups_array_t *ra, /* I - Requested attributes */
+ ipp_tag_t group, /* I - Group to copy */
+ int quickcopy, /* I - Do a quick copy? */
+ cups_array_t *exclude) /* I - Attributes to exclude? */
+{
+ ipp_attribute_t *fromattr; /* Source attribute */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "copy_attrs(to=%p, from=%p, ra=%p, group=%x, quickcopy=%d)",
+ to, from, ra, group, quickcopy);
+
+ if (!to || !from)
+ return;
+
+ for (fromattr = from->attrs; fromattr; fromattr = fromattr->next)
+ {
+ /*
+ * Filter attributes as needed...
+ */
+
+ if ((group != IPP_TAG_ZERO && fromattr->group_tag != group &&
+ fromattr->group_tag != IPP_TAG_ZERO) || !fromattr->name)
+ continue;
+
+ if (!strcmp(fromattr->name, "job-printer-uri"))
+ continue;
+
+ if (exclude &&
+ (cupsArrayFind(exclude, fromattr->name) ||
+ cupsArrayFind(exclude, "all")))
+ {
+ /*
+ * We need to exclude this attribute for security reasons; we require the
+ * job-id attribute regardless of the security settings for IPP
+ * conformance.
+ *
+ * The job-printer-uri attribute is handled by copy_job_attrs().
+ *
+ * Subscription attribute security is handled by copy_subscription_attrs().
+ */
+
+ if (strcmp(fromattr->name, "job-id"))
+ continue;
+ }
+
+ if (!ra || cupsArrayFind(ra, fromattr->name))
+ {
+ /*
+ * Don't send collection attributes by default to IPP/1.x clients
+ * since many do not support collections. Also don't send
+ * media-col-database unless specifically requested by the client.
+ */
+
+ if (fromattr->value_tag == IPP_TAG_BEGIN_COLLECTION &&
+ !ra &&
+ (to->request.status.version[0] == 1 ||
+ !strcmp(fromattr->name, "media-col-database")))
+ continue;
+
+ copy_attribute(to, fromattr, quickcopy);
+ }
+ }
+}
+
+
+/*
+ * 'copy_banner()' - Copy a banner file to the requests directory for the
+ * specified job.
+ */
+
+static int /* O - Size of banner file in kbytes */
+copy_banner(cupsd_client_t *con, /* I - Client connection */
+ cupsd_job_t *job, /* I - Job information */
+ const char *name) /* I - Name of banner */
+{
+ int i; /* Looping var */
+ int kbytes; /* Size of banner file in kbytes */
+ char filename[1024]; /* Job filename */
+ cupsd_banner_t *banner; /* Pointer to banner */
+ cups_file_t *in; /* Input file */
+ cups_file_t *out; /* Output file */
+ int ch; /* Character from file */
+ char attrname[255], /* Name of attribute */
+ *s; /* Pointer into name */
+ ipp_attribute_t *attr; /* Attribute */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "copy_banner(con=%p[%d], job=%p[%d], name=\"%s\")",
+ con, con ? con->http.fd : -1, job, job->id,
+ name ? name : "(null)");
+
+ /*
+ * Find the banner; return if not found or "none"...
+ */
+
+ if (!name || !strcmp(name, "none") ||
+ (banner = cupsdFindBanner(name)) == NULL)
+ return (0);
+
+ /*
+ * Open the banner and job files...
+ */
+
+ if (add_file(con, job, banner->filetype, 0))
+ return (-1);
+
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id,
+ job->num_files);
+ if ((out = cupsFileOpen(filename, "w")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create banner job file %s - %s",
+ filename, strerror(errno));
+ job->num_files --;
+ return (0);
+ }
+
+ fchmod(cupsFileNumber(out), 0640);
+ fchown(cupsFileNumber(out), RunUser, Group);
+
+ /*
+ * Try the localized banner file under the subdirectory...
+ */
+
+ strlcpy(attrname, job->attrs->attrs->next->values[0].string.text,
+ sizeof(attrname));
+ if (strlen(attrname) > 2 && attrname[2] == '-')
+ {
+ /*
+ * Convert ll-cc to ll_CC...
+ */
+
+ attrname[2] = '_';
+ attrname[3] = toupper(attrname[3] & 255);
+ attrname[4] = toupper(attrname[4] & 255);
+ }
+
+ snprintf(filename, sizeof(filename), "%s/banners/%s/%s", DataDir,
+ attrname, name);
+
+ if (access(filename, 0) && strlen(attrname) > 2)
+ {
+ /*
+ * Wasn't able to find "ll_CC" locale file; try the non-national
+ * localization banner directory.
+ */
+
+ attrname[2] = '\0';
+
+ snprintf(filename, sizeof(filename), "%s/banners/%s/%s", DataDir,
+ attrname, name);
+ }
+
+ if (access(filename, 0))
+ {
+ /*
+ * Use the non-localized banner file.
+ */
+
+ snprintf(filename, sizeof(filename), "%s/banners/%s", DataDir, name);
+ }
+
+ if ((in = cupsFileOpen(filename, "r")) == NULL)
+ {
+ cupsFileClose(out);
+ unlink(filename);
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to open banner template file %s - %s",
+ filename, strerror(errno));
+ job->num_files --;
+ return (0);
+ }
+
+ /*
+ * Parse the file to the end...
+ */
+
+ while ((ch = cupsFileGetChar(in)) != EOF)
+ if (ch == '{')
+ {
+ /*
+ * Get an attribute name...
+ */
+
+ for (s = attrname; (ch = cupsFileGetChar(in)) != EOF;)
+ if (!isalpha(ch & 255) && ch != '-' && ch != '?')
+ break;
+ else if (s < (attrname + sizeof(attrname) - 1))
+ *s++ = ch;
+ else
+ break;
+
+ *s = '\0';
+
+ if (ch != '}')
+ {
+ /*
+ * Ignore { followed by stuff that is not an attribute name...
+ */
+
+ cupsFilePrintf(out, "{%s%c", attrname, ch);
+ continue;
+ }
+
+ /*
+ * See if it is defined...
+ */
+
+ if (attrname[0] == '?')
+ s = attrname + 1;
+ else
+ s = attrname;
+
+ if (!strcmp(s, "printer-name"))
+ {
+ cupsFilePuts(out, job->dest);
+ continue;
+ }
+ else if ((attr = ippFindAttribute(job->attrs, s, IPP_TAG_ZERO)) == NULL)
+ {
+ /*
+ * See if we have a leading question mark...
+ */
+
+ if (attrname[0] != '?')
+ {
+ /*
+ * Nope, write to file as-is; probably a PostScript procedure...
+ */
+
+ cupsFilePrintf(out, "{%s}", attrname);
+ }
+
+ continue;
+ }
+
+ /*
+ * Output value(s)...
+ */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (i)
+ cupsFilePutChar(out, ',');
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ if (!strncmp(s, "time-at-", 8))
+ {
+ struct timeval tv; /* Time value */
+
+ tv.tv_sec = attr->values[i].integer;
+ tv.tv_usec = 0;
+
+ cupsFilePuts(out, cupsdGetDateTime(&tv, CUPSD_TIME_STANDARD));
+ }
+ else
+ cupsFilePrintf(out, "%d", attr->values[i].integer);
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ cupsFilePrintf(out, "%d", attr->values[i].boolean);
+ break;
+
+ case IPP_TAG_NOVALUE :
+ cupsFilePuts(out, "novalue");
+ break;
+
+ case IPP_TAG_RANGE :
+ cupsFilePrintf(out, "%d-%d", attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ cupsFilePrintf(out, "%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 :
+ case IPP_TAG_STRING :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ if (!_cups_strcasecmp(banner->filetype->type, "postscript"))
+ {
+ /*
+ * Need to quote strings for PS banners...
+ */
+
+ const char *p;
+
+ for (p = attr->values[i].string.text; *p; p ++)
+ {
+ if (*p == '(' || *p == ')' || *p == '\\')
+ {
+ cupsFilePutChar(out, '\\');
+ cupsFilePutChar(out, *p);
+ }
+ else if (*p < 32 || *p > 126)
+ cupsFilePrintf(out, "\\%03o", *p & 255);
+ else
+ cupsFilePutChar(out, *p);
+ }
+ }
+ else
+ cupsFilePuts(out, attr->values[i].string.text);
+ break;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+ }
+ }
+ else if (ch == '\\') /* Quoted char */
+ {
+ ch = cupsFileGetChar(in);
+
+ if (ch != '{') /* Only do special handling for \{ */
+ cupsFilePutChar(out, '\\');
+
+ cupsFilePutChar(out, ch);
+ }
+ else
+ cupsFilePutChar(out, ch);
+
+ cupsFileClose(in);
+
+ kbytes = (cupsFileTell(out) + 1023) / 1024;
+
+ if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
+ IPP_TAG_INTEGER)) != NULL)
+ attr->values[0].integer += kbytes;
+
+ cupsFileClose(out);
+
+ return (kbytes);
+}
+
+
+/*
+ * 'copy_file()' - Copy a PPD file or interface script...
+ */
+
+static int /* O - 0 = success, -1 = error */
+copy_file(const char *from, /* I - Source file */
+ const char *to) /* I - Destination file */
+{
+ cups_file_t *src, /* Source file */
+ *dst; /* Destination file */
+ int bytes; /* Bytes to read/write */
+ char buffer[2048]; /* Copy buffer */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_file(\"%s\", \"%s\")", from, to);
+
+ /*
+ * Open the source and destination file for a copy...
+ */
+
+ if ((src = cupsFileOpen(from, "rb")) == NULL)
+ return (-1);
+
+ if ((dst = cupsFileOpen(to, "wb")) == NULL)
+ {
+ cupsFileClose(src);
+ return (-1);
+ }
+
+ /*
+ * Copy the source file to the destination...
+ */
+
+ while ((bytes = cupsFileRead(src, buffer, sizeof(buffer))) > 0)
+ if (cupsFileWrite(dst, buffer, bytes) < bytes)
+ {
+ cupsFileClose(src);
+ cupsFileClose(dst);
+ return (-1);
+ }
+
+ /*
+ * Close both files and return...
+ */
+
+ cupsFileClose(src);
+
+ return (cupsFileClose(dst));
+}
+
+
+/*
+ * 'copy_model()' - Copy a PPD model file, substituting default values
+ * as needed...
+ */
+
+static int /* O - 0 = success, -1 = error */
+copy_model(cupsd_client_t *con, /* I - Client connection */
+ const char *from, /* I - Source file */
+ const char *to) /* I - Destination file */
+{
+ fd_set input; /* select() input set */
+ struct timeval timeout; /* select() timeout */
+ int maxfd; /* Max file descriptor for select() */
+ char tempfile[1024]; /* Temporary PPD file */
+ int tempfd; /* Temporary PPD file descriptor */
+ int temppid; /* Process ID of cups-driverd */
+ int temppipe[2]; /* Temporary pipes */
+ char *argv[4], /* Command-line arguments */
+ *envp[MAX_ENV]; /* Environment */
+ cups_file_t *src, /* Source file */
+ *dst; /* Destination file */
+ ppd_file_t *ppd; /* PPD file */
+ int bytes, /* Bytes from pipe */
+ total; /* Total bytes from pipe */
+ char buffer[2048]; /* Copy buffer */
+ int i; /* Looping var */
+ char option[PPD_MAX_NAME], /* Option name */
+ choice[PPD_MAX_NAME]; /* Choice name */
+ ppd_size_t *size; /* Default size */
+ int num_defaults; /* Number of default options */
+ cups_option_t *defaults; /* Default options */
+ char cups_protocol[PPD_MAX_LINE];
+ /* cupsProtocol attribute */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "copy_model(con=%p, from=\"%s\", to=\"%s\")",
+ con, from, to);
+
+ /*
+ * Run cups-driverd to get the PPD file...
+ */
+
+ argv[0] = "cups-driverd";
+ argv[1] = "cat";
+ argv[2] = (char *)from;
+ argv[3] = NULL;
+
+ cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
+
+ snprintf(buffer, sizeof(buffer), "%s/daemon/cups-driverd", ServerBin);
+ snprintf(tempfile, sizeof(tempfile), "%s/%d.ppd", TempDir, con->http.fd);
+ tempfd = open(tempfile, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (tempfd < 0 || cupsdOpenPipe(temppipe))
+ return (-1);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "copy_model: Running \"cups-driverd cat %s\"...", from);
+
+ if (!cupsdStartProcess(buffer, argv, envp, -1, temppipe[1], CGIPipes[1],
+ -1, -1, 0, DefaultProfile, NULL, &temppid))
+ {
+ close(tempfd);
+ unlink(tempfile);
+
+ return (-1);
+ }
+
+ close(temppipe[1]);
+
+ /*
+ * Wait up to 30 seconds for the PPD file to be copied...
+ */
+
+ total = 0;
+
+ if (temppipe[0] > CGIPipes[0])
+ maxfd = temppipe[0] + 1;
+ else
+ maxfd = CGIPipes[0] + 1;
+
+ for (;;)
+ {
+ /*
+ * See if we have data ready...
+ */
+
+ FD_ZERO(&input);
+ FD_SET(temppipe[0], &input);
+ FD_SET(CGIPipes[0], &input);
+
+ timeout.tv_sec = 30;
+ timeout.tv_usec = 0;
+
+ if ((i = select(maxfd, &input, NULL, NULL, &timeout)) < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ else
+ break;
+ }
+ else if (i == 0)
+ {
+ /*
+ * We have timed out...
+ */
+
+ break;
+ }
+
+ if (FD_ISSET(temppipe[0], &input))
+ {
+ /*
+ * Read the PPD file from the pipe, and write it to the PPD file.
+ */
+
+ if ((bytes = read(temppipe[0], buffer, sizeof(buffer))) > 0)
+ {
+ if (write(tempfd, buffer, bytes) < bytes)
+ break;
+
+ total += bytes;
+ }
+ else
+ break;
+ }
+
+ if (FD_ISSET(CGIPipes[0], &input))
+ cupsdUpdateCGI();
+ }
+
+ close(temppipe[0]);
+ close(tempfd);
+
+ if (!total)
+ {
+ /*
+ * No data from cups-deviced...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "copy_model: empty PPD file");
+ unlink(tempfile);
+ return (-1);
+ }
+
+ /*
+ * Read the source file and see what page sizes are supported...
+ */
+
+ if ((ppd = ppdOpenFile(tempfile)) == NULL)
+ {
+ unlink(tempfile);
+ return (-1);
+ }
+
+ /*
+ * Open the destination (if possible) and set the default options...
+ */
+
+ num_defaults = 0;
+ defaults = NULL;
+ cups_protocol[0] = '\0';
+
+ if ((dst = cupsFileOpen(to, "rb")) != NULL)
+ {
+ /*
+ * Read all of the default lines from the old PPD...
+ */
+
+ while (cupsFileGets(dst, buffer, sizeof(buffer)))
+ if (!strncmp(buffer, "*Default", 8))
+ {
+ /*
+ * Add the default option...
+ */
+
+ if (!ppd_parse_line(buffer, option, sizeof(option),
+ choice, sizeof(choice)))
+ {
+ ppd_option_t *ppdo; /* PPD option */
+
+
+ /*
+ * Only add the default if the default hasn't already been
+ * set and the choice exists in the new PPD...
+ */
+
+ if (!cupsGetOption(option, num_defaults, defaults) &&
+ (ppdo = ppdFindOption(ppd, option)) != NULL &&
+ ppdFindChoice(ppdo, choice))
+ num_defaults = cupsAddOption(option, choice, num_defaults,
+ &defaults);
+ }
+ }
+ else if (!strncmp(buffer, "*cupsProtocol:", 14))
+ strlcpy(cups_protocol, buffer, sizeof(cups_protocol));
+
+ cupsFileClose(dst);
+ }
+ else if ((size = ppdPageSize(ppd, DefaultPaperSize)) != NULL)
+ {
+ /*
+ * Add the default media sizes...
+ */
+
+ num_defaults = cupsAddOption("PageSize", size->name,
+ num_defaults, &defaults);
+ num_defaults = cupsAddOption("PageRegion", size->name,
+ num_defaults, &defaults);
+ num_defaults = cupsAddOption("PaperDimension", size->name,
+ num_defaults, &defaults);
+ num_defaults = cupsAddOption("ImageableArea", size->name,
+ num_defaults, &defaults);
+ }
+
+ ppdClose(ppd);
+
+ /*
+ * Open the source file for a copy...
+ */
+
+ if ((src = cupsFileOpen(tempfile, "rb")) == NULL)
+ {
+ cupsFreeOptions(num_defaults, defaults);
+ unlink(tempfile);
+ return (-1);
+ }
+
+ /*
+ * Open the destination file for a copy...
+ */
+
+ if ((dst = cupsFileOpen(to, "wb")) == NULL)
+ {
+ cupsFreeOptions(num_defaults, defaults);
+ cupsFileClose(src);
+ unlink(tempfile);
+ return (-1);
+ }
+
+ /*
+ * Copy the source file to the destination...
+ */
+
+ while (cupsFileGets(src, buffer, sizeof(buffer)))
+ {
+ if (!strncmp(buffer, "*Default", 8))
+ {
+ /*
+ * Check for an previous default option choice...
+ */
+
+ if (!ppd_parse_line(buffer, option, sizeof(option),
+ choice, sizeof(choice)))
+ {
+ const char *val; /* Default option value */
+
+
+ if ((val = cupsGetOption(option, num_defaults, defaults)) != NULL)
+ {
+ /*
+ * Substitute the previous choice...
+ */
+
+ snprintf(buffer, sizeof(buffer), "*Default%s: %s", option, val);
+ }
+ }
+ }
+
+ cupsFilePrintf(dst, "%s\n", buffer);
+ }
+
+ if (cups_protocol[0])
+ cupsFilePrintf(dst, "%s\n", cups_protocol);
+
+ cupsFreeOptions(num_defaults, defaults);
+
+ /*
+ * Close both files and return...
+ */
+
+ cupsFileClose(src);
+
+ unlink(tempfile);
+
+ return (cupsFileClose(dst));
+}
+
+
+/*
+ * 'copy_job_attrs()' - Copy job attributes.
+ */
+
+static void
+copy_job_attrs(cupsd_client_t *con, /* I - Client connection */
+ cupsd_job_t *job, /* I - Job */
+ cups_array_t *ra, /* I - Requested attributes array */
+ cups_array_t *exclude) /* I - Private attributes array */
+{
+ char job_uri[HTTP_MAX_URI]; /* Job URI */
+
+
+ /*
+ * Send the requested attributes for each job...
+ */
+
+ if (!cupsArrayFind(exclude, "all"))
+ {
+ if ((!exclude || !cupsArrayFind(exclude, "document-count")) &&
+ (!ra || cupsArrayFind(ra, "document-count")))
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "document-count", job->num_files);
+
+ if ((!exclude || !cupsArrayFind(exclude, "job-media-progress")) &&
+ (!ra || cupsArrayFind(ra, "job-media-progress")))
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "job-media-progress", job->progress);
+
+ if ((!exclude || !cupsArrayFind(exclude, "job-more-info")) &&
+ (!ra || cupsArrayFind(ra, "job-more-info")))
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "http",
+ NULL, con->servername, con->serverport, "/jobs/%d",
+ job->id);
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
+ "job-more-info", NULL, job_uri);
+ }
+
+ if (job->state_value > IPP_JOB_PROCESSING &&
+ (!exclude || !cupsArrayFind(exclude, "job-preserved")) &&
+ (!ra || cupsArrayFind(ra, "job-preserved")))
+ ippAddBoolean(con->response, IPP_TAG_JOB, "job-preserved",
+ job->num_files > 0);
+
+ if ((!exclude || !cupsArrayFind(exclude, "job-printer-up-time")) &&
+ (!ra || cupsArrayFind(ra, "job-printer-up-time")))
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "job-printer-up-time", time(NULL));
+ }
+
+ if (!ra || cupsArrayFind(ra, "job-printer-uri"))
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL,
+ con->servername, con->serverport,
+ job->dtype & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS) ?
+ "/classes/%s" : "/printers/%s",
+ job->dest);
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
+ "job-printer-uri", NULL, job_uri);
+ }
+
+ if (!ra || cupsArrayFind(ra, "job-state-reasons"))
+ add_job_state_reasons(con, job);
+
+ if (!ra || cupsArrayFind(ra, "job-uri"))
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL,
+ con->servername, con->serverport, "/jobs/%d",
+ job->id);
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
+ "job-uri", NULL, job_uri);
+ }
+
+ copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0, exclude);
+}
+
+
+/*
+ * 'copy_printer_attrs()' - Copy printer attributes.
+ */
+
+static void
+copy_printer_attrs(
+ cupsd_client_t *con, /* I - Client connection */
+ cupsd_printer_t *printer, /* I - Printer */
+ cups_array_t *ra) /* I - Requested attributes array */
+{
+ char printer_uri[HTTP_MAX_URI];
+ /* Printer URI */
+ char printer_icons[HTTP_MAX_URI];
+ /* Printer icons */
+ time_t curtime; /* Current time */
+ int i; /* Looping var */
+
+
+ /*
+ * Copy the printer attributes to the response using requested-attributes
+ * and document-format attributes that may be provided by the client.
+ */
+
+ curtime = time(NULL);
+
+ if (!ra || cupsArrayFind(ra, "marker-change-time"))
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "marker-change-time", printer->marker_time);
+
+ if (printer->num_printers > 0 &&
+ (!ra || cupsArrayFind(ra, "member-uris")))
+ {
+ ipp_attribute_t *member_uris; /* member-uris attribute */
+ cupsd_printer_t *p2; /* Printer in class */
+ ipp_attribute_t *p2_uri; /* printer-uri-supported for class printer */
+
+
+ if ((member_uris = ippAddStrings(con->response, IPP_TAG_PRINTER,
+ IPP_TAG_URI, "member-uris",
+ printer->num_printers, NULL,
+ NULL)) != NULL)
+ {
+ for (i = 0; i < printer->num_printers; i ++)
+ {
+ p2 = printer->printers[i];
+
+ if ((p2_uri = ippFindAttribute(p2->attrs, "printer-uri-supported",
+ IPP_TAG_URI)) != NULL)
+ member_uris->values[i].string.text =
+ _cupsStrRetain(p2_uri->values[0].string.text);
+ else
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri,
+ sizeof(printer_uri), "ipp", NULL, con->servername,
+ con->serverport,
+ (p2->type & CUPS_PRINTER_CLASS) ?
+ "/classes/%s" : "/printers/%s", p2->name);
+ member_uris->values[i].string.text = _cupsStrAlloc(printer_uri);
+ }
+ }
+ }
+ }
+
+ if (printer->alert && (!ra || cupsArrayFind(ra, "printer-alert")))
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_STRING,
+ "printer-alert", NULL, printer->alert);
+
+ if (printer->alert_description &&
+ (!ra || cupsArrayFind(ra, "printer-alert-description")))
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-alert-description", NULL,
+ printer->alert_description);
+
+ if (!ra || cupsArrayFind(ra, "printer-current-time"))
+ ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time",
+ ippTimeToDate(curtime));
+
+#ifdef HAVE_DNSSD
+ if (!ra || cupsArrayFind(ra, "printer-dns-sd-name"))
+ {
+ if (printer->reg_name)
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "printer-dns-sd-name", NULL, printer->reg_name);
+ else
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_NOVALUE,
+ "printer-dns-sd-name", 0);
+ }
+#endif /* HAVE_DNSSD */
+
+ if (!ra || cupsArrayFind(ra, "printer-error-policy"))
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "printer-error-policy", NULL, printer->error_policy);
+
+ if (!ra || cupsArrayFind(ra, "printer-error-policy-supported"))
+ {
+ static const char * const errors[] =/* printer-error-policy-supported values */
+ {
+ "abort-job",
+ "retry-current-job",
+ "retry-job",
+ "stop-printer"
+ };
+
+ if (printer->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS))
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
+ "printer-error-policy-supported", NULL, "retry-current-job");
+ else
+ ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
+ "printer-error-policy-supported",
+ sizeof(errors) / sizeof(errors[0]), NULL, errors);
+ }
+
+ if (!ra || cupsArrayFind(ra, "printer-icons"))
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, printer_icons, sizeof(printer_icons),
+ "http", NULL, con->servername, con->serverport,
+ "/icons/%s.png", printer->name);
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-icons",
+ NULL, printer_icons);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-icons=\"%s\"", printer_icons);
+ }
+
+ if (!ra || cupsArrayFind(ra, "printer-is-accepting-jobs"))
+ ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs",
+ printer->accepting);
+
+ if (!ra || cupsArrayFind(ra, "printer-is-shared"))
+ ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-shared",
+ printer->shared);
+
+ if ((!ra || cupsArrayFind(ra, "printer-more-info")) &&
+ !(printer->type & CUPS_PRINTER_DISCOVERED))
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
+ "http", NULL, con->servername, con->serverport,
+ (printer->type & CUPS_PRINTER_CLASS) ?
+ "/classes/%s" : "/printers/%s", printer->name);
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "printer-more-info", NULL, printer_uri);
+ }
+
+ if (!ra || cupsArrayFind(ra, "printer-op-policy"))
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "printer-op-policy", NULL, printer->op_policy);
+
+ if (!ra || cupsArrayFind(ra, "printer-state"))
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
+ printer->state);
+
+ if (!ra || cupsArrayFind(ra, "printer-state-change-time"))
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "printer-state-change-time", printer->state_time);
+
+ if (!ra || cupsArrayFind(ra, "printer-state-message"))
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-state-message", NULL, printer->state_message);
+
+ if (!ra || cupsArrayFind(ra, "printer-state-reasons"))
+ add_printer_state_reasons(con, printer);
+
+ if (!ra || cupsArrayFind(ra, "printer-type"))
+ {
+ int type; /* printer-type value */
+
+ /*
+ * Add the CUPS-specific printer-type attribute...
+ */
+
+ type = printer->type;
+
+ if (printer == DefaultPrinter)
+ type |= CUPS_PRINTER_DEFAULT;
+
+ if (!printer->accepting)
+ type |= CUPS_PRINTER_REJECTING;
+
+ if (!printer->shared)
+ type |= CUPS_PRINTER_NOT_SHARED;
+
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type",
+ type);
+ }
+
+ if (!ra || cupsArrayFind(ra, "printer-up-time"))
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "printer-up-time", curtime);
+
+ if ((!ra || cupsArrayFind(ra, "printer-uri-supported")) &&
+ !(printer->type & CUPS_PRINTER_DISCOVERED))
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
+ "ipp", NULL, con->servername, con->serverport,
+ (printer->type & CUPS_PRINTER_CLASS) ?
+ "/classes/%s" : "/printers/%s", printer->name);
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "printer-uri-supported", NULL, printer_uri);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-uri-supported=\"%s\"",
+ printer_uri);
+ }
+
+ if (!ra || cupsArrayFind(ra, "queued-job-count"))
+ add_queued_job_count(con, printer);
+
+ copy_attrs(con->response, printer->attrs, ra, IPP_TAG_ZERO, 0, NULL);
+ if (printer->ppd_attrs)
+ copy_attrs(con->response, printer->ppd_attrs, ra, IPP_TAG_ZERO, 0, NULL);
+ copy_attrs(con->response, CommonData, ra, IPP_TAG_ZERO, IPP_TAG_COPY, NULL);
+}
+
+
+/*
+ * 'copy_subscription_attrs()' - Copy subscription attributes.
+ */
+
+static void
+copy_subscription_attrs(
+ cupsd_client_t *con, /* I - Client connection */
+ cupsd_subscription_t *sub, /* I - Subscription */
+ cups_array_t *ra, /* I - Requested attributes array */
+ cups_array_t *exclude) /* I - Private attributes array */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ char printer_uri[HTTP_MAX_URI];
+ /* Printer URI */
+ int count; /* Number of events */
+ unsigned mask; /* Current event mask */
+ const char *name; /* Current event name */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "copy_subscription_attrs(con=%p, sub=%p, ra=%p, exclude=%p)",
+ con, sub, ra, exclude);
+
+ /*
+ * Copy the subscription attributes to the response using the
+ * requested-attributes attribute that may be provided by the client.
+ */
+
+ if (!exclude || !cupsArrayFind(exclude, "all"))
+ {
+ if ((!exclude || !cupsArrayFind(exclude, "notify-events")) &&
+ (!ra || cupsArrayFind(ra, "notify-events")))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_subscription_attrs: notify-events");
+
+ if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL)
+ {
+ /*
+ * Simple event list...
+ */
+
+ ippAddString(con->response, IPP_TAG_SUBSCRIPTION,
+ (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY),
+ "notify-events", NULL, name);
+ }
+ else
+ {
+ /*
+ * Complex event list...
+ */
+
+ for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1)
+ if (sub->mask & mask)
+ count ++;
+
+ attr = ippAddStrings(con->response, IPP_TAG_SUBSCRIPTION,
+ (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY),
+ "notify-events", count, NULL, NULL);
+
+ for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1)
+ if (sub->mask & mask)
+ {
+ attr->values[count].string.text =
+ (char *)cupsdEventName((cupsd_eventmask_t)mask);
+
+ count ++;
+ }
+ }
+ }
+
+ if ((!exclude || !cupsArrayFind(exclude, "notify-lease-duration")) &&
+ (!sub->job && (!ra || cupsArrayFind(ra, "notify-lease-duration"))))
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+ "notify-lease-duration", sub->lease);
+
+ if ((!exclude || !cupsArrayFind(exclude, "notify-recipient-uri")) &&
+ (sub->recipient && (!ra || cupsArrayFind(ra, "notify-recipient-uri"))))
+ ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
+ "notify-recipient-uri", NULL, sub->recipient);
+ else if ((!exclude || !cupsArrayFind(exclude, "notify-pull-method")) &&
+ (!ra || cupsArrayFind(ra, "notify-pull-method")))
+ ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
+ "notify-pull-method", NULL, "ippget");
+
+ if ((!exclude || !cupsArrayFind(exclude, "notify-subscriber-user-name")) &&
+ (!ra || cupsArrayFind(ra, "notify-subscriber-user-name")))
+ ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_NAME,
+ "notify-subscriber-user-name", NULL, sub->owner);
+
+ if ((!exclude || !cupsArrayFind(exclude, "notify-time-interval")) &&
+ (!ra || cupsArrayFind(ra, "notify-time-interval")))
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+ "notify-time-interval", sub->interval);
+
+ if (sub->user_data_len > 0 &&
+ (!exclude || !cupsArrayFind(exclude, "notify-user-data")) &&
+ (!ra || cupsArrayFind(ra, "notify-user-data")))
+ ippAddOctetString(con->response, IPP_TAG_SUBSCRIPTION, "notify-user-data",
+ sub->user_data, sub->user_data_len);
+ }
+
+ if (sub->job && (!ra || cupsArrayFind(ra, "notify-job-id")))
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+ "notify-job-id", sub->job->id);
+
+ if (sub->dest && (!ra || cupsArrayFind(ra, "notify-printer-uri")))
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
+ "ipp", NULL, con->servername, con->serverport,
+ "/printers/%s", sub->dest->name);
+ ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
+ "notify-printer-uri", NULL, printer_uri);
+ }
+
+ if (!ra || cupsArrayFind(ra, "notify-subscription-id"))
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+ "notify-subscription-id", sub->id);
+}
+
+
+/*
+ * 'create_job()' - Print a file to a printer or class.
+ */
+
+static void
+create_job(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ cupsd_printer_t *printer; /* Printer */
+ cupsd_job_t *job; /* New job */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "create_job(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, NULL, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Create the job object...
+ */
+
+ if ((job = add_job(con, printer, NULL)) == NULL)
+ return;
+
+ job->pending_timeout = 1;
+
+ /*
+ * Save and log the job...
+ */
+
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Queued on \"%s\" by \"%s\".",
+ job->dest, job->username);
+}
+
+
+/*
+ * 'create_requested_array()' - Create an array for the requested-attributes.
+ */
+
+static cups_array_t * /* O - Array of attributes or NULL */
+create_requested_array(ipp_t *request) /* I - IPP request */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *requested; /* requested-attributes attribute */
+ cups_array_t *ra; /* Requested attributes array */
+ char *value; /* Current value */
+
+
+ /*
+ * Get the requested-attributes attribute, and return NULL if we don't
+ * have one...
+ */
+
+ if ((requested = ippFindAttribute(request, "requested-attributes",
+ IPP_TAG_KEYWORD)) == NULL)
+ return (NULL);
+
+ /*
+ * If the attribute contains a single "all" keyword, return NULL...
+ */
+
+ if (requested->num_values == 1 &&
+ !strcmp(requested->values[0].string.text, "all"))
+ return (NULL);
+
+ /*
+ * Create an array using "strcmp" as the comparison function...
+ */
+
+ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+
+ for (i = 0; i < requested->num_values; i ++)
+ {
+ value = requested->values[i].string.text;
+
+ if (!strcmp(value, "job-template"))
+ {
+ cupsArrayAdd(ra, "copies");
+ cupsArrayAdd(ra, "copies-default");
+ cupsArrayAdd(ra, "copies-supported");
+ cupsArrayAdd(ra, "finishings");
+ cupsArrayAdd(ra, "finishings-default");
+ cupsArrayAdd(ra, "finishings-supported");
+ cupsArrayAdd(ra, "job-hold-until");
+ cupsArrayAdd(ra, "job-hold-until-default");
+ cupsArrayAdd(ra, "job-hold-until-supported");
+ cupsArrayAdd(ra, "job-priority");
+ cupsArrayAdd(ra, "job-priority-default");
+ cupsArrayAdd(ra, "job-priority-supported");
+ cupsArrayAdd(ra, "job-sheets");
+ cupsArrayAdd(ra, "job-sheets-default");
+ cupsArrayAdd(ra, "job-sheets-supported");
+ cupsArrayAdd(ra, "media");
+ cupsArrayAdd(ra, "media-default");
+ cupsArrayAdd(ra, "media-supported");
+ cupsArrayAdd(ra, "multiple-document-handling");
+ cupsArrayAdd(ra, "multiple-document-handling-default");
+ cupsArrayAdd(ra, "multiple-document-handling-supported");
+ cupsArrayAdd(ra, "number-up");
+ cupsArrayAdd(ra, "number-up-default");
+ cupsArrayAdd(ra, "number-up-supported");
+ cupsArrayAdd(ra, "orientation-requested");
+ cupsArrayAdd(ra, "orientation-requested-default");
+ cupsArrayAdd(ra, "orientation-requested-supported");
+ cupsArrayAdd(ra, "page-ranges");
+ cupsArrayAdd(ra, "page-ranges-supported");
+ cupsArrayAdd(ra, "printer-resolution");
+ cupsArrayAdd(ra, "printer-resolution-default");
+ cupsArrayAdd(ra, "printer-resolution-supported");
+ cupsArrayAdd(ra, "print-quality");
+ cupsArrayAdd(ra, "print-quality-default");
+ cupsArrayAdd(ra, "print-quality-supported");
+ cupsArrayAdd(ra, "sides");
+ cupsArrayAdd(ra, "sides-default");
+ cupsArrayAdd(ra, "sides-supported");
+ }
+ else if (!strcmp(value, "job-description"))
+ {
+ cupsArrayAdd(ra, "date-time-at-completed");
+ cupsArrayAdd(ra, "date-time-at-creation");
+ cupsArrayAdd(ra, "date-time-at-processing");
+ cupsArrayAdd(ra, "job-detailed-status-message");
+ cupsArrayAdd(ra, "job-document-access-errors");
+ cupsArrayAdd(ra, "job-id");
+ cupsArrayAdd(ra, "job-impressions");
+ cupsArrayAdd(ra, "job-impressions-completed");
+ cupsArrayAdd(ra, "job-k-octets");
+ cupsArrayAdd(ra, "job-k-octets-processed");
+ cupsArrayAdd(ra, "job-media-progress");
+ cupsArrayAdd(ra, "job-media-sheets");
+ cupsArrayAdd(ra, "job-media-sheets-completed");
+ cupsArrayAdd(ra, "job-message-from-operator");
+ cupsArrayAdd(ra, "job-more-info");
+ cupsArrayAdd(ra, "job-name");
+ cupsArrayAdd(ra, "job-originating-user-name");
+ cupsArrayAdd(ra, "job-printer-up-time");
+ cupsArrayAdd(ra, "job-printer-uri");
+ cupsArrayAdd(ra, "job-state");
+ cupsArrayAdd(ra, "job-state-message");
+ cupsArrayAdd(ra, "job-state-reasons");
+ cupsArrayAdd(ra, "job-uri");
+ cupsArrayAdd(ra, "number-of-documents");
+ cupsArrayAdd(ra, "number-of-intervening-jobs");
+ cupsArrayAdd(ra, "output-device-assigned");
+ cupsArrayAdd(ra, "time-at-completed");
+ cupsArrayAdd(ra, "time-at-creation");
+ cupsArrayAdd(ra, "time-at-processing");
+ }
+ else if (!strcmp(value, "printer-description"))
+ {
+ cupsArrayAdd(ra, "charset-configured");
+ cupsArrayAdd(ra, "charset-supported");
+ cupsArrayAdd(ra, "color-supported");
+ cupsArrayAdd(ra, "compression-supported");
+ cupsArrayAdd(ra, "document-format-default");
+ cupsArrayAdd(ra, "document-format-supported");
+ cupsArrayAdd(ra, "generated-natural-language-supported");
+ cupsArrayAdd(ra, "ipp-versions-supported");
+ cupsArrayAdd(ra, "job-impressions-supported");
+ cupsArrayAdd(ra, "job-k-octets-supported");
+ cupsArrayAdd(ra, "job-media-sheets-supported");
+ cupsArrayAdd(ra, "job-settable-attributes-supported");
+ cupsArrayAdd(ra, "multiple-document-jobs-supported");
+ cupsArrayAdd(ra, "multiple-operation-time-out");
+ cupsArrayAdd(ra, "natural-language-configured");
+ cupsArrayAdd(ra, "notify-attributes-supported");
+ cupsArrayAdd(ra, "notify-lease-duration-default");
+ cupsArrayAdd(ra, "notify-lease-duration-supported");
+ cupsArrayAdd(ra, "notify-max-events-supported");
+ cupsArrayAdd(ra, "notify-events-default");
+ cupsArrayAdd(ra, "notify-events-supported");
+ cupsArrayAdd(ra, "notify-pull-method-supported");
+ cupsArrayAdd(ra, "notify-schemes-supported");
+ cupsArrayAdd(ra, "operations-supported");
+ cupsArrayAdd(ra, "pages-per-minute");
+ cupsArrayAdd(ra, "pages-per-minute-color");
+ cupsArrayAdd(ra, "pdl-override-supported");
+ cupsArrayAdd(ra, "printer-alert");
+ cupsArrayAdd(ra, "printer-alert-description");
+ cupsArrayAdd(ra, "printer-commands");
+ cupsArrayAdd(ra, "printer-current-time");
+ cupsArrayAdd(ra, "printer-driver-installer");
+ cupsArrayAdd(ra, "printer-dns-sd-name");
+ cupsArrayAdd(ra, "printer-info");
+ cupsArrayAdd(ra, "printer-is-accepting-jobs");
+ cupsArrayAdd(ra, "printer-location");
+ cupsArrayAdd(ra, "printer-make-and-model");
+ cupsArrayAdd(ra, "printer-message-from-operator");
+ cupsArrayAdd(ra, "printer-more-info");
+ cupsArrayAdd(ra, "printer-more-info-manufacturer");
+ cupsArrayAdd(ra, "printer-name");
+ cupsArrayAdd(ra, "printer-state");
+ cupsArrayAdd(ra, "printer-state-message");
+ cupsArrayAdd(ra, "printer-state-reasons");
+ cupsArrayAdd(ra, "printer-settable-attributes-supported");
+ cupsArrayAdd(ra, "printer-type");
+ cupsArrayAdd(ra, "printer-up-time");
+ cupsArrayAdd(ra, "printer-uri-supported");
+ cupsArrayAdd(ra, "queued-job-count");
+ cupsArrayAdd(ra, "reference-uri-schemes-supported");
+ cupsArrayAdd(ra, "uri-authentication-supported");
+ cupsArrayAdd(ra, "uri-security-supported");
+ }
+ else if (!strcmp(value, "printer-defaults"))
+ {
+ char *name; /* Option name */
+
+
+ for (name = (char *)cupsArrayFirst(CommonDefaults);
+ name;
+ name = (char *)cupsArrayNext(CommonDefaults))
+ cupsArrayAdd(ra, name);
+ }
+ else if (!strcmp(value, "subscription-template"))
+ {
+ cupsArrayAdd(ra, "notify-attributes");
+ cupsArrayAdd(ra, "notify-charset");
+ cupsArrayAdd(ra, "notify-events");
+ cupsArrayAdd(ra, "notify-lease-duration");
+ cupsArrayAdd(ra, "notify-natural-language");
+ cupsArrayAdd(ra, "notify-pull-method");
+ cupsArrayAdd(ra, "notify-recipient-uri");
+ cupsArrayAdd(ra, "notify-time-interval");
+ cupsArrayAdd(ra, "notify-user-data");
+ }
+ else
+ cupsArrayAdd(ra, value);
+ }
+
+ return (ra);
+}
+
+
+/*
+ * 'create_subscription()' - Create a notification subscription.
+ */
+
+static void
+create_subscription(
+ cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ http_status_t status; /* Policy status */
+ int i; /* Looping var */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ char scheme[HTTP_MAX_URI],
+ /* Scheme portion of URI */
+ userpass[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ cupsd_printer_t *printer; /* Printer/class */
+ cupsd_job_t *job; /* Job */
+ int jobid; /* Job ID */
+ cupsd_subscription_t *sub; /* Subscription object */
+ const char *username, /* requesting-user-name or
+ authenticated username */
+ *recipient, /* notify-recipient-uri */
+ *pullmethod; /* notify-pull-method */
+ ipp_attribute_t *user_data; /* notify-user-data */
+ int interval, /* notify-time-interval */
+ lease; /* notify-lease-duration */
+ unsigned mask; /* notify-events */
+ ipp_attribute_t *notify_events,/* notify-events(-default) */
+ *notify_lease; /* notify-lease-duration(-default) */
+
+
+#ifdef DEBUG
+ for (attr = con->request->attrs; attr; attr = attr->next)
+ {
+ if (attr->group_tag != IPP_TAG_ZERO)
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "g%04x v%04x %s", attr->group_tag,
+ attr->value_tag, attr->name);
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "----SEP----");
+ }
+#endif /* DEBUG */
+
+ /*
+ * Is the destination valid?
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdCreateSubscription(con=%p(%d), uri=\"%s\")",
+ con, con->http.fd, uri->values[0].string.text);
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), userpass, sizeof(userpass), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (!strcmp(resource, "/"))
+ {
+ dtype = (cups_ptype_t)0;
+ printer = NULL;
+ }
+ else if (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10)
+ {
+ dtype = (cups_ptype_t)0;
+ printer = NULL;
+ }
+ else if (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9)
+ {
+ dtype = CUPS_PRINTER_CLASS;
+ printer = NULL;
+ }
+ else if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if (printer)
+ {
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
+ NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+ }
+ else if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ /*
+ * Get the user that is requesting the subscription...
+ */
+
+ username = get_username(con);
+
+ /*
+ * Find the first subscription group attribute; return if we have
+ * none...
+ */
+
+ for (attr = con->request->attrs; attr; attr = attr->next)
+ if (attr->group_tag == IPP_TAG_SUBSCRIPTION)
+ break;
+
+ if (!attr)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("No subscription attributes in request."));
+ return;
+ }
+
+ /*
+ * Process the subscription attributes in the request...
+ */
+
+ con->response->request.status.status_code = IPP_BAD_REQUEST;
+
+ while (attr)
+ {
+ recipient = NULL;
+ pullmethod = NULL;
+ user_data = NULL;
+ interval = 0;
+ lease = DefaultLeaseDuration;
+ jobid = 0;
+ mask = CUPSD_EVENT_NONE;
+
+ if (printer)
+ {
+ notify_events = ippFindAttribute(printer->attrs, "notify-events-default",
+ IPP_TAG_KEYWORD);
+ notify_lease = ippFindAttribute(printer->attrs,
+ "notify-lease-duration-default",
+ IPP_TAG_INTEGER);
+
+ if (notify_lease)
+ lease = notify_lease->values[0].integer;
+ }
+ else
+ {
+ notify_events = NULL;
+ notify_lease = NULL;
+ }
+
+ while (attr && attr->group_tag != IPP_TAG_ZERO)
+ {
+ if (!strcmp(attr->name, "notify-recipient-uri") &&
+ attr->value_tag == IPP_TAG_URI)
+ {
+ /*
+ * Validate the recipient scheme against the ServerBin/notifier
+ * directory...
+ */
+
+ char notifier[1024]; /* Notifier filename */
+
+
+ recipient = attr->values[0].string.text;
+
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, recipient,
+ scheme, sizeof(scheme), userpass, sizeof(userpass),
+ host, sizeof(host), &port,
+ resource, sizeof(resource)) < HTTP_URI_OK)
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Bad notify-recipient-uri \"%s\"."), recipient);
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
+ "notify-status-code", IPP_URI_SCHEME);
+ return;
+ }
+
+ snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin,
+ scheme);
+ if (access(notifier, X_OK))
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("notify-recipient-uri URI \"%s\" uses unknown "
+ "scheme."), recipient);
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
+ "notify-status-code", IPP_URI_SCHEME);
+ return;
+ }
+
+ if (!strcmp(scheme, "rss") && !check_rss_recipient(recipient))
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("notify-recipient-uri URI \"%s\" is already used."),
+ recipient);
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
+ "notify-status-code", IPP_ATTRIBUTES);
+ return;
+ }
+ }
+ else if (!strcmp(attr->name, "notify-pull-method") &&
+ attr->value_tag == IPP_TAG_KEYWORD)
+ {
+ pullmethod = attr->values[0].string.text;
+
+ if (strcmp(pullmethod, "ippget"))
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Bad notify-pull-method \"%s\"."), pullmethod);
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
+ "notify-status-code", IPP_ATTRIBUTES);
+ return;
+ }
+ }
+ else if (!strcmp(attr->name, "notify-charset") &&
+ attr->value_tag == IPP_TAG_CHARSET &&
+ strcmp(attr->values[0].string.text, "us-ascii") &&
+ strcmp(attr->values[0].string.text, "utf-8"))
+ {
+ send_ipp_status(con, IPP_CHARSET,
+ _("Character set \"%s\" not supported."),
+ attr->values[0].string.text);
+ return;
+ }
+ else if (!strcmp(attr->name, "notify-natural-language") &&
+ (attr->value_tag != IPP_TAG_LANGUAGE ||
+ strcmp(attr->values[0].string.text, DefaultLanguage)))
+ {
+ send_ipp_status(con, IPP_CHARSET,
+ _("Language \"%s\" not supported."),
+ attr->values[0].string.text);
+ return;
+ }
+ else if (!strcmp(attr->name, "notify-user-data") &&
+ attr->value_tag == IPP_TAG_STRING)
+ {
+ if (attr->num_values > 1 || attr->values[0].unknown.length > 63)
+ {
+ send_ipp_status(con, IPP_REQUEST_VALUE,
+ _("The notify-user-data value is too large "
+ "(%d > 63 octets)."),
+ attr->values[0].unknown.length);
+ return;
+ }
+
+ user_data = attr;
+ }
+ else if (!strcmp(attr->name, "notify-events") &&
+ attr->value_tag == IPP_TAG_KEYWORD)
+ notify_events = attr;
+ else if (!strcmp(attr->name, "notify-lease-duration") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ lease = attr->values[0].integer;
+ else if (!strcmp(attr->name, "notify-time-interval") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ interval = attr->values[0].integer;
+ else if (!strcmp(attr->name, "notify-job-id") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ jobid = attr->values[0].integer;
+
+ attr = attr->next;
+ }
+
+ if (notify_events)
+ {
+ for (i = 0; i < notify_events->num_values; i ++)
+ mask |= cupsdEventValue(notify_events->values[i].string.text);
+ }
+
+ if (recipient)
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "recipient=\"%s\"", recipient);
+ if (pullmethod)
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "pullmethod=\"%s\"", pullmethod);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "notify-lease-duration=%d", lease);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "notify-time-interval=%d", interval);
+
+ if (!recipient && !pullmethod)
+ break;
+
+ if (mask == CUPSD_EVENT_NONE)
+ {
+ if (jobid)
+ mask = CUPSD_EVENT_JOB_COMPLETED;
+ else if (printer)
+ mask = CUPSD_EVENT_PRINTER_STATE_CHANGED;
+ else
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("notify-events not specified."));
+ return;
+ }
+ }
+
+ if (MaxLeaseDuration && (lease == 0 || lease > MaxLeaseDuration))
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "create_subscription: Limiting notify-lease-duration to "
+ "%d seconds.",
+ MaxLeaseDuration);
+ lease = MaxLeaseDuration;
+ }
+
+ if (jobid)
+ {
+ if ((job = cupsdFindJob(jobid)) == NULL)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
+ jobid);
+ return;
+ }
+ }
+ else
+ job = NULL;
+
+ if ((sub = cupsdAddSubscription(mask, printer, job, recipient, 0)) == NULL)
+ {
+ send_ipp_status(con, IPP_TOO_MANY_SUBSCRIPTIONS,
+ _("There are too many subscriptions."));
+ return;
+ }
+
+ if (job)
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription #%d for job %d.",
+ sub->id, job->id);
+ else if (printer)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Added subscription #%d for printer \"%s\".",
+ sub->id, printer->name);
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription #%d for server.",
+ sub->id);
+
+ sub->interval = interval;
+ sub->lease = lease;
+ sub->expire = lease ? time(NULL) + lease : 0;
+
+ cupsdSetString(&sub->owner, username);
+
+ if (user_data)
+ {
+ sub->user_data_len = user_data->values[0].unknown.length;
+ memcpy(sub->user_data, user_data->values[0].unknown.data,
+ sub->user_data_len);
+ }
+
+ ippAddSeparator(con->response);
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+ "notify-subscription-id", sub->id);
+
+ con->response->request.status.status_code = IPP_OK;
+
+ if (attr)
+ attr = attr->next;
+ }
+
+ cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
+}
+
+
+/*
+ * 'delete_printer()' - Remove a printer or class from the system.
+ */
+
+static void
+delete_printer(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - URI of printer or class */
+{
+ http_status_t status; /* Policy status */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cupsd_printer_t *printer; /* Printer/class */
+ char filename[1024]; /* Script/PPD filename */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "delete_printer(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Do we have a valid URI?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ /*
+ * Remove old jobs...
+ */
+
+ cupsdCancelJobs(printer->name, NULL, 1);
+
+ /*
+ * Remove old subscriptions and send a "deleted printer" event...
+ */
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, printer, NULL,
+ "%s \"%s\" deleted by \"%s\".",
+ (dtype & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
+ printer->name, get_username(con));
+
+ cupsdExpireSubscriptions(printer, NULL);
+
+ /*
+ * Remove any old PPD or script files...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot,
+ printer->name);
+ unlink(filename);
+
+ snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
+ printer->name);
+ unlink(filename);
+
+ snprintf(filename, sizeof(filename), "%s/%s.png", CacheDir, printer->name);
+ unlink(filename);
+
+ snprintf(filename, sizeof(filename), "%s/%s.data", CacheDir, printer->name);
+ unlink(filename);
+
+#ifdef __APPLE__
+ /*
+ * Unregister color profiles...
+ */
+
+ apple_unregister_profiles(printer);
+#endif /* __APPLE__ */
+
+ if (dtype & CUPS_PRINTER_CLASS)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" deleted by \"%s\".",
+ printer->name, get_username(con));
+
+ cupsdDeletePrinter(printer, 0);
+ cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" deleted by \"%s\".",
+ printer->name, get_username(con));
+
+ if (cupsdDeletePrinter(printer, 0))
+ cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+ }
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+
+ /*
+ * Return with no errors...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'get_default()' - Get the default destination.
+ */
+
+static void
+get_default(cupsd_client_t *con) /* I - Client connection */
+{
+ http_status_t status; /* Policy status */
+ cups_array_t *ra; /* Requested attributes array */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_default(%p[%d])", con, con->http.fd);
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ if (DefaultPrinter)
+ {
+ ra = create_requested_array(con->request);
+
+ copy_printer_attrs(con, DefaultPrinter, ra);
+
+ cupsArrayDelete(ra);
+
+ con->response->request.status.status_code = IPP_OK;
+ }
+ else
+ send_ipp_status(con, IPP_NOT_FOUND, _("No default printer."));
+}
+
+
+/*
+ * 'get_devices()' - Get the list of available devices on the local system.
+ */
+
+static void
+get_devices(cupsd_client_t *con) /* I - Client connection */
+{
+ http_status_t status; /* Policy status */
+ ipp_attribute_t *limit, /* limit attribute */
+ *timeout, /* timeout attribute */
+ *requested, /* requested-attributes attribute */
+ *exclude, /* exclude-schemes attribute */
+ *include; /* include-schemes attribute */
+ char command[1024], /* cups-deviced command */
+ options[2048], /* Options to pass to command */
+ requested_str[256],
+ /* String for requested attributes */
+ exclude_str[512],
+ /* String for excluded schemes */
+ include_str[512];
+ /* String for included schemes */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_devices(%p[%d])", con, con->http.fd);
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ /*
+ * Run cups-deviced command with the given options...
+ */
+
+ limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
+ timeout = ippFindAttribute(con->request, "timeout", IPP_TAG_INTEGER);
+ requested = ippFindAttribute(con->request, "requested-attributes",
+ IPP_TAG_KEYWORD);
+ exclude = ippFindAttribute(con->request, "exclude-schemes", IPP_TAG_NAME);
+ include = ippFindAttribute(con->request, "include-schemes", IPP_TAG_NAME);
+
+ if (requested)
+ url_encode_attr(requested, requested_str, sizeof(requested_str));
+ else
+ strlcpy(requested_str, "requested-attributes=all", sizeof(requested_str));
+
+ if (exclude)
+ url_encode_attr(exclude, exclude_str, sizeof(exclude_str));
+ else
+ exclude_str[0] = '\0';
+
+ if (include)
+ url_encode_attr(include, include_str, sizeof(include_str));
+ else
+ include_str[0] = '\0';
+
+ snprintf(command, sizeof(command), "%s/daemon/cups-deviced", ServerBin);
+ snprintf(options, sizeof(options),
+ "%d+%d+%d+%d+%s%s%s%s%s",
+ con->request->request.op.request_id,
+ limit ? limit->values[0].integer : 0,
+ timeout ? timeout->values[0].integer : 15,
+ (int)User,
+ requested_str,
+ exclude_str[0] ? "%20" : "", exclude_str,
+ include_str[0] ? "%20" : "", include_str);
+
+ if (cupsdSendCommand(con, command, options, 1))
+ {
+ /*
+ * Command started successfully, don't send an IPP response here...
+ */
+
+ ippDelete(con->response);
+ con->response = NULL;
+ }
+ else
+ {
+ /*
+ * Command failed, return "internal error" so the user knows something
+ * went wrong...
+ */
+
+ send_ipp_status(con, IPP_INTERNAL_ERROR,
+ _("cups-deviced failed to execute."));
+ }
+}
+
+
+/*
+ * 'get_document()' - Get a copy of a job file.
+ */
+
+static void
+get_document(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job URI */
+{
+ http_status_t status; /* Policy status */
+ ipp_attribute_t *attr; /* Current attribute */
+ int jobid; /* Job ID */
+ int docnum; /* Document number */
+ cupsd_job_t *job; /* Current job */
+ char scheme[HTTP_MAX_URI], /* Method portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ char filename[1024], /* Filename for document */
+ format[1024]; /* Format for document */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_document(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (!strcmp(uri->name, "printer-uri"))
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Got a printer-uri attribute but no job-id."));
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (strncmp(resource, "/jobs/", 6))
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
+ uri->values[0].string.text);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = cupsdFindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con,
+ job->username)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ /*
+ * Get the document number...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "document-number",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Missing document-number attribute."));
+ return;
+ }
+
+ if ((docnum = attr->values[0].integer) < 1 || docnum > job->num_files ||
+ attr->num_values > 1)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("Document #%d does not exist in job #%d."), docnum,
+ jobid);
+ return;
+ }
+
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, jobid,
+ docnum);
+ if ((con->file = open(filename, O_RDONLY)) == -1)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to open document %d in job %d - %s", docnum, jobid,
+ strerror(errno));
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("Unable to open document #%d in job #%d."), docnum,
+ jobid);
+ return;
+ }
+
+ fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+
+ cupsdLoadJob(job);
+
+ snprintf(format, sizeof(format), "%s/%s", job->filetypes[docnum - 1]->super,
+ job->filetypes[docnum - 1]->type);
+
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format",
+ NULL, format);
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "document-number",
+ docnum);
+ if ((attr = ippFindAttribute(job->attrs, "document-name",
+ IPP_TAG_NAME)) != NULL)
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "document-name",
+ NULL, attr->values[0].string.text);
+}
+
+
+/*
+ * 'get_job_attrs()' - Get job attributes.
+ */
+
+static void
+get_job_attrs(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job URI */
+{
+ http_status_t status; /* Policy status */
+ ipp_attribute_t *attr; /* Current attribute */
+ int jobid; /* Job ID */
+ cupsd_job_t *job; /* Current job */
+ cupsd_printer_t *printer; /* Current printer */
+ cupsd_policy_t *policy; /* Current security policy */
+ char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ cups_array_t *ra, /* Requested attributes array */
+ *exclude; /* Private attributes array */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_job_attrs(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (!strcmp(uri->name, "printer-uri"))
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Got a printer-uri attribute but no job-id."));
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (strncmp(resource, "/jobs/", 6))
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
+ uri->values[0].string.text);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = cupsdFindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((printer = job->printer) == NULL)
+ printer = cupsdFindDest(job->dest);
+
+ if (printer)
+ policy = printer->op_policy_ptr;
+ else
+ policy = DefaultPolicyPtr;
+
+ if ((status = cupsdCheckPolicy(policy, con, job->username)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ exclude = cupsdGetPrivateAttrs(policy, con, printer, job->username);
+
+ /*
+ * Copy attributes...
+ */
+
+ cupsdLoadJob(job);
+
+ ra = create_requested_array(con->request);
+ copy_job_attrs(con, job, ra, exclude);
+ cupsArrayDelete(ra);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'get_jobs()' - Get a list of jobs for the specified printer.
+ */
+
+static void
+get_jobs(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ http_status_t status; /* Policy status */
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *dest; /* Destination */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cups_ptype_t dmask; /* Destination type mask */
+ char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ int job_comparison; /* Job comparison */
+ ipp_jstate_t job_state; /* job-state value */
+ int first_job_id; /* First job ID */
+ int limit; /* Maximum number of jobs to return */
+ int count; /* Number of jobs that match */
+ ipp_attribute_t *job_ids; /* job-ids attribute */
+ cupsd_job_t *job; /* Current job pointer */
+ cupsd_printer_t *printer; /* Printer */
+ cups_array_t *list; /* Which job list... */
+ cups_array_t *ra, /* Requested attributes array */
+ *exclude; /* Private attributes array */
+ cupsd_policy_t *policy; /* Current policy */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs(%p[%d], %s)", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (strcmp(uri->name, "printer-uri"))
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST, _("No printer-uri in request."));
+ return;
+ }
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (!strcmp(resource, "/") || !strcmp(resource, "/jobs"))
+ {
+ dest = NULL;
+ dtype = (cups_ptype_t)0;
+ dmask = (cups_ptype_t)0;
+ printer = NULL;
+ }
+ else if (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10)
+ {
+ dest = NULL;
+ dtype = (cups_ptype_t)0;
+ dmask = CUPS_PRINTER_CLASS;
+ printer = NULL;
+ }
+ else if (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9)
+ {
+ dest = NULL;
+ dtype = CUPS_PRINTER_CLASS;
+ dmask = CUPS_PRINTER_CLASS;
+ printer = NULL;
+ }
+ else if ((dest = cupsdValidateDest(uri->values[0].string.text, &dtype,
+ &printer)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+ else
+ {
+ dtype &= CUPS_PRINTER_CLASS;
+ dmask = CUPS_PRINTER_CLASS;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if (printer)
+ policy = printer->op_policy_ptr;
+ else
+ policy = DefaultPolicyPtr;
+
+ if ((status = cupsdCheckPolicy(policy, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ job_ids = ippFindAttribute(con->request, "job-ids", IPP_TAG_INTEGER);
+
+ /*
+ * See if the "which-jobs" attribute have been specified...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "which-jobs",
+ IPP_TAG_KEYWORD)) != NULL && job_ids)
+ {
+ send_ipp_status(con, IPP_CONFLICT,
+ _("The %s attribute cannot be provided with job-ids."),
+ "which-jobs");
+ return;
+ }
+ else if (!attr || !strcmp(attr->values[0].string.text, "not-completed"))
+ {
+ job_comparison = -1;
+ job_state = IPP_JOB_STOPPED;
+ list = Jobs;
+ }
+ else if (!strcmp(attr->values[0].string.text, "completed"))
+ {
+ job_comparison = 1;
+ job_state = IPP_JOB_CANCELED;
+ list = Jobs;
+ }
+ else if (!strcmp(attr->values[0].string.text, "aborted"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_ABORTED;
+ list = Jobs;
+ }
+ else if (!strcmp(attr->values[0].string.text, "all"))
+ {
+ job_comparison = 1;
+ job_state = IPP_JOB_PENDING;
+ list = Jobs;
+ }
+ else if (!strcmp(attr->values[0].string.text, "canceled"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_CANCELED;
+ list = Jobs;
+ }
+ else if (!strcmp(attr->values[0].string.text, "pending"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_PENDING;
+ list = ActiveJobs;
+ }
+ else if (!strcmp(attr->values[0].string.text, "pending-held"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_HELD;
+ list = ActiveJobs;
+ }
+ else if (!strcmp(attr->values[0].string.text, "processing"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_PROCESSING;
+ list = PrintingJobs;
+ }
+ else if (!strcmp(attr->values[0].string.text, "processing-stopped"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_STOPPED;
+ list = ActiveJobs;
+ }
+ else
+ {
+ send_ipp_status(con, IPP_ATTRIBUTES,
+ _("The which-jobs value \"%s\" is not supported."),
+ attr->values[0].string.text);
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
+ "which-jobs", NULL, attr->values[0].string.text);
+ return;
+ }
+
+ /*
+ * See if they want to limit the number of jobs reported...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "limit",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if (job_ids)
+ {
+ send_ipp_status(con, IPP_CONFLICT,
+ _("The %s attribute cannot be provided with job-ids."),
+ "limit");
+ return;
+ }
+
+ limit = attr->values[0].integer;
+ }
+ else
+ limit = 0;
+
+ if ((attr = ippFindAttribute(con->request, "first-job-id",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if (job_ids)
+ {
+ send_ipp_status(con, IPP_CONFLICT,
+ _("The %s attribute cannot be provided with job-ids."),
+ "first-job-id");
+ return;
+ }
+
+ first_job_id = attr->values[0].integer;
+ }
+ else
+ first_job_id = 1;
+
+ /*
+ * See if we only want to see jobs for a specific user...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "my-jobs",
+ IPP_TAG_BOOLEAN)) != NULL && job_ids)
+ {
+ send_ipp_status(con, IPP_CONFLICT,
+ _("The %s attribute cannot be provided with job-ids."),
+ "my-jobs");
+ return;
+ }
+ else if (attr && attr->values[0].boolean)
+ strlcpy(username, get_username(con), sizeof(username));
+ else
+ username[0] = '\0';
+
+ if ((ra = create_requested_array(con->request)) == NULL &&
+ !ippFindAttribute(con->request, "requested-attributes", IPP_TAG_KEYWORD))
+ {
+ /*
+ * IPP conformance - Get-Jobs has a default requested-attributes value of
+ * "job-id" and "job-uri".
+ */
+
+ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+ cupsArrayAdd(ra, "job-id");
+ cupsArrayAdd(ra, "job-uri");
+ }
+
+ /*
+ * OK, build a list of jobs for this printer...
+ */
+
+ if (job_ids)
+ {
+ int i; /* Looping var */
+
+ for (i = 0; i < job_ids->num_values; i ++)
+ {
+ if (!cupsdFindJob(job_ids->values[i].integer))
+ break;
+ }
+
+ if (i < job_ids->num_values)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
+ job_ids->values[i].integer);
+ return;
+ }
+
+ for (i = 0; i < job_ids->num_values; i ++)
+ {
+ job = cupsdFindJob(job_ids->values[i].integer);
+
+ cupsdLoadJob(job);
+
+ if (!job->attrs)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d",
+ job->id);
+ continue;
+ }
+
+ if (i > 0)
+ ippAddSeparator(con->response);
+
+ exclude = cupsdGetPrivateAttrs(job->printer ?
+ job->printer->op_policy_ptr :
+ policy, con, job->printer,
+ job->username);
+
+ copy_job_attrs(con, job, ra, exclude);
+ }
+ }
+ else
+ {
+ for (count = 0, job = (cupsd_job_t *)cupsArrayFirst(list);
+ (limit <= 0 || count < limit) && job;
+ job = (cupsd_job_t *)cupsArrayNext(list))
+ {
+ /*
+ * Filter out jobs that don't match...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "get_jobs: job->id=%d, dest=\"%s\", username=\"%s\", "
+ "state_value=%d, attrs=%p", job->id, job->dest,
+ job->username, job->state_value, job->attrs);
+
+ if (!job->dest || !job->username)
+ cupsdLoadJob(job);
+
+ if (!job->dest || !job->username)
+ continue;
+
+ if ((dest && strcmp(job->dest, dest)) &&
+ (!job->printer || !dest || strcmp(job->printer->name, dest)))
+ continue;
+ if ((job->dtype & dmask) != dtype &&
+ (!job->printer || (job->printer->type & dmask) != dtype))
+ continue;
+
+ if ((job_comparison < 0 && job->state_value > job_state) ||
+ (job_comparison == 0 && job->state_value != job_state) ||
+ (job_comparison > 0 && job->state_value < job_state))
+ continue;
+
+ if (job->id < first_job_id)
+ continue;
+
+ cupsdLoadJob(job);
+
+ if (!job->attrs)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d",
+ job->id);
+ continue;
+ }
+
+ if (username[0] && _cups_strcasecmp(username, job->username))
+ continue;
+
+ if (count > 0)
+ ippAddSeparator(con->response);
+
+ count ++;
+
+ exclude = cupsdGetPrivateAttrs(job->printer ?
+ job->printer->op_policy_ptr :
+ policy, con, job->printer,
+ job->username);
+
+ copy_job_attrs(con, job, ra, exclude);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: count=%d", count);
+ }
+
+ cupsArrayDelete(ra);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'get_notifications()' - Get events for a subscription.
+ */
+
+static void
+get_notifications(cupsd_client_t *con) /* I - Client connection */
+{
+ int i, j; /* Looping vars */
+ http_status_t status; /* Policy status */
+ cupsd_subscription_t *sub; /* Subscription */
+ ipp_attribute_t *ids, /* notify-subscription-ids */
+ *sequences; /* notify-sequence-numbers */
+ int min_seq; /* Minimum sequence number */
+ int interval; /* Poll interval */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_notifications(con=%p[%d])",
+ con, con->http.fd);
+
+ /*
+ * Get subscription attributes...
+ */
+
+ ids = ippFindAttribute(con->request, "notify-subscription-ids",
+ IPP_TAG_INTEGER);
+ sequences = ippFindAttribute(con->request, "notify-sequence-numbers",
+ IPP_TAG_INTEGER);
+
+ if (!ids)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Missing notify-subscription-ids attribute."));
+ return;
+ }
+
+ /*
+ * Are the subscription IDs valid?
+ */
+
+ for (i = 0, interval = 60; i < ids->num_values; i ++)
+ {
+ if ((sub = cupsdFindSubscription(ids->values[i].integer)) == NULL)
+ {
+ /*
+ * Bad subscription ID...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Subscription #%d does not exist."),
+ ids->values[i].integer);
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr :
+ DefaultPolicyPtr,
+ con, sub->owner)) != HTTP_OK)
+ {
+ send_http_error(con, status, sub->dest);
+ return;
+ }
+
+ /*
+ * Check the subscription type and update the interval accordingly.
+ */
+
+ if (sub->job && sub->job->state_value == IPP_JOB_PROCESSING &&
+ interval > 10)
+ interval = 10;
+ else if (sub->job && sub->job->state_value >= IPP_JOB_STOPPED)
+ interval = 0;
+ else if (sub->dest && sub->dest->state == IPP_PRINTER_PROCESSING &&
+ interval > 30)
+ interval = 30;
+ }
+
+ /*
+ * Tell the client to poll again in N seconds...
+ */
+
+ if (interval > 0)
+ ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
+ "notify-get-interval", interval);
+
+ ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
+ "printer-up-time", time(NULL));
+
+ /*
+ * Copy the subscription event attributes to the response.
+ */
+
+ con->response->request.status.status_code =
+ interval ? IPP_OK : IPP_OK_EVENTS_COMPLETE;
+
+ for (i = 0; i < ids->num_values; i ++)
+ {
+ /*
+ * Get the subscription and sequence number...
+ */
+
+ sub = cupsdFindSubscription(ids->values[i].integer);
+
+ if (sequences && i < sequences->num_values)
+ min_seq = sequences->values[i].integer;
+ else
+ min_seq = 1;
+
+ /*
+ * If we don't have any new events, nothing to do here...
+ */
+
+ if (min_seq > (sub->first_event_id + cupsArrayCount(sub->events)))
+ continue;
+
+ /*
+ * Otherwise copy all of the new events...
+ */
+
+ if (sub->first_event_id > min_seq)
+ j = 0;
+ else
+ j = min_seq - sub->first_event_id;
+
+ for (; j < cupsArrayCount(sub->events); j ++)
+ {
+ ippAddSeparator(con->response);
+
+ copy_attrs(con->response,
+ ((cupsd_event_t *)cupsArrayIndex(sub->events, j))->attrs, NULL,
+ IPP_TAG_EVENT_NOTIFICATION, 0, NULL);
+ }
+ }
+}
+
+
+/*
+ * 'get_ppd()' - Get a named PPD from the local system.
+ */
+
+static void
+get_ppd(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI or PPD name */
+{
+ http_status_t status; /* Policy status */
+ cupsd_printer_t *dest; /* Destination */
+ cups_ptype_t dtype; /* Destination type */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppd(%p[%d], %p[%s=%s])", con,
+ con->http.fd, uri, uri->name, uri->values[0].string.text);
+
+ if (!strcmp(uri->name, "ppd-name"))
+ {
+ /*
+ * Return a PPD file from cups-driverd...
+ */
+
+ char command[1024], /* cups-driverd command */
+ options[1024], /* Options to pass to command */
+ ppd_name[1024]; /* ppd-name */
+
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ /*
+ * Run cups-driverd command with the given options...
+ */
+
+ snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin);
+ url_encode_string(uri->values[0].string.text, ppd_name, sizeof(ppd_name));
+ snprintf(options, sizeof(options), "get+%d+%s",
+ con->request->request.op.request_id, ppd_name);
+
+ if (cupsdSendCommand(con, command, options, 0))
+ {
+ /*
+ * Command started successfully, don't send an IPP response here...
+ */
+
+ ippDelete(con->response);
+ con->response = NULL;
+ }
+ else
+ {
+ /*
+ * Command failed, return "internal error" so the user knows something
+ * went wrong...
+ */
+
+ send_ipp_status(con, IPP_INTERNAL_ERROR,
+ _("cups-driverd failed to execute."));
+ }
+ }
+ else if (!strcmp(uri->name, "printer-uri") &&
+ cupsdValidateDest(uri->values[0].string.text, &dtype, &dest))
+ {
+ int i; /* Looping var */
+ char filename[1024]; /* PPD filename */
+
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(dest->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, dest);
+ return;
+ }
+
+ /*
+ * See if we need the PPD for a class or remote printer...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
+ dest->name);
+
+ if ((dtype & CUPS_PRINTER_REMOTE) && access(filename, 0))
+ {
+ con->response->request.status.status_code = CUPS_SEE_OTHER;
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, dest->uri);
+ return;
+ }
+ else if (dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ {
+ for (i = 0; i < dest->num_printers; i ++)
+ if (!(dest->printers[i]->type &
+ (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)))
+ {
+ snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
+ dest->printers[i]->name);
+
+ if (!access(filename, 0))
+ break;
+ }
+
+ if (i < dest->num_printers)
+ dest = dest->printers[i];
+ else
+ {
+ con->response->request.status.status_code = CUPS_SEE_OTHER;
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, dest->printers[0]->uri);
+ return;
+ }
+ }
+
+ /*
+ * Found the printer with the PPD file, now see if there is one...
+ */
+
+ if ((con->file = open(filename, O_RDONLY)) < 0)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The PPD file \"%s\" could not be opened: %s"),
+ uri->values[0].string.text, strerror(errno));
+ return;
+ }
+
+ fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+
+ con->pipe_pid = 0;
+
+ con->response->request.status.status_code = IPP_OK;
+ }
+ else
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The PPD file \"%s\" could not be found."),
+ uri->values[0].string.text);
+}
+
+
+/*
+ * 'get_ppds()' - Get the list of PPD files on the local system.
+ */
+
+static void
+get_ppds(cupsd_client_t *con) /* I - Client connection */
+{
+ http_status_t status; /* Policy status */
+ ipp_attribute_t *limit, /* Limit attribute */
+ *device, /* ppd-device-id attribute */
+ *language, /* ppd-natural-language attribute */
+ *make, /* ppd-make attribute */
+ *model, /* ppd-make-and-model attribute */
+ *model_number, /* ppd-model-number attribute */
+ *product, /* ppd-product attribute */
+ *psversion, /* ppd-psverion attribute */
+ *type, /* ppd-type attribute */
+ *requested, /* requested-attributes attribute */
+ *exclude, /* exclude-schemes attribute */
+ *include; /* include-schemes attribute */
+ char command[1024], /* cups-driverd command */
+ options[4096], /* Options to pass to command */
+ device_str[256],/* Escaped ppd-device-id string */
+ language_str[256],
+ /* Escaped ppd-natural-language */
+ make_str[256], /* Escaped ppd-make string */
+ model_str[256], /* Escaped ppd-make-and-model string */
+ model_number_str[256],
+ /* ppd-model-number string */
+ product_str[256],
+ /* Escaped ppd-product string */
+ psversion_str[256],
+ /* Escaped ppd-psversion string */
+ type_str[256], /* Escaped ppd-type string */
+ requested_str[256],
+ /* String for requested attributes */
+ exclude_str[512],
+ /* String for excluded schemes */
+ include_str[512];
+ /* String for included schemes */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppds(%p[%d])", con, con->http.fd);
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ /*
+ * Run cups-driverd command with the given options...
+ */
+
+ limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
+ device = ippFindAttribute(con->request, "ppd-device-id", IPP_TAG_TEXT);
+ language = ippFindAttribute(con->request, "ppd-natural-language",
+ IPP_TAG_LANGUAGE);
+ make = ippFindAttribute(con->request, "ppd-make", IPP_TAG_TEXT);
+ model = ippFindAttribute(con->request, "ppd-make-and-model",
+ IPP_TAG_TEXT);
+ model_number = ippFindAttribute(con->request, "ppd-model-number",
+ IPP_TAG_INTEGER);
+ product = ippFindAttribute(con->request, "ppd-product", IPP_TAG_TEXT);
+ psversion = ippFindAttribute(con->request, "ppd-psversion", IPP_TAG_TEXT);
+ type = ippFindAttribute(con->request, "ppd-type", IPP_TAG_KEYWORD);
+ requested = ippFindAttribute(con->request, "requested-attributes",
+ IPP_TAG_KEYWORD);
+ exclude = ippFindAttribute(con->request, "exclude-schemes",
+ IPP_TAG_NAME);
+ include = ippFindAttribute(con->request, "include-schemes",
+ IPP_TAG_NAME);
+
+ if (requested)
+ url_encode_attr(requested, requested_str, sizeof(requested_str));
+ else
+ strlcpy(requested_str, "requested-attributes=all", sizeof(requested_str));
+
+ if (device)
+ url_encode_attr(device, device_str, sizeof(device_str));
+ else
+ device_str[0] = '\0';
+
+ if (language)
+ url_encode_attr(language, language_str, sizeof(language_str));
+ else
+ language_str[0] = '\0';
+
+ if (make)
+ url_encode_attr(make, make_str, sizeof(make_str));
+ else
+ make_str[0] = '\0';
+
+ if (model)
+ url_encode_attr(model, model_str, sizeof(model_str));
+ else
+ model_str[0] = '\0';
+
+ if (model_number)
+ snprintf(model_number_str, sizeof(model_number_str), "ppd-model-number=%d",
+ model_number->values[0].integer);
+ else
+ model_number_str[0] = '\0';
+
+ if (product)
+ url_encode_attr(product, product_str, sizeof(product_str));
+ else
+ product_str[0] = '\0';
+
+ if (psversion)
+ url_encode_attr(psversion, psversion_str, sizeof(psversion_str));
+ else
+ psversion_str[0] = '\0';
+
+ if (type)
+ url_encode_attr(type, type_str, sizeof(type_str));
+ else
+ type_str[0] = '\0';
+
+ if (exclude)
+ url_encode_attr(exclude, exclude_str, sizeof(exclude_str));
+ else
+ exclude_str[0] = '\0';
+
+ if (include)
+ url_encode_attr(include, include_str, sizeof(include_str));
+ else
+ include_str[0] = '\0';
+
+ snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin);
+ snprintf(options, sizeof(options),
+ "list+%d+%d+%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ con->request->request.op.request_id,
+ limit ? limit->values[0].integer : 0,
+ requested_str,
+ device ? "%20" : "", device_str,
+ language ? "%20" : "", language_str,
+ make ? "%20" : "", make_str,
+ model ? "%20" : "", model_str,
+ model_number ? "%20" : "", model_number_str,
+ product ? "%20" : "", product_str,
+ psversion ? "%20" : "", psversion_str,
+ type ? "%20" : "", type_str,
+ exclude_str[0] ? "%20" : "", exclude_str,
+ include_str[0] ? "%20" : "", include_str);
+
+ if (cupsdSendCommand(con, command, options, 0))
+ {
+ /*
+ * Command started successfully, don't send an IPP response here...
+ */
+
+ ippDelete(con->response);
+ con->response = NULL;
+ }
+ else
+ {
+ /*
+ * Command failed, return "internal error" so the user knows something
+ * went wrong...
+ */
+
+ send_ipp_status(con, IPP_INTERNAL_ERROR,
+ _("cups-driverd failed to execute."));
+ }
+}
+
+
+/*
+ * 'get_printer_attrs()' - Get printer attributes.
+ */
+
+static void
+get_printer_attrs(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ http_status_t status; /* Policy status */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cupsd_printer_t *printer; /* Printer/class */
+ cups_array_t *ra; /* Requested attributes array */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_attrs(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+
+ /*
+ * Send the attributes...
+ */
+
+ ra = create_requested_array(con->request);
+
+ copy_printer_attrs(con, printer, ra);
+
+ cupsArrayDelete(ra);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'get_printer_supported()' - Get printer supported values.
+ */
+
+static void
+get_printer_supported(
+ cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ http_status_t status; /* Policy status */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cupsd_printer_t *printer; /* Printer/class */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_supported(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+
+ /*
+ * Return a list of attributes that can be set via Set-Printer-Attributes.
+ */
+
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE,
+ "printer-info", 0);
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE,
+ "printer-location", 0);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'get_printers()' - Get a list of printers or classes.
+ */
+
+static void
+get_printers(cupsd_client_t *con, /* I - Client connection */
+ int type) /* I - 0 or CUPS_PRINTER_CLASS */
+{
+ http_status_t status; /* Policy status */
+ ipp_attribute_t *attr; /* Current attribute */
+ int limit; /* Max number of printers to return */
+ int count; /* Number of printers that match */
+ cupsd_printer_t *printer; /* Current printer pointer */
+ int printer_type, /* printer-type attribute */
+ printer_mask; /* printer-type-mask attribute */
+ char *location; /* Location string */
+ const char *username; /* Current user */
+ char *first_printer_name; /* first-printer-name attribute */
+ cups_array_t *ra; /* Requested attributes array */
+ int local; /* Local connection? */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printers(%p[%d], %x)", con,
+ con->http.fd, type);
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ /*
+ * Check for printers...
+ */
+
+ if (!Printers || !cupsArrayCount(Printers))
+ {
+ send_ipp_status(con, IPP_NOT_FOUND, _("No destinations added."));
+ return;
+ }
+
+ /*
+ * See if they want to limit the number of printers reported...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "limit",
+ IPP_TAG_INTEGER)) != NULL)
+ limit = attr->values[0].integer;
+ else
+ limit = 10000000;
+
+ if ((attr = ippFindAttribute(con->request, "first-printer-name",
+ IPP_TAG_NAME)) != NULL)
+ first_printer_name = attr->values[0].string.text;
+ else
+ first_printer_name = NULL;
+
+ /*
+ * Support filtering...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "printer-type",
+ IPP_TAG_ENUM)) != NULL)
+ printer_type = attr->values[0].integer;
+ else
+ printer_type = 0;
+
+ if ((attr = ippFindAttribute(con->request, "printer-type-mask",
+ IPP_TAG_ENUM)) != NULL)
+ printer_mask = attr->values[0].integer;
+ else
+ printer_mask = 0;
+
+ local = httpAddrLocalhost(&(con->clientaddr));
+
+ if ((attr = ippFindAttribute(con->request, "printer-location",
+ IPP_TAG_TEXT)) != NULL)
+ location = attr->values[0].string.text;
+ else
+ location = NULL;
+
+ if (con->username[0])
+ username = con->username;
+ else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
+ IPP_TAG_NAME)) != NULL)
+ username = attr->values[0].string.text;
+ else
+ username = NULL;
+
+ ra = create_requested_array(con->request);
+
+ /*
+ * OK, build a list of printers for this printer...
+ */
+
+ if (first_printer_name)
+ {
+ if ((printer = cupsdFindDest(first_printer_name)) == NULL)
+ printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ }
+ else
+ printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
+
+ for (count = 0;
+ count < limit && printer;
+ printer = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ if (!local && !printer->shared)
+ continue;
+
+ if ((!type || (printer->type & CUPS_PRINTER_CLASS) == type) &&
+ (printer->type & printer_mask) == printer_type &&
+ (!location ||
+ (printer->location && !_cups_strcasecmp(printer->location, location))))
+ {
+ /*
+ * If HideImplicitMembers is enabled, see if this printer or class
+ * is a member of an implicit class...
+ */
+
+ if (ImplicitClasses && HideImplicitMembers &&
+ printer->in_implicit_class)
+ continue;
+
+ /*
+ * If a username is specified, see if it is allowed or denied
+ * access...
+ */
+
+ if (cupsArrayCount(printer->users) && username &&
+ !user_allowed(printer, username))
+ continue;
+
+ /*
+ * Add the group separator as needed...
+ */
+
+ if (count > 0)
+ ippAddSeparator(con->response);
+
+ count ++;
+
+ /*
+ * Send the attributes...
+ */
+
+ copy_printer_attrs(con, printer, ra);
+ }
+ }
+
+ cupsArrayDelete(ra);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'get_subscription_attrs()' - Get subscription attributes.
+ */
+
+static void
+get_subscription_attrs(
+ cupsd_client_t *con, /* I - Client connection */
+ int sub_id) /* I - Subscription ID */
+{
+ http_status_t status; /* Policy status */
+ cupsd_subscription_t *sub; /* Subscription */
+ cupsd_policy_t *policy; /* Current security policy */
+ cups_array_t *ra, /* Requested attributes array */
+ *exclude; /* Private attributes array */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "get_subscription_attrs(con=%p[%d], sub_id=%d)",
+ con, con->http.fd, sub_id);
+
+ /*
+ * Is the subscription ID valid?
+ */
+
+ if ((sub = cupsdFindSubscription(sub_id)) == NULL)
+ {
+ /*
+ * Bad subscription ID...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Subscription #%d does not exist."),
+ sub_id);
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if (sub->dest)
+ policy = sub->dest->op_policy_ptr;
+ else
+ policy = DefaultPolicyPtr;
+
+ if ((status = cupsdCheckPolicy(policy, con, sub->owner)) != HTTP_OK)
+ {
+ send_http_error(con, status, sub->dest);
+ return;
+ }
+
+ exclude = cupsdGetPrivateAttrs(policy, con, sub->dest, sub->owner);
+
+ /*
+ * Copy the subscription attributes to the response using the
+ * requested-attributes attribute that may be provided by the client.
+ */
+
+ ra = create_requested_array(con->request);
+
+ copy_subscription_attrs(con, sub, ra, exclude);
+
+ cupsArrayDelete(ra);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'get_subscriptions()' - Get subscriptions.
+ */
+
+static void
+get_subscriptions(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer/job URI */
+{
+ http_status_t status; /* Policy status */
+ int count; /* Number of subscriptions */
+ int limit; /* Limit */
+ cupsd_subscription_t *sub; /* Subscription */
+ cups_array_t *ra; /* Requested attributes array */
+ ipp_attribute_t *attr; /* Attribute */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ char scheme[HTTP_MAX_URI],
+ /* Scheme portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ cupsd_job_t *job; /* Job pointer */
+ cupsd_printer_t *printer; /* Printer */
+ cupsd_policy_t *policy; /* Policy */
+ cups_array_t *exclude; /* Private attributes array */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "get_subscriptions(con=%p[%d], uri=%s)",
+ con, con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (!strcmp(resource, "/") ||
+ (!strncmp(resource, "/jobs", 5) && strlen(resource) <= 6) ||
+ (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10) ||
+ (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9))
+ {
+ printer = NULL;
+ job = NULL;
+ }
+ else if (!strncmp(resource, "/jobs/", 6) && resource[6])
+ {
+ printer = NULL;
+ job = cupsdFindJob(atoi(resource + 6));
+
+ if (!job)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
+ atoi(resource + 6));
+ return;
+ }
+ }
+ else if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+ else if ((attr = ippFindAttribute(con->request, "notify-job-id",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ job = cupsdFindJob(attr->values[0].integer);
+
+ if (!job)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."),
+ attr->values[0].integer);
+ return;
+ }
+ }
+ else
+ job = NULL;
+
+ /*
+ * Check policy...
+ */
+
+ if (printer)
+ policy = printer->op_policy_ptr;
+ else
+ policy = DefaultPolicyPtr;
+
+ if ((status = cupsdCheckPolicy(policy, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+
+ /*
+ * Copy the subscription attributes to the response using the
+ * requested-attributes attribute that may be provided by the client.
+ */
+
+ ra = create_requested_array(con->request);
+
+ if ((attr = ippFindAttribute(con->request, "limit",
+ IPP_TAG_INTEGER)) != NULL)
+ limit = attr->values[0].integer;
+ else
+ limit = 0;
+
+ /*
+ * See if we only want to see subscriptions for a specific user...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "my-subscriptions",
+ IPP_TAG_BOOLEAN)) != NULL &&
+ attr->values[0].boolean)
+ strlcpy(username, get_username(con), sizeof(username));
+ else
+ username[0] = '\0';
+
+ for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions), count = 0;
+ sub;
+ sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
+ if ((!printer || sub->dest == printer) && (!job || sub->job == job) &&
+ (!username[0] || !_cups_strcasecmp(username, sub->owner)))
+ {
+ ippAddSeparator(con->response);
+
+ exclude = cupsdGetPrivateAttrs(sub->dest ? sub->dest->op_policy_ptr :
+ policy, con, sub->dest,
+ sub->owner);
+
+ copy_subscription_attrs(con, sub, ra, exclude);
+
+ count ++;
+ if (limit && count >= limit)
+ break;
+ }
+
+ cupsArrayDelete(ra);
+
+ if (count)
+ con->response->request.status.status_code = IPP_OK;
+ else
+ send_ipp_status(con, IPP_NOT_FOUND, _("No subscriptions found."));
+}
+
+
+/*
+ * 'get_username()' - Get the username associated with a request.
+ */
+
+static const char * /* O - Username */
+get_username(cupsd_client_t *con) /* I - Connection */
+{
+ ipp_attribute_t *attr; /* Attribute */
+
+
+ if (con->username[0])
+ return (con->username);
+ else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
+ IPP_TAG_NAME)) != NULL)
+ return (attr->values[0].string.text);
+ else
+ return ("anonymous");
+}
+
+
+/*
+ * 'hold_job()' - Hold a print job.
+ */
+
+static void
+hold_job(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job or Printer URI */
+{
+ ipp_attribute_t *attr; /* Current job-hold-until */
+ const char *when; /* New value */
+ int jobid; /* Job ID */
+ char scheme[HTTP_MAX_URI], /* Method portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ cupsd_job_t *job; /* Job information */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_job(%p[%d], %s)", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (!strcmp(uri->name, "printer-uri"))
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Got a printer-uri attribute but no job-id."));
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (strncmp(resource, "/jobs/", 6))
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Bad job-uri \"%s\"."),
+ uri->values[0].string.text);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = cupsdFindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(job, con, job->username, username, sizeof(username)))
+ {
+ send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
+ cupsdFindDest(job->dest));
+ return;
+ }
+
+ /*
+ * Hold the job and return...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-hold-until",
+ IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_NAME);
+
+ if (attr)
+ {
+ when = attr->values[0].string.text;
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job,
+ "Job job-hold-until value changed by user.");
+ }
+ else
+ when = "indefinite";
+
+ cupsdSetJobHoldUntil(job, when, 1);
+ cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT, "Job held by \"%s\".",
+ username);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'hold_new_jobs()' - Hold pending/new jobs on a printer or class.
+ */
+
+static void
+hold_new_jobs(cupsd_client_t *con, /* I - Connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ http_status_t status; /* Policy status */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cupsd_printer_t *printer; /* Printer data */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_new_jobs(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+
+ /*
+ * Hold pending/new jobs sent to the printer...
+ */
+
+ printer->holding_new_jobs = 1;
+
+ cupsdSetPrinterReasons(printer, "+hold-new-jobs");
+
+ if (dtype & CUPS_PRINTER_CLASS)
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Class \"%s\" now holding pending/new jobs (\"%s\").",
+ printer->name, get_username(con));
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Printer \"%s\" now holding pending/new jobs (\"%s\").",
+ printer->name, get_username(con));
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'move_job()' - Move a job to a new destination.
+ */
+
+static void
+move_job(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job URI */
+{
+ http_status_t status; /* Policy status */
+ ipp_attribute_t *attr; /* Current attribute */
+ int jobid; /* Job ID */
+ cupsd_job_t *job; /* Current job */
+ const char *src; /* Source printer/class */
+ cups_ptype_t stype, /* Source type (printer or class) */
+ dtype; /* Destination type (printer/class) */
+ char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ cupsd_printer_t *sprinter, /* Source printer */
+ *dprinter; /* Destination printer */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "move_job(%p[%d], %s)", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Get the new printer or class...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-printer-uri",
+ IPP_TAG_URI)) == NULL)
+ {
+ /*
+ * Need job-printer-uri...
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("job-printer-uri attribute missing."));
+ return;
+ }
+
+ if (!cupsdValidateDest(attr->values[0].string.text, &dtype, &dprinter))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (!strcmp(uri->name, "printer-uri"))
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ /*
+ * Move all jobs...
+ */
+
+ if ((src = cupsdValidateDest(uri->values[0].string.text, &stype,
+ &sprinter)) == NULL)
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ job = NULL;
+ }
+ else
+ {
+ /*
+ * Otherwise, just move a single job...
+ */
+
+ if ((job = cupsdFindJob(attr->values[0].integer)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("Job #%d does not exist."), attr->values[0].integer);
+ return;
+ }
+ else
+ {
+ /*
+ * Job found, initialize source pointers...
+ */
+
+ src = NULL;
+ sprinter = NULL;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ if (strncmp(resource, "/jobs/", 6))
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
+ uri->values[0].string.text);
+ return;
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ jobid = atoi(resource + 6);
+
+ if ((job = cupsdFindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
+ return;
+ }
+ else
+ {
+ /*
+ * Job found, initialize source pointers...
+ */
+
+ src = NULL;
+ sprinter = NULL;
+ }
+ }
+
+ /*
+ * Check the policy of the destination printer...
+ */
+
+ if ((status = cupsdCheckPolicy(dprinter->op_policy_ptr, con,
+ job ? job->username : NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, dprinter);
+ return;
+ }
+
+ /*
+ * Now move the job or jobs...
+ */
+
+ if (job)
+ {
+ /*
+ * See if the job has been completed...
+ */
+
+ if (job->state_value > IPP_JOB_STOPPED)
+ {
+ /*
+ * Return a "not-possible" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Job #%d is finished and cannot be altered."),
+ job->id);
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(job, con, job->username, username, sizeof(username)))
+ {
+ send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
+ cupsdFindDest(job->dest));
+ return;
+ }
+
+ /*
+ * Move the job to a different printer or class...
+ */
+
+ cupsdMoveJob(job, dprinter);
+ }
+ else
+ {
+ /*
+ * Got the source printer, now look through the jobs...
+ */
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(Jobs))
+ {
+ /*
+ * See if the job is pointing at the source printer or has not been
+ * completed...
+ */
+
+ if (_cups_strcasecmp(job->dest, src) ||
+ job->state_value > IPP_JOB_STOPPED)
+ continue;
+
+ /*
+ * See if the job can be moved by the requesting user...
+ */
+
+ if (!validate_user(job, con, job->username, username, sizeof(username)))
+ continue;
+
+ /*
+ * Move the job to a different printer or class...
+ */
+
+ cupsdMoveJob(job, dprinter);
+ }
+ }
+
+ /*
+ * Start jobs if possible...
+ */
+
+ cupsdCheckJobs();
+
+ /*
+ * Return with "everything is OK" status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'ppd_parse_line()' - Parse a PPD default line.
+ */
+
+static int /* O - 0 on success, -1 on failure */
+ppd_parse_line(const char *line, /* I - Line */
+ char *option, /* O - Option name */
+ int olen, /* I - Size of option name */
+ char *choice, /* O - Choice name */
+ int clen) /* I - Size of choice name */
+{
+ /*
+ * Verify this is a default option line...
+ */
+
+ if (strncmp(line, "*Default", 8))
+ return (-1);
+
+ /*
+ * Read the option name...
+ */
+
+ for (line += 8, olen --;
+ *line > ' ' && *line < 0x7f && *line != ':' && *line != '/';
+ line ++)
+ if (olen > 0)
+ {
+ *option++ = *line;
+ olen --;
+ }
+
+ *option = '\0';
+
+ /*
+ * Skip everything else up to the colon (:)...
+ */
+
+ while (*line && *line != ':')
+ line ++;
+
+ if (!*line)
+ return (-1);
+
+ line ++;
+
+ /*
+ * Now grab the option choice, skipping leading whitespace...
+ */
+
+ while (isspace(*line & 255))
+ line ++;
+
+ for (clen --;
+ *line > ' ' && *line < 0x7f && *line != ':' && *line != '/';
+ line ++)
+ if (clen > 0)
+ {
+ *choice++ = *line;
+ clen --;
+ }
+
+ *choice = '\0';
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'print_job()' - Print a file to a printer or class.
+ */
+
+static void
+print_job(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_attribute_t *format; /* Document-format attribute */
+ const char *default_format; /* document-format-default value */
+ cupsd_job_t *job; /* New job */
+ char filename[1024]; /* Job filename */
+ mime_type_t *filetype; /* Type of file */
+ char super[MIME_MAX_SUPER], /* Supertype of file */
+ type[MIME_MAX_TYPE], /* Subtype of file */
+ mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
+ /* Textual name of mime type */
+ cupsd_printer_t *printer; /* Printer data */
+ struct stat fileinfo; /* File information */
+ int kbytes; /* Size of file */
+ int compression; /* Document compression */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "print_job(%p[%d], %s)", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Validate print file attributes, for now just document-format and
+ * compression (CUPS only supports "none" and "gzip")...
+ */
+
+ compression = CUPS_FILE_NONE;
+
+ if ((attr = ippFindAttribute(con->request, "compression",
+ IPP_TAG_KEYWORD)) != NULL)
+ {
+ if (strcmp(attr->values[0].string.text, "none")
+#ifdef HAVE_LIBZ
+ && strcmp(attr->values[0].string.text, "gzip")
+#endif /* HAVE_LIBZ */
+ )
+ {
+ send_ipp_status(con, IPP_ATTRIBUTES,
+ _("Unsupported compression \"%s\"."),
+ attr->values[0].string.text);
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
+ "compression", NULL, attr->values[0].string.text);
+ return;
+ }
+
+#ifdef HAVE_LIBZ
+ if (!strcmp(attr->values[0].string.text, "gzip"))
+ compression = CUPS_FILE_GZIP;
+#endif /* HAVE_LIBZ */
+ }
+
+ /*
+ * Do we have a file to print?
+ */
+
+ if (!con->filename)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST, _("No file in print request."));
+ return;
+ }
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, NULL, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Is it a format we support?
+ */
+
+ if ((format = ippFindAttribute(con->request, "document-format",
+ IPP_TAG_MIMETYPE)) != NULL)
+ {
+ /*
+ * Grab format from client...
+ */
+
+ if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super,
+ type) != 2)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Bad document-format \"%s\"."),
+ format->values[0].string.text);
+ return;
+ }
+ }
+ else if ((default_format = cupsGetOption("document-format",
+ printer->num_options,
+ printer->options)) != NULL)
+ {
+ /*
+ * Use default document format...
+ */
+
+ if (sscanf(default_format, "%15[^/]/%31[^;]", super, type) != 2)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Bad document-format \"%s\"."),
+ default_format);
+ return;
+ }
+ }
+ else
+ {
+ /*
+ * Auto-type it!
+ */
+
+ strcpy(super, "application");
+ strcpy(type, "octet-stream");
+ }
+
+ if (!strcmp(super, "application") && !strcmp(type, "octet-stream"))
+ {
+ /*
+ * Auto-type the file...
+ */
+
+ ipp_attribute_t *doc_name; /* document-name attribute */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job ???] Auto-typing file...");
+
+ doc_name = ippFindAttribute(con->request, "document-name", IPP_TAG_NAME);
+ filetype = mimeFileType(MimeDatabase, con->filename,
+ doc_name ? doc_name->values[0].string.text : NULL,
+ &compression);
+
+ if (!filetype)
+ filetype = mimeType(MimeDatabase, super, type);
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job ???] Request file type is %s/%s.",
+ filetype->super, filetype->type);
+ }
+ else
+ filetype = mimeType(MimeDatabase, super, type);
+
+ if (filetype &&
+ (!format ||
+ (!strcmp(super, "application") && !strcmp(type, "octet-stream"))))
+ {
+ /*
+ * Replace the document-format attribute value with the auto-typed or
+ * default one.
+ */
+
+ snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
+ filetype->type);
+
+ if (format)
+ {
+ _cupsStrFree(format->values[0].string.text);
+
+ format->values[0].string.text = _cupsStrAlloc(mimetype);
+ }
+ else
+ ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
+ "document-format", NULL, mimetype);
+ }
+ else if (!filetype)
+ {
+ send_ipp_status(con, IPP_DOCUMENT_FORMAT,
+ _("Unsupported document-format \"%s\"."),
+ format ? format->values[0].string.text :
+ "application/octet-stream");
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Hint: Do you have the raw file printing rules enabled?");
+
+ if (format)
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
+ "document-format", NULL, format->values[0].string.text);
+
+ return;
+ }
+
+ /*
+ * Read any embedded job ticket info from PS files...
+ */
+
+ if (!_cups_strcasecmp(filetype->super, "application") &&
+ (!_cups_strcasecmp(filetype->type, "postscript") ||
+ !_cups_strcasecmp(filetype->type, "pdf")))
+ read_job_ticket(con);
+
+ /*
+ * Create the job object...
+ */
+
+ if ((job = add_job(con, printer, filetype)) == NULL)
+ return;
+
+ /*
+ * Update quota data...
+ */
+
+ if (stat(con->filename, &fileinfo))
+ kbytes = 0;
+ else
+ kbytes = (fileinfo.st_size + 1023) / 1024;
+
+ cupsdUpdateQuota(printer, job->username, 0, kbytes);
+
+ if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
+ IPP_TAG_INTEGER)) != NULL)
+ attr->values[0].integer += kbytes;
+
+ /*
+ * Add the job file...
+ */
+
+ if (add_file(con, job, filetype, compression))
+ return;
+
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id,
+ job->num_files);
+ rename(con->filename, filename);
+ cupsdClearString(&con->filename);
+
+ /*
+ * See if we need to add the ending sheet...
+ */
+
+ if (cupsdTimeoutJob(job))
+ return;
+
+ /*
+ * Log and save the job...
+ */
+
+ cupsdLogJob(job, CUPSD_LOG_INFO,
+ "File of type %s/%s queued by \"%s\".",
+ filetype->super, filetype->type, job->username);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "hold_until=%d", (int)job->hold_until);
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Queued on \"%s\" by \"%s\".",
+ job->dest, job->username);
+
+ /*
+ * Start the job if possible...
+ */
+
+ cupsdCheckJobs();
+}
+
+
+/*
+ * 'read_job_ticket()' - Read a job ticket embedded in a print file.
+ *
+ * This function only gets called when printing a single PDF or PostScript
+ * file using the Print-Job operation. It doesn't work for Create-Job +
+ * Send-File, since the job attributes need to be set at job creation
+ * time for banners to work. The embedded job ticket stuff is here
+ * primarily to allow the Windows printer driver for CUPS to pass in JCL
+ * options and IPP attributes which otherwise would be lost.
+ *
+ * The format of a job ticket is simple:
+ *
+ * %cupsJobTicket: attr1=value1 attr2=value2 ... attrN=valueN
+ *
+ * %cupsJobTicket: attr1=value1
+ * %cupsJobTicket: attr2=value2
+ * ...
+ * %cupsJobTicket: attrN=valueN
+ *
+ * Job ticket lines must appear immediately after the first line that
+ * specifies PostScript (%!PS-Adobe-3.0) or PDF (%PDF) format, and CUPS
+ * stops looking for job ticket info when it finds a line that does not begin
+ * with "%cupsJobTicket:".
+ *
+ * The maximum length of a job ticket line, including the prefix, is
+ * 255 characters to conform with the Adobe DSC.
+ *
+ * Read-only attributes are rejected with a notice to the error log in
+ * case a malicious user tries anything. Since the job ticket is read
+ * prior to attribute validation in print_job(), job ticket attributes
+ * will go through the same validation as IPP attributes...
+ */
+
+static void
+read_job_ticket(cupsd_client_t *con) /* I - Client connection */
+{
+ cups_file_t *fp; /* File to read from */
+ char line[256]; /* Line data */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ ipp_t *ticket; /* New attributes */
+ ipp_attribute_t *attr, /* Current attribute */
+ *attr2, /* Job attribute */
+ *prev2; /* Previous job attribute */
+
+
+ /*
+ * First open the print file...
+ */
+
+ if ((fp = cupsFileOpen(con->filename, "rb")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to open print file for job ticket - %s",
+ strerror(errno));
+ return;
+ }
+
+ /*
+ * Skip the first line...
+ */
+
+ if (cupsFileGets(fp, line, sizeof(line)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to read from print file for job ticket - %s",
+ strerror(errno));
+ cupsFileClose(fp);
+ return;
+ }
+
+ if (strncmp(line, "%!PS-Adobe-", 11) && strncmp(line, "%PDF-", 5))
+ {
+ /*
+ * Not a DSC-compliant file, so no job ticket info will be available...
+ */
+
+ cupsFileClose(fp);
+ return;
+ }
+
+ /*
+ * Read job ticket info from the file...
+ */
+
+ num_options = 0;
+ options = NULL;
+
+ while (cupsFileGets(fp, line, sizeof(line)))
+ {
+ /*
+ * Stop at the first non-ticket line...
+ */
+
+ if (strncmp(line, "%cupsJobTicket:", 15))
+ break;
+
+ /*
+ * Add the options to the option array...
+ */
+
+ num_options = cupsParseOptions(line + 15, num_options, &options);
+ }
+
+ /*
+ * Done with the file; see if we have any options...
+ */
+
+ cupsFileClose(fp);
+
+ if (num_options == 0)
+ return;
+
+ /*
+ * OK, convert the options to an attribute list, and apply them to
+ * the request...
+ */
+
+ ticket = ippNew();
+ cupsEncodeOptions(ticket, num_options, options);
+
+ /*
+ * See what the user wants to change.
+ */
+
+ for (attr = ticket->attrs; attr; attr = attr->next)
+ {
+ if (attr->group_tag != IPP_TAG_JOB || !attr->name)
+ continue;
+
+ if (!strcmp(attr->name, "job-originating-host-name") ||
+ !strcmp(attr->name, "job-originating-user-name") ||
+ !strcmp(attr->name, "job-media-sheets-completed") ||
+ !strcmp(attr->name, "job-k-octets") ||
+ !strcmp(attr->name, "job-id") ||
+ !strncmp(attr->name, "job-state", 9) ||
+ !strncmp(attr->name, "time-at-", 8))
+ continue; /* Read-only attrs */
+
+ if ((attr2 = ippFindAttribute(con->request, attr->name,
+ IPP_TAG_ZERO)) != NULL)
+ {
+ /*
+ * Some other value; first free the old value...
+ */
+
+ if (con->request->attrs == attr2)
+ {
+ con->request->attrs = attr2->next;
+ prev2 = NULL;
+ }
+ else
+ {
+ for (prev2 = con->request->attrs; prev2; prev2 = prev2->next)
+ if (prev2->next == attr2)
+ {
+ prev2->next = attr2->next;
+ break;
+ }
+ }
+
+ if (con->request->last == attr2)
+ con->request->last = prev2;
+
+ _ippFreeAttr(attr2);
+ }
+
+ /*
+ * Add new option by copying it...
+ */
+
+ copy_attribute(con->request, attr, 0);
+ }
+
+ /*
+ * Then free the attribute list and option array...
+ */
+
+ ippDelete(ticket);
+ cupsFreeOptions(num_options, options);
+}
+
+
+/*
+ * 'reject_jobs()' - Reject print jobs to a printer.
+ */
+
+static void
+reject_jobs(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer or class URI */
+{
+ http_status_t status; /* Policy status */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cupsd_printer_t *printer; /* Printer data */
+ ipp_attribute_t *attr; /* printer-state-message text */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "reject_jobs(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+
+ /*
+ * Reject jobs sent to the printer...
+ */
+
+ printer->accepting = 0;
+
+ if ((attr = ippFindAttribute(con->request, "printer-state-message",
+ IPP_TAG_TEXT)) == NULL)
+ strcpy(printer->state_message, "Rejecting Jobs");
+ else
+ strlcpy(printer->state_message, attr->values[0].string.text,
+ sizeof(printer->state_message));
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
+ "No longer accepting jobs.");
+
+ if (dtype & CUPS_PRINTER_CLASS)
+ {
+ cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" rejecting jobs (\"%s\").",
+ printer->name, get_username(con));
+ }
+ else
+ {
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" rejecting jobs (\"%s\").",
+ printer->name, get_username(con));
+ }
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'release_held_new_jobs()' - Release pending/new jobs on a printer or class.
+ */
+
+static void
+release_held_new_jobs(
+ cupsd_client_t *con, /* I - Connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ http_status_t status; /* Policy status */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cupsd_printer_t *printer; /* Printer data */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_held_new_jobs(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+
+ /*
+ * Hold pending/new jobs sent to the printer...
+ */
+
+ printer->holding_new_jobs = 0;
+
+ cupsdSetPrinterReasons(printer, "-hold-new-jobs");
+
+ if (dtype & CUPS_PRINTER_CLASS)
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Class \"%s\" now printing pending/new jobs (\"%s\").",
+ printer->name, get_username(con));
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Printer \"%s\" now printing pending/new jobs (\"%s\").",
+ printer->name, get_username(con));
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'release_job()' - Release a held print job.
+ */
+
+static void
+release_job(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job or Printer URI */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ int jobid; /* Job ID */
+ char scheme[HTTP_MAX_URI], /* Method portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ cupsd_job_t *job; /* Job information */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_job(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (!strcmp(uri->name, "printer-uri"))
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Got a printer-uri attribute but no job-id."));
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (strncmp(resource, "/jobs/", 6))
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
+ uri->values[0].string.text);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = cupsdFindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
+ return;
+ }
+
+ /*
+ * See if job is "held"...
+ */
+
+ if (job->state_value != IPP_JOB_HELD)
+ {
+ /*
+ * Nope - return a "not possible" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_POSSIBLE, _("Job #%d is not held."), jobid);
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(job, con, job->username, username, sizeof(username)))
+ {
+ send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
+ cupsdFindDest(job->dest));
+ return;
+ }
+
+ /*
+ * Reset the job-hold-until value to "no-hold"...
+ */
+
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
+ IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+
+ if (attr)
+ {
+ _cupsStrFree(attr->values[0].string.text);
+
+ attr->value_tag = IPP_TAG_KEYWORD;
+ attr->values[0].string.text = _cupsStrAlloc("no-hold");
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job,
+ "Job job-hold-until value changed by user.");
+ }
+
+ /*
+ * Release the job and return...
+ */
+
+ cupsdReleaseJob(job);
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_STATE, cupsdFindDest(job->dest), job,
+ "Job released by user.");
+
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Released by \"%s\".", username);
+
+ con->response->request.status.status_code = IPP_OK;
+
+ cupsdCheckJobs();
+}
+
+
+/*
+ * 'renew_subscription()' - Renew an existing subscription...
+ */
+
+static void
+renew_subscription(
+ cupsd_client_t *con, /* I - Client connection */
+ int sub_id) /* I - Subscription ID */
+{
+ http_status_t status; /* Policy status */
+ cupsd_subscription_t *sub; /* Subscription */
+ ipp_attribute_t *lease; /* notify-lease-duration */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "renew_subscription(con=%p[%d], sub_id=%d)",
+ con, con->http.fd, sub_id);
+
+ /*
+ * Is the subscription ID valid?
+ */
+
+ if ((sub = cupsdFindSubscription(sub_id)) == NULL)
+ {
+ /*
+ * Bad subscription ID...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Subscription #%d does not exist."),
+ sub_id);
+ return;
+ }
+
+ if (sub->job)
+ {
+ /*
+ * Job subscriptions cannot be renewed...
+ */
+
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Job subscriptions cannot be renewed."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr :
+ DefaultPolicyPtr,
+ con, sub->owner)) != HTTP_OK)
+ {
+ send_http_error(con, status, sub->dest);
+ return;
+ }
+
+ /*
+ * Renew the subscription...
+ */
+
+ lease = ippFindAttribute(con->request, "notify-lease-duration",
+ IPP_TAG_INTEGER);
+
+ sub->lease = lease ? lease->values[0].integer : DefaultLeaseDuration;
+
+ if (MaxLeaseDuration && (sub->lease == 0 || sub->lease > MaxLeaseDuration))
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "renew_subscription: Limiting notify-lease-duration to "
+ "%d seconds.",
+ MaxLeaseDuration);
+ sub->lease = MaxLeaseDuration;
+ }
+
+ sub->expire = sub->lease ? time(NULL) + sub->lease : 0;
+
+ cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
+
+ con->response->request.status.status_code = IPP_OK;
+
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+ "notify-lease-duration", sub->lease);
+}
+
+
+/*
+ * 'restart_job()' - Restart an old print job.
+ */
+
+static void
+restart_job(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job or Printer URI */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ int jobid; /* Job ID */
+ cupsd_job_t *job; /* Job information */
+ char scheme[HTTP_MAX_URI], /* Method portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "restart_job(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (!strcmp(uri->name, "printer-uri"))
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Got a printer-uri attribute but no job-id."));
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (strncmp(resource, "/jobs/", 6))
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
+ uri->values[0].string.text);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = cupsdFindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
+ return;
+ }
+
+ /*
+ * See if job is in any of the "completed" states...
+ */
+
+ if (job->state_value <= IPP_JOB_PROCESSING)
+ {
+ /*
+ * Nope - return a "not possible" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_POSSIBLE, _("Job #%d is not complete."),
+ jobid);
+ return;
+ }
+
+ /*
+ * See if we have retained the job files...
+ */
+
+ cupsdLoadJob(job);
+
+ if (!job->attrs || job->num_files == 0)
+ {
+ /*
+ * Nope - return a "not possible" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Job #%d cannot be restarted - no files."), jobid);
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(job, con, job->username, username, sizeof(username)))
+ {
+ send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
+ cupsdFindDest(job->dest));
+ return;
+ }
+
+ /*
+ * See if the job-hold-until attribute is specified...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-hold-until",
+ IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_NAME);
+
+ if (attr && strcmp(attr->values[0].string.text, "no-hold"))
+ {
+ /*
+ * Return the job to a held state...
+ */
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG,
+ "Restarted by \"%s\" with job-hold-until=%s.",
+ username, attr->values[0].string.text);
+ cupsdSetJobHoldUntil(job, attr->values[0].string.text, 0);
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE,
+ NULL, job, "Job restarted by user with job-hold-until=%s",
+ attr->values[0].string.text);
+ }
+ else
+ {
+ /*
+ * Restart the job...
+ */
+
+ cupsdRestartJob(job);
+ cupsdCheckJobs();
+ }
+
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Restarted by \"%s\".", username);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'save_auth_info()' - Save authentication information for a job.
+ */
+
+static void
+save_auth_info(
+ cupsd_client_t *con, /* I - Client connection */
+ cupsd_job_t *job, /* I - Job */
+ ipp_attribute_t *auth_info) /* I - auth-info attribute, if any */
+{
+ int i; /* Looping var */
+ char filename[1024]; /* Job authentication filename */
+ cups_file_t *fp; /* Job authentication file */
+ char line[2048]; /* Line for file */
+ cupsd_printer_t *dest; /* Destination printer/class */
+
+
+ /*
+ * This function saves the in-memory authentication information for
+ * a job so that it can be used to authenticate with a remote host.
+ * The information is stored in a file that is readable only by the
+ * root user. The fields are Base-64 encoded, each on a separate line,
+ * followed by random number (up to 1024) of newlines to limit the
+ * amount of information that is exposed.
+ *
+ * Because of the potential for exposing of authentication information,
+ * this functionality is only enabled when running cupsd as root.
+ *
+ * This caching only works for the Basic and BasicDigest authentication
+ * types. Digest authentication cannot be cached this way, and in
+ * the future Kerberos authentication may make all of this obsolete.
+ *
+ * Authentication information is saved whenever an authenticated
+ * Print-Job, Create-Job, or CUPS-Authenticate-Job operation is
+ * performed.
+ *
+ * This information is deleted after a job is completed or canceled,
+ * so reprints may require subsequent re-authentication.
+ */
+
+ if (RunUser)
+ return;
+
+ if ((dest = cupsdFindDest(job->dest)) == NULL)
+ return;
+
+ /*
+ * Create the authentication file and change permissions...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/a%05d", RequestRoot, job->id);
+ if ((fp = cupsFileOpen(filename, "w")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to save authentication info to \"%s\" - %s",
+ filename, strerror(errno));
+ return;
+ }
+
+ fchown(cupsFileNumber(fp), 0, 0);
+ fchmod(cupsFileNumber(fp), 0400);
+
+ for (i = 0;
+ i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]));
+ i ++)
+ cupsdClearString(job->auth_env + i);
+
+ if (auth_info && auth_info->num_values == dest->num_auth_info_required)
+ {
+ /*
+ * Write 1 to 3 auth values...
+ */
+
+ for (i = 0;
+ i < auth_info->num_values &&
+ i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]));
+ i ++)
+ {
+ httpEncode64_2(line, sizeof(line), auth_info->values[i].string.text,
+ strlen(auth_info->values[i].string.text));
+ cupsFilePrintf(fp, "%s\n", line);
+
+ if (!strcmp(dest->auth_info_required[i], "username"))
+ cupsdSetStringf(job->auth_env + i, "AUTH_USERNAME=%s",
+ auth_info->values[i].string.text);
+ else if (!strcmp(dest->auth_info_required[i], "domain"))
+ cupsdSetStringf(job->auth_env + i, "AUTH_DOMAIN=%s",
+ auth_info->values[i].string.text);
+ else if (!strcmp(dest->auth_info_required[i], "password"))
+ cupsdSetStringf(job->auth_env + i, "AUTH_PASSWORD=%s",
+ auth_info->values[i].string.text);
+ else if (!strcmp(dest->auth_info_required[i], "negotiate"))
+ cupsdSetStringf(job->auth_env + i, "AUTH_NEGOTIATE=%s",
+ auth_info->values[i].string.text);
+ else
+ cupsdSetStringf(job->auth_env + i, "AUTH_%s=%s",
+ dest->auth_info_required[i],
+ auth_info->values[i].string.text);
+ }
+ }
+ else if (con->username[0])
+ {
+ /*
+ * Write the authenticated username...
+ */
+
+ httpEncode64_2(line, sizeof(line), con->username, strlen(con->username));
+ cupsFilePrintf(fp, "%s\n", line);
+
+ cupsdSetStringf(job->auth_env + 0, "AUTH_USERNAME=%s", con->username);
+
+ /*
+ * Write the authenticated password...
+ */
+
+ httpEncode64_2(line, sizeof(line), con->password, strlen(con->password));
+ cupsFilePrintf(fp, "%s\n", line);
+
+ cupsdSetStringf(job->auth_env + 1, "AUTH_PASSWORD=%s", con->password);
+ }
+
+#ifdef HAVE_GSSAPI
+ if (con->gss_uid > 0)
+ {
+ cupsFilePrintf(fp, "%d\n", (int)con->gss_uid);
+ cupsdSetStringf(&job->auth_uid, "AUTH_UID=%d", (int)con->gss_uid);
+ }
+#endif /* HAVE_GSSAPI */
+
+ /*
+ * Write a random number of newlines to the end of the file...
+ */
+
+ for (i = (CUPS_RAND() % 1024); i >= 0; i --)
+ cupsFilePutChar(fp, '\n');
+
+ /*
+ * Close the file and return...
+ */
+
+ cupsFileClose(fp);
+}
+
+
+/*
+ * 'send_document()' - Send a file to a printer or class.
+ */
+
+static void
+send_document(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_attribute_t *format; /* Request's document-format attribute */
+ ipp_attribute_t *jformat; /* Job's document-format attribute */
+ const char *default_format;/* document-format-default value */
+ int jobid; /* Job ID number */
+ cupsd_job_t *job; /* Current job */
+ char job_uri[HTTP_MAX_URI],
+ /* Job URI */
+ scheme[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ mime_type_t *filetype; /* Type of file */
+ char super[MIME_MAX_SUPER],
+ /* Supertype of file */
+ type[MIME_MAX_TYPE],
+ /* Subtype of file */
+ mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
+ /* Textual name of mime type */
+ char filename[1024]; /* Job filename */
+ cupsd_printer_t *printer; /* Current printer */
+ struct stat fileinfo; /* File information */
+ int kbytes; /* Size of file */
+ int compression; /* Type of compression */
+ int start_job; /* Start the job? */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_document(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (!strcmp(uri->name, "printer-uri"))
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Got a printer-uri attribute but no job-id."));
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (strncmp(resource, "/jobs/", 6))
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
+ uri->values[0].string.text);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = cupsdFindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
+ return;
+ }
+
+ printer = cupsdFindDest(job->dest);
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(job, con, job->username, username, sizeof(username)))
+ {
+ send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
+ cupsdFindDest(job->dest));
+ return;
+ }
+
+ /*
+ * OK, see if the client is sending the document compressed - CUPS
+ * only supports "none" and "gzip".
+ */
+
+ compression = CUPS_FILE_NONE;
+
+ if ((attr = ippFindAttribute(con->request, "compression",
+ IPP_TAG_KEYWORD)) != NULL)
+ {
+ if (strcmp(attr->values[0].string.text, "none")
+#ifdef HAVE_LIBZ
+ && strcmp(attr->values[0].string.text, "gzip")
+#endif /* HAVE_LIBZ */
+ )
+ {
+ send_ipp_status(con, IPP_ATTRIBUTES, _("Unsupported compression \"%s\"."),
+ attr->values[0].string.text);
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
+ "compression", NULL, attr->values[0].string.text);
+ return;
+ }
+
+#ifdef HAVE_LIBZ
+ if (!strcmp(attr->values[0].string.text, "gzip"))
+ compression = CUPS_FILE_GZIP;
+#endif /* HAVE_LIBZ */
+ }
+
+ /*
+ * Do we have a file to print?
+ */
+
+ if (!con->filename)
+ {
+ /*
+ * Check for an empty request with "last-document" set to true, which is
+ * used to close an "open" job by RFC 2911, section 3.3.2.
+ */
+
+ if (job->num_files > 0 &&
+ (attr = ippFindAttribute(con->request, "last-document",
+ IPP_TAG_BOOLEAN)) != NULL &&
+ attr->values[0].boolean)
+ goto last_document;
+
+ send_ipp_status(con, IPP_BAD_REQUEST, _("No file in print request."));
+ return;
+ }
+
+ /*
+ * Is it a format we support?
+ */
+
+ if ((format = ippFindAttribute(con->request, "document-format",
+ IPP_TAG_MIMETYPE)) != NULL)
+ {
+ /*
+ * Grab format from client...
+ */
+
+ if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]",
+ super, type) != 2)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"."),
+ format->values[0].string.text);
+ return;
+ }
+ }
+ else if ((default_format = cupsGetOption("document-format",
+ printer->num_options,
+ printer->options)) != NULL)
+ {
+ /*
+ * Use default document format...
+ */
+
+ if (sscanf(default_format, "%15[^/]/%31[^;]", super, type) != 2)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Bad document-format-default \"%s\"."), default_format);
+ return;
+ }
+ }
+ else
+ {
+ /*
+ * No document format attribute? Auto-type it!
+ */
+
+ strcpy(super, "application");
+ strcpy(type, "octet-stream");
+ }
+
+ if (!strcmp(super, "application") && !strcmp(type, "octet-stream"))
+ {
+ /*
+ * Auto-type the file...
+ */
+
+ ipp_attribute_t *doc_name; /* document-name attribute */
+
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Auto-typing file...");
+
+ doc_name = ippFindAttribute(con->request, "document-name", IPP_TAG_NAME);
+ filetype = mimeFileType(MimeDatabase, con->filename,
+ doc_name ? doc_name->values[0].string.text : NULL,
+ &compression);
+
+ if (!filetype)
+ filetype = mimeType(MimeDatabase, super, type);
+
+ if (filetype)
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Request file type is %s/%s.",
+ filetype->super, filetype->type);
+ }
+ else
+ filetype = mimeType(MimeDatabase, super, type);
+
+ if (filetype)
+ {
+ /*
+ * Replace the document-format attribute value with the auto-typed or
+ * default one.
+ */
+
+ snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
+ filetype->type);
+
+ if ((jformat = ippFindAttribute(job->attrs, "document-format",
+ IPP_TAG_MIMETYPE)) != NULL)
+ {
+ _cupsStrFree(jformat->values[0].string.text);
+
+ jformat->values[0].string.text = _cupsStrAlloc(mimetype);
+ }
+ else
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
+ "document-format", NULL, mimetype);
+ }
+ else if (!filetype)
+ {
+ send_ipp_status(con, IPP_DOCUMENT_FORMAT,
+ _("Unsupported document-format \"%s/%s\"."), super, type);
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Hint: Do you have the raw file printing rules enabled?");
+
+ if (format)
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
+ "document-format", NULL, format->values[0].string.text);
+
+ return;
+ }
+
+ if (printer->filetypes && !cupsArrayFind(printer->filetypes, filetype))
+ {
+ snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super,
+ filetype->type);
+
+ send_ipp_status(con, IPP_DOCUMENT_FORMAT,
+ _("Unsupported document-format \"%s\"."), mimetype);
+
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
+ "document-format", NULL, mimetype);
+
+ return;
+ }
+
+ /*
+ * Add the file to the job...
+ */
+
+ cupsdLoadJob(job);
+
+ if (add_file(con, job, filetype, compression))
+ return;
+
+ if (stat(con->filename, &fileinfo))
+ kbytes = 0;
+ else
+ kbytes = (fileinfo.st_size + 1023) / 1024;
+
+ cupsdUpdateQuota(printer, job->username, 0, kbytes);
+
+ if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
+ IPP_TAG_INTEGER)) != NULL)
+ attr->values[0].integer += kbytes;
+
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id,
+ job->num_files);
+ rename(con->filename, filename);
+
+ cupsdClearString(&con->filename);
+
+ cupsdLogJob(job, CUPSD_LOG_INFO, "File of type %s/%s queued by \"%s\".",
+ filetype->super, filetype->type, job->username);
+
+ /*
+ * Start the job if this is the last document...
+ */
+
+ last_document:
+
+ if ((attr = ippFindAttribute(con->request, "last-document",
+ IPP_TAG_BOOLEAN)) != NULL &&
+ attr->values[0].boolean)
+ {
+ /*
+ * See if we need to add the ending sheet...
+ */
+
+ if (cupsdTimeoutJob(job))
+ return;
+
+ if (job->state_value == IPP_JOB_STOPPED)
+ {
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ job->state_value = IPP_JOB_PENDING;
+ }
+ else if (job->state_value == IPP_JOB_HELD)
+ {
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
+ IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+
+ if (!attr || !strcmp(attr->values[0].string.text, "no-hold"))
+ {
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ job->state_value = IPP_JOB_PENDING;
+ }
+ }
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+
+ start_job = 1;
+ }
+ else
+ {
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
+ IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+
+ if (!attr || !strcmp(attr->values[0].string.text, "no-hold"))
+ {
+ job->state->values[0].integer = IPP_JOB_HELD;
+ job->state_value = IPP_JOB_HELD;
+ job->hold_until = time(NULL) + MultipleOperationTimeout;
+ job->dirty = 1;
+
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+ }
+
+ start_job = 0;
+ }
+
+ /*
+ * Fill in the response info...
+ */
+
+ snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName,
+ LocalPort, jobid);
+
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL,
+ job_uri);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", jobid);
+
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state",
+ job->state_value);
+ add_job_state_reasons(con, job);
+
+ con->response->request.status.status_code = IPP_OK;
+
+ /*
+ * Start the job if necessary...
+ */
+
+ if (start_job)
+ cupsdCheckJobs();
+}
+
+
+/*
+ * 'send_http_error()' - Send a HTTP error back to the IPP client.
+ */
+
+static void
+send_http_error(
+ cupsd_client_t *con, /* I - Client connection */
+ http_status_t status, /* I - HTTP status code */
+ cupsd_printer_t *printer) /* I - Printer, if any */
+{
+ ipp_attribute_t *uri; /* Request URI, if any */
+
+
+ if ((uri = ippFindAttribute(con->request, "printer-uri",
+ IPP_TAG_URI)) == NULL)
+ uri = ippFindAttribute(con->request, "job-uri", IPP_TAG_URI);
+
+ cupsdLogMessage(status == HTTP_FORBIDDEN ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG,
+ "Returning HTTP %s for %s (%s) from %s",
+ httpStatus(status),
+ con->request ?
+ ippOpString(con->request->request.op.operation_id) :
+ "no operation-id",
+ uri ? uri->values[0].string.text : "no URI",
+ con->http.hostname);
+
+ if (printer)
+ {
+ int auth_type; /* Type of authentication required */
+
+
+ auth_type = CUPSD_AUTH_NONE;
+
+ if (status == HTTP_UNAUTHORIZED &&
+ printer->num_auth_info_required > 0 &&
+ !strcmp(printer->auth_info_required[0], "negotiate") &&
+ con->request &&
+ (con->request->request.op.operation_id == IPP_PRINT_JOB ||
+ con->request->request.op.operation_id == IPP_CREATE_JOB ||
+ con->request->request.op.operation_id == CUPS_AUTHENTICATE_JOB))
+ {
+ /*
+ * Creating and authenticating jobs requires Kerberos...
+ */
+
+ auth_type = CUPSD_AUTH_NEGOTIATE;
+ }
+ else
+ {
+ /*
+ * Use policy/location-defined authentication requirements...
+ */
+
+ char resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ cupsd_location_t *auth; /* Pointer to authentication element */
+
+
+ if (printer->type & CUPS_PRINTER_CLASS)
+ snprintf(resource, sizeof(resource), "/classes/%s", printer->name);
+ else
+ snprintf(resource, sizeof(resource), "/printers/%s", printer->name);
+
+ if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
+ auth->type == CUPSD_AUTH_NONE)
+ auth = cupsdFindPolicyOp(printer->op_policy_ptr,
+ con->request ?
+ con->request->request.op.operation_id :
+ IPP_PRINT_JOB);
+
+ if (auth)
+ {
+ if (auth->type == CUPSD_AUTH_DEFAULT)
+ auth_type = DefaultAuthType;
+ else
+ auth_type = auth->type;
+ }
+ }
+
+ cupsdSendError(con, status, auth_type);
+ }
+ else
+ cupsdSendError(con, status, CUPSD_AUTH_NONE);
+
+ ippDelete(con->response);
+ con->response = NULL;
+
+ return;
+}
+
+
+/*
+ * 'send_ipp_status()' - Send a status back to the IPP client.
+ */
+
+static void
+send_ipp_status(cupsd_client_t *con, /* I - Client connection */
+ ipp_status_t status, /* I - IPP status code */
+ const char *message,/* I - Status message */
+ ...) /* I - Additional args as needed */
+{
+ va_list ap; /* Pointer to additional args */
+ char formatted[1024]; /* Formatted errror message */
+
+
+ va_start(ap, message);
+ vsnprintf(formatted, sizeof(formatted),
+ _cupsLangString(con->language, message), ap);
+ va_end(ap);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s: %s",
+ ippOpString(con->request->request.op.operation_id),
+ ippErrorString(status), formatted);
+
+ con->response->request.status.status_code = status;
+
+ if (ippFindAttribute(con->response, "attributes-charset",
+ IPP_TAG_ZERO) == NULL)
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, "utf-8");
+
+ if (ippFindAttribute(con->response, "attributes-natural-language",
+ IPP_TAG_ZERO) == NULL)
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, DefaultLanguage);
+
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_TEXT,
+ "status-message", NULL, formatted);
+}
+
+
+/*
+ * 'set_default()' - Set the default destination...
+ */
+
+static void
+set_default(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ http_status_t status; /* Policy status */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cupsd_printer_t *printer, /* Printer */
+ *oldprinter; /* Old default printer */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_default(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ /*
+ * Set it as the default...
+ */
+
+ oldprinter = DefaultPrinter;
+ DefaultPrinter = printer;
+
+ if (oldprinter)
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, oldprinter, NULL,
+ "%s is no longer the default printer.", oldprinter->name);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL,
+ "%s is now the default printer.", printer->name);
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS | CUPSD_DIRTY_CLASSES |
+ CUPSD_DIRTY_REMOTE | CUPSD_DIRTY_PRINTCAP);
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Default destination set to \"%s\" by \"%s\".",
+ printer->name, get_username(con));
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'set_job_attrs()' - Set job attributes.
+ */
+
+static void
+set_job_attrs(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job URI */
+{
+ ipp_attribute_t *attr, /* Current attribute */
+ *attr2; /* Job attribute */
+ int jobid; /* Job ID */
+ cupsd_job_t *job; /* Current job */
+ char scheme[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ int event; /* Events? */
+ int check_jobs; /* Check jobs? */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_job_attrs(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Start with "everything is OK" status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (!strcmp(uri->name, "printer-uri"))
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Got a printer-uri attribute but no job-id."));
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (strncmp(resource, "/jobs/", 6))
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."),
+ uri->values[0].string.text);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = cupsdFindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid);
+ return;
+ }
+
+ /*
+ * See if the job has been completed...
+ */
+
+ if (job->state_value > IPP_JOB_STOPPED)
+ {
+ /*
+ * Return a "not-possible" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Job #%d is finished and cannot be altered."), jobid);
+ return;
+ }
+
+ /*
+ * See if the job is owned by the requesting user...
+ */
+
+ if (!validate_user(job, con, job->username, username, sizeof(username)))
+ {
+ send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED,
+ cupsdFindDest(job->dest));
+ return;
+ }
+
+ /*
+ * See what the user wants to change.
+ */
+
+ cupsdLoadJob(job);
+
+ check_jobs = 0;
+ event = 0;
+
+ for (attr = con->request->attrs; attr; attr = attr->next)
+ {
+ if (attr->group_tag != IPP_TAG_JOB || !attr->name)
+ continue;
+
+ if (!strcmp(attr->name, "attributes-charset") ||
+ !strcmp(attr->name, "attributes-natural-language") ||
+ !strcmp(attr->name, "document-compression") ||
+ !strcmp(attr->name, "document-format") ||
+ !strcmp(attr->name, "job-detailed-status-messages") ||
+ !strcmp(attr->name, "job-document-access-errors") ||
+ !strcmp(attr->name, "job-id") ||
+ !strcmp(attr->name, "job-impressions-completed") ||
+ !strcmp(attr->name, "job-k-octets") ||
+ !strcmp(attr->name, "job-originating-host-name") ||
+ !strcmp(attr->name, "job-originating-user-name") ||
+ !strcmp(attr->name, "job-printer-up-time") ||
+ !strcmp(attr->name, "job-printer-uri") ||
+ !strcmp(attr->name, "job-sheets") ||
+ !strcmp(attr->name, "job-state-message") ||
+ !strcmp(attr->name, "job-state-reasons") ||
+ !strcmp(attr->name, "job-uri") ||
+ !strcmp(attr->name, "number-of-documents") ||
+ !strcmp(attr->name, "number-of-intervening-jobs") ||
+ !strcmp(attr->name, "output-device-assigned") ||
+ !strncmp(attr->name, "date-time-at-", 13) ||
+ !strncmp(attr->name, "job-k-octets", 12) ||
+ !strncmp(attr->name, "job-media-sheets", 16) ||
+ !strncmp(attr->name, "time-at-", 8))
+ {
+ /*
+ * Read-only attrs!
+ */
+
+ send_ipp_status(con, IPP_ATTRIBUTES_NOT_SETTABLE,
+ _("%s cannot be changed."), attr->name);
+
+ if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL)
+ attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
+
+ continue;
+ }
+
+ if (!strcmp(attr->name, "job-priority"))
+ {
+ /*
+ * Change the job priority...
+ */
+
+ if (attr->value_tag != IPP_TAG_INTEGER)
+ {
+ send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-priority value."));
+
+ if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL)
+ attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
+ }
+ else if (job->state_value >= IPP_JOB_PROCESSING)
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Job is completed and cannot be changed."));
+ return;
+ }
+ else if (con->response->request.status.status_code == IPP_OK)
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-priority to %d",
+ attr->values[0].integer);
+ cupsdSetJobPriority(job, attr->values[0].integer);
+
+ check_jobs = 1;
+ event |= CUPSD_EVENT_JOB_CONFIG_CHANGED |
+ CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED;
+ }
+ }
+ else if (!strcmp(attr->name, "job-state"))
+ {
+ /*
+ * Change the job state...
+ */
+
+ if (attr->value_tag != IPP_TAG_ENUM)
+ {
+ send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-state value."));
+
+ if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL)
+ attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
+ }
+ else
+ {
+ switch (attr->values[0].integer)
+ {
+ case IPP_JOB_PENDING :
+ case IPP_JOB_HELD :
+ if (job->state_value > IPP_JOB_HELD)
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Job state cannot be changed."));
+ return;
+ }
+ else if (con->response->request.status.status_code == IPP_OK)
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-state to %d",
+ attr->values[0].integer);
+ cupsdSetJobState(job, attr->values[0].integer,
+ CUPSD_JOB_DEFAULT,
+ "Job state changed by \"%s\"", username);
+ check_jobs = 1;
+ }
+ break;
+
+ case IPP_JOB_PROCESSING :
+ case IPP_JOB_STOPPED :
+ if (job->state_value != attr->values[0].integer)
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Job state cannot be changed."));
+ return;
+ }
+ break;
+
+ case IPP_JOB_CANCELED :
+ case IPP_JOB_ABORTED :
+ case IPP_JOB_COMPLETED :
+ if (job->state_value > IPP_JOB_PROCESSING)
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Job state cannot be changed."));
+ return;
+ }
+ else if (con->response->request.status.status_code == IPP_OK)
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-state to %d",
+ attr->values[0].integer);
+ cupsdSetJobState(job, (ipp_jstate_t)attr->values[0].integer,
+ CUPSD_JOB_DEFAULT,
+ "Job state changed by \"%s\"", username);
+ check_jobs = 1;
+ }
+ break;
+ }
+ }
+ }
+ else if (con->response->request.status.status_code != IPP_OK)
+ continue;
+ else if ((attr2 = ippFindAttribute(job->attrs, attr->name,
+ IPP_TAG_ZERO)) != NULL)
+ {
+ /*
+ * Some other value; first free the old value...
+ */
+
+ if (job->attrs->prev)
+ job->attrs->prev->next = attr2->next;
+ else
+ job->attrs->attrs = attr2->next;
+
+ if (job->attrs->last == attr2)
+ job->attrs->last = job->attrs->prev;
+
+ _ippFreeAttr(attr2);
+
+ /*
+ * Then copy the attribute...
+ */
+
+ copy_attribute(job->attrs, attr, 0);
+
+ /*
+ * See if the job-name or job-hold-until is being changed.
+ */
+
+ if (!strcmp(attr->name, "job-hold-until"))
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-hold-until to %s",
+ attr->values[0].string.text);
+ cupsdSetJobHoldUntil(job, attr->values[0].string.text, 0);
+
+ if (!strcmp(attr->values[0].string.text, "no-hold"))
+ {
+ cupsdReleaseJob(job);
+ check_jobs = 1;
+ }
+ else
+ cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT,
+ "Job held by \"%s\".", username);
+
+ event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE;
+ }
+ }
+ else if (attr->value_tag == IPP_TAG_DELETEATTR)
+ {
+ /*
+ * Delete the attribute...
+ */
+
+ if ((attr2 = ippFindAttribute(job->attrs, attr->name,
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (job->attrs->prev)
+ job->attrs->prev->next = attr2->next;
+ else
+ job->attrs->attrs = attr2->next;
+
+ if (attr2 == job->attrs->last)
+ job->attrs->last = job->attrs->prev;
+
+ _ippFreeAttr(attr2);
+
+ event |= CUPSD_EVENT_JOB_CONFIG_CHANGED;
+ }
+ }
+ else
+ {
+ /*
+ * Add new option by copying it...
+ */
+
+ copy_attribute(job->attrs, attr, 0);
+
+ event |= CUPSD_EVENT_JOB_CONFIG_CHANGED;
+ }
+ }
+
+ /*
+ * Save the job...
+ */
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+
+ /*
+ * Send events as needed...
+ */
+
+ if (event & CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED)
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED,
+ cupsdFindDest(job->dest), job,
+ "Job priority changed by user.");
+
+ if (event & CUPSD_EVENT_JOB_STATE)
+ cupsdAddEvent(CUPSD_EVENT_JOB_STATE, cupsdFindDest(job->dest), job,
+ job->state_value == IPP_JOB_HELD ?
+ "Job held by user." : "Job restarted by user.");
+
+ if (event & CUPSD_EVENT_JOB_CONFIG_CHANGED)
+ cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job,
+ "Job options changed by user.");
+
+ /*
+ * Start jobs if possible...
+ */
+
+ if (check_jobs)
+ cupsdCheckJobs();
+}
+
+
+/*
+ * 'set_printer_attrs()' - Set printer attributes.
+ */
+
+static void
+set_printer_attrs(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer */
+{
+ http_status_t status; /* Policy status */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cupsd_printer_t *printer; /* Printer/class */
+ ipp_attribute_t *attr; /* Printer attribute */
+ int changed = 0; /* Was anything changed? */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_printer_attrs(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+
+ /*
+ * Return a list of attributes that can be set via Set-Printer-Attributes.
+ */
+
+ if ((attr = ippFindAttribute(con->request, "printer-location",
+ IPP_TAG_TEXT)) != NULL)
+ {
+ cupsdSetString(&printer->location, attr->values[0].string.text);
+ changed = 1;
+ }
+
+ if ((attr = ippFindAttribute(con->request, "printer-info",
+ IPP_TAG_TEXT)) != NULL)
+ {
+ cupsdSetString(&printer->info, attr->values[0].string.text);
+ changed = 1;
+ }
+
+ /*
+ * Update the printer attributes and return...
+ */
+
+ if (changed)
+ {
+ cupsdSetPrinterAttrs(printer);
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_CONFIG, printer, NULL,
+ "Printer \"%s\" description or location changed by \"%s\".",
+ printer->name, get_username(con));
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Printer \"%s\" description or location changed by \"%s\".",
+ printer->name, get_username(con));
+ }
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'set_printer_defaults()' - Set printer default options from a request.
+ */
+
+static void
+set_printer_defaults(
+ cupsd_client_t *con, /* I - Client connection */
+ cupsd_printer_t *printer) /* I - Printer */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *attr; /* Current attribute */
+ int namelen; /* Length of attribute name */
+ char name[256], /* New attribute name */
+ value[256]; /* String version of integer attrs */
+
+
+ for (attr = con->request->attrs; attr; attr = attr->next)
+ {
+ /*
+ * Skip non-printer attributes...
+ */
+
+ if (attr->group_tag != IPP_TAG_PRINTER || !attr->name)
+ continue;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_printer_defaults: %s", attr->name);
+
+ if (!strcmp(attr->name, "job-sheets-default"))
+ {
+ /*
+ * Only allow keywords and names...
+ */
+
+ if (attr->value_tag != IPP_TAG_NAME && attr->value_tag != IPP_TAG_KEYWORD)
+ continue;
+
+ /*
+ * Only allow job-sheets-default to be set when running without a
+ * system high classification level...
+ */
+
+ if (Classification)
+ continue;
+
+ cupsdSetString(&printer->job_sheets[0], attr->values[0].string.text);
+
+ if (attr->num_values > 1)
+ cupsdSetString(&printer->job_sheets[1], attr->values[1].string.text);
+ else
+ cupsdSetString(&printer->job_sheets[1], "none");
+ }
+ else if (!strcmp(attr->name, "requesting-user-name-allowed"))
+ {
+ cupsdFreeStrings(&(printer->users));
+
+ printer->deny_users = 0;
+
+ if (attr->value_tag == IPP_TAG_NAME &&
+ (attr->num_values > 1 ||
+ strcmp(attr->values[0].string.text, "all")))
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ cupsdAddString(&(printer->users), attr->values[i].string.text);
+ }
+ }
+ else if (!strcmp(attr->name, "requesting-user-name-denied"))
+ {
+ cupsdFreeStrings(&(printer->users));
+
+ printer->deny_users = 1;
+
+ if (attr->value_tag == IPP_TAG_NAME &&
+ (attr->num_values > 1 ||
+ strcmp(attr->values[0].string.text, "none")))
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ cupsdAddString(&(printer->users), attr->values[i].string.text);
+ }
+ }
+ else if (!strcmp(attr->name, "job-quota-period"))
+ {
+ if (attr->value_tag != IPP_TAG_INTEGER)
+ continue;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-quota-period to %d...",
+ attr->values[0].integer);
+ cupsdFreeQuotas(printer);
+
+ printer->quota_period = attr->values[0].integer;
+ }
+ else if (!strcmp(attr->name, "job-k-limit"))
+ {
+ if (attr->value_tag != IPP_TAG_INTEGER)
+ continue;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-k-limit to %d...",
+ attr->values[0].integer);
+ cupsdFreeQuotas(printer);
+
+ printer->k_limit = attr->values[0].integer;
+ }
+ else if (!strcmp(attr->name, "job-page-limit"))
+ {
+ if (attr->value_tag != IPP_TAG_INTEGER)
+ continue;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-page-limit to %d...",
+ attr->values[0].integer);
+ cupsdFreeQuotas(printer);
+
+ printer->page_limit = attr->values[0].integer;
+ }
+ else if (!strcmp(attr->name, "printer-op-policy"))
+ {
+ cupsd_policy_t *p; /* Policy */
+
+
+ if (attr->value_tag != IPP_TAG_NAME)
+ continue;
+
+ if ((p = cupsdFindPolicy(attr->values[0].string.text)) != NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Setting printer-op-policy to \"%s\"...",
+ attr->values[0].string.text);
+ cupsdSetString(&printer->op_policy, attr->values[0].string.text);
+ printer->op_policy_ptr = p;
+ }
+ else
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Unknown printer-op-policy \"%s\"."),
+ attr->values[0].string.text);
+ return;
+ }
+ }
+ else if (!strcmp(attr->name, "printer-error-policy"))
+ {
+ if (attr->value_tag != IPP_TAG_NAME && attr->value_tag != IPP_TAG_KEYWORD)
+ continue;
+
+ if (strcmp(attr->values[0].string.text, "retry-current-job") &&
+ ((printer->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS)) ||
+ (strcmp(attr->values[0].string.text, "abort-job") &&
+ strcmp(attr->values[0].string.text, "retry-job") &&
+ strcmp(attr->values[0].string.text, "stop-printer"))))
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Unknown printer-error-policy \"%s\"."),
+ attr->values[0].string.text);
+ return;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Setting printer-error-policy to \"%s\"...",
+ attr->values[0].string.text);
+ cupsdSetString(&printer->error_policy, attr->values[0].string.text);
+ }
+
+ /*
+ * Skip any other non-default attributes...
+ */
+
+ namelen = strlen(attr->name);
+ if (namelen < 9 || strcmp(attr->name + namelen - 8, "-default") ||
+ namelen > (sizeof(name) - 1) || attr->num_values != 1)
+ continue;
+
+ /*
+ * OK, anything else must be a user-defined default...
+ */
+
+ strlcpy(name, attr->name, sizeof(name));
+ name[namelen - 8] = '\0'; /* Strip "-default" */
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_DELETEATTR :
+ printer->num_options = cupsRemoveOption(name,
+ printer->num_options,
+ &(printer->options));
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Deleting %s", attr->name);
+ break;
+
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_URI :
+ printer->num_options = cupsAddOption(name,
+ attr->values[0].string.text,
+ printer->num_options,
+ &(printer->options));
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Setting %s to \"%s\"...", attr->name,
+ attr->values[0].string.text);
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ printer->num_options = cupsAddOption(name,
+ attr->values[0].boolean ?
+ "true" : "false",
+ printer->num_options,
+ &(printer->options));
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Setting %s to %s...", attr->name,
+ attr->values[0].boolean ? "true" : "false");
+ break;
+
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ sprintf(value, "%d", attr->values[0].integer);
+ printer->num_options = cupsAddOption(name, value,
+ printer->num_options,
+ &(printer->options));
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Setting %s to %s...", attr->name, value);
+ break;
+
+ case IPP_TAG_RANGE :
+ sprintf(value, "%d-%d", attr->values[0].range.lower,
+ attr->values[0].range.upper);
+ printer->num_options = cupsAddOption(name, value,
+ printer->num_options,
+ &(printer->options));
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Setting %s to %s...", attr->name, value);
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ sprintf(value, "%dx%d%s", attr->values[0].resolution.xres,
+ attr->values[0].resolution.yres,
+ attr->values[0].resolution.units == IPP_RES_PER_INCH ?
+ "dpi" : "dpc");
+ printer->num_options = cupsAddOption(name, value,
+ printer->num_options,
+ &(printer->options));
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Setting %s to %s...", attr->name, value);
+ break;
+
+ default :
+ /* Do nothing for other values */
+ break;
+ }
+ }
+}
+
+
+/*
+ * 'start_printer()' - Start a printer.
+ */
+
+static void
+start_printer(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ int i; /* Temporary variable */
+ http_status_t status; /* Policy status */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cupsd_printer_t *printer; /* Printer data */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_printer(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+
+ /*
+ * Start the printer...
+ */
+
+ printer->state_message[0] = '\0';
+
+ cupsdStartPrinter(printer, 1);
+
+ if (dtype & CUPS_PRINTER_CLASS)
+ cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" started by \"%s\".",
+ printer->name, get_username(con));
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" started by \"%s\".",
+ printer->name, get_username(con));
+
+ cupsdCheckJobs();
+
+ /*
+ * Check quotas...
+ */
+
+ if ((i = check_quotas(con, printer)) < 0)
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE, _("Quota limit reached."));
+ return;
+ }
+ else if (i == 0)
+ {
+ send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Not allowed to print."));
+ return;
+ }
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'stop_printer()' - Stop a printer.
+ */
+
+static void
+stop_printer(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ http_status_t status; /* Policy status */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cupsd_printer_t *printer; /* Printer data */
+ ipp_attribute_t *attr; /* printer-state-message attribute */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "stop_printer(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+
+ /*
+ * Stop the printer...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "printer-state-message",
+ IPP_TAG_TEXT)) == NULL)
+ strcpy(printer->state_message, "Paused");
+ else
+ {
+ strlcpy(printer->state_message, attr->values[0].string.text,
+ sizeof(printer->state_message));
+ }
+
+ cupsdStopPrinter(printer, 1);
+
+ if (dtype & CUPS_PRINTER_CLASS)
+ cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" stopped by \"%s\".",
+ printer->name, get_username(con));
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" stopped by \"%s\".",
+ printer->name, get_username(con));
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'url_encode_attr()' - URL-encode a string attribute.
+ */
+
+static void
+url_encode_attr(ipp_attribute_t *attr, /* I - Attribute */
+ char *buffer,/* I - String buffer */
+ int bufsize)/* I - Size of buffer */
+{
+ int i; /* Looping var */
+ char *bufptr, /* Pointer into buffer */
+ *bufend; /* End of buffer */
+
+
+ strlcpy(buffer, attr->name, bufsize);
+ bufptr = buffer + strlen(buffer);
+ bufend = buffer + bufsize - 1;
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (bufptr >= bufend)
+ break;
+
+ if (i)
+ *bufptr++ = ',';
+ else
+ *bufptr++ = '=';
+
+ if (bufptr >= bufend)
+ break;
+
+ *bufptr++ = '\'';
+
+ bufptr = url_encode_string(attr->values[i].string.text,
+ bufptr, bufend - bufptr + 1);
+
+ if (bufptr >= bufend)
+ break;
+
+ *bufptr++ = '\'';
+ }
+
+ *bufptr = '\0';
+}
+
+
+/*
+ * 'url_encode_string()' - URL-encode a string.
+ */
+
+static char * /* O - End of string */
+url_encode_string(const char *s, /* I - String */
+ char *buffer, /* I - String buffer */
+ int bufsize) /* I - Size of buffer */
+{
+ char *bufptr, /* Pointer into buffer */
+ *bufend; /* End of buffer */
+ static const char *hex = "0123456789ABCDEF";
+ /* Hex digits */
+
+
+ bufptr = buffer;
+ bufend = buffer + bufsize - 1;
+
+ while (*s && bufptr < bufend)
+ {
+ if (*s == ' ' || *s == '%' || *s == '+')
+ {
+ if (bufptr >= (bufend - 2))
+ break;
+
+ *bufptr++ = '%';
+ *bufptr++ = hex[(*s >> 4) & 15];
+ *bufptr++ = hex[*s & 15];
+
+ s ++;
+ }
+ else if (*s == '\'' || *s == '\\')
+ {
+ if (bufptr >= (bufend - 1))
+ break;
+
+ *bufptr++ = '\\';
+ *bufptr++ = *s++;
+ }
+ else
+ *bufptr++ = *s++;
+ }
+
+ *bufptr = '\0';
+
+ return (bufptr);
+}
+
+
+/*
+ * 'user_allowed()' - See if a user is allowed to print to a queue.
+ */
+
+static int /* O - 0 if not allowed, 1 if allowed */
+user_allowed(cupsd_printer_t *p, /* I - Printer or class */
+ const char *username) /* I - Username */
+{
+ struct passwd *pw; /* User password data */
+ char baseuser[256], /* Base username */
+ *baseptr, /* Pointer to "@" in base username */
+ *name; /* Current user name */
+
+
+ if (cupsArrayCount(p->users) == 0)
+ return (1);
+
+ if (!strcmp(username, "root"))
+ return (1);
+
+ if (strchr(username, '@'))
+ {
+ /*
+ * Strip @REALM for username check...
+ */
+
+ strlcpy(baseuser, username, sizeof(baseuser));
+
+ if ((baseptr = strchr(baseuser, '@')) != NULL)
+ *baseptr = '\0';
+
+ username = baseuser;
+ }
+
+ pw = getpwnam(username);
+ endpwent();
+
+ for (name = (char *)cupsArrayFirst(p->users);
+ name;
+ name = (char *)cupsArrayNext(p->users))
+ {
+ if (name[0] == '@')
+ {
+ /*
+ * Check group membership...
+ */
+
+ if (cupsdCheckGroup(username, pw, name + 1))
+ break;
+ }
+ else if (name[0] == '#')
+ {
+ /*
+ * Check UUID...
+ */
+
+ if (cupsdCheckGroup(username, pw, name))
+ break;
+ }
+ else if (!_cups_strcasecmp(username, name))
+ break;
+ }
+
+ return ((name != NULL) != p->deny_users);
+}
+
+
+/*
+ * 'validate_job()' - Validate printer options and destination.
+ */
+
+static void
+validate_job(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ http_status_t status; /* Policy status */
+ ipp_attribute_t *attr, /* Current attribute */
+ *auth_info; /* auth-info attribute */
+ ipp_attribute_t *format; /* Document-format attribute */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ char super[MIME_MAX_SUPER],
+ /* Supertype of file */
+ type[MIME_MAX_TYPE];
+ /* Subtype of file */
+ cupsd_printer_t *printer; /* Printer */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "validate_job(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * OK, see if the client is sending the document compressed - CUPS
+ * doesn't support compression yet...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "compression",
+ IPP_TAG_KEYWORD)) != NULL)
+ {
+ if (strcmp(attr->values[0].string.text, "none")
+#ifdef HAVE_LIBZ
+ && strcmp(attr->values[0].string.text, "gzip")
+#endif /* HAVE_LIBZ */
+ )
+ {
+ send_ipp_status(con, IPP_ATTRIBUTES,
+ _("Unsupported compression \"%s\"."),
+ attr->values[0].string.text);
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
+ "compression", NULL, attr->values[0].string.text);
+ return;
+ }
+ }
+
+ /*
+ * Is it a format we support?
+ */
+
+ if ((format = ippFindAttribute(con->request, "document-format",
+ IPP_TAG_MIMETYPE)) != NULL)
+ {
+ if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]",
+ super, type) != 2)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"."),
+ format->values[0].string.text);
+ return;
+ }
+
+ if ((strcmp(super, "application") || strcmp(type, "octet-stream")) &&
+ !mimeType(MimeDatabase, super, type))
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Hint: Do you have the raw file printing rules enabled?");
+ send_ipp_status(con, IPP_DOCUMENT_FORMAT,
+ _("Unsupported document-format \"%s\"."),
+ format->values[0].string.text);
+ ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE,
+ "document-format", NULL, format->values[0].string.text);
+ return;
+ }
+ }
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class does not exist."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT);
+
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+ else if (printer->num_auth_info_required == 1 &&
+ !strcmp(printer->auth_info_required[0], "negotiate") &&
+ !con->username[0])
+ {
+ send_http_error(con, HTTP_UNAUTHORIZED, printer);
+ return;
+ }
+#ifdef HAVE_SSL
+ else if (auth_info && !con->http.tls &&
+ !httpAddrLocalhost(con->http.hostaddr))
+ {
+ /*
+ * Require encryption of auth-info over non-local connections...
+ */
+
+ send_http_error(con, HTTP_UPGRADE_REQUIRED, printer);
+ return;
+ }
+#endif /* HAVE_SSL */
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'validate_name()' - Make sure the printer name only contains valid chars.
+ */
+
+static int /* O - 0 if name is no good, 1 if good */
+validate_name(const char *name) /* I - Name to check */
+{
+ const char *ptr; /* Pointer into name */
+
+
+ /*
+ * Scan the whole name...
+ */
+
+ for (ptr = name; *ptr; ptr ++)
+ if ((*ptr > 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
+ return (0);
+
+ /*
+ * All the characters are good; validate the length, too...
+ */
+
+ return ((ptr - name) < 128);
+}
+
+
+/*
+ * 'validate_user()' - Validate the user for the request.
+ */
+
+static int /* O - 1 if permitted, 0 otherwise */
+validate_user(cupsd_job_t *job, /* I - Job */
+ cupsd_client_t *con, /* I - Client connection */
+ const char *owner, /* I - Owner of job/resource */
+ char *username, /* O - Authenticated username */
+ int userlen) /* I - Length of username */
+{
+ cupsd_printer_t *printer; /* Printer for job */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, "
+ "userlen=%d)",
+ job->id, con ? con->http.fd : 0,
+ owner ? owner : "(null)", username, userlen);
+
+ /*
+ * Validate input...
+ */
+
+ if (!con || !owner || !username || userlen <= 0)
+ return (0);
+
+ /*
+ * Get the best authenticated username that is available.
+ */
+
+ strlcpy(username, get_username(con), userlen);
+
+ /*
+ * Check the username against the owner...
+ */
+
+ printer = cupsdFindDest(job->dest);
+
+ return (cupsdCheckPolicy(printer ? printer->op_policy_ptr : DefaultPolicyPtr,
+ con, owner) == HTTP_OK);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/job.c b/scheduler/job.c
new file mode 100644
index 000000000..2ba006ed1
--- /dev/null
+++ b/scheduler/job.c
@@ -0,0 +1,4731 @@
+/*
+ * "$Id$"
+ *
+ * Job management routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdAddJob() - Add a new job to the job queue.
+ * cupsdCancelJobs() - Cancel all jobs for the given
+ * destination/user.
+ * cupsdCheckJobs() - Check the pending jobs and start any if the
+ * destination is available.
+ * cupsdCleanJobs() - Clean out old jobs.
+ * cupsdContinueJob() - Continue printing with the next file in a job.
+ * cupsdDeleteJob() - Free all memory used by a job.
+ * cupsdFreeAllJobs() - Free all jobs from memory.
+ * cupsdFindJob() - Find the specified job.
+ * cupsdGetPrinterJobCount() - Get the number of pending, processing, or held
+ * jobs in a printer or class.
+ * cupsdGetUserJobCount() - Get the number of pending, processing, or held
+ * jobs for a user.
+ * cupsdLoadAllJobs() - Load all jobs from disk.
+ * cupsdLoadJob() - Load a single job.
+ * cupsdMoveJob() - Move the specified job to a different
+ * destination.
+ * cupsdReleaseJob() - Release the specified job.
+ * cupsdRestartJob() - Restart the specified job.
+ * cupsdSaveAllJobs() - Save a summary of all jobs to disk.
+ * cupsdSaveJob() - Save a job to disk.
+ * cupsdSetJobHoldUntil() - Set the hold time for a job.
+ * cupsdSetJobPriority() - Set the priority of a job, moving it up/down
+ * in the list as needed.
+ * cupsdSetJobState() - Set the state of the specified print job.
+ * cupsdStopAllJobs() - Stop all print jobs.
+ * cupsdUnloadCompletedJobs() - Flush completed job history from memory.
+ * compare_active_jobs() - Compare the job IDs and priorities of two
+ * jobs.
+ * compare_jobs() - Compare the job IDs of two jobs.
+ * dump_job_history() - Dump any debug messages for a job.
+ * free_job_history() - Free any log history.
+ * finalize_job() - Cleanup after job filter processes and support
+ * data.
+ * get_options() - Get a string containing the job options.
+ * ipp_length() - Compute the size of the buffer needed to hold
+ * the textual IPP attributes.
+ * load_job_cache() - Load jobs from the job.cache file.
+ * load_next_job_id() - Load the NextJobId value from the job.cache
+ * file.
+ * load_request_root() - Load jobs from the RequestRoot directory.
+ * set_time() - Set one of the "time-at-xyz" attributes.
+ * start_job() - Start a print job.
+ * stop_job() - Stop a print job.
+ * unload_job() - Unload a job from memory.
+ * update_job() - Read a status update from a job's filters.
+ * update_job_attrs() - Update the job-printer-* attributes.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <grp.h>
+#include <cups/backend.h>
+#include <cups/dir.h>
+#ifdef __APPLE__
+# include <IOKit/pwr_mgt/IOPMLib.h>
+# ifdef HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H
+# include <IOKit/pwr_mgt/IOPMLibPrivate.h>
+# endif /* HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H */
+#endif /* __APPLE__ */
+
+
+/*
+ * Design Notes for Job Management
+ * -------------------------------
+ *
+ * STATE CHANGES
+ *
+ * pending Do nothing/check jobs
+ * pending-held Send SIGTERM to filters and backend
+ * processing Do nothing/start job
+ * stopped Send SIGKILL to filters and backend
+ * canceled Send SIGTERM to filters and backend
+ * aborted Finalize
+ * completed Finalize
+ *
+ * Finalize clears the printer <-> job association, deletes the status
+ * buffer, closes all of the pipes, etc. and doesn't get run until all of
+ * the print processes are finished.
+ *
+ * UNLOADING OF JOBS (cupsdUnloadCompletedJobs)
+ *
+ * We unload the job attributes when they are not needed to reduce overall
+ * memory consumption. We don't unload jobs where job->state_value <
+ * IPP_JOB_STOPPED, job->printer != NULL, or job->access_time is recent.
+ *
+ * STARTING OF JOBS (start_job)
+ *
+ * When a job is started, a status buffer, several pipes, a security
+ * profile, and a backend process are created for the life of that job.
+ * These are shared for every file in a job. For remote print jobs, the
+ * IPP backend is provided with every file in the job and no filters are
+ * run.
+ *
+ * The job->printer member tracks which printer is printing a job, which
+ * can be different than the destination in job->dest for classes. The
+ * printer object also has a job pointer to track which job is being
+ * printed.
+ *
+ * PRINTING OF JOB FILES (cupsdContinueJob)
+ *
+ * Each file in a job is filtered by 0 or more programs. After getting the
+ * list of filters needed and the total cost, the job is either passed or
+ * put back to the processing state until the current FilterLevel comes down
+ * enough to allow printing.
+ *
+ * If we can print, we build a string for the print options and run each of
+ * the filters, piping the output from one into the next.
+ *
+ * JOB STATUS UPDATES (update_job)
+ *
+ * The update_job function gets called whenever there are pending messages
+ * on the status pipe. These generally are updates to the marker-*,
+ * printer-state-message, or printer-state-reasons attributes. On EOF,
+ * finalize_job is called to clean up.
+ *
+ * FINALIZING JOBS (finalize_job)
+ *
+ * When all filters and the backend are done, we set the job state to
+ * completed (no errors), aborted (filter errors or abort-job policy),
+ * pending-held (auth required or retry-job policy), or pending
+ * (retry-current-job or stop-printer policies) as appropriate.
+ *
+ * Then we close the pipes and free the status buffers and profiles.
+ *
+ * JOB FILE COMPLETION (process_children in main.c)
+ *
+ * For multiple-file jobs, process_children (in main.c) sees that all
+ * filters have exited and calls in to print the next file if there are
+ * more files in the job, otherwise it waits for the backend to exit and
+ * update_job to do the cleanup.
+ */
+
+
+/*
+ * Local globals...
+ */
+
+static mime_filter_t gziptoany_filter =
+ {
+ NULL, /* Source type */
+ NULL, /* Destination type */
+ 0, /* Cost */
+ "gziptoany" /* Filter program to run */
+ };
+
+
+/*
+ * Local functions...
+ */
+
+static int compare_active_jobs(void *first, void *second, void *data);
+static int compare_jobs(void *first, void *second, void *data);
+static void dump_job_history(cupsd_job_t *job);
+static void finalize_job(cupsd_job_t *job, int set_job_state);
+static void free_job_history(cupsd_job_t *job);
+static char *get_options(cupsd_job_t *job, int banner_page, char *copies,
+ size_t copies_size, char *title,
+ size_t title_size);
+static size_t ipp_length(ipp_t *ipp);
+static void load_job_cache(const char *filename);
+static void load_next_job_id(const char *filename);
+static void load_request_root(void);
+static void set_time(cupsd_job_t *job, const char *name);
+static void start_job(cupsd_job_t *job, cupsd_printer_t *printer);
+static void stop_job(cupsd_job_t *job, cupsd_jobaction_t action);
+static void unload_job(cupsd_job_t *job);
+static void update_job(cupsd_job_t *job);
+static void update_job_attrs(cupsd_job_t *job, int do_message);
+
+
+/*
+ * 'cupsdAddJob()' - Add a new job to the job queue.
+ */
+
+cupsd_job_t * /* O - New job record */
+cupsdAddJob(int priority, /* I - Job priority */
+ const char *dest) /* I - Job destination */
+{
+ cupsd_job_t *job; /* New job record */
+
+
+ if ((job = calloc(sizeof(cupsd_job_t), 1)) == NULL)
+ return (NULL);
+
+ job->id = NextJobId ++;
+ job->priority = priority;
+ job->back_pipes[0] = -1;
+ job->back_pipes[1] = -1;
+ job->print_pipes[0] = -1;
+ job->print_pipes[1] = -1;
+ job->side_pipes[0] = -1;
+ job->side_pipes[1] = -1;
+ job->status_pipes[0] = -1;
+ job->status_pipes[1] = -1;
+
+ cupsdSetString(&job->dest, dest);
+
+ /*
+ * Add the new job to the "all jobs" and "active jobs" lists...
+ */
+
+ cupsArrayAdd(Jobs, job);
+ cupsArrayAdd(ActiveJobs, job);
+
+ return (job);
+}
+
+
+/*
+ * 'cupsdCancelJobs()' - Cancel all jobs for the given destination/user.
+ */
+
+void
+cupsdCancelJobs(const char *dest, /* I - Destination to cancel */
+ const char *username, /* I - Username or NULL */
+ int purge) /* I - Purge jobs? */
+{
+ cupsd_job_t *job; /* Current job */
+
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(Jobs))
+ {
+ if ((!job->dest || !job->username) && !cupsdLoadJob(job))
+ continue;
+
+ if ((!dest || !strcmp(job->dest, dest)) &&
+ (!username || !strcmp(job->username, username)))
+ {
+ /*
+ * Cancel all jobs matching this destination/user...
+ */
+
+ if (purge)
+ cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_PURGE,
+ "Job purged by user.");
+ else if (job->state_value < IPP_JOB_CANCELED)
+ cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_DEFAULT,
+ "Job canceled by user.");
+ }
+ }
+
+ cupsdCheckJobs();
+}
+
+
+/*
+ * 'cupsdCheckJobs()' - Check the pending jobs and start any if the destination
+ * is available.
+ */
+
+void
+cupsdCheckJobs(void)
+{
+ cupsd_job_t *job; /* Current job in queue */
+ cupsd_printer_t *printer, /* Printer destination */
+ *pclass; /* Printer class destination */
+ ipp_attribute_t *attr; /* Job attribute */
+ time_t curtime; /* Current time */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdCheckJobs: %d active jobs, sleeping=%d, reload=%d",
+ cupsArrayCount(ActiveJobs), Sleeping, NeedReload);
+
+ curtime = time(NULL);
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
+ {
+ /*
+ * Kill jobs if they are unresponsive...
+ */
+
+ if (job->kill_time && job->kill_time <= curtime)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Stopping unresponsive job!",
+ job->id);
+
+ stop_job(job, CUPSD_JOB_FORCE);
+ continue;
+ }
+
+ /*
+ * Start held jobs if they are ready...
+ */
+
+ if (job->state_value == IPP_JOB_HELD &&
+ job->hold_until &&
+ job->hold_until < curtime)
+ {
+ if (job->pending_timeout)
+ {
+ /*
+ * This job is pending; check that we don't have an active Send-Document
+ * operation in progress on any of the client connections, then timeout
+ * the job so we can start printing...
+ */
+
+ cupsd_client_t *con; /* Current client connection */
+
+
+ for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
+ con;
+ con = (cupsd_client_t *)cupsArrayNext(Clients))
+ if (con->request &&
+ con->request->request.op.operation_id == IPP_SEND_DOCUMENT)
+ break;
+
+ if (con)
+ continue;
+
+ if (cupsdTimeoutJob(job))
+ continue;
+ }
+
+ cupsdSetJobState(job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT,
+ "Job submission timed out.");
+ }
+
+ /*
+ * Continue jobs that are waiting on the FilterLimit...
+ */
+
+ if (job->pending_cost > 0 &&
+ ((FilterLevel + job->pending_cost) < FilterLimit || FilterLevel == 0))
+ cupsdContinueJob(job);
+
+ /*
+ * Start pending jobs if the destination is available...
+ */
+
+ if (job->state_value == IPP_JOB_PENDING && !NeedReload &&
+#ifndef kIOPMAssertionTypeDenySystemSleep
+ !Sleeping &&
+#endif /* !kIOPMAssertionTypeDenySystemSleep */
+ !DoingShutdown && !job->printer)
+ {
+ printer = cupsdFindDest(job->dest);
+ pclass = NULL;
+
+ while (printer &&
+ (printer->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS)))
+ {
+ /*
+ * If the class is remote, just pass it to the remote server...
+ */
+
+ pclass = printer;
+
+ if (pclass->state == IPP_PRINTER_STOPPED)
+ printer = NULL;
+ else if (pclass->type & CUPS_PRINTER_REMOTE)
+ break;
+ else
+ printer = cupsdFindAvailablePrinter(printer->name);
+ }
+
+ if (!printer && !pclass)
+ {
+ /*
+ * Whoa, the printer and/or class for this destination went away;
+ * cancel the job...
+ */
+
+ cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_PURGE,
+ "Job aborted because the destination printer/class "
+ "has gone away.");
+ }
+ else if (printer && !printer->holding_new_jobs)
+ {
+ /*
+ * See if the printer is available or remote and not printing a job;
+ * if so, start the job...
+ */
+
+ if (pclass)
+ {
+ /*
+ * Add/update a job-actual-printer-uri attribute for this job
+ * so that we know which printer actually printed the job...
+ */
+
+ if ((attr = ippFindAttribute(job->attrs, "job-actual-printer-uri",
+ IPP_TAG_URI)) != NULL)
+ cupsdSetString(&attr->values[0].string.text, printer->uri);
+ else
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI,
+ "job-actual-printer-uri", NULL, printer->uri);
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+ }
+
+ if ((!(printer->type & CUPS_PRINTER_DISCOVERED) && /* Printer is local */
+ printer->state == IPP_PRINTER_IDLE) || /* and idle, OR */
+ ((printer->type & CUPS_PRINTER_DISCOVERED) && /* Printer is remote */
+ !printer->job)) /* and not printing */
+ {
+ /*
+ * Start the job...
+ */
+
+ start_job(job, printer);
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * 'cupsdCleanJobs()' - Clean out old jobs.
+ */
+
+void
+cupsdCleanJobs(void)
+{
+ cupsd_job_t *job; /* Current job */
+
+
+ if (MaxJobs <= 0 && JobHistory)
+ return;
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
+ job && (cupsArrayCount(Jobs) >= MaxJobs || !JobHistory);
+ job = (cupsd_job_t *)cupsArrayNext(Jobs))
+ if (job->state_value >= IPP_JOB_CANCELED && !job->printer)
+ cupsdDeleteJob(job, CUPSD_JOB_PURGE);
+}
+
+
+/*
+ * 'cupsdContinueJob()' - Continue printing with the next file in a job.
+ */
+
+void
+cupsdContinueJob(cupsd_job_t *job) /* I - Job */
+{
+ int i; /* Looping var */
+ int slot; /* Pipe slot */
+ cups_array_t *filters = NULL,/* Filters for job */
+ *prefilters; /* Filters with prefilters */
+ mime_filter_t *filter, /* Current filter */
+ *prefilter, /* Prefilter */
+ port_monitor; /* Port monitor filter */
+ char scheme[255]; /* Device URI scheme */
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *ptr, /* Pointer into value */
+ *abort_message; /* Abort message */
+ ipp_jstate_t abort_state = IPP_JOB_STOPPED;
+ /* New job state on abort */
+ struct stat backinfo; /* Backend file information */
+ int backroot; /* Run backend as root? */
+ int pid; /* Process ID of new filter process */
+ int banner_page; /* 1 if banner page, 0 otherwise */
+ int filterfds[2][2] = { { -1, -1 }, { -1, -1 } };
+ /* Pipes used between filters */
+ int envc; /* Number of environment variables */
+ char **argv = NULL, /* Filter command-line arguments */
+ filename[1024], /* Job filename */
+ command[1024], /* Full path to command */
+ jobid[255], /* Job ID string */
+ title[IPP_MAX_NAME],
+ /* Job title string */
+ copies[255], /* # copies string */
+ *options, /* Options string */
+ *envp[MAX_ENV + 21],
+ /* Environment variables */
+ charset[255], /* CHARSET env variable */
+ class_name[255],/* CLASS env variable */
+ classification[1024],
+ /* CLASSIFICATION env variable */
+ content_type[1024],
+ /* CONTENT_TYPE env variable */
+ device_uri[1024],
+ /* DEVICE_URI env variable */
+ final_content_type[1024],
+ /* FINAL_CONTENT_TYPE env variable */
+ lang[255], /* LANG env variable */
+#ifdef __APPLE__
+ apple_language[255],
+ /* APPLE_LANGUAGE env variable */
+#endif /* __APPLE__ */
+ auth_info_required[255],
+ /* AUTH_INFO_REQUIRED env variable */
+ ppd[1024], /* PPD env variable */
+ printer_info[255],
+ /* PRINTER_INFO env variable */
+ printer_location[255],
+ /* PRINTER_LOCATION env variable */
+ printer_name[255],
+ /* PRINTER env variable */
+ *printer_state_reasons = NULL,
+ /* PRINTER_STATE_REASONS env var */
+ rip_max_cache[255];
+ /* RIP_MAX_CACHE env variable */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdContinueJob(job=%p(%d)): current_file=%d, num_files=%d",
+ job, job->id, job->current_file, job->num_files);
+
+ /*
+ * Figure out what filters are required to convert from
+ * the source to the destination type...
+ */
+
+ FilterLevel -= job->cost;
+
+ job->cost = 0;
+ job->pending_cost = 0;
+
+ memset(job->filters, 0, sizeof(job->filters));
+
+
+ if (job->printer->raw)
+ {
+ /*
+ * Remote jobs and raw queues go directly to the printer without
+ * filtering...
+ */
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Sending job to queue tagged as raw...");
+ }
+ else
+ {
+ /*
+ * Local jobs get filtered...
+ */
+
+ filters = mimeFilter(MimeDatabase, job->filetypes[job->current_file],
+ job->printer->filetype, &(job->cost));
+
+ if (!filters)
+ {
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to convert file %d to printable format!",
+ job->current_file);
+
+ abort_message = "Aborting job because it cannot be printed.";
+ abort_state = IPP_JOB_ABORTED;
+
+ goto abort_job;
+ }
+
+ /*
+ * Remove NULL ("-") filters...
+ */
+
+ for (filter = (mime_filter_t *)cupsArrayFirst(filters);
+ filter;
+ filter = (mime_filter_t *)cupsArrayNext(filters))
+ if (!strcmp(filter->filter, "-"))
+ cupsArrayRemove(filters, filter);
+
+ if (cupsArrayCount(filters) == 0)
+ {
+ cupsArrayDelete(filters);
+ filters = NULL;
+ }
+
+ /*
+ * If this printer has any pre-filters, insert the required pre-filter
+ * in the filters array...
+ */
+
+ if (job->printer->prefiltertype && filters)
+ {
+ prefilters = cupsArrayNew(NULL, NULL);
+
+ for (filter = (mime_filter_t *)cupsArrayFirst(filters);
+ filter;
+ filter = (mime_filter_t *)cupsArrayNext(filters))
+ {
+ if ((prefilter = mimeFilterLookup(MimeDatabase, filter->src,
+ job->printer->prefiltertype)))
+ {
+ cupsArrayAdd(prefilters, prefilter);
+ job->cost += prefilter->cost;
+ }
+
+ cupsArrayAdd(prefilters, filter);
+ }
+
+ cupsArrayDelete(filters);
+ filters = prefilters;
+ }
+ }
+
+ /*
+ * Set a minimum cost of 100 for all jobs so that FilterLimit
+ * works with raw queues and other low-cost paths.
+ */
+
+ if (job->cost < 100)
+ job->cost = 100;
+
+ /*
+ * See if the filter cost is too high...
+ */
+
+ if ((FilterLevel + job->cost) > FilterLimit && FilterLevel > 0 &&
+ FilterLimit > 0)
+ {
+ /*
+ * Don't print this job quite yet...
+ */
+
+ cupsArrayDelete(filters);
+
+ cupsdLogJob(job, CUPSD_LOG_INFO,
+ "Holding because filter limit has been reached.");
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2,
+ "cupsdContinueJob: file=%d, cost=%d, level=%d, limit=%d",
+ job->current_file, job->cost, FilterLevel,
+ FilterLimit);
+
+ job->pending_cost = job->cost;
+ job->cost = 0;
+ return;
+ }
+
+ FilterLevel += job->cost;
+
+ /*
+ * Add decompression/raw filter as needed...
+ */
+
+ if ((!job->printer->raw && job->compressions[job->current_file]) ||
+ (!filters && !job->printer->remote &&
+ (job->num_files > 1 || !strncmp(job->printer->device_uri, "file:", 5))))
+ {
+ /*
+ * Add gziptoany filter to the front of the list...
+ */
+
+ if (!filters)
+ filters = cupsArrayNew(NULL, NULL);
+
+ if (!cupsArrayInsert(filters, &gziptoany_filter))
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG,
+ "Unable to add decompression filter - %s", strerror(errno));
+
+ cupsArrayDelete(filters);
+
+ abort_message = "Stopping job because the scheduler ran out of memory.";
+
+ goto abort_job;
+ }
+ }
+
+ /*
+ * Add port monitor, if any...
+ */
+
+ if (job->printer->port_monitor)
+ {
+ /*
+ * Add port monitor to the end of the list...
+ */
+
+ if (!filters)
+ filters = cupsArrayNew(NULL, NULL);
+
+ port_monitor.src = NULL;
+ port_monitor.dst = NULL;
+ port_monitor.cost = 0;
+
+ snprintf(port_monitor.filter, sizeof(port_monitor.filter),
+ "%s/monitor/%s", ServerBin, job->printer->port_monitor);
+
+ if (!cupsArrayAdd(filters, &port_monitor))
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG,
+ "Unable to add port monitor - %s", strerror(errno));
+
+ abort_message = "Stopping job because the scheduler ran out of memory.";
+
+ goto abort_job;
+ }
+ }
+
+ /*
+ * Make sure we don't go over the "MAX_FILTERS" limit...
+ */
+
+ if (cupsArrayCount(filters) > MAX_FILTERS)
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG,
+ "Too many filters (%d > %d), unable to print!",
+ cupsArrayCount(filters), MAX_FILTERS);
+
+ abort_message = "Aborting job because it needs too many filters to print.";
+ abort_state = IPP_JOB_ABORTED;
+
+ goto abort_job;
+ }
+
+ /*
+ * Determine if we are printing a banner page or not...
+ */
+
+ if (job->job_sheets == NULL)
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "No job-sheets attribute.");
+ if ((job->job_sheets =
+ ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL)
+ cupsdLogJob(job, CUPSD_LOG_DEBUG,
+ "... but someone added one without setting job_sheets!");
+ }
+ else if (job->job_sheets->num_values == 1)
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "job-sheets=%s",
+ job->job_sheets->values[0].string.text);
+ else
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "job-sheets=%s,%s",
+ job->job_sheets->values[0].string.text,
+ job->job_sheets->values[1].string.text);
+
+ if (job->printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))
+ banner_page = 0;
+ else if (job->job_sheets == NULL)
+ banner_page = 0;
+ else if (_cups_strcasecmp(job->job_sheets->values[0].string.text, "none") != 0 &&
+ job->current_file == 0)
+ banner_page = 1;
+ else if (job->job_sheets->num_values > 1 &&
+ _cups_strcasecmp(job->job_sheets->values[1].string.text, "none") != 0 &&
+ job->current_file == (job->num_files - 1))
+ banner_page = 1;
+ else
+ banner_page = 0;
+
+ if ((options = get_options(job, banner_page, copies, sizeof(copies), title,
+ sizeof(title))) == NULL)
+ {
+ abort_message = "Stopping job because the scheduler ran out of memory.";
+
+ goto abort_job;
+ }
+
+ /*
+ * Build the command-line arguments for the filters. Each filter
+ * has 6 or 7 arguments:
+ *
+ * argv[0] = printer
+ * argv[1] = job ID
+ * argv[2] = username
+ * argv[3] = title
+ * argv[4] = # copies
+ * argv[5] = options
+ * argv[6] = filename (optional; normally stdin)
+ *
+ * This allows legacy printer drivers that use the old System V
+ * printing interface to be used by CUPS.
+ *
+ * For remote jobs, we send all of the files in the argument list.
+ */
+
+ if (job->printer->remote)
+ argv = calloc(7 + job->num_files, sizeof(char *));
+ else
+ argv = calloc(8, sizeof(char *));
+
+ if (!argv)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Unable to allocate argument array - %s",
+ strerror(errno));
+
+ abort_message = "Stopping job because the scheduler ran out of memory.";
+
+ goto abort_job;
+ }
+
+ sprintf(jobid, "%d", job->id);
+
+ argv[0] = job->printer->name;
+ argv[1] = jobid;
+ argv[2] = job->username;
+ argv[3] = title;
+ argv[4] = copies;
+ argv[5] = options;
+
+ if (job->printer->remote && job->num_files > 1)
+ {
+ for (i = 0; i < job->num_files; i ++)
+ {
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
+ job->id, i + 1);
+ argv[6 + i] = strdup(filename);
+ }
+ }
+ else
+ {
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
+ job->id, job->current_file + 1);
+ argv[6] = filename;
+ }
+
+ for (i = 0; argv[i]; i ++)
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "argv[%d]=\"%s\"", i, argv[i]);
+
+ /*
+ * Create environment variable strings for the filters...
+ */
+
+ attr = ippFindAttribute(job->attrs, "attributes-natural-language",
+ IPP_TAG_LANGUAGE);
+
+#ifdef __APPLE__
+ strcpy(apple_language, "APPLE_LANGUAGE=");
+ _cupsAppleLanguage(attr->values[0].string.text,
+ apple_language + 15, sizeof(apple_language) - 15);
+#endif /* __APPLE__ */
+
+ switch (strlen(attr->values[0].string.text))
+ {
+ default :
+ /*
+ * This is an unknown or badly formatted language code; use
+ * the POSIX locale...
+ */
+
+ strcpy(lang, "LANG=C");
+ break;
+
+ case 2 :
+ /*
+ * Just the language code (ll)...
+ */
+
+ snprintf(lang, sizeof(lang), "LANG=%s.UTF-8",
+ attr->values[0].string.text);
+ break;
+
+ case 5 :
+ /*
+ * Language and country code (ll-cc)...
+ */
+
+ snprintf(lang, sizeof(lang), "LANG=%c%c_%c%c.UTF-8",
+ attr->values[0].string.text[0],
+ attr->values[0].string.text[1],
+ toupper(attr->values[0].string.text[3] & 255),
+ toupper(attr->values[0].string.text[4] & 255));
+ break;
+ }
+
+ if ((attr = ippFindAttribute(job->attrs, "document-format",
+ IPP_TAG_MIMETYPE)) != NULL &&
+ (ptr = strstr(attr->values[0].string.text, "charset=")) != NULL)
+ snprintf(charset, sizeof(charset), "CHARSET=%s", ptr + 8);
+ else
+ strlcpy(charset, "CHARSET=utf-8", sizeof(charset));
+
+ snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s",
+ job->filetypes[job->current_file]->super,
+ job->filetypes[job->current_file]->type);
+ snprintf(device_uri, sizeof(device_uri), "DEVICE_URI=%s",
+ job->printer->device_uri);
+ snprintf(ppd, sizeof(ppd), "PPD=%s/ppd/%s.ppd", ServerRoot,
+ job->printer->name);
+ snprintf(printer_info, sizeof(printer_name), "PRINTER_INFO=%s",
+ job->printer->info ? job->printer->info : "");
+ snprintf(printer_location, sizeof(printer_name), "PRINTER_LOCATION=%s",
+ job->printer->location ? job->printer->location : "");
+ snprintf(printer_name, sizeof(printer_name), "PRINTER=%s", job->printer->name);
+ if (job->printer->num_reasons > 0)
+ {
+ char *psrptr; /* Pointer into PRINTER_STATE_REASONS */
+ size_t psrlen; /* Size of PRINTER_STATE_REASONS */
+
+ for (psrlen = 22, i = 0; i < job->printer->num_reasons; i ++)
+ psrlen += strlen(job->printer->reasons[i]) + 1;
+
+ if ((printer_state_reasons = malloc(psrlen)) != NULL)
+ {
+ /*
+ * All of these strcpy's are safe because we allocated the psr string...
+ */
+
+ strcpy(printer_state_reasons, "PRINTER_STATE_REASONS=");
+ for (psrptr = printer_state_reasons + 22, i = 0;
+ i < job->printer->num_reasons;
+ i ++)
+ {
+ if (i)
+ *psrptr++ = ',';
+ strcpy(psrptr, job->printer->reasons[i]);
+ psrptr += strlen(psrptr);
+ }
+ }
+ }
+ snprintf(rip_max_cache, sizeof(rip_max_cache), "RIP_MAX_CACHE=%s", RIPCache);
+
+ if (job->printer->num_auth_info_required == 1)
+ snprintf(auth_info_required, sizeof(auth_info_required),
+ "AUTH_INFO_REQUIRED=%s",
+ job->printer->auth_info_required[0]);
+ else if (job->printer->num_auth_info_required == 2)
+ snprintf(auth_info_required, sizeof(auth_info_required),
+ "AUTH_INFO_REQUIRED=%s,%s",
+ job->printer->auth_info_required[0],
+ job->printer->auth_info_required[1]);
+ else if (job->printer->num_auth_info_required == 3)
+ snprintf(auth_info_required, sizeof(auth_info_required),
+ "AUTH_INFO_REQUIRED=%s,%s,%s",
+ job->printer->auth_info_required[0],
+ job->printer->auth_info_required[1],
+ job->printer->auth_info_required[2]);
+ else if (job->printer->num_auth_info_required == 4)
+ snprintf(auth_info_required, sizeof(auth_info_required),
+ "AUTH_INFO_REQUIRED=%s,%s,%s,%s",
+ job->printer->auth_info_required[0],
+ job->printer->auth_info_required[1],
+ job->printer->auth_info_required[2],
+ job->printer->auth_info_required[3]);
+ else
+ strlcpy(auth_info_required, "AUTH_INFO_REQUIRED=none",
+ sizeof(auth_info_required));
+
+ envc = cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
+
+ envp[envc ++] = charset;
+ envp[envc ++] = lang;
+#ifdef __APPLE__
+ envp[envc ++] = apple_language;
+#endif /* __APPLE__ */
+ envp[envc ++] = ppd;
+ envp[envc ++] = rip_max_cache;
+ envp[envc ++] = content_type;
+ envp[envc ++] = device_uri;
+ envp[envc ++] = printer_info;
+ envp[envc ++] = printer_location;
+ envp[envc ++] = printer_name;
+ envp[envc ++] = printer_state_reasons ? printer_state_reasons :
+ "PRINTER_STATE_REASONS=none";
+ envp[envc ++] = banner_page ? "CUPS_FILETYPE=job-sheet" :
+ "CUPS_FILETYPE=document";
+
+ if (!job->printer->remote && !job->printer->raw)
+ {
+ filter = (mime_filter_t *)cupsArrayLast(filters);
+
+ if (job->printer->port_monitor)
+ filter = (mime_filter_t *)cupsArrayPrev(filters);
+
+ if (filter && filter->dst)
+ {
+ if ((ptr = strchr(filter->dst->type, '/')) != NULL)
+ snprintf(final_content_type, sizeof(final_content_type),
+ "FINAL_CONTENT_TYPE=%s", ptr + 1);
+ else
+ snprintf(final_content_type, sizeof(final_content_type),
+ "FINAL_CONTENT_TYPE=%s/%s", filter->dst->super,
+ filter->dst->type);
+ envp[envc ++] = final_content_type;
+ }
+ }
+
+ if (Classification && !banner_page)
+ {
+ if ((attr = ippFindAttribute(job->attrs, "job-sheets",
+ IPP_TAG_NAME)) == NULL)
+ snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
+ Classification);
+ else if (attr->num_values > 1 &&
+ strcmp(attr->values[1].string.text, "none") != 0)
+ snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
+ attr->values[1].string.text);
+ else
+ snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
+ attr->values[0].string.text);
+
+ envp[envc ++] = classification;
+ }
+
+ if (job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ {
+ snprintf(class_name, sizeof(class_name), "CLASS=%s", job->dest);
+ envp[envc ++] = class_name;
+ }
+
+ envp[envc ++] = auth_info_required;
+
+ for (i = 0;
+ i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]));
+ i ++)
+ if (job->auth_env[i])
+ envp[envc ++] = job->auth_env[i];
+ else
+ break;
+
+ if (job->auth_uid)
+ envp[envc ++] = job->auth_uid;
+
+ envp[envc] = NULL;
+
+ for (i = 0; i < envc; i ++)
+ if (!strncmp(envp[i], "AUTH_", 5))
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "envp[%d]=\"AUTH_%c****\"", i,
+ envp[i][5]);
+ else if (strncmp(envp[i], "DEVICE_URI=", 11))
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "envp[%d]=\"%s\"", i, envp[i]);
+ else
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "envp[%d]=\"DEVICE_URI=%s\"", i,
+ job->printer->sanitized_device_uri);
+
+ if (job->printer->remote)
+ job->current_file = job->num_files;
+ else
+ job->current_file ++;
+
+ /*
+ * Now create processes for all of the filters...
+ */
+
+ cupsdSetPrinterReasons(job->printer, "-cups-missing-filter-warning,"
+ "cups-insecure-filter-warning");
+
+ for (i = 0, slot = 0, filter = (mime_filter_t *)cupsArrayFirst(filters);
+ filter;
+ i ++, filter = (mime_filter_t *)cupsArrayNext(filters))
+ {
+ if (filter->filter[0] != '/')
+ snprintf(command, sizeof(command), "%s/filter/%s", ServerBin,
+ filter->filter);
+ else
+ strlcpy(command, filter->filter, sizeof(command));
+
+ if (i < (cupsArrayCount(filters) - 1))
+ {
+ if (cupsdOpenPipe(filterfds[slot]))
+ {
+ abort_message = "Stopping job because the scheduler could not create "
+ "the filter pipes.";
+
+ goto abort_job;
+ }
+ }
+ else
+ {
+ if (job->current_file == 1 ||
+ (job->printer->pc && job->printer->pc->single_file))
+ {
+ if (strncmp(job->printer->device_uri, "file:", 5) != 0)
+ {
+ if (cupsdOpenPipe(job->print_pipes))
+ {
+ abort_message = "Stopping job because the scheduler could not "
+ "create the backend pipes.";
+
+ goto abort_job;
+ }
+ }
+ else
+ {
+ job->print_pipes[0] = -1;
+ if (!strcmp(job->printer->device_uri, "file:/dev/null") ||
+ !strcmp(job->printer->device_uri, "file:///dev/null"))
+ job->print_pipes[1] = -1;
+ else
+ {
+ if (!strncmp(job->printer->device_uri, "file:/dev/", 10))
+ job->print_pipes[1] = open(job->printer->device_uri + 5,
+ O_WRONLY | O_EXCL);
+ else if (!strncmp(job->printer->device_uri, "file:///dev/", 12))
+ job->print_pipes[1] = open(job->printer->device_uri + 7,
+ O_WRONLY | O_EXCL);
+ else if (!strncmp(job->printer->device_uri, "file:///", 8))
+ job->print_pipes[1] = open(job->printer->device_uri + 7,
+ O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ else
+ job->print_pipes[1] = open(job->printer->device_uri + 5,
+ O_WRONLY | O_CREAT | O_TRUNC, 0600);
+
+ if (job->print_pipes[1] < 0)
+ {
+ abort_message = "Stopping job because the scheduler could not "
+ "open the output file.";
+
+ goto abort_job;
+ }
+
+ fcntl(job->print_pipes[1], F_SETFD,
+ fcntl(job->print_pipes[1], F_GETFD) | FD_CLOEXEC);
+ }
+ }
+ }
+
+ filterfds[slot][0] = job->print_pipes[0];
+ filterfds[slot][1] = job->print_pipes[1];
+ }
+
+ pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0],
+ filterfds[slot][1], job->status_pipes[1],
+ job->back_pipes[0], job->side_pipes[0], 0,
+ job->profile, job, job->filters + i);
+
+ cupsdClosePipe(filterfds[!slot]);
+
+ if (pid == 0)
+ {
+ cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to start filter \"%s\" - %s.",
+ filter->filter, strerror(errno));
+
+ abort_message = "Stopping job because the scheduler could not execute a "
+ "filter.";
+
+ goto abort_job;
+ }
+
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Started filter %s (PID %d)", command,
+ pid);
+
+ argv[6] = NULL;
+ slot = !slot;
+ }
+
+ cupsArrayDelete(filters);
+ filters = NULL;
+
+ /*
+ * Finally, pipe the final output into a backend process if needed...
+ */
+
+ if (strncmp(job->printer->device_uri, "file:", 5) != 0)
+ {
+ if (job->current_file == 1 || job->printer->remote ||
+ (job->printer->pc && job->printer->pc->single_file))
+ {
+ sscanf(job->printer->device_uri, "%254[^:]", scheme);
+ snprintf(command, sizeof(command), "%s/backend/%s", ServerBin, scheme);
+
+ /*
+ * See if the backend needs to run as root...
+ */
+
+ if (RunUser)
+ backroot = 0;
+ else if (stat(command, &backinfo))
+ backroot = 0;
+ else
+ backroot = !(backinfo.st_mode & (S_IRWXG | S_IRWXO));
+
+ argv[0] = job->printer->sanitized_device_uri;
+
+ filterfds[slot][0] = -1;
+ filterfds[slot][1] = -1;
+
+ pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0],
+ filterfds[slot][1], job->status_pipes[1],
+ job->back_pipes[1], job->side_pipes[1],
+ backroot, job->profile, job, &(job->backend));
+
+ if (pid == 0)
+ {
+ abort_message = "Stopping job because the sheduler could not execute "
+ "the backend.";
+
+ goto abort_job;
+ }
+ else
+ {
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Started backend %s (PID %d)",
+ command, pid);
+ }
+ }
+
+ if (job->current_file == job->num_files ||
+ (job->printer->pc && job->printer->pc->single_file))
+ cupsdClosePipe(job->print_pipes);
+
+ if (job->current_file == job->num_files)
+ {
+ cupsdClosePipe(job->back_pipes);
+ cupsdClosePipe(job->side_pipes);
+
+ close(job->status_pipes[1]);
+ job->status_pipes[1] = -1;
+ }
+ }
+ else
+ {
+ filterfds[slot][0] = -1;
+ filterfds[slot][1] = -1;
+
+ if (job->current_file == job->num_files ||
+ (job->printer->pc && job->printer->pc->single_file))
+ cupsdClosePipe(job->print_pipes);
+
+ if (job->current_file == job->num_files)
+ {
+ close(job->status_pipes[1]);
+ job->status_pipes[1] = -1;
+ }
+ }
+
+ cupsdClosePipe(filterfds[slot]);
+
+ if (job->printer->remote && job->num_files > 1)
+ {
+ for (i = 0; i < job->num_files; i ++)
+ free(argv[i + 6]);
+ }
+
+ free(argv);
+ if (printer_state_reasons)
+ free(printer_state_reasons);
+
+ cupsdAddSelect(job->status_buffer->fd, (cupsd_selfunc_t)update_job, NULL,
+ job);
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job, "Job #%d started.",
+ job->id);
+
+ return;
+
+
+ /*
+ * If we get here, we need to abort the current job and close out all
+ * files and pipes...
+ */
+
+ abort_job:
+
+ FilterLevel -= job->cost;
+ job->cost = 0;
+
+ for (slot = 0; slot < 2; slot ++)
+ cupsdClosePipe(filterfds[slot]);
+
+ cupsArrayDelete(filters);
+
+ if (argv)
+ {
+ if (job->printer->remote && job->num_files > 1)
+ {
+ for (i = 0; i < job->num_files; i ++)
+ free(argv[i + 6]);
+ }
+
+ free(argv);
+ }
+
+ if (printer_state_reasons)
+ free(printer_state_reasons);
+
+ cupsdClosePipe(job->print_pipes);
+ cupsdClosePipe(job->back_pipes);
+ cupsdClosePipe(job->side_pipes);
+
+ cupsdRemoveSelect(job->status_pipes[0]);
+ cupsdClosePipe(job->status_pipes);
+ cupsdStatBufDelete(job->status_buffer);
+ job->status_buffer = NULL;
+
+ /*
+ * Update the printer and job state.
+ */
+
+ cupsdSetJobState(job, abort_state, CUPSD_JOB_DEFAULT, "%s", abort_message);
+ cupsdSetPrinterState(job->printer, IPP_PRINTER_IDLE, 0);
+ update_job_attrs(job, 0);
+
+ if (job->history)
+ free_job_history(job);
+
+ cupsArrayRemove(PrintingJobs, job);
+
+ /*
+ * Clear the printer <-> job association...
+ */
+
+ job->printer->job = NULL;
+ job->printer = NULL;
+}
+
+
+/*
+ * 'cupsdDeleteJob()' - Free all memory used by a job.
+ */
+
+void
+cupsdDeleteJob(cupsd_job_t *job, /* I - Job */
+ cupsd_jobaction_t action)/* I - Action */
+{
+ int i; /* Looping var */
+ char filename[1024]; /* Job filename */
+
+
+ if (job->printer)
+ finalize_job(job, 1);
+
+ if (action == CUPSD_JOB_PURGE)
+ {
+ /*
+ * Remove the job info file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot,
+ job->id);
+ if (Classification)
+ cupsdRemoveFile(filename);
+ else
+ unlink(filename);
+ }
+
+ cupsdClearString(&job->username);
+ cupsdClearString(&job->dest);
+ for (i = 0;
+ i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]));
+ i ++)
+ cupsdClearString(job->auth_env + i);
+ cupsdClearString(&job->auth_uid);
+
+ if (job->num_files > 0)
+ {
+ free(job->compressions);
+ free(job->filetypes);
+
+ while (job->num_files > 0)
+ {
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
+ job->id, job->num_files);
+ if (Classification)
+ cupsdRemoveFile(filename);
+ else
+ unlink(filename);
+
+ job->num_files --;
+ }
+ }
+
+ if (job->history)
+ free_job_history(job);
+
+ unload_job(job);
+
+ cupsArrayRemove(Jobs, job);
+ cupsArrayRemove(ActiveJobs, job);
+ cupsArrayRemove(PrintingJobs, job);
+
+ free(job);
+}
+
+
+/*
+ * 'cupsdFreeAllJobs()' - Free all jobs from memory.
+ */
+
+void
+cupsdFreeAllJobs(void)
+{
+ cupsd_job_t *job; /* Current job */
+
+
+ if (!Jobs)
+ return;
+
+ cupsdHoldSignals();
+
+ cupsdStopAllJobs(CUPSD_JOB_FORCE, 0);
+ cupsdSaveAllJobs();
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(Jobs))
+ cupsdDeleteJob(job, CUPSD_JOB_DEFAULT);
+
+ cupsdReleaseSignals();
+}
+
+
+/*
+ * 'cupsdFindJob()' - Find the specified job.
+ */
+
+cupsd_job_t * /* O - Job data */
+cupsdFindJob(int id) /* I - Job ID */
+{
+ cupsd_job_t key; /* Search key */
+
+
+ key.id = id;
+
+ return ((cupsd_job_t *)cupsArrayFind(Jobs, &key));
+}
+
+
+/*
+ * 'cupsdGetPrinterJobCount()' - Get the number of pending, processing,
+ * or held jobs in a printer or class.
+ */
+
+int /* O - Job count */
+cupsdGetPrinterJobCount(
+ const char *dest) /* I - Printer or class name */
+{
+ int count; /* Job count */
+ cupsd_job_t *job; /* Current job */
+
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs), count = 0;
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
+ if (job->dest && !_cups_strcasecmp(job->dest, dest))
+ count ++;
+
+ return (count);
+}
+
+
+/*
+ * 'cupsdGetUserJobCount()' - Get the number of pending, processing,
+ * or held jobs for a user.
+ */
+
+int /* O - Job count */
+cupsdGetUserJobCount(
+ const char *username) /* I - Username */
+{
+ int count; /* Job count */
+ cupsd_job_t *job; /* Current job */
+
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs), count = 0;
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
+ if (!_cups_strcasecmp(job->username, username))
+ count ++;
+
+ return (count);
+}
+
+
+/*
+ * 'cupsdLoadAllJobs()' - Load all jobs from disk.
+ */
+
+void
+cupsdLoadAllJobs(void)
+{
+ char filename[1024]; /* Full filename of job.cache file */
+ struct stat fileinfo, /* Information on job.cache file */
+ dirinfo; /* Information on RequestRoot dir */
+
+
+
+ /*
+ * Create the job arrays as needed...
+ */
+
+ if (!Jobs)
+ Jobs = cupsArrayNew(compare_jobs, NULL);
+
+ if (!ActiveJobs)
+ ActiveJobs = cupsArrayNew(compare_active_jobs, NULL);
+
+ if (!PrintingJobs)
+ PrintingJobs = cupsArrayNew(compare_jobs, NULL);
+
+ /*
+ * See whether the job.cache file is older than the RequestRoot directory...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/job.cache", CacheDir);
+
+ if (stat(filename, &fileinfo))
+ {
+ fileinfo.st_mtime = 0;
+
+ if (errno != ENOENT)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to get file information for \"%s\" - %s",
+ filename, strerror(errno));
+ }
+
+ if (stat(RequestRoot, &dirinfo))
+ {
+ dirinfo.st_mtime = 0;
+
+ if (errno != ENOENT)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to get directory information for \"%s\" - %s",
+ RequestRoot, strerror(errno));
+ }
+
+ /*
+ * Load the most recent source for job data...
+ */
+
+ if (dirinfo.st_mtime > fileinfo.st_mtime)
+ {
+ load_request_root();
+
+ load_next_job_id(filename);
+ }
+ else
+ load_job_cache(filename);
+
+ /*
+ * Clean out old jobs as needed...
+ */
+
+ if (MaxJobs > 0 && cupsArrayCount(Jobs) >= MaxJobs)
+ cupsdCleanJobs();
+}
+
+
+/*
+ * 'cupsdLoadJob()' - Load a single job.
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsdLoadJob(cupsd_job_t *job) /* I - Job */
+{
+ int i; /* Looping var */
+ char jobfile[1024]; /* Job filename */
+ cups_file_t *fp; /* Job file */
+ int fileid; /* Current file ID */
+ ipp_attribute_t *attr; /* Job attribute */
+ const char *dest; /* Destination name */
+ cupsd_printer_t *destptr; /* Pointer to destination */
+ mime_type_t **filetypes; /* New filetypes array */
+ int *compressions; /* New compressions array */
+
+
+ if (job->attrs)
+ {
+ if (job->state_value > IPP_JOB_STOPPED)
+ job->access_time = time(NULL);
+
+ return (1);
+ }
+
+ if ((job->attrs = ippNew()) == NULL)
+ {
+ cupsdLogJob(job, CUPSD_LOG_ERROR, "Ran out of memory for job attributes!");
+ return (0);
+ }
+
+ /*
+ * Load job attributes...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] Loading attributes...", job->id);
+
+ snprintf(jobfile, sizeof(jobfile), "%s/c%05d", RequestRoot, job->id);
+ if ((fp = cupsFileOpen(jobfile, "r")) == NULL)
+ {
+ char newfile[1024]; /* New job filename */
+
+ snprintf(newfile, sizeof(newfile), "%s/c%05d.N", RequestRoot, job->id);
+ if ((fp = cupsFileOpen(newfile, "r")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Unable to open job control file \"%s\": %s",
+ job->id, jobfile, strerror(errno));
+ goto error;
+ }
+
+ unlink(jobfile);
+ rename(newfile, jobfile);
+ }
+
+ if (ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL, job->attrs) != IPP_DATA)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Unable to read job control file \"%s\".", job->id,
+ jobfile);
+ cupsFileClose(fp);
+ goto error;
+ }
+
+ cupsFileClose(fp);
+
+ /*
+ * Copy attribute data to the job object...
+ */
+
+ if (!ippFindAttribute(job->attrs, "time-at-creation", IPP_TAG_INTEGER))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Missing or bad time-at-creation attribute in "
+ "control file!", job->id);
+ goto error;
+ }
+
+ if ((job->state = ippFindAttribute(job->attrs, "job-state",
+ IPP_TAG_ENUM)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Missing or bad job-state attribute in control "
+ "file!", job->id);
+ goto error;
+ }
+
+ job->state_value = (ipp_jstate_t)job->state->values[0].integer;
+
+ if (!job->dest)
+ {
+ if ((attr = ippFindAttribute(job->attrs, "job-printer-uri",
+ IPP_TAG_URI)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] No job-printer-uri attribute in control file!",
+ job->id);
+ goto error;
+ }
+
+ if ((dest = cupsdValidateDest(attr->values[0].string.text, &(job->dtype),
+ &destptr)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Unable to queue job for destination \"%s\"!",
+ job->id, attr->values[0].string.text);
+ goto error;
+ }
+
+ cupsdSetString(&job->dest, dest);
+ }
+ else if ((destptr = cupsdFindDest(job->dest)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Unable to queue job for destination \"%s\"!",
+ job->id, job->dest);
+ goto error;
+ }
+
+ job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed",
+ IPP_TAG_INTEGER);
+ job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
+
+ if (!job->priority)
+ {
+ if ((attr = ippFindAttribute(job->attrs, "job-priority",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Missing or bad job-priority attribute in "
+ "control file!", job->id);
+ goto error;
+ }
+
+ job->priority = attr->values[0].integer;
+ }
+
+ if (!job->username)
+ {
+ if ((attr = ippFindAttribute(job->attrs, "job-originating-user-name",
+ IPP_TAG_NAME)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Missing or bad job-originating-user-name "
+ "attribute in control file!", job->id);
+ goto error;
+ }
+
+ cupsdSetString(&job->username, attr->values[0].string.text);
+ }
+
+ /*
+ * Set the job hold-until time and state...
+ */
+
+ if (job->state_value == IPP_JOB_HELD)
+ {
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
+ IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+
+ if (attr)
+ cupsdSetJobHoldUntil(job, attr->values[0].string.text, CUPSD_JOB_DEFAULT);
+ else
+ {
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ job->state_value = IPP_JOB_PENDING;
+ }
+ }
+ else if (job->state_value == IPP_JOB_PROCESSING)
+ {
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ job->state_value = IPP_JOB_PENDING;
+ }
+
+ if (!job->num_files)
+ {
+ /*
+ * Find all the d##### files...
+ */
+
+ for (fileid = 1; fileid < 10000; fileid ++)
+ {
+ snprintf(jobfile, sizeof(jobfile), "%s/d%05d-%03d", RequestRoot,
+ job->id, fileid);
+
+ if (access(jobfile, 0))
+ break;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "[Job %d] Auto-typing document file \"%s\"...", job->id,
+ jobfile);
+
+ if (fileid > job->num_files)
+ {
+ if (job->num_files == 0)
+ {
+ compressions = (int *)calloc(fileid, sizeof(int));
+ filetypes = (mime_type_t **)calloc(fileid, sizeof(mime_type_t *));
+ }
+ else
+ {
+ compressions = (int *)realloc(job->compressions,
+ sizeof(int) * fileid);
+ filetypes = (mime_type_t **)realloc(job->filetypes,
+ sizeof(mime_type_t *) *
+ fileid);
+ }
+
+ if (!compressions || !filetypes)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Ran out of memory for job file types!",
+ job->id);
+
+ ippDelete(job->attrs);
+ job->attrs = NULL;
+
+ if (compressions)
+ free(compressions);
+
+ if (filetypes)
+ free(filetypes);
+
+ if (job->compressions)
+ {
+ free(job->compressions);
+ job->compressions = NULL;
+ }
+
+ if (job->filetypes)
+ {
+ free(job->filetypes);
+ job->filetypes = NULL;
+ }
+
+ job->num_files = 0;
+ return (0);
+ }
+
+ job->compressions = compressions;
+ job->filetypes = filetypes;
+ job->num_files = fileid;
+ }
+
+ job->filetypes[fileid - 1] = mimeFileType(MimeDatabase, jobfile, NULL,
+ job->compressions + fileid - 1);
+
+ if (!job->filetypes[fileid - 1])
+ job->filetypes[fileid - 1] = mimeType(MimeDatabase, "application",
+ "vnd.cups-raw");
+ }
+ }
+
+ /*
+ * Load authentication information as needed...
+ */
+
+ if (job->state_value < IPP_JOB_STOPPED)
+ {
+ snprintf(jobfile, sizeof(jobfile), "%s/a%05d", RequestRoot, job->id);
+
+ for (i = 0;
+ i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]));
+ i ++)
+ cupsdClearString(job->auth_env + i);
+ cupsdClearString(&job->auth_uid);
+
+ if ((fp = cupsFileOpen(jobfile, "r")) != NULL)
+ {
+ int bytes; /* Size of auth data */
+ char line[255], /* Line from file */
+ data[255]; /* Decoded data */
+
+
+ for (i = 0;
+ i < destptr->num_auth_info_required &&
+ i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0])) &&
+ cupsFileGets(fp, line, sizeof(line));
+ i ++)
+ {
+ bytes = sizeof(data);
+ httpDecode64_2(data, &bytes, line);
+
+ if (!strcmp(destptr->auth_info_required[i], "username"))
+ cupsdSetStringf(job->auth_env + i, "AUTH_USERNAME=%s", data);
+ else if (!strcmp(destptr->auth_info_required[i], "domain"))
+ cupsdSetStringf(job->auth_env + i, "AUTH_DOMAIN=%s", data);
+ else if (!strcmp(destptr->auth_info_required[i], "password"))
+ cupsdSetStringf(job->auth_env + i, "AUTH_PASSWORD=%s", data);
+ else if (!strcmp(destptr->auth_info_required[i], "negotiate"))
+ cupsdSetStringf(job->auth_env + i, "AUTH_NEGOTIATE=%s", line);
+ }
+
+ if (cupsFileGets(fp, line, sizeof(line)) && isdigit(line[0] & 255))
+ cupsdSetStringf(&job->auth_uid, "AUTH_UID=%s", line);
+
+ cupsFileClose(fp);
+ }
+ }
+
+ job->access_time = time(NULL);
+ return (1);
+
+ /*
+ * If we get here then something bad happened...
+ */
+
+ error:
+
+ ippDelete(job->attrs);
+ job->attrs = NULL;
+
+ if (job->compressions)
+ {
+ free(job->compressions);
+ job->compressions = NULL;
+ }
+
+ if (job->filetypes)
+ {
+ free(job->filetypes);
+ job->filetypes = NULL;
+ }
+
+ job->num_files = 0;
+
+ if (Classification)
+ cupsdRemoveFile(jobfile);
+ else
+ unlink(jobfile);
+
+ return (0);
+}
+
+
+/*
+ * 'cupsdMoveJob()' - Move the specified job to a different destination.
+ */
+
+void
+cupsdMoveJob(cupsd_job_t *job, /* I - Job */
+ cupsd_printer_t *p) /* I - Destination printer or class */
+{
+ ipp_attribute_t *attr; /* job-printer-uri attribute */
+ const char *olddest; /* Old destination */
+ cupsd_printer_t *oldp; /* Old pointer */
+
+
+ /*
+ * Don't move completed jobs...
+ */
+
+ if (job->state_value > IPP_JOB_STOPPED)
+ return;
+
+ /*
+ * Get the old destination...
+ */
+
+ olddest = job->dest;
+
+ if (job->printer)
+ oldp = job->printer;
+ else
+ oldp = cupsdFindDest(olddest);
+
+ /*
+ * Change the destination information...
+ */
+
+ if (job->state_value > IPP_JOB_HELD)
+ cupsdSetJobState(job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT,
+ "Stopping job prior to move.");
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, oldp, job,
+ "Job #%d moved from %s to %s.", job->id, olddest,
+ p->name);
+
+ cupsdSetString(&job->dest, p->name);
+ job->dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE |
+ CUPS_PRINTER_IMPLICIT);
+
+ if ((attr = ippFindAttribute(job->attrs, "job-printer-uri",
+ IPP_TAG_URI)) != NULL)
+ cupsdSetString(&(attr->values[0].string.text), p->uri);
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job,
+ "Job #%d moved from %s to %s.", job->id, olddest,
+ p->name);
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+}
+
+
+/*
+ * 'cupsdReleaseJob()' - Release the specified job.
+ */
+
+void
+cupsdReleaseJob(cupsd_job_t *job) /* I - Job */
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReleaseJob(job=%p(%d))", job,
+ job->id);
+
+ if (job->state_value == IPP_JOB_HELD)
+ {
+ /*
+ * Add trailing banner as needed...
+ */
+
+ if (job->pending_timeout)
+ cupsdTimeoutJob(job);
+
+ cupsdSetJobState(job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT,
+ "Job released by user.");
+ }
+}
+
+
+/*
+ * 'cupsdRestartJob()' - Restart the specified job.
+ */
+
+void
+cupsdRestartJob(cupsd_job_t *job) /* I - Job */
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdRestartJob(job=%p(%d))", job,
+ job->id);
+
+ if (job->state_value == IPP_JOB_STOPPED || job->num_files)
+ cupsdSetJobState(job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT,
+ "Job restarted by user.");
+}
+
+
+/*
+ * 'cupsdSaveAllJobs()' - Save a summary of all jobs to disk.
+ */
+
+void
+cupsdSaveAllJobs(void)
+{
+ int i; /* Looping var */
+ cups_file_t *fp; /* job.cache file */
+ char filename[1024], /* job.cache filename */
+ temp[1024]; /* Temporary string */
+ cupsd_job_t *job; /* Current job */
+ time_t curtime; /* Current time */
+ struct tm *curdate; /* Current date */
+
+
+ snprintf(filename, sizeof(filename), "%s/job.cache", CacheDir);
+ if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm)) == NULL)
+ return;
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Saving job.cache...");
+
+ /*
+ * Write a small header to the file...
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+ strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
+
+ cupsFilePuts(fp, "# Job cache file for " CUPS_SVERSION "\n");
+ cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
+ cupsFilePrintf(fp, "NextJobId %d\n", NextJobId);
+
+ /*
+ * Write each job known to the system...
+ */
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(Jobs))
+ {
+ cupsFilePrintf(fp, "<Job %d>\n", job->id);
+ cupsFilePrintf(fp, "State %d\n", job->state_value);
+ cupsFilePrintf(fp, "Priority %d\n", job->priority);
+ cupsFilePrintf(fp, "HoldUntil %d\n", (int)job->hold_until);
+ cupsFilePrintf(fp, "Username %s\n", job->username);
+ cupsFilePrintf(fp, "Destination %s\n", job->dest);
+ cupsFilePrintf(fp, "DestType %d\n", job->dtype);
+ cupsFilePrintf(fp, "NumFiles %d\n", job->num_files);
+ for (i = 0; i < job->num_files; i ++)
+ cupsFilePrintf(fp, "File %d %s/%s %d\n", i + 1, job->filetypes[i]->super,
+ job->filetypes[i]->type, job->compressions[i]);
+ cupsFilePuts(fp, "</Job>\n");
+ }
+
+ cupsdCloseCreatedConfFile(fp, filename);
+}
+
+
+/*
+ * 'cupsdSaveJob()' - Save a job to disk.
+ */
+
+void
+cupsdSaveJob(cupsd_job_t *job) /* I - Job */
+{
+ char filename[1024], /* Job control filename */
+ newfile[1024]; /* New job control filename */
+ cups_file_t *fp; /* Job file */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSaveJob(job=%p(%d)): job->attrs=%p",
+ job, job->id, job->attrs);
+
+ snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, job->id);
+ snprintf(newfile, sizeof(newfile), "%s/c%05d.N", RequestRoot, job->id);
+
+ if ((fp = cupsFileOpen(newfile, "w")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Unable to create job control file \"%s\": %s",
+ job->id, newfile, strerror(errno));
+ return;
+ }
+
+ fchmod(cupsFileNumber(fp), 0600);
+ fchown(cupsFileNumber(fp), RunUser, Group);
+
+ job->attrs->state = IPP_IDLE;
+
+ if (ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL,
+ job->attrs) != IPP_DATA)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Unable to write job control file.", job->id);
+ cupsFileClose(fp);
+ unlink(newfile);
+ return;
+ }
+
+ if (cupsFileClose(fp))
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Unable to close job control file: %s",
+ job->id, strerror(errno));
+ else
+ {
+ unlink(filename);
+ if (rename(newfile, filename))
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Unable to finalize job control file: %s",
+ job->id, strerror(errno));
+ else
+ job->dirty = 0;
+ }
+}
+
+
+/*
+ * 'cupsdSetJobHoldUntil()' - Set the hold time for a job.
+ */
+
+void
+cupsdSetJobHoldUntil(cupsd_job_t *job, /* I - Job */
+ const char *when, /* I - When to resume */
+ int update)/* I - Update job-hold-until attr? */
+{
+ time_t curtime; /* Current time */
+ struct tm *curdate; /* Current date */
+ int hour; /* Hold hour */
+ int minute; /* Hold minute */
+ int second = 0; /* Hold second */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdSetJobHoldUntil(job=%p(%d), when=\"%s\", update=%d)",
+ job, job->id, when, update);
+
+ if (update)
+ {
+ /*
+ * Update the job-hold-until attribute...
+ */
+
+ ipp_attribute_t *attr; /* job-hold-until attribute */
+
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
+ IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+
+ if (attr)
+ cupsdSetString(&(attr->values[0].string.text), when);
+ else
+ attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-hold-until", NULL, when);
+
+ if (attr)
+ {
+ if (isdigit(when[0] & 255))
+ attr->value_tag = IPP_TAG_NAME;
+ else
+ attr->value_tag = IPP_TAG_KEYWORD;
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+ }
+ }
+
+ /*
+ * Update the hold time...
+ */
+
+ if (!strcmp(when, "indefinite") || !strcmp(when, "auth-info-required"))
+ {
+ /*
+ * Hold indefinitely...
+ */
+
+ job->hold_until = 0;
+ }
+ else if (!strcmp(when, "day-time"))
+ {
+ /*
+ * Hold to 6am the next morning unless local time is < 6pm.
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+
+ if (curdate->tm_hour < 18)
+ job->hold_until = curtime;
+ else
+ job->hold_until = curtime +
+ ((29 - curdate->tm_hour) * 60 + 59 -
+ curdate->tm_min) * 60 + 60 - curdate->tm_sec;
+ }
+ else if (!strcmp(when, "evening") || !strcmp(when, "night"))
+ {
+ /*
+ * Hold to 6pm unless local time is > 6pm or < 6am.
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+
+ if (curdate->tm_hour < 6 || curdate->tm_hour >= 18)
+ job->hold_until = curtime;
+ else
+ job->hold_until = curtime +
+ ((17 - curdate->tm_hour) * 60 + 59 -
+ curdate->tm_min) * 60 + 60 - curdate->tm_sec;
+ }
+ else if (!strcmp(when, "second-shift"))
+ {
+ /*
+ * Hold to 4pm unless local time is > 4pm.
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+
+ if (curdate->tm_hour >= 16)
+ job->hold_until = curtime;
+ else
+ job->hold_until = curtime +
+ ((15 - curdate->tm_hour) * 60 + 59 -
+ curdate->tm_min) * 60 + 60 - curdate->tm_sec;
+ }
+ else if (!strcmp(when, "third-shift"))
+ {
+ /*
+ * Hold to 12am unless local time is < 8am.
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+
+ if (curdate->tm_hour < 8)
+ job->hold_until = curtime;
+ else
+ job->hold_until = curtime +
+ ((23 - curdate->tm_hour) * 60 + 59 -
+ curdate->tm_min) * 60 + 60 - curdate->tm_sec;
+ }
+ else if (!strcmp(when, "weekend"))
+ {
+ /*
+ * Hold to weekend unless we are in the weekend.
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+
+ if (curdate->tm_wday == 0 || curdate->tm_wday == 6)
+ job->hold_until = curtime;
+ else
+ job->hold_until = curtime +
+ (((5 - curdate->tm_wday) * 24 +
+ (17 - curdate->tm_hour)) * 60 + 59 -
+ curdate->tm_min) * 60 + 60 - curdate->tm_sec;
+ }
+ else if (sscanf(when, "%d:%d:%d", &hour, &minute, &second) >= 2)
+ {
+ /*
+ * Hold to specified GMT time (HH:MM or HH:MM:SS)...
+ */
+
+ curtime = time(NULL);
+ curdate = gmtime(&curtime);
+
+ job->hold_until = curtime +
+ ((hour - curdate->tm_hour) * 60 + minute -
+ curdate->tm_min) * 60 + second - curdate->tm_sec;
+
+ /*
+ * Hold until next day as needed...
+ */
+
+ if (job->hold_until < curtime)
+ job->hold_until += 24 * 60 * 60;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSetJobHoldUntil: hold_until=%d",
+ (int)job->hold_until);
+}
+
+
+/*
+ * 'cupsdSetJobPriority()' - Set the priority of a job, moving it up/down in
+ * the list as needed.
+ */
+
+void
+cupsdSetJobPriority(
+ cupsd_job_t *job, /* I - Job ID */
+ int priority) /* I - New priority (0 to 100) */
+{
+ ipp_attribute_t *attr; /* Job attribute */
+
+
+ /*
+ * Don't change completed jobs...
+ */
+
+ if (job->state_value >= IPP_JOB_PROCESSING)
+ return;
+
+ /*
+ * Set the new priority and re-add the job into the active list...
+ */
+
+ cupsArrayRemove(ActiveJobs, job);
+
+ job->priority = priority;
+
+ if ((attr = ippFindAttribute(job->attrs, "job-priority",
+ IPP_TAG_INTEGER)) != NULL)
+ attr->values[0].integer = priority;
+ else
+ ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority",
+ priority);
+
+ cupsArrayAdd(ActiveJobs, job);
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+}
+
+
+/*
+ * 'cupsdSetJobState()' - Set the state of the specified print job.
+ */
+
+void
+cupsdSetJobState(
+ cupsd_job_t *job, /* I - Job to cancel */
+ ipp_jstate_t newstate, /* I - New job state */
+ cupsd_jobaction_t action, /* I - Action to take */
+ const char *message, /* I - Message to log */
+ ...) /* I - Additional arguments as needed */
+{
+ int i; /* Looping var */
+ ipp_jstate_t oldstate; /* Old state */
+ char filename[1024]; /* Job filename */
+ ipp_attribute_t *attr; /* Job attribute */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdSetJobState(job=%p(%d), state=%d, newstate=%d, "
+ "action=%d, message=\"%s\")", job, job->id, job->state_value,
+ newstate, action, message ? message : "(null)");
+
+
+ /*
+ * Make sure we have the job attributes...
+ */
+
+ if (!cupsdLoadJob(job))
+ return;
+
+ /*
+ * Don't do anything if the state is unchanged and we aren't purging the
+ * job...
+ */
+
+ oldstate = job->state_value;
+ if (newstate == oldstate && action != CUPSD_JOB_PURGE)
+ return;
+
+ /*
+ * Stop any processes that are working on the current job...
+ */
+
+ if (oldstate == IPP_JOB_PROCESSING)
+ stop_job(job, action);
+
+ /*
+ * Set the new job state...
+ */
+
+ job->state->values[0].integer = newstate;
+ job->state_value = newstate;
+
+ switch (newstate)
+ {
+ case IPP_JOB_PENDING :
+ /*
+ * Update job-hold-until as needed...
+ */
+
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
+ IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+
+ if (attr)
+ {
+ attr->value_tag = IPP_TAG_KEYWORD;
+ cupsdSetString(&(attr->values[0].string.text), "no-hold");
+ }
+
+ default :
+ break;
+
+ case IPP_JOB_ABORTED :
+ case IPP_JOB_CANCELED :
+ case IPP_JOB_COMPLETED :
+ set_time(job, "time-at-completed");
+ break;
+ }
+
+ /*
+ * Log message as needed...
+ */
+
+ if (message)
+ {
+ char buffer[2048]; /* Message buffer */
+ va_list ap; /* Pointer to additional arguments */
+
+ va_start(ap, message);
+ vsnprintf(buffer, sizeof(buffer), message, ap);
+ va_end(ap);
+
+ if (newstate > IPP_JOB_STOPPED)
+ cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, "%s", buffer);
+ else
+ cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job, "%s", buffer);
+
+ if (newstate == IPP_JOB_STOPPED || newstate == IPP_JOB_ABORTED)
+ cupsdLogJob(job, CUPSD_LOG_ERROR, "%s", buffer);
+ else
+ cupsdLogJob(job, CUPSD_LOG_INFO, "%s", buffer);
+ }
+
+ /*
+ * Handle post-state-change actions...
+ */
+
+ switch (newstate)
+ {
+ case IPP_JOB_PROCESSING :
+ /*
+ * Add the job to the "printing" list...
+ */
+
+ if (!cupsArrayFind(PrintingJobs, job))
+ cupsArrayAdd(PrintingJobs, job);
+
+ /*
+ * Set the processing time...
+ */
+
+ set_time(job, "time-at-processing");
+
+ case IPP_JOB_PENDING :
+ case IPP_JOB_HELD :
+ case IPP_JOB_STOPPED :
+ /*
+ * Make sure the job is in the active list...
+ */
+
+ if (!cupsArrayFind(ActiveJobs, job))
+ cupsArrayAdd(ActiveJobs, job);
+
+ /*
+ * Save the job state to disk...
+ */
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+ break;
+
+ case IPP_JOB_ABORTED :
+ case IPP_JOB_CANCELED :
+ case IPP_JOB_COMPLETED :
+ if (newstate == IPP_JOB_CANCELED)
+ {
+ /*
+ * Remove the job from the active list if there are no processes still
+ * running for it...
+ */
+
+ for (i = 0; job->filters[i] < 0; i++);
+
+ if (!job->filters[i] && job->backend <= 0)
+ cupsArrayRemove(ActiveJobs, job);
+ }
+ else
+ {
+ /*
+ * Otherwise just remove the job from the active list immediately...
+ */
+
+ cupsArrayRemove(ActiveJobs, job);
+ }
+
+ /*
+ * Expire job subscriptions since the job is now "completed"...
+ */
+
+ cupsdExpireSubscriptions(NULL, job);
+
+#ifdef __APPLE__
+ /*
+ * If we are going to sleep and the PrintingJobs count is now 0, allow the
+ * sleep to happen immediately...
+ */
+
+ if (Sleeping && cupsArrayCount(PrintingJobs) == 0)
+ cupsdAllowSleep();
+#endif /* __APPLE__ */
+
+ /*
+ * Remove any authentication data...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/a%05d", RequestRoot, job->id);
+ if (cupsdRemoveFile(filename) && errno != ENOENT)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to remove authentication cache: %s",
+ strerror(errno));
+
+ for (i = 0;
+ i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]));
+ i ++)
+ cupsdClearString(job->auth_env + i);
+
+ cupsdClearString(&job->auth_uid);
+
+ /*
+ * Remove the print file for good if we aren't preserving jobs or
+ * files...
+ */
+
+ if (!JobHistory || !JobFiles || action == CUPSD_JOB_PURGE)
+ {
+ for (i = 1; i <= job->num_files; i ++)
+ {
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
+ job->id, i);
+ if (Classification)
+ cupsdRemoveFile(filename);
+ else
+ unlink(filename);
+ }
+
+ if (job->num_files > 0)
+ {
+ free(job->filetypes);
+ free(job->compressions);
+
+ job->num_files = 0;
+ job->filetypes = NULL;
+ job->compressions = NULL;
+ }
+ }
+
+ if (JobHistory && action != CUPSD_JOB_PURGE)
+ {
+ /*
+ * Save job state info...
+ */
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+ }
+ else if (!job->printer)
+ {
+ /*
+ * Delete the job immediately if not actively printing...
+ */
+
+ cupsdDeleteJob(job, CUPSD_JOB_PURGE);
+ job = NULL;
+ }
+ break;
+ }
+
+ /*
+ * Finalize the job immediately if we forced things...
+ */
+
+ if (action >= CUPSD_JOB_FORCE && job && job->printer)
+ finalize_job(job, 0);
+
+ /*
+ * Update the server "busy" state...
+ */
+
+ cupsdSetBusyState();
+}
+
+
+/*
+ * 'cupsdStopAllJobs()' - Stop all print jobs.
+ */
+
+void
+cupsdStopAllJobs(
+ cupsd_jobaction_t action, /* I - Action */
+ int kill_delay) /* I - Number of seconds before we kill */
+{
+ cupsd_job_t *job; /* Current job */
+
+
+ DEBUG_puts("cupsdStopAllJobs()");
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(PrintingJobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(PrintingJobs))
+ {
+ if (kill_delay)
+ job->kill_time = time(NULL) + kill_delay;
+
+ cupsdSetJobState(job, IPP_JOB_PENDING, action, NULL);
+ }
+}
+
+
+/*
+ * 'cupsdUnloadCompletedJobs()' - Flush completed job history from memory.
+ */
+
+void
+cupsdUnloadCompletedJobs(void)
+{
+ cupsd_job_t *job; /* Current job */
+ time_t expire; /* Expiration time */
+
+
+ expire = time(NULL) - 60;
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(Jobs))
+ if (job->attrs && job->state_value >= IPP_JOB_STOPPED && !job->printer &&
+ job->access_time < expire)
+ {
+ if (job->dirty)
+ cupsdSaveJob(job);
+
+ unload_job(job);
+ }
+}
+
+
+/*
+ * 'compare_active_jobs()' - Compare the job IDs and priorities of two jobs.
+ */
+
+static int /* O - Difference */
+compare_active_jobs(void *first, /* I - First job */
+ void *second, /* I - Second job */
+ void *data) /* I - App data (not used) */
+{
+ int diff; /* Difference */
+
+
+ (void)data;
+
+ if ((diff = ((cupsd_job_t *)second)->priority -
+ ((cupsd_job_t *)first)->priority) != 0)
+ return (diff);
+ else
+ return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id);
+}
+
+
+/*
+ * 'compare_jobs()' - Compare the job IDs of two jobs.
+ */
+
+static int /* O - Difference */
+compare_jobs(void *first, /* I - First job */
+ void *second, /* I - Second job */
+ void *data) /* I - App data (not used) */
+{
+ (void)data;
+
+ return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id);
+}
+
+
+/*
+ * 'dump_job_history()' - Dump any debug messages for a job.
+ */
+
+static void
+dump_job_history(cupsd_job_t *job) /* I - Job */
+{
+ int i, /* Looping var */
+ oldsize; /* Current MaxLogSize */
+ struct tm *date; /* Date/time value */
+ cupsd_joblog_t *message; /* Current message */
+ char temp[2048], /* Log message */
+ *ptr, /* Pointer into log message */
+ start[256], /* Start time */
+ end[256]; /* End time */
+ cupsd_printer_t *printer; /* Printer for job */
+
+
+ /*
+ * See if we have anything to dump...
+ */
+
+ if (!job->history)
+ return;
+
+ /*
+ * Disable log rotation temporarily...
+ */
+
+ oldsize = MaxLogSize;
+ MaxLogSize = 0;
+
+ /*
+ * Copy the debug messages to the log...
+ */
+
+ message = (cupsd_joblog_t *)cupsArrayFirst(job->history);
+ date = localtime(&(message->time));
+ strftime(start, sizeof(start), "%X", date);
+
+ message = (cupsd_joblog_t *)cupsArrayLast(job->history);
+ date = localtime(&(message->time));
+ strftime(end, sizeof(end), "%X", date);
+
+ snprintf(temp, sizeof(temp),
+ "[Job %d] The following messages were recorded from %s to %s",
+ job->id, start, end);
+ cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
+
+ for (message = (cupsd_joblog_t *)cupsArrayFirst(job->history);
+ message;
+ message = (cupsd_joblog_t *)cupsArrayNext(job->history))
+ cupsdWriteErrorLog(CUPSD_LOG_DEBUG, message->message);
+
+ snprintf(temp, sizeof(temp), "[Job %d] End of messages", job->id);
+ cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
+
+ /*
+ * Log the printer state values...
+ */
+
+ if ((printer = job->printer) == NULL)
+ printer = cupsdFindDest(job->dest);
+
+ if (printer)
+ {
+ snprintf(temp, sizeof(temp), "[Job %d] printer-state=%d(%s)", job->id,
+ printer->state,
+ printer->state == IPP_PRINTER_IDLE ? "idle" :
+ printer->state == IPP_PRINTER_PROCESSING ? "processing" :
+ "stopped");
+ cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
+
+ snprintf(temp, sizeof(temp), "[Job %d] printer-state-message=\"%s\"",
+ job->id, printer->state_message);
+ cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
+
+ snprintf(temp, sizeof(temp), "[Job %d] printer-state-reasons=", job->id);
+ ptr = temp + strlen(temp);
+ if (printer->num_reasons == 0)
+ strlcpy(ptr, "none", sizeof(temp) - (ptr - temp));
+ else
+ {
+ for (i = 0;
+ i < printer->num_reasons && ptr < (temp + sizeof(temp) - 2);
+ i ++)
+ {
+ if (i)
+ *ptr++ = ',';
+
+ strlcpy(ptr, printer->reasons[i], sizeof(temp) - (ptr - temp));
+ ptr += strlen(ptr);
+ }
+ }
+ cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
+ }
+
+ /*
+ * Restore log file rotation...
+ */
+
+ MaxLogSize = oldsize;
+
+ /*
+ * Free all messages...
+ */
+
+ free_job_history(job);
+}
+
+
+/*
+ * 'free_job_history()' - Free any log history.
+ */
+
+static void
+free_job_history(cupsd_job_t *job) /* I - Job */
+{
+ char *message; /* Current message */
+
+
+ if (!job->history)
+ return;
+
+ for (message = (char *)cupsArrayFirst(job->history);
+ message;
+ message = (char *)cupsArrayNext(job->history))
+ free(message);
+
+ cupsArrayDelete(job->history);
+ job->history = NULL;
+}
+
+
+/*
+ * 'finalize_job()' - Cleanup after job filter processes and support data.
+ */
+
+static void
+finalize_job(cupsd_job_t *job, /* I - Job */
+ int set_job_state) /* I - 1 = set the job state */
+{
+ ipp_pstate_t printer_state; /* New printer state value */
+ ipp_jstate_t job_state; /* New job state value */
+ const char *message; /* Message for job state */
+ char buffer[1024]; /* Buffer for formatted messages */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "finalize_job(job=%p(%d))", job, job->id);
+
+ /*
+ * Clear the "connecting-to-device" reason, which is only valid when a printer
+ * is processing, along with any remote printing job state...
+ */
+
+ cupsdSetPrinterReasons(job->printer, "-connecting-to-device,"
+ "cups-remote-pending,"
+ "cups-remote-pending-held,"
+ "cups-remote-processing,"
+ "cups-remote-stopped,"
+ "cups-remote-canceled,"
+ "cups-remote-aborted,"
+ "cups-remote-completed");
+
+ /*
+ * Similarly, clear the "offline-report" reason for non-USB devices since we
+ * rarely have current information for network devices...
+ */
+
+ if (strncmp(job->printer->device_uri, "usb:", 4))
+ cupsdSetPrinterReasons(job->printer, "-offline-report");
+
+ /*
+ * Free the security profile...
+ */
+
+ cupsdDestroyProfile(job->profile);
+ job->profile = NULL;
+
+ /*
+ * Clear the unresponsive job watchdog timer...
+ */
+
+ job->kill_time = 0;
+
+ /*
+ * Close pipes and status buffer...
+ */
+
+ cupsdClosePipe(job->print_pipes);
+ cupsdClosePipe(job->back_pipes);
+ cupsdClosePipe(job->side_pipes);
+
+ cupsdRemoveSelect(job->status_pipes[0]);
+ cupsdClosePipe(job->status_pipes);
+ cupsdStatBufDelete(job->status_buffer);
+ job->status_buffer = NULL;
+
+ /*
+ * Process the exit status...
+ */
+
+ if (job->printer->state == IPP_PRINTER_PROCESSING)
+ printer_state = IPP_PRINTER_IDLE;
+ else
+ printer_state = job->printer->state;
+
+ switch (job_state = job->state_value)
+ {
+ case IPP_JOB_PENDING :
+ message = "Job paused.";
+ break;
+
+ case IPP_JOB_HELD :
+ message = "Job held.";
+ break;
+
+ default :
+ case IPP_JOB_PROCESSING :
+ case IPP_JOB_COMPLETED :
+ job_state = IPP_JOB_COMPLETED;
+ message = "Job completed.";
+ break;
+
+ case IPP_JOB_STOPPED :
+ message = "Job stopped.";
+ break;
+
+ case IPP_JOB_CANCELED :
+ message = "Job canceled.";
+ break;
+
+ case IPP_JOB_ABORTED :
+ message = "Job aborted.";
+ break;
+ }
+
+ if (job->status < 0)
+ {
+ /*
+ * Backend had errors...
+ */
+
+ int exit_code; /* Exit code from backend */
+
+
+ /*
+ * Convert the status to an exit code. Due to the way the W* macros are
+ * implemented on MacOS X (bug?), we have to store the exit status in a
+ * variable first and then convert...
+ */
+
+ exit_code = -job->status;
+ if (WIFEXITED(exit_code))
+ exit_code = WEXITSTATUS(exit_code);
+ else
+ exit_code = job->status;
+
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Backend returned status %d (%s)",
+ exit_code,
+ exit_code == CUPS_BACKEND_FAILED ? "failed" :
+ exit_code == CUPS_BACKEND_AUTH_REQUIRED ?
+ "authentication required" :
+ exit_code == CUPS_BACKEND_HOLD ? "hold job" :
+ exit_code == CUPS_BACKEND_STOP ? "stop printer" :
+ exit_code == CUPS_BACKEND_CANCEL ? "cancel job" :
+ exit_code < 0 ? "crashed" : "unknown");
+
+ /*
+ * Do what needs to be done...
+ */
+
+ switch (exit_code)
+ {
+ default :
+ case CUPS_BACKEND_FAILED :
+ /*
+ * Backend failure, use the error-policy to determine how to
+ * act...
+ */
+
+ if (job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ {
+ /*
+ * Queued on a class - mark the job as pending and we'll retry on
+ * another printer...
+ */
+
+ if (job_state == IPP_JOB_COMPLETED)
+ {
+ job_state = IPP_JOB_PENDING;
+ message = "Retrying job on another printer.";
+ }
+ }
+ else if (!strcmp(job->printer->error_policy, "retry-current-job"))
+ {
+ /*
+ * The error policy is "retry-current-job" - mark the job as pending
+ * and we'll retry on the same printer...
+ */
+
+ if (job_state == IPP_JOB_COMPLETED)
+ {
+ job_state = IPP_JOB_PENDING;
+ message = "Retrying job on same printer.";
+ }
+ }
+ else if ((job->printer->type & CUPS_PRINTER_FAX) ||
+ !strcmp(job->printer->error_policy, "retry-job"))
+ {
+ if (job_state == IPP_JOB_COMPLETED)
+ {
+ /*
+ * The job was queued on a fax or the error policy is "retry-job" -
+ * hold the job if the number of retries is less than the
+ * JobRetryLimit, otherwise abort the job.
+ */
+
+ job->tries ++;
+
+ if (job->tries > JobRetryLimit && JobRetryLimit > 0)
+ {
+ /*
+ * Too many tries...
+ */
+
+ snprintf(buffer, sizeof(buffer),
+ "Job aborted after %d unsuccessful attempts.",
+ JobRetryLimit);
+ job_state = IPP_JOB_ABORTED;
+ message = buffer;
+ }
+ else
+ {
+ /*
+ * Try again in N seconds...
+ */
+
+ snprintf(buffer, sizeof(buffer),
+ "Job held for %d seconds since it could not be sent.",
+ JobRetryInterval);
+
+ job->hold_until = time(NULL) + JobRetryInterval;
+ job_state = IPP_JOB_HELD;
+ message = buffer;
+ }
+ }
+ }
+ else if (!strcmp(job->printer->error_policy, "abort-job") &&
+ job_state == IPP_JOB_COMPLETED)
+ {
+ job_state = IPP_JOB_ABORTED;
+ message = "Job aborted due to backend errors; please consult "
+ "the error_log file for details.";
+ }
+ else if (job->state_value == IPP_JOB_PROCESSING)
+ {
+ job_state = IPP_JOB_PENDING;
+ printer_state = IPP_PRINTER_STOPPED;
+ message = "Printer stopped due to backend errors; please "
+ "consult the error_log file for details.";
+ }
+ break;
+
+ case CUPS_BACKEND_CANCEL :
+ /*
+ * Abort the job...
+ */
+
+ if (job_state == IPP_JOB_COMPLETED)
+ {
+ job_state = IPP_JOB_ABORTED;
+ message = "Job aborted due to backend errors; please consult "
+ "the error_log file for details.";
+ }
+ break;
+
+ case CUPS_BACKEND_HOLD :
+ if (job_state == IPP_JOB_COMPLETED)
+ {
+ /*
+ * Hold the job...
+ */
+
+ cupsdSetJobHoldUntil(job, "indefinite", 1);
+
+ job_state = IPP_JOB_HELD;
+ message = "Job held indefinitely due to backend errors; please "
+ "consult the error_log file for details.";
+ }
+ break;
+
+ case CUPS_BACKEND_STOP :
+ /*
+ * Stop the printer...
+ */
+
+ printer_state = IPP_PRINTER_STOPPED;
+ message = "Printer stopped due to backend errors; please "
+ "consult the error_log file for details.";
+
+ if (job_state == IPP_JOB_COMPLETED)
+ job_state = IPP_JOB_PENDING;
+ break;
+
+ case CUPS_BACKEND_AUTH_REQUIRED :
+ /*
+ * Hold the job for authentication...
+ */
+
+ if (job_state == IPP_JOB_COMPLETED)
+ {
+ cupsdSetJobHoldUntil(job, "auth-info-required", 1);
+
+ job_state = IPP_JOB_HELD;
+ message = "Job held for authentication.";
+ }
+ break;
+
+ case CUPS_BACKEND_RETRY :
+ if (job_state == IPP_JOB_COMPLETED)
+ {
+ /*
+ * Hold the job if the number of retries is less than the
+ * JobRetryLimit, otherwise abort the job.
+ */
+
+ job->tries ++;
+
+ if (job->tries > JobRetryLimit && JobRetryLimit > 0)
+ {
+ /*
+ * Too many tries...
+ */
+
+ snprintf(buffer, sizeof(buffer),
+ "Job aborted after %d unsuccessful attempts.",
+ JobRetryLimit);
+ job_state = IPP_JOB_ABORTED;
+ message = buffer;
+ }
+ else
+ {
+ /*
+ * Try again in N seconds...
+ */
+
+ snprintf(buffer, sizeof(buffer),
+ "Job held for %d seconds since it could not be sent.",
+ JobRetryInterval);
+
+ job->hold_until = time(NULL) + JobRetryInterval;
+ job_state = IPP_JOB_HELD;
+ message = buffer;
+ }
+ }
+ break;
+
+ case CUPS_BACKEND_RETRY_CURRENT :
+ /*
+ * Mark the job as pending and retry on the same printer...
+ */
+
+ if (job_state == IPP_JOB_COMPLETED)
+ {
+ job_state = IPP_JOB_PENDING;
+ message = "Retrying job on same printer.";
+ }
+ break;
+ }
+ }
+ else if (job->status > 0)
+ {
+ /*
+ * Filter had errors; stop job...
+ */
+
+ if (job_state == IPP_JOB_COMPLETED)
+ {
+ job_state = IPP_JOB_STOPPED;
+ message = "Job stopped due to filter errors; please consult the "
+ "error_log file for details.";
+ }
+ }
+
+ /*
+ * Update the printer and job state.
+ */
+
+ if (set_job_state && job_state != job->state_value)
+ cupsdSetJobState(job, job_state, CUPSD_JOB_DEFAULT, "%s", message);
+
+ cupsdSetPrinterState(job->printer, printer_state,
+ printer_state == IPP_PRINTER_STOPPED);
+ update_job_attrs(job, 0);
+
+ if (job->history)
+ {
+ if (job->status)
+ dump_job_history(job);
+ else
+ free_job_history(job);
+ }
+
+ cupsArrayRemove(PrintingJobs, job);
+
+ /*
+ * Clear the printer <-> job association...
+ */
+
+ job->printer->job = NULL;
+ job->printer = NULL;
+
+ /*
+ * Try printing another job...
+ */
+
+ if (printer_state != IPP_PRINTER_STOPPED)
+ cupsdCheckJobs();
+}
+
+
+/*
+ * 'get_options()' - Get a string containing the job options.
+ */
+
+static char * /* O - Options string */
+get_options(cupsd_job_t *job, /* I - Job */
+ int banner_page, /* I - Printing a banner page? */
+ char *copies, /* I - Copies buffer */
+ size_t copies_size, /* I - Size of copies buffer */
+ char *title, /* I - Title buffer */
+ size_t title_size) /* I - Size of title buffer */
+{
+ int i; /* Looping var */
+ size_t newlength; /* New option buffer length */
+ char *optptr, /* Pointer to options */
+ *valptr; /* Pointer in value string */
+ ipp_attribute_t *attr; /* Current attribute */
+ _ppd_cache_t *pc; /* PPD cache and mapping data */
+ int num_pwgppds; /* Number of PWG->PPD options */
+ cups_option_t *pwgppds, /* PWG->PPD options */
+ *pwgppd, /* Current PWG->PPD option */
+ *preset; /* Current preset option */
+ int print_color_mode,
+ /* Output mode (if any) */
+ print_quality; /* Print quality (if any) */
+ const char *ppd; /* PPD option choice */
+ int exact; /* Did we get an exact match? */
+ static char *options = NULL;/* Full list of options */
+ static size_t optlength = 0; /* Length of option buffer */
+
+
+ /*
+ * Building the options string is harder than it needs to be, but for the
+ * moment we need to pass strings for command-line args and not IPP attribute
+ * pointers... :)
+ *
+ * First build an options array for any PWG->PPD mapped option/choice pairs.
+ */
+
+ pc = job->printer->pc;
+ num_pwgppds = 0;
+ pwgppds = NULL;
+
+ if (pc &&
+ !ippFindAttribute(job->attrs,
+ "com.apple.print.DocumentTicket.PMSpoolFormat",
+ IPP_TAG_ZERO) &&
+ !ippFindAttribute(job->attrs, "APPrinterPreset", IPP_TAG_ZERO) &&
+ (ippFindAttribute(job->attrs, "output-mode", IPP_TAG_ZERO) ||
+ ippFindAttribute(job->attrs, "print-color-mode", IPP_TAG_ZERO) ||
+ ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ZERO)))
+ {
+ /*
+ * Map output-mode and print-quality to a preset...
+ */
+
+ if ((attr = ippFindAttribute(job->attrs, "print-color-mode",
+ IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "output-mode", IPP_TAG_KEYWORD);
+
+ if (attr && !strcmp(attr->values[0].string.text, "monochrome"))
+ print_color_mode = _PWG_PRINT_COLOR_MODE_MONOCHROME;
+ else
+ print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
+
+ if ((attr = ippFindAttribute(job->attrs, "print-quality",
+ IPP_TAG_ENUM)) != NULL &&
+ attr->values[0].integer >= IPP_QUALITY_DRAFT &&
+ attr->values[0].integer <= IPP_QUALITY_HIGH)
+ print_quality = attr->values[0].integer - IPP_QUALITY_DRAFT;
+ else
+ print_quality = _PWG_PRINT_QUALITY_NORMAL;
+
+ if (pc->num_presets[print_color_mode][print_quality] == 0)
+ {
+ /*
+ * Try to find a preset that works so that we maximize the chances of us
+ * getting a good print using IPP attributes.
+ */
+
+ if (pc->num_presets[print_color_mode][_PWG_PRINT_QUALITY_NORMAL] > 0)
+ print_quality = _PWG_PRINT_QUALITY_NORMAL;
+ else if (pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][print_quality] > 0)
+ print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
+ else
+ {
+ print_quality = _PWG_PRINT_QUALITY_NORMAL;
+ print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
+ }
+ }
+
+ if (pc->num_presets[print_color_mode][print_quality] > 0)
+ {
+ /*
+ * Copy the preset options as long as the corresponding names are not
+ * already defined in the IPP request...
+ */
+
+ for (i = pc->num_presets[print_color_mode][print_quality],
+ preset = pc->presets[print_color_mode][print_quality];
+ i > 0;
+ i --, preset ++)
+ {
+ if (!ippFindAttribute(job->attrs, preset->name, IPP_TAG_ZERO))
+ num_pwgppds = cupsAddOption(preset->name, preset->value, num_pwgppds,
+ &pwgppds);
+ }
+ }
+ }
+
+ if (pc)
+ {
+ if (!ippFindAttribute(job->attrs, "InputSlot", IPP_TAG_ZERO) &&
+ !ippFindAttribute(job->attrs, "HPPaperSource", IPP_TAG_ZERO))
+ {
+ if ((ppd = _ppdCacheGetInputSlot(pc, job->attrs, NULL)) != NULL)
+ num_pwgppds = cupsAddOption(pc->source_option, ppd, num_pwgppds,
+ &pwgppds);
+ else if (!ippFindAttribute(job->attrs, "AP_D_InputSlot", IPP_TAG_ZERO))
+ num_pwgppds = cupsAddOption("AP_D_InputSlot", "", num_pwgppds,
+ &pwgppds);
+ }
+ if (!ippFindAttribute(job->attrs, "MediaType", IPP_TAG_ZERO) &&
+ (ppd = _ppdCacheGetMediaType(pc, job->attrs, NULL)) != NULL)
+ num_pwgppds = cupsAddOption("MediaType", ppd, num_pwgppds, &pwgppds);
+
+ if (!ippFindAttribute(job->attrs, "PageRegion", IPP_TAG_ZERO) &&
+ !ippFindAttribute(job->attrs, "PageSize", IPP_TAG_ZERO) &&
+ (ppd = _ppdCacheGetPageSize(pc, job->attrs, NULL, &exact)) != NULL)
+ {
+ num_pwgppds = cupsAddOption("PageSize", ppd, num_pwgppds, &pwgppds);
+
+ if (!ippFindAttribute(job->attrs, "media", IPP_TAG_ZERO))
+ num_pwgppds = cupsAddOption("media", ppd, num_pwgppds, &pwgppds);
+ }
+
+ if (!ippFindAttribute(job->attrs, "OutputBin", IPP_TAG_ZERO) &&
+ (attr = ippFindAttribute(job->attrs, "output-bin",
+ IPP_TAG_ZERO)) != NULL &&
+ (attr->value_tag == IPP_TAG_KEYWORD ||
+ attr->value_tag == IPP_TAG_NAME) &&
+ (ppd = _ppdCacheGetOutputBin(pc, attr->values[0].string.text)) != NULL)
+ {
+ /*
+ * Map output-bin to OutputBin option...
+ */
+
+ num_pwgppds = cupsAddOption("OutputBin", ppd, num_pwgppds, &pwgppds);
+ }
+
+ if (pc->sides_option &&
+ !ippFindAttribute(job->attrs, pc->sides_option, IPP_TAG_ZERO) &&
+ (attr = ippFindAttribute(job->attrs, "sides", IPP_TAG_KEYWORD)) != NULL)
+ {
+ /*
+ * Map sides to duplex option...
+ */
+
+ if (!strcmp(attr->values[0].string.text, "one-sided"))
+ num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_1sided,
+ num_pwgppds, &pwgppds);
+ else if (!strcmp(attr->values[0].string.text, "two-sided-long-edge"))
+ num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_2sided_long,
+ num_pwgppds, &pwgppds);
+ else if (!strcmp(attr->values[0].string.text, "two-sided-short-edge"))
+ num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_2sided_short,
+ num_pwgppds, &pwgppds);
+ }
+ }
+
+ /*
+ * Figure out how much room we need...
+ */
+
+ newlength = ipp_length(job->attrs);
+
+ for (i = num_pwgppds, pwgppd = pwgppds; i > 0; i --, pwgppd ++)
+ newlength += 1 + strlen(pwgppd->name) + 1 + strlen(pwgppd->value);
+
+ /*
+ * Then allocate/reallocate the option buffer as needed...
+ */
+
+ if (newlength > optlength || !options)
+ {
+ if (!options)
+ optptr = malloc(newlength);
+ else
+ optptr = realloc(options, newlength);
+
+ if (!optptr)
+ {
+ cupsdLogJob(job, CUPSD_LOG_CRIT,
+ "Unable to allocate " CUPS_LLFMT " bytes for option buffer!",
+ CUPS_LLCAST newlength);
+ return (NULL);
+ }
+
+ options = optptr;
+ optlength = newlength;
+ }
+
+ /*
+ * Now loop through the attributes and convert them to the textual
+ * representation used by the filters...
+ */
+
+ optptr = options;
+ *optptr = '\0';
+
+ snprintf(title, title_size, "%s-%d", job->printer->name, job->id);
+ strlcpy(copies, "1", copies_size);
+
+ for (attr = job->attrs->attrs; attr != NULL; attr = attr->next)
+ {
+ if (!strcmp(attr->name, "copies") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ {
+ /*
+ * Don't use the # copies attribute if we are printing the job sheets...
+ */
+
+ if (!banner_page)
+ snprintf(copies, copies_size, "%d", attr->values[0].integer);
+ }
+ else if (!strcmp(attr->name, "job-name") &&
+ (attr->value_tag == IPP_TAG_NAME ||
+ attr->value_tag == IPP_TAG_NAMELANG))
+ strlcpy(title, attr->values[0].string.text, title_size);
+ else if (attr->group_tag == IPP_TAG_JOB)
+ {
+ /*
+ * Filter out other unwanted attributes...
+ */
+
+ if (attr->value_tag == IPP_TAG_NOVALUE ||
+ attr->value_tag == IPP_TAG_MIMETYPE ||
+ attr->value_tag == IPP_TAG_NAMELANG ||
+ attr->value_tag == IPP_TAG_TEXTLANG ||
+ (attr->value_tag == IPP_TAG_URI && strcmp(attr->name, "job-uuid")) ||
+ attr->value_tag == IPP_TAG_URISCHEME ||
+ attr->value_tag == IPP_TAG_BEGIN_COLLECTION) /* Not yet supported */
+ continue;
+
+ if (!strcmp(attr->name, "job-hold-until"))
+ continue;
+
+ if (!strncmp(attr->name, "job-", 4) &&
+ strcmp(attr->name, "job-billing") &&
+ strcmp(attr->name, "job-impressions") &&
+ strcmp(attr->name, "job-originating-host-name") &&
+ strcmp(attr->name, "job-uuid") &&
+ !(job->printer->type & CUPS_PRINTER_REMOTE))
+ continue;
+
+ if ((!strcmp(attr->name, "job-impressions") ||
+ !strcmp(attr->name, "page-label") ||
+ !strcmp(attr->name, "page-border") ||
+ !strncmp(attr->name, "number-up", 9) ||
+ !strcmp(attr->name, "page-ranges") ||
+ !strcmp(attr->name, "page-set") ||
+ !_cups_strcasecmp(attr->name, "AP_FIRSTPAGE_InputSlot") ||
+ !_cups_strcasecmp(attr->name, "AP_FIRSTPAGE_ManualFeed") ||
+ !_cups_strcasecmp(attr->name, "com.apple.print.PrintSettings."
+ "PMTotalSidesImaged..n.") ||
+ !_cups_strcasecmp(attr->name, "com.apple.print.PrintSettings."
+ "PMTotalBeginPages..n.")) &&
+ banner_page)
+ continue;
+
+ /*
+ * Otherwise add them to the list...
+ */
+
+ if (optptr > options)
+ strlcat(optptr, " ", optlength - (optptr - options));
+
+ if (attr->value_tag != IPP_TAG_BOOLEAN)
+ {
+ strlcat(optptr, attr->name, optlength - (optptr - options));
+ strlcat(optptr, "=", optlength - (optptr - options));
+ }
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (i)
+ strlcat(optptr, ",", optlength - (optptr - options));
+
+ optptr += strlen(optptr);
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ snprintf(optptr, optlength - (optptr - options),
+ "%d", attr->values[i].integer);
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ if (!attr->values[i].boolean)
+ strlcat(optptr, "no", optlength - (optptr - options));
+
+ strlcat(optptr, attr->name,
+ optlength - (optptr - options));
+ break;
+
+ case IPP_TAG_RANGE :
+ if (attr->values[i].range.lower == attr->values[i].range.upper)
+ snprintf(optptr, optlength - (optptr - options) - 1,
+ "%d", attr->values[i].range.lower);
+ else
+ snprintf(optptr, optlength - (optptr - options) - 1,
+ "%d-%d", attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ snprintf(optptr, optlength - (optptr - options) - 1,
+ "%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_STRING :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_URI :
+ for (valptr = attr->values[i].string.text; *valptr;)
+ {
+ if (strchr(" \t\n\\\'\"", *valptr))
+ *optptr++ = '\\';
+ *optptr++ = *valptr++;
+ }
+
+ *optptr = '\0';
+ break;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+ }
+
+ optptr += strlen(optptr);
+ }
+ }
+
+ /*
+ * Finally loop through the PWG->PPD mapped options and add them...
+ */
+
+ for (i = num_pwgppds, pwgppd = pwgppds; i > 0; i --, pwgppd ++)
+ {
+ *optptr++ = ' ';
+ strcpy(optptr, pwgppd->name);
+ optptr += strlen(optptr);
+ *optptr++ = '=';
+ strcpy(optptr, pwgppd->value);
+ optptr += strlen(optptr);
+ }
+
+ cupsFreeOptions(num_pwgppds, pwgppds);
+
+ /*
+ * Return the options string...
+ */
+
+ return (options);
+}
+
+
+/*
+ * 'ipp_length()' - Compute the size of the buffer needed to hold
+ * the textual IPP attributes.
+ */
+
+static size_t /* O - Size of attribute buffer */
+ipp_length(ipp_t *ipp) /* I - IPP request */
+{
+ size_t bytes; /* Number of bytes */
+ int i; /* Looping var */
+ ipp_attribute_t *attr; /* Current attribute */
+
+
+ /*
+ * Loop through all attributes...
+ */
+
+ bytes = 0;
+
+ for (attr = ipp->attrs; attr != NULL; attr = attr->next)
+ {
+ /*
+ * Skip attributes that won't be sent to filters...
+ */
+
+ if (attr->value_tag == IPP_TAG_NOVALUE ||
+ attr->value_tag == IPP_TAG_MIMETYPE ||
+ attr->value_tag == IPP_TAG_NAMELANG ||
+ attr->value_tag == IPP_TAG_TEXTLANG ||
+ attr->value_tag == IPP_TAG_URI ||
+ attr->value_tag == IPP_TAG_URISCHEME)
+ continue;
+
+ /*
+ * Add space for a leading space and commas between each value.
+ * For the first attribute, the leading space isn't used, so the
+ * extra byte can be used as the nul terminator...
+ */
+
+ bytes ++; /* " " separator */
+ bytes += attr->num_values; /* "," separators */
+
+ /*
+ * Boolean attributes appear as "foo,nofoo,foo,nofoo", while
+ * other attributes appear as "foo=value1,value2,...,valueN".
+ */
+
+ if (attr->value_tag != IPP_TAG_BOOLEAN)
+ bytes += strlen(attr->name);
+ else
+ bytes += attr->num_values * strlen(attr->name);
+
+ /*
+ * Now add the size required for each value in the attribute...
+ */
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ /*
+ * Minimum value of a signed integer is -2147483647, or 11 digits.
+ */
+
+ bytes += attr->num_values * 11;
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ /*
+ * Add two bytes for each false ("no") value...
+ */
+
+ for (i = 0; i < attr->num_values; i ++)
+ if (!attr->values[i].boolean)
+ bytes += 2;
+ break;
+
+ case IPP_TAG_RANGE :
+ /*
+ * A range is two signed integers separated by a hyphen, or
+ * 23 characters max.
+ */
+
+ bytes += attr->num_values * 23;
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ /*
+ * A resolution is two signed integers separated by an "x" and
+ * suffixed by the units, or 26 characters max.
+ */
+
+ bytes += attr->num_values * 26;
+ 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_URI :
+ /*
+ * Strings can contain characters that need quoting. We need
+ * at least 2 * len + 2 characters to cover the quotes and
+ * any backslashes in the string.
+ */
+
+ for (i = 0; i < attr->num_values; i ++)
+ bytes += 2 * strlen(attr->values[i].string.text) + 2;
+ break;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+ }
+
+ return (bytes);
+}
+
+
+/*
+ * 'load_job_cache()' - Load jobs from the job.cache file.
+ */
+
+static void
+load_job_cache(const char *filename) /* I - job.cache filename */
+{
+ cups_file_t *fp; /* job.cache file */
+ char line[1024], /* Line buffer */
+ *value; /* Value on line */
+ int linenum; /* Line number in file */
+ cupsd_job_t *job; /* Current job */
+ int jobid; /* Job ID */
+ char jobfile[1024]; /* Job filename */
+
+
+ /*
+ * Open the job.cache file...
+ */
+
+ if ((fp = cupsdOpenConfFile(filename)) == NULL)
+ {
+ load_request_root();
+ return;
+ }
+
+ /*
+ * Read entries from the job cache file and create jobs as needed.
+ */
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Loading job cache file \"%s\"...",
+ filename);
+
+ linenum = 0;
+ job = NULL;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ if (!_cups_strcasecmp(line, "NextJobId"))
+ {
+ if (value)
+ NextJobId = atoi(value);
+ }
+ else if (!_cups_strcasecmp(line, "<Job"))
+ {
+ if (job)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Missing </Job> directive on line %d!",
+ linenum);
+ continue;
+ }
+
+ if (!value)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Missing job ID on line %d!", linenum);
+ continue;
+ }
+
+ jobid = atoi(value);
+
+ if (jobid < 1)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad job ID %d on line %d!", jobid,
+ linenum);
+ continue;
+ }
+
+ snprintf(jobfile, sizeof(jobfile), "%s/c%05d", RequestRoot, jobid);
+ if (access(jobfile, 0))
+ {
+ snprintf(jobfile, sizeof(jobfile), "%s/c%05d.N", RequestRoot, jobid);
+ if (access(jobfile, 0))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Files have gone away!",
+ jobid);
+ continue;
+ }
+ }
+
+ job = calloc(1, sizeof(cupsd_job_t));
+ if (!job)
+ {
+ cupsdLogMessage(CUPSD_LOG_EMERG,
+ "[Job %d] Unable to allocate memory for job!", jobid);
+ break;
+ }
+
+ job->id = jobid;
+ job->back_pipes[0] = -1;
+ job->back_pipes[1] = -1;
+ job->print_pipes[0] = -1;
+ job->print_pipes[1] = -1;
+ job->side_pipes[0] = -1;
+ job->side_pipes[1] = -1;
+ job->status_pipes[0] = -1;
+ job->status_pipes[1] = -1;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] Loading from cache...",
+ job->id);
+ }
+ else if (!job)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Missing <Job #> directive on line %d!", linenum);
+ continue;
+ }
+ else if (!_cups_strcasecmp(line, "</Job>"))
+ {
+ cupsArrayAdd(Jobs, job);
+
+ if (job->state_value <= IPP_JOB_STOPPED && cupsdLoadJob(job))
+ cupsArrayAdd(ActiveJobs, job);
+
+ job = NULL;
+ }
+ else if (!value)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value on line %d!", linenum);
+ continue;
+ }
+ else if (!_cups_strcasecmp(line, "State"))
+ {
+ job->state_value = (ipp_jstate_t)atoi(value);
+
+ if (job->state_value < IPP_JOB_PENDING)
+ job->state_value = IPP_JOB_PENDING;
+ else if (job->state_value > IPP_JOB_COMPLETED)
+ job->state_value = IPP_JOB_COMPLETED;
+ }
+ else if (!_cups_strcasecmp(line, "HoldUntil"))
+ {
+ job->hold_until = atoi(value);
+ }
+ else if (!_cups_strcasecmp(line, "Priority"))
+ {
+ job->priority = atoi(value);
+ }
+ else if (!_cups_strcasecmp(line, "Username"))
+ {
+ cupsdSetString(&job->username, value);
+ }
+ else if (!_cups_strcasecmp(line, "Destination"))
+ {
+ cupsdSetString(&job->dest, value);
+ }
+ else if (!_cups_strcasecmp(line, "DestType"))
+ {
+ job->dtype = (cups_ptype_t)atoi(value);
+ }
+ else if (!_cups_strcasecmp(line, "NumFiles"))
+ {
+ job->num_files = atoi(value);
+
+ if (job->num_files < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad NumFiles value %d on line %d!",
+ job->num_files, linenum);
+ job->num_files = 0;
+ continue;
+ }
+
+ if (job->num_files > 0)
+ {
+ snprintf(jobfile, sizeof(jobfile), "%s/d%05d-001", RequestRoot,
+ job->id);
+ if (access(jobfile, 0))
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Data files have gone away!",
+ job->id);
+ job->num_files = 0;
+ continue;
+ }
+
+ job->filetypes = calloc(job->num_files, sizeof(mime_type_t *));
+ job->compressions = calloc(job->num_files, sizeof(int));
+
+ if (!job->filetypes || !job->compressions)
+ {
+ cupsdLogMessage(CUPSD_LOG_EMERG,
+ "[Job %d] Unable to allocate memory for %d files!",
+ job->id, job->num_files);
+ break;
+ }
+ }
+ }
+ else if (!_cups_strcasecmp(line, "File"))
+ {
+ int number, /* File number */
+ compression; /* Compression value */
+ char super[MIME_MAX_SUPER], /* MIME super type */
+ type[MIME_MAX_TYPE]; /* MIME type */
+
+
+ if (sscanf(value, "%d%*[ \t]%15[^/]/%255s%d", &number, super, type,
+ &compression) != 4)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad File on line %d!", linenum);
+ continue;
+ }
+
+ if (number < 1 || number > job->num_files)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad File number %d on line %d!",
+ number, linenum);
+ continue;
+ }
+
+ number --;
+
+ job->compressions[number] = compression;
+ job->filetypes[number] = mimeType(MimeDatabase, super, type);
+
+ if (!job->filetypes[number])
+ {
+ /*
+ * If the original MIME type is unknown, auto-type it!
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Unknown MIME type %s/%s for file %d!",
+ job->id, super, type, number + 1);
+
+ snprintf(jobfile, sizeof(jobfile), "%s/d%05d-%03d", RequestRoot,
+ job->id, number + 1);
+ job->filetypes[number] = mimeFileType(MimeDatabase, jobfile, NULL,
+ job->compressions + number);
+
+ /*
+ * If that didn't work, assume it is raw...
+ */
+
+ if (!job->filetypes[number])
+ job->filetypes[number] = mimeType(MimeDatabase, "application",
+ "vnd.cups-raw");
+ }
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown %s directive on line %d!",
+ line, linenum);
+ }
+
+ cupsFileClose(fp);
+}
+
+
+/*
+ * 'load_next_job_id()' - Load the NextJobId value from the job.cache file.
+ */
+
+static void
+load_next_job_id(const char *filename) /* I - job.cache filename */
+{
+ cups_file_t *fp; /* job.cache file */
+ char line[1024], /* Line buffer */
+ *value; /* Value on line */
+ int linenum; /* Line number in file */
+ int next_job_id; /* NextJobId value from line */
+
+
+ /*
+ * Read the NextJobId directive from the job.cache file and use
+ * the value (if any).
+ */
+
+ if ((fp = cupsFileOpen(filename, "r")) == NULL)
+ {
+ if (errno != ENOENT)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to open job cache file \"%s\": %s",
+ filename, strerror(errno));
+
+ return;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Loading NextJobId from job cache file \"%s\"...", filename);
+
+ linenum = 0;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ if (!_cups_strcasecmp(line, "NextJobId"))
+ {
+ if (value)
+ {
+ next_job_id = atoi(value);
+
+ if (next_job_id > NextJobId)
+ NextJobId = next_job_id;
+ }
+ break;
+ }
+ }
+
+ cupsFileClose(fp);
+}
+
+
+/*
+ * 'load_request_root()' - Load jobs from the RequestRoot directory.
+ */
+
+static void
+load_request_root(void)
+{
+ cups_dir_t *dir; /* Directory */
+ cups_dentry_t *dent; /* Directory entry */
+ cupsd_job_t *job; /* New job */
+
+
+ /*
+ * Open the requests directory...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Scanning %s for jobs...", RequestRoot);
+
+ if ((dir = cupsDirOpen(RequestRoot)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to open spool directory \"%s\": %s",
+ RequestRoot, strerror(errno));
+ return;
+ }
+
+ /*
+ * Read all the c##### files...
+ */
+
+ while ((dent = cupsDirRead(dir)) != NULL)
+ if (strlen(dent->filename) >= 6 && dent->filename[0] == 'c')
+ {
+ /*
+ * Allocate memory for the job...
+ */
+
+ if ((job = calloc(sizeof(cupsd_job_t), 1)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Ran out of memory for jobs!");
+ cupsDirClose(dir);
+ return;
+ }
+
+ /*
+ * Assign the job ID...
+ */
+
+ job->id = atoi(dent->filename + 1);
+ job->back_pipes[0] = -1;
+ job->back_pipes[1] = -1;
+ job->print_pipes[0] = -1;
+ job->print_pipes[1] = -1;
+ job->side_pipes[0] = -1;
+ job->side_pipes[1] = -1;
+ job->status_pipes[0] = -1;
+ job->status_pipes[1] = -1;
+
+ if (job->id >= NextJobId)
+ NextJobId = job->id + 1;
+
+ /*
+ * Load the job...
+ */
+
+ if (cupsdLoadJob(job))
+ {
+ /*
+ * Insert the job into the array, sorting by job priority and ID...
+ */
+
+ cupsArrayAdd(Jobs, job);
+
+ if (job->state_value <= IPP_JOB_STOPPED)
+ cupsArrayAdd(ActiveJobs, job);
+ else
+ unload_job(job);
+ }
+ }
+
+ cupsDirClose(dir);
+}
+
+
+/*
+ * 'set_time()' - Set one of the "time-at-xyz" attributes.
+ */
+
+static void
+set_time(cupsd_job_t *job, /* I - Job to update */
+ const char *name) /* I - Name of attribute */
+{
+ ipp_attribute_t *attr; /* Time attribute */
+
+
+ if ((attr = ippFindAttribute(job->attrs, name, IPP_TAG_ZERO)) != NULL)
+ {
+ attr->value_tag = IPP_TAG_INTEGER;
+ attr->values[0].integer = time(NULL);
+ }
+}
+
+
+/*
+ * 'start_job()' - Start a print job.
+ */
+
+static void
+start_job(cupsd_job_t *job, /* I - Job ID */
+ cupsd_printer_t *printer) /* I - Printer to print job */
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_job(job=%p(%d), printer=%p(%s))",
+ job, job->id, printer, printer->name);
+
+ /*
+ * Make sure we have some files around before we try to print...
+ */
+
+ if (job->num_files == 0)
+ {
+ cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT,
+ "Aborting job because it has no files.");
+ return;
+ }
+
+ /*
+ * Update the printer and job state to "processing"...
+ */
+
+ if (!cupsdLoadJob(job))
+ return;
+
+ if (job->printer_message)
+ cupsdSetString(&(job->printer_message->values[0].string.text), "");
+
+ cupsdSetJobState(job, IPP_JOB_PROCESSING, CUPSD_JOB_DEFAULT, NULL);
+ cupsdSetPrinterState(printer, IPP_PRINTER_PROCESSING, 0);
+ cupsdSetPrinterReasons(printer, "-cups-remote-pending,"
+ "cups-remote-pending-held,"
+ "cups-remote-processing,"
+ "cups-remote-stopped,"
+ "cups-remote-canceled,"
+ "cups-remote-aborted,"
+ "cups-remote-completed");
+
+ job->cost = 0;
+ job->current_file = 0;
+ job->progress = 0;
+ job->printer = printer;
+ printer->job = job;
+
+ /*
+ * Setup the last exit status and security profiles...
+ */
+
+ job->status = 0;
+ job->profile = cupsdCreateProfile(job->id);
+
+ /*
+ * Create the status pipes and buffer...
+ */
+
+ if (cupsdOpenPipe(job->status_pipes))
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG,
+ "Unable to create job status pipes - %s.", strerror(errno));
+
+ cupsdSetJobState(job, IPP_JOB_STOPPED, CUPSD_JOB_DEFAULT,
+ "Job stopped because the scheduler could not create the "
+ "job status pipes.");
+
+ cupsdDestroyProfile(job->profile);
+ job->profile = NULL;
+ return;
+ }
+
+ job->status_buffer = cupsdStatBufNew(job->status_pipes[0], NULL);
+ job->status_level = CUPSD_LOG_INFO;
+
+ /*
+ * Create the backchannel pipes and make them non-blocking...
+ */
+
+ if (cupsdOpenPipe(job->back_pipes))
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG,
+ "Unable to create back-channel pipes - %s.", strerror(errno));
+
+ cupsdSetJobState(job, IPP_JOB_STOPPED, CUPSD_JOB_DEFAULT,
+ "Job stopped because the scheduler could not create the "
+ "back-channel pipes.");
+
+ cupsdClosePipe(job->status_pipes);
+ cupsdStatBufDelete(job->status_buffer);
+ job->status_buffer = NULL;
+
+ cupsdDestroyProfile(job->profile);
+ job->profile = NULL;
+ return;
+ }
+
+ fcntl(job->back_pipes[0], F_SETFL,
+ fcntl(job->back_pipes[0], F_GETFL) | O_NONBLOCK);
+ fcntl(job->back_pipes[1], F_SETFL,
+ fcntl(job->back_pipes[1], F_GETFL) | O_NONBLOCK);
+
+ /*
+ * Create the side-channel pipes and make them non-blocking...
+ */
+
+ if (socketpair(AF_LOCAL, SOCK_STREAM, 0, job->side_pipes))
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG,
+ "Unable to create side-channel pipes - %s.", strerror(errno));
+
+ cupsdSetJobState(job, IPP_JOB_STOPPED, CUPSD_JOB_DEFAULT,
+ "Job stopped because the scheduler could not create the "
+ "side-channel pipes.");
+
+ cupsdClosePipe(job->back_pipes);
+
+ cupsdClosePipe(job->status_pipes);
+ cupsdStatBufDelete(job->status_buffer);
+ job->status_buffer = NULL;
+
+ cupsdDestroyProfile(job->profile);
+ job->profile = NULL;
+ return;
+ }
+
+ fcntl(job->side_pipes[0], F_SETFL,
+ fcntl(job->side_pipes[0], F_GETFL) | O_NONBLOCK);
+ fcntl(job->side_pipes[1], F_SETFL,
+ fcntl(job->side_pipes[1], F_GETFL) | O_NONBLOCK);
+
+ fcntl(job->side_pipes[0], F_SETFD,
+ fcntl(job->side_pipes[0], F_GETFD) | FD_CLOEXEC);
+ fcntl(job->side_pipes[1], F_SETFD,
+ fcntl(job->side_pipes[1], F_GETFD) | FD_CLOEXEC);
+
+ /*
+ * Now start the first file in the job...
+ */
+
+ cupsdContinueJob(job);
+}
+
+
+/*
+ * 'stop_job()' - Stop a print job.
+ */
+
+static void
+stop_job(cupsd_job_t *job, /* I - Job */
+ cupsd_jobaction_t action) /* I - Action */
+{
+ int i; /* Looping var */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "stop_job(job=%p(%d), action=%d)", job,
+ job->id, action);
+
+ FilterLevel -= job->cost;
+ job->cost = 0;
+
+ if (action == CUPSD_JOB_DEFAULT && !job->kill_time)
+ job->kill_time = time(NULL) + JobKillDelay;
+ else if (action >= CUPSD_JOB_FORCE)
+ job->kill_time = 0;
+
+ for (i = 0; job->filters[i]; i ++)
+ if (job->filters[i] > 0)
+ {
+ cupsdEndProcess(job->filters[i], action >= CUPSD_JOB_FORCE);
+
+ if (action >= CUPSD_JOB_FORCE)
+ job->filters[i] = -job->filters[i];
+ }
+
+ if (job->backend > 0)
+ {
+ cupsdEndProcess(job->backend, action >= CUPSD_JOB_FORCE);
+
+ if (action >= CUPSD_JOB_FORCE)
+ job->backend = -job->backend;
+ }
+
+ if (action >= CUPSD_JOB_FORCE)
+ {
+ /*
+ * Clear job status...
+ */
+
+ job->status = 0;
+ }
+}
+
+
+/*
+ * 'unload_job()' - Unload a job from memory.
+ */
+
+static void
+unload_job(cupsd_job_t *job) /* I - Job */
+{
+ if (!job->attrs)
+ return;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] Unloading...", job->id);
+
+ ippDelete(job->attrs);
+
+ job->attrs = NULL;
+ job->state = NULL;
+ job->sheets = NULL;
+ job->job_sheets = NULL;
+ job->printer_message = NULL;
+ job->printer_reasons = NULL;
+}
+
+
+/*
+ * 'update_job()' - Read a status update from a job's filters.
+ */
+
+void
+update_job(cupsd_job_t *job) /* I - Job to check */
+{
+ int i; /* Looping var */
+ int copies; /* Number of copies printed */
+ char message[CUPSD_SB_BUFFER_SIZE],
+ /* Message text */
+ *ptr; /* Pointer update... */
+ int loglevel, /* Log level for message */
+ event = 0; /* Events? */
+ static const char * const levels[] = /* Log levels */
+ {
+ "NONE",
+ "EMERG",
+ "ALERT",
+ "CRIT",
+ "ERROR",
+ "WARN",
+ "NOTICE",
+ "INFO",
+ "DEBUG",
+ "DEBUG2"
+ };
+
+
+ /*
+ * Get the printer associated with this job; if the printer is stopped for
+ * any reason then job->printer will be reset to NULL, so make sure we have
+ * a valid pointer...
+ */
+
+ while ((ptr = cupsdStatBufUpdate(job->status_buffer, &loglevel,
+ message, sizeof(message))) != NULL)
+ {
+ /*
+ * Process page and printer state messages as needed...
+ */
+
+ if (loglevel == CUPSD_LOG_PAGE)
+ {
+ /*
+ * Page message; send the message to the page_log file and update the
+ * job sheet count...
+ */
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "PAGE: %s", message);
+
+ if (job->sheets)
+ {
+ if (!_cups_strncasecmp(message, "total ", 6))
+ {
+ /*
+ * Got a total count of pages from a backend or filter...
+ */
+
+ copies = atoi(message + 6);
+ copies -= job->sheets->values[0].integer; /* Just track the delta */
+ }
+ else if (!sscanf(message, "%*d%d", &copies))
+ copies = 1;
+
+ job->sheets->values[0].integer += copies;
+
+ if (job->printer->page_limit)
+ cupsdUpdateQuota(job->printer, job->username, copies, 0);
+ }
+
+ cupsdLogPage(job, message);
+
+ if (job->sheets)
+ cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job,
+ "Printed %d page(s).", job->sheets->values[0].integer);
+ }
+ else if (loglevel == CUPSD_LOG_STATE)
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "STATE: %s", message);
+
+ if (!strcmp(message, "paused"))
+ {
+ cupsdStopPrinter(job->printer, 1);
+ return;
+ }
+ else if (cupsdSetPrinterReasons(job->printer, message))
+ event |= CUPSD_EVENT_PRINTER_STATE;
+
+ update_job_attrs(job, 0);
+ }
+ else if (loglevel == CUPSD_LOG_ATTR)
+ {
+ /*
+ * Set attribute(s)...
+ */
+
+ int num_attrs; /* Number of attributes */
+ cups_option_t *attrs; /* Attributes */
+ const char *attr; /* Attribute */
+
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "ATTR: %s", message);
+
+ num_attrs = cupsParseOptions(message, 0, &attrs);
+
+ if ((attr = cupsGetOption("auth-info-required", num_attrs,
+ attrs)) != NULL)
+ {
+ cupsdSetAuthInfoRequired(job->printer, attr, NULL);
+ cupsdSetPrinterAttrs(job->printer);
+
+ if (job->printer->type & CUPS_PRINTER_DISCOVERED)
+ cupsdMarkDirty(CUPSD_DIRTY_REMOTE);
+ else
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+ }
+
+ if ((attr = cupsGetOption("job-media-progress", num_attrs,
+ attrs)) != NULL)
+ {
+ int progress = atoi(attr);
+
+
+ if (progress >= 0 && progress <= 100)
+ {
+ job->progress = progress;
+
+ if (job->sheets)
+ cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job,
+ "Printing page %d, %d%%",
+ job->sheets->values[0].integer, job->progress);
+ }
+ }
+
+ if ((attr = cupsGetOption("printer-alert", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetString(&job->printer->alert, attr);
+ event |= CUPSD_EVENT_PRINTER_STATE;
+ }
+
+ if ((attr = cupsGetOption("printer-alert-description", num_attrs,
+ attrs)) != NULL)
+ {
+ cupsdSetString(&job->printer->alert_description, attr);
+ event |= CUPSD_EVENT_PRINTER_STATE;
+ }
+
+ if ((attr = cupsGetOption("marker-colors", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetPrinterAttr(job->printer, "marker-colors", (char *)attr);
+ job->printer->marker_time = time(NULL);
+ event |= CUPSD_EVENT_PRINTER_STATE;
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+ }
+
+ if ((attr = cupsGetOption("marker-levels", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetPrinterAttr(job->printer, "marker-levels", (char *)attr);
+ job->printer->marker_time = time(NULL);
+ event |= CUPSD_EVENT_PRINTER_STATE;
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+ }
+
+ if ((attr = cupsGetOption("marker-low-levels", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetPrinterAttr(job->printer, "marker-low-levels", (char *)attr);
+ job->printer->marker_time = time(NULL);
+ event |= CUPSD_EVENT_PRINTER_STATE;
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+ }
+
+ if ((attr = cupsGetOption("marker-high-levels", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetPrinterAttr(job->printer, "marker-high-levels", (char *)attr);
+ job->printer->marker_time = time(NULL);
+ event |= CUPSD_EVENT_PRINTER_STATE;
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+ }
+
+ if ((attr = cupsGetOption("marker-message", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetPrinterAttr(job->printer, "marker-message", (char *)attr);
+ job->printer->marker_time = time(NULL);
+ event |= CUPSD_EVENT_PRINTER_STATE;
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+ }
+
+ if ((attr = cupsGetOption("marker-names", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetPrinterAttr(job->printer, "marker-names", (char *)attr);
+ job->printer->marker_time = time(NULL);
+ event |= CUPSD_EVENT_PRINTER_STATE;
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+ }
+
+ if ((attr = cupsGetOption("marker-types", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetPrinterAttr(job->printer, "marker-types", (char *)attr);
+ job->printer->marker_time = time(NULL);
+ event |= CUPSD_EVENT_PRINTER_STATE;
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+ }
+
+ cupsFreeOptions(num_attrs, attrs);
+ }
+ else if (loglevel == CUPSD_LOG_PPD)
+ {
+ /*
+ * Set attribute(s)...
+ */
+
+ int num_keywords; /* Number of keywords */
+ cups_option_t *keywords; /* Keywords */
+
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "PPD: %s", message);
+
+ num_keywords = cupsParseOptions(message, 0, &keywords);
+
+ if (cupsdUpdatePrinterPPD(job->printer, num_keywords, keywords))
+ cupsdSetPrinterAttrs(job->printer);
+
+ cupsFreeOptions(num_keywords, keywords);
+ }
+ else
+ {
+ /*
+ * Strip legacy message prefix...
+ */
+
+ if (!strncmp(message, "recoverable:", 12))
+ {
+ ptr = message + 12;
+ while (isspace(*ptr & 255))
+ ptr ++;
+ }
+ else if (!strncmp(message, "recovered:", 10))
+ {
+ ptr = message + 10;
+ while (isspace(*ptr & 255))
+ ptr ++;
+ }
+ else
+ ptr = message;
+
+ cupsdLogJob(job, loglevel, "%s", ptr);
+
+ if (loglevel < CUPSD_LOG_DEBUG &&
+ strcmp(job->printer->state_message, ptr))
+ {
+ strlcpy(job->printer->state_message, ptr,
+ sizeof(job->printer->state_message));
+
+ event |= CUPSD_EVENT_PRINTER_STATE | CUPSD_EVENT_JOB_PROGRESS;
+
+ if (loglevel <= job->status_level && job->status_level > CUPSD_LOG_ERROR)
+ {
+ /*
+ * Some messages show in the job-printer-state-message attribute...
+ */
+
+ if (loglevel != CUPSD_LOG_NOTICE)
+ job->status_level = loglevel;
+
+ update_job_attrs(job, 1);
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG,
+ "Set job-printer-state-message to \"%s\", "
+ "current level=%s",
+ job->printer_message->values[0].string.text,
+ levels[job->status_level]);
+ }
+ }
+ }
+
+ if (!strchr(job->status_buffer->buffer, '\n'))
+ break;
+ }
+
+ if (event & CUPSD_EVENT_JOB_PROGRESS)
+ cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job,
+ "%s", job->printer->state_message);
+ if (event & CUPSD_EVENT_PRINTER_STATE)
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, job->printer, NULL,
+ (job->printer->type & CUPS_PRINTER_CLASS) ?
+ "Class \"%s\" state changed." :
+ "Printer \"%s\" state changed.",
+ job->printer->name);
+
+
+ if (ptr == NULL && !job->status_buffer->bufused)
+ {
+ /*
+ * See if all of the filters and the backend have returned their
+ * exit statuses.
+ */
+
+ for (i = 0; job->filters[i] < 0; i ++);
+
+ if (job->filters[i])
+ {
+ /*
+ * EOF but we haven't collected the exit status of all filters...
+ */
+
+ cupsdCheckProcess();
+ return;
+ }
+
+ if (job->current_file >= job->num_files && job->backend > 0)
+ {
+ /*
+ * EOF but we haven't collected the exit status of the backend...
+ */
+
+ cupsdCheckProcess();
+ return;
+ }
+
+ /*
+ * Handle the end of job stuff...
+ */
+
+ finalize_job(job, 1);
+
+ /*
+ * Check for new jobs...
+ */
+
+ cupsdCheckJobs();
+ }
+}
+
+
+/*
+ * 'update_job_attrs()' - Update the job-printer-* attributes.
+ */
+
+void
+update_job_attrs(cupsd_job_t *job, /* I - Job to update */
+ int do_message)/* I - 1 = copy job-printer-state message */
+{
+ int i; /* Looping var */
+ int num_reasons; /* Actual number of reasons */
+ const char * const *reasons; /* Reasons */
+ static const char *none = "none"; /* "none" reason */
+
+
+ /*
+ * Get/create the job-printer-state-* attributes...
+ */
+
+ if (!job->printer_message)
+ {
+ if ((job->printer_message = ippFindAttribute(job->attrs,
+ "job-printer-state-message",
+ IPP_TAG_TEXT)) == NULL)
+ job->printer_message = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_TEXT,
+ "job-printer-state-message",
+ NULL, "");
+ }
+
+ if (!job->printer_reasons)
+ job->printer_reasons = ippFindAttribute(job->attrs,
+ "job-printer-state-reasons",
+ IPP_TAG_KEYWORD);
+
+ /*
+ * Copy or clear the printer-state-message value as needed...
+ */
+
+ if (job->state_value != IPP_JOB_PROCESSING &&
+ job->status_level == CUPSD_LOG_INFO)
+ cupsdSetString(&(job->printer_message->values[0].string.text), "");
+ else if (job->printer->state_message[0] && do_message)
+ cupsdSetString(&(job->printer_message->values[0].string.text),
+ job->printer->state_message);
+
+ /*
+ * ... and the printer-state-reasons value...
+ */
+
+ if (job->printer->num_reasons == 0)
+ {
+ num_reasons = 1;
+ reasons = &none;
+ }
+ else
+ {
+ num_reasons = job->printer->num_reasons;
+ reasons = (const char * const *)job->printer->reasons;
+ }
+
+ if (!job->printer_reasons || job->printer_reasons->num_values != num_reasons)
+ {
+ /*
+ * Replace/create a job-printer-state-reasons attribute...
+ */
+
+ ippDeleteAttribute(job->attrs, job->printer_reasons);
+
+ job->printer_reasons = ippAddStrings(job->attrs,
+ IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-printer-state-reasons",
+ num_reasons, NULL, NULL);
+ }
+ else
+ {
+ /*
+ * Don't bother clearing the reason strings if they are the same...
+ */
+
+ for (i = 0; i < num_reasons; i ++)
+ if (strcmp(job->printer_reasons->values[i].string.text, reasons[i]))
+ break;
+
+ if (i >= num_reasons)
+ return;
+
+ /*
+ * Not the same, so free the current strings...
+ */
+
+ for (i = 0; i < num_reasons; i ++)
+ _cupsStrFree(job->printer_reasons->values[i].string.text);
+ }
+
+ /*
+ * Copy the reasons...
+ */
+
+ for (i = 0; i < num_reasons; i ++)
+ job->printer_reasons->values[i].string.text = _cupsStrAlloc(reasons[i]);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/job.h b/scheduler/job.h
new file mode 100644
index 000000000..22a6e2ef9
--- /dev/null
+++ b/scheduler/job.h
@@ -0,0 +1,164 @@
+/*
+ * "$Id$"
+ *
+ * Print job definitions for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/*
+ * Constants...
+ */
+
+typedef enum cupsd_jobaction_e /**** Actions for state changes ****/
+{
+ CUPSD_JOB_DEFAULT, /* Use default action */
+ CUPSD_JOB_FORCE, /* Force the change */
+ CUPSD_JOB_PURGE /* Force the change and purge */
+} cupsd_jobaction_t;
+
+
+/*
+ * Job request structure...
+ */
+
+struct cupsd_job_s /**** Job request ****/
+{
+ int id, /* Job ID */
+ priority, /* Job priority */
+ dirty; /* Do we need to write the "c" file? */
+ ipp_jstate_t state_value; /* Cached job-state */
+ int pending_timeout;/* Non-zero if the job was created and
+ * waiting on files */
+ char *username; /* Printing user */
+ char *dest; /* Destination printer or class */
+ cups_ptype_t dtype; /* Destination type */
+ cupsd_printer_t *printer; /* Printer this job is assigned to */
+ int num_files; /* Number of files in job */
+ mime_type_t **filetypes; /* File types */
+ int *compressions; /* Compression status of each file */
+ ipp_attribute_t *sheets; /* job-media-sheets-completed */
+ time_t access_time, /* Last access time */
+ kill_time, /* When to send SIGKILL */
+ hold_until; /* Hold expiration date/time */
+ ipp_attribute_t *state; /* Job state */
+ ipp_attribute_t *job_sheets; /* Job sheets (NULL if none) */
+ ipp_attribute_t *printer_message,
+ /* job-printer-state-message */
+ *printer_reasons;
+ /* job-printer-state-reasons */
+ int current_file; /* Current file in job */
+ ipp_t *attrs; /* Job attributes */
+ int print_pipes[2], /* Print data pipes */
+ back_pipes[2], /* Backchannel pipes */
+ side_pipes[2], /* Sidechannel pipes */
+ status_pipes[2];/* Status pipes */
+ cupsd_statbuf_t *status_buffer; /* Status buffer for this job */
+ int status_level; /* Highest log level in a status
+ * message */
+ int cost; /* Filtering cost */
+ int pending_cost; /* Waiting for FilterLimit */
+ int filters[MAX_FILTERS + 1];
+ /* Filter process IDs, 0 terminated */
+ int backend; /* Backend process ID */
+ int status; /* Status code from filters */
+ int tries; /* Number of tries for this job */
+ char *auth_env[3], /* AUTH_xxx environment variables,
+ * if any */
+ *auth_uid; /* AUTH_UID environment variable */
+ void *profile; /* Security profile */
+ cups_array_t *history; /* Debug log history */
+ int progress; /* Printing progress */
+};
+
+typedef struct cupsd_joblog_s /**** Job log message ****/
+{
+ time_t time; /* Time of message */
+ char message[1]; /* Message string */
+} cupsd_joblog_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR int JobHistory VALUE(1);
+ /* Preserve job history? */
+VAR int JobFiles VALUE(0);
+ /* Preserve job files? */
+VAR int MaxJobs VALUE(0),
+ /* Max number of jobs */
+ MaxActiveJobs VALUE(0),
+ /* Max number of active jobs */
+ MaxJobsPerUser VALUE(0),
+ /* Max jobs per user */
+ MaxJobsPerPrinter VALUE(0);
+ /* Max jobs per printer */
+VAR int JobAutoPurge VALUE(0);
+ /* Automatically purge jobs */
+VAR cups_array_t *Jobs VALUE(NULL),
+ /* List of current jobs */
+ *ActiveJobs VALUE(NULL),
+ /* List of active jobs */
+ *PrintingJobs VALUE(NULL);
+ /* List of jobs that are printing */
+VAR int NextJobId VALUE(1);
+ /* Next job ID to use */
+VAR int JobKillDelay VALUE(DEFAULT_TIMEOUT),
+ /* Delay before killing jobs */
+ JobRetryLimit VALUE(5),
+ /* Max number of tries */
+ JobRetryInterval VALUE(300);
+ /* Seconds between retries */
+
+
+/*
+ * Prototypes...
+ */
+
+extern cupsd_job_t *cupsdAddJob(int priority, const char *dest);
+extern void cupsdCancelJobs(const char *dest, const char *username,
+ int purge);
+extern void cupsdCheckJobs(void);
+extern void cupsdCleanJobs(void);
+extern void cupsdContinueJob(cupsd_job_t *job);
+extern void cupsdDeleteJob(cupsd_job_t *job,
+ cupsd_jobaction_t action);
+extern cupsd_job_t *cupsdFindJob(int id);
+extern void cupsdFreeAllJobs(void);
+extern int cupsdGetPrinterJobCount(const char *dest);
+extern int cupsdGetUserJobCount(const char *username);
+extern void cupsdLoadAllJobs(void);
+extern int cupsdLoadJob(cupsd_job_t *job);
+extern void cupsdMoveJob(cupsd_job_t *job, cupsd_printer_t *p);
+extern void cupsdReleaseJob(cupsd_job_t *job);
+extern void cupsdRestartJob(cupsd_job_t *job);
+extern void cupsdSaveAllJobs(void);
+extern void cupsdSaveJob(cupsd_job_t *job);
+extern void cupsdSetJobHoldUntil(cupsd_job_t *job,
+ const char *when, int update);
+extern void cupsdSetJobPriority(cupsd_job_t *job, int priority);
+extern void cupsdSetJobState(cupsd_job_t *job,
+ ipp_jstate_t newstate,
+ cupsd_jobaction_t action,
+ const char *message, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 4, 5)))
+#endif /* __GNUC__ */
+;
+extern void cupsdStopAllJobs(cupsd_jobaction_t action,
+ int kill_delay);
+extern int cupsdTimeoutJob(cupsd_job_t *job);
+extern void cupsdUnloadCompletedJobs(void);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/libcupsmime.exp b/scheduler/libcupsmime.exp
new file mode 100644
index 000000000..9d12ebb73
--- /dev/null
+++ b/scheduler/libcupsmime.exp
@@ -0,0 +1,21 @@
+_mimeAddFilter
+_mimeAddType
+_mimeAddTypeRule
+_mimeDelete
+_mimeDeleteFilter
+_mimeDeleteType
+_mimeFileType
+_mimeFilter
+_mimeFilterLookup
+_mimeFirstFilter
+_mimeFirstType
+_mimeLoad
+_mimeLoadFilters
+_mimeLoadTypes
+_mimeNew
+_mimeNextFilter
+_mimeNextType
+_mimeNumFilters
+_mimeNumTypes
+_mimeSetErrorCallback
+_mimeType
diff --git a/scheduler/listen.c b/scheduler/listen.c
new file mode 100644
index 000000000..b8baaf2bd
--- /dev/null
+++ b/scheduler/listen.c
@@ -0,0 +1,431 @@
+/*
+ * "$Id$"
+ *
+ * Server listening routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdDeleteAllListeners() - Delete all listeners.
+ * cupsdPauseListening() - Clear input polling on all listening sockets...
+ * cupsdResumeListening() - Set input polling on all listening sockets...
+ * cupsdStartListening() - Create all listening sockets...
+ * cupsdStopListening() - Close all listening sockets...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+
+/*
+ * Make sure the IPV6_V6ONLY is defined on Linux - older versions of
+ * glibc don't define it even if the kernel supports it...
+ */
+
+#if defined(__linux) && !defined(IPV6_V6ONLY)
+# define IPV6_V6ONLY 26
+#endif /* __linux && !IPV6_V6ONLY */
+
+
+/*
+ * 'cupsdDeleteAllListeners()' - Delete all listeners.
+ */
+
+void
+cupsdDeleteAllListeners(void)
+{
+ cupsd_listener_t *lis; /* Current listening socket */
+
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ free(lis);
+
+ cupsArrayDelete(Listeners);
+ Listeners = NULL;
+}
+
+
+/*
+ * 'cupsdPauseListening()' - Clear input polling on all listening sockets...
+ */
+
+void
+cupsdPauseListening(void)
+{
+ cupsd_listener_t *lis; /* Current listening socket */
+
+
+ if (cupsArrayCount(Listeners) < 1)
+ return;
+
+ if (cupsArrayCount(Clients) == MaxClients)
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Max clients reached, holding new connections...");
+ else if (errno == ENFILE || errno == EMFILE)
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Too many open files, holding new connections for "
+ "30 seconds...");
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits...");
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ cupsdRemoveSelect(lis->fd);
+
+ ListeningPaused = time(NULL) + 30;
+}
+
+
+/*
+ * 'cupsdResumeListening()' - Set input polling on all listening sockets...
+ */
+
+void
+cupsdResumeListening(void)
+{
+ cupsd_listener_t *lis; /* Current listening socket */
+
+
+ if (cupsArrayCount(Listeners) < 1)
+ return;
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Resuming new connection processing...");
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdResumeListening: Setting input bits...");
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
+
+ ListeningPaused = 0;
+}
+
+
+/*
+ * 'cupsdStartListening()' - Create all listening sockets...
+ */
+
+void
+cupsdStartListening(void)
+{
+ int status; /* Bind result */
+ int p, /* Port number */
+ val; /* Parameter value */
+ cupsd_listener_t *lis; /* Current listening socket */
+ char s[256]; /* String addresss */
+ const char *have_domain; /* Have a domain socket? */
+ static const char * const encryptions[] =
+ { /* Encryption values */
+ "IfRequested",
+ "Never",
+ "Required",
+ "Always"
+ };
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
+ cupsArrayCount(Listeners));
+
+ /*
+ * Setup socket listeners...
+ */
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
+ have_domain = NULL;
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ {
+ httpAddrString(&(lis->address), s, sizeof(s));
+ p = _httpAddrPort(&(lis->address));
+
+ /*
+ * If needed, create a socket for listening...
+ */
+
+ if (lis->fd == -1)
+ {
+ /*
+ * Create a socket for listening...
+ */
+
+ lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
+
+ if (lis->fd == -1)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to open listen socket for address %s:%d - %s.",
+ s, p, strerror(errno));
+
+#ifdef AF_INET6
+ /*
+ * IPv6 is often disabled while DNS returns IPv6 addresses...
+ */
+
+ if (lis->address.addr.sa_family != AF_INET6 &&
+ (FatalErrors & CUPSD_FATAL_LISTEN))
+ cupsdEndProcess(getpid(), 0);
+#else
+ if (FatalErrors & CUPSD_FATAL_LISTEN)
+ cupsdEndProcess(getpid(), 0);
+#endif /* AF_INET6 */
+
+ continue;
+ }
+
+ /*
+ * Set things up to reuse the local address for this port.
+ */
+
+ val = 1;
+#ifdef __sun
+ setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
+#else
+ setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+#endif /* __sun */
+
+ /*
+ * Bind to the port we found...
+ */
+
+#ifdef AF_INET6
+ if (lis->address.addr.sa_family == AF_INET6)
+ {
+# ifdef IPV6_V6ONLY
+ /*
+ * Accept only IPv6 connections on this socket, to avoid
+ * potential security issues and to make all platforms behave
+ * the same.
+ */
+
+ val = 1;
+# ifdef __sun
+ setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
+# else
+ setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
+# endif /* __sun */
+# endif /* IPV6_V6ONLY */
+
+ status = bind(lis->fd, (struct sockaddr *)&(lis->address),
+ httpAddrLength(&(lis->address)));
+ }
+ else
+#endif /* AF_INET6 */
+#ifdef AF_LOCAL
+ if (lis->address.addr.sa_family == AF_LOCAL)
+ {
+ mode_t mask; /* Umask setting */
+
+
+ /*
+ * Remove any existing domain socket file...
+ */
+
+ unlink(lis->address.un.sun_path);
+
+ /*
+ * Save the current umask and set it to 0 so that all users can access
+ * the domain socket...
+ */
+
+ mask = umask(0);
+
+ /*
+ * Bind the domain socket...
+ */
+
+ status = bind(lis->fd, (struct sockaddr *)&(lis->address),
+ httpAddrLength(&(lis->address)));
+
+ /*
+ * Restore the umask...
+ */
+
+ umask(mask);
+ }
+ else
+#endif /* AF_LOCAL */
+ status = bind(lis->fd, (struct sockaddr *)&(lis->address),
+ sizeof(lis->address.ipv4));
+
+ if (status < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to bind socket for address %s:%d - %s.",
+ s, p, strerror(errno));
+ close(lis->fd);
+ lis->fd = -1;
+
+ if (FatalErrors & CUPSD_FATAL_LISTEN)
+ cupsdEndProcess(getpid(), 0);
+
+ continue;
+ }
+
+ /*
+ * Listen for new clients.
+ */
+
+ if (listen(lis->fd, ListenBackLog) < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to listen for clients on address %s:%d - %s.",
+ s, p, strerror(errno));
+
+ close(lis->fd);
+ lis->fd = -1;
+
+ if (FatalErrors & CUPSD_FATAL_LISTEN)
+ cupsdEndProcess(getpid(), 0);
+
+ continue;
+ }
+ }
+
+ fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
+
+ if (p)
+ cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
+ s, p, lis->fd);
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
+ s, lis->fd);
+
+ if (chmod(s, 0140777))
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to change permisssions on domain socket "
+ "\"%s\" - %s", s, strerror(errno));
+ }
+
+ /*
+ * Save the first port that is bound to the local loopback or
+ * "any" address...
+ */
+
+ if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
+ (httpAddrLocalhost(&(lis->address)) ||
+ httpAddrAny(&(lis->address))))
+ {
+ LocalPort = p;
+ LocalEncryption = lis->encryption;
+ }
+
+#ifdef AF_LOCAL
+ if (lis->address.addr.sa_family == AF_LOCAL && !have_domain)
+ have_domain = lis->address.un.sun_path;
+#endif /* AF_LOCAL */
+ }
+
+ /*
+ * Make sure that we are listening on localhost!
+ */
+
+ if (!LocalPort && !have_domain)
+ {
+ cupsdLogMessage(CUPSD_LOG_EMERG,
+ "No Listen or Port lines were found to allow access via "
+ "localhost!");
+
+ if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN))
+ cupsdEndProcess(getpid(), 0);
+ }
+
+ /*
+ * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
+ * the listeners...
+ */
+
+ if (have_domain)
+ {
+ /*
+ * Use domain sockets for the local connection...
+ */
+
+ cupsdSetEnv("CUPS_SERVER", have_domain);
+
+ LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
+ }
+ else
+ {
+ /*
+ * Use the default local loopback address for the server...
+ */
+
+ cupsdSetEnv("CUPS_SERVER", "localhost");
+ }
+
+ cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);
+
+ if (LocalPort)
+ cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
+
+ /*
+ * Resume listening for connections...
+ */
+
+ cupsdResumeListening();
+}
+
+
+/*
+ * 'cupsdStopListening()' - Close all listening sockets...
+ */
+
+void
+cupsdStopListening(void)
+{
+ cupsd_listener_t *lis; /* Current listening socket */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdStopListening: closing all listen sockets.");
+
+ cupsdPauseListening();
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ {
+ if (lis->fd != -1)
+ {
+#ifdef WIN32
+ closesocket(lis->fd);
+#else
+ close(lis->fd);
+#endif /* WIN32 */
+
+#ifdef AF_LOCAL
+ /*
+ * Remove domain sockets...
+ */
+
+# ifdef HAVE_LAUNCH_H
+ if (lis->address.addr.sa_family == AF_LOCAL && !Launchd)
+# else
+ if (lis->address.addr.sa_family == AF_LOCAL)
+# endif /* HAVE_LAUNCH_H */
+ unlink(lis->address.un.sun_path);
+#endif /* AF_LOCAL */
+ }
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/log.c b/scheduler/log.c
new file mode 100644
index 000000000..d7245079f
--- /dev/null
+++ b/scheduler/log.c
@@ -0,0 +1,1077 @@
+/*
+ * "$Id$"
+ *
+ * Log file routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdCheckLogFile() - Open/rotate a log file if it needs it.
+ * cupsdGetDateTime() - Returns a pointer to a date/time string.
+ * cupsdLogGSSMessage() - Log a GSSAPI error...
+ * cupsdLogJob() - Log a job message.
+ * cupsdLogMessage() - Log a message to the error log file.
+ * cupsdLogPage() - Log a page to the page log file.
+ * cupsdLogRequest() - Log an HTTP request in Common Log Format.
+ * cupsdWriteErrorLog() - Write a line to the ErrorLog.
+ * format_log_line() - Format a line for a log file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <stdarg.h>
+#include <syslog.h>
+
+
+/*
+ * Local globals...
+ */
+
+static int log_linesize = 0; /* Size of line for output file */
+static char *log_line = NULL; /* Line for output file */
+
+
+/*
+ * Local functions...
+ */
+
+static int format_log_line(const char *message, va_list ap);
+
+
+/*
+ * 'cupsdCheckLogFile()' - Open/rotate a log file if it needs it.
+ */
+
+int /* O - 1 if log file open */
+cupsdCheckLogFile(cups_file_t **lf, /* IO - Log file */
+ const char *logname) /* I - Log filename */
+{
+ char backname[1024], /* Backup log filename */
+ filename[1024], /* Formatted log filename */
+ *ptr; /* Pointer into filename */
+ const char *logptr; /* Pointer into log filename */
+
+
+ /*
+ * See if we have a log file to check...
+ */
+
+ if (!lf || !logname || !logname[0])
+ return (1);
+
+ /*
+ * Format the filename as needed...
+ */
+
+ if (!*lf ||
+ (strncmp(logname, "/dev/", 5) && cupsFileTell(*lf) > MaxLogSize &&
+ MaxLogSize > 0))
+ {
+ /*
+ * Handle format strings...
+ */
+
+ filename[sizeof(filename) - 1] = '\0';
+
+ if (logname[0] != '/')
+ {
+ strlcpy(filename, ServerRoot, sizeof(filename));
+ strlcat(filename, "/", sizeof(filename));
+ }
+ else
+ filename[0] = '\0';
+
+ for (logptr = logname, ptr = filename + strlen(filename);
+ *logptr && ptr < (filename + sizeof(filename) - 1);
+ logptr ++)
+ if (*logptr == '%')
+ {
+ /*
+ * Format spec...
+ */
+
+ logptr ++;
+ if (*logptr == 's')
+ {
+ /*
+ * Insert the server name...
+ */
+
+ strlcpy(ptr, ServerName, sizeof(filename) - (ptr - filename));
+ ptr += strlen(ptr);
+ }
+ else
+ {
+ /*
+ * Otherwise just insert the character...
+ */
+
+ *ptr++ = *logptr;
+ }
+ }
+ else
+ *ptr++ = *logptr;
+
+ *ptr = '\0';
+ }
+
+ /*
+ * See if the log file is open...
+ */
+
+ if (!*lf)
+ {
+ /*
+ * Nope, open the log file...
+ */
+
+ if ((*lf = cupsFileOpen(filename, "a")) == NULL)
+ {
+ /*
+ * If the file is in CUPS_LOGDIR then try to create a missing directory...
+ */
+
+ if (!strncmp(filename, CUPS_LOGDIR, strlen(CUPS_LOGDIR)))
+ {
+ /*
+ * Try updating the permissions of the containing log directory, using
+ * the log file permissions as a basis...
+ */
+
+ int log_dir_perm = 0300 | LogFilePerm;
+ /* LogFilePerm + owner write/search */
+ if (log_dir_perm & 0040)
+ log_dir_perm |= 0010; /* Add group search */
+ if (log_dir_perm & 0004)
+ log_dir_perm |= 0001; /* Add other search */
+
+ cupsdCheckPermissions(CUPS_LOGDIR, NULL, log_dir_perm, RunUser, Group,
+ 1, -1);
+
+ *lf = cupsFileOpen(filename, "a");
+ }
+
+ if (*lf == NULL)
+ {
+ syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
+ strerror(errno));
+
+ if (FatalErrors & CUPSD_FATAL_LOG)
+ cupsdEndProcess(getpid(), 0);
+
+ return (0);
+ }
+ }
+
+ if (strncmp(filename, "/dev/", 5))
+ {
+ /*
+ * Change ownership and permissions of non-device logs...
+ */
+
+ fchown(cupsFileNumber(*lf), RunUser, Group);
+ fchmod(cupsFileNumber(*lf), LogFilePerm);
+ }
+ }
+
+ /*
+ * Do we need to rotate the log?
+ */
+
+ if (strncmp(logname, "/dev/", 5) && cupsFileTell(*lf) > MaxLogSize &&
+ MaxLogSize > 0)
+ {
+ /*
+ * Rotate log file...
+ */
+
+ cupsFileClose(*lf);
+
+ strcpy(backname, filename);
+ strlcat(backname, ".O", sizeof(backname));
+
+ unlink(backname);
+ rename(filename, backname);
+
+ if ((*lf = cupsFileOpen(filename, "a")) == NULL)
+ {
+ syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
+ strerror(errno));
+
+ if (FatalErrors & CUPSD_FATAL_LOG)
+ cupsdEndProcess(getpid(), 0);
+
+ return (0);
+ }
+
+ /*
+ * Change ownership and permissions of non-device logs...
+ */
+
+ fchown(cupsFileNumber(*lf), RunUser, Group);
+ fchmod(cupsFileNumber(*lf), LogFilePerm);
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'cupsdGetDateTime()' - Returns a pointer to a date/time string.
+ */
+
+char * /* O - Date/time string */
+cupsdGetDateTime(struct timeval *t, /* I - Time value or NULL for current */
+ cupsd_time_t format) /* I - Format to use */
+{
+ struct timeval curtime; /* Current time value */
+ struct tm *date; /* Date/time value */
+ static struct timeval last_time = { 0, 0 };
+ /* Last time we formatted */
+ static char s[1024]; /* Date/time string */
+ static const char * const months[12] =/* Months */
+ {
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec"
+ };
+
+
+ /*
+ * Make sure we have a valid time...
+ */
+
+ if (!t)
+ {
+ gettimeofday(&curtime, NULL);
+ t = &curtime;
+ }
+
+ if (t->tv_sec != last_time.tv_sec ||
+ (LogTimeFormat == CUPSD_TIME_USECS && t->tv_usec != last_time.tv_usec))
+ {
+ last_time = *t;
+
+ /*
+ * Get the date and time from the UNIX time value, and then format it
+ * into a string. Note that we *can't* use the strftime() function since
+ * it is localized and will seriously confuse automatic programs if the
+ * month names are in the wrong language!
+ *
+ * Also, we use the "timezone" variable that contains the current timezone
+ * offset from GMT in seconds so that we are reporting local time in the
+ * log files. If you want GMT, set the TZ environment variable accordingly
+ * before starting the scheduler.
+ *
+ * (*BSD and Darwin store the timezone offset in the tm structure)
+ */
+
+ date = localtime(&(t->tv_sec));
+
+ if (format == CUPSD_TIME_STANDARD)
+ snprintf(s, sizeof(s), "[%02d/%s/%04d:%02d:%02d:%02d %+03ld%02ld]",
+ date->tm_mday, months[date->tm_mon], 1900 + date->tm_year,
+ date->tm_hour, date->tm_min, date->tm_sec,
+#ifdef HAVE_TM_GMTOFF
+ date->tm_gmtoff / 3600, (date->tm_gmtoff / 60) % 60);
+#else
+ timezone / 3600, (timezone / 60) % 60);
+#endif /* HAVE_TM_GMTOFF */
+ else
+ snprintf(s, sizeof(s), "[%02d/%s/%04d:%02d:%02d:%02d.%06d %+03ld%02ld]",
+ date->tm_mday, months[date->tm_mon], 1900 + date->tm_year,
+ date->tm_hour, date->tm_min, date->tm_sec, (int)t->tv_usec,
+#ifdef HAVE_TM_GMTOFF
+ date->tm_gmtoff / 3600, (date->tm_gmtoff / 60) % 60);
+#else
+ timezone / 3600, (timezone / 60) % 60);
+#endif /* HAVE_TM_GMTOFF */
+ }
+
+ return (s);
+}
+
+
+/*
+ * 'cupsdLogFCMessage()' - Log a file checking message.
+ */
+
+void
+cupsdLogFCMessage(
+ void *context, /* I - Printer (if any) */
+ _cups_fc_result_t result, /* I - Check result */
+ const char *message) /* I - Message to log */
+{
+ cupsd_printer_t *p = (cupsd_printer_t *)context;
+ /* Printer */
+ cupsd_loglevel_t level; /* Log level */
+
+
+ if (result == _CUPS_FILE_CHECK_OK)
+ level = CUPSD_LOG_DEBUG2;
+ else
+ level = CUPSD_LOG_ERROR;
+
+ if (p)
+ {
+ cupsdLogMessage(level, "%s: %s", p->name, message);
+
+ if (result == _CUPS_FILE_CHECK_MISSING ||
+ result == _CUPS_FILE_CHECK_WRONG_TYPE)
+ {
+ strlcpy(p->state_message, message, sizeof(p->state_message));
+
+ if (cupsdSetPrinterReasons(p, "+cups-missing-filter-warning"))
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, p, NULL, "%s", message);
+ }
+ else if (result == _CUPS_FILE_CHECK_PERMISSIONS ||
+ result == _CUPS_FILE_CHECK_RELATIVE_PATH)
+ {
+ strlcpy(p->state_message, message, sizeof(p->state_message));
+
+ if (cupsdSetPrinterReasons(p, "+cups-insecure-filter-warning"))
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, p, NULL, "%s", message);
+ }
+ }
+ else
+ cupsdLogMessage(level, "%s", message);
+}
+
+
+#ifdef HAVE_GSSAPI
+/*
+ * 'cupsdLogGSSMessage()' - Log a GSSAPI error...
+ */
+
+int /* O - 1 on success, 0 on error */
+cupsdLogGSSMessage(
+ int level, /* I - Log level */
+ int major_status, /* I - Major GSSAPI status */
+ int minor_status, /* I - Minor GSSAPI status */
+ const char *message, /* I - printf-style message string */
+ ...) /* I - Additional args as needed */
+{
+ OM_uint32 err_major_status, /* Major status code for display */
+ err_minor_status; /* Minor status code for display */
+ OM_uint32 msg_ctx; /* Message context */
+ gss_buffer_desc major_status_string = GSS_C_EMPTY_BUFFER,
+ /* Major status message */
+ minor_status_string = GSS_C_EMPTY_BUFFER;
+ /* Minor status message */
+ int ret; /* Return value */
+
+
+ msg_ctx = 0;
+ err_major_status = gss_display_status(&err_minor_status,
+ major_status,
+ GSS_C_GSS_CODE,
+ GSS_C_NO_OID,
+ &msg_ctx,
+ &major_status_string);
+
+ if (!GSS_ERROR(err_major_status))
+ gss_display_status(&err_minor_status, minor_status, GSS_C_MECH_CODE,
+ GSS_C_NULL_OID, &msg_ctx, &minor_status_string);
+
+ ret = cupsdLogMessage(level, "%s: %s, %s", message,
+ (char *)major_status_string.value,
+ (char *)minor_status_string.value);
+ gss_release_buffer(&err_minor_status, &major_status_string);
+ gss_release_buffer(&err_minor_status, &minor_status_string);
+
+ return (ret);
+}
+#endif /* HAVE_GSSAPI */
+
+
+/*
+ * 'cupsdLogJob()' - Log a job message.
+ */
+
+int /* O - 1 on success, 0 on error */
+cupsdLogJob(cupsd_job_t *job, /* I - Job */
+ int level, /* I - Log level */
+ const char *message, /* I - Printf-style message string */
+ ...) /* I - Additional arguments as needed */
+{
+ va_list ap; /* Argument pointer */
+ char jobmsg[1024]; /* Format string for job message */
+ int status; /* Formatting status */
+
+
+ /*
+ * See if we want to log this message...
+ */
+
+ if (TestConfigFile || !ErrorLog)
+ return (1);
+
+ if ((level > LogLevel ||
+ (level == CUPSD_LOG_INFO && LogLevel < CUPSD_LOG_DEBUG)) &&
+ LogDebugHistory <= 0)
+ return (1);
+
+ /*
+ * Format and write the log message...
+ */
+
+ snprintf(jobmsg, sizeof(jobmsg), "[Job %d] %s", job->id, message);
+
+ do
+ {
+ va_start(ap, message);
+ status = format_log_line(jobmsg, ap);
+ va_end(ap);
+ }
+ while (status == 0);
+
+ if (status > 0)
+ {
+ if ((level > LogLevel ||
+ (level == CUPSD_LOG_INFO && LogLevel < CUPSD_LOG_DEBUG)) &&
+ LogDebugHistory > 0)
+ {
+ /*
+ * Add message to the job history...
+ */
+
+ cupsd_joblog_t *temp; /* Copy of log message */
+
+
+ if ((temp = malloc(sizeof(cupsd_joblog_t) + strlen(log_line))) != NULL)
+ {
+ temp->time = time(NULL);
+ strcpy(temp->message, log_line);
+ }
+
+ if (!job->history)
+ job->history = cupsArrayNew(NULL, NULL);
+
+ if (job->history && temp)
+ {
+ cupsArrayAdd(job->history, temp);
+
+ if (cupsArrayCount(job->history) > LogDebugHistory)
+ {
+ /*
+ * Remove excess messages...
+ */
+
+ temp = cupsArrayFirst(job->history);
+ cupsArrayRemove(job->history, temp);
+ free(temp);
+ }
+ }
+ else if (temp)
+ free(temp);
+
+ return (1);
+ }
+ else if (level <= LogLevel &&
+ (level != CUPSD_LOG_INFO || LogLevel >= CUPSD_LOG_DEBUG))
+ return (cupsdWriteErrorLog(level, log_line));
+ else
+ return (1);
+ }
+ else
+ return (cupsdWriteErrorLog(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for log line!"));
+}
+
+
+/*
+ * 'cupsdLogMessage()' - Log a message to the error log file.
+ */
+
+int /* O - 1 on success, 0 on error */
+cupsdLogMessage(int level, /* I - Log level */
+ const char *message, /* I - printf-style message string */
+ ...) /* I - Additional args as needed */
+{
+ va_list ap; /* Argument pointer */
+ int status; /* Formatting status */
+
+
+ /*
+ * See if we want to log this message...
+ */
+
+ if (TestConfigFile)
+ {
+ if (level <= CUPSD_LOG_WARN)
+ {
+ va_start(ap, message);
+ vfprintf(stderr, message, ap);
+ putc('\n', stderr);
+ va_end(ap);
+ }
+
+ return (1);
+ }
+
+ if (level > LogLevel || !ErrorLog)
+ return (1);
+
+ /*
+ * Format and write the log message...
+ */
+
+ do
+ {
+ va_start(ap, message);
+ status = format_log_line(message, ap);
+ va_end(ap);
+ }
+ while (status == 0);
+
+ if (status > 0)
+ return (cupsdWriteErrorLog(level, log_line));
+ else
+ return (cupsdWriteErrorLog(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for log line!"));
+}
+
+
+/*
+ * 'cupsdLogPage()' - Log a page to the page log file.
+ */
+
+int /* O - 1 on success, 0 on error */
+cupsdLogPage(cupsd_job_t *job, /* I - Job being printed */
+ const char *page) /* I - Page being printed */
+{
+ int i; /* Looping var */
+ char buffer[2048], /* Buffer for page log */
+ *bufptr, /* Pointer into buffer */
+ name[256]; /* Attribute name */
+ const char *format, /* Pointer into PageLogFormat */
+ *nameend; /* End of attribute name */
+ ipp_attribute_t *attr; /* Current attribute */
+ int number; /* Page number */
+ char copies[256]; /* Number of copies */
+
+
+ /*
+ * Format the line going into the page log...
+ */
+
+ if (!PageLogFormat)
+ return (1);
+
+ number = 1;
+ strcpy(copies, "1");
+ sscanf(page, "%d%255s", &number, copies);
+
+ for (format = PageLogFormat, bufptr = buffer; *format; format ++)
+ {
+ if (*format == '%')
+ {
+ format ++;
+
+ switch (*format)
+ {
+ case '%' : /* Literal % */
+ if (bufptr < (buffer + sizeof(buffer) - 1))
+ *bufptr++ = '%';
+ break;
+
+ case 'p' : /* Printer name */
+ strlcpy(bufptr, job->printer->name,
+ sizeof(buffer) - (bufptr - buffer));
+ bufptr += strlen(bufptr);
+ break;
+
+ case 'j' : /* Job ID */
+ snprintf(bufptr, sizeof(buffer) - (bufptr - buffer), "%d", job->id);
+ bufptr += strlen(bufptr);
+ break;
+
+ case 'u' : /* Username */
+ strlcpy(bufptr, job->username ? job->username : "-",
+ sizeof(buffer) - (bufptr - buffer));
+ bufptr += strlen(bufptr);
+ break;
+
+ case 'T' : /* Date and time */
+ strlcpy(bufptr, cupsdGetDateTime(NULL, LogTimeFormat),
+ sizeof(buffer) - (bufptr - buffer));
+ bufptr += strlen(bufptr);
+ break;
+
+ case 'P' : /* Page number */
+ snprintf(bufptr, sizeof(buffer) - (bufptr - buffer), "%d", number);
+ bufptr += strlen(bufptr);
+ break;
+
+ case 'C' : /* Number of copies */
+ strlcpy(bufptr, copies, sizeof(buffer) - (bufptr - buffer));
+ bufptr += strlen(bufptr);
+ break;
+
+ case '{' : /* {attribute} */
+ if ((nameend = strchr(format, '}')) != NULL &&
+ (nameend - format - 2) < (sizeof(name) - 1))
+ {
+ /*
+ * Pull the name from inside the brackets...
+ */
+
+ memcpy(name, format + 1, nameend - format - 1);
+ name[nameend - format - 1] = '\0';
+
+ format = nameend;
+
+ if ((attr = ippFindAttribute(job->attrs, name,
+ IPP_TAG_ZERO)) != NULL)
+ {
+ /*
+ * Add the attribute value...
+ */
+
+ for (i = 0;
+ i < attr->num_values &&
+ bufptr < (buffer + sizeof(buffer) - 1);
+ i ++)
+ {
+ if (i)
+ *bufptr++ = ',';
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ snprintf(bufptr, sizeof(buffer) - (bufptr - buffer),
+ "%d", attr->values[i].integer);
+ bufptr += strlen(bufptr);
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ snprintf(bufptr, sizeof(buffer) - (bufptr - buffer),
+ "%d", attr->values[i].boolean);
+ bufptr += strlen(bufptr);
+ break;
+
+ 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_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ strlcpy(bufptr, attr->values[i].string.text,
+ sizeof(buffer) - (bufptr - buffer));
+ bufptr += strlen(bufptr);
+ break;
+
+ default :
+ strlcpy(bufptr, "???",
+ sizeof(buffer) - (bufptr - buffer));
+ bufptr += strlen(bufptr);
+ break;
+ }
+ }
+ }
+ else if (bufptr < (buffer + sizeof(buffer) - 1))
+ *bufptr++ = '-';
+ break;
+ }
+
+ default :
+ if (bufptr < (buffer + sizeof(buffer) - 2))
+ {
+ *bufptr++ = '%';
+ *bufptr++ = *format;
+ }
+ break;
+ }
+ }
+ else if (bufptr < (buffer + sizeof(buffer) - 1))
+ *bufptr++ = *format;
+ }
+
+ *bufptr = '\0';
+
+#ifdef HAVE_VSYSLOG
+ /*
+ * See if we are logging pages via syslog...
+ */
+
+ if (!strcmp(PageLog, "syslog"))
+ {
+ syslog(LOG_INFO, "%s", buffer);
+
+ return (1);
+ }
+#endif /* HAVE_VSYSLOG */
+
+ /*
+ * Not using syslog; check the log file...
+ */
+
+ if (!cupsdCheckLogFile(&PageFile, PageLog))
+ return (0);
+
+ /*
+ * Print a page log entry of the form:
+ *
+ * printer user job-id [DD/MON/YYYY:HH:MM:SS +TTTT] page num-copies \
+ * billing hostname
+ */
+
+ cupsFilePrintf(PageFile, "%s\n", buffer);
+ cupsFileFlush(PageFile);
+
+ return (1);
+}
+
+
+/*
+ * 'cupsdLogRequest()' - Log an HTTP request in Common Log Format.
+ */
+
+int /* O - 1 on success, 0 on error */
+cupsdLogRequest(cupsd_client_t *con, /* I - Request to log */
+ http_status_t code) /* I - Response code */
+{
+ char temp[2048]; /* Temporary string for URI */
+ static const char * const states[] = /* HTTP client states... */
+ {
+ "WAITING",
+ "OPTIONS",
+ "GET",
+ "GET",
+ "HEAD",
+ "POST",
+ "POST",
+ "POST",
+ "PUT",
+ "PUT",
+ "DELETE",
+ "TRACE",
+ "CLOSE",
+ "STATUS"
+ };
+
+
+ /*
+ * Filter requests as needed...
+ */
+
+ if (AccessLogLevel < CUPSD_ACCESSLOG_ALL)
+ {
+ /*
+ * Eliminate simple GET, POST, and PUT requests...
+ */
+
+ if ((con->operation == HTTP_GET &&
+ strncmp(con->uri, "/admin/conf", 11) &&
+ strncmp(con->uri, "/admin/log", 10)) ||
+ (con->operation == HTTP_POST && !con->request &&
+ strncmp(con->uri, "/admin", 6)) ||
+ (con->operation != HTTP_GET && con->operation != HTTP_POST &&
+ con->operation != HTTP_PUT))
+ return (1);
+
+ if (con->request && con->response &&
+ (con->response->request.status.status_code < IPP_REDIRECTION_OTHER_SITE ||
+ con->response->request.status.status_code == IPP_NOT_FOUND))
+ {
+ /*
+ * Check successful requests...
+ */
+
+ ipp_op_t op = con->request->request.op.operation_id;
+ static cupsd_accesslog_t standard_ops[] =
+ {
+ CUPSD_ACCESSLOG_ALL, /* reserved */
+ CUPSD_ACCESSLOG_ALL, /* reserved */
+ CUPSD_ACCESSLOG_ACTIONS,/* Print-Job */
+ CUPSD_ACCESSLOG_ACTIONS,/* Print-URI */
+ CUPSD_ACCESSLOG_ACTIONS,/* Validate-Job */
+ CUPSD_ACCESSLOG_ACTIONS,/* Create-Job */
+ CUPSD_ACCESSLOG_ACTIONS,/* Send-Document */
+ CUPSD_ACCESSLOG_ACTIONS,/* Send-URI */
+ CUPSD_ACCESSLOG_ACTIONS,/* Cancel-Job */
+ CUPSD_ACCESSLOG_ALL, /* Get-Job-Attributes */
+ CUPSD_ACCESSLOG_ALL, /* Get-Jobs */
+ CUPSD_ACCESSLOG_ALL, /* Get-Printer-Attributes */
+ CUPSD_ACCESSLOG_ACTIONS,/* Hold-Job */
+ CUPSD_ACCESSLOG_ACTIONS,/* Release-Job */
+ CUPSD_ACCESSLOG_ACTIONS,/* Restart-Job */
+ CUPSD_ACCESSLOG_ALL, /* reserved */
+ CUPSD_ACCESSLOG_CONFIG, /* Pause-Printer */
+ CUPSD_ACCESSLOG_CONFIG, /* Resume-Printer */
+ CUPSD_ACCESSLOG_CONFIG, /* Purge-Jobs */
+ CUPSD_ACCESSLOG_CONFIG, /* Set-Printer-Attributes */
+ CUPSD_ACCESSLOG_ACTIONS,/* Set-Job-Attributes */
+ CUPSD_ACCESSLOG_CONFIG, /* Get-Printer-Supported-Values */
+ CUPSD_ACCESSLOG_ACTIONS,/* Create-Printer-Subscription */
+ CUPSD_ACCESSLOG_ACTIONS,/* Create-Job-Subscription */
+ CUPSD_ACCESSLOG_ALL, /* Get-Subscription-Attributes */
+ CUPSD_ACCESSLOG_ALL, /* Get-Subscriptions */
+ CUPSD_ACCESSLOG_ACTIONS,/* Renew-Subscription */
+ CUPSD_ACCESSLOG_ACTIONS,/* Cancel-Subscription */
+ CUPSD_ACCESSLOG_ALL, /* Get-Notifications */
+ CUPSD_ACCESSLOG_ACTIONS,/* Send-Notifications */
+ CUPSD_ACCESSLOG_ALL, /* reserved */
+ CUPSD_ACCESSLOG_ALL, /* reserved */
+ CUPSD_ACCESSLOG_ALL, /* reserved */
+ CUPSD_ACCESSLOG_ALL, /* Get-Print-Support-Files */
+ CUPSD_ACCESSLOG_CONFIG, /* Enable-Printer */
+ CUPSD_ACCESSLOG_CONFIG, /* Disable-Printer */
+ CUPSD_ACCESSLOG_CONFIG, /* Pause-Printer-After-Current-Job */
+ CUPSD_ACCESSLOG_ACTIONS,/* Hold-New-Jobs */
+ CUPSD_ACCESSLOG_ACTIONS,/* Release-Held-New-Jobs */
+ CUPSD_ACCESSLOG_CONFIG, /* Deactivate-Printer */
+ CUPSD_ACCESSLOG_CONFIG, /* Activate-Printer */
+ CUPSD_ACCESSLOG_CONFIG, /* Restart-Printer */
+ CUPSD_ACCESSLOG_CONFIG, /* Shutdown-Printer */
+ CUPSD_ACCESSLOG_CONFIG, /* Startup-Printer */
+ CUPSD_ACCESSLOG_ACTIONS,/* Reprocess-Job */
+ CUPSD_ACCESSLOG_ACTIONS,/* Cancel-Current-Job */
+ CUPSD_ACCESSLOG_ACTIONS,/* Suspend-Current-Job */
+ CUPSD_ACCESSLOG_ACTIONS,/* Resume-Job */
+ CUPSD_ACCESSLOG_ACTIONS,/* Promote-Job */
+ CUPSD_ACCESSLOG_ACTIONS /* Schedule-Job-After */
+ };
+ static cupsd_accesslog_t cups_ops[] =
+ {
+ CUPSD_ACCESSLOG_ALL, /* CUPS-Get-Default */
+ CUPSD_ACCESSLOG_ALL, /* CUPS-Get-Printers */
+ CUPSD_ACCESSLOG_CONFIG, /* CUPS-Add-Modify-Printer */
+ CUPSD_ACCESSLOG_CONFIG, /* CUPS-Delete-Printer */
+ CUPSD_ACCESSLOG_ALL, /* CUPS-Get-Classes */
+ CUPSD_ACCESSLOG_CONFIG, /* CUPS-Add-Modify-Class */
+ CUPSD_ACCESSLOG_CONFIG, /* CUPS-Delete-Class */
+ CUPSD_ACCESSLOG_CONFIG, /* CUPS-Accept-Jobs */
+ CUPSD_ACCESSLOG_CONFIG, /* CUPS-Reject-Jobs */
+ CUPSD_ACCESSLOG_CONFIG, /* CUPS-Set-Default */
+ CUPSD_ACCESSLOG_CONFIG, /* CUPS-Get-Devices */
+ CUPSD_ACCESSLOG_CONFIG, /* CUPS-Get-PPDs */
+ CUPSD_ACCESSLOG_ACTIONS,/* CUPS-Move-Job */
+ CUPSD_ACCESSLOG_ACTIONS,/* CUPS-Authenticate-Job */
+ CUPSD_ACCESSLOG_ALL /* CUPS-Get-PPD */
+ };
+
+
+ if ((op <= IPP_SCHEDULE_JOB_AFTER && standard_ops[op] > AccessLogLevel) ||
+ (op >= CUPS_GET_DEFAULT && op <= CUPS_GET_PPD &&
+ cups_ops[op - CUPS_GET_DEFAULT] > AccessLogLevel))
+ return (1);
+ }
+ }
+
+#ifdef HAVE_VSYSLOG
+ /*
+ * See if we are logging accesses via syslog...
+ */
+
+ if (!strcmp(AccessLog, "syslog"))
+ {
+ syslog(LOG_INFO,
+ "REQUEST %s - %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT " %s %s\n",
+ con->http.hostname, con->username[0] != '\0' ? con->username : "-",
+ states[con->operation], _httpEncodeURI(temp, con->uri, sizeof(temp)),
+ con->http.version / 100, con->http.version % 100,
+ code, CUPS_LLCAST con->bytes,
+ con->request ?
+ ippOpString(con->request->request.op.operation_id) : "-",
+ con->response ?
+ ippErrorString(con->response->request.status.status_code) : "-");
+
+ return (1);
+ }
+#endif /* HAVE_VSYSLOG */
+
+ /*
+ * Not using syslog; check the log file...
+ */
+
+ if (!cupsdCheckLogFile(&AccessFile, AccessLog))
+ return (0);
+
+ /*
+ * Write a log of the request in "common log format"...
+ */
+
+ cupsFilePrintf(AccessFile,
+ "%s - %s %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT " %s %s\n",
+ con->http.hostname,
+ con->username[0] != '\0' ? con->username : "-",
+ cupsdGetDateTime(&(con->start), LogTimeFormat),
+ states[con->operation],
+ _httpEncodeURI(temp, con->uri, sizeof(temp)),
+ con->http.version / 100, con->http.version % 100,
+ code, CUPS_LLCAST con->bytes,
+ con->request ?
+ ippOpString(con->request->request.op.operation_id) : "-",
+ con->response ?
+ ippErrorString(con->response->request.status.status_code) :
+ "-");
+
+ cupsFileFlush(AccessFile);
+
+ return (1);
+}
+
+
+/*
+ * 'cupsdWriteErrorLog()' - Write a line to the ErrorLog.
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsdWriteErrorLog(int level, /* I - Log level */
+ const char *message) /* I - Message string */
+{
+ static const char levels[] = /* Log levels... */
+ {
+ ' ',
+ 'X',
+ 'A',
+ 'C',
+ 'E',
+ 'W',
+ 'N',
+ 'I',
+ 'D',
+ 'd'
+ };
+#ifdef HAVE_VSYSLOG
+ static const int syslevels[] = /* SYSLOG levels... */
+ {
+ 0,
+ LOG_EMERG,
+ LOG_ALERT,
+ LOG_CRIT,
+ LOG_ERR,
+ LOG_WARNING,
+ LOG_NOTICE,
+ LOG_INFO,
+ LOG_DEBUG,
+ LOG_DEBUG
+ };
+#endif /* HAVE_VSYSLOG */
+
+
+#ifdef HAVE_VSYSLOG
+ /*
+ * See if we are logging errors via syslog...
+ */
+
+ if (!strcmp(ErrorLog, "syslog"))
+ {
+ syslog(syslevels[level], "%s", message);
+ return (1);
+ }
+#endif /* HAVE_VSYSLOG */
+
+ /*
+ * Not using syslog; check the log file...
+ */
+
+ if (!cupsdCheckLogFile(&ErrorFile, ErrorLog))
+ return (0);
+
+ /*
+ * Write the log message...
+ */
+
+ cupsFilePrintf(ErrorFile, "%c %s %s\n", levels[level],
+ cupsdGetDateTime(NULL, LogTimeFormat), message);
+ cupsFileFlush(ErrorFile);
+
+ return (1);
+}
+
+
+/*
+ * 'format_log_line()' - Format a line for a log file.
+ *
+ * This function resizes a global string buffer as needed. Each call returns
+ * a pointer to this buffer, so the contents are only good until the next call
+ * to format_log_line()...
+ */
+
+static int /* O - -1 for fatal, 0 for retry, 1 for success */
+format_log_line(const char *message, /* I - Printf-style format string */
+ va_list ap) /* I - Argument list */
+{
+ int len; /* Length of formatted line */
+
+
+ /*
+ * Allocate the line buffer as needed...
+ */
+
+ if (!log_linesize)
+ {
+ log_linesize = 8192;
+ log_line = malloc(log_linesize);
+
+ if (!log_line)
+ return (-1);
+ }
+
+ /*
+ * Format the log message...
+ */
+
+ len = vsnprintf(log_line, log_linesize, message, ap);
+
+ /*
+ * Resize the buffer as needed...
+ */
+
+ if (len >= log_linesize && log_linesize < 65536)
+ {
+ char *temp; /* Temporary string pointer */
+
+
+ len ++;
+
+ if (len < 8192)
+ len = 8192;
+ else if (len > 65536)
+ len = 65536;
+
+ temp = realloc(log_line, len);
+
+ if (temp)
+ {
+ log_line = temp;
+ log_linesize = len;
+
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/main.c b/scheduler/main.c
new file mode 100644
index 000000000..baaa3a1c3
--- /dev/null
+++ b/scheduler/main.c
@@ -0,0 +1,2075 @@
+/*
+ * "$Id$"
+ *
+ * Main loop for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Main entry for the CUPS scheduler.
+ * cupsdAddString() - Copy and add a string to an array.
+ * cupsdCheckProcess() - Tell the main loop to check for dead children.
+ * cupsdClearString() - Clear a string.
+ * cupsdFreeStrings() - Free an array of strings.
+ * cupsdHoldSignals() - Hold child and termination signals.
+ * cupsdReleaseSignals() - Release signals for delivery.
+ * cupsdSetString() - Set a string value.
+ * cupsdSetStringf() - Set a formatted string value.
+ * launchd_checkin() - Check-in with launchd and collect the listening
+ * fds.
+ * launchd_checkout() - Update the launchd KeepAlive file as needed.
+ * parent_handler() - Catch USR1/CHLD signals...
+ * process_children() - Process all dead children...
+ * select_timeout() - Calculate the select timeout value.
+ * sigchld_handler() - Handle 'child' signals from old processes.
+ * sighup_handler() - Handle 'hangup' signals to reconfigure the
+ * scheduler.
+ * sigterm_handler() - Handle 'terminate' signals that stop the scheduler.
+ * usage() - Show scheduler usage.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#define _MAIN_C_
+#include "cupsd.h"
+#include <sys/resource.h>
+#include <syslog.h>
+#include <grp.h>
+
+#ifdef HAVE_LAUNCH_H
+# include <launch.h>
+# include <libgen.h>
+# define CUPS_KEEPALIVE CUPS_CACHEDIR "/org.cups.cupsd"
+ /* Name of the launchd KeepAlive file */
+# ifndef LAUNCH_JOBKEY_KEEPALIVE
+# define LAUNCH_JOBKEY_KEEPALIVE "KeepAlive"
+# endif /* !LAUNCH_JOBKEY_KEEPALIVE */
+# ifndef LAUNCH_JOBKEY_PATHSTATE
+# define LAUNCH_JOBKEY_PATHSTATE "PathState"
+# endif /* !LAUNCH_JOBKEY_PATHSTATE */
+# ifndef LAUNCH_JOBKEY_SERVICEIPC
+# define LAUNCH_JOBKEY_SERVICEIPC "ServiceIPC"
+# endif /* !LAUNCH_JOBKEY_SERVICEIPC */
+#endif /* HAVE_LAUNCH_H */
+
+#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
+# include <malloc.h>
+#endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
+#ifdef HAVE_NOTIFY_H
+# include <notify.h>
+#endif /* HAVE_NOTIFY_H */
+
+
+/*
+ * Local functions...
+ */
+
+#ifdef HAVE_LAUNCHD
+static void launchd_checkin(void);
+static void launchd_checkout(void);
+#endif /* HAVE_LAUNCHD */
+static void parent_handler(int sig);
+static void process_children(void);
+static void sigchld_handler(int sig);
+static void sighup_handler(int sig);
+static void sigterm_handler(int sig);
+static long select_timeout(int fds);
+static void usage(int status);
+
+
+/*
+ * Local globals...
+ */
+
+static int parent_signal = 0;
+ /* Set to signal number from child */
+static int holdcount = 0; /* Number of times "hold" was called */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+static sigset_t holdmask; /* Old POSIX signal mask */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+static int dead_children = 0;
+ /* Dead children? */
+static int stop_scheduler = 0;
+ /* Should the scheduler stop? */
+
+
+/*
+ * 'main()' - Main entry for the CUPS scheduler.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ char *opt; /* Option character */
+ int fg; /* Run in the foreground */
+ int fds; /* Number of ready descriptors */
+ cupsd_client_t *con; /* Current client */
+ cupsd_job_t *job; /* Current job */
+ cupsd_listener_t *lis; /* Current listener */
+ time_t current_time, /* Current time */
+ activity, /* Client activity timer */
+ browse_time, /* Next browse send time */
+ senddoc_time, /* Send-Document time */
+ expire_time, /* Subscription expire time */
+ report_time, /* Malloc/client/job report time */
+ event_time; /* Last event notification time */
+ long timeout; /* Timeout for cupsdDoSelect() */
+ struct rlimit limit; /* Runtime limit */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+#ifdef __sgi
+ cups_file_t *fp; /* Fake lpsched lock file */
+ struct stat statbuf; /* Needed for checking lpsched FIFO */
+#endif /* __sgi */
+ int run_as_child = 0;
+ /* Needed for background fork/exec */
+#ifdef __APPLE__
+ int use_sysman = !getuid();
+ /* Use system management functions? */
+#else
+ time_t netif_time = 0; /* Time since last network update */
+#endif /* __APPLE__ */
+#if HAVE_LAUNCHD
+ int launchd_idle_exit;
+ /* Idle exit on select timeout? */
+#endif /* HAVE_LAUNCHD */
+
+
+#ifdef HAVE_GETEUID
+ /*
+ * Check for setuid invocation, which we do not support!
+ */
+
+ if (getuid() != geteuid())
+ {
+ fputs("cupsd: Cannot run as a setuid program\n", stderr);
+ return (1);
+ }
+#endif /* HAVE_GETEUID */
+
+ /*
+ * Check for command-line arguments...
+ */
+
+ fg = 0;
+
+#ifdef HAVE_LAUNCHD
+ if (getenv("CUPSD_LAUNCHD"))
+ {
+ Launchd = 1;
+ fg = 1;
+ }
+#endif /* HAVE_LAUNCHD */
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ for (opt = argv[i] + 1; *opt != '\0'; opt ++)
+ switch (*opt)
+ {
+ case 'C' : /* Run as child with config file */
+ run_as_child = 1;
+ fg = -1;
+
+ case 'c' : /* Configuration file */
+ i ++;
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr, _("cupsd: Expected config filename "
+ "after \"-c\" option."));
+ usage(1);
+ }
+
+ if (argv[i][0] == '/')
+ {
+ /*
+ * Absolute directory...
+ */
+
+ cupsdSetString(&ConfigurationFile, argv[i]);
+ }
+ else
+ {
+ /*
+ * Relative directory...
+ */
+
+ char *current; /* Current directory */
+
+
+ /*
+ * Allocate a buffer for the current working directory to
+ * reduce run-time stack usage; this approximates the
+ * behavior of some implementations of getcwd() when they
+ * are passed a NULL pointer.
+ */
+
+ if ((current = malloc(1024)) == NULL)
+ {
+ _cupsLangPuts(stderr,
+ _("cupsd: Unable to get current directory."));
+ return (1);
+ }
+
+ if (!getcwd(current, 1024))
+ {
+ _cupsLangPuts(stderr,
+ _("cupsd: Unable to get current directory."));
+ free(current);
+ return (1);
+ }
+
+ cupsdSetStringf(&ConfigurationFile, "%s/%s", current, argv[i]);
+ free(current);
+ }
+ break;
+
+ case 'f' : /* Run in foreground... */
+ fg = 1;
+ break;
+
+ case 'F' : /* Run in foreground, but disconnect from terminal... */
+ fg = -1;
+ break;
+
+ case 'h' : /* Show usage/help */
+ usage(0);
+ break;
+
+ case 'l' : /* Started by launchd... */
+#ifdef HAVE_LAUNCHD
+ Launchd = 1;
+ fg = 1;
+#else
+ _cupsLangPuts(stderr, _("cupsd: launchd(8) support not compiled "
+ "in, running in normal mode."));
+ fg = 0;
+#endif /* HAVE_LAUNCHD */
+ break;
+
+ case 'p' : /* Stop immediately for profiling */
+ fputs("cupsd: -p (startup profiling) is for internal testing "
+ "use only!\n", stderr);
+ stop_scheduler = 1;
+ fg = 1;
+ break;
+
+ case 'P' : /* Disable security profiles */
+ fputs("cupsd: -P (disable security profiles) is for internal "
+ "testing use only!\n", stderr);
+ UseProfiles = 0;
+ break;
+
+#ifdef __APPLE__
+ case 'S' : /* Disable system management functions */
+ fputs("cupsd: -S (disable system management) for internal "
+ "testing use only!\n", stderr);
+ use_sysman = 0;
+ break;
+#endif /* __APPLE__ */
+
+ case 't' : /* Test the cupsd.conf file... */
+ TestConfigFile = 1;
+ fg = 1;
+ break;
+
+ default : /* Unknown option */
+ _cupsLangPrintf(stderr, _("cupsd: Unknown option \"%c\" - "
+ "aborting."), *opt);
+ usage(1);
+ break;
+ }
+ else
+ {
+ _cupsLangPrintf(stderr, _("cupsd: Unknown argument \"%s\" - aborting."),
+ argv[i]);
+ usage(1);
+ }
+
+ if (!ConfigurationFile)
+ cupsdSetString(&ConfigurationFile, CUPS_SERVERROOT "/cupsd.conf");
+
+ /*
+ * If the user hasn't specified "-f", run in the background...
+ */
+
+ if (!fg)
+ {
+ /*
+ * Setup signal handlers for the parent...
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGUSR1, parent_handler);
+ sigset(SIGCHLD, parent_handler);
+
+ sigset(SIGHUP, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGUSR1);
+ action.sa_handler = parent_handler;
+ sigaction(SIGUSR1, &action, NULL);
+ sigaction(SIGCHLD, &action, NULL);
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGHUP, &action, NULL);
+#else
+ signal(SIGUSR1, parent_handler);
+ signal(SIGCLD, parent_handler);
+
+ signal(SIGHUP, SIG_IGN);
+#endif /* HAVE_SIGSET */
+
+ if (fork() > 0)
+ {
+ /*
+ * OK, wait for the child to startup and send us SIGUSR1 or to crash
+ * and the OS send us SIGCHLD... We also need to ignore SIGHUP which
+ * might be sent by the init script to restart the scheduler...
+ */
+
+ for (; parent_signal == 0;)
+ sleep(1);
+
+ if (parent_signal == SIGUSR1)
+ return (0);
+
+ if (wait(&i) < 0)
+ {
+ perror("cupsd");
+ return (1);
+ }
+ else if (WIFEXITED(i))
+ {
+ fprintf(stderr, "cupsd: Child exited with status %d\n",
+ WEXITSTATUS(i));
+ return (2);
+ }
+ else
+ {
+ fprintf(stderr, "cupsd: Child exited on signal %d\n", WTERMSIG(i));
+ return (3);
+ }
+ }
+
+#ifdef __OpenBSD__
+ /*
+ * Call _thread_sys_closefrom() so the child process doesn't reset the
+ * parent's file descriptors to be blocking. This is a workaround for a
+ * limitation of userland libpthread on OpenBSD.
+ */
+
+ _thread_sys_closefrom(0);
+#endif /* __OpenBSD__ */
+
+ /*
+ * Since CoreFoundation and DBUS both create fork-unsafe data on execution of
+ * a program, and since this kind of really unfriendly behavior seems to be
+ * more common these days in system libraries, we need to re-execute the
+ * background cupsd with the "-C" option to avoid problems. Unfortunately,
+ * we also have to assume that argv[0] contains the name of the cupsd
+ * executable - there is no portable way to get the real pathname...
+ */
+
+ execlp(argv[0], argv[0], "-C", ConfigurationFile, (char *)0);
+ exit(errno);
+ }
+
+ if (fg < 1)
+ {
+ /*
+ * Make sure we aren't tying up any filesystems...
+ */
+
+ chdir("/");
+
+#ifndef DEBUG
+ /*
+ * Disable core dumps...
+ */
+
+ getrlimit(RLIMIT_CORE, &limit);
+ limit.rlim_cur = 0;
+ setrlimit(RLIMIT_CORE, &limit);
+
+ /*
+ * Disconnect from the controlling terminal...
+ */
+
+ setsid();
+
+ /*
+ * Close all open files...
+ */
+
+ getrlimit(RLIMIT_NOFILE, &limit);
+
+ for (i = 0; i < limit.rlim_cur && i < 1024; i ++)
+ close(i);
+
+ /*
+ * Redirect stdin/out/err to /dev/null...
+ */
+
+ if ((i = open("/dev/null", O_RDONLY)) != 0)
+ {
+ dup2(i, 0);
+ close(i);
+ }
+
+ if ((i = open("/dev/null", O_WRONLY)) != 1)
+ {
+ dup2(i, 1);
+ close(i);
+ }
+
+ if ((i = open("/dev/null", O_WRONLY)) != 2)
+ {
+ dup2(i, 2);
+ close(i);
+ }
+#endif /* DEBUG */
+ }
+
+ /*
+ * Set the timezone info...
+ */
+
+ tzset();
+
+#ifdef LC_TIME
+ setlocale(LC_TIME, "");
+#endif /* LC_TIME */
+
+ /*
+ * Set the maximum number of files...
+ */
+
+ getrlimit(RLIMIT_NOFILE, &limit);
+
+#if !defined(HAVE_POLL) && !defined(HAVE_EPOLL) && !defined(HAVE_KQUEUE)
+ if (limit.rlim_max > FD_SETSIZE)
+ MaxFDs = FD_SETSIZE;
+ else
+#endif /* !HAVE_POLL && !HAVE_EPOLL && !HAVE_KQUEUE */
+#ifdef RLIM_INFINITY
+ if (limit.rlim_max == RLIM_INFINITY)
+ MaxFDs = 16384;
+ else
+#endif /* RLIM_INFINITY */
+ MaxFDs = limit.rlim_max;
+
+ limit.rlim_cur = MaxFDs;
+
+ setrlimit(RLIMIT_NOFILE, &limit);
+
+ cupsdStartSelect();
+
+ /*
+ * Read configuration...
+ */
+
+ if (!cupsdReadConfiguration())
+ {
+ if (TestConfigFile)
+ printf("%s contains errors\n", ConfigurationFile);
+ else
+ syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
+ ConfigurationFile);
+ return (1);
+ }
+ else if (TestConfigFile)
+ {
+ printf("%s is OK\n", ConfigurationFile);
+ return (0);
+ }
+
+ /*
+ * Clean out old temp files and printer cache data.
+ */
+
+ if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)))
+ cupsdCleanFiles(TempDir, NULL);
+
+ cupsdCleanFiles(CacheDir, "*.ipp");
+
+#if HAVE_LAUNCHD
+ if (Launchd)
+ {
+ /*
+ * If we were started by launchd get the listen sockets file descriptors...
+ */
+
+ launchd_checkin();
+ launchd_checkout();
+ }
+#endif /* HAVE_LAUNCHD */
+
+ /*
+ * Startup the server...
+ */
+
+ httpInitialize();
+
+ cupsdStartServer();
+
+ /*
+ * Catch hangup and child signals and ignore broken pipes...
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGCHLD, sigchld_handler);
+ sigset(SIGHUP, sighup_handler);
+ sigset(SIGPIPE, SIG_IGN);
+ sigset(SIGTERM, sigterm_handler);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGTERM);
+ sigaddset(&action.sa_mask, SIGCHLD);
+ action.sa_handler = sigchld_handler;
+ sigaction(SIGCHLD, &action, NULL);
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGHUP);
+ action.sa_handler = sighup_handler;
+ sigaction(SIGHUP, &action, NULL);
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGTERM);
+ sigaddset(&action.sa_mask, SIGCHLD);
+ action.sa_handler = sigterm_handler;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */
+ signal(SIGHUP, sighup_handler);
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGTERM, sigterm_handler);
+#endif /* HAVE_SIGSET */
+
+#ifdef __sgi
+ /*
+ * Try to create a fake lpsched lock file if one is not already there.
+ * Some Adobe applications need it under IRIX in order to enable
+ * printing...
+ */
+
+ if ((fp = cupsFileOpen("/var/spool/lp/SCHEDLOCK", "w")) == NULL)
+ {
+ syslog(LOG_LPR, "Unable to create fake lpsched lock file "
+ "\"/var/spool/lp/SCHEDLOCK\"\' - %s!",
+ strerror(errno));
+ }
+ else
+ {
+ fchmod(cupsFileNumber(fp), 0644);
+ fchown(cupsFileNumber(fp), User, Group);
+
+ cupsFileClose(fp);
+ }
+#endif /* __sgi */
+
+ /*
+ * Initialize authentication certificates...
+ */
+
+ cupsdInitCerts();
+
+ /*
+ * If we are running in the background, signal the parent process that
+ * we are up and running...
+ */
+
+ if (!fg || run_as_child)
+ {
+ /*
+ * Send a signal to the parent process, but only if the parent is
+ * not PID 1 (init). This avoids accidentally shutting down the
+ * system on OpenBSD if you CTRL-C the server before it is up...
+ */
+
+ i = getppid(); /* Save parent PID to avoid race condition */
+
+ if (i != 1)
+ kill(i, SIGUSR1);
+ }
+
+#ifdef __APPLE__
+ /*
+ * Start power management framework...
+ */
+
+ if (use_sysman)
+ cupsdStartSystemMonitor();
+#endif /* __APPLE__ */
+
+ /*
+ * Send server-started event...
+ */
+
+#ifdef HAVE_LAUNCHD
+ if (Launchd)
+ cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL,
+ "Scheduler started via launchd.");
+ else
+#endif /* HAVE_LAUNCHD */
+ if (fg)
+ cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL,
+ "Scheduler started in foreground.");
+ else
+ cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL,
+ "Scheduler started in background.");
+
+ /*
+ * Start any pending print jobs...
+ */
+
+ cupsdCheckJobs();
+
+ /*
+ * Loop forever...
+ */
+
+ current_time = time(NULL);
+ browse_time = current_time;
+ event_time = current_time;
+ expire_time = current_time;
+ fds = 1;
+ report_time = 0;
+ senddoc_time = current_time;
+
+ while (!stop_scheduler)
+ {
+ /*
+ * Check if there are dead children to handle...
+ */
+
+ if (dead_children)
+ process_children();
+
+ /*
+ * Check if we need to load the server configuration file...
+ */
+
+ if (NeedReload)
+ {
+ /*
+ * Close any idle clients...
+ */
+
+ if (cupsArrayCount(Clients) > 0)
+ {
+ for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
+ con;
+ con = (cupsd_client_t *)cupsArrayNext(Clients))
+ if (con->http.state == HTTP_WAITING)
+ cupsdCloseClient(con);
+ else
+ con->http.keep_alive = HTTP_KEEPALIVE_OFF;
+
+ cupsdPauseListening();
+ }
+
+ /*
+ * Restart if all clients are closed and all jobs finished, or
+ * if the reload timeout has elapsed...
+ */
+
+ if ((cupsArrayCount(Clients) == 0 &&
+ (cupsArrayCount(PrintingJobs) == 0 || NeedReload != RELOAD_ALL)) ||
+ (time(NULL) - ReloadTime) >= ReloadTimeout)
+ {
+ /*
+ * Shutdown the server...
+ */
+
+ DoingShutdown = 1;
+
+ cupsdStopServer();
+
+ /*
+ * Read configuration...
+ */
+
+ if (!cupsdReadConfiguration())
+ {
+ syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
+ ConfigurationFile);
+ break;
+ }
+
+#if HAVE_LAUNCHD
+ if (Launchd)
+ {
+ /*
+ * If we were started by launchd, get the listen socket file
+ * descriptors...
+ */
+
+ launchd_checkin();
+ launchd_checkout();
+ }
+#endif /* HAVE_LAUNCHD */
+
+ /*
+ * Startup the server...
+ */
+
+ DoingShutdown = 0;
+
+ cupsdStartServer();
+
+ /*
+ * Send a server-restarted event...
+ */
+
+ cupsdAddEvent(CUPSD_EVENT_SERVER_RESTARTED, NULL, NULL,
+ "Scheduler restarted.");
+ }
+ }
+
+ /*
+ * Check for available input or ready output. If cupsdDoSelect()
+ * returns 0 or -1, something bad happened and we should exit
+ * immediately.
+ *
+ * Note that we at least have one listening socket open at all
+ * times.
+ */
+
+ if ((timeout = select_timeout(fds)) > 1 && LastEvent)
+ timeout = 1;
+
+#if HAVE_LAUNCHD
+ /*
+ * If no other work is scheduled and we're being controlled by
+ * launchd then timeout after 'LaunchdTimeout' seconds of
+ * inactivity...
+ */
+
+ if (timeout == 86400 && Launchd && LaunchdTimeout && !NumPolled &&
+ !cupsArrayCount(ActiveJobs) &&
+ (!Browsing ||
+ (!BrowseRemoteProtocols &&
+ (!BrowseLocalProtocols || !cupsArrayCount(Printers)))))
+ {
+ timeout = LaunchdTimeout;
+ launchd_idle_exit = 1;
+ }
+ else
+ launchd_idle_exit = 0;
+#endif /* HAVE_LAUNCHD */
+
+ if ((fds = cupsdDoSelect(timeout)) < 0)
+ {
+ /*
+ * Got an error from select!
+ */
+
+#ifdef HAVE_DNSSD
+ cupsd_printer_t *p; /* Current printer */
+#endif /* HAVE_DNSSD */
+
+
+ if (errno == EINTR) /* Just interrupted by a signal */
+ continue;
+
+ /*
+ * Log all sorts of debug info to help track down the problem.
+ */
+
+ cupsdLogMessage(CUPSD_LOG_EMERG, "cupsdDoSelect() failed - %s!",
+ strerror(errno));
+
+ for (i = 0, con = (cupsd_client_t *)cupsArrayFirst(Clients);
+ con;
+ i ++, con = (cupsd_client_t *)cupsArrayNext(Clients))
+ cupsdLogMessage(CUPSD_LOG_EMERG,
+ "Clients[%d] = %d, file = %d, state = %d",
+ i, con->http.fd, con->file, con->http.state);
+
+ for (i = 0, lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ i ++, lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ cupsdLogMessage(CUPSD_LOG_EMERG, "Listeners[%d] = %d", i, lis->fd);
+
+ cupsdLogMessage(CUPSD_LOG_EMERG, "BrowseSocket = %d", BrowseSocket);
+
+ cupsdLogMessage(CUPSD_LOG_EMERG, "CGIPipes[0] = %d", CGIPipes[0]);
+
+#ifdef __APPLE__
+ cupsdLogMessage(CUPSD_LOG_EMERG, "SysEventPipes[0] = %d",
+ SysEventPipes[0]);
+#endif /* __APPLE__ */
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
+ cupsdLogMessage(CUPSD_LOG_EMERG, "Jobs[%d] = %d < [%d %d] > [%d %d]",
+ job->id,
+ job->status_buffer ? job->status_buffer->fd : -1,
+ job->print_pipes[0], job->print_pipes[1],
+ job->back_pipes[0], job->back_pipes[1]);
+
+#ifdef HAVE_DNSSD
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ cupsdLogMessage(CUPSD_LOG_EMERG, "printer[%s] reg_name=\"%s\"", p->name,
+ p->reg_name ? p->reg_name : "(null)");
+#endif /* HAVE_DNSSD */
+
+ break;
+ }
+
+ current_time = time(NULL);
+
+ /*
+ * Write dirty config/state files...
+ */
+
+ if (DirtyCleanTime && current_time >= DirtyCleanTime)
+ cupsdCleanDirty();
+
+#ifdef __APPLE__
+ /*
+ * If we are going to sleep and still have pending jobs, stop them after
+ * a period of time...
+ */
+
+ if (SleepJobs > 0 && current_time >= SleepJobs &&
+ cupsArrayCount(PrintingJobs) > 0)
+ {
+ SleepJobs = 0;
+ cupsdStopAllJobs(CUPSD_JOB_DEFAULT, 5);
+ }
+#endif /* __APPLE__ */
+
+#ifndef __APPLE__
+ /*
+ * Update the network interfaces once a minute...
+ */
+
+ if ((current_time - netif_time) >= 60)
+ {
+ netif_time = current_time;
+ NetIFUpdate = 1;
+ }
+#endif /* !__APPLE__ */
+
+#if HAVE_LAUNCHD
+ /*
+ * If no other work was scheduled and we're being controlled by launchd
+ * then timeout after 'LaunchdTimeout' seconds of inactivity...
+ */
+
+ if (!fds && launchd_idle_exit)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Printer sharing is off and there are no jobs pending, "
+ "will restart on demand.");
+ stop_scheduler = 1;
+ break;
+ }
+#endif /* HAVE_LAUNCHD */
+
+ /*
+ * Resume listening for new connections as needed...
+ */
+
+ if (ListeningPaused && ListeningPaused <= current_time &&
+ cupsArrayCount(Clients) < MaxClients)
+ cupsdResumeListening();
+
+ /*
+ * Expire subscriptions and unload completed jobs as needed...
+ */
+
+ if (current_time > expire_time)
+ {
+ if (cupsArrayCount(Subscriptions) > 0)
+ cupsdExpireSubscriptions(NULL, NULL);
+
+ cupsdUnloadCompletedJobs();
+
+ expire_time = current_time;
+ }
+
+ /*
+ * Update the browse list as needed...
+ */
+
+ if (Browsing)
+ {
+#ifdef HAVE_LIBSLP
+ if ((BrowseRemoteProtocols & BROWSE_SLP) &&
+ BrowseSLPRefresh <= current_time)
+ cupsdUpdateSLPBrowse();
+#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_LDAP
+ if ((BrowseRemoteProtocols & BROWSE_LDAP) &&
+ BrowseLDAPRefresh <= current_time)
+ cupsdUpdateLDAPBrowse();
+#endif /* HAVE_LDAP */
+ }
+
+ if (Browsing && current_time > browse_time)
+ {
+ cupsdSendBrowseList();
+ browse_time = current_time;
+ }
+
+#ifndef HAVE_AUTHORIZATION_H
+ /*
+ * Update the root certificate once every 5 minutes if we have client
+ * connections...
+ */
+
+ if ((current_time - RootCertTime) >= RootCertDuration && RootCertDuration &&
+ !RunUser && cupsArrayCount(Clients))
+ {
+ /*
+ * Update the root certificate...
+ */
+
+ cupsdDeleteCert(0);
+ cupsdAddCert(0, "root", NULL);
+ }
+#endif /* !HAVE_AUTHORIZATION_H */
+
+ /*
+ * Check for new data on the client sockets...
+ */
+
+ for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
+ con;
+ con = (cupsd_client_t *)cupsArrayNext(Clients))
+ {
+ /*
+ * Process pending data in the input buffer...
+ */
+
+ if (con->http.used)
+ {
+ cupsdReadClient(con);
+ continue;
+ }
+
+ /*
+ * Check the activity and close old clients...
+ */
+
+ activity = current_time - Timeout;
+ if (con->http.activity < activity && !con->pipe_pid)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Closing client %d after %d seconds of inactivity...",
+ con->http.fd, Timeout);
+
+ cupsdCloseClient(con);
+ continue;
+ }
+ }
+
+ /*
+ * Update any pending multi-file documents...
+ */
+
+ if ((current_time - senddoc_time) >= 10)
+ {
+ cupsdCheckJobs();
+ cupsdCleanJobs();
+ senddoc_time = current_time;
+ }
+
+ /*
+ * Log statistics at most once a minute when in debug mode...
+ */
+
+ if ((current_time - report_time) >= 60 && LogLevel >= CUPSD_LOG_DEBUG)
+ {
+ size_t string_count, /* String count */
+ alloc_bytes, /* Allocated string bytes */
+ total_bytes; /* Total string bytes */
+#ifdef HAVE_MALLINFO
+ struct mallinfo mem; /* Malloc information */
+
+
+ mem = mallinfo();
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-arena=%lu", mem.arena);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-used=%lu",
+ mem.usmblks + mem.uordblks);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-free=%lu",
+ mem.fsmblks + mem.fordblks);
+#endif /* HAVE_MALLINFO */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: clients=%d",
+ cupsArrayCount(Clients));
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: jobs=%d",
+ cupsArrayCount(Jobs));
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: jobs-active=%d",
+ cupsArrayCount(ActiveJobs));
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: printers=%d",
+ cupsArrayCount(Printers));
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: printers-implicit=%d",
+ cupsArrayCount(ImplicitPrinters));
+
+ string_count = _cupsStrStatistics(&alloc_bytes, &total_bytes);
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Report: stringpool-string-count=" CUPS_LLFMT,
+ CUPS_LLCAST string_count);
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Report: stringpool-alloc-bytes=" CUPS_LLFMT,
+ CUPS_LLCAST alloc_bytes);
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Report: stringpool-total-bytes=" CUPS_LLFMT,
+ CUPS_LLCAST total_bytes);
+
+ report_time = current_time;
+ }
+
+ /*
+ * Handle OS-specific event notification for any events that have
+ * accumulated. Don't send these more than once a second...
+ */
+
+ if (LastEvent && (current_time - event_time) >= 1)
+ {
+#ifdef HAVE_NOTIFY_POST
+ if (LastEvent & (CUPSD_EVENT_PRINTER_ADDED |
+ CUPSD_EVENT_PRINTER_DELETED |
+ CUPSD_EVENT_PRINTER_MODIFIED))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "notify_post(\"com.apple.printerListChange\")");
+ notify_post("com.apple.printerListChange");
+ }
+
+ if (LastEvent & CUPSD_EVENT_PRINTER_STATE_CHANGED)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "notify_post(\"com.apple.printerHistoryChange\")");
+ notify_post("com.apple.printerHistoryChange");
+ }
+
+ if (LastEvent & (CUPSD_EVENT_JOB_STATE_CHANGED |
+ CUPSD_EVENT_JOB_CONFIG_CHANGED |
+ CUPSD_EVENT_JOB_PROGRESS))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "notify_post(\"com.apple.jobChange\")");
+ notify_post("com.apple.jobChange");
+ }
+#endif /* HAVE_NOTIFY_POST */
+
+ /*
+ * Reset the accumulated events...
+ */
+
+ LastEvent = CUPSD_EVENT_NONE;
+ event_time = current_time;
+ }
+ }
+
+ /*
+ * Log a message based on what happened...
+ */
+
+ if (stop_scheduler)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "Scheduler shutting down normally.");
+ cupsdAddEvent(CUPSD_EVENT_SERVER_STOPPED, NULL, NULL,
+ "Scheduler shutting down normally.");
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Scheduler shutting down due to program error.");
+ cupsdAddEvent(CUPSD_EVENT_SERVER_STOPPED, NULL, NULL,
+ "Scheduler shutting down due to program error.");
+ }
+
+ /*
+ * Close all network clients...
+ */
+
+ DoingShutdown = 1;
+
+ cupsdStopServer();
+
+#ifdef HAVE_LAUNCHD
+ /*
+ * Update the launchd KeepAlive file as needed...
+ */
+
+ if (Launchd)
+ launchd_checkout();
+#endif /* HAVE_LAUNCHD */
+
+ /*
+ * Stop all jobs...
+ */
+
+ cupsdFreeAllJobs();
+
+#ifdef __APPLE__
+ /*
+ * Stop monitoring system event monitoring...
+ */
+
+ if (use_sysman)
+ cupsdStopSystemMonitor();
+#endif /* __APPLE__ */
+
+#ifdef HAVE_GSSAPI
+ /*
+ * Free the scheduler's Kerberos context...
+ */
+
+# ifdef __APPLE__
+ /*
+ * If the weak-linked GSSAPI/Kerberos library is not present, don't try
+ * to use it...
+ */
+
+ if (krb5_init_context != NULL)
+# endif /* __APPLE__ */
+ if (KerberosContext)
+ krb5_free_context(KerberosContext);
+#endif /* HAVE_GSSAPI */
+
+#ifdef __sgi
+ /*
+ * Remove the fake IRIX lpsched lock file, but only if the existing
+ * file is not a FIFO which indicates that the real IRIX lpsched is
+ * running...
+ */
+
+ if (!stat("/var/spool/lp/FIFO", &statbuf))
+ if (!S_ISFIFO(statbuf.st_mode))
+ unlink("/var/spool/lp/SCHEDLOCK");
+#endif /* __sgi */
+
+ cupsdStopSelect();
+
+ return (!stop_scheduler);
+}
+
+
+/*
+ * 'cupsdAddString()' - Copy and add a string to an array.
+ */
+
+int /* O - 1 on success, 0 on failure */
+cupsdAddString(cups_array_t **a, /* IO - String array */
+ const char *s) /* I - String to copy and add */
+{
+ if (!*a)
+ *a = cupsArrayNew3((cups_array_func_t)strcmp, NULL,
+ (cups_ahash_func_t)NULL, 0,
+ (cups_acopy_func_t)_cupsStrAlloc,
+ (cups_afree_func_t)_cupsStrFree);
+
+ return (cupsArrayAdd(*a, (char *)s));
+}
+
+
+/*
+ * 'cupsdCheckProcess()' - Tell the main loop to check for dead children.
+ */
+
+void
+cupsdCheckProcess(void)
+{
+ /*
+ * Flag that we have dead children...
+ */
+
+ dead_children = 1;
+}
+
+
+/*
+ * 'cupsdClearString()' - Clear a string.
+ */
+
+void
+cupsdClearString(char **s) /* O - String value */
+{
+ if (s && *s)
+ {
+ _cupsStrFree(*s);
+ *s = NULL;
+ }
+}
+
+
+/*
+ * 'cupsdFreeStrings()' - Free an array of strings.
+ */
+
+void
+cupsdFreeStrings(cups_array_t **a) /* IO - String array */
+{
+ if (*a)
+ {
+ cupsArrayDelete(*a);
+ *a = NULL;
+ }
+}
+
+
+/*
+ * 'cupsdHoldSignals()' - Hold child and termination signals.
+ */
+
+void
+cupsdHoldSignals(void)
+{
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ sigset_t newmask; /* New POSIX signal mask */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ holdcount ++;
+ if (holdcount > 1)
+ return;
+
+#ifdef HAVE_SIGSET
+ sighold(SIGTERM);
+ sighold(SIGCHLD);
+#elif defined(HAVE_SIGACTION)
+ sigemptyset(&newmask);
+ sigaddset(&newmask, SIGTERM);
+ sigaddset(&newmask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &newmask, &holdmask);
+#endif /* HAVE_SIGSET */
+}
+
+
+/*
+ * 'cupsdReleaseSignals()' - Release signals for delivery.
+ */
+
+void
+cupsdReleaseSignals(void)
+{
+ holdcount --;
+ if (holdcount > 0)
+ return;
+
+#ifdef HAVE_SIGSET
+ sigrelse(SIGTERM);
+ sigrelse(SIGCHLD);
+#elif defined(HAVE_SIGACTION)
+ sigprocmask(SIG_SETMASK, &holdmask, NULL);
+#endif /* HAVE_SIGSET */
+}
+
+
+/*
+ * 'cupsdSetString()' - Set a string value.
+ */
+
+void
+cupsdSetString(char **s, /* O - New string */
+ const char *v) /* I - String value */
+{
+ if (!s || *s == v)
+ return;
+
+ if (*s)
+ _cupsStrFree(*s);
+
+ if (v)
+ *s = _cupsStrAlloc(v);
+ else
+ *s = NULL;
+}
+
+
+/*
+ * 'cupsdSetStringf()' - Set a formatted string value.
+ */
+
+void
+cupsdSetStringf(char **s, /* O - New string */
+ const char *f, /* I - Printf-style format string */
+ ...) /* I - Additional args as needed */
+{
+ char v[4096]; /* Formatting string value */
+ va_list ap; /* Argument pointer */
+ char *olds; /* Old string */
+
+
+ if (!s)
+ return;
+
+ olds = *s;
+
+ if (f)
+ {
+ va_start(ap, f);
+ vsnprintf(v, sizeof(v), f, ap);
+ va_end(ap);
+
+ *s = _cupsStrAlloc(v);
+ }
+ else
+ *s = NULL;
+
+ if (olds)
+ _cupsStrFree(olds);
+}
+
+
+#ifdef HAVE_LAUNCHD
+/*
+ * 'launchd_checkin()' - Check-in with launchd and collect the listening fds.
+ */
+
+static void
+launchd_checkin(void)
+{
+ size_t i, /* Looping var */
+ count; /* Number of listeners */
+ launch_data_t ld_msg, /* Launch data message */
+ ld_resp, /* Launch data response */
+ ld_array, /* Launch data array */
+ ld_sockets, /* Launch data sockets dictionary */
+ tmp; /* Launch data */
+ cupsd_listener_t *lis; /* Listeners array */
+ http_addr_t addr; /* Address variable */
+ socklen_t addrlen; /* Length of address */
+ int fd; /* File descriptor */
+ char s[256]; /* String addresss */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "launchd_checkin: pid=%d", (int)getpid());
+
+ /*
+ * Check-in with launchd...
+ */
+
+ ld_msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
+ if ((ld_resp = launch_msg(ld_msg)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_checkin: launch_msg(\"" LAUNCH_KEY_CHECKIN
+ "\") IPC failure");
+ exit(EXIT_FAILURE);
+ return; /* anti-compiler-warning */
+ }
+
+ if (launch_data_get_type(ld_resp) == LAUNCH_DATA_ERRNO)
+ {
+ errno = launch_data_get_errno(ld_resp);
+ cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_checkin: Check-in failed: %s",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ return; /* anti-compiler-warning */
+ }
+
+ /*
+ * Get the sockets dictionary...
+ */
+
+ if ((ld_sockets = launch_data_dict_lookup(ld_resp, LAUNCH_JOBKEY_SOCKETS))
+ == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_checkin: No sockets found to answer requests on!");
+ exit(EXIT_FAILURE);
+ return; /* anti-compiler-warning */
+ }
+
+ /*
+ * Get the array of listener sockets...
+ */
+
+ if ((ld_array = launch_data_dict_lookup(ld_sockets, "Listeners")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_checkin: No sockets found to answer requests on!");
+ exit(EXIT_FAILURE);
+ return; /* anti-compiler-warning */
+ }
+
+ /*
+ * Add listening fd(s) to the Listener array...
+ */
+
+ if (launch_data_get_type(ld_array) == LAUNCH_DATA_ARRAY)
+ {
+ count = launch_data_array_get_count(ld_array);
+
+ for (i = 0; i < count; i ++)
+ {
+ /*
+ * Get the launchd file descriptor and address...
+ */
+
+ if ((tmp = launch_data_array_get_index(ld_array, i)) != NULL)
+ {
+ fd = launch_data_get_fd(tmp);
+ addrlen = sizeof(addr);
+
+ if (getsockname(fd, (struct sockaddr *)&addr, &addrlen))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_checkin: Unable to get local address - %s",
+ strerror(errno));
+ continue;
+ }
+
+ /*
+ * Try to match the launchd socket address to one of the listeners...
+ */
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ if (httpAddrEqual(&lis->address, &addr))
+ break;
+
+ /*
+ * Add a new listener If there's no match...
+ */
+
+ if (lis)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "launchd_checkin: Matched existing listener %s with fd %d...",
+ httpAddrString(&(lis->address), s, sizeof(s)), fd);
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "launchd_checkin: Adding new listener %s with fd %d...",
+ httpAddrString(&addr, s, sizeof(s)), fd);
+
+ if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_checkin: Unable to allocate listener - "
+ "%s.", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ cupsArrayAdd(Listeners, lis);
+
+ memcpy(&lis->address, &addr, sizeof(lis->address));
+ }
+
+ lis->fd = fd;
+
+# ifdef HAVE_SSL
+ if (_httpAddrPort(&(lis->address)) == 443)
+ lis->encryption = HTTP_ENCRYPT_ALWAYS;
+# endif /* HAVE_SSL */
+ }
+ }
+ }
+
+ launch_data_free(ld_msg);
+ launch_data_free(ld_resp);
+}
+
+
+/*
+ * 'launchd_checkout()' - Update the launchd KeepAlive file as needed.
+ */
+
+static void
+launchd_checkout(void)
+{
+ int fd; /* File descriptor */
+
+
+ /*
+ * Create or remove the launchd KeepAlive file based on whether
+ * there are active jobs, polling, browsing for remote printers or
+ * shared printers to advertise...
+ */
+
+ if (cupsArrayCount(ActiveJobs) || NumPolled ||
+ (Browsing &&
+ (BrowseRemoteProtocols ||
+ (BrowseLocalProtocols && cupsArrayCount(Printers)))))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Creating launchd keepalive file \"" CUPS_KEEPALIVE
+ "\"...");
+
+ if ((fd = open(CUPS_KEEPALIVE, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR)) >= 0)
+ close(fd);
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Removing launchd keepalive file \"" CUPS_KEEPALIVE
+ "\"...");
+
+ unlink(CUPS_KEEPALIVE);
+ }
+}
+#endif /* HAVE_LAUNCHD */
+
+
+/*
+ * 'parent_handler()' - Catch USR1/CHLD signals...
+ */
+
+static void
+parent_handler(int sig) /* I - Signal */
+{
+ /*
+ * Store the signal we got from the OS and return...
+ */
+
+ parent_signal = sig;
+}
+
+
+/*
+ * 'process_children()' - Process all dead children...
+ */
+
+static void
+process_children(void)
+{
+ int status; /* Exit status of child */
+ int pid, /* Process ID of child */
+ job_id; /* Job ID of child */
+ cupsd_job_t *job; /* Current job */
+ int i; /* Looping var */
+ char name[1024]; /* Process name */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_children()");
+
+ /*
+ * Reset the dead_children flag...
+ */
+
+ dead_children = 0;
+
+ /*
+ * Collect the exit status of some children...
+ */
+
+#ifdef HAVE_WAITPID
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+#elif defined(HAVE_WAIT3)
+ while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
+#else
+ if ((pid = wait(&status)) > 0)
+#endif /* HAVE_WAITPID */
+ {
+ /*
+ * Collect the name of the process that finished...
+ */
+
+ cupsdFinishProcess(pid, name, sizeof(name), &job_id);
+
+ /*
+ * Delete certificates for CGI processes...
+ */
+
+ if (pid)
+ cupsdDeleteCert(pid);
+
+ /*
+ * Handle completed job filters...
+ */
+
+ if (job_id > 0 && (job = cupsdFindJob(job_id)) != NULL)
+ {
+ for (i = 0; job->filters[i]; i ++)
+ if (job->filters[i] == pid)
+ break;
+
+ if (job->filters[i] || job->backend == pid)
+ {
+ /*
+ * OK, this process has gone away; what's left?
+ */
+
+ if (job->filters[i])
+ job->filters[i] = -pid;
+ else
+ job->backend = -pid;
+
+ if (status && status != SIGTERM && status != SIGKILL &&
+ status != SIGPIPE && job->status >= 0)
+ {
+ /*
+ * An error occurred; save the exit status so we know to stop
+ * the printer or cancel the job when all of the filters finish...
+ *
+ * A negative status indicates that the backend failed and the
+ * printer needs to be stopped.
+ */
+
+ if (job->filters[i])
+ job->status = status; /* Filter failed */
+ else
+ job->status = -status; /* Backend failed */
+
+ if (job->state_value == IPP_JOB_PROCESSING &&
+ job->status_level > CUPSD_LOG_ERROR)
+ {
+ char message[1024]; /* New printer-state-message */
+
+
+ job->status_level = CUPSD_LOG_ERROR;
+
+ snprintf(message, sizeof(message), "%s failed", name);
+
+ if (job->printer)
+ {
+ strlcpy(job->printer->state_message, message,
+ sizeof(job->printer->state_message));
+ }
+
+ if (!job->attrs)
+ cupsdLoadJob(job);
+
+ if (!job->printer_message && job->attrs)
+ {
+ if ((job->printer_message =
+ ippFindAttribute(job->attrs, "job-printer-state-message",
+ IPP_TAG_TEXT)) == NULL)
+ job->printer_message = ippAddString(job->attrs, IPP_TAG_JOB,
+ IPP_TAG_TEXT,
+ "job-printer-state-message",
+ NULL, NULL);
+ }
+
+ if (job->printer_message)
+ cupsdSetString(&(job->printer_message->values[0].string.text),
+ message);
+ }
+ }
+
+ /*
+ * If this is not the last file in a job, see if all of the
+ * filters are done, and if so move to the next file.
+ */
+
+ if (job->current_file < job->num_files && job->printer)
+ {
+ for (i = 0; job->filters[i] < 0; i ++);
+
+ if (!job->filters[i] &&
+ (!job->printer->pc || !job->printer->pc->single_file ||
+ job->backend <= 0))
+ {
+ /*
+ * Process the next file...
+ */
+
+ cupsdContinueJob(job);
+ }
+ }
+ else if (job->state_value >= IPP_JOB_CANCELED)
+ {
+ /*
+ * Remove the job from the active list if there are no processes still
+ * running for it...
+ */
+
+ for (i = 0; job->filters[i] < 0; i++);
+
+ if (!job->filters[i] && job->backend <= 0)
+ cupsArrayRemove(ActiveJobs, job);
+ }
+ }
+ }
+
+ /*
+ * Show the exit status as needed, ignoring SIGTERM and SIGKILL errors
+ * since they come when we kill/end a process...
+ */
+
+ if (status == SIGTERM || status == SIGKILL)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "PID %d (%s) was terminated normally with signal %d.",
+ pid, name, status);
+ }
+ else if (status == SIGPIPE)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "PID %d (%s) did not catch or ignore signal %d.",
+ pid, name, status);
+ }
+ else if (status)
+ {
+ if (WIFEXITED(status))
+ {
+ int code = WEXITSTATUS(status); /* Exit code */
+
+ if (code > 100)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "PID %d (%s) stopped with status %d (%s)", pid, name,
+ code, strerror(code - 100));
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "PID %d (%s) stopped with status %d.", pid, name,
+ code);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d (%s) crashed on signal %d.",
+ pid, name, WTERMSIG(status));
+
+ if (LogLevel < CUPSD_LOG_DEBUG)
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Hint: Try setting the LogLevel to \"debug\" to find "
+ "out more.");
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "PID %d (%s) exited with no errors.",
+ pid, name);
+ }
+
+ /*
+ * If wait*() is interrupted by a signal, tell main() to call us again...
+ */
+
+ if (pid < 0 && errno == EINTR)
+ dead_children = 1;
+}
+
+
+/*
+ * 'select_timeout()' - Calculate the select timeout value.
+ *
+ */
+
+static long /* O - Number of seconds */
+select_timeout(int fds) /* I - Number of descriptors returned */
+{
+ long timeout; /* Timeout for select */
+ time_t now; /* Current time */
+ cupsd_client_t *con; /* Client information */
+ cupsd_printer_t *p; /* Printer information */
+ cupsd_job_t *job; /* Job information */
+ cupsd_subscription_t *sub; /* Subscription information */
+ const char *why; /* Debugging aid */
+
+
+ /*
+ * Check to see if any of the clients have pending data to be
+ * processed; if so, the timeout should be 0...
+ */
+
+ for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
+ con;
+ con = (cupsd_client_t *)cupsArrayNext(Clients))
+ if (con->http.used > 0)
+ return (0);
+
+ /*
+ * If select has been active in the last second (fds > 0) or we have
+ * many resources in use then don't bother trying to optimize the
+ * timeout, just make it 1 second.
+ */
+
+ if (fds > 0 || cupsArrayCount(Clients) > 50)
+ return (1);
+
+ /*
+ * Otherwise, check all of the possible events that we need to wake for...
+ */
+
+ now = time(NULL);
+ timeout = now + 86400; /* 86400 == 1 day */
+ why = "do nothing";
+
+#ifdef __APPLE__
+ /*
+ * When going to sleep, wake up to cancel jobs that don't complete in time.
+ */
+
+ if (SleepJobs > 0 && SleepJobs < timeout)
+ {
+ timeout = SleepJobs;
+ why = "cancel jobs before sleeping";
+ }
+#endif /* __APPLE__ */
+
+ /*
+ * Check whether we are accepting new connections...
+ */
+
+ if (ListeningPaused > 0 && cupsArrayCount(Clients) < MaxClients &&
+ ListeningPaused < timeout)
+ {
+ if (ListeningPaused <= now)
+ timeout = now;
+ else
+ timeout = ListeningPaused;
+
+ why = "resume listening";
+ }
+
+ /*
+ * Check the activity and close old clients...
+ */
+
+ for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
+ con;
+ con = (cupsd_client_t *)cupsArrayNext(Clients))
+ if ((con->http.activity + Timeout) < timeout)
+ {
+ timeout = con->http.activity + Timeout;
+ why = "timeout a client connection";
+ }
+
+ /*
+ * Update the browse list as needed...
+ */
+
+ if (Browsing && BrowseLocalProtocols)
+ {
+#ifdef HAVE_LIBSLP
+ if ((BrowseLocalProtocols & BROWSE_SLP) && (BrowseSLPRefresh < timeout))
+ {
+ timeout = BrowseSLPRefresh;
+ why = "update SLP browsing";
+ }
+#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_LDAP
+ if ((BrowseLocalProtocols & BROWSE_LDAP) && (BrowseLDAPRefresh < timeout))
+ {
+ timeout = BrowseLDAPRefresh;
+ why = "update LDAP browsing";
+ }
+#endif /* HAVE_LDAP */
+
+ if ((BrowseLocalProtocols & BROWSE_CUPS) && NumBrowsers)
+ {
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ if (p->type & CUPS_PRINTER_REMOTE)
+ {
+ if ((p->browse_time + BrowseTimeout) < timeout)
+ {
+ timeout = p->browse_time + BrowseTimeout;
+ why = "browse timeout a printer";
+ }
+ }
+ else if (p->shared && !(p->type & CUPS_PRINTER_IMPLICIT))
+ {
+ if (BrowseInterval && (p->browse_time + BrowseInterval) < timeout)
+ {
+ timeout = p->browse_time + BrowseInterval;
+ why = "send browse update";
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Write out changes to configuration and state files...
+ */
+
+ if (DirtyCleanTime && timeout > DirtyCleanTime)
+ {
+ timeout = DirtyCleanTime;
+ why = "write dirty config/state files";
+ }
+
+ /*
+ * Check for any active jobs...
+ */
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
+ {
+ if (job->kill_time && job->kill_time < timeout)
+ {
+ timeout = job->kill_time;
+ why = "kill unresponsive jobs";
+ }
+
+ if (job->state_value == IPP_JOB_HELD && job->hold_until < timeout)
+ {
+ timeout = job->hold_until;
+ why = "release held jobs";
+ }
+ else if (job->state_value == IPP_JOB_PENDING && timeout > (now + 10))
+ {
+ timeout = now + 10;
+ why = "start pending jobs";
+ break;
+ }
+ }
+
+#ifdef HAVE_MALLINFO
+ /*
+ * Log memory usage every minute...
+ */
+
+ if (LogLevel >= CUPSD_LOG_DEBUG && (mallinfo_time + 60) < timeout)
+ {
+ timeout = mallinfo_time + 60;
+ why = "display memory usage";
+ }
+#endif /* HAVE_MALLINFO */
+
+ /*
+ * Expire subscriptions as needed...
+ */
+
+ for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
+ sub;
+ sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
+ if (!sub->job && sub->expire && sub->expire < timeout)
+ {
+ timeout = sub->expire;
+ why = "expire subscription";
+ }
+
+ /*
+ * Adjust from absolute to relative time. If p->browse_time above
+ * was 0 then we can end up with a negative value here, so check.
+ * We add 1 second to the timeout since events occur after the
+ * timeout expires, and limit the timeout to 86400 seconds (1 day)
+ * to avoid select() timeout limits present on some operating
+ * systems...
+ */
+
+ timeout = timeout - now + 1;
+
+ if (timeout < 1)
+ timeout = 1;
+ else if (timeout > 86400)
+ timeout = 86400;
+
+ /*
+ * Log and return the timeout value...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout(%d): %ld seconds to %s",
+ fds, timeout, why);
+
+ return (timeout);
+}
+
+
+/*
+ * 'sigchld_handler()' - Handle 'child' signals from old processes.
+ */
+
+static void
+sigchld_handler(int sig) /* I - Signal number */
+{
+ (void)sig;
+
+ /*
+ * Flag that we have dead children...
+ */
+
+ dead_children = 1;
+
+ /*
+ * Reset the signal handler as needed...
+ */
+
+#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
+ signal(SIGCLD, sigchld_handler);
+#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
+}
+
+
+/*
+ * 'sighup_handler()' - Handle 'hangup' signals to reconfigure the scheduler.
+ */
+
+static void
+sighup_handler(int sig) /* I - Signal number */
+{
+ (void)sig;
+
+ NeedReload = RELOAD_ALL;
+ ReloadTime = time(NULL);
+
+#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
+ signal(SIGHUP, sighup_handler);
+#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
+}
+
+
+/*
+ * 'sigterm_handler()' - Handle 'terminate' signals that stop the scheduler.
+ */
+
+static void
+sigterm_handler(int sig) /* I - Signal number */
+{
+ (void)sig; /* remove compiler warnings... */
+
+ /*
+ * Flag that we should stop and return...
+ */
+
+ stop_scheduler = 1;
+}
+
+
+/*
+ * 'usage()' - Show scheduler usage.
+ */
+
+static void
+usage(int status) /* O - Exit status */
+{
+ FILE *fp = status ? stderr : stdout; /* Output file */
+
+
+ _cupsLangPuts(fp, _("Usage: cupsd [options]"));
+ _cupsLangPuts(fp, _("Options:"));
+ _cupsLangPuts(fp, _(" -c config-file Load alternate configuration "
+ "file."));
+ _cupsLangPuts(fp, _(" -f Run in the foreground."));
+ _cupsLangPuts(fp, _(" -F Run in the foreground but "
+ "detach from console."));
+ _cupsLangPuts(fp, _(" -h Show this usage message."));
+ _cupsLangPuts(fp, _(" -l Run cupsd from launchd(8)."));
+ _cupsLangPuts(fp, _(" -t Test the configuration "
+ "file."));
+
+ exit(status);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/mime-private.h b/scheduler/mime-private.h
new file mode 100644
index 000000000..ffd769f12
--- /dev/null
+++ b/scheduler/mime-private.h
@@ -0,0 +1,48 @@
+/*
+ * "$Id$"
+ *
+ * Private MIME type/conversion database definitions for CUPS.
+ *
+ * Copyright 2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPS_MIME_PRIVATE_H_
+# define _CUPS_MIME_PRIVATE_H_
+
+# include "mime.h"
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Prototypes...
+ */
+
+extern void _mimeError(mime_t *mime, const char *format, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+#endif /* __GNUC__ */
+;
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_MIME_PRIVATE_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/mime.c b/scheduler/mime.c
new file mode 100644
index 000000000..abad962eb
--- /dev/null
+++ b/scheduler/mime.c
@@ -0,0 +1,960 @@
+/*
+ * "$Id$"
+ *
+ * MIME database file routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * mimeDelete() - Delete (free) a MIME database.
+ * mimeDeleteFilter() - Delete a filter from the MIME database.
+ * mimeDeleteType() - Delete a type from the MIME database.
+ * _mimeError() - Show an error message.
+ * mimeFirstFilter() - Get the first filter in the MIME database.
+ * mimeFirstType() - Get the first type in the MIME database.
+ * mimeLoad() - Create a new MIME database from disk.
+ * mimeLoadFilters() - Load filter definitions from disk.
+ * mimeLoadTypes() - Load type definitions from disk.
+ * mimeNew() - Create a new, empty MIME database.
+ * mimeNextFilter() - Get the next filter in the MIME database.
+ * mimeNextType() - Get the next type in the MIME database.
+ * mimeNumFilters() - Get the number of filters in a MIME database.
+ * mimeNumTypes() - Get the number of types in a MIME database.
+ * mimeSetErrorCallback() - Set the callback for error messages.
+ * mime_add_fcache() - Add a filter to the filter cache.
+ * mime_compare_fcache() - Compare two filter cache entries.
+ * mime_delete_fcache() - Free all memory used by the filter cache.
+ * mime_delete_rules() - Free all memory for the given rule tree.
+ * mime_load_convs() - Load a xyz.convs file.
+ * mime_load_types() - Load a xyz.types file.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/string-private.h>
+#include <cups/debug-private.h>
+#include <cups/dir.h>
+#include "mime-private.h"
+
+
+/*
+ * Local types...
+ */
+
+typedef struct _mime_fcache_s /**** Filter cache structure ****/
+{
+ char *name, /* Filter name */
+ *path; /* Full path to filter if available */
+} _mime_fcache_t;
+
+
+/*
+ * Local functions...
+ */
+
+static const char *mime_add_fcache(cups_array_t *filtercache, const char *name,
+ const char *filterpath);
+static int mime_compare_fcache(_mime_fcache_t *a, _mime_fcache_t *b);
+static void mime_delete_fcache(cups_array_t *filtercache);
+static void mime_delete_rules(mime_magic_t *rules);
+static void mime_load_convs(mime_t *mime, const char *filename,
+ const char *filterpath,
+ cups_array_t *filtercache);
+static void mime_load_types(mime_t *mime, const char *filename);
+
+
+/*
+ * 'mimeDelete()' - Delete (free) a MIME database.
+ */
+
+void
+mimeDelete(mime_t *mime) /* I - MIME database */
+{
+ mime_type_t *type; /* Current type */
+ mime_filter_t *filter; /* Current filter */
+
+
+ DEBUG_printf(("mimeDelete(mime=%p)", mime));
+
+ if (!mime)
+ return;
+
+ /*
+ * Loop through filters and free them...
+ */
+
+ for (filter = (mime_filter_t *)cupsArrayFirst(mime->filters);
+ filter;
+ filter = (mime_filter_t *)cupsArrayNext(mime->filters))
+ mimeDeleteFilter(mime, filter);
+
+ /*
+ * Loop through the file types and delete any rules...
+ */
+
+ for (type = (mime_type_t *)cupsArrayFirst(mime->types);
+ type;
+ type = (mime_type_t *)cupsArrayNext(mime->types))
+ mimeDeleteType(mime, type);
+
+ /*
+ * Free the types and filters arrays, and then the MIME database structure.
+ */
+
+ cupsArrayDelete(mime->types);
+ cupsArrayDelete(mime->filters);
+ cupsArrayDelete(mime->srcs);
+ free(mime);
+}
+
+
+/*
+ * 'mimeDeleteFilter()' - Delete a filter from the MIME database.
+ */
+
+void
+mimeDeleteFilter(mime_t *mime, /* I - MIME database */
+ mime_filter_t *filter) /* I - Filter */
+{
+ DEBUG_printf(("mimeDeleteFilter(mime=%p, filter=%p(%s/%s->%s/%s, cost=%d, "
+ "maxsize=" CUPS_LLFMT "))", mime, filter,
+ filter ? filter->src->super : "???",
+ filter ? filter->src->type : "???",
+ filter ? filter->dst->super : "???",
+ filter ? filter->dst->super : "???",
+ filter ? filter->cost : -1,
+ filter ? CUPS_LLCAST filter->maxsize : CUPS_LLCAST -1));
+
+ if (!mime || !filter)
+ return;
+
+#ifdef DEBUG
+ if (!cupsArrayFind(mime->filters, filter))
+ DEBUG_puts("1mimeDeleteFilter: Filter not in MIME database.");
+#endif /* DEBUG */
+
+ cupsArrayRemove(mime->filters, filter);
+ free(filter);
+
+ /*
+ * Deleting a filter invalidates the source lookup cache used by
+ * mimeFilter()...
+ */
+
+ if (mime->srcs)
+ {
+ DEBUG_puts("1mimeDeleteFilter: Deleting source lookup cache.");
+ cupsArrayDelete(mime->srcs);
+ mime->srcs = NULL;
+ }
+}
+
+
+/*
+ * 'mimeDeleteType()' - Delete a type from the MIME database.
+ */
+
+void
+mimeDeleteType(mime_t *mime, /* I - MIME database */
+ mime_type_t *mt) /* I - Type */
+{
+ DEBUG_printf(("mimeDeleteType(mime=%p, mt=%p(%s/%s))", mime, mt,
+ mt ? mt->super : "???", mt ? mt->type : "???"));
+
+ if (!mime || !mt)
+ return;
+
+#ifdef DEBUG
+ if (!cupsArrayFind(mime->types, mt))
+ DEBUG_puts("1mimeDeleteFilter: Type not in MIME database.");
+#endif /* DEBUG */
+
+ cupsArrayRemove(mime->types, mt);
+
+ mime_delete_rules(mt->rules);
+ free(mt);
+}
+
+
+/*
+ * '_mimeError()' - Show an error message.
+ */
+
+void
+_mimeError(mime_t *mime, /* I - MIME database */
+ const char *message, /* I - Printf-style message string */
+ ...) /* I - Additional arguments as needed */
+{
+ va_list ap; /* Argument pointer */
+ char buffer[8192]; /* Message buffer */
+
+
+ if (mime->error_cb)
+ {
+ va_start(ap, message);
+ vsnprintf(buffer, sizeof(buffer), message, ap);
+ va_end(ap);
+
+ (*mime->error_cb)(mime->error_ctx, buffer);
+ }
+}
+
+
+/*
+ * 'mimeFirstFilter()' - Get the first filter in the MIME database.
+ */
+
+mime_filter_t * /* O - Filter or NULL */
+mimeFirstFilter(mime_t *mime) /* I - MIME database */
+{
+ DEBUG_printf(("6mimeFirstFilter(mime=%p)", mime));
+
+ if (!mime)
+ {
+ DEBUG_puts("7mimeFirstFilter: Returning NULL.");
+ return (NULL);
+ }
+ else
+ {
+ mime_filter_t *first = (mime_filter_t *)cupsArrayFirst(mime->filters);
+ /* First filter */
+
+ DEBUG_printf(("7mimeFirstFilter: Returning %p.", first));
+ return (first);
+ }
+}
+
+
+/*
+ * 'mimeFirstType()' - Get the first type in the MIME database.
+ */
+
+mime_type_t * /* O - Type or NULL */
+mimeFirstType(mime_t *mime) /* I - MIME database */
+{
+ DEBUG_printf(("6mimeFirstType(mime=%p)", mime));
+
+ if (!mime)
+ {
+ DEBUG_puts("7mimeFirstType: Returning NULL.");
+ return (NULL);
+ }
+ else
+ {
+ mime_type_t *first = (mime_type_t *)cupsArrayFirst(mime->types);
+ /* First type */
+
+ DEBUG_printf(("7mimeFirstType: Returning %p.", first));
+ return (first);
+ }
+}
+
+
+/*
+ * 'mimeLoad()' - Create a new MIME database from disk.
+ *
+ * This function uses @link mimeLoadFilters@ and @link mimeLoadTypes@ to
+ * create a MIME database from a single directory.
+ */
+
+mime_t * /* O - New MIME database */
+mimeLoad(const char *pathname, /* I - Directory to load */
+ const char *filterpath) /* I - Directory to load */
+{
+ mime_t *mime; /* New MIME database */
+
+ DEBUG_printf(("mimeLoad(pathname=\"%s\", filterpath=\"%s\")", pathname,
+ filterpath));
+
+ mime = mimeLoadFilters(mimeLoadTypes(NULL, pathname), pathname, filterpath);
+ DEBUG_printf(("1mimeLoad: Returning %p.", mime));
+
+ return (mime);
+}
+
+
+/*
+ * 'mimeLoadFilters()' - Load filter definitions from disk.
+ *
+ * This function loads all of the .convs files from the specified directory.
+ * Use @link mimeLoadTypes@ to load all types before you load the filters.
+ */
+
+mime_t * /* O - MIME database */
+mimeLoadFilters(mime_t *mime, /* I - MIME database */
+ const char *pathname, /* I - Directory to load from */
+ const char *filterpath) /* I - Default filter program directory */
+{
+ cups_dir_t *dir; /* Directory */
+ cups_dentry_t *dent; /* Directory entry */
+ char filename[1024]; /* Full filename of .convs file */
+ cups_array_t *filtercache; /* Filter cache */
+
+
+ DEBUG_printf(("mimeLoadFilters(mime=%p, pathname=\"%s\", filterpath=\"%s\")",
+ mime, pathname, filterpath));
+
+ /*
+ * Range check input...
+ */
+
+ if (!mime || !pathname || !filterpath)
+ {
+ DEBUG_puts("1mimeLoadFilters: Bad arguments.");
+ return (mime);
+ }
+
+ /*
+ * Then open the directory specified by pathname...
+ */
+
+ if ((dir = cupsDirOpen(pathname)) == NULL)
+ {
+ DEBUG_printf(("1mimeLoadFilters: Unable to open \"%s\": %s", pathname,
+ strerror(errno)));
+ _mimeError(mime, "Unable to open \"%s\": %s", pathname, strerror(errno));
+ return (mime);
+ }
+
+ /*
+ * Read all the .convs files...
+ */
+
+ filtercache = cupsArrayNew((cups_array_func_t)mime_compare_fcache, NULL);
+
+ while ((dent = cupsDirRead(dir)) != NULL)
+ {
+ if (strlen(dent->filename) > 6 &&
+ !strcmp(dent->filename + strlen(dent->filename) - 6, ".convs"))
+ {
+ /*
+ * Load a mime.convs file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
+ DEBUG_printf(("1mimeLoadFilters: Loading \"%s\".", filename));
+ mime_load_convs(mime, filename, filterpath, filtercache);
+ }
+ }
+
+ mime_delete_fcache(filtercache);
+
+ cupsDirClose(dir);
+
+ return (mime);
+}
+
+
+/*
+ * 'mimeLoadTypes()' - Load type definitions from disk.
+ *
+ * This function loads all of the .types files from the specified directory.
+ * Use @link mimeLoadFilters@ to load all filters after you load the types.
+ */
+
+mime_t * /* O - MIME database */
+mimeLoadTypes(mime_t *mime, /* I - MIME database or @code NULL@ to create a new one */
+ const char *pathname) /* I - Directory to load from */
+{
+ cups_dir_t *dir; /* Directory */
+ cups_dentry_t *dent; /* Directory entry */
+ char filename[1024]; /* Full filename of .types file */
+
+
+ DEBUG_printf(("mimeLoadTypes(mime=%p, pathname=\"%s\")", mime, pathname));
+
+ /*
+ * First open the directory specified by pathname...
+ */
+
+ if ((dir = cupsDirOpen(pathname)) == NULL)
+ {
+ DEBUG_printf(("1mimeLoadTypes: Unable to open \"%s\": %s", pathname,
+ strerror(errno)));
+ DEBUG_printf(("1mimeLoadTypes: Returning %p.", mime));
+ _mimeError(mime, "Unable to open \"%s\": %s", pathname, strerror(errno));
+ return (mime);
+ }
+
+ /*
+ * If "mime" is NULL, make a new, empty database...
+ */
+
+ if (!mime)
+ mime = mimeNew();
+
+ if (!mime)
+ {
+ cupsDirClose(dir);
+ DEBUG_puts("1mimeLoadTypes: Returning NULL.");
+ return (NULL);
+ }
+
+ /*
+ * Read all the .types files...
+ */
+
+ while ((dent = cupsDirRead(dir)) != NULL)
+ {
+ if (strlen(dent->filename) > 6 &&
+ !strcmp(dent->filename + strlen(dent->filename) - 6, ".types"))
+ {
+ /*
+ * Load a mime.types file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
+ DEBUG_printf(("1mimeLoadTypes: Loading \"%s\".", filename));
+ mime_load_types(mime, filename);
+ }
+ }
+
+ cupsDirClose(dir);
+
+ DEBUG_printf(("1mimeLoadTypes: Returning %p.", mime));
+
+ return (mime);
+}
+
+
+/*
+ * 'mimeNew()' - Create a new, empty MIME database.
+ */
+
+mime_t * /* O - MIME database */
+mimeNew(void)
+{
+ return ((mime_t *)calloc(1, sizeof(mime_t)));
+}
+
+
+/*
+ * 'mimeNextFilter()' - Get the next filter in the MIME database.
+ */
+
+mime_filter_t * /* O - Filter or NULL */
+mimeNextFilter(mime_t *mime) /* I - MIME database */
+{
+ DEBUG_printf(("6mimeNextFilter(mime=%p)", mime));
+
+ if (!mime)
+ {
+ DEBUG_puts("7mimeNextFilter: Returning NULL.");
+ return (NULL);
+ }
+ else
+ {
+ mime_filter_t *next = (mime_filter_t *)cupsArrayNext(mime->filters);
+ /* Next filter */
+
+ DEBUG_printf(("7mimeNextFilter: Returning %p.", next));
+ return (next);
+ }
+}
+
+
+/*
+ * 'mimeNextType()' - Get the next type in the MIME database.
+ */
+
+mime_type_t * /* O - Type or NULL */
+mimeNextType(mime_t *mime) /* I - MIME database */
+{
+ DEBUG_printf(("6mimeNextType(mime=%p)", mime));
+
+ if (!mime)
+ {
+ DEBUG_puts("7mimeNextType: Returning NULL.");
+ return (NULL);
+ }
+ else
+ {
+ mime_type_t *next = (mime_type_t *)cupsArrayNext(mime->types);
+ /* Next type */
+
+ DEBUG_printf(("7mimeNextType: Returning %p.", next));
+ return (next);
+ }
+}
+
+
+/*
+ * 'mimeNumFilters()' - Get the number of filters in a MIME database.
+ */
+
+int
+mimeNumFilters(mime_t *mime) /* I - MIME database */
+{
+ DEBUG_printf(("mimeNumFilters(mime=%p)", mime));
+
+ if (!mime)
+ {
+ DEBUG_puts("1mimeNumFilters: Returning 0.");
+ return (0);
+ }
+ else
+ {
+ DEBUG_printf(("1mimeNumFilters: Returning %d.",
+ cupsArrayCount(mime->filters)));
+ return (cupsArrayCount(mime->filters));
+ }
+}
+
+
+/*
+ * 'mimeNumTypes()' - Get the number of types in a MIME database.
+ */
+
+int
+mimeNumTypes(mime_t *mime) /* I - MIME database */
+{
+ DEBUG_printf(("mimeNumTypes(mime=%p)", mime));
+
+ if (!mime)
+ {
+ DEBUG_puts("1mimeNumTypes: Returning 0.");
+ return (0);
+ }
+ else
+ {
+ DEBUG_printf(("1mimeNumTypes: Returning %d.",
+ cupsArrayCount(mime->types)));
+ return (cupsArrayCount(mime->types));
+ }
+}
+
+
+/*
+ * 'mimeSetErrorCallback()' - Set the callback for error messages.
+ */
+
+void
+mimeSetErrorCallback(
+ mime_t *mime, /* I - MIME database */
+ mime_error_cb_t cb, /* I - Callback function */
+ void *ctx) /* I - Context pointer for callback */
+{
+ if (mime)
+ {
+ mime->error_cb = cb;
+ mime->error_ctx = ctx;
+ }
+}
+
+
+/*
+ * 'mime_add_fcache()' - Add a filter to the filter cache.
+ */
+
+static const char * /* O - Full path to filter or NULL */
+mime_add_fcache(
+ cups_array_t *filtercache, /* I - Filter cache */
+ const char *name, /* I - Filter name */
+ const char *filterpath) /* I - Filter path */
+{
+ _mime_fcache_t key, /* Search key */
+ *temp; /* New filter cache */
+ char path[1024]; /* Full path to filter */
+
+
+ DEBUG_printf(("2mime_add_fcache(filtercache=%p, name=\"%s\", "
+ "filterpath=\"%s\")", filtercache, name, filterpath));
+
+ key.name = (char *)name;
+ if ((temp = (_mime_fcache_t *)cupsArrayFind(filtercache, &key)) != NULL)
+ {
+ DEBUG_printf(("3mime_add_fcache: Returning \"%s\".", temp->path));
+ return (temp->path);
+ }
+
+ if ((temp = calloc(1, sizeof(_mime_fcache_t))) == NULL)
+ {
+ DEBUG_puts("3mime_add_fcache: Returning NULL.");
+ return (NULL);
+ }
+
+ temp->name = strdup(name);
+
+ if (cupsFileFind(name, filterpath, 1, path, sizeof(path)))
+ temp->path = strdup(path);
+
+ cupsArrayAdd(filtercache, temp);
+
+ DEBUG_printf(("3mime_add_fcache: Returning \"%s\".", temp->path));
+ return (temp->path);
+}
+
+
+/*
+ * 'mime_compare_fcache()' - Compare two filter cache entries.
+ */
+
+static int /* O - Result of comparison */
+mime_compare_fcache(_mime_fcache_t *a, /* I - First entry */
+ _mime_fcache_t *b) /* I - Second entry */
+{
+ return (strcmp(a->name, b->name));
+}
+
+
+/*
+ * 'mime_delete_fcache()' - Free all memory used by the filter cache.
+ */
+
+static void
+mime_delete_fcache(
+ cups_array_t *filtercache) /* I - Filter cache */
+{
+ _mime_fcache_t *current; /* Current cache entry */
+
+
+ DEBUG_printf(("2mime_delete_fcache(filtercache=%p)", filtercache));
+
+ for (current = (_mime_fcache_t *)cupsArrayFirst(filtercache);
+ current;
+ current = (_mime_fcache_t *)cupsArrayNext(filtercache))
+ {
+ free(current->name);
+
+ if (current->path)
+ free(current->path);
+
+ free(current);
+ }
+
+ cupsArrayDelete(filtercache);
+}
+
+
+/*
+ * 'mime_delete_rules()' - Free all memory for the given rule tree.
+ */
+
+static void
+mime_delete_rules(mime_magic_t *rules) /* I - Rules to free */
+{
+ mime_magic_t *next; /* Next rule to free */
+
+
+ DEBUG_printf(("2mime_delete_rules(rules=%p)", rules));
+
+ /*
+ * Free the rules list, descending recursively to free any child rules.
+ */
+
+ while (rules != NULL)
+ {
+ next = rules->next;
+
+ if (rules->child != NULL)
+ mime_delete_rules(rules->child);
+
+ free(rules);
+ rules = next;
+ }
+}
+
+
+/*
+ * 'mime_load_convs()' - Load a xyz.convs file.
+ */
+
+static void
+mime_load_convs(
+ mime_t *mime, /* I - MIME database */
+ const char *filename, /* I - Convs file to load */
+ const char *filterpath, /* I - Path for filters */
+ cups_array_t *filtercache) /* I - Filter program cache */
+{
+ cups_file_t *fp; /* Convs file */
+ char line[1024], /* Input line from file */
+ *lineptr, /* Current position in line */
+ super[MIME_MAX_SUPER], /* Super-type name */
+ type[MIME_MAX_TYPE], /* Type name */
+ *temp, /* Temporary pointer */
+ *filter; /* Filter program */
+ mime_type_t *temptype, /* MIME type looping var */
+ *dsttype; /* Destination MIME type */
+ int cost; /* Cost of filter */
+
+
+ DEBUG_printf(("2mime_load_convs(mime=%p, filename=\"%s\", filterpath=\"%s\", "
+ "filtercache=%p)", mime, filename, filterpath, filtercache));
+
+ /*
+ * First try to open the file...
+ */
+
+ if ((fp = cupsFileOpen(filename, "r")) == NULL)
+ {
+ DEBUG_printf(("3mime_load_convs: Unable to open \"%s\": %s", filename,
+ strerror(errno)));
+ _mimeError(mime, "Unable to open \"%s\": %s", filename, strerror(errno));
+ return;
+ }
+
+ /*
+ * Then read each line from the file, skipping any comments in the file...
+ */
+
+ while (cupsFileGets(fp, line, sizeof(line)) != NULL)
+ {
+ /*
+ * Skip blank lines and lines starting with a #...
+ */
+
+ if (!line[0] || line[0] == '#')
+ continue;
+
+ /*
+ * Strip trailing whitespace...
+ */
+
+ for (lineptr = line + strlen(line) - 1;
+ lineptr >= line && isspace(*lineptr & 255);
+ lineptr --)
+ *lineptr = '\0';
+
+ /*
+ * Extract the destination super-type and type names from the middle of
+ * the line.
+ */
+
+ lineptr = line;
+ while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
+ lineptr ++;
+
+ while (*lineptr == ' ' || *lineptr == '\t')
+ lineptr ++;
+
+ temp = super;
+
+ while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
+ (temp - super + 1) < MIME_MAX_SUPER)
+ *temp++ = tolower(*lineptr++ & 255);
+
+ *temp = '\0';
+
+ if (*lineptr != '/')
+ continue;
+
+ lineptr ++;
+ temp = type;
+
+ while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
+ *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
+ *temp++ = tolower(*lineptr++ & 255);
+
+ *temp = '\0';
+
+ if (*lineptr == '\0' || *lineptr == '\n')
+ continue;
+
+ if ((dsttype = mimeType(mime, super, type)) == NULL)
+ {
+ DEBUG_printf(("3mime_load_convs: Destination type %s/%s not found.",
+ super, type));
+ continue;
+ }
+
+ /*
+ * Then get the cost and filter program...
+ */
+
+ while (*lineptr == ' ' || *lineptr == '\t')
+ lineptr ++;
+
+ if (*lineptr < '0' || *lineptr > '9')
+ continue;
+
+ cost = atoi(lineptr);
+
+ while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
+ lineptr ++;
+ while (*lineptr == ' ' || *lineptr == '\t')
+ lineptr ++;
+
+ if (*lineptr == '\0' || *lineptr == '\n')
+ continue;
+
+ filter = lineptr;
+
+ if (strcmp(filter, "-"))
+ {
+ /*
+ * Verify that the filter exists and is executable...
+ */
+
+ if (!mime_add_fcache(filtercache, filter, filterpath))
+ {
+ DEBUG_printf(("mime_load_convs: Filter %s not found in %s.", filter,
+ filterpath));
+ _mimeError(mime, "Filter \"%s\" not found.", filter);
+ continue;
+ }
+ }
+
+ /*
+ * Finally, get the source super-type and type names from the beginning of
+ * the line. We do it here so we can support wildcards...
+ */
+
+ lineptr = line;
+ temp = super;
+
+ while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
+ (temp - super + 1) < MIME_MAX_SUPER)
+ *temp++ = tolower(*lineptr++ & 255);
+
+ *temp = '\0';
+
+ if (*lineptr != '/')
+ continue;
+
+ lineptr ++;
+ temp = type;
+
+ while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
+ *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
+ *temp++ = tolower(*lineptr++ & 255);
+
+ *temp = '\0';
+
+ if (!strcmp(super, "*") && !strcmp(type, "*"))
+ {
+ /*
+ * Force * / * to be "application/octet-stream"...
+ */
+
+ strcpy(super, "application");
+ strcpy(type, "octet-stream");
+ }
+
+ /*
+ * Add the filter to the MIME database, supporting wildcards as needed...
+ */
+
+ for (temptype = (mime_type_t *)cupsArrayFirst(mime->types);
+ temptype;
+ temptype = (mime_type_t *)cupsArrayNext(mime->types))
+ if ((super[0] == '*' || !strcmp(temptype->super, super)) &&
+ (type[0] == '*' || !strcmp(temptype->type, type)))
+ mimeAddFilter(mime, temptype, dsttype, cost, filter);
+ }
+
+ cupsFileClose(fp);
+}
+
+
+/*
+ * 'mime_load_types()' - Load a xyz.types file.
+ */
+
+static void
+mime_load_types(mime_t *mime, /* I - MIME database */
+ const char *filename) /* I - Types file to load */
+{
+ cups_file_t *fp; /* Types file */
+ int linelen; /* Length of line */
+ char line[32768], /* Input line from file */
+ *lineptr, /* Current position in line */
+ super[MIME_MAX_SUPER], /* Super-type name */
+ type[MIME_MAX_TYPE], /* Type name */
+ *temp; /* Temporary pointer */
+ mime_type_t *typeptr; /* New MIME type */
+
+
+ DEBUG_printf(("2mime_load_types(mime=%p, filename=\"%s\")", mime, filename));
+
+ /*
+ * First try to open the file...
+ */
+
+ if ((fp = cupsFileOpen(filename, "r")) == NULL)
+ {
+ DEBUG_printf(("3mime_load_types: Unable to open \"%s\": %s", filename,
+ strerror(errno)));
+ _mimeError(mime, "Unable to open \"%s\": %s", filename, strerror(errno));
+ return;
+ }
+
+ /*
+ * Then read each line from the file, skipping any comments in the file...
+ */
+
+ while (cupsFileGets(fp, line, sizeof(line)) != NULL)
+ {
+ /*
+ * Skip blank lines and lines starting with a #...
+ */
+
+ if (!line[0] || line[0] == '#')
+ continue;
+
+ /*
+ * While the last character in the line is a backslash, continue on to the
+ * next line (and the next, etc.)
+ */
+
+ linelen = strlen(line);
+
+ while (line[linelen - 1] == '\\')
+ {
+ linelen --;
+
+ if (cupsFileGets(fp, line + linelen, sizeof(line) - linelen) == NULL)
+ line[linelen] = '\0';
+ else
+ linelen += strlen(line + linelen);
+ }
+
+ /*
+ * Extract the super-type and type names from the beginning of the line.
+ */
+
+ lineptr = line;
+ temp = super;
+
+ while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
+ (temp - super + 1) < MIME_MAX_SUPER)
+ *temp++ = tolower(*lineptr++ & 255);
+
+ *temp = '\0';
+
+ if (*lineptr != '/')
+ continue;
+
+ lineptr ++;
+ temp = type;
+
+ while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
+ *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
+ *temp++ = tolower(*lineptr++ & 255);
+
+ *temp = '\0';
+
+ /*
+ * Add the type and rules to the MIME database...
+ */
+
+ typeptr = mimeAddType(mime, super, type);
+ mimeAddTypeRule(typeptr, lineptr);
+ }
+
+ cupsFileClose(fp);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/mime.h b/scheduler/mime.h
new file mode 100644
index 000000000..6feceecc4
--- /dev/null
+++ b/scheduler/mime.h
@@ -0,0 +1,162 @@
+/*
+ * "$Id$"
+ *
+ * MIME type/conversion database definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPS_MIME_H_
+# define _CUPS_MIME_H_
+
+# include <cups/array.h>
+# include <cups/ipp.h>
+# include <cups/file.h>
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Constants...
+ */
+
+# define MIME_MAX_SUPER 16 /* Maximum size of supertype name */
+# define MIME_MAX_TYPE IPP_MAX_NAME /* Maximum size of type name */
+# define MIME_MAX_FILTER 256 /* Maximum size of filter pathname */
+# define MIME_MAX_BUFFER 4096 /* Maximum size of file buffer */
+
+
+/*
+ * Types/structures...
+ */
+
+typedef enum
+{
+ MIME_MAGIC_NOP, /* No operation */
+ MIME_MAGIC_AND, /* Logical AND of all children */
+ MIME_MAGIC_OR, /* Logical OR of all children */
+ MIME_MAGIC_MATCH, /* Filename match */
+ MIME_MAGIC_ASCII, /* ASCII characters in range */
+ MIME_MAGIC_PRINTABLE, /* Printable characters (32-255) in range */
+ MIME_MAGIC_STRING, /* String matches */
+ MIME_MAGIC_CHAR, /* Character/byte matches */
+ MIME_MAGIC_SHORT, /* Short/16-bit word matches */
+ MIME_MAGIC_INT, /* Integer/32-bit word matches */
+ MIME_MAGIC_LOCALE, /* Current locale matches string */
+ MIME_MAGIC_CONTAINS, /* File contains a string */
+ MIME_MAGIC_ISTRING /* Case-insensitive string matches */
+} mime_op_t;
+
+typedef struct _mime_magic_s /**** MIME Magic Data ****/
+{
+ struct _mime_magic_s *prev, /* Previous rule */
+ *next, /* Next rule */
+ *parent, /* Parent rules */
+ *child; /* Child rules */
+ short op, /* Operation code (see above) */
+ invert; /* Invert the result */
+ int offset, /* Offset in file */
+ region, /* Region length */
+ length; /* Length of data */
+ union
+ {
+ char matchv[64]; /* Match value */
+ char localev[64]; /* Locale value */
+ char stringv[64]; /* String value */
+ unsigned char charv; /* Byte value */
+ unsigned short shortv; /* Short value */
+ unsigned intv; /* Integer value */
+ } value;
+} mime_magic_t;
+
+typedef struct _mime_type_s /**** MIME Type Data ****/
+{
+ mime_magic_t *rules; /* Rules used to detect this type */
+ int priority; /* Priority of this type */
+ char super[MIME_MAX_SUPER], /* Super-type name ("image", "application", etc.) */
+ type[MIME_MAX_TYPE]; /* Type name ("png", "postscript", etc.) */
+} mime_type_t;
+
+typedef struct _mime_filter_s /**** MIME Conversion Filter Data ****/
+{
+ mime_type_t *src, /* Source type */
+ *dst; /* Destination type */
+ int cost; /* Relative cost */
+ char filter[MIME_MAX_FILTER];/* Filter program to use */
+ size_t maxsize; /* Maximum file size for this filter */
+} mime_filter_t;
+
+typedef void (*mime_error_cb_t)(void *ctx, const char *message);
+
+typedef struct _mime_s /**** MIME Database ****/
+{
+ cups_array_t *types; /* File types */
+ cups_array_t *filters; /* Type conversion filters */
+ cups_array_t *srcs; /* Filters sorted by source type */
+ mime_error_cb_t error_cb; /* Error message callback */
+ void *error_ctx; /* Pointer for callback */
+} mime_t;
+
+
+/*
+ * Functions...
+ */
+
+extern void mimeDelete(mime_t *mime);
+extern mime_t *mimeNew(void) _CUPS_API_1_5;
+extern mime_t *mimeLoad(const char *pathname, const char *filterpath);
+extern mime_t *mimeLoadFilters(mime_t *mime, const char *pathname,
+ const char *filterpath);
+extern mime_t *mimeLoadTypes(mime_t *mime, const char *pathname);
+
+extern mime_type_t *mimeAddType(mime_t *mime, const char *super,
+ const char *type);
+extern int mimeAddTypeRule(mime_type_t *mt, const char *rule);
+extern void mimeDeleteType(mime_t *mime, mime_type_t *mt);
+extern mime_type_t *mimeFileType(mime_t *mime, const char *pathname,
+ const char *filename, int *compression);
+extern mime_type_t *mimeFirstType(mime_t *mime);
+extern mime_type_t *mimeNextType(mime_t *mime);
+extern int mimeNumTypes(mime_t *mime);
+extern mime_type_t *mimeType(mime_t *mime, const char *super,
+ const char *type);
+
+extern mime_filter_t *mimeAddFilter(mime_t *mime, mime_type_t *src,
+ mime_type_t *dst, int cost,
+ const char *filter);
+extern void mimeDeleteFilter(mime_t *mime, mime_filter_t *filter);
+extern cups_array_t *mimeFilter(mime_t *mime, mime_type_t *src,
+ mime_type_t *dst, int *cost);
+extern cups_array_t *mimeFilter2(mime_t *mime, mime_type_t *src,
+ size_t srcsize, mime_type_t *dst,
+ int *cost);
+extern mime_filter_t *mimeFilterLookup(mime_t *mime, mime_type_t *src,
+ mime_type_t *dst);
+extern mime_filter_t *mimeFirstFilter(mime_t *mime);
+extern mime_filter_t *mimeNextFilter(mime_t *mime);
+extern int mimeNumFilters(mime_t *mime);
+extern void mimeSetErrorCallback(mime_t *mime, mime_error_cb_t cb,
+ void *context) _CUPS_API_1_5;
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_MIME_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/network.c b/scheduler/network.c
new file mode 100644
index 000000000..29b42ea04
--- /dev/null
+++ b/scheduler/network.c
@@ -0,0 +1,300 @@
+/*
+ * "$Id$"
+ *
+ * Network interface functions for the CUPS scheduler.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdNetIFFind() - Find a network interface.
+ * cupsdNetIFFree() - Free the current network interface list.
+ * cupsdNetIFUpdate() - Update the network interface list as needed...
+ * compare_netif() - Compare two network interfaces.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <cups/http-private.h>
+#include "cupsd.h"
+
+
+/*
+ * Local functions...
+ */
+
+static void cupsdNetIFFree(void);
+static int compare_netif(cupsd_netif_t *a, cupsd_netif_t *b);
+
+
+/*
+ * 'cupsdNetIFFind()' - Find a network interface.
+ */
+
+cupsd_netif_t * /* O - Network interface data */
+cupsdNetIFFind(const char *name) /* I - Name of interface */
+{
+ cupsd_netif_t key; /* Search key */
+
+
+ /*
+ * Update the interface list as needed...
+ */
+
+ if (NetIFUpdate)
+ cupsdNetIFUpdate();
+
+ /*
+ * Search for the named interface...
+ */
+
+ strlcpy(key.name, name, sizeof(key.name));
+
+ return ((cupsd_netif_t *)cupsArrayFind(NetIFList, &key));
+}
+
+
+/*
+ * 'cupsdNetIFFree()' - Free the current network interface list.
+ */
+
+static void
+cupsdNetIFFree(void)
+{
+ cupsd_netif_t *current; /* Current interface in array */
+
+
+ /*
+ * Loop through the interface list and free all the records...
+ */
+
+ for (current = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
+ current;
+ current = (cupsd_netif_t *)cupsArrayNext(NetIFList))
+ {
+ cupsArrayRemove(NetIFList, current);
+ free(current);
+ }
+}
+
+
+/*
+ * 'cupsdNetIFUpdate()' - Update the network interface list as needed...
+ */
+
+void
+cupsdNetIFUpdate(void)
+{
+ int match; /* Matching address? */
+ cupsd_listener_t *lis; /* Listen address */
+ cupsd_netif_t *temp; /* New interface */
+ struct ifaddrs *addrs, /* Interface address list */
+ *addr; /* Current interface address */
+ char hostname[1024]; /* Hostname for address */
+ size_t hostlen; /* Length of hostname */
+
+
+ /*
+ * Only update the list if we need to...
+ */
+
+ if (!NetIFUpdate)
+ return;
+
+ NetIFUpdate = 0;
+
+ /*
+ * Free the old interfaces...
+ */
+
+ cupsdNetIFFree();
+
+ /*
+ * Make sure we have an array...
+ */
+
+ if (!NetIFList)
+ NetIFList = cupsArrayNew((cups_array_func_t)compare_netif, NULL);
+
+ if (!NetIFList)
+ return;
+
+ /*
+ * Grab a new list of interfaces...
+ */
+
+ if (getifaddrs(&addrs) < 0)
+ return;
+
+ for (addr = addrs; addr != NULL; addr = addr->ifa_next)
+ {
+ /*
+ * See if this interface address is IPv4 or IPv6...
+ */
+
+ if (addr->ifa_addr == NULL ||
+ (addr->ifa_addr->sa_family != AF_INET
+#ifdef AF_INET6
+ && addr->ifa_addr->sa_family != AF_INET6
+#endif
+ ) ||
+ addr->ifa_netmask == NULL || addr->ifa_name == NULL)
+ continue;
+
+ /*
+ * Try looking up the hostname for the address as needed...
+ */
+
+ if (HostNameLookups)
+ httpAddrLookup((http_addr_t *)(addr->ifa_addr), hostname,
+ sizeof(hostname));
+ else
+ {
+ /*
+ * Map the default server address and localhost to the server name
+ * and localhost, respectively; for all other addresses, use the
+ * numeric address...
+ */
+
+ if (httpAddrLocalhost((http_addr_t *)(addr->ifa_addr)))
+ strcpy(hostname, "localhost");
+ else
+ httpAddrString((http_addr_t *)(addr->ifa_addr), hostname,
+ sizeof(hostname));
+ }
+
+ /*
+ * Create a new address element...
+ */
+
+ hostlen = strlen(hostname);
+ if ((temp = calloc(1, sizeof(cupsd_netif_t) + hostlen)) == NULL)
+ break;
+
+ /*
+ * Copy all of the information...
+ */
+
+ strlcpy(temp->name, addr->ifa_name, sizeof(temp->name));
+ temp->hostlen = hostlen;
+ strcpy(temp->hostname, hostname); /* Safe because hostname is allocated */
+
+ if (addr->ifa_addr->sa_family == AF_INET)
+ {
+ /*
+ * Copy IPv4 addresses...
+ */
+
+ memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in));
+ memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in));
+
+ if (addr->ifa_dstaddr)
+ memcpy(&(temp->broadcast), addr->ifa_dstaddr,
+ sizeof(struct sockaddr_in));
+ }
+#ifdef AF_INET6
+ else
+ {
+ /*
+ * Copy IPv6 addresses...
+ */
+
+ memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in6));
+ memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in6));
+
+ if (addr->ifa_dstaddr)
+ memcpy(&(temp->broadcast), addr->ifa_dstaddr,
+ sizeof(struct sockaddr_in6));
+ }
+#endif /* AF_INET6 */
+
+ if (!(addr->ifa_flags & IFF_POINTOPOINT) &&
+ !httpAddrLocalhost(&(temp->address)))
+ temp->is_local = 1;
+
+ /*
+ * Determine which port to use when advertising printers...
+ */
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ {
+ match = 0;
+
+ if (httpAddrAny(&(lis->address)))
+ match = 1;
+ else if (addr->ifa_addr->sa_family == AF_INET &&
+ lis->address.addr.sa_family == AF_INET &&
+ (lis->address.ipv4.sin_addr.s_addr &
+ temp->mask.ipv4.sin_addr.s_addr) ==
+ (temp->address.ipv4.sin_addr.s_addr &
+ temp->mask.ipv4.sin_addr.s_addr))
+ match = 1;
+#ifdef AF_INET6
+ else if (addr->ifa_addr->sa_family == AF_INET6 &&
+ lis->address.addr.sa_family == AF_INET6 &&
+ (lis->address.ipv6.sin6_addr.s6_addr[0] &
+ temp->mask.ipv6.sin6_addr.s6_addr[0]) ==
+ (temp->address.ipv6.sin6_addr.s6_addr[0] &
+ temp->mask.ipv6.sin6_addr.s6_addr[0]) &&
+ (lis->address.ipv6.sin6_addr.s6_addr[1] &
+ temp->mask.ipv6.sin6_addr.s6_addr[1]) ==
+ (temp->address.ipv6.sin6_addr.s6_addr[1] &
+ temp->mask.ipv6.sin6_addr.s6_addr[1]) &&
+ (lis->address.ipv6.sin6_addr.s6_addr[2] &
+ temp->mask.ipv6.sin6_addr.s6_addr[2]) ==
+ (temp->address.ipv6.sin6_addr.s6_addr[2] &
+ temp->mask.ipv6.sin6_addr.s6_addr[2]) &&
+ (lis->address.ipv6.sin6_addr.s6_addr[3] &
+ temp->mask.ipv6.sin6_addr.s6_addr[3]) ==
+ (temp->address.ipv6.sin6_addr.s6_addr[3] &
+ temp->mask.ipv6.sin6_addr.s6_addr[3]))
+ match = 1;
+#endif /* AF_INET6 */
+
+ if (match)
+ {
+ temp->port = _httpAddrPort(&(lis->address));
+ break;
+ }
+ }
+
+ /*
+ * Add it to the array...
+ */
+
+ cupsArrayAdd(NetIFList, temp);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: \"%s\" = %s:%d",
+ temp->name, temp->hostname, temp->port);
+ }
+
+ freeifaddrs(addrs);
+}
+
+
+/*
+ * 'compare_netif()' - Compare two network interfaces.
+ */
+
+static int /* O - Result of comparison */
+compare_netif(cupsd_netif_t *a, /* I - First network interface */
+ cupsd_netif_t *b) /* I - Second network interface */
+{
+ return (strcmp(a->name, b->name));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/network.h b/scheduler/network.h
new file mode 100644
index 000000000..c7a6aa0c3
--- /dev/null
+++ b/scheduler/network.h
@@ -0,0 +1,52 @@
+/*
+ * "$Id$"
+ *
+ * Network interface definitions for the CUPS scheduler.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/*
+ * Structures...
+ */
+
+typedef struct cupsd_netif_s /**** Network interface data ****/
+{
+ int is_local, /* Local (not point-to-point) interface? */
+ port; /* Listen port */
+ http_addr_t address, /* Network address */
+ mask, /* Network mask */
+ broadcast; /* Broadcast address */
+ size_t hostlen; /* Length of hostname */
+ char name[32], /* Network interface name */
+ hostname[1]; /* Hostname associated with interface */
+} cupsd_netif_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR int NetIFUpdate VALUE(1);
+ /* Network interface list needs updating */
+VAR cups_array_t *NetIFList VALUE(NULL);
+ /* Array of network interfaces */
+
+/*
+ * Prototypes...
+ */
+
+extern cupsd_netif_t *cupsdNetIFFind(const char *name);
+extern void cupsdNetIFUpdate(void);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/org.cups.cups-lpd.plist.in b/scheduler/org.cups.cups-lpd.plist.in
new file mode 100644
index 000000000..32067ef1d
--- /dev/null
+++ b/scheduler/org.cups.cups-lpd.plist.in
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Disabled</key>
+ <true/>
+ <key>Label</key>
+ <string>org.cups.cups-lpd</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/cups/daemon/cups-lpd</string>
+ <string>-o</string>
+ <string>document-format=application/octet-stream</string>
+ </array>
+ <key>Sockets</key>
+ <dict>
+ <key>Listeners</key>
+ <dict>
+ <key>SockServiceName</key>
+ <string>printer</string>
+ <key>SockType</key>
+ <string>stream</string>
+ </dict>
+ </dict>
+ <key>UserName</key>
+ <string>@CUPS_USER@</string>
+ <key>inetdCompatibility</key>
+ <dict>
+ <key>Wait</key>
+ <false/>
+ </dict>
+</dict>
+</plist>
diff --git a/scheduler/org.cups.cupsd.plist b/scheduler/org.cups.cupsd.plist
new file mode 100644
index 000000000..ccc861d8f
--- /dev/null
+++ b/scheduler/org.cups.cupsd.plist
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>org.cups.cupsd</string>
+ <key>EnableTransactions</key>
+ <true/>
+ <key>ExitTimeOut</key>
+ <integer>60</integer>
+ <key>KeepAlive</key>
+ <dict>
+ <key>PathState</key>
+ <dict>
+ <key>/private/var/spool/cups/cache/org.cups.cupsd</key>
+ <true/>
+ </dict>
+ </dict>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/sbin/cupsd</string>
+ <string>-l</string>
+ </array>
+ <!-- These environment variables are only used when CUPS is compiled
+ with --enable-debug-printfs -->
+ <key>EnvironmentVariables</key>
+ <dict>
+ <key>CUPS_DEBUG_LOG</key>
+ <string>/var/log/cups/debug_log</string>
+ <key>CUPS_DEBUG_LEVEL</key>
+ <string>3</string>
+ <key>CUPS_DEBUG_FILTER</key>
+ <string>^(http|_http|ipp|_ipp|mime).*</string>
+ </dict>
+ <key>ServiceIPC</key>
+ <true/>
+ <key>Sockets</key>
+ <dict>
+ <key>Listeners</key>
+ <array>
+ <dict>
+ <key>SockNodeName</key>
+ <string>::1</string>
+ <key>SockServiceName</key>
+ <string>ipp</string>
+ </dict>
+ <dict>
+ <key>SockNodeName</key>
+ <string>127.0.0.1</string>
+ <key>SockServiceName</key>
+ <string>ipp</string>
+ </dict>
+ <dict>
+ <key>SockPathMode</key>
+ <integer>49663</integer>
+ <key>SockPathName</key>
+ <string>/private/var/run/cupsd</string>
+ </dict>
+ </array>
+ </dict>
+</dict>
+</plist>
diff --git a/scheduler/policy.c b/scheduler/policy.c
new file mode 100644
index 000000000..466067036
--- /dev/null
+++ b/scheduler/policy.c
@@ -0,0 +1,517 @@
+/*
+ * "$Id$"
+ *
+ * Policy routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * AddPolicy() - Add a policy to the system.
+ * cupsdAddPolicyOp() - Add an operation to a policy.
+ * cupsdCheckPolicy() - Check the IPP operation and username against a
+ * policy.
+ * cupsdDeleteAllPolicies() - Delete all policies in memory.
+ * cupsdFindPolicy() - Find a named policy.
+ * cupsdFindPolicyOp() - Find a policy operation.
+ * cupsdGetPrivateAttrs() - Get the private attributes for the current
+ * request.
+ * compare_ops() - Compare two operations.
+ * compare_policies() - Compare two policies.
+ * free_policy() - Free the memory used by a policy.
+ * hash_op() - Generate a lookup hash for the operation.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <pwd.h>
+
+
+/*
+ * Local functions...
+ */
+
+static int compare_ops(cupsd_location_t *a, cupsd_location_t *b);
+static int compare_policies(cupsd_policy_t *a, cupsd_policy_t *b);
+static void free_policy(cupsd_policy_t *p);
+static int hash_op(cupsd_location_t *op);
+
+
+/*
+ * 'AddPolicy()' - Add a policy to the system.
+ */
+
+cupsd_policy_t * /* O - Policy */
+cupsdAddPolicy(const char *policy) /* I - Name of policy */
+{
+ cupsd_policy_t *temp; /* Pointer to policy */
+
+
+ if (!policy)
+ return (NULL);
+
+ if (!Policies)
+ Policies = cupsArrayNew3((cups_array_func_t)compare_policies, NULL,
+ (cups_ahash_func_t)NULL, 0,
+ (cups_acopy_func_t)NULL,
+ (cups_afree_func_t)free_policy);
+
+ if (!Policies)
+ return (NULL);
+
+ if ((temp = calloc(1, sizeof(cupsd_policy_t))) != NULL)
+ {
+ cupsdSetString(&temp->name, policy);
+ cupsArrayAdd(Policies, temp);
+ }
+
+ return (temp);
+}
+
+
+/*
+ * 'cupsdAddPolicyOp()' - Add an operation to a policy.
+ */
+
+cupsd_location_t * /* O - New policy operation */
+cupsdAddPolicyOp(cupsd_policy_t *p, /* I - Policy */
+ cupsd_location_t *po, /* I - Policy operation to copy */
+ ipp_op_t op) /* I - IPP operation code */
+{
+ cupsd_location_t *temp; /* New policy operation */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPolicyOp(p=%p, po=%p, op=%x(%s))",
+ p, po, op, ippOpString(op));
+
+ if (!p)
+ return (NULL);
+
+ if (!p->ops)
+ p->ops = cupsArrayNew3((cups_array_func_t)compare_ops, NULL,
+ (cups_ahash_func_t)hash_op, 128,
+ (cups_acopy_func_t)NULL,
+ (cups_afree_func_t)cupsdFreeLocation);
+
+ if (!p->ops)
+ return (NULL);
+
+ if ((temp = cupsdCopyLocation(po)) != NULL)
+ {
+ temp->op = op;
+ temp->limit = CUPSD_AUTH_LIMIT_IPP;
+
+ cupsArrayAdd(p->ops, temp);
+ }
+
+ return (temp);
+}
+
+
+/*
+ * 'cupsdCheckPolicy()' - Check the IPP operation and username against a policy.
+ */
+
+http_status_t /* I - 1 if OK, 0 otherwise */
+cupsdCheckPolicy(cupsd_policy_t *p, /* I - Policy */
+ cupsd_client_t *con, /* I - Client connection */
+ const char *owner) /* I - Owner of object */
+{
+ cupsd_location_t *po; /* Current policy operation */
+
+
+ /*
+ * Range check...
+ */
+
+ if (!p || !con)
+ {
+ cupsdLogMessage(CUPSD_LOG_CRIT, "cupsdCheckPolicy: p=%p, con=%p!", p, con);
+
+ return ((http_status_t)0);
+ }
+
+ /*
+ * Find a match for the operation...
+ */
+
+ if ((po = cupsdFindPolicyOp(p, con->request->request.op.operation_id)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckPolicy: No matching operation, returning 0!");
+ return ((http_status_t)0);
+ }
+
+ con->best = po;
+
+ /*
+ * Return the status of the check...
+ */
+
+ return (cupsdIsAuthorized(con, owner));
+}
+
+
+/*
+ * 'cupsdDeleteAllPolicies()' - Delete all policies in memory.
+ */
+
+void
+cupsdDeleteAllPolicies(void)
+{
+ cupsd_printer_t *printer; /* Current printer */
+
+
+ if (!Policies)
+ return;
+
+ /*
+ * First clear the policy pointers for all printers...
+ */
+
+ for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ printer;
+ printer = (cupsd_printer_t *)cupsArrayNext(Printers))
+ printer->op_policy_ptr = NULL;
+
+ DefaultPolicyPtr = NULL;
+
+ /*
+ * Then free all of the policies...
+ */
+
+ cupsArrayDelete(Policies);
+
+ Policies = NULL;
+}
+
+
+/*
+ * 'cupsdFindPolicy()' - Find a named policy.
+ */
+
+cupsd_policy_t * /* O - Policy */
+cupsdFindPolicy(const char *policy) /* I - Name of policy */
+{
+ cupsd_policy_t key; /* Search key */
+
+
+ /*
+ * Range check...
+ */
+
+ if (!policy)
+ return (NULL);
+
+ /*
+ * Look it up...
+ */
+
+ key.name = (char *)policy;
+ return ((cupsd_policy_t *)cupsArrayFind(Policies, &key));
+}
+
+
+/*
+ * 'cupsdFindPolicyOp()' - Find a policy operation.
+ */
+
+cupsd_location_t * /* O - Policy operation */
+cupsdFindPolicyOp(cupsd_policy_t *p, /* I - Policy */
+ ipp_op_t op) /* I - IPP operation */
+{
+ cupsd_location_t key, /* Search key... */
+ *po; /* Current policy operation */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp(p=%p, op=%x(%s))",
+ p, op, ippOpString(op));
+
+ /*
+ * Range check...
+ */
+
+ if (!p)
+ return (NULL);
+
+ /*
+ * Check the operation against the available policies...
+ */
+
+ key.op = op;
+ if ((po = (cupsd_location_t *)cupsArrayFind(p->ops, &key)) != NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdFindPolicyOp: Found exact match...");
+ return (po);
+ }
+
+ key.op = IPP_ANY_OPERATION;
+ if ((po = (cupsd_location_t *)cupsArrayFind(p->ops, &key)) != NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdFindPolicyOp: Found wildcard match...");
+ return (po);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp: No match found!");
+
+ return (NULL);
+}
+
+
+/*
+ * 'cupsdGetPrivateAttrs()' - Get the private attributes for the current
+ * request.
+ */
+
+cups_array_t * /* O - Array or NULL for no restrictions */
+cupsdGetPrivateAttrs(
+ cupsd_policy_t *policy, /* I - Policy */
+ cupsd_client_t *con, /* I - Client connection */
+ cupsd_printer_t *printer, /* I - Printer, if any */
+ const char *owner) /* I - Owner of object */
+{
+ char *name; /* Current name in access list */
+ cups_array_t *access_ptr, /* Access array */
+ *attrs_ptr; /* Attributes array */
+ const char *username; /* Username associated with request */
+ ipp_attribute_t *attr; /* Attribute from request */
+ struct passwd *pw; /* User info */
+
+
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdGetPrivateAttrs(policy=%p(%s), con=%p(%d), "
+ "printer=%p(%s), owner=\"%s\")", policy, policy->name, con,
+ con->http.fd, printer, printer ? printer->name : "", owner);
+#endif /* DEBUG */
+
+ /*
+ * Get the access and attributes lists that correspond to the request...
+ */
+
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: %s",
+ ippOpString(con->request->request.op.operation_id));
+#endif /* DEBUG */
+
+ switch (con->request->request.op.operation_id)
+ {
+ case IPP_GET_SUBSCRIPTIONS :
+ case IPP_GET_SUBSCRIPTION_ATTRIBUTES :
+ case IPP_GET_NOTIFICATIONS :
+ access_ptr = policy->sub_access;
+ attrs_ptr = policy->sub_attrs;
+ break;
+
+ default :
+ access_ptr = policy->job_access;
+ attrs_ptr = policy->job_attrs;
+ break;
+ }
+
+ /*
+ * If none of the attributes are private, return NULL now...
+ */
+
+ if ((name = (char *)cupsArrayFirst(attrs_ptr)) != NULL &&
+ !_cups_strcasecmp(name, "none"))
+ {
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
+
+ return (NULL);
+ }
+
+ /*
+ * Otherwise check the user against the access list...
+ */
+
+ if (con->username[0])
+ username = con->username;
+ else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
+ IPP_TAG_NAME)) != NULL)
+ username = attr->values[0].string.text;
+ else
+ username = "anonymous";
+
+ if (username[0])
+ {
+ pw = getpwnam(username);
+ endpwent();
+ }
+ else
+ pw = NULL;
+
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: username=\"%s\"",
+ username);
+#endif /* DEBUG */
+
+ /*
+ * Otherwise check the user against the access list...
+ */
+
+ for (name = (char *)cupsArrayFirst(access_ptr);
+ name;
+ name = (char *)cupsArrayNext(access_ptr))
+ {
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: name=%s", name);
+#endif /* DEBUG */
+
+ if (printer && !_cups_strcasecmp(name, "@ACL"))
+ {
+ char *acl; /* Current ACL user/group */
+
+ for (acl = (char *)cupsArrayFirst(printer->users);
+ acl;
+ acl = (char *)cupsArrayNext(printer->users))
+ {
+ if (acl[0] == '@')
+ {
+ /*
+ * Check group membership...
+ */
+
+ if (cupsdCheckGroup(username, pw, acl + 1))
+ break;
+ }
+ else if (acl[0] == '#')
+ {
+ /*
+ * Check UUID...
+ */
+
+ if (cupsdCheckGroup(username, pw, acl))
+ break;
+ }
+ else if (!_cups_strcasecmp(username, acl))
+ break;
+ }
+ }
+ else if (owner && !_cups_strcasecmp(name, "@OWNER") &&
+ !_cups_strcasecmp(username, owner))
+ {
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
+
+ return (NULL);
+ }
+ else if (!_cups_strcasecmp(name, "@SYSTEM"))
+ {
+ int i; /* Looping var */
+
+ for (i = 0; i < NumSystemGroups; i ++)
+ if (cupsdCheckGroup(username, pw, SystemGroups[i]))
+ {
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
+
+ return (NULL);
+ }
+ }
+ else if (name[0] == '@')
+ {
+ if (cupsdCheckGroup(username, pw, name + 1))
+ {
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
+
+ return (NULL);
+ }
+ }
+ else if (!_cups_strcasecmp(username, name))
+ {
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
+
+ return (NULL);
+ }
+ }
+
+ /*
+ * No direct access, so return private attributes list...
+ */
+
+#ifdef DEBUG
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning list.");
+#endif /* DEBUG */
+
+ return (attrs_ptr);
+}
+
+
+/*
+ * 'compare_ops()' - Compare two operations.
+ */
+
+static int /* O - Result of comparison */
+compare_ops(cupsd_location_t *a, /* I - First operation */
+ cupsd_location_t *b) /* I - Second operation */
+{
+ return (a->op - b->op);
+}
+
+
+/*
+ * 'compare_policies()' - Compare two policies.
+ */
+
+static int /* O - Result of comparison */
+compare_policies(cupsd_policy_t *a, /* I - First policy */
+ cupsd_policy_t *b) /* I - Second policy */
+{
+ return (_cups_strcasecmp(a->name, b->name));
+}
+
+
+/*
+ * 'free_policy()' - Free the memory used by a policy.
+ */
+
+static void
+free_policy(cupsd_policy_t *p) /* I - Policy to free */
+{
+ cupsArrayDelete(p->job_access);
+ cupsArrayDelete(p->job_attrs);
+ cupsArrayDelete(p->sub_access);
+ cupsArrayDelete(p->sub_attrs);
+ cupsArrayDelete(p->ops);
+ cupsdClearString(&p->name);
+ free(p);
+}
+
+
+/*
+ * 'hash_op()' - Generate a lookup hash for the operation.
+ */
+
+static int /* O - Hash value */
+hash_op(cupsd_location_t *op) /* I - Operation */
+{
+ return (((op->op >> 6) & 0x40) | (op->op & 0x3f));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/policy.h b/scheduler/policy.h
new file mode 100644
index 000000000..361271f2b
--- /dev/null
+++ b/scheduler/policy.h
@@ -0,0 +1,63 @@
+/*
+ * "$Id$"
+ *
+ * Policy definitions for the CUPS scheduler.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+
+/*
+ * Policy structure...
+ */
+
+typedef struct
+{
+ char *name; /* Policy name */
+ cups_array_t *job_access, /* Private users/groups for jobs */
+ *job_attrs, /* Private attributes for jobs */
+ *sub_access, /* Private users/groups for subscriptions */
+ *sub_attrs, /* Private attributes for subscriptions */
+ *ops; /* Operations */
+} cupsd_policy_t;
+
+typedef struct cupsd_printer_s cupsd_printer_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR cups_array_t *Policies VALUE(NULL);
+ /* Policies */
+
+
+/*
+ * Prototypes...
+ */
+
+extern cupsd_policy_t *cupsdAddPolicy(const char *policy);
+extern cupsd_location_t *cupsdAddPolicyOp(cupsd_policy_t *p,
+ cupsd_location_t *po,
+ ipp_op_t op);
+extern http_status_t cupsdCheckPolicy(cupsd_policy_t *p, cupsd_client_t *con,
+ const char *owner);
+extern void cupsdDeleteAllPolicies(void);
+extern cupsd_policy_t *cupsdFindPolicy(const char *policy);
+extern cupsd_location_t *cupsdFindPolicyOp(cupsd_policy_t *p, ipp_op_t op);
+extern cups_array_t *cupsdGetPrivateAttrs(cupsd_policy_t *p,
+ cupsd_client_t *con,
+ cupsd_printer_t *printer,
+ const char *owner);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/printers.c b/scheduler/printers.c
new file mode 100644
index 000000000..1a8041473
--- /dev/null
+++ b/scheduler/printers.c
@@ -0,0 +1,5427 @@
+/*
+ * "$Id$"
+ *
+ * Printer routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdAddPrinter() - Add a printer to the system.
+ * cupsdCreateCommonData() - Create the common printer data.
+ * cupsdDeleteAllPrinters() - Delete all printers from the system.
+ * cupsdDeletePrinter() - Delete a printer from the system.
+ * cupsdFindDest() - Find a destination in the list.
+ * cupsdFindPrinter() - Find a printer in the list.
+ * cupsdLoadAllPrinters() - Load printers from the printers.conf file.
+ * cupsdRenamePrinter() - Rename a printer.
+ * cupsdSaveAllPrinters() - Save all printer definitions to the
+ * printers.conf file.
+ * cupsdSetAuthInfoRequired() - Set the required authentication info.
+ * cupsdSetDeviceURI() - Set the device URI for a printer.
+ * cupsdSetPrinterAttr() - Set a printer attribute.
+ * cupsdSetPrinterAttrs() - Set printer attributes based upon the PPD
+ * file.
+ * cupsdSetPrinterReasons() - Set/update the reasons strings.
+ * cupsdSetPrinterState() - Update the current state of a printer.
+ * cupsdStopPrinter() - Stop a printer from printing any jobs...
+ * cupsdUpdatePrinterPPD() - Update keywords in a printer's PPD file.
+ * cupsdUpdatePrinters() - Update printers after a partial reload.
+ * cupsdValidateDest() - Validate a printer/class destination.
+ * cupsdWritePrintcap() - Write a pseudo-printcap file for older
+ * applications that need it...
+ * add_printer_defaults() - Add name-default attributes to the printer
+ * attributes.
+ * add_printer_filter() - Add a MIME filter for a printer.
+ * add_printer_formats() - Add document-format-supported values for a
+ * printer.
+ * compare_printers() - Compare two printers.
+ * delete_printer_filters() - Delete all MIME filters for a printer.
+ * dirty_printer() - Mark config and state files dirty for the
+ * specified printer.
+ * load_ppd() - Load a cached PPD file, updating the cache as
+ * needed.
+ * new_media_col() - Create a media-col collection value.
+ * write_irix_config() - Update the config files used by the IRIX
+ * desktop tools.
+ * write_irix_state() - Update the status files used by IRIX printing
+ * desktop tools.
+ * write_xml_string() - Write a string with XML escaping.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <cups/dir.h>
+#ifdef HAVE_APPLICATIONSERVICES_H
+# include <ApplicationServices/ApplicationServices.h>
+#endif /* HAVE_APPLICATIONSERVICES_H */
+#ifdef HAVE_SYS_MOUNT_H
+# include <sys/mount.h>
+#endif /* HAVE_SYS_MOUNT_H */
+#ifdef HAVE_SYS_STATVFS_H
+# include <sys/statvfs.h>
+#elif defined(HAVE_SYS_STATFS_H)
+# include <sys/statfs.h>
+#endif /* HAVE_SYS_STATVFS_H */
+#ifdef HAVE_SYS_VFS_H
+# include <sys/vfs.h>
+#endif /* HAVE_SYS_VFS_H */
+
+
+/*
+ * Local functions...
+ */
+
+static void add_printer_defaults(cupsd_printer_t *p);
+static void add_printer_filter(cupsd_printer_t *p, mime_type_t *type,
+ const char *filter);
+static void add_printer_formats(cupsd_printer_t *p);
+static int compare_printers(void *first, void *second, void *data);
+static void delete_printer_filters(cupsd_printer_t *p);
+static void dirty_printer(cupsd_printer_t *p);
+static void load_ppd(cupsd_printer_t *p);
+static ipp_t *new_media_col(_pwg_size_t *size, const char *source,
+ const char *type);
+#ifdef __sgi
+static void write_irix_config(cupsd_printer_t *p);
+static void write_irix_state(cupsd_printer_t *p);
+#endif /* __sgi */
+static void write_xml_string(cups_file_t *fp, const char *s);
+
+
+/*
+ * 'cupsdAddPrinter()' - Add a printer to the system.
+ */
+
+cupsd_printer_t * /* O - New printer */
+cupsdAddPrinter(const char *name) /* I - Name of printer */
+{
+ cupsd_printer_t *p; /* New printer */
+ char uri[1024], /* Printer URI */
+ uuid[64]; /* Printer UUID */
+
+
+ /*
+ * Range check input...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPrinter(\"%s\")", name);
+
+ /*
+ * Create a new printer entity...
+ */
+
+ if ((p = calloc(1, sizeof(cupsd_printer_t))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for printer - %s",
+ strerror(errno));
+ return (NULL);
+ }
+
+ cupsdSetString(&p->name, name);
+ cupsdSetString(&p->info, name);
+ cupsdSetString(&p->hostname, ServerName);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ ServerName, RemotePort, "/printers/%s", name);
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->uuid, _httpAssembleUUID(ServerName, RemotePort, name, 0,
+ uuid, sizeof(uuid)));
+ cupsdSetDeviceURI(p, "file:///dev/null");
+
+ p->state = IPP_PRINTER_STOPPED;
+ p->state_time = time(NULL);
+ p->accepting = 0;
+ p->shared = DefaultShared;
+ p->filetype = mimeAddType(MimeDatabase, "printer", name);
+
+ cupsdSetString(&p->job_sheets[0], "none");
+ cupsdSetString(&p->job_sheets[1], "none");
+
+ cupsdSetString(&p->error_policy, ErrorPolicy);
+ cupsdSetString(&p->op_policy, DefaultPolicy);
+
+ p->op_policy_ptr = DefaultPolicyPtr;
+
+ /*
+ * Insert the printer in the printer list alphabetically...
+ */
+
+ if (!Printers)
+ Printers = cupsArrayNew(compare_printers, NULL);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdAddPrinter: Adding %s to Printers", p->name);
+ cupsArrayAdd(Printers, p);
+
+ if (!ImplicitPrinters)
+ ImplicitPrinters = cupsArrayNew(compare_printers, NULL);
+
+ /*
+ * Return the new printer...
+ */
+
+ return (p);
+}
+
+
+/*
+ * 'cupsdCreateCommonData()' - Create the common printer data.
+ */
+
+void
+cupsdCreateCommonData(void)
+{
+ int i; /* Looping var */
+ ipp_attribute_t *attr; /* Attribute data */
+ cups_dir_t *dir; /* Notifier directory */
+ cups_dentry_t *dent; /* Notifier directory entry */
+ cups_array_t *notifiers; /* Notifier array */
+ char filename[1024], /* Filename */
+ *notifier; /* Current notifier */
+ cupsd_policy_t *p; /* Current policy */
+ int k_supported; /* Maximum file size supported */
+#ifdef HAVE_STATVFS
+ struct statvfs spoolinfo; /* FS info for spool directory */
+ double spoolsize; /* FS size */
+#elif defined(HAVE_STATFS)
+ struct statfs spoolinfo; /* FS info for spool directory */
+ double spoolsize; /* FS size */
+#endif /* HAVE_STATVFS */
+ static const int nups[] = /* number-up-supported values */
+ { 1, 2, 4, 6, 9, 16 };
+ static const int orients[4] =/* orientation-requested-supported values */
+ {
+ IPP_PORTRAIT,
+ IPP_LANDSCAPE,
+ IPP_REVERSE_LANDSCAPE,
+ IPP_REVERSE_PORTRAIT
+ };
+ static const char * const holds[] = /* job-hold-until-supported values */
+ {
+ "no-hold",
+ "indefinite",
+ "day-time",
+ "evening",
+ "night",
+ "second-shift",
+ "third-shift",
+ "weekend"
+ };
+ static const char * const versions[] =/* ipp-versions-supported values */
+ {
+ "1.0",
+ "1.1",
+ "2.0",
+ "2.1"
+ };
+ static const int ops[] = /* operations-supported values */
+ {
+ IPP_PRINT_JOB,
+ IPP_VALIDATE_JOB,
+ IPP_CREATE_JOB,
+ IPP_SEND_DOCUMENT,
+ IPP_CANCEL_JOB,
+ IPP_GET_JOB_ATTRIBUTES,
+ IPP_GET_JOBS,
+ IPP_GET_PRINTER_ATTRIBUTES,
+ IPP_HOLD_JOB,
+ IPP_RELEASE_JOB,
+ IPP_RESTART_JOB,
+ IPP_PAUSE_PRINTER,
+ IPP_RESUME_PRINTER,
+ IPP_PURGE_JOBS,
+ IPP_SET_PRINTER_ATTRIBUTES,
+ IPP_SET_JOB_ATTRIBUTES,
+ IPP_GET_PRINTER_SUPPORTED_VALUES,
+ IPP_CREATE_PRINTER_SUBSCRIPTION,
+ IPP_CREATE_JOB_SUBSCRIPTION,
+ IPP_GET_SUBSCRIPTION_ATTRIBUTES,
+ IPP_GET_SUBSCRIPTIONS,
+ IPP_RENEW_SUBSCRIPTION,
+ IPP_CANCEL_SUBSCRIPTION,
+ IPP_GET_NOTIFICATIONS,
+ IPP_ENABLE_PRINTER,
+ IPP_DISABLE_PRINTER,
+ IPP_HOLD_NEW_JOBS,
+ IPP_RELEASE_HELD_NEW_JOBS,
+ IPP_CANCEL_JOBS,
+ IPP_CANCEL_MY_JOBS,
+ IPP_CLOSE_JOB,
+ CUPS_GET_DEFAULT,
+ CUPS_GET_PRINTERS,
+ CUPS_ADD_PRINTER,
+ CUPS_DELETE_PRINTER,
+ CUPS_GET_CLASSES,
+ CUPS_ADD_CLASS,
+ CUPS_DELETE_CLASS,
+ CUPS_ACCEPT_JOBS,
+ CUPS_REJECT_JOBS,
+ CUPS_SET_DEFAULT,
+ CUPS_GET_DEVICES,
+ CUPS_GET_PPDS,
+ CUPS_MOVE_JOB,
+ CUPS_AUTHENTICATE_JOB,
+ CUPS_GET_PPD,
+ CUPS_GET_DOCUMENT,
+ IPP_RESTART_JOB
+ };
+ static const char * const charsets[] =/* charset-supported values */
+ {
+ "us-ascii",
+ "utf-8"
+ };
+ static const char * const compressions[] =
+ { /* document-compression-supported values */
+ "none"
+#ifdef HAVE_LIBZ
+ ,"gzip"
+#endif /* HAVE_LIBZ */
+ };
+ static const char * const media_col_supported[] =
+ { /* media-col-supported values */
+ "media-bottom-margin",
+ "media-left-margin",
+ "media-right-margin",
+ "media-size",
+ "media-source",
+ "media-top-margin",
+ "media-type"
+ };
+ static const char * const multiple_document_handling[] =
+ { /* multiple-document-handling-supported values */
+ "separate-documents-uncollated-copies",
+ "separate-documents-collated-copies"
+ };
+ static const char * const notify_attrs[] =
+ { /* notify-attributes-supported values */
+ "printer-state-change-time",
+ "notify-lease-expiration-time",
+ "notify-subscriber-user-name"
+ };
+ static const char * const notify_events[] =
+ { /* notify-events-supported values */
+ "job-completed",
+ "job-config-changed",
+ "job-created",
+ "job-progress",
+ "job-state-changed",
+ "job-stopped",
+ "printer-added",
+ "printer-changed",
+ "printer-config-changed",
+ "printer-deleted",
+ "printer-finishings-changed",
+ "printer-media-changed",
+ "printer-modified",
+ "printer-restarted",
+ "printer-shutdown",
+ "printer-state-changed",
+ "printer-stopped",
+ "server-audit",
+ "server-restarted",
+ "server-started",
+ "server-stopped"
+ };
+ static const char * const job_creation[] =
+ { /* job-creation-attributes-supported */
+ "copies",
+ "finishings",
+ "ipp-attribute-fidelity",
+ "job-hold-until",
+ "job-name",
+ "job-priority",
+ "job-sheets",
+ "media",
+ "media-col",
+ "multiple-document-handling",
+ "number-up",
+ "output-bin",
+ "output-mode",
+ "orientation-requested",
+ "page-ranges",
+ "print-quality",
+ "printer-resolution",
+ "sides"
+ };
+ static const char * const job_settable[] =
+ { /* job-settable-attributes-supported */
+ "copies",
+ "finishings",
+ "job-hold-until",
+ "job-name",
+ "job-priority",
+ "media",
+ "media-col",
+ "multiple-document-handling",
+ "number-up",
+ "output-bin",
+ "output-mode",
+ "orientation-requested",
+ "page-ranges",
+ "print-quality",
+ "printer-resolution",
+ "sides"
+ };
+ static const char * const pdf_versions[] =
+ { /* pdf-versions-supported */
+ "adobe-1.2",
+ "adobe-1.3",
+ "adobe-1.4",
+ "adobe-1.5",
+ "adobe-1.6",
+ "adobe-1.7",
+ "iso-19005-1_2005",
+ "iso-32000-1_2008",
+ "pwg-5102.3"
+ };
+ static const char * const printer_settable[] =
+ { /* printer-settable-attributes-supported */
+ "printer-info",
+ "printer-location"
+ };
+ static const char * const which_jobs[] =
+ { /* which-jobs-supported values */
+ "completed",
+ "not-completed",
+ "aborted",
+ "all",
+ "canceled",
+ "pending",
+ "pending-held",
+ "processing",
+ "processing-stopped"
+ };
+
+
+ if (CommonData)
+ ippDelete(CommonData);
+
+ CommonData = ippNew();
+
+ /*
+ * Get the maximum spool size based on the size of the filesystem used for
+ * the RequestRoot directory. If the host OS doesn't support the statfs call
+ * or the filesystem is larger than 2TiB, always report INT_MAX.
+ */
+
+#ifdef HAVE_STATVFS
+ if (statvfs(RequestRoot, &spoolinfo))
+ k_supported = INT_MAX;
+ else if ((spoolsize = (double)spoolinfo.f_frsize * spoolinfo.f_blocks / 1024) >
+ INT_MAX)
+ k_supported = INT_MAX;
+ else
+ k_supported = (int)spoolsize;
+
+#elif defined(HAVE_STATFS)
+ if (statfs(RequestRoot, &spoolinfo))
+ k_supported = INT_MAX;
+ else if ((spoolsize = (double)spoolinfo.f_bsize * spoolinfo.f_blocks / 1024) >
+ INT_MAX)
+ k_supported = INT_MAX;
+ else
+ k_supported = (int)spoolsize;
+
+#else
+ k_supported = INT_MAX;
+#endif /* HAVE_STATVFS */
+
+ /*
+ * This list of attributes is sorted to improve performance when the
+ * client provides a requested-attributes attribute...
+ */
+
+ /* charset-configured */
+ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
+ "charset-configured", NULL, "utf-8");
+
+ /* charset-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
+ "charset-supported", sizeof(charsets) / sizeof(charsets[0]),
+ NULL, charsets);
+
+ /* compression-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "compression-supported",
+ sizeof(compressions) / sizeof(compressions[0]),
+ NULL, compressions);
+
+ /* copies-supported */
+ ippAddRange(CommonData, IPP_TAG_PRINTER, "copies-supported", 1, MaxCopies);
+
+ /* cups-version */
+ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_TEXT | IPP_TAG_COPY,
+ "cups-version", NULL, CUPS_SVERSION + 6);
+
+ /* generated-natural-language-supported (no IPP_TAG_COPY) */
+ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
+ "generated-natural-language-supported", NULL, DefaultLanguage);
+
+ /* ipp-versions-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
+ NULL, versions);
+
+ /* ippget-event-life */
+ ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "ippget-event-life", 15);
+
+ /* job-creation-attributes-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "job-creation-attributes-supported",
+ sizeof(job_creation) / sizeof(job_creation[0]),
+ NULL, job_creation);
+
+ /* job-hold-until-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "job-hold-until-supported", sizeof(holds) / sizeof(holds[0]),
+ NULL, holds);
+
+ /* job-ids-supported */
+ ippAddBoolean(CommonData, IPP_TAG_PRINTER, "job-ids-supported", 1);
+
+ /* job-k-octets-supported */
+ ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-k-octets-supported", k_supported);
+
+ /* job-priority-supported */
+ ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-priority-supported", 100);
+
+ /* job-settable-attributes-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "job-settable-attributes-supported",
+ sizeof(job_settable) / sizeof(job_settable[0]),
+ NULL, job_settable);
+
+ /* job-sheets-supported */
+ if (cupsArrayCount(Banners) > 0)
+ {
+ /*
+ * Setup the job-sheets-supported attribute...
+ */
+
+ if (Classification && !ClassifyOverride)
+ attr = ippAddString(CommonData, IPP_TAG_PRINTER,
+ IPP_TAG_NAME | IPP_TAG_COPY,
+ "job-sheets-supported", NULL, Classification);
+ else
+ attr = ippAddStrings(CommonData, IPP_TAG_PRINTER,
+ IPP_TAG_NAME | IPP_TAG_COPY,
+ "job-sheets-supported", cupsArrayCount(Banners) + 1,
+ NULL, NULL);
+
+ if (attr == NULL)
+ cupsdLogMessage(CUPSD_LOG_EMERG,
+ "Unable to allocate memory for "
+ "job-sheets-supported attribute: %s!", strerror(errno));
+ else if (!Classification || ClassifyOverride)
+ {
+ cupsd_banner_t *banner; /* Current banner */
+
+
+ attr->values[0].string.text = _cupsStrAlloc("none");
+
+ for (i = 1, banner = (cupsd_banner_t *)cupsArrayFirst(Banners);
+ banner;
+ i ++, banner = (cupsd_banner_t *)cupsArrayNext(Banners))
+ attr->values[i].string.text = banner->name;
+ }
+ }
+ else
+ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
+ "job-sheets-supported", NULL, "none");
+
+ /* jpeg-k-octets-supported */
+ ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-k-octets-supported", 0,
+ k_supported);
+
+ /* jpeg-x-dimension-supported */
+ ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-x-dimension-supported", 0,
+ 65535);
+
+ /* jpeg-y-dimension-supported */
+ ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-y-dimension-supported", 1,
+ 65535);
+
+ /* media-col-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "media-col-supported",
+ sizeof(media_col_supported) /
+ sizeof(media_col_supported[0]), NULL,
+ media_col_supported);
+
+ /* multiple-document-handling-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "multiple-document-handling-supported",
+ sizeof(multiple_document_handling) /
+ sizeof(multiple_document_handling[0]), NULL,
+ multiple_document_handling);
+
+ /* multiple-document-jobs-supported */
+ ippAddBoolean(CommonData, IPP_TAG_PRINTER,
+ "multiple-document-jobs-supported", 1);
+
+ /* multiple-operation-time-out */
+ ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "multiple-operation-time-out", MultipleOperationTimeout);
+
+ /* natural-language-configured (no IPP_TAG_COPY) */
+ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
+ "natural-language-configured", NULL, DefaultLanguage);
+
+ /* notify-attributes-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "notify-attributes-supported",
+ (int)(sizeof(notify_attrs) / sizeof(notify_attrs[0])),
+ NULL, notify_attrs);
+
+ /* notify-lease-duration-supported */
+ ippAddRange(CommonData, IPP_TAG_PRINTER,
+ "notify-lease-duration-supported", 0,
+ MaxLeaseDuration ? MaxLeaseDuration : 2147483647);
+
+ /* notify-max-events-supported */
+ ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "notify-max-events-supported", MaxEvents);
+
+ /* notify-events-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "notify-events-supported",
+ (int)(sizeof(notify_events) / sizeof(notify_events[0])),
+ NULL, notify_events);
+
+ /* notify-pull-method-supported */
+ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "notify-pull-method-supported", NULL, "ippget");
+
+ /* notify-schemes-supported */
+ snprintf(filename, sizeof(filename), "%s/notifier", ServerBin);
+ if ((dir = cupsDirOpen(filename)) != NULL)
+ {
+ notifiers = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+
+ while ((dent = cupsDirRead(dir)) != NULL)
+ if (S_ISREG(dent->fileinfo.st_mode) &&
+ (dent->fileinfo.st_mode & S_IXOTH) != 0)
+ cupsArrayAdd(notifiers, _cupsStrAlloc(dent->filename));
+
+ if (cupsArrayCount(notifiers) > 0)
+ {
+ attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "notify-schemes-supported",
+ cupsArrayCount(notifiers), NULL, NULL);
+
+ for (i = 0, notifier = (char *)cupsArrayFirst(notifiers);
+ notifier;
+ i ++, notifier = (char *)cupsArrayNext(notifiers))
+ attr->values[i].string.text = notifier;
+ }
+
+ cupsArrayDelete(notifiers);
+ cupsDirClose(dir);
+ }
+
+ /* number-up-supported */
+ ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "number-up-supported", sizeof(nups) / sizeof(nups[0]), nups);
+
+ /* operations-supported */
+ ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "operations-supported",
+ sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, ops);
+
+ /* orientation-requested-supported */
+ ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "orientation-requested-supported", 4, orients);
+
+ /* page-ranges-supported */
+ ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1);
+
+ /* pdf-k-octets-supported */
+ ippAddRange(CommonData, IPP_TAG_PRINTER, "pdf-k-octets-supported", 0,
+ k_supported);
+
+ /* pdf-versions-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "pdf-versions-supported",
+ sizeof(pdf_versions) / sizeof(pdf_versions[0]), NULL,
+ pdf_versions);
+
+ /* pdl-override-supported */
+ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "pdl-override-supported", NULL, "attempted");
+
+ /* printer-op-policy-supported */
+ attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
+ "printer-op-policy-supported", cupsArrayCount(Policies),
+ NULL, NULL);
+ for (i = 0, p = (cupsd_policy_t *)cupsArrayFirst(Policies);
+ p;
+ i ++, p = (cupsd_policy_t *)cupsArrayNext(Policies))
+ attr->values[i].string.text = p->name;
+
+ /* printer-settable-attributes-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "printer-settable-attributes-supported",
+ sizeof(printer_settable) / sizeof(printer_settable[0]),
+ NULL, printer_settable);
+
+ /* server-is-sharing-printers */
+ ippAddBoolean(CommonData, IPP_TAG_PRINTER, "server-is-sharing-printers",
+ BrowseLocalProtocols != 0 && Browsing);
+
+ /* which-jobs-supported */
+ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "which-jobs-supported",
+ sizeof(which_jobs) / sizeof(which_jobs[0]), NULL, which_jobs);
+}
+
+
+/*
+ * 'cupsdDeleteAllPrinters()' - Delete all printers from the system.
+ */
+
+void
+cupsdDeleteAllPrinters(void)
+{
+ cupsd_printer_t *p; /* Pointer to current printer/class */
+
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ p->op_policy_ptr = DefaultPolicyPtr;
+ cupsdDeletePrinter(p, 0);
+ }
+}
+
+
+/*
+ * 'cupsdDeletePrinter()' - Delete a printer from the system.
+ */
+
+int /* O - 1 if classes affected, 0 otherwise */
+cupsdDeletePrinter(
+ cupsd_printer_t *p, /* I - Printer to delete */
+ int update) /* I - Update printers.conf? */
+{
+ int i, /* Looping var */
+ changed = 0; /* Class changed? */
+#ifdef __sgi
+ char filename[1024]; /* Interface script filename */
+#endif /* __sgi */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeletePrinter(p=%p(%s), update=%d)",
+ p, p->name, update);
+
+ /*
+ * Save the current position in the Printers array...
+ */
+
+ cupsArraySave(Printers);
+
+ /*
+ * Stop printing on this printer...
+ */
+
+ cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update);
+
+ p->state = IPP_PRINTER_STOPPED; /* Force for browsed printers */
+
+ if (p->job)
+ cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE,
+ update ? "Job stopped due to printer being deleted." :
+ "Job stopped.");
+
+ /*
+ * If this printer is the next for browsing, point to the next one...
+ */
+
+ if (p == BrowseNext)
+ {
+ cupsArrayFind(Printers, p);
+ BrowseNext = (cupsd_printer_t *)cupsArrayNext(Printers);
+ }
+
+ /*
+ * Remove the printer from the list...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdDeletePrinter: Removing %s from Printers", p->name);
+ cupsArrayRemove(Printers, p);
+
+ if (p->type & CUPS_PRINTER_IMPLICIT)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdDeletePrinter: Removing %s from ImplicitPrinters",
+ p->name);
+ cupsArrayRemove(ImplicitPrinters, p);
+ }
+
+ /*
+ * Remove the dummy interface/icon/option files under IRIX...
+ */
+
+#ifdef __sgi
+ snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
+ unlink(filename);
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui",
+ p->name);
+ unlink(filename);
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
+ unlink(filename);
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
+ unlink(filename);
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
+ unlink(filename);
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
+ unlink(filename);
+#endif /* __sgi */
+
+ /*
+ * If p is the default printer, assign a different one...
+ */
+
+ if (p == DefaultPrinter)
+ {
+ DefaultPrinter = NULL;
+
+ if (UseNetworkDefault)
+ {
+ /*
+ * Find the first network default printer and use it...
+ */
+
+ cupsd_printer_t *dp; /* New default printer */
+
+
+ for (dp = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ dp;
+ dp = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (dp != p && (dp->type & CUPS_PRINTER_DEFAULT))
+ {
+ DefaultPrinter = dp;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Remove this printer from any classes...
+ */
+
+ if (!(p->type & CUPS_PRINTER_IMPLICIT))
+ {
+ changed = cupsdDeletePrinterFromClasses(p);
+
+ /*
+ * Deregister from any browse protocols...
+ */
+
+ cupsdDeregisterPrinter(p, 1);
+ }
+
+ /*
+ * Free all memory used by the printer...
+ */
+
+ if (p->printers != NULL)
+ free(p->printers);
+
+ delete_printer_filters(p);
+
+ for (i = 0; i < p->num_reasons; i ++)
+ _cupsStrFree(p->reasons[i]);
+
+ ippDelete(p->attrs);
+ ippDelete(p->ppd_attrs);
+
+ mimeDeleteType(MimeDatabase, p->filetype);
+ mimeDeleteType(MimeDatabase, p->prefiltertype);
+
+ cupsdFreeStrings(&(p->users));
+ cupsdFreeQuotas(p);
+
+ cupsdClearString(&p->uri);
+ cupsdClearString(&p->hostname);
+ cupsdClearString(&p->name);
+ cupsdClearString(&p->location);
+ cupsdClearString(&p->make_model);
+ cupsdClearString(&p->info);
+ cupsdClearString(&p->job_sheets[0]);
+ cupsdClearString(&p->job_sheets[1]);
+ cupsdClearString(&p->device_uri);
+ cupsdClearString(&p->sanitized_device_uri);
+ cupsdClearString(&p->port_monitor);
+ cupsdClearString(&p->op_policy);
+ cupsdClearString(&p->error_policy);
+
+ cupsdClearString(&p->alert);
+ cupsdClearString(&p->alert_description);
+
+#ifdef HAVE_DNSSD
+ cupsdClearString(&p->pdl);
+#endif /* HAVE_DNSSD */
+
+ cupsArrayDelete(p->filetypes);
+
+ if (p->browse_attrs)
+ free(p->browse_attrs);
+
+ cupsFreeOptions(p->num_options, p->options);
+
+ free(p);
+
+ /*
+ * Restore the previous position in the Printers array...
+ */
+
+ cupsArrayRestore(Printers);
+
+ return (changed);
+}
+
+
+/*
+ * 'cupsdFindDest()' - Find a destination in the list.
+ */
+
+cupsd_printer_t * /* O - Destination in list */
+cupsdFindDest(const char *name) /* I - Name of printer or class to find */
+{
+ cupsd_printer_t key; /* Search key */
+
+
+ key.name = (char *)name;
+ return ((cupsd_printer_t *)cupsArrayFind(Printers, &key));
+}
+
+
+/*
+ * 'cupsdFindPrinter()' - Find a printer in the list.
+ */
+
+cupsd_printer_t * /* O - Printer in list */
+cupsdFindPrinter(const char *name) /* I - Name of printer to find */
+{
+ cupsd_printer_t *p; /* Printer in list */
+
+
+ if ((p = cupsdFindDest(name)) != NULL && (p->type & CUPS_PRINTER_CLASS))
+ return (NULL);
+ else
+ return (p);
+}
+
+
+/*
+ * 'cupsdLoadAllPrinters()' - Load printers from the printers.conf file.
+ */
+
+void
+cupsdLoadAllPrinters(void)
+{
+ int i; /* Looping var */
+ cups_file_t *fp; /* printers.conf file */
+ int linenum; /* Current line number */
+ char line[4096], /* Line from file */
+ *value, /* Pointer to value */
+ *valueptr; /* Pointer into value */
+ cupsd_printer_t *p; /* Current printer */
+
+
+ /*
+ * Open the printers.conf file...
+ */
+
+ snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot);
+ if ((fp = cupsdOpenConfFile(line)) == NULL)
+ return;
+
+ /*
+ * Read printer configurations until we hit EOF...
+ */
+
+ linenum = 0;
+ p = NULL;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ /*
+ * Decode the directive...
+ */
+
+ if (!_cups_strcasecmp(line, "<Printer") ||
+ !_cups_strcasecmp(line, "<DefaultPrinter"))
+ {
+ /*
+ * <Printer name> or <DefaultPrinter name>
+ */
+
+ if (p == NULL && value)
+ {
+ /*
+ * Add the printer and a base file type...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading printer %s...", value);
+
+ p = cupsdAddPrinter(value);
+ p->accepting = 1;
+ p->state = IPP_PRINTER_IDLE;
+
+ /*
+ * Set the default printer as needed...
+ */
+
+ if (!_cups_strcasecmp(line, "<DefaultPrinter"))
+ DefaultPrinter = p;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "</Printer>"))
+ {
+ if (p != NULL)
+ {
+ /*
+ * Close out the current printer...
+ */
+
+ cupsdSetPrinterAttrs(p);
+
+ if (strncmp(p->device_uri, "file:", 5) &&
+ p->state != IPP_PRINTER_STOPPED)
+ {
+ /*
+ * See if the backend exists...
+ */
+
+ snprintf(line, sizeof(line), "%s/backend/%s", ServerBin,
+ p->device_uri);
+
+ if ((valueptr = strchr(line + strlen(ServerBin), ':')) != NULL)
+ *valueptr = '\0'; /* Chop everything but URI scheme */
+
+ if (access(line, 0))
+ {
+ /*
+ * Backend does not exist, stop printer...
+ */
+
+ p->state = IPP_PRINTER_STOPPED;
+ snprintf(p->state_message, sizeof(p->state_message),
+ "Backend %s does not exist!", line);
+ }
+ }
+
+ p = NULL;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!p)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "UUID"))
+ {
+ if (value && !strncmp(value, "urn:uuid:", 9))
+ cupsdSetString(&(p->uuid), value);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad UUID on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "AuthInfoRequired"))
+ {
+ if (!cupsdSetAuthInfoRequired(p, value, NULL))
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad AuthInfoRequired on line %d of printers.conf.",
+ linenum);
+ }
+ else if (!_cups_strcasecmp(line, "Info"))
+ {
+ if (value)
+ cupsdSetString(&p->info, value);
+ }
+ else if (!_cups_strcasecmp(line, "MakeModel"))
+ {
+ if (value)
+ cupsdSetString(&p->make_model, value);
+ }
+ else if (!_cups_strcasecmp(line, "Location"))
+ {
+ if (value)
+ cupsdSetString(&p->location, value);
+ }
+ else if (!_cups_strcasecmp(line, "DeviceURI"))
+ {
+ if (value)
+ cupsdSetDeviceURI(p, value);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "Option") && value)
+ {
+ /*
+ * Option name value
+ */
+
+ for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
+
+ if (!*valueptr)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ else
+ {
+ for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
+
+ p->num_options = cupsAddOption(value, valueptr, p->num_options,
+ &(p->options));
+ }
+ }
+ else if (!_cups_strcasecmp(line, "PortMonitor"))
+ {
+ if (value && strcmp(value, "none"))
+ cupsdSetString(&p->port_monitor, value);
+ else if (value)
+ cupsdClearString(&p->port_monitor);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "Reason"))
+ {
+ if (value &&
+ strcmp(value, "connecting-to-device") &&
+ strcmp(value, "cups-insecure-filter-warning") &&
+ strcmp(value, "cups-missing-filter-warning"))
+ {
+ for (i = 0 ; i < p->num_reasons; i ++)
+ if (!strcmp(value, p->reasons[i]))
+ break;
+
+ if (i >= p->num_reasons &&
+ p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
+ {
+ p->reasons[p->num_reasons] = _cupsStrAlloc(value);
+ p->num_reasons ++;
+ }
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "State"))
+ {
+ /*
+ * Set the initial queue state...
+ */
+
+ if (value && !_cups_strcasecmp(value, "idle"))
+ p->state = IPP_PRINTER_IDLE;
+ else if (value && !_cups_strcasecmp(value, "stopped"))
+ {
+ p->state = IPP_PRINTER_STOPPED;
+
+ for (i = 0 ; i < p->num_reasons; i ++)
+ if (!strcmp("paused", p->reasons[i]))
+ break;
+
+ if (i >= p->num_reasons &&
+ p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
+ {
+ p->reasons[p->num_reasons] = _cupsStrAlloc("paused");
+ p->num_reasons ++;
+ }
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "StateMessage"))
+ {
+ /*
+ * Set the initial queue state message...
+ */
+
+ if (value)
+ strlcpy(p->state_message, value, sizeof(p->state_message));
+ }
+ else if (!_cups_strcasecmp(line, "StateTime"))
+ {
+ /*
+ * Set the state time...
+ */
+
+ if (value)
+ p->state_time = atoi(value);
+ }
+ else if (!_cups_strcasecmp(line, "Accepting"))
+ {
+ /*
+ * Set the initial accepting state...
+ */
+
+ if (value &&
+ (!_cups_strcasecmp(value, "yes") ||
+ !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "true")))
+ p->accepting = 1;
+ else if (value &&
+ (!_cups_strcasecmp(value, "no") ||
+ !_cups_strcasecmp(value, "off") ||
+ !_cups_strcasecmp(value, "false")))
+ p->accepting = 0;
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "Type"))
+ {
+ if (value)
+ p->type = atoi(value);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "Shared"))
+ {
+ /*
+ * Set the initial shared state...
+ */
+
+ if (value &&
+ (!_cups_strcasecmp(value, "yes") ||
+ !_cups_strcasecmp(value, "on") ||
+ !_cups_strcasecmp(value, "true")))
+ p->shared = 1;
+ else if (value &&
+ (!_cups_strcasecmp(value, "no") ||
+ !_cups_strcasecmp(value, "off") ||
+ !_cups_strcasecmp(value, "false")))
+ p->shared = 0;
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "JobSheets"))
+ {
+ /*
+ * Set the initial job sheets...
+ */
+
+ if (value)
+ {
+ for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
+
+ if (*valueptr)
+ *valueptr++ = '\0';
+
+ cupsdSetString(&p->job_sheets[0], value);
+
+ while (isspace(*valueptr & 255))
+ valueptr ++;
+
+ if (*valueptr)
+ {
+ for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
+
+ if (*valueptr)
+ *valueptr = '\0';
+
+ cupsdSetString(&p->job_sheets[1], value);
+ }
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "AllowUser"))
+ {
+ if (value)
+ {
+ p->deny_users = 0;
+ cupsdAddString(&(p->users), value);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "DenyUser"))
+ {
+ if (value)
+ {
+ p->deny_users = 1;
+ cupsdAddString(&(p->users), value);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "QuotaPeriod"))
+ {
+ if (value)
+ p->quota_period = atoi(value);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "PageLimit"))
+ {
+ if (value)
+ p->page_limit = atoi(value);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "KLimit"))
+ {
+ if (value)
+ p->k_limit = atoi(value);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "OpPolicy"))
+ {
+ if (value)
+ {
+ cupsd_policy_t *pol; /* Policy */
+
+
+ if ((pol = cupsdFindPolicy(value)) != NULL)
+ {
+ cupsdSetString(&p->op_policy, value);
+ p->op_policy_ptr = pol;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad policy \"%s\" on line %d of printers.conf",
+ value, linenum);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "ErrorPolicy"))
+ {
+ if (value)
+ cupsdSetString(&p->error_policy, value);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ }
+ else if (!_cups_strcasecmp(line, "Attribute") && value)
+ {
+ for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
+
+ if (!*valueptr)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of printers.conf.", linenum);
+ else
+ {
+ for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
+
+ if (!p->attrs)
+ cupsdSetPrinterAttrs(p);
+
+ if (!strcmp(value, "marker-change-time"))
+ p->marker_time = atoi(valueptr);
+ else
+ cupsdSetPrinterAttr(p, value, valueptr);
+ }
+ }
+ else if (_cups_strcasecmp(line, "Filter") &&
+ _cups_strcasecmp(line, "Prefilter") &&
+ _cups_strcasecmp(line, "Product"))
+ {
+ /*
+ * Something else we don't understand (and that wasn't used in a prior
+ * release of CUPS...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown configuration directive %s on line %d of "
+ "printers.conf.", line, linenum);
+ }
+ }
+
+ cupsFileClose(fp);
+}
+
+
+/*
+ * 'cupsdRenamePrinter()' - Rename a printer.
+ */
+
+void
+cupsdRenamePrinter(
+ cupsd_printer_t *p, /* I - Printer */
+ const char *name) /* I - New name */
+{
+ /*
+ * Remove the printer from the array(s) first...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdRenamePrinter: Removing %s from Printers", p->name);
+ cupsArrayRemove(Printers, p);
+
+ if (p->type & CUPS_PRINTER_IMPLICIT)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdRenamePrinter: Removing %s from ImplicitPrinters",
+ p->name);
+ cupsArrayRemove(ImplicitPrinters, p);
+ }
+
+ /*
+ * Rename the printer type...
+ */
+
+ mimeDeleteType(MimeDatabase, p->filetype);
+ p->filetype = mimeAddType(MimeDatabase, "printer", name);
+
+ if (p->prefiltertype)
+ {
+ mimeDeleteType(MimeDatabase, p->prefiltertype);
+ p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name);
+ }
+
+ /*
+ * Rename the printer...
+ */
+
+ cupsdSetString(&p->name, name);
+
+ /*
+ * Reset printer attributes...
+ */
+
+ cupsdSetPrinterAttrs(p);
+
+ /*
+ * Add the printer back to the printer array(s)...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdRenamePrinter: Adding %s to Printers", p->name);
+ cupsArrayAdd(Printers, p);
+
+ if (p->type & CUPS_PRINTER_IMPLICIT)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdRenamePrinter: Adding %s to ImplicitPrinters",
+ p->name);
+ cupsArrayAdd(ImplicitPrinters, p);
+ }
+}
+
+
+/*
+ * 'cupsdSaveAllPrinters()' - Save all printer definitions to the printers.conf
+ * file.
+ */
+
+void
+cupsdSaveAllPrinters(void)
+{
+ int i; /* Looping var */
+ cups_file_t *fp; /* printers.conf file */
+ char filename[1024], /* printers.conf filename */
+ temp[1024], /* Temporary string */
+ value[2048], /* Value string */
+ *ptr, /* Pointer into value */
+ *name; /* Current user/group name */
+ cupsd_printer_t *printer; /* Current printer class */
+ time_t curtime; /* Current time */
+ struct tm *curdate; /* Current date */
+ cups_option_t *option; /* Current option */
+ ipp_attribute_t *marker; /* Current marker attribute */
+
+
+ /*
+ * Create the printers.conf file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/printers.conf", ServerRoot);
+
+ if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm & 0600)) == NULL)
+ return;
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Saving printers.conf...");
+
+ /*
+ * Write a small header to the file...
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+ strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
+
+ cupsFilePuts(fp, "# Printer configuration file for " CUPS_SVERSION "\n");
+ cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
+ cupsFilePuts(fp, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n");
+
+ /*
+ * Write each local printer known to the system...
+ */
+
+ for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ printer;
+ printer = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ /*
+ * Skip remote destinations and printer classes...
+ */
+
+ if ((printer->type & CUPS_PRINTER_DISCOVERED) ||
+ (printer->type & CUPS_PRINTER_CLASS) ||
+ (printer->type & CUPS_PRINTER_IMPLICIT))
+ continue;
+
+ /*
+ * Write printers as needed...
+ */
+
+ if (printer == DefaultPrinter)
+ cupsFilePrintf(fp, "<DefaultPrinter %s>\n", printer->name);
+ else
+ cupsFilePrintf(fp, "<Printer %s>\n", printer->name);
+
+ cupsFilePrintf(fp, "UUID %s\n", printer->uuid);
+
+ if (printer->num_auth_info_required > 0)
+ {
+ switch (printer->num_auth_info_required)
+ {
+ case 1 :
+ strlcpy(value, printer->auth_info_required[0], sizeof(value));
+ break;
+
+ case 2 :
+ snprintf(value, sizeof(value), "%s,%s",
+ printer->auth_info_required[0],
+ printer->auth_info_required[1]);
+ break;
+
+ case 3 :
+ default :
+ snprintf(value, sizeof(value), "%s,%s,%s",
+ printer->auth_info_required[0],
+ printer->auth_info_required[1],
+ printer->auth_info_required[2]);
+ break;
+ }
+
+ cupsFilePutConf(fp, "AuthInfoRequired", value);
+ }
+
+ if (printer->info)
+ cupsFilePutConf(fp, "Info", printer->info);
+
+ if (printer->location)
+ cupsFilePutConf(fp, "Location", printer->location);
+
+ if (printer->make_model)
+ cupsFilePutConf(fp, "MakeModel", printer->make_model);
+
+ cupsFilePutConf(fp, "DeviceURI", printer->device_uri);
+
+ if (printer->port_monitor)
+ cupsFilePutConf(fp, "PortMonitor", printer->port_monitor);
+
+ if (printer->state == IPP_PRINTER_STOPPED)
+ {
+ cupsFilePuts(fp, "State Stopped\n");
+
+ if (printer->state_message)
+ cupsFilePutConf(fp, "StateMessage", printer->state_message);
+ }
+ else
+ cupsFilePuts(fp, "State Idle\n");
+
+ cupsFilePrintf(fp, "StateTime %d\n", (int)printer->state_time);
+
+ for (i = 0; i < printer->num_reasons; i ++)
+ if (strcmp(printer->reasons[i], "connecting-to-device") &&
+ strcmp(printer->reasons[i], "cups-insecure-filter-warning") &&
+ strcmp(printer->reasons[i], "cups-missing-filter-warning"))
+ cupsFilePutConf(fp, "Reason", printer->reasons[i]);
+
+ cupsFilePrintf(fp, "Type %d\n", printer->type);
+
+ if (printer->accepting)
+ cupsFilePuts(fp, "Accepting Yes\n");
+ else
+ cupsFilePuts(fp, "Accepting No\n");
+
+ if (printer->shared)
+ cupsFilePuts(fp, "Shared Yes\n");
+ else
+ cupsFilePuts(fp, "Shared No\n");
+
+ snprintf(value, sizeof(value), "%s %s", printer->job_sheets[0],
+ printer->job_sheets[1]);
+ cupsFilePutConf(fp, "JobSheets", value);
+
+ cupsFilePrintf(fp, "QuotaPeriod %d\n", printer->quota_period);
+ cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit);
+ cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit);
+
+ for (name = (char *)cupsArrayFirst(printer->users);
+ name;
+ name = (char *)cupsArrayNext(printer->users))
+ cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", name);
+
+ if (printer->op_policy)
+ cupsFilePutConf(fp, "OpPolicy", printer->op_policy);
+ if (printer->error_policy)
+ cupsFilePutConf(fp, "ErrorPolicy", printer->error_policy);
+
+ for (i = printer->num_options, option = printer->options;
+ i > 0;
+ i --, option ++)
+ {
+ snprintf(value, sizeof(value), "%s %s", option->name, option->value);
+ cupsFilePutConf(fp, "Option", value);
+ }
+
+ if ((marker = ippFindAttribute(printer->attrs, "marker-colors",
+ IPP_TAG_NAME)) != NULL)
+ {
+ snprintf(value, sizeof(value), "%s ", marker->name);
+
+ for (i = 0, ptr = value + strlen(value);
+ i < marker->num_values && ptr < (value + sizeof(value) - 1);
+ i ++)
+ {
+ if (i)
+ *ptr++ = ',';
+
+ strlcpy(ptr, marker->values[i].string.text,
+ value + sizeof(value) - ptr);
+ ptr += strlen(ptr);
+ }
+
+ *ptr = '\0';
+ cupsFilePutConf(fp, "Attribute", value);
+ }
+
+ if ((marker = ippFindAttribute(printer->attrs, "marker-levels",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ cupsFilePrintf(fp, "Attribute %s %d", marker->name,
+ marker->values[0].integer);
+ for (i = 1; i < marker->num_values; i ++)
+ cupsFilePrintf(fp, ",%d", marker->values[i].integer);
+ cupsFilePuts(fp, "\n");
+ }
+
+ if ((marker = ippFindAttribute(printer->attrs, "marker-low-levels",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ cupsFilePrintf(fp, "Attribute %s %d", marker->name,
+ marker->values[0].integer);
+ for (i = 1; i < marker->num_values; i ++)
+ cupsFilePrintf(fp, ",%d", marker->values[i].integer);
+ cupsFilePuts(fp, "\n");
+ }
+
+ if ((marker = ippFindAttribute(printer->attrs, "marker-high-levels",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ cupsFilePrintf(fp, "Attribute %s %d", marker->name,
+ marker->values[0].integer);
+ for (i = 1; i < marker->num_values; i ++)
+ cupsFilePrintf(fp, ",%d", marker->values[i].integer);
+ cupsFilePuts(fp, "\n");
+ }
+
+ if ((marker = ippFindAttribute(printer->attrs, "marker-message",
+ IPP_TAG_TEXT)) != NULL)
+ {
+ snprintf(value, sizeof(value), "%s %s", marker->name,
+ marker->values[0].string.text);
+
+ cupsFilePutConf(fp, "Attribute", value);
+ }
+
+ if ((marker = ippFindAttribute(printer->attrs, "marker-names",
+ IPP_TAG_NAME)) != NULL)
+ {
+ snprintf(value, sizeof(value), "%s ", marker->name);
+
+ for (i = 0, ptr = value + strlen(value);
+ i < marker->num_values && ptr < (value + sizeof(value) - 1);
+ i ++)
+ {
+ if (i)
+ *ptr++ = ',';
+
+ strlcpy(ptr, marker->values[i].string.text,
+ value + sizeof(value) - ptr);
+ ptr += strlen(ptr);
+ }
+
+ *ptr = '\0';
+ cupsFilePutConf(fp, "Attribute", value);
+ }
+
+ if ((marker = ippFindAttribute(printer->attrs, "marker-types",
+ IPP_TAG_KEYWORD)) != NULL)
+ {
+ snprintf(value, sizeof(value), "%s ", marker->name);
+
+ for (i = 0, ptr = value + strlen(value);
+ i < marker->num_values && ptr < (value + sizeof(value) - 1);
+ i ++)
+ {
+ if (i)
+ *ptr++ = ',';
+
+ strlcpy(ptr, marker->values[i].string.text,
+ value + sizeof(value) - ptr);
+ ptr += strlen(ptr);
+ }
+
+ *ptr = '\0';
+ cupsFilePutConf(fp, "Attribute", value);
+ }
+
+ if (printer->marker_time)
+ cupsFilePrintf(fp, "Attribute marker-change-time %ld\n",
+ (long)printer->marker_time);
+
+ cupsFilePuts(fp, "</Printer>\n");
+
+#ifdef __sgi
+ /*
+ * Make IRIX desktop & printer status happy
+ */
+
+ write_irix_state(printer);
+#endif /* __sgi */
+ }
+
+ cupsdCloseCreatedConfFile(fp, filename);
+}
+
+
+/*
+ * 'cupsdSetAuthInfoRequired()' - Set the required authentication info.
+ */
+
+int /* O - 1 if value OK, 0 otherwise */
+cupsdSetAuthInfoRequired(
+ cupsd_printer_t *p, /* I - Printer */
+ const char *values, /* I - Plain text value (or NULL) */
+ ipp_attribute_t *attr) /* I - IPP attribute value (or NULL) */
+{
+ int i; /* Looping var */
+
+
+ p->num_auth_info_required = 0;
+
+ /*
+ * Do we have a plain text value?
+ */
+
+ if (values)
+ {
+ /*
+ * Yes, grab the keywords...
+ */
+
+ const char *end; /* End of current value */
+
+
+ while (*values && p->num_auth_info_required < 4)
+ {
+ if ((end = strchr(values, ',')) == NULL)
+ end = values + strlen(values);
+
+ if ((end - values) == 4 && !strncmp(values, "none", 4))
+ {
+ if (p->num_auth_info_required != 0 || *end)
+ return (0);
+
+ p->auth_info_required[p->num_auth_info_required] = "none";
+ p->num_auth_info_required ++;
+
+ return (1);
+ }
+ else if ((end - values) == 9 && !strncmp(values, "negotiate", 9))
+ {
+ if (p->num_auth_info_required != 0 || *end)
+ return (0);
+
+ p->auth_info_required[p->num_auth_info_required] = "negotiate";
+ p->num_auth_info_required ++;
+
+ /*
+ * Don't allow sharing of queues that require Kerberos authentication.
+ */
+
+ if (p->shared)
+ {
+ cupsdDeregisterPrinter(p, 1);
+ p->shared = 0;
+ }
+ }
+ else if ((end - values) == 6 && !strncmp(values, "domain", 6))
+ {
+ p->auth_info_required[p->num_auth_info_required] = "domain";
+ p->num_auth_info_required ++;
+ }
+ else if ((end - values) == 8 && !strncmp(values, "password", 8))
+ {
+ p->auth_info_required[p->num_auth_info_required] = "password";
+ p->num_auth_info_required ++;
+ }
+ else if ((end - values) == 8 && !strncmp(values, "username", 8))
+ {
+ p->auth_info_required[p->num_auth_info_required] = "username";
+ p->num_auth_info_required ++;
+ }
+ else
+ return (0);
+
+ values = (*end) ? end + 1 : end;
+ }
+
+ if (p->num_auth_info_required == 0)
+ {
+ p->auth_info_required[0] = "none";
+ p->num_auth_info_required = 1;
+ }
+
+ /*
+ * Update the printer-type value as needed...
+ */
+
+ if (p->num_auth_info_required > 1 ||
+ strcmp(p->auth_info_required[0], "none"))
+ p->type |= CUPS_PRINTER_AUTHENTICATED;
+ else
+ p->type &= ~CUPS_PRINTER_AUTHENTICATED;
+
+ return (1);
+ }
+
+ /*
+ * Grab values from an attribute instead...
+ */
+
+ if (!attr || attr->num_values > 4)
+ return (0);
+
+ /*
+ * Update the printer-type value as needed...
+ */
+
+ if (attr->num_values > 1 ||
+ strcmp(attr->values[0].string.text, "none"))
+ p->type |= CUPS_PRINTER_AUTHENTICATED;
+ else
+ p->type &= ~CUPS_PRINTER_AUTHENTICATED;
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (!strcmp(attr->values[i].string.text, "none"))
+ {
+ if (p->num_auth_info_required != 0 || attr->num_values != 1)
+ return (0);
+
+ p->auth_info_required[p->num_auth_info_required] = "none";
+ p->num_auth_info_required ++;
+
+ return (1);
+ }
+ else if (!strcmp(attr->values[i].string.text, "negotiate"))
+ {
+ if (p->num_auth_info_required != 0 || attr->num_values != 1)
+ return (0);
+
+ p->auth_info_required[p->num_auth_info_required] = "negotiate";
+ p->num_auth_info_required ++;
+
+ /*
+ * Don't allow sharing of queues that require Kerberos authentication.
+ */
+
+ if (p->shared)
+ {
+ cupsdDeregisterPrinter(p, 1);
+ p->shared = 0;
+ }
+
+ return (1);
+ }
+ else if (!strcmp(attr->values[i].string.text, "domain"))
+ {
+ p->auth_info_required[p->num_auth_info_required] = "domain";
+ p->num_auth_info_required ++;
+ }
+ else if (!strcmp(attr->values[i].string.text, "password"))
+ {
+ p->auth_info_required[p->num_auth_info_required] = "password";
+ p->num_auth_info_required ++;
+ }
+ else if (!strcmp(attr->values[i].string.text, "username"))
+ {
+ p->auth_info_required[p->num_auth_info_required] = "username";
+ p->num_auth_info_required ++;
+ }
+ else
+ return (0);
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'cupsdSetDeviceURI()' - Set the device URI for a printer.
+ */
+
+void
+cupsdSetDeviceURI(cupsd_printer_t *p, /* I - Printer */
+ const char *uri) /* I - Device URI */
+{
+ char buffer[1024], /* URI buffer */
+ *start, /* Start of data after scheme */
+ *slash, /* First slash after scheme:// */
+ *ptr; /* Pointer into user@host:port part */
+
+
+ /*
+ * Set the full device URI..
+ */
+
+ cupsdSetString(&(p->device_uri), uri);
+
+ /*
+ * Copy the device URI to a temporary buffer so we can sanitize any auth
+ * info in it...
+ */
+
+ strlcpy(buffer, uri, sizeof(buffer));
+
+ /*
+ * Find the end of the scheme:// part...
+ */
+
+ if ((ptr = strchr(buffer, ':')) != NULL)
+ {
+ for (start = ptr + 1; *start; start ++)
+ if (*start != '/')
+ break;
+
+ /*
+ * Find the next slash (/) in the URI...
+ */
+
+ if ((slash = strchr(start, '/')) == NULL)
+ slash = start + strlen(start); /* No slash, point to the end */
+
+ /*
+ * Check for an @ sign before the slash...
+ */
+
+ if ((ptr = strchr(start, '@')) != NULL && ptr < slash)
+ {
+ /*
+ * Found an @ sign and it is before the resource part, so we have
+ * an authentication string. Copy the remaining URI over the
+ * authentication string...
+ */
+
+ _cups_strcpy(start, ptr + 1);
+ }
+ }
+
+ /*
+ * Save the sanitized URI...
+ */
+
+ cupsdSetString(&(p->sanitized_device_uri), buffer);
+}
+
+
+/*
+ * 'cupsdSetPrinterAttr()' - Set a printer attribute.
+ */
+
+void
+cupsdSetPrinterAttr(
+ cupsd_printer_t *p, /* I - Printer */
+ const char *name, /* I - Attribute name */
+ char *value) /* I - Attribute value string */
+{
+ ipp_attribute_t *attr; /* Attribute */
+ int i, /* Looping var */
+ count; /* Number of values */
+ char *ptr; /* Pointer into value */
+ ipp_tag_t value_tag; /* Value tag for this attribute */
+
+
+ /*
+ * Don't allow empty values...
+ */
+
+ if (!*value && strcmp(name, "marker-message"))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Ignoring empty \"%s\" attribute", name);
+ return;
+ }
+
+ /*
+ * Count the number of values...
+ */
+
+ for (count = 1, ptr = value;
+ (ptr = strchr(ptr, ',')) != NULL;
+ ptr ++, count ++);
+
+ /*
+ * Then add or update the attribute as needed...
+ */
+
+ if (!strcmp(name, "marker-levels") || !strcmp(name, "marker-low-levels") ||
+ !strcmp(name, "marker-high-levels"))
+ {
+ /*
+ * Integer values...
+ */
+
+ if ((attr = ippFindAttribute(p->attrs, name, IPP_TAG_INTEGER)) != NULL &&
+ attr->num_values < count)
+ {
+ ippDeleteAttribute(p->attrs, attr);
+ attr = NULL;
+ }
+
+ if (attr)
+ attr->num_values = count;
+ else
+ attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, name,
+ count, NULL);
+
+ if (!attr)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for printer attribute "
+ "(%d values)", count);
+ return;
+ }
+
+ for (i = 0; i < count; i ++)
+ {
+ if ((ptr = strchr(value, ',')) != NULL)
+ *ptr++ = '\0';
+
+ attr->values[i].integer = strtol(value, NULL, 10);
+
+ if (ptr)
+ value = ptr;
+ }
+ }
+ else
+ {
+ /*
+ * Name or keyword values...
+ */
+
+ if (!strcmp(name, "marker-types"))
+ value_tag = IPP_TAG_KEYWORD;
+ else if (!strcmp(name, "marker-message"))
+ value_tag = IPP_TAG_TEXT;
+ else
+ value_tag = IPP_TAG_NAME;
+
+ if ((attr = ippFindAttribute(p->attrs, name, value_tag)) != NULL &&
+ attr->num_values < count)
+ {
+ ippDeleteAttribute(p->attrs, attr);
+ attr = NULL;
+ }
+
+ if (attr)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ _cupsStrFree(attr->values[i].string.text);
+
+ attr->num_values = count;
+ }
+ else
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, value_tag, name,
+ count, NULL, NULL);
+
+ if (!attr)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate memory for printer attribute "
+ "(%d values)", count);
+ return;
+ }
+
+ for (i = 0; i < count; i ++)
+ {
+ if ((ptr = strchr(value, ',')) != NULL)
+ *ptr++ = '\0';
+
+ attr->values[i].string.text = _cupsStrAlloc(value);
+
+ if (ptr)
+ value = ptr;
+ }
+ }
+}
+
+
+/*
+ * 'cupsdSetPrinterAttrs()' - Set printer attributes based upon the PPD file.
+ */
+
+void
+cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
+{
+ int i, /* Looping var */
+ length; /* Length of browse attributes */
+ char resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int num_air; /* Number of auth-info-required values */
+ const char * const *air; /* auth-info-required values */
+ cupsd_location_t *auth; /* Pointer to authentication element */
+ const char *auth_supported; /* Authentication supported */
+ ipp_t *oldattrs; /* Old printer attributes */
+ ipp_attribute_t *attr; /* Attribute data */
+ cups_option_t *option; /* Current printer option */
+ char *name, /* Current user/group name */
+ *filter; /* Current filter */
+ static const char * const air_none[] =
+ { /* No authentication */
+ "none"
+ };
+ static const char * const air_userpass[] =
+ { /* Basic/Digest authentication */
+ "username",
+ "password"
+ };
+
+
+ DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name,
+ p->type));
+
+ /*
+ * Make sure that we have the common attributes defined...
+ */
+
+ if (!CommonData)
+ cupsdCreateCommonData();
+
+ /*
+ * Clear out old filters, if any...
+ */
+
+ delete_printer_filters(p);
+
+ /*
+ * Figure out the authentication that is required for the printer.
+ */
+
+ auth_supported = "requesting-user-name";
+ num_air = 1;
+ air = air_none;
+
+ if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none"))
+ {
+ num_air = p->num_auth_info_required;
+ air = p->auth_info_required;
+ }
+ else if ((p->type & CUPS_PRINTER_AUTHENTICATED) &&
+ (p->type & CUPS_PRINTER_DISCOVERED))
+ {
+ num_air = 2;
+ air = air_userpass;
+ }
+
+ if (p->type & CUPS_PRINTER_CLASS)
+ snprintf(resource, sizeof(resource), "/classes/%s", p->name);
+ else
+ snprintf(resource, sizeof(resource), "/printers/%s", p->name);
+
+ if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
+ auth->type == CUPSD_AUTH_NONE)
+ auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
+
+ if (auth)
+ {
+ int auth_type; /* Authentication type */
+
+
+ if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
+ auth_type = DefaultAuthType;
+
+ if (auth_type == CUPSD_AUTH_BASIC || auth_type == CUPSD_AUTH_BASICDIGEST)
+ auth_supported = "basic";
+ else if (auth_type == CUPSD_AUTH_DIGEST)
+ auth_supported = "digest";
+#ifdef HAVE_GSSAPI
+ else if (auth_type == CUPSD_AUTH_NEGOTIATE)
+ auth_supported = "negotiate";
+#endif /* HAVE_GSSAPI */
+
+ if (!(p->type & CUPS_PRINTER_DISCOVERED))
+ {
+ if (auth_type != CUPSD_AUTH_NONE)
+ p->type |= CUPS_PRINTER_AUTHENTICATED;
+ else
+ p->type &= ~CUPS_PRINTER_AUTHENTICATED;
+ }
+ }
+ else if (!(p->type & CUPS_PRINTER_DISCOVERED))
+ p->type &= ~CUPS_PRINTER_AUTHENTICATED;
+
+ /*
+ * Create the required IPP attributes for a printer...
+ */
+
+ oldattrs = p->attrs;
+ p->attrs = ippNew();
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "uri-authentication-supported", NULL, auth_supported);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "uri-security-supported", NULL, "none");
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL,
+ p->name);
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
+ NULL, p->location ? p->location : "");
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
+ NULL, p->info ? p->info : "");
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uuid", NULL,
+ p->uuid);
+
+ if (cupsArrayCount(p->users) > 0)
+ {
+ if (p->deny_users)
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "requesting-user-name-denied",
+ cupsArrayCount(p->users), NULL, NULL);
+ else
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "requesting-user-name-allowed",
+ cupsArrayCount(p->users), NULL, NULL);
+
+ for (i = 0, name = (char *)cupsArrayFirst(p->users);
+ name;
+ i ++, name = (char *)cupsArrayNext(p->users))
+ attr->values[i].string.text = _cupsStrRetain(name);
+ }
+
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-quota-period", p->quota_period);
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-k-limit", p->k_limit);
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-page-limit", p->page_limit);
+ ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "auth-info-required", num_air, NULL, air);
+
+ if (cupsArrayCount(Banners) > 0 && !(p->type & CUPS_PRINTER_DISCOVERED))
+ {
+ /*
+ * Setup the job-sheets-default attribute...
+ */
+
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "job-sheets-default", 2, NULL, NULL);
+
+ if (attr != NULL)
+ {
+ attr->values[0].string.text = _cupsStrAlloc(Classification ?
+ Classification : p->job_sheets[0]);
+ attr->values[1].string.text = _cupsStrAlloc(Classification ?
+ Classification : p->job_sheets[1]);
+ }
+ }
+
+ p->raw = 0;
+ p->remote = 0;
+
+ if (p->type & CUPS_PRINTER_DISCOVERED)
+ {
+ /*
+ * Tell the client this is a remote printer of some type...
+ */
+
+ if (strchr(p->uri, '?'))
+ {
+ /*
+ * Strip trailing "?options" from URI...
+ */
+
+ char *ptr; /* Pointer into URI */
+
+ strlcpy(resource, p->uri, sizeof(resource));
+ if ((ptr = strchr(resource, '?')) != NULL)
+ *ptr = '\0';
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "printer-uri-supported", NULL, resource);
+ }
+ else
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "printer-uri-supported", NULL, p->uri);
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info",
+ NULL, p->uri);
+
+ if (p->make_model)
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, p->make_model);
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
+ p->uri);
+
+ p->raw = 1;
+ p->remote = 1;
+ }
+ else
+ {
+ /*
+ * Assign additional attributes depending on whether this is a printer
+ * or class...
+ */
+
+ if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ {
+ p->raw = 1;
+ p->type &= ~CUPS_PRINTER_OPTIONS;
+
+ /*
+ * Add class-specific attributes...
+ */
+
+ if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0 &&
+ p->printers[0]->make_model)
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, p->printers[0]->make_model);
+ else
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, "Local Printer Class");
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
+ "file:///dev/null");
+
+ if (p->num_printers > 0)
+ {
+ /*
+ * Add a list of member names; URIs are added in copy_printer_attrs...
+ */
+
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "member-names", p->num_printers, NULL, NULL);
+ p->type |= CUPS_PRINTER_OPTIONS;
+
+ for (i = 0; i < p->num_printers; i ++)
+ {
+ if (attr != NULL)
+ attr->values[i].string.text = _cupsStrRetain(p->printers[i]->name);
+
+ p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Add printer-specific attributes...
+ */
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
+ p->sanitized_device_uri);
+
+ /*
+ * Assign additional attributes from the PPD file (if any)...
+ */
+
+ load_ppd(p);
+
+ /*
+ * Add filters for printer...
+ */
+
+ cupsdSetPrinterReasons(p, "-cups-missing-filter-warning,"
+ "cups-insecure-filter-warning");
+
+ if (p->pc && p->pc->filters)
+ {
+ for (filter = (char *)cupsArrayFirst(p->pc->filters);
+ filter;
+ filter = (char *)cupsArrayNext(p->pc->filters))
+ add_printer_filter(p, p->filetype, filter);
+ }
+ else if (!(p->type & CUPS_PRINTER_REMOTE))
+ {
+ char interface[1024]; /* Interface script */
+
+
+ snprintf(interface, sizeof(interface), "%s/interfaces/%s", ServerRoot,
+ p->name);
+ if (!access(interface, X_OK))
+ {
+ /*
+ * Yes, we have a System V style interface script; use it!
+ */
+
+ snprintf(interface, sizeof(interface), "*/* 0 %s/interfaces/%s",
+ ServerRoot, p->name);
+ add_printer_filter(p, p->filetype, interface);
+ }
+ else
+ {
+ /*
+ * Add a filter from application/vnd.cups-raw to printer/name to
+ * handle "raw" printing by users.
+ */
+
+ add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
+
+ /*
+ * Add a PostScript filter, since this is still possibly PS printer.
+ */
+
+ add_printer_filter(p, p->filetype,
+ "application/vnd.cups-postscript 0 -");
+ }
+ }
+
+ if (p->pc && p->pc->prefilters)
+ {
+ if (!p->prefiltertype)
+ p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name);
+
+ for (filter = (char *)cupsArrayFirst(p->pc->prefilters);
+ filter;
+ filter = (char *)cupsArrayNext(p->pc->prefilters))
+ add_printer_filter(p, p->prefiltertype, filter);
+ }
+ }
+ }
+
+ /*
+ * Copy marker attributes as needed...
+ */
+
+ if (oldattrs)
+ {
+ ipp_attribute_t *oldattr; /* Old attribute */
+
+
+ if ((oldattr = ippFindAttribute(oldattrs, "marker-colors",
+ IPP_TAG_NAME)) != NULL)
+ {
+ if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "marker-colors", oldattr->num_values, NULL,
+ NULL)) != NULL)
+ {
+ for (i = 0; i < oldattr->num_values; i ++)
+ attr->values[i].string.text =
+ _cupsStrRetain(oldattr->values[i].string.text);
+ }
+ }
+
+ if ((oldattr = ippFindAttribute(oldattrs, "marker-levels",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "marker-levels", oldattr->num_values,
+ NULL)) != NULL)
+ {
+ for (i = 0; i < oldattr->num_values; i ++)
+ attr->values[i].integer = oldattr->values[i].integer;
+ }
+ }
+
+ if ((oldattr = ippFindAttribute(oldattrs, "marker-message",
+ IPP_TAG_TEXT)) != NULL)
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "marker-message",
+ NULL, oldattr->values[0].string.text);
+
+ if ((oldattr = ippFindAttribute(oldattrs, "marker-low-levels",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "marker-low-levels", oldattr->num_values,
+ NULL)) != NULL)
+ {
+ for (i = 0; i < oldattr->num_values; i ++)
+ attr->values[i].integer = oldattr->values[i].integer;
+ }
+ }
+
+ if ((oldattr = ippFindAttribute(oldattrs, "marker-high-levels",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "marker-high-levels", oldattr->num_values,
+ NULL)) != NULL)
+ {
+ for (i = 0; i < oldattr->num_values; i ++)
+ attr->values[i].integer = oldattr->values[i].integer;
+ }
+ }
+
+ if ((oldattr = ippFindAttribute(oldattrs, "marker-names",
+ IPP_TAG_NAME)) != NULL)
+ {
+ if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "marker-names", oldattr->num_values, NULL,
+ NULL)) != NULL)
+ {
+ for (i = 0; i < oldattr->num_values; i ++)
+ attr->values[i].string.text =
+ _cupsStrRetain(oldattr->values[i].string.text);
+ }
+ }
+
+ if ((oldattr = ippFindAttribute(oldattrs, "marker-types",
+ IPP_TAG_KEYWORD)) != NULL)
+ {
+ if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "marker-types", oldattr->num_values, NULL,
+ NULL)) != NULL)
+ {
+ for (i = 0; i < oldattr->num_values; i ++)
+ attr->values[i].string.text =
+ _cupsStrRetain(oldattr->values[i].string.text);
+ }
+ }
+
+ ippDelete(oldattrs);
+ }
+
+ /*
+ * Force sharing off for remote queues...
+ */
+
+ if (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))
+ p->shared = 0;
+ else
+ {
+ /*
+ * Copy the printer options into a browse attributes string we can re-use.
+ */
+
+ const char *valptr; /* Pointer into value */
+ char *attrptr; /* Pointer into attribute string */
+
+
+ /*
+ * Free the old browse attributes as needed...
+ */
+
+ if (p->browse_attrs)
+ free(p->browse_attrs);
+
+ /*
+ * Compute the length of all attributes + job-sheets, lease-duration,
+ * and BrowseLocalOptions.
+ */
+
+ for (length = 1, i = p->num_options, option = p->options;
+ i > 0;
+ i --, option ++)
+ {
+ length += strlen(option->name) + 2;
+
+ if (option->value)
+ {
+ for (valptr = option->value; *valptr; valptr ++)
+ if (strchr(" \"\'\\", *valptr))
+ length += 2;
+ else
+ length ++;
+ }
+ }
+
+ length += 13 + strlen(p->job_sheets[0]) + strlen(p->job_sheets[1]);
+ length += 32;
+ if (BrowseLocalOptions)
+ length += 12 + strlen(BrowseLocalOptions);
+
+ /*
+ * Allocate the new string...
+ */
+
+ if ((p->browse_attrs = calloc(1, length)) == NULL)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to allocate %d bytes for browse data!",
+ length);
+ else
+ {
+ /*
+ * Got the allocated string, now copy the options and attributes over...
+ */
+
+ sprintf(p->browse_attrs, "job-sheets=%s,%s lease-duration=%d",
+ p->job_sheets[0], p->job_sheets[1], BrowseTimeout);
+ attrptr = p->browse_attrs + strlen(p->browse_attrs);
+
+ if (BrowseLocalOptions)
+ {
+ sprintf(attrptr, " ipp-options=%s", BrowseLocalOptions);
+ attrptr += strlen(attrptr);
+ }
+
+ for (i = p->num_options, option = p->options;
+ i > 0;
+ i --, option ++)
+ {
+ *attrptr++ = ' ';
+ strcpy(attrptr, option->name);
+ attrptr += strlen(attrptr);
+
+ if (option->value)
+ {
+ *attrptr++ = '=';
+
+ for (valptr = option->value; *valptr; valptr ++)
+ {
+ if (strchr(" \"\'\\", *valptr))
+ *attrptr++ = '\\';
+
+ *attrptr++ = *valptr;
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Populate the document-format-supported attribute...
+ */
+
+ add_printer_formats(p);
+
+ DEBUG_printf(("cupsdSetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
+ p->type));
+
+ /*
+ * Add name-default attributes...
+ */
+
+ add_printer_defaults(p);
+
+#ifdef __sgi
+ /*
+ * Write the IRIX printer config and status files...
+ */
+
+ write_irix_config(p);
+ write_irix_state(p);
+#endif /* __sgi */
+
+ /*
+ * Let the browse protocols reflect the change
+ */
+
+ cupsdRegisterPrinter(p);
+}
+
+
+/*
+ * 'cupsdSetPrinterReasons()' - Set/update the reasons strings.
+ */
+
+int /* O - 1 if something changed, 0 otherwise */
+cupsdSetPrinterReasons(
+ cupsd_printer_t *p, /* I - Printer */
+ const char *s) /* I - Reasons strings */
+{
+ int i, /* Looping var */
+ changed = 0; /* Did something change? */
+ const char *sptr; /* Pointer into reasons */
+ char reason[255], /* Reason string */
+ *rptr; /* Pointer into reason */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdSetPrinterReasons(p=%p(%s),s=\"%s\"", p, p->name, s);
+
+ if (s[0] == '-' || s[0] == '+')
+ {
+ /*
+ * Add/remove reasons...
+ */
+
+ sptr = s + 1;
+ }
+ else
+ {
+ /*
+ * Replace reasons...
+ */
+
+ sptr = s;
+
+ for (i = 0; i < p->num_reasons; i ++)
+ _cupsStrFree(p->reasons[i]);
+
+ p->num_reasons = 0;
+ changed = 1;
+
+ dirty_printer(p);
+ }
+
+ if (!strcmp(s, "none"))
+ return (changed);
+
+ /*
+ * Loop through all of the reasons...
+ */
+
+ while (*sptr)
+ {
+ /*
+ * Skip leading whitespace and commas...
+ */
+
+ while (isspace(*sptr & 255) || *sptr == ',')
+ sptr ++;
+
+ for (rptr = reason; *sptr && !isspace(*sptr & 255) && *sptr != ','; sptr ++)
+ if (rptr < (reason + sizeof(reason) - 1))
+ *rptr++ = *sptr;
+
+ if (rptr == reason)
+ break;
+
+ *rptr = '\0';
+
+ if (s[0] == '-')
+ {
+ /*
+ * Remove reason...
+ */
+
+ for (i = 0; i < p->num_reasons; i ++)
+ if (!strcmp(reason, p->reasons[i]))
+ {
+ /*
+ * Found a match, so remove it...
+ */
+
+ p->num_reasons --;
+ changed = 1;
+ _cupsStrFree(p->reasons[i]);
+
+ if (i < p->num_reasons)
+ memmove(p->reasons + i, p->reasons + i + 1,
+ (p->num_reasons - i) * sizeof(char *));
+
+ if (!strcmp(reason, "paused") && p->state == IPP_PRINTER_STOPPED)
+ cupsdSetPrinterState(p, IPP_PRINTER_IDLE, 1);
+
+ if (strcmp(reason, "connecting-to-device"))
+ dirty_printer(p);
+ break;
+ }
+ }
+ else if (p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
+ {
+ /*
+ * Add reason...
+ */
+
+ for (i = 0; i < p->num_reasons; i ++)
+ if (!strcmp(reason, p->reasons[i]))
+ break;
+
+ if (i >= p->num_reasons)
+ {
+ if (i >= (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
+ {
+ cupsdLogMessage(CUPSD_LOG_ALERT,
+ "Too many printer-state-reasons values for %s (%d)",
+ p->name, i + 1);
+ return (changed);
+ }
+
+ p->reasons[i] = _cupsStrAlloc(reason);
+ p->num_reasons ++;
+ changed = 1;
+
+ if (!strcmp(reason, "paused") && p->state != IPP_PRINTER_STOPPED)
+ cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 1);
+
+ if (strcmp(reason, "connecting-to-device"))
+ dirty_printer(p);
+ }
+ }
+ }
+
+ return (changed);
+}
+
+
+/*
+ * 'cupsdSetPrinterState()' - Update the current state of a printer.
+ */
+
+void
+cupsdSetPrinterState(
+ cupsd_printer_t *p, /* I - Printer to change */
+ ipp_pstate_t s, /* I - New state */
+ int update) /* I - Update printers.conf? */
+{
+ ipp_pstate_t old_state; /* Old printer state */
+ static const char * const printer_states[] =
+ { /* State strings */
+ "idle",
+ "processing",
+ "stopped"
+ };
+
+
+ /*
+ * Can't set status of remote printers...
+ */
+
+ if (p->type & CUPS_PRINTER_DISCOVERED)
+ return;
+
+ /*
+ * Set the new state...
+ */
+
+ old_state = p->state;
+ p->state = s;
+
+ if (old_state != s)
+ {
+ cupsdAddEvent(s == IPP_PRINTER_STOPPED ? CUPSD_EVENT_PRINTER_STOPPED :
+ CUPSD_EVENT_PRINTER_STATE, p, NULL,
+ "%s \"%s\" state changed to %s.",
+ (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
+ p->name, printer_states[p->state - IPP_PRINTER_IDLE]);
+
+ /*
+ * Let the browse code know this needs to be updated...
+ */
+
+ BrowseNext = p;
+ p->state_time = time(NULL);
+ p->browse_time = 0;
+
+#ifdef __sgi
+ write_irix_state(p);
+#endif /* __sgi */
+ }
+
+ /*
+ * Set/clear the paused reason as needed...
+ */
+
+ if (s == IPP_PRINTER_STOPPED)
+ cupsdSetPrinterReasons(p, "+paused");
+ else
+ cupsdSetPrinterReasons(p, "-paused");
+
+ /*
+ * Clear the message for the queue when going to processing...
+ */
+
+ if (s == IPP_PRINTER_PROCESSING)
+ p->state_message[0] = '\0';
+
+ /*
+ * Let the browse protocols reflect the change...
+ */
+
+ if (update)
+ cupsdRegisterPrinter(p);
+
+ /*
+ * Save the printer configuration if a printer goes from idle or processing
+ * to stopped (or visa-versa)...
+ */
+
+ if (update &&
+ (old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED))
+ dirty_printer(p);
+}
+
+
+/*
+ * 'cupsdStopPrinter()' - Stop a printer from printing any jobs...
+ */
+
+void
+cupsdStopPrinter(cupsd_printer_t *p, /* I - Printer to stop */
+ int update)/* I - Update printers.conf? */
+{
+ /*
+ * Set the printer state...
+ */
+
+ cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update);
+
+ /*
+ * See if we have a job printing on this printer...
+ */
+
+ if (p->job && p->job->state_value == IPP_JOB_PROCESSING)
+ cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT,
+ "Job stopped due to printer being paused.");
+}
+
+
+/*
+ * 'cupsdUpdatePrinterPPD()' - Update keywords in a printer's PPD file.
+ */
+
+int /* O - 1 if successful, 0 otherwise */
+cupsdUpdatePrinterPPD(
+ cupsd_printer_t *p, /* I - Printer */
+ int num_keywords, /* I - Number of keywords */
+ cups_option_t *keywords) /* I - Keywords */
+{
+ int i; /* Looping var */
+ cups_file_t *src, /* Original file */
+ *dst; /* New file */
+ char srcfile[1024], /* Original filename */
+ dstfile[1024], /* New filename */
+ line[1024], /* Line from file */
+ keystring[41]; /* Keyword from line */
+ cups_option_t *keyword; /* Current keyword */
+
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Updating keywords in PPD file for %s...",
+ p->name);
+
+ /*
+ * Get the old and new PPD filenames...
+ */
+
+ snprintf(srcfile, sizeof(srcfile), "%s/ppd/%s.ppd.O", ServerRoot, p->name);
+ snprintf(dstfile, sizeof(srcfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
+
+ /*
+ * Rename the old file and open the old and new...
+ */
+
+ if (rename(dstfile, srcfile))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup PPD file for %s: %s",
+ p->name, strerror(errno));
+ return (0);
+ }
+
+ if ((src = cupsFileOpen(srcfile, "r")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open PPD file \"%s\": %s",
+ srcfile, strerror(errno));
+ rename(srcfile, dstfile);
+ return (0);
+ }
+
+ if ((dst = cupsFileOpen(dstfile, "w")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create PPD file \"%s\": %s",
+ dstfile, strerror(errno));
+ cupsFileClose(src);
+ rename(srcfile, dstfile);
+ return (0);
+ }
+
+ /*
+ * Copy the first line and then write out all of the keywords...
+ */
+
+ if (!cupsFileGets(src, line, sizeof(line)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to read PPD file \"%s\": %s",
+ srcfile, strerror(errno));
+ cupsFileClose(src);
+ cupsFileClose(dst);
+ rename(srcfile, dstfile);
+ return (0);
+ }
+
+ cupsFilePrintf(dst, "%s\n", line);
+
+ for (i = num_keywords, keyword = keywords; i > 0; i --, keyword ++)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "*%s: %s", keyword->name, keyword->value);
+ cupsFilePrintf(dst, "*%s: %s\n", keyword->name, keyword->value);
+ }
+
+ /*
+ * Then copy the rest of the PPD file, dropping any keywords we changed.
+ */
+
+ while (cupsFileGets(src, line, sizeof(line)))
+ {
+ /*
+ * Skip keywords we've already set...
+ */
+
+ if (sscanf(line, "*%40[^:]:", keystring) == 1 &&
+ cupsGetOption(keystring, num_keywords, keywords))
+ continue;
+
+ /*
+ * Otherwise write the line...
+ */
+
+ cupsFilePrintf(dst, "%s\n", line);
+ }
+
+ /*
+ * Close files and return...
+ */
+
+ cupsFileClose(src);
+ cupsFileClose(dst);
+
+ return (1);
+}
+
+
+/*
+ * 'cupsdUpdatePrinters()' - Update printers after a partial reload.
+ */
+
+void
+cupsdUpdatePrinters(void)
+{
+ cupsd_printer_t *p; /* Current printer */
+
+
+ /*
+ * Loop through the printers and recreate the printer attributes
+ * for any local printers since the policy and/or access control
+ * stuff may have changed. Also, if browsing is disabled, remove
+ * any remote printers...
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ /*
+ * Remove remote printers if we are no longer browsing...
+ */
+
+ if (!Browsing &&
+ (p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_DISCOVERED)))
+ {
+ if (p->type & CUPS_PRINTER_IMPLICIT)
+ cupsArrayRemove(ImplicitPrinters, p);
+
+ cupsArraySave(Printers);
+ cupsdDeletePrinter(p, 0);
+ cupsArrayRestore(Printers);
+ continue;
+ }
+
+ /*
+ * Update the operation policy pointer...
+ */
+
+ if ((p->op_policy_ptr = cupsdFindPolicy(p->op_policy)) == NULL)
+ p->op_policy_ptr = DefaultPolicyPtr;
+
+ /*
+ * Update printer attributes as needed...
+ */
+
+ if (!(p->type & CUPS_PRINTER_DISCOVERED))
+ cupsdSetPrinterAttrs(p);
+ }
+}
+
+
+/*
+ * 'cupsdValidateDest()' - Validate a printer/class destination.
+ */
+
+const char * /* O - Printer or class name */
+cupsdValidateDest(
+ const char *uri, /* I - Printer URI */
+ cups_ptype_t *dtype, /* O - Type (printer or class) */
+ cupsd_printer_t **printer) /* O - Printer pointer */
+{
+ cupsd_printer_t *p; /* Current printer */
+ char localname[1024],/* Localized hostname */
+ *lptr, /* Pointer into localized hostname */
+ *sptr, /* Pointer into server name */
+ *rptr, /* Pointer into resource */
+ scheme[32], /* Scheme portion of URI */
+ username[64], /* Username portion of URI */
+ hostname[HTTP_MAX_HOST],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
+
+
+ DEBUG_printf(("cupsdValidateDest(uri=\"%s\", dtype=%p, printer=%p)\n", uri,
+ dtype, printer));
+
+ /*
+ * Initialize return values...
+ */
+
+ if (printer)
+ *printer = NULL;
+
+ if (dtype)
+ *dtype = (cups_ptype_t)0;
+
+ /*
+ * Pull the hostname and resource from the URI...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
+ username, sizeof(username), hostname, sizeof(hostname),
+ &port, resource, sizeof(resource));
+
+ /*
+ * See if the resource is a class or printer...
+ */
+
+ if (!strncmp(resource, "/classes/", 9))
+ {
+ /*
+ * Class...
+ */
+
+ rptr = resource + 9;
+ }
+ else if (!strncmp(resource, "/printers/", 10))
+ {
+ /*
+ * Printer...
+ */
+
+ rptr = resource + 10;
+ }
+ else
+ {
+ /*
+ * Bad resource name...
+ */
+
+ return (NULL);
+ }
+
+ /*
+ * See if the printer or class name exists...
+ */
+
+ p = cupsdFindDest(rptr);
+
+ if (p == NULL && strchr(rptr, '@') == NULL)
+ return (NULL);
+ else if (p != NULL)
+ {
+ if (printer)
+ *printer = p;
+
+ if (dtype)
+ *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED);
+
+ return (p->name);
+ }
+
+ /*
+ * Change localhost to the server name...
+ */
+
+ if (!_cups_strcasecmp(hostname, "localhost"))
+ strlcpy(hostname, ServerName, sizeof(hostname));
+
+ strlcpy(localname, hostname, sizeof(localname));
+
+ if (!_cups_strcasecmp(hostname, ServerName))
+ {
+ /*
+ * Localize the hostname...
+ */
+
+ lptr = strchr(localname, '.');
+ sptr = strchr(ServerName, '.');
+
+ if (sptr != NULL && lptr != NULL)
+ {
+ /*
+ * Strip the common domain name components...
+ */
+
+ while (lptr != NULL)
+ {
+ if (!_cups_strcasecmp(lptr, sptr))
+ {
+ *lptr = '\0';
+ break;
+ }
+ else
+ lptr = strchr(lptr + 1, '.');
+ }
+ }
+ }
+
+ DEBUG_printf(("localized hostname is \"%s\"...\n", localname));
+
+ /*
+ * Find a matching printer or class...
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (!_cups_strcasecmp(p->hostname, localname) &&
+ !_cups_strcasecmp(p->name, rptr))
+ {
+ if (printer)
+ *printer = p;
+
+ if (dtype)
+ *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED);
+
+ return (p->name);
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * 'cupsdWritePrintcap()' - Write a pseudo-printcap file for older applications
+ * that need it...
+ */
+
+void
+cupsdWritePrintcap(void)
+{
+ int i; /* Looping var */
+ cups_file_t *fp; /* Printcap file */
+ cupsd_printer_t *p; /* Current printer */
+
+
+#ifdef __sgi
+ /*
+ * Update the IRIX printer state for the default printer; if
+ * no printers remain, then the default printer file will be
+ * removed...
+ */
+
+ write_irix_state(DefaultPrinter);
+#endif /* __sgi */
+
+ /*
+ * See if we have a printcap file; if not, don't bother writing it.
+ */
+
+ if (!Printcap || !*Printcap)
+ return;
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Generating printcap %s...", Printcap);
+
+ /*
+ * Open the printcap file...
+ */
+
+ if ((fp = cupsFileOpen(Printcap, "w")) == NULL)
+ return;
+
+ /*
+ * Put a comment header at the top so that users will know where the
+ * data has come from...
+ */
+
+ if (PrintcapFormat != PRINTCAP_PLIST)
+ cupsFilePrintf(fp, "# This file was automatically generated by cupsd(8) "
+ "from the\n"
+ "# %s/printers.conf file. All changes to this file\n"
+ "# will be lost.\n", ServerRoot);
+
+ /*
+ * Write a new printcap with the current list of printers.
+ */
+
+ switch (PrintcapFormat)
+ {
+ case PRINTCAP_BSD :
+ /*
+ * Each printer is put in the file as:
+ *
+ * Printer1:
+ * Printer2:
+ * Printer3:
+ * ...
+ * PrinterN:
+ */
+
+ if (DefaultPrinter)
+ cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", DefaultPrinter->name,
+ DefaultPrinter->info, ServerName,
+ DefaultPrinter->name);
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (p != DefaultPrinter)
+ cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", p->name, p->info,
+ ServerName, p->name);
+ break;
+
+ case PRINTCAP_PLIST :
+ /*
+ * Each printer is written as a dictionary in a plist file.
+ * Currently the printer-name, printer-info, printer-is-accepting-jobs,
+ * printer-location, printer-make-and-model, printer-state,
+ * printer-state-reasons, printer-type, and (sanitized) device-uri.
+ */
+
+ cupsFilePuts(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD "
+ "PLIST 1.0//EN\" \"http://www.apple.com/DTDs/"
+ "PropertyList-1.0.dtd\">\n"
+ "<plist version=\"1.0\">\n"
+ "<array>\n");
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ cupsFilePuts(fp, "\t<dict>\n"
+ "\t\t<key>printer-name</key>\n"
+ "\t\t<string>");
+ write_xml_string(fp, p->name);
+ cupsFilePuts(fp, "</string>\n"
+ "\t\t<key>printer-info</key>\n"
+ "\t\t<string>");
+ write_xml_string(fp, p->info);
+ cupsFilePrintf(fp, "</string>\n"
+ "\t\t<key>printer-is-accepting-jobs</key>\n"
+ "\t\t<%s/>\n"
+ "\t\t<key>printer-location</key>\n"
+ "\t\t<string>", p->accepting ? "true" : "false");
+ write_xml_string(fp, p->location);
+ cupsFilePuts(fp, "</string>\n"
+ "\t\t<key>printer-make-and-model</key>\n"
+ "\t\t<string>");
+ write_xml_string(fp, p->make_model);
+ cupsFilePrintf(fp, "</string>\n"
+ "\t\t<key>printer-state</key>\n"
+ "\t\t<integer>%d</integer>\n"
+ "\t\t<key>printer-state-reasons</key>\n"
+ "\t\t<array>\n", p->state);
+ for (i = 0; i < p->num_reasons; i ++)
+ {
+ cupsFilePuts(fp, "\t\t\t<string>");
+ write_xml_string(fp, p->reasons[i]);
+ cupsFilePuts(fp, "</string>\n");
+ }
+ cupsFilePrintf(fp, "\t\t</array>\n"
+ "\t\t<key>printer-type</key>\n"
+ "\t\t<integer>%d</integer>\n"
+ "\t\t<key>device-uri</key>\n"
+ "\t\t<string>", p->type);
+ write_xml_string(fp, p->sanitized_device_uri);
+ cupsFilePuts(fp, "</string>\n"
+ "\t</dict>\n");
+ }
+ cupsFilePuts(fp, "</array>\n"
+ "</plist>\n");
+ break;
+
+ case PRINTCAP_SOLARIS :
+ /*
+ * Each printer is put in the file as:
+ *
+ * _all:all=Printer1,Printer2,Printer3,...,PrinterN
+ * _default:use=DefaultPrinter
+ * Printer1:\
+ * :bsdaddr=ServerName,Printer1:\
+ * :description=Description:
+ * Printer2:
+ * :bsdaddr=ServerName,Printer2:\
+ * :description=Description:
+ * Printer3:
+ * :bsdaddr=ServerName,Printer3:\
+ * :description=Description:
+ * ...
+ * PrinterN:
+ * :bsdaddr=ServerName,PrinterN:\
+ * :description=Description:
+ */
+
+ cupsFilePuts(fp, "_all:all=");
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayCurrent(Printers))
+ cupsFilePrintf(fp, "%s%c", p->name,
+ cupsArrayNext(Printers) ? ',' : '\n');
+
+ if (DefaultPrinter)
+ cupsFilePrintf(fp, "_default:use=%s\n", DefaultPrinter->name);
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ cupsFilePrintf(fp, "%s:\\\n"
+ "\t:bsdaddr=%s,%s:\\\n"
+ "\t:description=%s:\n",
+ p->name, ServerName, p->name,
+ p->info ? p->info : "");
+ break;
+ }
+
+ /*
+ * Close the file...
+ */
+
+ cupsFileClose(fp);
+}
+
+
+/*
+ * 'add_printer_defaults()' - Add name-default attributes to the printer attributes.
+ */
+
+static void
+add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
+{
+ int i; /* Looping var */
+ int num_options; /* Number of default options */
+ cups_option_t *options, /* Default options */
+ *option; /* Current option */
+ char name[256]; /* name-default */
+
+
+ /*
+ * Maintain a common array of default attribute names...
+ */
+
+ if (!CommonDefaults)
+ {
+ CommonDefaults = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+
+ cupsArrayAdd(CommonDefaults, _cupsStrAlloc("copies-default"));
+ cupsArrayAdd(CommonDefaults, _cupsStrAlloc("document-format-default"));
+ cupsArrayAdd(CommonDefaults, _cupsStrAlloc("finishings-default"));
+ cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-hold-until-default"));
+ cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-priority-default"));
+ cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-sheets-default"));
+ cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-col-default"));
+ cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default"));
+ cupsArrayAdd(CommonDefaults,
+ _cupsStrAlloc("orientation-requested-default"));
+ }
+
+ /*
+ * Add all of the default options from the .conf files...
+ */
+
+ for (num_options = 0, options = NULL, i = p->num_options, option = p->options;
+ i > 0;
+ i --, option ++)
+ {
+ if (strcmp(option->name, "ipp-options") &&
+ strcmp(option->name, "job-sheets") &&
+ strcmp(option->name, "lease-duration"))
+ {
+ snprintf(name, sizeof(name), "%s-default", option->name);
+ num_options = cupsAddOption(name, option->value, num_options, &options);
+
+ if (!cupsArrayFind(CommonDefaults, name))
+ cupsArrayAdd(CommonDefaults, _cupsStrAlloc(name));
+ }
+ }
+
+ /*
+ * Convert options to IPP attributes...
+ */
+
+ cupsEncodeOptions2(p->attrs, num_options, options, IPP_TAG_PRINTER);
+ cupsFreeOptions(num_options, options);
+
+ /*
+ * Add standard -default attributes as needed...
+ */
+
+ if (!cupsGetOption("copies", p->num_options, p->options))
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default",
+ 1);
+
+ if (!cupsGetOption("document-format", p->num_options, p->options))
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
+ "document-format-default", NULL, "application/octet-stream");
+
+ if (!cupsGetOption("job-hold-until", p->num_options, p->options))
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "job-hold-until-default", NULL, "no-hold");
+
+ if (!cupsGetOption("job-priority", p->num_options, p->options))
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-priority-default", 50);
+
+ if (!cupsGetOption("number-up", p->num_options, p->options))
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "number-up-default", 1);
+
+ if (!cupsGetOption("notify-lease-duration", p->num_options, p->options))
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "notify-lease-duration-default", DefaultLeaseDuration);
+
+ if (!cupsGetOption("notify-events", p->num_options, p->options))
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "notify-events-default", NULL, "job-completed");
+
+ if (!cupsGetOption("orientation-requested", p->num_options, p->options))
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE,
+ "orientation-requested-default", NULL, NULL);
+
+ if (!cupsGetOption("print-quality", p->num_options, p->options))
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "print-quality-default", IPP_QUALITY_NORMAL);
+}
+
+
+/*
+ * 'add_printer_filter()' - Add a MIME filter for a printer.
+ */
+
+static void
+add_printer_filter(
+ cupsd_printer_t *p, /* I - Printer to add to */
+ mime_type_t *filtertype, /* I - Filter or prefilter MIME type */
+ const char *filter) /* I - Filter to add */
+{
+ char super[MIME_MAX_SUPER], /* Super-type for filter */
+ type[MIME_MAX_TYPE], /* Type for filter */
+ dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */
+ dtype[MIME_MAX_TYPE], /* Destination type for filter */
+ dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2],
+ /* Destination super/type */
+ program[1024]; /* Program/filter name */
+ int cost; /* Cost of filter */
+ size_t maxsize = 0; /* Maximum supported file size */
+ mime_type_t *temptype, /* MIME type looping var */
+ *desttype; /* Destination MIME type */
+ mime_filter_t *filterptr; /* MIME filter */
+ char filename[1024]; /* Full filter filename */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "add_printer_filter(p=%p(%s), filtertype=%p(%s/%s), "
+ "filter=\"%s\")", p, p->name, filtertype, filtertype->super,
+ filtertype->type, filter);
+
+ /*
+ * Parse the filter string; it should be in one of the following formats:
+ *
+ * source/type cost program
+ * source/type cost maxsize(nnnn) program
+ * source/type dest/type cost program
+ * source/type dest/type cost maxsize(nnnn) program
+ */
+
+ if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
+ super, type, dsuper, dtype, &cost, program) == 6)
+ {
+ snprintf(dest, sizeof(dest), "%s/%s/%s", p->name, dsuper, dtype);
+
+ if ((desttype = mimeType(MimeDatabase, "printer", dest)) == NULL)
+ {
+ desttype = mimeAddType(MimeDatabase, "printer", dest);
+ if (!p->dest_types)
+ p->dest_types = cupsArrayNew(NULL, NULL);
+
+ cupsArrayAdd(p->dest_types, desttype);
+ }
+
+ }
+ else
+ {
+ if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost,
+ program) == 4)
+ {
+ desttype = filtertype;
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!",
+ p->name, filter);
+ return;
+ }
+ }
+
+ if (!strncmp(program, "maxsize(", 8))
+ {
+ char *ptr; /* Pointer into maxsize(nnnn) program */
+
+ maxsize = strtoll(program + 8, &ptr, 10);
+
+ if (*ptr != ')')
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!",
+ p->name, filter);
+ return;
+ }
+
+ ptr ++;
+ while (_cups_isspace(*ptr))
+ ptr ++;
+
+ _cups_strcpy(program, ptr);
+ }
+
+ /*
+ * Check permissions on the filter and its containing directory...
+ */
+
+ if (strcmp(program, "-"))
+ {
+ if (program[0] == '/')
+ strlcpy(filename, program, sizeof(filename));
+ else
+ snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program);
+
+ _cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !RunUser,
+ cupsdLogFCMessage, p);
+ }
+
+ /*
+ * Add the filter to the MIME database, supporting wildcards as needed...
+ */
+
+ for (temptype = mimeFirstType(MimeDatabase);
+ temptype;
+ temptype = mimeNextType(MimeDatabase))
+ if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) ||
+ !_cups_strcasecmp(temptype->super, super)) &&
+ (type[0] == '*' || !_cups_strcasecmp(temptype->type, type)))
+ {
+ if (desttype != filtertype)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "add_printer_filter: %s: adding filter %s/%s %s/%s %d "
+ "%s", p->name, temptype->super, temptype->type,
+ desttype->super, desttype->type,
+ cost, program);
+ filterptr = mimeAddFilter(MimeDatabase, temptype, desttype, cost,
+ program);
+
+ if (!mimeFilterLookup(MimeDatabase, desttype, filtertype))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "add_printer_filter: %s: adding filter %s/%s %s/%s "
+ "0 -", p->name, desttype->super, desttype->type,
+ filtertype->super, filtertype->type);
+ mimeAddFilter(MimeDatabase, desttype, filtertype, cost, "-");
+ }
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "add_printer_filter: %s: adding filter %s/%s %s/%s %d "
+ "%s", p->name, temptype->super, temptype->type,
+ filtertype->super, filtertype->type,
+ cost, program);
+ filterptr = mimeAddFilter(MimeDatabase, temptype, filtertype, cost,
+ program);
+ }
+
+ if (filterptr)
+ filterptr->maxsize = maxsize;
+ }
+}
+
+
+/*
+ * 'add_printer_formats()' - Add document-format-supported values for a printer.
+ */
+
+static void
+add_printer_formats(cupsd_printer_t *p) /* I - Printer */
+{
+ int i; /* Looping var */
+ mime_type_t *type; /* Current MIME type */
+ cups_array_t *filters; /* Filters */
+ ipp_attribute_t *attr; /* document-format-supported attribute */
+ char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
+ /* MIME type name */
+
+
+ /*
+ * Raw (and remote) queues advertise all of the supported MIME
+ * types...
+ */
+
+ cupsArrayDelete(p->filetypes);
+ p->filetypes = NULL;
+
+ if (p->raw)
+ {
+ ippAddStrings(p->attrs, IPP_TAG_PRINTER,
+ (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY),
+ "document-format-supported", NumMimeTypes, NULL, MimeTypes);
+ return;
+ }
+
+ /*
+ * Otherwise, loop through the supported MIME types and see if there
+ * are filters for them...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_formats: %d types, %d filters",
+ mimeNumTypes(MimeDatabase), mimeNumFilters(MimeDatabase));
+
+ p->filetypes = cupsArrayNew(NULL, NULL);
+
+ for (type = mimeFirstType(MimeDatabase);
+ type;
+ type = mimeNextType(MimeDatabase))
+ {
+ if (!_cups_strcasecmp(type->super, "printer"))
+ continue;
+
+ snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
+
+ if ((filters = mimeFilter(MimeDatabase, type, p->filetype, NULL)) != NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "add_printer_formats: %s: %s needs %d filters",
+ p->name, mimetype, cupsArrayCount(filters));
+
+ cupsArrayDelete(filters);
+ cupsArrayAdd(p->filetypes, type);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "add_printer_formats: %s: %s not supported",
+ p->name, mimetype);
+ }
+
+ /*
+ * Add the file formats that can be filtered...
+ */
+
+ if ((type = mimeType(MimeDatabase, "application", "octet-stream")) == NULL ||
+ !cupsArrayFind(p->filetypes, type))
+ i = 1;
+ else
+ i = 0;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "add_printer_formats: %s: %d supported types",
+ p->name, cupsArrayCount(p->filetypes) + i);
+
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
+ "document-format-supported",
+ cupsArrayCount(p->filetypes) + i, NULL, NULL);
+
+ if (i)
+ attr->values[0].string.text = _cupsStrAlloc("application/octet-stream");
+
+ for (type = (mime_type_t *)cupsArrayFirst(p->filetypes);
+ type;
+ i ++, type = (mime_type_t *)cupsArrayNext(p->filetypes))
+ {
+ snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
+
+ attr->values[i].string.text = _cupsStrAlloc(mimetype);
+ }
+
+#ifdef HAVE_DNSSD
+ {
+ char pdl[1024]; /* Buffer to build pdl list */
+ mime_filter_t *filter; /* MIME filter looping var */
+
+
+ /*
+ * We only support raw printing if this is not a Tioga PrintJobMgr based
+ * queue and if application/octet-stream is a known type...
+ */
+
+ for (filter = (mime_filter_t *)cupsArrayFirst(MimeDatabase->filters);
+ filter;
+ filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters))
+ {
+ if (filter->dst == p->filetype && filter->filter &&
+ strstr(filter->filter, "PrintJobMgr"))
+ break;
+ }
+
+ pdl[0] = '\0';
+
+ if (!filter && mimeType(MimeDatabase, "application", "octet-stream"))
+ strlcat(pdl, "application/octet-stream,", sizeof(pdl));
+
+ /*
+ * Then list a bunch of formats that are supported by the printer...
+ */
+
+ for (type = (mime_type_t *)cupsArrayFirst(p->filetypes);
+ type;
+ type = (mime_type_t *)cupsArrayNext(p->filetypes))
+ {
+ if (!_cups_strcasecmp(type->super, "application"))
+ {
+ if (!_cups_strcasecmp(type->type, "pdf"))
+ strlcat(pdl, "application/pdf,", sizeof(pdl));
+ else if (!_cups_strcasecmp(type->type, "postscript"))
+ strlcat(pdl, "application/postscript,", sizeof(pdl));
+ }
+ else if (!_cups_strcasecmp(type->super, "image"))
+ {
+ if (!_cups_strcasecmp(type->type, "jpeg"))
+ strlcat(pdl, "image/jpeg,", sizeof(pdl));
+ else if (!_cups_strcasecmp(type->type, "png"))
+ strlcat(pdl, "image/png,", sizeof(pdl));
+ else if (!_cups_strcasecmp(type->type, "pwg-raster"))
+ strlcat(pdl, "image/pwg-raster,", sizeof(pdl));
+ }
+ }
+
+ if (pdl[0])
+ pdl[strlen(pdl) - 1] = '\0'; /* Remove trailing comma */
+
+ cupsdSetString(&p->pdl, pdl);
+ }
+#endif /* HAVE_DNSSD */
+}
+
+
+/*
+ * 'compare_printers()' - Compare two printers.
+ */
+
+static int /* O - Result of comparison */
+compare_printers(void *first, /* I - First printer */
+ void *second, /* I - Second printer */
+ void *data) /* I - App data (not used) */
+{
+ (void)data;
+
+ return (_cups_strcasecmp(((cupsd_printer_t *)first)->name,
+ ((cupsd_printer_t *)second)->name));
+}
+
+
+/*
+ * 'delete_printer_filters()' - Delete all MIME filters for a printer.
+ */
+
+static void
+delete_printer_filters(
+ cupsd_printer_t *p) /* I - Printer to remove from */
+{
+ mime_filter_t *filter; /* MIME filter looping var */
+ mime_type_t *type; /* Destination types for filters */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (p == NULL)
+ return;
+
+ /*
+ * Remove all filters from the MIME database that have a destination
+ * type == printer...
+ */
+
+ for (filter = mimeFirstFilter(MimeDatabase);
+ filter;
+ filter = mimeNextFilter(MimeDatabase))
+ if (filter->dst == p->filetype || filter->dst == p->prefiltertype ||
+ cupsArrayFind(p->dest_types, filter->dst))
+ {
+ /*
+ * Delete the current filter...
+ */
+
+ mimeDeleteFilter(MimeDatabase, filter);
+ }
+
+ for (type = (mime_type_t *)cupsArrayFirst(p->dest_types);
+ type;
+ type = (mime_type_t *)cupsArrayNext(p->dest_types))
+ mimeDeleteType(MimeDatabase, type);
+
+ cupsArrayDelete(p->dest_types);
+ p->dest_types = NULL;
+
+ cupsdSetPrinterReasons(p, "-cups-insecure-filter-warning"
+ ",cups-missing-filter-warning");
+}
+
+
+/*
+ * 'dirty_printer()' - Mark config and state files dirty for the specified
+ * printer.
+ */
+
+static void
+dirty_printer(cupsd_printer_t *p) /* I - Printer */
+{
+ if (p->type & CUPS_PRINTER_DISCOVERED)
+ cupsdMarkDirty(CUPSD_DIRTY_REMOTE);
+ else if (p->type & CUPS_PRINTER_CLASS)
+ cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
+ else
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+
+ if (PrintcapFormat == PRINTCAP_PLIST)
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+}
+
+
+/*
+ * 'load_ppd()' - Load a cached PPD file, updating the cache as needed.
+ */
+
+static void
+load_ppd(cupsd_printer_t *p) /* I - Printer */
+{
+ int i, j, k; /* Looping vars */
+ char cache_name[1024]; /* Cache filename */
+ struct stat cache_info; /* Cache file info */
+ ppd_file_t *ppd; /* PPD file */
+ char ppd_name[1024]; /* PPD filename */
+ struct stat ppd_info; /* PPD file info */
+ int num_media; /* Number of media options */
+ ppd_size_t *size; /* Current PPD size */
+ ppd_option_t *duplex, /* Duplex option */
+ *output_bin, /* OutputBin option */
+ *output_mode, /* OutputMode option */
+ *resolution; /* (Set|JCL|)Resolution option */
+ ppd_choice_t *choice, /* Current PPD choice */
+ *input_slot, /* Current input slot */
+ *media_type; /* Current media type */
+ ppd_attr_t *ppd_attr; /* PPD attribute */
+ int xdpi, /* Horizontal resolution */
+ ydpi; /* Vertical resolution */
+ const char *resptr; /* Pointer into resolution keyword */
+ _pwg_size_t *pwgsize; /* Current PWG size */
+ _pwg_map_t *pwgsource, /* Current PWG source */
+ *pwgtype; /* Current PWG type */
+ ipp_attribute_t *attr; /* Attribute data */
+ ipp_value_t *val; /* Attribute value */
+ int num_finishings, /* Number of finishings */
+ finishings[5]; /* finishings-supported values */
+ int num_qualities, /* Number of print-quality values */
+ qualities[3]; /* print-quality values */
+ int num_margins, /* Number of media-*-margin-supported values */
+ margins[16]; /* media-*-margin-supported values */
+ const char *filter; /* Current filter */
+ static const char * const sides[3] = /* sides-supported values */
+ {
+ "one-sided",
+ "two-sided-long-edge",
+ "two-sided-short-edge"
+ };
+ static const char * const standard_commands[] =
+ { /* Standard CUPS commands */
+ "AutoConfigure",
+ "Clean",
+ "PrintSelfTestPage"
+ };
+
+
+ /*
+ * Check to see if the cache is up-to-date...
+ */
+
+ snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, p->name);
+ if (stat(cache_name, &cache_info))
+ cache_info.st_mtime = 0;
+
+ snprintf(ppd_name, sizeof(ppd_name), "%s/ppd/%s.ppd", ServerRoot, p->name);
+ if (stat(ppd_name, &ppd_info))
+ ppd_info.st_mtime = 1;
+
+ ippDelete(p->ppd_attrs);
+ p->ppd_attrs = NULL;
+
+ _ppdCacheDestroy(p->pc);
+ p->pc = NULL;
+
+ if (cache_info.st_mtime >= ppd_info.st_mtime)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", cache_name);
+
+ if ((p->pc = _ppdCacheCreateWithFile(cache_name, &p->ppd_attrs)) != NULL &&
+ p->ppd_attrs)
+ {
+ /*
+ * Loaded successfully!
+ */
+
+ return;
+ }
+ }
+
+ /*
+ * Reload PPD attributes from disk...
+ */
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", ppd_name);
+
+ p->type &= ~CUPS_PRINTER_OPTIONS;
+ p->type |= CUPS_PRINTER_BW;
+
+ finishings[0] = IPP_FINISHINGS_NONE;
+ num_finishings = 1;
+
+ p->ppd_attrs = ippNew();
+
+ if ((ppd = ppdOpenFile(ppd_name)) != NULL)
+ {
+ /*
+ * Add make/model and other various attributes...
+ */
+
+ p->pc = _ppdCacheCreateWithPPD(ppd);
+
+ ppdMarkDefaults(ppd);
+
+ if (ppd->color_device)
+ p->type |= CUPS_PRINTER_COLOR;
+ if (ppd->variable_sizes)
+ p->type |= CUPS_PRINTER_VARIABLE;
+ if (!ppd->manual_copies)
+ p->type |= CUPS_PRINTER_COPIES;
+ if ((ppd_attr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL)
+ if (ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
+ p->type |= CUPS_PRINTER_FAX;
+
+ ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "color-supported",
+ ppd->color_device);
+ if (ppd->throughput)
+ {
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "pages-per-minute", ppd->throughput);
+ if (ppd->color_device)
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "pages-per-minute-color", ppd->throughput);
+ }
+ else
+ {
+ /*
+ * When there is no speed information, just say "1 page per minute".
+ */
+
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "pages-per-minute", 1);
+ if (ppd->color_device)
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "pages-per-minute-color", 1);
+ }
+
+ num_qualities = 0;
+
+ if ((output_mode = ppdFindOption(ppd, "OutputMode")) != NULL)
+ {
+ if (ppdFindChoice(output_mode, "draft") ||
+ ppdFindChoice(output_mode, "fast"))
+ qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
+
+ qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
+
+ if (ppdFindChoice(output_mode, "best") ||
+ ppdFindChoice(output_mode, "high"))
+ qualities[num_qualities ++] = IPP_QUALITY_HIGH;
+ }
+ else if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL)
+ {
+ do
+ {
+ if (strstr(ppd_attr->spec, "draft") ||
+ strstr(ppd_attr->spec, "Draft"))
+ {
+ qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
+ break;
+ }
+ }
+ while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset",
+ NULL)) != NULL);
+
+ qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
+ qualities[num_qualities ++] = IPP_QUALITY_HIGH;
+ }
+ else
+ qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
+
+ ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "print-quality-supported", num_qualities, qualities);
+
+ if (ppd->nickname)
+ {
+ /*
+ * The NickName can be localized in the character set specified
+ * by the LanugageEncoding attribute. However, ppdOpen2() has
+ * already converted the ppd->nickname member to UTF-8 for us
+ * (the original attribute value is available separately)
+ */
+
+ cupsdSetString(&p->make_model, ppd->nickname);
+ }
+ else if (ppd->modelname)
+ {
+ /*
+ * Model name can only contain specific characters...
+ */
+
+ cupsdSetString(&p->make_model, ppd->modelname);
+ }
+ else
+ cupsdSetString(&p->make_model, "Bad PPD File");
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, p->make_model);
+
+ /*
+ * Add media options from the PPD file...
+ */
+
+ if (ppd->num_sizes == 0 || !p->pc)
+ {
+ if (!ppdFindAttr(ppd, "APScannerOnly", NULL))
+ cupsdLogMessage(CUPSD_LOG_CRIT,
+ "The PPD file for printer %s contains no media "
+ "options and is therefore invalid!", p->name);
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-default", NULL, "unknown");
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-supported", NULL, "unknown");
+ }
+ else
+ {
+ /*
+ * media-default
+ */
+
+ if ((size = ppdPageSize(ppd, NULL)) != NULL)
+ pwgsize = _ppdCacheGetSize(p->pc, size->name);
+ else
+ pwgsize = NULL;
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-default", NULL,
+ pwgsize ? pwgsize->map.pwg : "unknown");
+
+ /*
+ * media-col-default
+ */
+
+ if (pwgsize)
+ {
+ ipp_t *col; /* Collection value */
+
+ input_slot = ppdFindMarkedChoice(ppd, "InputSlot");
+ media_type = ppdFindMarkedChoice(ppd, "MediaType");
+ col = new_media_col(pwgsize,
+ input_slot ?
+ _ppdCacheGetSource(p->pc,
+ input_slot->choice) :
+ NULL,
+ media_type ?
+ _ppdCacheGetType(p->pc,
+ media_type->choice) :
+ NULL);
+
+ ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default",
+ col);
+ ippDelete(col);
+ }
+
+ /*
+ * media-supported
+ */
+
+ num_media = p->pc->num_sizes;
+ if (p->pc->custom_min_keyword)
+ num_media += 2;
+
+ if ((attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-supported", num_media, NULL,
+ NULL)) != NULL)
+ {
+ val = attr->values;
+
+ for (i = p->pc->num_sizes, pwgsize = p->pc->sizes;
+ i > 0;
+ i --, pwgsize ++, val ++)
+ val->string.text = _cupsStrRetain(pwgsize->map.pwg);
+
+ if (p->pc->custom_min_keyword)
+ {
+ val->string.text = _cupsStrRetain(p->pc->custom_min_keyword);
+ val ++;
+ val->string.text = _cupsStrRetain(p->pc->custom_max_keyword);
+ }
+ }
+
+ /*
+ * media-source-supported
+ */
+
+ if (p->pc->num_sources > 0 &&
+ (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-source-supported", p->pc->num_sources,
+ NULL, NULL)) != NULL)
+ {
+ for (i = p->pc->num_sources, pwgsource = p->pc->sources,
+ val = attr->values;
+ i > 0;
+ i --, pwgsource ++, val ++)
+ val->string.text = _cupsStrRetain(pwgsource->pwg);
+ }
+
+ /*
+ * media-type-supported
+ */
+
+ if (p->pc->num_types > 0 &&
+ (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-type-supported", p->pc->num_types,
+ NULL, NULL)) != NULL)
+ {
+ for (i = p->pc->num_types, pwgtype = p->pc->types,
+ val = attr->values;
+ i > 0;
+ i --, pwgtype ++, val ++)
+ val->string.text = _cupsStrRetain(pwgtype->pwg);
+ }
+
+ /*
+ * media-*-margin-supported
+ */
+
+ for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
+ i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
+ i --, pwgsize ++)
+ {
+ for (j = 0; j < num_margins; j ++)
+ if (pwgsize->bottom == margins[j])
+ break;
+
+ if (j >= num_margins)
+ {
+ margins[num_margins] = pwgsize->bottom;
+ num_margins ++;
+ }
+ }
+
+ if (num_margins > 0)
+ ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-bottom-margin-supported", num_margins, margins);
+ else
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-bottom-margin-supported", 0);
+
+ for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
+ i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
+ i --, pwgsize ++)
+ {
+ for (j = 0; j < num_margins; j ++)
+ if (pwgsize->left == margins[j])
+ break;
+
+ if (j >= num_margins)
+ {
+ margins[num_margins] = pwgsize->left;
+ num_margins ++;
+ }
+ }
+
+ if (num_margins > 0)
+ ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-left-margin-supported", num_margins, margins);
+ else
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-left-margin-supported", 0);
+
+ for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
+ i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
+ i --, pwgsize ++)
+ {
+ for (j = 0; j < num_margins; j ++)
+ if (pwgsize->right == margins[j])
+ break;
+
+ if (j >= num_margins)
+ {
+ margins[num_margins] = pwgsize->right;
+ num_margins ++;
+ }
+ }
+
+ if (num_margins > 0)
+ ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-right-margin-supported", num_margins, margins);
+ else
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-right-margin-supported", 0);
+
+ for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
+ i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
+ i --, pwgsize ++)
+ {
+ for (j = 0; j < num_margins; j ++)
+ if (pwgsize->top == margins[j])
+ break;
+
+ if (j >= num_margins)
+ {
+ margins[num_margins] = pwgsize->top;
+ num_margins ++;
+ }
+ }
+
+ if (num_margins > 0)
+ ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-top-margin-supported", num_margins, margins);
+ else
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-top-margin-supported", 0);
+
+ /*
+ * media-col-database
+ */
+
+ num_media = p->pc->num_sizes;
+ if (p->pc->num_sources)
+ {
+ if (p->pc->num_types > 0)
+ num_media += p->pc->num_sizes * p->pc->num_sources *
+ p->pc->num_types;
+ else
+ num_media += p->pc->num_sizes * p->pc->num_sources;
+ }
+ else if (p->pc->num_types)
+ num_media += p->pc->num_sizes * p->pc->num_types;
+
+ if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER,
+ "media-col-database", num_media,
+ NULL)) != NULL)
+ {
+ for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, val = attr->values;
+ i > 0;
+ i --, pwgsize ++)
+ {
+ /*
+ * Start by adding the page size without source or type...
+ */
+
+ ppdMarkOption(ppd, "PageSize", pwgsize->map.ppd);
+
+ val->collection = new_media_col(pwgsize, NULL, NULL);
+ val ++;
+
+ /*
+ * Then add the specific, supported combinations of size, source, and
+ * type...
+ */
+
+ if (p->pc->num_sources > 0)
+ {
+ for (j = p->pc->num_sources, pwgsource = p->pc->sources;
+ j > 0;
+ j --, pwgsource ++)
+ {
+ ppdMarkOption(ppd, "InputSlot", pwgsource->ppd);
+
+ if (p->pc->num_types > 0)
+ {
+ for (k = p->pc->num_types, pwgtype = p->pc->types;
+ k > 0;
+ k --, pwgtype ++)
+ {
+ if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
+ {
+ val->collection = new_media_col(pwgsize, pwgsource->pwg,
+ pwgtype->pwg);
+ val ++;
+ }
+ }
+ }
+ else if (!ppdConflicts(ppd))
+ {
+ val->collection = new_media_col(pwgsize, pwgsource->pwg, NULL);
+ val ++;
+ }
+ }
+ }
+ else if (p->pc->num_types > 0)
+ {
+ for (j = p->pc->num_types, pwgtype = p->pc->types;
+ j > 0;
+ j --, pwgtype ++)
+ {
+ if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
+ {
+ val->collection = new_media_col(pwgsize, NULL, pwgtype->pwg);
+ val ++;
+ }
+ }
+ }
+ }
+
+ /*
+ * Update the number of media-col-database values...
+ */
+
+ attr->num_values = val - attr->values;
+ }
+ }
+
+ /*
+ * Output bin...
+ */
+
+ if (p->pc && p->pc->num_bins > 0)
+ {
+ attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-bin-supported", p->pc->num_bins,
+ NULL, NULL);
+
+ if (attr != NULL)
+ {
+ for (i = 0, val = attr->values;
+ i < p->pc->num_bins;
+ i ++, val ++)
+ val->string.text = _cupsStrAlloc(p->pc->bins[i].pwg);
+ }
+
+ if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
+ {
+ for (i = 0; i < p->pc->num_bins; i ++)
+ if (!strcmp(p->pc->bins[i].ppd, output_bin->defchoice))
+ break;
+
+ if (i >= p->pc->num_bins)
+ i = 0;
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-bin-default", NULL, p->pc->bins[i].pwg);
+ }
+ else
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-bin-default", NULL, p->pc->bins[0].pwg);
+ }
+ else if (((ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder",
+ NULL)) != NULL &&
+ !_cups_strcasecmp(ppd_attr->value, "Reverse")) ||
+ (!ppd_attr && ppd->manufacturer && /* "Compatibility heuristic" */
+ (!_cups_strcasecmp(ppd->manufacturer, "epson") ||
+ !_cups_strcasecmp(ppd->manufacturer, "lexmark"))))
+ {
+ /*
+ * Report that this printer has a single output bin that leaves pages face
+ * up.
+ */
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-bin-supported", NULL, "face-up");
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-bin-default", NULL, "face-up");
+ }
+ else
+ {
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-bin-supported", NULL, "face-down");
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-bin-default", NULL, "face-down");
+ }
+
+ /*
+ * output-mode and print-color-mode...
+ */
+
+ if (ppd->color_device)
+ {
+ static const char * const output_modes[] =
+ {
+ "monochrome",
+ "color"
+ };
+
+ ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-mode-supported", 2, NULL, output_modes);
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-mode-default", NULL, "color");
+
+ ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "print-color-mode-supported", 2, NULL, output_modes);
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "print-color-mode-default", NULL, "color");
+ }
+ else
+ {
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-mode-supported", NULL, "monochrome");
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-mode-default", NULL, "monochrome");
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "print-color-mode-supported", NULL, "monochrome");
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "print-color-mode-default", NULL, "monochrome");
+ }
+
+ /*
+ * Printer resolutions...
+ */
+
+ if ((resolution = ppdFindOption(ppd, "Resolution")) == NULL)
+ if ((resolution = ppdFindOption(ppd, "JCLResolution")) == NULL)
+ if ((resolution = ppdFindOption(ppd, "SetResolution")) == NULL)
+ resolution = ppdFindOption(ppd, "CNRes_PGP");
+
+ if (resolution)
+ {
+ /*
+ * Report all supported resolutions...
+ */
+
+ attr = ippAddResolutions(p->ppd_attrs, IPP_TAG_PRINTER,
+ "printer-resolution-supported",
+ resolution->num_choices, IPP_RES_PER_INCH,
+ NULL, NULL);
+
+ for (i = 0, choice = resolution->choices;
+ i < resolution->num_choices;
+ i ++, choice ++)
+ {
+ xdpi = ydpi = (int)strtol(choice->choice, (char **)&resptr, 10);
+ if (resptr > choice->choice && xdpi > 0 && *resptr == 'x')
+ ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
+
+ if (xdpi <= 0 || ydpi <= 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Bad resolution \"%s\" for printer %s.",
+ choice->choice, p->name);
+ xdpi = ydpi = 300;
+ }
+
+ attr->values[i].resolution.xres = xdpi;
+ attr->values[i].resolution.yres = ydpi;
+ attr->values[i].resolution.units = IPP_RES_PER_INCH;
+
+ if (choice->marked)
+ ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
+ "printer-resolution-default", IPP_RES_PER_INCH,
+ xdpi, ydpi);
+ }
+ }
+ else if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL &&
+ ppd_attr->value)
+ {
+ /*
+ * Just the DefaultResolution to report...
+ */
+
+ xdpi = ydpi = (int)strtol(ppd_attr->value, (char **)&resptr, 10);
+ if (resptr > ppd_attr->value && xdpi > 0)
+ {
+ if (*resptr == 'x')
+ ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
+ else
+ ydpi = xdpi;
+ }
+
+ if (xdpi <= 0 || ydpi <= 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Bad default resolution \"%s\" for printer %s.",
+ ppd_attr->value, p->name);
+ xdpi = ydpi = 300;
+ }
+
+ ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
+ "printer-resolution-default", IPP_RES_PER_INCH,
+ xdpi, ydpi);
+ ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
+ "printer-resolution-supported", IPP_RES_PER_INCH,
+ xdpi, ydpi);
+ }
+ else
+ {
+ /*
+ * No resolutions in PPD - make one up...
+ */
+
+ ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
+ "printer-resolution-default", IPP_RES_PER_INCH,
+ 300, 300);
+ ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
+ "printer-resolution-supported", IPP_RES_PER_INCH,
+ 300, 300);
+ }
+
+ /*
+ * Duplexing, etc...
+ */
+
+ ppdMarkDefaults(ppd);
+
+ if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
+ if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
+ if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
+ if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL)
+ duplex = ppdFindOption(ppd, "JCLDuplex");
+
+ if (duplex && duplex->num_choices > 1 &&
+ !ppdInstallableConflict(ppd, duplex->keyword, "DuplexTumble"))
+ {
+ p->type |= CUPS_PRINTER_DUPLEX;
+
+ ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "sides-supported", 3, NULL, sides);
+
+ if (!_cups_strcasecmp(duplex->defchoice, "DuplexTumble"))
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "sides-default", NULL, "two-sided-short-edge");
+ else if (!_cups_strcasecmp(duplex->defchoice, "DuplexNoTumble"))
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "sides-default", NULL, "two-sided-long-edge");
+ else
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "sides-default", NULL, "one-sided");
+ }
+ else
+ {
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "sides-supported", NULL, "one-sided");
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "sides-default", NULL, "one-sided");
+ }
+
+ if (ppdFindOption(ppd, "Collate") != NULL)
+ p->type |= CUPS_PRINTER_COLLATE;
+
+ if (ppdFindOption(ppd, "StapleLocation") != NULL)
+ {
+ p->type |= CUPS_PRINTER_STAPLE;
+ finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
+ }
+
+ if (ppdFindOption(ppd, "BindEdge") != NULL)
+ {
+ p->type |= CUPS_PRINTER_BIND;
+ finishings[num_finishings++] = IPP_FINISHINGS_BIND;
+ }
+
+ for (i = 0; i < ppd->num_sizes; i ++)
+ if (ppd->sizes[i].length > 1728)
+ p->type |= CUPS_PRINTER_LARGE;
+ else if (ppd->sizes[i].length > 1008)
+ p->type |= CUPS_PRINTER_MEDIUM;
+ else
+ p->type |= CUPS_PRINTER_SMALL;
+
+ if ((ppd_attr = ppdFindAttr(ppd, "APICADriver", NULL)) != NULL &&
+ ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
+ {
+ if ((ppd_attr = ppdFindAttr(ppd, "APScannerOnly", NULL)) != NULL &&
+ ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
+ p->type |= CUPS_PRINTER_SCANNER;
+ else
+ p->type |= CUPS_PRINTER_MFP;
+ }
+
+ /*
+ * Scan the filters in the PPD file...
+ */
+
+ if (p->pc)
+ {
+ for (filter = (const char *)cupsArrayFirst(p->pc->filters);
+ filter;
+ filter = (const char *)cupsArrayNext(p->pc->filters))
+ {
+ if (!_cups_strncasecmp(filter, "application/vnd.cups-command", 28) &&
+ _cups_isspace(filter[28]))
+ {
+ p->type |= CUPS_PRINTER_COMMANDS;
+ break;
+ }
+ }
+ }
+
+ if (p->type & CUPS_PRINTER_COMMANDS)
+ {
+ char *commands, /* Copy of commands */
+ *start, /* Start of name */
+ *end; /* End of name */
+ int count; /* Number of commands */
+
+ if ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL)
+ {
+ for (count = 0, start = ppd_attr->value; *start; count ++)
+ {
+ while (_cups_isspace(*start))
+ start ++;
+
+ if (!*start)
+ break;
+
+ while (*start && !isspace(*start & 255))
+ start ++;
+ }
+ }
+ else
+ count = 0;
+
+ if (count > 0)
+ {
+ /*
+ * Make a copy of the commands string and count how many commands there
+ * are...
+ */
+
+ attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "printer-commands", count, NULL, NULL);
+
+ commands = strdup(ppd_attr->value);
+
+ for (count = 0, start = commands; *start; count ++)
+ {
+ while (isspace(*start & 255))
+ start ++;
+
+ if (!*start)
+ break;
+
+ end = start;
+ while (*end && !isspace(*end & 255))
+ end ++;
+
+ if (*end)
+ *end++ = '\0';
+
+ attr->values[count].string.text = _cupsStrAlloc(start);
+
+ start = end;
+ }
+
+ free(commands);
+ }
+ else
+ {
+ /*
+ * Add the standard list of commands...
+ */
+
+ ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "printer-commands",
+ (int)(sizeof(standard_commands) /
+ sizeof(standard_commands[0])), NULL,
+ standard_commands);
+ }
+ }
+ else
+ {
+ /*
+ * No commands supported...
+ */
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "printer-commands", NULL, "none");
+ }
+
+ /*
+ * Show current and available port monitors for this printer...
+ */
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
+ NULL, p->port_monitor ? p->port_monitor : "none");
+
+ for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
+ ppd_attr;
+ i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL));
+
+ if (ppd->protocols)
+ {
+ if (strstr(ppd->protocols, "TBCP"))
+ i ++;
+ else if (strstr(ppd->protocols, "BCP"))
+ i ++;
+ }
+
+ attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "port-monitor-supported", i, NULL, NULL);
+
+ attr->values[0].string.text = _cupsStrAlloc("none");
+
+ for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
+ ppd_attr;
+ i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
+ attr->values[i].string.text = _cupsStrAlloc(ppd_attr->value);
+
+ if (ppd->protocols)
+ {
+ if (strstr(ppd->protocols, "TBCP"))
+ attr->values[i].string.text = _cupsStrAlloc("tbcp");
+ else if (strstr(ppd->protocols, "BCP"))
+ attr->values[i].string.text = _cupsStrAlloc("bcp");
+ }
+
+ if (ppdFindAttr(ppd, "APRemoteQueueID", NULL))
+ p->type |= CUPS_PRINTER_REMOTE;
+
+#ifdef HAVE_APPLICATIONSERVICES_H
+ /*
+ * Convert the file referenced in APPrinterIconPath to a 128x128 PNG
+ * and save it as cacheDir/printername.png
+ */
+
+ if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL &&
+ ppd_attr->value &&
+ !_cupsFileCheck(ppd_attr->value, _CUPS_FILE_CHECK_FILE, !RunUser,
+ cupsdLogFCMessage, p))
+ {
+ CGImageRef imageRef = NULL;/* Current icon image */
+ CGImageRef biggestIconRef = NULL;
+ /* Biggest icon image */
+ CGImageRef closestTo128IconRef = NULL;
+ /* Icon image closest to and >= 128 */
+ CGImageSourceRef sourceRef; /* The file's image source */
+ char outPath[HTTP_MAX_URI];
+ /* The path to the PNG file */
+ CFURLRef outUrl; /* The URL made from the outPath */
+ CFURLRef icnsFileUrl; /* The URL of the original ICNS icon file */
+ CGImageDestinationRef destRef; /* The image destination to write */
+ size_t bytesPerRow; /* The bytes per row used for resizing */
+ CGContextRef context; /* The CG context used for resizing */
+
+ snprintf(outPath, sizeof(outPath), "%s/%s.png", CacheDir, p->name);
+ outUrl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
+ (UInt8 *)outPath,
+ strlen(outPath),
+ FALSE);
+ icnsFileUrl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
+ (UInt8 *)ppd_attr->value,
+ strlen(ppd_attr->value),
+ FALSE);
+ if (outUrl && icnsFileUrl)
+ {
+ sourceRef = CGImageSourceCreateWithURL(icnsFileUrl, NULL);
+ if (sourceRef)
+ {
+ for (i = 0; i < CGImageSourceGetCount(sourceRef); i ++)
+ {
+ imageRef = CGImageSourceCreateImageAtIndex(sourceRef, i, NULL);
+ if (!imageRef)
+ continue;
+
+ if (CGImageGetWidth(imageRef) == CGImageGetHeight(imageRef))
+ {
+ /*
+ * Loop through remembering the icon closest to 128 but >= 128
+ * and then remember the largest icon.
+ */
+
+ if (CGImageGetWidth(imageRef) >= 128 &&
+ (!closestTo128IconRef ||
+ CGImageGetWidth(imageRef) <
+ CGImageGetWidth(closestTo128IconRef)))
+ {
+ CGImageRelease(closestTo128IconRef);
+ CGImageRetain(imageRef);
+ closestTo128IconRef = imageRef;
+ }
+
+ if (!biggestIconRef ||
+ CGImageGetWidth(imageRef) > CGImageGetWidth(biggestIconRef))
+ {
+ CGImageRelease(biggestIconRef);
+ CGImageRetain(imageRef);
+ biggestIconRef = imageRef;
+ }
+ }
+
+ CGImageRelease(imageRef);
+ }
+
+ if (biggestIconRef)
+ {
+ /*
+ * If biggestIconRef is NULL, we found no icons. Otherwise we first
+ * want the closest to 128, but if none are larger than 128, we want
+ * the largest icon available.
+ */
+
+ imageRef = closestTo128IconRef ? closestTo128IconRef :
+ biggestIconRef;
+ CGImageRetain(imageRef);
+ CGImageRelease(biggestIconRef);
+ if (closestTo128IconRef)
+ CGImageRelease(closestTo128IconRef);
+ destRef = CGImageDestinationCreateWithURL(outUrl, kUTTypePNG, 1,
+ NULL);
+ if (destRef)
+ {
+ if (CGImageGetWidth(imageRef) != 128)
+ {
+ bytesPerRow = CGImageGetBytesPerRow(imageRef) /
+ CGImageGetWidth(imageRef) * 128;
+ context = CGBitmapContextCreate(NULL, 128, 128,
+ CGImageGetBitsPerComponent(imageRef),
+ bytesPerRow,
+ CGImageGetColorSpace(imageRef),
+ kCGImageAlphaPremultipliedFirst);
+ if (context)
+ {
+ CGContextDrawImage(context, CGRectMake(0, 0, 128, 128),
+ imageRef);
+ CGImageRelease(imageRef);
+ imageRef = CGBitmapContextCreateImage(context);
+ CGContextRelease(context);
+ }
+ }
+
+ CGImageDestinationAddImage(destRef, imageRef, NULL);
+ CGImageDestinationFinalize(destRef);
+ CFRelease(destRef);
+ }
+
+ CGImageRelease(imageRef);
+ }
+
+ CFRelease(sourceRef);
+ }
+ }
+
+ if (outUrl)
+ CFRelease(outUrl);
+
+ if (icnsFileUrl)
+ CFRelease(icnsFileUrl);
+ }
+#endif /* HAVE_APPLICATIONSERVICES_H */
+
+ /*
+ * Close the PPD and set the type...
+ */
+
+ ppdClose(ppd);
+ }
+ else if (!access(ppd_name, 0))
+ {
+ int pline; /* PPD line number */
+ ppd_status_t pstatus; /* PPD load status */
+
+
+ pstatus = ppdLastError(&pline);
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded!",
+ p->name);
+
+ if (pstatus <= PPD_ALLOC_ERROR)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s", strerror(errno));
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d.",
+ ppdErrorString(pstatus), pline);
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Hint: Run \"cupstestppd %s\" and fix any errors.",
+ ppd_name);
+ }
+ else
+ {
+ /*
+ * If we have an interface script, add a filter entry for it...
+ */
+
+ char interface[1024]; /* Interface script */
+
+
+ snprintf(interface, sizeof(interface), "%s/interfaces/%s", ServerRoot,
+ p->name);
+ if (!access(interface, X_OK))
+ {
+ /*
+ * Yes, we have a System V style interface script; use it!
+ */
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL,
+ "Local System V Printer");
+ }
+ else if (!strncmp(p->device_uri, "ipp://", 6) &&
+ (strstr(p->device_uri, "/printers/") != NULL ||
+ strstr(p->device_uri, "/classes/") != NULL ||
+ (strstr(p->device_uri, "._ipp.") != NULL &&
+ !strcmp(p->device_uri + strlen(p->device_uri) - 5,
+ "/cups"))))
+ {
+ /*
+ * Tell the client this is really a hard-wired remote printer.
+ */
+
+ p->type |= CUPS_PRINTER_REMOTE;
+
+ /*
+ * Point the printer-uri-supported attribute to the
+ * remote printer...
+ */
+
+ if (strchr(p->device_uri, '?'))
+ {
+ /*
+ * Strip trailing "?options" from URI...
+ */
+
+ char resource[HTTP_MAX_URI], /* New URI */
+ *ptr; /* Pointer into URI */
+
+ strlcpy(resource, p->device_uri, sizeof(resource));
+ if ((ptr = strchr(resource, '?')) != NULL)
+ *ptr = '\0';
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "printer-uri-supported", NULL, resource);
+ }
+ else
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "printer-uri-supported", NULL, p->device_uri);
+
+ /*
+ * Then set the make-and-model accordingly...
+ */
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, "Remote Printer");
+
+ /*
+ * Print all files directly...
+ */
+
+ p->raw = 1;
+ p->remote = 1;
+ }
+ else
+ {
+ /*
+ * Otherwise we have neither - treat this as a "dumb" printer
+ * with no PPD file...
+ */
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, "Local Raw Printer");
+
+ p->raw = 1;
+ }
+ }
+
+ ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "finishings-supported", num_finishings, finishings);
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "finishings-default", IPP_FINISHINGS_NONE);
+
+ if (ppd && p->pc)
+ {
+ /*
+ * Save cached PPD attributes to disk...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Saving %s...", cache_name);
+
+ _ppdCacheWriteFile(p->pc, cache_name, p->ppd_attrs);
+ }
+ else
+ {
+ /*
+ * Remove cache files...
+ */
+
+ if (cache_info.st_mtime)
+ unlink(cache_name);
+ }
+}
+
+
+/*
+ * 'new_media_col()' - Create a media-col collection value.
+ */
+
+static ipp_t * /* O - Collection value */
+new_media_col(_pwg_size_t *size, /* I - media-size/margin values */
+ const char *source, /* I - media-source value */
+ const char *type) /* I - media-type value */
+{
+ ipp_t *media_col, /* Collection value */
+ *media_size; /* media-size value */
+
+
+ media_col = ippNew();
+
+ media_size = ippNew();
+ ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "x-dimension", size->width);
+ ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "y-dimension", size->length);
+ ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size);
+ ippDelete(media_size);
+
+ ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-bottom-margin", size->bottom);
+ ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-left-margin", size->left);
+ ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-right-margin", size->right);
+ ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-top-margin", size->top);
+
+ if (source)
+ ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-source",
+ NULL, source);
+
+ if (type)
+ ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type",
+ NULL, type);
+
+ return (media_col);
+}
+
+
+#ifdef __sgi
+/*
+ * 'write_irix_config()' - Update the config files used by the IRIX
+ * desktop tools.
+ */
+
+static void
+write_irix_config(cupsd_printer_t *p) /* I - Printer to update */
+{
+ char filename[1024]; /* Interface script filename */
+ cups_file_t *fp; /* Interface script file */
+ ipp_attribute_t *attr; /* Attribute data */
+
+
+ /*
+ * Add dummy interface and GUI scripts to fool SGI's "challenged" printing
+ * tools. First the interface script that tells the tools what kind of
+ * printer we have...
+ */
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
+
+ if (p->type & CUPS_PRINTER_CLASS)
+ unlink(filename);
+ else if ((fp = cupsFileOpen(filename, "w")) != NULL)
+ {
+ cupsFilePuts(fp, "#!/bin/sh\n");
+
+ if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model",
+ IPP_TAG_TEXT)) != NULL)
+ cupsFilePrintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text);
+ else if (p->type & CUPS_PRINTER_CLASS)
+ cupsFilePuts(fp, "NAME=\"Printer Class\"\n");
+ else
+ cupsFilePuts(fp, "NAME=\"Remote Destination\"\n");
+
+ if (p->type & CUPS_PRINTER_COLOR)
+ cupsFilePuts(fp, "TYPE=ColorPostScript\n");
+ else
+ cupsFilePuts(fp, "TYPE=MonoPostScript\n");
+
+ cupsFilePrintf(fp, "HOSTNAME=%s\n", ServerName);
+ cupsFilePrintf(fp, "HOSTPRINTER=%s\n", p->name);
+
+ cupsFileClose(fp);
+
+ chmod(filename, 0755);
+ chown(filename, User, Group);
+ }
+
+ /*
+ * Then the member file that tells which device file the queue is connected
+ * to... Networked printers use "/dev/null" in this file, so that's what
+ * we use (the actual device URI can confuse some apps...)
+ */
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
+
+ if (p->type & CUPS_PRINTER_CLASS)
+ unlink(filename);
+ else if ((fp = cupsFileOpen(filename, "w")) != NULL)
+ {
+ cupsFilePuts(fp, "/dev/null\n");
+
+ cupsFileClose(fp);
+
+ chmod(filename, 0644);
+ chown(filename, User, Group);
+ }
+
+ /*
+ * The gui_interface file is a script or program that launches a GUI
+ * option panel for the printer, using options specified on the
+ * command-line in the third argument. The option panel must send
+ * any printing options to stdout on a single line when the user
+ * accepts them, or nothing if the user cancels the dialog.
+ *
+ * The default options panel program is /usr/bin/glpoptions, from
+ * the ESP Print Pro software. You can select another using the
+ * PrintcapGUI option.
+ */
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui", p->name);
+
+ if (p->type & CUPS_PRINTER_CLASS)
+ unlink(filename);
+ else if ((fp = cupsFileOpen(filename, "w")) != NULL)
+ {
+ cupsFilePuts(fp, "#!/bin/sh\n");
+ cupsFilePrintf(fp, "%s -d %s -o \"$3\"\n", PrintcapGUI, p->name);
+
+ cupsFileClose(fp);
+
+ chmod(filename, 0755);
+ chown(filename, User, Group);
+ }
+
+ /*
+ * The POD config file is needed by the printstatus command to show
+ * the printer location and device.
+ */
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
+
+ if (p->type & CUPS_PRINTER_CLASS)
+ unlink(filename);
+ else if ((fp = cupsFileOpen(filename, "w")) != NULL)
+ {
+ cupsFilePrintf(fp, "Printer Class | %s\n",
+ (p->type & CUPS_PRINTER_COLOR) ? "ColorPostScript" : "MonoPostScript");
+ cupsFilePrintf(fp, "Printer Model | %s\n", p->make_model ? p->make_model : "");
+ cupsFilePrintf(fp, "Location Code | %s\n", p->location ? p->location : "");
+ cupsFilePrintf(fp, "Physical Location | %s\n", p->info ? p->info : "");
+ cupsFilePrintf(fp, "Port Path | %s\n", p->device_uri);
+ cupsFilePrintf(fp, "Config Path | /var/spool/lp/pod/%s.config\n", p->name);
+ cupsFilePrintf(fp, "Active Status Path | /var/spool/lp/pod/%s.status\n", p->name);
+ cupsFilePuts(fp, "Status Update Wait | 10 seconds\n");
+
+ cupsFileClose(fp);
+
+ chmod(filename, 0664);
+ chown(filename, User, Group);
+ }
+}
+
+
+/*
+ * 'write_irix_state()' - Update the status files used by IRIX printing
+ * desktop tools.
+ */
+
+static void
+write_irix_state(cupsd_printer_t *p) /* I - Printer to update */
+{
+ char filename[1024]; /* Interface script filename */
+ cups_file_t *fp; /* Interface script file */
+ int tag; /* Status tag value */
+
+
+ if (p)
+ {
+ /*
+ * The POD status file is needed for the printstatus window to
+ * provide the current status of the printer.
+ */
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
+
+ if (p->type & CUPS_PRINTER_CLASS)
+ unlink(filename);
+ else if ((fp = cupsFileOpen(filename, "w")) != NULL)
+ {
+ cupsFilePrintf(fp, "Operational Status | %s\n",
+ (p->state == IPP_PRINTER_IDLE) ? "Idle" :
+ (p->state == IPP_PRINTER_PROCESSING) ? "Busy" :
+ "Faulted");
+ cupsFilePrintf(fp, "Information | 01 00 00 | %s\n", CUPS_SVERSION);
+ cupsFilePrintf(fp, "Information | 02 00 00 | Device URI: %s\n",
+ p->device_uri);
+ cupsFilePrintf(fp, "Information | 03 00 00 | %s jobs\n",
+ p->accepting ? "Accepting" : "Not accepting");
+ cupsFilePrintf(fp, "Information | 04 00 00 | %s\n", p->state_message);
+
+ cupsFileClose(fp);
+
+ chmod(filename, 0664);
+ chown(filename, User, Group);
+ }
+
+ /*
+ * The activeicons file is needed to provide desktop icons for printers:
+ *
+ * [ quoted from /usr/lib/print/tagit ]
+ *
+ * --- Type of printer tags (base values)
+ *
+ * Dumb=66048 # 0x10200
+ * DumbColor=66080 # 0x10220
+ * Raster=66112 # 0x10240
+ * ColorRaster=66144 # 0x10260
+ * Plotter=66176 # 0x10280
+ * PostScript=66208 # 0x102A0
+ * ColorPostScript=66240 # 0x102C0
+ * MonoPostScript=66272 # 0x102E0
+ *
+ * --- Printer state modifiers for local printers
+ *
+ * Idle=0 # 0x0
+ * Busy=1 # 0x1
+ * Faulted=2 # 0x2
+ * Unknown=3 # 0x3 (Faulted due to unknown reason)
+ *
+ * --- Printer state modifiers for network printers
+ *
+ * NetIdle=8 # 0x8
+ * NetBusy=9 # 0x9
+ * NetFaulted=10 # 0xA
+ * NetUnknown=11 # 0xB (Faulted due to unknown reason)
+ */
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
+
+ if (p->type & CUPS_PRINTER_CLASS)
+ unlink(filename);
+ else if ((fp = cupsFileOpen(filename, "w")) != NULL)
+ {
+ if (p->type & CUPS_PRINTER_COLOR)
+ tag = 66240;
+ else
+ tag = 66272;
+
+ if (p->type & CUPS_PRINTER_REMOTE)
+ tag |= 8;
+
+ if (p->state == IPP_PRINTER_PROCESSING)
+ tag |= 1;
+
+ else if (p->state == IPP_PRINTER_STOPPED)
+ tag |= 2;
+
+ cupsFilePuts(fp, "#!/bin/sh\n");
+ cupsFilePrintf(fp, "#Tag %d\n", tag);
+
+ cupsFileClose(fp);
+
+ chmod(filename, 0755);
+ chown(filename, User, Group);
+ }
+ }
+
+ /*
+ * The default file is needed by the printers window to show
+ * the default printer.
+ */
+
+ snprintf(filename, sizeof(filename), "/var/spool/lp/default");
+
+ if (DefaultPrinter != NULL)
+ {
+ if ((fp = cupsFileOpen(filename, "w")) != NULL)
+ {
+ cupsFilePrintf(fp, "%s\n", DefaultPrinter->name);
+
+ cupsFileClose(fp);
+
+ chmod(filename, 0644);
+ chown(filename, User, Group);
+ }
+ }
+ else
+ unlink(filename);
+}
+#endif /* __sgi */
+
+
+/*
+ * 'write_xml_string()' - Write a string with XML escaping.
+ */
+
+static void
+write_xml_string(cups_file_t *fp, /* I - File to write to */
+ const char *s) /* I - String to write */
+{
+ const char *start; /* Start of current sequence */
+
+
+ if (!s)
+ return;
+
+ for (start = s; *s; s ++)
+ {
+ if (*s == '&')
+ {
+ if (s > start)
+ cupsFileWrite(fp, start, s - start);
+
+ cupsFilePuts(fp, "&amp;");
+ start = s + 1;
+ }
+ else if (*s == '<')
+ {
+ if (s > start)
+ cupsFileWrite(fp, start, s - start);
+
+ cupsFilePuts(fp, "&lt;");
+ start = s + 1;
+ }
+ }
+
+ if (s > start)
+ cupsFilePuts(fp, start);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/printers.h b/scheduler/printers.h
new file mode 100644
index 000000000..1751578bf
--- /dev/null
+++ b/scheduler/printers.h
@@ -0,0 +1,177 @@
+/*
+ * "$Id$"
+ *
+ * Printer definitions for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifdef HAVE_DNSSD
+# include <dns_sd.h>
+#endif /* HAVE_DNSSD */
+#include <cups/pwg-private.h>
+
+
+/*
+ * Quota data...
+ */
+
+typedef struct
+{
+ char username[33]; /* User data */
+ time_t next_update; /* Next update time */
+ int page_count, /* Count of pages */
+ k_count; /* Count of kilobytes */
+} cupsd_quota_t;
+
+
+/*
+ * Printer/class information structure...
+ */
+
+typedef struct cupsd_job_s cupsd_job_t;
+
+struct cupsd_printer_s
+{
+ char *uri, /* Printer URI */
+ *uuid, /* Printer UUID */
+ *hostname, /* Host printer resides on */
+ *name, /* Printer name */
+ *location, /* Location code */
+ *make_model, /* Make and model */
+ *info, /* Description */
+ *op_policy, /* Operation policy name */
+ *error_policy; /* Error policy */
+ cupsd_policy_t *op_policy_ptr; /* Pointer to operation policy */
+ int shared; /* Shared? */
+ int accepting; /* Accepting jobs? */
+ int holding_new_jobs; /* Holding new jobs for printing? */
+ int in_implicit_class; /* In an implicit class? */
+ ipp_pstate_t state; /* Printer state */
+ char state_message[1024]; /* Printer state message */
+ int num_reasons; /* Number of printer-state-reasons */
+ char *reasons[64]; /* printer-state-reasons strings */
+ time_t state_time; /* Time at this state */
+ char *job_sheets[2]; /* Banners/job sheets */
+ cups_ptype_t type; /* Printer type (color, small, etc.) */
+ char *browse_attrs; /* Attributes sent with browse data */
+ time_t browse_expire; /* Expiration time for printer */
+ time_t browse_time; /* Last time update was sent/received */
+ char *device_uri; /* Device URI */
+ char *sanitized_device_uri; /* Sanitized device URI */
+ char *port_monitor; /* Port monitor */
+ int raw; /* Raw queue? */
+ int remote; /* Remote queue? */
+ mime_type_t *filetype, /* Pseudo-filetype for printer */
+ *prefiltertype; /* Pseudo-filetype for pre-filters */
+ cups_array_t *filetypes, /* Supported file types */
+ *dest_types; /* Destination types for queue */
+ cupsd_job_t *job; /* Current job in queue */
+ ipp_t *attrs, /* Attributes supported by this printer */
+ *ppd_attrs; /* Attributes based on the PPD */
+ int num_printers, /* Number of printers in class */
+ last_printer; /* Last printer job was sent to */
+ struct cupsd_printer_s **printers; /* Printers in class */
+ int quota_period, /* Period for quotas */
+ page_limit, /* Maximum number of pages */
+ k_limit; /* Maximum number of kilobytes */
+ cups_array_t *quotas; /* Quota records */
+ int deny_users; /* 1 = deny, 0 = allow */
+ cups_array_t *users; /* Allowed/denied users */
+ int sequence_number; /* Increasing sequence number */
+ int num_options; /* Number of default options */
+ cups_option_t *options; /* Default options */
+ int num_auth_info_required; /* Number of required auth fields */
+ const char *auth_info_required[4]; /* Required authentication fields */
+ char *alert, /* PSX printer-alert value */
+ *alert_description; /* PSX printer-alert-description value */
+ time_t marker_time; /* Last time marker attributes were updated */
+ _ppd_cache_t *pc; /* PPD cache and mapping data */
+
+#ifdef HAVE_DNSSD
+ char *reg_name, /* Name used for service registration */
+ *pdl, /* pdl value for TXT record */
+ *ipp_txt, /* IPP TXT record contents */
+ *printer_txt; /* LPD TXT record contents */
+ int ipp_len, /* IPP TXT record length */
+ printer_len; /* LPD TXT record length */
+ DNSServiceRef ipp_ref, /* Reference for _ipp._tcp,_cups */
+ printer_ref; /* Reference for _printer._tcp */
+#endif /* HAVE_DNSSD */
+};
+
+
+/*
+ * Globals...
+ */
+
+VAR ipp_t *CommonData VALUE(NULL);
+ /* Common printer object attrs */
+VAR cups_array_t *CommonDefaults VALUE(NULL);
+ /* Common -default option names */
+VAR cups_array_t *Printers VALUE(NULL),
+ /* Printer list */
+ *ImplicitPrinters VALUE(NULL);
+ /* Implicit class printers */
+VAR cupsd_printer_t *DefaultPrinter VALUE(NULL);
+ /* Default printer */
+VAR char *DefaultPolicy VALUE(NULL);
+ /* Default policy name */
+VAR cupsd_policy_t *DefaultPolicyPtr
+ VALUE(NULL);
+ /* Pointer to default policy */
+
+
+/*
+ * Prototypes...
+ */
+
+extern cupsd_printer_t *cupsdAddPrinter(const char *name);
+extern void cupsdCreateCommonData(void);
+extern void cupsdDeleteAllPrinters(void);
+extern int cupsdDeletePrinter(cupsd_printer_t *p, int update);
+extern cupsd_printer_t *cupsdFindDest(const char *name);
+extern cupsd_printer_t *cupsdFindPrinter(const char *name);
+extern cupsd_quota_t *cupsdFindQuota(cupsd_printer_t *p,
+ const char *username);
+extern void cupsdFreeQuotas(cupsd_printer_t *p);
+extern void cupsdLoadAllPrinters(void);
+extern void cupsdRenamePrinter(cupsd_printer_t *p,
+ const char *name);
+extern void cupsdSaveAllPrinters(void);
+extern int cupsdSetAuthInfoRequired(cupsd_printer_t *p,
+ const char *values,
+ ipp_attribute_t *attr);
+extern void cupsdSetDeviceURI(cupsd_printer_t *p, const char *uri);
+extern void cupsdSetPrinterAttr(cupsd_printer_t *p,
+ const char *name, char *value);
+extern void cupsdSetPrinterAttrs(cupsd_printer_t *p);
+extern int cupsdSetPrinterReasons(cupsd_printer_t *p,
+ const char *s);
+extern void cupsdSetPrinterState(cupsd_printer_t *p, ipp_pstate_t s,
+ int update);
+#define cupsdStartPrinter(p,u) cupsdSetPrinterState((p), IPP_PRINTER_IDLE, (u))
+extern void cupsdStopPrinter(cupsd_printer_t *p, int update);
+extern int cupsdUpdatePrinterPPD(cupsd_printer_t *p,
+ int num_keywords,
+ cups_option_t *keywords);
+extern void cupsdUpdatePrinters(void);
+extern cupsd_quota_t *cupsdUpdateQuota(cupsd_printer_t *p,
+ const char *username, int pages,
+ int k);
+extern const char *cupsdValidateDest(const char *uri,
+ cups_ptype_t *dtype,
+ cupsd_printer_t **printer);
+extern void cupsdWritePrintcap(void);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/process.c b/scheduler/process.c
new file mode 100644
index 000000000..cceb5f471
--- /dev/null
+++ b/scheduler/process.c
@@ -0,0 +1,656 @@
+/*
+ * "$Id$"
+ *
+ * Process management routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdCreateProfile() - Create an execution profile for a subprocess.
+ * cupsdDestroyProfile() - Delete an execution profile.
+ * cupsdEndProcess() - End a process.
+ * cupsdFinishProcess() - Finish a process and get its name.
+ * cupsdStartProcess() - Start a process.
+ * compare_procs() - Compare two processes.
+ * cupsd_requote() - Make a regular-expression version of a string.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <grp.h>
+#ifdef __APPLE__
+# include <libgen.h>
+#endif /* __APPLE__ */
+
+
+/*
+ * Process structure...
+ */
+
+typedef struct
+{
+ int pid, /* Process ID */
+ job_id; /* Job associated with process */
+ char name[1]; /* Name of process */
+} cupsd_proc_t;
+
+
+/*
+ * Local globals...
+ */
+
+static cups_array_t *process_array = NULL;
+
+
+/*
+ * Local functions...
+ */
+
+static int compare_procs(cupsd_proc_t *a, cupsd_proc_t *b);
+#ifdef HAVE_SANDBOX_H
+static char *cupsd_requote(char *dst, const char *src, size_t dstsize);
+#endif /* HAVE_SANDBOX_H */
+
+
+/*
+ * 'cupsdCreateProfile()' - Create an execution profile for a subprocess.
+ */
+
+void * /* O - Profile or NULL on error */
+cupsdCreateProfile(int job_id) /* I - Job ID or 0 for none */
+{
+#ifdef HAVE_SANDBOX_H
+ cups_file_t *fp; /* File pointer */
+ char profile[1024], /* File containing the profile */
+ cache[1024], /* Quoted CacheDir */
+ request[1024], /* Quoted RequestRoot */
+ root[1024], /* Quoted ServerRoot */
+ temp[1024]; /* Quoted TempDir */
+ const char *nodebug; /* " (with no-log)" for no debug */
+
+
+ if (!UseProfiles)
+ {
+ /*
+ * Only use sandbox profiles as root...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = NULL",
+ job_id);
+
+ return (NULL);
+ }
+
+ if ((fp = cupsTempFile2(profile, sizeof(profile))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = NULL",
+ job_id);
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create security profile: %s",
+ strerror(errno));
+ return (NULL);
+ }
+
+ fchown(cupsFileNumber(fp), RunUser, Group);
+ fchmod(cupsFileNumber(fp), 0640);
+
+ cupsd_requote(cache, CacheDir, sizeof(cache));
+ cupsd_requote(request, RequestRoot, sizeof(request));
+ cupsd_requote(root, ServerRoot, sizeof(root));
+ cupsd_requote(temp, TempDir, sizeof(temp));
+
+ nodebug = LogLevel < CUPSD_LOG_DEBUG ? " (with no-log)" : "";
+
+ cupsFilePuts(fp, "(version 1)\n");
+ cupsFilePuts(fp, "(allow default)\n");
+ cupsFilePrintf(fp,
+ "(deny file-write* file-read-data file-read-metadata\n"
+ " (regex"
+ " #\"^%s$\"" /* RequestRoot */
+ " #\"^%s/\"" /* RequestRoot/... */
+ ")%s)\n",
+ request, request, nodebug);
+ if (!RunUser)
+ cupsFilePrintf(fp,
+ "(deny file-write* file-read-data file-read-metadata\n"
+ " (regex"
+ " #\"^/Users$\""
+ " #\"^/Users/\""
+ ")%s)\n", nodebug);
+ cupsFilePrintf(fp,
+ "(deny file-write*\n"
+ " (regex"
+ " #\"^%s$\"" /* ServerRoot */
+ " #\"^%s/\"" /* ServerRoot/... */
+ " #\"^/private/etc$\""
+ " #\"^/private/etc/\""
+ " #\"^/usr/local/etc$\""
+ " #\"^/usr/local/etc/\""
+ " #\"^/Library$\""
+ " #\"^/Library/\""
+ " #\"^/System$\""
+ " #\"^/System/\""
+ ")%s)\n",
+ root, root, nodebug);
+ /* Specifically allow applications to stat RequestRoot */
+ cupsFilePrintf(fp,
+ "(allow file-read-metadata\n"
+ " (regex"
+ " #\"^%s$\"" /* RequestRoot */
+ "))\n",
+ request);
+ cupsFilePrintf(fp,
+ "(allow file-write* file-read-data file-read-metadata\n"
+ " (regex"
+ " #\"^%s$\"" /* TempDir */
+ " #\"^%s/\"" /* TempDir/... */
+ " #\"^%s$\"" /* CacheDir */
+ " #\"^%s/\"" /* CacheDir/... */
+ " #\"^%s/Library$\"" /* RequestRoot/Library */
+ " #\"^%s/Library/\"" /* RequestRoot/Library/... */
+ " #\"^/Library/Application Support/\""
+ " #\"^/Library/Caches/\""
+ " #\"^/Library/Preferences/\""
+ " #\"^/Library/Printers/.*/\""
+ " #\"^/Users/Shared/\""
+ "))\n",
+ temp, temp, cache, cache, request, request);
+ cupsFilePrintf(fp,
+ "(deny file-write*\n"
+ " (regex"
+ " #\"^/Library/Printers/PPDs$\""
+ " #\"^/Library/Printers/PPDs/\""
+ " #\"^/Library/Printers/PPD Plugins$\""
+ " #\"^/Library/Printers/PPD Plugins/\""
+ ")%s)\n", nodebug);
+ if (job_id)
+ {
+ /*
+ * Allow job filters to read the spool file(s)...
+ */
+
+ cupsFilePrintf(fp,
+ "(allow file-read-data file-read-metadata\n"
+ " (regex #\"^%s/([ac]%05d|d%05d-[0-9][0-9][0-9])$\"))\n",
+ request, job_id, job_id);
+ }
+ else
+ {
+ /*
+ * Allow email notifications from notifiers...
+ */
+
+ cupsFilePuts(fp,
+ "(allow process-exec\n"
+ " (literal \"/usr/sbin/sendmail\")\n"
+ " (with no-sandbox)\n"
+ ")\n");
+ }
+
+ cupsFileClose(fp);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = \"%s\"",
+ job_id, profile);
+ return ((void *)strdup(profile));
+
+#else
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = NULL",
+ job_id);
+
+ return (NULL);
+#endif /* HAVE_SANDBOX_H */
+}
+
+
+/*
+ * 'cupsdDestroyProfile()' - Delete an execution profile.
+ */
+
+void
+cupsdDestroyProfile(void *profile) /* I - Profile */
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeleteProfile(profile=\"%s\")",
+ profile ? (char *)profile : "(null)");
+
+#ifdef HAVE_SANDBOX_H
+ if (profile)
+ {
+ unlink((char *)profile);
+ free(profile);
+ }
+#endif /* HAVE_SANDBOX_H */
+}
+
+
+/*
+ * 'cupsdEndProcess()' - End a process.
+ */
+
+int /* O - 0 on success, -1 on failure */
+cupsdEndProcess(int pid, /* I - Process ID */
+ int force) /* I - Force child to die */
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdEndProcess(pid=%d, force=%d)", pid,
+ force);
+
+ if (!pid)
+ return (0);
+
+ if (!RunUser)
+ {
+ /*
+ * When running as root, cupsd puts child processes in their own process
+ * group. Using "-pid" sends a signal to all processes in the group.
+ */
+
+ pid = -pid;
+ }
+
+ if (force)
+ return (kill(pid, SIGKILL));
+ else
+ return (kill(pid, SIGTERM));
+}
+
+
+/*
+ * 'cupsdFinishProcess()' - Finish a process and get its name.
+ */
+
+const char * /* O - Process name */
+cupsdFinishProcess(int pid, /* I - Process ID */
+ char *name, /* I - Name buffer */
+ int namelen, /* I - Size of name buffer */
+ int *job_id) /* O - Job ID pointer or NULL */
+{
+ cupsd_proc_t key, /* Search key */
+ *proc; /* Matching process */
+
+
+ key.pid = pid;
+
+ if ((proc = (cupsd_proc_t *)cupsArrayFind(process_array, &key)) != NULL)
+ {
+ if (job_id)
+ *job_id = proc->job_id;
+
+ strlcpy(name, proc->name, namelen);
+ cupsArrayRemove(process_array, proc);
+ free(proc);
+ }
+ else
+ {
+ if (job_id)
+ *job_id = 0;
+
+ strlcpy(name, "unknown", namelen);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdFinishProcess(pid=%d, name=%p, namelen=%d, "
+ "job_id=%p(%d)) = \"%s\"", pid, name, namelen, job_id,
+ job_id ? *job_id : 0, name);
+
+ return (name);
+}
+
+
+/*
+ * 'cupsdStartProcess()' - Start a process.
+ */
+
+int /* O - Process ID or 0 */
+cupsdStartProcess(
+ const char *command, /* I - Full path to command */
+ char *argv[], /* I - Command-line arguments */
+ char *envp[], /* I - Environment */
+ int infd, /* I - Standard input file descriptor */
+ int outfd, /* I - Standard output file descriptor */
+ int errfd, /* I - Standard error file descriptor */
+ int backfd, /* I - Backchannel file descriptor */
+ int sidefd, /* I - Sidechannel file descriptor */
+ int root, /* I - Run as root? */
+ void *profile, /* I - Security profile to use */
+ cupsd_job_t *job, /* I - Job associated with process */
+ int *pid) /* O - Process ID */
+{
+ int i; /* Looping var */
+ const char *exec_path = command; /* Command to be exec'd */
+ char *real_argv[103], /* Real command-line arguments */
+ cups_exec[1024]; /* Path to "cups-exec" program */
+ int user; /* Command UID */
+ cupsd_proc_t *proc; /* New process record */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* POSIX signal handler */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+#if defined(__APPLE__)
+ char processPath[1024], /* CFProcessPath environment variable */
+ linkpath[1024]; /* Link path for symlinks... */
+ int linkbytes; /* Bytes for link path */
+#endif /* __APPLE__ */
+
+
+ *pid = 0;
+
+ /*
+ * Figure out the UID for the child process...
+ */
+
+ if (RunUser)
+ user = RunUser;
+ else if (root)
+ user = 0;
+ else
+ user = User;
+
+ /*
+ * Check the permissions of the command we are running...
+ */
+
+ if (_cupsFileCheck(command, _CUPS_FILE_CHECK_PROGRAM, !RunUser,
+ cupsdLogFCMessage, job ? job->printer : NULL))
+ return (0);
+
+#if defined(__APPLE__)
+ if (envp)
+ {
+ /*
+ * Add special voodoo magic for Mac OS X - this allows Mac OS X
+ * programs to access their bundle resources properly...
+ */
+
+ if ((linkbytes = readlink(command, linkpath, sizeof(linkpath) - 1)) > 0)
+ {
+ /*
+ * Yes, this is a symlink to the actual program, nul-terminate and
+ * use it...
+ */
+
+ linkpath[linkbytes] = '\0';
+
+ if (linkpath[0] == '/')
+ snprintf(processPath, sizeof(processPath), "CFProcessPath=%s",
+ linkpath);
+ else
+ snprintf(processPath, sizeof(processPath), "CFProcessPath=%s/%s",
+ dirname((char *)command), linkpath);
+ }
+ else
+ snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", command);
+
+ envp[0] = processPath; /* Replace <CFProcessPath> string */
+ }
+#endif /* __APPLE__ */
+
+ /*
+ * Use helper program when we have a sandbox profile...
+ */
+
+ if (profile)
+ {
+ snprintf(cups_exec, sizeof(cups_exec), "%s/daemon/cups-exec", ServerBin);
+
+ real_argv[0] = cups_exec;
+ real_argv[1] = profile;
+ real_argv[2] = (char *)command;
+
+ for (i = 0;
+ i < (int)(sizeof(real_argv) / sizeof(real_argv[0]) - 4) && argv[i];
+ i ++)
+ real_argv[i + 3] = argv[i];
+
+ real_argv[i + 3] = NULL;
+
+ argv = real_argv;
+ exec_path = cups_exec;
+ }
+
+ /*
+ * Block signals before forking...
+ */
+
+ cupsdHoldSignals();
+
+ if ((*pid = fork()) == 0)
+ {
+ /*
+ * Child process goes here; update stderr as needed...
+ */
+
+ if (errfd != 2)
+ {
+ if (errfd < 0)
+ errfd = open("/dev/null", O_WRONLY);
+
+ if (errfd != 2)
+ {
+ dup2(errfd, 2);
+ close(errfd);
+ }
+ }
+
+ /*
+ * Put this process in its own process group so that we can kill any child
+ * processes it creates.
+ */
+
+#ifdef HAVE_SETPGID
+ if (!RunUser && setpgid(0, 0))
+ exit(errno + 100);
+#else
+ if (!RunUser && setpgrp())
+ exit(errno + 100);
+#endif /* HAVE_SETPGID */
+
+ /*
+ * Update the remaining file descriptors as needed...
+ */
+
+ if (infd != 0)
+ {
+ if (infd < 0)
+ infd = open("/dev/null", O_RDONLY);
+
+ if (infd != 0)
+ {
+ dup2(infd, 0);
+ close(infd);
+ }
+ }
+
+ if (outfd != 1)
+ {
+ if (outfd < 0)
+ outfd = open("/dev/null", O_WRONLY);
+
+ if (outfd != 1)
+ {
+ dup2(outfd, 1);
+ close(outfd);
+ }
+ }
+
+ if (backfd != 3 && backfd >= 0)
+ {
+ dup2(backfd, 3);
+ close(backfd);
+ fcntl(3, F_SETFL, O_NDELAY);
+ }
+
+ if (sidefd != 4 && sidefd >= 0)
+ {
+ dup2(sidefd, 4);
+ close(sidefd);
+ fcntl(4, F_SETFL, O_NDELAY);
+ }
+
+ /*
+ * Change the priority of the process based on the FilterNice setting.
+ * (this is not done for root processes...)
+ */
+
+ if (!root)
+ nice(FilterNice);
+
+ /*
+ * Reset group membership to just the main one we belong to.
+ */
+
+ if (!RunUser && setgid(Group))
+ exit(errno + 100);
+
+ if (!RunUser && setgroups(1, &Group))
+ exit(errno + 100);
+
+ /*
+ * Change user to something "safe"...
+ */
+
+ if (!RunUser && user && setuid(user))
+ exit(errno + 100);
+
+ /*
+ * Change umask to restrict permissions on created files...
+ */
+
+ umask(077);
+
+ /*
+ * Unblock signals before doing the exec...
+ */
+
+#ifdef HAVE_SIGSET
+ sigset(SIGTERM, SIG_DFL);
+ sigset(SIGCHLD, SIG_DFL);
+ sigset(SIGPIPE, SIG_DFL);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_DFL;
+
+ sigaction(SIGTERM, &action, NULL);
+ sigaction(SIGCHLD, &action, NULL);
+ sigaction(SIGPIPE, &action, NULL);
+#else
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGCHLD, SIG_DFL);
+ signal(SIGPIPE, SIG_DFL);
+#endif /* HAVE_SIGSET */
+
+ cupsdReleaseSignals();
+
+ /*
+ * Execute the command; if for some reason this doesn't work, log an error
+ * exit with a non-zero value...
+ */
+
+ if (envp)
+ execve(exec_path, argv, envp);
+ else
+ execv(exec_path, argv);
+
+ exit(errno + 100);
+ }
+ else if (*pid < 0)
+ {
+ /*
+ * Error - couldn't fork a new process!
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to fork %s - %s.", command,
+ strerror(errno));
+
+ *pid = 0;
+ }
+ else
+ {
+ if (!process_array)
+ process_array = cupsArrayNew((cups_array_func_t)compare_procs, NULL);
+
+ if (process_array)
+ {
+ if ((proc = calloc(1, sizeof(cupsd_proc_t) + strlen(command))) != NULL)
+ {
+ proc->pid = *pid;
+ proc->job_id = job ? job->id : 0;
+ _cups_strcpy(proc->name, command);
+
+ cupsArrayAdd(process_array, proc);
+ }
+ }
+ }
+
+ cupsdReleaseSignals();
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdStartProcess(command=\"%s\", argv=%p, envp=%p, "
+ "infd=%d, outfd=%d, errfd=%d, backfd=%d, sidefd=%d, root=%d, "
+ "profile=%p, job=%p(%d), pid=%p) = %d",
+ command, argv, envp, infd, outfd, errfd, backfd, sidefd,
+ root, profile, job, job ? job->id : 0, pid, *pid);
+
+ return (*pid);
+}
+
+
+/*
+ * 'compare_procs()' - Compare two processes.
+ */
+
+static int /* O - Result of comparison */
+compare_procs(cupsd_proc_t *a, /* I - First process */
+ cupsd_proc_t *b) /* I - Second process */
+{
+ return (a->pid - b->pid);
+}
+
+
+#ifdef HAVE_SANDBOX_H
+/*
+ * 'cupsd_requote()' - Make a regular-expression version of a string.
+ */
+
+static char * /* O - Quoted string */
+cupsd_requote(char *dst, /* I - Destination buffer */
+ const char *src, /* I - Source string */
+ size_t dstsize) /* I - Size of destination buffer */
+{
+ int ch; /* Current character */
+ char *dstptr, /* Current position in buffer */
+ *dstend; /* End of destination buffer */
+
+
+ dstptr = dst;
+ dstend = dst + dstsize - 2;
+
+ while (*src && dstptr < dstend)
+ {
+ ch = *src++;
+
+ if (strchr(".?*()[]^$\\", ch))
+ *dstptr++ = '\\';
+
+ *dstptr++ = ch;
+ }
+
+ *dstptr = '\0';
+
+ return (dst);
+}
+#endif /* HAVE_SANDBOX_H */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/quotas.c b/scheduler/quotas.c
new file mode 100644
index 000000000..9f0b6c0a3
--- /dev/null
+++ b/scheduler/quotas.c
@@ -0,0 +1,244 @@
+/*
+ * "$Id$"
+ *
+ * Quota routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdFindQuota() - Find a quota record.
+ * cupsdFreeQuotas() - Free quotas for a printer.
+ * cupsdUpdateQuota() - Update quota data for the specified printer and user.
+ * add_quota() - Add a quota record for this printer and user.
+ * compare_quotas() - Compare two quota records...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+
+/*
+ * Local functions...
+ */
+
+static cupsd_quota_t *add_quota(cupsd_printer_t *p, const char *username);
+static int compare_quotas(const cupsd_quota_t *q1,
+ const cupsd_quota_t *q2);
+
+
+/*
+ * 'cupsdFindQuota()' - Find a quota record.
+ */
+
+cupsd_quota_t * /* O - Quota data */
+cupsdFindQuota(
+ cupsd_printer_t *p, /* I - Printer */
+ const char *username) /* I - User */
+{
+ cupsd_quota_t *q, /* Quota data pointer */
+ match; /* Search data */
+ char *ptr; /* Pointer into username */
+
+
+ if (!p || !username)
+ return (NULL);
+
+ strlcpy(match.username, username, sizeof(match.username));
+ if ((ptr = strchr(match.username, '@')) != NULL)
+ *ptr = '\0'; /* Strip @domain/@KDC */
+
+ if ((q = (cupsd_quota_t *)cupsArrayFind(p->quotas, &match)) != NULL)
+ return (q);
+ else
+ return (add_quota(p, username));
+}
+
+
+/*
+ * 'cupsdFreeQuotas()' - Free quotas for a printer.
+ */
+
+void
+cupsdFreeQuotas(cupsd_printer_t *p) /* I - Printer */
+{
+ cupsd_quota_t *q; /* Current quota record */
+
+
+ if (!p)
+ return;
+
+ for (q = (cupsd_quota_t *)cupsArrayFirst(p->quotas);
+ q;
+ q = (cupsd_quota_t *)cupsArrayNext(p->quotas))
+ free(q);
+
+ cupsArrayDelete(p->quotas);
+
+ p->quotas = NULL;
+}
+
+
+/*
+ * 'cupsdUpdateQuota()' - Update quota data for the specified printer and user.
+ */
+
+cupsd_quota_t * /* O - Quota data */
+cupsdUpdateQuota(
+ cupsd_printer_t *p, /* I - Printer */
+ const char *username, /* I - User */
+ int pages, /* I - Number of pages */
+ int k) /* I - Number of kilobytes */
+{
+ cupsd_quota_t *q; /* Quota data */
+ cupsd_job_t *job; /* Current job */
+ time_t curtime; /* Current time */
+ ipp_attribute_t *attr; /* Job attribute */
+
+
+ if (!p || !username)
+ return (NULL);
+
+ if (!p->k_limit && !p->page_limit)
+ return (NULL);
+
+ if ((q = cupsdFindQuota(p, username)) == NULL)
+ return (NULL);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdUpdateQuota: p=%s username=%s pages=%d k=%d",
+ p->name, username, pages, k);
+
+ curtime = time(NULL);
+
+ if (curtime < q->next_update)
+ {
+ q->page_count += pages;
+ q->k_count += k;
+
+ return (q);
+ }
+
+ if (p->quota_period)
+ curtime -= p->quota_period;
+ else
+ curtime = 0;
+
+ q->next_update = 0;
+ q->page_count = 0;
+ q->k_count = 0;
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(Jobs))
+ {
+ /*
+ * We only care about the current printer/class and user...
+ */
+
+ if (_cups_strcasecmp(job->dest, p->name) != 0 ||
+ _cups_strcasecmp(job->username, q->username) != 0)
+ continue;
+
+ /*
+ * Make sure attributes are loaded; we always call cupsdLoadJob() to ensure
+ * the access_time member is updated so the job isn't unloaded right away...
+ */
+
+ if (!cupsdLoadJob(job))
+ continue;
+
+ if ((attr = ippFindAttribute(job->attrs, "time-at-completion",
+ IPP_TAG_INTEGER)) == NULL)
+ if ((attr = ippFindAttribute(job->attrs, "time-at-processing",
+ IPP_TAG_INTEGER)) == NULL)
+ attr = ippFindAttribute(job->attrs, "time-at-creation",
+ IPP_TAG_INTEGER);
+
+ if (attr->values[0].integer < curtime)
+ {
+ /*
+ * This job is too old to count towards the quota, ignore it...
+ */
+
+ if (JobAutoPurge && !job->printer && job->state_value > IPP_JOB_STOPPED)
+ cupsdDeleteJob(job, CUPSD_JOB_PURGE);
+
+ continue;
+ }
+
+ if (q->next_update == 0)
+ q->next_update = attr->values[0].integer + p->quota_period;
+
+ if ((attr = ippFindAttribute(job->attrs, "job-media-sheets-completed",
+ IPP_TAG_INTEGER)) != NULL)
+ q->page_count += attr->values[0].integer;
+
+ if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
+ IPP_TAG_INTEGER)) != NULL)
+ q->k_count += attr->values[0].integer;
+ }
+
+ return (q);
+}
+
+
+/*
+ * 'add_quota()' - Add a quota record for this printer and user.
+ */
+
+static cupsd_quota_t * /* O - Quota data */
+add_quota(cupsd_printer_t *p, /* I - Printer */
+ const char *username) /* I - User */
+{
+ cupsd_quota_t *q; /* New quota data */
+ char *ptr; /* Pointer into username */
+
+
+ if (!p || !username)
+ return (NULL);
+
+ if (!p->quotas)
+ p->quotas = cupsArrayNew((cups_array_func_t)compare_quotas, NULL);
+
+ if (!p->quotas)
+ return (NULL);
+
+ if ((q = calloc(1, sizeof(cupsd_quota_t))) == NULL)
+ return (NULL);
+
+ strlcpy(q->username, username, sizeof(q->username));
+ if ((ptr = strchr(q->username, '@')) != NULL)
+ *ptr = '\0'; /* Strip @domain/@KDC */
+
+ cupsArrayAdd(p->quotas, q);
+
+ return (q);
+}
+
+
+/*
+ * 'compare_quotas()' - Compare two quota records...
+ */
+
+static int /* O - Result of comparison */
+compare_quotas(const cupsd_quota_t *q1, /* I - First quota record */
+ const cupsd_quota_t *q2) /* I - Second quota record */
+{
+ return (_cups_strcasecmp(q1->username, q2->username));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/select.c b/scheduler/select.c
new file mode 100644
index 000000000..15a3a532c
--- /dev/null
+++ b/scheduler/select.c
@@ -0,0 +1,951 @@
+/*
+ * "$Id$"
+ *
+ * Select abstraction functions for the CUPS scheduler.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2006-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdAddSelect() - Add a file descriptor to the list.
+ * cupsdDoSelect() - Do a select-like operation.
+ * cupsdIsSelecting() - Determine whether we are monitoring a file
+ * descriptor.
+ * cupsdRemoveSelect() - Remove a file descriptor from the list.
+ * cupsdStartSelect() - Initialize the file polling engine.
+ * cupsdStopSelect() - Shutdown the file polling engine.
+ * compare_fds() - Compare file descriptors.
+ * find_fd() - Find an existing file descriptor record.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+#ifdef HAVE_EPOLL
+# include <sys/epoll.h>
+# include <sys/poll.h>
+#elif defined(HAVE_KQUEUE)
+# include <sys/event.h>
+# include <sys/time.h>
+#elif defined(HAVE_POLL)
+# include <sys/poll.h>
+#elif defined(__hpux)
+# include <sys/time.h>
+#else
+# include <sys/select.h>
+#endif /* HAVE_EPOLL */
+
+
+/*
+ * Design Notes for Poll/Select API in CUPSD
+ * -----------------------------------------
+ *
+ * SUPPORTED APIS
+ *
+ * OS select poll epoll kqueue /dev/poll
+ * -------------- ------ ------ ------ ------ ---------
+ * AIX YES YES NO NO NO
+ * FreeBSD YES YES NO YES NO
+ * HP-UX YES YES NO NO NO
+ * IRIX YES YES NO NO NO
+ * Linux YES YES YES NO NO
+ * MacOS X YES YES NO YES NO
+ * NetBSD YES YES NO YES NO
+ * OpenBSD YES YES NO YES NO
+ * Solaris YES YES NO NO YES
+ * Tru64 YES YES NO NO NO
+ * Windows YES NO NO NO NO
+ *
+ *
+ * HIGH-LEVEL API
+ *
+ * typedef void (*cupsd_selfunc_t)(void *data);
+ *
+ * void cupsdStartSelect(void);
+ * void cupsdStopSelect(void);
+ * void cupsdAddSelect(int fd, cupsd_selfunc_t read_cb,
+ * cupsd_selfunc_t write_cb, void *data);
+ * void cupsdRemoveSelect(int fd);
+ * int cupsdDoSelect(int timeout);
+ *
+ *
+ * IMPLEMENTATION STRATEGY
+ *
+ * 0. Common Stuff
+ * a. CUPS array of file descriptor to callback functions
+ * and data + temporary array of removed fd's.
+ * b. cupsdStartSelect() creates the arrays
+ * c. cupsdStopSelect() destroys the arrays and all elements.
+ * d. cupsdAddSelect() adds to the array and allocates a
+ * new callback element.
+ * e. cupsdRemoveSelect() removes from the active array and
+ * adds to the inactive array.
+ * f. _cupsd_fd_t provides a reference-counted structure for
+ * tracking file descriptors that are monitored.
+ * g. cupsdDoSelect() frees all inactive FDs.
+ *
+ * 1. select() O(n)
+ * a. Input/Output fd_set variables, copied to working
+ * copies and then used with select().
+ * b. Loop through CUPS array, using FD_ISSET and calling
+ * the read/write callbacks as needed.
+ * c. cupsdRemoveSelect() clears fd_set bit from main and
+ * working sets.
+ * d. cupsdStopSelect() frees all of the memory used by the
+ * CUPS array and fd_set's.
+ *
+ * 2. poll() - O(n log n)
+ * a. Regular array of pollfd, sorted the same as the CUPS
+ * array.
+ * b. Loop through pollfd array, call the corresponding
+ * read/write callbacks as needed.
+ * c. cupsdAddSelect() adds first to CUPS array and flags the
+ * pollfd array as invalid.
+ * d. cupsdDoSelect() rebuilds pollfd array as needed, calls
+ * poll(), then loops through the pollfd array looking up
+ * as needed.
+ * e. cupsdRemoveSelect() flags the pollfd array as invalid.
+ * f. cupsdStopSelect() frees all of the memory used by the
+ * CUPS array and pollfd array.
+ *
+ * 3. epoll() - O(n)
+ * a. cupsdStartSelect() creates epoll file descriptor using
+ * epoll_create() with the maximum fd count, and
+ * allocates an events buffer for the maximum fd count.
+ * b. cupsdAdd/RemoveSelect() uses epoll_ctl() to add
+ * (EPOLL_CTL_ADD) or remove (EPOLL_CTL_DEL) a single
+ * event using the level-triggered semantics. The event
+ * user data field is a pointer to the new callback array
+ * element.
+ * c. cupsdDoSelect() uses epoll_wait() with the global event
+ * buffer allocated in cupsdStartSelect() and then loops
+ * through the events, using the user data field to find
+ * the callback record.
+ * d. cupsdStopSelect() closes the epoll file descriptor and
+ * frees all of the memory used by the event buffer.
+ *
+ * 4. kqueue() - O(n)
+ * b. cupsdStartSelect() creates kqueue file descriptor
+ * using kqueue() function and allocates a global event
+ * buffer.
+ * c. cupsdAdd/RemoveSelect() uses EV_SET and kevent() to
+ * register the changes. The event user data field is a
+ * pointer to the new callback array element.
+ * d. cupsdDoSelect() uses kevent() to poll for events and
+ * loops through the events, using the user data field to
+ * find the callback record.
+ * e. cupsdStopSelect() closes the kqueue() file descriptor
+ * and frees all of the memory used by the event buffer.
+ *
+ * 5. /dev/poll - O(n log n) - NOT YET IMPLEMENTED
+ * a. cupsdStartSelect() opens /dev/poll and allocates an
+ * array of pollfd structs; on failure to open /dev/poll,
+ * revert to poll() system call.
+ * b. cupsdAddSelect() writes a single pollfd struct to
+ * /dev/poll with the new file descriptor and the
+ * POLLIN/POLLOUT flags.
+ * c. cupsdRemoveSelect() writes a single pollfd struct to
+ * /dev/poll with the file descriptor and the POLLREMOVE
+ * flag.
+ * d. cupsdDoSelect() uses the DP_POLL ioctl to retrieve
+ * events from /dev/poll and then loops through the
+ * returned pollfd array, looking up the file descriptors
+ * as needed.
+ * e. cupsdStopSelect() closes /dev/poll and frees the
+ * pollfd array.
+ *
+ * PERFORMANCE
+ *
+ * In tests using the "make test" target with option 0 (keep cupsd
+ * running) and the "testspeed" program with "-c 50 -r 1000", epoll()
+ * performed 5.5% slower than select(), followed by kqueue() at 16%
+ * slower than select() and poll() at 18% slower than select(). Similar
+ * results were seen with twice the number of client connections.
+ *
+ * The epoll() and kqueue() performance is likely limited by the
+ * number of system calls used to add/modify/remove file
+ * descriptors dynamically. Further optimizations may be possible
+ * in the area of limiting use of cupsdAddSelect() and
+ * cupsdRemoveSelect(), however extreme care will be needed to avoid
+ * excess CPU usage and deadlock conditions.
+ *
+ * We may be able to improve the poll() implementation simply by
+ * keeping the pollfd array sync'd with the _cupsd_fd_t array, as that
+ * will eliminate the rebuilding of the array whenever there is a
+ * change and eliminate the fd array lookups in the inner loop of
+ * cupsdDoSelect().
+ *
+ * Since /dev/poll will never be able to use a shadow array, it may
+ * not make sense to implement support for it. ioctl() overhead will
+ * impact performance as well, so my guess would be that, for CUPS,
+ * /dev/poll will yield a net performance loss.
+ */
+
+/*
+ * Local structures...
+ */
+
+typedef struct _cupsd_fd_s
+{
+ int fd, /* File descriptor */
+ use; /* Use count */
+ cupsd_selfunc_t read_cb, /* Read callback */
+ write_cb; /* Write callback */
+ void *data; /* Data pointer for callbacks */
+} _cupsd_fd_t;
+
+
+/*
+ * Local globals...
+ */
+
+static cups_array_t *cupsd_fds = NULL;
+#if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
+static cups_array_t *cupsd_inactive_fds = NULL;
+static int cupsd_in_select = 0;
+#endif /* HAVE_EPOLL || HAVE_KQUEUE */
+
+#ifdef HAVE_KQUEUE
+static int cupsd_kqueue_fd = -1,
+ cupsd_kqueue_changes = 0;
+static struct kevent *cupsd_kqueue_events = NULL;
+#elif defined(HAVE_POLL)
+static int cupsd_alloc_pollfds = 0,
+ cupsd_update_pollfds = 0;
+static struct pollfd *cupsd_pollfds = NULL;
+# ifdef HAVE_EPOLL
+static int cupsd_epoll_fd = -1;
+static struct epoll_event *cupsd_epoll_events = NULL;
+# endif /* HAVE_EPOLL */
+#else /* select() */
+static fd_set cupsd_global_input,
+ cupsd_global_output,
+ cupsd_current_input,
+ cupsd_current_output;
+#endif /* HAVE_KQUEUE */
+
+
+/*
+ * Local functions...
+ */
+
+static int compare_fds(_cupsd_fd_t *a, _cupsd_fd_t *b);
+static _cupsd_fd_t *find_fd(int fd);
+#define release_fd(f) { \
+ (f)->use --; \
+ if (!(f)->use) free((f));\
+ }
+#define retain_fd(f) (f)->use++
+
+
+/*
+ * 'cupsdAddSelect()' - Add a file descriptor to the list.
+ */
+
+int /* O - 1 on success, 0 on error */
+cupsdAddSelect(int fd, /* I - File descriptor */
+ cupsd_selfunc_t read_cb, /* I - Read callback */
+ cupsd_selfunc_t write_cb,/* I - Write callback */
+ void *data) /* I - Data to pass to callback */
+{
+ _cupsd_fd_t *fdptr; /* File descriptor record */
+#ifdef HAVE_EPOLL
+ int added; /* 1 if added, 0 if modified */
+#endif /* HAVE_EPOLL */
+
+
+ /*
+ * Range check input...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdAddSelect(fd=%d, read_cb=%p, write_cb=%p, data=%p)",
+ fd, read_cb, write_cb, data);
+
+ if (fd < 0)
+ return (0);
+
+ /*
+ * See if this FD has already been added...
+ */
+
+ if ((fdptr = find_fd(fd)) == NULL)
+ {
+ /*
+ * No, add a new entry...
+ */
+
+ if ((fdptr = calloc(1, sizeof(_cupsd_fd_t))) == NULL)
+ return (0);
+
+ fdptr->fd = fd;
+ fdptr->use = 1;
+
+ if (!cupsArrayAdd(cupsd_fds, fdptr))
+ {
+ cupsdLogMessage(CUPSD_LOG_EMERG, "Unable to add fd %d to array!", fd);
+ free(fdptr);
+ return (0);
+ }
+
+#ifdef HAVE_EPOLL
+ added = 1;
+ }
+ else
+ added = 0;
+#else
+ }
+#endif /* HAVE_EPOLL */
+
+#ifdef HAVE_KQUEUE
+ {
+ struct kevent event; /* Event data */
+ struct timespec timeout; /* Timeout value */
+
+
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 0;
+
+ if (fdptr->read_cb != read_cb)
+ {
+ if (read_cb)
+ EV_SET(&event, fd, EVFILT_READ, EV_ADD, 0, 0, fdptr);
+ else
+ EV_SET(&event, fd, EVFILT_READ, EV_DELETE, 0, 0, fdptr);
+
+ if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout))
+ {
+ cupsdLogMessage(CUPSD_LOG_EMERG, "kevent() returned %s",
+ strerror(errno));
+ return (0);
+ }
+ }
+
+ if (fdptr->write_cb != write_cb)
+ {
+ if (write_cb)
+ EV_SET(&event, fd, EVFILT_WRITE, EV_ADD, 0, 0, fdptr);
+ else
+ EV_SET(&event, fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdptr);
+
+ if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout))
+ {
+ cupsdLogMessage(CUPSD_LOG_EMERG, "kevent() returned %s",
+ strerror(errno));
+ return (0);
+ }
+ }
+ }
+
+#elif defined(HAVE_POLL)
+# ifdef HAVE_EPOLL
+ if (cupsd_epoll_fd >= 0)
+ {
+ struct epoll_event event; /* Event data */
+
+
+ event.events = 0;
+
+ if (read_cb)
+ event.events |= EPOLLIN;
+
+ if (write_cb)
+ event.events |= EPOLLOUT;
+
+ event.data.ptr = fdptr;
+
+ if (epoll_ctl(cupsd_epoll_fd, added ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd,
+ &event))
+ {
+ close(cupsd_epoll_fd);
+ cupsd_epoll_fd = -1;
+ cupsd_update_pollfds = 1;
+ }
+ }
+ else
+# endif /* HAVE_EPOLL */
+
+ cupsd_update_pollfds = 1;
+
+#else /* select() */
+ /*
+ * Add or remove the file descriptor in the input and output sets
+ * for select()...
+ */
+
+ if (read_cb)
+ FD_SET(fd, &cupsd_global_input);
+ else
+ {
+ FD_CLR(fd, &cupsd_global_input);
+ FD_CLR(fd, &cupsd_current_input);
+ }
+
+ if (write_cb)
+ FD_SET(fd, &cupsd_global_output);
+ else
+ {
+ FD_CLR(fd, &cupsd_global_output);
+ FD_CLR(fd, &cupsd_current_output);
+ }
+#endif /* HAVE_KQUEUE */
+
+ /*
+ * Save the (new) read and write callbacks...
+ */
+
+ fdptr->read_cb = read_cb;
+ fdptr->write_cb = write_cb;
+ fdptr->data = data;
+
+ return (1);
+}
+
+
+/*
+ * 'cupsdDoSelect()' - Do a select-like operation.
+ */
+
+int /* O - Number of files or -1 on error */
+cupsdDoSelect(long timeout) /* I - Timeout in seconds */
+{
+ int nfds; /* Number of file descriptors */
+ _cupsd_fd_t *fdptr; /* Current file descriptor */
+#ifdef HAVE_KQUEUE
+ int i; /* Looping var */
+ struct kevent *event; /* Current event */
+ struct timespec ktimeout; /* kevent() timeout */
+
+
+ cupsd_in_select = 1;
+
+ if (timeout >= 0 && timeout < 86400)
+ {
+ ktimeout.tv_sec = timeout;
+ ktimeout.tv_nsec = 0;
+
+ nfds = kevent(cupsd_kqueue_fd, NULL, 0, cupsd_kqueue_events, MaxFDs,
+ &ktimeout);
+ }
+ else
+ nfds = kevent(cupsd_kqueue_fd, NULL, 0, cupsd_kqueue_events, MaxFDs, NULL);
+
+ cupsd_kqueue_changes = 0;
+
+ for (i = nfds, event = cupsd_kqueue_events; i > 0; i --, event ++)
+ {
+ fdptr = (_cupsd_fd_t *)event->udata;
+
+ if (cupsArrayFind(cupsd_inactive_fds, fdptr))
+ continue;
+
+ retain_fd(fdptr);
+
+ if (fdptr->read_cb && event->filter == EVFILT_READ)
+ (*(fdptr->read_cb))(fdptr->data);
+
+ if (fdptr->use > 1 && fdptr->write_cb && event->filter == EVFILT_WRITE &&
+ !cupsArrayFind(cupsd_inactive_fds, fdptr))
+ (*(fdptr->write_cb))(fdptr->data);
+
+ release_fd(fdptr);
+ }
+
+#elif defined(HAVE_POLL)
+ struct pollfd *pfd; /* Current pollfd structure */
+ int count; /* Number of file descriptors */
+
+
+# ifdef HAVE_EPOLL
+ cupsd_in_select = 1;
+
+ if (cupsd_epoll_fd >= 0)
+ {
+ int i; /* Looping var */
+ struct epoll_event *event; /* Current event */
+
+
+ if (timeout >= 0 && timeout < 86400)
+ nfds = epoll_wait(cupsd_epoll_fd, cupsd_epoll_events, MaxFDs,
+ timeout * 1000);
+ else
+ nfds = epoll_wait(cupsd_epoll_fd, cupsd_epoll_events, MaxFDs, -1);
+
+ if (nfds < 0 && errno != EINTR)
+ {
+ close(cupsd_epoll_fd);
+ cupsd_epoll_fd = -1;
+ }
+ else
+ {
+ for (i = nfds, event = cupsd_epoll_events; i > 0; i --, event ++)
+ {
+ fdptr = (_cupsd_fd_t *)event->data.ptr;
+
+ if (cupsArrayFind(cupsd_inactive_fds, fdptr))
+ continue;
+
+ retain_fd(fdptr);
+
+ if (fdptr->read_cb && (event->events & (EPOLLIN | EPOLLERR | EPOLLHUP)))
+ (*(fdptr->read_cb))(fdptr->data);
+
+ if (fdptr->use > 1 && fdptr->write_cb &&
+ (event->events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) &&
+ !cupsArrayFind(cupsd_inactive_fds, fdptr))
+ (*(fdptr->write_cb))(fdptr->data);
+
+ release_fd(fdptr);
+ }
+
+ goto release_inactive;
+ }
+ }
+# endif /* HAVE_EPOLL */
+
+ count = cupsArrayCount(cupsd_fds);
+
+ if (cupsd_update_pollfds)
+ {
+ /*
+ * Update the cupsd_pollfds array to match the current FD array...
+ */
+
+ cupsd_update_pollfds = 0;
+
+ /*
+ * (Re)allocate memory as needed...
+ */
+
+ if (count > cupsd_alloc_pollfds)
+ {
+ int allocfds = count + 16;
+
+
+ if (cupsd_pollfds)
+ pfd = realloc(cupsd_pollfds, allocfds * sizeof(struct pollfd));
+ else
+ pfd = malloc(allocfds * sizeof(struct pollfd));
+
+ if (!pfd)
+ {
+ cupsdLogMessage(CUPSD_LOG_EMERG,
+ "Unable to allocate %d bytes for polling!",
+ (int)(allocfds * sizeof(struct pollfd)));
+
+ return (-1);
+ }
+
+ cupsd_pollfds = pfd;
+ cupsd_alloc_pollfds = allocfds;
+ }
+
+ /*
+ * Rebuild the array...
+ */
+
+ for (fdptr = (_cupsd_fd_t *)cupsArrayFirst(cupsd_fds), pfd = cupsd_pollfds;
+ fdptr;
+ fdptr = (_cupsd_fd_t *)cupsArrayNext(cupsd_fds), pfd ++)
+ {
+ pfd->fd = fdptr->fd;
+ pfd->events = 0;
+
+ if (fdptr->read_cb)
+ pfd->events |= POLLIN;
+
+ if (fdptr->write_cb)
+ pfd->events |= POLLOUT;
+ }
+ }
+
+ if (timeout >= 0 && timeout < 86400)
+ nfds = poll(cupsd_pollfds, count, timeout * 1000);
+ else
+ nfds = poll(cupsd_pollfds, count, -1);
+
+ if (nfds > 0)
+ {
+ /*
+ * Do callbacks for each file descriptor...
+ */
+
+ for (pfd = cupsd_pollfds; count > 0; pfd ++, count --)
+ {
+ if (!pfd->revents)
+ continue;
+
+ if ((fdptr = find_fd(pfd->fd)) == NULL)
+ continue;
+
+ retain_fd(fdptr);
+
+ if (fdptr->read_cb && (pfd->revents & (POLLIN | POLLERR | POLLHUP)))
+ (*(fdptr->read_cb))(fdptr->data);
+
+ if (fdptr->use > 1 && fdptr->write_cb &&
+ (pfd->revents & (POLLOUT | POLLERR | POLLHUP)))
+ (*(fdptr->write_cb))(fdptr->data);
+
+ release_fd(fdptr);
+ }
+ }
+
+#else /* select() */
+ struct timeval stimeout; /* Timeout for select() */
+ int maxfd; /* Maximum file descriptor */
+
+
+ /*
+ * Figure out the highest file descriptor number...
+ */
+
+ if ((fdptr = (_cupsd_fd_t *)cupsArrayLast(cupsd_fds)) == NULL)
+ maxfd = 1;
+ else
+ maxfd = fdptr->fd + 1;
+
+ /*
+ * Do the select()...
+ */
+
+ cupsd_current_input = cupsd_global_input;
+ cupsd_current_output = cupsd_global_output;
+
+ if (timeout >= 0 && timeout < 86400)
+ {
+ stimeout.tv_sec = timeout;
+ stimeout.tv_usec = 0;
+
+ nfds = select(maxfd, &cupsd_current_input, &cupsd_current_output, NULL,
+ &stimeout);
+ }
+ else
+ nfds = select(maxfd, &cupsd_current_input, &cupsd_current_output, NULL,
+ NULL);
+
+ if (nfds > 0)
+ {
+ /*
+ * Do callbacks for each file descriptor...
+ */
+
+ for (fdptr = (_cupsd_fd_t *)cupsArrayFirst(cupsd_fds);
+ fdptr;
+ fdptr = (_cupsd_fd_t *)cupsArrayNext(cupsd_fds))
+ {
+ retain_fd(fdptr);
+
+ if (fdptr->read_cb && FD_ISSET(fdptr->fd, &cupsd_current_input))
+ (*(fdptr->read_cb))(fdptr->data);
+
+ if (fdptr->use > 1 && fdptr->write_cb &&
+ FD_ISSET(fdptr->fd, &cupsd_current_output))
+ (*(fdptr->write_cb))(fdptr->data);
+
+ release_fd(fdptr);
+ }
+ }
+
+#endif /* HAVE_KQUEUE */
+
+#if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
+ /*
+ * Release all inactive file descriptors...
+ */
+
+# ifndef HAVE_KQUEUE
+ release_inactive:
+# endif /* !HAVE_KQUEUE */
+
+ cupsd_in_select = 0;
+
+ for (fdptr = (_cupsd_fd_t *)cupsArrayFirst(cupsd_inactive_fds);
+ fdptr;
+ fdptr = (_cupsd_fd_t *)cupsArrayNext(cupsd_inactive_fds))
+ {
+ cupsArrayRemove(cupsd_inactive_fds, fdptr);
+ release_fd(fdptr);
+ }
+#endif /* HAVE_EPOLL || HAVE_KQUEUE */
+
+ /*
+ * Return the number of file descriptors handled...
+ */
+
+ return (nfds);
+}
+
+
+#ifdef CUPSD_IS_SELECTING
+/*
+ * 'cupsdIsSelecting()' - Determine whether we are monitoring a file
+ * descriptor.
+ */
+
+int /* O - 1 if selecting, 0 otherwise */
+cupsdIsSelecting(int fd) /* I - File descriptor */
+{
+ return (find_fd(fd) != NULL);
+}
+#endif /* CUPSD_IS_SELECTING */
+
+
+/*
+ * 'cupsdRemoveSelect()' - Remove a file descriptor from the list.
+ */
+
+void
+cupsdRemoveSelect(int fd) /* I - File descriptor */
+{
+ _cupsd_fd_t *fdptr; /* File descriptor record */
+#ifdef HAVE_EPOLL
+ struct epoll_event event; /* Event data */
+#elif defined(HAVE_KQUEUE)
+ struct kevent event; /* Event data */
+ struct timespec timeout; /* Timeout value */
+#elif defined(HAVE_POLL)
+ /* No variables for poll() */
+#endif /* HAVE_EPOLL */
+
+
+ /*
+ * Range check input...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdRemoveSelect(fd=%d)", fd);
+
+ if (fd < 0)
+ return;
+
+ /*
+ * Find the file descriptor...
+ */
+
+ if ((fdptr = find_fd(fd)) == NULL)
+ return;
+
+#ifdef HAVE_EPOLL
+ if (epoll_ctl(cupsd_epoll_fd, EPOLL_CTL_DEL, fd, &event))
+ {
+ close(cupsd_epoll_fd);
+ cupsd_epoll_fd = -1;
+ cupsd_update_pollfds = 1;
+ }
+
+#elif defined(HAVE_KQUEUE)
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 0;
+
+ if (fdptr->read_cb)
+ {
+ EV_SET(&event, fd, EVFILT_READ, EV_DELETE, 0, 0, fdptr);
+
+ if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout))
+ {
+ cupsdLogMessage(CUPSD_LOG_EMERG, "kevent() returned %s",
+ strerror(errno));
+ goto cleanup;
+ }
+ }
+
+ if (fdptr->write_cb)
+ {
+ EV_SET(&event, fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdptr);
+
+ if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout))
+ {
+ cupsdLogMessage(CUPSD_LOG_EMERG, "kevent() returned %s",
+ strerror(errno));
+ goto cleanup;
+ }
+ }
+
+#elif defined(HAVE_POLL)
+ /*
+ * Update the pollfds array...
+ */
+
+ cupsd_update_pollfds = 1;
+
+#else /* select() */
+ FD_CLR(fd, &cupsd_global_input);
+ FD_CLR(fd, &cupsd_global_output);
+ FD_CLR(fd, &cupsd_current_input);
+ FD_CLR(fd, &cupsd_current_output);
+#endif /* HAVE_EPOLL */
+
+#ifdef HAVE_KQUEUE
+ cleanup:
+#endif /* HAVE_KQUEUE */
+
+ /*
+ * Remove the file descriptor from the active array and add to the
+ * inactive array (or release, if we don't need the inactive array...)
+ */
+
+ cupsArrayRemove(cupsd_fds, fdptr);
+
+#if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
+ if (cupsd_in_select)
+ cupsArrayAdd(cupsd_inactive_fds, fdptr);
+ else
+#endif /* HAVE_EPOLL || HAVE_KQUEUE */
+
+ release_fd(fdptr);
+}
+
+
+/*
+ * 'cupsdStartSelect()' - Initialize the file polling engine.
+ */
+
+void
+cupsdStartSelect(void)
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartSelect()");
+
+ cupsd_fds = cupsArrayNew((cups_array_func_t)compare_fds, NULL);
+
+#if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
+ cupsd_inactive_fds = cupsArrayNew((cups_array_func_t)compare_fds, NULL);
+#endif /* HAVE_EPOLL || HAVE_KQUEUE */
+
+#ifdef HAVE_EPOLL
+ cupsd_epoll_fd = epoll_create(MaxFDs);
+ cupsd_epoll_events = calloc(MaxFDs, sizeof(struct epoll_event));
+ cupsd_update_pollfds = 0;
+
+#elif defined(HAVE_KQUEUE)
+ cupsd_kqueue_fd = kqueue();
+ cupsd_kqueue_changes = 0;
+ cupsd_kqueue_events = calloc(MaxFDs, sizeof(struct kevent));
+
+#elif defined(HAVE_POLL)
+ cupsd_update_pollfds = 0;
+
+#else /* select() */
+ FD_ZERO(&cupsd_global_input);
+ FD_ZERO(&cupsd_global_output);
+#endif /* HAVE_EPOLL */
+}
+
+
+/*
+ * 'cupsdStopSelect()' - Shutdown the file polling engine.
+ */
+
+void
+cupsdStopSelect(void)
+{
+ _cupsd_fd_t *fdptr; /* Current file descriptor */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStopSelect()");
+
+ for (fdptr = (_cupsd_fd_t *)cupsArrayFirst(cupsd_fds);
+ fdptr;
+ fdptr = (_cupsd_fd_t *)cupsArrayNext(cupsd_fds))
+ free(fdptr);
+
+ cupsArrayDelete(cupsd_fds);
+ cupsd_fds = NULL;
+
+#if defined(HAVE_EPOLL) || defined(HAVE_KQUEUE)
+ cupsArrayDelete(cupsd_inactive_fds);
+ cupsd_inactive_fds = NULL;
+#endif /* HAVE_EPOLL || HAVE_KQUEUE */
+
+#ifdef HAVE_KQUEUE
+ if (cupsd_kqueue_events)
+ {
+ free(cupsd_kqueue_events);
+ cupsd_kqueue_events = NULL;
+ }
+
+ if (cupsd_kqueue_fd >= 0)
+ {
+ close(cupsd_kqueue_fd);
+ cupsd_kqueue_fd = -1;
+ }
+
+ cupsd_kqueue_changes = 0;
+
+#elif defined(HAVE_POLL)
+# ifdef HAVE_EPOLL
+ if (cupsd_epoll_events)
+ {
+ free(cupsd_epoll_events);
+ cupsd_epoll_events = NULL;
+ }
+
+ if (cupsd_epoll_fd >= 0)
+ {
+ close(cupsd_epoll_fd);
+ cupsd_epoll_fd = -1;
+ }
+# endif /* HAVE_EPOLL */
+
+ if (cupsd_pollfds)
+ {
+ free(cupsd_pollfds);
+ cupsd_pollfds = NULL;
+ cupsd_alloc_pollfds = 0;
+ }
+
+ cupsd_update_pollfds = 0;
+
+#else /* select() */
+ FD_ZERO(&cupsd_global_input);
+ FD_ZERO(&cupsd_global_output);
+#endif /* HAVE_EPOLL */
+}
+
+
+/*
+ * 'compare_fds()' - Compare file descriptors.
+ */
+
+static int /* O - Result of comparison */
+compare_fds(_cupsd_fd_t *a, /* I - First file descriptor */
+ _cupsd_fd_t *b) /* I - Second file descriptor */
+{
+ return (a->fd - b->fd);
+}
+
+
+/*
+ * 'find_fd()' - Find an existing file descriptor record.
+ */
+
+static _cupsd_fd_t * /* O - FD record pointer or NULL */
+find_fd(int fd) /* I - File descriptor */
+{
+ _cupsd_fd_t *fdptr, /* Matching record (if any) */
+ key; /* Search key */
+
+
+ cupsArraySave(cupsd_fds);
+
+ key.fd = fd;
+ fdptr = (_cupsd_fd_t *)cupsArrayFind(cupsd_fds, &key);
+
+ cupsArrayRestore(cupsd_fds);
+
+ return (fdptr);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/server.c b/scheduler/server.c
new file mode 100644
index 000000000..83e9bd6fe
--- /dev/null
+++ b/scheduler/server.c
@@ -0,0 +1,184 @@
+/*
+ * "$Id$"
+ *
+ * Server start/stop routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdStartServer() - Start the server.
+ * cupsdStopServer() - Stop the server.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/http-private.h>
+#include "cupsd.h"
+#include <grp.h>
+#ifdef HAVE_NOTIFY_H
+# include <notify.h>
+#endif /* HAVE_NOTIFY_H */
+
+
+/*
+ * Local globals...
+ */
+
+static int started = 0; /* Did we start the server already? */
+
+
+/*
+ * 'cupsdStartServer()' - Start the server.
+ */
+
+void
+cupsdStartServer(void)
+{
+ /*
+ * Create the default security profile...
+ */
+
+ DefaultProfile = cupsdCreateProfile(0);
+
+ /*
+ * Startup all the networking stuff...
+ */
+
+ cupsdStartListening();
+ cupsdStartBrowsing();
+ cupsdStartPolling();
+
+ /*
+ * Create a pipe for CGI processes...
+ */
+
+ if (cupsdOpenPipe(CGIPipes))
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdStartServer: Unable to create pipes for CGI status!");
+ else
+ {
+ CGIStatusBuffer = cupsdStatBufNew(CGIPipes[0], "[CGI]");
+
+ cupsdAddSelect(CGIPipes[0], (cupsd_selfunc_t)cupsdUpdateCGI, NULL, NULL);
+ }
+
+ /*
+ * Mark that the server has started and printers and jobs may be changed...
+ */
+
+ LastEvent = CUPSD_EVENT_PRINTER_CHANGED | CUPSD_EVENT_JOB_STATE_CHANGED |
+ CUPSD_EVENT_SERVER_STARTED;
+ started = 1;
+
+ cupsdSetBusyState();
+}
+
+
+/*
+ * 'cupsdStopServer()' - Stop the server.
+ */
+
+void
+cupsdStopServer(void)
+{
+ if (!started)
+ return;
+
+ /*
+ * Close all network clients and stop all jobs...
+ */
+
+ cupsdCloseAllClients();
+ cupsdStopListening();
+ cupsdStopPolling();
+ cupsdStopBrowsing();
+ cupsdStopAllNotifiers();
+ cupsdDeleteAllCerts();
+
+ if (Clients)
+ {
+ cupsArrayDelete(Clients);
+ Clients = NULL;
+ }
+
+ /*
+ * Close the pipe for CGI processes...
+ */
+
+ if (CGIPipes[0] >= 0)
+ {
+ cupsdRemoveSelect(CGIPipes[0]);
+
+ cupsdStatBufDelete(CGIStatusBuffer);
+ close(CGIPipes[1]);
+
+ CGIPipes[0] = -1;
+ CGIPipes[1] = -1;
+ }
+
+#ifdef HAVE_NOTIFY_POST
+ /*
+ * Send one last notification as the server shuts down.
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "notify_post(\"com.apple.printerListChange\") last");
+ notify_post("com.apple.printerListChange");
+#endif /* HAVE_NOTIFY_POST */
+
+ /*
+ * Close all log files...
+ */
+
+ if (AccessFile != NULL)
+ {
+ cupsFileClose(AccessFile);
+
+ AccessFile = NULL;
+ }
+
+ if (ErrorFile != NULL)
+ {
+ cupsFileClose(ErrorFile);
+
+ ErrorFile = NULL;
+ }
+
+ if (PageFile != NULL)
+ {
+ cupsFileClose(PageFile);
+
+ PageFile = NULL;
+ }
+
+ /*
+ * Delete the default security profile...
+ */
+
+ cupsdDestroyProfile(DefaultProfile);
+ DefaultProfile = NULL;
+
+ /*
+ * Write out any dirty files...
+ */
+
+ if (DirtyFiles)
+ cupsdCleanDirty();
+
+ started = 0;
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/statbuf.c b/scheduler/statbuf.c
new file mode 100644
index 000000000..dc88be449
--- /dev/null
+++ b/scheduler/statbuf.c
@@ -0,0 +1,330 @@
+/*
+ * "$Id$"
+ *
+ * Status buffer routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdStatBufDelete() - Destroy a status buffer.
+ * cupsdStatBufNew() - Create a new status buffer.
+ * cupsdStatBufUpdate() - Update the status buffer.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <stdarg.h>
+
+
+/*
+ * 'cupsdStatBufDelete()' - Destroy a status buffer.
+ */
+
+void
+cupsdStatBufDelete(cupsd_statbuf_t *sb) /* I - Status buffer */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!sb)
+ return;
+
+ /*
+ * Close the status pipe and free memory used...
+ */
+
+ close(sb->fd);
+
+ free(sb);
+}
+
+
+/*
+ * 'cupsdStatBufNew()' - Create a new status buffer.
+ */
+
+cupsd_statbuf_t * /* O - New status buffer */
+cupsdStatBufNew(int fd, /* I - File descriptor of pipe */
+ const char *prefix, /* I - Printf-style prefix string */
+ ...) /* I - Additional args as needed */
+{
+ cupsd_statbuf_t *sb; /* New status buffer */
+ va_list ap; /* Argument list */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (fd < 0)
+ return (NULL);
+
+ /*
+ * Allocate the status buffer...
+ */
+
+ if ((sb = calloc(1, sizeof(cupsd_statbuf_t))) != NULL)
+ {
+ /*
+ * Assign the file descriptor...
+ */
+
+ sb->fd = fd;
+
+ /*
+ * Format the prefix string, if any. This is usually "[Job 123]"
+ * or "[Sub 123]", and so forth.
+ */
+
+ if (prefix)
+ {
+ /*
+ * Printf-style prefix string...
+ */
+
+ va_start(ap, prefix);
+ vsnprintf(sb->prefix, sizeof(sb->prefix), prefix, ap);
+ va_end(ap);
+ }
+ else
+ {
+ /*
+ * No prefix string...
+ */
+
+ sb->prefix[0] = '\0';
+ }
+ }
+
+ return (sb);
+}
+
+
+/*
+ * 'cupsdStatBufUpdate()' - Update the status buffer.
+ */
+
+char * /* O - Line from buffer, "", or NULL */
+cupsdStatBufUpdate(
+ cupsd_statbuf_t *sb, /* I - Status buffer */
+ int *loglevel, /* O - Log level */
+ char *line, /* I - Line buffer */
+ int linelen) /* I - Size of line buffer */
+{
+ int bytes; /* Number of bytes read */
+ char *lineptr, /* Pointer to end of line in buffer */
+ *message; /* Pointer to message text */
+
+
+ /*
+ * Check if the buffer already contains a full line...
+ */
+
+ if ((lineptr = strchr(sb->buffer, '\n')) == NULL)
+ {
+ /*
+ * No, read more data...
+ */
+
+ if ((bytes = read(sb->fd, sb->buffer + sb->bufused,
+ CUPSD_SB_BUFFER_SIZE - sb->bufused - 1)) > 0)
+ {
+ sb->bufused += bytes;
+ sb->buffer[sb->bufused] = '\0';
+
+ /*
+ * Guard against a line longer than the max buffer size...
+ */
+
+ if ((lineptr = strchr(sb->buffer, '\n')) == NULL &&
+ sb->bufused == (CUPSD_SB_BUFFER_SIZE - 1))
+ lineptr = sb->buffer + sb->bufused;
+ }
+ else if (bytes < 0 && errno == EINTR)
+ {
+ /*
+ * Return an empty line if we are interrupted...
+ */
+
+ *loglevel = CUPSD_LOG_NONE;
+ line[0] = '\0';
+
+ return (line);
+ }
+ else
+ {
+ /*
+ * End-of-file, so use the whole buffer...
+ */
+
+ lineptr = sb->buffer + sb->bufused;
+ *lineptr = '\0';
+ }
+
+ /*
+ * Final check for end-of-file...
+ */
+
+ if (sb->bufused == 0 && bytes == 0)
+ lineptr = NULL;
+ }
+
+ if (!lineptr)
+ {
+ /*
+ * End of file...
+ */
+
+ *loglevel = CUPSD_LOG_NONE;
+ line[0] = '\0';
+
+ return (NULL);
+ }
+
+ /*
+ * Terminate the line and process it...
+ */
+
+ *lineptr++ = '\0';
+
+ /*
+ * Figure out the logging level...
+ */
+
+ if (!strncmp(sb->buffer, "EMERG:", 6))
+ {
+ *loglevel = CUPSD_LOG_EMERG;
+ message = sb->buffer + 6;
+ }
+ else if (!strncmp(sb->buffer, "ALERT:", 6))
+ {
+ *loglevel = CUPSD_LOG_ALERT;
+ message = sb->buffer + 6;
+ }
+ else if (!strncmp(sb->buffer, "CRIT:", 5))
+ {
+ *loglevel = CUPSD_LOG_CRIT;
+ message = sb->buffer + 5;
+ }
+ else if (!strncmp(sb->buffer, "ERROR:", 6))
+ {
+ *loglevel = CUPSD_LOG_ERROR;
+ message = sb->buffer + 6;
+ }
+ else if (!strncmp(sb->buffer, "WARNING:", 8))
+ {
+ *loglevel = CUPSD_LOG_WARN;
+ message = sb->buffer + 8;
+ }
+ else if (!strncmp(sb->buffer, "NOTICE:", 7))
+ {
+ *loglevel = CUPSD_LOG_NOTICE;
+ message = sb->buffer + 7;
+ }
+ else if (!strncmp(sb->buffer, "INFO:", 5))
+ {
+ *loglevel = CUPSD_LOG_INFO;
+ message = sb->buffer + 5;
+ }
+ else if (!strncmp(sb->buffer, "DEBUG:", 6))
+ {
+ *loglevel = CUPSD_LOG_DEBUG;
+ message = sb->buffer + 6;
+ }
+ else if (!strncmp(sb->buffer, "DEBUG2:", 7))
+ {
+ *loglevel = CUPSD_LOG_DEBUG2;
+ message = sb->buffer + 7;
+ }
+ else if (!strncmp(sb->buffer, "PAGE:", 5))
+ {
+ *loglevel = CUPSD_LOG_PAGE;
+ message = sb->buffer + 5;
+ }
+ else if (!strncmp(sb->buffer, "STATE:", 6))
+ {
+ *loglevel = CUPSD_LOG_STATE;
+ message = sb->buffer + 6;
+ }
+ else if (!strncmp(sb->buffer, "ATTR:", 5))
+ {
+ *loglevel = CUPSD_LOG_ATTR;
+ message = sb->buffer + 5;
+ }
+ else if (!strncmp(sb->buffer, "PPD:", 4))
+ {
+ *loglevel = CUPSD_LOG_PPD;
+ message = sb->buffer + 4;
+ }
+ else
+ {
+ *loglevel = CUPSD_LOG_DEBUG;
+ message = sb->buffer;
+ }
+
+ /*
+ * Skip leading whitespace in the message...
+ */
+
+ while (isspace(*message & 255))
+ message ++;
+
+ /*
+ * Send it to the log file as needed...
+ */
+
+ if (sb->prefix[0])
+ {
+ if (*loglevel > CUPSD_LOG_NONE &&
+ (*loglevel != CUPSD_LOG_INFO || LogLevel >= CUPSD_LOG_DEBUG))
+ {
+ /*
+ * General status message; send it to the error_log file...
+ */
+
+ if (message[0] == '[')
+ cupsdLogMessage(*loglevel, "%s", message);
+ else
+ cupsdLogMessage(*loglevel, "%s %s", sb->prefix, message);
+ }
+ else if (*loglevel < CUPSD_LOG_NONE && LogLevel >= CUPSD_LOG_DEBUG)
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "%s %s", sb->prefix, sb->buffer);
+ }
+
+ /*
+ * Copy the message to the line buffer...
+ */
+
+ strlcpy(line, message, linelen);
+
+ /*
+ * Copy over the buffer data we've used up...
+ */
+
+ if (lineptr < sb->buffer + sb->bufused)
+ _cups_strcpy(sb->buffer, lineptr);
+
+ sb->bufused -= lineptr - sb->buffer;
+
+ if (sb->bufused < 0)
+ sb->bufused = 0;
+
+ return (line);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/statbuf.h b/scheduler/statbuf.h
new file mode 100644
index 000000000..212acdf18
--- /dev/null
+++ b/scheduler/statbuf.h
@@ -0,0 +1,49 @@
+/*
+ * "$Id$"
+ *
+ * Status buffer definitions for the CUPS scheduler.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+
+/*
+ * Constants...
+ */
+
+#define CUPSD_SB_BUFFER_SIZE 2048 /* Bytes for job status buffer */
+
+
+/*
+ * Types and structures...
+ */
+
+typedef struct /**** Status buffer */
+{
+ int fd; /* File descriptor to read from */
+ char prefix[64]; /* Prefix for log messages */
+ int bufused; /* How much is used in buffer */
+ char buffer[CUPSD_SB_BUFFER_SIZE]; /* Buffer */
+} cupsd_statbuf_t;
+
+
+/*
+ * Prototypes...
+ */
+
+extern void cupsdStatBufDelete(cupsd_statbuf_t *sb);
+extern cupsd_statbuf_t *cupsdStatBufNew(int fd, const char *prefix, ...);
+extern char *cupsdStatBufUpdate(cupsd_statbuf_t *sb, int *loglevel,
+ char *line, int linelen);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/subscriptions.c b/scheduler/subscriptions.c
new file mode 100644
index 000000000..90f88daba
--- /dev/null
+++ b/scheduler/subscriptions.c
@@ -0,0 +1,1638 @@
+/*
+ * "$Id$"
+ *
+ * Subscription routines for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdAddEvent() - Add an event to the global event cache.
+ * cupsdAddSubscription() - Add a new subscription object.
+ * cupsdDeleteAllSubscriptions() - Delete all subscriptions.
+ * cupsdDeleteSubscription() - Delete a subscription object.
+ * cupsdEventName() - Return a single event name.
+ * cupsdEventValue() - Return the event mask value for a name.
+ * cupsdExpireSubscriptions() - Expire old subscription objects.
+ * cupsdFindSubscription() - Find a subscription by ID.
+ * cupsdLoadAllSubscriptions() - Load all subscriptions from the .conf file.
+ * cupsdSaveAllSubscriptions() - Save all subscriptions to the .conf file.
+ * cupsdStopAllNotifiers() - Stop all notifier processes.
+ * cupsd_compare_subscriptions() - Compare two subscriptions.
+ * cupsd_delete_event() - Delete a single event...
+ * cupsd_send_dbus() - Send a DBUS notification...
+ * cupsd_send_notification() - Send a notification for the specified
+ * event.
+ * cupsd_start_notifier() - Start a notifier subprocess...
+ * cupsd_update_notifier() - Read messages from notifiers.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#ifdef HAVE_DBUS
+# include <dbus/dbus.h>
+# ifdef HAVE_DBUS_MESSAGE_ITER_INIT_APPEND
+# define dbus_message_append_iter_init dbus_message_iter_init_append
+# define dbus_message_iter_append_string(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &(v))
+# define dbus_message_iter_append_uint32(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &(v))
+# endif /* HAVE_DBUS_MESSAGE_ITER_INIT_APPEND */
+#endif /* HAVE_DBUS */
+
+
+/*
+ * Local functions...
+ */
+
+static int cupsd_compare_subscriptions(cupsd_subscription_t *first,
+ cupsd_subscription_t *second,
+ void *unused);
+static void cupsd_delete_event(cupsd_event_t *event);
+#ifdef HAVE_DBUS
+static void cupsd_send_dbus(cupsd_eventmask_t event, cupsd_printer_t *dest,
+ cupsd_job_t *job);
+#endif /* HAVE_DBUS */
+static void cupsd_send_notification(cupsd_subscription_t *sub,
+ cupsd_event_t *event);
+static void cupsd_start_notifier(cupsd_subscription_t *sub);
+static void cupsd_update_notifier(void);
+
+
+/*
+ * 'cupsdAddEvent()' - Add an event to the global event cache.
+ */
+
+void
+cupsdAddEvent(
+ cupsd_eventmask_t event, /* I - Event */
+ cupsd_printer_t *dest, /* I - Printer associated with event */
+ cupsd_job_t *job, /* I - Job associated with event */
+ const char *text, /* I - Notification text */
+ ...) /* I - Additional arguments as needed */
+{
+ va_list ap; /* Pointer to additional arguments */
+ char ftext[1024]; /* Formatted text buffer */
+ ipp_attribute_t *attr; /* Printer/job attribute */
+ cupsd_event_t *temp; /* New event pointer */
+ cupsd_subscription_t *sub; /* Current subscription */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdAddEvent(event=%s, dest=%p(%s), job=%p(%d), text=\"%s\", ...)",
+ cupsdEventName(event), dest, dest ? dest->name : "",
+ job, job ? job->id : 0, text);
+
+ /*
+ * Keep track of events with any OS-supplied notification mechanisms...
+ */
+
+ LastEvent |= event;
+
+#ifdef HAVE_DBUS
+ cupsd_send_dbus(event, dest, job);
+#endif /* HAVE_DBUS */
+
+ /*
+ * Return if we aren't keeping events...
+ */
+
+ if (MaxEvents <= 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "cupsdAddEvent: Discarding %s event since MaxEvents is %d!",
+ cupsdEventName(event), MaxEvents);
+ return;
+ }
+
+ /*
+ * Then loop through the subscriptions and add the event to the corresponding
+ * caches...
+ */
+
+ for (temp = NULL, sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
+ sub;
+ sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
+ {
+ /*
+ * Check if this subscription requires this event...
+ */
+
+ if ((sub->mask & event) != 0 &&
+ (sub->dest == dest || !sub->dest) &&
+ (sub->job == job || !sub->job))
+ {
+ /*
+ * Need this event, so create a new event record...
+ */
+
+ if ((temp = (cupsd_event_t *)calloc(1, sizeof(cupsd_event_t))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_CRIT,
+ "Unable to allocate memory for event - %s",
+ strerror(errno));
+ return;
+ }
+
+ temp->event = event;
+ temp->time = time(NULL);
+ temp->attrs = ippNew();
+ temp->job = job;
+ temp->dest = dest;
+
+ /*
+ * Add common event notification attributes...
+ */
+
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_CHARSET,
+ "notify-charset", NULL, "utf-8");
+
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_LANGUAGE,
+ "notify-natural-language", NULL, "en-US");
+
+ ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
+ "notify-subscription-id", sub->id);
+
+ ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
+ "notify-sequence-number", sub->next_event_id);
+
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD,
+ "notify-subscribed-event", NULL, cupsdEventName(event));
+
+ if (sub->user_data_len > 0)
+ ippAddOctetString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
+ "notify-user-data", sub->user_data,
+ sub->user_data_len);
+
+ ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
+ "printer-up-time", time(NULL));
+
+ va_start(ap, text);
+ vsnprintf(ftext, sizeof(ftext), text, ap);
+ va_end(ap);
+
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_TEXT,
+ "notify-text", NULL, ftext);
+
+ if (dest)
+ {
+ /*
+ * Add printer attributes...
+ */
+
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_URI,
+ "notify-printer-uri", NULL, dest->uri);
+
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME,
+ "printer-name", NULL, dest->name);
+
+ ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_ENUM,
+ "printer-state", dest->state);
+
+ if (dest->num_reasons == 0)
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
+ IPP_TAG_KEYWORD, "printer-state-reasons", NULL,
+ dest->state == IPP_PRINTER_STOPPED ? "paused" : "none");
+ else
+ ippAddStrings(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
+ IPP_TAG_KEYWORD, "printer-state-reasons",
+ dest->num_reasons, NULL,
+ (const char * const *)dest->reasons);
+
+ ippAddBoolean(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
+ "printer-is-accepting-jobs", dest->accepting);
+ }
+
+ if (job)
+ {
+ /*
+ * Add job attributes...
+ */
+
+ ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
+ "notify-job-id", job->id);
+ ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_ENUM,
+ "job-state", job->state_value);
+
+ if ((attr = ippFindAttribute(job->attrs, "job-name",
+ IPP_TAG_NAME)) != NULL)
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME,
+ "job-name", NULL, attr->values[0].string.text);
+
+ switch (job->state_value)
+ {
+ case IPP_JOB_PENDING :
+ if (dest && dest->state == IPP_PRINTER_STOPPED)
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
+ IPP_TAG_KEYWORD, "job-state-reasons", NULL,
+ "printer-stopped");
+ else
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
+ IPP_TAG_KEYWORD, "job-state-reasons", NULL,
+ "none");
+ break;
+
+ case IPP_JOB_HELD :
+ if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD) != NULL ||
+ ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME) != NULL)
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
+ IPP_TAG_KEYWORD, "job-state-reasons", NULL,
+ "job-hold-until-specified");
+ else
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
+ IPP_TAG_KEYWORD, "job-state-reasons", NULL,
+ "job-incoming");
+ break;
+
+ case IPP_JOB_PROCESSING :
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
+ IPP_TAG_KEYWORD, "job-state-reasons", NULL,
+ "job-printing");
+ break;
+
+ case IPP_JOB_STOPPED :
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
+ IPP_TAG_KEYWORD, "job-state-reasons", NULL,
+ "job-stopped");
+ break;
+
+ case IPP_JOB_CANCELED :
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
+ IPP_TAG_KEYWORD, "job-state-reasons", NULL,
+ "job-canceled-by-user");
+ break;
+
+ case IPP_JOB_ABORTED :
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
+ IPP_TAG_KEYWORD, "job-state-reasons", NULL,
+ "aborted-by-system");
+ break;
+
+ case IPP_JOB_COMPLETED :
+ ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
+ IPP_TAG_KEYWORD, "job-state-reasons", NULL,
+ "job-completed-successfully");
+ break;
+ }
+
+ ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
+ "job-impressions-completed",
+ job->sheets ? job->sheets->values[0].integer : 0);
+ }
+
+ /*
+ * Send the notification for this subscription...
+ */
+
+ cupsd_send_notification(sub, temp);
+ }
+ }
+
+ if (temp)
+ cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Discarding unused %s event...",
+ cupsdEventName(event));
+}
+
+
+/*
+ * 'cupsdAddSubscription()' - Add a new subscription object.
+ */
+
+cupsd_subscription_t * /* O - New subscription object */
+cupsdAddSubscription(
+ unsigned mask, /* I - Event mask */
+ cupsd_printer_t *dest, /* I - Printer, if any */
+ cupsd_job_t *job, /* I - Job, if any */
+ const char *uri, /* I - notify-recipient-uri, if any */
+ int sub_id) /* I - notify-subscription-id or 0 */
+{
+ cupsd_subscription_t *temp; /* New subscription object */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAddSubscription(mask=%x, dest=%p(%s), job=%p(%d), "
+ "uri=\"%s\")",
+ mask, dest, dest ? dest->name : "", job, job ? job->id : 0,
+ uri ? uri : "(null)");
+
+ if (!Subscriptions)
+ Subscriptions = cupsArrayNew((cups_array_func_t)cupsd_compare_subscriptions,
+ NULL);
+
+ if (!Subscriptions)
+ {
+ cupsdLogMessage(CUPSD_LOG_CRIT,
+ "Unable to allocate memory for subscriptions - %s",
+ strerror(errno));
+ return (NULL);
+ }
+
+ /*
+ * Limit the number of subscriptions...
+ */
+
+ if (MaxSubscriptions > 0 && cupsArrayCount(Subscriptions) >= MaxSubscriptions)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAddSubscription: Reached MaxSubscriptions %d "
+ "(count=%d)", MaxSubscriptions,
+ cupsArrayCount(Subscriptions));
+ return (NULL);
+ }
+
+ if (MaxSubscriptionsPerJob > 0 && job)
+ {
+ int count; /* Number of job subscriptions */
+
+ for (temp = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions),
+ count = 0;
+ temp;
+ temp = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
+ if (temp->job == job)
+ count ++;
+
+ if (count >= MaxSubscriptionsPerJob)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAddSubscription: Reached MaxSubscriptionsPerJob %d "
+ "for job #%d (count=%d)", MaxSubscriptionsPerJob,
+ job->id, count);
+ return (NULL);
+ }
+ }
+
+ if (MaxSubscriptionsPerPrinter > 0 && dest)
+ {
+ int count; /* Number of printer subscriptions */
+
+ for (temp = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions),
+ count = 0;
+ temp;
+ temp = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
+ if (temp->dest == dest)
+ count ++;
+
+ if (count >= MaxSubscriptionsPerPrinter)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdAddSubscription: Reached "
+ "MaxSubscriptionsPerPrinter %d for %s (count=%d)",
+ MaxSubscriptionsPerPrinter, dest->name, count);
+ return (NULL);
+ }
+ }
+
+ /*
+ * Allocate memory for this subscription...
+ */
+
+ if ((temp = calloc(1, sizeof(cupsd_subscription_t))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_CRIT,
+ "Unable to allocate memory for subscription object - %s",
+ strerror(errno));
+ return (NULL);
+ }
+
+ /*
+ * Fill in common data...
+ */
+
+ if (sub_id)
+ {
+ temp->id = sub_id;
+
+ if (sub_id >= NextSubscriptionId)
+ NextSubscriptionId = sub_id + 1;
+ }
+ else
+ {
+ temp->id = NextSubscriptionId;
+
+ NextSubscriptionId ++;
+ }
+
+ temp->mask = mask;
+ temp->dest = dest;
+ temp->job = job;
+ temp->pipe = -1;
+ temp->first_event_id = 1;
+ temp->next_event_id = 1;
+
+ cupsdSetString(&(temp->recipient), uri);
+
+ /*
+ * Add the subscription to the array...
+ */
+
+ cupsArrayAdd(Subscriptions, temp);
+
+ /*
+ * For RSS subscriptions, run the notifier immediately...
+ */
+
+ if (uri && !strncmp(uri, "rss:", 4))
+ cupsd_start_notifier(temp);
+
+ return (temp);
+}
+
+
+/*
+ * 'cupsdDeleteAllSubscriptions()' - Delete all subscriptions.
+ */
+
+void
+cupsdDeleteAllSubscriptions(void)
+{
+ cupsd_subscription_t *sub; /* Subscription */
+
+
+ if (!Subscriptions)
+ return;
+
+ for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
+ sub;
+ sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
+ cupsdDeleteSubscription(sub, 0);
+
+ cupsArrayDelete(Subscriptions);
+ Subscriptions = NULL;
+}
+
+
+/*
+ * 'cupsdDeleteSubscription()' - Delete a subscription object.
+ */
+
+void
+cupsdDeleteSubscription(
+ cupsd_subscription_t *sub, /* I - Subscription object */
+ int update) /* I - 1 = update subscriptions.conf */
+{
+ /*
+ * Close the pipe to the notifier as needed...
+ */
+
+ if (sub->pipe >= 0)
+ close(sub->pipe);
+
+ /*
+ * Remove subscription from array...
+ */
+
+ cupsArrayRemove(Subscriptions, sub);
+
+ /*
+ * Free memory...
+ */
+
+ cupsdClearString(&(sub->owner));
+ cupsdClearString(&(sub->recipient));
+
+ cupsArrayDelete(sub->events);
+
+ free(sub);
+
+ /*
+ * Update the subscriptions as needed...
+ */
+
+ if (update)
+ cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
+}
+
+
+/*
+ * 'cupsdEventName()' - Return a single event name.
+ */
+
+const char * /* O - Event name */
+cupsdEventName(
+ cupsd_eventmask_t event) /* I - Event value */
+{
+ switch (event)
+ {
+ default :
+ return (NULL);
+
+ case CUPSD_EVENT_PRINTER_RESTARTED :
+ return ("printer-restarted");
+
+ case CUPSD_EVENT_PRINTER_SHUTDOWN :
+ return ("printer-shutdown");
+
+ case CUPSD_EVENT_PRINTER_STOPPED :
+ return ("printer-stopped");
+
+ case CUPSD_EVENT_PRINTER_FINISHINGS_CHANGED :
+ return ("printer-finishings-changed");
+
+ case CUPSD_EVENT_PRINTER_MEDIA_CHANGED :
+ return ("printer-media-changed");
+
+ case CUPSD_EVENT_PRINTER_ADDED :
+ return ("printer-added");
+
+ case CUPSD_EVENT_PRINTER_DELETED :
+ return ("printer-deleted");
+
+ case CUPSD_EVENT_PRINTER_MODIFIED :
+ return ("printer-modified");
+
+ case CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED :
+ return ("printer-queue-order-changed");
+
+ case CUPSD_EVENT_PRINTER_STATE :
+ case CUPSD_EVENT_PRINTER_STATE_CHANGED :
+ return ("printer-state-changed");
+
+ case CUPSD_EVENT_PRINTER_CONFIG :
+ case CUPSD_EVENT_PRINTER_CONFIG_CHANGED :
+ return ("printer-config-changed");
+
+ case CUPSD_EVENT_PRINTER_CHANGED :
+ return ("printer-changed");
+
+ case CUPSD_EVENT_JOB_CREATED :
+ return ("job-created");
+
+ case CUPSD_EVENT_JOB_COMPLETED :
+ return ("job-completed");
+
+ case CUPSD_EVENT_JOB_STOPPED :
+ return ("job-stopped");
+
+ case CUPSD_EVENT_JOB_CONFIG_CHANGED :
+ return ("job-config-changed");
+
+ case CUPSD_EVENT_JOB_PROGRESS :
+ return ("job-progress");
+
+ case CUPSD_EVENT_JOB_STATE :
+ case CUPSD_EVENT_JOB_STATE_CHANGED :
+ return ("job-state-changed");
+
+ case CUPSD_EVENT_SERVER_RESTARTED :
+ return ("server-restarted");
+
+ case CUPSD_EVENT_SERVER_STARTED :
+ return ("server-started");
+
+ case CUPSD_EVENT_SERVER_STOPPED :
+ return ("server-stopped");
+
+ case CUPSD_EVENT_SERVER_AUDIT :
+ return ("server-audit");
+
+ case CUPSD_EVENT_ALL :
+ return ("all");
+ }
+}
+
+
+/*
+ * 'cupsdEventValue()' - Return the event mask value for a name.
+ */
+
+cupsd_eventmask_t /* O - Event mask value */
+cupsdEventValue(const char *name) /* I - Name of event */
+{
+ if (!strcmp(name, "all"))
+ return (CUPSD_EVENT_ALL);
+ else if (!strcmp(name, "printer-restarted"))
+ return (CUPSD_EVENT_PRINTER_RESTARTED);
+ else if (!strcmp(name, "printer-shutdown"))
+ return (CUPSD_EVENT_PRINTER_SHUTDOWN);
+ else if (!strcmp(name, "printer-stopped"))
+ return (CUPSD_EVENT_PRINTER_STOPPED);
+ else if (!strcmp(name, "printer-finishings-changed"))
+ return (CUPSD_EVENT_PRINTER_FINISHINGS_CHANGED);
+ else if (!strcmp(name, "printer-media-changed"))
+ return (CUPSD_EVENT_PRINTER_MEDIA_CHANGED);
+ else if (!strcmp(name, "printer-added"))
+ return (CUPSD_EVENT_PRINTER_ADDED);
+ else if (!strcmp(name, "printer-deleted"))
+ return (CUPSD_EVENT_PRINTER_DELETED);
+ else if (!strcmp(name, "printer-modified"))
+ return (CUPSD_EVENT_PRINTER_MODIFIED);
+ else if (!strcmp(name, "printer-queue-order-changed"))
+ return (CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED);
+ else if (!strcmp(name, "printer-state-changed"))
+ return (CUPSD_EVENT_PRINTER_STATE_CHANGED);
+ else if (!strcmp(name, "printer-config-changed"))
+ return (CUPSD_EVENT_PRINTER_CONFIG_CHANGED);
+ else if (!strcmp(name, "printer-changed"))
+ return (CUPSD_EVENT_PRINTER_CHANGED);
+ else if (!strcmp(name, "job-created"))
+ return (CUPSD_EVENT_JOB_CREATED);
+ else if (!strcmp(name, "job-completed"))
+ return (CUPSD_EVENT_JOB_COMPLETED);
+ else if (!strcmp(name, "job-stopped"))
+ return (CUPSD_EVENT_JOB_STOPPED);
+ else if (!strcmp(name, "job-config-changed"))
+ return (CUPSD_EVENT_JOB_CONFIG_CHANGED);
+ else if (!strcmp(name, "job-progress"))
+ return (CUPSD_EVENT_JOB_PROGRESS);
+ else if (!strcmp(name, "job-state-changed"))
+ return (CUPSD_EVENT_JOB_STATE_CHANGED);
+ else if (!strcmp(name, "server-restarted"))
+ return (CUPSD_EVENT_SERVER_RESTARTED);
+ else if (!strcmp(name, "server-started"))
+ return (CUPSD_EVENT_SERVER_STARTED);
+ else if (!strcmp(name, "server-stopped"))
+ return (CUPSD_EVENT_SERVER_STOPPED);
+ else if (!strcmp(name, "server-audit"))
+ return (CUPSD_EVENT_SERVER_AUDIT);
+ else
+ return (CUPSD_EVENT_NONE);
+}
+
+
+/*
+ * 'cupsdExpireSubscriptions()' - Expire old subscription objects.
+ */
+
+void
+cupsdExpireSubscriptions(
+ cupsd_printer_t *dest, /* I - Printer, if any */
+ cupsd_job_t *job) /* I - Job, if any */
+{
+ cupsd_subscription_t *sub; /* Current subscription */
+ int update; /* Update subscriptions.conf? */
+ time_t curtime; /* Current time */
+
+
+ curtime = time(NULL);
+ update = 0;
+
+ for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
+ sub;
+ sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
+ if ((!sub->job && !dest && sub->expire && sub->expire <= curtime) ||
+ (dest && sub->dest == dest) ||
+ (job && sub->job == job))
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "Subscription %d has expired...",
+ sub->id);
+
+ cupsdDeleteSubscription(sub, 0);
+
+ update = 1;
+ }
+
+ if (update)
+ cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
+}
+
+
+/*
+ * 'cupsdFindSubscription()' - Find a subscription by ID.
+ */
+
+cupsd_subscription_t * /* O - Subscription object */
+cupsdFindSubscription(int id) /* I - Subscription ID */
+{
+ cupsd_subscription_t sub; /* Subscription template */
+
+
+ sub.id = id;
+
+ return ((cupsd_subscription_t *)cupsArrayFind(Subscriptions, &sub));
+}
+
+
+/*
+ * 'cupsdLoadAllSubscriptions()' - Load all subscriptions from the .conf file.
+ */
+
+void
+cupsdLoadAllSubscriptions(void)
+{
+ int i; /* Looping var */
+ cups_file_t *fp; /* subscriptions.conf file */
+ int linenum; /* Current line number */
+ char line[1024], /* Line from file */
+ *value, /* Pointer to value */
+ *valueptr; /* Pointer into value */
+ cupsd_subscription_t *sub; /* Current subscription */
+ int hex; /* Non-zero if reading hex data */
+ int delete_sub; /* Delete subscription? */
+
+
+ /*
+ * Open the subscriptions.conf file...
+ */
+
+ snprintf(line, sizeof(line), "%s/subscriptions.conf", ServerRoot);
+ if ((fp = cupsdOpenConfFile(line)) == NULL)
+ return;
+
+ /*
+ * Read all of the lines from the file...
+ */
+
+ linenum = 0;
+ sub = NULL;
+ delete_sub = 0;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ if (!_cups_strcasecmp(line, "NextSubscriptionId") && value)
+ {
+ /*
+ * NextSubscriptionId NNN
+ */
+
+ i = atoi(value);
+ if (i >= NextSubscriptionId && i > 0)
+ NextSubscriptionId = i;
+ }
+ else if (!_cups_strcasecmp(line, "<Subscription"))
+ {
+ /*
+ * <Subscription #>
+ */
+
+ if (!sub && value && isdigit(value[0] & 255))
+ {
+ sub = cupsdAddSubscription(CUPSD_EVENT_NONE, NULL, NULL, NULL,
+ atoi(value));
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of subscriptions.conf.",
+ linenum);
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "</Subscription>"))
+ {
+ if (!sub)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of subscriptions.conf.",
+ linenum);
+ break;
+ }
+
+ if (delete_sub)
+ cupsdDeleteSubscription(sub, 0);
+
+ sub = NULL;
+ delete_sub = 0;
+ }
+ else if (!sub)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of subscriptions.conf.",
+ linenum);
+ }
+ else if (!_cups_strcasecmp(line, "Events"))
+ {
+ /*
+ * Events name
+ * Events name name name ...
+ */
+
+ if (!value)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of subscriptions.conf.",
+ linenum);
+ break;
+ }
+
+ while (*value)
+ {
+ /*
+ * Separate event names...
+ */
+
+ for (valueptr = value; !isspace(*valueptr) && *valueptr; valueptr ++);
+
+ while (isspace(*valueptr & 255))
+ *valueptr++ = '\0';
+
+ /*
+ * See if the name exists...
+ */
+
+ if ((sub->mask |= cupsdEventValue(value)) == CUPSD_EVENT_NONE)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown event name \'%s\' on line %d of subscriptions.conf.",
+ value, linenum);
+ break;
+ }
+
+ value = valueptr;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "Owner"))
+ {
+ /*
+ * Owner
+ */
+
+ if (value)
+ cupsdSetString(&sub->owner, value);
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of subscriptions.conf.",
+ linenum);
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "Recipient"))
+ {
+ /*
+ * Recipient uri
+ */
+
+ if (value)
+ cupsdSetString(&sub->recipient, value);
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of subscriptions.conf.",
+ linenum);
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "JobId"))
+ {
+ /*
+ * JobId #
+ */
+
+ if (value && isdigit(*value & 255))
+ {
+ if ((sub->job = cupsdFindJob(atoi(value))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Job %s not found on line %d of subscriptions.conf.",
+ value, linenum);
+ delete_sub = 1;
+ }
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of subscriptions.conf.",
+ linenum);
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "PrinterName"))
+ {
+ /*
+ * PrinterName name
+ */
+
+ if (value)
+ {
+ if ((sub->dest = cupsdFindDest(value)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Printer \'%s\' not found on line %d of subscriptions.conf.",
+ value, linenum);
+ delete_sub = 1;
+ }
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of subscriptions.conf.",
+ linenum);
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "UserData"))
+ {
+ /*
+ * UserData encoded-string
+ */
+
+ if (value)
+ {
+ for (i = 0, valueptr = value, hex = 0; i < 63 && *valueptr; i ++)
+ {
+ if (*valueptr == '<' && !hex)
+ {
+ hex = 1;
+ valueptr ++;
+ }
+
+ if (hex)
+ {
+ if (isxdigit(valueptr[0]) && isxdigit(valueptr[1]))
+ {
+ if (isdigit(valueptr[0]))
+ sub->user_data[i] = (valueptr[0] - '0') << 4;
+ else
+ sub->user_data[i] = (tolower(valueptr[0]) - 'a' + 10) << 4;
+
+ if (isdigit(valueptr[1]))
+ sub->user_data[i] |= valueptr[1] - '0';
+ else
+ sub->user_data[i] |= tolower(valueptr[1]) - 'a' + 10;
+
+ valueptr += 2;
+
+ if (*valueptr == '>')
+ {
+ hex = 0;
+ valueptr ++;
+ }
+ }
+ else
+ break;
+ }
+ else
+ sub->user_data[i] = *valueptr++;
+ }
+
+ if (*valueptr)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad UserData \'%s\' on line %d of subscriptions.conf.",
+ value, linenum);
+ }
+ else
+ sub->user_data_len = i;
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of subscriptions.conf.",
+ linenum);
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "LeaseDuration"))
+ {
+ /*
+ * LeaseDuration #
+ */
+
+ if (value && isdigit(*value & 255))
+ {
+ sub->lease = atoi(value);
+ sub->expire = sub->lease ? time(NULL) + sub->lease : 0;
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of subscriptions.conf.",
+ linenum);
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "Interval"))
+ {
+ /*
+ * Interval #
+ */
+
+ if (value && isdigit(*value & 255))
+ sub->interval = atoi(value);
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of subscriptions.conf.",
+ linenum);
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "ExpirationTime"))
+ {
+ /*
+ * ExpirationTime #
+ */
+
+ if (value && isdigit(*value & 255))
+ sub->expire = atoi(value);
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of subscriptions.conf.",
+ linenum);
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(line, "NextEventId"))
+ {
+ /*
+ * NextEventId #
+ */
+
+ if (value && isdigit(*value & 255))
+ sub->next_event_id = sub->first_event_id = atoi(value);
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of subscriptions.conf.",
+ linenum);
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Something else we don't understand...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unknown configuration directive %s on line %d of subscriptions.conf.",
+ line, linenum);
+ }
+ }
+
+ cupsFileClose(fp);
+}
+
+
+/*
+ * 'cupsdSaveAllSubscriptions()' - Save all subscriptions to the .conf file.
+ */
+
+void
+cupsdSaveAllSubscriptions(void)
+{
+ int i; /* Looping var */
+ cups_file_t *fp; /* subscriptions.conf file */
+ char filename[1024], /* subscriptions.conf filename */
+ temp[1024]; /* Temporary string */
+ cupsd_subscription_t *sub; /* Current subscription */
+ time_t curtime; /* Current time */
+ struct tm *curdate; /* Current date */
+ unsigned mask; /* Current event mask */
+ const char *name; /* Current event name */
+ int hex; /* Non-zero if we are writing hex data */
+
+
+ /*
+ * Create the subscriptions.conf file...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/subscriptions.conf", ServerRoot);
+
+ if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm)) == NULL)
+ return;
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Saving subscriptions.conf...");
+
+ /*
+ * Write a small header to the file...
+ */
+
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+ strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
+
+ cupsFilePuts(fp, "# Subscription configuration file for " CUPS_SVERSION "\n");
+ cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
+
+ cupsFilePrintf(fp, "NextSubscriptionId %d\n", NextSubscriptionId);
+
+ /*
+ * Write every subscription known to the system...
+ */
+
+ for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
+ sub;
+ sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
+ {
+ cupsFilePrintf(fp, "<Subscription %d>\n", sub->id);
+
+ if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL)
+ {
+ /*
+ * Simple event list...
+ */
+
+ cupsFilePrintf(fp, "Events %s\n", name);
+ }
+ else
+ {
+ /*
+ * Complex event list...
+ */
+
+ cupsFilePuts(fp, "Events");
+
+ for (mask = 1; mask < CUPSD_EVENT_ALL; mask <<= 1)
+ if (sub->mask & mask)
+ cupsFilePrintf(fp, " %s", cupsdEventName((cupsd_eventmask_t)mask));
+
+ cupsFilePuts(fp, "\n");
+ }
+
+ if (sub->owner)
+ cupsFilePrintf(fp, "Owner %s\n", sub->owner);
+ if (sub->recipient)
+ cupsFilePrintf(fp, "Recipient %s\n", sub->recipient);
+ if (sub->job)
+ cupsFilePrintf(fp, "JobId %d\n", sub->job->id);
+ if (sub->dest)
+ cupsFilePrintf(fp, "PrinterName %s\n", sub->dest->name);
+
+ if (sub->user_data_len > 0)
+ {
+ cupsFilePuts(fp, "UserData ");
+
+ for (i = 0, hex = 0; i < sub->user_data_len; i ++)
+ {
+ if (sub->user_data[i] < ' ' ||
+ sub->user_data[i] > 0x7f ||
+ sub->user_data[i] == '<')
+ {
+ if (!hex)
+ {
+ cupsFilePrintf(fp, "<%02X", sub->user_data[i]);
+ hex = 1;
+ }
+ else
+ cupsFilePrintf(fp, "%02X", sub->user_data[i]);
+ }
+ else
+ {
+ if (hex)
+ {
+ cupsFilePrintf(fp, ">%c", sub->user_data[i]);
+ hex = 0;
+ }
+ else
+ cupsFilePutChar(fp, sub->user_data[i]);
+ }
+ }
+
+ if (hex)
+ cupsFilePuts(fp, ">\n");
+ else
+ cupsFilePutChar(fp, '\n');
+ }
+
+ cupsFilePrintf(fp, "LeaseDuration %d\n", sub->lease);
+ cupsFilePrintf(fp, "Interval %d\n", sub->interval);
+ cupsFilePrintf(fp, "ExpirationTime %ld\n", (long)sub->expire);
+ cupsFilePrintf(fp, "NextEventId %d\n", sub->next_event_id);
+
+ cupsFilePuts(fp, "</Subscription>\n");
+ }
+
+ cupsdCloseCreatedConfFile(fp, filename);
+}
+
+
+/*
+ * 'cupsdStopAllNotifiers()' - Stop all notifier processes.
+ */
+
+void
+cupsdStopAllNotifiers(void)
+{
+ cupsd_subscription_t *sub; /* Current subscription */
+
+
+ /*
+ * See if we have started any notifiers...
+ */
+
+ if (!NotifierStatusBuffer)
+ return;
+
+ /*
+ * Yes, kill any processes that are left...
+ */
+
+ for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
+ sub;
+ sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
+ if (sub->pid)
+ {
+ cupsdEndProcess(sub->pid, 0);
+
+ close(sub->pipe);
+ sub->pipe = -1;
+ }
+
+ /*
+ * Close the status pipes...
+ */
+
+ if (NotifierPipes[0] >= 0)
+ {
+ cupsdRemoveSelect(NotifierPipes[0]);
+
+ cupsdStatBufDelete(NotifierStatusBuffer);
+
+ close(NotifierPipes[0]);
+ close(NotifierPipes[1]);
+
+ NotifierPipes[0] = -1;
+ NotifierPipes[1] = -1;
+ NotifierStatusBuffer = NULL;
+ }
+}
+
+
+/*
+ * 'cupsd_compare_subscriptions()' - Compare two subscriptions.
+ */
+
+static int /* O - Result of comparison */
+cupsd_compare_subscriptions(
+ cupsd_subscription_t *first, /* I - First subscription object */
+ cupsd_subscription_t *second, /* I - Second subscription object */
+ void *unused) /* I - Unused user data pointer */
+{
+ (void)unused;
+
+ return (first->id - second->id);
+}
+
+
+/*
+ * 'cupsd_delete_event()' - Delete a single event...
+ *
+ * Oldest events must be deleted first, otherwise the subscription cache
+ * flushing code will not work properly.
+ */
+
+static void
+cupsd_delete_event(cupsd_event_t *event)/* I - Event to delete */
+{
+ /*
+ * Free memory...
+ */
+
+ ippDelete(event->attrs);
+ free(event);
+}
+
+
+#ifdef HAVE_DBUS
+/*
+ * 'cupsd_send_dbus()' - Send a DBUS notification...
+ */
+
+static void
+cupsd_send_dbus(cupsd_eventmask_t event,/* I - Event to send */
+ cupsd_printer_t *dest,/* I - Destination, if any */
+ cupsd_job_t *job) /* I - Job, if any */
+{
+ DBusError error; /* Error, if any */
+ DBusMessage *message; /* Message to send */
+ DBusMessageIter iter; /* Iterator for message data */
+ const char *what; /* What to send */
+ static DBusConnection *con = NULL; /* Connection to DBUS server */
+
+
+ /*
+ * Figure out what to send, if anything...
+ */
+
+ if (event & CUPSD_EVENT_PRINTER_ADDED)
+ what = "PrinterAdded";
+ else if (event & CUPSD_EVENT_PRINTER_DELETED)
+ what = "PrinterRemoved";
+ else if (event & CUPSD_EVENT_PRINTER_CHANGED)
+ what = "QueueChanged";
+ else if (event & CUPSD_EVENT_JOB_CREATED)
+ what = "JobQueuedLocal";
+ else if ((event & CUPSD_EVENT_JOB_STATE) && job &&
+ job->state_value == IPP_JOB_PROCESSING)
+ what = "JobStartedLocal";
+ else
+ return;
+
+ /*
+ * Verify connection to DBUS server...
+ */
+
+ if (con && !dbus_connection_get_is_connected(con))
+ {
+ dbus_connection_unref(con);
+ con = NULL;
+ }
+
+ if (!con)
+ {
+ dbus_error_init(&error);
+
+ con = dbus_bus_get(getuid() ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error);
+ if (!con)
+ {
+ dbus_error_free(&error);
+ return;
+ }
+ }
+
+ /*
+ * Create and send the new message...
+ */
+
+ message = dbus_message_new_signal("/com/redhat/PrinterSpooler",
+ "com.redhat.PrinterSpooler", what);
+
+ dbus_message_append_iter_init(message, &iter);
+ if (dest)
+ dbus_message_iter_append_string(&iter, dest->name);
+ if (job)
+ {
+ dbus_message_iter_append_uint32(&iter, job->id);
+ dbus_message_iter_append_string(&iter, job->username);
+ }
+
+ dbus_connection_send(con, message, NULL);
+ dbus_connection_flush(con);
+ dbus_message_unref(message);
+}
+#endif /* HAVE_DBUS */
+
+
+/*
+ * 'cupsd_send_notification()' - Send a notification for the specified event.
+ */
+
+static void
+cupsd_send_notification(
+ cupsd_subscription_t *sub, /* I - Subscription object */
+ cupsd_event_t *event) /* I - Event to send */
+{
+ ipp_state_t state; /* IPP event state */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsd_send_notification(sub=%p(%d), event=%p(%s))",
+ sub, sub->id, event, cupsdEventName(event->event));
+
+ /*
+ * Allocate the events array as needed...
+ */
+
+ if (!sub->events)
+ {
+ sub->events = cupsArrayNew3((cups_array_func_t)NULL, NULL,
+ (cups_ahash_func_t)NULL, 0,
+ (cups_acopy_func_t)NULL,
+ (cups_afree_func_t)cupsd_delete_event);
+
+ if (!sub->events)
+ {
+ cupsdLogMessage(CUPSD_LOG_CRIT,
+ "Unable to allocate memory for subscription #%d!",
+ sub->id);
+ return;
+ }
+ }
+
+ /*
+ * Purge an old event as needed...
+ */
+
+ if (cupsArrayCount(sub->events) >= MaxEvents)
+ {
+ /*
+ * Purge the oldest event in the cache...
+ */
+
+ cupsArrayRemove(sub->events, cupsArrayFirst(sub->events));
+
+ sub->first_event_id ++;
+ }
+
+ /*
+ * Add the event to the subscription. Since the events array is
+ * always MaxEvents in length, and since we will have already
+ * removed an event from the subscription cache if we hit the
+ * event cache limit, we don't need to check for overflow here...
+ */
+
+ cupsArrayAdd(sub->events, event);
+
+ /*
+ * Deliver the event...
+ */
+
+ if (sub->recipient)
+ {
+ for (;;)
+ {
+ if (sub->pipe < 0)
+ cupsd_start_notifier(sub);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "sub->pipe=%d", sub->pipe);
+
+ if (sub->pipe < 0)
+ break;
+
+ event->attrs->state = IPP_IDLE;
+
+ while ((state = ippWriteFile(sub->pipe, event->attrs)) != IPP_DATA)
+ if (state == IPP_ERROR)
+ break;
+
+ if (state == IPP_ERROR)
+ {
+ if (errno == EPIPE)
+ {
+ /*
+ * Notifier died, try restarting it...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Notifier for subscription %d (%s) went away, "
+ "retrying!",
+ sub->id, sub->recipient);
+ cupsdEndProcess(sub->pid, 0);
+
+ close(sub->pipe);
+ sub->pipe = -1;
+ continue;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to send event for subscription %d (%s)!",
+ sub->id, sub->recipient);
+ }
+
+ /*
+ * If we get this far, break out of the loop...
+ */
+
+ break;
+ }
+ }
+
+ /*
+ * Bump the event sequence number...
+ */
+
+ sub->next_event_id ++;
+}
+
+
+/*
+ * 'cupsd_start_notifier()' - Start a notifier subprocess...
+ */
+
+static void
+cupsd_start_notifier(
+ cupsd_subscription_t *sub) /* I - Subscription object */
+{
+ int pid; /* Notifier process ID */
+ int fds[2]; /* Pipe file descriptors */
+ char *argv[4], /* Command-line arguments */
+ *envp[MAX_ENV], /* Environment variables */
+ user_data[128], /* Base-64 encoded user data */
+ scheme[256], /* notify-recipient-uri scheme */
+ *ptr, /* Pointer into scheme */
+ command[1024]; /* Notifier command */
+
+
+ /*
+ * Extract the scheme name from the recipient URI and point to the
+ * notifier program...
+ */
+
+ strlcpy(scheme, sub->recipient, sizeof(scheme));
+ if ((ptr = strchr(scheme, ':')) != NULL)
+ *ptr = '\0';
+
+ snprintf(command, sizeof(command), "%s/notifier/%s", ServerBin, scheme);
+
+ /*
+ * Base-64 encode the user data...
+ */
+
+ httpEncode64_2(user_data, sizeof(user_data), (char *)sub->user_data,
+ sub->user_data_len);
+
+ /*
+ * Setup the argument array...
+ */
+
+ argv[0] = command;
+ argv[1] = sub->recipient;
+ argv[2] = user_data;
+ argv[3] = NULL;
+
+ /*
+ * Setup the environment...
+ */
+
+ cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
+
+ /*
+ * Create pipes as needed...
+ */
+
+ if (!NotifierStatusBuffer)
+ {
+ /*
+ * Create the status pipe...
+ */
+
+ if (cupsdOpenPipe(NotifierPipes))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create pipes for notifier status - %s",
+ strerror(errno));
+ return;
+ }
+
+ NotifierStatusBuffer = cupsdStatBufNew(NotifierPipes[0], "[Notifier]");
+
+ cupsdAddSelect(NotifierPipes[0], (cupsd_selfunc_t)cupsd_update_notifier,
+ NULL, NULL);
+ }
+
+ if (cupsdOpenPipe(fds))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create pipes for notifier %s - %s",
+ scheme, strerror(errno));
+ return;
+ }
+
+ /*
+ * Make sure the delivery pipe is non-blocking...
+ */
+
+ fcntl(fds[1], F_SETFL, fcntl(fds[1], F_GETFL) | O_NONBLOCK);
+
+ /*
+ * Create the notifier process...
+ */
+
+ if (cupsdStartProcess(command, argv, envp, fds[0], -1, NotifierPipes[1],
+ -1, -1, 0, DefaultProfile, NULL, &pid) < 0)
+ {
+ /*
+ * Error - can't fork!
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to fork for notifier %s - %s",
+ scheme, strerror(errno));
+
+ cupsdClosePipe(fds);
+ }
+ else
+ {
+ /*
+ * Fork successful - return the PID...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Notifier %s started - PID = %d",
+ scheme, pid);
+
+ sub->pid = pid;
+ sub->pipe = fds[1];
+ sub->status = 0;
+
+ close(fds[0]);
+ }
+}
+
+
+/*
+ * 'cupsd_update_notifier()' - Read messages from notifiers.
+ */
+
+void
+cupsd_update_notifier(void)
+{
+ char message[1024]; /* Pointer to message text */
+ int loglevel; /* Log level for message */
+
+
+ while (cupsdStatBufUpdate(NotifierStatusBuffer, &loglevel,
+ message, sizeof(message)))
+ {
+ if (loglevel == CUPSD_LOG_INFO)
+ cupsdLogMessage(CUPSD_LOG_INFO, "%s", message);
+
+ if (!strchr(NotifierStatusBuffer->buffer, '\n'))
+ break;
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/subscriptions.h b/scheduler/subscriptions.h
new file mode 100644
index 000000000..eac866956
--- /dev/null
+++ b/scheduler/subscriptions.h
@@ -0,0 +1,166 @@
+/*
+ * "$Id$"
+ *
+ * Subscription definitions for the CUPS scheduler.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/*
+ * Event mask enumeration...
+ */
+
+typedef enum
+{
+ /* Individual printer events... */
+ CUPSD_EVENT_PRINTER_STATE = 0x0001, /* Sent after generic printer state change */
+ CUPSD_EVENT_PRINTER_RESTARTED = 0x0002,
+ /* Sent after printer restarted */
+ CUPSD_EVENT_PRINTER_SHUTDOWN = 0x0004,/* Sent after printer shutdown */
+ CUPSD_EVENT_PRINTER_STOPPED = 0x0008, /* Sent after printer stopped */
+
+ CUPSD_EVENT_PRINTER_CONFIG = 0x0010, /* Send after add/modify changes attrs */
+ CUPSD_EVENT_PRINTER_FINISHINGS_CHANGED = 0x0020,
+ /* Sent after finishings-supported changed */
+ CUPSD_EVENT_PRINTER_MEDIA_CHANGED = 0x0040,
+ /* Sent after media-supported changed */
+ CUPSD_EVENT_PRINTER_ADDED = 0x0080, /* Sent after printer added */
+ CUPSD_EVENT_PRINTER_DELETED = 0x0100, /* Sent after printer deleted */
+ CUPSD_EVENT_PRINTER_MODIFIED = 0x0200,/* Sent after printer modified */
+ CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED = 0x0400,
+ /* Sent when the order of jobs is changed */
+
+ /* Convenience printer event groupings... */
+ CUPSD_EVENT_PRINTER_STATE_CHANGED = 0x000f,
+ /* STATE + RESTARTED + SHUTDOWN + STOPPED */
+ CUPSD_EVENT_PRINTER_CONFIG_CHANGED = 0x0070,
+ /* CONFIG + FINISHINGS_CHANGED + MEDIA_CHANGED */
+ CUPSD_EVENT_PRINTER_CHANGED = 0x07ff, /* All of the above */
+
+ /* Individual job events... */
+ CUPSD_EVENT_JOB_STATE = 0x0800, /* Any state change */
+ CUPSD_EVENT_JOB_CREATED = 0x1000, /* Send after job is created */
+ CUPSD_EVENT_JOB_COMPLETED = 0x2000, /* Sent after job is completed */
+ CUPSD_EVENT_JOB_STOPPED = 0x4000, /* Sent after job is stopped */
+ CUPSD_EVENT_JOB_CONFIG_CHANGED = 0x8000,
+ /* Sent after set-job-attributes */
+ CUPSD_EVENT_JOB_PROGRESS = 0x10000, /* Sent for each page */
+
+ /* Convenience job event grouping... */
+ CUPSD_EVENT_JOB_STATE_CHANGED = 0x7800,
+ /* STATE + CREATED + COMPLETED + STOPPED */
+
+ /* Server events... */
+ CUPSD_EVENT_SERVER_RESTARTED = 0x20000,/* Sent after server restarts */
+ CUPSD_EVENT_SERVER_STARTED = 0x40000, /* Sent when server first starts */
+ CUPSD_EVENT_SERVER_STOPPED = 0x80000, /* Sent when server is stopped */
+ CUPSD_EVENT_SERVER_AUDIT = 0x100000, /* Security-related stuff */
+
+ /* Everything and nothing... */
+ CUPSD_EVENT_NONE = 0, /* Nothing */
+ CUPSD_EVENT_ALL = 0x1fffff /* Everything */
+} cupsd_eventmask_t;
+
+
+/*
+ * Notiification support structures...
+ */
+
+typedef struct cupsd_event_s /**** Event structure ****/
+{
+ cupsd_eventmask_t event; /* Event */
+ time_t time; /* Time of event */
+ ipp_t *attrs; /* Notification message */
+ cupsd_printer_t *dest; /* Associated printer, if any */
+ cupsd_job_t *job; /* Associated job, if any */
+} cupsd_event_t;
+
+typedef struct cupsd_subscription_s /**** Subscription structure ****/
+{
+ int id; /* subscription-id */
+ unsigned mask; /* Event mask */
+ char *owner; /* notify-subscriber-user-name */
+ char *recipient; /* notify-recipient-uri, if applicable */
+ unsigned char user_data[64]; /* notify-user-data */
+ int user_data_len; /* Length of notify-user-data */
+ int lease; /* notify-lease-duration */
+ int interval; /* notify-time-interval */
+ cupsd_printer_t *dest; /* notify-printer-uri, if any */
+ cupsd_job_t *job; /* notify-job-id, if any */
+ int pid; /* Process ID of notifier */
+ int pipe; /* Pipe to notifier */
+ int status; /* Exit status of notifier */
+ time_t last; /* Time of last notification */
+ time_t expire; /* Lease expiration time */
+ int first_event_id, /* First event-id in cache */
+ next_event_id; /* Next event-id to use */
+ cups_array_t *events; /* Cached events */
+} cupsd_subscription_t;
+
+
+/*
+ * Globals...
+ */
+
+VAR int MaxSubscriptions VALUE(100),
+ /* Overall subscription limit */
+ MaxSubscriptionsPerJob VALUE(0),
+ /* Per-job subscription limit */
+ MaxSubscriptionsPerPrinter VALUE(0),
+ /* Per-printer subscription limit */
+ MaxSubscriptionsPerUser VALUE(0),
+ /* Per-user subscription limit */
+ NextSubscriptionId VALUE(1),
+ /* Next subscription ID */
+ DefaultLeaseDuration VALUE(86400),
+ /* Default notify-lease-duration */
+ MaxLeaseDuration VALUE(0);
+ /* Maximum notify-lease-duration */
+VAR cups_array_t *Subscriptions VALUE(NULL);
+ /* Active subscriptions */
+
+VAR int MaxEvents VALUE(100); /* Maximum number of events */
+
+VAR unsigned LastEvent VALUE(0); /* Last event(s) processed */
+VAR int NotifierPipes[2] VALUE2(-1, -1);
+ /* Pipes for notifier error/debug output */
+VAR cupsd_statbuf_t *NotifierStatusBuffer VALUE(NULL);
+ /* Status buffer for pipes */
+
+
+/*
+ * Prototypes...
+ */
+
+extern void cupsdAddEvent(cupsd_eventmask_t event, cupsd_printer_t *dest,
+ cupsd_job_t *job, const char *text, ...);
+extern cupsd_subscription_t *
+ cupsdAddSubscription(unsigned mask, cupsd_printer_t *dest,
+ cupsd_job_t *job, const char *uri,
+ int sub_id);
+extern void cupsdDeleteAllSubscriptions(void);
+extern void cupsdDeleteSubscription(cupsd_subscription_t *sub, int update);
+extern const char *
+ cupsdEventName(cupsd_eventmask_t event);
+extern cupsd_eventmask_t
+ cupsdEventValue(const char *name);
+
+extern cupsd_subscription_t *
+ cupsdFindSubscription(int id);
+extern void cupsdExpireSubscriptions(cupsd_printer_t *dest,
+ cupsd_job_t *job);
+extern void cupsdLoadAllSubscriptions(void);
+extern void cupsdSaveAllSubscriptions(void);
+extern void cupsdStopAllNotifiers(void);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/sysman.c b/scheduler/sysman.c
new file mode 100644
index 000000000..5e2827eea
--- /dev/null
+++ b/scheduler/sysman.c
@@ -0,0 +1,1020 @@
+/*
+ * "$Id$"
+ *
+ * System management functions for the CUPS scheduler.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdCleanDirty() - Write dirty config and state files.
+ * cupsdMarkDirty() - Mark config or state files as needing a
+ * write.
+ * cupsdSetBusyState() - Let the system know when we are busy
+ * doing something.
+ * cupsdAllowSleep() - Tell the OS it is now OK to sleep.
+ * cupsdStartSystemMonitor() - Start monitoring for system change.
+ * cupsdStopSystemMonitor() - Stop monitoring for system change.
+ * sysEventThreadEntry() - A thread to receive power and computer
+ * name change notifications.
+ * sysEventPowerNotifier() - Handle power notification events.
+ * sysEventConfigurationNotifier() - Computer name changed notification
+ * callback.
+ * sysEventTimerNotifier() - Handle delayed event notifications.
+ * sysUpdate() - Update the current system state.
+ */
+
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#ifdef HAVE_VPROC_TRANSACTION_BEGIN
+# include <vproc.h>
+#endif /* HAVE_VPROC_TRANSACTION_BEGIN */
+#ifdef __APPLE__
+# include <IOKit/pwr_mgt/IOPMLib.h>
+# ifdef HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H
+# include <IOKit/pwr_mgt/IOPMLibPrivate.h>
+# endif /* HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H */
+#endif /* __APPLE__ */
+
+
+/*
+ * The system management functions cover disk and power management which
+ * are primarily used on portable computers.
+ *
+ * Disk management involves delaying the write of certain configuration
+ * and state files to minimize the number of times the disk has to spin
+ * up.
+ *
+ * Power management support is currently only implemented on MacOS X, but
+ * essentially we use four functions to let the OS know when it is OK to
+ * put the system to sleep, typically when we are not in the middle of
+ * printing a job.
+ *
+ * Once put to sleep, we invalidate all remote printers since it is common
+ * to wake up in a new location/on a new wireless network.
+ */
+
+/*
+ * Local globals...
+ */
+
+#ifdef kIOPMAssertionTypeDenySystemSleep
+static IOPMAssertionID dark_wake = 0; /* "Dark wake" assertion for sharing */
+#endif /* kIOPMAssertionTypeDenySystemSleep */
+
+
+/*
+ * 'cupsdCleanDirty()' - Write dirty config and state files.
+ */
+
+void
+cupsdCleanDirty(void)
+{
+ if (DirtyFiles & CUPSD_DIRTY_PRINTERS)
+ cupsdSaveAllPrinters();
+
+ if (DirtyFiles & CUPSD_DIRTY_CLASSES)
+ cupsdSaveAllClasses();
+
+ if (DirtyFiles & CUPSD_DIRTY_REMOTE)
+ cupsdSaveRemoteCache();
+
+ if (DirtyFiles & CUPSD_DIRTY_PRINTCAP)
+ cupsdWritePrintcap();
+
+ if (DirtyFiles & CUPSD_DIRTY_JOBS)
+ {
+ cupsd_job_t *job; /* Current job */
+
+ cupsdSaveAllJobs();
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(Jobs))
+ if (job->dirty)
+ cupsdSaveJob(job);
+ }
+
+ if (DirtyFiles & CUPSD_DIRTY_SUBSCRIPTIONS)
+ cupsdSaveAllSubscriptions();
+
+ DirtyFiles = CUPSD_DIRTY_NONE;
+ DirtyCleanTime = 0;
+
+ cupsdSetBusyState();
+}
+
+
+/*
+ * 'cupsdMarkDirty()' - Mark config or state files as needing a write.
+ */
+
+void
+cupsdMarkDirty(int what) /* I - What file(s) are dirty? */
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdMarkDirty(%c%c%c%c%c%c)",
+ (what & CUPSD_DIRTY_PRINTERS) ? 'P' : '-',
+ (what & CUPSD_DIRTY_CLASSES) ? 'C' : '-',
+ (what & CUPSD_DIRTY_REMOTE) ? 'R' : '-',
+ (what & CUPSD_DIRTY_PRINTCAP) ? 'p' : '-',
+ (what & CUPSD_DIRTY_JOBS) ? 'J' : '-',
+ (what & CUPSD_DIRTY_SUBSCRIPTIONS) ? 'S' : '-');
+
+ if (what == CUPSD_DIRTY_PRINTCAP && !Printcap)
+ return;
+
+ DirtyFiles |= what;
+
+ if (!DirtyCleanTime)
+ DirtyCleanTime = time(NULL) + DirtyCleanInterval;
+
+ cupsdSetBusyState();
+}
+
+
+/*
+ * 'cupsdSetBusyState()' - Let the system know when we are busy doing something.
+ */
+
+void
+cupsdSetBusyState(void)
+{
+ int i; /* Looping var */
+ cupsd_job_t *job; /* Current job */
+ cupsd_printer_t *p; /* Current printer */
+ int newbusy; /* New busy state */
+ static int busy = 0; /* Current busy state */
+ static const char * const busy_text[] =
+ { /* Text for busy states */
+ "Not busy",
+ "Dirty files",
+ "Printing jobs",
+ "Printing jobs and dirty files",
+ "Active clients",
+ "Active clients and dirty files",
+ "Active clients and printing jobs",
+ "Active clients, printing jobs, and dirty files"
+ };
+#ifdef HAVE_VPROC_TRANSACTION_BEGIN
+ static vproc_transaction_t vtran = 0; /* Current busy transaction */
+#endif /* HAVE_VPROC_TRANSACTION_BEGIN */
+
+
+ /*
+ * Figure out how busy we are...
+ */
+
+ newbusy = (DirtyCleanTime ? 1 : 0) |
+ (cupsArrayCount(ActiveClients) ? 4 : 0);
+
+ for (job = (cupsd_job_t *)cupsArrayFirst(PrintingJobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(PrintingJobs))
+ {
+ if ((p = job->printer) != NULL)
+ {
+ for (i = 0; i < p->num_reasons; i ++)
+ if (!strcmp(p->reasons[i], "connecting-to-device"))
+ break;
+
+ if (!p->num_reasons || i >= p->num_reasons)
+ break;
+ }
+ }
+
+ if (job)
+ newbusy |= 2;
+
+ /*
+ * Manage state changes...
+ */
+
+ if (newbusy != busy)
+ {
+ busy = newbusy;
+
+#ifdef HAVE_VPROC_TRANSACTION_BEGIN
+ if (busy && !vtran)
+ vtran = vproc_transaction_begin(NULL);
+ else if (!busy && vtran)
+ {
+ vproc_transaction_end(NULL, vtran);
+ vtran = 0;
+ }
+#endif /* HAVE_VPROC_TRANSACTION_BEGIN */
+
+#ifdef kIOPMAssertionTypeDenySystemSleep
+ if ((busy & 2) && !dark_wake)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "Asserting dark wake.");
+ IOPMAssertionCreateWithName(kIOPMAssertionTypeDenySystemSleep,
+ kIOPMAssertionLevelOn,
+ CFSTR("org.cups.cupsd"), &dark_wake);
+ }
+ else if (!(busy & 2) && dark_wake)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "Releasing dark wake assertion.");
+ IOPMAssertionRelease(dark_wake);
+ dark_wake = 0;
+ }
+#endif /* kIOPMAssertionTypeDenySystemSleep */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSetBusyState: %s", busy_text[busy]);
+ }
+}
+
+
+#ifdef __APPLE__
+/*
+ * This is the Apple-specific system event code. It works by creating
+ * a worker thread that waits for events from the OS and relays them
+ * to the main thread via a traditional pipe.
+ */
+
+/*
+ * Include MacOS-specific headers...
+ */
+
+# include <IOKit/IOKitLib.h>
+# include <IOKit/IOMessage.h>
+# include <IOKit/pwr_mgt/IOPMLib.h>
+# include <SystemConfiguration/SystemConfiguration.h>
+# include <pthread.h>
+
+
+/*
+ * Constants...
+ */
+
+# define SYSEVENT_CANSLEEP 0x1 /* Decide whether to allow sleep or not */
+# define SYSEVENT_WILLSLEEP 0x2 /* Computer will go to sleep */
+# define SYSEVENT_WOKE 0x4 /* Computer woke from sleep */
+# define SYSEVENT_NETCHANGED 0x8 /* Network changed */
+# define SYSEVENT_NAMECHANGED 0x10 /* Computer name changed */
+
+
+/*
+ * Structures...
+ */
+
+typedef struct cupsd_sysevent_s /*** System event data ****/
+{
+ unsigned char event; /* Event bit field */
+ io_connect_t powerKernelPort; /* Power context data */
+ long powerNotificationID; /* Power event data */
+} cupsd_sysevent_t;
+
+
+typedef struct cupsd_thread_data_s /*** Thread context data ****/
+{
+ cupsd_sysevent_t sysevent; /* System event */
+ CFRunLoopTimerRef timerRef; /* Timer to delay some change *
+ * notifications */
+} cupsd_thread_data_t;
+
+
+/*
+ * Local globals...
+ */
+
+static pthread_t SysEventThread = NULL;
+ /* Thread to host a runloop */
+static pthread_mutex_t SysEventThreadMutex = { 0 };
+ /* Coordinates access to shared gloabals */
+static pthread_cond_t SysEventThreadCond = { 0 };
+ /* Thread initialization complete condition */
+static CFRunLoopRef SysEventRunloop = NULL;
+ /* The runloop. Access must be protected! */
+static CFStringRef ComputerNameKey = NULL,
+ /* Computer name key */
+ BTMMKey = NULL, /* Back to My Mac key */
+ NetworkGlobalKeyIPv4 = NULL,
+ /* Network global IPv4 key */
+ NetworkGlobalKeyIPv6 = NULL,
+ /* Network global IPv6 key */
+ NetworkGlobalKeyDNS = NULL,
+ /* Network global DNS key */
+ HostNamesKey = NULL,
+ /* Host name key */
+ NetworkInterfaceKeyIPv4 = NULL,
+ /* Netowrk interface key */
+ NetworkInterfaceKeyIPv6 = NULL;
+ /* Netowrk interface key */
+static cupsd_sysevent_t LastSysEvent; /* Last system event (for delayed sleep) */
+
+
+/*
+ * Local functions...
+ */
+
+static void *sysEventThreadEntry(void);
+static void sysEventPowerNotifier(void *context, io_service_t service,
+ natural_t messageType,
+ void *messageArgument);
+static void sysEventConfigurationNotifier(SCDynamicStoreRef store,
+ CFArrayRef changedKeys,
+ void *context);
+static void sysEventTimerNotifier(CFRunLoopTimerRef timer, void *context);
+static void sysUpdate(void);
+
+
+/*
+ * 'cupsdAllowSleep()' - Tell the OS it is now OK to sleep.
+ */
+
+void
+cupsdAllowSleep(void)
+{
+ cupsdCleanDirty();
+
+ IOAllowPowerChange(LastSysEvent.powerKernelPort,
+ LastSysEvent.powerNotificationID);
+}
+
+
+/*
+ * 'cupsdStartSystemMonitor()' - Start monitoring for system change.
+ */
+
+void
+cupsdStartSystemMonitor(void)
+{
+ int flags; /* fcntl flags on pipe */
+
+
+ if (cupsdOpenPipe(SysEventPipes))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "System event monitor pipe() failed - %s!",
+ strerror(errno));
+ return;
+ }
+
+ cupsdAddSelect(SysEventPipes[0], (cupsd_selfunc_t)sysUpdate, NULL, NULL);
+
+ /*
+ * Set non-blocking mode on the descriptor we will be receiving notification
+ * events on.
+ */
+
+ flags = fcntl(SysEventPipes[0], F_GETFL, 0);
+ fcntl(SysEventPipes[0], F_SETFL, flags | O_NONBLOCK);
+
+ /*
+ * Start the thread that runs the runloop...
+ */
+
+ pthread_mutex_init(&SysEventThreadMutex, NULL);
+ pthread_cond_init(&SysEventThreadCond, NULL);
+ pthread_create(&SysEventThread, NULL, (void *(*)())sysEventThreadEntry, NULL);
+}
+
+
+/*
+ * 'cupsdStopSystemMonitor()' - Stop monitoring for system change.
+ */
+
+void
+cupsdStopSystemMonitor(void)
+{
+ CFRunLoopRef rl; /* The event handler runloop */
+
+
+ if (SysEventThread)
+ {
+ /*
+ * Make sure the thread has completed it's initialization and
+ * stored it's runloop reference in the shared global.
+ */
+
+ pthread_mutex_lock(&SysEventThreadMutex);
+
+ if (!SysEventRunloop)
+ pthread_cond_wait(&SysEventThreadCond, &SysEventThreadMutex);
+
+ rl = SysEventRunloop;
+ SysEventRunloop = NULL;
+
+ pthread_mutex_unlock(&SysEventThreadMutex);
+
+ if (rl)
+ CFRunLoopStop(rl);
+
+ pthread_join(SysEventThread, NULL);
+ pthread_mutex_destroy(&SysEventThreadMutex);
+ pthread_cond_destroy(&SysEventThreadCond);
+ }
+
+ if (SysEventPipes[0] >= 0)
+ {
+ cupsdRemoveSelect(SysEventPipes[0]);
+ cupsdClosePipe(SysEventPipes);
+ }
+}
+
+
+/*
+ * 'sysEventThreadEntry()' - A thread to receive power and computer name
+ * change notifications.
+ */
+
+static void * /* O - Return status/value */
+sysEventThreadEntry(void)
+{
+ io_object_t powerNotifierObj;
+ /* Power notifier object */
+ IONotificationPortRef powerNotifierPort;
+ /* Power notifier port */
+ SCDynamicStoreRef store = NULL;/* System Config dynamic store */
+ CFRunLoopSourceRef powerRLS = NULL,/* Power runloop source */
+ storeRLS = NULL;/* System Config runloop source */
+ CFStringRef key[6], /* System Config keys */
+ pattern[2]; /* System Config patterns */
+ CFArrayRef keys = NULL, /* System Config key array*/
+ patterns = NULL;/* System Config pattern array */
+ SCDynamicStoreContext storeContext; /* Dynamic store context */
+ CFRunLoopTimerContext timerContext; /* Timer context */
+ cupsd_thread_data_t threadData; /* Thread context data for the *
+ * runloop notifiers */
+
+
+ /*
+ * Register for power state change notifications
+ */
+
+ bzero(&threadData, sizeof(threadData));
+
+ threadData.sysevent.powerKernelPort =
+ IORegisterForSystemPower(&threadData, &powerNotifierPort,
+ sysEventPowerNotifier, &powerNotifierObj);
+
+ if (threadData.sysevent.powerKernelPort)
+ {
+ powerRLS = IONotificationPortGetRunLoopSource(powerNotifierPort);
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), powerRLS, kCFRunLoopDefaultMode);
+ }
+ else
+ DEBUG_puts("sysEventThreadEntry: error registering for system power "
+ "notifications");
+
+ /*
+ * Register for system configuration change notifications
+ */
+
+ bzero(&storeContext, sizeof(storeContext));
+ storeContext.info = &threadData;
+
+ store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"),
+ sysEventConfigurationNotifier, &storeContext);
+
+ if (!ComputerNameKey)
+ ComputerNameKey = SCDynamicStoreKeyCreateComputerName(kCFAllocatorDefault);
+
+ if (!BTMMKey)
+ BTMMKey = SCDynamicStoreKeyCreate(kCFAllocatorDefault,
+ CFSTR("Setup:/Network/BackToMyMac"));
+
+ if (!NetworkGlobalKeyIPv4)
+ NetworkGlobalKeyIPv4 =
+ SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault,
+ kSCDynamicStoreDomainState,
+ kSCEntNetIPv4);
+
+ if (!NetworkGlobalKeyIPv6)
+ NetworkGlobalKeyIPv6 =
+ SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault,
+ kSCDynamicStoreDomainState,
+ kSCEntNetIPv6);
+
+ if (!NetworkGlobalKeyDNS)
+ NetworkGlobalKeyDNS =
+ SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault,
+ kSCDynamicStoreDomainState,
+ kSCEntNetDNS);
+
+ if (!HostNamesKey)
+ HostNamesKey = SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault);
+
+ if (!NetworkInterfaceKeyIPv4)
+ NetworkInterfaceKeyIPv4 =
+ SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault,
+ kSCDynamicStoreDomainState,
+ kSCCompAnyRegex,
+ kSCEntNetIPv4);
+
+ if (!NetworkInterfaceKeyIPv6)
+ NetworkInterfaceKeyIPv6 =
+ SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault,
+ kSCDynamicStoreDomainState,
+ kSCCompAnyRegex,
+ kSCEntNetIPv6);
+
+ if (store && ComputerNameKey && HostNamesKey &&
+ NetworkGlobalKeyIPv4 && NetworkGlobalKeyIPv6 && NetworkGlobalKeyDNS &&
+ NetworkInterfaceKeyIPv4 && NetworkInterfaceKeyIPv6)
+ {
+ key[0] = ComputerNameKey;
+ key[1] = BTMMKey;
+ key[2] = NetworkGlobalKeyIPv4;
+ key[3] = NetworkGlobalKeyIPv6;
+ key[4] = NetworkGlobalKeyDNS;
+ key[5] = HostNamesKey;
+
+ pattern[0] = NetworkInterfaceKeyIPv4;
+ pattern[1] = NetworkInterfaceKeyIPv6;
+
+ keys = CFArrayCreate(kCFAllocatorDefault, (const void **)key,
+ sizeof(key) / sizeof(key[0]),
+ &kCFTypeArrayCallBacks);
+
+ patterns = CFArrayCreate(kCFAllocatorDefault, (const void **)pattern,
+ sizeof(pattern) / sizeof(pattern[0]),
+ &kCFTypeArrayCallBacks);
+
+ if (keys && patterns &&
+ SCDynamicStoreSetNotificationKeys(store, keys, patterns))
+ {
+ if ((storeRLS = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault,
+ store, 0)) != NULL)
+ {
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLS,
+ kCFRunLoopDefaultMode);
+ }
+ else
+ DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreateRunLoopSource "
+ "failed: %s\n", SCErrorString(SCError())));
+ }
+ else
+ DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreSetNotificationKeys "
+ "failed: %s\n", SCErrorString(SCError())));
+ }
+ else
+ DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreate failed: %s\n",
+ SCErrorString(SCError())));
+
+ if (keys)
+ CFRelease(keys);
+
+ if (patterns)
+ CFRelease(patterns);
+
+ /*
+ * Set up a timer to delay the wake change notifications.
+ *
+ * The initial time is set a decade or so into the future, we'll adjust
+ * this later.
+ */
+
+ bzero(&timerContext, sizeof(timerContext));
+ timerContext.info = &threadData;
+
+ threadData.timerRef =
+ CFRunLoopTimerCreate(kCFAllocatorDefault,
+ CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L),
+ 86400L * 365L * 10L, 0, 0, sysEventTimerNotifier,
+ &timerContext);
+ CFRunLoopAddTimer(CFRunLoopGetCurrent(), threadData.timerRef,
+ kCFRunLoopDefaultMode);
+
+ /*
+ * Store our runloop in a global so the main thread can use it to stop us.
+ */
+
+ pthread_mutex_lock(&SysEventThreadMutex);
+
+ SysEventRunloop = CFRunLoopGetCurrent();
+
+ pthread_cond_signal(&SysEventThreadCond);
+ pthread_mutex_unlock(&SysEventThreadMutex);
+
+ /*
+ * Disappear into the runloop until it's stopped by the main thread.
+ */
+
+ CFRunLoopRun();
+
+ /*
+ * Clean up before exiting.
+ */
+
+ if (threadData.timerRef)
+ {
+ CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), threadData.timerRef,
+ kCFRunLoopDefaultMode);
+ CFRelease(threadData.timerRef);
+ }
+
+ if (threadData.sysevent.powerKernelPort)
+ {
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerRLS,
+ kCFRunLoopDefaultMode);
+ IODeregisterForSystemPower(&powerNotifierObj);
+ IOServiceClose(threadData.sysevent.powerKernelPort);
+ IONotificationPortDestroy(powerNotifierPort);
+ }
+
+ if (storeRLS)
+ {
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), storeRLS,
+ kCFRunLoopDefaultMode);
+ CFRunLoopSourceInvalidate(storeRLS);
+ CFRelease(storeRLS);
+ }
+
+ if (store)
+ CFRelease(store);
+
+ pthread_exit(NULL);
+}
+
+
+/*
+ * 'sysEventPowerNotifier()' - Handle power notification events.
+ */
+
+static void
+sysEventPowerNotifier(
+ void *context, /* I - Thread context data */
+ io_service_t service, /* I - Unused service info */
+ natural_t messageType, /* I - Type of message */
+ void *messageArgument) /* I - Message data */
+{
+ int sendit = 1; /* Send event to main thread? *
+ * (0 = no, 1 = yes, 2 = delayed */
+ cupsd_thread_data_t *threadData; /* Thread context data */
+
+
+ threadData = (cupsd_thread_data_t *)context;
+
+ (void)service; /* anti-compiler-warning-code */
+
+ switch (messageType)
+ {
+ case kIOMessageCanSystemPowerOff:
+ case kIOMessageCanSystemSleep:
+ threadData->sysevent.event |= SYSEVENT_CANSLEEP;
+ break;
+
+ case kIOMessageSystemWillRestart:
+ case kIOMessageSystemWillPowerOff:
+ case kIOMessageSystemWillSleep:
+ threadData->sysevent.event |= SYSEVENT_WILLSLEEP;
+ break;
+
+ case kIOMessageSystemHasPoweredOn:
+ /*
+ * Because powered on is followed by a net-changed event, delay
+ * before sending it.
+ */
+
+ sendit = 2;
+ threadData->sysevent.event |= SYSEVENT_WOKE;
+ break;
+
+ case kIOMessageSystemWillNotPowerOff:
+ case kIOMessageSystemWillNotSleep:
+# ifdef kIOMessageSystemWillPowerOn
+ case kIOMessageSystemWillPowerOn:
+# endif /* kIOMessageSystemWillPowerOn */
+ default:
+ sendit = 0;
+ break;
+ }
+
+ if (sendit == 0)
+ IOAllowPowerChange(threadData->sysevent.powerKernelPort,
+ (long)messageArgument);
+ else
+ {
+ threadData->sysevent.powerNotificationID = (long)messageArgument;
+
+ if (sendit == 1)
+ {
+ /*
+ * Send the event to the main thread now.
+ */
+
+ write(SysEventPipes[1], &threadData->sysevent,
+ sizeof(threadData->sysevent));
+ threadData->sysevent.event = 0;
+ }
+ else
+ {
+ /*
+ * Send the event to the main thread after 1 to 2 seconds.
+ */
+
+ CFRunLoopTimerSetNextFireDate(threadData->timerRef,
+ CFAbsoluteTimeGetCurrent() + 2);
+ }
+ }
+}
+
+
+/*
+ * 'sysEventConfigurationNotifier()' - Network configuration change notification
+ * callback.
+ */
+
+static void
+sysEventConfigurationNotifier(
+ SCDynamicStoreRef store, /* I - System data (unused) */
+ CFArrayRef changedKeys, /* I - Changed data */
+ void *context) /* I - Thread context data */
+{
+ cupsd_thread_data_t *threadData; /* Thread context data */
+
+
+ threadData = (cupsd_thread_data_t *)context;
+
+ (void)store; /* anti-compiler-warning-code */
+
+ CFRange range = CFRangeMake(0, CFArrayGetCount(changedKeys));
+
+ if (CFArrayContainsValue(changedKeys, range, ComputerNameKey) ||
+ CFArrayContainsValue(changedKeys, range, BTMMKey))
+ threadData->sysevent.event |= SYSEVENT_NAMECHANGED;
+ else
+ {
+ threadData->sysevent.event |= SYSEVENT_NETCHANGED;
+
+ /*
+ * Indicate the network interface list needs updating...
+ */
+
+ NetIFUpdate = 1;
+ }
+
+ /*
+ * Because we registered for several different kinds of change notifications
+ * this callback usually gets called several times in a row. We use a timer to
+ * de-bounce these so we only end up generating one event for the main thread.
+ */
+
+ CFRunLoopTimerSetNextFireDate(threadData->timerRef,
+ CFAbsoluteTimeGetCurrent() + 5);
+}
+
+
+/*
+ * 'sysEventTimerNotifier()' - Handle delayed event notifications.
+ */
+
+static void
+sysEventTimerNotifier(
+ CFRunLoopTimerRef timer, /* I - Timer information */
+ void *context) /* I - Thread context data */
+{
+ cupsd_thread_data_t *threadData; /* Thread context data */
+
+
+ (void)timer;
+
+ threadData = (cupsd_thread_data_t *)context;
+
+ /*
+ * If an event is still pending send it to the main thread.
+ */
+
+ if (threadData->sysevent.event)
+ {
+ write(SysEventPipes[1], &threadData->sysevent,
+ sizeof(threadData->sysevent));
+ threadData->sysevent.event = 0;
+ }
+}
+
+
+/*
+ * 'sysUpdate()' - Update the current system state.
+ */
+
+static void
+sysUpdate(void)
+{
+ int i; /* Looping var */
+ cupsd_sysevent_t sysevent; /* The system event */
+ cupsd_printer_t *p; /* Printer information */
+
+
+ /*
+ * Drain the event pipe...
+ */
+
+ while (read((int)SysEventPipes[0], &sysevent, sizeof(sysevent))
+ == sizeof(sysevent))
+ {
+ if (sysevent.event & SYSEVENT_CANSLEEP)
+ {
+ /*
+ * If there are active printers that don't have the connecting-to-device
+ * printer-state-reason then cancel the sleep request (i.e. this reason
+ * indicates a job that is not yet connected to the printer)...
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ if (p->job)
+ {
+ for (i = 0; i < p->num_reasons; i ++)
+ if (!strcmp(p->reasons[i], "connecting-to-device"))
+ break;
+
+ if (!p->num_reasons || i >= p->num_reasons)
+ break;
+ }
+ }
+
+ if (p)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "System sleep canceled because printer %s is active",
+ p->name);
+ IOCancelPowerChange(sysevent.powerKernelPort,
+ sysevent.powerNotificationID);
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "System wants to sleep");
+ IOAllowPowerChange(sysevent.powerKernelPort,
+ sysevent.powerNotificationID);
+ }
+ }
+
+ if (sysevent.event & SYSEVENT_WILLSLEEP)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "System going to sleep");
+
+ Sleeping = 1;
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ if (p->type & CUPS_PRINTER_DISCOVERED)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Deleting remote destination \"%s\"", p->name);
+ cupsArraySave(Printers);
+ cupsdDeletePrinter(p, 0);
+ cupsArrayRestore(Printers);
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Deregistering local printer \"%s\"", p->name);
+ cupsdDeregisterPrinter(p, 0);
+ }
+ }
+
+ cupsdCleanDirty();
+
+#ifdef kIOPMAssertionTypeDenySystemSleep
+ /*
+ * Tell the OS it is OK to sleep when we remove our assertion...
+ */
+
+ IOAllowPowerChange(sysevent.powerKernelPort,
+ sysevent.powerNotificationID);
+
+#else
+ /*
+ * If we have no printing jobs, allow the power change immediately.
+ * Otherwise set the SleepJobs time to 15 seconds in the future when
+ * we'll take more drastic measures...
+ */
+
+ if (cupsArrayCount(PrintingJobs) == 0)
+ IOAllowPowerChange(sysevent.powerKernelPort,
+ sysevent.powerNotificationID);
+ else
+ {
+ /*
+ * If there are active printers that don't have the connecting-to-device
+ * printer-state-reason then delay the sleep request (i.e. this reason
+ * indicates a job that is not yet connected to the printer)...
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ if (p->job)
+ {
+ for (i = 0; i < p->num_reasons; i ++)
+ if (!strcmp(p->reasons[i], "connecting-to-device"))
+ break;
+
+ if (!p->num_reasons || i >= p->num_reasons)
+ break;
+ }
+ }
+
+ if (p)
+ {
+ LastSysEvent = sysevent;
+ SleepJobs = time(NULL) + 10;
+ }
+ else
+ {
+ IOAllowPowerChange(sysevent.powerKernelPort,
+ sysevent.powerNotificationID);
+ }
+ }
+#endif /* kIOPMAssertionTypeDenySystemSleep */
+ }
+
+ if (sysevent.event & SYSEVENT_WOKE)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "System woke from sleep");
+ IOAllowPowerChange(sysevent.powerKernelPort,
+ sysevent.powerNotificationID);
+ Sleeping = 0;
+ cupsdCheckJobs();
+ }
+
+ if (sysevent.event & SYSEVENT_NETCHANGED)
+ {
+ if (!Sleeping)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "System network configuration changed");
+
+ /*
+ * Resetting browse_time before calling cupsdSendBrowseList causes
+ * browse packets to be sent for local shared printers.
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ p->browse_time = 0;
+
+ cupsdSendBrowseList();
+ cupsdRestartPolling();
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "System network configuration changed; "
+ "ignored while sleeping");
+ }
+
+ if (sysevent.event & SYSEVENT_NAMECHANGED)
+ {
+ if (!Sleeping)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Computer name or BTMM domains changed");
+
+ /*
+ * De-register the individual printers...
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ cupsdDeregisterPrinter(p, 1);
+
+ /*
+ * Update the computer name and BTMM domain list...
+ */
+
+ cupsdUpdateDNSSDName();
+
+ /*
+ * Now re-register them...
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ p->browse_time = 0;
+ cupsdRegisterPrinter(p);
+ }
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Computer name or BTMM domains changed; ignored while "
+ "sleeping");
+ }
+ }
+}
+#endif /* __APPLE__ */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/sysman.h b/scheduler/sysman.h
new file mode 100644
index 000000000..e3f64aca0
--- /dev/null
+++ b/scheduler/sysman.h
@@ -0,0 +1,64 @@
+/*
+ * "$Id$"
+ *
+ * System management definitions for the CUPS scheduler.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/*
+ * Constants...
+ */
+
+#define CUPSD_DIRTY_NONE 0 /* Nothing is dirty */
+#define CUPSD_DIRTY_PRINTERS 1 /* printers.conf is dirty */
+#define CUPSD_DIRTY_CLASSES 2 /* classes.conf is dirty */
+#define CUPSD_DIRTY_REMOTE 4 /* remote.cache is dirty */
+#define CUPSD_DIRTY_PRINTCAP 8 /* printcap is dirty */
+#define CUPSD_DIRTY_JOBS 16 /* jobs.cache or "c" file(s) are dirty */
+#define CUPSD_DIRTY_SUBSCRIPTIONS 32 /* subscriptions.conf is dirty */
+
+/*
+ * Globals...
+ */
+
+VAR int DirtyFiles VALUE(CUPSD_DIRTY_NONE),
+ /* What files are dirty? */
+ DirtyCleanInterval VALUE(DEFAULT_KEEPALIVE);
+ /* How often do we write dirty files? */
+VAR time_t DirtyCleanTime VALUE(0);
+ /* When to clean dirty files next */
+VAR int Sleeping VALUE(0);
+ /* Non-zero if machine is entering or *
+ * in a sleep state... */
+VAR time_t SleepJobs VALUE(0);
+ /* Time when all jobs must be *
+ * canceled for system sleep. */
+#ifdef __APPLE__
+VAR int SysEventPipes[2] VALUE2(-1,-1);
+ /* System event notification pipes */
+#endif /* __APPLE__ */
+
+
+/*
+ * Prototypes...
+ */
+
+extern void cupsdAllowSleep(void);
+extern void cupsdCleanDirty(void);
+extern void cupsdMarkDirty(int what);
+extern void cupsdSetBusyState(void);
+extern void cupsdStartSystemMonitor(void);
+extern void cupsdStopSystemMonitor(void);
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/testdirsvc.c b/scheduler/testdirsvc.c
new file mode 100644
index 000000000..214cd0f8a
--- /dev/null
+++ b/scheduler/testdirsvc.c
@@ -0,0 +1,324 @@
+/*
+ * "$Id$"
+ *
+ * Browsing test program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Simulate one or more remote printers.
+ * usage() - Show program usage...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <cups/string-private.h>
+
+
+/*
+ * Local functions...
+ */
+
+static void usage(void);
+
+
+/*
+ * 'main()' - Simulate one or more remote printers.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i, /* Looping var */
+ printer, /* Current printer */
+ num_printers, /* Number of printers */
+ pclass, /* Current printer class */
+ num_pclasses, /* Number of printer classes */
+ server, /* Current server */
+ num_servers, /* Number of servers */
+ count, /* Number of printers sent this cycle */
+ interval, /* Browse Interval */
+ lease, /* Browse lease-duration */
+ continuous, /* Run continuously? */
+ port, /* Browse port */
+ sock, /* Browse socket */
+ val, /* Socket option value */
+ seconds, /* Seconds until next cycle */
+ verbose; /* Verbose output? */
+ const char *options; /* Options for URIs */
+ time_t curtime; /* Current UNIX time */
+ struct tm *curdate; /* Current date and time */
+ struct sockaddr_in addr; /* Broadcast address */
+ char packet[1540]; /* Data packet */
+ static const char * const names[26] = /* Printer names */
+ {
+ "alpha",
+ "bravo",
+ "charlie",
+ "delta",
+ "echo",
+ "foxtrot",
+ "golf",
+ "hotel",
+ "india",
+ "juliet",
+ "kilo",
+ "lima",
+ "mike",
+ "november",
+ "oscar",
+ "papa",
+ "quebec",
+ "romeo",
+ "sierra",
+ "tango",
+ "uniform",
+ "victor",
+ "wiskey",
+ "x-ray",
+ "yankee",
+ "zulu"
+ };
+
+
+ /*
+ * Process command-line arguments...
+ */
+
+ num_printers = 10;
+ num_pclasses = 5;
+ num_servers = 1;
+ interval = 30;
+ lease = 60;
+ port = 0;
+ verbose = 0;
+ continuous = 0;
+ options = NULL;
+
+ for (i = 1; i < argc; i ++)
+ {
+ if (!strcmp(argv[i], "-c"))
+ continuous = 1;
+ else if (!strcmp(argv[i], "-i"))
+ {
+ i ++;
+ if (i < argc)
+ interval = atoi(argv[i]);
+ else
+ usage();
+
+ continuous = 1;
+ }
+ else if (!strcmp(argv[i], "-l"))
+ {
+ i ++;
+ if (i < argc)
+ lease = atoi(argv[i]);
+ else
+ usage();
+ }
+ else if (!strcmp(argv[i], "-o"))
+ {
+ i ++;
+ if (i < argc)
+ options = argv[i];
+ else
+ usage();
+ }
+ else if (!strcmp(argv[i], "-C"))
+ {
+ i ++;
+ if (i < argc)
+ num_pclasses = atoi(argv[i]);
+ else
+ usage();
+ }
+ else if (!strcmp(argv[i], "-p"))
+ {
+ i ++;
+ if (i < argc)
+ num_printers = atoi(argv[i]);
+ else
+ usage();
+ }
+ else if (!strcmp(argv[i], "-s"))
+ {
+ i ++;
+ if (i < argc)
+ num_servers = atoi(argv[i]);
+ else
+ usage();
+ }
+ else if (!strcmp(argv[i], "-v"))
+ verbose = 1;
+ else if (isdigit(argv[i][0] & 255))
+ {
+ port = atoi(argv[i]);
+ }
+ else
+ usage();
+ }
+
+ if ((num_printers <= 0 && num_pclasses <= 0) || num_servers <= 0 ||
+ interval <= 0 || lease < 1 || port <= 0)
+ usage();
+
+ /*
+ * Open a broadcast socket...
+ */
+
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ perror("Unable to open broadcast socket");
+ return (1);
+ }
+
+ /*
+ * Set the "broadcast" flag...
+ */
+
+ val = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
+ {
+ perror("Unable to put socket in broadcast mode");
+
+ close(sock);
+ return (1);
+ }
+
+ /*
+ * Broadcast to 127.0.0.1 (localhost)
+ */
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_addr.s_addr = htonl(0x7f000001);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+
+ /*
+ * Send virtual printers continuously until we are stopped.
+ */
+
+ for (;;)
+ {
+ /*
+ * Start a new cycle of N printers...
+ */
+
+ printf("Sending %d printers from %d servers...\n", num_printers,
+ num_servers);
+
+ count = num_servers * (num_printers + num_pclasses) / interval + 1;
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+ seconds = interval;
+
+ for (i = 0, printer = 0; printer < num_printers; printer ++)
+ {
+ for (server = 0; server < num_servers; server ++, i ++)
+ {
+ if (i == count)
+ {
+ seconds --;
+ i = 0;
+ sleep(1);
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+ }
+
+ snprintf(packet, sizeof(packet),
+ "%x %x ipp://testserver-%d/printers/%s-%d \"Server Room %d\" "
+ "\"Test Printer %d\" \"Acme Blazer 2000\"%s%s "
+ "lease-duration=%d\n",
+ CUPS_PRINTER_REMOTE, IPP_PRINTER_IDLE, server + 1,
+ names[printer % 26], printer / 26 + 1, server + 1,
+ printer + 1, options ? " ipp-options=" : "",
+ options ? options : "", lease);
+
+ if (verbose)
+ printf("[%02d:%02d:%02d] %s", curdate->tm_hour, curdate->tm_min,
+ curdate->tm_sec, packet);
+
+ if (sendto(sock, packet, strlen(packet), 0,
+ (struct sockaddr *)&addr, sizeof(addr)) < 0)
+ perror("Unabled to send packet");
+ }
+ }
+
+
+ for (i = 0, pclass = 0; pclass < num_pclasses; pclass ++)
+ {
+ for (server = 0; server < num_servers; server ++, i ++)
+ {
+ if (i == count)
+ {
+ seconds --;
+ i = 0;
+ sleep(1);
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+ }
+
+ snprintf(packet, sizeof(packet),
+ "%x %x ipp://testserver-%d/classes/class-%s-%d \"Server Room %d\" "
+ "\"Test Class %d\" \"Acme Blazer 2000\"%s%s "
+ "lease-duration=%d\n",
+ CUPS_PRINTER_REMOTE | CUPS_PRINTER_CLASS, IPP_PRINTER_IDLE,
+ server + 1, names[pclass % 26], pclass / 26 + 1, server + 1,
+ pclass + 1, options ? " ipp-options=" : "",
+ options ? options : "", lease);
+
+ if (verbose)
+ printf("[%02d:%02d:%02d] %s", curdate->tm_hour, curdate->tm_min,
+ curdate->tm_sec, packet);
+
+ if (sendto(sock, packet, strlen(packet), 0,
+ (struct sockaddr *)&addr, sizeof(addr)) < 0)
+ perror("Unabled to send packet");
+ }
+ }
+
+ if (!continuous)
+ break;
+
+ /*
+ * Sleep for any remaining time...
+ */
+
+ if (seconds > 0)
+ sleep(seconds);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'usage()' - Show program usage...
+ */
+
+static void
+usage(void)
+{
+ puts("Usage: testdirsvc [-c] [-i interval] [-l lease-duration] "
+ "[-o ipp-options] [-p printers] "
+ "[-C classes] [-s servers] [-v] port");
+ exit(0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/testlpd.c b/scheduler/testlpd.c
new file mode 100644
index 000000000..818e4abc0
--- /dev/null
+++ b/scheduler/testlpd.c
@@ -0,0 +1,550 @@
+/*
+ * "$Id$"
+ *
+ * cups-lpd test program for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Simulate an LPD client.
+ * do_command() - Send the LPD command and wait for a response.
+ * print_job() - Submit a file for printing.
+ * print_waiting() - Print waiting jobs.
+ * remove_job() - Cancel a print job.
+ * status_long() - Show the long printer status.
+ * status_short() - Show the short printer status.
+ * usage() - Show program usage...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <cups/string-private.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+
+/*
+ * Local functions...
+ */
+
+static int do_command(int outfd, int infd, const char *command);
+static int print_job(int outfd, int infd, char *dest, char **args);
+static int print_waiting(int outfd, int infd, char *dest);
+static int remove_job(int outfd, int infd, char *dest, char **args);
+static int status_long(int outfd, int infd, char *dest, char **args);
+static int status_short(int outfd, int infd, char *dest, char **args);
+static void usage(void);
+
+
+/*
+ * 'main()' - Simulate an LPD client.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ int status; /* Test status */
+ char *op, /* Operation to test */
+ **opargs, /* Remaining arguments */
+ *dest; /* Destination */
+ int cupslpd_argc; /* Argument count for cups-lpd */
+ char *cupslpd_argv[1000]; /* Arguments for cups-lpd */
+ int cupslpd_stdin[2], /* Standard input for cups-lpd */
+ cupslpd_stdout[2], /* Standard output for cups-lpd */
+ cupslpd_pid, /* Process ID for cups-lpd */
+ cupslpd_status; /* Status of cups-lpd process */
+
+
+ /*
+ * Collect command-line arguments...
+ */
+
+ op = NULL;
+ opargs = NULL;
+ dest = NULL;
+ cupslpd_argc = 1;
+ cupslpd_argv[0] = (char *)"cups-lpd";
+
+ for (i = 1; i < argc; i ++)
+ if (!strncmp(argv[i], "-o", 2))
+ {
+ cupslpd_argv[cupslpd_argc++] = argv[i];
+
+ if (!argv[i][2])
+ {
+ i ++;
+
+ if (i >= argc)
+ usage();
+
+ cupslpd_argv[cupslpd_argc++] = argv[i];
+ }
+ }
+ else if (argv[i][0] == '-')
+ usage();
+ else if (!op)
+ op = argv[i];
+ else if (!dest)
+ dest = argv[i];
+ else
+ {
+ opargs = argv + i;
+ break;
+ }
+
+ if (!op ||
+ (!strcmp(op, "print-job") && (!dest || !opargs)) ||
+ (!strcmp(op, "remove-job") && (!dest || !opargs)) ||
+ (strcmp(op, "print-job") && strcmp(op, "print-waiting") &&
+ strcmp(op, "remove-job") && strcmp(op, "status-long") &&
+ strcmp(op, "status-short")))
+ {
+ printf("op=\"%s\", dest=\"%s\", opargs=%p\n", op, dest, opargs);
+ usage();
+ }
+
+ /*
+ * Run the cups-lpd program using pipes...
+ */
+
+ cupslpd_argv[cupslpd_argc] = NULL;
+
+ pipe(cupslpd_stdin);
+ pipe(cupslpd_stdout);
+
+ if ((cupslpd_pid = fork()) < 0)
+ {
+ /*
+ * Error!
+ */
+
+ perror("testlpd: Unable to fork");
+ return (1);
+ }
+ else if (cupslpd_pid == 0)
+ {
+ /*
+ * Child goes here...
+ */
+
+ dup2(cupslpd_stdin[0], 0);
+ close(cupslpd_stdin[0]);
+ close(cupslpd_stdin[1]);
+
+ dup2(cupslpd_stdout[1], 1);
+ close(cupslpd_stdout[0]);
+ close(cupslpd_stdout[1]);
+
+ execv("./cups-lpd", cupslpd_argv);
+
+ perror("testlpd: Unable to exec ./cups-lpd");
+ exit(errno);
+ }
+ else
+ {
+ close(cupslpd_stdin[0]);
+ close(cupslpd_stdout[1]);
+ }
+
+ /*
+ * Do the operation test...
+ */
+
+ if (!strcmp(op, "print-job"))
+ status = print_job(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs);
+ else if (!strcmp(op, "print-waiting"))
+ status = print_waiting(cupslpd_stdin[1], cupslpd_stdout[0], dest);
+ else if (!strcmp(op, "remove-job"))
+ status = remove_job(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs);
+ else if (!strcmp(op, "status-long"))
+ status = status_long(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs);
+ else if (!strcmp(op, "status-short"))
+ status = status_short(cupslpd_stdin[1], cupslpd_stdout[0], dest, opargs);
+ else
+ {
+ printf("Unknown operation \"%s\"!\n", op);
+ status = 1;
+ }
+
+ /*
+ * Kill the test program...
+ */
+
+ close(cupslpd_stdin[1]);
+ close(cupslpd_stdout[0]);
+
+ while (wait(&cupslpd_status) != cupslpd_pid);
+
+ printf("cups-lpd exit status was %d...\n", cupslpd_status);
+
+ /*
+ * Return the test status...
+ */
+
+ return (status);
+}
+
+
+/*
+ * 'do_command()' - Send the LPD command and wait for a response.
+ */
+
+static int /* O - Status from cups-lpd */
+do_command(int outfd, /* I - Command file descriptor */
+ int infd, /* I - Response file descriptor */
+ const char *command) /* I - Command line to send */
+{
+ int len; /* Length of command line */
+ char status; /* Status byte */
+
+
+ printf("COMMAND: %02X %s", command[0], command + 1);
+
+ len = strlen(command);
+
+ if (write(outfd, command, len) < len)
+ {
+ puts(" Write failed!");
+ return (-1);
+ }
+
+ if (read(infd, &status, 1) < 1)
+ puts("STATUS: ERROR");
+ else
+ printf("STATUS: %d\n", status);
+
+ return (status);
+}
+
+
+/*
+ * 'print_job()' - Submit a file for printing.
+ */
+
+static int /* O - Status from cups-lpd */
+print_job(int outfd, /* I - Command file descriptor */
+ int infd, /* I - Response file descriptor */
+ char *dest, /* I - Destination */
+ char **args) /* I - Arguments */
+{
+ int fd; /* Print file descriptor */
+ char command[1024], /* Command buffer */
+ control[1024], /* Control file */
+ buffer[8192]; /* Print buffer */
+ int status; /* Status of command */
+ struct stat fileinfo; /* File information */
+ char *jobname; /* Job name */
+ int sequence; /* Sequence number */
+ int bytes; /* Bytes read/written */
+
+
+ /*
+ * Check the print file...
+ */
+
+ if (stat(args[0], &fileinfo))
+ {
+ perror(args[0]);
+ return (-1);
+ }
+
+ if ((fd = open(args[0], O_RDONLY)) < 0)
+ {
+ perror(args[0]);
+ return (-1);
+ }
+
+ /*
+ * Send the "receive print job" command...
+ */
+
+ snprintf(command, sizeof(command), "\002%s\n", dest);
+ if ((status = do_command(outfd, infd, command)) != 0)
+ {
+ close(fd);
+ return (status);
+ }
+
+ /*
+ * Format a control file string that will be used to submit the job...
+ */
+
+ if ((jobname = strrchr(args[0], '/')) != NULL)
+ jobname ++;
+ else
+ jobname = args[0];
+
+ sequence = (int)getpid() % 1000;
+
+ snprintf(control, sizeof(control),
+ "Hlocalhost\n"
+ "P%s\n"
+ "J%s\n"
+ "ldfA%03dlocalhost\n"
+ "UdfA%03dlocalhost\n"
+ "N%s\n",
+ cupsUser(), jobname, sequence, sequence, jobname);
+
+ /*
+ * Send the control file...
+ */
+
+ bytes = strlen(control);
+
+ snprintf(command, sizeof(command), "\002%d cfA%03dlocalhost\n",
+ bytes, sequence);
+
+ if ((status = do_command(outfd, infd, command)) != 0)
+ {
+ close(fd);
+ return (status);
+ }
+
+ bytes ++;
+
+ if (write(outfd, control, bytes) < bytes)
+ {
+ printf("CONTROL: Unable to write %d bytes!\n", bytes);
+ close(fd);
+ return (-1);
+ }
+
+ printf("CONTROL: Wrote %d bytes.\n", bytes);
+
+ if (read(infd, command, 1) < 1)
+ {
+ puts("STATUS: ERROR");
+ close(fd);
+ return (-1);
+ }
+ else
+ {
+ status = command[0];
+
+ printf("STATUS: %d\n", status);
+ }
+
+ /*
+ * Send the data file...
+ */
+
+ snprintf(command, sizeof(command), "\003%d dfA%03dlocalhost\n",
+ (int)fileinfo.st_size, sequence);
+
+ if ((status = do_command(outfd, infd, command)) != 0)
+ {
+ close(fd);
+ return (status);
+ }
+
+ while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
+ {
+ if (write(outfd, buffer, bytes) < bytes)
+ {
+ printf("DATA: Unable to write %d bytes!\n", bytes);
+ close(fd);
+ return (-1);
+ }
+ }
+
+ write(outfd, "", 1);
+
+ close(fd);
+
+ printf("DATA: Wrote %d bytes.\n", (int)fileinfo.st_size);
+
+ if (read(infd, command, 1) < 1)
+ {
+ puts("STATUS: ERROR");
+ close(fd);
+ return (-1);
+ }
+ else
+ {
+ status = command[0];
+
+ printf("STATUS: %d\n", status);
+ }
+
+ return (status);
+}
+
+
+/*
+ * 'print_waiting()' - Print waiting jobs.
+ */
+
+static int /* O - Status from cups-lpd */
+print_waiting(int outfd, /* I - Command file descriptor */
+ int infd, /* I - Response file descriptor */
+ char *dest) /* I - Destination */
+{
+ char command[1024]; /* Command buffer */
+
+
+ /*
+ * Send the "print waiting jobs" command...
+ */
+
+ snprintf(command, sizeof(command), "\001%s\n", dest);
+
+ return (do_command(outfd, infd, command));
+}
+
+
+/*
+ * 'remove_job()' - Cancel a print job.
+ */
+
+static int /* O - Status from cups-lpd */
+remove_job(int outfd, /* I - Command file descriptor */
+ int infd, /* I - Response file descriptor */
+ char *dest, /* I - Destination */
+ char **args) /* I - Arguments */
+{
+ int i; /* Looping var */
+ char command[1024]; /* Command buffer */
+
+ /*
+ * Send the "remove jobs" command...
+ */
+
+ snprintf(command, sizeof(command), "\005%s", dest);
+
+ for (i = 0; args[i]; i ++)
+ {
+ strlcat(command, " ", sizeof(command));
+ strlcat(command, args[i], sizeof(command));
+ }
+
+ strlcat(command, "\n", sizeof(command));
+
+ return (do_command(outfd, infd, command));
+}
+
+
+/*
+ * 'status_long()' - Show the long printer status.
+ */
+
+static int /* O - Status from cups-lpd */
+status_long(int outfd, /* I - Command file descriptor */
+ int infd, /* I - Response file descriptor */
+ char *dest, /* I - Destination */
+ char **args) /* I - Arguments */
+{
+ char command[1024], /* Command buffer */
+ buffer[8192]; /* Status buffer */
+ int bytes; /* Bytes read/written */
+
+
+ /*
+ * Send the "send short status" command...
+ */
+
+ if (args)
+ snprintf(command, sizeof(command), "\004%s %s\n", dest, args[0]);
+ else
+ snprintf(command, sizeof(command), "\004%s\n", dest);
+
+ bytes = strlen(command);
+
+ if (write(outfd, command, bytes) < bytes)
+ return (-1);
+
+ /*
+ * Read the status back...
+ */
+
+ while ((bytes = read(infd, buffer, sizeof(buffer))) > 0)
+ {
+ fwrite(buffer, 1, bytes, stdout);
+ fflush(stdout);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'status_short()' - Show the short printer status.
+ */
+
+static int /* O - Status from cups-lpd */
+status_short(int outfd, /* I - Command file descriptor */
+ int infd, /* I - Response file descriptor */
+ char *dest, /* I - Destination */
+ char **args) /* I - Arguments */
+{
+ char command[1024], /* Command buffer */
+ buffer[8192]; /* Status buffer */
+ int bytes; /* Bytes read/written */
+
+
+ /*
+ * Send the "send short status" command...
+ */
+
+ if (args)
+ snprintf(command, sizeof(command), "\003%s %s\n", dest, args[0]);
+ else
+ snprintf(command, sizeof(command), "\003%s\n", dest);
+
+ bytes = strlen(command);
+
+ if (write(outfd, command, bytes) < bytes)
+ return (-1);
+
+ /*
+ * Read the status back...
+ */
+
+ while ((bytes = read(infd, buffer, sizeof(buffer))) > 0)
+ {
+ fwrite(buffer, 1, bytes, stdout);
+ fflush(stdout);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'usage()' - Show program usage...
+ */
+
+static void
+usage(void)
+{
+ puts("Usage: testlpd [options] print-job printer filename [... filename]");
+ puts(" testlpd [options] print-waiting [printer or user]");
+ puts(" testlpd [options] remove-job printer [user [job-id]]");
+ puts(" testlpd [options] status-long [printer or user]");
+ puts(" testlpd [options] status-short [printer or user]");
+ puts("");
+ puts("Options:");
+ puts(" -o name=value");
+
+ exit(0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/testmime.c b/scheduler/testmime.c
new file mode 100644
index 000000000..fb21ffffa
--- /dev/null
+++ b/scheduler/testmime.c
@@ -0,0 +1,531 @@
+/*
+ * "$Id$"
+ *
+ * MIME test program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Main entry for the test program.
+ * add_ppd_filter() - Add a printer filter from a PPD.
+ * add_ppd_filters() - Add all filters from a PPD.
+ * print_rules() - Print the rules for a file type...
+ * type_dir() - Show the MIME types for a given directory.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/string-private.h>
+#include <cups/dir.h>
+#include <cups/debug-private.h>
+#include <cups/ppd-private.h>
+#include "mime.h"
+
+
+/*
+ * Local functions...
+ */
+
+static void add_ppd_filter(mime_t *mime, mime_type_t *filtertype,
+ const char *filter);
+static void add_ppd_filters(mime_t *mime, ppd_file_t *ppd);
+static void print_rules(mime_magic_t *rules);
+static void type_dir(mime_t *mime, const char *dirname);
+
+
+/*
+ * 'main()' - Main entry for the test program.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping vars */
+ const char *filter_path; /* Filter path */
+ char super[MIME_MAX_SUPER], /* Super-type name */
+ type[MIME_MAX_TYPE]; /* Type name */
+ int compression; /* Compression of file */
+ int cost; /* Cost of filters */
+ mime_t *mime; /* MIME database */
+ mime_type_t *src, /* Source type */
+ *dst; /* Destination type */
+ struct stat srcinfo; /* Source information */
+ ppd_file_t *ppd; /* PPD file */
+ cups_array_t *filters; /* Filters for the file */
+ mime_filter_t *filter; /* Current filter */
+
+
+ mime = NULL;
+ src = NULL;
+ dst = NULL;
+ ppd = NULL;
+ filter_path = "../filter:" CUPS_SERVERBIN "/filter";
+
+ srcinfo.st_size = 0;
+
+ for (i = 1; i < argc; i ++)
+ if (!strcmp(argv[i], "-d"))
+ {
+ i ++;
+
+ if (i < argc)
+ {
+ mime = mimeLoad(argv[i], filter_path);
+
+ if (ppd)
+ add_ppd_filters(mime, ppd);
+ }
+ }
+ else if (!strcmp(argv[i], "-f"))
+ {
+ i ++;
+
+ if (i < argc)
+ filter_path = argv[i];
+ }
+ else if (!strcmp(argv[i], "-p"))
+ {
+ i ++;
+
+ if (i < argc)
+ {
+ ppd = ppdOpenFile(argv[i]);
+
+ if (mime)
+ add_ppd_filters(mime, ppd);
+ }
+ }
+ else if (!src)
+ {
+ if (!mime)
+ mime = mimeLoad("../conf", filter_path);
+
+ if (ppd)
+ add_ppd_filters(mime, ppd);
+
+ src = mimeFileType(mime, argv[i], NULL, &compression);
+ stat(argv[i], &srcinfo);
+
+ if (src)
+ printf("%s: %s/%s%s\n", argv[i], src->super, src->type,
+ compression ? " (gzipped)" : "");
+ else if ((src = mimeType(mime, "application", "octet-stream")) != NULL)
+ printf("%s: application/octet-stream\n", argv[i]);
+ else
+ {
+ printf("%s: unknown\n", argv[i]);
+ if (mime)
+ mimeDelete(mime);
+ return (1);
+ }
+ }
+ else
+ {
+ sscanf(argv[i], "%15[^/]/%31s", super, type);
+ dst = mimeType(mime, super, type);
+
+ filters = mimeFilter2(mime, src, srcinfo.st_size, dst, &cost);
+
+ if (!filters)
+ {
+ printf("No filters to convert from %s/%s to %s.\n", src->super,
+ src->type, argv[i]);
+ }
+ else
+ {
+ int first = 1; /* First filter shown? */
+
+ printf("Filter cost = %d\n", cost);
+
+ for (filter = (mime_filter_t *)cupsArrayFirst(filters);
+ filter;
+ filter = (mime_filter_t *)cupsArrayNext(filters))
+ {
+ if (!strcmp(filter->filter, "-"))
+ continue;
+
+ if (first)
+ {
+ first = 0;
+ fputs(filter->filter, stdout);
+ }
+ else
+ printf(" | %s", filter->filter);
+ }
+
+ putchar('\n');
+
+ cupsArrayDelete(filters);
+ }
+ }
+
+ if (!mime)
+ {
+ mime = mimeLoad("../conf", filter_path);
+ if (ppd)
+ add_ppd_filters(mime, ppd);
+ }
+
+ if (!src)
+ {
+ puts("MIME database types:");
+ for (src = mimeFirstType(mime); src; src = mimeNextType(mime))
+ {
+ printf("\t%s/%s (%d):\n", src->super, src->type, src->priority);
+ print_rules(src->rules);
+ puts("");
+ }
+
+ puts("");
+
+ puts("MIME database filters:");
+ for (filter = mimeFirstFilter(mime); filter; filter = mimeNextFilter(mime))
+ printf("\t%s/%s to %s/%s: %s (%d)\n",
+ filter->src->super, filter->src->type,
+ filter->dst->super, filter->dst->type,
+ filter->filter, filter->cost);
+
+ type_dir(mime, "../doc");
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'add_printer_filter()' - Add a printer filter from a PPD.
+ */
+
+static void
+add_ppd_filter(mime_t *mime, /* I - MIME database */
+ mime_type_t *filtertype, /* I - Filter or prefilter MIME type */
+ const char *filter) /* I - Filter to add */
+{
+ char super[MIME_MAX_SUPER], /* Super-type for filter */
+ type[MIME_MAX_TYPE], /* Type for filter */
+ dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */
+ dtype[MIME_MAX_TYPE], /* Destination type for filter */
+ dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2],
+ /* Destination super/type */
+ program[1024]; /* Program/filter name */
+ int cost; /* Cost of filter */
+ size_t maxsize = 0; /* Maximum supported file size */
+ mime_type_t *temptype, /* MIME type looping var */
+ *desttype; /* Destination MIME type */
+ mime_filter_t *filterptr; /* MIME filter */
+
+
+ DEBUG_printf(("add_ppd_filter(mime=%p, filtertype=%p(%s/%s), filter=\"%s\")",
+ mime, filtertype, filtertype->super, filtertype->type, filter));
+
+ /*
+ * Parse the filter string; it should be in one of the following formats:
+ *
+ * source/type cost program
+ * source/type cost maxsize(nnnn) program
+ * source/type dest/type cost program
+ * source/type dest/type cost maxsize(nnnn) program
+ */
+
+ if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
+ super, type, dsuper, dtype, &cost, program) == 6)
+ {
+ snprintf(dest, sizeof(dest), "test/%s/%s", dsuper, dtype);
+
+ if ((desttype = mimeType(mime, "printer", dest)) == NULL)
+ desttype = mimeAddType(mime, "printer", dest);
+ }
+ else
+ {
+ if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost,
+ program) == 4)
+ {
+ desttype = filtertype;
+ }
+ else
+ {
+ printf("testmime: Invalid filter string \"%s\".\n", filter);
+ return;
+ }
+ }
+
+ if (!strncmp(program, "maxsize(", 8))
+ {
+ char *ptr; /* Pointer into maxsize(nnnn) program */
+
+ maxsize = strtoll(program + 8, &ptr, 10);
+
+ if (*ptr != ')')
+ {
+ printf("testmime: Invalid filter string \"%s\".\n", filter);
+ return;
+ }
+
+ ptr ++;
+ while (_cups_isspace(*ptr))
+ ptr ++;
+
+ _cups_strcpy(program, ptr);
+ }
+
+ /*
+ * Add the filter to the MIME database, supporting wildcards as needed...
+ */
+
+ for (temptype = mimeFirstType(mime);
+ temptype;
+ temptype = mimeNextType(mime))
+ if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) ||
+ !_cups_strcasecmp(temptype->super, super)) &&
+ (type[0] == '*' || !_cups_strcasecmp(temptype->type, type)))
+ {
+ if (desttype != filtertype)
+ {
+ DEBUG_printf(("add_ppd_filter: Adding filter %s/%s %s/%s %d %s",
+ temptype->super, temptype->type, desttype->super,
+ desttype->type, cost, program));
+ filterptr = mimeAddFilter(mime, temptype, desttype, cost, program);
+
+ if (!mimeFilterLookup(mime, desttype, filtertype))
+ {
+ DEBUG_printf(("add_printer_filter: Adding filter %s/%s %s/%s 0 -",
+ desttype->super, desttype->type, filtertype->super,
+ filtertype->type));
+ mimeAddFilter(mime, desttype, filtertype, cost, "-");
+ }
+ }
+ else
+ {
+ DEBUG_printf(("add_printer_filter: Adding filter %s/%s %s/%s %d %s",
+ temptype->super, temptype->type, filtertype->super,
+ filtertype->type, cost, program));
+ filterptr = mimeAddFilter(mime, temptype, filtertype, cost, program);
+ }
+
+ if (filterptr)
+ filterptr->maxsize = maxsize;
+ }
+}
+
+
+/*
+ * 'add_ppd_filters()' - Add all filters from a PPD.
+ */
+
+static void
+add_ppd_filters(mime_t *mime, /* I - MIME database */
+ ppd_file_t *ppd) /* I - PPD file */
+{
+ _ppd_cache_t *pc; /* Cache data for PPD */
+ const char *value; /* Filter definition value */
+ mime_type_t *filter, /* Filter type */
+ *prefilter; /* Pre-filter type */
+
+
+ pc = _ppdCacheCreateWithPPD(ppd);
+ if (!pc)
+ return;
+
+ filter = mimeAddType(mime, "printer", "test");
+
+ if (pc->filters)
+ {
+ for (value = (const char *)cupsArrayFirst(pc->filters);
+ value;
+ value = (const char *)cupsArrayNext(pc->filters))
+ add_ppd_filter(mime, filter, value);
+ }
+ else
+ {
+ add_ppd_filter(mime, filter, "application/vnd.cups-raw 0 -");
+ add_ppd_filter(mime, filter, "application/vnd.cups-postscript 0 -");
+ }
+
+ if (pc->prefilters)
+ {
+ prefilter = mimeAddType(mime, "prefilter", "test");
+
+ for (value = (const char *)cupsArrayFirst(pc->prefilters);
+ value;
+ value = (const char *)cupsArrayNext(pc->prefilters))
+ add_ppd_filter(mime, prefilter, value);
+ }
+}
+
+
+/*
+ * 'print_rules()' - Print the rules for a file type...
+ */
+
+static void
+print_rules(mime_magic_t *rules) /* I - Rules to print */
+{
+ int i; /* Looping var */
+ static char indent[255] = "\t"; /* Indentation for rules */
+
+
+ if (rules == NULL)
+ return;
+
+ while (rules != NULL)
+ {
+ printf("%s[%p] ", indent, rules);
+
+ if (rules->invert)
+ printf("NOT ");
+
+ switch (rules->op)
+ {
+ case MIME_MAGIC_MATCH :
+ printf("match(%s)", rules->value.matchv);
+ break;
+ case MIME_MAGIC_LOCALE :
+ printf("locale(%s)", rules->value.localev);
+ break;
+ case MIME_MAGIC_ASCII :
+ printf("ascii(%d,%d)", rules->offset, rules->length);
+ break;
+ case MIME_MAGIC_PRINTABLE :
+ printf("printable(%d,%d)", rules->offset, rules->length);
+ break;
+ case MIME_MAGIC_STRING :
+ printf("string(%d,", rules->offset);
+ for (i = 0; i < rules->length; i ++)
+ if (rules->value.stringv[i] < ' ' ||
+ rules->value.stringv[i] > 126)
+ printf("<%02X>", rules->value.stringv[i]);
+ else
+ putchar(rules->value.stringv[i]);
+ putchar(')');
+ break;
+ case MIME_MAGIC_CHAR :
+ printf("char(%d,%d)", rules->offset, rules->value.charv);
+ break;
+ case MIME_MAGIC_SHORT :
+ printf("short(%d,%d)", rules->offset, rules->value.shortv);
+ break;
+ case MIME_MAGIC_INT :
+ printf("int(%d,%d)", rules->offset, rules->value.intv);
+ break;
+ case MIME_MAGIC_CONTAINS :
+ printf("contains(%d,%d,", rules->offset, rules->region);
+ for (i = 0; i < rules->length; i ++)
+ if (rules->value.stringv[i] < ' ' ||
+ rules->value.stringv[i] > 126)
+ printf("<%02X>", rules->value.stringv[i]);
+ else
+ putchar(rules->value.stringv[i]);
+ putchar(')');
+ break;
+ default :
+ break;
+ }
+
+ if (rules->child != NULL)
+ {
+ if (rules->op == MIME_MAGIC_OR)
+ puts("OR (");
+ else
+ puts("AND (");
+
+ strcat(indent, "\t");
+ print_rules(rules->child);
+ indent[strlen(indent) - 1] = '\0';
+ printf("%s)\n", indent);
+ }
+ else
+ putchar('\n');
+
+ rules = rules->next;
+ }
+}
+
+
+/*
+ * 'type_dir()' - Show the MIME types for a given directory.
+ */
+
+static void
+type_dir(mime_t *mime, /* I - MIME database */
+ const char *dirname) /* I - Directory */
+{
+ cups_dir_t *dir; /* Directory */
+ cups_dentry_t *dent; /* Directory entry */
+ char filename[1024]; /* File to type */
+ mime_type_t *filetype; /* File type */
+ int compression; /* Compressed file? */
+ mime_type_t *pstype; /* application/vnd.cups-postscript */
+ cups_array_t *filters; /* Filters to pstype */
+ mime_filter_t *filter; /* Current filter */
+ int cost; /* Filter cost */
+
+
+ dir = cupsDirOpen(dirname);
+ if (!dir)
+ return;
+
+ pstype = mimeType(mime, "application", "vnd.cups-postscript");
+
+ while ((dent = cupsDirRead(dir)) != NULL)
+ {
+ if (dent->filename[0] == '.')
+ continue;
+
+ snprintf(filename, sizeof(filename), "%s/%s", dirname, dent->filename);
+
+ if (S_ISDIR(dent->fileinfo.st_mode))
+ type_dir(mime, filename);
+
+ if (!S_ISREG(dent->fileinfo.st_mode))
+ continue;
+
+ filetype = mimeFileType(mime, filename, NULL, &compression);
+
+ if (filetype)
+ {
+ printf("%s: %s/%s%s\n", filename, filetype->super, filetype->type,
+ compression ? " (compressed)" : "");
+
+ filters = mimeFilter(mime, filetype, pstype, &cost);
+
+ if (!filters)
+ puts(" No filters to convert application/vnd.cups-postscript.");
+ else
+ {
+ printf(" Filter cost = %d\n", cost);
+
+ filter = (mime_filter_t *)cupsArrayFirst(filters);
+ printf(" %s", filter->filter);
+
+ for (filter = (mime_filter_t *)cupsArrayNext(filters);
+ filter;
+ filter = (mime_filter_t *)cupsArrayNext(filters))
+ printf(" | %s", filter->filter);
+
+ putchar('\n');
+
+ cupsArrayDelete(filters);
+ }
+ }
+ else
+ printf("%s: unknown%s\n", filename, compression ? " (compressed)" : "");
+ }
+
+ cupsDirClose(dir);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/testspeed.c b/scheduler/testspeed.c
new file mode 100644
index 000000000..7acc80519
--- /dev/null
+++ b/scheduler/testspeed.c
@@ -0,0 +1,365 @@
+/*
+ * "$Id$"
+ *
+ * Scheduler speed test for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Send multiple IPP requests and report on the average response
+ * time.
+ * do_test() - Run a test on a specific host...
+ * usage() - Show program usage...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/string-private.h>
+#include <cups/cups.h>
+#include <cups/language.h>
+#include <cups/debug-private.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+
+/*
+ * Local functions...
+ */
+
+static int do_test(const char *server, int port,
+ http_encryption_t encryption, int requests,
+ int verbose);
+static void usage(void);
+
+
+/*
+ * 'main()' - Send multiple IPP requests and report on the average response
+ * time.
+ */
+
+int
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ char *server, /* Server to use */
+ *ptr; /* Pointer to port in server */
+ int port; /* Port to use */
+ http_encryption_t encryption; /* Encryption to use */
+ int requests; /* Number of requests to send */
+ int children; /* Number of children to fork */
+ int good_children; /* Number of children that exited normally */
+ int pid; /* Child PID */
+ int status; /* Child status */
+ time_t start, /* Start time */
+ end; /* End time */
+ double elapsed; /* Elapsed time */
+ int verbose; /* Verbosity */
+
+
+ /*
+ * Parse command-line options...
+ */
+
+ requests = 100;
+ children = 5;
+ server = (char *)cupsServer();
+ port = ippPort();
+ encryption = HTTP_ENCRYPT_IF_REQUESTED;
+ verbose = 0;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ {
+ for (ptr = argv[i] + 1; *ptr; ptr ++)
+ switch (*ptr)
+ {
+ case 'c' : /* Number of children */
+ i ++;
+ if (i >= argc)
+ usage();
+
+ children = atoi(argv[i]);
+ break;
+
+ case 'r' : /* Number of requests */
+ i ++;
+ if (i >= argc)
+ usage();
+
+ requests = atoi(argv[i]);
+ break;
+
+ case 'E' : /* Enable encryption */
+ encryption = HTTP_ENCRYPT_REQUIRED;
+ break;
+
+ case 'v' : /* Verbose logging */
+ verbose ++;
+ break;
+
+ default :
+ usage();
+ break;
+ }
+ }
+ else
+ {
+ server = argv[i];
+
+ if (server[0] != '/' && (ptr = strrchr(server, ':')) != NULL)
+ {
+ *ptr++ = '\0';
+ port = atoi(ptr);
+ }
+ }
+
+ /*
+ * Then create child processes to act as clients...
+ */
+
+ if (children > 0)
+ {
+ printf("testspeed: Simulating %d clients with %d requests to %s with "
+ "%sencryption...\n", children, requests, server,
+ encryption == HTTP_ENCRYPT_IF_REQUESTED ? "no " : "");
+ }
+
+ start = time(NULL);
+
+ if (children < 1)
+ return (do_test(server, port, encryption, requests, verbose));
+ else if (children == 1)
+ good_children = do_test(server, port, encryption, requests, verbose) ? 0 : 1;
+ else
+ {
+ char options[255], /* Command-line options for child */
+ reqstr[255], /* Requests string for child */
+ serverstr[255]; /* Server:port string for child */
+
+
+ snprintf(reqstr, sizeof(reqstr), "%d", requests);
+
+ if (port == 631 || server[0] == '/')
+ strlcpy(serverstr, server, sizeof(serverstr));
+ else
+ snprintf(serverstr, sizeof(serverstr), "%s:%d", server, port);
+
+ strlcpy(options, "-cr", sizeof(options));
+
+ if (encryption == HTTP_ENCRYPT_REQUIRED)
+ strlcat(options, "E", sizeof(options));
+
+ if (verbose)
+ strlcat(options, "v", sizeof(options));
+
+ for (i = 0; i < children; i ++)
+ {
+ fflush(stdout);
+
+ if ((pid = fork()) == 0)
+ {
+ /*
+ * Child goes here...
+ */
+
+ execlp(argv[0], argv[0], options, "0", reqstr, serverstr, (char *)NULL);
+ exit(errno);
+ }
+ else if (pid < 0)
+ {
+ printf("testspeed: Fork failed: %s\n", strerror(errno));
+ break;
+ }
+ else
+ printf("testspeed: Started child %d...\n", pid);
+ }
+
+ /*
+ * Wait for children to finish...
+ */
+
+ puts("testspeed: Waiting for children to finish...");
+
+ for (good_children = 0;;)
+ {
+ pid = wait(&status);
+
+ if (pid < 0 && errno != EINTR)
+ break;
+
+ printf("testspeed: Ended child %d (%d)...\n", pid, status / 256);
+
+ if (!status)
+ good_children ++;
+ }
+ }
+
+ /*
+ * Compute the total run time...
+ */
+
+ if (good_children > 0)
+ {
+ end = time(NULL);
+ elapsed = end - start;
+ i = good_children * requests;
+
+ printf("testspeed: %dx%d=%d requests in %.1fs (%.3fs/r, %.1fr/s)\n",
+ good_children, requests, i, elapsed, elapsed / i, i / elapsed);
+ }
+
+ /*
+ * Exit with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'do_test()' - Run a test on a specific host...
+ */
+
+static int /* O - Exit status */
+do_test(const char *server, /* I - Server to use */
+ int port, /* I - Port number to use */
+ http_encryption_t encryption, /* I - Encryption to use */
+ int requests, /* I - Number of requests to send */
+ int verbose) /* I - Verbose output? */
+{
+ int i; /* Looping var */
+ http_t *http; /* Connection to server */
+ ipp_t *request; /* IPP Request */
+ struct timeval start, /* Start time */
+ end; /* End time */
+ double reqtime, /* Time for this request */
+ elapsed; /* Elapsed time */
+ int op; /* Current operation */
+ static ipp_op_t ops[4] = /* Operations to test... */
+ {
+ IPP_PRINT_JOB,
+ CUPS_GET_PRINTERS,
+ CUPS_GET_CLASSES,
+ IPP_GET_JOBS
+ };
+
+
+ /*
+ * Connect to the server...
+ */
+
+ if ((http = httpConnectEncrypt(server, port, encryption)) == NULL)
+ {
+ printf("testspeed(%d): unable to connect to server - %s\n", (int)getpid(),
+ strerror(errno));
+ return (1);
+ }
+
+ /*
+ * Do multiple requests...
+ */
+
+ for (elapsed = 0.0, i = 0; i < requests; i ++)
+ {
+ /*
+ * Build a request which requires the following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ *
+ * In addition, IPP_GET_JOBS needs a printer-uri attribute.
+ */
+
+ op = ops[i & 3];
+ request = ippNewRequest(op);
+
+ gettimeofday(&start, NULL);
+
+ if (verbose)
+ printf("testspeed(%d): %.6f %s ", (int)getpid(), elapsed,
+ ippOpString(op));
+
+ switch (op)
+ {
+ case IPP_GET_JOBS :
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, "ipp://localhost/printers/");
+
+ default :
+ ippDelete(cupsDoRequest(http, request, "/"));
+ break;
+
+ case IPP_PRINT_JOB :
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, "ipp://localhost/printers/test");
+ ippDelete(cupsDoFileRequest(http, request, "/printers/test",
+ "../data/testprint.ps"));
+ break;
+ }
+
+ gettimeofday(&end, NULL);
+
+ reqtime = (end.tv_sec - start.tv_sec) +
+ 0.000001 * (end.tv_usec - start.tv_usec);
+ elapsed += reqtime;
+
+ switch (cupsLastError())
+ {
+ case IPP_OK :
+ case IPP_NOT_FOUND :
+ if (verbose)
+ {
+ printf("succeeded: %s (%.6f)\n", cupsLastErrorString(), reqtime);
+ fflush(stdout);
+ }
+ break;
+
+ default :
+ if (!verbose)
+ printf("testspeed(%d): %s ", (int)getpid(),
+ ippOpString(ops[i & 3]));
+
+ printf("failed: %s\n", cupsLastErrorString());
+ httpClose(http);
+ return (1);
+ }
+ }
+
+ httpClose(http);
+
+ printf("testspeed(%d): %d requests in %.1fs (%.3fs/r, %.1fr/s)\n",
+ (int)getpid(), i, elapsed, elapsed / i, i / elapsed);
+
+ return (0);
+}
+
+
+/*
+ * 'usage()' - Show program usage...
+ */
+
+static void
+usage(void)
+{
+ puts("Usage: testspeed [-c children] [-h] [-r requests] [-v] [-E] "
+ "hostname[:port]");
+ exit(0);
+}
+
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/testsub.c b/scheduler/testsub.c
new file mode 100644
index 000000000..2f7b48659
--- /dev/null
+++ b/scheduler/testsub.c
@@ -0,0 +1,522 @@
+/*
+ * "$Id$"
+ *
+ * Scheduler notification tester for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2006-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Subscribe to the .
+ * print_attributes() - Print the attributes in a request...
+ * sigterm_handler() - Flag when the user hits CTRL-C...
+ * usage() - Show program usage...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups.h>
+#include <cups/debug-private.h>
+#include <cups/string-private.h>
+#include <signal.h>
+
+
+/*
+ * Local globals...
+ */
+
+static int terminate = 0;
+
+
+/*
+ * Local functions...
+ */
+
+static void print_attributes(ipp_t *ipp, int indent);
+static void sigterm_handler(int sig);
+static void usage(void);
+
+
+/*
+ * 'main()' - Subscribe to the .
+ */
+
+int
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ const char *uri; /* URI to use */
+ int num_events; /* Number of events */
+ const char *events[100]; /* Events */
+ int subscription_id, /* notify-subscription-id */
+ sequence_number, /* notify-sequence-number */
+ interval; /* Interval between polls */
+ http_t *http; /* HTTP connection */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* Current attribute */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+ /*
+ * Parse command-line...
+ */
+
+ num_events = 0;
+ uri = NULL;
+
+ for (i = 1; i < argc; i ++)
+ if (!strcmp(argv[i], "-E"))
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+ else if (!strcmp(argv[i], "-e"))
+ {
+ i ++;
+ if (i >= argc || num_events >= 100)
+ usage();
+
+ events[num_events] = argv[i];
+ num_events ++;
+ }
+ else if (!strcmp(argv[i], "-h"))
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ cupsSetServer(argv[i]);
+ }
+ else if (uri || strncmp(argv[i], "ipp://", 6))
+ usage();
+ else
+ uri = argv[i];
+
+ if (!uri)
+ usage();
+
+ if (num_events == 0)
+ {
+ events[0] = "all";
+ num_events = 1;
+ }
+
+ /*
+ * Connect to the server...
+ */
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ perror(cupsServer());
+ return (1);
+ }
+
+ /*
+ * Catch CTRL-C and SIGTERM...
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGINT, sigterm_handler);
+ sigset(SIGTERM, sigterm_handler);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = sigterm_handler;
+ sigaction(SIGINT, &action, NULL);
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGINT, sigterm_handler);
+ signal(SIGTERM, sigterm_handler);
+#endif /* HAVE_SIGSET */
+
+ /*
+ * Create the subscription...
+ */
+
+ if (strstr(uri, "/jobs/"))
+ {
+ request = ippNewRequest(IPP_CREATE_JOB_SUBSCRIPTION);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
+ }
+ else
+ {
+ request = ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
+ uri);
+ }
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ ippAddStrings(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events",
+ num_events, NULL, events);
+ ippAddString(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
+ "notify-pull-method", NULL, "ippget");
+
+ response = cupsDoRequest(http, request, uri);
+ if (cupsLastError() >= IPP_BAD_REQUEST)
+ {
+ fprintf(stderr, "Create-%s-Subscription: %s\n",
+ strstr(uri, "/jobs") ? "Job" : "Printer", cupsLastErrorString());
+ ippDelete(response);
+ httpClose(http);
+ return (1);
+ }
+
+ if ((attr = ippFindAttribute(response, "notify-subscription-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ fputs("ERROR: No notify-subscription-id in response!\n", stderr);
+ ippDelete(response);
+ httpClose(http);
+ return (1);
+ }
+
+ subscription_id = attr->values[0].integer;
+
+ printf("Create-%s-Subscription: notify-subscription-id=%d\n",
+ strstr(uri, "/jobs/") ? "Job" : "Printer", subscription_id);
+
+ ippDelete(response);
+
+ /*
+ * Monitor for events...
+ */
+
+ sequence_number = 0;
+
+ while (!terminate)
+ {
+ /*
+ * Get the current events...
+ */
+
+ printf("\nGet-Notifications(%d,%d):", subscription_id, sequence_number);
+ fflush(stdout);
+
+ request = ippNewRequest(IPP_GET_NOTIFICATIONS);
+
+ if (strstr(uri, "/jobs/"))
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
+ else
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
+ uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, cupsUser());
+
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
+ "notify-subscription-ids", subscription_id);
+ if (sequence_number)
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
+ "notify-sequence-numbers", sequence_number + 1);
+
+ response = cupsDoRequest(http, request, uri);
+
+ printf(" %s\n", ippErrorString(cupsLastError()));
+
+ if (cupsLastError() >= IPP_BAD_REQUEST)
+ fprintf(stderr, "Get-Notifications: %s\n", cupsLastErrorString());
+ else if (response)
+ {
+ print_attributes(response, 0);
+
+ for (attr = ippFindAttribute(response, "notify-sequence-number",
+ IPP_TAG_INTEGER);
+ attr;
+ attr = ippFindNextAttribute(response, "notify-sequence-number",
+ IPP_TAG_INTEGER))
+ if (attr->values[0].integer > sequence_number)
+ sequence_number = attr->values[0].integer;
+ }
+
+ if ((attr = ippFindAttribute(response, "notify-get-interval",
+ IPP_TAG_INTEGER)) != NULL &&
+ attr->values[0].integer > 0)
+ interval = attr->values[0].integer;
+ else
+ interval = 5;
+
+ ippDelete(response);
+ sleep(interval);
+ }
+
+ /*
+ * Cancel the subscription...
+ */
+
+ printf("\nCancel-Subscription:");
+ fflush(stdout);
+
+ request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION);
+
+ if (strstr(uri, "/jobs/"))
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
+ else
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
+ uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
+ "notify-subscription-id", subscription_id);
+
+ ippDelete(cupsDoRequest(http, request, uri));
+
+ printf(" %s\n", ippErrorString(cupsLastError()));
+
+ if (cupsLastError() >= IPP_BAD_REQUEST)
+ fprintf(stderr, "Cancel-Subscription: %s\n", cupsLastErrorString());
+
+ /*
+ * Close the connection and return...
+ */
+
+ httpClose(http);
+
+ return (0);
+}
+
+
+/*
+ * 'print_attributes()' - Print the attributes in a request...
+ */
+
+static void
+print_attributes(ipp_t *ipp, /* I - IPP request */
+ int indent) /* I - Indentation */
+{
+ int i; /* Looping var */
+ ipp_tag_t group; /* Current group */
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_value_t *val; /* Current value */
+ static const char * const tags[] = /* Value/group tag strings */
+ {
+ "reserved-00",
+ "operation-attributes-tag",
+ "job-attributes-tag",
+ "end-of-attributes-tag",
+ "printer-attributes-tag",
+ "unsupported-attributes-tag",
+ "subscription-attributes-tag",
+ "event-attributes-tag",
+ "reserved-08",
+ "reserved-09",
+ "reserved-0A",
+ "reserved-0B",
+ "reserved-0C",
+ "reserved-0D",
+ "reserved-0E",
+ "reserved-0F",
+ "unsupported",
+ "default",
+ "unknown",
+ "no-value",
+ "reserved-14",
+ "not-settable",
+ "delete-attr",
+ "admin-define",
+ "reserved-18",
+ "reserved-19",
+ "reserved-1A",
+ "reserved-1B",
+ "reserved-1C",
+ "reserved-1D",
+ "reserved-1E",
+ "reserved-1F",
+ "reserved-20",
+ "integer",
+ "boolean",
+ "enum",
+ "reserved-24",
+ "reserved-25",
+ "reserved-26",
+ "reserved-27",
+ "reserved-28",
+ "reserved-29",
+ "reserved-2a",
+ "reserved-2b",
+ "reserved-2c",
+ "reserved-2d",
+ "reserved-2e",
+ "reserved-2f",
+ "octetString",
+ "dateTime",
+ "resolution",
+ "rangeOfInteger",
+ "begCollection",
+ "textWithLanguage",
+ "nameWithLanguage",
+ "endCollection",
+ "reserved-38",
+ "reserved-39",
+ "reserved-3a",
+ "reserved-3b",
+ "reserved-3c",
+ "reserved-3d",
+ "reserved-3e",
+ "reserved-3f",
+ "reserved-40",
+ "textWithoutLanguage",
+ "nameWithoutLanguage",
+ "reserved-43",
+ "keyword",
+ "uri",
+ "uriScheme",
+ "charset",
+ "naturalLanguage",
+ "mimeMediaType",
+ "memberName"
+ };
+
+
+ for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next)
+ {
+ if ((attr->group_tag == IPP_TAG_ZERO && indent <= 8) || !attr->name)
+ {
+ group = IPP_TAG_ZERO;
+ putchar('\n');
+ continue;
+ }
+
+ if (group != attr->group_tag)
+ {
+ group = attr->group_tag;
+
+ putchar('\n');
+ for (i = 4; i < indent; i ++)
+ putchar(' ');
+
+ printf("%s:\n\n", tags[group]);
+ }
+
+ for (i = 0; i < indent; i ++)
+ putchar(' ');
+
+ printf("%s (", attr->name);
+ if (attr->num_values > 1)
+ printf("1setOf ");
+ printf("%s):", tags[attr->value_tag]);
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_ENUM :
+ case IPP_TAG_INTEGER :
+ for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
+ printf(" %d", val->integer);
+ putchar('\n');
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
+ printf(" %s", val->boolean ? "true" : "false");
+ putchar('\n');
+ break;
+
+ case IPP_TAG_RANGE :
+ for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
+ printf(" %d-%d", val->range.lower, val->range.upper);
+ putchar('\n');
+ break;
+
+ case IPP_TAG_DATE :
+ {
+ time_t vtime; /* Date/Time value */
+ struct tm *vdate; /* Date info */
+ char vstring[256]; /* Formatted time */
+
+ for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
+ {
+ vtime = ippDateToTime(val->date);
+ vdate = localtime(&vtime);
+ strftime(vstring, sizeof(vstring), "%c", vdate);
+ printf(" (%s)", vstring);
+ }
+ }
+ putchar('\n');
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
+ printf(" %dx%d%s", val->resolution.xres, val->resolution.yres,
+ val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpc");
+ putchar('\n');
+ break;
+
+ case IPP_TAG_STRING :
+ 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_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
+ printf(" \"%s\"", val->string.text);
+ putchar('\n');
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ putchar('\n');
+
+ for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
+ {
+ if (i)
+ putchar('\n');
+ print_attributes(val->collection, indent + 4);
+ }
+ break;
+
+ default :
+ printf("UNKNOWN (%d values)\n", attr->num_values);
+ break;
+ }
+ }
+}
+
+
+/*
+ * 'sigterm_handler()' - Flag when the user hits CTRL-C...
+ */
+
+static void
+sigterm_handler(int sig) /* I - Signal number (unused) */
+{
+ (void)sig;
+
+ terminate = 1;
+}
+
+
+/*
+ * 'usage()' - Show program usage...
+ */
+
+static void
+usage(void)
+{
+ puts("Usage: testsub [-E] [-e event ... -e eventN] [-h hostname] URI");
+ exit(0);
+}
+
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/type.c b/scheduler/type.c
new file mode 100644
index 000000000..289511692
--- /dev/null
+++ b/scheduler/type.c
@@ -0,0 +1,1216 @@
+/*
+ * "$Id$"
+ *
+ * MIME typing routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * mimeAddType() - Add a MIME type to a database.
+ * mimeAddTypeRule() - Add a detection rule for a file type.
+ * mimeFileType() - Determine the type of a file.
+ * mimeType() - Lookup a file type.
+ * mime_compare_types() - Compare two MIME super/type names.
+ * mime_check_rules() - Check each rule in a list.
+ * mime_patmatch() - Pattern matching.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/string-private.h>
+#include <cups/debug-private.h>
+#include <locale.h>
+#include "mime.h"
+
+
+/*
+ * Local types...
+ */
+
+typedef struct _mime_filebuf_s /**** File buffer for MIME typing ****/
+{
+ cups_file_t *fp; /* File pointer */
+ int offset, /* Offset in file */
+ length; /* Length of buffered data */
+ unsigned char buffer[MIME_MAX_BUFFER];/* Buffered data */
+} _mime_filebuf_t;
+
+
+/*
+ * Local functions...
+ */
+
+static int mime_compare_types(mime_type_t *t0, mime_type_t *t1);
+static int mime_check_rules(const char *filename, _mime_filebuf_t *fb,
+ mime_magic_t *rules);
+static int mime_patmatch(const char *s, const char *pat);
+
+
+/*
+ * Local globals...
+ */
+
+#ifdef DEBUG
+static const char * const debug_ops[] =
+ { /* Test names... */
+ "NOP", /* No operation */
+ "AND", /* Logical AND of all children */
+ "OR", /* Logical OR of all children */
+ "MATCH", /* Filename match */
+ "ASCII", /* ASCII characters in range */
+ "PRINTABLE", /* Printable characters (32-255) */
+ "STRING", /* String matches */
+ "CHAR", /* Character/byte matches */
+ "SHORT", /* Short/16-bit word matches */
+ "INT", /* Integer/32-bit word matches */
+ "LOCALE", /* Current locale matches string */
+ "CONTAINS", /* File contains a string */
+ "ISTRING" /* Case-insensitive string matches */
+ };
+#endif /* DEBUG */
+
+
+/*
+ * 'mimeAddType()' - Add a MIME type to a database.
+ */
+
+mime_type_t * /* O - New (or existing) MIME type */
+mimeAddType(mime_t *mime, /* I - MIME database */
+ const char *super, /* I - Super-type name */
+ const char *type) /* I - Type name */
+{
+ mime_type_t *temp; /* New MIME type */
+ size_t typelen; /* Length of type name */
+
+
+ DEBUG_printf(("mimeAddType(mime=%p, super=\"%s\", type=\"%s\")", mime, super,
+ type));
+
+ /*
+ * Range check input...
+ */
+
+ if (!mime || !super || !type)
+ {
+ DEBUG_puts("1mimeAddType: Returning NULL (bad arguments).");
+ return (NULL);
+ }
+
+ /*
+ * See if the type already exists; if so, return the existing type...
+ */
+
+ if ((temp = mimeType(mime, super, type)) != NULL)
+ {
+ DEBUG_printf(("1mimeAddType: Returning %p (existing).", temp));
+ return (temp);
+ }
+
+ /*
+ * The type doesn't exist; add it...
+ */
+
+ if (!mime->types)
+ mime->types = cupsArrayNew((cups_array_func_t)mime_compare_types, NULL);
+
+ if (!mime->types)
+ {
+ DEBUG_puts("1mimeAddType: Returning NULL (no types).");
+ return (NULL);
+ }
+
+ typelen = strlen(type) + 1;
+
+ if ((temp = calloc(1, sizeof(mime_type_t) - MIME_MAX_TYPE + typelen)) == NULL)
+ {
+ DEBUG_puts("1mimeAddType: Returning NULL (out of memory).");
+ return (NULL);
+ }
+
+ strlcpy(temp->super, super, sizeof(temp->super));
+ memcpy(temp->type, type, typelen);
+ temp->priority = 100;
+
+ cupsArrayAdd(mime->types, temp);
+
+ DEBUG_printf(("1mimeAddType: Returning %p (new).", temp));
+ return (temp);
+}
+
+
+/*
+ * 'mimeAddTypeRule()' - Add a detection rule for a file type.
+ */
+
+int /* O - 0 on success, -1 on failure */
+mimeAddTypeRule(mime_type_t *mt, /* I - Type to add to */
+ const char *rule) /* I - Rule to add */
+{
+ int num_values, /* Number of values seen */
+ op, /* Operation code */
+ logic, /* Logic for next rule */
+ invert; /* Invert following rule? */
+ char name[255], /* Name in rule string */
+ value[3][255], /* Value in rule string */
+ *ptr, /* Position in name or value */
+ quote; /* Quote character */
+ int length[3]; /* Length of each parameter */
+ mime_magic_t *temp, /* New rule */
+ *current; /* Current rule */
+
+
+ DEBUG_printf(("mimeAddTypeRule(mt=%p(%s/%s), rule=\"%s\")", mt,
+ mt ? mt->super : "???", mt ? mt->type : "???", rule));
+
+ /*
+ * Range check input...
+ */
+
+ if (!mt || !rule)
+ return (-1);
+
+ /*
+ * Find the last rule in the top-level of the rules tree.
+ */
+
+ for (current = mt->rules; current; current = current->next)
+ if (!current->next)
+ break;
+
+ /*
+ * Parse the rules string. Most rules are either a file extension or a
+ * comparison function:
+ *
+ * extension
+ * function(parameters)
+ */
+
+ logic = MIME_MAGIC_NOP;
+ invert = 0;
+
+ while (*rule != '\0')
+ {
+ while (isspace(*rule & 255))
+ rule ++;
+
+ if (*rule == '(')
+ {
+ DEBUG_puts("1mimeAddTypeRule: New parenthesis group");
+ logic = MIME_MAGIC_NOP;
+ rule ++;
+ }
+ else if (*rule == ')')
+ {
+ DEBUG_puts("1mimeAddTypeRule: Close paren...");
+ if (current == NULL || current->parent == NULL)
+ return (-1);
+
+ current = current->parent;
+
+ if (current->parent == NULL)
+ logic = MIME_MAGIC_OR;
+ else
+ logic = current->parent->op;
+
+ rule ++;
+ }
+ else if (*rule == '+' && current != NULL)
+ {
+ if (logic != MIME_MAGIC_AND &&
+ current != NULL && current->prev != NULL)
+ {
+ /*
+ * OK, we have more than 1 rule in the current tree level... Make a
+ * new group tree and move the previous rule to it...
+ */
+
+ if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL)
+ return (-1);
+
+ temp->op = MIME_MAGIC_AND;
+ temp->child = current;
+ temp->parent = current->parent;
+ current->prev->next = temp;
+ temp->prev = current->prev;
+
+ current->prev = NULL;
+ current->parent = temp;
+
+ DEBUG_printf(("1mimeAddTypeRule: Creating new AND group %p.", temp));
+ }
+ else if (current->parent)
+ {
+ DEBUG_printf(("1mimeAddTypeRule: Setting group %p op to AND.",
+ current->parent));
+ current->parent->op = MIME_MAGIC_AND;
+ }
+
+ logic = MIME_MAGIC_AND;
+ rule ++;
+ }
+ else if (*rule == ',')
+ {
+ if (logic != MIME_MAGIC_OR && current != NULL)
+ {
+ /*
+ * OK, we have two possibilities; either this is the top-level rule or
+ * we have a bunch of AND rules at this level.
+ */
+
+ if (current->parent == NULL)
+ {
+ /*
+ * This is the top-level rule; we have to move *all* of the AND rules
+ * down a level, as AND has precedence over OR.
+ */
+
+ if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL)
+ return (-1);
+
+ DEBUG_printf(("1mimeAddTypeRule: Creating new AND group %p inside OR "
+ "group.", temp));
+
+ while (current->prev != NULL)
+ {
+ current->parent = temp;
+ current = current->prev;
+ }
+
+ current->parent = temp;
+ temp->op = MIME_MAGIC_AND;
+ temp->child = current;
+
+ mt->rules = current = temp;
+ }
+ else
+ {
+ /*
+ * This isn't the top rule, so go up one level...
+ */
+
+ DEBUG_puts("1mimeAddTypeRule: Going up one level.");
+ current = current->parent;
+ }
+ }
+
+ logic = MIME_MAGIC_OR;
+ rule ++;
+ }
+ else if (*rule == '!')
+ {
+ DEBUG_puts("1mimeAddTypeRule: NOT");
+ invert = 1;
+ rule ++;
+ }
+ else if (isalnum(*rule & 255))
+ {
+ /*
+ * Read an extension name or a function...
+ */
+
+ ptr = name;
+ while (isalnum(*rule & 255) && (ptr - name) < (sizeof(name) - 1))
+ *ptr++ = *rule++;
+
+ *ptr = '\0';
+
+ if (*rule == '(')
+ {
+ /*
+ * Read function parameters...
+ */
+
+ rule ++;
+ for (num_values = 0;
+ num_values < (sizeof(value) / sizeof(value[0]));
+ num_values ++)
+ {
+ ptr = value[num_values];
+
+ while ((ptr - value[num_values]) < (sizeof(value[0]) - 1) &&
+ *rule != '\0' && *rule != ',' && *rule != ')')
+ {
+ if (isspace(*rule & 255))
+ {
+ /*
+ * Ignore whitespace...
+ */
+
+ rule ++;
+ continue;
+ }
+ else if (*rule == '\"' || *rule == '\'')
+ {
+ /*
+ * Copy quoted strings literally...
+ */
+
+ quote = *rule++;
+
+ while (*rule != '\0' && *rule != quote &&
+ (ptr - value[num_values]) < (sizeof(value[0]) - 1))
+ *ptr++ = *rule++;
+
+ if (*rule == quote)
+ rule ++;
+ else
+ return (-1);
+ }
+ else if (*rule == '<')
+ {
+ rule ++;
+
+ while (*rule != '>' && *rule != '\0' &&
+ (ptr - value[num_values]) < (sizeof(value[0]) - 1))
+ {
+ if (isxdigit(rule[0] & 255) && isxdigit(rule[1] & 255))
+ {
+ if (isdigit(*rule))
+ *ptr = (*rule++ - '0') << 4;
+ else
+ *ptr = (tolower(*rule++) - 'a' + 10) << 4;
+
+ if (isdigit(*rule))
+ *ptr++ |= *rule++ - '0';
+ else
+ *ptr++ |= tolower(*rule++) - 'a' + 10;
+ }
+ else
+ return (-1);
+ }
+
+ if (*rule == '>')
+ rule ++;
+ else
+ return (-1);
+ }
+ else
+ *ptr++ = *rule++;
+ }
+
+ *ptr = '\0';
+ length[num_values] = ptr - value[num_values];
+
+ if (*rule != ',')
+ {
+ num_values ++;
+ break;
+ }
+
+ rule ++;
+ }
+
+ if (*rule != ')')
+ return (-1);
+
+ rule ++;
+
+ /*
+ * Figure out the function...
+ */
+
+ if (!strcmp(name, "match"))
+ op = MIME_MAGIC_MATCH;
+ else if (!strcmp(name, "ascii"))
+ op = MIME_MAGIC_ASCII;
+ else if (!strcmp(name, "printable"))
+ op = MIME_MAGIC_PRINTABLE;
+ else if (!strcmp(name, "string"))
+ op = MIME_MAGIC_STRING;
+ else if (!strcmp(name, "istring"))
+ op = MIME_MAGIC_ISTRING;
+ else if (!strcmp(name, "char"))
+ op = MIME_MAGIC_CHAR;
+ else if (!strcmp(name, "short"))
+ op = MIME_MAGIC_SHORT;
+ else if (!strcmp(name, "int"))
+ op = MIME_MAGIC_INT;
+ else if (!strcmp(name, "locale"))
+ op = MIME_MAGIC_LOCALE;
+ else if (!strcmp(name, "contains"))
+ op = MIME_MAGIC_CONTAINS;
+ else if (!strcmp(name, "priority") && num_values == 1)
+ {
+ mt->priority = atoi(value[0]);
+ continue;
+ }
+ else
+ return (-1);
+ }
+ else
+ {
+ /*
+ * This is just a filename match on the extension...
+ */
+
+ snprintf(value[0], sizeof(value[0]), "*.%s", name);
+ length[0] = strlen(value[0]);
+ op = MIME_MAGIC_MATCH;
+ }
+
+ /*
+ * Add a rule for this operation.
+ */
+
+ if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL)
+ return (-1);
+
+ temp->invert = invert;
+ if (current != NULL)
+ {
+ temp->parent = current->parent;
+ current->next = temp;
+ }
+ else
+ mt->rules = temp;
+
+ temp->prev = current;
+
+ if (logic == MIME_MAGIC_NOP)
+ {
+ /*
+ * Add parenthetical grouping...
+ */
+
+ DEBUG_printf(("1mimeAddTypeRule: Making new OR group %p for "
+ "parenthesis.", temp));
+
+ temp->op = MIME_MAGIC_OR;
+
+ if ((temp->child = calloc(1, sizeof(mime_magic_t))) == NULL)
+ return (-1);
+
+ temp->child->parent = temp;
+ temp->child->invert = temp->invert;
+ temp->invert = 0;
+
+ temp = temp->child;
+ logic = MIME_MAGIC_OR;
+ }
+
+ DEBUG_printf(("1mimeAddTypeRule: Adding %p: %s, op=MIME_MAGIC_%s(%d), "
+ "logic=MIME_MAGIC_%s, invert=%d.", temp, name,
+ debug_ops[op], op, debug_ops[logic], invert));
+
+ /*
+ * Fill in data for the rule...
+ */
+
+ current = temp;
+ temp->op = op;
+ invert = 0;
+
+ switch (op)
+ {
+ case MIME_MAGIC_MATCH :
+ if (length[0] > (sizeof(temp->value.matchv) - 1))
+ return (-1);
+ strcpy(temp->value.matchv, value[0]);
+ break;
+ case MIME_MAGIC_ASCII :
+ case MIME_MAGIC_PRINTABLE :
+ temp->offset = strtol(value[0], NULL, 0);
+ temp->length = strtol(value[1], NULL, 0);
+ if (temp->length > MIME_MAX_BUFFER)
+ temp->length = MIME_MAX_BUFFER;
+ break;
+ case MIME_MAGIC_STRING :
+ case MIME_MAGIC_ISTRING :
+ temp->offset = strtol(value[0], NULL, 0);
+ if (length[1] > sizeof(temp->value.stringv))
+ return (-1);
+ temp->length = length[1];
+ memcpy(temp->value.stringv, value[1], length[1]);
+ break;
+ case MIME_MAGIC_CHAR :
+ temp->offset = strtol(value[0], NULL, 0);
+ if (length[1] == 1)
+ temp->value.charv = value[1][0];
+ else
+ temp->value.charv = (unsigned char)strtol(value[1], NULL, 0);
+
+ DEBUG_printf(("1mimeAddTypeRule: CHAR(%d,0x%02x)", temp->offset,
+ temp->value.charv));
+ break;
+ case MIME_MAGIC_SHORT :
+ temp->offset = strtol(value[0], NULL, 0);
+ temp->value.shortv = (unsigned short)strtol(value[1], NULL, 0);
+ break;
+ case MIME_MAGIC_INT :
+ temp->offset = strtol(value[0], NULL, 0);
+ temp->value.intv = (unsigned)strtol(value[1], NULL, 0);
+ break;
+ case MIME_MAGIC_LOCALE :
+ if (length[0] > (sizeof(temp->value.localev) - 1))
+ return (-1);
+
+ strcpy(temp->value.localev, value[0]);
+ break;
+ case MIME_MAGIC_CONTAINS :
+ temp->offset = strtol(value[0], NULL, 0);
+ temp->region = strtol(value[1], NULL, 0);
+ if (length[2] > sizeof(temp->value.stringv))
+ return (-1);
+ temp->length = length[2];
+ memcpy(temp->value.stringv, value[2], length[2]);
+ break;
+ }
+ }
+ else
+ break;
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'mimeFileType()' - Determine the type of a file.
+ */
+
+mime_type_t * /* O - Type of file */
+mimeFileType(mime_t *mime, /* I - MIME database */
+ const char *pathname, /* I - Name of file to check on disk */
+ const char *filename, /* I - Original filename or NULL */
+ int *compression) /* O - Is the file compressed? */
+{
+ _mime_filebuf_t fb; /* File buffer */
+ const char *base; /* Base filename of file */
+ mime_type_t *type, /* File type */
+ *best; /* Best match */
+
+
+ DEBUG_printf(("mimeFileType(mime=%p, pathname=\"%s\", filename=\"%s\", "
+ "compression=%p)", mime, pathname, filename, compression));
+
+ /*
+ * Range check input parameters...
+ */
+
+ if (!mime || !pathname)
+ {
+ DEBUG_puts("1mimeFileType: Returning NULL.");
+ return (NULL);
+ }
+
+ /*
+ * Try to open the file...
+ */
+
+ if ((fb.fp = cupsFileOpen(pathname, "r")) == NULL)
+ {
+ DEBUG_printf(("1mimeFileType: Unable to open \"%s\": %s", pathname,
+ strerror(errno)));
+ DEBUG_puts("1mimeFileType: Returning NULL.");
+ return (NULL);
+ }
+
+ fb.offset = -1;
+ fb.length = 0;
+
+ /*
+ * Figure out the base filename (without directory portion)...
+ */
+
+ if (filename)
+ {
+ if ((base = strrchr(filename, '/')) != NULL)
+ base ++;
+ else
+ base = filename;
+ }
+ else if ((base = strrchr(pathname, '/')) != NULL)
+ base ++;
+ else
+ base = pathname;
+
+ /*
+ * Then check it against all known types...
+ */
+
+ for (type = (mime_type_t *)cupsArrayFirst(mime->types), best = NULL;
+ type;
+ type = (mime_type_t *)cupsArrayNext(mime->types))
+ if (mime_check_rules(base, &fb, type->rules))
+ {
+ if (!best || type->priority > best->priority)
+ best = type;
+ }
+
+ /*
+ * Finally, close the file and return a match (if any)...
+ */
+
+ if (compression)
+ {
+ *compression = cupsFileCompression(fb.fp);
+ DEBUG_printf(("1mimeFileType: *compression=%d", *compression));
+ }
+
+ cupsFileClose(fb.fp);
+
+ DEBUG_printf(("1mimeFileType: Returning %p(%s/%s).", best,
+ best ? best->super : "???", best ? best->type : "???"));
+ return (best);
+}
+
+
+/*
+ * 'mimeType()' - Lookup a file type.
+ */
+
+mime_type_t * /* O - Matching file type definition */
+mimeType(mime_t *mime, /* I - MIME database */
+ const char *super, /* I - Super-type name */
+ const char *type) /* I - Type name */
+{
+ mime_type_t key, /* MIME type search key */
+ *mt; /* Matching type */
+
+
+ DEBUG_printf(("mimeType(mime=%p, super=\"%s\", type=\"%s\")", mime, super,
+ type));
+
+ /*
+ * Range check input...
+ */
+
+ if (!mime || !super || !type)
+ {
+ DEBUG_puts("1mimeType: Returning NULL.");
+ return (NULL);
+ }
+
+ /*
+ * Lookup the type in the array...
+ */
+
+ strlcpy(key.super, super, sizeof(key.super));
+ strlcpy(key.type, type, sizeof(key.type));
+
+ mt = (mime_type_t *)cupsArrayFind(mime->types, &key);
+ DEBUG_printf(("1mimeType: Returning %p.", mt));
+ return (mt);
+}
+
+
+/*
+ * 'mime_compare_types()' - Compare two MIME super/type names.
+ */
+
+static int /* O - Result of comparison */
+mime_compare_types(mime_type_t *t0, /* I - First type */
+ mime_type_t *t1) /* I - Second type */
+{
+ int i; /* Result of comparison */
+
+
+ if ((i = _cups_strcasecmp(t0->super, t1->super)) == 0)
+ i = _cups_strcasecmp(t0->type, t1->type);
+
+ return (i);
+}
+
+
+/*
+ * 'mime_check_rules()' - Check each rule in a list.
+ */
+
+static int /* O - 1 if match, 0 if no match */
+mime_check_rules(
+ const char *filename, /* I - Filename */
+ _mime_filebuf_t *fb, /* I - File to check */
+ mime_magic_t *rules) /* I - Rules to check */
+{
+ int n; /* Looping var */
+ int region; /* Region to look at */
+ int logic, /* Logic to apply */
+ result, /* Result of test */
+ intv; /* Integer value */
+ short shortv; /* Short value */
+ unsigned char *bufptr; /* Pointer into buffer */
+
+
+ DEBUG_printf(("4mime_check_rules(filename=\"%s\", fb=%p, rules=%p)", filename,
+ fb, rules));
+
+ if (rules == NULL)
+ return (0);
+
+ if (rules->parent == NULL)
+ logic = MIME_MAGIC_OR;
+ else
+ logic = rules->parent->op;
+
+ result = 0;
+
+ while (rules != NULL)
+ {
+ /*
+ * Compute the result of this rule...
+ */
+
+ switch (rules->op)
+ {
+ case MIME_MAGIC_MATCH :
+ result = mime_patmatch(filename, rules->value.matchv);
+ break;
+
+ case MIME_MAGIC_ASCII :
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (fb->offset < 0 || rules->offset < fb->offset ||
+ (rules->offset + rules->length) > (fb->offset + fb->length))
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ cupsFileSeek(fb->fp, rules->offset);
+ fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
+ sizeof(fb->buffer));
+ fb->offset = rules->offset;
+ }
+
+ /*
+ * Test for ASCII printable characters plus standard control chars.
+ */
+
+ if ((rules->offset + rules->length) > (fb->offset + fb->length))
+ n = fb->offset + fb->length - rules->offset;
+ else
+ n = rules->length;
+
+ bufptr = fb->buffer + rules->offset - fb->offset;
+ while (n > 0)
+ if ((*bufptr >= 32 && *bufptr <= 126) ||
+ (*bufptr >= 8 && *bufptr <= 13) ||
+ *bufptr == 26 || *bufptr == 27)
+ {
+ n --;
+ bufptr ++;
+ }
+ else
+ break;
+
+ result = (n == 0);
+ break;
+
+ case MIME_MAGIC_PRINTABLE :
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (fb->offset < 0 || rules->offset < fb->offset ||
+ (rules->offset + rules->length) > (fb->offset + fb->length))
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ cupsFileSeek(fb->fp, rules->offset);
+ fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
+ sizeof(fb->buffer));
+ fb->offset = rules->offset;
+ }
+
+ /*
+ * Test for 8-bit printable characters plus standard control chars.
+ */
+
+ if ((rules->offset + rules->length) > (fb->offset + fb->length))
+ n = fb->offset + fb->length - rules->offset;
+ else
+ n = rules->length;
+
+ bufptr = fb->buffer + rules->offset - fb->offset;
+
+ while (n > 0)
+ if (*bufptr >= 128 ||
+ (*bufptr >= 32 && *bufptr <= 126) ||
+ (*bufptr >= 8 && *bufptr <= 13) ||
+ *bufptr == 26 || *bufptr == 27)
+ {
+ n --;
+ bufptr ++;
+ }
+ else
+ break;
+
+ result = (n == 0);
+ break;
+
+ case MIME_MAGIC_STRING :
+ DEBUG_printf(("5mime_check_rules: string(%d, \"%s\")", rules->offset,
+ rules->value.stringv));
+
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (fb->offset < 0 || rules->offset < fb->offset ||
+ (rules->offset + rules->length) > (fb->offset + fb->length))
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ cupsFileSeek(fb->fp, rules->offset);
+ fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
+ sizeof(fb->buffer));
+ fb->offset = rules->offset;
+
+ DEBUG_printf(("5mime_check_rules: loaded %d byte fb->buffer at %d, starts "
+ "with \"%c%c%c%c\".",
+ fb->length, fb->offset, fb->buffer[0], fb->buffer[1],
+ fb->buffer[2], fb->buffer[3]));
+ }
+
+ /*
+ * Compare the buffer against the string. If the file is too
+ * short then don't compare - it can't match...
+ */
+
+ if ((rules->offset + rules->length) > (fb->offset + fb->length))
+ result = 0;
+ else
+ result = (memcmp(fb->buffer + rules->offset - fb->offset,
+ rules->value.stringv, rules->length) == 0);
+ DEBUG_printf(("5mime_check_rules: result=%d", result));
+ break;
+
+ case MIME_MAGIC_ISTRING :
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (fb->offset < 0 || rules->offset < fb->offset ||
+ (rules->offset + rules->length) > (fb->offset + fb->length))
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ cupsFileSeek(fb->fp, rules->offset);
+ fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
+ sizeof(fb->buffer));
+ fb->offset = rules->offset;
+ }
+
+ /*
+ * Compare the buffer against the string. If the file is too
+ * short then don't compare - it can't match...
+ */
+
+ if ((rules->offset + rules->length) > (fb->offset + fb->length))
+ result = 0;
+ else
+ result = (_cups_strncasecmp((char *)fb->buffer + rules->offset -
+ fb->offset,
+ rules->value.stringv, rules->length) == 0);
+ break;
+
+ case MIME_MAGIC_CHAR :
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (fb->offset < 0 || rules->offset < fb->offset)
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ cupsFileSeek(fb->fp, rules->offset);
+ fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
+ sizeof(fb->buffer));
+ fb->offset = rules->offset;
+ }
+
+ /*
+ * Compare the character values; if the file is too short, it
+ * can't match...
+ */
+
+ if (fb->length < 1)
+ result = 0;
+ else
+ result = (fb->buffer[rules->offset - fb->offset] ==
+ rules->value.charv);
+ break;
+
+ case MIME_MAGIC_SHORT :
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (fb->offset < 0 || rules->offset < fb->offset ||
+ (rules->offset + 2) > (fb->offset + fb->length))
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ cupsFileSeek(fb->fp, rules->offset);
+ fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
+ sizeof(fb->buffer));
+ fb->offset = rules->offset;
+ }
+
+ /*
+ * Compare the short values; if the file is too short, it
+ * can't match...
+ */
+
+ if (fb->length < 2)
+ result = 0;
+ else
+ {
+ bufptr = fb->buffer + rules->offset - fb->offset;
+ shortv = (bufptr[0] << 8) | bufptr[1];
+ result = (shortv == rules->value.shortv);
+ }
+ break;
+
+ case MIME_MAGIC_INT :
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (fb->offset < 0 || rules->offset < fb->offset ||
+ (rules->offset + 4) > (fb->offset + fb->length))
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ cupsFileSeek(fb->fp, rules->offset);
+ fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
+ sizeof(fb->buffer));
+ fb->offset = rules->offset;
+ }
+
+ /*
+ * Compare the int values; if the file is too short, it
+ * can't match...
+ */
+
+ if (fb->length < 4)
+ result = 0;
+ else
+ {
+ bufptr = fb->buffer + rules->offset - fb->offset;
+ intv = (((((bufptr[0] << 8) | bufptr[1]) << 8) |
+ bufptr[2]) << 8) | bufptr[3];
+ result = (intv == rules->value.intv);
+ }
+ break;
+
+ case MIME_MAGIC_LOCALE :
+#if defined(WIN32) || defined(__EMX__) || defined(__APPLE__)
+ result = (strcmp(rules->value.localev,
+ setlocale(LC_ALL, "")) == 0);
+#else
+ result = (strcmp(rules->value.localev,
+ setlocale(LC_MESSAGES, "")) == 0);
+#endif /* __APPLE__ */
+ break;
+
+ case MIME_MAGIC_CONTAINS :
+ /*
+ * Load the buffer if necessary...
+ */
+
+ if (fb->offset < 0 || rules->offset < fb->offset ||
+ (rules->offset + rules->region) > (fb->offset + fb->length))
+ {
+ /*
+ * Reload file buffer...
+ */
+
+ cupsFileSeek(fb->fp, rules->offset);
+ fb->length = cupsFileRead(fb->fp, (char *)fb->buffer,
+ sizeof(fb->buffer));
+ fb->offset = rules->offset;
+ }
+
+ /*
+ * Compare the buffer against the string. If the file is too
+ * short then don't compare - it can't match...
+ */
+
+ if ((rules->offset + rules->length) > (fb->offset + fb->length))
+ result = 0;
+ else
+ {
+ if (fb->length > rules->region)
+ region = rules->region - rules->length;
+ else
+ region = fb->length - rules->length;
+
+ for (n = 0; n < region; n ++)
+ if ((result = (memcmp(fb->buffer + rules->offset - fb->offset + n,
+ rules->value.stringv,
+ rules->length) == 0)) != 0)
+ break;
+ }
+ break;
+
+ default :
+ if (rules->child != NULL)
+ result = mime_check_rules(filename, fb, rules->child);
+ else
+ result = 0;
+ break;
+ }
+
+ /*
+ * If the logic is inverted, invert the result...
+ */
+
+ if (rules->invert)
+ result = !result;
+
+ /*
+ * OK, now if the current logic is OR and this result is true, the this
+ * rule set is true. If the current logic is AND and this result is false,
+ * the the rule set is false...
+ */
+
+ DEBUG_printf(("5mime_check_rules: result of test %p (MIME_MAGIC_%s) is %d",
+ rules, debug_ops[rules->op], result));
+
+ if ((result && logic == MIME_MAGIC_OR) ||
+ (!result && logic == MIME_MAGIC_AND))
+ return (result);
+
+ /*
+ * Otherwise the jury is still out on this one, so move to the next rule.
+ */
+
+ rules = rules->next;
+ }
+
+ return (result);
+}
+
+
+/*
+ * 'mime_patmatch()' - Pattern matching.
+ */
+
+static int /* O - 1 if match, 0 if no match */
+mime_patmatch(const char *s, /* I - String to match against */
+ const char *pat) /* I - Pattern to match against */
+{
+ /*
+ * Range check the input...
+ */
+
+ if (s == NULL || pat == NULL)
+ return (0);
+
+ /*
+ * Loop through the pattern and match strings, and stop if we come to a
+ * point where the strings don't match or we find a complete match.
+ */
+
+ while (*s != '\0' && *pat != '\0')
+ {
+ if (*pat == '*')
+ {
+ /*
+ * Wildcard - 0 or more characters...
+ */
+
+ pat ++;
+ if (*pat == '\0')
+ return (1); /* Last pattern char is *, so everything matches... */
+
+ /*
+ * Test all remaining combinations until we get to the end of the string.
+ */
+
+ while (*s != '\0')
+ {
+ if (mime_patmatch(s, pat))
+ return (1);
+
+ s ++;
+ }
+ }
+ else if (*pat == '?')
+ {
+ /*
+ * Wildcard - 1 character...
+ */
+
+ pat ++;
+ s ++;
+ continue;
+ }
+ else if (*pat == '[')
+ {
+ /*
+ * Match a character from the input set [chars]...
+ */
+
+ pat ++;
+ while (*pat != ']' && *pat != '\0')
+ if (*s == *pat)
+ break;
+ else
+ pat ++;
+
+ if (*pat == ']' || *pat == '\0')
+ return (0);
+
+ while (*pat != ']' && *pat != '\0')
+ pat ++;
+
+ if (*pat == ']')
+ pat ++;
+
+ continue;
+ }
+ else if (*pat == '\\')
+ {
+ /*
+ * Handle quoted characters...
+ */
+
+ pat ++;
+ }
+
+ /*
+ * Stop if the pattern and string don't match...
+ */
+
+ if (*pat++ != *s++)
+ return (0);
+ }
+
+ /*
+ * Done parsing the pattern and string; return 1 if the last character
+ * matches and 0 otherwise...
+ */
+
+ return (*s == *pat);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/util.c b/scheduler/util.c
new file mode 100644
index 000000000..c8ea8c9e9
--- /dev/null
+++ b/scheduler/util.c
@@ -0,0 +1,471 @@
+/*
+ * "$Id$"
+ *
+ * Mini-daemon utility functions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cupsdCompareNames() - Compare two names.
+ * cupsdCreateStringsArray() - Create a CUPS array of strings.
+ * cupsdExec() - Run a program with the correct environment.
+ * cupsdPipeCommand() - Read output from a command.
+ * cupsdSendIPPGroup() - Send a group tag.
+ * cupsdSendIPPHeader() - Send the IPP response header.
+ * cupsdSendIPPInteger() - Send an integer attribute.
+ * cupsdSendIPPString() - Send a string attribute.
+ * cupsdSendIPPTrailer() - Send the end-of-message tag.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "util.h"
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef __APPLE__
+# include <libgen.h>
+extern char **environ;
+#endif /* __APPLE__ */
+
+
+/*
+ * 'cupsdCompareNames()' - Compare two names.
+ *
+ * This function basically does a _cups_strcasecmp() of the two strings,
+ * but is also aware of numbers so that "a2" < "a100".
+ */
+
+int /* O - Result of comparison */
+cupsdCompareNames(const char *s, /* I - First string */
+ const char *t) /* I - Second string */
+{
+ int diff, /* Difference between digits */
+ digits; /* Number of digits */
+
+
+ /*
+ * Loop through both names, returning only when a difference is
+ * seen. Also, compare whole numbers rather than just characters, too!
+ */
+
+ while (*s && *t)
+ {
+ if (isdigit(*s & 255) && isdigit(*t & 255))
+ {
+ /*
+ * Got a number; start by skipping leading 0's...
+ */
+
+ while (*s == '0')
+ s ++;
+ while (*t == '0')
+ t ++;
+
+ /*
+ * Skip equal digits...
+ */
+
+ while (isdigit(*s & 255) && *s == *t)
+ {
+ s ++;
+ t ++;
+ }
+
+ /*
+ * Bounce out if *s and *t aren't both digits...
+ */
+
+ if (isdigit(*s & 255) && !isdigit(*t & 255))
+ return (1);
+ else if (!isdigit(*s & 255) && isdigit(*t & 255))
+ return (-1);
+ else if (!isdigit(*s & 255) || !isdigit(*t & 255))
+ continue;
+
+ if (*s < *t)
+ diff = -1;
+ else
+ diff = 1;
+
+ /*
+ * Figure out how many more digits there are...
+ */
+
+ digits = 0;
+ s ++;
+ t ++;
+
+ while (isdigit(*s & 255))
+ {
+ digits ++;
+ s ++;
+ }
+
+ while (isdigit(*t & 255))
+ {
+ digits --;
+ t ++;
+ }
+
+ /*
+ * Return if the number or value of the digits is different...
+ */
+
+ if (digits < 0)
+ return (-1);
+ else if (digits > 0)
+ return (1);
+ else if (diff)
+ return (diff);
+ }
+ else if (tolower(*s) < tolower(*t))
+ return (-1);
+ else if (tolower(*s) > tolower(*t))
+ return (1);
+ else
+ {
+ s ++;
+ t ++;
+ }
+ }
+
+ /*
+ * Return the results of the final comparison...
+ */
+
+ if (*s)
+ return (1);
+ else if (*t)
+ return (-1);
+ else
+ return (0);
+}
+
+
+/*
+ * 'cupsdCreateStringsArray()' - Create a CUPS array of strings.
+ */
+
+cups_array_t * /* O - CUPS array */
+cupsdCreateStringsArray(const char *s) /* I - Comma-delimited strings */
+{
+ if (!s || !*s)
+ return (NULL);
+ else
+ return (_cupsArrayNewStrings(s));
+}
+
+
+/*
+ * 'cupsdExec()' - Run a program with the correct environment.
+ *
+ * On Mac OS X, we need to update the CFProcessPath environment variable that
+ * is passed in the environment so the child can access its bundled resources.
+ */
+
+int /* O - exec() status */
+cupsdExec(const char *command, /* I - Full path to program */
+ char **argv) /* I - Command-line arguments */
+{
+#ifdef __APPLE__
+ int i, j; /* Looping vars */
+ char *envp[500], /* Array of environment variables */
+ cfprocesspath[1024], /* CFProcessPath environment variable */
+ linkpath[1024]; /* Link path for symlinks... */
+ int linkbytes; /* Bytes for link path */
+
+
+ /*
+ * Some Mac OS X programs are bundled and need the CFProcessPath environment
+ * variable defined. If the command is a symlink, resolve the link and point
+ * to the resolved location, otherwise, use the command path itself.
+ */
+
+ if ((linkbytes = readlink(command, linkpath, sizeof(linkpath) - 1)) > 0)
+ {
+ /*
+ * Yes, this is a symlink to the actual program, nul-terminate and
+ * use it...
+ */
+
+ linkpath[linkbytes] = '\0';
+
+ if (linkpath[0] == '/')
+ snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s",
+ linkpath);
+ else
+ snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s/%s",
+ dirname((char *)command), linkpath);
+ }
+ else
+ snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s", command);
+
+ envp[0] = cfprocesspath;
+
+ /*
+ * Copy the rest of the environment except for any CFProcessPath that may
+ * already be there...
+ */
+
+ for (i = 1, j = 0;
+ environ[j] && i < (int)(sizeof(envp) / sizeof(envp[0]) - 1);
+ j ++)
+ if (strncmp(environ[j], "CFProcessPath=", 14))
+ envp[i ++] = environ[j];
+
+ envp[i] = NULL;
+
+ /*
+ * Use execve() to run the program...
+ */
+
+ return (execve(command, argv, envp));
+
+#else
+ /*
+ * On other operating systems, just call execv() to use the same environment
+ * variables as the parent...
+ */
+
+ return (execv(command, argv));
+#endif /* __APPLE__ */
+}
+
+
+/*
+ * 'cupsdPipeCommand()' - Read output from a command.
+ */
+
+cups_file_t * /* O - CUPS file or NULL on error */
+cupsdPipeCommand(int *pid, /* O - Process ID or 0 on error */
+ const char *command, /* I - Command to run */
+ char **argv, /* I - Arguments to pass to command */
+ int user) /* I - User to run as or 0 for current */
+{
+ int fd, /* Temporary file descriptor */
+ fds[2]; /* Pipe file descriptors */
+
+
+ /*
+ * First create the pipe...
+ */
+
+ if (pipe(fds))
+ {
+ *pid = 0;
+ return (NULL);
+ }
+
+ /*
+ * Set the "close on exec" flag on each end of the pipe...
+ */
+
+ if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
+ {
+ close(fds[0]);
+ close(fds[1]);
+
+ *pid = 0;
+
+ return (NULL);
+ }
+
+ if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
+ {
+ close(fds[0]);
+ close(fds[1]);
+
+ *pid = 0;
+
+ return (NULL);
+ }
+
+ /*
+ * Then run the command...
+ */
+
+ if ((*pid = fork()) < 0)
+ {
+ /*
+ * Unable to fork!
+ */
+
+ *pid = 0;
+ close(fds[0]);
+ close(fds[1]);
+
+ return (NULL);
+ }
+ else if (!*pid)
+ {
+ /*
+ * Child comes here...
+ */
+
+ if (!getuid() && user)
+ setuid(user); /* Run as restricted user */
+
+ if ((fd = open("/dev/null", O_RDONLY)) > 0)
+ {
+ dup2(fd, 0); /* </dev/null */
+ close(fd);
+ }
+
+ dup2(fds[1], 1); /* >pipe */
+ close(fds[1]);
+
+ cupsdExec(command, argv);
+ exit(errno);
+ }
+
+ /*
+ * Parent comes here, open the input side of the pipe...
+ */
+
+ close(fds[1]);
+
+ return (cupsFileOpenFd(fds[0], "r"));
+}
+
+
+/*
+ * 'cupsdSendIPPGroup()' - Send a group tag.
+ */
+
+void
+cupsdSendIPPGroup(ipp_tag_t group_tag) /* I - Group tag */
+{
+ /*
+ * Send IPP group tag (1 byte)...
+ */
+
+ putchar(group_tag);
+}
+
+
+/*
+ * 'cupsdSendIPPHeader()' - Send the IPP response header.
+ */
+
+void
+cupsdSendIPPHeader(
+ ipp_status_t status_code, /* I - Status code */
+ int request_id) /* I - Request ID */
+{
+ /*
+ * Send IPP/1.1 response header: version number (2 bytes), status code
+ * (2 bytes), and request ID (4 bytes)...
+ *
+ * TODO: Add version number (IPP/2.x and IPP/1.0) support.
+ */
+
+ putchar(1);
+ putchar(1);
+
+ putchar(status_code >> 8);
+ putchar(status_code);
+
+ putchar(request_id >> 24);
+ putchar(request_id >> 16);
+ putchar(request_id >> 8);
+ putchar(request_id);
+}
+
+
+/*
+ * 'cupsdSendIPPInteger()' - Send an integer attribute.
+ */
+
+void
+cupsdSendIPPInteger(
+ ipp_tag_t value_tag, /* I - Value tag */
+ const char *name, /* I - Attribute name */
+ int value) /* I - Attribute value */
+{
+ size_t len; /* Length of attribute name */
+
+
+ /*
+ * Send IPP integer value: value tag (1 byte), name length (2 bytes),
+ * name string (without nul), value length (2 bytes), and value (4 bytes)...
+ */
+
+ putchar(value_tag);
+
+ len = strlen(name);
+ putchar(len >> 8);
+ putchar(len);
+
+ fputs(name, stdout);
+
+ putchar(0);
+ putchar(4);
+
+ putchar(value >> 24);
+ putchar(value >> 16);
+ putchar(value >> 8);
+ putchar(value);
+}
+
+
+/*
+ * 'cupsdSendIPPString()' - Send a string attribute.
+ */
+
+void
+cupsdSendIPPString(
+ ipp_tag_t value_tag, /* I - Value tag */
+ const char *name, /* I - Attribute name */
+ const char *value) /* I - Attribute value */
+{
+ size_t len; /* Length of attribute name */
+
+
+ /*
+ * Send IPP string value: value tag (1 byte), name length (2 bytes),
+ * name string (without nul), value length (2 bytes), and value string
+ * (without nul)...
+ */
+
+ putchar(value_tag);
+
+ len = strlen(name);
+ putchar(len >> 8);
+ putchar(len);
+
+ fputs(name, stdout);
+
+ len = strlen(value);
+ putchar(len >> 8);
+ putchar(len);
+
+ fputs(value, stdout);
+}
+
+
+/*
+ * 'cupsdSendIPPTrailer()' - Send the end-of-message tag.
+ */
+
+void
+cupsdSendIPPTrailer(void)
+{
+ putchar(IPP_TAG_END);
+ fflush(stdout);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/util.h b/scheduler/util.h
new file mode 100644
index 000000000..6c2a05ace
--- /dev/null
+++ b/scheduler/util.h
@@ -0,0 +1,71 @@
+/*
+ * "$Id$"
+ *
+ * Mini-daemon utility definitions for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPSD_UTIL_H_
+# define _CUPSD_UTIL_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include <cups/array-private.h>
+# include <cups/file-private.h>
+# include <signal.h>
+
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Types...
+ */
+
+typedef int (*cupsd_compare_func_t)(const void *, const void *);
+
+
+/*
+ * Prototypes...
+ */
+
+extern int cupsdCompareNames(const char *s, const char *t);
+extern cups_array_t *cupsdCreateStringsArray(const char *s);
+extern int cupsdExec(const char *command, char **argv);
+extern cups_file_t *cupsdPipeCommand(int *pid, const char *command,
+ char **argv, int user);
+extern void cupsdSendIPPGroup(ipp_tag_t group_tag);
+extern void cupsdSendIPPHeader(ipp_status_t status_code,
+ int request_id);
+extern void cupsdSendIPPInteger(ipp_tag_t value_tag,
+ const char *name, int value);
+extern void cupsdSendIPPString(ipp_tag_t value_tag,
+ const char *name, const char *value);
+extern void cupsdSendIPPTrailer(void);
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPSD_UTIL_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scripting/perl/CUPS.pm b/scripting/perl/CUPS.pm
new file mode 100644
index 000000000..5f2ed5f14
--- /dev/null
+++ b/scripting/perl/CUPS.pm
@@ -0,0 +1,144 @@
+package CUPS;
+
+use 5.006;
+use strict;
+use warnings;
+use Carp;
+
+require Exporter;
+require DynaLoader;
+use AutoLoader;
+
+our @ISA = qw(Exporter DynaLoader);
+
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+
+# This allows declaration use CUPS ':all';
+# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
+# will save memory.
+our %EXPORT_TAGS = ( 'all' => [ qw(
+ CUPS_DATE_ANY
+ CUPS_VERSION
+ HTTP_MAX_BUFFER
+ HTTP_MAX_HOST
+ HTTP_MAX_URI
+ HTTP_MAX_VALUE
+ IPP_MAX_NAME
+ IPP_MAX_VALUES
+ IPP_PORT
+ PPD_MAX_LINE
+ PPD_MAX_NAME
+ PPD_MAX_TEXT
+ PPD_VERSION
+) ] );
+
+our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+our @EXPORT = qw(
+ CUPS_DATE_ANY
+ CUPS_VERSION
+ HTTP_MAX_BUFFER
+ HTTP_MAX_HOST
+ HTTP_MAX_URI
+ HTTP_MAX_VALUE
+ IPP_MAX_NAME
+ IPP_MAX_VALUES
+ IPP_PORT
+ PPD_MAX_LINE
+ PPD_MAX_NAME
+ PPD_MAX_TEXT
+ PPD_VERSION
+);
+our $VERSION = '1.2';
+
+sub AUTOLOAD {
+ # This AUTOLOAD is used to 'autoload' constants from the constant()
+ # XS function. If a constant is not found then control is passed
+ # to the AUTOLOAD in AutoLoader.
+
+ my $constname;
+ our $AUTOLOAD;
+ ($constname = $AUTOLOAD) =~ s/.*:://;
+ croak "& not defined" if $constname eq 'constant';
+ my $val = constant($constname, @_ ? $_[0] : 0);
+ if ($! != 0) {
+ if ($! =~ /Invalid/ || $!{EINVAL}) {
+ $AutoLoader::AUTOLOAD = $AUTOLOAD;
+ goto &AutoLoader::AUTOLOAD;
+ }
+ else {
+ croak "Your vendor has not defined CUPS macro $constname";
+ }
+ }
+ {
+ no strict 'refs';
+ # Fixed between 5.005_53 and 5.005_61
+ if ($] >= 5.00561) {
+ *$AUTOLOAD = sub () { $val };
+ }
+ else {
+ *$AUTOLOAD = sub { $val };
+ }
+ }
+ goto &$AUTOLOAD;
+}
+
+bootstrap CUPS $VERSION;
+
+# Preloaded methods go here.
+
+# Autoload methods go after =cut, and are processed by the autosplit program.
+
+1;
+__END__
+# Below is stub documentation for your module. You better edit it!
+
+=head1 NAME
+
+CUPS - Perl extension for blah blah blah
+
+=head1 SYNOPSIS
+
+ use CUPS;
+ blah blah blah
+
+=head1 DESCRIPTION
+
+Stub documentation for CUPS, created by h2xs. It looks like the
+author of the extension was negligent enough to leave the stub
+unedited.
+
+Blah blah blah.
+
+=head2 EXPORT
+
+None by default.
+
+=head2 Exportable constants
+
+ CUPS_DATE_ANY
+ CUPS_VERSION
+ HTTP_MAX_BUFFER
+ HTTP_MAX_HOST
+ HTTP_MAX_URI
+ HTTP_MAX_VALUE
+ IPP_MAX_NAME
+ IPP_MAX_VALUES
+ IPP_PORT
+ PPD_MAX_LINE
+ PPD_MAX_NAME
+ PPD_MAX_TEXT
+ PPD_VERSION
+
+
+=head1 AUTHOR
+
+A. U. Thor, E<lt>a.u.thor@a.galaxy.far.far.awayE<gt>
+
+=head1 SEE ALSO
+
+L<perl>.
+
+=cut
diff --git a/scripting/perl/CUPS.xs b/scripting/perl/CUPS.xs
new file mode 100644
index 000000000..efaf6dc7a
--- /dev/null
+++ b/scripting/perl/CUPS.xs
@@ -0,0 +1,270 @@
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include <cups/cups.h>
+#include <cups/http.h>
+#include <cups/ipp.h>
+#include <cups/language.h>
+#include <cups/ppd.h>
+
+static int
+not_here(char *s)
+{
+ croak("%s not implemented on this architecture", s);
+ return -1;
+}
+
+static double
+constant_PPD_M(char *name, int len, int arg)
+{
+ if (5 + 3 >= len ) {
+ errno = EINVAL;
+ return 0;
+ }
+ switch (name[5 + 3]) {
+ case 'L':
+ if (strEQ(name + 5, "AX_LINE")) { /* PPD_M removed */
+#ifdef PPD_MAX_LINE
+ return PPD_MAX_LINE;
+#else
+ goto not_there;
+#endif
+ }
+ case 'N':
+ if (strEQ(name + 5, "AX_NAME")) { /* PPD_M removed */
+#ifdef PPD_MAX_NAME
+ return PPD_MAX_NAME;
+#else
+ goto not_there;
+#endif
+ }
+ case 'T':
+ if (strEQ(name + 5, "AX_TEXT")) { /* PPD_M removed */
+#ifdef PPD_MAX_TEXT
+ return PPD_MAX_TEXT;
+#else
+ goto not_there;
+#endif
+ }
+ }
+ errno = EINVAL;
+ return 0;
+
+not_there:
+ errno = ENOENT;
+ return 0;
+}
+
+static double
+constant_P(char *name, int len, int arg)
+{
+ if (1 + 3 >= len ) {
+ errno = EINVAL;
+ return 0;
+ }
+ switch (name[1 + 3]) {
+ case 'M':
+ if (!strnEQ(name + 1,"PD_", 3))
+ break;
+ return constant_PPD_M(name, len, arg);
+ case 'V':
+ if (strEQ(name + 1, "PD_VERSION")) { /* P removed */
+#ifdef PPD_VERSION
+ return PPD_VERSION;
+#else
+ goto not_there;
+#endif
+ }
+ }
+ errno = EINVAL;
+ return 0;
+
+not_there:
+ errno = ENOENT;
+ return 0;
+}
+
+static double
+constant_H(char *name, int len, int arg)
+{
+ if (1 + 8 >= len ) {
+ errno = EINVAL;
+ return 0;
+ }
+ switch (name[1 + 8]) {
+ case 'B':
+ if (strEQ(name + 1, "TTP_MAX_BUFFER")) { /* H removed */
+#ifdef HTTP_MAX_BUFFER
+ return HTTP_MAX_BUFFER;
+#else
+ goto not_there;
+#endif
+ }
+ case 'H':
+ if (strEQ(name + 1, "TTP_MAX_HOST")) { /* H removed */
+#ifdef HTTP_MAX_HOST
+ return HTTP_MAX_HOST;
+#else
+ goto not_there;
+#endif
+ }
+ case 'U':
+ if (strEQ(name + 1, "TTP_MAX_URI")) { /* H removed */
+#ifdef HTTP_MAX_URI
+ return HTTP_MAX_URI;
+#else
+ goto not_there;
+#endif
+ }
+ case 'V':
+ if (strEQ(name + 1, "TTP_MAX_VALUE")) { /* H removed */
+#ifdef HTTP_MAX_VALUE
+ return HTTP_MAX_VALUE;
+#else
+ goto not_there;
+#endif
+ }
+ }
+ errno = EINVAL;
+ return 0;
+
+not_there:
+ errno = ENOENT;
+ return 0;
+}
+
+static double
+constant_IPP_M(char *name, int len, int arg)
+{
+ if (5 + 3 >= len ) {
+ errno = EINVAL;
+ return 0;
+ }
+ switch (name[5 + 3]) {
+ case 'N':
+ if (strEQ(name + 5, "AX_NAME")) { /* IPP_M removed */
+#ifdef IPP_MAX_NAME
+ return IPP_MAX_NAME;
+#else
+ goto not_there;
+#endif
+ }
+ case 'V':
+ if (strEQ(name + 5, "AX_VALUES")) { /* IPP_M removed */
+#ifdef IPP_MAX_VALUES
+ return IPP_MAX_VALUES;
+#else
+ goto not_there;
+#endif
+ }
+ }
+ errno = EINVAL;
+ return 0;
+
+not_there:
+ errno = ENOENT;
+ return 0;
+}
+
+static double
+constant_I(char *name, int len, int arg)
+{
+ if (1 + 3 >= len ) {
+ errno = EINVAL;
+ return 0;
+ }
+ switch (name[1 + 3]) {
+ case 'M':
+ if (!strnEQ(name + 1,"PP_", 3))
+ break;
+ return constant_IPP_M(name, len, arg);
+ case 'P':
+ if (strEQ(name + 1, "PP_PORT")) { /* I removed */
+#ifdef IPP_PORT
+ return IPP_PORT;
+#else
+ goto not_there;
+#endif
+ }
+ }
+ errno = EINVAL;
+ return 0;
+
+not_there:
+ errno = ENOENT;
+ return 0;
+}
+
+static double
+constant_C(char *name, int len, int arg)
+{
+ if (1 + 4 >= len ) {
+ errno = EINVAL;
+ return 0;
+ }
+ switch (name[1 + 4]) {
+ case 'D':
+ if (strEQ(name + 1, "UPS_DATE_ANY")) { /* C removed */
+#ifdef CUPS_DATE_ANY
+ return CUPS_DATE_ANY;
+#else
+ goto not_there;
+#endif
+ }
+ case 'V':
+ if (strEQ(name + 1, "UPS_VERSION")) { /* C removed */
+#ifdef CUPS_VERSION
+ return CUPS_VERSION;
+#else
+ goto not_there;
+#endif
+ }
+ }
+ errno = EINVAL;
+ return 0;
+
+not_there:
+ errno = ENOENT;
+ return 0;
+}
+
+static double
+constant(char *name, int len, int arg)
+{
+ errno = 0;
+ switch (name[0 + 0]) {
+ case 'C':
+ return constant_C(name, len, arg);
+ case 'H':
+ return constant_H(name, len, arg);
+ case 'I':
+ return constant_I(name, len, arg);
+ case 'P':
+ return constant_P(name, len, arg);
+ }
+ errno = EINVAL;
+ return 0;
+
+not_there:
+ errno = ENOENT;
+ return 0;
+}
+
+
+MODULE = CUPS PACKAGE = CUPS
+
+
+double
+constant(sv,arg)
+ PREINIT:
+ STRLEN len;
+ INPUT:
+ SV * sv
+ char * s = SvPV(sv, len);
+ int arg
+ CODE:
+ RETVAL = constant(s,len,arg);
+ OUTPUT:
+ RETVAL
+
diff --git a/scripting/perl/Makefile.PL b/scripting/perl/Makefile.PL
new file mode 100644
index 000000000..f5e4bdd27
--- /dev/null
+++ b/scripting/perl/Makefile.PL
@@ -0,0 +1,17 @@
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ 'NAME' => 'CUPS',
+ 'VERSION_FROM' => 'CUPS.pm', # finds $VERSION
+ 'PREREQ_PM' => {}, # e.g., Module::Name => 1.1
+ ($] >= 5.005 ? ## Add these new keywords supported since 5.005
+ (ABSTRACT_FROM => 'CUPS.pm', # retrieve abstract from module
+ AUTHOR => 'A. U. Thor <a.u.thor@a.galaxy.far.far.away>') : ()),
+ 'LIBS' => ['-lcups '], # e.g., '-lm'
+ 'DEFINE' => '', # e.g., '-DHAVE_SOMETHING'
+ # Insert -I. if you add *.h files later:
+ 'INC' => '', # e.g., '-I/usr/include/other'
+ # Un-comment this if you add C files to link with later:
+ # 'OBJECT' => '$(O_FILES)', # link all the C files too
+);
diff --git a/scripting/perl/README b/scripting/perl/README
new file mode 100644
index 000000000..1605c7798
--- /dev/null
+++ b/scripting/perl/README
@@ -0,0 +1,35 @@
+CUPS version 1.2
+================
+
+The README is used to introduce the module and provide instructions on
+how to install the module, any machine dependencies it may have (for
+example C compilers and installed libraries) and any other information
+that should be provided before the module is installed.
+
+A README file is required for CPAN modules since CPAN extracts the
+README file from a module distribution so that people browsing the
+archive can use it get an idea of the modules uses. It is usually a
+good idea to provide version information here so that people can
+decide whether fixes for the module are worth downloading.
+
+INSTALLATION
+
+To install this module type the following:
+
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+ blah blah blah
+
+COPYRIGHT AND LICENCE
+
+Put the correct copyright and licence information here.
+
+Copyright (C) 2002 A. U. Thor blah blah blah
+
diff --git a/scripting/perl/test.pl b/scripting/perl/test.pl
new file mode 100644
index 000000000..acf31916b
--- /dev/null
+++ b/scripting/perl/test.pl
@@ -0,0 +1,17 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+#########################
+
+# change 'tests => 1' to 'tests => last_test_to_print';
+
+use Test;
+BEGIN { plan tests => 1 };
+use CUPS;
+ok(1); # If we made it this far, we're ok.
+
+#########################
+
+# Insert your test code below, the Test module is use()ed here so read
+# its man page ( perldoc Test ) for help writing this test script.
+
diff --git a/scripting/php/Dependencies b/scripting/php/Dependencies
new file mode 100644
index 000000000..d3c60c70f
--- /dev/null
+++ b/scripting/php/Dependencies
@@ -0,0 +1,7 @@
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+phpcups.o: ../../cups/string-private.h ../../config.h phpcups.h
+phpcups.o: ../../cups/cups.h ../../cups/file.h ../../cups/versioning.h
+phpcups.o: ../../cups/ipp.h ../../cups/http.h ../../cups/array.h
+phpcups.o: ../../cups/language.h ../../cups/language.h
+phpcups.o: ../../cups/debug-private.h
diff --git a/scripting/php/Makefile b/scripting/php/Makefile
new file mode 100644
index 000000000..79fb25e1d
--- /dev/null
+++ b/scripting/php/Makefile
@@ -0,0 +1,153 @@
+#
+# "$Id$"
+#
+# PHP Makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2007 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../../Makedefs
+
+
+#
+# Where to install and how to compile the PHP module...
+#
+
+PHPDIR = $(BUILDROOT)`$(PHPCONFIG) --extension-dir`
+OPTIONS = $(PHPOPTIONS)
+
+
+#
+# Object files...
+#
+
+OBJS = phpcups.o
+
+
+#
+# Targets in this directory...
+#
+
+PHPCUPS = phpcups.so
+
+
+#
+# Make all targets...
+#
+
+all: $(PHPCUPS)
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Remove object and target files...
+#
+
+clean:
+ $(RM) $(OBJS) $(PHPCUPS)
+
+
+#
+# Update dependencies (without system header dependencies...)
+#
+
+depend:
+ makedepend -Y -I../.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+
+
+#
+# Install programs...
+#
+
+install-exec:
+ echo Installing $(PHPCUPS) in $(PHPDIR)
+ $(INSTALL_DIR) $(PHPDIR)
+ $(INSTALL_LIB) $(PHPCUPS) $(PHPDIR)
+ if test "x$(SYMROOT)" != x; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ cp $(PHPCUPS) $(SYMROOT); \
+ fi
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall object and target files...
+#
+
+uninstall:
+ $(RM) $(PHPDIR)/$(PHPCUPS)
+ -$(RMDIR) $(PHPDIR)
+
+
+#
+# phpcups.so
+#
+
+phpcups.so: $(OBJS) ../../Makedefs
+ echo Linking $@...
+ if test `uname` = Darwin; then \
+ DSOFLAGS="-bundle -flat_namespace -undefined suppress $(RC_CFLAGS)"; \
+ else \
+ DSOFLAGS="$(DSOFLAGS)"; \
+ fi; \
+ echo $(DSO) $$DSOFLAGS $(ARCHFLAGS) -o $@ $(OBJS) -L../../cups $(LIBS); \
+ $(DSO) $$DSOFLAGS $(ARCHFLAGS) -o $@ $(OBJS) -L../../cups $(LIBS)
+
+
+#
+# Dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id$".
+#
diff --git a/scripting/php/README b/scripting/php/README
new file mode 100644
index 000000000..e4ab27d84
--- /dev/null
+++ b/scripting/php/README
@@ -0,0 +1,157 @@
+README - 02/25/2006
+-------------------
+
+INTRODUCTION
+
+ This directory contains a dynamically loadable CUPS extension
+ module for PHP 4 and 5. The CUPS 1.2 module has been
+ substantially updated to provide an API more consistent with
+ the C API and is NOT compatible with the CUPS 1.1 module.
+
+
+COMPILING AND INSTALLING
+
+ Run "make" to compile the PHP CUPS extension:
+
+ make
+
+ To install it, type:
+
+ make install
+
+
+RESOURCES AND SUPPORT
+
+ Questions should be reported to the CUPS newsgroups/mailing
+ lists at:
+
+ http://www.cups.org/newsgroups.php
+
+ Bug reports and enhancement requests can be submitted via the
+ form at:
+
+ http://www.cups.org/str.php
+
+
+QUICK REFERENCE DOCUMENTATION
+
+ In lieu of actual documentation, the following definitions
+ can be used as a quick reference to the supported functions:
+
+
+ CUPS_CANCEL_JOB
+
+ Cancels a job on the named destination:
+
+ bool cups_cancel_job(string dest, int id)
+
+ The return value is TRUE on success and FALSE on failure.
+
+ Example:
+
+ if (!cups_cancel_job("myprinter", 123))
+ print("Unable to cancel job: " . cups_last_error_string() . "\n");
+
+
+ CUPS_GET_DESTS
+
+ Gets a list of available destinations:
+
+ array cups_get_dests()
+
+ The return value is an array of objects with the following
+ properties:
+
+ name The name of the printer or class
+ instance The instance of the printer or class
+ is_default TRUE if the printer or class is the default destination
+ options Associative array of options and their values
+
+ Example:
+
+ $dest = cups_get_dests();
+
+
+ CUPS_GET_JOBS
+
+ Gets a list of jobs:
+
+ array cups_get_jobs(string dest, bool myjobs, int completed)
+
+ The "dest" string can be blank for jobs on all destinations.
+ Pass TRUE for "myjobs" to only get jobs for the current user.
+ The "completed" argument can be 0 for pending jobs, 1 for
+ completed jobs, and -1 for all jobs.
+
+ The return value is an array of objects with the following
+ properties:
+
+ id The job ID
+ dest Printer or class name
+ title Title/job name
+ user User the submitted the job
+ format Document format
+ state Job state
+ size Size in kilobytes
+ priority Priority (1-100)
+ completed_time Time the job was completed
+ creation_time Time the job was created
+ processing_time Time the job was processed
+
+ Example:
+
+ $jobs = cups_get_jobs("", FALSE, -1);
+
+
+ CUPS_LAST_ERROR
+
+ Returns the IPP status code for the most recent request:
+
+ int cups_last_error()
+
+ Example:
+
+ $error = cups_last_error();
+
+
+ CUPS_LAST_ERROR_STRING
+
+ Returns the IPP status-message string for the most recent request:
+
+ string cups_last_error_string()
+
+ Example:
+
+ $message = cups_last_error_string();
+
+
+ CUPS_PRINT_FILE
+
+ Prints a single file to a printer or class:
+
+ int cups_print_file(string dest, string filename, string title,
+ array options)
+
+ The return value is the job ID or 0 if there was an error.
+
+ Example:
+
+ $options = array("name" => "value", "name2" => "value2");
+ $id = cups_print_file("dest", "filename", "title", $options);
+
+
+ CUPS_PRINT_FILES
+
+ Prints one or more files to a printer or class:
+
+ int cups_print_files(string dest, array files, string title,
+ array options);
+
+ The return value is the job ID or 0 if there was an error.
+
+ Example:
+
+ $files = array("file1", "file2", "file3");
+ $options = array("name" => "value", "name2" => "value2");
+ $id = cups_print_file("dest", $files, "title", $options);
+
diff --git a/scripting/php/phpcups.c b/scripting/php/phpcups.c
new file mode 100644
index 000000000..563bd638f
--- /dev/null
+++ b/scripting/php/phpcups.c
@@ -0,0 +1,487 @@
+/*
+ * "$Id$"
+ *
+ * Printing utilities for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * cups_convert_options() - Convert a PHP options array to a CUPS options array.
+ * zm_startup_phpcups() - Initialize the CUPS module.
+ * zif_cups_cancel_job() - Cancel a job.
+ * zif_cups_get_dests() - Get a list of printers and classes.
+ * zif_cups_get_jobs() - Get a list of jobs.
+ * zif_cups_last_error() - Return the last IPP status code.
+ * zif_cups_last_error_string() - Return the last IPP status
+ * zif_cups_print_file() - Print a single file.
+ * zif_cups_print_files() - Print multiple files.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/string-private.h>
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "phpcups.h"
+
+
+/*
+ * PHP function list...
+ */
+
+function_entry phpcups_functions[] =
+{
+ PHP_FE(cups_cancel_job, NULL)
+ PHP_FE(cups_get_dests, NULL)
+ PHP_FE(cups_get_jobs, NULL)
+ PHP_FE(cups_last_error, NULL)
+ PHP_FE(cups_last_error_string, NULL)
+ PHP_FE(cups_print_file, NULL)
+ PHP_FE(cups_print_files, NULL)
+ {NULL, NULL, NULL}
+};
+
+
+/*
+ * PHP module info...
+ */
+
+zend_module_entry phpcups_module_entry =
+{
+ STANDARD_MODULE_HEADER,
+ "phpcups",
+ phpcups_functions,
+ PHP_MINIT(phpcups),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ CUPS_SVERSION,
+ STANDARD_MODULE_PROPERTIES
+};
+
+
+ZEND_GET_MODULE(phpcups)
+
+
+/*
+ * 'cups_convert_options()' - Convert a PHP options array to a CUPS options array.
+ */
+
+static int /* O - Number of options */
+cups_convert_options(
+ zval *optionsobj, /* I - Options array object */
+ cups_option_t **options) /* O - Options */
+{
+ int num_options; /* Number of options */
+ HashTable *ht; /* Option array hash table */
+ Bucket *current; /* Current element in array */
+ zval *value; /* Current value in array */
+ char temp[255]; /* String value for numbers */
+
+
+ ht = Z_ARRVAL_P(optionsobj);
+ num_options = 0;
+
+ for (current = ht->pListHead; current; current = current->pListNext)
+ {
+ value = (zval *)current->pDataPtr;
+
+ switch (Z_TYPE_P(value))
+ {
+ case IS_LONG :
+ sprintf(temp, "%ld", Z_LVAL_P(value));
+ num_options = cupsAddOption(current->arKey, temp, num_options,
+ options);
+ break;
+
+ case IS_DOUBLE :
+ sprintf(temp, "%g", Z_DVAL_P(value));
+ num_options = cupsAddOption(current->arKey, temp, num_options,
+ options);
+ break;
+
+ case IS_BOOL :
+ num_options = cupsAddOption(current->arKey,
+ Z_BVAL_P(value) ? "true" : "false",
+ num_options, options);
+ break;
+
+ case IS_STRING :
+ num_options = cupsAddOption(current->arKey, Z_STRVAL_P(value),
+ num_options, options);
+ break;
+ }
+ }
+
+ return (num_options);
+}
+
+
+/*
+ * 'zm_startup_phpcups()' - Initialize the CUPS module.
+ */
+
+PHP_MINIT_FUNCTION(phpcups)
+{
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_LOCAL", CUPS_PRINTER_LOCAL, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_CLASS", CUPS_PRINTER_CLASS, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_REMOTE", CUPS_PRINTER_REMOTE, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_BW", CUPS_PRINTER_BW, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_COLOR", CUPS_PRINTER_COLOR, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_DUPLEX", CUPS_PRINTER_DUPLEX, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_STAPLE", CUPS_PRINTER_STAPLE, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_COPIES", CUPS_PRINTER_COPIES, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_COLLATE", CUPS_PRINTER_COLLATE, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_PUNCH", CUPS_PRINTER_PUNCH, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_COVER", CUPS_PRINTER_COVER, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_BIND", CUPS_PRINTER_BIND, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_SORT", CUPS_PRINTER_SORT, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_SMALL", CUPS_PRINTER_SMALL, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_MEDIUM", CUPS_PRINTER_MEDIUM, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_LARGE", CUPS_PRINTER_LARGE, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_VARIABLE", CUPS_PRINTER_VARIABLE, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_IMPLICIT", CUPS_PRINTER_IMPLICIT, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_DEFAULT", CUPS_PRINTER_DEFAULT, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_FAX", CUPS_PRINTER_FAX, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_REJECTING", CUPS_PRINTER_REJECTING, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_DELETE", CUPS_PRINTER_DELETE, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_NOT_SHARED", CUPS_PRINTER_NOT_SHARED, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_AUTHENTICATED", CUPS_PRINTER_AUTHENTICATED, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_COMMANDS", CUPS_PRINTER_COMMANDS, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_DISCOVERED", CUPS_PRINTER_DISCOVERED, CONST_CS);
+ REGISTER_LONG_CONSTANT("CUPS_PRINTER_OPTIONS", CUPS_PRINTER_OPTIONS, CONST_CS);
+
+ REGISTER_LONG_CONSTANT("IPP_OK", IPP_OK, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_OK_SUBST", IPP_OK_SUBST, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_OK_CONFLICT", IPP_OK_CONFLICT, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_OK_IGNORED_SUBSCRIPTIONS", IPP_OK_IGNORED_SUBSCRIPTIONS, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_OK_IGNORED_NOTIFICATIONS", IPP_OK_IGNORED_NOTIFICATIONS, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_OK_TOO_MANY_EVENTS", IPP_OK_TOO_MANY_EVENTS, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_OK_BUT_CANCEL_SUBSCRIPTION", IPP_OK_BUT_CANCEL_SUBSCRIPTION, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_OK_EVENTS_COMPLETE", IPP_OK_EVENTS_COMPLETE, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_REDIRECTION_OTHER_SITE", IPP_REDIRECTION_OTHER_SITE, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_BAD_REQUEST", IPP_BAD_REQUEST, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_FORBIDDEN", IPP_FORBIDDEN, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_NOT_AUTHENTICATED", IPP_NOT_AUTHENTICATED, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_NOT_AUTHORIZED", IPP_NOT_AUTHORIZED, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_NOT_POSSIBLE", IPP_NOT_POSSIBLE, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_TIMEOUT", IPP_TIMEOUT, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_NOT_FOUND", IPP_NOT_FOUND, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_GONE", IPP_GONE, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_REQUEST_ENTITY", IPP_REQUEST_ENTITY, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_REQUEST_VALUE", IPP_REQUEST_VALUE, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_DOCUMENT_FORMAT", IPP_DOCUMENT_FORMAT, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_ATTRIBUTES", IPP_ATTRIBUTES, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_URI_SCHEME", IPP_URI_SCHEME, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_CHARSET", IPP_CHARSET, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_CONFLICT", IPP_CONFLICT, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_COMPRESSION_NOT_SUPPORTED", IPP_COMPRESSION_NOT_SUPPORTED, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_COMPRESSION_ERROR", IPP_COMPRESSION_ERROR, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_DOCUMENT_FORMAT_ERROR", IPP_DOCUMENT_FORMAT_ERROR, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_DOCUMENT_ACCESS_ERROR", IPP_DOCUMENT_ACCESS_ERROR, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_ATTRIBUTES_NOT_SETTABLE", IPP_ATTRIBUTES_NOT_SETTABLE, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_IGNORED_ALL_SUBSCRIPTIONS", IPP_IGNORED_ALL_SUBSCRIPTIONS, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_TOO_MANY_SUBSCRIPTIONS", IPP_TOO_MANY_SUBSCRIPTIONS, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_IGNORED_ALL_NOTIFICATIONS", IPP_IGNORED_ALL_NOTIFICATIONS, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_PRINT_SUPPORT_FILE_NOT_FOUND", IPP_PRINT_SUPPORT_FILE_NOT_FOUND, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_INTERNAL_ERROR", IPP_INTERNAL_ERROR, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_OPERATION_NOT_SUPPORTED", IPP_OPERATION_NOT_SUPPORTED, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_SERVICE_UNAVAILABLE", IPP_SERVICE_UNAVAILABLE, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_VERSION_NOT_SUPPORTED", IPP_VERSION_NOT_SUPPORTED, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_DEVICE_ERROR", IPP_DEVICE_ERROR, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_TEMPORARY_ERROR", IPP_TEMPORARY_ERROR, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_NOT_ACCEPTING", IPP_NOT_ACCEPTING, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_PRINTER_BUSY", IPP_PRINTER_BUSY, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_ERROR_JOB_CANCELLED", IPP_ERROR_JOB_CANCELLED, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_MULTIPLE_JOBS_NOT_SUPPORTED", IPP_MULTIPLE_JOBS_NOT_SUPPORTED, CONST_CS);
+ REGISTER_LONG_CONSTANT("IPP_PRINTER_IS_DEACTIVATED", IPP_PRINTER_IS_DEACTIVATED, CONST_CS);
+
+ return (SUCCESS);
+}
+
+/*
+ * 'zif_cups_cancel_job()' - Cancel a job.
+ */
+
+PHP_FUNCTION(cups_cancel_job)
+{
+ char *dest; /* Destination */
+ int dest_len, /* Length of destination */
+ id; /* Job ID */
+
+
+ if (ZEND_NUM_ARGS() != 2 ||
+ zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &dest, &dest_len, &id))
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ RETURN_LONG(cupsCancelJob(dest, id));
+}
+
+
+/*
+ * 'zif_cups_get_dests()' - Get a list of printers and classes.
+ */
+
+PHP_FUNCTION(cups_get_dests)
+{
+ int i, j, /* Looping vars */
+ num_dests; /* Number of destinations */
+ cups_dest_t *dests, /* Destinations */
+ *dest; /* Current destination */
+ cups_option_t *option; /* Current option */
+ zval *destobj, /* Destination object */
+ *optionsobj; /* Options object */
+
+
+ if (ZEND_NUM_ARGS() != 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ if ((num_dests = cupsGetDests(&dests)) <= 0)
+ {
+ RETURN_NULL();
+ }
+
+ if (array_init(return_value) == SUCCESS)
+ {
+ for (i = 0, dest = dests; i < num_dests; i ++, dest ++)
+ {
+ MAKE_STD_ZVAL(destobj);
+
+ if (object_init(destobj) == SUCCESS)
+ {
+ /*
+ * Add properties to the destination for each of the cups_dest_t
+ * members...
+ */
+
+ add_property_string(destobj, "name", dest->name, 1);
+ add_property_string(destobj, "instance",
+ dest->instance ? dest->instance : "", 1);
+ add_property_long(destobj, "is_default", dest->is_default);
+
+ /*
+ * Create an associative array for the options...
+ */
+
+ MAKE_STD_ZVAL(optionsobj);
+
+ if (array_init(optionsobj) == SUCCESS)
+ {
+ for (j = 0, option = dest->options;
+ j < dest->num_options;
+ j ++, option ++)
+ add_assoc_string(optionsobj, option->name, option->value, 1);
+
+ add_property_zval(destobj, "options", optionsobj);
+ }
+
+ add_index_zval(return_value, i, destobj);
+ }
+ }
+ }
+
+ cupsFreeDests(num_dests, dests);
+}
+
+
+/*
+ * 'zif_cups_get_jobs()' - Get a list of jobs.
+ */
+
+PHP_FUNCTION(cups_get_jobs)
+{
+ char *dest; /* Destination */
+ int dest_len, /* Length of destination */
+ myjobs, /* Only show my jobs? */
+ completed; /* Show completed jobs? */
+ int i, /* Looping var */
+ num_jobs; /* Number of jobs */
+ cups_job_t *jobs, /* Jobs */
+ *job; /* Current job */
+ zval *jobobj; /* Job object */
+
+
+
+
+ if (ZEND_NUM_ARGS() != 3 ||
+ zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sll", &dest, &dest_len, &myjobs, &completed))
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ if (!*dest)
+ dest = NULL;
+
+ if ((num_jobs = cupsGetJobs(&jobs, dest, myjobs, completed)) <= 0)
+ {
+ RETURN_NULL();
+ }
+
+ if (array_init(return_value) == SUCCESS)
+ {
+ for (i = 0, job = jobs; i < num_jobs; i ++, job ++)
+ {
+ MAKE_STD_ZVAL(jobobj);
+
+ if (object_init(jobobj) == SUCCESS)
+ {
+ /*
+ * Add properties to the job for each of the cups_job_t
+ * members...
+ */
+
+ add_property_long(jobobj, "id", job->id);
+ add_property_string(jobobj, "dest", job->dest, 1);
+ add_property_string(jobobj, "title", job->title, 1);
+ add_property_string(jobobj, "user", job->user, 1);
+ add_property_string(jobobj, "format", job->format, 1);
+ add_property_long(jobobj, "state", job->state);
+ add_property_long(jobobj, "size", job->size);
+ add_property_long(jobobj, "priority", job->priority);
+ add_property_long(jobobj, "completed_time", job->completed_time);
+ add_property_long(jobobj, "creation_time", job->creation_time);
+ add_property_long(jobobj, "processing_time", job->processing_time);
+
+ add_index_zval(return_value, i, jobobj);
+ }
+ }
+ }
+
+ cupsFreeJobs(num_jobs, jobs);
+}
+
+
+/*
+ * 'zif_cups_last_error()' - Return the last IPP status code.
+ */
+
+PHP_FUNCTION(cups_last_error)
+{
+ if (ZEND_NUM_ARGS() != 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ RETURN_LONG(cupsLastError());
+}
+
+
+/*
+ * 'zif_cups_last_error_string()' - Return the last IPP status-message.
+ */
+
+PHP_FUNCTION(cups_last_error_string)
+{
+ if (ZEND_NUM_ARGS() != 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ RETURN_STRING((char *)cupsLastErrorString(), 1);
+}
+
+
+/*
+ * 'zif_cups_print_file()' - Print a single file.
+ */
+
+PHP_FUNCTION(cups_print_file)
+{
+ char *dest; /* Destination */
+ int dest_len; /* Length of destination */
+ char *filename; /* Filename */
+ int filename_len; /* Length of filename */
+ char *title; /* Title */
+ int title_len; /* Length of title */
+ zval *optionsobj; /* Array of options */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ int id; /* Job ID */
+
+
+ if (ZEND_NUM_ARGS() != 4 ||
+ zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sssa", &dest, &dest_len,
+ &filename, &filename_len,
+ &title, &title_len, &optionsobj))
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ num_options = cups_convert_options(optionsobj, &options);
+
+ id = cupsPrintFile(dest, filename, title, num_options, options);
+
+ cupsFreeOptions(num_options, options);
+
+ RETURN_LONG(id);
+}
+
+
+/*
+ * 'zif_cups_print_files()' - Print multiple files.
+ */
+
+PHP_FUNCTION(cups_print_files)
+{
+ char *dest; /* Destination */
+ int dest_len; /* Length of destination */
+ zval *filesobj; /* Files array */
+ int num_files; /* Number of files */
+ const char *files[1000]; /* Files */
+ char *title; /* Title */
+ int title_len; /* Length of title */
+ zval *optionsobj; /* Array of options */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ HashTable *ht2; /* Option array hash table */
+ Bucket *current; /* Current element in array */
+ int id; /* Job ID */
+
+
+ if (ZEND_NUM_ARGS() != 4 ||
+ zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sasa", &dest, &dest_len, &filesobj,
+ &title, &title_len, &optionsobj))
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ ht2 = Z_ARRVAL_P(filesobj);
+ num_files = 0;
+
+ for (current = ht2->pListHead; current; current = current->pListNext)
+ {
+ files[num_files ++] = Z_STRVAL_P(((zval *)current->pDataPtr));
+
+ if (num_files >= (int)(sizeof(files) / sizeof(files[0])))
+ break;
+ }
+
+ num_options = cups_convert_options(optionsobj, &options);
+
+ id = cupsPrintFiles(dest, num_files, files, title, num_options, options);
+
+ cupsFreeOptions(num_options, options);
+
+ RETURN_LONG(id);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scripting/php/phpcups.h b/scripting/php/phpcups.h
new file mode 100644
index 000000000..e4cefaed8
--- /dev/null
+++ b/scripting/php/phpcups.h
@@ -0,0 +1,67 @@
+/*
+ * "$Id$"
+ *
+ * PHP module include file for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef PHPCUPS_H
+# define PHPCUPS_H
+
+/*
+ * Include necessary headers...
+ */
+
+# include <cups/cups.h>
+# include <cups/language.h>
+# include <cups/debug-private.h>
+# include <fcntl.h>
+# include <sys/stat.h>
+# if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+# else
+# include <unistd.h>
+# endif /* WIN32 || __EMX__ */
+
+
+/*
+ * Zend definitions...
+ */
+
+extern zend_module_entry phpcups_module_entry;
+# define phpext_phpcups_ptr &phpcups_module_entry
+
+# ifdef PHP_WIN32
+# define PHP_PHPCUPS_API __declspec(dllexport)
+# else
+# define PHP_PHPCUPS_API
+# endif
+
+# ifdef ZTS
+# include "TSRM.h"
+# endif
+
+PHP_MINIT_FUNCTION(phpcups);
+
+PHP_FUNCTION(cups_cancel_job);
+PHP_FUNCTION(cups_get_dests);
+PHP_FUNCTION(cups_get_jobs);
+PHP_FUNCTION(cups_last_error);
+PHP_FUNCTION(cups_last_error_string);
+PHP_FUNCTION(cups_print_file);
+PHP_FUNCTION(cups_print_files);
+
+#endif /* !PHPCUPS_H */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scripting/php/phpcups.php b/scripting/php/phpcups.php
new file mode 100755
index 000000000..0fe57190e
--- /dev/null
+++ b/scripting/php/phpcups.php
@@ -0,0 +1,60 @@
+#!/usr/bin/php -f
+<?
+//
+// "$Id: phpcups.php 3603 2003-04-11 18:42:52Z mike $"
+//
+// PHP test script for CUPS.
+//
+// Copyright 2007-2011 by Apple Inc.
+// Copyright 1997-2006 by Easy Software Products, all rights reserved.
+//
+// These coded instructions, statements, and computer programs are the
+// property of Apple Inc. 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
+// file is missing or damaged, see the license at "http://www.cups.org/".
+//
+
+// Make sure the module is loaded...
+if(!extension_loaded("phpcups"))
+{
+ dl("phpcups.so");
+}
+
+// Get the list of functions in the module...
+$module = "phpcups";
+$functions = get_extension_funcs($module);
+
+print("Functions available in the $module extension:\n");
+
+foreach ($functions as $func)
+{
+ print("$func\n");
+}
+
+print("\n");
+
+print("cups_get_dests:\n");
+print_r(cups_get_dests());
+
+print("cups_get_jobs(\"\", 0, -1):\n");
+print_r(cups_get_jobs("", 0, -1));
+
+print("cups_print_file(\"test\", \"../../test/testfile.jpg\", "
+ ."\"testfile.jpg\", ...):\n");
+print_r(cups_print_file("test", "../../test/testfile.jpg", "testfile.jpg",
+ array("scaling" => "100",
+ "page-label" => "testfile.jpg")));
+
+print("cups_print_files(\"test\", array(\"../../test/testfile.jpg\", "
+ ."\"../../test/testfile.ps\"), \"testfiles\", ...):\n");
+print_r(cups_print_files("test", array("../../test/testfile.jpg",
+ "../../test/testfile.ps"),
+ "testfiles",
+ array("scaling" => "100",
+ "page-label" => "testfile.jpg")));
+
+//
+// End of "$Id: phpcups.php 3603 2003-04-11 18:42:52Z mike $".
+//
+?>
diff --git a/standards/Makefile b/standards/Makefile
new file mode 100644
index 000000000..553eae138
--- /dev/null
+++ b/standards/Makefile
@@ -0,0 +1,163 @@
+#
+# "$Id$"
+#
+# Standards makefile for CUPS.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 2006 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+
+#
+# Standards...
+#
+
+RFCS = \
+ rfc1155.txt \
+ rfc1157.txt \
+ rfc1179.txt \
+ rfc1213.txt \
+ rfc1321.txt \
+ rfc2222.txt \
+ rfc2246.txt \
+ rfc2487.txt \
+ rfc2554.txt \
+ rfc2567.txt \
+ rfc2568.txt \
+ rfc2569.txt \
+ rfc2578.txt \
+ rfc2595.txt \
+ rfc2616.txt \
+ rfc2617.txt \
+ rfc2712.txt \
+ rfc2790.txt \
+ rfc2817.txt \
+ rfc2818.txt \
+ rfc2821.txt \
+ rfc2822.txt \
+ rfc2910.txt \
+ rfc2911.txt \
+ rfc2965.txt \
+ rfc3196.txt \
+ rfc3239.txt \
+ rfc3380.txt \
+ rfc3381.txt \
+ rfc3382.txt \
+ rfc3391.txt \
+ rfc3510.txt \
+ rfc3712.txt \
+ rfc3805.txt \
+ rfc3875.txt \
+ rfc3986.txt \
+ rfc3995.txt \
+ rfc3996.txt \
+ rfc3997.txt \
+ rfc3998.txt \
+ rfc4122.txt \
+ rfc4234.txt
+
+.SUFFIXES: .html .txt
+.txt.html: rfctohtml
+ echo Converting $< to HTML...
+ ./rfctohtml $< ../doc/help/$@
+
+
+#
+# Make everything...
+#
+
+all: rfctohtml $(RFCS:.txt=.html)
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Clean all config and object files...
+#
+
+clean:
+ $(RM) rfctohtml rfctohtml.o
+ $(RM) $(RFCS:.txt=.html)
+
+
+#
+# Dummy depend target...
+#
+
+depend:
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+
+
+#
+# Install programs...
+#
+
+install-exec:
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall files...
+#
+
+uninstall:
+
+
+#
+# rfctohtml - make html versions of RFCs...
+#
+
+rfctohtml: rfctohtml.o ../cups/$(LIBCUPSSTATIC)
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ rfctohtml.o ../cups/$(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# End of "$Id$".
+#
diff --git a/standards/X.690-0207.pdf b/standards/X.690-0207.pdf
new file mode 100644
index 000000000..8f88864a3
--- /dev/null
+++ b/standards/X.690-0207.pdf
Binary files differ
diff --git a/standards/cs-ipp20-20090731-5100.10.pdf b/standards/cs-ipp20-20090731-5100.10.pdf
new file mode 100644
index 000000000..1623ccb12
--- /dev/null
+++ b/standards/cs-ipp20-20090731-5100.10.pdf
Binary files differ
diff --git a/standards/cs-ippstate10-20090731-5100.9.pdf b/standards/cs-ippstate10-20090731-5100.9.pdf
new file mode 100644
index 000000000..3c3c5252c
--- /dev/null
+++ b/standards/cs-ippstate10-20090731-5100.9.pdf
Binary files differ
diff --git a/standards/papi-1.0.pdf b/standards/papi-1.0.pdf
new file mode 100644
index 000000000..bea5be817
--- /dev/null
+++ b/standards/papi-1.0.pdf
Binary files differ
diff --git a/standards/pwg5100.1.pdf b/standards/pwg5100.1.pdf
new file mode 100644
index 000000000..80260170f
--- /dev/null
+++ b/standards/pwg5100.1.pdf
Binary files differ
diff --git a/standards/pwg5100.2.pdf b/standards/pwg5100.2.pdf
new file mode 100644
index 000000000..6b0ad3abc
--- /dev/null
+++ b/standards/pwg5100.2.pdf
Binary files differ
diff --git a/standards/pwg5100.3.pdf b/standards/pwg5100.3.pdf
new file mode 100644
index 000000000..0ac46446f
--- /dev/null
+++ b/standards/pwg5100.3.pdf
Binary files differ
diff --git a/standards/pwg5100.5.pdf b/standards/pwg5100.5.pdf
new file mode 100644
index 000000000..536270768
--- /dev/null
+++ b/standards/pwg5100.5.pdf
Binary files differ
diff --git a/standards/pwg5100.6.pdf b/standards/pwg5100.6.pdf
new file mode 100644
index 000000000..0da4c21d4
--- /dev/null
+++ b/standards/pwg5100.6.pdf
Binary files differ
diff --git a/standards/pwg5100.7.pdf b/standards/pwg5100.7.pdf
new file mode 100644
index 000000000..174ba189b
--- /dev/null
+++ b/standards/pwg5100.7.pdf
Binary files differ
diff --git a/standards/pwg5100.8.pdf b/standards/pwg5100.8.pdf
new file mode 100644
index 000000000..e5dd9bf92
--- /dev/null
+++ b/standards/pwg5100.8.pdf
Binary files differ
diff --git a/standards/pwg5101.1.pdf b/standards/pwg5101.1.pdf
new file mode 100644
index 000000000..72354a595
--- /dev/null
+++ b/standards/pwg5101.1.pdf
Binary files differ
diff --git a/standards/pwg5105.1.pdf b/standards/pwg5105.1.pdf
new file mode 100644
index 000000000..ace68c9fe
--- /dev/null
+++ b/standards/pwg5105.1.pdf
Binary files differ
diff --git a/standards/pwg5107.1.pdf b/standards/pwg5107.1.pdf
new file mode 100644
index 000000000..018ce9c35
--- /dev/null
+++ b/standards/pwg5107.1.pdf
Binary files differ
diff --git a/standards/rfc1155.txt b/standards/rfc1155.txt
new file mode 100644
index 000000000..0e0f1b540
--- /dev/null
+++ b/standards/rfc1155.txt
@@ -0,0 +1,1235 @@
+
+
+
+
+
+
+Network Working Group M. Rose
+Request for Comments: 1155 Performance Systems International
+Obsoletes: RFC 1065 K. McCloghrie
+ Hughes LAN Systems
+ May 1990
+
+
+
+ Structure and Identification of Management Information
+ for TCP/IP-based Internets
+
+ Table of Contents
+
+1. Status of this Memo ............................................. 1
+2. Introduction .................................................... 2
+3. Structure and Identification of Management Information........... 4
+3.1 Names .......................................................... 4
+3.1.1 Directory .................................................... 5
+3.1.2 Mgmt ......................................................... 6
+3.1.3 Experimental ................................................. 6
+3.1.4 Private ...................................................... 7
+3.2 Syntax ......................................................... 7
+3.2.1 Primitive Types .............................................. 7
+3.2.1.1 Guidelines for Enumerated INTEGERs ......................... 7
+3.2.2 Constructor Types ............................................ 8
+3.2.3 Defined Types ................................................ 8
+3.2.3.1 NetworkAddress ............................................. 8
+3.2.3.2 IpAddress .................................................. 8
+3.2.3.3 Counter .................................................... 8
+3.2.3.4 Gauge ...................................................... 9
+3.2.3.5 TimeTicks .................................................. 9
+3.2.3.6 Opaque ..................................................... 9
+3.3 Encodings ...................................................... 9
+4. Managed Objects ................................................. 10
+4.1 Guidelines for Object Names .................................... 10
+4.2 Object Types and Instances ..................................... 10
+4.3 Macros for Managed Objects ..................................... 14
+5. Extensions to the MIB ........................................... 16
+6. Definitions ..................................................... 17
+7. Acknowledgements ................................................ 20
+8. References ...................................................... 21
+9. Security Considerations.......................................... 21
+10. Authors' Addresses.............................................. 22
+
+1. Status of this Memo
+
+ This RFC is a re-release of RFC 1065, with a changed "Status of this
+ Memo", plus a few minor typographical corrections. The technical
+
+
+
+Rose & McCloghrie [Page 1]
+
+RFC 1155 SMI May 1990
+
+
+ content of the document is unchanged from RFC 1065.
+
+ This memo provides the common definitions for the structure and
+ identification of management information for TCP/IP-based internets.
+ In particular, together with its companion memos which describe the
+ management information base along with the network management
+ protocol, these documents provide a simple, workable architecture and
+ system for managing TCP/IP-based internets and in particular, the
+ Internet.
+
+ This memo specifies a Standard Protocol for the Internet community.
+ Its status is "Recommended". TCP/IP implementations in the Internet
+ which are network manageable are expected to adopt and implement this
+ specification.
+
+ The Internet Activities Board recommends that all IP and TCP
+ implementations be network manageable. This implies implementation
+ of the Internet MIB (RFC-1156) and at least one of the two
+ recommended management protocols SNMP (RFC-1157) or CMOT (RFC-1095).
+ It should be noted that, at this time, SNMP is a full Internet
+ standard and CMOT is a draft standard. See also the Host and Gateway
+ Requirements RFCs for more specific information on the applicability
+ of this standard.
+
+ Please refer to the latest edition of the "IAB Official Protocol
+ Standards" RFC for current information on the state and status of
+ standard Internet protocols.
+
+ Distribution of this memo is unlimited.
+
+2. Introduction
+
+ This memo describes the common structures and identification scheme
+ for the definition of management information used in managing
+ TCP/IP-based internets. Included are descriptions of an object
+ information model for network management along with a set of generic
+ types used to describe management information. Formal descriptions
+ of the structure are given using Abstract Syntax Notation One (ASN.1)
+ [1].
+
+ This memo is largely concerned with organizational concerns and
+ administrative policy: it neither specifies the objects which are
+ managed, nor the protocols used to manage those objects. These
+ concerns are addressed by two companion memos: one describing the
+ Management Information Base (MIB) [2], and the other describing the
+ Simple Network Management Protocol (SNMP) [3].
+
+ This memo is based in part on the work of the Internet Engineering
+
+
+
+Rose & McCloghrie [Page 2]
+
+RFC 1155 SMI May 1990
+
+
+ Task Force, particularly the working note titled "Structure and
+ Identification of Management Information for the Internet" [4]. This
+ memo uses a skeletal structure derived from that note, but differs in
+ one very significant way: that note focuses entirely on the use of
+ OSI-style network management. As such, it is not suitable for use
+ with SNMP.
+
+ This memo attempts to achieve two goals: simplicity and
+ extensibility. Both are motivated by a common concern: although the
+ management of TCP/IP-based internets has been a topic of study for
+ some time, the authors do not feel that the depth and breadth of such
+ understanding is complete. More bluntly, we feel that previous
+ experiences, while giving the community insight, are hardly
+ conclusive. By fostering a simple SMI, the minimal number of
+ constraints are imposed on future potential approaches; further, by
+ fostering an extensible SMI, the maximal number of potential
+ approaches are available for experimentation.
+
+ It is believed that this memo and its two companions comply with the
+ guidelines set forth in RFC 1052, "IAB Recommendations for the
+ Development of Internet Network Management Standards" [5] and RFC
+ 1109, "Report of the Second Ad Hoc Network Management Review Group"
+ [6]. In particular, we feel that this memo, along with the memo
+ describing the management information base, provide a solid basis for
+ network management of the Internet.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rose & McCloghrie [Page 3]
+
+RFC 1155 SMI May 1990
+
+
+3. Structure and Identification of Management Information
+
+ Managed objects are accessed via a virtual information store, termed
+ the Management Information Base or MIB. Objects in the MIB are
+ defined using Abstract Syntax Notation One (ASN.1) [1].
+
+ Each type of object (termed an object type) has a name, a syntax, and
+ an encoding. The name is represented uniquely as an OBJECT
+ IDENTIFIER. An OBJECT IDENTIFIER is an administratively assigned
+ name. The administrative policies used for assigning names are
+ discussed later in this memo.
+
+ The syntax for an object type defines the abstract data structure
+ corresponding to that object type. For example, the structure of a
+ given object type might be an INTEGER or OCTET STRING. Although in
+ general, we should permit any ASN.1 construct to be available for use
+ in defining the syntax of an object type, this memo purposely
+ restricts the ASN.1 constructs which may be used. These restrictions
+ are made solely for the sake of simplicity.
+
+ The encoding of an object type is simply how instances of that object
+ type are represented using the object's type syntax. Implicitly tied
+ to the notion of an object's syntax and encoding is how the object is
+ represented when being transmitted on the network. This memo
+ specifies the use of the basic encoding rules of ASN.1 [7].
+
+ It is beyond the scope of this memo to define either the MIB used for
+ network management or the network management protocol. As mentioned
+ earlier, these tasks are left to companion memos. This memo attempts
+ to minimize the restrictions placed upon its companions so as to
+ maximize generality. However, in some cases, restrictions have been
+ made (e.g., the syntax which may be used when defining object types
+ in the MIB) in order to encourage a particular style of management.
+ Future editions of this memo may remove these restrictions.
+
+3.1. Names
+
+ Names are used to identify managed objects. This memo specifies
+ names which are hierarchical in nature. The OBJECT IDENTIFIER
+ concept is used to model this notion. An OBJECT IDENTIFIER can be
+ used for purposes other than naming managed object types; for
+ example, each international standard has an OBJECT IDENTIFIER
+ assigned to it for the purposes of identification. In short, OBJECT
+ IDENTIFIERs are a means for identifying some object, regardless of
+ the semantics associated with the object (e.g., a network object, a
+ standards document, etc.)
+
+ An OBJECT IDENTIFIER is a sequence of integers which traverse a
+
+
+
+Rose & McCloghrie [Page 4]
+
+RFC 1155 SMI May 1990
+
+
+ global tree. The tree consists of a root connected to a number of
+ labeled nodes via edges. Each node may, in turn, have children of
+ its own which are labeled. In this case, we may term the node a
+ subtree. This process may continue to an arbitrary level of depth.
+ Central to the notion of the OBJECT IDENTIFIER is the understanding
+ that administrative control of the meanings assigned to the nodes may
+ be delegated as one traverses the tree. A label is a pairing of a
+ brief textual description and an integer.
+
+ The root node itself is unlabeled, but has at least three children
+ directly under it: one node is administered by the International
+ Organization for Standardization, with label iso(1); another is
+ administrated by the International Telegraph and Telephone
+ Consultative Committee, with label ccitt(0); and the third is jointly
+ administered by the ISO and the CCITT, joint-iso-ccitt(2).
+
+ Under the iso(1) node, the ISO has designated one subtree for use by
+ other (inter)national organizations, org(3). Of the children nodes
+ present, two have been assigned to the U.S. National Institutes of
+ Standards and Technology. One of these subtrees has been transferred
+ by the NIST to the U.S. Department of Defense, dod(6).
+
+ As of this writing, the DoD has not indicated how it will manage its
+ subtree of OBJECT IDENTIFIERs. This memo assumes that DoD will
+ allocate a node to the Internet community, to be administered by the
+ Internet Activities Board (IAB) as follows:
+
+ internet OBJECT IDENTIFIER ::= { iso org(3) dod(6) 1 }
+
+ That is, the Internet subtree of OBJECT IDENTIFIERs starts with the
+ prefix:
+
+ 1.3.6.1.
+
+ This memo, as a standard approved by the IAB, now specifies the
+ policy under which this subtree of OBJECT IDENTIFIERs is
+ administered. Initially, four nodes are present:
+
+ directory OBJECT IDENTIFIER ::= { internet 1 }
+ mgmt OBJECT IDENTIFIER ::= { internet 2 }
+ experimental OBJECT IDENTIFIER ::= { internet 3 }
+ private OBJECT IDENTIFIER ::= { internet 4 }
+
+3.1.1. Directory
+
+ The directory(1) subtree is reserved for use with a future memo that
+ discusses how the OSI Directory may be used in the Internet.
+
+
+
+
+Rose & McCloghrie [Page 5]
+
+RFC 1155 SMI May 1990
+
+
+3.1.2. Mgmt
+
+ The mgmt(2) subtree is used to identify objects which are defined in
+ IAB-approved documents. Administration of the mgmt(2) subtree is
+ delegated by the IAB to the Internet Assigned Numbers Authority for
+ the Internet. As RFCs which define new versions of the Internet-
+ standard Management Information Base are approved, they are assigned
+ an OBJECT IDENTIFIER by the Internet Assigned Numbers Authority for
+ identifying the objects defined by that memo.
+
+ For example, the RFC which defines the initial Internet standard MIB
+ would be assigned management document number 1. This RFC would use
+ the OBJECT IDENTIFIER
+
+ { mgmt 1 }
+
+ or
+
+ 1.3.6.1.2.1
+
+ in defining the Internet-standard MIB.
+
+ The generation of new versions of the Internet-standard MIB is a
+ rigorous process. Section 5 of this memo describes the rules used
+ when a new version is defined.
+
+3.1.3. Experimental
+
+ The experimental(3) subtree is used to identify objects used in
+ Internet experiments. Administration of the experimental(3) subtree
+ is delegated by the IAB to the Internet Assigned Numbers Authority of
+ the Internet.
+
+ For example, an experimenter might received number 17, and would have
+ available the OBJECT IDENTIFIER
+
+ { experimental 17 }
+
+ or
+
+ 1.3.6.1.3.17
+
+ for use.
+
+ As a part of the assignment process, the Internet Assigned Numbers
+ Authority may make requirements as to how that subtree is used.
+
+
+
+
+
+Rose & McCloghrie [Page 6]
+
+RFC 1155 SMI May 1990
+
+
+3.1.4. Private
+
+ The private(4) subtree is used to identify objects defined
+ unilaterally. Administration of the private(4) subtree is delegated
+ by the IAB to the Internet Assigned Numbers Authority for the
+ Internet. Initially, this subtree has at least one child:
+
+ enterprises OBJECT IDENTIFIER ::= { private 1 }
+
+ The enterprises(1) subtree is used, among other things, to permit
+ parties providing networking subsystems to register models of their
+ products.
+
+ Upon receiving a subtree, the enterprise may, for example, define new
+ MIB objects in this subtree. In addition, it is strongly recommended
+ that the enterprise will also register its networking subsystems
+ under this subtree, in order to provide an unambiguous identification
+ mechanism for use in management protocols. For example, if the
+ "Flintstones, Inc." enterprise produced networking subsystems, then
+ they could request a node under the enterprises subtree from the
+ Internet Assigned Numbers Authority. Such a node might be numbered:
+
+ 1.3.6.1.4.1.42
+
+ The "Flintstones, Inc." enterprise might then register their "Fred
+ Router" under the name of:
+
+ 1.3.6.1.4.1.42.1.1
+
+3.2. Syntax
+
+ Syntax is used to define the structure corresponding to object types.
+ ASN.1 constructs are used to define this structure, although the full
+ generality of ASN.1 is not permitted.
+
+ The ASN.1 type ObjectSyntax defines the different syntaxes which may
+ be used in defining an object type.
+
+3.2.1. Primitive Types
+
+ Only the ASN.1 primitive types INTEGER, OCTET STRING, OBJECT
+ IDENTIFIER, and NULL are permitted. These are sometimes referred to
+ as non-aggregate types.
+
+3.2.1.1. Guidelines for Enumerated INTEGERs
+
+ If an enumerated INTEGER is listed as an object type, then a named-
+ number having the value 0 shall not be present in the list of
+
+
+
+Rose & McCloghrie [Page 7]
+
+RFC 1155 SMI May 1990
+
+
+ enumerations. Use of this value is prohibited.
+
+3.2.2. Constructor Types
+
+ The ASN.1 constructor type SEQUENCE is permitted, providing that it
+ is used to generate either lists or tables.
+
+ For lists, the syntax takes the form:
+
+ SEQUENCE { <type1>, ..., <typeN> }
+
+ where each <type> resolves to one of the ASN.1 primitive types listed
+ above. Further, these ASN.1 types are always present (the DEFAULT
+ and OPTIONAL clauses do not appear in the SEQUENCE definition).
+
+ For tables, the syntax takes the form:
+
+ SEQUENCE OF <entry>
+
+ where <entry> resolves to a list constructor.
+
+ Lists and tables are sometimes referred to as aggregate types.
+
+3.2.3. Defined Types
+
+ In addition, new application-wide types may be defined, so long as
+ they resolve into an IMPLICITly defined ASN.1 primitive type, list,
+ table, or some other application-wide type. Initially, few
+ application-wide types are defined. Future memos will no doubt
+ define others once a consensus is reached.
+
+3.2.3.1. NetworkAddress
+
+ This CHOICE represents an address from one of possibly several
+ protocol families. Currently, only one protocol family, the Internet
+ family, is present in this CHOICE.
+
+3.2.3.2. IpAddress
+
+ This application-wide type represents a 32-bit internet address. It
+ is represented as an OCTET STRING of length 4, in network byte-order.
+
+ When this ASN.1 type is encoded using the ASN.1 basic encoding rules,
+ only the primitive encoding form shall be used.
+
+3.2.3.3. Counter
+
+ This application-wide type represents a non-negative integer which
+
+
+
+Rose & McCloghrie [Page 8]
+
+RFC 1155 SMI May 1990
+
+
+ monotonically increases until it reaches a maximum value, when it
+ wraps around and starts increasing again from zero. This memo
+ specifies a maximum value of 2^32-1 (4294967295 decimal) for
+ counters.
+
+3.2.3.4. Gauge
+
+ This application-wide type represents a non-negative integer, which
+ may increase or decrease, but which latches at a maximum value. This
+ memo specifies a maximum value of 2^32-1 (4294967295 decimal) for
+ gauges.
+
+3.2.3.5. TimeTicks
+
+ This application-wide type represents a non-negative integer which
+ counts the time in hundredths of a second since some epoch. When
+ object types are defined in the MIB which use this ASN.1 type, the
+ description of the object type identifies the reference epoch.
+
+3.2.3.6. Opaque
+
+ This application-wide type supports the capability to pass arbitrary
+ ASN.1 syntax. A value is encoded using the ASN.1 basic rules into a
+ string of octets. This, in turn, is encoded as an OCTET STRING, in
+ effect "double-wrapping" the original ASN.1 value.
+
+ Note that a conforming implementation need only be able to accept and
+ recognize opaquely-encoded data. It need not be able to unwrap the
+ data and then interpret its contents.
+
+ Further note that by use of the ASN.1 EXTERNAL type, encodings other
+ than ASN.1 may be used in opaquely-encoded data.
+
+3.3. Encodings
+
+ Once an instance of an object type has been identified, its value may
+ be transmitted by applying the basic encoding rules of ASN.1 to the
+ syntax for the object type.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rose & McCloghrie [Page 9]
+
+RFC 1155 SMI May 1990
+
+
+4. Managed Objects
+
+ Although it is not the purpose of this memo to define objects in the
+ MIB, this memo specifies a format to be used by other memos which
+ define these objects.
+
+ An object type definition consists of five fields:
+
+ OBJECT:
+ -------
+ A textual name, termed the OBJECT DESCRIPTOR, for the object type,
+ along with its corresponding OBJECT IDENTIFIER.
+
+ Syntax:
+ The abstract syntax for the object type. This must resolve to an
+ instance of the ASN.1 type ObjectSyntax (defined below).
+
+ Definition:
+ A textual description of the semantics of the object type.
+ Implementations should ensure that their instance of the object
+ fulfills this definition since this MIB is intended for use in
+ multi-vendor environments. As such it is vital that objects have
+ consistent meaning across all machines.
+
+ Access:
+ One of read-only, read-write, write-only, or not-accessible.
+
+ Status:
+ One of mandatory, optional, or obsolete.
+
+ Future memos may also specify other fields for the objects which they
+ define.
+
+4.1. Guidelines for Object Names
+
+ No object type in the Internet-Standard MIB shall use a sub-
+ identifier of 0 in its name. This value is reserved for use with
+ future extensions.
+
+ Each OBJECT DESCRIPTOR corresponding to an object type in the
+ internet-standard MIB shall be a unique, but mnemonic, printable
+ string. This promotes a common language for humans to use when
+ discussing the MIB and also facilitates simple table mappings for
+ user interfaces.
+
+4.2. Object Types and Instances
+
+ An object type is a definition of a kind of managed object; it is
+
+
+
+Rose & McCloghrie [Page 10]
+
+RFC 1155 SMI May 1990
+
+
+ declarative in nature. In contrast, an object instance is an
+ instantiation of an object type which has been bound to a value. For
+ example, the notion of an entry in a routing table might be defined
+ in the MIB. Such a notion corresponds to an object type; individual
+ entries in a particular routing table which exist at some time are
+ object instances of that object type.
+
+ A collection of object types is defined in the MIB. Each such
+ subject type is uniquely named by its OBJECT IDENTIFIER and also has
+ a textual name, which is its OBJECT DESCRIPTOR. The means whereby
+ object instances are referenced is not defined in the MIB. Reference
+ to object instances is achieved by a protocol-specific mechanism: it
+ is the responsibility of each management protocol adhering to the SMI
+ to define this mechanism.
+
+ An object type may be defined in the MIB such that an instance of
+ that object type represents an aggregation of information also
+ represented by instances of some number of "subordinate" object
+ types. For example, suppose the following object types are defined
+ in the MIB:
+
+
+ OBJECT:
+ -------
+ atIndex { atEntry 1 }
+
+ Syntax:
+ INTEGER
+
+ Definition:
+ The interface number for the physical address.
+
+ Access:
+ read-write.
+
+ Status:
+ mandatory.
+
+
+ OBJECT:
+ -------
+ atPhysAddress { atEntry 2 }
+
+ Syntax:
+ OCTET STRING
+
+ Definition:
+ The media-dependent physical address.
+
+
+
+Rose & McCloghrie [Page 11]
+
+RFC 1155 SMI May 1990
+
+
+ Access:
+ read-write.
+
+ Status:
+ mandatory.
+
+
+ OBJECT:
+ -------
+ atNetAddress { atEntry 3 }
+
+ Syntax:
+ NetworkAddress
+
+ Definition:
+ The network address corresponding to the media-dependent physical
+ address.
+
+ Access:
+ read-write.
+
+ Status:
+ mandatory.
+
+ Then, a fourth object type might also be defined in the MIB:
+
+
+ OBJECT:
+ -------
+ atEntry { atTable 1 }
+
+ Syntax:
+
+ AtEntry ::= SEQUENCE {
+ atIndex
+ INTEGER,
+ atPhysAddress
+ OCTET STRING,
+ atNetAddress
+ NetworkAddress
+ }
+
+ Definition:
+ An entry in the address translation table.
+
+ Access:
+ read-write.
+
+
+
+
+Rose & McCloghrie [Page 12]
+
+RFC 1155 SMI May 1990
+
+
+ Status:
+ mandatory.
+
+ Each instance of this object type comprises information represented
+ by instances of the former three object types. An object type
+ defined in this way is called a list.
+
+ Similarly, tables can be formed by aggregations of a list type. For
+ example, a fifth object type might also be defined in the MIB:
+
+
+ OBJECT:
+ ------
+ atTable { at 1 }
+
+ Syntax:
+ SEQUENCE OF AtEntry
+
+ Definition:
+ The address translation table.
+
+ Access:
+ read-write.
+
+ Status:
+ mandatory.
+
+ such that each instance of the atTable object comprises information
+ represented by the set of atEntry object types that collectively
+ constitute a given atTable object instance, that is, a given address
+ translation table.
+
+ Consider how one might refer to a simple object within a table.
+ Continuing with the previous example, one might name the object type
+
+ { atPhysAddress }
+
+ and specify, using a protocol-specific mechanism, the object instance
+
+ { atNetAddress } = { internet "10.0.0.52" }
+
+ This pairing of object type and object instance would refer to all
+ instances of atPhysAddress which are part of any entry in some
+ address translation table for which the associated atNetAddress value
+ is { internet "10.0.0.52" }.
+
+ To continue with this example, consider how one might refer to an
+ aggregate object (list) within a table. Naming the object type
+
+
+
+Rose & McCloghrie [Page 13]
+
+RFC 1155 SMI May 1990
+
+
+ { atEntry }
+
+ and specifying, using a protocol-specific mechanism, the object
+ instance
+
+ { atNetAddress } = { internet "10.0.0.52" }
+
+ refers to all instances of entries in the table for which the
+ associated atNetAddress value is { internet "10.0.0.52" }.
+
+ Each management protocol must provide a mechanism for accessing
+ simple (non-aggregate) object types. Each management protocol
+ specifies whether or not it supports access to aggregate object
+ types. Further, the protocol must specify which instances are
+ "returned" when an object type/instance pairing refers to more than
+ one instance of a type.
+
+ To afford support for a variety of management protocols, all
+ information by which instances of a given object type may be usefully
+ distinguished, one from another, is represented by instances of
+ object types defined in the MIB.
+
+4.3. Macros for Managed Objects
+
+ In order to facilitate the use of tools for processing the definition
+ of the MIB, the OBJECT-TYPE macro may be used. This macro permits
+ the key aspects of an object type to be represented in a formal way.
+
+ OBJECT-TYPE MACRO ::=
+ BEGIN
+ TYPE NOTATION ::= "SYNTAX" type (TYPE ObjectSyntax)
+ "ACCESS" Access
+ "STATUS" Status
+ VALUE NOTATION ::= value (VALUE ObjectName)
+
+ Access ::= "read-only"
+ | "read-write"
+ | "write-only"
+ | "not-accessible"
+ Status ::= "mandatory"
+ | "optional"
+ | "obsolete"
+ END
+
+ Given the object types defined earlier, we might imagine the
+ following definitions being present in the MIB:
+
+ atIndex OBJECT-TYPE
+
+
+
+Rose & McCloghrie [Page 14]
+
+RFC 1155 SMI May 1990
+
+
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ ::= { atEntry 1 }
+
+ atPhysAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-write
+ STATUS mandatory
+ ::= { atEntry 2 }
+
+ atNetAddress OBJECT-TYPE
+ SYNTAX NetworkAddress
+ ACCESS read-write
+ STATUS mandatory
+ ::= { atEntry 3 }
+
+ atEntry OBJECT-TYPE
+ SYNTAX AtEntry
+ ACCESS read-write
+ STATUS mandatory
+ ::= { atTable 1 }
+
+ atTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AtEntry
+ ACCESS read-write
+ STATUS mandatory
+ ::= { at 1 }
+
+ AtEntry ::= SEQUENCE {
+ atIndex
+ INTEGER,
+ atPhysAddress
+ OCTET STRING,
+ atNetAddress
+ NetworkAddress
+ }
+
+ The first five definitions describe object types, relating, for
+ example, the OBJECT DESCRIPTOR atIndex to the OBJECT IDENTIFIER {
+ atEntry 1 }. In addition, the syntax of this object is defined
+ (INTEGER) along with the access permitted (read-write) and status
+ (mandatory). The sixth definition describes an ASN.1 type called
+ AtEntry.
+
+
+
+
+
+
+
+Rose & McCloghrie [Page 15]
+
+RFC 1155 SMI May 1990
+
+
+5. Extensions to the MIB
+
+ Every Internet-standard MIB document obsoletes all previous such
+ documents. The portion of a name, termed the tail, following the
+ OBJECT IDENTIFIER
+
+ { mgmt version-number }
+
+ used to name objects shall remain unchanged between versions. New
+ versions may:
+
+ (1) declare old object types obsolete (if necessary), but not
+ delete their names;
+
+ (2) augment the definition of an object type corresponding to a
+ list by appending non-aggregate object types to the object types
+ in the list; or,
+
+ (3) define entirely new object types.
+
+ New versions may not:
+
+ (1) change the semantics of any previously defined object without
+ changing the name of that object.
+
+ These rules are important because they admit easier support for
+ multiple versions of the Internet-standard MIB. In particular, the
+ semantics associated with the tail of a name remain constant
+ throughout different versions of the MIB. Because multiple versions
+ of the MIB may thus coincide in "tail-space," implementations
+ supporting multiple versions of the MIB can be vastly simplified.
+
+ However, as a consequence, a management agent might return an
+ instance corresponding to a superset of the expected object type.
+ Following the principle of robustness, in this exceptional case, a
+ manager should ignore any additional information beyond the
+ definition of the expected object type. However, the robustness
+ principle requires that one exercise care with respect to control
+ actions: if an instance does not have the same syntax as its
+ expected object type, then those control actions must fail. In both
+ the monitoring and control cases, the name of an object returned by
+ an operation must be identical to the name requested by an operation.
+
+
+
+
+
+
+
+
+
+Rose & McCloghrie [Page 16]
+
+RFC 1155 SMI May 1990
+
+
+6. Definitions
+
+ RFC1155-SMI DEFINITIONS ::= BEGIN
+
+ EXPORTS -- EVERYTHING
+ internet, directory, mgmt,
+ experimental, private, enterprises,
+ OBJECT-TYPE, ObjectName, ObjectSyntax, SimpleSyntax,
+ ApplicationSyntax, NetworkAddress, IpAddress,
+ Counter, Gauge, TimeTicks, Opaque;
+
+ -- the path to the root
+
+ internet OBJECT IDENTIFIER ::= { iso org(3) dod(6) 1 }
+
+ directory OBJECT IDENTIFIER ::= { internet 1 }
+
+ mgmt OBJECT IDENTIFIER ::= { internet 2 }
+
+ experimental OBJECT IDENTIFIER ::= { internet 3 }
+
+ private OBJECT IDENTIFIER ::= { internet 4 }
+ enterprises OBJECT IDENTIFIER ::= { private 1 }
+
+
+ -- definition of object types
+
+ OBJECT-TYPE MACRO ::=
+ BEGIN
+ TYPE NOTATION ::= "SYNTAX" type (TYPE ObjectSyntax)
+ "ACCESS" Access
+ "STATUS" Status
+ VALUE NOTATION ::= value (VALUE ObjectName)
+
+ Access ::= "read-only"
+ | "read-write"
+ | "write-only"
+ | "not-accessible"
+ Status ::= "mandatory"
+ | "optional"
+ | "obsolete"
+ END
+
+ -- names of objects in the MIB
+
+ ObjectName ::=
+ OBJECT IDENTIFIER
+
+
+
+
+Rose & McCloghrie [Page 17]
+
+RFC 1155 SMI May 1990
+
+
+ -- syntax of objects in the MIB
+
+ ObjectSyntax ::=
+ CHOICE {
+ simple
+ SimpleSyntax,
+
+ -- note that simple SEQUENCEs are not directly
+ -- mentioned here to keep things simple (i.e.,
+ -- prevent mis-use). However, application-wide
+ -- types which are IMPLICITly encoded simple
+ -- SEQUENCEs may appear in the following CHOICE
+
+ application-wide
+ ApplicationSyntax
+ }
+
+ SimpleSyntax ::=
+ CHOICE {
+ number
+ INTEGER,
+
+ string
+ OCTET STRING,
+
+ object
+ OBJECT IDENTIFIER,
+
+ empty
+ NULL
+ }
+
+ ApplicationSyntax ::=
+ CHOICE {
+ address
+ NetworkAddress,
+
+ counter
+ Counter,
+
+ gauge
+ Gauge,
+
+ ticks
+ TimeTicks,
+
+ arbitrary
+ Opaque
+
+
+
+Rose & McCloghrie [Page 18]
+
+RFC 1155 SMI May 1990
+
+
+ -- other application-wide types, as they are
+ -- defined, will be added here
+ }
+
+
+ -- application-wide types
+
+ NetworkAddress ::=
+ CHOICE {
+ internet
+ IpAddress
+ }
+
+ IpAddress ::=
+ [APPLICATION 0] -- in network-byte order
+ IMPLICIT OCTET STRING (SIZE (4))
+
+ Counter ::=
+ [APPLICATION 1]
+ IMPLICIT INTEGER (0..4294967295)
+
+ Gauge ::=
+ [APPLICATION 2]
+ IMPLICIT INTEGER (0..4294967295)
+
+ TimeTicks ::=
+ [APPLICATION 3]
+ IMPLICIT INTEGER (0..4294967295)
+
+ Opaque ::=
+ [APPLICATION 4] -- arbitrary ASN.1 value,
+ IMPLICIT OCTET STRING -- "double-wrapped"
+
+ END
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rose & McCloghrie [Page 19]
+
+RFC 1155 SMI May 1990
+
+
+7. Acknowledgements
+
+ This memo was influenced by three sets of contributors to earlier
+ drafts:
+
+ First, Lee Labarre of the MITRE Corporation, who as author of the
+ NETMAN SMI [4], presented the basic roadmap for the SMI.
+
+ Second, several individuals who provided valuable comments on this
+ memo prior to its initial distribution:
+
+ James R. Davin, Proteon
+ Mark S. Fedor, NYSERNet
+ Craig Partridge, BBN Laboratories
+ Martin Lee Schoffstall, Rensselaer Polytechnic Institute
+ Wengyik Yeong, NYSERNet
+
+
+ Third, the IETF MIB working group:
+
+ Karl Auerbach, Epilogue Technology
+ K. Ramesh Babu, Excelan
+ Lawrence Besaw, Hewlett-Packard
+ Jeffrey D. Case, University of Tennessee at Knoxville
+ James R. Davin, Proteon
+ Mark S. Fedor, NYSERNet
+ Robb Foster, BBN
+ Phill Gross, The MITRE Corporation
+ Bent Torp Jensen, Convergent Technology
+ Lee Labarre, The MITRE Corporation
+ Dan Lynch, Advanced Computing Environments
+ Keith McCloghrie, The Wollongong Group
+ Dave Mackie, 3Com/Bridge
+ Craig Partridge, BBN (chair)
+ Jim Robertson, 3Com/Bridge
+ Marshall T. Rose, The Wollongong Group
+ Greg Satz, cisco
+ Martin Lee Schoffstall, Rensselaer Polytechnic Institute
+ Lou Steinberg, IBM
+ Dean Throop, Data General
+ Unni Warrier, Unisys
+
+
+
+
+
+
+
+
+
+
+Rose & McCloghrie [Page 20]
+
+RFC 1155 SMI May 1990
+
+
+8. References
+
+ [1] Information processing systems - Open Systems Interconnection,
+ "Specification of Abstract Syntax Notation One (ASN.1)",
+ International Organization for Standardization, International
+ Standard 8824, December 1987.
+
+ [2] McCloghrie K., and M. Rose, "Management Information Base for
+ Network Management of TCP/IP-based Internets", RFC 1156,
+ Performance Systems International and Hughes LAN Systems, May
+ 1990.
+
+ [3] Case, J., M. Fedor, M. Schoffstall, and J. Davin, The Simple
+ Network Management Protocol", RFC 1157, University of Tennessee
+ at Knoxville, Performance Systems International, Performance
+ Systems International, and the MIT Laboratory for Computer
+ Science, May 1990.
+
+ [4] LaBarre, L., "Structure and Identification of Management
+ Information for the Internet", Internet Engineering Task Force
+ working note, Network Information Center, SRI International,
+ Menlo Park, California, April 1988.
+
+ [5] Cerf, V., "IAB Recommendations for the Development of Internet
+ Network Management Standards", RFC 1052, IAB, April 1988.
+
+ [6] Cerf, V., "Report of the Second Ad Hoc Network Management Review
+ Group", RFC 1109, IAB, August 1989.
+
+ [7] Information processing systems - Open Systems Interconnection,
+ "Specification of Basic Encoding Rules for Abstract Notation One
+ (ASN.1)", International Organization for Standardization,
+ International Standard 8825, December 1987.
+
+Security Considerations
+
+ Security issues are not discussed in this memo.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rose & McCloghrie [Page 21]
+
+RFC 1155 SMI May 1990
+
+
+Authors' Addresses
+
+ Marshall T. Rose
+ PSI, Inc.
+ PSI California Office
+ P.O. Box 391776
+ Mountain View, CA 94039
+
+ Phone: (415) 961-3380
+
+ EMail: mrose@PSI.COM
+
+
+ Keith McCloghrie
+ The Wollongong Group
+ 1129 San Antonio Road
+ Palo Alto, CA 04303
+
+ Phone: (415) 962-7160
+
+ EMail: sytek!kzm@HPLABS.HP.COM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rose & McCloghrie [Page 22]
+ \ No newline at end of file
diff --git a/standards/rfc1157.txt b/standards/rfc1157.txt
new file mode 100644
index 000000000..262e7eb5b
--- /dev/null
+++ b/standards/rfc1157.txt
@@ -0,0 +1,2019 @@
+
+
+
+
+
+
+Network Working Group J. Case
+Request for Comments: 1157 SNMP Research
+Obsoletes: RFC 1098 M. Fedor
+ Performance Systems International
+ M. Schoffstall
+ Performance Systems International
+ J. Davin
+ MIT Laboratory for Computer Science
+ May 1990
+
+
+ A Simple Network Management Protocol (SNMP)
+
+ Table of Contents
+
+ 1. Status of this Memo ................................... 2
+ 2. Introduction .......................................... 2
+ 3. The SNMP Architecture ................................. 5
+ 3.1 Goals of the Architecture ............................ 5
+ 3.2 Elements of the Architecture ......................... 5
+ 3.2.1 Scope of Management Information .................... 6
+ 3.2.2 Representation of Management Information ........... 6
+ 3.2.3 Operations Supported on Management Information ..... 7
+ 3.2.4 Form and Meaning of Protocol Exchanges ............. 8
+ 3.2.5 Definition of Administrative Relationships ......... 8
+ 3.2.6 Form and Meaning of References to Managed Objects .. 12
+ 3.2.6.1 Resolution of Ambiguous MIB References ........... 12
+ 3.2.6.2 Resolution of References across MIB Versions...... 12
+ 3.2.6.3 Identification of Object Instances ............... 12
+ 3.2.6.3.1 ifTable Object Type Names ...................... 13
+ 3.2.6.3.2 atTable Object Type Names ...................... 13
+ 3.2.6.3.3 ipAddrTable Object Type Names .................. 14
+ 3.2.6.3.4 ipRoutingTable Object Type Names ............... 14
+ 3.2.6.3.5 tcpConnTable Object Type Names ................. 14
+ 3.2.6.3.6 egpNeighTable Object Type Names ................ 15
+ 4. Protocol Specification ................................ 16
+ 4.1 Elements of Procedure ................................ 17
+ 4.1.1 Common Constructs .................................. 19
+ 4.1.2 The GetRequest-PDU ................................. 20
+ 4.1.3 The GetNextRequest-PDU ............................. 21
+ 4.1.3.1 Example of Table Traversal ....................... 23
+ 4.1.4 The GetResponse-PDU ................................ 24
+ 4.1.5 The SetRequest-PDU ................................. 25
+ 4.1.6 The Trap-PDU ....................................... 27
+ 4.1.6.1 The coldStart Trap ............................... 28
+ 4.1.6.2 The warmStart Trap ............................... 28
+ 4.1.6.3 The linkDown Trap ................................ 28
+ 4.1.6.4 The linkUp Trap .................................. 28
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 1]
+
+RFC 1157 SNMP May 1990
+
+
+ 4.1.6.5 The authenticationFailure Trap ................... 28
+ 4.1.6.6 The egpNeighborLoss Trap ......................... 28
+ 4.1.6.7 The enterpriseSpecific Trap ...................... 29
+ 5. Definitions ........................................... 30
+ 6. Acknowledgements ...................................... 33
+ 7. References ............................................ 34
+ 8. Security Considerations................................ 35
+ 9. Authors' Addresses..................................... 35
+
+1. Status of this Memo
+
+ This RFC is a re-release of RFC 1098, with a changed "Status of this
+ Memo" section plus a few minor typographical corrections. This memo
+ defines a simple protocol by which management information for a
+ network element may be inspected or altered by logically remote
+ users. In particular, together with its companion memos which
+ describe the structure of management information along with the
+ management information base, these documents provide a simple,
+ workable architecture and system for managing TCP/IP-based internets
+ and in particular the Internet.
+
+ The Internet Activities Board recommends that all IP and TCP
+ implementations be network manageable. This implies implementation
+ of the Internet MIB (RFC-1156) and at least one of the two
+ recommended management protocols SNMP (RFC-1157) or CMOT (RFC-1095).
+ It should be noted that, at this time, SNMP is a full Internet
+ standard and CMOT is a draft standard. See also the Host and Gateway
+ Requirements RFCs for more specific information on the applicability
+ of this standard.
+
+ Please refer to the latest edition of the "IAB Official Protocol
+ Standards" RFC for current information on the state and status of
+ standard Internet protocols.
+
+ Distribution of this memo is unlimited.
+
+2. Introduction
+
+ As reported in RFC 1052, IAB Recommendations for the Development of
+ Internet Network Management Standards [1], a two-prong strategy for
+ network management of TCP/IP-based internets was undertaken. In the
+ short-term, the Simple Network Management Protocol (SNMP) was to be
+ used to manage nodes in the Internet community. In the long-term,
+ the use of the OSI network management framework was to be examined.
+ Two documents were produced to define the management information: RFC
+ 1065, which defined the Structure of Management Information (SMI)
+ [2], and RFC 1066, which defined the Management Information Base
+ (MIB) [3]. Both of these documents were designed so as to be
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 2]
+
+RFC 1157 SNMP May 1990
+
+
+ compatible with both the SNMP and the OSI network management
+ framework.
+
+ This strategy was quite successful in the short-term: Internet-based
+ network management technology was fielded, by both the research and
+ commercial communities, within a few months. As a result of this,
+ portions of the Internet community became network manageable in a
+ timely fashion.
+
+ As reported in RFC 1109, Report of the Second Ad Hoc Network
+ Management Review Group [4], the requirements of the SNMP and the OSI
+ network management frameworks were more different than anticipated.
+ As such, the requirement for compatibility between the SMI/MIB and
+ both frameworks was suspended. This action permitted the operational
+ network management framework, the SNMP, to respond to new operational
+ needs in the Internet community by producing documents defining new
+ MIB items.
+
+ The IAB has designated the SNMP, SMI, and the initial Internet MIB to
+ be full "Standard Protocols" with "Recommended" status. By this
+ action, the IAB recommends that all IP and TCP implementations be
+ network manageable and that the implementations that are network
+ manageable are expected to adopt and implement the SMI, MIB, and
+ SNMP.
+
+ As such, the current network management framework for TCP/IP- based
+ internets consists of: Structure and Identification of Management
+ Information for TCP/IP-based Internets, which describes how managed
+ objects contained in the MIB are defined as set forth in RFC 1155
+ [5]; Management Information Base for Network Management of TCP/IP-
+ based Internets, which describes the managed objects contained in the
+ MIB as set forth in RFC 1156 [6]; and, the Simple Network Management
+ Protocol, which defines the protocol used to manage these objects, as
+ set forth in this memo.
+
+ As reported in RFC 1052, IAB Recommendations for the Development of
+ Internet Network Management Standards [1], the Internet Activities
+ Board has directed the Internet Engineering Task Force (IETF) to
+ create two new working groups in the area of network management. One
+ group was charged with the further specification and definition of
+ elements to be included in the Management Information Base (MIB).
+ The other was charged with defining the modifications to the Simple
+ Network Management Protocol (SNMP) to accommodate the short-term
+ needs of the network vendor and operations communities, and to align
+ with the output of the MIB working group.
+
+ The MIB working group produced two memos, one which defines a
+ Structure for Management Information (SMI) [2] for use by the managed
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 3]
+
+RFC 1157 SNMP May 1990
+
+
+ objects contained in the MIB. A second memo [3] defines the list of
+ managed objects.
+
+ The output of the SNMP Extensions working group is this memo, which
+ incorporates changes to the initial SNMP definition [7] required to
+ attain alignment with the output of the MIB working group. The
+ changes should be minimal in order to be consistent with the IAB's
+ directive that the working groups be "extremely sensitive to the need
+ to keep the SNMP simple." Although considerable care and debate has
+ gone into the changes to the SNMP which are reflected in this memo,
+ the resulting protocol is not backwardly-compatible with its
+ predecessor, the Simple Gateway Monitoring Protocol (SGMP) [8].
+ Although the syntax of the protocol has been altered, the original
+ philosophy, design decisions, and architecture remain intact. In
+ order to avoid confusion, new UDP ports have been allocated for use
+ by the protocol described in this memo.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 4]
+
+RFC 1157 SNMP May 1990
+
+
+3. The SNMP Architecture
+
+ Implicit in the SNMP architectural model is a collection of network
+ management stations and network elements. Network management
+ stations execute management applications which monitor and control
+ network elements. Network elements are devices such as hosts,
+ gateways, terminal servers, and the like, which have management
+ agents responsible for performing the network management functions
+ requested by the network management stations. The Simple Network
+ Management Protocol (SNMP) is used to communicate management
+ information between the network management stations and the agents in
+ the network elements.
+
+3.1. Goals of the Architecture
+
+ The SNMP explicitly minimizes the number and complexity of management
+ functions realized by the management agent itself. This goal is
+ attractive in at least four respects:
+
+ (1) The development cost for management agent software
+ necessary to support the protocol is accordingly reduced.
+
+ (2) The degree of management function that is remotely
+ supported is accordingly increased, thereby admitting
+ fullest use of internet resources in the management task.
+
+ (3) The degree of management function that is remotely
+ supported is accordingly increased, thereby imposing the
+ fewest possible restrictions on the form and
+ sophistication of management tools.
+
+ (4) Simplified sets of management functions are easily
+ understood and used by developers of network management
+ tools.
+
+ A second goal of the protocol is that the functional paradigm for
+ monitoring and control be sufficiently extensible to accommodate
+ additional, possibly unanticipated aspects of network operation and
+ management.
+
+ A third goal is that the architecture be, as much as possible,
+ independent of the architecture and mechanisms of particular hosts or
+ particular gateways.
+
+3.2. Elements of the Architecture
+
+ The SNMP architecture articulates a solution to the network
+ management problem in terms of:
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 5]
+
+RFC 1157 SNMP May 1990
+
+
+ (1) the scope of the management information communicated by
+ the protocol,
+
+ (2) the representation of the management information
+ communicated by the protocol,
+
+ (3) operations on management information supported by the
+ protocol,
+
+ (4) the form and meaning of exchanges among management
+ entities,
+
+ (5) the definition of administrative relationships among
+ management entities, and
+
+ (6) the form and meaning of references to management
+ information.
+
+3.2.1. Scope of Management Information
+
+ The scope of the management information communicated by operation of
+ the SNMP is exactly that represented by instances of all non-
+ aggregate object types either defined in Internet-standard MIB or
+ defined elsewhere according to the conventions set forth in
+ Internet-standard SMI [5].
+
+ Support for aggregate object types in the MIB is neither required for
+ conformance with the SMI nor realized by the SNMP.
+
+3.2.2. Representation of Management Information
+
+ Management information communicated by operation of the SNMP is
+ represented according to the subset of the ASN.1 language [9] that is
+ specified for the definition of non-aggregate types in the SMI.
+
+ The SGMP adopted the convention of using a well-defined subset of the
+ ASN.1 language [9]. The SNMP continues and extends this tradition by
+ utilizing a moderately more complex subset of ASN.1 for describing
+ managed objects and for describing the protocol data units used for
+ managing those objects. In addition, the desire to ease eventual
+ transition to OSI-based network management protocols led to the
+ definition in the ASN.1 language of an Internet-standard Structure of
+ Management Information (SMI) [5] and Management Information Base
+ (MIB) [6]. The use of the ASN.1 language, was, in part, encouraged
+ by the successful use of ASN.1 in earlier efforts, in particular, the
+ SGMP. The restrictions on the use of ASN.1 that are part of the SMI
+ contribute to the simplicity espoused and validated by experience
+ with the SGMP.
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 6]
+
+RFC 1157 SNMP May 1990
+
+
+ Also for the sake of simplicity, the SNMP uses only a subset of the
+ basic encoding rules of ASN.1 [10]. Namely, all encodings use the
+ definite-length form. Further, whenever permissible, non-constructor
+ encodings are used rather than constructor encodings. This
+ restriction applies to all aspects of ASN.1 encoding, both for the
+ top-level protocol data units and the data objects they contain.
+
+3.2.3. Operations Supported on Management Information
+
+ The SNMP models all management agent functions as alterations or
+ inspections of variables. Thus, a protocol entity on a logically
+ remote host (possibly the network element itself) interacts with the
+ management agent resident on the network element in order to retrieve
+ (get) or alter (set) variables. This strategy has at least two
+ positive consequences:
+
+ (1) It has the effect of limiting the number of essential
+ management functions realized by the management agent to
+ two: one operation to assign a value to a specified
+ configuration or other parameter and another to retrieve
+ such a value.
+
+ (2) A second effect of this decision is to avoid introducing
+ into the protocol definition support for imperative
+ management commands: the number of such commands is in
+ practice ever-increasing, and the semantics of such
+ commands are in general arbitrarily complex.
+
+ The strategy implicit in the SNMP is that the monitoring of network
+ state at any significant level of detail is accomplished primarily by
+ polling for appropriate information on the part of the monitoring
+ center(s). A limited number of unsolicited messages (traps) guide
+ the timing and focus of the polling. Limiting the number of
+ unsolicited messages is consistent with the goal of simplicity and
+ minimizing the amount of traffic generated by the network management
+ function.
+
+ The exclusion of imperative commands from the set of explicitly
+ supported management functions is unlikely to preclude any desirable
+ management agent operation. Currently, most commands are requests
+ either to set the value of some parameter or to retrieve such a
+ value, and the function of the few imperative commands currently
+ supported is easily accommodated in an asynchronous mode by this
+ management model. In this scheme, an imperative command might be
+ realized as the setting of a parameter value that subsequently
+ triggers the desired action. For example, rather than implementing a
+ "reboot command," this action might be invoked by simply setting a
+ parameter indicating the number of seconds until system reboot.
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 7]
+
+RFC 1157 SNMP May 1990
+
+
+3.2.4. Form and Meaning of Protocol Exchanges
+
+ The communication of management information among management entities
+ is realized in the SNMP through the exchange of protocol messages.
+ The form and meaning of those messages is defined below in Section 4.
+
+ Consistent with the goal of minimizing complexity of the management
+ agent, the exchange of SNMP messages requires only an unreliable
+ datagram service, and every message is entirely and independently
+ represented by a single transport datagram. While this document
+ specifies the exchange of messages via the UDP protocol [11], the
+ mechanisms of the SNMP are generally suitable for use with a wide
+ variety of transport services.
+
+3.2.5. Definition of Administrative Relationships
+
+ The SNMP architecture admits a variety of administrative
+ relationships among entities that participate in the protocol. The
+ entities residing at management stations and network elements which
+ communicate with one another using the SNMP are termed SNMP
+ application entities. The peer processes which implement the SNMP,
+ and thus support the SNMP application entities, are termed protocol
+ entities.
+
+ A pairing of an SNMP agent with some arbitrary set of SNMP
+ application entities is called an SNMP community. Each SNMP
+ community is named by a string of octets, that is called the
+ community name for said community.
+
+ An SNMP message originated by an SNMP application entity that in fact
+ belongs to the SNMP community named by the community component of
+ said message is called an authentic SNMP message. The set of rules
+ by which an SNMP message is identified as an authentic SNMP message
+ for a particular SNMP community is called an authentication scheme.
+ An implementation of a function that identifies authentic SNMP
+ messages according to one or more authentication schemes is called an
+ authentication service.
+
+ Clearly, effective management of administrative relationships among
+ SNMP application entities requires authentication services that (by
+ the use of encryption or other techniques) are able to identify
+ authentic SNMP messages with a high degree of certainty. Some SNMP
+ implementations may wish to support only a trivial authentication
+ service that identifies all SNMP messages as authentic SNMP messages.
+
+ For any network element, a subset of objects in the MIB that pertain
+ to that element is called a SNMP MIB view. Note that the names of
+ the object types represented in a SNMP MIB view need not belong to a
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 8]
+
+RFC 1157 SNMP May 1990
+
+
+ single sub-tree of the object type name space.
+
+ An element of the set { READ-ONLY, READ-WRITE } is called an SNMP
+ access mode.
+
+ A pairing of a SNMP access mode with a SNMP MIB view is called an
+ SNMP community profile. A SNMP community profile represents
+ specified access privileges to variables in a specified MIB view. For
+ every variable in the MIB view in a given SNMP community profile,
+ access to that variable is represented by the profile according to
+ the following conventions:
+
+ (1) if said variable is defined in the MIB with "Access:" of
+ "none," it is unavailable as an operand for any operator;
+
+ (2) if said variable is defined in the MIB with "Access:" of
+ "read-write" or "write-only" and the access mode of the
+ given profile is READ-WRITE, that variable is available
+ as an operand for the get, set, and trap operations;
+
+ (3) otherwise, the variable is available as an operand for
+ the get and trap operations.
+
+ (4) In those cases where a "write-only" variable is an
+ operand used for the get or trap operations, the value
+ given for the variable is implementation-specific.
+
+ A pairing of a SNMP community with a SNMP community profile is called
+ a SNMP access policy. An access policy represents a specified
+ community profile afforded by the SNMP agent of a specified SNMP
+ community to other members of that community. All administrative
+ relationships among SNMP application entities are architecturally
+ defined in terms of SNMP access policies.
+
+ For every SNMP access policy, if the network element on which the
+ SNMP agent for the specified SNMP community resides is not that to
+ which the MIB view for the specified profile pertains, then that
+ policy is called a SNMP proxy access policy. The SNMP agent
+ associated with a proxy access policy is called a SNMP proxy agent.
+ While careless definition of proxy access policies can result in
+ management loops, prudent definition of proxy policies is useful in
+ at least two ways:
+
+ (1) It permits the monitoring and control of network elements
+ which are otherwise not addressable using the management
+ protocol and the transport protocol. That is, a proxy
+ agent may provide a protocol conversion function allowing
+ a management station to apply a consistent management
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 9]
+
+RFC 1157 SNMP May 1990
+
+
+ framework to all network elements, including devices such
+ as modems, multiplexors, and other devices which support
+ different management frameworks.
+
+ (2) It potentially shields network elements from elaborate
+ access control policies. For example, a proxy agent may
+ implement sophisticated access control whereby diverse
+ subsets of variables within the MIB are made accessible
+ to different management stations without increasing the
+ complexity of the network element.
+
+ By way of example, Figure 1 illustrates the relationship between
+ management stations, proxy agents, and management agents. In this
+ example, the proxy agent is envisioned to be a normal Internet
+ Network Operations Center (INOC) of some administrative domain which
+ has a standard managerial relationship with a set of management
+ agents.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 10]
+
+RFC 1157 SNMP May 1990
+
+
+ +------------------+ +----------------+ +----------------+
+ | Region #1 INOC | |Region #2 INOC | |PC in Region #3 |
+ | | | | | |
+ |Domain=Region #1 | |Domain=Region #2| |Domain=Region #3|
+ |CPU=super-mini-1 | |CPU=super-mini-1| |CPU=Clone-1 |
+ |PCommunity=pub | |PCommunity=pub | |PCommunity=slate|
+ | | | | | |
+ +------------------+ +----------------+ +----------------+
+ /|\ /|\ /|\
+ | | |
+ | | |
+ | \|/ |
+ | +-----------------+ |
+ +-------------->| Region #3 INOC |<-------------+
+ | |
+ |Domain=Region #3 |
+ |CPU=super-mini-2 |
+ |PCommunity=pub, |
+ | slate |
+ |DCommunity=secret|
+ +-------------->| |<-------------+
+ | +-----------------+ |
+ | /|\ |
+ | | |
+ | | |
+ \|/ \|/ \|/
+ +-----------------+ +-----------------+ +-----------------+
+ |Domain=Region#3 | |Domain=Region#3 | |Domain=Region#3 |
+ |CPU=router-1 | |CPU=mainframe-1 | |CPU=modem-1 |
+ |DCommunity=secret| |DCommunity=secret| |DCommunity=secret|
+ +-----------------+ +-----------------+ +-----------------+
+
+
+ Domain: the administrative domain of the element
+ PCommunity: the name of a community utilizing a proxy agent
+ DCommunity: the name of a direct community
+
+
+ Figure 1
+ Example Network Management Configuration
+
+
+
+
+
+
+
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 11]
+
+RFC 1157 SNMP May 1990
+
+
+3.2.6. Form and Meaning of References to Managed Objects
+
+ The SMI requires that the definition of a conformant management
+ protocol address:
+
+ (1) the resolution of ambiguous MIB references,
+
+ (2) the resolution of MIB references in the presence multiple
+ MIB versions, and
+
+ (3) the identification of particular instances of object
+ types defined in the MIB.
+
+3.2.6.1. Resolution of Ambiguous MIB References
+
+ Because the scope of any SNMP operation is conceptually confined to
+ objects relevant to a single network element, and because all SNMP
+ references to MIB objects are (implicitly or explicitly) by unique
+ variable names, there is no possibility that any SNMP reference to
+ any object type defined in the MIB could resolve to multiple
+ instances of that type.
+
+3.2.6.2. Resolution of References across MIB Versions
+
+ The object instance referred to by any SNMP operation is exactly that
+ specified as part of the operation request or (in the case of a get-
+ next operation) its immediate successor in the MIB as a whole. In
+ particular, a reference to an object as part of some version of the
+ Internet-standard MIB does not resolve to any object that is not part
+ of said version of the Internet-standard MIB, except in the case that
+ the requested operation is get-next and the specified object name is
+ lexicographically last among the names of all objects presented as
+ part of said version of the Internet-Standard MIB.
+
+3.2.6.3. Identification of Object Instances
+
+ The names for all object types in the MIB are defined explicitly
+ either in the Internet-standard MIB or in other documents which
+ conform to the naming conventions of the SMI. The SMI requires that
+ conformant management protocols define mechanisms for identifying
+ individual instances of those object types for a particular network
+ element.
+
+ Each instance of any object type defined in the MIB is identified in
+ SNMP operations by a unique name called its "variable name." In
+ general, the name of an SNMP variable is an OBJECT IDENTIFIER of the
+ form x.y, where x is the name of a non-aggregate object type defined
+ in the MIB and y is an OBJECT IDENTIFIER fragment that, in a way
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 12]
+
+RFC 1157 SNMP May 1990
+
+
+ specific to the named object type, identifies the desired instance.
+
+ This naming strategy admits the fullest exploitation of the semantics
+ of the GetNextRequest-PDU (see Section 4), because it assigns names
+ for related variables so as to be contiguous in the lexicographical
+ ordering of all variable names known in the MIB.
+
+ The type-specific naming of object instances is defined below for a
+ number of classes of object types. Instances of an object type to
+ which none of the following naming conventions are applicable are
+ named by OBJECT IDENTIFIERs of the form x.0, where x is the name of
+ said object type in the MIB definition.
+
+ For example, suppose one wanted to identify an instance of the
+ variable sysDescr The object class for sysDescr is:
+
+ iso org dod internet mgmt mib system sysDescr
+ 1 3 6 1 2 1 1 1
+
+ Hence, the object type, x, would be 1.3.6.1.2.1.1.1 to which is
+ appended an instance sub-identifier of 0. That is, 1.3.6.1.2.1.1.1.0
+ identifies the one and only instance of sysDescr.
+
+3.2.6.3.1. ifTable Object Type Names
+
+ The name of a subnet interface, s, is the OBJECT IDENTIFIER value of
+ the form i, where i has the value of that instance of the ifIndex
+ object type associated with s.
+
+ For each object type, t, for which the defined name, n, has a prefix
+ of ifEntry, an instance, i, of t is named by an OBJECT IDENTIFIER of
+ the form n.s, where s is the name of the subnet interface about which
+ i represents information.
+
+ For example, suppose one wanted to identify the instance of the
+ variable ifType associated with interface 2. Accordingly, ifType.2
+ would identify the desired instance.
+
+3.2.6.3.2. atTable Object Type Names
+
+ The name of an AT-cached network address, x, is an OBJECT IDENTIFIER
+ of the form 1.a.b.c.d, where a.b.c.d is the value (in the familiar
+ "dot" notation) of the atNetAddress object type associated with x.
+
+ The name of an address translation equivalence e is an OBJECT
+ IDENTIFIER value of the form s.w, such that s is the value of that
+ instance of the atIndex object type associated with e and such that w
+ is the name of the AT-cached network address associated with e.
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 13]
+
+RFC 1157 SNMP May 1990
+
+
+ For each object type, t, for which the defined name, n, has a prefix
+ of atEntry, an instance, i, of t is named by an OBJECT IDENTIFIER of
+ the form n.y, where y is the name of the address translation
+ equivalence about which i represents information.
+
+ For example, suppose one wanted to find the physical address of an
+ entry in the address translation table (ARP cache) associated with an
+ IP address of 89.1.1.42 and interface 3. Accordingly,
+ atPhysAddress.3.1.89.1.1.42 would identify the desired instance.
+
+3.2.6.3.3. ipAddrTable Object Type Names
+
+ The name of an IP-addressable network element, x, is the OBJECT
+ IDENTIFIER of the form a.b.c.d such that a.b.c.d is the value (in the
+ familiar "dot" notation) of that instance of the ipAdEntAddr object
+ type associated with x.
+
+ For each object type, t, for which the defined name, n, has a prefix
+ of ipAddrEntry, an instance, i, of t is named by an OBJECT IDENTIFIER
+ of the form n.y, where y is the name of the IP-addressable network
+ element about which i represents information.
+
+ For example, suppose one wanted to find the network mask of an entry
+ in the IP interface table associated with an IP address of 89.1.1.42.
+ Accordingly, ipAdEntNetMask.89.1.1.42 would identify the desired
+ instance.
+
+3.2.6.3.4. ipRoutingTable Object Type Names
+
+ The name of an IP route, x, is the OBJECT IDENTIFIER of the form
+ a.b.c.d such that a.b.c.d is the value (in the familiar "dot"
+ notation) of that instance of the ipRouteDest object type associated
+ with x.
+
+ For each object type, t, for which the defined name, n, has a prefix
+ of ipRoutingEntry, an instance, i, of t is named by an OBJECT
+ IDENTIFIER of the form n.y, where y is the name of the IP route about
+ which i represents information.
+
+ For example, suppose one wanted to find the next hop of an entry in
+ the IP routing table associated with the destination of 89.1.1.42.
+ Accordingly, ipRouteNextHop.89.1.1.42 would identify the desired
+ instance.
+
+3.2.6.3.5. tcpConnTable Object Type Names
+
+ The name of a TCP connection, x, is the OBJECT IDENTIFIER of the form
+ a.b.c.d.e.f.g.h.i.j such that a.b.c.d is the value (in the familiar
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 14]
+
+RFC 1157 SNMP May 1990
+
+
+ "dot" notation) of that instance of the tcpConnLocalAddress object
+ type associated with x and such that f.g.h.i is the value (in the
+ familiar "dot" notation) of that instance of the tcpConnRemoteAddress
+ object type associated with x and such that e is the value of that
+ instance of the tcpConnLocalPort object type associated with x and
+ such that j is the value of that instance of the tcpConnRemotePort
+ object type associated with x.
+
+ For each object type, t, for which the defined name, n, has a prefix
+ of tcpConnEntry, an instance, i, of t is named by an OBJECT
+ IDENTIFIER of the form n.y, where y is the name of the TCP connection
+ about which i represents information.
+
+ For example, suppose one wanted to find the state of a TCP connection
+ between the local address of 89.1.1.42 on TCP port 21 and the remote
+ address of 10.0.0.51 on TCP port 2059. Accordingly,
+ tcpConnState.89.1.1.42.21.10.0.0.51.2059 would identify the desired
+ instance.
+
+3.2.6.3.6. egpNeighTable Object Type Names
+
+ The name of an EGP neighbor, x, is the OBJECT IDENTIFIER of the form
+ a.b.c.d such that a.b.c.d is the value (in the familiar "dot"
+ notation) of that instance of the egpNeighAddr object type associated
+ with x.
+
+ For each object type, t, for which the defined name, n, has a prefix
+ of egpNeighEntry, an instance, i, of t is named by an OBJECT
+ IDENTIFIER of the form n.y, where y is the name of the EGP neighbor
+ about which i represents information.
+
+ For example, suppose one wanted to find the neighbor state for the IP
+ address of 89.1.1.42. Accordingly, egpNeighState.89.1.1.42 would
+ identify the desired instance.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 15]
+
+RFC 1157 SNMP May 1990
+
+
+4. Protocol Specification
+
+ The network management protocol is an application protocol by which
+ the variables of an agent's MIB may be inspected or altered.
+
+ Communication among protocol entities is accomplished by the exchange
+ of messages, each of which is entirely and independently represented
+ within a single UDP datagram using the basic encoding rules of ASN.1
+ (as discussed in Section 3.2.2). A message consists of a version
+ identifier, an SNMP community name, and a protocol data unit (PDU).
+ A protocol entity receives messages at UDP port 161 on the host with
+ which it is associated for all messages except for those which report
+ traps (i.e., all messages except those which contain the Trap-PDU).
+ Messages which report traps should be received on UDP port 162 for
+ further processing. An implementation of this protocol need not
+ accept messages whose length exceeds 484 octets. However, it is
+ recommended that implementations support larger datagrams whenever
+ feasible.
+
+ It is mandatory that all implementations of the SNMP support the five
+ PDUs: GetRequest-PDU, GetNextRequest-PDU, GetResponse-PDU,
+ SetRequest-PDU, and Trap-PDU.
+
+ RFC1157-SNMP DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ ObjectName, ObjectSyntax, NetworkAddress, IpAddress, TimeTicks
+ FROM RFC1155-SMI;
+
+
+ -- top-level message
+
+ Message ::=
+ SEQUENCE {
+ version -- version-1 for this RFC
+ INTEGER {
+ version-1(0)
+ },
+
+ community -- community name
+ OCTET STRING,
+
+ data -- e.g., PDUs if trivial
+ ANY -- authentication is being used
+ }
+
+
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 16]
+
+RFC 1157 SNMP May 1990
+
+
+ -- protocol data units
+
+ PDUs ::=
+ CHOICE {
+ get-request
+ GetRequest-PDU,
+
+ get-next-request
+ GetNextRequest-PDU,
+
+ get-response
+ GetResponse-PDU,
+
+ set-request
+ SetRequest-PDU,
+
+ trap
+ Trap-PDU
+ }
+
+ -- the individual PDUs and commonly used
+ -- data types will be defined later
+
+ END
+
+
+4.1. Elements of Procedure
+
+ This section describes the actions of a protocol entity implementing
+ the SNMP. Note, however, that it is not intended to constrain the
+ internal architecture of any conformant implementation.
+
+ In the text that follows, the term transport address is used. In the
+ case of the UDP, a transport address consists of an IP address along
+ with a UDP port. Other transport services may be used to support the
+ SNMP. In these cases, the definition of a transport address should
+ be made accordingly.
+
+ The top-level actions of a protocol entity which generates a message
+ are as follows:
+
+ (1) It first constructs the appropriate PDU, e.g., the
+ GetRequest-PDU, as an ASN.1 object.
+
+ (2) It then passes this ASN.1 object along with a community
+ name its source transport address and the destination
+ transport address, to the service which implements the
+ desired authentication scheme. This authentication
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 17]
+
+RFC 1157 SNMP May 1990
+
+
+ service returns another ASN.1 object.
+
+ (3) The protocol entity then constructs an ASN.1 Message
+ object, using the community name and the resulting ASN.1
+ object.
+
+ (4) This new ASN.1 object is then serialized, using the basic
+ encoding rules of ASN.1, and then sent using a transport
+ service to the peer protocol entity.
+
+ Similarly, the top-level actions of a protocol entity which receives
+ a message are as follows:
+
+ (1) It performs a rudimentary parse of the incoming datagram
+ to build an ASN.1 object corresponding to an ASN.1
+ Message object. If the parse fails, it discards the
+ datagram and performs no further actions.
+
+ (2) It then verifies the version number of the SNMP message.
+ If there is a mismatch, it discards the datagram and
+ performs no further actions.
+
+ (3) The protocol entity then passes the community name and
+ user data found in the ASN.1 Message object, along with
+ the datagram's source and destination transport addresses
+ to the service which implements the desired
+ authentication scheme. This entity returns another ASN.1
+ object, or signals an authentication failure. In the
+ latter case, the protocol entity notes this failure,
+ (possibly) generates a trap, and discards the datagram
+ and performs no further actions.
+
+ (4) The protocol entity then performs a rudimentary parse on
+ the ASN.1 object returned from the authentication service
+ to build an ASN.1 object corresponding to an ASN.1 PDUs
+ object. If the parse fails, it discards the datagram and
+ performs no further actions. Otherwise, using the named
+ SNMP community, the appropriate profile is selected, and
+ the PDU is processed accordingly. If, as a result of
+ this processing, a message is returned then the source
+ transport address that the response message is sent from
+ shall be identical to the destination transport address
+ that the original request message was sent to.
+
+
+
+
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 18]
+
+RFC 1157 SNMP May 1990
+
+
+4.1.1. Common Constructs
+
+ Before introducing the six PDU types of the protocol, it is
+ appropriate to consider some of the ASN.1 constructs used frequently:
+
+ -- request/response information
+
+ RequestID ::=
+ INTEGER
+
+ ErrorStatus ::=
+ INTEGER {
+ noError(0),
+ tooBig(1),
+ noSuchName(2),
+ badValue(3),
+ readOnly(4)
+ genErr(5)
+ }
+
+ ErrorIndex ::=
+ INTEGER
+
+
+ -- variable bindings
+
+ VarBind ::=
+ SEQUENCE {
+ name
+ ObjectName,
+
+ value
+ ObjectSyntax
+ }
+
+ VarBindList ::=
+ SEQUENCE OF
+ VarBind
+
+
+ RequestIDs are used to distinguish among outstanding requests. By
+ use of the RequestID, an SNMP application entity can correlate
+ incoming responses with outstanding requests. In cases where an
+ unreliable datagram service is being used, the RequestID also
+ provides a simple means of identifying messages duplicated by the
+ network.
+
+ A non-zero instance of ErrorStatus is used to indicate that an
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 19]
+
+RFC 1157 SNMP May 1990
+
+
+ exception occurred while processing a request. In these cases,
+ ErrorIndex may provide additional information by indicating which
+ variable in a list caused the exception.
+
+ The term variable refers to an instance of a managed object. A
+ variable binding, or VarBind, refers to the pairing of the name of a
+ variable to the variable's value. A VarBindList is a simple list of
+ variable names and corresponding values. Some PDUs are concerned
+ only with the name of a variable and not its value (e.g., the
+ GetRequest-PDU). In this case, the value portion of the binding is
+ ignored by the protocol entity. However, the value portion must
+ still have valid ASN.1 syntax and encoding. It is recommended that
+ the ASN.1 value NULL be used for the value portion of such bindings.
+
+4.1.2. The GetRequest-PDU
+
+ The form of the GetRequest-PDU is:
+ GetRequest-PDU ::=
+ [0]
+ IMPLICIT SEQUENCE {
+ request-id
+ RequestID,
+
+ error-status -- always 0
+ ErrorStatus,
+
+ error-index -- always 0
+ ErrorIndex,
+
+ variable-bindings
+ VarBindList
+ }
+
+
+ The GetRequest-PDU is generated by a protocol entity only at the
+ request of its SNMP application entity.
+
+ Upon receipt of the GetRequest-PDU, the receiving protocol entity
+ responds according to any applicable rule in the list below:
+
+ (1) If, for any object named in the variable-bindings field,
+ the object's name does not exactly match the name of some
+ object available for get operations in the relevant MIB
+ view, then the receiving entity sends to the originator
+ of the received message the GetResponse-PDU of identical
+ form, except that the value of the error-status field is
+ noSuchName, and the value of the error-index field is the
+ index of said object name component in the received
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 20]
+
+RFC 1157 SNMP May 1990
+
+
+ message.
+
+ (2) If, for any object named in the variable-bindings field,
+ the object is an aggregate type (as defined in the SMI),
+ then the receiving entity sends to the originator of the
+ received message the GetResponse-PDU of identical form,
+ except that the value of the error-status field is
+ noSuchName, and the value of the error-index field is the
+ index of said object name component in the received
+ message.
+
+ (3) If the size of the GetResponse-PDU generated as described
+ below would exceed a local limitation, then the receiving
+ entity sends to the originator of the received message
+ the GetResponse-PDU of identical form, except that the
+ value of the error-status field is tooBig, and the value
+ of the error-index field is zero.
+
+ (4) If, for any object named in the variable-bindings field,
+ the value of the object cannot be retrieved for reasons
+ not covered by any of the foregoing rules, then the
+ receiving entity sends to the originator of the received
+ message the GetResponse-PDU of identical form, except
+ that the value of the error-status field is genErr and
+ the value of the error-index field is the index of said
+ object name component in the received message.
+
+ If none of the foregoing rules apply, then the receiving protocol
+ entity sends to the originator of the received message the
+ GetResponse-PDU such that, for each object named in the variable-
+ bindings field of the received message, the corresponding component
+ of the GetResponse-PDU represents the name and value of that
+ variable. The value of the error- status field of the GetResponse-
+ PDU is noError and the value of the error-index field is zero. The
+ value of the request-id field of the GetResponse-PDU is that of the
+ received message.
+
+4.1.3. The GetNextRequest-PDU
+
+ The form of the GetNextRequest-PDU is identical to that of the
+ GetRequest-PDU except for the indication of the PDU type. In the
+ ASN.1 language:
+
+ GetNextRequest-PDU ::=
+ [1]
+ IMPLICIT SEQUENCE {
+ request-id
+ RequestID,
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 21]
+
+RFC 1157 SNMP May 1990
+
+
+ error-status -- always 0
+ ErrorStatus,
+
+ error-index -- always 0
+ ErrorIndex,
+
+ variable-bindings
+ VarBindList
+ }
+
+
+ The GetNextRequest-PDU is generated by a protocol entity only at the
+ request of its SNMP application entity.
+
+ Upon receipt of the GetNextRequest-PDU, the receiving protocol entity
+ responds according to any applicable rule in the list below:
+
+ (1) If, for any object name in the variable-bindings field,
+ that name does not lexicographically precede the name of
+ some object available for get operations in the relevant
+ MIB view, then the receiving entity sends to the
+ originator of the received message the GetResponse-PDU of
+ identical form, except that the value of the error-status
+ field is noSuchName, and the value of the error-index
+ field is the index of said object name component in the
+ received message.
+
+ (2) If the size of the GetResponse-PDU generated as described
+ below would exceed a local limitation, then the receiving
+ entity sends to the originator of the received message
+ the GetResponse-PDU of identical form, except that the
+ value of the error-status field is tooBig, and the value
+ of the error-index field is zero.
+
+ (3) If, for any object named in the variable-bindings field,
+ the value of the lexicographical successor to the named
+ object cannot be retrieved for reasons not covered by any
+ of the foregoing rules, then the receiving entity sends
+ to the originator of the received message the
+ GetResponse-PDU of identical form, except that the value
+ of the error-status field is genErr and the value of the
+ error-index field is the index of said object name
+ component in the received message.
+
+ If none of the foregoing rules apply, then the receiving protocol
+ entity sends to the originator of the received message the
+ GetResponse-PDU such that, for each name in the variable-bindings
+ field of the received message, the corresponding component of the
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 22]
+
+RFC 1157 SNMP May 1990
+
+
+ GetResponse-PDU represents the name and value of that object whose
+ name is, in the lexicographical ordering of the names of all objects
+ available for get operations in the relevant MIB view, together with
+ the value of the name field of the given component, the immediate
+ successor to that value. The value of the error-status field of the
+ GetResponse-PDU is noError and the value of the errorindex field is
+ zero. The value of the request-id field of the GetResponse-PDU is
+ that of the received message.
+
+4.1.3.1. Example of Table Traversal
+
+ One important use of the GetNextRequest-PDU is the traversal of
+ conceptual tables of information within the MIB. The semantics of
+ this type of SNMP message, together with the protocol-specific
+ mechanisms for identifying individual instances of object types in
+ the MIB, affords access to related objects in the MIB as if they
+ enjoyed a tabular organization.
+
+ By the SNMP exchange sketched below, an SNMP application entity might
+ extract the destination address and next hop gateway for each entry
+ in the routing table of a particular network element. Suppose that
+ this routing table has three entries:
+
+ Destination NextHop Metric
+
+ 10.0.0.99 89.1.1.42 5
+ 9.1.2.3 99.0.0.3 3
+ 10.0.0.51 89.1.1.42 5
+
+
+ The management station sends to the SNMP agent a GetNextRequest-PDU
+ containing the indicated OBJECT IDENTIFIER values as the requested
+ variable names:
+
+ GetNextRequest ( ipRouteDest, ipRouteNextHop, ipRouteMetric1 )
+
+
+ The SNMP agent responds with a GetResponse-PDU:
+
+ GetResponse (( ipRouteDest.9.1.2.3 = "9.1.2.3" ),
+ ( ipRouteNextHop.9.1.2.3 = "99.0.0.3" ),
+ ( ipRouteMetric1.9.1.2.3 = 3 ))
+
+
+ The management station continues with:
+
+ GetNextRequest ( ipRouteDest.9.1.2.3,
+ ipRouteNextHop.9.1.2.3,
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 23]
+
+RFC 1157 SNMP May 1990
+
+
+ ipRouteMetric1.9.1.2.3 )
+
+
+ The SNMP agent responds:
+
+ GetResponse (( ipRouteDest.10.0.0.51 = "10.0.0.51" ),
+ ( ipRouteNextHop.10.0.0.51 = "89.1.1.42" ),
+ ( ipRouteMetric1.10.0.0.51 = 5 ))
+
+
+ The management station continues with:
+
+ GetNextRequest ( ipRouteDest.10.0.0.51,
+ ipRouteNextHop.10.0.0.51,
+ ipRouteMetric1.10.0.0.51 )
+
+
+ The SNMP agent responds:
+
+ GetResponse (( ipRouteDest.10.0.0.99 = "10.0.0.99" ),
+ ( ipRouteNextHop.10.0.0.99 = "89.1.1.42" ),
+ ( ipRouteMetric1.10.0.0.99 = 5 ))
+
+
+ The management station continues with:
+
+ GetNextRequest ( ipRouteDest.10.0.0.99,
+ ipRouteNextHop.10.0.0.99,
+ ipRouteMetric1.10.0.0.99 )
+
+
+ As there are no further entries in the table, the SNMP agent returns
+ those objects that are next in the lexicographical ordering of the
+ known object names. This response signals the end of the routing
+ table to the management station.
+
+4.1.4. The GetResponse-PDU
+
+ The form of the GetResponse-PDU is identical to that of the
+ GetRequest-PDU except for the indication of the PDU type. In the
+ ASN.1 language:
+
+ GetResponse-PDU ::=
+ [2]
+ IMPLICIT SEQUENCE {
+ request-id
+ RequestID,
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 24]
+
+RFC 1157 SNMP May 1990
+
+
+ error-status
+ ErrorStatus,
+
+ error-index
+ ErrorIndex,
+
+ variable-bindings
+ VarBindList
+ }
+
+
+ The GetResponse-PDU is generated by a protocol entity only upon
+ receipt of the GetRequest-PDU, GetNextRequest-PDU, or SetRequest-PDU,
+ as described elsewhere in this document.
+
+ Upon receipt of the GetResponse-PDU, the receiving protocol entity
+ presents its contents to its SNMP application entity.
+
+4.1.5. The SetRequest-PDU
+
+ The form of the SetRequest-PDU is identical to that of the
+ GetRequest-PDU except for the indication of the PDU type. In the
+ ASN.1 language:
+
+ SetRequest-PDU ::=
+ [3]
+ IMPLICIT SEQUENCE {
+ request-id
+ RequestID,
+
+ error-status -- always 0
+ ErrorStatus,
+
+ error-index -- always 0
+ ErrorIndex,
+
+ variable-bindings
+ VarBindList
+ }
+
+
+ The SetRequest-PDU is generated by a protocol entity only at the
+ request of its SNMP application entity.
+
+ Upon receipt of the SetRequest-PDU, the receiving entity responds
+ according to any applicable rule in the list below:
+
+ (1) If, for any object named in the variable-bindings field,
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 25]
+
+RFC 1157 SNMP May 1990
+
+
+ the object is not available for set operations in the
+ relevant MIB view, then the receiving entity sends to the
+ originator of the received message the GetResponse-PDU of
+ identical form, except that the value of the error-status
+ field is noSuchName, and the value of the error-index
+ field is the index of said object name component in the
+ received message.
+
+ (2) If, for any object named in the variable-bindings field,
+ the contents of the value field does not, according to
+ the ASN.1 language, manifest a type, length, and value
+ that is consistent with that required for the variable,
+ then the receiving entity sends to the originator of the
+ received message the GetResponse-PDU of identical form,
+ except that the value of the error-status field is
+ badValue, and the value of the error-index field is the
+ index of said object name in the received message.
+
+ (3) If the size of the Get Response type message generated as
+ described below would exceed a local limitation, then the
+ receiving entity sends to the originator of the received
+ message the GetResponse-PDU of identical form, except
+ that the value of the error-status field is tooBig, and
+ the value of the error-index field is zero.
+
+ (4) If, for any object named in the variable-bindings field,
+ the value of the named object cannot be altered for
+ reasons not covered by any of the foregoing rules, then
+ the receiving entity sends to the originator of the
+ received message the GetResponse-PDU of identical form,
+ except that the value of the error-status field is genErr
+ and the value of the error-index field is the index of
+ said object name component in the received message.
+
+ If none of the foregoing rules apply, then for each object named in
+ the variable-bindings field of the received message, the
+ corresponding value is assigned to the variable. Each variable
+ assignment specified by the SetRequest-PDU should be effected as if
+ simultaneously set with respect to all other assignments specified in
+ the same message.
+
+ The receiving entity then sends to the originator of the received
+ message the GetResponse-PDU of identical form except that the value
+ of the error-status field of the generated message is noError and the
+ value of the error-index field is zero.
+
+
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 26]
+
+RFC 1157 SNMP May 1990
+
+
+4.1.6. The Trap-PDU
+
+ The form of the Trap-PDU is:
+
+ Trap-PDU ::=
+ [4]
+
+ IMPLICIT SEQUENCE {
+ enterprise -- type of object generating
+ -- trap, see sysObjectID in [5]
+ OBJECT IDENTIFIER,
+
+ agent-addr -- address of object generating
+ NetworkAddress, -- trap
+
+ generic-trap -- generic trap type
+ INTEGER {
+ coldStart(0),
+ warmStart(1),
+ linkDown(2),
+ linkUp(3),
+ authenticationFailure(4),
+ egpNeighborLoss(5),
+ enterpriseSpecific(6)
+ },
+
+ specific-trap -- specific code, present even
+ INTEGER, -- if generic-trap is not
+ -- enterpriseSpecific
+
+ time-stamp -- time elapsed between the last
+ TimeTicks, -- (re)initialization of the network
+ -- entity and the generation of the
+ trap
+
+ variable-bindings -- "interesting" information
+ VarBindList
+ }
+
+
+ The Trap-PDU is generated by a protocol entity only at the request of
+ the SNMP application entity. The means by which an SNMP application
+ entity selects the destination addresses of the SNMP application
+ entities is implementation-specific.
+
+ Upon receipt of the Trap-PDU, the receiving protocol entity presents
+ its contents to its SNMP application entity.
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 27]
+
+RFC 1157 SNMP May 1990
+
+
+ The significance of the variable-bindings component of the Trap-PDU
+ is implementation-specific.
+
+ Interpretations of the value of the generic-trap field are:
+
+4.1.6.1. The coldStart Trap
+
+ A coldStart(0) trap signifies that the sending protocol entity is
+ reinitializing itself such that the agent's configuration or the
+ protocol entity implementation may be altered.
+
+4.1.6.2. The warmStart Trap
+
+ A warmStart(1) trap signifies that the sending protocol entity is
+ reinitializing itself such that neither the agent configuration nor
+ the protocol entity implementation is altered.
+
+4.1.6.3. The linkDown Trap
+
+ A linkDown(2) trap signifies that the sending protocol entity
+ recognizes a failure in one of the communication links represented in
+ the agent's configuration.
+
+ The Trap-PDU of type linkDown contains as the first element of its
+ variable-bindings, the name and value of the ifIndex instance for the
+ affected interface.
+
+4.1.6.4. The linkUp Trap
+
+ A linkUp(3) trap signifies that the sending protocol entity
+ recognizes that one of the communication links represented in the
+ agent's configuration has come up.
+
+ The Trap-PDU of type linkUp contains as the first element of its
+ variable-bindings, the name and value of the ifIndex instance for the
+ affected interface.
+
+4.1.6.5. The authenticationFailure Trap
+
+ An authenticationFailure(4) trap signifies that the sending protocol
+ entity is the addressee of a protocol message that is not properly
+ authenticated. While implementations of the SNMP must be capable of
+ generating this trap, they must also be capable of suppressing the
+ emission of such traps via an implementation-specific mechanism.
+
+4.1.6.6. The egpNeighborLoss Trap
+
+ An egpNeighborLoss(5) trap signifies that an EGP neighbor for whom
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 28]
+
+RFC 1157 SNMP May 1990
+
+
+ the sending protocol entity was an EGP peer has been marked down and
+ the peer relationship no longer obtains.
+
+ The Trap-PDU of type egpNeighborLoss contains as the first element of
+ its variable-bindings, the name and value of the egpNeighAddr
+ instance for the affected neighbor.
+
+4.1.6.7. The enterpriseSpecific Trap
+
+ A enterpriseSpecific(6) trap signifies that the sending protocol
+ entity recognizes that some enterprise-specific event has occurred.
+ The specific-trap field identifies the particular trap which
+ occurred.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 29]
+
+RFC 1157 SNMP May 1990
+
+
+5. Definitions
+
+ RFC1157-SNMP DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ ObjectName, ObjectSyntax, NetworkAddress, IpAddress, TimeTicks
+ FROM RFC1155-SMI;
+
+
+ -- top-level message
+
+ Message ::=
+ SEQUENCE {
+ version -- version-1 for this RFC
+ INTEGER {
+ version-1(0)
+ },
+
+ community -- community name
+ OCTET STRING,
+
+ data -- e.g., PDUs if trivial
+ ANY -- authentication is being used
+ }
+
+
+ -- protocol data units
+
+ PDUs ::=
+ CHOICE {
+ get-request
+ GetRequest-PDU,
+
+ get-next-request
+ GetNextRequest-PDU,
+
+ get-response
+ GetResponse-PDU,
+
+ set-request
+ SetRequest-PDU,
+
+ trap
+ Trap-PDU
+ }
+
+
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 30]
+
+RFC 1157 SNMP May 1990
+
+
+ -- PDUs
+
+ GetRequest-PDU ::=
+ [0]
+ IMPLICIT PDU
+
+ GetNextRequest-PDU ::=
+ [1]
+ IMPLICIT PDU
+
+ GetResponse-PDU ::=
+ [2]
+ IMPLICIT PDU
+
+ SetRequest-PDU ::=
+ [3]
+ IMPLICIT PDU
+
+ PDU ::=
+ SEQUENCE {
+ request-id
+ INTEGER,
+
+ error-status -- sometimes ignored
+ INTEGER {
+ noError(0),
+ tooBig(1),
+ noSuchName(2),
+ badValue(3),
+ readOnly(4),
+ genErr(5)
+ },
+
+ error-index -- sometimes ignored
+ INTEGER,
+
+ variable-bindings -- values are sometimes ignored
+ VarBindList
+ }
+
+ Trap-PDU ::=
+ [4]
+ IMPLICIT SEQUENCE {
+ enterprise -- type of object generating
+ -- trap, see sysObjectID in [5]
+
+
+ OBJECT IDENTIFIER,
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 31]
+
+RFC 1157 SNMP May 1990
+
+
+ agent-addr -- address of object generating
+ NetworkAddress, -- trap
+
+ generic-trap -- generic trap type
+ INTEGER {
+ coldStart(0),
+ warmStart(1),
+ linkDown(2),
+ linkUp(3),
+ authenticationFailure(4),
+ egpNeighborLoss(5),
+ enterpriseSpecific(6)
+ },
+
+ specific-trap -- specific code, present even
+ INTEGER, -- if generic-trap is not
+ -- enterpriseSpecific
+
+ time-stamp -- time elapsed between the last
+ TimeTicks, -- (re)initialization of the
+ network
+ -- entity and the generation of the
+ trap
+
+ variable-bindings -- "interesting" information
+ VarBindList
+ }
+
+
+ -- variable bindings
+
+ VarBind ::=
+ SEQUENCE {
+ name
+ ObjectName,
+
+ value
+ ObjectSyntax
+ }
+
+ VarBindList ::=
+ SEQUENCE OF
+ VarBind
+
+ END
+
+
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 32]
+
+RFC 1157 SNMP May 1990
+
+
+6. Acknowledgements
+
+ This memo was influenced by the IETF SNMP Extensions working
+ group:
+
+ Karl Auerbach, Epilogue Technology
+ K. Ramesh Babu, Excelan
+ Amatzia Ben-Artzi, 3Com/Bridge
+ Lawrence Besaw, Hewlett-Packard
+ Jeffrey D. Case, University of Tennessee at Knoxville
+ Anthony Chung, Sytek
+ James Davidson, The Wollongong Group
+ James R. Davin, MIT Laboratory for Computer Science
+ Mark S. Fedor, NYSERNet
+ Phill Gross, The MITRE Corporation
+ Satish Joshi, ACC
+ Dan Lynch, Advanced Computing Environments
+ Keith McCloghrie, The Wollongong Group
+ Marshall T. Rose, The Wollongong Group (chair)
+ Greg Satz, cisco
+ Martin Lee Schoffstall, Rensselaer Polytechnic Institute
+ Wengyik Yeong, NYSERNet
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 33]
+
+RFC 1157 SNMP May 1990
+
+
+7. References
+
+ [1] Cerf, V., "IAB Recommendations for the Development of
+ Internet Network Management Standards", RFC 1052, IAB,
+ April 1988.
+
+ [2] Rose, M., and K. McCloghrie, "Structure and Identification
+ of Management Information for TCP/IP-based internets",
+ RFC 1065, TWG, August 1988.
+
+ [3] McCloghrie, K., and M. Rose, "Management Information Base
+ for Network Management of TCP/IP-based internets",
+ RFC 1066, TWG, August 1988.
+
+ [4] Cerf, V., "Report of the Second Ad Hoc Network Management
+ Review Group", RFC 1109, IAB, August 1989.
+
+ [5] Rose, M., and K. McCloghrie, "Structure and Identification
+ of Management Information for TCP/IP-based Internets",
+ RFC 1155, Performance Systems International and Hughes LAN
+ Systems, May 1990.
+
+ [6] McCloghrie, K., and M. Rose, "Management Information Base
+ for Network Management of TCP/IP-based Internets",
+ RFC 1156, Hughes LAN Systems and Performance Systems
+ International, May 1990.
+
+ [7] Case, J., M. Fedor, M. Schoffstall, and J. Davin,
+ "A Simple Network Management Protocol", Internet
+ Engineering Task Force working note, Network Information
+ Center, SRI International, Menlo Park, California,
+ March 1988.
+
+ [8] Davin, J., J. Case, M. Fedor, and M. Schoffstall,
+ "A Simple Gateway Monitoring Protocol", RFC 1028,
+ Proteon, University of Tennessee at Knoxville,
+ Cornell University, and Rensselaer Polytechnic
+ Institute, November 1987.
+
+ [9] Information processing systems - Open Systems
+ Interconnection, "Specification of Abstract Syntax
+ Notation One (ASN.1)", International Organization for
+ Standardization, International Standard 8824,
+ December 1987.
+
+ [10] Information processing systems - Open Systems
+ Interconnection, "Specification of Basic Encoding Rules
+ for Abstract Notation One (ASN.1)", International
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 34]
+
+RFC 1157 SNMP May 1990
+
+
+ Organization for Standardization, International Standard
+ 8825, December 1987.
+
+ [11] Postel, J., "User Datagram Protocol", RFC 768,
+ USC/Information Sciences Institute, November 1980.
+
+Security Considerations
+
+ Security issues are not discussed in this memo.
+
+Authors' Addresses
+
+ Jeffrey D. Case
+ SNMP Research
+ P.O. Box 8593
+ Knoxville, TN 37996-4800
+
+ Phone: (615) 573-1434
+
+ Email: case@CS.UTK.EDU
+
+
+ Mark Fedor
+ Performance Systems International
+ Rensselaer Technology Park
+ 125 Jordan Road
+ Troy, NY 12180
+
+ Phone: (518) 283-8860
+
+ Email: fedor@patton.NYSER.NET
+
+
+ Martin Lee Schoffstall
+ Performance Systems International
+ Rensselaer Technology Park
+ 165 Jordan Road
+ Troy, NY 12180
+
+ Phone: (518) 283-8860
+
+ Email: schoff@NISC.NYSER.NET
+
+
+
+
+
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 35]
+
+RFC 1157 SNMP May 1990
+
+
+ James R. Davin
+ MIT Laboratory for Computer Science, NE43-507
+ 545 Technology Square
+ Cambridge, MA 02139
+
+ Phone: (617) 253-6020
+
+ EMail: jrd@ptt.lcs.mit.edu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Case, Fedor, Schoffstall, & Davin [Page 36]
+ \ No newline at end of file
diff --git a/standards/rfc1179.txt b/standards/rfc1179.txt
new file mode 100644
index 000000000..ef59411f7
--- /dev/null
+++ b/standards/rfc1179.txt
@@ -0,0 +1,787 @@
+
+
+
+
+
+
+Network Printing Working Group L. McLaughlin III, Editor
+Request for Comments: 1179 The Wollongong Group
+ August 1990
+
+
+ Line Printer Daemon Protocol
+
+Status of this Memo
+
+ This RFC describes an existing print server protocol widely used on
+ the Internet for communicating between line printer daemons (both
+ clients and servers). This memo is for informational purposes only,
+ and does not specify an Internet standard. Please refer to the
+ current edition of the "IAB Official Protocol Standards" for the
+ standardization state and status of this protocol. Distribution of
+ this memo is unlimited.
+
+1. Introduction
+
+ The Berkeley versions of the Unix(tm) operating system provide line
+ printer spooling with a collection of programs: lpr (assign to
+ queue), lpq (display the queue), lprm (remove from queue), and lpc
+ (control the queue). These programs interact with an autonomous
+ process called the line printer daemon. This RFC describes the
+ protocols with which a line printer daemon client may control
+ printing.
+
+ This memo is based almost entirely on the work of Robert Knight at
+ Princeton University. I gratefully acknowledge his efforts in
+ deciphering the UNIX lpr protocol and producing earlier versions of
+ this document.
+
+2. Model of Printing Environment
+
+ A group of hosts request services from a line printer daemon process
+ running on a host. The services provided by the process are related
+ to printing jobs. A printing job produces output from one file.
+ Each job will have a unique job number which is between 0 and 999,
+ inclusive. The jobs are requested by users which have names. These
+ user names may not start with a digit.
+
+3. Specification of the Protocol
+
+ The specification includes file formats for the control and data
+ files as well as messages used by the protocol.
+
+
+
+
+
+
+McLaughlin [Page 1]
+
+RFC 1179 LPR August 1990
+
+
+3.1 Message formats
+
+ LPR is a a TCP-based protocol. The port on which a line printer
+ daemon listens is 515. The source port must be in the range 721 to
+ 731, inclusive. A line printer daemon responds to commands send to
+ its port. All commands begin with a single octet code, which is a
+ binary number which represents the requested function. The code is
+ immediately followed by the ASCII name of the printer queue name on
+ which the function is to be performed. If there are other operands
+ to the command, they are separated from the printer queue name with
+ white space (ASCII space, horizontal tab, vertical tab, and form
+ feed). The end of the command is indicated with an ASCII line feed
+ character.
+
+4. Diagram Conventions
+
+ The diagrams in the rest of this RFC use these conventions. These
+ diagrams show the format of an octet stream sent to the server. The
+ outermost box represents this stream. Each box within the outermost
+ one shows one portion of the stream. If the contents of the box is
+ two decimal digits, this indicates that the binary 8 bit value is to
+ be used. If the contents is two uppercase letters, this indicates
+ that the corresponding ASCII control character is to be used. An
+ exception to this is that the character SP can be interpreted as
+ white space. (See the preceding section for a definition.) If the
+ contents is a single letter, the ASCII code for this letter must be
+ sent. Otherwise, the contents are intended to be mnemonic of the
+ contents of the field which is a sequence of octets.
+
+5. Daemon commands
+
+ The verbs in the command names should be interpreted as statements
+ made to the daemon. Thus, the command "Print any waiting jobs" is an
+ imperative to the line printer daemon to which it is sent. A new
+ connection must be made for each command to be given to the daemon.
+
+5.1 01 - Print any waiting jobs
+
+ +----+-------+----+
+ | 01 | Queue | LF |
+ +----+-------+----+
+ Command code - 1
+ Operand - Printer queue name
+
+ This command starts the printing process if it not already running.
+
+
+
+
+
+
+McLaughlin [Page 2]
+
+RFC 1179 LPR August 1990
+
+
+5.2 02 - Receive a printer job
+
+ +----+-------+----+
+ | 02 | Queue | LF |
+ +----+-------+----+
+ Command code - 2
+ Operand - Printer queue name
+
+ Receiving a job is controlled by a second level of commands. The
+ daemon is given commands by sending them over the same connection.
+ The commands are described in the next section (6).
+
+ After this command is sent, the client must read an acknowledgement
+ octet from the daemon. A positive acknowledgement is an octet of
+ zero bits. A negative acknowledgement is an octet of any other
+ pattern.
+
+5.3 03 - Send queue state (short)
+
+ +----+-------+----+------+----+
+ | 03 | Queue | SP | List | LF |
+ +----+-------+----+------+----+
+ Command code - 3
+ Operand 1 - Printer queue name
+ Other operands - User names or job numbers
+
+ If the user names or job numbers or both are supplied then only those
+ jobs for those users or with those numbers will be sent.
+
+ The response is an ASCII stream which describes the printer queue.
+ The stream continues until the connection closes. Ends of lines are
+ indicated with ASCII LF control characters. The lines may also
+ contain ASCII HT control characters.
+
+5.4 04 - Send queue state (long)
+
+ +----+-------+----+------+----+
+ | 04 | Queue | SP | List | LF |
+ +----+-------+----+------+----+
+ Command code - 4
+ Operand 1 - Printer queue name
+ Other operands - User names or job numbers
+
+ If the user names or job numbers or both are supplied then only those
+ jobs for those users or with those numbers will be sent.
+
+ The response is an ASCII stream which describes the printer queue.
+ The stream continues until the connection closes. Ends of lines are
+
+
+
+McLaughlin [Page 3]
+
+RFC 1179 LPR August 1990
+
+
+ indicated with ASCII LF control characters. The lines may also
+ contain ASCII HT control characters.
+
+5.5 05 - Remove jobs
+
+ +----+-------+----+-------+----+------+----+
+ | 05 | Queue | SP | Agent | SP | List | LF |
+ +----+-------+----+-------+----+------+----+
+ Command code - 5
+ Operand 1 - Printer queue name
+ Operand 2 - User name making request (the agent)
+ Other operands - User names or job numbers
+
+ This command deletes the print jobs from the specified queue which
+ are listed as the other operands. If only the agent is given, the
+ command is to delete the currently active job. Unless the agent is
+ "root", it is not possible to delete a job which is not owned by the
+ user. This is also the case for specifying user names instead of
+ numbers. That is, agent "root" can delete jobs by user name but no
+ other agents can.
+
+6. Receive job subcommands
+
+ These commands are processed when the line printer daemon has
+ been given the receive job command. The daemon will continue to
+ process commands until the connection is closed.
+
+ After a subcommand is sent, the client must wait for an
+ acknowledgement from the daemon. A positive acknowledgement is an
+ octet of zero bits. A negative acknowledgement is an octet of any
+ other pattern.
+
+ LPR clients SHOULD be able to sent the receive data file and receive
+ control file subcommands in either order. LPR servers MUST be able
+ to receive the control file subcommand first and SHOULD be able to
+ receive the data file subcommand first.
+
+6.1 01 - Abort job
+
+ Command code - 1
+ +----+----+
+ | 01 | LF |
+ +----+----+
+
+ No operands should be supplied. This subcommand will remove any
+ files which have been created during this "Receive job" command.
+
+
+
+
+
+McLaughlin [Page 4]
+
+RFC 1179 LPR August 1990
+
+
+6.2 02 - Receive control file
+
+ +----+-------+----+------+----+
+ | 02 | Count | SP | Name | LF |
+ +----+-------+----+------+----+
+ Command code - 2
+ Operand 1 - Number of bytes in control file
+ Operand 2 - Name of control file
+
+ The control file must be an ASCII stream with the ends of lines
+ indicated by ASCII LF. The total number of bytes in the stream is
+ sent as the first operand. The name of the control file is sent as
+ the second. It should start with ASCII "cfA", followed by a three
+ digit job number, followed by the host name which has constructed the
+ control file. Acknowledgement processing must occur as usual after
+ the command is sent.
+
+ The next "Operand 1" octets over the same TCP connection are the
+ intended contents of the control file. Once all of the contents have
+ been delivered, an octet of zero bits is sent as an indication that
+ the file being sent is complete. A second level of acknowledgement
+ processing must occur at this point.
+
+6.3 03 - Receive data file
+
+ +----+-------+----+------+----+
+ | 03 | Count | SP | Name | LF |
+ +----+-------+----+------+----+
+ Command code - 3
+ Operand 1 - Number of bytes in data file
+ Operand 2 - Name of data file
+
+ The data file may contain any 8 bit values at all. The total number
+ of bytes in the stream may be sent as the first operand, otherwise
+ the field should be cleared to 0. The name of the data file should
+ start with ASCII "dfA". This should be followed by a three digit job
+ number. The job number should be followed by the host name which has
+ constructed the data file. Interpretation of the contents of the
+ data file is determined by the contents of the corresponding control
+ file. If a data file length has been specified, the next "Operand 1"
+ octets over the same TCP connection are the intended contents of the
+ data file. In this case, once all of the contents have been
+ delivered, an octet of zero bits is sent as an indication that the
+ file being sent is complete. A second level of acknowledgement
+ processing must occur at this point.
+
+
+
+
+
+
+McLaughlin [Page 5]
+
+RFC 1179 LPR August 1990
+
+
+7. Control file lines
+
+ This section discusses the format of the lines in the control file
+ which is sent to the line printer daemon.
+
+ Each line of the control file consists of a single, printable ASCII
+ character which represents a function to be performed when the file
+ is printed. Interpretation of these command characters are case-
+ sensitive. The rest of the line after the command character is the
+ command's operand. No leading white space is permitted after the
+ command character. The line ends with an ASCII new line.
+
+ Those commands which have a lower case letter as a command code are
+ used to specify an actual printing request. The commands which use
+ upper case are used to describe parametric values or background
+ conditions.
+
+ Some commands must be included in every control file. These are 'H'
+ (responsible host) and 'P' (responsible user). Additionally, there
+ must be at least one lower case command to produce any output.
+
+7.1 C - Class for banner page
+
+ +---+-------+----+
+ | C | Class | LF |
+ +---+-------+----+
+ Command code - 'C'
+ Operand - Name of class for banner pages
+
+ This command sets the class name to be printed on the banner page.
+ The name must be 31 or fewer octets. The name can be omitted. If it
+ is, the name of the host on which the file is printed will be used.
+ The class is conventionally used to display the host from which the
+ printing job originated. It will be ignored unless the print banner
+ command ('L') is also used.
+
+7.2 H - Host name
+
+ +---+------+----+
+ | H | Host | LF |
+ +---+------+----+
+ Command code - 'H'
+ Operand - Name of host
+
+ This command specifies the name of the host which is to be treated as
+ the source of the print job. The command must be included in the
+ control file. The name of the host must be 31 or fewer octets.
+
+
+
+
+McLaughlin [Page 6]
+
+RFC 1179 LPR August 1990
+
+
+7.3 I - Indent Printing
+
+ +---+-------+----+
+ | I | count | LF |
+ +---+-------+----+
+ Command code - 'I'
+ Operand - Indenting count
+
+ This command specifies that, for files which are printed with the
+ 'f', of columns given. (It is ignored for other output generating
+ commands.) The identing count operand must be all decimal digits.
+
+7.4 J - Job name for banner page
+
+ +---+----------+----+
+ | J | Job name | LF |
+ +---+----------+----+
+ Command code - 'J'
+ Operand - Job name
+
+ This command sets the job name to be printed on the banner page. The
+ name of the job must be 99 or fewer octets. It can be omitted. The
+ job name is conventionally used to display the name of the file or
+ files which were "printed". It will be ignored unless the print
+ banner command ('L') is also used.
+
+7.5 L - Print banner page
+
+ +---+------+----+
+ | L | User | LF |
+ +---+------+----+
+ Command code - 'L'
+ Operand - Name of user for burst pages
+
+ This command causes the banner page to be printed. The user name can
+ be omitted. The class name for banner page and job name for banner
+ page commands must precede this command in the control file to be
+ effective.
+
+7.6 M - Mail When Printed
+
+ +---+------+----+
+ | M | user | LF |
+ +---+------+----+
+ Command code - 'M'
+ Operand - User name
+
+ This entry causes mail to be sent to the user given as the operand at
+
+
+
+McLaughlin [Page 7]
+
+RFC 1179 LPR August 1990
+
+
+ the host specified by the 'H' entry when the printing operation ends
+ (successfully or unsuccessfully).
+
+7.7 N - Name of source file
+
+ +---+------+----+
+ | N | Name | LF |
+ +---+------+----+
+ Command code - 'N'
+ Operand - File name
+
+ This command specifies the name of the file from which the data file
+ was constructed. It is returned on a query and used in printing with
+ the 'p' command when no title has been given. It must be 131 or
+ fewer octets.
+
+7.8 P - User identification
+
+ +---+------+----+
+ | P | Name | LF |
+ +---+------+----+
+ Command code - 'P'
+ Operand - User id
+
+ This command specifies the user identification of the entity
+ requesting the printing job. This command must be included in the
+ control file. The user identification must be 31 or fewer octets.
+
+7.9 S - Symbolic link data
+
+ +---+--------+----+-------+----+
+ | S | device | SP | inode | LF |
+ +---+--------+----+-------+----+
+ Command code - 'S'
+ Operand 1 - Device number
+ Operand 2 - Inode number
+
+ This command is used to record symbolic link data on a Unix system so
+ that changing a file's directory entry after a file is printed will
+ not print the new file. It is ignored if the data file is not
+ symbolically linked.
+
+
+
+
+
+
+
+
+
+
+McLaughlin [Page 8]
+
+RFC 1179 LPR August 1990
+
+
+7.10 T - Title for pr
+
+ +---+-------+----+
+ | T | title | LF |
+ +---+-------+----+
+ Command code - 'T'
+ Operand - Title text
+
+ This command provides a title for a file which is to be printed with
+ either the 'p' command. (It is ignored by all of the other printing
+ commands.) The title must be 79 or fewer octets.
+
+7.11 U - Unlink data file
+
+ +---+------+----+
+ | U | file | LF |
+ +---+------+----+
+ Command code - 'U'
+ Operand - File to unlink
+
+ This command indicates that the specified file is no longer needed.
+ This should only be used for data files.
+
+7.12 W - Width of output
+
+ +---+-------+----+
+ | W | width | LF |
+ +---+-------+----+
+ Command code - 'W'
+ Operand - Width count
+
+ This command limits the output to the specified number of columns for
+ the 'f', 'l', and 'p' commands. (It is ignored for other output
+ generating commands.) The width count operand must be all decimal
+ digits. It may be silently reduced to some lower value. The default
+ value for the width is 132.
+
+7.13 1 - troff R font
+
+ +---+------+----+
+ | 1 | file | LF |
+ +---+------+----+
+ Command code - '1'
+ Operand - File name
+
+ This command specifies the file name for the troff R font. [1] This
+ is the font which is printed using Times Roman by default.
+
+
+
+
+McLaughlin [Page 9]
+
+RFC 1179 LPR August 1990
+
+
+7.14 2 - troff I font
+
+ +---+------+----+
+ | 2 | file | LF |
+ +---+------+----+
+ Command code - '2'
+ Operand - File name
+
+ This command specifies the file name for the troff I font. [1] This
+ is the font which is printed using Times Italic by default.
+
+7.15 3 - troff B font
+
+ +---+------+----+
+ | 3 | file | LF |
+ +---+------+----+
+ Command code - '3'
+ Operand - File name
+
+ This command specifies the file name for the troff B font. [1] This
+ is the font which is printed using Times Bold by default.
+
+7.16 4 - troff S font
+
+ +---+------+----+
+ | 4 | file | LF |
+ +---+------+----+
+ Command code - '4'
+ Operand - File name
+
+ This command specifies the file name for the troff S font. [1] This
+ is the font which is printed using Special Mathematical Font by
+ default.
+
+7.17 c - Plot CIF file
+
+ +---+------+----+
+ | c | file | LF |
+ +---+------+----+
+ Command code - 'c'
+ Operand - File to plot
+
+ This command causes the data file to be plotted, treating the data as
+ CIF (CalTech Intermediate Form) graphics language. [2]
+
+
+
+
+
+
+
+McLaughlin [Page 10]
+
+RFC 1179 LPR August 1990
+
+
+7.18 d - Print DVI file
+
+ +---+------+----+
+ | d | file | LF |
+ +---+------+----+
+ Command code - 'd'
+ Operand - File to print
+
+ This command causes the data file to be printed, treating the data as
+ DVI (TeX output). [3]
+
+7.19 f - Print formatted file
+
+ +---+------+----+
+ | f | file | LF |
+ +---+------+----+
+ Command code - 'f'
+ Operand - File to print
+
+ This command cause the data file to be printed as a plain text file,
+ providing page breaks as necessary. Any ASCII control characters
+ which are not in the following list are discarded: HT, CR, FF, LF,
+ and BS.
+
+7.20 g - Plot file
+
+ +---+------+----+
+ | g | file | LF |
+ +---+------+----+
+ Command code - 'g'
+ Operand - File to plot
+
+ This command causes the data file to be plotted, treating the data as
+ output from the Berkeley Unix plot library. [1]
+
+7.21 k - Reserved for use by Kerberized LPR clients and servers.
+
+7.22 l - Print file leaving control characters
+
+ +---+------+----+
+ | l | file | LF |
+ +---+------+----+
+ Command code - 'l' (lower case L)
+ Operand - File to print
+
+ This command causes the specified data file to printed without
+ filtering the control characters (as is done with the 'f' command).
+
+
+
+
+McLaughlin [Page 11]
+
+RFC 1179 LPR August 1990
+
+
+7.23 n - Print ditroff output file
+
+ +---+------+----+
+ | n | file | LF |
+ +---+------+----+
+ Command code - 'n'
+ Operand - File to print
+
+ This command prints the data file to be printed, treating the data as
+ ditroff output. [4]
+
+7.24 o - Print Postscript output file
+
+ +---+------+----+
+ | o | file | LF |
+ +---+------+----+
+ Command code - 'o'
+ Operand - File to print
+
+ This command prints the data file to be printed, treating the data as
+ standard Postscript input.
+
+7.25 p - Print file with 'pr' format
+
+ +---+------+----+
+ | p | file | LF |
+ +---+------+----+
+ Command code - 'p'
+ Operand - File to print
+
+ This command causes the data file to be printed with a heading, page
+ numbers, and pagination. The heading should include the date and
+ time that printing was started, the title, and a page number
+ identifier followed by the page number. The title is the name of
+ file as specified by the 'N' command, unless the 'T' command (title)
+ has been given. After a page of text has been printed, a new page is
+ started with a new page number. (There is no way to specify the
+ length of the page.)
+
+7.26 r - File to print with FORTRAN carriage control
+
+ +---+------+----+
+ | r | file | LF |
+ +---+------+----+
+ Command code - 'r'
+ Operand - File to print
+
+ This command causes the data file to be printed, interpreting the
+
+
+
+McLaughlin [Page 12]
+
+RFC 1179 LPR August 1990
+
+
+ first column of each line as FORTRAN carriage control. The FORTRAN
+ standard limits this to blank, "1", "0", and "+" carriage controls.
+ Most FORTRAN programmers also expect "-" (triple space) to work as
+ well.
+
+7.27 t - Print troff output file
+
+ +---+------+----+
+ | t | file | LF |
+ +---+------+----+
+ Command code - 't'
+ Operand - File to print
+
+ This command prints the data file as Graphic Systems C/A/T
+ phototypesetter input. [5] This is the standard output of the Unix
+ "troff" command.
+
+7.28 v - Print raster file
+
+ +---+------+----+
+ | v | file | LF |
+ +---+------+----+
+ Command code - 'v'
+ Operand - File to print
+
+ This command prints a Sun raster format file. [6]
+
+7.29 z - Reserved for future use with the Palladium print system.
+
+REFERENCES and BIBLIOGRAPHY
+
+ [1] Computer Science Research Group, "UNIX Programmer's Reference
+ Manual", USENIX, 1986.
+
+ [2] Hon and Sequin, "A Guide to LSI Implementation", XEROX PARC,
+ 1980.
+
+ [3] Knuth, D., "TeX The Program".
+
+ [4] Kernighan, B., "A Typesetter-independent TROFF".
+
+ [5] "Model C/A/T Phototypesetter", Graphic Systems, Inc. Hudson, N.H.
+
+ [6] Sun Microsystems, "Pixrect Reference Manual", Sun Microsystems,
+ Mountain View, CA, 1988.
+
+
+
+
+
+
+McLaughlin [Page 13]
+
+RFC 1179 LPR August 1990
+
+
+Security Considerations
+
+ Security issues are not discussed in this memo.
+
+Author's Address
+
+ Leo J. McLaughlin III
+ The Wollongong Group
+ 1129 San Antonio Road
+ Palo Alto, CA 94303
+
+ Phone: 415-962-7100
+
+ EMail: ljm@twg.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+McLaughlin [Page 14]
+ \ No newline at end of file
diff --git a/standards/rfc1213.txt b/standards/rfc1213.txt
new file mode 100644
index 000000000..50a26f54f
--- /dev/null
+++ b/standards/rfc1213.txt
@@ -0,0 +1,3923 @@
+
+
+
+
+
+
+Network Working Group K. McCloghrie
+Request for Comments: 1213 Hughes LAN Systems, Inc.
+Obsoletes: RFC 1158 M. Rose
+ Performance Systems International
+ Editors
+ March 1991
+
+
+ Management Information Base for Network Management
+ of TCP/IP-based internets:
+ MIB-II
+
+Status of this Memo
+
+ This memo defines the second version of the Management Information
+ Base (MIB-II) for use with network management protocols in TCP/IP-
+ based internets. This RFC specifies an IAB standards track protocol
+ for the Internet community, and requests discussion and suggestions
+ for improvements. Please refer to the current edition of the "IAB
+ Official Protocol Standards" for the standardization state and status
+ of this protocol. Distribution of this memo is unlimited.
+
+Table of Contents
+
+ 1. Abstract............................................... 2
+ 2. Introduction .......................................... 2
+ 3. Changes from RFC 1156 ................................. 3
+ 3.1 Deprecated Objects ................................... 3
+ 3.2 Display Strings ...................................... 4
+ 3.3 Physical Addresses ................................... 4
+ 3.4 The System Group ..................................... 5
+ 3.5 The Interfaces Group ................................. 5
+ 3.6 The Address Translation Group ........................ 6
+ 3.7 The IP Group ......................................... 6
+ 3.8 The ICMP Group ....................................... 7
+ 3.9 The TCP Group ........................................ 7
+ 3.10 The UDP Group ....................................... 7
+ 3.11 The EGP Group ....................................... 7
+ 3.12 The Transmission Group .............................. 8
+ 3.13 The SNMP Group ...................................... 8
+ 3.14 Changes from RFC 1158 ................. ............. 9
+ 4. Objects ............................................... 10
+ 4.1 Format of Definitions ................................ 10
+ 5. Overview .............................................. 10
+ 6. Definitions ........................................... 12
+ 6.1 Textual Conventions .................................. 12
+ 6.2 Groups in MIB-II ..................................... 13
+ 6.3 The System Group ..................................... 13
+
+
+
+SNMP Working Group [Page 1]
+
+RFC 1213 MIB-II March 1991
+
+
+ 6.4 The Interfaces Group ................................. 16
+ 6.5 The Address Translation Group ........................ 23
+ 6.6 The IP Group ......................................... 26
+ 6.7 The ICMP Group ....................................... 41
+ 6.8 The TCP Group ........................................ 46
+ 6.9 The UDP Group ........................................ 52
+ 6.10 The EGP Group ....................................... 54
+ 6.11 The Transmission Group .............................. 60
+ 6.12 The SNMP Group ...................................... 60
+ 7. Acknowledgements ...................................... 67
+ 8. References ............................................ 69
+ 9. Security Considerations ............................... 70
+ 10. Authors' Addresses ................................... 70
+
+1. Abstract
+
+ This memo defines the second version of the Management Information
+ Base (MIB-II) for use with network management protocols in TCP/IP-
+ based internets. In particular, together with its companion memos
+ which describe the structure of management information (RFC 1155)
+ along with the network management protocol (RFC 1157) for TCP/IP-
+ based internets, these documents provide a simple, workable
+ architecture and system for managing TCP/IP-based internets and in
+ particular the Internet community.
+
+2. Introduction
+
+ As reported in RFC 1052, IAB Recommendations for the Development of
+ Internet Network Management Standards [1], a two-prong strategy for
+ network management of TCP/IP-based internets was undertaken. In the
+ short-term, the Simple Network Management Protocol (SNMP) was to be
+ used to manage nodes in the Internet community. In the long-term,
+ the use of the OSI network management framework was to be examined.
+ Two documents were produced to define the management information: RFC
+ 1065, which defined the Structure of Management Information (SMI)
+ [2], and RFC 1066, which defined the Management Information Base
+ (MIB) [3]. Both of these documents were designed so as to be
+ compatible with both the SNMP and the OSI network management
+ framework.
+
+ This strategy was quite successful in the short-term: Internet-based
+ network management technology was fielded, by both the research and
+ commercial communities, within a few months. As a result of this,
+ portions of the Internet community became network manageable in a
+ timely fashion.
+
+ As reported in RFC 1109, Report of the Second Ad Hoc Network
+ Management Review Group [4], the requirements of the SNMP and the OSI
+
+
+
+SNMP Working Group [Page 2]
+
+RFC 1213 MIB-II March 1991
+
+
+ network management frameworks were more different than anticipated.
+ As such, the requirement for compatibility between the SMI/MIB and
+ both frameworks was suspended. This action permitted the operational
+ network management framework, the SNMP, to respond to new operational
+ needs in the Internet community by producing this document.
+
+ As such, the current network management framework for TCP/IP- based
+ internets consists of: Structure and Identification of Management
+ Information for TCP/IP-based internets, RFC 1155 [12], which
+ describes how managed objects contained in the MIB are defined;
+ Management Information Base for Network Management of TCP/IP-based
+ internets: MIB-II, this memo, which describes the managed objects
+ contained in the MIB (and supercedes RFC 1156 [13]); and, the Simple
+ Network Management Protocol, RFC 1098 [5], which defines the protocol
+ used to manage these objects.
+
+3. Changes from RFC 1156
+
+ Features of this MIB include:
+
+ (1) incremental additions to reflect new operational
+ requirements;
+
+ (2) upwards compatibility with the SMI/MIB and the SNMP;
+
+ (3) improved support for multi-protocol entities; and,
+
+ (4) textual clean-up of the MIB to improve clarity and
+ readability.
+
+ The objects defined in MIB-II have the OBJECT IDENTIFIER prefix:
+
+ mib-2 OBJECT IDENTIFIER ::= { mgmt 1 }
+
+ which is identical to the prefix used in MIB-I.
+
+3.1. Deprecated Objects
+
+ In order to better prepare implementors for future changes in the
+ MIB, a new term "deprecated" may be used when describing an object.
+ A deprecated object in the MIB is one which must be supported, but
+ one which will most likely be removed from the next version of the
+ MIB (e.g., MIB-III).
+
+ MIB-II marks one object as being deprecated:
+
+ atTable
+
+
+
+
+SNMP Working Group [Page 3]
+
+RFC 1213 MIB-II March 1991
+
+
+ As a result of deprecating the atTable object, the entire Address
+ Translation group is deprecated.
+
+ Note that no functionality is lost with the deprecation of these
+ objects: new objects providing equivalent or superior functionality
+ are defined in MIB-II.
+
+3.2. Display Strings
+
+ In the past, there have been misinterpretations of the MIB as to when
+ a string of octets should contain printable characters, meant to be
+ displayed to a human. As a textual convention in the MIB, the
+ datatype
+
+ DisplayString ::=
+ OCTET STRING
+
+ is introduced. A DisplayString is restricted to the NVT ASCII
+ character set, as defined in pages 10-11 of [6].
+
+ The following objects are now defined in terms of DisplayString:
+
+ sysDescr
+ ifDescr
+
+ It should be noted that this change has no effect on either the
+ syntax nor semantics of these objects. The use of the DisplayString
+ notation is merely an artifact of the explanatory method used in
+ MIB-II and future MIBs.
+
+ Further it should be noted that any object defined in terms of OCTET
+ STRING may contain arbitrary binary data, in which each octet may
+ take any value from 0 to 255 (decimal).
+
+3.3. Physical Addresses
+
+ As a further, textual convention in the MIB, the datatype
+
+ PhysAddress ::=
+ OCTET STRING
+
+ is introduced to represent media- or physical-level addresses.
+
+ The following objects are now defined in terms of PhysAddress:
+
+ ifPhysAddress
+ atPhysAddress
+ ipNetToMediaPhysAddress
+
+
+
+SNMP Working Group [Page 4]
+
+RFC 1213 MIB-II March 1991
+
+
+ It should be noted that this change has no effect on either the
+ syntax nor semantics of these objects. The use of the PhysAddress
+ notation is merely an artifact of the explanatory method used in
+ MIB-II and future MIBs.
+
+3.4. The System Group
+
+ Four new objects are added to this group:
+
+ sysContact
+ sysName
+ sysLocation
+ sysServices
+
+ These provide contact, administrative, location, and service
+ information regarding the managed node.
+
+3.5. The Interfaces Group
+
+ The definition of the ifNumber object was incorrect, as it required
+ all interfaces to support IP. (For example, devices without IP, such
+ as MAC-layer bridges, could not be managed if this definition was
+ strictly followed.) The description of the ifNumber object is
+ changed accordingly.
+
+ The ifTable object was mistaken marked as read-write, it has been
+ (correctly) re-designated as not-accessible. In addition, several
+ new values have been added to the ifType column in the ifTable
+ object:
+
+ ppp(23)
+ softwareLoopback(24)
+ eon(25)
+ ethernet-3Mbit(26)
+ nsip(27)
+ slip(28)
+ ultra(29)
+ ds3(30)
+ sip(31)
+ frame-relay(32)
+
+ Finally, a new column has been added to the ifTable object:
+
+ ifSpecific
+
+ which provides information about information specific to the media
+ being used to realize the interface.
+
+
+
+
+SNMP Working Group [Page 5]
+
+RFC 1213 MIB-II March 1991
+
+
+3.6. The Address Translation Group
+
+ In MIB-I this group contained a table which permitted mappings from
+ network addresses (e.g., IP addresses) to physical addresses (e.g.,
+ MAC addresses). Experience has shown that efficient implementations
+ of this table make two assumptions: a single network protocol
+ environment, and mappings occur only from network address to physical
+ address.
+
+ The need to support multi-protocol nodes (e.g., those with both the
+ IP and CLNP active), and the need to support the inverse mapping
+ (e.g., for ES-IS), have invalidated both of these assumptions. As
+ such, the atTable object is declared deprecated.
+
+ In order to meet both the multi-protocol and inverse mapping
+ requirements, MIB-II and its successors will allocate up to two
+ address translation tables inside each network protocol group. That
+ is, the IP group will contain one address translation table, for
+ going from IP addresses to physical addresses. Similarly, when a
+ document defining MIB objects for the CLNP is produced (e.g., [7]),
+ it will contain two tables, for mappings in both directions, as this
+ is required for full functionality.
+
+ It should be noted that the choice of two tables (one for each
+ direction of mapping) provides for ease of implementation in many
+ cases, and does not introduce undue burden on implementations which
+ realize the address translation abstraction through a single internal
+ table.
+
+3.7. The IP Group
+
+ The access attribute of the variable ipForwarding has been changed
+ from read-only to read-write.
+
+ In addition, there is a new column to the ipAddrTable object,
+
+ ipAdEntReasmMaxSize
+
+ which keeps track of the largest IP datagram that can be re-assembled
+ on a particular interface.
+
+ The descriptor of the ipRoutingTable object has been changed to
+ ipRouteTable for consistency with the other IP routing objects.
+ There are also three new columns in the ipRouteTable object,
+
+ ipRouteMask
+ ipRouteMetric5
+ ipRouteInfo
+
+
+
+SNMP Working Group [Page 6]
+
+RFC 1213 MIB-II March 1991
+
+
+ the first is used for IP routing subsystems that support arbitrary
+ subnet masks, and the latter two are IP routing protocol-specific.
+
+ Two new objects are added to the IP group:
+
+ ipNetToMediaTable
+ ipRoutingDiscards
+
+ the first is the address translation table for the IP group
+ (providing identical functionality to the now deprecated atTable in
+ the address translation group), and the latter provides information
+ when routes are lost due to a lack of buffer space.
+
+3.8. The ICMP Group
+
+ There are no changes to this group.
+
+3.9. The TCP Group
+
+ Two new variables are added:
+
+ tcpInErrs
+ tcpOutRsts
+
+ which keep track of the number of incoming TCP segments in error and
+ the number of resets generated by a TCP.
+
+3.10. The UDP Group
+
+ A new table:
+
+ udpTable
+
+ is added.
+
+3.11. The EGP Group
+
+ Experience has indicated a need for additional objects that are
+ useful in EGP monitoring. In addition to making several additions to
+ the egpNeighborTable object, i.e.,
+
+ egpNeighAs
+ egpNeighInMsgs
+ egpNeighInErrs
+ egpNeighOutMsgs
+ egpNeighOutErrs
+ egpNeighInErrMsgs
+ egpNeighOutErrMsgs
+
+
+
+SNMP Working Group [Page 7]
+
+RFC 1213 MIB-II March 1991
+
+
+ egpNeighStateUps
+ egpNeighStateDowns
+ egpNeighIntervalHello
+ egpNeighIntervalPoll
+ egpNeighMode
+ egpNeighEventTrigger
+
+ a new variable is added:
+
+ egpAs
+
+ which gives the autonomous system associated with this EGP entity.
+
+3.12. The Transmission Group
+
+ MIB-I was lacking in that it did not distinguish between different
+ types of transmission media. A new group, the Transmission group, is
+ allocated for this purpose:
+
+ transmission OBJECT IDENTIFIER ::= { mib-2 10 }
+
+ When Internet-standard definitions for managing transmission media
+ are defined, the transmission group is used to provide a prefix for
+ the names of those objects.
+
+ Typically, such definitions reside in the experimental portion of the
+ MIB until they are "proven", then as a part of the Internet
+ standardization process, the definitions are accordingly elevated and
+ a new object identifier, under the transmission group is defined. By
+ convention, the name assigned is:
+
+ type OBJECT IDENTIFIER ::= { transmission number }
+
+ where "type" is the symbolic value used for the media in the ifType
+ column of the ifTable object, and "number" is the actual integer
+ value corresponding to the symbol.
+
+3.13. The SNMP Group
+
+ The application-oriented working groups of the IETF have been tasked
+ to be receptive towards defining MIB variables specific to their
+ respective applications.
+
+ For the SNMP, it is useful to have statistical information. A new
+ group, the SNMP group, is allocated for this purpose:
+
+ snmp OBJECT IDENTIFIER ::= { mib-2 11 }
+
+
+
+
+SNMP Working Group [Page 8]
+
+RFC 1213 MIB-II March 1991
+
+
+3.14. Changes from RFC 1158
+
+ Features of this MIB include:
+
+ (1) The managed objects in this document have been defined
+ using the conventions defined in the Internet-standard
+ SMI, as amended by the extensions specified in [14]. It
+ must be emphasized that definitions made using these
+ extensions are semantically identically to those in RFC
+ 1158.
+
+ (2) The PhysAddress textual convention has been introduced to
+ represent media addresses.
+
+ (3) The ACCESS clause of sysLocation is now read-write.
+
+ (4) The definition of sysServices has been clarified.
+
+ (5) New ifType values (29-32) have been defined. In
+ addition, the textual-descriptor for the DS1 and E1
+ interface types has been corrected.
+
+ (6) The definition of ipForwarding has been clarified.
+
+ (7) The definition of ipRouteType has been clarified.
+
+ (8) The ipRouteMetric5 and ipRouteInfo objects have been
+ defined.
+
+ (9) The ACCESS clause of tcpConnState is now read-write, to
+ support deletion of the TCB associated with a TCP
+ connection. The definition of this object has been
+ clarified to explain this usage.
+
+ (10) The definition of egpNeighEventTrigger has been
+ clarified.
+
+ (11) The definition of several of the variables in the new
+ snmp group have been clarified. In addition, the
+ snmpInBadTypes and snmpOutReadOnlys objects are no longer
+ present. (However, the object identifiers associated
+ with those objects are reserved to prevent future use.)
+
+ (12) The definition of snmpInReadOnlys has been clarified.
+
+ (13) The textual descriptor of the snmpEnableAuthTraps has
+ been changed to snmpEnableAuthenTraps, and the definition
+ has been clarified.
+
+
+
+SNMP Working Group [Page 9]
+
+RFC 1213 MIB-II March 1991
+
+
+ (14) The ipRoutingDiscards object was added.
+
+ (15) The optional use of an implementation-dependent, small
+ positive integer was disallowed when identifying
+ instances of the IP address and routing tables.
+
+4. Objects
+
+ Managed objects are accessed via a virtual information store, termed
+ the Management Information Base or MIB. Objects in the MIB are
+ defined using the subset of Abstract Syntax Notation One (ASN.1) [8]
+ defined in the SMI. In particular, each object has a name, a syntax,
+ and an encoding. The name is an object identifier, an
+ administratively assigned name, which specifies an object type. The
+ object type together with an object instance serves to uniquely
+ identify a specific instantiation of the object. For human
+ convenience, we often use a textual string, termed the OBJECT
+ DESCRIPTOR, to also refer to the object type.
+
+ The syntax of an object type defines the abstract data structure
+ corresponding to that object type. The ASN.1 language is used for
+ this purpose. However, the SMI [12] purposely restricts the ASN.1
+ constructs which may be used. These restrictions are explicitly made
+ for simplicity.
+
+ The encoding of an object type is simply how that object type is
+ represented using the object type's syntax. Implicitly tied to the
+ notion of an object type's syntax and encoding is how the object type
+ is represented when being transmitted on the network.
+
+ The SMI specifies the use of the basic encoding rules of ASN.1 [9],
+ subject to the additional requirements imposed by the SNMP.
+
+4.1. Format of Definitions
+
+ Section 6 contains contains the specification of all object types
+ contained in this MIB module. The object types are defined using the
+ conventions defined in the SMI, as amended by the extensions
+ specified in [14].
+
+5. Overview
+
+ Consistent with the IAB directive to produce simple, workable systems
+ in the short-term, the list of managed objects defined here, has been
+ derived by taking only those elements which are considered essential.
+
+ This approach of taking only the essential objects is NOT
+ restrictive, since the SMI defined in the companion memo provides
+
+
+
+SNMP Working Group [Page 10]
+
+RFC 1213 MIB-II March 1991
+
+
+ three extensibility mechanisms: one, the addition of new standard
+ objects through the definitions of new versions of the MIB; two, the
+ addition of widely-available but non-standard objects through the
+ experimental subtree; and three, the addition of private objects
+ through the enterprises subtree. Such additional objects can not
+ only be used for vendor-specific elements, but also for
+ experimentation as required to further the knowledge of which other
+ objects are essential.
+
+ The design of MIB-II is heavily influenced by the first extensibility
+ mechanism. Several new variables have been added based on
+ operational experience and need. Based on this, the criteria for
+ including an object in MIB-II are remarkably similar to the MIB-I
+ criteria:
+
+ (1) An object needed to be essential for either fault or
+ configuration management.
+
+ (2) Only weak control objects were permitted (by weak, it is
+ meant that tampering with them can do only limited
+ damage). This criterion reflects the fact that the
+ current management protocols are not sufficiently secure
+ to do more powerful control operations.
+
+ (3) Evidence of current use and utility was required.
+
+ (4) In MIB-I, an attempt was made to limit the number of
+ objects to about 100 to make it easier for vendors to
+ fully instrument their software. In MIB-II, this limit
+ was raised given the wide technological base now
+ implementing MIB-I.
+
+ (5) To avoid redundant variables, it was required that no
+ object be included that can be derived from others in the
+ MIB.
+
+ (6) Implementation specific objects (e.g., for BSD UNIX) were
+ excluded.
+
+ (7) It was agreed to avoid heavily instrumenting critical
+ sections of code. The general guideline was one counter
+ per critical section per layer.
+
+ MIB-II, like its predecessor, the Internet-standard MIB, contains
+ only essential elements. There is no need to allow individual
+ objects to be optional. Rather, the objects are arranged into the
+ following groups:
+
+
+
+
+SNMP Working Group [Page 11]
+
+RFC 1213 MIB-II March 1991
+
+
+ - System
+ - Interfaces
+ - Address Translation (deprecated)
+ - IP
+ - ICMP
+ - TCP
+ - UDP
+ - EGP
+ - Transmission
+ - SNMP
+
+ These groups are the basic unit of conformance: This method is as
+ follows: if the semantics of a group is applicable to an
+ implementation, then it must implement all objects in that group.
+ For example, an implementation must implement the EGP group if and
+ only if it implements the EGP.
+
+ There are two reasons for defining these groups: to provide a means
+ of assigning object identifiers; and, to provide a method for
+ implementations of managed agents to know which objects they must
+ implement.
+
+6. Definitions
+
+ RFC1213-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ mgmt, NetworkAddress, IpAddress, Counter, Gauge,
+ TimeTicks
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+ -- This MIB module uses the extended OBJECT-TYPE macro as
+ -- defined in [14];
+
+
+ -- MIB-II (same prefix as MIB-I)
+
+ mib-2 OBJECT IDENTIFIER ::= { mgmt 1 }
+
+ -- textual conventions
+
+ DisplayString ::=
+ OCTET STRING
+ -- This data type is used to model textual information taken
+ -- from the NVT ASCII character set. By convention, objects
+ -- with this syntax are declared as having
+
+
+
+SNMP Working Group [Page 12]
+
+RFC 1213 MIB-II March 1991
+
+
+ --
+ -- SIZE (0..255)
+
+ PhysAddress ::=
+ OCTET STRING
+ -- This data type is used to model media addresses. For many
+ -- types of media, this will be in a binary representation.
+ -- For example, an ethernet address would be represented as
+ -- a string of 6 octets.
+
+
+ -- groups in MIB-II
+
+ system OBJECT IDENTIFIER ::= { mib-2 1 }
+
+ interfaces OBJECT IDENTIFIER ::= { mib-2 2 }
+
+ at OBJECT IDENTIFIER ::= { mib-2 3 }
+
+ ip OBJECT IDENTIFIER ::= { mib-2 4 }
+
+ icmp OBJECT IDENTIFIER ::= { mib-2 5 }
+
+ tcp OBJECT IDENTIFIER ::= { mib-2 6 }
+
+ udp OBJECT IDENTIFIER ::= { mib-2 7 }
+
+ egp OBJECT IDENTIFIER ::= { mib-2 8 }
+
+ -- historical (some say hysterical)
+ -- cmot OBJECT IDENTIFIER ::= { mib-2 9 }
+
+ transmission OBJECT IDENTIFIER ::= { mib-2 10 }
+
+ snmp OBJECT IDENTIFIER ::= { mib-2 11 }
+
+
+ -- the System group
+
+ -- Implementation of the System group is mandatory for all
+ -- systems. If an agent is not configured to have a value
+ -- for any of these variables, a string of length 0 is
+ -- returned.
+
+ sysDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+SNMP Working Group [Page 13]
+
+RFC 1213 MIB-II March 1991
+
+
+ DESCRIPTION
+ "A textual description of the entity. This value
+ should include the full name and version
+ identification of the system's hardware type,
+ software operating-system, and networking
+ software. It is mandatory that this only contain
+ printable ASCII characters."
+ ::= { system 1 }
+
+ sysObjectID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The vendor's authoritative identification of the
+ network management subsystem contained in the
+ entity. This value is allocated within the SMI
+ enterprises subtree (1.3.6.1.4.1) and provides an
+ easy and unambiguous means for determining `what
+ kind of box' is being managed. For example, if
+ vendor `Flintstones, Inc.' was assigned the
+ subtree 1.3.6.1.4.1.4242, it could assign the
+ identifier 1.3.6.1.4.1.4242.1.1 to its `Fred
+ Router'."
+ ::= { system 2 }
+
+ sysUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The time (in hundredths of a second) since the
+ network management portion of the system was last
+ re-initialized."
+ ::= { system 3 }
+
+ sysContact OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The textual identification of the contact person
+ for this managed node, together with information
+ on how to contact this person."
+ ::= { system 4 }
+
+ sysName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+
+
+
+SNMP Working Group [Page 14]
+
+RFC 1213 MIB-II March 1991
+
+
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An administratively-assigned name for this
+ managed node. By convention, this is the node's
+ fully-qualified domain name."
+ ::= { system 5 }
+
+ sysLocation OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The physical location of this node (e.g.,
+ `telephone closet, 3rd floor')."
+ ::= { system 6 }
+
+ sysServices OBJECT-TYPE
+ SYNTAX INTEGER (0..127)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A value which indicates the set of services that
+ this entity primarily offers.
+
+ The value is a sum. This sum initially takes the
+ value zero, Then, for each layer, L, in the range
+ 1 through 7, that this node performs transactions
+ for, 2 raised to (L - 1) is added to the sum. For
+ example, a node which performs primarily routing
+ functions would have a value of 4 (2^(3-1)). In
+ contrast, a node which is a host offering
+ application services would have a value of 72
+ (2^(4-1) + 2^(7-1)). Note that in the context of
+ the Internet suite of protocols, values should be
+ calculated accordingly:
+
+ layer functionality
+ 1 physical (e.g., repeaters)
+ 2 datalink/subnetwork (e.g., bridges)
+ 3 internet (e.g., IP gateways)
+ 4 end-to-end (e.g., IP hosts)
+ 7 applications (e.g., mail relays)
+
+ For systems including OSI protocols, layers 5 and
+ 6 may also be counted."
+ ::= { system 7 }
+
+
+
+
+SNMP Working Group [Page 15]
+
+RFC 1213 MIB-II March 1991
+
+
+ -- the Interfaces group
+
+ -- Implementation of the Interfaces group is mandatory for
+ -- all systems.
+
+ ifNumber OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of network interfaces (regardless of
+ their current state) present on this system."
+ ::= { interfaces 1 }
+
+
+ -- the Interfaces table
+
+ -- The Interfaces table contains information on the entity's
+ -- interfaces. Each interface is thought of as being
+ -- attached to a `subnetwork'. Note that this term should
+ -- not be confused with `subnet' which refers to an
+ -- addressing partitioning scheme used in the Internet suite
+ -- of protocols.
+
+ ifTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IfEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of interface entries. The number of
+ entries is given by the value of ifNumber."
+ ::= { interfaces 2 }
+
+ ifEntry OBJECT-TYPE
+ SYNTAX IfEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "An interface entry containing objects at the
+ subnetwork layer and below for a particular
+ interface."
+ INDEX { ifIndex }
+ ::= { ifTable 1 }
+
+ IfEntry ::=
+ SEQUENCE {
+ ifIndex
+ INTEGER,
+
+
+
+SNMP Working Group [Page 16]
+
+RFC 1213 MIB-II March 1991
+
+
+ ifDescr
+ DisplayString,
+ ifType
+ INTEGER,
+ ifMtu
+ INTEGER,
+ ifSpeed
+ Gauge,
+ ifPhysAddress
+ PhysAddress,
+ ifAdminStatus
+ INTEGER,
+ ifOperStatus
+ INTEGER,
+ ifLastChange
+ TimeTicks,
+ ifInOctets
+ Counter,
+ ifInUcastPkts
+ Counter,
+ ifInNUcastPkts
+ Counter,
+ ifInDiscards
+ Counter,
+ ifInErrors
+ Counter,
+ ifInUnknownProtos
+ Counter,
+ ifOutOctets
+ Counter,
+ ifOutUcastPkts
+ Counter,
+ ifOutNUcastPkts
+ Counter,
+ ifOutDiscards
+ Counter,
+ ifOutErrors
+ Counter,
+ ifOutQLen
+ Gauge,
+ ifSpecific
+ OBJECT IDENTIFIER
+ }
+
+ ifIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+SNMP Working Group [Page 17]
+
+RFC 1213 MIB-II March 1991
+
+
+ DESCRIPTION
+ "A unique value for each interface. Its value
+ ranges between 1 and the value of ifNumber. The
+ value for each interface must remain constant at
+ least from one re-initialization of the entity's
+ network management system to the next re-
+ initialization."
+ ::= { ifEntry 1 }
+
+ ifDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A textual string containing information about the
+ interface. This string should include the name of
+ the manufacturer, the product name and the version
+ of the hardware interface."
+ ::= { ifEntry 2 }
+
+ ifType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+ regular1822(2),
+ hdh1822(3),
+ ddn-x25(4),
+ rfc877-x25(5),
+ ethernet-csmacd(6),
+ iso88023-csmacd(7),
+ iso88024-tokenBus(8),
+ iso88025-tokenRing(9),
+ iso88026-man(10),
+ starLan(11),
+ proteon-10Mbit(12),
+ proteon-80Mbit(13),
+ hyperchannel(14),
+ fddi(15),
+ lapb(16),
+ sdlc(17),
+ ds1(18), -- T-1
+ e1(19), -- european equiv. of T-1
+ basicISDN(20),
+ primaryISDN(21), -- proprietary serial
+ propPointToPointSerial(22),
+ ppp(23),
+ softwareLoopback(24),
+ eon(25), -- CLNP over IP [11]
+ ethernet-3Mbit(26),
+
+
+
+SNMP Working Group [Page 18]
+
+RFC 1213 MIB-II March 1991
+
+
+ nsip(27), -- XNS over IP
+ slip(28), -- generic SLIP
+ ultra(29), -- ULTRA technologies
+ ds3(30), -- T-3
+ sip(31), -- SMDS
+ frame-relay(32)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The type of interface, distinguished according to
+ the physical/link protocol(s) immediately `below'
+ the network layer in the protocol stack."
+ ::= { ifEntry 3 }
+
+ ifMtu OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The size of the largest datagram which can be
+ sent/received on the interface, specified in
+ octets. For interfaces that are used for
+ transmitting network datagrams, this is the size
+ of the largest network datagram that can be sent
+ on the interface."
+ ::= { ifEntry 4 }
+
+ ifSpeed OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An estimate of the interface's current bandwidth
+ in bits per second. For interfaces which do not
+ vary in bandwidth or for those where no accurate
+ estimation can be made, this object should contain
+ the nominal bandwidth."
+ ::= { ifEntry 5 }
+
+ ifPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interface's address at the protocol layer
+ immediately `below' the network layer in the
+ protocol stack. For interfaces which do not have
+
+
+
+SNMP Working Group [Page 19]
+
+RFC 1213 MIB-II March 1991
+
+
+ such an address (e.g., a serial line), this object
+ should contain an octet string of zero length."
+ ::= { ifEntry 6 }
+
+ ifAdminStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ up(1), -- ready to pass packets
+ down(2),
+ testing(3) -- in some test mode
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The desired state of the interface. The
+ testing(3) state indicates that no operational
+ packets can be passed."
+ ::= { ifEntry 7 }
+
+ ifOperStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ up(1), -- ready to pass packets
+ down(2),
+ testing(3) -- in some test mode
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The current operational state of the interface.
+ The testing(3) state indicates that no operational
+ packets can be passed."
+ ::= { ifEntry 8 }
+
+ ifLastChange OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime at the time the interface
+ entered its current operational state. If the
+ current state was entered prior to the last re-
+ initialization of the local network management
+ subsystem, then this object contains a zero
+ value."
+ ::= { ifEntry 9 }
+
+ ifInOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+
+
+
+SNMP Working Group [Page 20]
+
+RFC 1213 MIB-II March 1991
+
+
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets received on the
+ interface, including framing characters."
+ ::= { ifEntry 10 }
+
+ ifInUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of subnetwork-unicast packets
+ delivered to a higher-layer protocol."
+ ::= { ifEntry 11 }
+
+ ifInNUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of non-unicast (i.e., subnetwork-
+ broadcast or subnetwork-multicast) packets
+ delivered to a higher-layer protocol."
+ ::= { ifEntry 12 }
+
+ ifInDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of inbound packets which were chosen
+ to be discarded even though no errors had been
+ detected to prevent their being deliverable to a
+ higher-layer protocol. One possible reason for
+ discarding such a packet could be to free up
+ buffer space."
+ ::= { ifEntry 13 }
+
+ ifInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of inbound packets that contained
+ errors preventing them from being deliverable to a
+ higher-layer protocol."
+ ::= { ifEntry 14 }
+
+
+
+
+SNMP Working Group [Page 21]
+
+RFC 1213 MIB-II March 1991
+
+
+ ifInUnknownProtos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets received via the interface
+ which were discarded because of an unknown or
+ unsupported protocol."
+ ::= { ifEntry 15 }
+
+ ifOutOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets transmitted out of the
+ interface, including framing characters."
+ ::= { ifEntry 16 }
+
+ ifOutUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets that higher-level
+ protocols requested be transmitted to a
+ subnetwork-unicast address, including those that
+ were discarded or not sent."
+ ::= { ifEntry 17 }
+
+ ifOutNUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets that higher-level
+ protocols requested be transmitted to a non-
+ unicast (i.e., a subnetwork-broadcast or
+ subnetwork-multicast) address, including those
+ that were discarded or not sent."
+ ::= { ifEntry 18 }
+
+ ifOutDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of outbound packets which were chosen
+
+
+
+SNMP Working Group [Page 22]
+
+RFC 1213 MIB-II March 1991
+
+
+ to be discarded even though no errors had been
+ detected to prevent their being transmitted. One
+ possible reason for discarding such a packet could
+ be to free up buffer space."
+ ::= { ifEntry 19 }
+
+ ifOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of outbound packets that could not be
+ transmitted because of errors."
+ ::= { ifEntry 20 }
+
+ ifOutQLen OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The length of the output packet queue (in
+ packets)."
+ ::= { ifEntry 21 }
+
+ ifSpecific OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A reference to MIB definitions specific to the
+ particular media being used to realize the
+ interface. For example, if the interface is
+ realized by an ethernet, then the value of this
+ object refers to a document defining objects
+ specific to ethernet. If this information is not
+ present, its value should be set to the OBJECT
+ IDENTIFIER { 0 0 }, which is a syntatically valid
+ object identifier, and any conformant
+ implementation of ASN.1 and BER must be able to
+ generate and recognize this value."
+ ::= { ifEntry 22 }
+
+
+ -- the Address Translation group
+
+ -- Implementation of the Address Translation group is
+ -- mandatory for all systems. Note however that this group
+ -- is deprecated by MIB-II. That is, it is being included
+
+
+
+SNMP Working Group [Page 23]
+
+RFC 1213 MIB-II March 1991
+
+
+ -- solely for compatibility with MIB-I nodes, and will most
+ -- likely be excluded from MIB-III nodes. From MIB-II and
+ -- onwards, each network protocol group contains its own
+ -- address translation tables.
+
+ -- The Address Translation group contains one table which is
+ -- the union across all interfaces of the translation tables
+ -- for converting a NetworkAddress (e.g., an IP address) into
+ -- a subnetwork-specific address. For lack of a better term,
+ -- this document refers to such a subnetwork-specific address
+ -- as a `physical' address.
+
+ -- Examples of such translation tables are: for broadcast
+ -- media where ARP is in use, the translation table is
+ -- equivalent to the ARP cache; or, on an X.25 network where
+ -- non-algorithmic translation to X.121 addresses is
+ -- required, the translation table contains the
+ -- NetworkAddress to X.121 address equivalences.
+
+ atTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AtEntry
+ ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "The Address Translation tables contain the
+ NetworkAddress to `physical' address equivalences.
+ Some interfaces do not use translation tables for
+ determining address equivalences (e.g., DDN-X.25
+ has an algorithmic method); if all interfaces are
+ of this type, then the Address Translation table
+ is empty, i.e., has zero entries."
+ ::= { at 1 }
+
+ atEntry OBJECT-TYPE
+ SYNTAX AtEntry
+ ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "Each entry contains one NetworkAddress to
+ `physical' address equivalence."
+ INDEX { atIfIndex,
+ atNetAddress }
+ ::= { atTable 1 }
+
+ AtEntry ::=
+ SEQUENCE {
+ atIfIndex
+ INTEGER,
+
+
+
+SNMP Working Group [Page 24]
+
+RFC 1213 MIB-II March 1991
+
+
+ atPhysAddress
+ PhysAddress,
+ atNetAddress
+ NetworkAddress
+ }
+
+ atIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The interface on which this entry's equivalence
+ is effective. The interface identified by a
+ particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { atEntry 1 }
+
+ atPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The media-dependent `physical' address.
+
+ Setting this object to a null string (one of zero
+ length) has the effect of invaliding the
+ corresponding entry in the atTable object. That
+ is, it effectively dissasociates the interface
+ identified with said entry from the mapping
+ identified with said entry. It is an
+ implementation-specific matter as to whether the
+ agent removes an invalidated entry from the table.
+ Accordingly, management stations must be prepared
+ to receive tabular information from agents that
+ corresponds to entries not currently in use.
+ Proper interpretation of such entries requires
+ examination of the relevant atPhysAddress object."
+ ::= { atEntry 2 }
+
+ atNetAddress OBJECT-TYPE
+ SYNTAX NetworkAddress
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The NetworkAddress (e.g., the IP address)
+ corresponding to the media-dependent `physical'
+ address."
+
+
+
+SNMP Working Group [Page 25]
+
+RFC 1213 MIB-II March 1991
+
+
+ ::= { atEntry 3 }
+
+
+ -- the IP group
+
+ -- Implementation of the IP group is mandatory for all
+ -- systems.
+
+ ipForwarding OBJECT-TYPE
+ SYNTAX INTEGER {
+ forwarding(1), -- acting as a gateway
+ not-forwarding(2) -- NOT acting as a gateway
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The indication of whether this entity is acting
+ as an IP gateway in respect to the forwarding of
+ datagrams received by, but not addressed to, this
+ entity. IP gateways forward datagrams. IP hosts
+ do not (except those source-routed via the host).
+
+ Note that for some managed nodes, this object may
+ take on only a subset of the values possible.
+ Accordingly, it is appropriate for an agent to
+ return a `badValue' response if a management
+ station attempts to change this object to an
+ inappropriate value."
+ ::= { ip 1 }
+
+ ipDefaultTTL OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The default value inserted into the Time-To-Live
+ field of the IP header of datagrams originated at
+ this entity, whenever a TTL value is not supplied
+ by the transport layer protocol."
+ ::= { ip 2 }
+
+ ipInReceives OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of input datagrams received from
+ interfaces, including those received in error."
+
+
+
+SNMP Working Group [Page 26]
+
+RFC 1213 MIB-II March 1991
+
+
+ ::= { ip 3 }
+
+ ipInHdrErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams discarded due to
+ errors in their IP headers, including bad
+ checksums, version number mismatch, other format
+ errors, time-to-live exceeded, errors discovered
+ in processing their IP options, etc."
+ ::= { ip 4 }
+
+ ipInAddrErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams discarded because
+ the IP address in their IP header's destination
+ field was not a valid address to be received at
+ this entity. This count includes invalid
+ addresses (e.g., 0.0.0.0) and addresses of
+ unsupported Classes (e.g., Class E). For entities
+ which are not IP Gateways and therefore do not
+ forward datagrams, this counter includes datagrams
+ discarded because the destination address was not
+ a local address."
+ ::= { ip 5 }
+
+ ipForwDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams for which this
+ entity was not their final IP destination, as a
+ result of which an attempt was made to find a
+ route to forward them to that final destination.
+ In entities which do not act as IP Gateways, this
+ counter will include only those packets which were
+ Source-Routed via this entity, and the Source-
+ Route option processing was successful."
+ ::= { ip 6 }
+
+ ipInUnknownProtos OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+SNMP Working Group [Page 27]
+
+RFC 1213 MIB-II March 1991
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally-addressed datagrams
+ received successfully but discarded because of an
+ unknown or unsupported protocol."
+ ::= { ip 7 }
+
+ ipInDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input IP datagrams for which no
+ problems were encountered to prevent their
+ continued processing, but which were discarded
+ (e.g., for lack of buffer space). Note that this
+ counter does not include any datagrams discarded
+ while awaiting re-assembly."
+ ::= { ip 8 }
+
+ ipInDelivers OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of input datagrams successfully
+ delivered to IP user-protocols (including ICMP)."
+ ::= { ip 9 }
+
+ ipOutRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of IP datagrams which local IP
+ user-protocols (including ICMP) supplied to IP in
+ requests for transmission. Note that this counter
+ does not include any datagrams counted in
+ ipForwDatagrams."
+ ::= { ip 10 }
+
+ ipOutDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of output IP datagrams for which no
+
+
+
+SNMP Working Group [Page 28]
+
+RFC 1213 MIB-II March 1991
+
+
+ problem was encountered to prevent their
+ transmission to their destination, but which were
+ discarded (e.g., for lack of buffer space). Note
+ that this counter would include datagrams counted
+ in ipForwDatagrams if any such packets met this
+ (discretionary) discard criterion."
+ ::= { ip 11 }
+
+ ipOutNoRoutes OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams discarded because no
+ route could be found to transmit them to their
+ destination. Note that this counter includes any
+ packets counted in ipForwDatagrams which meet this
+ `no-route' criterion. Note that this includes any
+ datagarms which a host cannot route because all of
+ its default gateways are down."
+ ::= { ip 12 }
+
+ ipReasmTimeout OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of seconds which received
+ fragments are held while they are awaiting
+ reassembly at this entity."
+ ::= { ip 13 }
+
+ ipReasmReqds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP fragments received which needed
+ to be reassembled at this entity."
+ ::= { ip 14 }
+
+ ipReasmOKs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams successfully re-
+ assembled."
+
+
+
+SNMP Working Group [Page 29]
+
+RFC 1213 MIB-II March 1991
+
+
+ ::= { ip 15 }
+
+ ipReasmFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of failures detected by the IP re-
+ assembly algorithm (for whatever reason: timed
+ out, errors, etc). Note that this is not
+ necessarily a count of discarded IP fragments
+ since some algorithms (notably the algorithm in
+ RFC 815) can lose track of the number of fragments
+ by combining them as they are received."
+ ::= { ip 16 }
+
+ ipFragOKs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams that have been
+ successfully fragmented at this entity."
+ ::= { ip 17 }
+
+ ipFragFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams that have been
+ discarded because they needed to be fragmented at
+ this entity but could not be, e.g., because their
+ Don't Fragment flag was set."
+ ::= { ip 18 }
+
+ ipFragCreates OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagram fragments that have
+ been generated as a result of fragmentation at
+ this entity."
+ ::= { ip 19 }
+
+
+
+
+
+
+SNMP Working Group [Page 30]
+
+RFC 1213 MIB-II March 1991
+
+
+ -- the IP address table
+
+ -- The IP address table contains this entity's IP addressing
+ -- information.
+
+ ipAddrTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpAddrEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The table of addressing information relevant to
+ this entity's IP addresses."
+ ::= { ip 20 }
+
+ ipAddrEntry OBJECT-TYPE
+ SYNTAX IpAddrEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The addressing information for one of this
+ entity's IP addresses."
+ INDEX { ipAdEntAddr }
+ ::= { ipAddrTable 1 }
+
+ IpAddrEntry ::=
+ SEQUENCE {
+ ipAdEntAddr
+ IpAddress,
+ ipAdEntIfIndex
+ INTEGER,
+ ipAdEntNetMask
+ IpAddress,
+ ipAdEntBcastAddr
+ INTEGER,
+ ipAdEntReasmMaxSize
+ INTEGER (0..65535)
+ }
+
+ ipAdEntAddr OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address to which this entry's addressing
+ information pertains."
+ ::= { ipAddrEntry 1 }
+
+
+
+
+
+SNMP Working Group [Page 31]
+
+RFC 1213 MIB-II March 1991
+
+
+ ipAdEntIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The index value which uniquely identifies the
+ interface to which this entry is applicable. The
+ interface identified by a particular value of this
+ index is the same interface as identified by the
+ same value of ifIndex."
+ ::= { ipAddrEntry 2 }
+
+ ipAdEntNetMask OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The subnet mask associated with the IP address of
+ this entry. The value of the mask is an IP
+ address with all the network bits set to 1 and all
+ the hosts bits set to 0."
+ ::= { ipAddrEntry 3 }
+
+ ipAdEntBcastAddr OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of the least-significant bit in the IP
+ broadcast address used for sending datagrams on
+ the (logical) interface associated with the IP
+ address of this entry. For example, when the
+ Internet standard all-ones broadcast address is
+ used, the value will be 1. This value applies to
+ both the subnet and network broadcasts addresses
+ used by the entity on this (logical) interface."
+ ::= { ipAddrEntry 4 }
+
+ ipAdEntReasmMaxSize OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The size of the largest IP datagram which this
+ entity can re-assemble from incoming IP fragmented
+ datagrams received on this interface."
+ ::= { ipAddrEntry 5 }
+
+
+
+
+SNMP Working Group [Page 32]
+
+RFC 1213 MIB-II March 1991
+
+
+ -- the IP routing table
+
+ -- The IP routing table contains an entry for each route
+ -- presently known to this entity.
+
+ ipRouteTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpRouteEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "This entity's IP Routing table."
+ ::= { ip 21 }
+
+ ipRouteEntry OBJECT-TYPE
+ SYNTAX IpRouteEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A route to a particular destination."
+ INDEX { ipRouteDest }
+ ::= { ipRouteTable 1 }
+
+ IpRouteEntry ::=
+ SEQUENCE {
+ ipRouteDest
+ IpAddress,
+ ipRouteIfIndex
+ INTEGER,
+ ipRouteMetric1
+ INTEGER,
+ ipRouteMetric2
+ INTEGER,
+ ipRouteMetric3
+ INTEGER,
+ ipRouteMetric4
+ INTEGER,
+ ipRouteNextHop
+ IpAddress,
+ ipRouteType
+ INTEGER,
+ ipRouteProto
+ INTEGER,
+ ipRouteAge
+ INTEGER,
+ ipRouteMask
+ IpAddress,
+ ipRouteMetric5
+ INTEGER,
+
+
+
+SNMP Working Group [Page 33]
+
+RFC 1213 MIB-II March 1991
+
+
+ ipRouteInfo
+ OBJECT IDENTIFIER
+ }
+
+ ipRouteDest OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The destination IP address of this route. An
+ entry with a value of 0.0.0.0 is considered a
+ default route. Multiple routes to a single
+ destination can appear in the table, but access to
+ such multiple entries is dependent on the table-
+ access mechanisms defined by the network
+ management protocol in use."
+ ::= { ipRouteEntry 1 }
+
+ ipRouteIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The index value which uniquely identifies the
+ local interface through which the next hop of this
+ route should be reached. The interface identified
+ by a particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { ipRouteEntry 2 }
+
+ ipRouteMetric1 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The primary routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 3 }
+
+ ipRouteMetric2 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+
+
+
+SNMP Working Group [Page 34]
+
+RFC 1213 MIB-II March 1991
+
+
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 4 }
+
+ ipRouteMetric3 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 5 }
+
+ ipRouteMetric4 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 6 }
+
+ ipRouteNextHop OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address of the next hop of this route.
+ (In the case of a route bound to an interface
+ which is realized via a broadcast media, the value
+ of this field is the agent's IP address on that
+ interface.)"
+ ::= { ipRouteEntry 7 }
+
+ ipRouteType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ invalid(2), -- an invalidated route
+
+
+
+SNMP Working Group [Page 35]
+
+RFC 1213 MIB-II March 1991
+
+
+ -- route to directly
+ direct(3), -- connected (sub-)network
+
+ -- route to a non-local
+ indirect(4) -- host/network/sub-network
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The type of route. Note that the values
+ direct(3) and indirect(4) refer to the notion of
+ direct and indirect routing in the IP
+ architecture.
+
+ Setting this object to the value invalid(2) has
+ the effect of invalidating the corresponding entry
+ in the ipRouteTable object. That is, it
+ effectively dissasociates the destination
+ identified with said entry from the route
+ identified with said entry. It is an
+ implementation-specific matter as to whether the
+ agent removes an invalidated entry from the table.
+ Accordingly, management stations must be prepared
+ to receive tabular information from agents that
+ corresponds to entries not currently in use.
+ Proper interpretation of such entries requires
+ examination of the relevant ipRouteType object."
+ ::= { ipRouteEntry 8 }
+
+ ipRouteProto OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ -- non-protocol information,
+ -- e.g., manually configured
+ local(2), -- entries
+
+ -- set via a network
+ netmgmt(3), -- management protocol
+
+ -- obtained via ICMP,
+ icmp(4), -- e.g., Redirect
+
+ -- the remaining values are
+ -- all gateway routing
+ -- protocols
+ egp(5),
+ ggp(6),
+
+
+
+SNMP Working Group [Page 36]
+
+RFC 1213 MIB-II March 1991
+
+
+ hello(7),
+ rip(8),
+ is-is(9),
+ es-is(10),
+ ciscoIgrp(11),
+ bbnSpfIgp(12),
+ ospf(13),
+ bgp(14)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The routing mechanism via which this route was
+ learned. Inclusion of values for gateway routing
+ protocols is not intended to imply that hosts
+ should support those protocols."
+ ::= { ipRouteEntry 9 }
+
+ ipRouteAge OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The number of seconds since this route was last
+ updated or otherwise determined to be correct.
+ Note that no semantics of `too old' can be implied
+ except through knowledge of the routing protocol
+ by which the route was learned."
+ ::= { ipRouteEntry 10 }
+
+ ipRouteMask OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Indicate the mask to be logical-ANDed with the
+ destination address before being compared to the
+ value in the ipRouteDest field. For those systems
+ that do not support arbitrary subnet masks, an
+ agent constructs the value of the ipRouteMask by
+ determining whether the value of the correspondent
+ ipRouteDest field belong to a class-A, B, or C
+ network, and then using one of:
+
+ mask network
+ 255.0.0.0 class-A
+ 255.255.0.0 class-B
+ 255.255.255.0 class-C
+
+
+
+SNMP Working Group [Page 37]
+
+RFC 1213 MIB-II March 1991
+
+
+ If the value of the ipRouteDest is 0.0.0.0 (a
+ default route), then the mask value is also
+ 0.0.0.0. It should be noted that all IP routing
+ subsystems implicitly use this mechanism."
+ ::= { ipRouteEntry 11 }
+
+ ipRouteMetric5 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 12 }
+
+ ipRouteInfo OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A reference to MIB definitions specific to the
+ particular routing protocol which is responsible
+ for this route, as determined by the value
+ specified in the route's ipRouteProto value. If
+ this information is not present, its value should
+ be set to the OBJECT IDENTIFIER { 0 0 }, which is
+ a syntatically valid object identifier, and any
+ conformant implementation of ASN.1 and BER must be
+ able to generate and recognize this value."
+ ::= { ipRouteEntry 13 }
+
+
+ -- the IP Address Translation table
+
+ -- The IP address translation table contain the IpAddress to
+ -- `physical' address equivalences. Some interfaces do not
+ -- use translation tables for determining address
+ -- equivalences (e.g., DDN-X.25 has an algorithmic method);
+ -- if all interfaces are of this type, then the Address
+ -- Translation table is empty, i.e., has zero entries.
+
+ ipNetToMediaTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpNetToMediaEntry
+ ACCESS not-accessible
+ STATUS mandatory
+
+
+
+SNMP Working Group [Page 38]
+
+RFC 1213 MIB-II March 1991
+
+
+ DESCRIPTION
+ "The IP Address Translation table used for mapping
+ from IP addresses to physical addresses."
+ ::= { ip 22 }
+
+ ipNetToMediaEntry OBJECT-TYPE
+ SYNTAX IpNetToMediaEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Each entry contains one IpAddress to `physical'
+ address equivalence."
+ INDEX { ipNetToMediaIfIndex,
+ ipNetToMediaNetAddress }
+ ::= { ipNetToMediaTable 1 }
+
+ IpNetToMediaEntry ::=
+ SEQUENCE {
+ ipNetToMediaIfIndex
+ INTEGER,
+ ipNetToMediaPhysAddress
+ PhysAddress,
+ ipNetToMediaNetAddress
+ IpAddress,
+ ipNetToMediaType
+ INTEGER
+ }
+
+ ipNetToMediaIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The interface on which this entry's equivalence
+ is effective. The interface identified by a
+ particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { ipNetToMediaEntry 1 }
+
+ ipNetToMediaPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The media-dependent `physical' address."
+ ::= { ipNetToMediaEntry 2 }
+
+
+
+
+SNMP Working Group [Page 39]
+
+RFC 1213 MIB-II March 1991
+
+
+ ipNetToMediaNetAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The IpAddress corresponding to the media-
+ dependent `physical' address."
+ ::= { ipNetToMediaEntry 3 }
+
+ ipNetToMediaType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+ invalid(2), -- an invalidated mapping
+ dynamic(3),
+ static(4)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The type of mapping.
+
+ Setting this object to the value invalid(2) has
+ the effect of invalidating the corresponding entry
+ in the ipNetToMediaTable. That is, it effectively
+ dissasociates the interface identified with said
+ entry from the mapping identified with said entry.
+ It is an implementation-specific matter as to
+ whether the agent removes an invalidated entry
+ from the table. Accordingly, management stations
+ must be prepared to receive tabular information
+ from agents that corresponds to entries not
+ currently in use. Proper interpretation of such
+ entries requires examination of the relevant
+ ipNetToMediaType object."
+ ::= { ipNetToMediaEntry 4 }
+
+
+ -- additional IP objects
+
+ ipRoutingDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of routing entries which were chosen
+ to be discarded even though they are valid. One
+ possible reason for discarding such an entry could
+ be to free-up buffer space for other routing
+
+
+
+SNMP Working Group [Page 40]
+
+RFC 1213 MIB-II March 1991
+
+
+ entries."
+ ::= { ip 23 }
+
+
+ -- the ICMP group
+
+ -- Implementation of the ICMP group is mandatory for all
+ -- systems.
+
+ icmpInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ICMP messages which the
+ entity received. Note that this counter includes
+ all those counted by icmpInErrors."
+ ::= { icmp 1 }
+
+ icmpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP messages which the entity
+ received but determined as having ICMP-specific
+ errors (bad ICMP checksums, bad length, etc.)."
+ ::= { icmp 2 }
+
+ icmpInDestUnreachs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Destination Unreachable
+ messages received."
+ ::= { icmp 3 }
+
+ icmpInTimeExcds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Time Exceeded messages
+ received."
+ ::= { icmp 4 }
+
+
+
+
+
+SNMP Working Group [Page 41]
+
+RFC 1213 MIB-II March 1991
+
+
+ icmpInParmProbs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Parameter Problem messages
+ received."
+ ::= { icmp 5 }
+
+ icmpInSrcQuenchs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Source Quench messages
+ received."
+ ::= { icmp 6 }
+
+ icmpInRedirects OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Redirect messages received."
+ ::= { icmp 7 }
+
+ icmpInEchos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo (request) messages
+ received."
+ ::= { icmp 8 }
+
+ icmpInEchoReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo Reply messages received."
+ ::= { icmp 9 }
+
+ icmpInTimestamps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+
+
+
+SNMP Working Group [Page 42]
+
+RFC 1213 MIB-II March 1991
+
+
+ "The number of ICMP Timestamp (request) messages
+ received."
+ ::= { icmp 10 }
+
+ icmpInTimestampReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp Reply messages
+ received."
+ ::= { icmp 11 }
+
+ icmpInAddrMasks OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Request messages
+ received."
+ ::= { icmp 12 }
+
+ icmpInAddrMaskReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Reply messages
+ received."
+ ::= { icmp 13 }
+
+ icmpOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ICMP messages which this
+ entity attempted to send. Note that this counter
+ includes all those counted by icmpOutErrors."
+ ::= { icmp 14 }
+
+ icmpOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP messages which this entity did
+ not send due to problems discovered within ICMP
+
+
+
+SNMP Working Group [Page 43]
+
+RFC 1213 MIB-II March 1991
+
+
+ such as a lack of buffers. This value should not
+ include errors discovered outside the ICMP layer
+ such as the inability of IP to route the resultant
+ datagram. In some implementations there may be no
+ types of error which contribute to this counter's
+ value."
+ ::= { icmp 15 }
+
+ icmpOutDestUnreachs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Destination Unreachable
+ messages sent."
+ ::= { icmp 16 }
+
+ icmpOutTimeExcds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Time Exceeded messages sent."
+ ::= { icmp 17 }
+
+ icmpOutParmProbs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Parameter Problem messages
+ sent."
+ ::= { icmp 18 }
+
+ icmpOutSrcQuenchs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Source Quench messages sent."
+ ::= { icmp 19 }
+
+ icmpOutRedirects OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Redirect messages sent. For a
+
+
+
+SNMP Working Group [Page 44]
+
+RFC 1213 MIB-II March 1991
+
+
+ host, this object will always be zero, since hosts
+ do not send redirects."
+ ::= { icmp 20 }
+
+ icmpOutEchos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo (request) messages sent."
+ ::= { icmp 21 }
+
+ icmpOutEchoReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo Reply messages sent."
+ ::= { icmp 22 }
+
+ icmpOutTimestamps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp (request) messages
+ sent."
+ ::= { icmp 23 }
+
+ icmpOutTimestampReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp Reply messages
+ sent."
+ ::= { icmp 24 }
+
+ icmpOutAddrMasks OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Request messages
+ sent."
+ ::= { icmp 25 }
+
+
+
+
+
+SNMP Working Group [Page 45]
+
+RFC 1213 MIB-II March 1991
+
+
+ icmpOutAddrMaskReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Reply messages
+ sent."
+ ::= { icmp 26 }
+
+
+ -- the TCP group
+
+ -- Implementation of the TCP group is mandatory for all
+ -- systems that implement the TCP.
+
+ -- Note that instances of object types that represent
+ -- information about a particular TCP connection are
+ -- transient; they persist only as long as the connection
+ -- in question.
+
+ tcpRtoAlgorithm OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ constant(2), -- a constant rto
+ rsre(3), -- MIL-STD-1778, Appendix B
+ vanj(4) -- Van Jacobson's algorithm [10]
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The algorithm used to determine the timeout value
+ used for retransmitting unacknowledged octets."
+ ::= { tcp 1 }
+
+ tcpRtoMin OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The minimum value permitted by a TCP
+ implementation for the retransmission timeout,
+ measured in milliseconds. More refined semantics
+ for objects of this type depend upon the algorithm
+ used to determine the retransmission timeout. In
+ particular, when the timeout algorithm is rsre(3),
+ an object of this type has the semantics of the
+ LBOUND quantity described in RFC 793."
+
+
+
+SNMP Working Group [Page 46]
+
+RFC 1213 MIB-II March 1991
+
+
+ ::= { tcp 2 }
+
+
+ tcpRtoMax OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum value permitted by a TCP
+ implementation for the retransmission timeout,
+ measured in milliseconds. More refined semantics
+ for objects of this type depend upon the algorithm
+ used to determine the retransmission timeout. In
+ particular, when the timeout algorithm is rsre(3),
+ an object of this type has the semantics of the
+ UBOUND quantity described in RFC 793."
+ ::= { tcp 3 }
+
+ tcpMaxConn OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The limit on the total number of TCP connections
+ the entity can support. In entities where the
+ maximum number of connections is dynamic, this
+ object should contain the value -1."
+ ::= { tcp 4 }
+
+ tcpActiveOpens OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the SYN-SENT state from the
+ CLOSED state."
+ ::= { tcp 5 }
+
+ tcpPassiveOpens OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the SYN-RCVD state from the
+ LISTEN state."
+ ::= { tcp 6 }
+
+
+
+SNMP Working Group [Page 47]
+
+RFC 1213 MIB-II March 1991
+
+
+ tcpAttemptFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the CLOSED state from either
+ the SYN-SENT state or the SYN-RCVD state, plus the
+ number of times TCP connections have made a direct
+ transition to the LISTEN state from the SYN-RCVD
+ state."
+ ::= { tcp 7 }
+
+ tcpEstabResets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the CLOSED state from either
+ the ESTABLISHED state or the CLOSE-WAIT state."
+ ::= { tcp 8 }
+
+ tcpCurrEstab OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of TCP connections for which the
+ current state is either ESTABLISHED or CLOSE-
+ WAIT."
+ ::= { tcp 9 }
+
+ tcpInSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of segments received, including
+ those received in error. This count includes
+ segments received on currently established
+ connections."
+ ::= { tcp 10 }
+
+ tcpOutSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+SNMP Working Group [Page 48]
+
+RFC 1213 MIB-II March 1991
+
+
+ DESCRIPTION
+ "The total number of segments sent, including
+ those on current connections but excluding those
+ containing only retransmitted octets."
+ ::= { tcp 11 }
+
+ tcpRetransSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of segments retransmitted - that
+ is, the number of TCP segments transmitted
+ containing one or more previously transmitted
+ octets."
+ ::= { tcp 12 }
+
+
+ -- the TCP Connection table
+
+ -- The TCP connection table contains information about this
+ -- entity's existing TCP connections.
+
+ tcpConnTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF TcpConnEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A table containing TCP connection-specific
+ information."
+ ::= { tcp 13 }
+
+ tcpConnEntry OBJECT-TYPE
+ SYNTAX TcpConnEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about a particular current TCP
+ connection. An object of this type is transient,
+ in that it ceases to exist when (or soon after)
+ the connection makes the transition to the CLOSED
+ state."
+ INDEX { tcpConnLocalAddress,
+ tcpConnLocalPort,
+ tcpConnRemAddress,
+ tcpConnRemPort }
+ ::= { tcpConnTable 1 }
+
+
+
+
+SNMP Working Group [Page 49]
+
+RFC 1213 MIB-II March 1991
+
+
+ TcpConnEntry ::=
+ SEQUENCE {
+ tcpConnState
+ INTEGER,
+ tcpConnLocalAddress
+ IpAddress,
+ tcpConnLocalPort
+ INTEGER (0..65535),
+ tcpConnRemAddress
+ IpAddress,
+ tcpConnRemPort
+ INTEGER (0..65535)
+ }
+
+ tcpConnState OBJECT-TYPE
+ SYNTAX INTEGER {
+ closed(1),
+ listen(2),
+ synSent(3),
+ synReceived(4),
+ established(5),
+ finWait1(6),
+ finWait2(7),
+ closeWait(8),
+ lastAck(9),
+ closing(10),
+ timeWait(11),
+ deleteTCB(12)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The state of this TCP connection.
+
+ The only value which may be set by a management
+ station is deleteTCB(12). Accordingly, it is
+ appropriate for an agent to return a `badValue'
+ response if a management station attempts to set
+ this object to any other value.
+
+ If a management station sets this object to the
+ value deleteTCB(12), then this has the effect of
+ deleting the TCB (as defined in RFC 793) of the
+ corresponding connection on the managed node,
+ resulting in immediate termination of the
+ connection.
+
+ As an implementation-specific option, a RST
+
+
+
+SNMP Working Group [Page 50]
+
+RFC 1213 MIB-II March 1991
+
+
+ segment may be sent from the managed node to the
+ other TCP endpoint (note however that RST segments
+ are not sent reliably)."
+ ::= { tcpConnEntry 1 }
+
+ tcpConnLocalAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local IP address for this TCP connection. In
+ the case of a connection in the listen state which
+ is willing to accept connections for any IP
+ interface associated with the node, the value
+ 0.0.0.0 is used."
+ ::= { tcpConnEntry 2 }
+
+ tcpConnLocalPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local port number for this TCP connection."
+ ::= { tcpConnEntry 3 }
+
+ tcpConnRemAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The remote IP address for this TCP connection."
+ ::= { tcpConnEntry 4 }
+
+ tcpConnRemPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The remote port number for this TCP connection."
+ ::= { tcpConnEntry 5 }
+
+
+ -- additional TCP objects
+
+ tcpInErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+SNMP Working Group [Page 51]
+
+RFC 1213 MIB-II March 1991
+
+
+ DESCRIPTION
+ "The total number of segments received in error
+ (e.g., bad TCP checksums)."
+ ::= { tcp 14 }
+
+ tcpOutRsts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of TCP segments sent containing the
+ RST flag."
+ ::= { tcp 15 }
+
+
+ -- the UDP group
+
+ -- Implementation of the UDP group is mandatory for all
+ -- systems which implement the UDP.
+
+ udpInDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of UDP datagrams delivered to
+ UDP users."
+ ::= { udp 1 }
+
+ udpNoPorts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of received UDP datagrams for
+ which there was no application at the destination
+ port."
+ ::= { udp 2 }
+
+ udpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of received UDP datagrams that could
+ not be delivered for reasons other than the lack
+ of an application at the destination port."
+ ::= { udp 3 }
+
+
+
+SNMP Working Group [Page 52]
+
+RFC 1213 MIB-II March 1991
+
+
+ udpOutDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of UDP datagrams sent from this
+ entity."
+ ::= { udp 4 }
+
+
+ -- the UDP Listener table
+
+ -- The UDP listener table contains information about this
+ -- entity's UDP end-points on which a local application is
+ -- currently accepting datagrams.
+
+ udpTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF UdpEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A table containing UDP listener information."
+ ::= { udp 5 }
+
+ udpEntry OBJECT-TYPE
+ SYNTAX UdpEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about a particular current UDP
+ listener."
+ INDEX { udpLocalAddress, udpLocalPort }
+ ::= { udpTable 1 }
+
+ UdpEntry ::=
+ SEQUENCE {
+ udpLocalAddress
+ IpAddress,
+ udpLocalPort
+ INTEGER (0..65535)
+ }
+
+ udpLocalAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local IP address for this UDP listener. In
+
+
+
+SNMP Working Group [Page 53]
+
+RFC 1213 MIB-II March 1991
+
+
+ the case of a UDP listener which is willing to
+ accept datagrams for any IP interface associated
+ with the node, the value 0.0.0.0 is used."
+ ::= { udpEntry 1 }
+
+ udpLocalPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local port number for this UDP listener."
+ ::= { udpEntry 2 }
+
+
+ -- the EGP group
+
+ -- Implementation of the EGP group is mandatory for all
+ -- systems which implement the EGP.
+
+ egpInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received without
+ error."
+ ::= { egp 1 }
+
+ egpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received that proved
+ to be in error."
+ ::= { egp 2 }
+
+ egpOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of locally generated EGP
+ messages."
+ ::= { egp 3 }
+
+ egpOutErrors OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+SNMP Working Group [Page 54]
+
+RFC 1213 MIB-II March 1991
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages not
+ sent due to resource limitations within an EGP
+ entity."
+ ::= { egp 4 }
+
+
+ -- the EGP Neighbor table
+
+ -- The EGP neighbor table contains information about this
+ -- entity's EGP neighbors.
+
+ egpNeighTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EgpNeighEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The EGP neighbor table."
+ ::= { egp 5 }
+
+ egpNeighEntry OBJECT-TYPE
+ SYNTAX EgpNeighEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about this entity's relationship with
+ a particular EGP neighbor."
+ INDEX { egpNeighAddr }
+ ::= { egpNeighTable 1 }
+
+ EgpNeighEntry ::=
+ SEQUENCE {
+ egpNeighState
+ INTEGER,
+ egpNeighAddr
+ IpAddress,
+ egpNeighAs
+ INTEGER,
+ egpNeighInMsgs
+ Counter,
+ egpNeighInErrs
+ Counter,
+ egpNeighOutMsgs
+ Counter,
+ egpNeighOutErrs
+ Counter,
+
+
+
+SNMP Working Group [Page 55]
+
+RFC 1213 MIB-II March 1991
+
+
+ egpNeighInErrMsgs
+ Counter,
+ egpNeighOutErrMsgs
+ Counter,
+ egpNeighStateUps
+ Counter,
+ egpNeighStateDowns
+ Counter,
+ egpNeighIntervalHello
+ INTEGER,
+ egpNeighIntervalPoll
+ INTEGER,
+ egpNeighMode
+ INTEGER,
+ egpNeighEventTrigger
+ INTEGER
+ }
+
+ egpNeighState OBJECT-TYPE
+ SYNTAX INTEGER {
+ idle(1),
+ acquisition(2),
+ down(3),
+ up(4),
+ cease(5)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The EGP state of the local system with respect to
+ this entry's EGP neighbor. Each EGP state is
+ represented by a value that is one greater than
+ the numerical value associated with said state in
+ RFC 904."
+ ::= { egpNeighEntry 1 }
+
+ egpNeighAddr OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address of this entry's EGP neighbor."
+ ::= { egpNeighEntry 2 }
+
+ egpNeighAs OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+SNMP Working Group [Page 56]
+
+RFC 1213 MIB-II March 1991
+
+
+ DESCRIPTION
+ "The autonomous system of this EGP peer. Zero
+ should be specified if the autonomous system
+ number of the neighbor is not yet known."
+ ::= { egpNeighEntry 3 }
+
+ egpNeighInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received without error
+ from this EGP peer."
+ ::= { egpNeighEntry 4 }
+
+ egpNeighInErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received from this EGP
+ peer that proved to be in error (e.g., bad EGP
+ checksum)."
+ ::= { egpNeighEntry 5 }
+
+ egpNeighOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages to
+ this EGP peer."
+ ::= { egpNeighEntry 6 }
+
+ egpNeighOutErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages not
+ sent to this EGP peer due to resource limitations
+ within an EGP entity."
+ ::= { egpNeighEntry 7 }
+
+ egpNeighInErrMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+SNMP Working Group [Page 57]
+
+RFC 1213 MIB-II March 1991
+
+
+ DESCRIPTION
+ "The number of EGP-defined error messages received
+ from this EGP peer."
+ ::= { egpNeighEntry 8 }
+
+ egpNeighOutErrMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP-defined error messages sent to
+ this EGP peer."
+ ::= { egpNeighEntry 9 }
+
+ egpNeighStateUps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP state transitions to the UP
+ state with this EGP peer."
+ ::= { egpNeighEntry 10 }
+
+ egpNeighStateDowns OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP state transitions from the UP
+ state to any other state with this EGP peer."
+ ::= { egpNeighEntry 11 }
+
+ egpNeighIntervalHello OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interval between EGP Hello command
+ retransmissions (in hundredths of a second). This
+ represents the t1 timer as defined in RFC 904."
+ ::= { egpNeighEntry 12 }
+
+ egpNeighIntervalPoll OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interval between EGP poll command
+
+
+
+SNMP Working Group [Page 58]
+
+RFC 1213 MIB-II March 1991
+
+
+ retransmissions (in hundredths of a second). This
+ represents the t3 timer as defined in RFC 904."
+ ::= { egpNeighEntry 13 }
+
+ egpNeighMode OBJECT-TYPE
+ SYNTAX INTEGER { active(1), passive(2) }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The polling mode of this EGP entity, either
+ passive or active."
+ ::= { egpNeighEntry 14 }
+
+ egpNeighEventTrigger OBJECT-TYPE
+ SYNTAX INTEGER { start(1), stop(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A control variable used to trigger operator-
+ initiated Start and Stop events. When read, this
+ variable always returns the most recent value that
+ egpNeighEventTrigger was set to. If it has not
+ been set since the last initialization of the
+ network management subsystem on the node, it
+ returns a value of `stop'.
+
+ When set, this variable causes a Start or Stop
+ event on the specified neighbor, as specified on
+ pages 8-10 of RFC 904. Briefly, a Start event
+ causes an Idle peer to begin neighbor acquisition
+ and a non-Idle peer to reinitiate neighbor
+ acquisition. A stop event causes a non-Idle peer
+ to return to the Idle state until a Start event
+ occurs, either via egpNeighEventTrigger or
+ otherwise."
+ ::= { egpNeighEntry 15 }
+
+
+ -- additional EGP objects
+
+ egpAs OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The autonomous system number of this EGP entity."
+ ::= { egp 6 }
+
+
+
+
+SNMP Working Group [Page 59]
+
+RFC 1213 MIB-II March 1991
+
+
+ -- the Transmission group
+
+ -- Based on the transmission media underlying each interface
+ -- on a system, the corresponding portion of the Transmission
+ -- group is mandatory for that system.
+
+ -- When Internet-standard definitions for managing
+ -- transmission media are defined, the transmission group is
+ -- used to provide a prefix for the names of those objects.
+
+ -- Typically, such definitions reside in the experimental
+ -- portion of the MIB until they are "proven", then as a
+ -- part of the Internet standardization process, the
+ -- definitions are accordingly elevated and a new object
+ -- identifier, under the transmission group is defined. By
+ -- convention, the name assigned is:
+ --
+ -- type OBJECT IDENTIFIER ::= { transmission number }
+ --
+ -- where "type" is the symbolic value used for the media in
+ -- the ifType column of the ifTable object, and "number" is
+ -- the actual integer value corresponding to the symbol.
+
+
+ -- the SNMP group
+
+ -- Implementation of the SNMP group is mandatory for all
+ -- systems which support an SNMP protocol entity. Some of
+ -- the objects defined below will be zero-valued in those
+ -- SNMP implementations that are optimized to support only
+ -- those functions specific to either a management agent or
+ -- a management station. In particular, it should be
+ -- observed that the objects below refer to an SNMP entity,
+ -- and there may be several SNMP entities residing on a
+ -- managed node (e.g., if the node is hosting acting as
+ -- a management station).
+
+ snmpInPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of Messages delivered to the
+ SNMP entity from the transport service."
+ ::= { snmp 1 }
+
+ snmpOutPkts OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+SNMP Working Group [Page 60]
+
+RFC 1213 MIB-II March 1991
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ passed from the SNMP protocol entity to the
+ transport service."
+ ::= { snmp 2 }
+
+ snmpInBadVersions OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ delivered to the SNMP protocol entity and were for
+ an unsupported SNMP version."
+ ::= { snmp 3 }
+
+ snmpInBadCommunityNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which used a SNMP
+ community name not known to said entity."
+ ::= { snmp 4 }
+
+ snmpInBadCommunityUses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which represented an SNMP
+ operation which was not allowed by the SNMP
+ community named in the Message."
+ ::= { snmp 5 }
+
+ snmpInASNParseErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ASN.1 or BER errors
+ encountered by the SNMP protocol entity when
+ decoding received SNMP Messages."
+ ::= { snmp 6 }
+
+
+
+SNMP Working Group [Page 61]
+
+RFC 1213 MIB-II March 1991
+
+
+ -- { snmp 7 } is not used
+
+ snmpInTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig'."
+ ::= { snmp 8 }
+
+ snmpInNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `noSuchName'."
+ ::= { snmp 9 }
+
+ snmpInBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 10 }
+
+ snmpInReadOnlys OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number valid SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `readOnly'. It should be noted that it is a
+ protocol error to generate an SNMP PDU which
+ contains the value `readOnly' in the error-status
+ field, as such this object is provided as a means
+ of detecting incorrect implementations of the
+
+
+
+SNMP Working Group [Page 62]
+
+RFC 1213 MIB-II March 1991
+
+
+ SNMP."
+ ::= { snmp 11 }
+
+ snmpInGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 12 }
+
+ snmpInTotalReqVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ retrieved successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Get-Request
+ and Get-Next PDUs."
+ ::= { snmp 13 }
+
+ snmpInTotalSetVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ altered successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Set-Request
+ PDUs."
+ ::= { snmp 14 }
+
+ snmpInGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 15 }
+
+ snmpInGetNexts OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+SNMP Working Group [Page 63]
+
+RFC 1213 MIB-II March 1991
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 16 }
+
+ snmpInSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 17 }
+
+ snmpInGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 18 }
+
+ snmpInTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 19 }
+
+ snmpOutTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig.'"
+ ::= { snmp 20 }
+
+
+
+SNMP Working Group [Page 64]
+
+RFC 1213 MIB-II March 1991
+
+
+ snmpOutNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status is
+ `noSuchName'."
+ ::= { snmp 21 }
+
+ snmpOutBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 22 }
+
+ -- { snmp 23 } is not used
+
+ snmpOutGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 24 }
+
+ snmpOutGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 25 }
+
+ snmpOutGetNexts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+SNMP Working Group [Page 65]
+
+RFC 1213 MIB-II March 1991
+
+
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 26 }
+
+ snmpOutSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 27 }
+
+ snmpOutGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 28 }
+
+ snmpOutTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 29 }
+
+ snmpEnableAuthenTraps OBJECT-TYPE
+ SYNTAX INTEGER { enabled(1), disabled(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Indicates whether the SNMP agent process is
+ permitted to generate authentication-failure
+ traps. The value of this object overrides any
+ configuration information; as such, it provides a
+ means whereby all authentication-failure traps may
+ be disabled.
+
+ Note that it is strongly recommended that this
+ object be stored in non-volatile memory so that it
+ remains constant between re-initializations of the
+ network management system."
+
+
+
+SNMP Working Group [Page 66]
+
+RFC 1213 MIB-II March 1991
+
+
+ ::= { snmp 30 }
+
+ END
+
+7. Acknowledgements
+
+ This document was produced by the SNMP Working Group:
+
+ Anne Ambler, Spider
+ Karl Auerbach, Sun
+ Fred Baker, ACC
+ David Bridgham, Epilogue Technology
+ Ken Brinkerhoff
+ Ron Broersma, NOSC
+ Brian Brown, Synoptics
+ Jack Brown, US Army
+ Theodore Brunner, Bellcore
+ Jeff Buffum, HP
+ Jeffrey Buffum, HP
+ John Burress, Wellfleet
+ Jeffrey D. Case, University of Tennessee at Knoxville
+ Chris Chiptasso, Spartacus
+ Paul Ciarfella, DEC
+ Bob Collet
+ John Cook, Chipcom
+ Tracy Cox, Bellcore
+ James R. Davin, MIT-LCS
+ Eric Decker, cisco
+ Kurt Dobbins, Cabletron
+ Nadya El-Afandi, Network Systems
+ Gary Ellis, HP
+ Fred Engle
+ Mike Erlinger
+ Mark S. Fedor, PSI
+ Richard Fox, Synoptics
+ Karen Frisa, CMU
+ Stan Froyd, ACC
+ Chris Gunner, DEC
+ Fred Harris, University of Tennessee at Knoxville
+ Ken Hibbard, Xylogics
+ Ole Jacobsen, Interop
+ Ken Jones
+ Satish Joshi, Synoptics
+ Frank Kastenholz, Racal-Interlan
+ Shimshon Kaufman, Spartacus
+ Ken Key, University of Tennessee at Knoxville
+ Jim Kinder, Fibercom
+ Alex Koifman, BBN
+
+
+
+SNMP Working Group [Page 67]
+
+RFC 1213 MIB-II March 1991
+
+
+ Christopher Kolb, PSI
+ Cheryl Krupczak, NCR
+ Paul Langille, DEC
+ Martin Lee Schoffstall, PSI
+ Peter Lin, Vitalink
+ John Lunny, TWG
+ Carl Malamud
+ Gary Malkin, FTP Software, Inc.
+ Randy Mayhew, University of Tennessee at Knoxville
+ Keith McCloghrie, Hughes LAN Systems
+ Donna McMaster, David Systems
+ Lynn Monsanto, Sun
+ Dave Perkins, 3COM
+ Jim Reinstedler, Ungerman Bass
+ Anil Rijsinghani, DEC
+ Kathy Rinehart, Arnold AFB
+ Kary Robertson
+ Marshall T. Rose, PSI (chair)
+ L. Michael Sabo, NCSC
+ Jon Saperia, DEC
+ Greg Satz, cisco
+ Martin Schoffstall, PSI
+ John Seligson
+ Steve Sherry, Xyplex
+ Fei Shu, NEC
+ Sam Sjogren, TGV
+ Mark Sleeper, Sparta
+ Lance Sprung
+ Mike St.Johns
+ Bob Stewart, Xyplex
+ Emil Sturniold
+ Kaj Tesink, Bellcore
+ Geoff Thompson, Synoptics
+ Dean Throop, Data General
+ Bill Townsend, Xylogics
+ Maurice Turcotte, Racal-Milgo
+ Kannan Varadhou
+ Sudhanshu Verma, HP
+ Bill Versteeg, Network Research Corporation
+ Warren Vik, Interactive Systems
+ David Waitzman, BBN
+ Steve Waldbusser, CMU
+ Dan Wintringhan
+ David Wood
+ Wengyik Yeong, PSI
+ Jeff Young, Cray Research
+
+
+
+
+
+SNMP Working Group [Page 68]
+
+RFC 1213 MIB-II March 1991
+
+
+ In addition, the comments of the following individuals are also
+ acknolwedged:
+
+ Craig A. Finseth, Minnesota Supercomputer Center, Inc.
+ Jeffrey C. Honig, Cornell University Theory Center
+ Philip R. Karn, Bellcore
+
+8. References
+
+ [1] Cerf, V., "IAB Recommendations for the Development of Internet
+ Network Management Standards", RFC 1052, NRI, April 1988.
+
+ [2] Rose M., and K. McCloghrie, "Structure and Identification of
+ Management Information for TCP/IP-based internets," RFC 1065,
+ TWG, August 1988.
+
+ [3] McCloghrie, K., and M. Rose, "Management Information Base for
+ Network Management of TCP/IP-based internets, RFC 1066, TWG,
+ August 1988.
+
+ [4] Cerf, V., "Report of the Second Ad Hoc Network Management Review
+ Group", RFC 1109, NRI, August 1989.
+
+ [5] Case, J., Fedor, M., Schoffstall, M., and J. Davin, "Simple
+ Network Management Protocol (SNMP)", RFC 1098, University of
+ Tennessee at Knoxville, NYSERNet, Inc., Rensselaer Polytechnic
+ Institute, MIT Laboratory for Computer Science, April 1989.
+
+ [6] Postel, J., and J. Reynolds, "TELNET Protocol Specification", RFC
+ 854, USC/Information Sciences Institute, May 1983.
+
+ [7] Satz, G., "Connectionless Network Protocol (ISO 8473) and End
+ System to Intermediate System (ISO 9542) Management Information
+ Base", RFC 1162, cisco Systems, Inc., June 1990.
+
+ [8] Information processing systems - Open Systems Interconnection -
+ Specification of Abstract Syntax Notation One (ASN.1),
+ International Organization for Standardization, International
+ Standard 8824, December 1987.
+
+ [9] Information processing systems - Open Systems Interconnection -
+ Specification of Basic Encoding Rules for Abstract Notation One
+ (ASN.1), International Organization for Standardization,
+ International Standard 8825, December 1987.
+
+ [10] Jacobson, V., "Congestion Avoidance and Control", SIGCOMM 1988,
+ Stanford, California.
+
+
+
+
+SNMP Working Group [Page 69]
+
+RFC 1213 MIB-II March 1991
+
+
+ [11] Hagens, R., Hall, N., and M. Rose, "Use of the Internet as a
+ Subnetwork for Experimentation with the OSI Network Layer", RFC
+ 1070, U of Wiscsonsin - Madison, U of Wiscsonsin - Madison, The
+ Wollongong Group, February 1989.
+
+ [12] Rose M., and K. McCloghrie, "Structure and Identification of
+ Management Information for TCP/IP-based internets", RFC 1155,
+ Performance Systems International, Hughes LAN Systems, May 1990.
+
+ [13] Case, J., Fedor, M., Schoffstall, M., and J. Davin, "Simple
+ Network Management Protocol", RFC 1157, SNMP Research,
+ Performance Systems International, Performance Systems
+ International, MIT Laboratory for Computer Science, May 1990.
+
+ [14] Rose, M., and K. McCloghrie, Editors, "Concise MIB Definitions",
+ RFC 1212, Performance Systems International, Hughes LAN Systems,
+ March 1991.
+
+9. Security Considerations
+
+ Security issues are not discussed in this memo.
+
+10. Authors' Addresses
+
+ Keith McCloghrie
+ Hughes LAN Systems
+ 1225 Charleston Road
+ Mountain View, CA 94043
+ 1225 Charleston Road
+ Mountain View, CA 94043
+
+ Phone: (415) 966-7934
+
+ EMail: kzm@hls.com
+
+
+ Marshall T. Rose
+ Performance Systems International
+ 5201 Great America Parkway
+ Suite 3106
+ Santa Clara, CA 95054
+
+ Phone: +1 408 562 6222
+
+ EMail: mrose@psi.com
+ X.500: rose, psi, us
+
+
+
+
+
+SNMP Working Group [Page 70]
+ \ No newline at end of file
diff --git a/standards/rfc1321.txt b/standards/rfc1321.txt
new file mode 100644
index 000000000..68af27d2b
--- /dev/null
+++ b/standards/rfc1321.txt
@@ -0,0 +1,1179 @@
+
+
+
+
+
+
+Network Working Group R. Rivest
+Request for Comments: 1321 MIT Laboratory for Computer Science
+ and RSA Data Security, Inc.
+ April 1992
+
+
+ The MD5 Message-Digest Algorithm
+
+Status of this Memo
+
+ This memo provides information for the Internet community. It does
+ not specify an Internet standard. Distribution of this memo is
+ unlimited.
+
+Acknowlegements
+
+ We would like to thank Don Coppersmith, Burt Kaliski, Ralph Merkle,
+ David Chaum, and Noam Nisan for numerous helpful comments and
+ suggestions.
+
+Table of Contents
+
+ 1. Executive Summary 1
+ 2. Terminology and Notation 2
+ 3. MD5 Algorithm Description 3
+ 4. Summary 6
+ 5. Differences Between MD4 and MD5 6
+ References 7
+ APPENDIX A - Reference Implementation 7
+ Security Considerations 21
+ Author's Address 21
+
+1. Executive Summary
+
+ This document describes the MD5 message-digest algorithm. The
+ algorithm takes as input a message of arbitrary length and produces
+ as output a 128-bit "fingerprint" or "message digest" of the input.
+ It is conjectured that it is computationally infeasible to produce
+ two messages having the same message digest, or to produce any
+ message having a given prespecified target message digest. The MD5
+ algorithm is intended for digital signature applications, where a
+ large file must be "compressed" in a secure manner before being
+ encrypted with a private (secret) key under a public-key cryptosystem
+ such as RSA.
+
+
+
+
+
+
+
+Rivest [Page 1]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ The MD5 algorithm is designed to be quite fast on 32-bit machines. In
+ addition, the MD5 algorithm does not require any large substitution
+ tables; the algorithm can be coded quite compactly.
+
+ The MD5 algorithm is an extension of the MD4 message-digest algorithm
+ 1,2]. MD5 is slightly slower than MD4, but is more "conservative" in
+ design. MD5 was designed because it was felt that MD4 was perhaps
+ being adopted for use more quickly than justified by the existing
+ critical review; because MD4 was designed to be exceptionally fast,
+ it is "at the edge" in terms of risking successful cryptanalytic
+ attack. MD5 backs off a bit, giving up a little in speed for a much
+ greater likelihood of ultimate security. It incorporates some
+ suggestions made by various reviewers, and contains additional
+ optimizations. The MD5 algorithm is being placed in the public domain
+ for review and possible adoption as a standard.
+
+ For OSI-based applications, MD5's object identifier is
+
+ md5 OBJECT IDENTIFIER ::=
+ iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5}
+
+ In the X.509 type AlgorithmIdentifier [3], the parameters for MD5
+ should have type NULL.
+
+2. Terminology and Notation
+
+ In this document a "word" is a 32-bit quantity and a "byte" is an
+ eight-bit quantity. A sequence of bits can be interpreted in a
+ natural manner as a sequence of bytes, where each consecutive group
+ of eight bits is interpreted as a byte with the high-order (most
+ significant) bit of each byte listed first. Similarly, a sequence of
+ bytes can be interpreted as a sequence of 32-bit words, where each
+ consecutive group of four bytes is interpreted as a word with the
+ low-order (least significant) byte given first.
+
+ Let x_i denote "x sub i". If the subscript is an expression, we
+ surround it in braces, as in x_{i+1}. Similarly, we use ^ for
+ superscripts (exponentiation), so that x^i denotes x to the i-th
+ power.
+
+ Let the symbol "+" denote addition of words (i.e., modulo-2^32
+ addition). Let X <<< s denote the 32-bit value obtained by circularly
+ shifting (rotating) X left by s bit positions. Let not(X) denote the
+ bit-wise complement of X, and let X v Y denote the bit-wise OR of X
+ and Y. Let X xor Y denote the bit-wise XOR of X and Y, and let XY
+ denote the bit-wise AND of X and Y.
+
+
+
+
+
+Rivest [Page 2]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+3. MD5 Algorithm Description
+
+ We begin by supposing that we have a b-bit message as input, and that
+ we wish to find its message digest. Here b is an arbitrary
+ nonnegative integer; b may be zero, it need not be a multiple of
+ eight, and it may be arbitrarily large. We imagine the bits of the
+ message written down as follows:
+
+ m_0 m_1 ... m_{b-1}
+
+ The following five steps are performed to compute the message digest
+ of the message.
+
+3.1 Step 1. Append Padding Bits
+
+ The message is "padded" (extended) so that its length (in bits) is
+ congruent to 448, modulo 512. That is, the message is extended so
+ that it is just 64 bits shy of being a multiple of 512 bits long.
+ Padding is always performed, even if the length of the message is
+ already congruent to 448, modulo 512.
+
+ Padding is performed as follows: a single "1" bit is appended to the
+ message, and then "0" bits are appended so that the length in bits of
+ the padded message becomes congruent to 448, modulo 512. In all, at
+ least one bit and at most 512 bits are appended.
+
+3.2 Step 2. Append Length
+
+ A 64-bit representation of b (the length of the message before the
+ padding bits were added) is appended to the result of the previous
+ step. In the unlikely event that b is greater than 2^64, then only
+ the low-order 64 bits of b are used. (These bits are appended as two
+ 32-bit words and appended low-order word first in accordance with the
+ previous conventions.)
+
+ At this point the resulting message (after padding with bits and with
+ b) has a length that is an exact multiple of 512 bits. Equivalently,
+ this message has a length that is an exact multiple of 16 (32-bit)
+ words. Let M[0 ... N-1] denote the words of the resulting message,
+ where N is a multiple of 16.
+
+3.3 Step 3. Initialize MD Buffer
+
+ A four-word buffer (A,B,C,D) is used to compute the message digest.
+ Here each of A, B, C, D is a 32-bit register. These registers are
+ initialized to the following values in hexadecimal, low-order bytes
+ first):
+
+
+
+
+Rivest [Page 3]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ word A: 01 23 45 67
+ word B: 89 ab cd ef
+ word C: fe dc ba 98
+ word D: 76 54 32 10
+
+3.4 Step 4. Process Message in 16-Word Blocks
+
+ We first define four auxiliary functions that each take as input
+ three 32-bit words and produce as output one 32-bit word.
+
+ F(X,Y,Z) = XY v not(X) Z
+ G(X,Y,Z) = XZ v Y not(Z)
+ H(X,Y,Z) = X xor Y xor Z
+ I(X,Y,Z) = Y xor (X v not(Z))
+
+ In each bit position F acts as a conditional: if X then Y else Z.
+ The function F could have been defined using + instead of v since XY
+ and not(X)Z will never have 1's in the same bit position.) It is
+ interesting to note that if the bits of X, Y, and Z are independent
+ and unbiased, the each bit of F(X,Y,Z) will be independent and
+ unbiased.
+
+ The functions G, H, and I are similar to the function F, in that they
+ act in "bitwise parallel" to produce their output from the bits of X,
+ Y, and Z, in such a manner that if the corresponding bits of X, Y,
+ and Z are independent and unbiased, then each bit of G(X,Y,Z),
+ H(X,Y,Z), and I(X,Y,Z) will be independent and unbiased. Note that
+ the function H is the bit-wise "xor" or "parity" function of its
+ inputs.
+
+ This step uses a 64-element table T[1 ... 64] constructed from the
+ sine function. Let T[i] denote the i-th element of the table, which
+ is equal to the integer part of 4294967296 times abs(sin(i)), where i
+ is in radians. The elements of the table are given in the appendix.
+
+ Do the following:
+
+ /* Process each 16-word block. */
+ For i = 0 to N/16-1 do
+
+ /* Copy block i into X. */
+ For j = 0 to 15 do
+ Set X[j] to M[i*16+j].
+ end /* of loop on j */
+
+ /* Save A as AA, B as BB, C as CC, and D as DD. */
+ AA = A
+ BB = B
+
+
+
+Rivest [Page 4]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ CC = C
+ DD = D
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+ /* Do the following 16 operations. */
+ [ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4]
+ [ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8]
+ [ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12]
+ [ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16]
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+ /* Do the following 16 operations. */
+ [ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20]
+ [ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24]
+ [ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28]
+ [ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32]
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+ /* Do the following 16 operations. */
+ [ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36]
+ [ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40]
+ [ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44]
+ [ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48]
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+ /* Do the following 16 operations. */
+ [ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52]
+ [ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56]
+ [ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60]
+ [ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64]
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ A = A + AA
+ B = B + BB
+ C = C + CC
+ D = D + DD
+
+ end /* of loop on i */
+
+
+
+Rivest [Page 5]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+3.5 Step 5. Output
+
+ The message digest produced as output is A, B, C, D. That is, we
+ begin with the low-order byte of A, and end with the high-order byte
+ of D.
+
+ This completes the description of MD5. A reference implementation in
+ C is given in the appendix.
+
+4. Summary
+
+ The MD5 message-digest algorithm is simple to implement, and provides
+ a "fingerprint" or message digest of a message of arbitrary length.
+ It is conjectured that the difficulty of coming up with two messages
+ having the same message digest is on the order of 2^64 operations,
+ and that the difficulty of coming up with any message having a given
+ message digest is on the order of 2^128 operations. The MD5 algorithm
+ has been carefully scrutinized for weaknesses. It is, however, a
+ relatively new algorithm and further security analysis is of course
+ justified, as is the case with any new proposal of this sort.
+
+5. Differences Between MD4 and MD5
+
+ The following are the differences between MD4 and MD5:
+
+ 1. A fourth round has been added.
+
+ 2. Each step now has a unique additive constant.
+
+ 3. The function g in round 2 was changed from (XY v XZ v YZ) to
+ (XZ v Y not(Z)) to make g less symmetric.
+
+ 4. Each step now adds in the result of the previous step. This
+ promotes a faster "avalanche effect".
+
+ 5. The order in which input words are accessed in rounds 2 and
+ 3 is changed, to make these patterns less like each other.
+
+ 6. The shift amounts in each round have been approximately
+ optimized, to yield a faster "avalanche effect." The shifts in
+ different rounds are distinct.
+
+
+
+
+
+
+
+
+
+
+Rivest [Page 6]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+References
+
+ [1] Rivest, R., "The MD4 Message Digest Algorithm", RFC 1320, MIT and
+ RSA Data Security, Inc., April 1992.
+
+ [2] Rivest, R., "The MD4 message digest algorithm", in A.J. Menezes
+ and S.A. Vanstone, editors, Advances in Cryptology - CRYPTO '90
+ Proceedings, pages 303-311, Springer-Verlag, 1991.
+
+ [3] CCITT Recommendation X.509 (1988), "The Directory -
+ Authentication Framework."
+
+APPENDIX A - Reference Implementation
+
+ This appendix contains the following files taken from RSAREF: A
+ Cryptographic Toolkit for Privacy-Enhanced Mail:
+
+ global.h -- global header file
+
+ md5.h -- header file for MD5
+
+ md5c.c -- source code for MD5
+
+ For more information on RSAREF, send email to <rsaref@rsa.com>.
+
+ The appendix also includes the following file:
+
+ mddriver.c -- test driver for MD2, MD4 and MD5
+
+ The driver compiles for MD5 by default but can compile for MD2 or MD4
+ if the symbol MD is defined on the C compiler command line as 2 or 4.
+
+ The implementation is portable and should work on many different
+ plaforms. However, it is not difficult to optimize the implementation
+ on particular platforms, an exercise left to the reader. For example,
+ on "little-endian" platforms where the lowest-addressed byte in a 32-
+ bit word is the least significant and there are no alignment
+ restrictions, the call to Decode in MD5Transform can be replaced with
+ a typecast.
+
+A.1 global.h
+
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+The following makes PROTOTYPES default to 0 if it has not already
+
+
+
+Rivest [Page 7]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 0
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+A.2 md5.h
+
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+
+
+
+Rivest [Page 8]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init PROTO_LIST ((MD5_CTX *));
+void MD5Update PROTO_LIST
+ ((MD5_CTX *, unsigned char *, unsigned int));
+void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+
+A.3 md5c.c
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+#include "global.h"
+#include "md5.h"
+
+/* Constants for MD5Transform routine.
+ */
+
+
+
+Rivest [Page 9]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
+static void Encode PROTO_LIST
+ ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+ ((UINT4 *, unsigned char *, unsigned int));
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+
+
+
+Rivest [Page 10]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init (context)
+MD5_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD5Update (context, input, inputLen)
+MD5_CTX *context; /* context */
+unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+
+
+
+Rivest [Page 11]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+
+
+
+Rivest [Page 12]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+
+
+
+Rivest [Page 13]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+
+
+
+Rivest [Page 14]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+*/
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+
+
+
+Rivest [Page 15]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+
+A.4 mddriver.c
+
+/* MDDRIVER.C - test driver for MD2, MD4 and MD5
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+rights reserved.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* The following makes MD default to MD5 if it has not already been
+ defined with C compiler flags.
+ */
+#ifndef MD
+#define MD MD5
+#endif
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include "global.h"
+#if MD == 2
+#include "md2.h"
+#endif
+#if MD == 4
+
+
+
+Rivest [Page 16]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+#include "md4.h"
+#endif
+#if MD == 5
+#include "md5.h"
+#endif
+
+/* Length of test block, number of test blocks.
+ */
+#define TEST_BLOCK_LEN 1000
+#define TEST_BLOCK_COUNT 1000
+
+static void MDString PROTO_LIST ((char *));
+static void MDTimeTrial PROTO_LIST ((void));
+static void MDTestSuite PROTO_LIST ((void));
+static void MDFile PROTO_LIST ((char *));
+static void MDFilter PROTO_LIST ((void));
+static void MDPrint PROTO_LIST ((unsigned char [16]));
+
+#if MD == 2
+#define MD_CTX MD2_CTX
+#define MDInit MD2Init
+#define MDUpdate MD2Update
+#define MDFinal MD2Final
+#endif
+#if MD == 4
+#define MD_CTX MD4_CTX
+#define MDInit MD4Init
+#define MDUpdate MD4Update
+#define MDFinal MD4Final
+#endif
+#if MD == 5
+#define MD_CTX MD5_CTX
+#define MDInit MD5Init
+#define MDUpdate MD5Update
+#define MDFinal MD5Final
+#endif
+
+/* Main driver.
+
+Arguments (may be any combination):
+ -sstring - digests string
+ -t - runs time trial
+ -x - runs test script
+ filename - digests file
+ (none) - digests standard input
+ */
+int main (argc, argv)
+int argc;
+
+
+
+Rivest [Page 17]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+char *argv[];
+{
+ int i;
+
+ if (argc > 1)
+ for (i = 1; i < argc; i++)
+ if (argv[i][0] == '-' && argv[i][1] == 's')
+ MDString (argv[i] + 2);
+ else if (strcmp (argv[i], "-t") == 0)
+ MDTimeTrial ();
+ else if (strcmp (argv[i], "-x") == 0)
+ MDTestSuite ();
+ else
+ MDFile (argv[i]);
+ else
+ MDFilter ();
+
+ return (0);
+}
+
+/* Digests a string and prints the result.
+ */
+static void MDString (string)
+char *string;
+{
+ MD_CTX context;
+ unsigned char digest[16];
+ unsigned int len = strlen (string);
+
+ MDInit (&context);
+ MDUpdate (&context, string, len);
+ MDFinal (digest, &context);
+
+ printf ("MD%d (\"%s\") = ", MD, string);
+ MDPrint (digest);
+ printf ("\n");
+}
+
+/* Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte
+ blocks.
+ */
+static void MDTimeTrial ()
+{
+ MD_CTX context;
+ time_t endTime, startTime;
+ unsigned char block[TEST_BLOCK_LEN], digest[16];
+ unsigned int i;
+
+
+
+
+Rivest [Page 18]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ printf
+ ("MD%d time trial. Digesting %d %d-byte blocks ...", MD,
+ TEST_BLOCK_LEN, TEST_BLOCK_COUNT);
+
+ /* Initialize block */
+ for (i = 0; i < TEST_BLOCK_LEN; i++)
+ block[i] = (unsigned char)(i & 0xff);
+
+ /* Start timer */
+ time (&startTime);
+
+ /* Digest blocks */
+ MDInit (&context);
+ for (i = 0; i < TEST_BLOCK_COUNT; i++)
+ MDUpdate (&context, block, TEST_BLOCK_LEN);
+ MDFinal (digest, &context);
+
+ /* Stop timer */
+ time (&endTime);
+
+ printf (" done\n");
+ printf ("Digest = ");
+ MDPrint (digest);
+ printf ("\nTime = %ld seconds\n", (long)(endTime-startTime));
+ printf
+ ("Speed = %ld bytes/second\n",
+ (long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/(endTime-startTime));
+}
+
+/* Digests a reference suite of strings and prints the results.
+ */
+static void MDTestSuite ()
+{
+ printf ("MD%d test suite:\n", MD);
+
+ MDString ("");
+ MDString ("a");
+ MDString ("abc");
+ MDString ("message digest");
+ MDString ("abcdefghijklmnopqrstuvwxyz");
+ MDString
+ ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+ MDString
+ ("1234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890");
+}
+
+/* Digests a file and prints the result.
+
+
+
+Rivest [Page 19]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ */
+static void MDFile (filename)
+char *filename;
+{
+ FILE *file;
+ MD_CTX context;
+ int len;
+ unsigned char buffer[1024], digest[16];
+
+ if ((file = fopen (filename, "rb")) == NULL)
+ printf ("%s can't be opened\n", filename);
+
+ else {
+ MDInit (&context);
+ while (len = fread (buffer, 1, 1024, file))
+ MDUpdate (&context, buffer, len);
+ MDFinal (digest, &context);
+
+ fclose (file);
+
+ printf ("MD%d (%s) = ", MD, filename);
+ MDPrint (digest);
+ printf ("\n");
+ }
+}
+
+/* Digests the standard input and prints the result.
+ */
+static void MDFilter ()
+{
+ MD_CTX context;
+ int len;
+ unsigned char buffer[16], digest[16];
+
+ MDInit (&context);
+ while (len = fread (buffer, 1, 16, stdin))
+ MDUpdate (&context, buffer, len);
+ MDFinal (digest, &context);
+
+ MDPrint (digest);
+ printf ("\n");
+}
+
+/* Prints a message digest in hexadecimal.
+ */
+static void MDPrint (digest)
+unsigned char digest[16];
+{
+
+
+
+Rivest [Page 20]
+
+RFC 1321 MD5 Message-Digest Algorithm April 1992
+
+
+ unsigned int i;
+
+ for (i = 0; i < 16; i++)
+ printf ("%02x", digest[i]);
+}
+
+A.5 Test suite
+
+ The MD5 test suite (driver option "-x") should print the following
+ results:
+
+MD5 test suite:
+MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
+MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
+MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
+MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
+MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
+MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") =
+d174ab98d277d9f5a5611c2c9f419d9f
+MD5 ("123456789012345678901234567890123456789012345678901234567890123456
+78901234567890") = 57edf4a22be3c955ac49da2e2107b67a
+
+Security Considerations
+
+ The level of security discussed in this memo is considered to be
+ sufficient for implementing very high security hybrid digital-
+ signature schemes based on MD5 and a public-key cryptosystem.
+
+Author's Address
+
+ Ronald L. Rivest
+ Massachusetts Institute of Technology
+ Laboratory for Computer Science
+ NE43-324
+ 545 Technology Square
+ Cambridge, MA 02139-1986
+
+ Phone: (617) 253-5880
+ EMail: rivest@theory.lcs.mit.edu
+
+
+
+
+
+
+
+
+
+
+
+
+Rivest [Page 21]
+ \ No newline at end of file
diff --git a/standards/rfc2046.txt b/standards/rfc2046.txt
new file mode 100644
index 000000000..84d90c109
--- /dev/null
+++ b/standards/rfc2046.txt
@@ -0,0 +1,2467 @@
+
+
+
+
+
+
+Network Working Group N. Freed
+Request for Comments: 2046 Innosoft
+Obsoletes: 1521, 1522, 1590 N. Borenstein
+Category: Standards Track First Virtual
+ November 1996
+
+
+ Multipurpose Internet Mail Extensions
+ (MIME) Part Two:
+ Media Types
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Abstract
+
+ STD 11, RFC 822 defines a message representation protocol specifying
+ considerable detail about US-ASCII message headers, but which leaves
+ the message content, or message body, as flat US-ASCII text. This
+ set of documents, collectively called the Multipurpose Internet Mail
+ Extensions, or MIME, redefines the format of messages to allow for
+
+ (1) textual message bodies in character sets other than
+ US-ASCII,
+
+ (2) an extensible set of different formats for non-textual
+ message bodies,
+
+ (3) multi-part message bodies, and
+
+ (4) textual header information in character sets other than
+ US-ASCII.
+
+ These documents are based on earlier work documented in RFC 934, STD
+ 11, and RFC 1049, but extends and revises them. Because RFC 822 said
+ so little about message bodies, these documents are largely
+ orthogonal to (rather than a revision of) RFC 822.
+
+ The initial document in this set, RFC 2045, specifies the various
+ headers used to describe the structure of MIME messages. This second
+ document defines the general structure of the MIME media typing
+ system and defines an initial set of media types. The third document,
+ RFC 2047, describes extensions to RFC 822 to allow non-US-ASCII text
+
+
+
+Freed & Borenstein Standards Track [Page 1]
+
+RFC 2046 Media Types November 1996
+
+
+ data in Internet mail header fields. The fourth document, RFC 2048,
+ specifies various IANA registration procedures for MIME-related
+ facilities. The fifth and final document, RFC 2049, describes MIME
+ conformance criteria as well as providing some illustrative examples
+ of MIME message formats, acknowledgements, and the bibliography.
+
+ These documents are revisions of RFCs 1521 and 1522, which themselves
+ were revisions of RFCs 1341 and 1342. An appendix in RFC 2049
+ describes differences and changes from previous versions.
+
+Table of Contents
+
+ 1. Introduction ......................................... 3
+ 2. Definition of a Top-Level Media Type ................. 4
+ 3. Overview Of The Initial Top-Level Media Types ........ 4
+ 4. Discrete Media Type Values ........................... 6
+ 4.1 Text Media Type ..................................... 6
+ 4.1.1 Representation of Line Breaks ..................... 7
+ 4.1.2 Charset Parameter ................................. 7
+ 4.1.3 Plain Subtype ..................................... 11
+ 4.1.4 Unrecognized Subtypes ............................. 11
+ 4.2 Image Media Type .................................... 11
+ 4.3 Audio Media Type .................................... 11
+ 4.4 Video Media Type .................................... 12
+ 4.5 Application Media Type .............................. 12
+ 4.5.1 Octet-Stream Subtype .............................. 13
+ 4.5.2 PostScript Subtype ................................ 14
+ 4.5.3 Other Application Subtypes ........................ 17
+ 5. Composite Media Type Values .......................... 17
+ 5.1 Multipart Media Type ................................ 17
+ 5.1.1 Common Syntax ..................................... 19
+ 5.1.2 Handling Nested Messages and Multiparts ........... 24
+ 5.1.3 Mixed Subtype ..................................... 24
+ 5.1.4 Alternative Subtype ............................... 24
+ 5.1.5 Digest Subtype .................................... 26
+ 5.1.6 Parallel Subtype .................................. 27
+ 5.1.7 Other Multipart Subtypes .......................... 28
+ 5.2 Message Media Type .................................. 28
+ 5.2.1 RFC822 Subtype .................................... 28
+ 5.2.2 Partial Subtype ................................... 29
+ 5.2.2.1 Message Fragmentation and Reassembly ............ 30
+ 5.2.2.2 Fragmentation and Reassembly Example ............ 31
+ 5.2.3 External-Body Subtype ............................. 33
+ 5.2.4 Other Message Subtypes ............................ 40
+ 6. Experimental Media Type Values ....................... 40
+ 7. Summary .............................................. 41
+ 8. Security Considerations .............................. 41
+ 9. Authors' Addresses ................................... 42
+
+
+
+Freed & Borenstein Standards Track [Page 2]
+
+RFC 2046 Media Types November 1996
+
+
+ A. Collected Grammar .................................... 43
+
+1. Introduction
+
+ The first document in this set, RFC 2045, defines a number of header
+ fields, including Content-Type. The Content-Type field is used to
+ specify the nature of the data in the body of a MIME entity, by
+ giving media type and subtype identifiers, and by providing auxiliary
+ information that may be required for certain media types. After the
+ type and subtype names, the remainder of the header field is simply a
+ set of parameters, specified in an attribute/value notation. The
+ ordering of parameters is not significant.
+
+ In general, the top-level media type is used to declare the general
+ type of data, while the subtype specifies a specific format for that
+ type of data. Thus, a media type of "image/xyz" is enough to tell a
+ user agent that the data is an image, even if the user agent has no
+ knowledge of the specific image format "xyz". Such information can
+ be used, for example, to decide whether or not to show a user the raw
+ data from an unrecognized subtype -- such an action might be
+ reasonable for unrecognized subtypes of "text", but not for
+ unrecognized subtypes of "image" or "audio". For this reason,
+ registered subtypes of "text", "image", "audio", and "video" should
+ not contain embedded information that is really of a different type.
+ Such compound formats should be represented using the "multipart" or
+ "application" types.
+
+ Parameters are modifiers of the media subtype, and as such do not
+ fundamentally affect the nature of the content. The set of
+ meaningful parameters depends on the media type and subtype. Most
+ parameters are associated with a single specific subtype. However, a
+ given top-level media type may define parameters which are applicable
+ to any subtype of that type. Parameters may be required by their
+ defining media type or subtype or they may be optional. MIME
+ implementations must also ignore any parameters whose names they do
+ not recognize.
+
+ MIME's Content-Type header field and media type mechanism has been
+ carefully designed to be extensible, and it is expected that the set
+ of media type/subtype pairs and their associated parameters will grow
+ significantly over time. Several other MIME facilities, such as
+ transfer encodings and "message/external-body" access types, are
+ likely to have new values defined over time. In order to ensure that
+ the set of such values is developed in an orderly, well-specified,
+ and public manner, MIME sets up a registration process which uses the
+ Internet Assigned Numbers Authority (IANA) as a central registry for
+ MIME's various areas of extensibility. The registration process for
+ these areas is described in a companion document, RFC 2048.
+
+
+
+Freed & Borenstein Standards Track [Page 3]
+
+RFC 2046 Media Types November 1996
+
+
+ The initial seven standard top-level media type are defined and
+ described in the remainder of this document.
+
+2. Definition of a Top-Level Media Type
+
+ The definition of a top-level media type consists of:
+
+ (1) a name and a description of the type, including
+ criteria for whether a particular type would qualify
+ under that type,
+
+ (2) the names and definitions of parameters, if any, which
+ are defined for all subtypes of that type (including
+ whether such parameters are required or optional),
+
+ (3) how a user agent and/or gateway should handle unknown
+ subtypes of this type,
+
+ (4) general considerations on gatewaying entities of this
+ top-level type, if any, and
+
+ (5) any restrictions on content-transfer-encodings for
+ entities of this top-level type.
+
+3. Overview Of The Initial Top-Level Media Types
+
+ The five discrete top-level media types are:
+
+ (1) text -- textual information. The subtype "plain" in
+ particular indicates plain text containing no
+ formatting commands or directives of any sort. Plain
+ text is intended to be displayed "as-is". No special
+ software is required to get the full meaning of the
+ text, aside from support for the indicated character
+ set. Other subtypes are to be used for enriched text in
+ forms where application software may enhance the
+ appearance of the text, but such software must not be
+ required in order to get the general idea of the
+ content. Possible subtypes of "text" thus include any
+ word processor format that can be read without
+ resorting to software that understands the format. In
+ particular, formats that employ embeddded binary
+ formatting information are not considered directly
+ readable. A very simple and portable subtype,
+ "richtext", was defined in RFC 1341, with a further
+ revision in RFC 1896 under the name "enriched".
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 4]
+
+RFC 2046 Media Types November 1996
+
+
+ (2) image -- image data. "Image" requires a display device
+ (such as a graphical display, a graphics printer, or a
+ FAX machine) to view the information. An initial
+ subtype is defined for the widely-used image format
+ JPEG. . subtypes are defined for two widely-used image
+ formats, jpeg and gif.
+
+ (3) audio -- audio data. "Audio" requires an audio output
+ device (such as a speaker or a telephone) to "display"
+ the contents. An initial subtype "basic" is defined in
+ this document.
+
+ (4) video -- video data. "Video" requires the capability
+ to display moving images, typically including
+ specialized hardware and software. An initial subtype
+ "mpeg" is defined in this document.
+
+ (5) application -- some other kind of data, typically
+ either uninterpreted binary data or information to be
+ processed by an application. The subtype "octet-
+ stream" is to be used in the case of uninterpreted
+ binary data, in which case the simplest recommended
+ action is to offer to write the information into a file
+ for the user. The "PostScript" subtype is also defined
+ for the transport of PostScript material. Other
+ expected uses for "application" include spreadsheets,
+ data for mail-based scheduling systems, and languages
+ for "active" (computational) messaging, and word
+ processing formats that are not directly readable.
+ Note that security considerations may exist for some
+ types of application data, most notably
+ "application/PostScript" and any form of active
+ messaging. These issues are discussed later in this
+ document.
+
+ The two composite top-level media types are:
+
+ (1) multipart -- data consisting of multiple entities of
+ independent data types. Four subtypes are initially
+ defined, including the basic "mixed" subtype specifying
+ a generic mixed set of parts, "alternative" for
+ representing the same data in multiple formats,
+ "parallel" for parts intended to be viewed
+ simultaneously, and "digest" for multipart entities in
+ which each part has a default type of "message/rfc822".
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 5]
+
+RFC 2046 Media Types November 1996
+
+
+ (2) message -- an encapsulated message. A body of media
+ type "message" is itself all or a portion of some kind
+ of message object. Such objects may or may not in turn
+ contain other entities. The "rfc822" subtype is used
+ when the encapsulated content is itself an RFC 822
+ message. The "partial" subtype is defined for partial
+ RFC 822 messages, to permit the fragmented transmission
+ of bodies that are thought to be too large to be passed
+ through transport facilities in one piece. Another
+ subtype, "external-body", is defined for specifying
+ large bodies by reference to an external data source.
+
+ It should be noted that the list of media type values given here may
+ be augmented in time, via the mechanisms described above, and that
+ the set of subtypes is expected to grow substantially.
+
+4. Discrete Media Type Values
+
+ Five of the seven initial media type values refer to discrete bodies.
+ The content of these types must be handled by non-MIME mechanisms;
+ they are opaque to MIME processors.
+
+4.1. Text Media Type
+
+ The "text" media type is intended for sending material which is
+ principally textual in form. A "charset" parameter may be used to
+ indicate the character set of the body text for "text" subtypes,
+ notably including the subtype "text/plain", which is a generic
+ subtype for plain text. Plain text does not provide for or allow
+ formatting commands, font attribute specifications, processing
+ instructions, interpretation directives, or content markup. Plain
+ text is seen simply as a linear sequence of characters, possibly
+ interrupted by line breaks or page breaks. Plain text may allow the
+ stacking of several characters in the same position in the text.
+ Plain text in scripts like Arabic and Hebrew may also include
+ facilitites that allow the arbitrary mixing of text segments with
+ opposite writing directions.
+
+ Beyond plain text, there are many formats for representing what might
+ be known as "rich text". An interesting characteristic of many such
+ representations is that they are to some extent readable even without
+ the software that interprets them. It is useful, then, to
+ distinguish them, at the highest level, from such unreadable data as
+ images, audio, or text represented in an unreadable form. In the
+ absence of appropriate interpretation software, it is reasonable to
+ show subtypes of "text" to the user, while it is not reasonable to do
+ so with most nontextual data. Such formatted textual data should be
+ represented using subtypes of "text".
+
+
+
+Freed & Borenstein Standards Track [Page 6]
+
+RFC 2046 Media Types November 1996
+
+
+4.1.1. Representation of Line Breaks
+
+ The canonical form of any MIME "text" subtype MUST always represent a
+ line break as a CRLF sequence. Similarly, any occurrence of CRLF in
+ MIME "text" MUST represent a line break. Use of CR and LF outside of
+ line break sequences is also forbidden.
+
+ This rule applies regardless of format or character set or sets
+ involved.
+
+ NOTE: The proper interpretation of line breaks when a body is
+ displayed depends on the media type. In particular, while it is
+ appropriate to treat a line break as a transition to a new line when
+ displaying a "text/plain" body, this treatment is actually incorrect
+ for other subtypes of "text" like "text/enriched" [RFC-1896].
+ Similarly, whether or not line breaks should be added during display
+ operations is also a function of the media type. It should not be
+ necessary to add any line breaks to display "text/plain" correctly,
+ whereas proper display of "text/enriched" requires the appropriate
+ addition of line breaks.
+
+ NOTE: Some protocols defines a maximum line length. E.g. SMTP [RFC-
+ 821] allows a maximum of 998 octets before the next CRLF sequence.
+ To be transported by such protocols, data which includes too long
+ segments without CRLF sequences must be encoded with a suitable
+ content-transfer-encoding.
+
+4.1.2. Charset Parameter
+
+ A critical parameter that may be specified in the Content-Type field
+ for "text/plain" data is the character set. This is specified with a
+ "charset" parameter, as in:
+
+ Content-type: text/plain; charset=iso-8859-1
+
+ Unlike some other parameter values, the values of the charset
+ parameter are NOT case sensitive. The default character set, which
+ must be assumed in the absence of a charset parameter, is US-ASCII.
+
+ The specification for any future subtypes of "text" must specify
+ whether or not they will also utilize a "charset" parameter, and may
+ possibly restrict its values as well. For other subtypes of "text"
+ than "text/plain", the semantics of the "charset" parameter should be
+ defined to be identical to those specified here for "text/plain",
+ i.e., the body consists entirely of characters in the given charset.
+ In particular, definers of future "text" subtypes should pay close
+ attention to the implications of multioctet character sets for their
+ subtype definitions.
+
+
+
+Freed & Borenstein Standards Track [Page 7]
+
+RFC 2046 Media Types November 1996
+
+
+ The charset parameter for subtypes of "text" gives a name of a
+ character set, as "character set" is defined in RFC 2045. The rules
+ regarding line breaks detailed in the previous section must also be
+ observed -- a character set whose definition does not conform to
+ these rules cannot be used in a MIME "text" subtype.
+
+ An initial list of predefined character set names can be found at the
+ end of this section. Additional character sets may be registered
+ with IANA.
+
+ Other media types than subtypes of "text" might choose to employ the
+ charset parameter as defined here, but with the CRLF/line break
+ restriction removed. Therefore, all character sets that conform to
+ the general definition of "character set" in RFC 2045 can be
+ registered for MIME use.
+
+ Note that if the specified character set includes 8-bit characters
+ and such characters are used in the body, a Content-Transfer-Encoding
+ header field and a corresponding encoding on the data are required in
+ order to transmit the body via some mail transfer protocols, such as
+ SMTP [RFC-821].
+
+ The default character set, US-ASCII, has been the subject of some
+ confusion and ambiguity in the past. Not only were there some
+ ambiguities in the definition, there have been wide variations in
+ practice. In order to eliminate such ambiguity and variations in the
+ future, it is strongly recommended that new user agents explicitly
+ specify a character set as a media type parameter in the Content-Type
+ header field. "US-ASCII" does not indicate an arbitrary 7-bit
+ character set, but specifies that all octets in the body must be
+ interpreted as characters according to the US-ASCII character set.
+ National and application-oriented versions of ISO 646 [ISO-646] are
+ usually NOT identical to US-ASCII, and in that case their use in
+ Internet mail is explicitly discouraged. The omission of the ISO 646
+ character set from this document is deliberate in this regard. The
+ character set name of "US-ASCII" explicitly refers to the character
+ set defined in ANSI X3.4-1986 [US- ASCII]. The new international
+ reference version (IRV) of the 1991 edition of ISO 646 is identical
+ to US-ASCII. The character set name "ASCII" is reserved and must not
+ be used for any purpose.
+
+ NOTE: RFC 821 explicitly specifies "ASCII", and references an earlier
+ version of the American Standard. Insofar as one of the purposes of
+ specifying a media type and character set is to permit the receiver
+ to unambiguously determine how the sender intended the coded message
+ to be interpreted, assuming anything other than "strict ASCII" as the
+ default would risk unintentional and incompatible changes to the
+ semantics of messages now being transmitted. This also implies that
+
+
+
+Freed & Borenstein Standards Track [Page 8]
+
+RFC 2046 Media Types November 1996
+
+
+ messages containing characters coded according to other versions of
+ ISO 646 than US-ASCII and the 1991 IRV, or using code-switching
+ procedures (e.g., those of ISO 2022), as well as 8bit or multiple
+ octet character encodings MUST use an appropriate character set
+ specification to be consistent with MIME.
+
+ The complete US-ASCII character set is listed in ANSI X3.4- 1986.
+ Note that the control characters including DEL (0-31, 127) have no
+ defined meaning in apart from the combination CRLF (US-ASCII values
+ 13 and 10) indicating a new line. Two of the characters have de
+ facto meanings in wide use: FF (12) often means "start subsequent
+ text on the beginning of a new page"; and TAB or HT (9) often (though
+ not always) means "move the cursor to the next available column after
+ the current position where the column number is a multiple of 8
+ (counting the first column as column 0)." Aside from these
+ conventions, any use of the control characters or DEL in a body must
+ either occur
+
+ (1) because a subtype of text other than "plain"
+ specifically assigns some additional meaning, or
+
+ (2) within the context of a private agreement between the
+ sender and recipient. Such private agreements are
+ discouraged and should be replaced by the other
+ capabilities of this document.
+
+ NOTE: An enormous proliferation of character sets exist beyond US-
+ ASCII. A large number of partially or totally overlapping character
+ sets is NOT a good thing. A SINGLE character set that can be used
+ universally for representing all of the world's languages in Internet
+ mail would be preferrable. Unfortunately, existing practice in
+ several communities seems to point to the continued use of multiple
+ character sets in the near future. A small number of standard
+ character sets are, therefore, defined for Internet use in this
+ document.
+
+ The defined charset values are:
+
+ (1) US-ASCII -- as defined in ANSI X3.4-1986 [US-ASCII].
+
+ (2) ISO-8859-X -- where "X" is to be replaced, as
+ necessary, for the parts of ISO-8859 [ISO-8859]. Note
+ that the ISO 646 character sets have deliberately been
+ omitted in favor of their 8859 replacements, which are
+ the designated character sets for Internet mail. As of
+ the publication of this document, the legitimate values
+ for "X" are the digits 1 through 10.
+
+
+
+
+Freed & Borenstein Standards Track [Page 9]
+
+RFC 2046 Media Types November 1996
+
+
+ Characters in the range 128-159 has no assigned meaning in ISO-8859-
+ X. Characters with values below 128 in ISO-8859-X have the same
+ assigned meaning as they do in US-ASCII.
+
+ Part 6 of ISO 8859 (Latin/Arabic alphabet) and part 8 (Latin/Hebrew
+ alphabet) includes both characters for which the normal writing
+ direction is right to left and characters for which it is left to
+ right, but do not define a canonical ordering method for representing
+ bi-directional text. The charset values "ISO-8859-6" and "ISO-8859-
+ 8", however, specify that the visual method is used [RFC-1556].
+
+ All of these character sets are used as pure 7bit or 8bit sets
+ without any shift or escape functions. The meaning of shift and
+ escape sequences in these character sets is not defined.
+
+ The character sets specified above are the ones that were relatively
+ uncontroversial during the drafting of MIME. This document does not
+ endorse the use of any particular character set other than US-ASCII,
+ and recognizes that the future evolution of world character sets
+ remains unclear.
+
+ Note that the character set used, if anything other than US- ASCII,
+ must always be explicitly specified in the Content-Type field.
+
+ No character set name other than those defined above may be used in
+ Internet mail without the publication of a formal specification and
+ its registration with IANA, or by private agreement, in which case
+ the character set name must begin with "X-".
+
+ Implementors are discouraged from defining new character sets unless
+ absolutely necessary.
+
+ The "charset" parameter has been defined primarily for the purpose of
+ textual data, and is described in this section for that reason.
+ However, it is conceivable that non-textual data might also wish to
+ specify a charset value for some purpose, in which case the same
+ syntax and values should be used.
+
+ In general, composition software should always use the "lowest common
+ denominator" character set possible. For example, if a body contains
+ only US-ASCII characters, it SHOULD be marked as being in the US-
+ ASCII character set, not ISO-8859-1, which, like all the ISO-8859
+ family of character sets, is a superset of US-ASCII. More generally,
+ if a widely-used character set is a subset of another character set,
+ and a body contains only characters in the widely-used subset, it
+ should be labelled as being in that subset. This will increase the
+ chances that the recipient will be able to view the resulting entity
+ correctly.
+
+
+
+Freed & Borenstein Standards Track [Page 10]
+
+RFC 2046 Media Types November 1996
+
+
+4.1.3. Plain Subtype
+
+ The simplest and most important subtype of "text" is "plain". This
+ indicates plain text that does not contain any formatting commands or
+ directives. Plain text is intended to be displayed "as-is", that is,
+ no interpretation of embedded formatting commands, font attribute
+ specifications, processing instructions, interpretation directives,
+ or content markup should be necessary for proper display. The
+ default media type of "text/plain; charset=us-ascii" for Internet
+ mail describes existing Internet practice. That is, it is the type
+ of body defined by RFC 822.
+
+ No other "text" subtype is defined by this document.
+
+4.1.4. Unrecognized Subtypes
+
+ Unrecognized subtypes of "text" should be treated as subtype "plain"
+ as long as the MIME implementation knows how to handle the charset.
+ Unrecognized subtypes which also specify an unrecognized charset
+ should be treated as "application/octet- stream".
+
+4.2. Image Media Type
+
+ A media type of "image" indicates that the body contains an image.
+ The subtype names the specific image format. These names are not
+ case sensitive. An initial subtype is "jpeg" for the JPEG format
+ using JFIF encoding [JPEG].
+
+ The list of "image" subtypes given here is neither exclusive nor
+ exhaustive, and is expected to grow as more types are registered with
+ IANA, as described in RFC 2048.
+
+ Unrecognized subtypes of "image" should at a miniumum be treated as
+ "application/octet-stream". Implementations may optionally elect to
+ pass subtypes of "image" that they do not specifically recognize to a
+ secure and robust general-purpose image viewing application, if such
+ an application is available.
+
+ NOTE: Using of a generic-purpose image viewing application this way
+ inherits the security problems of the most dangerous type supported
+ by the application.
+
+4.3. Audio Media Type
+
+ A media type of "audio" indicates that the body contains audio data.
+ Although there is not yet a consensus on an "ideal" audio format for
+ use with computers, there is a pressing need for a format capable of
+ providing interoperable behavior.
+
+
+
+Freed & Borenstein Standards Track [Page 11]
+
+RFC 2046 Media Types November 1996
+
+
+ The initial subtype of "basic" is specified to meet this requirement
+ by providing an absolutely minimal lowest common denominator audio
+ format. It is expected that richer formats for higher quality and/or
+ lower bandwidth audio will be defined by a later document.
+
+ The content of the "audio/basic" subtype is single channel audio
+ encoded using 8bit ISDN mu-law [PCM] at a sample rate of 8000 Hz.
+
+ Unrecognized subtypes of "audio" should at a miniumum be treated as
+ "application/octet-stream". Implementations may optionally elect to
+ pass subtypes of "audio" that they do not specifically recognize to a
+ robust general-purpose audio playing application, if such an
+ application is available.
+
+4.4. Video Media Type
+
+ A media type of "video" indicates that the body contains a time-
+ varying-picture image, possibly with color and coordinated sound.
+ The term 'video' is used in its most generic sense, rather than with
+ reference to any particular technology or format, and is not meant to
+ preclude subtypes such as animated drawings encoded compactly. The
+ subtype "mpeg" refers to video coded according to the MPEG standard
+ [MPEG].
+
+ Note that although in general this document strongly discourages the
+ mixing of multiple media in a single body, it is recognized that many
+ so-called video formats include a representation for synchronized
+ audio, and this is explicitly permitted for subtypes of "video".
+
+ Unrecognized subtypes of "video" should at a minumum be treated as
+ "application/octet-stream". Implementations may optionally elect to
+ pass subtypes of "video" that they do not specifically recognize to a
+ robust general-purpose video display application, if such an
+ application is available.
+
+4.5. Application Media Type
+
+ The "application" media type is to be used for discrete data which do
+ not fit in any of the other categories, and particularly for data to
+ be processed by some type of application program. This is
+ information which must be processed by an application before it is
+ viewable or usable by a user. Expected uses for the "application"
+ media type include file transfer, spreadsheets, data for mail-based
+ scheduling systems, and languages for "active" (computational)
+ material. (The latter, in particular, can pose security problems
+ which must be understood by implementors, and are considered in
+ detail in the discussion of the "application/PostScript" media type.)
+
+
+
+
+Freed & Borenstein Standards Track [Page 12]
+
+RFC 2046 Media Types November 1996
+
+
+ For example, a meeting scheduler might define a standard
+ representation for information about proposed meeting dates. An
+ intelligent user agent would use this information to conduct a dialog
+ with the user, and might then send additional material based on that
+ dialog. More generally, there have been several "active" messaging
+ languages developed in which programs in a suitably specialized
+ language are transported to a remote location and automatically run
+ in the recipient's environment.
+
+ Such applications may be defined as subtypes of the "application"
+ media type. This document defines two subtypes:
+
+ octet-stream, and PostScript.
+
+ The subtype of "application" will often be either the name or include
+ part of the name of the application for which the data are intended.
+ This does not mean, however, that any application program name may be
+ used freely as a subtype of "application".
+
+4.5.1. Octet-Stream Subtype
+
+ The "octet-stream" subtype is used to indicate that a body contains
+ arbitrary binary data. The set of currently defined parameters is:
+
+ (1) TYPE -- the general type or category of binary data.
+ This is intended as information for the human recipient
+ rather than for any automatic processing.
+
+ (2) PADDING -- the number of bits of padding that were
+ appended to the bit-stream comprising the actual
+ contents to produce the enclosed 8bit byte-oriented
+ data. This is useful for enclosing a bit-stream in a
+ body when the total number of bits is not a multiple of
+ 8.
+
+ Both of these parameters are optional.
+
+ An additional parameter, "CONVERSIONS", was defined in RFC 1341 but
+ has since been removed. RFC 1341 also defined the use of a "NAME"
+ parameter which gave a suggested file name to be used if the data
+ were to be written to a file. This has been deprecated in
+ anticipation of a separate Content-Disposition header field, to be
+ defined in a subsequent RFC.
+
+ The recommended action for an implementation that receives an
+ "application/octet-stream" entity is to simply offer to put the data
+ in a file, with any Content-Transfer-Encoding undone, or perhaps to
+ use it as input to a user-specified process.
+
+
+
+Freed & Borenstein Standards Track [Page 13]
+
+RFC 2046 Media Types November 1996
+
+
+ To reduce the danger of transmitting rogue programs, it is strongly
+ recommended that implementations NOT implement a path-search
+ mechanism whereby an arbitrary program named in the Content-Type
+ parameter (e.g., an "interpreter=" parameter) is found and executed
+ using the message body as input.
+
+4.5.2. PostScript Subtype
+
+ A media type of "application/postscript" indicates a PostScript
+ program. Currently two variants of the PostScript language are
+ allowed; the original level 1 variant is described in [POSTSCRIPT]
+ and the more recent level 2 variant is described in [POSTSCRIPT2].
+
+ PostScript is a registered trademark of Adobe Systems, Inc. Use of
+ the MIME media type "application/postscript" implies recognition of
+ that trademark and all the rights it entails.
+
+ The PostScript language definition provides facilities for internal
+ labelling of the specific language features a given program uses.
+ This labelling, called the PostScript document structuring
+ conventions, or DSC, is very general and provides substantially more
+ information than just the language level. The use of document
+ structuring conventions, while not required, is strongly recommended
+ as an aid to interoperability. Documents which lack proper
+ structuring conventions cannot be tested to see whether or not they
+ will work in a given environment. As such, some systems may assume
+ the worst and refuse to process unstructured documents.
+
+ The execution of general-purpose PostScript interpreters entails
+ serious security risks, and implementors are discouraged from simply
+ sending PostScript bodies to "off- the-shelf" interpreters. While it
+ is usually safe to send PostScript to a printer, where the potential
+ for harm is greatly constrained by typical printer environments,
+ implementors should consider all of the following before they add
+ interactive display of PostScript bodies to their MIME readers.
+
+ The remainder of this section outlines some, though probably not all,
+ of the possible problems with the transport of PostScript entities.
+
+ (1) Dangerous operations in the PostScript language
+ include, but may not be limited to, the PostScript
+ operators "deletefile", "renamefile", "filenameforall",
+ and "file". "File" is only dangerous when applied to
+ something other than standard input or output.
+ Implementations may also define additional nonstandard
+ file operators; these may also pose a threat to
+ security. "Filenameforall", the wildcard file search
+ operator, may appear at first glance to be harmless.
+
+
+
+Freed & Borenstein Standards Track [Page 14]
+
+RFC 2046 Media Types November 1996
+
+
+ Note, however, that this operator has the potential to
+ reveal information about what files the recipient has
+ access to, and this information may itself be
+ sensitive. Message senders should avoid the use of
+ potentially dangerous file operators, since these
+ operators are quite likely to be unavailable in secure
+ PostScript implementations. Message receiving and
+ displaying software should either completely disable
+ all potentially dangerous file operators or take
+ special care not to delegate any special authority to
+ their operation. These operators should be viewed as
+ being done by an outside agency when interpreting
+ PostScript documents. Such disabling and/or checking
+ should be done completely outside of the reach of the
+ PostScript language itself; care should be taken to
+ insure that no method exists for re-enabling full-
+ function versions of these operators.
+
+ (2) The PostScript language provides facilities for exiting
+ the normal interpreter, or server, loop. Changes made
+ in this "outer" environment are customarily retained
+ across documents, and may in some cases be retained
+ semipermanently in nonvolatile memory. The operators
+ associated with exiting the interpreter loop have the
+ potential to interfere with subsequent document
+ processing. As such, their unrestrained use
+ constitutes a threat of service denial. PostScript
+ operators that exit the interpreter loop include, but
+ may not be limited to, the exitserver and startjob
+ operators. Message sending software should not
+ generate PostScript that depends on exiting the
+ interpreter loop to operate, since the ability to exit
+ will probably be unavailable in secure PostScript
+ implementations. Message receiving and displaying
+ software should completely disable the ability to make
+ retained changes to the PostScript environment by
+ eliminating or disabling the "startjob" and
+ "exitserver" operations. If these operations cannot be
+ eliminated or completely disabled the password
+ associated with them should at least be set to a hard-
+ to-guess value.
+
+ (3) PostScript provides operators for setting system-wide
+ and device-specific parameters. These parameter
+ settings may be retained across jobs and may
+ potentially pose a threat to the correct operation of
+ the interpreter. The PostScript operators that set
+ system and device parameters include, but may not be
+
+
+
+Freed & Borenstein Standards Track [Page 15]
+
+RFC 2046 Media Types November 1996
+
+
+ limited to, the "setsystemparams" and "setdevparams"
+ operators. Message sending software should not
+ generate PostScript that depends on the setting of
+ system or device parameters to operate correctly. The
+ ability to set these parameters will probably be
+ unavailable in secure PostScript implementations.
+ Message receiving and displaying software should
+ disable the ability to change system and device
+ parameters. If these operators cannot be completely
+ disabled the password associated with them should at
+ least be set to a hard-to-guess value.
+
+ (4) Some PostScript implementations provide nonstandard
+ facilities for the direct loading and execution of
+ machine code. Such facilities are quite obviously open
+ to substantial abuse. Message sending software should
+ not make use of such features. Besides being totally
+ hardware-specific, they are also likely to be
+ unavailable in secure implementations of PostScript.
+ Message receiving and displaying software should not
+ allow such operators to be used if they exist.
+
+ (5) PostScript is an extensible language, and many, if not
+ most, implementations of it provide a number of their
+ own extensions. This document does not deal with such
+ extensions explicitly since they constitute an unknown
+ factor. Message sending software should not make use
+ of nonstandard extensions; they are likely to be
+ missing from some implementations. Message receiving
+ and displaying software should make sure that any
+ nonstandard PostScript operators are secure and don't
+ present any kind of threat.
+
+ (6) It is possible to write PostScript that consumes huge
+ amounts of various system resources. It is also
+ possible to write PostScript programs that loop
+ indefinitely. Both types of programs have the
+ potential to cause damage if sent to unsuspecting
+ recipients. Message-sending software should avoid the
+ construction and dissemination of such programs, which
+ is antisocial. Message receiving and displaying
+ software should provide appropriate mechanisms to abort
+ processing after a reasonable amount of time has
+ elapsed. In addition, PostScript interpreters should be
+ limited to the consumption of only a reasonable amount
+ of any given system resource.
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 16]
+
+RFC 2046 Media Types November 1996
+
+
+ (7) It is possible to include raw binary information inside
+ PostScript in various forms. This is not recommended
+ for use in Internet mail, both because it is not
+ supported by all PostScript interpreters and because it
+ significantly complicates the use of a MIME Content-
+ Transfer-Encoding. (Without such binary, PostScript
+ may typically be viewed as line-oriented data. The
+ treatment of CRLF sequences becomes extremely
+ problematic if binary and line-oriented data are mixed
+ in a single Postscript data stream.)
+
+ (8) Finally, bugs may exist in some PostScript interpreters
+ which could possibly be exploited to gain unauthorized
+ access to a recipient's system. Apart from noting this
+ possibility, there is no specific action to take to
+ prevent this, apart from the timely correction of such
+ bugs if any are found.
+
+4.5.3. Other Application Subtypes
+
+ It is expected that many other subtypes of "application" will be
+ defined in the future. MIME implementations must at a minimum treat
+ any unrecognized subtypes as being equivalent to "application/octet-
+ stream".
+
+5. Composite Media Type Values
+
+ The remaining two of the seven initial Content-Type values refer to
+ composite entities. Composite entities are handled using MIME
+ mechanisms -- a MIME processor typically handles the body directly.
+
+5.1. Multipart Media Type
+
+ In the case of multipart entities, in which one or more different
+ sets of data are combined in a single body, a "multipart" media type
+ field must appear in the entity's header. The body must then contain
+ one or more body parts, each preceded by a boundary delimiter line,
+ and the last one followed by a closing boundary delimiter line.
+ After its boundary delimiter line, each body part then consists of a
+ header area, a blank line, and a body area. Thus a body part is
+ similar to an RFC 822 message in syntax, but different in meaning.
+
+ A body part is an entity and hence is NOT to be interpreted as
+ actually being an RFC 822 message. To begin with, NO header fields
+ are actually required in body parts. A body part that starts with a
+ blank line, therefore, is allowed and is a body part for which all
+ default values are to be assumed. In such a case, the absence of a
+ Content-Type header usually indicates that the corresponding body has
+
+
+
+Freed & Borenstein Standards Track [Page 17]
+
+RFC 2046 Media Types November 1996
+
+
+ a content-type of "text/plain; charset=US-ASCII".
+
+ The only header fields that have defined meaning for body parts are
+ those the names of which begin with "Content-". All other header
+ fields may be ignored in body parts. Although they should generally
+ be retained if at all possible, they may be discarded by gateways if
+ necessary. Such other fields are permitted to appear in body parts
+ but must not be depended on. "X-" fields may be created for
+ experimental or private purposes, with the recognition that the
+ information they contain may be lost at some gateways.
+
+ NOTE: The distinction between an RFC 822 message and a body part is
+ subtle, but important. A gateway between Internet and X.400 mail,
+ for example, must be able to tell the difference between a body part
+ that contains an image and a body part that contains an encapsulated
+ message, the body of which is a JPEG image. In order to represent
+ the latter, the body part must have "Content-Type: message/rfc822",
+ and its body (after the blank line) must be the encapsulated message,
+ with its own "Content-Type: image/jpeg" header field. The use of
+ similar syntax facilitates the conversion of messages to body parts,
+ and vice versa, but the distinction between the two must be
+ understood by implementors. (For the special case in which parts
+ actually are messages, a "digest" subtype is also defined.)
+
+ As stated previously, each body part is preceded by a boundary
+ delimiter line that contains the boundary delimiter. The boundary
+ delimiter MUST NOT appear inside any of the encapsulated parts, on a
+ line by itself or as the prefix of any line. This implies that it is
+ crucial that the composing agent be able to choose and specify a
+ unique boundary parameter value that does not contain the boundary
+ parameter value of an enclosing multipart as a prefix.
+
+ All present and future subtypes of the "multipart" type must use an
+ identical syntax. Subtypes may differ in their semantics, and may
+ impose additional restrictions on syntax, but must conform to the
+ required syntax for the "multipart" type. This requirement ensures
+ that all conformant user agents will at least be able to recognize
+ and separate the parts of any multipart entity, even those of an
+ unrecognized subtype.
+
+ As stated in the definition of the Content-Transfer-Encoding field
+ [RFC 2045], no encoding other than "7bit", "8bit", or "binary" is
+ permitted for entities of type "multipart". The "multipart" boundary
+ delimiters and header fields are always represented as 7bit US-ASCII
+ in any case (though the header fields may encode non-US-ASCII header
+ text as per RFC 2047) and data within the body parts can be encoded
+ on a part-by-part basis, with Content-Transfer-Encoding fields for
+ each appropriate body part.
+
+
+
+Freed & Borenstein Standards Track [Page 18]
+
+RFC 2046 Media Types November 1996
+
+
+5.1.1. Common Syntax
+
+ This section defines a common syntax for subtypes of "multipart".
+ All subtypes of "multipart" must use this syntax. A simple example
+ of a multipart message also appears in this section. An example of a
+ more complex multipart message is given in RFC 2049.
+
+ The Content-Type field for multipart entities requires one parameter,
+ "boundary". The boundary delimiter line is then defined as a line
+ consisting entirely of two hyphen characters ("-", decimal value 45)
+ followed by the boundary parameter value from the Content-Type header
+ field, optional linear whitespace, and a terminating CRLF.
+
+ NOTE: The hyphens are for rough compatibility with the earlier RFC
+ 934 method of message encapsulation, and for ease of searching for
+ the boundaries in some implementations. However, it should be noted
+ that multipart messages are NOT completely compatible with RFC 934
+ encapsulations; in particular, they do not obey RFC 934 quoting
+ conventions for embedded lines that begin with hyphens. This
+ mechanism was chosen over the RFC 934 mechanism because the latter
+ causes lines to grow with each level of quoting. The combination of
+ this growth with the fact that SMTP implementations sometimes wrap
+ long lines made the RFC 934 mechanism unsuitable for use in the event
+ that deeply-nested multipart structuring is ever desired.
+
+ WARNING TO IMPLEMENTORS: The grammar for parameters on the Content-
+ type field is such that it is often necessary to enclose the boundary
+ parameter values in quotes on the Content-type line. This is not
+ always necessary, but never hurts. Implementors should be sure to
+ study the grammar carefully in order to avoid producing invalid
+ Content-type fields. Thus, a typical "multipart" Content-Type header
+ field might look like this:
+
+ Content-Type: multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p
+
+ But the following is not valid:
+
+ Content-Type: multipart/mixed; boundary=gc0pJq0M:08jU534c0p
+
+ (because of the colon) and must instead be represented as
+
+ Content-Type: multipart/mixed; boundary="gc0pJq0M:08jU534c0p"
+
+ This Content-Type value indicates that the content consists of one or
+ more parts, each with a structure that is syntactically identical to
+ an RFC 822 message, except that the header area is allowed to be
+ completely empty, and that the parts are each preceded by the line
+
+
+
+
+Freed & Borenstein Standards Track [Page 19]
+
+RFC 2046 Media Types November 1996
+
+
+ --gc0pJq0M:08jU534c0p
+
+ The boundary delimiter MUST occur at the beginning of a line, i.e.,
+ following a CRLF, and the initial CRLF is considered to be attached
+ to the boundary delimiter line rather than part of the preceding
+ part. The boundary may be followed by zero or more characters of
+ linear whitespace. It is then terminated by either another CRLF and
+ the header fields for the next part, or by two CRLFs, in which case
+ there are no header fields for the next part. If no Content-Type
+ field is present it is assumed to be "message/rfc822" in a
+ "multipart/digest" and "text/plain" otherwise.
+
+ NOTE: The CRLF preceding the boundary delimiter line is conceptually
+ attached to the boundary so that it is possible to have a part that
+ does not end with a CRLF (line break). Body parts that must be
+ considered to end with line breaks, therefore, must have two CRLFs
+ preceding the boundary delimiter line, the first of which is part of
+ the preceding body part, and the second of which is part of the
+ encapsulation boundary.
+
+ Boundary delimiters must not appear within the encapsulated material,
+ and must be no longer than 70 characters, not counting the two
+ leading hyphens.
+
+ The boundary delimiter line following the last body part is a
+ distinguished delimiter that indicates that no further body parts
+ will follow. Such a delimiter line is identical to the previous
+ delimiter lines, with the addition of two more hyphens after the
+ boundary parameter value.
+
+ --gc0pJq0M:08jU534c0p--
+
+ NOTE TO IMPLEMENTORS: Boundary string comparisons must compare the
+ boundary value with the beginning of each candidate line. An exact
+ match of the entire candidate line is not required; it is sufficient
+ that the boundary appear in its entirety following the CRLF.
+
+ There appears to be room for additional information prior to the
+ first boundary delimiter line and following the final boundary
+ delimiter line. These areas should generally be left blank, and
+ implementations must ignore anything that appears before the first
+ boundary delimiter line or after the last one.
+
+ NOTE: These "preamble" and "epilogue" areas are generally not used
+ because of the lack of proper typing of these parts and the lack of
+ clear semantics for handling these areas at gateways, particularly
+ X.400 gateways. However, rather than leaving the preamble area
+ blank, many MIME implementations have found this to be a convenient
+
+
+
+Freed & Borenstein Standards Track [Page 20]
+
+RFC 2046 Media Types November 1996
+
+
+ place to insert an explanatory note for recipients who read the
+ message with pre-MIME software, since such notes will be ignored by
+ MIME-compliant software.
+
+ NOTE: Because boundary delimiters must not appear in the body parts
+ being encapsulated, a user agent must exercise care to choose a
+ unique boundary parameter value. The boundary parameter value in the
+ example above could have been the result of an algorithm designed to
+ produce boundary delimiters with a very low probability of already
+ existing in the data to be encapsulated without having to prescan the
+ data. Alternate algorithms might result in more "readable" boundary
+ delimiters for a recipient with an old user agent, but would require
+ more attention to the possibility that the boundary delimiter might
+ appear at the beginning of some line in the encapsulated part. The
+ simplest boundary delimiter line possible is something like "---",
+ with a closing boundary delimiter line of "-----".
+
+ As a very simple example, the following multipart message has two
+ parts, both of them plain text, one of them explicitly typed and one
+ of them implicitly typed:
+
+ From: Nathaniel Borenstein <nsb@bellcore.com>
+ To: Ned Freed <ned@innosoft.com>
+ Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)
+ Subject: Sample message
+ MIME-Version: 1.0
+ Content-type: multipart/mixed; boundary="simple boundary"
+
+ This is the preamble. It is to be ignored, though it
+ is a handy place for composition agents to include an
+ explanatory note to non-MIME conformant readers.
+
+ --simple boundary
+
+ This is implicitly typed plain US-ASCII text.
+ It does NOT end with a linebreak.
+ --simple boundary
+ Content-type: text/plain; charset=us-ascii
+
+ This is explicitly typed plain US-ASCII text.
+ It DOES end with a linebreak.
+
+ --simple boundary--
+
+ This is the epilogue. It is also to be ignored.
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 21]
+
+RFC 2046 Media Types November 1996
+
+
+ The use of a media type of "multipart" in a body part within another
+ "multipart" entity is explicitly allowed. In such cases, for obvious
+ reasons, care must be taken to ensure that each nested "multipart"
+ entity uses a different boundary delimiter. See RFC 2049 for an
+ example of nested "multipart" entities.
+
+ The use of the "multipart" media type with only a single body part
+ may be useful in certain contexts, and is explicitly permitted.
+
+ NOTE: Experience has shown that a "multipart" media type with a
+ single body part is useful for sending non-text media types. It has
+ the advantage of providing the preamble as a place to include
+ decoding instructions. In addition, a number of SMTP gateways move
+ or remove the MIME headers, and a clever MIME decoder can take a good
+ guess at multipart boundaries even in the absence of the Content-Type
+ header and thereby successfully decode the message.
+
+ The only mandatory global parameter for the "multipart" media type is
+ the boundary parameter, which consists of 1 to 70 characters from a
+ set of characters known to be very robust through mail gateways, and
+ NOT ending with white space. (If a boundary delimiter line appears to
+ end with white space, the white space must be presumed to have been
+ added by a gateway, and must be deleted.) It is formally specified
+ by the following BNF:
+
+ boundary := 0*69<bchars> bcharsnospace
+
+ bchars := bcharsnospace / " "
+
+ bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
+ "+" / "_" / "," / "-" / "." /
+ "/" / ":" / "=" / "?"
+
+ Overall, the body of a "multipart" entity may be specified as
+ follows:
+
+ dash-boundary := "--" boundary
+ ; boundary taken from the value of
+ ; boundary parameter of the
+ ; Content-Type field.
+
+ multipart-body := [preamble CRLF]
+ dash-boundary transport-padding CRLF
+ body-part *encapsulation
+ close-delimiter transport-padding
+ [CRLF epilogue]
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 22]
+
+RFC 2046 Media Types November 1996
+
+
+ transport-padding := *LWSP-char
+ ; Composers MUST NOT generate
+ ; non-zero length transport
+ ; padding, but receivers MUST
+ ; be able to handle padding
+ ; added by message transports.
+
+ encapsulation := delimiter transport-padding
+ CRLF body-part
+
+ delimiter := CRLF dash-boundary
+
+ close-delimiter := delimiter "--"
+
+ preamble := discard-text
+
+ epilogue := discard-text
+
+ discard-text := *(*text CRLF) *text
+ ; May be ignored or discarded.
+
+ body-part := MIME-part-headers [CRLF *OCTET]
+ ; Lines in a body-part must not start
+ ; with the specified dash-boundary and
+ ; the delimiter must not appear anywhere
+ ; in the body part. Note that the
+ ; semantics of a body-part differ from
+ ; the semantics of a message, as
+ ; described in the text.
+
+ OCTET := <any 0-255 octet value>
+
+ IMPORTANT: The free insertion of linear-white-space and RFC 822
+ comments between the elements shown in this BNF is NOT allowed since
+ this BNF does not specify a structured header field.
+
+ NOTE: In certain transport enclaves, RFC 822 restrictions such as
+ the one that limits bodies to printable US-ASCII characters may not
+ be in force. (That is, the transport domains may exist that resemble
+ standard Internet mail transport as specified in RFC 821 and assumed
+ by RFC 822, but without certain restrictions.) The relaxation of
+ these restrictions should be construed as locally extending the
+ definition of bodies, for example to include octets outside of the
+ US-ASCII range, as long as these extensions are supported by the
+ transport and adequately documented in the Content- Transfer-Encoding
+ header field. However, in no event are headers (either message
+ headers or body part headers) allowed to contain anything other than
+ US-ASCII characters.
+
+
+
+Freed & Borenstein Standards Track [Page 23]
+
+RFC 2046 Media Types November 1996
+
+
+ NOTE: Conspicuously missing from the "multipart" type is a notion of
+ structured, related body parts. It is recommended that those wishing
+ to provide more structured or integrated multipart messaging
+ facilities should define subtypes of multipart that are syntactically
+ identical but define relationships between the various parts. For
+ example, subtypes of multipart could be defined that include a
+ distinguished part which in turn is used to specify the relationships
+ between the other parts, probably referring to them by their
+ Content-ID field. Old implementations will not recognize the new
+ subtype if this approach is used, but will treat it as
+ multipart/mixed and will thus be able to show the user the parts that
+ are recognized.
+
+5.1.2. Handling Nested Messages and Multiparts
+
+ The "message/rfc822" subtype defined in a subsequent section of this
+ document has no terminating condition other than running out of data.
+ Similarly, an improperly truncated "multipart" entity may not have
+ any terminating boundary marker, and can turn up operationally due to
+ mail system malfunctions.
+
+ It is essential that such entities be handled correctly when they are
+ themselves imbedded inside of another "multipart" structure. MIME
+ implementations are therefore required to recognize outer level
+ boundary markers at ANY level of inner nesting. It is not sufficient
+ to only check for the next expected marker or other terminating
+ condition.
+
+5.1.3. Mixed Subtype
+
+ The "mixed" subtype of "multipart" is intended for use when the body
+ parts are independent and need to be bundled in a particular order.
+ Any "multipart" subtypes that an implementation does not recognize
+ must be treated as being of subtype "mixed".
+
+5.1.4. Alternative Subtype
+
+ The "multipart/alternative" type is syntactically identical to
+ "multipart/mixed", but the semantics are different. In particular,
+ each of the body parts is an "alternative" version of the same
+ information.
+
+ Systems should recognize that the content of the various parts are
+ interchangeable. Systems should choose the "best" type based on the
+ local environment and references, in some cases even through user
+ interaction. As with "multipart/mixed", the order of body parts is
+ significant. In this case, the alternatives appear in an order of
+ increasing faithfulness to the original content. In general, the
+
+
+
+Freed & Borenstein Standards Track [Page 24]
+
+RFC 2046 Media Types November 1996
+
+
+ best choice is the LAST part of a type supported by the recipient
+ system's local environment.
+
+ "Multipart/alternative" may be used, for example, to send a message
+ in a fancy text format in such a way that it can easily be displayed
+ anywhere:
+
+ From: Nathaniel Borenstein <nsb@bellcore.com>
+ To: Ned Freed <ned@innosoft.com>
+ Date: Mon, 22 Mar 1993 09:41:09 -0800 (PST)
+ Subject: Formatted text mail
+ MIME-Version: 1.0
+ Content-Type: multipart/alternative; boundary=boundary42
+
+ --boundary42
+ Content-Type: text/plain; charset=us-ascii
+
+ ... plain text version of message goes here ...
+
+ --boundary42
+ Content-Type: text/enriched
+
+ ... RFC 1896 text/enriched version of same message
+ goes here ...
+
+ --boundary42
+ Content-Type: application/x-whatever
+
+ ... fanciest version of same message goes here ...
+
+ --boundary42--
+
+ In this example, users whose mail systems understood the
+ "application/x-whatever" format would see only the fancy version,
+ while other users would see only the enriched or plain text version,
+ depending on the capabilities of their system.
+
+ In general, user agents that compose "multipart/alternative" entities
+ must place the body parts in increasing order of preference, that is,
+ with the preferred format last. For fancy text, the sending user
+ agent should put the plainest format first and the richest format
+ last. Receiving user agents should pick and display the last format
+ they are capable of displaying. In the case where one of the
+ alternatives is itself of type "multipart" and contains unrecognized
+ sub-parts, the user agent may choose either to show that alternative,
+ an earlier alternative, or both.
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 25]
+
+RFC 2046 Media Types November 1996
+
+
+ NOTE: From an implementor's perspective, it might seem more sensible
+ to reverse this ordering, and have the plainest alternative last.
+ However, placing the plainest alternative first is the friendliest
+ possible option when "multipart/alternative" entities are viewed
+ using a non-MIME-conformant viewer. While this approach does impose
+ some burden on conformant MIME viewers, interoperability with older
+ mail readers was deemed to be more important in this case.
+
+ It may be the case that some user agents, if they can recognize more
+ than one of the formats, will prefer to offer the user the choice of
+ which format to view. This makes sense, for example, if a message
+ includes both a nicely- formatted image version and an easily-edited
+ text version. What is most critical, however, is that the user not
+ automatically be shown multiple versions of the same data. Either
+ the user should be shown the last recognized version or should be
+ given the choice.
+
+ THE SEMANTICS OF CONTENT-ID IN MULTIPART/ALTERNATIVE: Each part of a
+ "multipart/alternative" entity represents the same data, but the
+ mappings between the two are not necessarily without information
+ loss. For example, information is lost when translating ODA to
+ PostScript or plain text. It is recommended that each part should
+ have a different Content-ID value in the case where the information
+ content of the two parts is not identical. And when the information
+ content is identical -- for example, where several parts of type
+ "message/external-body" specify alternate ways to access the
+ identical data -- the same Content-ID field value should be used, to
+ optimize any caching mechanisms that might be present on the
+ recipient's end. However, the Content-ID values used by the parts
+ should NOT be the same Content-ID value that describes the
+ "multipart/alternative" as a whole, if there is any such Content-ID
+ field. That is, one Content-ID value will refer to the
+ "multipart/alternative" entity, while one or more other Content-ID
+ values will refer to the parts inside it.
+
+5.1.5. Digest Subtype
+
+ This document defines a "digest" subtype of the "multipart" Content-
+ Type. This type is syntactically identical to "multipart/mixed", but
+ the semantics are different. In particular, in a digest, the default
+ Content-Type value for a body part is changed from "text/plain" to
+ "message/rfc822". This is done to allow a more readable digest
+ format that is largely compatible (except for the quoting convention)
+ with RFC 934.
+
+ Note: Though it is possible to specify a Content-Type value for a
+ body part in a digest which is other than "message/rfc822", such as a
+ "text/plain" part containing a description of the material in the
+
+
+
+Freed & Borenstein Standards Track [Page 26]
+
+RFC 2046 Media Types November 1996
+
+
+ digest, actually doing so is undesireble. The "multipart/digest"
+ Content-Type is intended to be used to send collections of messages.
+ If a "text/plain" part is needed, it should be included as a seperate
+ part of a "multipart/mixed" message.
+
+ A digest in this format might, then, look something like this:
+
+ From: Moderator-Address
+ To: Recipient-List
+ Date: Mon, 22 Mar 1994 13:34:51 +0000
+ Subject: Internet Digest, volume 42
+ MIME-Version: 1.0
+ Content-Type: multipart/mixed;
+ boundary="---- main boundary ----"
+
+ ------ main boundary ----
+
+ ...Introductory text or table of contents...
+
+ ------ main boundary ----
+ Content-Type: multipart/digest;
+ boundary="---- next message ----"
+
+ ------ next message ----
+
+ From: someone-else
+ Date: Fri, 26 Mar 1993 11:13:32 +0200
+ Subject: my opinion
+
+ ...body goes here ...
+
+ ------ next message ----
+
+ From: someone-else-again
+ Date: Fri, 26 Mar 1993 10:07:13 -0500
+ Subject: my different opinion
+
+ ... another body goes here ...
+
+ ------ next message ------
+
+ ------ main boundary ------
+
+5.1.6. Parallel Subtype
+
+ This document defines a "parallel" subtype of the "multipart"
+ Content-Type. This type is syntactically identical to
+ "multipart/mixed", but the semantics are different. In particular,
+
+
+
+Freed & Borenstein Standards Track [Page 27]
+
+RFC 2046 Media Types November 1996
+
+
+ in a parallel entity, the order of body parts is not significant.
+
+ A common presentation of this type is to display all of the parts
+ simultaneously on hardware and software that are capable of doing so.
+ However, composing agents should be aware that many mail readers will
+ lack this capability and will show the parts serially in any event.
+
+5.1.7. Other Multipart Subtypes
+
+ Other "multipart" subtypes are expected in the future. MIME
+ implementations must in general treat unrecognized subtypes of
+ "multipart" as being equivalent to "multipart/mixed".
+
+5.2. Message Media Type
+
+ It is frequently desirable, in sending mail, to encapsulate another
+ mail message. A special media type, "message", is defined to
+ facilitate this. In particular, the "rfc822" subtype of "message" is
+ used to encapsulate RFC 822 messages.
+
+ NOTE: It has been suggested that subtypes of "message" might be
+ defined for forwarded or rejected messages. However, forwarded and
+ rejected messages can be handled as multipart messages in which the
+ first part contains any control or descriptive information, and a
+ second part, of type "message/rfc822", is the forwarded or rejected
+ message. Composing rejection and forwarding messages in this manner
+ will preserve the type information on the original message and allow
+ it to be correctly presented to the recipient, and hence is strongly
+ encouraged.
+
+ Subtypes of "message" often impose restrictions on what encodings are
+ allowed. These restrictions are described in conjunction with each
+ specific subtype.
+
+ Mail gateways, relays, and other mail handling agents are commonly
+ known to alter the top-level header of an RFC 822 message. In
+ particular, they frequently add, remove, or reorder header fields.
+ These operations are explicitly forbidden for the encapsulated
+ headers embedded in the bodies of messages of type "message."
+
+5.2.1. RFC822 Subtype
+
+ A media type of "message/rfc822" indicates that the body contains an
+ encapsulated message, with the syntax of an RFC 822 message.
+ However, unlike top-level RFC 822 messages, the restriction that each
+ "message/rfc822" body must include a "From", "Date", and at least one
+ destination header is removed and replaced with the requirement that
+ at least one of "From", "Subject", or "Date" must be present.
+
+
+
+Freed & Borenstein Standards Track [Page 28]
+
+RFC 2046 Media Types November 1996
+
+
+ It should be noted that, despite the use of the numbers "822", a
+ "message/rfc822" entity isn't restricted to material in strict
+ conformance to RFC822, nor are the semantics of "message/rfc822"
+ objects restricted to the semantics defined in RFC822. More
+ specifically, a "message/rfc822" message could well be a News article
+ or a MIME message.
+
+ No encoding other than "7bit", "8bit", or "binary" is permitted for
+ the body of a "message/rfc822" entity. The message header fields are
+ always US-ASCII in any case, and data within the body can still be
+ encoded, in which case the Content-Transfer-Encoding header field in
+ the encapsulated message will reflect this. Non-US-ASCII text in the
+ headers of an encapsulated message can be specified using the
+ mechanisms described in RFC 2047.
+
+5.2.2. Partial Subtype
+
+ The "partial" subtype is defined to allow large entities to be
+ delivered as several separate pieces of mail and automatically
+ reassembled by a receiving user agent. (The concept is similar to IP
+ fragmentation and reassembly in the basic Internet Protocols.) This
+ mechanism can be used when intermediate transport agents limit the
+ size of individual messages that can be sent. The media type
+ "message/partial" thus indicates that the body contains a fragment of
+ a larger entity.
+
+ Because data of type "message" may never be encoded in base64 or
+ quoted-printable, a problem might arise if "message/partial" entities
+ are constructed in an environment that supports binary or 8bit
+ transport. The problem is that the binary data would be split into
+ multiple "message/partial" messages, each of them requiring binary
+ transport. If such messages were encountered at a gateway into a
+ 7bit transport environment, there would be no way to properly encode
+ them for the 7bit world, aside from waiting for all of the fragments,
+ reassembling the inner message, and then encoding the reassembled
+ data in base64 or quoted-printable. Since it is possible that
+ different fragments might go through different gateways, even this is
+ not an acceptable solution. For this reason, it is specified that
+ entities of type "message/partial" must always have a content-
+ transfer-encoding of 7bit (the default). In particular, even in
+ environments that support binary or 8bit transport, the use of a
+ content- transfer-encoding of "8bit" or "binary" is explicitly
+ prohibited for MIME entities of type "message/partial". This in turn
+ implies that the inner message must not use "8bit" or "binary"
+ encoding.
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 29]
+
+RFC 2046 Media Types November 1996
+
+
+ Because some message transfer agents may choose to automatically
+ fragment large messages, and because such agents may use very
+ different fragmentation thresholds, it is possible that the pieces of
+ a partial message, upon reassembly, may prove themselves to comprise
+ a partial message. This is explicitly permitted.
+
+ Three parameters must be specified in the Content-Type field of type
+ "message/partial": The first, "id", is a unique identifier, as close
+ to a world-unique identifier as possible, to be used to match the
+ fragments together. (In general, the identifier is essentially a
+ message-id; if placed in double quotes, it can be ANY message-id, in
+ accordance with the BNF for "parameter" given in RFC 2045.) The
+ second, "number", an integer, is the fragment number, which indicates
+ where this fragment fits into the sequence of fragments. The third,
+ "total", another integer, is the total number of fragments. This
+ third subfield is required on the final fragment, and is optional
+ (though encouraged) on the earlier fragments. Note also that these
+ parameters may be given in any order.
+
+ Thus, the second piece of a 3-piece message may have either of the
+ following header fields:
+
+ Content-Type: Message/Partial; number=2; total=3;
+ id="oc=jpbe0M2Yt4s@thumper.bellcore.com"
+
+ Content-Type: Message/Partial;
+ id="oc=jpbe0M2Yt4s@thumper.bellcore.com";
+ number=2
+
+ But the third piece MUST specify the total number of fragments:
+
+ Content-Type: Message/Partial; number=3; total=3;
+ id="oc=jpbe0M2Yt4s@thumper.bellcore.com"
+
+ Note that fragment numbering begins with 1, not 0.
+
+ When the fragments of an entity broken up in this manner are put
+ together, the result is always a complete MIME entity, which may have
+ its own Content-Type header field, and thus may contain any other
+ data type.
+
+5.2.2.1. Message Fragmentation and Reassembly
+
+ The semantics of a reassembled partial message must be those of the
+ "inner" message, rather than of a message containing the inner
+ message. This makes it possible, for example, to send a large audio
+ message as several partial messages, and still have it appear to the
+ recipient as a simple audio message rather than as an encapsulated
+
+
+
+Freed & Borenstein Standards Track [Page 30]
+
+RFC 2046 Media Types November 1996
+
+
+ message containing an audio message. That is, the encapsulation of
+ the message is considered to be "transparent".
+
+ When generating and reassembling the pieces of a "message/partial"
+ message, the headers of the encapsulated message must be merged with
+ the headers of the enclosing entities. In this process the following
+ rules must be observed:
+
+ (1) Fragmentation agents must split messages at line
+ boundaries only. This restriction is imposed because
+ splits at points other than the ends of lines in turn
+ depends on message transports being able to preserve
+ the semantics of messages that don't end with a CRLF
+ sequence. Many transports are incapable of preserving
+ such semantics.
+
+ (2) All of the header fields from the initial enclosing
+ message, except those that start with "Content-" and
+ the specific header fields "Subject", "Message-ID",
+ "Encrypted", and "MIME-Version", must be copied, in
+ order, to the new message.
+
+ (3) The header fields in the enclosed message which start
+ with "Content-", plus the "Subject", "Message-ID",
+ "Encrypted", and "MIME-Version" fields, must be
+ appended, in order, to the header fields of the new
+ message. Any header fields in the enclosed message
+ which do not start with "Content-" (except for the
+ "Subject", "Message-ID", "Encrypted", and "MIME-
+ Version" fields) will be ignored and dropped.
+
+ (4) All of the header fields from the second and any
+ subsequent enclosing messages are discarded by the
+ reassembly process.
+
+5.2.2.2. Fragmentation and Reassembly Example
+
+ If an audio message is broken into two pieces, the first piece might
+ look something like this:
+
+ X-Weird-Header-1: Foo
+ From: Bill@host.com
+ To: joe@otherhost.com
+ Date: Fri, 26 Mar 1993 12:59:38 -0500 (EST)
+ Subject: Audio mail (part 1 of 2)
+ Message-ID: <id1@host.com>
+ MIME-Version: 1.0
+ Content-type: message/partial; id="ABC@host.com";
+
+
+
+Freed & Borenstein Standards Track [Page 31]
+
+RFC 2046 Media Types November 1996
+
+
+ number=1; total=2
+
+ X-Weird-Header-1: Bar
+ X-Weird-Header-2: Hello
+ Message-ID: <anotherid@foo.com>
+ Subject: Audio mail
+ MIME-Version: 1.0
+ Content-type: audio/basic
+ Content-transfer-encoding: base64
+
+ ... first half of encoded audio data goes here ...
+
+ and the second half might look something like this:
+
+ From: Bill@host.com
+ To: joe@otherhost.com
+ Date: Fri, 26 Mar 1993 12:59:38 -0500 (EST)
+ Subject: Audio mail (part 2 of 2)
+ MIME-Version: 1.0
+ Message-ID: <id2@host.com>
+ Content-type: message/partial;
+ id="ABC@host.com"; number=2; total=2
+
+ ... second half of encoded audio data goes here ...
+
+ Then, when the fragmented message is reassembled, the resulting
+ message to be displayed to the user should look something like this:
+
+ X-Weird-Header-1: Foo
+ From: Bill@host.com
+ To: joe@otherhost.com
+ Date: Fri, 26 Mar 1993 12:59:38 -0500 (EST)
+ Subject: Audio mail
+ Message-ID: <anotherid@foo.com>
+ MIME-Version: 1.0
+ Content-type: audio/basic
+ Content-transfer-encoding: base64
+
+ ... first half of encoded audio data goes here ...
+ ... second half of encoded audio data goes here ...
+
+ The inclusion of a "References" field in the headers of the second
+ and subsequent pieces of a fragmented message that references the
+ Message-Id on the previous piece may be of benefit to mail readers
+ that understand and track references. However, the generation of
+ such "References" fields is entirely optional.
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 32]
+
+RFC 2046 Media Types November 1996
+
+
+ Finally, it should be noted that the "Encrypted" header field has
+ been made obsolete by Privacy Enhanced Messaging (PEM) [RFC-1421,
+ RFC-1422, RFC-1423, RFC-1424], but the rules above are nevertheless
+ believed to describe the correct way to treat it if it is encountered
+ in the context of conversion to and from "message/partial" fragments.
+
+5.2.3. External-Body Subtype
+
+ The external-body subtype indicates that the actual body data are not
+ included, but merely referenced. In this case, the parameters
+ describe a mechanism for accessing the external data.
+
+ When a MIME entity is of type "message/external-body", it consists of
+ a header, two consecutive CRLFs, and the message header for the
+ encapsulated message. If another pair of consecutive CRLFs appears,
+ this of course ends the message header for the encapsulated message.
+ However, since the encapsulated message's body is itself external, it
+ does NOT appear in the area that follows. For example, consider the
+ following message:
+
+ Content-type: message/external-body;
+ access-type=local-file;
+ name="/u/nsb/Me.jpeg"
+
+ Content-type: image/jpeg
+ Content-ID: <id42@guppylake.bellcore.com>
+ Content-Transfer-Encoding: binary
+
+ THIS IS NOT REALLY THE BODY!
+
+ The area at the end, which might be called the "phantom body", is
+ ignored for most external-body messages. However, it may be used to
+ contain auxiliary information for some such messages, as indeed it is
+ when the access-type is "mail- server". The only access-type defined
+ in this document that uses the phantom body is "mail-server", but
+ other access-types may be defined in the future in other
+ specifications that use this area.
+
+ The encapsulated headers in ALL "message/external-body" entities MUST
+ include a Content-ID header field to give a unique identifier by
+ which to reference the data. This identifier may be used for caching
+ mechanisms, and for recognizing the receipt of the data when the
+ access-type is "mail-server".
+
+ Note that, as specified here, the tokens that describe external-body
+ data, such as file names and mail server commands, are required to be
+ in the US-ASCII character set.
+
+
+
+
+Freed & Borenstein Standards Track [Page 33]
+
+RFC 2046 Media Types November 1996
+
+
+ If this proves problematic in practice, a new mechanism may be
+ required as a future extension to MIME, either as newly defined
+ access-types for "message/external-body" or by some other mechanism.
+
+ As with "message/partial", MIME entities of type "message/external-
+ body" MUST have a content-transfer-encoding of 7bit (the default).
+ In particular, even in environments that support binary or 8bit
+ transport, the use of a content- transfer-encoding of "8bit" or
+ "binary" is explicitly prohibited for entities of type
+ "message/external-body".
+
+5.2.3.1. General External-Body Parameters
+
+ The parameters that may be used with any "message/external- body"
+ are:
+
+ (1) ACCESS-TYPE -- A word indicating the supported access
+ mechanism by which the file or data may be obtained.
+ This word is not case sensitive. Values include, but
+ are not limited to, "FTP", "ANON-FTP", "TFTP", "LOCAL-
+ FILE", and "MAIL-SERVER". Future values, except for
+ experimental values beginning with "X-", must be
+ registered with IANA, as described in RFC 2048.
+ This parameter is unconditionally mandatory and MUST be
+ present on EVERY "message/external-body".
+
+ (2) EXPIRATION -- The date (in the RFC 822 "date-time"
+ syntax, as extended by RFC 1123 to permit 4 digits in
+ the year field) after which the existence of the
+ external data is not guaranteed. This parameter may be
+ used with ANY access-type and is ALWAYS optional.
+
+ (3) SIZE -- The size (in octets) of the data. The intent
+ of this parameter is to help the recipient decide
+ whether or not to expend the necessary resources to
+ retrieve the external data. Note that this describes
+ the size of the data in its canonical form, that is,
+ before any Content-Transfer-Encoding has been applied
+ or after the data have been decoded. This parameter
+ may be used with ANY access-type and is ALWAYS
+ optional.
+
+ (4) PERMISSION -- A case-insensitive field that indicates
+ whether or not it is expected that clients might also
+ attempt to overwrite the data. By default, or if
+ permission is "read", the assumption is that they are
+ not, and that if the data is retrieved once, it is
+ never needed again. If PERMISSION is "read-write",
+
+
+
+Freed & Borenstein Standards Track [Page 34]
+
+RFC 2046 Media Types November 1996
+
+
+ this assumption is invalid, and any local copy must be
+ considered no more than a cache. "Read" and "Read-
+ write" are the only defined values of permission. This
+ parameter may be used with ANY access-type and is
+ ALWAYS optional.
+
+ The precise semantics of the access-types defined here are described
+ in the sections that follow.
+
+5.2.3.2. The 'ftp' and 'tftp' Access-Types
+
+ An access-type of FTP or TFTP indicates that the message body is
+ accessible as a file using the FTP [RFC-959] or TFTP [RFC- 783]
+ protocols, respectively. For these access-types, the following
+ additional parameters are mandatory:
+
+ (1) NAME -- The name of the file that contains the actual
+ body data.
+
+ (2) SITE -- A machine from which the file may be obtained,
+ using the given protocol. This must be a fully
+ qualified domain name, not a nickname.
+
+ (3) Before any data are retrieved, using FTP, the user will
+ generally need to be asked to provide a login id and a
+ password for the machine named by the site parameter.
+ For security reasons, such an id and password are not
+ specified as content-type parameters, but must be
+ obtained from the user.
+
+ In addition, the following parameters are optional:
+
+ (1) DIRECTORY -- A directory from which the data named by
+ NAME should be retrieved.
+
+ (2) MODE -- A case-insensitive string indicating the mode
+ to be used when retrieving the information. The valid
+ values for access-type "TFTP" are "NETASCII", "OCTET",
+ and "MAIL", as specified by the TFTP protocol [RFC-
+ 783]. The valid values for access-type "FTP" are
+ "ASCII", "EBCDIC", "IMAGE", and "LOCALn" where "n" is a
+ decimal integer, typically 8. These correspond to the
+ representation types "A" "E" "I" and "L n" as specified
+ by the FTP protocol [RFC-959]. Note that "BINARY" and
+ "TENEX" are not valid values for MODE and that "OCTET"
+ or "IMAGE" or "LOCAL8" should be used instead. IF MODE
+ is not specified, the default value is "NETASCII" for
+ TFTP and "ASCII" otherwise.
+
+
+
+Freed & Borenstein Standards Track [Page 35]
+
+RFC 2046 Media Types November 1996
+
+
+5.2.3.3. The 'anon-ftp' Access-Type
+
+ The "anon-ftp" access-type is identical to the "ftp" access type,
+ except that the user need not be asked to provide a name and password
+ for the specified site. Instead, the ftp protocol will be used with
+ login "anonymous" and a password that corresponds to the user's mail
+ address.
+
+5.2.3.4. The 'local-file' Access-Type
+
+ An access-type of "local-file" indicates that the actual body is
+ accessible as a file on the local machine. Two additional parameters
+ are defined for this access type:
+
+ (1) NAME -- The name of the file that contains the actual
+ body data. This parameter is mandatory for the
+ "local-file" access-type.
+
+ (2) SITE -- A domain specifier for a machine or set of
+ machines that are known to have access to the data
+ file. This optional parameter is used to describe the
+ locality of reference for the data, that is, the site
+ or sites at which the file is expected to be visible.
+ Asterisks may be used for wildcard matching to a part
+ of a domain name, such as "*.bellcore.com", to indicate
+ a set of machines on which the data should be directly
+ visible, while a single asterisk may be used to
+ indicate a file that is expected to be universally
+ available, e.g., via a global file system.
+
+5.2.3.5. The 'mail-server' Access-Type
+
+ The "mail-server" access-type indicates that the actual body is
+ available from a mail server. Two additional parameters are defined
+ for this access-type:
+
+ (1) SERVER -- The addr-spec of the mail server from which
+ the actual body data can be obtained. This parameter
+ is mandatory for the "mail-server" access-type.
+
+ (2) SUBJECT -- The subject that is to be used in the mail
+ that is sent to obtain the data. Note that keying mail
+ servers on Subject lines is NOT recommended, but such
+ mail servers are known to exist. This is an optional
+ parameter.
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 36]
+
+RFC 2046 Media Types November 1996
+
+
+ Because mail servers accept a variety of syntaxes, some of which is
+ multiline, the full command to be sent to a mail server is not
+ included as a parameter in the content-type header field. Instead,
+ it is provided as the "phantom body" when the media type is
+ "message/external-body" and the access-type is mail-server.
+
+ Note that MIME does not define a mail server syntax. Rather, it
+ allows the inclusion of arbitrary mail server commands in the phantom
+ body. Implementations must include the phantom body in the body of
+ the message it sends to the mail server address to retrieve the
+ relevant data.
+
+ Unlike other access-types, mail-server access is asynchronous and
+ will happen at an unpredictable time in the future. For this reason,
+ it is important that there be a mechanism by which the returned data
+ can be matched up with the original "message/external-body" entity.
+ MIME mail servers must use the same Content-ID field on the returned
+ message that was used in the original "message/external-body"
+ entities, to facilitate such matching.
+
+5.2.3.6. External-Body Security Issues
+
+ "Message/external-body" entities give rise to two important security
+ issues:
+
+ (1) Accessing data via a "message/external-body" reference
+ effectively results in the message recipient performing
+ an operation that was specified by the message
+ originator. It is therefore possible for the message
+ originator to trick a recipient into doing something
+ they would not have done otherwise. For example, an
+ originator could specify a action that attempts
+ retrieval of material that the recipient is not
+ authorized to obtain, causing the recipient to
+ unwittingly violate some security policy. For this
+ reason, user agents capable of resolving external
+ references must always take steps to describe the
+ action they are to take to the recipient and ask for
+ explicit permisssion prior to performing it.
+
+ The 'mail-server' access-type is particularly
+ vulnerable, in that it causes the recipient to send a
+ new message whose contents are specified by the
+ original message's originator. Given the potential for
+ abuse, any such request messages that are constructed
+ should contain a clear indication that they were
+ generated automatically (e.g. in a Comments: header
+ field) in an attempt to resolve a MIME
+
+
+
+Freed & Borenstein Standards Track [Page 37]
+
+RFC 2046 Media Types November 1996
+
+
+ "message/external-body" reference.
+
+ (2) MIME will sometimes be used in environments that
+ provide some guarantee of message integrity and
+ authenticity. If present, such guarantees may apply
+ only to the actual direct content of messages -- they
+ may or may not apply to data accessed through MIME's
+ "message/external-body" mechanism. In particular, it
+ may be possible to subvert certain access mechanisms
+ even when the messaging system itself is secure.
+
+ It should be noted that this problem exists either with
+ or without the availabilty of MIME mechanisms. A
+ casual reference to an FTP site containing a document
+ in the text of a secure message brings up similar
+ issues -- the only difference is that MIME provides for
+ automatic retrieval of such material, and users may
+ place unwarranted trust is such automatic retrieval
+ mechanisms.
+
+5.2.3.7. Examples and Further Explanations
+
+ When the external-body mechanism is used in conjunction with the
+ "multipart/alternative" media type it extends the functionality of
+ "multipart/alternative" to include the case where the same entity is
+ provided in the same format but via different accces mechanisms.
+ When this is done the originator of the message must order the parts
+ first in terms of preferred formats and then by preferred access
+ mechanisms. The recipient's viewer should then evaluate the list
+ both in terms of format and access mechanisms.
+
+ With the emerging possibility of very wide-area file systems, it
+ becomes very hard to know in advance the set of machines where a file
+ will and will not be accessible directly from the file system.
+ Therefore it may make sense to provide both a file name, to be tried
+ directly, and the name of one or more sites from which the file is
+ known to be accessible. An implementation can try to retrieve remote
+ files using FTP or any other protocol, using anonymous file retrieval
+ or prompting the user for the necessary name and password. If an
+ external body is accessible via multiple mechanisms, the sender may
+ include multiple entities of type "message/external-body" within the
+ body parts of an enclosing "multipart/alternative" entity.
+
+ However, the external-body mechanism is not intended to be limited to
+ file retrieval, as shown by the mail-server access-type. Beyond
+ this, one can imagine, for example, using a video server for external
+ references to video clips.
+
+
+
+
+Freed & Borenstein Standards Track [Page 38]
+
+RFC 2046 Media Types November 1996
+
+
+ The embedded message header fields which appear in the body of the
+ "message/external-body" data must be used to declare the media type
+ of the external body if it is anything other than plain US-ASCII
+ text, since the external body does not have a header section to
+ declare its type. Similarly, any Content-transfer-encoding other
+ than "7bit" must also be declared here. Thus a complete
+ "message/external-body" message, referring to an object in PostScript
+ format, might look like this:
+
+ From: Whomever
+ To: Someone
+ Date: Whenever
+ Subject: whatever
+ MIME-Version: 1.0
+ Message-ID: <id1@host.com>
+ Content-Type: multipart/alternative; boundary=42
+ Content-ID: <id001@guppylake.bellcore.com>
+
+ --42
+ Content-Type: message/external-body; name="BodyFormats.ps";
+ site="thumper.bellcore.com"; mode="image";
+ access-type=ANON-FTP; directory="pub";
+ expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)"
+
+ Content-type: application/postscript
+ Content-ID: <id42@guppylake.bellcore.com>
+
+ --42
+ Content-Type: message/external-body; access-type=local-file;
+ name="/u/nsb/writing/rfcs/RFC-MIME.ps";
+ site="thumper.bellcore.com";
+ expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)"
+
+ Content-type: application/postscript
+ Content-ID: <id42@guppylake.bellcore.com>
+
+ --42
+ Content-Type: message/external-body;
+ access-type=mail-server
+ server="listserv@bogus.bitnet";
+ expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)"
+
+ Content-type: application/postscript
+ Content-ID: <id42@guppylake.bellcore.com>
+
+ get RFC-MIME.DOC
+
+ --42--
+
+
+
+Freed & Borenstein Standards Track [Page 39]
+
+RFC 2046 Media Types November 1996
+
+
+ Note that in the above examples, the default Content-transfer-
+ encoding of "7bit" is assumed for the external postscript data.
+
+ Like the "message/partial" type, the "message/external-body" media
+ type is intended to be transparent, that is, to convey the data type
+ in the external body rather than to convey a message with a body of
+ that type. Thus the headers on the outer and inner parts must be
+ merged using the same rules as for "message/partial". In particular,
+ this means that the Content-type and Subject fields are overridden,
+ but the From field is preserved.
+
+ Note that since the external bodies are not transported along with
+ the external body reference, they need not conform to transport
+ limitations that apply to the reference itself. In particular,
+ Internet mail transports may impose 7bit and line length limits, but
+ these do not automatically apply to binary external body references.
+ Thus a Content-Transfer-Encoding is not generally necessary, though
+ it is permitted.
+
+ Note that the body of a message of type "message/external-body" is
+ governed by the basic syntax for an RFC 822 message. In particular,
+ anything before the first consecutive pair of CRLFs is header
+ information, while anything after it is body information, which is
+ ignored for most access-types.
+
+5.2.4. Other Message Subtypes
+
+ MIME implementations must in general treat unrecognized subtypes of
+ "message" as being equivalent to "application/octet-stream".
+
+ Future subtypes of "message" intended for use with email should be
+ restricted to "7bit" encoding. A type other than "message" should be
+ used if restriction to "7bit" is not possible.
+
+6. Experimental Media Type Values
+
+ A media type value beginning with the characters "X-" is a private
+ value, to be used by consenting systems by mutual agreement. Any
+ format without a rigorous and public definition must be named with an
+ "X-" prefix, and publicly specified values shall never begin with
+ "X-". (Older versions of the widely used Andrew system use the "X-
+ BE2" name, so new systems should probably choose a different name.)
+
+ In general, the use of "X-" top-level types is strongly discouraged.
+ Implementors should invent subtypes of the existing types whenever
+ possible. In many cases, a subtype of "application" will be more
+ appropriate than a new top-level type.
+
+
+
+
+Freed & Borenstein Standards Track [Page 40]
+
+RFC 2046 Media Types November 1996
+
+
+7. Summary
+
+ The five discrete media types provide provide a standardized
+ mechanism for tagging entities as "audio", "image", or several other
+ kinds of data. The composite "multipart" and "message" media types
+ allow mixing and hierarchical structuring of entities of different
+ types in a single message. A distinguished parameter syntax allows
+ further specification of data format details, particularly the
+ specification of alternate character sets. Additional optional
+ header fields provide mechanisms for certain extensions deemed
+ desirable by many implementors. Finally, a number of useful media
+ types are defined for general use by consenting user agents, notably
+ "message/partial" and "message/external-body".
+
+9. Security Considerations
+
+ Security issues are discussed in the context of the
+ "application/postscript" type, the "message/external-body" type, and
+ in RFC 2048. Implementors should pay special attention to the
+ security implications of any media types that can cause the remote
+ execution of any actions in the recipient's environment. In such
+ cases, the discussion of the "application/postscript" type may serve
+ as a model for considering other media types with remote execution
+ capabilities.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 41]
+
+RFC 2046 Media Types November 1996
+
+
+9. Authors' Addresses
+
+ For more information, the authors of this document are best contacted
+ via Internet mail:
+
+ Ned Freed
+ Innosoft International, Inc.
+ 1050 East Garvey Avenue South
+ West Covina, CA 91790
+ USA
+
+ Phone: +1 818 919 3600
+ Fax: +1 818 919 3614
+ EMail: ned@innosoft.com
+
+
+ Nathaniel S. Borenstein
+ First Virtual Holdings
+ 25 Washington Avenue
+ Morristown, NJ 07960
+ USA
+
+ Phone: +1 201 540 8967
+ Fax: +1 201 993 3032
+ EMail: nsb@nsb.fv.com
+
+
+ MIME is a result of the work of the Internet Engineering Task Force
+ Working Group on RFC 822 Extensions. The chairman of that group,
+ Greg Vaudreuil, may be reached at:
+
+ Gregory M. Vaudreuil
+ Octel Network Services
+ 17080 Dallas Parkway
+ Dallas, TX 75248-1905
+ USA
+
+ EMail: Greg.Vaudreuil@Octel.Com
+
+
+
+
+
+
+
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 42]
+
+RFC 2046 Media Types November 1996
+
+
+Appendix A -- Collected Grammar
+
+ This appendix contains the complete BNF grammar for all the syntax
+ specified by this document.
+
+ By itself, however, this grammar is incomplete. It refers by name to
+ several syntax rules that are defined by RFC 822. Rather than
+ reproduce those definitions here, and risk unintentional differences
+ between the two, this document simply refers the reader to RFC 822
+ for the remaining definitions. Wherever a term is undefined, it
+ refers to the RFC 822 definition.
+
+ boundary := 0*69<bchars> bcharsnospace
+
+ bchars := bcharsnospace / " "
+
+ bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
+ "+" / "_" / "," / "-" / "." /
+ "/" / ":" / "=" / "?"
+
+ body-part := <"message" as defined in RFC 822, with all
+ header fields optional, not starting with the
+ specified dash-boundary, and with the
+ delimiter not occurring anywhere in the
+ body part. Note that the semantics of a
+ part differ from the semantics of a message,
+ as described in the text.>
+
+ close-delimiter := delimiter "--"
+
+ dash-boundary := "--" boundary
+ ; boundary taken from the value of
+ ; boundary parameter of the
+ ; Content-Type field.
+
+ delimiter := CRLF dash-boundary
+
+ discard-text := *(*text CRLF)
+ ; May be ignored or discarded.
+
+ encapsulation := delimiter transport-padding
+ CRLF body-part
+
+ epilogue := discard-text
+
+ multipart-body := [preamble CRLF]
+ dash-boundary transport-padding CRLF
+ body-part *encapsulation
+
+
+
+Freed & Borenstein Standards Track [Page 43]
+
+RFC 2046 Media Types November 1996
+
+
+ close-delimiter transport-padding
+ [CRLF epilogue]
+
+ preamble := discard-text
+
+ transport-padding := *LWSP-char
+ ; Composers MUST NOT generate
+ ; non-zero length transport
+ ; padding, but receivers MUST
+ ; be able to handle padding
+ ; added by message transports.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 44]
+
diff --git a/standards/rfc2222.txt b/standards/rfc2222.txt
new file mode 100644
index 000000000..2b0a2abc1
--- /dev/null
+++ b/standards/rfc2222.txt
@@ -0,0 +1,899 @@
+
+
+
+
+
+
+Network Working Group J. Myers
+Request for Comments: 2222 Netscape Communications
+Category: Standards Track October 1997
+
+
+ Simple Authentication and Security Layer (SASL)
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1997). All Rights Reserved.
+
+Table of Contents
+
+ 1. Abstract .............................................. 2
+ 2. Organization of this Document ......................... 2
+ 2.1. How to Read This Document ............................. 2
+ 2.2. Conventions Used in this Document ..................... 2
+ 2.3. Examples .............................................. 3
+ 3. Introduction and Overview ............................. 3
+ 4. Profiling requirements ................................ 4
+ 5. Specific issues ....................................... 5
+ 5.1. Client sends data first ............................... 5
+ 5.2. Server returns success with additional data ........... 5
+ 5.3. Multiple authentications .............................. 5
+ 6. Registration procedures ............................... 6
+ 6.1. Comments on SASL mechanism registrations .............. 6
+ 6.2. Location of Registered SASL Mechanism List ............ 6
+ 6.3. Change Control ........................................ 7
+ 6.4. Registration Template ................................. 7
+ 7. Mechanism definitions ................................. 8
+ 7.1. Kerberos version 4 mechanism .......................... 8
+ 7.2. GSSAPI mechanism ...................................... 9
+ 7.2.1 Client side of authentication protocol exchange ....... 9
+ 7.2.2 Server side of authentication protocol exchange ....... 10
+ 7.2.3 Security layer ........................................ 11
+ 7.3. S/Key mechanism ....................................... 11
+ 7.4. External mechanism .................................... 12
+ 8. References ............................................ 13
+ 9. Security Considerations ............................... 13
+ 10. Author's Address ...................................... 14
+
+
+
+Myers Standards Track [Page 1]
+
+RFC 2222 SASL October 1997
+
+
+ Appendix A. Relation of SASL to Transport Security .......... 15
+ Full Copyright Statement .................................... 16
+
+1. Abstract
+
+ This document describes a method for adding authentication support to
+ connection-based protocols. To use this specification, a protocol
+ includes a command for identifying and authenticating a user to a
+ server and for optionally negotiating protection of subsequent
+ protocol interactions. If its use is negotiated, a security layer is
+ inserted between the protocol and the connection. This document
+ describes how a protocol specifies such a command, defines several
+ mechanisms for use by the command, and defines the protocol used for
+ carrying a negotiated security layer over the connection.
+
+2. Organization of this Document
+
+2.1. How to Read This Document
+
+ This document is written to serve two different audiences, protocol
+ designers using this specification to support authentication in their
+ protocol, and implementors of clients or servers for those protocols
+ using this specification.
+
+ The sections "Introduction and Overview", "Profiling requirements",
+ and "Security Considerations" cover issues that protocol designers
+ need to understand and address in profiling this specification for
+ use in a specific protocol.
+
+ Implementors of a protocol using this specification need the
+ protocol-specific profiling information in addition to the
+ information in this document.
+
+2.2. Conventions Used in this Document
+
+ In examples, "C:" and "S:" indicate lines sent by the client and
+ server respectively.
+
+ The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
+ in this document are to be interpreted as defined in "Key words for
+ use in RFCs to Indicate Requirement Levels" [RFC 2119].
+
+
+
+
+
+
+
+
+
+
+Myers Standards Track [Page 2]
+
+RFC 2222 SASL October 1997
+
+
+2.3. Examples
+
+ Examples in this document are for the IMAP profile [RFC 2060] of this
+ specification. The base64 encoding of challenges and responses, as
+ well as the "+ " preceding the responses are part of the IMAP4
+ profile, not part of the SASL specification itself.
+
+3. Introduction and Overview
+
+ The Simple Authentication and Security Layer (SASL) is a method for
+ adding authentication support to connection-based protocols. To use
+ this specification, a protocol includes a command for identifying and
+ authenticating a user to a server and for optionally negotiating a
+ security layer for subsequent protocol interactions.
+
+ The command has a required argument identifying a SASL mechanism.
+ SASL mechanisms are named by strings, from 1 to 20 characters in
+ length, consisting of upper-case letters, digits, hyphens, and/or
+ underscores. SASL mechanism names must be registered with the IANA.
+ Procedures for registering new SASL mechanisms are given in the
+ section "Registration procedures"
+
+ If a server supports the requested mechanism, it initiates an
+ authentication protocol exchange. This consists of a series of
+ server challenges and client responses that are specific to the
+ requested mechanism. The challenges and responses are defined by the
+ mechanisms as binary tokens of arbitrary length. The protocol's
+ profile then specifies how these binary tokens are then encoded for
+ transfer over the connection.
+
+ After receiving the authentication command or any client response, a
+ server may issue a challenge, indicate failure, or indicate
+ completion. The protocol's profile specifies how the server
+ indicates which of the above it is doing.
+
+ After receiving a challenge, a client may issue a response or abort
+ the exchange. The protocol's profile specifies how the client
+ indicates which of the above it is doing.
+
+ During the authentication protocol exchange, the mechanism performs
+ authentication, transmits an authorization identity (frequently known
+ as a userid) from the client to server, and negotiates the use of a
+ mechanism-specific security layer. If the use of a security layer is
+ agreed upon, then the mechanism must also define or negotiate the
+ maximum cipher-text buffer size that each side is able to receive.
+
+
+
+
+
+
+Myers Standards Track [Page 3]
+
+RFC 2222 SASL October 1997
+
+
+ The transmitted authorization identity may be different than the
+ identity in the client's authentication credentials. This permits
+ agents such as proxy servers to authenticate using their own
+ credentials, yet request the access privileges of the identity for
+ which they are proxying. With any mechanism, transmitting an
+ authorization identity of the empty string directs the server to
+ derive an authorization identity from the client's authentication
+ credentials.
+
+ If use of a security layer is negotiated, it is applied to all
+ subsequent data sent over the connection. The security layer takes
+ effect immediately following the last response of the authentication
+ exchange for data sent by the client and the completion indication
+ for data sent by the server. Once the security layer is in effect,
+ the protocol stream is processed by the security layer into buffers
+ of cipher-text. Each buffer is transferred over the connection as a
+ stream of octets prepended with a four octet field in network byte
+ order that represents the length of the following buffer. The length
+ of the cipher-text buffer must be no larger than the maximum size
+ that was defined or negotiated by the other side.
+
+4. Profiling requirements
+
+ In order to use this specification, a protocol definition must supply
+ the following information:
+
+ 1. A service name, to be selected from the IANA registry of "service"
+ elements for the GSSAPI host-based service name form [RFC 2078].
+
+ 2. A definition of the command to initiate the authentication
+ protocol exchange. This command must have as a parameter the
+ mechanism name being selected by the client.
+
+ The command SHOULD have an optional parameter giving an initial
+ response. This optional parameter allows the client to avoid a
+ round trip when using a mechanism which is defined to have the
+ client send data first. When this initial response is sent by the
+ client and the selected mechanism is defined to have the server
+ start with an initial challenge, the command fails. See section
+ 5.1 of this document for further information.
+
+ 3. A definition of the method by which the authentication protocol
+ exchange is carried out, including how the challenges and
+ responses are encoded, how the server indicates completion or
+ failure of the exchange, how the client aborts an exchange, and
+ how the exchange method interacts with any line length limits in
+ the protocol.
+
+
+
+
+Myers Standards Track [Page 4]
+
+RFC 2222 SASL October 1997
+
+
+ 4. Identification of the octet where any negotiated security layer
+ starts to take effect, in both directions.
+
+ 5. A specification of how the authorization identity passed from the
+ client to the server is to be interpreted.
+
+5. Specific issues
+
+5.1. Client sends data first
+
+ Some mechanisms specify that the first data sent in the
+ authentication protocol exchange is from the client to the server.
+
+ If a protocol's profile permits the command which initiates an
+ authentication protocol exchange to contain an initial client
+ response, this parameter SHOULD be used with such mechanisms.
+
+ If the initial client response parameter is not given, or if a
+ protocol's profile does not permit the command which initiates an
+ authentication protocol exchange to contain an initial client
+ response, then the server issues a challenge with no data. The
+ client's response to this challenge is then used as the initial
+ client response. (The server then proceeds to send the next
+ challenge, indicates completion, or indicates failure.)
+
+5.2. Server returns success with additional data
+
+ Some mechanisms may specify that server challenge data be sent to the
+ client along with an indication of successful completion of the
+ exchange. This data would, for example, authenticate the server to
+ the client.
+
+ If a protocol's profile does not permit this server challenge to be
+ returned with a success indication, then the server issues the server
+ challenge without an indication of successful completion. The client
+ then responds with no data. After receiving this empty response, the
+ server then indicates successful completion.
+
+5.3. Multiple authentications
+
+ Unless otherwise stated by the protocol's profile, only one
+ successful SASL negotiation may occur in a protocol session. In this
+ case, once an authentication protocol exchange has successfully
+ completed, further attempts to initiate an authentication protocol
+ exchange fail.
+
+
+
+
+
+
+Myers Standards Track [Page 5]
+
+RFC 2222 SASL October 1997
+
+
+ In the case that a profile explicitly permits multiple successful
+ SASL negotiations to occur, then in no case may multiple security
+ layers be simultaneously in effect. If a security layer is in effect
+ and a subsequent SASL negotiation selects no security layer, the
+ original security layer remains in effect. If a security layer is in
+ effect and a subsequent SASL negotiation selects a second security
+ layer, then the second security layer replaces the first.
+
+6. Registration procedures
+
+ Registration of a SASL mechanism is done by filling in the template
+ in section 6.4 and sending it in to iana@isi.edu. IANA has the right
+ to reject obviously bogus registrations, but will perform no review
+ of clams made in the registration form.
+
+ There is no naming convention for SASL mechanisms; any name that
+ conforms to the syntax of a SASL mechanism name can be registered.
+
+ While the registration procedures do not require it, authors of SASL
+ mechanisms are encouraged to seek community review and comment
+ whenever that is feasible. Authors may seek community review by
+ posting a specification of their proposed mechanism as an internet-
+ draft. SASL mechanisms intended for widespread use should be
+ standardized through the normal IETF process, when appropriate.
+
+6.1. Comments on SASL mechanism registrations
+
+ Comments on registered SASL mechanisms should first be sent to the
+ "owner" of the mechanism. Submitters of comments may, after a
+ reasonable attempt to contact the owner, request IANA to attach their
+ comment to the SASL mechanism registration itself. If IANA approves
+ of this the comment will be made accessible in conjunction with the
+ SASL mechanism registration itself.
+
+6.2. Location of Registered SASL Mechanism List
+
+ SASL mechanism registrations will be posted in the anonymous FTP
+ directory "ftp://ftp.isi.edu/in-notes/iana/assignments/sasl-
+ mechanisms/" and all registered SASL mechanisms will be listed in the
+ periodically issued "Assigned Numbers" RFC [currently STD 2, RFC
+ 1700]. The SASL mechanism description and other supporting material
+ may also be published as an Informational RFC by sending it to "rfc-
+ editor@isi.edu" (please follow the instructions to RFC authors [RFC
+ 2223]).
+
+
+
+
+
+
+
+Myers Standards Track [Page 6]
+
+RFC 2222 SASL October 1997
+
+
+6.3. Change Control
+
+ Once a SASL mechanism registration has been published by IANA, the
+ author may request a change to its definition. The change request
+ follows the same procedure as the registration request.
+
+ The owner of a SASL mechanism may pass responsibility for the SASL
+ mechanism to another person or agency by informing IANA; this can be
+ done without discussion or review.
+
+ The IESG may reassign responsibility for a SASL mechanism. The most
+ common case of this will be to enable changes to be made to
+ mechanisms where the author of the registration has died, moved out
+ of contact or is otherwise unable to make changes that are important
+ to the community.
+
+ SASL mechanism registrations may not be deleted; mechanisms which are
+ no longer believed appropriate for use can be declared OBSOLETE by a
+ change to their "intended use" field; such SASL mechanisms will be
+ clearly marked in the lists published by IANA.
+
+ The IESG is considered to be the owner of all SASL mechanisms which
+ are on the IETF standards track.
+
+6.4. Registration Template
+
+ To: iana@iana.org
+ Subject: Registration of SASL mechanism X
+
+ SASL mechanism name:
+
+ Security considerations:
+
+ Published specification (optional, recommended):
+
+ Person & email address to contact for further information:
+
+ Intended usage:
+
+ (One of COMMON, LIMITED USE or OBSOLETE)
+
+ Author/Change controller:
+
+ (Any other information that the author deems interesting may be
+ added below this line.)
+
+
+
+
+
+
+Myers Standards Track [Page 7]
+
+RFC 2222 SASL October 1997
+
+
+7. Mechanism definitions
+
+ The following mechanisms are hereby defined.
+
+7.1. Kerberos version 4 mechanism
+
+ The mechanism name associated with Kerberos version 4 is
+ "KERBEROS_V4".
+
+ The first challenge consists of a random 32-bit number in network
+ byte order. The client responds with a Kerberos ticket and an
+ authenticator for the principal "service.hostname@realm", where
+ "service" is the service name specified in the protocol's profile,
+ "hostname" is the first component of the host name of the server with
+ all letters in lower case, and where "realm" is the Kerberos realm of
+ the server. The encrypted checksum field included within the
+ Kerberos authenticator contains the server provided challenge in
+ network byte order.
+
+ Upon decrypting and verifying the ticket and authenticator, the
+ server verifies that the contained checksum field equals the original
+ server provided random 32-bit number. Should the verification be
+ successful, the server must add one to the checksum and construct 8
+ octets of data, with the first four octets containing the incremented
+ checksum in network byte order, the fifth octet containing a bit-mask
+ specifying the security layers supported by the server, and the sixth
+ through eighth octets containing, in network byte order, the maximum
+ cipher-text buffer size the server is able to receive. The server
+ must encrypt using DES ECB mode the 8 octets of data in the session
+ key and issue that encrypted data in a second challenge. The client
+ considers the server authenticated if the first four octets of the
+ un-encrypted data is equal to one plus the checksum it previously
+ sent.
+
+ The client must construct data with the first four octets containing
+ the original server-issued checksum in network byte order, the fifth
+ octet containing the bit-mask specifying the selected security layer,
+ the sixth through eighth octets containing in network byte order the
+ maximum cipher-text buffer size the client is able to receive, and
+ the following octets containing the authorization identity. The
+ client must then append from one to eight zero-valued octets so that
+ the length of the data is a multiple of eight octets. The client must
+ then encrypt using DES PCBC mode the data with the session key and
+ respond with the encrypted data. The server decrypts the data and
+ verifies the contained checksum. The server must verify that the
+ principal identified in the Kerberos ticket is authorized to connect
+ as that authorization identity. After this verification, the
+ authentication process is complete.
+
+
+
+Myers Standards Track [Page 8]
+
+RFC 2222 SASL October 1997
+
+
+ The security layers and their corresponding bit-masks are as follows:
+
+ 1 No security layer
+ 2 Integrity (krb_mk_safe) protection
+ 4 Privacy (krb_mk_priv) protection
+
+ Other bit-masks may be defined in the future; bits which are not
+ understood must be negotiated off.
+
+ EXAMPLE: The following are two Kerberos version 4 login scenarios to
+ the IMAP4 protocol (note that the line breaks in the sample
+ authenticators are for editorial clarity and are not in real
+ authenticators)
+
+ S: * OK IMAP4 Server
+ C: A001 AUTHENTICATE KERBEROS_V4
+ S: + AmFYig==
+ C: BAcAQU5EUkVXLkNNVS5FRFUAOCAsho84kLN3/IJmrMG+25a4DT
+ +nZImJjnTNHJUtxAA+o0KPKfHEcAFs9a3CL5Oebe/ydHJUwYFd
+ WwuQ1MWiy6IesKvjL5rL9WjXUb9MwT9bpObYLGOKi1Qh
+ S: + or//EoAADZI=
+ C: DiAF5A4gA+oOIALuBkAAmw==
+ S: A001 OK Kerberos V4 authentication successful
+
+
+ S: * OK IMAP4 Server
+ C: A001 AUTHENTICATE KERBEROS_V4
+ S: + gcfgCA==
+ C: BAcAQU5EUkVXLkNNVS5FRFUAOCAsho84kLN3/IJmrMG+25a4DT
+ +nZImJjnTNHJUtxAA+o0KPKfHEcAFs9a3CL5Oebe/ydHJUwYFd
+ WwuQ1MWiy6IesKvjL5rL9WjXUb9MwT9bpObYLGOKi1Qh
+ S: A001 NO Kerberos V4 authentication failed
+
+7.2. GSSAPI mechanism
+
+ The mechanism name associated with all mechanisms employing the
+ GSSAPI [RFC 2078] is "GSSAPI".
+
+7.2.1 Client side of authentication protocol exchange
+
+ The client calls GSS_Init_sec_context, passing in 0 for
+ input_context_handle (initially) and a targ_name equal to output_name
+ from GSS_Import_Name called with input_name_type of
+ GSS_C_NT_HOSTBASED_SERVICE and input_name_string of
+ "service@hostname" where "service" is the service name specified in
+ the protocol's profile, and "hostname" is the fully qualified host
+ name of the server. The client then responds with the resulting
+ output_token. If GSS_Init_sec_context returns GSS_S_CONTINUE_NEEDED,
+
+
+
+Myers Standards Track [Page 9]
+
+RFC 2222 SASL October 1997
+
+
+ then the client should expect the server to issue a token in a
+ subsequent challenge. The client must pass the token to another call
+ to GSS_Init_sec_context, repeating the actions in this paragraph.
+
+ When GSS_Init_sec_context returns GSS_S_COMPLETE, the client takes
+ the following actions: If the last call to GSS_Init_sec_context
+ returned an output_token, then the client responds with the
+ output_token, otherwise the client responds with no data. The client
+ should then expect the server to issue a token in a subsequent
+ challenge. The client passes this token to GSS_Unwrap and interprets
+ the first octet of resulting cleartext as a bit-mask specifying the
+ security layers supported by the server and the second through fourth
+ octets as the maximum size output_message to send to the server. The
+ client then constructs data, with the first octet containing the
+ bit-mask specifying the selected security layer, the second through
+ fourth octets containing in network byte order the maximum size
+ output_message the client is able to receive, and the remaining
+ octets containing the authorization identity. The client passes the
+ data to GSS_Wrap with conf_flag set to FALSE, and responds with the
+ generated output_message. The client can then consider the server
+ authenticated.
+
+7.2.2 Server side of authentication protocol exchange
+
+ The server passes the initial client response to
+ GSS_Accept_sec_context as input_token, setting input_context_handle
+ to 0 (initially). If GSS_Accept_sec_context returns
+ GSS_S_CONTINUE_NEEDED, the server returns the generated output_token
+ to the client in challenge and passes the resulting response to
+ another call to GSS_Accept_sec_context, repeating the actions in this
+ paragraph.
+
+ When GSS_Accept_sec_context returns GSS_S_COMPLETE, the client takes
+ the following actions: If the last call to GSS_Accept_sec_context
+ returned an output_token, the server returns it to the client in a
+ challenge and expects a reply from the client with no data. Whether
+ or not an output_token was returned (and after receipt of any
+ response from the client to such an output_token), the server then
+ constructs 4 octets of data, with the first octet containing a bit-
+ mask specifying the security layers supported by the server and the
+ second through fourth octets containing in network byte order the
+ maximum size output_token the server is able to receive. The server
+ must then pass the plaintext to GSS_Wrap with conf_flag set to FALSE
+ and issue the generated output_message to the client in a challenge.
+ The server must then pass the resulting response to GSS_Unwrap and
+ interpret the first octet of resulting cleartext as the bit-mask for
+ the selected security layer, the second through fourth octets as the
+ maximum size output_message to send to the client, and the remaining
+
+
+
+Myers Standards Track [Page 10]
+
+RFC 2222 SASL October 1997
+
+
+ octets as the authorization identity. The server must verify that
+ the src_name is authorized to authenticate as the authorization
+ identity. After these verifications, the authentication process is
+ complete.
+
+7.2.3 Security layer
+
+ The security layers and their corresponding bit-masks are as follows:
+
+ 1 No security layer
+ 2 Integrity protection.
+ Sender calls GSS_Wrap with conf_flag set to FALSE
+ 4 Privacy protection.
+ Sender calls GSS_Wrap with conf_flag set to TRUE
+
+ Other bit-masks may be defined in the future; bits which are not
+ understood must be negotiated off.
+
+7.3. S/Key mechanism
+
+ The mechanism name associated with S/Key [RFC 1760] using the MD4
+ digest algorithm is "SKEY".
+
+ The client sends an initial response with the authorization identity.
+
+ The server then issues a challenge which contains the decimal
+ sequence number followed by a single space and the seed string for
+ the indicated authorization identity. The client responds with the
+ one-time-password, as either a 64-bit value in network byte order or
+ encoded in the "six English words" format.
+
+ The server must verify the one-time-password. After this
+ verification, the authentication process is complete.
+
+ S/Key authentication does not provide for any security layers.
+
+ EXAMPLE: The following are two S/Key login scenarios in the IMAP4
+ protocol.
+
+ S: * OK IMAP4 Server
+ C: A001 AUTHENTICATE SKEY
+ S: +
+ C: bW9yZ2Fu
+ S: + OTUgUWE1ODMwOA==
+ C: Rk9VUiBNQU5OIFNPT04gRklSIFZBUlkgTUFTSA==
+ S: A001 OK S/Key authentication successful
+
+
+
+
+
+Myers Standards Track [Page 11]
+
+RFC 2222 SASL October 1997
+
+
+ S: * OK IMAP4 Server
+ C: A001 AUTHENTICATE SKEY
+ S: +
+ C: c21pdGg=
+ S: + OTUgUWE1ODMwOA==
+ C: BsAY3g4gBNo=
+ S: A001 NO S/Key authentication failed
+
+ The following is an S/Key login scenario in an IMAP4-like protocol
+ which has an optional "initial response" argument to the AUTHENTICATE
+ command.
+
+ S: * OK IMAP4-Like Server
+ C: A001 AUTHENTICATE SKEY bW9yZ2Fu
+ S: + OTUgUWE1ODMwOA==
+ C: Rk9VUiBNQU5OIFNPT04gRklSIFZBUlkgTUFTSA==
+ S: A001 OK S/Key authentication successful
+
+7.4. External mechanism
+
+ The mechanism name associated with external authentication is
+ "EXTERNAL".
+
+ The client sends an initial response with the authorization identity.
+
+ The server uses information, external to SASL, to determine whether
+ the client is authorized to authenticate as the authorization
+ identity. If the client is so authorized, the server indicates
+ successful completion of the authentication exchange; otherwise the
+ server indicates failure.
+
+ The system providing this external information may be, for example,
+ IPsec or TLS.
+
+ If the client sends the empty string as the authorization identity
+ (thus requesting the authorization identity be derived from the
+ client's authentication credentials), the authorization identity is
+ to be derived from authentication credentials which exist in the
+ system which is providing the external authentication.
+
+
+
+
+
+
+
+
+
+
+
+
+Myers Standards Track [Page 12]
+
+RFC 2222 SASL October 1997
+
+
+8. References
+
+ [RFC 2060] Crispin, M., "Internet Message Access Protocol - Version
+ 4rev1", RFC 2060, December 1996.
+
+ [RFC 2078] Linn, J., "Generic Security Service Application Program
+ Interface, Version 2", RFC 2078, January 1997.
+
+ [RFC 2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", RFC 2119, March 1997.
+
+ [RFC 2223] Postel, J., and J. Reynolds, "Instructions to RFC
+ Authors", RFC 2223, October 1997.
+
+ [RFC 1760] Haller, N., "The S/Key One-Time Password System", RFC
+ 1760, February 1995.
+
+ [RFC 1700] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2,
+ RFC 1700, October 1994.
+
+9. Security Considerations
+
+ Security issues are discussed throughout this memo.
+
+ The mechanisms that support integrity protection are designed such
+ that the negotiation of the security layer and authorization identity
+ is integrity protected. When the client selects a security layer
+ with at least integrity protection, this protects against an active
+ attacker hijacking the connection and modifying the authentication
+ exchange to negotiate a plaintext connection.
+
+ When a server or client supports multiple authentication mechanisms,
+ each of which has a different security strength, it is possible for
+ an active attacker to cause a party to use the least secure mechanism
+ supported. To protect against this sort of attack, a client or
+ server which supports mechanisms of different strengths should have a
+ configurable minimum strength that it will use. It is not sufficient
+ for this minimum strength check to only be on the server, since an
+ active attacker can change which mechanisms the client sees as being
+ supported, causing the client to send authentication credentials for
+ its weakest supported mechanism.
+
+
+
+
+
+
+
+
+
+
+Myers Standards Track [Page 13]
+
+RFC 2222 SASL October 1997
+
+
+ The client's selection of a SASL mechanism is done in the clear and
+ may be modified by an active attacker. It is important for any new
+ SASL mechanisms to be designed such that an active attacker cannot
+ obtain an authentication with weaker security properties by modifying
+ the SASL mechanism name and/or the challenges and responses.
+
+ Any protocol interactions prior to authentication are performed in
+ the clear and may be modified by an active attacker. In the case
+ where a client selects integrity protection, it is important that any
+ security-sensitive protocol negotiations be performed after
+ authentication is complete. Protocols should be designed such that
+ negotiations performed prior to authentication should be either
+ ignored or revalidated once authentication is complete.
+
+10. Author's Address
+
+ John G. Myers
+ Netscape Communications
+ 501 E. Middlefield Road
+ Mail Stop MV-029
+ Mountain View, CA 94043-4042
+
+ EMail: jgmyers@netscape.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Myers Standards Track [Page 14]
+
+RFC 2222 SASL October 1997
+
+
+Appendix A. Relation of SASL to Transport Security
+
+ Questions have been raised about the relationship between SASL and
+ various services (such as IPsec and TLS) which provide a secured
+ connection.
+
+ Two of the key features of SASL are:
+
+ 1. The separation of the authorization identity from the identity in
+ the client's credentials. This permits agents such as proxy
+ servers to authenticate using their own credentials, yet request
+ the access privileges of the identity for which they are proxying.
+
+ 2. Upon successful completion of an authentication exchange, the
+ server knows the authorization identity the client wishes to use.
+ This allows servers to move to a "user is authenticated" state in
+ the protocol.
+
+ These features are extremely important to some application protocols,
+ yet Transport Security services do not always provide them. To
+ define SASL mechanisms based on these services would be a very messy
+ task, as the framing of these services would be redundant with the
+ framing of SASL and some method of providing these important SASL
+ features would have to be devised.
+
+ Sometimes it is desired to enable within an existing connection the
+ use of a security service which does not fit the SASL model. (TLS is
+ an example of such a service.) This can be done by adding a command,
+ for example "STARTTLS", to the protocol. Such a command is outside
+ the scope of SASL, and should be different from the command which
+ starts a SASL authentication protocol exchange.
+
+ In certain situations, it is reasonable to use SASL underneath one of
+ these Transport Security services. The transport service would
+ secure the connection, either service would authenticate the client,
+ and SASL would negotiate the authorization identity. The SASL
+ negotiation would be what moves the protocol from "unauthenticated"
+ to "authenticated" state. The "EXTERNAL" SASL mechanism is
+ explicitly intended to handle the case where the transport service
+ secures the connection and authenticates the client and SASL
+ negotiates the authorization identity.
+
+ When using SASL underneath a sufficiently strong Transport Security
+ service, a SASL security layer would most likely be redundant. The
+ client and server would thus probably want to negotiate off the use
+ of a SASL security layer.
+
+
+
+
+
+Myers Standards Track [Page 15]
+
+RFC 2222 SASL October 1997
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (1997). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implmentation may be prepared, copied, published
+ andand distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Myers Standards Track [Page 16]
+
diff --git a/standards/rfc2246.txt b/standards/rfc2246.txt
new file mode 100644
index 000000000..2e838cf5d
--- /dev/null
+++ b/standards/rfc2246.txt
@@ -0,0 +1,4483 @@
+
+
+
+
+
+
+Network Working Group T. Dierks
+Request for Comments: 2246 Certicom
+Category: Standards Track C. Allen
+ Certicom
+ January 1999
+
+
+ The TLS Protocol
+ Version 1.0
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+Abstract
+
+ This document specifies Version 1.0 of the Transport Layer Security
+ (TLS) protocol. The TLS protocol provides communications privacy over
+ the Internet. The protocol allows client/server applications to
+ communicate in a way that is designed to prevent eavesdropping,
+ tampering, or message forgery.
+
+Table of Contents
+
+ 1. Introduction 3
+ 2. Goals 4
+ 3. Goals of this document 5
+ 4. Presentation language 5
+ 4.1. Basic block size 6
+ 4.2. Miscellaneous 6
+ 4.3. Vectors 6
+ 4.4. Numbers 7
+ 4.5. Enumerateds 7
+ 4.6. Constructed types 8
+ 4.6.1. Variants 9
+ 4.7. Cryptographic attributes 10
+ 4.8. Constants 11
+ 5. HMAC and the pseudorandom function 11
+ 6. The TLS Record Protocol 13
+ 6.1. Connection states 14
+
+
+
+Dierks & Allen Standards Track [Page 1]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ 6.2. Record layer 16
+ 6.2.1. Fragmentation 16
+ 6.2.2. Record compression and decompression 17
+ 6.2.3. Record payload protection 18
+ 6.2.3.1. Null or standard stream cipher 19
+ 6.2.3.2. CBC block cipher 19
+ 6.3. Key calculation 21
+ 6.3.1. Export key generation example 22
+ 7. The TLS Handshake Protocol 23
+ 7.1. Change cipher spec protocol 24
+ 7.2. Alert protocol 24
+ 7.2.1. Closure alerts 25
+ 7.2.2. Error alerts 26
+ 7.3. Handshake Protocol overview 29
+ 7.4. Handshake protocol 32
+ 7.4.1. Hello messages 33
+ 7.4.1.1. Hello request 33
+ 7.4.1.2. Client hello 34
+ 7.4.1.3. Server hello 36
+ 7.4.2. Server certificate 37
+ 7.4.3. Server key exchange message 39
+ 7.4.4. Certificate request 41
+ 7.4.5. Server hello done 42
+ 7.4.6. Client certificate 43
+ 7.4.7. Client key exchange message 43
+ 7.4.7.1. RSA encrypted premaster secret message 44
+ 7.4.7.2. Client Diffie-Hellman public value 45
+ 7.4.8. Certificate verify 45
+ 7.4.9. Finished 46
+ 8. Cryptographic computations 47
+ 8.1. Computing the master secret 47
+ 8.1.1. RSA 48
+ 8.1.2. Diffie-Hellman 48
+ 9. Mandatory Cipher Suites 48
+ 10. Application data protocol 48
+ A. Protocol constant values 49
+ A.1. Record layer 49
+ A.2. Change cipher specs message 50
+ A.3. Alert messages 50
+ A.4. Handshake protocol 51
+ A.4.1. Hello messages 51
+ A.4.2. Server authentication and key exchange messages 52
+ A.4.3. Client authentication and key exchange messages 53
+ A.4.4. Handshake finalization message 54
+ A.5. The CipherSuite 54
+ A.6. The Security Parameters 56
+ B. Glossary 57
+ C. CipherSuite definitions 61
+
+
+
+Dierks & Allen Standards Track [Page 2]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ D. Implementation Notes 64
+ D.1. Temporary RSA keys 64
+ D.2. Random Number Generation and Seeding 64
+ D.3. Certificates and authentication 65
+ D.4. CipherSuites 65
+ E. Backward Compatibility With SSL 66
+ E.1. Version 2 client hello 67
+ E.2. Avoiding man-in-the-middle version rollback 68
+ F. Security analysis 69
+ F.1. Handshake protocol 69
+ F.1.1. Authentication and key exchange 69
+ F.1.1.1. Anonymous key exchange 69
+ F.1.1.2. RSA key exchange and authentication 70
+ F.1.1.3. Diffie-Hellman key exchange with authentication 71
+ F.1.2. Version rollback attacks 71
+ F.1.3. Detecting attacks against the handshake protocol 72
+ F.1.4. Resuming sessions 72
+ F.1.5. MD5 and SHA 72
+ F.2. Protecting application data 72
+ F.3. Final notes 73
+ G. Patent Statement 74
+ Security Considerations 75
+ References 75
+ Credits 77
+ Comments 78
+ Full Copyright Statement 80
+
+1. Introduction
+
+ The primary goal of the TLS Protocol is to provide privacy and data
+ integrity between two communicating applications. The protocol is
+ composed of two layers: the TLS Record Protocol and the TLS Handshake
+ Protocol. At the lowest level, layered on top of some reliable
+ transport protocol (e.g., TCP[TCP]), is the TLS Record Protocol. The
+ TLS Record Protocol provides connection security that has two basic
+ properties:
+
+ - The connection is private. Symmetric cryptography is used for
+ data encryption (e.g., DES [DES], RC4 [RC4], etc.) The keys for
+ this symmetric encryption are generated uniquely for each
+ connection and are based on a secret negotiated by another
+ protocol (such as the TLS Handshake Protocol). The Record
+ Protocol can also be used without encryption.
+
+ - The connection is reliable. Message transport includes a message
+ integrity check using a keyed MAC. Secure hash functions (e.g.,
+ SHA, MD5, etc.) are used for MAC computations. The Record
+ Protocol can operate without a MAC, but is generally only used in
+
+
+
+Dierks & Allen Standards Track [Page 3]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ this mode while another protocol is using the Record Protocol as
+ a transport for negotiating security parameters.
+
+ The TLS Record Protocol is used for encapsulation of various higher
+ level protocols. One such encapsulated protocol, the TLS Handshake
+ Protocol, allows the server and client to authenticate each other and
+ to negotiate an encryption algorithm and cryptographic keys before
+ the application protocol transmits or receives its first byte of
+ data. The TLS Handshake Protocol provides connection security that
+ has three basic properties:
+
+ - The peer's identity can be authenticated using asymmetric, or
+ public key, cryptography (e.g., RSA [RSA], DSS [DSS], etc.). This
+ authentication can be made optional, but is generally required
+ for at least one of the peers.
+
+ - The negotiation of a shared secret is secure: the negotiated
+ secret is unavailable to eavesdroppers, and for any authenticated
+ connection the secret cannot be obtained, even by an attacker who
+ can place himself in the middle of the connection.
+
+ - The negotiation is reliable: no attacker can modify the
+ negotiation communication without being detected by the parties
+ to the communication.
+
+ One advantage of TLS is that it is application protocol independent.
+ Higher level protocols can layer on top of the TLS Protocol
+ transparently. The TLS standard, however, does not specify how
+ protocols add security with TLS; the decisions on how to initiate TLS
+ handshaking and how to interpret the authentication certificates
+ exchanged are left up to the judgment of the designers and
+ implementors of protocols which run on top of TLS.
+
+2. Goals
+
+ The goals of TLS Protocol, in order of their priority, are:
+
+ 1. Cryptographic security: TLS should be used to establish a secure
+ connection between two parties.
+
+ 2. Interoperability: Independent programmers should be able to
+ develop applications utilizing TLS that will then be able to
+ successfully exchange cryptographic parameters without knowledge
+ of one another's code.
+
+ 3. Extensibility: TLS seeks to provide a framework into which new
+ public key and bulk encryption methods can be incorporated as
+ necessary. This will also accomplish two sub-goals: to prevent
+
+
+
+Dierks & Allen Standards Track [Page 4]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ the need to create a new protocol (and risking the introduction
+ of possible new weaknesses) and to avoid the need to implement an
+ entire new security library.
+
+ 4. Relative efficiency: Cryptographic operations tend to be highly
+ CPU intensive, particularly public key operations. For this
+ reason, the TLS protocol has incorporated an optional session
+ caching scheme to reduce the number of connections that need to
+ be established from scratch. Additionally, care has been taken to
+ reduce network activity.
+
+3. Goals of this document
+
+ This document and the TLS protocol itself are based on the SSL 3.0
+ Protocol Specification as published by Netscape. The differences
+ between this protocol and SSL 3.0 are not dramatic, but they are
+ significant enough that TLS 1.0 and SSL 3.0 do not interoperate
+ (although TLS 1.0 does incorporate a mechanism by which a TLS
+ implementation can back down to SSL 3.0). This document is intended
+ primarily for readers who will be implementing the protocol and those
+ doing cryptographic analysis of it. The specification has been
+ written with this in mind, and it is intended to reflect the needs of
+ those two groups. For that reason, many of the algorithm-dependent
+ data structures and rules are included in the body of the text (as
+ opposed to in an appendix), providing easier access to them.
+
+ This document is not intended to supply any details of service
+ definition nor interface definition, although it does cover select
+ areas of policy as they are required for the maintenance of solid
+ security.
+
+4. Presentation language
+
+ This document deals with the formatting of data in an external
+ representation. The following very basic and somewhat casually
+ defined presentation syntax will be used. The syntax draws from
+ several sources in its structure. Although it resembles the
+ programming language "C" in its syntax and XDR [XDR] in both its
+ syntax and intent, it would be risky to draw too many parallels. The
+ purpose of this presentation language is to document TLS only, not to
+ have general application beyond that particular goal.
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 5]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+4.1. Basic block size
+
+ The representation of all data items is explicitly specified. The
+ basic data block size is one byte (i.e. 8 bits). Multiple byte data
+ items are concatenations of bytes, from left to right, from top to
+ bottom. From the bytestream a multi-byte item (a numeric in the
+ example) is formed (using C notation) by:
+
+ value = (byte[0] << 8*(n-1)) | (byte[1] << 8*(n-2)) |
+ ... | byte[n-1];
+
+ This byte ordering for multi-byte values is the commonplace network
+ byte order or big endian format.
+
+4.2. Miscellaneous
+
+ Comments begin with "/*" and end with "*/".
+
+ Optional components are denoted by enclosing them in "[[ ]]" double
+ brackets.
+
+ Single byte entities containing uninterpreted data are of type
+ opaque.
+
+4.3. Vectors
+
+ A vector (single dimensioned array) is a stream of homogeneous data
+ elements. The size of the vector may be specified at documentation
+ time or left unspecified until runtime. In either case the length
+ declares the number of bytes, not the number of elements, in the
+ vector. The syntax for specifying a new type T' that is a fixed
+ length vector of type T is
+
+ T T'[n];
+
+ Here T' occupies n bytes in the data stream, where n is a multiple of
+ the size of T. The length of the vector is not included in the
+ encoded stream.
+
+ In the following example, Datum is defined to be three consecutive
+ bytes that the protocol does not interpret, while Data is three
+ consecutive Datum, consuming a total of nine bytes.
+
+ opaque Datum[3]; /* three uninterpreted bytes */
+ Datum Data[9]; /* 3 consecutive 3 byte vectors */
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 6]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Variable length vectors are defined by specifying a subrange of legal
+ lengths, inclusively, using the notation <floor..ceiling>. When
+ encoded, the actual length precedes the vector's contents in the byte
+ stream. The length will be in the form of a number consuming as many
+ bytes as required to hold the vector's specified maximum (ceiling)
+ length. A variable length vector with an actual length field of zero
+ is referred to as an empty vector.
+
+ T T'<floor..ceiling>;
+
+ In the following example, mandatory is a vector that must contain
+ between 300 and 400 bytes of type opaque. It can never be empty. The
+ actual length field consumes two bytes, a uint16, sufficient to
+ represent the value 400 (see Section 4.4). On the other hand, longer
+ can represent up to 800 bytes of data, or 400 uint16 elements, and it
+ may be empty. Its encoding will include a two byte actual length
+ field prepended to the vector. The length of an encoded vector must
+ be an even multiple of the length of a single element (for example, a
+ 17 byte vector of uint16 would be illegal).
+
+ opaque mandatory<300..400>;
+ /* length field is 2 bytes, cannot be empty */
+ uint16 longer<0..800>;
+ /* zero to 400 16-bit unsigned integers */
+
+4.4. Numbers
+
+ The basic numeric data type is an unsigned byte (uint8). All larger
+ numeric data types are formed from fixed length series of bytes
+ concatenated as described in Section 4.1 and are also unsigned. The
+ following numeric types are predefined.
+
+ uint8 uint16[2];
+ uint8 uint24[3];
+ uint8 uint32[4];
+ uint8 uint64[8];
+
+ All values, here and elsewhere in the specification, are stored in
+ "network" or "big-endian" order; the uint32 represented by the hex
+ bytes 01 02 03 04 is equivalent to the decimal value 16909060.
+
+4.5. Enumerateds
+
+ An additional sparse data type is available called enum. A field of
+ type enum can only assume the values declared in the definition.
+ Each definition is a different type. Only enumerateds of the same
+ type may be assigned or compared. Every element of an enumerated must
+
+
+
+
+Dierks & Allen Standards Track [Page 7]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ be assigned a value, as demonstrated in the following example. Since
+ the elements of the enumerated are not ordered, they can be assigned
+ any unique value, in any order.
+
+ enum { e1(v1), e2(v2), ... , en(vn) [[, (n)]] } Te;
+
+ Enumerateds occupy as much space in the byte stream as would its
+ maximal defined ordinal value. The following definition would cause
+ one byte to be used to carry fields of type Color.
+
+ enum { red(3), blue(5), white(7) } Color;
+
+ One may optionally specify a value without its associated tag to
+ force the width definition without defining a superfluous element.
+ In the following example, Taste will consume two bytes in the data
+ stream but can only assume the values 1, 2 or 4.
+
+ enum { sweet(1), sour(2), bitter(4), (32000) } Taste;
+
+ The names of the elements of an enumeration are scoped within the
+ defined type. In the first example, a fully qualified reference to
+ the second element of the enumeration would be Color.blue. Such
+ qualification is not required if the target of the assignment is well
+ specified.
+
+ Color color = Color.blue; /* overspecified, legal */
+ Color color = blue; /* correct, type implicit */
+
+ For enumerateds that are never converted to external representation,
+ the numerical information may be omitted.
+
+ enum { low, medium, high } Amount;
+
+4.6. Constructed types
+
+ Structure types may be constructed from primitive types for
+ convenience. Each specification declares a new, unique type. The
+ syntax for definition is much like that of C.
+
+ struct {
+ T1 f1;
+ T2 f2;
+ ...
+ Tn fn;
+ } [[T]];
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 8]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ The fields within a structure may be qualified using the type's name
+ using a syntax much like that available for enumerateds. For example,
+ T.f2 refers to the second field of the previous declaration.
+ Structure definitions may be embedded.
+
+4.6.1. Variants
+
+ Defined structures may have variants based on some knowledge that is
+ available within the environment. The selector must be an enumerated
+ type that defines the possible variants the structure defines. There
+ must be a case arm for every element of the enumeration declared in
+ the select. The body of the variant structure may be given a label
+ for reference. The mechanism by which the variant is selected at
+ runtime is not prescribed by the presentation language.
+
+ struct {
+ T1 f1;
+ T2 f2;
+ ....
+ Tn fn;
+ select (E) {
+ case e1: Te1;
+ case e2: Te2;
+ ....
+ case en: Ten;
+ } [[fv]];
+ } [[Tv]];
+
+ For example:
+
+ enum { apple, orange } VariantTag;
+ struct {
+ uint16 number;
+ opaque string<0..10>; /* variable length */
+ } V1;
+ struct {
+ uint32 number;
+ opaque string[10]; /* fixed length */
+ } V2;
+ struct {
+ select (VariantTag) { /* value of selector is implicit */
+ case apple: V1; /* VariantBody, tag = apple */
+ case orange: V2; /* VariantBody, tag = orange */
+ } variant_body; /* optional label on variant */
+ } VariantRecord;
+
+ Variant structures may be qualified (narrowed) by specifying a value
+ for the selector prior to the type. For example, a
+
+
+
+Dierks & Allen Standards Track [Page 9]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ orange VariantRecord
+
+ is a narrowed type of a VariantRecord containing a variant_body of
+ type V2.
+
+4.7. Cryptographic attributes
+
+ The four cryptographic operations digital signing, stream cipher
+ encryption, block cipher encryption, and public key encryption are
+ designated digitally-signed, stream-ciphered, block-ciphered, and
+ public-key-encrypted, respectively. A field's cryptographic
+ processing is specified by prepending an appropriate key word
+ designation before the field's type specification. Cryptographic keys
+ are implied by the current session state (see Section 6.1).
+
+ In digital signing, one-way hash functions are used as input for a
+ signing algorithm. A digitally-signed element is encoded as an opaque
+ vector <0..2^16-1>, where the length is specified by the signing
+ algorithm and key.
+
+ In RSA signing, a 36-byte structure of two hashes (one SHA and one
+ MD5) is signed (encrypted with the private key). It is encoded with
+ PKCS #1 block type 0 or type 1 as described in [PKCS1].
+
+ In DSS, the 20 bytes of the SHA hash are run directly through the
+ Digital Signing Algorithm with no additional hashing. This produces
+ two values, r and s. The DSS signature is an opaque vector, as above,
+ the contents of which are the DER encoding of:
+
+ Dss-Sig-Value ::= SEQUENCE {
+ r INTEGER,
+ s INTEGER
+ }
+
+ In stream cipher encryption, the plaintext is exclusive-ORed with an
+ identical amount of output generated from a cryptographically-secure
+ keyed pseudorandom number generator.
+
+ In block cipher encryption, every block of plaintext encrypts to a
+ block of ciphertext. All block cipher encryption is done in CBC
+ (Cipher Block Chaining) mode, and all items which are block-ciphered
+ will be an exact multiple of the cipher block length.
+
+ In public key encryption, a public key algorithm is used to encrypt
+ data in such a way that it can be decrypted only with the matching
+ private key. A public-key-encrypted element is encoded as an opaque
+ vector <0..2^16-1>, where the length is specified by the signing
+ algorithm and key.
+
+
+
+Dierks & Allen Standards Track [Page 10]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ An RSA encrypted value is encoded with PKCS #1 block type 2 as
+ described in [PKCS1].
+
+ In the following example:
+
+ stream-ciphered struct {
+ uint8 field1;
+ uint8 field2;
+ digitally-signed opaque hash[20];
+ } UserType;
+
+ The contents of hash are used as input for the signing algorithm,
+ then the entire structure is encrypted with a stream cipher. The
+ length of this structure, in bytes would be equal to 2 bytes for
+ field1 and field2, plus two bytes for the length of the signature,
+ plus the length of the output of the signing algorithm. This is known
+ due to the fact that the algorithm and key used for the signing are
+ known prior to encoding or decoding this structure.
+
+4.8. Constants
+
+ Typed constants can be defined for purposes of specification by
+ declaring a symbol of the desired type and assigning values to it.
+ Under-specified types (opaque, variable length vectors, and
+ structures that contain opaque) cannot be assigned values. No fields
+ of a multi-element structure or vector may be elided.
+
+ For example,
+
+ struct {
+ uint8 f1;
+ uint8 f2;
+ } Example1;
+
+ Example1 ex1 = {1, 4}; /* assigns f1 = 1, f2 = 4 */
+
+5. HMAC and the pseudorandom function
+
+ A number of operations in the TLS record and handshake layer required
+ a keyed MAC; this is a secure digest of some data protected by a
+ secret. Forging the MAC is infeasible without knowledge of the MAC
+ secret. The construction we use for this operation is known as HMAC,
+ described in [HMAC].
+
+ HMAC can be used with a variety of different hash algorithms. TLS
+ uses it in the handshake with two different algorithms: MD5 and SHA-
+ 1, denoting these as HMAC_MD5(secret, data) and HMAC_SHA(secret,
+
+
+
+
+Dierks & Allen Standards Track [Page 11]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ data). Additional hash algorithms can be defined by cipher suites and
+ used to protect record data, but MD5 and SHA-1 are hard coded into
+ the description of the handshaking for this version of the protocol.
+
+ In addition, a construction is required to do expansion of secrets
+ into blocks of data for the purposes of key generation or validation.
+ This pseudo-random function (PRF) takes as input a secret, a seed,
+ and an identifying label and produces an output of arbitrary length.
+
+ In order to make the PRF as secure as possible, it uses two hash
+ algorithms in a way which should guarantee its security if either
+ algorithm remains secure.
+
+ First, we define a data expansion function, P_hash(secret, data)
+ which uses a single hash function to expand a secret and seed into an
+ arbitrary quantity of output:
+
+ P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
+ HMAC_hash(secret, A(2) + seed) +
+ HMAC_hash(secret, A(3) + seed) + ...
+
+ Where + indicates concatenation.
+
+ A() is defined as:
+ A(0) = seed
+ A(i) = HMAC_hash(secret, A(i-1))
+
+ P_hash can be iterated as many times as is necessary to produce the
+ required quantity of data. For example, if P_SHA-1 was being used to
+ create 64 bytes of data, it would have to be iterated 4 times
+ (through A(4)), creating 80 bytes of output data; the last 16 bytes
+ of the final iteration would then be discarded, leaving 64 bytes of
+ output data.
+
+ TLS's PRF is created by splitting the secret into two halves and
+ using one half to generate data with P_MD5 and the other half to
+ generate data with P_SHA-1, then exclusive-or'ing the outputs of
+ these two expansion functions together.
+
+ S1 and S2 are the two halves of the secret and each is the same
+ length. S1 is taken from the first half of the secret, S2 from the
+ second half. Their length is created by rounding up the length of the
+ overall secret divided by two; thus, if the original secret is an odd
+ number of bytes long, the last byte of S1 will be the same as the
+ first byte of S2.
+
+ L_S = length in bytes of secret;
+ L_S1 = L_S2 = ceil(L_S / 2);
+
+
+
+Dierks & Allen Standards Track [Page 12]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ The secret is partitioned into two halves (with the possibility of
+ one shared byte) as described above, S1 taking the first L_S1 bytes
+ and S2 the last L_S2 bytes.
+
+ The PRF is then defined as the result of mixing the two pseudorandom
+ streams by exclusive-or'ing them together.
+
+ PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
+ P_SHA-1(S2, label + seed);
+
+ The label is an ASCII string. It should be included in the exact form
+ it is given without a length byte or trailing null character. For
+ example, the label "slithy toves" would be processed by hashing the
+ following bytes:
+
+ 73 6C 69 74 68 79 20 74 6F 76 65 73
+
+ Note that because MD5 produces 16 byte outputs and SHA-1 produces 20
+ byte outputs, the boundaries of their internal iterations will not be
+ aligned; to generate a 80 byte output will involve P_MD5 being
+ iterated through A(5), while P_SHA-1 will only iterate through A(4).
+
+6. The TLS Record Protocol
+
+ The TLS Record Protocol is a layered protocol. At each layer,
+ messages may include fields for length, description, and content.
+ The Record Protocol takes messages to be transmitted, fragments the
+ data into manageable blocks, optionally compresses the data, applies
+ a MAC, encrypts, and transmits the result. Received data is
+ decrypted, verified, decompressed, and reassembled, then delivered to
+ higher level clients.
+
+ Four record protocol clients are described in this document: the
+ handshake protocol, the alert protocol, the change cipher spec
+ protocol, and the application data protocol. In order to allow
+ extension of the TLS protocol, additional record types can be
+ supported by the record protocol. Any new record types should
+ allocate type values immediately beyond the ContentType values for
+ the four record types described here (see Appendix A.2). If a TLS
+ implementation receives a record type it does not understand, it
+ should just ignore it. Any protocol designed for use over TLS must be
+ carefully designed to deal with all possible attacks against it.
+ Note that because the type and length of a record are not protected
+ by encryption, care should be take to minimize the value of traffic
+ analysis of these values.
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 13]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+6.1. Connection states
+
+ A TLS connection state is the operating environment of the TLS Record
+ Protocol. It specifies a compression algorithm, encryption algorithm,
+ and MAC algorithm. In addition, the parameters for these algorithms
+ are known: the MAC secret and the bulk encryption keys and IVs for
+ the connection in both the read and the write directions. Logically,
+ there are always four connection states outstanding: the current read
+ and write states, and the pending read and write states. All records
+ are processed under the current read and write states. The security
+ parameters for the pending states can be set by the TLS Handshake
+ Protocol, and the Handshake Protocol can selectively make either of
+ the pending states current, in which case the appropriate current
+ state is disposed of and replaced with the pending state; the pending
+ state is then reinitialized to an empty state. It is illegal to make
+ a state which has not been initialized with security parameters a
+ current state. The initial current state always specifies that no
+ encryption, compression, or MAC will be used.
+
+ The security parameters for a TLS Connection read and write state are
+ set by providing the following values:
+
+ connection end
+ Whether this entity is considered the "client" or the "server" in
+ this connection.
+
+ bulk encryption algorithm
+ An algorithm to be used for bulk encryption. This specification
+ includes the key size of this algorithm, how much of that key is
+ secret, whether it is a block or stream cipher, the block size of
+ the cipher (if appropriate), and whether it is considered an
+ "export" cipher.
+
+ MAC algorithm
+ An algorithm to be used for message authentication. This
+ specification includes the size of the hash which is returned by
+ the MAC algorithm.
+
+ compression algorithm
+ An algorithm to be used for data compression. This specification
+ must include all information the algorithm requires to do
+ compression.
+
+ master secret
+ A 48 byte secret shared between the two peers in the connection.
+
+ client random
+ A 32 byte value provided by the client.
+
+
+
+Dierks & Allen Standards Track [Page 14]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ server random
+ A 32 byte value provided by the server.
+
+ These parameters are defined in the presentation language as:
+
+ enum { server, client } ConnectionEnd;
+
+ enum { null, rc4, rc2, des, 3des, des40 } BulkCipherAlgorithm;
+
+ enum { stream, block } CipherType;
+
+ enum { true, false } IsExportable;
+
+ enum { null, md5, sha } MACAlgorithm;
+
+ enum { null(0), (255) } CompressionMethod;
+
+ /* The algorithms specified in CompressionMethod,
+ BulkCipherAlgorithm, and MACAlgorithm may be added to. */
+
+ struct {
+ ConnectionEnd entity;
+ BulkCipherAlgorithm bulk_cipher_algorithm;
+ CipherType cipher_type;
+ uint8 key_size;
+ uint8 key_material_length;
+ IsExportable is_exportable;
+ MACAlgorithm mac_algorithm;
+ uint8 hash_size;
+ CompressionMethod compression_algorithm;
+ opaque master_secret[48];
+ opaque client_random[32];
+ opaque server_random[32];
+ } SecurityParameters;
+
+ The record layer will use the security parameters to generate the
+ following six items:
+
+ client write MAC secret
+ server write MAC secret
+ client write key
+ server write key
+ client write IV (for block ciphers only)
+ server write IV (for block ciphers only)
+
+ The client write parameters are used by the server when receiving and
+ processing records and vice-versa. The algorithm used for generating
+ these items from the security parameters is described in section 6.3.
+
+
+
+Dierks & Allen Standards Track [Page 15]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Once the security parameters have been set and the keys have been
+ generated, the connection states can be instantiated by making them
+ the current states. These current states must be updated for each
+ record processed. Each connection state includes the following
+ elements:
+
+ compression state
+ The current state of the compression algorithm.
+
+ cipher state
+ The current state of the encryption algorithm. This will consist
+ of the scheduled key for that connection. In addition, for block
+ ciphers running in CBC mode (the only mode specified for TLS),
+ this will initially contain the IV for that connection state and
+ be updated to contain the ciphertext of the last block encrypted
+ or decrypted as records are processed. For stream ciphers, this
+ will contain whatever the necessary state information is to allow
+ the stream to continue to encrypt or decrypt data.
+
+ MAC secret
+ The MAC secret for this connection as generated above.
+
+ sequence number
+ Each connection state contains a sequence number, which is
+ maintained separately for read and write states. The sequence
+ number must be set to zero whenever a connection state is made
+ the active state. Sequence numbers are of type uint64 and may not
+ exceed 2^64-1. A sequence number is incremented after each
+ record: specifically, the first record which is transmitted under
+ a particular connection state should use sequence number 0.
+
+6.2. Record layer
+
+ The TLS Record Layer receives uninterpreted data from higher layers
+ in non-empty blocks of arbitrary size.
+
+6.2.1. Fragmentation
+
+ The record layer fragments information blocks into TLSPlaintext
+ records carrying data in chunks of 2^14 bytes or less. Client message
+ boundaries are not preserved in the record layer (i.e., multiple
+ client messages of the same ContentType may be coalesced into a
+ single TLSPlaintext record, or a single message may be fragmented
+ across several records).
+
+ struct {
+ uint8 major, minor;
+ } ProtocolVersion;
+
+
+
+Dierks & Allen Standards Track [Page 16]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ enum {
+ change_cipher_spec(20), alert(21), handshake(22),
+ application_data(23), (255)
+ } ContentType;
+
+ struct {
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length;
+ opaque fragment[TLSPlaintext.length];
+ } TLSPlaintext;
+
+ type
+ The higher level protocol used to process the enclosed fragment.
+
+ version
+ The version of the protocol being employed. This document
+ describes TLS Version 1.0, which uses the version { 3, 1 }. The
+ version value 3.1 is historical: TLS version 1.0 is a minor
+ modification to the SSL 3.0 protocol, which bears the version
+ value 3.0. (See Appendix A.1).
+
+ length
+ The length (in bytes) of the following TLSPlaintext.fragment.
+ The length should not exceed 2^14.
+
+ fragment
+ The application data. This data is transparent and treated as an
+ independent block to be dealt with by the higher level protocol
+ specified by the type field.
+
+ Note: Data of different TLS Record layer content types may be
+ interleaved. Application data is generally of lower precedence
+ for transmission than other content types.
+
+6.2.2. Record compression and decompression
+
+ All records are compressed using the compression algorithm defined in
+ the current session state. There is always an active compression
+ algorithm; however, initially it is defined as
+ CompressionMethod.null. The compression algorithm translates a
+ TLSPlaintext structure into a TLSCompressed structure. Compression
+ functions are initialized with default state information whenever a
+ connection state is made active.
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 17]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Compression must be lossless and may not increase the content length
+ by more than 1024 bytes. If the decompression function encounters a
+ TLSCompressed.fragment that would decompress to a length in excess of
+ 2^14 bytes, it should report a fatal decompression failure error.
+
+ struct {
+ ContentType type; /* same as TLSPlaintext.type */
+ ProtocolVersion version;/* same as TLSPlaintext.version */
+ uint16 length;
+ opaque fragment[TLSCompressed.length];
+ } TLSCompressed;
+
+ length
+ The length (in bytes) of the following TLSCompressed.fragment.
+ The length should not exceed 2^14 + 1024.
+
+ fragment
+ The compressed form of TLSPlaintext.fragment.
+
+ Note: A CompressionMethod.null operation is an identity operation; no
+ fields are altered.
+
+ Implementation note:
+ Decompression functions are responsible for ensuring that
+ messages cannot cause internal buffer overflows.
+
+6.2.3. Record payload protection
+
+ The encryption and MAC functions translate a TLSCompressed structure
+ into a TLSCiphertext. The decryption functions reverse the process.
+ The MAC of the record also includes a sequence number so that
+ missing, extra or repeated messages are detectable.
+
+ struct {
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length;
+ select (CipherSpec.cipher_type) {
+ case stream: GenericStreamCipher;
+ case block: GenericBlockCipher;
+ } fragment;
+ } TLSCiphertext;
+
+ type
+ The type field is identical to TLSCompressed.type.
+
+ version
+ The version field is identical to TLSCompressed.version.
+
+
+
+Dierks & Allen Standards Track [Page 18]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ length
+ The length (in bytes) of the following TLSCiphertext.fragment.
+ The length may not exceed 2^14 + 2048.
+
+ fragment
+ The encrypted form of TLSCompressed.fragment, with the MAC.
+
+6.2.3.1. Null or standard stream cipher
+
+ Stream ciphers (including BulkCipherAlgorithm.null - see Appendix
+ A.6) convert TLSCompressed.fragment structures to and from stream
+ TLSCiphertext.fragment structures.
+
+ stream-ciphered struct {
+ opaque content[TLSCompressed.length];
+ opaque MAC[CipherSpec.hash_size];
+ } GenericStreamCipher;
+
+ The MAC is generated as:
+
+ HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type +
+ TLSCompressed.version + TLSCompressed.length +
+ TLSCompressed.fragment));
+
+ where "+" denotes concatenation.
+
+ seq_num
+ The sequence number for this record.
+
+ hash
+ The hashing algorithm specified by
+ SecurityParameters.mac_algorithm.
+
+ Note that the MAC is computed before encryption. The stream cipher
+ encrypts the entire block, including the MAC. For stream ciphers that
+ do not use a synchronization vector (such as RC4), the stream cipher
+ state from the end of one record is simply used on the subsequent
+ packet. If the CipherSuite is TLS_NULL_WITH_NULL_NULL, encryption
+ consists of the identity operation (i.e., the data is not encrypted
+ and the MAC size is zero implying that no MAC is used).
+ TLSCiphertext.length is TLSCompressed.length plus
+ CipherSpec.hash_size.
+
+6.2.3.2. CBC block cipher
+
+ For block ciphers (such as RC2 or DES), the encryption and MAC
+ functions convert TLSCompressed.fragment structures to and from block
+ TLSCiphertext.fragment structures.
+
+
+
+Dierks & Allen Standards Track [Page 19]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ block-ciphered struct {
+ opaque content[TLSCompressed.length];
+ opaque MAC[CipherSpec.hash_size];
+ uint8 padding[GenericBlockCipher.padding_length];
+ uint8 padding_length;
+ } GenericBlockCipher;
+
+ The MAC is generated as described in Section 6.2.3.1.
+
+ padding
+ Padding that is added to force the length of the plaintext to be
+ an integral multiple of the block cipher's block length. The
+ padding may be any length up to 255 bytes long, as long as it
+ results in the TLSCiphertext.length being an integral multiple of
+ the block length. Lengths longer than necessary might be
+ desirable to frustrate attacks on a protocol based on analysis of
+ the lengths of exchanged messages. Each uint8 in the padding data
+ vector must be filled with the padding length value.
+
+ padding_length
+ The padding length should be such that the total size of the
+ GenericBlockCipher structure is a multiple of the cipher's block
+ length. Legal values range from zero to 255, inclusive. This
+ length specifies the length of the padding field exclusive of the
+ padding_length field itself.
+
+ The encrypted data length (TLSCiphertext.length) is one more than the
+ sum of TLSCompressed.length, CipherSpec.hash_size, and
+ padding_length.
+
+ Example: If the block length is 8 bytes, the content length
+ (TLSCompressed.length) is 61 bytes, and the MAC length is 20
+ bytes, the length before padding is 82 bytes. Thus, the
+ padding length modulo 8 must be equal to 6 in order to make
+ the total length an even multiple of 8 bytes (the block
+ length). The padding length can be 6, 14, 22, and so on,
+ through 254. If the padding length were the minimum necessary,
+ 6, the padding would be 6 bytes, each containing the value 6.
+ Thus, the last 8 octets of the GenericBlockCipher before block
+ encryption would be xx 06 06 06 06 06 06 06, where xx is the
+ last octet of the MAC.
+
+ Note: With block ciphers in CBC mode (Cipher Block Chaining) the
+ initialization vector (IV) for the first record is generated with
+ the other keys and secrets when the security parameters are set.
+ The IV for subsequent records is the last ciphertext block from
+ the previous record.
+
+
+
+
+Dierks & Allen Standards Track [Page 20]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+6.3. Key calculation
+
+ The Record Protocol requires an algorithm to generate keys, IVs, and
+ MAC secrets from the security parameters provided by the handshake
+ protocol.
+
+ The master secret is hashed into a sequence of secure bytes, which
+ are assigned to the MAC secrets, keys, and non-export IVs required by
+ the current connection state (see Appendix A.6). CipherSpecs require
+ a client write MAC secret, a server write MAC secret, a client write
+ key, a server write key, a client write IV, and a server write IV,
+ which are generated from the master secret in that order. Unused
+ values are empty.
+
+ When generating keys and MAC secrets, the master secret is used as an
+ entropy source, and the random values provide unencrypted salt
+ material and IVs for exportable ciphers.
+
+ To generate the key material, compute
+
+ key_block = PRF(SecurityParameters.master_secret,
+ "key expansion",
+ SecurityParameters.server_random +
+ SecurityParameters.client_random);
+
+ until enough output has been generated. Then the key_block is
+ partitioned as follows:
+
+ client_write_MAC_secret[SecurityParameters.hash_size]
+ server_write_MAC_secret[SecurityParameters.hash_size]
+ client_write_key[SecurityParameters.key_material_length]
+ server_write_key[SecurityParameters.key_material_length]
+ client_write_IV[SecurityParameters.IV_size]
+ server_write_IV[SecurityParameters.IV_size]
+
+ The client_write_IV and server_write_IV are only generated for non-
+ export block ciphers. For exportable block ciphers, the
+ initialization vectors are generated later, as described below. Any
+ extra key_block material is discarded.
+
+ Implementation note:
+ The cipher spec which is defined in this document which requires
+ the most material is 3DES_EDE_CBC_SHA: it requires 2 x 24 byte
+ keys, 2 x 20 byte MAC secrets, and 2 x 8 byte IVs, for a total of
+ 104 bytes of key material.
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 21]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Exportable encryption algorithms (for which CipherSpec.is_exportable
+ is true) require additional processing as follows to derive their
+ final write keys:
+
+ final_client_write_key =
+ PRF(SecurityParameters.client_write_key,
+ "client write key",
+ SecurityParameters.client_random +
+ SecurityParameters.server_random);
+ final_server_write_key =
+ PRF(SecurityParameters.server_write_key,
+ "server write key",
+ SecurityParameters.client_random +
+ SecurityParameters.server_random);
+
+ Exportable encryption algorithms derive their IVs solely from the
+ random values from the hello messages:
+
+ iv_block = PRF("", "IV block", SecurityParameters.client_random +
+ SecurityParameters.server_random);
+
+ The iv_block is partitioned into two initialization vectors as the
+ key_block was above:
+
+ client_write_IV[SecurityParameters.IV_size]
+ server_write_IV[SecurityParameters.IV_size]
+
+ Note that the PRF is used without a secret in this case: this just
+ means that the secret has a length of zero bytes and contributes
+ nothing to the hashing in the PRF.
+
+6.3.1. Export key generation example
+
+ TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 requires five random bytes for
+ each of the two encryption keys and 16 bytes for each of the MAC
+ keys, for a total of 42 bytes of key material. The PRF output is
+ stored in the key_block. The key_block is partitioned, and the write
+ keys are salted because this is an exportable encryption algorithm.
+
+ key_block = PRF(master_secret,
+ "key expansion",
+ server_random +
+ client_random)[0..41]
+ client_write_MAC_secret = key_block[0..15]
+ server_write_MAC_secret = key_block[16..31]
+ client_write_key = key_block[32..36]
+ server_write_key = key_block[37..41]
+
+
+
+
+Dierks & Allen Standards Track [Page 22]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ final_client_write_key = PRF(client_write_key,
+ "client write key",
+ client_random +
+ server_random)[0..15]
+ final_server_write_key = PRF(server_write_key,
+ "server write key",
+ client_random +
+ server_random)[0..15]
+
+ iv_block = PRF("", "IV block", client_random +
+ server_random)[0..15]
+ client_write_IV = iv_block[0..7]
+ server_write_IV = iv_block[8..15]
+
+7. The TLS Handshake Protocol
+
+ The TLS Handshake Protocol consists of a suite of three sub-protocols
+ which are used to allow peers to agree upon security parameters for
+ the record layer, authenticate themselves, instantiate negotiated
+ security parameters, and report error conditions to each other.
+
+ The Handshake Protocol is responsible for negotiating a session,
+ which consists of the following items:
+
+ session identifier
+ An arbitrary byte sequence chosen by the server to identify an
+ active or resumable session state.
+
+ peer certificate
+ X509v3 [X509] certificate of the peer. This element of the state
+ may be null.
+
+ compression method
+ The algorithm used to compress data prior to encryption.
+
+ cipher spec
+ Specifies the bulk data encryption algorithm (such as null, DES,
+ etc.) and a MAC algorithm (such as MD5 or SHA). It also defines
+ cryptographic attributes such as the hash_size. (See Appendix A.6
+ for formal definition)
+
+ master secret
+ 48-byte secret shared between the client and server.
+
+ is resumable
+ A flag indicating whether the session can be used to initiate new
+ connections.
+
+
+
+
+Dierks & Allen Standards Track [Page 23]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ These items are then used to create security parameters for use by
+ the Record Layer when protecting application data. Many connections
+ can be instantiated using the same session through the resumption
+ feature of the TLS Handshake Protocol.
+
+7.1. Change cipher spec protocol
+
+ The change cipher spec protocol exists to signal transitions in
+ ciphering strategies. The protocol consists of a single message,
+ which is encrypted and compressed under the current (not the pending)
+ connection state. The message consists of a single byte of value 1.
+
+ struct {
+ enum { change_cipher_spec(1), (255) } type;
+ } ChangeCipherSpec;
+
+ The change cipher spec message is sent by both the client and server
+ to notify the receiving party that subsequent records will be
+ protected under the newly negotiated CipherSpec and keys. Reception
+ of this message causes the receiver to instruct the Record Layer to
+ immediately copy the read pending state into the read current state.
+ Immediately after sending this message, the sender should instruct
+ the record layer to make the write pending state the write active
+ state. (See section 6.1.) The change cipher spec message is sent
+ during the handshake after the security parameters have been agreed
+ upon, but before the verifying finished message is sent (see section
+ 7.4.9).
+
+7.2. Alert protocol
+
+ One of the content types supported by the TLS Record layer is the
+ alert type. Alert messages convey the severity of the message and a
+ description of the alert. Alert messages with a level of fatal result
+ in the immediate termination of the connection. In this case, other
+ connections corresponding to the session may continue, but the
+ session identifier must be invalidated, preventing the failed session
+ from being used to establish new connections. Like other messages,
+ alert messages are encrypted and compressed, as specified by the
+ current connection state.
+
+ enum { warning(1), fatal(2), (255) } AlertLevel;
+
+ enum {
+ close_notify(0),
+ unexpected_message(10),
+ bad_record_mac(20),
+ decryption_failed(21),
+ record_overflow(22),
+
+
+
+Dierks & Allen Standards Track [Page 24]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ decompression_failure(30),
+ handshake_failure(40),
+ bad_certificate(42),
+ unsupported_certificate(43),
+ certificate_revoked(44),
+ certificate_expired(45),
+ certificate_unknown(46),
+ illegal_parameter(47),
+ unknown_ca(48),
+ access_denied(49),
+ decode_error(50),
+ decrypt_error(51),
+ export_restriction(60),
+ protocol_version(70),
+ insufficient_security(71),
+ internal_error(80),
+ user_canceled(90),
+ no_renegotiation(100),
+ (255)
+ } AlertDescription;
+
+ struct {
+ AlertLevel level;
+ AlertDescription description;
+ } Alert;
+
+7.2.1. Closure alerts
+
+ The client and the server must share knowledge that the connection is
+ ending in order to avoid a truncation attack. Either party may
+ initiate the exchange of closing messages.
+
+ close_notify
+ This message notifies the recipient that the sender will not send
+ any more messages on this connection. The session becomes
+ unresumable if any connection is terminated without proper
+ close_notify messages with level equal to warning.
+
+ Either party may initiate a close by sending a close_notify alert.
+ Any data received after a closure alert is ignored.
+
+ Each party is required to send a close_notify alert before closing
+ the write side of the connection. It is required that the other party
+ respond with a close_notify alert of its own and close down the
+ connection immediately, discarding any pending writes. It is not
+ required for the initiator of the close to wait for the responding
+ close_notify alert before closing the read side of the connection.
+
+
+
+
+Dierks & Allen Standards Track [Page 25]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ If the application protocol using TLS provides that any data may be
+ carried over the underlying transport after the TLS connection is
+ closed, the TLS implementation must receive the responding
+ close_notify alert before indicating to the application layer that
+ the TLS connection has ended. If the application protocol will not
+ transfer any additional data, but will only close the underlying
+ transport connection, then the implementation may choose to close the
+ transport without waiting for the responding close_notify. No part of
+ this standard should be taken to dictate the manner in which a usage
+ profile for TLS manages its data transport, including when
+ connections are opened or closed.
+
+ NB: It is assumed that closing a connection reliably delivers
+ pending data before destroying the transport.
+
+7.2.2. Error alerts
+
+ Error handling in the TLS Handshake protocol is very simple. When an
+ error is detected, the detecting party sends a message to the other
+ party. Upon transmission or receipt of an fatal alert message, both
+ parties immediately close the connection. Servers and clients are
+ required to forget any session-identifiers, keys, and secrets
+ associated with a failed connection. The following error alerts are
+ defined:
+
+ unexpected_message
+ An inappropriate message was received. This alert is always fatal
+ and should never be observed in communication between proper
+ implementations.
+
+ bad_record_mac
+ This alert is returned if a record is received with an incorrect
+ MAC. This message is always fatal.
+
+ decryption_failed
+ A TLSCiphertext decrypted in an invalid way: either it wasn`t an
+ even multiple of the block length or its padding values, when
+ checked, weren`t correct. This message is always fatal.
+
+ record_overflow
+ A TLSCiphertext record was received which had a length more than
+ 2^14+2048 bytes, or a record decrypted to a TLSCompressed record
+ with more than 2^14+1024 bytes. This message is always fatal.
+
+ decompression_failure
+ The decompression function received improper input (e.g. data
+ that would expand to excessive length). This message is always
+ fatal.
+
+
+
+Dierks & Allen Standards Track [Page 26]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ handshake_failure
+ Reception of a handshake_failure alert message indicates that the
+ sender was unable to negotiate an acceptable set of security
+ parameters given the options available. This is a fatal error.
+
+ bad_certificate
+ A certificate was corrupt, contained signatures that did not
+ verify correctly, etc.
+
+ unsupported_certificate
+ A certificate was of an unsupported type.
+
+ certificate_revoked
+ A certificate was revoked by its signer.
+
+ certificate_expired
+ A certificate has expired or is not currently valid.
+
+ certificate_unknown
+ Some other (unspecified) issue arose in processing the
+ certificate, rendering it unacceptable.
+
+ illegal_parameter
+ A field in the handshake was out of range or inconsistent with
+ other fields. This is always fatal.
+
+ unknown_ca
+ A valid certificate chain or partial chain was received, but the
+ certificate was not accepted because the CA certificate could not
+ be located or couldn`t be matched with a known, trusted CA. This
+ message is always fatal.
+
+ access_denied
+ A valid certificate was received, but when access control was
+ applied, the sender decided not to proceed with negotiation.
+ This message is always fatal.
+
+ decode_error
+ A message could not be decoded because some field was out of the
+ specified range or the length of the message was incorrect. This
+ message is always fatal.
+
+ decrypt_error
+ A handshake cryptographic operation failed, including being
+ unable to correctly verify a signature, decrypt a key exchange,
+ or validate a finished message.
+
+
+
+
+
+Dierks & Allen Standards Track [Page 27]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ export_restriction
+ A negotiation not in compliance with export restrictions was
+ detected; for example, attempting to transfer a 1024 bit
+ ephemeral RSA key for the RSA_EXPORT handshake method. This
+ message is always fatal.
+
+ protocol_version
+ The protocol version the client has attempted to negotiate is
+ recognized, but not supported. (For example, old protocol
+ versions might be avoided for security reasons). This message is
+ always fatal.
+
+ insufficient_security
+ Returned instead of handshake_failure when a negotiation has
+ failed specifically because the server requires ciphers more
+ secure than those supported by the client. This message is always
+ fatal.
+
+ internal_error
+ An internal error unrelated to the peer or the correctness of the
+ protocol makes it impossible to continue (such as a memory
+ allocation failure). This message is always fatal.
+
+ user_canceled
+ This handshake is being canceled for some reason unrelated to a
+ protocol failure. If the user cancels an operation after the
+ handshake is complete, just closing the connection by sending a
+ close_notify is more appropriate. This alert should be followed
+ by a close_notify. This message is generally a warning.
+
+ no_renegotiation
+ Sent by the client in response to a hello request or by the
+ server in response to a client hello after initial handshaking.
+ Either of these would normally lead to renegotiation; when that
+ is not appropriate, the recipient should respond with this alert;
+ at that point, the original requester can decide whether to
+ proceed with the connection. One case where this would be
+ appropriate would be where a server has spawned a process to
+ satisfy a request; the process might receive security parameters
+ (key length, authentication, etc.) at startup and it might be
+ difficult to communicate changes to these parameters after that
+ point. This message is always a warning.
+
+ For all errors where an alert level is not explicitly specified, the
+ sending party may determine at its discretion whether this is a fatal
+ error or not; if an alert with a level of warning is received, the
+
+
+
+
+
+Dierks & Allen Standards Track [Page 28]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ receiving party may decide at its discretion whether to treat this as
+ a fatal error or not. However, all messages which are transmitted
+ with a level of fatal must be treated as fatal messages.
+
+7.3. Handshake Protocol overview
+
+ The cryptographic parameters of the session state are produced by the
+ TLS Handshake Protocol, which operates on top of the TLS Record
+ Layer. When a TLS client and server first start communicating, they
+ agree on a protocol version, select cryptographic algorithms,
+ optionally authenticate each other, and use public-key encryption
+ techniques to generate shared secrets.
+
+ The TLS Handshake Protocol involves the following steps:
+
+ - Exchange hello messages to agree on algorithms, exchange random
+ values, and check for session resumption.
+
+ - Exchange the necessary cryptographic parameters to allow the
+ client and server to agree on a premaster secret.
+
+ - Exchange certificates and cryptographic information to allow the
+ client and server to authenticate themselves.
+
+ - Generate a master secret from the premaster secret and exchanged
+ random values.
+
+ - Provide security parameters to the record layer.
+
+ - Allow the client and server to verify that their peer has
+ calculated the same security parameters and that the handshake
+ occurred without tampering by an attacker.
+
+ Note that higher layers should not be overly reliant on TLS always
+ negotiating the strongest possible connection between two peers:
+ there are a number of ways a man in the middle attacker can attempt
+ to make two entities drop down to the least secure method they
+ support. The protocol has been designed to minimize this risk, but
+ there are still attacks available: for example, an attacker could
+ block access to the port a secure service runs on, or attempt to get
+ the peers to negotiate an unauthenticated connection. The fundamental
+ rule is that higher levels must be cognizant of what their security
+ requirements are and never transmit information over a channel less
+ secure than what they require. The TLS protocol is secure, in that
+ any cipher suite offers its promised level of security: if you
+ negotiate 3DES with a 1024 bit RSA key exchange with a host whose
+ certificate you have verified, you can expect to be that secure.
+
+
+
+
+Dierks & Allen Standards Track [Page 29]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ However, you should never send data over a link encrypted with 40 bit
+ security unless you feel that data is worth no more than the effort
+ required to break that encryption.
+
+ These goals are achieved by the handshake protocol, which can be
+ summarized as follows: The client sends a client hello message to
+ which the server must respond with a server hello message, or else a
+ fatal error will occur and the connection will fail. The client hello
+ and server hello are used to establish security enhancement
+ capabilities between client and server. The client hello and server
+ hello establish the following attributes: Protocol Version, Session
+ ID, Cipher Suite, and Compression Method. Additionally, two random
+ values are generated and exchanged: ClientHello.random and
+ ServerHello.random.
+
+ The actual key exchange uses up to four messages: the server
+ certificate, the server key exchange, the client certificate, and the
+ client key exchange. New key exchange methods can be created by
+ specifying a format for these messages and defining the use of the
+ messages to allow the client and server to agree upon a shared
+ secret. This secret should be quite long; currently defined key
+ exchange methods exchange secrets which range from 48 to 128 bytes in
+ length.
+
+ Following the hello messages, the server will send its certificate,
+ if it is to be authenticated. Additionally, a server key exchange
+ message may be sent, if it is required (e.g. if their server has no
+ certificate, or if its certificate is for signing only). If the
+ server is authenticated, it may request a certificate from the
+ client, if that is appropriate to the cipher suite selected. Now the
+ server will send the server hello done message, indicating that the
+ hello-message phase of the handshake is complete. The server will
+ then wait for a client response. If the server has sent a certificate
+ request message, the client must send the certificate message. The
+ client key exchange message is now sent, and the content of that
+ message will depend on the public key algorithm selected between the
+ client hello and the server hello. If the client has sent a
+ certificate with signing ability, a digitally-signed certificate
+ verify message is sent to explicitly verify the certificate.
+
+ At this point, a change cipher spec message is sent by the client,
+ and the client copies the pending Cipher Spec into the current Cipher
+ Spec. The client then immediately sends the finished message under
+ the new algorithms, keys, and secrets. In response, the server will
+ send its own change cipher spec message, transfer the pending to the
+ current Cipher Spec, and send its finished message under the new
+
+
+
+
+
+Dierks & Allen Standards Track [Page 30]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Cipher Spec. At this point, the handshake is complete and the client
+ and server may begin to exchange application layer data. (See flow
+ chart below.)
+
+ Client Server
+
+ ClientHello -------->
+ ServerHello
+ Certificate*
+ ServerKeyExchange*
+ CertificateRequest*
+ <-------- ServerHelloDone
+ Certificate*
+ ClientKeyExchange
+ CertificateVerify*
+ [ChangeCipherSpec]
+ Finished -------->
+ [ChangeCipherSpec]
+ <-------- Finished
+ Application Data <-------> Application Data
+
+ Fig. 1 - Message flow for a full handshake
+
+ * Indicates optional or situation-dependent messages that are not
+ always sent.
+
+ Note: To help avoid pipeline stalls, ChangeCipherSpec is an
+ independent TLS Protocol content type, and is not actually a TLS
+ handshake message.
+
+ When the client and server decide to resume a previous session or
+ duplicate an existing session (instead of negotiating new security
+ parameters) the message flow is as follows:
+
+ The client sends a ClientHello using the Session ID of the session to
+ be resumed. The server then checks its session cache for a match. If
+ a match is found, and the server is willing to re-establish the
+ connection under the specified session state, it will send a
+ ServerHello with the same Session ID value. At this point, both
+ client and server must send change cipher spec messages and proceed
+ directly to finished messages. Once the re-establishment is complete,
+ the client and server may begin to exchange application layer data.
+ (See flow chart below.) If a Session ID match is not found, the
+ server generates a new session ID and the TLS client and server
+ perform a full handshake.
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 31]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Client Server
+
+ ClientHello -------->
+ ServerHello
+ [ChangeCipherSpec]
+ <-------- Finished
+ [ChangeCipherSpec]
+ Finished -------->
+ Application Data <-------> Application Data
+
+ Fig. 2 - Message flow for an abbreviated handshake
+
+ The contents and significance of each message will be presented in
+ detail in the following sections.
+
+7.4. Handshake protocol
+
+ The TLS Handshake Protocol is one of the defined higher level clients
+ of the TLS Record Protocol. This protocol is used to negotiate the
+ secure attributes of a session. Handshake messages are supplied to
+ the TLS Record Layer, where they are encapsulated within one or more
+ TLSPlaintext structures, which are processed and transmitted as
+ specified by the current active session state.
+
+ enum {
+ hello_request(0), client_hello(1), server_hello(2),
+ certificate(11), server_key_exchange (12),
+ certificate_request(13), server_hello_done(14),
+ certificate_verify(15), client_key_exchange(16),
+ finished(20), (255)
+ } HandshakeType;
+
+ struct {
+ HandshakeType msg_type; /* handshake type */
+ uint24 length; /* bytes in message */
+ select (HandshakeType) {
+ case hello_request: HelloRequest;
+ case client_hello: ClientHello;
+ case server_hello: ServerHello;
+ case certificate: Certificate;
+ case server_key_exchange: ServerKeyExchange;
+ case certificate_request: CertificateRequest;
+ case server_hello_done: ServerHelloDone;
+ case certificate_verify: CertificateVerify;
+ case client_key_exchange: ClientKeyExchange;
+ case finished: Finished;
+ } body;
+ } Handshake;
+
+
+
+Dierks & Allen Standards Track [Page 32]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ The handshake protocol messages are presented below in the order they
+ must be sent; sending handshake messages in an unexpected order
+ results in a fatal error. Unneeded handshake messages can be omitted,
+ however. Note one exception to the ordering: the Certificate message
+ is used twice in the handshake (from server to client, then from
+ client to server), but described only in its first position. The one
+ message which is not bound by these ordering rules in the Hello
+ Request message, which can be sent at any time, but which should be
+ ignored by the client if it arrives in the middle of a handshake.
+
+7.4.1. Hello messages
+
+ The hello phase messages are used to exchange security enhancement
+ capabilities between the client and server. When a new session
+ begins, the Record Layer's connection state encryption, hash, and
+ compression algorithms are initialized to null. The current
+ connection state is used for renegotiation messages.
+
+7.4.1.1. Hello request
+
+ When this message will be sent:
+ The hello request message may be sent by the server at any time.
+
+ Meaning of this message:
+ Hello request is a simple notification that the client should
+ begin the negotiation process anew by sending a client hello
+ message when convenient. This message will be ignored by the
+ client if the client is currently negotiating a session. This
+ message may be ignored by the client if it does not wish to
+ renegotiate a session, or the client may, if it wishes, respond
+ with a no_renegotiation alert. Since handshake messages are
+ intended to have transmission precedence over application data,
+ it is expected that the negotiation will begin before no more
+ than a few records are received from the client. If the server
+ sends a hello request but does not receive a client hello in
+ response, it may close the connection with a fatal alert.
+
+ After sending a hello request, servers should not repeat the request
+ until the subsequent handshake negotiation is complete.
+
+ Structure of this message:
+ struct { } HelloRequest;
+
+ Note: This message should never be included in the message hashes which
+ are maintained throughout the handshake and used in the finished
+ messages and the certificate verify message.
+
+
+
+
+
+Dierks & Allen Standards Track [Page 33]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+7.4.1.2. Client hello
+
+ When this message will be sent:
+ When a client first connects to a server it is required to send
+ the client hello as its first message. The client can also send a
+ client hello in response to a hello request or on its own
+ initiative in order to renegotiate the security parameters in an
+ existing connection.
+
+ Structure of this message:
+ The client hello message includes a random structure, which is
+ used later in the protocol.
+
+ struct {
+ uint32 gmt_unix_time;
+ opaque random_bytes[28];
+ } Random;
+
+ gmt_unix_time
+ The current time and date in standard UNIX 32-bit format (seconds
+ since the midnight starting Jan 1, 1970, GMT) according to the
+ sender's internal clock. Clocks are not required to be set
+ correctly by the basic TLS Protocol; higher level or application
+ protocols may define additional requirements.
+
+ random_bytes
+ 28 bytes generated by a secure random number generator.
+
+ The client hello message includes a variable length session
+ identifier. If not empty, the value identifies a session between the
+ same client and server whose security parameters the client wishes to
+ reuse. The session identifier may be from an earlier connection, this
+ connection, or another currently active connection. The second option
+ is useful if the client only wishes to update the random structures
+ and derived values of a connection, while the third option makes it
+ possible to establish several independent secure connections without
+ repeating the full handshake protocol. These independent connections
+ may occur sequentially or simultaneously; a SessionID becomes valid
+ when the handshake negotiating it completes with the exchange of
+ Finished messages and persists until removed due to aging or because
+ a fatal error was encountered on a connection associated with the
+ session. The actual contents of the SessionID are defined by the
+ server.
+
+ opaque SessionID<0..32>;
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 34]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Warning:
+ Because the SessionID is transmitted without encryption or
+ immediate MAC protection, servers must not place confidential
+ information in session identifiers or let the contents of fake
+ session identifiers cause any breach of security. (Note that the
+ content of the handshake as a whole, including the SessionID, is
+ protected by the Finished messages exchanged at the end of the
+ handshake.)
+
+ The CipherSuite list, passed from the client to the server in the
+ client hello message, contains the combinations of cryptographic
+ algorithms supported by the client in order of the client's
+ preference (favorite choice first). Each CipherSuite defines a key
+ exchange algorithm, a bulk encryption algorithm (including secret key
+ length) and a MAC algorithm. The server will select a cipher suite
+ or, if no acceptable choices are presented, return a handshake
+ failure alert and close the connection.
+
+ uint8 CipherSuite[2]; /* Cryptographic suite selector */
+
+ The client hello includes a list of compression algorithms supported
+ by the client, ordered according to the client's preference.
+
+ enum { null(0), (255) } CompressionMethod;
+
+ struct {
+ ProtocolVersion client_version;
+ Random random;
+ SessionID session_id;
+ CipherSuite cipher_suites<2..2^16-1>;
+ CompressionMethod compression_methods<1..2^8-1>;
+ } ClientHello;
+
+ client_version
+ The version of the TLS protocol by which the client wishes to
+ communicate during this session. This should be the latest
+ (highest valued) version supported by the client. For this
+ version of the specification, the version will be 3.1 (See
+ Appendix E for details about backward compatibility).
+
+ random
+ A client-generated random structure.
+
+ session_id
+ The ID of a session the client wishes to use for this connection.
+ This field should be empty if no session_id is available or the
+ client wishes to generate new security parameters.
+
+
+
+
+Dierks & Allen Standards Track [Page 35]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ cipher_suites
+ This is a list of the cryptographic options supported by the
+ client, with the client's first preference first. If the
+ session_id field is not empty (implying a session resumption
+ request) this vector must include at least the cipher_suite from
+ that session. Values are defined in Appendix A.5.
+
+ compression_methods
+ This is a list of the compression methods supported by the
+ client, sorted by client preference. If the session_id field is
+ not empty (implying a session resumption request) it must include
+ the compression_method from that session. This vector must
+ contain, and all implementations must support,
+ CompressionMethod.null. Thus, a client and server will always be
+ able to agree on a compression method.
+
+ After sending the client hello message, the client waits for a server
+ hello message. Any other handshake message returned by the server
+ except for a hello request is treated as a fatal error.
+
+ Forward compatibility note:
+ In the interests of forward compatibility, it is permitted for a
+ client hello message to include extra data after the compression
+ methods. This data must be included in the handshake hashes, but
+ must otherwise be ignored. This is the only handshake message for
+ which this is legal; for all other messages, the amount of data
+ in the message must match the description of the message
+ precisely.
+
+7.4.1.3. Server hello
+
+ When this message will be sent:
+ The server will send this message in response to a client hello
+ message when it was able to find an acceptable set of algorithms.
+ If it cannot find such a match, it will respond with a handshake
+ failure alert.
+
+ Structure of this message:
+ struct {
+ ProtocolVersion server_version;
+ Random random;
+ SessionID session_id;
+ CipherSuite cipher_suite;
+ CompressionMethod compression_method;
+ } ServerHello;
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 36]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ server_version
+ This field will contain the lower of that suggested by the client
+ in the client hello and the highest supported by the server. For
+ this version of the specification, the version is 3.1 (See
+ Appendix E for details about backward compatibility).
+
+ random
+ This structure is generated by the server and must be different
+ from (and independent of) ClientHello.random.
+
+ session_id
+ This is the identity of the session corresponding to this
+ connection. If the ClientHello.session_id was non-empty, the
+ server will look in its session cache for a match. If a match is
+ found and the server is willing to establish the new connection
+ using the specified session state, the server will respond with
+ the same value as was supplied by the client. This indicates a
+ resumed session and dictates that the parties must proceed
+ directly to the finished messages. Otherwise this field will
+ contain a different value identifying the new session. The server
+ may return an empty session_id to indicate that the session will
+ not be cached and therefore cannot be resumed. If a session is
+ resumed, it must be resumed using the same cipher suite it was
+ originally negotiated with.
+
+ cipher_suite
+ The single cipher suite selected by the server from the list in
+ ClientHello.cipher_suites. For resumed sessions this field is the
+ value from the state of the session being resumed.
+
+ compression_method
+ The single compression algorithm selected by the server from the
+ list in ClientHello.compression_methods. For resumed sessions
+ this field is the value from the resumed session state.
+
+7.4.2. Server certificate
+
+ When this message will be sent:
+ The server must send a certificate whenever the agreed-upon key
+ exchange method is not an anonymous one. This message will always
+ immediately follow the server hello message.
+
+ Meaning of this message:
+ The certificate type must be appropriate for the selected cipher
+ suite's key exchange algorithm, and is generally an X.509v3
+ certificate. It must contain a key which matches the key exchange
+ method, as follows. Unless otherwise specified, the signing
+
+
+
+
+Dierks & Allen Standards Track [Page 37]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ algorithm for the certificate must be the same as the algorithm
+ for the certificate key. Unless otherwise specified, the public
+ key may be of any length.
+
+ Key Exchange Algorithm Certificate Key Type
+
+ RSA RSA public key; the certificate must
+ allow the key to be used for encryption.
+
+ RSA_EXPORT RSA public key of length greater than
+ 512 bits which can be used for signing,
+ or a key of 512 bits or shorter which
+ can be used for either encryption or
+ signing.
+
+ DHE_DSS DSS public key.
+
+ DHE_DSS_EXPORT DSS public key.
+
+ DHE_RSA RSA public key which can be used for
+ signing.
+
+ DHE_RSA_EXPORT RSA public key which can be used for
+ signing.
+
+ DH_DSS Diffie-Hellman key. The algorithm used
+ to sign the certificate should be DSS.
+
+ DH_RSA Diffie-Hellman key. The algorithm used
+ to sign the certificate should be RSA.
+
+ All certificate profiles, key and cryptographic formats are defined
+ by the IETF PKIX working group [PKIX]. When a key usage extension is
+ present, the digitalSignature bit must be set for the key to be
+ eligible for signing, as described above, and the keyEncipherment bit
+ must be present to allow encryption, as described above. The
+ keyAgreement bit must be set on Diffie-Hellman certificates.
+
+ As CipherSuites which specify new key exchange methods are specified
+ for the TLS Protocol, they will imply certificate format and the
+ required encoded keying information.
+
+ Structure of this message:
+ opaque ASN.1Cert<1..2^24-1>;
+
+ struct {
+ ASN.1Cert certificate_list<0..2^24-1>;
+ } Certificate;
+
+
+
+Dierks & Allen Standards Track [Page 38]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ certificate_list
+ This is a sequence (chain) of X.509v3 certificates. The sender's
+ certificate must come first in the list. Each following
+ certificate must directly certify the one preceding it. Because
+ certificate validation requires that root keys be distributed
+ independently, the self-signed certificate which specifies the
+ root certificate authority may optionally be omitted from the
+ chain, under the assumption that the remote end must already
+ possess it in order to validate it in any case.
+
+ The same message type and structure will be used for the client's
+ response to a certificate request message. Note that a client may
+ send no certificates if it does not have an appropriate certificate
+ to send in response to the server's authentication request.
+
+ Note: PKCS #7 [PKCS7] is not used as the format for the certificate
+ vector because PKCS #6 [PKCS6] extended certificates are not
+ used. Also PKCS #7 defines a SET rather than a SEQUENCE, making
+ the task of parsing the list more difficult.
+
+7.4.3. Server key exchange message
+
+ When this message will be sent:
+ This message will be sent immediately after the server
+ certificate message (or the server hello message, if this is an
+ anonymous negotiation).
+
+ The server key exchange message is sent by the server only when
+ the server certificate message (if sent) does not contain enough
+ data to allow the client to exchange a premaster secret. This is
+ true for the following key exchange methods:
+
+ RSA_EXPORT (if the public key in the server certificate is
+ longer than 512 bits)
+ DHE_DSS
+ DHE_DSS_EXPORT
+ DHE_RSA
+ DHE_RSA_EXPORT
+ DH_anon
+
+ It is not legal to send the server key exchange message for the
+ following key exchange methods:
+
+ RSA
+ RSA_EXPORT (when the public key in the server certificate is
+ less than or equal to 512 bits in length)
+ DH_DSS
+ DH_RSA
+
+
+
+Dierks & Allen Standards Track [Page 39]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Meaning of this message:
+ This message conveys cryptographic information to allow the
+ client to communicate the premaster secret: either an RSA public
+ key to encrypt the premaster secret with, or a Diffie-Hellman
+ public key with which the client can complete a key exchange
+ (with the result being the premaster secret.)
+
+ As additional CipherSuites are defined for TLS which include new key
+ exchange algorithms, the server key exchange message will be sent if
+ and only if the certificate type associated with the key exchange
+ algorithm does not provide enough information for the client to
+ exchange a premaster secret.
+
+ Note: According to current US export law, RSA moduli larger than 512
+ bits may not be used for key exchange in software exported from
+ the US. With this message, the larger RSA keys encoded in
+ certificates may be used to sign temporary shorter RSA keys for
+ the RSA_EXPORT key exchange method.
+
+ Structure of this message:
+ enum { rsa, diffie_hellman } KeyExchangeAlgorithm;
+
+ struct {
+ opaque rsa_modulus<1..2^16-1>;
+ opaque rsa_exponent<1..2^16-1>;
+ } ServerRSAParams;
+
+ rsa_modulus
+ The modulus of the server's temporary RSA key.
+
+ rsa_exponent
+ The public exponent of the server's temporary RSA key.
+
+ struct {
+ opaque dh_p<1..2^16-1>;
+ opaque dh_g<1..2^16-1>;
+ opaque dh_Ys<1..2^16-1>;
+ } ServerDHParams; /* Ephemeral DH parameters */
+
+ dh_p
+ The prime modulus used for the Diffie-Hellman operation.
+
+ dh_g
+ The generator used for the Diffie-Hellman operation.
+
+ dh_Ys
+ The server's Diffie-Hellman public value (g^X mod p).
+
+
+
+
+Dierks & Allen Standards Track [Page 40]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ struct {
+ select (KeyExchangeAlgorithm) {
+ case diffie_hellman:
+ ServerDHParams params;
+ Signature signed_params;
+ case rsa:
+ ServerRSAParams params;
+ Signature signed_params;
+ };
+ } ServerKeyExchange;
+
+ params
+ The server's key exchange parameters.
+
+ signed_params
+ For non-anonymous key exchanges, a hash of the corresponding
+ params value, with the signature appropriate to that hash
+ applied.
+
+ md5_hash
+ MD5(ClientHello.random + ServerHello.random + ServerParams);
+
+ sha_hash
+ SHA(ClientHello.random + ServerHello.random + ServerParams);
+
+ enum { anonymous, rsa, dsa } SignatureAlgorithm;
+
+ select (SignatureAlgorithm)
+ { case anonymous: struct { };
+ case rsa:
+ digitally-signed struct {
+ opaque md5_hash[16];
+ opaque sha_hash[20];
+ };
+ case dsa:
+ digitally-signed struct {
+ opaque sha_hash[20];
+ };
+ } Signature;
+
+7.4.4. Certificate request
+
+ When this message will be sent:
+ A non-anonymous server can optionally request a certificate from
+ the client, if appropriate for the selected cipher suite. This
+ message, if sent, will immediately follow the Server Key Exchange
+ message (if it is sent; otherwise, the Server Certificate
+ message).
+
+
+
+Dierks & Allen Standards Track [Page 41]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Structure of this message:
+ enum {
+ rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
+ (255)
+ } ClientCertificateType;
+
+ opaque DistinguishedName<1..2^16-1>;
+
+ struct {
+ ClientCertificateType certificate_types<1..2^8-1>;
+ DistinguishedName certificate_authorities<3..2^16-1>;
+ } CertificateRequest;
+
+ certificate_types
+ This field is a list of the types of certificates requested,
+ sorted in order of the server's preference.
+
+ certificate_authorities
+ A list of the distinguished names of acceptable certificate
+ authorities. These distinguished names may specify a desired
+ distinguished name for a root CA or for a subordinate CA;
+ thus, this message can be used both to describe known roots
+ and a desired authorization space.
+
+ Note: DistinguishedName is derived from [X509].
+
+ Note: It is a fatal handshake_failure alert for an anonymous server to
+ request client identification.
+
+7.4.5. Server hello done
+
+ When this message will be sent:
+ The server hello done message is sent by the server to indicate
+ the end of the server hello and associated messages. After
+ sending this message the server will wait for a client response.
+
+ Meaning of this message:
+ This message means that the server is done sending messages to
+ support the key exchange, and the client can proceed with its
+ phase of the key exchange.
+
+ Upon receipt of the server hello done message the client should
+ verify that the server provided a valid certificate if required
+ and check that the server hello parameters are acceptable.
+
+ Structure of this message:
+ struct { } ServerHelloDone;
+
+
+
+
+Dierks & Allen Standards Track [Page 42]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+7.4.6. Client certificate
+
+ When this message will be sent:
+ This is the first message the client can send after receiving a
+ server hello done message. This message is only sent if the
+ server requests a certificate. If no suitable certificate is
+ available, the client should send a certificate message
+ containing no certificates. If client authentication is required
+ by the server for the handshake to continue, it may respond with
+ a fatal handshake failure alert. Client certificates are sent
+ using the Certificate structure defined in Section 7.4.2.
+
+ Note: When using a static Diffie-Hellman based key exchange method
+ (DH_DSS or DH_RSA), if client authentication is requested, the
+ Diffie-Hellman group and generator encoded in the client's
+ certificate must match the server specified Diffie-Hellman
+ parameters if the client's parameters are to be used for the key
+ exchange.
+
+7.4.7. Client key exchange message
+
+ When this message will be sent:
+ This message is always sent by the client. It will immediately
+ follow the client certificate message, if it is sent. Otherwise
+ it will be the first message sent by the client after it receives
+ the server hello done message.
+
+ Meaning of this message:
+ With this message, the premaster secret is set, either though
+ direct transmission of the RSA-encrypted secret, or by the
+ transmission of Diffie-Hellman parameters which will allow each
+ side to agree upon the same premaster secret. When the key
+ exchange method is DH_RSA or DH_DSS, client certification has
+ been requested, and the client was able to respond with a
+ certificate which contained a Diffie-Hellman public key whose
+ parameters (group and generator) matched those specified by the
+ server in its certificate, this message will not contain any
+ data.
+
+ Structure of this message:
+ The choice of messages depends on which key exchange method has
+ been selected. See Section 7.4.3 for the KeyExchangeAlgorithm
+ definition.
+
+ struct {
+ select (KeyExchangeAlgorithm) {
+ case rsa: EncryptedPreMasterSecret;
+ case diffie_hellman: ClientDiffieHellmanPublic;
+
+
+
+Dierks & Allen Standards Track [Page 43]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ } exchange_keys;
+ } ClientKeyExchange;
+
+7.4.7.1. RSA encrypted premaster secret message
+
+ Meaning of this message:
+ If RSA is being used for key agreement and authentication, the
+ client generates a 48-byte premaster secret, encrypts it using
+ the public key from the server's certificate or the temporary RSA
+ key provided in a server key exchange message, and sends the
+ result in an encrypted premaster secret message. This structure
+ is a variant of the client key exchange message, not a message in
+ itself.
+
+ Structure of this message:
+ struct {
+ ProtocolVersion client_version;
+ opaque random[46];
+ } PreMasterSecret;
+
+ client_version
+ The latest (newest) version supported by the client. This is
+ used to detect version roll-back attacks. Upon receiving the
+ premaster secret, the server should check that this value
+ matches the value transmitted by the client in the client
+ hello message.
+
+ random
+ 46 securely-generated random bytes.
+
+ struct {
+ public-key-encrypted PreMasterSecret pre_master_secret;
+ } EncryptedPreMasterSecret;
+
+ Note: An attack discovered by Daniel Bleichenbacher [BLEI] can be used
+ to attack a TLS server which is using PKCS#1 encoded RSA. The
+ attack takes advantage of the fact that by failing in different
+ ways, a TLS server can be coerced into revealing whether a
+ particular message, when decrypted, is properly PKCS#1 formatted
+ or not.
+
+ The best way to avoid vulnerability to this attack is to treat
+ incorrectly formatted messages in a manner indistinguishable from
+ correctly formatted RSA blocks. Thus, when it receives an
+ incorrectly formatted RSA block, a server should generate a
+ random 48-byte value and proceed using it as the premaster
+ secret. Thus, the server will act identically whether the
+ received RSA block is correctly encoded or not.
+
+
+
+Dierks & Allen Standards Track [Page 44]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ pre_master_secret
+ This random value is generated by the client and is used to
+ generate the master secret, as specified in Section 8.1.
+
+7.4.7.2. Client Diffie-Hellman public value
+
+ Meaning of this message:
+ This structure conveys the client's Diffie-Hellman public value
+ (Yc) if it was not already included in the client's certificate.
+ The encoding used for Yc is determined by the enumerated
+ PublicValueEncoding. This structure is a variant of the client
+ key exchange message, not a message in itself.
+
+ Structure of this message:
+ enum { implicit, explicit } PublicValueEncoding;
+
+ implicit
+ If the client certificate already contains a suitable
+ Diffie-Hellman key, then Yc is implicit and does not need to
+ be sent again. In this case, the Client Key Exchange message
+ will be sent, but will be empty.
+
+ explicit
+ Yc needs to be sent.
+
+ struct {
+ select (PublicValueEncoding) {
+ case implicit: struct { };
+ case explicit: opaque dh_Yc<1..2^16-1>;
+ } dh_public;
+ } ClientDiffieHellmanPublic;
+
+ dh_Yc
+ The client's Diffie-Hellman public value (Yc).
+
+7.4.8. Certificate verify
+
+ When this message will be sent:
+ This message is used to provide explicit verification of a client
+ certificate. This message is only sent following a client
+ certificate that has signing capability (i.e. all certificates
+ except those containing fixed Diffie-Hellman parameters). When
+ sent, it will immediately follow the client key exchange message.
+
+ Structure of this message:
+ struct {
+ Signature signature;
+ } CertificateVerify;
+
+
+
+Dierks & Allen Standards Track [Page 45]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ The Signature type is defined in 7.4.3.
+
+ CertificateVerify.signature.md5_hash
+ MD5(handshake_messages);
+
+ Certificate.signature.sha_hash
+ SHA(handshake_messages);
+
+ Here handshake_messages refers to all handshake messages sent or
+ received starting at client hello up to but not including this
+ message, including the type and length fields of the handshake
+ messages. This is the concatenation of all the Handshake structures
+ as defined in 7.4 exchanged thus far.
+
+7.4.9. Finished
+
+ When this message will be sent:
+ A finished message is always sent immediately after a change
+ cipher spec message to verify that the key exchange and
+ authentication processes were successful. It is essential that a
+ change cipher spec message be received between the other
+ handshake messages and the Finished message.
+
+ Meaning of this message:
+ The finished message is the first protected with the just-
+ negotiated algorithms, keys, and secrets. Recipients of finished
+ messages must verify that the contents are correct. Once a side
+ has sent its Finished message and received and validated the
+ Finished message from its peer, it may begin to send and receive
+ application data over the connection.
+
+ struct {
+ opaque verify_data[12];
+ } Finished;
+
+ verify_data
+ PRF(master_secret, finished_label, MD5(handshake_messages) +
+ SHA-1(handshake_messages)) [0..11];
+
+ finished_label
+ For Finished messages sent by the client, the string "client
+ finished". For Finished messages sent by the server, the
+ string "server finished".
+
+ handshake_messages
+ All of the data from all handshake messages up to but not
+ including this message. This is only data visible at the
+ handshake layer and does not include record layer headers.
+
+
+
+Dierks & Allen Standards Track [Page 46]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ This is the concatenation of all the Handshake structures as
+ defined in 7.4 exchanged thus far.
+
+ It is a fatal error if a finished message is not preceded by a change
+ cipher spec message at the appropriate point in the handshake.
+
+ The hash contained in finished messages sent by the server
+ incorporate Sender.server; those sent by the client incorporate
+ Sender.client. The value handshake_messages includes all handshake
+ messages starting at client hello up to, but not including, this
+ finished message. This may be different from handshake_messages in
+ Section 7.4.8 because it would include the certificate verify message
+ (if sent). Also, the handshake_messages for the finished message sent
+ by the client will be different from that for the finished message
+ sent by the server, because the one which is sent second will include
+ the prior one.
+
+ Note: Change cipher spec messages, alerts and any other record types
+ are not handshake messages and are not included in the hash
+ computations. Also, Hello Request messages are omitted from
+ handshake hashes.
+
+8. Cryptographic computations
+
+ In order to begin connection protection, the TLS Record Protocol
+ requires specification of a suite of algorithms, a master secret, and
+ the client and server random values. The authentication, encryption,
+ and MAC algorithms are determined by the cipher_suite selected by the
+ server and revealed in the server hello message. The compression
+ algorithm is negotiated in the hello messages, and the random values
+ are exchanged in the hello messages. All that remains is to calculate
+ the master secret.
+
+8.1. Computing the master secret
+
+ For all key exchange methods, the same algorithm is used to convert
+ the pre_master_secret into the master_secret. The pre_master_secret
+ should be deleted from memory once the master_secret has been
+ computed.
+
+ master_secret = PRF(pre_master_secret, "master secret",
+ ClientHello.random + ServerHello.random)
+ [0..47];
+
+ The master secret is always exactly 48 bytes in length. The length of
+ the premaster secret will vary depending on key exchange method.
+
+
+
+
+
+Dierks & Allen Standards Track [Page 47]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+8.1.1. RSA
+
+ When RSA is used for server authentication and key exchange, a 48-
+ byte pre_master_secret is generated by the client, encrypted under
+ the server's public key, and sent to the server. The server uses its
+ private key to decrypt the pre_master_secret. Both parties then
+ convert the pre_master_secret into the master_secret, as specified
+ above.
+
+ RSA digital signatures are performed using PKCS #1 [PKCS1] block type
+ 1. RSA public key encryption is performed using PKCS #1 block type 2.
+
+8.1.2. Diffie-Hellman
+
+ A conventional Diffie-Hellman computation is performed. The
+ negotiated key (Z) is used as the pre_master_secret, and is converted
+ into the master_secret, as specified above.
+
+ Note: Diffie-Hellman parameters are specified by the server, and may
+ be either ephemeral or contained within the server's certificate.
+
+9. Mandatory Cipher Suites
+
+ In the absence of an application profile standard specifying
+ otherwise, a TLS compliant application MUST implement the cipher
+ suite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA.
+
+10. Application data protocol
+
+ Application data messages are carried by the Record Layer and are
+ fragmented, compressed and encrypted based on the current connection
+ state. The messages are treated as transparent data to the record
+ layer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 48]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+A. Protocol constant values
+
+ This section describes protocol types and constants.
+
+A.1. Record layer
+
+ struct {
+ uint8 major, minor;
+ } ProtocolVersion;
+
+ ProtocolVersion version = { 3, 1 }; /* TLS v1.0 */
+
+ enum {
+ change_cipher_spec(20), alert(21), handshake(22),
+ application_data(23), (255)
+ } ContentType;
+
+ struct {
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length;
+ opaque fragment[TLSPlaintext.length];
+ } TLSPlaintext;
+
+ struct {
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length;
+ opaque fragment[TLSCompressed.length];
+ } TLSCompressed;
+
+ struct {
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length;
+ select (CipherSpec.cipher_type) {
+ case stream: GenericStreamCipher;
+ case block: GenericBlockCipher;
+ } fragment;
+ } TLSCiphertext;
+
+ stream-ciphered struct {
+ opaque content[TLSCompressed.length];
+ opaque MAC[CipherSpec.hash_size];
+ } GenericStreamCipher;
+
+ block-ciphered struct {
+ opaque content[TLSCompressed.length];
+
+
+
+Dierks & Allen Standards Track [Page 49]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ opaque MAC[CipherSpec.hash_size];
+ uint8 padding[GenericBlockCipher.padding_length];
+ uint8 padding_length;
+ } GenericBlockCipher;
+
+A.2. Change cipher specs message
+
+ struct {
+ enum { change_cipher_spec(1), (255) } type;
+ } ChangeCipherSpec;
+
+A.3. Alert messages
+
+ enum { warning(1), fatal(2), (255) } AlertLevel;
+
+ enum {
+ close_notify(0),
+ unexpected_message(10),
+ bad_record_mac(20),
+ decryption_failed(21),
+ record_overflow(22),
+ decompression_failure(30),
+ handshake_failure(40),
+ bad_certificate(42),
+ unsupported_certificate(43),
+ certificate_revoked(44),
+ certificate_expired(45),
+ certificate_unknown(46),
+ illegal_parameter(47),
+ unknown_ca(48),
+ access_denied(49),
+ decode_error(50),
+ decrypt_error(51),
+ export_restriction(60),
+ protocol_version(70),
+ insufficient_security(71),
+ internal_error(80),
+ user_canceled(90),
+ no_renegotiation(100),
+ (255)
+ } AlertDescription;
+
+ struct {
+ AlertLevel level;
+ AlertDescription description;
+ } Alert;
+
+
+
+
+
+Dierks & Allen Standards Track [Page 50]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+A.4. Handshake protocol
+
+ enum {
+ hello_request(0), client_hello(1), server_hello(2),
+ certificate(11), server_key_exchange (12),
+ certificate_request(13), server_hello_done(14),
+ certificate_verify(15), client_key_exchange(16),
+ finished(20), (255)
+ } HandshakeType;
+
+ struct {
+ HandshakeType msg_type;
+ uint24 length;
+ select (HandshakeType) {
+ case hello_request: HelloRequest;
+ case client_hello: ClientHello;
+ case server_hello: ServerHello;
+ case certificate: Certificate;
+ case server_key_exchange: ServerKeyExchange;
+ case certificate_request: CertificateRequest;
+ case server_hello_done: ServerHelloDone;
+ case certificate_verify: CertificateVerify;
+ case client_key_exchange: ClientKeyExchange;
+ case finished: Finished;
+ } body;
+ } Handshake;
+
+A.4.1. Hello messages
+
+ struct { } HelloRequest;
+
+ struct {
+ uint32 gmt_unix_time;
+ opaque random_bytes[28];
+ } Random;
+
+ opaque SessionID<0..32>;
+
+ uint8 CipherSuite[2];
+
+ enum { null(0), (255) } CompressionMethod;
+
+ struct {
+ ProtocolVersion client_version;
+ Random random;
+ SessionID session_id;
+ CipherSuite cipher_suites<2..2^16-1>;
+ CompressionMethod compression_methods<1..2^8-1>;
+
+
+
+Dierks & Allen Standards Track [Page 51]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ } ClientHello;
+
+ struct {
+ ProtocolVersion server_version;
+ Random random;
+ SessionID session_id;
+ CipherSuite cipher_suite;
+ CompressionMethod compression_method;
+ } ServerHello;
+
+A.4.2. Server authentication and key exchange messages
+
+ opaque ASN.1Cert<2^24-1>;
+
+ struct {
+ ASN.1Cert certificate_list<1..2^24-1>;
+ } Certificate;
+
+ enum { rsa, diffie_hellman } KeyExchangeAlgorithm;
+
+ struct {
+ opaque RSA_modulus<1..2^16-1>;
+ opaque RSA_exponent<1..2^16-1>;
+ } ServerRSAParams;
+
+ struct {
+ opaque DH_p<1..2^16-1>;
+ opaque DH_g<1..2^16-1>;
+ opaque DH_Ys<1..2^16-1>;
+ } ServerDHParams;
+
+ struct {
+ select (KeyExchangeAlgorithm) {
+ case diffie_hellman:
+ ServerDHParams params;
+ Signature signed_params;
+ case rsa:
+ ServerRSAParams params;
+ Signature signed_params;
+ };
+ } ServerKeyExchange;
+
+ enum { anonymous, rsa, dsa } SignatureAlgorithm;
+
+ select (SignatureAlgorithm)
+ { case anonymous: struct { };
+ case rsa:
+ digitally-signed struct {
+
+
+
+Dierks & Allen Standards Track [Page 52]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ opaque md5_hash[16];
+ opaque sha_hash[20];
+ };
+ case dsa:
+ digitally-signed struct {
+ opaque sha_hash[20];
+ };
+ } Signature;
+
+ enum {
+ rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
+ (255)
+ } ClientCertificateType;
+
+ opaque DistinguishedName<1..2^16-1>;
+
+ struct {
+ ClientCertificateType certificate_types<1..2^8-1>;
+ DistinguishedName certificate_authorities<3..2^16-1>;
+ } CertificateRequest;
+
+ struct { } ServerHelloDone;
+
+A.4.3. Client authentication and key exchange messages
+
+ struct {
+ select (KeyExchangeAlgorithm) {
+ case rsa: EncryptedPreMasterSecret;
+ case diffie_hellman: DiffieHellmanClientPublicValue;
+ } exchange_keys;
+ } ClientKeyExchange;
+
+ struct {
+ ProtocolVersion client_version;
+ opaque random[46];
+
+ } PreMasterSecret;
+
+ struct {
+ public-key-encrypted PreMasterSecret pre_master_secret;
+ } EncryptedPreMasterSecret;
+
+ enum { implicit, explicit } PublicValueEncoding;
+
+ struct {
+ select (PublicValueEncoding) {
+ case implicit: struct {};
+ case explicit: opaque DH_Yc<1..2^16-1>;
+
+
+
+Dierks & Allen Standards Track [Page 53]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ } dh_public;
+ } ClientDiffieHellmanPublic;
+
+ struct {
+ Signature signature;
+ } CertificateVerify;
+
+A.4.4. Handshake finalization message
+
+ struct {
+ opaque verify_data[12];
+ } Finished;
+
+A.5. The CipherSuite
+
+ The following values define the CipherSuite codes used in the client
+ hello and server hello messages.
+
+ A CipherSuite defines a cipher specification supported in TLS Version
+ 1.0.
+
+ TLS_NULL_WITH_NULL_NULL is specified and is the initial state of a
+ TLS connection during the first handshake on that channel, but must
+ not be negotiated, as it provides no more protection than an
+ unsecured connection.
+
+ CipherSuite TLS_NULL_WITH_NULL_NULL = { 0x00,0x00 };
+
+ The following CipherSuite definitions require that the server provide
+ an RSA certificate that can be used for key exchange. The server may
+ request either an RSA or a DSS signature-capable certificate in the
+ certificate request message.
+
+ CipherSuite TLS_RSA_WITH_NULL_MD5 = { 0x00,0x01 };
+ CipherSuite TLS_RSA_WITH_NULL_SHA = { 0x00,0x02 };
+ CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 = { 0x00,0x03 };
+ CipherSuite TLS_RSA_WITH_RC4_128_MD5 = { 0x00,0x04 };
+ CipherSuite TLS_RSA_WITH_RC4_128_SHA = { 0x00,0x05 };
+ CipherSuite TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = { 0x00,0x06 };
+ CipherSuite TLS_RSA_WITH_IDEA_CBC_SHA = { 0x00,0x07 };
+ CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x08 };
+ CipherSuite TLS_RSA_WITH_DES_CBC_SHA = { 0x00,0x09 };
+ CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x0A };
+
+ The following CipherSuite definitions are used for server-
+ authenticated (and optionally client-authenticated) Diffie-Hellman.
+ DH denotes cipher suites in which the server's certificate contains
+ the Diffie-Hellman parameters signed by the certificate authority
+
+
+
+Dierks & Allen Standards Track [Page 54]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ (CA). DHE denotes ephemeral Diffie-Hellman, where the Diffie-Hellman
+ parameters are signed by a DSS or RSA certificate, which has been
+ signed by the CA. The signing algorithm used is specified after the
+ DH or DHE parameter. The server can request an RSA or DSS signature-
+ capable certificate from the client for client authentication or it
+ may request a Diffie-Hellman certificate. Any Diffie-Hellman
+ certificate provided by the client must use the parameters (group and
+ generator) described by the server.
+
+ CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x0B };
+ CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA = { 0x00,0x0C };
+ CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00,0x0D };
+ CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x0E };
+ CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA = { 0x00,0x0F };
+ CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x10 };
+ CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x11 };
+ CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA = { 0x00,0x12 };
+ CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00,0x13 };
+ CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x14 };
+ CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA = { 0x00,0x15 };
+ CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x16 };
+
+ The following cipher suites are used for completely anonymous
+ Diffie-Hellman communications in which neither party is
+ authenticated. Note that this mode is vulnerable to man-in-the-middle
+ attacks and is therefore deprecated.
+
+ CipherSuite TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = { 0x00,0x17 };
+ CipherSuite TLS_DH_anon_WITH_RC4_128_MD5 = { 0x00,0x18 };
+ CipherSuite TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x19 };
+ CipherSuite TLS_DH_anon_WITH_DES_CBC_SHA = { 0x00,0x1A };
+ CipherSuite TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = { 0x00,0x1B };
+
+ Note: All cipher suites whose first byte is 0xFF are considered
+ private and can be used for defining local/experimental
+ algorithms. Interoperability of such types is a local matter.
+
+ Note: Additional cipher suites can be registered by publishing an RFC
+ which specifies the cipher suites, including the necessary TLS
+ protocol information, including message encoding, premaster
+ secret derivation, symmetric encryption and MAC calculation and
+ appropriate reference information for the algorithms involved.
+ The RFC editor's office may, at its discretion, choose to publish
+ specifications for cipher suites which are not completely
+ described (e.g., for classified algorithms) if it finds the
+ specification to be of technical interest and completely
+ specified.
+
+
+
+
+Dierks & Allen Standards Track [Page 55]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Note: The cipher suite values { 0x00, 0x1C } and { 0x00, 0x1D } are
+ reserved to avoid collision with Fortezza-based cipher suites in
+ SSL 3.
+
+A.6. The Security Parameters
+
+ These security parameters are determined by the TLS Handshake
+ Protocol and provided as parameters to the TLS Record Layer in order
+ to initialize a connection state. SecurityParameters includes:
+
+ enum { null(0), (255) } CompressionMethod;
+
+ enum { server, client } ConnectionEnd;
+
+ enum { null, rc4, rc2, des, 3des, des40, idea }
+ BulkCipherAlgorithm;
+
+ enum { stream, block } CipherType;
+
+ enum { true, false } IsExportable;
+
+ enum { null, md5, sha } MACAlgorithm;
+
+ /* The algorithms specified in CompressionMethod,
+ BulkCipherAlgorithm, and MACAlgorithm may be added to. */
+
+ struct {
+ ConnectionEnd entity;
+ BulkCipherAlgorithm bulk_cipher_algorithm;
+ CipherType cipher_type;
+ uint8 key_size;
+ uint8 key_material_length;
+ IsExportable is_exportable;
+ MACAlgorithm mac_algorithm;
+ uint8 hash_size;
+ CompressionMethod compression_algorithm;
+ opaque master_secret[48];
+ opaque client_random[32];
+ opaque server_random[32];
+ } SecurityParameters;
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 56]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+B. Glossary
+
+ application protocol
+ An application protocol is a protocol that normally layers
+ directly on top of the transport layer (e.g., TCP/IP). Examples
+ include HTTP, TELNET, FTP, and SMTP.
+
+ asymmetric cipher
+ See public key cryptography.
+
+ authentication
+ Authentication is the ability of one entity to determine the
+ identity of another entity.
+
+ block cipher
+ A block cipher is an algorithm that operates on plaintext in
+ groups of bits, called blocks. 64 bits is a common block size.
+
+ bulk cipher
+ A symmetric encryption algorithm used to encrypt large quantities
+ of data.
+
+ cipher block chaining (CBC)
+ CBC is a mode in which every plaintext block encrypted with a
+ block cipher is first exclusive-ORed with the previous ciphertext
+ block (or, in the case of the first block, with the
+ initialization vector). For decryption, every block is first
+ decrypted, then exclusive-ORed with the previous ciphertext block
+ (or IV).
+
+ certificate
+ As part of the X.509 protocol (a.k.a. ISO Authentication
+ framework), certificates are assigned by a trusted Certificate
+ Authority and provide a strong binding between a party's identity
+ or some other attributes and its public key.
+
+ client
+ The application entity that initiates a TLS connection to a
+ server. This may or may not imply that the client initiated the
+ underlying transport connection. The primary operational
+ difference between the server and client is that the server is
+ generally authenticated, while the client is only optionally
+ authenticated.
+
+ client write key
+ The key used to encrypt data written by the client.
+
+
+
+
+
+Dierks & Allen Standards Track [Page 57]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ client write MAC secret
+ The secret data used to authenticate data written by the client.
+
+ connection
+ A connection is a transport (in the OSI layering model
+ definition) that provides a suitable type of service. For TLS,
+ such connections are peer to peer relationships. The connections
+ are transient. Every connection is associated with one session.
+
+ Data Encryption Standard
+ DES is a very widely used symmetric encryption algorithm. DES is
+ a block cipher with a 56 bit key and an 8 byte block size. Note
+ that in TLS, for key generation purposes, DES is treated as
+ having an 8 byte key length (64 bits), but it still only provides
+ 56 bits of protection. (The low bit of each key byte is presumed
+ to be set to produce odd parity in that key byte.) DES can also
+ be operated in a mode where three independent keys and three
+ encryptions are used for each block of data; this uses 168 bits
+ of key (24 bytes in the TLS key generation method) and provides
+ the equivalent of 112 bits of security. [DES], [3DES]
+
+ Digital Signature Standard (DSS)
+ A standard for digital signing, including the Digital Signing
+ Algorithm, approved by the National Institute of Standards and
+ Technology, defined in NIST FIPS PUB 186, "Digital Signature
+ Standard," published May, 1994 by the U.S. Dept. of Commerce.
+ [DSS]
+
+ digital signatures
+ Digital signatures utilize public key cryptography and one-way
+ hash functions to produce a signature of the data that can be
+ authenticated, and is difficult to forge or repudiate.
+
+ handshake
+ An initial negotiation between client and server that establishes
+ the parameters of their transactions.
+
+ Initialization Vector (IV)
+ When a block cipher is used in CBC mode, the initialization
+ vector is exclusive-ORed with the first plaintext block prior to
+ encryption.
+
+ IDEA
+ A 64-bit block cipher designed by Xuejia Lai and James Massey.
+ [IDEA]
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 58]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Message Authentication Code (MAC)
+ A Message Authentication Code is a one-way hash computed from a
+ message and some secret data. It is difficult to forge without
+ knowing the secret data. Its purpose is to detect if the message
+ has been altered.
+
+ master secret
+ Secure secret data used for generating encryption keys, MAC
+ secrets, and IVs.
+
+ MD5
+ MD5 is a secure hashing function that converts an arbitrarily
+ long data stream into a digest of fixed size (16 bytes). [MD5]
+
+ public key cryptography
+ A class of cryptographic techniques employing two-key ciphers.
+ Messages encrypted with the public key can only be decrypted with
+ the associated private key. Conversely, messages signed with the
+ private key can be verified with the public key.
+
+ one-way hash function
+ A one-way transformation that converts an arbitrary amount of
+ data into a fixed-length hash. It is computationally hard to
+ reverse the transformation or to find collisions. MD5 and SHA are
+ examples of one-way hash functions.
+
+ RC2
+ A block cipher developed by Ron Rivest at RSA Data Security, Inc.
+ [RSADSI] described in [RC2].
+
+ RC4
+ A stream cipher licensed by RSA Data Security [RSADSI]. A
+ compatible cipher is described in [RC4].
+
+ RSA
+ A very widely used public-key algorithm that can be used for
+ either encryption or digital signing. [RSA]
+
+ salt
+ Non-secret random data used to make export encryption keys resist
+ precomputation attacks.
+
+ server
+ The server is the application entity that responds to requests
+ for connections from clients. See also under client.
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 59]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ session
+ A TLS session is an association between a client and a server.
+ Sessions are created by the handshake protocol. Sessions define a
+ set of cryptographic security parameters, which can be shared
+ among multiple connections. Sessions are used to avoid the
+ expensive negotiation of new security parameters for each
+ connection.
+
+ session identifier
+ A session identifier is a value generated by a server that
+ identifies a particular session.
+
+ server write key
+ The key used to encrypt data written by the server.
+
+ server write MAC secret
+ The secret data used to authenticate data written by the server.
+
+ SHA
+ The Secure Hash Algorithm is defined in FIPS PUB 180-1. It
+ produces a 20-byte output. Note that all references to SHA
+ actually use the modified SHA-1 algorithm. [SHA]
+
+ SSL
+ Netscape's Secure Socket Layer protocol [SSL3]. TLS is based on
+ SSL Version 3.0
+
+ stream cipher
+ An encryption algorithm that converts a key into a
+ cryptographically-strong keystream, which is then exclusive-ORed
+ with the plaintext.
+
+ symmetric cipher
+ See bulk cipher.
+
+ Transport Layer Security (TLS)
+ This protocol; also, the Transport Layer Security working group
+ of the Internet Engineering Task Force (IETF). See "Comments" at
+ the end of this document.
+
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 60]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+C. CipherSuite definitions
+
+CipherSuite Is Key Cipher Hash
+ Exportable Exchange
+
+TLS_NULL_WITH_NULL_NULL * NULL NULL NULL
+TLS_RSA_WITH_NULL_MD5 * RSA NULL MD5
+TLS_RSA_WITH_NULL_SHA * RSA NULL SHA
+TLS_RSA_EXPORT_WITH_RC4_40_MD5 * RSA_EXPORT RC4_40 MD5
+TLS_RSA_WITH_RC4_128_MD5 RSA RC4_128 MD5
+TLS_RSA_WITH_RC4_128_SHA RSA RC4_128 SHA
+TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 * RSA_EXPORT RC2_CBC_40 MD5
+TLS_RSA_WITH_IDEA_CBC_SHA RSA IDEA_CBC SHA
+TLS_RSA_EXPORT_WITH_DES40_CBC_SHA * RSA_EXPORT DES40_CBC SHA
+TLS_RSA_WITH_DES_CBC_SHA RSA DES_CBC SHA
+TLS_RSA_WITH_3DES_EDE_CBC_SHA RSA 3DES_EDE_CBC SHA
+TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA * DH_DSS_EXPORT DES40_CBC SHA
+TLS_DH_DSS_WITH_DES_CBC_SHA DH_DSS DES_CBC SHA
+TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA DH_DSS 3DES_EDE_CBC SHA
+TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA * DH_RSA_EXPORT DES40_CBC SHA
+TLS_DH_RSA_WITH_DES_CBC_SHA DH_RSA DES_CBC SHA
+TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA DH_RSA 3DES_EDE_CBC SHA
+TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA * DHE_DSS_EXPORT DES40_CBC SHA
+TLS_DHE_DSS_WITH_DES_CBC_SHA DHE_DSS DES_CBC SHA
+TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA DHE_DSS 3DES_EDE_CBC SHA
+TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA * DHE_RSA_EXPORT DES40_CBC SHA
+TLS_DHE_RSA_WITH_DES_CBC_SHA DHE_RSA DES_CBC SHA
+TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA DHE_RSA 3DES_EDE_CBC SHA
+TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 * DH_anon_EXPORT RC4_40 MD5
+TLS_DH_anon_WITH_RC4_128_MD5 DH_anon RC4_128 MD5
+TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA DH_anon DES40_CBC SHA
+TLS_DH_anon_WITH_DES_CBC_SHA DH_anon DES_CBC SHA
+TLS_DH_anon_WITH_3DES_EDE_CBC_SHA DH_anon 3DES_EDE_CBC SHA
+
+
+ * Indicates IsExportable is True
+
+ Key
+ Exchange
+ Algorithm Description Key size limit
+
+ DHE_DSS Ephemeral DH with DSS signatures None
+ DHE_DSS_EXPORT Ephemeral DH with DSS signatures DH = 512 bits
+ DHE_RSA Ephemeral DH with RSA signatures None
+ DHE_RSA_EXPORT Ephemeral DH with RSA signatures DH = 512 bits,
+ RSA = none
+ DH_anon Anonymous DH, no signatures None
+ DH_anon_EXPORT Anonymous DH, no signatures DH = 512 bits
+
+
+
+Dierks & Allen Standards Track [Page 61]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ DH_DSS DH with DSS-based certificates None
+ DH_DSS_EXPORT DH with DSS-based certificates DH = 512 bits
+ DH_RSA DH with RSA-based certificates None
+ DH_RSA_EXPORT DH with RSA-based certificates DH = 512 bits,
+ RSA = none
+ NULL No key exchange N/A
+ RSA RSA key exchange None
+ RSA_EXPORT RSA key exchange RSA = 512 bits
+
+ Key size limit
+ The key size limit gives the size of the largest public key that
+ can be legally used for encryption in cipher suites that are
+ exportable.
+
+ Key Expanded Effective IV Block
+ Cipher Type Material Key Material Key Bits Size Size
+
+ NULL * Stream 0 0 0 0 N/A
+ IDEA_CBC Block 16 16 128 8 8
+ RC2_CBC_40 * Block 5 16 40 8 8
+ RC4_40 * Stream 5 16 40 0 N/A
+ RC4_128 Stream 16 16 128 0 N/A
+ DES40_CBC * Block 5 8 40 8 8
+ DES_CBC Block 8 8 56 8 8
+ 3DES_EDE_CBC Block 24 24 168 8 8
+
+ * Indicates IsExportable is true.
+
+ Type
+ Indicates whether this is a stream cipher or a block cipher
+ running in CBC mode.
+
+ Key Material
+ The number of bytes from the key_block that are used for
+ generating the write keys.
+
+ Expanded Key Material
+ The number of bytes actually fed into the encryption algorithm
+
+ Effective Key Bits
+ How much entropy material is in the key material being fed into
+ the encryption routines.
+
+ IV Size
+ How much data needs to be generated for the initialization
+ vector. Zero for stream ciphers; equal to the block size for
+ block ciphers.
+
+
+
+
+Dierks & Allen Standards Track [Page 62]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Block Size
+ The amount of data a block cipher enciphers in one chunk; a
+ block cipher running in CBC mode can only encrypt an even
+ multiple of its block size.
+
+ Hash Hash Padding
+ function Size Size
+ NULL 0 0
+ MD5 16 48
+ SHA 20 40
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 63]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+D. Implementation Notes
+
+ The TLS protocol cannot prevent many common security mistakes. This
+ section provides several recommendations to assist implementors.
+
+D.1. Temporary RSA keys
+
+ US Export restrictions limit RSA keys used for encryption to 512
+ bits, but do not place any limit on lengths of RSA keys used for
+ signing operations. Certificates often need to be larger than 512
+ bits, since 512-bit RSA keys are not secure enough for high-value
+ transactions or for applications requiring long-term security. Some
+ certificates are also designated signing-only, in which case they
+ cannot be used for key exchange.
+
+ When the public key in the certificate cannot be used for encryption,
+ the server signs a temporary RSA key, which is then exchanged. In
+ exportable applications, the temporary RSA key should be the maximum
+ allowable length (i.e., 512 bits). Because 512-bit RSA keys are
+ relatively insecure, they should be changed often. For typical
+ electronic commerce applications, it is suggested that keys be
+ changed daily or every 500 transactions, and more often if possible.
+ Note that while it is acceptable to use the same temporary key for
+ multiple transactions, it must be signed each time it is used.
+
+ RSA key generation is a time-consuming process. In many cases, a
+ low-priority process can be assigned the task of key generation.
+
+ Whenever a new key is completed, the existing temporary key can be
+ replaced with the new one.
+
+D.2. Random Number Generation and Seeding
+
+ TLS requires a cryptographically-secure pseudorandom number generator
+ (PRNG). Care must be taken in designing and seeding PRNGs. PRNGs
+ based on secure hash operations, most notably MD5 and/or SHA, are
+ acceptable, but cannot provide more security than the size of the
+ random number generator state. (For example, MD5-based PRNGs usually
+ provide 128 bits of state.)
+
+ To estimate the amount of seed material being produced, add the
+ number of bits of unpredictable information in each seed byte. For
+ example, keystroke timing values taken from a PC compatible's 18.2 Hz
+ timer provide 1 or 2 secure bits each, even though the total size of
+ the counter value is 16 bits or more. To seed a 128-bit PRNG, one
+ would thus require approximately 100 such timer values.
+
+
+
+
+
+Dierks & Allen Standards Track [Page 64]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Warning: The seeding functions in RSAREF and versions of BSAFE prior to
+ 3.0 are order-independent. For example, if 1000 seed bits are
+ supplied, one at a time, in 1000 separate calls to the seed
+ function, the PRNG will end up in a state which depends only
+ on the number of 0 or 1 seed bits in the seed data (i.e.,
+ there are 1001 possible final states). Applications using
+ BSAFE or RSAREF must take extra care to ensure proper seeding.
+ This may be accomplished by accumulating seed bits into a
+ buffer and processing them all at once or by processing an
+ incrementing counter with every seed bit; either method will
+ reintroduce order dependence into the seeding process.
+
+D.3. Certificates and authentication
+
+ Implementations are responsible for verifying the integrity of
+ certificates and should generally support certificate revocation
+ messages. Certificates should always be verified to ensure proper
+ signing by a trusted Certificate Authority (CA). The selection and
+ addition of trusted CAs should be done very carefully. Users should
+ be able to view information about the certificate and root CA.
+
+D.4. CipherSuites
+
+ TLS supports a range of key sizes and security levels, including some
+ which provide no or minimal security. A proper implementation will
+ probably not support many cipher suites. For example, 40-bit
+ encryption is easily broken, so implementations requiring strong
+ security should not allow 40-bit keys. Similarly, anonymous Diffie-
+ Hellman is strongly discouraged because it cannot prevent man-in-
+ the-middle attacks. Applications should also enforce minimum and
+ maximum key sizes. For example, certificate chains containing 512-bit
+ RSA keys or signatures are not appropriate for high-security
+ applications.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 65]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+E. Backward Compatibility With SSL
+
+ For historical reasons and in order to avoid a profligate consumption
+ of reserved port numbers, application protocols which are secured by
+ TLS 1.0, SSL 3.0, and SSL 2.0 all frequently share the same
+ connection port: for example, the https protocol (HTTP secured by SSL
+ or TLS) uses port 443 regardless of which security protocol it is
+ using. Thus, some mechanism must be determined to distinguish and
+ negotiate among the various protocols.
+
+ TLS version 1.0 and SSL 3.0 are very similar; thus, supporting both
+ is easy. TLS clients who wish to negotiate with SSL 3.0 servers
+ should send client hello messages using the SSL 3.0 record format and
+ client hello structure, sending {3, 1} for the version field to note
+ that they support TLS 1.0. If the server supports only SSL 3.0, it
+ will respond with an SSL 3.0 server hello; if it supports TLS, with a
+ TLS server hello. The negotiation then proceeds as appropriate for
+ the negotiated protocol.
+
+ Similarly, a TLS server which wishes to interoperate with SSL 3.0
+ clients should accept SSL 3.0 client hello messages and respond with
+ an SSL 3.0 server hello if an SSL 3.0 client hello is received which
+ has a version field of {3, 0}, denoting that this client does not
+ support TLS.
+
+ Whenever a client already knows the highest protocol known to a
+ server (for example, when resuming a session), it should initiate the
+ connection in that native protocol.
+
+ TLS 1.0 clients that support SSL Version 2.0 servers must send SSL
+ Version 2.0 client hello messages [SSL2]. TLS servers should accept
+ either client hello format if they wish to support SSL 2.0 clients on
+ the same connection port. The only deviations from the Version 2.0
+ specification are the ability to specify a version with a value of
+ three and the support for more ciphering types in the CipherSpec.
+
+ Warning: The ability to send Version 2.0 client hello messages will be
+ phased out with all due haste. Implementors should make every
+ effort to move forward as quickly as possible. Version 3.0
+ provides better mechanisms for moving to newer versions.
+
+ The following cipher specifications are carryovers from SSL Version
+ 2.0. These are assumed to use RSA for key exchange and
+ authentication.
+
+ V2CipherSpec TLS_RC4_128_WITH_MD5 = { 0x01,0x00,0x80 };
+ V2CipherSpec TLS_RC4_128_EXPORT40_WITH_MD5 = { 0x02,0x00,0x80 };
+ V2CipherSpec TLS_RC2_CBC_128_CBC_WITH_MD5 = { 0x03,0x00,0x80 };
+
+
+
+Dierks & Allen Standards Track [Page 66]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ V2CipherSpec TLS_RC2_CBC_128_CBC_EXPORT40_WITH_MD5
+ = { 0x04,0x00,0x80 };
+ V2CipherSpec TLS_IDEA_128_CBC_WITH_MD5 = { 0x05,0x00,0x80 };
+ V2CipherSpec TLS_DES_64_CBC_WITH_MD5 = { 0x06,0x00,0x40 };
+ V2CipherSpec TLS_DES_192_EDE3_CBC_WITH_MD5 = { 0x07,0x00,0xC0 };
+
+ Cipher specifications native to TLS can be included in Version 2.0
+ client hello messages using the syntax below. Any V2CipherSpec
+ element with its first byte equal to zero will be ignored by Version
+ 2.0 servers. Clients sending any of the above V2CipherSpecs should
+ also include the TLS equivalent (see Appendix A.5):
+
+ V2CipherSpec (see TLS name) = { 0x00, CipherSuite };
+
+E.1. Version 2 client hello
+
+ The Version 2.0 client hello message is presented below using this
+ document's presentation model. The true definition is still assumed
+ to be the SSL Version 2.0 specification.
+
+ uint8 V2CipherSpec[3];
+
+ struct {
+ uint8 msg_type;
+ Version version;
+ uint16 cipher_spec_length;
+ uint16 session_id_length;
+ uint16 challenge_length;
+ V2CipherSpec cipher_specs[V2ClientHello.cipher_spec_length];
+ opaque session_id[V2ClientHello.session_id_length];
+ Random challenge;
+ } V2ClientHello;
+
+ msg_type
+ This field, in conjunction with the version field, identifies a
+ version 2 client hello message. The value should be one (1).
+
+ version
+ The highest version of the protocol supported by the client
+ (equals ProtocolVersion.version, see Appendix A.1).
+
+ cipher_spec_length
+ This field is the total length of the field cipher_specs. It
+ cannot be zero and must be a multiple of the V2CipherSpec length
+ (3).
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 67]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ session_id_length
+ This field must have a value of either zero or 16. If zero, the
+ client is creating a new session. If 16, the session_id field
+ will contain the 16 bytes of session identification.
+
+ challenge_length
+ The length in bytes of the client's challenge to the server to
+ authenticate itself. This value must be 32.
+
+ cipher_specs
+ This is a list of all CipherSpecs the client is willing and able
+ to use. There must be at least one CipherSpec acceptable to the
+ server.
+
+ session_id
+ If this field's length is not zero, it will contain the
+ identification for a session that the client wishes to resume.
+
+ challenge
+ The client challenge to the server for the server to identify
+ itself is a (nearly) arbitrary length random. The TLS server will
+ right justify the challenge data to become the ClientHello.random
+ data (padded with leading zeroes, if necessary), as specified in
+ this protocol specification. If the length of the challenge is
+ greater than 32 bytes, only the last 32 bytes are used. It is
+ legitimate (but not necessary) for a V3 server to reject a V2
+ ClientHello that has fewer than 16 bytes of challenge data.
+
+ Note: Requests to resume a TLS session should use a TLS client hello.
+
+E.2. Avoiding man-in-the-middle version rollback
+
+ When TLS clients fall back to Version 2.0 compatibility mode, they
+ should use special PKCS #1 block formatting. This is done so that TLS
+ servers will reject Version 2.0 sessions with TLS-capable clients.
+
+ When TLS clients are in Version 2.0 compatibility mode, they set the
+ right-hand (least-significant) 8 random bytes of the PKCS padding
+ (not including the terminal null of the padding) for the RSA
+ encryption of the ENCRYPTED-KEY-DATA field of the CLIENT-MASTER-KEY
+ to 0x03 (the other padding bytes are random). After decrypting the
+ ENCRYPTED-KEY-DATA field, servers that support TLS should issue an
+ error if these eight padding bytes are 0x03. Version 2.0 servers
+ receiving blocks padded in this manner will proceed normally.
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 68]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+F. Security analysis
+
+ The TLS protocol is designed to establish a secure connection between
+ a client and a server communicating over an insecure channel. This
+ document makes several traditional assumptions, including that
+ attackers have substantial computational resources and cannot obtain
+ secret information from sources outside the protocol. Attackers are
+ assumed to have the ability to capture, modify, delete, replay, and
+ otherwise tamper with messages sent over the communication channel.
+ This appendix outlines how TLS has been designed to resist a variety
+ of attacks.
+
+F.1. Handshake protocol
+
+ The handshake protocol is responsible for selecting a CipherSpec and
+ generating a Master Secret, which together comprise the primary
+ cryptographic parameters associated with a secure session. The
+ handshake protocol can also optionally authenticate parties who have
+ certificates signed by a trusted certificate authority.
+
+F.1.1. Authentication and key exchange
+
+ TLS supports three authentication modes: authentication of both
+ parties, server authentication with an unauthenticated client, and
+ total anonymity. Whenever the server is authenticated, the channel is
+ secure against man-in-the-middle attacks, but completely anonymous
+ sessions are inherently vulnerable to such attacks. Anonymous
+ servers cannot authenticate clients. If the server is authenticated,
+ its certificate message must provide a valid certificate chain
+ leading to an acceptable certificate authority. Similarly,
+ authenticated clients must supply an acceptable certificate to the
+ server. Each party is responsible for verifying that the other's
+ certificate is valid and has not expired or been revoked.
+
+ The general goal of the key exchange process is to create a
+ pre_master_secret known to the communicating parties and not to
+ attackers. The pre_master_secret will be used to generate the
+ master_secret (see Section 8.1). The master_secret is required to
+ generate the certificate verify and finished messages, encryption
+ keys, and MAC secrets (see Sections 7.4.8, 7.4.9 and 6.3). By sending
+ a correct finished message, parties thus prove that they know the
+ correct pre_master_secret.
+
+F.1.1.1. Anonymous key exchange
+
+ Completely anonymous sessions can be established using RSA or
+ Diffie-Hellman for key exchange. With anonymous RSA, the client
+ encrypts a pre_master_secret with the server's uncertified public key
+
+
+
+Dierks & Allen Standards Track [Page 69]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ extracted from the server key exchange message. The result is sent in
+ a client key exchange message. Since eavesdroppers do not know the
+ server's private key, it will be infeasible for them to decode the
+ pre_master_secret. (Note that no anonymous RSA Cipher Suites are
+ defined in this document).
+
+ With Diffie-Hellman, the server's public parameters are contained in
+ the server key exchange message and the client's are sent in the
+ client key exchange message. Eavesdroppers who do not know the
+ private values should not be able to find the Diffie-Hellman result
+ (i.e. the pre_master_secret).
+
+ Warning: Completely anonymous connections only provide protection
+ against passive eavesdropping. Unless an independent tamper-
+ proof channel is used to verify that the finished messages
+ were not replaced by an attacker, server authentication is
+ required in environments where active man-in-the-middle
+ attacks are a concern.
+
+F.1.1.2. RSA key exchange and authentication
+
+ With RSA, key exchange and server authentication are combined. The
+ public key may be either contained in the server's certificate or may
+ be a temporary RSA key sent in a server key exchange message. When
+ temporary RSA keys are used, they are signed by the server's RSA or
+ DSS certificate. The signature includes the current
+ ClientHello.random, so old signatures and temporary keys cannot be
+ replayed. Servers may use a single temporary RSA key for multiple
+ negotiation sessions.
+
+ Note: The temporary RSA key option is useful if servers need large
+ certificates but must comply with government-imposed size limits
+ on keys used for key exchange.
+
+ After verifying the server's certificate, the client encrypts a
+ pre_master_secret with the server's public key. By successfully
+ decoding the pre_master_secret and producing a correct finished
+ message, the server demonstrates that it knows the private key
+ corresponding to the server certificate.
+
+ When RSA is used for key exchange, clients are authenticated using
+ the certificate verify message (see Section 7.4.8). The client signs
+ a value derived from the master_secret and all preceding handshake
+ messages. These handshake messages include the server certificate,
+ which binds the signature to the server, and ServerHello.random,
+ which binds the signature to the current handshake process.
+
+
+
+
+
+Dierks & Allen Standards Track [Page 70]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+F.1.1.3. Diffie-Hellman key exchange with authentication
+
+ When Diffie-Hellman key exchange is used, the server can either
+ supply a certificate containing fixed Diffie-Hellman parameters or
+ can use the server key exchange message to send a set of temporary
+ Diffie-Hellman parameters signed with a DSS or RSA certificate.
+ Temporary parameters are hashed with the hello.random values before
+ signing to ensure that attackers do not replay old parameters. In
+ either case, the client can verify the certificate or signature to
+ ensure that the parameters belong to the server.
+
+ If the client has a certificate containing fixed Diffie-Hellman
+ parameters, its certificate contains the information required to
+ complete the key exchange. Note that in this case the client and
+ server will generate the same Diffie-Hellman result (i.e.,
+ pre_master_secret) every time they communicate. To prevent the
+ pre_master_secret from staying in memory any longer than necessary,
+ it should be converted into the master_secret as soon as possible.
+ Client Diffie-Hellman parameters must be compatible with those
+ supplied by the server for the key exchange to work.
+
+ If the client has a standard DSS or RSA certificate or is
+ unauthenticated, it sends a set of temporary parameters to the server
+ in the client key exchange message, then optionally uses a
+ certificate verify message to authenticate itself.
+
+F.1.2. Version rollback attacks
+
+ Because TLS includes substantial improvements over SSL Version 2.0,
+ attackers may try to make TLS-capable clients and servers fall back
+ to Version 2.0. This attack can occur if (and only if) two TLS-
+ capable parties use an SSL 2.0 handshake.
+
+ Although the solution using non-random PKCS #1 block type 2 message
+ padding is inelegant, it provides a reasonably secure way for Version
+ 3.0 servers to detect the attack. This solution is not secure against
+ attackers who can brute force the key and substitute a new
+ ENCRYPTED-KEY-DATA message containing the same key (but with normal
+ padding) before the application specified wait threshold has expired.
+ Parties concerned about attacks of this scale should not be using
+ 40-bit encryption keys anyway. Altering the padding of the least-
+ significant 8 bytes of the PKCS padding does not impact security for
+ the size of the signed hashes and RSA key lengths used in the
+ protocol, since this is essentially equivalent to increasing the
+ input block size by 8 bytes.
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 71]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+F.1.3. Detecting attacks against the handshake protocol
+
+ An attacker might try to influence the handshake exchange to make the
+ parties select different encryption algorithms than they would
+ normally choose. Because many implementations will support 40-bit
+ exportable encryption and some may even support null encryption or
+ MAC algorithms, this attack is of particular concern.
+
+ For this attack, an attacker must actively change one or more
+ handshake messages. If this occurs, the client and server will
+ compute different values for the handshake message hashes. As a
+ result, the parties will not accept each others' finished messages.
+ Without the master_secret, the attacker cannot repair the finished
+ messages, so the attack will be discovered.
+
+F.1.4. Resuming sessions
+
+ When a connection is established by resuming a session, new
+ ClientHello.random and ServerHello.random values are hashed with the
+ session's master_secret. Provided that the master_secret has not been
+ compromised and that the secure hash operations used to produce the
+ encryption keys and MAC secrets are secure, the connection should be
+ secure and effectively independent from previous connections.
+ Attackers cannot use known encryption keys or MAC secrets to
+ compromise the master_secret without breaking the secure hash
+ operations (which use both SHA and MD5).
+
+ Sessions cannot be resumed unless both the client and server agree.
+ If either party suspects that the session may have been compromised,
+ or that certificates may have expired or been revoked, it should
+ force a full handshake. An upper limit of 24 hours is suggested for
+ session ID lifetimes, since an attacker who obtains a master_secret
+ may be able to impersonate the compromised party until the
+ corresponding session ID is retired. Applications that may be run in
+ relatively insecure environments should not write session IDs to
+ stable storage.
+
+F.1.5. MD5 and SHA
+
+ TLS uses hash functions very conservatively. Where possible, both MD5
+ and SHA are used in tandem to ensure that non-catastrophic flaws in
+ one algorithm will not break the overall protocol.
+
+F.2. Protecting application data
+
+ The master_secret is hashed with the ClientHello.random and
+ ServerHello.random to produce unique data encryption keys and MAC
+ secrets for each connection.
+
+
+
+Dierks & Allen Standards Track [Page 72]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Outgoing data is protected with a MAC before transmission. To prevent
+ message replay or modification attacks, the MAC is computed from the
+ MAC secret, the sequence number, the message length, the message
+ contents, and two fixed character strings. The message type field is
+ necessary to ensure that messages intended for one TLS Record Layer
+ client are not redirected to another. The sequence number ensures
+ that attempts to delete or reorder messages will be detected. Since
+ sequence numbers are 64-bits long, they should never overflow.
+ Messages from one party cannot be inserted into the other's output,
+ since they use independent MAC secrets. Similarly, the server-write
+ and client-write keys are independent so stream cipher keys are used
+ only once.
+
+ If an attacker does break an encryption key, all messages encrypted
+ with it can be read. Similarly, compromise of a MAC key can make
+ message modification attacks possible. Because MACs are also
+ encrypted, message-alteration attacks generally require breaking the
+ encryption algorithm as well as the MAC.
+
+ Note: MAC secrets may be larger than encryption keys, so messages can
+ remain tamper resistant even if encryption keys are broken.
+
+F.3. Final notes
+
+ For TLS to be able to provide a secure connection, both the client
+ and server systems, keys, and applications must be secure. In
+ addition, the implementation must be free of security errors.
+
+ The system is only as strong as the weakest key exchange and
+ authentication algorithm supported, and only trustworthy
+ cryptographic functions should be used. Short public keys, 40-bit
+ bulk encryption keys, and anonymous servers should be used with great
+ caution. Implementations and users must be careful when deciding
+ which certificates and certificate authorities are acceptable; a
+ dishonest certificate authority can do tremendous damage.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 73]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+G. Patent Statement
+
+ Some of the cryptographic algorithms proposed for use in this
+ protocol have patent claims on them. In addition Netscape
+ Communications Corporation has a patent claim on the Secure Sockets
+ Layer (SSL) work that this standard is based on. The Internet
+ Standards Process as defined in RFC 2026 requests that a statement be
+ obtained from a Patent holder indicating that a license will be made
+ available to applicants under reasonable terms and conditions.
+
+ The Massachusetts Institute of Technology has granted RSA Data
+ Security, Inc., exclusive sub-licensing rights to the following
+ patent issued in the United States:
+
+ Cryptographic Communications System and Method ("RSA"), No.
+ 4,405,829
+
+ Netscape Communications Corporation has been issued the following
+ patent in the United States:
+
+ Secure Socket Layer Application Program Apparatus And Method
+ ("SSL"), No. 5,657,390
+
+ Netscape Communications has issued the following statement:
+
+ Intellectual Property Rights
+
+ Secure Sockets Layer
+
+ The United States Patent and Trademark Office ("the PTO")
+ recently issued U.S. Patent No. 5,657,390 ("the SSL Patent") to
+ Netscape for inventions described as Secure Sockets Layers
+ ("SSL"). The IETF is currently considering adopting SSL as a
+ transport protocol with security features. Netscape encourages
+ the royalty-free adoption and use of the SSL protocol upon the
+ following terms and conditions:
+
+ * If you already have a valid SSL Ref license today which
+ includes source code from Netscape, an additional patent
+ license under the SSL patent is not required.
+
+ * If you don't have an SSL Ref license, you may have a royalty
+ free license to build implementations covered by the SSL
+ Patent Claims or the IETF TLS specification provided that you
+ do not to assert any patent rights against Netscape or other
+ companies for the implementation of SSL or the IETF TLS
+ recommendation.
+
+
+
+
+Dierks & Allen Standards Track [Page 74]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ What are "Patent Claims":
+
+ Patent claims are claims in an issued foreign or domestic patent
+ that:
+
+ 1) must be infringed in order to implement methods or build
+ products according to the IETF TLS specification; or
+
+ 2) patent claims which require the elements of the SSL patent
+ claims and/or their equivalents to be infringed.
+
+ The Internet Society, Internet Architecture Board, Internet
+ Engineering Steering Group and the Corporation for National Research
+ Initiatives take no position on the validity or scope of the patents
+ and patent applications, nor on the appropriateness of the terms of
+ the assurance. The Internet Society and other groups mentioned above
+ have not made any determination as to any other intellectual property
+ rights which may apply to the practice of this standard. Any further
+ consideration of these matters is the user's own responsibility.
+
+Security Considerations
+
+ Security issues are discussed throughout this memo.
+
+References
+
+ [3DES] W. Tuchman, "Hellman Presents No Shortcut Solutions To DES,"
+ IEEE Spectrum, v. 16, n. 7, July 1979, pp40-41.
+
+ [BLEI] Bleichenbacher D., "Chosen Ciphertext Attacks against
+ Protocols Based on RSA Encryption Standard PKCS #1" in
+ Advances in Cryptology -- CRYPTO'98, LNCS vol. 1462, pages:
+ 1--12, 1998.
+
+ [DES] ANSI X3.106, "American National Standard for Information
+ Systems-Data Link Encryption," American National Standards
+ Institute, 1983.
+
+ [DH1] W. Diffie and M. E. Hellman, "New Directions in
+ Cryptography," IEEE Transactions on Information Theory, V.
+ IT-22, n. 6, Jun 1977, pp. 74-84.
+
+ [DSS] NIST FIPS PUB 186, "Digital Signature Standard," National
+ Institute of Standards and Technology, U.S. Department of
+ Commerce, May 18, 1994.
+
+ [FTP] Postel J., and J. Reynolds, "File Transfer Protocol", STD 9,
+ RFC 959, October 1985.
+
+
+
+Dierks & Allen Standards Track [Page 75]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ [HTTP] Berners-Lee, T., Fielding, R., and H. Frystyk, "Hypertext
+ Transfer Protocol -- HTTP/1.0", RFC 1945, May 1996.
+
+ [HMAC] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-
+ Hashing for Message Authentication," RFC 2104, February
+ 1997.
+
+ [IDEA] X. Lai, "On the Design and Security of Block Ciphers," ETH
+ Series in Information Processing, v. 1, Konstanz: Hartung-
+ Gorre Verlag, 1992.
+
+ [MD2] Kaliski, B., "The MD2 Message Digest Algorithm", RFC 1319,
+ April 1992.
+
+ [MD5] Rivest, R., "The MD5 Message Digest Algorithm", RFC 1321,
+ April 1992.
+
+ [PKCS1] RSA Laboratories, "PKCS #1: RSA Encryption Standard,"
+ version 1.5, November 1993.
+
+ [PKCS6] RSA Laboratories, "PKCS #6: RSA Extended Certificate Syntax
+ Standard," version 1.5, November 1993.
+
+ [PKCS7] RSA Laboratories, "PKCS #7: RSA Cryptographic Message Syntax
+ Standard," version 1.5, November 1993.
+
+ [PKIX] Housley, R., Ford, W., Polk, W. and D. Solo, "Internet
+ Public Key Infrastructure: Part I: X.509 Certificate and CRL
+ Profile", RFC 2459, January 1999.
+
+ [RC2] Rivest, R., "A Description of the RC2(r) Encryption
+ Algorithm", RFC 2268, January 1998.
+
+ [RC4] Thayer, R. and K. Kaukonen, A Stream Cipher Encryption
+ Algorithm, Work in Progress.
+
+ [RSA] R. Rivest, A. Shamir, and L. M. Adleman, "A Method for
+ Obtaining Digital Signatures and Public-Key Cryptosystems,"
+ Communications of the ACM, v. 21, n. 2, Feb 1978, pp. 120-
+ 126.
+
+ [RSADSI] Contact RSA Data Security, Inc., Tel: 415-595-8782
+
+ [SCH] B. Schneier. Applied Cryptography: Protocols, Algorithms,
+ and Source Code in C, Published by John Wiley & Sons, Inc.
+ 1994.
+
+
+
+
+
+Dierks & Allen Standards Track [Page 76]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ [SHA] NIST FIPS PUB 180-1, "Secure Hash Standard," National
+ Institute of Standards and Technology, U.S. Department of
+ Commerce, Work in Progress, May 31, 1994.
+
+ [SSL2] Hickman, Kipp, "The SSL Protocol", Netscape Communications
+ Corp., Feb 9, 1995.
+
+ [SSL3] A. Frier, P. Karlton, and P. Kocher, "The SSL 3.0 Protocol",
+ Netscape Communications Corp., Nov 18, 1996.
+
+ [TCP] Postel, J., "Transmission Control Protocol," STD 7, RFC 793,
+ September 1981.
+
+ [TEL] Postel J., and J. Reynolds, "Telnet Protocol
+ Specifications", STD 8, RFC 854, May 1993.
+
+ [TEL] Postel J., and J. Reynolds, "Telnet Option Specifications",
+ STD 8, RFC 855, May 1993.
+
+ [X509] CCITT. Recommendation X.509: "The Directory - Authentication
+ Framework". 1988.
+
+ [XDR] R. Srinivansan, Sun Microsystems, RFC-1832: XDR: External
+ Data Representation Standard, August 1995.
+
+Credits
+
+ Win Treese
+ Open Market
+
+ EMail: treese@openmarket.com
+
+
+ Editors
+
+ Christopher Allen Tim Dierks
+ Certicom Certicom
+
+ EMail: callen@certicom.com EMail: tdierks@certicom.com
+
+
+ Authors' Addresses
+
+ Tim Dierks Philip L. Karlton
+ Certicom Netscape Communications
+
+ EMail: tdierks@certicom.com
+
+
+
+
+Dierks & Allen Standards Track [Page 77]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Alan O. Freier Paul C. Kocher
+ Netscape Communications Independent Consultant
+
+ EMail: freier@netscape.com EMail: pck@netcom.com
+
+
+ Other contributors
+
+ Martin Abadi Robert Relyea
+ Digital Equipment Corporation Netscape Communications
+
+ EMail: ma@pa.dec.com EMail: relyea@netscape.com
+
+ Ran Canetti Jim Roskind
+ IBM Watson Research Center Netscape Communications
+
+ EMail: canetti@watson.ibm.com EMail: jar@netscape.com
+
+
+ Taher Elgamal Micheal J. Sabin, Ph. D.
+ Securify Consulting Engineer
+
+ EMail: elgamal@securify.com EMail: msabin@netcom.com
+
+
+ Anil R. Gangolli Dan Simon
+ Structured Arts Computing Corp. Microsoft
+
+ EMail: gangolli@structuredarts.com EMail: dansimon@microsoft.com
+
+
+ Kipp E.B. Hickman Tom Weinstein
+ Netscape Communications Netscape Communications
+
+ EMail: kipp@netscape.com EMail: tomw@netscape.com
+
+
+ Hugo Krawczyk
+ IBM Watson Research Center
+
+ EMail: hugo@watson.ibm.com
+
+Comments
+
+ The discussion list for the IETF TLS working group is located at the
+ e-mail address <ietf-tls@lists.consensus.com>. Information on the
+ group and information on how to subscribe to the list is at
+ <http://lists.consensus.com/>.
+
+
+
+Dierks & Allen Standards Track [Page 78]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+ Archives of the list can be found at:
+ <http://www.imc.org/ietf-tls/mail-archive/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 79]
+
+RFC 2246 The TLS Protocol Version 1.0 January 1999
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Dierks & Allen Standards Track [Page 80]
+
diff --git a/standards/rfc2487.txt b/standards/rfc2487.txt
new file mode 100644
index 000000000..fb1305f00
--- /dev/null
+++ b/standards/rfc2487.txt
@@ -0,0 +1,451 @@
+
+
+
+
+
+
+Network Working Group P. Hoffman
+Request for Comments: 2487 Internet Mail Consortium
+Category: Standards Track January 1999
+
+
+ SMTP Service Extension for Secure SMTP over TLS
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+1. Abstract
+
+ This document describes an extension to the SMTP service that allows
+ an SMTP server and client to use transport-layer security to provide
+ private, authenticated communication over the Internet. This gives
+ SMTP agents the ability to protect some or all of their
+ communications from eavesdroppers and attackers.
+
+2. Introduction
+
+ SMTP [RFC-821] servers and clients normally communicate in the clear
+ over the Internet. In many cases, this communication goes through one
+ or more router that is not controlled or trusted by either entity.
+ Such an untrusted router might allow a third party to monitor or
+ alter the communications between the server and client.
+
+ Further, there is often a desire for two SMTP agents to be able to
+ authenticate each others' identities. For example, a secure SMTP
+ server might only allow communications from other SMTP agents it
+ knows, or it might act differently for messages received from an
+ agent it knows than from one it doesn't know.
+
+ TLS [TLS], more commonly known as SSL, is a popular mechanism for
+ enhancing TCP communications with privacy and authentication. TLS is
+ in wide use with the HTTP protocol, and is also being used for adding
+ security to many other common protocols that run over TCP.
+
+
+
+
+
+
+Hoffman Standards Track [Page 1]
+
+RFC 2487 SMTP Service Extension January 1999
+
+
+2.1 Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [RFC-2119].
+
+3. STARTTLS Extension
+
+ The STARTTLS extension to SMTP is laid out as follows:
+
+ (1) the name of the SMTP service defined here is STARTTLS;
+
+ (2) the EHLO keyword value associated with the extension is STARTTLS;
+
+ (3) the STARTTLS keyword has no parameters;
+
+ (4) a new SMTP verb, "STARTTLS", is defined;
+
+ (5) no additional parameters are added to any SMTP command.
+
+4. The STARTTLS Keyword
+
+ The STARTTLS keyword is used to tell the SMTP client that the SMTP
+ server allows use of TLS. It takes no parameters.
+
+5. The STARTTLS Command
+
+ The format for the STARTTLS command is:
+
+ STARTTLS
+
+ with no parameters.
+
+ After the client gives the STARTTLS command, the server responds with
+ one of the following reply codes:
+
+ 220 Ready to start TLS
+ 501 Syntax error (no parameters allowed)
+ 454 TLS not available due to temporary reason
+
+ A publicly-referenced SMTP server MUST NOT require use of the
+ STARTTLS extension in order to deliver mail locally. This rule
+ prevents the STARTTLS extension from damaging the interoperability of
+ the Internet's SMTP infrastructure. A publicly-referenced SMTP server
+ is an SMTP server which runs on port 25 of an Internet host listed in
+ the MX record (or A record if an MX record is not present) for the
+ domain name on the right hand side of an Internet mail address.
+
+
+
+
+Hoffman Standards Track [Page 2]
+
+RFC 2487 SMTP Service Extension January 1999
+
+
+ Any SMTP server may refuse to accept messages for relay based on
+ authentication supplied during the TLS negotiation. An SMTP server
+ that is not publicly referenced may refuse to accept any messages for
+ relay or local delivery based on authentication supplied during the
+ TLS negotiation.
+
+ A SMTP server that is not publicly referenced may choose to require
+ that the client perform a TLS negotiation before accepting any
+ commands. In this case, the server SHOULD return the reply code:
+
+ 530 Must issue a STARTTLS command first
+
+ to every command other than NOOP, EHLO, STARTTLS, or QUIT. If the
+ client and server are using the ENHANCEDSTATUSCODES ESMTP extension
+ [RFC-2034], the status code to be returned SHOULD be 5.7.0.
+
+ After receiving a 220 response to a STARTTLS command, the client
+ SHOULD start the TLS negotiation before giving any other SMTP
+ commands.
+
+ If the SMTP client is using pipelining as defined in RFC 1854, the
+ STARTTLS command must be the last command in a group.
+
+5.1 Processing After the STARTTLS Command
+
+ After the TLS handshake has been completed, both parties MUST
+ immediately decide whether or not to continue based on the
+ authentication and privacy achieved. The SMTP client and server may
+ decide to move ahead even if the TLS negotiation ended with no
+ authentication and/or no privacy because most SMTP services are
+ performed with no authentication and no privacy, but some SMTP
+ clients or servers may want to continue only if a particular level of
+ authentication and/or privacy was achieved.
+
+ If the SMTP client decides that the level of authentication or
+ privacy is not high enough for it to continue, it SHOULD issue an
+ SMTP QUIT command immediately after the TLS negotiation is complete.
+ If the SMTP server decides that the level of authentication or
+ privacy is not high enough for it to continue, it SHOULD reply to
+ every SMTP command from the client (other than a QUIT command) with
+ the 554 reply code (with a possible text string such as "Command
+ refused due to lack of security").
+
+ The decision of whether or not to believe the authenticity of the
+ other party in a TLS negotiation is a local matter. However, some
+ general rules for the decisions are:
+
+
+
+
+
+Hoffman Standards Track [Page 3]
+
+RFC 2487 SMTP Service Extension January 1999
+
+
+ - A SMTP client would probably only want to authenticate an SMTP
+ server whose server certificate has a domain name that is the
+ domain name that the client thought it was connecting to.
+ - A publicly-referenced SMTP server would probably want to accept
+ any certificate from an SMTP client, and would possibly want to
+ put distinguishing information about the certificate in the
+ Received header of messages that were relayed or submitted from
+ the client.
+
+5.2 Result of the STARTTLS Command
+
+ Upon completion of the TLS handshake, the SMTP protocol is reset to
+ the initial state (the state in SMTP after a server issues a 220
+ service ready greeting). The server MUST discard any knowledge
+ obtained from the client, such as the argument to the EHLO command,
+ which was not obtained from the TLS negotiation itself. The client
+ MUST discard any knowledge obtained from the server, such as the list
+ of SMTP service extensions, which was not obtained from the TLS
+ negotiation itself. The client SHOULD send an EHLO command as the
+ first command after a successful TLS negotiation.
+
+ The list of SMTP service extensions returned in response to an EHLO
+ command received after the TLS handshake MAY be different than the
+ list returned before the TLS handshake. For example, an SMTP server
+ might not want to advertise support for a particular SASL mechanism
+ [SASL] unless a client has sent an appropriate client certificate
+ during a TLS handshake.
+
+ Both the client and the server MUST know if there is a TLS session
+ active. A client MUST NOT attempt to start a TLS session if a TLS
+ session is already active. A server MUST NOT return the TLS extension
+ in response to an EHLO command received after a TLS handshake has
+ completed.
+
+6. Usage Example
+
+ The following dialog illustrates how a client and server can start a
+ TLS session:
+
+ S: <waits for connection on TCP port 25>
+ C: <opens connection>
+ S: 220 mail.imc.org SMTP service ready
+ C: EHLO mail.ietf.org
+ S: 250-mail.imc.org offers a warm hug of welcome
+ S: 250 STARTTLS
+ C: STARTTLS
+ S: 220 Go ahead
+ C: <starts TLS negotiation>
+
+
+
+Hoffman Standards Track [Page 4]
+
+RFC 2487 SMTP Service Extension January 1999
+
+
+ C & S: <negotiate a TLS session>
+ C & S: <check result of negotiation>
+ C: <continues by sending an SMTP command>
+ . . .
+
+7. Security Considerations
+
+ It should be noted that SMTP is not an end-to-end mechanism. Thus, if
+ an SMTP client/server pair decide to add TLS privacy, they are not
+ securing the transport from the originating mail user agent to the
+ recipient. Further, because delivery of a single piece of mail may
+ go between more than two SMTP servers, adding TLS privacy to one pair
+ of servers does not mean that the entire SMTP chain has been made
+ private. Further, just because an SMTP server can authenticate an
+ SMTP client, it does not mean that the mail from the SMTP client was
+ authenticated by the SMTP client when the client received it.
+
+ Both the STMP client and server must check the result of the TLS
+ negotiation to see whether acceptable authentication or privacy was
+ achieved. Ignoring this step completely invalidates using TLS for
+ security. The decision about whether acceptable authentication or
+ privacy was achieved is made locally, is implementation-dependant,
+ and is beyond the scope of this document.
+
+ The SMTP client and server should note carefully the result of the
+ TLS negotiation. If the negotiation results in no privacy, or if it
+ results in privacy using algorithms or key lengths that are deemed
+ not strong enough, or if the authentication is not good enough for
+ either party, the client may choose to end the SMTP session with an
+ immediate QUIT command, or the server may choose to not accept any
+ more SMTP commands.
+
+ A server announcing in an EHLO response that it uses a particular TLS
+ protocol should not pose any security issues, since any use of TLS
+ will be at least as secure as no use of TLS.
+
+ A man-in-the-middle attack can be launched by deleting the "250
+ STARTTLS" response from the server. This would cause the client not
+ to try to start a TLS session. An SMTP client can protect against
+ this attack by recording the fact that a particular SMTP server
+ offers TLS during one session and generating an alarm if it does not
+ appear in the EHLO response for a later session. The lack of TLS
+ during a session SHOULD NOT result in the bouncing of email, although
+ it could result in delayed processing.
+
+
+
+
+
+
+
+Hoffman Standards Track [Page 5]
+
+RFC 2487 SMTP Service Extension January 1999
+
+
+ Before the TLS handshake has begun, any protocol interactions are
+ performed in the clear and may be modified by an active attacker. For
+ this reason, clients and servers MUST discard any knowledge obtained
+ prior to the start of the TLS handshake upon completion of the TLS
+ handshake.
+
+ The STARTTLS extension is not suitable for authenticating the author
+ of an email message unless every hop in the delivery chain, including
+ the submission to the first SMTP server, is authenticated. Another
+ proposal [SMTP-AUTH] can be used to authenticate delivery and MIME
+ security multiparts [MIME-SEC] can be used to authenticate the author
+ of an email message. In addition, the [SMTP-AUTH] proposal offers
+ simpler and more flexible options to authenticate an SMTP client and
+ the SASL EXTERNAL mechanism [SASL] MAY be used in conjunction with
+ the STARTTLS command to provide an authorization identity.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hoffman Standards Track [Page 6]
+
+RFC 2487 SMTP Service Extension January 1999
+
+
+A. References
+
+ [RFC-821] Postel, J., "Simple Mail Transfer Protocol", RFC 821,
+ August 1982.
+
+ [RFC-1869] Klensin, J., Freed, N, Rose, M, Stefferud, E. and D.
+ Crocker, "SMTP Service Extensions", STD 10, RFC 1869,
+ November 1995.
+
+ [RFC-2034] Freed, N., "SMTP Service Extension for Returning Enhanced
+ Error Codes", RFC 2034, October 1996.
+
+ [RFC-2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [SASL] Myers, J., "Simple Authentication and Security Layer
+ (SASL)", RFC 2222, October 1997.
+
+ [SMTP-AUTH] "SMTP Service Extension for Authentication", Work in
+ Progress.
+
+ [TLS] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0",
+ RFC 2246, January 1999.
+
+B. Author's Address
+
+ Paul Hoffman
+ Internet Mail Consortium
+ 127 Segre Place
+ Santa Cruz, CA 95060
+
+ Phone: (831) 426-9827
+ EMail: phoffman@imc.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hoffman Standards Track [Page 7]
+
+RFC 2487 SMTP Service Extension January 1999
+
+
+C. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hoffman Standards Track [Page 8]
+
diff --git a/standards/rfc2554.txt b/standards/rfc2554.txt
new file mode 100644
index 000000000..2922deaee
--- /dev/null
+++ b/standards/rfc2554.txt
@@ -0,0 +1,619 @@
+
+
+
+
+
+
+Network Working Group J. Myers
+Request for Comments: 2554 Netscape Communications
+Category: Standards Track March 1999
+
+
+ SMTP Service Extension
+ for Authentication
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+
+1. Introduction
+
+ This document defines an SMTP service extension [ESMTP] whereby an
+ SMTP client may indicate an authentication mechanism to the server,
+ perform an authentication protocol exchange, and optionally negotiate
+ a security layer for subsequent protocol interactions. This
+ extension is a profile of the Simple Authentication and Security
+ Layer [SASL].
+
+
+2. Conventions Used in this Document
+
+ In examples, "C:" and "S:" indicate lines sent by the client and
+ server respectively.
+
+ The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
+ in this document are to be interpreted as defined in "Key words for
+ use in RFCs to Indicate Requirement Levels" [KEYWORDS].
+
+
+3. The Authentication service extension
+
+
+ (1) the name of the SMTP service extension is "Authentication"
+
+ (2) the EHLO keyword value associated with this extension is "AUTH"
+
+
+
+
+Myers Standards Track [Page 1]
+
+RFC 2554 SMTP Authentication March 1999
+
+
+ (3) The AUTH EHLO keyword contains as a parameter a space separated
+ list of the names of supported SASL mechanisms.
+
+ (4) a new SMTP verb "AUTH" is defined
+
+ (5) an optional parameter using the keyword "AUTH" is added to the
+ MAIL FROM command, and extends the maximum line length of the
+ MAIL FROM command by 500 characters.
+
+ (6) this extension is appropriate for the submission protocol
+ [SUBMIT].
+
+
+4. The AUTH command
+
+ AUTH mechanism [initial-response]
+
+ Arguments:
+ a string identifying a SASL authentication mechanism.
+ an optional base64-encoded response
+
+ Restrictions:
+ After an AUTH command has successfully completed, no more AUTH
+ commands may be issued in the same session. After a successful
+ AUTH command completes, a server MUST reject any further AUTH
+ commands with a 503 reply.
+
+ The AUTH command is not permitted during a mail transaction.
+
+ Discussion:
+ The AUTH command indicates an authentication mechanism to the
+ server. If the server supports the requested authentication
+ mechanism, it performs an authentication protocol exchange to
+ authenticate and identify the user. Optionally, it also
+ negotiates a security layer for subsequent protocol
+ interactions. If the requested authentication mechanism is not
+ supported, the server rejects the AUTH command with a 504
+ reply.
+
+ The authentication protocol exchange consists of a series of
+ server challenges and client answers that are specific to the
+ authentication mechanism. A server challenge, otherwise known
+ as a ready response, is a 334 reply with the text part
+ containing a BASE64 encoded string. The client answer consists
+ of a line containing a BASE64 encoded string. If the client
+ wishes to cancel an authentication exchange, it issues a line
+ with a single "*". If the server receives such an answer, it
+ MUST reject the AUTH command by sending a 501 reply.
+
+
+
+Myers Standards Track [Page 2]
+
+RFC 2554 SMTP Authentication March 1999
+
+
+ The optional initial-response argument to the AUTH command is
+ used to save a round trip when using authentication mechanisms
+ that are defined to send no data in the initial challenge.
+ When the initial-response argument is used with such a
+ mechanism, the initial empty challenge is not sent to the
+ client and the server uses the data in the initial-response
+ argument as if it were sent in response to the empty challenge.
+ Unlike a zero-length client answer to a 334 reply, a zero-
+ length initial response is sent as a single equals sign ("=").
+ If the client uses an initial-response argument to the AUTH
+ command with a mechanism that sends data in the initial
+ challenge, the server rejects the AUTH command with a 535
+ reply.
+
+ If the server cannot BASE64 decode the argument, it rejects the
+ AUTH command with a 501 reply. If the server rejects the
+ authentication data, it SHOULD reject the AUTH command with a
+ 535 reply unless a more specific error code, such as one listed
+ in section 6, is appropriate. Should the client successfully
+ complete the authentication exchange, the SMTP server issues a
+ 235 reply.
+
+ The service name specified by this protocol's profile of SASL
+ is "smtp".
+
+ If a security layer is negotiated through the SASL
+ authentication exchange, it takes effect immediately following
+ the CRLF that concludes the authentication exchange for the
+ client, and the CRLF of the success reply for the server. Upon
+ a security layer's taking effect, the SMTP protocol is reset to
+ the initial state (the state in SMTP after a server issues a
+ 220 service ready greeting). The server MUST discard any
+ knowledge obtained from the client, such as the argument to the
+ EHLO command, which was not obtained from the SASL negotiation
+ itself. The client MUST discard any knowledge obtained from
+ the server, such as the list of SMTP service extensions, which
+ was not obtained from the SASL negotiation itself (with the
+ exception that a client MAY compare the list of advertised SASL
+ mechanisms before and after authentication in order to detect
+ an active down-negotiation attack). The client SHOULD send an
+ EHLO command as the first command after a successful SASL
+ negotiation which results in the enabling of a security layer.
+
+ The server is not required to support any particular
+ authentication mechanism, nor are authentication mechanisms
+ required to support any security layers. If an AUTH command
+ fails, the client may try another authentication mechanism by
+ issuing another AUTH command.
+
+
+
+Myers Standards Track [Page 3]
+
+RFC 2554 SMTP Authentication March 1999
+
+
+ If an AUTH command fails, the server MUST behave the same as if
+ the client had not issued the AUTH command.
+
+ The BASE64 string may in general be arbitrarily long. Clients
+ and servers MUST be able to support challenges and responses
+ that are as long as are generated by the authentication
+ mechanisms they support, independent of any line length
+ limitations the client or server may have in other parts of its
+ protocol implementation.
+
+ Examples:
+ S: 220 smtp.example.com ESMTP server ready
+ C: EHLO jgm.example.com
+ S: 250-smtp.example.com
+ S: 250 AUTH CRAM-MD5 DIGEST-MD5
+ C: AUTH FOOBAR
+ S: 504 Unrecognized authentication type.
+ C: AUTH CRAM-MD5
+ S: 334
+ PENCeUxFREJoU0NnbmhNWitOMjNGNndAZWx3b29kLmlubm9zb2Z0LmNvbT4=
+ C: ZnJlZCA5ZTk1YWVlMDljNDBhZjJiODRhMGMyYjNiYmFlNzg2ZQ==
+ S: 235 Authentication successful.
+
+
+
+5. The AUTH parameter to the MAIL FROM command
+
+ AUTH=addr-spec
+
+ Arguments:
+ An addr-spec containing the identity which submitted the message
+ to the delivery system, or the two character sequence "<>"
+ indicating such an identity is unknown or insufficiently
+ authenticated. To comply with the restrictions imposed on ESMTP
+ parameters, the addr-spec is encoded inside an xtext. The syntax
+ of an xtext is described in section 5 of [ESMTP-DSN].
+
+ Discussion:
+ The optional AUTH parameter to the MAIL FROM command allows
+ cooperating agents in a trusted environment to communicate the
+ authentication of individual messages.
+
+ If the server trusts the authenticated identity of the client to
+ assert that the message was originally submitted by the supplied
+ addr-spec, then the server SHOULD supply the same addr-spec in an
+ AUTH parameter when relaying the message to any server which
+ supports the AUTH extension.
+
+
+
+
+Myers Standards Track [Page 4]
+
+RFC 2554 SMTP Authentication March 1999
+
+
+ A MAIL FROM parameter of AUTH=<> indicates that the original
+ submitter of the message is not known. The server MUST NOT treat
+ the message as having been originally submitted by the client.
+
+ If the AUTH parameter to the MAIL FROM is not supplied, the
+ client has authenticated, and the server believes the message is
+ an original submission by the client, the server MAY supply the
+ client's identity in the addr-spec in an AUTH parameter when
+ relaying the message to any server which supports the AUTH
+ extension.
+
+ If the server does not sufficiently trust the authenticated
+ identity of the client, or if the client is not authenticated,
+ then the server MUST behave as if the AUTH=<> parameter was
+ supplied. The server MAY, however, write the value of the AUTH
+ parameter to a log file.
+
+ If an AUTH=<> parameter was supplied, either explicitly or due to
+ the requirement in the previous paragraph, then the server MUST
+ supply the AUTH=<> parameter when relaying the message to any
+ server which it has authenticated to using the AUTH extension.
+
+ A server MAY treat expansion of a mailing list as a new
+ submission, setting the AUTH parameter to the mailing list
+ address or mailing list administration address when relaying the
+ message to list subscribers.
+
+ It is conforming for an implementation to be hard-coded to treat
+ all clients as being insufficiently trusted. In that case, the
+ implementation does nothing more than parse and discard
+ syntactically valid AUTH parameters to the MAIL FROM command and
+ supply AUTH=<> parameters to any servers to which it
+ authenticates using the AUTH extension.
+
+ Examples:
+ C: MAIL FROM:<e=mc2@example.com> AUTH=e+3Dmc2@example.com
+ S: 250 OK
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Myers Standards Track [Page 5]
+
+RFC 2554 SMTP Authentication March 1999
+
+
+6. Error Codes
+
+ The following error codes may be used to indicate various conditions
+ as described.
+
+ 432 A password transition is needed
+
+ This response to the AUTH command indicates that the user needs to
+ transition to the selected authentication mechanism. This typically
+ done by authenticating once using the PLAIN authentication mechanism.
+
+ 534 Authentication mechanism is too weak
+
+ This response to the AUTH command indicates that the selected
+ authentication mechanism is weaker than server policy permits for
+ that user.
+
+ 538 Encryption required for requested authentication mechanism
+
+ This response to the AUTH command indicates that the selected
+ authentication mechanism may only be used when the underlying SMTP
+ connection is encrypted.
+
+ 454 Temporary authentication failure
+
+ This response to the AUTH command indicates that the authentication
+ failed due to a temporary server failure.
+
+ 530 Authentication required
+
+ This response may be returned by any command other than AUTH, EHLO,
+ HELO, NOOP, RSET, or QUIT. It indicates that server policy requires
+ authentication in order to perform the requested action.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Myers Standards Track [Page 6]
+
+RFC 2554 SMTP Authentication March 1999
+
+
+7. Formal Syntax
+
+ The following syntax specification uses the augmented Backus-Naur
+ Form (BNF) notation as specified in [ABNF].
+
+ Except as noted otherwise, all alphabetic characters are case-
+ insensitive. The use of upper or lower case characters to define
+ token strings is for editorial clarity only. Implementations MUST
+ accept these strings in a case-insensitive fashion.
+
+ UPALPHA = %x41-5A ;; Uppercase: A-Z
+
+ LOALPHA = %x61-7A ;; Lowercase: a-z
+
+ ALPHA = UPALPHA / LOALPHA ;; case insensitive
+
+ DIGIT = %x30-39 ;; Digits 0-9
+
+ HEXDIGIT = %x41-46 / DIGIT ;; hexidecimal digit (uppercase)
+
+ hexchar = "+" HEXDIGIT HEXDIGIT
+
+ xchar = %x21-2A / %x2C-3C / %x3E-7E
+ ;; US-ASCII except for "+", "=", SPACE and CTL
+
+ xtext = *(xchar / hexchar)
+
+ AUTH_CHAR = ALPHA / DIGIT / "-" / "_"
+
+ auth_type = 1*20AUTH_CHAR
+
+ auth_command = "AUTH" SPACE auth_type [SPACE (base64 / "=")]
+ *(CRLF [base64]) CRLF
+
+ auth_param = "AUTH=" xtext
+ ;; The decoded form of the xtext MUST be either
+ ;; an addr-spec or the two characters "<>"
+
+ base64 = base64_terminal /
+ ( 1*(4base64_CHAR) [base64_terminal] )
+
+ base64_char = UPALPHA / LOALPHA / DIGIT / "+" / "/"
+ ;; Case-sensitive
+
+ base64_terminal = (2base64_char "==") / (3base64_char "=")
+
+ continue_req = "334" SPACE [base64] CRLF
+
+
+
+
+Myers Standards Track [Page 7]
+
+RFC 2554 SMTP Authentication March 1999
+
+
+ CR = %x0C ;; ASCII CR, carriage return
+
+ CRLF = CR LF
+
+ CTL = %x00-1F / %x7F ;; any ASCII control character and DEL
+
+ LF = %x0A ;; ASCII LF, line feed
+
+ SPACE = %x20 ;; ASCII SP, space
+
+
+
+
+8. References
+
+ [ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [CRAM-MD5] Klensin, J., Catoe, R. and P. Krumviede, "IMAP/POP
+ AUTHorize Extension for Simple Challenge/Response", RFC
+ 2195, September 1997.
+
+ [ESMTP] Klensin, J., Freed, N., Rose, M., Stefferud, E. and D.
+ Crocker, "SMTP Service Extensions", RFC 1869, November
+ 1995.
+
+ [ESMTP-DSN] Moore, K, "SMTP Service Extension for Delivery Status
+ Notifications", RFC 1891, January 1996.
+
+ [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [SASL] Myers, J., "Simple Authentication and Security Layer
+ (SASL)", RFC 2222, October 1997.
+
+ [SUBMIT] Gellens, R. and J. Klensin, "Message Submission", RFC
+ 2476, December 1998.
+
+ [RFC821] Postel, J., "Simple Mail Transfer Protocol", STD 10, RFC
+ 821, August 1982.
+
+ [RFC822] Crocker, D., "Standard for the Format of ARPA Internet
+ Text Messages", STD 11, RFC 822, August 1982.
+
+
+
+
+
+
+
+
+Myers Standards Track [Page 8]
+
+RFC 2554 SMTP Authentication March 1999
+
+
+9. Security Considerations
+
+ Security issues are discussed throughout this memo.
+
+ If a client uses this extension to get an encrypted tunnel through an
+ insecure network to a cooperating server, it needs to be configured
+ to never send mail to that server when the connection is not mutually
+ authenticated and encrypted. Otherwise, an attacker could steal the
+ client's mail by hijacking the SMTP connection and either pretending
+ the server does not support the Authentication extension or causing
+ all AUTH commands to fail.
+
+ Before the SASL negotiation has begun, any protocol interactions are
+ performed in the clear and may be modified by an active attacker.
+ For this reason, clients and servers MUST discard any knowledge
+ obtained prior to the start of the SASL negotiation upon completion
+ of a SASL negotiation which results in a security layer.
+
+ This mechanism does not protect the TCP port, so an active attacker
+ may redirect a relay connection attempt to the submission port
+ [SUBMIT]. The AUTH=<> parameter prevents such an attack from causing
+ an relayed message without an envelope authentication to pick up the
+ authentication of the relay client.
+
+ A message submission client may require the user to authenticate
+ whenever a suitable SASL mechanism is advertised. Therefore, it may
+ not be desirable for a submission server [SUBMIT] to advertise a SASL
+ mechanism when use of that mechanism grants the client no benefits
+ over anonymous submission.
+
+ This extension is not intended to replace or be used instead of end-
+ to-end message signature and encryption systems such as S/MIME or
+ PGP. This extension addresses a different problem than end-to-end
+ systems; it has the following key differences:
+
+ (1) it is generally useful only within a trusted enclave
+
+ (2) it protects the entire envelope of a message, not just the
+ message's body.
+
+ (3) it authenticates the message submission, not authorship of the
+ message content
+
+ (4) it can give the sender some assurance the message was
+ delivered to the next hop in the case where the sender
+ mutually authenticates with the next hop and negotiates an
+ appropriate security layer.
+
+
+
+
+Myers Standards Track [Page 9]
+
+RFC 2554 SMTP Authentication March 1999
+
+
+ Additional security considerations are mentioned in the SASL
+ specification [SASL].
+
+
+
+10. Author's Address
+
+ John Gardiner Myers
+ Netscape Communications
+ 501 East Middlefield Road
+ Mail Stop MV-029
+ Mountain View, CA 94043
+
+ EMail: jgmyers@netscape.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Myers Standards Track [Page 10]
+
+RFC 2554 SMTP Authentication March 1999
+
+
+11. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Myers Standards Track [Page 11]
+
diff --git a/standards/rfc2567.txt b/standards/rfc2567.txt
new file mode 100644
index 000000000..d5ef440be
--- /dev/null
+++ b/standards/rfc2567.txt
@@ -0,0 +1,2411 @@
+
+
+
+
+
+
+Network Working Group F.D. Wright
+Request for Comments: 2567 Lexmark International
+Category: Experimental April 1999
+
+
+ Design Goals for an Internet Printing Protocol
+
+Status of this Memo
+
+ This memo defines an Experimental Protocol for the Internet
+ community. It does not specify an Internet standard of any kind.
+ Discussion and suggestions for improvement are requested.
+ Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+IESG Note
+
+ This document defines an Experimental protocol for the Internet
+ community. The IESG expects that a revised version of this protocol
+ will be published as Proposed Standard protocol. The Proposed
+ Standard, when published, is expected to change from the protocol
+ defined in this memo. In particular, it is expected that the
+ standards-track version of the protocol will incorporate strong
+ authentication and privacy features, and that an "ipp:" URL type will
+ be defined which supports those security measures. Other changes to
+ the protocol are also possible. Implementers are warned that future
+ versions of this protocol may not interoperate with the version of
+ IPP defined in this document, or if they do interoperate, that some
+ protocol features may not be available.
+
+ The IESG encourages experimentation with this protocol, especially in
+ combination with Transport Layer Security (TLS) [RFC2246], to help
+ determine how TLS may effectively be used as a security layer for
+ IPP.
+
+Abstract
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ using Internet tools and technologies. This document takes a broad
+ look at distributed printing functionality, and it enumerates real-
+ life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+
+
+
+Wright Experimental [Page 1]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ administrators. The design goals document calls out a subset of end
+ user requirements that are satisfied in IPP/1.0. Operator and
+ administrator requirements are out of scope for version 1.0.
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol (this document)
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.0: Model and Semantics [RFC2568]
+ Internet Printing Protocol/1.0: Encoding and Transport [RFC2565]
+ Internet Printing Protocol/1.0: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specifications, and gives background and rationale for the
+ IETF working group's major decisions.
+
+ The "Internet Printing Protocol/1.0: Model and Semantics" document
+ describes a simplified model consisting of abstract objects, their
+ attributes, and their operations that is independent of encoding and
+ transport. The model consists of a Printer and a Job object. The
+ Job optionally supports multiple documents. IPP 1.0 semantics allow
+ end-users and operators to query printer capabilities, submit print
+ jobs, inquire about the status of print jobs and printers, and cancel
+ print jobs. This document also addresses security,
+ internationalization, and directory issues.
+
+ The "Internet Printing Protocol/1.0: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1. It defines the encoding rules
+ for a new Internet media type called "application/ipp".
+
+ The "Internet Printing Protocol/1.0: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.0 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+
+
+
+
+Wright Experimental [Page 2]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+TABLE OF CONTENTS
+
+ 1. INTRODUCTION.....................................................4
+ 2. TERMINOLOGY......................................................4
+ 3. DESIGN GOALS.....................................................6
+ 3.1. End-user.......................................................6
+ 3.1.1. Finding or locating a printer................................6
+ 3.1.2. Create an instance of the printer............................7
+ 3.1.3. Viewing the status and capabilities of a printer.............7
+ 3.1.4. Submitting a print job.......................................8
+ 3.1.5. Viewing the status of a submitted print job..................9
+ 3.1.6. Canceling a Print Job........................................9
+ 3.2. Operator (NOT REQUIRED FOR V1.0)...............................9
+ 3.2.1. Alerting.....................................................9
+ 3.2.2. Changing Print and Job Status...............................10
+ 3.3. Administrator (NOT REQUIRED FOR v1.0).........................10
+ 4. OBJECTIVES OF THE PROTOCOL......................................10
+ 4.1. SECURITY CONSIDERATIONS.......................................11
+ 4.2. Interaction with LPD (RFC1179)................................12
+ 4.3. Extensibility.................................................12
+ 4.4. Firewalls.....................................................13
+ 4.5. Internationalization..........................................13
+ 5. IPP SCENARIOS...................................................13
+ 5.1. Printer Discovery.............................................14
+ 5.2. Driver Installation...........................................15
+ 5.3. Submitting a Print Job........................................15
+ 5.4. Getting Status/Capabilities...................................16
+ 5.5. Asynchronous Notification.....................................17
+ 5.6. Job Canceling.................................................17
+ 6. Security Considerations.........................................18
+ 7. REFERENCES......................................................18
+ 8. ACKNOWLEDGMENTS.................................................19
+ 9. AUTHOR'S ADDRESS................................................19
+ 10. APPENDIX - DETAILED SCENARIOS..................................20
+ 10.1. Printer discovery within an enterprise.......................20
+ 10.2. Printer discovery across enterprises.........................21
+ 10.3. Printer discovery on the Internet -logical operations........21
+ 10.4. Printer discovery on the Internet - authentication...........22
+ 10.5. Driver Download..............................................23
+ 10.6. Submitting a print job as a file.............................24
+ 10.7. Submitting a print job with two documents....................24
+ 10.8. Submitting a print job as a file, printing fails.............25
+ 10.9. Submitting a print job with authentication, PRIVACY and
+ payment......................................................26
+ 10.10. Submitting a print job with decryption error................27
+ 10.11. Submitting a print job with authentication..................28
+ 10.12. Submitting a print job generated dynamically................29
+ 10.13. Submitting a print job with a Printer jam - CANCELED........29
+
+
+
+Wright Experimental [Page 3]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ 10.14. Submitting a print job with a Printer jam - recovered.......30
+ 10.15. Submitting a print job with server pull.....................31
+ 10.16. Submitting a print job with referenced resources............32
+ 10.17. Getting Capabilities........................................33
+ 10.17.1. Submission Attributes.....................................33
+ 10.17.2. Printer Capabilities......................................33
+ 10.18. Getting Status..............................................34
+ 10.18.1. Printer State/Status......................................34
+ 10.18.2. Job Status................................................34
+ 10.18.3. Status of All My Jobs.....................................34
+ 10.19. Asynchronous Notification...................................35
+ 10.19.1. Job Completion............................................35
+ 10.19.2. Job Complete with Data....................................35
+ 10.19.3. Print Job Fails...........................................35
+ 10.20. Cancel a job................................................36
+ 10.21. End to end Scenario - within an enterprise..................36
+ 10.22. End to end Scenario - across enterprises....................37
+ 10.23. End to End Scenario - on the internet.......................40
+ 11. Full Copyright Statement.......................................43
+
+1. INTRODUCTION
+
+ The IPP protocol is heavily influenced by the printing model
+ introduced in the Document Printing Application (DPA) [ISO10175]
+ standard. Although DPA specifies both end user and administrative
+ features, IPP version 1.0 (IPP/1.0) focuses only on end user
+ functionality.
+
+2. TERMINOLOGY
+
+ Internet Printing for the purposes of this document is the
+ application of Internet tools, programs, servers and networks to
+ allow end-users to print to a remote printer using, after initial
+ setup or configuration, the same methods, operations and paradigms as
+ would be used for a locally attached or a local area network attached
+ printer. This could include the use of HTTP servers and browsers and
+ other applications for providing static, dynamic and interactive
+ printer locating services, user installation, selection,
+ configuration, print job submission, printer capability inquiry and
+ status inquiry of remote printers and jobs.
+
+ For the purposes of this document, a WEB Browser is software
+ available from a number of sources including but not limited to the
+ following: Microsoft Internet Explorer, NCSA Mosaic, Netscape
+ Navigator, Sun Hot Java!. The major task of these products is to use
+ the Hypertext Transport Protocol (HTTP) to retrieve, interpret and
+ display Hypertext Markup Language (HTML). These products are often a
+ part of a complete Internet Printing system because they are often
+
+
+
+Wright Experimental [Page 4]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ used as a means of obtaining the status of or more information about
+ the printing system; however, they may not be present in all
+ implementations.
+
+ Throughout this document, 'printer' shall be interpreted to include
+ any device which is capable of marking on a piece of media using any
+ available technology. These design goals do not include support for
+ multi-tiered printing solutions involving servers (single or
+ multiple) logically in front of the actual printing device yet all
+ such configurations shall be supported but shall appear to the end-
+ user as only a single device.
+
+ Throughout this document 'driver' refers to the code installed in
+ some client operating system to generate the print data stream for
+ the intended printer. Some computing environments may not include a
+ separate printer driver. Rather, the generation of the proper print
+ data stream is accomplished in an application on that computer. How
+ such a computer environment or application is updated to support a
+ new printer now made available using IPP is outside the scope of IPP.
+ The actual details for installing a printer driver are operating
+ system dependent and are also outside the scope of IPP. See also
+ section 4.1 (SECURITY CONSIDERATIONS) for security implications of
+ driver download and installation.
+
+ The IPP protocol will support the following physical configurations:
+
+ - An IPP client talking to an IPP Printer object imbedded in a
+ single, physical output device.
+ - An IPP Client talking to a server containing one or more IPP
+ Printer objects. Each Printer object is associated with exactly one
+ physical output device supported by the server. The protocol
+ between the server and the output devices is undefined.
+ - An IPP Client talking to an IPP Printer object in a server. The
+ Printer object is associated with one or more physical output
+ devices, but the client only sees the Printer object, which is an
+ abstraction and represents all of the associated physical output
+ devices. The protocol between the server and the physical output
+ devices is undefined.
+
+ Throughout this document, certain design goals will be identified as
+ not being a part of version 1.0 (or V1.0) of the protocol or as being
+ satisfied by means outside of IPP. IPP is assumed to be one part, an
+ enabler, of a complete Internet Printing solution. For example
+ printer instance creation is not performed by but is enabled by the
+ protocol. Globally, none of the operator or administrators wants and
+ needs are included in the design goals for version 1.0. Some of the
+ end-user wants and needs may also be excluded from version 1.0 and
+ will be so noted in the description of them. Subsequent versions of
+
+
+
+Wright Experimental [Page 5]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ the protocol (e.g. V2.0) may include support for these initially
+ excluded wants and needs.
+
+3. DESIGN GOALS
+
+ The next three sections identify the design goals for an Internet
+ printing protocol from three roles assumed by humans: end-user,
+ operator, and administrator. The goals defined here are only those
+ that need to be addressed by an Internet printing protocol. Other
+ wants and needs, such as that the operator needs physical access to
+ the printer (e.g. to be able to load paper or clear jams) are not
+ covered by this document. Section 5 contains scenarios which provide
+ more detailed examples of the entire process including discovery,
+ status, printing and end-of-job reporting.
+
+3.1. END-USER
+
+ An end-user of a printer accepting jobs through the Internet is one
+ of the roles in which humans act. The end-user is the person that
+ will submit a job to be printed on the printer.
+
+ The wants and needs of the end-user are broken down into six
+ categories: finding/locating a printer, creating a local instance of
+ a printer, viewing printer status, viewing printer capabilities,
+ submitting a print job, viewing print job status, altering the
+ attributes of a print job.
+
+3.1.1. Finding or locating a printer.
+
+ End-users want to be able to find and locate printers to which they
+ are authorized to print. They want to be able to perform this
+ function using a standard WEB browser or other application. Multiple
+ criteria can be applied to find the printers needed. These criteria
+ include but are not limited to:
+
+ - by name (Printer 1, Joes-color-printer, etc.)
+ - by geographic location (bldg 1, Kentucky, etc.)
+ - by capability or attribute (color, duplex, legal paper, etc.)
+
+ Additionally, while it is outside of scope of IPP, end-users want to
+ be able to limit the scope of their searching to:
+
+ - inside a functional sub-domain
+ - include only a particular domain (lexmark.com)
+ - exclude specified domains
+
+
+
+
+
+
+Wright Experimental [Page 6]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ While an Internet printing protocol may not of itself include this
+ function, IPP must define and enable a directory schema which will
+ provide the necessary information for a directory service
+ implementation to consistently represent printers by their IPP
+ attributes.
+
+3.1.2. Create an instance of the printer.
+
+ After finding the desired printer, an end-user needs to be able to
+ create a local instance of that printer within the end-user operating
+ system or desktop. This local instance will vary depending upon the
+ printing paradigm of the operating system. For example, some UNIX
+ users will only want a queue or a reference to a remote printer
+ created on their machine while other UNIX users and Windows NT users
+ will want the queue and also the necessary icons and registry entries
+ to be created and initialized. Where required, drivers may need to
+ be downloaded from some repository and installed on the computer.
+ All necessary decompressing, unpacking, and other installation
+ actions should occur without end-user interaction or intervention
+ excepting initial approval by the end-user. Once the local instance
+ of the printer has been installed, it shall appear to the end-user of
+ the operating system and to the applications running there as any
+ other printer (local, local area network connected, or network
+ operating system connected) on the end-user desktop or environment.
+ IPP's role in this goal is simply to enable the creation of the
+ printer instance providing information such as where to locate a
+ printer driver for this printer, as an attribute of an IPP Printer.
+
+3.1.3. Viewing the status and capabilities of a printer.
+
+ Before using a selected printer or, in fact at any time, the end-user
+ needs the ability to verify the characteristics and status of both
+ printers and jobs queued for that printer. When checking the
+ characteristics of a printer, the end-user typically wants to be able
+ to determine the capability of the device, e.g.:
+
+ - supported media, commonly paper, by size and type
+ - paper handling capability, e.g. duplex, collating, finishing
+ - color capability
+
+ When checking the status of the printer and its print jobs, the end-
+ user typically wants to be able to determine:
+
+ - is the printer on-line?
+ - what are the defaults to be used for printing?
+ - how many jobs are queued for the printer?
+ - how are job priorities assigned? (outside the scope of IPP)
+
+
+
+
+Wright Experimental [Page 7]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+3.1.4. Submitting a print job.
+
+ Once the desired printer has been located and installed, the end-user
+ wants to print to that printer from normal applications using
+ standard methods. These normal applications include such programs as
+ word processors, spreadsheets, data-base applications, WEB browsers,
+ production printing applications, etc. Additionally, the end-user
+ may want to print a file already existing on the end-user's computer
+ -- "simple push". In addition to printing from an application and
+ simple push, the end-user needs to have the ability to submit a print
+ job by reference. Printing by reference is defined to mean as
+ submitting a job by providing a reference to an existing document.
+ The reference, a URI, will be resolved before the actual print
+ process occurs. Submitting a job by reference relieves the user from
+ downloading the document from the remote server and then sending it
+ via IPP to the printer. This saves both time and network bandwidth.
+
+ Some means shall be provided to determine if the format of a job
+ matches the capability of the printer. This can be done by one of
+ the following (all of which are outside of scope of the IPP
+ protocol):
+
+ - the end-user selects the correct printer driver
+ - the printer automatically selects the proper interpreter
+ - the end-user uses some other manual procedure.
+
+ A standard action shall be defined should the job's requirements not
+ match the capabilities of the printer.
+
+ Because the end-user does not want to know the details of the
+ underlying printing process, the protocol must support job-to-printer
+ capability matching (all implementations are not necessarily required
+ to implement this function.) This matching capability requires
+ knowing both the printer's capabilities and attributes and those
+ capabilities and attributes required by the job. Actions taken when
+ a print job requires capabilities or attributes that are not
+ available on the printer vary and can include but are not limited to:
+
+ - rejecting the print job
+ - redirecting the print job to another printer (Not in V1.0)
+ - printing the job, accepting differences in the appearance
+
+ Print jobs will also be submitted by background or batch applications
+ without human intervention.
+
+ End-users need the ability to set certain print job parameters at the
+ time the job is submitted. These parameters include but are not
+ limited to:
+
+
+
+Wright Experimental [Page 8]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ - number of copies
+ - single or two sided printing
+ - finishing
+ - job priority
+
+3.1.5. Viewing the status of a submitted print job.
+
+ After a job has been submitted to a printer, the end-user needs a way
+ to view the status of that job (i.e. job waiting, job printing, job
+ done) and to determine where the job is in the print queue.
+
+ In addition to the need to inquire about the status of a print job,
+ automatic notification of the completion of that job is also
+ required.
+
+ Notification means are not defined by the protocol but the protocol
+ must provide a means of enabling and disabling the notification.
+
+3.1.6. Canceling a Print Job
+
+ While a job is waiting to be printed or has been started but not yet
+ completed, the original creator/submitter of the print job (i.e. the
+ end-user) shall be able to cancel the job entirely (job is waiting)
+ or the remaining portion of it (job is printing.) Altering the print
+ job itself is not a V1.0 design goal.
+
+3.2. OPERATOR (NOT REQUIRED FOR V1.0)
+
+ An operator of a printer accepting jobs through the Internet is one
+ of the roles in which humans act. The operator has the
+ responsibility of monitoring the status of the printer as well as
+ managing and controlling the jobs at the device. These
+ responsibilities include but are not limited to the replenishing of
+ supplies (ink, toner, paper, etc.), the clearing of minor errors
+ (paper jams, etc.) and the re-prioritization of end-user jobs.
+ Operator wants and needs will not be addressed by V1.0 of the
+ protocol.
+
+ The wants and needs of the operator include all those of the end-user
+ but may include additional privileges. For example, an operator may
+ be able to view all print jobs on a printer while the end-user might
+ only be able to see his own jobs.
+
+3.2.1. Alerting.
+
+ One of the required operator functions is having the ability to
+ discover or to be alerted to changes in the status of a printer
+ particularly those changes that cause a printer to stop printing and
+
+
+
+Wright Experimental [Page 9]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ to be able to correct those problems. As such, an Internet printing
+ protocol shall be able to alert a designated operator or operators to
+ these conditions such as 'out of paper', 'out of ink', etc.
+ Additionally. the operator shall be able to, asynchronous to other
+ printer activity, inquire as to a printer's or a job's status.
+
+3.2.2. Changing Print and Job Status.
+
+ Another of the required operator functions is the ability to affect
+ changes to printer and job status remotely. For example, the
+ operator will need to be able to re-prioritize or cancel any print
+ jobs on a printer to which the operator has authority.
+
+3.3. ADMINISTRATOR (NOT REQUIRED FOR V1.0)
+
+ An administrator of a printer accepting jobs through the Internet is
+ one of the roles in which humans act. The administrator has the
+ responsibility of creating the printer instances and controlling the
+ authorization of other end-users and operators. Administrator wants
+ and needs will not be addressed by V1.0 of the protocol.
+
+ The wants and needs of the administrator include all those of the
+ end-user and, in some environments, some or all of those of the
+ operator. Minimally, the administrator must also have the tools,
+ programs, utilities and supporting protocols available to be able to:
+
+ - create an instance of a printer
+ - create, edit and maintain the list of authorized end-users
+ - create, edit and maintain the list of authorized operators
+ - create, edit and maintain the list of authorized
+ administrators
+ - create, customize, change or otherwise alter the manner in
+ which the status capabilities and other information about printers
+ and jobs are presented
+ - create, customize, or change other printer or job features
+ - administrate billing or other charge-back mechanisms
+ - create sets of defaults
+ - create sets of capabilities
+
+ The administrator must have the capability to perform all the above
+ tasks locally or remotely to the printer.
+
+4. OBJECTIVES OF THE PROTOCOL
+
+ The protocol to be defined by an Internet printing working group will
+ address the wants and needs of the end-user (V1.0). It will not, at
+ least initially, address the operator or administrator wants and
+ needs (V2.0).
+
+
+
+Wright Experimental [Page 10]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ The protocol defined shall be independent of the operating system of
+ both the client and the server. Generally, any platform capable of
+ supporting a WEB Browser should be capable of being a client.
+ Generally, any platform providing a WEB/HTTP server and printing
+ services should be capable of being a server. Usage of the WEB
+ Browser and Server is not required for IPP; the operating system,
+ operating system extensions or other applications may provide IPP
+ functionality directly.
+
+ In many environments such as Windows 95, Windows NT and OS/2, the
+ print data is created and transmitted to the printer on the fly
+ rather than being created, spooled and then transmitted to the
+ printer (a typical UNIX method.) The Internet Printing Protocol must
+ properly handle either methodology and make this transparent to the
+ end-user.
+
+4.1. SECURITY CONSIDERATIONS
+
+ It is required that the Internet Printing Protocol be able to operate
+ within a secure environment. Wherever reasonable, IPP ought to make
+ use of existing security protocols and services. IPP will not invent
+ new security features when the design goals described in this
+ document can be met by existing protocols and services. Examples of
+ such services include Secure Socket Layer Version 3 (SSL3) [SSL] and
+ HTTP Digest Access Authentication [RFC2069]. Note: SSL3 is not on
+ the IETF standards track.
+
+ Since we cannot anticipate the security levels or the specific
+ threats that any given IPP print administrator may be concerned with,
+ IPP must be capable of operating with different security mechanisms
+ and policies as required by the individual installation. The initial
+ security needs of IPP are derived from two primary considerations.
+ First, the printing environments described in this document take into
+ account that the client, the Printer, and the document to be printed
+ may each exist in different security domains. When objects are in
+ different security domains the design goals for authentication and
+ message protection may be much stronger than when they are all in the
+ same domain.
+
+ Secondly, the sensitivity and value of the content being printed will
+ vary from one instance of a print job to another. For example, a
+ publicly available document does not need the same level of
+ protection as a payroll document does. Message protection design
+ goals include data origin authentication, privacy, integrity, and
+ non-repudiation.
+
+
+
+
+
+
+Wright Experimental [Page 11]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ In many environments (e.g. Windows, OS/2) a printer driver may be
+ needed to create the proper datastream for printer. This document
+ discusses downloading such a new driver from a variety of sources.
+ Downloading and installing any software, including drivers) on a
+ computer exposes that computer to a number of security risks
+ including but not limited to:
+
+ - defective software
+ - malicious software (e.g. Trojan horses)
+ - inappropriate software (i.e. software doing something
+ deemed unreasonable by the user.)
+
+ As such, proper security considerations and actions need to be taken
+ by the user and/or a system administrator to prevent the compromising
+ of the computer. Administrators should configure downloading
+ mechanism for printer drivers in such a way as to be able to verify
+ the source of driver software and encrypt or otherwise protect that
+ software during download.
+
+ Examples including security considerations can be found in sections 5
+ (IPP SCENARIOS) and 10 (APPENDIX - DETAILED SCENARIOS) later in this
+ document.
+
+4.2. INTERACTION WITH LPD (RFC1179)
+
+ Many versions of UNIX and in fact other operating systems provide a
+ means of printing as described in [RFC1179] (Line Printer Daemon
+ Protocol.) This document describes the file formats for the control
+ and data files as well as the messages used by the protocol. Because
+ of the simplistic approach taken by this protocol, many manufacturers
+ have include proprietary enhancements and extensions to 'lpd.'
+ Because of this divergence and due to other design goals described in
+ this document, there is no requirement for backward compatibility or
+ interoperability with 'lpd'. However, a mapping of LPD functionality
+ and IPP functionality shall be provided so as to enable a gateway
+ between LPD and IPP.
+
+4.3. EXTENSIBILITY
+
+ The Internet Printing Protocol shall be extensible by several means
+ that facilitate interoperability and prevent implementation
+ collisions:
+
+ - by providing a process whereby implementers can submit proposals
+ for registration of new attributes and new enumerated values for
+ existing attributes.
+
+
+
+
+
+Wright Experimental [Page 12]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ * that require review and approval. The Internet Assigned
+ Number Authority (IANA) will be the repository for such
+ accepted registration proposals after review.
+
+ * that do not require review and approval. IANA will be the
+ repository for such registrations.
+
+ - by providing syntax in the protocol so that implementers may add
+ private (i.e. unregistered) attributes and enumerated attribute
+ values.
+
+ - by providing versioning and negotiation so as to enable future
+ implementations of IPP to interoperate with implementations of
+ version 1.0 of IPP.
+
+4.4. FIREWALLS
+
+ As stated in section 3 Design Goals, Internet printing shall, by
+ definition, support printing from one enterprise to another. As
+ such, the Internet printing protocol must be capable of passing
+ through firewalls and/or proxy servers (where enabled by the firewall
+ administrator) preferably without modification to the existing
+ firewall technology.
+
+4.5. INTERNATIONALIZATION
+
+ Users of Internet printing will come from all over the world. As
+ such, where appropriate, internationalization and localization will
+ be enabled for the protocol.
+
+5. IPP SCENARIOS
+
+ Each of the scenarios in this section describes a specific IPP
+ operation, such as submitting a print job. Section 10 contains
+ several detailed flows for each scenario to provide additional
+ detail. The examples should not be considered exhaustive, but
+ illustrative of the functions and features required in the protocol.
+ Flows are intended to be protocol neutral. It is not assumed that all
+ of the functions and features described in these scenarios will
+ necessarily be supported directly by IPP or in version 1.0 of IPP.
+
+ See the IPP Model and Semantics document for details on
+ configurations of clients, servers and firewalls.
+
+
+
+
+
+
+
+
+Wright Experimental [Page 13]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+5.1. PRINTER DISCOVERY
+
+ Client Directory Service
+ Service
+
+ +----------------------------------------------------------- >
+ give me information on printers with these characteristics
+
+
+ < -----------------------------------------------------------+
+ Information on Printers matching these characteristics
+
+ The objective of printer discovery is to locate printers that meet
+ the client's wants and needs. The Directory Service should provide
+ enough information for the client to make an initial choice. The
+ client may have to connect to each individual Printer offered to get
+ more detail. Not all information available from the Directory
+ Service is obtained using IPP; some information may be
+ administratively provided.
+
+ The actual protocol used between client and Directory or Name Service
+ is considered outside the scope of IPP. Printer Discover is included
+ in the scenarios to provide design goals for the directory schema for
+ IPP Printers and to further define Printer attributes.
+
+ Characteristics that might be considered when locating a Printer
+ include:
+
+ - capabilities of the Printer, e.g. PDLs supported
+ - physical location, e.g. in building 010
+ - driver required and location
+ - cost per page to print (outside the scope of IPP)
+ - whether or not printer is access controlled
+ - whether or not usage requires client authentication
+ - whether or not Printer can be authenticated
+ - whether or not payment is required for printing (outside the scope
+ of IPP)
+ - maximum job size (spool size) (outside the scope of IPP)
+ - whether or not Printer support compression (outside the scope of
+ IPP)
+ - whether or not Printer supports encryption
+ - administrative limits on this Printer
+ - maximum number of copies per job
+ - maximum number of pages per job
+
+
+
+
+
+
+
+Wright Experimental [Page 14]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Responses could additionally include:
+
+ - how to get more information
+ - web page
+ - telephone number
+ - help desk
+
+5.2. DRIVER INSTALLATION
+
+ Client Printer
+
+ +----------------------------------------------------------- >
+ Where can I find a driver & software to install it?
+
+
+ < -----------------------------------------------------------+
+ URIs for drivers and install software
+
+ Driver here refers to the code installed in some client operating
+ system to generate the print data stream for the intended printer.
+ The actual details for installing a printer driver are operating
+ system dependent and are also outside the scope of IPP. However, an
+ IPP printer or a directory service advertising an IPP Printer should
+ be capable of telling a client what drivers are available and/or
+ required, where they can be found, and provide pointers to
+ installation instructions, installation code or initialization
+ strings required to install the driver. See section 4.1 (SECURITY
+ CONSIDERATIONS) for security implications of driver download and
+ installation.
+
+5.3. SUBMITTING A PRINT JOB
+
+ Client IPP Printer
+
+ +----------------------------------------------------------- >
+ Here is a Print Job
+ - Job attributes
+ - Print data
+
+
+ < -----------------------------------------------------------+
+ Response
+
+ The protocol must support these sources of client data:
+
+ - Print data is a file submitted with the job
+ - Print data is generated on the fly by an application
+ - Print data is a file referenced by a URI
+
+
+
+Wright Experimental [Page 15]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ The protocol must handle overrun conditions in the printer and must
+ support overlapped printing and downloading of the file in devices
+ that are unable to spool files before printing them.
+
+ Every print request will have a response. Responses will indicate
+ success or failure of the request and provide information on failures
+ when they occur. Responses would include things like:
+
+ - Got the print job and queued it
+ - Got the print job and am printing it
+ - Got the print job, started to print it, but printing failed
+ - why it failed (e.g. unrecoverable PostScript error)
+ - state of the printer
+ - how much printed
+ - Got the print job but couldn't print it
+ - why it can't be printed
+ - state of the printer
+ - Got the print job but don't know what to do with it
+ - Didn't get a complete print job (e.g. communication failure)
+
+5.4. GETTING STATUS/CAPABILITIES
+
+ Client IPP Printer
+
+ +----------------------------------------------------------- >
+ Get status and/or capabilities of Printer
+
+
+ < -----------------------------------------------------------+
+ Status/Capabilities
+
+ Clients will need to get information about
+
+ - Static capabilities of the device
+ - Dynamic state of the Printer (e.g. out of paper)
+ - State of a specific job owned by this client
+ - State of all jobs owned by this client
+ - queued
+ - printing
+ - completed
+
+
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 16]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ - Job submission attributes supported/required
+ - scheduling attributes (e.g. priority)
+ - production attributes (e.g. number of copies)
+
+5.5. ASYNCHRONOUS NOTIFICATION
+
+ Client IPP Printer
+
+ +----------------------------------------------------------- >
+ Use the following method to notify me of Printer events
+
+ .
+ .
+ .
+ < -----------------------------------------------------------+
+ Asynchronous notification of Printer event
+
+ Clients must be able to request asynchronous notification for Printer
+ events such as
+
+ - job completion
+ - a fatal error that requires the job to be resubmitted
+ - a condition that severely impacts a queued job for this client
+ e.g. printer is out of paper
+
+ Note: end-user notification is a V1.0 design goal while operator
+ notification is for V2.0.
+
+5.6. JOB CANCELING
+
+ Client IPP Printer
+
+ +----------------------------------------------------------- >
+ Cancel the named job as indicated
+
+
+ < -----------------------------------------------------------+
+ Response (did it or not)
+
+ Similarly clients must be able to make changes to jobs which have
+ been submitted and are queued for printing. Changing of job
+ attributes should also be supported. Job modifications, holding and
+ releasing of jobs are not included in the design goals for IPP v1.0.
+
+
+
+
+
+
+
+
+Wright Experimental [Page 17]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+6. SECURITY CONSIDERATIONS
+
+ The security considerations for IPP are described in Section 4.1
+ above.
+
+7. REFERENCES
+
+ [ipp-iig] Hastings, T. and C. Manros, "Internet Printing
+ Protocol/1.0: Implementer's Guide", Work in Progress.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569, April
+ 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2568, April 1999.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Tuner, "Internet
+ Printing Protocol/1.0: Encoding and Transport", RFC 2565,
+ April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+ [ISO10175] ISO/IEC 10175, Document Printing Application, June 1996.
+
+ [RFC1179] McLaughlin, L., "Line Printer Daemon Protocol" RFC 1179,
+ August 1990.
+
+ [SSL] Netscape, The SSL Protocol, Version 3, (Text version
+ 3.02), November 1996.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 18]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+8. ACKNOWLEDGMENTS
+
+ This document draws heavily from preliminary work done by others
+ especially in the Printer Working Group (PWG). The author gratefully
+ acknowledges the specific contributions of:
+
+ Scott Isaacson Roger deBry
+ Novell Utah Valley State College
+ sisaacson@novell.com debryro@uvsc.edu
+
+ Carl-Uno Manros Robert Herriot
+ Xerox Sun
+ manros@cp10.es.xerox.com Robert.Herrior@pahv.xerox.xom
+
+ Tom Hastings Peter Zehler
+ Xerox Xerox
+ hastings@cp10.es.xerox.com Peter.Zehler@usa.xerox.com
+
+9. AUTHOR'S ADDRESS
+
+ F.D. (Don) Wright
+ Lexmark International
+ C14/035-3
+ 740 New Circle Rd
+ Lexington, KY 40550
+
+ Phone: 606-232-4808
+ Fax: 606-232-6740
+ EMail: don@lexmark.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 19]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+10. APPENDIX - DETAILED SCENARIOS
+
+ The following are more detailed scenarios illustrating how the
+ Internet Printing Protocol is expected to be used as a part of a
+ complete Internet Printing system. Some parts of the scenarios
+ include concepts, functions and information that may be outside of
+ the scope of version 1.0 of IPP (e.g. cost per page, payments means
+ available, etc.) The information contained herein is meant to be
+ generic. There may not be an exact wording or terminology match
+ between these scenarios and the implementation documents.
+
+10.1. PRINTER DISCOVERY WITHIN AN ENTERPRISE
+
+ A user wants to find a color Postscript printer in his/her enterprise
+ which will print transparencies. The client, directory service, and
+ printer are all behind the same corporate firewall. Because color
+ foils are expensive, printers of this type are access controlled and
+ require an account to be established so that printing can be billed
+ back to the using department. Note the request to find a printer
+ usable by Dept. J15. Drivers for all supported printers are
+ available from the server they are associated with. A help desk is
+ provided for end user support. The printer is unattended.
+
+ Client Directory Service
+
+ +---------------------------------------------------------- >
+ Find a printer with these characteristics
+ - prints color, prints transparencies
+ - prints Postscript
+ - is in building 003
+ - accessible by the client
+
+ < ----------------------------------------------------------+
+ Printer "Color-A"
+ - prints color, prints transparencies
+ - prints Postscript
+ - in room H-6, building 003
+ - driver ABC-Postscript-V1.3 required, here is URI
+ - cost is $.45 per page for color transparencies
+ - limit is 10 pages per job
+ - authentication required to use printer
+ - printer is unattended
+ - help desk at x5001
+
+ Printer "Color-B"
+ - prints color, prints transparencies
+ - prints Postscript
+ - in room J-10, building 003
+
+
+
+Wright Experimental [Page 20]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ - driver XYZ-Postscript-V2.4 required, here is URI
+ - cost is $1.25 page for color transparencies
+ - limit is 5 pages per job
+ - authentication is required to use printer
+ - printer is unattended
+ - help desk at x5001
+
+10.2. PRINTER DISCOVERY ACROSS ENTERPRISES
+
+ A user in Company A wants to find a public printer in a business
+ partner's enterprise (Company B) on which to print a purchase order.
+ The client is behind one corporate firewall and the directory service
+ and the printer are behind a different corporate firewall. Drivers
+ for all supported printers are available from the server they are
+ associated with. A web page is provided for end user support for
+ public printers.
+
+ Client Company B Directory Service
+
+ +---------------------------------------------------------- >
+ Find a printer with these characteristics
+ - prints black and white
+ - is in El Segundo, building A
+ - is a public printer
+
+ < ----------------------------------------------------------+
+ Printer "Public-A"
+ - prints black and white
+ - prints Postscript
+ - in El Segundo, room H-6, building A
+ - driver ABC-Postscript-V1.3 required, here is URI
+ - printer is public
+ - help available at http://xerox/elSegundo/publicPrinters
+
+ Printer "Public-B"
+ - prints black and white
+ - prints PCL/5e
+ - is in El Segundo, room J-10, building A
+ - driver XYZ-PCL-V2.4 required, here is URI
+ - printer is public
+ - help available at http://xerox/elSegundo/publicPrinters
+
+10.3. PRINTER DISCOVERY ON THE INTERNET -LOGICAL OPERATIONS
+
+ A student wants to print a paper on a printer at his neighborhood
+ Ink-o's print shop. The report was written using Microsoft Word. The
+ student is interested in the cost of printing since his budget is
+ limited. Note the use of logical operators to find this information.
+
+
+
+Wright Experimental [Page 21]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Client Ink-o's Directory Service
+
+ +---------------------------------------------------------- >
+ Find a Printer with these characteristics
+ - prints color or black and white
+ - costs less than $.50 per page
+ - tell me about resolution and marking technology
+
+ < ----------------------------------------------------------+
+ Printer "Color-A"
+ - prints color
+ - 600 dpi laser printer
+ - prints Postscript
+ - driver ABC-Postscript-V1.3 required, here is URI
+ - cost is $.50 per page for color
+ - payment required prior to submitting print job
+ - here is URI for more information on Ink-o's
+
+ Printer "Mono-B"
+ - prints black and white
+ - 300 dpi inkjet printer
+ - prints Postscript
+ - driver XYZ-Postscript-V2.4 required, here is URI
+ - cost is $0.35 page for black and white
+ - payment required prior to submitting print job
+ - here is URI for more information on Ink-o's
+
+10.4. PRINTER DISCOVERY ON THE INTERNET - AUTHENTICATION
+
+ An executive in her hotel room is finishing an important presentation
+ on her laptop computer. She connects to a local print shop through
+ the web to get a copy of her charts printed for tomorrow's
+ presentation. She must find a print shop that is convenient to her
+ hotel and can print color transparencies. She wants to be sure that
+ the printer can be authenticated and can accept encrypted data.
+
+ Client SirZippy Directory Service
+
+ +---------------------------------------------------------- >
+ Find a Printer with these characteristics
+ - prints color transparencies
+ - is in Boulder, Colorado
+ - Printer can be authenticated
+ - Printer supports encryption
+
+
+
+
+
+
+
+Wright Experimental [Page 22]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Tell me when you are open for business
+
+ < ----------------------------------------------------------+
+ Printer "Color-A"
+ - prints color transparencies
+ - prints Postscript
+ - driver ABC-Postscript-V1.3 required, here is URI
+ - payment required prior to submitting print job
+ - Printer can be authenticated
+ - Data can be encrypted
+ - Located at 1670 Pearl Street, Boulder, CO
+ - This Branch is open 24 hours a day
+
+
+ Printer "Color-B"
+ - prints color transparencies
+ - prints Postscript
+ - driver ABC-Postscript-V1.3 required, here is URI
+ - payment required prior to submitting print job
+ - Printer can be authenticated
+ - Data can be encrypted
+ - Located at 1220 Arapahoe, Boulder, CO
+ - This Branch is open from 9:00 am to 6:30 pm
+
+10.5. DRIVER DOWNLOAD
+
+ An end user in an enterprise wants to print a lengthy report on a
+ newly installed high speed PostScript printer. Since she will likely
+ use this printer often, she would like to download a driver and
+ install it on her workstation. She is running Windows 95. Note:
+ Driver download is not a V1.0 design goal.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Tell me where to find print drivers for you
+
+
+
+ < ----------------------------------------------------------+
+ Driver install file is at
+ http://www.ibm.com/drivers/NP12a/Win95
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 23]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+10.6. SUBMITTING A PRINT JOB AS A FILE
+
+ An end-user wants to submit a print job. The print file already
+ exists on his workstation. The client and printer are behind the same
+ corporate firewall. The printer is available to anyone behind the
+ firewall and no authorization or authentication is required. The data
+ is pushed to the printer. The printer is capable of spooling the
+ output. No errors occur.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - document is in Postscript format
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ Print job accepted and spooled
+ - job id = #12345
+ - current state of print job = spooled
+ - submission time = 02/12/97, 15:35
+ - printer state = printing
+
+10.7. SUBMITTING A PRINT JOB WITH TWO DOCUMENTS
+
+ An end-user wants to submit a print job. The print file already
+ exists on his workstation. The client and printer are behind the same
+ corporate firewall. The printer is available to anyone behind the
+ firewall and no authorization or authentication is required. The data
+ is pushed to the printer. The job consists of two separate documents.
+ The printer is capable of spooling the output. No errors occur.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+
+ < ----------------------------------------------------------+
+
+
+
+Wright Experimental [Page 24]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Print job accepted and spooled
+ - job id = #12345
+ - submission time = 02/12/97, 15:35
+ +---------------------------------------------------------- >
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ - OK
+
+ +---------------------------------------------------------- >
+ - here is the document to print, it is the last document.
+
+ < ----------------------------------------------------------+
+ - OK
+
+10.8. SUBMITTING A PRINT JOB AS A FILE, PRINTING FAILS
+
+ An end-user wants to submit a print job. The print file already
+ exists on his workstation. The client and printer are behind the same
+ corporate firewall. The printer is available to anyone behind the
+ firewall and no authorization or authentication is required. The data
+ is pushed to the printer. The printer is not capable of spooling the
+ output so it begins printing while still receiving the file. An error
+ occurs and the printer cannot complete printing (in this case the
+ user requires A4 paper and that paper size is not available on the
+ printer.)
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - document is in Postscript format
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ Print job accepted
+
+ - printing failed
+ - current state of print job = canceled (A4 not available)
+ - submission time = 02/12/97, 15:35
+ - printer state = ready
+
+
+
+
+
+Wright Experimental [Page 25]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+10.9. SUBMITTING A PRINT JOB WITH AUTHENTICATION, PRIVACY AND PAYMENT
+
+ A traveling executive needs to print a set of transparencies for an
+ important business meeting. The charts are in Lotus Freelance format
+ on his notebook computer. He has located a SirZippy print shop near
+ his hotel that will print color transparencies. Because the
+ information on the charts is sensitive, he wants to be sure that his
+ data is sent to the Printer in an encrypted format. He also wants to
+ authenticate the Printer. The Printer also authenticates the user.
+ Payment occurs across the Internet.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+
+ Mutual authentication and exchange of secret keys
+
+ +---------------------------------------------------------- >
+ Here is a print job (encrypted)
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - tell me where to pick up output
+ - document is in Postscript format
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ Print job accepted and spooled (encrypted)
+ - job id = #12345
+ - current state of print job = spooled
+ - submission time = 02/12/97, 15:35
+ - printer state = printing
+ - payment required to proceed with job
+ - pick up at 230 East Main after 3:30 pm today
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+ Payment transaction
+
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 26]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+10.10. SUBMITTING A PRINT JOB WITH DECRYPTION ERROR
+
+ A traveling executive needs to print a set of transparencies for an
+ important business meeting. The charts are in Lotus Freelance format
+ on his notebook computer. He has located a SirZippy print shop near
+ his hotel that will print color transparencies. Because the
+ information on the charts is sensitive, he wants to be sure that his
+ data is sent to the printer in an encrypted format. He also wants to
+ authenticate the printer. The printer also authenticates the user.
+ Payment occurs across the Internet. An error occurs during
+ decryption.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+ Mutual authentication and exchange of secret keys
+
+
+ +---------------------------------------------------------- >
+ Here is a print job (encrypted)
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - tell me where to pick up output
+ - document is in Postscript format
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ Print job accepted and spooled (encrypted)
+ - job id = #12345
+ - current state of print job = spooled
+ - submission time = 02/12/97, 15:35
+ - printer state = printing
+ - payment required to proceed with job
+ - pick up at 230 East Main after 3:30 pm today
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+ Payment transaction
+ .
+ .
+ .
+ < ----------------------------------------------------------+
+ Asynchronous response (email in this case)
+ - decryption failed on job #12345
+
+
+
+Wright Experimental [Page 27]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ - no pages printed
+ - current state of job = aborted
+
+10.11. SUBMITTING A PRINT JOB WITH AUTHENTICATION
+
+ An end-user wants to submit a print job. The print file already
+ exists on his workstation. The client and printer are behind the same
+ corporate firewall. The printer is available to anyone behind the
+ firewall but authentication and authorization is required.
+ Authorization takes place using the authenticated end-user's name.
+ The data is pushed to the printer. The printer is capable of spooling
+ the output.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+ Authentication
+
+ Note: An authentication failure would end the transaction at
+ this point.
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - tell me where to pick up output
+ - document is in Postscript format
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ Print job accepted and spooled
+ - job id = #12345
+ - current state of print job = spooled
+ - submission time = 02/12/97, 15:35
+ - printer state = printing
+
+
+
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 28]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+10.12. SUBMITTING A PRINT JOB GENERATED DYNAMICALLY
+
+ An end-user wants to submit a print job. The print data is generated
+ dynamically and is being transmitted by a printer driver on the
+ client workstation as available. The client and printer are behind
+ the same corporate firewall. The printer is available to anyone
+ behind the firewall and no authentication and authorization is
+ required. The data is pushed to the printer. The printer is capable
+ of spooling the output. No error occurs.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - document is in Postscript format
+ - here is the print job
+
+
+ < ----------------------------------------------------------+
+ Print data accepted and spooling started
+ - job id = #12345
+ - current job state = spooled
+ - submission time = 02/12/97, 15:35
+ - printer state = printing
+
+10.13. SUBMITTING A PRINT JOB WITH A PRINTER JAM - CANCELED
+
+ An end-user wants to submit a print job. The print data is generated
+ dynamically and is being transmitted by a printer driver on the
+ client workstation as available. The client and printer are behind
+ the same corporate firewall. The printer is available to anyone
+ behind the firewall and no authentication and authorization is
+ required. The data is pushed to the printer. The printer is not
+ capable of spooling the output. The printer jams notifies the user
+ and the user chooses to cancel the job.
+
+ Client IPP Printer
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+
+
+
+Wright Experimental [Page 29]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ - return status of the printer in response
+ - document is in Postscript format
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ Print data accepted and printing started
+ - job id = #12345
+
+ +---------------------------------------------------------- >
+ - What is the status of print job #12345?
+
+ < --------------------------------------------------------- +
+ - Job #12345 accepted but printer jammed, cannot continue
+
+ +---------------------------------------------------------- >
+ - Cancel job #12345
+
+ * Printer flushes remaining data
+ < ----------------------------------------------------------+
+ Print job terminated
+ - current job state = canceled
+ - submission time = 02/12/97, 15:35
+ - printer state = jammed
+
+10.14. SUBMITTING A PRINT JOB WITH A PRINTER JAM - RECOVERED
+
+ An end-user wants to submit a print job. The print data is generated
+ dynamically and is being transmitted by a printer driver on the
+ client workstation as available. The client and printer are behind
+ the same corporate firewall. The printer is available to anyone
+ behind the firewall and no authentication and authorization is
+ required. The data is pushed to the printer. The printer is not
+ capable of spooling the output. The printer jams, notifies the user
+ and the user clears the jam and elects to continue.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - document is in Postscript format
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+
+
+
+Wright Experimental [Page 30]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Print data accepted and printing started
+ - job id = #12345
+
+ < --------------------------------------------------------- +
+ - Notification: printer jammed, cannot continue
+
+ * Jam is clear by human intervention, printing continues
+
+ +---------------------------------------------------------- >
+ Here is the last part of the document to print
+
+ < ----------------------------------------------------------+
+ Print job received
+ - current job state = printing
+ - submission time = 02/12/97, 15:35
+ - printer state = printing
+
+10.15. SUBMITTING A PRINT JOB WITH SERVER PULL
+
+ An end-user wants to submit a print job. The print data is in a file
+ and is publicly available. It is pulled by the printer. The client
+ and printer are behind the same corporate firewall. The printer is
+ available to anyone behind the firewall and no authentication and
+ authorization is required. The printer is capable of spooling the
+ output. Printing may start before the entire job has been pulled.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Here is a print job
+
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+ - here is a reference to the data to be printed
+
+ < ----------------------------------------------------------+
+ Print data accepted and printing started
+ - job id = #12345
+ - current state of job = spooled
+ - submission time = 02/12/97, 13:15
+ - printer state = printing
+
+ .
+ .
+ < ----------------------------------------------------------+
+
+
+
+Wright Experimental [Page 31]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Get the file to be printed
+
+ +---------------------------------------------------------- >
+ Here it is
+
+ Note: Failure to find the file, would end the transaction
+ with an error at this point and an asynchronous
+ notification would be send to the Client.
+
+ < ----------------------------------------------------------+
+ Data received
+
+10.16. SUBMITTING A PRINT JOB WITH REFERENCED RESOURCES
+
+ An end-user wants to submit a print job. Part of the print data is
+ on a file on the user's workstation. It is pushed by the client, but
+ the print job requires some resource not included in the print file.
+ The client and printer are behind the same corporate firewall. The
+ printer is available to anyone behind the firewall and no
+ authentication and authorization is required. The printer is capable
+ of spooling the output. No errors occur.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job name = MyJob
+ - notify me by email when done printing
+ - print on iso-a4-white paper
+ - print on both sides of the paper
+ - return status of the printer in response
+
+ < ----------------------------------------------------------+
+ Print job accepted and spooled
+ - job id = #12345
+ - submission time = 02/12/97, 15:35
+
+ +---------------------------------------------------------- >
+ - here is the document to print
+
+ < ----------------------------------------------------------+
+ - OK
+
+ +---------------------------------------------------------- >
+ - here is the URI to print, it is the last document.
+
+ < ----------------------------------------------------------+
+ - OK
+
+
+
+Wright Experimental [Page 32]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ < ----------------------------------------------------------+
+ Get the external resource
+
+ +---------------------------------------------------------- >
+ Here it is
+
+10.17. GETTING CAPABILITIES
+
+10.17.1. Submission Attributes
+
+ An end-user wants to get the production and scheduling attributes
+ that are supported or required when submitting jobs to this printer.
+ The client will use these attributes when forming the subsequent
+ print request.
+
+ Client IPP Printer
+ +---------------------------------------------------------- >
+ I'm going to submit a Postscript job
+ give me your job submission attributes
+
+ < ----------------------------------------------------------+
+ Postscript production attributes for this Printer are:
+ - medium-select = us-letter-white, us-legal-white
+ - default is us-letter-white
+ - copies = 1,2,3,4,5
+ - default is 1
+ - print-quality = draft, normal, high
+ - default is draft
+ - sides = 1-sided, 2-sided-long-edge
+ - default is 2-sided-long-edge
+ - Job scheduling attributes for this Printer are:
+ - job-priority = 1,2,3
+ - default = 3
+
+10.17.2. Printer Capabilities
+
+ An end-user wants to determine the resolution, marking technology,
+ and PDLs supported by the printer.
+
+ Client IPP Printer
+ +---------------------------------------------------------- >
+ Please tell me the
+ - resolution of the printer
+ - the marking technology of the printer
+ - PDLs supported
+ < ----------------------------------------------------------+
+ Printer resolution = 600 dpi
+ Marking Technology = laser
+
+
+
+Wright Experimental [Page 33]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ PDLs supported = Postscript level 2, PCL/6
+
+10.18. GETTING STATUS
+
+10.18.1. Printer State/Status
+
+ An end-user wants to determine the state or status of the printer.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ What is the state of the printer?
+
+ < ----------------------------------------------------------+
+ Printer state = out-of-paper
+
+10.18.2. Job Status
+
+ An end user wants to get the status of a job he has submitted.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Please tell me the status of job #12345
+
+ < ----------------------------------------------------------+
+ Job #12345 is queued
+ it is number 3 in the queue
+ printer state = printing
+
+10.18.3. Status of All My Jobs
+
+ An end user wants to get a list of all of the jobs he has submitted
+ to this Printer.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ Please tell me the status of my jobs
+
+ < ----------------------------------------------------------+
+ Job #00012 is complete
+ Printed at 12:35 on 01/23/97
+
+ Job #09876 is printing
+
+ Job #12345 is queued
+ it is number 3 in the queue
+
+
+
+Wright Experimental [Page 34]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Job #34567 is queued
+ it is number 7 in the queue
+
+10.19. ASYNCHRONOUS NOTIFICATION
+
+10.19.1. Job Completion
+
+ An end-user wants to get notification of events that affect his print
+ jobs. Print job completes without error.
+
+ Client IPP Printer
+
+ < ----------------------------------------------------------+
+ Print job #123 completed
+
+10.19.2. Job Complete with Data
+
+ An end-user wants to get notification of events that affect his print
+ jobs. Print job completes, users asked for all end of job
+ information.
+
+ Client IPP Printer
+
+ < ----------------------------------------------------------+
+ Print job #123 completed
+ - total pages printed = 15
+ - number of copies printed = 3
+ - total cost to print = $7.45
+ - pick up copies in room H-6, building 005
+
+10.19.3. Print Job Fails
+
+ An end-user wants to get notification of events that affect his print
+ jobs. Print job fails. Printer is unattended.
+
+ Client IPP Printer
+
+ < ----------------------------------------------------------+
+ Print job #123 failed
+ - total pages printed = 15
+ - number of pages submitted = 25
+ - printer-state = jammed
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 35]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+10.20. CANCEL A JOB
+
+ The end-user submits a print job and later decides to cancel it.
+
+ Client IPP Printer
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+ Authentication.
+
+
+ +---------------------------------------------------------- >
+ Cancel job #1234
+
+ < ----------------------------------------------------------+
+ Job #1234 Canceled
+
+
+10.21. END TO END SCENARIO - WITHIN AN ENTERPRISE
+
+ An office worker prints on shared departmental printers. All printers
+ in the office are public, that is, no authentication or authorization
+ is required. Printers are protected from external access by a
+ firewall. No billing or accounting is required. Most printing is done
+ from desktop applications. A help desk is provided for printing
+ problems. Standard operating systems and applications are used.
+ Drivers are available, but are installed manually by support
+ personnel. This scenario assumes that drivers have been installed and
+ that drivers are not IPP aware, that is, they cannot communicate
+ across an IPP connection to obtain status and capabilities. IPP
+ printers appear in application pull-down menus. Printer
+ configuration data is hard wired into the driver.
+
+ End-user selects print from the application pull down menu. An IPP
+ printer is selected from the list of Printers offered
+
+ The driver puts up a dialogue with hard-wired set of options for this
+ printer. The end-user makes choices and submits job.
+
+ Client IPP Printer
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job-name = memo-to-boss
+ - notify me by email when job is complete
+ - print on us-letter-white paper
+ - print 1 copy
+ - print at normal quality
+ - print on 1 side
+
+
+
+Wright Experimental [Page 36]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ - give me the state of the printer in response
+
+ The driver generates the print data and passes it to the IPP driver a
+ piece at a time as it is generated.
+
+ +---------------------------------------------------------- >
+ Here is the print data
+
+
+ < ----------------------------------------------------------+
+ Print data received, file is spooled
+ - printer state = printing
+ - time submitted = 2/12/97, 15:35
+ - current job state = spooled
+
+ Client adds this job to list of current jobs. List of jobs and state
+ of each is available on a pull-down menu on the client.
+
+ End-user selects job #1234 from list and clicks on it to see its
+ status.
+
+ +---------------------------------------------------------- >
+ Give me the state of job #1234
+ and the state of the Printer
+
+ < ----------------------------------------------------------+
+ Job #1234 state = spooled
+ - it is number 3 in the queue
+ - printer state = printing
+
+ The job completes without error
+
+ < ----------------------------------------------------------+
+ Job #1234 completed
+ 12 of 12 pages printed
+
+10.22. END TO END SCENARIO - ACROSS ENTERPRISES
+
+ An office worker in Company A needs to print an office document on a
+ "public" printer at Company B, a business partner. Both companies
+ have corporate firewalls so the print request must flow out of A's
+ firewall and into B's firewall. The office worker can look at public
+ printers in Company B's directory service. The document is generated
+ by a desktop application. Since the printer is "public" no
+ authentication or authorization is required. A driver is downloaded.
+ The driver is IPP aware, that is, it can communicate dynamically
+ through the IPP protocol layer to obtain information about the
+ printer.
+
+
+
+Wright Experimental [Page 37]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Client Company B's Directory Service
+
+ End user connects to B's Directory service
+
+ +---------------------------------------------------------- >
+ Find a Printer with these characteristics
+ - public (no authorization or authentication required)
+ - is in Lexington, building 004
+ - prints black and white
+
+ < ----------------------------------------------------------+
+ Printer "Public-A"
+ - http://www.lexmark.com/pubprinter/a
+
+ Printer "Public-B"
+ - http://www.lexmark.com/pubprinter/b
+
+ End user selects Public-A
+
+ Client Public-A
+
+ +---------------------------------------------------------- >
+ Where can I find a driver for you?
+
+ < ----------------------------------------------------------+
+ Drivers at http://www.lexmark.com/pubprinters/a/os245
+
+ End user gets driver and installs it on his PC.
+
+ End-user selects print from the application pull down menu. "Public-
+ A" is selected from the list of Printers offered
+
+ +---------------------------------------------------------- >
+ I'm going to submit a print job
+ give me your job submission attributes
+
+ < ----------------------------------------------------------+
+
+ Production attributes for this Printer are:
+ - medium-select = us-letter-white, us-legal-white
+ - default is us-letter-white
+ - copies = 1,2,3,4,5
+ - default is 1
+ - print-quality = draft, normal, high
+ - default is draft
+ - sides = 1-sided, 2-sided-long-edge
+ - default is 2-sided-long-edge
+
+
+
+
+Wright Experimental [Page 38]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Job scheduling attributes for this Printer are:
+ - job-priority = 1,2,3
+ default = 3
+
+ Driver puts up dialogue with available options and fills in the
+ defaults.
+
+ End-user makes choices and submits job
+
+ +---------------------------------------------------------- >
+ Here is a print job
+ - job-name = memo-to-Don-Wright
+ - notify me by email when job is complete
+ - print on us-letter-white paper
+ - print 1 copy
+ - print at normal quality
+ - print on 1 side
+ - give me the state of the printer in response
+
+
+ The driver generates the print data and passes it to the IPP driver a
+ piece at a time.
+
+ +---------------------------------------------------------- >
+ Here is the print data
+
+ < ----------------------------------------------------------+
+ Print data received, and spooling started
+ print job id = #1234
+
+ Print data received, file is spooled
+
+ - printer state = printing
+ - time submitted = 2/12/97, 15:35
+ - current job state = spooled
+
+ Client adds this job to list of current jobs. List of jobs and state
+ of each is available on a pull-down menu on the client.
+
+ End-user selects job #1234 from list and clicks on it to see its
+ status.
+
+ +---------------------------------------------------------- >
+ Give me the state of job #1234
+ and the state of the Printer
+
+ < ----------------------------------------------------------+
+ Job #1234 state = spooled
+
+
+
+Wright Experimental [Page 39]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ - it is number 3 in the queue
+ - printer state = printing
+
+ * The job completes without error
+ < ----------------------------------------------------------+
+ Job #1234 completed
+ 12 of 12 pages printed
+
+10.23. END TO END SCENARIO - ON THE INTERNET
+
+ An executive in her hotel room is finishing an important presentation
+ on her laptop computer. She connects to a local print shop through
+ the web to get a copy of her charts printed for tomorrow's
+ presentation. She must find a print shop that is convenient and can
+ print color transparencies. She must download and temporarily install
+ a driver in order to generate the PDL required by the print shop.
+ Mutual authentication is required by the print shop and payment must
+ be made in advance. The job is encrypted on the wire to prevent
+ eavesdropping.
+
+ End-user completes presentation. She goes to the web and connects to
+ the SirZippy home page.
+
+ Client SirZippy Directory Service
+ +---------------------------------------------------------- >
+
+ Find me a printer with these characteristics
+ - Near Market Street in San Jose
+ - Prints color transparencies
+ - drivers can be downloaded
+ - supports privacy (encryption)
+ -
+
+ Available Printers matching these characteristics are looked up in the
+ Directory Service
+
+ < ----------------------------------------------------------+
+
+ Printer "Color-A"
+ - located at 123 First Street in San Jose
+ - URI is http://www.SirZippy.com/FirstStreet/Color-A
+ - prints color transparencies
+ - 600 dpi laser
+ - driver ABC-Postscript-V1.3 available at this URI
+ - cost = $.75 per page
+ - authentication required to use printer
+ - payment required prior to printing
+
+
+
+
+Wright Experimental [Page 40]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Printer "Color-B"
+ - located at 67 San Carlos Street, San Jose
+ - URI is http://www.SirZippy.com/SanCarlos/Color-B
+ - prints color transparencies
+ - 1200 dpi laser
+ - driver XYZ-PostScript-V4.3 available at this URI
+ - cost = $1.25 per page
+ - authentication required to use printer
+ - payment required prior to printing
+ - more information at this URI
+
+ The user decides to use the first printer because it is closer. She
+ connects to the URI given to get a driver.
+
+ Client Driver URI
+
+ +---------------------------------------------------------- >
+ I need a driver for "Color-A"
+
+
+ < ----------------------------------------------------------+
+ Driver installer is at http://www.xerox.com/prtdrvrs
+
+ Driver is installed
+
+ User connects to
+ "Color-A"
+
+ Client IPP Printer "Color-A"
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+ Mutual authentication and exchange of secret keys
+
+ +---------------------------------------------------------- >
+ I'm going to submit a print job
+ give me your job submission attributes
+
+ < ----------------------------------------------------------+
+ Production attributes for this Printer are:
+ - medium-select = us-letter-white, us-legal-white
+ - default is us-letter-white
+ - copies = 1,2,3,4,5
+ - default is 1
+ - print-quality = draft, normal, high
+ - default is draft
+ - sides = 1-sided, 2-sided-long-edge
+ - default is 2-sided-long-edge
+
+
+
+Wright Experimental [Page 41]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+ Job scheduling attributes for this Printer are:
+ - job-priority = 1,2,3
+ default = 3
+
+ Driver puts up dialogue with available options and fills in the
+ defaults.
+
+ End-user makes choices and submits job
+
+ +---------------------------------------------------------- >
+ Here is a print job
+
+ - job-name = presentation
+ - notify me by email when job is complete
+ - print on us-letter-transparency
+ - print 1 copy
+ - print at high quality
+ - print by 9:00 am tomorrow morning
+ - give me the state of the printer in response
+
+ The driver generates the print data and passes it to the IPP driver a
+ piece at a time.
+
+ +---------------------------------------------------------- >
+ Here is the print data
+
+ < ---------------------------------------------------------+
+ Print data received, and spooling started
+ print job id = #1234
+
+ Print data received, file is spooled
+ - printer state = printing
+ - time submitted = 2/12/97, 15:35
+ - current job state = held, waiting for payment
+
+ +---------------------------------------------------------- >
+ < ----------------------------------------------------------+
+ Payment transaction
+
+ < ----------------------------------------------------------+
+ Job is scheduled to print, pick up after 9:00am tomorrow
+ Thank you for using SirZippy
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 42]
+
+RFC 2567 Internet Printing Design Goals April 1999
+
+
+11. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Wright Experimental [Page 43]
+
diff --git a/standards/rfc2568.txt b/standards/rfc2568.txt
new file mode 100644
index 000000000..2d3ae4905
--- /dev/null
+++ b/standards/rfc2568.txt
@@ -0,0 +1,563 @@
+
+
+
+
+
+
+Network Working Group S. Zilles
+Request for Comments: 2568 Adobe Systems Inc.
+Category: Experimental April 1999
+
+
+ Rationale for the Structure of the Model and Protocol
+ for the Internet Printing Protocol
+
+Status of this Memo
+
+ This memo defines an Experimental Protocol for the Internet
+ community. It does not specify an Internet standard of any kind.
+ Discussion and suggestions for improvement are requested.
+ Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+IESG Note
+
+ This document defines an Experimental protocol for the Internet
+ community. The IESG expects that a revised version of this protocol
+ will be published as Proposed Standard protocol. The Proposed
+ Standard, when published, is expected to change from the protocol
+ defined in this memo. In particular, it is expected that the
+ standards-track version of the protocol will incorporate strong
+ authentication and privacy features, and that an "ipp:" URL type will
+ be defined which supports those security measures. Other changes to
+ the protocol are also possible. Implementors are warned that future
+ versions of this protocol may not interoperate with the version of
+ IPP defined in this document, or if they do interoperate, that some
+ protocol features may not be available.
+
+ The IESG encourages experimentation with this protocol, especially in
+ combination with Transport Layer Security (TLS) [RFC2246], to help
+ determine how TLS may effectively be used as a security layer for
+ IPP.
+
+ABSTRACT
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ using Internet tools and technologies. This document describes IPP
+ from a high level view, defines a roadmap for the various documents
+ that form the suite of IPP specifications, and gives background and
+ rationale for the IETF working group's major decisions.
+
+
+
+Zilles Experimental [Page 1]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol (this document)
+ Internet Printing Protocol/1.0: Model and Semantics [RFC2566]
+ Internet Printing Protocol/1.0: Encoding and Transport [RFC2565]
+ Internet Printing Protocol/1.0: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. The Design Goals document calls out a subset of end
+ user requirements that are satisfied in IPP/1.0. Operator and
+ administrator requirements are out of scope for version 1.0.
+
+ The "Internet Printing Protocol/1.0: Model and Semantics" document
+ describes a simplified model consisting of abstract objects, their
+ attributes, and their operations that is independent of encoding and
+ transport. The model consists of a Printer and a Job object. The
+ Job optionally supports multiple documents. This document also
+ addresses security, internationalization, and directory issues.
+
+ The "Internet Printing Protocol/1.0: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1. It defines the encoding rules
+ for a new Internet media type called "application/ipp".
+
+ The "Internet Printing Protocol/1.0: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.0 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+1. ARCHITECTURAL OVERVIEW
+
+ The Internet Printing Protocol (IPP) is an application level protocol
+ that can be used for distributed printing on the Internet. This
+ protocol defines interactions between a client and a server. The
+
+
+
+Zilles Experimental [Page 2]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+ protocol allows a client to inquire about capabilities of a printer,
+ to submit print jobs and to inquire about and cancel print jobs. The
+ server for these requests is the Printer; the Printer is an
+ abstraction of a generic document output device and/or a print
+ service provider. Thus, the Printer could be a real printing device,
+ such as a computer printer or fax output device, or it could be a
+ service that interfaced with output devices.
+
+ The protocol is heavily influenced by the printing model introduced
+ in the Document Printing Application (DPA) [ISO10175] standard.
+ Although DPA specifies both end user and administrative features, IPP
+ version 1.0 (IPP/1.0) focuses only on end user functionality.
+
+ The architecture for IPP defines (in the Model and Semantics document
+ [RFC2566]) an abstract Model for the data which is used to control
+ the printing process and to provide information about the process and
+ the capabilities of the Printer. This abstract Model is hierarchical
+ in nature and reflects the structure of the Printer and the Jobs that
+ may be being processed by the Printer.
+
+ The Internet provides a channel between the client and the
+ server/Printer. Use of this channel requires flattening and
+ sequencing the hierarchical Model data. Therefore, the IPP also
+ defines (in the Encoding and Transport document [RFC2565]) an
+ encoding of the data in the model for transfer between the client and
+ server. This transfer of data may be either a request or the
+ response to a request.
+
+ Finally, the IPP defines (in the Encoding and Transport document
+ [RFC2565]) a protocol for transferring the encoded request and
+ response data between the client and the server/Printer.
+
+ An example of a typical interaction would be a request from the
+ client to create a print job. The client would assemble the Model
+ data to be associated with that job, such as the name of the job, the
+ media to use, the number of pages to place on each media instance,
+ etc. This data would then be encoded according to the Protocol and
+ would be transmitted according to the Protocol. The server/Printer
+ would receive the encoded Model data, decode it into a form
+ understood by the server/Printer and, based on that data, do one of
+ two things: (1) accept the job or (2) reject the job. In either case,
+ the server must construct a response in terms of the Model data,
+ encode that response according to the Protocol and transmit that
+ encoded Model data as the response to the request using the Protocol.
+
+ Another part of the IPP architecture is the Directory Schema
+ described in the model document. The role of a Directory Schema is to
+ provide a standard set of attributes which might be used to query a
+
+
+
+Zilles Experimental [Page 3]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+ directory service for the URI of a Printer that is likely to meet the
+ needs of the client. The IPP architecture also addresses security
+ issues such as control of access to server/Printers and secure
+ transmissions of requests, response and the data to be printed.
+
+2. THE PRINTER
+
+ Because the (abstract) server/Printer encompasses a wide range of
+ implementations, it is necessary to make some assumptions about a
+ minimal implementation. The most likely minimal implementation is one
+ that is embedded in an output device running a specialized real time
+ operating system and with limited processing, memory and storage
+ capabilities. This printer will be connected to the Internet and will
+ have at least a TCP/IP capability with (likely) SNMP [RFC1905,
+ RFC1906] support for the Internet connection. In addition, it is
+ likely the the Printer will be an HTML/HTTP server to allow direct
+ user access to information about the printer.
+
+3. RATIONALE FOR THE MODEL
+
+ The Model [RFC2566] is defined independently of any encoding of the
+ Model data both to support the likely uses of IPP and to be robust
+ with respect to the possibility of alternate encoding.
+
+ It is expected that a client or server/Printer would represent the
+ Model data in some data structure within the applications/servers
+ that support IPP. Therefore, the Model was designed to make that
+ representation straightforward. Typically a parser or formatter would
+ be used to convert from or to the encoded data format. Once in an
+ internal form suitable to a product, the data can be manipulated by
+ the product. For example, the data sent with a Print Job can be used
+ to control the processing of that Print Job.
+
+ The semantics of IPP are attached to the (abstract) Model.
+ Therefore, the application/server is not dependent on the encoding of
+ the Model data, and it is possible to consider alternative mechanisms
+ and formats by which the data could be transmitted from a client to a
+ server; for example, a server could have a direct, client-less GUI
+ interface that might be used to accept some kinds of Print Jobs. This
+ independence would also allow a different encoding and/or
+ transmission mechanism to be used if the ones adopted here were shown
+ to be overly limiting in the future. Such a change could be migrated
+ into new products as an alternate protocol stack/parser for the Model
+ data.
+
+
+
+
+
+
+
+Zilles Experimental [Page 4]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+ Having an abstract Model also allows the Model data to be aligned
+ with the (abstract) model used in the Printer [RFC1759], Job and Host
+ Resources MIBs. This provides consistency in interpretation of the
+ data obtained independently of how the data is accessed, whether via
+ IPP or via SNMP [RFC1905, RFC1906] and the Printer/Job MIBs.
+
+ There is one aspect of the Model that deserves some extra
+ explanation. There are two ways for identifying a Job object: (a)
+ with a Job URI and (b) using a combination of the Printer URI and a
+ Job ID (a 32 bit positive integer). Allowing Job objects to have URIs
+ allows for flexibility and scalability. For example a job could be
+ moved from a printer with a large backlog to one with a smaller load
+ and the job identification, the Job object URI, need not change.
+ However, many existing printing systems have local models or
+ interface constraints that force Job objects to be identified using
+ only a 32-bit positive integer rather than a URI. This numeric Job
+ ID is only unique within the context of the Printer object to which
+ the create request was originally submitted. In order to allow both
+ types of client access to Jobs (either by Job URI or by numeric Job
+ ID), when the Printer object successfully processes a create request
+ and creates a new Job, the Printer object generates both a Job URI
+ and a Job ID for the new Job object. This requirement allows all
+ clients to access Printer objects and Job objects independent of any
+ local constraints imposed on the client implementation.
+
+4. RATIONALE FOR THE PROTOCOL
+
+ There are two parts to the Protocol: (1) the encoding of the Model
+ data and (2) the mechanism for transmitting the model data between
+ client and server.
+
+4.1 The Encoding
+
+ To make it simpler to develop embedded printers, a very simple binary
+ encoding has been chosen. This encoding is adequate to represent the
+ kinds of data that occur within the Model. It has a simple structure
+ consisting of sequences of attributes. Each attribute has a name,
+ prefixed by a name length, and a value. The names are strings
+ constrained to characters from a subset of ASCII. The values are
+ either scalars or a sequence of scalars. Each scalar value has a
+ length specification and a value tag which indicates the type of the
+ value. The value type has two parts: a major class part, such as
+ integer or string, and a minor class part which distinguishes the
+ usage of the major class, such as dateTime string. Tagging of the
+ values with type information allows for introducing new value types
+ at some future time.
+
+
+
+
+
+Zilles Experimental [Page 5]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+ A fully encoded request/response has a version number, an operation
+ (for a request) or a status and optionally a status message (for a
+ response), associated parameters and attributes which are encoded
+ Model data and, optionally (for a request), print data following the
+ Model data.
+
+4.2 The Transmission Mechanism
+
+ The chosen mechanism for transmitting the encoded Model data is HTTP
+ 1.1 Post (and associated response). No modifications to HTTP 1.1 are
+ proposed or required. The sole role of the Transmission Mechanism is
+ to provide a transfer of encoded Model data from/to the client
+ to/from the server. This could be done using any data delivery
+ mechanism. The key reasons why HTTP 1.1 Post is used are given below.
+ The most important of these is the first. With perhaps this
+ exception, these reasons could be satisfied by other mechanisms.
+ There is no claim that this list uniquely determines a choice of
+ mechanism.
+
+ 1. HTTP 1.0 is already widely deployed and, based on the recent
+ evidence, HTTP 1.1 is being widely deployed as the manufacturers
+ release new products. The performance benefits of HTTP 1.1 have
+ been shown and manufactures are reacting positively.
+
+ Wide deployment has meant that many of the problems of making a
+ protocol work in a wide range of environments from local net to
+ Intranet to Internet have been solved and will stay solved with
+ HTTP 1.1 deployment.
+
+ 2. HTTP 1.1 solves most of the problems that might have required a
+ new protocol to be developed. HTTP 1.1 allows persistent
+ connections that make a multi-message protocol be more efficient;
+ for example it is practical to have separate Create-Job and Send-
+ Document messages. Chunking allows the transmission of large print
+ files without having to pre-scan the file to determine the file
+ length. The accept headers allow the client's protocol and
+ localization desires to be transmitted with the IPP operations and
+ data. If the Model were to provide for the redirection of Job
+ requests, such as Cancel-Job, when a Job is moved, the HTTP
+ redirect response allows a client to be informed when a Job he is
+ interested in is moved to another server/Printer for any reason.
+
+ 3. Most network Printers will be implementing HTTP servers for
+ reasons other than IPP. These network attached Printers want to
+ provide information on how to use the printer, its current state,
+ HELP information, etc. in HTML. This requires having an HTTP
+ server which would be available to do IPP functions as well.
+
+
+
+
+Zilles Experimental [Page 6]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+ 4. Most of the complexity of HTTP 1.1 is concerned with the
+ implementation of HTTP proxies and not the implementation of HTTP
+ clients and/or servers. Work is proceeding in the HTTP Working
+ Group to help identify what must be done by a server. As the
+ Encoding and Transport document shows, that is not very much.
+
+ 5. HTTP implementations provide support for handling URLs that
+ would have to be provided if a new protocol were defined.
+
+ 6. An HTTP based solution fits well with the Internet security
+ mechanisms that are currently deployed or being deployed. HTTP
+ will run over SSL3. The digest access authentication mechanism of
+ HTTP 1.1 provides an adequate level of access control. These
+ solutions are deployed and in practical use; a new solution would
+ require extensive use to have the same degree of confidence in its
+ security. Note: SSL3 is not on the IETF standards track.
+
+ 7. HTTP provides an extensibility model that a new protocol would
+ have to develop independently. In particular, the headers,
+ intent-types (via Internet Media Types) and error codes have wide
+ acceptance and a useful set of definitions and methods for
+ extension.
+
+ 8. Although not strictly a reason why IPP should use HTTP as the
+ transmission protocol, it is extremely helpful that there are many
+ prototyping tools that work with HTTP and that CGI scripts can be
+ used to test and debug parts of the protocol.
+
+ 9. Finally, the POST method was chosen to carry the print data
+ because its usage for data transmission has been established, it
+ works and the results are available via CGI scripts or servlets.
+ Creating a new method would have better identified the intended
+ use of the POSTed data, but a new method would be more difficult
+ to deploy. Assigning a new default port for IPP provided the
+ necessary identification with minimal impact to installed
+ infrastructure, so was chosen instead.
+
+5. RATIONALE FOR THE DIRECTORY SCHEMA
+
+ Successful use of IPP depends on the client finding a suitable IPP
+ enabled Printer to which to send a IPP requests, such as print a
+ job. This task is simplified if there is a Directory Service which
+ can be queried for a suitable Printer. The purpose of the
+ Directory Schema is to have a standard description of Printer
+ attributes that can be associated the URI for the printer. These
+ attributes are a subset of the Model attributes and can be encoded
+ in the appropriate query syntax for the Directory Service being
+ used by the client.
+
+
+
+Zilles Experimental [Page 7]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+6. SECURITY CONSIDERATIONS - RATIONALE FOR SECURITY
+
+ Security is an area of active work on the Internet. Complete
+ solutions to a wide range of security concerns are not yet
+ available. Therefore, in the design of IPP, the focus has been on
+ identifying a set of security protocols/features that are
+ implemented (or currently implementable) and solve real problems
+ with distributed printing. The two areas that seem appropriate to
+ support are: (1) authorization to use a Printer and (2) secure
+ interaction with a printer. The chosen mechanisms are the digest
+ authentication mechanism of HTTP 1.1 and SSL3 [SSL] secure
+ communication mechanism.
+
+7. REFERENCES
+
+ [ipp-iig] Hastings, T. and C. Manros, "Internet Printing
+ Protocol/1.0:Implementer's Guide", Work in Progress.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569, April
+ 1999.
+
+ [RFC2566] deBry, R., Isaacson, S., Hastings, T., Herriot, R. and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Tuner, "Internet
+ Printing Protocol/1.0: Encoding and Transport", RFC 2565,
+ April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [ISO10175] ISO/IEC 10175 "Document Printing Application (DPA)", June
+ 1996.
+
+ [RFC1759] Smith, R., Wright, F., Hastings, T., Zilles, S. and J.
+ Gyllenskog, "Printer MIB", RFC 1759, March 1995.
+
+ [RFC1905] Case, J., McCloghrie, K., Rose, M. and S. Waldbusser,
+ "Protocol Operations for Version 2 of the Simple Network
+ Management Protocol (SNMPv2)", RFC 1905, January 1996.
+
+ [RFC1906] Case, J., McCloghrie, K., Rose, M. and S. Waldbusser,
+ "Transport Mappings for Version 2 of the Simple Network
+ Management Protocol (SNMPv2)", RFC 1906, January 1996.
+
+
+
+
+
+Zilles Experimental [Page 8]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+ [SSL] Netscape, The SSL Protocol, Version 3, (Text version
+ 3.02), November 1996.
+
+8. AUTHOR'S ADDRESS
+
+ Stephen Zilles
+ Adobe Systems Incorporated
+ 345 Park Avenue
+ MailStop W14
+ San Jose, CA 95110-2704
+
+ Phone: +1 408 536-4766
+ Fax: +1 408 537-4042
+ EMail: szilles@adobe.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Zilles Experimental [Page 9]
+
+RFC 2568 Rationale for IPP April 1999
+
+
+9. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Zilles Experimental [Page 10]
+
diff --git a/standards/rfc2569.txt b/standards/rfc2569.txt
new file mode 100644
index 000000000..767857c34
--- /dev/null
+++ b/standards/rfc2569.txt
@@ -0,0 +1,1571 @@
+
+
+
+
+
+
+Network Working Group R. Herriot
+Request For Comments: 2569 Xerox Corporation
+Category: Experimental N. Jacobs
+ Sun Microsystems, Inc.
+ T. Hastings
+ Xerox Corporation
+ J. Martin
+ Underscore, Inc.
+ April 1999
+
+
+ Mapping between LPD and IPP Protocols
+
+Status of this Memo
+
+ This memo defines an Experimental Protocol for the Internet
+ community. It does not specify an Internet standard of any kind.
+ Discussion and suggestions for improvement are requested.
+ Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+IESG Note
+
+ This document defines an Experimental protocol for the Internet
+ community. The IESG expects that a revised version of this protocol
+ will be published as Proposed Standard protocol. The Proposed
+ Standard, when published, is expected to change from the protocol
+ defined in this memo. In particular, it is expected that the
+ standards-track version of the protocol will incorporate strong
+ authentication and privacy features, and that an "ipp:" URL type will
+ be defined which supports those security measures. Other changes to
+ the protocol are also possible. Implementors are warned that future
+ versions of this protocol may not interoperate with the version of
+ IPP defined in this document, or if they do interoperate, that some
+ protocol features may not be available.
+
+ The IESG encourages experimentation with this protocol, especially in
+ combination with Transport Layer Security (TLS) [RFC 2246], to help
+ determine how TLS may effectively be used as a security layer for
+ IPP.
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 1]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+Abstract
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ using Internet tools and technologies. This document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon). This document describes the mapping between (1) the commands
+ and operands of the 'Line Printer Daemon (LPD) Protocol' specified in
+ RFC 1179 and (2) the operations, operation attributes and job
+ template attributes of the Internet Printing Protocol/1.0 (IPP). One
+ of the purposes of this document is to compare the functionality of
+ the two protocols. Another purpose is to facilitate implementation
+ of gateways between LPD and IPP.
+
+ WARNING: RFC 1179 was not on the IETF standards track. While RFC
+ 1179 was intended to record existing practice, it fell short in some
+ areas. However, this specification maps between (1) the actual
+ current practice of RFC 1179 and (2) IPP. This document does not
+ attempt to map the numerous divergent extensions to the LPD protocol
+ that have been made by many implementers.
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.0: Model and Semantics [RFC2566]
+ Internet Printing Protocol/1.0: Encoding and Transport [RFC2565]
+ Internet Printing Protocol/1.0: Implementors Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols (this document)
+
+ The document, "Design Goals for an Internet Printing Protocol", takes
+ a broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. Operator and administrator requirements are
+ out of scope for version 1.0.
+
+ The document, "Rationale for the Structure and Model and Protocol for
+ the Internet Printing Protocol", describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specifications, and gives background and rationale for the
+ IETF working group's major decisions.
+
+
+
+
+
+Herriot, et al. Experimental [Page 2]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ The document, "Internet Printing Protocol/1.0: Model and Semantics",
+ describes a simplified model with abstract objects, their attributes,
+ and their operations. It introduces a Printer and a Job object. The
+ Job object supports multiple documents per Job. It also addresses
+ security, internationalization, and directory issues.
+
+ The document, "Internet Printing Protocol/1.0: Encoding and
+ Transport", is a formal mapping of the abstract operations and
+ attributes defined in the model document onto HTTP/1.1. It defines
+ the encoding rules for a new Internet media type called '
+ application/ipp'.
+
+ This document "Internet Printing Protocol/1.0: Implementer's Guide",
+ gives advice to implementers of IPP clients and IPP objects.
+
+TABLE OF CONTENTS
+
+ 1. Introduction.....................................................4
+ 2. Terminology......................................................5
+ 3. Mapping from LPD Commands to IPP Operations......................5
+ 3.1 Print any waiting jobs..........................................6
+ 3.2 Receive a printer job...........................................6
+ 3.2.1 Abort job.....................................................7
+ 3.2.2 Receive control file..........................................7
+ 3.2.3 Receive data file.............................................8
+ 3.3 Send queue state (short)........................................8
+ 3.4 Send queue state (long)........................................10
+ 3.5 Remove jobs....................................................12
+ 4. Mapping of LPD Control File Lines to IPP Operation and Job
+ Template Attributes.............................................13
+ 4.1 Required Job Functions.........................................13
+ 4.2 Optional Job Functions.........................................14
+ 4.3 Required Document Functions....................................14
+ 4.4 Recommended Document Functions.................................16
+ 5. Mapping from IPP operations to LPD commands.....................16
+ 5.1 Print-Job......................................................16
+ 5.2 Print-URI......................................................18
+ 5.3 Validate-Job...................................................18
+ 5.4 Create-Job.....................................................18
+ 5.5 Send-Document..................................................18
+ 5.6 Send-URI.......................................................18
+ 5.7 Cancel-Job.....................................................18
+ 5.8 Get-Printer-Attributes.........................................19
+ 5.9 Get-Job-Attributes.............................................19
+ 5.10 Get-Jobs......................................................20
+ 6. Mapping of IPP Attributes to LPD Control File Lines.............20
+ 6.1 Required Job Functions.........................................21
+ 6.2 Optional Job Functions.........................................21
+
+
+
+Herriot, et al. Experimental [Page 3]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ 6.3 Required Document Functions....................................22
+ 7. Security Considerations.........................................23
+ 8. References......................................................23
+ 9. Authors' Addresses..............................................24
+ 10.Appendix A: ABNF Syntax for response of Send-queue-state (short)25
+ 11.Appendix B: ABNF Syntax for response of Send-queue-state (long) 26
+ 12.Appendix C: Unsupported LPD functions...........................27
+ 13.Full Copyright Statement........................................28
+
+1. Introduction
+
+ The reader of this specification is expected to be familiar with the
+ IPP Model and Semantics specification [RFC2566], the IPP Encoding and
+ Transport [RF2565], and the Line Printer Daemon (LPD) protocol
+ specification [RFC1179] as described in RFC 1179.
+
+ RFC 1179 was written in 1990 in an attempt to document existing LPD
+ protocol implementations. Since then, a number of undocumented
+ extensions have been made by vendors to support functionality
+ specific to their printing solutions. All of these extensions
+ consist of additional control file commands. This document does not
+ address any of these vendor extensions. Rather it addresses existing
+ practice within the context of the features described by RFC 1179.
+ Deviations of existing practice from RFC 1179 are so indicated.
+
+ Other LPD control file commands in RFC 1179 are obsolete. They are
+ intended to work on "text" only formats and are inappropriate for
+ many contemporary document formats that completely specify each page.
+ This document does not address the support of these obsolete
+ features.
+
+ In the area of document formats, also known as page description
+ languages (PDL), RFC 1179 defines a fixed set with no capability for
+ extension. Consequently, some new PDL's are not supported, and some
+ of those that are supported are sufficiently unimportant now that
+ they have not been registered for use with the Printer MIB [RFC1759]
+ and IPP [RFC2566] [RFC2565], though they could be registered if
+ desired. See the Printer MIB specification [RFC1759] and/or the IPP
+ Model specification [RFC2566] for instructions for registration of
+ document-formats with IANA. IANA lists the registered document-
+ formats as "printer languages".
+
+ This document addresses the protocol mapping for both directions:
+ mapping of the LPD protocol to the IPP protocol and mapping of the
+ IPP protocol to the LPD protocol. The former is called the "LPD-to-
+ IPP mapper" and the latter is called the "IPP-to-LPD mapper".
+
+
+
+
+
+Herriot, et al. Experimental [Page 4]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ This document is an informational document that is not on the
+ standards track. It is intended to help implementers of gateways
+ between IPP and LPD. It also provides an example, which gives
+ additional insight into IPP.
+
+2. Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC 2119 [RFC2119].
+
+ RFC 1179 uses the word "command" in two contexts: for over-the-wire
+ operations and for command file functions. This document SHALL use
+ the word "command" for the former and the phrase "functions" for the
+ latter. The syntax of the LPD commands is given using ABNF
+ [RFC2234].
+
+ The following tokens are used in order to make the syntax more
+ readable:
+
+ LF stands for %x0A (linefeed)
+ SP stands for %x20. (space)
+ DIGIT stands for %x30-39 ("0" to "9")
+
+3. Mapping from LPD Commands to IPP Operations
+
+ This section describes the mapping from LPD commands to IPP
+ operations. Each of the following sub-sections appear as sub-
+ sections of section 5 of RFC 1179.
+
+ The following table summarizes the IPP operation that the mapper uses
+ when it receives an LPD command. Each section below gives more
+ detail:
+
+ LPD command IPP operation
+
+
+ print-any-waiting-jobs ignore
+ receive-a-printer-job Print-Job or Create-Job/Send-Document
+ send queue state Get-Printer-Attributes and Get-Jobs
+ (short or long)
+ remove-jobs Cancel-Job
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 5]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+3.1 Print any waiting jobs
+
+ Command syntax:
+
+ print-waiting-jobs = %x01 printer-name LF
+
+ This command causes the LPD daemon check its queue and print any
+ waiting jobs. An IPP printer handles waiting jobs without such a
+ nudge.
+
+ If the mapper receives this LPD command, it SHALL ignore it and send
+ no IPP operation.
+
+3.2 Receive a printer job
+
+ Command syntax:
+
+ receive-job = %x02 printer-name LF
+
+ The control file and data files mentioned in the following paragraphs
+ are received via LPD sub-commands that follow this command. Their
+ mapping to IPP commands and attributes is described later in this
+ section.
+
+ The mapper maps the 'Receive a printer job' command to either:
+
+ - the Print-Job operation which includes a single data file or
+ - the Create-Job operation followed by one Send-Document operation
+ for each data file.
+
+ If the IPP printer supports both Create-Job and Send-Document, and if
+ a job consists of:
+
+ - a single data file, the mapper SHOULD use the Print-Job
+ operation, but MAY use the Create-Job and Send-Document
+ operations.
+ - more than one data file, the mapper SHALL use Create-Job
+ followed by one Send-Document for each received LPD data file.
+
+ If the IPP printer does not support both Create-Job and Send-
+ Document, and if a job consists of:
+
+ - a single data file, the mapper SHALL use the PrintJob
+ operation.
+ - more than one data file, the mapper SHALL submit each received
+ LPD data file as a separate Print-Job operation (thereby
+ converting a single LPD job into multiple IPP jobs).
+
+
+
+
+Herriot, et al. Experimental [Page 6]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ If the mapper uses Create-Job and Send-Document, it MUST send the
+ Create-Job operation before it sends any Send-Document operations
+ whether the LPD control file, which supplies attributes for Create-
+ Job, arrives before or after all LPD data files.
+
+ NOTE: This specification does not specify how the mapper maps: the
+ LPD Printer-name operand to the IPP "printer-uri" operation
+ attribute.
+
+ The following three sub-sections gives further details about the
+ mapping from LPD receive-a-printer-job sub-commands. Each of the
+ following subsections appear as sub-sections of section 6 of RFC
+ 1179.
+
+3.2.1 Abort job
+
+ Sub-command syntax:
+
+ abort-job = %x1 LF
+
+ This sub-command of receive-a-printer-job is intended to abort any
+ job transfer in process.
+
+ If the mapper receives this sub-command, it SHALL cancel the job that
+ it is in the process of transmitting.
+
+ If the mapper is in the process of sending a Print-Job or Create-Job
+ operation, it terminates the job either by closing the connection, or
+ performing the Cancel-Job operation with the job-uri that it received
+ from the Print-Job or Create-Job operation.
+
+ NOTE: This sub-command is implied if at any time the connection
+ between the LPD client and server is terminated before an entire
+ print job has been transferred via an LPD Receive-a-printer-job
+ request.
+
+3.2.2 Receive control file
+
+ Sub-command syntax:
+
+ receive-control-file = %x2 number-of-bytes SP name-of-control-file LF
+ number-of-bytes = 1*DIGIT
+ name-of-control-file = "cfA" job-number client-host-name
+ ; e.g. "cfA123woden"
+ job-number = 3DIGIT
+ client-host-name = <a host name>
+
+
+
+
+
+Herriot, et al. Experimental [Page 7]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ This sub-command is roughly equivalent to the IPP Create-Job
+ operation.
+
+ The mapper SHALL use the contents of the received LPD control file to
+ create IPP operation attribute and job template attribute values to
+ transmit with the Print-Job or Create-Job operation.
+
+3.2.3 Receive data file
+
+Sub-command syntax: %x3 number-of-bytes-in-data-file Name-of-data-file
+
+ receive-data-file = %x03 number-of-bytes SP name-of-data-file LF
+ number-of-bytes = 1*DIGIT
+ name-of-data-file = "df" letter job-number client-host-name
+ ; e.g. "dfA123woden for the first file
+ letter = %x41-5A / %x61-7A ; "A" to "Z", "a" to "z"
+ ; first file is "A",
+ ; second "B", and 52nd file is "z"
+ job-number = 3DIGIT
+ client-host-name = <a host name>
+
+ This sub-command is roughly equivalent to the IPP Send-Document
+ operation.
+
+ The mapper SHALL use the contents of the received LPD data file as
+ the data to transmit with the IPP Print-Job or Send-Document
+ operation.
+
+ Although RFC 1179 alludes to a method for passing an unspecified
+ length data file by using an octet-count of zero, no implementations
+ support this feature. The mapper SHALL reject a job that has a value
+ of 0 in the number-of-bytes field.
+
+3.3 Send queue state (short)
+
+ Command syntax:
+
+send-queue-short = %x03 printer-name *(SP(user-name / job-number)) LF
+
+ The mapper's response to this command includes information about the
+ printer and its jobs. RFC 1179 specifies neither the information nor
+ the format of its response. This document requires the mapper to
+ follow existing practice as specified in this document.
+
+ The mapper SHALL produce a response in the following format which
+ consists of a printer-status line optionally followed by a heading
+ line, and a list of jobs. This format is defined by examples below.
+ Appendix A contains the ABNF syntax.
+
+
+
+Herriot, et al. Experimental [Page 8]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ For an printer with no jobs, the response starts in column 1 and is:
+
+ no entries
+
+ For a printer with jobs, an example of the response is:
+
+ killtree is ready and printing
+ Rank Owner Job Files Total Size
+ active fred 123 stuff 1204 bytes
+ 1st smith 124 resume, foo 34576 bytes
+ 2nd fred 125 more 99 bytes
+ 3rd mary 126 mydoc 378 bytes
+ 4th jones 127 statistics.ps 4567 bytes
+ 5th fred 128 data.txt 9 bytes
+
+ The column numbers of above headings and job entries are:
+
+ | | | | |
+ 01 08 19 35 63
+
+ The mapper SHALL produce each field above from the following IPP
+ attribute:
+
+ LPD field IPP attribute special conversion details
+
+ printer- printer-state and For a printer-state of idle or
+ status printer-state-reasons processing, the mapper SHALL use
+ the formats above. For stopped,
+ the mapper SHALL use printer-
+ state-reasons to produce an
+ unspecified format for the error.
+ rank number-of- the mapper SHALL the format above
+ intervening-jobs
+ owner job-originating-user- unspecified conversion; job-
+ name originating-user-name may be the
+ mapper's user-name
+ job job-id the mapper shall use the job-id
+ files document-name the mapper shall create a comma
+ separated list of the document-
+ names and then truncate this list
+ to the first 24 characters
+ total- job-k- the mapper shall multiple the
+ size octets*copies*1024 value of job-k-octets by 1024 and
+ by the value of the "copies"
+ attribute.
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 9]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ A mapper SHOULD use the job attribute number-of-intervening-jobs
+ rather than the job's position in a list of jobs to determine 'rank'
+ because a Printer may omit jobs that it wants to keep secret. If a
+ printer doesn't support the job attribute number-of-intervening-jobs,
+ a mapper MAY use the job's position.
+
+ Note: a Printer may set the value of job-originating-user-name to the
+ authenticated user or to the value of "requesting-user-name",
+ depending on the implementation and configuration. For a gateway, the
+ authenticated user is the user-id of the gateway, but the
+ "requesting-user-name" may contain the name of the user who is the
+ gateway's client.
+
+ In order to obtain the information specified above, The LPD-to-IPP
+ mapper SHALL use the Get-Printer-Attributes operation to get
+ printer-status and SHOULD use the Get-Jobs operation to get
+ information about all of the jobs. If the LPD command contains job-
+ numbers or user-names, the mapper MAY handle the filtering of the
+ response. If the LPD command contains job-numbers but no user-names,
+ the mapper MAY use Get-Job-Attributes on each converted job-number
+ rather than Get-Jobs. If the LPD command contains a single user-name
+ but no job-numbers, the mapper MAY use Get-Jobs with the my-jobs
+ option if the server supports this option and if the server allows
+ the client to be a proxy for the LPD user.
+
+ NOTE: This specification does not define how the mapper maps the LPD
+ Printer-name operand to the IPP "printer-uri" operation attribute.
+
+3.4 Send queue state (long)
+
+ Command syntax:
+
+ send-queue-long = %x04 printer-name *(SP(user-name / job-number)) LF
+
+ The mapper's response to this command includes information about the
+ printer and its jobs. RFC 1179 specifies neither the information nor
+ the format of its response. This document requires the mapper to
+ follow existing practice as specified in this document.
+
+ The mapper SHALL produce a response in the following format which
+ consists of a printer-status line optionally followed a list of jobs,
+ where each job consists of a blank line, a description line, and one
+ line for each file. The description line contains the user-name,
+ rank, job-number and host. This format is defined by examples below.
+ Appendix B contain the ABNF syntax.
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 10]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ For an printer with no jobs the response is:
+
+ no entries
+
+ For a printer with jobs, an example of the response is:
+
+ killtree is ready and printing
+
+ fred: active [job 123 tiger]
+ 2 copies of stuff 602 bytes
+
+ smith: 1st [job 124 snail]
+ 2 copies of resume 7088 bytes
+ 2 copies of foo 10200 bytes
+
+ fred: 2nd [job 125 tiger]
+ more 99 bytes
+
+ The column numbers of above headings and job entries are:
+
+ | | |
+ 01 09 41
+
+ Although the format of the long form is different from the format of
+ the short form, their fields are identical except for a) the copies
+ and host fields which are only in the long form, and b) the "size"
+ field contains the single copy size of each file. Thus the sum of
+ the file sizes in the "size" field times the value of the "copies"
+ field produces the value for the "Total Size" field in the short
+ form. For fields other than the host and copies fields, see the
+ preceding section. For the host field see the table below.
+
+ LPD field IPP attribute special conversion details
+
+ host unspecified conversion; job-
+ originating-host may be the
+ mapper's host
+ copies copies the mapper shall assume the
+ value of copies precedes the
+ string "copies of "; otherwise,
+ the value of copies is 1.
+
+ NOTE: This specification does not define how the mapper maps the LPD
+ Printer-name operand to the IPP printer-uri operation attribute.
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 11]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+3.5 Remove jobs
+
+ Command syntax:
+
+ remove-jobs = %x05 printer-name SP agent
+ *(SP(user-name / job-number)) LF
+
+ The agent operand is the user-name of the user initiating the
+ remove-jobs command. The special user-name 'root' indicates a
+ privileged user who can remove jobs whose user-name differs from the
+ agent.
+
+ The mapper SHALL issue one Cancel-Job operation for each job
+ referenced by the remove-jobs command. Each job-number in the
+ remove-jobs command references a single job. Each user-name in the
+ remove-jobs command implicitly references all jobs owned by the
+ specified user. The active job is implicitly referenced when the
+ remove-jobs command contains neither job-numbers nor user-names. The
+ mapper MAY use Get-Jobs to determine the job-uri of implicitly
+ referenced jobs.
+
+ The mapper SHALL not use the agent name of 'root' when end-users
+ cancel their own jobs. Violation of this rule creates a potential
+ security violation, and it may cause the printer to issue a
+ notification that misleads a user into thinking that some other
+ person canceled the job.
+
+ If the agent of a remove-jobs command for a job J is the same as the
+ user name specified with the 'P' function in the control file for job
+ J, then the mapper SHALL ensure that the initiator of the Cancel-Job
+ command for job J is the same as job-originating-user for job J.
+
+ Note: This requirement means that a mapper must be consistent in who
+ the receiver perceives as the initiator of IPP operations. The mapper
+ either acts as itself or acts on behalf of another user. The latter
+ is preferable if it is possible. This consistency is necessary
+ between Print-Job/Create-Job and Cancel-Job in order for Cancel-Job
+ to work, but it is also desirable for other operations. For example,
+ Get-Jobs may give more information about job submitted by the
+ initiator of this operation.
+
+ NOTE: This specification does not define how the mapper maps: (1) the
+ LPD printer-name to the IPP "printer-uri" or (2) the LPD job-number
+ to the IPP "job-uri".
+
+ NOTE: This specification does not specify how the mapper maps the LPD
+ user-name to the IPP job-originating-user because the mapper may use
+ its own user-name with jobs.
+
+
+
+Herriot, et al. Experimental [Page 12]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+4. Mapping of LPD Control File Lines to IPP Operation and Job Template
+ Attributes
+
+ This section describes the mapping from LPD control file lines
+ (called 'functions') to IPP operation attributes and job template
+ attributes. The mapper receives the control file lines via the LPD
+ receive-control-file sub-command. Each of the LPD functions appear
+ as sub-sections of section 7 of RFC 1179.
+
+ In LPD control file lines, the text operands have a maximum length of
+ 31 or 99 while IPP operation attribute and job template attribute
+ values have a maximum of 255 or 1023 octets, depending on the
+ attribute syntax. Therefore, no data is lost.
+
+ The mapper converts each supported LPD function to its corresponding
+ IPP operation or job template attribute as defined by tables in the
+ subsections that follow. These subsections group functions according
+ to whether they are:
+
+ - required with a job,
+ - optional with a job
+ - required with each document.
+
+ In the tables below, each LPD value is given a name, such as 'h'. If
+ an IPP value uses the LPD value, then the IPP value column contains
+ the LPD name, such as 'h' to denote this. Otherwise, the IPP value
+ column specifies the literal value.
+
+4.1 Required Job Functions
+
+ The following LPD functions MUST be in a received LPD job. The mapper
+ SHALL receive each of the following LPD functions and SHALL include
+ the information as a operation or job template attribute with each
+ IPP job. The functions SHOULD be in the order 'H', 'P' and they
+ SHOULD be the first two functions in the control file, but they MAY
+ be anywhere in the control file and in any order:
+
+ LPD function IPP
+ name value description name value
+
+ H h Originating Host h (in security layer)
+ P u User identification requesting- u (and in security
+ user-name layer)
+ none ipp- 'true'
+ attribute-
+ fidelity
+
+
+
+
+
+Herriot, et al. Experimental [Page 13]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ A mapper MAY send its own host rather than the client's host, and a
+ mapper MAY send its own user-name as user identification rather than
+ the client user. But in any case, the values sent SHALL be compatible
+ with the Cancel-Job operation. The IPP operation MAY have no way to
+ specify an originating host-name.
+
+ The mapper SHALL include ipp-attribute-fidelity = true so that it
+ doesn't have to determine which attributes a printer supports.
+
+4.2 Optional Job Functions
+
+ The following LPD functions MAY be present in a received job. These
+ functions SHOULD follow the required job functions and precede the
+ document functions, but they MAY be anywhere in the control file.
+
+ If the mapper receives such an LPD function, the mapper SHALL include
+ the corresponding IPP attribute with the value converted as specified
+ in the table below. If the mapper does not receive such an LPD
+ attribute, the mapper SHALL NOT include the corresponding IPP
+ attribute, except the 'L' LPD function whose absence has a special
+ meaning as noted in the table.
+
+ LPD function IPP
+ name value description name value
+
+ J j Job name for job-name j
+ banner page
+ L l Print banner page job-sheets 'standard' if 'L' is
+ present
+ 'none' if 'L' is present
+ M m Mail When Printed IPP has no notification
+ mechanism. To support
+ this LPD feature, the
+ gateway must poll using
+ the Get-Job-Attributes
+ operation.
+
+4.3 Required Document Functions
+
+ The mapper SHALL receive one set of the required document functions
+ with each copy of a document, and SHALL include the converted
+ information as operation or job template attributes with each IPP
+ document.
+
+ If the control file contains required and recommended document
+ functions, the required functions SHOULD precede the recommended ones
+ and if the job contains multiple documents, all the functions for
+
+
+
+
+Herriot, et al. Experimental [Page 14]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ each document are grouped together as shown in the example of section
+ 6.3 "Required Document Functions". However, the document functions
+ MAY be in any order.
+
+ LPD function IPP
+ name value description name value
+
+ f fff Print formatted document-format 'application/octet-
+ file stream'
+ l fff Print file leaving document-format 'application/octet-
+ control characters stream'
+ o fff Print Postscript document-format 'application/PostScri
+ output file pt'
+ copies see note
+
+ Note: In practice, the 'f' LPD function is often overloaded. It is
+ often used with any format of document data including PostScript and
+ PCL data.
+
+ Note: In practice, the 'l' LPD function is often used as a rough
+ equivalent to the 'f' function.
+
+ Note: When RFC 1179 was written, no implementation supported the 'o'
+ function; instead 'f' was used for PostScript. Windows NT now sends '
+ o' function for a PostScript file.
+
+ Note: the value 'fff' of the 'f', 'l' and 'o' functions is the name
+ of the data file as transferred, e.g. "dfA123woden".
+
+ If the mapper receives any other lower case letter, the mapper SHALL
+ reject the job because the document contains a format that the mapper
+ does not support.
+
+ The mapper determines the number of copies by counting the number of
+ occurrences of each 'fff' file with one of the lower-case functions
+ above. For example, if 'f dfA123woden' occurs 4 times, then copies
+ has a value of 4. Although the LPD protocol allows the value of
+ copies to be different for each document, the commands and the
+ receiving print systems don't support this.
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 15]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+4.4 Recommended Document Functions
+
+ The mapper SHOULD receive one set of the recommended document
+ functions with each document, and SHOULD include the converted
+ information as an operation or job template attribute with each IPP
+ document. The functions SHOULD be received in the order 'U' and 'N',
+ but they MAY arrive in any order.
+
+ LPD function IPP
+ name value description name value
+
+ U fff ignored
+ N n Name of source file document-name n
+
+ Note: the value 'fff' of the 'U' function is the name of the data
+ file as transferred, e.g. "dfA123woden".
+
+5. Mapping from IPP operations to LPD commands
+
+ If the IPP-to-LPD mapper receives an IPP operation, the following
+ table summarizes the LPD command that it uses. Each section below
+ gives the detail. Each of the following sub-sections appear as sub-
+ sections of section 3 in the document "Internet Printing
+ Protocol/1.0: Model and Semantics" [RFC2566].
+
+ IPP operation LPD command
+
+ Print-Job or Print-URI or receive-a-printer-job
+ Create-Job/Send-Document/Send-URI and then print-any-waiting-jobs
+ Validate-Job implemented by the mapper
+ Cancel-Job remove-jobs
+ Get-Printer-Attributes, Get-Job- send queue state (short or long)
+ Attributes or Get-Jobs
+
+5.1 Print-Job
+
+ The mapper SHALL send the following commands in the order listed
+ below:
+
+ - receive-a-printer-job command
+ - both receive-control-file sub-command and receive-data-file
+ sub-command (unspecified order, see Note below)
+ - print-any-waiting-jobs command, except that if the mapper is
+ sending a sequence of receive a printer-job commands, it MAY
+ omit sending print-any-waiting-jobs after any receive a
+ printer-job command that is neither the first nor last command
+ in this sequence
+
+
+
+
+Herriot, et al. Experimental [Page 16]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ Note: it is recommended that the order of the receive-control-file
+ subcommand and the receive-data-file sub-command be configurable
+ because either order fails for some print systems. Some print systems
+ assume that the control file follows all data files and start
+ printing immediately on receipt of the control file. When such a
+ print system tries to print a data file that has not arrived, it
+ produces an error. Other print systems assume that the control file
+ arrives before the data files and start printing when the first data
+ file arrives. Such a system ignores the control information, such as
+ banner page or copies.
+
+ NOTE: This specification does not define the mapping between the IPP
+ printer-uri and the LPD printer-name.
+
+ The mapper SHALL send the IPP operation attributes and job template
+ attributes received from the operation to the LPD printer by using
+ the LPD receive-control-file sub-command. The mapper SHALL create the
+ LPD job-number for use in the control file name, but the receiving
+ printer MAY, in some circumstances, assign a different job-number to
+ the job. The mapper SHALL create the IPP job-id and IPP job-uri
+ returned in the Print-Job response.
+
+ NOTE: This specification does not specify how the mapper determines
+ the LPD job-number, the IPP job-id or the IPP job-uri of a job that
+ it creates nor does it specify the relationship between the IPP job-
+ uri, IPP the job-id and the LPD job-number, both of which the mapper
+ creates. However, it is likely that the mapper will use the same
+ integer value for both the LPD job-number and the IPP job-id, and
+ that the IPP Job-uri is the printer's URI with the job-id
+ concatenated on the end.
+
+ The mapper SHALL send data received in the IPP operation to the LPD
+ printer by using the LPD receive-data-file sub-command. The mapper
+ SHALL specify the exact number of bytes being transmitted in the
+ number-of-bytes field of the receive-data-file sub-command. It SHALL
+ NOT use a value of 0 in this field.
+
+ If the mapper, while it is transmitting a receive-a-printer-job
+ command or sub-command, either detects that its IPP connection has
+ closed or receives a Cancel-Job operation, the mapper SHALL terminate
+ the LPD job either with the abort sub-command or the remove-jobs
+ command.
+
+ This document does not address error code conversion.
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 17]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+5.2 Print-URI
+
+ The mapper SHALL handle this operation in the same way as a Print-Job
+ operation except that it SHALL obtain data referenced by the
+ "document-uri" operation attribute and SHALL then treat that data as
+ if it had been received via a Print-Job operation.
+
+5.3 Validate-Job
+
+ The mapper SHALL perform this operation directly. Because LPD
+ supports very few attributes, this operation doesn't have much to
+ check.
+
+5.4 Create-Job
+
+ The mapper SHALL handle this operation like Print-Job, except:
+
+ - the mapper SHALL send the control file after it has received the
+ last Send-Document or Send-URI operation because the control
+ file contains all the document-name and document-format values
+ specified in the Send-Document and Send-URI operations.
+ - the mapper SHALL perform one receive-data-file sub-command for
+ each Send-Document or Send-URI operation received and in the
+ same order received.
+ - the mapper SHALL send the control file either before all data
+ files or after all data files. (See the note in the section on
+ Print-Job about the dilemma of sending the control file either
+ before or after the data files.
+
+5.5 Send-Document
+
+ The mapper performs a receive-data-file sub-command on the received
+ data. See the preceding section 5.4 "Create-Job" for the details.
+
+5.6 Send-URI
+
+ The mapper SHALL obtain the data referenced by the "document-uri"
+ operation attribute, and SHALL then treat that data as if it had been
+ received via a Send-Document operation. See the preceding section 5.5
+ "Send-Document" for the details.
+
+5.7 Cancel-Job
+
+ The mapper SHALL perform a remove-jobs command with the following
+ operation attributes:
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 18]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ - the printer is the one to which the job was submitted, that is
+ the IPP printer-uri is mapped to an LPD printer-name by the same
+ mechanism as for all commands
+ - the agent is the authenticated user-name of the IPP client
+ - the job-number is the job-id returned by the Print-Job command,
+ that is, the LPD job-number has the same value as the IPP job-id
+ for likely implementations
+
+5.8 Get-Printer-Attributes
+
+ LPD severely limits the set of attributes that the mapper is able to
+ return in its response for this operation. The mapper SHALL support,
+ at most, the following printer attributes:
+
+ - printer-state
+ - printer-state-reasons
+
+ The mapper uses either the long or short form of the "send queue
+ state" command.
+
+ The mapper SHALL assume that the LPD response that it receives has
+ the format and information specified in section 3.3 "Send queue state
+ (short)" and section 3.4 "Send queue state (long)". The mapper SHALL
+ determine the value of each requested attribute by using the inverse
+ of the mapping specified in the two aforementioned sections.
+
+ Note: the mapper can determine the response from the printer-status
+ line without examining the rest of the LPD response.
+
+5.9 Get-Job-Attributes
+
+ LPD severely limits the set of attributes that the mapper is able to
+ return in its response for this operation. The mapper SHALL support,
+ at most, the following job attributes:
+
+ - number-of-intervening-jobs
+ - job-originating-user-name
+ - job-id
+ - document-name
+ - job-k-octets
+ - copies
+
+ The mapper uses either the long or short form of the "send queue
+ state" command. If it receives a request for the "job-k-octets" or
+ "copies" and supports the attribute it SHALL use the long form;
+ otherwise, it SHALL use the short form.
+
+
+
+
+
+Herriot, et al. Experimental [Page 19]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ Note: the value of job-k-octets is the value in the short form
+ divided by the number of "copies" which is on the long form only. Its
+ value can also be determined by adding the "size" field values for
+ each document in the job in the long form.
+
+ The mapper SHALL assume that the LPD response that it receives has
+ the format and information specified in section 3.3 "Send queue state
+ (short)" and section 3.4 "Send queue state (long)". The mapper SHALL
+ determine the value of each requested attribute by using the inverse
+ of the mapping specified in the two aforementioned sections.
+
+ Note: when the mapper uses the LPD short form, it can determine the
+ response from the single LPD line that pertains to the job specified
+ by the Get-Job-Attributes operation.
+
+ Note: the mapper can use its correspondence between the IPP job-id,
+ job-uri and the LPD job-number.
+
+5.10 Get-Jobs
+
+ The mapper SHALL perform this operation in the same way as Get-Job-
+ Attributes except that the mapper converts all the LPD job-lines, and
+ the IPP response contains one job object for each job-line in the LPD
+ response.
+
+6. Mapping of IPP Attributes to LPD Control File Lines
+
+ This section describes the mapping from IPP operation attributes and
+ job template attributes to LPD control file lines (called '
+ functions'). The mapper receives the IPP operation attributes and job
+ template atributes via the IPP operation. Each of the IPP operation
+ attributes and job template attributes appear as sub-sections of
+ section 3 and 4.2 in the IPP model document [RFC2566].
+
+ In the context of LPD control file lines, the text operands have a
+ maximum length of 31 or 99 while IPP operation attributes and job
+ template attributes have a maximum of 255 or 1023 octets, depending
+ on the attribute syntax. Therefore, there may be some data loss if
+ the IPP operation attribute and job template attribute values exceed
+ the maximum length of the LPD equivalent operands.
+
+ The mapper converts each supported IPP operation attribute and job
+ template attribute to its corresponding LPD function as defined by
+ tables in the subsections that follow. These subsections group
+ functions according to whether they are:
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 20]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ - required with a job,
+ - optional with a job
+ - required with each document.
+
+ In the tables below, each IPP value is given a name, such as 'h'. If
+ an LPD value uses the IPP value, then the LPD value column contains
+ the IPP name, such as 'h' to denote this. Otherwise, the LPD value
+ column specifies the literal value.
+
+6.1 Required Job Functions
+
+ The mapper SHALL include the following LPD functions with each job,
+ and they SHALL have the specified value. They SHALL be the first
+ functions in the control file and they SHALL be in the order "H" and
+ then "P".
+
+ IPP LPD function
+ name value name value description
+
+ (perhaps in security h H gateway host Originating Host
+ layer)
+ requesting-user-name u P u User identification
+ and in the security
+ layer
+
+ A mapper SHALL sends its own host rather than the client's host,
+ because some LPD systems require that it be the same as the host from
+ which the remove-jobs command comes. A mapper MAY send its own user
+ name as user identification rather than the client user. But in any
+ case, the values sent SHALL be compatible with the LPD remove-jobs
+ operation.
+
+6.2 Optional Job Functions
+
+ The mapper MAY include the following LPD functions with each job.
+ They SHALL have the specified value if they are sent. These
+ functions, if present, SHALL follow the require job functions, and
+ they SHALL precede the required document functions.
+
+ IPP attribute LPD function
+ name value name value description
+
+ job-name j J j Job name for banner
+ page
+ job-sheets 'standard' L u Print banner page
+ job-sheets 'none' omit 'L' function
+
+
+
+
+
+Herriot, et al. Experimental [Page 21]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ Note: 'L' has special meaning when it is omitted. If 'J' is omitted,
+ some undefined behavior occurs with respect to the banner page.
+
+6.3 Required Document Functions
+
+ The mapper SHALL include one set of the following LPD functions with
+ each document, and they SHALL have the specified values. For each
+ document, the order of the functions SHALL be 'f', 'U' and then 'N',
+ where 'f' is replicated once for each copy.
+
+ IPP attribute LPD function
+
+ name value name value description
+
+ document- 'application/octet- f fff Print formatted file
+ format stream' or
+ 'application/PostScript'
+ copies c replicate 'f' 'c'
+ times
+ none U fff Unlink data file
+ document- n N n Name of source file
+ name
+
+ Note: the value 'fff' of the 'f' and 'U' functions is the name of the
+ data file as transferred, e.g. "dfA123woden".
+
+ Note: the mapper SHALL not send the 'o' function
+
+ ISSUE: should we register DVI, troff or ditroff?
+
+ If the mapper receives no "ipp-attribute-fidelitybest-effort" or it
+ has a value of false, then the mapper SHALL reject the job if it
+ specifies attributes or attribute values that are not among those
+ supported in the above tables.
+
+ Below is an example of the minimal control file for a job with three
+ copies of two files 'foo' and 'bar':
+
+ H tiger
+ P jones
+ f dfA123woden
+ f dfA123woden
+ f dfA123woden
+ U dfA123woden
+ N foo
+ f dfB123woden
+ f dfB123woden
+ f dfB123woden
+
+
+
+Herriot, et al. Experimental [Page 22]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+ U dfB123woden
+ N bar
+
+7. Security Considerations
+
+ There are no security issues beyond those covered in the IPP Encoding
+ and Transport document [RFC2565], the IPP model document [RFC2566]
+ and the LPD document [RFC1179].
+
+8. References
+
+ [ipp-iig] Hasting, T., et al., "Internet Printing Protocol/1.0:
+ Implementer's Guide", Work in Progress.
+
+ [RFC1759] Smith, R., Wright, F., Hastings, T., Zilles, S., and J.
+ Gyllenskog, "Printer MIB", RFC 1759, March 1995.
+
+ [RFC1179] McLaughlin, L., "Line Printer Daemon Protocol", RFC 1179,
+ August 1990.
+
+ [RFC2119] Bradner, S. "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2234] D. Crocker et al., "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Tuner, "Internet
+ Printing Protocol/1.0: Encoding and Transport", RFC 2565,
+ April 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S., and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 23]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+9. Authors' Addresses
+
+ Robert Herriot (Editor)
+ Xerox Corporation
+ 3400 Hillview Ave., Bldg #1
+ Palo Alto, CA 94304
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ EMail: rherriot@pahv.xerox.com
+
+
+ Norm Jacobs
+ Sun Microsystems Inc.
+ 1430 Owl Ridge Rd.
+ Colorado Springs, CO 80919
+
+ Phone: 719-532-9927
+ Fax: 719-535-0956
+ EMail: Norm.Jacobs@Central.sun.com
+
+
+ Thomas N. Hastings
+ Xerox Corporation
+ 701 S. Aviation Blvd., ESAE-231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ EMail: hastings@cp10.es.xerox.com
+
+
+ Jay Martin
+ Underscore, Inc.
+ 41-C Sagamore Park Road
+ Hudson, NH 03051-4915
+
+ Phone: 603-889-7000
+ Fax: 603-889-2699
+ EMail: jkm@underscore.com
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 24]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+10. Appendix A: ABNF Syntax for response of Send-queue-state (short)
+
+ The syntax in ABNF for the response to the LPD command 'send-queue-
+ state (long)' is:
+
+ status-response = empty-queue / nonempty-queue
+ empty-queue = "no-entries" LF
+ nonempty-queue = printer-status LF heading LF *(job LF)
+ printer-status = OK-status / error-status
+ OK-status = printer-name SP "ready and printing" LF
+ error-status = < implementation dependent status information >
+ heading = "Rank" 3SP "Owner" 6SP "Job" 13SP "Files"
+ 23SP "Total Size" LF
+ ; the column headings and their values below begin
+ at the columns
+ ; 1, 8, 19, 35 and 63
+ job = rank *SP owner *SP job *SP files *SP total-size "bytes"
+ ; jobs are in order of oldest to newest
+ rank = "active" / "1st" / "2nd" / "3rd" / integer "th"
+ ; job that is printing is "active"
+ ; other values show position in the queue
+ owner = <user name of person who submitted the job>
+ job = 1*3DIGIT ; job-number
+ files = <file name> *( "," <file name>) ; truncated to 24 characters
+ total-size = 1*DIGIT ; combined size in bytes of all documents
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 25]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+11. Appendix B: ABNF Syntax for response of Send-queue-state (long)
+
+ The syntax in ABNF for the response to the LPD command 'send-queue-
+ state (long)' is:
+
+ status-response = empty-queue / nonempty-queue
+ empty-queue = "no-entries" LF
+ nonempty-queue = printer-status LF *job
+ printer-status = OK-status / error-status
+ OK-status = printer-name SP "ready and printing" LF
+ error-status = < implementation dependent status information >
+ job = LF line-1 LF line-2 LF
+ line-1 = owner ":" SP rank 1*SP "[job" job SP host "]"
+ line-2 = file-name 1*SP document-size "bytes"
+ ; jobs are in order of oldest to newest
+ rank = "active" / "1st" / "2nd" / "3rd" / integer "th"
+ ; job that is printing is "active"
+ ; other values show position in the queue
+ owner = <user name of person who submitted the job>
+ job = 1*3DIGIT
+ file-name = [ 1*DIGIT "copies of" SP ] <file name>
+ ; truncated to 24 characters
+ document-size = 1*DIGIT ;size of single copy of the document.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 26]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+12. Appendix C: Unsupported LPD functions
+
+ The follow LPD functions have no IPP equivalent. The LPD-to-IPP
+ mapper ignores them and the IPP-to-LPD mapper does not send them.
+
+ LPD command
+ name description
+
+ C Class for banner page
+ I Indent Printing
+ H Host of client
+ M Mail when printed
+ S Symbolic link data
+ T Title for pr
+ W Width of output
+ 1 troff R font
+ 2 troff I font
+ 3 troff B font
+ 4 troff S font
+
+ The follow LPD functions specify document-formats which have no IPP
+ equivalent, unless someone registers them. The LPD-to-IPP mapper
+ rejects jobs that request such a document format, and the IPP-to-LPD
+ mapper does not send them.
+
+ LPD command
+ name description
+
+ c Plot CIF file
+ d Print DVI file
+ g Plot file
+ k reserved for Kerberized clients and servers
+ n Print ditroff output file
+ p Print file with 'pr' format
+ r File to print with FORTRAN carriage control
+ t Print troff output file
+ v Print raster file
+ z reserved for future use with the Palladium
+ print system
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 27]
+
+RFC 2569 Mapping between LPD and IPP Protocols April 1999
+
+
+13. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Experimental [Page 28]
+
diff --git a/standards/rfc2578.txt b/standards/rfc2578.txt
new file mode 100644
index 000000000..0c1423c24
--- /dev/null
+++ b/standards/rfc2578.txt
@@ -0,0 +1,2541 @@
+
+
+
+
+
+
+
+Network Working Group Editors of this version:
+Request for Comments: 2578 K. McCloghrie
+STD: 58 Cisco Systems
+Obsoletes: 1902 D. Perkins
+Category: Standards Track SNMPinfo
+ J. Schoenwaelder
+ TU Braunschweig
+ Authors of previous version:
+ J. Case
+ SNMP Research
+ K. McCloghrie
+ Cisco Systems
+ M. Rose
+ First Virtual Holdings
+ S. Waldbusser
+ International Network Services
+ April 1999
+
+
+ Structure of Management Information Version 2 (SMIv2)
+
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+
+Table of Contents
+
+ 1 Introduction .................................................3
+ 1.1 A Note on Terminology ......................................4
+ 2 Definitions ..................................................4
+ 2.1 The MODULE-IDENTITY macro ..................................5
+ 2.2 Object Names and Syntaxes ..................................5
+ 2.3 The OBJECT-TYPE macro ......................................8
+ 2.5 The NOTIFICATION-TYPE macro ...............................10
+ 2.6 Administrative Identifiers ................................11
+ 3 Information Modules .........................................11
+ 3.1 Macro Invocation ..........................................12
+ 3.1.1 Textual Values and Strings ..............................13
+
+
+McCloghrie, et al. Standards Track [Page 1]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ 3.2 IMPORTing Symbols .........................................14
+ 3.3 Exporting Symbols .........................................14
+ 3.4 ASN.1 Comments ............................................14
+ 3.5 OBJECT IDENTIFIER values ..................................15
+ 3.6 OBJECT IDENTIFIER usage ...................................15
+ 3.7 Reserved Keywords .........................................16
+ 4 Naming Hierarchy ............................................16
+ 5 Mapping of the MODULE-IDENTITY macro ........................17
+ 5.1 Mapping of the LAST-UPDATED clause ........................17
+ 5.2 Mapping of the ORGANIZATION clause ........................17
+ 5.3 Mapping of the CONTACT-INFO clause ........................18
+ 5.4 Mapping of the DESCRIPTION clause .........................18
+ 5.5 Mapping of the REVISION clause ............................18
+ 5.5.1 Mapping of the DESCRIPTION sub-clause ...................18
+ 5.6 Mapping of the MODULE-IDENTITY value ......................18
+ 5.7 Usage Example .............................................18
+ 6 Mapping of the OBJECT-IDENTITY macro ........................19
+ 6.1 Mapping of the STATUS clause ..............................19
+ 6.2 Mapping of the DESCRIPTION clause .........................20
+ 6.3 Mapping of the REFERENCE clause ...........................20
+ 6.4 Mapping of the OBJECT-IDENTITY value ......................20
+ 6.5 Usage Example .............................................20
+ 7 Mapping of the OBJECT-TYPE macro ............................20
+ 7.1 Mapping of the SYNTAX clause ..............................21
+ 7.1.1 Integer32 and INTEGER ...................................21
+ 7.1.2 OCTET STRING ............................................21
+ 7.1.3 OBJECT IDENTIFIER .......................................22
+ 7.1.4 The BITS construct ......................................22
+ 7.1.5 IpAddress ...............................................22
+ 7.1.6 Counter32 ...............................................23
+ 7.1.7 Gauge32 .................................................23
+ 7.1.8 TimeTicks ...............................................24
+ 7.1.9 Opaque ..................................................24
+ 7.1.10 Counter64 ..............................................24
+ 7.1.11 Unsigned32 .............................................25
+ 7.1.12 Conceptual Tables ......................................25
+ 7.1.12.1 Creation and Deletion of Conceptual Rows .............26
+ 7.2 Mapping of the UNITS clause ...............................26
+ 7.3 Mapping of the MAX-ACCESS clause ..........................26
+ 7.4 Mapping of the STATUS clause ..............................27
+ 7.5 Mapping of the DESCRIPTION clause .........................27
+ 7.6 Mapping of the REFERENCE clause ...........................27
+ 7.7 Mapping of the INDEX clause ...............................27
+ 7.8 Mapping of the AUGMENTS clause ............................29
+ 7.8.1 Relation between INDEX and AUGMENTS clauses .............30
+ 7.9 Mapping of the DEFVAL clause ..............................30
+ 7.10 Mapping of the OBJECT-TYPE value .........................31
+ 7.11 Usage Example ............................................32
+
+
+McCloghrie, et al. Standards Track [Page 2]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ 8 Mapping of the NOTIFICATION-TYPE macro ......................34
+ 8.1 Mapping of the OBJECTS clause .............................34
+ 8.2 Mapping of the STATUS clause ..............................34
+ 8.3 Mapping of the DESCRIPTION clause .........................35
+ 8.4 Mapping of the REFERENCE clause ...........................35
+ 8.5 Mapping of the NOTIFICATION-TYPE value ....................35
+ 8.6 Usage Example .............................................35
+ 9 Refined Syntax ..............................................36
+ 10 Extending an Information Module ............................37
+ 10.1 Object Assignments .......................................37
+ 10.2 Object Definitions .......................................38
+ 10.3 Notification Definitions .................................39
+ 11 Appendix A: Detailed Sub-typing Rules ......................40
+ 11.1 Syntax Rules .............................................40
+ 11.2 Examples .................................................41
+ 12 Security Considerations ....................................41
+ 13 Editors' Addresses .........................................41
+ 14 References .................................................42
+ 15 Full Copyright Statement ...................................43
+
+1. Introduction
+
+ Management information is viewed as a collection of managed objects,
+ residing in a virtual information store, termed the Management
+ Information Base (MIB). Collections of related objects are defined
+ in MIB modules. These modules are written using an adapted subset of
+ OSI's Abstract Syntax Notation One, ASN.1 (1988) [1]. It is the
+ purpose of this document, the Structure of Management Information
+ (SMI), to define that adapted subset, and to assign a set of
+ associated administrative values.
+
+ The SMI is divided into three parts: module definitions, object
+ definitions, and, notification definitions.
+
+(1) Module definitions are used when describing information modules.
+ An ASN.1 macro, MODULE-IDENTITY, is used to concisely convey the
+ semantics of an information module.
+
+(2) Object definitions are used when describing managed objects. An
+ ASN.1 macro, OBJECT-TYPE, is used to concisely convey the syntax
+ and semantics of a managed object.
+
+(3) Notification definitions are used when describing unsolicited
+ transmissions of management information. An ASN.1 macro,
+ NOTIFICATION-TYPE, is used to concisely convey the syntax and
+ semantics of a notification.
+
+
+
+
+McCloghrie, et al. Standards Track [Page 3]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+1.1. A Note on Terminology
+
+ For the purpose of exposition, the original Structure of Management
+ Information, as described in RFCs 1155 (STD 16), 1212 (STD 16), and
+ RFC 1215, is termed the SMI version 1 (SMIv1). The current version
+ of the Structure of Management Information is termed SMI version 2
+ (SMIv2).
+
+2. Definitions
+
+SNMPv2-SMI DEFINITIONS ::= BEGIN
+
+
+-- the path to the root
+
+org OBJECT IDENTIFIER ::= { iso 3 } -- "iso" = 1
+dod OBJECT IDENTIFIER ::= { org 6 }
+internet OBJECT IDENTIFIER ::= { dod 1 }
+
+directory OBJECT IDENTIFIER ::= { internet 1 }
+
+mgmt OBJECT IDENTIFIER ::= { internet 2 }
+mib-2 OBJECT IDENTIFIER ::= { mgmt 1 }
+transmission OBJECT IDENTIFIER ::= { mib-2 10 }
+
+experimental OBJECT IDENTIFIER ::= { internet 3 }
+
+private OBJECT IDENTIFIER ::= { internet 4 }
+enterprises OBJECT IDENTIFIER ::= { private 1 }
+
+security OBJECT IDENTIFIER ::= { internet 5 }
+
+snmpV2 OBJECT IDENTIFIER ::= { internet 6 }
+
+-- transport domains
+snmpDomains OBJECT IDENTIFIER ::= { snmpV2 1 }
+
+-- transport proxies
+snmpProxys OBJECT IDENTIFIER ::= { snmpV2 2 }
+
+-- module identities
+snmpModules OBJECT IDENTIFIER ::= { snmpV2 3 }
+
+-- Extended UTCTime, to allow dates with four-digit years
+-- (Note that this definition of ExtUTCTime is not to be IMPORTed
+-- by MIB modules.)
+ExtUTCTime ::= OCTET STRING(SIZE(11 | 13))
+ -- format is YYMMDDHHMMZ or YYYYMMDDHHMMZ
+
+
+McCloghrie, et al. Standards Track [Page 4]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ -- where: YY - last two digits of year (only years
+ -- between 1900-1999)
+ -- YYYY - last four digits of the year (any year)
+ -- MM - month (01 through 12)
+ -- DD - day of month (01 through 31)
+ -- HH - hours (00 through 23)
+ -- MM - minutes (00 through 59)
+ -- Z - denotes GMT (the ASCII character Z)
+ --
+ -- For example, "9502192015Z" and "199502192015Z" represent
+ -- 8:15pm GMT on 19 February 1995. Years after 1999 must use
+ -- the four digit year format. Years 1900-1999 may use the
+ -- two or four digit format.
+
+-- definitions for information modules
+
+MODULE-IDENTITY MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ "LAST-UPDATED" value(Update ExtUTCTime)
+ "ORGANIZATION" Text
+ "CONTACT-INFO" Text
+ "DESCRIPTION" Text
+ RevisionPart
+
+ VALUE NOTATION ::=
+ value(VALUE OBJECT IDENTIFIER)
+
+ RevisionPart ::=
+ Revisions
+ | empty
+ Revisions ::=
+ Revision
+ | Revisions Revision
+ Revision ::=
+ "REVISION" value(Update ExtUTCTime)
+ "DESCRIPTION" Text
+
+ -- a character string as defined in section 3.1.1
+ Text ::= value(IA5String)
+END
+
+
+OBJECT-IDENTITY MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ "STATUS" Status
+ "DESCRIPTION" Text
+
+
+McCloghrie, et al. Standards Track [Page 5]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ ReferPart
+
+ VALUE NOTATION ::=
+ value(VALUE OBJECT IDENTIFIER)
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ -- a character string as defined in section 3.1.1
+ Text ::= value(IA5String)
+END
+
+
+-- names of objects
+-- (Note that these definitions of ObjectName and NotificationName
+-- are not to be IMPORTed by MIB modules.)
+
+ObjectName ::=
+ OBJECT IDENTIFIER
+
+NotificationName ::=
+ OBJECT IDENTIFIER
+
+-- syntax of objects
+
+-- the "base types" defined here are:
+-- 3 built-in ASN.1 types: INTEGER, OCTET STRING, OBJECT IDENTIFIER
+-- 8 application-defined types: Integer32, IpAddress, Counter32,
+-- Gauge32, Unsigned32, TimeTicks, Opaque, and Counter64
+
+ObjectSyntax ::=
+ CHOICE {
+ simple
+ SimpleSyntax,
+
+ -- note that SEQUENCEs for conceptual tables and
+ -- rows are not mentioned here...
+
+ application-wide
+ ApplicationSyntax
+ }
+
+
+
+McCloghrie, et al. Standards Track [Page 6]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+-- built-in ASN.1 types
+
+SimpleSyntax ::=
+ CHOICE {
+ -- INTEGERs with a more restrictive range
+ -- may also be used
+ integer-value -- includes Integer32
+ INTEGER (-2147483648..2147483647),
+
+ -- OCTET STRINGs with a more restrictive size
+ -- may also be used
+ string-value
+ OCTET STRING (SIZE (0..65535)),
+
+ objectID-value
+ OBJECT IDENTIFIER
+ }
+
+-- indistinguishable from INTEGER, but never needs more than
+-- 32-bits for a two's complement representation
+Integer32 ::=
+ INTEGER (-2147483648..2147483647)
+
+
+-- application-wide types
+
+ApplicationSyntax ::=
+ CHOICE {
+ ipAddress-value
+ IpAddress,
+
+ counter-value
+ Counter32,
+
+ timeticks-value
+ TimeTicks,
+
+ arbitrary-value
+ Opaque,
+
+ big-counter-value
+ Counter64,
+
+ unsigned-integer-value -- includes Gauge32
+ Unsigned32
+ }
+
+-- in network-byte order
+
+
+McCloghrie, et al. Standards Track [Page 7]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+-- (this is a tagged type for historical reasons)
+IpAddress ::=
+ [APPLICATION 0]
+ IMPLICIT OCTET STRING (SIZE (4))
+
+-- this wraps
+Counter32 ::=
+ [APPLICATION 1]
+ IMPLICIT INTEGER (0..4294967295)
+
+-- this doesn't wrap
+Gauge32 ::=
+ [APPLICATION 2]
+ IMPLICIT INTEGER (0..4294967295)
+
+-- an unsigned 32-bit quantity
+-- indistinguishable from Gauge32
+Unsigned32 ::=
+ [APPLICATION 2]
+ IMPLICIT INTEGER (0..4294967295)
+
+-- hundredths of seconds since an epoch
+TimeTicks ::=
+ [APPLICATION 3]
+ IMPLICIT INTEGER (0..4294967295)
+
+-- for backward-compatibility only
+Opaque ::=
+ [APPLICATION 4]
+ IMPLICIT OCTET STRING
+
+-- for counters that wrap in less than one hour with only 32 bits
+Counter64 ::=
+ [APPLICATION 6]
+ IMPLICIT INTEGER (0..18446744073709551615)
+
+
+-- definition for objects
+
+OBJECT-TYPE MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ "SYNTAX" Syntax
+ UnitsPart
+ "MAX-ACCESS" Access
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+
+
+McCloghrie, et al. Standards Track [Page 8]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ IndexPart
+ DefValPart
+
+ VALUE NOTATION ::=
+ value(VALUE ObjectName)
+
+ Syntax ::= -- Must be one of the following:
+ -- a base type (or its refinement),
+ -- a textual convention (or its refinement), or
+ -- a BITS pseudo-type
+ type
+ | "BITS" "{" NamedBits "}"
+
+ NamedBits ::= NamedBit
+ | NamedBits "," NamedBit
+
+ NamedBit ::= identifier "(" number ")" -- number is nonnegative
+
+ UnitsPart ::=
+ "UNITS" Text
+ | empty
+
+ Access ::=
+ "not-accessible"
+ | "accessible-for-notify"
+ | "read-only"
+ | "read-write"
+ | "read-create"
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ IndexPart ::=
+ "INDEX" "{" IndexTypes "}"
+ | "AUGMENTS" "{" Entry "}"
+ | empty
+ IndexTypes ::=
+ IndexType
+ | IndexTypes "," IndexType
+ IndexType ::=
+ "IMPLIED" Index
+ | Index
+
+
+McCloghrie, et al. Standards Track [Page 9]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ Index ::=
+ -- use the SYNTAX value of the
+ -- correspondent OBJECT-TYPE invocation
+ value(ObjectName)
+ Entry ::=
+ -- use the INDEX value of the
+ -- correspondent OBJECT-TYPE invocation
+ value(ObjectName)
+
+ DefValPart ::= "DEFVAL" "{" Defvalue "}"
+ | empty
+
+ Defvalue ::= -- must be valid for the type specified in
+ -- SYNTAX clause of same OBJECT-TYPE macro
+ value(ObjectSyntax)
+ | "{" BitsValue "}"
+
+ BitsValue ::= BitNames
+ | empty
+
+ BitNames ::= BitName
+ | BitNames "," BitName
+
+ BitName ::= identifier
+
+ -- a character string as defined in section 3.1.1
+ Text ::= value(IA5String)
+END
+
+
+-- definitions for notifications
+
+NOTIFICATION-TYPE MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ ObjectsPart
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+
+ VALUE NOTATION ::=
+ value(VALUE NotificationName)
+
+ ObjectsPart ::=
+ "OBJECTS" "{" Objects "}"
+ | empty
+ Objects ::=
+ Object
+
+
+McCloghrie, et al. Standards Track [Page 10]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ | Objects "," Object
+ Object ::=
+ value(ObjectName)
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ -- a character string as defined in section 3.1.1
+ Text ::= value(IA5String)
+END
+
+-- definitions of administrative identifiers
+
+zeroDotZero OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "A value used for null identifiers."
+ ::= { 0 0 }
+
+END
+
+3. Information Modules
+
+ An "information module" is an ASN.1 module defining information
+ relating to network management.
+
+ The SMI describes how to use an adapted subset of ASN.1 (1988) to
+ define an information module. Further, additional restrictions are
+ placed on "standard" information modules. It is strongly recommended
+ that "enterprise-specific" information modules also adhere to these
+ restrictions.
+
+ Typically, there are three kinds of information modules:
+
+(1) MIB modules, which contain definitions of inter-related managed
+ objects, make use of the OBJECT-TYPE and NOTIFICATION-TYPE macros;
+
+(2) compliance statements for MIB modules, which make use of the
+ MODULE-COMPLIANCE and OBJECT-GROUP macros [2]; and,
+
+(3) capability statements for agent implementations which make use of
+ the AGENT-CAPABILITIES macros [2].
+
+
+McCloghrie, et al. Standards Track [Page 11]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ This classification scheme does not imply a rigid taxonomy. For
+ example, a "standard" information module will normally include
+ definitions of managed objects and a compliance statement.
+ Similarly, an "enterprise-specific" information module might include
+ definitions of managed objects and a capability statement. Of
+ course, a "standard" information module may not contain capability
+ statements.
+
+ The constructs of ASN.1 allowed in SMIv2 information modules include:
+ the IMPORTS clause, value definitions for OBJECT IDENTIFIERs, type
+ definitions for SEQUENCEs (with restrictions), ASN.1 type assignments
+ of the restricted ASN.1 types allowed in SMIv2, and instances of
+ ASN.1 macros defined in this document and its companion documents [2,
+ 3]. Additional ASN.1 macros must not be defined in SMIv2 information
+ modules. SMIv1 macros must not be used in SMIv2 information modules.
+
+ The names of all standard information modules must be unique (but
+ different versions of the same information module should have the
+ same name). Developers of enterprise information modules are
+ encouraged to choose names for their information modules that will
+ have a low probability of colliding with standard or other enterprise
+ information modules. An information module may not use the ASN.1
+ construct of placing an object identifier value between the module
+ name and the "DEFINITIONS" keyword. For the purposes of this
+ specification, an ASN.1 module name begins with an upper-case letter
+ and continues with zero or more letters, digits, or hyphens, except
+ that a hyphen can not be the last character, nor can there be two
+ consecutive hyphens.
+
+ All information modules start with exactly one invocation of the
+ MODULE-IDENTITY macro, which provides contact information as well as
+ revision history to distinguish between versions of the same
+ information module. This invocation must appear immediately after
+ any IMPORTs statements.
+
+3.1. Macro Invocation
+
+ Within an information module, each macro invocation appears as:
+
+ <descriptor> <macro> <clauses> ::= <value>
+
+ where <descriptor> corresponds to an ASN.1 identifier, <macro> names
+ the macro being invoked, and <clauses> and <value> depend on the
+ definition of the macro. (Note that this definition of a descriptor
+ applies to all macros defined in this memo and in [2].)
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 12]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ For the purposes of this specification, an ASN.1 identifier consists
+ of one or more letters or digits, and its initial character must be a
+ lower-case letter. Note that hyphens are not allowed by this
+ specification (except for use by information modules converted from
+ SMIv1 which did allow hyphens).
+
+ For all descriptors appearing in an information module, the
+ descriptor shall be unique and mnemonic, and shall not exceed 64
+ characters in length. (However, descriptors longer than 32
+ characters are not recommended.) This promotes a common language for
+ humans to use when discussing the information module and also
+ facilitates simple table mappings for user-interfaces.
+
+ The set of descriptors defined in all "standard" information modules
+ shall be unique.
+
+ Finally, by convention, if the descriptor refers to an object with a
+ SYNTAX clause value of either Counter32 or Counter64, then the
+ descriptor used for the object should denote plurality.
+
+3.1.1. Textual Values and Strings
+
+ Some clauses in a macro invocation may take a character string as a
+ textual value (e.g., the DESCRIPTION clause). Other clauses take
+ binary or hexadecimal strings (in any position where a non-negative
+ number is allowed).
+
+ A character string is preceded and followed by the quote character
+ ("), and consists of an arbitrary number (possibly zero) of:
+
+ - any 7-bit displayable ASCII characters except quote ("),
+ - tab characters,
+ - spaces, and
+ - line terminator characters (\n or \r\n).
+
+ The value of a character string is interpreted as ASCII.
+
+ A binary string consists of a number (possibly zero) of zeros and
+ ones preceded by a single (') and followed by either the pair ('B) or
+ ('b), where the number is a multiple of eight.
+
+ A hexadecimal string consists of an even number (possibly zero) of
+ hexadecimal digits, preceded by a single (') and followed by either
+ the pair ('H) or ('h). Digits specified via letters can be in upper
+ or lower case.
+
+ Note that ASN.1 comments can not be enclosed inside any of these
+ types of strings.
+
+
+McCloghrie, et al. Standards Track [Page 13]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+3.2. IMPORTing Symbols
+
+ To reference an external object, the IMPORTS statement must be used
+ to identify both the descriptor and the module in which the
+ descriptor is defined, where the module is identified by its ASN.1
+ module name.
+
+ Note that when symbols from "enterprise-specific" information modules
+ are referenced (e.g., a descriptor), there is the possibility of
+ collision. As such, if different objects with the same descriptor
+ are IMPORTed, then this ambiguity is resolved by prefixing the
+ descriptor with the name of the information module and a dot ("."),
+ i.e.,
+
+ "module.descriptor"
+
+ (All descriptors must be unique within any information module.)
+
+ Of course, this notation can be used to refer to objects even when
+ there is no collision when IMPORTing symbols.
+
+ Finally, if any of the ASN.1 named types and macros defined in this
+ document, specifically:
+
+ Counter32, Counter64, Gauge32, Integer32, IpAddress, MODULE-
+ IDENTITY, NOTIFICATION-TYPE, Opaque, OBJECT-TYPE, OBJECT-
+ IDENTITY, TimeTicks, Unsigned32,
+
+ or any of those defined in [2] or [3], are used in an information
+ module, then they must be imported using the IMPORTS statement.
+ However, the following must not be included in an IMPORTS statement:
+
+ - named types defined by ASN.1 itself, specifically: INTEGER,
+ OCTET STRING, OBJECT IDENTIFIER, SEQUENCE, SEQUENCE OF type,
+ - the BITS construct.
+
+3.3. Exporting Symbols
+
+ The ASN.1 EXPORTS statement is not allowed in SMIv2 information
+ modules. All items defined in an information module are
+ automatically exported.
+
+3.4. ASN.1 Comments
+
+ ASN.1 comments can be included in an information module. However, it
+ is recommended that all substantive descriptions be placed within an
+ appropriate DESCRIPTION clause.
+
+
+
+McCloghrie, et al. Standards Track [Page 14]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ ASN.1 comments commence with a pair of adjacent hyphens and end with
+ the next pair of adjacent hyphens or at the end of the line,
+ whichever occurs first. Comments ended by a pair of hyphens have the
+ effect of a single space character.
+
+3.5. OBJECT IDENTIFIER values
+
+ An OBJECT IDENTIFIER value is an ordered list of non-negative
+ numbers. For the SMIv2, each number in the list is referred to as a
+ sub-identifier, there are at most 128 sub-identifiers in a value, and
+ each sub-identifier has a maximum value of 2^32-1 (4294967295
+ decimal).
+
+ All OBJECT IDENTIFIER values have at least two sub-identifiers, where
+ the value of the first sub-identifier is one of the following well-
+ known names:
+
+ Value Name
+ 0 ccitt
+ 1 iso
+ 2 joint-iso-ccitt
+
+ (Note that this SMI does not recognize "new" well-known names, e.g.,
+ as defined when the CCITT became the ITU.)
+
+3.6. OBJECT IDENTIFIER usage
+
+ OBJECT IDENTIFIERs are used in information modules in two ways:
+
+(1) registration: the definition of a particular item is registered as
+ a particular OBJECT IDENTIFIER value, and associated with a
+ particular descriptor. After such a registration, the semantics
+ thereby associated with the value are not allowed to change, the
+ OBJECT IDENTIFIER can not be used for any other registration, and
+ the descriptor can not be changed nor associated with any other
+ registration. The following macros result in a registration:
+
+ OBJECT-TYPE, MODULE-IDENTITY, NOTIFICATION-TYPE, OBJECT-GROUP,
+ OBJECT-IDENTITY, NOTIFICATION-GROUP, MODULE-COMPLIANCE,
+ AGENT-CAPABILITIES.
+
+(2) assignment: a descriptor can be assigned to a particular OBJECT
+ IDENTIFIER value. For this usage, the semantics associated with
+ the OBJECT IDENTIFIER value is not allowed to change, and a
+ descriptor assigned to a particular OBJECT IDENTIFIER value cannot
+ subsequently be assigned to another. However, multiple descriptors
+ can be assigned to the same OBJECT IDENTIFIER value. Such
+ assignments are specified in the following manner:
+
+
+McCloghrie, et al. Standards Track [Page 15]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ mib OBJECT IDENTIFIER ::= { mgmt 1 } -- from RFC1156
+ mib-2 OBJECT IDENTIFIER ::= { mgmt 1 } -- from RFC1213
+ fredRouter OBJECT IDENTIFIER ::= { flintStones 1 1 }
+ barneySwitch OBJECT IDENTIFIER ::= { flintStones bedrock(2) 1 }
+
+ Note while the above examples are legal, the following is not:
+
+ dinoHost OBJECT IDENTIFIER ::= { flintStones bedrock 2 }
+
+ A descriptor is allowed to be associated with both a registration and
+ an assignment, providing both are associated with the same OBJECT
+ IDENTIFIER value and semantics.
+
+3.7. Reserved Keywords
+
+ The following are reserved keywords which must not be used as
+ descriptors or module names:
+
+ ABSENT ACCESS AGENT-CAPABILITIES ANY APPLICATION AUGMENTS BEGIN
+ BIT BITS BOOLEAN BY CHOICE COMPONENT COMPONENTS CONTACT-INFO
+ CREATION-REQUIRES Counter32 Counter64 DEFAULT DEFINED
+ DEFINITIONS DEFVAL DESCRIPTION DISPLAY-HINT END ENUMERATED
+ ENTERPRISE EXPLICIT EXPORTS EXTERNAL FALSE FROM GROUP Gauge32
+ IDENTIFIER IMPLICIT IMPLIED IMPORTS INCLUDES INDEX INTEGER
+ Integer32 IpAddress LAST-UPDATED MANDATORY-GROUPS MAX MAX-ACCESS
+ MIN MIN-ACCESS MINUS-INFINITY MODULE MODULE-COMPLIANCE MODULE-
+ IDENTITY NOTIFICATION-GROUP NOTIFICATION-TYPE NOTIFICATIONS NULL
+ OBJECT OBJECT-GROUP OBJECT-IDENTITY OBJECT-TYPE OBJECTS OCTET OF
+ OPTIONAL ORGANIZATION Opaque PLUS-INFINITY PRESENT PRIVATE
+ PRODUCT-RELEASE REAL REFERENCE REVISION SEQUENCE SET SIZE STATUS
+ STRING SUPPORTS SYNTAX TAGS TEXTUAL-CONVENTION TRAP-TYPE TRUE
+ TimeTicks UNITS UNIVERSAL Unsigned32 VARIABLES VARIATION WITH
+ WRITE-SYNTAX
+
+4. Naming Hierarchy
+
+ The root of the subtree administered by the Internet Assigned Numbers
+ Authority (IANA) for the Internet is:
+
+ internet OBJECT IDENTIFIER ::= { iso 3 6 1 }
+
+ That is, the Internet subtree of OBJECT IDENTIFIERs starts with the
+ prefix:
+
+ 1.3.6.1.
+
+ Several branches underneath this subtree are used for network
+ management:
+
+
+McCloghrie, et al. Standards Track [Page 16]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ mgmt OBJECT IDENTIFIER ::= { internet 2 }
+ experimental OBJECT IDENTIFIER ::= { internet 3 }
+ private OBJECT IDENTIFIER ::= { internet 4 }
+ enterprises OBJECT IDENTIFIER ::= { private 1 }
+
+ However, the SMI does not prohibit the definition of objects in other
+ portions of the object tree.
+
+ The mgmt(2) subtree is used to identify "standard" objects.
+
+ The experimental(3) subtree is used to identify objects being
+ designed by working groups of the IETF. If an information module
+ produced by a working group becomes a "standard" information module,
+ then at the very beginning of its entry onto the Internet standards
+ track, the objects are moved under the mgmt(2) subtree.
+
+ The private(4) subtree is used to identify objects defined
+ unilaterally. The enterprises(1) subtree beneath private is used,
+ among other things, to permit providers of networking subsystems to
+ register models of their products.
+
+5. Mapping of the MODULE-IDENTITY macro
+
+ The MODULE-IDENTITY macro is used to provide contact and revision
+ history for each information module. It must appear exactly once in
+ every information module. It should be noted that the expansion of
+ the MODULE-IDENTITY macro is something which conceptually happens
+ during implementation and not during run-time.
+
+ Note that reference in an IMPORTS clause or in clauses of SMIv2
+ macros to an information module is NOT through the use of the
+ 'descriptor' of a MODULE-IDENTITY macro; rather, an information
+ module is referenced through specifying its module name.
+
+5.1. Mapping of the LAST-UPDATED clause
+
+ The LAST-UPDATED clause, which must be present, contains the date and
+ time that this information module was last edited.
+
+5.2. Mapping of the ORGANIZATION clause
+
+ The ORGANIZATION clause, which must be present, contains a textual
+ description of the organization under whose auspices this information
+ module was developed.
+
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 17]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+5.3. Mapping of the CONTACT-INFO clause
+
+ The CONTACT-INFO clause, which must be present, contains the name,
+ postal address, telephone number, and electronic mail address of the
+ person to whom technical queries concerning this information module
+ should be sent.
+
+5.4. Mapping of the DESCRIPTION clause
+
+ The DESCRIPTION clause, which must be present, contains a high-level
+ textual description of the contents of this information module.
+
+5.5. Mapping of the REVISION clause
+
+ The REVISION clause, which need not be present, is repeatedly used to
+ describe the revisions (including the initial version) made to this
+ information module, in reverse chronological order (i.e., most recent
+ first). Each instance of this clause contains the date and time of
+ the revision.
+
+5.5.1. Mapping of the DESCRIPTION sub-clause
+
+ The DESCRIPTION sub-clause, which must be present for each REVISION
+ clause, contains a high-level textual description of the revision
+ identified in that REVISION clause.
+
+5.6. Mapping of the MODULE-IDENTITY value
+
+ The value of an invocation of the MODULE-IDENTITY macro is an OBJECT
+ IDENTIFIER. As such, this value may be authoritatively used when
+ specifying an OBJECT IDENTIFIER value to refer to the information
+ module containing the invocation.
+
+ Note that it is a common practice to use the value of the MODULE-
+ IDENTITY macro as a subtree under which other OBJECT IDENTIFIER
+ values assigned within the module are defined. However, it is legal
+ (and occasionally necessary) for the other OBJECT IDENTIFIER values
+ assigned within the module to be unrelated to the OBJECT IDENTIFIER
+ value of the MODULE-IDENTITY macro.
+
+5.7. Usage Example
+
+ Consider how a skeletal MIB module might be constructed: e.g.,
+
+ FIZBIN-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, experimental
+
+
+McCloghrie, et al. Standards Track [Page 18]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ FROM SNMPv2-SMI;
+
+
+ fizbin MODULE-IDENTITY
+ LAST-UPDATED "199505241811Z"
+ ORGANIZATION "IETF SNMPv2 Working Group"
+ CONTACT-INFO
+ " Marshall T. Rose
+
+ Postal: Dover Beach Consulting, Inc.
+ 420 Whisman Court
+ Mountain View, CA 94043-2186
+ US
+
+ Tel: +1 415 968 1052
+ Fax: +1 415 968 2510
+
+ E-mail: mrose@dbc.mtview.ca.us"
+
+ DESCRIPTION
+ "The MIB module for entities implementing the xxxx
+ protocol."
+ REVISION "9505241811Z"
+ DESCRIPTION
+ "The latest version of this MIB module."
+ REVISION "9210070433Z"
+ DESCRIPTION
+ "The initial version of this MIB module, published in
+ RFC yyyy."
+ -- contact IANA for actual number
+ ::= { experimental xx }
+
+ END
+
+6. Mapping of the OBJECT-IDENTITY macro
+
+ The OBJECT-IDENTITY macro is used to define information about an
+ OBJECT IDENTIFIER assignment. All administrative OBJECT IDENTIFIER
+ assignments which define a type identification value (see
+ AutonomousType, a textual convention defined in [3]) should be
+ defined via the OBJECT-IDENTITY macro. It should be noted that the
+ expansion of the OBJECT-IDENTITY macro is something which
+ conceptually happens during implementation and not during run-time.
+
+6.1. Mapping of the STATUS clause
+
+ The STATUS clause, which must be present, indicates whether this
+ definition is current or historic.
+
+
+McCloghrie, et al. Standards Track [Page 19]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ The value "current" means that the definition is current and valid.
+ The value "obsolete" means the definition is obsolete and should not
+ be implemented and/or can be removed if previously implemented.
+ While the value "deprecated" also indicates an obsolete definition,
+ it permits new/continued implementation in order to foster
+ interoperability with older/existing implementations.
+
+6.2. Mapping of the DESCRIPTION clause
+
+ The DESCRIPTION clause, which must be present, contains a textual
+ description of the object assignment.
+
+6.3. Mapping of the REFERENCE clause
+
+ The REFERENCE clause, which need not be present, contains a textual
+ cross-reference to some other document, either another information
+ module which defines a related assignment, or some other document
+ which provides additional information relevant to this definition.
+
+6.4. Mapping of the OBJECT-IDENTITY value
+
+ The value of an invocation of the OBJECT-IDENTITY macro is an OBJECT
+ IDENTIFIER.
+
+6.5. Usage Example
+
+ Consider how an OBJECT IDENTIFIER assignment might be made: e.g.,
+
+ fizbin69 OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The authoritative identity of the Fizbin 69 chipset."
+ ::= { fizbinChipSets 1 }
+
+7. Mapping of the OBJECT-TYPE macro
+
+ The OBJECT-TYPE macro is used to define a type of managed object. It
+ should be noted that the expansion of the OBJECT-TYPE macro is
+ something which conceptually happens during implementation and not
+ during run-time.
+
+ For leaf objects which are not columnar objects (i.e., not contained
+ within a conceptual table), instances of the object are identified by
+ appending a sub-identifier of zero to the name of that object.
+ Otherwise, the INDEX clause of the conceptual row object superior to
+ a columnar object defines instance identification information.
+
+
+
+
+McCloghrie, et al. Standards Track [Page 20]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+7.1. Mapping of the SYNTAX clause
+
+ The SYNTAX clause, which must be present, defines the abstract data
+ structure corresponding to that object. The data structure must be
+ one of the following: a base type, the BITS construct, or a textual
+ convention. (SEQUENCE OF and SEQUENCE are also possible for
+ conceptual tables, see section 7.1.12). The base types are those
+ defined in the ObjectSyntax CHOICE. A textual convention is a
+ newly-defined type defined as a sub-type of a base type [3].
+
+ An extended subset of the full capabilities of ASN.1 (1988) sub-
+ typing is allowed, as appropriate to the underlying ASN.1 type. Any
+ such restriction on size, range or enumerations specified in this
+ clause represents the maximal level of support which makes "protocol
+ sense". Restrictions on sub-typing are specified in detail in
+ Section 9 and Appendix A of this memo.
+
+ The semantics of ObjectSyntax are now described.
+
+7.1.1. Integer32 and INTEGER
+
+ The Integer32 type represents integer-valued information between
+ -2^31 and 2^31-1 inclusive (-2147483648 to 2147483647 decimal). This
+ type is indistinguishable from the INTEGER type. Both the INTEGER
+ and Integer32 types may be sub-typed to be more constrained than the
+ Integer32 type.
+
+ The INTEGER type (but not the Integer32 type) may also be used to
+ represent integer-valued information as named-number enumerations.
+ In this case, only those named-numbers so enumerated may be present
+ as a value. Note that although it is recommended that enumerated
+ values start at 1 and be numbered contiguously, any valid value for
+ Integer32 is allowed for an enumerated value and, further, enumerated
+ values needn't be contiguously assigned.
+
+ Finally, a label for a named-number enumeration must consist of one
+ or more letters or digits, up to a maximum of 64 characters, and the
+ initial character must be a lower-case letter. (However, labels
+ longer than 32 characters are not recommended.) Note that hyphens
+ are not allowed by this specification (except for use by information
+ modules converted from SMIv1 which did allow hyphens).
+
+7.1.2. OCTET STRING
+
+ The OCTET STRING type represents arbitrary binary or textual data.
+ Although the SMI-specified size limitation for this type is 65535
+ octets, MIB designers should realize that there may be implementation
+ and interoperability limitations for sizes in excess of 255 octets.
+
+
+McCloghrie, et al. Standards Track [Page 21]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+7.1.3. OBJECT IDENTIFIER
+
+ The OBJECT IDENTIFIER type represents administratively assigned
+ names. Any instance of this type may have at most 128 sub-
+ identifiers. Further, each sub-identifier must not exceed the value
+ 2^32-1 (4294967295 decimal).
+
+7.1.4. The BITS construct
+
+ The BITS construct represents an enumeration of named bits. This
+ collection is assigned non-negative, contiguous (but see below)
+ values, starting at zero. Only those named-bits so enumerated may be
+ present in a value. (Thus, enumerations must be assigned to
+ consecutive bits; however, see Section 9 for refinements of an object
+ with this syntax.)
+
+ As part of updating an information module, for an object defined
+ using the BITS construct, new enumerations can be added or existing
+ enumerations can have new labels assigned to them. After an
+ enumeration is added, it might not be possible to distinguish between
+ an implementation of the updated object for which the new enumeration
+ is not asserted, and an implementation of the object prior to the
+ addition. Depending on the circumstances, such an ambiguity could
+ either be desirable or could be undesirable. The means to avoid such
+ an ambiguity is dependent on the encoding of values on the wire;
+ however, one possibility is to define new enumerations starting at
+ the next multiple of eight bits. (Of course, this can also result in
+ the enumerations no longer being contiguous.)
+
+ Although there is no SMI-specified limitation on the number of
+ enumerations (and therefore on the length of a value), except as may
+ be imposed by the limit on the length of an OCTET STRING, MIB
+ designers should realize that there may be implementation and
+ interoperability limitations for sizes in excess of 128 bits.
+
+ Finally, a label for a named-number enumeration must consist of one
+ or more letters or digits, up to a maximum of 64 characters, and the
+ initial character must be a lower-case letter. (However, labels
+ longer than 32 characters are not recommended.) Note that hyphens
+ are not allowed by this specification.
+
+7.1.5. IpAddress
+
+ The IpAddress type represents a 32-bit internet address. It is
+ represented as an OCTET STRING of length 4, in network byte-order.
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 22]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ Note that the IpAddress type is a tagged type for historical reasons.
+ Network addresses should be represented using an invocation of the
+ TEXTUAL-CONVENTION macro [3].
+
+7.1.6. Counter32
+
+ The Counter32 type represents a non-negative integer which
+ monotonically increases until it reaches a maximum value of 2^32-1
+ (4294967295 decimal), when it wraps around and starts increasing
+ again from zero.
+
+ Counters have no defined "initial" value, and thus, a single value of
+ a Counter has (in general) no information content. Discontinuities
+ in the monotonically increasing value normally occur at re-
+ initialization of the management system, and at other times as
+ specified in the description of an object-type using this ASN.1 type.
+ If such other times can occur, for example, the creation of an object
+ instance at times other than re-initialization, then a corresponding
+ object should be defined, with an appropriate SYNTAX clause, to
+ indicate the last discontinuity. Examples of appropriate SYNTAX
+ clause include: TimeStamp (a textual convention defined in [3]),
+ DateAndTime (another textual convention from [3]) or TimeTicks.
+
+ The value of the MAX-ACCESS clause for objects with a SYNTAX clause
+ value of Counter32 is either "read-only" or "accessible-for-notify".
+
+ A DEFVAL clause is not allowed for objects with a SYNTAX clause value
+ of Counter32.
+
+7.1.7. Gauge32
+
+ The Gauge32 type represents a non-negative integer, which may
+ increase or decrease, but shall never exceed a maximum value, nor
+ fall below a minimum value. The maximum value can not be greater
+ than 2^32-1 (4294967295 decimal), and the minimum value can not be
+ smaller than 0. The value of a Gauge32 has its maximum value
+ whenever the information being modeled is greater than or equal to
+ its maximum value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value. If the
+ information being modeled subsequently decreases below (increases
+ above) the maximum (minimum) value, the Gauge32 also decreases
+ (increases). (Note that despite of the use of the term "latched" in
+ the original definition of this type, it does not become "stuck" at
+ its maximum or minimum value.)
+
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 23]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+7.1.8. TimeTicks
+
+ The TimeTicks type represents a non-negative integer which represents
+ the time, modulo 2^32 (4294967296 decimal), in hundredths of a second
+ between two epochs. When objects are defined which use this ASN.1
+ type, the description of the object identifies both of the reference
+ epochs.
+
+ For example, [3] defines the TimeStamp textual convention which is
+ based on the TimeTicks type. With a TimeStamp, the first reference
+ epoch is defined as the time when sysUpTime [5] was zero, and the
+ second reference epoch is defined as the current value of sysUpTime.
+
+ The TimeTicks type may not be sub-typed.
+
+7.1.9. Opaque
+
+ The Opaque type is provided solely for backward-compatibility, and
+ shall not be used for newly-defined object types.
+
+ The Opaque type supports the capability to pass arbitrary ASN.1
+ syntax. A value is encoded using the ASN.1 Basic Encoding Rules [4]
+ into a string of octets. This, in turn, is encoded as an OCTET
+ STRING, in effect "double-wrapping" the original ASN.1 value.
+
+ Note that a conforming implementation need only be able to accept and
+ recognize opaquely-encoded data. It need not be able to unwrap the
+ data and then interpret its contents.
+
+ A requirement on "standard" MIB modules is that no object may have a
+ SYNTAX clause value of Opaque.
+
+7.1.10. Counter64
+
+ The Counter64 type represents a non-negative integer which
+ monotonically increases until it reaches a maximum value of 2^64-1
+ (18446744073709551615 decimal), when it wraps around and starts
+ increasing again from zero.
+
+ Counters have no defined "initial" value, and thus, a single value of
+ a Counter has (in general) no information content. Discontinuities
+ in the monotonically increasing value normally occur at re-
+ initialization of the management system, and at other times as
+ specified in the description of an object-type using this ASN.1 type.
+ If such other times can occur, for example, the creation of an object
+ instance at times other than re-initialization, then a corresponding
+ object should be defined, with an appropriate SYNTAX clause, to
+ indicate the last discontinuity. Examples of appropriate SYNTAX
+
+
+McCloghrie, et al. Standards Track [Page 24]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ clause are: TimeStamp (a textual convention defined in [3]),
+ DateAndTime (another textual convention from [3]) or TimeTicks.
+
+ The value of the MAX-ACCESS clause for objects with a SYNTAX clause
+ value of Counter64 is either "read-only" or "accessible-for-notify".
+
+ A requirement on "standard" MIB modules is that the Counter64 type
+ may be used only if the information being modeled would wrap in less
+ than one hour if the Counter32 type was used instead.
+
+ A DEFVAL clause is not allowed for objects with a SYNTAX clause value
+ of Counter64.
+
+7.1.11. Unsigned32
+
+ The Unsigned32 type represents integer-valued information between 0
+ and 2^32-1 inclusive (0 to 4294967295 decimal).
+
+7.1.12. Conceptual Tables
+
+ Management operations apply exclusively to scalar objects. However,
+ it is sometimes convenient for developers of management applications
+ to impose an imaginary, tabular structure on an ordered collection of
+ objects within the MIB. Each such conceptual table contains zero or
+ more rows, and each row may contain one or more scalar objects,
+ termed columnar objects. This conceptualization is formalized by
+ using the OBJECT-TYPE macro to define both an object which
+ corresponds to a table and an object which corresponds to a row in
+ that table. A conceptual table has SYNTAX of the form:
+
+ SEQUENCE OF <EntryType>
+
+ where <EntryType> refers to the SEQUENCE type of its subordinate
+ conceptual row. A conceptual row has SYNTAX of the form:
+
+ <EntryType>
+
+ where <EntryType> is a SEQUENCE type defined as follows:
+
+ <EntryType> ::= SEQUENCE { <type1>, ... , <typeN> }
+
+ where there is one <type> for each subordinate object, and each
+ <type> is of the form:
+
+ <descriptor> <syntax>
+
+ where <descriptor> is the descriptor naming a subordinate object, and
+ <syntax> has the value of that subordinate object's SYNTAX clause,
+
+
+McCloghrie, et al. Standards Track [Page 25]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ except that both sub-typing information and the named values for
+ enumerated integers or the named bits for the BITS construct, are
+ omitted from <syntax>.
+
+ Further, a <type> is always present for every subordinate object.
+ (The ASN.1 DEFAULT and OPTIONAL clauses are disallowed in the
+ SEQUENCE definition.) The MAX-ACCESS clause for conceptual tables
+ and rows is "not-accessible".
+
+7.1.12.1. Creation and Deletion of Conceptual Rows
+
+ For newly-defined conceptual rows which allow the creation of new
+ object instances and/or the deletion of existing object instances,
+ there should be one columnar object with a SYNTAX clause value of
+ RowStatus (a textual convention defined in [3]) and a MAX-ACCESS
+ clause value of read-create. By convention, this is termed the
+ status column for the conceptual row.
+
+7.2. Mapping of the UNITS clause
+
+ This UNITS clause, which need not be present, contains a textual
+ definition of the units associated with that object.
+
+7.3. Mapping of the MAX-ACCESS clause
+
+ The MAX-ACCESS clause, which must be present, defines whether it
+ makes "protocol sense" to read, write and/or create an instance of
+ the object, or to include its value in a notification. This is the
+ maximal level of access for the object. (This maximal level of
+ access is independent of any administrative authorization policy.)
+
+ The value "read-write" indicates that read and write access make
+ "protocol sense", but create does not. The value "read-create"
+ indicates that read, write and create access make "protocol sense".
+ The value "not-accessible" indicates an auxiliary object (see Section
+ 7.7). The value "accessible-for-notify" indicates an object which is
+ accessible only via a notification (e.g., snmpTrapOID [5]).
+
+ These values are ordered, from least to greatest: "not-accessible",
+ "accessible-for-notify", "read-only", "read-write", "read-create".
+
+ If any columnar object in a conceptual row has "read-create" as its
+ maximal level of access, then no other columnar object of the same
+ conceptual row may have a maximal access of "read-write". (Note that
+ "read-create" is a superset of "read-write".)
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 26]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+7.4. Mapping of the STATUS clause
+
+ The STATUS clause, which must be present, indicates whether this
+ definition is current or historic.
+
+ The value "current" means that the definition is current and valid.
+ The value "obsolete" means the definition is obsolete and should not
+ be implemented and/or can be removed if previously implemented.
+ While the value "deprecated" also indicates an obsolete definition,
+ it permits new/continued implementation in order to foster
+ interoperability with older/existing implementations.
+
+7.5. Mapping of the DESCRIPTION clause
+
+ The DESCRIPTION clause, which must be present, contains a textual
+ definition of that object which provides all semantic definitions
+ necessary for implementation, and should embody any information which
+ would otherwise be communicated in any ASN.1 commentary annotations
+ associated with the object.
+
+7.6. Mapping of the REFERENCE clause
+
+ The REFERENCE clause, which need not be present, contains a textual
+ cross-reference to some other document, either another information
+ module which defines a related assignment, or some other document
+ which provides additional information relevant to this definition.
+
+7.7. Mapping of the INDEX clause
+
+ The INDEX clause, which must be present if that object corresponds to
+ a conceptual row (unless an AUGMENTS clause is present instead), and
+ must be absent otherwise, defines instance identification information
+ for the columnar objects subordinate to that object.
+
+ The instance identification information in an INDEX clause must
+ specify object(s) such that value(s) of those object(s) will
+ unambiguously distinguish a conceptual row. The objects can be
+ columnar objects from the same and/or another conceptual table, but
+ must not be scalar objects. Multiple occurrences of the same object
+ in a single INDEX clause is strongly discouraged.
+
+ The syntax of the objects in the INDEX clause indicate how to form
+ the instance-identifier:
+
+(1) integer-valued (i.e., having INTEGER as its underlying primitive
+ type): a single sub-identifier taking the integer value (this
+ works only for non-negative integers);
+
+
+
+McCloghrie, et al. Standards Track [Page 27]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+(2) string-valued, fixed-length strings (or variable-length preceded by
+ the IMPLIED keyword): `n' sub-identifiers, where `n' is the length
+ of the string (each octet of the string is encoded in a separate
+ sub-identifier);
+
+(3) string-valued, variable-length strings (not preceded by the IMPLIED
+ keyword): `n+1' sub-identifiers, where `n' is the length of the
+ string (the first sub-identifier is `n' itself, following this,
+ each octet of the string is encoded in a separate sub-identifier);
+
+(4) object identifier-valued (when preceded by the IMPLIED keyword):
+ `n' sub-identifiers, where `n' is the number of sub-identifiers in
+ the value (each sub-identifier of the value is copied into a
+ separate sub-identifier);
+
+(5) object identifier-valued (when not preceded by the IMPLIED
+ keyword): `n+1' sub-identifiers, where `n' is the number of sub-
+ identifiers in the value (the first sub-identifier is `n' itself,
+ following this, each sub-identifier in the value is copied);
+
+(6) IpAddress-valued: 4 sub-identifiers, in the familiar a.b.c.d
+ notation.
+
+ Note that the IMPLIED keyword can only be present for an object
+ having a variable-length syntax (e.g., variable-length strings or
+ object identifier-valued objects), Further, the IMPLIED keyword can
+ only be associated with the last object in the INDEX clause.
+ Finally, the IMPLIED keyword may not be used on a variable-length
+ string object if that string might have a value of zero-length.
+
+ Since a single value of a Counter has (in general) no information
+ content (see section 7.1.6 and 7.1.10), objects defined using the
+ syntax, Counter32 or Counter64, must not be specified in an INDEX
+
+ clause. If an object defined using the BITS construct is used in an
+ INDEX clause, it is considered a variable-length string.
+
+ Instances identified by use of integer-valued objects should be
+ numbered starting from one (i.e., not from zero). The use of zero as
+ a value for an integer-valued index object should be avoided, except
+ in special cases.
+
+ Objects which are both specified in the INDEX clause of a conceptual
+ row and also columnar objects of the same conceptual row are termed
+ auxiliary objects. The MAX-ACCESS clause for auxiliary objects is
+ "not-accessible", except in the following circumstances:
+
+
+
+
+McCloghrie, et al. Standards Track [Page 28]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+(1) within a MIB module originally written to conform to SMIv1, and
+ later converted to conform to SMIv2; or
+
+(2) a conceptual row must contain at least one columnar object which is
+ not an auxiliary object. In the event that all of a conceptual
+ row's columnar objects are also specified in its INDEX clause, then
+ one of them must be accessible, i.e., have a MAX-ACCESS clause of
+ "read-only". (Note that this situation does not arise for a
+ conceptual row allowing create access, since such a row will have a
+ status column which will not be an auxiliary object.)
+
+ Note that objects specified in a conceptual row's INDEX clause need
+ not be columnar objects of that conceptual row. In this situation,
+ the DESCRIPTION clause of the conceptual row must include a textual
+ explanation of how the objects which are included in the INDEX clause
+ but not columnar objects of that conceptual row, are used in uniquely
+ identifying instances of the conceptual row's columnar objects.
+
+7.8. Mapping of the AUGMENTS clause
+
+ The AUGMENTS clause, which must not be present unless the object
+ corresponds to a conceptual row, is an alternative to the INDEX
+ clause. Every object corresponding to a conceptual row has either an
+ INDEX clause or an AUGMENTS clause.
+
+ If an object corresponding to a conceptual row has an INDEX clause,
+ that row is termed a base conceptual row; alternatively, if the
+ object has an AUGMENTS clause, the row is said to be a conceptual row
+ augmentation, where the AUGMENTS clause names the object
+ corresponding to the base conceptual row which is augmented by this
+ conceptual row augmentation. (Thus, a conceptual row augmentation
+ cannot itself be augmented.) Instances of subordinate columnar
+ objects of a conceptual row augmentation are identified according to
+ the INDEX clause of the base conceptual row corresponding to the
+ object named in the AUGMENTS clause. Further, instances of
+ subordinate columnar objects of a conceptual row augmentation exist
+ according to the same semantics as instances of subordinate columnar
+ objects of the base conceptual row being augmented. As such, note
+ that creation of a base conceptual row implies the correspondent
+ creation of any conceptual row augmentations.
+
+ For example, a MIB designer might wish to define additional columns
+ in an "enterprise-specific" MIB which logically extend a conceptual
+ row in a "standard" MIB. The "standard" MIB definition of the
+ conceptual row would include the INDEX clause and the "enterprise-
+ specific" MIB would contain the definition of a conceptual row using
+ the AUGMENTS clause. On the other hand, it would be incorrect to use
+ the AUGMENTS clause for the relationship between RFC 2233's ifTable
+
+
+McCloghrie, et al. Standards Track [Page 29]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ and the many media-specific MIBs which extend it for specific media
+ (e.g., the dot3Table in RFC 2358), since not all interfaces are of
+ the same media.
+
+ Note that a base conceptual row may be augmented by multiple
+ conceptual row augmentations.
+
+7.8.1. Relation between INDEX and AUGMENTS clauses
+
+ When defining instance identification information for a conceptual
+ table:
+
+(1) If there is a one-to-one correspondence between the conceptual rows
+ of this table and an existing table, then the AUGMENTS clause
+ should be used.
+
+(2) Otherwise, if there is a sparse relationship between the conceptual
+ rows of this table and an existing table, then an INDEX clause
+ should be used which is identical to that in the existing table.
+ For example, the relationship between RFC 2233's ifTable and a
+ media-specific MIB which extends the ifTable for a specific media
+ (e.g., the dot3Table in RFC 2358), is a sparse relationship.
+
+(3) Otherwise, if no existing objects have the required syntax and
+ semantics, then auxiliary objects should be defined within the
+ conceptual row for the new table, and those objects should be used
+ within the INDEX clause for the conceptual row.
+
+7.9. Mapping of the DEFVAL clause
+
+ The DEFVAL clause, which need not be present, defines an acceptable
+ default value which may be used at the discretion of an agent when an
+ object instance is created. That is, the value is a "hint" to
+ implementors.
+
+ During conceptual row creation, if an instance of a columnar object
+ is not present as one of the operands in the correspondent management
+ protocol set operation, then the value of the DEFVAL clause, if
+ present, indicates an acceptable default value that an agent might
+ use (especially for a read-only object).
+
+ Note that with this definition of the DEFVAL clause, it is
+ appropriate to use it for any columnar object of a read-create table.
+ It is also permitted to use it for scalar objects dynamically created
+ by an agent, or for columnar objects of a read-write table
+ dynamically created by an agent.
+
+
+
+
+McCloghrie, et al. Standards Track [Page 30]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ The value of the DEFVAL clause must, of course, correspond to the
+ SYNTAX clause for the object. If the value is an OBJECT IDENTIFIER,
+ then it must be expressed as a single ASN.1 identifier, and not as a
+ collection of sub-identifiers.
+
+ Note that if an operand to the management protocol set operation is
+ an instance of a read-only object, then the error `notWritable' [6]
+ will be returned. As such, the DEFVAL clause can be used to provide
+ an acceptable default value that an agent might use.
+
+ By way of example, consider the following possible DEFVAL clauses:
+
+ ObjectSyntax DEFVAL clause
+ ---------------- ------------
+ Integer32 DEFVAL { 1 }
+ -- same for Gauge32, TimeTicks, Unsigned32
+ INTEGER DEFVAL { valid } -- enumerated value
+ OCTET STRING DEFVAL { 'ffffffffffff'H }
+ DisplayString DEFVAL { "SNMP agent" }
+ IpAddress DEFVAL { 'c0210415'H } -- 192.33.4.21
+ OBJECT IDENTIFIER DEFVAL { sysDescr }
+ BITS DEFVAL { { primary, secondary } }
+ -- enumerated values that are set
+ BITS DEFVAL { { } }
+ -- no enumerated values are set
+
+ A binary string used in a DEFVAL clause for an OCTET STRING must be
+ either an integral multiple of eight or zero bits in length;
+ similarly, a hexadecimal string must be an even number of hexadecimal
+ digits. The value of a character string used in a DEFVAL clause must
+ not contain tab characters or line terminator characters.
+
+ Object types with SYNTAX of Counter32 and Counter64 may not have
+ DEFVAL clauses, since they do not have defined initial values.
+ However, it is recommended that they be initialized to zero.
+
+7.10. Mapping of the OBJECT-TYPE value
+
+ The value of an invocation of the OBJECT-TYPE macro is the name of
+ the object, which is an OBJECT IDENTIFIER, an administratively
+ assigned name.
+
+ When an OBJECT IDENTIFIER is assigned to an object:
+
+(1) If the object corresponds to a conceptual table, then only a single
+ assignment, that for a conceptual row, is present immediately
+ beneath that object. The administratively assigned name for the
+ conceptual row object is derived by appending a sub-identifier of
+
+
+McCloghrie, et al. Standards Track [Page 31]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ "1" to the administratively assigned name for the conceptual table.
+
+(2) If the object corresponds to a conceptual row, then at least one
+ assignment, one for each column in the conceptual row, is present
+ beneath that object. The administratively assigned name for each
+ column is derived by appending a unique, positive sub-identifier to
+ the administratively assigned name for the conceptual row.
+
+(3) Otherwise, no other OBJECT IDENTIFIERs which are subordinate to the
+ object may be assigned.
+
+ Note that the final sub-identifier of any administratively assigned
+ name for an object shall be positive. A zero-valued final sub-
+ identifier is reserved for future use.
+
+7.11. Usage Example
+
+ Consider how one might define a conceptual table and its
+ subordinates. (This example uses the RowStatus textual convention
+ defined in [3].)
+
+ evalSlot OBJECT-TYPE
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The index number of the first unassigned entry in the
+ evaluation table, or the value of zero indicating that
+ all entries are assigned.
+
+ A management station should create new entries in the
+ evaluation table using this algorithm: first, issue a
+ management protocol retrieval operation to determine the
+ value of evalSlot; and, second, issue a management
+ protocol set operation to create an instance of the
+ evalStatus object setting its value to createAndGo(4) or
+ createAndWait(5). If this latter operation succeeds,
+ then the management station may continue modifying the
+ instances corresponding to the newly created conceptual
+ row, without fear of collision with other management
+ stations."
+ ::= { eval 1 }
+
+ evalTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EvalEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+
+
+McCloghrie, et al. Standards Track [Page 32]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ "The (conceptual) evaluation table."
+ ::= { eval 2 }
+
+ evalEntry OBJECT-TYPE
+ SYNTAX EvalEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) in the evaluation table."
+ INDEX { evalIndex }
+ ::= { evalTable 1 }
+
+ EvalEntry ::=
+ SEQUENCE {
+ evalIndex Integer32,
+ evalString DisplayString,
+ evalValue Integer32,
+ evalStatus RowStatus
+ }
+
+ evalIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The auxiliary variable used for identifying instances of
+ the columnar objects in the evaluation table."
+ ::= { evalEntry 1 }
+
+ evalString OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The string to evaluate."
+ ::= { evalEntry 2 }
+
+ evalValue OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value when evalString was last evaluated, or zero if
+ no such value is available."
+ DEFVAL { 0 }
+ ::= { evalEntry 3 }
+
+ evalStatus OBJECT-TYPE
+
+
+McCloghrie, et al. Standards Track [Page 33]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status column used for creating, modifying, and
+ deleting instances of the columnar objects in the
+ evaluation table."
+ DEFVAL { active }
+ ::= { evalEntry 4 }
+
+8. Mapping of the NOTIFICATION-TYPE macro
+
+ The NOTIFICATION-TYPE macro is used to define the information
+ contained within an unsolicited transmission of management
+ information (i.e., within either a SNMPv2-Trap-PDU or InformRequest-
+ PDU). It should be noted that the expansion of the NOTIFICATION-TYPE
+ macro is something which conceptually happens during implementation
+ and not during run-time.
+
+8.1. Mapping of the OBJECTS clause
+
+ The OBJECTS clause, which need not be present, defines an ordered
+ sequence of MIB object types. One and only one object instance for
+ each occurrence of each object type must be present, and in the
+ specified order, in every instance of the notification. If the same
+ object type occurs multiple times in a notification's ordered
+ sequence, then an object instance is present for each of them. An
+ object type specified in this clause must not have an MAX-ACCESS
+ clause of "not-accessible". The notification's DESCRIPTION clause
+ must specify the information/meaning conveyed by each occurrence of
+ each object type in the sequence. The DESCRIPTION clause must also
+ specify which object instance is present for each object type in the
+ notification.
+
+ Note that an agent is allowed, at its own discretion, to append as
+ many additional objects as it considers useful to the end of the
+ notification (i.e., after the objects defined by the OBJECTS clause).
+
+8.2. Mapping of the STATUS clause
+
+ The STATUS clause, which must be present, indicates whether this
+ definition is current or historic.
+
+ The value "current" means that the definition is current and valid.
+ The value "obsolete" means the definition is obsolete and should not
+ be implemented and/or can be removed if previously implemented.
+ While the value "deprecated" also indicates an obsolete definition,
+ it permits new/continued implementation in order to foster
+
+
+McCloghrie, et al. Standards Track [Page 34]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ interoperability with older/existing implementations.
+
+8.3. Mapping of the DESCRIPTION clause
+
+ The DESCRIPTION clause, which must be present, contains a textual
+ definition of the notification which provides all semantic
+ definitions necessary for implementation, and should embody any
+ information which would otherwise be communicated in any ASN.1
+ commentary annotations associated with the notification. In
+ particular, the DESCRIPTION clause should document which instances of
+ the objects mentioned in the OBJECTS clause should be contained
+ within notifications of this type.
+
+8.4. Mapping of the REFERENCE clause
+
+ The REFERENCE clause, which need not be present, contains a textual
+ cross-reference to some other document, either another information
+ module which defines a related assignment, or some other document
+ which provides additional information relevant to this definition.
+
+8.5. Mapping of the NOTIFICATION-TYPE value
+
+ The value of an invocation of the NOTIFICATION-TYPE macro is the name
+ of the notification, which is an OBJECT IDENTIFIER, an
+ administratively assigned name. In order to achieve compatibility
+ with SNMPv1 traps, both when converting SMIv1 information modules
+ to/from this SMI, and in the procedures employed by multi-lingual
+ systems and proxy forwarding applications, the next to last sub-
+ identifier in the name of any newly-defined notification must have
+ the value zero.
+
+ Sections 4.2.6 and 4.2.7 of [6] describe how the NOTIFICATION-TYPE
+ macro is used to generate a SNMPv2-Trap-PDU or InformRequest-PDU,
+ respectively.
+
+8.6. Usage Example
+
+ Consider how a configuration change notification might be described:
+
+ entityMIBTraps OBJECT IDENTIFIER ::= { entityMIB 2 }
+ entityMIBTrapPrefix OBJECT IDENTIFIER ::= { entityMIBTraps 0 }
+
+ entConfigChange NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "An entConfigChange trap is sent when the value of
+ entLastChangeTime changes. It can be utilized by an NMS to
+ trigger logical/physical entity table maintenance polls.
+
+
+McCloghrie, et al. Standards Track [Page 35]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+
+ An agent must not generate more than one entConfigChange
+ 'trap-event' in a five second period, where a 'trap-event'
+ is the transmission of a single trap PDU to a list of
+ trap destinations. If additional configuration changes
+ occur within the five second 'throttling' period, then
+ these trap-events should be suppressed by the agent. An
+ NMS should periodically check the value of
+ entLastChangeTime to detect any missed entConfigChange
+ trap-events, e.g. due to throttling or transmission loss."
+ ::= { entityMIBTrapPrefix 1 }
+
+ According to this invocation, the notification authoritatively
+ identified as
+
+ { entityMIBTrapPrefix 1 }
+
+ is used to report a particular type of configuration change.
+
+9. Refined Syntax
+
+ Some macros have clauses which allows syntax to be refined,
+ specifically: the SYNTAX clause of the OBJECT-TYPE macro, and the
+ SYNTAX/WRITE-SYNTAX clauses of the MODULE-COMPLIANCE and AGENT-
+ CAPABILITIES macros [2]. However, not all refinements of syntax are
+ appropriate. In particular, the object's primitive or application
+ type must not be changed.
+
+ Further, the following restrictions apply:
+
+ Restrictions to Refinement of
+ object syntax range enumeration size
+ ----------------- ----- ----------- ----
+ INTEGER (1) (2) -
+ Integer32 (1) - -
+ Unsigned32 (1) - -
+ OCTET STRING - - (3)
+ OBJECT IDENTIFIER - - -
+ BITS - (2) -
+ IpAddress - - -
+ Counter32 - - -
+ Counter64 - - -
+ Gauge32 (1) - -
+ TimeTicks - - -
+
+ where:
+
+
+
+
+McCloghrie, et al. Standards Track [Page 36]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+(1) the range of permitted values may be refined by raising the lower-
+ bounds, by reducing the upper-bounds, and/or by reducing the
+ alternative value/range choices;
+
+(2) the enumeration of named-values may be refined by removing one or
+ more named-values (note that for BITS, a refinement may cause the
+ enumerations to no longer be contiguous); or,
+
+(3) the size in octets of the value may be refined by raising the
+ lower-bounds, by reducing the upper-bounds, and/or by reducing the
+ alternative size choices.
+
+ No other types of refinements can be specified in the SYNTAX clause.
+ However, the DESCRIPTION clause is available to specify additional
+ restrictions which can not be expressed in the SYNTAX clause.
+ Further details on (and examples of) sub-typing are provided in
+ Appendix A.
+
+10. Extending an Information Module
+
+ As experience is gained with an information module, it may be
+ desirable to revise that information module. However, changes are
+ not allowed if they have any potential to cause interoperability
+ problems "over the wire" between an implementation using an original
+ specification and an implementation using an updated
+ specification(s).
+
+ For any change, the invocation of the MODULE-IDENTITY macro must be
+ updated to include information about the revision: specifically,
+ updating the LAST-UPDATED clause, adding a pair of REVISION and
+ DESCRIPTION clauses (see section 5.5), and making any necessary
+ changes to existing clauses, including the ORGANIZATION and CONTACT-
+ INFO clauses.
+
+ Note that any definition contained in an information module is
+ available to be IMPORT-ed by any other information module, and is
+ referenced in an IMPORTS clause via the module name. Thus, a module
+ name should not be changed. Specifically, the module name (e.g.,
+ "FIZBIN-MIB" in the example of Section 5.7) should not be changed
+ when revising an information module (except to correct typographical
+ errors), and definitions should not be moved from one information
+ module to another.
+
+ Also note that obsolete definitions must not be removed from MIB
+ modules since their descriptors may still be referenced by other
+ information modules, and the OBJECT IDENTIFIERs used to name them
+ must never be re-assigned.
+
+
+
+McCloghrie, et al. Standards Track [Page 37]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+10.1. Object Assignments
+
+ If any non-editorial change is made to any clause of a object
+ assignment, then the OBJECT IDENTIFIER value associated with that
+ object assignment must also be changed, along with its associated
+ descriptor.
+
+10.2. Object Definitions
+
+ An object definition may be revised in any of the following ways:
+
+(1) A SYNTAX clause containing an enumerated INTEGER may have new
+ enumerations added or existing labels changed. Similarly, named
+ bits may be added or existing labels changed for the BITS
+ construct.
+
+(2) The value of a SYNTAX clause may be replaced by a textual
+ convention, providing the textual convention is defined to use the
+ same primitive ASN.1 type, has the same set of values, and has
+ identical semantics.
+
+(3) A STATUS clause value of "current" may be revised as "deprecated"
+ or "obsolete". Similarly, a STATUS clause value of "deprecated"
+ may be revised as "obsolete". When making such a change, the
+ DESCRIPTION clause should be updated to explain the rationale.
+
+(4) A DEFVAL clause may be added or updated.
+
+(5) A REFERENCE clause may be added or updated.
+
+(6) A UNITS clause may be added.
+
+(7) A conceptual row may be augmented by adding new columnar objects at
+ the end of the row, and making the corresponding update to the
+ SEQUENCE definition.
+
+(8) Clarifications and additional information may be included in the
+ DESCRIPTION clause.
+
+(9) Entirely new objects may be defined, named with previously
+ unassigned OBJECT IDENTIFIER values.
+
+ Otherwise, if the semantics of any previously defined object are
+ changed (i.e., if a non-editorial change is made to any clause other
+ than those specifically allowed above), then the OBJECT IDENTIFIER
+ value associated with that object must also be changed.
+
+
+
+
+McCloghrie, et al. Standards Track [Page 38]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ Note that changing the descriptor associated with an existing object
+ is considered a semantic change, as these strings may be used in an
+ IMPORTS statement.
+
+10.3. Notification Definitions
+
+ A notification definition may be revised in any of the following
+ ways:
+
+(1) A REFERENCE clause may be added or updated.
+
+(2) A STATUS clause value of "current" may be revised as "deprecated"
+ or "obsolete". Similarly, a STATUS clause value of "deprecated"
+ may be revised as "obsolete". When making such a change, the
+ DESCRIPTION clause should be updated to explain the rationale.
+
+(3) A DESCRIPTION clause may be clarified.
+
+ Otherwise, if the semantics of any previously defined notification
+ are changed (i.e., if a non-editorial change is made to any clause
+ other those specifically allowed above), then the OBJECT IDENTIFIER
+ value associated with that notification must also be changed.
+
+ Note that changing the descriptor associated with an existing
+ notification is considered a semantic change, as these strings may be
+ used in an IMPORTS statement.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 39]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+11. Appendix A: Detailed Sub-typing Rules
+
+
+11.1. Syntax Rules
+
+ The syntax rules for sub-typing are given below. Note that while
+ this syntax is based on ASN.1, it includes some extensions beyond
+ what is allowed in ASN.1, and a number of ASN.1 constructs are not
+ allowed by this syntax.
+
+ <integerSubType>
+ ::= <empty>
+ | "(" <range> ["|" <range>]... ")"
+
+ <octetStringSubType>
+ ::= <empty>
+ | "(" "SIZE" "(" <range> ["|" <range>]... ")" ")"
+
+ <range>
+ ::= <value>
+ | <value> ".." <value>
+
+ <value>
+ ::= "-" <number>
+ | <number>
+ | <hexString>
+ | <binString>
+
+ where:
+ <empty> is the empty string
+ <number> is a non-negative integer
+ <hexString> is a hexadecimal string (e.g., '0F0F'H)
+ <binString> is a binary string (e.g, '1010'B)
+
+ <range> is further restricted as follows:
+ - any <value> used in a SIZE clause must be non-negative.
+ - when a pair of values is specified, the first value
+ must be less than the second value.
+ - when multiple ranges are specified, the ranges may
+ not overlap but may touch. For example, (1..4 | 4..9)
+ is invalid, and (1..4 | 5..9) is valid.
+ - the ranges must be a subset of the maximum range of the
+ base type.
+
+
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 40]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+11.2. Examples
+
+ Some examples of legal sub-typing:
+
+ Integer32 (-20..100)
+ Integer32 (0..100 | 300..500)
+ Integer32 (300..500 | 0..100)
+ Integer32 (0 | 2 | 4 | 6 | 8 | 10)
+ OCTET STRING (SIZE(0..100))
+ OCTET STRING (SIZE(0..100 | 300..500))
+ OCTET STRING (SIZE(0 | 2 | 4 | 6 | 8 | 10))
+ SYNTAX TimeInterval (0..100)
+ SYNTAX DisplayString (SIZE(0..32))
+
+ (Note the last two examples above are not valid in a TEXTUAL
+ CONVENTION, see [3].)
+
+ Some examples of illegal sub-typing:
+
+ Integer32 (150..100) -- first greater than second
+ Integer32 (0..100 | 50..500) -- ranges overlap
+ Integer32 (0 | 2 | 0 ) -- value duplicated
+ Integer32 (MIN..-1 | 1..MAX) -- MIN and MAX not allowed
+ Integer32 (SIZE (0..34)) -- must not use SIZE
+ OCTET STRING (0..100) -- must use SIZE
+ OCTET STRING (SIZE(-10..100)) -- negative SIZE
+
+12. Security Considerations
+
+ This document defines a language with which to write and read
+ descriptions of management information. The language itself has no
+ security impact on the Internet.
+
+
+
+13. Editors' Addresses
+
+ Keith McCloghrie
+ Cisco Systems, Inc.
+ 170 West Tasman Drive
+ San Jose, CA 95134-1706
+ USA
+ Phone: +1 408 526 5260
+ EMail: kzm@cisco.com
+
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 41]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+ David Perkins
+ SNMPinfo
+ 3763 Benton Street
+ Santa Clara, CA 95051
+ USA
+ Phone: +1 408 221-8702
+ EMail: dperkins@snmpinfo.com
+
+ Juergen Schoenwaelder
+ TU Braunschweig
+ Bueltenweg 74/75
+ 38106 Braunschweig
+ Germany
+ Phone: +49 531 391-3283
+ EMail: schoenw@ibr.cs.tu-bs.de
+
+
+14. References
+
+[1] Information processing systems - Open Systems Interconnection -
+ Specification of Abstract Syntax Notation One (ASN.1),
+ International Organization for Standardization. International
+ Standard 8824, (December, 1987).
+
+[2] McCloghrie, K., Perkins, D., Schoenwaelder, J., Case, J., Rose, M.
+ and S. Waldbusser, "Conformance Statements for SMIv2", STD 58,
+ RFC 2580, April 1999.
+
+[3] McCloghrie, K., Perkins, D., Schoenwaelder, J., Case, J., Rose, M.
+ and S. Waldbusser, "Textual Conventions for SMIv2", STD 58,
+ RFC 2579, April 1999.
+
+[4] Information processing systems - Open Systems Interconnection -
+ Specification of Basic Encoding Rules for Abstract Syntax Notation
+ One (ASN.1), International Organization for Standardization.
+ International Standard 8825, (December, 1987).
+
+[5] The SNMPv2 Working Group, Case, J., McCloghrie, K., Rose, M. and
+ S. Waldbusser, "Management Information Base for Version 2 of the
+ Simple Network Management Protocol (SNMPv2)", RFC 1907, January
+ 1996.
+
+[6] The SNMPv2 Working Group, Case, J., McCloghrie, K., Rose, M. and
+ S. Waldbusser, "Protocol Operations for Version 2 of the Simple
+ Network Management Protocol (SNMPv2)", RFC 1905, January 1996.
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 42]
+
+
+
+
+
+RFC 2578 SMIv2 April 1999
+
+
+15. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE."
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 43]
+
+
+
+
+
diff --git a/standards/rfc2579.txt b/standards/rfc2579.txt
new file mode 100644
index 000000000..972eb029e
--- /dev/null
+++ b/standards/rfc2579.txt
@@ -0,0 +1,1533 @@
+
+
+
+
+
+
+
+Network Working Group Editors of this version:
+Request for Comments: 2579 K. McCloghrie
+STD: 58 Cisco Systems
+Obsoletes: 1903 D. Perkins
+Category: Standards Track SNMPinfo
+ J. Schoenwaelder
+ TU Braunschweig
+ Authors of previous version:
+ J. Case
+ SNMP Research
+ K. McCloghrie
+ Cisco Systems
+ M. Rose
+ First Virtual Holdings
+ S. Waldbusser
+ International Network Services
+ April 1999
+
+
+ Textual Conventions for SMIv2
+
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+
+Table of Contents
+
+ 1 Introduction ..................................................2
+ 1.1 A Note on Terminology .......................................2
+ 2 Definitions ...................................................2
+ 3 Mapping of the TEXTUAL-CONVENTION macro ......................20
+ 3.1 Mapping of the DISPLAY-HINT clause .........................21
+ 3.2 Mapping of the STATUS clause ...............................22
+ 3.3 Mapping of the DESCRIPTION clause ..........................23
+ 3.4 Mapping of the REFERENCE clause ............................23
+ 3.5 Mapping of the SYNTAX clause ...............................23
+ 4 Sub-typing of Textual Conventions ............................23
+ 5 Revising a Textual Convention Definition .....................23
+
+
+McCloghrie, et al. Standards Track [Page 1]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ 6 Security Considerations ......................................24
+ 7 Editors' Addresses ...........................................25
+ 8 References ...................................................25
+ 9 Full Copyright Statement .....................................26
+
+1. Introduction
+
+ Management information is viewed as a collection of managed objects,
+ residing in a virtual information store, termed the Management
+ Information Base (MIB). Collections of related objects are defined
+ in MIB modules. These modules are written using an adapted subset of
+ OSI's Abstract Syntax Notation One, ASN.1 (1988) [1], termed the
+ Structure of Management Information (SMI) [2].
+
+ When designing a MIB module, it is often useful to define new types
+ similar to those defined in the SMI. In comparison to a type defined
+ in the SMI, each of these new types has a different name, a similar
+ syntax, but a more precise semantics. These newly defined types are
+ termed textual conventions, and are used for the convenience of
+ humans reading the MIB module. It is the purpose of this document to
+ define the initial set of textual conventions available to all MIB
+ modules.
+
+ Objects defined using a textual convention are always encoded by
+ means of the rules that define their primitive type. However,
+ textual conventions often have special semantics associated with
+ them. As such, an ASN.1 macro, TEXTUAL-CONVENTION, is used to
+ concisely convey the syntax and semantics of a textual convention.
+
+1.1. A Note on Terminology
+
+ For the purpose of exposition, the original Structure of Management
+ Information, as described in RFCs 1155 (STD 16), 1212 (STD 16), and
+ RFC 1215, is termed the SMI version 1 (SMIv1). The current version
+ of the Structure of Management Information is termed SMI version 2
+ (SMIv2).
+
+2. Definitions
+
+SNMPv2-TC DEFINITIONS ::= BEGIN
+
+IMPORTS
+ TimeTicks FROM SNMPv2-SMI;
+
+
+-- definition of textual conventions
+
+TEXTUAL-CONVENTION MACRO ::=
+
+
+McCloghrie, et al. Standards Track [Page 2]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+BEGIN
+ TYPE NOTATION ::=
+ DisplayPart
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+ "SYNTAX" Syntax
+
+ VALUE NOTATION ::=
+ value(VALUE Syntax) -- adapted ASN.1
+
+ DisplayPart ::=
+ "DISPLAY-HINT" Text
+ | empty
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ -- a character string as defined in [2]
+ Text ::= value(IA5String)
+
+ Syntax ::= -- Must be one of the following:
+ -- a base type (or its refinement), or
+ -- a BITS pseudo-type
+ type
+ | "BITS" "{" NamedBits "}"
+
+ NamedBits ::= NamedBit
+ | NamedBits "," NamedBit
+
+ NamedBit ::= identifier "(" number ")" -- number is nonnegative
+
+END
+
+
+
+
+DisplayString ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "255a"
+ STATUS current
+ DESCRIPTION
+ "Represents textual information taken from the NVT ASCII
+
+
+McCloghrie, et al. Standards Track [Page 3]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ character set, as defined in pages 4, 10-11 of RFC 854.
+
+ To summarize RFC 854, the NVT ASCII repertoire specifies:
+
+ - the use of character codes 0-127 (decimal)
+
+ - the graphics characters (32-126) are interpreted as
+ US ASCII
+
+ - NUL, LF, CR, BEL, BS, HT, VT and FF have the special
+ meanings specified in RFC 854
+
+ - the other 25 codes have no standard interpretation
+
+ - the sequence 'CR LF' means newline
+
+ - the sequence 'CR NUL' means carriage-return
+
+ - an 'LF' not preceded by a 'CR' means moving to the
+ same column on the next line.
+
+ - the sequence 'CR x' for any x other than LF or NUL is
+ illegal. (Note that this also means that a string may
+ end with either 'CR LF' or 'CR NUL', but not with CR.)
+
+ Any object defined using this syntax may not exceed 255
+ characters in length."
+ SYNTAX OCTET STRING (SIZE (0..255))
+
+PhysAddress ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "1x:"
+ STATUS current
+ DESCRIPTION
+ "Represents media- or physical-level addresses."
+ SYNTAX OCTET STRING
+
+
+MacAddress ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "1x:"
+ STATUS current
+ DESCRIPTION
+ "Represents an 802 MAC address represented in the
+ `canonical' order defined by IEEE 802.1a, i.e., as if it
+ were transmitted least significant bit first, even though
+ 802.5 (in contrast to other 802.x protocols) requires MAC
+ addresses to be transmitted most significant bit first."
+ SYNTAX OCTET STRING (SIZE (6))
+
+
+
+McCloghrie, et al. Standards Track [Page 4]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+TruthValue ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents a boolean value."
+ SYNTAX INTEGER { true(1), false(2) }
+
+TestAndIncr ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents integer-valued information used for atomic
+ operations. When the management protocol is used to specify
+ that an object instance having this syntax is to be
+ modified, the new value supplied via the management protocol
+ must precisely match the value presently held by the
+ instance. If not, the management protocol set operation
+ fails with an error of `inconsistentValue'. Otherwise, if
+ the current value is the maximum value of 2^31-1 (2147483647
+ decimal), then the value held by the instance is wrapped to
+ zero; otherwise, the value held by the instance is
+ incremented by one. (Note that regardless of whether the
+ management protocol set operation succeeds, the variable-
+ binding in the request and response PDUs are identical.)
+
+ The value of the ACCESS clause for objects having this
+ syntax is either `read-write' or `read-create'. When an
+ instance of a columnar object having this syntax is created,
+ any value may be supplied via the management protocol.
+
+ When the network management portion of the system is re-
+ initialized, the value of every object instance having this
+ syntax must either be incremented from its value prior to
+ the re-initialization, or (if the value prior to the re-
+ initialization is unknown) be set to a pseudo-randomly
+ generated value."
+ SYNTAX INTEGER (0..2147483647)
+
+AutonomousType ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents an independently extensible type identification
+ value. It may, for example, indicate a particular sub-tree
+ with further MIB definitions, or define a particular type of
+ protocol or hardware."
+ SYNTAX OBJECT IDENTIFIER
+
+
+InstancePointer ::= TEXTUAL-CONVENTION
+ STATUS obsolete
+
+
+McCloghrie, et al. Standards Track [Page 5]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ DESCRIPTION
+ "A pointer to either a specific instance of a MIB object or
+ a conceptual row of a MIB table in the managed device. In
+ the latter case, by convention, it is the name of the
+ particular instance of the first accessible columnar object
+ in the conceptual row.
+
+ The two uses of this textual convention are replaced by
+ VariablePointer and RowPointer, respectively."
+ SYNTAX OBJECT IDENTIFIER
+
+
+VariablePointer ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "A pointer to a specific object instance. For example,
+ sysContact.0 or ifInOctets.3."
+ SYNTAX OBJECT IDENTIFIER
+
+
+RowPointer ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents a pointer to a conceptual row. The value is the
+ name of the instance of the first accessible columnar object
+ in the conceptual row.
+
+ For example, ifIndex.3 would point to the 3rd row in the
+ ifTable (note that if ifIndex were not-accessible, then
+ ifDescr.3 would be used instead)."
+ SYNTAX OBJECT IDENTIFIER
+
+RowStatus ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "The RowStatus textual convention is used to manage the
+ creation and deletion of conceptual rows, and is used as the
+ value of the SYNTAX clause for the status column of a
+ conceptual row (as described in Section 7.7.1 of [2].)
+
+
+
+
+
+
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 6]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ The status column has six defined values:
+
+ - `active', which indicates that the conceptual row is
+ available for use by the managed device;
+
+ - `notInService', which indicates that the conceptual
+ row exists in the agent, but is unavailable for use by
+ the managed device (see NOTE below); 'notInService' has
+ no implication regarding the internal consistency of
+ the row, availability of resources, or consistency with
+ the current state of the managed device;
+
+ - `notReady', which indicates that the conceptual row
+ exists in the agent, but is missing information
+ necessary in order to be available for use by the
+ managed device (i.e., one or more required columns in
+ the conceptual row have not been instanciated);
+
+ - `createAndGo', which is supplied by a management
+ station wishing to create a new instance of a
+ conceptual row and to have its status automatically set
+ to active, making it available for use by the managed
+ device;
+
+ - `createAndWait', which is supplied by a management
+ station wishing to create a new instance of a
+ conceptual row (but not make it available for use by
+ the managed device); and,
+
+ - `destroy', which is supplied by a management station
+ wishing to delete all of the instances associated with
+ an existing conceptual row.
+
+ Whereas five of the six values (all except `notReady') may
+ be specified in a management protocol set operation, only
+ three values will be returned in response to a management
+ protocol retrieval operation: `notReady', `notInService' or
+ `active'. That is, when queried, an existing conceptual row
+ has only three states: it is either available for use by
+ the managed device (the status column has value `active');
+ it is not available for use by the managed device, though
+ the agent has sufficient information to attempt to make it
+ so (the status column has value `notInService'); or, it is
+ not available for use by the managed device, and an attempt
+ to make it so would fail because the agent has insufficient
+ information (the state column has value `notReady').
+
+
+
+
+McCloghrie, et al. Standards Track [Page 7]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ NOTE WELL
+
+ This textual convention may be used for a MIB table,
+ irrespective of whether the values of that table's
+ conceptual rows are able to be modified while it is
+ active, or whether its conceptual rows must be taken
+ out of service in order to be modified. That is, it is
+ the responsibility of the DESCRIPTION clause of the
+ status column to specify whether the status column must
+ not be `active' in order for the value of some other
+ column of the same conceptual row to be modified. If
+ such a specification is made, affected columns may be
+ changed by an SNMP set PDU if the RowStatus would not
+ be equal to `active' either immediately before or after
+ processing the PDU. In other words, if the PDU also
+ contained a varbind that would change the RowStatus
+ value, the column in question may be changed if the
+ RowStatus was not equal to `active' as the PDU was
+ received, or if the varbind sets the status to a value
+ other than 'active'.
+
+
+ Also note that whenever any elements of a row exist, the
+ RowStatus column must also exist.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 8]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ To summarize the effect of having a conceptual row with a
+ status column having a SYNTAX clause value of RowStatus,
+ consider the following state diagram:
+
+
+ STATE
+ +--------------+-----------+-------------+-------------
+ | A | B | C | D
+ | |status col.|status column|
+ |status column | is | is |status column
+ ACTION |does not exist| notReady | notInService| is active
+--------------+--------------+-----------+-------------+-------------
+set status |noError ->D|inconsist- |inconsistent-|inconsistent-
+column to | or | entValue| Value| Value
+createAndGo |inconsistent- | | |
+ | Value| | |
+--------------+--------------+-----------+-------------+-------------
+set status |noError see 1|inconsist- |inconsistent-|inconsistent-
+column to | or | entValue| Value| Value
+createAndWait |wrongValue | | |
+--------------+--------------+-----------+-------------+-------------
+set status |inconsistent- |inconsist- |noError |noError
+column to | Value| entValue| |
+active | | | |
+ | | or | |
+ | | | |
+ | |see 2 ->D|see 8 ->D| ->D
+--------------+--------------+-----------+-------------+-------------
+set status |inconsistent- |inconsist- |noError |noError ->C
+column to | Value| entValue| |
+notInService | | | |
+ | | or | | or
+ | | | |
+ | |see 3 ->C| ->C|see 6
+--------------+--------------+-----------+-------------+-------------
+set status |noError |noError |noError |noError ->A
+column to | | | | or
+destroy | ->A| ->A| ->A|see 7
+--------------+--------------+-----------+-------------+-------------
+set any other |see 4 |noError |noError |see 5
+column to some| | | |
+value | | see 1| ->C| ->D
+--------------+--------------+-----------+-------------+-------------
+
+ (1) goto B or C, depending on information available to the
+ agent.
+
+ (2) if other variable bindings included in the same PDU,
+
+
+McCloghrie, et al. Standards Track [Page 9]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ provide values for all columns which are missing but
+ required, and all columns have acceptable values, then
+ return noError and goto D.
+
+ (3) if other variable bindings included in the same PDU,
+ provide legal values for all columns which are missing but
+ required, then return noError and goto C.
+
+ (4) at the discretion of the agent, the return value may be
+ either:
+
+ inconsistentName: because the agent does not choose to
+ create such an instance when the corresponding
+ RowStatus instance does not exist, or
+
+ inconsistentValue: if the supplied value is
+ inconsistent with the state of some other MIB object's
+ value, or
+
+ noError: because the agent chooses to create the
+ instance.
+
+ If noError is returned, then the instance of the status
+ column must also be created, and the new state is B or C,
+ depending on the information available to the agent. If
+ inconsistentName or inconsistentValue is returned, the row
+ remains in state A.
+
+ (5) depending on the MIB definition for the column/table,
+ either noError or inconsistentValue may be returned.
+
+ (6) the return value can indicate one of the following
+ errors:
+
+ wrongValue: because the agent does not support
+ notInService (e.g., an agent which does not support
+ createAndWait), or
+
+ inconsistentValue: because the agent is unable to take
+ the row out of service at this time, perhaps because it
+ is in use and cannot be de-activated.
+
+ (7) the return value can indicate the following error:
+
+ inconsistentValue: because the agent is unable to
+ remove the row at this time, perhaps because it is in
+ use and cannot be de-activated.
+
+
+
+McCloghrie, et al. Standards Track [Page 10]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ (8) the transition to D can fail, e.g., if the values of the
+ conceptual row are inconsistent, then the error code would
+ be inconsistentValue.
+
+ NOTE: Other processing of (this and other varbinds of) the
+ set request may result in a response other than noError
+ being returned, e.g., wrongValue, noCreation, etc.
+
+
+ Conceptual Row Creation
+
+ There are four potential interactions when creating a
+ conceptual row: selecting an instance-identifier which is
+ not in use; creating the conceptual row; initializing any
+ objects for which the agent does not supply a default; and,
+ making the conceptual row available for use by the managed
+ device.
+
+ Interaction 1: Selecting an Instance-Identifier
+
+ The algorithm used to select an instance-identifier varies
+ for each conceptual row. In some cases, the instance-
+ identifier is semantically significant, e.g., the
+ destination address of a route, and a management station
+ selects the instance-identifier according to the semantics.
+
+ In other cases, the instance-identifier is used solely to
+ distinguish conceptual rows, and a management station
+ without specific knowledge of the conceptual row might
+ examine the instances present in order to determine an
+ unused instance-identifier. (This approach may be used, but
+ it is often highly sub-optimal; however, it is also a
+ questionable practice for a naive management station to
+ attempt conceptual row creation.)
+
+ Alternately, the MIB module which defines the conceptual row
+ might provide one or more objects which provide assistance
+ in determining an unused instance-identifier. For example,
+ if the conceptual row is indexed by an integer-value, then
+ an object having an integer-valued SYNTAX clause might be
+ defined for such a purpose, allowing a management station to
+ issue a management protocol retrieval operation. In order
+ to avoid unnecessary collisions between competing management
+ stations, `adjacent' retrievals of this object should be
+ different.
+
+ Finally, the management station could select a pseudo-random
+ number to use as the index. In the event that this index
+
+
+McCloghrie, et al. Standards Track [Page 11]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ was already in use and an inconsistentValue was returned in
+ response to the management protocol set operation, the
+ management station should simply select a new pseudo-random
+ number and retry the operation.
+
+ A MIB designer should choose between the two latter
+ algorithms based on the size of the table (and therefore the
+ efficiency of each algorithm). For tables in which a large
+ number of entries are expected, it is recommended that a MIB
+ object be defined that returns an acceptable index for
+ creation. For tables with small numbers of entries, it is
+ recommended that the latter pseudo-random index mechanism be
+ used.
+
+ Interaction 2: Creating the Conceptual Row
+
+ Once an unused instance-identifier has been selected, the
+ management station determines if it wishes to create and
+ activate the conceptual row in one transaction or in a
+ negotiated set of interactions.
+
+ Interaction 2a: Creating and Activating the Conceptual Row
+
+ The management station must first determine the column
+ requirements, i.e., it must determine those columns for
+ which it must or must not provide values. Depending on the
+ complexity of the table and the management station's
+ knowledge of the agent's capabilities, this determination
+ can be made locally by the management station. Alternately,
+ the management station issues a management protocol get
+ operation to examine all columns in the conceptual row that
+ it wishes to create. In response, for each column, there
+ are three possible outcomes:
+
+ - a value is returned, indicating that some other
+ management station has already created this conceptual
+ row. We return to interaction 1.
+
+ - the exception `noSuchInstance' is returned,
+ indicating that the agent implements the object-type
+ associated with this column, and that this column in at
+ least one conceptual row would be accessible in the MIB
+ view used by the retrieval were it to exist. For those
+ columns to which the agent provides read-create access,
+ the `noSuchInstance' exception tells the management
+ station that it should supply a value for this column
+ when the conceptual row is to be created.
+
+
+
+McCloghrie, et al. Standards Track [Page 12]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ - the exception `noSuchObject' is returned, indicating
+ that the agent does not implement the object-type
+ associated with this column or that there is no
+ conceptual row for which this column would be
+ accessible in the MIB view used by the retrieval. As
+ such, the management station can not issue any
+ management protocol set operations to create an
+ instance of this column.
+
+ Once the column requirements have been determined, a
+ management protocol set operation is accordingly issued.
+ This operation also sets the new instance of the status
+ column to `createAndGo'.
+
+ When the agent processes the set operation, it verifies that
+ it has sufficient information to make the conceptual row
+ available for use by the managed device. The information
+ available to the agent is provided by two sources: the
+ management protocol set operation which creates the
+ conceptual row, and, implementation-specific defaults
+ supplied by the agent (note that an agent must provide
+ implementation-specific defaults for at least those objects
+ which it implements as read-only). If there is sufficient
+ information available, then the conceptual row is created, a
+ `noError' response is returned, the status column is set to
+ `active', and no further interactions are necessary (i.e.,
+ interactions 3 and 4 are skipped). If there is insufficient
+ information, then the conceptual row is not created, and the
+ set operation fails with an error of `inconsistentValue'.
+ On this error, the management station can issue a management
+ protocol retrieval operation to determine if this was
+ because it failed to specify a value for a required column,
+ or, because the selected instance of the status column
+ already existed. In the latter case, we return to
+ interaction 1. In the former case, the management station
+ can re-issue the set operation with the additional
+ information, or begin interaction 2 again using
+ `createAndWait' in order to negotiate creation of the
+ conceptual row.
+
+
+
+
+
+
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 13]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ NOTE WELL
+
+ Regardless of the method used to determine the column
+ requirements, it is possible that the management
+ station might deem a column necessary when, in fact,
+ the agent will not allow that particular columnar
+ instance to be created or written. In this case, the
+ management protocol set operation will fail with an
+ error such as `noCreation' or `notWritable'. In this
+ case, the management station decides whether it needs
+ to be able to set a value for that particular columnar
+ instance. If not, the management station re-issues the
+ management protocol set operation, but without setting
+ a value for that particular columnar instance;
+ otherwise, the management station aborts the row
+ creation algorithm.
+
+ Interaction 2b: Negotiating the Creation of the Conceptual
+ Row
+
+ The management station issues a management protocol set
+ operation which sets the desired instance of the status
+ column to `createAndWait'. If the agent is unwilling to
+ process a request of this sort, the set operation fails with
+ an error of `wrongValue'. (As a consequence, such an agent
+ must be prepared to accept a single management protocol set
+ operation, i.e., interaction 2a above, containing all of the
+ columns indicated by its column requirements.) Otherwise,
+ the conceptual row is created, a `noError' response is
+ returned, and the status column is immediately set to either
+ `notInService' or `notReady', depending on whether it has
+ sufficient information to (attempt to) make the conceptual
+ row available for use by the managed device. If there is
+ sufficient information available, then the status column is
+ set to `notInService'; otherwise, if there is insufficient
+ information, then the status column is set to `notReady'.
+ Regardless, we proceed to interaction 3.
+
+ Interaction 3: Initializing non-defaulted Objects
+
+ The management station must now determine the column
+ requirements. It issues a management protocol get operation
+ to examine all columns in the created conceptual row. In
+ the response, for each column, there are three possible
+ outcomes:
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 14]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ - a value is returned, indicating that the agent
+ implements the object-type associated with this column
+ and had sufficient information to provide a value. For
+ those columns to which the agent provides read-create
+ access (and for which the agent allows their values to
+ be changed after their creation), a value return tells
+ the management station that it may issue additional
+ management protocol set operations, if it desires, in
+ order to change the value associated with this column.
+
+ - the exception `noSuchInstance' is returned,
+ indicating that the agent implements the object-type
+ associated with this column, and that this column in at
+ least one conceptual row would be accessible in the MIB
+ view used by the retrieval were it to exist. However,
+ the agent does not have sufficient information to
+ provide a value, and until a value is provided, the
+ conceptual row may not be made available for use by the
+ managed device. For those columns to which the agent
+ provides read-create access, the `noSuchInstance'
+ exception tells the management station that it must
+ issue additional management protocol set operations, in
+ order to provide a value associated with this column.
+
+ - the exception `noSuchObject' is returned, indicating
+ that the agent does not implement the object-type
+ associated with this column or that there is no
+ conceptual row for which this column would be
+ accessible in the MIB view used by the retrieval. As
+ such, the management station can not issue any
+ management protocol set operations to create an
+ instance of this column.
+
+ If the value associated with the status column is
+ `notReady', then the management station must first deal with
+ all `noSuchInstance' columns, if any. Having done so, the
+ value of the status column becomes `notInService', and we
+ proceed to interaction 4.
+
+
+
+
+
+
+
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 15]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ Interaction 4: Making the Conceptual Row Available
+
+ Once the management station is satisfied with the values
+ associated with the columns of the conceptual row, it issues
+ a management protocol set operation to set the status column
+ to `active'. If the agent has sufficient information to
+ make the conceptual row available for use by the managed
+ device, the management protocol set operation succeeds (a
+ `noError' response is returned). Otherwise, the management
+ protocol set operation fails with an error of
+ `inconsistentValue'.
+
+ NOTE WELL
+
+ A conceptual row having a status column with value
+ `notInService' or `notReady' is unavailable to the
+ managed device. As such, it is possible for the
+ managed device to create its own instances during the
+ time between the management protocol set operation
+ which sets the status column to `createAndWait' and the
+ management protocol set operation which sets the status
+ column to `active'. In this case, when the management
+ protocol set operation is issued to set the status
+ column to `active', the values held in the agent
+ supersede those used by the managed device.
+
+ If the management station is prevented from setting the
+ status column to `active' (e.g., due to management station
+ or network failure) the conceptual row will be left in the
+ `notInService' or `notReady' state, consuming resources
+ indefinitely. The agent must detect conceptual rows that
+ have been in either state for an abnormally long period of
+ time and remove them. It is the responsibility of the
+ DESCRIPTION clause of the status column to indicate what an
+ abnormally long period of time would be. This period of
+ time should be long enough to allow for human response time
+ (including `think time') between the creation of the
+ conceptual row and the setting of the status to `active'.
+ In the absence of such information in the DESCRIPTION
+ clause, it is suggested that this period be approximately 5
+ minutes in length. This removal action applies not only to
+ newly-created rows, but also to previously active rows which
+ are set to, and left in, the notInService state for a
+ prolonged period exceeding that which is considered normal
+ for such a conceptual row.
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 16]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ Conceptual Row Suspension
+
+ When a conceptual row is `active', the management station
+ may issue a management protocol set operation which sets the
+ instance of the status column to `notInService'. If the
+ agent is unwilling to do so, the set operation fails with an
+ error of `wrongValue' or `inconsistentValue'. Otherwise,
+ the conceptual row is taken out of service, and a `noError'
+ response is returned. It is the responsibility of the
+ DESCRIPTION clause of the status column to indicate under
+ what circumstances the status column should be taken out of
+ service (e.g., in order for the value of some other column
+ of the same conceptual row to be modified).
+
+
+ Conceptual Row Deletion
+
+ For deletion of conceptual rows, a management protocol set
+ operation is issued which sets the instance of the status
+ column to `destroy'. This request may be made regardless of
+ the current value of the status column (e.g., it is possible
+ to delete conceptual rows which are either `notReady',
+ `notInService' or `active'.) If the operation succeeds,
+ then all instances associated with the conceptual row are
+ immediately removed."
+ SYNTAX INTEGER {
+ -- the following two values are states:
+ -- these values may be read or written
+ active(1),
+ notInService(2),
+
+ -- the following value is a state:
+ -- this value may be read, but not written
+ notReady(3),
+
+ -- the following three values are
+ -- actions: these values may be written,
+ -- but are never read
+ createAndGo(4),
+ createAndWait(5),
+ destroy(6)
+ }
+
+TimeStamp ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "The value of the sysUpTime object at which a specific
+ occurrence happened. The specific occurrence must be
+
+
+McCloghrie, et al. Standards Track [Page 17]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ defined in the description of any object defined using this
+ type.
+
+ If sysUpTime is reset to zero as a result of a re-
+ initialization of the network management (sub)system, then
+ the values of all TimeStamp objects are also reset.
+ However, after approximately 497 days without a re-
+ initialization, the sysUpTime object will reach 2^^32-1 and
+ then increment around to zero; in this case, existing values
+ of TimeStamp objects do not change. This can lead to
+ ambiguities in the value of TimeStamp objects."
+ SYNTAX TimeTicks
+
+
+TimeInterval ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "A period of time, measured in units of 0.01 seconds."
+ SYNTAX INTEGER (0..2147483647)
+
+DateAndTime ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
+ STATUS current
+ DESCRIPTION
+ "A date-time specification.
+
+ field octets contents range
+ ----- ------ -------- -----
+ 1 1-2 year* 0..65536
+ 2 3 month 1..12
+ 3 4 day 1..31
+ 4 5 hour 0..23
+ 5 6 minutes 0..59
+ 6 7 seconds 0..60
+ (use 60 for leap-second)
+ 7 8 deci-seconds 0..9
+ 8 9 direction from UTC '+' / '-'
+ 9 10 hours from UTC* 0..13
+ 10 11 minutes from UTC 0..59
+
+ * Notes:
+ - the value of year is in network-byte order
+ - daylight saving time in New Zealand is +13
+
+ For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
+ displayed as:
+
+ 1992-5-26,13:30:15.0,-4:0
+
+
+McCloghrie, et al. Standards Track [Page 18]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ Note that if only local time is known, then timezone
+ information (fields 8-10) is not present."
+ SYNTAX OCTET STRING (SIZE (8 | 11))
+
+
+StorageType ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Describes the memory realization of a conceptual row. A
+ row which is volatile(2) is lost upon reboot. A row which
+ is either nonVolatile(3), permanent(4) or readOnly(5), is
+ backed up by stable storage. A row which is permanent(4)
+ can be changed but not deleted. A row which is readOnly(5)
+ cannot be changed nor deleted.
+
+ If the value of an object with this syntax is either
+ permanent(4) or readOnly(5), it cannot be written.
+ Conversely, if the value is either other(1), volatile(2) or
+ nonVolatile(3), it cannot be modified to be permanent(4) or
+ readOnly(5). (All illegal modifications result in a
+ 'wrongValue' error.)
+
+ Every usage of this textual convention is required to
+ specify the columnar objects which a permanent(4) row must
+ at a minimum allow to be writable."
+ SYNTAX INTEGER {
+ other(1), -- eh?
+ volatile(2), -- e.g., in RAM
+ nonVolatile(3), -- e.g., in NVRAM
+ permanent(4), -- e.g., partially in ROM
+ readOnly(5) -- e.g., completely in ROM
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 19]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+TDomain ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Denotes a kind of transport service.
+
+ Some possible values, such as snmpUDPDomain, are defined in
+ the SNMPv2-TM MIB module. Other possible values are defined
+ in other MIB modules."
+ REFERENCE "The SNMPv2-TM MIB module is defined in RFC 1906."
+ SYNTAX OBJECT IDENTIFIER
+
+
+TAddress ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Denotes a transport service address.
+
+ A TAddress value is always interpreted within the context of a
+ TDomain value. Thus, each definition of a TDomain value must
+ be accompanied by a definition of a textual convention for use
+ with that TDomain. Some possible textual conventions, such as
+ SnmpUDPAddress for snmpUDPDomain, are defined in the SNMPv2-TM
+ MIB module. Other possible textual conventions are defined in
+ other MIB modules."
+ REFERENCE "The SNMPv2-TM MIB module is defined in RFC 1906."
+ SYNTAX OCTET STRING (SIZE (1..255))
+
+
+END
+
+3. Mapping of the TEXTUAL-CONVENTION macro
+
+ The TEXTUAL-CONVENTION macro is used to convey the syntax and
+ semantics associated with a textual convention. It should be noted
+ that the expansion of the TEXTUAL-CONVENTION macro is something which
+ conceptually happens during implementation and not during run-time.
+
+ The name of a textual convention must consist of one or more letters
+ or digits, with the initial character being an upper case letter.
+ The name must not conflict with any of the reserved words listed in
+ section 3.7 of [2], should not consist of all upper case letters, and
+ shall not exceed 64 characters in length. (However, names longer
+ than 32 characters are not recommended.) The hyphen is not allowed
+ in the name of a textual convention (except for use in information
+ modules converted from SMIv1 which allowed hyphens in ASN.1 type
+ assignments). Further, all names used for the textual conventions
+ defined in all "standard" information modules shall be unique.
+
+
+
+McCloghrie, et al. Standards Track [Page 20]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+3.1. Mapping of the DISPLAY-HINT clause
+
+ The DISPLAY-HINT clause, which need not be present, gives a hint as
+ to how the value of an instance of an object with the syntax defined
+ using this textual convention might be displayed. The DISPLAY-HINT
+ clause must not be present if the Textual Convention is defined with
+ a syntax of: OBJECT IDENTIFIER, IpAddress, Counter32, Counter64, or
+ any enumerated syntax (BITS or INTEGER). The determination of
+ whether it makes sense for other syntax types is dependent on the
+ specific definition of the Textual Convention.
+
+ When the syntax has an underlying primitive type of INTEGER, the hint
+ consists of an integer-format specification, containing two parts.
+ The first part is a single character suggesting a display format,
+ either: `x' for hexadecimal, or `d' for decimal, or `o' for octal, or
+ `b' for binary. For all types, when rendering the value, leading
+ zeros are omitted, and for negative values, a minus sign is rendered
+ immediately before the digits. The second part is always omitted for
+ `x', `o' and `b', and need not be present for `d'. If present, the
+ second part starts with a hyphen and is followed by a decimal number,
+ which defines the implied decimal point when rendering the value.
+ For example:
+
+ Hundredths ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "d-2"
+ ...
+ SYNTAX INTEGER (0..10000)
+
+ suggests that a Hundredths value of 1234 be rendered as "12.34"
+
+
+ When the syntax has an underlying primitive type of OCTET STRING, the
+ hint consists of one or more octet-format specifications. Each
+ specification consists of five parts, with each part using and
+ removing zero or more of the next octets from the value and producing
+ the next zero or more characters to be displayed. The octets within
+ the value are processed in order of significance, most significant
+ first.
+
+ The five parts of a octet-format specification are:
+
+(1) the (optional) repeat indicator; if present, this part is a `*',
+ and indicates that the current octet of the value is to be used as
+ the repeat count. The repeat count is an unsigned integer (which
+ may be zero) which specifies how many times the remainder of this
+ octet-format specification should be successively applied. If the
+ repeat indicator is not present, the repeat count is one.
+
+
+
+McCloghrie, et al. Standards Track [Page 21]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+(2) the octet length: one or more decimal digits specifying the number
+ of octets of the value to be used and formatted by this octet-
+ specification. Note that the octet length can be zero. If less
+ than this number of octets remain in the value, then the lesser
+ number of octets are used.
+
+(3) the display format, either: `x' for hexadecimal, `d' for decimal,
+ `o' for octal, `a' for ascii, or `t' for UTF-8. If the octet
+ length part is greater than one, and the display format part refers
+ to a numeric format, then network-byte ordering (big-endian
+ encoding) is used interpreting the octets in the value. The octets
+ processed by the `t' display format do not necessarily form an
+ integral number of UTF-8 characters. Trailing octets which do not
+ form a valid UTF-8 encoded character are discarded.
+
+(4) the (optional) display separator character; if present, this part
+ is a single character which is produced for display after each
+ application of this octet-specification; however, this character is
+ not produced for display if it would be immediately followed by the
+ display of the repeat terminator character for this octet-
+ specification. This character can be any character other than a
+ decimal digit and a `*'.
+
+(5) the (optional) repeat terminator character, which can be present
+ only if the display separator character is present and this octet-
+ specification begins with a repeat indicator; if present, this part
+ is a single character which is produced after all the zero or more
+ repeated applications (as given by the repeat count) of this
+ octet-specification. This character can be any character other
+ than a decimal digit and a `*'.
+
+ Output of a display separator character or a repeat terminator
+ character is suppressed if it would occur as the last character of
+ the display.
+
+ If the octets of the value are exhausted before all the octet-format
+ specification have been used, then the excess specifications are
+ ignored. If additional octets remain in the value after interpreting
+ all the octet-format specifications, then the last octet-format
+ specification is re-interpreted to process the additional octets,
+ until no octets remain in the value.
+
+3.2. Mapping of the STATUS clause
+
+ The STATUS clause, which must be present, indicates whether this
+ definition is current or historic.
+
+ The value "current" means that the definition is current and valid.
+
+
+McCloghrie, et al. Standards Track [Page 22]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ The value "obsolete" means the definition is obsolete and should not
+ be implemented and/or can be removed if previously implemented.
+ While the value "deprecated" also indicates an obsolete definition,
+ it permits new/continued implementation in order to foster
+ interoperability with older/existing implementations.
+
+3.3. Mapping of the DESCRIPTION clause
+
+ The DESCRIPTION clause, which must be present, contains a textual
+ definition of the textual convention, which provides all semantic
+ definitions necessary for implementation, and should embody any
+ information which would otherwise be communicated in any ASN.1
+ commentary annotations associated with the object.
+
+3.4. Mapping of the REFERENCE clause
+
+ The REFERENCE clause, which need not be present, contains a textual
+ cross-reference to some other document, either another information
+ module which defines a related assignment, or some other document
+ which provides additional information relevant to this definition.
+
+3.5. Mapping of the SYNTAX clause
+
+ The SYNTAX clause, which must be present, defines abstract data
+ structure corresponding to the textual convention. The data
+ structure must be one of the alternatives defined in the ObjectSyntax
+ CHOICE or the BITS construct (see section 7.1 in [2]). Note that
+ this means that the SYNTAX clause of a Textual Convention can not
+ refer to a previously defined Textual Convention.
+
+ An extended subset of the full capabilities of ASN.1 (1988) sub-
+ typing is allowed, as appropriate to the underlying ASN.1 type. Any
+ such restriction on size, range or enumerations specified in this
+ clause represents the maximal level of support which makes "protocol
+ sense". Restrictions on sub-typing are specified in detail in
+ Section 9 and Appendix A of [2].
+
+4. Sub-typing of Textual Conventions
+
+ The SYNTAX clause of a TEXTUAL CONVENTION macro may be sub-typed in
+ the same way as the SYNTAX clause of an OBJECT-TYPE macro (see
+ section 11 of [2]).
+
+5. Revising a Textual Convention Definition
+
+ It may be desirable to revise the definition of a textual convention
+ after experience is gained with it. However, changes are not allowed
+ if they have any potential to cause interoperability problems "over
+
+
+McCloghrie, et al. Standards Track [Page 23]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+ the wire" between an implementation using an original specification
+ and an implementation using an updated specification(s). Such
+ changes can only be accommodated by defining a new textual convention
+ (i.e., a new name).
+
+ The following revisions are allowed:
+
+(1) A SYNTAX clause containing an enumerated INTEGER may have new
+ enumerations added or existing labels changed. Similarly, named
+ bits may be added or existing labels changed for the BITS
+ construct.
+
+(2) A STATUS clause value of "current" may be revised as "deprecated"
+ or "obsolete". Similarly, a STATUS clause value of "deprecated"
+ may be revised as "obsolete". When making such a change, the
+ DESCRIPTION clause should be updated to explain the rationale.
+
+(3) A REFERENCE clause may be added or updated.
+
+(4) A DISPLAY-HINTS clause may be added or updated.
+
+(5) Clarifications and additional information may be included in the
+ DESCRIPTION clause.
+
+(6) Any editorial change.
+
+ Note that with the introduction of the TEXTUAL-CONVENTION macro,
+ there is no longer any need to define types in the following manner:
+
+ DisplayString ::= OCTET STRING (SIZE (0..255))
+
+ When revising an information module containing a definition such as
+ this, that definition should be replaced by a TEXTUAL-CONVENTION
+ macro.
+
+6. Security Considerations
+
+ This document defines the means to define new data types for the
+ language used to write and read descriptions of management
+ information. These data types have no security impact on the
+ Internet.
+
+
+
+
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 24]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+7. Editors' Addresses
+
+ Keith McCloghrie
+ Cisco Systems, Inc.
+ 170 West Tasman Drive
+ San Jose, CA 95134-1706
+ USA
+ Phone: +1 408 526 5260
+ EMail: kzm@cisco.com
+
+ David Perkins
+ SNMPinfo
+ 3763 Benton Street
+ Santa Clara, CA 95051
+ USA
+ Phone: +1 408 221-8702
+ EMail: dperkins@snmpinfo.com
+
+ Juergen Schoenwaelder
+ TU Braunschweig
+ Bueltenweg 74/75
+ 38106 Braunschweig
+ Germany
+ Phone: +49 531 391-3283
+ EMail: schoenw@ibr.cs.tu-bs.de
+
+
+8. References
+
+[1] Information processing systems - Open Systems Interconnection -
+ Specification of Abstract Syntax Notation One (ASN.1),
+ International Organization for Standardization. International
+ Standard 8824, (December, 1987).
+
+[2] McCloghrie, K., Perkins, D., Schoenwaelder, J., Case, J., Rose, M.
+ and S. Waldbusser, "Structure of Management Information Version 2
+ (SMIv2)", STD 58, RFC 2578, April 1999.
+
+[3] The SNMPv2 Working Group, Case, J., McCloghrie, K., Rose, M. and
+ Waldbusser, S., "Transport Mappings for Version 2 of the" Simple
+ Network Management Protocol (SNMPv2)", RFC 1906, January 1996.
+
+
+
+
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 25]
+
+
+
+
+
+RFC 2579 Textual Conventions for SMIv2 April 1999
+
+
+9. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE."
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+McCloghrie, et al. Standards Track [Page 26]
diff --git a/standards/rfc2595.txt b/standards/rfc2595.txt
new file mode 100644
index 000000000..66897cd6c
--- /dev/null
+++ b/standards/rfc2595.txt
@@ -0,0 +1,843 @@
+
+
+
+
+
+
+Network Working Group C. Newman
+Request for Comments: 2595 Innosoft
+Category: Standards Track June 1999
+
+
+ Using TLS with IMAP, POP3 and ACAP
+
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+1. Motivation
+
+ The TLS protocol (formerly known as SSL) provides a way to secure an
+ application protocol from tampering and eavesdropping. The option of
+ using such security is desirable for IMAP, POP and ACAP due to common
+ connection eavesdropping and hijacking attacks [AUTH]. Although
+ advanced SASL authentication mechanisms can provide a lightweight
+ version of this service, TLS is complimentary to simple
+ authentication-only SASL mechanisms or deployed clear-text password
+ login commands.
+
+ Many sites have a high investment in authentication infrastructure
+ (e.g., a large database of a one-way-function applied to user
+ passwords), so a privacy layer which is not tightly bound to user
+ authentication can protect against network eavesdropping attacks
+ without requiring a new authentication infrastructure and/or forcing
+ all users to change their password. Recognizing that such sites will
+ desire simple password authentication in combination with TLS
+ encryption, this specification defines the PLAIN SASL mechanism for
+ use with protocols which lack a simple password authentication
+ command such as ACAP and SMTP. (Note there is a separate RFC for the
+ STARTTLS command in SMTP [SMTPTLS].)
+
+ There is a strong desire in the IETF to eliminate the transmission of
+ clear-text passwords over unencrypted channels. While SASL can be
+ used for this purpose, TLS provides an additional tool with different
+ deployability characteristics. A server supporting both TLS with
+
+
+
+
+Newman Standards Track [Page 1]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ simple passwords and a challenge/response SASL mechanism is likely to
+ interoperate with a wide variety of clients without resorting to
+ unencrypted clear-text passwords.
+
+ The STARTTLS command rectifies a number of the problems with using a
+ separate port for a "secure" protocol variant. Some of these are
+ mentioned in section 7.
+
+1.1. Conventions Used in this Document
+
+ The key words "REQUIRED", "MUST", "MUST NOT", "SHOULD", "SHOULD NOT",
+ "MAY", and "OPTIONAL" in this document are to be interpreted as
+ described in "Key words for use in RFCs to Indicate Requirement
+ Levels" [KEYWORDS].
+
+ Terms related to authentication are defined in "On Internet
+ Authentication" [AUTH].
+
+ Formal syntax is defined using ABNF [ABNF].
+
+ In examples, "C:" and "S:" indicate lines sent by the client and
+ server respectively.
+
+2. Basic Interoperability and Security Requirements
+
+ The following requirements apply to all implementations of the
+ STARTTLS extension for IMAP, POP3 and ACAP.
+
+2.1. Cipher Suite Requirements
+
+ Implementation of the TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA [TLS] cipher
+ suite is REQUIRED. This is important as it assures that any two
+ compliant implementations can be configured to interoperate.
+
+ All other cipher suites are OPTIONAL.
+
+2.2. Privacy Operational Mode Security Requirements
+
+ Both clients and servers SHOULD have a privacy operational mode which
+ refuses authentication unless successful activation of an encryption
+ layer (such as that provided by TLS) occurs prior to or at the time
+ of authentication and which will terminate the connection if that
+ encryption layer is deactivated. Implementations are encouraged to
+ have flexability with respect to the minimal encryption strength or
+ cipher suites permitted. A minimalist approach to this
+ recommendation would be an operational mode where the
+ TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA cipher suite is mandatory prior to
+ permitting authentication.
+
+
+
+Newman Standards Track [Page 2]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ Clients MAY have an operational mode which uses encryption only when
+ it is advertised by the server, but authentication continues
+ regardless. For backwards compatibility, servers SHOULD have an
+ operational mode where only the authentication mechanisms required by
+ the relevant base protocol specification are needed to successfully
+ authenticate.
+
+2.3. Clear-Text Password Requirements
+
+ Clients and servers which implement STARTTLS MUST be configurable to
+ refuse all clear-text login commands or mechanisms (including both
+ standards-track and nonstandard mechanisms) unless an encryption
+ layer of adequate strength is active. Servers which allow
+ unencrypted clear-text logins SHOULD be configurable to refuse
+ clear-text logins both for the entire server, and on a per-user
+ basis.
+
+2.4. Server Identity Check
+
+ During the TLS negotiation, the client MUST check its understanding
+ of the server hostname against the server's identity as presented in
+ the server Certificate message, in order to prevent man-in-the-middle
+ attacks. Matching is performed according to these rules:
+
+ - The client MUST use the server hostname it used to open the
+ connection as the value to compare against the server name as
+ expressed in the server certificate. The client MUST NOT use any
+ form of the server hostname derived from an insecure remote source
+ (e.g., insecure DNS lookup). CNAME canonicalization is not done.
+
+ - If a subjectAltName extension of type dNSName is present in the
+ certificate, it SHOULD be used as the source of the server's
+ identity.
+
+ - Matching is case-insensitive.
+
+ - A "*" wildcard character MAY be used as the left-most name
+ component in the certificate. For example, *.example.com would
+ match a.example.com, foo.example.com, etc. but would not match
+ example.com.
+
+ - If the certificate contains multiple names (e.g. more than one
+ dNSName field), then a match with any one of the fields is
+ considered acceptable.
+
+ If the match fails, the client SHOULD either ask for explicit user
+ confirmation, or terminate the connection and indicate the server's
+ identity is suspect.
+
+
+
+Newman Standards Track [Page 3]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+2.5. TLS Security Policy Check
+
+ Both the client and server MUST check the result of the STARTTLS
+ command and subsequent TLS negotiation to see whether acceptable
+ authentication or privacy was achieved. Ignoring this step
+ completely invalidates using TLS for security. The decision about
+ whether acceptable authentication or privacy was achieved is made
+ locally, is implementation-dependent, and is beyond the scope of this
+ document.
+
+3. IMAP STARTTLS extension
+
+ When the TLS extension is present in IMAP, "STARTTLS" is listed as a
+ capability in response to the CAPABILITY command. This extension
+ adds a single command, "STARTTLS" to the IMAP protocol which is used
+ to begin a TLS negotiation.
+
+3.1. STARTTLS Command
+
+ Arguments: none
+
+ Responses: no specific responses for this command
+
+ Result: OK - begin TLS negotiation
+ BAD - command unknown or arguments invalid
+
+ A TLS negotiation begins immediately after the CRLF at the end of
+ the tagged OK response from the server. Once a client issues a
+ STARTTLS command, it MUST NOT issue further commands until a
+ server response is seen and the TLS negotiation is complete.
+
+ The STARTTLS command is only valid in non-authenticated state.
+ The server remains in non-authenticated state, even if client
+ credentials are supplied during the TLS negotiation. The SASL
+ [SASL] EXTERNAL mechanism MAY be used to authenticate once TLS
+ client credentials are successfully exchanged, but servers
+ supporting the STARTTLS command are not required to support the
+ EXTERNAL mechanism.
+
+ Once TLS has been started, the client MUST discard cached
+ information about server capabilities and SHOULD re-issue the
+ CAPABILITY command. This is necessary to protect against
+ man-in-the-middle attacks which alter the capabilities list prior
+ to STARTTLS. The server MAY advertise different capabilities
+ after STARTTLS.
+
+ The formal syntax for IMAP is amended as follows:
+
+
+
+
+Newman Standards Track [Page 4]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ command_any =/ "STARTTLS"
+
+ Example: C: a001 CAPABILITY
+ S: * CAPABILITY IMAP4rev1 STARTTLS LOGINDISABLED
+ S: a001 OK CAPABILITY completed
+ C: a002 STARTTLS
+ S: a002 OK Begin TLS negotiation now
+ <TLS negotiation, further commands are under TLS layer>
+ C: a003 CAPABILITY
+ S: * CAPABILITY IMAP4rev1 AUTH=EXTERNAL
+ S: a003 OK CAPABILITY completed
+ C: a004 LOGIN joe password
+ S: a004 OK LOGIN completed
+
+3.2. IMAP LOGINDISABLED capability
+
+ The current IMAP protocol specification (RFC 2060) requires the
+ implementation of the LOGIN command which uses clear-text passwords.
+ Many sites may choose to disable this command unless encryption is
+ active for security reasons. An IMAP server MAY advertise that the
+ LOGIN command is disabled by including the LOGINDISABLED capability
+ in the capability response. Such a server will respond with a tagged
+ "NO" response to any attempt to use the LOGIN command.
+
+ An IMAP server which implements STARTTLS MUST implement support for
+ the LOGINDISABLED capability on unencrypted connections.
+
+ An IMAP client which complies with this specification MUST NOT issue
+ the LOGIN command if this capability is present.
+
+ This capability is useful to prevent clients compliant with this
+ specification from sending an unencrypted password in an environment
+ subject to passive attacks. It has no impact on an environment
+ subject to active attacks as a man-in-the-middle attacker can remove
+ this capability. Therefore this does not relieve clients of the need
+ to follow the privacy mode recommendation in section 2.2.
+
+ Servers advertising this capability will fail to interoperate with
+ many existing compliant IMAP clients and will be unable to prevent
+ those clients from disclosing the user's password.
+
+4. POP3 STARTTLS extension
+
+ The POP3 STARTTLS extension adds the STLS command to POP3 servers.
+ If this is implemented, the POP3 extension mechanism [POP3EXT] MUST
+ also be implemented to avoid the need for client probing of multiple
+ commands. The capability name "STLS" indicates this command is
+ present and permitted in the current state.
+
+
+
+Newman Standards Track [Page 5]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ STLS
+
+ Arguments: none
+
+ Restrictions:
+ Only permitted in AUTHORIZATION state.
+
+ Discussion:
+ A TLS negotiation begins immediately after the CRLF at the
+ end of the +OK response from the server. A -ERR response
+ MAY result if a security layer is already active. Once a
+ client issues a STLS command, it MUST NOT issue further
+ commands until a server response is seen and the TLS
+ negotiation is complete.
+
+ The STLS command is only permitted in AUTHORIZATION state
+ and the server remains in AUTHORIZATION state, even if
+ client credentials are supplied during the TLS negotiation.
+ The AUTH command [POP-AUTH] with the EXTERNAL mechanism
+ [SASL] MAY be used to authenticate once TLS client
+ credentials are successfully exchanged, but servers
+ supporting the STLS command are not required to support the
+ EXTERNAL mechanism.
+
+ Once TLS has been started, the client MUST discard cached
+ information about server capabilities and SHOULD re-issue
+ the CAPA command. This is necessary to protect against
+ man-in-the-middle attacks which alter the capabilities list
+ prior to STLS. The server MAY advertise different
+ capabilities after STLS.
+
+ Possible Responses:
+ +OK -ERR
+
+ Examples:
+ C: STLS
+ S: +OK Begin TLS negotiation
+ <TLS negotiation, further commands are under TLS layer>
+ ...
+ C: STLS
+ S: -ERR Command not permitted when TLS active
+
+
+
+
+
+
+
+
+
+
+Newman Standards Track [Page 6]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+5. ACAP STARTTLS extension
+
+ When the TLS extension is present in ACAP, "STARTTLS" is listed as a
+ capability in the ACAP greeting. No arguments to this capability are
+ defined at this time. This extension adds a single command,
+ "STARTTLS" to the ACAP protocol which is used to begin a TLS
+ negotiation.
+
+5.1. STARTTLS Command
+
+ Arguments: none
+
+ Responses: no specific responses for this command
+
+ Result: OK - begin TLS negotiation
+ BAD - command unknown or arguments invalid
+
+ A TLS negotiation begins immediately after the CRLF at the end of
+ the tagged OK response from the server. Once a client issues a
+ STARTTLS command, it MUST NOT issue further commands until a
+ server response is seen and the TLS negotiation is complete.
+
+ The STARTTLS command is only valid in non-authenticated state.
+ The server remains in non-authenticated state, even if client
+ credentials are supplied during the TLS negotiation. The SASL
+ [SASL] EXTERNAL mechanism MAY be used to authenticate once TLS
+ client credentials are successfully exchanged, but servers
+ supporting the STARTTLS command are not required to support the
+ EXTERNAL mechanism.
+
+ After the TLS layer is established, the server MUST re-issue an
+ untagged ACAP greeting. This is necessary to protect against
+ man-in-the-middle attacks which alter the capabilities list prior
+ to STARTTLS. The client MUST discard cached capability
+ information and replace it with the information from the new ACAP
+ greeting. The server MAY advertise different capabilities after
+ STARTTLS.
+
+ The formal syntax for ACAP is amended as follows:
+
+ command_any =/ "STARTTLS"
+
+ Example: S: * ACAP (SASL "CRAM-MD5") (STARTTLS)
+ C: a002 STARTTLS
+ S: a002 OK "Begin TLS negotiation now"
+ <TLS negotiation, further commands are under TLS layer>
+ S: * ACAP (SASL "CRAM-MD5" "PLAIN" "EXTERNAL")
+
+
+
+
+Newman Standards Track [Page 7]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+6. PLAIN SASL mechanism
+
+ Clear-text passwords are simple, interoperate with almost all
+ existing operating system authentication databases, and are useful
+ for a smooth transition to a more secure password-based
+ authentication mechanism. The drawback is that they are unacceptable
+ for use over an unencrypted network connection.
+
+ This defines the "PLAIN" SASL mechanism for use with ACAP and other
+ protocols with no clear-text login command. The PLAIN SASL mechanism
+ MUST NOT be advertised or used unless a strong encryption layer (such
+ as the provided by TLS) is active or backwards compatibility dictates
+ otherwise.
+
+ The mechanism consists of a single message from the client to the
+ server. The client sends the authorization identity (identity to
+ login as), followed by a US-ASCII NUL character, followed by the
+ authentication identity (identity whose password will be used),
+ followed by a US-ASCII NUL character, followed by the clear-text
+ password. The client may leave the authorization identity empty to
+ indicate that it is the same as the authentication identity.
+
+ The server will verify the authentication identity and password with
+ the system authentication database and verify that the authentication
+ credentials permit the client to login as the authorization identity.
+ If both steps succeed, the user is logged in.
+
+ The server MAY also use the password to initialize any new
+ authentication database, such as one suitable for CRAM-MD5
+ [CRAM-MD5].
+
+ Non-US-ASCII characters are permitted as long as they are represented
+ in UTF-8 [UTF-8]. Use of non-visible characters or characters which
+ a user may be unable to enter on some keyboards is discouraged.
+
+ The formal grammar for the client message using Augmented BNF [ABNF]
+ follows.
+
+ message = [authorize-id] NUL authenticate-id NUL password
+ authenticate-id = 1*UTF8-SAFE ; MUST accept up to 255 octets
+ authorize-id = 1*UTF8-SAFE ; MUST accept up to 255 octets
+ password = 1*UTF8-SAFE ; MUST accept up to 255 octets
+ NUL = %x00
+ UTF8-SAFE = %x01-09 / %x0B-0C / %x0E-7F / UTF8-2 /
+ UTF8-3 / UTF8-4 / UTF8-5 / UTF8-6
+ UTF8-1 = %x80-BF
+ UTF8-2 = %xC0-DF UTF8-1
+ UTF8-3 = %xE0-EF 2UTF8-1
+
+
+
+Newman Standards Track [Page 8]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ UTF8-4 = %xF0-F7 3UTF8-1
+ UTF8-5 = %xF8-FB 4UTF8-1
+ UTF8-6 = %xFC-FD 5UTF8-1
+
+ Here is an example of how this might be used to initialize a CRAM-MD5
+ authentication database for ACAP:
+
+ Example: S: * ACAP (SASL "CRAM-MD5") (STARTTLS)
+ C: a001 AUTHENTICATE "CRAM-MD5"
+ S: + "<1896.697170952@postoffice.reston.mci.net>"
+ C: "tim b913a602c7eda7a495b4e6e7334d3890"
+ S: a001 NO (TRANSITION-NEEDED)
+ "Please change your password, or use TLS to login"
+ C: a002 STARTTLS
+ S: a002 OK "Begin TLS negotiation now"
+ <TLS negotiation, further commands are under TLS layer>
+ S: * ACAP (SASL "CRAM-MD5" "PLAIN" "EXTERNAL")
+ C: a003 AUTHENTICATE "PLAIN" {21+}
+ C: <NUL>tim<NUL>tanstaaftanstaaf
+ S: a003 OK CRAM-MD5 password initialized
+
+ Note: In this example, <NUL> represents a single ASCII NUL octet.
+
+7. imaps and pop3s ports
+
+ Separate "imaps" and "pop3s" ports were registered for use with SSL.
+ Use of these ports is discouraged in favor of the STARTTLS or STLS
+ commands.
+
+ A number of problems have been observed with separate ports for
+ "secure" variants of protocols. This is an attempt to enumerate some
+ of those problems.
+
+ - Separate ports lead to a separate URL scheme which intrudes into
+ the user interface in inappropriate ways. For example, many web
+ pages use language like "click here if your browser supports SSL."
+ This is a decision the browser is often more capable of making than
+ the user.
+
+ - Separate ports imply a model of either "secure" or "not secure."
+ This can be misleading in a number of ways. First, the "secure"
+ port may not in fact be acceptably secure as an export-crippled
+ cipher suite might be in use. This can mislead users into a false
+ sense of security. Second, the normal port might in fact be
+ secured by using a SASL mechanism which includes a security layer.
+ Thus the separate port distinction makes the complex topic of
+ security policy even more confusing. One common result of this
+ confusion is that firewall administrators are often misled into
+
+
+
+Newman Standards Track [Page 9]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ permitting the "secure" port and blocking the standard port. This
+ could be a poor choice given the common use of SSL with a 40-bit
+ key encryption layer and plain-text password authentication is less
+ secure than strong SASL mechanisms such as GSSAPI with Kerberos 5.
+
+ - Use of separate ports for SSL has caused clients to implement only
+ two security policies: use SSL or don't use SSL. The desirable
+ security policy "use TLS when available" would be cumbersome with
+ the separate port model, but is simple with STARTTLS.
+
+ - Port numbers are a limited resource. While they are not yet in
+ short supply, it is unwise to set a precedent that could double (or
+ worse) the speed of their consumption.
+
+
+8. IANA Considerations
+
+ This constitutes registration of the "STARTTLS" and "LOGINDISABLED"
+ IMAP capabilities as required by section 7.2.1 of RFC 2060 [IMAP].
+
+ The registration for the POP3 "STLS" capability follows:
+
+ CAPA tag: STLS
+ Arguments: none
+ Added commands: STLS
+ Standard commands affected: May enable USER/PASS as a side-effect.
+ CAPA command SHOULD be re-issued after successful completion.
+ Announced states/Valid states: AUTHORIZATION state only.
+ Specification reference: this memo
+
+ The registration for the ACAP "STARTTLS" capability follows:
+
+ Capability name: STARTTLS
+ Capability keyword: STARTTLS
+ Capability arguments: none
+ Published Specification(s): this memo
+ Person and email address for further information:
+ see author's address section below
+
+ The registration for the PLAIN SASL mechanism follows:
+
+ SASL mechanism name: PLAIN
+ Security Considerations: See section 9 of this memo
+ Published specification: this memo
+ Person & email address to contact for further information:
+ see author's address section below
+ Intended usage: COMMON
+ Author/Change controller: see author's address section below
+
+
+
+Newman Standards Track [Page 10]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+9. Security Considerations
+
+ TLS only provides protection for data sent over a network connection.
+ Messages transferred over IMAP or POP3 are still available to server
+ administrators and usually subject to eavesdropping, tampering and
+ forgery when transmitted through SMTP or NNTP. TLS is no substitute
+ for an end-to-end message security mechanism using MIME security
+ multiparts [MIME-SEC].
+
+ A man-in-the-middle attacker can remove STARTTLS from the capability
+ list or generate a failure response to the STARTTLS command. In
+ order to detect such an attack, clients SHOULD warn the user when
+ session privacy is not active and/or be configurable to refuse to
+ proceed without an acceptable level of security.
+
+ A man-in-the-middle attacker can always cause a down-negotiation to
+ the weakest authentication mechanism or cipher suite available. For
+ this reason, implementations SHOULD be configurable to refuse weak
+ mechanisms or cipher suites.
+
+ Any protocol interactions prior to the TLS handshake are performed in
+ the clear and can be modified by a man-in-the-middle attacker. For
+ this reason, clients MUST discard cached information about server
+ capabilities advertised prior to the start of the TLS handshake.
+
+ Clients are encouraged to clearly indicate when the level of
+ encryption active is known to be vulnerable to attack using modern
+ hardware (such as encryption keys with 56 bits of entropy or less).
+
+ The LOGINDISABLED IMAP capability (discussed in section 3.2) only
+ reduces the potential for passive attacks, it provides no protection
+ against active attacks. The responsibility remains with the client
+ to avoid sending a password over a vulnerable channel.
+
+ The PLAIN mechanism relies on the TLS encryption layer for security.
+ When used without TLS, it is vulnerable to a common network
+ eavesdropping attack. Therefore PLAIN MUST NOT be advertised or used
+ unless a suitable TLS encryption layer is active or backwards
+ compatibility dictates otherwise.
+
+ When the PLAIN mechanism is used, the server gains the ability to
+ impersonate the user to all services with the same password
+ regardless of any encryption provided by TLS or other network privacy
+ mechanisms. While many other authentication mechanisms have similar
+ weaknesses, stronger SASL mechanisms such as Kerberos address this
+ issue. Clients are encouraged to have an operational mode where all
+ mechanisms which are likely to reveal the user's password to the
+ server are disabled.
+
+
+
+Newman Standards Track [Page 11]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ The security considerations for TLS apply to STARTTLS and the
+ security considerations for SASL apply to the PLAIN mechanism.
+ Additional security requirements are discussed in section 2.
+
+10. References
+
+ [ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [ACAP] Newman, C. and J. Myers, "ACAP -- Application
+ Configuration Access Protocol", RFC 2244, November 1997.
+
+ [AUTH] Haller, N. and R. Atkinson, "On Internet Authentication",
+ RFC 1704, October 1994.
+
+ [CRAM-MD5] Klensin, J., Catoe, R. and P. Krumviede, "IMAP/POP
+ AUTHorize Extension for Simple Challenge/Response", RFC
+ 2195, September 1997.
+
+ [IMAP] Crispin, M., "Internet Message Access Protocol - Version
+ 4rev1", RFC 2060, December 1996.
+
+ [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [MIME-SEC] Galvin, J., Murphy, S., Crocker, S. and N. Freed,
+ "Security Multiparts for MIME: Multipart/Signed and
+ Multipart/Encrypted", RFC 1847, October 1995.
+
+ [POP3] Myers, J. and M. Rose, "Post Office Protocol - Version 3",
+ STD 53, RFC 1939, May 1996.
+
+ [POP3EXT] Gellens, R., Newman, C. and L. Lundblade, "POP3 Extension
+ Mechanism", RFC 2449, November 1998.
+
+ [POP-AUTH] Myers, J., "POP3 AUTHentication command", RFC 1734,
+ December 1994.
+
+ [SASL] Myers, J., "Simple Authentication and Security Layer
+ (SASL)", RFC 2222, October 1997.
+
+ [SMTPTLS] Hoffman, P., "SMTP Service Extension for Secure SMTP over
+ TLS", RFC 2487, January 1999.
+
+ [TLS] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0",
+ RFC 2246, January 1999.
+
+
+
+
+
+Newman Standards Track [Page 12]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ [UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO
+ 10646", RFC 2279, January 1998.
+
+
+11. Author's Address
+
+ Chris Newman
+ Innosoft International, Inc.
+ 1050 Lakes Drive
+ West Covina, CA 91790 USA
+
+ EMail: chris.newman@innosoft.com
+
+
+A. Appendix -- Compliance Checklist
+
+ An implementation is not compliant if it fails to satisfy one or more
+ of the MUST requirements for the protocols it implements. An
+ implementation that satisfies all the MUST and all the SHOULD
+ requirements for its protocols is said to be "unconditionally
+ compliant"; one that satisfies all the MUST requirements but not all
+ the SHOULD requirements for its protocols is said to be
+ "conditionally compliant".
+
+ Rules Section
+ ----- -------
+ Mandatory-to-implement Cipher Suite 2.1
+ SHOULD have mode where encryption required 2.2
+ server SHOULD have mode where TLS not required 2.2
+ MUST be configurable to refuse all clear-text login
+ commands or mechanisms 2.3
+ server SHOULD be configurable to refuse clear-text
+ login commands on entire server and on per-user basis 2.3
+ client MUST check server identity 2.4
+ client MUST use hostname used to open connection 2.4
+ client MUST NOT use hostname from insecure remote lookup 2.4
+ client SHOULD support subjectAltName of dNSName type 2.4
+ client SHOULD ask for confirmation or terminate on fail 2.4
+ MUST check result of STARTTLS for acceptable privacy 2.5
+ client MUST NOT issue commands after STARTTLS
+ until server response and negotiation done 3.1,4,5.1
+ client MUST discard cached information 3.1,4,5.1,9
+ client SHOULD re-issue CAPABILITY/CAPA command 3.1,4
+ IMAP server with STARTTLS MUST implement LOGINDISABLED 3.2
+ IMAP client MUST NOT issue LOGIN if LOGINDISABLED 3.2
+ POP server MUST implement POP3 extensions 4
+ ACAP server MUST re-issue ACAP greeting 5.1
+
+
+
+
+Newman Standards Track [Page 13]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+ client SHOULD warn when session privacy not active and/or
+ refuse to proceed without acceptable security level 9
+ SHOULD be configurable to refuse weak mechanisms or
+ cipher suites 9
+
+ The PLAIN mechanism is an optional part of this specification.
+ However if it is implemented the following rules apply:
+
+ Rules Section
+ ----- -------
+ MUST NOT use PLAIN unless strong encryption active
+ or backwards compatibility dictates otherwise 6,9
+ MUST use UTF-8 encoding for characters in PLAIN 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Newman Standards Track [Page 14]
+
+RFC 2595 Using TLS with IMAP, POP3 and ACAP June 1999
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Newman Standards Track [Page 15]
+
diff --git a/standards/rfc2616.txt b/standards/rfc2616.txt
new file mode 100644
index 000000000..45d7d08b8
--- /dev/null
+++ b/standards/rfc2616.txt
@@ -0,0 +1,9859 @@
+
+
+
+
+
+
+Network Working Group R. Fielding
+Request for Comments: 2616 UC Irvine
+Obsoletes: 2068 J. Gettys
+Category: Standards Track Compaq/W3C
+ J. Mogul
+ Compaq
+ H. Frystyk
+ W3C/MIT
+ L. Masinter
+ Xerox
+ P. Leach
+ Microsoft
+ T. Berners-Lee
+ W3C/MIT
+ June 1999
+
+
+ Hypertext Transfer Protocol -- HTTP/1.1
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+Abstract
+
+ The Hypertext Transfer Protocol (HTTP) is an application-level
+ protocol for distributed, collaborative, hypermedia information
+ systems. It is a generic, stateless, protocol which can be used for
+ many tasks beyond its use for hypertext, such as name servers and
+ distributed object management systems, through extension of its
+ request methods, error codes and headers [47]. A feature of HTTP is
+ the typing and negotiation of data representation, allowing systems
+ to be built independently of the data being transferred.
+
+ HTTP has been in use by the World-Wide Web global information
+ initiative since 1990. This specification defines the protocol
+ referred to as "HTTP/1.1", and is an update to RFC 2068 [33].
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 1]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+Table of Contents
+
+ 1 Introduction ...................................................7
+ 1.1 Purpose......................................................7
+ 1.2 Requirements .................................................8
+ 1.3 Terminology ..................................................8
+ 1.4 Overall Operation ...........................................12
+ 2 Notational Conventions and Generic Grammar ....................14
+ 2.1 Augmented BNF ...............................................14
+ 2.2 Basic Rules .................................................15
+ 3 Protocol Parameters ...........................................17
+ 3.1 HTTP Version ................................................17
+ 3.2 Uniform Resource Identifiers ................................18
+ 3.2.1 General Syntax ...........................................19
+ 3.2.2 http URL .................................................19
+ 3.2.3 URI Comparison ...........................................20
+ 3.3 Date/Time Formats ...........................................20
+ 3.3.1 Full Date ................................................20
+ 3.3.2 Delta Seconds ............................................21
+ 3.4 Character Sets ..............................................21
+ 3.4.1 Missing Charset ..........................................22
+ 3.5 Content Codings .............................................23
+ 3.6 Transfer Codings ............................................24
+ 3.6.1 Chunked Transfer Coding ..................................25
+ 3.7 Media Types .................................................26
+ 3.7.1 Canonicalization and Text Defaults .......................27
+ 3.7.2 Multipart Types ..........................................27
+ 3.8 Product Tokens ..............................................28
+ 3.9 Quality Values ..............................................29
+ 3.10 Language Tags ...............................................29
+ 3.11 Entity Tags .................................................30
+ 3.12 Range Units .................................................30
+ 4 HTTP Message ..................................................31
+ 4.1 Message Types ...............................................31
+ 4.2 Message Headers .............................................31
+ 4.3 Message Body ................................................32
+ 4.4 Message Length ..............................................33
+ 4.5 General Header Fields .......................................34
+ 5 Request .......................................................35
+ 5.1 Request-Line ................................................35
+ 5.1.1 Method ...................................................36
+ 5.1.2 Request-URI ..............................................36
+ 5.2 The Resource Identified by a Request ........................38
+ 5.3 Request Header Fields .......................................38
+ 6 Response ......................................................39
+ 6.1 Status-Line .................................................39
+ 6.1.1 Status Code and Reason Phrase ............................39
+ 6.2 Response Header Fields ......................................41
+
+
+
+Fielding, et al. Standards Track [Page 2]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 7 Entity ........................................................42
+ 7.1 Entity Header Fields ........................................42
+ 7.2 Entity Body .................................................43
+ 7.2.1 Type .....................................................43
+ 7.2.2 Entity Length ............................................43
+ 8 Connections ...................................................44
+ 8.1 Persistent Connections ......................................44
+ 8.1.1 Purpose ..................................................44
+ 8.1.2 Overall Operation ........................................45
+ 8.1.3 Proxy Servers ............................................46
+ 8.1.4 Practical Considerations .................................46
+ 8.2 Message Transmission Requirements ...........................47
+ 8.2.1 Persistent Connections and Flow Control ..................47
+ 8.2.2 Monitoring Connections for Error Status Messages .........48
+ 8.2.3 Use of the 100 (Continue) Status .........................48
+ 8.2.4 Client Behavior if Server Prematurely Closes Connection ..50
+ 9 Method Definitions ............................................51
+ 9.1 Safe and Idempotent Methods .................................51
+ 9.1.1 Safe Methods .............................................51
+ 9.1.2 Idempotent Methods .......................................51
+ 9.2 OPTIONS .....................................................52
+ 9.3 GET .........................................................53
+ 9.4 HEAD ........................................................54
+ 9.5 POST ........................................................54
+ 9.6 PUT .........................................................55
+ 9.7 DELETE ......................................................56
+ 9.8 TRACE .......................................................56
+ 9.9 CONNECT .....................................................57
+ 10 Status Code Definitions ......................................57
+ 10.1 Informational 1xx ...........................................57
+ 10.1.1 100 Continue .............................................58
+ 10.1.2 101 Switching Protocols ..................................58
+ 10.2 Successful 2xx ..............................................58
+ 10.2.1 200 OK ...................................................58
+ 10.2.2 201 Created ..............................................59
+ 10.2.3 202 Accepted .............................................59
+ 10.2.4 203 Non-Authoritative Information ........................59
+ 10.2.5 204 No Content ...........................................60
+ 10.2.6 205 Reset Content ........................................60
+ 10.2.7 206 Partial Content ......................................60
+ 10.3 Redirection 3xx .............................................61
+ 10.3.1 300 Multiple Choices .....................................61
+ 10.3.2 301 Moved Permanently ....................................62
+ 10.3.3 302 Found ................................................62
+ 10.3.4 303 See Other ............................................63
+ 10.3.5 304 Not Modified .........................................63
+ 10.3.6 305 Use Proxy ............................................64
+ 10.3.7 306 (Unused) .............................................64
+
+
+
+Fielding, et al. Standards Track [Page 3]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 10.3.8 307 Temporary Redirect ...................................65
+ 10.4 Client Error 4xx ............................................65
+ 10.4.1 400 Bad Request .........................................65
+ 10.4.2 401 Unauthorized ........................................66
+ 10.4.3 402 Payment Required ....................................66
+ 10.4.4 403 Forbidden ...........................................66
+ 10.4.5 404 Not Found ...........................................66
+ 10.4.6 405 Method Not Allowed ..................................66
+ 10.4.7 406 Not Acceptable ......................................67
+ 10.4.8 407 Proxy Authentication Required .......................67
+ 10.4.9 408 Request Timeout .....................................67
+ 10.4.10 409 Conflict ............................................67
+ 10.4.11 410 Gone ................................................68
+ 10.4.12 411 Length Required .....................................68
+ 10.4.13 412 Precondition Failed .................................68
+ 10.4.14 413 Request Entity Too Large ............................69
+ 10.4.15 414 Request-URI Too Long ................................69
+ 10.4.16 415 Unsupported Media Type ..............................69
+ 10.4.17 416 Requested Range Not Satisfiable .....................69
+ 10.4.18 417 Expectation Failed ..................................70
+ 10.5 Server Error 5xx ............................................70
+ 10.5.1 500 Internal Server Error ................................70
+ 10.5.2 501 Not Implemented ......................................70
+ 10.5.3 502 Bad Gateway ..........................................70
+ 10.5.4 503 Service Unavailable ..................................70
+ 10.5.5 504 Gateway Timeout ......................................71
+ 10.5.6 505 HTTP Version Not Supported ...........................71
+ 11 Access Authentication ........................................71
+ 12 Content Negotiation ..........................................71
+ 12.1 Server-driven Negotiation ...................................72
+ 12.2 Agent-driven Negotiation ....................................73
+ 12.3 Transparent Negotiation .....................................74
+ 13 Caching in HTTP ..............................................74
+ 13.1.1 Cache Correctness ........................................75
+ 13.1.2 Warnings .................................................76
+ 13.1.3 Cache-control Mechanisms .................................77
+ 13.1.4 Explicit User Agent Warnings .............................78
+ 13.1.5 Exceptions to the Rules and Warnings .....................78
+ 13.1.6 Client-controlled Behavior ...............................79
+ 13.2 Expiration Model ............................................79
+ 13.2.1 Server-Specified Expiration ..............................79
+ 13.2.2 Heuristic Expiration .....................................80
+ 13.2.3 Age Calculations .........................................80
+ 13.2.4 Expiration Calculations ..................................83
+ 13.2.5 Disambiguating Expiration Values .........................84
+ 13.2.6 Disambiguating Multiple Responses ........................84
+ 13.3 Validation Model ............................................85
+ 13.3.1 Last-Modified Dates ......................................86
+
+
+
+Fielding, et al. Standards Track [Page 4]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 13.3.2 Entity Tag Cache Validators ..............................86
+ 13.3.3 Weak and Strong Validators ...............................86
+ 13.3.4 Rules for When to Use Entity Tags and Last-Modified Dates.89
+ 13.3.5 Non-validating Conditionals ..............................90
+ 13.4 Response Cacheability .......................................91
+ 13.5 Constructing Responses From Caches ..........................92
+ 13.5.1 End-to-end and Hop-by-hop Headers ........................92
+ 13.5.2 Non-modifiable Headers ...................................92
+ 13.5.3 Combining Headers ........................................94
+ 13.5.4 Combining Byte Ranges ....................................95
+ 13.6 Caching Negotiated Responses ................................95
+ 13.7 Shared and Non-Shared Caches ................................96
+ 13.8 Errors or Incomplete Response Cache Behavior ................97
+ 13.9 Side Effects of GET and HEAD ................................97
+ 13.10 Invalidation After Updates or Deletions ...................97
+ 13.11 Write-Through Mandatory ...................................98
+ 13.12 Cache Replacement .........................................99
+ 13.13 History Lists .............................................99
+ 14 Header Field Definitions ....................................100
+ 14.1 Accept .....................................................100
+ 14.2 Accept-Charset .............................................102
+ 14.3 Accept-Encoding ............................................102
+ 14.4 Accept-Language ............................................104
+ 14.5 Accept-Ranges ..............................................105
+ 14.6 Age ........................................................106
+ 14.7 Allow ......................................................106
+ 14.8 Authorization ..............................................107
+ 14.9 Cache-Control ..............................................108
+ 14.9.1 What is Cacheable .......................................109
+ 14.9.2 What May be Stored by Caches ............................110
+ 14.9.3 Modifications of the Basic Expiration Mechanism .........111
+ 14.9.4 Cache Revalidation and Reload Controls ..................113
+ 14.9.5 No-Transform Directive ..................................115
+ 14.9.6 Cache Control Extensions ................................116
+ 14.10 Connection ...............................................117
+ 14.11 Content-Encoding .........................................118
+ 14.12 Content-Language .........................................118
+ 14.13 Content-Length ...........................................119
+ 14.14 Content-Location .........................................120
+ 14.15 Content-MD5 ..............................................121
+ 14.16 Content-Range ............................................122
+ 14.17 Content-Type .............................................124
+ 14.18 Date .....................................................124
+ 14.18.1 Clockless Origin Server Operation ......................125
+ 14.19 ETag .....................................................126
+ 14.20 Expect ...................................................126
+ 14.21 Expires ..................................................127
+ 14.22 From .....................................................128
+
+
+
+Fielding, et al. Standards Track [Page 5]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 14.23 Host .....................................................128
+ 14.24 If-Match .................................................129
+ 14.25 If-Modified-Since ........................................130
+ 14.26 If-None-Match ............................................132
+ 14.27 If-Range .................................................133
+ 14.28 If-Unmodified-Since ......................................134
+ 14.29 Last-Modified ............................................134
+ 14.30 Location .................................................135
+ 14.31 Max-Forwards .............................................136
+ 14.32 Pragma ...................................................136
+ 14.33 Proxy-Authenticate .......................................137
+ 14.34 Proxy-Authorization ......................................137
+ 14.35 Range ....................................................138
+ 14.35.1 Byte Ranges ...........................................138
+ 14.35.2 Range Retrieval Requests ..............................139
+ 14.36 Referer ..................................................140
+ 14.37 Retry-After ..............................................141
+ 14.38 Server ...................................................141
+ 14.39 TE .......................................................142
+ 14.40 Trailer ..................................................143
+ 14.41 Transfer-Encoding..........................................143
+ 14.42 Upgrade ..................................................144
+ 14.43 User-Agent ...............................................145
+ 14.44 Vary .....................................................145
+ 14.45 Via ......................................................146
+ 14.46 Warning ..................................................148
+ 14.47 WWW-Authenticate .........................................150
+ 15 Security Considerations .......................................150
+ 15.1 Personal Information....................................151
+ 15.1.1 Abuse of Server Log Information .........................151
+ 15.1.2 Transfer of Sensitive Information .......................151
+ 15.1.3 Encoding Sensitive Information in URI's .................152
+ 15.1.4 Privacy Issues Connected to Accept Headers ..............152
+ 15.2 Attacks Based On File and Path Names .......................153
+ 15.3 DNS Spoofing ...............................................154
+ 15.4 Location Headers and Spoofing ..............................154
+ 15.5 Content-Disposition Issues .................................154
+ 15.6 Authentication Credentials and Idle Clients ................155
+ 15.7 Proxies and Caching ........................................155
+ 15.7.1 Denial of Service Attacks on Proxies....................156
+ 16 Acknowledgments .............................................156
+ 17 References ..................................................158
+ 18 Authors' Addresses ..........................................162
+ 19 Appendices ..................................................164
+ 19.1 Internet Media Type message/http and application/http ......164
+ 19.2 Internet Media Type multipart/byteranges ...................165
+ 19.3 Tolerant Applications ......................................166
+ 19.4 Differences Between HTTP Entities and RFC 2045 Entities ....167
+
+
+
+Fielding, et al. Standards Track [Page 6]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 19.4.1 MIME-Version ............................................167
+ 19.4.2 Conversion to Canonical Form ............................167
+ 19.4.3 Conversion of Date Formats ..............................168
+ 19.4.4 Introduction of Content-Encoding ........................168
+ 19.4.5 No Content-Transfer-Encoding ............................168
+ 19.4.6 Introduction of Transfer-Encoding .......................169
+ 19.4.7 MHTML and Line Length Limitations .......................169
+ 19.5 Additional Features ........................................169
+ 19.5.1 Content-Disposition .....................................170
+ 19.6 Compatibility with Previous Versions .......................170
+ 19.6.1 Changes from HTTP/1.0 ...................................171
+ 19.6.2 Compatibility with HTTP/1.0 Persistent Connections ......172
+ 19.6.3 Changes from RFC 2068 ...................................172
+ 20 Index .......................................................175
+ 21 Full Copyright Statement ....................................176
+
+1 Introduction
+
+1.1 Purpose
+
+ The Hypertext Transfer Protocol (HTTP) is an application-level
+ protocol for distributed, collaborative, hypermedia information
+ systems. HTTP has been in use by the World-Wide Web global
+ information initiative since 1990. The first version of HTTP,
+ referred to as HTTP/0.9, was a simple protocol for raw data transfer
+ across the Internet. HTTP/1.0, as defined by RFC 1945 [6], improved
+ the protocol by allowing messages to be in the format of MIME-like
+ messages, containing metainformation about the data transferred and
+ modifiers on the request/response semantics. However, HTTP/1.0 does
+ not sufficiently take into consideration the effects of hierarchical
+ proxies, caching, the need for persistent connections, or virtual
+ hosts. In addition, the proliferation of incompletely-implemented
+ applications calling themselves "HTTP/1.0" has necessitated a
+ protocol version change in order for two communicating applications
+ to determine each other's true capabilities.
+
+ This specification defines the protocol referred to as "HTTP/1.1".
+ This protocol includes more stringent requirements than HTTP/1.0 in
+ order to ensure reliable implementation of its features.
+
+ Practical information systems require more functionality than simple
+ retrieval, including search, front-end update, and annotation. HTTP
+ allows an open-ended set of methods and headers that indicate the
+ purpose of a request [47]. It builds on the discipline of reference
+ provided by the Uniform Resource Identifier (URI) [3], as a location
+ (URL) [4] or name (URN) [20], for indicating the resource to which a
+
+
+
+
+
+Fielding, et al. Standards Track [Page 7]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ method is to be applied. Messages are passed in a format similar to
+ that used by Internet mail [9] as defined by the Multipurpose
+ Internet Mail Extensions (MIME) [7].
+
+ HTTP is also used as a generic protocol for communication between
+ user agents and proxies/gateways to other Internet systems, including
+ those supported by the SMTP [16], NNTP [13], FTP [18], Gopher [2],
+ and WAIS [10] protocols. In this way, HTTP allows basic hypermedia
+ access to resources available from diverse applications.
+
+1.2 Requirements
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC 2119 [34].
+
+ An implementation is not compliant if it fails to satisfy one or more
+ of the MUST or REQUIRED level requirements for the protocols it
+ implements. An implementation that satisfies all the MUST or REQUIRED
+ level and all the SHOULD level requirements for its protocols is said
+ to be "unconditionally compliant"; one that satisfies all the MUST
+ level requirements but not all the SHOULD level requirements for its
+ protocols is said to be "conditionally compliant."
+
+1.3 Terminology
+
+ This specification uses a number of terms to refer to the roles
+ played by participants in, and objects of, the HTTP communication.
+
+ connection
+ A transport layer virtual circuit established between two programs
+ for the purpose of communication.
+
+ message
+ The basic unit of HTTP communication, consisting of a structured
+ sequence of octets matching the syntax defined in section 4 and
+ transmitted via the connection.
+
+ request
+ An HTTP request message, as defined in section 5.
+
+ response
+ An HTTP response message, as defined in section 6.
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 8]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ resource
+ A network data object or service that can be identified by a URI,
+ as defined in section 3.2. Resources may be available in multiple
+ representations (e.g. multiple languages, data formats, size, and
+ resolutions) or vary in other ways.
+
+ entity
+ The information transferred as the payload of a request or
+ response. An entity consists of metainformation in the form of
+ entity-header fields and content in the form of an entity-body, as
+ described in section 7.
+
+ representation
+ An entity included with a response that is subject to content
+ negotiation, as described in section 12. There may exist multiple
+ representations associated with a particular response status.
+
+ content negotiation
+ The mechanism for selecting the appropriate representation when
+ servicing a request, as described in section 12. The
+ representation of entities in any response can be negotiated
+ (including error responses).
+
+ variant
+ A resource may have one, or more than one, representation(s)
+ associated with it at any given instant. Each of these
+ representations is termed a `varriant'. Use of the term `variant'
+ does not necessarily imply that the resource is subject to content
+ negotiation.
+
+ client
+ A program that establishes connections for the purpose of sending
+ requests.
+
+ user agent
+ The client which initiates a request. These are often browsers,
+ editors, spiders (web-traversing robots), or other end user tools.
+
+ server
+ An application program that accepts connections in order to
+ service requests by sending back responses. Any given program may
+ be capable of being both a client and a server; our use of these
+ terms refers only to the role being performed by the program for a
+ particular connection, rather than to the program's capabilities
+ in general. Likewise, any server may act as an origin server,
+ proxy, gateway, or tunnel, switching behavior based on the nature
+ of each request.
+
+
+
+
+Fielding, et al. Standards Track [Page 9]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ origin server
+ The server on which a given resource resides or is to be created.
+
+ proxy
+ An intermediary program which acts as both a server and a client
+ for the purpose of making requests on behalf of other clients.
+ Requests are serviced internally or by passing them on, with
+ possible translation, to other servers. A proxy MUST implement
+ both the client and server requirements of this specification. A
+ "transparent proxy" is a proxy that does not modify the request or
+ response beyond what is required for proxy authentication and
+ identification. A "non-transparent proxy" is a proxy that modifies
+ the request or response in order to provide some added service to
+ the user agent, such as group annotation services, media type
+ transformation, protocol reduction, or anonymity filtering. Except
+ where either transparent or non-transparent behavior is explicitly
+ stated, the HTTP proxy requirements apply to both types of
+ proxies.
+
+ gateway
+ A server which acts as an intermediary for some other server.
+ Unlike a proxy, a gateway receives requests as if it were the
+ origin server for the requested resource; the requesting client
+ may not be aware that it is communicating with a gateway.
+
+ tunnel
+ An intermediary program which is acting as a blind relay between
+ two connections. Once active, a tunnel is not considered a party
+ to the HTTP communication, though the tunnel may have been
+ initiated by an HTTP request. The tunnel ceases to exist when both
+ ends of the relayed connections are closed.
+
+ cache
+ A program's local store of response messages and the subsystem
+ that controls its message storage, retrieval, and deletion. A
+ cache stores cacheable responses in order to reduce the response
+ time and network bandwidth consumption on future, equivalent
+ requests. Any client or server may include a cache, though a cache
+ cannot be used by a server that is acting as a tunnel.
+
+ cacheable
+ A response is cacheable if a cache is allowed to store a copy of
+ the response message for use in answering subsequent requests. The
+ rules for determining the cacheability of HTTP responses are
+ defined in section 13. Even if a resource is cacheable, there may
+ be additional constraints on whether a cache can use the cached
+ copy for a particular request.
+
+
+
+
+Fielding, et al. Standards Track [Page 10]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ first-hand
+ A response is first-hand if it comes directly and without
+ unnecessary delay from the origin server, perhaps via one or more
+ proxies. A response is also first-hand if its validity has just
+ been checked directly with the origin server.
+
+ explicit expiration time
+ The time at which the origin server intends that an entity should
+ no longer be returned by a cache without further validation.
+
+ heuristic expiration time
+ An expiration time assigned by a cache when no explicit expiration
+ time is available.
+
+ age
+ The age of a response is the time since it was sent by, or
+ successfully validated with, the origin server.
+
+ freshness lifetime
+ The length of time between the generation of a response and its
+ expiration time.
+
+ fresh
+ A response is fresh if its age has not yet exceeded its freshness
+ lifetime.
+
+ stale
+ A response is stale if its age has passed its freshness lifetime.
+
+ semantically transparent
+ A cache behaves in a "semantically transparent" manner, with
+ respect to a particular response, when its use affects neither the
+ requesting client nor the origin server, except to improve
+ performance. When a cache is semantically transparent, the client
+ receives exactly the same response (except for hop-by-hop headers)
+ that it would have received had its request been handled directly
+ by the origin server.
+
+ validator
+ A protocol element (e.g., an entity tag or a Last-Modified time)
+ that is used to find out whether a cache entry is an equivalent
+ copy of an entity.
+
+ upstream/downstream
+ Upstream and downstream describe the flow of a message: all
+ messages flow from upstream to downstream.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 11]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ inbound/outbound
+ Inbound and outbound refer to the request and response paths for
+ messages: "inbound" means "traveling toward the origin server",
+ and "outbound" means "traveling toward the user agent"
+
+1.4 Overall Operation
+
+ The HTTP protocol is a request/response protocol. A client sends a
+ request to the server in the form of a request method, URI, and
+ protocol version, followed by a MIME-like message containing request
+ modifiers, client information, and possible body content over a
+ connection with a server. The server responds with a status line,
+ including the message's protocol version and a success or error code,
+ followed by a MIME-like message containing server information, entity
+ metainformation, and possible entity-body content. The relationship
+ between HTTP and MIME is described in appendix 19.4.
+
+ Most HTTP communication is initiated by a user agent and consists of
+ a request to be applied to a resource on some origin server. In the
+ simplest case, this may be accomplished via a single connection (v)
+ between the user agent (UA) and the origin server (O).
+
+ request chain ------------------------>
+ UA -------------------v------------------- O
+ <----------------------- response chain
+
+ A more complicated situation occurs when one or more intermediaries
+ are present in the request/response chain. There are three common
+ forms of intermediary: proxy, gateway, and tunnel. A proxy is a
+ forwarding agent, receiving requests for a URI in its absolute form,
+ rewriting all or part of the message, and forwarding the reformatted
+ request toward the server identified by the URI. A gateway is a
+ receiving agent, acting as a layer above some other server(s) and, if
+ necessary, translating the requests to the underlying server's
+ protocol. A tunnel acts as a relay point between two connections
+ without changing the messages; tunnels are used when the
+ communication needs to pass through an intermediary (such as a
+ firewall) even when the intermediary cannot understand the contents
+ of the messages.
+
+ request chain -------------------------------------->
+ UA -----v----- A -----v----- B -----v----- C -----v----- O
+ <------------------------------------- response chain
+
+ The figure above shows three intermediaries (A, B, and C) between the
+ user agent and origin server. A request or response message that
+ travels the whole chain will pass through four separate connections.
+ This distinction is important because some HTTP communication options
+
+
+
+Fielding, et al. Standards Track [Page 12]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ may apply only to the connection with the nearest, non-tunnel
+ neighbor, only to the end-points of the chain, or to all connections
+ along the chain. Although the diagram is linear, each participant may
+ be engaged in multiple, simultaneous communications. For example, B
+ may be receiving requests from many clients other than A, and/or
+ forwarding requests to servers other than C, at the same time that it
+ is handling A's request.
+
+ Any party to the communication which is not acting as a tunnel may
+ employ an internal cache for handling requests. The effect of a cache
+ is that the request/response chain is shortened if one of the
+ participants along the chain has a cached response applicable to that
+ request. The following illustrates the resulting chain if B has a
+ cached copy of an earlier response from O (via C) for a request which
+ has not been cached by UA or A.
+
+ request chain ---------->
+ UA -----v----- A -----v----- B - - - - - - C - - - - - - O
+ <--------- response chain
+
+ Not all responses are usefully cacheable, and some requests may
+ contain modifiers which place special requirements on cache behavior.
+ HTTP requirements for cache behavior and cacheable responses are
+ defined in section 13.
+
+ In fact, there are a wide variety of architectures and configurations
+ of caches and proxies currently being experimented with or deployed
+ across the World Wide Web. These systems include national hierarchies
+ of proxy caches to save transoceanic bandwidth, systems that
+ broadcast or multicast cache entries, organizations that distribute
+ subsets of cached data via CD-ROM, and so on. HTTP systems are used
+ in corporate intranets over high-bandwidth links, and for access via
+ PDAs with low-power radio links and intermittent connectivity. The
+ goal of HTTP/1.1 is to support the wide diversity of configurations
+ already deployed while introducing protocol constructs that meet the
+ needs of those who build web applications that require high
+ reliability and, failing that, at least reliable indications of
+ failure.
+
+ HTTP communication usually takes place over TCP/IP connections. The
+ default port is TCP 80 [19], but other ports can be used. This does
+ not preclude HTTP from being implemented on top of any other protocol
+ on the Internet, or on other networks. HTTP only presumes a reliable
+ transport; any protocol that provides such guarantees can be used;
+ the mapping of the HTTP/1.1 request and response structures onto the
+ transport data units of the protocol in question is outside the scope
+ of this specification.
+
+
+
+
+Fielding, et al. Standards Track [Page 13]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ In HTTP/1.0, most implementations used a new connection for each
+ request/response exchange. In HTTP/1.1, a connection may be used for
+ one or more request/response exchanges, although connections may be
+ closed for a variety of reasons (see section 8.1).
+
+2 Notational Conventions and Generic Grammar
+
+2.1 Augmented BNF
+
+ All of the mechanisms specified in this document are described in
+ both prose and an augmented Backus-Naur Form (BNF) similar to that
+ used by RFC 822 [9]. Implementors will need to be familiar with the
+ notation in order to understand this specification. The augmented BNF
+ includes the following constructs:
+
+ name = definition
+ The name of a rule is simply the name itself (without any
+ enclosing "<" and ">") and is separated from its definition by the
+ equal "=" character. White space is only significant in that
+ indentation of continuation lines is used to indicate a rule
+ definition that spans more than one line. Certain basic rules are
+ in uppercase, such as SP, LWS, HT, CRLF, DIGIT, ALPHA, etc. Angle
+ brackets are used within definitions whenever their presence will
+ facilitate discerning the use of rule names.
+
+ "literal"
+ Quotation marks surround literal text. Unless stated otherwise,
+ the text is case-insensitive.
+
+ rule1 | rule2
+ Elements separated by a bar ("|") are alternatives, e.g., "yes |
+ no" will accept yes or no.
+
+ (rule1 rule2)
+ Elements enclosed in parentheses are treated as a single element.
+ Thus, "(elem (foo | bar) elem)" allows the token sequences "elem
+ foo elem" and "elem bar elem".
+
+ *rule
+ The character "*" preceding an element indicates repetition. The
+ full form is "<n>*<m>element" indicating at least <n> and at most
+ <m> occurrences of element. Default values are 0 and infinity so
+ that "*(element)" allows any number, including zero; "1*element"
+ requires at least one; and "1*2element" allows one or two.
+
+ [rule]
+ Square brackets enclose optional elements; "[foo bar]" is
+ equivalent to "*1(foo bar)".
+
+
+
+Fielding, et al. Standards Track [Page 14]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ N rule
+ Specific repetition: "<n>(element)" is equivalent to
+ "<n>*<n>(element)"; that is, exactly <n> occurrences of (element).
+ Thus 2DIGIT is a 2-digit number, and 3ALPHA is a string of three
+ alphabetic characters.
+
+ #rule
+ A construct "#" is defined, similar to "*", for defining lists of
+ elements. The full form is "<n>#<m>element" indicating at least
+ <n> and at most <m> elements, each separated by one or more commas
+ (",") and OPTIONAL linear white space (LWS). This makes the usual
+ form of lists very easy; a rule such as
+ ( *LWS element *( *LWS "," *LWS element ))
+ can be shown as
+ 1#element
+ Wherever this construct is used, null elements are allowed, but do
+ not contribute to the count of elements present. That is,
+ "(element), , (element) " is permitted, but counts as only two
+ elements. Therefore, where at least one element is required, at
+ least one non-null element MUST be present. Default values are 0
+ and infinity so that "#element" allows any number, including zero;
+ "1#element" requires at least one; and "1#2element" allows one or
+ two.
+
+ ; comment
+ A semi-colon, set off some distance to the right of rule text,
+ starts a comment that continues to the end of line. This is a
+ simple way of including useful notes in parallel with the
+ specifications.
+
+ implied *LWS
+ The grammar described by this specification is word-based. Except
+ where noted otherwise, linear white space (LWS) can be included
+ between any two adjacent words (token or quoted-string), and
+ between adjacent words and separators, without changing the
+ interpretation of a field. At least one delimiter (LWS and/or
+
+ separators) MUST exist between any two tokens (for the definition
+ of "token" below), since they would otherwise be interpreted as a
+ single token.
+
+2.2 Basic Rules
+
+ The following rules are used throughout this specification to
+ describe basic parsing constructs. The US-ASCII coded character set
+ is defined by ANSI X3.4-1986 [21].
+
+
+
+
+
+Fielding, et al. Standards Track [Page 15]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ OCTET = <any 8-bit sequence of data>
+ CHAR = <any US-ASCII character (octets 0 - 127)>
+ UPALPHA = <any US-ASCII uppercase letter "A".."Z">
+ LOALPHA = <any US-ASCII lowercase letter "a".."z">
+ ALPHA = UPALPHA | LOALPHA
+ DIGIT = <any US-ASCII digit "0".."9">
+ CTL = <any US-ASCII control character
+ (octets 0 - 31) and DEL (127)>
+ CR = <US-ASCII CR, carriage return (13)>
+ LF = <US-ASCII LF, linefeed (10)>
+ SP = <US-ASCII SP, space (32)>
+ HT = <US-ASCII HT, horizontal-tab (9)>
+ <"> = <US-ASCII double-quote mark (34)>
+
+ HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
+ protocol elements except the entity-body (see appendix 19.3 for
+ tolerant applications). The end-of-line marker within an entity-body
+ is defined by its associated media type, as described in section 3.7.
+
+ CRLF = CR LF
+
+ HTTP/1.1 header field values can be folded onto multiple lines if the
+ continuation line begins with a space or horizontal tab. All linear
+ white space, including folding, has the same semantics as SP. A
+ recipient MAY replace any linear white space with a single SP before
+ interpreting the field value or forwarding the message downstream.
+
+ LWS = [CRLF] 1*( SP | HT )
+
+ The TEXT rule is only used for descriptive field contents and values
+ that are not intended to be interpreted by the message parser. Words
+ of *TEXT MAY contain characters from character sets other than ISO-
+ 8859-1 [22] only when encoded according to the rules of RFC 2047
+ [14].
+
+ TEXT = <any OCTET except CTLs,
+ but including LWS>
+
+ A CRLF is allowed in the definition of TEXT only as part of a header
+ field continuation. It is expected that the folding LWS will be
+ replaced with a single SP before interpretation of the TEXT value.
+
+ Hexadecimal numeric characters are used in several protocol elements.
+
+ HEX = "A" | "B" | "C" | "D" | "E" | "F"
+ | "a" | "b" | "c" | "d" | "e" | "f" | DIGIT
+
+
+
+
+
+Fielding, et al. Standards Track [Page 16]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Many HTTP/1.1 header field values consist of words separated by LWS
+ or special characters. These special characters MUST be in a quoted
+ string to be used within a parameter value (as defined in section
+ 3.6).
+
+ token = 1*<any CHAR except CTLs or separators>
+ separators = "(" | ")" | "<" | ">" | "@"
+ | "," | ";" | ":" | "\" | <">
+ | "/" | "[" | "]" | "?" | "="
+ | "{" | "}" | SP | HT
+
+ Comments can be included in some HTTP header fields by surrounding
+ the comment text with parentheses. Comments are only allowed in
+ fields containing "comment" as part of their field value definition.
+ In all other fields, parentheses are considered part of the field
+ value.
+
+ comment = "(" *( ctext | quoted-pair | comment ) ")"
+ ctext = <any TEXT excluding "(" and ")">
+
+ A string of text is parsed as a single word if it is quoted using
+ double-quote marks.
+
+ quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
+ qdtext = <any TEXT except <">>
+
+ The backslash character ("\") MAY be used as a single-character
+ quoting mechanism only within quoted-string and comment constructs.
+
+ quoted-pair = "\" CHAR
+
+3 Protocol Parameters
+
+3.1 HTTP Version
+
+ HTTP uses a "<major>.<minor>" numbering scheme to indicate versions
+ of the protocol. The protocol versioning policy is intended to allow
+ the sender to indicate the format of a message and its capacity for
+ understanding further HTTP communication, rather than the features
+ obtained via that communication. No change is made to the version
+ number for the addition of message components which do not affect
+ communication behavior or which only add to extensible field values.
+ The <minor> number is incremented when the changes made to the
+ protocol add features which do not change the general message parsing
+ algorithm, but which may add to the message semantics and imply
+ additional capabilities of the sender. The <major> number is
+ incremented when the format of a message within the protocol is
+ changed. See RFC 2145 [36] for a fuller explanation.
+
+
+
+Fielding, et al. Standards Track [Page 17]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The version of an HTTP message is indicated by an HTTP-Version field
+ in the first line of the message.
+
+ HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
+
+ Note that the major and minor numbers MUST be treated as separate
+ integers and that each MAY be incremented higher than a single digit.
+ Thus, HTTP/2.4 is a lower version than HTTP/2.13, which in turn is
+ lower than HTTP/12.3. Leading zeros MUST be ignored by recipients and
+ MUST NOT be sent.
+
+ An application that sends a request or response message that includes
+ HTTP-Version of "HTTP/1.1" MUST be at least conditionally compliant
+ with this specification. Applications that are at least conditionally
+ compliant with this specification SHOULD use an HTTP-Version of
+ "HTTP/1.1" in their messages, and MUST do so for any message that is
+ not compatible with HTTP/1.0. For more details on when to send
+ specific HTTP-Version values, see RFC 2145 [36].
+
+ The HTTP version of an application is the highest HTTP version for
+ which the application is at least conditionally compliant.
+
+ Proxy and gateway applications need to be careful when forwarding
+ messages in protocol versions different from that of the application.
+ Since the protocol version indicates the protocol capability of the
+ sender, a proxy/gateway MUST NOT send a message with a version
+ indicator which is greater than its actual version. If a higher
+ version request is received, the proxy/gateway MUST either downgrade
+ the request version, or respond with an error, or switch to tunnel
+ behavior.
+
+ Due to interoperability problems with HTTP/1.0 proxies discovered
+ since the publication of RFC 2068[33], caching proxies MUST, gateways
+ MAY, and tunnels MUST NOT upgrade the request to the highest version
+ they support. The proxy/gateway's response to that request MUST be in
+ the same major version as the request.
+
+ Note: Converting between versions of HTTP may involve modification
+ of header fields required or forbidden by the versions involved.
+
+3.2 Uniform Resource Identifiers
+
+ URIs have been known by many names: WWW addresses, Universal Document
+ Identifiers, Universal Resource Identifiers [3], and finally the
+ combination of Uniform Resource Locators (URL) [4] and Names (URN)
+ [20]. As far as HTTP is concerned, Uniform Resource Identifiers are
+ simply formatted strings which identify--via name, location, or any
+ other characteristic--a resource.
+
+
+
+Fielding, et al. Standards Track [Page 18]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+3.2.1 General Syntax
+
+ URIs in HTTP can be represented in absolute form or relative to some
+ known base URI [11], depending upon the context of their use. The two
+ forms are differentiated by the fact that absolute URIs always begin
+ with a scheme name followed by a colon. For definitive information on
+ URL syntax and semantics, see "Uniform Resource Identifiers (URI):
+ Generic Syntax and Semantics," RFC 2396 [42] (which replaces RFCs
+ 1738 [4] and RFC 1808 [11]). This specification adopts the
+ definitions of "URI-reference", "absoluteURI", "relativeURI", "port",
+ "host","abs_path", "rel_path", and "authority" from that
+ specification.
+
+ The HTTP protocol does not place any a priori limit on the length of
+ a URI. Servers MUST be able to handle the URI of any resource they
+ serve, and SHOULD be able to handle URIs of unbounded length if they
+ provide GET-based forms that could generate such URIs. A server
+ SHOULD return 414 (Request-URI Too Long) status if a URI is longer
+ than the server can handle (see section 10.4.15).
+
+ Note: Servers ought to be cautious about depending on URI lengths
+ above 255 bytes, because some older client or proxy
+ implementations might not properly support these lengths.
+
+3.2.2 http URL
+
+ The "http" scheme is used to locate network resources via the HTTP
+ protocol. This section defines the scheme-specific syntax and
+ semantics for http URLs.
+
+ http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
+
+ If the port is empty or not given, port 80 is assumed. The semantics
+ are that the identified resource is located at the server listening
+ for TCP connections on that port of that host, and the Request-URI
+ for the resource is abs_path (section 5.1.2). The use of IP addresses
+ in URLs SHOULD be avoided whenever possible (see RFC 1900 [24]). If
+ the abs_path is not present in the URL, it MUST be given as "/" when
+ used as a Request-URI for a resource (section 5.1.2). If a proxy
+ receives a host name which is not a fully qualified domain name, it
+ MAY add its domain to the host name it received. If a proxy receives
+ a fully qualified domain name, the proxy MUST NOT change the host
+ name.
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 19]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+3.2.3 URI Comparison
+
+ When comparing two URIs to decide if they match or not, a client
+ SHOULD use a case-sensitive octet-by-octet comparison of the entire
+ URIs, with these exceptions:
+
+ - A port that is empty or not given is equivalent to the default
+ port for that URI-reference;
+
+ - Comparisons of host names MUST be case-insensitive;
+
+ - Comparisons of scheme names MUST be case-insensitive;
+
+ - An empty abs_path is equivalent to an abs_path of "/".
+
+ Characters other than those in the "reserved" and "unsafe" sets (see
+ RFC 2396 [42]) are equivalent to their ""%" HEX HEX" encoding.
+
+ For example, the following three URIs are equivalent:
+
+ http://abc.com:80/~smith/home.html
+ http://ABC.com/%7Esmith/home.html
+ http://ABC.com:/%7esmith/home.html
+
+3.3 Date/Time Formats
+
+3.3.1 Full Date
+
+ HTTP applications have historically allowed three different formats
+ for the representation of date/time stamps:
+
+ Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
+ Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+ Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
+
+ The first format is preferred as an Internet standard and represents
+ a fixed-length subset of that defined by RFC 1123 [8] (an update to
+ RFC 822 [9]). The second format is in common use, but is based on the
+ obsolete RFC 850 [12] date format and lacks a four-digit year.
+ HTTP/1.1 clients and servers that parse the date value MUST accept
+ all three formats (for compatibility with HTTP/1.0), though they MUST
+ only generate the RFC 1123 format for representing HTTP-date values
+ in header fields. See section 19.3 for further information.
+
+ Note: Recipients of date values are encouraged to be robust in
+ accepting date values that may have been sent by non-HTTP
+ applications, as is sometimes the case when retrieving or posting
+ messages via proxies/gateways to SMTP or NNTP.
+
+
+
+Fielding, et al. Standards Track [Page 20]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ All HTTP date/time stamps MUST be represented in Greenwich Mean Time
+ (GMT), without exception. For the purposes of HTTP, GMT is exactly
+ equal to UTC (Coordinated Universal Time). This is indicated in the
+ first two formats by the inclusion of "GMT" as the three-letter
+ abbreviation for time zone, and MUST be assumed when reading the
+ asctime format. HTTP-date is case sensitive and MUST NOT include
+ additional LWS beyond that specifically included as SP in the
+ grammar.
+
+ HTTP-date = rfc1123-date | rfc850-date | asctime-date
+ rfc1123-date = wkday "," SP date1 SP time SP "GMT"
+ rfc850-date = weekday "," SP date2 SP time SP "GMT"
+ asctime-date = wkday SP date3 SP time SP 4DIGIT
+ date1 = 2DIGIT SP month SP 4DIGIT
+ ; day month year (e.g., 02 Jun 1982)
+ date2 = 2DIGIT "-" month "-" 2DIGIT
+ ; day-month-year (e.g., 02-Jun-82)
+ date3 = month SP ( 2DIGIT | ( SP 1DIGIT ))
+ ; month day (e.g., Jun 2)
+ time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ ; 00:00:00 - 23:59:59
+ wkday = "Mon" | "Tue" | "Wed"
+ | "Thu" | "Fri" | "Sat" | "Sun"
+ weekday = "Monday" | "Tuesday" | "Wednesday"
+ | "Thursday" | "Friday" | "Saturday" | "Sunday"
+ month = "Jan" | "Feb" | "Mar" | "Apr"
+ | "May" | "Jun" | "Jul" | "Aug"
+ | "Sep" | "Oct" | "Nov" | "Dec"
+
+ Note: HTTP requirements for the date/time stamp format apply only
+ to their usage within the protocol stream. Clients and servers are
+ not required to use these formats for user presentation, request
+ logging, etc.
+
+3.3.2 Delta Seconds
+
+ Some HTTP header fields allow a time value to be specified as an
+ integer number of seconds, represented in decimal, after the time
+ that the message was received.
+
+ delta-seconds = 1*DIGIT
+
+3.4 Character Sets
+
+ HTTP uses the same definition of the term "character set" as that
+ described for MIME:
+
+
+
+
+
+Fielding, et al. Standards Track [Page 21]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The term "character set" is used in this document to refer to a
+ method used with one or more tables to convert a sequence of octets
+ into a sequence of characters. Note that unconditional conversion in
+ the other direction is not required, in that not all characters may
+ be available in a given character set and a character set may provide
+ more than one sequence of octets to represent a particular character.
+ This definition is intended to allow various kinds of character
+ encoding, from simple single-table mappings such as US-ASCII to
+ complex table switching methods such as those that use ISO-2022's
+ techniques. However, the definition associated with a MIME character
+ set name MUST fully specify the mapping to be performed from octets
+ to characters. In particular, use of external profiling information
+ to determine the exact mapping is not permitted.
+
+ Note: This use of the term "character set" is more commonly
+ referred to as a "character encoding." However, since HTTP and
+ MIME share the same registry, it is important that the terminology
+ also be shared.
+
+ HTTP character sets are identified by case-insensitive tokens. The
+ complete set of tokens is defined by the IANA Character Set registry
+ [19].
+
+ charset = token
+
+ Although HTTP allows an arbitrary token to be used as a charset
+ value, any token that has a predefined value within the IANA
+ Character Set registry [19] MUST represent the character set defined
+ by that registry. Applications SHOULD limit their use of character
+ sets to those defined by the IANA registry.
+
+ Implementors should be aware of IETF character set requirements [38]
+ [41].
+
+3.4.1 Missing Charset
+
+ Some HTTP/1.0 software has interpreted a Content-Type header without
+ charset parameter incorrectly to mean "recipient should guess."
+ Senders wishing to defeat this behavior MAY include a charset
+ parameter even when the charset is ISO-8859-1 and SHOULD do so when
+ it is known that it will not confuse the recipient.
+
+ Unfortunately, some older HTTP/1.0 clients did not deal properly with
+ an explicit charset parameter. HTTP/1.1 recipients MUST respect the
+ charset label provided by the sender; and those user agents that have
+ a provision to "guess" a charset MUST use the charset from the
+
+
+
+
+
+Fielding, et al. Standards Track [Page 22]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ content-type field if they support that charset, rather than the
+ recipient's preference, when initially displaying a document. See
+ section 3.7.1.
+
+3.5 Content Codings
+
+ Content coding values indicate an encoding transformation that has
+ been or can be applied to an entity. Content codings are primarily
+ used to allow a document to be compressed or otherwise usefully
+ transformed without losing the identity of its underlying media type
+ and without loss of information. Frequently, the entity is stored in
+ coded form, transmitted directly, and only decoded by the recipient.
+
+ content-coding = token
+
+ All content-coding values are case-insensitive. HTTP/1.1 uses
+ content-coding values in the Accept-Encoding (section 14.3) and
+ Content-Encoding (section 14.11) header fields. Although the value
+ describes the content-coding, what is more important is that it
+ indicates what decoding mechanism will be required to remove the
+ encoding.
+
+ The Internet Assigned Numbers Authority (IANA) acts as a registry for
+ content-coding value tokens. Initially, the registry contains the
+ following tokens:
+
+ gzip An encoding format produced by the file compression program
+ "gzip" (GNU zip) as described in RFC 1952 [25]. This format is a
+ Lempel-Ziv coding (LZ77) with a 32 bit CRC.
+
+ compress
+ The encoding format produced by the common UNIX file compression
+ program "compress". This format is an adaptive Lempel-Ziv-Welch
+ coding (LZW).
+
+ Use of program names for the identification of encoding formats
+ is not desirable and is discouraged for future encodings. Their
+ use here is representative of historical practice, not good
+ design. For compatibility with previous implementations of HTTP,
+ applications SHOULD consider "x-gzip" and "x-compress" to be
+ equivalent to "gzip" and "compress" respectively.
+
+ deflate
+ The "zlib" format defined in RFC 1950 [31] in combination with
+ the "deflate" compression mechanism described in RFC 1951 [29].
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 23]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ identity
+ The default (identity) encoding; the use of no transformation
+ whatsoever. This content-coding is used only in the Accept-
+ Encoding header, and SHOULD NOT be used in the Content-Encoding
+ header.
+
+ New content-coding value tokens SHOULD be registered; to allow
+ interoperability between clients and servers, specifications of the
+ content coding algorithms needed to implement a new value SHOULD be
+ publicly available and adequate for independent implementation, and
+ conform to the purpose of content coding defined in this section.
+
+3.6 Transfer Codings
+
+ Transfer-coding values are used to indicate an encoding
+ transformation that has been, can be, or may need to be applied to an
+ entity-body in order to ensure "safe transport" through the network.
+ This differs from a content coding in that the transfer-coding is a
+ property of the message, not of the original entity.
+
+ transfer-coding = "chunked" | transfer-extension
+ transfer-extension = token *( ";" parameter )
+
+ Parameters are in the form of attribute/value pairs.
+
+ parameter = attribute "=" value
+ attribute = token
+ value = token | quoted-string
+
+ All transfer-coding values are case-insensitive. HTTP/1.1 uses
+ transfer-coding values in the TE header field (section 14.39) and in
+ the Transfer-Encoding header field (section 14.41).
+
+ Whenever a transfer-coding is applied to a message-body, the set of
+ transfer-codings MUST include "chunked", unless the message is
+ terminated by closing the connection. When the "chunked" transfer-
+ coding is used, it MUST be the last transfer-coding applied to the
+ message-body. The "chunked" transfer-coding MUST NOT be applied more
+ than once to a message-body. These rules allow the recipient to
+ determine the transfer-length of the message (section 4.4).
+
+ Transfer-codings are analogous to the Content-Transfer-Encoding
+ values of MIME [7], which were designed to enable safe transport of
+ binary data over a 7-bit transport service. However, safe transport
+ has a different focus for an 8bit-clean transfer protocol. In HTTP,
+ the only unsafe characteristic of message-bodies is the difficulty in
+ determining the exact body length (section 7.2.2), or the desire to
+ encrypt data over a shared transport.
+
+
+
+Fielding, et al. Standards Track [Page 24]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The Internet Assigned Numbers Authority (IANA) acts as a registry for
+ transfer-coding value tokens. Initially, the registry contains the
+ following tokens: "chunked" (section 3.6.1), "identity" (section
+ 3.6.2), "gzip" (section 3.5), "compress" (section 3.5), and "deflate"
+ (section 3.5).
+
+ New transfer-coding value tokens SHOULD be registered in the same way
+ as new content-coding value tokens (section 3.5).
+
+ A server which receives an entity-body with a transfer-coding it does
+ not understand SHOULD return 501 (Unimplemented), and close the
+ connection. A server MUST NOT send transfer-codings to an HTTP/1.0
+ client.
+
+3.6.1 Chunked Transfer Coding
+
+ The chunked encoding modifies the body of a message in order to
+ transfer it as a series of chunks, each with its own size indicator,
+ followed by an OPTIONAL trailer containing entity-header fields. This
+ allows dynamically produced content to be transferred along with the
+ information necessary for the recipient to verify that it has
+ received the full message.
+
+ Chunked-Body = *chunk
+ last-chunk
+ trailer
+ CRLF
+
+ chunk = chunk-size [ chunk-extension ] CRLF
+ chunk-data CRLF
+ chunk-size = 1*HEX
+ last-chunk = 1*("0") [ chunk-extension ] CRLF
+
+ chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
+ chunk-ext-name = token
+ chunk-ext-val = token | quoted-string
+ chunk-data = chunk-size(OCTET)
+ trailer = *(entity-header CRLF)
+
+ The chunk-size field is a string of hex digits indicating the size of
+ the chunk. The chunked encoding is ended by any chunk whose size is
+ zero, followed by the trailer, which is terminated by an empty line.
+
+ The trailer allows the sender to include additional HTTP header
+ fields at the end of the message. The Trailer header field can be
+ used to indicate which header fields are included in a trailer (see
+ section 14.40).
+
+
+
+
+Fielding, et al. Standards Track [Page 25]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ A server using chunked transfer-coding in a response MUST NOT use the
+ trailer for any header fields unless at least one of the following is
+ true:
+
+ a)the request included a TE header field that indicates "trailers" is
+ acceptable in the transfer-coding of the response, as described in
+ section 14.39; or,
+
+ b)the server is the origin server for the response, the trailer
+ fields consist entirely of optional metadata, and the recipient
+ could use the message (in a manner acceptable to the origin server)
+ without receiving this metadata. In other words, the origin server
+ is willing to accept the possibility that the trailer fields might
+ be silently discarded along the path to the client.
+
+ This requirement prevents an interoperability failure when the
+ message is being received by an HTTP/1.1 (or later) proxy and
+ forwarded to an HTTP/1.0 recipient. It avoids a situation where
+ compliance with the protocol would have necessitated a possibly
+ infinite buffer on the proxy.
+
+ An example process for decoding a Chunked-Body is presented in
+ appendix 19.4.6.
+
+ All HTTP/1.1 applications MUST be able to receive and decode the
+ "chunked" transfer-coding, and MUST ignore chunk-extension extensions
+ they do not understand.
+
+3.7 Media Types
+
+ HTTP uses Internet Media Types [17] in the Content-Type (section
+ 14.17) and Accept (section 14.1) header fields in order to provide
+ open and extensible data typing and type negotiation.
+
+ media-type = type "/" subtype *( ";" parameter )
+ type = token
+ subtype = token
+
+ Parameters MAY follow the type/subtype in the form of attribute/value
+ pairs (as defined in section 3.6).
+
+ The type, subtype, and parameter attribute names are case-
+ insensitive. Parameter values might or might not be case-sensitive,
+ depending on the semantics of the parameter name. Linear white space
+ (LWS) MUST NOT be used between the type and subtype, nor between an
+ attribute and its value. The presence or absence of a parameter might
+ be significant to the processing of a media-type, depending on its
+ definition within the media type registry.
+
+
+
+Fielding, et al. Standards Track [Page 26]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Note that some older HTTP applications do not recognize media type
+ parameters. When sending data to older HTTP applications,
+ implementations SHOULD only use media type parameters when they are
+ required by that type/subtype definition.
+
+ Media-type values are registered with the Internet Assigned Number
+ Authority (IANA [19]). The media type registration process is
+ outlined in RFC 1590 [17]. Use of non-registered media types is
+ discouraged.
+
+3.7.1 Canonicalization and Text Defaults
+
+ Internet media types are registered with a canonical form. An
+ entity-body transferred via HTTP messages MUST be represented in the
+ appropriate canonical form prior to its transmission except for
+ "text" types, as defined in the next paragraph.
+
+ When in canonical form, media subtypes of the "text" type use CRLF as
+ the text line break. HTTP relaxes this requirement and allows the
+ transport of text media with plain CR or LF alone representing a line
+ break when it is done consistently for an entire entity-body. HTTP
+ applications MUST accept CRLF, bare CR, and bare LF as being
+ representative of a line break in text media received via HTTP. In
+ addition, if the text is represented in a character set that does not
+ use octets 13 and 10 for CR and LF respectively, as is the case for
+ some multi-byte character sets, HTTP allows the use of whatever octet
+ sequences are defined by that character set to represent the
+ equivalent of CR and LF for line breaks. This flexibility regarding
+ line breaks applies only to text media in the entity-body; a bare CR
+ or LF MUST NOT be substituted for CRLF within any of the HTTP control
+ structures (such as header fields and multipart boundaries).
+
+ If an entity-body is encoded with a content-coding, the underlying
+ data MUST be in a form defined above prior to being encoded.
+
+ The "charset" parameter is used with some media types to define the
+ character set (section 3.4) of the data. When no explicit charset
+ parameter is provided by the sender, media subtypes of the "text"
+ type are defined to have a default charset value of "ISO-8859-1" when
+ received via HTTP. Data in character sets other than "ISO-8859-1" or
+ its subsets MUST be labeled with an appropriate charset value. See
+ section 3.4.1 for compatibility problems.
+
+3.7.2 Multipart Types
+
+ MIME provides for a number of "multipart" types -- encapsulations of
+ one or more entities within a single message-body. All multipart
+ types share a common syntax, as defined in section 5.1.1 of RFC 2046
+
+
+
+Fielding, et al. Standards Track [Page 27]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ [40], and MUST include a boundary parameter as part of the media type
+ value. The message body is itself a protocol element and MUST
+ therefore use only CRLF to represent line breaks between body-parts.
+ Unlike in RFC 2046, the epilogue of any multipart message MUST be
+ empty; HTTP applications MUST NOT transmit the epilogue (even if the
+ original multipart contains an epilogue). These restrictions exist in
+ order to preserve the self-delimiting nature of a multipart message-
+ body, wherein the "end" of the message-body is indicated by the
+ ending multipart boundary.
+
+ In general, HTTP treats a multipart message-body no differently than
+ any other media type: strictly as payload. The one exception is the
+ "multipart/byteranges" type (appendix 19.2) when it appears in a 206
+ (Partial Content) response, which will be interpreted by some HTTP
+ caching mechanisms as described in sections 13.5.4 and 14.16. In all
+ other cases, an HTTP user agent SHOULD follow the same or similar
+ behavior as a MIME user agent would upon receipt of a multipart type.
+ The MIME header fields within each body-part of a multipart message-
+ body do not have any significance to HTTP beyond that defined by
+ their MIME semantics.
+
+ In general, an HTTP user agent SHOULD follow the same or similar
+ behavior as a MIME user agent would upon receipt of a multipart type.
+ If an application receives an unrecognized multipart subtype, the
+ application MUST treat it as being equivalent to "multipart/mixed".
+
+ Note: The "multipart/form-data" type has been specifically defined
+ for carrying form data suitable for processing via the POST
+ request method, as described in RFC 1867 [15].
+
+3.8 Product Tokens
+
+ Product tokens are used to allow communicating applications to
+ identify themselves by software name and version. Most fields using
+ product tokens also allow sub-products which form a significant part
+ of the application to be listed, separated by white space. By
+ convention, the products are listed in order of their significance
+ for identifying the application.
+
+ product = token ["/" product-version]
+ product-version = token
+
+ Examples:
+
+ User-Agent: CERN-LineMode/2.15 libwww/2.17b3
+ Server: Apache/0.8.4
+
+
+
+
+
+Fielding, et al. Standards Track [Page 28]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Product tokens SHOULD be short and to the point. They MUST NOT be
+ used for advertising or other non-essential information. Although any
+ token character MAY appear in a product-version, this token SHOULD
+ only be used for a version identifier (i.e., successive versions of
+ the same product SHOULD only differ in the product-version portion of
+ the product value).
+
+3.9 Quality Values
+
+ HTTP content negotiation (section 12) uses short "floating point"
+ numbers to indicate the relative importance ("weight") of various
+ negotiable parameters. A weight is normalized to a real number in
+ the range 0 through 1, where 0 is the minimum and 1 the maximum
+ value. If a parameter has a quality value of 0, then content with
+ this parameter is `not acceptable' for the client. HTTP/1.1
+ applications MUST NOT generate more than three digits after the
+ decimal point. User configuration of these values SHOULD also be
+ limited in this fashion.
+
+ qvalue = ( "0" [ "." 0*3DIGIT ] )
+ | ( "1" [ "." 0*3("0") ] )
+
+ "Quality values" is a misnomer, since these values merely represent
+ relative degradation in desired quality.
+
+3.10 Language Tags
+
+ A language tag identifies a natural language spoken, written, or
+ otherwise conveyed by human beings for communication of information
+ to other human beings. Computer languages are explicitly excluded.
+ HTTP uses language tags within the Accept-Language and Content-
+ Language fields.
+
+ The syntax and registry of HTTP language tags is the same as that
+ defined by RFC 1766 [1]. In summary, a language tag is composed of 1
+ or more parts: A primary language tag and a possibly empty series of
+ subtags:
+
+ language-tag = primary-tag *( "-" subtag )
+ primary-tag = 1*8ALPHA
+ subtag = 1*8ALPHA
+
+ White space is not allowed within the tag and all tags are case-
+ insensitive. The name space of language tags is administered by the
+ IANA. Example tags include:
+
+ en, en-US, en-cockney, i-cherokee, x-pig-latin
+
+
+
+
+Fielding, et al. Standards Track [Page 29]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ where any two-letter primary-tag is an ISO-639 language abbreviation
+ and any two-letter initial subtag is an ISO-3166 country code. (The
+ last three tags above are not registered tags; all but the last are
+ examples of tags which could be registered in future.)
+
+3.11 Entity Tags
+
+ Entity tags are used for comparing two or more entities from the same
+ requested resource. HTTP/1.1 uses entity tags in the ETag (section
+ 14.19), If-Match (section 14.24), If-None-Match (section 14.26), and
+ If-Range (section 14.27) header fields. The definition of how they
+ are used and compared as cache validators is in section 13.3.3. An
+ entity tag consists of an opaque quoted string, possibly prefixed by
+ a weakness indicator.
+
+ entity-tag = [ weak ] opaque-tag
+ weak = "W/"
+ opaque-tag = quoted-string
+
+ A "strong entity tag" MAY be shared by two entities of a resource
+ only if they are equivalent by octet equality.
+
+ A "weak entity tag," indicated by the "W/" prefix, MAY be shared by
+ two entities of a resource only if the entities are equivalent and
+ could be substituted for each other with no significant change in
+ semantics. A weak entity tag can only be used for weak comparison.
+
+ An entity tag MUST be unique across all versions of all entities
+ associated with a particular resource. A given entity tag value MAY
+ be used for entities obtained by requests on different URIs. The use
+ of the same entity tag value in conjunction with entities obtained by
+ requests on different URIs does not imply the equivalence of those
+ entities.
+
+3.12 Range Units
+
+ HTTP/1.1 allows a client to request that only part (a range of) the
+ response entity be included within the response. HTTP/1.1 uses range
+ units in the Range (section 14.35) and Content-Range (section 14.16)
+ header fields. An entity can be broken down into subranges according
+ to various structural units.
+
+ range-unit = bytes-unit | other-range-unit
+ bytes-unit = "bytes"
+ other-range-unit = token
+
+ The only range unit defined by HTTP/1.1 is "bytes". HTTP/1.1
+ implementations MAY ignore ranges specified using other units.
+
+
+
+Fielding, et al. Standards Track [Page 30]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ HTTP/1.1 has been designed to allow implementations of applications
+ that do not depend on knowledge of ranges.
+
+4 HTTP Message
+
+4.1 Message Types
+
+ HTTP messages consist of requests from client to server and responses
+ from server to client.
+
+ HTTP-message = Request | Response ; HTTP/1.1 messages
+
+ Request (section 5) and Response (section 6) messages use the generic
+ message format of RFC 822 [9] for transferring entities (the payload
+ of the message). Both types of message consist of a start-line, zero
+ or more header fields (also known as "headers"), an empty line (i.e.,
+ a line with nothing preceding the CRLF) indicating the end of the
+ header fields, and possibly a message-body.
+
+ generic-message = start-line
+ *(message-header CRLF)
+ CRLF
+ [ message-body ]
+ start-line = Request-Line | Status-Line
+
+ In the interest of robustness, servers SHOULD ignore any empty
+ line(s) received where a Request-Line is expected. In other words, if
+ the server is reading the protocol stream at the beginning of a
+ message and receives a CRLF first, it should ignore the CRLF.
+
+ Certain buggy HTTP/1.0 client implementations generate extra CRLF's
+ after a POST request. To restate what is explicitly forbidden by the
+ BNF, an HTTP/1.1 client MUST NOT preface or follow a request with an
+ extra CRLF.
+
+4.2 Message Headers
+
+ HTTP header fields, which include general-header (section 4.5),
+ request-header (section 5.3), response-header (section 6.2), and
+ entity-header (section 7.1) fields, follow the same generic format as
+ that given in Section 3.1 of RFC 822 [9]. Each header field consists
+ of a name followed by a colon (":") and the field value. Field names
+ are case-insensitive. The field value MAY be preceded by any amount
+ of LWS, though a single SP is preferred. Header fields can be
+ extended over multiple lines by preceding each extra line with at
+ least one SP or HT. Applications ought to follow "common form", where
+ one is known or indicated, when generating HTTP constructs, since
+ there might exist some implementations that fail to accept anything
+
+
+
+Fielding, et al. Standards Track [Page 31]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ beyond the common forms.
+
+ message-header = field-name ":" [ field-value ]
+ field-name = token
+ field-value = *( field-content | LWS )
+ field-content = <the OCTETs making up the field-value
+ and consisting of either *TEXT or combinations
+ of token, separators, and quoted-string>
+
+ The field-content does not include any leading or trailing LWS:
+ linear white space occurring before the first non-whitespace
+ character of the field-value or after the last non-whitespace
+ character of the field-value. Such leading or trailing LWS MAY be
+ removed without changing the semantics of the field value. Any LWS
+ that occurs between field-content MAY be replaced with a single SP
+ before interpreting the field value or forwarding the message
+ downstream.
+
+ The order in which header fields with differing field names are
+ received is not significant. However, it is "good practice" to send
+ general-header fields first, followed by request-header or response-
+ header fields, and ending with the entity-header fields.
+
+ Multiple message-header fields with the same field-name MAY be
+ present in a message if and only if the entire field-value for that
+ header field is defined as a comma-separated list [i.e., #(values)].
+ It MUST be possible to combine the multiple header fields into one
+ "field-name: field-value" pair, without changing the semantics of the
+ message, by appending each subsequent field-value to the first, each
+ separated by a comma. The order in which header fields with the same
+ field-name are received is therefore significant to the
+ interpretation of the combined field value, and thus a proxy MUST NOT
+ change the order of these field values when a message is forwarded.
+
+4.3 Message Body
+
+ The message-body (if any) of an HTTP message is used to carry the
+ entity-body associated with the request or response. The message-body
+ differs from the entity-body only when a transfer-coding has been
+ applied, as indicated by the Transfer-Encoding header field (section
+ 14.41).
+
+ message-body = entity-body
+ | <entity-body encoded as per Transfer-Encoding>
+
+ Transfer-Encoding MUST be used to indicate any transfer-codings
+ applied by an application to ensure safe and proper transfer of the
+ message. Transfer-Encoding is a property of the message, not of the
+
+
+
+Fielding, et al. Standards Track [Page 32]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ entity, and thus MAY be added or removed by any application along the
+ request/response chain. (However, section 3.6 places restrictions on
+ when certain transfer-codings may be used.)
+
+ The rules for when a message-body is allowed in a message differ for
+ requests and responses.
+
+ The presence of a message-body in a request is signaled by the
+ inclusion of a Content-Length or Transfer-Encoding header field in
+ the request's message-headers. A message-body MUST NOT be included in
+ a request if the specification of the request method (section 5.1.1)
+ does not allow sending an entity-body in requests. A server SHOULD
+ read and forward a message-body on any request; if the request method
+ does not include defined semantics for an entity-body, then the
+ message-body SHOULD be ignored when handling the request.
+
+ For response messages, whether or not a message-body is included with
+ a message is dependent on both the request method and the response
+ status code (section 6.1.1). All responses to the HEAD request method
+ MUST NOT include a message-body, even though the presence of entity-
+ header fields might lead one to believe they do. All 1xx
+ (informational), 204 (no content), and 304 (not modified) responses
+ MUST NOT include a message-body. All other responses do include a
+ message-body, although it MAY be of zero length.
+
+4.4 Message Length
+
+ The transfer-length of a message is the length of the message-body as
+ it appears in the message; that is, after any transfer-codings have
+ been applied. When a message-body is included with a message, the
+ transfer-length of that body is determined by one of the following
+ (in order of precedence):
+
+ 1.Any response message which "MUST NOT" include a message-body (such
+ as the 1xx, 204, and 304 responses and any response to a HEAD
+ request) is always terminated by the first empty line after the
+ header fields, regardless of the entity-header fields present in
+ the message.
+
+ 2.If a Transfer-Encoding header field (section 14.41) is present and
+ has any value other than "identity", then the transfer-length is
+ defined by use of the "chunked" transfer-coding (section 3.6),
+ unless the message is terminated by closing the connection.
+
+ 3.If a Content-Length header field (section 14.13) is present, its
+ decimal value in OCTETs represents both the entity-length and the
+ transfer-length. The Content-Length header field MUST NOT be sent
+ if these two lengths are different (i.e., if a Transfer-Encoding
+
+
+
+Fielding, et al. Standards Track [Page 33]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ header field is present). If a message is received with both a
+ Transfer-Encoding header field and a Content-Length header field,
+ the latter MUST be ignored.
+
+ 4.If the message uses the media type "multipart/byteranges", and the
+ ransfer-length is not otherwise specified, then this self-
+ elimiting media type defines the transfer-length. This media type
+ UST NOT be used unless the sender knows that the recipient can arse
+ it; the presence in a request of a Range header with ultiple byte-
+ range specifiers from a 1.1 client implies that the lient can parse
+ multipart/byteranges responses.
+
+ A range header might be forwarded by a 1.0 proxy that does not
+ understand multipart/byteranges; in this case the server MUST
+ delimit the message using methods defined in items 1,3 or 5 of
+ this section.
+
+ 5.By the server closing the connection. (Closing the connection
+ cannot be used to indicate the end of a request body, since that
+ would leave no possibility for the server to send back a response.)
+
+ For compatibility with HTTP/1.0 applications, HTTP/1.1 requests
+ containing a message-body MUST include a valid Content-Length header
+ field unless the server is known to be HTTP/1.1 compliant. If a
+ request contains a message-body and a Content-Length is not given,
+ the server SHOULD respond with 400 (bad request) if it cannot
+ determine the length of the message, or with 411 (length required) if
+ it wishes to insist on receiving a valid Content-Length.
+
+ All HTTP/1.1 applications that receive entities MUST accept the
+ "chunked" transfer-coding (section 3.6), thus allowing this mechanism
+ to be used for messages when the message length cannot be determined
+ in advance.
+
+ Messages MUST NOT include both a Content-Length header field and a
+ non-identity transfer-coding. If the message does include a non-
+ identity transfer-coding, the Content-Length MUST be ignored.
+
+ When a Content-Length is given in a message where a message-body is
+ allowed, its field value MUST exactly match the number of OCTETs in
+ the message-body. HTTP/1.1 user agents MUST notify the user when an
+ invalid length is received and detected.
+
+4.5 General Header Fields
+
+ There are a few header fields which have general applicability for
+ both request and response messages, but which do not apply to the
+ entity being transferred. These header fields apply only to the
+
+
+
+Fielding, et al. Standards Track [Page 34]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ message being transmitted.
+
+ general-header = Cache-Control ; Section 14.9
+ | Connection ; Section 14.10
+ | Date ; Section 14.18
+ | Pragma ; Section 14.32
+ | Trailer ; Section 14.40
+ | Transfer-Encoding ; Section 14.41
+ | Upgrade ; Section 14.42
+ | Via ; Section 14.45
+ | Warning ; Section 14.46
+
+ General-header field names can be extended reliably only in
+ combination with a change in the protocol version. However, new or
+ experimental header fields may be given the semantics of general
+ header fields if all parties in the communication recognize them to
+ be general-header fields. Unrecognized header fields are treated as
+ entity-header fields.
+
+5 Request
+
+ A request message from a client to a server includes, within the
+ first line of that message, the method to be applied to the resource,
+ the identifier of the resource, and the protocol version in use.
+
+ Request = Request-Line ; Section 5.1
+ *(( general-header ; Section 4.5
+ | request-header ; Section 5.3
+ | entity-header ) CRLF) ; Section 7.1
+ CRLF
+ [ message-body ] ; Section 4.3
+
+5.1 Request-Line
+
+ The Request-Line begins with a method token, followed by the
+ Request-URI and the protocol version, and ending with CRLF. The
+ elements are separated by SP characters. No CR or LF is allowed
+ except in the final CRLF sequence.
+
+ Request-Line = Method SP Request-URI SP HTTP-Version CRLF
+
+
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 35]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+5.1.1 Method
+
+ The Method token indicates the method to be performed on the
+ resource identified by the Request-URI. The method is case-sensitive.
+
+ Method = "OPTIONS" ; Section 9.2
+ | "GET" ; Section 9.3
+ | "HEAD" ; Section 9.4
+ | "POST" ; Section 9.5
+ | "PUT" ; Section 9.6
+ | "DELETE" ; Section 9.7
+ | "TRACE" ; Section 9.8
+ | "CONNECT" ; Section 9.9
+ | extension-method
+ extension-method = token
+
+ The list of methods allowed by a resource can be specified in an
+ Allow header field (section 14.7). The return code of the response
+ always notifies the client whether a method is currently allowed on a
+ resource, since the set of allowed methods can change dynamically. An
+ origin server SHOULD return the status code 405 (Method Not Allowed)
+ if the method is known by the origin server but not allowed for the
+ requested resource, and 501 (Not Implemented) if the method is
+ unrecognized or not implemented by the origin server. The methods GET
+ and HEAD MUST be supported by all general-purpose servers. All other
+ methods are OPTIONAL; however, if the above methods are implemented,
+ they MUST be implemented with the same semantics as those specified
+ in section 9.
+
+5.1.2 Request-URI
+
+ The Request-URI is a Uniform Resource Identifier (section 3.2) and
+ identifies the resource upon which to apply the request.
+
+ Request-URI = "*" | absoluteURI | abs_path | authority
+
+ The four options for Request-URI are dependent on the nature of the
+ request. The asterisk "*" means that the request does not apply to a
+ particular resource, but to the server itself, and is only allowed
+ when the method used does not necessarily apply to a resource. One
+ example would be
+
+ OPTIONS * HTTP/1.1
+
+ The absoluteURI form is REQUIRED when the request is being made to a
+ proxy. The proxy is requested to forward the request or service it
+ from a valid cache, and return the response. Note that the proxy MAY
+ forward the request on to another proxy or directly to the server
+
+
+
+Fielding, et al. Standards Track [Page 36]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ specified by the absoluteURI. In order to avoid request loops, a
+ proxy MUST be able to recognize all of its server names, including
+ any aliases, local variations, and the numeric IP address. An example
+ Request-Line would be:
+
+ GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1
+
+ To allow for transition to absoluteURIs in all requests in future
+ versions of HTTP, all HTTP/1.1 servers MUST accept the absoluteURI
+ form in requests, even though HTTP/1.1 clients will only generate
+ them in requests to proxies.
+
+ The authority form is only used by the CONNECT method (section 9.9).
+
+ The most common form of Request-URI is that used to identify a
+ resource on an origin server or gateway. In this case the absolute
+ path of the URI MUST be transmitted (see section 3.2.1, abs_path) as
+ the Request-URI, and the network location of the URI (authority) MUST
+ be transmitted in a Host header field. For example, a client wishing
+ to retrieve the resource above directly from the origin server would
+ create a TCP connection to port 80 of the host "www.w3.org" and send
+ the lines:
+
+ GET /pub/WWW/TheProject.html HTTP/1.1
+ Host: www.w3.org
+
+ followed by the remainder of the Request. Note that the absolute path
+ cannot be empty; if none is present in the original URI, it MUST be
+ given as "/" (the server root).
+
+ The Request-URI is transmitted in the format specified in section
+ 3.2.1. If the Request-URI is encoded using the "% HEX HEX" encoding
+ [42], the origin server MUST decode the Request-URI in order to
+ properly interpret the request. Servers SHOULD respond to invalid
+ Request-URIs with an appropriate status code.
+
+ A transparent proxy MUST NOT rewrite the "abs_path" part of the
+ received Request-URI when forwarding it to the next inbound server,
+ except as noted above to replace a null abs_path with "/".
+
+ Note: The "no rewrite" rule prevents the proxy from changing the
+ meaning of the request when the origin server is improperly using
+ a non-reserved URI character for a reserved purpose. Implementors
+ should be aware that some pre-HTTP/1.1 proxies have been known to
+ rewrite the Request-URI.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 37]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+5.2 The Resource Identified by a Request
+
+ The exact resource identified by an Internet request is determined by
+ examining both the Request-URI and the Host header field.
+
+ An origin server that does not allow resources to differ by the
+ requested host MAY ignore the Host header field value when
+ determining the resource identified by an HTTP/1.1 request. (But see
+ section 19.6.1.1 for other requirements on Host support in HTTP/1.1.)
+
+ An origin server that does differentiate resources based on the host
+ requested (sometimes referred to as virtual hosts or vanity host
+ names) MUST use the following rules for determining the requested
+ resource on an HTTP/1.1 request:
+
+ 1. If Request-URI is an absoluteURI, the host is part of the
+ Request-URI. Any Host header field value in the request MUST be
+ ignored.
+
+ 2. If the Request-URI is not an absoluteURI, and the request includes
+ a Host header field, the host is determined by the Host header
+ field value.
+
+ 3. If the host as determined by rule 1 or 2 is not a valid host on
+ the server, the response MUST be a 400 (Bad Request) error message.
+
+ Recipients of an HTTP/1.0 request that lacks a Host header field MAY
+ attempt to use heuristics (e.g., examination of the URI path for
+ something unique to a particular host) in order to determine what
+ exact resource is being requested.
+
+5.3 Request Header Fields
+
+ The request-header fields allow the client to pass additional
+ information about the request, and about the client itself, to the
+ server. These fields act as request modifiers, with semantics
+ equivalent to the parameters on a programming language method
+ invocation.
+
+ request-header = Accept ; Section 14.1
+ | Accept-Charset ; Section 14.2
+ | Accept-Encoding ; Section 14.3
+ | Accept-Language ; Section 14.4
+ | Authorization ; Section 14.8
+ | Expect ; Section 14.20
+ | From ; Section 14.22
+ | Host ; Section 14.23
+ | If-Match ; Section 14.24
+
+
+
+Fielding, et al. Standards Track [Page 38]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ | If-Modified-Since ; Section 14.25
+ | If-None-Match ; Section 14.26
+ | If-Range ; Section 14.27
+ | If-Unmodified-Since ; Section 14.28
+ | Max-Forwards ; Section 14.31
+ | Proxy-Authorization ; Section 14.34
+ | Range ; Section 14.35
+ | Referer ; Section 14.36
+ | TE ; Section 14.39
+ | User-Agent ; Section 14.43
+
+ Request-header field names can be extended reliably only in
+ combination with a change in the protocol version. However, new or
+ experimental header fields MAY be given the semantics of request-
+ header fields if all parties in the communication recognize them to
+ be request-header fields. Unrecognized header fields are treated as
+ entity-header fields.
+
+6 Response
+
+ After receiving and interpreting a request message, a server responds
+ with an HTTP response message.
+
+ Response = Status-Line ; Section 6.1
+ *(( general-header ; Section 4.5
+ | response-header ; Section 6.2
+ | entity-header ) CRLF) ; Section 7.1
+ CRLF
+ [ message-body ] ; Section 7.2
+
+6.1 Status-Line
+
+ The first line of a Response message is the Status-Line, consisting
+ of the protocol version followed by a numeric status code and its
+ associated textual phrase, with each element separated by SP
+ characters. No CR or LF is allowed except in the final CRLF sequence.
+
+ Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
+
+6.1.1 Status Code and Reason Phrase
+
+ The Status-Code element is a 3-digit integer result code of the
+ attempt to understand and satisfy the request. These codes are fully
+ defined in section 10. The Reason-Phrase is intended to give a short
+ textual description of the Status-Code. The Status-Code is intended
+ for use by automata and the Reason-Phrase is intended for the human
+ user. The client is not required to examine or display the Reason-
+ Phrase.
+
+
+
+Fielding, et al. Standards Track [Page 39]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The first digit of the Status-Code defines the class of response. The
+ last two digits do not have any categorization role. There are 5
+ values for the first digit:
+
+ - 1xx: Informational - Request received, continuing process
+
+ - 2xx: Success - The action was successfully received,
+ understood, and accepted
+
+ - 3xx: Redirection - Further action must be taken in order to
+ complete the request
+
+ - 4xx: Client Error - The request contains bad syntax or cannot
+ be fulfilled
+
+ - 5xx: Server Error - The server failed to fulfill an apparently
+ valid request
+
+ The individual values of the numeric status codes defined for
+ HTTP/1.1, and an example set of corresponding Reason-Phrase's, are
+ presented below. The reason phrases listed here are only
+ recommendations -- they MAY be replaced by local equivalents without
+ affecting the protocol.
+
+ Status-Code =
+ "100" ; Section 10.1.1: Continue
+ | "101" ; Section 10.1.2: Switching Protocols
+ | "200" ; Section 10.2.1: OK
+ | "201" ; Section 10.2.2: Created
+ | "202" ; Section 10.2.3: Accepted
+ | "203" ; Section 10.2.4: Non-Authoritative Information
+ | "204" ; Section 10.2.5: No Content
+ | "205" ; Section 10.2.6: Reset Content
+ | "206" ; Section 10.2.7: Partial Content
+ | "300" ; Section 10.3.1: Multiple Choices
+ | "301" ; Section 10.3.2: Moved Permanently
+ | "302" ; Section 10.3.3: Found
+ | "303" ; Section 10.3.4: See Other
+ | "304" ; Section 10.3.5: Not Modified
+ | "305" ; Section 10.3.6: Use Proxy
+ | "307" ; Section 10.3.8: Temporary Redirect
+ | "400" ; Section 10.4.1: Bad Request
+ | "401" ; Section 10.4.2: Unauthorized
+ | "402" ; Section 10.4.3: Payment Required
+ | "403" ; Section 10.4.4: Forbidden
+ | "404" ; Section 10.4.5: Not Found
+ | "405" ; Section 10.4.6: Method Not Allowed
+ | "406" ; Section 10.4.7: Not Acceptable
+
+
+
+Fielding, et al. Standards Track [Page 40]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ | "407" ; Section 10.4.8: Proxy Authentication Required
+ | "408" ; Section 10.4.9: Request Time-out
+ | "409" ; Section 10.4.10: Conflict
+ | "410" ; Section 10.4.11: Gone
+ | "411" ; Section 10.4.12: Length Required
+ | "412" ; Section 10.4.13: Precondition Failed
+ | "413" ; Section 10.4.14: Request Entity Too Large
+ | "414" ; Section 10.4.15: Request-URI Too Large
+ | "415" ; Section 10.4.16: Unsupported Media Type
+ | "416" ; Section 10.4.17: Requested range not satisfiable
+ | "417" ; Section 10.4.18: Expectation Failed
+ | "500" ; Section 10.5.1: Internal Server Error
+ | "501" ; Section 10.5.2: Not Implemented
+ | "502" ; Section 10.5.3: Bad Gateway
+ | "503" ; Section 10.5.4: Service Unavailable
+ | "504" ; Section 10.5.5: Gateway Time-out
+ | "505" ; Section 10.5.6: HTTP Version not supported
+ | extension-code
+
+ extension-code = 3DIGIT
+ Reason-Phrase = *<TEXT, excluding CR, LF>
+
+ HTTP status codes are extensible. HTTP applications are not required
+ to understand the meaning of all registered status codes, though such
+ understanding is obviously desirable. However, applications MUST
+ understand the class of any status code, as indicated by the first
+ digit, and treat any unrecognized response as being equivalent to the
+ x00 status code of that class, with the exception that an
+ unrecognized response MUST NOT be cached. For example, if an
+ unrecognized status code of 431 is received by the client, it can
+ safely assume that there was something wrong with its request and
+ treat the response as if it had received a 400 status code. In such
+ cases, user agents SHOULD present to the user the entity returned
+ with the response, since that entity is likely to include human-
+ readable information which will explain the unusual status.
+
+6.2 Response Header Fields
+
+ The response-header fields allow the server to pass additional
+ information about the response which cannot be placed in the Status-
+ Line. These header fields give information about the server and about
+ further access to the resource identified by the Request-URI.
+
+ response-header = Accept-Ranges ; Section 14.5
+ | Age ; Section 14.6
+ | ETag ; Section 14.19
+ | Location ; Section 14.30
+ | Proxy-Authenticate ; Section 14.33
+
+
+
+Fielding, et al. Standards Track [Page 41]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ | Retry-After ; Section 14.37
+ | Server ; Section 14.38
+ | Vary ; Section 14.44
+ | WWW-Authenticate ; Section 14.47
+
+ Response-header field names can be extended reliably only in
+ combination with a change in the protocol version. However, new or
+ experimental header fields MAY be given the semantics of response-
+ header fields if all parties in the communication recognize them to
+ be response-header fields. Unrecognized header fields are treated as
+ entity-header fields.
+
+7 Entity
+
+ Request and Response messages MAY transfer an entity if not otherwise
+ restricted by the request method or response status code. An entity
+ consists of entity-header fields and an entity-body, although some
+ responses will only include the entity-headers.
+
+ In this section, both sender and recipient refer to either the client
+ or the server, depending on who sends and who receives the entity.
+
+7.1 Entity Header Fields
+
+ Entity-header fields define metainformation about the entity-body or,
+ if no body is present, about the resource identified by the request.
+ Some of this metainformation is OPTIONAL; some might be REQUIRED by
+ portions of this specification.
+
+ entity-header = Allow ; Section 14.7
+ | Content-Encoding ; Section 14.11
+ | Content-Language ; Section 14.12
+ | Content-Length ; Section 14.13
+ | Content-Location ; Section 14.14
+ | Content-MD5 ; Section 14.15
+ | Content-Range ; Section 14.16
+ | Content-Type ; Section 14.17
+ | Expires ; Section 14.21
+ | Last-Modified ; Section 14.29
+ | extension-header
+
+ extension-header = message-header
+
+ The extension-header mechanism allows additional entity-header fields
+ to be defined without changing the protocol, but these fields cannot
+ be assumed to be recognizable by the recipient. Unrecognized header
+ fields SHOULD be ignored by the recipient and MUST be forwarded by
+ transparent proxies.
+
+
+
+Fielding, et al. Standards Track [Page 42]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+7.2 Entity Body
+
+ The entity-body (if any) sent with an HTTP request or response is in
+ a format and encoding defined by the entity-header fields.
+
+ entity-body = *OCTET
+
+ An entity-body is only present in a message when a message-body is
+ present, as described in section 4.3. The entity-body is obtained
+ from the message-body by decoding any Transfer-Encoding that might
+ have been applied to ensure safe and proper transfer of the message.
+
+7.2.1 Type
+
+ When an entity-body is included with a message, the data type of that
+ body is determined via the header fields Content-Type and Content-
+ Encoding. These define a two-layer, ordered encoding model:
+
+ entity-body := Content-Encoding( Content-Type( data ) )
+
+ Content-Type specifies the media type of the underlying data.
+ Content-Encoding may be used to indicate any additional content
+ codings applied to the data, usually for the purpose of data
+ compression, that are a property of the requested resource. There is
+ no default encoding.
+
+ Any HTTP/1.1 message containing an entity-body SHOULD include a
+ Content-Type header field defining the media type of that body. If
+ and only if the media type is not given by a Content-Type field, the
+ recipient MAY attempt to guess the media type via inspection of its
+ content and/or the name extension(s) of the URI used to identify the
+ resource. If the media type remains unknown, the recipient SHOULD
+ treat it as type "application/octet-stream".
+
+7.2.2 Entity Length
+
+ The entity-length of a message is the length of the message-body
+ before any transfer-codings have been applied. Section 4.4 defines
+ how the transfer-length of a message-body is determined.
+
+
+
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 43]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+8 Connections
+
+8.1 Persistent Connections
+
+8.1.1 Purpose
+
+ Prior to persistent connections, a separate TCP connection was
+ established to fetch each URL, increasing the load on HTTP servers
+ and causing congestion on the Internet. The use of inline images and
+ other associated data often require a client to make multiple
+ requests of the same server in a short amount of time. Analysis of
+ these performance problems and results from a prototype
+ implementation are available [26] [30]. Implementation experience and
+ measurements of actual HTTP/1.1 (RFC 2068) implementations show good
+ results [39]. Alternatives have also been explored, for example,
+ T/TCP [27].
+
+ Persistent HTTP connections have a number of advantages:
+
+ - By opening and closing fewer TCP connections, CPU time is saved
+ in routers and hosts (clients, servers, proxies, gateways,
+ tunnels, or caches), and memory used for TCP protocol control
+ blocks can be saved in hosts.
+
+ - HTTP requests and responses can be pipelined on a connection.
+ Pipelining allows a client to make multiple requests without
+ waiting for each response, allowing a single TCP connection to
+ be used much more efficiently, with much lower elapsed time.
+
+ - Network congestion is reduced by reducing the number of packets
+ caused by TCP opens, and by allowing TCP sufficient time to
+ determine the congestion state of the network.
+
+ - Latency on subsequent requests is reduced since there is no time
+ spent in TCP's connection opening handshake.
+
+ - HTTP can evolve more gracefully, since errors can be reported
+ without the penalty of closing the TCP connection. Clients using
+ future versions of HTTP might optimistically try a new feature,
+ but if communicating with an older server, retry with old
+ semantics after an error is reported.
+
+ HTTP implementations SHOULD implement persistent connections.
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 44]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+8.1.2 Overall Operation
+
+ A significant difference between HTTP/1.1 and earlier versions of
+ HTTP is that persistent connections are the default behavior of any
+ HTTP connection. That is, unless otherwise indicated, the client
+ SHOULD assume that the server will maintain a persistent connection,
+ even after error responses from the server.
+
+ Persistent connections provide a mechanism by which a client and a
+ server can signal the close of a TCP connection. This signaling takes
+ place using the Connection header field (section 14.10). Once a close
+ has been signaled, the client MUST NOT send any more requests on that
+ connection.
+
+8.1.2.1 Negotiation
+
+ An HTTP/1.1 server MAY assume that a HTTP/1.1 client intends to
+ maintain a persistent connection unless a Connection header including
+ the connection-token "close" was sent in the request. If the server
+ chooses to close the connection immediately after sending the
+ response, it SHOULD send a Connection header including the
+ connection-token close.
+
+ An HTTP/1.1 client MAY expect a connection to remain open, but would
+ decide to keep it open based on whether the response from a server
+ contains a Connection header with the connection-token close. In case
+ the client does not want to maintain a connection for more than that
+ request, it SHOULD send a Connection header including the
+ connection-token close.
+
+ If either the client or the server sends the close token in the
+ Connection header, that request becomes the last one for the
+ connection.
+
+ Clients and servers SHOULD NOT assume that a persistent connection is
+ maintained for HTTP versions less than 1.1 unless it is explicitly
+ signaled. See section 19.6.2 for more information on backward
+ compatibility with HTTP/1.0 clients.
+
+ In order to remain persistent, all messages on the connection MUST
+ have a self-defined message length (i.e., one not defined by closure
+ of the connection), as described in section 4.4.
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 45]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+8.1.2.2 Pipelining
+
+ A client that supports persistent connections MAY "pipeline" its
+ requests (i.e., send multiple requests without waiting for each
+ response). A server MUST send its responses to those requests in the
+ same order that the requests were received.
+
+ Clients which assume persistent connections and pipeline immediately
+ after connection establishment SHOULD be prepared to retry their
+ connection if the first pipelined attempt fails. If a client does
+ such a retry, it MUST NOT pipeline before it knows the connection is
+ persistent. Clients MUST also be prepared to resend their requests if
+ the server closes the connection before sending all of the
+ corresponding responses.
+
+ Clients SHOULD NOT pipeline requests using non-idempotent methods or
+ non-idempotent sequences of methods (see section 9.1.2). Otherwise, a
+ premature termination of the transport connection could lead to
+ indeterminate results. A client wishing to send a non-idempotent
+ request SHOULD wait to send that request until it has received the
+ response status for the previous request.
+
+8.1.3 Proxy Servers
+
+ It is especially important that proxies correctly implement the
+ properties of the Connection header field as specified in section
+ 14.10.
+
+ The proxy server MUST signal persistent connections separately with
+ its clients and the origin servers (or other proxy servers) that it
+ connects to. Each persistent connection applies to only one transport
+ link.
+
+ A proxy server MUST NOT establish a HTTP/1.1 persistent connection
+ with an HTTP/1.0 client (but see RFC 2068 [33] for information and
+ discussion of the problems with the Keep-Alive header implemented by
+ many HTTP/1.0 clients).
+
+8.1.4 Practical Considerations
+
+ Servers will usually have some time-out value beyond which they will
+ no longer maintain an inactive connection. Proxy servers might make
+ this a higher value since it is likely that the client will be making
+ more connections through the same server. The use of persistent
+ connections places no requirements on the length (or existence) of
+ this time-out for either the client or the server.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 46]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ When a client or server wishes to time-out it SHOULD issue a graceful
+ close on the transport connection. Clients and servers SHOULD both
+ constantly watch for the other side of the transport close, and
+ respond to it as appropriate. If a client or server does not detect
+ the other side's close promptly it could cause unnecessary resource
+ drain on the network.
+
+ A client, server, or proxy MAY close the transport connection at any
+ time. For example, a client might have started to send a new request
+ at the same time that the server has decided to close the "idle"
+ connection. From the server's point of view, the connection is being
+ closed while it was idle, but from the client's point of view, a
+ request is in progress.
+
+ This means that clients, servers, and proxies MUST be able to recover
+ from asynchronous close events. Client software SHOULD reopen the
+ transport connection and retransmit the aborted sequence of requests
+ without user interaction so long as the request sequence is
+ idempotent (see section 9.1.2). Non-idempotent methods or sequences
+ MUST NOT be automatically retried, although user agents MAY offer a
+ human operator the choice of retrying the request(s). Confirmation by
+ user-agent software with semantic understanding of the application
+ MAY substitute for user confirmation. The automatic retry SHOULD NOT
+ be repeated if the second sequence of requests fails.
+
+ Servers SHOULD always respond to at least one request per connection,
+ if at all possible. Servers SHOULD NOT close a connection in the
+ middle of transmitting a response, unless a network or client failure
+ is suspected.
+
+ Clients that use persistent connections SHOULD limit the number of
+ simultaneous connections that they maintain to a given server. A
+ single-user client SHOULD NOT maintain more than 2 connections with
+ any server or proxy. A proxy SHOULD use up to 2*N connections to
+ another server or proxy, where N is the number of simultaneously
+ active users. These guidelines are intended to improve HTTP response
+ times and avoid congestion.
+
+8.2 Message Transmission Requirements
+
+8.2.1 Persistent Connections and Flow Control
+
+ HTTP/1.1 servers SHOULD maintain persistent connections and use TCP's
+ flow control mechanisms to resolve temporary overloads, rather than
+ terminating connections with the expectation that clients will retry.
+ The latter technique can exacerbate network congestion.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 47]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+8.2.2 Monitoring Connections for Error Status Messages
+
+ An HTTP/1.1 (or later) client sending a message-body SHOULD monitor
+ the network connection for an error status while it is transmitting
+ the request. If the client sees an error status, it SHOULD
+ immediately cease transmitting the body. If the body is being sent
+ using a "chunked" encoding (section 3.6), a zero length chunk and
+ empty trailer MAY be used to prematurely mark the end of the message.
+ If the body was preceded by a Content-Length header, the client MUST
+ close the connection.
+
+8.2.3 Use of the 100 (Continue) Status
+
+ The purpose of the 100 (Continue) status (see section 10.1.1) is to
+ allow a client that is sending a request message with a request body
+ to determine if the origin server is willing to accept the request
+ (based on the request headers) before the client sends the request
+ body. In some cases, it might either be inappropriate or highly
+ inefficient for the client to send the body if the server will reject
+ the message without looking at the body.
+
+ Requirements for HTTP/1.1 clients:
+
+ - If a client will wait for a 100 (Continue) response before
+ sending the request body, it MUST send an Expect request-header
+ field (section 14.20) with the "100-continue" expectation.
+
+ - A client MUST NOT send an Expect request-header field (section
+ 14.20) with the "100-continue" expectation if it does not intend
+ to send a request body.
+
+ Because of the presence of older implementations, the protocol allows
+ ambiguous situations in which a client may send "Expect: 100-
+ continue" without receiving either a 417 (Expectation Failed) status
+ or a 100 (Continue) status. Therefore, when a client sends this
+ header field to an origin server (possibly via a proxy) from which it
+ has never seen a 100 (Continue) status, the client SHOULD NOT wait
+ for an indefinite period before sending the request body.
+
+ Requirements for HTTP/1.1 origin servers:
+
+ - Upon receiving a request which includes an Expect request-header
+ field with the "100-continue" expectation, an origin server MUST
+ either respond with 100 (Continue) status and continue to read
+ from the input stream, or respond with a final status code. The
+ origin server MUST NOT wait for the request body before sending
+ the 100 (Continue) response. If it responds with a final status
+ code, it MAY close the transport connection or it MAY continue
+
+
+
+Fielding, et al. Standards Track [Page 48]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ to read and discard the rest of the request. It MUST NOT
+ perform the requested method if it returns a final status code.
+
+ - An origin server SHOULD NOT send a 100 (Continue) response if
+ the request message does not include an Expect request-header
+ field with the "100-continue" expectation, and MUST NOT send a
+ 100 (Continue) response if such a request comes from an HTTP/1.0
+ (or earlier) client. There is an exception to this rule: for
+ compatibility with RFC 2068, a server MAY send a 100 (Continue)
+ status in response to an HTTP/1.1 PUT or POST request that does
+ not include an Expect request-header field with the "100-
+ continue" expectation. This exception, the purpose of which is
+ to minimize any client processing delays associated with an
+ undeclared wait for 100 (Continue) status, applies only to
+ HTTP/1.1 requests, and not to requests with any other HTTP-
+ version value.
+
+ - An origin server MAY omit a 100 (Continue) response if it has
+ already received some or all of the request body for the
+ corresponding request.
+
+ - An origin server that sends a 100 (Continue) response MUST
+ ultimately send a final status code, once the request body is
+ received and processed, unless it terminates the transport
+ connection prematurely.
+
+ - If an origin server receives a request that does not include an
+ Expect request-header field with the "100-continue" expectation,
+ the request includes a request body, and the server responds
+ with a final status code before reading the entire request body
+ from the transport connection, then the server SHOULD NOT close
+ the transport connection until it has read the entire request,
+ or until the client closes the connection. Otherwise, the client
+ might not reliably receive the response message. However, this
+ requirement is not be construed as preventing a server from
+ defending itself against denial-of-service attacks, or from
+ badly broken client implementations.
+
+ Requirements for HTTP/1.1 proxies:
+
+ - If a proxy receives a request that includes an Expect request-
+ header field with the "100-continue" expectation, and the proxy
+ either knows that the next-hop server complies with HTTP/1.1 or
+ higher, or does not know the HTTP version of the next-hop
+ server, it MUST forward the request, including the Expect header
+ field.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 49]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ - If the proxy knows that the version of the next-hop server is
+ HTTP/1.0 or lower, it MUST NOT forward the request, and it MUST
+ respond with a 417 (Expectation Failed) status.
+
+ - Proxies SHOULD maintain a cache recording the HTTP version
+ numbers received from recently-referenced next-hop servers.
+
+ - A proxy MUST NOT forward a 100 (Continue) response if the
+ request message was received from an HTTP/1.0 (or earlier)
+ client and did not include an Expect request-header field with
+ the "100-continue" expectation. This requirement overrides the
+ general rule for forwarding of 1xx responses (see section 10.1).
+
+8.2.4 Client Behavior if Server Prematurely Closes Connection
+
+ If an HTTP/1.1 client sends a request which includes a request body,
+ but which does not include an Expect request-header field with the
+ "100-continue" expectation, and if the client is not directly
+ connected to an HTTP/1.1 origin server, and if the client sees the
+ connection close before receiving any status from the server, the
+ client SHOULD retry the request. If the client does retry this
+ request, it MAY use the following "binary exponential backoff"
+ algorithm to be assured of obtaining a reliable response:
+
+ 1. Initiate a new connection to the server
+
+ 2. Transmit the request-headers
+
+ 3. Initialize a variable R to the estimated round-trip time to the
+ server (e.g., based on the time it took to establish the
+ connection), or to a constant value of 5 seconds if the round-
+ trip time is not available.
+
+ 4. Compute T = R * (2**N), where N is the number of previous
+ retries of this request.
+
+ 5. Wait either for an error response from the server, or for T
+ seconds (whichever comes first)
+
+ 6. If no error response is received, after T seconds transmit the
+ body of the request.
+
+ 7. If client sees that the connection is closed prematurely,
+ repeat from step 1 until the request is accepted, an error
+ response is received, or the user becomes impatient and
+ terminates the retry process.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 50]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If at any point an error status is received, the client
+
+ - SHOULD NOT continue and
+
+ - SHOULD close the connection if it has not completed sending the
+ request message.
+
+9 Method Definitions
+
+ The set of common methods for HTTP/1.1 is defined below. Although
+ this set can be expanded, additional methods cannot be assumed to
+ share the same semantics for separately extended clients and servers.
+
+ The Host request-header field (section 14.23) MUST accompany all
+ HTTP/1.1 requests.
+
+9.1 Safe and Idempotent Methods
+
+9.1.1 Safe Methods
+
+ Implementors should be aware that the software represents the user in
+ their interactions over the Internet, and should be careful to allow
+ the user to be aware of any actions they might take which may have an
+ unexpected significance to themselves or others.
+
+ In particular, the convention has been established that the GET and
+ HEAD methods SHOULD NOT have the significance of taking an action
+ other than retrieval. These methods ought to be considered "safe".
+ This allows user agents to represent other methods, such as POST, PUT
+ and DELETE, in a special way, so that the user is made aware of the
+ fact that a possibly unsafe action is being requested.
+
+ Naturally, it is not possible to ensure that the server does not
+ generate side-effects as a result of performing a GET request; in
+ fact, some dynamic resources consider that a feature. The important
+ distinction here is that the user did not request the side-effects,
+ so therefore cannot be held accountable for them.
+
+9.1.2 Idempotent Methods
+
+ Methods can also have the property of "idempotence" in that (aside
+ from error or expiration issues) the side-effects of N > 0 identical
+ requests is the same as for a single request. The methods GET, HEAD,
+ PUT and DELETE share this property. Also, the methods OPTIONS and
+ TRACE SHOULD NOT have side effects, and so are inherently idempotent.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 51]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ However, it is possible that a sequence of several requests is non-
+ idempotent, even if all of the methods executed in that sequence are
+ idempotent. (A sequence is idempotent if a single execution of the
+ entire sequence always yields a result that is not changed by a
+ reexecution of all, or part, of that sequence.) For example, a
+ sequence is non-idempotent if its result depends on a value that is
+ later modified in the same sequence.
+
+ A sequence that never has side effects is idempotent, by definition
+ (provided that no concurrent operations are being executed on the
+ same set of resources).
+
+9.2 OPTIONS
+
+ The OPTIONS method represents a request for information about the
+ communication options available on the request/response chain
+ identified by the Request-URI. This method allows the client to
+ determine the options and/or requirements associated with a resource,
+ or the capabilities of a server, without implying a resource action
+ or initiating a resource retrieval.
+
+ Responses to this method are not cacheable.
+
+ If the OPTIONS request includes an entity-body (as indicated by the
+ presence of Content-Length or Transfer-Encoding), then the media type
+ MUST be indicated by a Content-Type field. Although this
+ specification does not define any use for such a body, future
+ extensions to HTTP might use the OPTIONS body to make more detailed
+ queries on the server. A server that does not support such an
+ extension MAY discard the request body.
+
+ If the Request-URI is an asterisk ("*"), the OPTIONS request is
+ intended to apply to the server in general rather than to a specific
+ resource. Since a server's communication options typically depend on
+ the resource, the "*" request is only useful as a "ping" or "no-op"
+ type of method; it does nothing beyond allowing the client to test
+ the capabilities of the server. For example, this can be used to test
+ a proxy for HTTP/1.1 compliance (or lack thereof).
+
+ If the Request-URI is not an asterisk, the OPTIONS request applies
+ only to the options that are available when communicating with that
+ resource.
+
+ A 200 response SHOULD include any header fields that indicate
+ optional features implemented by the server and applicable to that
+ resource (e.g., Allow), possibly including extensions not defined by
+ this specification. The response body, if any, SHOULD also include
+ information about the communication options. The format for such a
+
+
+
+Fielding, et al. Standards Track [Page 52]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ body is not defined by this specification, but might be defined by
+ future extensions to HTTP. Content negotiation MAY be used to select
+ the appropriate response format. If no response body is included, the
+ response MUST include a Content-Length field with a field-value of
+ "0".
+
+ The Max-Forwards request-header field MAY be used to target a
+ specific proxy in the request chain. When a proxy receives an OPTIONS
+ request on an absoluteURI for which request forwarding is permitted,
+ the proxy MUST check for a Max-Forwards field. If the Max-Forwards
+ field-value is zero ("0"), the proxy MUST NOT forward the message;
+ instead, the proxy SHOULD respond with its own communication options.
+ If the Max-Forwards field-value is an integer greater than zero, the
+ proxy MUST decrement the field-value when it forwards the request. If
+ no Max-Forwards field is present in the request, then the forwarded
+ request MUST NOT include a Max-Forwards field.
+
+9.3 GET
+
+ The GET method means retrieve whatever information (in the form of an
+ entity) is identified by the Request-URI. If the Request-URI refers
+ to a data-producing process, it is the produced data which shall be
+ returned as the entity in the response and not the source text of the
+ process, unless that text happens to be the output of the process.
+
+ The semantics of the GET method change to a "conditional GET" if the
+ request message includes an If-Modified-Since, If-Unmodified-Since,
+ If-Match, If-None-Match, or If-Range header field. A conditional GET
+ method requests that the entity be transferred only under the
+ circumstances described by the conditional header field(s). The
+ conditional GET method is intended to reduce unnecessary network
+ usage by allowing cached entities to be refreshed without requiring
+ multiple requests or transferring data already held by the client.
+
+ The semantics of the GET method change to a "partial GET" if the
+ request message includes a Range header field. A partial GET requests
+ that only part of the entity be transferred, as described in section
+ 14.35. The partial GET method is intended to reduce unnecessary
+ network usage by allowing partially-retrieved entities to be
+ completed without transferring data already held by the client.
+
+ The response to a GET request is cacheable if and only if it meets
+ the requirements for HTTP caching described in section 13.
+
+ See section 15.1.3 for security considerations when used for forms.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 53]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+9.4 HEAD
+
+ The HEAD method is identical to GET except that the server MUST NOT
+ return a message-body in the response. The metainformation contained
+ in the HTTP headers in response to a HEAD request SHOULD be identical
+ to the information sent in response to a GET request. This method can
+ be used for obtaining metainformation about the entity implied by the
+ request without transferring the entity-body itself. This method is
+ often used for testing hypertext links for validity, accessibility,
+ and recent modification.
+
+ The response to a HEAD request MAY be cacheable in the sense that the
+ information contained in the response MAY be used to update a
+ previously cached entity from that resource. If the new field values
+ indicate that the cached entity differs from the current entity (as
+ would be indicated by a change in Content-Length, Content-MD5, ETag
+ or Last-Modified), then the cache MUST treat the cache entry as
+ stale.
+
+9.5 POST
+
+ The POST method is used to request that the origin server accept the
+ entity enclosed in the request as a new subordinate of the resource
+ identified by the Request-URI in the Request-Line. POST is designed
+ to allow a uniform method to cover the following functions:
+
+ - Annotation of existing resources;
+
+ - Posting a message to a bulletin board, newsgroup, mailing list,
+ or similar group of articles;
+
+ - Providing a block of data, such as the result of submitting a
+ form, to a data-handling process;
+
+ - Extending a database through an append operation.
+
+ The actual function performed by the POST method is determined by the
+ server and is usually dependent on the Request-URI. The posted entity
+ is subordinate to that URI in the same way that a file is subordinate
+ to a directory containing it, a news article is subordinate to a
+ newsgroup to which it is posted, or a record is subordinate to a
+ database.
+
+ The action performed by the POST method might not result in a
+ resource that can be identified by a URI. In this case, either 200
+ (OK) or 204 (No Content) is the appropriate response status,
+ depending on whether or not the response includes an entity that
+ describes the result.
+
+
+
+Fielding, et al. Standards Track [Page 54]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If a resource has been created on the origin server, the response
+ SHOULD be 201 (Created) and contain an entity which describes the
+ status of the request and refers to the new resource, and a Location
+ header (see section 14.30).
+
+ Responses to this method are not cacheable, unless the response
+ includes appropriate Cache-Control or Expires header fields. However,
+ the 303 (See Other) response can be used to direct the user agent to
+ retrieve a cacheable resource.
+
+ POST requests MUST obey the message transmission requirements set out
+ in section 8.2.
+
+ See section 15.1.3 for security considerations.
+
+9.6 PUT
+
+ The PUT method requests that the enclosed entity be stored under the
+ supplied Request-URI. If the Request-URI refers to an already
+ existing resource, the enclosed entity SHOULD be considered as a
+ modified version of the one residing on the origin server. If the
+ Request-URI does not point to an existing resource, and that URI is
+ capable of being defined as a new resource by the requesting user
+ agent, the origin server can create the resource with that URI. If a
+ new resource is created, the origin server MUST inform the user agent
+ via the 201 (Created) response. If an existing resource is modified,
+ either the 200 (OK) or 204 (No Content) response codes SHOULD be sent
+ to indicate successful completion of the request. If the resource
+ could not be created or modified with the Request-URI, an appropriate
+ error response SHOULD be given that reflects the nature of the
+ problem. The recipient of the entity MUST NOT ignore any Content-*
+ (e.g. Content-Range) headers that it does not understand or implement
+ and MUST return a 501 (Not Implemented) response in such cases.
+
+ If the request passes through a cache and the Request-URI identifies
+ one or more currently cached entities, those entries SHOULD be
+ treated as stale. Responses to this method are not cacheable.
+
+ The fundamental difference between the POST and PUT requests is
+ reflected in the different meaning of the Request-URI. The URI in a
+ POST request identifies the resource that will handle the enclosed
+ entity. That resource might be a data-accepting process, a gateway to
+ some other protocol, or a separate entity that accepts annotations.
+ In contrast, the URI in a PUT request identifies the entity enclosed
+ with the request -- the user agent knows what URI is intended and the
+ server MUST NOT attempt to apply the request to some other resource.
+ If the server desires that the request be applied to a different URI,
+
+
+
+
+Fielding, et al. Standards Track [Page 55]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ it MUST send a 301 (Moved Permanently) response; the user agent MAY
+ then make its own decision regarding whether or not to redirect the
+ request.
+
+ A single resource MAY be identified by many different URIs. For
+ example, an article might have a URI for identifying "the current
+ version" which is separate from the URI identifying each particular
+ version. In this case, a PUT request on a general URI might result in
+ several other URIs being defined by the origin server.
+
+ HTTP/1.1 does not define how a PUT method affects the state of an
+ origin server.
+
+ PUT requests MUST obey the message transmission requirements set out
+ in section 8.2.
+
+ Unless otherwise specified for a particular entity-header, the
+ entity-headers in the PUT request SHOULD be applied to the resource
+ created or modified by the PUT.
+
+9.7 DELETE
+
+ The DELETE method requests that the origin server delete the resource
+ identified by the Request-URI. This method MAY be overridden by human
+ intervention (or other means) on the origin server. The client cannot
+ be guaranteed that the operation has been carried out, even if the
+ status code returned from the origin server indicates that the action
+ has been completed successfully. However, the server SHOULD NOT
+ indicate success unless, at the time the response is given, it
+ intends to delete the resource or move it to an inaccessible
+ location.
+
+ A successful response SHOULD be 200 (OK) if the response includes an
+ entity describing the status, 202 (Accepted) if the action has not
+ yet been enacted, or 204 (No Content) if the action has been enacted
+ but the response does not include an entity.
+
+ If the request passes through a cache and the Request-URI identifies
+ one or more currently cached entities, those entries SHOULD be
+ treated as stale. Responses to this method are not cacheable.
+
+9.8 TRACE
+
+ The TRACE method is used to invoke a remote, application-layer loop-
+ back of the request message. The final recipient of the request
+ SHOULD reflect the message received back to the client as the
+ entity-body of a 200 (OK) response. The final recipient is either the
+
+
+
+
+Fielding, et al. Standards Track [Page 56]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ origin server or the first proxy or gateway to receive a Max-Forwards
+ value of zero (0) in the request (see section 14.31). A TRACE request
+ MUST NOT include an entity.
+
+ TRACE allows the client to see what is being received at the other
+ end of the request chain and use that data for testing or diagnostic
+ information. The value of the Via header field (section 14.45) is of
+ particular interest, since it acts as a trace of the request chain.
+ Use of the Max-Forwards header field allows the client to limit the
+ length of the request chain, which is useful for testing a chain of
+ proxies forwarding messages in an infinite loop.
+
+ If the request is valid, the response SHOULD contain the entire
+ request message in the entity-body, with a Content-Type of
+ "message/http". Responses to this method MUST NOT be cached.
+
+9.9 CONNECT
+
+ This specification reserves the method name CONNECT for use with a
+ proxy that can dynamically switch to being a tunnel (e.g. SSL
+ tunneling [44]).
+
+10 Status Code Definitions
+
+ Each Status-Code is described below, including a description of which
+ method(s) it can follow and any metainformation required in the
+ response.
+
+10.1 Informational 1xx
+
+ This class of status code indicates a provisional response,
+ consisting only of the Status-Line and optional headers, and is
+ terminated by an empty line. There are no required headers for this
+ class of status code. Since HTTP/1.0 did not define any 1xx status
+ codes, servers MUST NOT send a 1xx response to an HTTP/1.0 client
+ except under experimental conditions.
+
+ A client MUST be prepared to accept one or more 1xx status responses
+ prior to a regular response, even if the client does not expect a 100
+ (Continue) status message. Unexpected 1xx status responses MAY be
+ ignored by a user agent.
+
+ Proxies MUST forward 1xx responses, unless the connection between the
+ proxy and its client has been closed, or unless the proxy itself
+ requested the generation of the 1xx response. (For example, if a
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 57]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ proxy adds a "Expect: 100-continue" field when it forwards a request,
+ then it need not forward the corresponding 100 (Continue)
+ response(s).)
+
+10.1.1 100 Continue
+
+ The client SHOULD continue with its request. This interim response is
+ used to inform the client that the initial part of the request has
+ been received and has not yet been rejected by the server. The client
+ SHOULD continue by sending the remainder of the request or, if the
+ request has already been completed, ignore this response. The server
+ MUST send a final response after the request has been completed. See
+ section 8.2.3 for detailed discussion of the use and handling of this
+ status code.
+
+10.1.2 101 Switching Protocols
+
+ The server understands and is willing to comply with the client's
+ request, via the Upgrade message header field (section 14.42), for a
+ change in the application protocol being used on this connection. The
+ server will switch protocols to those defined by the response's
+ Upgrade header field immediately after the empty line which
+ terminates the 101 response.
+
+ The protocol SHOULD be switched only when it is advantageous to do
+ so. For example, switching to a newer version of HTTP is advantageous
+ over older versions, and switching to a real-time, synchronous
+ protocol might be advantageous when delivering resources that use
+ such features.
+
+10.2 Successful 2xx
+
+ This class of status code indicates that the client's request was
+ successfully received, understood, and accepted.
+
+10.2.1 200 OK
+
+ The request has succeeded. The information returned with the response
+ is dependent on the method used in the request, for example:
+
+ GET an entity corresponding to the requested resource is sent in
+ the response;
+
+ HEAD the entity-header fields corresponding to the requested
+ resource are sent in the response without any message-body;
+
+ POST an entity describing or containing the result of the action;
+
+
+
+
+Fielding, et al. Standards Track [Page 58]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ TRACE an entity containing the request message as received by the
+ end server.
+
+10.2.2 201 Created
+
+ The request has been fulfilled and resulted in a new resource being
+ created. The newly created resource can be referenced by the URI(s)
+ returned in the entity of the response, with the most specific URI
+ for the resource given by a Location header field. The response
+ SHOULD include an entity containing a list of resource
+ characteristics and location(s) from which the user or user agent can
+ choose the one most appropriate. The entity format is specified by
+ the media type given in the Content-Type header field. The origin
+ server MUST create the resource before returning the 201 status code.
+ If the action cannot be carried out immediately, the server SHOULD
+ respond with 202 (Accepted) response instead.
+
+ A 201 response MAY contain an ETag response header field indicating
+ the current value of the entity tag for the requested variant just
+ created, see section 14.19.
+
+10.2.3 202 Accepted
+
+ The request has been accepted for processing, but the processing has
+ not been completed. The request might or might not eventually be
+ acted upon, as it might be disallowed when processing actually takes
+ place. There is no facility for re-sending a status code from an
+ asynchronous operation such as this.
+
+ The 202 response is intentionally non-committal. Its purpose is to
+ allow a server to accept a request for some other process (perhaps a
+ batch-oriented process that is only run once per day) without
+ requiring that the user agent's connection to the server persist
+ until the process is completed. The entity returned with this
+ response SHOULD include an indication of the request's current status
+ and either a pointer to a status monitor or some estimate of when the
+ user can expect the request to be fulfilled.
+
+10.2.4 203 Non-Authoritative Information
+
+ The returned metainformation in the entity-header is not the
+ definitive set as available from the origin server, but is gathered
+ from a local or a third-party copy. The set presented MAY be a subset
+ or superset of the original version. For example, including local
+ annotation information about the resource might result in a superset
+ of the metainformation known by the origin server. Use of this
+ response code is not required and is only appropriate when the
+ response would otherwise be 200 (OK).
+
+
+
+Fielding, et al. Standards Track [Page 59]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+10.2.5 204 No Content
+
+ The server has fulfilled the request but does not need to return an
+ entity-body, and might want to return updated metainformation. The
+ response MAY include new or updated metainformation in the form of
+ entity-headers, which if present SHOULD be associated with the
+ requested variant.
+
+ If the client is a user agent, it SHOULD NOT change its document view
+ from that which caused the request to be sent. This response is
+ primarily intended to allow input for actions to take place without
+ causing a change to the user agent's active document view, although
+ any new or updated metainformation SHOULD be applied to the document
+ currently in the user agent's active view.
+
+ The 204 response MUST NOT include a message-body, and thus is always
+ terminated by the first empty line after the header fields.
+
+10.2.6 205 Reset Content
+
+ The server has fulfilled the request and the user agent SHOULD reset
+ the document view which caused the request to be sent. This response
+ is primarily intended to allow input for actions to take place via
+ user input, followed by a clearing of the form in which the input is
+ given so that the user can easily initiate another input action. The
+ response MUST NOT include an entity.
+
+10.2.7 206 Partial Content
+
+ The server has fulfilled the partial GET request for the resource.
+ The request MUST have included a Range header field (section 14.35)
+ indicating the desired range, and MAY have included an If-Range
+ header field (section 14.27) to make the request conditional.
+
+ The response MUST include the following header fields:
+
+ - Either a Content-Range header field (section 14.16) indicating
+ the range included with this response, or a multipart/byteranges
+ Content-Type including Content-Range fields for each part. If a
+ Content-Length header field is present in the response, its
+ value MUST match the actual number of OCTETs transmitted in the
+ message-body.
+
+ - Date
+
+ - ETag and/or Content-Location, if the header would have been sent
+ in a 200 response to the same request
+
+
+
+
+Fielding, et al. Standards Track [Page 60]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ - Expires, Cache-Control, and/or Vary, if the field-value might
+ differ from that sent in any previous response for the same
+ variant
+
+ If the 206 response is the result of an If-Range request that used a
+ strong cache validator (see section 13.3.3), the response SHOULD NOT
+ include other entity-headers. If the response is the result of an
+ If-Range request that used a weak validator, the response MUST NOT
+ include other entity-headers; this prevents inconsistencies between
+ cached entity-bodies and updated headers. Otherwise, the response
+ MUST include all of the entity-headers that would have been returned
+ with a 200 (OK) response to the same request.
+
+ A cache MUST NOT combine a 206 response with other previously cached
+ content if the ETag or Last-Modified headers do not match exactly,
+ see 13.5.4.
+
+ A cache that does not support the Range and Content-Range headers
+ MUST NOT cache 206 (Partial) responses.
+
+10.3 Redirection 3xx
+
+ This class of status code indicates that further action needs to be
+ taken by the user agent in order to fulfill the request. The action
+ required MAY be carried out by the user agent without interaction
+ with the user if and only if the method used in the second request is
+ GET or HEAD. A client SHOULD detect infinite redirection loops, since
+ such loops generate network traffic for each redirection.
+
+ Note: previous versions of this specification recommended a
+ maximum of five redirections. Content developers should be aware
+ that there might be clients that implement such a fixed
+ limitation.
+
+10.3.1 300 Multiple Choices
+
+ The requested resource corresponds to any one of a set of
+ representations, each with its own specific location, and agent-
+ driven negotiation information (section 12) is being provided so that
+ the user (or user agent) can select a preferred representation and
+ redirect its request to that location.
+
+ Unless it was a HEAD request, the response SHOULD include an entity
+ containing a list of resource characteristics and location(s) from
+ which the user or user agent can choose the one most appropriate. The
+ entity format is specified by the media type given in the Content-
+ Type header field. Depending upon the format and the capabilities of
+
+
+
+
+Fielding, et al. Standards Track [Page 61]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ the user agent, selection of the most appropriate choice MAY be
+ performed automatically. However, this specification does not define
+ any standard for such automatic selection.
+
+ If the server has a preferred choice of representation, it SHOULD
+ include the specific URI for that representation in the Location
+ field; user agents MAY use the Location field value for automatic
+ redirection. This response is cacheable unless indicated otherwise.
+
+10.3.2 301 Moved Permanently
+
+ The requested resource has been assigned a new permanent URI and any
+ future references to this resource SHOULD use one of the returned
+ URIs. Clients with link editing capabilities ought to automatically
+ re-link references to the Request-URI to one or more of the new
+ references returned by the server, where possible. This response is
+ cacheable unless indicated otherwise.
+
+ The new permanent URI SHOULD be given by the Location field in the
+ response. Unless the request method was HEAD, the entity of the
+ response SHOULD contain a short hypertext note with a hyperlink to
+ the new URI(s).
+
+ If the 301 status code is received in response to a request other
+ than GET or HEAD, the user agent MUST NOT automatically redirect the
+ request unless it can be confirmed by the user, since this might
+ change the conditions under which the request was issued.
+
+ Note: When automatically redirecting a POST request after
+ receiving a 301 status code, some existing HTTP/1.0 user agents
+ will erroneously change it into a GET request.
+
+10.3.3 302 Found
+
+ The requested resource resides temporarily under a different URI.
+ Since the redirection might be altered on occasion, the client SHOULD
+ continue to use the Request-URI for future requests. This response
+ is only cacheable if indicated by a Cache-Control or Expires header
+ field.
+
+ The temporary URI SHOULD be given by the Location field in the
+ response. Unless the request method was HEAD, the entity of the
+ response SHOULD contain a short hypertext note with a hyperlink to
+ the new URI(s).
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 62]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If the 302 status code is received in response to a request other
+ than GET or HEAD, the user agent MUST NOT automatically redirect the
+ request unless it can be confirmed by the user, since this might
+ change the conditions under which the request was issued.
+
+ Note: RFC 1945 and RFC 2068 specify that the client is not allowed
+ to change the method on the redirected request. However, most
+ existing user agent implementations treat 302 as if it were a 303
+ response, performing a GET on the Location field-value regardless
+ of the original request method. The status codes 303 and 307 have
+ been added for servers that wish to make unambiguously clear which
+ kind of reaction is expected of the client.
+
+10.3.4 303 See Other
+
+ The response to the request can be found under a different URI and
+ SHOULD be retrieved using a GET method on that resource. This method
+ exists primarily to allow the output of a POST-activated script to
+ redirect the user agent to a selected resource. The new URI is not a
+ substitute reference for the originally requested resource. The 303
+ response MUST NOT be cached, but the response to the second
+ (redirected) request might be cacheable.
+
+ The different URI SHOULD be given by the Location field in the
+ response. Unless the request method was HEAD, the entity of the
+ response SHOULD contain a short hypertext note with a hyperlink to
+ the new URI(s).
+
+ Note: Many pre-HTTP/1.1 user agents do not understand the 303
+ status. When interoperability with such clients is a concern, the
+ 302 status code may be used instead, since most user agents react
+ to a 302 response as described here for 303.
+
+10.3.5 304 Not Modified
+
+ If the client has performed a conditional GET request and access is
+ allowed, but the document has not been modified, the server SHOULD
+ respond with this status code. The 304 response MUST NOT contain a
+ message-body, and thus is always terminated by the first empty line
+ after the header fields.
+
+ The response MUST include the following header fields:
+
+ - Date, unless its omission is required by section 14.18.1
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 63]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If a clockless origin server obeys these rules, and proxies and
+ clients add their own Date to any response received without one (as
+ already specified by [RFC 2068], section 14.19), caches will operate
+ correctly.
+
+ - ETag and/or Content-Location, if the header would have been sent
+ in a 200 response to the same request
+
+ - Expires, Cache-Control, and/or Vary, if the field-value might
+ differ from that sent in any previous response for the same
+ variant
+
+ If the conditional GET used a strong cache validator (see section
+ 13.3.3), the response SHOULD NOT include other entity-headers.
+ Otherwise (i.e., the conditional GET used a weak validator), the
+ response MUST NOT include other entity-headers; this prevents
+ inconsistencies between cached entity-bodies and updated headers.
+
+ If a 304 response indicates an entity not currently cached, then the
+ cache MUST disregard the response and repeat the request without the
+ conditional.
+
+ If a cache uses a received 304 response to update a cache entry, the
+ cache MUST update the entry to reflect any new field values given in
+ the response.
+
+10.3.6 305 Use Proxy
+
+ The requested resource MUST be accessed through the proxy given by
+ the Location field. The Location field gives the URI of the proxy.
+ The recipient is expected to repeat this single request via the
+ proxy. 305 responses MUST only be generated by origin servers.
+
+ Note: RFC 2068 was not clear that 305 was intended to redirect a
+ single request, and to be generated by origin servers only. Not
+ observing these limitations has significant security consequences.
+
+10.3.7 306 (Unused)
+
+ The 306 status code was used in a previous version of the
+ specification, is no longer used, and the code is reserved.
+
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 64]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+10.3.8 307 Temporary Redirect
+
+ The requested resource resides temporarily under a different URI.
+ Since the redirection MAY be altered on occasion, the client SHOULD
+ continue to use the Request-URI for future requests. This response
+ is only cacheable if indicated by a Cache-Control or Expires header
+ field.
+
+ The temporary URI SHOULD be given by the Location field in the
+ response. Unless the request method was HEAD, the entity of the
+ response SHOULD contain a short hypertext note with a hyperlink to
+ the new URI(s) , since many pre-HTTP/1.1 user agents do not
+ understand the 307 status. Therefore, the note SHOULD contain the
+ information necessary for a user to repeat the original request on
+ the new URI.
+
+ If the 307 status code is received in response to a request other
+ than GET or HEAD, the user agent MUST NOT automatically redirect the
+ request unless it can be confirmed by the user, since this might
+ change the conditions under which the request was issued.
+
+10.4 Client Error 4xx
+
+ The 4xx class of status code is intended for cases in which the
+ client seems to have erred. Except when responding to a HEAD request,
+ the server SHOULD include an entity containing an explanation of the
+ error situation, and whether it is a temporary or permanent
+ condition. These status codes are applicable to any request method.
+ User agents SHOULD display any included entity to the user.
+
+ If the client is sending data, a server implementation using TCP
+ SHOULD be careful to ensure that the client acknowledges receipt of
+ the packet(s) containing the response, before the server closes the
+ input connection. If the client continues sending data to the server
+ after the close, the server's TCP stack will send a reset packet to
+ the client, which may erase the client's unacknowledged input buffers
+ before they can be read and interpreted by the HTTP application.
+
+10.4.1 400 Bad Request
+
+ The request could not be understood by the server due to malformed
+ syntax. The client SHOULD NOT repeat the request without
+ modifications.
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 65]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+10.4.2 401 Unauthorized
+
+ The request requires user authentication. The response MUST include a
+ WWW-Authenticate header field (section 14.47) containing a challenge
+ applicable to the requested resource. The client MAY repeat the
+ request with a suitable Authorization header field (section 14.8). If
+ the request already included Authorization credentials, then the 401
+ response indicates that authorization has been refused for those
+ credentials. If the 401 response contains the same challenge as the
+ prior response, and the user agent has already attempted
+ authentication at least once, then the user SHOULD be presented the
+ entity that was given in the response, since that entity might
+ include relevant diagnostic information. HTTP access authentication
+ is explained in "HTTP Authentication: Basic and Digest Access
+ Authentication" [43].
+
+10.4.3 402 Payment Required
+
+ This code is reserved for future use.
+
+10.4.4 403 Forbidden
+
+ The server understood the request, but is refusing to fulfill it.
+ Authorization will not help and the request SHOULD NOT be repeated.
+ If the request method was not HEAD and the server wishes to make
+ public why the request has not been fulfilled, it SHOULD describe the
+ reason for the refusal in the entity. If the server does not wish to
+ make this information available to the client, the status code 404
+ (Not Found) can be used instead.
+
+10.4.5 404 Not Found
+
+ The server has not found anything matching the Request-URI. No
+ indication is given of whether the condition is temporary or
+ permanent. The 410 (Gone) status code SHOULD be used if the server
+ knows, through some internally configurable mechanism, that an old
+ resource is permanently unavailable and has no forwarding address.
+ This status code is commonly used when the server does not wish to
+ reveal exactly why the request has been refused, or when no other
+ response is applicable.
+
+10.4.6 405 Method Not Allowed
+
+ The method specified in the Request-Line is not allowed for the
+ resource identified by the Request-URI. The response MUST include an
+ Allow header containing a list of valid methods for the requested
+ resource.
+
+
+
+
+Fielding, et al. Standards Track [Page 66]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+10.4.7 406 Not Acceptable
+
+ The resource identified by the request is only capable of generating
+ response entities which have content characteristics not acceptable
+ according to the accept headers sent in the request.
+
+ Unless it was a HEAD request, the response SHOULD include an entity
+ containing a list of available entity characteristics and location(s)
+ from which the user or user agent can choose the one most
+ appropriate. The entity format is specified by the media type given
+ in the Content-Type header field. Depending upon the format and the
+ capabilities of the user agent, selection of the most appropriate
+ choice MAY be performed automatically. However, this specification
+ does not define any standard for such automatic selection.
+
+ Note: HTTP/1.1 servers are allowed to return responses which are
+ not acceptable according to the accept headers sent in the
+ request. In some cases, this may even be preferable to sending a
+ 406 response. User agents are encouraged to inspect the headers of
+ an incoming response to determine if it is acceptable.
+
+ If the response could be unacceptable, a user agent SHOULD
+ temporarily stop receipt of more data and query the user for a
+ decision on further actions.
+
+10.4.8 407 Proxy Authentication Required
+
+ This code is similar to 401 (Unauthorized), but indicates that the
+ client must first authenticate itself with the proxy. The proxy MUST
+ return a Proxy-Authenticate header field (section 14.33) containing a
+ challenge applicable to the proxy for the requested resource. The
+ client MAY repeat the request with a suitable Proxy-Authorization
+ header field (section 14.34). HTTP access authentication is explained
+ in "HTTP Authentication: Basic and Digest Access Authentication"
+ [43].
+
+10.4.9 408 Request Timeout
+
+ The client did not produce a request within the time that the server
+ was prepared to wait. The client MAY repeat the request without
+ modifications at any later time.
+
+10.4.10 409 Conflict
+
+ The request could not be completed due to a conflict with the current
+ state of the resource. This code is only allowed in situations where
+ it is expected that the user might be able to resolve the conflict
+ and resubmit the request. The response body SHOULD include enough
+
+
+
+Fielding, et al. Standards Track [Page 67]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ information for the user to recognize the source of the conflict.
+ Ideally, the response entity would include enough information for the
+ user or user agent to fix the problem; however, that might not be
+ possible and is not required.
+
+ Conflicts are most likely to occur in response to a PUT request. For
+ example, if versioning were being used and the entity being PUT
+ included changes to a resource which conflict with those made by an
+ earlier (third-party) request, the server might use the 409 response
+ to indicate that it can't complete the request. In this case, the
+ response entity would likely contain a list of the differences
+ between the two versions in a format defined by the response
+ Content-Type.
+
+10.4.11 410 Gone
+
+ The requested resource is no longer available at the server and no
+ forwarding address is known. This condition is expected to be
+ considered permanent. Clients with link editing capabilities SHOULD
+ delete references to the Request-URI after user approval. If the
+ server does not know, or has no facility to determine, whether or not
+ the condition is permanent, the status code 404 (Not Found) SHOULD be
+ used instead. This response is cacheable unless indicated otherwise.
+
+ The 410 response is primarily intended to assist the task of web
+ maintenance by notifying the recipient that the resource is
+ intentionally unavailable and that the server owners desire that
+ remote links to that resource be removed. Such an event is common for
+ limited-time, promotional services and for resources belonging to
+ individuals no longer working at the server's site. It is not
+ necessary to mark all permanently unavailable resources as "gone" or
+ to keep the mark for any length of time -- that is left to the
+ discretion of the server owner.
+
+10.4.12 411 Length Required
+
+ The server refuses to accept the request without a defined Content-
+ Length. The client MAY repeat the request if it adds a valid
+ Content-Length header field containing the length of the message-body
+ in the request message.
+
+10.4.13 412 Precondition Failed
+
+ The precondition given in one or more of the request-header fields
+ evaluated to false when it was tested on the server. This response
+ code allows the client to place preconditions on the current resource
+ metainformation (header field data) and thus prevent the requested
+ method from being applied to a resource other than the one intended.
+
+
+
+Fielding, et al. Standards Track [Page 68]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+10.4.14 413 Request Entity Too Large
+
+ The server is refusing to process a request because the request
+ entity is larger than the server is willing or able to process. The
+ server MAY close the connection to prevent the client from continuing
+ the request.
+
+ If the condition is temporary, the server SHOULD include a Retry-
+ After header field to indicate that it is temporary and after what
+ time the client MAY try again.
+
+10.4.15 414 Request-URI Too Long
+
+ The server is refusing to service the request because the Request-URI
+ is longer than the server is willing to interpret. This rare
+ condition is only likely to occur when a client has improperly
+ converted a POST request to a GET request with long query
+ information, when the client has descended into a URI "black hole" of
+ redirection (e.g., a redirected URI prefix that points to a suffix of
+ itself), or when the server is under attack by a client attempting to
+ exploit security holes present in some servers using fixed-length
+ buffers for reading or manipulating the Request-URI.
+
+10.4.16 415 Unsupported Media Type
+
+ The server is refusing to service the request because the entity of
+ the request is in a format not supported by the requested resource
+ for the requested method.
+
+10.4.17 416 Requested Range Not Satisfiable
+
+ A server SHOULD return a response with this status code if a request
+ included a Range request-header field (section 14.35), and none of
+ the range-specifier values in this field overlap the current extent
+ of the selected resource, and the request did not include an If-Range
+ request-header field. (For byte-ranges, this means that the first-
+ byte-pos of all of the byte-range-spec values were greater than the
+ current length of the selected resource.)
+
+ When this status code is returned for a byte-range request, the
+ response SHOULD include a Content-Range entity-header field
+ specifying the current length of the selected resource (see section
+ 14.16). This response MUST NOT use the multipart/byteranges content-
+ type.
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 69]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+10.4.18 417 Expectation Failed
+
+ The expectation given in an Expect request-header field (see section
+ 14.20) could not be met by this server, or, if the server is a proxy,
+ the server has unambiguous evidence that the request could not be met
+ by the next-hop server.
+
+10.5 Server Error 5xx
+
+ Response status codes beginning with the digit "5" indicate cases in
+ which the server is aware that it has erred or is incapable of
+ performing the request. Except when responding to a HEAD request, the
+ server SHOULD include an entity containing an explanation of the
+ error situation, and whether it is a temporary or permanent
+ condition. User agents SHOULD display any included entity to the
+ user. These response codes are applicable to any request method.
+
+10.5.1 500 Internal Server Error
+
+ The server encountered an unexpected condition which prevented it
+ from fulfilling the request.
+
+10.5.2 501 Not Implemented
+
+ The server does not support the functionality required to fulfill the
+ request. This is the appropriate response when the server does not
+ recognize the request method and is not capable of supporting it for
+ any resource.
+
+10.5.3 502 Bad Gateway
+
+ The server, while acting as a gateway or proxy, received an invalid
+ response from the upstream server it accessed in attempting to
+ fulfill the request.
+
+10.5.4 503 Service Unavailable
+
+ The server is currently unable to handle the request due to a
+ temporary overloading or maintenance of the server. The implication
+ is that this is a temporary condition which will be alleviated after
+ some delay. If known, the length of the delay MAY be indicated in a
+ Retry-After header. If no Retry-After is given, the client SHOULD
+ handle the response as it would for a 500 response.
+
+ Note: The existence of the 503 status code does not imply that a
+ server must use it when becoming overloaded. Some servers may wish
+ to simply refuse the connection.
+
+
+
+
+Fielding, et al. Standards Track [Page 70]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+10.5.5 504 Gateway Timeout
+
+ The server, while acting as a gateway or proxy, did not receive a
+ timely response from the upstream server specified by the URI (e.g.
+ HTTP, FTP, LDAP) or some other auxiliary server (e.g. DNS) it needed
+ to access in attempting to complete the request.
+
+ Note: Note to implementors: some deployed proxies are known to
+ return 400 or 500 when DNS lookups time out.
+
+10.5.6 505 HTTP Version Not Supported
+
+ The server does not support, or refuses to support, the HTTP protocol
+ version that was used in the request message. The server is
+ indicating that it is unable or unwilling to complete the request
+ using the same major version as the client, as described in section
+ 3.1, other than with this error message. The response SHOULD contain
+ an entity describing why that version is not supported and what other
+ protocols are supported by that server.
+
+11 Access Authentication
+
+ HTTP provides several OPTIONAL challenge-response authentication
+ mechanisms which can be used by a server to challenge a client
+ request and by a client to provide authentication information. The
+ general framework for access authentication, and the specification of
+ "basic" and "digest" authentication, are specified in "HTTP
+ Authentication: Basic and Digest Access Authentication" [43]. This
+ specification adopts the definitions of "challenge" and "credentials"
+ from that specification.
+
+12 Content Negotiation
+
+ Most HTTP responses include an entity which contains information for
+ interpretation by a human user. Naturally, it is desirable to supply
+ the user with the "best available" entity corresponding to the
+ request. Unfortunately for servers and caches, not all users have the
+ same preferences for what is "best," and not all user agents are
+ equally capable of rendering all entity types. For that reason, HTTP
+ has provisions for several mechanisms for "content negotiation" --
+ the process of selecting the best representation for a given response
+ when there are multiple representations available.
+
+ Note: This is not called "format negotiation" because the
+ alternate representations may be of the same media type, but use
+ different capabilities of that type, be in different languages,
+ etc.
+
+
+
+
+Fielding, et al. Standards Track [Page 71]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Any response containing an entity-body MAY be subject to negotiation,
+ including error responses.
+
+ There are two kinds of content negotiation which are possible in
+ HTTP: server-driven and agent-driven negotiation. These two kinds of
+ negotiation are orthogonal and thus may be used separately or in
+ combination. One method of combination, referred to as transparent
+ negotiation, occurs when a cache uses the agent-driven negotiation
+ information provided by the origin server in order to provide
+ server-driven negotiation for subsequent requests.
+
+12.1 Server-driven Negotiation
+
+ If the selection of the best representation for a response is made by
+ an algorithm located at the server, it is called server-driven
+ negotiation. Selection is based on the available representations of
+ the response (the dimensions over which it can vary; e.g. language,
+ content-coding, etc.) and the contents of particular header fields in
+ the request message or on other information pertaining to the request
+ (such as the network address of the client).
+
+ Server-driven negotiation is advantageous when the algorithm for
+ selecting from among the available representations is difficult to
+ describe to the user agent, or when the server desires to send its
+ "best guess" to the client along with the first response (hoping to
+ avoid the round-trip delay of a subsequent request if the "best
+ guess" is good enough for the user). In order to improve the server's
+ guess, the user agent MAY include request header fields (Accept,
+ Accept-Language, Accept-Encoding, etc.) which describe its
+ preferences for such a response.
+
+ Server-driven negotiation has disadvantages:
+
+ 1. It is impossible for the server to accurately determine what
+ might be "best" for any given user, since that would require
+ complete knowledge of both the capabilities of the user agent
+ and the intended use for the response (e.g., does the user want
+ to view it on screen or print it on paper?).
+
+ 2. Having the user agent describe its capabilities in every
+ request can be both very inefficient (given that only a small
+ percentage of responses have multiple representations) and a
+ potential violation of the user's privacy.
+
+ 3. It complicates the implementation of an origin server and the
+ algorithms for generating responses to a request.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 72]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 4. It may limit a public cache's ability to use the same response
+ for multiple user's requests.
+
+ HTTP/1.1 includes the following request-header fields for enabling
+ server-driven negotiation through description of user agent
+ capabilities and user preferences: Accept (section 14.1), Accept-
+ Charset (section 14.2), Accept-Encoding (section 14.3), Accept-
+ Language (section 14.4), and User-Agent (section 14.43). However, an
+ origin server is not limited to these dimensions and MAY vary the
+ response based on any aspect of the request, including information
+ outside the request-header fields or within extension header fields
+ not defined by this specification.
+
+ The Vary header field can be used to express the parameters the
+ server uses to select a representation that is subject to server-
+ driven negotiation. See section 13.6 for use of the Vary header field
+ by caches and section 14.44 for use of the Vary header field by
+ servers.
+
+12.2 Agent-driven Negotiation
+
+ With agent-driven negotiation, selection of the best representation
+ for a response is performed by the user agent after receiving an
+ initial response from the origin server. Selection is based on a list
+ of the available representations of the response included within the
+ header fields or entity-body of the initial response, with each
+ representation identified by its own URI. Selection from among the
+ representations may be performed automatically (if the user agent is
+ capable of doing so) or manually by the user selecting from a
+ generated (possibly hypertext) menu.
+
+ Agent-driven negotiation is advantageous when the response would vary
+ over commonly-used dimensions (such as type, language, or encoding),
+ when the origin server is unable to determine a user agent's
+ capabilities from examining the request, and generally when public
+ caches are used to distribute server load and reduce network usage.
+
+ Agent-driven negotiation suffers from the disadvantage of needing a
+ second request to obtain the best alternate representation. This
+ second request is only efficient when caching is used. In addition,
+ this specification does not define any mechanism for supporting
+ automatic selection, though it also does not prevent any such
+ mechanism from being developed as an extension and used within
+ HTTP/1.1.
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 73]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ HTTP/1.1 defines the 300 (Multiple Choices) and 406 (Not Acceptable)
+ status codes for enabling agent-driven negotiation when the server is
+ unwilling or unable to provide a varying response using server-driven
+ negotiation.
+
+12.3 Transparent Negotiation
+
+ Transparent negotiation is a combination of both server-driven and
+ agent-driven negotiation. When a cache is supplied with a form of the
+ list of available representations of the response (as in agent-driven
+ negotiation) and the dimensions of variance are completely understood
+ by the cache, then the cache becomes capable of performing server-
+ driven negotiation on behalf of the origin server for subsequent
+ requests on that resource.
+
+ Transparent negotiation has the advantage of distributing the
+ negotiation work that would otherwise be required of the origin
+ server and also removing the second request delay of agent-driven
+ negotiation when the cache is able to correctly guess the right
+ response.
+
+ This specification does not define any mechanism for transparent
+ negotiation, though it also does not prevent any such mechanism from
+ being developed as an extension that could be used within HTTP/1.1.
+
+13 Caching in HTTP
+
+ HTTP is typically used for distributed information systems, where
+ performance can be improved by the use of response caches. The
+ HTTP/1.1 protocol includes a number of elements intended to make
+ caching work as well as possible. Because these elements are
+ inextricable from other aspects of the protocol, and because they
+ interact with each other, it is useful to describe the basic caching
+ design of HTTP separately from the detailed descriptions of methods,
+ headers, response codes, etc.
+
+ Caching would be useless if it did not significantly improve
+ performance. The goal of caching in HTTP/1.1 is to eliminate the need
+ to send requests in many cases, and to eliminate the need to send
+ full responses in many other cases. The former reduces the number of
+ network round-trips required for many operations; we use an
+ "expiration" mechanism for this purpose (see section 13.2). The
+ latter reduces network bandwidth requirements; we use a "validation"
+ mechanism for this purpose (see section 13.3).
+
+ Requirements for performance, availability, and disconnected
+ operation require us to be able to relax the goal of semantic
+ transparency. The HTTP/1.1 protocol allows origin servers, caches,
+
+
+
+Fielding, et al. Standards Track [Page 74]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ and clients to explicitly reduce transparency when necessary.
+ However, because non-transparent operation may confuse non-expert
+ users, and might be incompatible with certain server applications
+ (such as those for ordering merchandise), the protocol requires that
+ transparency be relaxed
+
+ - only by an explicit protocol-level request when relaxed by
+ client or origin server
+
+ - only with an explicit warning to the end user when relaxed by
+ cache or client
+
+ Therefore, the HTTP/1.1 protocol provides these important elements:
+
+ 1. Protocol features that provide full semantic transparency when
+ this is required by all parties.
+
+ 2. Protocol features that allow an origin server or user agent to
+ explicitly request and control non-transparent operation.
+
+ 3. Protocol features that allow a cache to attach warnings to
+ responses that do not preserve the requested approximation of
+ semantic transparency.
+
+ A basic principle is that it must be possible for the clients to
+ detect any potential relaxation of semantic transparency.
+
+ Note: The server, cache, or client implementor might be faced with
+ design decisions not explicitly discussed in this specification.
+ If a decision might affect semantic transparency, the implementor
+ ought to err on the side of maintaining transparency unless a
+ careful and complete analysis shows significant benefits in
+ breaking transparency.
+
+13.1.1 Cache Correctness
+
+ A correct cache MUST respond to a request with the most up-to-date
+ response held by the cache that is appropriate to the request (see
+ sections 13.2.5, 13.2.6, and 13.12) which meets one of the following
+ conditions:
+
+ 1. It has been checked for equivalence with what the origin server
+ would have returned by revalidating the response with the
+ origin server (section 13.3);
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 75]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 2. It is "fresh enough" (see section 13.2). In the default case,
+ this means it meets the least restrictive freshness requirement
+ of the client, origin server, and cache (see section 14.9); if
+ the origin server so specifies, it is the freshness requirement
+ of the origin server alone.
+
+ If a stored response is not "fresh enough" by the most
+ restrictive freshness requirement of both the client and the
+ origin server, in carefully considered circumstances the cache
+ MAY still return the response with the appropriate Warning
+ header (see section 13.1.5 and 14.46), unless such a response
+ is prohibited (e.g., by a "no-store" cache-directive, or by a
+ "no-cache" cache-request-directive; see section 14.9).
+
+ 3. It is an appropriate 304 (Not Modified), 305 (Proxy Redirect),
+ or error (4xx or 5xx) response message.
+
+ If the cache can not communicate with the origin server, then a
+ correct cache SHOULD respond as above if the response can be
+ correctly served from the cache; if not it MUST return an error or
+ warning indicating that there was a communication failure.
+
+ If a cache receives a response (either an entire response, or a 304
+ (Not Modified) response) that it would normally forward to the
+ requesting client, and the received response is no longer fresh, the
+ cache SHOULD forward it to the requesting client without adding a new
+ Warning (but without removing any existing Warning headers). A cache
+ SHOULD NOT attempt to revalidate a response simply because that
+ response became stale in transit; this might lead to an infinite
+ loop. A user agent that receives a stale response without a Warning
+ MAY display a warning indication to the user.
+
+13.1.2 Warnings
+
+ Whenever a cache returns a response that is neither first-hand nor
+ "fresh enough" (in the sense of condition 2 in section 13.1.1), it
+ MUST attach a warning to that effect, using a Warning general-header.
+ The Warning header and the currently defined warnings are described
+ in section 14.46. The warning allows clients to take appropriate
+ action.
+
+ Warnings MAY be used for other purposes, both cache-related and
+ otherwise. The use of a warning, rather than an error status code,
+ distinguish these responses from true failures.
+
+ Warnings are assigned three digit warn-codes. The first digit
+ indicates whether the Warning MUST or MUST NOT be deleted from a
+ stored cache entry after a successful revalidation:
+
+
+
+Fielding, et al. Standards Track [Page 76]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 1xx Warnings that describe the freshness or revalidation status of
+ the response, and so MUST be deleted after a successful
+ revalidation. 1XX warn-codes MAY be generated by a cache only when
+ validating a cached entry. It MUST NOT be generated by clients.
+
+ 2xx Warnings that describe some aspect of the entity body or entity
+ headers that is not rectified by a revalidation (for example, a
+ lossy compression of the entity bodies) and which MUST NOT be
+ deleted after a successful revalidation.
+
+ See section 14.46 for the definitions of the codes themselves.
+
+ HTTP/1.0 caches will cache all Warnings in responses, without
+ deleting the ones in the first category. Warnings in responses that
+ are passed to HTTP/1.0 caches carry an extra warning-date field,
+ which prevents a future HTTP/1.1 recipient from believing an
+ erroneously cached Warning.
+
+ Warnings also carry a warning text. The text MAY be in any
+ appropriate natural language (perhaps based on the client's Accept
+ headers), and include an OPTIONAL indication of what character set is
+ used.
+
+ Multiple warnings MAY be attached to a response (either by the origin
+ server or by a cache), including multiple warnings with the same code
+ number. For example, a server might provide the same warning with
+ texts in both English and Basque.
+
+ When multiple warnings are attached to a response, it might not be
+ practical or reasonable to display all of them to the user. This
+ version of HTTP does not specify strict priority rules for deciding
+ which warnings to display and in what order, but does suggest some
+ heuristics.
+
+13.1.3 Cache-control Mechanisms
+
+ The basic cache mechanisms in HTTP/1.1 (server-specified expiration
+ times and validators) are implicit directives to caches. In some
+ cases, a server or client might need to provide explicit directives
+ to the HTTP caches. We use the Cache-Control header for this purpose.
+
+ The Cache-Control header allows a client or server to transmit a
+ variety of directives in either requests or responses. These
+ directives typically override the default caching algorithms. As a
+ general rule, if there is any apparent conflict between header
+ values, the most restrictive interpretation is applied (that is, the
+ one that is most likely to preserve semantic transparency). However,
+
+
+
+
+Fielding, et al. Standards Track [Page 77]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ in some cases, cache-control directives are explicitly specified as
+ weakening the approximation of semantic transparency (for example,
+ "max-stale" or "public").
+
+ The cache-control directives are described in detail in section 14.9.
+
+13.1.4 Explicit User Agent Warnings
+
+ Many user agents make it possible for users to override the basic
+ caching mechanisms. For example, the user agent might allow the user
+ to specify that cached entities (even explicitly stale ones) are
+ never validated. Or the user agent might habitually add "Cache-
+ Control: max-stale=3600" to every request. The user agent SHOULD NOT
+ default to either non-transparent behavior, or behavior that results
+ in abnormally ineffective caching, but MAY be explicitly configured
+ to do so by an explicit action of the user.
+
+ If the user has overridden the basic caching mechanisms, the user
+ agent SHOULD explicitly indicate to the user whenever this results in
+ the display of information that might not meet the server's
+ transparency requirements (in particular, if the displayed entity is
+ known to be stale). Since the protocol normally allows the user agent
+ to determine if responses are stale or not, this indication need only
+ be displayed when this actually happens. The indication need not be a
+ dialog box; it could be an icon (for example, a picture of a rotting
+ fish) or some other indicator.
+
+ If the user has overridden the caching mechanisms in a way that would
+ abnormally reduce the effectiveness of caches, the user agent SHOULD
+ continually indicate this state to the user (for example, by a
+ display of a picture of currency in flames) so that the user does not
+ inadvertently consume excess resources or suffer from excessive
+ latency.
+
+13.1.5 Exceptions to the Rules and Warnings
+
+ In some cases, the operator of a cache MAY choose to configure it to
+ return stale responses even when not requested by clients. This
+ decision ought not be made lightly, but may be necessary for reasons
+ of availability or performance, especially when the cache is poorly
+ connected to the origin server. Whenever a cache returns a stale
+ response, it MUST mark it as such (using a Warning header) enabling
+ the client software to alert the user that there might be a potential
+ problem.
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 78]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ It also allows the user agent to take steps to obtain a first-hand or
+ fresh response. For this reason, a cache SHOULD NOT return a stale
+ response if the client explicitly requests a first-hand or fresh one,
+ unless it is impossible to comply for technical or policy reasons.
+
+13.1.6 Client-controlled Behavior
+
+ While the origin server (and to a lesser extent, intermediate caches,
+ by their contribution to the age of a response) are the primary
+ source of expiration information, in some cases the client might need
+ to control a cache's decision about whether to return a cached
+ response without validating it. Clients do this using several
+ directives of the Cache-Control header.
+
+ A client's request MAY specify the maximum age it is willing to
+ accept of an unvalidated response; specifying a value of zero forces
+ the cache(s) to revalidate all responses. A client MAY also specify
+ the minimum time remaining before a response expires. Both of these
+ options increase constraints on the behavior of caches, and so cannot
+ further relax the cache's approximation of semantic transparency.
+
+ A client MAY also specify that it will accept stale responses, up to
+ some maximum amount of staleness. This loosens the constraints on the
+ caches, and so might violate the origin server's specified
+ constraints on semantic transparency, but might be necessary to
+ support disconnected operation, or high availability in the face of
+ poor connectivity.
+
+13.2 Expiration Model
+
+13.2.1 Server-Specified Expiration
+
+ HTTP caching works best when caches can entirely avoid making
+ requests to the origin server. The primary mechanism for avoiding
+ requests is for an origin server to provide an explicit expiration
+ time in the future, indicating that a response MAY be used to satisfy
+ subsequent requests. In other words, a cache can return a fresh
+ response without first contacting the server.
+
+ Our expectation is that servers will assign future explicit
+ expiration times to responses in the belief that the entity is not
+ likely to change, in a semantically significant way, before the
+ expiration time is reached. This normally preserves semantic
+ transparency, as long as the server's expiration times are carefully
+ chosen.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 79]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The expiration mechanism applies only to responses taken from a cache
+ and not to first-hand responses forwarded immediately to the
+ requesting client.
+
+ If an origin server wishes to force a semantically transparent cache
+ to validate every request, it MAY assign an explicit expiration time
+ in the past. This means that the response is always stale, and so the
+ cache SHOULD validate it before using it for subsequent requests. See
+ section 14.9.4 for a more restrictive way to force revalidation.
+
+ If an origin server wishes to force any HTTP/1.1 cache, no matter how
+ it is configured, to validate every request, it SHOULD use the "must-
+ revalidate" cache-control directive (see section 14.9).
+
+ Servers specify explicit expiration times using either the Expires
+ header, or the max-age directive of the Cache-Control header.
+
+ An expiration time cannot be used to force a user agent to refresh
+ its display or reload a resource; its semantics apply only to caching
+ mechanisms, and such mechanisms need only check a resource's
+ expiration status when a new request for that resource is initiated.
+ See section 13.13 for an explanation of the difference between caches
+ and history mechanisms.
+
+13.2.2 Heuristic Expiration
+
+ Since origin servers do not always provide explicit expiration times,
+ HTTP caches typically assign heuristic expiration times, employing
+ algorithms that use other header values (such as the Last-Modified
+ time) to estimate a plausible expiration time. The HTTP/1.1
+ specification does not provide specific algorithms, but does impose
+ worst-case constraints on their results. Since heuristic expiration
+ times might compromise semantic transparency, they ought to used
+ cautiously, and we encourage origin servers to provide explicit
+ expiration times as much as possible.
+
+13.2.3 Age Calculations
+
+ In order to know if a cached entry is fresh, a cache needs to know if
+ its age exceeds its freshness lifetime. We discuss how to calculate
+ the latter in section 13.2.4; this section describes how to calculate
+ the age of a response or cache entry.
+
+ In this discussion, we use the term "now" to mean "the current value
+ of the clock at the host performing the calculation." Hosts that use
+ HTTP, but especially hosts running origin servers and caches, SHOULD
+ use NTP [28] or some similar protocol to synchronize their clocks to
+ a globally accurate time standard.
+
+
+
+Fielding, et al. Standards Track [Page 80]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ HTTP/1.1 requires origin servers to send a Date header, if possible,
+ with every response, giving the time at which the response was
+ generated (see section 14.18). We use the term "date_value" to denote
+ the value of the Date header, in a form appropriate for arithmetic
+ operations.
+
+ HTTP/1.1 uses the Age response-header to convey the estimated age of
+ the response message when obtained from a cache. The Age field value
+ is the cache's estimate of the amount of time since the response was
+ generated or revalidated by the origin server.
+
+ In essence, the Age value is the sum of the time that the response
+ has been resident in each of the caches along the path from the
+ origin server, plus the amount of time it has been in transit along
+ network paths.
+
+ We use the term "age_value" to denote the value of the Age header, in
+ a form appropriate for arithmetic operations.
+
+ A response's age can be calculated in two entirely independent ways:
+
+ 1. now minus date_value, if the local clock is reasonably well
+ synchronized to the origin server's clock. If the result is
+ negative, the result is replaced by zero.
+
+ 2. age_value, if all of the caches along the response path
+ implement HTTP/1.1.
+
+ Given that we have two independent ways to compute the age of a
+ response when it is received, we can combine these as
+
+ corrected_received_age = max(now - date_value, age_value)
+
+ and as long as we have either nearly synchronized clocks or all-
+ HTTP/1.1 paths, one gets a reliable (conservative) result.
+
+ Because of network-imposed delays, some significant interval might
+ pass between the time that a server generates a response and the time
+ it is received at the next outbound cache or client. If uncorrected,
+ this delay could result in improperly low ages.
+
+ Because the request that resulted in the returned Age value must have
+ been initiated prior to that Age value's generation, we can correct
+ for delays imposed by the network by recording the time at which the
+ request was initiated. Then, when an Age value is received, it MUST
+ be interpreted relative to the time the request was initiated, not
+
+
+
+
+
+Fielding, et al. Standards Track [Page 81]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ the time that the response was received. This algorithm results in
+ conservative behavior no matter how much delay is experienced. So, we
+ compute:
+
+ corrected_initial_age = corrected_received_age
+ + (now - request_time)
+
+ where "request_time" is the time (according to the local clock) when
+ the request that elicited this response was sent.
+
+ Summary of age calculation algorithm, when a cache receives a
+ response:
+
+ /*
+ * age_value
+ * is the value of Age: header received by the cache with
+ * this response.
+ * date_value
+ * is the value of the origin server's Date: header
+ * request_time
+ * is the (local) time when the cache made the request
+ * that resulted in this cached response
+ * response_time
+ * is the (local) time when the cache received the
+ * response
+ * now
+ * is the current (local) time
+ */
+
+ apparent_age = max(0, response_time - date_value);
+ corrected_received_age = max(apparent_age, age_value);
+ response_delay = response_time - request_time;
+ corrected_initial_age = corrected_received_age + response_delay;
+ resident_time = now - response_time;
+ current_age = corrected_initial_age + resident_time;
+
+ The current_age of a cache entry is calculated by adding the amount
+ of time (in seconds) since the cache entry was last validated by the
+ origin server to the corrected_initial_age. When a response is
+ generated from a cache entry, the cache MUST include a single Age
+ header field in the response with a value equal to the cache entry's
+ current_age.
+
+ The presence of an Age header field in a response implies that a
+ response is not first-hand. However, the converse is not true, since
+ the lack of an Age header field in a response does not imply that the
+
+
+
+
+
+Fielding, et al. Standards Track [Page 82]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ response is first-hand unless all caches along the request path are
+ compliant with HTTP/1.1 (i.e., older HTTP caches did not implement
+ the Age header field).
+
+13.2.4 Expiration Calculations
+
+ In order to decide whether a response is fresh or stale, we need to
+ compare its freshness lifetime to its age. The age is calculated as
+ described in section 13.2.3; this section describes how to calculate
+ the freshness lifetime, and to determine if a response has expired.
+ In the discussion below, the values can be represented in any form
+ appropriate for arithmetic operations.
+
+ We use the term "expires_value" to denote the value of the Expires
+ header. We use the term "max_age_value" to denote an appropriate
+ value of the number of seconds carried by the "max-age" directive of
+ the Cache-Control header in a response (see section 14.9.3).
+
+ The max-age directive takes priority over Expires, so if max-age is
+ present in a response, the calculation is simply:
+
+ freshness_lifetime = max_age_value
+
+ Otherwise, if Expires is present in the response, the calculation is:
+
+ freshness_lifetime = expires_value - date_value
+
+ Note that neither of these calculations is vulnerable to clock skew,
+ since all of the information comes from the origin server.
+
+ If none of Expires, Cache-Control: max-age, or Cache-Control: s-
+ maxage (see section 14.9.3) appears in the response, and the response
+ does not include other restrictions on caching, the cache MAY compute
+ a freshness lifetime using a heuristic. The cache MUST attach Warning
+ 113 to any response whose age is more than 24 hours if such warning
+ has not already been added.
+
+ Also, if the response does have a Last-Modified time, the heuristic
+ expiration value SHOULD be no more than some fraction of the interval
+ since that time. A typical setting of this fraction might be 10%.
+
+ The calculation to determine if a response has expired is quite
+ simple:
+
+ response_is_fresh = (freshness_lifetime > current_age)
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 83]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+13.2.5 Disambiguating Expiration Values
+
+ Because expiration values are assigned optimistically, it is possible
+ for two caches to contain fresh values for the same resource that are
+ different.
+
+ If a client performing a retrieval receives a non-first-hand response
+ for a request that was already fresh in its own cache, and the Date
+ header in its existing cache entry is newer than the Date on the new
+ response, then the client MAY ignore the response. If so, it MAY
+ retry the request with a "Cache-Control: max-age=0" directive (see
+ section 14.9), to force a check with the origin server.
+
+ If a cache has two fresh responses for the same representation with
+ different validators, it MUST use the one with the more recent Date
+ header. This situation might arise because the cache is pooling
+ responses from other caches, or because a client has asked for a
+ reload or a revalidation of an apparently fresh cache entry.
+
+13.2.6 Disambiguating Multiple Responses
+
+ Because a client might be receiving responses via multiple paths, so
+ that some responses flow through one set of caches and other
+ responses flow through a different set of caches, a client might
+ receive responses in an order different from that in which the origin
+ server sent them. We would like the client to use the most recently
+ generated response, even if older responses are still apparently
+ fresh.
+
+ Neither the entity tag nor the expiration value can impose an
+ ordering on responses, since it is possible that a later response
+ intentionally carries an earlier expiration time. The Date values are
+ ordered to a granularity of one second.
+
+ When a client tries to revalidate a cache entry, and the response it
+ receives contains a Date header that appears to be older than the one
+ for the existing entry, then the client SHOULD repeat the request
+ unconditionally, and include
+
+ Cache-Control: max-age=0
+
+ to force any intermediate caches to validate their copies directly
+ with the origin server, or
+
+ Cache-Control: no-cache
+
+ to force any intermediate caches to obtain a new copy from the origin
+ server.
+
+
+
+Fielding, et al. Standards Track [Page 84]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If the Date values are equal, then the client MAY use either response
+ (or MAY, if it is being extremely prudent, request a new response).
+ Servers MUST NOT depend on clients being able to choose
+ deterministically between responses generated during the same second,
+ if their expiration times overlap.
+
+13.3 Validation Model
+
+ When a cache has a stale entry that it would like to use as a
+ response to a client's request, it first has to check with the origin
+ server (or possibly an intermediate cache with a fresh response) to
+ see if its cached entry is still usable. We call this "validating"
+ the cache entry. Since we do not want to have to pay the overhead of
+ retransmitting the full response if the cached entry is good, and we
+ do not want to pay the overhead of an extra round trip if the cached
+ entry is invalid, the HTTP/1.1 protocol supports the use of
+ conditional methods.
+
+ The key protocol features for supporting conditional methods are
+ those concerned with "cache validators." When an origin server
+ generates a full response, it attaches some sort of validator to it,
+ which is kept with the cache entry. When a client (user agent or
+ proxy cache) makes a conditional request for a resource for which it
+ has a cache entry, it includes the associated validator in the
+ request.
+
+ The server then checks that validator against the current validator
+ for the entity, and, if they match (see section 13.3.3), it responds
+ with a special status code (usually, 304 (Not Modified)) and no
+ entity-body. Otherwise, it returns a full response (including
+ entity-body). Thus, we avoid transmitting the full response if the
+ validator matches, and we avoid an extra round trip if it does not
+ match.
+
+ In HTTP/1.1, a conditional request looks exactly the same as a normal
+ request for the same resource, except that it carries a special
+ header (which includes the validator) that implicitly turns the
+ method (usually, GET) into a conditional.
+
+ The protocol includes both positive and negative senses of cache-
+ validating conditions. That is, it is possible to request either that
+ a method be performed if and only if a validator matches or if and
+ only if no validators match.
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 85]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Note: a response that lacks a validator may still be cached, and
+ served from cache until it expires, unless this is explicitly
+ prohibited by a cache-control directive. However, a cache cannot
+ do a conditional retrieval if it does not have a validator for the
+ entity, which means it will not be refreshable after it expires.
+
+13.3.1 Last-Modified Dates
+
+ The Last-Modified entity-header field value is often used as a cache
+ validator. In simple terms, a cache entry is considered to be valid
+ if the entity has not been modified since the Last-Modified value.
+
+13.3.2 Entity Tag Cache Validators
+
+ The ETag response-header field value, an entity tag, provides for an
+ "opaque" cache validator. This might allow more reliable validation
+ in situations where it is inconvenient to store modification dates,
+ where the one-second resolution of HTTP date values is not
+ sufficient, or where the origin server wishes to avoid certain
+ paradoxes that might arise from the use of modification dates.
+
+ Entity Tags are described in section 3.11. The headers used with
+ entity tags are described in sections 14.19, 14.24, 14.26 and 14.44.
+
+13.3.3 Weak and Strong Validators
+
+ Since both origin servers and caches will compare two validators to
+ decide if they represent the same or different entities, one normally
+ would expect that if the entity (the entity-body or any entity-
+ headers) changes in any way, then the associated validator would
+ change as well. If this is true, then we call this validator a
+ "strong validator."
+
+ However, there might be cases when a server prefers to change the
+ validator only on semantically significant changes, and not when
+ insignificant aspects of the entity change. A validator that does not
+ always change when the resource changes is a "weak validator."
+
+ Entity tags are normally "strong validators," but the protocol
+ provides a mechanism to tag an entity tag as "weak." One can think of
+ a strong validator as one that changes whenever the bits of an entity
+ changes, while a weak value changes whenever the meaning of an entity
+ changes. Alternatively, one can think of a strong validator as part
+ of an identifier for a specific entity, while a weak validator is
+ part of an identifier for a set of semantically equivalent entities.
+
+ Note: One example of a strong validator is an integer that is
+ incremented in stable storage every time an entity is changed.
+
+
+
+Fielding, et al. Standards Track [Page 86]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ An entity's modification time, if represented with one-second
+ resolution, could be a weak validator, since it is possible that
+ the resource might be modified twice during a single second.
+
+ Support for weak validators is optional. However, weak validators
+ allow for more efficient caching of equivalent objects; for
+ example, a hit counter on a site is probably good enough if it is
+ updated every few days or weeks, and any value during that period
+ is likely "good enough" to be equivalent.
+
+ A "use" of a validator is either when a client generates a request
+ and includes the validator in a validating header field, or when a
+ server compares two validators.
+
+ Strong validators are usable in any context. Weak validators are only
+ usable in contexts that do not depend on exact equality of an entity.
+ For example, either kind is usable for a conditional GET of a full
+ entity. However, only a strong validator is usable for a sub-range
+ retrieval, since otherwise the client might end up with an internally
+ inconsistent entity.
+
+ Clients MAY issue simple (non-subrange) GET requests with either weak
+ validators or strong validators. Clients MUST NOT use weak validators
+ in other forms of request.
+
+ The only function that the HTTP/1.1 protocol defines on validators is
+ comparison. There are two validator comparison functions, depending
+ on whether the comparison context allows the use of weak validators
+ or not:
+
+ - The strong comparison function: in order to be considered equal,
+ both validators MUST be identical in every way, and both MUST
+ NOT be weak.
+
+ - The weak comparison function: in order to be considered equal,
+ both validators MUST be identical in every way, but either or
+ both of them MAY be tagged as "weak" without affecting the
+ result.
+
+ An entity tag is strong unless it is explicitly tagged as weak.
+ Section 3.11 gives the syntax for entity tags.
+
+ A Last-Modified time, when used as a validator in a request, is
+ implicitly weak unless it is possible to deduce that it is strong,
+ using the following rules:
+
+ - The validator is being compared by an origin server to the
+ actual current validator for the entity and,
+
+
+
+Fielding, et al. Standards Track [Page 87]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ - That origin server reliably knows that the associated entity did
+ not change twice during the second covered by the presented
+ validator.
+
+ or
+
+ - The validator is about to be used by a client in an If-
+ Modified-Since or If-Unmodified-Since header, because the client
+ has a cache entry for the associated entity, and
+
+ - That cache entry includes a Date value, which gives the time
+ when the origin server sent the original response, and
+
+ - The presented Last-Modified time is at least 60 seconds before
+ the Date value.
+
+ or
+
+ - The validator is being compared by an intermediate cache to the
+ validator stored in its cache entry for the entity, and
+
+ - That cache entry includes a Date value, which gives the time
+ when the origin server sent the original response, and
+
+ - The presented Last-Modified time is at least 60 seconds before
+ the Date value.
+
+ This method relies on the fact that if two different responses were
+ sent by the origin server during the same second, but both had the
+ same Last-Modified time, then at least one of those responses would
+ have a Date value equal to its Last-Modified time. The arbitrary 60-
+ second limit guards against the possibility that the Date and Last-
+ Modified values are generated from different clocks, or at somewhat
+ different times during the preparation of the response. An
+ implementation MAY use a value larger than 60 seconds, if it is
+ believed that 60 seconds is too short.
+
+ If a client wishes to perform a sub-range retrieval on a value for
+ which it has only a Last-Modified time and no opaque validator, it
+ MAY do this only if the Last-Modified time is strong in the sense
+ described here.
+
+ A cache or origin server receiving a conditional request, other than
+ a full-body GET request, MUST use the strong comparison function to
+ evaluate the condition.
+
+ These rules allow HTTP/1.1 caches and clients to safely perform sub-
+ range retrievals on values that have been obtained from HTTP/1.0
+
+
+
+Fielding, et al. Standards Track [Page 88]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ servers.
+
+13.3.4 Rules for When to Use Entity Tags and Last-Modified Dates
+
+ We adopt a set of rules and recommendations for origin servers,
+ clients, and caches regarding when various validator types ought to
+ be used, and for what purposes.
+
+ HTTP/1.1 origin servers:
+
+ - SHOULD send an entity tag validator unless it is not feasible to
+ generate one.
+
+ - MAY send a weak entity tag instead of a strong entity tag, if
+ performance considerations support the use of weak entity tags,
+ or if it is unfeasible to send a strong entity tag.
+
+ - SHOULD send a Last-Modified value if it is feasible to send one,
+ unless the risk of a breakdown in semantic transparency that
+ could result from using this date in an If-Modified-Since header
+ would lead to serious problems.
+
+ In other words, the preferred behavior for an HTTP/1.1 origin server
+ is to send both a strong entity tag and a Last-Modified value.
+
+ In order to be legal, a strong entity tag MUST change whenever the
+ associated entity value changes in any way. A weak entity tag SHOULD
+ change whenever the associated entity changes in a semantically
+ significant way.
+
+ Note: in order to provide semantically transparent caching, an
+ origin server must avoid reusing a specific strong entity tag
+ value for two different entities, or reusing a specific weak
+ entity tag value for two semantically different entities. Cache
+ entries might persist for arbitrarily long periods, regardless of
+ expiration times, so it might be inappropriate to expect that a
+ cache will never again attempt to validate an entry using a
+ validator that it obtained at some point in the past.
+
+ HTTP/1.1 clients:
+
+ - If an entity tag has been provided by the origin server, MUST
+ use that entity tag in any cache-conditional request (using If-
+ Match or If-None-Match).
+
+ - If only a Last-Modified value has been provided by the origin
+ server, SHOULD use that value in non-subrange cache-conditional
+ requests (using If-Modified-Since).
+
+
+
+Fielding, et al. Standards Track [Page 89]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ - If only a Last-Modified value has been provided by an HTTP/1.0
+ origin server, MAY use that value in subrange cache-conditional
+ requests (using If-Unmodified-Since:). The user agent SHOULD
+ provide a way to disable this, in case of difficulty.
+
+ - If both an entity tag and a Last-Modified value have been
+ provided by the origin server, SHOULD use both validators in
+ cache-conditional requests. This allows both HTTP/1.0 and
+ HTTP/1.1 caches to respond appropriately.
+
+ An HTTP/1.1 origin server, upon receiving a conditional request that
+ includes both a Last-Modified date (e.g., in an If-Modified-Since or
+ If-Unmodified-Since header field) and one or more entity tags (e.g.,
+ in an If-Match, If-None-Match, or If-Range header field) as cache
+ validators, MUST NOT return a response status of 304 (Not Modified)
+ unless doing so is consistent with all of the conditional header
+ fields in the request.
+
+ An HTTP/1.1 caching proxy, upon receiving a conditional request that
+ includes both a Last-Modified date and one or more entity tags as
+ cache validators, MUST NOT return a locally cached response to the
+ client unless that cached response is consistent with all of the
+ conditional header fields in the request.
+
+ Note: The general principle behind these rules is that HTTP/1.1
+ servers and clients should transmit as much non-redundant
+ information as is available in their responses and requests.
+ HTTP/1.1 systems receiving this information will make the most
+ conservative assumptions about the validators they receive.
+
+ HTTP/1.0 clients and caches will ignore entity tags. Generally,
+ last-modified values received or used by these systems will
+ support transparent and efficient caching, and so HTTP/1.1 origin
+ servers should provide Last-Modified values. In those rare cases
+ where the use of a Last-Modified value as a validator by an
+ HTTP/1.0 system could result in a serious problem, then HTTP/1.1
+ origin servers should not provide one.
+
+13.3.5 Non-validating Conditionals
+
+ The principle behind entity tags is that only the service author
+ knows the semantics of a resource well enough to select an
+ appropriate cache validation mechanism, and the specification of any
+ validator comparison function more complex than byte-equality would
+ open up a can of worms. Thus, comparisons of any other headers
+ (except Last-Modified, for compatibility with HTTP/1.0) are never
+ used for purposes of validating a cache entry.
+
+
+
+
+Fielding, et al. Standards Track [Page 90]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+13.4 Response Cacheability
+
+ Unless specifically constrained by a cache-control (section 14.9)
+ directive, a caching system MAY always store a successful response
+ (see section 13.8) as a cache entry, MAY return it without validation
+ if it is fresh, and MAY return it after successful validation. If
+ there is neither a cache validator nor an explicit expiration time
+ associated with a response, we do not expect it to be cached, but
+ certain caches MAY violate this expectation (for example, when little
+ or no network connectivity is available). A client can usually detect
+ that such a response was taken from a cache by comparing the Date
+ header to the current time.
+
+ Note: some HTTP/1.0 caches are known to violate this expectation
+ without providing any Warning.
+
+ However, in some cases it might be inappropriate for a cache to
+ retain an entity, or to return it in response to a subsequent
+ request. This might be because absolute semantic transparency is
+ deemed necessary by the service author, or because of security or
+ privacy considerations. Certain cache-control directives are
+ therefore provided so that the server can indicate that certain
+ resource entities, or portions thereof, are not to be cached
+ regardless of other considerations.
+
+ Note that section 14.8 normally prevents a shared cache from saving
+ and returning a response to a previous request if that request
+ included an Authorization header.
+
+ A response received with a status code of 200, 203, 206, 300, 301 or
+ 410 MAY be stored by a cache and used in reply to a subsequent
+ request, subject to the expiration mechanism, unless a cache-control
+ directive prohibits caching. However, a cache that does not support
+ the Range and Content-Range headers MUST NOT cache 206 (Partial
+ Content) responses.
+
+ A response received with any other status code (e.g. status codes 302
+ and 307) MUST NOT be returned in a reply to a subsequent request
+ unless there are cache-control directives or another header(s) that
+ explicitly allow it. For example, these include the following: an
+ Expires header (section 14.21); a "max-age", "s-maxage", "must-
+ revalidate", "proxy-revalidate", "public" or "private" cache-control
+ directive (section 14.9).
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 91]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+13.5 Constructing Responses From Caches
+
+ The purpose of an HTTP cache is to store information received in
+ response to requests for use in responding to future requests. In
+ many cases, a cache simply returns the appropriate parts of a
+ response to the requester. However, if the cache holds a cache entry
+ based on a previous response, it might have to combine parts of a new
+ response with what is held in the cache entry.
+
+13.5.1 End-to-end and Hop-by-hop Headers
+
+ For the purpose of defining the behavior of caches and non-caching
+ proxies, we divide HTTP headers into two categories:
+
+ - End-to-end headers, which are transmitted to the ultimate
+ recipient of a request or response. End-to-end headers in
+ responses MUST be stored as part of a cache entry and MUST be
+ transmitted in any response formed from a cache entry.
+
+ - Hop-by-hop headers, which are meaningful only for a single
+ transport-level connection, and are not stored by caches or
+ forwarded by proxies.
+
+ The following HTTP/1.1 headers are hop-by-hop headers:
+
+ - Connection
+ - Keep-Alive
+ - Proxy-Authenticate
+ - Proxy-Authorization
+ - TE
+ - Trailers
+ - Transfer-Encoding
+ - Upgrade
+
+ All other headers defined by HTTP/1.1 are end-to-end headers.
+
+ Other hop-by-hop headers MUST be listed in a Connection header,
+ (section 14.10) to be introduced into HTTP/1.1 (or later).
+
+13.5.2 Non-modifiable Headers
+
+ Some features of the HTTP/1.1 protocol, such as Digest
+ Authentication, depend on the value of certain end-to-end headers. A
+ transparent proxy SHOULD NOT modify an end-to-end header unless the
+ definition of that header requires or specifically allows that.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 92]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ A transparent proxy MUST NOT modify any of the following fields in a
+ request or response, and it MUST NOT add any of these fields if not
+ already present:
+
+ - Content-Location
+
+ - Content-MD5
+
+ - ETag
+
+ - Last-Modified
+
+ A transparent proxy MUST NOT modify any of the following fields in a
+ response:
+
+ - Expires
+
+ but it MAY add any of these fields if not already present. If an
+ Expires header is added, it MUST be given a field-value identical to
+ that of the Date header in that response.
+
+ A proxy MUST NOT modify or add any of the following fields in a
+ message that contains the no-transform cache-control directive, or in
+ any request:
+
+ - Content-Encoding
+
+ - Content-Range
+
+ - Content-Type
+
+ A non-transparent proxy MAY modify or add these fields to a message
+ that does not include no-transform, but if it does so, it MUST add a
+ Warning 214 (Transformation applied) if one does not already appear
+ in the message (see section 14.46).
+
+ Warning: unnecessary modification of end-to-end headers might
+ cause authentication failures if stronger authentication
+ mechanisms are introduced in later versions of HTTP. Such
+ authentication mechanisms MAY rely on the values of header fields
+ not listed here.
+
+ The Content-Length field of a request or response is added or deleted
+ according to the rules in section 4.4. A transparent proxy MUST
+ preserve the entity-length (section 7.2.2) of the entity-body,
+ although it MAY change the transfer-length (section 4.4).
+
+
+
+
+
+Fielding, et al. Standards Track [Page 93]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+13.5.3 Combining Headers
+
+ When a cache makes a validating request to a server, and the server
+ provides a 304 (Not Modified) response or a 206 (Partial Content)
+ response, the cache then constructs a response to send to the
+ requesting client.
+
+ If the status code is 304 (Not Modified), the cache uses the entity-
+ body stored in the cache entry as the entity-body of this outgoing
+ response. If the status code is 206 (Partial Content) and the ETag or
+ Last-Modified headers match exactly, the cache MAY combine the
+ contents stored in the cache entry with the new contents received in
+ the response and use the result as the entity-body of this outgoing
+ response, (see 13.5.4).
+
+ The end-to-end headers stored in the cache entry are used for the
+ constructed response, except that
+
+ - any stored Warning headers with warn-code 1xx (see section
+ 14.46) MUST be deleted from the cache entry and the forwarded
+ response.
+
+ - any stored Warning headers with warn-code 2xx MUST be retained
+ in the cache entry and the forwarded response.
+
+ - any end-to-end headers provided in the 304 or 206 response MUST
+ replace the corresponding headers from the cache entry.
+
+ Unless the cache decides to remove the cache entry, it MUST also
+ replace the end-to-end headers stored with the cache entry with
+ corresponding headers received in the incoming response, except for
+ Warning headers as described immediately above. If a header field-
+ name in the incoming response matches more than one header in the
+ cache entry, all such old headers MUST be replaced.
+
+ In other words, the set of end-to-end headers received in the
+ incoming response overrides all corresponding end-to-end headers
+ stored with the cache entry (except for stored Warning headers with
+ warn-code 1xx, which are deleted even if not overridden).
+
+ Note: this rule allows an origin server to use a 304 (Not
+ Modified) or a 206 (Partial Content) response to update any header
+ associated with a previous response for the same entity or sub-
+ ranges thereof, although it might not always be meaningful or
+ correct to do so. This rule does not allow an origin server to use
+ a 304 (Not Modified) or a 206 (Partial Content) response to
+ entirely delete a header that it had provided with a previous
+ response.
+
+
+
+Fielding, et al. Standards Track [Page 94]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+13.5.4 Combining Byte Ranges
+
+ A response might transfer only a subrange of the bytes of an entity-
+ body, either because the request included one or more Range
+ specifications, or because a connection was broken prematurely. After
+ several such transfers, a cache might have received several ranges of
+ the same entity-body.
+
+ If a cache has a stored non-empty set of subranges for an entity, and
+ an incoming response transfers another subrange, the cache MAY
+ combine the new subrange with the existing set if both the following
+ conditions are met:
+
+ - Both the incoming response and the cache entry have a cache
+ validator.
+
+ - The two cache validators match using the strong comparison
+ function (see section 13.3.3).
+
+ If either requirement is not met, the cache MUST use only the most
+ recent partial response (based on the Date values transmitted with
+ every response, and using the incoming response if these values are
+ equal or missing), and MUST discard the other partial information.
+
+13.6 Caching Negotiated Responses
+
+ Use of server-driven content negotiation (section 12.1), as indicated
+ by the presence of a Vary header field in a response, alters the
+ conditions and procedure by which a cache can use the response for
+ subsequent requests. See section 14.44 for use of the Vary header
+ field by servers.
+
+ A server SHOULD use the Vary header field to inform a cache of what
+ request-header fields were used to select among multiple
+ representations of a cacheable response subject to server-driven
+ negotiation. The set of header fields named by the Vary field value
+ is known as the "selecting" request-headers.
+
+ When the cache receives a subsequent request whose Request-URI
+ specifies one or more cache entries including a Vary header field,
+ the cache MUST NOT use such a cache entry to construct a response to
+ the new request unless all of the selecting request-headers present
+ in the new request match the corresponding stored request-headers in
+ the original request.
+
+ The selecting request-headers from two requests are defined to match
+ if and only if the selecting request-headers in the first request can
+ be transformed to the selecting request-headers in the second request
+
+
+
+Fielding, et al. Standards Track [Page 95]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ by adding or removing linear white space (LWS) at places where this
+ is allowed by the corresponding BNF, and/or combining multiple
+ message-header fields with the same field name following the rules
+ about message headers in section 4.2.
+
+ A Vary header field-value of "*" always fails to match and subsequent
+ requests on that resource can only be properly interpreted by the
+ origin server.
+
+ If the selecting request header fields for the cached entry do not
+ match the selecting request header fields of the new request, then
+ the cache MUST NOT use a cached entry to satisfy the request unless
+ it first relays the new request to the origin server in a conditional
+ request and the server responds with 304 (Not Modified), including an
+ entity tag or Content-Location that indicates the entity to be used.
+
+ If an entity tag was assigned to a cached representation, the
+ forwarded request SHOULD be conditional and include the entity tags
+ in an If-None-Match header field from all its cache entries for the
+ resource. This conveys to the server the set of entities currently
+ held by the cache, so that if any one of these entities matches the
+ requested entity, the server can use the ETag header field in its 304
+ (Not Modified) response to tell the cache which entry is appropriate.
+ If the entity-tag of the new response matches that of an existing
+ entry, the new response SHOULD be used to update the header fields of
+ the existing entry, and the result MUST be returned to the client.
+
+ If any of the existing cache entries contains only partial content
+ for the associated entity, its entity-tag SHOULD NOT be included in
+ the If-None-Match header field unless the request is for a range that
+ would be fully satisfied by that entry.
+
+ If a cache receives a successful response whose Content-Location
+ field matches that of an existing cache entry for the same Request-
+ ]URI, whose entity-tag differs from that of the existing entry, and
+ whose Date is more recent than that of the existing entry, the
+ existing entry SHOULD NOT be returned in response to future requests
+ and SHOULD be deleted from the cache.
+
+13.7 Shared and Non-Shared Caches
+
+ For reasons of security and privacy, it is necessary to make a
+ distinction between "shared" and "non-shared" caches. A non-shared
+ cache is one that is accessible only to a single user. Accessibility
+ in this case SHOULD be enforced by appropriate security mechanisms.
+ All other caches are considered to be "shared." Other sections of
+
+
+
+
+
+Fielding, et al. Standards Track [Page 96]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ this specification place certain constraints on the operation of
+ shared caches in order to prevent loss of privacy or failure of
+ access controls.
+
+13.8 Errors or Incomplete Response Cache Behavior
+
+ A cache that receives an incomplete response (for example, with fewer
+ bytes of data than specified in a Content-Length header) MAY store
+ the response. However, the cache MUST treat this as a partial
+ response. Partial responses MAY be combined as described in section
+ 13.5.4; the result might be a full response or might still be
+ partial. A cache MUST NOT return a partial response to a client
+ without explicitly marking it as such, using the 206 (Partial
+ Content) status code. A cache MUST NOT return a partial response
+ using a status code of 200 (OK).
+
+ If a cache receives a 5xx response while attempting to revalidate an
+ entry, it MAY either forward this response to the requesting client,
+ or act as if the server failed to respond. In the latter case, it MAY
+ return a previously received response unless the cached entry
+ includes the "must-revalidate" cache-control directive (see section
+ 14.9).
+
+13.9 Side Effects of GET and HEAD
+
+ Unless the origin server explicitly prohibits the caching of their
+ responses, the application of GET and HEAD methods to any resources
+ SHOULD NOT have side effects that would lead to erroneous behavior if
+ these responses are taken from a cache. They MAY still have side
+ effects, but a cache is not required to consider such side effects in
+ its caching decisions. Caches are always expected to observe an
+ origin server's explicit restrictions on caching.
+
+ We note one exception to this rule: since some applications have
+ traditionally used GETs and HEADs with query URLs (those containing a
+ "?" in the rel_path part) to perform operations with significant side
+ effects, caches MUST NOT treat responses to such URIs as fresh unless
+ the server provides an explicit expiration time. This specifically
+ means that responses from HTTP/1.0 servers for such URIs SHOULD NOT
+ be taken from a cache. See section 9.1.1 for related information.
+
+13.10 Invalidation After Updates or Deletions
+
+ The effect of certain methods performed on a resource at the origin
+ server might cause one or more existing cache entries to become non-
+ transparently invalid. That is, although they might continue to be
+ "fresh," they do not accurately reflect what the origin server would
+ return for a new request on that resource.
+
+
+
+Fielding, et al. Standards Track [Page 97]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ There is no way for the HTTP protocol to guarantee that all such
+ cache entries are marked invalid. For example, the request that
+ caused the change at the origin server might not have gone through
+ the proxy where a cache entry is stored. However, several rules help
+ reduce the likelihood of erroneous behavior.
+
+ In this section, the phrase "invalidate an entity" means that the
+ cache will either remove all instances of that entity from its
+ storage, or will mark these as "invalid" and in need of a mandatory
+ revalidation before they can be returned in response to a subsequent
+ request.
+
+ Some HTTP methods MUST cause a cache to invalidate an entity. This is
+ either the entity referred to by the Request-URI, or by the Location
+ or Content-Location headers (if present). These methods are:
+
+ - PUT
+
+ - DELETE
+
+ - POST
+
+ In order to prevent denial of service attacks, an invalidation based
+ on the URI in a Location or Content-Location header MUST only be
+ performed if the host part is the same as in the Request-URI.
+
+ A cache that passes through requests for methods it does not
+ understand SHOULD invalidate any entities referred to by the
+ Request-URI.
+
+13.11 Write-Through Mandatory
+
+ All methods that might be expected to cause modifications to the
+ origin server's resources MUST be written through to the origin
+ server. This currently includes all methods except for GET and HEAD.
+ A cache MUST NOT reply to such a request from a client before having
+ transmitted the request to the inbound server, and having received a
+ corresponding response from the inbound server. This does not prevent
+ a proxy cache from sending a 100 (Continue) response before the
+ inbound server has sent its final reply.
+
+ The alternative (known as "write-back" or "copy-back" caching) is not
+ allowed in HTTP/1.1, due to the difficulty of providing consistent
+ updates and the problems arising from server, cache, or network
+ failure prior to write-back.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 98]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+13.12 Cache Replacement
+
+ If a new cacheable (see sections 14.9.2, 13.2.5, 13.2.6 and 13.8)
+ response is received from a resource while any existing responses for
+ the same resource are cached, the cache SHOULD use the new response
+ to reply to the current request. It MAY insert it into cache storage
+ and MAY, if it meets all other requirements, use it to respond to any
+ future requests that would previously have caused the old response to
+ be returned. If it inserts the new response into cache storage the
+ rules in section 13.5.3 apply.
+
+ Note: a new response that has an older Date header value than
+ existing cached responses is not cacheable.
+
+13.13 History Lists
+
+ User agents often have history mechanisms, such as "Back" buttons and
+ history lists, which can be used to redisplay an entity retrieved
+ earlier in a session.
+
+ History mechanisms and caches are different. In particular history
+ mechanisms SHOULD NOT try to show a semantically transparent view of
+ the current state of a resource. Rather, a history mechanism is meant
+ to show exactly what the user saw at the time when the resource was
+ retrieved.
+
+ By default, an expiration time does not apply to history mechanisms.
+ If the entity is still in storage, a history mechanism SHOULD display
+ it even if the entity has expired, unless the user has specifically
+ configured the agent to refresh expired history documents.
+
+ This is not to be construed to prohibit the history mechanism from
+ telling the user that a view might be stale.
+
+ Note: if history list mechanisms unnecessarily prevent users from
+ viewing stale resources, this will tend to force service authors
+ to avoid using HTTP expiration controls and cache controls when
+ they would otherwise like to. Service authors may consider it
+ important that users not be presented with error messages or
+ warning messages when they use navigation controls (such as BACK)
+ to view previously fetched resources. Even though sometimes such
+ resources ought not to cached, or ought to expire quickly, user
+ interface considerations may force service authors to resort to
+ other means of preventing caching (e.g. "once-only" URLs) in order
+ not to suffer the effects of improperly functioning history
+ mechanisms.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 99]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14 Header Field Definitions
+
+ This section defines the syntax and semantics of all standard
+ HTTP/1.1 header fields. For entity-header fields, both sender and
+ recipient refer to either the client or the server, depending on who
+ sends and who receives the entity.
+
+14.1 Accept
+
+ The Accept request-header field can be used to specify certain media
+ types which are acceptable for the response. Accept headers can be
+ used to indicate that the request is specifically limited to a small
+ set of desired types, as in the case of a request for an in-line
+ image.
+
+ Accept = "Accept" ":"
+ #( media-range [ accept-params ] )
+
+ media-range = ( "*/*"
+ | ( type "/" "*" )
+ | ( type "/" subtype )
+ ) *( ";" parameter )
+ accept-params = ";" "q" "=" qvalue *( accept-extension )
+ accept-extension = ";" token [ "=" ( token | quoted-string ) ]
+
+ The asterisk "*" character is used to group media types into ranges,
+ with "*/*" indicating all media types and "type/*" indicating all
+ subtypes of that type. The media-range MAY include media type
+ parameters that are applicable to that range.
+
+ Each media-range MAY be followed by one or more accept-params,
+ beginning with the "q" parameter for indicating a relative quality
+ factor. The first "q" parameter (if any) separates the media-range
+ parameter(s) from the accept-params. Quality factors allow the user
+ or user agent to indicate the relative degree of preference for that
+ media-range, using the qvalue scale from 0 to 1 (section 3.9). The
+ default value is q=1.
+
+ Note: Use of the "q" parameter name to separate media type
+ parameters from Accept extension parameters is due to historical
+ practice. Although this prevents any media type parameter named
+ "q" from being used with a media range, such an event is believed
+ to be unlikely given the lack of any "q" parameters in the IANA
+ media type registry and the rare usage of any media type
+ parameters in Accept. Future media types are discouraged from
+ registering any parameter named "q".
+
+
+
+
+
+Fielding, et al. Standards Track [Page 100]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The example
+
+ Accept: audio/*; q=0.2, audio/basic
+
+ SHOULD be interpreted as "I prefer audio/basic, but send me any audio
+ type if it is the best available after an 80% mark-down in quality."
+
+ If no Accept header field is present, then it is assumed that the
+ client accepts all media types. If an Accept header field is present,
+ and if the server cannot send a response which is acceptable
+ according to the combined Accept field value, then the server SHOULD
+ send a 406 (not acceptable) response.
+
+ A more elaborate example is
+
+ Accept: text/plain; q=0.5, text/html,
+ text/x-dvi; q=0.8, text/x-c
+
+ Verbally, this would be interpreted as "text/html and text/x-c are
+ the preferred media types, but if they do not exist, then send the
+ text/x-dvi entity, and if that does not exist, send the text/plain
+ entity."
+
+ Media ranges can be overridden by more specific media ranges or
+ specific media types. If more than one media range applies to a given
+ type, the most specific reference has precedence. For example,
+
+ Accept: text/*, text/html, text/html;level=1, */*
+
+ have the following precedence:
+
+ 1) text/html;level=1
+ 2) text/html
+ 3) text/*
+ 4) */*
+
+ The media type quality factor associated with a given type is
+ determined by finding the media range with the highest precedence
+ which matches that type. For example,
+
+ Accept: text/*;q=0.3, text/html;q=0.7, text/html;level=1,
+ text/html;level=2;q=0.4, */*;q=0.5
+
+ would cause the following values to be associated:
+
+ text/html;level=1 = 1
+ text/html = 0.7
+ text/plain = 0.3
+
+
+
+Fielding, et al. Standards Track [Page 101]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ image/jpeg = 0.5
+ text/html;level=2 = 0.4
+ text/html;level=3 = 0.7
+
+ Note: A user agent might be provided with a default set of quality
+ values for certain media ranges. However, unless the user agent is
+ a closed system which cannot interact with other rendering agents,
+ this default set ought to be configurable by the user.
+
+14.2 Accept-Charset
+
+ The Accept-Charset request-header field can be used to indicate what
+ character sets are acceptable for the response. This field allows
+ clients capable of understanding more comprehensive or special-
+ purpose character sets to signal that capability to a server which is
+ capable of representing documents in those character sets.
+
+ Accept-Charset = "Accept-Charset" ":"
+ 1#( ( charset | "*" )[ ";" "q" "=" qvalue ] )
+
+
+ Character set values are described in section 3.4. Each charset MAY
+ be given an associated quality value which represents the user's
+ preference for that charset. The default value is q=1. An example is
+
+ Accept-Charset: iso-8859-5, unicode-1-1;q=0.8
+
+ The special value "*", if present in the Accept-Charset field,
+ matches every character set (including ISO-8859-1) which is not
+ mentioned elsewhere in the Accept-Charset field. If no "*" is present
+ in an Accept-Charset field, then all character sets not explicitly
+ mentioned get a quality value of 0, except for ISO-8859-1, which gets
+ a quality value of 1 if not explicitly mentioned.
+
+ If no Accept-Charset header is present, the default is that any
+ character set is acceptable. If an Accept-Charset header is present,
+ and if the server cannot send a response which is acceptable
+ according to the Accept-Charset header, then the server SHOULD send
+ an error response with the 406 (not acceptable) status code, though
+ the sending of an unacceptable response is also allowed.
+
+14.3 Accept-Encoding
+
+ The Accept-Encoding request-header field is similar to Accept, but
+ restricts the content-codings (section 3.5) that are acceptable in
+ the response.
+
+ Accept-Encoding = "Accept-Encoding" ":"
+
+
+
+Fielding, et al. Standards Track [Page 102]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 1#( codings [ ";" "q" "=" qvalue ] )
+ codings = ( content-coding | "*" )
+
+ Examples of its use are:
+
+ Accept-Encoding: compress, gzip
+ Accept-Encoding:
+ Accept-Encoding: *
+ Accept-Encoding: compress;q=0.5, gzip;q=1.0
+ Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0
+
+ A server tests whether a content-coding is acceptable, according to
+ an Accept-Encoding field, using these rules:
+
+ 1. If the content-coding is one of the content-codings listed in
+ the Accept-Encoding field, then it is acceptable, unless it is
+ accompanied by a qvalue of 0. (As defined in section 3.9, a
+ qvalue of 0 means "not acceptable.")
+
+ 2. The special "*" symbol in an Accept-Encoding field matches any
+ available content-coding not explicitly listed in the header
+ field.
+
+ 3. If multiple content-codings are acceptable, then the acceptable
+ content-coding with the highest non-zero qvalue is preferred.
+
+ 4. The "identity" content-coding is always acceptable, unless
+ specifically refused because the Accept-Encoding field includes
+ "identity;q=0", or because the field includes "*;q=0" and does
+ not explicitly include the "identity" content-coding. If the
+ Accept-Encoding field-value is empty, then only the "identity"
+ encoding is acceptable.
+
+ If an Accept-Encoding field is present in a request, and if the
+ server cannot send a response which is acceptable according to the
+ Accept-Encoding header, then the server SHOULD send an error response
+ with the 406 (Not Acceptable) status code.
+
+ If no Accept-Encoding field is present in a request, the server MAY
+ assume that the client will accept any content coding. In this case,
+ if "identity" is one of the available content-codings, then the
+ server SHOULD use the "identity" content-coding, unless it has
+ additional information that a different content-coding is meaningful
+ to the client.
+
+ Note: If the request does not include an Accept-Encoding field,
+ and if the "identity" content-coding is unavailable, then
+ content-codings commonly understood by HTTP/1.0 clients (i.e.,
+
+
+
+Fielding, et al. Standards Track [Page 103]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ "gzip" and "compress") are preferred; some older clients
+ improperly display messages sent with other content-codings. The
+ server might also make this decision based on information about
+ the particular user-agent or client.
+
+ Note: Most HTTP/1.0 applications do not recognize or obey qvalues
+ associated with content-codings. This means that qvalues will not
+ work and are not permitted with x-gzip or x-compress.
+
+14.4 Accept-Language
+
+ The Accept-Language request-header field is similar to Accept, but
+ restricts the set of natural languages that are preferred as a
+ response to the request. Language tags are defined in section 3.10.
+
+ Accept-Language = "Accept-Language" ":"
+ 1#( language-range [ ";" "q" "=" qvalue ] )
+ language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
+
+ Each language-range MAY be given an associated quality value which
+ represents an estimate of the user's preference for the languages
+ specified by that range. The quality value defaults to "q=1". For
+ example,
+
+ Accept-Language: da, en-gb;q=0.8, en;q=0.7
+
+ would mean: "I prefer Danish, but will accept British English and
+ other types of English." A language-range matches a language-tag if
+ it exactly equals the tag, or if it exactly equals a prefix of the
+ tag such that the first tag character following the prefix is "-".
+ The special range "*", if present in the Accept-Language field,
+ matches every tag not matched by any other range present in the
+ Accept-Language field.
+
+ Note: This use of a prefix matching rule does not imply that
+ language tags are assigned to languages in such a way that it is
+ always true that if a user understands a language with a certain
+ tag, then this user will also understand all languages with tags
+ for which this tag is a prefix. The prefix rule simply allows the
+ use of prefix tags if this is the case.
+
+ The language quality factor assigned to a language-tag by the
+ Accept-Language field is the quality value of the longest language-
+ range in the field that matches the language-tag. If no language-
+ range in the field matches the tag, the language quality factor
+ assigned is 0. If no Accept-Language header is present in the
+ request, the server
+
+
+
+
+Fielding, et al. Standards Track [Page 104]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ SHOULD assume that all languages are equally acceptable. If an
+ Accept-Language header is present, then all languages which are
+ assigned a quality factor greater than 0 are acceptable.
+
+ It might be contrary to the privacy expectations of the user to send
+ an Accept-Language header with the complete linguistic preferences of
+ the user in every request. For a discussion of this issue, see
+ section 15.1.4.
+
+ As intelligibility is highly dependent on the individual user, it is
+ recommended that client applications make the choice of linguistic
+ preference available to the user. If the choice is not made
+ available, then the Accept-Language header field MUST NOT be given in
+ the request.
+
+ Note: When making the choice of linguistic preference available to
+ the user, we remind implementors of the fact that users are not
+ familiar with the details of language matching as described above,
+ and should provide appropriate guidance. As an example, users
+ might assume that on selecting "en-gb", they will be served any
+ kind of English document if British English is not available. A
+ user agent might suggest in such a case to add "en" to get the
+ best matching behavior.
+
+14.5 Accept-Ranges
+
+ The Accept-Ranges response-header field allows the server to
+ indicate its acceptance of range requests for a resource:
+
+ Accept-Ranges = "Accept-Ranges" ":" acceptable-ranges
+ acceptable-ranges = 1#range-unit | "none"
+
+ Origin servers that accept byte-range requests MAY send
+
+ Accept-Ranges: bytes
+
+ but are not required to do so. Clients MAY generate byte-range
+ requests without having received this header for the resource
+ involved. Range units are defined in section 3.12.
+
+ Servers that do not accept any kind of range request for a
+ resource MAY send
+
+ Accept-Ranges: none
+
+ to advise the client not to attempt a range request.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 105]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14.6 Age
+
+ The Age response-header field conveys the sender's estimate of the
+ amount of time since the response (or its revalidation) was
+ generated at the origin server. A cached response is "fresh" if
+ its age does not exceed its freshness lifetime. Age values are
+ calculated as specified in section 13.2.3.
+
+ Age = "Age" ":" age-value
+ age-value = delta-seconds
+
+ Age values are non-negative decimal integers, representing time in
+ seconds.
+
+ If a cache receives a value larger than the largest positive
+ integer it can represent, or if any of its age calculations
+ overflows, it MUST transmit an Age header with a value of
+ 2147483648 (2^31). An HTTP/1.1 server that includes a cache MUST
+ include an Age header field in every response generated from its
+ own cache. Caches SHOULD use an arithmetic type of at least 31
+ bits of range.
+
+14.7 Allow
+
+ The Allow entity-header field lists the set of methods supported
+ by the resource identified by the Request-URI. The purpose of this
+ field is strictly to inform the recipient of valid methods
+ associated with the resource. An Allow header field MUST be
+ present in a 405 (Method Not Allowed) response.
+
+ Allow = "Allow" ":" #Method
+
+ Example of use:
+
+ Allow: GET, HEAD, PUT
+
+ This field cannot prevent a client from trying other methods.
+ However, the indications given by the Allow header field value
+ SHOULD be followed. The actual set of allowed methods is defined
+ by the origin server at the time of each request.
+
+ The Allow header field MAY be provided with a PUT request to
+ recommend the methods to be supported by the new or modified
+ resource. The server is not required to support these methods and
+ SHOULD include an Allow header in the response giving the actual
+ supported methods.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 106]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ A proxy MUST NOT modify the Allow header field even if it does not
+ understand all the methods specified, since the user agent might
+ have other means of communicating with the origin server.
+
+14.8 Authorization
+
+ A user agent that wishes to authenticate itself with a server--
+ usually, but not necessarily, after receiving a 401 response--does
+ so by including an Authorization request-header field with the
+ request. The Authorization field value consists of credentials
+ containing the authentication information of the user agent for
+ the realm of the resource being requested.
+
+ Authorization = "Authorization" ":" credentials
+
+ HTTP access authentication is described in "HTTP Authentication:
+ Basic and Digest Access Authentication" [43]. If a request is
+ authenticated and a realm specified, the same credentials SHOULD
+ be valid for all other requests within this realm (assuming that
+ the authentication scheme itself does not require otherwise, such
+ as credentials that vary according to a challenge value or using
+ synchronized clocks).
+
+ When a shared cache (see section 13.7) receives a request
+ containing an Authorization field, it MUST NOT return the
+ corresponding response as a reply to any other request, unless one
+ of the following specific exceptions holds:
+
+ 1. If the response includes the "s-maxage" cache-control
+ directive, the cache MAY use that response in replying to a
+ subsequent request. But (if the specified maximum age has
+ passed) a proxy cache MUST first revalidate it with the origin
+ server, using the request-headers from the new request to allow
+ the origin server to authenticate the new request. (This is the
+ defined behavior for s-maxage.) If the response includes "s-
+ maxage=0", the proxy MUST always revalidate it before re-using
+ it.
+
+ 2. If the response includes the "must-revalidate" cache-control
+ directive, the cache MAY use that response in replying to a
+ subsequent request. But if the response is stale, all caches
+ MUST first revalidate it with the origin server, using the
+ request-headers from the new request to allow the origin server
+ to authenticate the new request.
+
+ 3. If the response includes the "public" cache-control directive,
+ it MAY be returned in reply to any subsequent request.
+
+
+
+
+Fielding, et al. Standards Track [Page 107]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14.9 Cache-Control
+
+ The Cache-Control general-header field is used to specify directives
+ that MUST be obeyed by all caching mechanisms along the
+ request/response chain. The directives specify behavior intended to
+ prevent caches from adversely interfering with the request or
+ response. These directives typically override the default caching
+ algorithms. Cache directives are unidirectional in that the presence
+ of a directive in a request does not imply that the same directive is
+ to be given in the response.
+
+ Note that HTTP/1.0 caches might not implement Cache-Control and
+ might only implement Pragma: no-cache (see section 14.32).
+
+ Cache directives MUST be passed through by a proxy or gateway
+ application, regardless of their significance to that application,
+ since the directives might be applicable to all recipients along the
+ request/response chain. It is not possible to specify a cache-
+ directive for a specific cache.
+
+ Cache-Control = "Cache-Control" ":" 1#cache-directive
+
+ cache-directive = cache-request-directive
+ | cache-response-directive
+
+ cache-request-directive =
+ "no-cache" ; Section 14.9.1
+ | "no-store" ; Section 14.9.2
+ | "max-age" "=" delta-seconds ; Section 14.9.3, 14.9.4
+ | "max-stale" [ "=" delta-seconds ] ; Section 14.9.3
+ | "min-fresh" "=" delta-seconds ; Section 14.9.3
+ | "no-transform" ; Section 14.9.5
+ | "only-if-cached" ; Section 14.9.4
+ | cache-extension ; Section 14.9.6
+
+ cache-response-directive =
+ "public" ; Section 14.9.1
+ | "private" [ "=" <"> 1#field-name <"> ] ; Section 14.9.1
+ | "no-cache" [ "=" <"> 1#field-name <"> ]; Section 14.9.1
+ | "no-store" ; Section 14.9.2
+ | "no-transform" ; Section 14.9.5
+ | "must-revalidate" ; Section 14.9.4
+ | "proxy-revalidate" ; Section 14.9.4
+ | "max-age" "=" delta-seconds ; Section 14.9.3
+ | "s-maxage" "=" delta-seconds ; Section 14.9.3
+ | cache-extension ; Section 14.9.6
+
+ cache-extension = token [ "=" ( token | quoted-string ) ]
+
+
+
+Fielding, et al. Standards Track [Page 108]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ When a directive appears without any 1#field-name parameter, the
+ directive applies to the entire request or response. When such a
+ directive appears with a 1#field-name parameter, it applies only to
+ the named field or fields, and not to the rest of the request or
+ response. This mechanism supports extensibility; implementations of
+ future versions of the HTTP protocol might apply these directives to
+ header fields not defined in HTTP/1.1.
+
+ The cache-control directives can be broken down into these general
+ categories:
+
+ - Restrictions on what are cacheable; these may only be imposed by
+ the origin server.
+
+ - Restrictions on what may be stored by a cache; these may be
+ imposed by either the origin server or the user agent.
+
+ - Modifications of the basic expiration mechanism; these may be
+ imposed by either the origin server or the user agent.
+
+ - Controls over cache revalidation and reload; these may only be
+ imposed by a user agent.
+
+ - Control over transformation of entities.
+
+ - Extensions to the caching system.
+
+14.9.1 What is Cacheable
+
+ By default, a response is cacheable if the requirements of the
+ request method, request header fields, and the response status
+ indicate that it is cacheable. Section 13.4 summarizes these defaults
+ for cacheability. The following Cache-Control response directives
+ allow an origin server to override the default cacheability of a
+ response:
+
+ public
+ Indicates that the response MAY be cached by any cache, even if it
+ would normally be non-cacheable or cacheable only within a non-
+ shared cache. (See also Authorization, section 14.8, for
+ additional details.)
+
+ private
+ Indicates that all or part of the response message is intended for
+ a single user and MUST NOT be cached by a shared cache. This
+ allows an origin server to state that the specified parts of the
+
+
+
+
+
+Fielding, et al. Standards Track [Page 109]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ response are intended for only one user and are not a valid
+ response for requests by other users. A private (non-shared) cache
+ MAY cache the response.
+
+ Note: This usage of the word private only controls where the
+ response may be cached, and cannot ensure the privacy of the
+ message content.
+
+ no-cache
+ If the no-cache directive does not specify a field-name, then a
+ cache MUST NOT use the response to satisfy a subsequent request
+ without successful revalidation with the origin server. This
+ allows an origin server to prevent caching even by caches that
+ have been configured to return stale responses to client requests.
+
+ If the no-cache directive does specify one or more field-names,
+ then a cache MAY use the response to satisfy a subsequent request,
+ subject to any other restrictions on caching. However, the
+ specified field-name(s) MUST NOT be sent in the response to a
+ subsequent request without successful revalidation with the origin
+ server. This allows an origin server to prevent the re-use of
+ certain header fields in a response, while still allowing caching
+ of the rest of the response.
+
+ Note: Most HTTP/1.0 caches will not recognize or obey this
+ directive.
+
+14.9.2 What May be Stored by Caches
+
+ no-store
+ The purpose of the no-store directive is to prevent the
+ inadvertent release or retention of sensitive information (for
+ example, on backup tapes). The no-store directive applies to the
+ entire message, and MAY be sent either in a response or in a
+ request. If sent in a request, a cache MUST NOT store any part of
+ either this request or any response to it. If sent in a response,
+ a cache MUST NOT store any part of either this response or the
+ request that elicited it. This directive applies to both non-
+ shared and shared caches. "MUST NOT store" in this context means
+ that the cache MUST NOT intentionally store the information in
+ non-volatile storage, and MUST make a best-effort attempt to
+ remove the information from volatile storage as promptly as
+ possible after forwarding it.
+
+ Even when this directive is associated with a response, users
+ might explicitly store such a response outside of the caching
+ system (e.g., with a "Save As" dialog). History buffers MAY store
+ such responses as part of their normal operation.
+
+
+
+Fielding, et al. Standards Track [Page 110]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The purpose of this directive is to meet the stated requirements
+ of certain users and service authors who are concerned about
+ accidental releases of information via unanticipated accesses to
+ cache data structures. While the use of this directive might
+ improve privacy in some cases, we caution that it is NOT in any
+ way a reliable or sufficient mechanism for ensuring privacy. In
+ particular, malicious or compromised caches might not recognize or
+ obey this directive, and communications networks might be
+ vulnerable to eavesdropping.
+
+14.9.3 Modifications of the Basic Expiration Mechanism
+
+ The expiration time of an entity MAY be specified by the origin
+ server using the Expires header (see section 14.21). Alternatively,
+ it MAY be specified using the max-age directive in a response. When
+ the max-age cache-control directive is present in a cached response,
+ the response is stale if its current age is greater than the age
+ value given (in seconds) at the time of a new request for that
+ resource. The max-age directive on a response implies that the
+ response is cacheable (i.e., "public") unless some other, more
+ restrictive cache directive is also present.
+
+ If a response includes both an Expires header and a max-age
+ directive, the max-age directive overrides the Expires header, even
+ if the Expires header is more restrictive. This rule allows an origin
+ server to provide, for a given response, a longer expiration time to
+ an HTTP/1.1 (or later) cache than to an HTTP/1.0 cache. This might be
+ useful if certain HTTP/1.0 caches improperly calculate ages or
+ expiration times, perhaps due to desynchronized clocks.
+
+ Many HTTP/1.0 cache implementations will treat an Expires value that
+ is less than or equal to the response Date value as being equivalent
+ to the Cache-Control response directive "no-cache". If an HTTP/1.1
+ cache receives such a response, and the response does not include a
+ Cache-Control header field, it SHOULD consider the response to be
+ non-cacheable in order to retain compatibility with HTTP/1.0 servers.
+
+ Note: An origin server might wish to use a relatively new HTTP
+ cache control feature, such as the "private" directive, on a
+ network including older caches that do not understand that
+ feature. The origin server will need to combine the new feature
+ with an Expires field whose value is less than or equal to the
+ Date value. This will prevent older caches from improperly
+ caching the response.
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 111]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ s-maxage
+ If a response includes an s-maxage directive, then for a shared
+ cache (but not for a private cache), the maximum age specified by
+ this directive overrides the maximum age specified by either the
+ max-age directive or the Expires header. The s-maxage directive
+ also implies the semantics of the proxy-revalidate directive (see
+ section 14.9.4), i.e., that the shared cache must not use the
+ entry after it becomes stale to respond to a subsequent request
+ without first revalidating it with the origin server. The s-
+ maxage directive is always ignored by a private cache.
+
+ Note that most older caches, not compliant with this specification,
+ do not implement any cache-control directives. An origin server
+ wishing to use a cache-control directive that restricts, but does not
+ prevent, caching by an HTTP/1.1-compliant cache MAY exploit the
+ requirement that the max-age directive overrides the Expires header,
+ and the fact that pre-HTTP/1.1-compliant caches do not observe the
+ max-age directive.
+
+ Other directives allow a user agent to modify the basic expiration
+ mechanism. These directives MAY be specified on a request:
+
+ max-age
+ Indicates that the client is willing to accept a response whose
+ age is no greater than the specified time in seconds. Unless max-
+ stale directive is also included, the client is not willing to
+ accept a stale response.
+
+ min-fresh
+ Indicates that the client is willing to accept a response whose
+ freshness lifetime is no less than its current age plus the
+ specified time in seconds. That is, the client wants a response
+ that will still be fresh for at least the specified number of
+ seconds.
+
+ max-stale
+ Indicates that the client is willing to accept a response that has
+ exceeded its expiration time. If max-stale is assigned a value,
+ then the client is willing to accept a response that has exceeded
+ its expiration time by no more than the specified number of
+ seconds. If no value is assigned to max-stale, then the client is
+ willing to accept a stale response of any age.
+
+ If a cache returns a stale response, either because of a max-stale
+ directive on a request, or because the cache is configured to
+ override the expiration time of a response, the cache MUST attach a
+ Warning header to the stale response, using Warning 110 (Response is
+ stale).
+
+
+
+Fielding, et al. Standards Track [Page 112]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ A cache MAY be configured to return stale responses without
+ validation, but only if this does not conflict with any "MUST"-level
+ requirements concerning cache validation (e.g., a "must-revalidate"
+ cache-control directive).
+
+ If both the new request and the cached entry include "max-age"
+ directives, then the lesser of the two values is used for determining
+ the freshness of the cached entry for that request.
+
+14.9.4 Cache Revalidation and Reload Controls
+
+ Sometimes a user agent might want or need to insist that a cache
+ revalidate its cache entry with the origin server (and not just with
+ the next cache along the path to the origin server), or to reload its
+ cache entry from the origin server. End-to-end revalidation might be
+ necessary if either the cache or the origin server has overestimated
+ the expiration time of the cached response. End-to-end reload may be
+ necessary if the cache entry has become corrupted for some reason.
+
+ End-to-end revalidation may be requested either when the client does
+ not have its own local cached copy, in which case we call it
+ "unspecified end-to-end revalidation", or when the client does have a
+ local cached copy, in which case we call it "specific end-to-end
+ revalidation."
+
+ The client can specify these three kinds of action using Cache-
+ Control request directives:
+
+ End-to-end reload
+ The request includes a "no-cache" cache-control directive or, for
+ compatibility with HTTP/1.0 clients, "Pragma: no-cache". Field
+ names MUST NOT be included with the no-cache directive in a
+ request. The server MUST NOT use a cached copy when responding to
+ such a request.
+
+ Specific end-to-end revalidation
+ The request includes a "max-age=0" cache-control directive, which
+ forces each cache along the path to the origin server to
+ revalidate its own entry, if any, with the next cache or server.
+ The initial request includes a cache-validating conditional with
+ the client's current validator.
+
+ Unspecified end-to-end revalidation
+ The request includes "max-age=0" cache-control directive, which
+ forces each cache along the path to the origin server to
+ revalidate its own entry, if any, with the next cache or server.
+ The initial request does not include a cache-validating
+
+
+
+
+Fielding, et al. Standards Track [Page 113]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ conditional; the first cache along the path (if any) that holds a
+ cache entry for this resource includes a cache-validating
+ conditional with its current validator.
+
+ max-age
+ When an intermediate cache is forced, by means of a max-age=0
+ directive, to revalidate its own cache entry, and the client has
+ supplied its own validator in the request, the supplied validator
+ might differ from the validator currently stored with the cache
+ entry. In this case, the cache MAY use either validator in making
+ its own request without affecting semantic transparency.
+
+ However, the choice of validator might affect performance. The
+ best approach is for the intermediate cache to use its own
+ validator when making its request. If the server replies with 304
+ (Not Modified), then the cache can return its now validated copy
+ to the client with a 200 (OK) response. If the server replies with
+ a new entity and cache validator, however, the intermediate cache
+ can compare the returned validator with the one provided in the
+ client's request, using the strong comparison function. If the
+ client's validator is equal to the origin server's, then the
+ intermediate cache simply returns 304 (Not Modified). Otherwise,
+ it returns the new entity with a 200 (OK) response.
+
+ If a request includes the no-cache directive, it SHOULD NOT
+ include min-fresh, max-stale, or max-age.
+
+ only-if-cached
+ In some cases, such as times of extremely poor network
+ connectivity, a client may want a cache to return only those
+ responses that it currently has stored, and not to reload or
+ revalidate with the origin server. To do this, the client may
+ include the only-if-cached directive in a request. If it receives
+ this directive, a cache SHOULD either respond using a cached entry
+ that is consistent with the other constraints of the request, or
+ respond with a 504 (Gateway Timeout) status. However, if a group
+ of caches is being operated as a unified system with good internal
+ connectivity, such a request MAY be forwarded within that group of
+ caches.
+
+ must-revalidate
+ Because a cache MAY be configured to ignore a server's specified
+ expiration time, and because a client request MAY include a max-
+ stale directive (which has a similar effect), the protocol also
+ includes a mechanism for the origin server to require revalidation
+ of a cache entry on any subsequent use. When the must-revalidate
+ directive is present in a response received by a cache, that cache
+ MUST NOT use the entry after it becomes stale to respond to a
+
+
+
+Fielding, et al. Standards Track [Page 114]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ subsequent request without first revalidating it with the origin
+ server. (I.e., the cache MUST do an end-to-end revalidation every
+ time, if, based solely on the origin server's Expires or max-age
+ value, the cached response is stale.)
+
+ The must-revalidate directive is necessary to support reliable
+ operation for certain protocol features. In all circumstances an
+ HTTP/1.1 cache MUST obey the must-revalidate directive; in
+ particular, if the cache cannot reach the origin server for any
+ reason, it MUST generate a 504 (Gateway Timeout) response.
+
+ Servers SHOULD send the must-revalidate directive if and only if
+ failure to revalidate a request on the entity could result in
+ incorrect operation, such as a silently unexecuted financial
+ transaction. Recipients MUST NOT take any automated action that
+ violates this directive, and MUST NOT automatically provide an
+ unvalidated copy of the entity if revalidation fails.
+
+ Although this is not recommended, user agents operating under
+ severe connectivity constraints MAY violate this directive but, if
+ so, MUST explicitly warn the user that an unvalidated response has
+ been provided. The warning MUST be provided on each unvalidated
+ access, and SHOULD require explicit user confirmation.
+
+ proxy-revalidate
+ The proxy-revalidate directive has the same meaning as the must-
+ revalidate directive, except that it does not apply to non-shared
+ user agent caches. It can be used on a response to an
+ authenticated request to permit the user's cache to store and
+ later return the response without needing to revalidate it (since
+ it has already been authenticated once by that user), while still
+ requiring proxies that service many users to revalidate each time
+ (in order to make sure that each user has been authenticated).
+ Note that such authenticated responses also need the public cache
+ control directive in order to allow them to be cached at all.
+
+14.9.5 No-Transform Directive
+
+ no-transform
+ Implementors of intermediate caches (proxies) have found it useful
+ to convert the media type of certain entity bodies. A non-
+ transparent proxy might, for example, convert between image
+ formats in order to save cache space or to reduce the amount of
+ traffic on a slow link.
+
+ Serious operational problems occur, however, when these
+ transformations are applied to entity bodies intended for certain
+ kinds of applications. For example, applications for medical
+
+
+
+Fielding, et al. Standards Track [Page 115]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ imaging, scientific data analysis and those using end-to-end
+ authentication, all depend on receiving an entity body that is bit
+ for bit identical to the original entity-body.
+
+ Therefore, if a message includes the no-transform directive, an
+ intermediate cache or proxy MUST NOT change those headers that are
+ listed in section 13.5.2 as being subject to the no-transform
+ directive. This implies that the cache or proxy MUST NOT change
+ any aspect of the entity-body that is specified by these headers,
+ including the value of the entity-body itself.
+
+14.9.6 Cache Control Extensions
+
+ The Cache-Control header field can be extended through the use of one
+ or more cache-extension tokens, each with an optional assigned value.
+ Informational extensions (those which do not require a change in
+ cache behavior) MAY be added without changing the semantics of other
+ directives. Behavioral extensions are designed to work by acting as
+ modifiers to the existing base of cache directives. Both the new
+ directive and the standard directive are supplied, such that
+ applications which do not understand the new directive will default
+ to the behavior specified by the standard directive, and those that
+ understand the new directive will recognize it as modifying the
+ requirements associated with the standard directive. In this way,
+ extensions to the cache-control directives can be made without
+ requiring changes to the base protocol.
+
+ This extension mechanism depends on an HTTP cache obeying all of the
+ cache-control directives defined for its native HTTP-version, obeying
+ certain extensions, and ignoring all directives that it does not
+ understand.
+
+ For example, consider a hypothetical new response directive called
+ community which acts as a modifier to the private directive. We
+ define this new directive to mean that, in addition to any non-shared
+ cache, any cache which is shared only by members of the community
+ named within its value may cache the response. An origin server
+ wishing to allow the UCI community to use an otherwise private
+ response in their shared cache(s) could do so by including
+
+ Cache-Control: private, community="UCI"
+
+ A cache seeing this header field will act correctly even if the cache
+ does not understand the community cache-extension, since it will also
+ see and understand the private directive and thus default to the safe
+ behavior.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 116]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Unrecognized cache-directives MUST be ignored; it is assumed that any
+ cache-directive likely to be unrecognized by an HTTP/1.1 cache will
+ be combined with standard directives (or the response's default
+ cacheability) such that the cache behavior will remain minimally
+ correct even if the cache does not understand the extension(s).
+
+14.10 Connection
+
+ The Connection general-header field allows the sender to specify
+ options that are desired for that particular connection and MUST NOT
+ be communicated by proxies over further connections.
+
+ The Connection header has the following grammar:
+
+ Connection = "Connection" ":" 1#(connection-token)
+ connection-token = token
+
+ HTTP/1.1 proxies MUST parse the Connection header field before a
+ message is forwarded and, for each connection-token in this field,
+ remove any header field(s) from the message with the same name as the
+ connection-token. Connection options are signaled by the presence of
+ a connection-token in the Connection header field, not by any
+ corresponding additional header field(s), since the additional header
+ field may not be sent if there are no parameters associated with that
+ connection option.
+
+ Message headers listed in the Connection header MUST NOT include
+ end-to-end headers, such as Cache-Control.
+
+ HTTP/1.1 defines the "close" connection option for the sender to
+ signal that the connection will be closed after completion of the
+ response. For example,
+
+ Connection: close
+
+ in either the request or the response header fields indicates that
+ the connection SHOULD NOT be considered `persistent' (section 8.1)
+ after the current request/response is complete.
+
+ HTTP/1.1 applications that do not support persistent connections MUST
+ include the "close" connection option in every message.
+
+ A system receiving an HTTP/1.0 (or lower-version) message that
+ includes a Connection header MUST, for each connection-token in this
+ field, remove and ignore any header field(s) from the message with
+ the same name as the connection-token. This protects against mistaken
+ forwarding of such header fields by pre-HTTP/1.1 proxies. See section
+ 19.6.2.
+
+
+
+Fielding, et al. Standards Track [Page 117]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14.11 Content-Encoding
+
+ The Content-Encoding entity-header field is used as a modifier to the
+ media-type. When present, its value indicates what additional content
+ codings have been applied to the entity-body, and thus what decoding
+ mechanisms must be applied in order to obtain the media-type
+ referenced by the Content-Type header field. Content-Encoding is
+ primarily used to allow a document to be compressed without losing
+ the identity of its underlying media type.
+
+ Content-Encoding = "Content-Encoding" ":" 1#content-coding
+
+ Content codings are defined in section 3.5. An example of its use is
+
+ Content-Encoding: gzip
+
+ The content-coding is a characteristic of the entity identified by
+ the Request-URI. Typically, the entity-body is stored with this
+ encoding and is only decoded before rendering or analogous usage.
+ However, a non-transparent proxy MAY modify the content-coding if the
+ new coding is known to be acceptable to the recipient, unless the
+ "no-transform" cache-control directive is present in the message.
+
+ If the content-coding of an entity is not "identity", then the
+ response MUST include a Content-Encoding entity-header (section
+ 14.11) that lists the non-identity content-coding(s) used.
+
+ If the content-coding of an entity in a request message is not
+ acceptable to the origin server, the server SHOULD respond with a
+ status code of 415 (Unsupported Media Type).
+
+ If multiple encodings have been applied to an entity, the content
+ codings MUST be listed in the order in which they were applied.
+ Additional information about the encoding parameters MAY be provided
+ by other entity-header fields not defined by this specification.
+
+14.12 Content-Language
+
+ The Content-Language entity-header field describes the natural
+ language(s) of the intended audience for the enclosed entity. Note
+ that this might not be equivalent to all the languages used within
+ the entity-body.
+
+ Content-Language = "Content-Language" ":" 1#language-tag
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 118]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Language tags are defined in section 3.10. The primary purpose of
+ Content-Language is to allow a user to identify and differentiate
+ entities according to the user's own preferred language. Thus, if the
+ body content is intended only for a Danish-literate audience, the
+ appropriate field is
+
+ Content-Language: da
+
+ If no Content-Language is specified, the default is that the content
+ is intended for all language audiences. This might mean that the
+ sender does not consider it to be specific to any natural language,
+ or that the sender does not know for which language it is intended.
+
+ Multiple languages MAY be listed for content that is intended for
+ multiple audiences. For example, a rendition of the "Treaty of
+ Waitangi," presented simultaneously in the original Maori and English
+ versions, would call for
+
+ Content-Language: mi, en
+
+ However, just because multiple languages are present within an entity
+ does not mean that it is intended for multiple linguistic audiences.
+ An example would be a beginner's language primer, such as "A First
+ Lesson in Latin," which is clearly intended to be used by an
+ English-literate audience. In this case, the Content-Language would
+ properly only include "en".
+
+ Content-Language MAY be applied to any media type -- it is not
+ limited to textual documents.
+
+14.13 Content-Length
+
+ The Content-Length entity-header field indicates the size of the
+ entity-body, in decimal number of OCTETs, sent to the recipient or,
+ in the case of the HEAD method, the size of the entity-body that
+ would have been sent had the request been a GET.
+
+ Content-Length = "Content-Length" ":" 1*DIGIT
+
+ An example is
+
+ Content-Length: 3495
+
+ Applications SHOULD use this field to indicate the transfer-length of
+ the message-body, unless this is prohibited by the rules in section
+ 4.4.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 119]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Any Content-Length greater than or equal to zero is a valid value.
+ Section 4.4 describes how to determine the length of a message-body
+ if a Content-Length is not given.
+
+ Note that the meaning of this field is significantly different from
+ the corresponding definition in MIME, where it is an optional field
+ used within the "message/external-body" content-type. In HTTP, it
+ SHOULD be sent whenever the message's length can be determined prior
+ to being transferred, unless this is prohibited by the rules in
+ section 4.4.
+
+14.14 Content-Location
+
+ The Content-Location entity-header field MAY be used to supply the
+ resource location for the entity enclosed in the message when that
+ entity is accessible from a location separate from the requested
+ resource's URI. A server SHOULD provide a Content-Location for the
+ variant corresponding to the response entity; especially in the case
+ where a resource has multiple entities associated with it, and those
+ entities actually have separate locations by which they might be
+ individually accessed, the server SHOULD provide a Content-Location
+ for the particular variant which is returned.
+
+ Content-Location = "Content-Location" ":"
+ ( absoluteURI | relativeURI )
+
+ The value of Content-Location also defines the base URI for the
+ entity.
+
+ The Content-Location value is not a replacement for the original
+ requested URI; it is only a statement of the location of the resource
+ corresponding to this particular entity at the time of the request.
+ Future requests MAY specify the Content-Location URI as the request-
+ URI if the desire is to identify the source of that particular
+ entity.
+
+ A cache cannot assume that an entity with a Content-Location
+ different from the URI used to retrieve it can be used to respond to
+ later requests on that Content-Location URI. However, the Content-
+ Location can be used to differentiate between multiple entities
+ retrieved from a single requested resource, as described in section
+ 13.6.
+
+ If the Content-Location is a relative URI, the relative URI is
+ interpreted relative to the Request-URI.
+
+ The meaning of the Content-Location header in PUT or POST requests is
+ undefined; servers are free to ignore it in those cases.
+
+
+
+Fielding, et al. Standards Track [Page 120]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14.15 Content-MD5
+
+ The Content-MD5 entity-header field, as defined in RFC 1864 [23], is
+ an MD5 digest of the entity-body for the purpose of providing an
+ end-to-end message integrity check (MIC) of the entity-body. (Note: a
+ MIC is good for detecting accidental modification of the entity-body
+ in transit, but is not proof against malicious attacks.)
+
+ Content-MD5 = "Content-MD5" ":" md5-digest
+ md5-digest = <base64 of 128 bit MD5 digest as per RFC 1864>
+
+ The Content-MD5 header field MAY be generated by an origin server or
+ client to function as an integrity check of the entity-body. Only
+ origin servers or clients MAY generate the Content-MD5 header field;
+ proxies and gateways MUST NOT generate it, as this would defeat its
+ value as an end-to-end integrity check. Any recipient of the entity-
+ body, including gateways and proxies, MAY check that the digest value
+ in this header field matches that of the entity-body as received.
+
+ The MD5 digest is computed based on the content of the entity-body,
+ including any content-coding that has been applied, but not including
+ any transfer-encoding applied to the message-body. If the message is
+ received with a transfer-encoding, that encoding MUST be removed
+ prior to checking the Content-MD5 value against the received entity.
+
+ This has the result that the digest is computed on the octets of the
+ entity-body exactly as, and in the order that, they would be sent if
+ no transfer-encoding were being applied.
+
+ HTTP extends RFC 1864 to permit the digest to be computed for MIME
+ composite media-types (e.g., multipart/* and message/rfc822), but
+ this does not change how the digest is computed as defined in the
+ preceding paragraph.
+
+ There are several consequences of this. The entity-body for composite
+ types MAY contain many body-parts, each with its own MIME and HTTP
+ headers (including Content-MD5, Content-Transfer-Encoding, and
+ Content-Encoding headers). If a body-part has a Content-Transfer-
+ Encoding or Content-Encoding header, it is assumed that the content
+ of the body-part has had the encoding applied, and the body-part is
+ included in the Content-MD5 digest as is -- i.e., after the
+ application. The Transfer-Encoding header field is not allowed within
+ body-parts.
+
+ Conversion of all line breaks to CRLF MUST NOT be done before
+ computing or checking the digest: the line break convention used in
+ the text actually transmitted MUST be left unaltered when computing
+ the digest.
+
+
+
+Fielding, et al. Standards Track [Page 121]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Note: while the definition of Content-MD5 is exactly the same for
+ HTTP as in RFC 1864 for MIME entity-bodies, there are several ways
+ in which the application of Content-MD5 to HTTP entity-bodies
+ differs from its application to MIME entity-bodies. One is that
+ HTTP, unlike MIME, does not use Content-Transfer-Encoding, and
+ does use Transfer-Encoding and Content-Encoding. Another is that
+ HTTP more frequently uses binary content types than MIME, so it is
+ worth noting that, in such cases, the byte order used to compute
+ the digest is the transmission byte order defined for the type.
+ Lastly, HTTP allows transmission of text types with any of several
+ line break conventions and not just the canonical form using CRLF.
+
+14.16 Content-Range
+
+ The Content-Range entity-header is sent with a partial entity-body to
+ specify where in the full entity-body the partial body should be
+ applied. Range units are defined in section 3.12.
+
+ Content-Range = "Content-Range" ":" content-range-spec
+
+ content-range-spec = byte-content-range-spec
+ byte-content-range-spec = bytes-unit SP
+ byte-range-resp-spec "/"
+ ( instance-length | "*" )
+
+ byte-range-resp-spec = (first-byte-pos "-" last-byte-pos)
+ | "*"
+ instance-length = 1*DIGIT
+
+ The header SHOULD indicate the total length of the full entity-body,
+ unless this length is unknown or difficult to determine. The asterisk
+ "*" character means that the instance-length is unknown at the time
+ when the response was generated.
+
+ Unlike byte-ranges-specifier values (see section 14.35.1), a byte-
+ range-resp-spec MUST only specify one range, and MUST contain
+ absolute byte positions for both the first and last byte of the
+ range.
+
+ A byte-content-range-spec with a byte-range-resp-spec whose last-
+ byte-pos value is less than its first-byte-pos value, or whose
+ instance-length value is less than or equal to its last-byte-pos
+ value, is invalid. The recipient of an invalid byte-content-range-
+ spec MUST ignore it and any content transferred along with it.
+
+ A server sending a response with status code 416 (Requested range not
+ satisfiable) SHOULD include a Content-Range field with a byte-range-
+ resp-spec of "*". The instance-length specifies the current length of
+
+
+
+Fielding, et al. Standards Track [Page 122]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ the selected resource. A response with status code 206 (Partial
+ Content) MUST NOT include a Content-Range field with a byte-range-
+ resp-spec of "*".
+
+ Examples of byte-content-range-spec values, assuming that the entity
+ contains a total of 1234 bytes:
+
+ . The first 500 bytes:
+ bytes 0-499/1234
+
+ . The second 500 bytes:
+ bytes 500-999/1234
+
+ . All except for the first 500 bytes:
+ bytes 500-1233/1234
+
+ . The last 500 bytes:
+ bytes 734-1233/1234
+
+ When an HTTP message includes the content of a single range (for
+ example, a response to a request for a single range, or to a request
+ for a set of ranges that overlap without any holes), this content is
+ transmitted with a Content-Range header, and a Content-Length header
+ showing the number of bytes actually transferred. For example,
+
+ HTTP/1.1 206 Partial content
+ Date: Wed, 15 Nov 1995 06:25:24 GMT
+ Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
+ Content-Range: bytes 21010-47021/47022
+ Content-Length: 26012
+ Content-Type: image/gif
+
+ When an HTTP message includes the content of multiple ranges (for
+ example, a response to a request for multiple non-overlapping
+ ranges), these are transmitted as a multipart message. The multipart
+ media type used for this purpose is "multipart/byteranges" as defined
+ in appendix 19.2. See appendix 19.6.3 for a compatibility issue.
+
+ A response to a request for a single range MUST NOT be sent using the
+ multipart/byteranges media type. A response to a request for
+ multiple ranges, whose result is a single range, MAY be sent as a
+ multipart/byteranges media type with one part. A client that cannot
+ decode a multipart/byteranges message MUST NOT ask for multiple
+ byte-ranges in a single request.
+
+ When a client requests multiple byte-ranges in one request, the
+ server SHOULD return them in the order that they appeared in the
+ request.
+
+
+
+Fielding, et al. Standards Track [Page 123]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If the server ignores a byte-range-spec because it is syntactically
+ invalid, the server SHOULD treat the request as if the invalid Range
+ header field did not exist. (Normally, this means return a 200
+ response containing the full entity).
+
+ If the server receives a request (other than one including an If-
+ Range request-header field) with an unsatisfiable Range request-
+ header field (that is, all of whose byte-range-spec values have a
+ first-byte-pos value greater than the current length of the selected
+ resource), it SHOULD return a response code of 416 (Requested range
+ not satisfiable) (section 10.4.17).
+
+ Note: clients cannot depend on servers to send a 416 (Requested
+ range not satisfiable) response instead of a 200 (OK) response for
+ an unsatisfiable Range request-header, since not all servers
+ implement this request-header.
+
+14.17 Content-Type
+
+ The Content-Type entity-header field indicates the media type of the
+ entity-body sent to the recipient or, in the case of the HEAD method,
+ the media type that would have been sent had the request been a GET.
+
+ Content-Type = "Content-Type" ":" media-type
+
+ Media types are defined in section 3.7. An example of the field is
+
+ Content-Type: text/html; charset=ISO-8859-4
+
+ Further discussion of methods for identifying the media type of an
+ entity is provided in section 7.2.1.
+
+14.18 Date
+
+ The Date general-header field represents the date and time at which
+ the message was originated, having the same semantics as orig-date in
+ RFC 822. The field value is an HTTP-date, as described in section
+ 3.3.1; it MUST be sent in RFC 1123 [8]-date format.
+
+ Date = "Date" ":" HTTP-date
+
+ An example is
+
+ Date: Tue, 15 Nov 1994 08:12:31 GMT
+
+ Origin servers MUST include a Date header field in all responses,
+ except in these cases:
+
+
+
+
+Fielding, et al. Standards Track [Page 124]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 1. If the response status code is 100 (Continue) or 101 (Switching
+ Protocols), the response MAY include a Date header field, at
+ the server's option.
+
+ 2. If the response status code conveys a server error, e.g. 500
+ (Internal Server Error) or 503 (Service Unavailable), and it is
+ inconvenient or impossible to generate a valid Date.
+
+ 3. If the server does not have a clock that can provide a
+ reasonable approximation of the current time, its responses
+ MUST NOT include a Date header field. In this case, the rules
+ in section 14.18.1 MUST be followed.
+
+ A received message that does not have a Date header field MUST be
+ assigned one by the recipient if the message will be cached by that
+ recipient or gatewayed via a protocol which requires a Date. An HTTP
+ implementation without a clock MUST NOT cache responses without
+ revalidating them on every use. An HTTP cache, especially a shared
+ cache, SHOULD use a mechanism, such as NTP [28], to synchronize its
+ clock with a reliable external standard.
+
+ Clients SHOULD only send a Date header field in messages that include
+ an entity-body, as in the case of the PUT and POST requests, and even
+ then it is optional. A client without a clock MUST NOT send a Date
+ header field in a request.
+
+ The HTTP-date sent in a Date header SHOULD NOT represent a date and
+ time subsequent to the generation of the message. It SHOULD represent
+ the best available approximation of the date and time of message
+ generation, unless the implementation has no means of generating a
+ reasonably accurate date and time. In theory, the date ought to
+ represent the moment just before the entity is generated. In
+ practice, the date can be generated at any time during the message
+ origination without affecting its semantic value.
+
+14.18.1 Clockless Origin Server Operation
+
+ Some origin server implementations might not have a clock available.
+ An origin server without a clock MUST NOT assign Expires or Last-
+ Modified values to a response, unless these values were associated
+ with the resource by a system or user with a reliable clock. It MAY
+ assign an Expires value that is known, at or before server
+ configuration time, to be in the past (this allows "pre-expiration"
+ of responses without storing separate Expires values for each
+ resource).
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 125]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14.19 ETag
+
+ The ETag response-header field provides the current value of the
+ entity tag for the requested variant. The headers used with entity
+ tags are described in sections 14.24, 14.26 and 14.44. The entity tag
+ MAY be used for comparison with other entities from the same resource
+ (see section 13.3.3).
+
+ ETag = "ETag" ":" entity-tag
+
+ Examples:
+
+ ETag: "xyzzy"
+ ETag: W/"xyzzy"
+ ETag: ""
+
+14.20 Expect
+
+ The Expect request-header field is used to indicate that particular
+ server behaviors are required by the client.
+
+ Expect = "Expect" ":" 1#expectation
+
+ expectation = "100-continue" | expectation-extension
+ expectation-extension = token [ "=" ( token | quoted-string )
+ *expect-params ]
+ expect-params = ";" token [ "=" ( token | quoted-string ) ]
+
+
+ A server that does not understand or is unable to comply with any of
+ the expectation values in the Expect field of a request MUST respond
+ with appropriate error status. The server MUST respond with a 417
+ (Expectation Failed) status if any of the expectations cannot be met
+ or, if there are other problems with the request, some other 4xx
+ status.
+
+ This header field is defined with extensible syntax to allow for
+ future extensions. If a server receives a request containing an
+ Expect field that includes an expectation-extension that it does not
+ support, it MUST respond with a 417 (Expectation Failed) status.
+
+ Comparison of expectation values is case-insensitive for unquoted
+ tokens (including the 100-continue token), and is case-sensitive for
+ quoted-string expectation-extensions.
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 126]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The Expect mechanism is hop-by-hop: that is, an HTTP/1.1 proxy MUST
+ return a 417 (Expectation Failed) status if it receives a request
+ with an expectation that it cannot meet. However, the Expect
+ request-header itself is end-to-end; it MUST be forwarded if the
+ request is forwarded.
+
+ Many older HTTP/1.0 and HTTP/1.1 applications do not understand the
+ Expect header.
+
+ See section 8.2.3 for the use of the 100 (continue) status.
+
+14.21 Expires
+
+ The Expires entity-header field gives the date/time after which the
+ response is considered stale. A stale cache entry may not normally be
+ returned by a cache (either a proxy cache or a user agent cache)
+ unless it is first validated with the origin server (or with an
+ intermediate cache that has a fresh copy of the entity). See section
+ 13.2 for further discussion of the expiration model.
+
+ The presence of an Expires field does not imply that the original
+ resource will change or cease to exist at, before, or after that
+ time.
+
+ The format is an absolute date and time as defined by HTTP-date in
+ section 3.3.1; it MUST be in RFC 1123 date format:
+
+ Expires = "Expires" ":" HTTP-date
+
+ An example of its use is
+
+ Expires: Thu, 01 Dec 1994 16:00:00 GMT
+
+ Note: if a response includes a Cache-Control field with the max-
+ age directive (see section 14.9.3), that directive overrides the
+ Expires field.
+
+ HTTP/1.1 clients and caches MUST treat other invalid date formats,
+ especially including the value "0", as in the past (i.e., "already
+ expired").
+
+ To mark a response as "already expired," an origin server sends an
+ Expires date that is equal to the Date header value. (See the rules
+ for expiration calculations in section 13.2.4.)
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 127]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ To mark a response as "never expires," an origin server sends an
+ Expires date approximately one year from the time the response is
+ sent. HTTP/1.1 servers SHOULD NOT send Expires dates more than one
+ year in the future.
+
+ The presence of an Expires header field with a date value of some
+ time in the future on a response that otherwise would by default be
+ non-cacheable indicates that the response is cacheable, unless
+ indicated otherwise by a Cache-Control header field (section 14.9).
+
+14.22 From
+
+ The From request-header field, if given, SHOULD contain an Internet
+ e-mail address for the human user who controls the requesting user
+ agent. The address SHOULD be machine-usable, as defined by "mailbox"
+ in RFC 822 [9] as updated by RFC 1123 [8]:
+
+ From = "From" ":" mailbox
+
+ An example is:
+
+ From: webmaster@w3.org
+
+ This header field MAY be used for logging purposes and as a means for
+ identifying the source of invalid or unwanted requests. It SHOULD NOT
+ be used as an insecure form of access protection. The interpretation
+ of this field is that the request is being performed on behalf of the
+ person given, who accepts responsibility for the method performed. In
+ particular, robot agents SHOULD include this header so that the
+ person responsible for running the robot can be contacted if problems
+ occur on the receiving end.
+
+ The Internet e-mail address in this field MAY be separate from the
+ Internet host which issued the request. For example, when a request
+ is passed through a proxy the original issuer's address SHOULD be
+ used.
+
+ The client SHOULD NOT send the From header field without the user's
+ approval, as it might conflict with the user's privacy interests or
+ their site's security policy. It is strongly recommended that the
+ user be able to disable, enable, and modify the value of this field
+ at any time prior to a request.
+
+14.23 Host
+
+ The Host request-header field specifies the Internet host and port
+ number of the resource being requested, as obtained from the original
+ URI given by the user or referring resource (generally an HTTP URL,
+
+
+
+Fielding, et al. Standards Track [Page 128]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ as described in section 3.2.2). The Host field value MUST represent
+ the naming authority of the origin server or gateway given by the
+ original URL. This allows the origin server or gateway to
+ differentiate between internally-ambiguous URLs, such as the root "/"
+ URL of a server for multiple host names on a single IP address.
+
+ Host = "Host" ":" host [ ":" port ] ; Section 3.2.2
+
+ A "host" without any trailing port information implies the default
+ port for the service requested (e.g., "80" for an HTTP URL). For
+ example, a request on the origin server for
+ <http://www.w3.org/pub/WWW/> would properly include:
+
+ GET /pub/WWW/ HTTP/1.1
+ Host: www.w3.org
+
+ A client MUST include a Host header field in all HTTP/1.1 request
+ messages . If the requested URI does not include an Internet host
+ name for the service being requested, then the Host header field MUST
+ be given with an empty value. An HTTP/1.1 proxy MUST ensure that any
+ request message it forwards does contain an appropriate Host header
+ field that identifies the service being requested by the proxy. All
+ Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad Request)
+ status code to any HTTP/1.1 request message which lacks a Host header
+ field.
+
+ See sections 5.2 and 19.6.1.1 for other requirements relating to
+ Host.
+
+14.24 If-Match
+
+ The If-Match request-header field is used with a method to make it
+ conditional. A client that has one or more entities previously
+ obtained from the resource can verify that one of those entities is
+ current by including a list of their associated entity tags in the
+ If-Match header field. Entity tags are defined in section 3.11. The
+ purpose of this feature is to allow efficient updates of cached
+ information with a minimum amount of transaction overhead. It is also
+ used, on updating requests, to prevent inadvertent modification of
+ the wrong version of a resource. As a special case, the value "*"
+ matches any current entity of the resource.
+
+ If-Match = "If-Match" ":" ( "*" | 1#entity-tag )
+
+ If any of the entity tags match the entity tag of the entity that
+ would have been returned in the response to a similar GET request
+ (without the If-Match header) on that resource, or if "*" is given
+
+
+
+
+Fielding, et al. Standards Track [Page 129]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ and any current entity exists for that resource, then the server MAY
+ perform the requested method as if the If-Match header field did not
+ exist.
+
+ A server MUST use the strong comparison function (see section 13.3.3)
+ to compare the entity tags in If-Match.
+
+ If none of the entity tags match, or if "*" is given and no current
+ entity exists, the server MUST NOT perform the requested method, and
+ MUST return a 412 (Precondition Failed) response. This behavior is
+ most useful when the client wants to prevent an updating method, such
+ as PUT, from modifying a resource that has changed since the client
+ last retrieved it.
+
+ If the request would, without the If-Match header field, result in
+ anything other than a 2xx or 412 status, then the If-Match header
+ MUST be ignored.
+
+ The meaning of "If-Match: *" is that the method SHOULD be performed
+ if the representation selected by the origin server (or by a cache,
+ possibly using the Vary mechanism, see section 14.44) exists, and
+ MUST NOT be performed if the representation does not exist.
+
+ A request intended to update a resource (e.g., a PUT) MAY include an
+ If-Match header field to signal that the request method MUST NOT be
+ applied if the entity corresponding to the If-Match value (a single
+ entity tag) is no longer a representation of that resource. This
+ allows the user to indicate that they do not wish the request to be
+ successful if the resource has been changed without their knowledge.
+ Examples:
+
+ If-Match: "xyzzy"
+ If-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
+ If-Match: *
+
+ The result of a request having both an If-Match header field and
+ either an If-None-Match or an If-Modified-Since header fields is
+ undefined by this specification.
+
+14.25 If-Modified-Since
+
+ The If-Modified-Since request-header field is used with a method to
+ make it conditional: if the requested variant has not been modified
+ since the time specified in this field, an entity will not be
+ returned from the server; instead, a 304 (not modified) response will
+ be returned without any message-body.
+
+ If-Modified-Since = "If-Modified-Since" ":" HTTP-date
+
+
+
+Fielding, et al. Standards Track [Page 130]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ An example of the field is:
+
+ If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
+
+ A GET method with an If-Modified-Since header and no Range header
+ requests that the identified entity be transferred only if it has
+ been modified since the date given by the If-Modified-Since header.
+ The algorithm for determining this includes the following cases:
+
+ a) If the request would normally result in anything other than a
+ 200 (OK) status, or if the passed If-Modified-Since date is
+ invalid, the response is exactly the same as for a normal GET.
+ A date which is later than the server's current time is
+ invalid.
+
+ b) If the variant has been modified since the If-Modified-Since
+ date, the response is exactly the same as for a normal GET.
+
+ c) If the variant has not been modified since a valid If-
+ Modified-Since date, the server SHOULD return a 304 (Not
+ Modified) response.
+
+ The purpose of this feature is to allow efficient updates of cached
+ information with a minimum amount of transaction overhead.
+
+ Note: The Range request-header field modifies the meaning of If-
+ Modified-Since; see section 14.35 for full details.
+
+ Note: If-Modified-Since times are interpreted by the server, whose
+ clock might not be synchronized with the client.
+
+ Note: When handling an If-Modified-Since header field, some
+ servers will use an exact date comparison function, rather than a
+ less-than function, for deciding whether to send a 304 (Not
+ Modified) response. To get best results when sending an If-
+ Modified-Since header field for cache validation, clients are
+ advised to use the exact date string received in a previous Last-
+ Modified header field whenever possible.
+
+ Note: If a client uses an arbitrary date in the If-Modified-Since
+ header instead of a date taken from the Last-Modified header for
+ the same request, the client should be aware of the fact that this
+ date is interpreted in the server's understanding of time. The
+ client should consider unsynchronized clocks and rounding problems
+ due to the different encodings of time between the client and
+ server. This includes the possibility of race conditions if the
+ document has changed between the time it was first requested and
+ the If-Modified-Since date of a subsequent request, and the
+
+
+
+Fielding, et al. Standards Track [Page 131]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ possibility of clock-skew-related problems if the If-Modified-
+ Since date is derived from the client's clock without correction
+ to the server's clock. Corrections for different time bases
+ between client and server are at best approximate due to network
+ latency.
+
+ The result of a request having both an If-Modified-Since header field
+ and either an If-Match or an If-Unmodified-Since header fields is
+ undefined by this specification.
+
+14.26 If-None-Match
+
+ The If-None-Match request-header field is used with a method to make
+ it conditional. A client that has one or more entities previously
+ obtained from the resource can verify that none of those entities is
+ current by including a list of their associated entity tags in the
+ If-None-Match header field. The purpose of this feature is to allow
+ efficient updates of cached information with a minimum amount of
+ transaction overhead. It is also used to prevent a method (e.g. PUT)
+ from inadvertently modifying an existing resource when the client
+ believes that the resource does not exist.
+
+ As a special case, the value "*" matches any current entity of the
+ resource.
+
+ If-None-Match = "If-None-Match" ":" ( "*" | 1#entity-tag )
+
+ If any of the entity tags match the entity tag of the entity that
+ would have been returned in the response to a similar GET request
+ (without the If-None-Match header) on that resource, or if "*" is
+ given and any current entity exists for that resource, then the
+ server MUST NOT perform the requested method, unless required to do
+ so because the resource's modification date fails to match that
+ supplied in an If-Modified-Since header field in the request.
+ Instead, if the request method was GET or HEAD, the server SHOULD
+ respond with a 304 (Not Modified) response, including the cache-
+ related header fields (particularly ETag) of one of the entities that
+ matched. For all other request methods, the server MUST respond with
+ a status of 412 (Precondition Failed).
+
+ See section 13.3.3 for rules on how to determine if two entities tags
+ match. The weak comparison function can only be used with GET or HEAD
+ requests.
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 132]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If none of the entity tags match, then the server MAY perform the
+ requested method as if the If-None-Match header field did not exist,
+ but MUST also ignore any If-Modified-Since header field(s) in the
+ request. That is, if no entity tags match, then the server MUST NOT
+ return a 304 (Not Modified) response.
+
+ If the request would, without the If-None-Match header field, result
+ in anything other than a 2xx or 304 status, then the If-None-Match
+ header MUST be ignored. (See section 13.3.4 for a discussion of
+ server behavior when both If-Modified-Since and If-None-Match appear
+ in the same request.)
+
+ The meaning of "If-None-Match: *" is that the method MUST NOT be
+ performed if the representation selected by the origin server (or by
+ a cache, possibly using the Vary mechanism, see section 14.44)
+ exists, and SHOULD be performed if the representation does not exist.
+ This feature is intended to be useful in preventing races between PUT
+ operations.
+
+ Examples:
+
+ If-None-Match: "xyzzy"
+ If-None-Match: W/"xyzzy"
+ If-None-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
+ If-None-Match: W/"xyzzy", W/"r2d2xxxx", W/"c3piozzzz"
+ If-None-Match: *
+
+ The result of a request having both an If-None-Match header field and
+ either an If-Match or an If-Unmodified-Since header fields is
+ undefined by this specification.
+
+14.27 If-Range
+
+ If a client has a partial copy of an entity in its cache, and wishes
+ to have an up-to-date copy of the entire entity in its cache, it
+ could use the Range request-header with a conditional GET (using
+ either or both of If-Unmodified-Since and If-Match.) However, if the
+ condition fails because the entity has been modified, the client
+ would then have to make a second request to obtain the entire current
+ entity-body.
+
+ The If-Range header allows a client to "short-circuit" the second
+ request. Informally, its meaning is `if the entity is unchanged, send
+ me the part(s) that I am missing; otherwise, send me the entire new
+ entity'.
+
+ If-Range = "If-Range" ":" ( entity-tag | HTTP-date )
+
+
+
+
+Fielding, et al. Standards Track [Page 133]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If the client has no entity tag for an entity, but does have a Last-
+ Modified date, it MAY use that date in an If-Range header. (The
+ server can distinguish between a valid HTTP-date and any form of
+ entity-tag by examining no more than two characters.) The If-Range
+ header SHOULD only be used together with a Range header, and MUST be
+ ignored if the request does not include a Range header, or if the
+ server does not support the sub-range operation.
+
+ If the entity tag given in the If-Range header matches the current
+ entity tag for the entity, then the server SHOULD provide the
+ specified sub-range of the entity using a 206 (Partial content)
+ response. If the entity tag does not match, then the server SHOULD
+ return the entire entity using a 200 (OK) response.
+
+14.28 If-Unmodified-Since
+
+ The If-Unmodified-Since request-header field is used with a method to
+ make it conditional. If the requested resource has not been modified
+ since the time specified in this field, the server SHOULD perform the
+ requested operation as if the If-Unmodified-Since header were not
+ present.
+
+ If the requested variant has been modified since the specified time,
+ the server MUST NOT perform the requested operation, and MUST return
+ a 412 (Precondition Failed).
+
+ If-Unmodified-Since = "If-Unmodified-Since" ":" HTTP-date
+
+ An example of the field is:
+
+ If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT
+
+ If the request normally (i.e., without the If-Unmodified-Since
+ header) would result in anything other than a 2xx or 412 status, the
+ If-Unmodified-Since header SHOULD be ignored.
+
+ If the specified date is invalid, the header is ignored.
+
+ The result of a request having both an If-Unmodified-Since header
+ field and either an If-None-Match or an If-Modified-Since header
+ fields is undefined by this specification.
+
+14.29 Last-Modified
+
+ The Last-Modified entity-header field indicates the date and time at
+ which the origin server believes the variant was last modified.
+
+ Last-Modified = "Last-Modified" ":" HTTP-date
+
+
+
+Fielding, et al. Standards Track [Page 134]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ An example of its use is
+
+ Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
+
+ The exact meaning of this header field depends on the implementation
+ of the origin server and the nature of the original resource. For
+ files, it may be just the file system last-modified time. For
+ entities with dynamically included parts, it may be the most recent
+ of the set of last-modify times for its component parts. For database
+ gateways, it may be the last-update time stamp of the record. For
+ virtual objects, it may be the last time the internal state changed.
+
+ An origin server MUST NOT send a Last-Modified date which is later
+ than the server's time of message origination. In such cases, where
+ the resource's last modification would indicate some time in the
+ future, the server MUST replace that date with the message
+ origination date.
+
+ An origin server SHOULD obtain the Last-Modified value of the entity
+ as close as possible to the time that it generates the Date value of
+ its response. This allows a recipient to make an accurate assessment
+ of the entity's modification time, especially if the entity changes
+ near the time that the response is generated.
+
+ HTTP/1.1 servers SHOULD send Last-Modified whenever feasible.
+
+14.30 Location
+
+ The Location response-header field is used to redirect the recipient
+ to a location other than the Request-URI for completion of the
+ request or identification of a new resource. For 201 (Created)
+ responses, the Location is that of the new resource which was created
+ by the request. For 3xx responses, the location SHOULD indicate the
+ server's preferred URI for automatic redirection to the resource. The
+ field value consists of a single absolute URI.
+
+ Location = "Location" ":" absoluteURI
+
+ An example is:
+
+ Location: http://www.w3.org/pub/WWW/People.html
+
+ Note: The Content-Location header field (section 14.14) differs
+ from Location in that the Content-Location identifies the original
+ location of the entity enclosed in the request. It is therefore
+ possible for a response to contain header fields for both Location
+ and Content-Location. Also see section 13.10 for cache
+ requirements of some methods.
+
+
+
+Fielding, et al. Standards Track [Page 135]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14.31 Max-Forwards
+
+ The Max-Forwards request-header field provides a mechanism with the
+ TRACE (section 9.8) and OPTIONS (section 9.2) methods to limit the
+ number of proxies or gateways that can forward the request to the
+ next inbound server. This can be useful when the client is attempting
+ to trace a request chain which appears to be failing or looping in
+ mid-chain.
+
+ Max-Forwards = "Max-Forwards" ":" 1*DIGIT
+
+ The Max-Forwards value is a decimal integer indicating the remaining
+ number of times this request message may be forwarded.
+
+ Each proxy or gateway recipient of a TRACE or OPTIONS request
+ containing a Max-Forwards header field MUST check and update its
+ value prior to forwarding the request. If the received value is zero
+ (0), the recipient MUST NOT forward the request; instead, it MUST
+ respond as the final recipient. If the received Max-Forwards value is
+ greater than zero, then the forwarded message MUST contain an updated
+ Max-Forwards field with a value decremented by one (1).
+
+ The Max-Forwards header field MAY be ignored for all other methods
+ defined by this specification and for any extension methods for which
+ it is not explicitly referred to as part of that method definition.
+
+14.32 Pragma
+
+ The Pragma general-header field is used to include implementation-
+ specific directives that might apply to any recipient along the
+ request/response chain. All pragma directives specify optional
+ behavior from the viewpoint of the protocol; however, some systems
+ MAY require that behavior be consistent with the directives.
+
+ Pragma = "Pragma" ":" 1#pragma-directive
+ pragma-directive = "no-cache" | extension-pragma
+ extension-pragma = token [ "=" ( token | quoted-string ) ]
+
+ When the no-cache directive is present in a request message, an
+ application SHOULD forward the request toward the origin server even
+ if it has a cached copy of what is being requested. This pragma
+ directive has the same semantics as the no-cache cache-directive (see
+ section 14.9) and is defined here for backward compatibility with
+ HTTP/1.0. Clients SHOULD include both header fields when a no-cache
+ request is sent to a server not known to be HTTP/1.1 compliant.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 136]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Pragma directives MUST be passed through by a proxy or gateway
+ application, regardless of their significance to that application,
+ since the directives might be applicable to all recipients along the
+ request/response chain. It is not possible to specify a pragma for a
+ specific recipient; however, any pragma directive not relevant to a
+ recipient SHOULD be ignored by that recipient.
+
+ HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the client had
+ sent "Cache-Control: no-cache". No new Pragma directives will be
+ defined in HTTP.
+
+ Note: because the meaning of "Pragma: no-cache as a response
+ header field is not actually specified, it does not provide a
+ reliable replacement for "Cache-Control: no-cache" in a response
+
+14.33 Proxy-Authenticate
+
+ The Proxy-Authenticate response-header field MUST be included as part
+ of a 407 (Proxy Authentication Required) response. The field value
+ consists of a challenge that indicates the authentication scheme and
+ parameters applicable to the proxy for this Request-URI.
+
+ Proxy-Authenticate = "Proxy-Authenticate" ":" 1#challenge
+
+ The HTTP access authentication process is described in "HTTP
+ Authentication: Basic and Digest Access Authentication" [43]. Unlike
+ WWW-Authenticate, the Proxy-Authenticate header field applies only to
+ the current connection and SHOULD NOT be passed on to downstream
+ clients. However, an intermediate proxy might need to obtain its own
+ credentials by requesting them from the downstream client, which in
+ some circumstances will appear as if the proxy is forwarding the
+ Proxy-Authenticate header field.
+
+14.34 Proxy-Authorization
+
+ The Proxy-Authorization request-header field allows the client to
+ identify itself (or its user) to a proxy which requires
+ authentication. The Proxy-Authorization field value consists of
+ credentials containing the authentication information of the user
+ agent for the proxy and/or realm of the resource being requested.
+
+ Proxy-Authorization = "Proxy-Authorization" ":" credentials
+
+ The HTTP access authentication process is described in "HTTP
+ Authentication: Basic and Digest Access Authentication" [43] . Unlike
+ Authorization, the Proxy-Authorization header field applies only to
+ the next outbound proxy that demanded authentication using the Proxy-
+ Authenticate field. When multiple proxies are used in a chain, the
+
+
+
+Fielding, et al. Standards Track [Page 137]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Proxy-Authorization header field is consumed by the first outbound
+ proxy that was expecting to receive credentials. A proxy MAY relay
+ the credentials from the client request to the next proxy if that is
+ the mechanism by which the proxies cooperatively authenticate a given
+ request.
+
+14.35 Range
+
+14.35.1 Byte Ranges
+
+ Since all HTTP entities are represented in HTTP messages as sequences
+ of bytes, the concept of a byte range is meaningful for any HTTP
+ entity. (However, not all clients and servers need to support byte-
+ range operations.)
+
+ Byte range specifications in HTTP apply to the sequence of bytes in
+ the entity-body (not necessarily the same as the message-body).
+
+ A byte range operation MAY specify a single range of bytes, or a set
+ of ranges within a single entity.
+
+ ranges-specifier = byte-ranges-specifier
+ byte-ranges-specifier = bytes-unit "=" byte-range-set
+ byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec )
+ byte-range-spec = first-byte-pos "-" [last-byte-pos]
+ first-byte-pos = 1*DIGIT
+ last-byte-pos = 1*DIGIT
+
+ The first-byte-pos value in a byte-range-spec gives the byte-offset
+ of the first byte in a range. The last-byte-pos value gives the
+ byte-offset of the last byte in the range; that is, the byte
+ positions specified are inclusive. Byte offsets start at zero.
+
+ If the last-byte-pos value is present, it MUST be greater than or
+ equal to the first-byte-pos in that byte-range-spec, or the byte-
+ range-spec is syntactically invalid. The recipient of a byte-range-
+ set that includes one or more syntactically invalid byte-range-spec
+ values MUST ignore the header field that includes that byte-range-
+ set.
+
+ If the last-byte-pos value is absent, or if the value is greater than
+ or equal to the current length of the entity-body, last-byte-pos is
+ taken to be equal to one less than the current length of the entity-
+ body in bytes.
+
+ By its choice of last-byte-pos, a client can limit the number of
+ bytes retrieved without knowing the size of the entity.
+
+
+
+
+Fielding, et al. Standards Track [Page 138]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ suffix-byte-range-spec = "-" suffix-length
+ suffix-length = 1*DIGIT
+
+ A suffix-byte-range-spec is used to specify the suffix of the
+ entity-body, of a length given by the suffix-length value. (That is,
+ this form specifies the last N bytes of an entity-body.) If the
+ entity is shorter than the specified suffix-length, the entire
+ entity-body is used.
+
+ If a syntactically valid byte-range-set includes at least one byte-
+ range-spec whose first-byte-pos is less than the current length of
+ the entity-body, or at least one suffix-byte-range-spec with a non-
+ zero suffix-length, then the byte-range-set is satisfiable.
+ Otherwise, the byte-range-set is unsatisfiable. If the byte-range-set
+ is unsatisfiable, the server SHOULD return a response with a status
+ of 416 (Requested range not satisfiable). Otherwise, the server
+ SHOULD return a response with a status of 206 (Partial Content)
+ containing the satisfiable ranges of the entity-body.
+
+ Examples of byte-ranges-specifier values (assuming an entity-body of
+ length 10000):
+
+ - The first 500 bytes (byte offsets 0-499, inclusive): bytes=0-
+ 499
+
+ - The second 500 bytes (byte offsets 500-999, inclusive):
+ bytes=500-999
+
+ - The final 500 bytes (byte offsets 9500-9999, inclusive):
+ bytes=-500
+
+ - Or bytes=9500-
+
+ - The first and last bytes only (bytes 0 and 9999): bytes=0-0,-1
+
+ - Several legal but not canonical specifications of the second 500
+ bytes (byte offsets 500-999, inclusive):
+ bytes=500-600,601-999
+ bytes=500-700,601-999
+
+14.35.2 Range Retrieval Requests
+
+ HTTP retrieval requests using conditional or unconditional GET
+ methods MAY request one or more sub-ranges of the entity, instead of
+ the entire entity, using the Range request header, which applies to
+ the entity returned as the result of the request:
+
+ Range = "Range" ":" ranges-specifier
+
+
+
+Fielding, et al. Standards Track [Page 139]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ A server MAY ignore the Range header. However, HTTP/1.1 origin
+ servers and intermediate caches ought to support byte ranges when
+ possible, since Range supports efficient recovery from partially
+ failed transfers, and supports efficient partial retrieval of large
+ entities.
+
+ If the server supports the Range header and the specified range or
+ ranges are appropriate for the entity:
+
+ - The presence of a Range header in an unconditional GET modifies
+ what is returned if the GET is otherwise successful. In other
+ words, the response carries a status code of 206 (Partial
+ Content) instead of 200 (OK).
+
+ - The presence of a Range header in a conditional GET (a request
+ using one or both of If-Modified-Since and If-None-Match, or
+ one or both of If-Unmodified-Since and If-Match) modifies what
+ is returned if the GET is otherwise successful and the
+ condition is true. It does not affect the 304 (Not Modified)
+ response returned if the conditional is false.
+
+ In some cases, it might be more appropriate to use the If-Range
+ header (see section 14.27) in addition to the Range header.
+
+ If a proxy that supports ranges receives a Range request, forwards
+ the request to an inbound server, and receives an entire entity in
+ reply, it SHOULD only return the requested range to its client. It
+ SHOULD store the entire received response in its cache if that is
+ consistent with its cache allocation policies.
+
+14.36 Referer
+
+ The Referer[sic] request-header field allows the client to specify,
+ for the server's benefit, the address (URI) of the resource from
+ which the Request-URI was obtained (the "referrer", although the
+ header field is misspelled.) The Referer request-header allows a
+ server to generate lists of back-links to resources for interest,
+ logging, optimized caching, etc. It also allows obsolete or mistyped
+ links to be traced for maintenance. The Referer field MUST NOT be
+ sent if the Request-URI was obtained from a source that does not have
+ its own URI, such as input from the user keyboard.
+
+ Referer = "Referer" ":" ( absoluteURI | relativeURI )
+
+ Example:
+
+ Referer: http://www.w3.org/hypertext/DataSources/Overview.html
+
+
+
+
+Fielding, et al. Standards Track [Page 140]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If the field value is a relative URI, it SHOULD be interpreted
+ relative to the Request-URI. The URI MUST NOT include a fragment. See
+ section 15.1.3 for security considerations.
+
+14.37 Retry-After
+
+ The Retry-After response-header field can be used with a 503 (Service
+ Unavailable) response to indicate how long the service is expected to
+ be unavailable to the requesting client. This field MAY also be used
+ with any 3xx (Redirection) response to indicate the minimum time the
+ user-agent is asked wait before issuing the redirected request. The
+ value of this field can be either an HTTP-date or an integer number
+ of seconds (in decimal) after the time of the response.
+
+ Retry-After = "Retry-After" ":" ( HTTP-date | delta-seconds )
+
+ Two examples of its use are
+
+ Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
+ Retry-After: 120
+
+ In the latter example, the delay is 2 minutes.
+
+14.38 Server
+
+ The Server response-header field contains information about the
+ software used by the origin server to handle the request. The field
+ can contain multiple product tokens (section 3.8) and comments
+ identifying the server and any significant subproducts. The product
+ tokens are listed in order of their significance for identifying the
+ application.
+
+ Server = "Server" ":" 1*( product | comment )
+
+ Example:
+
+ Server: CERN/3.0 libwww/2.17
+
+ If the response is being forwarded through a proxy, the proxy
+ application MUST NOT modify the Server response-header. Instead, it
+ SHOULD include a Via field (as described in section 14.45).
+
+ Note: Revealing the specific software version of the server might
+ allow the server machine to become more vulnerable to attacks
+ against software that is known to contain security holes. Server
+ implementors are encouraged to make this field a configurable
+ option.
+
+
+
+
+Fielding, et al. Standards Track [Page 141]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+14.39 TE
+
+ The TE request-header field indicates what extension transfer-codings
+ it is willing to accept in the response and whether or not it is
+ willing to accept trailer fields in a chunked transfer-coding. Its
+ value may consist of the keyword "trailers" and/or a comma-separated
+ list of extension transfer-coding names with optional accept
+ parameters (as described in section 3.6).
+
+ TE = "TE" ":" #( t-codings )
+ t-codings = "trailers" | ( transfer-extension [ accept-params ] )
+
+ The presence of the keyword "trailers" indicates that the client is
+ willing to accept trailer fields in a chunked transfer-coding, as
+ defined in section 3.6.1. This keyword is reserved for use with
+ transfer-coding values even though it does not itself represent a
+ transfer-coding.
+
+ Examples of its use are:
+
+ TE: deflate
+ TE:
+ TE: trailers, deflate;q=0.5
+
+ The TE header field only applies to the immediate connection.
+ Therefore, the keyword MUST be supplied within a Connection header
+ field (section 14.10) whenever TE is present in an HTTP/1.1 message.
+
+ A server tests whether a transfer-coding is acceptable, according to
+ a TE field, using these rules:
+
+ 1. The "chunked" transfer-coding is always acceptable. If the
+ keyword "trailers" is listed, the client indicates that it is
+ willing to accept trailer fields in the chunked response on
+ behalf of itself and any downstream clients. The implication is
+ that, if given, the client is stating that either all
+ downstream clients are willing to accept trailer fields in the
+ forwarded response, or that it will attempt to buffer the
+ response on behalf of downstream recipients.
+
+ Note: HTTP/1.1 does not define any means to limit the size of a
+ chunked response such that a client can be assured of buffering
+ the entire response.
+
+ 2. If the transfer-coding being tested is one of the transfer-
+ codings listed in the TE field, then it is acceptable unless it
+ is accompanied by a qvalue of 0. (As defined in section 3.9, a
+ qvalue of 0 means "not acceptable.")
+
+
+
+Fielding, et al. Standards Track [Page 142]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 3. If multiple transfer-codings are acceptable, then the
+ acceptable transfer-coding with the highest non-zero qvalue is
+ preferred. The "chunked" transfer-coding always has a qvalue
+ of 1.
+
+ If the TE field-value is empty or if no TE field is present, the only
+ transfer-coding is "chunked". A message with no transfer-coding is
+ always acceptable.
+
+14.40 Trailer
+
+ The Trailer general field value indicates that the given set of
+ header fields is present in the trailer of a message encoded with
+ chunked transfer-coding.
+
+ Trailer = "Trailer" ":" 1#field-name
+
+ An HTTP/1.1 message SHOULD include a Trailer header field in a
+ message using chunked transfer-coding with a non-empty trailer. Doing
+ so allows the recipient to know which header fields to expect in the
+ trailer.
+
+ If no Trailer header field is present, the trailer SHOULD NOT include
+ any header fields. See section 3.6.1 for restrictions on the use of
+ trailer fields in a "chunked" transfer-coding.
+
+ Message header fields listed in the Trailer header field MUST NOT
+ include the following header fields:
+
+ . Transfer-Encoding
+
+ . Content-Length
+
+ . Trailer
+
+14.41 Transfer-Encoding
+
+ The Transfer-Encoding general-header field indicates what (if any)
+ type of transformation has been applied to the message body in order
+ to safely transfer it between the sender and the recipient. This
+ differs from the content-coding in that the transfer-coding is a
+ property of the message, not of the entity.
+
+ Transfer-Encoding = "Transfer-Encoding" ":" 1#transfer-coding
+
+ Transfer-codings are defined in section 3.6. An example is:
+
+ Transfer-Encoding: chunked
+
+
+
+Fielding, et al. Standards Track [Page 143]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ If multiple encodings have been applied to an entity, the transfer-
+ codings MUST be listed in the order in which they were applied.
+ Additional information about the encoding parameters MAY be provided
+ by other entity-header fields not defined by this specification.
+
+ Many older HTTP/1.0 applications do not understand the Transfer-
+ Encoding header.
+
+14.42 Upgrade
+
+ The Upgrade general-header allows the client to specify what
+ additional communication protocols it supports and would like to use
+ if the server finds it appropriate to switch protocols. The server
+ MUST use the Upgrade header field within a 101 (Switching Protocols)
+ response to indicate which protocol(s) are being switched.
+
+ Upgrade = "Upgrade" ":" 1#product
+
+ For example,
+
+ Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
+
+ The Upgrade header field is intended to provide a simple mechanism
+ for transition from HTTP/1.1 to some other, incompatible protocol. It
+ does so by allowing the client to advertise its desire to use another
+ protocol, such as a later version of HTTP with a higher major version
+ number, even though the current request has been made using HTTP/1.1.
+ This eases the difficult transition between incompatible protocols by
+ allowing the client to initiate a request in the more commonly
+ supported protocol while indicating to the server that it would like
+ to use a "better" protocol if available (where "better" is determined
+ by the server, possibly according to the nature of the method and/or
+ resource being requested).
+
+ The Upgrade header field only applies to switching application-layer
+ protocols upon the existing transport-layer connection. Upgrade
+ cannot be used to insist on a protocol change; its acceptance and use
+ by the server is optional. The capabilities and nature of the
+ application-layer communication after the protocol change is entirely
+ dependent upon the new protocol chosen, although the first action
+ after changing the protocol MUST be a response to the initial HTTP
+ request containing the Upgrade header field.
+
+ The Upgrade header field only applies to the immediate connection.
+ Therefore, the upgrade keyword MUST be supplied within a Connection
+ header field (section 14.10) whenever Upgrade is present in an
+ HTTP/1.1 message.
+
+
+
+
+Fielding, et al. Standards Track [Page 144]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The Upgrade header field cannot be used to indicate a switch to a
+ protocol on a different connection. For that purpose, it is more
+ appropriate to use a 301, 302, 303, or 305 redirection response.
+
+ This specification only defines the protocol name "HTTP" for use by
+ the family of Hypertext Transfer Protocols, as defined by the HTTP
+ version rules of section 3.1 and future updates to this
+ specification. Any token can be used as a protocol name; however, it
+ will only be useful if both the client and server associate the name
+ with the same protocol.
+
+14.43 User-Agent
+
+ The User-Agent request-header field contains information about the
+ user agent originating the request. This is for statistical purposes,
+ the tracing of protocol violations, and automated recognition of user
+ agents for the sake of tailoring responses to avoid particular user
+ agent limitations. User agents SHOULD include this field with
+ requests. The field can contain multiple product tokens (section 3.8)
+ and comments identifying the agent and any subproducts which form a
+ significant part of the user agent. By convention, the product tokens
+ are listed in order of their significance for identifying the
+ application.
+
+ User-Agent = "User-Agent" ":" 1*( product | comment )
+
+ Example:
+
+ User-Agent: CERN-LineMode/2.15 libwww/2.17b3
+
+14.44 Vary
+
+ The Vary field value indicates the set of request-header fields that
+ fully determines, while the response is fresh, whether a cache is
+ permitted to use the response to reply to a subsequent request
+ without revalidation. For uncacheable or stale responses, the Vary
+ field value advises the user agent about the criteria that were used
+ to select the representation. A Vary field value of "*" implies that
+ a cache cannot determine from the request headers of a subsequent
+ request whether this response is the appropriate representation. See
+ section 13.6 for use of the Vary header field by caches.
+
+ Vary = "Vary" ":" ( "*" | 1#field-name )
+
+ An HTTP/1.1 server SHOULD include a Vary header field with any
+ cacheable response that is subject to server-driven negotiation.
+ Doing so allows a cache to properly interpret future requests on that
+ resource and informs the user agent about the presence of negotiation
+
+
+
+Fielding, et al. Standards Track [Page 145]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ on that resource. A server MAY include a Vary header field with a
+ non-cacheable response that is subject to server-driven negotiation,
+ since this might provide the user agent with useful information about
+ the dimensions over which the response varies at the time of the
+ response.
+
+ A Vary field value consisting of a list of field-names signals that
+ the representation selected for the response is based on a selection
+ algorithm which considers ONLY the listed request-header field values
+ in selecting the most appropriate representation. A cache MAY assume
+ that the same selection will be made for future requests with the
+ same values for the listed field names, for the duration of time for
+ which the response is fresh.
+
+ The field-names given are not limited to the set of standard
+ request-header fields defined by this specification. Field names are
+ case-insensitive.
+
+ A Vary field value of "*" signals that unspecified parameters not
+ limited to the request-headers (e.g., the network address of the
+ client), play a role in the selection of the response representation.
+ The "*" value MUST NOT be generated by a proxy server; it may only be
+ generated by an origin server.
+
+14.45 Via
+
+ The Via general-header field MUST be used by gateways and proxies to
+ indicate the intermediate protocols and recipients between the user
+ agent and the server on requests, and between the origin server and
+ the client on responses. It is analogous to the "Received" field of
+ RFC 822 [9] and is intended to be used for tracking message forwards,
+ avoiding request loops, and identifying the protocol capabilities of
+ all senders along the request/response chain.
+
+ Via = "Via" ":" 1#( received-protocol received-by [ comment ] )
+ received-protocol = [ protocol-name "/" ] protocol-version
+ protocol-name = token
+ protocol-version = token
+ received-by = ( host [ ":" port ] ) | pseudonym
+ pseudonym = token
+
+ The received-protocol indicates the protocol version of the message
+ received by the server or client along each segment of the
+ request/response chain. The received-protocol version is appended to
+ the Via field value when the message is forwarded so that information
+ about the protocol capabilities of upstream applications remains
+ visible to all recipients.
+
+
+
+
+Fielding, et al. Standards Track [Page 146]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The protocol-name is optional if and only if it would be "HTTP". The
+ received-by field is normally the host and optional port number of a
+ recipient server or client that subsequently forwarded the message.
+ However, if the real host is considered to be sensitive information,
+ it MAY be replaced by a pseudonym. If the port is not given, it MAY
+ be assumed to be the default port of the received-protocol.
+
+ Multiple Via field values represents each proxy or gateway that has
+ forwarded the message. Each recipient MUST append its information
+ such that the end result is ordered according to the sequence of
+ forwarding applications.
+
+ Comments MAY be used in the Via header field to identify the software
+ of the recipient proxy or gateway, analogous to the User-Agent and
+ Server header fields. However, all comments in the Via field are
+ optional and MAY be removed by any recipient prior to forwarding the
+ message.
+
+ For example, a request message could be sent from an HTTP/1.0 user
+ agent to an internal proxy code-named "fred", which uses HTTP/1.1 to
+ forward the request to a public proxy at nowhere.com, which completes
+ the request by forwarding it to the origin server at www.ics.uci.edu.
+ The request received by www.ics.uci.edu would then have the following
+ Via header field:
+
+ Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
+
+ Proxies and gateways used as a portal through a network firewall
+ SHOULD NOT, by default, forward the names and ports of hosts within
+ the firewall region. This information SHOULD only be propagated if
+ explicitly enabled. If not enabled, the received-by host of any host
+ behind the firewall SHOULD be replaced by an appropriate pseudonym
+ for that host.
+
+ For organizations that have strong privacy requirements for hiding
+ internal structures, a proxy MAY combine an ordered subsequence of
+ Via header field entries with identical received-protocol values into
+ a single such entry. For example,
+
+ Via: 1.0 ricky, 1.1 ethel, 1.1 fred, 1.0 lucy
+
+ could be collapsed to
+
+ Via: 1.0 ricky, 1.1 mertz, 1.0 lucy
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 147]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Applications SHOULD NOT combine multiple entries unless they are all
+ under the same organizational control and the hosts have already been
+ replaced by pseudonyms. Applications MUST NOT combine entries which
+ have different received-protocol values.
+
+14.46 Warning
+
+ The Warning general-header field is used to carry additional
+ information about the status or transformation of a message which
+ might not be reflected in the message. This information is typically
+ used to warn about a possible lack of semantic transparency from
+ caching operations or transformations applied to the entity body of
+ the message.
+
+ Warning headers are sent with responses using:
+
+ Warning = "Warning" ":" 1#warning-value
+
+ warning-value = warn-code SP warn-agent SP warn-text
+ [SP warn-date]
+
+ warn-code = 3DIGIT
+ warn-agent = ( host [ ":" port ] ) | pseudonym
+ ; the name or pseudonym of the server adding
+ ; the Warning header, for use in debugging
+ warn-text = quoted-string
+ warn-date = <"> HTTP-date <">
+
+ A response MAY carry more than one Warning header.
+
+ The warn-text SHOULD be in a natural language and character set that
+ is most likely to be intelligible to the human user receiving the
+ response. This decision MAY be based on any available knowledge, such
+ as the location of the cache or user, the Accept-Language field in a
+ request, the Content-Language field in a response, etc. The default
+ language is English and the default character set is ISO-8859-1.
+
+ If a character set other than ISO-8859-1 is used, it MUST be encoded
+ in the warn-text using the method described in RFC 2047 [14].
+
+ Warning headers can in general be applied to any message, however
+ some specific warn-codes are specific to caches and can only be
+ applied to response messages. New Warning headers SHOULD be added
+ after any existing Warning headers. A cache MUST NOT delete any
+ Warning header that it received with a message. However, if a cache
+ successfully validates a cache entry, it SHOULD remove any Warning
+ headers previously attached to that entry except as specified for
+
+
+
+
+Fielding, et al. Standards Track [Page 148]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ specific Warning codes. It MUST then add any Warning headers received
+ in the validating response. In other words, Warning headers are those
+ that would be attached to the most recent relevant response.
+
+ When multiple Warning headers are attached to a response, the user
+ agent ought to inform the user of as many of them as possible, in the
+ order that they appear in the response. If it is not possible to
+ inform the user of all of the warnings, the user agent SHOULD follow
+ these heuristics:
+
+ - Warnings that appear early in the response take priority over
+ those appearing later in the response.
+
+ - Warnings in the user's preferred character set take priority
+ over warnings in other character sets but with identical warn-
+ codes and warn-agents.
+
+ Systems that generate multiple Warning headers SHOULD order them with
+ this user agent behavior in mind.
+
+ Requirements for the behavior of caches with respect to Warnings are
+ stated in section 13.1.2.
+
+ This is a list of the currently-defined warn-codes, each with a
+ recommended warn-text in English, and a description of its meaning.
+
+ 110 Response is stale
+ MUST be included whenever the returned response is stale.
+
+ 111 Revalidation failed
+ MUST be included if a cache returns a stale response because an
+ attempt to revalidate the response failed, due to an inability to
+ reach the server.
+
+ 112 Disconnected operation
+ SHOULD be included if the cache is intentionally disconnected from
+ the rest of the network for a period of time.
+
+ 113 Heuristic expiration
+ MUST be included if the cache heuristically chose a freshness
+ lifetime greater than 24 hours and the response's age is greater
+ than 24 hours.
+
+ 199 Miscellaneous warning
+ The warning text MAY include arbitrary information to be presented
+ to a human user, or logged. A system receiving this warning MUST
+ NOT take any automated action, besides presenting the warning to
+ the user.
+
+
+
+Fielding, et al. Standards Track [Page 149]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 214 Transformation applied
+ MUST be added by an intermediate cache or proxy if it applies any
+ transformation changing the content-coding (as specified in the
+ Content-Encoding header) or media-type (as specified in the
+ Content-Type header) of the response, or the entity-body of the
+ response, unless this Warning code already appears in the response.
+
+ 299 Miscellaneous persistent warning
+ The warning text MAY include arbitrary information to be presented
+ to a human user, or logged. A system receiving this warning MUST
+ NOT take any automated action.
+
+ If an implementation sends a message with one or more Warning headers
+ whose version is HTTP/1.0 or lower, then the sender MUST include in
+ each warning-value a warn-date that matches the date in the response.
+
+ If an implementation receives a message with a warning-value that
+ includes a warn-date, and that warn-date is different from the Date
+ value in the response, then that warning-value MUST be deleted from
+ the message before storing, forwarding, or using it. (This prevents
+ bad consequences of naive caching of Warning header fields.) If all
+ of the warning-values are deleted for this reason, the Warning header
+ MUST be deleted as well.
+
+14.47 WWW-Authenticate
+
+ The WWW-Authenticate response-header field MUST be included in 401
+ (Unauthorized) response messages. The field value consists of at
+ least one challenge that indicates the authentication scheme(s) and
+ parameters applicable to the Request-URI.
+
+ WWW-Authenticate = "WWW-Authenticate" ":" 1#challenge
+
+ The HTTP access authentication process is described in "HTTP
+ Authentication: Basic and Digest Access Authentication" [43]. User
+ agents are advised to take special care in parsing the WWW-
+ Authenticate field value as it might contain more than one challenge,
+ or if more than one WWW-Authenticate header field is provided, the
+ contents of a challenge itself can contain a comma-separated list of
+ authentication parameters.
+
+15 Security Considerations
+
+ This section is meant to inform application developers, information
+ providers, and users of the security limitations in HTTP/1.1 as
+ described by this document. The discussion does not include
+ definitive solutions to the problems revealed, though it does make
+ some suggestions for reducing security risks.
+
+
+
+Fielding, et al. Standards Track [Page 150]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+15.1 Personal Information
+
+ HTTP clients are often privy to large amounts of personal information
+ (e.g. the user's name, location, mail address, passwords, encryption
+ keys, etc.), and SHOULD be very careful to prevent unintentional
+ leakage of this information via the HTTP protocol to other sources.
+ We very strongly recommend that a convenient interface be provided
+ for the user to control dissemination of such information, and that
+ designers and implementors be particularly careful in this area.
+ History shows that errors in this area often create serious security
+ and/or privacy problems and generate highly adverse publicity for the
+ implementor's company.
+
+15.1.1 Abuse of Server Log Information
+
+ A server is in the position to save personal data about a user's
+ requests which might identify their reading patterns or subjects of
+ interest. This information is clearly confidential in nature and its
+ handling can be constrained by law in certain countries. People using
+ the HTTP protocol to provide data are responsible for ensuring that
+ such material is not distributed without the permission of any
+ individuals that are identifiable by the published results.
+
+15.1.2 Transfer of Sensitive Information
+
+ Like any generic data transfer protocol, HTTP cannot regulate the
+ content of the data that is transferred, nor is there any a priori
+ method of determining the sensitivity of any particular piece of
+ information within the context of any given request. Therefore,
+ applications SHOULD supply as much control over this information as
+ possible to the provider of that information. Four header fields are
+ worth special mention in this context: Server, Via, Referer and From.
+
+ Revealing the specific software version of the server might allow the
+ server machine to become more vulnerable to attacks against software
+ that is known to contain security holes. Implementors SHOULD make the
+ Server header field a configurable option.
+
+ Proxies which serve as a portal through a network firewall SHOULD
+ take special precautions regarding the transfer of header information
+ that identifies the hosts behind the firewall. In particular, they
+ SHOULD remove, or replace with sanitized versions, any Via fields
+ generated behind the firewall.
+
+ The Referer header allows reading patterns to be studied and reverse
+ links drawn. Although it can be very useful, its power can be abused
+ if user details are not separated from the information contained in
+
+
+
+
+Fielding, et al. Standards Track [Page 151]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ the Referer. Even when the personal information has been removed, the
+ Referer header might indicate a private document's URI whose
+ publication would be inappropriate.
+
+ The information sent in the From field might conflict with the user's
+ privacy interests or their site's security policy, and hence it
+ SHOULD NOT be transmitted without the user being able to disable,
+ enable, and modify the contents of the field. The user MUST be able
+ to set the contents of this field within a user preference or
+ application defaults configuration.
+
+ We suggest, though do not require, that a convenient toggle interface
+ be provided for the user to enable or disable the sending of From and
+ Referer information.
+
+ The User-Agent (section 14.43) or Server (section 14.38) header
+ fields can sometimes be used to determine that a specific client or
+ server have a particular security hole which might be exploited.
+ Unfortunately, this same information is often used for other valuable
+ purposes for which HTTP currently has no better mechanism.
+
+15.1.3 Encoding Sensitive Information in URI's
+
+ Because the source of a link might be private information or might
+ reveal an otherwise private information source, it is strongly
+ recommended that the user be able to select whether or not the
+ Referer field is sent. For example, a browser client could have a
+ toggle switch for browsing openly/anonymously, which would
+ respectively enable/disable the sending of Referer and From
+ information.
+
+ Clients SHOULD NOT include a Referer header field in a (non-secure)
+ HTTP request if the referring page was transferred with a secure
+ protocol.
+
+ Authors of services which use the HTTP protocol SHOULD NOT use GET
+ based forms for the submission of sensitive data, because this will
+ cause this data to be encoded in the Request-URI. Many existing
+ servers, proxies, and user agents will log the request URI in some
+ place where it might be visible to third parties. Servers can use
+ POST-based form submission instead
+
+15.1.4 Privacy Issues Connected to Accept Headers
+
+ Accept request-headers can reveal information about the user to all
+ servers which are accessed. The Accept-Language header in particular
+ can reveal information the user would consider to be of a private
+ nature, because the understanding of particular languages is often
+
+
+
+Fielding, et al. Standards Track [Page 152]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ strongly correlated to the membership of a particular ethnic group.
+ User agents which offer the option to configure the contents of an
+ Accept-Language header to be sent in every request are strongly
+ encouraged to let the configuration process include a message which
+ makes the user aware of the loss of privacy involved.
+
+ An approach that limits the loss of privacy would be for a user agent
+ to omit the sending of Accept-Language headers by default, and to ask
+ the user whether or not to start sending Accept-Language headers to a
+ server if it detects, by looking for any Vary response-header fields
+ generated by the server, that such sending could improve the quality
+ of service.
+
+ Elaborate user-customized accept header fields sent in every request,
+ in particular if these include quality values, can be used by servers
+ as relatively reliable and long-lived user identifiers. Such user
+ identifiers would allow content providers to do click-trail tracking,
+ and would allow collaborating content providers to match cross-server
+ click-trails or form submissions of individual users. Note that for
+ many users not behind a proxy, the network address of the host
+ running the user agent will also serve as a long-lived user
+ identifier. In environments where proxies are used to enhance
+ privacy, user agents ought to be conservative in offering accept
+ header configuration options to end users. As an extreme privacy
+ measure, proxies could filter the accept headers in relayed requests.
+ General purpose user agents which provide a high degree of header
+ configurability SHOULD warn users about the loss of privacy which can
+ be involved.
+
+15.2 Attacks Based On File and Path Names
+
+ Implementations of HTTP origin servers SHOULD be careful to restrict
+ the documents returned by HTTP requests to be only those that were
+ intended by the server administrators. If an HTTP server translates
+ HTTP URIs directly into file system calls, the server MUST take
+ special care not to serve files that were not intended to be
+ delivered to HTTP clients. For example, UNIX, Microsoft Windows, and
+ other operating systems use ".." as a path component to indicate a
+ directory level above the current one. On such a system, an HTTP
+ server MUST disallow any such construct in the Request-URI if it
+ would otherwise allow access to a resource outside those intended to
+ be accessible via the HTTP server. Similarly, files intended for
+ reference only internally to the server (such as access control
+ files, configuration files, and script code) MUST be protected from
+ inappropriate retrieval, since they might contain sensitive
+ information. Experience has shown that minor bugs in such HTTP server
+ implementations have turned into security risks.
+
+
+
+
+Fielding, et al. Standards Track [Page 153]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+15.3 DNS Spoofing
+
+ Clients using HTTP rely heavily on the Domain Name Service, and are
+ thus generally prone to security attacks based on the deliberate
+ mis-association of IP addresses and DNS names. Clients need to be
+ cautious in assuming the continuing validity of an IP number/DNS name
+ association.
+
+ In particular, HTTP clients SHOULD rely on their name resolver for
+ confirmation of an IP number/DNS name association, rather than
+ caching the result of previous host name lookups. Many platforms
+ already can cache host name lookups locally when appropriate, and
+ they SHOULD be configured to do so. It is proper for these lookups to
+ be cached, however, only when the TTL (Time To Live) information
+ reported by the name server makes it likely that the cached
+ information will remain useful.
+
+ If HTTP clients cache the results of host name lookups in order to
+ achieve a performance improvement, they MUST observe the TTL
+ information reported by DNS.
+
+ If HTTP clients do not observe this rule, they could be spoofed when
+ a previously-accessed server's IP address changes. As network
+ renumbering is expected to become increasingly common [24], the
+ possibility of this form of attack will grow. Observing this
+ requirement thus reduces this potential security vulnerability.
+
+ This requirement also improves the load-balancing behavior of clients
+ for replicated servers using the same DNS name and reduces the
+ likelihood of a user's experiencing failure in accessing sites which
+ use that strategy.
+
+15.4 Location Headers and Spoofing
+
+ If a single server supports multiple organizations that do not trust
+ one another, then it MUST check the values of Location and Content-
+ Location headers in responses that are generated under control of
+ said organizations to make sure that they do not attempt to
+ invalidate resources over which they have no authority.
+
+15.5 Content-Disposition Issues
+
+ RFC 1806 [35], from which the often implemented Content-Disposition
+ (see section 19.5.1) header in HTTP is derived, has a number of very
+ serious security considerations. Content-Disposition is not part of
+ the HTTP standard, but since it is widely implemented, we are
+ documenting its use and risks for implementors. See RFC 2183 [49]
+ (which updates RFC 1806) for details.
+
+
+
+Fielding, et al. Standards Track [Page 154]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+15.6 Authentication Credentials and Idle Clients
+
+ Existing HTTP clients and user agents typically retain authentication
+ information indefinitely. HTTP/1.1. does not provide a method for a
+ server to direct clients to discard these cached credentials. This is
+ a significant defect that requires further extensions to HTTP.
+ Circumstances under which credential caching can interfere with the
+ application's security model include but are not limited to:
+
+ - Clients which have been idle for an extended period following
+ which the server might wish to cause the client to reprompt the
+ user for credentials.
+
+ - Applications which include a session termination indication
+ (such as a `logout' or `commit' button on a page) after which
+ the server side of the application `knows' that there is no
+ further reason for the client to retain the credentials.
+
+ This is currently under separate study. There are a number of work-
+ arounds to parts of this problem, and we encourage the use of
+ password protection in screen savers, idle time-outs, and other
+ methods which mitigate the security problems inherent in this
+ problem. In particular, user agents which cache credentials are
+ encouraged to provide a readily accessible mechanism for discarding
+ cached credentials under user control.
+
+15.7 Proxies and Caching
+
+ By their very nature, HTTP proxies are men-in-the-middle, and
+ represent an opportunity for man-in-the-middle attacks. Compromise of
+ the systems on which the proxies run can result in serious security
+ and privacy problems. Proxies have access to security-related
+ information, personal information about individual users and
+ organizations, and proprietary information belonging to users and
+ content providers. A compromised proxy, or a proxy implemented or
+ configured without regard to security and privacy considerations,
+ might be used in the commission of a wide range of potential attacks.
+
+ Proxy operators should protect the systems on which proxies run as
+ they would protect any system that contains or transports sensitive
+ information. In particular, log information gathered at proxies often
+ contains highly sensitive personal information, and/or information
+ about organizations. Log information should be carefully guarded, and
+ appropriate guidelines for use developed and followed. (Section
+ 15.1.1).
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 155]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Caching proxies provide additional potential vulnerabilities, since
+ the contents of the cache represent an attractive target for
+ malicious exploitation. Because cache contents persist after an HTTP
+ request is complete, an attack on the cache can reveal information
+ long after a user believes that the information has been removed from
+ the network. Therefore, cache contents should be protected as
+ sensitive information.
+
+ Proxy implementors should consider the privacy and security
+ implications of their design and coding decisions, and of the
+ configuration options they provide to proxy operators (especially the
+ default configuration).
+
+ Users of a proxy need to be aware that they are no trustworthier than
+ the people who run the proxy; HTTP itself cannot solve this problem.
+
+ The judicious use of cryptography, when appropriate, may suffice to
+ protect against a broad range of security and privacy attacks. Such
+ cryptography is beyond the scope of the HTTP/1.1 specification.
+
+15.7.1 Denial of Service Attacks on Proxies
+
+ They exist. They are hard to defend against. Research continues.
+ Beware.
+
+16 Acknowledgments
+
+ This specification makes heavy use of the augmented BNF and generic
+ constructs defined by David H. Crocker for RFC 822 [9]. Similarly, it
+ reuses many of the definitions provided by Nathaniel Borenstein and
+ Ned Freed for MIME [7]. We hope that their inclusion in this
+ specification will help reduce past confusion over the relationship
+ between HTTP and Internet mail message formats.
+
+ The HTTP protocol has evolved considerably over the years. It has
+ benefited from a large and active developer community--the many
+ people who have participated on the www-talk mailing list--and it is
+ that community which has been most responsible for the success of
+ HTTP and of the World-Wide Web in general. Marc Andreessen, Robert
+ Cailliau, Daniel W. Connolly, Bob Denny, John Franks, Jean-Francois
+ Groff, Phillip M. Hallam-Baker, Hakon W. Lie, Ari Luotonen, Rob
+ McCool, Lou Montulli, Dave Raggett, Tony Sanders, and Marc
+ VanHeyningen deserve special recognition for their efforts in
+ defining early aspects of the protocol.
+
+ This document has benefited greatly from the comments of all those
+ participating in the HTTP-WG. In addition to those already mentioned,
+ the following individuals have contributed to this specification:
+
+
+
+Fielding, et al. Standards Track [Page 156]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Gary Adams Ross Patterson
+ Harald Tveit Alvestrand Albert Lunde
+ Keith Ball John C. Mallery
+ Brian Behlendorf Jean-Philippe Martin-Flatin
+ Paul Burchard Mitra
+ Maurizio Codogno David Morris
+ Mike Cowlishaw Gavin Nicol
+ Roman Czyborra Bill Perry
+ Michael A. Dolan Jeffrey Perry
+ David J. Fiander Scott Powers
+ Alan Freier Owen Rees
+ Marc Hedlund Luigi Rizzo
+ Greg Herlihy David Robinson
+ Koen Holtman Marc Salomon
+ Alex Hopmann Rich Salz
+ Bob Jernigan Allan M. Schiffman
+ Shel Kaphan Jim Seidman
+ Rohit Khare Chuck Shotton
+ John Klensin Eric W. Sink
+ Martijn Koster Simon E. Spero
+ Alexei Kosut Richard N. Taylor
+ David M. Kristol Robert S. Thau
+ Daniel LaLiberte Bill (BearHeart) Weinman
+ Ben Laurie Francois Yergeau
+ Paul J. Leach Mary Ellen Zurko
+ Daniel DuBois Josh Cohen
+
+
+ Much of the content and presentation of the caching design is due to
+ suggestions and comments from individuals including: Shel Kaphan,
+ Paul Leach, Koen Holtman, David Morris, and Larry Masinter.
+
+ Most of the specification of ranges is based on work originally done
+ by Ari Luotonen and John Franks, with additional input from Steve
+ Zilles.
+
+ Thanks to the "cave men" of Palo Alto. You know who you are.
+
+ Jim Gettys (the current editor of this document) wishes particularly
+ to thank Roy Fielding, the previous editor of this document, along
+ with John Klensin, Jeff Mogul, Paul Leach, Dave Kristol, Koen
+ Holtman, John Franks, Josh Cohen, Alex Hopmann, Scott Lawrence, and
+ Larry Masinter for their help. And thanks go particularly to Jeff
+ Mogul and Scott Lawrence for performing the "MUST/MAY/SHOULD" audit.
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 157]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ The Apache Group, Anselm Baird-Smith, author of Jigsaw, and Henrik
+ Frystyk implemented RFC 2068 early, and we wish to thank them for the
+ discovery of many of the problems that this document attempts to
+ rectify.
+
+17 References
+
+ [1] Alvestrand, H., "Tags for the Identification of Languages", RFC
+ 1766, March 1995.
+
+ [2] Anklesaria, F., McCahill, M., Lindner, P., Johnson, D., Torrey,
+ D. and B. Alberti, "The Internet Gopher Protocol (a distributed
+ document search and retrieval protocol)", RFC 1436, March 1993.
+
+ [3] Berners-Lee, T., "Universal Resource Identifiers in WWW", RFC
+ 1630, June 1994.
+
+ [4] Berners-Lee, T., Masinter, L. and M. McCahill, "Uniform Resource
+ Locators (URL)", RFC 1738, December 1994.
+
+ [5] Berners-Lee, T. and D. Connolly, "Hypertext Markup Language -
+ 2.0", RFC 1866, November 1995.
+
+ [6] Berners-Lee, T., Fielding, R. and H. Frystyk, "Hypertext Transfer
+ Protocol -- HTTP/1.0", RFC 1945, May 1996.
+
+ [7] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part One: Format of Internet Message Bodies",
+ RFC 2045, November 1996.
+
+ [8] Braden, R., "Requirements for Internet Hosts -- Communication
+ Layers", STD 3, RFC 1123, October 1989.
+
+ [9] Crocker, D., "Standard for The Format of ARPA Internet Text
+ Messages", STD 11, RFC 822, August 1982.
+
+ [10] Davis, F., Kahle, B., Morris, H., Salem, J., Shen, T., Wang, R.,
+ Sui, J., and M. Grinbaum, "WAIS Interface Protocol Prototype
+ Functional Specification," (v1.5), Thinking Machines
+ Corporation, April 1990.
+
+ [11] Fielding, R., "Relative Uniform Resource Locators", RFC 1808,
+ June 1995.
+
+ [12] Horton, M. and R. Adams, "Standard for Interchange of USENET
+ Messages", RFC 1036, December 1987.
+
+
+
+
+
+Fielding, et al. Standards Track [Page 158]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ [13] Kantor, B. and P. Lapsley, "Network News Transfer Protocol", RFC
+ 977, February 1986.
+
+ [14] Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part
+ Three: Message Header Extensions for Non-ASCII Text", RFC 2047,
+ November 1996.
+
+ [15] Nebel, E. and L. Masinter, "Form-based File Upload in HTML", RFC
+ 1867, November 1995.
+
+ [16] Postel, J., "Simple Mail Transfer Protocol", STD 10, RFC 821,
+ August 1982.
+
+ [17] Postel, J., "Media Type Registration Procedure", RFC 1590,
+ November 1996.
+
+ [18] Postel, J. and J. Reynolds, "File Transfer Protocol", STD 9, RFC
+ 959, October 1985.
+
+ [19] Reynolds, J. and J. Postel, "Assigned Numbers", STD 2, RFC 1700,
+ October 1994.
+
+ [20] Sollins, K. and L. Masinter, "Functional Requirements for
+ Uniform Resource Names", RFC 1737, December 1994.
+
+ [21] US-ASCII. Coded Character Set - 7-Bit American Standard Code for
+ Information Interchange. Standard ANSI X3.4-1986, ANSI, 1986.
+
+ [22] ISO-8859. International Standard -- Information Processing --
+ 8-bit Single-Byte Coded Graphic Character Sets --
+ Part 1: Latin alphabet No. 1, ISO-8859-1:1987.
+ Part 2: Latin alphabet No. 2, ISO-8859-2, 1987.
+ Part 3: Latin alphabet No. 3, ISO-8859-3, 1988.
+ Part 4: Latin alphabet No. 4, ISO-8859-4, 1988.
+ Part 5: Latin/Cyrillic alphabet, ISO-8859-5, 1988.
+ Part 6: Latin/Arabic alphabet, ISO-8859-6, 1987.
+ Part 7: Latin/Greek alphabet, ISO-8859-7, 1987.
+ Part 8: Latin/Hebrew alphabet, ISO-8859-8, 1988.
+ Part 9: Latin alphabet No. 5, ISO-8859-9, 1990.
+
+ [23] Meyers, J. and M. Rose, "The Content-MD5 Header Field", RFC
+ 1864, October 1995.
+
+ [24] Carpenter, B. and Y. Rekhter, "Renumbering Needs Work", RFC
+ 1900, February 1996.
+
+ [25] Deutsch, P., "GZIP file format specification version 4.3", RFC
+ 1952, May 1996.
+
+
+
+Fielding, et al. Standards Track [Page 159]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ [26] Venkata N. Padmanabhan, and Jeffrey C. Mogul. "Improving HTTP
+ Latency", Computer Networks and ISDN Systems, v. 28, pp. 25-35,
+ Dec. 1995. Slightly revised version of paper in Proc. 2nd
+ International WWW Conference '94: Mosaic and the Web, Oct. 1994,
+ which is available at
+ http://www.ncsa.uiuc.edu/SDG/IT94/Proceedings/DDay/mogul/HTTPLat
+ ency.html.
+
+ [27] Joe Touch, John Heidemann, and Katia Obraczka. "Analysis of HTTP
+ Performance", <URL: http://www.isi.edu/touch/pubs/http-perf96/>,
+ ISI Research Report ISI/RR-98-463, (original report dated Aug.
+ 1996), USC/Information Sciences Institute, August 1998.
+
+ [28] Mills, D., "Network Time Protocol (Version 3) Specification,
+ Implementation and Analysis", RFC 1305, March 1992.
+
+ [29] Deutsch, P., "DEFLATE Compressed Data Format Specification
+ version 1.3", RFC 1951, May 1996.
+
+ [30] S. Spero, "Analysis of HTTP Performance Problems,"
+ http://sunsite.unc.edu/mdma-release/http-prob.html.
+
+ [31] Deutsch, P. and J. Gailly, "ZLIB Compressed Data Format
+ Specification version 3.3", RFC 1950, May 1996.
+
+ [32] Franks, J., Hallam-Baker, P., Hostetler, J., Leach, P.,
+ Luotonen, A., Sink, E. and L. Stewart, "An Extension to HTTP:
+ Digest Access Authentication", RFC 2069, January 1997.
+
+ [33] Fielding, R., Gettys, J., Mogul, J., Frystyk, H. and T.
+ Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC
+ 2068, January 1997.
+
+ [34] Bradner, S., "Key words for use in RFCs to Indicate Requirement
+ Levels", BCP 14, RFC 2119, March 1997.
+
+ [35] Troost, R. and Dorner, S., "Communicating Presentation
+ Information in Internet Messages: The Content-Disposition
+ Header", RFC 1806, June 1995.
+
+ [36] Mogul, J., Fielding, R., Gettys, J. and H. Frystyk, "Use and
+ Interpretation of HTTP Version Numbers", RFC 2145, May 1997.
+ [jg639]
+
+ [37] Palme, J., "Common Internet Message Headers", RFC 2076, February
+ 1997. [jg640]
+
+
+
+
+
+Fielding, et al. Standards Track [Page 160]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ [38] Yergeau, F., "UTF-8, a transformation format of Unicode and
+ ISO-10646", RFC 2279, January 1998. [jg641]
+
+ [39] Nielsen, H.F., Gettys, J., Baird-Smith, A., Prud'hommeaux, E.,
+ Lie, H., and C. Lilley. "Network Performance Effects of
+ HTTP/1.1, CSS1, and PNG," Proceedings of ACM SIGCOMM '97, Cannes
+ France, September 1997.[jg642]
+
+ [40] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046, November
+ 1996. [jg643]
+
+ [41] Alvestrand, H., "IETF Policy on Character Sets and Languages",
+ BCP 18, RFC 2277, January 1998. [jg644]
+
+ [42] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform Resource
+ Identifiers (URI): Generic Syntax and Semantics", RFC 2396,
+ August 1998. [jg645]
+
+ [43] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S.,
+ Leach, P., Luotonen, A., Sink, E. and L. Stewart, "HTTP
+ Authentication: Basic and Digest Access Authentication", RFC
+ 2617, June 1999. [jg646]
+
+ [44] Luotonen, A., "Tunneling TCP based protocols through Web proxy
+ servers," Work in Progress. [jg647]
+
+ [45] Palme, J. and A. Hopmann, "MIME E-mail Encapsulation of
+ Aggregate Documents, such as HTML (MHTML)", RFC 2110, March
+ 1997.
+
+ [46] Bradner, S., "The Internet Standards Process -- Revision 3", BCP
+ 9, RFC 2026, October 1996.
+
+ [47] Masinter, L., "Hyper Text Coffee Pot Control Protocol
+ (HTCPCP/1.0)", RFC 2324, 1 April 1998.
+
+ [48] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Five: Conformance Criteria and Examples",
+ RFC 2049, November 1996.
+
+ [49] Troost, R., Dorner, S. and K. Moore, "Communicating Presentation
+ Information in Internet Messages: The Content-Disposition Header
+ Field", RFC 2183, August 1997.
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 161]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+18 Authors' Addresses
+
+ Roy T. Fielding
+ Information and Computer Science
+ University of California, Irvine
+ Irvine, CA 92697-3425, USA
+
+ Fax: +1 (949) 824-1715
+ EMail: fielding@ics.uci.edu
+
+
+ James Gettys
+ World Wide Web Consortium
+ MIT Laboratory for Computer Science
+ 545 Technology Square
+ Cambridge, MA 02139, USA
+
+ Fax: +1 (617) 258 8682
+ EMail: jg@w3.org
+
+
+ Jeffrey C. Mogul
+ Western Research Laboratory
+ Compaq Computer Corporation
+ 250 University Avenue
+ Palo Alto, California, 94305, USA
+
+ EMail: mogul@wrl.dec.com
+
+
+ Henrik Frystyk Nielsen
+ World Wide Web Consortium
+ MIT Laboratory for Computer Science
+ 545 Technology Square
+ Cambridge, MA 02139, USA
+
+ Fax: +1 (617) 258 8682
+ EMail: frystyk@w3.org
+
+
+ Larry Masinter
+ Xerox Corporation
+ 3333 Coyote Hill Road
+ Palo Alto, CA 94034, USA
+
+ EMail: masinter@parc.xerox.com
+
+
+
+
+
+Fielding, et al. Standards Track [Page 162]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Paul J. Leach
+ Microsoft Corporation
+ 1 Microsoft Way
+ Redmond, WA 98052, USA
+
+ EMail: paulle@microsoft.com
+
+
+ Tim Berners-Lee
+ Director, World Wide Web Consortium
+ MIT Laboratory for Computer Science
+ 545 Technology Square
+ Cambridge, MA 02139, USA
+
+ Fax: +1 (617) 258 8682
+ EMail: timbl@w3.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 163]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+19 Appendices
+
+19.1 Internet Media Type message/http and application/http
+
+ In addition to defining the HTTP/1.1 protocol, this document serves
+ as the specification for the Internet media type "message/http" and
+ "application/http". The message/http type can be used to enclose a
+ single HTTP request or response message, provided that it obeys the
+ MIME restrictions for all "message" types regarding line length and
+ encodings. The application/http type can be used to enclose a
+ pipeline of one or more HTTP request or response messages (not
+ intermixed). The following is to be registered with IANA [17].
+
+ Media Type name: message
+ Media subtype name: http
+ Required parameters: none
+ Optional parameters: version, msgtype
+ version: The HTTP-Version number of the enclosed message
+ (e.g., "1.1"). If not present, the version can be
+ determined from the first line of the body.
+ msgtype: The message type -- "request" or "response". If not
+ present, the type can be determined from the first
+ line of the body.
+ Encoding considerations: only "7bit", "8bit", or "binary" are
+ permitted
+ Security considerations: none
+
+ Media Type name: application
+ Media subtype name: http
+ Required parameters: none
+ Optional parameters: version, msgtype
+ version: The HTTP-Version number of the enclosed messages
+ (e.g., "1.1"). If not present, the version can be
+ determined from the first line of the body.
+ msgtype: The message type -- "request" or "response". If not
+ present, the type can be determined from the first
+ line of the body.
+ Encoding considerations: HTTP messages enclosed by this type
+ are in "binary" format; use of an appropriate
+ Content-Transfer-Encoding is required when
+ transmitted via E-mail.
+ Security considerations: none
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 164]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+19.2 Internet Media Type multipart/byteranges
+
+ When an HTTP 206 (Partial Content) response message includes the
+ content of multiple ranges (a response to a request for multiple
+ non-overlapping ranges), these are transmitted as a multipart
+ message-body. The media type for this purpose is called
+ "multipart/byteranges".
+
+ The multipart/byteranges media type includes two or more parts, each
+ with its own Content-Type and Content-Range fields. The required
+ boundary parameter specifies the boundary string used to separate
+ each body-part.
+
+ Media Type name: multipart
+ Media subtype name: byteranges
+ Required parameters: boundary
+ Optional parameters: none
+ Encoding considerations: only "7bit", "8bit", or "binary" are
+ permitted
+ Security considerations: none
+
+
+ For example:
+
+ HTTP/1.1 206 Partial Content
+ Date: Wed, 15 Nov 1995 06:25:24 GMT
+ Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
+ Content-type: multipart/byteranges; boundary=THIS_STRING_SEPARATES
+
+ --THIS_STRING_SEPARATES
+ Content-type: application/pdf
+ Content-range: bytes 500-999/8000
+
+ ...the first range...
+ --THIS_STRING_SEPARATES
+ Content-type: application/pdf
+ Content-range: bytes 7000-7999/8000
+
+ ...the second range
+ --THIS_STRING_SEPARATES--
+
+ Notes:
+
+ 1) Additional CRLFs may precede the first boundary string in the
+ entity.
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 165]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ 2) Although RFC 2046 [40] permits the boundary string to be
+ quoted, some existing implementations handle a quoted boundary
+ string incorrectly.
+
+ 3) A number of browsers and servers were coded to an early draft
+ of the byteranges specification to use a media type of
+ multipart/x-byteranges, which is almost, but not quite
+ compatible with the version documented in HTTP/1.1.
+
+19.3 Tolerant Applications
+
+ Although this document specifies the requirements for the generation
+ of HTTP/1.1 messages, not all applications will be correct in their
+ implementation. We therefore recommend that operational applications
+ be tolerant of deviations whenever those deviations can be
+ interpreted unambiguously.
+
+ Clients SHOULD be tolerant in parsing the Status-Line and servers
+ tolerant when parsing the Request-Line. In particular, they SHOULD
+ accept any amount of SP or HT characters between fields, even though
+ only a single SP is required.
+
+ The line terminator for message-header fields is the sequence CRLF.
+ However, we recommend that applications, when parsing such headers,
+ recognize a single LF as a line terminator and ignore the leading CR.
+
+ The character set of an entity-body SHOULD be labeled as the lowest
+ common denominator of the character codes used within that body, with
+ the exception that not labeling the entity is preferred over labeling
+ the entity with the labels US-ASCII or ISO-8859-1. See section 3.7.1
+ and 3.4.1.
+
+ Additional rules for requirements on parsing and encoding of dates
+ and other potential problems with date encodings include:
+
+ - HTTP/1.1 clients and caches SHOULD assume that an RFC-850 date
+ which appears to be more than 50 years in the future is in fact
+ in the past (this helps solve the "year 2000" problem).
+
+ - An HTTP/1.1 implementation MAY internally represent a parsed
+ Expires date as earlier than the proper value, but MUST NOT
+ internally represent a parsed Expires date as later than the
+ proper value.
+
+ - All expiration-related calculations MUST be done in GMT. The
+ local time zone MUST NOT influence the calculation or comparison
+ of an age or expiration time.
+
+
+
+
+Fielding, et al. Standards Track [Page 166]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ - If an HTTP header incorrectly carries a date value with a time
+ zone other than GMT, it MUST be converted into GMT using the
+ most conservative possible conversion.
+
+19.4 Differences Between HTTP Entities and RFC 2045 Entities
+
+ HTTP/1.1 uses many of the constructs defined for Internet Mail (RFC
+ 822 [9]) and the Multipurpose Internet Mail Extensions (MIME [7]) to
+ allow entities to be transmitted in an open variety of
+ representations and with extensible mechanisms. However, RFC 2045
+ discusses mail, and HTTP has a few features that are different from
+ those described in RFC 2045. These differences were carefully chosen
+ to optimize performance over binary connections, to allow greater
+ freedom in the use of new media types, to make date comparisons
+ easier, and to acknowledge the practice of some early HTTP servers
+ and clients.
+
+ This appendix describes specific areas where HTTP differs from RFC
+ 2045. Proxies and gateways to strict MIME environments SHOULD be
+ aware of these differences and provide the appropriate conversions
+ where necessary. Proxies and gateways from MIME environments to HTTP
+ also need to be aware of the differences because some conversions
+ might be required.
+
+19.4.1 MIME-Version
+
+ HTTP is not a MIME-compliant protocol. However, HTTP/1.1 messages MAY
+ include a single MIME-Version general-header field to indicate what
+ version of the MIME protocol was used to construct the message. Use
+ of the MIME-Version header field indicates that the message is in
+ full compliance with the MIME protocol (as defined in RFC 2045[7]).
+ Proxies/gateways are responsible for ensuring full compliance (where
+ possible) when exporting HTTP messages to strict MIME environments.
+
+ MIME-Version = "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
+
+ MIME version "1.0" is the default for use in HTTP/1.1. However,
+ HTTP/1.1 message parsing and semantics are defined by this document
+ and not the MIME specification.
+
+19.4.2 Conversion to Canonical Form
+
+ RFC 2045 [7] requires that an Internet mail entity be converted to
+ canonical form prior to being transferred, as described in section 4
+ of RFC 2049 [48]. Section 3.7.1 of this document describes the forms
+ allowed for subtypes of the "text" media type when transmitted over
+ HTTP. RFC 2046 requires that content with a type of "text" represent
+ line breaks as CRLF and forbids the use of CR or LF outside of line
+
+
+
+Fielding, et al. Standards Track [Page 167]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ break sequences. HTTP allows CRLF, bare CR, and bare LF to indicate a
+ line break within text content when a message is transmitted over
+ HTTP.
+
+ Where it is possible, a proxy or gateway from HTTP to a strict MIME
+ environment SHOULD translate all line breaks within the text media
+ types described in section 3.7.1 of this document to the RFC 2049
+ canonical form of CRLF. Note, however, that this might be complicated
+ by the presence of a Content-Encoding and by the fact that HTTP
+ allows the use of some character sets which do not use octets 13 and
+ 10 to represent CR and LF, as is the case for some multi-byte
+ character sets.
+
+ Implementors should note that conversion will break any cryptographic
+ checksums applied to the original content unless the original content
+ is already in canonical form. Therefore, the canonical form is
+ recommended for any content that uses such checksums in HTTP.
+
+19.4.3 Conversion of Date Formats
+
+ HTTP/1.1 uses a restricted set of date formats (section 3.3.1) to
+ simplify the process of date comparison. Proxies and gateways from
+ other protocols SHOULD ensure that any Date header field present in a
+ message conforms to one of the HTTP/1.1 formats and rewrite the date
+ if necessary.
+
+19.4.4 Introduction of Content-Encoding
+
+ RFC 2045 does not include any concept equivalent to HTTP/1.1's
+ Content-Encoding header field. Since this acts as a modifier on the
+ media type, proxies and gateways from HTTP to MIME-compliant
+ protocols MUST either change the value of the Content-Type header
+ field or decode the entity-body before forwarding the message. (Some
+ experimental applications of Content-Type for Internet mail have used
+ a media-type parameter of ";conversions=<content-coding>" to perform
+ a function equivalent to Content-Encoding. However, this parameter is
+ not part of RFC 2045.)
+
+19.4.5 No Content-Transfer-Encoding
+
+ HTTP does not use the Content-Transfer-Encoding (CTE) field of RFC
+ 2045. Proxies and gateways from MIME-compliant protocols to HTTP MUST
+ remove any non-identity CTE ("quoted-printable" or "base64") encoding
+ prior to delivering the response message to an HTTP client.
+
+ Proxies and gateways from HTTP to MIME-compliant protocols are
+ responsible for ensuring that the message is in the correct format
+ and encoding for safe transport on that protocol, where "safe
+
+
+
+Fielding, et al. Standards Track [Page 168]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ transport" is defined by the limitations of the protocol being used.
+ Such a proxy or gateway SHOULD label the data with an appropriate
+ Content-Transfer-Encoding if doing so will improve the likelihood of
+ safe transport over the destination protocol.
+
+19.4.6 Introduction of Transfer-Encoding
+
+ HTTP/1.1 introduces the Transfer-Encoding header field (section
+ 14.41). Proxies/gateways MUST remove any transfer-coding prior to
+ forwarding a message via a MIME-compliant protocol.
+
+ A process for decoding the "chunked" transfer-coding (section 3.6)
+ can be represented in pseudo-code as:
+
+ length := 0
+ read chunk-size, chunk-extension (if any) and CRLF
+ while (chunk-size > 0) {
+ read chunk-data and CRLF
+ append chunk-data to entity-body
+ length := length + chunk-size
+ read chunk-size and CRLF
+ }
+ read entity-header
+ while (entity-header not empty) {
+ append entity-header to existing header fields
+ read entity-header
+ }
+ Content-Length := length
+ Remove "chunked" from Transfer-Encoding
+
+19.4.7 MHTML and Line Length Limitations
+
+ HTTP implementations which share code with MHTML [45] implementations
+ need to be aware of MIME line length limitations. Since HTTP does not
+ have this limitation, HTTP does not fold long lines. MHTML messages
+ being transported by HTTP follow all conventions of MHTML, including
+ line length limitations and folding, canonicalization, etc., since
+ HTTP transports all message-bodies as payload (see section 3.7.2) and
+ does not interpret the content or any MIME header lines that might be
+ contained therein.
+
+19.5 Additional Features
+
+ RFC 1945 and RFC 2068 document protocol elements used by some
+ existing HTTP implementations, but not consistently and correctly
+ across most HTTP/1.1 applications. Implementors are advised to be
+ aware of these features, but cannot rely upon their presence in, or
+ interoperability with, other HTTP/1.1 applications. Some of these
+
+
+
+Fielding, et al. Standards Track [Page 169]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ describe proposed experimental features, and some describe features
+ that experimental deployment found lacking that are now addressed in
+ the base HTTP/1.1 specification.
+
+ A number of other headers, such as Content-Disposition and Title,
+ from SMTP and MIME are also often implemented (see RFC 2076 [37]).
+
+19.5.1 Content-Disposition
+
+ The Content-Disposition response-header field has been proposed as a
+ means for the origin server to suggest a default filename if the user
+ requests that the content is saved to a file. This usage is derived
+ from the definition of Content-Disposition in RFC 1806 [35].
+
+ content-disposition = "Content-Disposition" ":"
+ disposition-type *( ";" disposition-parm )
+ disposition-type = "attachment" | disp-extension-token
+ disposition-parm = filename-parm | disp-extension-parm
+ filename-parm = "filename" "=" quoted-string
+ disp-extension-token = token
+ disp-extension-parm = token "=" ( token | quoted-string )
+
+ An example is
+
+ Content-Disposition: attachment; filename="fname.ext"
+
+ The receiving user agent SHOULD NOT respect any directory path
+ information present in the filename-parm parameter, which is the only
+ parameter believed to apply to HTTP implementations at this time. The
+ filename SHOULD be treated as a terminal component only.
+
+ If this header is used in a response with the application/octet-
+ stream content-type, the implied suggestion is that the user agent
+ should not display the response, but directly enter a `save response
+ as...' dialog.
+
+ See section 15.5 for Content-Disposition security issues.
+
+19.6 Compatibility with Previous Versions
+
+ It is beyond the scope of a protocol specification to mandate
+ compliance with previous versions. HTTP/1.1 was deliberately
+ designed, however, to make supporting previous versions easy. It is
+ worth noting that, at the time of composing this specification
+ (1996), we would expect commercial HTTP/1.1 servers to:
+
+ - recognize the format of the Request-Line for HTTP/0.9, 1.0, and
+ 1.1 requests;
+
+
+
+Fielding, et al. Standards Track [Page 170]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ - understand any valid request in the format of HTTP/0.9, 1.0, or
+ 1.1;
+
+ - respond appropriately with a message in the same major version
+ used by the client.
+
+ And we would expect HTTP/1.1 clients to:
+
+ - recognize the format of the Status-Line for HTTP/1.0 and 1.1
+ responses;
+
+ - understand any valid response in the format of HTTP/0.9, 1.0, or
+ 1.1.
+
+ For most implementations of HTTP/1.0, each connection is established
+ by the client prior to the request and closed by the server after
+ sending the response. Some implementations implement the Keep-Alive
+ version of persistent connections described in section 19.7.1 of RFC
+ 2068 [33].
+
+19.6.1 Changes from HTTP/1.0
+
+ This section summarizes major differences between versions HTTP/1.0
+ and HTTP/1.1.
+
+19.6.1.1 Changes to Simplify Multi-homed Web Servers and Conserve IP
+ Addresses
+
+ The requirements that clients and servers support the Host request-
+ header, report an error if the Host request-header (section 14.23) is
+ missing from an HTTP/1.1 request, and accept absolute URIs (section
+ 5.1.2) are among the most important changes defined by this
+ specification.
+
+ Older HTTP/1.0 clients assumed a one-to-one relationship of IP
+ addresses and servers; there was no other established mechanism for
+ distinguishing the intended server of a request than the IP address
+ to which that request was directed. The changes outlined above will
+ allow the Internet, once older HTTP clients are no longer common, to
+ support multiple Web sites from a single IP address, greatly
+ simplifying large operational Web servers, where allocation of many
+ IP addresses to a single host has created serious problems. The
+ Internet will also be able to recover the IP addresses that have been
+ allocated for the sole purpose of allowing special-purpose domain
+ names to be used in root-level HTTP URLs. Given the rate of growth of
+ the Web, and the number of servers already deployed, it is extremely
+
+
+
+
+
+Fielding, et al. Standards Track [Page 171]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ important that all implementations of HTTP (including updates to
+ existing HTTP/1.0 applications) correctly implement these
+ requirements:
+
+ - Both clients and servers MUST support the Host request-header.
+
+ - A client that sends an HTTP/1.1 request MUST send a Host header.
+
+ - Servers MUST report a 400 (Bad Request) error if an HTTP/1.1
+ request does not include a Host request-header.
+
+ - Servers MUST accept absolute URIs.
+
+19.6.2 Compatibility with HTTP/1.0 Persistent Connections
+
+ Some clients and servers might wish to be compatible with some
+ previous implementations of persistent connections in HTTP/1.0
+ clients and servers. Persistent connections in HTTP/1.0 are
+ explicitly negotiated as they are not the default behavior. HTTP/1.0
+ experimental implementations of persistent connections are faulty,
+ and the new facilities in HTTP/1.1 are designed to rectify these
+ problems. The problem was that some existing 1.0 clients may be
+ sending Keep-Alive to a proxy server that doesn't understand
+ Connection, which would then erroneously forward it to the next
+ inbound server, which would establish the Keep-Alive connection and
+ result in a hung HTTP/1.0 proxy waiting for the close on the
+ response. The result is that HTTP/1.0 clients must be prevented from
+ using Keep-Alive when talking to proxies.
+
+ However, talking to proxies is the most important use of persistent
+ connections, so that prohibition is clearly unacceptable. Therefore,
+ we need some other mechanism for indicating a persistent connection
+ is desired, which is safe to use even when talking to an old proxy
+ that ignores Connection. Persistent connections are the default for
+ HTTP/1.1 messages; we introduce a new keyword (Connection: close) for
+ declaring non-persistence. See section 14.10.
+
+ The original HTTP/1.0 form of persistent connections (the Connection:
+ Keep-Alive and Keep-Alive header) is documented in RFC 2068. [33]
+
+19.6.3 Changes from RFC 2068
+
+ This specification has been carefully audited to correct and
+ disambiguate key word usage; RFC 2068 had many problems in respect to
+ the conventions laid out in RFC 2119 [34].
+
+ Clarified which error code should be used for inbound server failures
+ (e.g. DNS failures). (Section 10.5.5).
+
+
+
+Fielding, et al. Standards Track [Page 172]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ CREATE had a race that required an Etag be sent when a resource is
+ first created. (Section 10.2.2).
+
+ Content-Base was deleted from the specification: it was not
+ implemented widely, and there is no simple, safe way to introduce it
+ without a robust extension mechanism. In addition, it is used in a
+ similar, but not identical fashion in MHTML [45].
+
+ Transfer-coding and message lengths all interact in ways that
+ required fixing exactly when chunked encoding is used (to allow for
+ transfer encoding that may not be self delimiting); it was important
+ to straighten out exactly how message lengths are computed. (Sections
+ 3.6, 4.4, 7.2.2, 13.5.2, 14.13, 14.16)
+
+ A content-coding of "identity" was introduced, to solve problems
+ discovered in caching. (section 3.5)
+
+ Quality Values of zero should indicate that "I don't want something"
+ to allow clients to refuse a representation. (Section 3.9)
+
+ The use and interpretation of HTTP version numbers has been clarified
+ by RFC 2145. Require proxies to upgrade requests to highest protocol
+ version they support to deal with problems discovered in HTTP/1.0
+ implementations (Section 3.1)
+
+ Charset wildcarding is introduced to avoid explosion of character set
+ names in accept headers. (Section 14.2)
+
+ A case was missed in the Cache-Control model of HTTP/1.1; s-maxage
+ was introduced to add this missing case. (Sections 13.4, 14.8, 14.9,
+ 14.9.3)
+
+ The Cache-Control: max-age directive was not properly defined for
+ responses. (Section 14.9.3)
+
+ There are situations where a server (especially a proxy) does not
+ know the full length of a response but is capable of serving a
+ byterange request. We therefore need a mechanism to allow byteranges
+ with a content-range not indicating the full length of the message.
+ (Section 14.16)
+
+ Range request responses would become very verbose if all meta-data
+ were always returned; by allowing the server to only send needed
+ headers in a 206 response, this problem can be avoided. (Section
+ 10.2.7, 13.5.3, and 14.27)
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 173]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Fix problem with unsatisfiable range requests; there are two cases:
+ syntactic problems, and range doesn't exist in the document. The 416
+ status code was needed to resolve this ambiguity needed to indicate
+ an error for a byte range request that falls outside of the actual
+ contents of a document. (Section 10.4.17, 14.16)
+
+ Rewrite of message transmission requirements to make it much harder
+ for implementors to get it wrong, as the consequences of errors here
+ can have significant impact on the Internet, and to deal with the
+ following problems:
+
+ 1. Changing "HTTP/1.1 or later" to "HTTP/1.1", in contexts where
+ this was incorrectly placing a requirement on the behavior of
+ an implementation of a future version of HTTP/1.x
+
+ 2. Made it clear that user-agents should retry requests, not
+ "clients" in general.
+
+ 3. Converted requirements for clients to ignore unexpected 100
+ (Continue) responses, and for proxies to forward 100 responses,
+ into a general requirement for 1xx responses.
+
+ 4. Modified some TCP-specific language, to make it clearer that
+ non-TCP transports are possible for HTTP.
+
+ 5. Require that the origin server MUST NOT wait for the request
+ body before it sends a required 100 (Continue) response.
+
+ 6. Allow, rather than require, a server to omit 100 (Continue) if
+ it has already seen some of the request body.
+
+ 7. Allow servers to defend against denial-of-service attacks and
+ broken clients.
+
+ This change adds the Expect header and 417 status code. The message
+ transmission requirements fixes are in sections 8.2, 10.4.18,
+ 8.1.2.2, 13.11, and 14.20.
+
+ Proxies should be able to add Content-Length when appropriate.
+ (Section 13.5.2)
+
+ Clean up confusion between 403 and 404 responses. (Section 10.4.4,
+ 10.4.5, and 10.4.11)
+
+ Warnings could be cached incorrectly, or not updated appropriately.
+ (Section 13.1.2, 13.2.4, 13.5.2, 13.5.3, 14.9.3, and 14.46) Warning
+ also needed to be a general header, as PUT or other methods may have
+ need for it in requests.
+
+
+
+Fielding, et al. Standards Track [Page 174]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+ Transfer-coding had significant problems, particularly with
+ interactions with chunked encoding. The solution is that transfer-
+ codings become as full fledged as content-codings. This involves
+ adding an IANA registry for transfer-codings (separate from content
+ codings), a new header field (TE) and enabling trailer headers in the
+ future. Transfer encoding is a major performance benefit, so it was
+ worth fixing [39]. TE also solves another, obscure, downward
+ interoperability problem that could have occurred due to interactions
+ between authentication trailers, chunked encoding and HTTP/1.0
+ clients.(Section 3.6, 3.6.1, and 14.39)
+
+ The PATCH, LINK, UNLINK methods were defined but not commonly
+ implemented in previous versions of this specification. See RFC 2068
+ [33].
+
+ The Alternates, Content-Version, Derived-From, Link, URI, Public and
+ Content-Base header fields were defined in previous versions of this
+ specification, but not commonly implemented. See RFC 2068 [33].
+
+20 Index
+
+ Please see the PostScript version of this RFC for the INDEX.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 175]
+
+RFC 2616 HTTP/1.1 June 1999
+
+
+21. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fielding, et al. Standards Track [Page 176]
+
diff --git a/standards/rfc2617.txt b/standards/rfc2617.txt
new file mode 100644
index 000000000..771aa924a
--- /dev/null
+++ b/standards/rfc2617.txt
@@ -0,0 +1,1907 @@
+
+
+
+
+
+
+Network Working Group J. Franks
+Request for Comments: 2617 Northwestern University
+Obsoletes: 2069 P. Hallam-Baker
+Category: Standards Track Verisign, Inc.
+ J. Hostetler
+ AbiSource, Inc.
+ S. Lawrence
+ Agranat Systems, Inc.
+ P. Leach
+ Microsoft Corporation
+ A. Luotonen
+ Netscape Communications Corporation
+ L. Stewart
+ Open Market, Inc.
+ June 1999
+
+
+ HTTP Authentication: Basic and Digest Access Authentication
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+Abstract
+
+ "HTTP/1.0", includes the specification for a Basic Access
+ Authentication scheme. This scheme is not considered to be a secure
+ method of user authentication (unless used in conjunction with some
+ external secure system such as SSL [5]), as the user name and
+ password are passed over the network as cleartext.
+
+ This document also provides the specification for HTTP's
+ authentication framework, the original Basic authentication scheme
+ and a scheme based on cryptographic hashes, referred to as "Digest
+ Access Authentication". It is therefore also intended to serve as a
+ replacement for RFC 2069 [6]. Some optional elements specified by
+ RFC 2069 have been removed from this specification due to problems
+ found since its publication; other new elements have been added for
+ compatibility, those new elements have been made optional, but are
+ strongly recommended.
+
+
+
+Franks, et al. Standards Track [Page 1]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ Like Basic, Digest access authentication verifies that both parties
+ to a communication know a shared secret (a password); unlike Basic,
+ this verification can be done without sending the password in the
+ clear, which is Basic's biggest weakness. As with most other
+ authentication protocols, the greatest sources of risks are usually
+ found not in the core protocol itself but in policies and procedures
+ surrounding its use.
+
+Table of Contents
+
+ 1 Access Authentication................................ 3
+ 1.1 Reliance on the HTTP/1.1 Specification............ 3
+ 1.2 Access Authentication Framework................... 3
+ 2 Basic Authentication Scheme.......................... 5
+ 3 Digest Access Authentication Scheme.................. 6
+ 3.1 Introduction...................................... 6
+ 3.1.1 Purpose......................................... 6
+ 3.1.2 Overall Operation............................... 6
+ 3.1.3 Representation of digest values................. 7
+ 3.1.4 Limitations..................................... 7
+ 3.2 Specification of Digest Headers................... 7
+ 3.2.1 The WWW-Authenticate Response Header............ 8
+ 3.2.2 The Authorization Request Header................ 11
+ 3.2.3 The Authentication-Info Header.................. 15
+ 3.3 Digest Operation.................................. 17
+ 3.4 Security Protocol Negotiation..................... 18
+ 3.5 Example........................................... 18
+ 3.6 Proxy-Authentication and Proxy-Authorization...... 19
+ 4 Security Considerations.............................. 19
+ 4.1 Authentication of Clients using Basic
+ Authentication.................................... 19
+ 4.2 Authentication of Clients using Digest
+ Authentication.................................... 20
+ 4.3 Limited Use Nonce Values.......................... 21
+ 4.4 Comparison of Digest with Basic Authentication.... 22
+ 4.5 Replay Attacks.................................... 22
+ 4.6 Weakness Created by Multiple Authentication
+ Schemes........................................... 23
+ 4.7 Online dictionary attacks......................... 23
+ 4.8 Man in the Middle................................. 24
+ 4.9 Chosen plaintext attacks.......................... 24
+ 4.10 Precomputed dictionary attacks.................... 25
+ 4.11 Batch brute force attacks......................... 25
+ 4.12 Spoofing by Counterfeit Servers................... 25
+ 4.13 Storing passwords................................. 26
+ 4.14 Summary........................................... 26
+ 5 Sample implementation................................ 27
+ 6 Acknowledgments...................................... 31
+
+
+
+Franks, et al. Standards Track [Page 2]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ 7 References........................................... 31
+ 8 Authors' Addresses................................... 32
+ 9 Full Copyright Statement............................. 34
+
+1 Access Authentication
+
+1.1 Reliance on the HTTP/1.1 Specification
+
+ This specification is a companion to the HTTP/1.1 specification [2].
+ It uses the augmented BNF section 2.1 of that document, and relies on
+ both the non-terminals defined in that document and other aspects of
+ the HTTP/1.1 specification.
+
+1.2 Access Authentication Framework
+
+ HTTP provides a simple challenge-response authentication mechanism
+ that MAY be used by a server to challenge a client request and by a
+ client to provide authentication information. It uses an extensible,
+ case-insensitive token to identify the authentication scheme,
+ followed by a comma-separated list of attribute-value pairs which
+ carry the parameters necessary for achieving authentication via that
+ scheme.
+
+ auth-scheme = token
+ auth-param = token "=" ( token | quoted-string )
+
+ The 401 (Unauthorized) response message is used by an origin server
+ to challenge the authorization of a user agent. This response MUST
+ include a WWW-Authenticate header field containing at least one
+ challenge applicable to the requested resource. The 407 (Proxy
+ Authentication Required) response message is used by a proxy to
+ challenge the authorization of a client and MUST include a Proxy-
+ Authenticate header field containing at least one challenge
+ applicable to the proxy for the requested resource.
+
+ challenge = auth-scheme 1*SP 1#auth-param
+
+ Note: User agents will need to take special care in parsing the WWW-
+ Authenticate or Proxy-Authenticate header field value if it contains
+ more than one challenge, or if more than one WWW-Authenticate header
+ field is provided, since the contents of a challenge may itself
+ contain a comma-separated list of authentication parameters.
+
+ The authentication parameter realm is defined for all authentication
+ schemes:
+
+ realm = "realm" "=" realm-value
+ realm-value = quoted-string
+
+
+
+Franks, et al. Standards Track [Page 3]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ The realm directive (case-insensitive) is required for all
+ authentication schemes that issue a challenge. The realm value
+ (case-sensitive), in combination with the canonical root URL (the
+ absoluteURI for the server whose abs_path is empty; see section 5.1.2
+ of [2]) of the server being accessed, defines the protection space.
+ These realms allow the protected resources on a server to be
+ partitioned into a set of protection spaces, each with its own
+ authentication scheme and/or authorization database. The realm value
+ is a string, generally assigned by the origin server, which may have
+ additional semantics specific to the authentication scheme. Note that
+ there may be multiple challenges with the same auth-scheme but
+ different realms.
+
+ A user agent that wishes to authenticate itself with an origin
+ server--usually, but not necessarily, after receiving a 401
+ (Unauthorized)--MAY do so by including an Authorization header field
+ with the request. A client that wishes to authenticate itself with a
+ proxy--usually, but not necessarily, after receiving a 407 (Proxy
+ Authentication Required)--MAY do so by including a Proxy-
+ Authorization header field with the request. Both the Authorization
+ field value and the Proxy-Authorization field value consist of
+ credentials containing the authentication information of the client
+ for the realm of the resource being requested. The user agent MUST
+ choose to use one of the challenges with the strongest auth-scheme it
+ understands and request credentials from the user based upon that
+ challenge.
+
+ credentials = auth-scheme #auth-param
+
+ Note that many browsers will only recognize Basic and will require
+ that it be the first auth-scheme presented. Servers should only
+ include Basic if it is minimally acceptable.
+
+ The protection space determines the domain over which credentials can
+ be automatically applied. If a prior request has been authorized, the
+ same credentials MAY be reused for all other requests within that
+ protection space for a period of time determined by the
+ authentication scheme, parameters, and/or user preference. Unless
+ otherwise defined by the authentication scheme, a single protection
+ space cannot extend outside the scope of its server.
+
+ If the origin server does not wish to accept the credentials sent
+ with a request, it SHOULD return a 401 (Unauthorized) response. The
+ response MUST include a WWW-Authenticate header field containing at
+ least one (possibly new) challenge applicable to the requested
+ resource. If a proxy does not accept the credentials sent with a
+ request, it SHOULD return a 407 (Proxy Authentication Required). The
+ response MUST include a Proxy-Authenticate header field containing a
+
+
+
+Franks, et al. Standards Track [Page 4]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ (possibly new) challenge applicable to the proxy for the requested
+ resource.
+
+ The HTTP protocol does not restrict applications to this simple
+ challenge-response mechanism for access authentication. Additional
+ mechanisms MAY be used, such as encryption at the transport level or
+ via message encapsulation, and with additional header fields
+ specifying authentication information. However, these additional
+ mechanisms are not defined by this specification.
+
+ Proxies MUST be completely transparent regarding user agent
+ authentication by origin servers. That is, they must forward the
+ WWW-Authenticate and Authorization headers untouched, and follow the
+ rules found in section 14.8 of [2]. Both the Proxy-Authenticate and
+ the Proxy-Authorization header fields are hop-by-hop headers (see
+ section 13.5.1 of [2]).
+
+2 Basic Authentication Scheme
+
+ The "basic" authentication scheme is based on the model that the
+ client must authenticate itself with a user-ID and a password for
+ each realm. The realm value should be considered an opaque string
+ which can only be compared for equality with other realms on that
+ server. The server will service the request only if it can validate
+ the user-ID and password for the protection space of the Request-URI.
+ There are no optional authentication parameters.
+
+ For Basic, the framework above is utilized as follows:
+
+ challenge = "Basic" realm
+ credentials = "Basic" basic-credentials
+
+ Upon receipt of an unauthorized request for a URI within the
+ protection space, the origin server MAY respond with a challenge like
+ the following:
+
+ WWW-Authenticate: Basic realm="WallyWorld"
+
+ where "WallyWorld" is the string assigned by the server to identify
+ the protection space of the Request-URI. A proxy may respond with the
+ same challenge using the Proxy-Authenticate header field.
+
+ To receive authorization, the client sends the userid and password,
+ separated by a single colon (":") character, within a base64 [7]
+ encoded string in the credentials.
+
+ basic-credentials = base64-user-pass
+ base64-user-pass = <base64 [4] encoding of user-pass,
+
+
+
+Franks, et al. Standards Track [Page 5]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ except not limited to 76 char/line>
+ user-pass = userid ":" password
+ userid = *<TEXT excluding ":">
+ password = *TEXT
+
+ Userids might be case sensitive.
+
+ If the user agent wishes to send the userid "Aladdin" and password
+ "open sesame", it would use the following header field:
+
+ Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
+
+ A client SHOULD assume that all paths at or deeper than the depth of
+ the last symbolic element in the path field of the Request-URI also
+ are within the protection space specified by the Basic realm value of
+ the current challenge. A client MAY preemptively send the
+ corresponding Authorization header with requests for resources in
+ that space without receipt of another challenge from the server.
+ Similarly, when a client sends a request to a proxy, it may reuse a
+ userid and password in the Proxy-Authorization header field without
+ receiving another challenge from the proxy server. See section 4 for
+ security considerations associated with Basic authentication.
+
+3 Digest Access Authentication Scheme
+
+3.1 Introduction
+
+3.1.1 Purpose
+
+ The protocol referred to as "HTTP/1.0" includes the specification for
+ a Basic Access Authentication scheme[1]. That scheme is not
+ considered to be a secure method of user authentication, as the user
+ name and password are passed over the network in an unencrypted form.
+ This section provides the specification for a scheme that does not
+ send the password in cleartext, referred to as "Digest Access
+ Authentication".
+
+ The Digest Access Authentication scheme is not intended to be a
+ complete answer to the need for security in the World Wide Web. This
+ scheme provides no encryption of message content. The intent is
+ simply to create an access authentication method that avoids the most
+ serious flaws of Basic authentication.
+
+3.1.2 Overall Operation
+
+ Like Basic Access Authentication, the Digest scheme is based on a
+ simple challenge-response paradigm. The Digest scheme challenges
+ using a nonce value. A valid response contains a checksum (by
+
+
+
+Franks, et al. Standards Track [Page 6]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ default, the MD5 checksum) of the username, the password, the given
+ nonce value, the HTTP method, and the requested URI. In this way, the
+ password is never sent in the clear. Just as with the Basic scheme,
+ the username and password must be prearranged in some fashion not
+ addressed by this document.
+
+3.1.3 Representation of digest values
+
+ An optional header allows the server to specify the algorithm used to
+ create the checksum or digest. By default the MD5 algorithm is used
+ and that is the only algorithm described in this document.
+
+ For the purposes of this document, an MD5 digest of 128 bits is
+ represented as 32 ASCII printable characters. The bits in the 128 bit
+ digest are converted from most significant to least significant bit,
+ four bits at a time to their ASCII presentation as follows. Each four
+ bits is represented by its familiar hexadecimal notation from the
+ characters 0123456789abcdef. That is, binary 0000 gets represented by
+ the character '0', 0001, by '1', and so on up to the representation
+ of 1111 as 'f'.
+
+3.1.4 Limitations
+
+ The Digest authentication scheme described in this document suffers
+ from many known limitations. It is intended as a replacement for
+ Basic authentication and nothing more. It is a password-based system
+ and (on the server side) suffers from all the same problems of any
+ password system. In particular, no provision is made in this protocol
+ for the initial secure arrangement between user and server to
+ establish the user's password.
+
+ Users and implementors should be aware that this protocol is not as
+ secure as Kerberos, and not as secure as any client-side private-key
+ scheme. Nevertheless it is better than nothing, better than what is
+ commonly used with telnet and ftp, and better than Basic
+ authentication.
+
+3.2 Specification of Digest Headers
+
+ The Digest Access Authentication scheme is conceptually similar to
+ the Basic scheme. The formats of the modified WWW-Authenticate header
+ line and the Authorization header line are specified below. In
+ addition, a new header, Authentication-Info, is specified.
+
+
+
+
+
+
+
+
+Franks, et al. Standards Track [Page 7]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+3.2.1 The WWW-Authenticate Response Header
+
+ If a server receives a request for an access-protected object, and an
+ acceptable Authorization header is not sent, the server responds with
+ a "401 Unauthorized" status code, and a WWW-Authenticate header as
+ per the framework defined above, which for the digest scheme is
+ utilized as follows:
+
+ challenge = "Digest" digest-challenge
+
+ digest-challenge = 1#( realm | [ domain ] | nonce |
+ [ opaque ] |[ stale ] | [ algorithm ] |
+ [ qop-options ] | [auth-param] )
+
+
+ domain = "domain" "=" <"> URI ( 1*SP URI ) <">
+ URI = absoluteURI | abs_path
+ nonce = "nonce" "=" nonce-value
+ nonce-value = quoted-string
+ opaque = "opaque" "=" quoted-string
+ stale = "stale" "=" ( "true" | "false" )
+ algorithm = "algorithm" "=" ( "MD5" | "MD5-sess" |
+ token )
+ qop-options = "qop" "=" <"> 1#qop-value <">
+ qop-value = "auth" | "auth-int" | token
+
+ The meanings of the values of the directives used above are as
+ follows:
+
+ realm
+ A string to be displayed to users so they know which username and
+ password to use. This string should contain at least the name of
+ the host performing the authentication and might additionally
+ indicate the collection of users who might have access. An example
+ might be "registered_users@gotham.news.com".
+
+ domain
+ A quoted, space-separated list of URIs, as specified in RFC XURI
+ [7], that define the protection space. If a URI is an abs_path, it
+ is relative to the canonical root URL (see section 1.2 above) of
+ the server being accessed. An absoluteURI in this list may refer to
+ a different server than the one being accessed. The client can use
+ this list to determine the set of URIs for which the same
+ authentication information may be sent: any URI that has a URI in
+ this list as a prefix (after both have been made absolute) may be
+ assumed to be in the same protection space. If this directive is
+ omitted or its value is empty, the client should assume that the
+ protection space consists of all URIs on the responding server.
+
+
+
+Franks, et al. Standards Track [Page 8]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ This directive is not meaningful in Proxy-Authenticate headers, for
+ which the protection space is always the entire proxy; if present
+ it should be ignored.
+
+ nonce
+ A server-specified data string which should be uniquely generated
+ each time a 401 response is made. It is recommended that this
+ string be base64 or hexadecimal data. Specifically, since the
+ string is passed in the header lines as a quoted string, the
+ double-quote character is not allowed.
+
+ The contents of the nonce are implementation dependent. The quality
+ of the implementation depends on a good choice. A nonce might, for
+ example, be constructed as the base 64 encoding of
+
+ time-stamp H(time-stamp ":" ETag ":" private-key)
+
+ where time-stamp is a server-generated time or other non-repeating
+ value, ETag is the value of the HTTP ETag header associated with
+ the requested entity, and private-key is data known only to the
+ server. With a nonce of this form a server would recalculate the
+ hash portion after receiving the client authentication header and
+ reject the request if it did not match the nonce from that header
+ or if the time-stamp value is not recent enough. In this way the
+ server can limit the time of the nonce's validity. The inclusion of
+ the ETag prevents a replay request for an updated version of the
+ resource. (Note: including the IP address of the client in the
+ nonce would appear to offer the server the ability to limit the
+ reuse of the nonce to the same client that originally got it.
+ However, that would break proxy farms, where requests from a single
+ user often go through different proxies in the farm. Also, IP
+ address spoofing is not that hard.)
+
+ An implementation might choose not to accept a previously used
+ nonce or a previously used digest, in order to protect against a
+ replay attack. Or, an implementation might choose to use one-time
+ nonces or digests for POST or PUT requests and a time-stamp for GET
+ requests. For more details on the issues involved see section 4.
+ of this document.
+
+ The nonce is opaque to the client.
+
+ opaque
+ A string of data, specified by the server, which should be returned
+ by the client unchanged in the Authorization header of subsequent
+ requests with URIs in the same protection space. It is recommended
+ that this string be base64 or hexadecimal data.
+
+
+
+
+Franks, et al. Standards Track [Page 9]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ stale
+ A flag, indicating that the previous request from the client was
+ rejected because the nonce value was stale. If stale is TRUE
+ (case-insensitive), the client may wish to simply retry the request
+ with a new encrypted response, without reprompting the user for a
+ new username and password. The server should only set stale to TRUE
+ if it receives a request for which the nonce is invalid but with a
+ valid digest for that nonce (indicating that the client knows the
+ correct username/password). If stale is FALSE, or anything other
+ than TRUE, or the stale directive is not present, the username
+ and/or password are invalid, and new values must be obtained.
+
+ algorithm
+ A string indicating a pair of algorithms used to produce the digest
+ and a checksum. If this is not present it is assumed to be "MD5".
+ If the algorithm is not understood, the challenge should be ignored
+ (and a different one used, if there is more than one).
+
+ In this document the string obtained by applying the digest
+ algorithm to the data "data" with secret "secret" will be denoted
+ by KD(secret, data), and the string obtained by applying the
+ checksum algorithm to the data "data" will be denoted H(data). The
+ notation unq(X) means the value of the quoted-string X without the
+ surrounding quotes.
+
+ For the "MD5" and "MD5-sess" algorithms
+
+ H(data) = MD5(data)
+
+ and
+
+ KD(secret, data) = H(concat(secret, ":", data))
+
+ i.e., the digest is the MD5 of the secret concatenated with a colon
+ concatenated with the data. The "MD5-sess" algorithm is intended to
+ allow efficient 3rd party authentication servers; for the
+ difference in usage, see the description in section 3.2.2.2.
+
+ qop-options
+ This directive is optional, but is made so only for backward
+ compatibility with RFC 2069 [6]; it SHOULD be used by all
+ implementations compliant with this version of the Digest scheme.
+ If present, it is a quoted string of one or more tokens indicating
+ the "quality of protection" values supported by the server. The
+ value "auth" indicates authentication; the value "auth-int"
+ indicates authentication with integrity protection; see the
+
+
+
+
+
+Franks, et al. Standards Track [Page 10]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ descriptions below for calculating the response directive value for
+ the application of this choice. Unrecognized options MUST be
+ ignored.
+
+ auth-param
+ This directive allows for future extensions. Any unrecognized
+ directive MUST be ignored.
+
+3.2.2 The Authorization Request Header
+
+ The client is expected to retry the request, passing an Authorization
+ header line, which is defined according to the framework above,
+ utilized as follows.
+
+ credentials = "Digest" digest-response
+ digest-response = 1#( username | realm | nonce | digest-uri
+ | response | [ algorithm ] | [cnonce] |
+ [opaque] | [message-qop] |
+ [nonce-count] | [auth-param] )
+
+ username = "username" "=" username-value
+ username-value = quoted-string
+ digest-uri = "uri" "=" digest-uri-value
+ digest-uri-value = request-uri ; As specified by HTTP/1.1
+ message-qop = "qop" "=" qop-value
+ cnonce = "cnonce" "=" cnonce-value
+ cnonce-value = nonce-value
+ nonce-count = "nc" "=" nc-value
+ nc-value = 8LHEX
+ response = "response" "=" request-digest
+ request-digest = <"> 32LHEX <">
+ LHEX = "0" | "1" | "2" | "3" |
+ "4" | "5" | "6" | "7" |
+ "8" | "9" | "a" | "b" |
+ "c" | "d" | "e" | "f"
+
+ The values of the opaque and algorithm fields must be those supplied
+ in the WWW-Authenticate response header for the entity being
+ requested.
+
+ response
+ A string of 32 hex digits computed as defined below, which proves
+ that the user knows a password
+
+ username
+ The user's name in the specified realm.
+
+
+
+
+
+Franks, et al. Standards Track [Page 11]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ digest-uri
+ The URI from Request-URI of the Request-Line; duplicated here
+ because proxies are allowed to change the Request-Line in transit.
+
+ qop
+ Indicates what "quality of protection" the client has applied to
+ the message. If present, its value MUST be one of the alternatives
+ the server indicated it supports in the WWW-Authenticate header.
+ These values affect the computation of the request-digest. Note
+ that this is a single token, not a quoted list of alternatives as
+ in WWW- Authenticate. This directive is optional in order to
+ preserve backward compatibility with a minimal implementation of
+ RFC 2069 [6], but SHOULD be used if the server indicated that qop
+ is supported by providing a qop directive in the WWW-Authenticate
+ header field.
+
+ cnonce
+ This MUST be specified if a qop directive is sent (see above), and
+ MUST NOT be specified if the server did not send a qop directive in
+ the WWW-Authenticate header field. The cnonce-value is an opaque
+ quoted string value provided by the client and used by both client
+ and server to avoid chosen plaintext attacks, to provide mutual
+ authentication, and to provide some message integrity protection.
+ See the descriptions below of the calculation of the response-
+ digest and request-digest values.
+
+ nonce-count
+ This MUST be specified if a qop directive is sent (see above), and
+ MUST NOT be specified if the server did not send a qop directive in
+ the WWW-Authenticate header field. The nc-value is the hexadecimal
+ count of the number of requests (including the current request)
+ that the client has sent with the nonce value in this request. For
+ example, in the first request sent in response to a given nonce
+ value, the client sends "nc=00000001". The purpose of this
+ directive is to allow the server to detect request replays by
+ maintaining its own copy of this count - if the same nc-value is
+ seen twice, then the request is a replay. See the description
+ below of the construction of the request-digest value.
+
+ auth-param
+ This directive allows for future extensions. Any unrecognized
+ directive MUST be ignored.
+
+ If a directive or its value is improper, or required directives are
+ missing, the proper response is 400 Bad Request. If the request-
+ digest is invalid, then a login failure should be logged, since
+ repeated login failures from a single client may indicate an attacker
+ attempting to guess passwords.
+
+
+
+Franks, et al. Standards Track [Page 12]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ The definition of request-digest above indicates the encoding for its
+ value. The following definitions show how the value is computed.
+
+3.2.2.1 Request-Digest
+
+ If the "qop" value is "auth" or "auth-int":
+
+ request-digest = <"> < KD ( H(A1), unq(nonce-value)
+ ":" nc-value
+ ":" unq(cnonce-value)
+ ":" unq(qop-value)
+ ":" H(A2)
+ ) <">
+
+ If the "qop" directive is not present (this construction is for
+ compatibility with RFC 2069):
+
+ request-digest =
+ <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) >
+ <">
+
+ See below for the definitions for A1 and A2.
+
+3.2.2.2 A1
+
+ If the "algorithm" directive's value is "MD5" or is unspecified, then
+ A1 is:
+
+ A1 = unq(username-value) ":" unq(realm-value) ":" passwd
+
+ where
+
+ passwd = < user's password >
+
+ If the "algorithm" directive's value is "MD5-sess", then A1 is
+ calculated only once - on the first request by the client following
+ receipt of a WWW-Authenticate challenge from the server. It uses the
+ server nonce from that challenge, and the first client nonce value to
+ construct A1 as follows:
+
+ A1 = H( unq(username-value) ":" unq(realm-value)
+ ":" passwd )
+ ":" unq(nonce-value) ":" unq(cnonce-value)
+
+ This creates a 'session key' for the authentication of subsequent
+ requests and responses which is different for each "authentication
+ session", thus limiting the amount of material hashed with any one
+ key. (Note: see further discussion of the authentication session in
+
+
+
+Franks, et al. Standards Track [Page 13]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ section 3.3.) Because the server need only use the hash of the user
+ credentials in order to create the A1 value, this construction could
+ be used in conjunction with a third party authentication service so
+ that the web server would not need the actual password value. The
+ specification of such a protocol is beyond the scope of this
+ specification.
+
+3.2.2.3 A2
+
+ If the "qop" directive's value is "auth" or is unspecified, then A2
+ is:
+
+ A2 = Method ":" digest-uri-value
+
+ If the "qop" value is "auth-int", then A2 is:
+
+ A2 = Method ":" digest-uri-value ":" H(entity-body)
+
+3.2.2.4 Directive values and quoted-string
+
+ Note that the value of many of the directives, such as "username-
+ value", are defined as a "quoted-string". However, the "unq" notation
+ indicates that surrounding quotation marks are removed in forming the
+ string A1. Thus if the Authorization header includes the fields
+
+ username="Mufasa", realm=myhost@testrealm.com
+
+ and the user Mufasa has password "Circle Of Life" then H(A1) would be
+ H(Mufasa:myhost@testrealm.com:Circle Of Life) with no quotation marks
+ in the digested string.
+
+ No white space is allowed in any of the strings to which the digest
+ function H() is applied unless that white space exists in the quoted
+ strings or entity body whose contents make up the string to be
+ digested. For example, the string A1 illustrated above must be
+
+ Mufasa:myhost@testrealm.com:Circle Of Life
+
+ with no white space on either side of the colons, but with the white
+ space between the words used in the password value. Likewise, the
+ other strings digested by H() must not have white space on either
+ side of the colons which delimit their fields unless that white space
+ was in the quoted strings or entity body being digested.
+
+ Also note that if integrity protection is applied (qop=auth-int), the
+ H(entity-body) is the hash of the entity body, not the message body -
+ it is computed before any transfer encoding is applied by the sender
+
+
+
+
+Franks, et al. Standards Track [Page 14]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ and after it has been removed by the recipient. Note that this
+ includes multipart boundaries and embedded headers in each part of
+ any multipart content-type.
+
+3.2.2.5 Various considerations
+
+ The "Method" value is the HTTP request method as specified in section
+ 5.1.1 of [2]. The "request-uri" value is the Request-URI from the
+ request line as specified in section 5.1.2 of [2]. This may be "*",
+ an "absoluteURL" or an "abs_path" as specified in section 5.1.2 of
+ [2], but it MUST agree with the Request-URI. In particular, it MUST
+ be an "absoluteURL" if the Request-URI is an "absoluteURL". The
+ "cnonce-value" is an optional client-chosen value whose purpose is
+ to foil chosen plaintext attacks.
+
+ The authenticating server must assure that the resource designated by
+ the "uri" directive is the same as the resource specified in the
+ Request-Line; if they are not, the server SHOULD return a 400 Bad
+ Request error. (Since this may be a symptom of an attack, server
+ implementers may want to consider logging such errors.) The purpose
+ of duplicating information from the request URL in this field is to
+ deal with the possibility that an intermediate proxy may alter the
+ client's Request-Line. This altered (but presumably semantically
+ equivalent) request would not result in the same digest as that
+ calculated by the client.
+
+ Implementers should be aware of how authenticated transactions
+ interact with shared caches. The HTTP/1.1 protocol specifies that
+ when a shared cache (see section 13.7 of [2]) has received a request
+ containing an Authorization header and a response from relaying that
+ request, it MUST NOT return that response as a reply to any other
+ request, unless one of two Cache-Control (see section 14.9 of [2])
+ directives was present in the response. If the original response
+ included the "must-revalidate" Cache-Control directive, the cache MAY
+ use the entity of that response in replying to a subsequent request,
+ but MUST first revalidate it with the origin server, using the
+ request headers from the new request to allow the origin server to
+ authenticate the new request. Alternatively, if the original response
+ included the "public" Cache-Control directive, the response entity
+ MAY be returned in reply to any subsequent request.
+
+3.2.3 The Authentication-Info Header
+
+ The Authentication-Info header is used by the server to communicate
+ some information regarding the successful authentication in the
+ response.
+
+
+
+
+
+Franks, et al. Standards Track [Page 15]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ AuthenticationInfo = "Authentication-Info" ":" auth-info
+ auth-info = 1#(nextnonce | [ message-qop ]
+ | [ response-auth ] | [ cnonce ]
+ | [nonce-count] )
+ nextnonce = "nextnonce" "=" nonce-value
+ response-auth = "rspauth" "=" response-digest
+ response-digest = <"> *LHEX <">
+
+ The value of the nextnonce directive is the nonce the server wishes
+ the client to use for a future authentication response. The server
+ may send the Authentication-Info header with a nextnonce field as a
+ means of implementing one-time or otherwise changing nonces. If the
+ nextnonce field is present the client SHOULD use it when constructing
+ the Authorization header for its next request. Failure of the client
+ to do so may result in a request to re-authenticate from the server
+ with the "stale=TRUE".
+
+ Server implementations should carefully consider the performance
+ implications of the use of this mechanism; pipelined requests will
+ not be possible if every response includes a nextnonce directive
+ that must be used on the next request received by the server.
+ Consideration should be given to the performance vs. security
+ tradeoffs of allowing an old nonce value to be used for a limited
+ time to permit request pipelining. Use of the nonce-count can
+ retain most of the security advantages of a new server nonce
+ without the deleterious affects on pipelining.
+
+ message-qop
+ Indicates the "quality of protection" options applied to the
+ response by the server. The value "auth" indicates authentication;
+ the value "auth-int" indicates authentication with integrity
+ protection. The server SHOULD use the same value for the message-
+ qop directive in the response as was sent by the client in the
+ corresponding request.
+
+ The optional response digest in the "response-auth" directive
+ supports mutual authentication -- the server proves that it knows the
+ user's secret, and with qop=auth-int also provides limited integrity
+ protection of the response. The "response-digest" value is calculated
+ as for the "request-digest" in the Authorization header, except that
+ if "qop=auth" or is not specified in the Authorization header for the
+ request, A2 is
+
+ A2 = ":" digest-uri-value
+
+ and if "qop=auth-int", then A2 is
+
+ A2 = ":" digest-uri-value ":" H(entity-body)
+
+
+
+Franks, et al. Standards Track [Page 16]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ where "digest-uri-value" is the value of the "uri" directive on the
+ Authorization header in the request. The "cnonce-value" and "nc-
+ value" MUST be the ones for the client request to which this message
+ is the response. The "response-auth", "cnonce", and "nonce-count"
+ directives MUST BE present if "qop=auth" or "qop=auth-int" is
+ specified.
+
+ The Authentication-Info header is allowed in the trailer of an HTTP
+ message transferred via chunked transfer-coding.
+
+3.3 Digest Operation
+
+ Upon receiving the Authorization header, the server may check its
+ validity by looking up the password that corresponds to the submitted
+ username. Then, the server must perform the same digest operation
+ (e.g., MD5) performed by the client, and compare the result to the
+ given request-digest value.
+
+ Note that the HTTP server does not actually need to know the user's
+ cleartext password. As long as H(A1) is available to the server, the
+ validity of an Authorization header may be verified.
+
+ The client response to a WWW-Authenticate challenge for a protection
+ space starts an authentication session with that protection space.
+ The authentication session lasts until the client receives another
+ WWW-Authenticate challenge from any server in the protection space. A
+ client should remember the username, password, nonce, nonce count and
+ opaque values associated with an authentication session to use to
+ construct the Authorization header in future requests within that
+ protection space. The Authorization header may be included
+ preemptively; doing so improves server efficiency and avoids extra
+ round trips for authentication challenges. The server may choose to
+ accept the old Authorization header information, even though the
+ nonce value included might not be fresh. Alternatively, the server
+ may return a 401 response with a new nonce value, causing the client
+ to retry the request; by specifying stale=TRUE with this response,
+ the server tells the client to retry with the new nonce, but without
+ prompting for a new username and password.
+
+ Because the client is required to return the value of the opaque
+ directive given to it by the server for the duration of a session,
+ the opaque data may be used to transport authentication session state
+ information. (Note that any such use can also be accomplished more
+ easily and safely by including the state in the nonce.) For example,
+ a server could be responsible for authenticating content that
+ actually sits on another server. It would achieve this by having the
+ first 401 response include a domain directive whose value includes a
+ URI on the second server, and an opaque directive whose value
+
+
+
+Franks, et al. Standards Track [Page 17]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ contains the state information. The client will retry the request, at
+ which time the server might respond with a 301/302 redirection,
+ pointing to the URI on the second server. The client will follow the
+ redirection, and pass an Authorization header , including the
+ <opaque> data.
+
+ As with the basic scheme, proxies must be completely transparent in
+ the Digest access authentication scheme. That is, they must forward
+ the WWW-Authenticate, Authentication-Info and Authorization headers
+ untouched. If a proxy wants to authenticate a client before a request
+ is forwarded to the server, it can be done using the Proxy-
+ Authenticate and Proxy-Authorization headers described in section 3.6
+ below.
+
+3.4 Security Protocol Negotiation
+
+ It is useful for a server to be able to know which security schemes a
+ client is capable of handling.
+
+ It is possible that a server may want to require Digest as its
+ authentication method, even if the server does not know that the
+ client supports it. A client is encouraged to fail gracefully if the
+ server specifies only authentication schemes it cannot handle.
+
+3.5 Example
+
+ The following example assumes that an access-protected document is
+ being requested from the server via a GET request. The URI of the
+ document is "http://www.nowhere.org/dir/index.html". Both client and
+ server know that the username for this document is "Mufasa", and the
+ password is "Circle Of Life" (with one space between each of the
+ three words).
+
+ The first time the client requests the document, no Authorization
+ header is sent, so the server responds with:
+
+ HTTP/1.1 401 Unauthorized
+ WWW-Authenticate: Digest
+ realm="testrealm@host.com",
+ qop="auth,auth-int",
+ nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
+ opaque="5ccc069c403ebaf9f0171e9517f40e41"
+
+ The client may prompt the user for the username and password, after
+ which it will respond with a new request, including the following
+ Authorization header:
+
+
+
+
+
+Franks, et al. Standards Track [Page 18]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ Authorization: Digest username="Mufasa",
+ realm="testrealm@host.com",
+ nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
+ uri="/dir/index.html",
+ qop=auth,
+ nc=00000001,
+ cnonce="0a4f113b",
+ response="6629fae49393a05397450978507c4ef1",
+ opaque="5ccc069c403ebaf9f0171e9517f40e41"
+
+3.6 Proxy-Authentication and Proxy-Authorization
+
+ The digest authentication scheme may also be used for authenticating
+ users to proxies, proxies to proxies, or proxies to origin servers by
+ use of the Proxy-Authenticate and Proxy-Authorization headers. These
+ headers are instances of the Proxy-Authenticate and Proxy-
+ Authorization headers specified in sections 10.33 and 10.34 of the
+ HTTP/1.1 specification [2] and their behavior is subject to
+ restrictions described there. The transactions for proxy
+ authentication are very similar to those already described. Upon
+ receiving a request which requires authentication, the proxy/server
+ must issue the "407 Proxy Authentication Required" response with a
+ "Proxy-Authenticate" header. The digest-challenge used in the
+ Proxy-Authenticate header is the same as that for the WWW-
+ Authenticate header as defined above in section 3.2.1.
+
+ The client/proxy must then re-issue the request with a Proxy-
+ Authorization header, with directives as specified for the
+ Authorization header in section 3.2.2 above.
+
+ On subsequent responses, the server sends Proxy-Authentication-Info
+ with directives the same as those for the Authentication-Info header
+ field.
+
+ Note that in principle a client could be asked to authenticate itself
+ to both a proxy and an end-server, but never in the same response.
+
+4 Security Considerations
+
+4.1 Authentication of Clients using Basic Authentication
+
+ The Basic authentication scheme is not a secure method of user
+ authentication, nor does it in any way protect the entity, which is
+ transmitted in cleartext across the physical network used as the
+ carrier. HTTP does not prevent additional authentication schemes and
+ encryption mechanisms from being employed to increase security or the
+ addition of enhancements (such as schemes to use one-time passwords)
+ to Basic authentication.
+
+
+
+Franks, et al. Standards Track [Page 19]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ The most serious flaw in Basic authentication is that it results in
+ the essentially cleartext transmission of the user's password over
+ the physical network. It is this problem which Digest Authentication
+ attempts to address.
+
+ Because Basic authentication involves the cleartext transmission of
+ passwords it SHOULD NOT be used (without enhancements) to protect
+ sensitive or valuable information.
+
+ A common use of Basic authentication is for identification purposes
+ -- requiring the user to provide a user name and password as a means
+ of identification, for example, for purposes of gathering accurate
+ usage statistics on a server. When used in this way it is tempting to
+ think that there is no danger in its use if illicit access to the
+ protected documents is not a major concern. This is only correct if
+ the server issues both user name and password to the users and in
+ particular does not allow the user to choose his or her own password.
+ The danger arises because naive users frequently reuse a single
+ password to avoid the task of maintaining multiple passwords.
+
+ If a server permits users to select their own passwords, then the
+ threat is not only unauthorized access to documents on the server but
+ also unauthorized access to any other resources on other systems that
+ the user protects with the same password. Furthermore, in the
+ server's password database, many of the passwords may also be users'
+ passwords for other sites. The owner or administrator of such a
+ system could therefore expose all users of the system to the risk of
+ unauthorized access to all those sites if this information is not
+ maintained in a secure fashion.
+
+ Basic Authentication is also vulnerable to spoofing by counterfeit
+ servers. If a user can be led to believe that he is connecting to a
+ host containing information protected by Basic authentication when,
+ in fact, he is connecting to a hostile server or gateway, then the
+ attacker can request a password, store it for later use, and feign an
+ error. This type of attack is not possible with Digest
+ Authentication. Server implementers SHOULD guard against the
+ possibility of this sort of counterfeiting by gateways or CGI
+ scripts. In particular it is very dangerous for a server to simply
+ turn over a connection to a gateway. That gateway can then use the
+ persistent connection mechanism to engage in multiple transactions
+ with the client while impersonating the original server in a way that
+ is not detectable by the client.
+
+4.2 Authentication of Clients using Digest Authentication
+
+ Digest Authentication does not provide a strong authentication
+ mechanism, when compared to public key based mechanisms, for example.
+
+
+
+Franks, et al. Standards Track [Page 20]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ However, it is significantly stronger than (e.g.) CRAM-MD5, which has
+ been proposed for use with LDAP [10], POP and IMAP (see RFC 2195
+ [9]). It is intended to replace the much weaker and even more
+ dangerous Basic mechanism.
+
+ Digest Authentication offers no confidentiality protection beyond
+ protecting the actual password. All of the rest of the request and
+ response are available to an eavesdropper.
+
+ Digest Authentication offers only limited integrity protection for
+ the messages in either direction. If qop=auth-int mechanism is used,
+ those parts of the message used in the calculation of the WWW-
+ Authenticate and Authorization header field response directive values
+ (see section 3.2 above) are protected. Most header fields and their
+ values could be modified as a part of a man-in-the-middle attack.
+
+ Many needs for secure HTTP transactions cannot be met by Digest
+ Authentication. For those needs TLS or SHTTP are more appropriate
+ protocols. In particular Digest authentication cannot be used for any
+ transaction requiring confidentiality protection. Nevertheless many
+ functions remain for which Digest authentication is both useful and
+ appropriate. Any service in present use that uses Basic should be
+ switched to Digest as soon as practical.
+
+4.3 Limited Use Nonce Values
+
+ The Digest scheme uses a server-specified nonce to seed the
+ generation of the request-digest value (as specified in section
+ 3.2.2.1 above). As shown in the example nonce in section 3.2.1, the
+ server is free to construct the nonce such that it may only be used
+ from a particular client, for a particular resource, for a limited
+ period of time or number of uses, or any other restrictions. Doing
+ so strengthens the protection provided against, for example, replay
+ attacks (see 4.5). However, it should be noted that the method
+ chosen for generating and checking the nonce also has performance and
+ resource implications. For example, a server may choose to allow
+ each nonce value to be used only once by maintaining a record of
+ whether or not each recently issued nonce has been returned and
+ sending a next-nonce directive in the Authentication-Info header
+ field of every response. This protects against even an immediate
+ replay attack, but has a high cost checking nonce values, and perhaps
+ more important will cause authentication failures for any pipelined
+ requests (presumably returning a stale nonce indication). Similarly,
+ incorporating a request-specific element such as the Etag value for a
+ resource limits the use of the nonce to that version of the resource
+ and also defeats pipelining. Thus it may be useful to do so for
+ methods with side effects but have unacceptable performance for those
+ that do not.
+
+
+
+Franks, et al. Standards Track [Page 21]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+4.4 Comparison of Digest with Basic Authentication
+
+ Both Digest and Basic Authentication are very much on the weak end of
+ the security strength spectrum. But a comparison between the two
+ points out the utility, even necessity, of replacing Basic by Digest.
+
+ The greatest threat to the type of transactions for which these
+ protocols are used is network snooping. This kind of transaction
+ might involve, for example, online access to a database whose use is
+ restricted to paying subscribers. With Basic authentication an
+ eavesdropper can obtain the password of the user. This not only
+ permits him to access anything in the database, but, often worse,
+ will permit access to anything else the user protects with the same
+ password.
+
+ By contrast, with Digest Authentication the eavesdropper only gets
+ access to the transaction in question and not to the user's password.
+ The information gained by the eavesdropper would permit a replay
+ attack, but only with a request for the same document, and even that
+ may be limited by the server's choice of nonce.
+
+4.5 Replay Attacks
+
+ A replay attack against Digest authentication would usually be
+ pointless for a simple GET request since an eavesdropper would
+ already have seen the only document he could obtain with a replay.
+ This is because the URI of the requested document is digested in the
+ client request and the server will only deliver that document. By
+ contrast under Basic Authentication once the eavesdropper has the
+ user's password, any document protected by that password is open to
+ him.
+
+ Thus, for some purposes, it is necessary to protect against replay
+ attacks. A good Digest implementation can do this in various ways.
+ The server created "nonce" value is implementation dependent, but if
+ it contains a digest of the client IP, a time-stamp, the resource
+ ETag, and a private server key (as recommended above) then a replay
+ attack is not simple. An attacker must convince the server that the
+ request is coming from a false IP address and must cause the server
+ to deliver the document to an IP address different from the address
+ to which it believes it is sending the document. An attack can only
+ succeed in the period before the time-stamp expires. Digesting the
+ client IP and time-stamp in the nonce permits an implementation which
+ does not maintain state between transactions.
+
+ For applications where no possibility of replay attack can be
+ tolerated the server can use one-time nonce values which will not be
+ honored for a second use. This requires the overhead of the server
+
+
+
+Franks, et al. Standards Track [Page 22]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ remembering which nonce values have been used until the nonce time-
+ stamp (and hence the digest built with it) has expired, but it
+ effectively protects against replay attacks.
+
+ An implementation must give special attention to the possibility of
+ replay attacks with POST and PUT requests. Unless the server employs
+ one-time or otherwise limited-use nonces and/or insists on the use of
+ the integrity protection of qop=auth-int, an attacker could replay
+ valid credentials from a successful request with counterfeit form
+ data or other message body. Even with the use of integrity protection
+ most metadata in header fields is not protected. Proper nonce
+ generation and checking provides some protection against replay of
+ previously used valid credentials, but see 4.8.
+
+4.6 Weakness Created by Multiple Authentication Schemes
+
+ An HTTP/1.1 server may return multiple challenges with a 401
+ (Authenticate) response, and each challenge may use a different
+ auth-scheme. A user agent MUST choose to use the strongest auth-
+ scheme it understands and request credentials from the user based
+ upon that challenge.
+
+ Note that many browsers will only recognize Basic and will require
+ that it be the first auth-scheme presented. Servers should only
+ include Basic if it is minimally acceptable.
+
+ When the server offers choices of authentication schemes using the
+ WWW-Authenticate header, the strength of the resulting authentication
+ is only as good as that of the of the weakest of the authentication
+ schemes. See section 4.8 below for discussion of particular attack
+ scenarios that exploit multiple authentication schemes.
+
+4.7 Online dictionary attacks
+
+ If the attacker can eavesdrop, then it can test any overheard
+ nonce/response pairs against a list of common words. Such a list is
+ usually much smaller than the total number of possible passwords. The
+ cost of computing the response for each password on the list is paid
+ once for each challenge.
+
+ The server can mitigate this attack by not allowing users to select
+ passwords that are in a dictionary.
+
+
+
+
+
+
+
+
+
+Franks, et al. Standards Track [Page 23]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+4.8 Man in the Middle
+
+ Both Basic and Digest authentication are vulnerable to "man in the
+ middle" (MITM) attacks, for example, from a hostile or compromised
+ proxy. Clearly, this would present all the problems of eavesdropping.
+ But it also offers some additional opportunities to the attacker.
+
+ A possible man-in-the-middle attack would be to add a weak
+ authentication scheme to the set of choices, hoping that the client
+ will use one that exposes the user's credentials (e.g. password). For
+ this reason, the client should always use the strongest scheme that
+ it understands from the choices offered.
+
+ An even better MITM attack would be to remove all offered choices,
+ replacing them with a challenge that requests only Basic
+ authentication, then uses the cleartext credentials from the Basic
+ authentication to authenticate to the origin server using the
+ stronger scheme it requested. A particularly insidious way to mount
+ such a MITM attack would be to offer a "free" proxy caching service
+ to gullible users.
+
+ User agents should consider measures such as presenting a visual
+ indication at the time of the credentials request of what
+ authentication scheme is to be used, or remembering the strongest
+ authentication scheme ever requested by a server and produce a
+ warning message before using a weaker one. It might also be a good
+ idea for the user agent to be configured to demand Digest
+ authentication in general, or from specific sites.
+
+ Or, a hostile proxy might spoof the client into making a request the
+ attacker wanted rather than one the client wanted. Of course, this is
+ still much harder than a comparable attack against Basic
+ Authentication.
+
+4.9 Chosen plaintext attacks
+
+ With Digest authentication, a MITM or a malicious server can
+ arbitrarily choose the nonce that the client will use to compute the
+ response. This is called a "chosen plaintext" attack. The ability to
+ choose the nonce is known to make cryptanalysis much easier [8].
+
+ However, no way to analyze the MD5 one-way function used by Digest
+ using chosen plaintext is currently known.
+
+ The countermeasure against this attack is for clients to be
+ configured to require the use of the optional "cnonce" directive;
+ this allows the client to vary the input to the hash in a way not
+ chosen by the attacker.
+
+
+
+Franks, et al. Standards Track [Page 24]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+4.10 Precomputed dictionary attacks
+
+ With Digest authentication, if the attacker can execute a chosen
+ plaintext attack, the attacker can precompute the response for many
+ common words to a nonce of its choice, and store a dictionary of
+ (response, password) pairs. Such precomputation can often be done in
+ parallel on many machines. It can then use the chosen plaintext
+ attack to acquire a response corresponding to that challenge, and
+ just look up the password in the dictionary. Even if most passwords
+ are not in the dictionary, some might be. Since the attacker gets to
+ pick the challenge, the cost of computing the response for each
+ password on the list can be amortized over finding many passwords. A
+ dictionary with 100 million password/response pairs would take about
+ 3.2 gigabytes of disk storage.
+
+ The countermeasure against this attack is to for clients to be
+ configured to require the use of the optional "cnonce" directive.
+
+4.11 Batch brute force attacks
+
+ With Digest authentication, a MITM can execute a chosen plaintext
+ attack, and can gather responses from many users to the same nonce.
+ It can then find all the passwords within any subset of password
+ space that would generate one of the nonce/response pairs in a single
+ pass over that space. It also reduces the time to find the first
+ password by a factor equal to the number of nonce/response pairs
+ gathered. This search of the password space can often be done in
+ parallel on many machines, and even a single machine can search large
+ subsets of the password space very quickly -- reports exist of
+ searching all passwords with six or fewer letters in a few hours.
+
+ The countermeasure against this attack is to for clients to be
+ configured to require the use of the optional "cnonce" directive.
+
+4.12 Spoofing by Counterfeit Servers
+
+ Basic Authentication is vulnerable to spoofing by counterfeit
+ servers. If a user can be led to believe that she is connecting to a
+ host containing information protected by a password she knows, when
+ in fact she is connecting to a hostile server, then the hostile
+ server can request a password, store it away for later use, and feign
+ an error. This type of attack is more difficult with Digest
+ Authentication -- but the client must know to demand that Digest
+ authentication be used, perhaps using some of the techniques
+ described above to counter "man-in-the-middle" attacks. Again, the
+ user can be helped in detecting this attack by a visual indication of
+ the authentication mechanism in use with appropriate guidance in
+ interpreting the implications of each scheme.
+
+
+
+Franks, et al. Standards Track [Page 25]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+4.13 Storing passwords
+
+ Digest authentication requires that the authenticating agent (usually
+ the server) store some data derived from the user's name and password
+ in a "password file" associated with a given realm. Normally this
+ might contain pairs consisting of username and H(A1), where H(A1) is
+ the digested value of the username, realm, and password as described
+ above.
+
+ The security implications of this are that if this password file is
+ compromised, then an attacker gains immediate access to documents on
+ the server using this realm. Unlike, say a standard UNIX password
+ file, this information need not be decrypted in order to access
+ documents in the server realm associated with this file. On the other
+ hand, decryption, or more likely a brute force attack, would be
+ necessary to obtain the user's password. This is the reason that the
+ realm is part of the digested data stored in the password file. It
+ means that if one Digest authentication password file is compromised,
+ it does not automatically compromise others with the same username
+ and password (though it does expose them to brute force attack).
+
+ There are two important security consequences of this. First the
+ password file must be protected as if it contained unencrypted
+ passwords, because for the purpose of accessing documents in its
+ realm, it effectively does.
+
+ A second consequence of this is that the realm string should be
+ unique among all realms which any single user is likely to use. In
+ particular a realm string should include the name of the host doing
+ the authentication. The inability of the client to authenticate the
+ server is a weakness of Digest Authentication.
+
+4.14 Summary
+
+ By modern cryptographic standards Digest Authentication is weak. But
+ for a large range of purposes it is valuable as a replacement for
+ Basic Authentication. It remedies some, but not all, weaknesses of
+ Basic Authentication. Its strength may vary depending on the
+ implementation. In particular the structure of the nonce (which is
+ dependent on the server implementation) may affect the ease of
+ mounting a replay attack. A range of server options is appropriate
+ since, for example, some implementations may be willing to accept the
+ server overhead of one-time nonces or digests to eliminate the
+ possibility of replay. Others may satisfied with a nonce like the one
+ recommended above restricted to a single IP address and a single ETag
+ or with a limited lifetime.
+
+
+
+
+
+Franks, et al. Standards Track [Page 26]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ The bottom line is that *any* compliant implementation will be
+ relatively weak by cryptographic standards, but *any* compliant
+ implementation will be far superior to Basic Authentication.
+
+5 Sample implementation
+
+ The following code implements the calculations of H(A1), H(A2),
+ request-digest and response-digest, and a test program which computes
+ the values used in the example of section 3.5. It uses the MD5
+ implementation from RFC 1321.
+
+ File "digcalc.h":
+
+#define HASHLEN 16
+typedef char HASH[HASHLEN];
+#define HASHHEXLEN 32
+typedef char HASHHEX[HASHHEXLEN+1];
+#define IN
+#define OUT
+
+/* calculate H(A1) as per HTTP Digest spec */
+void DigestCalcHA1(
+ IN char * pszAlg,
+ IN char * pszUserName,
+ IN char * pszRealm,
+ IN char * pszPassword,
+ IN char * pszNonce,
+ IN char * pszCNonce,
+ OUT HASHHEX SessionKey
+ );
+
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+void DigestCalcResponse(
+ IN HASHHEX HA1, /* H(A1) */
+ IN char * pszNonce, /* nonce from server */
+ IN char * pszNonceCount, /* 8 hex digits */
+ IN char * pszCNonce, /* client nonce */
+ IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
+ IN char * pszMethod, /* method from the request */
+ IN char * pszDigestUri, /* requested URL */
+ IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
+ OUT HASHHEX Response /* request-digest or response-digest */
+ );
+
+File "digcalc.c":
+
+#include <global.h>
+#include <md5.h>
+
+
+
+Franks, et al. Standards Track [Page 27]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+#include <string.h>
+#include "digcalc.h"
+
+void CvtHex(
+ IN HASH Bin,
+ OUT HASHHEX Hex
+ )
+{
+ unsigned short i;
+ unsigned char j;
+
+ for (i = 0; i < HASHLEN; i++) {
+ j = (Bin[i] >> 4) & 0xf;
+ if (j <= 9)
+ Hex[i*2] = (j + '0');
+ else
+ Hex[i*2] = (j + 'a' - 10);
+ j = Bin[i] & 0xf;
+ if (j <= 9)
+ Hex[i*2+1] = (j + '0');
+ else
+ Hex[i*2+1] = (j + 'a' - 10);
+ };
+ Hex[HASHHEXLEN] = '\0';
+};
+
+/* calculate H(A1) as per spec */
+void DigestCalcHA1(
+ IN char * pszAlg,
+ IN char * pszUserName,
+ IN char * pszRealm,
+ IN char * pszPassword,
+ IN char * pszNonce,
+ IN char * pszCNonce,
+ OUT HASHHEX SessionKey
+ )
+{
+ MD5_CTX Md5Ctx;
+ HASH HA1;
+
+ MD5Init(&Md5Ctx);
+ MD5Update(&Md5Ctx, pszUserName, strlen(pszUserName));
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszRealm, strlen(pszRealm));
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszPassword, strlen(pszPassword));
+ MD5Final(HA1, &Md5Ctx);
+ if (stricmp(pszAlg, "md5-sess") == 0) {
+
+
+
+Franks, et al. Standards Track [Page 28]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ MD5Init(&Md5Ctx);
+ MD5Update(&Md5Ctx, HA1, HASHLEN);
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce));
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));
+ MD5Final(HA1, &Md5Ctx);
+ };
+ CvtHex(HA1, SessionKey);
+};
+
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+void DigestCalcResponse(
+ IN HASHHEX HA1, /* H(A1) */
+ IN char * pszNonce, /* nonce from server */
+ IN char * pszNonceCount, /* 8 hex digits */
+ IN char * pszCNonce, /* client nonce */
+ IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
+ IN char * pszMethod, /* method from the request */
+ IN char * pszDigestUri, /* requested URL */
+ IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
+ OUT HASHHEX Response /* request-digest or response-digest */
+ )
+{
+ MD5_CTX Md5Ctx;
+ HASH HA2;
+ HASH RespHash;
+ HASHHEX HA2Hex;
+
+ // calculate H(A2)
+ MD5Init(&Md5Ctx);
+ MD5Update(&Md5Ctx, pszMethod, strlen(pszMethod));
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszDigestUri, strlen(pszDigestUri));
+ if (stricmp(pszQop, "auth-int") == 0) {
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);
+ };
+ MD5Final(HA2, &Md5Ctx);
+ CvtHex(HA2, HA2Hex);
+
+ // calculate response
+ MD5Init(&Md5Ctx);
+ MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce));
+ MD5Update(&Md5Ctx, ":", 1);
+ if (*pszQop) {
+
+
+
+Franks, et al. Standards Track [Page 29]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ MD5Update(&Md5Ctx, pszNonceCount, strlen(pszNonceCount));
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));
+ MD5Update(&Md5Ctx, ":", 1);
+ MD5Update(&Md5Ctx, pszQop, strlen(pszQop));
+ MD5Update(&Md5Ctx, ":", 1);
+ };
+ MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
+ MD5Final(RespHash, &Md5Ctx);
+ CvtHex(RespHash, Response);
+};
+
+File "digtest.c":
+
+
+#include <stdio.h>
+#include "digcalc.h"
+
+void main(int argc, char ** argv) {
+
+ char * pszNonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093";
+ char * pszCNonce = "0a4f113b";
+ char * pszUser = "Mufasa";
+ char * pszRealm = "testrealm@host.com";
+ char * pszPass = "Circle Of Life";
+ char * pszAlg = "md5";
+ char szNonceCount[9] = "00000001";
+ char * pszMethod = "GET";
+ char * pszQop = "auth";
+ char * pszURI = "/dir/index.html";
+ HASHHEX HA1;
+ HASHHEX HA2 = "";
+ HASHHEX Response;
+
+ DigestCalcHA1(pszAlg, pszUser, pszRealm, pszPass, pszNonce,
+pszCNonce, HA1);
+ DigestCalcResponse(HA1, pszNonce, szNonceCount, pszCNonce, pszQop,
+ pszMethod, pszURI, HA2, Response);
+ printf("Response = %s\n", Response);
+};
+
+
+
+
+
+
+
+
+
+
+
+Franks, et al. Standards Track [Page 30]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+6 Acknowledgments
+
+ Eric W. Sink, of AbiSource, Inc., was one of the original authors
+ before the specification underwent substantial revision.
+
+ In addition to the authors, valuable discussion instrumental in
+ creating this document has come from Peter J. Churchyard, Ned Freed,
+ and David M. Kristol.
+
+ Jim Gettys and Larry Masinter edited this document for update.
+
+7 References
+
+ [1] Berners-Lee, T., Fielding, R. and H. Frystyk, "Hypertext
+ Transfer Protocol -- HTTP/1.0", RFC 1945, May 1996.
+
+ [2] Fielding, R., Gettys, J., Mogul, J., Frysyk, H., Masinter, L.,
+ Leach, P. and T. Berners-Lee, "Hypertext Transfer Protocol --
+ HTTP/1.1", RFC 2616, June 1999.
+
+ [3] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, April
+ 1992.
+
+ [4] Freed, N. and N. Borenstein. "Multipurpose Internet Mail
+ Extensions (MIME) Part One: Format of Internet Message Bodies",
+ RFC 2045, November 1996.
+
+ [5] Dierks, T. and C. Allen "The TLS Protocol, Version 1.0", RFC
+ 2246, January 1999.
+
+ [6] Franks, J., Hallam-Baker, P., Hostetler, J., Leach, P.,
+ Luotonen, A., Sink, E. and L. Stewart, "An Extension to HTTP :
+ Digest Access Authentication", RFC 2069, January 1997.
+
+ [7] Berners Lee, T, Fielding, R. and L. Masinter, "Uniform Resource
+ Identifiers (URI): Generic Syntax", RFC 2396, August 1998.
+
+ [8] Kaliski, B.,Robshaw, M., "Message Authentication with MD5",
+ CryptoBytes, Sping 1995, RSA Inc,
+ (http://www.rsa.com/rsalabs/pubs/cryptobytes/spring95/md5.htm)
+
+ [9] Klensin, J., Catoe, R. and P. Krumviede, "IMAP/POP AUTHorize
+ Extension for Simple Challenge/Response", RFC 2195, September
+ 1997.
+
+ [10] Morgan, B., Alvestrand, H., Hodges, J., Wahl, M.,
+ "Authentication Methods for LDAP", Work in Progress.
+
+
+
+
+Franks, et al. Standards Track [Page 31]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+8 Authors' Addresses
+
+ John Franks
+ Professor of Mathematics
+ Department of Mathematics
+ Northwestern University
+ Evanston, IL 60208-2730, USA
+
+ EMail: john@math.nwu.edu
+
+
+ Phillip M. Hallam-Baker
+ Principal Consultant
+ Verisign Inc.
+ 301 Edgewater Place
+ Suite 210
+ Wakefield MA 01880, USA
+
+ EMail: pbaker@verisign.com
+
+
+ Jeffery L. Hostetler
+ Software Craftsman
+ AbiSource, Inc.
+ 6 Dunlap Court
+ Savoy, IL 61874
+
+ EMail: jeff@AbiSource.com
+
+
+ Scott D. Lawrence
+ Agranat Systems, Inc.
+ 5 Clocktower Place, Suite 400
+ Maynard, MA 01754, USA
+
+ EMail: lawrence@agranat.com
+
+
+ Paul J. Leach
+ Microsoft Corporation
+ 1 Microsoft Way
+ Redmond, WA 98052, USA
+
+ EMail: paulle@microsoft.com
+
+
+
+
+
+
+
+Franks, et al. Standards Track [Page 32]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+ Ari Luotonen
+ Member of Technical Staff
+ Netscape Communications Corporation
+ 501 East Middlefield Road
+ Mountain View, CA 94043, USA
+
+
+ Lawrence C. Stewart
+ Open Market, Inc.
+ 215 First Street
+ Cambridge, MA 02142, USA
+
+ EMail: stewart@OpenMarket.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Franks, et al. Standards Track [Page 33]
+
+RFC 2617 HTTP Authentication June 1999
+
+
+9. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Franks, et al. Standards Track [Page 34]
+
diff --git a/standards/rfc2712.txt b/standards/rfc2712.txt
new file mode 100644
index 000000000..4888e2e2d
--- /dev/null
+++ b/standards/rfc2712.txt
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+Network Working Group A. Medvinsky
+Request for Comments: 2712 Excite
+Category: Standards Track M. Hur
+ CyberSafe Corporation
+ October 1999
+
+
+ Addition of Kerberos Cipher Suites to Transport Layer Security (TLS)
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+IESG Note:
+
+ The 40-bit ciphersuites defined in this memo are included only for
+ the purpose of documenting the fact that those ciphersuite codes have
+ already been assigned. 40-bit ciphersuites were designed to comply
+ with US-centric, and now obsolete, export restrictions. They were
+ never secure, and nowadays are inadequate even for casual
+ applications. Implementation and use of the 40-bit ciphersuites
+ defined in this document, and elsewhere, is strongly discouraged.
+
+1. Abstract
+
+ This document proposes the addition of new cipher suites to the TLS
+ protocol [1] to support Kerberos-based authentication. Kerberos
+ credentials are used to achieve mutual authentication and to
+ establish a master secret which is subsequently used to secure
+ client-server communication.
+
+2. Introduction
+
+ Flexibility is one of the main strengths of the TLS protocol.
+ Clients and servers can negotiate cipher suites to meet specific
+ security and administrative policies. However, to date,
+ authentication in TLS is limited only to public key solutions. As a
+ result, TLS does not fully support organizations with heterogeneous
+ security deployments that include authentication systems based on
+ symmetric cryptography. Kerberos, originally developed at MIT, is
+
+
+
+Medvinsky & Hur Standards Track [Page 1]
+
+RFC 2712 Addition of Kerberos Cipher Suites to TLS October 1999
+
+
+ based on an open standard [2] and is the most widely deployed
+ symmetric key authentication system. This document proposes a new
+ option for negotiating Kerberos authentication within the TLS
+ framework. This achieves mutual authentication and the establishment
+ of a master secret using Kerberos credentials. The proposed changes
+ are minimal and, in fact, no different from adding a new public key
+ algorithm to the TLS framework.
+
+3. Kerberos Authentication Option In TLS
+
+ This section describes the addition of the Kerberos authentication
+ option to the TLS protocol. Throughout this document, we refer to
+ the basic SSL handshake shown in Figure 1. For a review of the TLS
+ handshake see [1].
+
+ CLIENT SERVER
+ ------ ------
+ ClientHello
+ -------------------------------->
+ ServerHello
+ Certificate *
+ ServerKeyExchange*
+ CertificateRequest*
+ ServerHelloDone
+ <-------------------------------
+ Certificate*
+ ClientKeyExchange
+ CertificateVerify*
+ change cipher spec
+ Finished
+ | -------------------------------->
+ | change cipher spec
+ | Finished
+ | |
+ | |
+ Application Data <------------------------------->Application Data
+
+ FIGURE 1: The TLS protocol. All messages followed by a star are
+ optional. Note: This figure was taken from an IETF document
+ [1].
+
+ The TLS security context is negotiated in the client and server hello
+ messages. For example: TLS_RSA_WITH_RC4_MD5 means the initial
+ authentication will be done using the RSA public key algorithm, RC4
+ will be used for the session key, and MACs will be based on the MD5
+ algorithm. Thus, to facilitate the Kerberos authentication option,
+ we must start by defining new cipher suites including (but not
+ limited to):
+
+
+
+Medvinsky & Hur Standards Track [Page 2]
+
+RFC 2712 Addition of Kerberos Cipher Suites to TLS October 1999
+
+
+ CipherSuite TLS_KRB5_WITH_DES_CBC_SHA = { 0x00,0x1E };
+ CipherSuite TLS_KRB5_WITH_3DES_EDE_CBC_SHA = { 0x00,0x1F };
+ CipherSuite TLS_KRB5_WITH_RC4_128_SHA = { 0x00,0x20 };
+ CipherSuite TLS_KRB5_WITH_IDEA_CBC_SHA = { 0x00,0x21 };
+ CipherSuite TLS_KRB5_WITH_DES_CBC_MD5 = { 0x00,0x22 };
+ CipherSuite TLS_KRB5_WITH_3DES_EDE_CBC_MD5 = { 0x00,0x23 };
+ CipherSuite TLS_KRB5_WITH_RC4_128_MD5 = { 0x00,0x24 };
+ CipherSuite TLS_KRB5_WITH_IDEA_CBC_MD5 = { 0x00,0x25 };
+
+ CipherSuite TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA = { 0x00,0x26 };
+ CipherSuite TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA = { 0x00,0x27 };
+ CipherSuite TLS_KRB5_EXPORT_WITH_RC4_40_SHA = { 0x00,0x28 };
+ CipherSuite TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 = { 0x00,0x29 };
+ CipherSuite TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 = { 0x00,0x2A };
+ CipherSuite TLS_KRB5_EXPORT_WITH_RC4_40_MD5 = { 0x00,0x2B };
+
+ To establish a Kerberos-based security context, one or more of the
+ above cipher suites must be specified in the client hello message.
+ If the TLS server supports the Kerberos authentication option, the
+ server hello message, sent to the client, will confirm the Kerberos
+ cipher suite selected by the server. The server's certificate, the
+ client
+
+ CertificateRequest, and the ServerKeyExchange shown in Figure 1 will
+ be omitted since authentication and the establishment of a master
+ secret will be done using the client's Kerberos credentials for the
+ TLS server. The client's certificate will be omitted for the same
+ reason. Note that these messages are specified as optional in the
+ TLS protocol; therefore, omitting them is permissible.
+
+ The Kerberos option must be added to the ClientKeyExchange message as
+ shown in Figure 2.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Medvinsky & Hur Standards Track [Page 3]
+
+RFC 2712 Addition of Kerberos Cipher Suites to TLS October 1999
+
+
+ struct
+ {
+ select (KeyExchangeAlgorithm)
+ {
+ case krb5: KerberosWrapper; /* new addition */
+ case rsa: EncryptedPreMasterSecret;
+ case diffie_hellman: ClientDiffieHellmanPublic;
+ } Exchange_keys;
+
+ } ClientKeyExchange;
+
+ struct
+ {
+ opaque Ticket;
+ opaque authenticator; /* optional */
+ opaque EncryptedPreMasterSecret; /* encrypted with the session key
+ which is sealed in the ticket */
+ } KerberosWrapper; /* new addition */
+
+ FIGURE 2: The Kerberos option in the ClientKeyExchange.
+
+ To use the Kerberos authentication option, the TLS client must obtain
+ a service ticket for the TLS server. In TLS, the ClientKeyExchange
+ message is used to pass a random 48-byte pre-master secret to the
+ server.
+
+ The client and server then use the pre-master secret to independently
+ derive the master secret, which in turn is used for generating
+ session keys and for MAC computations. Thus, if the Kerberos option
+ is selected, the pre-master secret structure is the same as that used
+ in the RSA case; it is encrypted under the Kerberos session key and
+ sent to the TLS server along with the Kerberos credentials (see
+ Figure 2). The ticket and authenticator are encoded per RFC 1510
+ (ASN.1 encoding). Once the ClientKeyExchange message is received,
+ the server's secret key is used to unwrap the credentials and extract
+ the pre-master secret.
+
+ Note that a Kerberos authenticator is not required, since the master
+ secret derived by the client and server is seeded with a random value
+ passed in the server hello message, thus foiling replay attacks.
+ However, the authenticator may still prove useful for passing
+ authorization information and is thus allotted an optional field (see
+ Figure 2).
+
+ Lastly, the client and server exchange the finished messages to
+ complete the handshake. At this point we have achieved the
+ following:
+
+
+
+
+Medvinsky & Hur Standards Track [Page 4]
+
+RFC 2712 Addition of Kerberos Cipher Suites to TLS October 1999
+
+
+ 1) A master secret, used to protect all subsequent communication, is
+ securely established.
+
+ 2) Mutual client-server authentication is achieved, since the TLS
+ server proves knowledge of the master secret in the finished
+ message.
+
+ Note that the Kerberos option fits in seamlessly, without adding any
+ new messages.
+
+4. Naming Conventions:
+
+ To obtain an appropriate service ticket, the TLS client must
+ determine the principal name of the TLS server. The Kerberos service
+ naming convention is used for this purpose, as follows:
+
+ host/MachineName@Realm
+ where:
+ - The literal, "host", follows the Kerberos convention when not
+ concerned about the protection domain on a particular machine.
+ - "MachineName" is the particular instance of the service.
+ - The Kerberos "Realm" is the domain name of the machine.
+
+5. Summary
+
+ The proposed Kerberos authentication option is added in exactly the
+ same manner as a new public key algorithm would be added to TLS.
+ Furthermore, it establishes the master secret in exactly the same
+ manner.
+
+6. Security Considerations
+
+ Kerberos ciphersuites are subject to the same security considerations
+ as the TLS protocol. In addition, just as a public key
+ implementation must take care to protect the private key (for example
+ the PIN for a smartcard), a Kerberos implementation must take care to
+ protect the long lived secret that is shared between the principal
+ and the KDC. In particular, a weak password may be subject to a
+ dictionary attack. In order to strengthen the initial authentication
+ to a KDC, an implementor may choose to utilize secondary
+ authentication via a token card, or one may utilize initial
+ authentication to the KDC based on public key cryptography (commonly
+ known as PKINIT - a product of the Common Authentication Technology
+ working group of the IETF).
+
+
+
+
+
+
+
+Medvinsky & Hur Standards Track [Page 5]
+
+RFC 2712 Addition of Kerberos Cipher Suites to TLS October 1999
+
+
+7. Acknowledgements
+
+ We would like to thank Clifford Neuman for his invaluable comments on
+ earlier versions of this document.
+
+8. References
+
+ [1] Dierks, T. and C. Allen, "The TLS Protocol, Version 1.0", RFC
+ 2246, January 1999.
+
+ [2] Kohl J. and C. Neuman, "The Kerberos Network Authentication
+ Service (V5)", RFC 1510, September 1993.
+
+9. Authors' Addresses
+
+ Ari Medvinsky
+ Excite
+ 555 Broadway
+ Redwood City, CA 94063
+
+ Phone: +1 650 569 2119
+ EMail: amedvins@excitecorp.com
+ http://www.excite.com
+
+
+ Matthew Hur
+ CyberSafe Corporation
+ 1605 NW Sammamish Road
+ Issaquah WA 98027-5378
+
+ Phone: +1 425 391 6000
+ EMail: matt.hur@cybersafe.com
+ http://www.cybersafe.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Medvinsky & Hur Standards Track [Page 6]
+
+RFC 2712 Addition of Kerberos Cipher Suites to TLS October 1999
+
+
+10. Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Medvinsky & Hur Standards Track [Page 7]
+
diff --git a/standards/rfc2790.txt b/standards/rfc2790.txt
new file mode 100644
index 000000000..3b0ddd81b
--- /dev/null
+++ b/standards/rfc2790.txt
@@ -0,0 +1,2803 @@
+
+
+
+
+
+
+Network Working Group S. Waldbusser
+Request for Comments: 2790 Lucent Technologies Inc.
+Obsoletes: 1514 P. Grillo
+Category: Standards Track WeSync.com
+ March 2000
+
+
+ Host Resources MIB
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+Abstract
+
+ This memo defines a portion of the Management Information Base (MIB)
+ for use with network management protocols in the Internet community.
+ This memo obsoletes RFC 1514, the "Host Resources MIB". This memo
+ extends that specification by clarifying changes based on
+ implementation and deployment experience and documenting the Host
+ Resources MIB in SMIv2 format while remaining semantically identical
+ to the existing SMIv1-based MIB.
+
+ This memo defines a MIB for use with managing host systems. The term
+ "host" is construed to mean any computer that communicates with other
+ similar computers attached to the internet and that is directly used
+ by one or more human beings. Although this MIB does not necessarily
+ apply to devices whose primary function is communications services
+ (e.g., terminal servers, routers, bridges, monitoring equipment),
+ such relevance is not explicitly precluded. This MIB instruments
+ attributes common to all internet hosts including, for example, both
+ personal computers and systems that run variants of Unix.
+
+
+
+
+
+
+
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 1]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+Table of Contents
+
+ 1 The SNMP Management Framework ............................ 2
+ 2 Host Resources MIB ....................................... 3
+ 3 IANA Considerations ...................................... 4
+ 4 Definitions .............................................. 4
+ 4.1 Textual Conventions .................................... 6
+ 4.2 The Host Resources System Group ........................ 7
+ 4.3 The Host Resources Storage Group ....................... 9
+ 4.4 The Host Resources Device Group ........................ 12
+ 4.5 The Host Resources Running Software Group .............. 26
+ 4.6 The Host Resources Running Software Performance
+ Group ................................................. 29
+ 4.7 The Host Resources Installed Software Group ............ 30
+ 4.8 Conformance Definitions ................................ 33
+ 5 Type Definitions ......................................... 36
+ 6 Internationalization Considerations ...................... 44
+ 7 Security Considerations .................................. 45
+ 8 References ............................................... 46
+ 9 Acknowledgments .......................................... 48
+ 10 Authors' Addresses ...................................... 49
+ 11 Intellectual Property ................................... 49
+ 12 Full Copyright Statement ................................ 50
+
+1. The SNMP Management Framework
+
+ The SNMP Management Framework presently consists of five major
+ components:
+
+ o An overall architecture, described in RFC 2571 [RFC2571].
+
+ o Mechanisms for describing and naming objects and events for the
+ purpose of management. The first version of this Structure of
+ Management Information (SMI) is called SMIv1 and described in STD
+ 16, RFC 1155 [RFC1155], STD 16, RFC 1212 [RFC1212] and RFC 1215
+ [RFC1215]. The second version, called SMIv2, is described in STD
+ 58, RFC 2578 [RFC2578], RFC 2579 [RFC2579] and RFC 2580
+ [RFC2580].
+
+ o Message protocols for transferring management information. The
+ first version of the SNMP message protocol is called SNMPv1 and
+ described in STD 15, RFC 1157 [RFC1157]. A second version of the
+ SNMP message protocol, which is not an Internet standards track
+ protocol, is called SNMPv2c and described in RFC 1901 [RFC1901]
+ and RFC 1906 [RFC1906]. The third version of the message protocol
+ is called SNMPv3 and described in RFC 1906 [RFC1906], RFC 2572
+ [RFC2572] and RFC 2574 [RFC2574].
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 2]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ o Protocol operations for accessing management information. The
+ first set of protocol operations and associated PDU formats is
+ described in STD 15, RFC 1157 [RFC1157]. A second set of protocol
+ operations and associated PDU formats is described in RFC 1905
+ [RFC1905].
+
+ o A set of fundamental applications described in RFC 2573 [RFC2573]
+ and the view-based access control mechanism described in RFC 2575
+ [RFC2575].
+
+ A more detailed introduction to the current SNMP Management Framework
+ can be found in RFC 2570 [RFC2570].
+
+ Managed objects are accessed via a virtual information store, termed
+ the Management Information Base or MIB. Objects in the MIB are
+ defined using the mechanisms defined in the SMI.
+
+ This memo specifies a MIB module that is compliant to the SMIv2. A
+ MIB conforming to the SMIv1 can be produced through the appropriate
+ translations. The resulting translated MIB must be semantically
+ equivalent, except where objects or events are omitted because no
+ translation is possible (use of Counter64). Some machine readable
+ information in SMIv2 will be converted into textual descriptions in
+ SMIv1 during the translation process. However, this loss of machine
+ readable information is not considered to change the semantics of the
+ MIB.
+
+2. Host Resources MIB
+
+ The Host Resources MIB defines a uniform set of objects useful for
+ the management of host computers. Host computers are independent of
+ the operating system, network services, or any software application.
+
+ The Host Resources MIB defines objects which are common across many
+ computer system architectures.
+
+ In addition, there are objects in the SNMPv2-MIB [RFC1907] and IF-MIB
+ [RFC2233] which also provide host management functionality.
+ Implementation of the System and Interfaces groups is mandatory for
+ implementors of the Host Resources MIB.
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED","MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [RFC2119].
+
+
+
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 3]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+3. IANA Considerations
+
+ This MIB contains type definitions for storage types, device types,
+ and file system types for use as values for the hrStorageType,
+ hrDeviceType, and hrFSType objects, respectively. As new computing
+ technologies are developed, new types need to be registered for these
+ technologies. The IANA (Internet Assigned Numbers Authority) is
+ designated as the registration authority for new registrations beyond
+ those published in this document. The IANA will maintain the HOST-
+ RESOURCES-TYPES module as new registrations are added and publish new
+ versions of this module.
+
+ Given the large number of such technologies and potential confusion
+ in naming of these technologies (such as a technology known by two
+ names or a name and an acronym), there is a real danger that more
+ than one registration might be created for what is essentially the
+ same technology. In order to ensure that future type registrations
+ are performed correctly, applications for new types will be reviewed
+ by a Designated Expert appointed by the IESG.
+
+4. Definitions
+
+ HOST-RESOURCES-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, mib-2,
+ Integer32, Counter32, Gauge32, TimeTicks FROM SNMPv2-SMI
+
+ TEXTUAL-CONVENTION, DisplayString,
+ TruthValue, DateAndTime, AutonomousType FROM SNMPv2-TC
+
+ MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF
+
+ InterfaceIndexOrZero FROM IF-MIB;
+
+ hostResourcesMibModule MODULE-IDENTITY
+ LAST-UPDATED "200003060000Z" -- 6 March 2000
+ ORGANIZATION "IETF Host Resources MIB Working Group"
+ CONTACT-INFO
+ "Steve Waldbusser
+ Postal: Lucent Technologies, Inc.
+ 1213 Innsbruck Dr.
+ Sunnyvale, CA 94089
+ USA
+ Phone: 650-318-1251
+ Fax: 650-318-1633
+ Email: waldbusser@lucent.com
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 4]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ In addition, the Host Resources MIB mailing list is
+ dedicated to discussion of this MIB. To join the
+ mailing list, send a request message to
+ hostmib-request@andrew.cmu.edu. The mailing list
+ address is hostmib@andrew.cmu.edu."
+
+ DESCRIPTION
+ "This MIB is for use in managing host systems. The term
+ `host' is construed to mean any computer that communicates
+ with other similar computers attached to the internet and
+ that is directly used by one or more human beings. Although
+ this MIB does not necessarily apply to devices whose primary
+ function is communications services (e.g., terminal servers,
+ routers, bridges, monitoring equipment), such relevance is
+ not explicitly precluded. This MIB instruments attributes
+ common to all internet hosts including, for example, both
+ personal computers and systems that run variants of Unix."
+
+ REVISION "200003060000Z" -- 6 March 2000
+ DESCRIPTION
+ "Clarifications and bug fixes based on implementation
+ experience. This revision was also reformatted in the SMIv2
+ format. The revisions made were:
+
+ New RFC document standards:
+ Added Copyright notice, updated introduction to SNMP
+ Framework, updated references section, added reference to
+ RFC 2119, and added a meaningful Security Considerations
+ section.
+
+ New IANA considerations section for registration of new types
+
+ Conversion to new SMIv2 syntax for the following types and
+ macros:
+ Counter32, Integer32, Gauge32, MODULE-IDENTITY,
+ OBJECT-TYPE, TEXTUAL-CONVENTION, OBJECT-IDENTITY,
+ MODULE-COMPLIANCE, OBJECT-GROUP
+
+ Used new Textual Conventions:
+ TruthValue, DateAndTime, AutonomousType,
+ InterfaceIndexOrZero
+
+ Fixed typo in hrPrinterStatus.
+
+ Added missing error bits to hrPrinterDetectedErrorState and
+ clarified confusion resulting from suggested mappings to
+ hrPrinterStatus.
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 5]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ Clarified that size of objects of type
+ InternationalDisplayString is number of octets, not number
+ of encoded symbols.
+
+ Clarified the use of the following objects based on
+ implementation experience:
+ hrSystemInitialLoadDevice, hrSystemInitialLoadParameters,
+ hrMemorySize, hrStorageSize, hrStorageAllocationFailures,
+ hrDeviceErrors, hrProcessorLoad, hrNetworkIfIndex,
+ hrDiskStorageCapacity, hrSWRunStatus, hrSWRunPerfCPU,
+ and hrSWInstalledDate.
+
+ Clarified implementation technique for hrSWInstalledTable.
+
+ Used new AUGMENTS clause for hrSWRunPerfTable.
+
+ Added Internationalization Considerations section.
+
+ This revision published as RFC2790."
+
+ REVISION "9910202200Z" -- 20 October, 1999
+ DESCRIPTION
+ "The original version of this MIB, published as
+ RFC1514."
+ ::= { hrMIBAdminInfo 1 }
+
+ host OBJECT IDENTIFIER ::= { mib-2 25 }
+
+ hrSystem OBJECT IDENTIFIER ::= { host 1 }
+ hrStorage OBJECT IDENTIFIER ::= { host 2 }
+ hrDevice OBJECT IDENTIFIER ::= { host 3 }
+ hrSWRun OBJECT IDENTIFIER ::= { host 4 }
+ hrSWRunPerf OBJECT IDENTIFIER ::= { host 5 }
+ hrSWInstalled OBJECT IDENTIFIER ::= { host 6 }
+ hrMIBAdminInfo OBJECT IDENTIFIER ::= { host 7 }
+
+ -- textual conventions
+
+ KBytes ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Storage size, expressed in units of 1024 bytes."
+ SYNTAX Integer32 (0..2147483647)
+
+ ProductID ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "This textual convention is intended to identify the
+
+
+
+Waldbusser & Grillo Standards Track [Page 6]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ manufacturer, model, and version of a specific
+ hardware or software product. It is suggested that
+ these OBJECT IDENTIFIERs are allocated such that all
+ products from a particular manufacturer are registered
+ under a subtree distinct to that manufacturer. In
+ addition, all versions of a product should be
+ registered under a subtree distinct to that product.
+ With this strategy, a management station may uniquely
+ determine the manufacturer and/or model of a product
+ whose productID is unknown to the management station.
+ Objects of this type may be useful for inventory
+ purposes or for automatically detecting
+ incompatibilities or version mismatches between
+ various hardware and software components on a system.
+
+ For example, the product ID for the ACME 4860 66MHz
+ clock doubled processor might be:
+ enterprises.acme.acmeProcessors.a4860DX2.MHz66
+
+ A software product might be registered as:
+ enterprises.acme.acmeOperatingSystems.acmeDOS.six(6).one(1)
+ "
+ SYNTAX OBJECT IDENTIFIER
+
+ -- unknownProduct will be used for any unknown ProductID
+ -- unknownProduct OBJECT IDENTIFIER ::= { 0 0 }
+
+ InternationalDisplayString ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "This data type is used to model textual information
+ in some character set. A network management station
+ should use a local algorithm to determine which
+ character set is in use and how it should be
+ displayed. Note that this character set may be
+ encoded with more than one octet per symbol, but will
+ most often be NVT ASCII. When a size clause is
+ specified for an object of this type, the size refers
+ to the length in octets, not the number of symbols."
+ SYNTAX OCTET STRING
+
+ -- The Host Resources System Group
+
+ hrSystemUptime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+
+
+
+Waldbusser & Grillo Standards Track [Page 7]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ "The amount of time since this host was last
+ initialized. Note that this is different from
+ sysUpTime in the SNMPv2-MIB [RFC1907] because
+ sysUpTime is the uptime of the network management
+ portion of the system."
+ ::= { hrSystem 1 }
+
+ hrSystemDate OBJECT-TYPE
+ SYNTAX DateAndTime
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The host's notion of the local date and time of day."
+ ::= { hrSystem 2 }
+
+ hrSystemInitialLoadDevice OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The index of the hrDeviceEntry for the device from
+ which this host is configured to load its initial
+ operating system configuration (i.e., which operating
+ system code and/or boot parameters).
+
+ Note that writing to this object just changes the
+ configuration that will be used the next time the
+ operating system is loaded and does not actually cause
+ the reload to occur."
+ ::= { hrSystem 3 }
+
+ hrSystemInitialLoadParameters OBJECT-TYPE
+ SYNTAX InternationalDisplayString (SIZE (0..128))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object contains the parameters (e.g. a pathname
+ and parameter) supplied to the load device when
+ requesting the initial operating system configuration
+ from that device.
+
+ Note that writing to this object just changes the
+ configuration that will be used the next time the
+ operating system is loaded and does not actually cause
+ the reload to occur."
+ ::= { hrSystem 4 }
+
+ hrSystemNumUsers OBJECT-TYPE
+
+
+
+Waldbusser & Grillo Standards Track [Page 8]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of user sessions for which this host is
+ storing state information. A session is a collection
+ of processes requiring a single act of user
+ authentication and possibly subject to collective job
+ control."
+ ::= { hrSystem 5 }
+
+ hrSystemProcesses OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of process contexts currently loaded or
+ running on this system."
+ ::= { hrSystem 6 }
+
+ hrSystemMaxProcesses OBJECT-TYPE
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum number of process contexts this system
+ can support. If there is no fixed maximum, the value
+ should be zero. On systems that have a fixed maximum,
+ this object can help diagnose failures that occur when
+ this maximum is reached."
+ ::= { hrSystem 7 }
+
+ -- The Host Resources Storage Group
+
+ -- Registration point for storage types, for use with hrStorageType.
+ -- These are defined in the HOST-RESOURCES-TYPES module.
+ hrStorageTypes OBJECT IDENTIFIER ::= { hrStorage 1 }
+
+ hrMemorySize OBJECT-TYPE
+ SYNTAX KBytes
+ UNITS "KBytes"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The amount of physical read-write main memory,
+ typically RAM, contained by the host."
+ ::= { hrStorage 2 }
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 9]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ hrStorageTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HrStorageEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table of logical storage areas on
+ the host.
+
+ An entry shall be placed in the storage table for each
+ logical area of storage that is allocated and has
+ fixed resource limits. The amount of storage
+ represented in an entity is the amount actually usable
+ by the requesting entity, and excludes loss due to
+ formatting or file system reference information.
+
+ These entries are associated with logical storage
+ areas, as might be seen by an application, rather than
+ physical storage entities which are typically seen by
+ an operating system. Storage such as tapes and
+ floppies without file systems on them are typically
+ not allocated in chunks by the operating system to
+ requesting applications, and therefore shouldn't
+ appear in this table. Examples of valid storage for
+ this table include disk partitions, file systems, ram
+ (for some architectures this is further segmented into
+ regular memory, extended memory, and so on), backing
+ store for virtual memory (`swap space').
+
+ This table is intended to be a useful diagnostic for
+ `out of memory' and `out of buffers' types of
+ failures. In addition, it can be a useful performance
+ monitoring tool for tracking memory, disk, or buffer
+ usage."
+ ::= { hrStorage 3 }
+
+ hrStorageEntry OBJECT-TYPE
+ SYNTAX HrStorageEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A (conceptual) entry for one logical storage area on
+ the host. As an example, an instance of the
+ hrStorageType object might be named hrStorageType.3"
+ INDEX { hrStorageIndex }
+ ::= { hrStorageTable 1 }
+
+ HrStorageEntry ::= SEQUENCE {
+ hrStorageIndex Integer32,
+
+
+
+Waldbusser & Grillo Standards Track [Page 10]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ hrStorageType AutonomousType,
+ hrStorageDescr DisplayString,
+ hrStorageAllocationUnits Integer32,
+ hrStorageSize Integer32,
+ hrStorageUsed Integer32,
+ hrStorageAllocationFailures Counter32
+ }
+
+ hrStorageIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A unique value for each logical storage area
+ contained by the host."
+ ::= { hrStorageEntry 1 }
+
+ hrStorageType OBJECT-TYPE
+ SYNTAX AutonomousType
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of storage represented by this entry."
+ ::= { hrStorageEntry 2 }
+
+ hrStorageDescr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A description of the type and instance of the storage
+ described by this entry."
+ ::= { hrStorageEntry 3 }
+
+ hrStorageAllocationUnits OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ UNITS "Bytes"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The size, in bytes, of the data objects allocated
+ from this pool. If this entry is monitoring sectors,
+ blocks, buffers, or packets, for example, this number
+ will commonly be greater than one. Otherwise this
+ number will typically be one."
+ ::= { hrStorageEntry 4 }
+
+ hrStorageSize OBJECT-TYPE
+
+
+
+Waldbusser & Grillo Standards Track [Page 11]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The size of the storage represented by this entry, in
+ units of hrStorageAllocationUnits. This object is
+ writable to allow remote configuration of the size of
+ the storage area in those cases where such an
+ operation makes sense and is possible on the
+ underlying system. For example, the amount of main
+ memory allocated to a buffer pool might be modified or
+ the amount of disk space allocated to virtual memory
+ might be modified."
+ ::= { hrStorageEntry 5 }
+
+ hrStorageUsed OBJECT-TYPE
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The amount of the storage represented by this entry
+ that is allocated, in units of
+ hrStorageAllocationUnits."
+ ::= { hrStorageEntry 6 }
+
+ hrStorageAllocationFailures OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of requests for storage represented by
+ this entry that could not be honored due to not enough
+ storage. It should be noted that as this object has a
+ SYNTAX of Counter32, that it does not have a defined
+ initial value. However, it is recommended that this
+ object be initialized to zero, even though management
+ stations must not depend on such an initialization."
+ ::= { hrStorageEntry 7 }
+
+ -- The Host Resources Device Group
+ --
+ -- The device group is useful for identifying and diagnosing the
+ -- devices on a system. The hrDeviceTable contains common
+ -- information for any type of device. In addition, some devices
+ -- have device-specific tables for more detailed information. More
+ -- such tables may be defined in the future for other device types.
+
+ -- Registration point for device types, for use with hrDeviceType.
+
+
+
+Waldbusser & Grillo Standards Track [Page 12]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ -- These are defined in the HOST-RESOURCES-TYPES module.
+ hrDeviceTypes OBJECT IDENTIFIER ::= { hrDevice 1 }
+
+ hrDeviceTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HrDeviceEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table of devices contained by the
+ host."
+ ::= { hrDevice 2 }
+
+ hrDeviceEntry OBJECT-TYPE
+ SYNTAX HrDeviceEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A (conceptual) entry for one device contained by the
+ host. As an example, an instance of the hrDeviceType
+ object might be named hrDeviceType.3"
+ INDEX { hrDeviceIndex }
+ ::= { hrDeviceTable 1 }
+
+ HrDeviceEntry ::= SEQUENCE {
+ hrDeviceIndex Integer32,
+ hrDeviceType AutonomousType,
+ hrDeviceDescr DisplayString,
+ hrDeviceID ProductID,
+ hrDeviceStatus INTEGER,
+ hrDeviceErrors Counter32
+ }
+
+ hrDeviceIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A unique value for each device contained by the host.
+ The value for each device must remain constant at
+ least from one re-initialization of the agent to the
+ next re-initialization."
+ ::= { hrDeviceEntry 1 }
+
+ hrDeviceType OBJECT-TYPE
+ SYNTAX AutonomousType
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+
+
+
+Waldbusser & Grillo Standards Track [Page 13]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ "An indication of the type of device.
+
+ If this value is
+ `hrDeviceProcessor { hrDeviceTypes 3 }' then an entry
+ exists in the hrProcessorTable which corresponds to
+ this device.
+
+ If this value is
+ `hrDeviceNetwork { hrDeviceTypes 4 }', then an entry
+ exists in the hrNetworkTable which corresponds to this
+ device.
+
+ If this value is
+ `hrDevicePrinter { hrDeviceTypes 5 }', then an entry
+ exists in the hrPrinterTable which corresponds to this
+ device.
+
+ If this value is
+ `hrDeviceDiskStorage { hrDeviceTypes 6 }', then an
+ entry exists in the hrDiskStorageTable which
+ corresponds to this device."
+ ::= { hrDeviceEntry 2 }
+
+ hrDeviceDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..64))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of this device, including the
+ device's manufacturer and revision, and optionally,
+ its serial number."
+ ::= { hrDeviceEntry 3 }
+
+ hrDeviceID OBJECT-TYPE
+ SYNTAX ProductID
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The product ID for this device."
+ ::= { hrDeviceEntry 4 }
+
+ hrDeviceStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ unknown(1),
+ running(2),
+ warning(3),
+ testing(4),
+ down(5)
+
+
+
+Waldbusser & Grillo Standards Track [Page 14]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The current operational state of the device described
+ by this row of the table. A value unknown(1)
+ indicates that the current state of the device is
+ unknown. running(2) indicates that the device is up
+ and running and that no unusual error conditions are
+ known. The warning(3) state indicates that agent has
+ been informed of an unusual error condition by the
+ operational software (e.g., a disk device driver) but
+ that the device is still 'operational'. An example
+ would be a high number of soft errors on a disk. A
+ value of testing(4), indicates that the device is not
+ available for use because it is in the testing state.
+ The state of down(5) is used only when the agent has
+ been informed that the device is not available for any
+ use."
+ ::= { hrDeviceEntry 5 }
+
+ hrDeviceErrors OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of errors detected on this device. It
+ should be noted that as this object has a SYNTAX of
+ Counter32, that it does not have a defined initial
+ value. However, it is recommended that this object be
+ initialized to zero, even though management stations
+ must not depend on such an initialization."
+ ::= { hrDeviceEntry 6 }
+
+ hrProcessorTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HrProcessorEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table of processors contained by the
+ host.
+
+ Note that this table is potentially sparse: a
+ (conceptual) entry exists only if the correspondent
+ value of the hrDeviceType object is
+ `hrDeviceProcessor'."
+ ::= { hrDevice 3 }
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 15]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ hrProcessorEntry OBJECT-TYPE
+ SYNTAX HrProcessorEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A (conceptual) entry for one processor contained by
+ the host. The hrDeviceIndex in the index represents
+ the entry in the hrDeviceTable that corresponds to the
+ hrProcessorEntry.
+
+ As an example of how objects in this table are named,
+ an instance of the hrProcessorFrwID object might be
+ named hrProcessorFrwID.3"
+ INDEX { hrDeviceIndex }
+ ::= { hrProcessorTable 1 }
+
+ HrProcessorEntry ::= SEQUENCE {
+ hrProcessorFrwID ProductID,
+ hrProcessorLoad Integer32
+ }
+
+ hrProcessorFrwID OBJECT-TYPE
+ SYNTAX ProductID
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The product ID of the firmware associated with the
+ processor."
+ ::= { hrProcessorEntry 1 }
+
+ hrProcessorLoad OBJECT-TYPE
+ SYNTAX Integer32 (0..100)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The average, over the last minute, of the percentage
+ of time that this processor was not idle.
+ Implementations may approximate this one minute
+ smoothing period if necessary."
+ ::= { hrProcessorEntry 2 }
+
+ hrNetworkTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HrNetworkEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table of network devices contained
+ by the host.
+
+
+
+Waldbusser & Grillo Standards Track [Page 16]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ Note that this table is potentially sparse: a
+ (conceptual) entry exists only if the correspondent
+ value of the hrDeviceType object is
+ `hrDeviceNetwork'."
+ ::= { hrDevice 4 }
+
+ hrNetworkEntry OBJECT-TYPE
+ SYNTAX HrNetworkEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A (conceptual) entry for one network device contained
+ by the host. The hrDeviceIndex in the index
+ represents the entry in the hrDeviceTable that
+ corresponds to the hrNetworkEntry.
+
+ As an example of how objects in this table are named,
+ an instance of the hrNetworkIfIndex object might be
+ named hrNetworkIfIndex.3"
+ INDEX { hrDeviceIndex }
+ ::= { hrNetworkTable 1 }
+
+ HrNetworkEntry ::= SEQUENCE {
+ hrNetworkIfIndex InterfaceIndexOrZero
+ }
+
+ hrNetworkIfIndex OBJECT-TYPE
+ SYNTAX InterfaceIndexOrZero
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of ifIndex which corresponds to this
+ network device. If this device is not represented in
+ the ifTable, then this value shall be zero."
+ ::= { hrNetworkEntry 1 }
+
+ hrPrinterTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HrPrinterEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table of printers local to the host.
+
+ Note that this table is potentially sparse: a
+ (conceptual) entry exists only if the correspondent
+ value of the hrDeviceType object is
+ `hrDevicePrinter'."
+ ::= { hrDevice 5 }
+
+
+
+Waldbusser & Grillo Standards Track [Page 17]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ hrPrinterEntry OBJECT-TYPE
+ SYNTAX HrPrinterEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A (conceptual) entry for one printer local to the
+ host. The hrDeviceIndex in the index represents the
+ entry in the hrDeviceTable that corresponds to the
+ hrPrinterEntry.
+
+ As an example of how objects in this table are named,
+ an instance of the hrPrinterStatus object might be
+ named hrPrinterStatus.3"
+ INDEX { hrDeviceIndex }
+ ::= { hrPrinterTable 1 }
+
+ HrPrinterEntry ::= SEQUENCE {
+ hrPrinterStatus INTEGER,
+ hrPrinterDetectedErrorState OCTET STRING
+ }
+
+ hrPrinterStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1),
+ unknown(2),
+ idle(3),
+ printing(4),
+ warmup(5)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The current status of this printer device."
+ ::= { hrPrinterEntry 1 }
+
+ hrPrinterDetectedErrorState OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "This object represents any error conditions detected
+ by the printer. The error conditions are encoded as
+ bits in an octet string, with the following
+ definitions:
+
+ Condition Bit #
+
+ lowPaper 0
+
+
+
+Waldbusser & Grillo Standards Track [Page 18]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ noPaper 1
+ lowToner 2
+ noToner 3
+ doorOpen 4
+ jammed 5
+ offline 6
+ serviceRequested 7
+ inputTrayMissing 8
+ outputTrayMissing 9
+ markerSupplyMissing 10
+ outputNearFull 11
+ outputFull 12
+ inputTrayEmpty 13
+ overduePreventMaint 14
+
+ Bits are numbered starting with the most significant
+ bit of the first byte being bit 0, the least
+ significant bit of the first byte being bit 7, the
+ most significant bit of the second byte being bit 8,
+ and so on. A one bit encodes that the condition was
+ detected, while a zero bit encodes that the condition
+ was not detected.
+
+ This object is useful for alerting an operator to
+ specific warning or error conditions that may occur,
+ especially those requiring human intervention."
+ ::= { hrPrinterEntry 2 }
+
+ hrDiskStorageTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HrDiskStorageEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table of long-term storage devices
+ contained by the host. In particular, disk devices
+ accessed remotely over a network are not included
+ here.
+
+ Note that this table is potentially sparse: a
+ (conceptual) entry exists only if the correspondent
+ value of the hrDeviceType object is
+ `hrDeviceDiskStorage'."
+ ::= { hrDevice 6 }
+
+ hrDiskStorageEntry OBJECT-TYPE
+ SYNTAX HrDiskStorageEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+
+
+
+Waldbusser & Grillo Standards Track [Page 19]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ DESCRIPTION
+ "A (conceptual) entry for one long-term storage device
+ contained by the host. The hrDeviceIndex in the index
+ represents the entry in the hrDeviceTable that
+ corresponds to the hrDiskStorageEntry. As an example,
+ an instance of the hrDiskStorageCapacity object might
+ be named hrDiskStorageCapacity.3"
+ INDEX { hrDeviceIndex }
+ ::= { hrDiskStorageTable 1 }
+
+ HrDiskStorageEntry ::= SEQUENCE {
+ hrDiskStorageAccess INTEGER,
+ hrDiskStorageMedia INTEGER,
+ hrDiskStorageRemoveble TruthValue,
+ hrDiskStorageCapacity KBytes
+ }
+
+ hrDiskStorageAccess OBJECT-TYPE
+ SYNTAX INTEGER {
+ readWrite(1),
+ readOnly(2)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An indication if this long-term storage device is
+ readable and writable or only readable. This should
+ reflect the media type, any write-protect mechanism,
+ and any device configuration that affects the entire
+ device."
+ ::= { hrDiskStorageEntry 1 }
+
+ hrDiskStorageMedia OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1),
+ unknown(2),
+ hardDisk(3),
+ floppyDisk(4),
+ opticalDiskROM(5),
+ opticalDiskWORM(6), -- Write Once Read Many
+ opticalDiskRW(7),
+ ramDisk(8)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An indication of the type of media used in this long-
+ term storage device."
+
+
+
+Waldbusser & Grillo Standards Track [Page 20]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ ::= { hrDiskStorageEntry 2 }
+
+ hrDiskStorageRemoveble OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Denotes whether or not the disk media may be removed
+ from the drive."
+ ::= { hrDiskStorageEntry 3 }
+
+ hrDiskStorageCapacity OBJECT-TYPE
+ SYNTAX KBytes
+ UNITS "KBytes"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total size for this long-term storage device. If
+ the media is removable and is currently removed, this
+ value should be zero."
+ ::= { hrDiskStorageEntry 4 }
+
+ hrPartitionTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HrPartitionEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table of partitions for long-term
+ storage devices contained by the host. In particular,
+ partitions accessed remotely over a network are not
+ included here."
+ ::= { hrDevice 7 }
+
+ hrPartitionEntry OBJECT-TYPE
+ SYNTAX HrPartitionEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A (conceptual) entry for one partition. The
+ hrDeviceIndex in the index represents the entry in the
+ hrDeviceTable that corresponds to the
+ hrPartitionEntry.
+
+ As an example of how objects in this table are named,
+ an instance of the hrPartitionSize object might be
+ named hrPartitionSize.3.1"
+ INDEX { hrDeviceIndex, hrPartitionIndex }
+ ::= { hrPartitionTable 1 }
+
+
+
+Waldbusser & Grillo Standards Track [Page 21]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ HrPartitionEntry ::= SEQUENCE {
+ hrPartitionIndex Integer32,
+ hrPartitionLabel InternationalDisplayString,
+ hrPartitionID OCTET STRING,
+ hrPartitionSize KBytes,
+ hrPartitionFSIndex Integer32
+ }
+
+ hrPartitionIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A unique value for each partition on this long-term
+ storage device. The value for each long-term storage
+ device must remain constant at least from one re-
+ initialization of the agent to the next re-
+ initialization."
+ ::= { hrPartitionEntry 1 }
+
+ hrPartitionLabel OBJECT-TYPE
+ SYNTAX InternationalDisplayString (SIZE (0..128))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of this partition."
+ ::= { hrPartitionEntry 2 }
+
+ hrPartitionID OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A descriptor which uniquely represents this partition
+ to the responsible operating system. On some systems,
+ this might take on a binary representation."
+ ::= { hrPartitionEntry 3 }
+
+ hrPartitionSize OBJECT-TYPE
+ SYNTAX KBytes
+ UNITS "KBytes"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The size of this partition."
+ ::= { hrPartitionEntry 4 }
+
+ hrPartitionFSIndex OBJECT-TYPE
+
+
+
+Waldbusser & Grillo Standards Track [Page 22]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The index of the file system mounted on this
+ partition. If no file system is mounted on this
+ partition, then this value shall be zero. Note that
+ multiple partitions may point to one file system,
+ denoting that that file system resides on those
+ partitions. Multiple file systems may not reside on
+ one partition."
+ ::= { hrPartitionEntry 5 }
+
+ -- The File System Table
+
+ -- Registration point for popular File System types,
+ -- for use with hrFSType. These are defined in the
+ -- HOST-RESOURCES-TYPES module.
+ hrFSTypes OBJECT IDENTIFIER ::= { hrDevice 9 }
+
+ hrFSTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HrFSEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table of file systems local to this
+ host or remotely mounted from a file server. File
+ systems that are in only one user's environment on a
+ multi-user system will not be included in this table."
+ ::= { hrDevice 8 }
+
+ hrFSEntry OBJECT-TYPE
+ SYNTAX HrFSEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A (conceptual) entry for one file system local to
+ this host or remotely mounted from a file server.
+ File systems that are in only one user's environment
+ on a multi-user system will not be included in this
+ table.
+
+ As an example of how objects in this table are named,
+ an instance of the hrFSMountPoint object might be
+ named hrFSMountPoint.3"
+ INDEX { hrFSIndex }
+ ::= { hrFSTable 1 }
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 23]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ HrFSEntry ::= SEQUENCE {
+ hrFSIndex Integer32,
+ hrFSMountPoint InternationalDisplayString,
+ hrFSRemoteMountPoint InternationalDisplayString,
+ hrFSType AutonomousType,
+ hrFSAccess INTEGER,
+ hrFSBootable TruthValue,
+ hrFSStorageIndex Integer32,
+ hrFSLastFullBackupDate DateAndTime,
+ hrFSLastPartialBackupDate DateAndTime
+ }
+
+ hrFSIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A unique value for each file system local to this
+ host. The value for each file system must remain
+ constant at least from one re-initialization of the
+ agent to the next re-initialization."
+ ::= { hrFSEntry 1 }
+
+ hrFSMountPoint OBJECT-TYPE
+ SYNTAX InternationalDisplayString (SIZE(0..128))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The path name of the root of this file system."
+ ::= { hrFSEntry 2 }
+
+ hrFSRemoteMountPoint OBJECT-TYPE
+ SYNTAX InternationalDisplayString (SIZE(0..128))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A description of the name and/or address of the
+ server that this file system is mounted from. This
+ may also include parameters such as the mount point on
+ the remote file system. If this is not a remote file
+ system, this string should have a length of zero."
+ ::= { hrFSEntry 3 }
+
+ hrFSType OBJECT-TYPE
+ SYNTAX AutonomousType
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+
+
+
+Waldbusser & Grillo Standards Track [Page 24]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ "The value of this object identifies the type of this
+ file system."
+ ::= { hrFSEntry 4 }
+
+ hrFSAccess OBJECT-TYPE
+ SYNTAX INTEGER {
+ readWrite(1),
+ readOnly(2)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An indication if this file system is logically
+ configured by the operating system to be readable and
+ writable or only readable. This does not represent
+ any local access-control policy, except one that is
+ applied to the file system as a whole."
+ ::= { hrFSEntry 5 }
+
+ hrFSBootable OBJECT-TYPE
+ SYNTAX TruthValue
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A flag indicating whether this file system is
+ bootable."
+ ::= { hrFSEntry 6 }
+
+ hrFSStorageIndex OBJECT-TYPE
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The index of the hrStorageEntry that represents
+ information about this file system. If there is no
+ such information available, then this value shall be
+ zero. The relevant storage entry will be useful in
+ tracking the percent usage of this file system and
+ diagnosing errors that may occur when it runs out of
+ space."
+ ::= { hrFSEntry 7 }
+
+ hrFSLastFullBackupDate OBJECT-TYPE
+ SYNTAX DateAndTime
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The last date at which this complete file system was
+
+
+
+Waldbusser & Grillo Standards Track [Page 25]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ copied to another storage device for backup. This
+ information is useful for ensuring that backups are
+ being performed regularly.
+
+ If this information is not known, then this variable
+ shall have the value corresponding to January 1, year
+ 0000, 00:00:00.0, which is encoded as
+ (hex)'00 00 01 01 00 00 00 00'."
+ ::= { hrFSEntry 8 }
+
+ hrFSLastPartialBackupDate OBJECT-TYPE
+ SYNTAX DateAndTime
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The last date at which a portion of this file system
+ was copied to another storage device for backup. This
+ information is useful for ensuring that backups are
+ being performed regularly.
+
+ If this information is not known, then this variable
+ shall have the value corresponding to January 1, year
+ 0000, 00:00:00.0, which is encoded as
+ (hex)'00 00 01 01 00 00 00 00'."
+ ::= { hrFSEntry 9 }
+
+ -- The Host Resources Running Software Group
+ --
+ -- The hrSWRunTable contains an entry for each distinct piece of
+ -- software that is running or loaded into physical or virtual
+ -- memory in preparation for running. This includes the host's
+ -- operating system, device drivers, and applications.
+
+ hrSWOSIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of the hrSWRunIndex for the hrSWRunEntry
+ that represents the primary operating system running
+ on this host. This object is useful for quickly and
+ uniquely identifying that primary operating system."
+ ::= { hrSWRun 1 }
+
+ hrSWRunTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HrSWRunEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+
+
+
+Waldbusser & Grillo Standards Track [Page 26]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ DESCRIPTION
+ "The (conceptual) table of software running on the
+ host."
+ ::= { hrSWRun 2 }
+
+ hrSWRunEntry OBJECT-TYPE
+ SYNTAX HrSWRunEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A (conceptual) entry for one piece of software
+ running on the host Note that because the installed
+ software table only contains information for software
+ stored locally on this host, not every piece of
+ running software will be found in the installed
+ software table. This is true of software that was
+ loaded and run from a non-local source, such as a
+ network-mounted file system.
+
+ As an example of how objects in this table are named,
+ an instance of the hrSWRunName object might be named
+ hrSWRunName.1287"
+ INDEX { hrSWRunIndex }
+ ::= { hrSWRunTable 1 }
+
+ HrSWRunEntry ::= SEQUENCE {
+ hrSWRunIndex Integer32,
+ hrSWRunName InternationalDisplayString,
+ hrSWRunID ProductID,
+ hrSWRunPath InternationalDisplayString,
+ hrSWRunParameters InternationalDisplayString,
+ hrSWRunType INTEGER,
+ hrSWRunStatus INTEGER
+ }
+
+ hrSWRunIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A unique value for each piece of software running on
+ the host. Wherever possible, this should be the
+ system's native, unique identification number."
+ ::= { hrSWRunEntry 1 }
+
+ hrSWRunName OBJECT-TYPE
+ SYNTAX InternationalDisplayString (SIZE (0..64))
+ MAX-ACCESS read-only
+
+
+
+Waldbusser & Grillo Standards Track [Page 27]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ STATUS current
+ DESCRIPTION
+ "A textual description of this running piece of
+ software, including the manufacturer, revision, and
+ the name by which it is commonly known. If this
+ software was installed locally, this should be the
+ same string as used in the corresponding
+ hrSWInstalledName."
+ ::= { hrSWRunEntry 2 }
+
+ hrSWRunID OBJECT-TYPE
+ SYNTAX ProductID
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The product ID of this running piece of software."
+ ::= { hrSWRunEntry 3 }
+
+ hrSWRunPath OBJECT-TYPE
+ SYNTAX InternationalDisplayString (SIZE(0..128))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A description of the location on long-term storage
+ (e.g. a disk drive) from which this software was
+ loaded."
+ ::= { hrSWRunEntry 4 }
+
+ hrSWRunParameters OBJECT-TYPE
+ SYNTAX InternationalDisplayString (SIZE(0..128))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A description of the parameters supplied to this
+ software when it was initially loaded."
+ ::= { hrSWRunEntry 5 }
+
+ hrSWRunType OBJECT-TYPE
+ SYNTAX INTEGER {
+ unknown(1),
+ operatingSystem(2),
+ deviceDriver(3),
+ application(4)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of this software."
+
+
+
+Waldbusser & Grillo Standards Track [Page 28]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ ::= { hrSWRunEntry 6 }
+
+ hrSWRunStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ running(1),
+ runnable(2), -- waiting for resource
+ -- (i.e., CPU, memory, IO)
+ notRunnable(3), -- loaded but waiting for event
+ invalid(4) -- not loaded
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The status of this running piece of software.
+ Setting this value to invalid(4) shall cause this
+ software to stop running and to be unloaded. Sets to
+ other values are not valid."
+ ::= { hrSWRunEntry 7 }
+
+ -- The Host Resources Running Software Performance Group
+ --
+ -- The hrSWRunPerfTable contains an entry corresponding to
+ -- each entry in the hrSWRunTable.
+
+ hrSWRunPerfTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HrSWRunPerfEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table of running software
+ performance metrics."
+ ::= { hrSWRunPerf 1 }
+
+ hrSWRunPerfEntry OBJECT-TYPE
+ SYNTAX HrSWRunPerfEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A (conceptual) entry containing software performance
+ metrics. As an example, an instance of the
+ hrSWRunPerfCPU object might be named
+ hrSWRunPerfCPU.1287"
+ AUGMENTS { hrSWRunEntry } -- This table augments information in
+ -- the hrSWRunTable.
+ ::= { hrSWRunPerfTable 1 }
+
+ HrSWRunPerfEntry ::= SEQUENCE {
+ hrSWRunPerfCPU Integer32,
+
+
+
+Waldbusser & Grillo Standards Track [Page 29]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ hrSWRunPerfMem KBytes
+ }
+
+ hrSWRunPerfCPU OBJECT-TYPE
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of centi-seconds of the total system's CPU
+ resources consumed by this process. Note that on a
+ multi-processor system, this value may increment by
+ more than one centi-second in one centi-second of real
+ (wall clock) time."
+ ::= { hrSWRunPerfEntry 1 }
+
+ hrSWRunPerfMem OBJECT-TYPE
+ SYNTAX KBytes
+ UNITS "KBytes"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total amount of real system memory allocated to
+ this process."
+ ::= { hrSWRunPerfEntry 2 }
+
+ -- The Host Resources Installed Software Group
+ --
+ -- The hrSWInstalledTable contains an entry for each piece
+ -- of software installed in long-term storage (e.g. a disk
+ -- drive) locally on this host. Note that this does not
+ -- include software loadable remotely from a network
+ -- server.
+ --
+ -- Different implementations may track software in varying
+ -- ways. For example, while some implementations may track
+ -- executable files as distinct pieces of software, other
+ -- implementations may use other strategies such as keeping
+ -- track of software "packages" (e.g., related groups of files)
+ -- or keeping track of system or application "patches".
+ --
+ -- This table is useful for identifying and inventorying
+ -- software on a host and for diagnosing incompatibility
+ -- and version mismatch problems between various pieces
+ -- of hardware and software.
+
+ hrSWInstalledLastChange OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+
+
+
+Waldbusser & Grillo Standards Track [Page 30]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when an entry in the
+ hrSWInstalledTable was last added, renamed, or
+ deleted. Because this table is likely to contain many
+ entries, polling of this object allows a management
+ station to determine when re-downloading of the table
+ might be useful."
+ ::= { hrSWInstalled 1 }
+
+ hrSWInstalledLastUpdateTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when the hrSWInstalledTable
+ was last completely updated. Because caching of this
+ data will be a popular implementation strategy,
+ retrieval of this object allows a management station
+ to obtain a guarantee that no data in this table is
+ older than the indicated time."
+ ::= { hrSWInstalled 2 }
+
+ hrSWInstalledTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HrSWInstalledEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table of software installed on this
+ host."
+ ::= { hrSWInstalled 3 }
+
+ hrSWInstalledEntry OBJECT-TYPE
+ SYNTAX HrSWInstalledEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A (conceptual) entry for a piece of software
+ installed on this host.
+
+ As an example of how objects in this table are named,
+ an instance of the hrSWInstalledName object might be
+ named hrSWInstalledName.96"
+ INDEX { hrSWInstalledIndex }
+ ::= { hrSWInstalledTable 1 }
+
+ HrSWInstalledEntry ::= SEQUENCE {
+ hrSWInstalledIndex Integer32,
+
+
+
+Waldbusser & Grillo Standards Track [Page 31]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ hrSWInstalledName InternationalDisplayString,
+ hrSWInstalledID ProductID,
+ hrSWInstalledType INTEGER,
+ hrSWInstalledDate DateAndTime
+ }
+
+ hrSWInstalledIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A unique value for each piece of software installed
+ on the host. This value shall be in the range from 1
+ to the number of pieces of software installed on the
+ host."
+ ::= { hrSWInstalledEntry 1 }
+
+ hrSWInstalledName OBJECT-TYPE
+ SYNTAX InternationalDisplayString (SIZE (0..64))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of this installed piece of
+ software, including the manufacturer, revision, the
+ name by which it is commonly known, and optionally,
+ its serial number."
+ ::= { hrSWInstalledEntry 2 }
+
+ hrSWInstalledID OBJECT-TYPE
+ SYNTAX ProductID
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The product ID of this installed piece of software."
+ ::= { hrSWInstalledEntry 3 }
+
+ hrSWInstalledType OBJECT-TYPE
+ SYNTAX INTEGER {
+ unknown(1),
+ operatingSystem(2),
+ deviceDriver(3),
+ application(4)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of this software."
+ ::= { hrSWInstalledEntry 4 }
+
+
+
+Waldbusser & Grillo Standards Track [Page 32]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ hrSWInstalledDate OBJECT-TYPE
+ SYNTAX DateAndTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The last-modification date of this application as it
+ would appear in a directory listing.
+
+ If this information is not known, then this variable
+ shall have the value corresponding to January 1, year
+ 0000, 00:00:00.0, which is encoded as
+ (hex)'00 00 01 01 00 00 00 00'."
+ ::= { hrSWInstalledEntry 5 }
+
+ -- Conformance information
+
+ hrMIBCompliances OBJECT IDENTIFIER ::= { hrMIBAdminInfo 2 }
+ hrMIBGroups OBJECT IDENTIFIER ::= { hrMIBAdminInfo 3 }
+
+ -- Compliance Statements
+ hrMIBCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The requirements for conformance to the Host Resources MIB."
+ MODULE -- this module
+ MANDATORY-GROUPS { hrSystemGroup, hrStorageGroup,
+ hrDeviceGroup }
+
+ OBJECT hrSystemDate
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Write access is not required."
+
+ OBJECT hrSystemInitialLoadDevice
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Write access is not required."
+
+ OBJECT hrSystemInitialLoadParameters
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Write access is not required."
+
+ OBJECT hrStorageSize
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Write access is not required."
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 33]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ OBJECT hrFSLastFullBackupDate
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Write access is not required."
+
+ OBJECT hrFSLastPartialBackupDate
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Write access is not required."
+
+ GROUP hrSWRunGroup
+ DESCRIPTION
+ "The Running Software Group. Implementation
+ of this group is mandatory only when the
+ hrSWRunPerfGroup is implemented."
+
+ OBJECT hrSWRunStatus
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Write access is not required."
+
+ GROUP hrSWRunPerfGroup
+ DESCRIPTION
+ "The Running Software Performance Group.
+ Implementation of this group is at the discretion
+ of the implementor."
+
+ GROUP hrSWInstalledGroup
+ DESCRIPTION
+ "The Installed Software Group.
+ Implementation of this group is at the discretion
+ of the implementor."
+
+ ::= { hrMIBCompliances 1 }
+
+ hrSystemGroup OBJECT-GROUP
+ OBJECTS {
+ hrSystemUptime, hrSystemDate,
+ hrSystemInitialLoadDevice,
+ hrSystemInitialLoadParameters,
+ hrSystemNumUsers, hrSystemProcesses,
+ hrSystemMaxProcesses
+ }
+ STATUS current
+ DESCRIPTION
+ "The Host Resources System Group."
+ ::= { hrMIBGroups 1 }
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 34]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ hrStorageGroup OBJECT-GROUP
+ OBJECTS {
+ hrMemorySize, hrStorageIndex, hrStorageType,
+ hrStorageDescr, hrStorageAllocationUnits,
+ hrStorageSize, hrStorageUsed,
+ hrStorageAllocationFailures
+ }
+ STATUS current
+ DESCRIPTION
+ "The Host Resources Storage Group."
+ ::= { hrMIBGroups 2 }
+
+ hrDeviceGroup OBJECT-GROUP
+ OBJECTS {
+ hrDeviceIndex, hrDeviceType, hrDeviceDescr,
+ hrDeviceID, hrDeviceStatus, hrDeviceErrors,
+ hrProcessorFrwID, hrProcessorLoad,
+ hrNetworkIfIndex, hrPrinterStatus,
+ hrPrinterDetectedErrorState,
+ hrDiskStorageAccess, hrDiskStorageMedia,
+ hrDiskStorageRemoveble, hrDiskStorageCapacity,
+ hrPartitionIndex, hrPartitionLabel,
+ hrPartitionID, hrPartitionSize,
+ hrPartitionFSIndex, hrFSIndex, hrFSMountPoint,
+ hrFSRemoteMountPoint, hrFSType, hrFSAccess,
+ hrFSBootable, hrFSStorageIndex,
+ hrFSLastFullBackupDate,
+ hrFSLastPartialBackupDate
+ }
+ STATUS current
+ DESCRIPTION
+ "The Host Resources Device Group."
+ ::= { hrMIBGroups 3 }
+
+ hrSWRunGroup OBJECT-GROUP
+ OBJECTS {
+ hrSWOSIndex, hrSWRunIndex, hrSWRunName,
+ hrSWRunID, hrSWRunPath, hrSWRunParameters,
+ hrSWRunType, hrSWRunStatus
+ }
+ STATUS current
+ DESCRIPTION
+ "The Host Resources Running Software Group."
+ ::= { hrMIBGroups 4 }
+
+ hrSWRunPerfGroup OBJECT-GROUP
+ OBJECTS { hrSWRunPerfCPU, hrSWRunPerfMem }
+ STATUS current
+
+
+
+Waldbusser & Grillo Standards Track [Page 35]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ DESCRIPTION
+ "The Host Resources Running Software
+ Performance Group."
+ ::= { hrMIBGroups 5 }
+
+ hrSWInstalledGroup OBJECT-GROUP
+ OBJECTS {
+ hrSWInstalledLastChange,
+ hrSWInstalledLastUpdateTime,
+ hrSWInstalledIndex, hrSWInstalledName,
+ hrSWInstalledID, hrSWInstalledType,
+ hrSWInstalledDate
+ }
+ STATUS current
+ DESCRIPTION
+ "The Host Resources Installed Software Group."
+ ::= { hrMIBGroups 6 }
+
+ END
+
+5. Type Definitions
+
+ HOST-RESOURCES-TYPES DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ MODULE-IDENTITY, OBJECT-IDENTITY FROM SNMPv2-SMI
+ hrMIBAdminInfo, hrStorage, hrDevice FROM HOST-RESOURCES-MIB;
+
+ hostResourcesTypesModule MODULE-IDENTITY
+ LAST-UPDATED "200003060000Z" -- 6 March, 2000
+ ORGANIZATION "IETF Host Resources MIB Working Group"
+ CONTACT-INFO
+ "Steve Waldbusser
+ Postal: Lucent Technologies, Inc.
+ 1213 Innsbruck Dr.
+ Sunnyvale, CA 94089
+ USA
+ Phone: 650-318-1251
+ Fax: 650-318-1633
+ Email: waldbusser@ins.com
+
+ In addition, the Host Resources MIB mailing list is dedicated
+ to discussion of this MIB. To join the mailing list, send a
+ request message to hostmib-request@andrew.cmu.edu. The mailing
+ list address is hostmib@andrew.cmu.edu."
+ DESCRIPTION
+ "This MIB module registers type definitions for
+ storage types, device types, and file system types.
+
+
+
+Waldbusser & Grillo Standards Track [Page 36]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ After the initial revision, this module will be
+ maintained by IANA."
+ REVISION "200003060000Z" -- 6 March 2000
+ DESCRIPTION
+ "The original version of this module, published as RFC
+ 2790."
+ ::= { hrMIBAdminInfo 4 }
+
+ -- Registrations for some storage types, for use with hrStorageType
+ hrStorageTypes OBJECT IDENTIFIER ::= { hrStorage 1 }
+
+ hrStorageOther OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The storage type identifier used when no other defined
+ type is appropriate."
+ ::= { hrStorageTypes 1 }
+
+ hrStorageRam OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The storage type identifier used for RAM."
+ ::= { hrStorageTypes 2 }
+
+ hrStorageVirtualMemory OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The storage type identifier used for virtual memory,
+ temporary storage of swapped or paged memory."
+ ::= { hrStorageTypes 3 }
+
+ hrStorageFixedDisk OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The storage type identifier used for non-removable
+ rigid rotating magnetic storage devices."
+ ::= { hrStorageTypes 4 }
+
+ hrStorageRemovableDisk OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The storage type identifier used for removable rigid
+ rotating magnetic storage devices."
+ ::= { hrStorageTypes 5 }
+
+ hrStorageFloppyDisk OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+
+
+
+Waldbusser & Grillo Standards Track [Page 37]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ "The storage type identifier used for non-rigid rotating
+ magnetic storage devices."
+ ::= { hrStorageTypes 6 }
+
+ hrStorageCompactDisc OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The storage type identifier used for read-only rotating
+ optical storage devices."
+ ::= { hrStorageTypes 7 }
+
+ hrStorageRamDisk OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The storage type identifier used for a file system that
+ is stored in RAM."
+ ::= { hrStorageTypes 8 }
+
+ hrStorageFlashMemory OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The storage type identifier used for flash memory."
+ ::= { hrStorageTypes 9 }
+
+ hrStorageNetworkDisk OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The storage type identifier used for a
+ networked file system."
+ ::= { hrStorageTypes 10 }
+
+ -- Registrations for some device types, for use with hrDeviceType
+ hrDeviceTypes OBJECT IDENTIFIER ::= { hrDevice 1 }
+
+ hrDeviceOther OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used when no other defined
+ type is appropriate."
+ ::= { hrDeviceTypes 1 }
+
+ hrDeviceUnknown OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used when the device type is
+ unknown."
+ ::= { hrDeviceTypes 2 }
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 38]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ hrDeviceProcessor OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a CPU."
+ ::= { hrDeviceTypes 3 }
+
+ hrDeviceNetwork OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a network interface."
+ ::= { hrDeviceTypes 4 }
+
+ hrDevicePrinter OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a printer."
+ ::= { hrDeviceTypes 5 }
+
+ hrDeviceDiskStorage OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a disk drive."
+ ::= { hrDeviceTypes 6 }
+
+ hrDeviceVideo OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a video device."
+ ::= { hrDeviceTypes 10 }
+
+ hrDeviceAudio OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for an audio device."
+ ::= { hrDeviceTypes 11 }
+
+ hrDeviceCoprocessor OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a co-processor."
+ ::= { hrDeviceTypes 12 }
+
+ hrDeviceKeyboard OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a keyboard device."
+ ::= { hrDeviceTypes 13 }
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 39]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ hrDeviceModem OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a modem."
+ ::= { hrDeviceTypes 14 }
+
+ hrDeviceParallelPort OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a parallel port."
+ ::= { hrDeviceTypes 15 }
+
+ hrDevicePointing OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a pointing device
+ (e.g., a mouse)."
+ ::= { hrDeviceTypes 16 }
+
+ hrDeviceSerialPort OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a serial port."
+ ::= { hrDeviceTypes 17 }
+
+ hrDeviceTape OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a tape storage device."
+ ::= { hrDeviceTypes 18 }
+
+ hrDeviceClock OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a clock device."
+ ::= { hrDeviceTypes 19 }
+
+ hrDeviceVolatileMemory OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a volatile memory
+ storage device."
+ ::= { hrDeviceTypes 20 }
+
+ hrDeviceNonVolatileMemory OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The device type identifier used for a non-volatile memory
+
+
+
+Waldbusser & Grillo Standards Track [Page 40]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ storage device."
+ ::= { hrDeviceTypes 21 }
+
+ -- Registrations for some popular File System types,
+ -- for use with hrFSType.
+ hrFSTypes OBJECT IDENTIFIER ::= { hrDevice 9 }
+
+ hrFSOther OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used when no other
+ defined type is appropriate."
+ ::= { hrFSTypes 1 }
+
+ hrFSUnknown OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used when the type of
+ file system is unknown."
+ ::= { hrFSTypes 2 }
+
+ hrFSBerkeleyFFS OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ Berkeley Fast File System."
+ ::= { hrFSTypes 3 }
+
+ hrFSSys5FS OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ System V File System."
+ ::= { hrFSTypes 4 }
+
+ hrFSFat OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for
+ DOS's FAT file system."
+ ::= { hrFSTypes 5 }
+
+ hrFSHPFS OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for OS/2's
+ High Performance File System."
+ ::= { hrFSTypes 6 }
+
+
+
+Waldbusser & Grillo Standards Track [Page 41]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ hrFSHFS OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ Macintosh Hierarchical File System."
+ ::= { hrFSTypes 7 }
+
+ hrFSMFS OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ Macintosh File System."
+ ::= { hrFSTypes 8 }
+
+ hrFSNTFS OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ Windows NT File System."
+ ::= { hrFSTypes 9 }
+
+ hrFSVNode OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ VNode File System."
+ ::= { hrFSTypes 10 }
+
+ hrFSJournaled OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ Journaled File System."
+ ::= { hrFSTypes 11 }
+
+ hrFSiso9660 OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ ISO 9660 File System for CD's."
+ ::= { hrFSTypes 12 }
+
+ hrFSRockRidge OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ RockRidge File System for CD's."
+ ::= { hrFSTypes 13 }
+
+
+
+Waldbusser & Grillo Standards Track [Page 42]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ hrFSNFS OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ NFS File System."
+ ::= { hrFSTypes 14 }
+
+ hrFSNetware OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ Netware File System."
+ ::= { hrFSTypes 15 }
+
+ hrFSAFS OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ Andrew File System."
+ ::= { hrFSTypes 16 }
+
+ hrFSDFS OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ OSF DCE Distributed File System."
+ ::= { hrFSTypes 17 }
+
+ hrFSAppleshare OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ AppleShare File System."
+ ::= { hrFSTypes 18 }
+
+ hrFSRFS OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ RFS File System."
+ ::= { hrFSTypes 19 }
+
+ hrFSDGCFS OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ Data General DGCFS."
+ ::= { hrFSTypes 20 }
+
+
+
+Waldbusser & Grillo Standards Track [Page 43]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ hrFSBFS OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ SVR4 Boot File System."
+ ::= { hrFSTypes 21 }
+
+ hrFSFAT32 OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ Windows FAT32 File System."
+ ::= { hrFSTypes 22 }
+
+ hrFSLinuxExt2 OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The file system type identifier used for the
+ Linux EXT2 File System."
+ ::= { hrFSTypes 23 }
+
+ END
+
+6. Internationalization Considerations
+
+ This MIB has many objects that identify file-system pathnames on the
+ managed host. Many file systems allow pathnames to be encoded in a
+ variety of character sets (other than ASCII), but do not support the
+ encoding of the actual character set used with the pathname. The
+ implementation strategy is that user interfaces (i.e. character-based
+ shells or graphical applications) will have configuration options
+ that control with which character set they will interpret and display
+ all pathnames. This is often a per-user configuration (e.g. an
+ environment variable), so that users using different languages and
+ character sets on a multi-user system may each work effectively with
+ their preferred character set. A human usually controls this
+ configuration. If an application is not configured or is configured
+ incorrectly, it will often have trouble displaying pathnames in the
+ intended character set.
+
+ This situation made it important for this MIB to handle two issues:
+
+ 1) Pathname objects must be able to transfer a variety of character
+ sets with potentially multi-byte encodings; and,
+
+
+
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 44]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ 2) HostMIB agents will generally not be correctly configured for the
+ appropriate character set to be used for all files on the system,
+ particularly on a system with multiple users using different
+ character sets. It was thus impossible to mandate that the agent
+ tag pathnames with the character set in use.
+
+ These issues were solved with the introduction of the
+ InternationalDisplayString textual convention, which supports multi-
+ byte encodings. Network management stations should use a local
+ algorithm to determine which character set is in use and how it
+ should be displayed. It is expected that network management station
+ applications will rely on human configuration to choose which
+ character set in which to interpret InternationalDisplayString
+ objects, much like an application running locally on that host.
+
+7. Security Considerations
+
+ There are a number of management objects defined in this MIB that
+ have a MAX-ACCESS clause of read-write. Such objects may be
+ considered sensitive or vulnerable in some network environments. The
+ support for SET operations in a non-secure environment without proper
+ protection can have a negative effect on system operations.
+
+ There are a number of managed objects in this MIB that may contain
+ sensitive information. The objects in the Running Software Group list
+ information about running software on the system (including the
+ operating system software and version). Some may wish not to
+ disclose to others what software they are running. Further, an
+ inventory of the running software and versions may be helpful to an
+ attacker who hopes to exploit software bugs in certain applications.
+ The same issues exist for the objects in the Installed Software
+ Group.
+
+ It is thus important to control even GET access to these objects and
+ possibly to even encrypt the values of these object when sending them
+ over the network via SNMP. Not all versions of SNMP provide features
+ for such a secure environment.
+
+ SNMPv1 by itself is not a secure environment. Even if the network
+ itself is secure (for example by using IPSec), even then, there is no
+ control as to who on the secure network is allowed to access and
+ GET/SET (read/change/create/delete) the objects in this MIB.
+
+ It is recommended that the implementers consider the security
+ features as provided by the SNMPv3 framework. Specifically, the use
+ of the User-based Security Model RFC 2574 [RFC2574] and the View-
+ based Access Control Model RFC 2575 [RFC2575] is recommended.
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 45]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ It is then a customer/user responsibility to ensure that the SNMP
+ entity giving access to an instance of this MIB, is properly
+ configured to give access to the objects only to those principals
+ (users) that have legitimate rights to indeed GET or SET
+ (change/create/delete) them.
+
+8. References
+
+ [RFC2571] Harrington, D., Presuhn, R. and B. Wijnen, "An
+ Architecture for Describing SNMP Management Frameworks",
+ RFC 2571, April 1999.
+
+ [RFC1155] Rose, M. and K. McCloghrie, "Structure and Identification
+ of Management Information for TCP/IP-based Internets",
+ STD 16, RFC 1155, May 1990.
+
+ [RFC1212] Rose, M. and K. McCloghrie, "Concise MIB Definitions",
+ STD 16, RFC 1212, March 1991.
+
+ [RFC1215] Rose, M., "A Convention for Defining Traps for use with
+ the SNMP", RFC 1215, March 1991.
+
+ [RFC2578] McCloghrie, K., Perkins, D., Schoenwaelder, J., Case, J.,
+ Rose, M. and S. Waldbusser, "Structure of Management
+ Information Version 2 (SMIv2)", STD 58, RFC 2578, April
+ 1999.
+
+ [RFC2579] McCloghrie, K., Perkins, D., Schoenwaelder, J., Case, J.,
+ Rose, M. and S. Waldbusser, "Textual Conventions for
+ SMIv2", STD 58, RFC 2579, April 1999.
+
+ [RFC2580] McCloghrie, K., Perkins, D., Schoenwaelder, J., Case, J.,
+ Rose, M. and S. Waldbusser, "Conformance Statements for
+ SMIv2", STD 58, RFC 2580, April 1999.
+
+ [RFC1157] Case, J., Fedor, M., Schoffstall, M. and J. Davin,
+ "Simple Network Management Protocol", STD 15, RFC 1157,
+ May 1990.
+
+ [RFC1901] Case, J., McCloghrie, K., Rose, M. and S. Waldbusser,
+ "Introduction to Community-based SNMPv2", RFC 1901,
+ January 1996.
+
+ [RFC1906] Case, J., McCloghrie, K., Rose, M. and S. Waldbusser,
+ "Transport Mappings for Version 2 of the Simple Network
+ Management Protocol (SNMPv2)", RFC 1906, January 1996.
+
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 46]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+ [RFC2572] Case, J., Harrington D., Presuhn R. and B. Wijnen,
+ "Message Processing and Dispatching for the Simple
+ Network Management Protocol (SNMP)", RFC 2572, April 1999
+
+ [RFC2574] Blumenthal, U. and B. Wijnen, "User-based Security Model
+ (USM) for version 3 of the Simple Network Management
+ Protocol (SNMPv3)", RFC 2574, April 1999.
+
+ [RFC1905] Case, J., McCloghrie, K., Rose, M. and S. Waldbusser,
+ "Protocol Operations for Version 2 of the Simple Network
+ Management Protocol (SNMPv2)", RFC 1905, January 1996.
+
+ [RFC2573] Levi, D., Meyer, P. and B. Stewart, "SNMPv3
+ Applications", RFC 2573, April 1999.
+
+ [RFC2575] Wijnen, B., Presuhn, R. and K. McCloghrie, "View-based
+ Access Control Model (VACM) for the Simple Network
+ Management Protocol (SNMP)", RFC 2575, April 1999.
+
+ [RFC2570] Case, J., Mundy, R., Partain, D. and B. Stewart,
+ "Introduction to Version 3 of the Internet- standard
+ Network Management Framework", RFC 2570, April 1999.
+
+ [RFC1907] Case, J., McCloghrie, K., Rose, M. and S. Waldbusser,
+ "Management Information Base for Version 2 of the Simple
+ Network Management Protocol (SNMPv2)", RFC 1907, January
+ 1996.
+
+ [RFC2233] McCloghrie, K. and F. Kastenholz, "The Interfaces Group
+ MIB", RFC 2233, November 1997.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 47]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+9. Acknowledgments
+
+ This document was produced by the Host Resources MIB working group.
+
+ Bobby Krupczak's efforts were particularly helpful in the creation of
+ the draft standard version of this document.
+
+ In addition, the authors gratefully acknowledge the comments of the
+ following individuals:
+
+ Amatzia Ben-Artzi NetManage
+ Ron Bergman Hitachi, Inc.
+ Steve Bostock Novell
+ Stephen Bush GE Information Systems
+ Jeff Case SNMP Research
+ Chuck Davin Bellcore
+ Ray Edgarton Bell Atlantic
+ Mike Erlinger Aerospace Corporation
+ Tim Farley Magee Enterprises
+ Mark Kepke Hewlett Packard
+ Bobby Krupczak Empire Technologies, Inc.
+ Cheryl Krupczak Empire Technologies, Inc.
+ Harry Lewis IBM Corp.
+ Keith McCloghrie Cisco Systems
+ Greg Minshall Novell
+ Steve Moulton SNMP Research
+ Dave Perkins Synoptics
+ Ed Reeder Objective Systems Integrators
+ Mike Ritter Apple Computer
+ Marshall Rose Dover Beach Consulting
+ Jon Saperia DEC
+ Rodney Thayer Sable Technology
+ Kaj Tesink Bellcore
+ Dean Throop Data General
+ Bert Wijnen Lucent
+ Lloyd Young Lexmark International
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 48]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+10. Authors' Addresses
+
+ Pete Grillo
+ WeSync.com
+ 1001 SW Fifth Ave, Fifth Floor
+ Portland, OR 97204
+
+ Phone: 503-425-5051
+ Fax: 503-827-6718
+ email: pete@wesync.com
+ Phone: +1 503 827 6717
+
+
+ Steven Waldbusser
+ Lucent Technologies, Inc.
+ 1213 Innsbruck Dr.
+ Sunnyvale CA 94089
+
+ Phone: +1 650 318 1251
+ Fax: +1 650 318 1633
+ EMail: waldbusser@ins.com
+
+11. Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of
+ any intellectual property or other rights that might be
+ claimed to pertain to the implementation or use of the
+ technology described in this document or the extent to which
+ any license under such rights might or might not be available;
+ neither does it represent that it has made any effort to
+ identify any such rights. Information on the IETF's
+ procedures with respect to rights in standards-track and
+ standards-related documentation can be found in BCP-11.
+ Copies of claims of rights made available for publication and
+ any assurances of licenses to be made available, or the result
+ of an attempt made to obtain a general license or permission
+ for the use of such proprietary rights by implementors or
+ users of this specification can be obtained from the IETF
+ Secretariat.
+
+ The IETF invites any interested party to bring to its
+ attention any copyrights, patents or patent applications, or
+ other proprietary rights which may cover technology that may
+ be required to practice this standard. Please address the
+ information to the IETF Executive Director.
+
+
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 49]
+
+RFC 2790 Host Resources MIB March 2000
+
+
+12. Full Copyright Statement
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Waldbusser & Grillo Standards Track [Page 50]
+
diff --git a/standards/rfc2817.txt b/standards/rfc2817.txt
new file mode 100644
index 000000000..d7b7e703b
--- /dev/null
+++ b/standards/rfc2817.txt
@@ -0,0 +1,731 @@
+
+
+
+
+
+
+Network Working Group R. Khare
+Request for Comments: 2817 4K Associates / UC Irvine
+Updates: 2616 S. Lawrence
+Category: Standards Track Agranat Systems, Inc.
+ May 2000
+
+
+ Upgrading to TLS Within HTTP/1.1
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+Abstract
+
+ This memo explains how to use the Upgrade mechanism in HTTP/1.1 to
+ initiate Transport Layer Security (TLS) over an existing TCP
+ connection. This allows unsecured and secured HTTP traffic to share
+ the same well known port (in this case, http: at 80 rather than
+ https: at 443). It also enables "virtual hosting", so a single HTTP +
+ TLS server can disambiguate traffic intended for several hostnames at
+ a single IP address.
+
+ Since HTTP/1.1 [1] defines Upgrade as a hop-by-hop mechanism, this
+ memo also documents the HTTP CONNECT method for establishing end-to-
+ end tunnels across HTTP proxies. Finally, this memo establishes new
+ IANA registries for public HTTP status codes, as well as public or
+ private Upgrade product tokens.
+
+ This memo does NOT affect the current definition of the 'https' URI
+ scheme, which already defines a separate namespace
+ (http://example.org/ and https://example.org/ are not equivalent).
+
+
+
+
+
+
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 1]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+Table of Contents
+
+ 1. Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . 2
+ 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 2.1 Requirements Terminology . . . . . . . . . . . . . . . . . . . 4
+ 3. Client Requested Upgrade to HTTP over TLS . . . . . . . . . . 4
+ 3.1 Optional Upgrade . . . . . . . . . . . . . . . . . . . . . . . 4
+ 3.2 Mandatory Upgrade . . . . . . . . . . . . . . . . . . . . . . 4
+ 3.3 Server Acceptance of Upgrade Request . . . . . . . . . . . . . 4
+ 4. Server Requested Upgrade to HTTP over TLS . . . . . . . . . . 5
+ 4.1 Optional Advertisement . . . . . . . . . . . . . . . . . . . . 5
+ 4.2 Mandatory Advertisement . . . . . . . . . . . . . . . . . . . 5
+ 5. Upgrade across Proxies . . . . . . . . . . . . . . . . . . . . 6
+ 5.1 Implications of Hop By Hop Upgrade . . . . . . . . . . . . . . 6
+ 5.2 Requesting a Tunnel with CONNECT . . . . . . . . . . . . . . . 6
+ 5.3 Establishing a Tunnel with CONNECT . . . . . . . . . . . . . . 7
+ 6. Rationale for the use of a 4xx (client error) Status Code . . 7
+ 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 8
+ 7.1 HTTP Status Code Registry . . . . . . . . . . . . . . . . . . 8
+ 7.2 HTTP Upgrade Token Registry . . . . . . . . . . . . . . . . . 8
+ 8. Security Considerations . . . . . . . . . . . . . . . . . . . 9
+ 8.1 Implications for the https: URI Scheme . . . . . . . . . . . . 10
+ 8.2 Security Considerations for CONNECT . . . . . . . . . . . . . 10
+ References . . . . . . . . . . . . . . . . . . . . . . . . . . 10
+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 11
+ A. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 12
+ Full Copyright Statement . . . . . . . . . . . . . . . . . . . 13
+
+1. Motivation
+
+ The historical practice of deploying HTTP over SSL3 [3] has
+ distinguished the combination from HTTP alone by a unique URI scheme
+ and the TCP port number. The scheme 'http' meant the HTTP protocol
+ alone on port 80, while 'https' meant the HTTP protocol over SSL on
+ port 443. Parallel well-known port numbers have similarly been
+ requested -- and in some cases, granted -- to distinguish between
+ secured and unsecured use of other application protocols (e.g.
+ snews, ftps). This approach effectively halves the number of
+ available well known ports.
+
+ At the Washington DC IETF meeting in December 1997, the Applications
+ Area Directors and the IESG reaffirmed that the practice of issuing
+ parallel "secure" port numbers should be deprecated. The HTTP/1.1
+ Upgrade mechanism can apply Transport Layer Security [6] to an open
+ HTTP connection.
+
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 2]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+ In the nearly two years since, there has been broad acceptance of the
+ concept behind this proposal, but little interest in implementing
+ alternatives to port 443 for generic Web browsing. In fact, nothing
+ in this memo affects the current interpretation of https: URIs.
+ However, new application protocols built atop HTTP, such as the
+ Internet Printing Protocol [7], call for just such a mechanism in
+ order to move ahead in the IETF standards process.
+
+ The Upgrade mechanism also solves the "virtual hosting" problem.
+ Rather than allocating multiple IP addresses to a single host, an
+ HTTP/1.1 server will use the Host: header to disambiguate the
+ intended web service. As HTTP/1.1 usage has grown more prevalent,
+ more ISPs are offering name-based virtual hosting, thus delaying IP
+ address space exhaustion.
+
+ TLS (and SSL) have been hobbled by the same limitation as earlier
+ versions of HTTP: the initial handshake does not specify the intended
+ hostname, relying exclusively on the IP address. Using a cleartext
+ HTTP/1.1 Upgrade: preamble to the TLS handshake -- choosing the
+ certificates based on the initial Host: header -- will allow ISPs to
+ provide secure name-based virtual hosting as well.
+
+2. Introduction
+
+ TLS, a.k.a., SSL (Secure Sockets Layer), establishes a private end-
+ to-end connection, optionally including strong mutual authentication,
+ using a variety of cryptosystems. Initially, a handshake phase uses
+ three subprotocols to set up a record layer, authenticate endpoints,
+ set parameters, as well as report errors. Then, there is an ongoing
+ layered record protocol that handles encryption, compression, and
+ reassembly for the remainder of the connection. The latter is
+ intended to be completely transparent. For example, there is no
+ dependency between TLS's record markers and or certificates and
+ HTTP/1.1's chunked encoding or authentication.
+
+ Either the client or server can use the HTTP/1.1 [1] Upgrade
+ mechanism (Section 14.42) to indicate that a TLS-secured connection
+ is desired or necessary. This memo defines the "TLS/1.0" Upgrade
+ token, and a new HTTP Status Code, "426 Upgrade Required".
+
+ Section 3 and Section 4 describe the operation of a directly
+ connected client and server. Intermediate proxies must establish an
+ end-to-end tunnel before applying those operations, as explained in
+ Section 5.
+
+
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 3]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+2.1 Requirements Terminology
+
+ Keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT" and
+ "MAY" that appear in this document are to be interpreted as described
+ in RFC 2119 [11].
+
+3. Client Requested Upgrade to HTTP over TLS
+
+ When the client sends an HTTP/1.1 request with an Upgrade header
+ field containing the token "TLS/1.0", it is requesting the server to
+ complete the current HTTP/1.1 request after switching to TLS/1.0.
+
+3.1 Optional Upgrade
+
+ A client MAY offer to switch to secured operation during any clear
+ HTTP request when an unsecured response would be acceptable:
+
+ GET http://example.bank.com/acct_stat.html?749394889300 HTTP/1.1
+ Host: example.bank.com
+ Upgrade: TLS/1.0
+ Connection: Upgrade
+
+ In this case, the server MAY respond to the clear HTTP operation
+ normally, OR switch to secured operation (as detailed in the next
+ section).
+
+ Note that HTTP/1.1 [1] specifies "the upgrade keyword MUST be
+ supplied within a Connection header field (section 14.10) whenever
+ Upgrade is present in an HTTP/1.1 message".
+
+3.2 Mandatory Upgrade
+
+ If an unsecured response would be unacceptable, a client MUST send an
+ OPTIONS request first to complete the switch to TLS/1.0 (if
+ possible).
+
+ OPTIONS * HTTP/1.1
+ Host: example.bank.com
+ Upgrade: TLS/1.0
+ Connection: Upgrade
+
+3.3 Server Acceptance of Upgrade Request
+
+ As specified in HTTP/1.1 [1], if the server is prepared to initiate
+ the TLS handshake, it MUST send the intermediate "101 Switching
+ Protocol" and MUST include an Upgrade response header specifying the
+ tokens of the protocol stack it is switching to:
+
+
+
+
+Khare & Lawrence Standards Track [Page 4]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+ HTTP/1.1 101 Switching Protocols
+ Upgrade: TLS/1.0, HTTP/1.1
+ Connection: Upgrade
+
+ Note that the protocol tokens listed in the Upgrade header of a 101
+ Switching Protocols response specify an ordered 'bottom-up' stack.
+
+ As specified in HTTP/1.1 [1], Section 10.1.2: "The server will
+ switch protocols to those defined by the response's Upgrade header
+ field immediately after the empty line which terminates the 101
+ response".
+
+ Once the TLS handshake completes successfully, the server MUST
+ continue with the response to the original request. Any TLS handshake
+ failure MUST lead to disconnection, per the TLS error alert
+ specification.
+
+4. Server Requested Upgrade to HTTP over TLS
+
+ The Upgrade response header field advertises possible protocol
+ upgrades a server MAY accept. In conjunction with the "426 Upgrade
+ Required" status code, a server can advertise the exact protocol
+ upgrade(s) that a client MUST accept to complete the request.
+
+4.1 Optional Advertisement
+
+ As specified in HTTP/1.1 [1], the server MAY include an Upgrade
+ header in any response other than 101 or 426 to indicate a
+ willingness to switch to any (combination) of the protocols listed.
+
+4.2 Mandatory Advertisement
+
+ A server MAY indicate that a client request can not be completed
+ without TLS using the "426 Upgrade Required" status code, which MUST
+ include an an Upgrade header field specifying the token of the
+ required TLS version.
+
+ HTTP/1.1 426 Upgrade Required
+ Upgrade: TLS/1.0, HTTP/1.1
+ Connection: Upgrade
+
+ The server SHOULD include a message body in the 426 response which
+ indicates in human readable form the reason for the error and
+ describes any alternative courses which may be available to the user.
+
+ Note that even if a client is willing to use TLS, it must use the
+ operations in Section 3 to proceed; the TLS handshake cannot begin
+ immediately after the 426 response.
+
+
+
+Khare & Lawrence Standards Track [Page 5]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+5. Upgrade across Proxies
+
+ As a hop-by-hop header, Upgrade is negotiated between each pair of
+ HTTP counterparties. If a User Agent sends a request with an Upgrade
+ header to a proxy, it is requesting a change to the protocol between
+ itself and the proxy, not an end-to-end change.
+
+ Since TLS, in particular, requires end-to-end connectivity to provide
+ authentication and prevent man-in-the-middle attacks, this memo
+ specifies the CONNECT method to establish a tunnel across proxies.
+
+ Once a tunnel is established, any of the operations in Section 3 can
+ be used to establish a TLS connection.
+
+5.1 Implications of Hop By Hop Upgrade
+
+ If an origin server receives an Upgrade header from a proxy and
+ responds with a 101 Switching Protocols response, it is changing the
+ protocol only on the connection between the proxy and itself.
+ Similarly, a proxy might return a 101 response to its client to
+ change the protocol on that connection independently of the protocols
+ it is using to communicate toward the origin server.
+
+ These scenarios also complicate diagnosis of a 426 response. Since
+ Upgrade is a hop-by-hop header, a proxy that does not recognize 426
+ might remove the accompanying Upgrade header and prevent the client
+ from determining the required protocol switch. If a client receives
+ a 426 status without an accompanying Upgrade header, it will need to
+ request an end to end tunnel connection as described in Section 5.2
+ and repeat the request in order to obtain the required upgrade
+ information.
+
+ This hop-by-hop definition of Upgrade was a deliberate choice. It
+ allows for incremental deployment on either side of proxies, and for
+ optimized protocols between cascaded proxies without the knowledge of
+ the parties that are not a part of the change.
+
+5.2 Requesting a Tunnel with CONNECT
+
+ A CONNECT method requests that a proxy establish a tunnel connection
+ on its behalf. The Request-URI portion of the Request-Line is always
+ an 'authority' as defined by URI Generic Syntax [2], which is to say
+ the host name and port number destination of the requested connection
+ separated by a colon:
+
+ CONNECT server.example.com:80 HTTP/1.1
+ Host: server.example.com:80
+
+
+
+
+Khare & Lawrence Standards Track [Page 6]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+ Other HTTP mechanisms can be used normally with the CONNECT method --
+ except end-to-end protocol Upgrade requests, of course, since the
+ tunnel must be established first.
+
+ For example, proxy authentication might be used to establish the
+ authority to create a tunnel:
+
+ CONNECT server.example.com:80 HTTP/1.1
+ Host: server.example.com:80
+ Proxy-Authorization: basic aGVsbG86d29ybGQ=
+
+ Like any other pipelined HTTP/1.1 request, data to be tunneled may be
+ sent immediately after the blank line. The usual caveats also apply:
+ data may be discarded if the eventual response is negative, and the
+ connection may be reset with no response if more than one TCP segment
+ is outstanding.
+
+5.3 Establishing a Tunnel with CONNECT
+
+ Any successful (2xx) response to a CONNECT request indicates that the
+ proxy has established a connection to the requested host and port,
+ and has switched to tunneling the current connection to that server
+ connection.
+
+ It may be the case that the proxy itself can only reach the requested
+ origin server through another proxy. In this case, the first proxy
+ SHOULD make a CONNECT request of that next proxy, requesting a tunnel
+ to the authority. A proxy MUST NOT respond with any 2xx status code
+ unless it has either a direct or tunnel connection established to the
+ authority.
+
+ An origin server which receives a CONNECT request for itself MAY
+ respond with a 2xx status code to indicate that a connection is
+ established.
+
+ If at any point either one of the peers gets disconnected, any
+ outstanding data that came from that peer will be passed to the other
+ one, and after that also the other connection will be terminated by
+ the proxy. If there is outstanding data to that peer undelivered,
+ that data will be discarded.
+
+6. Rationale for the use of a 4xx (client error) Status Code
+
+ Reliable, interoperable negotiation of Upgrade features requires an
+ unambiguous failure signal. The 426 Upgrade Required status code
+ allows a server to definitively state the precise protocol extensions
+ a given resource must be served with.
+
+
+
+
+Khare & Lawrence Standards Track [Page 7]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+ It might at first appear that the response should have been some form
+ of redirection (a 3xx code), by analogy to an old-style redirection
+ to an https: URI. User agents that do not understand Upgrade:
+ preclude this.
+
+ Suppose that a 3xx code had been assigned for "Upgrade Required"; a
+ user agent that did not recognize it would treat it as 300. It would
+ then properly look for a "Location" header in the response and
+ attempt to repeat the request at the URL in that header field. Since
+ it did not know to Upgrade to incorporate the TLS layer, it would at
+ best fail again at the new URL.
+
+7. IANA Considerations
+
+ IANA shall create registries for two name spaces, as described in BCP
+ 26 [10]:
+
+ o HTTP Status Codes
+ o HTTP Upgrade Tokens
+
+7.1 HTTP Status Code Registry
+
+ The HTTP Status Code Registry defines the name space for the Status-
+ Code token in the Status line of an HTTP response. The initial
+ values for this name space are those specified by:
+
+ 1. Draft Standard for HTTP/1.1 [1]
+ 2. Web Distributed Authoring and Versioning [4] [defines 420-424]
+ 3. WebDAV Advanced Collections [5] (Work in Progress) [defines 425]
+ 4. Section 6 [defines 426]
+
+ Values to be added to this name space SHOULD be subject to review in
+ the form of a standards track document within the IETF Applications
+ Area. Any such document SHOULD be traceable through statuses of
+ either 'Obsoletes' or 'Updates' to the Draft Standard for
+ HTTP/1.1 [1].
+
+7.2 HTTP Upgrade Token Registry
+
+ The HTTP Upgrade Token Registry defines the name space for product
+ tokens used to identify protocols in the Upgrade HTTP header field.
+ Each registered token should be associated with one or a set of
+ specifications, and with contact information.
+
+ The Draft Standard for HTTP/1.1 [1] specifies that these tokens obey
+ the production for 'product':
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 8]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+ product = token ["/" product-version]
+ product-version = token
+
+ Registrations should be allowed on a First Come First Served basis as
+ described in BCP 26 [10]. These specifications need not be IETF
+ documents or be subject to IESG review, but should obey the following
+ rules:
+
+ 1. A token, once registered, stays registered forever.
+ 2. The registration MUST name a responsible party for the
+ registration.
+ 3. The registration MUST name a point of contact.
+ 4. The registration MAY name the documentation required for the
+ token.
+ 5. The responsible party MAY change the registration at any time.
+ The IANA will keep a record of all such changes, and make them
+ available upon request.
+ 6. The responsible party for the first registration of a "product"
+ token MUST approve later registrations of a "version" token
+ together with that "product" token before they can be registered.
+ 7. If absolutely required, the IESG MAY reassign the responsibility
+ for a token. This will normally only be used in the case when a
+ responsible party cannot be contacted.
+
+ This specification defines the protocol token "TLS/1.0" as the
+ identifier for the protocol specified by The TLS Protocol [6].
+
+ It is NOT required that specifications for upgrade tokens be made
+ publicly available, but the contact information for the registration
+ SHOULD be.
+
+8. Security Considerations
+
+ The potential for a man-in-the-middle attack (deleting the Upgrade
+ header) remains the same as current, mixed http/https practice:
+
+ o Removing the Upgrade header is similar to rewriting web pages to
+ change https:// links to http:// links.
+ o The risk is only present if the server is willing to vend such
+ information over both a secure and an insecure channel in the
+ first place.
+ o If the client knows for a fact that a server is TLS-compliant, it
+ can insist on it by only sending an Upgrade request with a no-op
+ method like OPTIONS.
+ o Finally, as the https: specification warns, "users should
+ carefully examine the certificate presented by the server to
+ determine if it meets their expectations".
+
+
+
+
+Khare & Lawrence Standards Track [Page 9]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+ Furthermore, for clients that do not explicitly try to invoke TLS,
+ servers can use the Upgrade header in any response other than 101 or
+ 426 to advertise TLS compliance. Since TLS compliance should be
+ considered a feature of the server and not the resource at hand, it
+ should be sufficient to send it once, and let clients cache that
+ fact.
+
+8.1 Implications for the https: URI Scheme
+
+ While nothing in this memo affects the definition of the 'https' URI
+ scheme, widespread adoption of this mechanism for HyperText content
+ could use 'http' to identify both secure and non-secure resources.
+
+ The choice of what security characteristics are required on the
+ connection is left to the client and server. This allows either
+ party to use any information available in making this determination.
+ For example, user agents may rely on user preference settings or
+ information about the security of the network such as 'TLS required
+ on all POST operations not on my local net', or servers may apply
+ resource access rules such as 'the FORM on this page must be served
+ and submitted using TLS'.
+
+8.2 Security Considerations for CONNECT
+
+ A generic TCP tunnel is fraught with security risks. First, such
+ authorization should be limited to a small number of known ports.
+ The Upgrade: mechanism defined here only requires onward tunneling at
+ port 80. Second, since tunneled data is opaque to the proxy, there
+ are additional risks to tunneling to other well-known or reserved
+ ports. A putative HTTP client CONNECTing to port 25 could relay spam
+ via SMTP, for example.
+
+References
+
+ [1] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L.,
+ Leach, P. and T. Berners-Lee, "Hypertext Transfer Protocol --
+ HTTP/1.1", RFC 2616, June 1999.
+
+ [2] Berners-Lee, T., Fielding, R. and L. Masinter, "URI Generic
+ Syntax", RFC 2396, August 1998.
+
+ [3] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000.
+
+ [4] Goland, Y., Whitehead, E., Faizi, A., Carter, S. and D. Jensen,
+ "Web Distributed Authoring and Versioning", RFC 2518, February
+ 1999.
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 10]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+ [5] Slein, J., Whitehead, E.J., et al., "WebDAV Advanced Collections
+ Protocol", Work In Progress.
+
+ [6] Dierks, T. and C. Allen, "The TLS Protocol", RFC 2246, January
+ 1999.
+
+ [7] Herriot, R., Butler, S., Moore, P. and R. Turner, "Internet
+ Printing Protocol/1.0: Encoding and Transport", RFC 2565, April
+ 1999.
+
+ [8] Luotonen, A., "Tunneling TCP based protocols through Web proxy
+ servers", Work In Progress. (Also available in: Luotonen, Ari.
+ Web Proxy Servers, Prentice-Hall, 1997 ISBN:0136806120.)
+
+ [9] Rose, M., "Writing I-Ds and RFCs using XML", RFC 2629, June
+ 1999.
+
+ [10] Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA
+ Considerations Section in RFCs", BCP 26, RFC 2434, October 1998.
+
+ [11] Bradner, S., "Key words for use in RFCs to Indicate Requirement
+ Levels", BCP 14, RFC 2119, March 1997.
+
+Authors' Addresses
+
+ Rohit Khare
+ 4K Associates / UC Irvine
+ 3207 Palo Verde
+ Irvine, CA 92612
+ US
+
+ Phone: +1 626 806 7574
+ EMail: rohit@4K-associates.com
+ URI: http://www.4K-associates.com/
+
+
+ Scott Lawrence
+ Agranat Systems, Inc.
+ 5 Clocktower Place
+ Suite 400
+ Maynard, MA 01754
+ US
+
+ Phone: +1 978 461 0888
+ EMail: lawrence@agranat.com
+ URI: http://www.agranat.com/
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 11]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+Appendix A. Acknowledgments
+
+ The CONNECT method was originally described in a Work in Progress
+ titled, "Tunneling TCP based protocols through Web proxy servers",
+ [8] by Ari Luotonen of Netscape Communications Corporation. It was
+ widely implemented by HTTP proxies, but was never made a part of any
+ IETF Standards Track document. The method name CONNECT was reserved,
+ but not defined in [1].
+
+ The definition provided here is derived directly from that earlier
+ memo, with some editorial changes and conformance to the stylistic
+ conventions since established in other HTTP specifications.
+
+ Additional Thanks to:
+
+ o Paul Hoffman for his work on the STARTTLS command extension for
+ ESMTP.
+ o Roy Fielding for assistance with the rationale behind Upgrade:
+ and its interaction with OPTIONS.
+ o Eric Rescorla for his work on standardizing the existing https:
+ practice to compare with.
+ o Marshall Rose, for the xml2rfc document type description and tools
+ [9].
+ o Jim Whitehead, for sorting out the current range of available HTTP
+ status codes.
+ o Henrik Frystyk Nielsen, whose work on the Mandatory extension
+ mechanism pointed out a hop-by-hop Upgrade still requires
+ tunneling.
+ o Harald Alvestrand for improvements to the token registration
+ rules.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 12]
+
+RFC 2817 HTTP Upgrade to TLS May 2000
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Khare & Lawrence Standards Track [Page 13]
+
diff --git a/standards/rfc2818.txt b/standards/rfc2818.txt
new file mode 100644
index 000000000..219a1c427
--- /dev/null
+++ b/standards/rfc2818.txt
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+Network Working Group E. Rescorla
+Request for Comments: 2818 RTFM, Inc.
+Category: Informational May 2000
+
+
+ HTTP Over TLS
+
+Status of this Memo
+
+ This memo provides information for the Internet community. It does
+ not specify an Internet standard of any kind. Distribution of this
+ memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+Abstract
+
+ This memo describes how to use TLS to secure HTTP connections over
+ the Internet. Current practice is to layer HTTP over SSL (the
+ predecessor to TLS), distinguishing secured traffic from insecure
+ traffic by the use of a different server port. This document
+ documents that practice using TLS. A companion document describes a
+ method for using HTTP/TLS over the same port as normal HTTP
+ [RFC2817].
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . 2
+ 1.1. Requirements Terminology . . . . . . . . . . . . . . . 2
+ 2. HTTP Over TLS . . . . . . . . . . . . . . . . . . . . . . 2
+ 2.1. Connection Initiation . . . . . . . . . . . . . . . . . 2
+ 2.2. Connection Closure . . . . . . . . . . . . . . . . . . 2
+ 2.2.1. Client Behavior . . . . . . . . . . . . . . . . . . . 3
+ 2.2.2. Server Behavior . . . . . . . . . . . . . . . . . . . 3
+ 2.3. Port Number . . . . . . . . . . . . . . . . . . . . . . 4
+ 2.4. URI Format . . . . . . . . . . . . . . . . . . . . . . 4
+ 3. Endpoint Identification . . . . . . . . . . . . . . . . . 4
+ 3.1. Server Identity . . . . . . . . . . . . . . . . . . . . 4
+ 3.2. Client Identity . . . . . . . . . . . . . . . . . . . . 5
+ References . . . . . . . . . . . . . . . . . . . . . . . . . 6
+ Security Considerations . . . . . . . . . . . . . . . . . . 6
+ Author's Address . . . . . . . . . . . . . . . . . . . . . . 6
+ Full Copyright Statement . . . . . . . . . . . . . . . . . . 7
+
+
+
+
+
+
+Rescorla Informational [Page 1]
+
+RFC 2818 HTTP Over TLS May 2000
+
+
+1. Introduction
+
+ HTTP [RFC2616] was originally used in the clear on the Internet.
+ However, increased use of HTTP for sensitive applications has
+ required security measures. SSL, and its successor TLS [RFC2246] were
+ designed to provide channel-oriented security. This document
+ describes how to use HTTP over TLS.
+
+1.1. Requirements Terminology
+
+ Keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT" and
+ "MAY" that appear in this document are to be interpreted as described
+ in [RFC2119].
+
+2. HTTP Over TLS
+
+ Conceptually, HTTP/TLS is very simple. Simply use HTTP over TLS
+ precisely as you would use HTTP over TCP.
+
+2.1. Connection Initiation
+
+ The agent acting as the HTTP client should also act as the TLS
+ client. It should initiate a connection to the server on the
+ appropriate port and then send the TLS ClientHello to begin the TLS
+ handshake. When the TLS handshake has finished. The client may then
+ initiate the first HTTP request. All HTTP data MUST be sent as TLS
+ "application data". Normal HTTP behavior, including retained
+ connections should be followed.
+
+2.2. Connection Closure
+
+ TLS provides a facility for secure connection closure. When a valid
+ closure alert is received, an implementation can be assured that no
+ further data will be received on that connection. TLS
+ implementations MUST initiate an exchange of closure alerts before
+ closing a connection. A TLS implementation MAY, after sending a
+ closure alert, close the connection without waiting for the peer to
+ send its closure alert, generating an "incomplete close". Note that
+ an implementation which does this MAY choose to reuse the session.
+ This SHOULD only be done when the application knows (typically
+ through detecting HTTP message boundaries) that it has received all
+ the message data that it cares about.
+
+ As specified in [RFC2246], any implementation which receives a
+ connection close without first receiving a valid closure alert (a
+ "premature close") MUST NOT reuse that session. Note that a
+ premature close does not call into question the security of the data
+ already received, but simply indicates that subsequent data might
+
+
+
+Rescorla Informational [Page 2]
+
+RFC 2818 HTTP Over TLS May 2000
+
+
+ have been truncated. Because TLS is oblivious to HTTP
+ request/response boundaries, it is necessary to examine the HTTP data
+ itself (specifically the Content-Length header) to determine whether
+ the truncation occurred inside a message or between messages.
+
+2.2.1. Client Behavior
+
+ Because HTTP uses connection closure to signal end of server data,
+ client implementations MUST treat any premature closes as errors and
+ the data received as potentially truncated. While in some cases the
+ HTTP protocol allows the client to find out whether truncation took
+ place so that, if it received the complete reply, it may tolerate
+ such errors following the principle to "[be] strict when sending and
+ tolerant when receiving" [RFC1958], often truncation does not show in
+ the HTTP protocol data; two cases in particular deserve special note:
+
+ A HTTP response without a Content-Length header. Since data length
+ in this situation is signalled by connection close a premature
+ close generated by the server cannot be distinguished from a
+ spurious close generated by an attacker.
+
+ A HTTP response with a valid Content-Length header closed before
+ all data has been read. Because TLS does not provide document
+ oriented protection, it is impossible to determine whether the
+ server has miscomputed the Content-Length or an attacker has
+ truncated the connection.
+
+ There is one exception to the above rule. When encountering a
+ premature close, a client SHOULD treat as completed all requests for
+ which it has received as much data as specified in the Content-Length
+ header.
+
+ A client detecting an incomplete close SHOULD recover gracefully. It
+ MAY resume a TLS session closed in this fashion.
+
+ Clients MUST send a closure alert before closing the connection.
+ Clients which are unprepared to receive any more data MAY choose not
+ to wait for the server's closure alert and simply close the
+ connection, thus generating an incomplete close on the server side.
+
+2.2.2. Server Behavior
+
+ RFC 2616 permits an HTTP client to close the connection at any time,
+ and requires servers to recover gracefully. In particular, servers
+ SHOULD be prepared to receive an incomplete close from the client,
+ since the client can often determine when the end of server data is.
+ Servers SHOULD be willing to resume TLS sessions closed in this
+ fashion.
+
+
+
+Rescorla Informational [Page 3]
+
+RFC 2818 HTTP Over TLS May 2000
+
+
+ Implementation note: In HTTP implementations which do not use
+ persistent connections, the server ordinarily expects to be able to
+ signal end of data by closing the connection. When Content-Length is
+ used, however, the client may have already sent the closure alert and
+ dropped the connection.
+
+ Servers MUST attempt to initiate an exchange of closure alerts with
+ the client before closing the connection. Servers MAY close the
+ connection after sending the closure alert, thus generating an
+ incomplete close on the client side.
+
+2.3. Port Number
+
+ The first data that an HTTP server expects to receive from the client
+ is the Request-Line production. The first data that a TLS server (and
+ hence an HTTP/TLS server) expects to receive is the ClientHello.
+ Consequently, common practice has been to run HTTP/TLS over a
+ separate port in order to distinguish which protocol is being used.
+ When HTTP/TLS is being run over a TCP/IP connection, the default port
+ is 443. This does not preclude HTTP/TLS from being run over another
+ transport. TLS only presumes a reliable connection-oriented data
+ stream.
+
+2.4. URI Format
+
+ HTTP/TLS is differentiated from HTTP URIs by using the 'https'
+ protocol identifier in place of the 'http' protocol identifier. An
+ example URI specifying HTTP/TLS is:
+
+ https://www.example.com/~smith/home.html
+
+3. Endpoint Identification
+
+3.1. Server Identity
+
+ In general, HTTP/TLS requests are generated by dereferencing a URI.
+ As a consequence, the hostname for the server is known to the client.
+ If the hostname is available, the client MUST check it against the
+ server's identity as presented in the server's Certificate message,
+ in order to prevent man-in-the-middle attacks.
+
+ If the client has external information as to the expected identity of
+ the server, the hostname check MAY be omitted. (For instance, a
+ client may be connecting to a machine whose address and hostname are
+ dynamic but the client knows the certificate that the server will
+ present.) In such cases, it is important to narrow the scope of
+ acceptable certificates as much as possible in order to prevent man
+
+
+
+
+Rescorla Informational [Page 4]
+
+RFC 2818 HTTP Over TLS May 2000
+
+
+ in the middle attacks. In special cases, it may be appropriate for
+ the client to simply ignore the server's identity, but it must be
+ understood that this leaves the connection open to active attack.
+
+ If a subjectAltName extension of type dNSName is present, that MUST
+ be used as the identity. Otherwise, the (most specific) Common Name
+ field in the Subject field of the certificate MUST be used. Although
+ the use of the Common Name is existing practice, it is deprecated and
+ Certification Authorities are encouraged to use the dNSName instead.
+
+ Matching is performed using the matching rules specified by
+ [RFC2459]. If more than one identity of a given type is present in
+ the certificate (e.g., more than one dNSName name, a match in any one
+ of the set is considered acceptable.) Names may contain the wildcard
+ character * which is considered to match any single domain name
+ component or component fragment. E.g., *.a.com matches foo.a.com but
+ not bar.foo.a.com. f*.com matches foo.com but not bar.com.
+
+ In some cases, the URI is specified as an IP address rather than a
+ hostname. In this case, the iPAddress subjectAltName must be present
+ in the certificate and must exactly match the IP in the URI.
+
+ If the hostname does not match the identity in the certificate, user
+ oriented clients MUST either notify the user (clients MAY give the
+ user the opportunity to continue with the connection in any case) or
+ terminate the connection with a bad certificate error. Automated
+ clients MUST log the error to an appropriate audit log (if available)
+ and SHOULD terminate the connection (with a bad certificate error).
+ Automated clients MAY provide a configuration setting that disables
+ this check, but MUST provide a setting which enables it.
+
+ Note that in many cases the URI itself comes from an untrusted
+ source. The above-described check provides no protection against
+ attacks where this source is compromised. For example, if the URI was
+ obtained by clicking on an HTML page which was itself obtained
+ without using HTTP/TLS, a man in the middle could have replaced the
+ URI. In order to prevent this form of attack, users should carefully
+ examine the certificate presented by the server to determine if it
+ meets their expectations.
+
+3.2. Client Identity
+
+ Typically, the server has no external knowledge of what the client's
+ identity ought to be and so checks (other than that the client has a
+ certificate chain rooted in an appropriate CA) are not possible. If a
+ server has such knowledge (typically from some source external to
+ HTTP or TLS) it SHOULD check the identity as described above.
+
+
+
+
+Rescorla Informational [Page 5]
+
+RFC 2818 HTTP Over TLS May 2000
+
+
+References
+
+ [RFC2459] Housley, R., Ford, W., Polk, W. and D. Solo, "Internet
+ Public Key Infrastructure: Part I: X.509 Certificate and
+ CRL Profile", RFC 2459, January 1999.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter,
+ L., Leach, P. and T. Berners-Lee, "Hypertext Transfer
+ Protocol, HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC2119] Bradner, S., "Key Words for use in RFCs to indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol", RFC 2246,
+ January 1999.
+
+ [RFC2817] Khare, R. and S. Lawrence, "Upgrading to TLS Within
+ HTTP/1.1", RFC 2817, May 2000.
+
+Security Considerations
+
+ This entire document is about security.
+
+Author's Address
+
+ Eric Rescorla
+ RTFM, Inc.
+ 30 Newell Road, #16
+ East Palo Alto, CA 94303
+
+ Phone: (650) 328-8631
+ EMail: ekr@rtfm.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rescorla Informational [Page 6]
+
+RFC 2818 HTTP Over TLS May 2000
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rescorla Informational [Page 7]
+
diff --git a/standards/rfc2821.txt b/standards/rfc2821.txt
new file mode 100644
index 000000000..0eac91188
--- /dev/null
+++ b/standards/rfc2821.txt
@@ -0,0 +1,4427 @@
+
+
+
+
+
+
+Network Working Group J. Klensin, Editor
+Request for Comments: 2821 AT&T Laboratories
+Obsoletes: 821, 974, 1869 April 2001
+Updates: 1123
+Category: Standards Track
+
+
+ Simple Mail Transfer Protocol
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+Abstract
+
+ This document is a self-contained specification of the basic protocol
+ for the Internet electronic mail transport. It consolidates, updates
+ and clarifies, but doesn't add new or change existing functionality
+ of the following:
+
+ - the original SMTP (Simple Mail Transfer Protocol) specification of
+ RFC 821 [30],
+
+ - domain name system requirements and implications for mail
+ transport from RFC 1035 [22] and RFC 974 [27],
+
+ - the clarifications and applicability statements in RFC 1123 [2],
+ and
+
+ - material drawn from the SMTP Extension mechanisms [19].
+
+ It obsoletes RFC 821, RFC 974, and updates RFC 1123 (replaces the
+ mail transport materials of RFC 1123). However, RFC 821 specifies
+ some features that were not in significant use in the Internet by the
+ mid-1990s and (in appendices) some additional transport models.
+ Those sections are omitted here in the interest of clarity and
+ brevity; readers needing them should refer to RFC 821.
+
+
+
+
+
+
+Klensin Standards Track [Page 1]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ It also includes some additional material from RFC 1123 that required
+ amplification. This material has been identified in multiple ways,
+ mostly by tracking flaming on various lists and newsgroups and
+ problems of unusual readings or interpretations that have appeared as
+ the SMTP extensions have been deployed. Where this specification
+ moves beyond consolidation and actually differs from earlier
+ documents, it supersedes them technically as well as textually.
+
+ Although SMTP was designed as a mail transport and delivery protocol,
+ this specification also contains information that is important to its
+ use as a 'mail submission' protocol, as recommended for POP [3, 26]
+ and IMAP [6]. Additional submission issues are discussed in RFC 2476
+ [15].
+
+ Section 2.3 provides definitions of terms specific to this document.
+ Except when the historical terminology is necessary for clarity, this
+ document uses the current 'client' and 'server' terminology to
+ identify the sending and receiving SMTP processes, respectively.
+
+ A companion document [32] discusses message headers, message bodies
+ and formats and structures for them, and their relationship.
+
+Table of Contents
+
+ 1. Introduction .................................................. 4
+ 2. The SMTP Model ................................................ 5
+ 2.1 Basic Structure .............................................. 5
+ 2.2 The Extension Model .......................................... 7
+ 2.2.1 Background ................................................. 7
+ 2.2.2 Definition and Registration of Extensions .................. 8
+ 2.3 Terminology .................................................. 9
+ 2.3.1 Mail Objects ............................................... 10
+ 2.3.2 Senders and Receivers ...................................... 10
+ 2.3.3 Mail Agents and Message Stores ............................. 10
+ 2.3.4 Host ....................................................... 11
+ 2.3.5 Domain ..................................................... 11
+ 2.3.6 Buffer and State Table ..................................... 11
+ 2.3.7 Lines ...................................................... 12
+ 2.3.8 Originator, Delivery, Relay, and Gateway Systems ........... 12
+ 2.3.9 Message Content and Mail Data .............................. 13
+ 2.3.10 Mailbox and Address ....................................... 13
+ 2.3.11 Reply ..................................................... 13
+ 2.4 General Syntax Principles and Transaction Model .............. 13
+ 3. The SMTP Procedures: An Overview .............................. 15
+ 3.1 Session Initiation ........................................... 15
+ 3.2 Client Initiation ............................................ 16
+ 3.3 Mail Transactions ............................................ 16
+ 3.4 Forwarding for Address Correction or Updating ................ 19
+
+
+
+Klensin Standards Track [Page 2]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ 3.5 Commands for Debugging Addresses ............................. 20
+ 3.5.1 Overview ................................................... 20
+ 3.5.2 VRFY Normal Response ....................................... 22
+ 3.5.3 Meaning of VRFY or EXPN Success Response ................... 22
+ 3.5.4 Semantics and Applications of EXPN ......................... 23
+ 3.6 Domains ...................................................... 23
+ 3.7 Relaying ..................................................... 24
+ 3.8 Mail Gatewaying .............................................. 25
+ 3.8.1 Header Fields in Gatewaying ................................ 26
+ 3.8.2 Received Lines in Gatewaying ............................... 26
+ 3.8.3 Addresses in Gatewaying .................................... 26
+ 3.8.4 Other Header Fields in Gatewaying .......................... 27
+ 3.8.5 Envelopes in Gatewaying .................................... 27
+ 3.9 Terminating Sessions and Connections ......................... 27
+ 3.10 Mailing Lists and Aliases ................................... 28
+ 3.10.1 Alias ..................................................... 28
+ 3.10.2 List ...................................................... 28
+ 4. The SMTP Specifications ....................................... 29
+ 4.1 SMTP Commands ................................................ 29
+ 4.1.1 Command Semantics and Syntax ............................... 29
+ 4.1.1.1 Extended HELLO (EHLO) or HELLO (HELO) ................... 29
+ 4.1.1.2 MAIL (MAIL) .............................................. 31
+ 4.1.1.3 RECIPIENT (RCPT) ......................................... 31
+ 4.1.1.4 DATA (DATA) .............................................. 33
+ 4.1.1.5 RESET (RSET) ............................................. 34
+ 4.1.1.6 VERIFY (VRFY) ............................................ 35
+ 4.1.1.7 EXPAND (EXPN) ............................................ 35
+ 4.1.1.8 HELP (HELP) .............................................. 35
+ 4.1.1.9 NOOP (NOOP) .............................................. 35
+ 4.1.1.10 QUIT (QUIT) ............................................. 36
+ 4.1.2 Command Argument Syntax .................................... 36
+ 4.1.3 Address Literals ........................................... 38
+ 4.1.4 Order of Commands .......................................... 39
+ 4.1.5 Private-use Commands ....................................... 40
+ 4.2 SMTP Replies ................................................ 40
+ 4.2.1 Reply Code Severities and Theory ........................... 42
+ 4.2.2 Reply Codes by Function Groups ............................. 44
+ 4.2.3 Reply Codes in Numeric Order .............................. 45
+ 4.2.4 Reply Code 502 ............................................. 46
+ 4.2.5 Reply Codes After DATA and the Subsequent <CRLF>.<CRLF> .... 46
+ 4.3 Sequencing of Commands and Replies ........................... 47
+ 4.3.1 Sequencing Overview ........................................ 47
+ 4.3.2 Command-Reply Sequences .................................... 48
+ 4.4 Trace Information ............................................ 49
+ 4.5 Additional Implementation Issues ............................. 53
+ 4.5.1 Minimum Implementation ..................................... 53
+ 4.5.2 Transparency ............................................... 53
+ 4.5.3 Sizes and Timeouts ......................................... 54
+
+
+
+Klensin Standards Track [Page 3]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ 4.5.3.1 Size limits and minimums ................................. 54
+ 4.5.3.2 Timeouts ................................................. 56
+ 4.5.4 Retry Strategies ........................................... 57
+ 4.5.4.1 Sending Strategy ......................................... 58
+ 4.5.4.2 Receiving Strategy ....................................... 59
+ 4.5.5 Messages with a null reverse-path .......................... 59
+ 5. Address Resolution and Mail Handling .......................... 60
+ 6. Problem Detection and Handling ................................ 62
+ 6.1 Reliable Delivery and Replies by Email ....................... 62
+ 6.2 Loop Detection ............................................... 63
+ 6.3 Compensating for Irregularities .............................. 63
+ 7. Security Considerations ....................................... 64
+ 7.1 Mail Security and Spoofing ................................... 64
+ 7.2 "Blind" Copies ............................................... 65
+ 7.3 VRFY, EXPN, and Security ..................................... 65
+ 7.4 Information Disclosure in Announcements ...................... 66
+ 7.5 Information Disclosure in Trace Fields ....................... 66
+ 7.6 Information Disclosure in Message Forwarding ................. 67
+ 7.7 Scope of Operation of SMTP Servers ........................... 67
+ 8. IANA Considerations ........................................... 67
+ 9. References .................................................... 68
+ 10. Editor's Address ............................................. 70
+ 11. Acknowledgments .............................................. 70
+ Appendices ....................................................... 71
+ A. TCP Transport Service ......................................... 71
+ B. Generating SMTP Commands from RFC 822 Headers ................. 71
+ C. Source Routes ................................................. 72
+ D. Scenarios ..................................................... 73
+ E. Other Gateway Issues .......................................... 76
+ F. Deprecated Features of RFC 821 ................................ 76
+ Full Copyright Statement ......................................... 79
+
+1. Introduction
+
+ The objective of the Simple Mail Transfer Protocol (SMTP) is to
+ transfer mail reliably and efficiently.
+
+ SMTP is independent of the particular transmission subsystem and
+ requires only a reliable ordered data stream channel. While this
+ document specifically discusses transport over TCP, other transports
+ are possible. Appendices to RFC 821 describe some of them.
+
+ An important feature of SMTP is its capability to transport mail
+ across networks, usually referred to as "SMTP mail relaying" (see
+ section 3.8). A network consists of the mutually-TCP-accessible
+ hosts on the public Internet, the mutually-TCP-accessible hosts on a
+ firewall-isolated TCP/IP Intranet, or hosts in some other LAN or WAN
+ environment utilizing a non-TCP transport-level protocol. Using
+
+
+
+Klensin Standards Track [Page 4]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ SMTP, a process can transfer mail to another process on the same
+ network or to some other network via a relay or gateway process
+ accessible to both networks.
+
+ In this way, a mail message may pass through a number of intermediate
+ relay or gateway hosts on its path from sender to ultimate recipient.
+ The Mail eXchanger mechanisms of the domain name system [22, 27] (and
+ section 5 of this document) are used to identify the appropriate
+ next-hop destination for a message being transported.
+
+2. The SMTP Model
+
+2.1 Basic Structure
+
+ The SMTP design can be pictured as:
+
+ +----------+ +----------+
+ +------+ | | | |
+ | User |<-->| | SMTP | |
+ +------+ | Client- |Commands/Replies| Server- |
+ +------+ | SMTP |<-------------->| SMTP | +------+
+ | File |<-->| | and Mail | |<-->| File |
+ |System| | | | | |System|
+ +------+ +----------+ +----------+ +------+
+ SMTP client SMTP server
+
+ When an SMTP client has a message to transmit, it establishes a two-
+ way transmission channel to an SMTP server. The responsibility of an
+ SMTP client is to transfer mail messages to one or more SMTP servers,
+ or report its failure to do so.
+
+ The means by which a mail message is presented to an SMTP client, and
+ how that client determines the domain name(s) to which mail messages
+ are to be transferred is a local matter, and is not addressed by this
+ document. In some cases, the domain name(s) transferred to, or
+ determined by, an SMTP client will identify the final destination(s)
+ of the mail message. In other cases, common with SMTP clients
+ associated with implementations of the POP [3, 26] or IMAP [6]
+ protocols, or when the SMTP client is inside an isolated transport
+ service environment, the domain name determined will identify an
+ intermediate destination through which all mail messages are to be
+ relayed. SMTP clients that transfer all traffic, regardless of the
+ target domain names associated with the individual messages, or that
+ do not maintain queues for retrying message transmissions that
+ initially cannot be completed, may otherwise conform to this
+ specification but are not considered fully-capable. Fully-capable
+ SMTP implementations, including the relays used by these less capable
+
+
+
+
+Klensin Standards Track [Page 5]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ ones, and their destinations, are expected to support all of the
+ queuing, retrying, and alternate address functions discussed in this
+ specification.
+
+ The means by which an SMTP client, once it has determined a target
+ domain name, determines the identity of an SMTP server to which a
+ copy of a message is to be transferred, and then performs that
+ transfer, is covered by this document. To effect a mail transfer to
+ an SMTP server, an SMTP client establishes a two-way transmission
+ channel to that SMTP server. An SMTP client determines the address
+ of an appropriate host running an SMTP server by resolving a
+ destination domain name to either an intermediate Mail eXchanger host
+ or a final target host.
+
+ An SMTP server may be either the ultimate destination or an
+ intermediate "relay" (that is, it may assume the role of an SMTP
+ client after receiving the message) or "gateway" (that is, it may
+ transport the message further using some protocol other than SMTP).
+ SMTP commands are generated by the SMTP client and sent to the SMTP
+ server. SMTP replies are sent from the SMTP server to the SMTP
+ client in response to the commands.
+
+ In other words, message transfer can occur in a single connection
+ between the original SMTP-sender and the final SMTP-recipient, or can
+ occur in a series of hops through intermediary systems. In either
+ case, a formal handoff of responsibility for the message occurs: the
+ protocol requires that a server accept responsibility for either
+ delivering a message or properly reporting the failure to do so.
+
+ Once the transmission channel is established and initial handshaking
+ completed, the SMTP client normally initiates a mail transaction.
+ Such a transaction consists of a series of commands to specify the
+ originator and destination of the mail and transmission of the
+ message content (including any headers or other structure) itself.
+ When the same message is sent to multiple recipients, this protocol
+ encourages the transmission of only one copy of the data for all
+ recipients at the same destination (or intermediate relay) host.
+
+ The server responds to each command with a reply; replies may
+ indicate that the command was accepted, that additional commands are
+ expected, or that a temporary or permanent error condition exists.
+ Commands specifying the sender or recipients may include server-
+ permitted SMTP service extension requests as discussed in section
+ 2.2. The dialog is purposely lock-step, one-at-a-time, although this
+ can be modified by mutually-agreed extension requests such as command
+ pipelining [13].
+
+
+
+
+
+Klensin Standards Track [Page 6]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ Once a given mail message has been transmitted, the client may either
+ request that the connection be shut down or may initiate other mail
+ transactions. In addition, an SMTP client may use a connection to an
+ SMTP server for ancillary services such as verification of email
+ addresses or retrieval of mailing list subscriber addresses.
+
+ As suggested above, this protocol provides mechanisms for the
+ transmission of mail. This transmission normally occurs directly
+ from the sending user's host to the receiving user's host when the
+ two hosts are connected to the same transport service. When they are
+ not connected to the same transport service, transmission occurs via
+ one or more relay SMTP servers. An intermediate host that acts as
+ either an SMTP relay or as a gateway into some other transmission
+ environment is usually selected through the use of the domain name
+ service (DNS) Mail eXchanger mechanism.
+
+ Usually, intermediate hosts are determined via the DNS MX record, not
+ by explicit "source" routing (see section 5 and appendices C and
+ F.2).
+
+2.2 The Extension Model
+
+2.2.1 Background
+
+ In an effort that started in 1990, approximately a decade after RFC
+ 821 was completed, the protocol was modified with a "service
+ extensions" model that permits the client and server to agree to
+ utilize shared functionality beyond the original SMTP requirements.
+ The SMTP extension mechanism defines a means whereby an extended SMTP
+ client and server may recognize each other, and the server can inform
+ the client as to the service extensions that it supports.
+
+ Contemporary SMTP implementations MUST support the basic extension
+ mechanisms. For instance, servers MUST support the EHLO command even
+ if they do not implement any specific extensions and clients SHOULD
+ preferentially utilize EHLO rather than HELO. (However, for
+ compatibility with older conforming implementations, SMTP clients and
+ servers MUST support the original HELO mechanisms as a fallback.)
+ Unless the different characteristics of HELO must be identified for
+ interoperability purposes, this document discusses only EHLO.
+
+ SMTP is widely deployed and high-quality implementations have proven
+ to be very robust. However, the Internet community now considers
+ some services to be important that were not anticipated when the
+ protocol was first designed. If support for those services is to be
+ added, it must be done in a way that permits older implementations to
+ continue working acceptably. The extension framework consists of:
+
+
+
+
+Klensin Standards Track [Page 7]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ - The SMTP command EHLO, superseding the earlier HELO,
+
+ - a registry of SMTP service extensions,
+
+ - additional parameters to the SMTP MAIL and RCPT commands, and
+
+ - optional replacements for commands defined in this protocol, such
+ as for DATA in non-ASCII transmissions [33].
+
+ SMTP's strength comes primarily from its simplicity. Experience with
+ many protocols has shown that protocols with few options tend towards
+ ubiquity, whereas protocols with many options tend towards obscurity.
+
+ Each and every extension, regardless of its benefits, must be
+ carefully scrutinized with respect to its implementation, deployment,
+ and interoperability costs. In many cases, the cost of extending the
+ SMTP service will likely outweigh the benefit.
+
+2.2.2 Definition and Registration of Extensions
+
+ The IANA maintains a registry of SMTP service extensions. A
+ corresponding EHLO keyword value is associated with each extension.
+ Each service extension registered with the IANA must be defined in a
+ formal standards-track or IESG-approved experimental protocol
+ document. The definition must include:
+
+ - the textual name of the SMTP service extension;
+
+ - the EHLO keyword value associated with the extension;
+
+ - the syntax and possible values of parameters associated with the
+ EHLO keyword value;
+
+ - any additional SMTP verbs associated with the extension
+ (additional verbs will usually be, but are not required to be, the
+ same as the EHLO keyword value);
+
+ - any new parameters the extension associates with the MAIL or RCPT
+ verbs;
+
+ - a description of how support for the extension affects the
+ behavior of a server and client SMTP; and,
+
+ - the increment by which the extension is increasing the maximum
+ length of the commands MAIL and/or RCPT, over that specified in
+ this standard.
+
+
+
+
+
+Klensin Standards Track [Page 8]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ In addition, any EHLO keyword value starting with an upper or lower
+ case "X" refers to a local SMTP service extension used exclusively
+ through bilateral agreement. Keywords beginning with "X" MUST NOT be
+ used in a registered service extension. Conversely, keyword values
+ presented in the EHLO response that do not begin with "X" MUST
+ correspond to a standard, standards-track, or IESG-approved
+ experimental SMTP service extension registered with IANA. A
+ conforming server MUST NOT offer non-"X"-prefixed keyword values that
+ are not described in a registered extension.
+
+ Additional verbs and parameter names are bound by the same rules as
+ EHLO keywords; specifically, verbs beginning with "X" are local
+ extensions that may not be registered or standardized. Conversely,
+ verbs not beginning with "X" must always be registered.
+
+2.3 Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described below.
+
+ 1. MUST This word, or the terms "REQUIRED" or "SHALL", mean that
+ the definition is an absolute requirement of the specification.
+
+ 2. MUST NOT This phrase, or the phrase "SHALL NOT", mean that the
+ definition is an absolute prohibition of the specification.
+
+ 3. SHOULD This word, or the adjective "RECOMMENDED", mean that
+ there may exist valid reasons in particular circumstances to
+ ignore a particular item, but the full implications must be
+ understood and carefully weighed before choosing a different
+ course.
+
+ 4. SHOULD NOT This phrase, or the phrase "NOT RECOMMENDED" mean
+ that there may exist valid reasons in particular circumstances
+ when the particular behavior is acceptable or even useful, but the
+ full implications should be understood and the case carefully
+ weighed before implementing any behavior described with this
+ label.
+
+ 5. MAY This word, or the adjective "OPTIONAL", mean that an item is
+ truly optional. One vendor may choose to include the item because
+ a particular marketplace requires it or because the vendor feels
+ that it enhances the product while another vendor may omit the
+ same item. An implementation which does not include a particular
+ option MUST be prepared to interoperate with another
+ implementation which does include the option, though perhaps with
+ reduced functionality. In the same vein an implementation which
+
+
+
+Klensin Standards Track [Page 9]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ does include a particular option MUST be prepared to interoperate
+ with another implementation which does not include the option
+ (except, of course, for the feature the option provides.)
+
+2.3.1 Mail Objects
+
+ SMTP transports a mail object. A mail object contains an envelope
+ and content.
+
+ The SMTP envelope is sent as a series of SMTP protocol units
+ (described in section 3). It consists of an originator address (to
+ which error reports should be directed); one or more recipient
+ addresses; and optional protocol extension material. Historically,
+ variations on the recipient address specification command (RCPT TO)
+ could be used to specify alternate delivery modes, such as immediate
+ display; those variations have now been deprecated (see appendix F,
+ section F.6).
+
+ The SMTP content is sent in the SMTP DATA protocol unit and has two
+ parts: the headers and the body. If the content conforms to other
+ contemporary standards, the headers form a collection of field/value
+ pairs structured as in the message format specification [32]; the
+ body, if structured, is defined according to MIME [12]. The content
+ is textual in nature, expressed using the US-ASCII repertoire [1].
+ Although SMTP extensions (such as "8BITMIME" [20]) may relax this
+ restriction for the content body, the content headers are always
+ encoded using the US-ASCII repertoire. A MIME extension [23] defines
+ an algorithm for representing header values outside the US-ASCII
+ repertoire, while still encoding them using the US-ASCII repertoire.
+
+2.3.2 Senders and Receivers
+
+ In RFC 821, the two hosts participating in an SMTP transaction were
+ described as the "SMTP-sender" and "SMTP-receiver". This document
+ has been changed to reflect current industry terminology and hence
+ refers to them as the "SMTP client" (or sometimes just "the client")
+ and "SMTP server" (or just "the server"), respectively. Since a
+ given host may act both as server and client in a relay situation,
+ "receiver" and "sender" terminology is still used where needed for
+ clarity.
+
+2.3.3 Mail Agents and Message Stores
+
+ Additional mail system terminology became common after RFC 821 was
+ published and, where convenient, is used in this specification. In
+ particular, SMTP servers and clients provide a mail transport service
+ and therefore act as "Mail Transfer Agents" (MTAs). "Mail User
+ Agents" (MUAs or UAs) are normally thought of as the sources and
+
+
+
+Klensin Standards Track [Page 10]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ targets of mail. At the source, an MUA might collect mail to be
+ transmitted from a user and hand it off to an MTA; the final
+ ("delivery") MTA would be thought of as handing the mail off to an
+ MUA (or at least transferring responsibility to it, e.g., by
+ depositing the message in a "message store"). However, while these
+ terms are used with at least the appearance of great precision in
+ other environments, the implied boundaries between MUAs and MTAs
+ often do not accurately match common, and conforming, practices with
+ Internet mail. Hence, the reader should be cautious about inferring
+ the strong relationships and responsibilities that might be implied
+ if these terms were used elsewhere.
+
+2.3.4 Host
+
+ For the purposes of this specification, a host is a computer system
+ attached to the Internet (or, in some cases, to a private TCP/IP
+ network) and supporting the SMTP protocol. Hosts are known by names
+ (see "domain"); identifying them by numerical address is discouraged.
+
+2.3.5 Domain
+
+ A domain (or domain name) consists of one or more dot-separated
+ components. These components ("labels" in DNS terminology [22]) are
+ restricted for SMTP purposes to consist of a sequence of letters,
+ digits, and hyphens drawn from the ASCII character set [1]. Domain
+ names are used as names of hosts and of other entities in the domain
+ name hierarchy. For example, a domain may refer to an alias (label
+ of a CNAME RR) or the label of Mail eXchanger records to be used to
+ deliver mail instead of representing a host name. See [22] and
+ section 5 of this specification.
+
+ The domain name, as described in this document and in [22], is the
+ entire, fully-qualified name (often referred to as an "FQDN"). A
+ domain name that is not in FQDN form is no more than a local alias.
+ Local aliases MUST NOT appear in any SMTP transaction.
+
+2.3.6 Buffer and State Table
+
+ SMTP sessions are stateful, with both parties carefully maintaining a
+ common view of the current state. In this document we model this
+ state by a virtual "buffer" and a "state table" on the server which
+ may be used by the client to, for example, "clear the buffer" or
+ "reset the state table," causing the information in the buffer to be
+ discarded and the state to be returned to some previous state.
+
+
+
+
+
+
+
+Klensin Standards Track [Page 11]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+2.3.7 Lines
+
+ SMTP commands and, unless altered by a service extension, message
+ data, are transmitted in "lines". Lines consist of zero or more data
+ characters terminated by the sequence ASCII character "CR" (hex value
+ 0D) followed immediately by ASCII character "LF" (hex value 0A).
+ This termination sequence is denoted as <CRLF> in this document.
+ Conforming implementations MUST NOT recognize or generate any other
+ character or character sequence as a line terminator. Limits MAY be
+ imposed on line lengths by servers (see section 4.5.3).
+
+ In addition, the appearance of "bare" "CR" or "LF" characters in text
+ (i.e., either without the other) has a long history of causing
+ problems in mail implementations and applications that use the mail
+ system as a tool. SMTP client implementations MUST NOT transmit
+ these characters except when they are intended as line terminators
+ and then MUST, as indicated above, transmit them only as a <CRLF>
+ sequence.
+
+2.3.8 Originator, Delivery, Relay, and Gateway Systems
+
+ This specification makes a distinction among four types of SMTP
+ systems, based on the role those systems play in transmitting
+ electronic mail. An "originating" system (sometimes called an SMTP
+ originator) introduces mail into the Internet or, more generally,
+ into a transport service environment. A "delivery" SMTP system is
+ one that receives mail from a transport service environment and
+ passes it to a mail user agent or deposits it in a message store
+ which a mail user agent is expected to subsequently access. A
+ "relay" SMTP system (usually referred to just as a "relay") receives
+ mail from an SMTP client and transmits it, without modification to
+ the message data other than adding trace information, to another SMTP
+ server for further relaying or for delivery.
+
+ A "gateway" SMTP system (usually referred to just as a "gateway")
+ receives mail from a client system in one transport environment and
+ transmits it to a server system in another transport environment.
+ Differences in protocols or message semantics between the transport
+ environments on either side of a gateway may require that the gateway
+ system perform transformations to the message that are not permitted
+ to SMTP relay systems. For the purposes of this specification,
+ firewalls that rewrite addresses should be considered as gateways,
+ even if SMTP is used on both sides of them (see [11]).
+
+
+
+
+
+
+
+
+Klensin Standards Track [Page 12]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+2.3.9 Message Content and Mail Data
+
+ The terms "message content" and "mail data" are used interchangeably
+ in this document to describe the material transmitted after the DATA
+ command is accepted and before the end of data indication is
+ transmitted. Message content includes message headers and the
+ possibly-structured message body. The MIME specification [12]
+ provides the standard mechanisms for structured message bodies.
+
+2.3.10 Mailbox and Address
+
+ As used in this specification, an "address" is a character string
+ that identifies a user to whom mail will be sent or a location into
+ which mail will be deposited. The term "mailbox" refers to that
+ depository. The two terms are typically used interchangeably unless
+ the distinction between the location in which mail is placed (the
+ mailbox) and a reference to it (the address) is important. An
+ address normally consists of user and domain specifications. The
+ standard mailbox naming convention is defined to be "local-
+ part@domain": contemporary usage permits a much broader set of
+ applications than simple "user names". Consequently, and due to a
+ long history of problems when intermediate hosts have attempted to
+ optimize transport by modifying them, the local-part MUST be
+ interpreted and assigned semantics only by the host specified in the
+ domain part of the address.
+
+2.3.11 Reply
+
+ An SMTP reply is an acknowledgment (positive or negative) sent from
+ receiver to sender via the transmission channel in response to a
+ command. The general form of a reply is a numeric completion code
+ (indicating failure or success) usually followed by a text string.
+ The codes are for use by programs and the text is usually intended
+ for human users. Recent work [34] has specified further structuring
+ of the reply strings, including the use of supplemental and more
+ specific completion codes.
+
+2.4 General Syntax Principles and Transaction Model
+
+ SMTP commands and replies have a rigid syntax. All commands begin
+ with a command verb. All Replies begin with a three digit numeric
+ code. In some commands and replies, arguments MUST follow the verb
+ or reply code. Some commands do not accept arguments (after the
+ verb), and some reply codes are followed, sometimes optionally, by
+ free form text. In both cases, where text appears, it is separated
+ from the verb or reply code by a space character. Complete
+ definitions of commands and replies appear in section 4.
+
+
+
+
+Klensin Standards Track [Page 13]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ Verbs and argument values (e.g., "TO:" or "to:" in the RCPT command
+ and extension name keywords) are not case sensitive, with the sole
+ exception in this specification of a mailbox local-part (SMTP
+ Extensions may explicitly specify case-sensitive elements). That is,
+ a command verb, an argument value other than a mailbox local-part,
+ and free form text MAY be encoded in upper case, lower case, or any
+ mixture of upper and lower case with no impact on its meaning. This
+ is NOT true of a mailbox local-part. The local-part of a mailbox
+ MUST BE treated as case sensitive. Therefore, SMTP implementations
+ MUST take care to preserve the case of mailbox local-parts. Mailbox
+ domains are not case sensitive. In particular, for some hosts the
+ user "smith" is different from the user "Smith". However, exploiting
+ the case sensitivity of mailbox local-parts impedes interoperability
+ and is discouraged.
+
+ A few SMTP servers, in violation of this specification (and RFC 821)
+ require that command verbs be encoded by clients in upper case.
+ Implementations MAY wish to employ this encoding to accommodate those
+ servers.
+
+ The argument field consists of a variable length character string
+ ending with the end of the line, i.e., with the character sequence
+ <CRLF>. The receiver will take no action until this sequence is
+ received.
+
+ The syntax for each command is shown with the discussion of that
+ command. Common elements and parameters are shown in section 4.1.2.
+
+ Commands and replies are composed of characters from the ASCII
+ character set [1]. When the transport service provides an 8-bit byte
+ (octet) transmission channel, each 7-bit character is transmitted
+ right justified in an octet with the high order bit cleared to zero.
+ More specifically, the unextended SMTP service provides seven bit
+ transport only. An originating SMTP client which has not
+ successfully negotiated an appropriate extension with a particular
+ server MUST NOT transmit messages with information in the high-order
+ bit of octets. If such messages are transmitted in violation of this
+ rule, receiving SMTP servers MAY clear the high-order bit or reject
+ the message as invalid. In general, a relay SMTP SHOULD assume that
+ the message content it has received is valid and, assuming that the
+ envelope permits doing so, relay it without inspecting that content.
+ Of course, if the content is mislabeled and the data path cannot
+ accept the actual content, this may result in ultimate delivery of a
+ severely garbled message to the recipient. Delivery SMTP systems MAY
+ reject ("bounce") such messages rather than deliver them. No sending
+ SMTP system is permitted to send envelope commands in any character
+
+
+
+
+
+Klensin Standards Track [Page 14]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ set other than US-ASCII; receiving systems SHOULD reject such
+ commands, normally using "500 syntax error - invalid character"
+ replies.
+
+ Eight-bit message content transmission MAY be requested of the server
+ by a client using extended SMTP facilities, notably the "8BITMIME"
+ extension [20]. 8BITMIME SHOULD be supported by SMTP servers.
+ However, it MUST not be construed as authorization to transmit
+ unrestricted eight bit material. 8BITMIME MUST NOT be requested by
+ senders for material with the high bit on that is not in MIME format
+ with an appropriate content-transfer encoding; servers MAY reject
+ such messages.
+
+ The metalinguistic notation used in this document corresponds to the
+ "Augmented BNF" used in other Internet mail system documents. The
+ reader who is not familiar with that syntax should consult the ABNF
+ specification [8]. Metalanguage terms used in running text are
+ surrounded by pointed brackets (e.g., <CRLF>) for clarity.
+
+3. The SMTP Procedures: An Overview
+
+ This section contains descriptions of the procedures used in SMTP:
+ session initiation, the mail transaction, forwarding mail, verifying
+ mailbox names and expanding mailing lists, and the opening and
+ closing exchanges. Comments on relaying, a note on mail domains, and
+ a discussion of changing roles are included at the end of this
+ section. Several complete scenarios are presented in appendix D.
+
+3.1 Session Initiation
+
+ An SMTP session is initiated when a client opens a connection to a
+ server and the server responds with an opening message.
+
+ SMTP server implementations MAY include identification of their
+ software and version information in the connection greeting reply
+ after the 220 code, a practice that permits more efficient isolation
+ and repair of any problems. Implementations MAY make provision for
+ SMTP servers to disable the software and version announcement where
+ it causes security concerns. While some systems also identify their
+ contact point for mail problems, this is not a substitute for
+ maintaining the required "postmaster" address (see section 4.5.1).
+
+ The SMTP protocol allows a server to formally reject a transaction
+ while still allowing the initial connection as follows: a 554
+ response MAY be given in the initial connection opening message
+ instead of the 220. A server taking this approach MUST still wait
+ for the client to send a QUIT (see section 4.1.1.10) before closing
+ the connection and SHOULD respond to any intervening commands with
+
+
+
+Klensin Standards Track [Page 15]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ "503 bad sequence of commands". Since an attempt to make an SMTP
+ connection to such a system is probably in error, a server returning
+ a 554 response on connection opening SHOULD provide enough
+ information in the reply text to facilitate debugging of the sending
+ system.
+
+3.2 Client Initiation
+
+ Once the server has sent the welcoming message and the client has
+ received it, the client normally sends the EHLO command to the
+ server, indicating the client's identity. In addition to opening the
+ session, use of EHLO indicates that the client is able to process
+ service extensions and requests that the server provide a list of the
+ extensions it supports. Older SMTP systems which are unable to
+ support service extensions and contemporary clients which do not
+ require service extensions in the mail session being initiated, MAY
+ use HELO instead of EHLO. Servers MUST NOT return the extended
+ EHLO-style response to a HELO command. For a particular connection
+ attempt, if the server returns a "command not recognized" response to
+ EHLO, the client SHOULD be able to fall back and send HELO.
+
+ In the EHLO command the host sending the command identifies itself;
+ the command may be interpreted as saying "Hello, I am <domain>" (and,
+ in the case of EHLO, "and I support service extension requests").
+
+3.3 Mail Transactions
+
+ There are three steps to SMTP mail transactions. The transaction
+ starts with a MAIL command which gives the sender identification.
+ (In general, the MAIL command may be sent only when no mail
+ transaction is in progress; see section 4.1.4.) A series of one or
+ more RCPT commands follows giving the receiver information. Then a
+ DATA command initiates transfer of the mail data and is terminated by
+ the "end of mail" data indicator, which also confirms the
+ transaction.
+
+ The first step in the procedure is the MAIL command.
+
+ MAIL FROM:<reverse-path> [SP <mail-parameters> ] <CRLF>
+
+ This command tells the SMTP-receiver that a new mail transaction is
+ starting and to reset all its state tables and buffers, including any
+ recipients or mail data. The <reverse-path> portion of the first or
+ only argument contains the source mailbox (between "<" and ">"
+ brackets), which can be used to report errors (see section 4.2 for a
+ discussion of error reporting). If accepted, the SMTP server returns
+ a 250 OK reply. If the mailbox specification is not acceptable for
+ some reason, the server MUST return a reply indicating whether the
+
+
+
+Klensin Standards Track [Page 16]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ failure is permanent (i.e., will occur again if the client tries to
+ send the same address again) or temporary (i.e., the address might be
+ accepted if the client tries again later). Despite the apparent
+ scope of this requirement, there are circumstances in which the
+ acceptability of the reverse-path may not be determined until one or
+ more forward-paths (in RCPT commands) can be examined. In those
+ cases, the server MAY reasonably accept the reverse-path (with a 250
+ reply) and then report problems after the forward-paths are received
+ and examined. Normally, failures produce 550 or 553 replies.
+
+ Historically, the <reverse-path> can contain more than just a
+ mailbox, however, contemporary systems SHOULD NOT use source routing
+ (see appendix C).
+
+ The optional <mail-parameters> are associated with negotiated SMTP
+ service extensions (see section 2.2).
+
+ The second step in the procedure is the RCPT command.
+
+ RCPT TO:<forward-path> [ SP <rcpt-parameters> ] <CRLF>
+
+ The first or only argument to this command includes a forward-path
+ (normally a mailbox and domain, always surrounded by "<" and ">"
+ brackets) identifying one recipient. If accepted, the SMTP server
+ returns a 250 OK reply and stores the forward-path. If the recipient
+ is known not to be a deliverable address, the SMTP server returns a
+ 550 reply, typically with a string such as "no such user - " and the
+ mailbox name (other circumstances and reply codes are possible).
+ This step of the procedure can be repeated any number of times.
+
+ The <forward-path> can contain more than just a mailbox.
+ Historically, the <forward-path> can be a source routing list of
+ hosts and the destination mailbox, however, contemporary SMTP clients
+ SHOULD NOT utilize source routes (see appendix C). Servers MUST be
+ prepared to encounter a list of source routes in the forward path,
+ but SHOULD ignore the routes or MAY decline to support the relaying
+ they imply. Similarly, servers MAY decline to accept mail that is
+ destined for other hosts or systems. These restrictions make a
+ server useless as a relay for clients that do not support full SMTP
+ functionality. Consequently, restricted-capability clients MUST NOT
+ assume that any SMTP server on the Internet can be used as their mail
+ processing (relaying) site. If a RCPT command appears without a
+ previous MAIL command, the server MUST return a 503 "Bad sequence of
+ commands" response. The optional <rcpt-parameters> are associated
+ with negotiated SMTP service extensions (see section 2.2).
+
+ The third step in the procedure is the DATA command (or some
+ alternative specified in a service extension).
+
+
+
+Klensin Standards Track [Page 17]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ DATA <CRLF>
+
+ If accepted, the SMTP server returns a 354 Intermediate reply and
+ considers all succeeding lines up to but not including the end of
+ mail data indicator to be the message text. When the end of text is
+ successfully received and stored the SMTP-receiver sends a 250 OK
+ reply.
+
+ Since the mail data is sent on the transmission channel, the end of
+ mail data must be indicated so that the command and reply dialog can
+ be resumed. SMTP indicates the end of the mail data by sending a
+ line containing only a "." (period or full stop). A transparency
+ procedure is used to prevent this from interfering with the user's
+ text (see section 4.5.2).
+
+ The end of mail data indicator also confirms the mail transaction and
+ tells the SMTP server to now process the stored recipients and mail
+ data. If accepted, the SMTP server returns a 250 OK reply. The DATA
+ command can fail at only two points in the protocol exchange:
+
+ - If there was no MAIL, or no RCPT, command, or all such commands
+ were rejected, the server MAY return a "command out of sequence"
+ (503) or "no valid recipients" (554) reply in response to the DATA
+ command. If one of those replies (or any other 5yz reply) is
+ received, the client MUST NOT send the message data; more
+ generally, message data MUST NOT be sent unless a 354 reply is
+ received.
+
+ - If the verb is initially accepted and the 354 reply issued, the
+ DATA command should fail only if the mail transaction was
+ incomplete (for example, no recipients), or if resources were
+ unavailable (including, of course, the server unexpectedly
+ becoming unavailable), or if the server determines that the
+ message should be rejected for policy or other reasons.
+
+ However, in practice, some servers do not perform recipient
+ verification until after the message text is received. These servers
+ SHOULD treat a failure for one or more recipients as a "subsequent
+ failure" and return a mail message as discussed in section 6. Using
+ a "550 mailbox not found" (or equivalent) reply code after the data
+ are accepted makes it difficult or impossible for the client to
+ determine which recipients failed.
+
+ When RFC 822 format [7, 32] is being used, the mail data include the
+ memo header items such as Date, Subject, To, Cc, From. Server SMTP
+ systems SHOULD NOT reject messages based on perceived defects in the
+ RFC 822 or MIME [12] message header or message body. In particular,
+
+
+
+
+Klensin Standards Track [Page 18]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ they MUST NOT reject messages in which the numbers of Resent-fields
+ do not match or Resent-to appears without Resent-from and/or Resent-
+ date.
+
+ Mail transaction commands MUST be used in the order discussed above.
+
+3.4 Forwarding for Address Correction or Updating
+
+ Forwarding support is most often required to consolidate and simplify
+ addresses within, or relative to, some enterprise and less frequently
+ to establish addresses to link a person's prior address with current
+ one. Silent forwarding of messages (without server notification to
+ the sender), for security or non-disclosure purposes, is common in
+ the contemporary Internet.
+
+ In both the enterprise and the "new address" cases, information
+ hiding (and sometimes security) considerations argue against exposure
+ of the "final" address through the SMTP protocol as a side-effect of
+ the forwarding activity. This may be especially important when the
+ final address may not even be reachable by the sender. Consequently,
+ the "forwarding" mechanisms described in section 3.2 of RFC 821, and
+ especially the 251 (corrected destination) and 551 reply codes from
+ RCPT must be evaluated carefully by implementers and, when they are
+ available, by those configuring systems.
+
+ In particular:
+
+ * Servers MAY forward messages when they are aware of an address
+ change. When they do so, they MAY either provide address-updating
+ information with a 251 code, or may forward "silently" and return
+ a 250 code. But, if a 251 code is used, they MUST NOT assume that
+ the client will actually update address information or even return
+ that information to the user.
+
+ Alternately,
+
+ * Servers MAY reject or bounce messages when they are not
+ deliverable when addressed. When they do so, they MAY either
+ provide address-updating information with a 551 code, or may
+ reject the message as undeliverable with a 550 code and no
+ address-specific information. But, if a 551 code is used, they
+ MUST NOT assume that the client will actually update address
+ information or even return that information to the user.
+
+ SMTP server implementations that support the 251 and/or 551 reply
+ codes are strongly encouraged to provide configuration mechanisms so
+ that sites which conclude that they would undesirably disclose
+ information can disable or restrict their use.
+
+
+
+Klensin Standards Track [Page 19]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+3.5 Commands for Debugging Addresses
+
+3.5.1 Overview
+
+ SMTP provides commands to verify a user name or obtain the content of
+ a mailing list. This is done with the VRFY and EXPN commands, which
+ have character string arguments. Implementations SHOULD support VRFY
+ and EXPN (however, see section 3.5.2 and 7.3).
+
+ For the VRFY command, the string is a user name or a user name and
+ domain (see below). If a normal (i.e., 250) response is returned,
+ the response MAY include the full name of the user and MUST include
+ the mailbox of the user. It MUST be in either of the following
+ forms:
+
+ User Name <local-part@domain>
+ local-part@domain
+
+ When a name that is the argument to VRFY could identify more than one
+ mailbox, the server MAY either note the ambiguity or identify the
+ alternatives. In other words, any of the following are legitimate
+ response to VRFY:
+
+ 553 User ambiguous
+
+ or
+
+ 553- Ambiguous; Possibilities are
+ 553-Joe Smith <jsmith@foo.com>
+ 553-Harry Smith <hsmith@foo.com>
+ 553 Melvin Smith <dweep@foo.com>
+
+ or
+
+ 553-Ambiguous; Possibilities
+ 553- <jsmith@foo.com>
+ 553- <hsmith@foo.com>
+ 553 <dweep@foo.com>
+
+ Under normal circumstances, a client receiving a 553 reply would be
+ expected to expose the result to the user. Use of exactly the forms
+ given, and the "user ambiguous" or "ambiguous" keywords, possibly
+ supplemented by extended reply codes such as those described in [34],
+ will facilitate automated translation into other languages as needed.
+ Of course, a client that was highly automated or that was operating
+ in another language than English, might choose to try to translate
+ the response, to return some other indication to the user than the
+
+
+
+
+Klensin Standards Track [Page 20]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ literal text of the reply, or to take some automated action such as
+ consulting a directory service for additional information before
+ reporting to the user.
+
+ For the EXPN command, the string identifies a mailing list, and the
+ successful (i.e., 250) multiline response MAY include the full name
+ of the users and MUST give the mailboxes on the mailing list.
+
+ In some hosts the distinction between a mailing list and an alias for
+ a single mailbox is a bit fuzzy, since a common data structure may
+ hold both types of entries, and it is possible to have mailing lists
+ containing only one mailbox. If a request is made to apply VRFY to a
+ mailing list, a positive response MAY be given if a message so
+ addressed would be delivered to everyone on the list, otherwise an
+ error SHOULD be reported (e.g., "550 That is a mailing list, not a
+ user" or "252 Unable to verify members of mailing list"). If a
+ request is made to expand a user name, the server MAY return a
+ positive response consisting of a list containing one name, or an
+ error MAY be reported (e.g., "550 That is a user name, not a mailing
+ list").
+
+ In the case of a successful multiline reply (normal for EXPN) exactly
+ one mailbox is to be specified on each line of the reply. The case
+ of an ambiguous request is discussed above.
+
+ "User name" is a fuzzy term and has been used deliberately. An
+ implementation of the VRFY or EXPN commands MUST include at least
+ recognition of local mailboxes as "user names". However, since
+ current Internet practice often results in a single host handling
+ mail for multiple domains, hosts, especially hosts that provide this
+ functionality, SHOULD accept the "local-part@domain" form as a "user
+ name"; hosts MAY also choose to recognize other strings as "user
+ names".
+
+ The case of expanding a mailbox list requires a multiline reply, such
+ as:
+
+ C: EXPN Example-People
+ S: 250-Jon Postel <Postel@isi.edu>
+ S: 250-Fred Fonebone <Fonebone@physics.foo-u.edu>
+ S: 250 Sam Q. Smith <SQSmith@specific.generic.com>
+
+ or
+
+ C: EXPN Executive-Washroom-List
+ S: 550 Access Denied to You.
+
+
+
+
+
+Klensin Standards Track [Page 21]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ The character string arguments of the VRFY and EXPN commands cannot
+ be further restricted due to the variety of implementations of the
+ user name and mailbox list concepts. On some systems it may be
+ appropriate for the argument of the EXPN command to be a file name
+ for a file containing a mailing list, but again there are a variety
+ of file naming conventions in the Internet. Similarly, historical
+ variations in what is returned by these commands are such that the
+ response SHOULD be interpreted very carefully, if at all, and SHOULD
+ generally only be used for diagnostic purposes.
+
+3.5.2 VRFY Normal Response
+
+ When normal (2yz or 551) responses are returned from a VRFY or EXPN
+ request, the reply normally includes the mailbox name, i.e.,
+ "<local-part@domain>", where "domain" is a fully qualified domain
+ name, MUST appear in the syntax. In circumstances exceptional enough
+ to justify violating the intent of this specification, free-form text
+ MAY be returned. In order to facilitate parsing by both computers
+ and people, addresses SHOULD appear in pointed brackets. When
+ addresses, rather than free-form debugging information, are returned,
+ EXPN and VRFY MUST return only valid domain addresses that are usable
+ in SMTP RCPT commands. Consequently, if an address implies delivery
+ to a program or other system, the mailbox name used to reach that
+ target MUST be given. Paths (explicit source routes) MUST NOT be
+ returned by VRFY or EXPN.
+
+ Server implementations SHOULD support both VRFY and EXPN. For
+ security reasons, implementations MAY provide local installations a
+ way to disable either or both of these commands through configuration
+ options or the equivalent. When these commands are supported, they
+ are not required to work across relays when relaying is supported.
+ Since they were both optional in RFC 821, they MUST be listed as
+ service extensions in an EHLO response, if they are supported.
+
+3.5.3 Meaning of VRFY or EXPN Success Response
+
+ A server MUST NOT return a 250 code in response to a VRFY or EXPN
+ command unless it has actually verified the address. In particular,
+ a server MUST NOT return 250 if all it has done is to verify that the
+ syntax given is valid. In that case, 502 (Command not implemented)
+ or 500 (Syntax error, command unrecognized) SHOULD be returned. As
+ stated elsewhere, implementation (in the sense of actually validating
+ addresses and returning information) of VRFY and EXPN are strongly
+ recommended. Hence, implementations that return 500 or 502 for VRFY
+ are not in full compliance with this specification.
+
+
+
+
+
+
+Klensin Standards Track [Page 22]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ There may be circumstances where an address appears to be valid but
+ cannot reasonably be verified in real time, particularly when a
+ server is acting as a mail exchanger for another server or domain.
+ "Apparent validity" in this case would normally involve at least
+ syntax checking and might involve verification that any domains
+ specified were ones to which the host expected to be able to relay
+ mail. In these situations, reply code 252 SHOULD be returned. These
+ cases parallel the discussion of RCPT verification discussed in
+ section 2.1. Similarly, the discussion in section 3.4 applies to the
+ use of reply codes 251 and 551 with VRFY (and EXPN) to indicate
+ addresses that are recognized but that would be forwarded or bounced
+ were mail received for them. Implementations generally SHOULD be
+ more aggressive about address verification in the case of VRFY than
+ in the case of RCPT, even if it takes a little longer to do so.
+
+3.5.4 Semantics and Applications of EXPN
+
+ EXPN is often very useful in debugging and understanding problems
+ with mailing lists and multiple-target-address aliases. Some systems
+ have attempted to use source expansion of mailing lists as a means of
+ eliminating duplicates. The propagation of aliasing systems with
+ mail on the Internet, for hosts (typically with MX and CNAME DNS
+ records), for mailboxes (various types of local host aliases), and in
+ various proxying arrangements, has made it nearly impossible for
+ these strategies to work consistently, and mail systems SHOULD NOT
+ attempt them.
+
+3.6 Domains
+
+ Only resolvable, fully-qualified, domain names (FQDNs) are permitted
+ when domain names are used in SMTP. In other words, names that can
+ be resolved to MX RRs or A RRs (as discussed in section 5) are
+ permitted, as are CNAME RRs whose targets can be resolved, in turn,
+ to MX or A RRs. Local nicknames or unqualified names MUST NOT be
+ used. There are two exceptions to the rule requiring FQDNs:
+
+ - The domain name given in the EHLO command MUST BE either a primary
+ host name (a domain name that resolves to an A RR) or, if the host
+ has no name, an address literal as described in section 4.1.1.1.
+
+ - The reserved mailbox name "postmaster" may be used in a RCPT
+ command without domain qualification (see section 4.1.1.3) and
+ MUST be accepted if so used.
+
+
+
+
+
+
+
+
+Klensin Standards Track [Page 23]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+3.7 Relaying
+
+ In general, the availability of Mail eXchanger records in the domain
+ name system [22, 27] makes the use of explicit source routes in the
+ Internet mail system unnecessary. Many historical problems with
+ their interpretation have made their use undesirable. SMTP clients
+ SHOULD NOT generate explicit source routes except under unusual
+ circumstances. SMTP servers MAY decline to act as mail relays or to
+ accept addresses that specify source routes. When route information
+ is encountered, SMTP servers are also permitted to ignore the route
+ information and simply send to the final destination specified as the
+ last element in the route and SHOULD do so. There has been an
+ invalid practice of using names that do not appear in the DNS as
+ destination names, with the senders counting on the intermediate
+ hosts specified in source routing to resolve any problems. If source
+ routes are stripped, this practice will cause failures. This is one
+ of several reasons why SMTP clients MUST NOT generate invalid source
+ routes or depend on serial resolution of names.
+
+ When source routes are not used, the process described in RFC 821 for
+ constructing a reverse-path from the forward-path is not applicable
+ and the reverse-path at the time of delivery will simply be the
+ address that appeared in the MAIL command.
+
+ A relay SMTP server is usually the target of a DNS MX record that
+ designates it, rather than the final delivery system. The relay
+ server may accept or reject the task of relaying the mail in the same
+ way it accepts or rejects mail for a local user. If it accepts the
+ task, it then becomes an SMTP client, establishes a transmission
+ channel to the next SMTP server specified in the DNS (according to
+ the rules in section 5), and sends it the mail. If it declines to
+ relay mail to a particular address for policy reasons, a 550 response
+ SHOULD be returned.
+
+ Many mail-sending clients exist, especially in conjunction with
+ facilities that receive mail via POP3 or IMAP, that have limited
+ capability to support some of the requirements of this specification,
+ such as the ability to queue messages for subsequent delivery
+ attempts. For these clients, it is common practice to make private
+ arrangements to send all messages to a single server for processing
+ and subsequent distribution. SMTP, as specified here, is not ideally
+ suited for this role, and work is underway on standardized mail
+ submission protocols that might eventually supercede the current
+ practices. In any event, because these arrangements are private and
+ fall outside the scope of this specification, they are not described
+ here.
+
+
+
+
+
+Klensin Standards Track [Page 24]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ It is important to note that MX records can point to SMTP servers
+ which act as gateways into other environments, not just SMTP relays
+ and final delivery systems; see sections 3.8 and 5.
+
+ If an SMTP server has accepted the task of relaying the mail and
+ later finds that the destination is incorrect or that the mail cannot
+ be delivered for some other reason, then it MUST construct an
+ "undeliverable mail" notification message and send it to the
+ originator of the undeliverable mail (as indicated by the reverse-
+ path). Formats specified for non-delivery reports by other standards
+ (see, for example, [24, 25]) SHOULD be used if possible.
+
+ This notification message must be from the SMTP server at the relay
+ host or the host that first determines that delivery cannot be
+ accomplished. Of course, SMTP servers MUST NOT send notification
+ messages about problems transporting notification messages. One way
+ to prevent loops in error reporting is to specify a null reverse-path
+ in the MAIL command of a notification message. When such a message
+ is transmitted the reverse-path MUST be set to null (see section
+ 4.5.5 for additional discussion). A MAIL command with a null
+ reverse-path appears as follows:
+
+ MAIL FROM:<>
+
+ As discussed in section 2.4.1, a relay SMTP has no need to inspect or
+ act upon the headers or body of the message data and MUST NOT do so
+ except to add its own "Received:" header (section 4.4) and,
+ optionally, to attempt to detect looping in the mail system (see
+ section 6.2).
+
+3.8 Mail Gatewaying
+
+ While the relay function discussed above operates within the Internet
+ SMTP transport service environment, MX records or various forms of
+ explicit routing may require that an intermediate SMTP server perform
+ a translation function between one transport service and another. As
+ discussed in section 2.3.8, when such a system is at the boundary
+ between two transport service environments, we refer to it as a
+ "gateway" or "gateway SMTP".
+
+ Gatewaying mail between different mail environments, such as
+ different mail formats and protocols, is complex and does not easily
+ yield to standardization. However, some general requirements may be
+ given for a gateway between the Internet and another mail
+ environment.
+
+
+
+
+
+
+Klensin Standards Track [Page 25]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+3.8.1 Header Fields in Gatewaying
+
+ Header fields MAY be rewritten when necessary as messages are
+ gatewayed across mail environment boundaries. This may involve
+ inspecting the message body or interpreting the local-part of the
+ destination address in spite of the prohibitions in section 2.4.1.
+
+ Other mail systems gatewayed to the Internet often use a subset of
+ RFC 822 headers or provide similar functionality with a different
+ syntax, but some of these mail systems do not have an equivalent to
+ the SMTP envelope. Therefore, when a message leaves the Internet
+ environment, it may be necessary to fold the SMTP envelope
+ information into the message header. A possible solution would be to
+ create new header fields to carry the envelope information (e.g.,
+ "X-SMTP-MAIL:" and "X-SMTP-RCPT:"); however, this would require
+ changes in mail programs in foreign environments and might risk
+ disclosure of private information (see section 7.2).
+
+3.8.2 Received Lines in Gatewaying
+
+ When forwarding a message into or out of the Internet environment, a
+ gateway MUST prepend a Received: line, but it MUST NOT alter in any
+ way a Received: line that is already in the header.
+
+ "Received:" fields of messages originating from other environments
+ may not conform exactly to this specification. However, the most
+ important use of Received: lines is for debugging mail faults, and
+ this debugging can be severely hampered by well-meaning gateways that
+ try to "fix" a Received: line. As another consequence of trace
+ fields arising in non-SMTP environments, receiving systems MUST NOT
+ reject mail based on the format of a trace field and SHOULD be
+ extremely robust in the light of unexpected information or formats in
+ those fields.
+
+ The gateway SHOULD indicate the environment and protocol in the "via"
+ clauses of Received field(s) that it supplies.
+
+3.8.3 Addresses in Gatewaying
+
+ From the Internet side, the gateway SHOULD accept all valid address
+ formats in SMTP commands and in RFC 822 headers, and all valid RFC
+ 822 messages. Addresses and headers generated by gateways MUST
+ conform to applicable Internet standards (including this one and RFC
+ 822). Gateways are, of course, subject to the same rules for
+ handling source routes as those described for other SMTP systems in
+ section 3.3.
+
+
+
+
+
+Klensin Standards Track [Page 26]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+3.8.4 Other Header Fields in Gatewaying
+
+ The gateway MUST ensure that all header fields of a message that it
+ forwards into the Internet mail environment meet the requirements for
+ Internet mail. In particular, all addresses in "From:", "To:",
+ "Cc:", etc., fields MUST be transformed (if necessary) to satisfy RFC
+ 822 syntax, MUST reference only fully-qualified domain names, and
+ MUST be effective and useful for sending replies. The translation
+ algorithm used to convert mail from the Internet protocols to another
+ environment's protocol SHOULD ensure that error messages from the
+ foreign mail environment are delivered to the return path from the
+ SMTP envelope, not to the sender listed in the "From:" field (or
+ other fields) of the RFC 822 message.
+
+3.8.5 Envelopes in Gatewaying
+
+ Similarly, when forwarding a message from another environment into
+ the Internet, the gateway SHOULD set the envelope return path in
+ accordance with an error message return address, if supplied by the
+ foreign environment. If the foreign environment has no equivalent
+ concept, the gateway must select and use a best approximation, with
+ the message originator's address as the default of last resort.
+
+3.9 Terminating Sessions and Connections
+
+ An SMTP connection is terminated when the client sends a QUIT
+ command. The server responds with a positive reply code, after which
+ it closes the connection.
+
+ An SMTP server MUST NOT intentionally close the connection except:
+
+ - After receiving a QUIT command and responding with a 221 reply.
+
+ - After detecting the need to shut down the SMTP service and
+ returning a 421 response code. This response code can be issued
+ after the server receives any command or, if necessary,
+ asynchronously from command receipt (on the assumption that the
+ client will receive it after the next command is issued).
+
+ In particular, a server that closes connections in response to
+ commands that are not understood is in violation of this
+ specification. Servers are expected to be tolerant of unknown
+ commands, issuing a 500 reply and awaiting further instructions from
+ the client.
+
+
+
+
+
+
+
+Klensin Standards Track [Page 27]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ An SMTP server which is forcibly shut down via external means SHOULD
+ attempt to send a line containing a 421 response code to the SMTP
+ client before exiting. The SMTP client will normally read the 421
+ response code after sending its next command.
+
+ SMTP clients that experience a connection close, reset, or other
+ communications failure due to circumstances not under their control
+ (in violation of the intent of this specification but sometimes
+ unavoidable) SHOULD, to maintain the robustness of the mail system,
+ treat the mail transaction as if a 451 response had been received and
+ act accordingly.
+
+3.10 Mailing Lists and Aliases
+
+ An SMTP-capable host SHOULD support both the alias and the list
+ models of address expansion for multiple delivery. When a message is
+ delivered or forwarded to each address of an expanded list form, the
+ return address in the envelope ("MAIL FROM:") MUST be changed to be
+ the address of a person or other entity who administers the list.
+ However, in this case, the message header [32] MUST be left
+ unchanged; in particular, the "From" field of the message header is
+ unaffected.
+
+ An important mail facility is a mechanism for multi-destination
+ delivery of a single message, by transforming (or "expanding" or
+ "exploding") a pseudo-mailbox address into a list of destination
+ mailbox addresses. When a message is sent to such a pseudo-mailbox
+ (sometimes called an "exploder"), copies are forwarded or
+ redistributed to each mailbox in the expanded list. Servers SHOULD
+ simply utilize the addresses on the list; application of heuristics
+ or other matching rules to eliminate some addresses, such as that of
+ the originator, is strongly discouraged. We classify such a pseudo-
+ mailbox as an "alias" or a "list", depending upon the expansion
+ rules.
+
+3.10.1 Alias
+
+ To expand an alias, the recipient mailer simply replaces the pseudo-
+ mailbox address in the envelope with each of the expanded addresses
+ in turn; the rest of the envelope and the message body are left
+ unchanged. The message is then delivered or forwarded to each
+ expanded address.
+
+3.10.2 List
+
+ A mailing list may be said to operate by "redistribution" rather than
+ by "forwarding". To expand a list, the recipient mailer replaces the
+ pseudo-mailbox address in the envelope with all of the expanded
+
+
+
+Klensin Standards Track [Page 28]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ addresses. The return address in the envelope is changed so that all
+ error messages generated by the final deliveries will be returned to
+ a list administrator, not to the message originator, who generally
+ has no control over the contents of the list and will typically find
+ error messages annoying.
+
+4. The SMTP Specifications
+
+4.1 SMTP Commands
+
+4.1.1 Command Semantics and Syntax
+
+ The SMTP commands define the mail transfer or the mail system
+ function requested by the user. SMTP commands are character strings
+ terminated by <CRLF>. The commands themselves are alphabetic
+ characters terminated by <SP> if parameters follow and <CRLF>
+ otherwise. (In the interest of improved interoperability, SMTP
+ receivers are encouraged to tolerate trailing white space before the
+ terminating <CRLF>.) The syntax of the local part of a mailbox must
+ conform to receiver site conventions and the syntax specified in
+ section 4.1.2. The SMTP commands are discussed below. The SMTP
+ replies are discussed in section 4.2.
+
+ A mail transaction involves several data objects which are
+ communicated as arguments to different commands. The reverse-path is
+ the argument of the MAIL command, the forward-path is the argument of
+ the RCPT command, and the mail data is the argument of the DATA
+ command. These arguments or data objects must be transmitted and
+ held pending the confirmation communicated by the end of mail data
+ indication which finalizes the transaction. The model for this is
+ that distinct buffers are provided to hold the types of data objects,
+ that is, there is a reverse-path buffer, a forward-path buffer, and a
+ mail data buffer. Specific commands cause information to be appended
+ to a specific buffer, or cause one or more buffers to be cleared.
+
+ Several commands (RSET, DATA, QUIT) are specified as not permitting
+ parameters. In the absence of specific extensions offered by the
+ server and accepted by the client, clients MUST NOT send such
+ parameters and servers SHOULD reject commands containing them as
+ having invalid syntax.
+
+4.1.1.1 Extended HELLO (EHLO) or HELLO (HELO)
+
+ These commands are used to identify the SMTP client to the SMTP
+ server. The argument field contains the fully-qualified domain name
+ of the SMTP client if one is available. In situations in which the
+ SMTP client system does not have a meaningful domain name (e.g., when
+ its address is dynamically allocated and no reverse mapping record is
+
+
+
+Klensin Standards Track [Page 29]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ available), the client SHOULD send an address literal (see section
+ 4.1.3), optionally followed by information that will help to identify
+ the client system. y The SMTP server identifies itself to the SMTP
+ client in the connection greeting reply and in the response to this
+ command.
+
+ A client SMTP SHOULD start an SMTP session by issuing the EHLO
+ command. If the SMTP server supports the SMTP service extensions it
+ will give a successful response, a failure response, or an error
+ response. If the SMTP server, in violation of this specification,
+ does not support any SMTP service extensions it will generate an
+ error response. Older client SMTP systems MAY, as discussed above,
+ use HELO (as specified in RFC 821) instead of EHLO, and servers MUST
+ support the HELO command and reply properly to it. In any event, a
+ client MUST issue HELO or EHLO before starting a mail transaction.
+
+ These commands, and a "250 OK" reply to one of them, confirm that
+ both the SMTP client and the SMTP server are in the initial state,
+ that is, there is no transaction in progress and all state tables and
+ buffers are cleared.
+
+ Syntax:
+
+ ehlo = "EHLO" SP Domain CRLF
+ helo = "HELO" SP Domain CRLF
+
+ Normally, the response to EHLO will be a multiline reply. Each line
+ of the response contains a keyword and, optionally, one or more
+ parameters. Following the normal syntax for multiline replies, these
+ keyworks follow the code (250) and a hyphen for all but the last
+ line, and the code and a space for the last line. The syntax for a
+ positive response, using the ABNF notation and terminal symbols of
+ [8], is:
+
+ ehlo-ok-rsp = ( "250" domain [ SP ehlo-greet ] CRLF )
+ / ( "250-" domain [ SP ehlo-greet ] CRLF
+ *( "250-" ehlo-line CRLF )
+ "250" SP ehlo-line CRLF )
+
+ ehlo-greet = 1*(%d0-9 / %d11-12 / %d14-127)
+ ; string of any characters other than CR or LF
+
+ ehlo-line = ehlo-keyword *( SP ehlo-param )
+
+ ehlo-keyword = (ALPHA / DIGIT) *(ALPHA / DIGIT / "-")
+ ; additional syntax of ehlo-params depends on
+ ; ehlo-keyword
+
+
+
+
+Klensin Standards Track [Page 30]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ ehlo-param = 1*(%d33-127)
+ ; any CHAR excluding <SP> and all
+ ; control characters (US-ASCII 0-31 inclusive)
+
+ Although EHLO keywords may be specified in upper, lower, or mixed
+ case, they MUST always be recognized and processed in a case-
+ insensitive manner. This is simply an extension of practices
+ specified in RFC 821 and section 2.4.1.
+
+4.1.1.2 MAIL (MAIL)
+
+ This command is used to initiate a mail transaction in which the mail
+ data is delivered to an SMTP server which may, in turn, deliver it to
+ one or more mailboxes or pass it on to another system (possibly using
+ SMTP). The argument field contains a reverse-path and may contain
+ optional parameters. In general, the MAIL command may be sent only
+ when no mail transaction is in progress, see section 4.1.4.
+
+ The reverse-path consists of the sender mailbox. Historically, that
+ mailbox might optionally have been preceded by a list of hosts, but
+ that behavior is now deprecated (see appendix C). In some types of
+ reporting messages for which a reply is likely to cause a mail loop
+ (for example, mail delivery and nondelivery notifications), the
+ reverse-path may be null (see section 3.7).
+
+ This command clears the reverse-path buffer, the forward-path buffer,
+ and the mail data buffer; and inserts the reverse-path information
+ from this command into the reverse-path buffer.
+
+ If service extensions were negotiated, the MAIL command may also
+ carry parameters associated with a particular service extension.
+
+ Syntax:
+
+ "MAIL FROM:" ("<>" / Reverse-Path)
+ [SP Mail-parameters] CRLF
+
+4.1.1.3 RECIPIENT (RCPT)
+
+ This command is used to identify an individual recipient of the mail
+ data; multiple recipients are specified by multiple use of this
+ command. The argument field contains a forward-path and may contain
+ optional parameters.
+
+ The forward-path normally consists of the required destination
+ mailbox. Sending systems SHOULD not generate the optional list of
+ hosts known as a source route. Receiving systems MUST recognize
+
+
+
+
+Klensin Standards Track [Page 31]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ source route syntax but SHOULD strip off the source route
+ specification and utilize the domain name associated with the mailbox
+ as if the source route had not been provided.
+
+ Similarly, relay hosts SHOULD strip or ignore source routes, and
+ names MUST NOT be copied into the reverse-path. When mail reaches
+ its ultimate destination (the forward-path contains only a
+ destination mailbox), the SMTP server inserts it into the destination
+ mailbox in accordance with its host mail conventions.
+
+ For example, mail received at relay host xyz.com with envelope
+ commands
+
+ MAIL FROM:<userx@y.foo.org>
+ RCPT TO:<@hosta.int,@jkl.org:userc@d.bar.org>
+
+ will normally be sent directly on to host d.bar.org with envelope
+ commands
+
+ MAIL FROM:<userx@y.foo.org>
+ RCPT TO:<userc@d.bar.org>
+
+ As provided in appendix C, xyz.com MAY also choose to relay the
+ message to hosta.int, using the envelope commands
+
+ MAIL FROM:<userx@y.foo.org>
+ RCPT TO:<@hosta.int,@jkl.org:userc@d.bar.org>
+
+ or to jkl.org, using the envelope commands
+
+ MAIL FROM:<userx@y.foo.org>
+ RCPT TO:<@jkl.org:userc@d.bar.org>
+
+ Of course, since hosts are not required to relay mail at all, xyz.com
+ may also reject the message entirely when the RCPT command is
+ received, using a 550 code (since this is a "policy reason").
+
+ If service extensions were negotiated, the RCPT command may also
+ carry parameters associated with a particular service extension
+ offered by the server. The client MUST NOT transmit parameters other
+ than those associated with a service extension offered by the server
+ in its EHLO response.
+
+Syntax:
+ "RCPT TO:" ("<Postmaster@" domain ">" / "<Postmaster>" / Forward-Path)
+ [SP Rcpt-parameters] CRLF
+
+
+
+
+
+Klensin Standards Track [Page 32]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+4.1.1.4 DATA (DATA)
+
+ The receiver normally sends a 354 response to DATA, and then treats
+ the lines (strings ending in <CRLF> sequences, as described in
+ section 2.3.7) following the command as mail data from the sender.
+ This command causes the mail data to be appended to the mail data
+ buffer. The mail data may contain any of the 128 ASCII character
+ codes, although experience has indicated that use of control
+ characters other than SP, HT, CR, and LF may cause problems and
+ SHOULD be avoided when possible.
+
+ The mail data is terminated by a line containing only a period, that
+ is, the character sequence "<CRLF>.<CRLF>" (see section 4.5.2). This
+ is the end of mail data indication. Note that the first <CRLF> of
+ this terminating sequence is also the <CRLF> that ends the final line
+ of the data (message text) or, if there was no data, ends the DATA
+ command itself. An extra <CRLF> MUST NOT be added, as that would
+ cause an empty line to be added to the message. The only exception
+ to this rule would arise if the message body were passed to the
+ originating SMTP-sender with a final "line" that did not end in
+ <CRLF>; in that case, the originating SMTP system MUST either reject
+ the message as invalid or add <CRLF> in order to have the receiving
+ SMTP server recognize the "end of data" condition.
+
+ The custom of accepting lines ending only in <LF>, as a concession to
+ non-conforming behavior on the part of some UNIX systems, has proven
+ to cause more interoperability problems than it solves, and SMTP
+ server systems MUST NOT do this, even in the name of improved
+ robustness. In particular, the sequence "<LF>.<LF>" (bare line
+ feeds, without carriage returns) MUST NOT be treated as equivalent to
+ <CRLF>.<CRLF> as the end of mail data indication.
+
+ Receipt of the end of mail data indication requires the server to
+ process the stored mail transaction information. This processing
+ consumes the information in the reverse-path buffer, the forward-path
+ buffer, and the mail data buffer, and on the completion of this
+ command these buffers are cleared. If the processing is successful,
+ the receiver MUST send an OK reply. If the processing fails the
+ receiver MUST send a failure reply. The SMTP model does not allow
+ for partial failures at this point: either the message is accepted by
+ the server for delivery and a positive response is returned or it is
+ not accepted and a failure reply is returned. In sending a positive
+ completion reply to the end of data indication, the receiver takes
+ full responsibility for the message (see section 6.1). Errors that
+ are diagnosed subsequently MUST be reported in a mail message, as
+ discussed in section 4.4.
+
+
+
+
+
+Klensin Standards Track [Page 33]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ When the SMTP server accepts a message either for relaying or for
+ final delivery, it inserts a trace record (also referred to
+ interchangeably as a "time stamp line" or "Received" line) at the top
+ of the mail data. This trace record indicates the identity of the
+ host that sent the message, the identity of the host that received
+ the message (and is inserting this time stamp), and the date and time
+ the message was received. Relayed messages will have multiple time
+ stamp lines. Details for formation of these lines, including their
+ syntax, is specified in section 4.4.
+
+ Additional discussion about the operation of the DATA command appears
+ in section 3.3.
+
+ Syntax:
+ "DATA" CRLF
+
+4.1.1.5 RESET (RSET)
+
+ This command specifies that the current mail transaction will be
+ aborted. Any stored sender, recipients, and mail data MUST be
+ discarded, and all buffers and state tables cleared. The receiver
+ MUST send a "250 OK" reply to a RSET command with no arguments. A
+ reset command may be issued by the client at any time. It is
+ effectively equivalent to a NOOP (i.e., if has no effect) if issued
+ immediately after EHLO, before EHLO is issued in the session, after
+ an end-of-data indicator has been sent and acknowledged, or
+ immediately before a QUIT. An SMTP server MUST NOT close the
+ connection as the result of receiving a RSET; that action is reserved
+ for QUIT (see section 4.1.1.10).
+
+ Since EHLO implies some additional processing and response by the
+ server, RSET will normally be more efficient than reissuing that
+ command, even though the formal semantics are the same.
+
+ There are circumstances, contrary to the intent of this
+ specification, in which an SMTP server may receive an indication that
+ the underlying TCP connection has been closed or reset. To preserve
+ the robustness of the mail system, SMTP servers SHOULD be prepared
+ for this condition and SHOULD treat it as if a QUIT had been received
+ before the connection disappeared.
+
+ Syntax:
+ "RSET" CRLF
+
+
+
+
+
+
+
+
+Klensin Standards Track [Page 34]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+4.1.1.6 VERIFY (VRFY)
+
+ This command asks the receiver to confirm that the argument
+ identifies a user or mailbox. If it is a user name, information is
+ returned as specified in section 3.5.
+
+ This command has no effect on the reverse-path buffer, the forward-
+ path buffer, or the mail data buffer.
+
+ Syntax:
+ "VRFY" SP String CRLF
+
+4.1.1.7 EXPAND (EXPN)
+
+ This command asks the receiver to confirm that the argument
+ identifies a mailing list, and if so, to return the membership of
+ that list. If the command is successful, a reply is returned
+ containing information as described in section 3.5. This reply will
+ have multiple lines except in the trivial case of a one-member list.
+
+ This command has no effect on the reverse-path buffer, the forward-
+ path buffer, or the mail data buffer and may be issued at any time.
+
+ Syntax:
+ "EXPN" SP String CRLF
+
+4.1.1.8 HELP (HELP)
+
+ This command causes the server to send helpful information to the
+ client. The command MAY take an argument (e.g., any command name)
+ and return more specific information as a response.
+
+ This command has no effect on the reverse-path buffer, the forward-
+ path buffer, or the mail data buffer and may be issued at any time.
+
+ SMTP servers SHOULD support HELP without arguments and MAY support it
+ with arguments.
+
+ Syntax:
+ "HELP" [ SP String ] CRLF
+
+4.1.1.9 NOOP (NOOP)
+
+ This command does not affect any parameters or previously entered
+ commands. It specifies no action other than that the receiver send
+ an OK reply.
+
+
+
+
+
+Klensin Standards Track [Page 35]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ This command has no effect on the reverse-path buffer, the forward-
+ path buffer, or the mail data buffer and may be issued at any time.
+ If a parameter string is specified, servers SHOULD ignore it.
+
+ Syntax:
+ "NOOP" [ SP String ] CRLF
+
+4.1.1.10 QUIT (QUIT)
+
+ This command specifies that the receiver MUST send an OK reply, and
+ then close the transmission channel.
+
+ The receiver MUST NOT intentionally close the transmission channel
+ until it receives and replies to a QUIT command (even if there was an
+ error). The sender MUST NOT intentionally close the transmission
+ channel until it sends a QUIT command and SHOULD wait until it
+ receives the reply (even if there was an error response to a previous
+ command). If the connection is closed prematurely due to violations
+ of the above or system or network failure, the server MUST cancel any
+ pending transaction, but not undo any previously completed
+ transaction, and generally MUST act as if the command or transaction
+ in progress had received a temporary error (i.e., a 4yz response).
+
+ The QUIT command may be issued at any time.
+
+ Syntax:
+ "QUIT" CRLF
+
+4.1.2 Command Argument Syntax
+
+ The syntax of the argument fields of the above commands (using the
+ syntax specified in [8] where applicable) is given below. Some of
+ the productions given below are used only in conjunction with source
+ routes as described in appendix C. Terminals not defined in this
+ document, such as ALPHA, DIGIT, SP, CR, LF, CRLF, are as defined in
+ the "core" syntax [8 (section 6)] or in the message format syntax
+ [32].
+
+ Reverse-path = Path
+ Forward-path = Path
+ Path = "<" [ A-d-l ":" ] Mailbox ">"
+ A-d-l = At-domain *( "," A-d-l )
+ ; Note that this form, the so-called "source route",
+ ; MUST BE accepted, SHOULD NOT be generated, and SHOULD be
+ ; ignored.
+ At-domain = "@" domain
+ Mail-parameters = esmtp-param *(SP esmtp-param)
+ Rcpt-parameters = esmtp-param *(SP esmtp-param)
+
+
+
+Klensin Standards Track [Page 36]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ esmtp-param = esmtp-keyword ["=" esmtp-value]
+ esmtp-keyword = (ALPHA / DIGIT) *(ALPHA / DIGIT / "-")
+ esmtp-value = 1*(%d33-60 / %d62-127)
+ ; any CHAR excluding "=", SP, and control characters
+ Keyword = Ldh-str
+ Argument = Atom
+ Domain = (sub-domain 1*("." sub-domain)) / address-literal
+ sub-domain = Let-dig [Ldh-str]
+
+ address-literal = "[" IPv4-address-literal /
+ IPv6-address-literal /
+ General-address-literal "]"
+ ; See section 4.1.3
+
+ Mailbox = Local-part "@" Domain
+
+ Local-part = Dot-string / Quoted-string
+ ; MAY be case-sensitive
+
+ Dot-string = Atom *("." Atom)
+
+ Atom = 1*atext
+
+ Quoted-string = DQUOTE *qcontent DQUOTE
+
+ String = Atom / Quoted-string
+
+ While the above definition for Local-part is relatively permissive,
+ for maximum interoperability, a host that expects to receive mail
+ SHOULD avoid defining mailboxes where the Local-part requires (or
+ uses) the Quoted-string form or where the Local-part is case-
+ sensitive. For any purposes that require generating or comparing
+ Local-parts (e.g., to specific mailbox names), all quoted forms MUST
+ be treated as equivalent and the sending system SHOULD transmit the
+ form that uses the minimum quoting possible.
+
+ Systems MUST NOT define mailboxes in such a way as to require the use
+ in SMTP of non-ASCII characters (octets with the high order bit set
+ to one) or ASCII "control characters" (decimal value 0-31 and 127).
+ These characters MUST NOT be used in MAIL or RCPT commands or other
+ commands that require mailbox names.
+
+ Note that the backslash, "\", is a quote character, which is used to
+ indicate that the next character is to be used literally (instead of
+ its normal interpretation). For example, "Joe\,Smith" indicates a
+ single nine character user field with the comma being the fourth
+ character of the field.
+
+
+
+
+Klensin Standards Track [Page 37]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ To promote interoperability and consistent with long-standing
+ guidance about conservative use of the DNS in naming and applications
+ (e.g., see section 2.3.1 of the base DNS document, RFC1035 [22]),
+ characters outside the set of alphas, digits, and hyphen MUST NOT
+ appear in domain name labels for SMTP clients or servers. In
+ particular, the underscore character is not permitted. SMTP servers
+ that receive a command in which invalid character codes have been
+ employed, and for which there are no other reasons for rejection,
+ MUST reject that command with a 501 response.
+
+4.1.3 Address Literals
+
+ Sometimes a host is not known to the domain name system and
+ communication (and, in particular, communication to report and repair
+ the error) is blocked. To bypass this barrier a special literal form
+ of the address is allowed as an alternative to a domain name. For
+ IPv4 addresses, this form uses four small decimal integers separated
+ by dots and enclosed by brackets such as [123.255.37.2], which
+ indicates an (IPv4) Internet Address in sequence-of-octets form. For
+ IPv6 and other forms of addressing that might eventually be
+ standardized, the form consists of a standardized "tag" that
+ identifies the address syntax, a colon, and the address itself, in a
+ format specified as part of the IPv6 standards [17].
+
+ Specifically:
+
+ IPv4-address-literal = Snum 3("." Snum)
+ IPv6-address-literal = "IPv6:" IPv6-addr
+ General-address-literal = Standardized-tag ":" 1*dcontent
+ Standardized-tag = Ldh-str
+ ; MUST be specified in a standards-track RFC
+ ; and registered with IANA
+
+ Snum = 1*3DIGIT ; representing a decimal integer
+ ; value in the range 0 through 255
+ Let-dig = ALPHA / DIGIT
+ Ldh-str = *( ALPHA / DIGIT / "-" ) Let-dig
+
+ IPv6-addr = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp
+ IPv6-hex = 1*4HEXDIG
+ IPv6-full = IPv6-hex 7(":" IPv6-hex)
+ IPv6-comp = [IPv6-hex *5(":" IPv6-hex)] "::" [IPv6-hex *5(":"
+ IPv6-hex)]
+ ; The "::" represents at least 2 16-bit groups of zeros
+ ; No more than 6 groups in addition to the "::" may be
+ ; present
+ IPv6v4-full = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal
+ IPv6v4-comp = [IPv6-hex *3(":" IPv6-hex)] "::"
+
+
+
+Klensin Standards Track [Page 38]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ [IPv6-hex *3(":" IPv6-hex) ":"] IPv4-address-literal
+ ; The "::" represents at least 2 16-bit groups of zeros
+ ; No more than 4 groups in addition to the "::" and
+ ; IPv4-address-literal may be present
+
+4.1.4 Order of Commands
+
+ There are restrictions on the order in which these commands may be
+ used.
+
+ A session that will contain mail transactions MUST first be
+ initialized by the use of the EHLO command. An SMTP server SHOULD
+ accept commands for non-mail transactions (e.g., VRFY or EXPN)
+ without this initialization.
+
+ An EHLO command MAY be issued by a client later in the session. If
+ it is issued after the session begins, the SMTP server MUST clear all
+ buffers and reset the state exactly as if a RSET command had been
+ issued. In other words, the sequence of RSET followed immediately by
+ EHLO is redundant, but not harmful other than in the performance cost
+ of executing unnecessary commands.
+
+ If the EHLO command is not acceptable to the SMTP server, 501, 500,
+ or 502 failure replies MUST be returned as appropriate. The SMTP
+ server MUST stay in the same state after transmitting these replies
+ that it was in before the EHLO was received.
+
+ The SMTP client MUST, if possible, ensure that the domain parameter
+ to the EHLO command is a valid principal host name (not a CNAME or MX
+ name) for its host. If this is not possible (e.g., when the client's
+ address is dynamically assigned and the client does not have an
+ obvious name), an address literal SHOULD be substituted for the
+ domain name and supplemental information provided that will assist in
+ identifying the client.
+
+ An SMTP server MAY verify that the domain name parameter in the EHLO
+ command actually corresponds to the IP address of the client.
+ However, the server MUST NOT refuse to accept a message for this
+ reason if the verification fails: the information about verification
+ failure is for logging and tracing only.
+
+ The NOOP, HELP, EXPN, VRFY, and RSET commands can be used at any time
+ during a session, or without previously initializing a session. SMTP
+ servers SHOULD process these normally (that is, not return a 503
+ code) even if no EHLO command has yet been received; clients SHOULD
+ open a session with EHLO before sending these commands.
+
+
+
+
+
+Klensin Standards Track [Page 39]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ If these rules are followed, the example in RFC 821 that shows "550
+ access denied to you" in response to an EXPN command is incorrect
+ unless an EHLO command precedes the EXPN or the denial of access is
+ based on the client's IP address or other authentication or
+ authorization-determining mechanisms.
+
+ The MAIL command (or the obsolete SEND, SOML, or SAML commands)
+ begins a mail transaction. Once started, a mail transaction consists
+ of a transaction beginning command, one or more RCPT commands, and a
+ DATA command, in that order. A mail transaction may be aborted by
+ the RSET (or a new EHLO) command. There may be zero or more
+ transactions in a session. MAIL (or SEND, SOML, or SAML) MUST NOT be
+ sent if a mail transaction is already open, i.e., it should be sent
+ only if no mail transaction had been started in the session, or it
+ the previous one successfully concluded with a successful DATA
+ command, or if the previous one was aborted with a RSET.
+
+ If the transaction beginning command argument is not acceptable, a
+ 501 failure reply MUST be returned and the SMTP server MUST stay in
+ the same state. If the commands in a transaction are out of order to
+ the degree that they cannot be processed by the server, a 503 failure
+ reply MUST be returned and the SMTP server MUST stay in the same
+ state.
+
+ The last command in a session MUST be the QUIT command. The QUIT
+ command cannot be used at any other time in a session, but SHOULD be
+ used by the client SMTP to request connection closure, even when no
+ session opening command was sent and accepted.
+
+4.1.5 Private-use Commands
+
+ As specified in section 2.2.2, commands starting in "X" may be used
+ by bilateral agreement between the client (sending) and server
+ (receiving) SMTP agents. An SMTP server that does not recognize such
+ a command is expected to reply with "500 Command not recognized". An
+ extended SMTP server MAY list the feature names associated with these
+ private commands in the response to the EHLO command.
+
+ Commands sent or accepted by SMTP systems that do not start with "X"
+ MUST conform to the requirements of section 2.2.2.
+
+4.2 SMTP Replies
+
+ Replies to SMTP commands serve to ensure the synchronization of
+ requests and actions in the process of mail transfer and to guarantee
+ that the SMTP client always knows the state of the SMTP server.
+ Every command MUST generate exactly one reply.
+
+
+
+
+Klensin Standards Track [Page 40]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ The details of the command-reply sequence are described in section
+ 4.3.
+
+ An SMTP reply consists of a three digit number (transmitted as three
+ numeric characters) followed by some text unless specified otherwise
+ in this document. The number is for use by automata to determine
+ what state to enter next; the text is for the human user. The three
+ digits contain enough encoded information that the SMTP client need
+ not examine the text and may either discard it or pass it on to the
+ user, as appropriate. Exceptions are as noted elsewhere in this
+ document. In particular, the 220, 221, 251, 421, and 551 reply codes
+ are associated with message text that must be parsed and interpreted
+ by machines. In the general case, the text may be receiver dependent
+ and context dependent, so there are likely to be varying texts for
+ each reply code. A discussion of the theory of reply codes is given
+ in section 4.2.1. Formally, a reply is defined to be the sequence: a
+ three-digit code, <SP>, one line of text, and <CRLF>, or a multiline
+ reply (as defined in section 4.2.1). Since, in violation of this
+ specification, the text is sometimes not sent, clients which do not
+ receive it SHOULD be prepared to process the code alone (with or
+ without a trailing space character). Only the EHLO, EXPN, and HELP
+ commands are expected to result in multiline replies in normal
+ circumstances, however, multiline replies are allowed for any
+ command.
+
+ In ABNF, server responses are:
+
+ Greeting = "220 " Domain [ SP text ] CRLF
+ Reply-line = Reply-code [ SP text ] CRLF
+
+ where "Greeting" appears only in the 220 response that announces that
+ the server is opening its part of the connection.
+
+ An SMTP server SHOULD send only the reply codes listed in this
+ document. An SMTP server SHOULD use the text shown in the examples
+ whenever appropriate.
+
+ An SMTP client MUST determine its actions only by the reply code, not
+ by the text (except for the "change of address" 251 and 551 and, if
+ necessary, 220, 221, and 421 replies); in the general case, any text,
+ including no text at all (although senders SHOULD NOT send bare
+ codes), MUST be acceptable. The space (blank) following the reply
+ code is considered part of the text. Whenever possible, a receiver-
+ SMTP SHOULD test the first digit (severity indication) of the reply
+ code.
+
+
+
+
+
+
+Klensin Standards Track [Page 41]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ The list of codes that appears below MUST NOT be construed as
+ permanent. While the addition of new codes should be a rare and
+ significant activity, with supplemental information in the textual
+ part of the response being preferred, new codes may be added as the
+ result of new Standards or Standards-track specifications.
+ Consequently, a sender-SMTP MUST be prepared to handle codes not
+ specified in this document and MUST do so by interpreting the first
+ digit only.
+
+4.2.1 Reply Code Severities and Theory
+
+ The three digits of the reply each have a special significance. The
+ first digit denotes whether the response is good, bad or incomplete.
+ An unsophisticated SMTP client, or one that receives an unexpected
+ code, will be able to determine its next action (proceed as planned,
+ redo, retrench, etc.) by examining this first digit. An SMTP client
+ that wants to know approximately what kind of error occurred (e.g.,
+ mail system error, command syntax error) may examine the second
+ digit. The third digit and any supplemental information that may be
+ present is reserved for the finest gradation of information.
+
+ There are five values for the first digit of the reply code:
+
+ 1yz Positive Preliminary reply
+ The command has been accepted, but the requested action is being
+ held in abeyance, pending confirmation of the information in this
+ reply. The SMTP client should send another command specifying
+ whether to continue or abort the action. Note: unextended SMTP
+ does not have any commands that allow this type of reply, and so
+ does not have continue or abort commands.
+
+ 2yz Positive Completion reply
+ The requested action has been successfully completed. A new
+ request may be initiated.
+
+ 3yz Positive Intermediate reply
+ The command has been accepted, but the requested action is being
+ held in abeyance, pending receipt of further information. The
+ SMTP client should send another command specifying this
+ information. This reply is used in command sequence groups (i.e.,
+ in DATA).
+
+ 4yz Transient Negative Completion reply
+ The command was not accepted, and the requested action did not
+ occur. However, the error condition is temporary and the action
+ may be requested again. The sender should return to the beginning
+ of the command sequence (if any). It is difficult to assign a
+ meaning to "transient" when two different sites (receiver- and
+
+
+
+Klensin Standards Track [Page 42]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ sender-SMTP agents) must agree on the interpretation. Each reply
+ in this category might have a different time value, but the SMTP
+ client is encouraged to try again. A rule of thumb to determine
+ whether a reply fits into the 4yz or the 5yz category (see below)
+ is that replies are 4yz if they can be successful if repeated
+ without any change in command form or in properties of the sender
+ or receiver (that is, the command is repeated identically and the
+ receiver does not put up a new implementation.)
+
+ 5yz Permanent Negative Completion reply
+ The command was not accepted and the requested action did not
+ occur. The SMTP client is discouraged from repeating the exact
+ request (in the same sequence). Even some "permanent" error
+ conditions can be corrected, so the human user may want to direct
+ the SMTP client to reinitiate the command sequence by direct
+ action at some point in the future (e.g., after the spelling has
+ been changed, or the user has altered the account status).
+
+ The second digit encodes responses in specific categories:
+
+ x0z Syntax: These replies refer to syntax errors, syntactically
+ correct commands that do not fit any functional category, and
+ unimplemented or superfluous commands.
+
+ x1z Information: These are replies to requests for information,
+ such as status or help.
+
+ x2z Connections: These are replies referring to the transmission
+ channel.
+
+ x3z Unspecified.
+
+ x4z Unspecified.
+
+ x5z Mail system: These replies indicate the status of the receiver
+ mail system vis-a-vis the requested transfer or other mail system
+ action.
+
+ The third digit gives a finer gradation of meaning in each category
+ specified by the second digit. The list of replies illustrates this.
+ Each reply text is recommended rather than mandatory, and may even
+ change according to the command with which it is associated. On the
+ other hand, the reply codes must strictly follow the specifications
+ in this section. Receiver implementations should not invent new
+ codes for slightly different situations from the ones described here,
+ but rather adapt codes already defined.
+
+
+
+
+
+Klensin Standards Track [Page 43]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ For example, a command such as NOOP, whose successful execution does
+ not offer the SMTP client any new information, will return a 250
+ reply. The reply is 502 when the command requests an unimplemented
+ non-site-specific action. A refinement of that is the 504 reply for
+ a command that is implemented, but that requests an unimplemented
+ parameter.
+
+ The reply text may be longer than a single line; in these cases the
+ complete text must be marked so the SMTP client knows when it can
+ stop reading the reply. This requires a special format to indicate a
+ multiple line reply.
+
+ The format for multiline replies requires that every line, except the
+ last, begin with the reply code, followed immediately by a hyphen,
+ "-" (also known as minus), followed by text. The last line will
+ begin with the reply code, followed immediately by <SP>, optionally
+ some text, and <CRLF>. As noted above, servers SHOULD send the <SP>
+ if subsequent text is not sent, but clients MUST be prepared for it
+ to be omitted.
+
+ For example:
+
+ 123-First line
+ 123-Second line
+ 123-234 text beginning with numbers
+ 123 The last line
+
+ In many cases the SMTP client then simply needs to search for a line
+ beginning with the reply code followed by <SP> or <CRLF> and ignore
+ all preceding lines. In a few cases, there is important data for the
+ client in the reply "text". The client will be able to identify
+ these cases from the current context.
+
+4.2.2 Reply Codes by Function Groups
+
+ 500 Syntax error, command unrecognized
+ (This may include errors such as command line too long)
+ 501 Syntax error in parameters or arguments
+ 502 Command not implemented (see section 4.2.4)
+ 503 Bad sequence of commands
+ 504 Command parameter not implemented
+
+ 211 System status, or system help reply
+ 214 Help message
+ (Information on how to use the receiver or the meaning of a
+ particular non-standard command; this reply is useful only
+ to the human user)
+
+
+
+
+Klensin Standards Track [Page 44]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ 220 <domain> Service ready
+ 221 <domain> Service closing transmission channel
+ 421 <domain> Service not available, closing transmission channel
+ (This may be a reply to any command if the service knows it
+ must shut down)
+
+ 250 Requested mail action okay, completed
+ 251 User not local; will forward to <forward-path>
+ (See section 3.4)
+ 252 Cannot VRFY user, but will accept message and attempt
+ delivery
+ (See section 3.5.3)
+ 450 Requested mail action not taken: mailbox unavailable
+ (e.g., mailbox busy)
+ 550 Requested action not taken: mailbox unavailable
+ (e.g., mailbox not found, no access, or command rejected
+ for policy reasons)
+ 451 Requested action aborted: error in processing
+ 551 User not local; please try <forward-path>
+ (See section 3.4)
+ 452 Requested action not taken: insufficient system storage
+ 552 Requested mail action aborted: exceeded storage allocation
+ 553 Requested action not taken: mailbox name not allowed
+ (e.g., mailbox syntax incorrect)
+ 354 Start mail input; end with <CRLF>.<CRLF>
+ 554 Transaction failed (Or, in the case of a connection-opening
+ response, "No SMTP service here")
+
+4.2.3 Reply Codes in Numeric Order
+
+ 211 System status, or system help reply
+ 214 Help message
+ (Information on how to use the receiver or the meaning of a
+ particular non-standard command; this reply is useful only
+ to the human user)
+ 220 <domain> Service ready
+ 221 <domain> Service closing transmission channel
+ 250 Requested mail action okay, completed
+ 251 User not local; will forward to <forward-path>
+ (See section 3.4)
+ 252 Cannot VRFY user, but will accept message and attempt
+ delivery
+ (See section 3.5.3)
+
+ 354 Start mail input; end with <CRLF>.<CRLF>
+
+
+
+
+
+
+Klensin Standards Track [Page 45]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ 421 <domain> Service not available, closing transmission channel
+ (This may be a reply to any command if the service knows it
+ must shut down)
+ 450 Requested mail action not taken: mailbox unavailable
+ (e.g., mailbox busy)
+ 451 Requested action aborted: local error in processing
+ 452 Requested action not taken: insufficient system storage
+ 500 Syntax error, command unrecognized
+ (This may include errors such as command line too long)
+ 501 Syntax error in parameters or arguments
+ 502 Command not implemented (see section 4.2.4)
+ 503 Bad sequence of commands
+ 504 Command parameter not implemented
+ 550 Requested action not taken: mailbox unavailable
+ (e.g., mailbox not found, no access, or command rejected
+ for policy reasons)
+ 551 User not local; please try <forward-path>
+ (See section 3.4)
+ 552 Requested mail action aborted: exceeded storage allocation
+ 553 Requested action not taken: mailbox name not allowed
+ (e.g., mailbox syntax incorrect)
+ 554 Transaction failed (Or, in the case of a connection-opening
+ response, "No SMTP service here")
+
+4.2.4 Reply Code 502
+
+ Questions have been raised as to when reply code 502 (Command not
+ implemented) SHOULD be returned in preference to other codes. 502
+ SHOULD be used when the command is actually recognized by the SMTP
+ server, but not implemented. If the command is not recognized, code
+ 500 SHOULD be returned. Extended SMTP systems MUST NOT list
+ capabilities in response to EHLO for which they will return 502 (or
+ 500) replies.
+
+4.2.5 Reply Codes After DATA and the Subsequent <CRLF>.<CRLF>
+
+ When an SMTP server returns a positive completion status (2yz code)
+ after the DATA command is completed with <CRLF>.<CRLF>, it accepts
+ responsibility for:
+
+ - delivering the message (if the recipient mailbox exists), or
+
+ - if attempts to deliver the message fail due to transient
+ conditions, retrying delivery some reasonable number of times at
+ intervals as specified in section 4.5.4.
+
+
+
+
+
+
+Klensin Standards Track [Page 46]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ - if attempts to deliver the message fail due to permanent
+ conditions, or if repeated attempts to deliver the message fail
+ due to transient conditions, returning appropriate notification to
+ the sender of the original message (using the address in the SMTP
+ MAIL command).
+
+ When an SMTP server returns a permanent error status (5yz) code after
+ the DATA command is completed with <CRLF>.<CRLF>, it MUST NOT make
+ any subsequent attempt to deliver that message. The SMTP client
+ retains responsibility for delivery of that message and may either
+ return it to the user or requeue it for a subsequent attempt (see
+ section 4.5.4.1).
+
+ The user who originated the message SHOULD be able to interpret the
+ return of a transient failure status (by mail message or otherwise)
+ as a non-delivery indication, just as a permanent failure would be
+ interpreted. I.e., if the client SMTP successfully handles these
+ conditions, the user will not receive such a reply.
+
+ When an SMTP server returns a permanent error status (5yz) code after
+ the DATA command is completely with <CRLF>.<CRLF>, it MUST NOT make
+ any subsequent attempt to deliver the message. As with temporary
+ error status codes, the SMTP client retains responsibility for the
+ message, but SHOULD not again attempt delivery to the same server
+ without user review and intervention of the message.
+
+4.3 Sequencing of Commands and Replies
+
+4.3.1 Sequencing Overview
+
+ The communication between the sender and receiver is an alternating
+ dialogue, controlled by the sender. As such, the sender issues a
+ command and the receiver responds with a reply. Unless other
+ arrangements are negotiated through service extensions, the sender
+ MUST wait for this response before sending further commands.
+
+ One important reply is the connection greeting. Normally, a receiver
+ will send a 220 "Service ready" reply when the connection is
+ completed. The sender SHOULD wait for this greeting message before
+ sending any commands.
+
+ Note: all the greeting-type replies have the official name (the
+ fully-qualified primary domain name) of the server host as the first
+ word following the reply code. Sometimes the host will have no
+ meaningful name. See 4.1.3 for a discussion of alternatives in these
+ situations.
+
+
+
+
+
+Klensin Standards Track [Page 47]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ For example,
+
+ 220 ISIF.USC.EDU Service ready
+ or
+ 220 mail.foo.com SuperSMTP v 6.1.2 Service ready
+ or
+ 220 [10.0.0.1] Clueless host service ready
+
+ The table below lists alternative success and failure replies for
+ each command. These SHOULD be strictly adhered to: a receiver may
+ substitute text in the replies, but the meaning and action implied by
+ the code numbers and by the specific command reply sequence cannot be
+ altered.
+
+4.3.2 Command-Reply Sequences
+
+ Each command is listed with its usual possible replies. The prefixes
+ used before the possible replies are "I" for intermediate, "S" for
+ success, and "E" for error. Since some servers may generate other
+ replies under special circumstances, and to allow for future
+ extension, SMTP clients SHOULD, when possible, interpret only the
+ first digit of the reply and MUST be prepared to deal with
+ unrecognized reply codes by interpreting the first digit only.
+ Unless extended using the mechanisms described in section 2.2, SMTP
+ servers MUST NOT transmit reply codes to an SMTP client that are
+ other than three digits or that do not start in a digit between 2 and
+ 5 inclusive.
+
+ These sequencing rules and, in principle, the codes themselves, can
+ be extended or modified by SMTP extensions offered by the server and
+ accepted (requested) by the client.
+
+ In addition to the codes listed below, any SMTP command can return
+ any of the following codes if the corresponding unusual circumstances
+ are encountered:
+
+ 500 For the "command line too long" case or if the command name was
+ not recognized. Note that producing a "command not recognized"
+ error in response to the required subset of these commands is a
+ violation of this specification.
+
+ 501 Syntax error in command or arguments. In order to provide for
+ future extensions, commands that are specified in this document as
+ not accepting arguments (DATA, RSET, QUIT) SHOULD return a 501
+ message if arguments are supplied in the absence of EHLO-
+ advertised extensions.
+
+ 421 Service shutting down and closing transmission channel
+
+
+
+Klensin Standards Track [Page 48]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ Specific sequences are:
+
+ CONNECTION ESTABLISHMENT
+ S: 220
+ E: 554
+ EHLO or HELO
+ S: 250
+ E: 504, 550
+ MAIL
+ S: 250
+ E: 552, 451, 452, 550, 553, 503
+ RCPT
+ S: 250, 251 (but see section 3.4 for discussion of 251 and 551)
+ E: 550, 551, 552, 553, 450, 451, 452, 503, 550
+ DATA
+ I: 354 -> data -> S: 250
+ E: 552, 554, 451, 452
+ E: 451, 554, 503
+ RSET
+ S: 250
+ VRFY
+ S: 250, 251, 252
+ E: 550, 551, 553, 502, 504
+ EXPN
+ S: 250, 252
+ E: 550, 500, 502, 504
+ HELP
+ S: 211, 214
+ E: 502, 504
+ NOOP
+ S: 250
+ QUIT
+ S: 221
+
+4.4 Trace Information
+
+ When an SMTP server receives a message for delivery or further
+ processing, it MUST insert trace ("time stamp" or "Received")
+ information at the beginning of the message content, as discussed in
+ section 4.1.1.4.
+
+ This line MUST be structured as follows:
+
+ - The FROM field, which MUST be supplied in an SMTP environment,
+ SHOULD contain both (1) the name of the source host as presented
+ in the EHLO command and (2) an address literal containing the IP
+ address of the source, determined from the TCP connection.
+
+
+
+
+Klensin Standards Track [Page 49]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ - The ID field MAY contain an "@" as suggested in RFC 822, but this
+ is not required.
+
+ - The FOR field MAY contain a list of <path> entries when multiple
+ RCPT commands have been given. This may raise some security
+ issues and is usually not desirable; see section 7.2.
+
+ An Internet mail program MUST NOT change a Received: line that was
+ previously added to the message header. SMTP servers MUST prepend
+ Received lines to messages; they MUST NOT change the order of
+ existing lines or insert Received lines in any other location.
+
+ As the Internet grows, comparability of Received fields is important
+ for detecting problems, especially slow relays. SMTP servers that
+ create Received fields SHOULD use explicit offsets in the dates
+ (e.g., -0800), rather than time zone names of any type. Local time
+ (with an offset) is preferred to UT when feasible. This formulation
+ allows slightly more information about local circumstances to be
+ specified. If UT is needed, the receiver need merely do some simple
+ arithmetic to convert the values. Use of UT loses information about
+ the time zone-location of the server. If it is desired to supply a
+ time zone name, it SHOULD be included in a comment.
+
+ When the delivery SMTP server makes the "final delivery" of a
+ message, it inserts a return-path line at the beginning of the mail
+ data. This use of return-path is required; mail systems MUST support
+ it. The return-path line preserves the information in the <reverse-
+ path> from the MAIL command. Here, final delivery means the message
+ has left the SMTP environment. Normally, this would mean it had been
+ delivered to the destination user or an associated mail drop, but in
+ some cases it may be further processed and transmitted by another
+ mail system.
+
+ It is possible for the mailbox in the return path to be different
+ from the actual sender's mailbox, for example, if error responses are
+ to be delivered to a special error handling mailbox rather than to
+ the message sender. When mailing lists are involved, this
+ arrangement is common and useful as a means of directing errors to
+ the list maintainer rather than the message originator.
+
+ The text above implies that the final mail data will begin with a
+ return path line, followed by one or more time stamp lines. These
+ lines will be followed by the mail data headers and body [32].
+
+ It is sometimes difficult for an SMTP server to determine whether or
+ not it is making final delivery since forwarding or other operations
+ may occur after the message is accepted for delivery. Consequently,
+
+
+
+
+Klensin Standards Track [Page 50]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ any further (forwarding, gateway, or relay) systems MAY remove the
+ return path and rebuild the MAIL command as needed to ensure that
+ exactly one such line appears in a delivered message.
+
+ A message-originating SMTP system SHOULD NOT send a message that
+ already contains a Return-path header. SMTP servers performing a
+ relay function MUST NOT inspect the message data, and especially not
+ to the extent needed to determine if Return-path headers are present.
+ SMTP servers making final delivery MAY remove Return-path headers
+ before adding their own.
+
+ The primary purpose of the Return-path is to designate the address to
+ which messages indicating non-delivery or other mail system failures
+ are to be sent. For this to be unambiguous, exactly one return path
+ SHOULD be present when the message is delivered. Systems using RFC
+ 822 syntax with non-SMTP transports SHOULD designate an unambiguous
+ address, associated with the transport envelope, to which error
+ reports (e.g., non-delivery messages) should be sent.
+
+ Historical note: Text in RFC 822 that appears to contradict the use
+ of the Return-path header (or the envelope reverse path address from
+ the MAIL command) as the destination for error messages is not
+ applicable on the Internet. The reverse path address (as copied into
+ the Return-path) MUST be used as the target of any mail containing
+ delivery error messages.
+
+ In particular:
+
+ - a gateway from SMTP->elsewhere SHOULD insert a return-path header,
+ unless it is known that the "elsewhere" transport also uses
+ Internet domain addresses and maintains the envelope sender
+ address separately.
+
+ - a gateway from elsewhere->SMTP SHOULD delete any return-path
+ header present in the message, and either copy that information to
+ the SMTP envelope or combine it with information present in the
+ envelope of the other transport system to construct the reverse
+ path argument to the MAIL command in the SMTP envelope.
+
+ The server must give special treatment to cases in which the
+ processing following the end of mail data indication is only
+ partially successful. This could happen if, after accepting several
+ recipients and the mail data, the SMTP server finds that the mail
+ data could be successfully delivered to some, but not all, of the
+ recipients. In such cases, the response to the DATA command MUST be
+ an OK reply. However, the SMTP server MUST compose and send an
+ "undeliverable mail" notification message to the originator of the
+ message.
+
+
+
+Klensin Standards Track [Page 51]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ A single notification listing all of the failed recipients or
+ separate notification messages MUST be sent for each failed
+ recipient. For economy of processing by the sender, the former is
+ preferred when possible. All undeliverable mail notification
+ messages are sent using the MAIL command (even if they result from
+ processing the obsolete SEND, SOML, or SAML commands) and use a null
+ return path as discussed in section 3.7.
+
+ The time stamp line and the return path line are formally defined as
+ follows:
+
+Return-path-line = "Return-Path:" FWS Reverse-path <CRLF>
+
+Time-stamp-line = "Received:" FWS Stamp <CRLF>
+
+Stamp = From-domain By-domain Opt-info ";" FWS date-time
+
+ ; where "date-time" is as defined in [32]
+ ; but the "obs-" forms, especially two-digit
+ ; years, are prohibited in SMTP and MUST NOT be used.
+
+From-domain = "FROM" FWS Extended-Domain CFWS
+
+By-domain = "BY" FWS Extended-Domain CFWS
+
+Extended-Domain = Domain /
+ ( Domain FWS "(" TCP-info ")" ) /
+ ( Address-literal FWS "(" TCP-info ")" )
+
+TCP-info = Address-literal / ( Domain FWS Address-literal )
+ ; Information derived by server from TCP connection
+ ; not client EHLO.
+
+Opt-info = [Via] [With] [ID] [For]
+
+Via = "VIA" FWS Link CFWS
+
+With = "WITH" FWS Protocol CFWS
+
+ID = "ID" FWS String / msg-id CFWS
+
+For = "FOR" FWS 1*( Path / Mailbox ) CFWS
+
+Link = "TCP" / Addtl-Link
+Addtl-Link = Atom
+ ; Additional standard names for links are registered with the
+ ; Internet Assigned Numbers Authority (IANA). "Via" is
+ ; primarily of value with non-Internet transports. SMTP
+
+
+
+Klensin Standards Track [Page 52]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ ; servers SHOULD NOT use unregistered names.
+Protocol = "ESMTP" / "SMTP" / Attdl-Protocol
+Attdl-Protocol = Atom
+ ; Additional standard names for protocols are registered with the
+ ; Internet Assigned Numbers Authority (IANA). SMTP servers
+ ; SHOULD NOT use unregistered names.
+
+4.5 Additional Implementation Issues
+
+4.5.1 Minimum Implementation
+
+ In order to make SMTP workable, the following minimum implementation
+ is required for all receivers. The following commands MUST be
+ supported to conform to this specification:
+
+ EHLO
+ HELO
+ MAIL
+ RCPT
+ DATA
+ RSET
+ NOOP
+ QUIT
+ VRFY
+
+ Any system that includes an SMTP server supporting mail relaying or
+ delivery MUST support the reserved mailbox "postmaster" as a case-
+ insensitive local name. This postmaster address is not strictly
+ necessary if the server always returns 554 on connection opening (as
+ described in section 3.1). The requirement to accept mail for
+ postmaster implies that RCPT commands which specify a mailbox for
+ postmaster at any of the domains for which the SMTP server provides
+ mail service, as well as the special case of "RCPT TO:<Postmaster>"
+ (with no domain specification), MUST be supported.
+
+ SMTP systems are expected to make every reasonable effort to accept
+ mail directed to Postmaster from any other system on the Internet.
+ In extreme cases --such as to contain a denial of service attack or
+ other breach of security-- an SMTP server may block mail directed to
+ Postmaster. However, such arrangements SHOULD be narrowly tailored
+ so as to avoid blocking messages which are not part of such attacks.
+
+4.5.2 Transparency
+
+ Without some provision for data transparency, the character sequence
+ "<CRLF>.<CRLF>" ends the mail text and cannot be sent by the user.
+ In general, users are not aware of such "forbidden" sequences. To
+
+
+
+
+Klensin Standards Track [Page 53]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ allow all user composed text to be transmitted transparently, the
+ following procedures are used:
+
+ - Before sending a line of mail text, the SMTP client checks the
+ first character of the line. If it is a period, one additional
+ period is inserted at the beginning of the line.
+
+ - When a line of mail text is received by the SMTP server, it checks
+ the line. If the line is composed of a single period, it is
+ treated as the end of mail indicator. If the first character is a
+ period and there are other characters on the line, the first
+ character is deleted.
+
+ The mail data may contain any of the 128 ASCII characters. All
+ characters are to be delivered to the recipient's mailbox, including
+ spaces, vertical and horizontal tabs, and other control characters.
+ If the transmission channel provides an 8-bit byte (octet) data
+ stream, the 7-bit ASCII codes are transmitted right justified in the
+ octets, with the high order bits cleared to zero. See 3.7 for
+ special treatment of these conditions in SMTP systems serving a relay
+ function.
+
+ In some systems it may be necessary to transform the data as it is
+ received and stored. This may be necessary for hosts that use a
+ different character set than ASCII as their local character set, that
+ store data in records rather than strings, or which use special
+ character sequences as delimiters inside mailboxes. If such
+ transformations are necessary, they MUST be reversible, especially if
+ they are applied to mail being relayed.
+
+4.5.3 Sizes and Timeouts
+
+4.5.3.1 Size limits and minimums
+
+ There are several objects that have required minimum/maximum sizes.
+ Every implementation MUST be able to receive objects of at least
+ these sizes. Objects larger than these sizes SHOULD be avoided when
+ possible. However, some Internet mail constructs such as encoded
+ X.400 addresses [16] will often require larger objects: clients MAY
+ attempt to transmit these, but MUST be prepared for a server to
+ reject them if they cannot be handled by it. To the maximum extent
+ possible, implementation techniques which impose no limits on the
+ length of these objects should be used.
+
+ local-part
+ The maximum total length of a user name or other local-part is 64
+ characters.
+
+
+
+
+Klensin Standards Track [Page 54]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ domain
+ The maximum total length of a domain name or number is 255
+ characters.
+
+ path
+ The maximum total length of a reverse-path or forward-path is 256
+ characters (including the punctuation and element separators).
+
+ command line
+ The maximum total length of a command line including the command
+ word and the <CRLF> is 512 characters. SMTP extensions may be
+ used to increase this limit.
+
+ reply line
+ The maximum total length of a reply line including the reply code
+ and the <CRLF> is 512 characters. More information may be
+ conveyed through multiple-line replies.
+
+ text line
+ The maximum total length of a text line including the <CRLF> is
+ 1000 characters (not counting the leading dot duplicated for
+ transparency). This number may be increased by the use of SMTP
+ Service Extensions.
+
+ message content
+ The maximum total length of a message content (including any
+ message headers as well as the message body) MUST BE at least 64K
+ octets. Since the introduction of Internet standards for
+ multimedia mail [12], message lengths on the Internet have grown
+ dramatically, and message size restrictions should be avoided if
+ at all possible. SMTP server systems that must impose
+ restrictions SHOULD implement the "SIZE" service extension [18],
+ and SMTP client systems that will send large messages SHOULD
+ utilize it when possible.
+
+ recipients buffer
+ The minimum total number of recipients that must be buffered is
+ 100 recipients. Rejection of messages (for excessive recipients)
+ with fewer than 100 RCPT commands is a violation of this
+ specification. The general principle that relaying SMTP servers
+ MUST NOT, and delivery SMTP servers SHOULD NOT, perform validation
+ tests on message headers suggests that rejecting a message based
+ on the total number of recipients shown in header fields is to be
+ discouraged. A server which imposes a limit on the number of
+ recipients MUST behave in an orderly fashion, such as to reject
+ additional addresses over its limit rather than silently
+ discarding addresses previously accepted. A client that needs to
+
+
+
+
+Klensin Standards Track [Page 55]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ deliver a message containing over 100 RCPT commands SHOULD be
+ prepared to transmit in 100-recipient "chunks" if the server
+ declines to accept more than 100 recipients in a single message.
+
+ Errors due to exceeding these limits may be reported by using the
+ reply codes. Some examples of reply codes are:
+
+ 500 Line too long.
+ or
+ 501 Path too long
+ or
+ 452 Too many recipients (see below)
+ or
+ 552 Too much mail data.
+
+ RFC 821 [30] incorrectly listed the error where an SMTP server
+ exhausts its implementation limit on the number of RCPT commands
+ ("too many recipients") as having reply code 552. The correct reply
+ code for this condition is 452. Clients SHOULD treat a 552 code in
+ this case as a temporary, rather than permanent, failure so the logic
+ below works.
+
+ When a conforming SMTP server encounters this condition, it has at
+ least 100 successful RCPT commands in its recipients buffer. If the
+ server is able to accept the message, then at least these 100
+ addresses will be removed from the SMTP client's queue. When the
+ client attempts retransmission of those addresses which received 452
+ responses, at least 100 of these will be able to fit in the SMTP
+ server's recipients buffer. Each retransmission attempt which is
+ able to deliver anything will be able to dispose of at least 100 of
+ these recipients.
+
+ If an SMTP server has an implementation limit on the number of RCPT
+ commands and this limit is exhausted, it MUST use a response code of
+ 452 (but the client SHOULD also be prepared for a 552, as noted
+ above). If the server has a configured site-policy limitation on the
+ number of RCPT commands, it MAY instead use a 5XX response code.
+ This would be most appropriate if the policy limitation was intended
+ to apply if the total recipient count for a particular message body
+ were enforced even if that message body was sent in multiple mail
+ transactions.
+
+4.5.3.2 Timeouts
+
+ An SMTP client MUST provide a timeout mechanism. It MUST use per-
+ command timeouts rather than somehow trying to time the entire mail
+ transaction. Timeouts SHOULD be easily reconfigurable, preferably
+ without recompiling the SMTP code. To implement this, a timer is set
+
+
+
+Klensin Standards Track [Page 56]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ for each SMTP command and for each buffer of the data transfer. The
+ latter means that the overall timeout is inherently proportional to
+ the size of the message.
+
+ Based on extensive experience with busy mail-relay hosts, the minimum
+ per-command timeout values SHOULD be as follows:
+
+ Initial 220 Message: 5 minutes
+ An SMTP client process needs to distinguish between a failed TCP
+ connection and a delay in receiving the initial 220 greeting
+ message. Many SMTP servers accept a TCP connection but delay
+ delivery of the 220 message until their system load permits more
+ mail to be processed.
+
+ MAIL Command: 5 minutes
+
+ RCPT Command: 5 minutes
+ A longer timeout is required if processing of mailing lists and
+ aliases is not deferred until after the message was accepted.
+
+ DATA Initiation: 2 minutes
+ This is while awaiting the "354 Start Input" reply to a DATA
+ command.
+
+ Data Block: 3 minutes
+ This is while awaiting the completion of each TCP SEND call
+ transmitting a chunk of data.
+
+ DATA Termination: 10 minutes.
+ This is while awaiting the "250 OK" reply. When the receiver gets
+ the final period terminating the message data, it typically
+ performs processing to deliver the message to a user mailbox. A
+ spurious timeout at this point would be very wasteful and would
+ typically result in delivery of multiple copies of the message,
+ since it has been successfully sent and the server has accepted
+ responsibility for delivery. See section 6.1 for additional
+ discussion.
+
+ An SMTP server SHOULD have a timeout of at least 5 minutes while it
+ is awaiting the next command from the sender.
+
+4.5.4 Retry Strategies
+
+ The common structure of a host SMTP implementation includes user
+ mailboxes, one or more areas for queuing messages in transit, and one
+ or more daemon processes for sending and receiving mail. The exact
+ structure will vary depending on the needs of the users on the host
+
+
+
+
+Klensin Standards Track [Page 57]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ and the number and size of mailing lists supported by the host. We
+ describe several optimizations that have proved helpful, particularly
+ for mailers supporting high traffic levels.
+
+ Any queuing strategy MUST include timeouts on all activities on a
+ per-command basis. A queuing strategy MUST NOT send error messages
+ in response to error messages under any circumstances.
+
+4.5.4.1 Sending Strategy
+
+ The general model for an SMTP client is one or more processes that
+ periodically attempt to transmit outgoing mail. In a typical system,
+ the program that composes a message has some method for requesting
+ immediate attention for a new piece of outgoing mail, while mail that
+ cannot be transmitted immediately MUST be queued and periodically
+ retried by the sender. A mail queue entry will include not only the
+ message itself but also the envelope information.
+
+ The sender MUST delay retrying a particular destination after one
+ attempt has failed. In general, the retry interval SHOULD be at
+ least 30 minutes; however, more sophisticated and variable strategies
+ will be beneficial when the SMTP client can determine the reason for
+ non-delivery.
+
+ Retries continue until the message is transmitted or the sender gives
+ up; the give-up time generally needs to be at least 4-5 days. The
+ parameters to the retry algorithm MUST be configurable.
+
+ A client SHOULD keep a list of hosts it cannot reach and
+ corresponding connection timeouts, rather than just retrying queued
+ mail items.
+
+ Experience suggests that failures are typically transient (the target
+ system or its connection has crashed), favoring a policy of two
+ connection attempts in the first hour the message is in the queue,
+ and then backing off to one every two or three hours.
+
+ The SMTP client can shorten the queuing delay in cooperation with the
+ SMTP server. For example, if mail is received from a particular
+ address, it is likely that mail queued for that host can now be sent.
+ Application of this principle may, in many cases, eliminate the
+ requirement for an explicit "send queues now" function such as ETRN
+ [9].
+
+ The strategy may be further modified as a result of multiple
+ addresses per host (see below) to optimize delivery time vs. resource
+ usage.
+
+
+
+
+Klensin Standards Track [Page 58]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ An SMTP client may have a large queue of messages for each
+ unavailable destination host. If all of these messages were retried
+ in every retry cycle, there would be excessive Internet overhead and
+ the sending system would be blocked for a long period. Note that an
+ SMTP client can generally determine that a delivery attempt has
+ failed only after a timeout of several minutes and even a one-minute
+ timeout per connection will result in a very large delay if retries
+ are repeated for dozens, or even hundreds, of queued messages to the
+ same host.
+
+ At the same time, SMTP clients SHOULD use great care in caching
+ negative responses from servers. In an extreme case, if EHLO is
+ issued multiple times during the same SMTP connection, different
+ answers may be returned by the server. More significantly, 5yz
+ responses to the MAIL command MUST NOT be cached.
+
+ When a mail message is to be delivered to multiple recipients, and
+ the SMTP server to which a copy of the message is to be sent is the
+ same for multiple recipients, then only one copy of the message
+ SHOULD be transmitted. That is, the SMTP client SHOULD use the
+ command sequence: MAIL, RCPT, RCPT,... RCPT, DATA instead of the
+ sequence: MAIL, RCPT, DATA, ..., MAIL, RCPT, DATA. However, if there
+ are very many addresses, a limit on the number of RCPT commands per
+ MAIL command MAY be imposed. Implementation of this efficiency
+ feature is strongly encouraged.
+
+ Similarly, to achieve timely delivery, the SMTP client MAY support
+ multiple concurrent outgoing mail transactions. However, some limit
+ may be appropriate to protect the host from devoting all its
+ resources to mail.
+
+4.5.4.2 Receiving Strategy
+
+ The SMTP server SHOULD attempt to keep a pending listen on the SMTP
+ port at all times. This requires the support of multiple incoming
+ TCP connections for SMTP. Some limit MAY be imposed but servers that
+ cannot handle more than one SMTP transaction at a time are not in
+ conformance with the intent of this specification.
+
+ As discussed above, when the SMTP server receives mail from a
+ particular host address, it could activate its own SMTP queuing
+ mechanisms to retry any mail pending for that host address.
+
+4.5.5 Messages with a null reverse-path
+
+ There are several types of notification messages which are required
+ by existing and proposed standards to be sent with a null reverse
+ path, namely non-delivery notifications as discussed in section 3.7,
+
+
+
+Klensin Standards Track [Page 59]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ other kinds of Delivery Status Notifications (DSNs) [24], and also
+ Message Disposition Notifications (MDNs) [10]. All of these kinds of
+ messages are notifications about a previous message, and they are
+ sent to the reverse-path of the previous mail message. (If the
+ delivery of such a notification message fails, that usually indicates
+ a problem with the mail system of the host to which the notification
+ message is addressed. For this reason, at some hosts the MTA is set
+ up to forward such failed notification messages to someone who is
+ able to fix problems with the mail system, e.g., via the postmaster
+ alias.)
+
+ All other types of messages (i.e., any message which is not required
+ by a standards-track RFC to have a null reverse-path) SHOULD be sent
+ with with a valid, non-null reverse-path.
+
+ Implementors of automated email processors should be careful to make
+ sure that the various kinds of messages with null reverse-path are
+ handled correctly, in particular such systems SHOULD NOT reply to
+ messages with null reverse-path.
+
+5. Address Resolution and Mail Handling
+
+ Once an SMTP client lexically identifies a domain to which mail will
+ be delivered for processing (as described in sections 3.6 and 3.7), a
+ DNS lookup MUST be performed to resolve the domain name [22]. The
+ names are expected to be fully-qualified domain names (FQDNs):
+ mechanisms for inferring FQDNs from partial names or local aliases
+ are outside of this specification and, due to a history of problems,
+ are generally discouraged. The lookup first attempts to locate an MX
+ record associated with the name. If a CNAME record is found instead,
+ the resulting name is processed as if it were the initial name. If
+ no MX records are found, but an A RR is found, the A RR is treated as
+ if it was associated with an implicit MX RR, with a preference of 0,
+ pointing to that host. If one or more MX RRs are found for a given
+ name, SMTP systems MUST NOT utilize any A RRs associated with that
+ name unless they are located using the MX RRs; the "implicit MX" rule
+ above applies only if there are no MX records present. If MX records
+ are present, but none of them are usable, this situation MUST be
+ reported as an error.
+
+ When the lookup succeeds, the mapping can result in a list of
+ alternative delivery addresses rather than a single address, because
+ of multiple MX records, multihoming, or both. To provide reliable
+ mail transmission, the SMTP client MUST be able to try (and retry)
+ each of the relevant addresses in this list in order, until a
+ delivery attempt succeeds. However, there MAY also be a configurable
+ limit on the number of alternate addresses that can be tried. In any
+ case, the SMTP client SHOULD try at least two addresses.
+
+
+
+Klensin Standards Track [Page 60]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ Two types of information is used to rank the host addresses: multiple
+ MX records, and multihomed hosts.
+
+ Multiple MX records contain a preference indication that MUST be used
+ in sorting (see below). Lower numbers are more preferred than higher
+ ones. If there are multiple destinations with the same preference
+ and there is no clear reason to favor one (e.g., by recognition of an
+ easily-reached address), then the sender-SMTP MUST randomize them to
+ spread the load across multiple mail exchangers for a specific
+ organization.
+
+ The destination host (perhaps taken from the preferred MX record) may
+ be multihomed, in which case the domain name resolver will return a
+ list of alternative IP addresses. It is the responsibility of the
+ domain name resolver interface to have ordered this list by
+ decreasing preference if necessary, and SMTP MUST try them in the
+ order presented.
+
+ Although the capability to try multiple alternative addresses is
+ required, specific installations may want to limit or disable the use
+ of alternative addresses. The question of whether a sender should
+ attempt retries using the different addresses of a multihomed host
+ has been controversial. The main argument for using the multiple
+ addresses is that it maximizes the probability of timely delivery,
+ and indeed sometimes the probability of any delivery; the counter-
+ argument is that it may result in unnecessary resource use. Note
+ that resource use is also strongly determined by the sending strategy
+ discussed in section 4.5.4.1.
+
+ If an SMTP server receives a message with a destination for which it
+ is a designated Mail eXchanger, it MAY relay the message (potentially
+ after having rewritten the MAIL FROM and/or RCPT TO addresses), make
+ final delivery of the message, or hand it off using some mechanism
+ outside the SMTP-provided transport environment. Of course, neither
+ of the latter require that the list of MX records be examined
+ further.
+
+ If it determines that it should relay the message without rewriting
+ the address, it MUST sort the MX records to determine candidates for
+ delivery. The records are first ordered by preference, with the
+ lowest-numbered records being most preferred. The relay host MUST
+ then inspect the list for any of the names or addresses by which it
+ might be known in mail transactions. If a matching record is found,
+ all records at that preference level and higher-numbered ones MUST be
+ discarded from consideration. If there are no records left at that
+ point, it is an error condition, and the message MUST be returned as
+ undeliverable. If records do remain, they SHOULD be tried, best
+ preference first, as described above.
+
+
+
+Klensin Standards Track [Page 61]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+6. Problem Detection and Handling
+
+6.1 Reliable Delivery and Replies by Email
+
+ When the receiver-SMTP accepts a piece of mail (by sending a "250 OK"
+ message in response to DATA), it is accepting responsibility for
+ delivering or relaying the message. It must take this responsibility
+ seriously. It MUST NOT lose the message for frivolous reasons, such
+ as because the host later crashes or because of a predictable
+ resource shortage.
+
+ If there is a delivery failure after acceptance of a message, the
+ receiver-SMTP MUST formulate and mail a notification message. This
+ notification MUST be sent using a null ("<>") reverse path in the
+ envelope. The recipient of this notification MUST be the address
+ from the envelope return path (or the Return-Path: line). However,
+ if this address is null ("<>"), the receiver-SMTP MUST NOT send a
+ notification. Obviously, nothing in this section can or should
+ prohibit local decisions (i.e., as part of the same system
+ environment as the receiver-SMTP) to log or otherwise transmit
+ information about null address events locally if that is desired. If
+ the address is an explicit source route, it MUST be stripped down to
+ its final hop.
+
+ For example, suppose that an error notification must be sent for a
+ message that arrived with:
+
+ MAIL FROM:<@a,@b:user@d>
+
+ The notification message MUST be sent using:
+
+ RCPT TO:<user@d>
+
+ Some delivery failures after the message is accepted by SMTP will be
+ unavoidable. For example, it may be impossible for the receiving
+ SMTP server to validate all the delivery addresses in RCPT command(s)
+ due to a "soft" domain system error, because the target is a mailing
+ list (see earlier discussion of RCPT), or because the server is
+ acting as a relay and has no immediate access to the delivering
+ system.
+
+ To avoid receiving duplicate messages as the result of timeouts, a
+ receiver-SMTP MUST seek to minimize the time required to respond to
+ the final <CRLF>.<CRLF> end of data indicator. See RFC 1047 [28] for
+ a discussion of this problem.
+
+
+
+
+
+
+Klensin Standards Track [Page 62]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+6.2 Loop Detection
+
+ Simple counting of the number of "Received:" headers in a message has
+ proven to be an effective, although rarely optimal, method of
+ detecting loops in mail systems. SMTP servers using this technique
+ SHOULD use a large rejection threshold, normally at least 100
+ Received entries. Whatever mechanisms are used, servers MUST contain
+ provisions for detecting and stopping trivial loops.
+
+6.3 Compensating for Irregularities
+
+ Unfortunately, variations, creative interpretations, and outright
+ violations of Internet mail protocols do occur; some would suggest
+ that they occur quite frequently. The debate as to whether a well-
+ behaved SMTP receiver or relay should reject a malformed message,
+ attempt to pass it on unchanged, or attempt to repair it to increase
+ the odds of successful delivery (or subsequent reply) began almost
+ with the dawn of structured network mail and shows no signs of
+ abating. Advocates of rejection claim that attempted repairs are
+ rarely completely adequate and that rejection of bad messages is the
+ only way to get the offending software repaired. Advocates of
+ "repair" or "deliver no matter what" argue that users prefer that
+ mail go through it if at all possible and that there are significant
+ market pressures in that direction. In practice, these market
+ pressures may be more important to particular vendors than strict
+ conformance to the standards, regardless of the preference of the
+ actual developers.
+
+ The problems associated with ill-formed messages were exacerbated by
+ the introduction of the split-UA mail reading protocols [3, 26, 5,
+ 21]. These protocols have encouraged the use of SMTP as a posting
+ protocol, and SMTP servers as relay systems for these client hosts
+ (which are often only intermittently connected to the Internet).
+ Historically, many of those client machines lacked some of the
+ mechanisms and information assumed by SMTP (and indeed, by the mail
+ format protocol [7]). Some could not keep adequate track of time;
+ others had no concept of time zones; still others could not identify
+ their own names or addresses; and, of course, none could satisfy the
+ assumptions that underlay RFC 822's conception of authenticated
+ addresses.
+
+ In response to these weak SMTP clients, many SMTP systems now
+ complete messages that are delivered to them in incomplete or
+ incorrect form. This strategy is generally considered appropriate
+ when the server can identify or authenticate the client, and there
+ are prior agreements between them. By contrast, there is at best
+ great concern about fixes applied by a relay or delivery SMTP server
+ that has little or no knowledge of the user or client machine.
+
+
+
+Klensin Standards Track [Page 63]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ The following changes to a message being processed MAY be applied
+ when necessary by an originating SMTP server, or one used as the
+ target of SMTP as an initial posting protocol:
+
+ - Addition of a message-id field when none appears
+
+ - Addition of a date, time or time zone when none appears
+
+ - Correction of addresses to proper FQDN format
+
+ The less information the server has about the client, the less likely
+ these changes are to be correct and the more caution and conservatism
+ should be applied when considering whether or not to perform fixes
+ and how. These changes MUST NOT be applied by an SMTP server that
+ provides an intermediate relay function.
+
+ In all cases, properly-operating clients supplying correct
+ information are preferred to corrections by the SMTP server. In all
+ cases, documentation of actions performed by the servers (in trace
+ fields and/or header comments) is strongly encouraged.
+
+7. Security Considerations
+
+7.1 Mail Security and Spoofing
+
+ SMTP mail is inherently insecure in that it is feasible for even
+ fairly casual users to negotiate directly with receiving and relaying
+ SMTP servers and create messages that will trick a naive recipient
+ into believing that they came from somewhere else. Constructing such
+ a message so that the "spoofed" behavior cannot be detected by an
+ expert is somewhat more difficult, but not sufficiently so as to be a
+ deterrent to someone who is determined and knowledgeable.
+ Consequently, as knowledge of Internet mail increases, so does the
+ knowledge that SMTP mail inherently cannot be authenticated, or
+ integrity checks provided, at the transport level. Real mail
+ security lies only in end-to-end methods involving the message
+ bodies, such as those which use digital signatures (see [14] and,
+ e.g., PGP [4] or S/MIME [31]).
+
+ Various protocol extensions and configuration options that provide
+ authentication at the transport level (e.g., from an SMTP client to
+ an SMTP server) improve somewhat on the traditional situation
+ described above. However, unless they are accompanied by careful
+ handoffs of responsibility in a carefully-designed trust environment,
+ they remain inherently weaker than end-to-end mechanisms which use
+ digitally signed messages rather than depending on the integrity of
+ the transport system.
+
+
+
+
+Klensin Standards Track [Page 64]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ Efforts to make it more difficult for users to set envelope return
+ path and header "From" fields to point to valid addresses other than
+ their own are largely misguided: they frustrate legitimate
+ applications in which mail is sent by one user on behalf of another
+ or in which error (or normal) replies should be directed to a special
+ address. (Systems that provide convenient ways for users to alter
+ these fields on a per-message basis should attempt to establish a
+ primary and permanent mailbox address for the user so that Sender
+ fields within the message data can be generated sensibly.)
+
+ This specification does not further address the authentication issues
+ associated with SMTP other than to advocate that useful functionality
+ not be disabled in the hope of providing some small margin of
+ protection against an ignorant user who is trying to fake mail.
+
+7.2 "Blind" Copies
+
+ Addresses that do not appear in the message headers may appear in the
+ RCPT commands to an SMTP server for a number of reasons. The two
+ most common involve the use of a mailing address as a "list exploder"
+ (a single address that resolves into multiple addresses) and the
+ appearance of "blind copies". Especially when more than one RCPT
+ command is present, and in order to avoid defeating some of the
+ purpose of these mechanisms, SMTP clients and servers SHOULD NOT copy
+ the full set of RCPT command arguments into the headers, either as
+ part of trace headers or as informational or private-extension
+ headers. Since this rule is often violated in practice, and cannot
+ be enforced, sending SMTP systems that are aware of "bcc" use MAY
+ find it helpful to send each blind copy as a separate message
+ transaction containing only a single RCPT command.
+
+ There is no inherent relationship between either "reverse" (from
+ MAIL, SAML, etc., commands) or "forward" (RCPT) addresses in the SMTP
+ transaction ("envelope") and the addresses in the headers. Receiving
+ systems SHOULD NOT attempt to deduce such relationships and use them
+ to alter the headers of the message for delivery. The popular
+ "Apparently-to" header is a violation of this principle as well as a
+ common source of unintended information disclosure and SHOULD NOT be
+ used.
+
+7.3 VRFY, EXPN, and Security
+
+ As discussed in section 3.5, individual sites may want to disable
+ either or both of VRFY or EXPN for security reasons. As a corollary
+ to the above, implementations that permit this MUST NOT appear to
+ have verified addresses that are not, in fact, verified. If a site
+
+
+
+
+
+Klensin Standards Track [Page 65]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ disables these commands for security reasons, the SMTP server MUST
+ return a 252 response, rather than a code that could be confused with
+ successful or unsuccessful verification.
+
+ Returning a 250 reply code with the address listed in the VRFY
+ command after having checked it only for syntax violates this rule.
+ Of course, an implementation that "supports" VRFY by always returning
+ 550 whether or not the address is valid is equally not in
+ conformance.
+
+ Within the last few years, the contents of mailing lists have become
+ popular as an address information source for so-called "spammers."
+ The use of EXPN to "harvest" addresses has increased as list
+ administrators have installed protections against inappropriate uses
+ of the lists themselves. Implementations SHOULD still provide
+ support for EXPN, but sites SHOULD carefully evaluate the tradeoffs.
+ As authentication mechanisms are introduced into SMTP, some sites may
+ choose to make EXPN available only to authenticated requestors.
+
+7.4 Information Disclosure in Announcements
+
+ There has been an ongoing debate about the tradeoffs between the
+ debugging advantages of announcing server type and version (and,
+ sometimes, even server domain name) in the greeting response or in
+ response to the HELP command and the disadvantages of exposing
+ information that might be useful in a potential hostile attack. The
+ utility of the debugging information is beyond doubt. Those who
+ argue for making it available point out that it is far better to
+ actually secure an SMTP server rather than hope that trying to
+ conceal known vulnerabilities by hiding the server's precise identity
+ will provide more protection. Sites are encouraged to evaluate the
+ tradeoff with that issue in mind; implementations are strongly
+ encouraged to minimally provide for making type and version
+ information available in some way to other network hosts.
+
+7.5 Information Disclosure in Trace Fields
+
+ In some circumstances, such as when mail originates from within a LAN
+ whose hosts are not directly on the public Internet, trace
+ ("Received") fields produced in conformance with this specification
+ may disclose host names and similar information that would not
+ normally be available. This ordinarily does not pose a problem, but
+ sites with special concerns about name disclosure should be aware of
+ it. Also, the optional FOR clause should be supplied with caution or
+ not at all when multiple recipients are involved lest it
+ inadvertently disclose the identities of "blind copy" recipients to
+ others.
+
+
+
+
+Klensin Standards Track [Page 66]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+7.6 Information Disclosure in Message Forwarding
+
+ As discussed in section 3.4, use of the 251 or 551 reply codes to
+ identify the replacement address associated with a mailbox may
+ inadvertently disclose sensitive information. Sites that are
+ concerned about those issues should ensure that they select and
+ configure servers appropriately.
+
+7.7 Scope of Operation of SMTP Servers
+
+ It is a well-established principle that an SMTP server may refuse to
+ accept mail for any operational or technical reason that makes sense
+ to the site providing the server. However, cooperation among sites
+ and installations makes the Internet possible. If sites take
+ excessive advantage of the right to reject traffic, the ubiquity of
+ email availability (one of the strengths of the Internet) will be
+ threatened; considerable care should be taken and balance maintained
+ if a site decides to be selective about the traffic it will accept
+ and process.
+
+ In recent years, use of the relay function through arbitrary sites
+ has been used as part of hostile efforts to hide the actual origins
+ of mail. Some sites have decided to limit the use of the relay
+ function to known or identifiable sources, and implementations SHOULD
+ provide the capability to perform this type of filtering. When mail
+ is rejected for these or other policy reasons, a 550 code SHOULD be
+ used in response to EHLO, MAIL, or RCPT as appropriate.
+
+8. IANA Considerations
+
+ IANA will maintain three registries in support of this specification.
+ The first consists of SMTP service extensions with the associated
+ keywords, and, as needed, parameters and verbs. As specified in
+ section 2.2.2, no entry may be made in this registry that starts in
+ an "X". Entries may be made only for service extensions (and
+ associated keywords, parameters, or verbs) that are defined in
+ standards-track or experimental RFCs specifically approved by the
+ IESG for this purpose.
+
+ The second registry consists of "tags" that identify forms of domain
+ literals other than those for IPv4 addresses (specified in RFC 821
+ and in this document) and IPv6 addresses (specified in this
+ document). Additional literal types require standardization before
+ being used; none are anticipated at this time.
+
+ The third, established by RFC 821 and renewed by this specification,
+ is a registry of link and protocol identifiers to be used with the
+ "via" and "with" subclauses of the time stamp ("Received: header")
+
+
+
+Klensin Standards Track [Page 67]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ described in section 4.4. Link and protocol identifiers in addition
+ to those specified in this document may be registered only by
+ standardization or by way of an RFC-documented, IESG-approved,
+ Experimental protocol extension.
+
+9. References
+
+ [1] American National Standards Institute (formerly United States of
+ America Standards Institute), X3.4, 1968, "USA Code for
+ Information Interchange". ANSI X3.4-1968 has been replaced by
+ newer versions with slight modifications, but the 1968 version
+ remains definitive for the Internet.
+
+ [2] Braden, R., "Requirements for Internet hosts - application and
+ support", STD 3, RFC 1123, October 1989.
+
+ [3] Butler, M., Chase, D., Goldberger, J., Postel, J. and J.
+ Reynolds, "Post Office Protocol - version 2", RFC 937, February
+ 1985.
+
+ [4] Callas, J., Donnerhacke, L., Finney, H. and R. Thayer, "OpenPGP
+ Message Format", RFC 2440, November 1998.
+
+ [5] Crispin, M., "Interactive Mail Access Protocol - Version 2", RFC
+ 1176, August 1990.
+
+ [6] Crispin, M., "Internet Message Access Protocol - Version 4", RFC
+ 2060, December 1996.
+
+ [7] Crocker, D., "Standard for the Format of ARPA Internet Text
+ Messages", RFC 822, August 1982.
+
+ [8] Crocker, D. and P. Overell, Eds., "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [9] De Winter, J., "SMTP Service Extension for Remote Message Queue
+ Starting", RFC 1985, August 1996.
+
+ [10] Fajman, R., "An Extensible Message Format for Message
+ Disposition Notifications", RFC 2298, March 1998.
+
+ [11] Freed, N, "Behavior of and Requirements for Internet Firewalls",
+ RFC 2979, October 2000.
+
+ [12] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part One: Format of Internet Message Bodies",
+ RFC 2045, December 1996.
+
+
+
+
+Klensin Standards Track [Page 68]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ [13] Freed, N., "SMTP Service Extension for Command Pipelining", RFC
+ 2920, September 2000.
+
+ [14] Galvin, J., Murphy, S., Crocker, S. and N. Freed, "Security
+ Multiparts for MIME: Multipart/Signed and Multipart/Encrypted",
+ RFC 1847, October 1995.
+
+ [15] Gellens, R. and J. Klensin, "Message Submission", RFC 2476,
+ December 1998.
+
+ [16] Kille, S., "Mapping between X.400 and RFC822/MIME", RFC 2156,
+ January 1998.
+
+ [17] Hinden, R and S. Deering, Eds. "IP Version 6 Addressing
+ Architecture", RFC 2373, July 1998.
+
+ [18] Klensin, J., Freed, N. and K. Moore, "SMTP Service Extension for
+ Message Size Declaration", STD 10, RFC 1870, November 1995.
+
+ [19] Klensin, J., Freed, N., Rose, M., Stefferud, E. and D. Crocker,
+ "SMTP Service Extensions", STD 10, RFC 1869, November 1995.
+
+ [20] Klensin, J., Freed, N., Rose, M., Stefferud, E. and D. Crocker,
+ "SMTP Service Extension for 8bit-MIMEtransport", RFC 1652, July
+ 1994.
+
+ [21] Lambert, M., "PCMAIL: A distributed mail system for personal
+ computers", RFC 1056, July 1988.
+
+ [22] Mockapetris, P., "Domain names - implementation and
+ specification", STD 13, RFC 1035, November 1987.
+
+ Mockapetris, P., "Domain names - concepts and facilities", STD
+ 13, RFC 1034, November 1987.
+
+ [23] Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part
+ Three: Message Header Extensions for Non-ASCII Text", RFC 2047,
+ December 1996.
+
+ [24] Moore, K., "SMTP Service Extension for Delivery Status
+ Notifications", RFC 1891, January 1996.
+
+ [25] Moore, K., and G. Vaudreuil, "An Extensible Message Format for
+ Delivery Status Notifications", RFC 1894, January 1996.
+
+ [26] Myers, J. and M. Rose, "Post Office Protocol - Version 3", STD
+ 53, RFC 1939, May 1996.
+
+
+
+
+Klensin Standards Track [Page 69]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ [27] Partridge, C., "Mail routing and the domain system", RFC 974,
+ January 1986.
+
+ [28] Partridge, C., "Duplicate messages and SMTP", RFC 1047, February
+ 1988.
+
+ [29] Postel, J., ed., "Transmission Control Protocol - DARPA Internet
+ Program Protocol Specification", STD 7, RFC 793, September 1981.
+
+ [30] Postel, J., "Simple Mail Transfer Protocol", RFC 821, August
+ 1982.
+
+ [31] Ramsdell, B., Ed., "S/MIME Version 3 Message Specification", RFC
+ 2633, June 1999.
+
+ [32] Resnick, P., Ed., "Internet Message Format", RFC 2822, April
+ 2001.
+
+ [33] Vaudreuil, G., "SMTP Service Extensions for Transmission of
+ Large and Binary MIME Messages", RFC 1830, August 1995.
+
+ [34] Vaudreuil, G., "Enhanced Mail System Status Codes", RFC 1893,
+ January 1996.
+
+10. Editor's Address
+
+ John C. Klensin
+ AT&T Laboratories
+ 99 Bedford St
+ Boston, MA 02111 USA
+
+ Phone: 617-574-3076
+ EMail: klensin@research.att.com
+
+11. Acknowledgments
+
+ Many people worked long and hard on the many iterations of this
+ document. There was wide-ranging debate in the IETF DRUMS Working
+ Group, both on its mailing list and in face to face discussions,
+ about many technical issues and the role of a revised standard for
+ Internet mail transport, and many contributors helped form the
+ wording in this specification. The hundreds of participants in the
+ many discussions since RFC 821 was produced are too numerous to
+ mention, but they all helped this document become what it is.
+
+
+
+
+
+
+
+Klensin Standards Track [Page 70]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+APPENDICES
+
+A. TCP Transport Service
+
+ The TCP connection supports the transmission of 8-bit bytes. The
+ SMTP data is 7-bit ASCII characters. Each character is transmitted
+ as an 8-bit byte with the high-order bit cleared to zero. Service
+ extensions may modify this rule to permit transmission of full 8-bit
+ data bytes as part of the message body, but not in SMTP commands or
+ responses.
+
+B. Generating SMTP Commands from RFC 822 Headers
+
+ Some systems use RFC 822 headers (only) in a mail submission
+ protocol, or otherwise generate SMTP commands from RFC 822 headers
+ when such a message is handed to an MTA from a UA. While the MTA-UA
+ protocol is a private matter, not covered by any Internet Standard,
+ there are problems with this approach. For example, there have been
+ repeated problems with proper handling of "bcc" copies and
+ redistribution lists when information that conceptually belongs to a
+ mail envelopes is not separated early in processing from header
+ information (and kept separate).
+
+ It is recommended that the UA provide its initial ("submission
+ client") MTA with an envelope separate from the message itself.
+ However, if the envelope is not supplied, SMTP commands SHOULD be
+ generated as follows:
+
+ 1. Each recipient address from a TO, CC, or BCC header field SHOULD
+ be copied to a RCPT command (generating multiple message copies if
+ that is required for queuing or delivery). This includes any
+ addresses listed in a RFC 822 "group". Any BCC fields SHOULD then
+ be removed from the headers. Once this process is completed, the
+ remaining headers SHOULD be checked to verify that at least one
+ To:, Cc:, or Bcc: header remains. If none do, then a bcc: header
+ with no additional information SHOULD be inserted as specified in
+ [32].
+
+ 2. The return address in the MAIL command SHOULD, if possible, be
+ derived from the system's identity for the submitting (local)
+ user, and the "From:" header field otherwise. If there is a
+ system identity available, it SHOULD also be copied to the Sender
+ header field if it is different from the address in the From
+ header field. (Any Sender field that was already there SHOULD be
+ removed.) Systems may provide a way for submitters to override
+ the envelope return address, but may want to restrict its use to
+ privileged users. This will not prevent mail forgery, but may
+ lessen its incidence; see section 7.1.
+
+
+
+Klensin Standards Track [Page 71]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ When an MTA is being used in this way, it bears responsibility for
+ ensuring that the message being transmitted is valid. The mechanisms
+ for checking that validity, and for handling (or returning) messages
+ that are not valid at the time of arrival, are part of the MUA-MTA
+ interface and not covered by this specification.
+
+ A submission protocol based on Standard RFC 822 information alone
+ MUST NOT be used to gateway a message from a foreign (non-SMTP) mail
+ system into an SMTP environment. Additional information to construct
+ an envelope must come from some source in the other environment,
+ whether supplemental headers or the foreign system's envelope.
+
+ Attempts to gateway messages using only their header "to" and "cc"
+ fields have repeatedly caused mail loops and other behavior adverse
+ to the proper functioning of the Internet mail environment. These
+ problems have been especially common when the message originates from
+ an Internet mailing list and is distributed into the foreign
+ environment using envelope information. When these messages are then
+ processed by a header-only remailer, loops back to the Internet
+ environment (and the mailing list) are almost inevitable.
+
+C. Source Routes
+
+ Historically, the <reverse-path> was a reverse source routing list of
+ hosts and a source mailbox. The first host in the <reverse-path>
+ SHOULD be the host sending the MAIL command. Similarly, the
+ <forward-path> may be a source routing lists of hosts and a
+ destination mailbox. However, in general, the <forward-path> SHOULD
+ contain only a mailbox and domain name, relying on the domain name
+ system to supply routing information if required. The use of source
+ routes is deprecated; while servers MUST be prepared to receive and
+ handle them as discussed in section 3.3 and F.2, clients SHOULD NOT
+ transmit them and this section was included only to provide context.
+
+ For relay purposes, the forward-path may be a source route of the
+ form "@ONE,@TWO:JOE@THREE", where ONE, TWO, and THREE MUST BE fully-
+ qualified domain names. This form is used to emphasize the
+ distinction between an address and a route. The mailbox is an
+ absolute address, and the route is information about how to get
+ there. The two concepts should not be confused.
+
+ If source routes are used, RFC 821 and the text below should be
+ consulted for the mechanisms for constructing and updating the
+ forward- and reverse-paths.
+
+
+
+
+
+
+
+Klensin Standards Track [Page 72]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ The SMTP server transforms the command arguments by moving its own
+ identifier (its domain name or that of any domain for which it is
+ acting as a mail exchanger), if it appears, from the forward-path to
+ the beginning of the reverse-path.
+
+ Notice that the forward-path and reverse-path appear in the SMTP
+ commands and replies, but not necessarily in the message. That is,
+ there is no need for these paths and especially this syntax to appear
+ in the "To:" , "From:", "CC:", etc. fields of the message header.
+ Conversely, SMTP servers MUST NOT derive final message delivery
+ information from message header fields.
+
+ When the list of hosts is present, it is a "reverse" source route and
+ indicates that the mail was relayed through each host on the list
+ (the first host in the list was the most recent relay). This list is
+ used as a source route to return non-delivery notices to the sender.
+ As each relay host adds itself to the beginning of the list, it MUST
+ use its name as known in the transport environment to which it is
+ relaying the mail rather than that of the transport environment from
+ which the mail came (if they are different).
+
+D. Scenarios
+
+ This section presents complete scenarios of several types of SMTP
+ sessions. In the examples, "C:" indicates what is said by the SMTP
+ client, and "S:" indicates what is said by the SMTP server.
+
+D.1 A Typical SMTP Transaction Scenario
+
+ This SMTP example shows mail sent by Smith at host bar.com, to Jones,
+ Green, and Brown at host foo.com. Here we assume that host bar.com
+ contacts host foo.com directly. The mail is accepted for Jones and
+ Brown. Green does not have a mailbox at host foo.com.
+
+ S: 220 foo.com Simple Mail Transfer Service Ready
+ C: EHLO bar.com
+ S: 250-foo.com greets bar.com
+ S: 250-8BITMIME
+ S: 250-SIZE
+ S: 250-DSN
+ S: 250 HELP
+ C: MAIL FROM:<Smith@bar.com>
+ S: 250 OK
+ C: RCPT TO:<Jones@foo.com>
+ S: 250 OK
+ C: RCPT TO:<Green@foo.com>
+ S: 550 No such user here
+ C: RCPT TO:<Brown@foo.com>
+
+
+
+Klensin Standards Track [Page 73]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ S: 250 OK
+ C: DATA
+ S: 354 Start mail input; end with <CRLF>.<CRLF>
+ C: Blah blah blah...
+ C: ...etc. etc. etc.
+ C: .
+ S: 250 OK
+ C: QUIT
+ S: 221 foo.com Service closing transmission channel
+
+D.2 Aborted SMTP Transaction Scenario
+
+ S: 220 foo.com Simple Mail Transfer Service Ready
+ C: EHLO bar.com
+ S: 250-foo.com greets bar.com
+ S: 250-8BITMIME
+ S: 250-SIZE
+ S: 250-DSN
+ S: 250 HELP
+ C: MAIL FROM:<Smith@bar.com>
+ S: 250 OK
+ C: RCPT TO:<Jones@foo.com>
+ S: 250 OK
+ C: RCPT TO:<Green@foo.com>
+ S: 550 No such user here
+ C: RSET
+ S: 250 OK
+ C: QUIT
+ S: 221 foo.com Service closing transmission channel
+
+D.3 Relayed Mail Scenario
+
+ Step 1 -- Source Host to Relay Host
+
+ S: 220 foo.com Simple Mail Transfer Service Ready
+ C: EHLO bar.com
+ S: 250-foo.com greets bar.com
+ S: 250-8BITMIME
+ S: 250-SIZE
+ S: 250-DSN
+ S: 250 HELP
+ C: MAIL FROM:<JQP@bar.com>
+ S: 250 OK
+ C: RCPT TO:<@foo.com:Jones@XYZ.COM>
+ S: 250 OK
+ C: DATA
+ S: 354 Start mail input; end with <CRLF>.<CRLF>
+ C: Date: Thu, 21 May 1998 05:33:29 -0700
+
+
+
+Klensin Standards Track [Page 74]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ C: From: John Q. Public <JQP@bar.com>
+ C: Subject: The Next Meeting of the Board
+ C: To: Jones@xyz.com
+ C:
+ C: Bill:
+ C: The next meeting of the board of directors will be
+ C: on Tuesday.
+ C: John.
+ C: .
+ S: 250 OK
+ C: QUIT
+ S: 221 foo.com Service closing transmission channel
+
+ Step 2 -- Relay Host to Destination Host
+
+ S: 220 xyz.com Simple Mail Transfer Service Ready
+ C: EHLO foo.com
+ S: 250 xyz.com is on the air
+ C: MAIL FROM:<@foo.com:JQP@bar.com>
+ S: 250 OK
+ C: RCPT TO:<Jones@XYZ.COM>
+ S: 250 OK
+ C: DATA
+ S: 354 Start mail input; end with <CRLF>.<CRLF>
+ C: Received: from bar.com by foo.com ; Thu, 21 May 1998
+ C: 05:33:29 -0700
+ C: Date: Thu, 21 May 1998 05:33:22 -0700
+ C: From: John Q. Public <JQP@bar.com>
+ C: Subject: The Next Meeting of the Board
+ C: To: Jones@xyz.com
+ C:
+ C: Bill:
+ C: The next meeting of the board of directors will be
+ C: on Tuesday.
+ C: John.
+ C: .
+ S: 250 OK
+ C: QUIT
+ S: 221 foo.com Service closing transmission channel
+
+D.4 Verifying and Sending Scenario
+
+ S: 220 foo.com Simple Mail Transfer Service Ready
+ C: EHLO bar.com
+ S: 250-foo.com greets bar.com
+ S: 250-8BITMIME
+ S: 250-SIZE
+ S: 250-DSN
+
+
+
+Klensin Standards Track [Page 75]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+ S: 250-VRFY
+ S: 250 HELP
+ C: VRFY Crispin
+ S: 250 Mark Crispin <Admin.MRC@foo.com>
+ C: SEND FROM:<EAK@bar.com>
+ S: 250 OK
+ C: RCPT TO:<Admin.MRC@foo.com>
+ S: 250 OK
+ C: DATA
+ S: 354 Start mail input; end with <CRLF>.<CRLF>
+ C: Blah blah blah...
+ C: ...etc. etc. etc.
+ C: .
+ S: 250 OK
+ C: QUIT
+ S: 221 foo.com Service closing transmission channel
+
+E. Other Gateway Issues
+
+ In general, gateways between the Internet and other mail systems
+ SHOULD attempt to preserve any layering semantics across the
+ boundaries between the two mail systems involved. Gateway-
+ translation approaches that attempt to take shortcuts by mapping,
+ (such as envelope information from one system to the message headers
+ or body of another) have generally proven to be inadequate in
+ important ways. Systems translating between environments that do not
+ support both envelopes and headers and Internet mail must be written
+ with the understanding that some information loss is almost
+ inevitable.
+
+F. Deprecated Features of RFC 821
+
+ A few features of RFC 821 have proven to be problematic and SHOULD
+ NOT be used in Internet mail.
+
+F.1 TURN
+
+ This command, described in RFC 821, raises important security issues
+ since, in the absence of strong authentication of the host requesting
+ that the client and server switch roles, it can easily be used to
+ divert mail from its correct destination. Its use is deprecated;
+ SMTP systems SHOULD NOT use it unless the server can authenticate the
+ client.
+
+
+
+
+
+
+
+
+Klensin Standards Track [Page 76]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+F.2 Source Routing
+
+ RFC 821 utilized the concept of explicit source routing to get mail
+ from one host to another via a series of relays. The requirement to
+ utilize source routes in regular mail traffic was eliminated by the
+ introduction of the domain name system "MX" record and the last
+ significant justification for them was eliminated by the
+ introduction, in RFC 1123, of a clear requirement that addresses
+ following an "@" must all be fully-qualified domain names.
+ Consequently, the only remaining justifications for the use of source
+ routes are support for very old SMTP clients or MUAs and in mail
+ system debugging. They can, however, still be useful in the latter
+ circumstance and for routing mail around serious, but temporary,
+ problems such as problems with the relevant DNS records.
+
+ SMTP servers MUST continue to accept source route syntax as specified
+ in the main body of this document and in RFC 1123. They MAY, if
+ necessary, ignore the routes and utilize only the target domain in
+ the address. If they do utilize the source route, the message MUST
+ be sent to the first domain shown in the address. In particular, a
+ server MUST NOT guess at shortcuts within the source route.
+
+ Clients SHOULD NOT utilize explicit source routing except under
+ unusual circumstances, such as debugging or potentially relaying
+ around firewall or mail system configuration errors.
+
+F.3 HELO
+
+ As discussed in sections 3.1 and 4.1.1, EHLO is strongly preferred to
+ HELO when the server will accept the former. Servers must continue
+ to accept and process HELO in order to support older clients.
+
+F.4 #-literals
+
+ RFC 821 provided for specifying an Internet address as a decimal
+ integer host number prefixed by a pound sign, "#". In practice, that
+ form has been obsolete since the introduction of TCP/IP. It is
+ deprecated and MUST NOT be used.
+
+F.5 Dates and Years
+
+ When dates are inserted into messages by SMTP clients or servers
+ (e.g., in trace fields), four-digit years MUST BE used. Two-digit
+ years are deprecated; three-digit years were never permitted in the
+ Internet mail system.
+
+
+
+
+
+
+Klensin Standards Track [Page 77]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+F.6 Sending versus Mailing
+
+ In addition to specifying a mechanism for delivering messages to
+ user's mailboxes, RFC 821 provided additional, optional, commands to
+ deliver messages directly to the user's terminal screen. These
+ commands (SEND, SAML, SOML) were rarely implemented, and changes in
+ workstation technology and the introduction of other protocols may
+ have rendered them obsolete even where they are implemented.
+
+ Clients SHOULD NOT provide SEND, SAML, or SOML as services. Servers
+ MAY implement them. If they are implemented by servers, the
+ implementation model specified in RFC 821 MUST be used and the
+ command names MUST be published in the response to the EHLO command.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Klensin Standards Track [Page 78]
+
+RFC 2821 Simple Mail Transfer Protocol April 2001
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Klensin Standards Track [Page 79]
+
diff --git a/standards/rfc2822.txt b/standards/rfc2822.txt
new file mode 100644
index 000000000..9f698f77d
--- /dev/null
+++ b/standards/rfc2822.txt
@@ -0,0 +1,2859 @@
+
+
+
+
+
+
+Network Working Group P. Resnick, Editor
+Request for Comments: 2822 QUALCOMM Incorporated
+Obsoletes: 822 April 2001
+Category: Standards Track
+
+
+ Internet Message Format
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+Abstract
+
+ This standard specifies a syntax for text messages that are sent
+ between computer users, within the framework of "electronic mail"
+ messages. This standard supersedes the one specified in Request For
+ Comments (RFC) 822, "Standard for the Format of ARPA Internet Text
+ Messages", updating it to reflect current practice and incorporating
+ incremental changes that were specified in other RFCs.
+
+Table of Contents
+
+ 1. Introduction ............................................... 3
+ 1.1. Scope .................................................... 3
+ 1.2. Notational conventions ................................... 4
+ 1.2.1. Requirements notation .................................. 4
+ 1.2.2. Syntactic notation ..................................... 4
+ 1.3. Structure of this document ............................... 4
+ 2. Lexical Analysis of Messages ............................... 5
+ 2.1. General Description ...................................... 5
+ 2.1.1. Line Length Limits ..................................... 6
+ 2.2. Header Fields ............................................ 7
+ 2.2.1. Unstructured Header Field Bodies ....................... 7
+ 2.2.2. Structured Header Field Bodies ......................... 7
+ 2.2.3. Long Header Fields ..................................... 7
+ 2.3. Body ..................................................... 8
+ 3. Syntax ..................................................... 9
+ 3.1. Introduction ............................................. 9
+ 3.2. Lexical Tokens ........................................... 9
+
+
+
+Resnick Standards Track [Page 1]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ 3.2.1. Primitive Tokens ....................................... 9
+ 3.2.2. Quoted characters ......................................10
+ 3.2.3. Folding white space and comments .......................11
+ 3.2.4. Atom ...................................................12
+ 3.2.5. Quoted strings .........................................13
+ 3.2.6. Miscellaneous tokens ...................................13
+ 3.3. Date and Time Specification ..............................14
+ 3.4. Address Specification ....................................15
+ 3.4.1. Addr-spec specification ................................16
+ 3.5 Overall message syntax ....................................17
+ 3.6. Field definitions ........................................18
+ 3.6.1. The origination date field .............................20
+ 3.6.2. Originator fields ......................................21
+ 3.6.3. Destination address fields .............................22
+ 3.6.4. Identification fields ..................................23
+ 3.6.5. Informational fields ...................................26
+ 3.6.6. Resent fields ..........................................26
+ 3.6.7. Trace fields ...........................................28
+ 3.6.8. Optional fields ........................................29
+ 4. Obsolete Syntax ............................................29
+ 4.1. Miscellaneous obsolete tokens ............................30
+ 4.2. Obsolete folding white space .............................31
+ 4.3. Obsolete Date and Time ...................................31
+ 4.4. Obsolete Addressing ......................................33
+ 4.5. Obsolete header fields ...................................33
+ 4.5.1. Obsolete origination date field ........................34
+ 4.5.2. Obsolete originator fields .............................34
+ 4.5.3. Obsolete destination address fields ....................34
+ 4.5.4. Obsolete identification fields .........................35
+ 4.5.5. Obsolete informational fields ..........................35
+ 4.5.6. Obsolete resent fields .................................35
+ 4.5.7. Obsolete trace fields ..................................36
+ 4.5.8. Obsolete optional fields ...............................36
+ 5. Security Considerations ....................................36
+ 6. Bibliography ...............................................37
+ 7. Editor's Address ...........................................38
+ 8. Acknowledgements ...........................................39
+ Appendix A. Example messages ..................................41
+ A.1. Addressing examples ......................................41
+ A.1.1. A message from one person to another with simple
+ addressing .............................................41
+ A.1.2. Different types of mailboxes ...........................42
+ A.1.3. Group addresses ........................................43
+ A.2. Reply messages ...........................................43
+ A.3. Resent messages ..........................................44
+ A.4. Messages with trace fields ...............................46
+ A.5. White space, comments, and other oddities ................47
+ A.6. Obsoleted forms ..........................................47
+
+
+
+Resnick Standards Track [Page 2]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ A.6.1. Obsolete addressing ....................................48
+ A.6.2. Obsolete dates .........................................48
+ A.6.3. Obsolete white space and comments ......................48
+ Appendix B. Differences from earlier standards ................49
+ Appendix C. Notices ...........................................50
+ Full Copyright Statement ......................................51
+
+1. Introduction
+
+1.1. Scope
+
+ This standard specifies a syntax for text messages that are sent
+ between computer users, within the framework of "electronic mail"
+ messages. This standard supersedes the one specified in Request For
+ Comments (RFC) 822, "Standard for the Format of ARPA Internet Text
+ Messages" [RFC822], updating it to reflect current practice and
+ incorporating incremental changes that were specified in other RFCs
+ [STD3].
+
+ This standard specifies a syntax only for text messages. In
+ particular, it makes no provision for the transmission of images,
+ audio, or other sorts of structured data in electronic mail messages.
+ There are several extensions published, such as the MIME document
+ series [RFC2045, RFC2046, RFC2049], which describe mechanisms for the
+ transmission of such data through electronic mail, either by
+ extending the syntax provided here or by structuring such messages to
+ conform to this syntax. Those mechanisms are outside of the scope of
+ this standard.
+
+ In the context of electronic mail, messages are viewed as having an
+ envelope and contents. The envelope contains whatever information is
+ needed to accomplish transmission and delivery. (See [RFC2821] for a
+ discussion of the envelope.) The contents comprise the object to be
+ delivered to the recipient. This standard applies only to the format
+ and some of the semantics of message contents. It contains no
+ specification of the information in the envelope.
+
+ However, some message systems may use information from the contents
+ to create the envelope. It is intended that this standard facilitate
+ the acquisition of such information by programs.
+
+ This specification is intended as a definition of what message
+ content format is to be passed between systems. Though some message
+ systems locally store messages in this format (which eliminates the
+ need for translation between formats) and others use formats that
+ differ from the one specified in this standard, local storage is
+ outside of the scope of this standard.
+
+
+
+
+Resnick Standards Track [Page 3]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ Note: This standard is not intended to dictate the internal formats
+ used by sites, the specific message system features that they are
+ expected to support, or any of the characteristics of user interface
+ programs that create or read messages. In addition, this standard
+ does not specify an encoding of the characters for either transport
+ or storage; that is, it does not specify the number of bits used or
+ how those bits are specifically transferred over the wire or stored
+ on disk.
+
+1.2. Notational conventions
+
+1.2.1. Requirements notation
+
+ This document occasionally uses terms that appear in capital letters.
+ When the terms "MUST", "SHOULD", "RECOMMENDED", "MUST NOT", "SHOULD
+ NOT", and "MAY" appear capitalized, they are being used to indicate
+ particular requirements of this specification. A discussion of the
+ meanings of these terms appears in [RFC2119].
+
+1.2.2. Syntactic notation
+
+ This standard uses the Augmented Backus-Naur Form (ABNF) notation
+ specified in [RFC2234] for the formal definitions of the syntax of
+ messages. Characters will be specified either by a decimal value
+ (e.g., the value %d65 for uppercase A and %d97 for lowercase A) or by
+ a case-insensitive literal value enclosed in quotation marks (e.g.,
+ "A" for either uppercase or lowercase A). See [RFC2234] for the full
+ description of the notation.
+
+1.3. Structure of this document
+
+ This document is divided into several sections.
+
+ This section, section 1, is a short introduction to the document.
+
+ Section 2 lays out the general description of a message and its
+ constituent parts. This is an overview to help the reader understand
+ some of the general principles used in the later portions of this
+ document. Any examples in this section MUST NOT be taken as
+ specification of the formal syntax of any part of a message.
+
+ Section 3 specifies formal ABNF rules for the structure of each part
+ of a message (the syntax) and describes the relationship between
+ those parts and their meaning in the context of a message (the
+ semantics). That is, it describes the actual rules for the structure
+ of each part of a message (the syntax) as well as a description of
+ the parts and instructions on how they ought to be interpreted (the
+ semantics). This includes analysis of the syntax and semantics of
+
+
+
+Resnick Standards Track [Page 4]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ subparts of messages that have specific structure. The syntax
+ included in section 3 represents messages as they MUST be created.
+ There are also notes in section 3 to indicate if any of the options
+ specified in the syntax SHOULD be used over any of the others.
+
+ Both sections 2 and 3 describe messages that are legal to generate
+ for purposes of this standard.
+
+ Section 4 of this document specifies an "obsolete" syntax. There are
+ references in section 3 to these obsolete syntactic elements. The
+ rules of the obsolete syntax are elements that have appeared in
+ earlier revisions of this standard or have previously been widely
+ used in Internet messages. As such, these elements MUST be
+ interpreted by parsers of messages in order to be conformant to this
+ standard. However, since items in this syntax have been determined
+ to be non-interoperable or to cause significant problems for
+ recipients of messages, they MUST NOT be generated by creators of
+ conformant messages.
+
+ Section 5 details security considerations to take into account when
+ implementing this standard.
+
+ Section 6 is a bibliography of references in this document.
+
+ Section 7 contains the editor's address.
+
+ Section 8 contains acknowledgements.
+
+ Appendix A lists examples of different sorts of messages. These
+ examples are not exhaustive of the types of messages that appear on
+ the Internet, but give a broad overview of certain syntactic forms.
+
+ Appendix B lists the differences between this standard and earlier
+ standards for Internet messages.
+
+ Appendix C has copyright and intellectual property notices.
+
+2. Lexical Analysis of Messages
+
+2.1. General Description
+
+ At the most basic level, a message is a series of characters. A
+ message that is conformant with this standard is comprised of
+ characters with values in the range 1 through 127 and interpreted as
+ US-ASCII characters [ASCII]. For brevity, this document sometimes
+ refers to this range of characters as simply "US-ASCII characters".
+
+
+
+
+
+Resnick Standards Track [Page 5]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ Note: This standard specifies that messages are made up of characters
+ in the US-ASCII range of 1 through 127. There are other documents,
+ specifically the MIME document series [RFC2045, RFC2046, RFC2047,
+ RFC2048, RFC2049], that extend this standard to allow for values
+ outside of that range. Discussion of those mechanisms is not within
+ the scope of this standard.
+
+ Messages are divided into lines of characters. A line is a series of
+ characters that is delimited with the two characters carriage-return
+ and line-feed; that is, the carriage return (CR) character (ASCII
+ value 13) followed immediately by the line feed (LF) character (ASCII
+ value 10). (The carriage-return/line-feed pair is usually written in
+ this document as "CRLF".)
+
+ A message consists of header fields (collectively called "the header
+ of the message") followed, optionally, by a body. The header is a
+ sequence of lines of characters with special syntax as defined in
+ this standard. The body is simply a sequence of characters that
+ follows the header and is separated from the header by an empty line
+ (i.e., a line with nothing preceding the CRLF).
+
+2.1.1. Line Length Limits
+
+ There are two limits that this standard places on the number of
+ characters in a line. Each line of characters MUST be no more than
+ 998 characters, and SHOULD be no more than 78 characters, excluding
+ the CRLF.
+
+ The 998 character limit is due to limitations in many implementations
+ which send, receive, or store Internet Message Format messages that
+ simply cannot handle more than 998 characters on a line. Receiving
+ implementations would do well to handle an arbitrarily large number
+ of characters in a line for robustness sake. However, there are so
+ many implementations which (in compliance with the transport
+ requirements of [RFC2821]) do not accept messages containing more
+ than 1000 character including the CR and LF per line, it is important
+ for implementations not to create such messages.
+
+ The more conservative 78 character recommendation is to accommodate
+ the many implementations of user interfaces that display these
+ messages which may truncate, or disastrously wrap, the display of
+ more than 78 characters per line, in spite of the fact that such
+ implementations are non-conformant to the intent of this
+ specification (and that of [RFC2821] if they actually cause
+ information to be lost). Again, even though this limitation is put on
+ messages, it is encumbant upon implementations which display messages
+
+
+
+
+
+Resnick Standards Track [Page 6]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ to handle an arbitrarily large number of characters in a line
+ (certainly at least up to the 998 character limit) for the sake of
+ robustness.
+
+2.2. Header Fields
+
+ Header fields are lines composed of a field name, followed by a colon
+ (":"), followed by a field body, and terminated by CRLF. A field
+ name MUST be composed of printable US-ASCII characters (i.e.,
+ characters that have values between 33 and 126, inclusive), except
+ colon. A field body may be composed of any US-ASCII characters,
+ except for CR and LF. However, a field body may contain CRLF when
+ used in header "folding" and "unfolding" as described in section
+ 2.2.3. All field bodies MUST conform to the syntax described in
+ sections 3 and 4 of this standard.
+
+2.2.1. Unstructured Header Field Bodies
+
+ Some field bodies in this standard are defined simply as
+ "unstructured" (which is specified below as any US-ASCII characters,
+ except for CR and LF) with no further restrictions. These are
+ referred to as unstructured field bodies. Semantically, unstructured
+ field bodies are simply to be treated as a single line of characters
+ with no further processing (except for header "folding" and
+ "unfolding" as described in section 2.2.3).
+
+2.2.2. Structured Header Field Bodies
+
+ Some field bodies in this standard have specific syntactical
+ structure more restrictive than the unstructured field bodies
+ described above. These are referred to as "structured" field bodies.
+ Structured field bodies are sequences of specific lexical tokens as
+ described in sections 3 and 4 of this standard. Many of these tokens
+ are allowed (according to their syntax) to be introduced or end with
+ comments (as described in section 3.2.3) as well as the space (SP,
+ ASCII value 32) and horizontal tab (HTAB, ASCII value 9) characters
+ (together known as the white space characters, WSP), and those WSP
+ characters are subject to header "folding" and "unfolding" as
+ described in section 2.2.3. Semantic analysis of structured field
+ bodies is given along with their syntax.
+
+2.2.3. Long Header Fields
+
+ Each header field is logically a single line of characters comprising
+ the field name, the colon, and the field body. For convenience
+ however, and to deal with the 998/78 character limitations per line,
+ the field body portion of a header field can be split into a multiple
+ line representation; this is called "folding". The general rule is
+
+
+
+Resnick Standards Track [Page 7]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ that wherever this standard allows for folding white space (not
+ simply WSP characters), a CRLF may be inserted before any WSP. For
+ example, the header field:
+
+ Subject: This is a test
+
+ can be represented as:
+
+ Subject: This
+ is a test
+
+ Note: Though structured field bodies are defined in such a way that
+ folding can take place between many of the lexical tokens (and even
+ within some of the lexical tokens), folding SHOULD be limited to
+ placing the CRLF at higher-level syntactic breaks. For instance, if
+ a field body is defined as comma-separated values, it is recommended
+ that folding occur after the comma separating the structured items in
+ preference to other places where the field could be folded, even if
+ it is allowed elsewhere.
+
+ The process of moving from this folded multiple-line representation
+ of a header field to its single line representation is called
+ "unfolding". Unfolding is accomplished by simply removing any CRLF
+ that is immediately followed by WSP. Each header field should be
+ treated in its unfolded form for further syntactic and semantic
+ evaluation.
+
+2.3. Body
+
+ The body of a message is simply lines of US-ASCII characters. The
+ only two limitations on the body are as follows:
+
+ - CR and LF MUST only occur together as CRLF; they MUST NOT appear
+ independently in the body.
+
+ - Lines of characters in the body MUST be limited to 998 characters,
+ and SHOULD be limited to 78 characters, excluding the CRLF.
+
+ Note: As was stated earlier, there are other standards documents,
+ specifically the MIME documents [RFC2045, RFC2046, RFC2048, RFC2049]
+ that extend this standard to allow for different sorts of message
+ bodies. Again, these mechanisms are beyond the scope of this
+ document.
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 8]
+
+RFC 2822 Internet Message Format April 2001
+
+
+3. Syntax
+
+3.1. Introduction
+
+ The syntax as given in this section defines the legal syntax of
+ Internet messages. Messages that are conformant to this standard
+ MUST conform to the syntax in this section. If there are options in
+ this section where one option SHOULD be generated, that is indicated
+ either in the prose or in a comment next to the syntax.
+
+ For the defined expressions, a short description of the syntax and
+ use is given, followed by the syntax in ABNF, followed by a semantic
+ analysis. Primitive tokens that are used but otherwise unspecified
+ come from [RFC2234].
+
+ In some of the definitions, there will be nonterminals whose names
+ start with "obs-". These "obs-" elements refer to tokens defined in
+ the obsolete syntax in section 4. In all cases, these productions
+ are to be ignored for the purposes of generating legal Internet
+ messages and MUST NOT be used as part of such a message. However,
+ when interpreting messages, these tokens MUST be honored as part of
+ the legal syntax. In this sense, section 3 defines a grammar for
+ generation of messages, with "obs-" elements that are to be ignored,
+ while section 4 adds grammar for interpretation of messages.
+
+3.2. Lexical Tokens
+
+ The following rules are used to define an underlying lexical
+ analyzer, which feeds tokens to the higher-level parsers. This
+ section defines the tokens used in structured header field bodies.
+
+ Note: Readers of this standard need to pay special attention to how
+ these lexical tokens are used in both the lower-level and
+ higher-level syntax later in the document. Particularly, the white
+ space tokens and the comment tokens defined in section 3.2.3 get used
+ in the lower-level tokens defined here, and those lower-level tokens
+ are in turn used as parts of the higher-level tokens defined later.
+ Therefore, the white space and comments may be allowed in the
+ higher-level tokens even though they may not explicitly appear in a
+ particular definition.
+
+3.2.1. Primitive Tokens
+
+ The following are primitive tokens referred to elsewhere in this
+ standard, but not otherwise defined in [RFC2234]. Some of them will
+ not appear anywhere else in the syntax, but they are convenient to
+ refer to in other parts of this document.
+
+
+
+
+Resnick Standards Track [Page 9]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ Note: The "specials" below are just such an example. Though the
+ specials token does not appear anywhere else in this standard, it is
+ useful for implementers who use tools that lexically analyze
+ messages. Each of the characters in specials can be used to indicate
+ a tokenization point in lexical analysis.
+
+NO-WS-CTL = %d1-8 / ; US-ASCII control characters
+ %d11 / ; that do not include the
+ %d12 / ; carriage return, line feed,
+ %d14-31 / ; and white space characters
+ %d127
+
+text = %d1-9 / ; Characters excluding CR and LF
+ %d11 /
+ %d12 /
+ %d14-127 /
+ obs-text
+
+specials = "(" / ")" / ; Special characters used in
+ "<" / ">" / ; other parts of the syntax
+ "[" / "]" /
+ ":" / ";" /
+ "@" / "\" /
+ "," / "." /
+ DQUOTE
+
+ No special semantics are attached to these tokens. They are simply
+ single characters.
+
+3.2.2. Quoted characters
+
+ Some characters are reserved for special interpretation, such as
+ delimiting lexical tokens. To permit use of these characters as
+ uninterpreted data, a quoting mechanism is provided.
+
+quoted-pair = ("\" text) / obs-qp
+
+ Where any quoted-pair appears, it is to be interpreted as the text
+ character alone. That is to say, the "\" character that appears as
+ part of a quoted-pair is semantically "invisible".
+
+ Note: The "\" character may appear in a message where it is not part
+ of a quoted-pair. A "\" character that does not appear in a
+ quoted-pair is not semantically invisible. The only places in this
+ standard where quoted-pair currently appears are ccontent, qcontent,
+ dcontent, no-fold-quote, and no-fold-literal.
+
+
+
+
+
+Resnick Standards Track [Page 10]
+
+RFC 2822 Internet Message Format April 2001
+
+
+3.2.3. Folding white space and comments
+
+ White space characters, including white space used in folding
+ (described in section 2.2.3), may appear between many elements in
+ header field bodies. Also, strings of characters that are treated as
+ comments may be included in structured field bodies as characters
+ enclosed in parentheses. The following defines the folding white
+ space (FWS) and comment constructs.
+
+ Strings of characters enclosed in parentheses are considered comments
+ so long as they do not appear within a "quoted-string", as defined in
+ section 3.2.5. Comments may nest.
+
+ There are several places in this standard where comments and FWS may
+ be freely inserted. To accommodate that syntax, an additional token
+ for "CFWS" is defined for places where comments and/or FWS can occur.
+ However, where CFWS occurs in this standard, it MUST NOT be inserted
+ in such a way that any line of a folded header field is made up
+ entirely of WSP characters and nothing else.
+
+FWS = ([*WSP CRLF] 1*WSP) / ; Folding white space
+ obs-FWS
+
+ctext = NO-WS-CTL / ; Non white space controls
+
+ %d33-39 / ; The rest of the US-ASCII
+ %d42-91 / ; characters not including "(",
+ %d93-126 ; ")", or "\"
+
+ccontent = ctext / quoted-pair / comment
+
+comment = "(" *([FWS] ccontent) [FWS] ")"
+
+CFWS = *([FWS] comment) (([FWS] comment) / FWS)
+
+ Throughout this standard, where FWS (the folding white space token)
+ appears, it indicates a place where header folding, as discussed in
+ section 2.2.3, may take place. Wherever header folding appears in a
+ message (that is, a header field body containing a CRLF followed by
+ any WSP), header unfolding (removal of the CRLF) is performed before
+ any further lexical analysis is performed on that header field
+ according to this standard. That is to say, any CRLF that appears in
+ FWS is semantically "invisible."
+
+ A comment is normally used in a structured field body to provide some
+ human readable informational text. Since a comment is allowed to
+ contain FWS, folding is permitted within the comment. Also note that
+ since quoted-pair is allowed in a comment, the parentheses and
+
+
+
+Resnick Standards Track [Page 11]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ backslash characters may appear in a comment so long as they appear
+ as a quoted-pair. Semantically, the enclosing parentheses are not
+ part of the comment; the comment is what is contained between the two
+ parentheses. As stated earlier, the "\" in any quoted-pair and the
+ CRLF in any FWS that appears within the comment are semantically
+ "invisible" and therefore not part of the comment either.
+
+ Runs of FWS, comment or CFWS that occur between lexical tokens in a
+ structured field header are semantically interpreted as a single
+ space character.
+
+3.2.4. Atom
+
+ Several productions in structured header field bodies are simply
+ strings of certain basic characters. Such productions are called
+ atoms.
+
+ Some of the structured header field bodies also allow the period
+ character (".", ASCII value 46) within runs of atext. An additional
+ "dot-atom" token is defined for those purposes.
+
+atext = ALPHA / DIGIT / ; Any character except controls,
+ "!" / "#" / ; SP, and specials.
+ "$" / "%" / ; Used for atoms
+ "&" / "'" /
+ "*" / "+" /
+ "-" / "/" /
+ "=" / "?" /
+ "^" / "_" /
+ "`" / "{" /
+ "|" / "}" /
+ "~"
+
+atom = [CFWS] 1*atext [CFWS]
+
+dot-atom = [CFWS] dot-atom-text [CFWS]
+
+dot-atom-text = 1*atext *("." 1*atext)
+
+ Both atom and dot-atom are interpreted as a single unit, comprised of
+ the string of characters that make it up. Semantically, the optional
+ comments and FWS surrounding the rest of the characters are not part
+ of the atom; the atom is only the run of atext characters in an atom,
+ or the atext and "." characters in a dot-atom.
+
+
+
+
+
+
+
+Resnick Standards Track [Page 12]
+
+RFC 2822 Internet Message Format April 2001
+
+
+3.2.5. Quoted strings
+
+ Strings of characters that include characters other than those
+ allowed in atoms may be represented in a quoted string format, where
+ the characters are surrounded by quote (DQUOTE, ASCII value 34)
+ characters.
+
+qtext = NO-WS-CTL / ; Non white space controls
+
+ %d33 / ; The rest of the US-ASCII
+ %d35-91 / ; characters not including "\"
+ %d93-126 ; or the quote character
+
+qcontent = qtext / quoted-pair
+
+quoted-string = [CFWS]
+ DQUOTE *([FWS] qcontent) [FWS] DQUOTE
+ [CFWS]
+
+ A quoted-string is treated as a unit. That is, quoted-string is
+ identical to atom, semantically. Since a quoted-string is allowed to
+ contain FWS, folding is permitted. Also note that since quoted-pair
+ is allowed in a quoted-string, the quote and backslash characters may
+ appear in a quoted-string so long as they appear as a quoted-pair.
+
+ Semantically, neither the optional CFWS outside of the quote
+ characters nor the quote characters themselves are part of the
+ quoted-string; the quoted-string is what is contained between the two
+ quote characters. As stated earlier, the "\" in any quoted-pair and
+ the CRLF in any FWS/CFWS that appears within the quoted-string are
+ semantically "invisible" and therefore not part of the quoted-string
+ either.
+
+3.2.6. Miscellaneous tokens
+
+ Three additional tokens are defined, word and phrase for combinations
+ of atoms and/or quoted-strings, and unstructured for use in
+ unstructured header fields and in some places within structured
+ header fields.
+
+word = atom / quoted-string
+
+phrase = 1*word / obs-phrase
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 13]
+
+RFC 2822 Internet Message Format April 2001
+
+
+utext = NO-WS-CTL / ; Non white space controls
+ %d33-126 / ; The rest of US-ASCII
+ obs-utext
+
+unstructured = *([FWS] utext) [FWS]
+
+3.3. Date and Time Specification
+
+ Date and time occur in several header fields. This section specifies
+ the syntax for a full date and time specification. Though folding
+ white space is permitted throughout the date-time specification, it
+ is RECOMMENDED that a single space be used in each place that FWS
+ appears (whether it is required or optional); some older
+ implementations may not interpret other occurrences of folding white
+ space correctly.
+
+date-time = [ day-of-week "," ] date FWS time [CFWS]
+
+day-of-week = ([FWS] day-name) / obs-day-of-week
+
+day-name = "Mon" / "Tue" / "Wed" / "Thu" /
+ "Fri" / "Sat" / "Sun"
+
+date = day month year
+
+year = 4*DIGIT / obs-year
+
+month = (FWS month-name FWS) / obs-month
+
+month-name = "Jan" / "Feb" / "Mar" / "Apr" /
+ "May" / "Jun" / "Jul" / "Aug" /
+ "Sep" / "Oct" / "Nov" / "Dec"
+
+day = ([FWS] 1*2DIGIT) / obs-day
+
+time = time-of-day FWS zone
+
+time-of-day = hour ":" minute [ ":" second ]
+
+hour = 2DIGIT / obs-hour
+
+minute = 2DIGIT / obs-minute
+
+second = 2DIGIT / obs-second
+
+zone = (( "+" / "-" ) 4DIGIT) / obs-zone
+
+
+
+
+
+Resnick Standards Track [Page 14]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ The day is the numeric day of the month. The year is any numeric
+ year 1900 or later.
+
+ The time-of-day specifies the number of hours, minutes, and
+ optionally seconds since midnight of the date indicated.
+
+ The date and time-of-day SHOULD express local time.
+
+ The zone specifies the offset from Coordinated Universal Time (UTC,
+ formerly referred to as "Greenwich Mean Time") that the date and
+ time-of-day represent. The "+" or "-" indicates whether the
+ time-of-day is ahead of (i.e., east of) or behind (i.e., west of)
+ Universal Time. The first two digits indicate the number of hours
+ difference from Universal Time, and the last two digits indicate the
+ number of minutes difference from Universal Time. (Hence, +hhmm
+ means +(hh * 60 + mm) minutes, and -hhmm means -(hh * 60 + mm)
+ minutes). The form "+0000" SHOULD be used to indicate a time zone at
+ Universal Time. Though "-0000" also indicates Universal Time, it is
+ used to indicate that the time was generated on a system that may be
+ in a local time zone other than Universal Time and therefore
+ indicates that the date-time contains no information about the local
+ time zone.
+
+ A date-time specification MUST be semantically valid. That is, the
+ day-of-the-week (if included) MUST be the day implied by the date,
+ the numeric day-of-month MUST be between 1 and the number of days
+ allowed for the specified month (in the specified year), the
+ time-of-day MUST be in the range 00:00:00 through 23:59:60 (the
+ number of seconds allowing for a leap second; see [STD12]), and the
+ zone MUST be within the range -9959 through +9959.
+
+3.4. Address Specification
+
+ Addresses occur in several message header fields to indicate senders
+ and recipients of messages. An address may either be an individual
+ mailbox, or a group of mailboxes.
+
+address = mailbox / group
+
+mailbox = name-addr / addr-spec
+
+name-addr = [display-name] angle-addr
+
+angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
+
+group = display-name ":" [mailbox-list / CFWS] ";"
+ [CFWS]
+
+
+
+
+Resnick Standards Track [Page 15]
+
+RFC 2822 Internet Message Format April 2001
+
+
+display-name = phrase
+
+mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list
+
+address-list = (address *("," address)) / obs-addr-list
+
+ A mailbox receives mail. It is a conceptual entity which does not
+ necessarily pertain to file storage. For example, some sites may
+ choose to print mail on a printer and deliver the output to the
+ addressee's desk. Normally, a mailbox is comprised of two parts: (1)
+ an optional display name that indicates the name of the recipient
+ (which could be a person or a system) that could be displayed to the
+ user of a mail application, and (2) an addr-spec address enclosed in
+ angle brackets ("<" and ">"). There is also an alternate simple form
+ of a mailbox where the addr-spec address appears alone, without the
+ recipient's name or the angle brackets. The Internet addr-spec
+ address is described in section 3.4.1.
+
+ Note: Some legacy implementations used the simple form where the
+ addr-spec appears without the angle brackets, but included the name
+ of the recipient in parentheses as a comment following the addr-spec.
+ Since the meaning of the information in a comment is unspecified,
+ implementations SHOULD use the full name-addr form of the mailbox,
+ instead of the legacy form, to specify the display name associated
+ with a mailbox. Also, because some legacy implementations interpret
+ the comment, comments generally SHOULD NOT be used in address fields
+ to avoid confusing such implementations.
+
+ When it is desirable to treat several mailboxes as a single unit
+ (i.e., in a distribution list), the group construct can be used. The
+ group construct allows the sender to indicate a named group of
+ recipients. This is done by giving a display name for the group,
+ followed by a colon, followed by a comma separated list of any number
+ of mailboxes (including zero and one), and ending with a semicolon.
+ Because the list of mailboxes can be empty, using the group construct
+ is also a simple way to communicate to recipients that the message
+ was sent to one or more named sets of recipients, without actually
+ providing the individual mailbox address for each of those
+ recipients.
+
+3.4.1. Addr-spec specification
+
+ An addr-spec is a specific Internet identifier that contains a
+ locally interpreted string followed by the at-sign character ("@",
+ ASCII value 64) followed by an Internet domain. The locally
+ interpreted string is either a quoted-string or a dot-atom. If the
+ string can be represented as a dot-atom (that is, it contains no
+ characters other than atext characters or "." surrounded by atext
+
+
+
+Resnick Standards Track [Page 16]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ characters), then the dot-atom form SHOULD be used and the
+ quoted-string form SHOULD NOT be used. Comments and folding white
+ space SHOULD NOT be used around the "@" in the addr-spec.
+
+addr-spec = local-part "@" domain
+
+local-part = dot-atom / quoted-string / obs-local-part
+
+domain = dot-atom / domain-literal / obs-domain
+
+domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
+
+dcontent = dtext / quoted-pair
+
+dtext = NO-WS-CTL / ; Non white space controls
+
+ %d33-90 / ; The rest of the US-ASCII
+ %d94-126 ; characters not including "[",
+ ; "]", or "\"
+
+ The domain portion identifies the point to which the mail is
+ delivered. In the dot-atom form, this is interpreted as an Internet
+ domain name (either a host name or a mail exchanger name) as
+ described in [STD3, STD13, STD14]. In the domain-literal form, the
+ domain is interpreted as the literal Internet address of the
+ particular host. In both cases, how addressing is used and how
+ messages are transported to a particular host is covered in the mail
+ transport document [RFC2821]. These mechanisms are outside of the
+ scope of this document.
+
+ The local-part portion is a domain dependent string. In addresses,
+ it is simply interpreted on the particular host as a name of a
+ particular mailbox.
+
+3.5 Overall message syntax
+
+ A message consists of header fields, optionally followed by a message
+ body. Lines in a message MUST be a maximum of 998 characters
+ excluding the CRLF, but it is RECOMMENDED that lines be limited to 78
+ characters excluding the CRLF. (See section 2.1.1 for explanation.)
+ In a message body, though all of the characters listed in the text
+ rule MAY be used, the use of US-ASCII control characters (values 1
+ through 8, 11, 12, and 14 through 31) is discouraged since their
+ interpretation by receivers for display is not guaranteed.
+
+
+
+
+
+
+
+Resnick Standards Track [Page 17]
+
+RFC 2822 Internet Message Format April 2001
+
+
+message = (fields / obs-fields)
+ [CRLF body]
+
+body = *(*998text CRLF) *998text
+
+ The header fields carry most of the semantic information and are
+ defined in section 3.6. The body is simply a series of lines of text
+ which are uninterpreted for the purposes of this standard.
+
+3.6. Field definitions
+
+ The header fields of a message are defined here. All header fields
+ have the same general syntactic structure: A field name, followed by
+ a colon, followed by the field body. The specific syntax for each
+ header field is defined in the subsequent sections.
+
+ Note: In the ABNF syntax for each field in subsequent sections, each
+ field name is followed by the required colon. However, for brevity
+ sometimes the colon is not referred to in the textual description of
+ the syntax. It is, nonetheless, required.
+
+ It is important to note that the header fields are not guaranteed to
+ be in a particular order. They may appear in any order, and they
+ have been known to be reordered occasionally when transported over
+ the Internet. However, for the purposes of this standard, header
+ fields SHOULD NOT be reordered when a message is transported or
+ transformed. More importantly, the trace header fields and resent
+ header fields MUST NOT be reordered, and SHOULD be kept in blocks
+ prepended to the message. See sections 3.6.6 and 3.6.7 for more
+ information.
+
+ The only required header fields are the origination date field and
+ the originator address field(s). All other header fields are
+ syntactically optional. More information is contained in the table
+ following this definition.
+
+fields = *(trace
+ *(resent-date /
+ resent-from /
+ resent-sender /
+ resent-to /
+ resent-cc /
+ resent-bcc /
+ resent-msg-id))
+ *(orig-date /
+ from /
+ sender /
+ reply-to /
+
+
+
+Resnick Standards Track [Page 18]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ to /
+ cc /
+ bcc /
+ message-id /
+ in-reply-to /
+ references /
+ subject /
+ comments /
+ keywords /
+ optional-field)
+
+ The following table indicates limits on the number of times each
+ field may occur in a message header as well as any special
+ limitations on the use of those fields. An asterisk next to a value
+ in the minimum or maximum column indicates that a special restriction
+ appears in the Notes column.
+
+Field Min number Max number Notes
+
+trace 0 unlimited Block prepended - see
+ 3.6.7
+
+resent-date 0* unlimited* One per block, required
+ if other resent fields
+ present - see 3.6.6
+
+resent-from 0 unlimited* One per block - see
+ 3.6.6
+
+resent-sender 0* unlimited* One per block, MUST
+ occur with multi-address
+ resent-from - see 3.6.6
+
+resent-to 0 unlimited* One per block - see
+ 3.6.6
+
+resent-cc 0 unlimited* One per block - see
+ 3.6.6
+
+resent-bcc 0 unlimited* One per block - see
+ 3.6.6
+
+resent-msg-id 0 unlimited* One per block - see
+ 3.6.6
+
+orig-date 1 1
+
+from 1 1 See sender and 3.6.2
+
+
+
+Resnick Standards Track [Page 19]
+
+RFC 2822 Internet Message Format April 2001
+
+
+sender 0* 1 MUST occur with multi-
+ address from - see 3.6.2
+
+reply-to 0 1
+
+to 0 1
+
+cc 0 1
+
+bcc 0 1
+
+message-id 0* 1 SHOULD be present - see
+ 3.6.4
+
+in-reply-to 0* 1 SHOULD occur in some
+ replies - see 3.6.4
+
+references 0* 1 SHOULD occur in some
+ replies - see 3.6.4
+
+subject 0 1
+
+comments 0 unlimited
+
+keywords 0 unlimited
+
+optional-field 0 unlimited
+
+ The exact interpretation of each field is described in subsequent
+ sections.
+
+3.6.1. The origination date field
+
+ The origination date field consists of the field name "Date" followed
+ by a date-time specification.
+
+orig-date = "Date:" date-time CRLF
+
+ The origination date specifies the date and time at which the creator
+ of the message indicated that the message was complete and ready to
+ enter the mail delivery system. For instance, this might be the time
+ that a user pushes the "send" or "submit" button in an application
+ program. In any case, it is specifically not intended to convey the
+ time that the message is actually transported, but rather the time at
+ which the human or other creator of the message has put the message
+ into its final form, ready for transport. (For example, a portable
+ computer user who is not connected to a network might queue a message
+
+
+
+
+Resnick Standards Track [Page 20]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ for delivery. The origination date is intended to contain the date
+ and time that the user queued the message, not the time when the user
+ connected to the network to send the message.)
+
+3.6.2. Originator fields
+
+ The originator fields of a message consist of the from field, the
+ sender field (when applicable), and optionally the reply-to field.
+ The from field consists of the field name "From" and a
+ comma-separated list of one or more mailbox specifications. If the
+ from field contains more than one mailbox specification in the
+ mailbox-list, then the sender field, containing the field name
+ "Sender" and a single mailbox specification, MUST appear in the
+ message. In either case, an optional reply-to field MAY also be
+ included, which contains the field name "Reply-To" and a
+ comma-separated list of one or more addresses.
+
+from = "From:" mailbox-list CRLF
+
+sender = "Sender:" mailbox CRLF
+
+reply-to = "Reply-To:" address-list CRLF
+
+ The originator fields indicate the mailbox(es) of the source of the
+ message. The "From:" field specifies the author(s) of the message,
+ that is, the mailbox(es) of the person(s) or system(s) responsible
+ for the writing of the message. The "Sender:" field specifies the
+ mailbox of the agent responsible for the actual transmission of the
+ message. For example, if a secretary were to send a message for
+ another person, the mailbox of the secretary would appear in the
+ "Sender:" field and the mailbox of the actual author would appear in
+ the "From:" field. If the originator of the message can be indicated
+ by a single mailbox and the author and transmitter are identical, the
+ "Sender:" field SHOULD NOT be used. Otherwise, both fields SHOULD
+ appear.
+
+ The originator fields also provide the information required when
+ replying to a message. When the "Reply-To:" field is present, it
+ indicates the mailbox(es) to which the author of the message suggests
+ that replies be sent. In the absence of the "Reply-To:" field,
+ replies SHOULD by default be sent to the mailbox(es) specified in the
+ "From:" field unless otherwise specified by the person composing the
+ reply.
+
+ In all cases, the "From:" field SHOULD NOT contain any mailbox that
+ does not belong to the author(s) of the message. See also section
+ 3.6.3 for more information on forming the destination addresses for a
+ reply.
+
+
+
+Resnick Standards Track [Page 21]
+
+RFC 2822 Internet Message Format April 2001
+
+
+3.6.3. Destination address fields
+
+ The destination fields of a message consist of three possible fields,
+ each of the same form: The field name, which is either "To", "Cc", or
+ "Bcc", followed by a comma-separated list of one or more addresses
+ (either mailbox or group syntax).
+
+to = "To:" address-list CRLF
+
+cc = "Cc:" address-list CRLF
+
+bcc = "Bcc:" (address-list / [CFWS]) CRLF
+
+ The destination fields specify the recipients of the message. Each
+ destination field may have one or more addresses, and each of the
+ addresses indicate the intended recipients of the message. The only
+ difference between the three fields is how each is used.
+
+ The "To:" field contains the address(es) of the primary recipient(s)
+ of the message.
+
+ The "Cc:" field (where the "Cc" means "Carbon Copy" in the sense of
+ making a copy on a typewriter using carbon paper) contains the
+ addresses of others who are to receive the message, though the
+ content of the message may not be directed at them.
+
+ The "Bcc:" field (where the "Bcc" means "Blind Carbon Copy") contains
+ addresses of recipients of the message whose addresses are not to be
+ revealed to other recipients of the message. There are three ways in
+ which the "Bcc:" field is used. In the first case, when a message
+ containing a "Bcc:" field is prepared to be sent, the "Bcc:" line is
+ removed even though all of the recipients (including those specified
+ in the "Bcc:" field) are sent a copy of the message. In the second
+ case, recipients specified in the "To:" and "Cc:" lines each are sent
+ a copy of the message with the "Bcc:" line removed as above, but the
+ recipients on the "Bcc:" line get a separate copy of the message
+ containing a "Bcc:" line. (When there are multiple recipient
+ addresses in the "Bcc:" field, some implementations actually send a
+ separate copy of the message to each recipient with a "Bcc:"
+ containing only the address of that particular recipient.) Finally,
+ since a "Bcc:" field may contain no addresses, a "Bcc:" field can be
+ sent without any addresses indicating to the recipients that blind
+ copies were sent to someone. Which method to use with "Bcc:" fields
+ is implementation dependent, but refer to the "Security
+ Considerations" section of this document for a discussion of each.
+
+
+
+
+
+
+Resnick Standards Track [Page 22]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ When a message is a reply to another message, the mailboxes of the
+ authors of the original message (the mailboxes in the "From:" field)
+ or mailboxes specified in the "Reply-To:" field (if it exists) MAY
+ appear in the "To:" field of the reply since these would normally be
+ the primary recipients of the reply. If a reply is sent to a message
+ that has destination fields, it is often desirable to send a copy of
+ the reply to all of the recipients of the message, in addition to the
+ author. When such a reply is formed, addresses in the "To:" and
+ "Cc:" fields of the original message MAY appear in the "Cc:" field of
+ the reply, since these are normally secondary recipients of the
+ reply. If a "Bcc:" field is present in the original message,
+ addresses in that field MAY appear in the "Bcc:" field of the reply,
+ but SHOULD NOT appear in the "To:" or "Cc:" fields.
+
+ Note: Some mail applications have automatic reply commands that
+ include the destination addresses of the original message in the
+ destination addresses of the reply. How those reply commands behave
+ is implementation dependent and is beyond the scope of this document.
+ In particular, whether or not to include the original destination
+ addresses when the original message had a "Reply-To:" field is not
+ addressed here.
+
+3.6.4. Identification fields
+
+ Though optional, every message SHOULD have a "Message-ID:" field.
+ Furthermore, reply messages SHOULD have "In-Reply-To:" and
+ "References:" fields as appropriate, as described below.
+
+ The "Message-ID:" field contains a single unique message identifier.
+ The "References:" and "In-Reply-To:" field each contain one or more
+ unique message identifiers, optionally separated by CFWS.
+
+ The message identifier (msg-id) is similar in syntax to an angle-addr
+ construct without the internal CFWS.
+
+message-id = "Message-ID:" msg-id CRLF
+
+in-reply-to = "In-Reply-To:" 1*msg-id CRLF
+
+references = "References:" 1*msg-id CRLF
+
+msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
+
+id-left = dot-atom-text / no-fold-quote / obs-id-left
+
+id-right = dot-atom-text / no-fold-literal / obs-id-right
+
+no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE
+
+
+
+Resnick Standards Track [Page 23]
+
+RFC 2822 Internet Message Format April 2001
+
+
+no-fold-literal = "[" *(dtext / quoted-pair) "]"
+
+ The "Message-ID:" field provides a unique message identifier that
+ refers to a particular version of a particular message. The
+ uniqueness of the message identifier is guaranteed by the host that
+ generates it (see below). This message identifier is intended to be
+ machine readable and not necessarily meaningful to humans. A message
+ identifier pertains to exactly one instantiation of a particular
+ message; subsequent revisions to the message each receive new message
+ identifiers.
+
+ Note: There are many instances when messages are "changed", but those
+ changes do not constitute a new instantiation of that message, and
+ therefore the message would not get a new message identifier. For
+ example, when messages are introduced into the transport system, they
+ are often prepended with additional header fields such as trace
+ fields (described in section 3.6.7) and resent fields (described in
+ section 3.6.6). The addition of such header fields does not change
+ the identity of the message and therefore the original "Message-ID:"
+ field is retained. In all cases, it is the meaning that the sender
+ of the message wishes to convey (i.e., whether this is the same
+ message or a different message) that determines whether or not the
+ "Message-ID:" field changes, not any particular syntactic difference
+ that appears (or does not appear) in the message.
+
+ The "In-Reply-To:" and "References:" fields are used when creating a
+ reply to a message. They hold the message identifier of the original
+ message and the message identifiers of other messages (for example,
+ in the case of a reply to a message which was itself a reply). The
+ "In-Reply-To:" field may be used to identify the message (or
+ messages) to which the new message is a reply, while the
+ "References:" field may be used to identify a "thread" of
+ conversation.
+
+ When creating a reply to a message, the "In-Reply-To:" and
+ "References:" fields of the resultant message are constructed as
+ follows:
+
+ The "In-Reply-To:" field will contain the contents of the "Message-
+ ID:" field of the message to which this one is a reply (the "parent
+ message"). If there is more than one parent message, then the "In-
+ Reply-To:" field will contain the contents of all of the parents'
+ "Message-ID:" fields. If there is no "Message-ID:" field in any of
+ the parent messages, then the new message will have no "In-Reply-To:"
+ field.
+
+
+
+
+
+
+Resnick Standards Track [Page 24]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ The "References:" field will contain the contents of the parent's
+ "References:" field (if any) followed by the contents of the parent's
+ "Message-ID:" field (if any). If the parent message does not contain
+ a "References:" field but does have an "In-Reply-To:" field
+ containing a single message identifier, then the "References:" field
+ will contain the contents of the parent's "In-Reply-To:" field
+ followed by the contents of the parent's "Message-ID:" field (if
+ any). If the parent has none of the "References:", "In-Reply-To:",
+ or "Message-ID:" fields, then the new message will have no
+ "References:" field.
+
+ Note: Some implementations parse the "References:" field to display
+ the "thread of the discussion". These implementations assume that
+ each new message is a reply to a single parent and hence that they
+ can walk backwards through the "References:" field to find the parent
+ of each message listed there. Therefore, trying to form a
+ "References:" field for a reply that has multiple parents is
+ discouraged and how to do so is not defined in this document.
+
+ The message identifier (msg-id) itself MUST be a globally unique
+ identifier for a message. The generator of the message identifier
+ MUST guarantee that the msg-id is unique. There are several
+ algorithms that can be used to accomplish this. Since the msg-id has
+ a similar syntax to angle-addr (identical except that comments and
+ folding white space are not allowed), a good method is to put the
+ domain name (or a domain literal IP address) of the host on which the
+ message identifier was created on the right hand side of the "@", and
+ put a combination of the current absolute date and time along with
+ some other currently unique (perhaps sequential) identifier available
+ on the system (for example, a process id number) on the left hand
+ side. Using a date on the left hand side and a domain name or domain
+ literal on the right hand side makes it possible to guarantee
+ uniqueness since no two hosts use the same domain name or IP address
+ at the same time. Though other algorithms will work, it is
+ RECOMMENDED that the right hand side contain some domain identifier
+ (either of the host itself or otherwise) such that the generator of
+ the message identifier can guarantee the uniqueness of the left hand
+ side within the scope of that domain.
+
+ Semantically, the angle bracket characters are not part of the
+ msg-id; the msg-id is what is contained between the two angle bracket
+ characters.
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 25]
+
+RFC 2822 Internet Message Format April 2001
+
+
+3.6.5. Informational fields
+
+ The informational fields are all optional. The "Keywords:" field
+ contains a comma-separated list of one or more words or
+ quoted-strings. The "Subject:" and "Comments:" fields are
+ unstructured fields as defined in section 2.2.1, and therefore may
+ contain text or folding white space.
+
+subject = "Subject:" unstructured CRLF
+
+comments = "Comments:" unstructured CRLF
+
+keywords = "Keywords:" phrase *("," phrase) CRLF
+
+ These three fields are intended to have only human-readable content
+ with information about the message. The "Subject:" field is the most
+ common and contains a short string identifying the topic of the
+ message. When used in a reply, the field body MAY start with the
+ string "Re: " (from the Latin "res", in the matter of) followed by
+ the contents of the "Subject:" field body of the original message.
+ If this is done, only one instance of the literal string "Re: " ought
+ to be used since use of other strings or more than one instance can
+ lead to undesirable consequences. The "Comments:" field contains any
+ additional comments on the text of the body of the message. The
+ "Keywords:" field contains a comma-separated list of important words
+ and phrases that might be useful for the recipient.
+
+3.6.6. Resent fields
+
+ Resent fields SHOULD be added to any message that is reintroduced by
+ a user into the transport system. A separate set of resent fields
+ SHOULD be added each time this is done. All of the resent fields
+ corresponding to a particular resending of the message SHOULD be
+ together. Each new set of resent fields is prepended to the message;
+ that is, the most recent set of resent fields appear earlier in the
+ message. No other fields in the message are changed when resent
+ fields are added.
+
+ Each of the resent fields corresponds to a particular field elsewhere
+ in the syntax. For instance, the "Resent-Date:" field corresponds to
+ the "Date:" field and the "Resent-To:" field corresponds to the "To:"
+ field. In each case, the syntax for the field body is identical to
+ the syntax given previously for the corresponding field.
+
+ When resent fields are used, the "Resent-From:" and "Resent-Date:"
+ fields MUST be sent. The "Resent-Message-ID:" field SHOULD be sent.
+ "Resent-Sender:" SHOULD NOT be used if "Resent-Sender:" would be
+ identical to "Resent-From:".
+
+
+
+Resnick Standards Track [Page 26]
+
+RFC 2822 Internet Message Format April 2001
+
+
+resent-date = "Resent-Date:" date-time CRLF
+
+resent-from = "Resent-From:" mailbox-list CRLF
+
+resent-sender = "Resent-Sender:" mailbox CRLF
+
+resent-to = "Resent-To:" address-list CRLF
+
+resent-cc = "Resent-Cc:" address-list CRLF
+
+resent-bcc = "Resent-Bcc:" (address-list / [CFWS]) CRLF
+
+resent-msg-id = "Resent-Message-ID:" msg-id CRLF
+
+ Resent fields are used to identify a message as having been
+ reintroduced into the transport system by a user. The purpose of
+ using resent fields is to have the message appear to the final
+ recipient as if it were sent directly by the original sender, with
+ all of the original fields remaining the same. Each set of resent
+ fields correspond to a particular resending event. That is, if a
+ message is resent multiple times, each set of resent fields gives
+ identifying information for each individual time. Resent fields are
+ strictly informational. They MUST NOT be used in the normal
+ processing of replies or other such automatic actions on messages.
+
+ Note: Reintroducing a message into the transport system and using
+ resent fields is a different operation from "forwarding".
+ "Forwarding" has two meanings: One sense of forwarding is that a mail
+ reading program can be told by a user to forward a copy of a message
+ to another person, making the forwarded message the body of the new
+ message. A forwarded message in this sense does not appear to have
+ come from the original sender, but is an entirely new message from
+ the forwarder of the message. On the other hand, forwarding is also
+ used to mean when a mail transport program gets a message and
+ forwards it on to a different destination for final delivery. Resent
+ header fields are not intended for use with either type of
+ forwarding.
+
+ The resent originator fields indicate the mailbox of the person(s) or
+ system(s) that resent the message. As with the regular originator
+ fields, there are two forms: a simple "Resent-From:" form which
+ contains the mailbox of the individual doing the resending, and the
+ more complex form, when one individual (identified in the
+ "Resent-Sender:" field) resends a message on behalf of one or more
+ others (identified in the "Resent-From:" field).
+
+ Note: When replying to a resent message, replies behave just as they
+ would with any other message, using the original "From:",
+
+
+
+Resnick Standards Track [Page 27]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ "Reply-To:", "Message-ID:", and other fields. The resent fields are
+ only informational and MUST NOT be used in the normal processing of
+ replies.
+
+ The "Resent-Date:" indicates the date and time at which the resent
+ message is dispatched by the resender of the message. Like the
+ "Date:" field, it is not the date and time that the message was
+ actually transported.
+
+ The "Resent-To:", "Resent-Cc:", and "Resent-Bcc:" fields function
+ identically to the "To:", "Cc:", and "Bcc:" fields respectively,
+ except that they indicate the recipients of the resent message, not
+ the recipients of the original message.
+
+ The "Resent-Message-ID:" field provides a unique identifier for the
+ resent message.
+
+3.6.7. Trace fields
+
+ The trace fields are a group of header fields consisting of an
+ optional "Return-Path:" field, and one or more "Received:" fields.
+ The "Return-Path:" header field contains a pair of angle brackets
+ that enclose an optional addr-spec. The "Received:" field contains a
+ (possibly empty) list of name/value pairs followed by a semicolon and
+ a date-time specification. The first item of the name/value pair is
+ defined by item-name, and the second item is either an addr-spec, an
+ atom, a domain, or a msg-id. Further restrictions may be applied to
+ the syntax of the trace fields by standards that provide for their
+ use, such as [RFC2821].
+
+trace = [return]
+ 1*received
+
+return = "Return-Path:" path CRLF
+
+path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) /
+ obs-path
+
+received = "Received:" name-val-list ";" date-time CRLF
+
+name-val-list = [CFWS] [name-val-pair *(CFWS name-val-pair)]
+
+name-val-pair = item-name CFWS item-value
+
+item-name = ALPHA *(["-"] (ALPHA / DIGIT))
+
+item-value = 1*angle-addr / addr-spec /
+ atom / domain / msg-id
+
+
+
+Resnick Standards Track [Page 28]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ A full discussion of the Internet mail use of trace fields is
+ contained in [RFC2821]. For the purposes of this standard, the trace
+ fields are strictly informational, and any formal interpretation of
+ them is outside of the scope of this document.
+
+3.6.8. Optional fields
+
+ Fields may appear in messages that are otherwise unspecified in this
+ standard. They MUST conform to the syntax of an optional-field.
+ This is a field name, made up of the printable US-ASCII characters
+ except SP and colon, followed by a colon, followed by any text which
+ conforms to unstructured.
+
+ The field names of any optional-field MUST NOT be identical to any
+ field name specified elsewhere in this standard.
+
+optional-field = field-name ":" unstructured CRLF
+
+field-name = 1*ftext
+
+ftext = %d33-57 / ; Any character except
+ %d59-126 ; controls, SP, and
+ ; ":".
+
+ For the purposes of this standard, any optional field is
+ uninterpreted.
+
+4. Obsolete Syntax
+
+ Earlier versions of this standard allowed for different (usually more
+ liberal) syntax than is allowed in this version. Also, there have
+ been syntactic elements used in messages on the Internet whose
+ interpretation have never been documented. Though some of these
+ syntactic forms MUST NOT be generated according to the grammar in
+ section 3, they MUST be accepted and parsed by a conformant receiver.
+ This section documents many of these syntactic elements. Taking the
+ grammar in section 3 and adding the definitions presented in this
+ section will result in the grammar to use for interpretation of
+ messages.
+
+ Note: This section identifies syntactic forms that any implementation
+ MUST reasonably interpret. However, there are certainly Internet
+ messages which do not conform to even the additional syntax given in
+ this section. The fact that a particular form does not appear in any
+ section of this document is not justification for computer programs
+ to crash or for malformed data to be irretrievably lost by any
+ implementation. To repeat an example, though this document requires
+ lines in messages to be no longer than 998 characters, silently
+
+
+
+Resnick Standards Track [Page 29]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ discarding the 999th and subsequent characters in a line without
+ warning would still be bad behavior for an implementation. It is up
+ to the implementation to deal with messages robustly.
+
+ One important difference between the obsolete (interpreting) and the
+ current (generating) syntax is that in structured header field bodies
+ (i.e., between the colon and the CRLF of any structured header
+ field), white space characters, including folding white space, and
+ comments can be freely inserted between any syntactic tokens. This
+ allows many complex forms that have proven difficult for some
+ implementations to parse.
+
+ Another key difference between the obsolete and the current syntax is
+ that the rule in section 3.2.3 regarding lines composed entirely of
+ white space in comments and folding white space does not apply. See
+ the discussion of folding white space in section 4.2 below.
+
+ Finally, certain characters that were formerly allowed in messages
+ appear in this section. The NUL character (ASCII value 0) was once
+ allowed, but is no longer for compatibility reasons. CR and LF were
+ allowed to appear in messages other than as CRLF; this use is also
+ shown here.
+
+ Other differences in syntax and semantics are noted in the following
+ sections.
+
+4.1. Miscellaneous obsolete tokens
+
+ These syntactic elements are used elsewhere in the obsolete syntax or
+ in the main syntax. The obs-char and obs-qp elements each add ASCII
+ value 0. Bare CR and bare LF are added to obs-text and obs-utext.
+ The period character is added to obs-phrase. The obs-phrase-list
+ provides for "empty" elements in a comma-separated list of phrases.
+
+ Note: The "period" (or "full stop") character (".") in obs-phrase is
+ not a form that was allowed in earlier versions of this or any other
+ standard. Period (nor any other character from specials) was not
+ allowed in phrase because it introduced a parsing difficulty
+ distinguishing between phrases and portions of an addr-spec (see
+ section 4.4). It appears here because the period character is
+ currently used in many messages in the display-name portion of
+ addresses, especially for initials in names, and therefore must be
+ interpreted properly. In the future, period may appear in the
+ regular syntax of phrase.
+
+obs-qp = "\" (%d0-127)
+
+obs-text = *LF *CR *(obs-char *LF *CR)
+
+
+
+Resnick Standards Track [Page 30]
+
+RFC 2822 Internet Message Format April 2001
+
+
+obs-char = %d0-9 / %d11 / ; %d0-127 except CR and
+ %d12 / %d14-127 ; LF
+
+obs-utext = obs-text
+
+obs-phrase = word *(word / "." / CFWS)
+
+obs-phrase-list = phrase / 1*([phrase] [CFWS] "," [CFWS]) [phrase]
+
+ Bare CR and bare LF appear in messages with two different meanings.
+ In many cases, bare CR or bare LF are used improperly instead of CRLF
+ to indicate line separators. In other cases, bare CR and bare LF are
+ used simply as ASCII control characters with their traditional ASCII
+ meanings.
+
+4.2. Obsolete folding white space
+
+ In the obsolete syntax, any amount of folding white space MAY be
+ inserted where the obs-FWS rule is allowed. This creates the
+ possibility of having two consecutive "folds" in a line, and
+ therefore the possibility that a line which makes up a folded header
+ field could be composed entirely of white space.
+
+ obs-FWS = 1*WSP *(CRLF 1*WSP)
+
+4.3. Obsolete Date and Time
+
+ The syntax for the obsolete date format allows a 2 digit year in the
+ date field and allows for a list of alphabetic time zone
+ specifications that were used in earlier versions of this standard.
+ It also permits comments and folding white space between many of the
+ tokens.
+
+obs-day-of-week = [CFWS] day-name [CFWS]
+
+obs-year = [CFWS] 2*DIGIT [CFWS]
+
+obs-month = CFWS month-name CFWS
+
+obs-day = [CFWS] 1*2DIGIT [CFWS]
+
+obs-hour = [CFWS] 2DIGIT [CFWS]
+
+obs-minute = [CFWS] 2DIGIT [CFWS]
+
+obs-second = [CFWS] 2DIGIT [CFWS]
+
+obs-zone = "UT" / "GMT" / ; Universal Time
+
+
+
+Resnick Standards Track [Page 31]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ ; North American UT
+ ; offsets
+ "EST" / "EDT" / ; Eastern: - 5/ - 4
+ "CST" / "CDT" / ; Central: - 6/ - 5
+ "MST" / "MDT" / ; Mountain: - 7/ - 6
+ "PST" / "PDT" / ; Pacific: - 8/ - 7
+
+ %d65-73 / ; Military zones - "A"
+ %d75-90 / ; through "I" and "K"
+ %d97-105 / ; through "Z", both
+ %d107-122 ; upper and lower case
+
+ Where a two or three digit year occurs in a date, the year is to be
+ interpreted as follows: If a two digit year is encountered whose
+ value is between 00 and 49, the year is interpreted by adding 2000,
+ ending up with a value between 2000 and 2049. If a two digit year is
+ encountered with a value between 50 and 99, or any three digit year
+ is encountered, the year is interpreted by adding 1900.
+
+ In the obsolete time zone, "UT" and "GMT" are indications of
+ "Universal Time" and "Greenwich Mean Time" respectively and are both
+ semantically identical to "+0000".
+
+ The remaining three character zones are the US time zones. The first
+ letter, "E", "C", "M", or "P" stands for "Eastern", "Central",
+ "Mountain" and "Pacific". The second letter is either "S" for
+ "Standard" time, or "D" for "Daylight" (or summer) time. Their
+ interpretations are as follows:
+
+ EDT is semantically equivalent to -0400
+ EST is semantically equivalent to -0500
+ CDT is semantically equivalent to -0500
+ CST is semantically equivalent to -0600
+ MDT is semantically equivalent to -0600
+ MST is semantically equivalent to -0700
+ PDT is semantically equivalent to -0700
+ PST is semantically equivalent to -0800
+
+ The 1 character military time zones were defined in a non-standard
+ way in [RFC822] and are therefore unpredictable in their meaning.
+ The original definitions of the military zones "A" through "I" are
+ equivalent to "+0100" through "+0900" respectively; "K", "L", and "M"
+ are equivalent to "+1000", "+1100", and "+1200" respectively; "N"
+ through "Y" are equivalent to "-0100" through "-1200" respectively;
+ and "Z" is equivalent to "+0000". However, because of the error in
+ [RFC822], they SHOULD all be considered equivalent to "-0000" unless
+ there is out-of-band information confirming their meaning.
+
+
+
+
+Resnick Standards Track [Page 32]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ Other multi-character (usually between 3 and 5) alphabetic time zones
+ have been used in Internet messages. Any such time zone whose
+ meaning is not known SHOULD be considered equivalent to "-0000"
+ unless there is out-of-band information confirming their meaning.
+
+4.4. Obsolete Addressing
+
+ There are three primary differences in addressing. First, mailbox
+ addresses were allowed to have a route portion before the addr-spec
+ when enclosed in "<" and ">". The route is simply a comma-separated
+ list of domain names, each preceded by "@", and the list terminated
+ by a colon. Second, CFWS were allowed between the period-separated
+ elements of local-part and domain (i.e., dot-atom was not used). In
+ addition, local-part is allowed to contain quoted-string in addition
+ to just atom. Finally, mailbox-list and address-list were allowed to
+ have "null" members. That is, there could be two or more commas in
+ such a list with nothing in between them.
+
+obs-angle-addr = [CFWS] "<" [obs-route] addr-spec ">" [CFWS]
+
+obs-route = [CFWS] obs-domain-list ":" [CFWS]
+
+obs-domain-list = "@" domain *(*(CFWS / "," ) [CFWS] "@" domain)
+
+obs-local-part = word *("." word)
+
+obs-domain = atom *("." atom)
+
+obs-mbox-list = 1*([mailbox] [CFWS] "," [CFWS]) [mailbox]
+
+obs-addr-list = 1*([address] [CFWS] "," [CFWS]) [address]
+
+ When interpreting addresses, the route portion SHOULD be ignored.
+
+4.5. Obsolete header fields
+
+ Syntactically, the primary difference in the obsolete field syntax is
+ that it allows multiple occurrences of any of the fields and they may
+ occur in any order. Also, any amount of white space is allowed
+ before the ":" at the end of the field name.
+
+obs-fields = *(obs-return /
+ obs-received /
+ obs-orig-date /
+ obs-from /
+ obs-sender /
+ obs-reply-to /
+ obs-to /
+
+
+
+Resnick Standards Track [Page 33]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ obs-cc /
+ obs-bcc /
+ obs-message-id /
+ obs-in-reply-to /
+ obs-references /
+ obs-subject /
+ obs-comments /
+ obs-keywords /
+ obs-resent-date /
+ obs-resent-from /
+ obs-resent-send /
+ obs-resent-rply /
+ obs-resent-to /
+ obs-resent-cc /
+ obs-resent-bcc /
+ obs-resent-mid /
+ obs-optional)
+
+ Except for destination address fields (described in section 4.5.3),
+ the interpretation of multiple occurrences of fields is unspecified.
+ Also, the interpretation of trace fields and resent fields which do
+ not occur in blocks prepended to the message is unspecified as well.
+ Unless otherwise noted in the following sections, interpretation of
+ other fields is identical to the interpretation of their non-obsolete
+ counterparts in section 3.
+
+4.5.1. Obsolete origination date field
+
+obs-orig-date = "Date" *WSP ":" date-time CRLF
+
+4.5.2. Obsolete originator fields
+
+obs-from = "From" *WSP ":" mailbox-list CRLF
+
+obs-sender = "Sender" *WSP ":" mailbox CRLF
+
+obs-reply-to = "Reply-To" *WSP ":" mailbox-list CRLF
+
+4.5.3. Obsolete destination address fields
+
+obs-to = "To" *WSP ":" address-list CRLF
+
+obs-cc = "Cc" *WSP ":" address-list CRLF
+
+obs-bcc = "Bcc" *WSP ":" (address-list / [CFWS]) CRLF
+
+
+
+
+
+
+Resnick Standards Track [Page 34]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ When multiple occurrences of destination address fields occur in a
+ message, they SHOULD be treated as if the address-list in the first
+ occurrence of the field is combined with the address lists of the
+ subsequent occurrences by adding a comma and concatenating.
+
+4.5.4. Obsolete identification fields
+
+ The obsolete "In-Reply-To:" and "References:" fields differ from the
+ current syntax in that they allow phrase (words or quoted strings) to
+ appear. The obsolete forms of the left and right sides of msg-id
+ allow interspersed CFWS, making them syntactically identical to
+ local-part and domain respectively.
+
+obs-message-id = "Message-ID" *WSP ":" msg-id CRLF
+
+obs-in-reply-to = "In-Reply-To" *WSP ":" *(phrase / msg-id) CRLF
+
+obs-references = "References" *WSP ":" *(phrase / msg-id) CRLF
+
+obs-id-left = local-part
+
+obs-id-right = domain
+
+ For purposes of interpretation, the phrases in the "In-Reply-To:" and
+ "References:" fields are ignored.
+
+ Semantically, none of the optional CFWS surrounding the local-part
+ and the domain are part of the obs-id-left and obs-id-right
+ respectively.
+
+4.5.5. Obsolete informational fields
+
+obs-subject = "Subject" *WSP ":" unstructured CRLF
+
+obs-comments = "Comments" *WSP ":" unstructured CRLF
+
+obs-keywords = "Keywords" *WSP ":" obs-phrase-list CRLF
+
+4.5.6. Obsolete resent fields
+
+ The obsolete syntax adds a "Resent-Reply-To:" field, which consists
+ of the field name, the optional comments and folding white space, the
+ colon, and a comma separated list of addresses.
+
+obs-resent-from = "Resent-From" *WSP ":" mailbox-list CRLF
+
+obs-resent-send = "Resent-Sender" *WSP ":" mailbox CRLF
+
+
+
+
+Resnick Standards Track [Page 35]
+
+RFC 2822 Internet Message Format April 2001
+
+
+obs-resent-date = "Resent-Date" *WSP ":" date-time CRLF
+
+obs-resent-to = "Resent-To" *WSP ":" address-list CRLF
+
+obs-resent-cc = "Resent-Cc" *WSP ":" address-list CRLF
+
+obs-resent-bcc = "Resent-Bcc" *WSP ":"
+ (address-list / [CFWS]) CRLF
+
+obs-resent-mid = "Resent-Message-ID" *WSP ":" msg-id CRLF
+
+obs-resent-rply = "Resent-Reply-To" *WSP ":" address-list CRLF
+
+ As with other resent fields, the "Resent-Reply-To:" field is to be
+ treated as trace information only.
+
+4.5.7. Obsolete trace fields
+
+ The obs-return and obs-received are again given here as template
+ definitions, just as return and received are in section 3. Their
+ full syntax is given in [RFC2821].
+
+obs-return = "Return-Path" *WSP ":" path CRLF
+
+obs-received = "Received" *WSP ":" name-val-list CRLF
+
+obs-path = obs-angle-addr
+
+4.5.8. Obsolete optional fields
+
+obs-optional = field-name *WSP ":" unstructured CRLF
+
+5. Security Considerations
+
+ Care needs to be taken when displaying messages on a terminal or
+ terminal emulator. Powerful terminals may act on escape sequences
+ and other combinations of ASCII control characters with a variety of
+ consequences. They can remap the keyboard or permit other
+ modifications to the terminal which could lead to denial of service
+ or even damaged data. They can trigger (sometimes programmable)
+ answerback messages which can allow a message to cause commands to be
+ issued on the recipient's behalf. They can also effect the operation
+ of terminal attached devices such as printers. Message viewers may
+ wish to strip potentially dangerous terminal escape sequences from
+ the message prior to display. However, other escape sequences appear
+ in messages for useful purposes (cf. [RFC2045, RFC2046, RFC2047,
+ RFC2048, RFC2049, ISO2022]) and therefore should not be stripped
+ indiscriminately.
+
+
+
+Resnick Standards Track [Page 36]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ Transmission of non-text objects in messages raises additional
+ security issues. These issues are discussed in [RFC2045, RFC2046,
+ RFC2047, RFC2048, RFC2049].
+
+ Many implementations use the "Bcc:" (blind carbon copy) field
+ described in section 3.6.3 to facilitate sending messages to
+ recipients without revealing the addresses of one or more of the
+ addressees to the other recipients. Mishandling this use of "Bcc:"
+ has implications for confidential information that might be revealed,
+ which could eventually lead to security problems through knowledge of
+ even the existence of a particular mail address. For example, if
+ using the first method described in section 3.6.3, where the "Bcc:"
+ line is removed from the message, blind recipients have no explicit
+ indication that they have been sent a blind copy, except insofar as
+ their address does not appear in the message header. Because of
+ this, one of the blind addressees could potentially send a reply to
+ all of the shown recipients and accidentally reveal that the message
+ went to the blind recipient. When the second method from section
+ 3.6.3 is used, the blind recipient's address appears in the "Bcc:"
+ field of a separate copy of the message. If the "Bcc:" field sent
+ contains all of the blind addressees, all of the "Bcc:" recipients
+ will be seen by each "Bcc:" recipient. Even if a separate message is
+ sent to each "Bcc:" recipient with only the individual's address,
+ implementations still need to be careful to process replies to the
+ message as per section 3.6.3 so as not to accidentally reveal the
+ blind recipient to other recipients.
+
+6. Bibliography
+
+ [ASCII] American National Standards Institute (ANSI), Coded
+ Character Set - 7-Bit American National Standard Code for
+ Information Interchange, ANSI X3.4, 1986.
+
+ [ISO2022] International Organization for Standardization (ISO),
+ Information processing - ISO 7-bit and 8-bit coded
+ character sets - Code extension techniques, Third edition
+ - 1986-05-01, ISO 2022, 1986.
+
+ [RFC822] Crocker, D., "Standard for the Format of ARPA Internet
+ Text Messages", RFC 822, August 1982.
+
+ [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part One: Format of Internet Message
+ Bodies", RFC 2045, November 1996.
+
+ [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046,
+ November 1996.
+
+
+
+Resnick Standards Track [Page 37]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ [RFC2047] Moore, K., "Multipurpose Internet Mail Extensions (MIME)
+ Part Three: Message Header Extensions for Non-ASCII Text",
+ RFC 2047, November 1996.
+
+ [RFC2048] Freed, N., Klensin, J. and J. Postel, "Multipurpose
+ Internet Mail Extensions (MIME) Part Four: Format of
+ Internet Message Bodies", RFC 2048, November 1996.
+
+ [RFC2049] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Five: Conformance Criteria and
+ Examples", RFC 2049, November 1996.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2234] Crocker, D., Editor, and P. Overell, "Augmented BNF for
+ Syntax Specifications: ABNF", RFC 2234, November 1997.
+
+ [RFC2821] Klensin, J., Editor, "Simple Mail Transfer Protocol", RFC
+ 2821, March 2001.
+
+ [STD3] Braden, R., "Host Requirements", STD 3, RFC 1122 and RFC
+ 1123, October 1989.
+
+ [STD12] Mills, D., "Network Time Protocol", STD 12, RFC 1119,
+ September 1989.
+
+ [STD13] Mockapetris, P., "Domain Name System", STD 13, RFC 1034
+ and RFC 1035, November 1987.
+
+ [STD14] Partridge, C., "Mail Routing and the Domain System", STD
+ 14, RFC 974, January 1986.
+
+7. Editor's Address
+
+ Peter W. Resnick
+ QUALCOMM Incorporated
+ 5775 Morehouse Drive
+ San Diego, CA 92121-1714
+ USA
+
+ Phone: +1 858 651 4478
+ Fax: +1 858 651 1102
+ EMail: presnick@qualcomm.com
+
+
+
+
+
+
+
+Resnick Standards Track [Page 38]
+
+RFC 2822 Internet Message Format April 2001
+
+
+8. Acknowledgements
+
+ Many people contributed to this document. They included folks who
+ participated in the Detailed Revision and Update of Messaging
+ Standards (DRUMS) Working Group of the Internet Engineering Task
+ Force (IETF), the chair of DRUMS, the Area Directors of the IETF, and
+ people who simply sent their comments in via e-mail. The editor is
+ deeply indebted to them all and thanks them sincerely. The below
+ list includes everyone who sent e-mail concerning this document.
+ Hopefully, everyone who contributed is named here:
+
+ Matti Aarnio Barry Finkel Larry Masinter
+ Tanaka Akira Erik Forsberg Denis McKeon
+ Russ Allbery Chuck Foster William P McQuillan
+ Eric Allman Paul Fox Alexey Melnikov
+ Harald Tveit Alvestrand Klaus M. Frank Perry E. Metzger
+ Ran Atkinson Ned Freed Steven Miller
+ Jos Backus Jochen Friedrich Keith Moore
+ Bruce Balden Randall C. Gellens John Gardiner Myers
+ Dave Barr Sukvinder Singh Gill Chris Newman
+ Alan Barrett Tim Goodwin John W. Noerenberg
+ John Beck Philip Guenther Eric Norman
+ J. Robert von Behren Tony Hansen Mike O'Dell
+ Jos den Bekker John Hawkinson Larry Osterman
+ D. J. Bernstein Philip Hazel Paul Overell
+ James Berriman Kai Henningsen Jacob Palme
+ Norbert Bollow Robert Herriot Michael A. Patton
+ Raj Bose Paul Hethmon Uzi Paz
+ Antony Bowesman Jim Hill Michael A. Quinlan
+ Scott Bradner Paul E. Hoffman Eric S. Raymond
+ Randy Bush Steve Hole Sam Roberts
+ Tom Byrer Kari Hurtta Hugh Sasse
+ Bruce Campbell Marco S. Hyman Bart Schaefer
+ Larry Campbell Ofer Inbar Tom Scola
+ W. J. Carpenter Olle Jarnefors Wolfgang Segmuller
+ Michael Chapman Kevin Johnson Nick Shelness
+ Richard Clayton Sudish Joseph John Stanley
+ Maurizio Codogno Maynard Kang Einar Stefferud
+ Jim Conklin Prabhat Keni Jeff Stephenson
+ R. Kelley Cook John C. Klensin Bernard Stern
+ Steve Coya Graham Klyne Peter Sylvester
+ Mark Crispin Brad Knowles Mark Symons
+ Dave Crocker Shuhei Kobayashi Eric Thomas
+ Matt Curtin Peter Koch Lee Thompson
+ Michael D'Errico Dan Kohn Karel De Vriendt
+ Cyrus Daboo Christian Kuhtz Matthew Wall
+ Jutta Degener Anand Kumria Rolf Weber
+ Mark Delany Steen Larsen Brent B. Welch
+
+
+
+Resnick Standards Track [Page 39]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ Steve Dorner Eliot Lear Dan Wing
+ Harold A. Driscoll Barry Leiba Jack De Winter
+ Michael Elkins Jay Levitt Gregory J. Woodhouse
+ Robert Elz Lars-Johan Liman Greg A. Woods
+ Johnny Eriksson Charles Lindsey Kazu Yamamoto
+ Erik E. Fair Pete Loshin Alain Zahm
+ Roger Fajman Simon Lyall Jamie Zawinski
+ Patrik Faltstrom Bill Manning Timothy S. Zurcher
+ Claus Andre Farber John Martin
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 40]
+
+RFC 2822 Internet Message Format April 2001
+
+
+Appendix A. Example messages
+
+ This section presents a selection of messages. These are intended to
+ assist in the implementation of this standard, but should not be
+ taken as normative; that is to say, although the examples in this
+ section were carefully reviewed, if there happens to be a conflict
+ between these examples and the syntax described in sections 3 and 4
+ of this document, the syntax in those sections is to be taken as
+ correct.
+
+ Messages are delimited in this section between lines of "----". The
+ "----" lines are not part of the message itself.
+
+A.1. Addressing examples
+
+ The following are examples of messages that might be sent between two
+ individuals.
+
+A.1.1. A message from one person to another with simple addressing
+
+ This could be called a canonical message. It has a single author,
+ John Doe, a single recipient, Mary Smith, a subject, the date, a
+ message identifier, and a textual message in the body.
+
+----
+From: John Doe <jdoe@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: Fri, 21 Nov 1997 09:55:06 -0600
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 41]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ If John's secretary Michael actually sent the message, though John
+ was the author and replies to this message should go back to him, the
+ sender field would be used:
+
+----
+From: John Doe <jdoe@machine.example>
+Sender: Michael Jones <mjones@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: Fri, 21 Nov 1997 09:55:06 -0600
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+A.1.2. Different types of mailboxes
+
+ This message includes multiple addresses in the destination fields
+ and also uses several different forms of addresses.
+
+----
+From: "Joe Q. Public" <john.q.public@example.com>
+To: Mary Smith <mary@x.test>, jdoe@example.org, Who? <one@y.test>
+Cc: <boss@nil.test>, "Giant; \"Big\" Box" <sysservices@example.net>
+Date: Tue, 1 Jul 2003 10:52:37 +0200
+Message-ID: <5678.21-Nov-1997@example.com>
+
+Hi everyone.
+----
+
+ Note that the display names for Joe Q. Public and Giant; "Big" Box
+ needed to be enclosed in double-quotes because the former contains
+ the period and the latter contains both semicolon and double-quote
+ characters (the double-quote characters appearing as quoted-pair
+ construct). Conversely, the display name for Who? could appear
+ without them because the question mark is legal in an atom. Notice
+ also that jdoe@example.org and boss@nil.test have no display names
+ associated with them at all, and jdoe@example.org uses the simpler
+ address form without the angle brackets.
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 42]
+
+RFC 2822 Internet Message Format April 2001
+
+
+A.1.3. Group addresses
+
+----
+From: Pete <pete@silly.example>
+To: A Group:Chris Jones <c@a.test>,joe@where.test,John <jdoe@one.test>;
+Cc: Undisclosed recipients:;
+Date: Thu, 13 Feb 1969 23:32:54 -0330
+Message-ID: <testabcd.1234@silly.example>
+
+Testing.
+----
+
+ In this message, the "To:" field has a single group recipient named A
+ Group which contains 3 addresses, and a "Cc:" field with an empty
+ group recipient named Undisclosed recipients.
+
+A.2. Reply messages
+
+ The following is a series of three messages that make up a
+ conversation thread between John and Mary. John firsts sends a
+ message to Mary, Mary then replies to John's message, and then John
+ replies to Mary's reply message.
+
+ Note especially the "Message-ID:", "References:", and "In-Reply-To:"
+ fields in each message.
+
+----
+From: John Doe <jdoe@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: Fri, 21 Nov 1997 09:55:06 -0600
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 43]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ When sending replies, the Subject field is often retained, though
+ prepended with "Re: " as described in section 3.6.5.
+
+----
+From: Mary Smith <mary@example.net>
+To: John Doe <jdoe@machine.example>
+Reply-To: "Mary Smith: Personal Account" <smith@home.example>
+Subject: Re: Saying Hello
+Date: Fri, 21 Nov 1997 10:01:10 -0600
+Message-ID: <3456@example.net>
+In-Reply-To: <1234@local.machine.example>
+References: <1234@local.machine.example>
+
+This is a reply to your hello.
+----
+
+ Note the "Reply-To:" field in the above message. When John replies
+ to Mary's message above, the reply should go to the address in the
+ "Reply-To:" field instead of the address in the "From:" field.
+
+----
+To: "Mary Smith: Personal Account" <smith@home.example>
+From: John Doe <jdoe@machine.example>
+Subject: Re: Saying Hello
+Date: Fri, 21 Nov 1997 11:00:00 -0600
+Message-ID: <abcd.1234@local.machine.tld>
+In-Reply-To: <3456@example.net>
+References: <1234@local.machine.example> <3456@example.net>
+
+This is a reply to your reply.
+----
+
+A.3. Resent messages
+
+ Start with the message that has been used as an example several
+ times:
+
+----
+From: John Doe <jdoe@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: Fri, 21 Nov 1997 09:55:06 -0600
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+
+
+
+Resnick Standards Track [Page 44]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ Say that Mary, upon receiving this message, wishes to send a copy of
+ the message to Jane such that (a) the message would appear to have
+ come straight from John; (b) if Jane replies to the message, the
+ reply should go back to John; and (c) all of the original
+ information, like the date the message was originally sent to Mary,
+ the message identifier, and the original addressee, is preserved. In
+ this case, resent fields are prepended to the message:
+
+----
+Resent-From: Mary Smith <mary@example.net>
+Resent-To: Jane Brown <j-brown@other.example>
+Resent-Date: Mon, 24 Nov 1997 14:22:01 -0800
+Resent-Message-ID: <78910@example.net>
+From: John Doe <jdoe@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: Fri, 21 Nov 1997 09:55:06 -0600
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+ If Jane, in turn, wished to resend this message to another person,
+ she would prepend her own set of resent header fields to the above
+ and send that.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 45]
+
+RFC 2822 Internet Message Format April 2001
+
+
+A.4. Messages with trace fields
+
+ As messages are sent through the transport system as described in
+ [RFC2821], trace fields are prepended to the message. The following
+ is an example of what those trace fields might look like. Note that
+ there is some folding white space in the first one since these lines
+ can be long.
+
+----
+Received: from x.y.test
+ by example.net
+ via TCP
+ with ESMTP
+ id ABC12345
+ for <mary@example.net>; 21 Nov 1997 10:05:43 -0600
+Received: from machine.example by x.y.test; 21 Nov 1997 10:01:22 -0600
+From: John Doe <jdoe@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: Fri, 21 Nov 1997 09:55:06 -0600
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 46]
+
+RFC 2822 Internet Message Format April 2001
+
+
+A.5. White space, comments, and other oddities
+
+ White space, including folding white space, and comments can be
+ inserted between many of the tokens of fields. Taking the example
+ from A.1.3, white space and comments can be inserted into all of the
+ fields.
+
+----
+From: Pete(A wonderful \) chap) <pete(his account)@silly.test(his host)>
+To:A Group(Some people)
+ :Chris Jones <c@(Chris's host.)public.example>,
+ joe@example.org,
+ John <jdoe@one.test> (my dear friend); (the end of the group)
+Cc:(Empty list)(start)Undisclosed recipients :(nobody(that I know)) ;
+Date: Thu,
+ 13
+ Feb
+ 1969
+ 23:32
+ -0330 (Newfoundland Time)
+Message-ID: <testabcd.1234@silly.test>
+
+Testing.
+----
+
+ The above example is aesthetically displeasing, but perfectly legal.
+ Note particularly (1) the comments in the "From:" field (including
+ one that has a ")" character appearing as part of a quoted-pair); (2)
+ the white space absent after the ":" in the "To:" field as well as
+ the comment and folding white space after the group name, the special
+ character (".") in the comment in Chris Jones's address, and the
+ folding white space before and after "joe@example.org,"; (3) the
+ multiple and nested comments in the "Cc:" field as well as the
+ comment immediately following the ":" after "Cc"; (4) the folding
+ white space (but no comments except at the end) and the missing
+ seconds in the time of the date field; and (5) the white space before
+ (but not within) the identifier in the "Message-ID:" field.
+
+A.6. Obsoleted forms
+
+ The following are examples of obsolete (that is, the "MUST NOT
+ generate") syntactic elements described in section 4 of this
+ document.
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 47]
+
+RFC 2822 Internet Message Format April 2001
+
+
+A.6.1. Obsolete addressing
+
+ Note in the below example the lack of quotes around Joe Q. Public,
+ the route that appears in the address for Mary Smith, the two commas
+ that appear in the "To:" field, and the spaces that appear around the
+ "." in the jdoe address.
+
+----
+From: Joe Q. Public <john.q.public@example.com>
+To: Mary Smith <@machine.tld:mary@example.net>, , jdoe@test . example
+Date: Tue, 1 Jul 2003 10:52:37 +0200
+Message-ID: <5678.21-Nov-1997@example.com>
+
+Hi everyone.
+----
+
+A.6.2. Obsolete dates
+
+ The following message uses an obsolete date format, including a non-
+ numeric time zone and a two digit year. Note that although the
+ day-of-week is missing, that is not specific to the obsolete syntax;
+ it is optional in the current syntax as well.
+
+----
+From: John Doe <jdoe@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: 21 Nov 97 09:55:06 GMT
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+A.6.3. Obsolete white space and comments
+
+ White space and comments can appear between many more elements than
+ in the current syntax. Also, folding lines that are made up entirely
+ of white space are legal.
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 48]
+
+RFC 2822 Internet Message Format April 2001
+
+
+----
+From : John Doe <jdoe@machine(comment). example>
+To : Mary Smith
+__
+ <mary@example.net>
+Subject : Saying Hello
+Date : Fri, 21 Nov 1997 09(comment): 55 : 06 -0600
+Message-ID : <1234 @ local(blah) .machine .example>
+
+This is a message just to say hello.
+So, "Hello".
+----
+
+ Note especially the second line of the "To:" field. It starts with
+ two space characters. (Note that "__" represent blank spaces.)
+ Therefore, it is considered part of the folding as described in
+ section 4.2. Also, the comments and white space throughout
+ addresses, dates, and message identifiers are all part of the
+ obsolete syntax.
+
+Appendix B. Differences from earlier standards
+
+ This appendix contains a list of changes that have been made in the
+ Internet Message Format from earlier standards, specifically [RFC822]
+ and [STD3]. Items marked with an asterisk (*) below are items which
+ appear in section 4 of this document and therefore can no longer be
+ generated.
+
+ 1. Period allowed in obsolete form of phrase.
+ 2. ABNF moved out of document to [RFC2234].
+ 3. Four or more digits allowed for year.
+ 4. Header field ordering (and lack thereof) made explicit.
+ 5. Encrypted header field removed.
+ 6. Received syntax loosened to allow any token/value pair.
+ 7. Specifically allow and give meaning to "-0000" time zone.
+ 8. Folding white space is not allowed between every token.
+ 9. Requirement for destinations removed.
+ 10. Forwarding and resending redefined.
+ 11. Extension header fields no longer specifically called out.
+ 12. ASCII 0 (null) removed.*
+ 13. Folding continuation lines cannot contain only white space.*
+ 14. Free insertion of comments not allowed in date.*
+ 15. Non-numeric time zones not allowed.*
+ 16. Two digit years not allowed.*
+ 17. Three digit years interpreted, but not allowed for generation.
+ 18. Routes in addresses not allowed.*
+ 19. CFWS within local-parts and domains not allowed.*
+ 20. Empty members of address lists not allowed.*
+
+
+
+Resnick Standards Track [Page 49]
+
+RFC 2822 Internet Message Format April 2001
+
+
+ 21. Folding white space between field name and colon not allowed.*
+ 22. Comments between field name and colon not allowed.
+ 23. Tightened syntax of in-reply-to and references.*
+ 24. CFWS within msg-id not allowed.*
+ 25. Tightened semantics of resent fields as informational only.
+ 26. Resent-Reply-To not allowed.*
+ 27. No multiple occurrences of fields (except resent and received).*
+ 28. Free CR and LF not allowed.*
+ 29. Routes in return path not allowed.*
+ 30. Line length limits specified.
+ 31. Bcc more clearly specified.
+
+Appendix C. Notices
+
+ Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ intellectual property or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; neither does it represent that it
+ has made any effort to identify any such rights. Information on the
+ IETF's procedures with respect to rights in standards-track and
+ standards-related documentation can be found in BCP-11. Copies of
+ claims of rights made available for publication and any assurances of
+ licenses to be made available, or the result of an attempt made to
+ obtain a general license or permission for the use of such
+ proprietary rights by implementors or users of this specification can
+ be obtained from the IETF Secretariat.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 50]
+
+RFC 2822 Internet Message Format April 2001
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick Standards Track [Page 51]
+
diff --git a/standards/rfc2910.txt b/standards/rfc2910.txt
new file mode 100644
index 000000000..e13631c2a
--- /dev/null
+++ b/standards/rfc2910.txt
@@ -0,0 +1,2579 @@
+
+
+
+
+
+
+Network Working Group R. Herriot, Editor
+Request for Comments: 2910 Xerox Corporation
+Obsoletes: 2565 S. Butler
+Category: Standards Track Hewlett-Packard
+ P. Moore
+ Peerless Systems Networking
+ R. Turner
+ 2wire.com
+ J. Wenn
+ Xerox Corporation
+ September 2000
+
+
+ Internet Printing Protocol/1.1: Encoding and Transport
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+Abstract
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ using Internet tools and technologies. This document defines the
+ rules for encoding IPP operations and IPP attributes into a new
+ Internet mime media type called "application/ipp". This document
+ also defines the rules for transporting over Hypertext Transfer
+ Protocol (HTTP) a message body whose Content-Type is
+ "application/ipp". This document defines a new scheme named 'ipp' for
+ identifying IPP printers and jobs.
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 1]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport (this
+ document)
+ Internet Printing Protocol/1.1: Implementer's Guide [ipp-iig]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The document, "Design Goals for an Internet Printing Protocol", takes
+ a broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.1. A few OPTIONAL operator operations have
+ been added to IPP/1.1.
+
+ The document, "Rationale for the Structure and Model and Protocol for
+ the Internet Printing Protocol", describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF working group's major decisions.
+
+ The document, "Internet Printing Protocol/1.1: Model and Semantics",
+ describes a simplified model with abstract objects, their attributes,
+ and their operations that are independent of encoding and transport.
+ It introduces a Printer and a Job object. The Job object optionally
+ supports multiple documents per Job. It also addresses security,
+ internationalization, and directory issues.
+
+ The document "Internet Printing Protocol/1.1: Implementer's Guide",
+ gives advice to implementers of IPP clients and IPP objects.
+
+ The document "Mapping between LPD and IPP Protocols", gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 2]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+Table of Contents
+
+ 1. Introduction ...................................................4
+ 2. Conformance Terminology ........................................4
+ 3. Encoding of the Operation Layer ...............................4
+ 3.1 Picture of the Encoding ...................................6
+ 3.1.1 Request and Response...................................6
+ 3.1.2 Attribute Group........................................6
+ 3.1.3 Attribute..............................................7
+ 3.1.4 Picture of the Encoding of an Attribute-with-one-value.7
+ 3.1.5 Additional-value.......................................8
+ 3.1.6 Alternative Picture of the Encoding of a Request Or a
+ Response...............................................9
+ 3.2 Syntax of Encoding ........................................9
+ 3.3 Attribute-group ..........................................11
+ 3.4 Required Parameters ......................................12
+ 3.4.1 Version-number........................................12
+ 3.4.2 Operation-id..........................................12
+ 3.4.3 Status-code...........................................12
+ 3.4.4 Request-id............................................13
+ 3.5 Tags .....................................................13
+ 3.5.1 Delimiter Tags........................................13
+ 3.5.2 Value Tags............................................14
+ 3.6 Name-Length ..............................................16
+ 3.7 (Attribute) Name .........................................16
+ 3.8 Value Length .............................................16
+ 3.9 (Attribute) Value ........................................17
+ 3.10 Data .....................................................18
+ 4. Encoding of Transport Layer ...................................18
+ 4.1 Printer-uri and job-uri ..................................19
+ 5. IPP URL Scheme ................................................20
+ 6. IANA Considerations ...........................................22
+ 7. Internationalization Considerations ...........................23
+ 8. Security Considerations .......................................23
+ 8.1 Security Conformance Requirements ........................23
+ 8.1.1 Digest Authentication.................................23
+ 8.1.2 Transport Layer Security (TLS)........................24
+ 8.2 Using IPP with TLS .......................................25
+ 9. Interoperability with IPP/1.0 Implementations .................25
+ 9.1 The "version-number" Parameter ...........................25
+ 9.2 Security and URL Schemes .................................26
+ 10. References ...................................................27
+ 11. Authors' Addresses ...........................................29
+ 12. Other Participants: ..........................................31
+ 13. Appendix A: Protocol Examples ................................33
+ 13.1 Print-Job Request ........................................33
+ 13.2 Print-Job Response (successful) ..........................34
+ 13.3 Print-Job Response (failure) .............................35
+
+
+
+Herriot, et al. Standards Track [Page 3]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ 13.4 Print-Job Response (success with attributes ignored) .....36
+ 13.5 Print-URI Request ........................................38
+ 13.6 Create-Job Request .......................................39
+ 13.7 Get-Jobs Request .........................................40
+ 13.8 Get-Jobs Response ........................................41
+ 14. Appendix B: Registration of MIME Media Type Information for
+ "application/ipp".............................................42
+ 15. Appendix C: Changes from IPP/1.0 .............................44
+ 16. Full Copyright Statement .....................................45
+
+1. Introduction
+
+ This document contains the rules for encoding IPP operations and
+ describes two layers: the transport layer and the operation layer.
+
+ The transport layer consists of an HTTP/1.1 request or response. RFC
+ 2616 [RFC2616] describes HTTP/1.1. This document specifies the HTTP
+ headers that an IPP implementation supports.
+
+ The operation layer consists of a message body in an HTTP request or
+ response. The document "Internet Printing Protocol/1.1: Model and
+ Semantics" [RFC2911] defines the semantics of such a message body and
+ the supported values. This document specifies the encoding of an IPP
+ operation. The aforementioned document [RFC2911] is henceforth
+ referred to as the "IPP model document" or simply "model document".
+
+ Note: the version number of IPP (1.1) and HTTP (1.1) are not linked.
+ They both just happen to be 1.1.
+
+2. Conformance Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",
+ "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
+ interpreted as described in RFC 2119 [RFC2119].
+
+3. Encoding of the Operation Layer
+
+ The operation layer is the message body part of the HTTP request or
+ response and it MUST contain a single IPP operation request or IPP
+ operation response. Each request or response consists of a sequence
+ of values and attribute groups. Attribute groups consist of a
+ sequence of attributes each of which is a name and value. Names and
+ values are ultimately sequences of octets.
+
+ The encoding consists of octets as the most primitive type. There are
+ several types built from octets, but three important types are
+ integers, character strings and octet strings, on which most other
+ data types are built. Every character string in this encoding MUST be
+
+
+
+Herriot, et al. Standards Track [Page 4]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ a sequence of characters where the characters are associated with
+ some charset and some natural language. A character string MUST be in
+ "reading order" with the first character in the value (according to
+ reading order) being the first character in the encoding. A character
+ string whose associated charset is US-ASCII whose associated natural
+ language is US English is henceforth called a US-ASCII-STRING. A
+ character string whose associated charset and natural language are
+ specified in a request or response as described in the model document
+ is henceforth called a LOCALIZED-STRING. An octet string MUST be in
+ "IPP model document order" with the first octet in the value
+ (according to the IPP model document order) being the first octet in
+ the encoding. Every integer in this encoding MUST be encoded as a
+ signed integer using two's-complement binary encoding with big-endian
+ format (also known as "network order" and "most significant byte
+ first"). The number of octets for an integer MUST be 1, 2 or 4,
+ depending on usage in the protocol. Such one-octet integers,
+ henceforth called SIGNED-BYTE, are used for the version-number and
+ tag fields. Such two-byte integers, henceforth called SIGNED-SHORT
+ are used for the operation-id, status-code and length fields. Four
+ byte integers, henceforth called SIGNED-INTEGER, are used for value
+ fields and the request-id.
+
+ The following two sections present the encoding of the operation
+ layer in two ways:
+
+ - informally through pictures and description
+ - formally through Augmented Backus-Naur Form (ABNF), as
+ specified by RFC 2234 [RFC2234]
+
+ An operation request or response MUST use the encoding described in
+ these two sections.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 5]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+3.1 Picture of the Encoding
+
+3.1.1 Request and Response
+
+ An operation request or response is encoded as follows:
+
+ -----------------------------------------------
+ | version-number | 2 bytes - required
+ -----------------------------------------------
+ | operation-id (request) |
+ | or | 2 bytes - required
+ | status-code (response) |
+ -----------------------------------------------
+ | request-id | 4 bytes - required
+ -----------------------------------------------
+ | attribute-group | n bytes - 0 or more
+ -----------------------------------------------
+ | end-of-attributes-tag | 1 byte - required
+ -----------------------------------------------
+ | data | q bytes - optional
+ -----------------------------------------------
+
+ The first three fields in the above diagram contain the value of
+ attributes described in section 3.1.1 of the Model document.
+
+ The fourth field is the "attribute-group" field, and it occurs 0 or
+ more times. Each "attribute-group" field represents a single group of
+ attributes, such as an Operation Attributes group or a Job Attributes
+ group (see the Model document). The IPP model document specifies the
+ required attribute groups and their order for each operation request
+ and response.
+
+ The "end-of-attributes-tag" field is always present, even when the
+ "data" is not present. The Model document specifies for each
+ operation request and response whether the "data" field is present or
+ absent.
+
+3.1.2 Attribute Group
+
+ Each "attribute-group" field is encoded as follows:
+
+ -----------------------------------------------
+ | begin-attribute-group-tag | 1 byte
+ ----------------------------------------------------------
+ | attribute | p bytes |- 0 or more
+ ----------------------------------------------------------
+
+
+
+
+
+Herriot, et al. Standards Track [Page 6]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ The "begin-attribute-group-tag" field marks the beginning of an
+ "attribute-group" field and its value identifies the type of
+ attribute group, e.g. Operations Attributes group versus a Job
+ Attributes group. The "begin-attribute-group-tag" field also marks
+ the end of the previous attribute group except for the "begin-
+ attribute-group-tag" field in the first "attribute-group" field of a
+ request or response. The "begin-attribute-group-tag" field acts as
+ an "attribute-group" terminator because an "attribute-group" field
+ cannot nest inside another "attribute-group" field.
+
+ An "attribute-group" field contains zero or more "attribute" fields.
+
+ Note, the values of the "begin-attribute-group-tag" field and the
+ "end-of-attributes-tag" field are called "delimiter-tags".
+
+3.1.3 Attribute
+
+ An "attribute" field is encoded as follows:
+
+ -----------------------------------------------
+ | attribute-with-one-value | q bytes
+ ----------------------------------------------------------
+ | additional-value | r bytes |- 0 or more
+ ----------------------------------------------------------
+
+ When an attribute is single valued (e.g. "copies" with value of 10)
+ or multi-valued with one value (e.g. "sides-supported" with just the
+ value 'one-sided') it is encoded with just an "attribute-with-one-
+ value" field. When an attribute is multi-valued with n values (e.g.
+ "sides-supported" with the values 'one-sided' and 'two-sided-long-
+ edge'), it is encoded with an "attribute-with-one-value" field
+ followed by n-1 "additional-value" fields.
+
+3.1.4 Picture of the Encoding of an Attribute-with-one-value
+
+ Each "attribute-with-one-value" field is encoded as follows:
+
+ -----------------------------------------------
+ | value-tag | 1 byte
+ -----------------------------------------------
+ | name-length (value is u) | 2 bytes
+ -----------------------------------------------
+ | name | u bytes
+ -----------------------------------------------
+ | value-length (value is v) | 2 bytes
+ -----------------------------------------------
+ | value | v bytes
+ -----------------------------------------------
+
+
+
+Herriot, et al. Standards Track [Page 7]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ An "attribute-with-one-value" field is encoded with five subfields:
+
+ The "value-tag" field specifies the attribute syntax, e.g. 0x44
+ for the attribute syntax 'keyword'.
+
+ The "name-length" field specifies the length of the "name" field
+ in bytes, e.g. u in the above diagram or 15 for the name "sides-
+ supported".
+
+ The "name" field contains the textual name of the attribute, e.g.
+ "sides-supported".
+
+ The "value-length" field specifies the length of the "value" field
+ in bytes, e.g. v in the above diagram or 9 for the (keyword) value
+ 'one-sided'.
+
+ The "value" field contains the value of the attribute, e.g. the
+ textual value 'one-sided'.
+
+3.1.5 Additional-value
+
+ Each "additional-value" field is encoded as follows:
+
+ -----------------------------------------------
+ | value-tag | 1 byte
+ -----------------------------------------------
+ | name-length (value is 0x0000) | 2 bytes
+ -----------------------------------------------
+ | value-length (value is w) | 2 bytes
+ -----------------------------------------------
+ | value | w bytes
+ -----------------------------------------------
+
+ An "additional-value" is encoded with four subfields:
+
+ The "value-tag" field specifies the attribute syntax, e.g. 0x44
+ for the attribute syntax 'keyword'.
+
+ The "name-length" field has the value of 0 in order to signify
+ that it is an "additional-value". The value of the "name-length"
+ field distinguishes an "additional-value" field ("name-length" is
+ 0) from an "attribute-with-one-value" field ("name-length" is not
+ 0).
+
+ The "value-length" field specifies the length of the "value" field
+ in bytes, e.g. w in the above diagram or 19 for the (keyword)
+ value 'two-sided-long-edge'.
+
+
+
+
+Herriot, et al. Standards Track [Page 8]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ The "value" field contains the value of the attribute, e.g. the
+ textual value 'two-sided-long-edge'.
+
+3.1.6 Alternative Picture of the Encoding of a Request Or a Response
+
+ From the standpoint of a parser that performs an action based on a
+ "tag" value, the encoding consists of:
+
+ -----------------------------------------------
+ | version-number | 2 bytes - required
+ -----------------------------------------------
+ | operation-id (request) |
+ | or | 2 bytes - required
+ | status-code (response) |
+ -----------------------------------------------
+ | request-id | 4 bytes - required
+ -----------------------------------------------------------
+ | tag (delimiter-tag or value-tag) | 1 byte |
+ ----------------------------------------------- |-0 or more
+ | empty or rest of attribute | x bytes |
+ -----------------------------------------------------------
+ | end-of-attributes-tag | 1 byte - required
+ -----------------------------------------------
+ | data | y bytes - optional
+ -----------------------------------------------
+
+ The following show what fields the parser would expect after each
+ type of "tag":
+
+ - "begin-attribute-group-tag": expect zero or more "attribute"
+ fields
+ - "value-tag": expect the remainder of an "attribute-with-one-
+ value" or an "additional-value".
+ - "end-of-attributes-tag": expect that "attribute" fields are
+ complete and there is optional "data"
+
+3.2 Syntax of Encoding
+
+ The syntax below is ABNF [RFC2234] except 'strings of literals' MUST
+ be case sensitive. For example 'a' means lower case 'a' and not
+ upper case 'A'. In addition, SIGNED-BYTE and SIGNED-SHORT fields
+ are represented as '%x' values which show their range of values.
+
+ ipp-message = ipp-request / ipp-response
+ ipp-request = version-number operation-id request-id
+ *attribute-group end-of-attributes-tag data
+ ipp-response = version-number status-code request-id
+ *attribute-group end-of-attributes-tag data
+
+
+
+Herriot, et al. Standards Track [Page 9]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ attribute-group = begin-attribute-group-tag *attribute
+
+ version-number = major-version-number minor-version-number
+ major-version-number = SIGNED-BYTE
+ minor-version-number = SIGNED-BYTE
+
+ operation-id = SIGNED-SHORT ; mapping from model defined below
+ status-code = SIGNED-SHORT ; mapping from model defined below
+ request-id = SIGNED-INTEGER ; whose value is > 0
+
+ attribute = attribute-with-one-value *additional-value
+
+ attribute-with-one-value = value-tag name-length name
+ value-length value
+ additional-value = value-tag zero-name-length value-length value
+
+ name-length = SIGNED-SHORT ; number of octets of 'name'
+ name = LALPHA *( LALPHA / DIGIT / "-" / "_" / "." )
+ value-length = SIGNED-SHORT ; number of octets of 'value'
+ value = OCTET-STRING
+
+ data = OCTET-STRING
+
+ zero-name-length = %x00.00 ; name-length of 0
+ value-tag = %x10-FF ;see section 3.7.2
+ begin-attribute-group-tag = %x00-02 / %04-0F ; see section 3.7.1
+ end-of-attributes-tag = %x03 ; tag of 3
+ ; see section 3.7.1
+ SIGNED-BYTE = BYTE
+ SIGNED-SHORT = 2BYTE
+ SIGNED-INTEGER = 4BYTE
+ DIGIT = %x30-39 ; "0" to "9"
+ LALPHA = %x61-7A ; "a" to "z"
+ BYTE = %x00-FF
+ OCTET-STRING = *BYTE
+
+ The syntax below defines additional terms that are referenced in this
+ document. This syntax provides an alternate grouping of the delimiter
+ tags.
+
+ delimiter-tag = begin-attribute-group-tag / ; see section 3.7.1
+ end-of-attributes-tag
+ delimiter-tag = %x00-0F ; see section 3.7.1
+
+ begin-attribute-group-tag = %x00 / operation-attributes-tag /
+ job-attributes-tag / printer-attributes-tag /
+ unsupported-attributes-tag / %x06-0F
+ operation-attributes-tag = %x01 ; tag of 1
+
+
+
+Herriot, et al. Standards Track [Page 10]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ job-attributes-tag = %x02 ; tag of 2
+ printer-attributes-tag = %x04 ; tag of 4
+ unsupported-attributes-tag = %x05 ; tag of 5
+
+3.3 Attribute-group
+
+ Each "attribute-group" field MUST be encoded with the "begin-
+ attribute-group-tag" field followed by zero or more "attribute" sub-
+ fields.
+
+ The table below maps the model document group name to value of the
+ "begin-attribute-group-tag" field:
+
+ Model Document Group "begin-attribute-group-tag" field
+ values
+
+ Operation Attributes "operations-attributes-tag"
+ Job Template Attributes "job-attributes-tag"
+ Job Object Attributes "job-attributes-tag"
+ Unsupported Attributes "unsupported-attributes-tag"
+ Requested Attributes "job-attributes-tag"
+ (Get-Job-Attributes)
+ Requested Attributes "printer-attributes-tag"
+ (Get-Printer-Attributes)
+ Document Content in a special position as
+ described above
+
+ For each operation request and response, the model document
+ prescribes the required and optional attribute groups, along with
+ their order. Within each attribute group, the model document
+ prescribes the required and optional attributes, along with their
+ order.
+
+ When the Model document requires an attribute group in a request or
+ response and the attribute group contains zero attributes, a request
+ or response SHOULD encode the attribute group with the "begin-
+ attribute-group-tag" field followed by zero "attribute" fields. For
+ example, if the client requests a single unsupported attribute with
+ the Get-Printer-Attributes operation, the Printer MUST return no
+ "attribute" fields, and it SHOULD return a "begin-attribute-group-
+ tag" field for the Printer Attributes Group. The Unsupported
+ Attributes group is not such an example. According to the model
+ document, the Unsupported Attributes Group SHOULD be present only if
+ the unsupported attributes group contains at least one attribute.
+
+ A receiver of a request MUST be able to process the following as
+ equivalent empty attribute groups:
+
+
+
+
+Herriot, et al. Standards Track [Page 11]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ a) A "begin-attribute-group-tag" field with zero following
+ "attribute" fields.
+
+ b) An expected but missing "begin-attribute-group-tag" field.
+
+ When the Model document requires a sequence of an unknown number of
+ attribute groups, each of the same type, the encoding MUST contain
+ one "begin-attribute-group-tag" field for each attribute group even
+ when an "attribute-group" field contains zero "attribute" sub-fields.
+ For example, for the Get-Jobs operation may return zero attributes
+ for some jobs and not others. The "begin-attribute-group-tag" field
+ followed by zero "attribute" fields tells the recipient that there is
+ a job in queue for which no information is available except that it
+ is in the queue.
+
+3.4 Required Parameters
+
+ Some operation elements are called parameters in the model document
+ [RFC2911]. They MUST be encoded in a special position and they MUST
+ NOT appear as operation attributes. These parameters are described
+ in the subsections below.
+
+3.4.1 Version-number
+
+ The "version-number" field MUST consist of a major and minor
+ version-number, each of which MUST be represented by a SIGNED-BYTE.
+ The major version-number MUST be the first byte of the encoding and
+ the minor version-number MUST be the second byte of the encoding. The
+ protocol described in this document MUST have a major version-number
+ of 1 (0x01) and a minor version-number of 1 (0x01). The ABNF for
+ these two bytes MUST be %x01.01.
+
+3.4.2 Operation-id
+
+ The "operation-id" field MUST contain an operation-id value defined
+ in the model document. The value MUST be encoded as a SIGNED-SHORT
+ and it MUST be in the third and fourth bytes of the encoding of an
+ operation request.
+
+3.4.3 Status-code
+
+ The "status-code" field MUST contain a status-code value defined in
+ the model document. The value MUST be encoded as a SIGNED-SHORT and
+ it MUST be in the third and fourth bytes of the encoding of an
+ operation response.
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 12]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ The status-code is an operation attribute in the model document. In
+ the protocol, the status-code is in a special position, outside of
+ the operation attributes.
+
+ If an IPP status-code is returned, then the HTTP Status-Code MUST be
+ 200 (successful-ok). With any other HTTP Status-Code value, the HTTP
+ response MUST NOT contain an IPP message-body, and thus no IPP
+ status-code is returned.
+
+3.4.4 Request-id
+
+ The "request-id" field MUST contain a request-id value as defined in
+ the model document. The value MUST be encoded as a SIGNED-INTEGER and
+ it MUST be in the fifth through eighth bytes of the encoding.
+
+3.5 Tags
+
+ There are two kinds of tags:
+
+ - delimiter tags: delimit major sections of the protocol, namely
+ attributes and data
+ - value tags: specify the type of each attribute value
+
+3.5.1 Delimiter Tags
+
+ The following table specifies the values for the delimiter tags:
+
+ Tag Value (Hex) Meaning
+
+ 0x00 reserved for definition in a future IETF
+ standards track document
+ 0x01 "operation-attributes-tag"
+ 0x02 "job-attributes-tag"
+ 0x03 "end-of-attributes-tag"
+ 0x04 "printer-attributes-tag"
+ 0x05 "unsupported-attributes-tag"
+ 0x06-0x0f reserved for future delimiters in IETF
+ standards track documents
+
+ When a "begin-attribute-group-tag" field occurs in the protocol, it
+ means that zero or more following attributes up to the next delimiter
+ tag MUST be attributes belonging to the attribute group specified by
+ the value of the "begin-attribute-group-tag". For example, if the
+ value of "begin-attribute-group-tag" is 0x01, the following
+ attributes MUST be members of the Operations Attributes group.
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 13]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ The "end-of-attributes-tag" (value 0x03) MUST occur exactly once in
+ an operation. It MUST be the last "delimiter-tag". If the operation
+ has a document-content group, the document data in that group MUST
+ follow the "end-of-attributes-tag".
+
+ The order and presence of "attribute-group" fields (whose beginning
+ is marked by the "begin-attribute-group-tag" subfield) for each
+ operation request and each operation response MUST be that defined in
+ the model document. For further details, see section 3.7 "(Attribute)
+ Name" and 13 "Appendix A: Protocol Examples".
+
+ A Printer MUST treat a "delimiter-tag" (values from 0x00 through
+ 0x0F) differently from a "value-tag" (values from 0x10 through 0xFF)
+ so that the Printer knows that there is an entire attribute group
+ that it doesn't understand as opposed to a single value that it
+ doesn't understand.
+
+3.5.2 Value Tags
+
+ The remaining tables show values for the "value-tag" field, which is
+ the first octet of an attribute. The "value-tag" field specifies the
+ type of the value of the attribute.
+
+ The following table specifies the "out-of-band" values for the
+ "value-tag" field.
+
+ Tag Value (Hex) Meaning
+
+ 0x10 unsupported
+ 0x11 reserved for 'default' for definition in a future
+ IETF standards track document
+ 0x12 unknown
+ 0x13 no-value
+ 0x14-0x1F reserved for "out-of-band" values in future IETF
+ standards track documents.
+
+ The following table specifies the integer values for the "value-tag"
+ field:
+
+ Tag Value (Hex) Meaning
+
+ 0x20 reserved for definition in a future IETF
+ standards track document
+ 0x21 integer
+ 0x22 boolean
+ 0x23 enum
+ 0x24-0x2F reserved for integer types for definition in
+ future IETF standards track documents
+
+
+
+Herriot, et al. Standards Track [Page 14]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ NOTE: 0x20 is reserved for "generic integer" if it should ever be
+ needed.
+
+ The following table specifies the octetString values for the "value-
+ tag" field:
+
+ Tag Value (Hex) Meaning
+
+ 0x30 octetString with an unspecified format
+ 0x31 dateTime
+ 0x32 resolution
+ 0x33 rangeOfInteger
+ 0x34 reserved for definition in a future IETF
+ standards track document
+ 0x35 textWithLanguage
+ 0x36 nameWithLanguage
+ 0x37-0x3F reserved for octetString type definitions in
+ future IETF standards track documents
+
+ The following table specifies the character-string values for the
+ "value-tag" field:
+
+ Tag Value (Hex) Meaning
+
+ 0x40 reserved for definition in a future IETF
+ standards track document
+ 0x41 textWithoutLanguage
+ 0x42 nameWithoutLanguage
+ 0x43 reserved for definition in a future IETF
+ standards track document
+ 0x44 keyword
+ 0x45 uri
+ 0x46 uriScheme
+ 0x47 charset
+ 0x48 naturalLanguage
+ 0x49 mimeMediaType
+ 0x4A-0x5F reserved for character string type definitions
+ in future IETF standards track documents
+
+ NOTE: 0x40 is reserved for "generic character-string" if it should
+ ever be needed.
+
+ NOTE: an attribute value always has a type, which is explicitly
+ specified by its tag; one such tag value is "nameWithoutLanguage".
+ An attribute's name has an implicit type, which is keyword.
+
+ The values 0x60-0xFF are reserved for future type definitions in IETF
+ standards track documents.
+
+
+
+Herriot, et al. Standards Track [Page 15]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ The tag 0x7F is reserved for extending types beyond the 255 values
+ available with a single byte. A tag value of 0x7F MUST signify that
+ the first 4 bytes of the value field are interpreted as the tag
+ value. Note this future extension doesn't affect parsers that are
+ unaware of this special tag. The tag is like any other unknown tag,
+ and the value length specifies the length of a value, which contains
+ a value that the parser treats atomically. Values from 0x00 to
+ 0x37777777 are reserved for definition in future IETF standard track
+ documents. The values 0x40000000 to 0x7FFFFFFF are reserved for
+ vendor extensions.
+
+3.6 Name-Length
+
+ The "name-length" field MUST consist of a SIGNED-SHORT. This field
+ MUST specify the number of octets in the immediately following "name"
+ field. The value of this field excludes the two bytes of the "name-
+ length" field. For example, if the "name" field contains "sides", the
+ value of this field is 5.
+
+ If a "name-length" field has a value of zero, the following "name"
+ field MUST be empty, and the following value MUST be treated as an
+ additional value for the attribute encoded in the nearest preceding
+ "attribute-with-one-value" field. Within an attribute group, if two
+ or more attributes have the same name, the attribute group is mal-
+ formed (see [RFC2911] section 3.1.3). The zero-length name is the
+ only mechanism for multi-valued attributes.
+
+3.7 (Attribute) Name
+
+ The "name" field MUST contain the name of an attribute. The model
+ document [RFC2911] specifies such names.
+
+3.8 Value Length
+
+ The "value-length" field MUST consist of a SIGNED-SHORT. This field
+ MUST specify the number of octets in the immediately following
+ "value" field. The value of this field excludes the two bytes of the
+ "value-length" field. For example, if the "value" field contains the
+ keyword (text) value 'one-sided', the value of this field is 9.
+
+ For any of the types represented by binary signed integers, the
+ sender MUST encode the value in exactly four octets.
+
+ For any of the types represented by character-strings, the sender
+ MUST encode the value with all the characters of the string and
+ without any padding characters.
+
+
+
+
+
+Herriot, et al. Standards Track [Page 16]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ For "out-of-band" "value-tag" fields defined in this document, such
+ as "unsupported", the "value-length" MUST be 0 and the "value" empty;
+ the "value" has no meaning when the "value-tag" has one of these
+ "out-of-band" values. For future "out-of-band" "value-tag" fields,
+ the same rule holds unless the definition explicitly states that the
+ "value-length" MAY be non-zero and the "value" non-empty.
+
+3.9 (Attribute) Value
+
+ The syntax types (specified by the "value-tag" field) and most of the
+ details of the representation of attribute values are defined in the
+ IPP model document. The table below augments the information in the
+ model document, and defines the syntax types from the model document
+ in terms of the 5 basic types defined in section 3, "Encoding of the
+ Operation Layer". The 5 types are US-ASCII-STRING, LOCALIZED-STRING,
+ SIGNED-INTEGER, SIGNED-SHORT, SIGNED-BYTE, and OCTET-STRING.
+
+ Syntax of Attribute Encoding
+ Value
+
+ textWithoutLanguage, LOCALIZED-STRING.
+ nameWithoutLanguage
+
+ textWithLanguage OCTET-STRING consisting of 4 fields:
+ a. a SIGNED-SHORT which is the number of
+ octets in the following field
+ b. a value of type natural-language,
+ c. a SIGNED-SHORT which is the number of
+ octets in the following field,
+ d. a value of type textWithoutLanguage.
+ The length of a textWithLanguage value MUST be
+ 4 + the value of field a + the value of field c.
+
+ nameWithLanguage OCTET-STRING consisting of 4 fields:
+ a. a SIGNED-SHORT which is the number of
+ octets in the following field
+ b. a value of type natural-language,
+ c. a SIGNED-SHORT which is the number of
+ octets in the following field
+ d. a value of type nameWithoutLanguage.
+ The length of a nameWithLanguage value MUST be
+ 4 + the value of field a + the value of field c.
+
+ charset, US-ASCII-STRING.
+ naturalLanguage,
+ mimeMediaType,
+ keyword, uri, and
+ uriScheme
+
+
+
+Herriot, et al. Standards Track [Page 17]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Syntax of Attribute Encoding
+ Value
+
+ boolean SIGNED-BYTE where 0x00 is 'false' and 0x01 is
+ 'true'.
+
+ integer and enum a SIGNED-INTEGER.
+
+ dateTime OCTET-STRING consisting of eleven octets whose
+ contents are defined by "DateAndTime" in RFC
+ 1903 [RFC1903].
+
+ resolution OCTET-STRING consisting of nine octets of 2
+ SIGNED-INTEGERs followed by a SIGNED-BYTE. The
+ first SIGNED-INTEGER contains the value of
+ cross feed direction resolution. The second
+ SIGNED-INTEGER contains the value of feed
+ direction resolution. The SIGNED-BYTE contains
+ the units
+
+ rangeOfInteger Eight octets consisting of 2 SIGNED-INTEGERs.
+ The first SIGNED-INTEGER contains the lower
+ bound and the second SIGNED-INTEGER contains
+ the upper bound.
+
+ 1setOf X Encoding according to the rules for an
+ attribute with more than 1 value. Each value
+ X is encoded according to the rules for
+ encoding its type.
+
+ octetString OCTET-STRING
+
+
+ The attribute syntax type of the value determines its encoding and
+ the value of its "value-tag".
+
+3.10 Data
+
+ The "data" field MUST include any data required by the operation
+
+4. Encoding of Transport Layer
+
+ HTTP/1.1 [RFC2616] is the transport layer for this protocol.
+
+ The operation layer has been designed with the assumption that the
+ transport layer contains the following information:
+
+
+
+
+
+Herriot, et al. Standards Track [Page 18]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ - the URI of the target job or printer operation
+ - the total length of the data in the operation layer, either as
+ a single length or as a sequence of chunks each with a length.
+
+ It is REQUIRED that a printer implementation support HTTP over the
+ IANA assigned Well Known Port 631 (the IPP default port), though a
+ printer implementation may support HTTP over some other port as well.
+
+ Each HTTP operation MUST use the POST method where the request-URI is
+ the object target of the operation, and where the "Content-Type" of
+ the message-body in each request and response MUST be
+ "application/ipp". The message-body MUST contain the operation layer
+ and MUST have the syntax described in section 3.2 "Syntax of
+ Encoding". A client implementation MUST adhere to the rules for a
+ client described for HTTP1.1 [RFC2616]. A printer (server)
+ implementation MUST adhere the rules for an origin server described
+ for HTTP1.1 [RFC2616].
+
+ An IPP server sends a response for each request that it receives. If
+ an IPP server detects an error, it MAY send a response before it has
+ read the entire request. If the HTTP layer of the IPP server
+ completes processing the HTTP headers successfully, it MAY send an
+ intermediate response, such as "100 Continue", with no IPP data
+ before sending the IPP response. A client MUST expect such a variety
+ of responses from an IPP server. For further information on HTTP/1.1,
+ consult the HTTP documents [RFC2616].
+
+ An HTTP server MUST support chunking for IPP requests, and an IPP
+ client MUST support chunking for IPP responses according to HTTP/1.1
+ [RFC2616]. Note: this rule causes a conflict with non-compliant
+ implementations of HTTP/1.1 that don't support chunking for POST
+ methods, and this rule may cause a conflict with non-compliant
+ implementations of HTTP/1.1 that don't support chunking for CGI
+ scripts.
+
+4.1 Printer-uri and job-uri
+
+ All Printer and Job objects are identified by a Uniform Resource
+ Identifier (URI) [RFC2396] so that they can be persistently and
+ unambiguously referenced. Since every URL is a specialized form of a
+ URI, even though the more generic term URI is used throughout the
+ rest of this document, its usage is intended to cover the more
+ specific notion of URL as well.
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 19]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Some operation elements are encoded twice, once as the request-URI on
+ the HTTP Request-Line and a second time as a REQUIRED operation
+ attribute in the application/ipp entity. These attributes are the
+ target URI for the operation and are called printer-uri and job-uri.
+ Note: The target URI is included twice in an operation referencing
+ the same IPP object, but the two URIs NEED NOT be literally
+ identical. One can be a relative URI and the other can be an absolute
+ URI. HTTP/1.1 allows clients to generate and send a relative URI
+ rather than an absolute URI. A relative URI identifies a resource
+ with the scope of the HTTP server, but does not include scheme, host
+ or port. The following statements characterize how URLs should be
+ used in the mapping of IPP onto HTTP/1.1:
+
+ 1. Although potentially redundant, a client MUST supply the target
+ of the operation both as an operation attribute and as a URI at
+ the HTTP layer. The rationale for this decision is to maintain
+ a consistent set of rules for mapping application/ipp to
+ possibly many communication layers, even where URLs are not
+ used as the addressing mechanism in the transport layer.
+ 2. Even though these two URLs might not be literally identical
+ (one being relative and the other being absolute), they MUST
+ both reference the same IPP object. However, a Printer NEED NOT
+ verify that the two URLs reference the same IPP object, and
+ NEED NOT take any action if it determines the two URLs to be
+ different.
+ 3. The URI in the HTTP layer is either relative or absolute and is
+ used by the HTTP server to route the HTTP request to the
+ correct resource relative to that HTTP server. The HTTP server
+ need not be aware of the URI within the operation request.
+ 4. Once the HTTP server resource begins to process the HTTP
+ request, it might get the reference to the appropriate IPP
+ Printer object from either the HTTP URI (using to the context
+ of the HTTP server for relative URLs) or from the URI within
+ the operation request; the choice is up to the implementation.
+ 5. HTTP URIs can be relative or absolute, but the target URI in
+ the operation MUST be an absolute URI.
+
+5. IPP URL Scheme
+
+ The IPP/1.1 document defines a new scheme 'ipp' as the value of a URL
+ that identifies either an IPP printer object or an IPP job object.
+ The IPP attributes using the 'ipp' scheme are specified below.
+ Because the HTTP layer does not support the 'ipp' scheme, a client
+ MUST map 'ipp' URLs to 'http' URLs, and then follows the HTTP
+ [RFC2616][RFC2617] rules for constructing a Request-Line and HTTP
+ headers. The mapping is simple because the 'ipp' scheme implies all
+ of the same protocol semantics as that of the 'http' scheme
+
+
+
+
+Herriot, et al. Standards Track [Page 20]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ [RFC2616], except that it represents a print service and the implicit
+ (default) port number that clients use to connect to a server is port
+ 631.
+
+ In the remainder of this section the term 'ipp-URL' means a URL whose
+ scheme is 'ipp' and whose implicit (default) port is 631. The term
+ 'http-URL' means a URL whose scheme is 'http', and the term 'https-
+ URL' means a URL whose scheme is 'https',
+
+ A client and an IPP object (i.e. the server) MUST support the ipp-URL
+ value in the following IPP attributes.
+ job attributes:
+ job-uri
+ job-printer-uri
+ printer attributes:
+ printer-uri-supported
+ operation attributes:
+ job-uri
+ printer-uri
+ Each of the above attributes identifies a printer or job object. The
+ ipp-URL is intended as the value of the attributes in this list, and
+ for no other attributes. All of these attributes have a syntax type
+ of 'uri', but there are attributes with a syntax type of 'uri' that
+ do not use the 'ipp' scheme, e.g. 'job-more-info'.
+
+ If a printer registers its URL with a directory service, the printer
+ MUST register an ipp-URL.
+
+ User interfaces are beyond the scope of this document. But if
+ software exposes the ipp-URL values of any of the above five
+ attributes to a human user, it is REQUIRED that the human see the
+ ipp-URL as is.
+
+ When a client sends a request, it MUST convert a target ipp-URL to a
+ target http-URL for the HTTP layer according to the following rules:
+
+ 1. change the 'ipp' scheme to 'http'
+ 2. add an explicit port 631 if the URL does not contain an
+ explicit port. Note: port 631 is the IANA assigned Well Known
+ Port for the 'ipp' scheme.
+
+ The client MUST use the target http-URL in both the HTTP Request-
+ Line and HTTP headers, as specified by HTTP [RFC2616] [RFC2617] .
+ However, the client MUST use the target ipp-URL for the value of the
+ "printer-uri" or "job-uri" operation attribute within the
+ application/ipp body of the request. The server MUST use the ipp-URL
+
+
+
+
+
+Herriot, et al. Standards Track [Page 21]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ for the value of the "printer-uri", "job-uri" or "printer-uri-
+ supported" attributes within the application/ipp body of the
+ response.
+
+ For example, when an IPP client sends a request directly (i.e. no
+ proxy) to an ipp-URL "ipp://myhost.com/myprinter/myqueue", it opens a
+ TCP connection to port 631 (the ipp implicit port) on the host
+ "myhost.com" and sends the following data:
+
+ POST /myprinter/myqueue HTTP/1.1
+ Host: myhost.com:631
+ Content-type: application/ipp
+ Transfer-Encoding: chunked
+ ...
+ "printer-uri" "ipp://myhost.com/myprinter/myqueue"
+ (encoded in application/ipp message body)
+ ...
+
+ As another example, when an IPP client sends the same request as
+ above via a proxy "myproxy.com", it opens a TCP connection to the
+ proxy port 8080 on the proxy host "myproxy.com" and sends the
+ following data:
+
+ POST http://myhost.com:631/myprinter/myqueue HTTP/1.1
+ Host: myhost.com:631
+ Content-type: application/ipp
+ Transfer-Encoding: chunked
+ ...
+ "printer-uri" "ipp://myhost.com/myprinter/myqueue"
+ (encoded in application/ipp message body)
+ ...
+
+ The proxy then connects to the IPP origin server with headers that
+ are the same as the "no-proxy" example above.
+
+6. IANA Considerations
+
+ This section describes the procedures for allocating encoding for the
+ following IETF standards track extensions and vendor extensions to
+ the IPP/1.1 Encoding and Transport document:
+
+ 1. attribute syntaxes - see [RFC2911] section 6.3
+ 2. attribute groups - see [RFC2911] section 6.5
+ 3. out-of-band attribute values - see [RFC2911] section 6.7
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 22]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ These extensions follow the "type2" registration procedures defined
+ in [RFC2911] section 6. Extensions registered for use with IPP/1.1
+ are OPTIONAL for client and IPP object conformance to the IPP/1.1
+ Encoding and Transport document.
+
+ These extension procedures are aligned with the guidelines as set
+ forth by the IESG [IANA-CON]. The [RFC2911] Section 11 describes how
+ to propose new registrations for consideration. IANA will reject
+ registration proposals that leave out required information or do not
+ follow the appropriate format described in [RFC2911] Section 11. The
+ IPP/1.1 Encoding and Transport document may also be extended by an
+ appropriate RFC that specifies any of the above extensions.
+
+7. Internationalization Considerations
+
+ See the section on "Internationalization Considerations" in the
+ document "Internet Printing Protocol/1.1: Model and Semantics"
+ [RFC2911] for information on internationalization. This document adds
+ no additional issues.
+
+8. Security Considerations
+
+ The IPP Model and Semantics document [RFC2911] discusses high level
+ security requirements (Client Authentication, Server Authentication
+ and Operation Privacy). Client Authentication is the mechanism by
+ which the client proves its identity to the server in a secure
+ manner. Server Authentication is the mechanism by which the server
+ proves its identity to the client in a secure manner. Operation
+ Privacy is defined as a mechanism for protecting operations from
+ eavesdropping.
+
+8.1 Security Conformance Requirements
+
+ This section defines the security requirements for IPP clients and
+ IPP objects.
+
+8.1.1 Digest Authentication
+
+ IPP clients MUST support:
+
+ Digest Authentication [RFC2617].
+
+ MD5 and MD5-sess MUST be implemented and supported.
+
+ The Message Integrity feature NEED NOT be used.
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 23]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ IPP Printers SHOULD support:
+
+ Digest Authentication [RFC2617].
+
+ MD5 and MD5-sess MUST be implemented and supported.
+
+ The Message Integrity feature NEED NOT be used.
+
+ The reasons that IPP Printers SHOULD (rather than MUST) support
+ Digest Authentication are:
+
+ 1. While Client Authentication is important, there is a certain class
+ of printer devices where it does not make sense. Specifically, a
+ low-end device with limited ROM space and low paper throughput may
+ not need Client Authentication. This class of device typically
+ requires firmware designers to make trade-offs between protocols
+ and functionality to arrive at the lowest-cost solution possible.
+ Factored into the designer's decisions is not just the size of the
+ code, but also the testing, maintenance, usefulness, and time-to-
+ market impact for each feature delivered to the customer. Forcing
+ such low-end devices to provide security in order to claim IPP/1.1
+ conformance would not make business sense and could potentially
+ stall the adoption of the standard.
+
+ 2. Print devices that have high-volume throughput and have available
+ ROM space have a compelling argument to provide support for Client
+ Authentication that safeguards the device from unauthorized
+ access. These devices are prone to a high loss of consumables and
+ paper if unauthorized access should occur.
+
+8.1.2 Transport Layer Security (TLS)
+
+ IPP Printers SHOULD support Transport Layer Security (TLS) [RFC2246]
+ for Server Authentication and Operation Privacy. IPP Printers MAY
+ also support TLS for Client Authentication. If an IPP Printer
+ supports TLS, it MUST support the TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
+ cipher suite as mandated by RFC 2246 [RFC2246]. All other cipher
+ suites are OPTIONAL. An IPP Printer MAY support Basic Authentication
+ (described in HTTP/1.1 [RFC2617]) for Client Authentication if the
+ channel is secure. TLS with the above mandated cipher suite can
+ provide such a secure channel.
+
+ If a IPP client supports TLS, it MUST support the
+ TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA cipher suite as mandated by RFC
+ 2246 [RFC2246]. All other cipher suites are OPTIONAL.
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 24]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ The IPP Model and Semantics document defines two printer attributes
+ ("uri-authentication-supported" and "uri-security-supported") that
+ the client can use to discover the security policy of a printer. That
+ document also outlines IPP-specific security considerations and
+ should be the primary reference for security implications with regard
+ to the IPP protocol itself. For backward compatibility with IPP
+ version 1.0, IPP clients and printers may also support SSL3 [ssl].
+ This is in addition to the security required in this document.
+
+8.2 Using IPP with TLS
+
+ IPP/1.1 uses the "Upgrading to TLS Within HTTP/1.1" mechanism
+ [RFC2817]. An initial IPP request never uses TLS. The client
+ requests a secure TLS connection by using the HTTP "Upgrade" header,
+ while the server agrees in the HTTP response. The switch to TLS
+ occurs either because the server grants the client's request to
+ upgrade to TLS, or a server asks to switch to TLS in its response.
+ Secure communication begins with a server's response to switch to
+ TLS.
+
+9. Interoperability with IPP/1.0 Implementations
+
+ It is beyond the scope of this specification to mandate conformance
+ with previous versions. IPP/1.1 was deliberately designed, however,
+ to make supporting previous versions easy. It is worth noting that,
+ at the time of composing this specification (1999), we would expect
+ IPP/1.1 Printer implementations to:
+
+ understand any valid request in the format of IPP/1.0, or 1.1;
+
+ respond appropriately with a response containing the same
+ "version-number" parameter value used by the client in the
+ request.
+
+ And we would expect IPP/1.1 clients to:
+
+ understand any valid response in the format of IPP/1.0, or 1.1.
+
+9.1 The "version-number" Parameter
+
+ The following are rules regarding the "version-number" parameter (see
+ section 3.3):
+
+ 1. Clients MUST send requests containing a "version-number"
+ parameter with a '1.1' value and SHOULD try supplying alternate
+ version numbers if they receive a 'server-error-version-not-
+ supported' error return in a response.
+
+
+
+
+Herriot, et al. Standards Track [Page 25]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ 2. IPP objects MUST accept requests containing a "version-number"
+ parameter with a '1.1' value (or reject the request for reasons
+ other than 'server-error-version-not-supported').
+
+ 3. It is recommended that IPP objects accept any request with the
+ major version '1' (or reject the request for reasons other than
+ 'server-error-version-not-supported'). See [RFC2911]
+ "versions" sub-section.
+
+ 4. In any case, security MUST NOT be compromised when a client
+ supplies a lower "version-number" parameter in a request. For
+ example, if an IPP/1.1 conforming Printer object accepts
+ version '1.0' requests and is configured to enforce Digest
+ Authentication, it MUST do the same for a version '1.0'
+ request.
+
+9.2 Security and URL Schemes
+
+ The following are rules regarding security, the "version-number"
+ parameter, and the URL scheme supplied in target attributes and
+ responses:
+
+ 1. When a client supplies a request, the "printer-uri" or "job-
+ uri" target operation attribute MUST have the same scheme as
+ that indicated in one of the values of the "printer-uri-
+ supported" Printer attribute.
+
+ 2. When the server returns the "job-printer-uri" or "job-uri" Job
+ Description attributes, it SHOULD return the same scheme
+ ('ipp', 'https', 'http', etc.) that the client supplied in the
+ "printer-uri" or "job-uri" target operation attributes in the
+ Get-Job-Attributes or Get-Jobs request, rather than the scheme
+ used when the job was created. However, when a client requests
+ job attributes using the Get-Job-Attributes or Get-Jobs
+ operations, the jobs and job attributes that the server returns
+ depends on: (1) the security in effect when the job was
+ created, (2) the security in effect in the query request, and
+ (3) the security policy in force.
+
+ 3. It is recommended that if a server registers a non-secure ipp-
+ URL with a directory service (see [RFC2911] "Generic Directory
+ Schema" Appendix), then it also register an http-URL for
+ interoperability with IPP/1.0 clients (see section 9).
+
+ 4. In any case, security MUST NOT be compromised when a client
+ supplies an 'http' or other non-secure URL scheme in the target
+ "printer-uri" and "job-uri" operation attributes in a request.
+
+
+
+
+Herriot, et al. Standards Track [Page 26]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+10. References
+
+ [dpa] ISO/IEC 10175 Document Printing Application (DPA), June
+ 1996.
+
+ [iana] IANA Registry of Coded Character Sets:
+ ftp://ftp.isi.edu/in-notes/iana/assignments/character-
+ sets.
+
+ [IANA-CON] Narten, T. and H. Alvestrand, "Guidelines for Writing an
+ IANA Considerations Section in RFCs", BCP 26, RFC 2434,
+ October 1998.
+
+ [ipp-iig] Hastings, Tom, et al., "Internet Printing Protocol/1.1:
+ Implementer's Guide", Work in Progress.
+
+ [RFC822] Crocker, D., "Standard for the Format of ARPA Internet
+ Text Messages", STD 11, RFC 822, August 1982.
+
+ [RFC1123] Braden, S., "Requirements for Internet Hosts - Application
+ and Support", STD 3, RFC 1123, October, 1989.
+
+ [RFC1179] McLaughlin, L. III, (editor), "Line Printer Daemon
+ Protocol", RFC 1179, August 1990.
+
+ [RFC2223] Postel, J. and J. Reynolds, "Instructions to RFC Authors",
+ RFC 2223, October 1997.
+
+ [RFC1738] Berners-Lee, T., Masinter, L. and M. McCahill, "Uniform
+ Resource Locators (URL)", RFC 1738, December 1994.
+
+ [RFC1759] Smith, R., Wright, F., Hastings, T., Zilles, S. and J.
+ Gyllenskog, "Printer MIB", RFC 1759, March 1995.
+
+ [RFC1766] Alvestrand, H., "Tags for the Identification of
+ Languages", RFC 1766, March 1995.
+
+ [RFC1808] Fielding, R., "Relative Uniform Resource Locators", RFC
+ 1808, June 1995.
+
+ [RFC1903] Case, J., McCloghrie, K., Rose, M. and S. Waldbusser,
+ "Textual Conventions for Version 2 of the Simple Network
+ Management Protocol (SNMPv2)", RFC 1903, January 1996.
+
+ [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046,
+ November 1996.
+
+
+
+
+Herriot, et al. Standards Track [Page 27]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ [RFC2048] Freed, N., Klensin, J. and J. Postel, "Multipurpose
+ Internet Mail Extension (MIME) Part Four: Registration
+ Procedures", BCP 13, RFC 2048, November 1996.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2184] Freed, N. and K. Moore, "MIME Parameter Value and Encoded
+ Word Extensions: Character Sets, Languages, and
+ Continuations", RFC 2184, August 1997.
+
+ [RFC2234] Crocker, D. and P. Overall, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol", RFC 2246.
+ January 1999.
+
+ [RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform
+ Resource Identifiers (URI): Generic Syntax", RFC 2396,
+ August 1998.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Turner,
+ "Internet Printing Protocol/1.0: Encoding and Transport",
+ RFC 2565, April 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569, April
+ 1999.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P. and T. Berners-Lee, "Hypertext
+ Transfer Protocol - HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC2617] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S.,
+ Leach, P., Luotonen, A. and L. Stewart, "HTTP
+ Authentication: Basic and Digest Access Authentication",
+ RFC 2617, June 1999.
+
+
+
+Herriot, et al. Standards Track [Page 28]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ [RFC2817] Khare, R. and S. Lawrence, "Upgrading to TLS Within
+ HTTP/1.1", RFC 2817, May 2000.
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P., Turner, R. and J.
+ Wenn, "Internet Printing Protocol/1.1: Encoding and
+ Transport", RFC 2910, September 2000.
+
+ [RFC2911] Hastings, T., Herriot, R., deBry, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.1: Model and
+ Semantics", RFC 2911, September 2000.
+
+ [SSL] Netscape, The SSL Protocol, Version 3, (Text version
+ 3.02), November 1996.
+
+11. Authors' Addresses
+
+ Robert Herriot, Editor
+ Xerox Corporation
+ 3400 Hillview Ave., Bldg #1
+ Palo Alto, CA 94304
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ EMail: robert.herriot@pahv.xerox.com
+
+
+ Sylvan Butler
+ Hewlett-Packard
+ 11311 Chinden Blvd.
+ Boise, ID 83714
+
+ Phone: 208-396-6000
+ Fax: 208-396-3457
+ EMail: sbutler@boi.hp.com
+
+
+ Paul Moore
+ Peerless Systems Networking
+ 10900 NE 8th St #900
+ Bellevue, WA 98004
+
+ Phone: 425-462-5852
+ EMail: pmoore@peerless.com
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 29]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Randy Turner
+ 2Wire, Inc.
+ 694 Tasman Dr.
+ Milpitas, CA 95035
+
+ Phone: 408-546-1273
+
+
+ John Wenn
+ Xerox Corporation
+ 737 Hawaii St
+ El Segundo, CA 90245
+
+ Phone: 310-333-5764
+ Fax: 310-333-5514
+ EMail: jwenn@cp10.es.xerox.com
+
+
+ IPP Web Page: http://www.pwg.org/ipp/
+ IPP Mailing List: ipp@pwg.org
+
+ To subscribe to the ipp mailing list, send the following email:
+ 1) send it to majordomo@pwg.org
+ 2) leave the subject line blank
+ 3) put the following two lines in the message body:
+ subscribe ipp
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 30]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+12. Other Participants:
+
+ Chuck Adams - Tektronix Shivaun Albright - HP
+ Stefan Andersson - Axis Jeff Barnett - IBM
+ Ron Bergman - Hitachi Koki Imaging Dennis Carney - IBM
+ Systems
+ Keith Carter - IBM Angelo Caruso - Xerox
+ Rajesh Chawla - TR Computing Nancy Chen - Okidata
+ Solutions
+ Josh Cohen - Microsoft Jeff Copeland - QMS
+ Andy Davidson - Tektronix Roger deBry - IBM
+ Maulik Desai - Auco Mabry Dozier - QMS
+ Lee Farrell - Canon Information Satoshi Fujitami - Ricoh
+ Systems
+ Steve Gebert - IBM Sue Gleeson - Digital
+ Charles Gordon - Osicom Brian Grimshaw - Apple
+ Jerry Hadsell - IBM Richard Hart - Digital
+ Tom Hastings - Xerox Henrik Holst - I-data
+ Stephen Holmstead Zhi-Hong Huang - Zenographics
+ Scott Isaacson - Novell Babek Jahromi - Microsoft
+ Swen Johnson - Xerox David Kellerman - Northlake
+ Software
+ Robert Kline - TrueSpectra Charles Kong - Panasonic
+ Carl Kugler - IBM Dave Kuntz - Hewlett-Packard
+ Takami Kurono - Brother Rick Landau - Digital
+ Scott Lawrence - Agranot Systems Greg LeClair - Epson
+ Dwight Lewis - Lexmark Harry Lewis - IBM
+ Tony Liao - Vivid Image Roy Lomicka - Digital
+ Pete Loya - HP Ray Lutz - Cognisys
+ Mike MacKay - Novell, Inc. David Manchala - Xerox
+ Carl-Uno Manros - Xerox Jay Martin - Underscore
+ Stan McConnell - Xerox Larry Masinter - Xerox
+ Sandra Matts - Hewlett Packard Peter Michalek - Shinesoft
+ Ira McDonald - High North Inc. Mike Moldovan - G3 Nova
+ Tetsuya Morita - Ricoh Yuichi Niwa - Ricoh
+ Pat Nogay - IBM Ron Norton - Printronics
+ Hugo Parra, Novell Bob Pentecost - Hewlett-Packard
+ Patrick Powell - Astart Jeff Rackowitz - Intermec
+ Technologies
+ Eric Random - Peerless Rob Rhoads - Intel
+ Xavier Riley - Xerox Gary Roberts - Ricoh
+ David Roach - Unisys Stuart Rowley - Kyocera
+ Yuji Sasaki - Japan Computer Richard Schneider - Epson
+ Industry
+ Kris Schoff - HP Katsuaki Sekiguchi - Canon
+ Information Systems
+
+
+
+
+
+Herriot, et al. Standards Track [Page 31]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Bob Setterbo - Adobe Gail Songer - Peerless
+ Hideki Tanaka - Cannon Information Devon Taylor - Novell, Inc.
+ Systems
+ Mike Timperman - Lexmark Atsushi Uchino - Epson
+ Shigeru Ueda - Canon Bob Von Andel - Allegro Software
+ William Wagner - NetSilicon/DPI Jim Walker - DAZEL
+ Chris Wellens - Interworking Labs Trevor Wells - Hewlett Packard
+ Craig Whittle - Sharp Labs Rob Whittle - Novell, Inc.
+ Jasper Wong - Xionics Don Wright - Lexmark
+ Michael Wu - Heidelberg Digital Rick Yardumian - Xerox
+ Michael Yeung - Canon Information Lloyd Young - Lexmark
+ Systems
+ Atsushi Yuki - Kyocera Peter Zehler - Xerox
+ William Zhang - Canon Information Frank Zhao - Panasonic
+ Systems
+ Steve Zilles - Adobe Rob Zirnstein - Canon Information
+ Systems
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 32]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+13. Appendix A: Protocol Examples
+
+13.1 Print-Job Request
+
+ The following is an example of a Print-Job request with job-name,
+ copies, and sides specified. The "ipp-attribute-fidelity" attribute
+ is set to 'true' so that the print request will fail if the "copies"
+ or the "sides" attribute are not supported or their values are not
+ supported.
+
+ Octets Symbolic Value Protocol field
+
+ 0x0101 1.1 version-number
+ 0x0002 Print-Job operation-id
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- name
+ natural- attributes-natural-language
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x45 uri type value-tag
+ 0x000B name-length
+ printer-uri printer-uri name
+ 0x0015 value-length
+ ipp://forest/ printer pinetree value
+ pinetree
+ 0x42 nameWithoutLanguage type value-tag
+ 0x0008 name-length
+ job-name job-name name
+ 0x0006 value-length
+ foobar foobar value
+ 0x22 boolean type value-tag
+ 0x0016 name-length
+ ipp-attribute- ipp-attribute-fidelity name
+ fidelity
+ 0x0001 value-length
+ 0x01 true value
+
+
+
+
+
+Herriot, et al. Standards Track [Page 33]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ 0x02 start job-attributes job-attributes-tag
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ copies copies name
+ 0x0004 value-length
+ 0x00000014 20 value
+ 0x44 keyword type value-tag
+ 0x0005 name-length
+ sides sides name
+ 0x0013 value-length
+ two-sided- two-sided-long-edge value
+ long-edge
+ 0x03 end-of-attributes end-of-attributes-tag
+ %!PS... <PostScript> data
+
+13.2 Print-Job Response (successful)
+
+ Here is an example of a successful Print-Job response to the previous
+ Print-Job request. The printer supported the "copies" and "sides"
+ attributes and their supplied values. The status code returned is
+ 'successful-ok'.
+
+ Octets Symbolic Value Protocol field
+
+ 0x0101 1.1 version-number
+ 0x0000 successful-ok status-code
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural- name
+ natural-language language
+ 0x0005 value-length
+ en-us en-US value
+ 0x41 textWithoutLanguage type value-tag
+ 0x000E name-length
+ status-message status-message name
+ 0x000D value-length
+
+
+
+
+
+Herriot, et al. Standards Track [Page 34]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ successful-ok successful-ok value
+ 0x02 start job-attributes job-attributes-tag
+ 0x21 integer value-tag
+ 0x0006 name-length
+ job-id job-id name
+ 0x0004 value-length
+ 147 147 value
+ 0x45 uri type value-tag
+ 0x0007 name-length
+ job-uri job-uri name
+ 0x0019 value-length
+ ipp://forest/ job 123 on pinetree value
+ pinetree/123
+ 0x23 enum type value-tag
+ 0x0009 name-length
+ job-state job-state name
+ 0x0004 value-length
+ 0x0003 pending value
+ 0x03 end-of-attributes end-of-attributes-tag
+
+13.3 Print-Job Response (failure)
+
+ Here is an example of an unsuccessful Print-Job response to the
+ previous Print-Job request. It fails because, in this case, the
+ printer does not support the "sides" attribute and because the value
+ '20' for the "copies" attribute is not supported. Therefore, no job
+ is created, and neither a "job-id" nor a "job-uri" operation
+ attribute is returned. The error code returned is 'client-error-
+ attributes-or-values-not-supported' (0x040B).
+
+ 0x0101 1.1 version-number
+ 0x040B client-error-attributes-or- status-code
+ values-not-supported
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 35]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x41 textWithoutLanguage type value-tag
+ 0x000E name-length
+ status- status-message name
+ message
+ 0x002F value-length
+ client-error- value
+ attributes- values-not-supported
+ or-values- client-error-attributes-or-
+ not-supported
+ 0x05 start unsupported-attributes unsupported-attributes tag
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ copies copies name
+ 0x0004 value-length
+ 0x00000014 20 value
+ 0x10 unsupported (type) value-tag
+ 0x0005 name-length
+ sides sides name
+ 0x0000 value-length
+ 0x03 end-of-attributes end-of-attributes-tag
+
+13.4 Print-Job Response (success with attributes ignored)
+
+ Here is an example of a successful Print-Job response to a Print-Job
+ request like the previous Print-Job request, except that the value of
+ 'ipp-attribute-fidelity' is false. The print request succeeds, even
+ though, in this case, the printer supports neither the "sides"
+ attribute nor the value '20' for the "copies" attribute. Therefore, a
+ job is created, and both a "job-id" and a "job-uri" operation
+ attribute are returned. The unsupported attributes are also returned
+ in an Unsupported Attributes Group. The error code returned is
+ 'successful-ok-ignored-or-substituted-attributes' (0x0001).
+
+ Octets Symbolic Value Protocol field
+
+ 0x0101 1.1 version-number
+ 0x0001 successful-ok-ignored-or- status-code
+
+
+
+
+
+Herriot, et al. Standards Track [Page 36]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ substituted-attributes
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural- name
+ natural-language language
+ 0x0005 value-length
+ en-us en-US value
+ 0x41 textWithoutLanguage type value-tag
+ 0x000E name-length
+ status-message status-message name
+ 0x002F value-length
+ successful-ok- successful-ok-ignored-or- value
+ ignored-or- substituted-attributes
+ substituted-
+ attributes
+ 0x05 start unsupported- unsupported-attributes
+ attributes tag
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ copies copies name
+ 0x0004 value-length
+ 0x00000014 20 value
+ 0x10 unsupported (type) value-tag
+ 0x0005 name-length
+ sides sides name
+ 0x0000 value-length
+ 0x02 start job-attributes job-attributes-tag
+ 0x21 integer value-tag
+ 0x0006 name-length
+ job-id job-id name
+ 0x0004 value-length
+ 147 147 value
+ 0x45 uri type value-tag
+ 0x0007 name-length
+ job-uri job-uri name
+ 0x0019 value-length
+ ipp://forest/ job 123 on pinetree value
+ pinetree/123
+
+
+
+Herriot, et al. Standards Track [Page 37]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ 0x23 enum type value-tag
+ 0x0009 name-length
+ job-state job-state name
+ 0x0004 value-length
+ 0x0003 pending value
+ 0x03 end-of-attributes end-of-attributes-tag
+
+13.5 Print-URI Request
+
+ The following is an example of Print-URI request with copies and
+ job-name parameters:
+
+ Octets Symbolic Value Protocol field
+
+ 0x0101 1.1 version-number
+ 0x0003 Print-URI operation-id
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x45 uri type value-tag
+ 0x000B name-length
+ printer-uri printer-uri name
+ 0x0015 value-length
+ ipp://forest/ printer pinetree value
+ pinetree
+ 0x45 uri type value-tag
+ 0x000C name-length
+ document-uri document-uri name
+ 0x0011 value-length
+ ftp://foo.com ftp://foo.com/foo value
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 38]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ /foo
+ 0x42 nameWithoutLanguage type value-tag
+ 0x0008 name-length
+ job-name job-name name
+ 0x0006 value-length
+ foobar foobar value
+ 0x02 start job-attributes job-attributes-tag
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ copies copies name
+ 0x0004 value-length
+ 0x00000001 1 value
+ 0x03 end-of-attributes end-of-attributes-tag
+
+13.6 Create-Job Request
+
+ The following is an example of Create-Job request with no parameters
+ and no attributes:
+
+ Octets Symbolic Value Protocol field
+
+ 0x0101 1.1 version-number
+ 0x0005 Create-Job operation-id
+ 0x00000001 1 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x45 uri type value-tag
+ 0x000B name-length
+ printer-uri printer-uri name
+ 0x0015 value-length
+ ipp://forest/ printer pinetree value
+ pinetree
+
+
+
+
+
+Herriot, et al. Standards Track [Page 39]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ inetree
+ 0x03 end-of-attributes end-of-attributes-tag
+
+13.7 Get-Jobs Request
+
+ The following is an example of Get-Jobs request with parameters but
+ no attributes:
+
+ Octets Symbolic Value Protocol field
+
+ 0x0101 1.1 version-number
+ 0x000A Get-Jobs operation-id
+ 0x00000123 0x123 request-id
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x0008 value-length
+ us-ascii US-ASCII value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x45 uri type value-tag
+ 0x000B name-length
+ printer-uri printer-uri name
+ 0x0015 value-length
+ ipp://forest/ printer pinetree value
+ pinetree
+ 0x21 integer type value-tag
+ 0x0005 name-length
+ limit limit name
+ 0x0004 value-length
+ 0x00000032 50 value
+ 0x44 keyword type value-tag
+ 0x0014 name-length
+ requested- requested-attributes name
+ attributes
+ 0x0006 value-length
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 40]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ job-id job-id value
+ 0x44 keyword type value-tag
+ 0x0000 additional value name-length
+ 0x0008 value-length
+ job-name job-name value
+ 0x44 keyword type value-tag
+ 0x0000 additional value name-length
+ 0x000F value-length
+ document-format document-format value
+ 0x03 end-of-attributes end-of-attributes-tag
+
+13.8 Get-Jobs Response
+
+ The following is an of Get-Jobs response from previous request with 3
+ jobs. The Printer returns no information about the second job
+ (because of security reasons):
+
+ Octets Symbolic Value Protocol field
+
+ 0x0101 1.1 version-number
+ 0x0000 successful-ok status-code
+ 0x00000123 0x123 request-id (echoed
+ back)
+ 0x01 start operation-attributes operation-attributes-tag
+ 0x47 charset type value-tag
+ 0x0012 name-length
+ attributes- attributes-charset name
+ charset
+ 0x000A value-length
+ ISO-8859-1 ISO-8859-1 value
+ 0x48 natural-language type value-tag
+ 0x001B name-length
+ attributes- attributes-natural-language name
+ natural-
+ language
+ 0x0005 value-length
+ en-us en-US value
+ 0x41 textWithoutLanguage type value-tag
+ 0x000E name-length
+ status-message status-message name
+ 0x000D value-length
+ successful-ok successful-ok value
+ 0x02 start job-attributes (1st job-attributes-tag
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 41]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Octets Symbolic Value Protocol field
+
+ object)
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ job-id job-id name
+ 0x0004 value-length
+ 147 147 value
+ 0x36 nameWithLanguage value-tag
+ 0x0008 name-length
+ job-name job-name name
+ 0x000C value-length
+ 0x0005 sub-value-length
+ fr-ca fr-CA value
+ 0x0003 sub-value-length
+ fou fou name
+ 0x02 start job-attributes (2nd job-attributes-tag
+ object)
+ 0x02 start job-attributes (3rd job-attributes-tag
+ object)
+ 0x21 integer type value-tag
+ 0x0006 name-length
+ job-id job-id name
+ 0x0004 value-length
+ 148 149 value
+ 0x36 nameWithLanguage value-tag
+ 0x0008 name-length
+ job-name job-name name
+ 0x0012 value-length
+ 0x0005 sub-value-length
+ de-CH de-CH value
+ 0x0009 sub-value-length
+ isch guet isch guet name
+ 0x03 end-of-attributes end-of-attributes-tag
+
+14. Appendix B: Registration of MIME Media Type Information for
+ "application/ipp"
+
+ This appendix contains the information that IANA requires for
+ registering a MIME media type. The information following this
+ paragraph will be forwarded to IANA to register application/ipp whose
+ contents are defined in Section 3 "Encoding of the Operation Layer"
+ in this document:
+
+ MIME type name: application
+
+ MIME subtype name: ipp
+
+
+
+
+Herriot, et al. Standards Track [Page 42]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ A Content-Type of "application/ipp" indicates an Internet Printing
+ Protocol message body (request or response). Currently there is one
+ version: IPP/1.1, whose syntax is described in Section 3 "Encoding of
+ the Operation Layer" of [RFC2910], and whose semantics are described
+ in [RFC2911].
+
+ Required parameters: none
+
+ Optional parameters: none
+
+ Encoding considerations:
+
+ IPP/1.1 protocol requests/responses MAY contain long lines and ALWAYS
+ contain binary data (for example attribute value lengths).
+
+ Security considerations:
+
+ IPP/1.1 protocol requests/responses do not introduce any security
+ risks not already inherent in the underlying transport protocols.
+ Protocol mixed-version interworking rules in [RFC2911] as well as
+ protocol encoding rules in [RFC2910] are complete and unambiguous.
+
+ Interoperability considerations:
+
+ IPP/1.1 requests (generated by clients) and responses (generated by
+ servers) MUST comply with all conformance requirements imposed by the
+ normative specifications [RFC2911] and [RFC2910]. Protocol encoding
+ rules specified in [RFC2910] are comprehensive, so that
+ interoperability between conforming implementations is guaranteed
+ (although support for specific optional features is not ensured).
+ Both the "charset" and "natural-language" of all IPP/1.1 attribute
+ values which are a LOCALIZED-STRING are explicit within IPP protocol
+ requests/responses (without recourse to any external information in
+ HTTP, SMTP, or other message transport headers).
+
+ Published specifications:
+
+ [RFC2911] Hastings, T., Herriot, R., deBry, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.1: Model and
+ Semantics", RFC 2911, September 2000.
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P., Turner, R. and J.
+ Wenn, "Internet Printing Protocol/1.1: Encoding and
+ Transport", RFC 2910, September 2000.
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 43]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ Applications which use this media type:
+
+ Internet Printing Protocol (IPP) print clients and print servers,
+ communicating using HTTP/1.1 (see [RFC2910]), SMTP/ESMTP, FTP, or
+ other transport protocol. Messages of type "application/ipp" are
+ self-contained and transport-independent, including "charset" and
+ "natural-language" context for any LOCALIZED-STRING value.
+
+ Person & email address to contact for further information:
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE-231
+ El Segundo, CA
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ EMail: hastings@cp10.es.xerox.com
+
+ or
+
+ Robert Herriot
+ Xerox Corporation
+ 3400 Hillview Ave., Bldg #1
+ Palo Alto, CA 94304
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ EMail: robert.herriot@pahv.xerox.com
+
+ Intended usage:
+
+ COMMON
+
+15. Appendix C: Changes from IPP/1.0
+
+ IPP/1.1 is identical to IPP/1.0 [RFC2565] with the follow changes:
+
+ 1. Attributes values that identify a printer or job object use a new
+ 'ipp' scheme. The 'http' and 'https' schemes are supported only
+ for backward compatibility. See section 5.
+
+ 2. Clients MUST support of Digest Authentication, IPP Printers SHOULD
+ support Digest Authentication. See Section 8.1.1
+
+ 3. TLS is recommended for channel security. In addition, SSL3 may be
+ supported for backward compatibility. See Section 8.1.2
+
+
+
+
+Herriot, et al. Standards Track [Page 44]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+ 4. It is recommended that IPP/1.1 objects accept any request with
+ major version number '1'. See section 9.1.
+
+ 5. IPP objects SHOULD return the URL scheme requested for "job-
+ printer-uri" and "job-uri" Job Attributes, rather than the URL
+ scheme used to create the job. See section 9.2.
+
+ 6. The IANA and Internationalization sections have been added. The
+ terms "private use" and "experimental" have been changed to
+ "vendor extension". The reserved allocations for attribute group
+ tags, attribute syntax tags, and out-of-band attribute values have
+ been clarified as to which are reserved to future IETF standards
+ track documents and which are reserved to vendor extension. Both
+ kinds of extensions use the type2 registration procedures as
+ defined in [RFC2911].
+
+ 7. Clarified that future "out-of-band" value definitions may use the
+ value field if additional information is needed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 45]
+
+RFC 2910 IPP/1.1: Encoding and Transport September 2000
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 46]
+
diff --git a/standards/rfc2911.txt b/standards/rfc2911.txt
new file mode 100644
index 000000000..29c85a426
--- /dev/null
+++ b/standards/rfc2911.txt
@@ -0,0 +1,12547 @@
+
+
+
+
+
+
+Network Working Group T. Hastings, Editor
+Request for Comments: 2911 R. Herriot
+Obsoletes: 2566 Xerox Corporation
+Category: Standards Track R. deBry
+ Utah Valley State College
+ S. Isaacson
+ Novell, Inc.
+ P. Powell
+ Astart Technologies
+ September 2000
+
+
+ Internet Printing Protocol/1.1: Model and Semantics
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+Abstract
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ using Internet tools and technologies. This document describes a
+ simplified model consisting of abstract objects, their attributes,
+ and their operations that is independent of encoding and transport.
+ The model consists of a Printer and a Job object. A Job optionally
+ supports multiple documents. IPP 1.1 semantics allow end-users and
+ operators to query printer capabilities, submit print jobs, inquire
+ about the status of print jobs and printers, cancel, hold, release,
+ and restart print jobs. IPP 1.1 semantics allow operators to pause,
+ resume, and purge (jobs from) Printer objects. This document also
+ addresses security, internationalization, and directory issues.
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 1]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics (this document)
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [IPP-IIG]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. A few OPTIONAL operator operations have
+ been added to IPP/1.1.
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF working group's major decisions.
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1 [RFC2616]. It defines the
+ encoding rules for a new Internet MIME media type called
+ "application/ipp". This document also defines the rules for
+ transporting over HTTP a message body whose Content-Type is
+ "application/ipp". This document defines a new scheme named 'ipp'
+ for identifying IPP printers and jobs.
+
+ The "Internet Printing Protocol/1.1: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.1 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 2]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+Table of Contents
+
+ 1. Introduction 9
+ 1.1 Simplified Printing Model 10
+ 2. IPP Objects 12
+ 2.1 Printer Object 13
+ 2.2 Job Object 15
+ 2.3 Object Relationships 16
+ 2.4 Object Identity 17
+ 3. IPP Operations 20
+ 3.1 Common Semantics 21
+ 3.1.1 Required Parameters 21
+ 3.1.2 Operation IDs and Request IDs 22
+ 3.1.3 Attributes 22
+ 3.1.4 Character Set and Natural Language Operation Attribute 24
+ 3.1.4.1 Request Operation Attributes 25
+ 3.1.4.2 Response Operation Attributes 29
+ 3.1.5 Operation Targets 30
+ 3.1.6 Operation Response Status Codes and Status Messages 32
+ 3.1.6.1 "status-code" (type2 enum) 32
+ 3.1.6.2 "status-message" (text(255)) 33
+ 3.1.6.3 "detailed-status-message" (text(MAX)) 33
+ 3.1.6.4 "document-access-error" (text(MAX)) 34
+ 3.1.7 Unsupported Attributes 34
+ 3.1.8 Versions 36
+ 3.1.9 Job Creation Operations 38
+ 3.2 Printer Operations 41
+ 3.2.1 Print-Job Operation 41
+ 3.2.1.1 Print-Job Request 41
+ 3.2.1.2 Print-Job Response 46
+ 3.2.2 Print-URI Operation 48
+ 3.2.3 Validate-Job Operation 49
+ 3.2.4 Create-Job Operation 49
+ 3.2.5 Get-Printer-Attributes Operation 50
+ 3.2.5.1 Get-Printer-Attributes Request 51
+ 3.2.5.2 Get-Printer-Attributes Response 53
+ 3.2.6 Get-Jobs Operation 54
+ 3.2.6.1 Get-Jobs Request 54
+ 3.2.6.2 Get-Jobs Response 56
+ 3.2.7 Pause-Printer Operation 57
+ 3.2.7.1 Pause-Printer Request 59
+ 3.2.7.2 Pause-Printer Response 60
+ 3.2.8 Resume-Printer Operation 60
+ 3.2.9 Purge-Jobs Operation 61
+ 3.3 Job Operations 62
+ 3.3.1 Send-Document Operation 62
+ 3.3.1.1 Send-Document Request 64
+ 3.3.1.2 Send-Document Response 65
+
+
+
+Hastings, et al. Standards Track [Page 3]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 3.3.2 Send-URI Operation 66
+ 3.3.3 Cancel-Job Operation 66
+ 3.3.3.1 Cancel-Job Request 67
+ 3.3.3.2 Cancel-Job Response 68
+ 3.3.4 Get-Job-Attributes Operation 69
+ 3.3.4.1 Get-Job-Attributes Request 69
+ 3.3.4.2 Get-Job-Attributes Response 70
+ 3.3.5 Hold-Job Operation 71
+ 3.3.5.1 Hold-Job Request 72
+ 3.3.5.2 Hold-Job Response 73
+ 3.3.6 Release-Job Operation 74
+ 3.3.7 Restart-Job Operation 75
+ 3.3.7.1 Restart-Job Request 76
+ 3.3.7.2 Restart-Job Response 78
+ 4. Object Attributes 78
+ 4.1 Attribute Syntaxes 78
+ 4.1.1 'text' 79
+ 4.1.1.1 'textWithoutLanguage' 80
+ 4.1.1.2 'textWithLanguage' 80
+ 4.1.2 'name' 81
+ 4.1.2.1 'nameWithoutLanguage' 82
+ 4.1.2.2 'nameWithLanguage' 82
+ 4.1.2.3 Matching 'name' attribute values 83
+ 4.1.3 'keyword' 84
+ 4.1.4 'enum' 85
+ 4.1.5 'uri' 85
+ 4.1.6 'uriScheme' 86
+ 4.1.7 'charset' 86
+ 4.1.8 'naturalLanguage' 87
+ 4.1.9 'mimeMediaType' 87
+ 4.1.9.1 Application/octet-stream -- Auto-Sensing 88
+ the document format
+ 4.1.10 'octetString' 89
+ 4.1.11 'boolean' 89
+ 4.1.12 'integer' 89
+ 4.1.13 'rangeOfInteger' 90
+ 4.1.14 'dateTime' 90
+ 4.1.15 'resolution' 90
+ 4.1.16 '1setOf X' 90
+ 4.2 Job Template Attributes 91
+ 4.2.1 job-priority (integer(1:100)) 94
+ 4.2.2 job-hold-until (type3 keyword | name (MAX)) 95
+ 4.2.3 job-sheets (type3 keyword | name(MAX)) 96
+ 4.2.4 multiple-document-handling (type2 keyword) 96
+ 4.2.5 copies (integer(1:MAX)) 98
+ 4.2.6 finishings (1setOf type2 enum) 98
+ 4.2.7 page-ranges (1setOf rangeOfInteger (1:MAX)) 101
+ 4.2.8 sides (type2 keyword) 102
+
+
+
+Hastings, et al. Standards Track [Page 4]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 4.2.9 number-up (integer(1:MAX)) 102
+ 4.2.10 orientation-requested (type2 enum) 103
+ 4.2.11 media (type3 keyword | name(MAX)) 104
+ 4.2.12 printer-resolution (resolution) 105
+ 4.2.13 print-quality (type2 enum) 105
+ 4.3 Job Description Attributes 106
+ 4.3.1 job-uri (uri) 107
+ 4.3.2 job-id (integer(1:MAX)) 108
+ 4.3.3 job-printer-uri (uri) 108
+ 4.3.4 job-more-info (uri) 108
+ 4.3.5 job-name (name(MAX)) 108
+ 4.3.6 job-originating-user-name (name(MAX)) 109
+ 4.3.7 job-state (type1 enum) 109
+ 4.3.7.1 Forwarding Servers 112
+ 4.3.7.2 Partitioning of Job States 112
+ 4.3.8 job-state-reasons (1setOf type2 keyword) 113
+ 4.3.9 job-state-message (text(MAX)) 118
+ 4.3.10 job-detailed-status-messages (1setOf text(MAX)) 118
+ 4.3.11 job-document-access-errors (1setOf text(MAX)) 118
+ 4.3.12 number-of-documents (integer(0:MAX)) 119
+ 4.3.13 output-device-assigned (name(127)) 119
+ 4.3.14 Event Time Job Description Attributes 119
+ 4.3.14.1 time-at-creation (integer(MIN:MAX)) 120
+ 4.3.14.2 time-at-processing (integer(MIN:MAX)) 120
+ 4.3.14.3 time-at-completed (integer(MIN:MAX)) 120
+ 4.3.14.4 job-printer-up-time (integer(1:MAX)) 120
+ 4.3.14.5 date-time-at-creation (dateTime) 121
+ 4.3.14.6 date-time-at-processing (dateTime) 121
+ 4.3.14.7 date-time-at-completed (dateTime) 121
+ 4.3.15 number-of-intervening-jobs (integer(0:MAX)) 121
+ 4.3.16 job-message-from-operator (text(127)) 121
+ 4.3.17 Job Size Attributes 121
+ 4.3.17.1 job-k-octets (integer(0:MAX)) 122
+ 4.3.17.2 job-impressions (integer(0:MAX)) 122
+ 4.3.17.3 job-media-sheets (integer(0:MAX)) 123
+ 4.3.18 Job Progress Attributes 123
+ 4.3.18.1 job-k-octets-processed (integer(0:MAX)) 123
+ 4.3.18.2 job-impressions-completed (integer(0:MAX)) 123
+ 4.3.18.3 job-media-sheets-completed (integer(0:MAX)) 124
+ 4.3.19 attributes-charset (charset) 124
+ 4.3.20 attributes-natural-language (naturalLanguage) 124
+ 4.4 Printer Description Attributes 124
+ 4.4.1 printer-uri-supported (1setOf uri) 126
+ 4.4.2 uri-authentication-supported (1setOf type2 keyword) 127
+ 4.4.3 uri-security-supported (1setOf type2 keyword) 128
+ 4.4.4 printer-name (name(127)) 129
+ 4.4.5 printer-location (text(127)) 129
+ 4.4.6 printer-info (text(127)) 130
+
+
+
+Hastings, et al. Standards Track [Page 5]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 4.4.7 printer-more-info (uri) 130
+ 4.4.8 printer-driver-installer (uri) 130
+ 4.4.9 printer-make-and-model (text(127)) 130
+ 4.4.10 printer-more-info-manufacturer (uri) 130
+ 4.4.11 printer-state (type1 enum) 131
+ 4.4.12 printer-state-reasons (1setOf type2 keyword) 131
+ 4.4.13 printer-state-message (text(MAX)) 134
+ 4.4.14 ipp-versions-supported (1setOf type2 keyword) 134
+ 4.4.15 operations-supported (1setOf type2 enum) 135
+ 4.4.16 multiple-document-jobs-supported (boolean) 136
+ 4.4.17 charset-configured (charset) 136
+ 4.4.18 charset-supported (1setOf charset) 137
+ 4.4.19 natural-language-configured (naturalLanguage) 137
+ 4.4.20 generated-natural-language-supported
+ (1setOf naturalLanguage) 137
+ 4.4.21 document-format-default (mimeMediaType) 138
+ 4.4.22 document-format-supported (1setOf mimeMediaType) 138
+ 4.4.23 printer-is-accepting-jobs (boolean) 138
+ 4.4.24 queued-job-count (integer(0:MAX)) 138
+ 4.4.25 printer-message-from-operator (text(127)) 139
+ 4.4.26 color-supported (boolean) 139
+ 4.4.27 reference-uri-schemes-supported (1setOf uriScheme) 139
+ 4.4.28 pdl-override-supported (type2 keyword) 139
+ 4.4.29 printer-up-time (integer(1:MAX)) 140
+ 4.4.30 printer-current-time (dateTime) 140
+ 4.4.31 multiple-operation-time-out (integer(1:MAX)) 141
+ 4.4.32 compression-supported (1setOf type3 keyword) 141
+ 4.4.33 job-k-octets-supported (rangeOfInteger(0:MAX)) 142
+ 4.4.34 job-impressions-supported (rangeOfInteger(0:MAX)) 142
+ 4.4.35 job-media-sheets-supported (rangeOfInteger(0:MAX)) 142
+ 4.4.36 pages-per-minute (integer(0:MAX)) 142
+ 4.4.37 pages-per-minute-color (integer(0:MAX)) 142
+ 5. Conformance 143
+ 5.1 Client Conformance Requirements 143
+ 5.2 IPP Object Conformance Requirements 145
+ 5.2.1 Objects 145
+ 5.2.2 Operations 145
+ 5.2.3 IPP Object Attributes 146
+ 5.2.4 Versions 146
+ 5.2.5 Extensions 147
+ 5.2.6 Attribute Syntaxes 147
+ 5.2.7 Security 148
+ 5.3 Charset and Natural Language Requirements 148
+ 6. IANA Considerations 148
+ 6.1 Typed 'keyword' and 'enum' Extensions 149
+ 6.2 Attribute Extensibility 151
+ 6.3 Attribute Syntax Extensibility 152
+ 6.4 Operation Extensibility 152
+
+
+
+Hastings, et al. Standards Track [Page 6]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 6.5 Attribute Group Extensibility 153
+ 6.6 Status Code Extensibility 153
+ 6.7 Out-of-band Attribute Value Extensibility 154
+ 6.8 Registration of MIME types/sub-types for document-formats 154
+ 6.9 Registration of charsets for use in 'charset'
+ attribute values 154
+ 7. Internationalization Considerations 154
+ 8. Security Considerations 158
+ 8.1 Security Scenarios 159
+ 8.1.1 Client and Server in the Same Security Domain 159
+ 8.1.2 Client and Server in Different Security Domains 159
+ 8.1.3 Print by Reference 160
+ 8.2 URIs in Operation, Job, and Printer attributes 160
+ 8.3 URIs for each authentication mechanisms 160
+ 8.4 Restricted Queries 161
+ 8.5 Operations performed by operators and system
+ administrators 161
+ 8.6 Queries on jobs submitted using non-IPP protocols 162
+ 9. References 162
+ 10. Authors' Addresses 166
+ 11. Formats for IPP Registration Proposals 168
+ 11.1 Type2 keyword attribute values registration 169
+ 11.2 Type3 keyword attribute values registration 169
+ 11.3 Type2 enum attribute values registration 169
+ 11.4 Type3 enum attribute values registration 170
+ 11.5 Attribute registration 170
+ 11.6 Attribute Syntax registration 171
+ 11.7 Operation registration 171
+ 11.8 Attribute Group registration 171
+ 11.9 Status code registration 172
+ 11.10 Out-of-band Attribute Value registration 172
+ 12. APPENDIX A: Terminology 173
+ 12.1 Conformance Terminology 173
+ 12.1.1 NEED NOT 173
+ 12.2 Model Terminology 173
+ 12.2.1 Keyword 173
+ 12.2.2 Attributes 173
+ 12.2.2.1 Attribute Name 173
+ 12.2.2.2 Attribute Group Name 174
+ 12.2.2.3 Attribute Value 174
+ 12.2.2.4 Attribute Syntax 174
+ 12.2.3 Supports 174
+ 12.2.4 print-stream page 176
+ 12.2.5 impression 177
+ 13. APPENDIX B: Status Codes and Suggested Status Code Messages 177
+ 13.1 Status Codes 178
+ 13.1.1 Informational 178
+ 13.1.2 Successful Status Codes 178
+
+
+
+Hastings, et al. Standards Track [Page 7]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 13.1.2.1 successful-ok (0x0000) 178
+ 13.1.2.2 successful-ok-ignored-or-substituted-attributes
+ (0x0001) 179
+ 13.1.2.3 successful-ok-conflicting-attributes (0x0002) 179
+ 13.1.3 Redirection Status Codes 179
+ 13.1.4 Client Error Status Codes 179
+ 13.1.4.1 client-error-bad-request (0x0400) 180
+ 13.1.4.2 client-error-forbidden (0x0401) 180
+ 13.1.4.3 client-error-not-authenticated (0x0402) 180
+ 13.1.4.4 client-error-not-authorized (0x0403) 180
+ 13.1.4.5 client-error-not-possible (0x0404) 180
+ 13.1.4.6 client-error-timeout (0x0405) 181
+ 13.1.4.7 client-error-not-found (0x0406) 181
+ 13.1.4.8 client-error-gone (0x0407) 181
+ 13.1.4.9 client-error-request-entity-too-large (0x0408) 182
+ 13.1.4.10 client-error-request-value-too-long (0x0409) 182
+ 13.1.4.11 client-error-document-format-not-supported (0x040A) 182
+ 13.1.4.12 client-error-attributes-or-values-not-supported
+ (0x040B) 183
+ 13.1.4.13 client-error-uri-scheme-not-supported (0x040C) 183
+ 13.1.4.14 client-error-charset-not-supported (0x040D) 183
+ 13.1.4.15 client-error-conflicting-attributes (0x040E) 183
+ 13.1.4.16 client-error-compression-not-supported (0x040F) 184
+ 13.1.4.17 client-error-compression-error (0x0410) 184
+ 13.1.4.18 client-error-document-format-error (0x0411) 184
+ 13.1.4.19 client-error-document-access-error (0x0412) 184
+ 13.1.5 Server Error Status Codes 185
+ 13.1.5.1 server-error-internal-error (0x0500) 185
+ 13.1.5.2 server-error-operation-not-supported (0x0501) 185
+ 13.1.5.3 server-error-service-unavailable (0x0502) 185
+ 13.1.5.4 server-error-version-not-supported (0x0503) 185
+ 13.1.5.5 server-error-device-error (0x0504) 186
+ 13.1.5.6 server-error-temporary-error (0x0505) 186
+ 13.1.5.7 server-error-not-accepting-jobs (0x0506) 187
+ 13.1.5.8 server-error-busy (0x0507) 187
+ 13.1.5.9 server-error-job-canceled (0x0508) 187
+ 13.1.5.10 server-error-multiple-document-jobs-not-supported
+ (0x0509) 187
+ 13.2 Status Codes for IPP Operations 187
+ 14. APPENDIX C: "media" keyword values 190
+ 15. APPENDIX D: Processing IPP Attributes 208
+ 15.1 Fidelity 209
+ 15.2 Page Description Language (PDL) Override 210
+ 15.3 Using Job Template Attributes During Document Processing 212
+ 16. APPENDIX E: Generic Directory Schema 214
+ 17. APPENDIX F: Differences between the IPP/1.0 and IPP/1.1
+ "Model and Semantics" Documents 215
+ 18. Full Copyright Statement 224
+
+
+
+Hastings, et al. Standards Track [Page 8]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+1. Introduction
+
+ The Internet Printing Protocol (IPP) is an application level protocol
+ that can be used for distributed printing using Internet tools and
+ technologies. IPP version 1.1 (IPP/1.1) focuses primarily on end
+ user functionality with a few administrative operations included.
+ This document is just one of a suite of documents that fully define
+ IPP. The full set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics (this document)
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [IPP-IIG]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ Anyone reading these documents for the first time is strongly
+ encouraged to read the IPP documents in the above order.
+
+ This document is laid out as follows:
+
+ - The rest of Section 1 is an introduction to the IPP simplified
+ model for distributed printing.
+ - Section 2 introduces the object types covered in the model with
+ their basic behaviors, attributes, and interactions.
+ - Section 3 defines the operations included in IPP/1.1. IPP
+ operations are synchronous, therefore, for each operation, there is
+ a both request and a response.
+ - Section 4 defines the attributes (and their syntaxes) that are used
+ in the model.
+ - Sections 5 - 6 summarizes the implementation conformance
+ requirements for objects that support the protocol and IANA
+ considerations, respectively.
+ - Sections 7 - 11 cover the Internationalization and Security
+ considerations as well as References, Author contact information,
+ and Formats for Registration Proposals.
+ - Sections 12 - 14 are appendices that cover Terminology, Status
+ Codes and Messages, and "media" keyword values.
+
+ Note: This document uses terms such as "attributes", "keywords",
+ and "support". These terms have special meaning and are defined
+ in the model terminology section 12.2. Capitalized terms, such
+ as MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, MAY, NEED NOT,
+ and OPTIONAL, have special meaning relating to conformance.
+ These terms are defined in section 12.1 on conformance
+ terminology, most of which is taken from RFC 2119 [RFC2119].
+
+
+
+
+Hastings, et al. Standards Track [Page 9]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - Section 15 is an appendix that helps to clarify the effects of
+ interactions between related attributes and their values.
+ - Section 16 is an appendix that enumerates the subset of Printer
+ attributes that form a generic directory schema. These attributes
+ are useful when registering a Printer so that a client can find the
+ Printer not just by name, but by filtered searches as well.
+ - Section 17 is an appendix summarizing the additions and changes
+ from the IPP/1.0 "Model and Semantics" document [RFC2566] to make
+ this IPP/1.1 document.
+ - Section 18 is the full copyright notice.
+
+1.1 Simplified Printing Model
+
+ In order to achieve its goal of realizing a workable printing
+ protocol for the Internet, the Internet Printing Protocol (IPP) is
+ based on a simplified printing model that abstracts the many
+ components of real world printing solutions. The Internet is a
+ distributed computing environment where requesters of print services
+ (clients, applications, printer drivers, etc.) cooperate and interact
+ with print service providers. This model and semantics document
+ describes a simple, abstract model for IPP even though the underlying
+ configurations may be complex "n-tier" client/server systems. An
+ important simplifying step in the IPP model is to expose only the key
+ objects and interfaces required for printing. The model described in
+ this model document does not include features, interfaces, and
+ relationships that are beyond the scope of the first version of IPP
+ (IPP/1.1). IPP/1.1 incorporates many of the relevant ideas and
+ lessons learned from other specification and development efforts
+ [HTPP] [ISO10175] [LDPA] [P1387.4] [PSIS] [RFC1179] [SWP]. IPP is
+ heavily influenced by the printing model introduced in the Document
+ Printing Application (DPA) [ISO10175] standard. Although DPA
+ specifies both end user and administrative features, IPP version 1.1
+ (IPP/1.1) focuses primarily on end user functionality with a few
+ additional OPTIONAL operator operations.
+
+ The IPP/1.1 model encapsulates the important components of
+ distributed printing into two object types:
+
+ - Printer (Section 2.1)
+ - Job (Section 2.2)
+
+ Each object type has an associated set of operations (see section 3)
+ and attributes (see section 4).
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 10]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ It is important, however, to understand that in real system
+ implementations (which lie underneath the abstracted IPP/1.1 model),
+ there are other components of a print service which are not
+ explicitly defined in the IPP/1.1 model. The following figure
+ illustrates where IPP/1.1 fits with respect to these other
+ components.
+
+ +--------------+
+ | Application |
+ o +. . . . . . . |
+ \|/ | Spooler |
+ / \ +. . . . . . . | +---------+
+ End-User | Print Driver |---| File |
+ +-----------+ +-----+ +------+-------+ +----+----+
+ | Browser | | GUI | | |
+ +-----+-----+ +--+--+ | |
+ | | | |
+ | +---+------------+---+ |
+ N D S | | IPP Client |------------+
+ O I E | +---------+----------+
+ T R C | |
+ I E U |
+ F C R -------------- Transport ------------------
+ I T I
+ C O T | --+
+ A R Y +--------+--------+ |
+ T Y | IPP Server | |
+ I +--------+--------+ |
+ O | |
+ N +-----------------+ | IPP Printer
+ | Print Service | |
+ +-----------------+ |
+ | --+
+ +-----------------+
+ | Output Device(s)|
+ +-----------------+
+
+ An IPP Printer object encapsulates the functions normally associated
+ with physical output devices along with the spooling, scheduling and
+ multiple device management functions often associated with a print
+ server. Printer objects are optionally registered as entries in a
+ directory where end users find and select them based on some sort of
+ filtered and context based searching mechanism (see section 16). The
+ directory is used to store relatively static information about the
+ Printer, allowing end users to search for and find Printers that
+ match their search criteria, for example: name, context, printer
+ capabilities, etc. The more dynamic information, such as state,
+ currently loaded and ready media, number of jobs at the Printer,
+
+
+
+Hastings, et al. Standards Track [Page 11]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ errors, warnings, and so forth, is directly associated with the
+ Printer object itself rather than with the entry in the directory
+ which only represents the Printer object.
+
+ IPP clients implement the IPP protocol on the client side and give
+ end users (or programs running on behalf of end users) the ability to
+ query Printer objects and submit and manage print jobs. An IPP
+ server is just that part of the Printer object that implements the
+ server-side protocol. The rest of the Printer object implements (or
+ gateways into) the application semantics of the print service itself.
+ The Printer objects may be embedded in an output device or may be
+ implemented on a host on the network that communicates with an output
+ device.
+
+ When a job is submitted to the Printer object and the Printer object
+ validates the attributes in the submission request, the Printer
+ object creates a new Job object. The end user then interacts with
+ this new Job object to query its status and monitor the progress of
+ the job. An end user can also cancel their print jobs by using the
+ Job object's Cancel-Job operation. An end-user can also hold,
+ release, and restart their print jobs using the Job object's OPTIONAL
+ Hold-Job, Release-Job, and Restart-Job operations, if implemented.
+
+ A privileged operator or administrator of a Printer object can
+ cancel, hold, release, and restart any user's job using the REQUIRED
+ Cancel-Job and the OPTIONAL Hold-Job, Release-Job, and Restart-Job
+ operations. In additional privileged operator or administrator of a
+ Printer object can pause, resume, or purge (jobs from) a Printer
+ object using the OPTIONAL Pause-Printer, Resume-Printer, and Purge-
+ Jobs operations, if implemented.
+
+ The notification service is out of scope for this IPP/1.1 document,
+ but using such a notification service, the end user is able to
+ register for and receive Printer specific and Job specific events.
+ An end user can query the status of Printer objects and can follow
+ the progress of Job objects by polling using the Get-Printer-
+ Attributes, Get-Jobs, and Get-Job-Attributes operations.
+
+2. IPP Objects
+
+ The IPP/1.1 model introduces objects of type Printer and Job. Each
+ type of object models relevant aspects of a real-world entity such as
+ a real printer or real print job. Each object type is defined as a
+ set of possible attributes that may be supported by instances of that
+ object type. For each object (instance), the actual set of supported
+ attributes and values describe a specific implementation. The
+ object's attributes and values describe its state, capabilities,
+ realizable features, job processing functions, and default behaviors
+
+
+
+Hastings, et al. Standards Track [Page 12]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ and characteristics. For example, the Printer object type is defined
+ as a set of attributes that each Printer object potentially supports.
+ In the same manner, the Job object type is defined as a set of
+ attributes that are potentially supported by each Job object.
+
+ Each attribute included in the set of attributes defining an object
+ type is labeled as:
+
+ - "REQUIRED": each object MUST support the attribute.
+ - "RECOMMENDED": each object SHOULD support the attribute.
+ - "OPTIONAL": each object MAY support the attribute.
+
+ Some definitions of attribute values indicate that an object MUST or
+ SHOULD support the value; otherwise, support of the value is
+ OPTIONAL.
+
+ However, if an implementation supports an attribute, it MUST support
+ at least one of the possible values for that attribute.
+
+2.1 Printer Object
+
+ The major component of the IPP/1.1 model is the Printer object. A
+ Printer object implements the server-side of the IPP/1.1 protocol.
+ Using the protocol, end users may query the attributes of the Printer
+ object and submit print jobs to the Printer object. The actual
+ implementation components behind the Printer abstraction may take on
+ different forms and different configurations. However, the model
+ abstraction allows the details of the configuration of real
+ components to remain opaque to the end user. Section 3 describes
+ each of the Printer operations in detail.
+
+ The capabilities and state of a Printer object are described by its
+ attributes. Printer attributes are divided into two groups:
+
+ - "job-template" attributes: These attributes describe supported job
+ processing capabilities and defaults for the Printer object. (See
+ section 4.2)
+ - "printer-description" attributes: These attributes describe the
+ Printer object's identification, state, location, references to
+ other sources of information about the Printer object, etc. (see
+ section 4.4)
+
+ Since a Printer object is an abstraction of a generic document output
+ device and print service provider, a Printer object could be used to
+ represent any real or virtual device with semantics consistent with
+ the Printer object, such as a fax device, an imager, or even a CD
+ writer.
+
+
+
+
+Hastings, et al. Standards Track [Page 13]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Some examples of configurations supporting a Printer object include:
+
+ 1) An output device with no spooling capabilities
+ 2) An output device with a built-in spooler
+ 3) A print server supporting IPP with one or more associated
+ output devices
+ 3a) The associated output devices may or may not be capable of
+ spooling jobs
+ 3b) The associated output devices may or may not support IPP
+
+ The following figures show some examples of how Printer objects can
+ be realized on top of various distributed printing configurations.
+ The embedded case below represents configurations 1 and 2. The hosted
+ and fan-out figures below represent configurations 3a and 3b.
+
+ In this document the term "client" refers to a software entity that
+ sends IPP operation requests to an IPP Printer object and accepts IPP
+ operation responses. A client MAY be:
+
+ 1. contained within software controlled by an end user, e.g.
+ activated by the "Print" menu item in an application or
+
+ 2. the print server component that sends IPP requests to either an
+ output device or another "downstream" print server.
+
+ The term "IPP Printer" is a network entity that accepts IPP operation
+ requests and returns IPP operation responses. As such, an IPP object
+ MAY be:
+
+ 1. an (embedded) device component that accepts IPP requests and
+ controls the device or
+
+ 2. a component of a print server that accepts IPP requests (where
+ the print server controls one or more networked devices using
+ IPP or other protocols).
+
+ Legend:
+
+ ##### indicates a Printer object which is
+ either embedded in an output device or is
+ hosted in a server. The Printer object
+ might or might not be capable of queuing/spooling.
+
+ any indicates any network protocol or direct
+ connect, including IPP
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 14]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ embedded printer:
+ output device
+ +---------------+
+ O +--------+ | ########### |
+ /|\ | client |------------IPP------------># Printer # |
+ / \ +--------+ | # Object # |
+ | ########### |
+ +---------------+
+
+ hosted printer:
+ +---------------+
+ O +--------+ ########### | |
+ /|\ | client |--IPP--># Printer #-any->| output device |
+ / \ +--------+ # Object # | |
+ ########### +---------------+
+
+
+ +---------------+
+ fan out: | |
+ +-->| output device |
+ any/ | |
+ O +--------+ ########### / +---------------+
+ /|\ | client |-IPP-># Printer #--*
+ / \ +--------+ # Object # \ +---------------+
+ ########### any\ | |
+ +-->| output device |
+ | |
+ +---------------+
+
+2.2 Job Object
+
+ A Job object is used to model a print job. A Job object contains
+ documents. The information required to create a Job object is sent
+ in a create request from the end user via an IPP Client to the
+ Printer object. The Printer object validates the create request, and
+ if the Printer object accepts the request, the Printer object creates
+ the new Job object. Section 3 describes each of the Job operations
+ in detail.
+
+ The characteristics and state of a Job object are described by its
+ attributes. Job attributes are grouped into two groups as follows:
+
+ - "job-template" attributes: These attributes can be supplied by
+ the client or end user and include job processing instructions
+ which are intended to override any Printer object defaults
+ and/or instructions embedded within the document data. (See
+ section 4.2)
+
+
+
+
+Hastings, et al. Standards Track [Page 15]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - "job-description" attributes: These attributes describe the Job
+ object's identification, state, size, etc. The client supplies
+ some of these attributes, and the Printer object generates
+ others. (See section 4.3)
+
+ An implementation MUST support at least one document per Job object.
+ An implementation MAY support multiple documents per Job object. A
+ document is either:
+
+ - a stream of document data in a format supported by the Printer
+ object (typically a Page Description Language - PDL), or
+ - a reference to such a stream of document data
+
+ In IPP/1.1, a document is not modeled as an IPP object, therefore it
+ has no object identifier or associated attributes. All job
+ processing instructions are modeled as Job object attributes. These
+ attributes are called Job Template attributes and they apply equally
+ to all documents within a Job object.
+
+2.3 Object Relationships
+
+ IPP objects have relationships that are maintained persistently along
+ with the persistent storage of the object attributes.
+
+ A Printer object can represent either one or more physical output
+ devices or a logical device which "processes" jobs but never actually
+ uses a physical output device to put marks on paper. Examples of
+ logical devices include a Web page publisher or a gateway into an
+ online document archive or repository. A Printer object contains
+ zero or more Job objects.
+
+ A Job object is contained by exactly one Printer object, however the
+ identical document data associated with a Job object could be sent to
+ either the same or a different Printer object. In this case, a
+ second Job object would be created which would be almost identical to
+ the first Job object, however it would have new (different) Job
+ object identifiers (see section 2.4).
+
+ A Job object is either empty (before any documents have been added)
+ or contains one or more documents. If the contained document is a
+ stream of document data, that stream can be contained in only one
+ document. However, there can be identical copies of the stream in
+ other documents in the same or different Job objects. If the
+ contained document is just a reference to a stream of document data,
+ other documents (in the same or different Job object(s)) may contain
+ the same reference.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 16]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+2.4 Object Identity
+
+ All Printer and Job objects are identified by a Uniform Resource
+ Identifier (URI) [RFC2396] so that they can be persistently and
+ unambiguously referenced. Since every URL is a specialized form of a
+ URI, even though the more generic term URI is used throughout the
+ rest of this document, its usage is intended to cover the more
+ specific notion of URL as well.
+
+ An administrator configures Printer objects to either support or not
+ support authentication and/or message privacy using Transport Layer
+ Security (TLS) [RFC2246] (the mechanism for security configuration is
+ outside the scope of this IPP/1.1 document). In some situations,
+ both types of connections (both authenticated and unauthenticated)
+ can be established using a single communication channel that has some
+ sort of negotiation mechanism. In other situations, multiple
+ communication channels are used, one for each type of security
+ configuration. Section 8 provides a full description of all security
+ considerations and configurations.
+
+ If a Printer object supports more than one communication channel,
+ some or all of those channels might support and/or require different
+ security mechanisms. In such cases, an administrator could expose
+ the simultaneous support for these multiple communication channels as
+ multiple URIs for a single Printer object where each URI represents
+ one of the communication channels to the Printer object. To support
+ this flexibility, the IPP Printer object type defines a multi-valued
+ identification attribute called the "printer-uri-supported"
+ attribute. It MUST contain at least one URI. It MAY contain more
+ than one URI. That is, every Printer object will have at least one
+ URI that identifies at least one communication channel to the Printer
+ object, but it may have more than one URI where each URI identifies a
+ different communication channel to the Printer object. The
+ "printer-uri-supported" attribute has two companion attributes, the
+ "uri-security-supported" attribute and the "uri-authentication-
+ supported". Both have the same cardinality as "printer-uri-
+ supported". The purpose of the "uri-security-supported" attribute is
+ to indicate the security mechanisms (if any) used for each URI listed
+ in "printer-uri-supported". The purpose of the "uri-authentication-
+ supported" attribute is to indicate the authentication mechanisms (if
+ any) used for each URI listed in "printer-uri-supported". These
+ three attributes are fully described in sections 4.4.1, 4.4.2, and
+ 4.4.3.
+
+ When a job is submitted to the Printer object via a create request,
+ the client supplies only a single Printer object URI. The client
+ supplied Printer object URI MUST be one of the values in the
+ "printer-uri-supported" Printer attribute.
+
+
+
+Hastings, et al. Standards Track [Page 17]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ IPP/1.1 does not specify how the client obtains the client supplied
+ URI, but it is RECOMMENDED that a Printer object be registered as an
+ entry in a directory service. End-users and programs can then
+ interrogate the directory searching for Printers. Section 16 defines
+ a generic schema for Printer object entries in the directory service
+ and describes how the entry acts as a bridge to the actual IPP
+ Printer object. The entry in the directory that represents the IPP
+ Printer object includes the possibly many URIs for that Printer
+ object as values in one its attributes.
+
+ When a client submits a create request to the Printer object, the
+ Printer object validates the request and creates a new Job object.
+ The Printer object assigns the new Job object a URI which is stored
+ in the "job-uri" Job attribute. This URI is then used by clients as
+ the target for subsequent Job operations. The Printer object
+ generates a Job URI based on its configured security policy and the
+ URI used by the client in the create request.
+
+ For example, consider a Printer object that supports both a
+ communication channel secured by the use of SSL3 (using HTTP over
+ SSL3 with an "https" schemed URI) and another open communication
+ channel that is not secured with SSL3 (using a simple "http" schemed
+ URI). If a client were to submit a job using the secure URI, the
+ Printer object would assign the new Job object a secure URI as well.
+ If a client were to submit a job using the open-channel URI, the
+ Printer would assign the new Job object an open-channel URI.
+
+ In addition, the Printer object also populates the Job object's
+ "job-printer-uri" attribute. This is a reference back to the Printer
+ object that created the Job object. If a client only has access to a
+ Job object's "job-uri" identifier, the client can query the Job's
+ "job-printer-uri" attribute in order to determine which Printer
+ object created the Job object. If the Printer object supports more
+ than one URI, the Printer object picks the one URI supplied by the
+ client when creating the job to build the value for and to populate
+ the Job's "job-printer-uri" attribute.
+
+ Allowing Job objects to have URIs allows for flexibility and
+ scalability. For example, in some implementations, the Printer
+ object might create Jobs that are processed in the same local
+ environment as the Printer object itself. In this case, the Job URI
+ might just be a composition of the Printer's URI and some unique
+ component for the Job object, such as the unique 32-bit positive
+ integer mentioned later in this paragraph. In other implementations,
+ the Printer object might be a central clearing-house for validating
+ all Job object creation requests, but the Job object itself might be
+ created in some environment that is remote from the Printer object.
+ In this case, the Job object's URI may have no physical-location
+
+
+
+Hastings, et al. Standards Track [Page 18]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ relationship at all to the Printer object's URI. Again, the fact
+ that Job objects have URIs allows for flexibility and scalability,
+ however, many existing printing systems have local models or
+ interface constraints that force print jobs to be identified using
+ only a 32-bit positive integer rather than an independent URI. This
+ numeric Job ID is only unique within the context of the Printer
+ object to which the create request was originally submitted.
+ Therefore, in order to allow both types of client access to IPP Job
+ objects (either by Job URI or by numeric Job ID), when the Printer
+ object successfully processes a create request and creates a new Job
+ object, the Printer object MUST generate both a Job URI and a Job ID.
+ The Job ID (stored in the "job-id" attribute) only has meaning in the
+ context of the Printer object to which the create request was
+ originally submitted. This requirement to support both Job URIs and
+ Job IDs allows all types of clients to access Printer objects and Job
+ objects no matter the local constraints imposed on the client
+ implementation.
+
+ In addition to identifiers, Printer objects and Job objects have
+ names ("printer-name" and "job-name"). An object name NEED NOT be
+ unique across all instances of all objects. A Printer object's name
+ is chosen and set by an administrator through some mechanism outside
+ the scope of this IPP/1.1 document. A Job object's name is
+ optionally chosen and supplied by the IPP client submitting the job.
+ If the client does not supply a Job object name, the Printer object
+ generates a name for the new Job object. In all cases, the name only
+ has local meaning.
+
+ To summarize:
+
+ - Each Printer object is identified with one or more URIs. The
+ Printer's "printer-uri-supported" attribute contains the URI(s).
+ - The Printer object's "uri-security-supported" attribute
+ identifies the communication channel security protocols that may
+ or may not have been configured for the various Printer object
+ URIs (e.g., 'tls' or 'none').
+ - The Printer object's "uri-authentication-supported" attribute
+ identifies the authentication mechanisms that may or may not
+ have been configured for the various Printer object URIs (e.g.,
+ 'digest' or 'none').
+ - Each Job object is identified with a Job URI. The Job's "job-
+ uri" attribute contains the URI.
+ - Each Job object is also identified with Job ID which is a 32-
+ bit, positive integer. The Job's "job-id" attribute contains
+ the Job ID. The Job ID is only unique within the context of the
+ Printer object which created the Job object.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 19]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - Each Job object has a "job-printer-uri" attribute which contains
+ the URI of the Printer object that was used to create the Job
+ object. This attribute is used to determine the Printer object
+ that created a Job object when given only the URI for the Job
+ object. This linkage is necessary to determine the languages,
+ charsets, and operations which are supported on that Job (the
+ basis for such support comes from the creating Printer object).
+ - Each Printer object has a name (which is not necessarily
+ unique). The administrator chooses and sets this name through
+ some mechanism outside the scope of this IPP/1.1 document. The
+ Printer object's "printer-name" attribute contains the name.
+ - Each Job object has a name (which is not necessarily unique).
+ The client optionally supplies this name in the create request.
+ If the client does not supply this name, the Printer object
+ generates a name for the Job object. The Job object's "job-name"
+ attribute contains the name.
+
+3. IPP Operations
+
+ IPP objects support operations. An operation consists of a request
+ and a response. When a client communicates with an IPP object, the
+ client issues an operation request to the URI for that object.
+ Operation requests and responses have parameters that identify the
+ operation. Operations also have attributes that affect the run-time
+ characteristics of the operation (the intended target, localization
+ information, etc.). These operation-specific attributes are called
+ operation attributes (as compared to object attributes such as
+ Printer object attributes or Job object attributes). Each request
+ carries along with it any operation attributes, object attributes,
+ and/or document data required to perform the operation. Each request
+ requires a response from the object. Each response indicates success
+ or failure of the operation with a status code as a response
+ parameter. The response contains any operation attributes, object
+ attributes, and/or status messages generated during the execution of
+ the operation request.
+
+ This section describes the semantics of the IPP operations, both
+ requests and responses, in terms of the parameters, attributes, and
+ other data associated with each operation.
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 20]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The IPP/1.1 Printer operations are:
+
+ Print-Job (section 3.2.1)
+ Print-URI (section 3.2.2)
+ Validate-Job (section 3.2.3)
+ Create-Job (section 3.2.4)
+ Get-Printer-Attributes (section 3.2.5)
+ Get-Jobs (section 3.2.6)
+ Pause-Printer (section 3.3.5)
+ Resume-Printer (section 3.3.6)
+ Purge-Jobs (section 3.3.7)
+
+ The Job operations are:
+
+ Send-Document (section 3.3.1)
+ Send-URI (section 3.3.2)
+ Cancel-Job (section 3.3.3)
+ Get-Job-Attributes (section 3.3.4)
+ Hold-Job (section 3.3.5)
+ Release-Job (section 3.3.6)
+ Restart-Job (section 3.3.7)
+
+ The Send-Document and Send-URI Job operations are used to add a new
+ document to an existing multi-document Job object created using the
+ Create-Job operation.
+
+3.1 Common Semantics
+
+ All IPP operations require some common parameters and operation
+ attributes. These common elements and their semantic characteristics
+ are defined and described in more detail in the following sections.
+
+3.1.1 Required Parameters
+
+ Every operation request contains the following REQUIRED parameters:
+
+ - a "version-number",
+ - an "operation-id",
+ - a "request-id", and
+ - the attributes that are REQUIRED for that type of request.
+
+ Every operation response contains the following REQUIRED parameters:
+
+ - a "version-number",
+ - a "status-code",
+ - the "request-id" that was supplied in the corresponding request,
+ and
+ - the attributes that are REQUIRED for that type of response.
+
+
+
+Hastings, et al. Standards Track [Page 21]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The "Encoding and Transport" document [RFC2910] defines special rules
+ for the encoding of these parameters. All other operation elements
+ are represented using the more generic encoding rules for attributes
+ and groups of attributes.
+
+3.1.2 Operation IDs and Request IDs
+
+ Each IPP operation request includes an identifying "operation-id"
+ value. Valid values are defined in the "operations-supported"
+ Printer attribute section (see section 4.4.15). The client specifies
+ which operation is being requested by supplying the correct
+ "operation-id" value.
+
+ In addition, every invocation of an operation is identified by a
+ "request-id" value. For each request, the client chooses the
+ "request-id" which MUST be an integer (possibly unique depending on
+ client requirements) in the range from 1 to 2**31 - 1 (inclusive).
+ This "request-id" allows clients to manage multiple outstanding
+ requests. The receiving IPP object copies all 32-bits of the client-
+ supplied "request-id" attribute into the response so that the client
+ can match the response with the correct outstanding request, even if
+ the "request-id" is out of range. If the request is terminated
+ before the complete "request-id" is received, the IPP object rejects
+ the request and returns a response with a "request-id" of 0.
+
+ Note: In some cases, the transport protocol underneath IPP might be a
+ connection oriented protocol that would make it impossible for a
+ client to receive responses in any order other than the order in
+ which the corresponding requests were sent. In such cases, the
+ "request-id" attribute would not be essential for correct protocol
+ operation. However, in other mappings, the operation responses can
+ come back in any order. In these cases, the "request-id" would be
+ essential.
+
+3.1.3 Attributes
+
+ Operation requests and responses are both composed of groups of
+ attributes and/or document data. The attributes groups are:
+
+ - Operation Attributes: These attributes are passed in the
+ operation and affect the IPP object's behavior while processing
+ the operation request and may affect other attributes or groups
+ of attributes. Some operation attributes describe the document
+ data associated with the print job and are associated with new
+ Job objects, however most operation attributes do not persist
+ beyond the life of the operation. The description of each
+ operation attribute includes conformance statements indicating
+ which operation attributes are REQUIRED and which are OPTIONAL
+
+
+
+Hastings, et al. Standards Track [Page 22]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ for an IPP object to support and which attributes a client MUST
+ supply in a request and an IPP object MUST supply in a response.
+ - Job Template Attributes: These attributes affect the processing
+ of a job. A client OPTIONALLY supplies Job Template Attributes
+ in a create request, and the receiving object MUST be prepared
+ to receive all supported attributes. The Job object can later
+ be queried to find out what Job Template attributes were
+ originally requested in the create request, and such attributes
+ are returned in the response as Job Object Attributes. The
+ Printer object can be queried about its Job Template attributes
+ to find out what type of job processing capabilities are
+ supported and/or what the default job processing behaviors are,
+ though such attributes are returned in the response as Printer
+ Object Attributes. The "ipp-attribute-fidelity" operation
+ attribute affects processing of all client-supplied Job Template
+ attributes (see sections 3.2.1.2 and 15 for a full description
+ of "ipp-attribute-fidelity" and its relationship to other
+ attributes).
+ - Job Object Attributes: These attributes are returned in response
+ to a query operation directed at a Job object.
+ - Printer Object Attributes: These attributes are returned in
+ response to a query operation directed at a Printer object.
+ - Unsupported Attributes: In a create request, the client supplies
+ a set of Operation and Job Template attributes. If any of these
+ attributes or their values is unsupported by the Printer object,
+ the Printer object returns the set of unsupported attributes in
+ the response. Sections 3.1.7, 3.2.1.2, and 15 give a full
+ description of how Job Template attributes supplied by the
+ client in a create request are processed by the Printer object
+ and how unsupported attributes are returned to the client.
+ Because of extensibility, any IPP object might receive a request
+ that contains new or unknown attributes or values for which it
+ has no support. In such cases, the IPP object processes what it
+ can and returns the unsupported attributes in the response. The
+ Unsupported Attribute group is defined for all operation
+ responses for returning unsupported attributes that the client
+ supplied in the request.
+
+ Later in this section, each operation is formally defined by
+ identifying the allowed and expected groups of attributes for each
+ request and response. The model identifies a specific order for each
+ group in each request or response, but the attributes within each
+ group may be in any order, unless specified otherwise.
+
+ The attributes within a group MUST be unique; if an attribute with
+ the same name occurs more than once, the group is mal-formed.
+ Clients MUST NOT submit such malformed requests and Printers MUST NOT
+ return such malformed responses. If such a malformed request is
+
+
+
+Hastings, et al. Standards Track [Page 23]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ submitted to a Printer, the Printer MUST either (1) reject the
+ request with the 'client-error-bad-request' status code (see section
+ 13.1.4.1) or (2) process the request normally after selecting only
+ one of the attribute instances, depending on implementation. Which
+ attribute is selected when there are duplicate attributes depends on
+ implementation. The IPP Printer MUST NOT use the values from more
+ than one such duplicate attribute instance.
+
+ Each attribute definition includes the attribute's name followed by
+ the name of its attribute syntax(es) in parenthesizes. In addition,
+ each 'integer' attribute is followed by the allowed range in
+ parentheses, (m:n), for values of that attribute. Each 'text' or
+ 'name' attribute is followed by the maximum size in octets in
+ parentheses, (size), for values of that attribute. For more details
+ on attribute syntax notation, see the descriptions of these
+ attributes syntaxes in section 4.1.
+
+ Note: Document data included in the operation is not strictly an
+ attribute, but it is treated as a special attribute group for
+ ordering purposes. The only operations that support supplying the
+ document data within an operation request are Print-Job and Send-
+ Document. There are no operation responses that include document
+ data.
+
+ Some operations are REQUIRED for IPP objects to support; the others
+ are OPTIONAL (see section 5.2.2). Therefore, before using an
+ OPTIONAL operation, a client SHOULD first use the REQUIRED Get-
+ Printer-Attributes operation to query the Printer's "operations-
+ supported" attribute in order to determine which OPTIONAL Printer and
+ Job operations are actually supported. The client SHOULD NOT use an
+ OPTIONAL operation that is not supported. When an IPP object
+ receives a request to perform an operation it does not support, it
+ returns the 'server-error-operation-not-supported' status code (see
+ section 13.1.5.2). An IPP object is non-conformant if it does not
+ support a REQUIRED operation.
+
+3.1.4 Character Set and Natural Language Operation Attributes
+
+ Some Job and Printer attributes have values that are text strings and
+ names intended for human understanding rather than machine
+ understanding (see the 'text' and 'name' attribute syntax
+ descriptions in section 4.1). The following sections describe two
+ special Operation Attributes called "attributes-charset" and
+ "attributes-natural-language". These attributes are always part of
+ the Operation Attributes group. For most attribute groups, the order
+ of the attributes within the group is not important. However, for
+ these two attributes within the Operation Attributes group, the order
+ is critical. The "attributes-charset" attribute MUST be the first
+
+
+
+Hastings, et al. Standards Track [Page 24]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ attribute in the group and the "attributes-natural-language"
+ attribute MUST be the second attribute in the group. In other words,
+ these attributes MUST be supplied in every IPP request and response,
+ they MUST come first in the group, and MUST come in the specified
+ order. For job creation operations, the IPP Printer implementation
+ saves these two attributes with the new Job object as Job Description
+ attributes. For the sake of brevity in this document, these
+ operation attribute descriptions are not repeated with every
+ operation request and response, but have a reference back to this
+ section instead.
+
+3.1.4.1 Request Operation Attributes
+
+ The client MUST supply and the Printer object MUST support the
+ following REQUIRED operation attributes in every IPP/1.1 operation
+ request:
+
+ "attributes-charset" (charset):
+ This operation attribute identifies the charset (coded
+ character set and encoding method) used by any 'text' and
+ 'name' attributes that the client is supplying in this request.
+ It also identifies the charset that the Printer object MUST use
+ (if supported) for all 'text' and 'name' attributes and status
+ messages that the Printer object returns in the response to
+ this request. See Sections 4.1.1 and 4.1.2 for the definition
+ of the 'text' and 'name' attribute syntaxes.
+
+ All clients and IPP objects MUST support the 'utf-8' charset
+ [RFC2279] and MAY support additional charsets provided that
+ they are registered with IANA [IANA-CS]. If the Printer object
+ does not support the client supplied charset value, the Printer
+ object MUST reject the request, set the "attributes-charset" to
+ 'utf-8' in the response, and return the 'client-error-charset-
+ not-supported' status code and any 'text' or 'name' attributes
+ using the 'utf-8' charset. The Printer NEED NOT return any
+ attributes in the Unsupported Attributes Group (See sections
+ 3.1.7 and 3.2.1.2). The Printer object MUST indicate the
+ charset(s) supported as the values of the "charset-supported"
+ Printer attribute (see Section 4.4.18), so that the client can
+ query to determine which charset(s) are supported.
+
+ Note to client implementers: Since IPP objects are only
+ required to support the 'utf-8' charset, in order to maximize
+ interoperability with multiple IPP object implementations, a
+ client may want to supply 'utf-8' in the "attributes-charset"
+ operation attribute, even though the client is only passing and
+ able to present a simpler charset, such as US-ASCII [ASCII] or
+ ISO-8859-1 [ISO8859-1]. Then the client will have to filter
+
+
+
+Hastings, et al. Standards Track [Page 25]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ out (or charset convert) those characters that are returned in
+ the response that it cannot present to its user. On the other
+ hand, if both the client and the IPP objects also support a
+ charset in common besides utf-8, the client may want to use
+ that charset in order to avoid charset conversion or data loss.
+
+ See the 'charset' attribute syntax description in Section 4.1.7
+ for the syntax and semantic interpretation of the values of
+ this attribute and for example values.
+
+ "attributes-natural-language" (naturalLanguage):
+ This operation attribute identifies the natural language used
+ by any 'text' and 'name' attributes that the client is
+ supplying in this request. This attribute also identifies the
+ natural language that the Printer object SHOULD use for all
+ 'text' and 'name' attributes and status messages that the
+ Printer object returns in the response to this request. See
+ the 'naturalLanguage' attribute syntax description in section
+ 4.1.8 for the syntax and semantic interpretation of the values
+ of this attribute and for example values.
+
+ There are no REQUIRED natural languages required for the
+ Printer object to support. However, the Printer object's
+ "generated-natural-language-supported" attribute identifies the
+ natural languages supported by the Printer object and any
+ contained Job objects for all text strings generated by the IPP
+ object. A client MAY query this attribute to determine which
+ natural language(s) are supported for generated messages.
+
+ For any of the attributes for which the Printer object
+ generates text, i.e., for the "job-state-message", "printer-
+ state-message", and status messages (see Section 3.1.6), the
+ Printer object MUST be able to generate these text strings in
+ any of its supported natural languages. If the client requests
+ a natural language that is not supported, the Printer object
+ MUST return these generated messages in the Printer's
+ configured natural language as specified by the Printer's
+ "natural-language-configured" attribute" (see Section 4.4.19).
+
+ For other 'text' and 'name' attributes supplied by the client,
+ authentication system, operator, system administrator, or
+ manufacturer (i.e., for "job-originating-user-name", "printer-
+ name" (name), "printer-location" (text), "printer-info" (text),
+ and "printer-make-and-model" (text)), the Printer object is
+ only required to support the configured natural language of the
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 26]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Printer identified by the Printer object's "natural-language-
+ configured" attribute, though support of additional natural
+ languages for these attributes is permitted.
+
+ For any 'text' or 'name' attribute in the request that is in a
+ different natural language than the value supplied in the
+ "attributes-natural-language" operation attribute, the client
+ MUST use the Natural Language Override mechanism (see sections
+ 4.1.1.2 and 4.1.2.2) for each such attribute value supplied.
+ The client MAY use the Natural Language Override mechanism
+ redundantly, i.e., use it even when the value is in the same
+ natural language as the value supplied in the "attributes-
+ natural-language" operation attribute of the request.
+
+ The IPP object MUST accept any natural language and any Natural
+ Language Override, whether the IPP object supports that natural
+ language or not (and independent of the value of the "ipp-
+ attribute-fidelity" Operation attribute). That is the IPP
+ object accepts all client supplied values no matter what the
+ values are in the Printer object's "generated-natural-
+ language-supported" attribute. That attribute, "generated-
+ natural-language-supported", only applies to generated
+ messages, not client supplied messages. The IPP object MUST
+ remember that natural language for all client-supplied
+ attributes, and when returning those attributes in response to
+ a query, the IPP object MUST indicate that natural language.
+
+ Each value whose attribute syntax type is 'text' or 'name' (see
+ sections 4.1.1 and 4.1.2) has an Associated Natural-Language.
+ This document does not specify how this association is stored
+ in a Printer or Job object. When such a value is encoded in a
+ request or response, the natural language is either implicit or
+ explicit:
+
+ - In the implicit case, the value contains only the text/name
+ value, and the language is specified by the "attributes-
+ natural-language" operation attribute in the request or
+ response (see sections 4.1.1.1 textWithoutLanguage and
+ 4.1.2.1 nameWithoutLanguage).
+
+ - In the explicit case (also known as the Natural-Language
+ Override case), the value contains both the language and the
+ text/name value (see sections 4.1.1.2 textWithLanguage and
+ 4.1.2.2 nameWithLanguage).
+
+ For example, the "job-name" attribute MAY be supplied by the
+ client in a create request. The text value for this attribute
+ will be in the natural language identified by the "attribute-
+
+
+
+Hastings, et al. Standards Track [Page 27]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ natural-language" attribute, or if different, as identified by
+ the Natural Language Override mechanism. If supplied, the IPP
+ object will use the value of the "job-name" attribute to
+ populate the Job object's "job-name" attribute. Whenever any
+ client queries the Job object's "job-name" attribute, the IPP
+ object returns the attribute as stored and uses the Natural
+ Language Override mechanism to specify the natural language, if
+ it is different from that reported in the "attributes-natural-
+ language" operation attribute of the response. The IPP object
+ MAY use the Natural Language Override mechanism redundantly,
+ i.e., use it even when the value is in the same natural
+ language as the value supplied in the "attributes-natural-
+ language" operation attribute of the response.
+
+ An IPP object MUST NOT reject a request based on a supplied
+ natural language in an "attributes-natural-language" Operation
+ attribute or in any attribute that uses the Natural Language
+ Override.
+
+ Clients SHOULD NOT supply 'text' or 'name' attributes that use an
+ illegal combination of natural language and charset. For example,
+ suppose a Printer object supports charsets 'utf-8', 'iso-8859-1', and
+ 'iso-8859-7'. Suppose also, that it supports natural languages 'en'
+ (English), 'fr' (French), and 'el' (Greek). Although the Printer
+ object supports the charset 'iso-8859-1' and natural language 'el',
+ it probably does not support the combination of Greek text strings
+ using the 'iso-8859-1' charset. The Printer object handles this
+ apparent incompatibility differently depending on the context in
+ which it occurs:
+
+ - In a create request: If the client supplies a text or name
+ attribute (for example, the "job-name" operation attribute) that
+ uses an apparently incompatible combination, it is a client
+ choice that does not affect the Printer object or its correct
+ operation. Therefore, the Printer object simply accepts the
+ client supplied value, stores it with the Job object, and
+ responds back with the same combination whenever the client (or
+ any client) queries for that attribute.
+ - In a query-type operation, like Get-Printer-Attributes: If the
+ client requests an apparently incompatible combination, the
+ Printer object responds (as described in section 3.1.4.2) using
+ the Printer's configured natural language rather than the
+ natural language requested by the client.
+
+ In either case, the Printer object does not reject the request
+ because of the apparent incompatibility. The potential incompatible
+ combination of charset and natural language can occur either at the
+ global operation level or at the Natural Language Override
+
+
+
+Hastings, et al. Standards Track [Page 28]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ attribute-by-attribute level. In addition, since the response always
+ includes explicit charset and natural language information, there is
+ never any question or ambiguity in how the client interprets the
+ response.
+
+3.1.4.2 Response Operation Attributes
+
+ The Printer object MUST supply and the client MUST support the
+ following REQUIRED operation attributes in every IPP/1.1 operation
+ response:
+
+ "attributes-charset" (charset):
+ This operation attribute identifies the charset used by any
+ 'text' and 'name' attributes that the Printer object is
+ returning in this response. The value in this response MUST be
+ the same value as the "attributes-charset" operation attribute
+ supplied by the client in the request. If this is not possible
+ (i.e., the charset requested is not supported), the request
+ would have been rejected. See "attributes-charset" described
+ in Section 3.1.4.1 above.
+
+ If the Printer object supports more than just the 'utf-8'
+ charset, the Printer object MUST be able to code convert
+ between each of the charsets supported on a highest fidelity
+ possible basis in order to return the 'text' and 'name'
+ attributes in the charset requested by the client. However,
+ some information loss MAY occur during the charset conversion
+ depending on the charsets involved. For example, the Printer
+ object may convert from a UTF-8 'a' to a US-ASCII 'a' (with no
+ loss of information), from an ISO Latin 1 CAPITAL LETTER A WITH
+ ACUTE ACCENT to US-ASCII 'A' (losing the accent), or from a
+ UTF-8 Japanese Kanji character to some ISO Latin 1 error
+ character indication such as '?', decimal code equivalent, or
+ to the absence of a character, depending on implementation.
+
+ Whether an implementation that supports more than one charset
+ stores the data in the charset supplied by the client or code
+ converts to one of the other supported charsets, depends on
+ implementation. The strategy should try to minimize loss of
+ information during code conversion. On each response, such an
+ implementation converts from its internal charset to that
+ requested.
+
+ "attributes-natural-language" (naturalLanguage):
+ This operation attribute identifies the natural language used
+ by any 'text' and 'name' attributes that the IPP object is
+ returning in this response. Unlike the "attributes-charset"
+ operation attribute, the IPP object NEED NOT return the same
+
+
+
+Hastings, et al. Standards Track [Page 29]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ value as that supplied by the client in the request. The IPP
+ object MAY return the natural language of the Job object or the
+ Printer's configured natural language as identified by the
+ Printer object's "natural-language-configured" attribute,
+ rather than the natural language supplied by the client. For
+ any 'text' or 'name' attribute or status message in the
+ response that is in a different natural language than the value
+ returned in the "attributes-natural-language" operation
+ attribute, the IPP object MUST use the Natural Language
+ Override mechanism (see sections 4.1.1.2 and 4.1.2.2) on each
+ attribute value returned. The IPP object MAY use the Natural
+ Language Override mechanism redundantly, i.e., use it even when
+ the value is in the same natural language as the value supplied
+ in the "attributes-natural-language" operation attribute of the
+ response.
+
+3.1.5 Operation Targets
+
+ All IPP operations are directed at IPP objects. For Printer
+ operations, the operation is always directed at a Printer object
+ using one of its URIs (i.e., one of the values in the Printer
+ object's "printer-uri-supported" attribute). Even if the Printer
+ object supports more than one URI, the client supplies only one URI
+ as the target of the operation. The client identifies the target
+ object by supplying the correct URI in the "printer-uri (uri)"
+ operation attribute.
+
+ For Job operations, the operation is directed at either:
+
+ - The Job object itself using the Job object's URI. In this case,
+ the client identifies the target object by supplying the correct
+ URI in the "job-uri (uri)" operation attribute.
+ - The Printer object that created the Job object using both the
+ Printer objects URI and the Job object's Job ID. Since the
+ Printer object that created the Job object generated the Job ID,
+ it MUST be able to correctly associate the client supplied Job
+ ID with the correct Job object. The client supplies the Printer
+ object's URI in the "printer-uri (uri)" operation attribute and
+ the Job object's Job ID in the "job-id (integer(1:MAX))"
+ operation attribute.
+
+ If the operation is directed at the Job object directly using the Job
+ object's URI, the client MUST NOT include the redundant "job-id"
+ operation attribute.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 30]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The operation target attributes are REQUIRED operation attributes
+ that MUST be included in every operation request. Like the charset
+ and natural language attributes (see section 3.1.4), the operation
+ target attributes are specially ordered operation attributes. In all
+ cases, the operation target attributes immediately follow the
+ "attributes-charset" and "attributes-natural-language" attributes
+ within the operation attribute group, however the specific ordering
+ rules are:
+
+ - In the case where there is only one operation target attribute
+ (i.e., either only the "printer-uri" attribute or only the
+ "job-uri" attribute), that attribute MUST be the third attribute
+ in the operation attributes group.
+ - In the case where Job operations use two operation target
+ attributes (i.e., the "printer-uri" and "job-id" attributes),
+ the "printer-uri" attribute MUST be the third attribute and the
+ "job-id" attribute MUST be the fourth attribute.
+
+ In all cases, the target URIs contained within the body of IPP
+ operation requests and responses must be in absolute format rather
+ than relative format (a relative URL identifies a resource with the
+ scope of the HTTP server, but does not include scheme, host or port).
+
+ The following rules apply to the use of port numbers in URIs that
+ identify IPP objects:
+
+ 1. If the URI scheme allows the port number to be explicitly
+ included in the URI string, and a port number is specified
+ within the URI, then that port number MUST be used by the
+ client to contact the IPP object.
+
+ 2. If the URI scheme allows the port number to be explicitly
+ included in the URI string, and a port number is not specified
+ within the URI, then default port number implied by that URI
+ scheme MUST be used by the client to contact the IPP object.
+
+ 3. If the URI scheme does not allow an explicit port number to be
+ specified within the URI, then the default port number implied
+ by that URI MUST be used by the client to contact the IPP
+ object.
+
+ Note: The IPP "Encoding and Transport document [RFC2910] shows a
+ mapping of IPP onto HTTP/1.1 [RFC2616] and defines a new default port
+ number for using IPP over HTTP/1.1.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 31]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.1.6 Operation Response Status Codes and Status Messages
+
+ Every operation response includes a REQUIRED "status-code" parameter
+ and an OPTIONAL "status-message" operation attribute, and an OPTIONAL
+ "detailed-status-message" operation attribute. The Print-URI and
+ Send-URI response MAY include an OPTIONAL "document-access-error"
+ operation attribute.
+
+3.1.6.1 "status-code" (type2 enum)
+
+ The REQUIRED "status-code" parameter provides information on the
+ processing of a request.
+
+ The status code is intended for use by automata. A client
+ implementation of IPP SHOULD convert status code values into any
+ localized message that has semantic meaning to the end user.
+
+ The "status-code" value is a numeric value that has semantic meaning.
+ The "status-code" syntax is similar to a "type2 enum" (see section
+ 4.1 on "Attribute Syntaxes") except that values can range only from
+ 0x0000 to 0x7FFF. Section 13 describes the status codes, assigns the
+ numeric values, and suggests a corresponding status message for each
+ status code for use by the client when the user's natural language is
+ English.
+
+ If the Printer performs an operation with no errors and it encounters
+ no problems, it MUST return the status code 'successful-ok' in the
+ response. See section 13.
+
+ If the client supplies unsupported values for the following
+ parameters or Operation attributes, the Printer object MUST reject
+ the operation, NEED NOT return the unsupported attribute value in the
+ Unsupported Attributes group, and MUST return the indicated status
+ code:
+
+ Parameter/Attribute Status code
+
+ version-number server-error-version-not-supported
+ operation-id server-error-operation-not-supported
+ attributes-charset client-error-charset-not-supported
+ compression client-error-compression-not-supported
+ document-format client-error-document-format-not-supported
+ document-uri client-error-uri-scheme-not-supported,
+ client-error-document-access-error
+
+ If the client supplies unsupported values for other attributes, or
+ unsupported attributes, the Printer returns the status code defined
+ in section 3.1.7 on Unsupported Attributes.
+
+
+
+Hastings, et al. Standards Track [Page 32]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.1.6.2 "status-message" (text(255))
+
+ The OPTIONAL "status-message" operation attribute provides a short
+ textual description of the status of the operation. The "status-
+ message" attribute's syntax is "text(255)", so the maximum length is
+ 255 octets (see section 4.1.1). The status message is intended for
+ the human end user. If a response does include a "status-message"
+ attribute, an IPP client NEED NOT examine or display the messages,
+ however it SHOULD do so in some implementation specific manner. The
+ "status-message" is especially useful for a later version of a
+ Printer object to return as supplemental information for the human
+ user to accompany a status code that an earlier version of a client
+ might not understand.
+
+ If the Printer object supports the "status-message" operation
+ attribute, the Printer object MUST be able to generate this message
+ in any of the natural languages identified by the Printer object's
+ "generated-natural-language-supported" attribute (see the
+ "attributes-natural-language" operation attribute specified in
+ section 3.1.4.1. Section 13 suggests the text for the status message
+ returned by the Printer for use with the English natural language.
+
+ As described in section 3.1.4.1 for any returned 'text' attribute, if
+ there is a choice for generating this message, the Printer object
+ uses the natural language indicated by the value of the "attributes-
+ natural-language" in the client request if supported, otherwise the
+ Printer object uses the value in the Printer object's own "natural-
+ language-configured" attribute.
+
+ If the Printer object supports the "status-message" operation
+ attribute, it SHOULD use the REQUIRED 'utf-8' charset to return a
+ status message for the following error status codes (see section 13):
+ 'client-error-bad-request', 'client-error-charset-not-supported',
+ 'server-error-internal-error', 'server-error-operation-not-
+ supported', and 'server-error-version-not-supported'. In this case,
+ it MUST set the value of the "attributes-charset" operation attribute
+ to 'utf-8' in the error response.
+
+3.1.6.3 "detailed-status-message" (text(MAX))
+
+ The OPTIONAL "detailed-status-message" operation attribute provides
+ additional more detailed technical and implementation-specific
+ information about the operation. The "detailed-status-message"
+ attribute's syntax is "text(MAX)", so the maximum length is 1023
+ octets (see section 4.1.1). If the Printer objects supports the
+ "detailed-status-message" operation attribute, the Printer NEED NOT
+ localize the message, since it is intended for use by the system
+ administrator or other experienced technical persons. Localization
+
+
+
+Hastings, et al. Standards Track [Page 33]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ might obscure the technical meaning of such messages. Clients MUST
+ NOT attempt to parse the value of this attribute. See the
+ "document-access-error" operation attribute (section 3.1.6.4) for
+ additional errors that a program can process.
+
+3.1.6.4 "document-access-error" (text(MAX))
+
+ This OPTIONAL operation attribute provides additional information
+ about any document access errors encountered by the Printer before it
+ returned a response to the Print-URI (section 3.2.2) or Send-URI
+ (section 3.3.1) operation. For errors in the protocol identified by
+ the URI scheme in the "document-uri" operation attribute, such as
+ 'http:' or 'ftp:', the error code is returned in parentheses,
+ followed by the URI. For example:
+
+ (404) http://ftp.pwg.org/pub/pwg/ipp/new_MOD/ipp-model-v11.pdf
+
+ Most Internet protocols use decimal error codes (unlike IPP), so the
+ ASCII error code representation is in decimal.
+
+3.1.7 Unsupported Attributes
+
+ The Unsupported Attributes group contains attributes that are not
+ supported by the operation. This group is primarily for the job
+ creation operations, but all operations can return this group.
+
+ A Printer object MUST include an Unsupported Attributes group in a
+ response if the status code is one of the following: 'successful-
+ ok-ignored-or-substituted-attributes', 'successful-ok-conflicting-
+ attributes', 'client-error-attributes-or-values-not-supported' or
+ 'client-error-conflicting-attributes'.
+
+ If the status code is one of the four specified in the preceding
+ paragraph, the Unsupported Attributes group MUST contain all of those
+ attributes and only those attributes that are:
+
+ a. an Operation or Job Template attribute supplied in the request,
+ and
+
+ b. unsupported by the printer. See below for details on the three
+ categories "unsupported" attributes.
+
+ If the status code is one of those in the table in section 3.1.6.1,
+ the Unsupported Attributes group NEED NOT contain the unsupported
+ parameter or attribute indicated in that table.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 34]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ If the Printer object is not returning any Unsupported Attributes in
+ the response, the Printer object SHOULD omit Group 2 rather than
+ sending an empty group. However, a client MUST be able to accept an
+ empty group.
+
+ Unsupported attributes fall into three categories:
+
+ 1. The Printer object does not support the supplied attribute (no
+ matter what the attribute syntax or value).
+
+ 2. The Printer object does support the attribute, but does not
+ support some or all of the particular attribute syntaxes or
+ values supplied by the client (i.e., the Printer object does
+ not have those attribute syntaxes or values in its
+ corresponding "xxx-supported" attribute).
+
+ 3. The Printer object does support the attributes and values
+ supplied, but the particular values are in conflict with one
+ another, because they violate a constraint, such as not being
+ able to staple transparencies.
+
+ In the case of an unsupported attribute name, the Printer object
+ returns the client-supplied attribute with a substituted value of
+ 'unsupported'. This value's syntax type is "out-of-band" and its
+ encoding is defined by special rules for "out-of-band" values in the
+ "Encoding and Transport" document [RFC2910]. Its value indicates no
+ support for the attribute itself (see the beginning of section 4.1).
+
+ In the case of a supported attribute with one or more unsupported
+ attribute syntaxes or values, the Printer object simply returns the
+ client-supplied attribute with the unsupported attribute syntaxes or
+ values as supplied by the client. This indicates support for the
+ attribute, but no support for that particular attribute syntax or
+ value. If the client supplies a multi-valued attribute with more
+ than one value and the Printer object supports the attribute but only
+ supports a subset of the client-supplied attribute syntaxes or
+ values, the Printer object
+
+ MUST return only those attribute syntaxes or values that are
+ unsupported.
+
+ In the case of two (or more) supported attribute values that are in
+ conflict with one another (although each is supported independently,
+ the values conflict when requested together within the same job), the
+ Printer object MUST return all the values that it ignores or
+ substitutes to resolve the conflict, but not any of the values that
+
+
+
+
+
+Hastings, et al. Standards Track [Page 35]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ it is still using. The choice for exactly how to resolve the
+ conflict is implementation dependent. See sections 3.2.1.2 and 15.
+ See The Implementer's Guide [IPP-IIG] for an example.
+
+3.1.8 Versions
+
+ Each operation request and response carries with it a "version-
+ number" parameter. Each value of the "version-number" is in the form
+ "X.Y" where X is the major version number and Y is the minor version
+ number. By including a version number in the client request, it
+ allows the client to identify which version of IPP it is interested
+ in using, i.e., the version whose conformance requirements the client
+ may be depending upon the Printer to meet.
+
+ If the IPP object does not support that major version number supplied
+ by the client, i.e., the major version field of the "version-number"
+ parameter does not match any of the values of the Printer's "ipp-
+ versions-supported" (see section 4.4.14), the object MUST respond
+ with a status code of 'server-error-version-not-supported' along with
+ the closest version number that is supported (see section 13.1.5.4).
+ If the major version number is supported, but the minor version
+ number is not, the IPP object SHOULD accept and attempt to perform
+ the request (or reject the request if the operation is not
+ supported), else it rejects the request and returns the 'server-
+ error-version-not-supported' status code. In all cases, the IPP
+ object MUST return the "version-number" that it supports that is
+ closest to the version number supplied by the client in the request.
+
+ There is no version negotiation per se. However, if after receiving
+ a 'server-error-version-not-supported' status code from an IPP
+ object, a client SHOULD try again with a different version number. A
+ client MAY also determine the versions supported either from a
+ directory that conforms to Appendix E (see section 16) or by querying
+ the Printer object's "ipp-versions-supported" attribute (see section
+ 4.4.14) to determine which versions are supported.
+
+ An IPP object implementation MUST support version '1.1', i.e., meet
+ the conformance requirements for IPP/1.1 as specified in this
+ document and [RFC2910]. It is recommended that IPP object
+ implementations accept any request with the major version '1' (or
+ reject the request if the operation is not supported).
+
+ There is only one notion of "version number" that covers both IPP
+ Model and IPP Protocol changes. Thus the version number MUST change
+ when introducing a new version of the Model and Semantics document
+ (this document) or a new version of the "Encoding and Transport"
+ document [RFC2910].
+
+
+
+
+Hastings, et al. Standards Track [Page 36]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Changes to the major version number of the Model and Semantics
+ document indicate structural or syntactic changes that make it
+ impossible for older version of IPP clients and Printer objects to
+ correctly parse and correctly process the new or changed attributes,
+ operations and responses. If the major version number changes, the
+ minor version numbers is set to zero. As an example, adding the
+ REQUIRED "ipp-attribute-fidelity" attribute to version '1.1' (if it
+ had not been part of version '1.0'), would have required a change to
+ the major version number, since an IPP/1.0 Printer would not have
+ processed a request with the correct semantics that contained the
+ "ipp-attribute-fidelity" attribute that it did not know about. Items
+ that might affect the changing of the major version number include
+ any changes to the Model and Semantics document (this document) or
+ the "Encoding and Transport" document [RFC2910] itself, such as:
+
+ - reordering of ordered attributes or attribute sets
+ - changes to the syntax of existing attributes
+ - adding REQUIRED (for an IPP object to support) operation
+ attribute groups
+ - adding values to existing REQUIRED operation attributes
+ - adding REQUIRED operations
+
+ Changes to the minor version number indicate the addition of new
+ features, attributes and attribute values that may not be understood
+ by all IPP objects, but which can be ignored if not understood.
+ Items that might affect the changing of the minor version number
+ include any changes to the model objects and attributes but not the
+ encoding and transport rules [RFC2910] (except adding attribute
+ syntaxes). Examples of such changes are:
+
+ - grouping all extensions not included in a previous version into
+ a new version
+ - adding new attribute values
+ - adding new object attributes
+ - adding OPTIONAL (for an IPP object to support) operation
+ attributes (i.e., those attributes that an IPP object can ignore
+ without confusing clients)
+ - adding OPTIONAL (for an IPP object to support) operation
+ attribute groups (i.e., those attributes that an IPP object can
+ ignore without confusing clients)
+ - adding new attribute syntaxes
+ - adding OPTIONAL operations
+ - changing Job Description attributes or Printer Description
+ attributes from OPTIONAL to REQUIRED or vice versa.
+ - adding OPTIONAL attribute syntaxes to an existing attribute.
+
+ The encoding of the "version-number" MUST NOT change over any version
+ number (either major or minor). This rule guarantees that all future
+
+
+
+Hastings, et al. Standards Track [Page 37]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ versions will be backwards compatible with all previous versions (at
+ least for checking the "version-number"). In addition, any protocol
+ elements (attributes, error codes, tags, etc.) that are not carried
+ forward from one version to the next are deprecated so that they can
+ never be reused with new semantics.
+
+ Implementations that support a certain version NEED NOT support ALL
+ previous versions. As each new version is defined (through the
+ release of a new IPP specification document), that version will
+ specify which previous versions MUST and which versions SHOULD be
+ supported in compliant implementations.
+
+3.1.9 Job Creation Operations
+
+ In order to "submit a print job" and create a new Job object, a
+ client issues a create request. A create request is any one of
+ following three operation requests:
+
+ - The Print-Job Request: A client that wants to submit a print job
+ with only a single document uses the Print-Job operation. The
+ operation allows for the client to "push" the document data to
+ the Printer object by including the document data in the request
+ itself.
+
+ - The Print-URI Request: A client that wants to submit a print job
+ with only a single document (where the Printer object "pulls"
+ the document data instead of the client "pushing" the data to
+ the Printer object) uses the Print-URI operation. In this
+ case, the client includes in the request only a URI reference to
+ the document data (not the document data itself).
+
+ - The Create-Job Request: A client that wants to submit a print
+ job with multiple documents uses the Create-Job operation. This
+ operation is followed by an arbitrary number (one or more) of
+ Send-Document and/or Send-URI operations (each creating another
+ document for the newly create Job object). The Send-Document
+ operation includes the document data in the request (the client
+ "pushes" the document data to the printer), and the Send-URI
+ operation includes only a URI reference to the document data in
+ the request (the Printer "pulls" the document data from the
+ referenced location). The last Send-Document or Send-URI
+ request for a given Job object includes a "last-document"
+ operation attribute set to 'true' indicating that this is the
+ last request.
+
+ Throughout this model document, the term "create request" is used to
+ refer to any of these three operation requests.
+
+
+
+
+Hastings, et al. Standards Track [Page 38]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ A Create-Job operation followed by only one Send-Document operation
+ is semantically equivalent to a Print-Job operation, however, for
+ performance reasons, the client SHOULD use the Print-Job operation
+ for all single document jobs. Also, Print-Job is a REQUIRED
+ operation (all implementations MUST support it) whereas Create-Job is
+ an OPTIONAL operation, hence some implementations might not support
+ it.
+
+ Job submission time is the point in time when a client issues a
+ create request. The initial state of every Job object is the
+ 'pending', 'pending-held', or 'processing' state (see section 4.3.7).
+ When the Printer object begins processing the print job, the Job
+ object's state moves to 'processing'. This is known as job
+ processing time. There are validation checks that must be done at
+ job submission time and others that must be performed at job
+ processing time.
+
+ At job submission time and at the time a Validate-Job operation is
+ received, the Printer MUST do the following:
+
+ 1. Process the client supplied attributes and either accept or
+ reject the request
+ 2. Validate the syntax of and support for the scheme of any client
+ supplied URI
+
+ At job submission time the Printer object MUST validate whether or
+ not the supplied attributes, attribute syntaxes, and values are
+ supported by matching them with the Printer object's corresponding
+ "xxx-supported" attributes. See section 3.1.7 for details. [IPP-
+ IIG] presents suggested steps for an IPP object to either accept or
+ reject any request and additional steps for processing create
+ requests.
+
+ At job submission time the Printer object NEED NOT perform the
+ validation checks reserved for job processing time such as:
+
+ 1. Validating the document data
+ 2. Validating the actual contents of any client supplied URI
+ (resolve the reference and follow the link to the document
+ data)
+
+ At job submission time, these additional job processing time
+ validation checks are essentially useless, since they require
+ actually parsing and interpreting the document data, are not
+ guaranteed to be 100% accurate, and MUST be done, yet again, at job
+ processing time. Also, in the case of a URI, checking for
+ availability at job submission time does not guarantee availability
+
+
+
+
+Hastings, et al. Standards Track [Page 39]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ at job processing time. In addition, at job processing time, the
+ Printer object might discover any of the following conditions that
+ were not detectable at job submission time:
+
+ - runtime errors in the document data,
+ - nested document data that is in an unsupported format,
+ - the URI reference is no longer valid (i.e., the server hosting
+ the document might be down), or
+ - any other job processing error
+
+ At job submission time, a Printer object, especially a non-spooling
+ Printer, MAY accept jobs that it does not have enough space for. In
+ such a situation, a Printer object MAY stop reading data from a
+ client for an indefinite period of time. A client MUST be prepared
+ for a write operation to block for an indefinite period of time (see
+ section 5.1 on client conformance).
+
+ When a Printer object has too little space for starting a new job, it
+ MAY reject a new create request. In this case, a Printer object MUST
+ return a response (in reply to the rejected request) with a status-
+ code of 'server-error-busy' (see section 14.1.5.8) and it MAY close
+ the connection before receiving all bytes of the operation. A
+ Printer SHOULD indicate that it is temporarily unable to accept jobs
+ by setting the 'spool-space-full' value in its "printer-state-
+ reasons" attribute and removing the value when it can accept another
+ job (see section 4.4.12).
+
+ When receiving a 'server-error-busy' status-code in an operation
+ response, a client MUST be prepared for the Printer object to close
+ the connection before the client has sent all of the data (especially
+ for the Print-Job operation). A client MUST be prepared to keep
+ submitting a create request until the IPP Printer object accepts the
+ create request.
+
+ At job processing time, since the Printer object has already
+ responded with a successful status code in the response to the create
+ request, if the Printer object detects an error, the Printer object
+ is unable to inform the end user of the error with an operation
+ status code. In this case, the Printer, depending on the error, can
+ set the job object's "job-state", "job-state-reasons", or "job-
+ state-message" attributes to the appropriate value(s) so that later
+ queries can report the correct job status.
+
+ Note: Asynchronous notification of events is outside the scope of
+ this IPP/1.1 document.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 40]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.2 Printer Operations
+
+ All Printer operations are directed at Printer objects. A client
+ MUST always supply the "printer-uri" operation attribute in order to
+ identify the correct target of the operation.
+
+3.2.1 Print-Job Operation
+
+ This REQUIRED operation allows a client to submit a print job with
+ only one document and supply the document data (rather than just a
+ reference to the data). See Section 15 for the suggested steps for
+ processing create operations and their Operation and Job Template
+ attributes.
+
+3.2.1.1 Print-Job Request
+
+ The following groups of attributes are supplied as part of the
+ Print-Job Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1. The Printer object
+ MUST copy these values to the corresponding Job Description
+ attributes described in sections 4.3.19 and 4.3.20.
+
+ Target:
+ The "printer-uri" (uri) operation attribute which is the target
+ for this operation as described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "job-name" (name(MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It contains the client
+ supplied Job name. If this attribute is supplied by the
+ client, its value is used for the "job-name" attribute of the
+ newly created Job object. The client MAY automatically include
+ any information that will help the end-user distinguish amongst
+ his/her jobs, such as the name of the application program along
+ with information from the document, such as the document name,
+ document subject, or source file name. If this attribute is
+ not supplied by the client, the Printer generates a name to use
+ in the "job-name" attribute of the newly created Job object
+ (see Section 4.3.5).
+
+
+
+Hastings, et al. Standards Track [Page 41]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ "ipp-attribute-fidelity" (boolean):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. The value 'true' indicates
+ that total fidelity to client supplied Job Template attributes
+ and values is required, else the Printer object MUST reject the
+ Print-Job request. The value 'false' indicates that a
+ reasonable attempt to print the Job object is acceptable and
+ the Printer object MUST accept the Print-Job request. If not
+ supplied, the Printer object assumes the value is 'false'. All
+ Printer objects MUST support both types of job processing. See
+ section 15 for a full description of "ipp-attribute-fidelity"
+ and its relationship to other attributes, especially the
+ Printer object's "pdl-override-supported" attribute.
+
+ "document-name" (name(MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It contains the client
+ supplied document name. The document name MAY be different
+ than the Job name. Typically, the client software
+ automatically supplies the document name on behalf of the end
+ user by using a file name or an application generated name. If
+ this attribute is supplied, its value can be used in a manner
+ defined by each implementation. Examples include: printed
+ along with the Job (job start sheet, page adornments, etc.),
+ used by accounting or resource tracking management tools, or
+ even stored along with the document as a document level
+ attribute. IPP/1.1 does not support the concept of document
+ level attributes.
+
+ "compression" (type3 keyword):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute and the "compression-
+ supported" attribute (see section 4.4.32). The client supplied
+ "compression" operation attribute identifies the compression
+ algorithm used on the document data. The following cases exist:
+
+ a) If the client omits this attribute, the Printer object MUST
+ assume that the data is not compressed (i.e. the Printer
+ follows the rules below as if the client supplied the
+ "compression" attribute with a value of 'none').
+ b) If the client supplies this attribute, but the value is not
+ supported by the Printer object, i.e., the value is not one
+ of the values of the Printer object's "compression-
+ supported" attribute, the Printer object MUST reject the
+ request, and return the 'client-error-compression-not-
+ supported' status code. See section 3.1.7 for returning
+ unsupported attributes and values.
+
+
+
+
+Hastings, et al. Standards Track [Page 42]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ c) If the client supplies the attribute and the Printer object
+ supports the attribute value, the Printer object uses the
+ corresponding decompression algorithm on the document data.
+ d) If the decompression algorithm fails before the Printer
+ returns an operation response, the Printer object MUST
+ reject the request and return the 'client-error-
+ compression-error' status code.
+ e) If the decompression algorithm fails after the Printer
+ returns an operation response, the Printer object MUST abort
+ the job and add the 'compression-error' value to the job's
+ "job-state-reasons" attribute.
+ f) If the decompression algorithm succeeds, the document data
+ MUST then have the format specified by the job's "document-
+ format" attribute, if supplied (see "document-format"
+ operation attribute definition below).
+
+ "document-format" (mimeMediaType):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. The value of this
+ attribute identifies the format of the supplied document data.
+ The following cases exist:
+
+ a) If the client does not supply this attribute, the Printer
+ object assumes that the document data is in the format
+ defined by the Printer object's "document-format-default"
+ attribute. (i.e. the Printer follows the rules below as if
+ the client supplied the "document-format" attribute with a
+ value equal to the printer's default value).
+ b) If the client supplies this attribute, but the value is not
+ supported by the Printer object, i.e., the value is not one
+ of the values of the Printer object's "document-format-
+ supported" attribute, the Printer object MUST reject the
+ request and return the 'client-error-document-format-not-
+ supported' status code.
+ c) If the client supplies this attribute and its value is
+ 'application/octet-stream' (i.e. to be auto-sensed, see
+ Section 4.1.9.1), and the format is not one of the
+ document-formats that the Printer can auto-sense, and this
+ check occurs before the Printer returns an operation
+ response, then the Printer MUST reject the request and
+ return the 'client-error-document-format-not-supported'
+ status code.
+ d) If the client supplies this attribute, and the value is
+ supported by the Printer object, the Printer is capable of
+ interpreting the document data.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 43]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ e) If interpreting of the document data fails before the
+ Printer returns an operation response, the Printer object
+ MUST reject the request and return the 'client-error-
+ document-format-error' status code.
+ f) If interpreting of the document data fails after the Printer
+ returns an operation response, the Printer object MUST abort
+ the job and add the 'document-format-error' value to the
+ job's "job-state-reasons" attribute.
+
+ "document-natural-language" (naturalLanguage):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute. This attribute
+ specifies the natural language of the document for those
+ document-formats that require a specification of the natural
+ language in order to image the document unambiguously. There
+ are no particular values required for the Printer object to
+ support.
+
+ "job-k-octets" (integer(0:MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute and the "job-k-
+ octets-supported" attribute (see section 4.4.33). The client
+ supplied "job-k-octets" operation attribute identifies the
+ total size of the document(s) in K octets being submitted (see
+ section 4.3.17.1 for the complete semantics). If the client
+ supplies the attribute and the Printer object supports the
+ attribute, the value of the attribute is used to populate the
+ Job object's "job-k-octets" Job Description attribute.
+
+ For this attribute and the following two attributes ("job-
+ impressions", and "job-media-sheets"), if the client supplies
+ the attribute, but the Printer object does not support the
+ attribute, the Printer object ignores the client-supplied
+ value. If the client supplies the attribute and the Printer
+ supports the attribute, and the value is within the range of
+ the corresponding Printer object's "xxx-supported" attribute,
+ the Printer object MUST use the value to populate the Job
+ object's "xxx" attribute. If the client supplies the attribute
+ and the Printer supports the attribute, but the value is
+ outside the range of the corresponding Printer object's "xxx-
+ supported" attribute, the Printer object MUST copy the
+ attribute and its value to the Unsupported Attributes response
+ group, reject the request, and return the 'client-error-
+ attributes-or-values-not-supported' status code. If the client
+ does not supply the attribute, the Printer object MAY choose to
+ populate the corresponding Job object attribute depending on
+ whether the Printer object supports the attribute and is able
+ to calculate or discern the correct value.
+
+
+
+Hastings, et al. Standards Track [Page 44]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ "job-impressions" (integer(0:MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute and the "job-
+ impressions-supported" attribute (see section 4.4.34). The
+ client supplied "job-impressions" operation attribute
+ identifies the total size in number of impressions of the
+ document(s) being submitted (see section 4.3.17.2 for the
+ complete semantics).
+
+ See last paragraph under "job-k-octets".
+
+ "job-media-sheets" (integer(0:MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute and the "job-media-
+ sheets-supported" attribute (see section 4.4.35). The client
+ supplied "job-media-sheets" operation attribute identifies the
+ total number of media sheets to be produced for this job (see
+ section 4.3.17.3 for the complete semantics).
+
+ See last paragraph under "job-k-octets".
+
+ Group 2: Job Template Attributes
+
+ The client OPTIONALLY supplies a set of Job Template attributes as
+ defined in section 4.2. If the client is not supplying any Job
+ Template attributes in the request, the client SHOULD omit Group 2
+ rather than sending an empty group. However, a Printer object
+ MUST be able to accept an empty group.
+
+ Group 3: Document Content
+
+ The client MUST supply the document data to be processed.
+
+ In addition to the MANDATORY parameters required for every
+ operation request, the simplest Print-Job Request consists of just
+ the "attributes-charset" and "attributes-natural-language"
+ operation attributes; the "printer-uri" target operation
+ attribute; the Document Content and nothing else. In this simple
+ case, the Printer object:
+
+ - creates a new Job object (the Job object contains a single
+ document),
+ - stores a generated Job name in the "job-name" attribute in the
+ natural language and charset requested (see Section 3.1.4.1) (if
+ those are supported, otherwise using the Printer object's
+ default natural language and charset), and
+
+
+
+
+
+Hastings, et al. Standards Track [Page 45]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - at job processing time, uses its corresponding default value
+ attributes for the supported Job Template attributes that were
+ not supplied by the client as IPP attribute or embedded
+ instructions in the document data.
+
+3.2.1.2 Print-Job Response
+
+ The Printer object MUST return to the client the following sets of
+ attributes as part of the Print-Job Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in sections 13 and 3.1.6. If
+ the client supplies unsupported or conflicting Job Template
+ attributes or values, the Printer object MUST reject or accept
+ the Print-Job request depending on the whether the client
+ supplied a 'true' or 'false' value for the "ipp-attribute-
+ fidelity" operation attribute. See the Implementer's Guide
+ [IPP-IIG] for a complete description of the suggested steps for
+ processing a create request.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See section 3.1.7 for details on returning Unsupported Attributes.
+
+ The value of the "ipp-attribute-fidelity" supplied by the client
+ does not affect what attributes the Printer object returns in this
+ group. The value of "ipp-attribute-fidelity" only affects whether
+ the Print-Job operation is accepted or rejected. If the job is
+ accepted, the client may query the job using the Get-Job-
+ Attributes operation requesting the unsupported attributes that
+ were returned in the create response to see which attributes were
+ ignored (not stored on the Job object) and which attributes were
+ stored with other (substituted) values.
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 46]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Group 3: Job Object Attributes
+
+ "job-uri" (uri):
+ The Printer object MUST return the Job object's URI by
+ returning the contents of the REQUIRED "job-uri" Job object
+ attribute. The client uses the Job object's URI when directing
+ operations at the Job object. The Printer object always uses
+ its configured security policy when creating the new URI.
+ However, if the Printer object supports more than one URI, the
+ Printer object also uses information about which URI was used
+ in the Print-Job Request to generated the new URI so that the
+ new URI references the correct access channel. In other words,
+ if the Print-Job Request comes in over a secure channel, the
+ Printer object MUST generate a Job URI that uses the secure
+ channel as well.
+
+ "job-id" (integer(1:MAX)):
+ The Printer object MUST return the Job object's Job ID by
+ returning the REQUIRED "job-id" Job object attribute. The
+ client uses this "job-id" attribute in conjunction with the
+ "printer-uri" attribute used in the Print-Job Request when
+ directing Job operations at the Printer object.
+
+ "job-state" (type1 enum):
+ The Printer object MUST return the Job object's REQUIRED "job-
+ state" attribute. The value of this attribute (along with the
+ value of the next attribute: "job-state-reasons") is taken
+ from a "snapshot" of the new Job object at some meaningful
+ point in time (implementation defined) between when the Printer
+ object receives the Print-Job Request and when the Printer
+ object returns the response.
+
+ "job-state-reasons" (1setOf type2 keyword):
+ The Printer object MUST return the Job object's REQUIRED "job-
+ state-reasons" attribute.
+
+ "job-state-message" (text(MAX)):
+ The Printer object OPTIONALLY returns the Job object's OPTIONAL
+ "job-state-message" attribute. If the Printer object supports
+ this attribute then it MUST be returned in the response. If
+ this attribute is not returned in the response, the client can
+ assume that the "job-state-message" attribute is not supported
+ and will not be returned in a subsequent Job object query.
+
+ "number-of-intervening-jobs" (integer(0:MAX)):
+ The Printer object OPTIONALLY returns the Job object's OPTIONAL
+ "number-of-intervening-jobs" attribute. If the Printer object
+ supports this attribute then it MUST be returned in the
+
+
+
+Hastings, et al. Standards Track [Page 47]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ response. If this attribute is not returned in the response,
+ the client can assume that the "number-of-intervening-jobs"
+ attribute is not supported and will not be returned in a
+ subsequent Job object query.
+
+ Note: Since any printer state information which affects a job's
+ state is reflected in the "job-state" and "job-state-reasons"
+ attributes, it is sufficient to return only these attributes
+ and no specific printer status attributes.
+
+ Note: In addition to the MANDATORY parameters required for every
+ operation response, the simplest response consists of the just the
+ "attributes-charset" and "attributes-natural-language" operation
+ attributes and the "job-uri", "job-id", and "job-state" Job Object
+ Attributes. In this simplest case, the status code is 'successful-
+ ok' and there is no "status-message" or "detailed-status-message"
+ operation attribute.
+
+3.2.2 Print-URI Operation
+
+ This OPTIONAL operation is identical to the Print-Job operation
+ (section 3.2.1) except that a client supplies a URI reference to the
+ document data using the "document-uri" (uri) operation attribute (in
+ Group 1) rather than including the document data itself. Before
+ returning the response, the Printer MUST validate that the Printer
+ supports the retrieval method (e.g., http, ftp, etc.) implied by the
+ URI, and MUST check for valid URI syntax. If the client-supplied URI
+ scheme is not supported, i.e. the value is not in the Printer
+ object's "referenced-uri-scheme-supported" attribute, the Printer
+ object MUST reject the request and return the 'client-error-uri-
+ scheme-not-supported' status code.
+
+ The IPP Printer MAY validate the accessibility of the document as
+ part of the operation or subsequently. If the Printer determines an
+ accessibility problem before returning an operation response, it
+ rejects the request and returns the 'client-error-document-access-
+ error' status code. The Printer MAY also return a specific document
+ access error code using the "document-access-error" operation
+ attribute (see section 3.1.6.4).
+
+ If the Printer determines this document accessibility problem after
+ accepting the request and returning an operation response with one of
+ the successful status codes, the Printer adds the 'document-access-
+ error' value to the job's "job-state-reasons" attribute and MAY
+ populate the job's "job-document-access-errors" Job Description
+ attribute (see section 4.3.11). See The Implementer's Guide [IPP-
+ IIG] for suggested additional checks.
+
+
+
+
+Hastings, et al. Standards Track [Page 48]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ If the Printer object supports this operation, it MUST support the
+ "reference-uri-schemes-supported" Printer attribute (see section
+ 4.4.27).
+
+ It is up to the IPP object to interpret the URI and subsequently
+ "pull" the document from the source referenced by the URI string.
+
+3.2.3 Validate-Job Operation
+
+ This REQUIRED operation is similar to the Print-Job operation
+ (section 3.2.1) except that a client supplies no document data and
+ the Printer allocates no resources (i.e., it does not create a new
+ Job object). This operation is used only to verify capabilities of a
+ printer object against whatever attributes are supplied by the client
+ in the Validate-Job request. By using the Validate-Job operation a
+ client can validate that an identical Print-Job operation (with the
+ document data) would be accepted. The Validate-Job operation also
+ performs the same security negotiation as the Print-Job operation
+ (see section 8), so that a client can check that the client and
+ Printer object security requirements can be met before performing a
+ Print-Job operation.
+
+ The Validate-Job operation does not accept a "document-uri" attribute
+ in order to allow a client to check that the same Print-URI operation
+ will be accepted, since the client doesn't send the data with the
+ Print-URI operation. The client SHOULD just issue the Print-URI
+ request.
+
+ The Printer object returns the same status codes, Operation
+ Attributes (Group 1) and Unsupported Attributes (Group 2) as the
+ Print-Job operation. However, no Job Object Attributes (Group 3) are
+ returned, since no Job object is created.
+
+3.2.4 Create-Job Operation
+
+ This OPTIONAL operation is similar to the Print-Job operation
+ (section 3.2.1) except that in the Create-Job request, a client does
+ not supply document data or any reference to document data. Also,
+ the client does not supply any of the "document-name", "document-
+ format", "compression", or "document-natural-language" operation
+ attributes. This operation is followed by one or more Send-Document
+ or Send-URI operations. In each of those operation requests, the
+ client OPTIONALLY supplies the "document-name", "document-format",
+ and "document-natural-language" attributes for each document in the
+ multi-document Job object.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 49]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ If a Printer object supports the Create-Job operation, it MUST also
+ support the Send-Document operation and also MAY support the Send-URI
+ operation.
+
+ If the Printer object supports this operation, it MUST support the
+ "multiple-operation-time-out" Printer attribute (see section 4.4.31).
+
+ If the Printer object supports this operation, then it MUST support
+ the "multiple-document-jobs-supported" Printer Description attribute
+ (see section 4.4.16) and indicate whether or not it supports
+ multiple-document jobs.
+
+ If the Printer object supports this operation and supports multiple
+ documents in a job, then it MUST support the "multiple-document-
+ handling" Job Template job attribute with at least one value (see
+ section 4.2.4) and the associated "multiple-document-handling-
+ default" and "multiple-document-handling-supported" Job Template
+ Printer attributes (see section 4.2).
+
+ After the Create-Job operation has completed, the value of the "job-
+ state" attribute is similar to the "job-state" after a Print-Job,
+ even though no document-data has arrived. A Printer MAY set the
+ 'job-data-insufficient' value of the job's "job-state-reason"
+ attribute to indicate that processing cannot begin until sufficient
+ data has arrived and set the "job-state" to either 'pending' or
+ 'pending-held'. A non-spooling printer that doesn't implement the
+ 'pending' job state may even set the "job-state" to 'processing',
+ even though there is not yet any data to process. See sections 4.3.7
+ and 4.3.8.
+
+3.2.5 Get-Printer-Attributes Operation
+
+ This REQUIRED operation allows a client to request the values of the
+ attributes of a Printer object. In the request, the client supplies
+ the set of Printer attribute names and/or attribute group names in
+ which the requester is interested. In the response, the Printer
+ object returns a corresponding attribute set with the appropriate
+ attribute values filled in.
+
+ For Printer objects, the possible names of attribute groups are:
+
+ - 'job-template': the subset of the Job Template attributes that
+ apply to a Printer object (the last two columns of the table in
+ Section 4.2) that the implementation supports for Printer
+ objects.
+ - 'printer-description': the subset of the attributes specified in
+ Section 4.4 that the implementation supports for Printer
+ objects.
+
+
+
+Hastings, et al. Standards Track [Page 50]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - 'all': the special group 'all' that includes all attributes that
+ the implementation supports for Printer objects.
+
+ Since a client MAY request specific attributes or named groups, there
+ is a potential that there is some overlap. For example, if a client
+ requests, 'printer-name' and 'all', the client is actually requesting
+ the "printer-name" attribute twice: once by naming it explicitly, and
+ once by inclusion in the 'all' group. In such cases, the Printer
+ object NEED NOT return each attribute only once in the response even
+ if it is requested multiple times. The client SHOULD NOT request the
+ same attribute in multiple ways.
+
+ It is NOT REQUIRED that a Printer object support all attributes
+ belonging to a group (since some attributes are OPTIONAL). However,
+ it is REQUIRED that each Printer object support all group names.
+
+3.2.5.1 Get-Printer-Attributes Request
+
+ The following sets of attributes are part of the Get-Printer-
+ Attributes Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1.
+
+ Target:
+ The "printer-uri" (uri) operation attribute which is the target
+ for this operation as described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "requested-attributes" (1setOf keyword):
+ The client OPTIONALLY supplies a set of attribute names and/or
+ attribute group names in whose values the requester is
+ interested. The Printer object MUST support this attribute.
+ If the client omits this attribute, the Printer MUST respond as
+ if this attribute had been supplied with a value of 'all'.
+
+ "document-format" (mimeMediaType):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. This attribute is useful
+ for a Printer object to determine the set of supported
+ attribute values that relate to the requested document format.
+ The Printer object MUST return the attributes and values that
+
+
+
+Hastings, et al. Standards Track [Page 51]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ it uses to validate a job on a create or Validate-Job operation
+ in which this document format is supplied. The Printer object
+ SHOULD return only (1) those attributes that are supported for
+ the specified format and (2) the attribute values that are
+ supported for the specified document format. By specifying the
+ document format, the client can get the Printer object to
+ eliminate the attributes and values that are not supported for
+ a specific document format. For example, a Printer object
+ might have multiple interpreters to support both
+ 'application/postscript' (for PostScript) and 'text/plain' (for
+ text) documents. However, for only one of those interpreters
+ might the Printer object be able to support "number-up" with
+ values of '1', '2', and '4'. For the other interpreter it
+ might be able to only support "number-up" with a value of '1'.
+ Thus a client can use the Get-Printer-Attributes operation to
+ obtain the attributes and values that will be used to
+ accept/reject a create job operation.
+
+ If the Printer object does not distinguish between different
+ sets of supported values for each different document format
+ when validating jobs in the create and Validate-Job operations,
+ it MUST NOT distinguish between different document formats in
+ the Get-Printer-Attributes operation. If the Printer object
+ does distinguish between different sets of supported values for
+ each different document format specified by the client, this
+ specialization applies only to the following Printer object
+ attributes:
+
+ - Printer attributes that are Job Template attributes ("xxx-
+ default" "xxx-supported", and "xxx-ready" in the Table in
+ Section 4.2),
+ - "pdl-override-supported",
+ - "compression-supported",
+ - "job-k-octets-supported",
+ - "job-impressions-supported",
+ - "job-media-sheets-supported",
+ - "printer-driver-installer",
+ - "color-supported", and
+ - "reference-uri-schemes-supported"
+
+ The values of all other Printer object attributes (including
+ "document-format-supported") remain invariant with respect to the
+ client supplied document format (except for new Printer
+ description attribute as registered according to section 6.2).
+
+ If the client omits this "document-format" operation attribute,
+ the Printer object MUST respond as if the attribute had been
+ supplied with the value of the Printer object's "document-format-
+
+
+
+Hastings, et al. Standards Track [Page 52]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ default" attribute. It is RECOMMENDED that the client always
+ supply a value for "document-format", since the Printer object's
+ "document-format-default" may be 'application/octet-stream', in
+ which case the returned attributes and values are for the union of
+ the document formats that the Printer can automatically sense.
+ For more details, see the description of the 'mimeMediaType'
+ attribute syntax in section 4.1.9.
+
+ If the client supplies a value for the "document-format" Operation
+ attribute that is not supported by the Printer, i.e., is not among
+ the values of the Printer object's "document-format-supported"
+ attribute, the Printer object MUST reject the operation and return
+ the 'client-error-document-format-not-supported' status code.
+
+3.2.5.2 Get-Printer-Attributes Response
+
+ The Printer object returns the following sets of attributes as part
+ of the Get-Printer-Attributes Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in sections 13 and 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See section 3.1.7 for details on returning Unsupported Attributes.
+
+ The response NEED NOT contain the "requested-attributes" operation
+ attribute with any supplied values (attribute keywords) that were
+ requested by the client but are not supported by the IPP object.
+ If the Printer object does return unsupported attributes
+ referenced in the "requested-attributes" operation attribute and
+ that attribute included group names, such as 'all', the
+ unsupported attributes MUST NOT include attributes described in
+ the standard but not supported by the implementation.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 53]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Group 3: Printer Object Attributes
+
+ This is the set of requested attributes and their current values.
+ The Printer object ignores (does not respond with) any requested
+ attribute which is not supported. The Printer object MAY respond
+ with a subset of the supported attributes and values, depending on
+ the security policy in force. However, the Printer object MUST
+ respond with the 'unknown' value for any supported attribute
+ (including all REQUIRED attributes) for which the Printer object
+ does not know the value. Also the Printer object MUST respond
+ with the 'no-value' for any supported attribute (including all
+ REQUIRED attributes) for which the system administrator has not
+ configured a value. See the description of the "out-of-band"
+ values in the beginning of Section 4.1.
+
+3.2.6 Get-Jobs Operation
+
+ This REQUIRED operation allows a client to retrieve the list of Job
+ objects belonging to the target Printer object. The client may also
+ supply a list of Job attribute names and/or attribute group names. A
+ group of Job object attributes will be returned for each Job object
+ that is returned.
+
+ This operation is similar to the Get-Job-Attributes operation, except
+ that this Get-Jobs operation returns attributes from possibly more
+ than one object.
+
+3.2.6.1 Get-Jobs Request
+
+ The client submits the Get-Jobs request to a Printer object.
+
+ The following groups of attributes are part of the Get-Jobs Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1.
+
+ Target:
+ The "printer-uri" (uri) operation attribute which is the target
+ for this operation as described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 54]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ "limit" (integer(1:MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It is an integer value that
+ determines the maximum number of jobs that a client will
+ receive from the Printer even if "which-jobs" or "my-jobs"
+ constrain which jobs are returned. The limit is a "stateless
+ limit" in that if the value supplied by the client is 'N', then
+ only the first 'N' jobs are returned in the Get-Jobs Response.
+ There is no mechanism to allow for the next 'M' jobs after the
+ first 'N' jobs. If the client does not supply this attribute,
+ the Printer object responds with all applicable jobs.
+
+ "requested-attributes" (1setOf type2 keyword):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It is a set of Job
+ attribute names and/or attribute groups names in whose values
+ the requester is interested. This set of attributes is
+ returned for each Job object that is returned. The allowed
+ attribute group names are the same as those defined in the
+ Get-Job-Attributes operation in section 3.3.4. If the client
+ does not supply this attribute, the Printer MUST respond as if
+ the client had supplied this attribute with two values: 'job-
+ uri' and 'job-id'.
+
+ "which-jobs" (type2 keyword):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It indicates which Job
+ objects MUST be returned by the Printer object. The values for
+ this attribute are:
+
+ 'completed': This includes any Job object whose state is
+ 'completed', 'canceled', or 'aborted'.
+ 'not-completed': This includes any Job object whose state is
+ 'pending', 'processing', 'processing-stopped', or 'pending-
+ held'.
+
+ A Printer object MUST support both values. However, if the
+ implementation does not keep jobs in the 'completed',
+ 'canceled', and 'aborted' states, then it returns no jobs when
+ the 'completed' value is supplied.
+
+ If a client supplies some other value, the Printer object MUST
+ copy the attribute and the unsupported value to the Unsupported
+ Attributes response group, reject the request, and return the
+ 'client-error-attributes-or-values-not-supported' status code.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 55]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ If the client does not supply this attribute, the Printer
+ object MUST respond as if the client had supplied the attribute
+ with a value of 'not-completed'.
+
+ "my-jobs" (boolean):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It indicates whether jobs
+ from all users or just the jobs submitted by the requesting
+ user of this request MUST be considered as candidate jobs to be
+ returned by the Printer object. If the client does not supply
+ this attribute, the Printer object MUST respond as if the
+ client had supplied the attribute with a value of 'false',
+ i.e., jobs from all users. The means for authenticating the
+ requesting user and matching the jobs is described in section
+ 8.
+
+3.2.6.2 Get-Jobs Response
+
+ The Printer object returns all of the Job objects up to the number
+ specified by the "limit" attribute that match the criteria as defined
+ by the attribute values supplied by the client in the request. It is
+ possible that no Job objects are returned since there may literally
+ be no Job objects at the Printer, or there may be no Job objects that
+ match the criteria supplied by the client. If the client requests
+ any Job attributes at all, there is a set of Job Object Attributes
+ returned for each Job object.
+
+ It is not an error for the Printer to return 0 jobs. If the response
+ returns 0 jobs because there are no jobs matching the criteria, and
+ the request would have returned 1 or more jobs with a status code of
+ 'successful-ok' if there had been jobs matching the criteria, then
+ the status code for 0 jobs MUST be 'successful-ok'.
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in sections 13 and 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 56]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Group 2: Unsupported Attributes
+
+ See section 3.1.7 for details on returning Unsupported Attributes.
+
+ The response NEED NOT contain the "requested-attributes" operation
+ attribute with any supplied values (attribute keywords) that were
+ requested by the client but are not supported by the IPP object.
+ If the Printer object does return unsupported attributes
+ referenced in the "requested-attributes" operation attribute and
+ that attribute included group names, such as 'all', the
+ unsupported attributes MUST NOT include attributes described in
+ the standard but not supported by the implementation.
+
+ Groups 3 to N: Job Object Attributes
+
+ The Printer object responds with one set of Job Object Attributes
+ for each returned Job object. The Printer object ignores (does
+ not respond with) any requested attribute or value which is not
+ supported or which is restricted by the security policy in force,
+ including whether the requesting user is the user that submitted
+ the job (job originating user) or not (see section 8). However,
+ the Printer object MUST respond with the 'unknown' value for any
+ supported attribute (including all REQUIRED attributes) for which
+ the Printer object does not know the value, unless it would
+ violate the security policy. See the description of the "out-of-
+ band" values in the beginning of Section 4.1.
+
+ Jobs are returned in the following order:
+
+ - If the client requests all 'completed' Jobs (Jobs in the
+ 'completed', 'aborted', or 'canceled' states), then the Jobs are
+ returned newest to oldest (with respect to actual completion
+ time)
+ - If the client requests all 'not-completed' Jobs (Jobs in the
+ 'pending', 'processing', 'pending-held', and 'processing-
+ stopped' states), then Jobs are returned in relative
+ chronological order of expected time to complete (based on
+ whatever scheduling algorithm is configured for the Printer
+ object).
+
+3.2.7 Pause-Printer Operation
+
+ This OPTIONAL operation allows a client to stop the Printer object
+ from scheduling jobs on all its devices. Depending on
+ implementation, the Pause-Printer operation MAY also stop the Printer
+ from processing the current job or jobs. Any job that is currently
+ being printed is either stopped as soon as the implementation permits
+
+
+
+
+Hastings, et al. Standards Track [Page 57]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ or is completed, depending on implementation. The Printer object
+ MUST still accept create operations to create new jobs, but MUST
+ prevent any jobs from entering the 'processing' state.
+
+ If the Pause-Printer operation is supported, then the Resume-Printer
+ operation MUST be supported, and vice-versa.
+
+ The IPP Printer stops the current job(s) on its device(s) that were
+ in the 'processing' or 'processing-stopped' states as soon as the
+ implementation permits. If the implementation will take appreciable
+ time to stop, the IPP Printer adds the 'moving-to-paused' value to
+ the Printer object's "printer-state-reasons" attribute (see section
+ 4.4.12). When the device(s) have all stopped, the IPP Printer
+ transitions the Printer object to the 'stopped' state, removes the
+ 'moving-to-paused' value, if present, and adds the 'paused' value to
+ the Printer object's "printer-state-reasons" attribute.
+
+ When the current job(s) complete that were in the 'processing' state,
+ the IPP Printer transitions them to the 'completed' state. When the
+ current job(s) stop in mid processing that were in the 'processing'
+ state, the IPP Printer transitions them to the 'processing-stopped'
+ state and adds the 'printer-stopped' value to the job's "job-state-
+ reasons" attribute.
+
+ For any jobs that are 'pending' or 'pending-held', the 'printer-
+ stopped' value of the jobs' "job-state-reasons" attribute also
+ applies. However, the IPP Printer NEED NOT update those jobs' "job-
+ state-reasons" attributes and only need return the 'printer-stopped'
+ value when those jobs are queried (so-called "lazy evaluation").
+
+ Whether the Pause-Printer operation affects jobs that were submitted
+ to the device from other sources than the IPP Printer object in the
+ same way that the Pause-Printer operation affects jobs that were
+ submitted to the IPP Printer object using IPP, depends on
+ implementation, i.e., on whether the IPP protocol is being used as a
+ universal management protocol or just to manage IPP jobs,
+ respectively.
+
+ The IPP Printer MUST accept the request in any state and transition
+ the Printer to the indicated new "printer-state" before returning as
+ follows:
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 58]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Current New "printer IPP Printer's response status
+ "printer- "printer- -state- code and action:
+ state" state" reasons"
+
+ 'idle' 'stopped' 'paused' 'successful-ok'
+ 'processing' 'processing' 'moving- OPTION 1: 'successful-ok';
+ to- Later, when all output has
+ paused' stopped, the "printer-state"
+ becomes 'stopped', and the
+ 'paused' value replaces the
+ 'moving-to-paused' value in the
+ "printer-state-reasons"
+ attribute
+ 'processing' 'stopped' 'paused' OPTION 2: 'successful-ok';
+ all device output stopped
+ immediately
+ 'stopped' 'stopped' 'paused' 'successful-ok'
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must be an operator or administrator of the Printer
+ object (see Sections 1 and 8.5). Otherwise, the IPP Printer MUST
+ reject the operation and return: 'client-error-forbidden', 'client-
+ error-not-authenticated', or 'client-error-not-authorized' as
+ appropriate.
+
+3.2.7.1 Pause-Printer Request
+
+ The following groups of attributes are part of the Pause-Printer
+ Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1.
+
+ Target:
+ The "printer-uri" (uri) operation attribute which is the target
+ for this operation as described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 59]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.2.7.2 Pause-Printer Response
+
+ The following groups of attributes are part of the Pause-Printer
+ Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in sections 13 and 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See section 3.1.7 for details on returning Unsupported Attributes.
+
+3.2.8 Resume-Printer Operation
+
+ This operation allows a client to resume the Printer object
+ scheduling jobs on all its devices. The Printer object MUST remove
+ the 'paused' and 'moving-to-paused' values from the Printer object's
+ "printer-state-reasons" attribute, if present. If there are no other
+ reasons to keep a device paused (such as media-jam), the IPP Printer
+ is free to transition itself to the 'processing' or 'idle' states,
+ depending on whether there are jobs to be processed or not,
+ respectively, and the device(s) resume processing jobs.
+
+ If the Pause-Printer operation is supported, then the Resume-Printer
+ operation MUST be supported, and vice-versa.
+
+ The IPP Printer removes the 'printer-stopped' value from any job's
+ "job-state-reasons" attributes contained in that Printer.
+
+ The IPP Printer MUST accept the request in any state, transition the
+ Printer object to the indicated new state as follows:
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 60]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Current New "printer- IPP Printer's response status code and
+ "printer- state" action:
+ state"
+
+ 'idle' 'idle' 'successful-ok'
+ 'processing' 'processing' 'successful-ok'
+
+ 'stopped' 'processing' 'successful-ok';
+ when there are jobs to be processed
+ 'stopped' 'idle' 'successful-ok';
+ when there are no jobs to be processed.
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must be an operator or administrator of the Printer
+ object (see Sections 1 and 8.5). Otherwise, the IPP Printer MUST
+ reject the operation and return: 'client-error-forbidden', 'client-
+ error-not-authenticated', or 'client-error-not-authorized' as
+ appropriate.
+
+ The Resume-Printer Request and Resume-Printer Response have the same
+ attribute groups and attributes as the Pause-Printer operation (see
+ sections 3.2.7.1 and 3.2.7.2).
+
+3.2.9 Purge-Jobs Operation
+
+ This OPTIONAL operation allows a client to remove all jobs from an
+ IPP Printer object, regardless of their job states, including jobs in
+ the Printer object's Job History (see Section 4.3.7.2). After a
+ Purge-Jobs operation has been performed, a Printer object MUST return
+ no jobs in subsequent Get-Job-Attributes and Get-Jobs responses
+ (until new jobs are submitted).
+
+ Whether the Purge-Jobs (and Get-Jobs) operation affects jobs that
+ were submitted to the device from other sources than the IPP Printer
+ object in the same way that the Purge-Jobs operation affects jobs
+ that were submitted to the IPP Printer object using IPP, depends on
+ implementation, i.e., on whether the IPP protocol is being used as a
+ universal management protocol or just to manage IPP jobs,
+ respectively.
+
+ Note: if an operator wants to cancel all jobs without clearing out
+ the Job History, the operator uses the Cancel-Job operation on each
+ job instead of using the Purge-Jobs operation.
+
+ The Printer object MUST accept this operation in any state and
+ transition the Printer object to the 'idle' state.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 61]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must be an operator or administrator of the Printer
+ object (see Sections 1 and 8.5). Otherwise, the IPP object MUST
+ reject the operation and return: client-error-forbidden, client-
+ error-not-authenticated, and client-error-not-authorized as
+ appropriate.
+
+ The Purge-Jobs Request and Purge-Jobs Response have the same
+ attribute groups and attributes as the Pause-Printer operation (see
+ sections 3.2.7.1 and 3.2.7.2).
+
+3.3 Job Operations
+
+ All Job operations are directed at Job objects. A client MUST always
+ supply some means of identifying the Job object in order to identify
+ the correct target of the operation. That job identification MAY
+ either be a single Job URI or a combination of a Printer URI with a
+ Job ID. The IPP object implementation MUST support both forms of
+ identification for every job.
+
+3.3.1 Send-Document Operation
+
+ This OPTIONAL operation allows a client to create a multi-document
+ Job object that is initially "empty" (contains no documents). In the
+ Create-Job response, the Printer object returns the Job object's URI
+ (the "job-uri" attribute) and the Job object's 32-bit identifier (the
+ "job-id" attribute). For each new document that the client desires
+ to add, the client uses a Send-Document operation. Each Send-
+ Document Request contains the entire stream of document data for one
+ document.
+
+ If the Printer supports this operation but does not support multiple
+ documents per job, the Printer MUST reject subsequent Send-Document
+ operations supplied with data and return the 'server-error-multiple-
+ document-jobs-not-supported'. However, the Printer MUST accept the
+ first document with a 'true' or 'false' value for the "last-document"
+ operation attribute (see below), so that clients MAY always submit
+ one document jobs with a 'false' value for "last-document" in the
+ first Send-Document and a 'true' for "last-document" in the second
+ Send-Document (with no data).
+
+ Since the Create-Job and the send operations (Send-Document or Send-
+ URI operations) that follow could occur over an arbitrarily long
+ period of time for a particular job, a client MUST send another send
+ operation within an IPP Printer defined minimum time interval after
+ the receipt of the previous request for the job. If a Printer object
+ supports the Create-Job and Send-Document operations, the Printer
+ object MUST support the "multiple-operation-time-out" attribute (see
+
+
+
+Hastings, et al. Standards Track [Page 62]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ section 4.4.31). This attribute indicates the minimum number of
+ seconds the Printer object will wait for the next send operation
+ before taking some recovery action.
+
+ An IPP object MUST recover from an errant client that does not supply
+ a send operation, sometime after the minimum time interval specified
+ by the Printer object's "multiple-operation-time-out" attribute.
+ Such recovery MAY include any of the following or other recovery
+ actions:
+
+ 1. Assume that the Job is an invalid job, start the process of
+ changing the job state to 'aborted', add the 'aborted-by-
+ system' value to the job's "job-state-reasons" attribute (see
+ section 4.3.8), and clean up all resources associated with the
+ Job. In this case, if another send operation is finally
+ received, the Printer responds with an "client-error-not-
+ possible" or "client-error-not-found" depending on whether or
+ not the Job object is still around when the send operation
+ finally arrives.
+ 2. Assume that the last send operation received was in fact the
+ last document (as if the "last-document" flag had been set to
+ 'true'), close the Job object, and proceed to process it (i.e.,
+ move the Job's state to 'pending').
+ 3. Assume that the last send operation received was in fact the
+ last document, close the Job, but move it to the 'pending-held'
+ and add the 'submission-interrupted' value to the job's "job-
+ state-reasons" attribute (see section 4.3.8). This action
+ allows the user or an operator to determine whether to continue
+ processing the Job by moving it back to the 'pending' state
+ using the Release-Job operation (see section 3.3.6) or to
+ cancel the job using the Cancel-Job operation (see section
+ 3.3.3).
+
+ Each implementation is free to decide the "best" action to take
+ depending on local policy, whether any documents have been added,
+ whether the implementation spools jobs or not, and/or any other
+ piece of information available to it. If the choice is to abort the
+ Job object, it is possible that the Job object may already have been
+ processed to the point that some media sheet pages have been printed.
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must either be the job owner (as determined in the
+ Create-Job operation) or an operator or administrator of the Printer
+ object (see Sections 1 and 8.5). Otherwise, the IPP object MUST
+ reject the operation and return: 'client-error-forbidden', 'client-
+ error-not-authenticated', or 'client-error-not-authorized' as
+ appropriate.
+
+
+
+
+Hastings, et al. Standards Track [Page 63]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.3.1.1 Send-Document Request
+
+ The following attribute sets are part of the Send-Document Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1.
+
+ Target:
+ Either (1) the "printer-uri" (uri) plus "job-id"
+ (integer(1:MAX))or (2) the "job-uri" (uri) operation
+ attribute(s) which define the target for this operation as
+ described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "document-name" (name(MAX)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. It contains the client
+ supplied document name. The document name MAY be different than
+ the Job name. It might be helpful, but NEED NOT be unique
+ across multiple documents in the same Job. Typically, the
+ client software automatically supplies the document name on
+ behalf of the end user by using a file name or an application
+ generated name. See the description of the "document-name"
+ operation attribute in the Print-Job Request (section 3.2.1.1)
+ for more information about this attribute.
+
+ "compression" (type3 keyword):
+ See the description of "compression" for the Print-Job operation
+ in Section 3.2.1.1.
+
+ "document-format" (mimeMediaType):
+ See the description of "document-format" for the Print-Job
+ operation in Section 3.2.1.1.
+
+ "document-natural-language" (naturalLanguage):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute. This attribute
+ specifies the natural language of the document for those
+ document-formats that require a specification of the natural
+ language in order to image the document unambiguously. There
+ are no particular values required for the Printer object to
+ support.
+
+
+
+Hastings, et al. Standards Track [Page 64]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ "last-document" (boolean):
+ The client MUST supply this attribute. The Printer object MUST
+ support this attribute. It is a boolean flag that is set to
+ 'true' if this is the last document for the Job, 'false'
+ otherwise.
+
+ Group 2: Document Content
+
+ The client MUST supply the document data if the "last-document"
+ flag is set to 'false'. However, since a client might not know
+ that the previous document sent with a Send-Document (or Send-URI)
+ operation was the last document (i.e., the "last-document"
+ attribute was set to 'false'), it is legal to send a Send-Document
+ request with no document data where the "last-document" flag is
+ set to 'true'. Such a request MUST NOT increment the value of the
+ Job object's "number-of-documents" attribute, since no real
+ document was added to the job. It is not an error for a client to
+ submit a job with no actual document data, i.e., only a single
+ Create-Job and Send-Document request with a "last-document"
+ operation attribute set to 'true' with no document data.
+
+3.3.1.2 Send-Document Response
+
+ The following sets of attributes are part of the Send-Document
+ Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in sections 13 and 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See section 3.1.7 for details on returning Unsupported Attributes.
+
+ Group 3: Job Object Attributes
+
+ This is the same set of attributes as described in the Print-Job
+ response (see section 3.2.1.2).
+
+
+
+
+
+Hastings, et al. Standards Track [Page 65]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.3.2 Send-URI Operation
+
+ This OPTIONAL operation is identical to the Send-Document operation
+ (see section 3.3.1) except that a client MUST supply a URI reference
+ ("document-uri" operation attribute) rather than the document data
+ itself. If a Printer object supports this operation, clients can use
+ both Send-URI or Send-Document operations to add new documents to an
+ existing multi-document Job object. However, if a client needs to
+ indicate that the previous Send-URI or Send-Document was the last
+ document, the client MUST use the Send-Document operation with no
+ document data and the "last-document" flag set to 'true' (rather than
+ using a Send-URI operation with no "document-uri" operation
+ attribute).
+
+ If a Printer object supports this operation, it MUST also support the
+ Print-URI operation (see section 3.2.2).
+
+ The Printer object MUST validate the syntax and URI scheme of the
+ supplied URI before returning a response, just as in the Print-URI
+ operation. The IPP Printer MAY validate the accessibility of the
+ document as part of the operation or subsequently (see section
+ 3.2.2).
+
+3.3.3 Cancel-Job Operation
+
+ This REQUIRED operation allows a client to cancel a Print Job from
+ the time the job is created up to the time it is completed, canceled,
+ or aborted. Since a Job might already be printing by the time a
+ Cancel-Job is received, some media sheet pages might be printed
+ before the job is actually terminated.
+
+ The IPP object MUST accept or reject the request based on the job's
+ current state and transition the job to the indicated new state as
+ follows:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 66]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Current "job- New "job- IPP object's response status
+ state" state" code and action:
+
+ 'pending' 'canceled' 'successful-ok'
+ 'pending-held' 'canceled' 'successful-ok'
+ 'processing' 'canceled' 'successful-ok'
+ 'processing' 'processing' 'successful-ok' See Rule 1
+ 'processing' 'processing' 'client-error-not-possible'
+ See Rule 2
+ 'processing- 'canceled' 'successful-ok'
+ stopped'
+ 'processing- 'processing- 'successful-ok' See Rule 1
+ stopped' stopped'
+ 'processing- 'processing- 'client-error-not-possible'
+ stopped' stopped' See Rule 2
+ 'completed' 'completed' 'client-error-not-possible'
+ 'canceled' 'canceled' 'client-error-not-possible'
+ 'aborted' 'aborted' 'client-error-not-possible'
+
+ Rule 1: If the implementation requires some measurable time to
+ cancel the job in the 'processing' or 'processing-stopped' job
+ states, the IPP object MUST add the 'processing-to-stop-point' value
+ to the job's "job-state-reasons" attribute and then transition the
+ job to the 'canceled' state when the processing ceases (see section
+ 4.3.8).
+
+ Rule 2: If the Job object already has the 'processing-to-stop-point'
+ value in its "job-state-reasons" attribute, then the Printer object
+ MUST reject a Cancel-Job operation.
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must either be the job owner or an operator or
+ administrator of the Printer object (see Sections 1 and 8.5).
+ Otherwise, the IPP object MUST reject the operation and return:
+ 'client-error-forbidden', 'client-error-not-authenticated', or
+ 'client-error-not-authorized' as appropriate.
+
+3.3.3.1 Cancel-Job Request
+
+ The following groups of attributes are part of the Cancel-Job
+ Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1.
+
+
+
+
+Hastings, et al. Standards Track [Page 67]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Target:
+ Either (1) the "printer-uri" (uri) plus "job-id"
+ (integer(1:MAX))or (2) the "job-uri" (uri) operation
+ attribute(s) which define the target for this operation as
+ described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "message" (text(127)):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object OPTIONALLY supports this attribute. It is a message to
+ the operator. This "message" attribute is not the same as the
+ "job-message-from-operator" attribute. That attribute is used
+ to report a message from the operator to the end user that
+ queries that attribute. This "message" operation attribute is
+ used to send a message from the client to the operator along
+ with the operation request. It is an implementation decision
+ of how or where to display this message to the operator (if at
+ all).
+
+3.3.3.2 Cancel-Job Response
+
+ The following sets of attributes are part of the Cancel-Job Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in sections 13 and 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See section 3.1.7 for details on returning Unsupported Attributes.
+
+ Once a successful response has been sent, the implementation
+ guarantees that the Job will eventually end up in the 'canceled'
+ state. Between the time of the Cancel-Job operation is accepted and
+ when the job enters the 'canceled' job-state (see section 4.3.7), the
+ "job-state-reasons" attribute SHOULD contain the 'processing-to-
+ stop-point'
+
+
+
+Hastings, et al. Standards Track [Page 68]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ value which indicates to later queries that although the Job might
+ still be 'processing', it will eventually end up in the
+ 'canceled' state, not the 'completed' state.
+
+3.3.4 Get-Job-Attributes Operation
+
+ This REQUIRED operation allows a client to request the values of
+ attributes of a Job object and it is almost identical to the Get-
+ Printer-Attributes operation (see section 3.2.5). The only
+ differences are that the operation is directed at a Job object rather
+ than a Printer object, there is no "document-format" operation
+ attribute used when querying a Job object, and the returned attribute
+ group is a set of Job object attributes rather than a set of Printer
+ object attributes.
+
+ For Jobs, the possible names of attribute groups are:
+
+ - 'job-template': the subset of the Job Template attributes that
+ apply to a Job object (the first column of the table in Section
+ 4.2) that the implementation supports for Job objects.
+ - 'job-description': the subset of the Job Description attributes
+ specified in Section 4.3 that the implementation supports for
+ Job objects.
+ - 'all': the special group 'all' that includes all attributes that
+ the implementation supports for Job objects.
+
+ Since a client MAY request specific attributes or named groups, there
+ is a potential that there is some overlap. For example, if a client
+ requests, 'job-name' and 'job-description', the client is actually
+ requesting the "job-name" attribute once by naming it explicitly, and
+ once by inclusion in the 'job-description' group. In such cases, the
+ Printer object NEED NOT return the attribute only once in the
+ response even if it is requested multiple times. The client SHOULD
+ NOT request the same attribute in multiple ways.
+
+ It is NOT REQUIRED that a Job object support all attributes belonging
+ to a group (since some attributes are OPTIONAL). However it is
+ REQUIRED that each Job object support all these group names.
+
+3.3.4.1 Get-Job-Attributes Request
+
+ The following groups of attributes are part of the Get-Job-Attributes
+ Request when the request is directed at a Job object:
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 69]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1.
+
+ Target:
+ Either (1) the "printer-uri" (uri) plus "job-id"
+ (integer(1:MAX)) or (2) the "job-uri" (uri) operation
+ attribute(s) which define the target for this operation as
+ described in section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in section 8.3.
+
+ "requested-attributes" (1setOf keyword):
+ The client OPTIONALLY supplies this attribute. The IPP object
+ MUST support this attribute. It is a set of attribute names
+ and/or attribute group names in whose values the requester is
+ interested. If the client omits this attribute, the IPP object
+ MUST respond as if this attribute had been supplied with a value
+ of 'all'.
+
+3.3.4.2 Get-Job-Attributes Response
+
+ The Printer object returns the following sets of attributes as part
+ of the Get-Job-Attributes Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in sections 13 and 3.1.6.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2. The "attributes-
+ natural-language" MAY be the natural language of the Job
+ object, rather than the one requested.
+
+ Group 2: Unsupported Attributes
+
+ See section 3.1.7 for details on returning Unsupported Attributes.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 70]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The response NEED NOT contain the "requested-attributes" operation
+ attribute with any supplied values (attribute keywords) that were
+ requested by the client but are not supported by the IPP object.
+ If the Printer object does return unsupported attributes
+ referenced in the "requested-attributes" operation attribute and
+ that attribute included group names, such as 'all', the
+ unsupported attributes MUST NOT include attributes described in
+ the standard but not supported by the implementation.
+
+ Group 3: Job Object Attributes
+
+ This is the set of requested attributes and their current values.
+ The IPP object ignores (does not respond with) any requested
+ attribute or value which is not supported or which is restricted
+ by the security policy in force, including whether the requesting
+ user is the user that submitted the job (job originating user) or
+ not (see section 8). However, the IPP object MUST respond with
+ the 'unknown' value for any supported attribute (including all
+ REQUIRED attributes) for which the IPP object does not know the
+ value, unless it would violate the security policy. See the
+ description of the "out-of-band" values in the beginning of
+ Section 4.1.
+
+3.3.5 Hold-Job Operation
+
+ This OPTIONAL operation allows a client to hold a pending job in the
+ queue so that it is not eligible for scheduling. If the Hold-Job
+ operation is supported, then the Release-Job operation MUST be
+ supported, and vice-versa. The OPTIONAL "job-hold-until" operation
+ attribute allows a client to specify whether to hold the job
+ indefinitely or until a specified time period, if supported.
+
+ The IPP object MUST accept or reject the request based on the job's
+ current state and transition the job to the indicated new state as
+ follows:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 71]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Current "job- New "job-state" IPP object's response status
+ state" code and action:
+
+ 'pending' 'pending-held' 'successful-ok' See Rule 1
+ 'pending' 'pending' 'successful-ok' See Rule 2
+ 'pending-held' 'pending-held' 'successful-ok' See Rule 1
+ 'pending-held' 'pending' 'successful-ok' See Rule 2
+ 'processing' 'processing' 'client-error-not-possible'
+ 'processing- 'processing- 'client-error-not-possible'
+ stopped' stopped'
+ 'completed' 'completed' 'client-error-not-possible'
+ 'canceled' 'canceled' 'client-error-not-possible'
+ 'aborted' 'aborted' 'client-error-not-possible'
+
+ Rule 1: If the implementation supports multiple reasons for a job to
+ be in the 'pending-held' state, the IPP object MUST add the 'job-
+ hold-until-specified' value to the job's "job-state-reasons"
+ attribute.
+
+ Rule 2: If the IPP object supports the "job-hold-until" operation
+ attribute, but the specified time period has already started (or is
+ the 'no-hold' value) and there are no other reasons to hold the job,
+ the IPP object MUST make the job be a candidate for processing
+ immediately (see Section 4.2.2) by putting the job in the 'pending'
+ state.
+
+ Note: In order to keep the Hold-Job operation simple, such a request
+ is rejected when the job is in the 'processing' or 'processing-
+ stopped' states. If an operation is needed to hold jobs while in
+ these states, it will be added as an additional operation, rather
+ than overloading the Hold-Job operation. Then it is clear to clients
+ by querying the Printer object's "operations-supported" (see Section
+ 4.4.15) and the Job object's "job-state" (see Section 4.3.7)
+ attributes which operations are possible.
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must either be the job owner or an operator or
+ administrator of the Printer object (see Sections 1 and 8.5).
+ Otherwise, the IPP object MUST reject the operation and return:
+ 'client-error-forbidden', 'client-error-not-authenticated', or
+ 'client-error-not-authorized' as appropriate.
+
+3.3.5.1 Hold-Job Request
+
+ The groups and operation attributes are the same as for a Cancel-Job
+ request (see section 3.3.3.1), with the addition of the following
+ Group 1 Operation attribute:
+
+
+
+
+Hastings, et al. Standards Track [Page 72]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ "job-hold-until" (type3 keyword | name(MAX)):
+ The client OPTIONALLY supplies this Operation attribute. The
+ IPP object MUST support this operation attribute in a Hold-Job
+ request, if it supports the "job-hold-until" Job template
+ attribute in create operations. See section 4.2.2. The IPP
+ object SHOULD support the "job-hold-until" Job Template
+ attribute for use in job create operations with at least the
+ 'indefinite' value, if it supports the Hold-Job operation.
+ Otherwise, a client cannot create a job and hold it immediately
+ (without picking some supported time period in the future).
+
+ If supplied and supported as specified in the Printer's "job-
+ hold-until-supported" attribute, the IPP object copies the
+ supplied operation attribute to the Job object, replacing the
+ job's previous "job-hold-until" attribute, if present, and
+ makes the job a candidate for scheduling during the supplied
+ named time period.
+
+ If supplied, but either the "job-hold-until" Operation
+ attribute itself or the value supplied is not supported, the
+ IPP object accepts the request, returns the unsupported
+ attribute or value in the Unsupported Attributes Group
+ according to section 3.1.7, returns the 'successful-ok-
+ ignored-or-substituted-attributes, and holds the job
+ indefinitely until a client performs a subsequent Release-Job
+ operation.
+
+ If the client (1) supplies a value that specifies a time period
+ that has already started or the 'no-hold' value (meaning don't
+ hold the job) and (2) the IPP object supports the "job-hold-
+ until" operation attribute and there are no other reasons to
+ hold the job, the IPP object MUST accept the operation and make
+ the job be a candidate for processing immediately (see Section
+ 4.2.2).
+
+ If the client does not supply a "job-hold-until" Operation
+ attribute in the request, the IPP object MUST populate the job
+ object with a "job-hold-until" attribute with the 'indefinite'
+ value (if IPP object supports the "job-hold-until" attribute)
+ and hold the job indefinitely, until a client performs a
+ Release-Job operation.
+
+3.3.5.2 Hold-Job Response
+
+ The groups and attributes are the same as for a Cancel-Job response
+ (see section 3.3.3.2).
+
+
+
+
+
+Hastings, et al. Standards Track [Page 73]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.3.6 Release-Job Operation
+
+ This OPTIONAL operation allows a client to release a previously held
+ job so that it is again eligible for scheduling. If the Hold-Job
+ operation is supported, then the Release-Job operation MUST be
+ supported, and vice-versa.
+
+ This operation removes the "job-hold-until" job attribute, if
+ present, from the job object that had been supplied in the create or
+ most recent Hold-Job or Restart-Job operation and removes its effect
+ on the job. The IPP object MUST remove the 'job-hold-until-
+ specified' value from the job's "job-state-reasons" attribute, if
+ present. See section 4.3.8.
+
+ The IPP object MUST accept or reject the request based on the job's
+ current state and transition the job to the indicated new state as
+ follows:
+
+ Current "job- New "job-state" IPP object's response status
+ state" code and action:
+
+ 'pending' 'pending' 'successful-ok'
+ No effect on the job.
+ 'pending-held' 'pending-held' 'successful-ok' See Rule 1
+ 'pending-held' 'pending' 'successful-ok'
+ 'processing' 'processing' 'successful-ok'
+ No effect on the job.
+ 'processing- 'processing- 'successful-ok'
+ stopped' stopped' No effect on the job.
+ 'completed' 'completed' 'client-error-not-possible'
+ 'canceled' 'canceled' 'client-error-not-possible'
+ 'aborted' 'aborted' 'client-error-not-possible'
+
+ Rule 1: If there are other reasons to keep the job in the 'pending-
+ held' state, such as 'resources-are-not-ready', the job remains in
+ the 'pending-held' state. Thus the 'pending-held' state is not just
+ for jobs that have the 'job-hold-until' applied to them, but are for
+ any reason to keep the job from being a candidate for scheduling and
+ processing, such as 'resources-are-not-ready'. See the "job-hold-
+ until" attribute (section 4.2.2).
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must either be the job owner or an operator or
+ administrator of the Printer object (see Sections 1 and 8.5).
+ Otherwise, the IPP object MUST reject the operation and return:
+ 'client-error-forbidden', 'client-error-not-authenticated', or
+ 'client-error-not-authorized' as appropriate.
+
+
+
+
+Hastings, et al. Standards Track [Page 74]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The Release-Job Request and Release-Job Response have the same
+ attribute groups and attributes as the Cancel-Job operation (see
+ section 3.3.3.1 and 3.3.3.2).
+
+3.3.7 Restart-Job Operation
+
+ This OPTIONAL operation allows a client to restart a job that is
+ retained in the queue after processing has completed (see section
+ 4.3.7.2).
+
+ The job is moved to the 'pending' or 'pending-held' job state and
+ restarts at the beginning on the same IPP Printer object with the
+ same attribute values. If any of the documents in the job were
+ passed by reference (Print-URI or Send-URI), the Printer MUST re-
+ fetch the data, since the semantics of Restart-Job are to repeat all
+ Job processing. The Job Description attributes that accumulate job
+ progress, such as "job-impressions-completed", "job-media-sheets-
+ completed", and "job-k-octets-processed", MUST be reset to 0 so that
+ they give an accurate record of the job from its restart point. The
+ job object MUST continue to use the same "job-uri" and "job-id"
+ attribute values.
+
+ Note: If in the future an operation is needed that does not reset
+ the job progress attributes, then a new operation will be defined
+ which makes a copy of the job, assigns a new "job-uri" and "job-id"
+ to the copy and resets the job progress attributes in the new copy
+ only.
+
+ The IPP object MUST accept or reject the request based on the job's
+ current state, transition the job to the indicated new state as
+ follows:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 75]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Current "job- New "job-state" IPP object's response status
+ state" code and action:
+
+ 'pending' 'pending' 'client-error-not-possible'
+ 'pending-held' 'pending-held' 'client-error-not-possible'
+ 'processing' 'processing' 'client-error-not-possible'
+ 'processing- 'processing- 'client-error-not-possible'
+ stopped' stopped'
+ 'completed' 'pending' or 'successful-ok' - job is started
+ 'pending-held' over.
+ 'completed' 'completed' 'client-error-not-possible' -
+ see Rule 1
+ 'canceled' 'pending' or 'successful-ok' - job is started
+ 'pending-held' over.
+ 'canceled' 'canceled' 'client-error-not-possible' -
+ see Rule 1
+ 'aborted' 'pending' or 'successful-ok' - job is started
+ 'pending-held' over.
+ 'aborted' 'aborted' 'client-error-not-possible' -
+ see Rule 1
+
+ Rule 1: If the Job Retention Period has expired for the job in this
+ state, then the IPP object rejects the operation. See section
+ 4.3.7.2.
+
+ Note: In order to prevent a user from inadvertently restarting a job
+ in the middle, the Restart-Job request is rejected when the job is in
+ the 'processing' or 'processing-stopped' states. If in the future an
+ operation is needed to hold or restart jobs while in these states, it
+ will be added as an additional operation, rather than overloading the
+ Restart-Job operation, so that it is clear that the user intended
+ that the current job not be completed.
+
+ Access Rights: The authenticated user (see section 8.3) performing
+ this operation must either be the job owner or an operator or
+ administrator of the Printer object (see Sections 1 and 8.5).
+ Otherwise, the IPP object MUST reject the operation and return:
+ 'client-error-forbidden', 'client-error-not-authenticated', or
+ 'client-error-not-authorized' as appropriate.
+
+3.3.7.1 Restart-Job Request
+
+ The groups and attributes are the same as for a Cancel-Job request
+ (see section 3.3.3.1), with the addition of the following Group 1
+ Operation attribute:
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 76]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ "job-hold-until" (type3 keyword | name(MAX)):
+ The client OPTIONALLY supplies this attribute. The IPP object
+ MUST support this Operation attribute in a Restart-Job request,
+ if it supports the "job-hold-until" Job Template attribute in
+ create operations. See section 4.2.2. Otherwise, the IPP
+ object NEED NOT support the "job-hold-until" Operation
+ attribute in a Restart-Job request.
+
+ If supplied and supported as specified in the Printer's "job-
+ hold-until-supported" attribute, the IPP object copies the
+ supplied Operation attribute to the Job object, replacing the
+ job's previous "job-hold-until" attribute, if present, and
+ makes the job a candidate for scheduling during the supplied
+ named time period. See section 4.2.2.
+
+ If supplied, but the value is not supported, the IPP object
+ accepts the request, returns the unsupported attribute or value
+ in the Unsupported Attributes Group according to section 3.1.7,
+ returns the 'successful-ok-ignored-or-substituted-attributes'
+ status code, and holds the job indefinitely until a client
+ performs a subsequent Release-Job operation.
+
+ If supplied, but the "job-hold-until" Operation attribute
+ itself is not supported, the IPP object accepts the request,
+ returns the unsupported attribute with the out-of-band
+ 'unsupported' value in the Unsupported Attributes Group
+ according to section 3.1.7, returns the 'successful-ok-
+ ignored-or-substituted-attributes' status code, and restarts
+ the job, i.e., ignores the "job-hold-until" attribute.
+
+ If the client (1) supplies a value that specifies a time period
+ that has already started or the 'no-hold' value (meaning don't
+ hold the job) and (2) the IPP object supports the "job-hold-
+ until" operation attribute and there are no other reasons to
+ hold the job, the IPP object makes the job a candidate for
+ processing immediately (see Section 4.2.2).
+
+ If the client does not supply a "job-hold-until" operation
+ attribute in the request, the IPP object removes the "job-
+ hold-until" attribute, if present, from the job. If there are
+ no other reasons to hold the job, the Restart-Job operation
+ makes the job a candidate for processing immediately (see
+ Section 4.2.2).
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 77]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+3.3.7.2 Restart-Job Response
+
+ The groups and attributes are the same as for a Cancel-Job response
+ (see section 3.3.3.2).
+
+ Note: In the future an OPTIONAL Modify-Job or Set-Job-Attributes
+ operation may be specified that allows the client to modify other
+ attributes before releasing the restarted job.
+
+4. Object Attributes
+
+ This section describes the attributes with their corresponding
+ attribute syntaxes and values that are part of the IPP model. The
+ sections below show the objects and their associated attributes which
+ are included within the scope of this protocol. Many of these
+ attributes are derived from other relevant documents:
+
+ - Document Printing Application (DPA) [ISO10175]
+ - RFC 1759 Printer MIB [RFC1759]
+
+ Each attribute is uniquely identified in this document using a
+ "keyword" (see section 12.2.1) which is the name of the attribute.
+ The keyword is included in the section header describing that
+ attribute.
+
+ Note: Not only are keywords used to identify attributes, but one of
+ the attribute syntaxes described below is "keyword" so that some
+ attributes have keyword values. Therefore, these attributes are
+ defined as having an attribute syntax that is a set of keywords.
+
+4.1 Attribute Syntaxes
+
+ This section defines the basic attribute syntax types that all
+ clients and IPP objects MUST be able to accept in responses and
+ accept in requests, respectively. Each attribute description in
+ sections 3 and 4 includes the name of attribute syntax(es) in the
+ heading (in parentheses). A conforming implementation of an
+ attribute MUST include the semantics of the attribute syntax(es) so
+ identified. Section 6.3 describes how the protocol can be extended
+ with new attribute syntaxes.
+
+ The attribute syntaxes are specified in the following sub-sections,
+ where the sub-section heading is the keyword name of the attribute
+ syntax inside the single quotes. In operation requests and responses
+ each attribute value MUST be represented as one of the attribute
+ syntaxes specified in the sub-section heading for the attribute. In
+ addition, the value of an attribute in a response (but not in a
+
+
+
+
+Hastings, et al. Standards Track [Page 78]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ request) MAY be one of the "out-of-band" values whose special
+ encoding rules are defined in the "Encoding and Transport" document
+ [RFC2910]. Standard "out-of-band" values are:
+
+ 'unknown': The attribute is supported by the IPP object, but the
+ value is unknown to the IPP object for some reason.
+ 'unsupported': The attribute is unsupported by the IPP object.
+ This value MUST be returned only as the value of an attribute
+ in the Unsupported Attributes Group.
+ 'no-value': The attribute is supported by the Printer object, but
+ the administrator has not yet configured a value.
+
+ All attributes in a request MUST have one or more values as defined
+ in Sections 4.2 to 4.4. Thus clients MUST NOT supply attributes with
+ "out-of-band" values for operations defined in this document. All
+ attributes in a response MUST have one or more values as defined in
+ Sections 4.2 to 4.4 or a single "out-of-band" value.
+
+ Most attributes are defined to have a single attribute syntax.
+ However, a few attributes (e.g., "job-sheet", "media", "job-hold-
+ until") are defined to have several attribute syntaxes, depending on
+ the value. These multiple attribute syntaxes are separated by the
+ "|" character in the sub-section heading to indicate the choice.
+ Since each value MUST be tagged as to its attribute syntax in the
+ protocol, a single-valued attribute instance may have any one of its
+ attribute syntaxes and a multi-valued attribute instance may have a
+ mixture of its defined attribute syntaxes.
+
+4.1.1 'text'
+
+ A text attribute is an attribute whose value is a sequence of zero or
+ more characters encoded in a maximum of 1023 ('MAX') octets. MAX is
+ the maximum length for each value of any text attribute. However, if
+ an attribute will always contain values whose maximum length is much
+ less than MAX, the definition of that attribute will include a
+ qualifier that defines the maximum length for values of that
+ attribute. For example: the "printer-location" attribute is
+ specified as "printer-location (text(127))". In this case, text
+ values for "printer-location" MUST NOT exceed 127 octets; if supplied
+ with a longer text string via some external interface (other than the
+ protocol), implementations are free to truncate to this shorter
+ length limitation.
+
+ In this document, all text attributes are defined using the 'text'
+ syntax. However, 'text' is used only for brevity; the formal
+ interpretation of 'text' is: 'textWithoutLanguage |
+ textWithLanguage'. That is, for any attribute defined in this
+ document using the 'text' attribute syntax, all IPP objects and
+
+
+
+Hastings, et al. Standards Track [Page 79]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ clients MUST support both the 'textWithoutLanguage' and
+ 'textWithLanguage' attribute syntaxes. However, in actual usage and
+ protocol execution, objects and clients accept and return only one of
+ the two syntax per attribute. The syntax 'text' never appears "on-
+ the-wire".
+
+ Both 'textWithoutLanguage' and 'textWithLanguage' are needed to
+ support the real world needs of interoperability between sites and
+ systems that use different natural languages as the basis for human
+ communication. Generally, one natural language applies to all text
+ attributes in a given request or response. The language is indicated
+ by the "attributes-natural-language" operation attribute defined in
+ section 3.1.4 or "attributes-natural-language" job attribute defined
+ in section 4.3.20, and there is no need to identify the natural
+ language for each text string on a value-by-value basis. In these
+ cases, the attribute syntax 'textWithoutLanguage' is used for text
+ attributes. In other cases, the client needs to supply or the
+ Printer object needs to return a text value in a natural language
+ that is different from the rest of the text values in the request or
+ response. In these cases, the client or Printer object uses the
+ attribute syntax 'textWithLanguage' for text attributes (this is the
+ Natural Language Override mechanism described in section 3.1.4).
+
+ The 'textWithoutLanguage' and 'textWithLanguage' attribute syntaxes
+ are described in more detail in the following sections.
+
+4.1.1.1 'textWithoutLanguage'
+
+ The 'textWithoutLanguage' syntax indicates a value that is sequence
+ of zero or more characters encoded in a maximum of 1023 (MAX) octets.
+ Text strings are encoded using the rules of some charset. The
+ Printer object MUST support the UTF-8 charset [RFC2279] and MAY
+ support additional charsets to represent 'text' values, provided that
+ the charsets are registered with IANA [IANA-CS]. See Section 4.1.7
+ for the definition of the 'charset' attribute syntax, including
+ restricted semantics and examples of charsets.
+
+4.1.1.2 'textWithLanguage'
+
+ The 'textWithLanguage' attribute syntax is a compound attribute
+ syntax consisting of two parts: a 'textWithoutLanguage' part encoded
+ in a maximum of 1023 (MAX) octets plus an additional
+ 'naturalLanguage' (see section 4.1.8) part that overrides the natural
+ language in force. The 'naturalLanguage' part explicitly identifies
+ the natural language that applies to the text part of that value and
+ that value alone. For any give text attribute, the
+ 'textWithoutLanguage' part is limited to the maximum length defined
+ for that 'text' attribute, and the 'naturalLanguage' part is always
+
+
+
+Hastings, et al. Standards Track [Page 80]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ limited to 63 (additional) octets. Using the 'textWithLanguage'
+ attribute syntax rather than the normal 'textWithoutLanguage' syntax
+ is the so-called Natural Language Override mechanism and MUST be
+ supported by all IPP objects and clients.
+
+ If the attribute is multi-valued (1setOf text), then the
+ 'textWithLanguage' attribute syntax MUST be used to explicitly
+ specify each attribute value whose natural language needs to be
+ overridden. Other values in a multi-valued 'text' attribute in a
+ request or a response revert to the natural language of the operation
+ attribute.
+
+ In a create request, the Printer object MUST accept and store with
+ the Job object any natural language in the "attributes-natural-
+ language" operation attribute, whether the Printer object supports
+ that natural language or not. Furthermore, the Printer object MUST
+ accept and store any 'textWithLanguage' attribute value, whether the
+ Printer object supports that natural language or not. These
+ requirements are independent of the value of the "ipp-attribute-
+ fidelity" operation attribute that the client MAY supply.
+
+ Example: If the client supplies the "attributes-natural-language"
+ operation attribute with the value: 'en' indicating English, but the
+ value of the "job-name" attribute is in French, the client MUST use
+ the 'textWithLanguage' attribute syntax with the following two
+ values:
+
+ 'fr': Natural Language Override indicating French
+ 'Rapport Mensuel': the job name in French
+
+ See the "Encoding and Transport" document [RFC2910] section 3.9 for
+ the encoding of the two parts and Appendix A for a detailed example
+ of the 'textWithLanguage' attribute syntax.
+
+4.1.2 'name'
+
+ This syntax type is used for user-friendly strings, such as a Printer
+ name, that, for humans, are more meaningful than identifiers. Names
+ are never translated from one natural language to another. The
+ 'name' attribute syntax is essentially the same as 'text', including
+ the REQUIRED support of UTF-8 except that the sequence of characters
+ is limited so that its encoded form MUST NOT exceed 255 (MAX) octets.
+
+ Also like 'text', 'name' is really an abbreviated notation for either
+ 'nameWithoutLanguage' or 'nameWithLanguage'. That is, all IPP
+ objects and clients MUST support both the 'nameWithoutLanguage' and
+ 'nameWithLanguage' attribute syntaxes. However, in actual usage and
+
+
+
+
+Hastings, et al. Standards Track [Page 81]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ protocol execution, objects and clients accept and return only one of
+ the two syntax per attribute. The syntax 'name' never appears "on-
+ the-wire".
+
+ Only the 'text' and 'name' attribute syntaxes permit the Natural
+ Language Override mechanism.
+
+ Some attributes are defined as 'type3 keyword | name'. These
+ attributes support values that are either type3 keywords or names.
+ This dual-syntax mechanism enables a site administrator to extend
+ these attributes to legally include values that are locally defined
+ by the site administrator. Such names are not registered with IANA.
+
+4.1.2.1 'nameWithoutLanguage'
+
+ The 'nameWithoutLanguage' syntax indicates a value that is sequence
+ of zero or more characters encoded in a maximum of 255 (MAX) octets.
+
+4.1.2.2 'nameWithLanguage'
+
+ The 'nameWithLanguage' attribute syntax is a compound attribute
+ syntax consisting of two parts: a 'nameWithoutLanguage' part encoded
+ in a maximum of 1023 (MAX) octets plus an additional
+ 'naturalLanguage' (see section 4.1.8) part that overrides the natural
+ language in force. The 'naturalLanguage' part explicitly identifies
+ the natural language that applies to that name value and that name
+ value alone. For any give text attribute, the 'textWithoutLanguage'
+ part is limited to the maximum length defined for that 'text'
+ attribute, and the 'naturalLanguage' part is always limited to 63
+ (additional) octets. Using the 'textWithLanguage' attribute syntax
+ rather than the normal 'textWithoutLanguage' syntax is the so-called
+ Natural Language Override mechanism and MUST be supported by all IPP
+ objects and clients.
+
+ The 'nameWithLanguage' attribute syntax behaves the same as the
+ 'textWithLanguage' syntax. Using the 'textWithLanguage' attribute
+ syntax rather than the normal 'textWithoutLanguage' syntax is the
+ so-called Natural Language Override mechanism and MUST be supported
+ by all IPP objects and clients. If a name is in a language that is
+ different than the rest of the object or operation, then this
+ 'nameWithLanguage' syntax is used rather than the generic
+ 'nameWithoutLanguage' syntax.
+
+ If the attribute is multi-valued (1setOf text), then the
+ 'nameWithLanguage' attribute syntax MUST be used to explicitly
+ specify each attribute value whose natural language needs to be
+ overridden.
+
+
+
+
+Hastings, et al. Standards Track [Page 82]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Other values in a multi-valued 'name' attribute in a request or a
+ response revert to the natural language of the operation attribute.
+
+ In a create request, the Printer object MUST accept and store with
+ the Job object any natural language in the "attributes-natural-
+ language" operation attribute, whether the Printer object supports
+ that natural language or not. Furthermore, the Printer object MUST
+ accept and store any 'nameWithLanguage' attribute value, whether the
+ Printer object supports that natural language or not. These
+ requirements are independent of the value of the "ipp-attribute-
+ fidelity" operation attribute that the client MAY supply.
+
+ Example: If the client supplies the "attributes-natural-language"
+ operation attribute with the value: 'en' indicating English, but the
+ "printer-name" attribute is in German, the client MUST use the
+ 'nameWithLanguage' attribute syntax as follows:
+
+ 'de': Natural Language Override indicating German
+ 'Farbdrucker': the Printer name in German
+
+ See the "Encoding and Transport" document [RFC2910] section 3.9 for
+ the encoding of the two parts and Appendix A for a detailed example
+ of the 'nameWithLanguage' attribute syntax.
+
+4.1.2.3 Matching 'name' attribute values
+
+ For purposes of matching two 'name' attribute values for equality,
+ such as in job validation (where a client-supplied value for
+ attribute "xxx" is checked to see if the value is among the values of
+ the Printer object's corresponding "xxx-supported" attribute), the
+ following match rules apply:
+
+ 1. 'keyword' values never match 'name' values.
+
+ 2. 'name' (nameWithoutLanguage and nameWithLanguage) values match
+ if (1) the name parts match and (2) the Associated Natural-
+ Language parts (see section 3.1.4.1) match. The matching rules
+ are:
+
+ a. the name parts match if the two names are identical
+ character by character, except it is RECOMMENDED that case
+ be ignored. For example: 'Ajax-letter-head-white' MUST
+ match 'Ajax-letter-head-white' and SHOULD match 'ajax-
+ letter-head-white' and 'AJAX-LETTER-HEAD-WHITE'.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 83]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ b. the Associated Natural-Language parts match if the shorter
+ of the two meets the syntactic requirements of RFC 1766
+ [RFC1766] and matches byte for byte with the longer. For
+ example, 'en' matches 'en', 'en-us' and 'en-gb', but matches
+ neither 'fr' nor 'e'.
+
+4.1.3 'keyword'
+
+ The 'keyword' attribute syntax is a sequence of characters, length: 1
+ to 255, containing only the US-ASCII [ASCII] encoded values for
+ lowercase letters ("a" - "z"), digits ("0" - "9"), hyphen ("-"), dot
+ ("."), and underscore ("_"). The first character MUST be a lowercase
+ letter. Furthermore, keywords MUST be in U.S. English.
+
+ This syntax type is used for enumerating semantic identifiers of
+ entities in the abstract protocol, i.e., entities identified in this
+ document. Keywords are used as attribute names or values of
+ attributes. Unlike 'text' and 'name' attribute values, 'keyword'
+ values MUST NOT use the Natural Language Override mechanism, since
+ they MUST always be US-ASCII and U.S. English.
+
+ Keywords are for use in the protocol. A user interface will likely
+ provide a mapping between protocol keywords and displayable user-
+ friendly words and phrases which are localized to the natural
+ language of the user. While the keywords specified in this document
+ MAY be displayed to users whose natural language is U.S. English,
+ they MAY be mapped to other U.S. English words for U.S. English
+ users, since the user interface is outside the scope of this
+ document.
+
+ In the definition for each attribute of this syntax type, the full
+ set of defined keyword values for that attribute are listed.
+
+ When a keyword is used to represent an attribute (its name), it MUST
+ be unique within the full scope of all IPP objects and attributes.
+ When a keyword is used to represent a value of an attribute, it MUST
+ be unique just within the scope of that attribute. That is, the same
+ keyword MUST NOT be used for two different values within the same
+ attribute to mean two different semantic ideas. However, the same
+ keyword MAY be used across two or more attributes, representing
+ different semantic ideas for each attribute. Section 6.1 describes
+ how the protocol can be extended with new keyword values. Examples
+ of attribute name keywords:
+
+ "job-name"
+ "attributes-charset"
+
+
+
+
+
+Hastings, et al. Standards Track [Page 84]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Note: This document uses "type1", "type2", and "type3" prefixes to
+ the "keyword" basic syntax to indicate different levels of review for
+ extensions (see section 6.1).
+
+4.1.4 'enum'
+
+ The 'enum' attribute syntax is an enumerated integer value that is in
+ the range from 1 to 2**31 - 1 (MAX). Each value has an associated
+ 'keyword' name. In the definition for each attribute of this syntax
+ type, the full set of possible values for that attribute are listed.
+ This syntax type is used for attributes for which there are enum
+ values assigned by other standards, such as SNMP MIBs. A number of
+ attribute enum values in this document are also used for
+ corresponding attributes in other standards [RFC1759]. This syntax
+ type is not used for attributes to which the administrator may assign
+ values. Section 6.1 describes how the protocol can be extended with
+ new enum values.
+
+ Enum values are for use in the protocol. A user interface will
+ provide a mapping between protocol enum values and displayable user-
+ friendly words and phrases which are localized to the natural
+ language of the user. While the enum symbols specified in this
+ document MAY be displayed to users whose natural language is U.S.
+ English, they MAY be mapped to other U.S. English words for U.S.
+ English users, since the user interface is outside the scope of this
+ document.
+
+ Note: SNMP MIBs use '2' for 'unknown' which corresponds to the IPP
+ "out-of-band" value 'unknown'. See the description of the "out-of-
+ band" values at the beginning of Section 4.1. Therefore, attributes
+ of type 'enum' start at '3'.
+
+ Note: This document uses "type1", "type2", and "type3" prefixes to
+ the "enum" basic syntax to indicate different levels of review for
+ extensions (see section 6.1).
+
+4.1.5 'uri'
+
+ The 'uri' attribute syntax is any valid Uniform Resource Identifier
+ or URI [RFC2396]. Most often, URIs are simply Uniform Resource
+ Locators or URLs. The maximum length of URIs used as values of IPP
+ attributes is 1023 octets. Although most other IPP attribute syntax
+ types allow for only lower-cased values, this attribute syntax type
+ conforms to the case-sensitive and case-insensitive rules specified
+ in [RFC2396]. See also [IPP-IIG] for a discussion of case in URIs.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 85]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.1.6 'uriScheme'
+
+ The 'uriScheme' attribute syntax is a sequence of characters
+ representing a URI scheme according to RFC 2396 [RFC2396]. Though
+ RFC 2396 requires that the values be case-insensitive, IPP requires
+ all lower case values in IPP attributes to simplify comparing by IPP
+ clients and Printer objects.
+
+ Standard values for this syntax type are the following keywords:
+
+ 'ipp': for IPP schemed URIs (e.g., "ipp:...")
+ 'http': for HTTP schemed URIs (e.g., "http:...")
+ 'https': for use with HTTPS schemed URIs (e.g., "https:...") (not
+ on IETF standards track)
+ 'ftp': for FTP schemed URIs (e.g., "ftp:...")
+ 'mailto': for SMTP schemed URIs (e.g., "mailto:...")
+ 'file': for file schemed URIs (e.g., "file:...")
+
+ A Printer object MAY support any URI 'scheme' that has been
+ registered with IANA [IANA-MT]. The maximum length of URI 'scheme'
+ values used to represent IPP attribute values is 63 octets.
+
+4.1.7 'charset'
+
+ The 'charset' attribute syntax is a standard identifier for a
+ charset. A charset is a coded character set and encoding scheme.
+ Charsets are used for labeling certain document contents and 'text'
+ and 'name' attribute values. The syntax and semantics of this
+ attribute syntax are specified in RFC 2046 [RFC2046] and contained in
+ the IANA character-set Registry [IANA-CS] according to the IANA
+ procedures [RFC2278]. Though RFC 2046 requires that the values be
+ case-insensitive US-ASCII [ASCII], IPP requires all lower case values
+ in IPP attributes to simplify comparing by IPP clients and Printer
+ objects. When a character-set in the IANA registry has more than one
+ name (alias), the name labeled as "(preferred MIME name)", if
+ present, MUST be used.
+
+ The maximum length of 'charset' values used to represent IPP
+ attribute values is 63 octets.
+
+ Some examples are:
+
+ 'utf-8': ISO 10646 Universal Multiple-Octet Coded Character Set
+ (UCS) represented as the UTF-8 [RFC2279] transfer encoding
+ scheme in which US-ASCII is a subset charset.
+ 'us-ascii': 7-bit American Standard Code for Information
+ Interchange (ASCII), ANSI X3.4-1986 [ASCII]. That standard
+
+
+
+
+Hastings, et al. Standards Track [Page 86]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ defines US-ASCII, but RFC 2045 [RFC2045] eliminates most of the
+ control characters from conformant usage in MIME and IPP.
+ 'iso-8859-1': 8-bit One-Byte Coded Character Set, Latin Alphabet
+ Nr 1 [ISO8859-1]. That standard defines a coded character set
+ that is used by Latin languages in the Western Hemisphere and
+ Western Europe. US-ASCII is a subset charset.
+
+ Some attribute descriptions MAY place additional requirements on
+ charset values that may be used, such as REQUIRED values that MUST be
+ supported or additional restrictions, such as requiring that the
+ charset have US- ASCII as a subset charset.
+
+4.1.8 'naturalLanguage'
+
+ The 'naturalLanguage' attribute syntax is a standard identifier for a
+ natural language and optionally a country. The values for this
+ syntax type are defined by RFC 1766 [RFC1766]. Though RFC 1766
+ requires that the values be case-insensitive US-ASCII [ASCII], IPP
+ requires all lower case to simplify comparing by IPP clients and
+ Printer objects. Examples include:
+
+ 'en': for English
+ 'en-us': for US English
+ 'fr': for French
+ 'de': for German
+
+ The maximum length of 'naturalLanguage' values used to represent IPP
+ attribute values is 63 octets.
+
+4.1.9 'mimeMediaType'
+
+ The 'mimeMediaType' attribute syntax is the Internet Media Type
+ (sometimes called MIME type) as defined by RFC 2046 [RFC2046] and
+ registered according to the procedures of RFC 2048 [RFC2048] for
+ identifying a document format. The value MAY include a charset, or
+ other, parameter, depending on the specification of the Media Type in
+ the IANA Registry [IANA-MT]. Although most other IPP syntax types
+ allow for only lower-cased values, this syntax type allows for
+ mixed-case values which are case-insensitive.
+
+ Examples are:
+ 'text/html': An HTML document
+ 'text/plain': A plain text document in US-ASCII (RFC 2046
+ indicates that in the absence of the charset parameter MUST
+ mean US-ASCII rather than simply unspecified) [RFC2046].
+ 'text/plain; charset=US-ASCII': A plain text document in US-ASCII
+ [52, 56].
+
+
+
+
+Hastings, et al. Standards Track [Page 87]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'text/plain; charset=ISO-8859-1': A plain text document in ISO
+ 8859-1 (Latin 1) [ISO8859-1].
+ 'text/plain; charset=utf-8': A plain text document in ISO 10646
+ represented as UTF-8 [RFC2279]
+ 'application/postscript': A PostScript document [RFC2046]
+ 'application/vnd.hp-PCL': A PCL document [IANA-MT] (charset
+ escape sequence embedded in the document data)
+ 'application/pdf': Portable Document Format - see IANA MIME Media
+ Type registry
+ 'application/octet-stream': Auto-sense - see section 4.1.9.1
+
+ The maximum length of a 'mimeMediaType' value to represent IPP
+ attribute values is 255 octets.
+
+4.1.9.1 Application/octet-stream -- Auto-Sensing the document format
+
+ One special type is 'application/octet-stream'. If the Printer
+ object supports this value, the Printer object MUST be capable of
+ auto-sensing the format of the document data using an
+ implementation-dependent method that examines some number of octets
+ of the document data, either as part of the create operation and/or
+ at document processing time. During auto-sensing, a Printer may
+ determine that the document-data has a format that the Printer
+ doesn't recognize. If the Printer determines this problem before
+ returning an operation response, it rejects the request and returns
+ the 'client-error-document-format-not-supported' status code. If the
+ Printer determines this problem after accepting the request and
+ returning an operation response with one of the successful status
+ codes, the Printer adds the 'unsupported-document-format' value to
+ the job's "job-state-reasons" attribute.
+
+ If the Printer object's default value attribute "document-format-
+ default" is set to 'application/octet-stream', the Printer object not
+ only supports auto-sensing of the document format, but will depend on
+ the result of applying its auto-sensing when the client does not
+ supply the "document-format" attribute. If the client supplies a
+ document format value, the Printer MUST rely on the supplied
+ attribute, rather than trust its auto-sensing algorithm. To
+ summarize:
+
+ 1. If the client does not supply a document format value, the
+ Printer MUST rely on its default value setting (which may be
+ 'application/octet-stream' indicating an auto-sensing
+ mechanism).
+ 2. If the client supplies a value other than 'application/octet-
+ stream', the client is supplying valid information about the
+ format of the document data and the Printer object MUST trust
+ the client supplied value more than the outcome of applying an
+
+
+
+Hastings, et al. Standards Track [Page 88]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ automatic format detection mechanism. For example, the client
+ may be requesting the printing of a PostScript file as a
+ 'text/plain' document. The Printer object MUST print a text
+ representation of the PostScript commands rather than interpret
+ the stream of PostScript commands and print the result.
+ 3. If the client supplies a value of 'application/octet-stream',
+ the client is indicating that the Printer object MUST use its
+ auto-sensing mechanism on the client supplied document data
+ whether auto-sensing is the Printer object's default or not.
+
+ Note: Since the auto-sensing algorithm is probabilistic, if the
+ client requests both auto-sensing ("document-format" set to
+ 'application/octet-stream') and true fidelity ("ipp-attribute-
+ fidelity" set to 'true'), the Printer object might not be able to
+ guarantee exactly what the end user intended (the auto-sensing
+ algorithm might mistake one document format for another), but it is
+ able to guarantee that its auto-sensing mechanism be used.
+
+ When a Printer performs auto-sensing of a document in a submitted
+ job, it is RECOMMENDED that the Printer indicate to the user that
+ such auto-sensing has occurred and which document-format was auto-
+ sensed by printing that information on the job's job-start-sheet.
+
+4.1.10 'octetString'
+
+ The 'octetString' attribute syntax is a sequence of octets encoded in
+ a maximum of 1023 octets which is indicated in sub-section headers
+ using the notation: octetString(MAX). This syntax type is used for
+ opaque data.
+
+4.1.11 'boolean'
+
+ The 'boolean' attribute syntax has only two values: 'true' and
+ 'false'.
+
+4.1.12 'integer'
+
+ The 'integer' attribute syntax is an integer value that is in the
+ range from -2**31 (MIN) to 2**31 - 1 (MAX). Each individual
+ attribute may specify the range constraint explicitly in sub-section
+ headers if the range is different from the full range of possible
+ integer values. For example: job-priority (integer(1:100)) for the
+ "job-priority" attribute. However, the enforcement of that
+ additional constraint is up to the IPP objects, not the protocol.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 89]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.1.13 'rangeOfInteger'
+
+ The 'rangeOfInteger' attribute syntax is an ordered pair of integers
+ that defines an inclusive range of integer values. The first integer
+ specifies the lower bound and the second specifies the upper bound.
+ If a range constraint is specified in the header description for an
+ attribute in this document whose attribute syntax is 'rangeOfInteger'
+ (i.e., 'X:Y' indicating X as a minimum value and Y as a maximum
+ value), then the constraint applies to both integers.
+
+4.1.14 'dateTime'
+
+ The 'dateTime' attribute syntax is a standard, fixed length, 11 octet
+ representation of the "DateAndTime" syntax as defined in RFC 2579
+ [RFC2579]. RFC 2579 also identifies an 8 octet representation of a
+ "DateAndTime" value, but IPP objects MUST use the 11 octet
+ representation. A user interface will provide a mapping between
+ protocol dateTime values and displayable user-friendly words or
+ presentation values and phrases which are localized to the natural
+ language and date format of the user, including time zone.
+
+4.1.15 'resolution'
+
+ The 'resolution' attribute syntax specifies a two-dimensional
+ resolution in the indicated units. It consists of 3 values: a cross
+ feed direction resolution (positive integer value), a feed direction
+ resolution (positive integer value), and a units value. The
+ semantics of these three components are taken from the Printer MIB
+ [RFC1759] suggested values. That is, the cross feed direction
+ component resolution component is the same as the
+ prtMarkerAddressabilityXFeedDir object in the Printer MIB, the feed
+ direction component resolution component is the same as the
+ prtMarkerAddressabilityFeedDir in the Printer MIB, and the units
+ component is the same as the prtMarkerAddressabilityUnit object in
+ the Printer MIB (namely, '3' indicates dots per inch and '4'
+ indicates dots per centimeter). All three values MUST be present
+ even if the first two values are the same. Example: '300', '600',
+ '3' indicates a 300 dpi cross-feed direction resolution, a 600 dpi
+ feed direction resolution, since a '3' indicates dots per inch (dpi).
+
+4.1.16 '1setOf X'
+
+ The '1setOf X' attribute syntax is 1 or more values of attribute
+ syntax type X. This syntax type is used for multi-valued attributes.
+ The syntax type is called '1setOf' rather than just 'setOf' as a
+ reminder that the set of values MUST NOT be empty (i.e., a set of
+
+
+
+
+
+Hastings, et al. Standards Track [Page 90]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ size 0). Sets are normally unordered. However each attribute
+ description of this type may specify that the values MUST be in a
+ certain order for that attribute.
+
+4.2 Job Template Attributes
+
+ Job Template attributes describe job processing behavior. Support
+ for Job Template attributes by a Printer object is OPTIONAL (see
+ section 12.2.3 for a description of support for OPTIONAL attributes).
+ Also, clients OPTIONALLY supply Job Template attributes in create
+ requests.
+
+ Job Template attributes conform to the following rules. For each Job
+ Template attribute called "xxx":
+
+ 1. If the Printer object supports "xxx" then it MUST support both
+ a "xxx-default" attribute (unless there is a "No" in the table
+ below) and a "xxx-supported" attribute. If the Printer object
+ doesn't support "xxx", then it MUST support neither an "xxx-
+ default" attribute nor an "xxx-supported" attribute, and it
+ MUST treat an attribute "xxx" supplied by a client as
+ unsupported. An attribute "xxx" may be supported for some
+ document formats and not supported for other document formats.
+ For example, it is expected that a Printer object would only
+ support "orientation-requested" for some document formats (such
+ as 'text/plain' or 'text/html') but not others (such as
+ 'application/postscript').
+
+ 2. "xxx" is OPTIONALLY supplied by the client in a create request.
+ If "xxx" is supplied, the client is indicating a desired job
+ processing behavior for this Job. When "xxx" is not supplied,
+ the client is indicating that the Printer object apply its
+ default job processing behavior at job processing time if the
+ document content does not contain an embedded instruction
+ indicating an xxx-related behavior.
+
+ Since an administrator MAY change the default value attribute
+ after a Job object has been submitted but before it has been
+ processed, the default value used by the Printer object at job
+ processing time may be different that the default value in
+ effect at job submission time.
+
+ 3. The "xxx-supported" attribute is a Printer object attribute
+ that describes which job processing behaviors are supported by
+ that Printer object. A client can query the Printer object to
+ find out what xxx-related behaviors are supported by inspecting
+ the returned values of the "xxx-supported" attribute.
+
+
+
+
+Hastings, et al. Standards Track [Page 91]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Note: The "xxx" in each "xxx-supported" attribute name is
+ singular, even though an "xxx-supported" attribute usually has
+ more than one value, such as "job-sheet-supported", unless the
+ "xxx" Job Template attribute is plural, such as "finishings" or
+ "sides". In such cases the "xxx-supported" attribute names
+ are: "finishings- supported" and "sides-supported".
+
+ 4. The "xxx-default" default value attribute describes what will
+ be done at job processing time when no other job processing
+ information is supplied by the client (either explicitly as an
+ IPP attribute in the create request or implicitly as an
+ embedded instruction within the document data).
+
+ If an application wishes to present an end user with a list of
+ supported values from which to choose, the application SHOULD query
+ the Printer object for its supported value attributes. The
+ application SHOULD also query the default value attributes. If the
+ application then limits selectable values to only those value that
+ are supported, the application can guarantee that the values supplied
+ by the client in the create request all fall within the set of
+ supported values at the Printer. When querying the Printer, the
+ client MAY enumerate each attribute by name in the Get-Printer-
+ Attributes Request, or the client MAY just name the "job-template"
+ group in order to get the complete set of supported attributes (both
+ supported and default attributes).
+
+ The "finishings" attribute is an example of a Job Template attribute.
+ It can take on a set of values such as 'staple', 'punch', and/or
+ 'cover'. A client can query the Printer object for the "finishings-
+ supported" attribute and the "finishings-default" attribute. The
+ supported attribute contains a set of supported values. The default
+ value attribute contains the finishing value(s) that will be used for
+ a new Job if the client does not supply a "finishings" attribute in
+ the create request and the document data does not contain any
+ corresponding finishing instructions. If the client does supply the
+ "finishings" attribute in the create request, the IPP object
+ validates the value or values to make sure that they are a subset of
+ the supported values identified in the Printer object's "finishings-
+ supported" attribute. See section 3.1.7.
+
+ The table below summarizes the names and relationships for all Job
+ Template attributes. The first column of the table (labeled "Job
+ Attribute") shows the name and syntax for each Job Template attribute
+ in the Job object. These are the attributes that can optionally be
+ supplied by the client in a create request. The last two columns
+ (labeled "Printer: Default Value Attribute" and "Printer: Supported
+ Values Attribute") show the name and syntax for each Job Template
+ attribute in the Printer object (the default value attribute and the
+
+
+
+Hastings, et al. Standards Track [Page 92]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ supported values attribute). A "No" in the table means the Printer
+ MUST NOT support the attribute (that is, the attribute is simply not
+ applicable). For brevity in the table, the 'text' and 'name' entries
+ do not show the maximum length for each attribute.
+
+ +===================+======================+======================+
+ | Job Attribute |Printer: Default Value| Printer: Supported |
+ | | Attribute | Values Attribute |
+ +===================+======================+======================+
+ | job-priority | job-priority-default |job-priority-supported|
+ | (integer 1:100) | (integer 1:100) |(integer 1:100) |
+ +-------------------+----------------------+----------------------+
+ | job-hold-until | job-hold-until- |job-hold-until- |
+ | (type3 keyword | | default | supported |
+ | name) | (type3 keyword | |(1setOf ( |
+ | | name) |type3 keyword | name))|
+ +-------------------+----------------------+----------------------+
+ | job-sheets | job-sheets-default |job-sheets-supported |
+ | (type3 keyword | | (type3 keyword | |(1setOf ( |
+ | name) | name) |type3 keyword | name))|
+ +-------------------+----------------------+----------------------+
+ |multiple-document- |multiple-document- |multiple-document- |
+ | handling | handling-default |handling-supported |
+ | (type2 keyword) | (type2 keyword) |(1setOf type2 keyword)|
+ +-------------------+----------------------+----------------------+
+ | copies | copies-default | copies-supported |
+ | (integer (1:MAX)) | (integer (1:MAX)) | (rangeOfInteger |
+ | | | (1:MAX)) |
+ +-------------------+----------------------+----------------------+
+ | finishings | finishings-default | finishings-supported |
+ |(1setOf type2 enum)|(1setOf type2 enum) |(1setOf type2 enum) |
+ +-------------------+----------------------+----------------------+
+ | page-ranges | No | page-ranges- |
+ | (1setOf | | supported (boolean) |
+ | rangeOfInteger | | |
+ | (1:MAX)) | | |
+ +-------------------+----------------------+----------------------+
+ | sides | sides-default | sides-supported |
+ | (type2 keyword) | (type2 keyword) |(1setOf type2 keyword)|
+ +-------------------+----------------------+----------------------+
+ | number-up | number-up-default | number-up-supported |
+ | (integer (1:MAX)) | (integer (1:MAX)) |(1setOf (integer |
+ | | | (1:MAX) | |
+ | | | rangeOfInteger |
+ | | | (1:MAX))) |
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 93]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ +-------------------+----------------------+----------------------+
+ | orientation- |orientation-requested-|orientation-requested-|
+ | requested | default | supported |
+ | (type2 enum) | (type2 enum) | (1setOf type2 enum) |
+ +-------------------+----------------------+----------------------+
+ | media | media-default | media-supported |
+ | (type3 keyword | | (type3 keyword | |(1setOf ( |
+ | name) | name) |type3 keyword | name))|
+ | | | |
+ | | | media-ready |
+ | | |(1setOf ( |
+ | | |type3 keyword | name))|
+ +-------------------+----------------------+----------------------+
+ | printer-resolution| printer-resolution- | printer-resolution- |
+ | (resolution) | default | supported |
+ | | (resolution) |(1setOf resolution) |
+ +-------------------+----------------------+----------------------+
+ | print-quality | print-quality-default| print-quality- |
+ | (type2 enum) | (type2 enum) | supported |
+ | | |(1setOf type2 enum) |
+ +-------------------+----------------------+----------------------+
+
+4.2.1 job-priority (integer(1:100))
+
+ This attribute specifies a priority for scheduling the Job. A higher
+ value specifies a higher priority. The value 1 indicates the lowest
+ possible priority. The value 100 indicates the highest possible
+ priority. Among those jobs that are ready to print, a Printer MUST
+ print all jobs with a priority value of n before printing those with
+ a priority value of n-1 for all n.
+
+ If the Printer object supports this attribute, it MUST always support
+ the full range from 1 to 100. No administrative restrictions are
+ permitted. This way an end-user can always make full use of the
+ entire range with any Printer object. If privileged jobs are
+ implemented outside IPP/1.1, they MUST have priorities higher than
+ 100, rather than restricting the range available to end-users.
+
+ If the client does not supply this attribute and this attribute is
+ supported by the Printer object, the Printer object MUST use the
+ value of the Printer object's "job-priority-default" at job
+ submission time (unlike most Job Template attributes that are used if
+ necessary at job processing time).
+
+ The syntax for the "job-priority-supported" is also integer(1:100).
+ This single integer value indicates the number of priority levels
+ supported. The Printer object MUST take the value supplied by the
+ client and map it to the closest integer in a sequence of n integers
+
+
+
+Hastings, et al. Standards Track [Page 94]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ values that are evenly distributed over the range from 1 to 100 using
+ the formula:
+
+ roundToNearestInt((100x+50)/n)
+
+ where n is the value of "job-priority-supported" and x ranges from 0
+ through n-1.
+
+ For example, if n=1 the sequence of values is 50; if n=2, the
+ sequence of values is: 25 and 75; if n = 3, the sequence of values
+ is: 17, 50 and 83; if n = 10, the sequence of values is: 5, 15, 25,
+ 35, 45, 55, 65, 75, 85, and 95; if n = 100, the sequence of values
+ is: 1, 2, 3, ... 100.
+
+ If the value of the Printer object's "job-priority-supported" is 10
+ and the client supplies values in the range 1 to 10, the Printer
+ object maps them to 5, in the range 11 to 20, the Printer object maps
+ them to 15, etc.
+
+4.2.2 job-hold-until (type3 keyword | name (MAX))
+
+ This attribute specifies the named time period during which the Job
+ MUST become a candidate for printing.
+
+ Standard keyword values for named time periods are:
+
+ 'no-hold': immediately, if there are not other reasons to hold the
+ job
+ 'indefinite': - the job is held indefinitely, until a client
+ performs a Release-Job (section 3.3.6)
+ 'day-time': during the day
+ 'evening': evening
+ 'night': night
+ 'weekend': weekend
+ 'second-shift': second-shift (after close of business)
+ 'third-shift': third-shift (after midnight)
+
+ An administrator MUST associate allowable print times with a named
+ time period (by means outside the scope of this IPP/1.1 document).
+ An administrator is encouraged to pick names that suggest the type of
+ time period. An administrator MAY define additional values using the
+ 'name' or 'keyword' attribute syntax, depending on implementation.
+
+ If the value of this attribute specifies a time period that is in the
+ future, the Printer SHOULD add the 'job-hold-until-specified' value
+ to the job's "job-state-reasons" attribute, MUST move the job to the
+
+
+
+
+
+Hastings, et al. Standards Track [Page 95]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'pending-held' state, and MUST NOT schedule the job for printing
+ until the specified time-period arrives.
+
+ When the specified time period arrives, the Printer MUST remove the
+ 'job-hold-until-specified' value from the job's "job-state-reason"
+ attribute, if present. If there are no other job state reasons that
+ keep the job in the 'pending-held' state, the Printer MUST consider
+ the job as a candidate for processing by moving the job to the
+ 'pending' state.
+
+ If this job attribute value is the named value 'no-hold', or the
+ specified time period has already started, the job MUST be a
+ candidate for processing immediately.
+
+ If the client does not supply this attribute and this attribute is
+ supported by the Printer object, the Printer object MUST use the
+ value of the Printer object's "job-hold-until-default" at job
+ submission time (unlike most Job Template attributes that are used if
+ necessary at job processing time).
+
+4.2.3 job-sheets (type3 keyword | name(MAX))
+
+ This attribute determines which job start/end sheet(s), if any, MUST
+ be printed with a job.
+
+ Standard keyword values are:
+
+ 'none': no job sheet is printed
+ 'standard': one or more site specific standard job sheets are
+ printed, e.g. a single start sheet or both start and end sheet is
+ printed
+
+ An administrator MAY define additional values using the 'name' or
+ 'keyword' attribute syntax, depending on implementation.
+
+ The effect of this attribute on jobs with multiple documents MAY be
+ affected by the "multiple-document-handling" job attribute (section
+ 4.2.4), depending on the job sheet semantics.
+
+4.2.4 multiple-document-handling (type2 keyword)
+
+ This attribute is relevant only if a job consists of two or more
+ documents. This attribute MUST be supported with at least one value
+ if the Printer supports multiple documents per job (see sections
+ 3.2.4 and 3.3.1). The attribute controls finishing operations and
+ the placement of one or more print-stream pages into impressions and
+ onto media sheets. When the value of the "copies" attribute exceeds
+ 1, it also controls the order in which the copies that result from
+
+
+
+Hastings, et al. Standards Track [Page 96]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ processing the documents are produced. For the purposes of this
+ explanations, if "a" represents an instance of document data, then
+ the result of processing the data in document "a" is a sequence of
+ media sheets represented by "a(*)".
+
+ Standard keyword values are:
+
+ 'single-document': If a Job object has multiple documents, say,
+ the document data is called a and b, then the result of
+ processing all the document data (a and then b) MUST be treated
+ as a single sequence of media sheets for finishing operations;
+ that is, finishing would be performed on the concatenation of
+ the sequences a(*),b(*). The Printer object MUST NOT force the
+ data in each document instance to be formatted onto a new
+ print-stream page, nor to start a new impression on a new media
+ sheet. If more than one copy is made, the ordering of the sets
+ of media sheets resulting from processing the document data
+ MUST be a(*), b(*), a(*), b(*), start on a new media sheet.
+ 'separate-documents-uncollated-copies': If a Job object has
+ multiple documents, say, the document data is called a and b,
+ then the result of processing the data in each document
+ instance MUST be treated as a single sequence of media sheets
+ for finishing operations; that is, the sets a(*) and b(*) would
+ each be finished separately. The Printer object MUST force each
+ copy of the result of processing the data in a single document
+ to start on a new media sheet. If more than one copy is made,
+ the ordering of the sets of media sheets resulting from
+ processing the document data MUST be a(*), a(*), ..., b(*),
+ b(*) ... .
+ 'separate-documents-collated-copies': If a Job object has multiple
+ documents, say, the document data is called a and b, then the
+ result of processing the data in each document instance MUST be
+ treated as a single sequence of media sheets for finishing
+ operations; that is, the sets a(*) and b(*) would each be
+ finished separately. The Printer object MUST force each copy of
+ the result of processing the data in a single document to start
+ on a new media sheet. If more than one copy is made, the
+ ordering of the sets of media sheets resulting from processing
+ the document data MUST be a(*), b(*), a(*), b(*), ... .
+ 'single-document-new-sheet': Same as 'single-document', except
+ that the Printer object MUST ensure that the first impression
+ of each document instance in the job is placed on a new media
+ sheet. This value allows multiple documents to be stapled
+ together with a single staple where each document starts on a
+ new sheet.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 97]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The 'single-document' value is the same as 'separate-documents-
+ collated-copies' with respect to ordering of print-stream pages, but
+ not media sheet generation, since 'single-document' will put the
+ first page of the next document on the back side of a sheet if an odd
+ number of pages have been produced so far for the job, while
+ 'separate-documents-collated- copies' always forces the next document
+ or document copy on to a new sheet. In addition, if the "finishings"
+ attribute specifies 'staple', then with 'single-document', documents
+ a and b are stapled together as a single document with no regard to
+ new sheets, with 'single-document-new-sheet', documents a and b are
+ stapled together as a single document, but document b starts on a new
+ sheet, but with 'separate-documents-uncollated-copies' and
+ 'separate-documents-collated-copies', documents a and b are stapled
+ separately.
+
+ Note: None of these values provide means to produce uncollated sheets
+ within a document, i.e., where multiple copies of sheet n are
+ produced before sheet n+1 of the same document.
+
+ The relationship of this attribute and the other attributes that
+ control document processing is described in section 15.3.
+
+4.2.5 copies (integer(1:MAX))
+
+ This attribute specifies the number of copies to be printed.
+
+ On many devices the supported number of collated copies will be
+ limited by the number of physical output bins on the device, and may
+ be different from the number of uncollated copies which can be
+ supported.
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.6 finishings (1setOf type2 enum)
+
+ This attribute identifies the finishing operations that the Printer
+ uses for each copy of each printed document in the Job. For Jobs with
+ multiple documents, the "multiple-document-handling" attribute
+ determines what constitutes a "copy" for purposes of finishing.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 98]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Standard enum values are:
+
+ Value Symbolic Name and Description
+
+ '3' 'none': Perform no finishing
+ '4' 'staple': Bind the document(s) with one or more staples. The
+ exact number and placement of the staples is site-
+ defined.
+ '5' 'punch': This value indicates that holes are required in the
+ finished document. The exact number and placement of the
+ holes is site-defined The punch specification MAY be
+ satisfied (in a site- and implementation-specific manner)
+ either by drilling/punching, or by substituting pre-
+ drilled media.
+ '6' 'cover': This value is specified when it is desired to select
+ a non-printed (or pre-printed) cover for the document.
+ This does not supplant the specification of a printed
+ cover (on cover stock medium) by the document itself.
+ '7' 'bind': This value indicates that a binding is to be applied
+ to the document; the type and placement of the binding is
+ site-defined.
+ '8' 'saddle-stitch': Bind the document(s) with one or more
+ staples (wire stitches) along the middle fold. The exact
+ number and placement of the staples and the middle fold
+ is implementation and/or site-defined.
+ '9' 'edge-stitch': Bind the document(s) with one or more staples
+ (wire stitches) along one edge. The exact number and
+ placement of the staples is implementation and/or site-
+ defined.
+ '10'-'19' reserved for future generic finishing enum values.
+
+ The following values are more specific; they indicate a corner or an
+ edge as if the document were a portrait document (see below):
+
+ '20' 'staple-top-left': Bind the document(s) with one or more
+ staples in the top left corner.
+ '21' 'staple-bottom-left': Bind the document(s) with one or more
+ staples in the bottom left corner.
+ '22' 'staple-top-right': Bind the document(s) with one or more
+ staples in the top right corner.
+ '23' 'staple-bottom-right': Bind the document(s) with one or more
+ staples in the bottom right corner.
+ '24' 'edge-stitch-left': Bind the document(s) with one or more
+ staples (wire stitches) along the left edge. The exact
+ number and placement of the staples is implementation
+ and/or site-defined.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 99]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ '25' 'edge-stitch-top': Bind the document(s) with one or more
+ staples (wire stitches) along the top edge. The exact
+ number and placement of the staples is implementation
+ and/or site-defined.
+ '26' 'edge-stitch-right': Bind the document(s) with one or more
+ staples (wire stitches) along the right edge. The exact
+ number and placement of the staples is implementation
+ and/or site-defined.
+ '27' 'edge-stitch-bottom': Bind the document(s) with one or more
+ staples (wire stitches) along the bottom edge. The exact
+ number and placement of the staples is implementation
+ and/or site-defined.
+ '28' 'staple-dual-left': Bind the document(s) with two staples
+ (wire stitches) along the left edge assuming a portrait
+ document (see above).
+ '29' 'staple-dual-top': Bind the document(s) with two staples
+ (wire stitches) along the top edge assuming a portrait
+ document (see above).
+ '30' 'staple-dual-right': Bind the document(s) with two staples
+ (wire stitches) along the right edge assuming a portrait
+ document (see above).
+ '31' 'staple-dual-bottom': Bind the document(s) with two staples
+ (wire stitches) along the bottom edge assuming a portrait
+ document (see above).
+
+ The 'staple-xxx' values are specified with respect to the document as
+ if the document were a portrait document. If the document is
+ actually a landscape or a reverse-landscape document, the client
+ supplies the appropriate transformed value. For example, to position
+ a staple in the upper left hand corner of a landscape document when
+ held for reading, the client supplies the 'staple-bottom-left' value
+ (since landscape is defined as a +90 degree rotation of the image
+ with respect to the media from portrait, i.e., anti-clockwise). On
+ the other hand, to position a staple in the upper left hand corner of
+ a reverse-landscape document when held for reading, the client
+ supplies the 'staple-top-right' value (since reverse-landscape is
+ defined as a -90 degree rotation of the image with respect to the
+ media from portrait, i.e., clockwise).
+
+ The angle (vertical, horizontal, angled) of each staple with respect
+ to the document depends on the implementation which may in turn
+ depend on the value of the attribute.
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+
+
+Hastings, et al. Standards Track [Page 100]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ If the client supplies a value of 'none' along with any other
+ combination of values, it is the same as if only that other
+ combination of values had been supplied (that is the 'none' value has
+ no effect).
+
+4.2.7 page-ranges (1setOf rangeOfInteger (1:MAX))
+
+ This attribute identifies the range(s) of print-stream pages that the
+ Printer object uses for each copy of each document which are to be
+ printed. Nothing is printed for any pages identified that do not
+ exist in the document(s). Ranges MUST be in ascending order, for
+ example: 1-3, 5-7, 15-19 and MUST NOT overlap, so that a non-spooling
+ Printer object can process the job in a single pass. If the ranges
+ are not ascending or are overlapping, the IPP object MUST reject the
+ request and return the 'client-error-bad-request' status code. The
+ attribute is associated with print-stream pages not application-
+ numbered pages (for example, the page numbers found in the headers
+ and or footers for certain word processing applications).
+
+ For Jobs with multiple documents, the "multiple-document-handling"
+ attribute determines what constitutes a "copy" for purposes of the
+ specified page range(s). When "multiple-document-handling" is
+ 'single-document', the Printer object MUST apply each supplied page
+ range once to the concatenation of the print-stream pages. For
+ example, if there are 8 documents of 10 pages each, the page-range
+ '41:60' prints the pages in the 5th and 6th documents as a single
+ document and none of the pages of the other documents are printed.
+ When "multiple-document- handling" is 'separate-documents-
+ uncollated-copies' or 'separate-documents-collated-copies', the
+ Printer object MUST apply each supplied page range repeatedly to each
+ document copy. For the same job, the page-range '1:3, 10:10' would
+ print the first 3 pages and the 10th page of each of the 8 documents
+ in the Job, as 8 separate documents.
+
+ In most cases, the exact pages to be printed will be generated by a
+ device driver and this attribute would not be required. However,
+ when printing an archived document which has already been formatted,
+ the end user may elect to print just a subset of the pages contained
+ in the document. In this case, if page-range = n.m is specified, the
+ first page to be printed will be page n. All subsequent pages of the
+ document will be printed through and including page m.
+
+ "page-ranges-supported" is a boolean value indicating whether or not
+ the printer is capable of supporting the printing of page ranges.
+ This capability may differ from one PDL to another. There is no
+ "page-ranges-default" attribute. If the "page-ranges" attribute is
+ not supplied by the client, all pages of the document will be
+ printed.
+
+
+
+Hastings, et al. Standards Track [Page 101]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.8 sides (type2 keyword)
+
+ This attribute specifies how print-stream pages are to be imposed
+ upon the sides of an instance of a selected medium, i.e., an
+ impression.
+
+ The standard keyword values are:
+
+ 'one-sided': imposes each consecutive print-stream page upon the
+ same side of consecutive media sheets.
+ 'two-sided-long-edge': imposes each consecutive pair of print-
+ stream pages upon front and back sides of consecutive media
+ sheets, such that the orientation of each pair of print-stream
+ pages on the medium would be correct for the reader as if for
+ binding on the long edge. This imposition is sometimes called
+ 'duplex' or 'head-to-head'.
+ 'two-sided-short-edge': imposes each consecutive pair of print-
+ stream pages upon front and back sides of consecutive media
+ sheets, such that the orientation of each pair of print-stream
+ pages on the medium would be correct for the reader as if for
+ binding on the short edge. This imposition is sometimes called
+ 'tumble' or 'head-to-toe'.
+ 'two-sided-long-edge', 'two-sided-short-edge',
+ 'tumble', and 'duplex' all work the same for portrait or
+ landscape. However
+ 'head-to-toe' is
+ 'tumble' in portrait but 'duplex' in landscape. 'head-to-head'
+ also switches between 'duplex' and 'tumble' when using portrait
+ and landscape modes.
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.9 number-up (integer(1:MAX))
+
+ This attribute specifies the number of print-stream pages to impose
+ upon a single side of an instance of a selected medium. For example,
+ if the value is:
+
+
+
+
+Hastings, et al. Standards Track [Page 102]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Value Description
+
+ '1' the Printer MUST place one print-stream page on a single side
+ of an instance of the selected medium (MAY add some sort
+ of translation, scaling, or rotation).
+ '2' the Printer MUST place two print-stream pages on a single side
+ of an instance of the selected medium (MAY add some sort
+ of translation, scaling, or rotation).
+ '4' the Printer MUST place four print-stream pages on a single
+ side of an instance of the selected medium (MAY add some
+ sort of translation, scaling, or rotation).
+
+ This attribute primarily controls the translation, scaling and
+ rotation of print-stream pages.
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.10 orientation-requested (type2 enum)
+
+ This attribute indicates the desired orientation for printed print-
+ stream pages; it does not describe the orientation of the client-
+ supplied print-stream pages.
+
+ For some document formats (such as 'application/postscript'), the
+ desired orientation of the print-stream pages is specified within the
+ document data. This information is generated by a device driver
+ prior to the submission of the print job. Other document formats
+ (such as 'text/plain') do not include the notion of desired
+ orientation within the document data. In the latter case it is
+ possible for the Printer object to bind the desired orientation to
+ the document data after it has been submitted. It is expected that a
+ Printer object would only support "orientations-requested" for some
+ document formats (e.g., 'text/plain' or 'text/html') but not others
+ (e.g., 'application/postscript'). This is no different than any
+ other Job Template attribute since section 4.2, item 1, points out
+ that a Printer object may support or not support any Job Template
+ attribute based on the document format supplied by the client.
+ However, a special mention is made here since it is very likely that
+ a Printer object will support "orientation-requested" for only a
+ subset of the supported document formats.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 103]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Standard enum values are:
+
+ Value Symbolic Name and Description
+
+ '3' 'portrait': The content will be imaged across the short edge
+ of the medium.
+ '4' 'landscape': The content will be imaged across the long edge
+ of the medium. Landscape is defined to be a rotation of
+ the print-stream page to be imaged by +90 degrees with
+ respect to the medium (i.e. anti-clockwise) from the
+ portrait orientation. Note: The +90 direction was
+ chosen because simple finishing on the long edge is the
+ same edge whether portrait or landscape
+ '5' 'reverse-landscape': The content will be imaged across the
+ long edge of the medium. Reverse-landscape is defined to
+ be a rotation of the print-stream page to be imaged by -
+ 90 degrees with respect to the medium (i.e. clockwise)
+ from the portrait orientation. Note: The 'reverse-
+ landscape' value was added because some applications
+ rotate landscape -90 degrees from portrait, rather than
+ +90 degrees.
+ '6' 'reverse-portrait': The content will be imaged across the
+ short edge of the medium. Reverse-portrait is defined to
+ be a rotation of the print-stream page to be imaged by
+ 180 degrees with respect to the medium from the portrait
+ orientation. Note: The 'reverse-portrait' value was
+ added for use with the "finishings" attribute in cases
+ where the opposite edge is desired for finishing a
+ portrait document on simple finishing devices that have
+ only one finishing position. Thus a 'text'/plain'
+ portrait document can be stapled "on the right" by a
+ simple finishing device as is common use with some middle
+ eastern languages such as Hebrew.
+
+ Note: The effect of this attribute on jobs with multiple documents is
+ controlled by the "multiple-document-handling" job attribute (section
+ 4.2.4) and the relationship of this attribute and the other
+ attributes that control document processing is described in section
+ 15.3.
+
+4.2.11 media (type3 keyword | name(MAX))
+
+ This attribute identifies the medium that the Printer uses for all
+ impressions of the Job.
+
+ The values for "media" include medium-names, medium-sizes, input-
+ trays and electronic forms so that one attribute specifies the media.
+ If a Printer object supports a medium name as a value of this
+
+
+
+Hastings, et al. Standards Track [Page 104]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ attribute, such a medium name implicitly selects an input-tray that
+ contains the specified medium. If a Printer object supports a medium
+ size as a value of this attribute, such a medium size implicitly
+ selects a medium name that in turn implicitly selects an input-tray
+ that contains the medium with the specified size. If a Printer
+ object supports an input-tray as the value of this attribute, such an
+ input-tray implicitly selects the medium that is in that input-tray
+ at the time the job prints. This case includes manual-feed input-
+ trays. If a Printer object supports an electronic form as the value
+ of this attribute, such an electronic form implicitly selects a
+ medium-name that in turn implicitly selects an input-tray that
+ contains the medium specified by the electronic form. The electronic
+ form also implicitly selects an image that the Printer MUST merge
+ with the document data as its prints each page.
+
+ Standard keyword values are taken from ISO DPA [ISO10175], the
+ Printer MIB [RFC1759], and ASME-Y14.1M [ASME-Y14.1M] and are listed
+ in section 14. An administrator MAY define additional values using
+ the 'name' or 'keyword' attribute syntax, depending on
+ implementation.
+
+ There is also an additional Printer attribute named "media-ready"
+ which differs from "media-supported" in that legal values only
+ include the subset of "media-supported" values that are physically
+ loaded and ready for printing with no operator intervention required.
+ If an IPP object supports "media-supported", it NEED NOT support
+ "media-ready".
+
+ The relationship of this attribute and the other attributes that
+ control document processing is described in section 15.3.
+
+4.2.12 printer-resolution (resolution)
+
+ This attribute identifies the resolution that Printer uses for the
+ Job.
+
+4.2.13 print-quality (type2 enum)
+
+ This attribute specifies the print quality that the Printer uses for
+ the Job.
+
+ The standard enum values are:
+
+ Value Symbolic Name and Description
+
+ '3' 'draft': lowest quality available on the printer
+ '4' 'normal': normal or intermediate quality on the printer
+ '5' 'high': highest quality available on the printer
+
+
+
+Hastings, et al. Standards Track [Page 105]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.3 Job Description Attributes
+
+ The attributes in this section form the attribute group called "job-
+ description". The following table summarizes these attributes. The
+ third column indicates whether the attribute is a REQUIRED attribute
+ that MUST be supported by Printer objects. If it is not indicated as
+ REQUIRED, then it is OPTIONAL. The maximum size in octets for 'text'
+ and 'name' attributes is indicated in parenthesizes.
+
+ +----------------------------+----------------------+--------------+
+ | Attribute | Syntax | REQUIRED? |
+ +----------------------------+----------------------+--------------+
+ | job-uri | uri | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-id | integer(1:MAX) | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-printer-uri | uri | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-more-info | uri | |
+ +----------------------------+----------------------+--------------+
+ | job-name | name (MAX) | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-originating-user-name | name (MAX) | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-state | type1 enum | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-state-reasons | 1setOf type2 keyword | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-state-message | text (MAX) | |
+ +----------------------------+----------------------+--------------+
+ | job-detailed-status- | 1setOf text (MAX) | |
+ | messages | | |
+ +----------------------------+----------------------+--------------+
+ | job-document-access-errors | 1setOf text (MAX) | |
+ +----------------------------+----------------------+--------------+
+ | number-of-documents | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | output-device-assigned | name (127) | |
+ +----------------------------+----------------------+--------------+
+ | time-at-creation | integer (MIN:MAX) | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | time-at-processing | integer (MIN:MAX) | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | time-at-completed | integer (MIN:MAX) | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | job-printer-up-time | integer (1:MAX) | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | date-time-at-creation | dateTime | |
+
+
+
+Hastings, et al. Standards Track [Page 106]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ +----------------------------+----------------------+--------------+
+ | date-time-at-processing | dateTime | |
+ +----------------------------+----------------------+--------------+
+ | date-time-at-completed | dateTime | |
+ +----------------------------+----------------------+--------------+
+ | number-of-intervening-jobs | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | job-message-from-operator | text (127) | |
+ +----------------------------+----------------------+--------------+
+ | job-k-octets | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | job-impressions | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | job-media-sheets | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | job-k-octets-processed | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | job-impressions-completed | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | job-media-sheets-completed | integer (0:MAX) | |
+ +----------------------------+----------------------+--------------+
+ | attributes-charset | charset | REQUIRED |
+ +----------------------------+----------------------+--------------+
+ | attributes-natural-language| naturalLanguage | REQUIRED |
+ +----------------------------+----------------------+--------------+
+
+4.3.1 job-uri (uri)
+
+ This REQUIRED attribute contains the URI for the job. The Printer
+ object, on receipt of a new job, generates a URI which identifies the
+ new Job. The Printer object returns the value of the "job-uri"
+ attribute as part of the response to a create request. The precise
+ format of a Job URI is implementation dependent. If the Printer
+ object supports more than one URI and there is some relationship
+ between the newly formed Job URI and the Printer object's URI, the
+ Printer object uses the Printer URI supplied by the client in the
+ create request. For example, if the create request comes in over a
+ secure channel, the new Job URI MUST use the same secure channel.
+ This can be guaranteed because the Printer object is responsible for
+ generating the Job URI and the Printer object is aware of its
+ security configuration and policy as well as the Printer URI used in
+ the create request.
+
+ For a description of this attribute and its relationship to "job-id"
+ and "job-printer-uri" attribute, see the discussion in section 2.4 on
+ "Object Identity".
+
+
+
+
+
+Hastings, et al. Standards Track [Page 107]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.3.2 job-id (integer(1:MAX))
+
+ This REQUIRED attribute contains the ID of the job. The Printer, on
+ receipt of a new job, generates an ID which identifies the new Job on
+ that Printer. The Printer returns the value of the "job-id"
+ attribute as part of the response to a create request. The 0 value
+ is not included to allow for compatibility with SNMP index values
+ which also cannot be 0.
+
+ For a description of this attribute and its relationship to "job-uri"
+ and "job-printer-uri" attribute, see the discussion in section 2.4 on
+ "Object Identity".
+
+4.3.3 job-printer-uri (uri)
+
+ This REQUIRED attribute identifies the Printer object that created
+ this Job object. When a Printer object creates a Job object, it
+ populates this attribute with the Printer object URI that was used in
+ the create request. This attribute permits a client to identify the
+ Printer object that created this Job object when only the Job
+ object's URI is available to the client. The client queries the
+ creating Printer object to determine which languages, charsets,
+ operations, are supported for this Job.
+
+ For a description of this attribute and its relationship to "job-uri"
+ and "job-id" attribute, see the discussion in section 2.4 on "Object
+ Identity".
+
+4.3.4 job-more-info (uri)
+
+ Similar to "printer-more-info", this attribute contains the URI
+ referencing some resource with more information about this Job
+ object, perhaps an HTML page containing information about the Job.
+
+4.3.5 job-name (name(MAX))
+
+ This REQUIRED attribute is the name of the job. It is a name that is
+ more user friendly than the "job-uri" attribute value. It does not
+ need to be unique between Jobs. The Job's "job-name" attribute is
+ set to the value supplied by the client in the "job-name" operation
+ attribute in the create request (see Section 3.2.1.1). If, however,
+ the "job-name" operation attribute is not supplied by the client in
+ the create request, the Printer object, on creation of the Job, MUST
+ generate a name. The printer SHOULD generate the value of the Job's
+ "job-name" attribute from the first of the following sources that
+ produces a value: 1) the "document-name" operation attribute of the
+
+
+
+
+
+Hastings, et al. Standards Track [Page 108]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ first (or only) document, 2) the "document-URI" attribute of the
+ first (or only) document, or 3) any other piece of Job specific
+ and/or Document Content information.
+
+4.3.6 job-originating-user-name (name(MAX))
+
+ This REQUIRED attribute contains the name of the end user that
+ submitted the print job. The Printer object sets this attribute to
+ the most authenticated printable name that it can obtain from the
+ authentication service over which the IPP operation was received.
+ Only if such is not available, does the Printer object use the value
+ supplied by the client in the "requesting-user-name" operation
+ attribute of the create operation (see Sections 4.4.2, 4.4.3, and 8).
+
+ Note: The Printer object needs to keep an internal originating user
+ id of some form, typically as a credential of a principal, with the
+ Job object. Since such an internal attribute is implementation-
+ dependent and not of interest to clients, it is not specified as a
+ Job Description attribute. This originating user id is used for
+ authorization checks (if any) on all subsequent operations.
+
+4.3.7 job-state (type1 enum)
+
+ This REQUIRED attribute identifies the current state of the job.
+ Even though the IPP protocol defines seven values for job states
+ (plus the out-of-band 'unknown' value - see Section 4.1),
+ implementations only need to support those states which are
+ appropriate for the particular implementation. In other words, a
+ Printer supports only those job states implemented by the output
+ device and available to the Printer object implementation.
+
+ Standard enum values are:
+
+ Values Symbolic Name and Description
+
+ '3' 'pending': The job is a candidate to start processing, but is
+ not yet processing.
+
+ '4' 'pending-held': The job is not a candidate for processing for
+ any number of reasons but will return to the 'pending'
+ state as soon as the reasons are no longer present. The
+ job's "job-state-reason" attribute MUST indicate why the
+ job is no longer a candidate for processing.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 109]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ '5' 'processing': One or more of:
+
+ 1. the job is using, or is attempting to use, one or
+ more purely software processes that are analyzing,
+ creating, or interpreting a PDL, etc.,
+ 2. the job is using, or is attempting to use, one or
+ more hardware devices that are interpreting a PDL, making
+ marks on a medium, and/or performing finishing, such as
+ stapling, etc.,
+ 3. the Printer object has made the job ready for
+ printing, but the output device is not yet printing it,
+ either because the job hasn't reached the output device
+ or because the job is queued in the output device or some
+ other spooler, awaiting the output device to print it.
+
+ When the job is in the 'processing' state, the entire job
+ state includes the detailed status represented in the
+ Printer object's "printer-state", "printer-state-
+ reasons", and "printer-state-message" attributes.
+
+ Implementations MAY, though they NEED NOT, include
+ additional values in the job's "job-state-reasons"
+ attribute to indicate the progress of the job, such as
+ adding the 'job-printing' value to indicate when the
+ output device is actually making marks on paper and/or
+ the 'processing-to-stop-point' value to indicate that the
+ IPP object is in the process of canceling or aborting the
+ job. Most implementations won't bother with this nuance.
+
+ '6' 'processing-stopped': The job has stopped while processing
+ for any number of reasons and will return to the
+ 'processing' state as soon as the reasons are no longer
+ present.
+
+ The job's "job-state-reason" attribute MAY indicate why
+ the job has stopped processing. For example, if the
+ output device is stopped, the 'printer-stopped' value MAY
+ be included in the job's "job-state-reasons" attribute.
+
+ Note: When an output device is stopped, the device
+ usually indicates its condition in human readable form
+ locally at the device. A client can obtain more complete
+ device status remotely by querying the Printer object's
+ "printer-state", "printer-state-reasons" and "printer-
+ state-message" attributes.
+
+ '7' 'canceled': The job has been canceled by a Cancel-Job
+ operation and the Printer object has completed canceling
+
+
+
+Hastings, et al. Standards Track [Page 110]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ the job and all job status attributes have reached their
+ final values for the job. While the Printer object is
+ canceling the job, the job remains in its current state,
+ but the job's "job-state-reasons" attribute SHOULD
+ contain the 'processing-to-stop-point' value and one of
+ the 'canceled-by-user', 'canceled-by-operator', or
+ 'canceled-at-device' value. When the job moves to the
+ 'canceled' state, the 'processing-to-stop-point' value,
+ if present, MUST be removed, but the 'canceled-by-xxx',
+ if present, MUST remain.
+
+ '8' 'aborted': The job has been aborted by the system, usually
+ while the job was in the 'processing' or 'processing-
+ stopped' state and the Printer has completed aborting the
+ job and all job status attributes have reached their
+ final values for the job. While the Printer object is
+ aborting the job, the job remains in its current state,
+ but the job's "job-state-reasons" attribute SHOULD
+ contain the 'processing-to-stop-point' and 'aborted-by-
+ system' values. When the job moves to the 'aborted'
+ state, the 'processing-to-stop-point' value, if present,
+ MUST be removed, but the 'aborted-by-system' value, if
+ present, MUST remain.
+
+ '9' 'completed': The job has completed successfully or with
+ warnings or errors after processing and all of the job
+ media sheets have been successfully stacked in the
+ appropriate output bin(s) and all job status attributes
+ have reached their final values for the job. The job's
+ "job-state-reasons" attribute SHOULD contain one of:
+ 'completed-successfully', 'completed-with-warnings', or
+ 'completed-with-errors' values.
+
+ The final value for this attribute MUST be one of: 'completed',
+ 'canceled', or 'aborted' before the Printer removes the job
+ altogether. The length of time that jobs remain in the 'canceled',
+ 'aborted', and 'completed' states depends on implementation. See
+ section 4.3.7.2.
+
+ The following figure shows the normal job state transitions.
+
+ +----> canceled
+ /
+ +----> pending --------> processing ---------+------> completed
+ | ^ ^ \
+ --->+ | | +----> aborted
+ | v v /
+ +----> pending-held processing-stopped ---+
+
+
+
+Hastings, et al. Standards Track [Page 111]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Normally a job progresses from left to right. Other state
+ transitions are unlikely, but are not forbidden. Not shown are the
+ transitions to the 'canceled' state from the 'pending', 'pending-
+ held', and 'processing-stopped' states.
+
+ Jobs reach one of the three terminal states: 'completed', 'canceled',
+ or 'aborted', after the jobs have completed all activity, including
+ stacking output media, after the jobs have completed all activity,
+ and all job status attributes have reached their final values for the
+ job.
+
+4.3.7.1 Forwarding Servers
+
+ As with all other IPP attributes, if the implementation cannot
+ determine the correct value for this attribute, it SHOULD respond
+ with the out-of-band value 'unknown' (see section 4.1) rather than
+ try to guess at some possibly incorrect value and give the end user
+ the wrong impression about the state of the Job object. For example,
+ if the implementation is just a gateway into some printing system
+ from which it can normally get status, but temporarily is unable,
+ then the implementation should return the 'unknown' value. However,
+ if the implementation is a gateway to a printing system that never
+ provides detailed status about the print job, the implementation MAY
+ set the IPP Job object's state to 'completed', provided that it also
+ sets the 'queued-in-device' value in the job's "job-state-reasons"
+ attribute (see section 4.3.8).
+
+4.3.7.2 Partitioning of Job States
+
+ This section partitions the 7 job states into phases: Job Not
+ Completed, Job Retention, Job History, and Job Removal. This section
+ also explains the 'job-restartable' value of the "job-state-reasons"
+ Job Description attribute for use with the Restart-Job operation.
+
+ Job Not Completed: When a job is in the 'pending', 'pending-held',
+ 'processing', or 'processing-stopped' states, the job is not
+ completed.
+
+ Job Retention: When a job enters one of the three terminal job
+ states: 'completed', 'canceled', or 'aborted', the IPP Printer
+ object MAY "retain" the job in a restartable condition for an
+ implementation-defined time period. This time period MAY be zero
+ seconds and MAY depend on the terminal job state. This phase is
+ called Job Retention. While in the Job Retention phase, the job's
+ document data is retained and a client may restart the job using the
+ Restart-Job operation. If the IPP object supports the Restart-Job
+
+
+
+
+
+Hastings, et al. Standards Track [Page 112]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ operation, then it SHOULD indicate that the job is restartable by
+ adding the 'job-restartable' value to the job's "job-state-reasons"
+ attribute (see Section 4.3.8) during the Job Retention phase.
+
+ Job History: After the Job Retention phase expires for a job, the
+ Printer object deletes the document data for the job and the job
+ becomes part of the Job History. The Printer object MAY also delete
+ any number of the job attributes. Since the job is no longer
+ restartable, the Printer object MUST remove the 'job-restartable'
+ value from the job's "job-state-reasons" attribute, if present.
+
+ Job Removal: After the job has remained in the Job History for an
+ implementation-defined time, such as when the number of jobs exceeds
+ a fixed number or after a fixed time period (which MAY be zero
+ seconds), the IPP Printer removes the job from the system.
+
+ Using the Get-Jobs operation and supplying the 'not-completed' value
+ for the "which-jobs" operation attribute, a client is requesting jobs
+ in the Job Not Completed phase. Using the Get-Jobs operation and
+ supplying the 'completed' value for the "which-jobs" operation
+ attribute, a client is requesting jobs in the Job Retention and Job
+ History phases. Using the Get-Job-Attributes operation, a client is
+ requesting a job in any phase except Job Removal. After Job Removal,
+ the Get-Job-Attributes and Get-Jobs operations no longer are capable
+ of returning any information about a job.
+
+4.3.8 job-state-reasons (1setOf type2 keyword)
+
+ This REQUIRED attribute provides additional information about the
+ job's current state, i.e., information that augments the value of the
+ job's "job-state" attribute.
+
+ These values MAY be used with any job state or states for which the
+ reason makes sense. Some of these value definitions indicate
+ conformance requirements; the rest are OPTIONAL. Furthermore, when
+ implemented, the Printer MUST return these values when the reason
+ applies and MUST NOT return them when the reason no longer applies
+ whether the value of the Job's "job-state" attribute changed or not.
+ When the Job does not have any reasons for being in its current
+ state, the value of the Job's "job-state-reasons" attribute MUST be
+ 'none'.
+
+ Note: While values cannot be added to the 'job-state' attribute
+ without impacting deployed clients that take actions upon receiving
+ "job-state" values, it is the intent that additional "job-state-
+ reasons" values can be defined and registered without impacting such
+ deployed clients. In other words, the "job-state-reasons" attribute
+ is intended to be extensible.
+
+
+
+Hastings, et al. Standards Track [Page 113]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The following standard keyword values are defined. For ease of
+ understanding, the values are presented in the order in which the
+ reasons are likely to occur (if implemented), starting with the
+ 'job-incoming' value:
+
+ 'none': There are no reasons for the job's current state. This
+ state reason is semantically equivalent to "job-state-reasons"
+ without any value and MUST be used when there is no other
+ value, since the 1setOf attribute syntax requires at least one
+ value.
+ 'job-incoming': Either (1) the Printer has accepted the Create-
+ Job operation and is expecting additional Send-Document and/or
+ Send-URI operations, or (2) the Printer is retrieving/accepting
+ document data as a result of a Print-Job, Print-URI, Send-
+ Document or Send-URI operation.
+ 'job-data-insufficient': The Create-Job operation has been
+ accepted by the Printer, but the Printer is expecting
+ additional document data before it can move the job into the
+ 'processing' state. If a Printer starts processing before it
+ has received all data, the Printer removes the 'job-data-
+ insufficient' reason, but the 'job-incoming' remains. If a
+ Printer starts processing after it has received all data, the
+ Printer removes the 'job-data-insufficient' reason and the
+ 'job-incoming' at the same time.
+ 'document-access-error': After accepting a Print-URI or Send-URI
+ request, the Printer could not access one or more documents
+ passed by reference. This reason is intended to cover any file
+ access problem, including file does not exist and access denied
+ because of an access control problem. The Printer MAY also
+ indicate the document access error using the "job-document-
+ access-errors" Job Description attribute (see section 4.3.11).
+ Whether the Printer aborts the job and moves the job to the
+ 'aborted' job state or prints all documents that are accessible
+ and moves the job to the 'completed' job state and adds the
+ 'completed-with-errors' value in the job's "job-state-reasons"
+ attribute depends on implementation and/or site policy. This
+ value SHOULD be supported if the Print-URI or Send-URI
+ operations are supported.
+ 'submission-interrupted': The job was not completely submitted
+ for some unforeseen reason, such as: (1) the Printer has
+ crashed before the job was closed by the client, (2) the
+ Printer or the document transfer method has crashed in some
+ non-recoverable way before the document data was entirely
+ transferred to the Printer, (3) the client crashed or failed to
+ close the job before the time-out period. See section 4.4.31.
+ 'job-outgoing': The Printer is transmitting the job to the output
+ device.
+
+
+
+
+Hastings, et al. Standards Track [Page 114]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'job-hold-until-specified': The value of the job's "job-hold-
+ until" attribute was specified with a time period that is still
+ in the future. The job MUST NOT be a candidate for processing
+ until this reason is removed and there are no other reasons to
+ hold the job. This value SHOULD be supported if the "job-
+ hold-until" Job Template attribute is supported.
+ 'resources-are-not-ready': At least one of the resources needed
+ by the job, such as media, fonts, resource objects, etc., is
+ not ready on any of the physical printer's for which the job is
+ a candidate. This condition MAY be detected when the job is
+ accepted, or subsequently while the job is pending or
+ processing, depending on implementation. The job may remain in
+ its current state or be moved to the 'pending-held' state,
+ depending on implementation and/or job scheduling policy.
+ 'printer-stopped-partly': The value of the Printer's "printer-
+ state-reasons" attribute contains the value 'stopped-partly'.
+ 'printer-stopped': The value of the Printer's "printer-state"
+ attribute is 'stopped'.
+ 'job-interpreting': Job is in the 'processing' state, but more
+ specifically, the Printer is interpreting the document data.
+ 'job-queued': Job is in the 'processing' state, but more
+ specifically, the Printer has queued the document data.
+ 'job-transforming': Job is in the 'processing' state, but more
+ specifically, the Printer is interpreting document data and
+ producing another electronic representation.
+ 'job-queued-for-marker': Job is in any of the 'pending-held',
+ 'pending', or 'processing' states, but more specifically, the
+ Printer has completed enough processing of the document to be
+ able to start marking and the job is waiting for the marker.
+ Systems that require human intervention to release jobs using
+ the Release-Job operation, put the job into the 'pending-held'
+ job state. Systems that automatically select a job to use the
+ marker put the job into the 'pending' job state or keep the
+ job in the 'processing' job state while waiting for the marker,
+ depending on implementation. All implementations put the job
+ into (or back into) the 'processing' state when marking does
+ begin.
+ 'job-printing': The output device is marking media. This value is
+ useful for Printers which spend a great deal of time processing
+ (1) when no marking is happening and then want to show that
+ marking is now happening or (2) when the job is in the process
+ of being canceled or aborted while the job remains in the
+ 'processing' state, but the marking has not yet stopped so that
+ impression or sheet counts are still increasing for the job.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 115]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'job-canceled-by-user': The job was canceled by the owner of the
+ job using the Cancel-Job request, i.e., by a user whose
+ authenticated identity is the same as the value of the
+ originating user that created the Job object, or by some other
+ authorized end-user, such as a member of the job owner's
+ security group. This value SHOULD be supported.
+ 'job-canceled-by-operator': The job was canceled by the operator
+ using the Cancel-Job request, i.e., by a user who has been
+ authenticated as having operator privileges (whether local or
+ remote). If the security policy is to allow anyone to cancel
+ anyone's job, then this value may be used when the job is
+ canceled by other than the owner of the job. For such a
+ security policy, in effect, everyone is an operator as far as
+ canceling jobs with IPP is concerned. This value SHOULD be
+ supported if the implementation permits canceling by other than
+ the owner of the job.
+ 'job-canceled-at-device': The job was canceled by an unidentified
+ local user, i.e., a user at a console at the device. This
+ value SHOULD be supported if the implementation supports
+ canceling jobs at the console.
+ 'aborted-by-system': The job (1) is in the process of being
+ aborted, (2) has been aborted by the system and placed in the
+ 'aborted' state, or (3) has been aborted by the system and
+ placed in the 'pending-held' state, so that a user or operator
+ can manually try the job again. This value SHOULD be
+ supported.
+ 'unsupported-compression': The job was aborted by the system
+ because the Printer determined while attempting to decompress
+ the document-data's that the compression is actually not among
+ those supported by the Printer. This value MUST be supported,
+ since "compressions is a REQUIRED operation attribute.
+ 'compression-error': The job was aborted by the system because the
+ Printer encountered an error in the document-data while
+ decompressing it. If the Printer posts this reason, the
+ document-data has already passed any tests that would have led
+ to the 'unsupported-compression' job-state-reason.
+ 'unsupported-document-format': The job was aborted by the system
+ because the document-data's document-format is not among those
+ supported by the Printer. If the client specifies the
+ document-format as 'application/octet-stream', the printer MAY
+ abort the job and post this reason even though the format is a
+ member of the "document-format-supported" printer attribute,
+ but not among the auto-sensed document-formats. This value
+ MUST be supported, since "document-format" is a REQUIRED
+ operation attribute.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 116]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'document-format-error': The job was aborted by the system because
+ the Printer encountered an error in the document-data while
+ processing it. If the Printer posts this reason, the
+ document-data has already passed any tests that would have led
+ to the 'unsupported-document-format' job-state-reason.
+ 'processing-to-stop-point': The requester has issued a Cancel-Job
+ operation or the Printer object has aborted the job, but is
+ still performing some actions on the job until a specified stop
+ point occurs or job termination/cleanup is completed.
+
+ If the implementation requires some measurable time to cancel
+ the job in the 'processing' or 'processing-stopped' job states,
+ the IPP object MUST use this value to indicate that the Printer
+ object is still performing some actions on the job while the
+ job remains in the 'processing' or 'processing-stopped' state.
+ After all the job's job description attributes have stopped
+ incrementing, the Printer object moves the job from the
+ 'processing' state to the 'canceled' or
+ 'aborted' job states.
+
+ 'service-off-line': The Printer is off-line and accepting no
+ jobs. All 'pending' jobs are put into the 'pending-held'
+ state. This situation could be true if the service's or
+ document transform's input is impaired or broken.
+ 'job-completed-successfully': The job completed successfully.
+ This value SHOULD be supported.
+ 'job-completed-with-warnings': The job completed with warnings.
+ This value SHOULD be supported if the implementation detects
+ warnings.
+ 'job-completed-with-errors': The job completed with errors (and
+ possibly warnings too). This value SHOULD be supported if the
+ implementation detects errors.
+ 'job-restartable' - This job is retained (see section 4.3.7.2) and
+ is currently able to be restarted using the Restart-Job
+ operation (see section 3.3.7). If 'job-restartable' is a value
+ of the job's 'job-state-reasons' attribute, then the IPP object
+ MUST accept a Restart-Job operation for that job. This value
+ SHOULD be supported if the Restart-Job operation is supported.
+ 'queued-in-device': The job has been forwarded to a device or
+ print system that is unable to send back status. The Printer
+ sets the job's "job-state " attribute to 'completed' and adds
+ the 'queued-in-device' value to the job's "job-state-reasons"
+ attribute to indicate that the Printer has no additional
+ information about the job and never will have any better
+ information. See section 4.3.7.1.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 117]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.3.9 job-state-message (text(MAX))
+
+ This attribute specifies information about the "job-state" and "job-
+ state-reasons" attributes in human readable text. If the Printer
+ object supports this attribute, the Printer object MUST be able to
+ generate this message in any of the natural languages identified by
+ the Printer's "generated-natural-language-supported" attribute (see
+ the "attributes-natural-language" operation attribute specified in
+ Section 3.1.4.1).
+
+ The value SHOULD NOT contain additional information not contained in
+ the values of the "job-state" and "job-states-reasons" attributes,
+ such as interpreter error information. Otherwise, application
+ programs might attempt to parse the (localized text). For such
+ additional information such as interpreter errors for application
+ program consumption or specific document access errors, new
+ attributes with keyword values, needs to be developed and registered.
+
+4.3.10 job-detailed-status-messages (1setOf text(MAX))
+
+ This attribute specifies additional detailed and technical
+ information about the job. The Printer NEED NOT localize the
+ message(s), since they are intended for use by the system
+ administrator or other experienced technical persons. Localization
+ might obscure the technical meaning of such messages. Clients MUST
+ NOT attempt to parse the value of this attribute. See "job-
+ document-access-errors" (section 4.3.11) for additional errors that a
+ program can process.
+
+4.3.11 job-document-access-errors (1setOf text(MAX))
+
+ This attribute provides additional information about each document
+ access error for this job encountered by the Printer after it
+ returned a response to the Print-URI or Send-URI operation and
+ subsequently attempted to access document(s) supplied in the Print-
+ URI or Send-URI operation. For errors in the protocol that is
+ identified by the URI scheme in the "document-uri" operation
+ attribute, such as 'http:' or 'ftp:', the error code is returned in
+ parentheses, followed by the URI. For example:
+
+ (404) http://ftp.pwg.org/pub/pwg/ipp/new_MOD/ipp-model-v11.pdf
+
+ Most Internet protocols use decimal error codes (unlike IPP), so the
+ ASCII error code representation is in decimal.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 118]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.3.12 number-of-documents (integer(0:MAX))
+
+ This attribute indicates the number of documents in the job, i.e.,
+ the number of Send-Document, Send-URI, Print-Job, or Print-URI
+ operations that the Printer has accepted for this job, regardless of
+ whether the document data has reached the Printer object or not.
+
+ Implementations supporting the OPTIONAL Create-Job/Send-
+ Document/Send-URI operations SHOULD support this attribute so that
+ clients can query the number of documents in each job.
+
+4.3.13 output-device-assigned (name(127))
+
+ This attribute identifies the output device to which the Printer
+ object has assigned this job. If an output device implements an
+ embedded Printer object, the Printer object NEED NOT set this
+ attribute. If a print server implements a Printer object, the value
+ MAY be empty (zero- length string) or not returned until the Printer
+ object assigns an output device to the job. This attribute is
+ particularly useful when a single Printer object supports multiple
+ devices (so called "fan-out" - see section 2.1).
+
+4.3.14 Event Time Job Description Attributes
+
+ This section defines the Job Description attributes that indicate the
+ time at which certain events occur for a job. If the job event has
+ not yet occurred, then the IPP object MUST return the 'no-value'
+ out-of-band value (see the beginning of Section 4.1). The "time-at-
+ xxx(integer)" attributes represent time as an 'integer' representing
+ the number of seconds since the device was powered up (informally
+ called "time ticks"). The "date-time-at-xxx(dateTime)" attributes
+ represent time as 'dateTime' representing date and time (including an
+ offset from UTC).
+
+ In order to populate these attributes, the Printer object copies the
+ value(s) of the following Printer Description attributes at the time
+ the event occurs:
+
+ 1. the value in the Printer's "printer-up-time" attribute for the
+ "time-at-xxx(integer)" attributes
+
+ 2. the value in the Printer's "printer-current-time" attribute for
+ the "date-time-at-xxx(dateTime)" attributes.
+
+ If the Printer resets its "printer-up-time" attribute to 1 on power-
+ up (see section 4.4.29) and has persistent jobs, then it MUST change
+ all of jobs' "time-at-xxx(integer)" (time tick) job attributes whose
+ events have occurred either to:
+
+
+
+Hastings, et al. Standards Track [Page 119]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 1. 0 to indicate that the event happened before the most recent
+ power up OR
+
+ 2. the negative of the number of seconds before the most recent
+ power-up that the event took place, though the negative number
+ NEED NOT reflect the exact number of seconds.
+
+ If a client queries a "time-at-xxx(integer)" time tick Job attribute
+ and finds the value to be 0 or negative, the client MUST assume that
+ the event occurred in some life other than the Printer's current
+ life.
+
+ Note: A Printer does not change the values of any "date-time-at-
+ xxx(dateTime)" job attributes on power-up.
+
+4.3.14.1 time-at-creation (integer(MIN:MAX))
+
+ This REQUIRED attribute indicates the time at which the Job object
+ was created.
+
+4.3.14.2 time-at-processing (integer(MIN:MAX))
+
+ This REQUIRED attribute indicates the time at which the Job object
+ first began processing after the create operation or the most recent
+ Restart-Job operation. The out-of-band 'no-value' value is returned
+ if the job has not yet been in the 'processing' state (see the
+ beginning of Section 4.1).
+
+4.3.14.3 time-at-completed (integer(MIN:MAX))
+
+ This REQUIRED attribute indicates the time at which the Job object
+ completed (or was canceled or aborted). The out-of-band 'no-value'
+ value is returned if the job has not yet completed, been canceled, or
+ aborted (see the beginning of Section 4.1).
+
+4.3.14.4 job-printer-up-time (integer(1:MAX))
+
+ This REQUIRED Job Description attribute indicates the amount of time
+ (in seconds) that the Printer implementation has been up and running.
+ This attribute is an alias for the "printer-up-time" Printer
+ Description attribute (see Section 4.4.29).
+
+ A client MAY request this attribute in a Get-Job-Attributes or Get-
+ Jobs request and use the value returned in combination with other
+ requested Event Time Job Description Attributes in order to display
+ time attributes to a user. The difference between this attribute and
+ the 'integer' value of a "time-at-xxx" attribute is the number of
+
+
+
+
+Hastings, et al. Standards Track [Page 120]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ seconds ago that the "time-at-xxx" event occurred. A client can
+ compute the wall-clock time at which the "time-at-xxx" event occurred
+ by subtracting this difference from the client's wall-clock time.
+
+4.3.14.5 date-time-at-creation (dateTime)
+
+ This attribute indicates the date and time at which the Job object
+ was created.
+
+4.3.14.6 date-time-at-processing (dateTime)
+
+ This attribute indicates the date and time at which the Job object
+ first began processing after the create operation or the most recent
+ Restart-Job operation.
+
+4.3.14.7 date-time-at-completed (dateTime)
+
+ This attribute indicates the date and time at which the Job object
+ completed (or was canceled or aborted).
+
+4.3.15 number-of-intervening-jobs (integer(0:MAX))
+
+ This attribute indicates the number of jobs that are "ahead" of this
+ job in the relative chronological order of expected time to complete
+ (i.e., the current scheduled order). For efficiency, it is only
+ necessary to calculate this value when an operation is performed that
+ requests this attribute.
+
+4.3.16 job-message-from-operator (text(127))
+
+ This attribute provides a message from an operator, system
+ administrator or "intelligent" process to indicate to the end user
+ the reasons for modification or other management action taken on a
+ job.
+
+4.3.17 Job Size Attributes
+
+ This sub-section defines job attributes that describe the size of the
+ job. These attributes are not intended to be counters; they are
+ intended to be useful routing and scheduling information if known.
+ For these attributes, the Printer object may try to compute the value
+ if it is not supplied in the create request. Even if the client does
+ supply a value for these three attributes in the create request, the
+ Printer object MAY choose to change the value if the Printer object
+ is able to compute a value which is more accurate than the client
+ supplied value. The Printer object may be able to determine the
+ correct value for these attributes either right at job submission
+ time or at any later point in time.
+
+
+
+Hastings, et al. Standards Track [Page 121]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.3.17.1 job-k-octets (integer(0:MAX))
+
+ This attribute specifies the total size of the document(s) in K
+ octets, i.e., in units of 1024 octets requested to be processed in
+ the job. The value MUST be rounded up, so that a job between 1 and
+ 1024 octets MUST be indicated as being 1, 1025 to 2048 MUST be 2,
+ etc.
+
+ This value MUST NOT include the multiplicative factors contributed by
+ the number of copies specified by the "copies" attribute, independent
+ of whether the device can process multiple copies without making
+ multiple passes over the job or document data and independent of
+ whether the output is collated or not. Thus the value is independent
+ of the implementation and indicates the size of the document(s)
+ measured in K octets independent of the number of copies.
+
+ This value MUST also not include the multiplicative factor due to a
+ copies instruction embedded in the document data. If the document
+ data actually includes replications of the document data, this value
+ will include such replication. In other words, this value is always
+ the size of the source document data, rather than a measure of the
+ hardcopy output to be produced.
+
+4.3.17.2 job-impressions (integer(0:MAX))
+
+ This attribute specifies the total size in number of impressions of
+ the document(s) being submitted (see the definition of impression in
+ section 12.2.5).
+
+ As with "job-k-octets", this value MUST NOT include the
+ multiplicative factors contributed by the number of copies specified
+ by the "copies" attribute, independent of whether the device can
+ process multiple copies without making multiple passes over the job
+ or document data and independent of whether the output is collated or
+ not. Thus the value is independent of the implementation and
+ reflects the size of the document(s) measured in impressions
+ independent of the number of copies.
+
+ As with "job-k-octets", this value MUST also not include the
+ multiplicative factor due to a copies instruction embedded in the
+ document data. If the document data actually includes replications
+ of the document data, this value will include such replication. In
+ other words, this value is always the number of impressions in the
+ source document data, rather than a measure of the number of
+ impressions to be produced by the job.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 122]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.3.17.3 job-media-sheets (integer(0:MAX))
+
+ This attribute specifies the total number of media sheets to be
+ produced for this job.
+
+ Unlike the "job-k-octets" and the "job-impressions" attributes, this
+ value MUST include the multiplicative factors contributed by the
+ number of copies specified by the "copies" attribute and a 'number of
+ copies' instruction embedded in the document data, if any. This
+ difference allows the system administrator to control the lower and
+ upper bounds of both (1) the size of the document(s) with "job-k-
+ octets-supported" and "job-impressions-supported" and (2) the size of
+ the job with "job-media-sheets-supported".
+
+4.3.18 Job Progress Attributes
+
+ This sub-section defines job attributes that describe the progress of
+ the job. These attributes are intended to be counters. That is, the
+ value for a job that has not started processing MUST be 0. When the
+ job's "job-state" is 'processing' or 'processing-stopped', this value
+ is intended to contain the amount of the job that has been processed
+ to the time at which the attributes are requested. When the job
+ enters the 'completed', 'canceled', or 'aborted' states, these values
+ are the final values for the job.
+
+4.3.18.1 job-k-octets-processed (integer(0:MAX))
+
+ This attribute specifies the total number of octets processed in K
+ octets, i.e., in units of 1024 octets so far. The value MUST be
+ rounded up, so that a job between 1 and 1024 octets inclusive MUST be
+ indicated as being 1, 1025 to 2048 inclusive MUST be 2, etc.
+
+ For implementations where multiple copies are produced by the
+ interpreter with only a single pass over the data, the final value
+ MUST be equal to the value of the "job-k-octets" attribute. For
+ implementations where multiple copies are produced by the interpreter
+ by processing the data for each copy, the final value MUST be a
+ multiple of the value of the "job-k-octets" attribute.
+
+4.3.18.2 job-impressions-completed (integer(0:MAX))
+
+ This job attribute specifies the number of impressions completed for
+ the job so far. For printing devices, the impressions completed
+ includes interpreting, marking, and stacking the output.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 123]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.3.18.3 job-media-sheets-completed (integer(0:MAX))
+
+ This job attribute specifies the media-sheets completed marking and
+ stacking for the entire job so far whether those sheets have been
+ processed on one side or on both.
+
+4.3.19 attributes-charset (charset)
+
+ This REQUIRED attribute is populated using the value in the client
+ supplied "attributes-charset" attribute in the create request. It
+ identifies the charset (coded character set and encoding method) used
+ by any Job attributes with attribute syntax 'text' and 'name' that
+ were supplied by the client in the create request. See Section 3.1.4
+ for a complete description of the "attributes-charset" operation
+ attribute.
+
+ This attribute does not indicate the charset in which the 'text' and
+ 'name' values are stored internally in the Job object. The internal
+ charset is implementation-defined. The IPP object MUST convert from
+ whatever the internal charset is to that being requested in an
+ operation as specified in Section 3.1.4.
+
+4.3.20 attributes-natural-language (naturalLanguage)
+
+ This REQUIRED attribute is populated using the value in the client
+ supplied "attributes-natural-language" attribute in the create
+ request. It identifies the natural language used for any Job
+ attributes with attribute syntax 'text' and 'name' that were supplied
+ by the client in the create request. See Section 3.1.4 for a
+ complete description of the "attributes-natural-language" operation
+ attribute. See Sections 4.1.1.2 and 4.1.2.2 for how a Natural
+ Language Override may be supplied explicitly for each 'text' and
+ 'name' attribute value that differs from the value identified by the
+ "attributes-natural-language" attribute.
+
+4.4 Printer Description Attributes
+
+ These attributes form the attribute group called "printer-
+ description". The following table summarizes these attributes, their
+ syntax, and whether or not they are REQUIRED for a Printer object to
+ support. If they are not indicated as REQUIRED, they are OPTIONAL.
+ The maximum size in octets for 'text' and 'name' attributes is
+ indicated in parenthesizes.
+
+ Note: How these attributes are set by an Administrator is outside the
+ scope of this IPP/1.1 document.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 124]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ +----------------------------+---------------------------+-----------+
+ | Attribute | Syntax | REQUIRED? |
+ +----------------------------+---------------------------+-----------+
+ | printer-uri-supported | 1setOf uri | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | uri-security-supported | 1setOf type2 keyword | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | uri-authentication- | 1setOf type2 keyword | REQUIRED |
+ | supported | | |
+ +----------------------------+---------------------------+-----------+
+ | printer-name | name (127) | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | printer-location | text (127) | |
+ +----------------------------+---------------------------+-----------+
+ | printer-info | text (127) | |
+ +----------------------------+---------------------------+-----------+
+ | printer-more-info | uri | |
+ +----------------------------+---------------------------+-----------+
+ | printer-driver-installer | uri | |
+ +----------------------------+---------------------------+-----------+
+ | printer-make-and-model | text (127) | |
+ +----------------------------+---------------------------+-----------+
+ | printer-more-info- | uri | |
+ | manufacturer | | |
+ +----------------------------+---------------------------+-----------+
+ | printer-state | type1 enum | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | printer-state-reasons | 1setOf type2 keyword | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | printer-state-message | text (MAX) | |
+ +----------------------------+---------------------------+-----------+
+ | ipp-versions-supported | 1setOf type2 keyword | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | operations-supported | 1setOf type2 enum | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | multiple-document-jobs- | boolean | |
+ | supported | | |
+ +----------------------------+---------------------------+-----------+
+ | charset-configured | charset | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | charset-supported | 1setOf charset | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | natural-language-configured| naturalLanguage | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | generated-natural-language-| 1setOf naturalLanguage | REQUIRED |
+ | supported | | |
+ +----------------------------+---------------------------+-----------+
+ | document-format-default | mimeMediaType | REQUIRED |
+
+
+
+Hastings, et al. Standards Track [Page 125]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ +----------------------------+---------------------------+-----------+
+ | document-format-supported | 1setOf mimeMediaType | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | printer-is-accepting-jobs | boolean | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | queued-job-count | integer (0:MAX) | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | printer-message-from- | text (127) | |
+ | operator | | |
+ +----------------------------+---------------------------+-----------+
+ | color-supported | boolean | |
+ +----------------------------+---------------------------+-----------+
+ | reference-uri-schemes- | 1setOf uriScheme | |
+ | supported | | |
+ +----------------------------+---------------------------+-----------+
+ | pdl-override-supported | type2 keyword | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | printer-up-time | integer (1:MAX) | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | printer-current-time | dateTime | |
+ +----------------------------+---------------------------+-----------+
+ | multiple-operation-time-out| integer (1:MAX) | |
+ +----------------------------+---------------------------+-----------+
+ | compression-supported | 1setOf type3 keyword | REQUIRED |
+ +----------------------------+---------------------------+-----------+
+ | job-k-octets-supported | rangeOfInteger (0:MAX) | |
+ +----------------------------+---------------------------+-----------+
+ | job-impressions-supported | rangeOfInteger (0:MAX) | |
+ +----------------------------+---------------------------+-----------+
+ | job-media-sheets-supported | rangeOfInteger (0:MAX) | |
+ +----------------------------+---------------------------+-----------+
+ | pages-per-minute | integer(0:MAX) | |
+ +----------------------------+---------------------------+-----------+
+ | pages-per-minute-color | integer(0:MAX) | |
+ +----------------------------+---------------------------+-----------+
+
+4.4.1 printer-uri-supported (1setOf uri)
+
+ This REQUIRED Printer attribute contains at least one URI for the
+ Printer object. It OPTIONALLY contains more than one URI for the
+ Printer object. An administrator determines a Printer object's
+ URI(s) and configures this attribute to contain those URIs by some
+ means outside the scope of this IPP/1.1 document. The precise format
+ of this URI is implementation dependent and depends on the protocol.
+ See the next two sections for a description of the "uri-security-
+ supported" and "uri-authentication-supported" attributes, both of
+
+
+
+
+
+Hastings, et al. Standards Track [Page 126]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ which are the REQUIRED companion attributes to this "printer-uri-
+ supported" attribute. See section 2.4 on Printer object identity and
+ section 8.2 on security and URIs for more information.
+
+4.4.2 uri-authentication-supported (1setOf type2 keyword)
+
+ This REQUIRED Printer attribute MUST have the same cardinality
+ (contain the same number of values) as the "printer-uri-supported"
+ attribute. This attribute identifies the Client Authentication
+ mechanism associated with each URI listed in the "printer-uri-
+ supported" attribute. The Printer object uses the specified mechanism
+ to identify the authenticated user (see section 8.3). The "i th"
+ value in "uri-authentication-supported" corresponds to the "i th"
+ value in "printer-uri-supported" and it describes the authentication
+ mechanisms used by the Printer when accessed via that URI. See
+ [RFC2910] for more details on Client Authentication.
+
+ The following standard keyword values are defined:
+
+ 'none': There is no authentication mechanism associated with the
+ URI. The Printer object assumes that the authenticated user is
+ "anonymous".
+ 'requesting-user-name': When a client performs an operation whose
+ target is the associated URI, the Printer object assumes that
+ the authenticated user is specified by the "requesting-user-
+ name" Operation attribute (see section 8.3). If the
+ "requesting-user-name" attribute is absent in a request, the
+ Printer object assumes that the authenticated user is
+ "anonymous".
+ 'basic': When a client performs an operation whose target is the
+ associated URI, the Printer object challenges the client with
+ HTTP basic authentication [RFC2617]. The Printer object assumes
+ that the authenticated user is the name received via the basic
+ authentication mechanism.
+ 'digest': When a client performs an operation whose target is the
+ associated URI, the Printer object challenges the client with
+ HTTP digest authentication [RFC2617]. The Printer object
+ assumes that the authenticated user is the name received via
+ the digest authentication mechanism.
+ 'certificate': When a client performs an operation whose target is
+ the associated URI, the Printer object expects the client to
+ provide a certificate. The Printer object assumes that the
+ authenticated user is the textual name contained within the
+ certificate.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 127]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.4.3 uri-security-supported (1setOf type2 keyword)
+
+ This REQUIRED Printer attribute MUST have the same cardinality
+ (contain the same number of values) as the "printer-uri-supported"
+ attribute. This attribute identifies the security mechanisms used
+ for each URI listed in the "printer-uri-supported" attribute. The "i
+ th" value in "uri-security-supported" corresponds to the "i th" value
+ in "printer-uri-supported" and it describes the security mechanisms
+ used for accessing the Printer object via that URI. See [RFC2910]
+ for more details on security mechanisms.
+
+ The following standard keyword values are defined:
+
+ 'none': There are no secure communication channel protocols in use
+ for the given URI.
+ 'ssl3': SSL3 [SSL] is the secure communications channel protocol
+ in use for the given URI.
+ 'tls': TLS [RFC2246] is the secure communications channel
+ protocol in use for the given URI.
+
+ This attribute is orthogonal to the definition of a Client
+ Authentication mechanism. Specifically, 'none' does not exclude
+ Client Authentication. See section 4.4.2.
+
+ Consider the following example. For a single Printer object, an
+ administrator configures the "printer-uri-supported", "uri-
+ authentication-supported" and "uri-security-supported" attributes as
+ follows:
+
+ "printer-uri-supported": 'xxx://acme.com/open-use-printer',
+ 'xxx://acme.com/restricted-use-printer',
+ 'xxx://acme.com/private-printer'
+ "uri-authentication-supported": 'none', 'digest', 'basic'
+ "uri-security-supported": 'none', 'none', 'tls'
+
+ Note: 'xxx' is not a valid scheme. See the IPP/1.1 "Transport and
+ Encoding" document [RFC2910] for the actual URI schemes to be used in
+ object target attributes.
+
+ In this case, one Printer object has three URIs.
+
+ - For the first URI, 'xxx://acme.com/open-use-printer', the value
+ 'none' in "uri-security-supported" indicates that there is no
+ secure channel protocol configured to run under HTTP. The value
+ of 'none' in "uri-authentication-supported" indicates that all
+ users are 'anonymous'. There will be no challenge and the
+ Printer will ignore "requesting-user-name".
+
+
+
+
+Hastings, et al. Standards Track [Page 128]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - For the second URI, 'xxx://acme.com/restricted-use-printer', the
+ value 'none' in "uri-security-supported" indicates that there is
+ no secure channel protocol configured to run under HTTP. The
+ value of 'digest' in "uri-authentication-supported" indicates
+ that the Printer will issue a challenge and that the Printer
+ will use the name supplied by the digest mechanism to determine
+ the authenticated user (see section 8.3).
+ - For the third URI, 'xxx://acme.com/private-printer', the value
+ 'tls' in "uri-security-supported" indicates that TLS is being
+ used to secure the channel. The client SHOULD be prepared to
+ use TLS framing to negotiate an acceptable ciphersuite to use
+ while communicating with the Printer object. In this case, the
+ name implies the use of a secure communications channel, but the
+ fact is made explicit by the presence of the 'tls' value in
+ "uri-security-supported". The client does not need to resort to
+ understanding which security it must use by following naming
+ conventions or by parsing the URI to determine which security
+ mechanisms are implied. The value of 'basic' in "uri-
+ authentication-supported" indicates that the Printer will issue
+ a challenge and that the Printer will use the name supplied by
+ the digest mechanism to determine the authenticated user (see
+ section 8.3). Because this challenge occurs in a tls session,
+ the channel is secure.
+
+ It is expected that many IPP Printer objects will be configured to
+ support only one channel (either configured to use TLS access or not)
+ and only one authentication mechanism. Such Printer objects only have
+ one URI listed in the "printer-uri-supported" attribute. No matter
+ the configuration of the Printer object (whether it has only one URI
+ or more than one URI), a client MUST supply only one URI in the
+ target "printer-uri" operation attribute.
+
+4.4.4 printer-name (name(127))
+
+ This REQUIRED Printer attribute contains the name of the Printer
+ object. It is a name that is more end-user friendly than a URI. An
+ administrator determines a printer's name and sets this attribute to
+ that name. This name may be the last part of the printer's URI or it
+ may be unrelated. In non-US-English locales, a name may contain
+ characters that are not allowed in a URI.
+
+4.4.5 printer-location (text(127))
+
+ This Printer attribute identifies the location of the device. This
+ could include things like: "in Room 123A, second floor of building
+ XYZ".
+
+
+
+
+
+Hastings, et al. Standards Track [Page 129]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.4.6 printer-info (text(127))
+
+ This Printer attribute identifies the descriptive information about
+ this Printer object. This could include things like: "This printer
+ can be used for printing color transparencies for HR presentations",
+ or "Out of courtesy for others, please print only small (1-5 page)
+ jobs at this printer", or even "This printer is going away on July 1,
+ 1997, please find a new printer".
+
+4.4.7 printer-more-info (uri)
+
+ This Printer attribute contains a URI used to obtain more information
+ about this specific Printer object. For example, this could be an
+ HTTP type URI referencing an HTML page accessible to a Web Browser.
+ The information obtained from this URI is intended for end user
+ consumption. Features outside the scope of IPP can be accessed from
+ this URI. The information is intended to be specific to this printer
+ instance and site specific services (e.g. job pricing, services
+ offered, end user assistance). The device manufacturer may initially
+ populate this attribute.
+
+4.4.8 printer-driver-installer (uri)
+
+ This Printer attribute contains a URI to use to locate the driver
+ installer for this Printer object. This attribute is intended for
+ consumption by automata. The mechanics of print driver installation
+ is outside the scope of this IPP/1.1 document. The device
+ manufacturer may initially populate this attribute.
+
+4.4.9 printer-make-and-model (text(127))
+
+ This Printer attribute identifies the make and model of the device.
+ The device manufacturer may initially populate this attribute.
+
+4.4.10 printer-more-info-manufacturer (uri)
+
+ This Printer attribute contains a URI used to obtain more information
+ about this type of device. The information obtained from this URI is
+ intended for end user consumption. Features outside the scope of IPP
+ can be accessed from this URI (e.g., latest firmware, upgrades, print
+ drivers, optional features available, details on color support). The
+ information is intended to be germane to this printer without regard
+ to site specific modifications or services. The device manufacturer
+ may initially populate this attribute.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 130]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.4.11 printer-state (type1 enum)
+
+ This REQUIRED Printer attribute identifies the current state of the
+ device. The "printer-state reasons" attribute augments the
+ "printer-state" attribute to give more detailed information about the
+ Printer in the given printer state.
+
+ A Printer object need only update this attribute before responding to
+ an operation which requests the attribute; the Printer object NEED
+ NOT update this attribute continually, since asynchronous event
+ notification is not part of IPP/1.1. A Printer NEED NOT implement
+ all values if they are not applicable to a given implementation.
+
+ The following standard enum values are defined:
+
+ Value Symbolic Name and Description
+
+ '3' 'idle': Indicates that new jobs can start processing without
+ waiting.
+ '4' 'processing': Indicates that jobs are processing; new jobs
+ will wait before processing.
+ '5' 'stopped': Indicates that no jobs can be processed and
+ intervention is required.
+
+ Values of "printer-state-reasons", such as 'spool-area-full' and
+ 'stopped-partly', MAY be used to provide further information.
+
+4.4.12 printer-state-reasons (1setOf type2 keyword)
+
+ This REQUIRED Printer attribute supplies additional detail about the
+ device's state. Some of the these value definitions indicate
+ conformance requirements; the rest are OPTIONAL.
+
+ Each keyword value MAY have a suffix to indicate its level of
+ severity. The three levels are: report (least severe), warning, and
+ error (most severe).
+
+ - '-report': This suffix indicates that the reason is a "report".
+ An implementation may choose to omit some or all reports. Some
+ reports specify finer granularity about the printer state;
+ others serve as a precursor to a warning. A report MUST contain
+ nothing that could affect the printed output.
+ - '-warning': This suffix indicates that the reason is a
+ "warning". An implementation may choose to omit some or all
+ warnings. Warnings serve as a precursor to an error. A warning
+ MUST contain nothing that prevents a job from completing, though
+ in some cases the output may be of lower quality.
+
+
+
+
+Hastings, et al. Standards Track [Page 131]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - '-error': This suffix indicates that the reason is an "error".
+ An implementation MUST include all errors. If this attribute
+ contains one or more errors, printer MUST be in the stopped
+ state.
+
+ If the implementation does not add any one of the three suffixes, all
+ parties MUST assume that the reason is an "error".
+
+ If a Printer object controls more than one output device, each value
+ of this attribute MAY apply to one or more of the output devices. An
+ error on one output device that does not stop the Printer object as a
+ whole MAY appear as a warning in the Printer's "printer-state-reasons
+ attribute". If the "printer-state" for such a Printer has a value of
+ 'stopped', then there MUST be an error reason among the values in the
+ "printer-state-reasons" attribute.
+
+ The following standard keyword values are defined:
+
+ 'other': The device has detected an error other than one listed in
+ this document.
+ 'none': There are not reasons. This state reason is semantically
+ equivalent to "printer-state-reasons" without any value and
+ MUST be used, since the 1setOf attribute syntax requires at
+ least one value.
+ 'media-needed': A tray has run out of media.
+ 'media-jam': The device has a media jam.
+ 'moving-to-paused': Someone has paused the Printer object using
+ the Pause-Printer operation (see section 3.2.7) or other means,
+ but the device(s) are taking an appreciable time to stop.
+ Later, when all output has stopped, the "printer-state" becomes
+ 'stopped', and the 'paused' value replaces the 'moving-to-
+ paused' value in the "printer-state-reasons" attribute. This
+ value MUST be supported, if the Pause-Printer operation is
+ supported and the implementation takes significant time to
+ pause a device in certain circumstances.
+ 'paused': Someone has paused the Printer object using the Pause-
+ Printer operation (see section 3.2.7) or other means and the
+ Printer object's "printer-state" is 'stopped'. In this state,
+ a Printer MUST NOT produce printed output, but it MUST perform
+ other operations requested by a client. If a Printer had been
+ printing a job when the Printer was paused, the Printer MUST
+ resume printing that job when the Printer is no longer paused
+ and leave no evidence in the printed output of such a pause.
+ This value MUST be supported, if the Pause-Printer operation is
+ supported.
+ 'shutdown': Someone has removed a Printer object from service, and
+ the device may be powered down or physically removed. In this
+ state, a Printer object MUST NOT produce printed output, and
+
+
+
+Hastings, et al. Standards Track [Page 132]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ unless the Printer object is realized by a print server that is
+ still active, the Printer object MUST perform no other
+ operations requested by a client, including returning this
+ value. If a Printer object had been printing a job when it was
+ shutdown, the Printer NEED NOT resume printing that job when
+ the Printer is no longer shutdown. If the Printer resumes
+ printing such a job, it may leave evidence in the printed
+ output of such a shutdown, e.g. the part printed before the
+ shutdown may be printed a second time after the shutdown.
+ 'connecting-to-device': The Printer object has scheduled a job on
+ the output device and is in the process of connecting to a
+ shared network output device (and might not be able to actually
+ start printing the job for an arbitrarily long time depending
+ on the usage of the output device by other servers on the
+ network).
+ 'timed-out': The server was able to connect to the output device
+ (or is always connected), but was unable to get a response from
+ the output device.
+ 'stopping': The Printer object is in the process of stopping the
+ device and will be stopped in a while. When the device is
+ stopped, the Printer object will change the Printer object's
+ state to 'stopped'. The 'stopping-warning' reason is never an
+ error, even for a Printer with a single output device. When an
+ output-device ceases accepting jobs, the Printer will have this
+ reason while the output device completes printing.
+ 'stopped-partly': When a Printer object controls more than one
+ output device, this reason indicates that one or more output
+ devices are stopped. If the reason is a report, fewer than
+ half of the output devices are stopped. If the reason is a
+ warning, fewer than all of the output devices are stopped.
+ 'toner-low': The device is low on toner.
+ 'toner-empty': The device is out of toner.
+ 'spool-area-full': The limit of persistent storage allocated for
+ spooling has been reached. The Printer is temporarily unable
+ to accept more jobs. The Printer will remove this value when
+ it is able to accept more jobs. This value SHOULD be used by a
+ non-spooling Printer that only accepts one or a small number
+ jobs at a time or a spooling Printer that has filled the spool
+ space.
+ 'cover-open': One or more covers on the device are open.
+ 'interlock-open': One or more interlock devices on the printer are
+ unlocked.
+ 'door-open': One or more doors on the device are open.
+ 'input-tray-missing': One or more input trays are not in the
+ device.
+ 'media-low': At least one input tray is low on media.
+ 'media-empty': At least one input tray is empty.
+
+
+
+
+Hastings, et al. Standards Track [Page 133]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'output-tray-missing': One or more output trays are not in the
+ device
+ 'output-area-almost-full': One or more output area is almost full
+ (e.g. tray, stacker, collator).
+ 'output-area-full': One or more output area is full. (e.g. tray,
+ stacker, collator)
+ 'marker-supply-low': The device is low on at least one marker
+ supply. (e.g. toner, ink, ribbon)
+ 'marker-supply-empty: The device is out of at least one marker
+ supply. (e.g. toner, ink, ribbon)
+ 'marker-waste-almost-full': The device marker supply waste
+ receptacle is almost full.
+ 'marker-waste-full': The device marker supply waste receptacle is
+ full.
+ 'fuser-over-temp': The fuser temperature is above normal.
+ 'fuser-under-temp': The fuser temperature is below normal.
+ 'opc-near-eol': The optical photo conductor is near end of life.
+ 'opc-life-over': The optical photo conductor is no longer
+ functioning.
+ 'developer-low': The device is low on developer.
+ 'developer-empty: The device is out of developer.
+ 'interpreter-resource-unavailable': An interpreter resource is
+ unavailable (i.e. font, form)
+
+4.4.13 printer-state-message (text(MAX))
+
+ This Printer attribute specifies information about the "printer-
+ state" and "printer-state-reasons" attributes in human readable text.
+ If the Printer object supports this attribute, the Printer object
+ MUST be able to generate this message in any of the natural languages
+ identified by the Printer's "generated-natural-language-supported"
+ attribute (see the "attributes-natural-language" operation attribute
+ specified in Section 3.1.4.1).
+
+4.4.14 ipp-versions-supported (1setOf type2 keyword)
+
+ This REQUIRED attribute identifies the IPP protocol version(s) that
+ this Printer supports, including major and minor versions, i.e., the
+ version numbers for which this Printer implementation meets the
+ conformance requirements. For version number validation, the Printer
+ matches the (two-octet binary) "version-number" parameter supplied by
+ the client in each request (see sections 3.1.1 and 3.1.8) with the
+ (US-ASCII) keyword values of this attribute.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 134]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The following standard keyword values are defined:
+
+ '1.0': Meets the conformance requirement of IPP version 1.0 as
+ specified in RFC 2566 [RFC2566] and RFC 2565 [RFC2565]
+ including any extensions registered according to Section 6 and
+ any extension defined in this version or any future version of
+ the IPP "Model and Semantics" document or the IPP "Encoding and
+ Transport" document following the rules, if any, when the
+ "version-number" parameter is '1.0'.
+ '1.1': Meets the conformance requirement of IPP version 1.1 as
+ specified in this document and [RFC2910] including any
+ extensions registered according to Section 6 and any extension
+ defined in any future versions of the IPP "Model and Semantics"
+ document or the IPP Encoding and Transport document following
+ the rules, if any, when the "version-number" parameter is
+ '1.1'.
+
+4.4.15 operations-supported (1setOf type2 enum)
+
+ This REQUIRED Printer attribute specifies the set of supported
+ operations for this Printer object and contained Job objects.
+
+ This attribute is encoded as any other enum attribute syntax
+ according to [RFC2910] as 32-bits. However, all 32-bit enum values
+ for this attribute MUST NOT exceed 0x00008FFF, since these same
+ values are also passed in two octets in the "operation-id" parameter
+ (see section 3.1.1) in each Protocol request with the two high order
+ octets omitted in order to indicate the operation being performed
+ [RFC2910].
+
+ The following standard enum and "operation-id" (see section 3.1.2)
+ values are defined:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 135]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Value Operation Name
+ ----------------- -------------------------------------
+
+ 0x0000 reserved, not used
+ 0x0001 reserved, not used
+ 0x0002 Print-Job
+ 0x0003 Print-URI
+ 0x0004 Validate-Job
+ 0x0005 Create-Job
+ 0x0006 Send-Document
+ 0x0007 Send-URI
+ 0x0008 Cancel-Job
+ 0x0009 Get-Job-Attributes
+ 0x000A Get-Jobs
+ 0x000B Get-Printer-Attributes
+ 0x000C Hold-Job
+ 0x000D Release-Job
+ 0x000E Restart-Job
+ 0x000F reserved for a future operation
+ 0x0010 Pause-Printer
+ 0x0011 Resume-Printer
+ 0x0012 Purge-Jobs
+ 0x0013-0x3FFF reserved for future IETF standards track
+ operations (see section 6.4)
+ 0x4000-0x8FFF reserved for vendor extensions (see section 6.4)
+
+4.4.16 multiple-document-jobs-supported (boolean)
+
+ This Printer attribute indicates whether or not the Printer supports
+ more than one document per job, i.e., more than one Send-Document or
+ Send-Data operation with document data. If the Printer supports the
+ Create-Job and Send-Document operations (see section 3.2.4 and
+ 3.3.1), it MUST support this attribute.
+
+4.4.17 charset-configured (charset)
+
+ This REQUIRED Printer attribute identifies the charset that the
+ Printer object has been configured to represent 'text' and 'name'
+ Printer attributes that are set by the operator, system
+ administrator, or manufacturer, i.e., for "printer-name" (name),
+ "printer-location" (text), "printer-info" (text), and "printer-make-
+ and-model" (text). Therefore, the value of the Printer object's
+ "charset-configured" attribute MUST also be among the values of the
+ Printer object's "charset-supported" attribute.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 136]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.4.18 charset-supported (1setOf charset)
+
+ This REQUIRED Printer attribute identifies the set of charsets that
+ the Printer and contained Job objects support in attributes with
+ attribute syntax 'text' and 'name'. At least the value 'utf-8' MUST
+ be present, since IPP objects MUST support the UTF-8 [RFC2279]
+ charset. If a Printer object supports a charset, it means that for
+ all attributes of syntax 'text' and 'name' the IPP object MUST (1)
+ accept the charset in requests and return the charset in responses as
+ needed.
+
+ If more charsets than UTF-8 are supported, the IPP object MUST
+ perform charset conversion between the charsets as described in
+ Section 3.1.4.2.
+
+4.4.19 natural-language-configured (naturalLanguage)
+
+ This REQUIRED Printer attribute identifies the natural language that
+ the Printer object has been configured to represent 'text' and 'name'
+ Printer attributes that are set by the operator, system
+ administrator, or manufacturer, i.e., for "printer-name" (name),
+ "printer-location" (text), "printer-info" (text), and "printer-make-
+ and-model" (text). When returning these Printer attributes, the
+ Printer object MAY return them in the configured natural language
+ specified by this attribute, instead of the natural language
+ requested by the client in the "attributes-natural-language"
+ operation attribute. See Section 3.1.4.1 for the specification of
+ the OPTIONAL multiple natural language support. Therefore, the value
+ of the Printer object's "natural-language-configured" attribute MUST
+ also be among the values of the Printer object's "generated-natural-
+ language-supported" attribute.
+
+4.4.20 generated-natural-language-supported (1setOf naturalLanguage)
+
+ This REQUIRED Printer attribute identifies the natural language(s)
+ that the Printer object and contained Job objects support in
+ attributes with attribute syntax 'text' and 'name'. The natural
+ language(s) supported depends on implementation and/or configuration.
+ Unlike charsets, IPP objects MUST accept requests with any natural
+ language or any Natural Language Override whether the natural
+ language is supported or not.
+
+ If a Printer object supports a natural language, it means that for
+ any of the attributes for which the Printer or Job object generates
+ messages, i.e., for the "job-state-message" and "printer-state-
+ message" attributes and Operation Messages (see Section 3.1.5) in
+ operation responses, the Printer and Job objects MUST be able to
+
+
+
+
+Hastings, et al. Standards Track [Page 137]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ generate messages in any of the Printer's supported natural
+ languages. See section 3.1.4 for the definition of 'text' and 'name'
+ attributes in operation requests and responses.
+
+ Note: A Printer object that supports multiple natural languages,
+ often has separate catalogs of messages, one for each natural
+ language supported.
+
+4.4.21 document-format-default (mimeMediaType)
+
+ This REQUIRED Printer attribute identifies the document format that
+ the Printer object has been configured to assume if the client does
+ not supply a "document-format" operation attribute in any of the
+ operation requests that supply document data. The standard values
+ for this attribute are Internet Media types (sometimes called MIME
+ types). For further details see the description of the
+ 'mimeMediaType' attribute syntax in Section 4.1.9.
+
+4.4.22 document-format-supported (1setOf mimeMediaType)
+
+ This REQUIRED Printer attribute identifies the set of document
+ formats that the Printer object and contained Job objects can
+ support. For further details see the description of the
+ 'mimeMediaType' attribute syntax in Section 4.1.9.
+
+4.4.23 printer-is-accepting-jobs (boolean)
+
+ This REQUIRED Printer attribute indicates whether the printer is
+ currently able to accept jobs, i.e., is accepting Print-Job, Print-
+ URI, and Create-Job requests. If the value is 'true', the printer is
+ accepting jobs. If the value is 'false', the Printer object is
+ currently rejecting any jobs submitted to it. In this case, the
+ Printer object returns the 'server-error-not-accepting-jobs' status
+ code.
+
+ This value is independent of the "printer-state" and "printer-state-
+ reasons" attributes because its value does not affect the current
+ job; rather it affects future jobs. This attribute, when 'false',
+ causes the Printer to reject jobs even when the "printer-state" is
+ 'idle' or, when 'true', causes the Printer object to accepts jobs
+ even when the "printer-state" is 'stopped'.
+
+4.4.24 queued-job-count (integer(0:MAX))
+
+ This REQUIRED Printer attribute contains a count of the number of
+ jobs that are either 'pending', 'processing', 'pending-held', or
+ 'processing-stopped' and is set by the Printer object.
+
+
+
+
+Hastings, et al. Standards Track [Page 138]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+4.4.25 printer-message-from-operator (text(127))
+
+ This Printer attribute provides a message from an operator, system
+ administrator or "intelligent" process to indicate to the end user
+ information or status of the printer, such as why it is unavailable
+ or when it is expected to be available.
+
+4.4.26 color-supported (boolean)
+
+ This Printer attribute identifies whether the device is capable of
+ any type of color printing at all, including highlight color. All
+ document instructions having to do with color are embedded within the
+ document PDL (none are external IPP attributes in IPP/1.1).
+
+ Note: end-users are able to determine the nature and details of the
+ color support by querying the "printer-more-info-manufacturer"
+ Printer attribute.
+
+4.4.27 reference-uri-schemes-supported (1setOf uriScheme)
+
+ This Printer attribute specifies which URI schemes are supported for
+ use in the "document-uri" operation attribute of the Print-URI or
+ Send-URI operation. If a Printer object supports these optional
+ operations, it MUST support the "reference-uri-schemes-supported"
+ Printer attribute with at least the following schemed URI value:
+
+ 'ftp': The Printer object will use an FTP 'get' operation as
+ defined in RFC 2228 [RFC2228] using FTP URLs as defined by
+ [RFC2396] and [RFC2316].
+
+ The Printer object MAY OPTIONALLY support other URI schemes (see
+ section 4.1.6).
+
+4.4.28 pdl-override-supported (type2 keyword)
+
+ This REQUIRED Printer attribute expresses the ability for a
+ particular Printer implementation to either attempt to override
+ document data instructions with IPP attributes or not.
+
+ This attribute takes on the following keyword values:
+
+ - 'attempted': This value indicates that the Printer object
+ attempts to make the IPP attribute values take precedence over
+ embedded instructions in the document data, however there is no
+ guarantee.
+ - 'not-attempted': This value indicates that the Printer object
+ makes no attempt to make the IPP attribute values take
+ precedence over embedded instructions in the document data.
+
+
+
+Hastings, et al. Standards Track [Page 139]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Section 15 contains a full description of how this attribute
+ interacts with and affects other IPP attributes, especially the
+ "ipp-attribute-fidelity" attribute.
+
+4.4.29 printer-up-time (integer(1:MAX))
+
+ This REQUIRED Printer attribute indicates the amount of time (in
+ seconds) that this Printer instance has been up and running. The
+ value is a monotonically increasing value starting from 1 when the
+ Printer object is started-up (initialized, booted, etc.). This value
+ is used to populate the Event Time Job Description Job attributes
+ "time-at-creation", "time-at-processing", and "time-at-completed"
+ (see section 4.3.14).
+
+ If the Printer object goes down at some value 'n', and comes back up,
+ the implementation MAY:
+
+ 1. Know how long it has been down, and resume at some value
+ greater than 'n', or
+ 2. Restart from 1.
+
+ In other words, if the device or devices that the Printer object is
+ representing are restarted or power cycled, the Printer object MAY
+ continue counting this value or MAY reset this value to 1 depending
+ on implementation. However, if the Printer object software ceases
+ running, and restarts without knowing the last value for "printer-
+ up-time", the implementation MUST reset this value to 1. If this
+ value is reset and the Printer has persistent jobs, the Printer MUST
+ reset the "time-at-xxx(integer) Event Time Job Description attributes
+ according to Section 4.3.14. An implementation MAY use both
+ implementation alternatives, depending on warm versus cold start,
+ respectively.
+
+4.4.30 printer-current-time (dateTime)
+
+ This Printer attribute indicates the current date and time. This
+ value is used to populate the Event Time Job Description attributes:
+ "date-time-at-creation", "date-time-at-processing", and "date-time-
+ at-completed" (see Section 4.3.14).
+
+ The date and time is obtained on a "best efforts basis" and does not
+ have to be that precise in order to work in practice. A Printer
+ implementation sets the value of this attribute by obtaining the date
+ and time via some implementation-dependent means, such as getting the
+ value from a network time server, initialization at time of
+ manufacture, or setting by an administrator. See [IPP-IIG] for
+ examples. If an implementation supports this attribute and the
+ implementation knows that it has not yet been set, then the
+
+
+
+Hastings, et al. Standards Track [Page 140]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ implementation MUST return the value of this attribute using the
+ out-of-band 'no-value' meaning not configured. See the beginning of
+ section 4.1.
+
+ The time zone of this attribute NEED NOT be the time zone used by
+ people located near the Printer object or device. The client MUST
+ NOT expect that the time zone of any received 'dateTime' value to be
+ in the time zone of the client or in the time zone of the people
+ located near the printer.
+
+ The client SHOULD display any dateTime attributes to the user in
+ client local time by converting the 'dateTime' value returned by the
+ server to the time zone of the client, rather than using the time
+ zone returned by the Printer in attributes that use the 'dateTime'
+ attribute syntax.
+
+4.4.31 multiple-operation-time-out (integer(1:MAX))
+
+ This Printer attributes identifies the minimum time (in seconds) that
+ the Printer object waits for additional Send-Document or Send-URI
+ operations to follow a still-open Job object before taking any
+ recovery actions, such as the ones indicated in section 3.3.1. If
+ the Printer object supports the Create-Job and Send-Document
+ operations (see section 3.2.4 and 3.3.1), it MUST support this
+ attribute.
+
+ It is RECOMMENDED that vendors supply a value for this attribute that
+ is between 60 and 240 seconds. An implementation MAY allow a system
+ administrator to set this attribute (by means outside this IPP/1.1
+ document). If so, the system administrator MAY be able to set values
+ outside this range.
+
+4.4.32 compression-supported (1setOf type3 keyword)
+
+ This REQUIRED Printer attribute identifies the set of supported
+ compression algorithms for document data. Compression only applies
+ to the document data; compression does not apply to the encoding of
+ the IPP operation itself. The supported values are used to validate
+ the client supplied "compression" operation attributes in Print-Job,
+ Send-Document, and Send-URI requests.
+
+ Standard keyword values are :
+
+ 'none': no compression is used.
+ 'deflate': ZIP public domain inflate/deflate) compression technology
+ in RFC 1951 [RFC1951]
+ 'gzip' GNU zip compression technology described in RFC 1952
+ [RFC1952].
+
+
+
+Hastings, et al. Standards Track [Page 141]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'compress': UNIX compression technology in RFC 1977 [RFC1977]
+
+4.4.33 job-k-octets-supported (rangeOfInteger(0:MAX))
+
+ This Printer attribute specifies the upper and lower bounds of total
+ sizes of jobs in K octets, i.e., in units of 1024 octets. The
+ supported values are used to validate the client supplied "job-k-
+ octets" operation attributes in create requests. The corresponding
+ job description attribute "job-k-octets" is defined in section
+ 4.3.17.1.
+
+4.4.34 job-impressions-supported (rangeOfInteger(0:MAX))
+
+ This Printer attribute specifies the upper and lower bounds for the
+ number of impressions per job. The supported values are used to
+ validate the client supplied "job-impressions" operation attributes
+ in create requests. The corresponding job description attribute
+ "job-impressions" is defined in section 4.3.17.2.
+
+4.4.35 job-media-sheets-supported (rangeOfInteger(0:MAX))
+
+ This Printer attribute specifies the upper and lower bounds for the
+ number of media sheets per job. The supported values are used to
+ validate the client supplied "job-media-sheets" operation attributes
+ in create requests. The corresponding Job attribute "job-media-
+ sheets" is defined in section 4.3.17.3.
+
+4.4.36 pages-per-minute (integer(0:MAX))
+
+ This Printer attributes specifies the nominal number of pages per
+ minute to the nearest whole number which may be generated by this
+ printer (e.g., simplex, black-and-white). This attribute is
+ informative, not a service guarantee. Generally, it is the value
+ used in the marketing literature to describe the device.
+
+ A value of 0 indicates a device that takes more than two minutes to
+ process a page.
+
+4.4.37 pages-per-minute-color (integer(0:MAX))
+
+ This Printer attributes specifies the nominal number of pages per
+ minute to the nearest whole number which may be generated by this
+ printer when printing color (e.g., simplex, color). For purposes of
+ this attribute, "color" means the same as for the "color-supported"
+ attribute, namely, the device is capable of any type of color
+ printing at all, including highlight color. This attribute is
+
+
+
+
+
+Hastings, et al. Standards Track [Page 142]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ informative, not a service guarantee. Generally, it is the value
+ used in the marketing literature to describe the color capabilities
+ of this device.
+
+ A value of 0 indicates a device that takes more than two minutes to
+ process a page.
+
+ If a color device has several color modes, it MAY use the pages-per-
+ minute value for this attribute that corresponds to the mode that
+ produces the highest number.
+
+ Black and white only printers MUST NOT support this attribute. If
+ this attribute is present, then the "color-supported" Printer
+ description attribute MUST be present and have a 'true' value.
+
+ The values of these two attributes returned by the Get-Printer-
+ Attributes operation MAY be affected by the "document-format"
+ attribute supplied by the client in the Get-Printer-Attributes
+ request. In other words, the implementation MAY have different
+ speeds depending on the document format being processed. See section
+ 3.2.5.1 Get-Printer-Attributes.
+
+5. Conformance
+
+ This section describes conformance issues and requirements. This
+ document introduces model entities such as objects, operations,
+ attributes, attribute syntaxes, and attribute values. These
+ conformance sections describe the conformance requirements which
+ apply to these model entities.
+
+5.1 Client Conformance Requirements
+
+ This section describes the conformance requirements for a client (see
+ section 2.1), whether it be:
+
+ 1. contained within software controlled by an end user, e.g.
+ activated by the "Print" menu item in an application that sends
+ IPP requests or
+
+ 2. the print server component that sends IPP requests to either an
+ output device or another "downstream" print server.
+
+ A conforming client MUST support all REQUIRED operations as defined
+ in this document. For each attribute included in an operation
+ request, a conforming client MUST supply a value whose type and value
+ syntax conforms to the requirements of the Model document as
+ specified in Sections 3 and 4. A conforming client MAY supply any
+
+
+
+
+Hastings, et al. Standards Track [Page 143]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ IETF standards track extensions and/or vendor extensions in an
+ operation request, as long as the extensions meet the requirements in
+ Section 6.
+
+ Otherwise, there are no conformance requirements placed on the user
+ interfaces provided by IPP clients or their applications. For
+ example, one application might not allow an end user to submit
+ multiple documents per job, while another does. One application
+ might first query a Printer object in order to supply a graphical
+ user interface (GUI) dialogue box with supported and default values
+ whereas a different implementation might not.
+
+ When sending a request, an IPP client NEED NOT supply any attributes
+ that are indicated as OPTIONALLY supplied by the client.
+
+ A client MUST be able to accept any of the attribute syntaxes defined
+ in Section 4.1, including their full range, that may be returned to
+ it in a response from a Printer object. In particular for each
+ attribute that the client supports whose attribute syntax is 'text',
+ the client MUST accept and process both the 'textWithoutLanguage' and
+ 'textWithLanguage' forms. Similarly, for each attribute that the
+ client supports whose attribute syntax is 'name', the client MUST
+ accept and process both the 'nameWithoutLanguage' and
+ 'nameWithLanguage' forms. For presentation purposes, truncation of
+ long attribute values is not recommended. A recommended approach
+ would be for the client implementation to allow the user to scroll
+ through long attribute values.
+
+ A response MAY contain attribute groups, attributes, attribute
+ syntaxes, values, and status codes that the client does not expect.
+ Therefore, a client implementation MUST gracefully handle such
+ responses and not refuse to inter-operate with a conforming Printer
+ that is returning IETF standards track extension or vendor
+ extensions, including attribute groups, attributes, attribute
+ syntaxes, attribute values, status codes, and out-of-band attribute
+ values that conform to Section 6. Clients may choose to ignore any
+ parameters, attribute groups, attributes, attribute syntaxes, or
+ values that they do not understand.
+
+ While a client is sending data to a printer, it SHOULD do its best to
+ prevent a channel from being closed by a lower layer when the channel
+ is blocked (i.e. flow-controlled off) for whatever reason, e.g. 'out
+ of paper' or 'job ahead hasn't freed up enough memory'. However, the
+ layer that launched the print submission (e.g. an end user) MAY close
+ the channel in order to cancel the job. When a client closes a
+ channel, a Printer MAY print all or part of the received portion of
+ the document. See the "Encoding and Transport" document [RFC2910]
+ for more details.
+
+
+
+Hastings, et al. Standards Track [Page 144]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ A client MUST support Client Authentication as defined in the IPP/1.1
+ Encoding and Transport document [RFC2910]. A client SHOULD support
+ Operation Privacy and Server Authentication as defined in the IPP/1.1
+ Encoding and Transport document [RFC2910]. See also section 8 of
+ this document.
+
+5.2 IPP Object Conformance Requirements
+
+ This section specifies the conformance requirements for conforming
+ implementations of IPP objects (see section 2). These requirements
+ apply to an IPP object whether it is:
+
+ (1) an (embedded) device component that accepts IPP requests and
+ controls the device or
+
+ (2) a component of a print server that accepts IPP requests (where
+ the print server control one or more networked devices using IPP or
+ other protocols).
+
+5.2.1 Objects
+
+ Conforming implementations MUST implement all of the model objects as
+ defined in this document in the indicated sections:
+
+ Section 2.1 - Printer Object
+ Section 2.2 - Job Object
+
+5.2.2 Operations
+
+ Conforming IPP object implementations MUST implement all of the
+ REQUIRED model operations, including REQUIRED responses, as defined
+ in this document in the indicated sections:
+
+ For a Printer object:
+ Print-Job (section 3.2.1) REQUIRED
+ Print-URI (section 3.2.2) OPTIONAL
+ Validate-Job (section 3.2.3) REQUIRED
+ Create-Job (section 3.2.4) OPTIONAL
+ Get-Printer-Attributes (section 3.2.5) REQUIRED
+ Get-Jobs (section 3.2.6) REQUIRED
+ Pause-Printer (section 3.2.7) OPTIONAL
+ Resume-Printer (section 3.2.8) OPTIONAL
+ Purge-Jobs (section 3.2.9) OPTIONAL
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 145]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ For a Job object:
+ Send-Document (section 3.3.1) OPTIONAL
+ Send-URI (section 3.3.2) OPTIONAL
+ Cancel-Job (section 3.3.3) REQUIRED
+ Get-Job-Attributes (section 3.3.4) REQUIRED
+ Hold-Job (section 3.3.5) OPTIONAL
+ Release-Job (section 3.3.6) OPTIONAL
+ Restart-Job (section 3.3.7) OPTIONAL
+
+ Conforming IPP objects MUST support all REQUIRED operation attributes
+ and all values of such attributes if so indicated in the description.
+ Conforming IPP objects MUST ignore all unsupported or unknown
+ operation attributes or operation attribute groups received in a
+ request, but MUST reject a request that contains a supported
+ operation attribute that contains an unsupported value.
+
+ Conforming IPP objects MAY return operation responses that contain
+ attributes groups, attributes names, attribute syntaxes, attribute
+ values, and status codes that are extensions to this standard. The
+ additional attribute groups MAY occur in any order.
+
+ The following section on object attributes specifies the support
+ required for object attributes.
+
+5.2.3 IPP Object Attributes
+
+ Conforming IPP objects MUST support all of the REQUIRED object
+ attributes, as defined in this document in the indicated sections.
+
+ If an object supports an attribute, it MUST support only those values
+ specified in this document or through the extension mechanism
+ described in section 5.2.4. It MAY support any non-empty subset of
+ these values. That is, it MUST support at least one of the specified
+ values and at most all of them.
+
+5.2.4 Versions
+
+ IPP/1.1 clients MUST meet the conformance requirements for clients
+ specified in this document and [RFC2910]. IPP/1.1 clients MUST send
+ requests containing a "version-number" parameter with a '1.1' value.
+
+ IPP/1.1 Printer and Job objects MUST meet the conformance
+ requirements for IPP objects specified in this document and
+ [RFC2910]. IPP/1.1 objects MUST accept requests containing a
+ "version-number" parameter with a '1.1' value (or reject the request
+ if the operation is not supported).
+
+
+
+
+
+Hastings, et al. Standards Track [Page 146]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ It is beyond the scope of this specification to mandate conformance
+ with previous versions. IPP/1.1 was deliberately designed, however,
+ to make supporting previous versions easy. It is worth noting that,
+ at the time of composing this specification (1999), we would expect
+ IPP/1.1 Printer implementations to:
+
+ understand any valid request in the format of IPP/1.0, or 1.1;
+
+ respond appropriately with a response containing the same
+ "version-number" parameter value used by the client in the request.
+
+ And we would expect IPP/1.1 clients to:
+
+ understand any valid response in the format of IPP/1.0, or 1.1.
+
+ It is recommended that IPP/1.1 clients try supplying alternate
+ version numbers if they receive a 'server-error-version-not-
+ supported' error return in a response.
+
+5.2.5 Extensions
+
+ A conforming IPP object MAY support IETF standards track extensions
+ and vendor extensions, as long as the extensions meet the
+ requirements specified in Section 6.
+
+ For each attribute included in an operation response, a conforming
+ IPP object MUST return a value whose type and value syntax conforms
+ to the requirement of the Model document as specified in Sections 3
+ and 4.
+
+5.2.6 Attribute Syntaxes
+
+ An IPP object MUST be able to accept any of the attribute syntaxes
+ defined in Section 4.1, including their full range, in any operation
+ in which a client may supply attributes or the system administrator
+ may configure attributes (by means outside the scope of this IPP/1.1
+ document). In particular for each attribute that the IPP object
+ supports whose attribute syntax is 'text', the IPP object MUST accept
+ and process both the 'textWithoutLanguage' and 'textWithLanguage'
+ forms. Similarly, for each attribute that the IPP object supports
+ whose attribute syntax is 'name', the IPP object MUST accept and
+ process both the 'nameWithoutLanguage' and 'nameWithLanguage' forms.
+ Furthermore, an IPP object MUST return attributes to the client in
+ operation responses that conform to the syntax specified in Section
+ 4.1, including their full range if supplied previously by a client.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 147]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+5.2.7 Security
+
+ An IPP Printer implementation SHOULD contain support for Client
+ Authentication as defined in the IPP/1.1 Encoding and Transport
+ document [RFC2910]. A Printer implementation MAY allow an
+ administrator to configure the Printer so that all, some, or none of
+ the users are authenticated. See also section 8 of this document.
+
+ An IPP Printer implementation SHOULD contain support for Operation
+ Privacy and Server Authentication as defined in the IPP/1.1 Encoding
+ and Transport document [RFC2910]. A Printer implementation MAY allow
+ an administrator to configure the degree of support for Operation
+ Privacy and Server Authentication. See also section 8 of this
+ document.
+
+ Security MUST NOT be compromised when a client supplies a lower
+ "version-number" parameter in a request. For example, if an IPP/1.1
+ conforming Printer object accepts version '1.0' requests and is
+ configured to enforce Digest Authentication, it MUST do the same for
+ a version '1.0' request.
+
+5.3 Charset and Natural Language Requirements
+
+ All clients and IPP objects MUST support the 'utf-8' charset as
+ defined in section 4.1.7.
+
+ IPP objects MUST be able to accept any client request which correctly
+ uses the "attributes-natural-language" operation attribute or the
+ Natural Language Override mechanism on any individual attribute
+ whether or not the natural language is supported by the IPP object.
+ If an IPP object supports a natural language, then it MUST be able to
+ translate (perhaps by table lookup) all generated 'text' or 'name'
+ attribute values into one of the supported languages (see section
+ 3.1.4). That is, the IPP object that supports a natural language
+ NEED NOT be a general purpose translator of any arbitrary 'text' or
+ 'name' value supplied by the client into that natural language.
+ However, the object MUST be able to translate (automatically
+ generate) any of its own attribute values and messages into that
+ natural language.
+
+6. IANA Considerations
+
+ This section describes the procedures for defining semantics for the
+ following IETF standards track extensions and vendor extensions to
+ the IPP/1.1 Model and Semantics document:
+
+ 1. keyword attribute values
+ 2. enum attribute values
+
+
+
+Hastings, et al. Standards Track [Page 148]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 3. attributes
+ 4. attribute syntaxes
+ 5. operations
+ 6. attribute groups
+ 7. status codes
+ 8. out-of-band attribute values
+
+ Extensions registered for use with IPP/1.1 are OPTIONAL for client
+ and IPP object conformance to the IPP/1.1 "Model and Semantics"
+ document (this document).
+
+ These extension procedures are aligned with the guidelines as set
+ forth by the IESG [IANA-CON]. Section 11 describes how to propose
+ new registrations for consideration. IANA will reject registration
+ proposals that leave out required information or do not follow the
+ appropriate format described in Section 11. The IPP/1.1 Model and
+ Semantics document may also be extended by an appropriate RFC that
+ specifies any of the above extensions.
+
+6.1 Typed 'keyword' and 'enum' Extensions
+
+ IPP allows for 'keyword' and 'enum' extensions (see sections 4.1.2.3
+ and 4.1.4). This document uses prefixes to the 'keyword' and 'enum'
+ basic attribute syntax type in order to communicate extra information
+ to the reader through its name. This extra information is not
+ represented in the protocol because it is unimportant to a client or
+ Printer object. The list below describes the prefixes and their
+ meaning.
+
+ "type1": This IPP specification document must be revised (or
+ another IETF standards track document which augments this
+ document) to add a new keyword or a new enum. No vendor
+ defined keywords or enums are allowed.
+
+ "type2": Implementers can, at any time, add new keyword or enum
+ values by proposing the complete specification to IANA:
+
+ iana@iana.org
+
+ IANA will forward the registration proposal to the IPP
+ Designated Expert who will review the proposal with a mailing
+ list that the Designated Expert keeps for this purpose.
+ Initially, that list will be the mailing list used by the IPP
+ WG:
+
+ ipp@pwg.org
+
+ even after the IPP WG is disbanded as permitted by [IANA-CON].
+
+
+
+Hastings, et al. Standards Track [Page 149]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The IPP Designated Expert is appointed by the IESG Area
+ Director responsible for IPP, according to [IANA-CON].
+
+ When a type2 keyword or enum is approved, the IPP Designated
+ Expert becomes the point of contact for any future maintenance
+ that might be required for that registration.
+
+ "type3": Implementers can, at any time, add new keyword and enum
+ values by submitting the complete specification to IANA as for
+ type2 who will forward the proposal to the IPP Designated
+ Expert. While no additional technical review is required, the
+ IPP Designated Expert may, at his/her discretion, forward the
+ proposal to the same mailing list as for type2 registrations
+ for advice and comment.
+
+ When a type3 keyword or enum is approved by the IPP Designated
+ Expert, the original proposer becomes the point of contact for
+ any future maintenance that might be required for that
+ registration.
+
+ For type2 and type3 keywords, the proposer includes the name of the
+ keyword in the registration proposal and the name is part of the
+ technical review.
+
+ After type2 and type3 enums specifications are approved, the IPP
+ Designated Expert in consultation with IANA assigns the next
+ available enum number for each enum value.
+
+ IANA will publish approved type2 and type3 keyword and enum
+ attributes value registration specifications in:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-values/xxx/yyy.txt
+
+ where xxx is the attribute name that specifies the initial values and
+ yyy.txt is a descriptive file name that contains one or more enums or
+ keywords approved at the same time. For example, if several
+ additional enums for stapling are approved for use with the
+ "finishings" attribute (and "finishings-default" and "finishings-
+ supported" attributes), IANA will publish the additional values in
+ the file:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-
+ values/finishings/stapling.txt
+
+ Note: Some attributes are defined to be: 'type3 keywords' | 'name'
+ which allows for attribute values to be extended by a site
+ administrator with administrator defined names. Such names are not
+ registered with IANA.
+
+
+
+Hastings, et al. Standards Track [Page 150]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ By definition, each of the three types above assert some sort of
+ registry or review process in order for extensions to be considered
+ valid. Each higher numbered level (1, 2, 3) tends to be decreasingly
+ less stringent than the previous level. Therefore, any typeN value
+ MAY be registered using a process for some typeM where M is less than
+ N, however such registration is NOT REQUIRED. For example, a type3
+ value MAY be registered in a type 1 manner (by being included in a
+ future version of an IPP specification), however, it is NOT REQUIRED.
+
+ This document defines keyword and enum values for all of the above
+ types, including type3 keywords.
+
+ For vendor keyword extensions, implementers SHOULD use keywords with
+ a suitable distinguishing prefix, such as "xxx-" where xxx follows
+ the syntax rules for keywords (see section 4.1.3) and is the
+ (lowercase) fully qualified company name registered with IANA for use
+ in domain names [RFC1035]. For example, if the company XYZ Corp. had
+ obtained the domain name "XYZ.com", then a vendor keyword 'abc' would
+ be: 'xyz.com-abc'.
+
+ Note: RFC 1035 [RFC1035] indicates that while upper and lower case
+ letters are allowed in domain names, no significance is attached to
+ the case. That is, two names with the same spelling but different
+ case are to be treated as if identical. Also, the labels in a domain
+ name must follow the rules for ARPANET host names: They must start
+ with a letter, end with a letter or digit, and have as interior
+ characters only letters, digits, and hyphen. Labels must be 63
+ characters or less. Labels are separated by the "." character.
+
+ For vendor enum extensions, implementers MUST use values in the
+ reserved integer range which is 2**30 to 2**31-1.
+
+6.2 Attribute Extensibility
+
+ Attribute names (see section 4.1.3) are type2 keywords. Therefore,
+ new attributes may be registered and have the same status as
+ attributes in this document by following the type2 extension rules.
+ For vendor attribute extensions, implementers SHOULD use keywords
+ with a suitable distinguishing prefix as described in Section 6.1.
+
+ IANA will publish approved attribute registration specifications as
+ separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/attributes/xxx-yyy.txt
+
+ where "xxx-yyy" is the new attribute name.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 151]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ If a new Printer object attribute is defined and its values can be
+ affected by a specific document format, its specification needs to
+ contain the following sentence:
+
+ "The value of this attribute returned in a Get-Printer-
+ Attributes response MAY depend on the "document-format"
+ attribute supplied (see Section 3.2.5.1)."
+
+ If the specification does not, then its value in the Get-Printer-
+ Attributes response MUST NOT depend on the "document-format" supplied
+ in the request. When a new Job Template attribute is registered, the
+ value of the Printer attributes MAY vary with "document-format"
+ supplied in the request without the specification having to indicate
+ so.
+
+6.3 Attribute Syntax Extensibility
+
+ Attribute syntaxes (see section 4.1) are like type2 enums.
+ Therefore, new attribute syntaxes may be registered and have the same
+ status as attribute syntaxes in this document by following the type2
+ extension rules described in Section 6.1. The initial set of value
+ codes that identify each of the attribute syntaxes have been assigned
+ in the "Encoding and Transport" document [RFC2910], including a
+ designated range for vendor extension.
+
+ For attribute syntaxes, the IPP Designated Expert in consultation
+ with IANA assigns the next attribute syntax code in the appropriate
+ range as specified in [RFC2910]. IANA will publish approved
+ attribute syntax registration specifications as separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-syntaxes/xxx-yyy.txt
+
+ where 'xxx-yyy' is the new attribute syntax name.
+
+6.4 Operation Extensibility
+
+ Operations (see section 3) may also be registered following the type2
+ procedures described in Section 6.1, though major new operations will
+ usually be done by a new standards track RFC that augments this
+ document. For vendor operation extensions, implementers MUST use the
+ range for the "operation-id" in requests specified in Section 4.4.15
+ "operations-supported" Printer attribute.
+
+ For operations, the IPP Designated Expert in consultation with IANA
+ assigns the next operation-id code as specified in Section 4.4.15.
+ IANA will publish approved operation registration specifications as
+ separate files:
+
+
+
+
+Hastings, et al. Standards Track [Page 152]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ ftp.isi.edu/iana/assignments/ipp/operations/Xxx-Yyy.txt
+
+ where "Xxx-Yyy" is the new operation name.
+
+6.5 Attribute Group Extensibility
+
+ Attribute groups (see section 3.1.3) passed in requests and responses
+ may be registered following the type2 procedures described in Section
+ 6.1. The initial set of attribute group tags have been assigned in
+ the "Encoding and Transport" document [RFC2910], including a
+ designated range for vendor extension.
+
+ For attribute groups, the IPP Designated Expert in consultation with
+ IANA assigns the next attribute group tag code in the appropriate
+ range as specified in [RFC2910]. IANA will publish approved
+ attribute group registration specifications as separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/attribute-group-tags/xxx-yyy-
+ tag.txt
+
+ where 'xxx-yyy-tag' is the new attribute group tag name.
+
+6.6 Status Code Extensibility
+
+ Operation status codes (see section 3.1.6.1) may also be registered
+ following the type2 procedures described in Section 6.1. The values
+ for status codes are allocated in ranges as specified in Section 14
+ for each status code class:
+
+ "informational" - Request received, continuing process
+ "successful" - The action was successfully received, understood, and
+ accepted
+ "redirection" - Further action must be taken in order to complete the
+ request
+ "client-error" - The request contains bad syntax or cannot be
+ fulfilled
+ "server-error" - The IPP object failed to fulfill an apparently
+ valid request
+
+ For vendor operation status code extensions, implementers MUST use
+ the top of each range as specified in Section 13.
+
+ For operation status codes, the IPP Designated Expert in consultation
+ with IANA assigns the next status code in the appropriate class range
+ as specified in Section 13. IANA will publish approved status code
+ registration specifications as separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/status-codes/xxx-yyy.txt
+
+
+
+Hastings, et al. Standards Track [Page 153]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ where "xxx-yyy" is the new operation status code keyword.
+
+6.7 Out-of-band Attribute Value Extensibility
+
+ Out-of-band attribute values (see the beginning of section 4.1)
+ passed in requests and responses may be registered following the
+ type2 procedures described in Section 6.1. The initial set of out-
+ of-band attribute value tags have been assigned in the "Encoding and
+ Transport" document [RFC2910].
+
+ For out-of-band attribute value tags, the IPP Designated Expert in
+ consultation with IANA assigns the next out-of-band attribute value
+ tag code in the appropriate range as specified in [RFC2910]. IANA
+ will publish approved out-of-band attribute value tags registration
+ specifications as separate files:
+
+ ftp.isi.edu/iana/assignments/ipp/out-of-band-attribute-value-
+ tags/xxx-yyy-tag.txt
+
+ where 'xxx-yyy-tag' is the new out-of-band attribute value tag name.
+
+6.8 Registration of MIME types/sub-types for document-formats
+
+ The "document-format" attribute's syntax is 'mimeMediaType'. This
+ means that valid values are Internet Media Types (see Section 4.1.9).
+ RFC 2045 [RFC2045] defines the syntax for valid Internet media types.
+ IANA is the registry for all Internet media types.
+
+6.9 Registration of charsets for use in 'charset' attribute values
+
+ The "attributes-charset" attribute's syntax is 'charset'. This means
+ that valid values are charsets names. When a charset in the IANA
+ registry has more than one name (alias), the name labeled as
+ "(preferred MIME name)", if present, MUST be used (see Section
+ 4.1.7). IANA is the registry for charsets following the procedures
+ of [RFC2278].
+
+7. Internationalization Considerations
+
+ Some of the attributes have values that are text strings and names
+ which are intended for human understanding rather than machine
+ understanding (see the 'text' and 'name' attribute syntaxes in
+ Sections 4.1.1 and 4.1.2).
+
+ In each operation request, the client
+
+ - identifies the charset and natural language of the request which
+ affects each supplied 'text' and 'name' attribute value, and
+
+
+
+Hastings, et al. Standards Track [Page 154]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - requests the charset and natural language for attributes
+ returned by the IPP object in operation responses (as described
+ in Section 3.1.4.1).
+
+ In addition, the client MAY separately and individually identify the
+ Natural Language Override of a supplied 'text' or 'name' attribute
+ using the 'textWithLanguage' and 'nameWithLanguage' technique
+ described section 4.1.1.2 and 4.1.2.2 respectively.
+
+ All IPP objects MUST support the UTF-8 [RFC2279] charset in all
+ 'text' and 'name' attributes supported. If an IPP object supports
+ more than the UTF-8 charset, the object MUST convert between them in
+ order to return the requested charset to the client according to
+ Section 3.1.4.2. If an IPP object supports more than one natural
+ language, the object SHOULD return 'text' and 'name' values in the
+ natural language requested where those values are generated by the
+ Printer (see Section 3.1.4.1).
+
+ For Printers that support multiple charsets and/or multiple natural
+ languages in 'text' and 'name' attributes, different jobs may have
+ been submitted in differing charsets and/or natural languages. All
+ responses MUST be returned in the charset requested by the client.
+ However, the Get-Jobs operation uses the 'textWithLanguage' and
+ 'nameWithLanguage' mechanism to identify the differing natural
+ languages with each job attribute returned.
+
+ The Printer object also has configured charset and natural language
+ attributes. The client can query the Printer object to determine
+ the list of charsets and natural languages supported by the Printer
+ object and what the Printer object's configured values are. See the
+ "charset-configured", "charset-supported", "natural-language-
+ configured", and "generated-natural-language-supported" Printer
+ description attributes for more details.
+
+ The "charset-supported" attributed identifies the supported charsets.
+ If a charset is supported, the IPP object MUST be capable of
+ converting to and from that charset into any other supported charset.
+ In many cases, an IPP object will support only one charset and it
+ MUST be the UTF-8 charset.
+
+ The "charset-configured" attribute identifies the one supported
+ charset which is the native charset given the current configuration
+ of the IPP object (administrator defined).
+
+ The "generated-natural-language-supported" attribute identifies the
+ set of supported natural languages for generated messages; it is not
+ related to the set of natural languages that must be accepted for
+ client supplied 'text' and 'name' attributes. For client supplied
+
+
+
+Hastings, et al. Standards Track [Page 155]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'text' and 'name' attributes, an IPP object MUST accept ALL supplied
+ natural languages. Just because a Printer object is currently
+ configured to support 'en-us' natural language does not mean that the
+ Printer object should reject a job if the client supplies a job name
+ that is in 'fr-ca'.
+
+ The "natural-language-configured" attribute identifies the one
+ supported natural language for generated messages which is the native
+ natural language given the current configuration of the IPP object
+ (administrator defined).
+
+ Attributes of type 'text' and 'name' are populated from different
+ sources. These attributes can be categorized into following groups
+ (depending on the source of the attribute):
+
+ 1. Some attributes are supplied by the client (e.g., the client
+ supplied "job-name", "document-name", and "requesting-user-
+ name" operation attributes along with the corresponding Job
+ object's "job-name" and "job-originating-user-name"
+ attributes). The IPP object MUST accept these attributes in
+ any natural language no matter what the set of supported
+ languages for generated messages
+ 2. Some attributes are supplied by the system administrator (e.g.,
+ the Printer object's "printer-name" and "printer-location"
+ attributes). These too can be in any natural language. If the
+ natural language for these attributes is different than what a
+ client requests, then they must be reported using the Natural
+ Language Override mechanism.
+ 3. Some attributes are supplied by the device manufacturer (e.g.,
+ the Printer object's "printer-make-and-model" attribute).
+ These too can be in any natural language. If the natural
+ language for these attributes is different than what a client
+ requests, then they must be reported using the Natural Language
+ Override mechanism.
+ 4. Some attributes are supplied by the operator (e.g., the Job
+ object's "job-message-from-operator" attribute). These too can
+ be in any natural language. If the natural language for these
+ attributes is different than what a client requests, then they
+ must be reported using the Natural Language Override mechanism.
+ 5. Some attributes are generated by the IPP object (e.g., the Job
+ object's "job-state-message" attribute, the Printer object's
+ "printer-state-message" attribute, and the "status-message"
+ operation attribute). These attributes can only be in one of
+ the "generated-natural-language-supported" natural languages.
+ If a client requests some natural language for these attributes
+ other than one of the supported values, the IPP object SHOULD
+
+
+
+
+
+Hastings, et al. Standards Track [Page 156]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ respond using the value of the "natural-language-configured"
+ attribute (using the Natural Language Override mechanism if
+ needed).
+
+ The 'text' and 'name' attributes specified in this version of this
+ document (additional ones will be registered according to the
+ procedures in Section 6) are:
+
+ Attributes Source
+
+ Operation Attributes:
+ job-name (name) client
+ document-name (name) client
+ requesting-user-name (name) client
+ status-message (text) Job or Printer object
+ detailed-status-message (text) Job or Printer object -
+ see rule 1
+ document-access-error (text) Job or Printer object -
+ see rule 1
+
+ Job Template Attributes:
+ job-hold-until (keyword | name) client matches
+ administrator-configured
+ job-hold-until-default (keyword | name) client matches
+ administrator-configured
+ job-hold-until-supported (keyword | client matches
+ name) administrator-configured
+ job-sheets (keyword | name) client matches
+ administrator-configured
+ job-sheets-default (keyword | name) client matches
+ administrator-configured
+ job-sheets-supported (keyword | name) client matches
+ administrator-configured
+ media (keyword | name) client matches
+ administrator-configured
+ media-default (keyword | name) client matches
+ administrator-configured
+ media-supported (keyword | name) client matches
+ administrator-configured
+ media-ready (keyword | name) client matches
+ administrator-configured
+
+ Job Description Attributes:
+ job-name (name) client or Printer object
+ job-originating-user-name (name) Printer object
+ job-state-message (text) Job or Printer object
+ output-device-assigned (name(127)) administrator
+ job-message-from-operator (text(127)) operator
+
+
+
+Hastings, et al. Standards Track [Page 157]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ job-detailed-status-messages (1setOf Job or Printer object -
+ text) see rule 1
+ job-document-access-errors (1setOf Job or Printer object -
+ text) see rule 1
+
+ Printer Description Attributes:
+ printer-name (name(127)) administrator
+ printer-location (text(127)) administrator
+ printer-info (text(127)) administrator
+ printer-make-and-model (text(127)) administrator or
+ manufacturer
+ printer-state-message (text) Printer object
+ printer-message-from-operator operator
+ (text(127))
+
+ Rule 1 - Neither the Printer nor the client localizes these message
+ attributes, since they are intended for use by the system
+ administrator or other experienced technical persons.
+
+8. Security Considerations
+
+ It is difficult to anticipate the security risks that might exist in
+ any given IPP environment. For example, if IPP is used within a given
+ corporation over a private network, the risks of exposing document
+ data may be low enough that the corporation will choose not to use
+ encryption on that data. However, if the connection between the
+ client and the IPP object is over a public network, the client may
+ wish to protect the content of the information during transmission
+ through the network with encryption.
+
+ Furthermore, the value of the information being printed may vary from
+ one IPP environment to the next. Printing payroll checks, for
+ example, would have a different value than printing public
+ information from a file. There is also the possibly of denial-of-
+ service attacks, but denial-of-service attacks against printing
+ resources are not well understood and there is no published
+ precedents regarding this scenario.
+
+ Once the authenticated identity of the requester has been supplied to
+ the IPP object, the object uses that identity to enforce any
+ authorization policy that might be in place. For example, one site's
+ policy might be that only the job owner is allowed to cancel a job.
+ The details and mechanisms to set up a particular access control
+ policy are not part of IPP/1.1, and must be established via some
+ other type of administrative or access control framework. However,
+ there are operation status codes that allow an IPP server to return
+ information back to a client about any potential access control
+ violations for an IPP object.
+
+
+
+Hastings, et al. Standards Track [Page 158]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ During a create operation, the client's identity is recorded in the
+ Job object in an implementation-defined attribute. This information
+ can be used to verify a client's identity for subsequent operations
+ on that Job object in order to enforce any access control policy that
+ might be in effect. See section 8.3 below for more details.
+
+ Since the security levels or the specific threats that an IPP system
+ administrator may be concerned with cannot be anticipated, IPP MUST
+ be capable of operating with different security mechanisms and
+ security policies as required by the individual installation.
+ Security policies might vary from very strong, to very weak, to none
+ at all, and corresponding security mechanisms will be required.
+
+8.1 Security Scenarios
+
+ The following sections describe specific security attacks for IPP
+ environments. Where examples are provided they should be considered
+ illustrative of the environment and not an exhaustive set. Not all of
+ these environments will necessarily be addressed in initial
+ implementations of IPP.
+
+8.1.1 Client and Server in the Same Security Domain
+
+ This environment is typical of internal networks where traditional
+ office workers print the output of personal productivity applications
+ on shared work-group printers, or where batch applications print
+ their output on large production printers. Although the identity of
+ the user may be trusted in this environment, a user might want to
+ protect the content of a document against such attacks as
+ eavesdropping, replaying or tampering.
+
+8.1.2 Client and Server in Different Security Domains
+
+ Examples of this environment include printing a document created by
+ the client on a publicly available printer, such as at a commercial
+ print shop; or printing a document remotely on a business associate's
+ printer. This latter operation is functionally equivalent to sending
+ the document to the business associate as a facsimile. Printing
+ sensitive information on a Printer in a different security domain
+ requires strong security measures. In this environment authentication
+ of the printer is required as well as protection against unauthorized
+ use of print resources. Since the document crosses security domains,
+ protection against eavesdropping and document tampering are also
+ required. It will also be important in this environment to protect
+ Printers against "spamming" and malicious document content.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 159]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+8.1.3 Print by Reference
+
+ When the document is not stored on the client, printing can be done
+ by reference. That is, the print request can contain a reference, or
+ pointer, to the document instead of the actual document itself (see
+ sections 3.2.2 and 3.3.2). Standard methods currently do not exist
+ for remote entities to "assume" the credentials of a client for
+ forwarding requests to a 3rd party. It is anticipated that Print-By-
+ Reference will be used to access "public" documents and that
+ sophisticated methods for authenticating "proxies" is not specified
+ in this document.
+
+8.2 URIs in Operation, Job, and Printer attributes
+
+ The "printer-uri-supported" attribute contains the Printer object's
+ URI(s). Its companion attribute, "uri-security-supported",
+ identifies the security mechanism used for each URI listed in the
+ "printer-uri-supported" attribute. For each Printer operation
+ request, a client MUST supply only one URI in the "printer-uri"
+ operation attribute. In other words, even though the Printer
+ supports more than one URI, the client only interacts with the
+ Printer object using one if its URIs. This duality is not needed for
+ Job objects, since the Printer objects is the factory for Job
+ objects, and the Printer object will generate the correct URI for new
+ Job objects depending on the Printer object's security configuration.
+
+8.3 URIs for each authentication mechanisms
+
+ Each URI has an authentication mechanism associated with it. If the
+ URI is the i'th element of "printer-uri-supported", then
+ authentication mechanism is the "i th" element of "uri-
+ authentication-supported". For a list of possible authentication
+ mechanisms, see section 4.4.2.
+
+ The Printer object uses an authentication mechanism to determine the
+ name of the user performing an operation. This user is called the
+ "authenticated user". The credibility of authentication depends on
+ the mechanism that the Printer uses to obtain the user's name. When
+ the authentication mechanism is 'none', all authenticated users are
+ "anonymous".
+
+ During job creation operations, the Printer initializes the value of
+ the "job-originating-user-name" attribute (see section 4.3.6) to be
+ the authenticated user. The authenticated user is this case is called
+ the "job owner".
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 160]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ If an implementation can be configured to support more than one
+ authentication mechanism (see section 4.4.2), then it MUST implement
+ rules for determining equality of authenticated user names which have
+ been authenticated via different authentication mechanisms. One
+ possible policy is that identical names that are authenticated via
+ different mechanisms are different. For example, a user can cancel
+ his job only if he uses the same authentication mechanism for both
+ Cancel-Job and Print-Job. Another policy is that identical names
+ that are authenticated via different mechanism are the same if the
+ authentication mechanism for the later operation is not less strong
+ than the authentication mechanism for the earlier job creation
+ operation. For example, a user can cancel his job only if he uses
+ the same or stronger authentication mechanism for Cancel-Job and
+ Print-Job. With this second policy a job submitted via 'requesting-
+ user-name' authentication could be canceled via 'digest'
+ authentication. With the first policy, the job could not be canceled
+ in this way.
+
+ A client is able to determine the authentication mechanism used to
+ create a job. It is the i'th value of the Printer's "uri-
+ authentication-supported" attribute (see section 4.4.2), where i is
+ the index of the element of the Printer's "printer-uri-supported"
+ attribute (see section 4.4.1) equal to the job's "job-printer-uri"
+ attribute (see section 4.3.3).
+
+8.4 Restricted Queries
+
+ In many IPP operations, a client supplies a list of attributes to be
+ returned in the response. For security reasons, an IPP object may be
+ configured not to return all attributes (or all values) that a client
+ requests. The job attributes returned MAY depend on whether the
+ requesting user is the same as the user that submitted the job. The
+ IPP object MAY even return none of the requested attributes. In such
+ cases, the status returned is the same as if the object had returned
+ all requested attributes. The client cannot tell by such a response
+ whether the requested attribute was present or absent on the object.
+
+8.5 Operations performed by operators and system administrators
+
+ For the three printer operations Pause-Printer, Resume-Printer, and
+ Purge-Jobs (see sections 3.2.7, 3.2.8 and 3.2.9), the requesting user
+ is intended to be an operator or administrator of the Printer object
+ (see section 1). Otherwise, the IPP Printer MUST reject the
+ operation and return: 'client-error-forbidden', 'client-error-not-
+ authenticated', or 'client-error-not-authorized' as appropriate. For
+ operations on jobs, the requesting user is intended to be the job
+
+
+
+
+
+Hastings, et al. Standards Track [Page 161]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ owner or may be an operator or administrator of the Printer object.
+ The means for authorizing an operator or administrator of the Printer
+ object are not specified in this document.
+
+8.6 Queries on jobs submitted using non-IPP protocols
+
+ If the device that an IPP Printer is representing is able to accept
+ jobs using other job submission protocols in addition to IPP, it is
+ RECOMMENDED that such an implementation at least allow such "foreign"
+ jobs to be queried using Get-Jobs returning "job-id" and "job-uri" as
+ 'unknown'. Such an implementation NEED NOT support all of the same
+ IPP job attributes as for IPP jobs. The IPP object returns the
+ 'unknown' out-of-band value for any requested attribute of a foreign
+ job that is supported for IPP jobs, but not for foreign jobs.
+
+ It is further RECOMMENDED, that the IPP Printer generate "job-id" and
+ "job-uri" values for such "foreign jobs", if possible, so that they
+ may be targets of other IPP operations, such as Get-Job-Attributes
+ and Cancel-Job. Such an implementation also needs to deal with the
+ problem of authentication of such foreign jobs. One approach would
+ be to treat all such foreign jobs as belonging to users other than
+ the user of the IPP client. Another approach would be for the
+ foreign job to belong to 'anonymous'. Only if the IPP client has
+ been authenticated as an operator or administrator of the IPP Printer
+ object, could the foreign jobs be queried by an IPP request.
+ Alternatively, if the security policy is to allow users to query
+ other users' jobs, then the foreign jobs would also be visible to an
+ end-user IPP client using Get-Jobs and Get-Job-Attributes.
+
+9. References
+
+ [ASME-Y14.1M] Metric Drawing Sheet Size and Format, ASME Y14.1M-1995.
+ This standard defines metric sheet sizes and formats
+ for engineering drawings.
+
+ [ASCII] Coded Character Set - 7-bit American Standard Code for
+ Information Interchange (ASCII), ANSI X3.4-1986. This
+ standard is the specification of the US-ASCII charset.
+
+ [BCP-11] Bradner S. and R. Hovey, "The Organizations Involved in
+ the IETF Standards Process", BCP 11, RFC 2028, October
+ 1996.
+
+ [HTPP] J. Barnett, K. Carter, R. DeBry, "Initial Draft -
+ Hypertext Printing Protocol - HTPP/1.0", October 1996,
+ ftp://ftp.pwg.org/pub/pwg/ipp/historic/htpp/overview.ps.gz
+
+
+
+
+
+Hastings, et al. Standards Track [Page 162]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ [IANA-CON] Narten, T. and H. Alvestrand, "Guidelines for Writing
+ an IANA Considerations Section in RFCs", BCP 26, RFC
+ 2434, October 1998.
+
+ [IANA-CS] IANA Registry of Coded Character Sets:
+ ftp://ftp.isi.edu/in-notes/iana/assignments/character-
+ sets
+
+ [IANA-MT] IANA Registry of Media Types: ftp://ftp.isi.edu/in-
+ notes/iana/assignments/media-types/
+
+ [IPP-IIG] Hastings, T., Manros, C., Kugler, C., Holst, H., and P.
+ Zehler, "Internet Printing Protocol/1.1: draft-ietf-
+ ipp-implementers-guide-v11-01.txt, work in progress,
+ May 30, 2000.
+
+ [ISO10646-1] ISO/IEC 10646-1:1993, "Information technology --
+ Universal Multiple-Octet Coded Character Set (UCS) -
+ Part 1: Architecture and Basic Multilingual Plane,
+ JTC1/SC2."
+
+ [ISO8859-1] ISO/IEC 8859-1:1987, "Information technology -- 8-bit
+ One-Byte Coded Character Set - Part 1: Latin Alphabet
+ Nr 1", 1987, JTC1/SC2.
+
+ [ISO10175] ISO/IEC 10175 Document Printing Application (DPA), June
+ 1996.
+
+ [LDPA] T. Hastings, S. Isaacson, M. MacKay, C. Manros, D.
+ Taylor, P. Zehler, "LDPA - Lightweight Document
+ Printing Application", October 1996,
+ ftp://ftp.pwg.org/pub/pwg/ipp/historic/ldpa/ldpa8.pdf.gz
+
+ [P1387.4] Kirk, M. (editor), POSIX System Administration - Part
+ 4: Printing Interfaces, POSIX 1387.4 D8, 1994.
+
+ [PSIS] Herriot, R. (editor), X/Open A Printing System
+ Interoperability Specification (PSIS), August 1995.
+
+ [PWG] Printer Working Group, http://www.pwg.org.
+
+ [RFC1035] Mockapetris, P., "Domain Names - Implementation and
+ Specification", STD 13, RFC 1035, November 1987.
+
+ [RFC1179] McLaughlin, L., "Line Printer Daemon Protocol", RFC
+ 1179, August 1990.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 163]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ [RFC1759] Smith, R., Wright, F., Hastings, T., Zilles, S. and J.
+ Gyllenskog, "Printer MIB", RFC 1759, March 1995.
+
+ [RFC1766] Alvestrand, H., "Tags for the Identification of
+ Languages", RFC 1766, March 1995.
+
+ [RFC1951] Deutsch, P., "DEFLATE Compressed Data Format
+ Specification version 1.3 ", RFC 1951, May 1996.
+
+ [RFC1952] Deutsch, P., "GZIP file format specification version
+ 4.3", RFC 1952, May 1996.
+
+ [RFC1977] Schryver, V., "PPP BSD Compression Protocol", RFC 1977,
+ August 1996.
+
+ [RFC2026] Bradner, S., "The Internet Standards Process --
+ Revision 3", BCP 9, RFC 2026, October 1996.
+
+ [RFC2045] Freed, N. and N. Borenstein, ", Multipurpose Internet
+ Mail Extensions (MIME) Part One: Format of Internet
+ Message Bodies", RFC 2045, November 1996.
+
+ [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet
+ Mail Extensions (MIME) Part Two: Media Types", RFC
+ 2046, November 1996.
+
+ [RFC2048] Freed, N., Klensin, J. and J. Postel, "Multipurpose
+ Internet Mail Extension (MIME) Part Four: Registration
+ Procedures", RFC 2048, November 1996.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2228] Horowitz, M. and S. Lunt, "FTP Security Extensions",
+ RFC 2228, October 1997.
+
+ [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol Version
+ 1.0", RFC 2246, January 1999.
+
+ [RFC2277] Alvestrand, H., "IETF Policy on Character Sets and
+ Languages" BCP 18, RFC 2277, January 1998.
+
+ [RFC2278] Freed, N. and J. Postel: "IANA CharSet Registration
+ Procedures", BCP 19, RFC 2278, January 1998.
+
+ [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO
+ 10646", RFC 2279, January 1998.
+
+
+
+
+Hastings, et al. Standards Track [Page 164]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ [RFC2316] Bellovin, S., "Report of the IAB Security Architecture
+ Workshop", RFC 2316, April 1998.
+
+ [RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform
+ Resource Identifiers (URI): Generic Syntax", RFC 2396,
+ August 1998.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Turner,
+ "Internet Printing Protocol/1.0: Encoding and
+ Transport", RFC 2565, April 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S. and
+ P. Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569,
+ April 1999.
+
+ [RFC2579] McCloghrie, K., Perkins, D. and J. Schoenwaelder,
+ "Textual Conventions for SMIv2", STD 58, RFC 2579,
+ April 1999.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P. and T. Berners-Lee, "Hypertext
+ Transfer Protocol - HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC2617] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence,
+ S., Leach, P., Luotonen, A. and L. Stewart, "HTTP
+ Authentication: Basic and Digest Access
+ Authentication", RFC 2617, June 1999.
+
+ [RFC2639] Hastings, T. and C. Manros, "Internet Printing
+ Protocol/1.0: Encoding and Transport", RFC 2639, July
+ 1999.
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P., Turner, R. and J.
+ Wenn, "Internet Printing Protocol/1.1: Encoding and
+ Transport", RFC 2910, September 2000.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 165]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ [SSL] Netscape, The SSL Protocol, Version 3, (Text version
+ 3.02), November 1996.
+
+ [SWP] P. Moore, B. Jahromi, S. Butler, "Simple Web Printing
+ SWP/1.0", May 7, 1997,
+ ftp://ftp.pwg.org/pub/pwg/ipp/new_PRO/swp9705.pdf
+
+10. Authors' Addresses
+
+ Scott A. Isaacson, Editor
+ Novell, Inc.
+ 122 E 1700 S
+ Provo, UT 84606
+
+ Phone: 801-861-7366
+ Fax: 801-861-2517
+ EMail: sisaacson@novell.com
+
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ EMail: hastings@cp10.es.xerox.com
+
+
+ Robert Herriot
+ Xerox Corp.
+ 3400 Hill View Ave, Building 1
+ Palo Alto, CA 94304
+
+ Phone: 650-813-7696
+ Fax: 650-813-6860
+ EMail: robert.herriot@pahv.xerox.com
+
+
+ Roger deBry
+ Utah Valley State College
+ Orem, UT 84058
+
+ Phone: (801) 222-8000
+ EMail: debryro@uvsc.edu
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 166]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Patrick Powell
+ Astart Technologies
+ 9475 Chesapeake Dr., Suite D
+ San Diego, CA 95123
+
+ Phone: (619) 874-6543
+ Fax: (619) 279-8424
+ EMail: papowell@astart.com
+
+ IPP Web Page: http://www.pwg.org/ipp/
+ IPP Mailing List: ipp@pwg.org
+
+ To subscribe to the ipp mailing list, send the following email:
+ 1) send it to majordomo@pwg.org
+ 2) leave the subject line blank
+ 3) put the following two lines in the message body:
+ subscribe ipp
+ end
+
+ Implementers of this specification document are encouraged to join
+ IPP Mailing List in order to participate in any discussions of
+ clarification issues and review of registration proposals for
+ additional attributes and values.
+
+ Other Participants:
+
+ Chuck Adams - Tektronix Shivaun Albright - HP
+ Stefan Andersson - Axis Jeff Barnett - IBM
+ Ron Bergman - Hitachi Koki Imaging Dennis Carney - IBM
+ Systems
+ Keith Carter - IBM Angelo Caruso - Xerox
+ Rajesh Chawla - TR Computing Nancy Chen - Okidata
+ Solutions
+ Josh Cohen - Microsoft Jeff Copeland - QMS
+ Andy Davidson - Tektronix Roger deBry - IBM
+ Maulik Desai - Auco Mabry Dozier - QMS
+ Lee Farrell - Canon Information Satoshi Fujitami - Ricoh
+ Systems
+ Steve Gebert - IBM Sue Gleeson - Digital
+ Charles Gordon - Osicom Brian Grimshaw - Apple
+ Jerry Hadsell - IBM Richard Hart - Digital
+ Tom Hastings - Xerox Henrik Holst - I-data
+ Stephen Holmstead Zhi-Hong Huang - Zenographics
+ Scott Isaacson - Novell Babek Jahromi - Microsoft
+ Swen Johnson - Xerox David Kellerman - Northlake
+ Software
+ Robert Kline - TrueSpectra Charles Kong - Panasonic
+ Carl Kugler - IBM Dave Kuntz - Hewlett-Packard
+
+
+
+Hastings, et al. Standards Track [Page 167]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Takami Kurono - Brother Rick Landau - Digital
+ Scott Lawrence - Agranot Systems Greg LeClair - Epson
+ Dwight Lewis - Lexmark Harry Lewis - IBM
+ Tony Liao - Vivid Image Roy Lomicka - Digital
+ Pete Loya - HP Ray Lutz - Cognisys
+ Mike MacKay - Novell, Inc. David Manchala - Xerox
+ Carl-Uno Manros - Xerox Jay Martin - Underscore
+ Stan McConnell - Xerox Larry Masinter - Xerox
+ Sandra Matts - Hewlett Packard Peter Michalek - Shinesoft
+ Ira McDonald - High North Inc. Mike Moldovan - G3 Nova
+ Tetsuya Morita - Ricoh Yuichi Niwa - Ricoh
+ Pat Nogay - IBM Ron Norton - Printronics
+ Hugo Parra, Novell Bob Pentecost - Hewlett-Packard
+ Patrick Powell - Astart Jeff Rackowitz - Intermec
+ Technologies
+ Eric Random - Peerless Rob Rhoads - Intel
+ Xavier Riley - Xerox Gary Roberts - Ricoh
+ David Roach - Unisys Stuart Rowley - Kyocera
+ Yuji Sasaki - Japan Computer Richard Schneider - Epson
+ Industry
+ Kris Schoff - HP Katsuaki Sekiguchi - Canon
+ Bob Setterbo - Adobe Gail Songer - Peerless
+ Hideki Tanaka - Cannon Devon Taylor - Novell
+ Mike Timperman - Lexmark Atsushi Uchino - Epson
+ Shigeru Ueda - Canon Bob Von Andel - Allegro Software
+ William Wagner - NetSilicon/DPI Jim Walker - DAZEL
+ Chris Wellens - Interworking Labs Trevor Wells - Hewlett Packard
+ Craig Whittle - Sharp Labs Rob Whittle - Novell, Inc.
+ Jasper Wong - Xionics Don Wright - Lexmark
+ Michael Wu - Heidelberg Digital Rick Yardumian - Xerox
+ Michael Yeung - Toshiba Lloyd Young - Lexmark
+ Atsushi Yuki - Kyocera Peter Zehler - Xerox
+ William Zhang- Canon Information Frank Zhao - Panasonic
+ Systems
+ Steve Zilles - Adobe Rob Zirnstein - Canon Information
+ Systems
+
+11. Formats for IPP Registration Proposals
+
+ In order to propose an IPP extension for registration, the proposer
+ must submit an application to IANA by email to "iana@iana.org" or by
+ filling out the appropriate form on the IANA web pages
+ (http://www.iana.org). This section specifies the required
+ information and the formats for proposing registrations of extensions
+ to IPP as provided in Section 6 for:
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 168]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 1. type2 'keyword' attribute values
+ 2. type3 'keyword' attribute values
+ 3. type2 'enum' attribute values
+ 4. type3 'enum' attribute values
+ 5. attributes
+ 6. attribute syntaxes
+ 7. operations
+ 8. status codes
+ 9. out-of-band attribute values
+
+11.1 Type2 keyword attribute values registration,
+
+ Type of registration: type2 keyword attribute value
+ Name of attribute to which this keyword specification is to be added:
+ Proposed keyword name of this keyword value:
+ Specification of this keyword value (follow the style of IPP Model
+ Section 4.1.2.3):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For type2 keywords, the Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.2 Type3 keyword attribute values registration
+
+ Type of registration: type3 keyword attribute value
+ Name of attribute to which this keyword specification is to be added:
+ Proposed keyword name of this keyword value:
+ Specification of this keyword value (follow the style of IPP Model
+ Section 4.1.2.3):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For type3 keywords, the proposer will be the point of contact
+ for the approved registration specification, if any maintenance of
+ the registration specification is needed.
+
+11.3 Type2 enum attribute values registration
+
+ Type of registration: type2 enum attribute value
+ Name of attribute to which this enum specification is to be added:
+ Keyword symbolic name of this enum value:
+ Numeric value (to be assigned by the IPP Designated Expert in
+ consultation with IANA):
+
+
+
+
+Hastings, et al. Standards Track [Page 169]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Specification of this enum value (follow the style of IPP Model
+ Section 4.1.4):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For type2 enums, the Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.4 Type3 enum attribute values registration
+
+ Type of registration: type3 enum attribute value
+ Name of attribute to which this enum specification is to be added:
+ Keyword symbolic name of this enum value:
+ Numeric value (to be assigned by the IPP Designated Expert in
+ consultation with IANA):
+ Specification of this enum value (follow the style of IPP Model
+ Section 4.1.4):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For type3 enums, the proposer will be the point of contact for
+ the approved registration specification, if any maintenance of the
+ registration specification is needed.
+
+11.5 Attribute registration
+
+ Type of registration: attribute
+ Proposed keyword name of this attribute:
+ Types of attribute (Operation, Job Template, Job Description, Printer
+ Description):
+ Operations to be used with if the attribute is an operation attribute:
+ Object (Job, Printer, etc. if bound to an object):
+ Attribute syntax(es) (include 1setOf and range as in Section 4.2):
+ If attribute syntax is 'keyword' or 'enum', is it type2 or type3:
+ If this is a Printer attribute, MAY the value returned depend on
+ "document-format" (See Section 6.2):
+ If this is a Job Template attribute, how does its specification depend
+ on the value of the "multiple-document-handling" attribute:
+ Specification of this attribute (follow the style of IPP Model Section
+ 4.2):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+
+
+
+
+Hastings, et al. Standards Track [Page 170]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Note: For attributes, the IPP Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.6 Attribute Syntax registration
+
+ Type of registration: attribute syntax
+ Proposed name of this attribute syntax:
+ Type of attribute syntax (integer, octetString, character-string, see
+ [RFC2910]):
+ Numeric tag according to [RFC2910] (to be assigned by the IPP
+ Designated Expert in consultation with IANA):
+ Specification of this attribute (follow the style of IPP Model Section
+ 4.1):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For attribute syntaxes, the IPP Designated Expert will be the
+ point of contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.7 Operation registration
+
+ Type of registration: operation
+ Proposed name of this operation:
+ Numeric operation-id value according to section 4.4.15 (to be assigned
+ by the IPP Designated Expert in consultation with IANA):
+ Object Target (Job, Printer, etc. that operation is upon):
+ Specification of this operation (follow the style of IPP Model Section
+ 3):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For operations, the IPP Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.8 Attribute Group registration
+
+ Type of registration: attribute group
+ Proposed name of this attribute group:
+ Numeric tag according to [RFC2910] (to be assigned by the IPP
+ Designated Expert in consultation with IANA):
+ Operation requests and group number for each operation in which the
+ attribute group occurs:
+
+
+
+
+Hastings, et al. Standards Track [Page 171]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Operation responses and group number for each operation in which the
+ attribute group occurs:
+ Specification of this attribute group (follow the style of IPP Model
+ Section 3):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For attribute groups, the IPP Designated Expert will be the
+ point of contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.9 Status code registration
+
+ Type of registration: status code
+ Keyword symbolic name of this status code value:
+ Numeric value (to be assigned by the IPP Designated Expert in
+ consultation with IANA):
+ Operations that this status code may be used with:
+ Specification of this status code (follow the style of IPP Model
+ Section 13 APPENDIX B: Status Codes and Suggested Status Code
+ Messages):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For status codes, the Designated Expert will be the point of
+ contact for the approved registration specification, if any
+ maintenance of the registration specification is needed.
+
+11.10 Out-of-band Attribute Value registration
+
+ Type of registration: out-of-band attribute value
+ Proposed name of this out-of-band attribute value:
+ Numeric tag according to [RFC2910] (to be assigned by the IPP Designated
+ Expert in consultation with IANA):
+ Operations that this out-of-band attribute value may be used with:
+ Attributes that this out-of-band attribute value may be used with:
+ Specification of this out-of-band attribute value (follow the style of
+ the beginning of IPP Model Section 4.1):
+ Name of proposer:
+ Address of proposer:
+ Email address of proposer:
+
+ Note: For out-of-band attribute values, the IPP Designated Expert
+ will be the point of contact for the approved registration
+ specification, if any maintenance of the registration specification
+ is needed.
+
+
+
+Hastings, et al. Standards Track [Page 172]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+12. APPENDIX A: Terminology
+
+ This specification document uses the terminology defined in this
+ section.
+
+12.1 Conformance Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",
+ "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
+ interpreted as described in RFC 2119 [RFC2119].
+
+12.1.1 NEED NOT
+
+ This term is not included in RFC 2119. The verb "NEED NOT" indicates
+ an action that the subject of the sentence does not have to implement
+ in order to claim conformance to the standard. The verb "NEED NOT"
+ is used instead of "MAY NOT" since "MAY NOT" sounds like a
+ prohibition.
+
+12.2 Model Terminology
+
+12.2.1 Keyword
+
+ Keywords are used within this document as identifiers of semantic
+ entities within the abstract model (see section 4.1.2.3). Attribute
+ names, some attribute values, attribute syntaxes, and attribute group
+ names are represented as keywords.
+
+12.2.2 Attributes
+
+ An attribute is an item of information that is associated with an
+ instance of an IPP object. An attribute consists of an attribute
+ name and one or more attribute values. Each attribute has a specific
+ attribute syntax. All object attributes are defined in section 4 and
+ all operation attributes are defined in section 3.
+
+ Job Template Attributes are described in section 4.2. The client
+ optionally supplies Job Template attributes in a create request
+ (operation requests that create Job objects). The Printer object has
+ associated attributes which define supported and default values for
+ the Printer.
+
+12.2.2.1 Attribute Name
+
+ Each attribute is uniquely identified in this document by its
+ attribute name. An attribute name is a keyword. The keyword
+ attribute name is given in the section header describing that
+
+
+
+
+Hastings, et al. Standards Track [Page 173]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ attribute. In running text in this document, attribute names are
+ indicated inside double quotation marks (") where the quotation marks
+ are not part of the keyword itself.
+
+12.2.2.2 Attribute Group Name
+
+ Related attributes are grouped into named groups. The name of the
+ group is a keyword. The group name may be used in place of naming
+ all the attributes in the group explicitly. Attribute groups are
+ defined in section 3.
+
+12.2.2.3 Attribute Value
+
+ Each attribute has one or more values. Attribute values are
+ represented in the syntax type specified for that attribute. In
+ running text in this document, attribute values are indicated inside
+ single quotation marks ('), whether their attribute syntax is
+ keyword, integer, text, etc. where the quotation marks are not part
+ of the value itself.
+
+12.2.2.4 Attribute Syntax
+
+ Each attribute is defined using an explicit syntax type. In this
+ document, each syntax type is defined as a keyword with specific
+ meaning. The "Encoding and Transport" document [RFC2910] indicates
+ the actual "on-the-wire" encoding rules for each syntax type.
+ Attribute syntax types are defined in section 4.1.
+
+12.2.3 Supports
+
+ By definition, a Printer object supports an attribute only if that
+ Printer object responds with the corresponding attribute populated
+ with some value(s) in a response to a query for that attribute. A
+ Printer object supports an attribute value if the value is one of the
+ Printer object's "supported values" attributes. The device behind a
+ Printer object may exhibit a behavior that corresponds to some IPP
+ attribute, but if the Printer object, when queried for that
+ attribute, doesn't respond with the attribute, then as far as IPP is
+ concerned, that implementation does not support that feature. If the
+ Printer object's "xxx-supported" attribute is not populated with a
+ particular value (even if that value is a legal value for that
+ attribute), then that Printer object does not support that particular
+ value.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 174]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ A conforming implementation MUST support all REQUIRED attributes.
+ However, even for REQUIRED attributes, conformance to IPP does not
+ mandate that all implementations support all possible values
+ representing all possible job processing behaviors and features. For
+ example, if a given instance of a Printer supports only certain
+ document formats, then that Printer responds with the "document-
+ format-supported" attribute populated with a set of values, possibly
+ only one, taken from the entire set of possible values defined for
+ that attribute. This limited set of values represents the Printer's
+ set of supported document formats. Supporting an attribute and some
+ set of values for that attribute enables IPP end users to be aware of
+ and make use of those features associated with that attribute and
+ those values. If an implementation chooses to not support an
+ attribute or some specific value, then IPP end users would have no
+ ability to make use of that feature within the context of IPP itself.
+ However, due to existing practice and legacy systems which are not
+ IPP aware, there might be some other mechanism outside the scope of
+ IPP to control or request the "unsupported" feature (such as embedded
+ instructions within the document data itself).
+
+ For example, consider the "finishings-supported" attribute.
+
+ 1) If a Printer object is not physically capable of stapling, the
+ "finishings-supported" attribute MUST NOT be populated with the
+ value of 'staple'.
+ 2) A Printer object is physically capable of stapling, however an
+ implementation chooses not to support stapling in the IPP
+ "finishings" attribute. In this case, 'staple' MUST NOT be a
+ value in the "finishings-supported" Printer object attribute.
+ Without support for the value 'staple', an IPP end user would
+ have no means within the protocol itself to request that a Job
+ be stapled. However, an existing document data formatter might
+ be able to request that the document be stapled directly with
+ an embedded instruction within the document data. In this
+ case, the IPP implementation does not "support" stapling,
+ however the end user is still able to have some control over
+ the stapling of the completed job.
+ 3) A Printer object is physically capable of stapling, and an
+ implementation chooses to support stapling in the IPP
+ "finishings" attribute. In this case, 'staple' MUST be a value
+ in the "finishings-supported" Printer object attribute. Doing
+ so, would enable end users to be aware of and make use of the
+ stapling feature using IPP attributes.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 175]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Even though support for Job Template attributes by a Printer object
+ is OPTIONAL, it is RECOMMENDED that if the device behind a Printer
+ object is capable of realizing any feature or function that
+ corresponds to an IPP attribute and some associated value, then that
+ implementation SHOULD support that IPP attribute and value.
+
+ The set of values in any of the supported value attributes is set
+ (populated) by some administrative process or automatic sensing
+ mechanism that is outside the scope of this IPP/1.1 document. For
+ administrative policy and control reasons, an administrator may
+ choose to make only a subset of possible values visible to the end
+ user. In this case, the real output device behind the IPP Printer
+ abstraction may be capable of a certain feature, however an
+ administrator is specifying that access to that feature not be
+ exposed to the end user through the IPP protocol. Also, since a
+ Printer object may represent a logical print device (not just a
+ physical device) the actual process for supporting a value is
+ undefined and left up to the implementation. However, if a Printer
+ object supports a value, some manual human action may be needed to
+ realize the semantic action associated with the value, but no end
+ user action is required.
+
+ For example, if one of the values in the "finishings-supported"
+ attribute is 'staple', the actual process might be an automatic
+ staple action by a physical device controlled by some command sent to
+ the device. Or, the actual process of stapling might be a manual
+ action by an operator at an operator attended Printer object.
+
+ For another example of how supported attributes function, consider a
+ system administrator who desires to control all print jobs so that no
+ job sheets are printed in order to conserve paper. To force no job
+ sheets, the system administrator sets the only supported value for
+ the "job-sheets-supported" attribute to 'none'. In this case, if a
+ client requests anything except 'none', the create request is
+ rejected or the "job-sheets" value is ignored (depending on the value
+ of "ipp-attribute-fidelity"). To force the use of job start/end
+ sheets on all jobs, the administrator does not include the value
+ 'none' in the "job-sheets- supported" attribute. In this case, if a
+ client requests 'none', the create request is rejected or the "job-
+ sheets" value is ignored (again depending on the value of "ipp-
+ attribute-fidelity").
+
+12.2.4 print-stream page
+
+ A "print-stream page" is a page according to the definition of pages
+ in the language used to express the document data.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 176]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+12.2.5 impression
+
+ An "impression" is the image (possibly many print-stream pages in
+ different configurations) imposed onto a single media page.
+
+13. APPENDIX B: Status Codes and Suggested Status Code Messages
+
+ This section defines status code enum keywords and values that are
+ used to provide semantic information on the results of an operation
+ request. Each operation response MUST include a status code. The
+ response MAY also contain a status message that provides a short
+ textual description of the status. The status code is intended for
+ use by automata, and the status message is intended for the human end
+ user. Since the status message is an OPTIONAL component of the
+ operation response, an IPP application (i.e., a browser, GUI, print
+ driver or gateway) is NOT REQUIRED to examine or display the status
+ message, since it MAY not be returned to the application.
+
+ The prefix of the status keyword defines the class of response as
+ follows:
+
+ "informational" - Request received, continuing process
+ "successful" - The action was successfully received, understood,
+ and accepted
+ "redirection" - Further action must be taken in order to complete
+ the request
+ "client-error" - The request contains bad syntax or cannot be
+ fulfilled
+ "server-error" - The IPP object failed to fulfill an apparently
+ valid request
+
+ As with type2 enums, IPP status codes are extensible. IPP clients
+ are NOT REQUIRED to understand the meaning of all registered status
+ codes, though such understanding is obviously desirable. However,
+ IPP clients MUST understand the class of any status code, as
+ indicated by the prefix, and treat any unrecognized response as being
+ equivalent to the first status code of that class, with the exception
+ that an unrecognized response MUST NOT be cached. For example, if an
+ unrecognized status code of "client-error-xxx-yyy" is received by the
+ client, it can safely assume that there was something wrong with its
+ request and treat the response as if it had received a "client-
+ error-bad-request" status code. In such cases, IPP applications
+ SHOULD present the OPTIONAL message (if present) to the end user
+ since the message is likely to contain human readable information
+ which will help to explain the unusual status. The name of the enum
+ is the suggested status message for US English.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 177]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The status code values range from 0x0000 to 0x7FFF. The value ranges
+ for each status code class are as follows:
+
+ "successful" - 0x0000 to 0x00FF
+ "informational" - 0x0100 to 0x01FF
+ "redirection" - 0x0200 to 0x02FF
+ "client-error" - 0x0400 to 0x04FF
+ "server-error" - 0x0500 to 0x05FF
+
+ The top half (128 values) of each range (0x0n40 to 0x0nFF, for n = 0
+ to 5) is reserved for vendor use within each status code class.
+ Values 0x0600 to 0x7FFF are reserved for future assignment by IETF
+ standards track documents and MUST NOT be used.
+
+13.1 Status Codes
+
+ Each status code is described below. Section 13.1.5.9 contains a
+ table that indicates which status codes apply to which operations.
+ The Implementer's Guide [IPP-IIG] describe the suggested steps for
+ processing IPP attributes for all operations, including returning
+ status codes.
+
+13.1.1 Informational
+
+ This class of status code indicates a provisional response and is to
+ be used for informational purposes only.
+
+ There are no status codes defined in IPP/1.1 for this class of status
+ code.
+
+13.1.2 Successful Status Codes
+
+ This class of status code indicates that the client's request was
+ successfully received, understood, and accepted.
+
+13.1.2.1 successful-ok (0x0000)
+
+ The request has succeeded and no request attributes were substituted
+ or ignored. In the case of a response to a create request, the
+ 'successful-ok' status code indicates that the request was
+ successfully received and validated, and that the Job object has been
+ created; it does not indicate that the job has been processed. The
+ transition of the Job object into the 'completed' state is the only
+ indicator that the job has been printed.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 178]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.2.2 successful-ok-ignored-or-substituted-attributes (0x0001)
+
+ The request has succeeded, but some supplied (1) attributes were
+ ignored or (2) unsupported values were substituted with supported
+ values or were ignored in order to perform the operation without
+ rejecting it. Unsupported attributes, attribute syntaxes, or values
+ MUST be returned in the Unsupported Attributes group of the response
+ for all operations. There is an exception to this rule for the query
+ operations: Get-Printer-Attributes, Get-Jobs, and Get-Job-Attributes
+ for the "requested-attributes" operation attribute only. When the
+ supplied values of the "requested-attributes" operation attribute are
+ requesting attributes that are not supported, the IPP object MAY, but
+ is NOT REQUIRED to, return the "requested-attributes" attribute in
+ the Unsupported Attribute response group (with the unsupported values
+ only). See sections 3.1.7 and 3.2.1.2.
+
+13.1.2.3 successful-ok-conflicting-attributes (0x0002)
+
+ The request has succeeded, but some supplied attribute values
+ conflicted with the values of other supplied attributes. These
+ conflicting values were either (1) substituted with (supported)
+ values or (2) the attributes were removed in order to process the job
+ without rejecting it. Attributes or values which conflict with other
+ attributes and have been substituted or ignored MUST be returned in
+ the Unsupported Attributes group of the response for all operations
+ as supplied by the client. See sections 3.1.7 and 3.2.1.2.
+
+13.1.3 Redirection Status Codes
+
+ This class of status code indicates that further action needs to be
+ taken to fulfill the request.
+
+ There are no status codes defined in IPP/1.1 for this class of status
+ code.
+
+13.1.4 Client Error Status Codes
+
+ This class of status code is intended for cases in which the client
+ seems to have erred. The IPP object SHOULD return a message
+ containing an explanation of the error situation and whether it is a
+ temporary or permanent condition.
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 179]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.4.1 client-error-bad-request (0x0400)
+
+ The request could not be understood by the IPP object due to
+ malformed syntax (such as the value of a fixed length attribute whose
+ length does not match the prescribed length for that attribute - see
+ the Implementer's Guide [IPP-IIG] ). The IPP application SHOULD NOT
+ repeat the request without modifications.
+
+13.1.4.2 client-error-forbidden (0x0401)
+
+ The IPP object understood the request, but is refusing to fulfill it.
+ Additional authentication information or authorization credentials
+ will not help and the request SHOULD NOT be repeated. This status
+ code is commonly used when the IPP object does not wish to reveal
+ exactly why the request has been refused or when no other response is
+ applicable.
+
+13.1.4.3 client-error-not-authenticated (0x0402)
+
+ The request requires user authentication. The IPP client may repeat
+ the request with suitable authentication information. If the request
+ already included authentication information, then this status code
+ indicates that authorization has been refused for those credentials.
+ If this response contains the same challenge as the prior response,
+ and the user agent has already attempted authentication at least
+ once, then the response message may contain relevant diagnostic
+ information. This status codes reveals more information than
+ "client-error-forbidden".
+
+13.1.4.4 client-error-not-authorized (0x0403)
+
+ The requester is not authorized to perform the request. Additional
+ authentication information or authorization credentials will not help
+ and the request SHOULD NOT be repeated. This status code is used
+ when the IPP object wishes to reveal that the authentication
+ information is understandable, however, the requester is explicitly
+ not authorized to perform the request. This status codes reveals
+ more information than "client-error-forbidden" and "client-error-
+ not-authenticated".
+
+13.1.4.5 client-error-not-possible (0x0404)
+
+ This status code is used when the request is for something that can
+ not happen. For example, there might be a request to cancel a job
+ that has already been canceled or aborted by the system. The IPP
+ client SHOULD NOT repeat the request.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 180]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.4.6 client-error-timeout (0x0405)
+
+ The client did not produce a request within the time that the IPP
+ object was prepared to wait. For example, a client issued a Create-
+ Job operation and then, after a long period of time, issued a Send-
+ Document operation and this error status code was returned in
+ response to the Send-Document request (see section 3.3.1). The IPP
+ object might have been forced to clean up resources that had been
+ held for the waiting additional Documents. The IPP object was forced
+ to close the Job since the client took too long. The client SHOULD
+ NOT repeat the request without modifications.
+
+13.1.4.7 client-error-not-found (0x0406)
+
+ The IPP object has not found anything matching the request URI. No
+ indication is given of whether the condition is temporary or
+ permanent. For example, a client with an old reference to a Job (a
+ URI) tries to cancel the Job, however in the mean time the Job might
+ have been completed and all record of it at the Printer has been
+ deleted. This status code, 'client-error-not-found' is returned
+ indicating that the referenced Job can not be found. This error
+ status code is also used when a client supplies a URI as a reference
+ to the document data in either a Print-URI or Send-URI operation, but
+ the document can not be found.
+
+ In practice, an IPP application should avoid a not found situation by
+ first querying and presenting a list of valid Printer URIs and Job
+ URIs to the end-user.
+
+13.1.4.8 client-error-gone (0x0407)
+
+ The requested object is no longer available and no forwarding address
+ is known. This condition should be considered permanent. Clients
+ with link editing capabilities should delete references to the
+ request URI after user approval. If the IPP object does not know or
+ has no facility to determine, whether or not the condition is
+ permanent, the status code "client-error-not-found" should be used
+ instead.
+
+ This response is primarily intended to assist the task of maintenance
+ by notifying the recipient that the resource is intentionally
+ unavailable and that the IPP object administrator desires that remote
+ links to that resource be removed. It is not necessary to mark all
+ permanently unavailable resources as "gone" or to keep the mark for
+ any length of time -- that is left to the discretion of the IPP
+ object administrator and/or Printer implementation.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 181]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.4.9 client-error-request-entity-too-large (0x0408)
+
+ The IPP object is refusing to process a request because the request
+ entity is larger than the IPP object is willing or able to process.
+ An IPP Printer returns this status code when it limits the size of
+ print jobs and it receives a print job that exceeds that limit or
+ when the attributes are so many that their encoding causes the
+ request entity to exceed IPP object capacity.
+
+13.1.4.10 client-error-request-value-too-long (0x0409)
+
+ The IPP object is refusing to service the request because one or more
+ of the client-supplied attributes has a variable length value that is
+ longer than the maximum length specified for that attribute. The IPP
+ object might not have sufficient resources (memory, buffers, etc.) to
+ process (even temporarily), interpret, and/or ignore a value larger
+ than the maximum length. Another use of this error code is when the
+ IPP object supports the processing of a large value that is less than
+ the maximum length, but during the processing of the request as a
+ whole, the object may pass the value onto some other system component
+ which is not able to accept the large value. For more details, see
+ the Implementer's Guide [IPP-IIG] .
+
+ Note: For attribute values that are URIs, this rare condition is
+ only likely to occur when a client has improperly submitted a request
+ with long query information (e.g. an IPP application allows an end-
+ user to enter an invalid URI), when the client has descended into a
+ URI "black hole" of redirection (e.g., a redirected URI prefix that
+ points to a suffix of itself), or when the IPP object is under attack
+ by a client attempting to exploit security holes present in some IPP
+ objects using fixed-length buffers for reading or manipulating the
+ Request-URI.
+
+13.1.4.11 client-error-document-format-not-supported (0x040A)
+
+ The IPP object is refusing to service the request because the
+ document data is in a format, as specified in the "document-format"
+ operation attribute, that is not supported by the Printer object.
+ This error is returned independent of the client-supplied "ipp-
+ attribute-fidelity". The Printer object MUST return this status
+ code, even if there are other Job Template attributes that are not
+ supported as well, since this error is a bigger problem than with Job
+ Template attributes. See sections 3.1.6.1, 3.1.7, and 3.2.1.1.
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 182]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.4.12 client-error-attributes-or-values-not-supported (0x040B)
+
+ In a create request, if the Printer object does not support one or
+ more attributes, attribute syntaxes, or attribute values supplied in
+ the request and the client supplied the "ipp-attribute-fidelity"
+ operation attribute with the 'true' value, the Printer object MUST
+ return this status code. The Printer object MUST also return in the
+ Unsupported Attributes Group all the attributes and/or values
+ supplied by the client that are not supported. See section 3.1.7.
+ For example, if the request indicates 'iso-a4' media, but that media
+ type is not supported by the Printer object. Or, if the client
+ supplies a Job Template attribute and the attribute itself is not
+ even supported by the Printer. If the "ipp-attribute-fidelity"
+ attribute is 'false', the Printer MUST ignore or substitute values
+ for unsupported Job Template attributes and values rather than reject
+ the request and return this status code.
+
+ For any operation where a client requests attributes (such as a Get-
+ Jobs, Get-Printer-Attributes, or Get-Job-Attributes operation), if
+ the IPP object does not support one or more of the requested
+ attributes, the IPP object simply ignores the unsupported requested
+ attributes and processes the request as if they had not been
+ supplied, rather than returning this status code. In this case, the
+ IPP object MUST return the 'successful-ok-ignored-or-substituted-
+ attributes' status code and MAY return the unsupported attributes as
+ values of the "requested-attributes" in the Unsupported Attributes
+ Group (see section 13.1.2.2).
+
+13.1.4.13 client-error-uri-scheme-not-supported (0x040C)
+
+ The scheme of the client-supplied URI in a Print-URI or a Send-URI
+ operation is not supported. See sections 3.1.6.1 and 3.1.7.
+
+13.1.4.14 client-error-charset-not-supported (0x040D)
+
+ For any operation, if the IPP Printer does not support the charset
+ supplied by the client in the "attributes-charset" operation
+ attribute, the Printer MUST reject the operation and return this
+ status and any 'text' or 'name' attributes using the 'utf-8' charset
+ (see Section 3.1.4.1). See sections 3.1.6.1 and 3.1.7.
+
+13.1.4.15 client-error-conflicting-attributes (0x040E)
+
+ The request is rejected because some attribute values conflicted with
+ the values of other attributes which this document does not permit to
+ be substituted or ignored. The Printer object MUST also return in
+ the Unsupported Attributes Group the conflicting attributes supplied
+ by the client. See sections 3.1.7 and 3.2.1.2.
+
+
+
+Hastings, et al. Standards Track [Page 183]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.4.16 client-error-compression-not-supported (0x040F)
+
+ The IPP object is refusing to service the request because the
+ document data, as specified in the "compression" operation attribute,
+ is compressed in a way that is not supported by the Printer object.
+ This error is returned independent of the client-supplied "ipp-
+ attribute-fidelity". The Printer object MUST return this status
+ code, even if there are other Job Template attributes that are not
+ supported as well, since this error is a bigger problem than with Job
+ Template attributes. See sections 3.1.6.1, 3.1.7, and 3.2.1.1.
+
+13.1.4.17 client-error-compression-error (0x0410)
+
+ The IPP object is refusing to service the request because the
+ document data cannot be decompressed when using the algorithm
+ specified by the "compression" operation attribute. This error is
+ returned independent of the client-supplied "ipp-attribute-fidelity".
+ The Printer object MUST return this status code, even if there are
+ Job Template attributes that are not supported as well, since this
+ error is a bigger problem than with Job Template attributes. See
+ sections 3.1.7 and 3.2.1.1.
+
+13.1.4.18 client-error-document-format-error (0x0411)
+
+ The IPP object is refusing to service the request because Printer
+ encountered an error in the document data while interpreting it.
+ This error is returned independent of the client-supplied "ipp-
+ attribute-fidelity". The Printer object MUST return this status
+ code, even if there are Job Template attributes that are not
+ supported as well, since this error is a bigger problem than with Job
+ Template attributes. See sections 3.1.7 and 3.2.1.1.
+
+13.1.4.19 client-error-document-access-error (0x0412)
+
+ The IPP object is refusing to service the Print-URI or Send-URI
+ request because Printer encountered an access error while attempting
+ to validate the accessibility or access the document data specified
+ in the "document-uri" operation attribute. The Printer MAY also
+ return a specific document access error code using the "document-
+ access-error" operation attribute (see section 3.1.6.4). This error
+ is returned independent of the client-supplied "ipp-attribute-
+ fidelity". The Printer object MUST return this status code, even if
+ there are Job Template attributes that are not supported as well,
+ since this error is a bigger problem than with Job Template
+ attributes. See sections 3.1.6.1 and 3.1.7.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 184]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.5 Server Error Status Codes
+
+ This class of status codes indicates cases in which the IPP object is
+ aware that it has erred or is incapable of performing the request.
+ The IPP object SHOULD include a message containing an explanation of
+ the error situation, and whether it is a temporary or permanent
+ condition.
+
+13.1.5.1 server-error-internal-error (0x0500)
+
+ The IPP object encountered an unexpected condition that prevented it
+ from fulfilling the request. This error status code differs from
+ "server-error-temporary-error" in that it implies a more permanent
+ type of internal error. It also differs from "server-error-device-
+ error" in that it implies an unexpected condition (unlike a paper-jam
+ or out-of-toner problem which is undesirable but expected). This
+ error status code indicates that probably some knowledgeable human
+ intervention is required.
+
+13.1.5.2 server-error-operation-not-supported (0x0501)
+
+ The IPP object does not support the functionality required to fulfill
+ the request. This is the appropriate response when the IPP object
+ does not recognize an operation or is not capable of supporting it.
+ See sections 3.1.6.1 and 3.1.7.
+
+13.1.5.3 server-error-service-unavailable (0x0502)
+
+ The IPP object is currently unable to handle the request due to a
+ temporary overloading or maintenance of the IPP object. The
+ implication is that this is a temporary condition which will be
+ alleviated after some delay. If known, the length of the delay may be
+ indicated in the message. If no delay is given, the IPP application
+ should handle the response as it would for a "server-error-
+ temporary-error" response. If the condition is more permanent, the
+ error status codes "client-error-gone" or "client-error-not-found"
+ could be used.
+
+13.1.5.4 server-error-version-not-supported (0x0503)
+
+ The IPP object does not support, or refuses to support, the IPP
+ protocol version that was supplied as the value of the "version-
+ number" operation parameter in the request. The IPP object is
+ indicating that it is unable or unwilling to complete the request
+ using the same major and minor version number as supplied in the
+ request other than with this error message. The error response SHOULD
+ contain a "status-message" attribute (see section 3.1.6.2) describing
+
+
+
+
+Hastings, et al. Standards Track [Page 185]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ why that version is not supported and what other versions are
+ supported by that IPP object. See sections 3.1.6.1, 3.1.7, and
+ 3.1.8.
+
+ The error response MUST identify in the "version-number" operation
+ parameter the closest version number that the IPP object does
+ support. For example, if a client supplies version '1.0' and an
+ IPP/1.1 object supports version '1.0', then it responds with version
+ '1.0' in all responses to such a request. If the IPP/1.1 object does
+ not support version '1.0', then it should accept the request and
+ respond with version '1.1' or may reject the request and respond with
+ this error code and version
+ '1.1'. If a client supplies a version '1.2', the IPP/1.1 object
+ should accept the request and return version '1.1' or may reject the
+ request and respond with this error code and version '1.1'. See
+ sections 3.1.8 and 4.4.14.
+
+13.1.5.5 server-error-device-error (0x0504)
+
+ A printer error, such as a paper jam, occurs while the IPP object
+ processes a Print or Send operation. The response contains the true
+ Job Status (the values of the "job-state" and "job-state-reasons"
+ attributes). Additional information can be returned in the OPTIONAL
+ "job-state-message" attribute value or in the OPTIONAL status message
+ that describes the error in more detail. This error status code is
+ only returned in situations where the Printer is unable to accept the
+ create request because of such a device error. For example, if the
+ Printer is unable to spool, and can only accept one job at a time,
+ the reason it might reject a create request is that the printer
+ currently has a paper jam. In many cases however, where the Printer
+ object can accept the request even though the Printer has some error
+ condition, the 'successful-ok' status code will be returned. In such
+ a case, the client would look at the returned Job Object Attributes
+ or later query the Printer to determine its state and state reasons.
+
+13.1.5.6 server-error-temporary-error (0x0505)
+
+ A temporary error such as a buffer full write error, a memory
+ overflow (i.e. the document data exceeds the memory of the Printer),
+ or a disk full condition, occurs while the IPP Printer processes an
+ operation. The client MAY try the unmodified request again at some
+ later point in time with an expectation that the temporary internal
+ error condition may have been cleared. Alternatively, as an
+ implementation option, a Printer object MAY delay the response until
+ the temporary condition is cleared so that no error is returned.
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 186]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+13.1.5.7 server-error-not-accepting-jobs (0x0506)
+
+ A temporary error indicating that the Printer is not currently
+ accepting jobs, because the administrator has set the value of the
+ Printer's "printer-is-accepting-jobs" attribute to 'false' (by means
+ outside the scope of this IPP/1.1 document).
+
+13.1.5.8 server-error-busy (0x0507)
+
+ A temporary error indicating that the Printer is too busy processing
+ jobs and/or other requests. The client SHOULD try the unmodified
+ request again at some later point in time with an expectation that
+ the temporary busy condition will have been cleared.
+
+13.1.5.9 server-error-job-canceled (0x0508)
+
+ An error indicating that the job has been canceled by an operator or
+ the system while the client was transmitting the data to the IPP
+ Printer. If a job-id and job-uri had been created, then they are
+ returned in the Print-Job, Send-Document, or Send-URI response as
+ usual; otherwise, no job-id and job-uri are returned in the response.
+
+13.1.5.10 server-error-multiple-document-jobs-not-supported (0x0509)
+
+ The IPP object does not support multiple documents per job and a
+ client attempted to supply document data with a second Send-Document
+ or Send-URI operation.
+
+13.2 Status Codes for IPP Operations
+
+ PJ = Print-Job, PU = Print-URI, CJ = Create-Job, SD = Send-Document
+ SU = Send-URI, V = Validate-Job, GA = Get-Job-Attributes and
+ Get-Printer-Attributes, GJ = Get-Jobs, C = Cancel-Job
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 187]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ IPP Operations
+ IPP Status Keyword PJ PU CJ SD SU V GA GJ C
+ ------------------ -- -- -- -- -- - -- -- -
+ successful-ok x x x x x x x x x
+ successful-ok-ignored-or-substituted- x x x x x x x x x
+ attributes
+ successful-ok-conflicting-attributes x x x x x x x x x
+ client-error-bad-request x x x x x x x x x
+ client-error-forbidden x x x x x x x x x
+ client-error-not-authenticated x x x x x x x x x
+ client-error-not-authorized x x x x x x x x x
+ client-error-not-possible x x x x x x x x x
+ client-error-timeout x x
+ client-error-not-found x x x x x x x x x
+ client-error-gone x x x x x x x x x
+ client-error-request-entity-too-large x x x x x x x x x
+ client-error-request-value-too-long x x x x x x x x x
+ client-error-document-format-not- x x x x x x
+ supported
+ client-error-attributes-or-values-not- x x x x x x x x x
+ supported
+ client-error-uri-scheme-not-supported x x
+ client-error-charset-not-supported x x x x x x x x x
+ client-error-conflicting-attributes x x x x x x x x x
+ client-error-compression-not-supported x x x x x
+ client-error-compression-error x x x x
+ client-error-document-format-error x x x x
+ client-error-document-access-error x x
+ server-error-internal-error x x x x x x x x x
+ server-error-operation-not-supported x x x x
+ server-error-service-unavailable x x x x x x x x x
+ server-error-version-not-supported x x x x x x x x x
+ server-error-device-error x x x x x
+ server-error-temporary-error x x x x x
+ server-error-not-accepting-jobs x x x x
+ server-error-busy x x x x x x x x x
+ server-error-job-canceled x x x
+ server-error-multiple-document-jobs- x x
+ not-supported
+
+ HJ = Hold-Job, RJ = Release-Job, RS = Restart-Job
+ PP = Pause-Printer, RP = Resume-Printer, PJ = Purge-Jobs
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 188]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ IPP Operations (cont.)
+ IPP Status Keyword HJ RJ RS PP RP PJ
+ ------------------ -- -- -- -- -- --
+ successful-ok x x x x x x
+ successful-ok-ignored-or-substituted- x x x x x x
+ attributes
+ successful-ok-conflicting-attributes x x x x x x
+ client-error-bad-request x x x x x x
+ client-error-forbidden x x x x x x
+ client-error-not-authenticated x x x x x x
+ client-error-not-authorized x x x x x x
+ client-error-not-possible x x x x x x
+ client-error-timeout
+ client-error-not-found x x x x x x
+ client-error-gone x x x x x x
+ client-error-request-entity-too-large x x x x x x
+ client-error-request-value-too-long x x x x x x
+ client-error-document-format-not-
+ supported
+ client-error-attributes-or-values-not- x x x x x x
+ supported
+ client-error-uri-scheme-not-supported
+ client-error-charset-not-supported x x x x x x
+ client-error-conflicting-attributes x x x x x x
+ client-error-compression-not-supported
+ client-error-compression-error
+ client-error-document-format-error
+ client-error-document-access-error
+ server-error-internal-error x x x x x x
+ server-error-operation-not-supported x x x x x x
+ server-error-service-unavailable x x x x x x
+ server-error-version-not-supported x x x x x x
+ server-error-device-error
+ server-error-temporary-error x x x x x x
+ server-error-not-accepting-jobs
+ server-error-busy x x x x x x
+ server-error-job-canceled
+ server-error-multiple-document-jobs-
+ not-supported
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 189]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+14. APPENDIX C: "media" keyword values
+
+ Standard keyword values are taken from several sources.
+
+ Standard values are defined (taken from DPA[ISO10175] and the Printer
+ MIB[RFC1759]):
+
+ 'default': The default medium for the output device
+ 'iso-a4-white': Specifies the ISO A4 white medium: 210 mm x 297 mm
+ 'iso-a4-colored': Specifies the ISO A4 colored medium: 210 mm x 297
+ mm
+ 'iso-a4-transparent' Specifies the ISO A4 transparent medium: 210 mm
+ x 297 mm
+ 'iso-a3-white': Specifies the ISO A3 white medium: 297 mm x 420 mm
+ 'iso-a3-colored': Specifies the ISO A3 colored medium: 297 mm x 420
+ mm
+ 'iso-a5-white': Specifies the ISO A5 white medium: 148 mm x 210 mm
+ 'iso-a5-colored': Specifies the ISO A5 colored medium: 148 mm x 210
+ mm
+ 'iso-b4-white': Specifies the ISO B4 white medium: 250 mm x 353 mm
+ 'iso-b4-colored': Specifies the ISO B4 colored medium: 250 mm x 353
+ mm
+ 'iso-b5-white': Specifies the ISO B5 white medium: 176 mm x 250 mm
+ 'iso-b5-colored': Specifies the ISO B5 colored medium: 176 mm x 250
+ mm
+ 'jis-b4-white': Specifies the JIS B4 white medium: 257 mm x 364 mm
+ 'jis-b4-colored': Specifies the JIS B4 colored medium: 257 mm x 364
+ mm
+ 'jis-b5-white': Specifies the JIS B5 white medium: 182 mm x 257 mm
+ 'jis-b5-colored': Specifies the JIS B5 colored medium: 182 mm x 257
+ mm
+
+ The following standard values are defined for North American media:
+
+ 'na-letter-white': Specifies the North American letter white medium
+ 'na-letter-colored': Specifies the North American letter colored
+ medium
+ 'na-letter-transparent': Specifies the North American letter
+ transparent medium
+ 'na-legal-white': Specifies the North American legal white medium
+ 'na-legal-colored': Specifies the North American legal colored
+ medium
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 190]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The following standard values are defined for envelopes:
+
+ 'iso-b4-envelope': Specifies the ISO B4 envelope medium
+ 'iso-b5-envelope': Specifies the ISO B5 envelope medium
+ 'iso-c3-envelope': Specifies the ISO C3 envelope medium
+ 'iso-c4-envelope': Specifies the ISO C4 envelope medium
+ 'iso-c5-envelope': Specifies the ISO C5 envelope medium
+ 'iso-c6-envelope': Specifies the ISO C6 envelope medium
+ 'iso-designated-long-envelope': Specifies the ISO Designated Long
+ envelope medium
+ 'na-10x13-envelope': Specifies the North American 10x13 envelope
+ medium
+ 'na-9x12-envelope': Specifies the North American 9x12 envelope
+ medium
+ 'monarch-envelope': Specifies the Monarch envelope
+ 'na-number-10-envelope': Specifies the North American number 10
+ business envelope medium
+ 'na-7x9-envelope': Specifies the North American 7x9 inch envelope
+ 'na-9x11-envelope': Specifies the North American 9x11 inch
+ envelope
+ 'na-10x14-envelope': Specifies the North American 10x14 inch
+ envelope
+ 'na-number-9-envelope': Specifies the North American number 9
+ business envelope
+ 'na-6x9-envelope': Specifies the North American 6x9 inch envelope
+ 'na-10x15-envelope': Specifies the North American 10x15 inch
+ envelope
+
+ The following standard values are defined for the less commonly used
+ media:
+
+ 'executive-white': Specifies the white executive medium
+ 'folio-white': Specifies the folio white medium
+ 'invoice-white': Specifies the white invoice medium
+ 'ledger-white': Specifies the white ledger medium
+ 'quarto-white': Specified the white quarto medium
+ 'iso-a0-white': Specifies the ISO A0 white medium: 841 mm x 1189 mm
+ 'iso-a0-transparent': Specifies the ISO A0 transparent medium: 841 mm
+ x 1189 mm
+ 'iso-a0-translucent': Specifies the ISO A0 translucent medium: 841 mm
+ x 1189 mm
+ 'iso-a1-white': Specifies the ISO A1 white medium: 594 mm x 841 mm
+ 'iso-a1-transparent': Specifies the ISO A1 transparent medium: 594 mm
+ x 841 mm
+ 'iso-a1-translucent': Specifies the ISO A1 translucent medium: 594 mm
+ x 841 mm
+ 'iso-a2-white': Specifies the ISO A2 white medium: 420 mm x 594 mm
+
+
+
+
+Hastings, et al. Standards Track [Page 191]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'iso-a2-transparent': Specifies the ISO A2 transparent medium: 420 mm
+ x 594 mm
+ 'iso-a2-translucent': Specifies the ISO A2 translucent medium: 420 mm
+ x 594 mm
+ 'iso-a3-transparent': Specifies the ISO A3 transparent medium: 297 mm
+ x 420 mm
+ 'iso-a3-translucent': Specifies the ISO A3 translucent medium: 297 mm
+ x 420 mm
+ 'iso-a4-translucent': Specifies the ISO A4 translucent medium: 210 mm
+ x 297 mm
+ 'iso-a5-transparent': Specifies the ISO A5 transparent medium: 148 mm
+ x 210 mm
+ 'iso-a5-translucent': Specifies the ISO A5 translucent medium: 148 mm
+ x 210 mm
+ 'iso-a6-white': Specifies the ISO A6 white medium: 105 mm x 148 mm
+ 'iso-a7-white': Specifies the ISO A7 white medium: 74 mm x 105 mm
+ 'iso-a8-white': Specifies the ISO A8 white medium: 52 mm x 74 mm
+ 'iso-a9-white': Specifies the ISO A9 white medium: 37 mm x 52 mm
+ 'iso-a10-white': Specifies the ISO A10 white medium: 26 mm x 37 mm
+ 'iso-b0-white': Specifies the ISO B0 white medium: 1000 mm x 1414 mm
+ 'iso-b1-white': Specifies the ISO B1 white medium: 707 mm x 1000 mm
+ 'iso-b2-white': Specifies the ISO B2 white medium: 500 mm x 707 mm
+ 'iso-b3-white': Specifies the ISO B3 white medium: 353 mm x 500 mm
+ 'iso-b6-white': Specifies the ISO B6 white medium: 125 mm x 176 mm
+ 'iso-b7-white': Specifies the ISO B7 white medium: 88 mm x 125 mm
+ 'iso-b8-white': Specifies the ISO B8 white medium: 62 mm x 88 mm
+ 'iso-b9-white': Specifies the ISO B9 white medium: 44 mm x 62 mm
+ 'iso-b10-white': Specifies the ISO B10 white medium: 31 mm x 44 mm
+ 'jis-b0-white': Specifies the JIS B0 white medium: 1030 mm x 1456 mm
+ 'jis-b0-transparent': Specifies the JIS B0 transparent medium: 1030
+ mm x 1456 mm
+ 'jis-b0-translucent': Specifies the JIS B0 translucent medium: 1030
+ mm x 1456 mm
+ 'jis-b1-white': Specifies the JIS B1 white medium: 728 mm x 1030 mm
+ 'jis-b1-transparent': Specifies the JIS B1 transparent medium: 728 mm
+ x 1030 mm
+ 'jis-b1-translucent': Specifies the JIS B1 translucent medium: 728 mm
+ x 1030 mm
+ 'jis-b2-white': Specifies the JIS B2 white medium: 515 mm x 728 mm
+ 'jis-b2-transparent': Specifies the JIS B2 transparent medium: 515 mm
+ x 728 mm
+ 'jis-b2-translucent': Specifies the JIS B2 translucent medium: 515 mm
+ x 728 mm
+ 'jis-b3-white': Specifies the JIS B3 white medium: 364 mm x 515 mm
+ 'jis-b3-transparent': Specifies the JIS B3 transparent medium: 364 mm
+ x 515 mm
+ 'jis-b3-translucent': Specifies the JIS B3 translucent medium: 364 mm
+ x 515 mm
+
+
+
+Hastings, et al. Standards Track [Page 192]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'jis-b4-transparent': Specifies the JIS B4 transparent medium: 257 mm
+ x 364 mm
+ 'jis-b4-translucent': Specifies the JIS B4 translucent medium: 257 mm
+ x 364 mm
+ 'jis-b5-transparent': Specifies the JIS B5 transparent medium: 182 mm
+ x 257 mm
+ 'jis-b5-translucent': Specifies the JIS B5 translucent medium: 182 mm
+ x 257 mm
+ 'jis-b6-white': Specifies the JIS B6 white medium: 128 mm x 182 mm
+ 'jis-b7-white': Specifies the JIS B7 white medium: 91 mm x 128 mm
+ 'jis-b8-white': Specifies the JIS B8 white medium: 64 mm x 91 mm
+ 'jis-b9-white': Specifies the JIS B9 white medium: 45 mm x 64 mm
+ 'jis-b10-white': Specifies the JIS B10 white medium: 32 mm x 45 mm
+
+ The following standard values are defined for American Standard (i.e.
+ ANSI) engineering media:
+
+ 'a-white': Specifies the engineering ANSI A size white medium: 8.5
+ inches x 11 inches
+ 'a-transparent': Specifies the engineering ANSI A size transparent
+ medium: 8.5 inches x 11 inches
+ 'a-translucent': Specifies the engineering ANSI A size translucent
+ medium: 8.5 inches x 11 inches
+ 'b-white': Specifies the engineering ANSI B size white medium: 11
+ inches x 17 inches
+ 'b-transparent': Specifies the engineering ANSI B size transparent
+ medium: 11 inches x 17 inches)
+ 'b-translucent': Specifies the engineering ANSI B size translucent
+ medium: 11 inches x 17 inches
+ 'c-white': Specifies the engineering ANSI C size white medium: 17
+ inches x 22 inches
+ 'c-transparent': Specifies the engineering ANSI C size transparent
+ medium: 17 inches x 22 inches
+ 'c-translucent': Specifies the engineering ANSI C size translucent
+ medium: 17 inches x 22 inches
+ 'd-white': Specifies the engineering ANSI D size white medium: 22
+ inches x 34 inches
+ 'd-transparent': Specifies the engineering ANSI D size transparent
+ medium: 22 inches x 34 inches
+ 'd-translucent': Specifies the engineering ANSI D size translucent
+ medium: 22 inches x 34 inches
+ 'e-white': Specifies the engineering ANSI E size white medium: 34
+ inches x 44 inches
+ 'e-transparent': Specifies the engineering ANSI E size transparent
+ medium: 34 inches x 44 inches
+ 'e-translucent': Specifies the engineering ANSI E size translucent
+ medium: 34 inches x 44 inches
+
+
+
+
+Hastings, et al. Standards Track [Page 193]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The following standard values are defined for American Standard (i.e.
+ ANSI) engineering media for devices that provide the "synchro-cut"
+ feature (see section 14.1):
+
+ 'axsynchro-white': Specifies the roll paper having the width of the
+ longer edge (11 inches) of the engineering ANSI A size white medium
+ and cuts synchronizing with data.
+ 'axsynchro-transparent': Specifies the roll paper having the width of
+ the longer edge (11 inches) of the engineering ANSI A size
+ transparent medium and cuts synchronizing with data.
+ 'axsynchro-translucent': Specifies the roll paper having the width of
+ the longer edge (11 inches) of the engineering ANSI A size
+ translucent medium and cuts synchronizing with data.
+ 'bxsynchro-white': Specifies the roll paper having the width of the
+ longer edge (17 inches) of the engineering ANSI B size white medium
+ and cuts synchronizing with data.
+ 'bxsynchro-transparent': Specifies the roll paper having the width of
+ the longer edge (17 inches) of the engineering ANSI B size
+ transparent medium and cuts synchronizing with data.
+ 'bxsynchro-translucent': Specifies the roll paper having the width of
+ the longer edge (17 inches) of the engineering ANSI B size
+ translucent medium and cuts synchronizing with data.
+ 'cxsynchro-white': Specifies the roll paper having the width of the
+ longer edge (22 inches) of the engineering ANSI C size white medium
+ and cuts synchronizing with data.
+ 'cxsynchro-transparent': Specifies the roll paper having the width of
+ the longer edge (22 inches) of the engineering ANSI C size
+ transparent medium and cuts synchronizing with data.
+ 'cxsynchro-translucent': Specifies the roll paper having the width of
+ the longer edge (22 inches) of the engineering ANSI C size
+ translucent medium and cuts synchronizing with data.
+ 'dxsynchro-white': Specifies the roll paper having the width of the
+ longer edge (34 inches) of the engineering ANSI D size white medium
+ and cuts synchronizing with data.
+ 'dxsynchro-transparent': Specifies the roll paper having the width of
+ the longer edge (34 inches) of the engineering ANSI D size
+ transparent medium and cuts synchronizing with data.
+ 'dxsynchro-translucent': Specifies the roll paper having the width of
+ the longer edge (34 inches) of the engineering ANSI D size
+ translucent medium and cuts synchronizing with data.
+ 'exsynchro-white': Specifies the roll paper having the width of the
+ longer edge (44 inches) of the engineering ANSI E size white medium
+ and cuts synchronizing with data.
+ 'exsynchro-transparent': Specifies the roll paper having the width of
+ the longer edge (44 inches) of the engineering ANSI E size
+ transparent medium and cuts synchronizing with data.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 194]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'exsynchro-translucent': Specifies the roll paper having the width of
+ the longer edge (44 inches) of the engineering ANSI E size
+ translucent medium and cuts synchronizing with data.
+
+ The following standard values are defined for American Architectural
+ engineering media:
+
+ 'arch-a-white': Specifies the Architectural A size white medium: 9
+ inches x 12 inches
+ 'arch-a-transparent': Specifies the Architectural A size transparent
+ medium: 9 inches x 12 inches
+ 'arch-a-translucent': Specifies the Architectural A size translucent
+ medium: 9 inches x 12 inches
+ 'arch-b-white': Specifies the Architectural B size white medium: 12
+ inches x 18 inches
+ 'arch-b-transparent': Specifies the Architectural B size transparent
+ medium: 12 inches x 18 inches
+ 'arch-b-translucent': Specifies the Architectural B size translucent
+ medium: 12 inches x 18 inches
+ 'arch-c-white': Specifies the Architectural C size white medium: 18
+ inches x 24 inches
+ 'arch-c-transparent': Specifies the Architectural C size transparent
+ medium: 18 inches x 24 inches
+ 'arch-c-translucent': Specifies the Architectural C size translucent
+ medium: 18 inches x 24 inches
+ 'arch-d-white': Specifies the Architectural D size white medium: 24
+ inches x 36 inches
+ 'arch-d-transparent': Specifies the Architectural D size transparent
+ medium: 24 inches x 36 inches
+ 'arch-d-translucent': Specifies the Architectural D size translucent
+ medium: 24 inches x 36 inches
+ 'arch-e-white': Specifies the Architectural E size white medium: 36
+ inches x 48 inches
+ 'arch-e-transparent': Specifies the Architectural E size transparent
+ medium: 36 inches x 48 inches
+ 'arch-e-translucent': Specifies the Architectural E size translucent
+ medium: 36 inches x 48 inches
+
+ The following standard values are defined for American Architectural
+ engineering media for devices that provide the "synchro-cut" feature
+ (see section 14.1):
+
+ 'arch-axsynchro-white': Specifies the roll paper having the width of
+ the longer edge (12 inches) of the Architectural A size white
+ medium and cuts synchronizing with data.
+ 'arch-axsynchro-transparent': Specifies the roll paper having the
+ width of the longer edge (12 inches) of the Architectural A size
+ transparent medium and cuts synchronizing with data.
+
+
+
+Hastings, et al. Standards Track [Page 195]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'arch-axsynchro-translucent': Specifies the roll paper having the
+ width of the longer edge (12 inches) of the Architectural A size
+ translucent medium and cuts synchronizing with data.
+ 'arch-bxsynchro-white': Specifies the roll paper having the width of
+ the longer edge (18 inches) of the Architectural B size white
+ medium and cuts synchronizing with data.
+ 'arch-bxsynchro-transparent': Specifies the roll paper having the
+ width of the longer edge (18 inches) of the Architectural B size
+ transparent medium and cuts synchronizing with data.
+ 'arch-bxsynchro-translucent': Specifies the roll paper having the
+ width of the longer edge (18 inches) of the Architectural B size
+ translucent medium and cuts synchronizing with data.
+ 'arch-cxsynchro-white': Specifies the roll paper having the width of
+ the longer edge (24 inches) of the Architectural C size white
+ medium and cuts synchronizing with data.
+ 'arch-cxsynchro-transparent': Specifies the roll paper having the
+ width of the longer edge (24 inches) of the Architectural C size
+ transparent medium and cuts synchronizing with data.
+ 'arch-cxsynchro-translucent': Specifies the roll paper having the
+ width of the longer edge (24 inches) of the Architectural C size
+ translucent medium and cuts synchronizing with data.
+ 'arch-dxsynchro-white': Specifies the roll paper having the width of
+ the longer edge (36 inches) of the Architectural D size white
+ medium and cuts synchronizing with data.
+ 'arch-dxsynchro-transparent': Specifies the roll paper having the
+ width of the longer edge (36 inches) of the Architectural D size
+ transparent medium and cuts synchronizing with data.
+ 'arch-dxsynchro-translucent': Specifies the roll paper having the
+ width of the longer edge (36 inches) of the Architectural D size
+ translucent medium and cuts synchronizing with data.
+ 'arch-exsynchro-white': Specifies the roll paper having the width of
+ the longer edge (48 inches) of the Architectural E size white
+ medium and cuts synchronizing with data.
+ 'arch-exsynchro-transparent': Specifies the roll paper having the
+ width of the longer edge (48 inches) of the Architectural E size
+ transparent medium and cuts synchronizing with data.
+ 'arch-exsynchro-translucent': Specifies the roll paper having the
+ width of the longer edge (48 inches) of the Architectural E size
+ translucent medium and cuts synchronizing with data.
+
+ The following standard values are defined for Japanese and European
+ Standard (i.e. ISO) engineering media, which are of a long fixed size
+ [ASME-Y14.1M]:
+
+ 'iso-a1x3-white': Specifies the ISO A1X3 white medium having the
+ width of the longer edge (841 mm) of the ISO A1 medium
+
+
+
+
+
+Hastings, et al. Standards Track [Page 196]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'iso-a1x3-transparent': Specifies the ISO A1X3 transparent medium
+ having the width of the longer edge (841 mm) of the ISO A1
+ medium
+ 'iso-a1x3-translucent': Specifies the ISO A1X3 translucent medium
+ having the width of the longer edge (841 mm) of the ISO A1
+ medium
+ 'iso-a1x4-white': Specifies the ISO A1X4 white medium having the
+ width of the longer edge (841 mm) of the ISO A1 medium
+ 'iso-a1x4-transparent': Specifies the ISO A1X4 transparent medium
+ having the width of the longer edge (841 mm) of the ISO A1
+ medium
+ 'iso-a1x4- translucent': Specifies the ISO A1X4 translucent medium
+ having the width of the longer edge (841 mm) of the ISO A1
+ medium
+ 'iso-a2x3-white': Specifies the ISO A2X3 white medium having the
+ width of the longer edge (594 mm) of the ISO A2 medium
+ 'iso-a2x3-transparent': Specifies the ISO A2X3 transparent medium
+ having the width of the longer edge (594 mm) of the ISO A2
+ medium
+ 'iso-a2x3-translucent': Specifies the ISO A2X3 translucent medium
+ having the width of the longer edge (594 mm) of the ISO A2
+ medium
+ 'iso-a2x4-white': Specifies the ISO A2X4 white medium having the
+ width of the longer edge (594 mm) of the ISO A2 medium
+ 'iso-a2x4-transparent': Specifies the ISO A2X4 transparent medium
+ having the width of the longer edge (594 mm) of the ISO A2
+ medium
+ 'iso-a2x4-translucent': Specifies the ISO A2X4 translucent medium
+ having the width of the longer edge (594 mm) of the ISO A2
+ medium
+ 'iso-a2x5-white': Specifies the ISO A2X5 white medium having the
+ width of the longer edge (594 mm) of the ISO A2 medium
+ 'iso-a2x5-transparent': Specifies the ISO A2X5 transparent medium
+ having the width of the longer edge (594 mm) of the ISO A2
+ medium
+ 'iso-a2x5-translucent': Specifies the ISO A2X5 translucent medium
+ having the width of the longer edge (594 mm) of the ISO A2
+ medium
+ 'iso-a3x3-white': Specifies the ISO A3X3 white medium having the
+ width of the longer edge (420 mm) of the ISO A3 medium
+ 'iso-a3x3-transparent': Specifies the ISO A3X3 transparent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x3-translucent': Specifies the ISO A3X3 translucent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x4-white': Specifies the ISO A3X4 white medium having the
+ width of the longer edge (420 mm) of the ISO A3 medium
+
+
+
+Hastings, et al. Standards Track [Page 197]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'iso-a3x4-transparent': Specifies the ISO A3X4 transparent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x4-translucent': Specifies the ISO A3X4 translucent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x5-white': Specifies the ISO A3X5 white medium having the
+ width of the longer edge (420 mm) of the ISO A3 medium
+ 'iso-a3x5-transparent': Specifies the ISO A3X5 transparent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x5-translucent': Specifies the ISO A3X5 translucent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x6-white': Specifies the ISO A3X6 white medium having the
+ width of the longer edge (420 mm) of the ISO A3 medium
+ 'iso-a3x6-transparent': Specifies the ISO A3X6 transparent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x6-translucent': Specifies the ISO A3X6 translucent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x7-white': Specifies the ISO A3X7 white medium having the
+ width of the longer edge (420 mm) of the ISO A3 medium
+ 'iso-a3x7-transparent': Specifies the ISO A3X7 transparent medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a3x7-translucent'': Specifies the ISO A3X7 translucent' medium
+ having the width of the longer edge (420 mm) of the ISO A3
+ medium
+ 'iso-a4x3-white': Specifies the ISO A4X3 white medium having the
+ width of the longer edge (297 mm) of the ISO A4 medium
+ 'iso-a4x3-transparent': Specifies the ISO A4X3 transparent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x3-translucent'': Specifies the ISO A4X3 translucent' medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x4-white': Specifies the ISO A4X4 white medium having the
+ width of the longer edge (297 mm) of the ISO A4 medium
+ 'iso-a4x4-transparent': Specifies the ISO A4X4 transparent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x4-translucent': Specifies the ISO A4X4 translucent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x5-white': Specifies the ISO A4X5 white medium having the
+ width of the longer edge (297 mm) of the ISO A4 medium
+
+
+
+Hastings, et al. Standards Track [Page 198]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'iso-a4x5-transparent': Specifies the ISO A4X5 transparent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x5-translucent': Specifies the ISO A4X5 translucent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x6-white': Specifies the ISO A4X6 white medium having the
+ width of the longer edge (297 mm) of the ISO A4 medium
+ 'iso-a4x6-transparent': Specifies the ISO A4X6 transparent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x6-translucent': Specifies the ISO A4X6 translucent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x7-white': Specifies the ISO A4X7 white medium having the
+ width of the longer edge (297 mm) of the ISO A4 medium
+ 'iso-a4x7-transparent': Specifies the ISO A4X7 transparent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x7-translucent': Specifies the ISO A4X7 translucent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x8-white': Specifies the ISO A4X8 white medium having the
+ width of the longer edge (297 mm) of the ISO A4 medium
+ 'iso-a4x8-transparent': Specifies the ISO A4X8 transparent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x8-translucent': Specifies the ISO A4X8 translucent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x9-white': Specifies the ISO A4X9 white medium having the
+ width of the longer edge (297 mm) of the ISO A4 medium
+ 'iso-a4x9-transparent': Specifies the ISO A4X9 transparent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+ 'iso-a4x9-translucent': Specifies the ISO A4X9 translucent medium
+ having the width of the longer edge (297 mm) of the ISO A4
+ medium
+
+ The following standard values are defined for Japanese and European
+ Standard (i.e. ISO) engineering media, which are either a long fixed
+ size [ASME-Y14.1M] or roll feed, for devices that provide the
+ "synchro-cut" feature (see section 14.1):
+
+ 'iso-a0xsynchro-white': Specifies the paper having the width of the
+ longer edge (1189 mm) of the ISO A0 white medium and cuts
+ synchronizing with data.
+
+
+
+
+Hastings, et al. Standards Track [Page 199]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'iso-a0xsynchro-transparent': Specifies the paper having the width of
+ the longer edge (1189 mm) of the ISO A0 transparent medium and
+ cuts synchronizing with data.
+ 'iso-a0xsynchro-translucent': Specifies the paper having the width of
+ the longer edge (1189 mm) of the ISO A0 translucent medium and
+ cuts synchronizing with data.
+ 'iso-a1xsynchro-white': Specifies the paper having the width of the
+ longer edge (841 mm) of the ISO A1 white medium and cuts
+ synchronizing with data.
+ 'iso-a1xsynchro-transparent': Specifies the paper having the width of
+ the longer edge (841 mm) of the ISO A1 transparent medium and
+ cuts synchronizing with data.
+ 'iso-a1xsynchro-translucent': Specifies the paper having the width of
+ the longer edge (841 mm) of the ISO A1 translucent medium and
+ cuts synchronizing with data.
+ 'iso-a2xsynchro-white': Specifies the paper having the width of the
+ longer edge (594 mm) of the ISO A2 white medium and cuts
+ synchronizing with data.
+ 'iso-a2xsynchro-transparent': Specifies the paper having the width of
+ the longer edge (594 mm) of the ISO A2 transparent medium and
+ cuts synchronizing with data.
+ 'iso-a2xsynchro-translucent': Specifies the paper having the width of
+ the longer edge (594 mm) of the ISO A2 translucent medium and
+ cuts synchronizing with data.
+ 'iso-a3xsynchro-white': Specifies the paper having the width of the
+ longer edge (420 mm) of the ISO A3 white medium and cuts
+ synchronizing with data.
+ 'iso-a3xsynchro-transparent': Specifies the paper having the width of
+ the longer edge (420 mm) of the ISO A3 transparent medium and
+ cuts synchronizing with data.
+ 'iso-a3xsynchro-translucent': Specifies the paper having the width of
+ the longer edge (420 mm) of the ISO A3 translucent medium and
+ cuts synchronizing with data.
+ 'iso-a4xsynchro-white': Specifies the paper having the width of the
+ longer edge (297 mm) of the ISO A4 white medium and cuts
+ synchronizing with data.
+ 'iso-a4xsynchro-transparent': Specifies the paper having the width of
+ the longer edge (297 mm) of the ISO A4 transparent medium and
+ cuts synchronizing with data.
+ 'iso-a4xsynchro-translucent': Specifies the paper having the width of
+ the longer edge (297 mm) of the ISO A4 transparent medium and
+ cuts synchronizing with data.
+
+ The following standard values are defined for American Standard (i.e.
+ ANSI) engineering media, American Architectural engineering media,
+ and Japanese and European Standard (i.e. ISO) engineering media,
+
+
+
+
+
+Hastings, et al. Standards Track [Page 200]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ which are either a long fixed size [ASME-Y14.1M] or roll feed, for
+ devices that provide the "synchro-cut" feature and/or the "auto-
+ select" feature (see section 14.1):
+
+ 'auto-white': Specifies that the printer selects the white medium
+ with the appropriate fixed size (e.g. a1, a2, etc.) or data-
+ synchro size, and the selection is implementation-defined.
+ 'auto-transparent': Specifies that the printer selects the
+ transparent medium with the appropriate fixed size (e.g. a1, a2,
+ etc.) or data-synchro size, and the selection is implementation-
+ defined.
+ 'auto-translucent': Specifies that the printer selects the
+ translucent medium with the appropriate fixed size (e.g. a1, a2,
+ etc.) or data-synchro size, and the selection is implementation-
+ defined.
+ 'auto-fixed-size-white': Specifies that the printer selects the white
+ medium with the appropriate fixed size (e.g. a1, a2, etc.) or
+ the appropriate long fixed size listed above.
+ 'auto-fixed-size-transparent': Specifies that the printer selects the
+ transparent medium with the appropriate fixed size (e.g. a1, a2,
+ etc.) or the appropriate long fixed size listed above.
+ 'auto-fixed-size-translucent': Specifies that the printer selects the
+ translucent medium with the appropriate fixed size (e.g. a1, a2,
+ etc.) or the appropriate long fixed size listed above.
+ 'auto-synchro-white': Specifies that the printer selects the white
+ paper with the appropriate width and cuts it synchronizing with
+ data.
+ 'auto-synchro-transparent': Specifies that the printer selects the
+ transparent paper with the appropriate width and cuts it
+ synchronizing with data.
+ 'auto-synchro-translucent': Specifies that the printer selects the
+ translucent paper with the appropriate width and cuts it
+ synchronizing with data.
+
+ The following standard values are defined for input-trays (from ISO
+ DPA and the Printer MIB):
+
+ 'top': The top input tray in the printer.
+ 'middle': The middle input tray in the printer.
+ 'bottom': The bottom input tray in the printer.
+ 'envelope': The envelope input tray in the printer.
+ 'manual': The manual feed input tray in the printer.
+ 'large-capacity': The large capacity input tray in the printer.
+ 'main': The main input tray
+ 'side': The side input tray
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 201]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The following standard values are defined for media sizes (from ISO
+ DPA):
+
+ 'iso-a0': Specifies the ISO A0 size: 841 mm by 1189 mm as defined in
+ ISO 216
+ 'iso-a1': Specifies the ISO A1 size: 594 mm by 841 mm as defined in
+ ISO 216
+ 'iso-a2': Specifies the ISO A2 size: 420 mm by 594 mm as defined in
+ ISO 216
+ 'iso-a3': Specifies the ISO A3 size: 297 mm by 420 mm as defined in
+ ISO 216
+ 'iso-a4': Specifies the ISO A4 size: 210 mm by 297 mm as defined in
+ ISO 216
+ 'iso-a5': Specifies the ISO A5 size: 148 mm by 210 mm as defined in
+ ISO 216
+ 'iso-a6': Specifies the ISO A6 size: 105 mm by 148 mm as defined in
+ ISO 216
+ 'iso-a7': Specifies the ISO A7 size: 74 mm by 105 mm as defined in
+ ISO 216
+ 'iso-a8': Specifies the ISO A8 size: 52 mm by 74 mm as defined in ISO
+ 216
+ 'iso-a9': Specifies the ISO A9 size: 37 mm by 52 mm as defined in ISO
+ 216
+ 'iso-a10': Specifies the ISO A10 size: 26 mm by 37 mm as defined in
+ ISO 216
+ 'iso-b0': Specifies the ISO B0 size: 1000 mm by 1414 mm as defined in
+ ISO 216
+ 'iso-b1': Specifies the ISO B1 size: 707 mm by 1000 mm as defined in
+ ISO 216
+ 'iso-b2': Specifies the ISO B2 size: 500 mm by 707 mm as defined in
+ ISO 216
+ 'iso-b3': Specifies the ISO B3 size: 353 mm by 500 mm as defined in
+ ISO 216
+ 'iso-b4': Specifies the ISO B4 size: 250 mm by 353 mm as defined in
+ ISO 216
+ 'iso-b5': Specifies the ISO B5 size: 176 mm by 250 mm as defined in
+ ISO 216
+ 'iso-b6': Specifies the ISO B6 size: 125 mm by 176 mm as defined in
+ ISO 216
+ 'iso-b7': Specifies the ISO B7 size: 88 mm by 125 mm as defined in
+ ISO 216
+ 'iso-b8': Specifies the ISO B8 size: 62 mm by 88 mm as defined in ISO
+ 216
+ 'iso-b9': Specifies the ISO B9 size: 44 mm by 62 mm as defined in ISO
+ 216
+ 'iso-b10': Specifies the ISO B10 size: 31 mm by 44 mm as defined in
+ ISO 216
+
+
+
+
+Hastings, et al. Standards Track [Page 202]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'na-letter': Specifies the North American letter size: 8.5 inches by
+ 11 inches
+ 'na-legal': Specifies the North American legal size: 8.5 inches by 14
+ inches
+ 'na-8x10': Specifies the North American 8 inches by 10 inches
+ 'na-5x7': Specifies the North American 5 inches by 7 inches
+ 'executive': Specifies the executive size (7.25 X 10.5 in)
+ 'folio': Specifies the folio size (8.5 X 13 in)
+ 'invoice': Specifies the invoice size (5.5 X 8.5 in)
+ 'ledger': Specifies the ledger size (11 X 17 in)
+ 'quarto': Specifies the quarto size (8.5 X 10.83 in)
+ 'iso-c3': Specifies the ISO C3 size: 324 mm by 458 mm as defined in
+ ISO 269
+ 'iso-c4': Specifies the ISO C4 size: 229 mm by 324 mm as defined in
+ ISO 269
+ 'iso-c5': Specifies the ISO C5 size: 162 mm by 229 mm as defined in
+ ISO 269
+ 'iso-c6': Specifies the ISO C6 size: 114 mm by 162 mm as defined in
+ ISO 269
+ 'iso-designated-long': Specifies the ISO Designated Long size: 110 mm
+ by 220 mm as defined in ISO 269
+ 'na-10x13-envelope': Specifies the North American 10x13 size: 10
+ inches by 13 inches
+ 'na-9x12-envelope': Specifies the North American 9x12 size: 9 inches
+ by 12 inches
+ 'na-number-10-envelope': Specifies the North American number 10
+ business envelope size: 4.125 inches by 9.5 inches
+ 'na-7x9-envelope': Specifies the North American 7x9 inch envelope
+ size
+ 'na-9x11-envelope': Specifies the North American 9x11 inch envelope
+ size
+ 'na-10x14-envelope': Specifies the North American 10x14 inch envelope
+ size
+ 'na-number-9-envelope': Specifies the North American number 9
+ business envelope size
+ 'na-6x9-envelope': Specifies the North American 6x9 envelope size
+ 'na-10x15-envelope': Specifies the North American 10x15 envelope size
+ 'monarch-envelope': Specifies the Monarch envelope size (3.87 x 7.5
+ in)
+ 'jis-b0': Specifies the JIS B0 size: 1030mm x 1456mm
+ 'jis-b1': Specifies the JIS B1 size: 728mm x 1030mm
+ 'jis-b2': Specifies the JIS B2 size: 515mm x 728mm
+ 'jis-b3': Specifies the JIS B3 size: 364mm x 515mm
+ 'jis-b4': Specifies the JIS B4 size: 257mm x 364mm
+ 'jis-b5': Specifies the JIS B5 size: 182mm x 257mm
+ 'jis-b6': Specifies the JIS B6 size: 128mm x 182mm
+ 'jis-b7': Specifies the JIS B7 size: 91mm x 128mm
+ 'jis-b8': Specifies the JIS B8 size: 64mm x 91mm
+
+
+
+Hastings, et al. Standards Track [Page 203]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 'jis-b9': Specifies the JIS B9 size: 45mm x 64mm
+ 'jis-b10': Specifies the JIS B10 size: 32mm x 45mm
+
+ The following standard values are defined for American Standard (i.e.
+ ANSI) engineering media sizes:
+
+ 'a': Specifies the engineering ANSI A size medium: 8.5 inches x 11
+ inches
+ 'b': Specifies the engineering ANSI B size medium: 11 inches x 17
+ inches
+ 'c': Specifies the engineering ANSI C size medium: 17 inches x 22
+ inches
+ 'd': Specifies the engineering ANSI D size medium: 22 inches x 34
+ inches
+ 'e': Specifies the engineering ANSI E size medium: 34 inches x 44
+ inches
+
+ The following standard values are defined for American Architectural
+ engineering media sizes:
+
+ 'arch-a': Specifies the Architectural A size medium: 9 inches x 12
+ inches
+ 'arch-b': Specifies the Architectural B size medium: 12 inches x 18
+ inches
+ 'arch-c': Specifies the Architectural C size medium: 18 inches x 24
+ inches
+ 'arch-d': Specifies the Architectural D size medium: 24 inches x 36
+ inches
+ 'arch-e': Specifies the Architectural E size medium: 36 inches x 48
+ inches
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 204]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+14.1. Examples
+
+ Below are examples to supplement the engineering media value
+ definitions.
+
+ Example 1: "Synchro-Cut", a device cutting the roll paper in
+ synchronization with the data
+
+ data height: A1 height
+ data width (shaded): A1 width < data width < (A1 width) x 2
+ specified value: 'iso-a1xsynchro-white'
+
+ | |
+ |<--- data width --->|
+ | |
+ | | | |
+ |<- A1 width ->|<- A1 width ->|
+ | | | |
+ cross ^ | | | |
+ feed | +--------------------------------------------/
+ direction | |//////////////|/////| | ^ /
+ | |//////////////|/////| | | /
+ | |//////////////|/////| | | /
+ | |//////////////|/////| | | \
+<-----------+- |//////////////|/////| | A1 \ roll
+feed | |//////////////|/////| | height \ paper
+direction |//////////////|/////| | | \
+ |//////////////|/////| | | /
+ |//////////////|/////| | v /
+ +------------------------------------------/
+ |
+ |
+ |<------ CUT HERE (to synchronize
+ | with data width)
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 205]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Example 2: "Auto-Cut", a device cutting the roll paper at multiples
+ of fixed-size media width
+
+ data height: A1 height
+ data width (shaded): A1 width < data width < (A1 width) x 2
+ specified value: 'auto-fixed-size-white'
+
+ | |
+ |<--- data width --->|
+ | |
+ | | | |
+ |<- A1 width ->|<- A1 width ->|
+ | | | |
+ cross ^ | | | |
+ feed | +--------------------------------------------/
+ direction | |//////////////|/////| | ^ /
+ | |//////////////|/////| | | /
+ | |//////////////|/////| | | /
+ | |//////////////|/////| | | \
+<-----------+- |//////////////|/////| | A1 \ roll
+feed | |//////////////|/////| | height \ paper
+direction |//////////////|/////| | | \
+ |//////////////|/////| | | /
+ |//////////////|/////| | v /
+ +------------------------------------------/
+ |
+ |
+ |<--- CUT HERE
+ | (to synchronize
+ | with data width)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 206]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Example 3: the 'iso-a4x4-white' fixed size paper
+
+ paper height: A4 height
+ paper width: (A4 width) x 4
+ specified value: 'iso-a4x4-white'
+
+ | | | | |
+ |<- A4 width ->|<- A4 width ->|<- A4 width ->|<- A4 width ->|
+ | | | | |
+ | | | | |
+ +-----------------------------------------------------------+
+ | ^ | | | |
+ | | | | | |
+ | | | | | |
+ | A4 | | | |
+ | height | | | |
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | v | | | |
+ +-----------------------------------------------------------+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 207]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Example 4: "Synchro-Cut", a device cutting the fixed size paper in
+ synchronization with the data
+
+ data height: A4 height
+ data width (shaded): (A4 width) x 2 < data width < (A4 width) x 3
+ specified value: 'iso-a4xsynchro-white'
+
+ | |
+ |<---------- data width ----------->|
+ | |
+ | | | | |
+ |<- A4 width ->|<- A4 width ->|<- A4 width ->|
+ | | | | |
+ cross ^ | | | | |
+ feed | +--------------------------------------------+
+ direction | |//////////////|//////////////|/////| ^ |
+ | |//////////////|//////////////|/////| | |
+ | |//////////////|//////////////|/////| | |
+ | |//////////////|//////////////|/////| | |
+ <-----------+- |//////////////|//////////////|/////| A4 |
+ feed | |//////////////|//////////////|/////| height |
+ direction |//////////////|//////////////|/////| | |
+ |//////////////|//////////////|/////| | |
+ |//////////////|//////////////|/////| v |
+ +--------------------------------------------+
+ |
+ CUT HERE ---->|
+ (to synchronize |
+ with data width) |
+
+15. APPENDIX D: Processing IPP Attributes
+
+ When submitting a print job to a Printer object, the IPP model allows
+ a client to supply operation and Job Template attributes along with
+ the document data. These Job Template attributes in the create
+ request affect the rendering, production and finishing of the
+ documents in the job. Similar types of instructions may also be
+ contained in the document to be printed, that is, embedded within the
+ print data itself. In addition, the Printer has a set of attributes
+ that describe what rendering and finishing options which are
+ supported by that Printer. This model, which allows for flexibility
+ and power, also introduces the potential that at job submission time,
+ these client-supplied attributes may conflict with either:
+
+ - what the implementation is capable of realizing (i.e., what the
+ Printer supports), as well as
+ - the instructions embedded within the print data itself.
+
+
+
+
+Hastings, et al. Standards Track [Page 208]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The following sections describe how these two types of conflicts are
+ handled in the IPP model.
+
+15.1 Fidelity
+
+ If there is a conflict between what the client requests and what a
+ Printer object supports, the client may request one of two possible
+ conflict handling mechanisms:
+
+ 1) either reject the job since the job can not be processed
+ exactly as specified, or
+ 2) allow the Printer to make any changes necessary to proceed with
+ processing the Job the best it can.
+
+ In the first case the client is indicating to the Printer object:
+ "Print the job exactly as specified with no exceptions, and if that
+ can't be done, don't even bother printing the job at all." In the
+ second case, the client is indicating to the Printer object: "It is
+ more important to make sure the job is printed rather than be
+ processed exactly as specified; just make sure the job is printed
+ even if some client-supplied attributes need to be changed or
+ ignored."
+
+ The IPP model accounts for this situation by introducing an "ipp-
+ attribute-fidelity" attribute.
+
+ In a create request, "ipp-attribute-fidelity" is a boolean operation
+ attribute that is OPTIONALLY supplied by the client. The value
+ 'true' indicates that total fidelity to client supplied Job Template
+ attributes and values is required. The client is requesting that the
+ Job be printed exactly as specified, and if that is not possible then
+ the job MUST be rejected rather than processed incorrectly. The
+ value 'false' indicates that a reasonable attempt to print the Job is
+ acceptable. If a Printer does not support some of the client
+ supplied Job Template attributes or values, the Printer MUST ignore
+ them or substitute any supported value for unsupported values,
+ respectively. The Printer may choose to substitute the default value
+ associated with that attribute, or use some other supported value
+ that is similar to the unsupported requested value. For example, if
+ a client supplies a "media" value of 'na-letter', the Printer may
+ choose to substitute 'iso-a4' rather than a default value of
+ 'envelope'. If the client does not supply the "ipp-attribute-
+ fidelity" attribute, the Printer assumes a value of 'false'.
+
+ Each Printer implementation MUST support both types of "fidelity"
+ printing (that is whether the client supplies a value of 'true' or
+ 'false'):
+
+
+
+
+Hastings, et al. Standards Track [Page 209]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ - If the client supplies 'false' or does not supply the attribute,
+ the Printer object MUST always accept the request by ignoring
+ unsupported Job Template attributes and by substituting
+ unsupported values of supported Job Template attributes with
+ supported values.
+ - If the client supplies 'true', the Printer object MUST reject
+ the request if the client supplies unsupported Job Template
+ attributes.
+
+ Since a client can always query a Printer to find out exactly what is
+ and is not supported, "ipp-attribute-fidelity" set to 'false' is
+ useful when:
+
+ 1) The End-User uses a command line interface to request
+ attributes that might not be supported.
+ 2) In a GUI context, if the End User expects the job might be
+ moved to another printer and prefers a sub-optimal result to
+ nothing at all.
+ 3) The End User just wants something reasonable in lieu of nothing
+ at all.
+
+15.2 Page Description Language (PDL) Override
+
+ If there is a conflict between the value of an IPP Job Template
+ attribute and a corresponding instruction in the document data, the
+ value of the IPP attribute SHOULD take precedence over the document
+ instruction. Consider the case where a previously formatted file of
+ document data is sent to an IPP Printer. In this case, if the client
+ supplies any attributes at job submission time, the client desires
+ that those attributes override the embedded instructions. Consider
+ the case were a previously formatted document has embedded in it
+ commands to load 'iso-a4' media. However, the document is passed to
+ an end user that only has access to a printer with 'na-letter' media
+ loaded. That end user most likely wants to submit that document to
+ an IPP Printer with the "media" Job Template attribute set to 'na-
+ letter'. The job submission attribute should take precedence over
+ the embedded PDL instruction. However, until companies that supply
+ document data interpreters allow a way for external IPP attributes to
+ take precedence over embedded job production instructions, a Printer
+ might not be able to support the semantics that IPP attributes
+ override the embedded instructions.
+
+ The IPP model accounts for this situation by introducing a "pdl-
+ override-supported" attribute that describes the Printer objects
+ capabilities to override instructions embedded in the PDL data
+ stream. The value of the "pdl-override-supported" attribute is
+ configured by means outside the scope of this IPP/1.1 document.
+
+
+
+
+Hastings, et al. Standards Track [Page 210]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ This REQUIRED Printer attribute takes on the following values:
+
+ - 'attempted': This value indicates that the Printer object
+ attempts to make the IPP attribute values take precedence over
+ embedded instructions in the document data, however there is no
+ guarantee.
+ - 'not-attempted': This value indicates that the Printer object
+ makes no attempt to make the IPP attribute values take
+ precedence over embedded instructions in the document data.
+
+ At job processing time, an implementation that supports the value of
+ 'attempted' might do one of several different actions:
+
+ 1) Generate an output device specific command sequence to realize
+ the feature represented by the IPP attribute value.
+ 2) Parse the document data itself and replace the conflicting
+ embedded instruction with a new embedded instruction that
+ matches the intent of the IPP attribute value.
+ 3) Indicate to the Printer that external supplied attributes take
+ precedence over embedded instructions and then pass the
+ external IPP attribute values to the document data interpreter.
+ 4) Anything else that allows for the semantics that IPP attributes
+ override embedded document data instructions.
+
+ Since 'attempted' does not offer any type of guarantee, even though a
+ given Printer object might not do a very "good" job of attempting to
+ ensure that IPP attributes take a higher precedence over instructions
+ embedded in the document data, it would still be a conforming
+ implementation.
+
+ At job processing time, an implementation that supports the value of
+ 'not-attempted' might do one of the following actions:
+
+ 1) Simply pre-pend the document data with the PDL instruction that
+ corresponds to the client-supplied PDL attribute, such that if
+ the document data also has the same PDL instruction, it will
+ override what the Printer object pre-pended. In other words,
+ this implementation is using the same implementation semantics
+ for the client-supplied IPP attributes as for the Printer
+ object defaults.
+
+ 2) Parse the document data and replace the conflicting embedded
+ instruction with a new embedded instruction that approximates,
+ but does not match, the semantic intent of the IPP attribute
+ value.
+
+ Note: The "ipp-attribute-fidelity" attribute applies to the
+ Printer's ability to either accept or reject other unsupported Job
+
+
+
+Hastings, et al. Standards Track [Page 211]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ Template attributes. In other words, if "ipp-attribute-fidelity" is
+ set to 'true', a Job is accepted if and only if the client supplied
+ Job Template attributes and values are supported by the Printer.
+ Whether these attributes actually affect the processing of the Job
+ when the document data contains embedded instructions depends on the
+ ability of the Printer to override the instructions embedded in the
+ document data with the semantics of the IPP attributes. If the
+ document data attributes can be overridden ("pdl-override-supported"
+ set to 'attempted'), the Printer makes an attempt to use the IPP
+ attributes when processing the Job. If the document data attributes
+ can not be overridden ("pdl-override-supported" set to 'not-
+ attempted'), the Printer makes no attempt to override the embedded
+ document data instructions with the IPP attributes when processing
+ the Job, and hence, the IPP attributes may fail to affect the Job
+ processing and output when the corresponding instruction is embedded
+ in the document data.
+
+15.3 Using Job Template Attributes During Document Processing.
+
+ The Printer object uses some of the Job object's Job Template
+ attributes during the processing of the document data associated with
+ that job. These include, but are not limited to, "orientation-
+ requested", "number-up", "sides", "media", and "copies". The
+ processing of each document in a Job Object MUST follow the steps
+ below. These steps are intended only to identify when and how
+ attributes are to be used in processing document data and any
+ alternative steps that accomplishes the same effect can be used to
+ implement this specification document.
+
+ 1. Using the client supplied "document-format" attribute or some
+ form of document format detection algorithm (if the value of
+ "document-format" is not specific enough), determine whether or
+ not the document data has already been formatted for printing.
+ If the document data has been formatted, then go to step 2.
+ Otherwise, the document data MUST be formatted. The formatting
+ detection algorithm is implementation defined and is not
+ specified by this document. The formatting of the document
+ data uses the "orientation-requested" attribute to determine
+ how the formatted print data should be placed on a print-stream
+ page, see section 4.2.10 for the details.
+
+ 2. The document data is in the form of a print-stream in a known
+ media type. The "page-ranges" attribute is used to select, as
+ specified in section 4.2.7, a sub-sequence of the pages in the
+ print-stream that are to be processed and images.
+
+ 3. The input to this step is a sequence of print-stream pages.
+ This step is controlled by the "number-up" attribute. If the
+
+
+
+Hastings, et al. Standards Track [Page 212]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ value of "number-up" is N, then during the processing of the
+ print-stream pages, each N print-stream pages are positioned,
+ as specified in section 4.2.9, to create a single impression.
+ If a given document does not have N more print-stream pages,
+ then the completion of the impression is controlled by the
+ "multiple-document-handling" attribute as described in section
+ 4.2.4; when the value of this attribute is 'single-document' or
+ 'single-document-new-sheet', the print-stream pages of document
+ data from subsequent documents is used to complete the
+ impression.
+
+ The size(scaling), position(translation) and rotation of the
+ print-stream pages on the impression is implementation defined.
+ Note that during this process the print-stream pages may be
+ rendered to a form suitable for placing on the impression; this
+ rendering is controlled by the values of the "printer-
+ resolution" and "print-quality" attributes as described in
+ sections 4.2.12 and 4.2.13. In the case N=1, the impression is
+ nearly the same as the print-stream page; the differences would
+ only be in the size, position and rotation of the print-stream
+ page and/or any decoration, such as a frame to the page, that
+ is added by the implementation.
+
+ 4. The collection of impressions is placed, in sequence, onto
+ sides of the media sheets. This placement is controlled by the
+ "sides" attribute and the orientation of the print-stream page,
+ as described in section 4.2.8. The orientation of the print-
+ stream pages affects the orientation of the impression; for
+ example, if "number-up" equals 2, then, typically, two portrait
+ print-stream pages become one landscape impression. Note that
+ the placement of impressions onto media sheets is also
+ controlled by the "multiple-document-handling" attribute as
+ described in section 4.2.4.
+
+ 5. The "copies" and "multiple-document-handling" attributes are
+ used to determine how many copies of each media instance are
+ created and in what order. See sections 4.2.5 and 4.2.4 for the
+ details.
+
+ 6. When the correct number of copies are created, the media
+ instances are finished according to the values of the
+ "finishings" attribute as described in 4.2.6. Note that
+ sometimes finishing operations may require manual intervention
+ to perform the finishing operations on the copies, especially
+ uncollated copies. This document allows any or all of the
+ processing steps to be performed automatically or manually at
+ the discretion of the Printer object.
+
+
+
+
+Hastings, et al. Standards Track [Page 213]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+16. APPENDIX E: Generic Directory Schema
+
+ This section defines a generic schema for an entry in a directory
+ service. A directory service is a means by which service users can
+ locate service providers. In IPP environments, this means that IPP
+ Printers can be registered (either automatically or with the help of
+ an administrator) as entries of type printer in the directory using
+ an implementation specific mechanism such as entry attributes, entry
+ type fields, specific branches, etc. Directory clients can search or
+ browse for entries of type printer. Clients use the directory
+ service to find entries based on naming, organizational contexts, or
+ filtered searches on attribute values of entries. For example, a
+ client can find all printers in the "Local Department" context.
+ Authentication and authorization are also often part of a directory
+ service so that an administrator can place limits on end users so
+ that they are only allowed to find entries to which they have certain
+ access rights. IPP itself does not require any specific directory
+ service protocol or provider.
+
+ Note: Some directory implementations allow for the notion of
+ "aliasing". That is, one directory entry object can appear as
+ multiple directory entry object with different names for each object.
+ In each case, each alias refers to the same directory entry object
+ which refers to a single IPP Printer object.
+
+ The generic schema is a subset of IPP Printer Job Template and
+ Printer Description attributes (sections 4.2 and 4.4). These
+ attributes are identified as either RECOMMENDED or OPTIONAL for the
+ directory entry itself. This conformance labeling is NOT the same
+ conformance labeling applied to the attributes of IPP Printers
+ objects. The conformance labeling in this Appendix is intended to
+ apply to directory templates and to IPP Printer implementations that
+ subscribe by adding one or more entries to a directory. RECOMMENDED
+ attributes SHOULD be associated with each directory entry. OPTIONAL
+ attributes MAY be associated with the directory entry (if known or
+ supported). In addition, all directory entry attributes SHOULD
+ reflect the current attribute values for the corresponding Printer
+ object.
+
+ The names of attributes in directory schema and entries SHOULD be the
+ same as the IPP Printer attribute names as shown, as much as
+ possible.
+
+ In order to bridge between the directory service and the IPP Printer
+ object, one of the RECOMMENDED directory entry attributes is the
+ Printer object's "printer-uri-supported" attribute. The directory
+ client queries the "printer-uri-supported" attribute (or its
+ equivalent) in the directory entry and then the IPP client addresses
+
+
+
+Hastings, et al. Standards Track [Page 214]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ the IPP Printer object using one of its URIs. The "uri-security-
+ supported" attribute identifies the protocol (if any) used to secure
+ a channel.
+
+ The following attributes define the generic schema for directory
+ entries of type PRINTER:
+
+ printer-uri-supported RECOMMENDED Section 4.4.1
+ uri-authentication-supported RECOMMENDED Section 4.4.2
+ uri-security-supported RECOMMENDED Section 4.4.3
+ printer-name RECOMMENDED Section 4.4.4
+ printer-location RECOMMENDED Section 4.4.5
+ printer-info OPTIONAL Section 4.4.6
+ printer-more-info OPTIONAL Section 4.4.7
+ printer-make-and-model RECOMMENDED Section 4.4.9
+ ipp-versions-supported RECOMMENDED Section 4.4.14
+ multiple-document-jobs-supported OPTIONAL Section 4.4.16
+ charset-supported OPTIONAL Section 4.4.18
+
+ generated-natural-language-
+ supported OPTIONAL Section 4.4.20
+ document-format-supported RECOMMENDED Section 4.4.22
+ color-supported RECOMMENDED Section 4.4.26
+ compression-supported RECOMMENDED Section 4.4.32
+ pages-per-minute OPTIONAL Section 4.4.36
+ pages-per-minute-color OPTIONAL Section 4.4.37
+
+ finishings-supported OPTIONAL Section 4.2.6
+ number-up-supported OPTIONAL Section 4.2.7
+ sides-supported RECOMMENDED Section 4.2.8
+ media-supported RECOMMENDED Section 4.2.11
+ printer-resolution-supported OPTIONAL Section 4.2.12
+ print-quality-supported OPTIONAL Section 4.2.13
+
+17. APPENDIX F: Differences between the IPP/1.0 and IPP/1.1 "Model and
+ Semantics" Documents
+
+ This Appendix is divided into two lists that summarize the
+ differences between IPP/1.1 (this document) and IPP/1.0 [RFC2566].
+ The section numbers refer to the numbers in this document which in
+ some cases have changed from RFC 2566. When a change affects
+ multiple sections, the item is listed once in the order of the first
+ section affected and the remaining affected section numbers are
+ indicated.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 215]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ The first list contains extensions and clarifications and the second
+ list contains changes in semantics or conformance. However, client
+ and IPP object implementations of IPP/1.0 MAY implement any of the
+ extensions and clarifications in this document.
+
+ The following extensions and clarifications have been incorporated
+ into this document:
+
+ 1. Section 2.1 - clarified that the term "client" can be either
+ contained in software controlled by an end user or a part of a
+ print server that controls devices.
+ 2. Section 2 - clarified that the term "IPP object" and "Printer
+ object" can either be embedded in a device object or part of a
+ print server that accepts IPP requests.
+ 3. Section 2.4 - added the description of the new "uri-
+ authentication-supported" Printer Description attribute.
+ 4. Section 3.1.3, 3.1.6, 3.2.5.2, and 3.2.6.2 - clarified the
+ error handling for operation attributes that have their own
+ status code.
+ 5. Section 3.1.3 - clarified that multiple occurrences of the
+ same attribute in an attribute group is mal-formed. An IPP
+ Printer MAY reject the request or choose one of the
+ attributes.
+ 6. Section 3.1.6 - reorganized this section into sub-sections to
+ separately describe "status-code", "status-message",
+ "detailed-status-message", and "document-access-error"
+ attributes.
+ 7. Section 3.1.6.1 - clarified the error status codes and their
+ relationship to operation attributes.
+ 8. Section 3.1.6.3 - Added the OPTIONAL "detailed-status-message
+ (text(MAX))" operation attribute to provide additional more
+ detailed information about a response.
+ 9. Section 3.1.6.4 and 3.2.2 - Added the OPTIONAL "document-
+ access-error (text(MAX))" operation attribute for use with
+ Print-URI and Send-URI responses.
+ 10. Sections 3.1.7 - Added this new section to clarify returning
+ Unsupported Attributes for all operations, including only
+ returning attributes that were in the request. Moved the text
+ from section 3.2.1.2 Unsupported Attributes to this section.
+ 11. Sections 3.1.7 and 4.1 - clarified the encoding of the "out-
+ of-band" 'unsupported' and 'unknown' values.
+ 12. Section 3.1.8 - clarified that only the version number
+ parameter will be carried forward into future major or minor
+ versions of the protocol.
+ 13. Section 3.1.8 - relaxed the requirements to increment the
+ major version number in future versions of the Model and
+ Semantics document.
+
+
+
+
+Hastings, et al. Standards Track [Page 216]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 14. Section 3.1.9, and 3.2.5 - added the 'processing' state to the
+ list of job states that a job can be in after a Create-Job
+ operation.
+ 15. Section 3.1.9 - clarified that a non-spooling Printer MAY
+ accept zero or more subsequent jobs while processing a job and
+ flow control them down. Subsequent create requests are
+ rejected with the 'server-error-busy' error status.
+ 16. Section 3.2.1.1 - clarified the validation of the
+ "compression" operation attribute and its relationship to the
+ validation of the "document-format" attribute and returning
+ Unsupported Attributes.
+ 17. Sections 3.2.1.1, 4.3.8, 13.1.4.16, and 13.1.4.17 - added the
+ 'client-error-compression-not-supported', 'client-error-
+ compression-error' status codes and the 'unsupported-
+ compression' and 'compression-error' job-state-reasons.
+ 18. Sections 3.2.1.1 and 4.3.8 - added 'unsupported-document-
+ format' and 'document-format-error' job-state-reasons.
+ 19. Sections 3.2.2, 4.3.8 and 13.1.4.19 - added 'client-error-
+ document-access-error' status code and 'document-access-error'
+ job state reason.
+ 20. Section 3.2.5.2 and 3.2.6.2 - clarified that the Unsupported
+ Attributes group MUST NOT include attributes not requested in
+ the Get-Printer-Attributes request.
+ 21. Section 3.2.6 - clarified that "limit" takes precedence over
+ "which-jobs" and "my-jobs'.
+ 22. Section 3.2.6.2 - clarified that Get-Jobs returns
+ 'successful-ok' when no jobs to return.
+ 23. Sections 3.2.7, 3.2.8, and 3.2.9 - added the OPTIONAL Pause-
+ Printer, Resume-Printer, and Purge-Jobs operations
+ 24. Section 3.3.1 - clarified that the authorization required for
+ a Send-Document request MUST be the same user as the Create-
+ Job or an operator.
+ 25. Section 3.3.1.1 - clarified that a Create-Job Send-Document
+ with "last-document" = 'true' and no data is not an error; its
+ a job with no documents.
+ 26. Sections 3.3.5, 3.3.6, and 3.3.7 - added the OPTIONAL Hold-
+ Job, Release-Job, and Restart-Job operations. Clarified the
+ Restart-Job operation so that the Printer MUST re-fetch any
+ documents passed by-reference (Print-URI or Send-URI).
+ 27. Section 4.1 - clarified that the encoding of the out-of-band
+ values are specified in the Encoding and Transport" document.
+ 28. Section 4.1 - Clarified that the requirement that clients MUST
+ NOT send "out-of-band" values in requests applies only to
+ operations defined in this document. Other operations are
+ allowed to define "out-of-band" values that clients can
+ supply.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 217]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 29. Sections 4.1.1 and 4.1.2 - clarified that the maximum 'text'
+ and 'name' values of 1023 and 255 are for the
+ 'textWithoutLanguage' portion of the 'textWithLanguage' form,
+ so that the maximum number of octets for the actual text and
+ name data is the same for the without and with language forms;
+ the 'naturalLanguage' part is in addition.
+ 30. Section 4.1.9 - clarified that 'mimeMediaType' values can
+ include any parameters from the IANA Registry, not just
+ charset parameters.
+ 31. Section 4.1.9.1 - clarified that 'application/octet-stream'
+ auto-sensing can happen at create request time and/or
+ job/document processing time.
+ 32. Section 4.1.9.1 - clarified that auto-sensing involves the
+ Printer examining some number of octets of document data using
+ an implementation-dependent method.
+ 33. Section 4.1.14 - clarified that the localization of dateTime
+ by the client includes the time zone.
+ 34. Section 4.2 - clarified that xxx-supported have multiple
+ keywords and/or names by adding parentheses to the table to
+ give: (1setOf (type3 keyword | name))
+ 35. Section 4.2.2 - added the 'indefinite' keyword value to the
+ "job-hold-until" attribute for use with the create operations
+ and Hold-Job and Restart-Job operations.
+ 36. Section 4.2.6 - added more enum values to the "finishings" Job
+ Template attribute.
+ 37. Section 4.2.6 - clarified that the landscape definition is a
+ rotation of the image with respect to the medium.
+ 38. Section 4.3.7 - added that a forwarding server that cannot get
+ any job state MAY return the job's state as 'completed',
+ provided that it also return the new 'queued-in-device' job
+ state reason.
+ 39. Section 4.3.7.2 - added the Partitioning of Job States section
+ to clarify the concepts of Job Retention, Job History, and Job
+ Removal.
+ 40. Section 4.3.8 - added 'job-data-insufficient' job state reason
+ to indicate whether sufficient data has arrived for the
+ document to start to be processed.
+ 41. Section 4.3.8 - added 'document-access-error' job state reason
+ to indicate an access error of any kind.
+ 42. Section 4.3.8 - added 'job-queued-for-marker' job state reason
+ to indicate whether the job has completed some processing and
+ is waiting for the marker.
+ 43. Section 4.3.8 - added 'unsupported-compression' and
+ 'compression-error' job state reasons to indicate compression
+ not supported or compression processing error after the create
+ has been accepted.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 218]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 44. Section 4.3.8 - added 'unsupported-document-format' and
+ 'document-format-error' job state reasons to indicate document
+ not supported or document format processing error after the
+ create has been accepted.
+ 45. Section 4.3.8 - added 'queued-in-device' job state reason to
+ indicate that a job as been forwarded to a print system or
+ device that does not provide any job status.
+ 46. Section 4.3.10 - added "job-detailed-status-messages (1setOf
+ text(MAX)) for returning detailed error messages.
+ 47. Section 4.3.11 - added the "job-document-access-errors (1setOf
+ text(MAX))
+ 48. Section 4.3.14.2 - clarified that the time recorded is the
+ first time processing since the create operation or the
+ Restart-Job operation.
+ 49. Section 4.3.14.2 and 4.3.14.3 - clarified that the out-of-band
+ value 'no-value' is returned if the job has not started
+ processing or has not completed, respectively.
+ 50. Section 4.3.14 - Added the OPTIONAL "date-time-at-creation",
+ "date-time-at-processing", and "date-time-at-completed" Event
+ Time Job Description attributes
+ 51. Section 4.4.3 - added the 'tls' value to "uri-security-
+ supported" attribute.
+ 52. Section 4.4.3 - clarified "uri-security-supported" is
+ orthogonal to Client Authentication so that 'none' does not
+ exclude Client Authentication.
+ 53. Section 4.4.11 - simplified the "printer-state" descriptions
+ while generalizing to allow high end devices that interpret
+ one or more jobs while marking another. Indicated that
+ 'spool-area-full' and 'stopped-partly' "printer-state-reasons"
+ may be used to provide further state information.
+ 54. Section 4.4.12 - added the 'moving-to-paused' keyword value to
+ the "printer-state-reasons" attribute for use with the Pause-
+ Printer operation.
+ 55. Section 4.4.12 - replaced the duplicate 'marker-supply-low'
+ keyword with the missing 'toner-empty' keyword for the
+ "printer-state-reasons" attribute. (This correction was also
+ made before RFC 2566 was published).
+ 56. Section 4.4.12 - clarified 'spool-area-full' "printer-state-
+ reasons" to include non-spooling printers to indicate when it
+ can and cannot accept another job.
+ 57. Section 4.4.15 - added the enum values to the "operations-
+ supported" attribute for the new operations. Clarified that
+ the values of this attribute are encoded as any enum, namely
+ 32-bit values.
+ 58. Section 4.4.30 - clarified that the dateTime value of
+ "printer-current-time" is on a "best efforts basis". If a
+ proper date-time cannot be obtained, the implementation
+ returns the 'no-value' out-of-band value. Also clarified that
+
+
+
+Hastings, et al. Standards Track [Page 219]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ the time zone NEED NOT be the time zone that the people near
+ the device use and that the client SHOULD display the dateTime
+ attributes in the user's local time.
+ 59. Sections 4.4.36 and 4.4.37 - added the OPTIONAL "pages-per-
+ minute" and "pages-per-minute-color" Printer Description
+ attributes.
+ 60. Section 5.1 - clarified that the client conformance
+ requirements apply to clients controlled by an end user and
+ clients in servers.
+ 61. Section 5.1 - clarified that any response MAY contain
+ additional attribute groups, attributes, attribute syntaxes,
+ or attribute values.
+ 62. Section 5.1 - clarified that a client SHOULD do its best to
+ prevent a channel from being closed by a lower layer when the
+ channel is flow controlled off by the IPP Printer.
+ 63. Section 5.2 - clarified that the IPP object requirements apply
+ to objects embedded in devices or that are parts of servers.
+ 64. Section 5.2.2 - clarified that IPP objects MAY return
+ operation responses that contain attribute groups, attribute
+ names, attribute syntaxes, attribute values, and status codes
+ that are extensions to this standard.
+ 65. Section 6 - changed the terminology of "private extensions" to
+ "vendor extensions" and indicated that they are registered
+ with IANA along with IETF standards track extensions.
+ 66. Section 6.7 - inserted this section on registering out-of-band
+ attribute values with IANA as extensions.
+ 67. Section 8.3 - clarified the use of URIs for each Client
+ Authentication mechanism.
+ 68. Section 8.5 - added the security discussion around the new
+ operator/administrator operations.
+ 69. Section 13.1.4.16 - added client-error-compression-not-
+ supported (0x040F)
+ 70. Section 13.1.4.17 - added client-error-compression-error
+ (0x0410)
+ 71. Section 13.1.4.18 - added client-error-document-format-error
+ (0x0411)
+ 72. Section 13.1.4.19 - added client-error-document-access-error
+ (0x0412)
+ 73. Section 13.1.5.10 - added server-error-multiple-document-
+ jobs-not-supported (0x0509)
+ 74. Section 14 - added 'a-white', 'b-white', 'c-white', 'd-white',
+ and 'e-white' and clarified that the existing 'a', 'b', 'c',
+ 'd', and 'e' values are size values. Added American,
+ Japanese, and European Engineering sizes, filled out
+ -transparent and - translucent media names and drawings for
+ the synchro cut sizes.
+
+
+
+
+
+Hastings, et al. Standards Track [Page 220]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 75. Section 16 - softened the RECOMMENDATION for IPP Printer
+ attributes in a Directory schema so that they can have
+ equivalents.
+ 76. Section 16 - added the OPTIONAL "pages-per-minute" and
+ "pages-per-minute-color" Printer attributes to the Directory
+ schema.
+ 77. Section 16 - added OPTIONAL "multiple-document-jobs-supported"
+ to the Directory schema.
+ 78. Section 16 - added RECOMMENDED "uri-authentication-supported",
+ "ipp-versions-supported", and "compression-supported" to the
+ Directory schema.
+
+ The following changes in semantics and/or conformance have been
+ incorporated into this document:
+
+ 1. Section 3.1.6.3 - allowed a Printer to localize the
+ "detailed-status-message" operation response attribute, but
+ indicated that such localization might obscure the technical
+ meaning of such messages.
+ 2. Section 3.1.8, 5.2.4, and 13.1.5.4 - Clients and IPP objects
+ MUST support version 1.1 conformance requirements. It is
+ recommended that they interoperate with 1.0. Also clarified
+ that IPP Printers MUST accept '1.1' requests. It is
+ recommended that they also accept '1.x' requests.
+
+ 3. Section 3.2.1.1 and section 4.4.32 - changed the "compression"
+ operation and the "compression-supported" Printer Description
+ attribute from OPTIONAL to REQUIRED.
+ 4. Sections 3.2.1.2 and 4.3.8 - changed "job-state-reasons" from
+ RECOMMENDED to REQUIRED, so that "job-state-reasons" MUST be
+ returned in create operation responses.
+ 5. Sections 3.2.4, 3.3.1, 4.4.16, and 16 - changed Create-
+ Job/Send-Document so that they MAY be implemented while only
+ supporting one document jobs. Added the "multiple-document-
+ jobs-supported" boolean Printer Description attribute to
+ indicate whether Create-Job/Send-Document support multiple
+ document jobs or not. Added to the Directory schema.
+ 6. Section 4.1.9 - deleted 'text/plain; charset=iso-10646-ucs-2',
+ since binary is not legal with the 'text' type.
+ 7. Section 4.1.9.1 - added the RECOMMENDATION that a Printer
+ indicate by printing on the job's job-start-sheet that auto-
+ sensing has occurred and what document format was auto-sensed.
+ 8. Section 4.2.4 - indicated that the "multiple-document-
+ handling" Job Template attribute MUST be supported with at
+ least one value if the Printer supports multiple documents per
+ job
+
+
+
+
+
+Hastings, et al. Standards Track [Page 221]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 9. Section 4.3.7.2 - indicated that the 'job-restartable' job
+ state reason SHOULD be supported if the Restart-Job operation
+ is supported.
+ 10. Section 4.3.8 - changed "job-state-reasons" from RECOMMENDED
+ to REQUIRED.
+ 11. Section 4.3.8 - clarified the conformance of the values of the
+ "job-state-reasons" attribute by copying conformance
+ requirements from other sections of the document so that it is
+ clear from reading the definition of "job-state-reasons" which
+ values MUST or SHOULD be supported. The 'none',
+ 'unsupported-compression', and 'unsupported-document-format'
+ values MUST be supported. The 'job-hold-until-specified'
+ SHOULD be specified if the "job-hold-until" Job Template is
+ supported. The following values SHOULD be supported: 'job-
+ canceled-by-user', 'aborted-by-system', and 'job-completed-
+ successfully'. The
+ 'job-canceled-by-operator' SHOULD be supported if the
+ implementation permits canceling by other than the job owner.
+ The 'job-canceled-at-device' SHOULD be supported if the device
+ supports canceling jobs at the console. The 'job-completed-
+ with-warnings' SHOULD be supported, if the implementation
+ detects warnings. The 'job-completed-with-errors' SHOULD be
+ supported if the implementation detects errors. The 'job-
+ restartable' SHOULD be supported if the Restart-Job operation
+ is supported.
+ 12. Section 4.3.10 - allowed a Printer to localize the "job-
+ detailed-status-message" Job Description attribute, but
+ indicated that such localization might obscure the technical
+ meaning of such messages.
+ 13. Section 4.3.14 - changed the "time-at-creation", "time-at-
+ processing", and "time-at-completed" Event Time Job
+ Description attributes from OPTIONAL to REQUIRED.
+ 14. Section 4.3.14.4 - added the REQUIRED "job-printer-up-time
+ (integer(1:MAX))" Job Description attribute as an alias for
+ "printer-up-time" to reduce number of operations to get job
+ times.
+ 15. Section 4.4.2 - added the REQUIRED "uri-authentication-
+ supported (1setOf type2 keyword)" Printer Description
+ attribute to describe the Client Authentication used by each
+ Printer URI.
+ 16. Section 4.4.12 - changed "printer-state-reasons" Printer
+ Description attribute from OPTIONAL to REQUIRED.
+ 17. Section 4.4.12 - changed 'paused' value of "printer-state-
+ reasons" to MUST if Pause-Printer operation is supported.
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 222]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+ 18. Section 4.4.14 - added the REQUIRED "ipp-versions-supported
+ (1setOf keyword)" Printer Description attribute, since IPP/1.1
+ Printers do not have to support version '1.0' conformance
+ requirements. Section 4.4.16 - added the "multiple-document-
+ jobs-supported (boolean)" Printer Description attribute so
+ that a client can tell whether a Printer that supports
+ Create-Job/Send-Document supports multiple document jobs or
+ not. This attribute is REQUIRED if the Create-Job operation
+ is supported.
+ 19. Section 4.4.24 - changed the "queued-job-count" Printer
+ Description attribute from RECOMMENDED to REQUIRED.
+ 20. Section 4.4.32 - changed "compression-supported (1setOf type3
+ keyword)" Printer Description attribute from OPTIONAL to
+ REQUIRED.
+ 21. Section 5.1 - changed the client security requirements from
+ RECOMMENDED non-standards track SSL3 to MUST support Client
+ Authentication as defined in the IPP/1.1 Encoding and
+ Transport document [RFC2910]. A client SHOULD support
+ Operation Privacy and Server Authentication as defined in the
+ IPP/1.1 Encoding and Transport document [RFC2910].
+ 22. Section 5.2.7 - changed the IPP object security requirements
+ from OPTIONAL non-standards track SSL3 to SHOULD contain
+ support for Client Authentication as defined in the IPP/1.1
+ Encoding and Transport document [RFC2910]. A Printer
+ implementation MAY allow an administrator to configure the
+ Printer so that all, some, or none of the users are
+ authenticated. An IPP Printer implementation SHOULD contain
+ support for Operation Privacy and Server Authentication as
+ defined in the IPP/1.1 Encoding and Transport document
+ [RFC2910]. A Printer implementation MAY allow an
+ administrator to configure the degree of support for Operation
+ Privacy and Server Authentication. Security MUST NOT be
+ compromised when the client supplies a lower version-number in
+ a request.
+ 23. Section 14 (Appendix C): Corrected typo, changing the keyword
+ 'iso-10-white' to 'iso-a10-white'.
+
+ See also the "IPP/1.1 Encoding and Transport" [RFC2910] document for
+ differences between IPP/1.0 [RFC2565] and IPP/1.1 [RFC2910].
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 223]
+
+RFC 2911 IPP/1.1: Model and Semantics September 2000
+
+
+18. Full Copyright Statement
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Standards Track [Page 224]
+
diff --git a/standards/rfc2965.txt b/standards/rfc2965.txt
new file mode 100644
index 000000000..8a4d02b17
--- /dev/null
+++ b/standards/rfc2965.txt
@@ -0,0 +1,1459 @@
+
+
+
+
+
+
+Network Working Group D. Kristol
+Request for Comments: 2965 Bell Laboratories, Lucent Technologies
+Obsoletes: 2109 L. Montulli
+Category: Standards Track Epinions.com, Inc.
+ October 2000
+
+
+ HTTP State Management Mechanism
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+IESG Note
+
+ The IESG notes that this mechanism makes use of the .local top-level
+ domain (TLD) internally when handling host names that don't contain
+ any dots, and that this mechanism might not work in the expected way
+ should an actual .local TLD ever be registered.
+
+Abstract
+
+ This document specifies a way to create a stateful session with
+ Hypertext Transfer Protocol (HTTP) requests and responses. It
+ describes three new headers, Cookie, Cookie2, and Set-Cookie2, which
+ carry state information between participating origin servers and user
+ agents. The method described here differs from Netscape's Cookie
+ proposal [Netscape], but it can interoperate with HTTP/1.0 user
+ agents that use Netscape's method. (See the HISTORICAL section.)
+
+ This document reflects implementation experience with RFC 2109 and
+ obsoletes it.
+
+1. TERMINOLOGY
+
+ The terms user agent, client, server, proxy, origin server, and
+ http_URL have the same meaning as in the HTTP/1.1 specification
+ [RFC2616]. The terms abs_path and absoluteURI have the same meaning
+ as in the URI Syntax specification [RFC2396].
+
+
+
+
+Kristol & Montulli Standards Track [Page 1]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ Host name (HN) means either the host domain name (HDN) or the numeric
+ Internet Protocol (IP) address of a host. The fully qualified domain
+ name is preferred; use of numeric IP addresses is strongly
+ discouraged.
+
+ The terms request-host and request-URI refer to the values the client
+ would send to the server as, respectively, the host (but not port)
+ and abs_path portions of the absoluteURI (http_URL) of the HTTP
+ request line. Note that request-host is a HN.
+
+ The term effective host name is related to host name. If a host name
+ contains no dots, the effective host name is that name with the
+ string .local appended to it. Otherwise the effective host name is
+ the same as the host name. Note that all effective host names
+ contain at least one dot.
+
+ The term request-port refers to the port portion of the absoluteURI
+ (http_URL) of the HTTP request line. If the absoluteURI has no
+ explicit port, the request-port is the HTTP default, 80. The
+ request-port of a cookie is the request-port of the request in which
+ a Set-Cookie2 response header was returned to the user agent.
+
+ Host names can be specified either as an IP address or a HDN string.
+ Sometimes we compare one host name with another. (Such comparisons
+ SHALL be case-insensitive.) Host A's name domain-matches host B's if
+
+ * their host name strings string-compare equal; or
+
+ * A is a HDN string and has the form NB, where N is a non-empty
+ name string, B has the form .B', and B' is a HDN string. (So,
+ x.y.com domain-matches .Y.com but not Y.com.)
+
+ Note that domain-match is not a commutative operation: a.b.c.com
+ domain-matches .c.com, but not the reverse.
+
+ The reach R of a host name H is defined as follows:
+
+ * If
+
+ - H is the host domain name of a host; and,
+
+ - H has the form A.B; and
+
+ - A has no embedded (that is, interior) dots; and
+
+ - B has at least one embedded dot, or B is the string "local".
+ then the reach of H is .B.
+
+
+
+
+Kristol & Montulli Standards Track [Page 2]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ * Otherwise, the reach of H is H.
+
+ For two strings that represent paths, P1 and P2, P1 path-matches P2
+ if P2 is a prefix of P1 (including the case where P1 and P2 string-
+ compare equal). Thus, the string /tec/waldo path-matches /tec.
+
+ Because it was used in Netscape's original implementation of state
+ management, we will use the term cookie to refer to the state
+ information that passes between an origin server and user agent, and
+ that gets stored by the user agent.
+
+1.1 Requirements
+
+ The key words "MAY", "MUST", "MUST NOT", "OPTIONAL", "RECOMMENDED",
+ "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT" in this
+ document are to be interpreted as described in RFC 2119 [RFC2119].
+
+2. STATE AND SESSIONS
+
+ This document describes a way to create stateful sessions with HTTP
+ requests and responses. Currently, HTTP servers respond to each
+ client request without relating that request to previous or
+ subsequent requests; the state management mechanism allows clients
+ and servers that wish to exchange state information to place HTTP
+ requests and responses within a larger context, which we term a
+ "session". This context might be used to create, for example, a
+ "shopping cart", in which user selections can be aggregated before
+ purchase, or a magazine browsing system, in which a user's previous
+ reading affects which offerings are presented.
+
+ Neither clients nor servers are required to support cookies. A
+ server MAY refuse to provide content to a client that does not return
+ the cookies it sends.
+
+3. DESCRIPTION
+
+ We describe here a way for an origin server to send state information
+ to the user agent, and for the user agent to return the state
+ information to the origin server. The goal is to have a minimal
+ impact on HTTP and user agents.
+
+3.1 Syntax: General
+
+ The two state management headers, Set-Cookie2 and Cookie, have common
+ syntactic properties involving attribute-value pairs. The following
+ grammar uses the notation, and tokens DIGIT (decimal digits), token
+
+
+
+
+
+Kristol & Montulli Standards Track [Page 3]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ (informally, a sequence of non-special, non-white space characters),
+ and http_URL from the HTTP/1.1 specification [RFC2616] to describe
+ their syntax.
+
+ av-pairs = av-pair *(";" av-pair)
+ av-pair = attr ["=" value] ; optional value
+ attr = token
+ value = token | quoted-string
+
+ Attributes (names) (attr) are case-insensitive. White space is
+ permitted between tokens. Note that while the above syntax
+ description shows value as optional, most attrs require them.
+
+ NOTE: The syntax above allows whitespace between the attribute and
+ the = sign.
+
+3.2 Origin Server Role
+
+ 3.2.1 General The origin server initiates a session, if it so
+ desires. To do so, it returns an extra response header to the
+ client, Set-Cookie2. (The details follow later.)
+
+ A user agent returns a Cookie request header (see below) to the
+ origin server if it chooses to continue a session. The origin server
+ MAY ignore it or use it to determine the current state of the
+ session. It MAY send back to the client a Set-Cookie2 response
+ header with the same or different information, or it MAY send no
+ Set-Cookie2 header at all. The origin server effectively ends a
+ session by sending the client a Set-Cookie2 header with Max-Age=0.
+
+ Servers MAY return Set-Cookie2 response headers with any response.
+ User agents SHOULD send Cookie request headers, subject to other
+ rules detailed below, with every request.
+
+ An origin server MAY include multiple Set-Cookie2 headers in a
+ response. Note that an intervening gateway could fold multiple such
+ headers into a single header.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kristol & Montulli Standards Track [Page 4]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ 3.2.2 Set-Cookie2 Syntax The syntax for the Set-Cookie2 response
+ header is
+
+ set-cookie = "Set-Cookie2:" cookies
+ cookies = 1#cookie
+ cookie = NAME "=" VALUE *(";" set-cookie-av)
+ NAME = attr
+ VALUE = value
+ set-cookie-av = "Comment" "=" value
+ | "CommentURL" "=" <"> http_URL <">
+ | "Discard"
+ | "Domain" "=" value
+ | "Max-Age" "=" value
+ | "Path" "=" value
+ | "Port" [ "=" <"> portlist <"> ]
+ | "Secure"
+ | "Version" "=" 1*DIGIT
+ portlist = 1#portnum
+ portnum = 1*DIGIT
+
+ Informally, the Set-Cookie2 response header comprises the token Set-
+ Cookie2:, followed by a comma-separated list of one or more cookies.
+ Each cookie begins with a NAME=VALUE pair, followed by zero or more
+ semi-colon-separated attribute-value pairs. The syntax for
+ attribute-value pairs was shown earlier. The specific attributes and
+ the semantics of their values follows. The NAME=VALUE attribute-
+ value pair MUST come first in each cookie. The others, if present,
+ can occur in any order. If an attribute appears more than once in a
+ cookie, the client SHALL use only the value associated with the first
+ appearance of the attribute; a client MUST ignore values after the
+ first.
+
+ The NAME of a cookie MAY be the same as one of the attributes in this
+ specification. However, because the cookie's NAME must come first in
+ a Set-Cookie2 response header, the NAME and its VALUE cannot be
+ confused with an attribute-value pair.
+
+ NAME=VALUE
+ REQUIRED. The name of the state information ("cookie") is NAME,
+ and its value is VALUE. NAMEs that begin with $ are reserved and
+ MUST NOT be used by applications.
+
+ The VALUE is opaque to the user agent and may be anything the
+ origin server chooses to send, possibly in a server-selected
+ printable ASCII encoding. "Opaque" implies that the content is of
+ interest and relevance only to the origin server. The content
+ may, in fact, be readable by anyone that examines the Set-Cookie2
+ header.
+
+
+
+Kristol & Montulli Standards Track [Page 5]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ Comment=value
+ OPTIONAL. Because cookies can be used to derive or store private
+ information about a user, the value of the Comment attribute
+ allows an origin server to document how it intends to use the
+ cookie. The user can inspect the information to decide whether to
+ initiate or continue a session with this cookie. Characters in
+ value MUST be in UTF-8 encoding. [RFC2279]
+
+ CommentURL="http_URL"
+ OPTIONAL. Because cookies can be used to derive or store private
+ information about a user, the CommentURL attribute allows an
+ origin server to document how it intends to use the cookie. The
+ user can inspect the information identified by the URL to decide
+ whether to initiate or continue a session with this cookie.
+
+ Discard
+ OPTIONAL. The Discard attribute instructs the user agent to
+ discard the cookie unconditionally when the user agent terminates.
+
+ Domain=value
+ OPTIONAL. The value of the Domain attribute specifies the domain
+ for which the cookie is valid. If an explicitly specified value
+ does not start with a dot, the user agent supplies a leading dot.
+
+ Max-Age=value
+ OPTIONAL. The value of the Max-Age attribute is delta-seconds,
+ the lifetime of the cookie in seconds, a decimal non-negative
+ integer. To handle cached cookies correctly, a client SHOULD
+ calculate the age of the cookie according to the age calculation
+ rules in the HTTP/1.1 specification [RFC2616]. When the age is
+ greater than delta-seconds seconds, the client SHOULD discard the
+ cookie. A value of zero means the cookie SHOULD be discarded
+ immediately.
+
+ Path=value
+ OPTIONAL. The value of the Path attribute specifies the subset of
+ URLs on the origin server to which this cookie applies.
+
+ Port[="portlist"]
+ OPTIONAL. The Port attribute restricts the port to which a cookie
+ may be returned in a Cookie request header. Note that the syntax
+ REQUIREs quotes around the OPTIONAL portlist even if there is only
+ one portnum in portlist.
+
+
+
+
+
+
+
+
+Kristol & Montulli Standards Track [Page 6]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ Secure
+ OPTIONAL. The Secure attribute (with no value) directs the user
+ agent to use only (unspecified) secure means to contact the origin
+ server whenever it sends back this cookie, to protect the
+ confidentially and authenticity of the information in the cookie.
+
+ The user agent (possibly with user interaction) MAY determine what
+ level of security it considers appropriate for "secure" cookies.
+ The Secure attribute should be considered security advice from the
+ server to the user agent, indicating that it is in the session's
+ interest to protect the cookie contents. When it sends a "secure"
+ cookie back to a server, the user agent SHOULD use no less than
+ the same level of security as was used when it received the cookie
+ from the server.
+
+ Version=value
+ REQUIRED. The value of the Version attribute, a decimal integer,
+ identifies the version of the state management specification to
+ which the cookie conforms. For this specification, Version=1
+ applies.
+
+ 3.2.3 Controlling Caching An origin server must be cognizant of the
+ effect of possible caching of both the returned resource and the
+ Set-Cookie2 header. Caching "public" documents is desirable. For
+ example, if the origin server wants to use a public document such as
+ a "front door" page as a sentinel to indicate the beginning of a
+ session for which a Set-Cookie2 response header must be generated,
+ the page SHOULD be stored in caches "pre-expired" so that the origin
+ server will see further requests. "Private documents", for example
+ those that contain information strictly private to a session, SHOULD
+ NOT be cached in shared caches.
+
+ If the cookie is intended for use by a single user, the Set-Cookie2
+ header SHOULD NOT be cached. A Set-Cookie2 header that is intended
+ to be shared by multiple users MAY be cached.
+
+ The origin server SHOULD send the following additional HTTP/1.1
+ response headers, depending on circumstances:
+
+ * To suppress caching of the Set-Cookie2 header:
+
+ Cache-control: no-cache="set-cookie2"
+
+ and one of the following:
+
+ * To suppress caching of a private document in shared caches:
+
+ Cache-control: private
+
+
+
+Kristol & Montulli Standards Track [Page 7]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ * To allow caching of a document and require that it be validated
+ before returning it to the client:
+
+ Cache-Control: must-revalidate, max-age=0
+
+ * To allow caching of a document, but to require that proxy
+ caches (not user agent caches) validate it before returning it
+ to the client:
+
+ Cache-Control: proxy-revalidate, max-age=0
+
+ * To allow caching of a document and request that it be validated
+ before returning it to the client (by "pre-expiring" it):
+
+ Cache-control: max-age=0
+
+ Not all caches will revalidate the document in every case.
+
+ HTTP/1.1 servers MUST send Expires: old-date (where old-date is a
+ date long in the past) on responses containing Set-Cookie2 response
+ headers unless they know for certain (by out of band means) that
+ there are no HTTP/1.0 proxies in the response chain. HTTP/1.1
+ servers MAY send other Cache-Control directives that permit caching
+ by HTTP/1.1 proxies in addition to the Expires: old-date directive;
+ the Cache-Control directive will override the Expires: old-date for
+ HTTP/1.1 proxies.
+
+3.3 User Agent Role
+
+ 3.3.1 Interpreting Set-Cookie2 The user agent keeps separate track
+ of state information that arrives via Set-Cookie2 response headers
+ from each origin server (as distinguished by name or IP address and
+ port). The user agent MUST ignore attribute-value pairs whose
+ attribute it does not recognize. The user agent applies these
+ defaults for optional attributes that are missing:
+
+ Discard The default behavior is dictated by the presence or absence
+ of a Max-Age attribute.
+
+ Domain Defaults to the effective request-host. (Note that because
+ there is no dot at the beginning of effective request-host,
+ the default Domain can only domain-match itself.)
+
+ Max-Age The default behavior is to discard the cookie when the user
+ agent exits.
+
+ Path Defaults to the path of the request URL that generated the
+ Set-Cookie2 response, up to and including the right-most /.
+
+
+
+Kristol & Montulli Standards Track [Page 8]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ Port The default behavior is that a cookie MAY be returned to any
+ request-port.
+
+ Secure If absent, the user agent MAY send the cookie over an
+ insecure channel.
+
+ 3.3.2 Rejecting Cookies To prevent possible security or privacy
+ violations, a user agent rejects a cookie according to rules below.
+ The goal of the rules is to try to limit the set of servers for which
+ a cookie is valid, based on the values of the Path, Domain, and Port
+ attributes and the request-URI, request-host and request-port.
+
+ A user agent rejects (SHALL NOT store its information) if the Version
+ attribute is missing. Moreover, a user agent rejects (SHALL NOT
+ store its information) if any of the following is true of the
+ attributes explicitly present in the Set-Cookie2 response header:
+
+ * The value for the Path attribute is not a prefix of the
+ request-URI.
+
+ * The value for the Domain attribute contains no embedded dots,
+ and the value is not .local.
+
+ * The effective host name that derives from the request-host does
+ not domain-match the Domain attribute.
+
+ * The request-host is a HDN (not IP address) and has the form HD,
+ where D is the value of the Domain attribute, and H is a string
+ that contains one or more dots.
+
+ * The Port attribute has a "port-list", and the request-port was
+ not in the list.
+
+ Examples:
+
+ * A Set-Cookie2 from request-host y.x.foo.com for Domain=.foo.com
+ would be rejected, because H is y.x and contains a dot.
+
+ * A Set-Cookie2 from request-host x.foo.com for Domain=.foo.com
+ would be accepted.
+
+ * A Set-Cookie2 with Domain=.com or Domain=.com., will always be
+ rejected, because there is no embedded dot.
+
+ * A Set-Cookie2 with Domain=ajax.com will be accepted, and the
+ value for Domain will be taken to be .ajax.com, because a dot
+ gets prepended to the value.
+
+
+
+
+Kristol & Montulli Standards Track [Page 9]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ * A Set-Cookie2 with Port="80,8000" will be accepted if the
+ request was made to port 80 or 8000 and will be rejected
+ otherwise.
+
+ * A Set-Cookie2 from request-host example for Domain=.local will
+ be accepted, because the effective host name for the request-
+ host is example.local, and example.local domain-matches .local.
+
+ 3.3.3 Cookie Management If a user agent receives a Set-Cookie2
+ response header whose NAME is the same as that of a cookie it has
+ previously stored, the new cookie supersedes the old when: the old
+ and new Domain attribute values compare equal, using a case-
+ insensitive string-compare; and, the old and new Path attribute
+ values string-compare equal (case-sensitive). However, if the Set-
+ Cookie2 has a value for Max-Age of zero, the (old and new) cookie is
+ discarded. Otherwise a cookie persists (resources permitting) until
+ whichever happens first, then gets discarded: its Max-Age lifetime is
+ exceeded; or, if the Discard attribute is set, the user agent
+ terminates the session.
+
+ Because user agents have finite space in which to store cookies, they
+ MAY also discard older cookies to make space for newer ones, using,
+ for example, a least-recently-used algorithm, along with constraints
+ on the maximum number of cookies that each origin server may set.
+
+ If a Set-Cookie2 response header includes a Comment attribute, the
+ user agent SHOULD store that information in a human-readable form
+ with the cookie and SHOULD display the comment text as part of a
+ cookie inspection user interface.
+
+ If a Set-Cookie2 response header includes a CommentURL attribute, the
+ user agent SHOULD store that information in a human-readable form
+ with the cookie, or, preferably, SHOULD allow the user to follow the
+ http_URL link as part of a cookie inspection user interface.
+
+ The cookie inspection user interface may include a facility whereby a
+ user can decide, at the time the user agent receives the Set-Cookie2
+ response header, whether or not to accept the cookie. A potentially
+ confusing situation could arise if the following sequence occurs:
+
+ * the user agent receives a cookie that contains a CommentURL
+ attribute;
+
+ * the user agent's cookie inspection interface is configured so
+ that it presents a dialog to the user before the user agent
+ accepts the cookie;
+
+
+
+
+
+Kristol & Montulli Standards Track [Page 10]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ * the dialog allows the user to follow the CommentURL link when
+ the user agent receives the cookie; and,
+
+ * when the user follows the CommentURL link, the origin server
+ (or another server, via other links in the returned content)
+ returns another cookie.
+
+ The user agent SHOULD NOT send any cookies in this context. The user
+ agent MAY discard any cookie it receives in this context that the
+ user has not, through some user agent mechanism, deemed acceptable.
+
+ User agents SHOULD allow the user to control cookie destruction, but
+ they MUST NOT extend the cookie's lifetime beyond that controlled by
+ the Discard and Max-Age attributes. An infrequently-used cookie may
+ function as a "preferences file" for network applications, and a user
+ may wish to keep it even if it is the least-recently-used cookie. One
+ possible implementation would be an interface that allows the
+ permanent storage of a cookie through a checkbox (or, conversely, its
+ immediate destruction).
+
+ Privacy considerations dictate that the user have considerable
+ control over cookie management. The PRIVACY section contains more
+ information.
+
+ 3.3.4 Sending Cookies to the Origin Server When it sends a request
+ to an origin server, the user agent includes a Cookie request header
+ if it has stored cookies that are applicable to the request, based on
+
+ * the request-host and request-port;
+
+ * the request-URI;
+
+ * the cookie's age.
+
+ The syntax for the header is:
+
+cookie = "Cookie:" cookie-version 1*((";" | ",") cookie-value)
+cookie-value = NAME "=" VALUE [";" path] [";" domain] [";" port]
+cookie-version = "$Version" "=" value
+NAME = attr
+VALUE = value
+path = "$Path" "=" value
+domain = "$Domain" "=" value
+port = "$Port" [ "=" <"> value <"> ]
+
+ The value of the cookie-version attribute MUST be the value from the
+ Version attribute of the corresponding Set-Cookie2 response header.
+ Otherwise the value for cookie-version is 0. The value for the path
+
+
+
+Kristol & Montulli Standards Track [Page 11]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ attribute MUST be the value from the Path attribute, if one was
+ present, of the corresponding Set-Cookie2 response header. Otherwise
+ the attribute SHOULD be omitted from the Cookie request header. The
+ value for the domain attribute MUST be the value from the Domain
+ attribute, if one was present, of the corresponding Set-Cookie2
+ response header. Otherwise the attribute SHOULD be omitted from the
+ Cookie request header.
+
+ The port attribute of the Cookie request header MUST mirror the Port
+ attribute, if one was present, in the corresponding Set-Cookie2
+ response header. That is, the port attribute MUST be present if the
+ Port attribute was present in the Set-Cookie2 header, and it MUST
+ have the same value, if any. Otherwise, if the Port attribute was
+ absent from the Set-Cookie2 header, the attribute likewise MUST be
+ omitted from the Cookie request header.
+
+ Note that there is neither a Comment nor a CommentURL attribute in
+ the Cookie request header corresponding to the ones in the Set-
+ Cookie2 response header. The user agent does not return the comment
+ information to the origin server.
+
+ The user agent applies the following rules to choose applicable
+ cookie-values to send in Cookie request headers from among all the
+ cookies it has received.
+
+ Domain Selection
+ The origin server's effective host name MUST domain-match the
+ Domain attribute of the cookie.
+
+ Port Selection
+ There are three possible behaviors, depending on the Port
+ attribute in the Set-Cookie2 response header:
+
+ 1. By default (no Port attribute), the cookie MAY be sent to any
+ port.
+
+ 2. If the attribute is present but has no value (e.g., Port), the
+ cookie MUST only be sent to the request-port it was received
+ from.
+
+ 3. If the attribute has a port-list, the cookie MUST only be
+ returned if the new request-port is one of those listed in
+ port-list.
+
+ Path Selection
+ The request-URI MUST path-match the Path attribute of the cookie.
+
+
+
+
+
+Kristol & Montulli Standards Track [Page 12]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ Max-Age Selection
+ Cookies that have expired should have been discarded and thus are
+ not forwarded to an origin server.
+
+ If multiple cookies satisfy the criteria above, they are ordered in
+ the Cookie header such that those with more specific Path attributes
+ precede those with less specific. Ordering with respect to other
+ attributes (e.g., Domain) is unspecified.
+
+ Note: For backward compatibility, the separator in the Cookie header
+ is semi-colon (;) everywhere. A server SHOULD also accept comma (,)
+ as the separator between cookie-values for future compatibility.
+
+ 3.3.5 Identifying What Version is Understood: Cookie2 The Cookie2
+ request header facilitates interoperation between clients and servers
+ that understand different versions of the cookie specification. When
+ the client sends one or more cookies to an origin server, if at least
+ one of those cookies contains a $Version attribute whose value is
+ different from the version that the client understands, then the
+ client MUST also send a Cookie2 request header, the syntax for which
+ is
+
+ cookie2 = "Cookie2:" cookie-version
+
+ Here the value for cookie-version is the highest version of cookie
+ specification (currently 1) that the client understands. The client
+ needs to send at most one such request header per request.
+
+ 3.3.6 Sending Cookies in Unverifiable Transactions Users MUST have
+ control over sessions in order to ensure privacy. (See PRIVACY
+ section below.) To simplify implementation and to prevent an
+ additional layer of complexity where adequate safeguards exist,
+ however, this document distinguishes between transactions that are
+ verifiable and those that are unverifiable. A transaction is
+ verifiable if the user, or a user-designated agent, has the option to
+ review the request-URI prior to its use in the transaction. A
+ transaction is unverifiable if the user does not have that option.
+ Unverifiable transactions typically arise when a user agent
+ automatically requests inlined or embedded entities or when it
+ resolves redirection (3xx) responses from an origin server.
+ Typically the origin transaction, the transaction that the user
+ initiates, is verifiable, and that transaction may directly or
+ indirectly induce the user agent to make unverifiable transactions.
+
+ An unverifiable transaction is to a third-party host if its request-
+ host U does not domain-match the reach R of the request-host O in the
+ origin transaction.
+
+
+
+
+Kristol & Montulli Standards Track [Page 13]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ When it makes an unverifiable transaction, a user agent MUST disable
+ all cookie processing (i.e., MUST NOT send cookies, and MUST NOT
+ accept any received cookies) if the transaction is to a third-party
+ host.
+
+ This restriction prevents a malicious service author from using
+ unverifiable transactions to induce a user agent to start or continue
+ a session with a server in a different domain. The starting or
+ continuation of such sessions could be contrary to the privacy
+ expectations of the user, and could also be a security problem.
+
+ User agents MAY offer configurable options that allow the user agent,
+ or any autonomous programs that the user agent executes, to ignore
+ the above rule, so long as these override options default to "off".
+
+ (N.B. Mechanisms may be proposed that will automate overriding the
+ third-party restrictions under controlled conditions.)
+
+ Many current user agents already provide a review option that would
+ render many links verifiable. For instance, some user agents display
+ the URL that would be referenced for a particular link when the mouse
+ pointer is placed over that link. The user can therefore determine
+ whether to visit that site before causing the browser to do so.
+ (Though not implemented on current user agents, a similar technique
+ could be used for a button used to submit a form -- the user agent
+ could display the action to be taken if the user were to select that
+ button.) However, even this would not make all links verifiable; for
+ example, links to automatically loaded images would not normally be
+ subject to "mouse pointer" verification.
+
+ Many user agents also provide the option for a user to view the HTML
+ source of a document, or to save the source to an external file where
+ it can be viewed by another application. While such an option does
+ provide a crude review mechanism, some users might not consider it
+ acceptable for this purpose.
+
+3.4 How an Origin Server Interprets the Cookie Header
+
+ A user agent returns much of the information in the Set-Cookie2
+ header to the origin server when the request-URI path-matches the
+ Path attribute of the cookie. When it receives a Cookie header, the
+ origin server SHOULD treat cookies with NAMEs whose prefix is $
+ specially, as an attribute for the cookie.
+
+
+
+
+
+
+
+
+Kristol & Montulli Standards Track [Page 14]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+3.5 Caching Proxy Role
+
+ One reason for separating state information from both a URL and
+ document content is to facilitate the scaling that caching permits.
+ To support cookies, a caching proxy MUST obey these rules already in
+ the HTTP specification:
+
+ * Honor requests from the cache, if possible, based on cache
+ validity rules.
+
+ * Pass along a Cookie request header in any request that the
+ proxy must make of another server.
+
+ * Return the response to the client. Include any Set-Cookie2
+ response header.
+
+ * Cache the received response subject to the control of the usual
+ headers, such as Expires,
+
+ Cache-control: no-cache
+
+ and
+
+ Cache-control: private
+
+ * Cache the Set-Cookie2 subject to the control of the usual
+ header,
+
+ Cache-control: no-cache="set-cookie2"
+
+ (The Set-Cookie2 header should usually not be cached.)
+
+ Proxies MUST NOT introduce Set-Cookie2 (Cookie) headers of their own
+ in proxy responses (requests).
+
+4. EXAMPLES
+
+4.1 Example 1
+
+ Most detail of request and response headers has been omitted. Assume
+ the user agent has no stored cookies.
+
+ 1. User Agent -> Server
+
+ POST /acme/login HTTP/1.1
+ [form data]
+
+ User identifies self via a form.
+
+
+
+Kristol & Montulli Standards Track [Page 15]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ 2. Server -> User Agent
+
+ HTTP/1.1 200 OK
+ Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"
+
+ Cookie reflects user's identity.
+
+ 3. User Agent -> Server
+
+ POST /acme/pickitem HTTP/1.1
+ Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
+ [form data]
+
+ User selects an item for "shopping basket".
+
+ 4. Server -> User Agent
+
+ HTTP/1.1 200 OK
+ Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
+ Path="/acme"
+
+ Shopping basket contains an item.
+
+ 5. User Agent -> Server
+
+ POST /acme/shipping HTTP/1.1
+ Cookie: $Version="1";
+ Customer="WILE_E_COYOTE"; $Path="/acme";
+ Part_Number="Rocket_Launcher_0001"; $Path="/acme"
+ [form data]
+
+ User selects shipping method from form.
+
+ 6. Server -> User Agent
+
+ HTTP/1.1 200 OK
+ Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme"
+
+ New cookie reflects shipping method.
+
+ 7. User Agent -> Server
+
+ POST /acme/process HTTP/1.1
+ Cookie: $Version="1";
+ Customer="WILE_E_COYOTE"; $Path="/acme";
+ Part_Number="Rocket_Launcher_0001"; $Path="/acme";
+ Shipping="FedEx"; $Path="/acme"
+ [form data]
+
+
+
+Kristol & Montulli Standards Track [Page 16]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ User chooses to process order.
+
+ 8. Server -> User Agent
+
+ HTTP/1.1 200 OK
+
+ Transaction is complete.
+
+ The user agent makes a series of requests on the origin server, after
+ each of which it receives a new cookie. All the cookies have the
+ same Path attribute and (default) domain. Because the request-URIs
+ all path-match /acme, the Path attribute of each cookie, each request
+ contains all the cookies received so far.
+
+4.2 Example 2
+
+ This example illustrates the effect of the Path attribute. All
+ detail of request and response headers has been omitted. Assume the
+ user agent has no stored cookies.
+
+ Imagine the user agent has received, in response to earlier requests,
+ the response headers
+
+ Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
+ Path="/acme"
+
+ and
+
+ Set-Cookie2: Part_Number="Riding_Rocket_0023"; Version="1";
+ Path="/acme/ammo"
+
+ A subsequent request by the user agent to the (same) server for URLs
+ of the form /acme/ammo/... would include the following request
+ header:
+
+ Cookie: $Version="1";
+ Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo";
+ Part_Number="Rocket_Launcher_0001"; $Path="/acme"
+
+ Note that the NAME=VALUE pair for the cookie with the more specific
+ Path attribute, /acme/ammo, comes before the one with the less
+ specific Path attribute, /acme. Further note that the same cookie
+ name appears more than once.
+
+ A subsequent request by the user agent to the (same) server for a URL
+ of the form /acme/parts/ would include the following request header:
+
+
+
+
+
+Kristol & Montulli Standards Track [Page 17]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001";
+ $Path="/acme"
+
+ Here, the second cookie's Path attribute /acme/ammo is not a prefix
+ of the request URL, /acme/parts/, so the cookie does not get
+ forwarded to the server.
+
+5. IMPLEMENTATION CONSIDERATIONS
+
+ Here we provide guidance on likely or desirable details for an origin
+ server that implements state management.
+
+5.1 Set-Cookie2 Content
+
+ An origin server's content should probably be divided into disjoint
+ application areas, some of which require the use of state
+ information. The application areas can be distinguished by their
+ request URLs. The Set-Cookie2 header can incorporate information
+ about the application areas by setting the Path attribute for each
+ one.
+
+ The session information can obviously be clear or encoded text that
+ describes state. However, if it grows too large, it can become
+ unwieldy. Therefore, an implementor might choose for the session
+ information to be a key to a server-side resource. Of course, using
+ a database creates some problems that this state management
+ specification was meant to avoid, namely:
+
+ 1. keeping real state on the server side;
+
+ 2. how and when to garbage-collect the database entry, in case the
+ user agent terminates the session by, for example, exiting.
+
+5.2 Stateless Pages
+
+ Caching benefits the scalability of WWW. Therefore it is important
+ to reduce the number of documents that have state embedded in them
+ inherently. For example, if a shopping-basket-style application
+ always displays a user's current basket contents on each page, those
+ pages cannot be cached, because each user's basket's contents would
+ be different. On the other hand, if each page contains just a link
+ that allows the user to "Look at My Shopping Basket", the page can be
+ cached.
+
+
+
+
+
+
+
+
+Kristol & Montulli Standards Track [Page 18]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+5.3 Implementation Limits
+
+ Practical user agent implementations have limits on the number and
+ size of cookies that they can store. In general, user agents' cookie
+ support should have no fixed limits. They should strive to store as
+ many frequently-used cookies as possible. Furthermore, general-use
+ user agents SHOULD provide each of the following minimum capabilities
+ individually, although not necessarily simultaneously:
+
+ * at least 300 cookies
+
+ * at least 4096 bytes per cookie (as measured by the characters
+ that comprise the cookie non-terminal in the syntax description
+ of the Set-Cookie2 header, and as received in the Set-Cookie2
+ header)
+
+ * at least 20 cookies per unique host or domain name
+
+ User agents created for specific purposes or for limited-capacity
+ devices SHOULD provide at least 20 cookies of 4096 bytes, to ensure
+ that the user can interact with a session-based origin server.
+
+ The information in a Set-Cookie2 response header MUST be retained in
+ its entirety. If for some reason there is inadequate space to store
+ the cookie, it MUST be discarded, not truncated.
+
+ Applications should use as few and as small cookies as possible, and
+ they should cope gracefully with the loss of a cookie.
+
+ 5.3.1 Denial of Service Attacks User agents MAY choose to set an
+ upper bound on the number of cookies to be stored from a given host
+ or domain name or on the size of the cookie information. Otherwise a
+ malicious server could attempt to flood a user agent with many
+ cookies, or large cookies, on successive responses, which would force
+ out cookies the user agent had received from other servers. However,
+ the minima specified above SHOULD still be supported.
+
+6. PRIVACY
+
+ Informed consent should guide the design of systems that use cookies.
+ A user should be able to find out how a web site plans to use
+ information in a cookie and should be able to choose whether or not
+ those policies are acceptable. Both the user agent and the origin
+ server must assist informed consent.
+
+
+
+
+
+
+
+Kristol & Montulli Standards Track [Page 19]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+6.1 User Agent Control
+
+ An origin server could create a Set-Cookie2 header to track the path
+ of a user through the server. Users may object to this behavior as
+ an intrusive accumulation of information, even if their identity is
+ not evident. (Identity might become evident, for example, if a user
+ subsequently fills out a form that contains identifying information.)
+ This state management specification therefore requires that a user
+ agent give the user control over such a possible intrusion, although
+ the interface through which the user is given this control is left
+ unspecified. However, the control mechanisms provided SHALL at least
+ allow the user
+
+ * to completely disable the sending and saving of cookies.
+
+ * to determine whether a stateful session is in progress.
+
+ * to control the saving of a cookie on the basis of the cookie's
+ Domain attribute.
+
+ Such control could be provided, for example, by mechanisms
+
+ * to notify the user when the user agent is about to send a
+ cookie to the origin server, to offer the option not to begin a
+ session.
+
+ * to display a visual indication that a stateful session is in
+ progress.
+
+ * to let the user decide which cookies, if any, should be saved
+ when the user concludes a window or user agent session.
+
+ * to let the user examine and delete the contents of a cookie at
+ any time.
+
+ A user agent usually begins execution with no remembered state
+ information. It SHOULD be possible to configure a user agent never
+ to send Cookie headers, in which case it can never sustain state with
+ an origin server. (The user agent would then behave like one that is
+ unaware of how to handle Set-Cookie2 response headers.)
+
+ When the user agent terminates execution, it SHOULD let the user
+ discard all state information. Alternatively, the user agent MAY ask
+ the user whether state information should be retained; the default
+ should be "no". If the user chooses to retain state information, it
+ would be restored the next time the user agent runs.
+
+
+
+
+
+Kristol & Montulli Standards Track [Page 20]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ NOTE: User agents should probably be cautious about using files to
+ store cookies long-term. If a user runs more than one instance of
+ the user agent, the cookies could be commingled or otherwise
+ corrupted.
+
+6.2 Origin Server Role
+
+ An origin server SHOULD promote informed consent by adding CommentURL
+ or Comment information to the cookies it sends. CommentURL is
+ preferred because of the opportunity to provide richer information in
+ a multiplicity of languages.
+
+6.3 Clear Text
+
+ The information in the Set-Cookie2 and Cookie headers is unprotected.
+ As a consequence:
+
+ 1. Any sensitive information that is conveyed in them is exposed
+ to intruders.
+
+ 2. A malicious intermediary could alter the headers as they travel
+ in either direction, with unpredictable results.
+
+ These facts imply that information of a personal and/or financial
+ nature should only be sent over a secure channel. For less sensitive
+ information, or when the content of the header is a database key, an
+ origin server should be vigilant to prevent a bad Cookie value from
+ causing failures.
+
+ A user agent in a shared user environment poses a further risk.
+ Using a cookie inspection interface, User B could examine the
+ contents of cookies that were saved when User A used the machine.
+
+7. SECURITY CONSIDERATIONS
+
+7.1 Protocol Design
+
+ The restrictions on the value of the Domain attribute, and the rules
+ concerning unverifiable transactions, are meant to reduce the ways
+ that cookies can "leak" to the "wrong" site. The intent is to
+ restrict cookies to one host, or a closely related set of hosts.
+ Therefore a request-host is limited as to what values it can set for
+ Domain. We consider it acceptable for hosts host1.foo.com and
+ host2.foo.com to share cookies, but not a.com and b.com.
+
+ Similarly, a server can set a Path only for cookies that are related
+ to the request-URI.
+
+
+
+
+Kristol & Montulli Standards Track [Page 21]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+7.2 Cookie Spoofing
+
+ Proper application design can avoid spoofing attacks from related
+ domains. Consider:
+
+ 1. User agent makes request to victim.cracker.edu, gets back
+ cookie session_id="1234" and sets the default domain
+ victim.cracker.edu.
+
+ 2. User agent makes request to spoof.cracker.edu, gets back cookie
+ session-id="1111", with Domain=".cracker.edu".
+
+ 3. User agent makes request to victim.cracker.edu again, and
+ passes
+
+ Cookie: $Version="1"; session_id="1234",
+ $Version="1"; session_id="1111"; $Domain=".cracker.edu"
+
+ The server at victim.cracker.edu should detect that the second
+ cookie was not one it originated by noticing that the Domain
+ attribute is not for itself and ignore it.
+
+7.3 Unexpected Cookie Sharing
+
+ A user agent SHOULD make every attempt to prevent the sharing of
+ session information between hosts that are in different domains.
+ Embedded or inlined objects may cause particularly severe privacy
+ problems if they can be used to share cookies between disparate
+ hosts. For example, a malicious server could embed cookie
+ information for host a.com in a URI for a CGI on host b.com. User
+ agent implementors are strongly encouraged to prevent this sort of
+ exchange whenever possible.
+
+7.4 Cookies For Account Information
+
+ While it is common practice to use them this way, cookies are not
+ designed or intended to be used to hold authentication information,
+ such as account names and passwords. Unless such cookies are
+ exchanged over an encrypted path, the account information they
+ contain is highly vulnerable to perusal and theft.
+
+8. OTHER, SIMILAR, PROPOSALS
+
+ Apart from RFC 2109, three other proposals have been made to
+ accomplish similar goals. This specification began as an amalgam of
+ Kristol's State-Info proposal [DMK95] and Netscape's Cookie proposal
+ [Netscape].
+
+
+
+
+Kristol & Montulli Standards Track [Page 22]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ Brian Behlendorf proposed a Session-ID header that would be user-
+ agent-initiated and could be used by an origin server to track
+ "clicktrails". It would not carry any origin-server-defined state,
+ however. Phillip Hallam-Baker has proposed another client-defined
+ session ID mechanism for similar purposes.
+
+ While both session IDs and cookies can provide a way to sustain
+ stateful sessions, their intended purpose is different, and,
+ consequently, the privacy requirements for them are different. A
+ user initiates session IDs to allow servers to track progress through
+ them, or to distinguish multiple users on a shared machine. Cookies
+ are server-initiated, so the cookie mechanism described here gives
+ users control over something that would otherwise take place without
+ the users' awareness. Furthermore, cookies convey rich, server-
+ selected information, whereas session IDs comprise user-selected,
+ simple information.
+
+9. HISTORICAL
+
+9.1 Compatibility with Existing Implementations
+
+ Existing cookie implementations, based on the Netscape specification,
+ use the Set-Cookie (not Set-Cookie2) header. User agents that
+ receive in the same response both a Set-Cookie and Set-Cookie2
+ response header for the same cookie MUST discard the Set-Cookie
+ information and use only the Set-Cookie2 information. Furthermore, a
+ user agent MUST assume, if it received a Set-Cookie2 response header,
+ that the sending server complies with this document and will
+ understand Cookie request headers that also follow this
+ specification.
+
+ New cookies MUST replace both equivalent old- and new-style cookies.
+ That is, if a user agent that follows both this specification and
+ Netscape's original specification receives a Set-Cookie2 response
+ header, and the NAME and the Domain and Path attributes match (per
+ the Cookie Management section) a Netscape-style cookie, the
+ Netscape-style cookie MUST be discarded, and the user agent MUST
+ retain only the cookie adhering to this specification.
+
+ Older user agents that do not understand this specification, but that
+ do understand Netscape's original specification, will not recognize
+ the Set-Cookie2 response header and will receive and send cookies
+ according to the older specification.
+
+
+
+
+
+
+
+
+Kristol & Montulli Standards Track [Page 23]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+ A user agent that supports both this specification and Netscape-style
+ cookies SHOULD send a Cookie request header that follows the older
+ Netscape specification if it received the cookie in a Set-Cookie
+ response header and not in a Set-Cookie2 response header. However,
+ it SHOULD send the following request header as well:
+
+ Cookie2: $Version="1"
+
+ The Cookie2 header advises the server that the user agent understands
+ new-style cookies. If the server understands new-style cookies, as
+ well, it SHOULD continue the stateful session by sending a Set-
+ Cookie2 response header, rather than Set-Cookie. A server that does
+ not understand new-style cookies will simply ignore the Cookie2
+ request header.
+
+9.2 Caching and HTTP/1.0
+
+ Some caches, such as those conforming to HTTP/1.0, will inevitably
+ cache the Set-Cookie2 and Set-Cookie headers, because there was no
+ mechanism to suppress caching of headers prior to HTTP/1.1. This
+ caching can lead to security problems. Documents transmitted by an
+ origin server along with Set-Cookie2 and Set-Cookie headers usually
+ either will be uncachable, or will be "pre-expired". As long as
+ caches obey instructions not to cache documents (following Expires:
+ <a date in the past> or Pragma: no-cache (HTTP/1.0), or Cache-
+ control: no-cache (HTTP/1.1)) uncachable documents present no
+ problem. However, pre-expired documents may be stored in caches.
+ They require validation (a conditional GET) on each new request, but
+ some cache operators loosen the rules for their caches, and sometimes
+ serve expired documents without first validating them. This
+ combination of factors can lead to cookies meant for one user later
+ being sent to another user. The Set-Cookie2 and Set-Cookie headers
+ are stored in the cache, and, although the document is stale
+ (expired), the cache returns the document in response to later
+ requests, including cached headers.
+
+10. ACKNOWLEDGEMENTS
+
+ This document really represents the collective efforts of the HTTP
+ Working Group of the IETF and, particularly, the following people, in
+ addition to the authors: Roy Fielding, Yaron Goland, Marc Hedlund,
+ Ted Hardie, Koen Holtman, Shel Kaphan, Rohit Khare, Foteos Macrides,
+ David W. Morris.
+
+
+
+
+
+
+
+
+Kristol & Montulli Standards Track [Page 24]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+11. AUTHORS' ADDRESSES
+
+ David M. Kristol
+ Bell Laboratories, Lucent Technologies
+ 600 Mountain Ave. Room 2A-333
+ Murray Hill, NJ 07974
+
+ Phone: (908) 582-2250
+ Fax: (908) 582-1239
+ EMail: dmk@bell-labs.com
+
+
+ Lou Montulli
+ Epinions.com, Inc.
+ 2037 Landings Dr.
+ Mountain View, CA 94301
+
+ EMail: lou@montulli.org
+
+12. REFERENCES
+
+ [DMK95] Kristol, D.M., "Proposed HTTP State-Info Mechanism",
+ available at <http://portal.research.bell-
+ labs.com/~dmk/state-info.html>, September, 1995.
+
+ [Netscape] "Persistent Client State -- HTTP Cookies", available at
+ <http://www.netscape.com/newsref/std/cookie_spec.html>,
+ undated.
+
+ [RFC2109] Kristol, D. and L. Montulli, "HTTP State Management
+ Mechanism", RFC 2109, February 1997.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2279] Yergeau, F., "UTF-8, a transformation format of Unicode
+ and ISO-10646", RFC 2279, January 1998.
+
+ [RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform
+ Resource Identifiers (URI): Generic Syntax", RFC 2396,
+ August 1998.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H. and T.
+ Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1",
+ RFC 2616, June 1999.
+
+
+
+
+
+
+Kristol & Montulli Standards Track [Page 25]
+
+RFC 2965 HTTP State Management Mechanism October 2000
+
+
+13. Full Copyright Statement
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kristol & Montulli Standards Track [Page 26]
+
diff --git a/standards/rfc3196.txt b/standards/rfc3196.txt
new file mode 100644
index 000000000..50b7c2d97
--- /dev/null
+++ b/standards/rfc3196.txt
@@ -0,0 +1,5379 @@
+
+
+
+
+
+
+Network Working Group T. Hastings
+Request for Comments: 3196 C. Manros
+Obsoletes: 2639 P. Zehler
+Category: Informational Xerox Corporation
+ C. Kugler
+ IBM Printing Systems Co
+ H. Holst
+ i-data Printing Systems
+ November 2001
+
+
+ Internet Printing Protocol/1.1: Implementor's Guide
+
+Status of this Memo
+
+ This memo provides information for the Internet community. It does
+ not specify an Internet standard of any kind. Distribution of this
+ memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+Abstract
+
+ This document is one of a set of documents, which together describe
+ all aspects of a new Internet Printing Protocol (IPP).
+
+Table of Contents
+
+ 1 Introduction................................................... 4
+ 1.1 Conformance language........................................ 5
+ 1.2 Other terminology........................................... 6
+ 1.3 Issues Raised from Interoperability Testing Events.......... 6
+ 2 IPP Objects.................................................... 6
+ 3 IPP Operations................................................. 7
+ 3.1 Common Semantics............................................ 7
+ 3.1.1 Summary of Operation Attributes............................ 8
+ 3.1.2 Suggested Operation Processing Steps for IPP Objects....... 16
+ 3.1.2.1 Suggested Operation Processing Steps for all Operations. 17
+ 3.1.2.1.1 Validate version number............................... 18
+ 3.1.2.1.2 Validate operation identifier......................... 20
+ 3.1.2.1.3 Validate the request identifier....................... 20
+ 3.1.2.1.4 Validate attribute group and attribute presence and
+ order................................................. 20
+ 3.1.2.1.4.1 Validate the presence and order of attribute groups. 20
+ 3.1.2.1.4.2 Ignore unknown attribute groups in the expected
+ position............................................ 21
+
+
+
+Hastings, et al. Informational [Page 1]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ 3.1.2.1.4.3 Validate the presence of a single occurrence of
+ required Operation attributes....................... 21
+ 3.1.2.1.5 Validate the values of the REQUIRED Operation
+ attributes............................................ 29
+ 3.1.2.1.6 Validate the values of the OPTIONAL Operation
+ attributes............................................ 33
+ 3.1.2.2 Suggested Additional Processing Steps for Operations
+ that Create/Validate Jobs and Add Documents............. 37
+ 3.1.2.2.1 Default "ipp-attribute-fidelity" if not supplied...... 37
+ 3.1.2.2.2 Check that the Printer object is accepting jobs....... 38
+ 3.1.2.2.3 Validate the values of the Job Template attributes.... 38
+ 3.1.2.3 Algorithm for job validation............................ 39
+ 3.1.2.3.1 Check for conflicting Job Template attributes values.. 45
+ 3.1.2.3.2 Decide whether to REJECT the request.................. 46
+ 3.1.2.3.3 For the Validate-Job operation, RETURN one of the
+ success status codes.................................. 48
+ 3.1.2.3.4 Create the Job object with attributes to support...... 48
+ 3.1.2.3.5 Return one of the success status codes................ 50
+ 3.1.2.3.6 Accept appended Document Content...................... 50
+ 3.1.2.3.7 Scheduling and Starting to Process the Job............ 50
+ 3.1.2.3.8 Completing the Job.................................... 50
+ 3.1.2.3.9 Destroying the Job after completion................... 51
+ 3.1.2.3.10 Interaction with "ipp-attribute-fidelity"............. 51
+ 3.1.2.3.11 Character set code conversion support................. 51
+ 3.1.2.3.12 What charset to return when an unsupported charset is
+ requested (Issue 1.19)?....... ....................... 52
+ 3.1.2.3.13 Natural Language Override (NLO)....................... 53
+ 3.1.3 Status codes returned by operation......................... 55
+ 3.1.3.1 Printer Operations...................................... 55
+ 3.1.3.1.1 Print-Job............................................. 55
+ 3.1.3.1.2 Print-URI............................................. 58
+ 3.1.3.1.3 Validate-Job.......................................... 58
+ 3.1.3.1.4 Create-Job............................................ 58
+ 3.1.3.1.5 Get-Printer-Attributes................................ 59
+ 3.1.3.1.6 Get-Jobs.............................................. 60
+ 3.1.3.1.7 Pause-Printer......................................... 61
+ 3.1.3.1.8 Resume-Printer........................................ 62
+ 3.1.3.1.8.1 What about Printers unable to change state due to
+ an error condition?................................. 63
+ 3.1.3.1.8.2 How is "printer-state" handled on Resume-Printer?... 63
+ 3.1.3.1.9 Purge-Printer......................................... 63
+ 3.1.3.2 Job Operations.......................................... 64
+ 3.1.3.2.1 Send-Document......................................... 64
+ 3.1.3.2.2 Send-URI.............................................. 65
+ 3.1.3.2.3 Cancel-Job............................................ 65
+ 3.1.3.2.4 Get-Job-Attributes.................................... 67
+ 3.1.3.2.5 Hold-Job.............................................. 68
+ 3.1.3.2.6 Release-Job........................................... 69
+
+
+
+Hastings, et al. Informational [Page 2]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ 3.1.3.2.7 Restart-Job........................................... 69
+ 3.1.3.2.7.1 Can documents be added to a restarted job?.......... 69
+ 3.1.4 Returning unsupported attributes in Get-Xxxx responses
+ (Issue 1.18)............................................... 70
+ 3.1.5 Sending empty attribute groups............................. 70
+ 3.2 Printer Operations.......................................... 71
+ 3.2.1 Print-Job operation........................................ 71
+ 3.2.1.1 Flow controlling the data portion of a Print-Job
+ request (Issue 1.22).................................... 71
+ 3.2.1.2 Returning job-state in Print-Job response (Issue 1.30).. 71
+ 3.2.2 Get-Printer-Attributes operation........................... 72
+ 3.2.3 Get-Jobs operation......................................... 72
+ 3.2.3.1 Get-Jobs, my-jobs='true', and 'requesting-user-name'
+ (Issue 1.39)?.......................................... 72
+ 3.2.3.2 Why is there a "limit" attribute in the Get-Jobs
+ operation?.............................................. 73
+ 3.2.4 Create-Job operation....................................... 73
+ 3.3 Job Operations.............................................. 74
+ 3.3.1 Validate-Job............................................... 74
+ 3.3.2 Restart-Job................................................ 74
+ 4 Object Attributes.............................................. 74
+ 4.1 Attribute Syntax's.......................................... 74
+ 4.1.1 The 'none' value for empty sets (Issue 1.37)............... 74
+ 4.1.2 Multi-valued attributes (Issue 1.31)....................... 75
+ 4.1.3 Case Sensitivity in URIs (issue 1.6)....................... 75
+ 4.1.4 Maximum length for xxxWithLanguage and xxxWithoutLanguage.. 76
+ 4.2 Job Template Attributes..................................... 76
+ 4.2.1 multiple-document-handling(type2 keyword).................. 76
+ 4.2.1.1 Support of multiple document jobs....................... 76
+ 4.3 Job Description Attributes.................................. 76
+ 4.3.1 Getting the date and time of day........................... 76
+ 4.4 Printer Description Attributes.............................. 77
+ 4.4.1 queued-job-count (integer(0:MAX)).......................... 77
+ 4.4.1.1 Why is "queued-job-count" RECOMMENDED (Issue 1.14)?..... 77
+ 4.4.1.2 Is "queued-job-count" a good measure of how busy a
+ printer is (Issue 1.15)?................................ 77
+ 4.4.2 printer-current-time (dateTime)............................ 78
+ 4.4.3 Printer-uri................................................ 78
+ 4.5 Empty Jobs.................................................. 79
+ 5 Directory Considerations....................................... 79
+ 5.1 General Directory Schema Considerations..................... 79
+ 5.2 IPP Printer with a DNS name................................. 79
+ 6 Security Considerations........................................ 80
+ 6.1 Querying jobs with IPP that were submitted using other job
+ submission protocols (Issue 1.32)........................... 80
+ 7 Encoding and Transport......................................... 81
+ 7.1 General Headers............................................. 83
+ 7.2 Request Headers............................................ 84
+
+
+
+Hastings, et al. Informational [Page 3]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ 7.3 Response Headers............................................ 86
+ 7.4 Entity Headers............................................. 87
+ 7.5 Optional support for HTTP/1.0............................... 88
+ 7.6 HTTP/1.1 Chunking........................................... 88
+ 7.6.1 Disabling IPP Server Response Chunking..................... 88
+ 7.6.2 Warning About the Support of Chunked Requests.............. 88
+ 8 References..................................................... 89
+ 9 Authors' Addresses............................................. 91
+ 10 Description of the Base IPP Documents.......................... 94
+ 11 Full Copyright Statement....................................... 96
+
+Tables
+
+ Table 1 - Summary of Printer operation attributes that sender MUST
+ supply ................................................. 8
+ Table 2 - Summary of Printer operation attributes that sender MAY
+ supply ................................................. 10
+ Table 3 - Summary of Job operation attributes that sender MUST
+ supply.................................................. 12
+ Table 4 - Summary of Job operation attributes that sender MAY
+ supply.................................................. 14
+ Table 5 - Printer operation response attributes................... 16
+ Table 6 - Examples of validating IPP version...................... 19
+ Table 7 - Rules for validating single values X against Z.......... 40
+
+1. Introduction
+
+ IPP is an application level protocol that can be used for distributed
+ printing using Internet tools and technologies. This document
+ contains information that supplements the IPP Model and Semantics
+ [RFC2911] and the IPP Transport and Encoding [RFC2910] documents. It
+ is intended to help implementers understand IPP/1.1, as well as
+ IPP/1.0 [RFC2565, RFC2566], and some of the considerations that may
+ assist them in the design of their client and/or IPP object
+ implementation. For example, a typical order of processing requests
+ is given, including error checking. Motivation for some of the
+ specification decisions is also included.
+
+ This document obsoletes RFC 2639 which was the Implementor's Guide
+ for IPP/1.0. The IPP Implementor's Guide (IIG) (this document)
+ contains information that supplements the IPP Model and Semantics
+ [RFC2911] and the IPP Transport and Encoding [RFC2910] documents.
+ This document is just one of a suite of documents that fully define
+ IPP. The base set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol [RFC2568]
+
+
+
+Hastings, et al. Informational [Page 4]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementor's Guide (this
+ document)
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ See section 10 for a description of these base IPP documents. Anyone
+ reading these documents for the first time is strongly encouraged to
+ read the IPP documents in the above order.
+
+ As such the information in this document is not part of the formal
+ specification of IPP/1.1. Instead information is presented to help
+ implementers understand IPP/1.1, as well as IPP/1.0 [RFC2565,
+ RFC2566], including some of the motivation for decisions taken by the
+ committee in developing the specification. Some of the
+ implementation considerations are intended to help implementers
+ design their client and/or IPP object implementations. If there are
+ any contradictions between this document and [RFC2911] or [RFC2910],
+ those documents take precedence over this document.
+
+ Platform-specific implementation considerations will be included in
+ this guide as they become known.
+
+ Note: In order to help the reader of the IIG and the IPP Model and
+ Semantics document, the sections in this document parallel the
+ corresponding sections in the Model document and are numbered the
+ same for ease of cross reference. The sections that correspond to
+ the IPP Transport and Encoding are correspondingly offset.
+
+1.1 Conformance language
+
+ Usually, this document does not contain the terminology MUST, MUST
+ NOT, MAY, NEED NOT, SHOULD, SHOULD NOT, REQUIRED, and OPTIONAL.
+ However, when those terms do appear in this document, their intent is
+ to repeat what the [RFC2911] and [RFC2910] documents require and
+ allow, rather than specifying additional conformance requirements.
+ These terms are defined in section 12 on conformance terminology in
+ [RFC2911], most of which is taken from RFC 2119 [RFC2119].
+
+ Implementers should read section 12 (APPENDIX A) in [RFC2911] in
+ order to understand these capitalized words. The words MUST, MUST
+ NOT, and REQUIRED indicate what implementations are required to
+ support in a client or IPP object in order to be conformant to
+ [RFC2911] and [RFC2910]. MAY, NEED NOT, and OPTIONAL indicate was is
+ merely allowed as an implementer option. The verbs SHOULD and SHOULD
+ NOT indicate suggested behavior, but which is not required or
+ disallowed, respectively, in order to conform to the specification.
+
+
+
+
+Hastings, et al. Informational [Page 5]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+1.2 Other terminology
+
+ This document uses other terms, such as "attributes", "operation",
+ and "Printer" as defined in [RFC2911] section 12. In addition, the
+ term "sender" refers to the client that sends a request or an IPP
+ object that returns a response. The term "receiver" refers to the
+ IPP object that receives a request and to a client that receives a
+ response.
+
+1.3 Issues Raised from Interoperability Testing Events
+
+ The IPP WG has conducted three open Interoperability Testing Events.
+ The first one was held in September 1998, the second one was held in
+ March 1999, and the third one was held in October 2000. See the
+ summary reports in:
+
+ ftp://ftp.pwg.org/pub/pwg/ipp/new_TES/
+
+ The issues raised from the first Interoperability Testing Event are
+ numbered 1.n in this document and have been incorporated into
+ "IPP/1.0 Model and Semantics" [RFC2566] and the "IPP/1.0 Encoding and
+ Transport" [RFC2565] documents. However, some of the discussion is
+ left here in the Implementor's Guide to help understanding.
+
+ The issues raised from the second Interoperability Testing Event are
+ numbered 2.n in this document have been incorporated into "IPP/1.1
+ Model and Semantics" [RFC2911] and the "IPP/1.1 Encoding and
+ Transport" [RFC2910] documents. However, some of the discussion is
+ left here in the Implementor's Guide to help understanding.
+
+ The issues raised from the third Interoperability Testing Event are
+ numbered 3.n in this document and are described in:
+
+ ftp://ftp.pwg.org/pub/pwg/ipp/Issues/Issues-raised-at-Bake-
+ Off3.pdf
+
+ ftp://ftp.pwg.org/pub/pwg/ipp/Issues/Issues-raised-at-Bake-
+ Off3.doc
+
+ ftp://ftp.pwg.org/pub/pwg/ipp/Issues/Issues-raised-at-Bake-
+ Off3.txt
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 6]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+2. IPP Objects
+
+ The term "client" in IPP is intended to mean any client that issues
+ IPP operation requests and accepts IPP operation responses, whether
+ it be a desktop or a server. In other words, the term "client" does
+ not just mean end-user clients, such as those associated with
+ desktops.
+
+ The term "IPP Printer" in IPP is intended to mean an object that
+ accepts IPP operation requests and returns IPP operation responses,
+ whether implemented in a server or a device. An IPP Printer object
+ MAY, if implemented in a server, turn around and forward received
+ jobs (and other requests) to other devices and print
+ servers/services, either using IPP or some other protocol.
+
+3 IPP Operations
+
+ This section corresponds to Section 3 "IPP Operations" in the
+ IPP/1.1 Model and Semantics document [RFC2911].
+
+3.1 Common Semantics
+
+ This section discusses semantics common to all operations.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 7]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+3.1.1 Summary of Operation Attributes
+
+ Table 1 - Summary of Printer operation attributes that sender MUST
+ supply
+
+Printer Operations
+
+ Requests Responses
+ Operation PJ, PU CJ GPA GJ PP, All
+ Attributes VJ (O) (O) (R) (R) RP, Operations
+ (R) PP
+ (O+)
+
+ Operation parameters--REQUIRED to be supplied by the sender:
+
+ operation-id R R R R R R
+
+ status-code R
+
+ request-id R R R R R R R
+
+ version-number R R R R R R R
+
+ Operation attributes--REQUIRED to be supplied by the sender:
+
+ attributes- R R R R R R R
+ charset
+
+ attributes- R R R R R R R
+ natural-
+ language
+
+ document-uri R
+
+ job-id*
+
+ job-uri*
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 8]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+Printer Operations
+
+ Requests Responses
+
+ Operation PJ, PU CJ GPA GJ PP, All
+ Attributes VJ (O) (O) (R) (R) RP, Operations
+ (R) PP
+ (O+)
+ last-document
+
+ printer-uri R R R R R R
+
+ Operation attributes--RECOMMENDED to be supplied by the
+ sender:
+
+ job-name R R R
+
+ requesting-user- R R R R R R
+ name
+
+ Legend:
+
+ PJ, VJ: Print-Job, Validate-Job
+ PU: Print-URI
+ CJ: Create-Job
+ GPA: Get-Printer-Attributes
+ GJ: Get-Jobs
+ PP, RP, PP: Pause-Printer, Resume-Printer, Purge-Printer
+ R indicates a REQUIRED operation that MUST be supported by the IPP
+ object (Printer or Job). For attributes, R indicates that the
+ attribute MUST be supported by the IPP object that supports the
+ associated operation.
+ O indicates an OPTIONAL operation or attribute that MAY be supported
+ by the IPP object (Printer or Job).
+ + indicates that this is not an IPP/1.0 feature, but is only a part
+ of IPP/1.1 and future versions of IPP.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 9]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Table 2 - Summary of Printer operation attributes that sender MAY
+ supply
+
+Printer Operations
+
+ Requests Respon-
+ ses
+ Operation Attributes PJ, PU CJ GPA GJ PP, All
+ VJ (O) (O) (R) (R) RP, Opera
+ (R) PP tions
+ (O+)
+
+ Operation attributes--OPTIONAL to be supplied by the sender:
+
+ status-message O
+
+ detailed-status- O
+ message
+
+ document-access- O**
+ error
+
+ compression R R
+
+ document-format R R R
+
+ document-name O O
+
+ document-natural- O O
+ language
+
+ ipp-attribute- R R R
+ fidelity
+
+ job-impressions O O O
+
+ job-k-octets O O O
+
+ job-media-sheets O O O
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 10]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+Printer Operations
+
+ Requests Respon-
+ ses
+ Operation Attributes PJ, PU CJ GPA GJ PP, All
+ VJ (O) (O) (R) (R) RP, Opera
+ (R) PP tions
+ (O+)
+
+ limit R
+
+ message
+
+ my-jobs R
+
+ requested-attributes R R
+
+ which-jobs R
+
+ Legend:
+
+ PJ, VJ: Print-Job, Validate-Job
+ PU: Print-URI
+ CJ: Create-Job
+ GPA: Get-Printer-Attributes
+ GJ: Get-Jobs
+ PP, RP, PP: Pause-Printer, Resume-Printer, Purge-Printer
+ R indicates a REQUIRED operation that MUST be supported by the IPP
+ object (Printer or Job). For attributes, R indicates that the
+ attribute MUST be supported by the IPP object that supports the
+ associated operation.
+ O indicates an OPTIONAL operation or attribute that MAY be supported
+ by the IPP object (Printer or Job).
+ + indicates that this is not an IPP/1.0 feature, but is only a part
+ of IPP/1.1 and future versions of IPP.
+ * "job-id" is REQUIRED only if used together with "printer-uri" to
+ identify the target job; otherwise, "job-uri" is REQUIRED.
+ ** "document-access-error" applies to the Print-URI response only.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 11]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Table 3 - Summary of Job operation attributes that sender MUST supply
+
+Job Operations
+
+ Requests Responses
+ Operation SD SU CJ GJA HJ All
+ Attributes (O) (O) (R) (R) RJ, RJ Opera-
+ (O+) tions
+
+ Operation parameters--REQUIRED to be supplied by the sender:
+
+ operation-id R R R R R
+
+ status-code R
+
+ request-id R R R R R R
+
+ version-number R R R R R R
+
+ Operation attributes--REQUIRED to be supplied by the sender:
+
+ attributes-charset R R R R R R
+
+ attributes-natural- R R R R R R
+ language
+
+ document-uri R
+
+ job-id* R R R R R
+
+ job-uri* R R R R R
+
+ last-document R R
+
+ printer-uri R R R R R
+
+ Operation attributes--RECOMMENDED to be supplied by the sender:
+
+ job-name
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 12]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+Job Operations
+
+ Requests Responses
+
+ Operation SD SU CJ GJA HJ All
+ Attributes (O) (O) (R) (R) RJ, RJ Opera-
+ (O+) tions
+
+ requesting-user- R R R R R
+ name
+
+ Legend:
+
+ SD: Send-Document
+ SU: Send-URI
+ CJ: Cancel-Job
+ GJA: Get-Job-Attributes
+ HJ, RJ, RJ: Hold-Job, Release-Job, Restart-Job
+ R indicates a REQUIRED operation that MUST be supported by the IPP
+ object (Printer or Job). For attributes, R indicates that the
+ attribute MUST be supported by the IPP object that supports the
+ associated operation.
+ O indicates an OPTIONAL operation or attribute that MAY be supported
+ by the IPP object (Printer or Job).
+ + indicates that this is not an IPP/1.0 feature, but is only a part
+ of IPP/1.1 and future versions of IPP.
+ * "job-id" is REQUIRED only if used together with "printer-uri" to
+ identify the target job; otherwise, "job-uri" is REQUIRED.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 13]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Table 4 - Summary of Job operation attributes that sender MAY supply
+
+Job Operations
+
+ Requests Responses
+
+ Operation SD SU CJ GJA HJ, SD All
+ Attributes (O) (O) (R) (R) RJ, (O) Opera-
+ RJ tions
+ (O+)
+
+ Operation attributes--OPTIONAL to be supplied by the sender:
+
+ status-message O
+
+ detailed-status- O
+ message
+
+ document-access- O**
+ error
+
+ compression R R
+
+ document-format R R
+
+ document-name O O
+
+ document-natural- O O
+ language
+
+ ipp-attribute-
+ fidelity
+
+ job-impressions
+
+ job-k-octets
+
+ job-media-sheets
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 14]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+Job Operations
+
+ Requests Responses
+
+ Operation SD SU CJ GJA HJ, SD All
+ Attributes (O) (O) (R) (R) RJ, (O) Opera-
+ RJ tions
+ (O+)
+
+ limit
+
+ message O O O
+
+ job-hold-until R
+
+ my-jobs
+
+ requested- R
+ attributes
+
+ which-jobs
+
+ Legend:
+
+ SD: Send-Document
+ SU: Send-URI
+ CJ: Cancel-Job
+ GJA: Get-Job-Attributes
+ HJ, RJ, RJ: Hold-Job, Release-Job, Restart-Job
+ R indicates a REQUIRED operation that MUST be supported by the IPP
+ object (Printer or Job). For attributes, R indicates that the
+ attribute MUST be supported by the IPP object that supports the
+ associated operation.
+ O indicates an OPTIONAL operation or attribute that MAY be supported
+ by the IPP object (Printer or Job).
+ + indicates that this is not an IPP/1.0 feature, but is only a part
+ of IPP/1.1 and future versions of IPP.
+ * "job-id" is REQUIRED only if used together with "printer-uri" to
+ identify the target job; otherwise, "job-uri" is REQUIRED.
+ ** "document-access-error" applies to the Send-URI operation only
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 15]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Table 5 - Printer operation response attributes
+
+Printer Operations
+
+ Response
+
+ Operation PJ (R) VJ (R) PU (O) CJ (O) GPA GJ (R) PP,
+ Attributes SD (O) SU (O) (R) RP, PP
+ (O+)
+
+ job-uri R R R
+
+ job-id R R R
+
+ job-state R R R
+
+ job-state- R+ R+ R+
+ reasons
+
+ number-of- O O O
+ intervening-
+ jobs
+
+ document- O
+ access-
+ error+
+
+ Legend:
+
+ PJ, SJ: Print-Job, Send-Document
+ VJ: Validate-Job
+ PU, SU: Print-URI, Send-URI
+ CJ: Create-Job
+ GPA: Get-Printer-Attributes
+ GJ: Get-Jobs
+ PP, RP, PP: Pause-Printer, Resume-Printer, Purge-Printer
+ R indicates a REQUIRED operation that MUST be supported by the IPP
+ object (Printer or Job). For attributes, R indicates that the
+ attribute MUST be supported by the IPP object that supports the
+ associated operation.
+ O indicates an OPTIONAL operation or attribute that MAY be supported
+ by the IPP object (Printer or Job).
+
+3.1.2 Suggested Operation Processing Steps for IPP Objects
+
+ This section suggests the steps and error checks that an IPP object
+ MAY perform when processing requests and returning responses. An IPP
+ object MAY perform some or all of the error checks. However, some
+
+
+
+Hastings, et al. Informational [Page 16]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ implementations MAY choose to be more forgiving than the error checks
+ shown here, in order to be able to accept requests from non-
+ conforming clients. Not performing all of these error checks is a
+ so-called "forgiving" implementation. On the other hand, clients
+ that successfully submit requests to IPP objects that do perform all
+ the error checks will be more likely to be able to interoperate with
+ other IPP object implementations. Thus an implementer of an IPP
+ object needs to decide whether to be a "forgiving" or a "strict"
+ implementation. Therefore, the error status codes returned may
+ differ between implementations. Consequentially, client SHOULD NOT
+ expect exactly the error code processing described in this section.
+
+ When an IPP object receives a request, the IPP object either accepts
+ or rejects the request. In order to determine whether or not to
+ accept or reject the request, the IPP object SHOULD execute the
+ following steps. The order of the steps may be rearranged and/or
+ combined, including making one or multiple passes over the request.
+
+ A client MUST supply requests that would pass all of the error checks
+ indicated here in order to be a conforming client. Therefore, a
+ client SHOULD supply requests that are conforming, in order to avoid
+ being rejected by some IPP object implementations and/or risking
+ different semantics by different implementations of forgiving
+ implementations. For example, a forgiving implementation that
+ accepts multiple occurrences of the same attribute, rather than
+ rejecting the request might use the first occurrences, while another
+ might use the last occurrence. Thus such a non-conforming client
+ would get different results from the two forgiving implementations.
+
+ In the following, processing continues step by step until a "RETURNS
+ the xxx status code ..." statement is encountered. Error returns are
+ indicated by the verb: "REJECTS". Since clients have difficulty
+ getting the status code before sending all of the document data in a
+ Print-Job request, clients SHOULD use the Validate-Job operation
+ before sending large documents to be printed, in order to validate
+ whether the IPP Printer will accept the job or not.
+
+ It is assumed that security authentication and authorization has
+ already taken place at a lower layer.
+
+3.1.2.1 Suggested Operation Processing Steps for all Operations
+
+ This section is intended to apply to all operations. The next
+ section contains the additional steps for the Print-Job, Validate-
+ Job, Print-URI, Create-Job, Send-Document, and Send-URI operations
+ that create jobs, adds documents, and validates jobs.
+
+
+
+
+
+Hastings, et al. Informational [Page 17]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ IIG Sect # Flow IPP error status codes
+ ---------- ---- ----------------------
+ |
+ v err
+ 3.1.2.1.1 <Validate version> --> server-error-version-not-
+ supported
+ ok|
+ v err
+ 3.1.2.1.2 <Validate operation> --> server-error-operation-not-
+ supported
+ ok|
+ v err
+ 3.1.2.1.4.1- <Validate presence> --> client-error-bad-request
+ 3.1.2.1.4.2 <of attributes>
+ ok|
+ v err
+ 3.1.2.1.4.3 <Validate presence> --> client-error-bad-request
+ <of operation attr>
+ ok|
+ v err
+ 3.1.2.1.5 <Validate values of> --> client-error-bad-request
+ <operation attrs> client-error-request-value-
+ too-long
+ <(length, tag, range,>
+ <multi-value)>
+ ok|
+ v err
+ 3.1.2.1.5 <Validate values> --> client-error-bad-request
+ <with supported values> client-error-charset-not-
+ supported
+ ok| client-error-attributes-or-
+ values-
+ | not-supported
+ v err
+ 3.1.2.1.6 <Validate optionally> --> client-error-bad-request
+ <operation attr> client-error-natural-language-
+ not-supported
+ | client-error-request-value-
+ too-long
+ | client-error-attributes-or-
+ values-not-supported
+
+3.1.2.1.1 Validate version number
+
+ Every request and every response contains the "version-number"
+ attribute. The value of this attribute is the major and minor
+ version number of the syntax and semantics that the client and IPP
+ object is using, respectively. The "version-number" attribute
+
+
+
+Hastings, et al. Informational [Page 18]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ remains in a fixed position across all future versions so that all
+ clients and IPP object that support future versions can determine
+ which version is being used. The IPP object checks to see if the
+ major version number supplied in the request is supported. If not,
+ the Printer object REJECTS the request and RETURNS the 'server-
+ error-version-not-supported' status code in the response. The IPP
+ object returns in the "version-number" response attribute the major
+ and minor version for the error response. Thus the client can learn
+ at least one major and minor version that the IPP object supports.
+ The IPP object is encouraged to return the closest version number to
+ the one supplied by the client.
+
+ The checking of the minor version number is implementation dependent,
+ however if the client-supplied minor version is explicitly supported,
+ the IPP object MUST respond using that identical minor version
+ number. If the major version number matches, but the minor version
+ number does not, the Printer SHOULD accept and attempt to process the
+ request, or MAY reject the request and return the 'server-error-
+ version-not-supported' status code. In all cases, the Printer MUST
+ return the nearest version number that it supports. For example,
+ suppose that an IPP/1.2 Printer supports versions '1.1' and '1.2'.
+ The following responses are conforming:
+
+ Table 6 - Examples of validating IPP version
+
+ Client supplies Printer Accept Request? Printer returns
+
+
+ 1.0 yes (SHOULD) 1.1
+
+ 1.0 no (SHOULD NOT) 1.1
+
+ 1.1 yes (MUST) 1.1
+
+ 1.2 yes (MUST) 1.2
+
+ 1.3 yes (SHOULD) 1.2
+
+ 1.3 no (SHOULD NOT) 1.2
+
+ It is advantageous for Printers to support both IPP/1.1 and IPP/1.0,
+ so that they can interoperate with either client implementations.
+ Some implementations may allow an Administrator to explicitly disable
+ support for one or the other by setting the "ipp-versions-supported"
+ Printer description attribute.
+
+
+
+
+
+
+Hastings, et al. Informational [Page 19]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Likewise, it is advantageous for clients to support both versions to
+ allow interoperability with new and legacy Printers.
+
+3.1.2.1.2 Validate operation identifier
+
+ The Printer object checks to see if the "operation-id" attribute
+ supplied by the client is supported as indicated in the Printer
+ object's "operations-supported" attribute. If not, the Printer
+ REJECTS the request and returns the 'server-error-operation-not-
+ supported' status code in the response.
+
+3.1.2.1.3 Validate the request identifier
+
+ The Printer object SHOULD NOT check to see if the "request-id"
+ attribute supplied by the client is in range: between 1 and 2**31 - 1
+ (inclusive), but copies all 32 bits.
+
+ Note: The "version-number", "operation-id", and the "request-id"
+ parameters are in fixed octet positions in the IPP/1.1 encoding. The
+ "version-number" parameter will be the same fixed octet position in
+ all versions of the protocol. These fields are validated before
+ proceeding with the rest of the validation.
+
+3.1.2.1.4 Validate attribute group and attribute presence and order
+
+ The order of the following validation steps depends on
+ implementation.
+
+3.1.2.1.4.1 Validate the presence and order of attribute groups
+
+ Client requests and IPP object responses contain attribute groups
+ that Section 3 requires to be present and in a specified order. An
+ IPP object verifies that the attribute groups are present and in the
+ correct order in requests supplied by clients (attribute groups
+ without an * in the following tables).
+
+ If an IPP object receives a request with (1) required attribute
+ groups missing, or (2) the attributes groups are out of order, or (3)
+ the groups are repeated, the IPP object REJECTS the request and
+ RETURNS the 'client-error-bad-request' status code. For example, it
+ is an error for the Job Template Attributes group to occur before the
+ Operation Attributes group, for the Operation Attributes group to be
+ omitted, or for an attribute group to occur more than once, except in
+ the Get-Jobs response.
+
+ Since this kind of attribute group error is most likely to be an
+ error detected by a client developer rather than by a customer, the
+ IPP object NEED NOT return an indication of which attribute group was
+
+
+
+Hastings, et al. Informational [Page 20]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ in error in either the Unsupported Attributes group or the Status
+ Message. Also, the IPP object NEED NOT find all attribute group
+ errors before returning this error.
+
+3.1.2.1.4.2 Ignore unknown attribute groups in the expected position
+
+ Future attribute groups may be added to the specification at the end
+ of requests just before the Document Content and at the end of
+ response, except for the Get-Jobs response, where it maybe there or
+ before the first job attributes returned. If an IPP object receives
+ an unknown attribute group in these positions, it ignores the entire
+ group, rather than returning an error, since that group may be a new
+ group in a later minor version of the protocol that can be ignored.
+ (If the new attribute group cannot be ignored without confusing the
+ client, the major version number would have been increased in the
+ protocol document and in the request). If the unknown group occurs
+ in a different position, the IPP object REJECTS the request and
+ RETURNS the 'client-error-bad-request' status code.
+
+ Clients also ignore unknown attribute groups returned in a response.
+
+ Note: By validating that requests are in the proper form, IPP
+ objects force clients to use the proper form which, in turn,
+ increases the chances that customers will be able to use such clients
+ from multiple vendors with IPP objects from other vendors.
+
+3.1.2.1.4.3 Validate the presence of a single occurrence of required
+ Operation attributes
+
+ Client requests and IPP object responses contain Operation attributes
+ that [RFC2911] Section 3 requires to be present. Attributes within a
+ group may be in any order, except for the ordering of target,
+ charset, and natural languages attributes. These attributes MUST be
+ first, and MUST be supplied in the following order: charset, natural
+ language, and then target. An IPP object verifies that the
+ attributes that Section 4 requires to be supplied by the client have
+ been supplied in the request (attributes without an * in the
+ following tables). An asterisk (*) indicates groups and Operation
+ attributes that the client may omit in a request or an IPP object may
+ omit in a response.
+
+ If an IPP object receives a request with required attributes missing
+ or repeated from a group or in the wrong position, the behavior of
+ the IPP object is IMPLEMENTATION DEPENDENT. Some of the possible
+ implementations are:
+
+ REJECTS the request and RETURNS the 'client-error-bad-request'
+ status code
+
+
+
+Hastings, et al. Informational [Page 21]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ accepts the request and uses the first occurrence of the attribute
+ no matter where it is
+
+ accepts the request and uses the last occurrence of the attribute
+ no matter where it is
+
+ accept the request and assume some default value for the missing
+ attribute
+
+ Therefore, client MUST send conforming requests, if they want to
+ receive the same behavior from all IPP object implementations. For
+ example, it is an error for the "attributes-charset" or "attributes-
+ natural-language" attribute to be omitted in any operation request,
+ or for an Operation attribute to be supplied in a Job Template group
+ or a Job Template attribute to be supplied in an Operation Attribute
+ group in a create request. It is also an error to supply the
+ "attributes-charset" attribute twice.
+
+ Since these kinds of attribute errors are most likely to be detected
+ by a client developer rather than by a customer, the IPP object NEED
+ NOT return an indication of which attribute was in error in either
+ the Unsupported Attributes group or the Status Message. Also, the
+ IPP object NEED NOT find all attribute errors before returning this
+ error.
+
+ The following tables list all the attributes for all the operations
+ by attribute group in each request and each response. The order of
+ the groups is the order that the client supplies the groups as
+ specified in [RFC2911] Section 3. The order of the attributes within
+ a group is arbitrary, except as noted for some of the special
+ operation attributes (charset, natural language, and target). The
+ tables below use the following notation:
+
+ R indicates a REQUIRED attribute or operation that an IPP
+ object MUST support
+ O indicates an OPTIONAL attribute or operation that an IPP
+ object NEED NOT support
+ * indicates that a client MAY omit the attribute in a request
+ and that an IPP object MAY omit the attribute in a response.
+ The absence of an * means that a client MUST supply the
+ attribute in a request and an IPP object MUST supply the
+ attribute in a response.
+ + indicates that this is not a IPP/1.0 operation, but is only
+ a part of IPP/1.1 and future versions of IPP.
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 22]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Operation Requests
+
+ The tables below show the attributes in their proper attribute groups
+ for operation requests:
+
+ Note: All operation requests contain "version-number", "operation-
+ id", and "request-id" parameters.
+
+ Print-Job Request (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+ job-name (R*)
+ ipp-attribute-fidelity (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+ compression (R*)
+ job-k-octets (O*)
+ job-impressions (O*)
+ job-media-sheets (O*)
+ Group 2: Job Template Attributes (R*)
+ <Job Template attributes> (O*)
+ (see [RFC2911] Section 4.2)
+ Group 3: Document Content (R)
+ <document content>
+
+ Validate-Job Request (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+ job-name (R*)
+ ipp-attribute-fidelity (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+ compression (R*)
+ job-k-octets (O*)
+ job-impressions (O*)
+ job-media-sheets (O*)
+ Group 2: Job Template Attributes (R*)
+ <Job Template attributes> (O*)
+ (see [RFC2911] Section 4.2)
+
+
+
+
+Hastings, et al. Informational [Page 23]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Print-URI Request (O):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ document-uri (R)
+ requesting-user-name (R*)
+ job-name (R*)
+ ipp-attribute-fidelity (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+ compression (R*)
+ job-k-octets (O*)
+ job-impressions (O*)
+ job-media-sheets (O*)
+ Group 2: Job Template Attributes (R*)
+ <Job Template attributes> (O*) (see
+ (see [RFC2911] Section 4.2)
+
+ Create-Job Request (O):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+ job-name (R*)
+ ipp-attribute-fidelity (R*)
+ job-k-octets (O*)
+ job-impressions (O*)
+ job-media-sheets (O*)
+ Group 2: Job Template Attributes (R*)
+ <Job Template attributes> (O*) (see
+ (see [RFC2911] Section 4.2)
+
+ Get-Printer-Attributes Request (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+ requested-attributes (R*)
+ document-format (R*)
+
+ Get-Jobs Request (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+
+
+
+Hastings, et al. Informational [Page 24]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ printer-uri (R)
+ requesting-user-name (R*)
+ limit (R*)
+ requested-attributes (R*)
+ which-jobs (R*)
+ my-jobs (R*)
+
+ Send-Document Request (O):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ (printer-uri & job-id) | job-uri (R)
+ last-document (R)
+ requesting-user-name (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+ compression (R*)
+ Group 2: Document Content (R*)
+ <document content>
+
+ Send-URI Request (O):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ (printer-uri & job-id) | job-uri (R)
+ last-document (R)
+ document-uri (R)
+ requesting-user-name (R*)
+ document-name (R*)
+ document-format (R*)
+ document-natural-language (O*)
+ compression (R*)
+
+ Cancel-Job Request (R):
+ Release-Job Request (O+):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ (printer-uri & job-id) | job-uri (R)
+ requesting-user-name (R*)
+ message (O*)
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 25]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Get-Job-Attributes Request (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ (printer-uri & job-id) | job-uri (R)
+ requesting-user-name (R*)
+ requested-attributes (R*)
+
+ Pause-Printer Request (O+):
+ Resume-Printer Request (O+):
+ Purge-Printer Request (O+):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ printer-uri (R)
+ requesting-user-name (R*)
+
+ Hold-Job Request (O+):
+ Restart-Job Request (O+):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ (printer-uri & job-id) | job-uri (R)
+ requesting-user-name (R*)
+ job-hold-until (R*)
+ message (O*)
+
+ Operation Responses
+
+ The tables below show the response attributes in their proper
+ attribute groups for responses.
+
+ Note: All operation responses contain "version-number", "status-
+ code", and "request-id" parameters.
+
+ Print-Job Response (R):
+ Create-Job Response (O):
+ Send-Document Response (O):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ detailed-status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 3)
+ n <unsupported attributes> (R*)
+ Group 3: Job Object Attributes(R*) (see Note 2)
+ job-uri (R)
+ job-id (R)
+
+
+
+Hastings, et al. Informational [Page 26]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ job-state (R)
+ job-state-reasons (O* | R+)
+ job-state-message (O*)
+ number-of-intervening-jobs (O*)
+
+ Validate-Job Response (R):
+ Cancel-Job Response (R):
+ Hold-Job Response (O+):
+ Release-Job Response (O+):
+ Restart-Job Response (O+):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ detailed-status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 3)
+ <unsupported attributes> (R*)
+
+ Print-URI Response (O):
+ Send-URI Response (O):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ detailed-status-message (O*)
+ document-access-error (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 3)
+ <unsupported attributes> (R*)
+ Group 3: Job Object Attributes(R*) (see Note 2)
+ job-uri (R)
+ job-id (R)
+ job-state (R)
+ job-state-reasons (O* | R+)
+ job-state-message (O*)
+ number-of-intervening-jobs (O*)
+
+ Get-Printer-Attributes Response (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ detailed-status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 4)
+ <unsupported attributes> (R*)
+ Group 3: Printer Object Attributes(R*) (see Note 2)
+ <requested attributes> (R*)
+
+
+
+
+
+Hastings, et al. Informational [Page 27]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Get-Jobs Response (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ detailed-status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 4)
+ <unsupported attributes> (R*)
+ Group 3: Job Object Attributes(R*) (see Note 2, 5)
+ <requested attributes> (R*)
+
+ Get-Job-Attributes Response (R):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ detailed-status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 4)
+ <unsupported attributes> (R*)
+ Group 3: Job Object Attributes(R*) (see Note 2)
+ <requested attributes> (R*)
+
+ Pause-Printer Response (O+):
+ Resume-Printer Response (O+):
+ Purge-Printer Response (O+):
+ Group 1: Operation Attributes (R)
+ attributes-charset (R)
+ attributes-natural-language (R)
+ status-message (O*)
+ detailed-status-message (O*)
+ Group 2: Unsupported Attributes (R*) (see Note 4)
+ <unsupported attributes> (R*)
+
+ Note 2 - the Job Object Attributes and Printer Object Attributes are
+ returned only if the IPP object returns one of the success status
+ codes.
+
+ Note 3 - the Unsupported Attributes Group is present only if the
+ client included some Operation and/or Job Template attributes or
+ values that the Printer doesn't support whether a success or an error
+ return.
+
+ Note 4 - the Unsupported Attributes Group is present only if the
+ client included some Operation attributes that the Printer doesn't
+ support whether a success or an error return.
+
+
+
+
+
+
+Hastings, et al. Informational [Page 28]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Note 5: for the Get-Jobs operation the response contains a separate
+ Job Object Attributes group 3 to N containing requested-attributes
+ for each job object in the response.
+
+3.1.2.1.5 Validate the values of the REQUIRED Operation attributes
+
+ An IPP object validates the values supplied by the client of the
+ REQUIRED Operation attribute that the IPP object MUST support. The
+ next section specifies the validation of the values of the OPTIONAL
+ Operation attributes that IPP objects MAY support.
+
+ The IPP object performs the following syntactic validation checks of
+ each Operation attribute value:
+
+ a) that the length of each Operation attribute value is correct
+ for the attribute syntax tag supplied by the client according
+ to [RFC2911] Section 4.1,
+
+ b) that the attribute syntax tag is correct for that Operation
+ attribute according to [RFC2911] Section 3,
+
+ c) that the value is in the range specified for that Operation
+ attribute according to [RFC2911] Section 3,
+
+ d) that multiple values are supplied by the client only for
+ operation attributes that are multi-valued, i.e., that are
+ 1setOf X according to [RFC2911] Section 3.
+
+ If any of these checks fail, the IPP object REJECTS the request and
+ RETURNS the 'client-error-bad-request' or the 'client-error-request-
+ value-too-long' status code. Since such an error is most likely to
+ be an error detected by a client developer, rather than by an end-
+ user, the IPP object NEED NOT return an indication of which attribute
+ had the error in either the Unsupported Attributes Group or the
+ Status Message. The description for each of these syntactic checks
+ is explicitly expressed in the first IF statement in the following
+ table.
+
+ In addition, the IPP object checks each Operation attribute value
+ against some Printer object attribute or some hard-coded value if
+ there is no "xxx-supported" Printer object attribute defined. If its
+ value is not among those supported or is not in the range supported,
+ then the IPP object REJECTS the request and RETURNS the error status
+ code indicated in the table by the second IF statement. If the value
+ of the Printer object's "xxx-supported" attribute is 'no-value'
+ (because the system administrator hasn't configured a value), the
+ check always fails.
+
+
+
+
+Hastings, et al. Informational [Page 29]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ -----------------------------------------------
+
+ attributes-charset (charset)
+
+ IF NOT a single non-empty 'charset' value, REJECT/RETURN 'client-
+ error-bad-request'.
+
+ IF the value length is greater than 63 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ IF NOT in the Printer object's "charset-supported" attribute,
+ REJECT/RETURN "client-error-charset-not-supported".
+
+ attributes-natural-language(naturalLanguage)
+
+ IF NOT a single non-empty 'naturalLanguage' value, REJECT/RETURN
+ 'client-error-bad-request'.
+
+ IF the value length is greater than 63 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ ACCEPT the request even if not a member of the set in the Printer
+ object's "generated-natural-language-supported" attribute. If the
+ supplied value is not a member of the Printer object's
+ "generated-natural-language-supported" attribute, use the Printer
+ object's "natural-language- configured" value.
+
+ requesting-user-name
+
+ IF NOT a single 'name' value, REJECT/RETURN 'client-error-bad-
+ request'.
+
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ IF the IPP object can obtain a better-authenticated name, use it
+ instead.
+
+ job-name(name)
+
+ IF NOT a single 'name' value, REJECT/RETURN 'client-error-bad-
+ request'.
+
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ IF NOT supplied by the client, the Printer object creates a name
+ from the document-name or document-uri.
+
+
+
+Hastings, et al. Informational [Page 30]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ document-name (name)
+
+ IF NOT a single 'name' value, REJECT/RETURN 'client-error-bad-
+ request'.
+
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ ipp-attribute-fidelity (boolean)
+
+ IF NEITHER a single 'true' NOR a single 'false' 'boolean' value,
+ REJECT/RETURN 'client-error-bad-request'.
+
+ IF the value length is NOT equal to 1 octet, REJECT/RETURN
+ 'client-error-request-value-too-long'
+
+ IF NOT supplied by the client, the IPP object assumes the value
+ 'false'.
+
+ document-format (mimeMediaType)
+
+ IF NOT a single non-empty 'mimeMediaType' value, REJECT/RETURN
+ 'client-error-bad-request'.
+
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ IF NOT in the Printer object's "document-format-supported"
+ attribute, REJECT/RETURN 'client-error-document-format-not-
+ supported'
+
+ IF NOT supplied by the client, the IPP object assumes the value of
+ the Printer object's "document-format-default" attribute.
+
+ document-uri (uri)
+
+ IF NOT a single non-empty 'uri' value, REJECT/RETURN 'client-
+ error-bad-request'.
+
+ IF the value length is greater than 1023 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ IF the URI syntax is not valid, REJECT/RETURN 'client-error-bad-
+ request'.
+
+ If the client-supplied URI scheme is not supported, i.e., the
+ value is not in the Printer object's referenced-uri-scheme-
+ supported" attribute, the Printer object MUST reject the request
+
+
+
+Hastings, et al. Informational [Page 31]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ and return the 'client-error-uri-scheme-not-supported' status
+ code. The Printer object MAY check to see if the document exists
+ and is accessible. If the document is not found or is not
+ accessible, REJECT/RETURN 'client-error-not found'.
+
+ last-document (boolean)
+
+ IF NEITHER a single 'true' NOR a single 'false' 'boolean' value,
+ REJECT/RETURN 'client-error-bad-request'.
+
+ IF the value length is NOT equal to 1 octet, REJECT/RETURN
+ 'client-error-request-value-too-long'
+
+ job-id (integer(1:MAX))
+
+ IF NOT an single 'integer' value equal to 4 octets AND in the
+ range 1 to MAX, REJECT/RETURN 'client-error-bad-request'.
+
+ IF NOT a job-id of an existing Job object, REJECT/RETURN 'client-
+ error-not-found' or 'client-error-gone' status code, if keep track
+ of recently deleted jobs.
+
+ requested-attributes (1setOf keyword)
+
+ IF NOT one or more 'keyword' values, REJECT/RETURN 'client-
+ error-bad-request'.
+
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ Ignore unsupported values, which are the keyword names of
+ unsupported attributes. Don't bother to copy such requested
+ (unsupported) attributes to the Unsupported Attribute response
+ group since the response will not return them.
+
+ which-jobs (type2 keyword)
+
+ IF NOT a single 'keyword' value, REJECT/RETURN 'client-error-bad-
+ request'.
+
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ IF NEITHER 'completed' NOR 'not-completed', copy the attribute and
+ the unsupported value to the Unsupported Attributes response group
+ and REJECT/RETURN 'client-error-attributes-or-values-not-
+ supported'.
+
+
+
+
+Hastings, et al. Informational [Page 32]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Note: a Printer still supports the 'completed' value even if it
+ keeps no completed/canceled/aborted jobs: by returning no jobs
+ when so queried.
+
+ IF NOT supplied by the client, the IPP object assumes the 'not-
+ completed' value.
+
+ my-jobs (boolean)
+
+ IF NEITHER a single 'true' NOR a single 'false' 'boolean' value,
+ REJECT/RETURN 'client-error-bad-request'.
+
+ IF the value length is NOT equal to 1 octet, REJECT/RETURN
+ 'client-error-request-value-too-long'
+
+ IF NOT supplied by the client, the IPP object assumes the 'false'
+ value.
+
+ limit (integer(1:MAX))
+
+ IF NOT a single 'integer' value equal to 4 octets AND in the range
+ 1 to MAX, REJECT/RETURN 'client-error-bad-request'.
+
+ IF NOT supplied by the client, the IPP object returns all jobs, no
+ matter how many.
+
+ -----------------------------------------------
+
+3.1.2.1.6 Validate the values of the OPTIONAL Operation attributes
+
+ OPTIONAL Operation attributes are those that an IPP object MAY
+ support. An IPP object validates the values of the OPTIONAL
+ attributes supplied by the client. The IPP object performs the same
+ syntactic validation checks for each OPTIONAL attribute value as in
+ Section 3.1.2.1.5. As in Section 3.1.2.1.5, if any fail, the IPP
+ object REJECTS the request and RETURNS the 'client-error-bad-request'
+ or the 'client-error-request-value-too-long' status code.
+
+ In addition, the IPP object checks each Operation attribute value
+ against some Printer attribute or some hard-coded value if there is
+ no "xxx-supported" Printer attribute defined. If its value is not
+ among those supported or is not in the range supported, then the IPP
+ object REJECTS the request and RETURNS the error status code
+ indicated in the table. If the value of the Printer object's "xxx-
+ supported" attribute is 'no-value' (because the system administrator
+ hasn't configured a value), the check always fails.
+
+
+
+
+
+Hastings, et al. Informational [Page 33]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ If the IPP object doesn't recognize/support an attribute, the IPP
+ object treats the attribute as an unknown or unsupported attribute
+ (see the last row in the table below).
+
+ -----------------------------------------------
+
+ document-natural-language (naturalLanguage)
+
+ IF NOT a single non-empty 'naturalLanguage' value, REJECT/RETURN
+ 'client-error-bad-request'.
+
+ IF the value length is greater than 63 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ IF NOT a value that the Printer object supports in document
+ formats, (no corresponding "xxx-supported" Printer attribute),
+ REJECT/RETURN 'client-error-natural-language-not-supported'.
+
+ compression (type3 keyword)
+
+ IF NOT a single 'keyword' value, REJECT/RETURN 'client-error-bad-
+ request'.
+
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ IF NOT in the Printer object's "compression-supported" attribute,
+ REJECT/RETURN 'client-error-compression-not-supported'.
+
+ Note to IPP/1.0 implementers: Support for the "compression"
+ attribute was optional in IPP/1.0 and was changed to REQUIRED in
+ IPP/1.1. However, an IPP/1.0 object SHOULD at least check for the
+ "compression" attribute being present and reject the create
+ request, if they don't support "compression". Not checking is a
+ bug, since the data will be unintelligible.
+
+ job-k-octets (integer(0:MAX))
+
+ IF NOT a single 'integer' value equal to 4 octets, REJECT/RETURN
+ 'client-error-bad-request'.
+
+ IF NOT in the range of the Printer object's "job-k-octets-
+ supported" attribute, copy the attribute and the unsupported value
+ to the Unsupported Attributes response group and REJECT/RETURN
+ 'client-error-attributes-or-values-not-supported'.
+
+
+
+
+
+
+Hastings, et al. Informational [Page 34]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ job-impressions (integer(0:MAX))
+
+ IF NOT a single 'integer' value equal to 4 octets, REJECT/RETURN
+ 'client-error-bad-request'.
+
+ IF NOT in the range of the Printer object's "job-impressions-
+ supported" attribute, copy the attribute and the unsupported value
+ to the Unsupported Attributes response group and REJECT/RETURN
+ 'client-error-attributes-or-values-not-supported'.
+
+ job-media-sheets (integer(0:MAX))
+
+ IF NOT a single 'integer' value equal to 4 octets, REJECT/RETURN
+ 'client-error-bad-request'.
+
+ IF NOT in the range of the Printer object's "job-media-sheets-
+ supported" attribute, copy the attribute and the unsupported value
+ to the Unsupported Attributes response group and REJECT/RETURN
+ 'client-error-attributes-or-values-not-supported'.
+
+ message (text(127))
+
+ IF NOT a single 'text' value, REJECT/RETURN 'client-error-bad-
+ request'.
+
+ IF the value length is greater than 127 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ unknown or unsupported attribute
+
+ IF the attribute syntax supplied by the client is supported but
+ the length is not legal for that attribute syntax, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ ELSE copy the attribute and value to the Unsupported Attributes
+ response group and change the attribute value to the "out-of-band"
+ 'unsupported' value, but otherwise ignore the attribute.
+
+ Note: Future Operation attributes may be added to the protocol
+ specification that may occur anywhere in the specified group. When
+ the operation is otherwise successful, the IPP object returns the
+ 'successful-ok-ignored-or-substituted-attributes' status code.
+ Ignoring unsupported Operation attributes in all operations is
+ analogous to the handling of unsupported Job Template attributes in
+ the create and Validate-Job operations when the client supplies the
+ "ipp-attribute-fidelity" Operation attribute with the 'false' value.
+ This last rule is so that we can add OPTIONAL Operation attributes to
+ future versions of IPP so that older clients can inter-work with new
+
+
+
+Hastings, et al. Informational [Page 35]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ IPP objects and newer clients can inter-work with older IPP objects.
+ (If the new attribute cannot be ignored without performing
+ unexpectedly, the major version number would have been increased in
+ the protocol document and in the request). This rule for Operation
+ attributes is independent of the value of the "ipp-attribute-
+ fidelity" attribute. For example, if an IPP object doesn't support
+ the OPTIONAL "job-k-octets" attribute', the IPP object treats "job-
+ k-octets" as an unknown attribute and only checks the length for the
+ 'integer' attribute syntax supplied by the client. If it is not four
+ octets, the IPP object REJECTS the request and RETURNS the 'client-
+ error-bad-request' status code, else the IPP object copies the
+ attribute to the Unsupported Attribute response group, setting the
+ value to the "out-of-band" 'unsupported' value, but otherwise ignores
+ the attribute.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 36]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+3.1.2.2 Suggested Additional Processing Steps for Operations that
+ Create/Validate Jobs and Add Documents
+
+ This section in combination with the previous section recommends the
+ processing steps for the Print-Job, Validate-Job, Print-URI, Create-
+ Job, Send-Document, and Send-URI operations that IPP objects SHOULD
+ use. These are the operations that create jobs, validate a Print-Job
+ request, and add documents to a job.
+
+ IIG Sect # Flow IPP error status codes
+ ---------- ---- ----------------------
+ |
+ v No
+ 3.1.2.2.1 <ipp-attribute-fidelity> ------------------+
+ <supplied?> |
+ Yes| |
+ | ipp-attribute-fidelity = no |
+ |<------------------------------+
+ v No
+ 3.1.2.2.2 <Printer is> --> server-error-not-accepting-jobs
+ <accepting jobs?>
+ Yes|
+ v err
+ 3.1.2.3 <Validate values of> --> client-error-bad-request
+ <Job template attributes> client-error-request-value-too-
+ long
+ <(length, tag, range,>
+ <multi-value)>
+ ok|
+ v err
+ 3.1.2.3 <Validate values with> --> client-error-bad-request
+ <supported values> client-error-attributes-or-
+ | values-not-supported
+ v err
+ 3.1.2.3.1 <Any conflicting> --> client-error-conflicting-
+ attributes
+ <Job Template attr values> client-error-attributes-or-
+ values-not-supported
+ v
+
+3.1.2.2.1 Default "ipp-attribute-fidelity" if not supplied
+
+ The Printer object checks to see if the client supplied an "ipp-
+ attribute-fidelity" Operation attribute. If the attribute is not
+ supplied by the client, the IPP object assumes that the value is
+ 'false'.
+
+
+
+
+
+Hastings, et al. Informational [Page 37]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+3.1.2.2.2 Check that the Printer object is accepting jobs
+
+ If the value of the Printer objects "printer-is-accepting-jobs" is
+ 'false', the Printer object REJECTS the request and RETURNS the
+ 'server-error-not-accepting-jobs' status code.
+
+3.1.2.2.3 Validate the values of the Job Template attributes
+
+ An IPP object validates the values of all Job Template attribute
+ supplied by the client. The IPP object performs the analogous
+ syntactic validation checks of each Job Template attribute value that
+ it performs for Operation attributes (see Section 3.1.2.1.5.):
+
+ a) that the length of each value is correct for the attribute
+ syntax tag supplied by the client according to [RFC2911]
+ Section 4.1.
+
+ b) that the attribute syntax tag is correct for that attribute
+ according to [RFC2911] Sections 4.2 to 4.4.
+
+ c) that multiple values are supplied only for multi-valued
+ attributes, i.e., that are 1setOf X according to [RFC2911]
+ Sections 4.2 to 4.4.
+
+ As in Section 3.1.2.1.5, if any of these syntactic checks fail, the
+ IPP object REJECTS the request and RETURNS the 'client-error-bad-
+ request' or 'client-error-request-value-too-long' status code as
+ appropriate, independent of the value of the "ipp-attribute-
+ fidelity". Since such an error is most likely to be an error
+ detected by a client developer, rather than by an end-user, the IPP
+ object NEED NOT return an indication of which attribute had the error
+ in either the Unsupported Attributes Group or the Status Message.
+ The description for each of these syntactic checks is explicitly
+ expressed in the first IF statement in the following table.
+
+ Each Job Template attribute MUST occur no more than once. If an IPP
+ Printer receives a create request with multiple occurrences of a Job
+ Template attribute, it MAY:
+
+ 1. reject the operation and return the 'client-error-bad-request'
+ error status code
+
+ 2. accept the operation and use the first occurrence of the
+ attribute
+
+ 3. accept the operation and use the last occurrence of the
+ attribute
+
+
+
+
+Hastings, et al. Informational [Page 38]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ depending on implementation. Therefore, clients MUST NOT supply
+ multiple occurrences of the same Job Template attribute in the Job
+ Attributes group in the request.
+
+3.1.2.3 Algorithm for job validation
+
+ The process of validating a Job-Template attribute "xxx" against a
+ Printer attribute "xxx-supported" can use the following validation
+ algorithm (see section 3.2.1.2 in [RFC2911]).
+
+ To validate the value U of Job-Template attribute "xxx" against the
+ value V of Printer "xxx-supported", perform the following algorithm:
+
+ 1. If U is multi-valued, validate each value X of U by performing the
+ algorithm in Table 7 with each value X. Each validation is
+ separate from the standpoint of returning unsupported values.
+ Example: If U is "finishings" that the client supplies with
+ 'staple', 'bind' values, then X takes on the successive values:
+ 'staple', then 'bind'
+
+ 2. If V is multi-valued, validate X against each Z of V by performing
+ the algorithm in Table 7 with each value Z. If a value Z
+ validates, the validation for the attribute value X succeeds. If
+ it fails, the algorithm is applied to the next value Z of V. If
+ there are no more values Z of V, validation fails. Example" If V
+ is "sides-supported" with values: 'one- sided', 'two-sided-long',
+ and 'two-sided-short', then Z takes on the successive values:
+ 'one-sided', 'two-sided-long', and 'two-sided-short'. If the
+ client supplies "sides" with 'two-sided- long', the first
+ comparison fails ('one-sided' is not equal to 'two-sided-long'),
+ the second comparison succeeds ('two-sided-long' is equal to
+ 'two-sided-long"), and the third comparison ('two-sided-short'
+ with 'two-sided-long') is not even performed.
+
+ 3. If both U and V are single-valued, let X be U and Z be V and use
+ the validation rules in Table 7.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 39]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Table 7 - Rules for validating single values X against Z
+
+ Attribute syntax attribute syntax validated if:
+ of X of Z
+
+ integer rangeOfInteger X is within the range of Z
+
+ uri uriScheme the uri scheme in X is equal to
+ Z
+
+ any boolean the value of Z is TRUE
+
+ any any X and Z are of the same type
+ and are equal.
+
+ If the value of the Printer object's "xxx-supported" attribute is
+ 'no-value' (because the system administrator hasn't configured a
+ value), the check always fails. If the check fails, the IPP object
+ copies the attribute to the Unsupported Attributes response group
+ with its unsupported value. If the attribute contains more than one
+ value, each value is checked and each unsupported value is separately
+ copied, while supported values are not copied. If an IPP object
+ doesn't recognize/support a Job Template attribute, i.e., there is no
+ corresponding Printer object "xxx-supported" attribute, the IPP
+ object treats the attribute as an unknown or unsupported attribute
+ (see the last row in the table below).
+
+ If some Job Template attributes are supported for some document
+ formats and not for others or the values are different for different
+ document formats, the IPP object SHOULD take that into account in
+ this validation using the value of the "document-format" supplied by
+ the client (or defaulted to the value of the Printer's "document-
+ format-default" attribute, if not supplied by the client). For
+ example, if "number-up" is supported for the 'text/plain' document
+ format, but not for the 'application/postscript' document format, the
+ check SHOULD (though it NEED NOT) depend on the value of the
+ "document-format" operation attribute. See "document-format" in
+ [RFC2911] section 3.2.1.1 and 3.2.5.1.
+
+ Note: whether the request is accepted or rejected is determined by
+ the value of the "ipp-attribute-fidelity" attribute in a subsequent
+ step, so that all Job Template attribute supplied are examined and
+ all unsupported attributes and/or values are copied to the
+ Unsupported Attributes response group.
+
+ -----------------------------------------------
+
+
+
+
+
+Hastings, et al. Informational [Page 40]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ job-priority (integer(1:100))
+
+ IF NOT a single 'integer' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+
+ IF NOT supplied by the client, use the value of the Printer
+ object's "job-priority-default" attribute at job submission time.
+
+ IF NOT in the range 1 to 100, inclusive, copy the attribute and
+ the unsupported value to the Unsupported Attributes response
+ group.
+
+ Map the value to the nearest supported value in the range 1:100 as
+ specified by the number of discrete values indicated by the value
+ of the Printer's "job-priority-supported" attribute. See the
+ formula in [RFC2911] Section 4.2.1.
+
+ job-hold-until (type3 keyword | name)
+
+ IF NOT a single 'keyword' or 'name' value, REJECT/RETURN 'client-
+ error-bad-request'.
+
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ IF NOT supplied by the client, use the value of the Printer
+ object's "job-hold-until" attribute at job submission time.
+
+ IF NOT in the Printer object's "job-hold-until-supported"
+ attribute, copy the attribute and the unsupported value to the
+ Unsupported Attributes response group.
+
+ job-sheets (type3 keyword | name)
+
+ IF NOT a single 'keyword' or 'name' value, REJECT/RETURN 'client-
+ error-bad-request'.
+
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ IF NOT in the Printer object's "job-sheets-supported" attribute,
+ copy the attribute and the unsupported value to the Unsupported
+ Attributes response group.
+
+ multiple-document-handling (type2 keyword)
+
+ IF NOT a single 'keyword' value, REJECT/RETURN 'client-error-bad-
+ request'.
+
+
+
+Hastings, et al. Informational [Page 41]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ IF NOT in the Printer object's "multiple-document-handling-
+ supported" attribute, copy the attribute and the unsupported value
+ to the Unsupported Attributes response group.
+
+ copies (integer(1:MAX))
+
+ IF NOT a single 'integer' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+
+ IF NOT in range of the Printer object's "copies-supported"
+ attribute
+
+ copy the attribute and the unsupported value to the Unsupported
+ Attributes response group.
+
+ finishings (1setOf type2 enum)
+
+ IF NOT an 'enum' value(s) each with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+
+ IF NOT in the Printer object's "finishings-supported" attribute,
+ copy the attribute and the unsupported value(s), but not any
+ supported values, to the Unsupported Attributes response group.
+
+ page-ranges (1setOf rangeOfInteger(1:MAX))
+
+ IF NOT a 'rangeOfInteger' value(s) each with a length equal to 8
+ octets, REJECT/RETURN 'client-error-bad-request'.
+
+ IF first value is greater than second value in any range, the
+ ranges are not in ascending order, or ranges overlap,
+ REJECT/RETURN 'client-error-bad-request'.
+
+ IF the value of the Printer object's "page-ranges-supported"
+ attribute is 'false', copy the attribute to the Unsupported
+ Attributes response group and set the value to the "out-of-band"
+ 'unsupported' value.
+
+ sides (type2 keyword)
+
+ IF NOT a single 'keyword' value, REJECT/RETURN 'client-error-bad-
+ request'.
+
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+
+
+Hastings, et al. Informational [Page 42]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ IF NOT in the Printer object's "sides-supported" attribute, copy
+ the attribute and the unsupported value to the Unsupported
+ Attributes response group.
+
+ number-up (integer(1:MAX))
+
+ IF NOT a single 'integer' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+
+ IF NOT a value or in the range of one of the values of the Printer
+ object's "number-up-supported" attribute, copy the attribute and
+ value to the Unsupported Attribute response group.
+
+ orientation-requested (type2 enum)
+
+ IF NOT a single 'enum' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+
+ IF NOT in the Printer object's "orientation-requested-supported"
+ attribute, copy the attribute and the unsupported value to the
+ Unsupported Attributes response group.
+
+ media (type3 keyword | name)
+
+ IF NOT a single 'keyword' or 'name' value, REJECT/RETURN 'client-
+ error-bad-request'.
+
+ IF the value length is greater than 255 octets, REJECT/RETURN
+ 'client-error-request-value-too-long'.
+
+ IF NOT in the Printer object's "media-supported" attribute, copy
+ the attribute and the unsupported value to the Unsupported
+ Attributes response group.
+
+ printer-resolution (resolution)
+
+ IF NOT a single 'resolution' value with a length equal to 9
+ octets, REJECT/RETURN 'client-error-bad-request'.
+
+ IF NOT in the Printer object's "printer-resolution-supported"
+ attribute, copy the attribute and the unsupported value to the
+ Unsupported Attributes response group.
+
+ print-quality (type2 enum)
+
+ IF NOT a single 'enum' value with a length equal to 4 octets,
+ REJECT/RETURN 'client-error-bad-request'.
+
+
+
+
+Hastings, et al. Informational [Page 43]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ IF NOT in the Printer object's "print-quality-supported"
+ attribute, copy the attribute and the unsupported value to the
+ Unsupported Attributes response group.
+
+ unknown or unsupported attribute (i.e., there is no corresponding
+ Printer object "xxx-supported" attribute)
+
+ IF the attribute syntax supplied by the client is supported but
+ the length is not legal for that attribute syntax,
+
+ REJECT/RETURN 'client-error-bad-request' if the length of the
+ attribute syntax is fixed or 'client-error-request-value-too-long'
+ if the length of the attribute syntax is variable.
+
+ ELSE copy the attribute and value to the Unsupported Attributes
+ response group and change the attribute value to the "out-of-band"
+ 'unsupported' value. Any remaining Job Template Attributes are
+ either unknown or unsupported Job Template attributes and are
+ validated algorithmically according to their attribute syntax for
+ proper length (see below).
+
+ -----------------------------------------------
+
+ If the attribute syntax is supported AND the length check fails,
+ the IPP object REJECTS the request and RETURNS the 'client-error-
+ bad-request' if the length of the attribute syntax is fixed or the
+ 'client-error-request-value-too-long' status code if the length of
+ the attribute syntax is variable. Otherwise, the IPP object copies
+ the unsupported Job Template attribute to the Unsupported
+ Attributes response group and changes the attribute value to the
+ "out-of-band" 'unsupported' value. The following table shows the
+ length checks for all attribute syntaxes. In the following table:
+ "<=" means less than or equal, "=" means equal to:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 44]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Name Octet length check for read-write attributes
+ ---------- ---------------------------------------------
+
+ 'textWithLanguage <= 1023 AND 'naturalLanguage' <= 63
+ 'textWithoutLanguage' <= 1023
+ 'nameWithLanguage' <= 255 AND 'naturalLanguage' <= 63
+ 'nameWithoutLanguage' <= 255
+ 'keyword' <= 255
+ 'enum' = 4
+ 'uri' <= 1023
+ 'uriScheme' <= 63
+ 'charset' <= 63
+ 'naturalLanguage' <= 63
+ 'mimeMediaType' <= 255
+ 'octetString' <= 1023
+ 'boolean' = 1
+ 'integer' = 4
+ 'rangeOfInteger' = 8
+ 'dateTime' = 11
+ 'resolution' = 9
+ '1setOf X'
+
+ Note: It's possible for a Printer to receive a zero length keyword
+ in a request. Since this is a keyword, its value needs to be
+ compared with the supported values. Assuming that the printer
+ doesn't have any values in its corresponding "xxx-supported"
+ attribute that are keywords of zero length, the comparison will fail.
+ Then the request will be accepted or rejected depending on the value
+ of "ipp-attributes-fidelity" being 'false' or 'true', respectively.
+ No special handling is required for
+
+3.1.2.3.1 Check for conflicting Job Template attributes values
+
+ Once all the Operation and Job Template attributes have been checked
+ individually, the Printer object SHOULD check for any conflicting
+ values among all the supported values supplied by the client. For
+ example, a Printer object might be able to staple and to print on
+ transparencies, however due to physical stapling constraints, the
+ Printer object might not be able to staple transparencies. The IPP
+ object copies the supported attributes and their conflicting
+ attribute values to the Unsupported Attributes response group. The
+ Printer object only copies over those attributes that the Printer
+ object either ignores or substitutes in order to resolve the
+ conflict, and it returns the original values which were supplied by
+ the client. For example suppose the client supplies "finishings"
+ equals 'staple' and "media" equals 'transparency', but the Printer
+ object does not support stapling transparencies. If the Printer
+ chooses to ignore the stapling request in order to resolve the
+
+
+
+Hastings, et al. Informational [Page 45]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ conflict, the Printer objects returns "finishings" equal to 'staple'
+ in the Unsupported Attributes response group. If any attributes are
+ multi-valued, only the conflicting values of the attributes are
+ copied.
+
+ Note: The decisions made to resolve the conflict (if there is a
+ choice) is implementation dependent.
+
+3.1.2.3.2 Decide whether to REJECT the request
+
+ If there were any unsupported Job Template attributes or
+ unsupported/conflicting Job Template attribute values and the client
+ supplied the "ipp-attribute-fidelity" attribute with the 'true'
+ value, the Printer object REJECTS the request and return the status
+ code:
+
+ 1.'client-error-conflicting-attributes' status code, if there were
+ any conflicts between attributes supplied by the client.
+
+ 2.'client-error-attributes-or-values-not-supported' status code,
+ otherwise.
+
+ Note: Unsupported Operation attributes or values that are returned
+ do not affect the status returned in this step. If the unsupported
+ Operation attribute was a serious error, the above already rejected
+ the request in a previous step. If control gets to this step with
+ unsupported Operation attributes being returned, they are not serious
+ errors.
+
+ In general, the final results of Job processing are unknown at Job
+ submission time. The client has to rely on notifications or polling
+ to find out what happens at Job processing time. However, there are
+ cases in which some Printers can determine at Job submission time
+ that Job processing is going to fail. As an optimization, we'd like
+ to have the Printer reject the Job in these cases.
+
+ There are three types of "processing" errors that might be detectable
+ at Job submission time:
+
+ 1. 'client-error-document-format-not-supported' : For the Print-
+ Job, Send-Document, Print-URI, and Send-URI operations, if all these
+ conditions are true:
+
+ - the Printer supports auto-sensing,
+ - the request "document-format" operation attribute is
+ 'application/octet-stream',
+ - the Printer receives document data before responding,
+ - the Printer auto-senses the document format before responding,
+
+
+
+Hastings, et al. Informational [Page 46]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ - the sensed document format is not supported by the Printer
+
+ then the Printer should respond with 'client-error-document-format-
+ not-supported' status.
+
+ 2. 'client-error-compression-error': For the Print-Job, Send-
+ Document, Print-URI, and Send-URI operations, if all these
+ conditions are true:
+
+ - the client supplies a supported value for the "compression"
+ operation attribute in the request
+ - the Printer receives document data before responding,
+ - the Printer attempts to decompress the document data before
+ responding,
+ - the document data cannot be decompressed using the algorithm
+ specified by the "compression" operation attribute
+
+ then the Printer should respond with 'client-error-compression-error'
+ status.
+
+ 3. 'client-error-document-access-error': For the Print-URI, and
+ Send-URI operations, if the Printer attempts and fails to pull the
+ referenced document data before responding, it should respond with
+ 'client-error-document-access-error' status.
+
+ Some Printers are not able to detect these errors until Job
+ processing time. In that case, the errors are recorded in the
+ corresponding job-state and job-state reason attributes. (There is
+ no standard way for a client to determine whether a Printer can
+ detect these errors at Job submission time.) For example, if auto-
+ sensing happens AFTER the job is accepted (as opposed to auto-sensing
+ at submit time before returning the response), the implementation
+ aborts the job, puts the job in the 'aborted' state and sets the
+ 'unsupported-document-format' value in the job's "job-state-reasons".
+
+ A client should always provide a valid "document-format" operation
+ attribute whenever practical. In the absence of other information, a
+ client itself may sniff the document data to determine document
+ format.
+
+ Auto sensing at Job submission time may be more difficult for the
+ Printer when combined with compression. For auto-sensed Jobs, a
+ client may be better off deferring compression to the transfer
+ protocol layer, e.g.; by using the HTTP Content-Encoding header.
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 47]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+3.1.2.3.3 For the Validate-Job operation, RETURN one of the success
+ status codes
+
+ If the requested operation is the Validate-Job operation, the Printer
+ object returns:
+
+ 1. the "successful-ok" status code, if there are no unsupported or
+ conflicting Job Template attributes or values.
+ 2. the "successful-ok-conflicting-attributes, if there are any
+ conflicting Job Template attribute or values.
+ 3. the "successful-ok-ignored-or-substituted-attributes, if there
+ are only unsupported Job Template attributes or values.
+
+ Note: Unsupported Operation attributes or values that are returned
+ do not affect the status returned in this step. If the unsupported
+ Operation attribute was a serious error, the above already rejected
+ the request in a previous step. If control gets to this step with
+ unsupported Operation attributes being returned, they are not serious
+ errors.
+
+3.1.2.3.4 Create the Job object with attributes to support
+
+ If "ipp-attribute-fidelity" is set to 'false' (or it was not supplied
+ by the client), the Printer object:
+
+ 1. creates a Job object, assigns a unique value to the job's
+ "job-uri" and "job-id" attributes, and initializes all of the
+ job's other supported Job Description attributes.
+ 2. removes all unsupported attributes from the Job object.
+ 3. for each unsupported value, removes either the unsupported
+ value or substitutes the unsupported attribute value with some
+ supported value. If an attribute has no values after removing
+ unsupported values from it, the attribute is removed from the
+ Job object (so that the normal default behavior at job
+ processing time will take place for that attribute).
+ 4. for each conflicting value, removes either the conflicting
+ value or substitutes the conflicting attribute value with some
+ other supported value. If an attribute has no values after
+ removing conflicting values from it, the attribute is removed
+ from the Job object (so that the normal default behavior at job
+ processing time will take place for that attribute).
+
+ If there were no attributes or values flagged as unsupported, or the
+ value of 'ipp-attribute-fidelity" was 'false', the Printer object is
+ able to accept the create request and create a new Job object. If
+ the "ipp-attribute-fidelity" attribute is set to 'true', the Job
+ Template attributes that populate the new Job object are necessarily
+ all the Job Template attributes supplied in the create request. If
+
+
+
+Hastings, et al. Informational [Page 48]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ the "ipp-attribute-fidelity" attribute is set to 'false', the Job
+ Template attributes that populate the new Job object are all the
+ client supplied Job Template attributes that are supported or that
+ have value substitution. Thus, some of the requested Job Template
+ attributes will not appear in the Job object because the Printer
+ object did not support those attributes. The attributes that
+ populate the Job object are persistently stored with the Job object
+ for that Job. A Get-Job-Attributes operation on that Job object will
+ return only those attributes that are persistently stored with the
+ Job object.
+
+ Note: All Job Template attributes that are persistently stored with
+ the Job object are intended to be "override values"; that is, they
+ that take precedence over whatever other embedded instructions might
+ be in the document data itself. However, it is not possible for all
+ Printer objects to realize the semantics of "override". End users
+ may query the Printer's "pdl-override-supported" attribute to
+ determine if the Printer either attempts or does not attempt to
+ override document data instructions with IPP attributes.
+
+ There are some cases, where a Printer supports a Job Template
+ attribute and has an associated default value set for that attribute.
+ In the case where a client does not supply the corresponding
+ attribute, the Printer does not use its default values to populate
+ Job attributes when creating the new Job object; only Job Template
+ attributes actually in the create request are used to populate the
+ Job object. The Printer's default values are only used later at Job
+ processing time if no other IPP attribute or instruction embedded in
+ the document data is present.
+
+ Note: If the default values associated with Job Template attributes
+ that the client did not supply were to be used to populate the Job
+ object, then these values would become "override values" rather than
+ defaults. If the Printer supports the 'attempted' value of the
+ "pdl-override-supported" attribute, then these override values could
+ replace values specified within the document data. This is not the
+ intent of the default value mechanism. A default value for an
+ attribute is used only if the create request did not specify that
+ attribute (or it was ignored when allowed by "ipp-attribute-fidelity"
+ being 'false') and no value was provided within the content of the
+ document data.
+
+ If the client does not supply a value for some Job Template
+ attribute, and the Printer does not support that attribute, as far as
+ IPP is concerned, the result of processing that Job (with respect to
+ the missing attribute) is undefined.
+
+
+
+
+
+Hastings, et al. Informational [Page 49]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+3.1.2.3.5 Return one of the success status codes
+
+ Once the Job object has been created, the Printer object accepts the
+ request and returns to the client:
+
+ 1. the 'successful-ok' status code, if there are no unsupported or
+ conflicting Job Template attributes or values.
+ 2. the 'successful-ok-conflicting-attributes' status code, if
+ there are any conflicting Job Template attribute or values.
+ 3. the 'successful-ok-ignored-or-substituted-attributes' status
+ code, if there are only unsupported Job Template attributes or
+ values.
+
+ Note: Unsupported Operation attributes or values that are returned
+ do not affect the status returned in this step. If the unsupported
+ Operation attribute was a serious error, the above already rejected
+ the request in a previous step. If control gets to this step with
+ unsupported Operation attributes being returned, they are not serious
+ errors.
+
+ The Printer object also returns Job status attributes that indicate
+ the initial state of the Job ('pending', 'pending-held',
+ 'processing', etc.), etc. See Print-Job Response, [RFC2911] section
+ 3.2.1.2.
+
+3.1.2.3.6 Accept appended Document Content
+
+ The Printer object accepts the appended Document Content data and
+ either starts it printing, or spools it for later processing.
+
+3.1.2.3.7 Scheduling and Starting to Process the Job
+
+ The Printer object uses its own configuration and implementation
+ specific algorithms for scheduling the Job in the correct processing
+ order. Once the Printer object begins processing the Job, the
+ Printer changes the Job's state to 'processing'. If the Printer
+ object supports PDL override (the "pdl-override-supported" attribute
+ set to 'attempted'), the implementation does its best to see that IPP
+ attributes take precedence over embedded instructions in the document
+ data.
+
+3.1.2.3.8 Completing the Job
+
+ The Printer object continues to process the Job until it can move the
+ Job into the 'completed' state. If an Cancel-Job operation is
+ received, the implementation eventually moves the Job into the
+ 'canceled' state. If the system encounters errors during processing
+ that do not allow it to progress the Job into a completed state, the
+
+
+
+Hastings, et al. Informational [Page 50]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ implementation halts all processing, cleans up any resources, and
+ moves the Job into the 'aborted' state.
+
+3.1.2.3.9 Destroying the Job after completion
+
+ Once the Job moves to the 'completed', 'aborted', or 'canceled'
+ state, it is an implementation decision as to when to destroy the Job
+ object and release all associated resources. Once the Job has been
+ destroyed, the Printer would return either the "client-error-not-
+ found" or "client-error-gone" status codes for operations directed at
+ that Job.
+
+ Note: the Printer object SHOULD NOT re-use a "job-uri" or "job-id"
+ value for a sufficiently long time after a job has been destroyed, so
+ that stale references kept by clients are less likely to access the
+ wrong (newer) job.
+
+3.1.2.3.10 Interaction with "ipp-attribute-fidelity"
+
+ Some Printer object implementations may support "ipp-attribute-
+ fidelity" set to 'true' and "pdl-override-supported" set to
+ 'attempted' and yet still not be able to realize exactly what the
+ client specifies in the create request. This is due to legacy
+ decisions and assumptions that have been made about the role of job
+ instructions embedded within the document data and external job
+ instructions that accompany the document data and how to handle
+ conflicts between such instructions. The inability to be 100%
+ precise about how a given implementation will behave is also
+ compounded by the fact that the two special attributes, "ipp-
+ attribute-fidelity" and "pdl-"override-supported", apply to the whole
+ job rather than specific values for each attribute. For example, some
+ implementations may be able to override almost all Job Template
+ attributes except for "number-up". Character Sets, natural
+ languages, and internationalization
+
+ This section discusses character set support, natural language
+ support and internationalization.
+
+3.1.2.3.11 Character set code conversion support
+
+ IPP clients and IPP objects are REQUIRED to support UTF-8. They MAY
+ support additional charsets. It is RECOMMENDED that an IPP object
+ also support US-ASCII, since many clients support US-ASCII, and
+ indicate that UTF-8 and US-ASCII are supported by populating the
+ Printer's "charset-supported" with 'utf-8' and 'us-ascii' values. An
+ IPP object is required to code covert with as little loss as possible
+ between the charsets that it supports, as indicated in the Printer's
+ "charsets-supported" attribute.
+
+
+
+Hastings, et al. Informational [Page 51]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ How should the server handle the situation where the "attributes-
+ charset" of the response itself is "us-ascii", but one or more
+ attributes in that response is in the "utf-8" format?
+
+ Example: Consider a case where a client sends a Print-Job request
+ with "utf-8" as the value of "attributes-charset" and with the "job-
+ name" attribute supplied. Later another client submits a Get-Job-
+ Attribute or Get-Jobs request. This second request contains the
+ "attributes-charset" with value "us-ascii" and "requested-attributes"
+ attribute with exactly one value "job-name".
+
+ According to the RFC2911 document (section 3.1.4.2), the value of the
+ "attributes-charset" for the response of the second request must be
+ "us-ascii" since that is the charset specified in the request. The
+ "job-name" value, however, is in "utf-8" format. Should the request
+ be rejected even though both "utf-8" and "us-ascii" charsets are
+ supported by the server? or should the "job-name" value be converted
+ to "us-ascii" and return "successful-ok-conflicting-attributes"
+ (0x0002) as the status code?
+
+ Answer: An IPP object that supports both utf-8 (REQUIRED) and us-
+ ascii, the second paragraph of section 3.1.4.2 applies so that the
+ IPP object MUST accept the request, perform code set conversion
+ between these two charsets with "the highest fidelity possible" and
+ return 'successful-ok', rather than a warning 'successful-ok-
+ conflicting-attributes, or an error. The printer will do the best it
+ can to convert between each of the character sets that it supports --
+ even if that means providing a string of question marks because none
+ of the characters are representable in US ASCII. If it can't perform
+ such conversion, it MUST NOT advertise us-ascii as a value of its
+ "attributes-charset-supported" and MUST reject any request that
+ requests 'us-ascii'.
+
+ One IPP object implementation strategy is to convert all request text
+ and name values to a Unicode internal representation. This is 16-bit
+ and virtually universal. Then convert to the specified operation
+ attributes-charset on output.
+
+ Also it would be smarter for a client to ask for 'utf-8', rather than
+ 'us-ascii' and throw away characters that it doesn't understand,
+ rather than depending on the code conversion of the IPP object.
+
+3.1.2.3.12 What charset to return when an unsupported charset is
+ requested (Issue 1.19)?
+
+ Section 3.1.4.1 Request Operation attributes was clarified in
+ November 1998 as follows:
+
+
+
+
+Hastings, et al. Informational [Page 52]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ All clients and IPP objects MUST support the 'utf-8' charset
+ [RFC2044] and MAY support additional charsets provided that they are
+ registered with IANA [IANA-CS]. If the Printer object does not
+ support the client supplied charset value, the Printer object MUST
+ reject the request, set the "attributes-charset" to 'utf-8' in the
+ response, and return the 'client-error-charset-not-supported' status
+ code and any 'text' or 'name' attributes using the 'utf-8' charset.
+
+ Since the client and IPP object MUST support UTF-8, returning any
+ text or name attributes in UTF-8 when the client requests a charset
+ that is not supported should allow the client to display the text or
+ name.
+
+ Since such an error is a client error, rather than a user error, the
+ client should check the status code first so that it can avoid
+ displaying any other returned 'text' and 'name' attributes that are
+ not in the charset requested.
+
+ Furthermore, [RFC2911] section 14.1.4.14 client-error-charset-not-
+ supported (0x040D) was clarified in November 1998 as follows:
+
+ For any operation, if the IPP Printer does not support the charset
+ supplied by the client in the "attributes-charset" operation
+ attribute, the Printer MUST reject the operation and return this
+ status and any 'text' or 'name' attributes using the 'utf-8' charset
+ (see Section 3.1.4.1).
+
+3.1.2.3.13 Natural Language Override (NLO)
+
+ The 'text' and 'name' attributes each have two forms. One has an
+ implicit natural language, and the other has an explicit natural
+ language. The 'textWithoutLanguage' and 'textWithLanguage' are the
+ two 'text' forms. The 'nameWithoutLanguage" and 'nameWithLanguage
+ are the two 'name' forms. If a receiver (IPP object or IPP client)
+ supports an attribute with attribute syntax 'text', it MUST support
+ both forms in a request and a response. A sender (IPP client or IPP
+ object) MAY send either form for any such attribute. When a sender
+ sends a WithoutLanguage form, the implicit natural language is
+ specified in the "attributes-natural-language" operation attribute,
+ which all senders MUST include in every request and response.
+
+ When a sender sends a WithLanguage form, it MAY be different from the
+ implicit natural language supplied by the sender or it MAY be the
+ same. The receiver MUST treat either form equivalently.
+
+ There is an implementation decision for senders, whether to always
+ send the WithLanguage forms or use the WithoutLanguage form when the
+ attribute's natural language is the same as the request or response.
+
+
+
+Hastings, et al. Informational [Page 53]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ The former approach makes the sender implementation simpler. The
+ latter approach is more efficient on the wire and allows inter-
+ working with non-conforming receivers that fail to support the
+ WithLanguage forms. As each approach have advantages, the choice is
+ completely up to the implementer of the sender.
+
+ Furthermore, when a client receives a 'text' or 'name' job attribute
+ that it had previously supplied, that client MUST NOT expect to see
+ the attribute in the same form, i.e., in the same WithoutLanguage or
+ WithLanguage form as the client supplied when it created the job.
+ The IPP object is free to transform the attribute from the
+ WithLanguage form to the WithoutLanguage form and vice versa, as long
+ as the natural language is preserved. However, in order to meet this
+ latter requirement, it is usually simpler for the IPP object
+ implementation to store the natural language explicitly with the
+ attribute value, i.e., to store using an internal representation that
+ resembles the WithLanguage form.
+
+ The IPP Printer MUST copy the natural language of a job, i.e., the
+ value of the "attributes-natural-language" operation attribute
+ supplied by the client in the create operation, to the Job object as
+ a Job Description attribute, so that a client is able to query it.
+ In returning a Get-Job-Attributes response, the IPP object MAY return
+ one of three natural language values in the responses "attributes-
+ natural-language" operation attribute: (1) that requested by the
+ requester, (2) the natural language of the job, or (3) the configured
+ natural language of the IPP Printer, if the requested language is not
+ supported by the IPP Printer.
+
+ This "attributes-natural-language" Job Description attribute is
+ useful for an IPP object implementation that prints start sheets in
+ the language of the user who submitted the job. This same Job
+ Description attribute is useful to a multi-lingual operator who has
+ to communicate with different job submitters in different natural
+ languages. This same Job Description attribute is expected to be
+ used in the future to generate notification messages in the natural
+ language of the job submitter.
+
+ Early drafts of [RFC2911] contained a job-level natural language
+ override (NLO) for the Get-Jobs response. A job-level (NLO) is an
+ (unrequested) Job Attribute which then specified the implicit natural
+ language for any other WithoutLanguage job attributes returned in the
+ response for that job. Interoperability testing of early
+ implementations showed that no one was implementing the job-level NLO
+ in Get-Job responses. So the job-level NLO was eliminated from the
+ Get-Jobs response. This simplification makes all requests and
+ responses consistent in that the implicit natural language for any
+
+
+
+
+Hastings, et al. Informational [Page 54]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ WithoutLanguage 'text' or 'name' form is always supplied in the
+ request's or response's "attributes-natural-language" operation
+ attribute.
+
+3.1.3 Status codes returned by operation
+
+ This section corresponds to [RFC2911] section 3.1.6 "Operation
+ Response Status Codes and Status Messages". This section lists all
+ status codes once in the first operation (Print-Job). Then it lists
+ the status codes that are different or specialized for subsequent
+ operations under each operation.
+
+3.1.3.1 Printer Operations
+
+3.1.3.1.1 Print-Job
+
+ The Printer object MUST return one of the following "status-code"
+ values for the indicated reason. Whether all of the document data
+ has been accepted or not before returning the success or error
+ response depends on implementation. See Section 13 in [RFC2911] for
+ a more complete description of each status code.
+
+ For the following success status codes, the Job object has been
+ created and the "job-id", and "job-uri" assigned and returned in the
+ response:
+
+ successful-ok: no request attributes were substituted or ignored.
+
+ successful-ok-ignored-or-substituted-attributes: some supplied
+ (1) attributes were ignored or (2) unsupported attribute syntaxes
+ or values were substituted with supported values or were ignored.
+ Unsupported attributes, attribute syntax's, or values MUST be
+ returned in the Unsupported Attributes group of the response.
+
+ successful-ok-conflicting-attributes: some supplied attribute
+ values conflicted with the values of other supplied attributes and
+ were either substituted or ignored. Attributes or values which
+ conflict with other attributes and have been substituted or
+ ignored MUST be returned in the Unsupported Attributes group of
+ the response as supplied by the client.
+
+ [RFC2911] section 3.1.6 Operation Status Codes and Messages states:
+
+ If the Printer object supports the "status-message" operation
+ attribute, it SHOULD use the REQUIRED 'utf-8' charset to return a
+ status message for the following error status codes (see section
+ 13 in [RFC2911]): 'client-error-bad-request', 'client-error-
+ charset-not-supported', 'server-error-internal-error', 'server-
+
+
+
+Hastings, et al. Informational [Page 55]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ error-operation-not-supported', and 'server-error-version-not-
+ supported'. In this case, it MUST set the value of the
+ "attributes-charset" operation attribute to 'utf-8' in the error
+ response.
+
+ For the following error status codes, no job is created and no
+ "job-id" or "job-uri" is returned:
+
+ client-error-bad-request: The request syntax does not conform
+ to the specification.
+
+ client-error-forbidden: The request is being refused for
+ authorization or authentication reasons. The implementation
+ security policy is to not reveal whether the failure is one of
+ authentication or authorization.
+
+ client-error-not-authenticated: Either the request requires
+ authentication information to be supplied or the authentication
+ information is not sufficient for authorization.
+
+ client-error-not-authorized: The requester is not authorized
+ to perform the request on the target object.
+
+ client-error-not-possible: The request cannot be carried out
+ because of the state of the system. See also 'server-error-
+ not-accepting-jobs' status code, which MUST take precedence if
+ the Printer object's "printer-accepting-jobs" attribute is
+ 'false'.
+
+ client-error-timeout: not applicable.
+
+ client-error-not-found: the target object does not exist.
+
+ client-error-gone: the target object no longer exists and no
+ forwarding address is known.
+
+ client-error-request-entity-too-large: the size of the request
+ and/or print data exceeds the capacity of the IPP Printer to
+ process it.
+
+ client-error-request-value-too-long: the size of request
+ variable length attribute values, such as 'text' and 'name'
+ attribute syntax's, exceed the maximum length specified in
+ [RFC2911] for the attribute and MUST be returned in the
+ Unsupported Attributes Group.
+
+
+
+
+
+
+Hastings, et al. Informational [Page 56]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ supplied is not supported. The "document-format" attribute
+ with the unsupported value MUST be returned in the Unsupported
+ Attributes Group. This error SHOULD take precedence over any
+ other 'xxx-not-supported' error, except 'client-error-charset-
+ not-supported'.
+
+ client-error-attributes-or-values-not-supported: one or more
+ supplied attributes, attribute syntax's, or values are not
+ supported and the client supplied the "ipp-attributes-
+ fidelity" operation attribute with a 'true' value. They MUST
+ be returned in the Unsupported Attributes Group as explained
+ below.
+
+ client-error-uri-scheme-not-supported: not applicable.
+
+ client-error-charset-not-supported: the charset supplied in
+ the "attributes-charset" operation attribute is not supported.
+ The Printer's "configured-charset" MUST be returned in the
+ response as the value of the "attributes-charset" operation
+ attribute and used for any 'text' and 'name' attributes
+ returned in the error response. This error SHOULD take
+ precedence over any other error, unless the request syntax is
+ so bad that the client's supplied "attributes-charset" cannot
+ be determined.
+
+ client-error-conflicting-attributes: one or more supplied
+ attribute values conflicted with each other and the client
+ supplied the "ipp-attributes-fidelity" operation attribute with
+ a 'true' value. They MUST be returned in the Unsupported
+ Attributes Group as explained below.
+
+ server-error-internal-error: an unexpected condition prevents
+ the request from being fulfilled.
+
+ server-error-operation-not-supported: not applicable (since
+ Print-Job is REQUIRED).
+
+ server-error-service-unavailable: the service is temporarily
+ overloaded.
+
+ server-error-version-not-supported: the version in the request
+ is not supported. The "closest" version number supported MUST
+ be returned in the response.
+
+ server-error-device-error: a device error occurred while
+ receiving or spooling the request or document data or the IPP
+ Printer object can only accept one job at a time.
+
+
+
+
+Hastings, et al. Informational [Page 57]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ server-error-temporary-error: a temporary error such as a
+ buffer full write error, a memory overflow, or a disk full
+ condition occurred while receiving the request and/or the
+ document data.
+
+ server-error-not-accepting-jobs: the Printer object's
+ "printer-is-not-accepting-jobs" attribute is 'false'.
+
+ server-error-busy: the Printer is too busy processing jobs to
+ accept another job at this time.
+
+ server-error-job-canceled: the job has been canceled by an
+ operator or the system while the client was transmitting the
+ document data.
+
+3.1.3.1.2 Print-URI
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to Print-URI with the following
+ specializations and differences. See Section 14 for a more complete
+ description of each status code.
+
+ client-error-uri-scheme-not-supported: the URI scheme supplied
+ in the "document-uri" operation attribute is not supported and
+ is returned in the Unsupported Attributes group.
+
+ server-error-operation-not-supported: the Print-URI operation
+ is not supported.
+
+3.1.3.1.3 Validate-Job
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to Validate-Job. See Section 13 in
+ [RFC2911] for a more complete description of each status code.
+
+3.1.3.1.4 Create-Job
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to Create-Job with the following
+ specializations and differences. See Section 13 in [RFC2911] for a
+ more complete description of each status code.
+
+ server-error-operation-not-supported: the Create-Job operation
+ is not supported.
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 58]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ client-error-multiple-document-jobs-not-supported: while the
+ Create-Job and Send-Document operations are supported, this
+ implementation doesn't support more than one document with
+ data.
+
+3.1.3.1.5 Get-Printer-Attributes
+
+ All of the Print-Job status codes described in Section
+ 3.1.3.1.1 Print-Job Response are applicable to the Get-
+ Printer-Attributes operation with the following
+ specialization's and differences. See Section 13 in [RFC2911]
+ for a more complete description of each status code.
+
+ For the following success status codes, the requested
+ attributes are returned in Group 3 in the response:
+
+ successful-ok: no operation attributes or values were
+ substituted or ignored (same as Print-Job) and no requested
+ attributes were unsupported.
+
+ successful-ok-ignored-or-substituted-attributes: The
+ "requested-attributes" operation attribute MAY, but NEED NOT,
+ be returned with the unsupported values.
+
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For the error status codes, Group 3 is returned containing no
+ attributes or is not returned at all:
+
+ client-error-not-possible: Same as Print-Job, in addition the
+ Printer object is not accepting any requests.
+
+ client-error-request-entity-too-large: same as Print-job,
+ except that no print data is involved.
+
+ client-error-attributes-or-values-not-supported: not
+ applicable, since unsupported operation attributes and/or
+ values MUST be ignored and an appropriate success code returned
+ (see above).
+
+ client-error-conflicting-attributes: same as Print-Job, except
+ that "ipp-attribute-fidelity" is not involved.
+
+ server-error-operation-not-supported: not applicable (since
+ Get-Printer-Attributes is REQUIRED).
+
+ server-error-device-error: same as Print-Job, except that no
+ document data is involved.
+
+
+
+Hastings, et al. Informational [Page 59]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ server-error-temporary-error: same as Print-Job, except that
+ no document data is involved.
+
+ server-error-not-accepting-jobs: not applicable.
+
+ server-error-busy: same as Print-Job, except the IPP object is
+ too busy to accept even query requests.
+
+ server-error-job-canceled: not applicable.
+
+3.1.3.1.6 Get-Jobs
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to the Get-Jobs operation with the
+ following specialization's and differences. See Section 13 in
+ [RFC2911] for a more complete description of each status code.
+
+ For the following success status codes, the requested attributes are
+ returned in Group 3 in the response:
+
+ successful-ok: same as Get-Printer-Attributes (see section
+ 3.1.3.1.5).
+
+ successful-ok-ignored-or-substituted-attributes: same as Get-
+ Printer-Attributes (see section 3.1.3.1.5).
+
+ successful-ok-conflicting-attributes: same as Get-Printer-
+ Attributes (see section 3.1.3.1.5).
+
+ For any error status codes, Group 3 is returned containing no
+ attributes or is not returned at all. The following brief error
+ status code descriptions contain unique information for use with
+ Get-Jobs operation. See section 14 for the other error status codes
+ that apply uniformly to all operations:
+
+ client-error-not-possible: Same as Print-Job, in addition the
+ Printer object is not accepting any requests.
+
+ client-error-request-entity-too-large: same as Print-job,
+ except that no print data is involved.
+
+ client-error-document-format-not-supported: not applicable.
+
+ client-error-attributes-or-values-not-supported: not
+ applicable, since unsupported operation attributes and/or
+ values MUST be ignored and an appropriate success code returned
+ (see above).
+
+
+
+
+Hastings, et al. Informational [Page 60]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ client-error-conflicting-attributes: same as Print-Job, except
+ that "ipp-attribute-fidelity" is not involved.
+
+ server-error-operation-not-supported: not applicable (since
+ Get-Jobs is REQUIRED).
+
+ server-error-device-error: same as Print-Job, except that no
+ document data is involved.
+
+ server-error-temporary-error: same as Print-Job, except that
+ no document data is involved.
+
+ server-error-not-accepting-jobs: not applicable.
+
+ server-error-job-canceled: not applicable.
+
+3.1.3.1.7 Pause-Printer
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to Pause-Printer with the following
+ specializations and differences. See Section 13 in [RFC2911] for a
+ more complete description of each status code.
+
+ For the following success status codes, the Printer object is being
+ stopped from scheduling jobs on all its devices.
+
+ successful-ok: no request attributes were substituted or
+ ignored (same as Print-Job).
+
+ successful-ok-ignored-or-substituted-attributes: same as
+ Print-Job.
+
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For any of the error status codes, the Printer object has not been
+ stopped from scheduling jobs on all its devices.
+
+ client-error-not-possible: not applicable.
+
+ client-error-not-found: the target Printer object does not
+ exist.
+
+ client-error-gone: the target Printer object no longer exists
+ and no forwarding address is known.
+
+ client-error-request-entity-too-large: same as Print-Job,
+ except no document data is involved.
+
+
+
+
+Hastings, et al. Informational [Page 61]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ client-error-document-format-not-supported: not applicable.
+
+ client-error-conflicting-attributes: same as Print-Job, except
+ that the Printer's "printer-is-accepting-jobs" attribute is not
+ involved.
+
+ server-error-operation-not-supported: the Pause-Printer
+ operation is not supported.
+
+ server-error-device-error: not applicable.
+
+ server-error-temporary-error: same as Print-Job, except no
+ document data is involved.
+
+ server-error-not-accepting-jobs: not applicable.
+
+ server-error-job-canceled: not applicable.
+
+3.1.3.1.8 Resume-Printer
+
+ All of the Print-Job status code descriptions in Section 3.1.3.1.1
+ Print-Job Response with the specialization's described for Pause-
+ Printer are applicable to Resume-Printer. See Section 13 in
+ [RFC2911] for a more complete description of each status code.
+
+ For the following success status codes, the Printer object resumes
+ scheduling jobs on all its devices.
+
+ successful-ok: no request attributes were substituted or
+ ignored (same as Print-Job).
+
+ successful-ok-ignored-or-substituted-attributes: same as
+ Print-Job.
+
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For any of the error status codes, the Printer object does not resume
+ scheduling jobs.
+
+ server-error-operation-not-supported: the Resume-Printer
+ operation is not supported.
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 62]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+3.1.3.1.8.1 What about Printers unable to change state due to an error
+ condition?
+
+ If, in case, the IPP printer is unable to change its state due to
+ some problem with the actual printer device (say, it is shut down or
+ there is a media-jam as indicated in [RFC2911]), what should be the
+ result of the "Resume-Printer" operation? Should it still change the
+ 'printer-state-reasons' and return success or should it fail ?
+
+ The Resume-Printer operation must clear the 'paused' or 'moving-to-
+ paused' 'printer-state-message'. The operation must return a
+ 'successful-ok' status code.
+
+3.1.3.1.8.2 How is "printer-state" handled on Resume-Printer?
+
+ If the Resume-Printer operation succeeds, what should be the value of
+ "printer-state" and who should take care of the "printer-state"
+ attribute value later on ?
+
+ The Resume-Printer operation may change the "printer-state-reasons"
+ value.
+
+ The "printer-state" will change to one of three states:
+
+ 1. 'idle' - no additional jobs and no error conditions present
+
+ 2. 'processing' - job available and no error conditions present
+
+ 3. current state (i.e. no change) an error condition is present
+ (e.g. media jam)
+
+ In the third case the "printer-state-reason" will be cleared by
+ automata when it detects the error condition no longer exists. The
+ "printer-state" will move to 'idle' or 'processing' when conditions
+ permit. (i.e. no more error conditions)
+
+3.1.3.1.9 Purge-Printer
+
+ All of the Print-Job status code descriptions in Section 3.1.3.1.1
+ Print-Job Response with the specialization's described for Pause-
+ Printer are applicable to Purge-Printer. See Section 13 in [RFC2911]
+ for a more complete description of each status code.
+
+ For the following success status codes, the Printer object purges all
+ it's jobs.
+
+ successful-ok: no request attributes were substituted or
+ ignored (same as Print-Job).
+
+
+
+Hastings, et al. Informational [Page 63]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ successful-ok-ignored-or-substituted-attributes: same as
+ Print-Job.
+
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For any of the error status codes, the Printer object does not purge
+ any jobs.
+
+ server-error-operation-not-supported: the Purge-Printer
+ operation is not supported.
+
+3.1.3.2 Job Operations
+
+3.1.3.2.1 Send-Document
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to the Get-Printer-Attributes
+ operation with the following specialization's and differences. See
+ Section 13 in [RFC2911] for a more complete description of each
+ status code.
+
+ For the following success status codes, the document has been added
+ to the specified Job object and the job's "number-of-documents"
+ attribute has been incremented:
+
+ successful-ok: no request attributes were substituted or
+ ignored (same as Print-Job).
+
+ successful-ok-ignored-or-substituted-attributes: same as
+ Print-Job.
+
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For the error status codes, no document has been added to the Job
+ object and the job's "number-of-documents" attribute has not been
+ incremented:
+
+ client-error-not-possible: Same as Print-Job, except that the
+ Printer's "printer-is-accepting-jobs" attribute is not
+ involved, so that the client is able to finish submitting a job
+ that was created with a Create-Job operation after this
+ attribute has been set to 'true'. Another condition is that
+ the state of the job precludes Send-Document, i.e., the job has
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 64]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ already been closed out by the client. However, if the IPP
+ Printer closed out the job due to timeout, the 'client-error-
+ timeout' error status SHOULD be returned instead.
+
+ client-error-timeout: This request was sent after the Printer
+ closed the job, because it has not received a Send-Document or
+ Send-URI operation within the Printer's "multiple-operation-
+ time-out" period .
+
+ client-error-request-entity-too-large: same as Print-Job.
+
+ client-error-conflicting-attributes: same as Print-Job, except
+ that "ipp-attributes-fidelity" operation attribute is not
+ involved..
+
+ server-error-operation-not-supported: the Send-Document
+ request is not supported.
+
+ server-error-not-accepting-jobs: not applicable.
+
+ server-error-job-canceled: the job has been canceled by an
+ operator or the system while the client was transmitting the
+ data.
+
+3.1.3.2.2 Send-URI
+
+ All of the Print-Job status code descriptions in Section 3.1.3.1.1
+ Print-Job Response with the specialization's described for Send-
+ Document are applicable to Send-URI. See Section 13 in [RFC2911] for
+ a more complete description of each status code.
+
+ client-error-uri-scheme-not-supported: the URI scheme supplied
+ in the "document-uri" operation attribute is not supported and
+ the "document-uri" attribute MUST be returned in the
+ Unsupported Attributes group.
+
+ server-error-operation-not-supported: the Send-URI operation is
+ not supported.
+
+3.1.3.2.3 Cancel-Job
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to Cancel-Job with the following
+ specializations and differences. See Section 13 in [RFC2911] for a
+ more complete description of each status code.
+
+ For the following success status codes, the Job object is being
+ canceled or has been canceled:
+
+
+
+Hastings, et al. Informational [Page 65]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ successful-ok: no request attributes were substituted or
+ ignored (same as Print-Job).
+
+ successful-ok-ignored-or-substituted-attributes: same as
+ Print-Job.
+
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For any of the error status codes, the Job object has not been
+ canceled or was previously canceled.
+
+ client-error-not-possible: The request cannot be carried out
+ because of the state of the Job object ('completed',
+ 'canceled', or 'aborted') or the state of the system.
+
+ client-error-not-found: the target Printer and/or Job object
+ does not exist.
+
+ client-error-gone: the target Printer and/or Job object no
+ longer exists and no forwarding address is known.
+
+ client-error-request-entity-too-large: same as Print-Job,
+ except no document data is involved.
+
+ client-error-document-format-not-supported: not applicable.
+
+ client-error-attributes-or-values-not-supported: not
+ applicable, since unsupported operation attributes and values
+ MUST be ignored.
+
+ client-error-conflicting-attributes: same as Print-Job, except
+ that the Printer's "printer-is-accepting-jobs" attribute is not
+ involved.
+
+ server-error-operation-not-supported: not applicable (Cancel-
+ Job is REQUIRED).
+
+ server-error-device-error: same as Print-Job, except no
+ document data is involved.
+
+ server-error-temporary-error: same as Print-Job, except no
+ document data is involved.
+
+ server-error-not-accepting-jobs: not applicable.
+
+ server-error-job-canceled: not applicable.
+
+
+
+
+
+Hastings, et al. Informational [Page 66]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+3.1.3.2.4 Get-Job-Attributes
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to Get-Job-Attributes with the
+ following specializations and differences. See Section 13 in
+ [RFC2911] for a more complete description of each status code.
+
+ For the following success status codes, the requested attributes are
+ returned in Group 3 in the response:
+
+ successful-ok: same as Get-Printer-Attributes (see section
+ 3.1.3.1.5).
+
+ successful-ok-ignored-or-substituted-attributes: same as Get-
+ Printer-Attributes (see section 3.1.3.1.5).
+
+ successful-ok-conflicting-attributes: same as Get-Printer-
+ Attributes (see section 3.1.3.1.5).
+
+ For the error status codes, Group 3 is returned containing no
+ attributes or is not returned at all.
+
+ client-error-not-possible: Same as Print-Job, in addition the
+ Printer object is not accepting any requests.
+
+ client-error-document-format-not-supported: not applicable.
+
+ client-error-attributes-or-values-not-supported: not
+ applicable.
+
+ client-error-uri-scheme-not-supported: not applicable.
+
+ client-error-attributes-or-values-not-supported: not
+ applicable, since unsupported operation attributes and/or
+ values MUST be ignored and an appropriate success code returned
+ (see above).
+
+ client-error-conflicting-attributes: not applicable
+
+ server-error-operation-not-supported: not applicable (since
+ Get-Job-Attributes is REQUIRED).
+
+ server-error-device-error: same as Print-Job, except no
+ document data is involved.
+
+ server-error-temporary-error: sane as Print-Job, except no
+ document data is involved..
+
+
+
+
+Hastings, et al. Informational [Page 67]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ server-error-not-accepting-jobs: not applicable.
+
+ server-error-job-canceled: not applicable.
+
+3.1.3.2.5 Hold-Job
+
+ All of the Print-Job status codes described in Section 3.1.3.1.1
+ Print-Job Response are applicable to Hold-Job with the following
+ specializations and differences. See Section 13 in [RFC2911] for a
+ more complete description of each status code.
+
+ For the following success status codes, the Job object is being held
+ or has been held:
+
+ successful-ok: no request attributes were substituted or
+ ignored (same as Print-Job).
+
+ successful-ok-ignored-or-substituted-attributes: same as
+ Print-Job.
+
+ successful-ok-conflicting-attributes: same as Print-Job.
+
+ For any of the error status codes, the Job object has not been held
+ or was previously held.
+
+ client-error-not-possible: The request cannot be carried out
+ because of the state of the Job object ('completed',
+ 'canceled', or 'aborted') or the state of the system.
+
+ client-error-not-found: the target Printer and/or Job object
+ does not exist.
+
+ client-error-gone: the target Printer and/or Job object no
+ longer exists and no forwarding address is known.
+
+ client-error-request-entity-too-large: same as Print-Job,
+ except no document data is involved.
+
+ client-error-document-format-not-supported: not applicable.
+
+ client-error-conflicting-attributes: same as Print-Job, except
+ that the Printer's "printer-is-accepting-jobs" attribute is not
+ involved.
+
+ server-error-operation-not-supported: the Hold-Job operation is
+ not supported.
+
+ server-error-device-error: not applicable.
+
+
+
+Hastings, et al. Informational [Page 68]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ server-error-temporary-error: same as Print-Job, except no
+ document data is involved.
+
+ server-error-not-accepting-jobs: not applicable.
+
+ server-error-job-canceled: not applicable.
+
+3.1.3.2.6 Release-Job
+
+ All of the Print-Job status code descriptions in Section 3.1.3.1.1
+ Print-Job Response with the specialization's described for Hold-Job
+ are applicable to Release-Job. See Section 13 in [RFC2911] for a
+ more complete description of each status code.
+
+ server-error-operation-not-supported: the Release-Job operation
+ is not supported.
+
+3.1.3.2.7 Restart-Job
+
+ All of the Print-Job status code descriptions in Section 3.1.3.1.1
+ Print-Job Response with the specialization's described for Hold-Job
+ are applicable to Restart-Job. See Section 13 in [RFC2911] for a
+ more complete description of each status code.
+
+ server-error-operation-not-supported: the Restart-Job operation
+ is not supported.
+
+3.1.3.2.7.1 Can documents be added to a restarted job?
+
+ Assume I give a Create-Job request along with a set of 5 documents.
+ All the documents get printed and the job state is moved to
+ completed. I issue a Restart-Job request on the job. Now the issue
+ is that, if I try to add new documents to the restarted job, will the
+ IPP Server permit me to do so or return "client-error-not-possible "
+ and again print those 5 jobs?
+
+ A job can not move to the 'completed' state until all the documents
+ have been processed. The 'last-document' flag indicates when the
+ last document for a job is being sent from the client. This is the
+ semantic equivalent of closing a job. No documents may be added once
+ a job is closed. Section 3.3.7 of the IPP/1.1 model states "The job
+ is moved to the 'pending' job state and restarts the beginning on the
+ same IPP Printer object with the same attribute values." 'number-
+ of-documents' is a job attribute.
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 69]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+3.1.4 Returning unsupported attributes in Get-Xxxx responses (Issue
+ 1.18)
+
+ In the Get-Printer-Attributes, Get-Jobs, or Get-Job-Attributes
+ responses, the client cannot depend on getting unsupported attributes
+ returned in the Unsupported Attributes group that the client
+ requested, but are not supported by the IPP object. However, such
+ unsupported requested attributes will not be returned in the Job
+ Attributes or Printer Attributes group (since they are unsupported).
+ Furthermore, the IPP object is REQUIRED to return the 'successful-
+ ok-ignored-or-substituted-attributes' status code, so that the client
+ knows that not all that was requested has been returned.
+
+3.1.5 Sending empty attribute groups
+
+ The [RFC2911] and [RFC2910] specifications RECOMMEND that a sender
+ not send an empty attribute group in a request or a response.
+ However, they REQUIRE a receiver to accept an empty attribute group
+ as equivalent to the omission of that group. So a client SHOULD omit
+ the Job Template Attributes group entirely in a create operation that
+ is not supplying any Job Template attributes. Similarly, an IPP
+ object SHOULD omit an empty Unsupported Attributes group if there are
+ no unsupported attributes to be returned in a response.
+
+ The [RFC2910] specification REQUIRES a receiver to be able to receive
+ either an empty attribute group or an omitted attribute group and
+ treat them equivalently. The term "receiver" means an IPP object for
+ a request and a client for a response. The term "sender' means a
+ client for a request and an IPP object for a response.
+
+ There is an exception to the rule for Get-Jobs when there are no
+ attributes to be returned. [RFC2910] contains the following
+ paragraph:
+
+ The syntax allows an xxx-attributes-tag to be present when the xxx-
+ attribute-sequence that follows is empty. The syntax is defined this
+ way to allow for the response of Get-Jobs where no attributes are
+ returned for some job-objects. Although it is RECOMMENDED that the
+ sender not send an xxx-attributes-tag if there are no attributes
+ (except in the Get-Jobs response just mentioned), the receiver MUST
+ be able to decode such syntax.
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 70]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+3.2 Printer Operations
+
+3.2.1 Print-Job operation
+
+3.2.1.1 Flow controlling the data portion of a Print-Job request (Issue
+ 1.22)
+
+ A paused printer, or one that is stopped due to paper out or jam or
+ spool space full or buffer space full, may flow control the data of a
+ Print-Job operation (at the TCP/IP layer), so that the client is not
+ able to send all the document data. Consequently, the Printer will
+ not return a response until the condition is changed.
+
+ The Printer should not return a Print-Job response with an error code
+ in any of these conditions, since either the printer will be resumed
+ and/or the condition will be freed either by human intervention or as
+ jobs print.
+
+ In writing test scripts to test IPP Printers, the script must also be
+ written not to expect a response, if the printer has been paused,
+ until the printer is resumed, in order to work with all possible
+ implementations.
+
+3.2.1.2 Returning job-state in Print-Job response (Issue 1.30)
+
+ An IPP client submits a small job via Print-Job. By the time the IPP
+ printer/print server is putting together a response to the operation,
+ the job has finished printing and been removed as an object from the
+ print system. What should the job-state be in the response?
+
+ The Model suggests that the Printer return a response before it even
+ accepts the document content. The Job Object Attributes are returned
+ only if the IPP object returns one of the success status codes. Then
+ the job-state would always be "pending" or "pending-held".
+
+ This issue comes up for the implementation of an IPP Printer object
+ as a server that forwards jobs to devices that do not provide job
+ status back to the server. If the server is reasonably certain that
+ the job completed successfully, then it should return the job-state
+ as 'completed'. Also the server can keep the job in its "job
+ history" long after the job is no longer in the device. Then a user
+ could query the server and see that the job was in the 'completed'
+ state and completed as specified by the jobs "time-at-completed"
+ time, which would be the same as the server submitted the job to the
+ device.
+
+
+
+
+
+
+Hastings, et al. Informational [Page 71]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ An alternative is for the server to respond to the client before or
+ while sending the job to the device, instead of waiting until the
+ server has finished sending the job to the device. In this case, the
+ server can return the job's state as 'pending' with the 'job-
+ outgoing' value in the job's "job-state-reasons" attribute.
+
+ If the server doesn't know for sure whether the job completed
+ successfully (or at all), it could return the (out-of-band) 'unknown'
+ value.
+
+ On the other hand, if the server is able to query the device and/or
+ setup some sort of event notification that the device initiates when
+ the job makes state transitions, then the server can return the
+ current job state in the Print-Job response and in subsequent queries
+ because the server knows what the job state is in the device (or can
+ query the device).
+
+ All of these alternatives depend on implementation of the server and
+ the device.
+
+3.2.2 Get-Printer-Attributes operation
+
+ If a Printer supports the "printer-make-and-model" attribute and
+ returns the .INF file model name of the printer in that attribute,
+ the Microsoft client will automatically install the correct driver
+ (if available).
+
+ Clients which poll periodically for printer status or queued-job-
+ count should use the "requested-attributes" operation attribute to
+ limit the scope of the query in order to save Printer and network
+ resources.
+
+3.2.3 Get-Jobs operation
+
+3.2.3.1 Get-Jobs, my-jobs='true', and 'requesting-user-name' (Issue
+ 1.39)?
+
+ In [RFC2911] section 3.2.6.1 'Get-Jobs Request', if the attribute
+ 'my-jobs' is present and set to TRUE, MUST the 'requesting-user-name'
+ attribute be there too, and if it's not present what should the IPP
+ printer do?
+
+ [RFC2911] Section 8.3 describes the various cases of "requesting-
+ user-name" being present or not for any operation. If the client
+ does not supply a value for "requesting-user-name", the printer MUST
+ assume that the client is supplying some anonymous name, such as
+ "anonymous".
+
+
+
+
+Hastings, et al. Informational [Page 72]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+3.2.3.2 Why is there a "limit" attribute in the Get-Jobs operation?
+
+ When using the Get-Jobs operation a client implementer might choose
+ to limit the number of jobs that the client shows on the first
+ screenful. For example, if its UI can only display 50 jobs, it can
+ defend itself against a printer that would otherwise return 500 jobs,
+ perhaps taking a long time on a slow dial-up line. The client can
+ then go and ask for a larger number of jobs in the background, while
+ showing the user the first 50 jobs. Since the job history is returned
+ in reverse order, namely the most recently completed jobs are
+ returned first, the user is most likely interested in the first jobs
+ that are returned. Limiting the number of jobs may be especially
+ useful for a client that is requesting 'completed' jobs from a
+ printer that keeps a long job history. Clients that don't mind
+ sometimes getting very large responses, can omit the "limit"
+ attribute in their Get-Jobs requests.
+
+3.2.4 Create-Job operation
+
+ A Printer may respond to a Create-Job operation with "job-state"
+ 'pending' or 'pending-held' and " job-state-reason" 'job-data-
+ insufficient' to indicate that operation has been accepted by the
+ Printer, but the Printer is expecting additional document data before
+ it can move the job into the 'processing' state. Alternatively, it
+ may respond with "job-state" 'processing' and "job-state-reason"
+ 'job-incoming' to indicate that the Create-Job operation has been
+ accepted by the Printer, but the Printer is expecting additional
+ Send-Document and/or Send-URI operations and/or is
+ accessing/accepting document data. The second alternative is for
+ non-spooling Printers that don't implement the 'pending' state.
+
+ Should the server wait for the "last-document" operation attribute
+ set to 'true' before starting to "process" the job?
+
+ It depends on implementation. Some servers spool the entire job,
+ including all document data, before starting to process, so such an
+ implementation would wait for the "last-document" before starting to
+ process the job. If the time-out occurs without the "last-document",
+ then the server takes one of the indicated actions in section 3.3.1
+ in the [RFC2911] document. Other servers will start to process
+ document data as soon as they have some. These are the so-called
+ "non-spooling" printers. Currently, there isn't a way for a client to
+ determine whether the Printer will spool all the data or will start
+ to process (and print) as soon as it has some data.
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 73]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+3.3 Job Operations
+
+3.3.1 Validate-Job
+
+ The Validate-Job operation has been designed so that its
+ implementation may be a part of the Print-Job operation. Therefore,
+ requiring Validate-Job is not a burden on implementers. Also it is
+ useful for client's to be able to count on its presence in all
+ conformance implementations, so that the client can determine before
+ sending a long document, whether the job will be accepted by the IPP
+ Printer or not.
+
+3.3.2 Restart-Job
+
+ The Restart-Job operation allows the reprocessing of a completed job.
+ Some jobs store the document data on the printer. Jobs created using
+ the Print-Job operation are an example. It is required that the
+ printer retains the job data after the job has moved to a 'completed
+ state' in order for the Restart-Job operation to succeed.
+
+ Some jobs contain only a reference to the job data. A job created
+ using the Print-URI is an example of such a job. When the Restart-
+ Job operation is issued the job is reprocessed. The job data MUST be
+ retrieved again to print the job.
+
+ It is possible that a job fails while attempting to access the print
+ data. When such a job is the target of a Restart-Job the Printer
+ SHALL attempt to retrieve the job data again.
+
+4 Object Attributes
+
+4.1 Attribute Syntax's
+
+4.1.1 The 'none' value for empty sets (Issue 1.37)
+
+ [RFC2911] states that the 'none' value should be used as the value of
+ a 1setOf when the set is empty. In most cases, sets that are
+ potentially empty contain keywords so the keyword 'none' is used, but
+ for the 3 finishings attributes, the values are enums and thus the
+ empty set is represented by the enum 3. Currently there are no other
+ attributes with 1setOf values, which can be empty and can contain
+ values that are not keywords. This exception requires special code
+ and is a potential place for bugs. It would have been better if we
+ had chosen an out-of-band value, either "no-value" or some new value,
+ such as 'none'. Since we didn't, implementations have to deal with
+ the different representations of 'none', depending on the attribute
+ syntax.
+
+
+
+
+Hastings, et al. Informational [Page 74]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+4.1.2 Multi-valued attributes (Issue 1.31)
+
+ What is the attribute syntax for a multi-valued attribute? Since
+ some attributes support values in more than one data type, such as
+ "media", "job-hold-until", and "job-sheets", IPP semantics associate
+ the attribute syntax with each value, not with the attribute as a
+ whole. The protocol associates the attribute syntax tag with each
+ value. Don't be fooled, just because the attribute syntax tag comes
+ before the attribute keyword. All attribute values after the first
+ have a zero length attribute keyword as the indication of a
+ subsequent value of the same attribute.
+
+4.1.3 Case Sensitivity in URIs (issue 1.6)
+
+ IPP client and server implementations must be aware of the diverse
+ uppercase/lowercase nature of URIs. RFC 2396 defines URL schemes and
+ Host names as case insensitive but reminds us that the rest of the
+ URL may well demonstrate case sensitivity. When creating URL's for
+ fields where the choice is completely arbitrary, it is probably best
+ to select lower case. However, this cannot be guaranteed and
+ implementations MUST NOT rely on any fields being case-sensitive or
+ case-insensitive in the URL beyond the URL scheme and host name
+ fields.
+
+ The reason that the IPP specification does not make any restrictions
+ on URIs, is so that implementations of IPP may use off-the-shelf
+ components that conform to the standards that define URIs, such as
+ RFC 2396 and the HTTP/1.1 specifications [RFC2616]. See these
+ specifications for rules of matching, comparison, and case-
+ sensitivity.
+
+ It is also recommended that System Administrators and implementations
+ avoid creating URLs for different printers that differ only in their
+ case. For example, don't have Printer1 and printer1 as two different
+ IPP Printers.
+
+ Example of equivalent URI's
+
+ http://abc.com:80/~smith/home.html
+
+ http://ABC.com/%7Esmith/home.html
+
+ http:/ABC.com:/%7esmith/home.html
+
+ Example of equivalent URI's using the IPP scheme
+
+ ipp://abc.com:631/~smith/home.html
+
+
+
+
+Hastings, et al. Informational [Page 75]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ ipp://ABC.com/%7Esmith/home.html
+
+ http:/ABC.com:631/%7esmith/home.html
+
+ The HTTP/1.1 specification [RFC2616] contains more details on
+ comparing URLs.
+
+4.1.4 Maximum length for xxxWithLanguage and xxxWithoutLanguage
+
+ The 'textWithLanguage' and 'nameWithLanguage' are compound syntaxes
+ that have two components. The first component is the 'language'
+ component that can contain up to 63 octets. The second component is
+ the 'text' or 'name' component. The maximum length of these are 1023
+ octets and 255 octets respectively. The definition of attributes
+ with either syntax may further restrict the length (e.g., printer-
+ name (name(127))).
+
+ The length of the 'language' component has no effect on the allowable
+ length of 'text' in 'textWithLanguage' or the length of 'name' in
+ 'nameWithLanguage'
+
+4.2 Job Template Attributes
+
+4.2.1 multiple-document-handling(type2 keyword)
+
+4.2.1.1 Support of multiple document jobs
+
+ IPP/1.0 is silent on which of the four effects an implementation
+ would perform if it supports Create-Job, but does not support
+ "multiple-document-handling" or multiple documents per job. IPP/1.1
+ was changed so that a Printer could support Create-Job without having
+ to support multiple document jobs. The "multiple-document-jobs-
+ supported" (boolean) Printer description attribute was added to
+ IPP/1.1 along with the 'server-error-multiple-document-jobs-not-
+ supported' status code for a Printer to indicate whether or not it
+ supports multiple document jobs, when it supports the Create-Job
+ operation. Also IPP/1.1 was clarified that the Printer MUST support
+ the "multiple-document-handling" (type2 keyword) Job Template
+ attribute with at least one value if the Printer supports multiple
+ documents per job.
+
+4.3 Job Description Attributes
+
+4.3.1 Getting the date and time of day
+
+ The "date-time-at-creation", "date-time-at-processing", and "date-
+ time-at-completed" attributes are returned as dateTime syntax. These
+ attributes are OPTIONAL for a Printer to support. However, there are
+
+
+
+Hastings, et al. Informational [Page 76]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ various ways for a Printer to get the date and time of day. Some
+ suggestions:
+
+ 1. A Printer can get time from an NTP timeserver if there's one
+ reachable on the network . See RFC 1305. Also DHCP option 32
+ in RFC 2132 returns the IP address of the NTP server.
+
+ 2. Get the date and time at startup from a human operator
+
+ 3. Have an operator set the date and time using a web
+ administrative interface
+
+ 4. Get the date and time from incoming HTTP requests, though the
+ problems of spoofing need to be considered. Perhaps comparing
+ several HTTP requests could reduce the chances of spoofing.
+
+ 5. Internal date time clock battery driven.
+
+ 6. Query "http://tycho.usno.navy.mil/cgi-bin/timer.pl"
+
+4.4 Printer Description Attributes
+
+4.4.1 queued-job-count (integer(0:MAX))
+
+4.4.1.1 Why is "queued-job-count" RECOMMENDED (Issue 1.14)?
+
+ The reason that "queued-job-count" is RECOMMENDED, is that some
+ clients look at that attribute alone when summarizing the status of a
+ list of printers, instead of doing a Get-Jobs to determine the number
+ of jobs in the queue. Implementations that fail to support the
+ "queued-job-count" will cause that client to display 0 jobs when
+ there are actually queued jobs.
+
+ We would have made it a REQUIRED Printer attribute, but some
+ implementations had already been completed before the issue was
+ raised, so making it a SHOULD was a compromise.
+
+4.4.1.2 Is "queued-job-count" a good measure of how busy a printer is
+ (Issue 1.15)?
+
+ The "queued-job-count" is not a good measure of how busy the printer
+ is when there are held jobs. A future registration could be to add a
+ "held-job-count" (or an "active-job-count") Printer Description
+ attribute if experience shows that such an attribute (combination) is
+ needed to quickly indicate how busy a printer really is.
+
+
+
+
+
+
+Hastings, et al. Informational [Page 77]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+4.4.2 printer-current-time (dateTime)
+
+ A Printer implementation MAY support this attribute by obtaining the
+ date and time by any number of implementation-dependent means at
+ startup or subsequently. Examples include:
+
+ 1. an internal date time clock,
+
+ 2. from the operator at startup using the console,
+
+ 3. from an operator using an administrative web page,
+
+ 4. from HTTP headers supplied in client requests,
+
+ 5. use HTTP to query "http://tycho.usno.navy.mil/cgi-bin/timer.pl"
+
+ 6. from the network, using NTP [RFC1305] or DHCP option 32
+ [RFC2132] that returns the IP address of the NTP server.
+
+ If an implementation supports this attribute by obtaining the current
+ time from the network (at startup or later), but the time is not
+ available, then the implementation MUST return the value of this
+ attribute using the out-of-band 'no-value' meaning not configured.
+ See the beginning of section 4.1.
+
+ Since the new "date-and-time-at-xxx" Job Description attributes refer
+ to the "printer-current-time", they will be covered also.
+
+4.4.3 Printer-uri
+
+ Must the operational attribute for printer-uri match one of the
+ values in "printer-uri-supported"?
+
+ A forgiving printer implementation would not reject the operation.
+ But the implementation has its rights to reject a printer or job
+ operation if the operational attribute printer-uri is not a value of
+ the printer-uri-supported. The printer might not be improperly
+ configured. The request obviously reached the printer. The printer
+ could treat the printer-uri as the logical equivalent of a value in
+ the printer-uri-supported. It would be implementation dependent for
+ which value, and associated security policy, would apply. This does
+ also apply to a job object specified with a printer-uri and job-id,
+ or with a job-uri. See section 4.1.3 for how to compare URI's.
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 78]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+4.5 Empty Jobs
+
+ The IPP object model does not prohibit a job that contains no
+ documents. Such a job may be created in a number of ways including a
+ 'create-job' followed by an 'add-document' that contains no data and
+ has the 'last-document' flag set.
+
+ An empty job is processed just as any other job. The operation that
+ "closes" an empty job is not rejected because the job is empty. If
+ no other conditions exist, other than the job is empty, the response
+ to the operation will indicate success. After the job is scheduled
+ and processed, the job state SHALL be 'completed'.
+
+ There will be some variation in the value(s) of the "job-state-
+ reasons" attribute. It is required that if no conditions, other than
+ the job being empty, exist the "job-state-reasons" SHALL include the
+
+ 'completed-successfully'. If other conditions existed, the
+ 'completed-with-warnings' or 'completed-with-errors' values may be
+ used.
+
+5 Directory Considerations
+
+5.1 General Directory Schema Considerations
+
+ The [RFC2911] document lists RECOMMENDED and OPTIONAL Printer object
+ attributes for directory schemas. See [RFC2911] APPENDIX E: Generic
+ Directory Schema.
+
+ The SLP printer template is defined in the "Definition of the Printer
+ Abstract Service Type v2.0" document [svrloc-printer]. The LDAP
+ printer template is defined in the "Internet Printing Protocol (IPP):
+ LDAP Schema for Printer Services" document [ldap-printer]. Both
+ documents systematically add "printer-" to any attribute that doesn't
+ already start with "printer-" in order to keep the printer directory
+ attributes distinct from other directory attributes. Also, instead
+ of using "printer-uri-supported", "uri-authentication-supported", and
+ "uri-security-supported", they use a "printer-xri-supported"
+ attribute with special syntax to contain all of the same information
+ in a single attribute.
+
+5.2 IPP Printer with a DNS name
+
+ If the IPP printer has a DNS name should there be at least two values
+ for the printer-uri-supported attribute. One URL with the fully
+ qualified DNS name the other with the IP address in the URL?
+
+
+
+
+
+Hastings, et al. Informational [Page 79]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ The printer may contain one or the other or both. It's up to the
+ administrator to configure this attribute.
+
+6 Security Considerations
+
+ The security considerations given in [RFC2911] Section 8 "Security
+ Considerations" all apply to this document. In addition, the
+ following sub-sections describes security consideration that have
+ arisen as a result of implementation testing.
+
+6.1 Querying jobs with IPP that were submitted using other job
+ submission protocols (Issue 1.32)
+
+ The following clarification was added to [RFC2911] section 8.5:
+
+ 8.5 Queries on jobs submitted using non-IPP protocols If the
+ device that an IPP Printer is representing is able to accept jobs
+ using other job submission protocols in addition to IPP, it is
+ RECOMMEND that such an implementation at least allow such
+ "foreign" jobs to be queried using Get-Jobs returning "job-id" and
+ "job-uri" as 'unknown'. Such an implementation NEED NOT support
+ all of the same IPP job attributes as for IPP jobs. The IPP
+ object returns the 'unknown' out-of-band value for any requested
+ attribute of a foreign job that is supported for IPP jobs, but not
+ for foreign jobs.
+
+ It is further RECOMMENDED, that the IPP Printer generate "job-id"
+ and "job-uri" values for such "foreign jobs", if possible, so that
+ they may be targets of other IPP operations, such as Get-Job-
+ Attributes and Cancel-Job. Such an implementation also needs to
+ deal with the problem of authentication of such foreign jobs. One
+ approach would be to treat all such foreign jobs as belonging to
+ users other than the user of the IPP client. Another approach
+ would be for the foreign job to belong to 'anonymous'. Only if
+ the IPP client has been authenticated as an operator or
+ administrator of the IPP Printer object, could the foreign jobs be
+ queried by an IPP request. Alternatively, if the security policy
+ were to allow users to query other users' jobs, then the foreign
+ jobs would also be visible to an end-user IPP client using Get-
+ Jobs and Get-Job- Attributes.
+
+ Thus IPP MAY be implemented as a "universal" protocol that
+ provides access to jobs submitted with any job submission
+ protocol. As IPP becomes widely implemented, providing a more
+ universal access makes sense.
+
+
+
+
+
+
+Hastings, et al. Informational [Page 80]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+7 Encoding and Transport
+
+ This section discusses various aspects of IPP/1.1 Encoding and
+ Transport [RFC2910].
+
+ A server is not required to send a response until after it has
+ received the client's entire request. Hence, a client must not
+ expect a response until after it has sent the entire request.
+ However, we recommend that the server return a response as soon as
+ possible if an error is detected while the client is still sending
+ the data, rather than waiting until all of the data is received.
+ Therefore, we also recommend that a client listen for an error
+ response that an IPP server MAY send before it receives all the data.
+ In this case a client, if chunking the data, can send a premature
+ zero-length chunk to end the request before sending all the data (and
+ so the client can keep the connection open for other requests, rather
+ than closing it). If the request is blocked for some reason, a
+ client MAY determine the reason by opening another connection to
+ query the server using Get-Printer-Attributes.
+
+ IPP, by design, uses TCP's built-in flow control mechanisms [RFC 793]
+ to throttle clients when Printers are busy. Therefore, it is
+ perfectly normal for an IPP client transmitting a Job to be blocked
+ for a really long time. Accordingly, socket timeouts must be
+ avoided. Some socket implementations have a timeout option, which
+ specifies how long a write operation on a socket can be blocked
+ before it times out and the blocking ends. A client should set this
+ option for infinite timeout when transmitting Job submissions.
+
+ Some IPP client applications might be able to perform other useful
+ work while a Job transmission is blocked. For example, the client
+ may have other jobs that it could transmit to other Printers
+ simultaneously. A client may have a GUI, which must remain
+ responsive to the user while the Job transmission is blocked. These
+ clients should be designed to spawn a thread to handle the Job
+ transmission at its own pace, leaving the main application free to do
+ other work. Alternatively, single-threaded applications could use
+ non-blocking I/O.
+
+ Some Printer conditions, such as jam or lack of paper, could cause a
+ client to be blocked indefinitely. Clients may open additional
+ connections to the Printer to Get-Printer-Attributes, determine the
+ state of the device, alert a user if the printer is stopped, and let
+ a user decide whether to abort the job transmission or not.
+
+ In the following sections, there are tables of all HTTP headers,
+ which describe their use in an IPP client or server. The following
+ is an explanation of each column in these tables.
+
+
+
+Hastings, et al. Informational [Page 81]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ - the "header" column contains the name of a header
+ - the "request/client" column indicates whether a client sends the
+ header.
+ - the "request/ server" column indicates whether a server supports
+ the header when received.
+ - the "response/ server" column indicates whether a server sends
+ the header.
+ - the "response /client" column indicates whether a client
+ supports the header when received.
+ - the "values and conditions" column specifies the allowed header
+ values and the conditions for the header to be present in a
+ request/response.
+
+ The table for "request headers" does not have columns for responses,
+ and the table for "response headers" does not have columns for
+ requests.
+
+ The following is an explanation of the values in the "request/client"
+ and "response/ server" columns.
+
+ - must: the client or server MUST send the header,
+ - must-if: the client or server MUST send the header when the
+ condition described in the "values and conditions" column is
+ met,
+ - may: the client or server MAY send the header
+ - not: the client or server SHOULD NOT send the header. It is not
+ relevant to an IPP implementation.
+
+ The following is an explanation of the values in the
+ "response/client" and "request/ server" columns.
+
+ - must: the client or server MUST support the header,
+ - may: the client or server MAY support the header
+ - not: the client or server SHOULD NOT support the header. It is
+ not relevant to an IPP implementation.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 82]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+7.1 General Headers
+
+ The following is a table for the general headers.
+
+ General- Request Response Values and Conditions
+ Header
+
+ Client Server Server Client
+
+
+ Cache- not must not "no-cache" only
+ Control must
+
+ Connection must- must must- must "close" only. Both
+ if if client and server
+ SHOULD keep a
+ connection for the
+ duration of a sequence
+ of operations. The
+ client and server MUST
+ include this header
+ for the last operation
+ in such a sequence.
+
+ Date may may must may per RFC 1123 [RFC1123]
+ from RFC 2616
+ [RFC2616]
+
+ Pragma must not must not "no-cache" only
+
+ Transfer- must- must must- must "chunked" only. Header
+ Encoding if if MUST be present if
+ Content-Length is
+ absent.
+
+ Upgrade not not not not
+
+ Via not not not not
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 83]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+7.2 Request Headers
+
+ The following is a table for the request headers.
+
+ Request- Client Server Request Values and Conditions
+ Header
+
+ Accept may must "application/ipp" only. This
+ value is the default if the
+ client omits it
+
+ Accept- not not Charset information is within the
+ Charset application/ipp entity
+
+ Accept- may must empty and per RFC 2616 [RFC2616]
+ Encoding and IANA registry for content-
+ codings
+
+ Accept- not not language information is within the
+ Language application/ipp entity
+
+ Authorization must- must per RFC 2616. A client MUST send
+ if this header when it receives a
+ 401 "Unauthorized" response and
+ does not receive a "Proxy-
+ Authenticate" header.
+
+ From not not per RFC 2616. Because RFC
+ recommends sending this header
+ only with the user's approval,
+ it is not very useful
+
+ Host must must per RFC 2616
+
+ If-Match not not
+
+ If-Modified- not not
+ Since
+
+ If-None-Match not not
+
+ If-Range not not
+
+ If- not not
+ Unmodified-
+ Since
+
+
+
+
+
+Hastings, et al. Informational [Page 84]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Request- Client Server Request Values and Conditions
+ Header
+
+ Max-Forwards not not
+
+ Proxy- must- not per RFC 2616. A client MUST send
+ Authorizati if this header when it receives a
+ on 401 "Unauthorized" response and
+ a "Proxy-Authenticate" header.
+
+ Range not not
+
+ Referrer not not
+
+ User-Agent not not
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 85]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+7.3 Response Headers
+
+ The following is a table for the request headers.
+
+ Response- Server Client Response Values and Conditions
+ Header
+
+
+ Accept-Ranges not not
+
+ Age not not
+
+ Location must- may per RFC 2616. When URI needs
+ if redirection.
+
+ Proxy- must per RFC 2616
+ Authenticat
+ e not
+
+ Public may may per RFC 2616
+
+ Retry-After may may per RFC 2616
+
+ Server not not
+
+ Vary not not
+
+ Warning may may per RFC 2616
+
+ WWW- must- must per RFC 2616. When a server needs
+ Authenticate if to authenticate a client.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 86]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+7.4 Entity Headers
+
+ The following is a table for the entity headers.
+
+ Entity-Header Request Response Values and
+ Conditions
+
+ Client Server Server Client
+
+ Allow not not not not
+
+ Content-Base not not not not
+
+ Content- may must must must per RFC 2616 and
+ Encoding IANA registry for
+ content codings.
+
+ Content- not not not not Application/ipp
+ Language handles language
+
+ Content- must- must must- must the length of the
+ Length if if message-body per
+ RFC 2616. Header
+ MUST be present
+ if Transfer-
+ Encoding is
+ absent..
+
+ Content- not not not not
+ Location
+
+ Content-MD5 may may may may per RFC 2616
+
+ Content-Range not not not not
+
+ Content-Type must must must must "application/ipp"
+ only
+
+ ETag not not not not
+
+ Expires not not not not
+
+ Last-Modified not not not not
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 87]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+7.5 Optional support for HTTP/1.0
+
+ IPP implementations consist of an HTTP layer and an IPP layer. In
+ the following discussion, the term "client" refers to the HTTP client
+ layer and the term "server" refers to the HTTP server layer. The
+ Encoding and Transport document [RFC2910] requires that HTTP 1.1 MUST
+ be supported by all clients and all servers. However, a client
+ and/or a server implementation may choose to also support HTTP 1.0.
+
+ This option means that a server may choose to communicate with a
+ (non-conforming) client that only supports HTTP 1.0. In such cases
+ the server should not use any HTTP 1.1 specific parameters or
+ features and should respond using HTTP version number 1.0.
+
+ This option also means that a client may choose to communicate with a
+ (non-conforming) server that only supports HTTP 1.0. In such cases,
+ if the server responds with an HTTP 'unsupported version number' to
+ an HTTP 1.1 request, the client should retry using HTTP version
+ number 1.0.
+
+7.6 HTTP/1.1 Chunking
+
+7.6.1 Disabling IPP Server Response Chunking
+
+ Clients MUST anticipate that the HTTP/1.1 server may chunk responses
+ and MUST accept them in responses. However, a (non-conforming) HTTP
+ client that is unable to accept chunked responses may attempt to
+ request an HTTP 1.1 server not to use chunking in its response to an
+ operation by using the following HTTP header:
+
+ TE: identity
+
+ This mechanism should not be used by a server to disable a client
+ from chunking a request, since chunking of document data is an
+ important feature for clients to send long documents.
+
+7.6.2 Warning About the Support of Chunked Requests
+
+ This section describes some problems with the use of chunked requests
+ and HTTP/1.1 servers.
+
+ The HTTP/1.1 standard [RFC2616] requires that conforming servers
+ support chunked requests for any method. However, in spite of this
+ requirement, some HTTP/1.1 implementations support chunked responses
+ in the GET method, but do not support chunked POST method requests.
+ Some HTTP/1.1 implementations that support CGI scripts [CGI] and/or
+ servlets [Servlet] require that the client supply a Content-Length.
+ These implementations might reject a chunked POST method and return a
+
+
+
+Hastings, et al. Informational [Page 88]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ 411 status code (Length Required), might attempt to buffer the
+ request and run out of room returning a 413 status code (Request
+ Entity Too Large), or might successfully accept the chunked request.
+
+ Because of this lack of conformance of HTTP servers to the HTTP/1.1
+ standard, the IPP standard [RFC2910] REQUIRES that a conforming IPP
+ Printer object implementation support chunked requests and that
+ conforming clients accept chunked responses. Therefore, IPP object
+ implementers are warned to seek HTTP server implementations that
+ support chunked POST requests in order to conform to the IPP standard
+ and/or use implementation techniques that support chunked POST
+ requests.
+
+8 References
+
+ [CGI] CGI/1.1 (http://www.w3.org/CGI/).
+
+ [IANA-CS] IANA Registry of Coded Character Sets:
+ http://www.iana.org/assignments/character-sets
+
+ [ldap-printer] Fleming, P., Jones, K., Lewis, H. and I. McDonald,
+ "Internet Printing Protocol (IPP): LDAP Schema for
+ Printer Services", Work in Progress.
+
+ [RFC793] Postel, J., "Transmission Control Protocol", STD 7,
+ RFC 793, September 1981.
+
+ [RFC1123] Braden, R., "Requirements for Internet Hosts -
+ Application and Support", RFC 1123, October, 1989.
+
+ [RFC2026] Bradner, S., "The Internet Standards Process --
+ Revision 3", BCP 9, RFC 2026, October 1996.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119 , March 1997.
+
+ [RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter,
+ "Uniform Resource Identifiers (URI): Generic
+ Syntax", RFC 2396, August 1998.
+
+ [RFC2565] DeBry, R., Hastings, T., Herriot, R., Isaacson, S.
+ and P. Powell, "Internet Printing Protocol/1.0:
+ Model and Semantics", RFC 2566, April 1999.
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 89]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ [RFC2566] Herriot, R., Butler, S., Moore, P. and R. Turner,
+ "Internet Printing Protocol/1.0: Encoding and
+ Transport", RFC 2565, April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model
+ and Protocol for the Internet Printing Protocol",
+ RFC 2568, April 1999.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J.
+ Martin, "Mapping between LPD and IPP Protocols",
+ RFC 2569, April 1999.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P. and T. Berners-Lee,
+ "Hypertext Transfer Protocol - HTTP/1.1", RFC 2616,
+ June 1999.
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P. and R. Turner,
+ "Internet Printing Protocol/1.0: Encoding and
+ Transport", RFC 2910, September, 2000.
+
+ [RFC2911] DeBry, R., Hastings, T., Herriot, R., Isaacson, S.
+ and P. Powell, "Internet Printing Protocol/1.0:
+ Model and Semantics", RFC 2911, September, 2000.
+
+ [Servlet] Servlet Specification Version 2.1
+ (http://java.sun.com/products/servlet/2.1/
+ index.html).
+
+ [svrloc-printer] St. Pierre, P., Isaacson, S., McDonald, I.,
+ "Definition of the Printer Abstract Service Type
+ v2.0", http://www.isi.edu/in-
+ notes/iana/assignments/svrloc-
+ templates/printer.2.0.en (IANA Registered, May 27,
+ 2000).
+
+ [SSL] Netscape, The SSL Protocol, Version 3, (Text
+ version 3.02), November 1996.
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 90]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+9. Authors' Addresses
+
+ Thomas N. Hastings
+ Xerox Corporation
+ 701 Aviation Blvd.
+ El Segundo, CA 90245
+
+ EMail: hastings@cp10.es.xerox.com
+
+
+ Carl-Uno Manros
+ Independent Consultant
+ 1601 N. Sepulveda Blvd. #505
+ Manhattan Beach, CA 90266
+
+ Email: carl@manros.com
+
+
+ Carl Kugler
+ Mail Stop 003G
+ IBM Printing Systems Co
+ 6300 Diagonal Hwy
+ Boulder CO 80301
+
+ EMail: Kugler@us.ibm.com
+
+
+ Henrik Holst
+ i-data Printing Systems
+ Vadstrupvej 35-43
+ 2880 Bagsvaerd, Denmark
+
+ EMail: hh@I-data.com
+
+
+ Peter Zehler
+ Xerox Corporation
+ 800 Philips Road
+ Webster, NY 14580
+
+ EMail: PZehler@crt.xerox.com
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 91]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ IPP Web Page: http://www.pwg.org/ipp/
+ IPP Mailing List: ipp@pwg.org
+
+ To subscribe to the ipp mailing list, send the following email:
+
+ 1) send it to majordomo@pwg.org
+ 2) leave the subject line blank
+ 3) put the following two lines in the message body:
+ subscribe ipp
+ end
+
+ Implementers of this specification document are encouraged to join
+ the IPP Mailing List in order to participate in any discussions of
+ clarification issues and review of registration proposals for
+ additional attributes and values. In order to reduce spam the
+ mailing list rejects mail from non-subscribers, so you must subscribe
+ to the mailing list in order to send a question or comment to the
+ mailing list.
+
+ Other Participants:
+
+ Chuck Adams - Tektronix Shivaun Albright - HP
+
+ Stefan Andersson - Axis Jeff Barnett - IBM
+
+ Ron Bergman - Hitachi Koki Dennis Carney - IBM
+ Imaging Systems
+
+ Keith Carter - IBM Angelo Caruso - Xerox
+
+ Rajesh Chawla - TR Computing Nancy Chen - Okidata
+ Solutions
+
+ Josh Cohen - Microsoft Jeff Copeland - QMS
+
+ Andy Davidson - Tektronix Roger deBry - IBM
+
+ Maulik Desai - Auco Mabry Dozier - QMS
+
+ Lee Farrell - Canon Information Satoshi Fujitami - Ricoh
+ Systems
+
+ Steve Gebert - IBM Sue Gleeson - Digital
+
+ Charles Gordon - Osicom Brian Grimshaw - Apple
+
+ Jerry Hadsell - IBM Richard Hart - Digital
+
+
+
+
+Hastings, et al. Informational [Page 92]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Tom Hastings - Xerox Henrik Holst - I-data
+
+ Stephen Holmstead Zhi-Hong Huang - Zenographics
+
+ Scott Isaacson - Novell Babek Jahromi - Microsoft
+
+ Swen Johnson - Xerox David Kellerman - Northlake
+ Software
+
+ Robert Kline - TrueSpectra Charles Kong - Panasonic
+
+ Carl Kugler - IBM Dave Kuntz - Hewlett-Packard
+
+ Takami Kurono - Brother Rick Landau - Digital
+
+ Scott Lawrence - Agranot Systems Greg LeClair - Epson
+
+ Dwight Lewis - Lexmark Harry Lewis - IBM
+
+ Tony Liao - Vivid Image Roy Lomicka - Digital
+
+ Pete Loya - HP Ray Lutz - Cognisys
+
+ Mike MacKay - Novell, Inc. David Manchala - Xerox
+
+ Carl-Uno Manros - Xerox Jay Martin - Underscore
+
+ Stan McConnell - Xerox Larry Masinter - Xerox
+
+ Sandra Matts - Hewlett Packard Peter Michalek - Shinesoft
+
+ Ira McDonald - High North Inc. Mike Moldovan - G3 Nova
+
+ Tetsuya Morita - Ricoh Yuichi Niwa - Ricoh
+
+ Pat Nogay - IBM Ron Norton - Printronics
+
+ Hugo Parra, Novell Bob Pentecost - Hewlett-Packard
+
+ Patrick Powell - Astart Jeff Rackowitz - Intermec
+ Technologies
+
+ Eric Random - Peerless Rob Rhoads - Intel
+
+ Xavier Riley - Xerox Gary Roberts - Ricoh
+
+ David Roach - Unisys Stuart Rowley - Kyocera
+
+
+
+
+Hastings, et al. Informational [Page 93]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ Yuji Sasaki - Japan Computer Richard Schneider - Epson
+ Industry
+
+ Kris Schoff - HP Katsuaki Sekiguchi - Canon
+
+ Bob Setterbo - Adobe Gail Songer - Peerless
+
+ Hideki Tanaka - Canon Devon Taylor - Novell, Inc.
+
+ Mike Timperman - Lexmark Atsushi Uchino - Epson
+
+ Shigeru Ueda - Canon Bob Von Andel - Allegro Software
+
+ William Wagner - NetSilicon/DPI Jim Walker - DAZEL
+
+ Chris Wellens - Interworking Labs Trevor Wells - Hewlett Packard
+
+ Craig Whittle - Sharp Labs Rob Whittle - Novell, Inc.
+
+ Jasper Wong - Xionics Don Wright - Lexmark
+
+ Michael Wu - Heidelberg Digital Rick Yardumian - Xerox
+
+ Michael Yeung - Toshiba Lloyd Young - Lexmark
+
+ Atsushi Yuki - Kyocera Peter Zehler - Xerox
+
+ William Zhang- Canon Information Frank Zhao - Panasonic
+ Systems
+
+ Steve Zilles - Adobe Rob Zirnstein - Canon
+ Information Systems
+
+10. Description of the Base IPP Documents
+
+ In addition to this document, the base set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+
+
+
+Hastings, et al. Informational [Page 94]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0 [RFC2566, RFC2565]. A few OPTIONAL operator
+ operations have been added to IPP/1.1 [RFC2911, RFC2910].
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF IPP working group's major decisions.
+
+ The "Internet Printing Protocol/1.1: Model and Semantics" document
+ describes a simplified model with abstract objects, their attributes,
+ and their operations. The model introduces a Printer and a Job. The
+ Job supports multiple documents per Job. The model document also
+ addresses how security, internationalization, and directory issues
+ are addressed.
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1 [RFC2616]. It also defines the
+ encoding rules for a new Internet MIME media type called
+ "application/ipp". This document also defines the rules for
+ transporting a message body over HTTP whose Content-Type is
+ "application/ipp". This document defines the 'ipp' scheme for
+ identifying IPP printers and jobs.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 95]
+
+RFC 3196 Internet Printing Protocol/1.1 November 2001
+
+
+11 Full Copyright Statement
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 96]
+
diff --git a/standards/rfc3239.txt b/standards/rfc3239.txt
new file mode 100644
index 000000000..edd131517
--- /dev/null
+++ b/standards/rfc3239.txt
@@ -0,0 +1,843 @@
+
+
+
+
+
+
+Network Working Group C. Kugler
+Request for Comments: 3239 H. Lewis
+Category: Informational IBM Corporation
+ T. Hastings
+ Xerox Corporation
+ February 2002
+
+
+ Internet Printing Protocol (IPP):
+ Requirements for Job, Printer, and Device Administrative Operations
+
+
+Status of this Memo
+
+ This memo provides information for the Internet community. It does
+ not specify an Internet standard of any kind. Distribution of this
+ memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+Abstract
+
+ This document specifies the requirements and uses cases for some
+ optional administrative operations for use with the Internet Printing
+ Protocol (IPP) version 1.0 and version 1.1. Some of these
+ administrative operations operate on the IPP Job and Printer objects.
+ The remaining operations operate on a new Device object that more
+ closely models a single output device.
+
+Table of Contents
+
+ 1 Introduction.....................................................2
+ 2 Terminology......................................................2
+ 3 Requirements and Use Cases.......................................3
+ 4 IANA Considerations.............................................10
+ 5 Internationalization Considerations.............................10
+ 6 Security Considerations.........................................10
+ 7 References......................................................11
+ Appendix A: Description of base IPP documents......................12
+ Authors' Addresses.................................................14
+ Full Copyright Statement...........................................15
+
+List of Tables
+
+ Table 1 - List of Printer Operations and corresponding Device
+ Operations ..................................................... 9
+
+
+
+Kugler, Lewis & Hastings Informational [Page 1]
+
+RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002
+
+
+1 Introduction
+
+ The Internet Printing Protocol (IPP) is an application level protocol
+ that can be used for distributed printing using Internet tools and
+ technologies. IPP version 1.1 ([RFC2911, RFC2910]) focuses on end
+ user functionality with a few administrative operations included (for
+ a description of the base IPP documents, see Appendix A). This
+ document defines the requirements and use cases for additional
+ optional end user, operator, and administrator operations used to
+ control Job objects, Printer objects (see [RFC2911]) and a new Device
+ object. The new Device object more closely models a single output
+ device and has no notion of a job, while the Printer object models a
+ print service which understands jobs and may represent one or more
+ output devices.
+
+ The scope of IPP is characterized in RFC 2567 [RFC2567] "Design Goals
+ for an Internet Printing Protocol". It is not the intent of this
+ document to revise or clarify this scope or conjecture as to the
+ degree of industry adoption or trends related to IPP within printing
+ systems. It is the intent of this document to extend the original
+ set of operations - in a similar fashion to the Set1 extensions which
+ referred to IPP/1.0 and were later incorporated into IPP/1.1.
+
+2 Terminology
+
+ This section defines terminology used throughout this document and
+ the corresponding documents that define the Administrative operations
+ on Job, Printer, and Device objects.
+
+ This document uses terms such as "client", "Printer", "Job",
+ "attributes", "keywords", and "support". These terms have special
+ meaning and are defined in the model terminology [RFC2911] section
+ 12.2.
+
+ In addition, the following capitalized terms are defined:
+
+ IPP Printer object (or Printer for short) - a software abstraction
+ defined by [RFC2911].
+
+ Printer Operation - an operation whose target is an IPP Printer
+ object and whose effect is on the Printer object.
+
+ Output Device - the physical imaging mechanism that an IPP Printer
+ controls. Note: while this term is capitalized in this
+ specification (but not in [RFC2911]), there is no formal object
+ called an Output Device.
+
+
+
+
+
+Kugler, Lewis & Hastings Informational [Page 2]
+
+RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002
+
+
+ Device Operation - an operation whose target is an IPP Printer
+ object and whose defined effect is on an Output Device.
+
+ Output Device Fan-Out - a configuration in which an IPP Printer
+ controls more that one output-device.
+
+ Printer fan-out - a configuration in which an IPP Printer object
+ controls more than one Subordinate IPP Printer object.
+
+ Printer fan-in - a configuration in which an IPP Printer object is
+ controlled by more than one IPP Printer object.
+
+ Subordinate Printer - an IPP Printer object that is controlled by
+ another IPP Printer object. Such a Subordinate Printer may
+ have one or more Subordinate Printers.
+
+ Leaf Printer - a Subordinate Printer that has no Subordinate
+ Printers.
+
+ Non-Leaf Printer - an IPP Printer object that has one or more
+ Subordinate Printers.
+
+ Chained Printer - a Non-Leaf Printer that has exactly one
+ Subordinate Printer.
+
+ Job Creation operations - IPP operations that create a Job object:
+ Print-Job, Print-URI, and Create-Job.
+
+3 Requirements and Use Cases
+
+ The Administrative operations for Job and Printer objects will be
+ defined in one document [ipp-ops-set2]. The Administrative
+ operations for Device objects will be defined in a separate document.
+ The requirements are presented here together to show the parallelism.
+
+ 1. Have separate operations for affecting the IPP Printer
+ versus affecting the Output Device, so its clear what the
+ intent of each is, and implementers can implement one or the
+ other or both.
+
+ 2. Support fan-out of Printer objects.
+
+ 3. Support fan-out of Output Devices.
+
+ 4. Support fan-in of Printer objects, as long as it doesn't
+ make the semantics more complicated when not supporting
+ fan-in.
+
+
+
+
+Kugler, Lewis & Hastings Informational [Page 3]
+
+RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002
+
+
+ 5. Support fan-in of output objects, as long as it doesn't make
+ the semantics more complicated when not supporting fan-in.
+
+ 6. Instead of having operation attributes that alter the
+ behavior of the operation significantly, have separate
+ operations, so that it is simple and clear to a client which
+ semantics the Printer is supporting (by querying the
+ "operations-supported" attribute) and it is simple to
+ describe the capabilities of a Printer implementation in
+ written documentation (just list the optional operations
+ supported).
+
+ 7. Need a Printer Operation to prevent a Printer object from
+ accepting new IPP jobs, but currently accepted jobs continue
+ unaffected to be scheduled and processed. Need a companion
+ one to restore the Printer object to accept new IPP jobs.
+
+ Usage: Operator is preparing to take the IPP Printer out of
+ service or to change the configuration of the IPP Printer.
+
+ Suggested name and operations: Disable-Printer and Enable-
+ Printer
+
+ 8. Need a Device Operation to prevent an Output Device from
+ accepting any new jobs from any job submission protocol and
+ a companion one to restore the Output Device to accepting
+ any jobs.
+
+ Usage: Operator is preparing to take the Output Device out
+ of service.
+
+ Suggested name and operations: Disable-Device and Enable
+ Device
+
+ 9. Need a Printer Operation to stop the processing after the
+ current IPP job completes and not start processing any
+ additional IPP jobs (either by scheduling the jobs or
+ sending them to the Output Device), but continue to accept
+ new IPP jobs. Need a companion operation to start
+ processing/sending IPP jobs again.
+
+ Usage: Operator wants to gracefully stop the IPP Printer at
+ the next job boundary. The Pause-Printer-After-Current-Job
+ operation is also invoked implicitly by the Deactivate-
+ Printer and the Shutdown-Printer Operations.
+
+ Suggested name and operations: Pause-Printer-After-
+ Current-Job, (IPP/1.1) Resume-Printer
+
+
+
+Kugler, Lewis & Hastings Informational [Page 4]
+
+RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002
+
+
+ 10. Need a Device Operation to stop the processing the current
+ job "immediately", no matter what protocol. Its like the
+ Pause button on the Output Device. This operation is for
+ emergencies. The stop point depends on implementation, but
+ can be mid page, end of page, end of sheet, or after a few
+ sheets for Output Devices that can't stop that quickly. The
+ paper path isn't run out. Need a companion operation to
+ start processing the current any-protocol job without losing
+ any thing.
+
+ Usage: Operator sees something bad about to happen, such as
+ the paper is about to jam, or the toner is running out, or
+ the device is overheating or wants to add more paper.
+
+ Suggested name and operations: Pause-Device-Now, Resume-
+ Device
+
+ 11. Need a Printer Operation to stop the processing of IPP jobs
+ after all of the currently accepted jobs have been
+ processed, but any newly accepted jobs go into the
+ 'processing-held' state.
+
+ Usage: This allows an operator to reconfigure the Output
+ Device in order to let jobs that are held waiting for
+ resources, such as special media, get a chance. Then the
+ operator uses another operation after reconfiguring. He
+ repeats the two operations to restore the Output Device to
+ its normal media.
+
+ Suggested name and operations: Hold-New-Jobs, Release-
+ Held-New-Jobs
+
+ 12. Need a Device Operation to stop processing the current any-
+ protocol job at a convenient point, such as after the
+ current copy (or end of job if last or only copy). Need a
+ companion operation to start processing the current any-
+ protocol job or next job without losing any thing.
+
+ Usage: The operator wants to empty the output bin that is
+ near full. The paper path is run out.
+
+ Suggested name and operations: Pause-Device-After-Current-
+ Copy, Resume-Device
+
+
+
+
+
+
+
+
+Kugler, Lewis & Hastings Informational [Page 5]
+
+RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002
+
+
+ 13. Need a Device Operation that always pauses on a device-
+ defined boundary, no matter how many copies, in order to not
+ break up a job. Need a companion operation to start
+ processing the current any-protocol job or next job without
+ losing any thing.
+
+ Usage: The operator wants to empty the output bin that is
+ near full, but he doesn't want to break up a job in case it
+ has multiple copies. The paper path is run out.
+
+ Suggested name and operations: Pause-Device-After-Current-
+ Job, Resume-Device
+
+ 14. Need a Printer Operation that combines Disable-Printer,
+ Pause-Printer-After-Current-Job, and rejects all other Job,
+ Printer, and Device Operations, except Job and Printer
+ queries, System Administrator Set-Printer-Attributes, and
+ the companion operation to resume activity. In other words,
+ this operation makes the Printer a read-only object in a
+ graceful manner for end-users and the operator.
+
+ Usage: The administrator wants to reconfigure the Printer
+ object using the Set-Printer-Attributes operation without
+ disturbing the current in process work, but wants to make
+ sure that the operator isn't also trying to change the
+ Printer object as part of running the Printer.
+
+ Suggested name and operation: Deactivate-Printer,
+ Activate-Printer
+
+ 15. Need a Device Operation that combines Disable-Device,
+ Pause-Device-After-Current-Job, and rejects all other Device
+ Operations, except Job and Printer queries and the companion
+ operation to resume activity. In other words, this
+ operation makes the Output Device a read-only object in a
+ graceful manner.
+
+ Usage: The field service person wants to open up the device
+ without disturbing the current in process work, perhaps to
+ replace staples, or replace the toner cartridge.
+
+ Suggested name and operation: Deactivate-Device, Activate-
+ Device
+
+
+
+
+
+
+
+
+Kugler, Lewis & Hastings Informational [Page 6]
+
+RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002
+
+
+ 16. Need a Printer Operation to recover from the IPP Printer
+ software that has gotten confused (run out of heap memory or
+ gotten into a state that it doesn't seem to be able to get
+ out of). This is a condition that shouldn't happen, but
+ does in real life. Any volatile information is saved if
+ possible before the software is re-initialized. No
+ companion operation is needed to undo this. We don't want
+ to go back to the "confused" state :-).
+
+ Usage: The IPP Printer software has gotten confused or
+ isn't responding properly.
+
+ Suggested name and operation: Restart-Printer
+
+ 17. Need a Device Operation to recover from the Output Device
+ hardware and software that has gotten confused (gotten into
+ a state that it doesn't seem to be able to get out of, run
+ out of heap memory, etc.). This is a condition that
+ shouldn't happen, but does in real life. This is the same
+ and has the same options as the Printer MIB reset. No
+ companion operation is needed to undo this. We don't want
+ to go back to the "confused" state :-).
+
+ Usage: The Output Device has gotten confused or need
+ resetting to some initial conditions.
+
+ Suggested name and operation: Reset-Device
+
+ 18. Need a Printer Operation to put the IPP Printer object out
+ of business with no way in the protocol to bring that
+ instantiation back to life (but see Startup-Printer which
+ brings up exactly one new instantiation to life with the
+ same URL). Any volatile information is saved if possible.
+
+ Usage: The Printer is being moved or the building's power
+ is being shut off.
+
+ Suggested name and operation: Shutdown-Printer
+
+ 19. Need a Printer Operation to bring an IPP Printer to life
+ when there is an already running host.
+
+ Usage: After the host is started (by means outside the IPP
+ protocol), the operator is able to ask the host to bring up
+ any number of Printer objects (that the host has been
+ configured in some way) each with distinct URLs.
+
+ Suggested name and operation: Startup-Printer
+
+
+
+Kugler, Lewis & Hastings Informational [Page 7]
+
+RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002
+
+
+ 20. Need a Device Operation to power off the Output Device after
+ writing out any software state. It is assumed that other
+ operations have more gracefully prepared the Output Device
+ for this drastic and immediate. There is no companion
+ Device Operation to bring the power back on.
+
+ Usage: The Output Device is going to be moved, the power in
+ the building is going to be shutoff, the repair man has
+ arrived and needs to take the Output Device apart.
+
+ Suggested name and operation: Power-Off-Device
+
+ 21. Need a Device Operation to startup a powered-off device.
+
+ Usage: After a Power-Off-Device, if the device can be
+ powered back up (possibly by an intervening host that
+ supports the Device Operation).
+
+ Suggest name and operation: Power-On-Device
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kugler, Lewis & Hastings Informational [Page 8]
+
+RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002
+
+
+ The tentative list of Printer and the corresponding Device Operations
+ is shown in Table 1:
+
+ Table 1 - List of Printer Operations and corresponding Device
+ Operations
+
+ Printer Operation Corresponding Device Operation
+ equivalent
+
+ Disable-Printer Disable-Device
+
+ Enable-Printer Enable-Device
+
+ Pause-Printer (IPP/1.1 - [RFC2911] Pause-Device-Now
+ - one interpretation)
+
+ no Pause-Device-After-Current-Copy
+
+ Pause-Printer-After-Current-Job Pause-Device-After-Current-Job
+
+ Resume-Printer (IPP/1.1 - Resume-Device
+ [RFC2911])
+
+ Hold-New-Jobs no
+
+ Release-Held-New-Jobs no
+
+ Deactivate-Printer Deactivate-Device
+
+ Activate-Printer Activate-Device
+
+ Purge-Jobs (IPP/1.1 - [RFC2911]) Purge-Device
+
+ Restart-Printer Reset-Device
+
+ Shutdown-Printer Power-Off-Device
+
+ Startup-Printer Power-On-Device
+
+ There are no conformance dependencies between Printer Operations and
+ Device Operations. Either may be supported without supporting the
+ corresponding operations.
+
+
+
+
+
+
+
+
+
+Kugler, Lewis & Hastings Informational [Page 9]
+
+RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002
+
+
+4 IANA Considerations
+
+ This document does not define anything to be registered. When a
+ document is produced that defines operations that meet the
+ requirements in this document, those operations will be registered
+ according to the procedures in [RFC2911] section 6.4.
+
+5 Internationalization Considerations
+
+ This document has the same localization considerations as the
+ [RFC2911].
+
+6 Security Considerations
+
+ This document defines the requirements for operations that are
+ intended to be used by an operator or system administrator. These
+ operations, when defined, would affect how the Printer behaves and
+ establish policy and/or operating behavior that ordinary users
+ shouldn't be able to perform. Printer implementations that support
+ such operations should authenticate users and authorized them as
+ being an operator or a system administrator for the system.
+ Otherwise, unprivileged users could affect the policy and behavior of
+ IPP Printers, thereby affecting other users. Similarly clients that
+ supports such operations should be prepared to provide the necessary
+ authentication information. See the security provisions in [RFC2911]
+ for authentication, such as TLS.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kugler, Lewis & Hastings Informational [Page 10]
+
+RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002
+
+
+7 References
+
+ [ipp-ntfy] Herriot, R., Hastings, T., Isaacson, S., Martin, J.,
+ deBry, R., Shepherd, M. and R. Bergman, "Internet
+ Printing Protocol/1.1: IPP Event Notifications and
+ Subscriptions", Work in Progress.
+
+ [ipp-ops-set2] Kugler, C., Hastings, T. and H. Lewis, "Internet
+ Printing Protocol (IPP): Job and Printer
+ Administrative Operations", Work in Progress.
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Tuner,
+ "Internet Printing Protocol/1.0: Encoding and
+ Transport", RFC 2565, April 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R. and S. Isaacson,
+ P. Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model and
+ Protocol for the Internet Printing Protocol", RFC
+ 2568, April 1999.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569,
+ April 1999.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P. and T. Berners-Lee, "Hypertext
+ Transfer Protocol - HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P. and R. Tuner,
+ "Internet Printing Protocol/1.1: Encoding and
+ Transport", RFC 2910, September 2000.
+
+ [RFC2911] deBry, R., Hastings, T., Herriot, R., Isaacson, S. and
+ P. Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2911, September 2000.
+
+ [RFC3196] Hastings, T., Manros, C., Zehler, P., Kuger, C. and H.
+ Holst, "Internet Printing Protocol/1.1: Implementer's
+ Guide", RFC 3196, November 2001.
+
+
+
+
+
+
+Kugler, Lewis & Hastings Informational [Page 11]
+
+RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002
+
+
+Appendix A: Description of base IPP documents
+
+ The base set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [RFC3196]
+ Mapping between LPD and IPP Protocols [RFC2569]
+ Internet Printing Protocol (IPP): IPP Event Notifications and
+ Subscriptions [ipp-ntfy]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0. A few optional operator operations have
+ been added to IPP/1.1.
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF working group's major decisions.
+
+ The "Internet Printing Protocol/1.1: Model and Semantics" document
+ describes a simplified model with abstract objects, their attributes,
+ and their operations that are independent of encoding and transport.
+ It introduces a Printer and a Job object. The Job object optionally
+ supports multiple documents per Job. It also addresses security,
+ internationalization, and directory issues.
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1 [RFC2616]. It defines the
+ encoding rules for a new Internet MIME media type called
+ "application/ipp". This document also defines the rules for
+ transporting over HTTP a message body whose Content-Type is
+ "application/ipp". This document defines the 'ippget' scheme for
+ identifying IPP printers and jobs.
+
+
+
+
+
+
+
+Kugler, Lewis & Hastings Informational [Page 12]
+
+RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002
+
+
+ The "Internet Printing Protocol/1.1: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.1 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+ The "IPP Event Notifications and Subscriptions" document defines an
+ extension to IPP/1.0 [RFC2566, RFC2565] and IPP/1.1 [RFC2911,
+ RFC2910]. This extension allows a client to subscribe to printing
+ related Events and defines the semantics for delivering asynchronous
+
+ Event Notifications to the specified Notification Recipient via a
+ specified Delivery Method (i.e., protocols) defined in (separate)
+ Delivery Method documents.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kugler, Lewis & Hastings Informational [Page 13]
+
+RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002
+
+
+Authors' Addresses
+
+ Carl Kugler
+ IBM
+ Boulder CO
+
+ Phone: (303) 924-5060
+ EMail: kugler@us.ibm.com
+
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ EMail: hastings@cp10.es.xerox.com
+
+
+ Harry Lewis
+ IBM
+ Boulder CO
+
+ Phone: (303) 924-5337
+ EMail: harryl@us.ibm.com
+
+ IPP Web Page: http://www.pwg.org/ipp/
+ IPP Mailing List: ipp@pwg.org
+
+ To subscribe to the ipp mailing list, send the following email:
+
+ 1) send it to majordomo@pwg.org
+ 2) leave the subject line blank
+ 3) put the following two lines in the message body:
+ subscribe ipp
+ end
+
+ Implementers of this specification document are encouraged to join
+ the IPP Mailing List in order to participate in any discussions of
+ clarification issues and review of registration proposals for
+ additional attributes and values. In order to reduce spam the
+ mailing list rejects mail from non-subscribers, so you must subscribe
+ to the mailing list in order to send a question or comment to the
+ mailing list.
+
+
+
+
+
+
+Kugler, Lewis & Hastings Informational [Page 14]
+
+RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kugler, Lewis & Hastings Informational [Page 15]
+
diff --git a/standards/rfc3282.txt b/standards/rfc3282.txt
new file mode 100644
index 000000000..bf5b868b1
--- /dev/null
+++ b/standards/rfc3282.txt
@@ -0,0 +1,451 @@
+
+
+
+
+
+
+Network Working Group H. Alvestrand
+Request for Comments: 3282 Cisco Systems
+Obsoletes: 1766 May 2002
+Category: Standards Track
+
+
+ Content Language Headers
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+Abstract
+
+ This document defines a "Content-language:" header, for use in cases
+ where one desires to indicate the language of something that has RFC
+ 822-like headers, like MIME body parts or Web documents, and an
+ "Accept-Language:" header for use in cases where one wishes to
+ indicate one's preferences with regard to language.
+
+1. Introduction
+
+ There are a number of languages presently or previously used by human
+ beings in this world.
+
+ A great number of these people would prefer to have information
+ presented in a language which they understand.
+
+ In some contexts, it is possible to have information available in
+ more than one language, or it might be possible to provide tools
+ (such as dictionaries) to assist in the understanding of a language.
+
+ In other cases, it may be desirable to use a computer program to
+ convert information from one format (such as plaintext) into another
+ (such as computer-synthesized speech, or Braille, or high-quality
+ print renderings).
+
+
+
+
+
+
+
+Alvestrand Standards Track [Page 1]
+
+RFC 3282 Content Language Headers May 2002
+
+
+ A prerequisite for any such function is a means of labelling the
+ information content with an identifier for the language that is used
+ in this information content, such as is defined by [TAGS]. This
+ document specifies a protocol element for use with protocols that use
+ RFC 822-like headers for carrying language tags as defined in [TAGS].
+
+ The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [RFC 2119].
+
+2. The Content-language header
+
+ The "Content-Language" header is intended for use in the case where
+ one desires to indicate the language(s) of something that has RFC
+ 822-like headers, such as MIME body parts or Web documents.
+
+ The RFC 822 EBNF of the Content-Language header is:
+
+ Content-Language = "Content-Language" ":" 1#Language-tag
+
+ In the more strict RFC 2234 ABNF:
+
+ Content-Language = "Content-Language" ":" [CFWS] Language-List
+ Language-List = Language-Tag [CFWS]
+ *("," [CFWS] Language-Tag [CFWS])
+
+ The Content-Language header may list several languages in a comma-
+ separated list.
+
+ The CFWS construct is intended to function like the whitespace
+ convention in RFC 822, which means also that one can place
+ parenthesized comments anywhere in the language sequence, or use
+ continuation lines. A formal definition is given in RFC 2822
+ [RFC2822].
+
+ In keeping with the tradition of RFC 2822, a more liberal "obsolete"
+ grammar is also given:
+
+ obs-content-language = "Content-Language" *WSP ":"
+ [CFWS] Language-List
+
+ Like RFC 2822, this specification says that conforming
+ implementations MUST accept the obs-content-language syntax, but MUST
+ NOT generate it; all generated headers MUST conform to the Content-
+ Language syntax.
+
+
+
+
+
+
+Alvestrand Standards Track [Page 2]
+
+RFC 3282 Content Language Headers May 2002
+
+
+2.1 Examples of Content-language values
+
+ Voice recording from Liverpool downtown
+
+ Content-type: audio/basic
+ Content-Language: en-scouse
+
+ Document in Mingo, an American Indian language which does not have an
+ ISO 639 code:
+
+ Content-type: text/plain
+ Content-Language: i-mingo
+
+ A English-French dictionary
+
+ Content-type: application/dictionary
+ Content-Language: en, fr (This is a dictionary)
+
+ An official European Commission document (in a few of its official
+ languages):
+
+ Content-type: multipart/alternative
+ Content-Language: da, de, el, en, fr, it
+
+ An excerpt from Star Trek
+
+ Content-type: video/mpeg
+ Content-Language: i-klingon
+
+3. The Accept-Language header
+
+ The "Accept-Language" header is intended for use in cases where a
+ user or a process desires to identify the preferred language(s) when
+ RFC 822-like headers, such as MIME body parts or Web documents, are
+ used.
+
+ The RFC 822 EBNF of the Accept-Language header is:
+
+ Accept-Language = "Accept-Language" ":"
+ 1#( language-range [ ";" "q" "=" qvalue ] )
+
+ A slightly more restrictive RFC 2234 ABNF definition is:
+
+ Accept-Language = "Accept-Language:" [CFWS] language-q
+ *( "," [CFWS] language-q )
+ language-q = language-range [";" [CFWS] "q=" qvalue ] [CFWS]
+ qvalue = ( "0" [ "." 0*3DIGIT ] )
+ / ( "1" [ "." 0*3("0") ] )
+
+
+
+Alvestrand Standards Track [Page 3]
+
+RFC 3282 Content Language Headers May 2002
+
+
+
+ A more liberal RFC 2234 ABNF definition is:
+
+ Obs-accept-language = "Accept-Language" *WSP ":" [CFWS]
+ obs-language-q *( "," [CFWS] obs-language-q ) [CFWS]
+ obs-language-q = language-range
+ [ [CFWS] ";" [CFWS] "q" [CFWS] "=" qvalue ]
+
+ Like RFC 2822, this specification says that conforming
+ implementations MUST accept the obs-accept-language syntax, but MUST
+ NOT generate it; all generated messages MUST conform to the Accept-
+ Language syntax.
+
+ The syntax and semantics of language-range is defined in [TAGS]. The
+ Accept-Language header may list several language-ranges in a comma-
+ separated list, and each may include a quality value Q. If no Q
+ values are given, the language-ranges are given in priority order,
+ with the leftmost language-range being the most preferred language;
+ this is an extension to the HTTP/1.1 rules, but matches current
+ practice.
+
+ If Q values are given, refer to HTTP/1.1 [RFC 2616] for the details
+ on how to evaluate it.
+
+4. Security Considerations
+
+ The only security issue that has been raised with language tags since
+ the publication of RFC 1766, which stated that "Security issues are
+ believed to be irrelevant to this memo", is a concern with language
+ ranges used in content negotiation - that they may be used to infer
+ the nationality of the sender, and thus identify potential targets
+ for surveillance.
+
+ This is a special case of the general problem that anything you send
+ is visible to the receiving party; it is useful to be aware that such
+ concerns can exist in some cases.
+
+ The exact magnitude of the threat, and any possible countermeasures,
+ is left to each application protocol.
+
+5. Character set considerations
+
+ This document adds no new considerations beyond what is mentioned in
+ [TAGS].
+
+
+
+
+
+
+
+Alvestrand Standards Track [Page 4]
+
+RFC 3282 Content Language Headers May 2002
+
+
+6. Acknowledgements
+
+ This document has benefited from many rounds of review and comments
+ in various fora of the IETF and the Internet working groups.
+
+ Any list of contributors is bound to be incomplete; please regard the
+ following as only a selection from the group of people who have
+ contributed to make this document what it is today.
+
+ In alphabetical order:
+
+ Tim Berners-Lee, Nathaniel Borenstein, Sean M. Burke, John Clews, Jim
+ Conklin, John Cowan, Dave Crocker, Martin Duerst, Michael Everson,
+ Ned Freed, Tim Goodwin, Dirk-Willem van Gulik, Marion Gunn, Paul
+ Hoffman, Olle Jarnefors, John Klensin, Bruce Lilly, Keith Moore,
+ Chris Newman, Masataka Ohta, Keld Jorn Simonsen, Rhys Weatherley,
+ Misha Wolf, Francois Yergeau and many, many others.
+
+ Special thanks must go to Michael Everson, who has served as language
+ tag reviewer for almost the entire period, since the publication of
+ RFC 1766, and has provided a great deal of input to this revision.
+ Bruce Lilly did a special job of reading and commenting on my ABNF
+ definitions.
+
+7. References
+
+ [TAGS] Alvestrand, H., "Tags for the Identification of
+ Languages", BCP 47, RFC 3066
+
+ [ISO 639] ISO 639:1988 (E/F) - Code for the representation of names
+ of languages - The International Organization for
+ Standardization, 1st edition, 1988-04-01 Prepared by
+ ISO/TC 37 - Terminology (principles and coordination).
+ Note that a new version (ISO 639-1:2000) is in
+ preparation at the time of this writing.
+
+ [ISO 639-2] ISO 639-2:1998 - Codes for the representation of names of
+ languages -- Part 2: Alpha-3 code - edition 1, 1998-11-
+ 01, 66 pages, prepared by ISO/TC 37/SC 2
+
+ [ISO 3166] ISO 3166:1988 (E/F) - Codes for the representation of
+ names of countries - The International Organization for
+ Standardization, 3rd edition, 1988-08-15.
+
+ [ISO 15924] ISO/DIS 15924 - Codes for the representation of names of
+ scripts (under development by ISO TC46/SC2)
+
+
+
+
+
+Alvestrand Standards Track [Page 5]
+
+RFC 3282 Content Language Headers May 2002
+
+
+ [RFC 2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part One: Format of Internet Message
+ Bodies", RFC 2045, November 1996.
+
+ [RFC 2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046,
+ November 1996.
+
+ [RFC 2047] Moore, K., "MIME (Multipurpose Internet Mail Extensions)
+ Part Three: Message Header Extensions for Non-ASCII
+ Text", RFC 2047, November 1996.
+
+ [RFC 2048] Freed, N., Klensin, J. and J. Postel, "Multipurpose
+ Internet Mail Extensions (MIME) Part Four: Registration
+ Procedures", RFC 2048, November 1996.
+
+ [RFC 2049] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Five: Conformance Criteria and
+ Examples", RFC 2049, November 1996.
+
+ [RFC 2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC 2234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [RFC 2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P. and T. Berners-Lee, "Hypertext
+ Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC 2822] Resnick, P., "Internet Message Format", RFC 2822, April
+ 2001.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Alvestrand Standards Track [Page 6]
+
+RFC 3282 Content Language Headers May 2002
+
+
+Appendix A: Changes from RFC 1766
+
+ The definition of the language tags has been split, and is now RFC
+ 3066. The differences parameter to multipart/alternative is no
+ longer part of this standard, because no implementations of the
+ function were ever found. Consult RFC 1766 if you need the
+ information.
+
+ The ABNF for content-language has been updated to use the RFC 2234
+ ABNF.
+
+Author's Address
+
+ Harald Tveit Alvestrand
+ Cisco Systems
+ Weidemanns vei 27
+ 7043 Trondheim
+ NORWAY
+
+ EMail: Harald@Alvestrand.no
+ Phone: +47 73 50 33 52
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Alvestrand Standards Track [Page 7]
+
+RFC 3282 Content Language Headers May 2002
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Alvestrand Standards Track [Page 8]
+
diff --git a/standards/rfc3380.txt b/standards/rfc3380.txt
new file mode 100644
index 000000000..6ea6c07ce
--- /dev/null
+++ b/standards/rfc3380.txt
@@ -0,0 +1,3307 @@
+
+
+
+
+
+
+Network Working Group T. Hastings
+Request for Comments: 3380 Xerox Corporation
+Updates: 2910, 2911 R. Herriot
+Category: Standards Track Consultant
+ C. Kugler
+ H. Lewis
+ IBM Corporation
+ September 2002
+
+
+ Internet Printing Protocol (IPP):
+ Job and Printer Set Operations
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+Abstract
+
+ This document is an OPTIONAL extension to the Internet Printing
+ Protocol (IPP/1.0 and IPP/1.1). This document specifies 3 additional
+ OPTIONAL operations for use with the Internet Printing Protocol/1.0
+ (IPP) and IPP/1.1. The end user, operator, and administrator Set-
+ Job-Attributes and Set-Printer-Attributes operations are used to
+ modify IPP Job objects and Printer objects, respectively. The Get-
+ Printer-Supported-Values administrative operation returns values that
+ the IPP Printer will accept for setting its "xxx-supported"
+ attributes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 1]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+Table of Contents
+
+ 1 Introduction......................................................4
+ 2 Terminology.......................................................5
+ 2.1 Conformance Terminology.........................................5
+ 2.2 Other terminology...............................................5
+ 3 Requirements and Use Cases........................................5
+ 4 Definition of the Set operations..................................6
+ 4.1 Set-Printer-Attributes Operation................................7
+ 4.1.1 Settable and READ-ONLY Printer Description attributes.........9
+ 4.1.2 Set-Printer-Attributes Request...............................10
+ 4.1.3 Set-Printer-Attributes Response..............................12
+ 4.2 Set-Job-Attributes Operation...................................13
+ 4.2.1 Settable and READ-ONLY Job Description attributes............16
+ 4.2.2 Set-Job-Attributes Request...................................17
+ 4.2.3 Set-Job-Attributes Response..................................18
+ 4.3 Get-Printer-Supported-Values Operation.........................19
+ 4.3.1 Definition of the usage of the 'admin-define' out-of-band
+ attribute value..............................................20
+ 5 New Operation attributes.........................................22
+ 5.1 printer-message-from-operator (text(127))......................22
+ 5.2 job-message-from-operator (text(127))..........................23
+ 6 New Printer Description Attributes...............................24
+ 6.1 printer-settable-attributes-supported (1setOf type2 keyword)...24
+ 6.2 job-settable-attributes-supported (1setOf type2 keyword).......25
+ 6.3 document-format-varying-attributes (1setOf type2 keyword)......25
+ 6.4 printer-message-time (integer(MIN:MAX))........................25
+ 6.5 printer-message-date-time (dateTime)...........................26
+ 6.6 printer-xri-supported (1setOf collection)......................26
+ 6.7 xri-uri-scheme-supported (1setOf uriScheme)....................28
+ 6.8 xri-authentication-supported (1setOf type2 keyword)............29
+ 6.9 xri-security-supported (1setOf type2 keyword)..................29
+ 7 Additional status codes..........................................29
+ 7.1 client-error-attributes-not-settable (0x0413)..................29
+ 8 Additional out-of-band values....................................30
+ 8.1 'not-settable' out-of-band value...............................30
+ 8.1.1 Encoding of the 'not-settable' out-of-band attribute value...30
+ 8.2 'delete-attribute' out-of-band value...........................30
+ 8.2.1 Encoding of the 'delete-attribute' out-of-band value.........31
+ 8.3 'admin-define' out-of-band attribute value.....................31
+ 8.3.1 Encoding of the 'admin-define' out-of-band attribute value...32
+ 9 New Values for Existing Printer Description Attributes...........33
+ 9.1 operations-supported (1setOf type2 enum).......................33
+ 10 Conformance Requirements........................................33
+ 11 IANA Considerations.............................................34
+ 11.1 Operation Registrations.......................................35
+ 11.2 Additional Enum Attribute Value Registrations for the
+ "operations-supported" Printer Attribute......................35
+
+
+
+Hastings, et. al. Standards Track [Page 2]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ 11.3 Attribute Registrations.......................................35
+ 11.4 Status code Registrations.....................................36
+ 11.5 Out-of-band Attribute Value Registrations.....................36
+ 12 Internationalization Considerations.............................37
+ 13 Security Considerations.........................................37
+ 14 References......................................................38
+ 14.1 Normative References..........................................38
+ 14.2 Informative References........................................38
+ Appendix A: Allowed Values for Set-Printer-Attributes and Set-Job-
+ Attributes requests (Normative)........................39
+ Appendix B: Attributes returned from Get-Printer-Supported-Values
+ (Normative)............................................50
+ Appendix C: Description of the Base IPP Documents (Informative)....55
+ Authors' Addresses.................................................56
+ Full Copyright Statement...........................................58
+
+Table of Tables
+
+ Table 1 - Operation-Id assignments.................................7
+ Table 2 - Job State Transition Table for the Set-Job-Attributes
+ operation ..............................................15
+ Table 3 - Member attributes of "printer-xri-supported" (1setOf
+ collection) ............................................27
+ Table 4 - Operation-id assignments................................33
+ Table 5 - Validation rules for 'Any of "xxx-supported" '..........40
+ Table 6 - Validation rules for 'From Get-Printer-Supported-Values'41
+ Table 7 - Values allowed for Job Template Attributes in the Set-Job-
+ Attributes Operation ...................................42
+ Table 8 - Values allowed for Job Description Attributes in the Set-
+ Job-Attributes Operation ...............................43
+ Table 9 - Values allowed for Printer Job Template Attributes in the
+ Set-Printer-Attributes Operation .......................44
+ Table 10 - Values allowed for Printer Description Attributes in the
+ Set-Printer-Attributes Operation .......................47
+ Table 11 - Printer Job Template Attributes returned from Get-Printer-
+ Supported-Values .......................................51
+ Table 12 - Printer Job Template Attributes returned from Get-Printer-
+ Supported-Values .......................................51
+ Table 13 - Printer Description Attributes returned from Get-Printer-
+ Supported-Values .......................................51
+ Table 14 - Printer Job Template Attributes returned from Get-Printer-
+ Supported-Values .......................................52
+ Table 15 - Printer Job Template Attributes returned from Get-Printer-
+ Supported-Values .......................................52
+ Table 16 - Printer Description Attributes returned from Get-Printer-
+ Supported-Values .......................................53
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 3]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+1 Introduction
+
+ This document is an OPTIONAL extension to IPP/1.0 [RFC2565, RFC2566]
+ and IPP/1.1 [RFC2911, RFC2910]. For a description of the base IPP
+ documents see Appendix C.
+
+ The Internet Printing Protocol (IPP) is an application level protocol
+ that can be used for distributed printing using Internet tools and
+ technologies. IPP version 1.1 [RFC2911, RFC2910] focuses on end user
+ functionality with a few administrative operations included. This
+ document defines additional OPTIONAL end user, operator, and
+ administrator Set-Job-Attributes and Set-Printer-Attributes
+ operations used to modify IPP Job objects and Printer objects,
+ respectively. It also defines a third Get-Printer-Supported-Values
+ administrator operation that returns values that the IPP Printer will
+ accept for setting its "xxx-supported" attributes. The Get-Printer-
+ Supported-Values operation MUST be supported, if the implementation
+ supports setting any "xxx-supported" Printer attributes using the
+ Set-Printer-Attributes operation.
+
+ Nine Printer Description attributes are defined:
+
+ printer-settable-attributes-supported (1setOf type2 keyword)
+ job-settable-attributes-supported (1setOf type2 keyword)
+ document-format-varying-attributes (1setOf type2 keyword)
+ printer-message-time (integer(MIN:MAX))
+ printer-message-date-time (dateTime)
+ printer-xri-supported (1setOf collection)
+ xri-uri-scheme-supported (1setOf uriScheme)
+ xri-authentication-supported (1setOf type2 keyword)
+ xri-security-supported (1setOf type2 keyword)
+
+ Three out-of-band values are defined for use with these three
+ operations: 'delete-attribute' for deleting Job attributes with the
+ Set-Job-Attributes request, 'not-settable' for use in either the
+ Set-Job-Attributes or Set-Printer-Attributes responses, and 'admin-
+ define' for use in the Get-Printer-Supported-Values response.
+
+ Two operation attributes: "printer-message-from-operator" (text) and
+ "job-message-from-operator" (text) are defined to set the
+ corresponding IPP/1.1 Printer and Job Description attributes with the
+ same names. These operation attributes may be used with any
+ operation that affect the Printer or Job object for which an
+ operation might want to indicate a message. For the Set-Job-
+ Attributes and Set-Printer-Attributes operations, the client MUST
+ explicitly set them, rather than using these operation attributes.
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 4]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ A Printer implementation can make the value of some attributes
+ dependent on the document-format, e.g., "resolution-supported".
+
+2 Terminology
+
+ This section defines terminology used throughout this document.
+
+2.1 Conformance Terminology
+
+ Capitalized terms, such as MUST, MUST NOT, REQUIRED, SHOULD, SHOULD
+ NOT, MAY, NEED NOT, and OPTIONAL, have special meaning relating to
+ conformance as defined in BCP 14, RFC 2119 [RFC2119] and [RFC2911]
+ section 12.1. If an implementation supports the extension defined in
+ this document, then these terms apply; otherwise, they do not. These
+ terms define conformance to this document only; they do not affect
+ conformance to other documents, unless explicitly stated otherwise.
+
+2.2 Other terminology
+
+ This document uses terms such as Job object (or Job), IPP Printer
+ object (or Printer), "operation", "request", response", "attributes",
+ "keywords", and "support". These terms have special meaning and are
+ defined in the model terminology [RFC2911], section 12.2. The
+ following additional terms are introduced in this document:
+
+ READ-ONLY: used in an attribute definition document to indicate that
+ the attribute MUST NOT be settable using an IPP protocol Set
+ operation. In other words, the attribute is not settable by
+ definition.
+
+ not-settable: an implementation does not support setting an attribute
+ (whether or not the attribute's definition is READ-ONLY).
+
+3 Requirements and Use Cases
+
+ The following requirements and usage are intended to be met by the
+ specification in this document.
+
+ 1. The end-user and the operator need a way to modify a Job that is
+ in the 'pending' or 'pending-held' state.
+
+ Usage: The end-user discovers that he/she forgot to include a
+ print instruction, such as "finishings" = 'staple' after
+ submitting a job. Rather than canceling the job and resubmitting
+ it to the same IPP Printer, the end-user is able to modify the job
+ on the IPP Printer.
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 5]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ The operator needs to modify a job because it is requesting a
+ particular kind of media for which there is no more, but the
+ policy is to print the job on a comparable medium.
+
+ 2. The system administrator needs a way to re-configure or change the
+ policy of the IPP Printer remotely.
+
+ Usage: The system administrator is adding additional named media
+ to the supported media list (setting 'name' values to the "media-
+ supported" Printer attribute).
+
+ The system administrator is reducing the capability of the IPP
+ Printer by removing one of the operations from the supported
+ operations list, such as Cancel-Job, because the policy is to run
+ the IPP Printer like a public facsimile machine. After having
+ removed Cancel-Job from the list of supported operations, an
+ administrative client needs to be able to display to an
+ administrator that the implementation is capable of being
+ reconfigured to support Cancel-Job once again.
+
+ The system administrator is remotely configuring the IPP Printer
+ after installing it, and so is replacing the Printer Description
+ attributes that have the out-of-band 'no-value' value (see
+ [RFC2911], section 4.1) with the proper values.
+
+ The operator is changing the media loaded in the input tray, and
+ so is replacing the "media-ready" Job Template Printer attribute
+ value with the proper values.
+
+4 Definition of the Set operations
+
+ The Set-Printer-Attributes operations (as are all Printer operations)
+ are directed at Printer objects. A client MUST always supply the
+ "printer-uri" operation attribute in order to identify the correct
+ target of the operation. These descriptions assume all of the common
+ semantics of the IPP/1.1 Model and Semantics document [RFC2911],
+ section 3.1.
+
+ The Set-Job-Attributes operations (as are all Job operations) are
+ directed at Job objects. A client MUST always supply some means of
+ identifying the Job object in order to identify the correct target of
+ the operation. That job identification MAY either be a single Job
+ URI or a combination of a Printer URI with a Job ID, as defined in
+ [RFC2911]. The IPP object implementation MUST support both forms of
+ identification for every job. If possible, a client SHOULD use the
+ Printer URI with a Job ID rather than a Job URI, since the 32-bit
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 6]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ "job-id" is more readily translated to and from other print protocols
+ that MAY be serving as gateways into or out of the IPP
+ implementation.
+
+ The Set Printer operations are summarized in Table 1:
+
+ Table 1 - Operation-Id assignments
+
+ Operation Name Operation Brief description
+ -Id
+
+ Set-Printer- 0x0013 Sets attribute values of the target
+ Attributes Printer object
+
+ Set-Job-Attributes 0x0014 Sets attribute values of the target
+ Job object
+
+ Get-Printer- 0x0015 Gets values that are valid for
+ Supported-Values setting "xxx-supported" attributes
+ using the Set-Printer-Attributes
+ operation
+
+4.1 Set-Printer-Attributes Operation
+
+ This OPTIONAL operation allows a client to set the values of the
+ attributes of a Printer object. In the request, the client supplies
+ the set of Printer keyword attribute names and values that are to be
+ set. In the response, the Printer object returns success or rejects
+ the entire request with indications of which attribute or attributes
+ could not be set.
+
+ The Printer object validates the client-supplied attributes in the
+ Set-Printer-Attributes request. For an attribute to validate, it
+ MUST meet all of the following rules:
+
+ 1. The number of attributes supplied by the client MUST NOT exceed
+ the maximum number that the Printer supports in a Set-Printer-
+ Attributes request. A Printer MUST accept at least one attribute,
+ but SHOULD accept a reasonable number in a single Set-Printer-
+ Attributes request.
+
+ Note: There is no way for the client to determine the maximum
+ number of attributes that the Printer supports in a Set-Printer-
+ Attributes request, except to try a reasonable number.
+
+ 2. The Printer MUST support the attribute.
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 7]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ 3. The attribute MUST NOT be READ-ONLY, i.e., the definition of the
+ attribute MUST NOT indicate that the attribute is READ-ONLY (see
+ Appendix A for an indication of which IPP/1.1 attributes are
+ READ-ONLY).
+
+ 4. The attribute MUST be settable in this implementation.
+
+ 5. The Printer MUST support the value, according to the rules defined
+ in Appendix A, i.e., each value of each supplied "xxx" attribute
+ MUST be validated against the value of a corresponding "xxx-
+ supported" Printer attribute. One of those rules permits an
+ administrator to set arbitrary 'name' values to those "xxx-
+ supported" Printer attributes that include the 'name' attribute
+ syntax if the implementation supports the 'admin-define' out-of-
+ band value for that "xxx-supported" attribute (see section 8.3 and
+ Appendix A).
+
+ 6. The attribute's values MUST NOT conflict with the values of other
+ Printer attributes, including ones being set in this same
+ operation.
+
+ If any of the supplied attributes are not validate, the Printer
+ object MUST reject the entire operation; the Printer object MUST NOT
+ partially set some of the supplied attributes. In other words, after
+ the operation, all the supplied attributes MUST be set or none of
+ them MUST be set, thus making the Set-Printer-Attributes an atomic
+ operation.
+
+ The Printer MUST accept this operation when its READ-ONLY "printer-
+ state" attribute (see [RFC2911], section 4.4.11) is 'idle' or
+ 'stopped', and SHOULD accept it when the value is 'processing'. The
+ Printer MUST accept this operation for any of the values of the
+ Printer object's READ-ONLY "printer-state-reasons" and "printer-is-
+ accepting-jobs" attributes, unless explicitly defined otherwise in
+ the definition of these attributes' values.
+
+ This operation MUST NOT change the value of attributes not specified
+ in the operation unless the definition of the attribute explicitly
+ specifies such side-effects. For example, this document explicitly
+ specifies that when this operation sets "printer-message-from-
+ operator", the Printer also MUST set the READ-ONLY "printer-message-
+ time" and READ-ONLY "printer-message-date-time" attributes to the
+ time of the operation as a side effect. In particular, if this
+ operation changes an "xxx-default" attribute, the new value MUST be
+ in the "xxx-supported" attributes or the request MUST contain a new
+ value for "xxx-supported", which contains the new value for the
+ "xxx-default". Otherwise, the Printer MUST reject the operation. In
+ general, Printer attribute definitions that are settable will not
+
+
+
+Hastings, et. al. Standards Track [Page 8]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ define side-effects on other attributes that are settable, only side
+ effects on READ-ONLY attributes, if any.
+
+4.1.1 Settable and READ-ONLY Printer Description attributes
+
+ If the Printer supports the Set-Printer-Attributes operation, then it
+ SHOULD support the setting of:
+
+ all Job Template Default ("xxx-default") attributes
+ all Job Template Supported ("xxx-supported") attributes
+ all Job Template Ready ("xxx-ready") attributes
+
+ that the implementation supports (see [RFC2911] section 4.2 and
+ extensions).
+
+ Some Printer Description attributes (see [RFC2911] section 4.4) MUST
+ NOT be settable, i.e., they are defined to be READ-ONLY. An
+ attribute marked as "READ-ONLY" in the Printer Description attribute
+ table in Appendix A is such an attribute. The Printer attributes
+ that are not marked as "READ-ONLY" MAY be settable using the Set-
+ Printer-Attributes operation, depending on implementation.
+
+ Note: From now on, all extensions that define new object attributes
+ will indicate whether or not the attributes are READ-ONLY, by
+ including the "READ-ONLY" adjective in their descriptions and/or
+ explicitly stating whether they MAY be settable.
+
+ The current values of each "xxx-supported" Printer attribute MUST
+ reflect the current policy for support of the corresponding "xxx"
+ attribute. If an "xxx-supported" Printer attribute is settable in an
+ implementation, then its value(s) MUST affect the behavior of the
+ implementation. If an "xxx-supported" Printer attribute is defined
+ to be READ-ONLY or is not-settable in an implementation, then its
+ values MUST NOT be settable using the Set-Printer-Attributes
+ operation. Consider the following examples:
+
+ For example, if the "operations-supported" Printer Description
+ attribute (see [RFC2911] section 4.4.15) is settable in a
+ particular implementation, then changing its value with a Set-
+ Printer-Attributes operation MUST affect the operations that the
+ implementation accepts or rejects. Such an implementation will
+ need to be able to reject values for operations that it contains
+ no code support for (see section 4.3). If the "operations-
+ supported" Printer Description attribute is not settable in a
+ particular implementation, then that implementation MUST reject an
+ attempt to set it with a Set-Printer-Attributes operation, return
+ the 'client-error-attributes-not-settable' status code (see
+ section 7.1), and return the "operations-supported" attribute,
+
+
+
+Hastings, et. al. Standards Track [Page 9]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ with the out-of-band 'not-settable' value in the Unsupported
+ Attributes Group.
+
+ As another example, consider an implementation in which the
+ "media-default" and "media-supported" are settable. If a client
+ supplies a Set-Printer-Attributes request that contains the
+ "media-default" attribute with a value that is not a member of the
+ Printer's "media-supported" attribute, the Printer MUST reject the
+ request and return the "client-error-conflicting-attributes"
+ status code with the "media-default" and "media-supported"
+ attributes and their values (see [RFC2911] section 3.1.7).
+
+ As a third example, if a client supplies a Set-Printer-Attributes
+ request that contains both the "media-default" and the "media-
+ supported" attributes, but includes a value in the "media-default"
+ that is not a member of the supplied "media-supported" attribute,
+ the Printer MUST reject the request and return the "client-error-
+ conflicting-attributes" status code with the "media-default" and
+ "media-supported" attributes and their values (see [RFC2911]
+ section 3.1.7).
+
+ Access Rights: The authenticated user (see [RFC2911] section 8.3)
+ performing this operation must be an operator or administrator of the
+ Printer object (see [RFC2911] Sections 1 and 8.5). Most Printer
+ attributes will require administrator access rights to set, such as
+ "xxx-supported", while some will require operator access rights only,
+ such as "media-ready" and "printer-message-from-operator". Which
+ attributes require which access rights depends on implementation, and
+ MAY depend on site policy.
+
+4.1.2 Set-Printer-Attributes Request
+
+ The following sets of attributes are part of the Set-Printer-
+ Attributes Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes, as described in [RFC2911], section 3.1.4.1.
+
+ Target:
+ The "printer-uri" (uri) operation attribute, which is the
+ target for this operation, as described in [RFC2911], section
+ 3.1.5.
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 10]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client, as described in [RFC2911], section 8.3.
+
+ "document-format" (mimeMediaType):
+ The client OPTIONALLY supplies this attribute. The Printer
+ object MUST support this attribute. This attribute is useful
+ for a client to select the document-format to which the
+ attribute modification should be applied. A Printer
+ implementation MAY allow some attributes to have different
+ values for each document format that it supports. See
+ [RFC2911], section 3.2.5.1 "Get-Printer-Attributes Request".
+
+ If the client includes this attribute, the Printer MUST change
+ the supplied attributes for the document format specified by
+ this attribute. If a supplied attribute is a member of the
+ "document-format-varying-attributes" (i.e., the attribute
+ varies by document format, see section 6.3), the Printer MUST
+ change the supplied attribute for the document format specified
+ by this attribute, but not for other document formats. If a
+ supplied attribute isn't a member of the "document-format-
+ varying-attributes" (i.e., it doesn't vary by document format),
+ the Printer MUST change the supplied attribute for all document
+ formats.
+
+ If the client omits this attribute, the Printer MUST change the
+ supplied attributes for all document formats, whether or not
+ they vary by document-format.
+
+ If the client supplies a value for the "document-format"
+ Operation attribute, that is either 'application/octet-stream'
+ or not supported by the Printer, i.e., is not among the values
+ of the Printer object's "document-format-supported" attribute,
+ the Printer object MUST reject the operation and return the
+ 'client-error-document-format-not-supported' status code.
+ Note: the document-format 'application/octet-stream' is the
+ union of several document-formats (see [RFC2911] section
+ 3.2.5.1, Get-Printer-Attributes) and is not a true document-
+ format.
+
+ Group 2: Printer Attributes
+
+ The client MUST supply a set of Printer attributes with one or
+ more values (including explicitly allowed out-of-band values) as
+ defined in [RFC2911] section 4.2 Job Template Attributes ("xxx-
+ default", "xxx-supported", and "xxx-ready" attributes), section
+ 4.4 Printer Description Attributes, and any attribute extensions
+ supported by the Printer. The value(s) of each Printer attribute
+
+
+
+Hastings, et. al. Standards Track [Page 11]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ supplied in Group 2 replaces the value(s) of the corresponding
+ Printer attribute on the target Printer object. For attributes
+ that can have multiple values (1setOf), all values supplied by the
+ client replace all values of the corresponding Printer object
+ attribute. If a Printer object attribute had not yet been
+ configured, and so assumed the 'no-value' out-of-band value (see
+ [RFC2911] section 4.1), the supplied value(s) replaces the 'no-
+ value' value.
+
+4.1.3 Set-Printer-Attributes Response
+
+ The Printer object returns the following sets of attributes as part
+ of the Get-Printer-Attributes Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute, as described in [RFC2911] sections 3.1.6
+ and 13.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes, as described in [RFC2911], section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911], section 3.1.7, for details on returning Unsupported
+ Attributes.
+
+ If some of the attributes in the operation fail to validate, the
+ Printer MUST reject the operation, MUST NOT change any Printer
+ attributes, and MUST return the indicated status code below. In
+ this group, the Printer MUST also return all attributes that fail
+ to validate. The following are the reasons that an attribute
+ fails to validate and the value returns for the attribute, along
+ with the indicated status code and order of detection:
+
+ 1. The number of attributes supplied by the client exceeds the
+ maximum number that the Printer supports in a Set-Printer-
+ Attributes request: return the 'client-error-request-entity-
+ too-large' (see [RFC2911], section 13.1.4.9).
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 12]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ 2. The Printer doesn't support the attribute: return the attribute
+ with the "out-of-band" value 'unsupported' (see [RFC2911]
+ section 3.1.7 and [RFC2910]) and the 'client-error-attributes-
+ or-values-not-supported (see [RFC2911], section 13.1.4.12).
+
+ 3. The attribute is either READ-ONLY (in its definition) or is
+ not-settable in this implementation: return the attribute with
+ the "out-of-band" value 'not-settable' (see section 8.1) and
+ the 'client-error-attributes-not-settable' status code (see
+ section 7.1).
+
+ 4. The Printer doesn't support the value: if the attribute in the
+ operation has a single value, return it. If the attribute in
+ the operation is multi-valued, return only those values in a
+ 1setOf that are not supported. Return the 'client-error-
+ attributes-or-values-not-supported' status code (see [RFC2911],
+ section 13.1.4.12).
+
+ 5. The values of some of the supplied attributes conflict with one
+ another and/or other Printer attribute values not being set: if
+ the conflicting attribute in the operation has a single value,
+ return the attribute and the value. If the attribute in the
+ operation is multi-valued, return only the attribute and those
+ values in a 1setOf that are conflicting with other attributes.
+ Return the 'client-error-conflicting-attributes' status code
+ (see [RFC2911], section 13.1.4.15).
+
+4.2 Set-Job-Attributes Operation
+
+ This OPTIONAL operation allows a client to set the values of the
+ attributes of a Job object. In the request, the client supplies the
+ set of Job keyword attribute names and values that are to be set. In
+ the response, the IPP object returns success or rejects the entire
+ request with indications of which attribute or attributes could not
+ be set.
+
+ This operation is almost identical to the Set-Printer-Attributes
+ operation and follows the same rules for validation (see section
+ 4.1). The only differences are that the Set-Job-Attributes operation
+ is directed at a Job object rather than a Printer object, there is no
+ "document-format" operation attribute used when setting a Job object,
+ the operation can add an attribute to the (Job) object, the 'delete-
+ attributes' out-of-band value is permitted to remove an attribute,
+ and the validation is the same as the Job Creation operations
+ (Print-Job, Print-URI, and Create-Job), i.e., depends on the "xxx-
+ supported" Printer Description attributes (see [RFC2911] section
+ 3.1). Using the Set-Printer-Attributes operation, the administrator
+ can set arbitrary 'name' values to those "xxx-supported" Printer
+
+
+
+Hastings, et. al. Standards Track [Page 13]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ attributes, that include the 'name' attribute syntax, if the
+ implementation supports the 'admin-define' out-of-band value for that
+ "xxx-supported" attribute (see section 8.3 and Appendix A). However,
+ the Set-Job-Attributes cannot be used to add unsupported names to the
+ Job object.
+
+ If a client supplies a job attribute in a Set-Job-Attributes request
+ that the Printer supports, and the job was originally submitted
+ without supplying that attribute, the Printer adds the attribute to
+ the Job object.
+
+ If the client supplies a job attribute with the "out-of-band" value
+ 'delete-attribute' (see section 8.2), then the Printer MUST remove
+ the attribute and all of its values from the Job object, if present.
+ The semantic effect of the client supplying the 'delete-attribute'
+ value in a Set-Job-Attributes operation MUST be the same as if the
+ attribute had not been supplied with the Job object in the Job
+ Creation operation, i.e., the Printer applies its default attribute
+ or behavior with lower precedence that the PDL (see the beginning of
+ [RFC2911] section 4.2 and [RFC2911] 3.2.1.1). Any subsequent query
+ of the Job object using Get-Job-Attributes or Get-Jobs, MUST NOT
+ return any attribute that has been deleted using the 'delete-
+ attribute' out-of-band value. However, a client can re-establish
+ such a deleted Job attribute with any supported value(s), using a
+ subsequent Set-Job-Attributes operation.
+
+ If the client supplies an attribute in a Set-Job-Attributes request
+ with the 'delete-attribute' value and that attribute is not present
+ on the Job object, the Printer ignores that supplied attribute in the
+ request, does not return the attribute in the Unsupported Attributes
+ group, and returns the 'successful-ok' status code, if there are no
+ other problems with the request.
+
+ The validation of the Set-Job-Attributes request is performed by the
+ Printer as if the job had been submitted originally with the new
+ attribute values (and the deleted attributes removed) and with "ipp-
+ attribute-fidelity" set to 'true', i.e., all modified attributes Job
+ attributes and values MUST be supported in combination with the Job
+ attributes not modified. If such a Job Creation operation would have
+ been accepted, then the Set-Job-Attributes MUST be accepted. If such
+ a Job Creation operation would have been rejected, then the Set-Job-
+ Attributes MUST be rejected and the Job MUST be unchanged. In
+ addition, if any of the supplied attributes are not supported, are
+ not settable, or the values are not supported, the Printer object
+ MUST reject the entire operation; the Printer object MUST NOT
+ partially set some of the supplied attributes. In other words, after
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 14]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ the operation, all the supplied attributes MUST be set or none of
+ them MUST be set, thus making the Set-Job-Attributes an atomic
+ operation.
+
+ The IPP object MUST accept or reject this operation when the Job's
+ READ-ONLY "job-state" attribute has the values shown in Table 2. The
+ job's current state MUST affect whether the IPP object accepts or
+ rejects the request. For example, in the case where the operation
+ creates a request for unavailable resources, the Job transitions to a
+ new state. Table 2 shows the allowed behaviors in each job state and
+ the transitions.
+
+ Table 2 - Job State Transition Table for the Set-Job-Attributes
+ operation
+
+ Current New IPP object's response status code
+ "job-state" "job-state" and "action":
+
+
+ 'pending' 'pending' 'successful-ok'
+
+ 'pending' 'pending-held' 'successful-ok' - needed resources
+ are not ready
+
+ 'pending-held' 'pending-held' 'successful-ok'
+
+ 'pending-held' 'pending' 'successful-ok' - needed resources
+ are ready
+
+ 'processing' 'processing' 'successful-ok' or 'client-error-
+ not-possible' depending on
+ implementation, including the
+ attributes being set, whether the
+ job has started marking media,
+ etc.
+
+ 'processing- 'processing- 'successful-ok' or 'client-error-
+ stopped' stopped' not-possible' depending on
+ implementation, including the
+ attributes being set, whether the
+ job has started marking media,
+ etc.
+
+ 'completed' 'completed' 'client-error-not-possible'
+
+ 'canceled' 'canceled' 'client-error-not-possible'
+
+ 'aborted' 'aborted' 'client-error-not-possible'
+
+
+
+Hastings, et. al. Standards Track [Page 15]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ This operation MUST NOT change the value of attributes not specified
+ in the operation unless the definition of the attribute explicitly
+ specifies such side-effects. In general, Job attribute definitions
+ that are settable will not define side-effects on other attributes
+ that are settable, only side effects on READ-ONLY attributes, if any.
+
+4.2.1 Settable and READ-ONLY Job Description attributes
+
+ If the Printer supports the "job-message-from-operator" Job
+ Description attribute (see [RFC2911] section 4.3.16) and the client
+ explicitly supplies a new value for the "job-message-from-operator"
+ Job Description attribute in Group 2 in the Set-Job-Attributes
+ request, then the Printer MUST set the "job-message-from-operator"
+ Job Description attribute to this new value.
+
+ If the Printer supports the Set-Job-Attributes operation, then it
+ SHOULD support the setting of:
+
+ all Job Template job ("xxx") attributes
+
+ that the implementation supports (see [RFC2911] section 4.2 and
+ extensions).
+
+ Some Job Description attributes (see [RFC2911] section 4.3) MUST NOT
+ be settable, i.e., they are defined to be READ-ONLY. An attribute
+ marked as "READ-ONLY" in the Job Description attribute table in
+ Appendix A is such an attribute. The Job attributes not marked as
+ "READ-ONLY" MAY be settable using the Set-Job-Attributes operation,
+ depending on implementation.
+
+ Note: From now on, all extensions that define new object attributes
+ will indicate whether or not the attributes are READ-ONLY, by
+ including the "READ-ONLY" adjective in their descriptions and/or
+ explicitly stating whether they MAY be settable.
+
+ Access Rights: The authenticated user (see [RFC2911] section 8.3)
+ performing this operation must either be the job owner (as determined
+ in the Job Creation operation) or an operator or administrator of the
+ Printer object (see [RFC2911] Sections 1 and 8.5).
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 16]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+4.2.2 Set-Job-Attributes Request
+
+ The following sets of attributes are part of the Set-Job-Attributes
+ Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911], section 3.1.4.1.
+
+ Target:
+ Either (1) the "printer-uri" (uri) plus "job-id"
+ (integer(1:MAX)) or (2) the "job-uri" (uri) operation
+ attribute(s), which defines the target for this operation as
+ described in [RFC2911], section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client, as described in [RFC2911], section 8.3.
+
+ Group 2: Job Attributes
+
+ The client MUST supply a set of Job attributes with one or more
+ values (including explicitly allowed out-of-band values) as
+ defined in [RFC2911], section 4.2, Job Template Attributes ("xxx"
+ attributes), section 4.3, Job Description Attributes, and any
+ attribute extensions supported by the Printer. The value(s) of
+ each Job attribute supplied in Group 2 replaces the value(s) of
+ the corresponding Job attribute on the target Job object. For
+ attributes that can have multiple values (1setOf), all values
+ supplied by the client replace all values of the corresponding Job
+ object attribute.
+
+ If the client supplies an "xxx" attribute with the 'delete-
+ attribute' out-of-band value (see section 8.2), the Printer MUST
+ remove the "xxx" attribute from the Job object, if present.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 17]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+4.2.3 Set-Job-Attributes Response
+
+ The IPP object returns the following sets of attributes as part of
+ the Set-Job-Attributes Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in [RFC2911], sections 3.1.6
+ and 13.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911], section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911], section 3.1.7, for details on returning Unsupported
+ Attributes.
+
+ If some of the attributes in the operation fail to validate, the
+ Printer MUST reject the operation, MUST NOT change any Job
+ attributes, and MUST return the indicated status code below. In
+ this group, the Printer MUST also return all attributes that fail
+ to validate. The following are the reasons that an attribute
+ fails to validate and the value returns for the attribute, along
+ with the indicated status code and order of detection:
+
+ 1. The number of attributes supplied by the client exceeds the
+ maximum number that the Printer supports in a Set-Printer-
+ Attributes request: return the 'client-error-request-entity-
+ too-large' (see [RFC2911], section 13.1.4.9).
+
+ 2. The Printer doesn't support the attribute: return the attribute
+ with the 'unsupported' out-of-band attribute value (see
+ [RFC2911], section 3.1.7 and [RFC2910]) and the 'client-error-
+ attributes-or-values-not-supported (see [RFC2911], section
+ 13.1.4.12).
+
+ 3. The attribute is READ-ONLY (in its definition) or is not-
+ settable in this implementation: return the attribute with the
+ 'not-settable' out-of-band attribute value (see section 8.1)
+ and the 'client-error-attributes-not-settable' status code (see
+ section 7.1).
+
+
+
+
+Hastings, et. al. Standards Track [Page 18]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ 4. The Printer doesn't support the value: if the attribute in the
+ operation has a single value return it. If the attribute in
+ the operation is multi-valued, return only those values in a
+ 1setOf that are not supported. Return the 'client-error-
+ attributes-or-values-not-supported' status code (see [RFC2911],
+ section 13.1.4.12).
+
+ 5. The values of some of the supplied attributes conflict with one
+ another and/or other Job attribute values not being set: if
+ the conflicting attribute in the operation has a single value,
+ return the attribute and the value. If the attribute in the
+ operation is multi-valued, return only the attribute and those
+ values in a 1setOf that are conflicting with other attributes.
+ Return the 'client-error-conflicting-attributes' status code
+ (see [RFC2911],y section 13.1.4.15).
+
+4.3 Get-Printer-Supported-Values Operation
+
+ This OPTIONAL operation allows a client to request the values that
+ the Printer allows in the Set-Printer-Attributes operation for "xxx-
+ supported" attributes. If the Printer supports the Set-Printer-
+ Attributes operation AND some of its "xxx-supported" Printer
+ attributes are settable, then the Printer MUST also support this
+ operation.
+
+ The Printer MUST return in the Get-Printer-Supported-Values response,
+ those, and only those, "xxx-supported" Printer attributes that it
+ supports setting with the Set-Printer-Attributes operation.
+ Furthermore, if a client requests the value of an attribute that is
+ not settable or is not supported (as in the Get-Printer-Attributes
+ response), the Unsupported Attributes Group of the response NEED NOT
+ contain the "requested-attributes" operation attribute with any such
+ requested (attribute keyword) values.
+
+ This operation has identical request/response attributes to the Get-
+ Printer-Attributes operation in IPP/1.1 [RFC2911]. The operation
+ also behaves identically to the Get-Printer-Attributes operation in
+ IPP/1.1 [RFC2911], with the following exceptions:
+
+ 1. The Get-Printer-Supported-Values operation supports only "xxx-
+ supported" attributes.
+
+ 2. The Get-Printer-Attributes operation returns the few "xxx-
+ supported" attributes that are defined to be single valued, such
+ as "page-ranges-supported" (boolean) or "pdl-override-supported"
+ (type2 keyword), as single values, while Get-Printer-Supported-
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 19]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Values returns the possible values that can be set as a 1setOf of
+ the same attribute syntax type (See Appendix B: Attributes
+ returned from Get-Printer-Supported-Values).
+
+ 3. The Get-Printer-Attributes operation returns the current values of
+ requested attributes, while the Get-Printer-Supported-Values
+ operation returns the values that are inherently supported by the
+ implementation code, i.e., the values that an administrative
+ client can set in a Set-Printer-Attributes request.
+
+ 4. The Get-Printer-Attributes operation returns the current values of
+ requested "xxx-supported" attributes that the Printer is
+ configured to accept in Job Creation operations, including
+ additional values defined by the administrator, while the Get-
+ Printer-Supported-Values operation returns only the values of
+ "xxx-supported" attributes that are inherently supported by the
+ implementation and does not return any additional values defined
+ by the administrator, where the implementation supports the
+ 'admin-define' out-of-band value.
+
+ 5. The Get-Printer-Attributes never returns the 'admin-define' out-
+ of-band attribute value, while the Get-Printer-Supported-
+ Attributes operation does, if the implementation allows the
+ administrator to define name values by setting that "xxx-
+ supported" attribute with any 'name' value(s).
+
+ 6. The Get-Printer-Attributes operation only requires end-user access
+ rights, while the Get-Printer-Supported-Values requires
+ administrator access rights.
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be an administrator of the Printer
+ object (see [RFC2911], Sections 1 and 8.5).
+
+4.3.1 Definition of the usage of the 'admin-define' out-of-band
+ attribute value
+
+ If the Set-Printer-Attributes operation allows the System
+ Administrator to define arbitrary 'name' values for an "xxx-
+ supported" attribute, then the Get-Printer-Supported-Values operation
+ MUST return the 'admin-define' out-of-band attribute value (see
+ section 8.3) as one of the values of the "xxx-supported" attribute.
+ In other words, the 'admin-define' out-of-band attribute value
+ indicates that the Printer implementation supports clients setting
+ arbitrary 'name' attribute syntax values for that "xxx-supported"
+ attribute using the Set-Printer-Attributes operation, as long as the
+ attribute is defined with the 'name' attribute syntax.
+
+
+
+
+Hastings, et. al. Standards Track [Page 20]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ For example, if the Get-Printer-Supported-Values operation returns
+ several keywords as the value of the "media-supported" attribute,
+ then the Set-Printer-Attributes operation MUST accept any of these
+ keywords as values for the "media-supported" attribute. If the Get-
+ Printer-Supported-Values operation returns an 'admin-define' out-of-
+ band attribute value as one of the values of the "media-supported"
+ attribute, then the Set-Printer-Attributes operation MUST accept any
+ value whose attribute syntax is 'name', as a value for the "media-
+ supported" attribute (provided that the user is properly
+ authenticated to use the Set-Printer-Attributes operation, e.g., has
+ administrative access rights).
+
+ The Get-Printer-Supported-Values MAY return the 'admin-define' out-
+ of-band attribute value for any IPP/1.1 or extension Job Template
+ attribute if the implementation supports allowing the System
+ Administrator to add values to the "xxx-supported" attribute using
+ the Set-Printer-Attributes operation. In this case, the Printer MUST
+ accept any 'name' value of the correct attribute syntax in a Set-
+ Printer-Attributes operation that is setting that attribute. For
+ "xxx-supported" attributes that are defined with a choice of
+ attribute syntaxes, such as 'keyword | name', it is the 'name'
+ attribute syntax that the System Administrator can use to add new
+ values, not the 'keyword' attribute syntax. For IPP/1.1, this
+ requirement includes the following Job Template attributes:
+
+ media-supported
+ job-hold-until-supported
+ job-sheets-supported
+
+ Implementations that support additional Job Template attributes that
+ include the 'name' attribute syntax, MAY use the 'admin-define' out-
+ of-band value with them.
+
+ If the 'admin-define' out-of-band attribute value is not one of the
+ values of an "xxx-supported" attribute returned in a Get-Printer-
+ Supported-Values response, then the Printer MUST NOT allow the Set-
+ Printer-Attributes operation for that attribute to contain a value
+ that is not one of the explicit 'keyword' or 'name' values returned
+ in a Get-Printer-Supported-Values response.
+
+ See Appendix B: Attributes returned from Get-Printer-Supported-Values
+ for a full list of values returned by this operation.
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 21]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+5 New Operation attributes
+
+ This section defines new operation attributes for use with the
+ IPP/1.1 operations indicated. As new operations are defined, they
+ will also indicate explicitly whether these operation attributes are
+ defined for use with them.
+
+5.1 printer-message-from-operator (text(127))
+
+ The Printer SHOULD support this Operation attribute in following
+ operations if it supports the corresponding "printer-message-from-
+ operator" Printer Description attribute.
+
+ Pause-Printer
+ Resume-Printer
+ Purge-Jobs
+
+ The client OPTIONALLY supplies this Operation attribute in the above
+ operations. The value of this attribute is a message from the
+ operator about the Printer object on which the operator is performing
+ the operation. If this operation attribute is supported, the Printer
+ copies the value to its "printer-message-from-operator" Printer
+ Description attribute (see [RFC2911], section 4.4.25), even if this
+ Operation attribute is a zero-length text value or consists solely of
+ white space.
+
+ If the Printer supports this operation attribute, it MUST support
+ both a zero-length text value and the 'no-value' out-of-band value
+ (see [RFC2911] section 4.1) to indicate that the operator has sent no
+ message. In this case, the Printer sets the value of the "printer-
+ message-from-operator" to the zero-length value or 'no-value' out-
+ of-band value, respectively. If the client queries the "printer-
+ message-from-operator" Printer attribute, the Printer returns the
+ attribute with the zero-length value or the 'no-value' value,
+ respectively.
+
+ In addition, the Printer automatically copies:
+
+ 1. the value of its "printer-up-time" attribute (see [RFC2911],
+ section 4.4.29) to its "printer-message-time" attribute,
+
+ 2. the value of its printer-current-time" (dateTime) attribute (see
+ [RFC2911], section 4.4.30) to its "printer-message-date-time"
+ attribute, if supported.
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 22]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ If the client omits this operation attribute, the Printer does not
+ change the value of its "printer-message-from-operator", "printer-
+ message-time" and "printer-message-date-time" Printer Description
+ attributes.
+
+ The "printer-message-from-operator" operation attribute MUST NOT be
+ supported as an operation attribute for the Set-Printer-Attributes
+ operation. If the operator wants to set the Printer's "printer-
+ message-from-operator" Printer Description attribute when issuing the
+ Set-Printer-Attributes operation, the client supplies the "printer-
+ message-from-operator" explicitly with its new value as one of the
+ Printer Description attributes in Group 2 in the request; the Printer
+ also updates its "printer-message-time" and "printer-message-date-
+ time" Printer Description attributes. If the client does not
+ explicitly supply the "printer-message-from-operator" with its new
+ value in the Set-Printer-Attributes request, the Printer leaves the
+ value of the Printer's "printer-message-from-operator" Printer
+ Description attribute unchanged.
+
+5.2 job-message-from-operator (text(127))
+
+ The Printer SHOULD support this Operation attribute in following
+ operations if it supports the corresponding "job-message-from-
+ operator" Job Description attribute.
+
+ Cancel-Job
+ Hold-Job
+ Release-Job
+ Restart-Job
+
+ The client OPTIONALLY supplies this attribute in the above
+ operations. The value of this attribute is a message from the
+ operator about the Job object on which the operator has just
+ performed an operation. If supported, the Printer copies the value
+ to the Job's "job-message-from-operator" Job Description attribute
+ (see [RFC2911], section 4.3.16) (even if this Operation attribute is
+ a zero-length text value or consists solely of white space).
+
+ If the Printer supports this operation attribute, it MUST support
+ both a zero-length text value and the 'no-value' out-of-band value
+ (see [RFC2911], section 4.1), to indicate that the operator has sent
+ no message. In this case, the Printer sets the value of the "job-
+ message-from-operator" to the zero-length value or 'no-value' out-
+ of-band value, respectively. If the client queries the "job-
+ message-from-operator" Job attribute, the IPP object returns the
+ attribute with the zero-length value or the 'no-value' value,
+ respectively.
+
+
+
+
+Hastings, et. al. Standards Track [Page 23]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ If the client omits this attribute, the Printer does not change the
+ value of its "job-message-from-operator" Job Description attribute.
+
+ Note: There are no corresponding 'job-message-time" and "job-
+ message-date-time" Job Description attributes, since the usual
+ lifetime of a job is limited.
+
+ The "job-message-from-operator" operation attribute MUST NOT be
+ supported as an operation attribute for the Set-Job-Attributes
+ operation. If the operator wants to set the Job's "job-message-
+ from-operator" Job Description attribute when issuing the Set-Job-
+ Attributes operation, the client MUST supply the "job-message-from-
+ operator" with its new value as one of the Job Description attributes
+ in Group 2 in the request. Otherwise, the Printer leaves the value
+ of the Job's "job-message-from-operator" Job Description attribute
+ unchanged by not explicitly setting the attribute. If the client
+ does not explicitly supply the "job-message-from-operator" with its
+ new value in the Set-Job-Attributes request, the Printer leaves the
+ value of the Job's "job-message-from-operator" Job Description
+ attribute unchanged.
+
+6 New Printer Description Attributes
+
+ The following new Printer Description attributes are needed to
+ support the new operations defined in this document.
+
+6.1 printer-settable-attributes-supported (1setOf type2 keyword)
+
+ This REQUIRED READ-ONLY Printer Description attribute identifies the
+ Printer object attributes that are settable in this implementation,
+ i.e., that are settable using the Set-Printer-Attributes operations
+ (see section 4.1). This attribute MUST be supported if the Set-
+ Printer-Attributes operations is supported. The Printer MUST reject
+ attempts to set any Printer attributes that are not one of the values
+ of this attribute, returning the 'client-error-attributes-not-
+ settable' status code (see section 7.1). The value of this attribute
+ MAY depend on the value of the "document-format" operation attribute
+ supplied in the Get-Printer-Attributes operation (see [RFC2911],
+ section 3.2.5.1).
+
+ Standard keyword values are:
+
+ 'none': There are no settable Printer attributes.
+ 'xxx': Where 'xxx' is any of the keyword attribute names allowed
+ by section 4.1.1.
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 24]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+6.2 job-settable-attributes-supported (1setOf type2 keyword)
+
+ This REQUIRED READ-ONLY Printer Description attribute identifies the
+ Job object attributes that are settable in this implementation, i.e.,
+ that are settable using the Set-Job-Attributes operation (see section
+ 4.2). This attribute MUST be supported if the Set-Job-Attributes
+ operations are supported. The Printer MUST reject attempts to set
+ any Job attributes that are not one of the values of this attribute,
+ returning the 'client-error-attributes-not-settable' status code (see
+ section 7.1).
+
+ Standard keyword values are:
+
+ 'none': There are no settable Job attributes.
+ 'xxx': Where 'xxx' is any of the keyword attribute names allowed
+ by section 4.2.1.
+
+6.3 document-format-varying-attributes (1setOf type2 keyword)
+
+ This OPTIONAL READ-ONLY Printer Description attribute contains a set
+ of attribute name keywords. This attribute SHOULD be supported by a
+ Printer object if the Printer object has Printer attributes whose
+ value vary depending on document format (see [RFC2911], Get-Printer-
+ Attributes operation). This attribute specifies which attribute
+ values can vary by document-format. If an attribute's name, "xxx",
+ is a member of this attribute and the value of attribute "xxx" is
+ changed with the Set-Printer-Attributes operation that included the
+ "document-format" operation attribute, then the Printer MUST change
+ the value for the specified document format and no other document
+ formats (see section 4.1.2). If an attribute's name, "xxx", is not a
+ member of this attribute and the value of attribute "xxx" is changed
+ with the Set-Printer-Attributes operation, then the attribute is
+ changed for all document formats (whether or not the client supplied
+ the "document-format" operation attribute).
+
+6.4 printer-message-time (integer(MIN:MAX))
+
+ This OPTIONAL READ-ONLY Printer Description attribute contains the
+ time that the Printer's "printer-message-from-operator" was changed
+ by the operator using any operation where the client supplied the
+ "printer-message-from-operator" operation attribute (see section 5.1)
+ or was explicitly set using the Set-Printer-Attributes operation (see
+ section 4.1). This attribute allows the users to know when the
+ "printer-message-from-operator" Printer Description attribute was
+ last set.
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 25]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ The Printer sets the value of this attribute by copying the value of
+ the Printer's "printer-up-time" attribute (see [RFC2911], section
+ 4.3.14). If the Printer resets its "printer-up-time" attribute to 1
+ on power-up, then it MUST change the value of the "printer-message-
+ time" to 0 or a negative number as specified in [RFC2911], section
+ 4.3.14.
+
+ Note: This attribute helps users better understand the context for
+ the "printer-message-from-operator" message.
+
+6.5 printer-message-date-time (dateTime)
+
+ This OPTIONAL READ-ONLY Printer Description attribute contains the
+ date and time that the Printer's "printer-message-from-operator" was
+ changed by the operator, using any operation where the client
+ supplied the "printer-message-from-operator" operation attribute (see
+ section 5.1) or was explicitly set using the Set-Printer-Attributes
+ operation (see section 4.1). This attribute allows the users to know
+ when the "printer-message-from-operator" Printer Description
+ attribute was last set.
+
+ This attribute MUST be supported if the Printer supports both the
+ "printer-message-time" and the "printer-current-time" (dateTime)
+ attributes (see [RFC2911], section 4.4.30).
+
+ Note: This attribute helps users better understand the context for
+ the "printer-message-from-operator" message.
+
+6.6 printer-xri-supported (1setOf collection)
+
+ This OPTIONAL Printer Description attribute is a multi-valued
+ attribute where each value has the 'collection' attribute syntax (see
+ [RFC3382]), containing member attributes with the same semantics as
+ the following IPP/1.1 READ-ONLY Printer Description attributes,
+ except for cardinality:
+
+ printer-uri-supported (1setOf uri)
+ - see [RFC2911], section 4.4.1
+ uri-authentication-supported (1setOf type2 keyword)
+ - see [RFC2911], section 4.4.2.
+ uri-security-supported (1setOf type2 keyword)
+ - see [RFC2911], section 4.4.3.
+
+ When setting the "printer-xri-supported" attribute with a Set-
+ Printer-Attributes request, the Printer MUST also set these three
+ IPP/1.1 READ-ONLY Printer Description attributes as a defined side
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 26]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ effect. Thus, this collection attribute provides the means to set
+ these three IPP/1.1 READ-ONLY attributes atomically so that they are
+ never left in a partially inconsistent state.
+
+ An IPP Printer MUST NOT provide any other way, using IPP, to set
+ these three IPP/1.1 READ-ONLY Printer Description attributes, since
+ they are READ-ONLY and MUST have consistent values at all times.
+ Note: The "printer-xri-supported" (1setOf collection) attribute can
+ be put into a directory schema that requires a single text string
+ value, such as could be used with SLPv2 [RFC2608], [RFC2609] or
+ LDAPv3 [RFC2251], [RFC2252], [RFC2926], by using suitable delimiting
+ characters to separate member attributes of the collection and/or
+ terminating collection values.
+
+ The member attributes of the "printer-xri-supported" (1setOf
+ collection) are given in Table 3.
+
+ Table 3 - Member attributes of "printer-xri-supported" (1setOf
+ collection)
+
+ Member attribute client Printer
+ MUST MUST
+ supply support
+
+ xri-uri (uri) yes yes
+
+ xri-authentication (type2 keyword) yes yes
+
+ xri-security (type2 keyword) yes yes
+
+ Other than the uniqueness and the cardinality requirements, the
+ semantics of these three member attributes is given in [RFC2911]
+ sections 4.4.1, 4.4.2, and 4.4.3, respectively.
+
+ A client can query the current values using the Get-Printer-
+ Attributes operation by supplying either:
+
+ 1. the three IPP/1.1 attribute names: "printer-uri-supported", "uri-
+ authentication-supported", "uri-security-supported" and getting
+ back the parallel values OR
+
+ 2. the single attribute name: "printer-xri-supported" and getting
+ back the 1setOf collection which contains the same information
+ semantically, but in a different form.
+
+ A client can query what member attribute values can be set by
+ supplying the three attribute names: "xri-uri-scheme-supported",
+ "xri-authentication-supported", and "xri-security-supported" in a
+
+
+
+Hastings, et. al. Standards Track [Page 27]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Get-Printer-Supported-Values request and getting back the uriScheme
+ and type2 keyword values that can be set. Since the "printer-xri-
+ supported", "uri-authentication-supported", and "uri-security-
+ supported" attributes are READ-ONLY, they are not queriable with the
+ Get-Printer-Supported-Values operation (see section 4.3). See Table
+ 16.
+
+ For example:
+
+ "printer-xri-supported =
+ { "xri-uri" = ipp://abc.com/p1
+ "xri-authentication" = basic
+ "xri-security" = tls
+ },
+ { "xri-uri" = ipp://abc.com/p2
+ "xri-authentication" = digest
+ "xri-security" = tls
+ },
+ { "xri-uri" = ipp://abc.com/p3
+ "xri-authentication" = none
+ "xri-security" = none
+ }
+
+ would cause the Printer to set the three corresponding IPP/1.1 READ-
+ ONLY attributes, each with three parallel values as follows:
+
+ "printer-uri-supported" = { ipp://abc.com/p1, ipp://abc.com/p2,
+ ipp://abc.com/p3 }
+ "uri-authentication-supported" = { basic, digest, none }
+ "uri-security-supported" = { tls, tls, none }
+
+6.7 xri-uri-scheme-supported (1setOf uriScheme)
+
+ This OPTIONAL READ-ONLY Printer Description attribute identifies the
+ URI schemes that the implementation supports for use in the
+ "printer-uri-supported" (1setOf uri) Printer Description attribute
+ (see [RFC2911] section 4.4.1) and the "xri-uri" member attribute of
+ the "printer-xri-supported" (1setOf collection) Printer Description
+ attribute (see section 6.6).
+
+ A Printer MUST support this attribute if it supports the setting of
+ the "printer-xri-supported" (1setOf collection) with the Set-
+ Printer-Attributes operation.
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 28]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+6.8 xri-authentication-supported (1setOf type2 keyword)
+
+ This OPTIONAL READ-ONLY Printer Description attribute identifies the
+ Client Authentication mechanisms that the implementation supports for
+ use in the "uri-authentication-supported" (1setOf type2 keyword)
+ Printer Description attribute (see [RFC2911], section 4.4.2) and the
+ "xri-authentication" member attribute of the "printer-xri-supported"
+ (1setOf collection) Printer Description attribute (see section 6.6).
+
+ A Printer MUST support this attribute if it supports setting the
+ "printer-xri-supported" (1setOf collection) with the Set-Printer-
+ Attributes operation.
+
+6.9 xri-security-supported (1setOf type2 keyword)
+
+ This OPTIONAL READ-ONLY Printer Description attribute identifies the
+ URI schemes that the implementation supports for use in the "uri-
+ security-supported" (1setOf type2 keyword) Printer Description
+ attribute (see [RFC2911], section 4.4.3) and the "xri-security"
+ member attribute of the "printer-xri-supported" (1setOf collection)
+ Printer Description attribute (see section 6.6).
+
+ A Printer MUST support this attribute if it supports setting the
+ "printer-xri-supported" (1setOf collection) with the Set-Printer-
+ Attributes operation.
+
+7 Additional status codes
+
+ This section defines new status codes used by the operations defined
+ in this document.
+
+7.1 client-error-attributes-not-settable (0x0413)
+
+ The Set-Printer-Attributes or Set-Job-Attributes operation failed
+ because one or more of the specified attributes cannot be set, either
+ because the attribute is defined to be READ-ONLY or the attribute is
+ not settable in this implementation (see sections 4.1.3 and 4.2.3).
+ The Printer MUST return this error code and the attribute keyword
+ name(s) and the 'not-settable' out-of-band value (see section 8.1) in
+ the Unsupported Attributes Group (see [RFC2911], section 3.1.7) for
+ all of the attributes that could not be set. When the Printer
+ returns this status, it MUST NOT change any of the attributes
+ supplied in the operation.
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 29]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+8 Additional out-of-band values
+
+ This section defines additional out-of-band values. As with all
+ out-of-band values, a client or a Printer MUST NOT use an out-of-band
+ value unless the definition of the attribute in an operation request
+ and/or response explicitly allows such usage. See the beginning of
+ [RFC2911], section 4.1.
+
+8.1 'not-settable' out-of-band value
+
+ The 'not-settable' out-of-band attribute value is returned by the IPP
+ Printer in the Unsupported Attributes group of a response to indicate
+ that the attribute supplied by the client in the request is READ-ONLY
+ by definition or is not settable in this implementation.
+
+ The 'not-settable' out-of-band attribute value is defined for use
+ with the Set-Job-Attributes and Set-Printer-Attributes responses
+ only. If a future additional "set" operation allows the 'not-
+ settable' out-of-band value, its definition document MUST indicate
+ such use explicitly, including with which attributes.
+
+ An IPP object MUST support the 'not-settable' out-of-band value in a
+ Set-Job-Attributes or Set-Printer-Attributes request if it supports
+ those operations. A client MUST NOT supply the 'not-settable' out-
+ of-band value in any request. An IPP object MUST NOT support the
+ 'not-settable' out-of-band value in other operations, unless the
+ operations' definition document explicitly defines such usage. If a
+ Printer receives this out-of-band value in any operation request, the
+ Printer MUST either (1) reject the entire request and return the
+ 'client-error-bad-request' status code or (2) ignore the attribute
+ and return it with the 'unsupported' out-of-band value.
+
+ See sections 4.1.3 and 4.2.3 in this document for an example
+ definition of the usage of the 'not-settable' out-of-band value in
+ the Set-Printer-Attributes and Set-Job-Attributes responses.
+
+8.1.1 Encoding of the 'not-settable' out-of-band attribute value
+
+ The encoding of the 'not-settable' out-of-band value is 0x15 (see
+ [RFC2910]). The value-length MUST be 0 and the value empty.
+
+8.2 'delete-attribute' out-of-band value
+
+ The 'delete-attribute' out-of-band attribute value is supplied by the
+ client in a request to indicate that the Printer is to remove the
+ supplied attribute and all of its values from the target object, if
+ present.
+
+
+
+
+Hastings, et. al. Standards Track [Page 30]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ The 'delete-attribute' out-of-band attribute value is defined for use
+ with the Set-Job-Attributes request only. If a future additional
+ "set" operation allows the 'delete-attribute' out-of-band value, its
+ definition document MUST indicate such use explicitly, including with
+ which attributes.
+
+ An IPP Printer MUST support the 'delete-attribute' out-of-band value
+ if it supports the Set-Job-Attributes operation. A client MUST NOT
+ supply, and an IPP object MUST NOT support, the 'delete-attribute'
+ out-of-band value in other operations, unless the operations'
+ definition document explicitly defines such usage. For example, the
+ 'delete-attribute' out-of-band value MUST NOT be used in the Set-
+ Printer-Attributes operation, where the absence of an attribute from
+ an IPP object indicates that the attribute is not supported. If a
+ Printer receives this out-of-band value in other operation requests,
+ the Printer MUST either (1) reject the entire request and return the
+ 'client-error-bad-request' status code or (2) ignore the attribute
+ and return it with the 'unsupported' out-of-band value.
+
+ See section 4.2 in this document for the definition of the usage of
+ the 'delete-attribute' out-of-band value in the Set-Job-Attributes
+ request.
+
+8.2.1 Encoding of the 'delete-attribute' out-of-band value
+
+ The encoding of the 'delete-attribute' out-of-band value is 0x16 (see
+ [RFC2910]). The value-length MUST be 0 and the value empty.
+
+8.3 'admin-define' out-of-band attribute value
+
+ Section 4.3 defines the Get-Printer-Supported-Values response to
+ contain the values of an "xxx-supported" attribute that are supported
+ by the implementation before any additional values are defined by the
+ administrator. The 'admin-define' out-of-band attribute value is
+ returned as an additional value of an "xxx-supported" attribute in a
+ Get-Printer-Supported-Values response to indicate that the
+ implementation supports allowing an administrator to define
+ additional arbitrary 'name' values for that "xxx-supported"
+ attribute.
+
+ For example, if the "media-supported" (1setOf (type3 keyword | name))
+ attribute contains this value, then the Printer MUST permit an
+ administrator to add new media names to the Printer's "media-
+ supported" attribute. In order for an administrator to add new
+ values to a Printer's "xxx-supported" attribute, the client supplies
+ the existing and new values in a Set-Printer-Attributes request for
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 31]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ that attribute. The client MUST supply any such administratively
+ defined values in the Set-Printer-Attributes request, using the
+ 'name' attribute syntax.
+
+ The 'admin-define' out-of-band attribute value is defined for use
+ with the Get-Printer-Supported-Values response only. A Printer MUST
+ NOT return the 'admin-define' out-of-band value in a Get-Printer-
+ Attributes response, since such a response indicates what an end-user
+ client can supply in a Job Creation operation. If a future
+ additional "get" operation allows the 'admin-define' out-of-band
+ value, its definition document MUST indicate such use explicitly,
+ including with which attributes.
+
+ An IPP Printer MUST support the 'admin-define' out-of-band value, if
+ it supports a client setting arbitrary 'name' values of an "xxx-
+ supported" Printer attribute using the Set-Printer-Attributes
+ operation. A client MUST NOT supply the 'admin-define' out-of-band
+ value in any request. An IPP object MUST NOT support the 'admin-
+ define' out-of-band value in other operations, unless the operations'
+ definition document explicitly defines such usage. If a Printer
+ receives this out-of-band value in any operation request, the Printer
+ MUST either (1) reject the entire request and return the 'client-
+ error-bad-request' status code or (2) ignore the attribute and return
+ it with the 'unsupported' out-of-band value.
+
+ This document defines that the 'admin-define' out-of-band value MUST
+ be used only with "xxx-supported" attributes that are defined to
+ include the 'name' attribute syntax. This out-of-band value is not
+ intended to be used with "xxx-supported" attributes of other
+ attribute syntaxes, such as 'uri', even though the administrator
+ defines arbitrary values for such attributes. If other documents
+ extend the use of the 'admin-define' out-of-band value to other
+ attribute syntaxes, such a document MUST define such use explicitly,
+ including with which attributes.
+
+ See section 4.3 in this document for an example definition of the
+ usage of the 'admin-define' out-of-band attribute value in any "xxx-
+ supported" attribute returned in a Get-Printer-Supported-Values
+ response that is defined to include the 'name' attribute syntax.
+
+8.3.1 Encoding of the 'admin-define' out-of-band attribute value
+
+ The encoding of the 'admin-define' out-of-band attribute value is
+ 0x17 (see [RFC2910]). The value-length MUST be 0 and the value
+ empty.
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 32]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+9 New Values for Existing Printer Description Attributes
+
+ This section contains those attributes for which additional values
+ are added.
+
+9.1 operations-supported (1setOf type2 enum)
+
+ The following "operation-id" values are added in order to support the
+ new operations defined in this document:
+
+ Table 4 - Operation-id assignments
+
+ Value Operation Name
+
+ 0x0013 Set-Printer-Attributes
+
+ 0x0014 Set-Job-Attributes
+
+ 0x0015 Get-Printer-Supported-Values
+
+10 Conformance Requirements
+
+ This section specifies the conformance requirements for clients and
+ IPP objects.
+
+ Both the Set-Job-Attributes and the Set-Printer-Attributes operations
+ defined in the document are OPTIONAL for an IPP object to support.
+ Either one MAY be supported without the other or both MAY be
+ supported. However, if the Set-Printer-Attributes operation is
+ supported, then the Get-Printer-Supported-Values operation MUST be
+ supported if any "xxx-supported" attributes are settable. Otherwise,
+ the Get-Printer-Supported-Values operation is OPTIONAL for an IPP
+ Printer to support.
+
+ If the Set-Printer-Attributes operation is supported, then the
+ Printer MUST support the following additional items:
+
+ 1. the Get-Printer-Supported-Values operation (see section 5), if
+ any "xxx-supported" attributes are settable.
+
+ 2. the "printer-settable-attributes-supported" Printer Description
+ attribute (see section 6.1).
+
+ 3. the 'not-settable' out-of-band value in responses (see section
+ 8.1).
+
+ 4. the 'client-error-not-settable' status code (see section 7.1).
+
+
+
+
+Hastings, et. al. Standards Track [Page 33]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ 5. if the "printer-message-from-operator" Printer Description
+ attribute is supported (see [RFC2911], section 4.4.25), then it
+ MUST be settable.
+
+ 6. the Get-Printer-Supported-Values operation (see section 4.3),
+ if any "xxx-supported" attributes are settable.
+
+ 7. If a client can set a value with the 'name' attribute syntax
+ for one or more "xxx-supported" attributes, then the 'admin-
+ define' out-of-band attribute value (see section 8.3) MUST be
+ supported in the Get-Printer-Supported-Values response for each
+ such settable attribute (see section 4.3)
+
+ If the Set-Job-Attributes operation is supported, then the Printer
+ MUST support the following additional items:
+
+ 1. the "job-settable-attributes-supported" Printer Description
+ attribute (see section 6.2).
+
+ 2. the 'not-settable' out-of-band value in responses (see section
+ 8.1).
+
+ 3. the 'delete-attribute' out-of-band value in requests (see
+ section 8.2).
+
+ 4. the 'client-error-not-settable' status code (see section 7.1).
+
+ 5. if the "job-message-from-operator" Printer Description
+ attribute is supported (see [RFC2911], 4.3.16), then it MUST be
+ settable.
+
+ It is OPTIONAL for the Printer object to support the "printer-
+ message-time" (integer) and "printer-message-date-time" (dateTime)
+ Printer Description attributes. If both the "printer-message-time"
+ (integer) and the "printer-current-time" (dateTime) (see [RFC2911],
+ section 4.4.30) attributes are supported, then the "printer-message-
+ date-time" (dateTime) Printer Description attribute MUST be
+ supported.
+
+ As with all out-of-band values, a client or a Printer MUST NOT use an
+ out-of-band value, unless the definition document for the attribute
+ in an operation request and/or response explicitly allows such usage.
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 34]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+11 IANA Considerations
+
+ This section contains registration information for IANA to add to the
+ various IPP Registries according to the procedures defined in RFC
+ 2911 [RFC2911], section 6. The resulting registrations will be
+ published in the http://www.iana.org/assignments/ipp-registrations
+ registry.
+
+11.1 Operation Registrations
+
+ The following table lists all of the operations defined in this
+ document. These are to be registered according to the procedures
+ defined in RFC 2911 [RFC2911], section 6.4.
+
+ Operations: Ref. Section:
+ Set-Printer-Attributes RFC 3380 4.1
+ Set-Job-Attributes RFC 3380 4.2
+ Get-Printer-Supported-Values RFC 3380 4.3
+
+11.2 Additional Enum Attribute Value Registrations for the
+ "operations-supported" Printer Attribute
+
+ The following table lists all the new enum attribute values defined
+ in this document as additional type2 enum values for use with the
+ "operations-supported" Printer Description attribute. These are to
+ be registered according to the procedures defined in RFC 2911 [RFC
+ 2911], section 6.1.
+
+ Enum Attribute Values: Value Ref. Section:
+ Set-Printer-Attributes 0x0013 RFC 3380 4
+ Set-Job-Attributes 0x0014 RFC 3380 4
+ Get-Printer-Supported-Values 0x0015 RFC 3380 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 35]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+11.3 Keyword attribute value registrations
+
+ The following table lists all of the attributes defined in this
+ standard which have keywords values defined:
+
+ printer-settable-attributes-supported (1setOf type2 keyword)
+ RFC 3380 6.1
+ none RFC 3380 6.1
+ <Any other Printer attribute keyword name>
+ job-settable-attributes-supported (1setOf type2 keyword)
+ RFC 3380 6.2
+ none RFC 3380 6.2
+ <Any other Job attribute keyword name>
+ document-format-varying-attributes (1setOf type2 keyword)
+ RFC 3380 6.3
+ none
+ <Any Printer attribute keyword name>
+ xri-security-supported (1setOf type2 keyword) RFC 3380 6.9
+ none RFC 2911 4.4.3
+ ssl3 RFC 2911 4.4.3
+ tls' RFC 2911 4.4.3
+ xri-authentication-supported (1setOf type2 keyword)
+ none RFC 2911 4.4.2
+ requesting-user-name RFC 2911 4.4.2
+ basic RFC 2911 4.4.2
+ digest RFC 2911 4.4.2
+ certificate RFC 2911 4.4.2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 36]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+11.4 Attribute Registrations
+
+ The following table lists all of the attributes defined in this
+ document. These are to be registered according to the procedures in
+ RFC 2911 [RFC2911], section 6.2.
+
+ Operation attributes: Ref. Section:
+ printer-message-from-operator (text(127)) RFC 3380 5.1
+ job-message-from-operator (text(127)) RFC 3380 5.2
+
+ Printer Description attributes: Ref. Section:
+ printer-settable-attributes-supported (1setOf type2 keyword)
+ RFC 3380 6.1
+ job-settable-attributes-supported (1setOf type2 keyword)
+ RFC 3380 6.2
+ document-format-varying-attributes (1setOf type2 keyword)
+ RFC 3380 6.3
+ printer-message-time (integer(MIN:MAX)) RFC 3380 6.4
+ printer-message-date-time (dateTime) RFC 3380 6.5
+ printer-xri-supported (1setOf collection) RFC 3380 6.6
+ xri-uri (uri) RFC 3380 6.6
+ xri-authentication (type2 keyword) RFC 3380 6.6
+ xri-security (type2 keyword) RFC 3380 6.6
+ xri-uri-scheme-supported (1setOf uriScheme) RFC 3380 6.7
+ xri-authentication-supported (1setOf type2 keyword) 6.8
+ xri-security-supported (1setOf type2 keyword) RFC 3380 6.9
+
+11.5 Status code Registrations
+
+ The following table lists the status code defined in this document.
+ This is to be registered according to the procedures in RFC 2911
+ [RFC2911], section 6.6.
+
+ Status codes: Ref. Section:
+ client-error-attributes-not-settable (0x0413) RFC 3380 7.1
+
+11.6 Out-of-band Attribute Value Registrations
+
+ The following table lists all of the out-of-band attribute values
+ defined in this document. These are to be registered according to
+ the procedures in RFC 2911 [RFC2911] section 6.7.
+
+ Value: Out-of-band Attribute value name: Ref. Section:
+ 0x15 not-settable RFC 3380 8.1
+ 0x16 delete-attribute RFC 3380 8.2
+ 0x17 admin-define RFC 3380 8.3
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 37]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+12 Internationalization Considerations
+
+ This document has the same localization considerations as [RFC2911].
+
+13 Security Considerations
+
+ The IPP Model and Semantics document ([RFC2911], section 8) discusses
+ high level security requirements (Client Authentication, Server
+ Authentication and Operation Privacy). Client Authentication is the
+ mechanism by which the client proves its identity to the server in a
+ secure manner. Server Authentication is the mechanism by which the
+ server proves its identity to the client in a secure manner.
+ Operation Privacy is defined as a mechanism for protecting operations
+ from eavesdropping.
+
+ In addition, the introduction of the Set-Printer-Attributes and Set-
+ Job-Attributes operations creates another security threat, since the
+ client is able to modify the Printer and Job attributes stored in the
+ Printer. Such modifications could lead to denial of service.
+
+ A malicious user could alter the policy established by the system
+ administrator and stored in the Printer attributes. Such alteration
+ could either grant access to more resources or deny access to
+ resources that the system administrator has established. For
+ example, the malicious user could remove all of the document-format
+ values from the "document-format-supported" Printer attribute so that
+ the Printer would refuse to accept all jobs.
+
+ The general remedy for such malicious user actions against Printer
+ attributes is to have strong Client Authentication coupled with
+ Printer access control, to limit the users who have System
+ Administrator or Operator privileges.
+
+ A malicious user could modify the Job Template attributes of another
+ user's Job, such as the "copies" attribute. For example, setting the
+ number of copies to a large number.
+
+ The general remedy for such malicious user actions against another
+ user's job is to have strong Client Authentication coupled with
+ Printer access control to limit the users who have System
+ Administrator or Operator privileges who can modify any job and, in
+ addition, store the Client Authentication with each Job so that only
+ the job owner End User can modify his/her own job.
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 38]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+14 References
+
+14.1 Normative References
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Tuner, "Internet
+ Printing Protocol/1.0: Encoding and Transport", RFC 2565,
+ April 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P. and R. Turner,
+ "Internet Printing Protocol/1.1: Encoding and Transport",
+ RFC 2910, September 2000.
+
+ [RFC2911] Hastings, T., Herriot, R., deBry, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2911, September 2000.
+
+ [RFC3382] deBry, R., Hastings, T., Herriot, R., Ocke, K. and P.
+ Zehler, "Internet Printing Protocol (IPP): The
+ 'collection' attribute syntax", RFC 3382, September 2002.
+
+14.2 Informative References
+
+ [RFC2251] Wahl, M., Howes, T. abd S. Kille, "Lightweight Directory
+ Access Protocol (v3)", RFC 2251, December 1997.
+
+ [RFC2252] Wahl, M., Coulbeck, A., Howes, T. and S. Kille,
+ "Lightweight Directory Access Protocol (v3): Attribute
+ Syntax Definitions", RFC 2252, December 1997.
+
+ [RFC2608] Guttman, E., Perkins, C., Veizades, J. and M. Day,
+ "Service Location Protocol, Version 2", RFC 2608, June
+ 1999.
+
+ [RFC2609] Guttman, E., Perkins, C. and J. Kempf, "Service Templates
+ and service: Schemes", RFC 2609, June 1999.
+
+ [RFC3196] Hastings, T., Manros, C., Zehler, P., Kugler, C. and H.
+ Holst, "Internet Printing Protocol/1.1: Implementor's
+ Guide", RFC 3196, November 2001.
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 39]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+Appendix A: Allowed Values for Set-Printer-Attributes and
+ Set-Job-Attributes requests (Normative)
+
+ This appendix is a normative part of this document and contains a
+ table of all IPP/1.1 attributes. Each row contains:
+
+ - an attribute and
+
+ - the values allowed in the Set-Printer-Attributes or Set-Job-
+ Attributes request for the attribute. The entry in each cell
+ is the name (first few words) of each item below 1, 2, 3, 4a-g,
+ and 5.
+
+ The allowed values include the following cases:
+
+ 1. READ-ONLY: the Set-Printer-Attributes or Set-Job-Attributes
+ operation MUST NOT change this attribute and MUST reject the
+ entire operation (see section 7.1).
+
+ 2. Any of "xxx-supported": the Set-Printer-Attributes or Set-
+ Job-Attributes operation accepts values that are allowed
+ according to the IPP/1.1 rules for validating the value(s) of
+ an "xxx" Printer or Job attribute against the value(s) of the
+ corresponding "xxx-supported" Printer attribute. Table 5
+ summarizes those validation rules depending on each attribute
+ syntax and value of an "xxx" attribute supplied in the request
+ and that of the corresponding "xxx-supported" Printer
+ attribute. The "xxx-supported" attribute syntax type and
+ value(s) are obtained from a Get-Printer-Supported-Values
+ response (see the tables in this Appendix).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 40]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Table 5 - Validation rules for 'Any of "xxx-supported" '
+
+ Type of "xxx" Type of "xxx- Validates if:
+ value to be supported" value
+ set
+
+ integer rangeOfInteger each value is in one of the
+ "xxx-supported" ranges
+
+ uri uriScheme each uri scheme matches one
+ of the "xxx-supported"
+ schemes
+
+ any boolean if the boolean "xxx-
+ supported" is 'true'
+
+ any same type each value matches an "xxx-
+ supported" value of the same
+ type
+
+ For additional non-normative explanatory information see section
+ 3.1.2.3 of the "Internet Printing Protocol/1.1: Implementer's Guide"
+ [RFC3196].
+
+ 3. From Get-Printer-Supported-Values: the Set-Printer-Attributes
+ operation accepts values that are allowed according to the
+ IPP/1.1 rules for validating the value(s) of an "xxx" Printer
+ attribute against the value(s) of the corresponding "xxx-
+ supported" Printer attribute. Table 6 summarizes those
+ validation rules depending on each attribute syntax and value
+ of an "xxx" attribute supplied in the request and that of the
+ corresponding "xxx-supported" Printer attribute. The "xxx-
+ supported" attribute syntax type and attribute value(s) are
+ obtained from a Get-Printer-Supported-Values response (see
+ Appendix B: Attributes returned from Get-Printer-Supported-
+ Values below).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 41]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Table 6 - Validation rules for 'From Get-Printer-Supported-Values'
+
+ Type of -
+ "xxx" supported" value Validates if:
+ value to
+ be set Type of "xxx
+
+
+ integer rangeOfInteger each 'integer' value is in one of
+ the "xxx-supported" ranges
+
+ uri uriScheme the uri scheme of each value
+ matches one of the "xxx-supported"
+ schemes
+
+ any boolean if the boolean "xxx-supported" is
+ 'true'
+
+ name 'admin-define' any 'name' value matches
+ out-of-band
+ value
+
+ any same type each value matches an "xxx-
+ supported" value of the same type
+
+ For additional non-normative explanatory information see section
+ 3.1.2.3 of the "Internet Printing Protocol/1.1: Implementer's Guide"
+ [RFC3196].
+
+ 4. Any value of the proper attribute syntax: the Set-Printer-
+ Attributes or Set-Job-Attributes operation accepts any value of
+ the specified attribute syntax. The attribute syntaxes
+ supported are enumerated below.
+
+ a. Any text(127)
+ b. Any name(127)
+ c. Any uri
+ d. Any boolean
+ e. Any positive integer
+ f. Any dateTime
+ g. 1setOf any uri
+
+ 5. Combination of 'Any of "xxx-supported"' or 'Any name'. If a
+ Printer implementation doesn't want to allow setting values
+ indicated in this Appendix as "any xxx", it can make the value
+ be not-settable.
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 42]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Table 7 - Values allowed for Job Template Attributes in the
+ Set-Job-Attributes Operation
+
+ Job Template Attributes Values allowed for
+ Set
+
+ job-priority (integer(1:100)) Any of "xxx-
+ supported"
+
+ job-hold-until (type3 keyword | name (MAX)) Any of "xxx-
+ supported"
+
+ job-sheets (type3 keyword | name(MAX)) Any of "xxx-
+ supported"
+
+ multiple-document-handling (type2 keyword) Any of "xxx-
+ supported"
+
+ copies (integer(1:MAX)) Any of "xxx-
+ supported"
+
+ finishings (1setOf type2 enum) Any of "xxx-
+ supported"
+
+ page-ranges (1setOf rangeOfInteger (1:MAX)) Any of "xxx-
+ supported"
+
+ sides (type2 keyword) Any of "xxx-
+ supported"
+
+ number-up (integer(1:MAX)) Any of "xxx-
+ supported"
+
+ orientation-requested (type2 enum) Any of "xxx-
+ supported"
+
+ media (type3 keyword | name(MAX)) Any of "xxx-
+ supported"
+
+ printer-resolution (resolution) Any of "xxx-
+ supported"
+
+ print-quality (type2 enum) Any of "xxx-
+ supported"
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 43]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Table 8 - Values allowed for Job Description Attributes in the
+ Set-Job-Attributes Operation
+
+ Job Description Attributes Values allowed for
+ Set
+
+ job-uri (uri) READ-ONLY
+
+ job-id (integer(1:MAX)) READ-ONLY
+
+ job-printer-uri (uri) READ-ONLY
+
+ job-more-info (uri) READ-ONLY
+
+ job-name (name(MAX)) Any name(MAX)
+
+ job-originating-user-name (name(MAX)) READ-ONLY
+
+ job-state (type1 enum) READ-ONLY
+
+ job-state-reasons (1setOf type2 keyword) READ-ONLY
+
+ job-state-message (text(MAX)) READ-ONLY
+
+ job-detailed-status-messages (1setOf READ-ONLY
+ text(MAX))
+
+ job-document-access-errors (1setOf READ-ONLY
+ text(MAX))
+
+ number-of-documents (integer(0:MAX)) READ-ONLY
+
+ output-device-assigned (name(127)) READ-ONLY
+
+ time-at-creation (integer(MIN:MAX)) READ-ONLY
+
+ time-at-processing (integer(MIN:MAX)) READ-ONLY
+
+ time-at-completed (integer(MIN:MAX)) READ-ONLY
+
+ job-printer-up-time (integer(1:MAX)) READ-ONLY
+
+ date-time-at-creation (dateTime) READ-ONLY
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 44]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Job Description Attributes Values allowed for
+ Set
+
+ date-time-at-processing (dateTime) READ-ONLY
+
+ date-time-at-completed (dateTime) READ-ONLY
+
+ number-of-intervening-jobs (integer(0:MAX)) READ-ONLY
+
+ job-message-from-operator (text(127)) Any text(127)
+
+ job-k-octets (integer(0:MAX)) READ-ONLY
+
+ job-impressions (integer(0:MAX)) READ-ONLY
+
+ job-media-sheets (integer(0:MAX)) READ-ONLY
+
+ job-k-octets-processed (integer(0:MAX)) READ-ONLY
+
+ job-impressions-completed (integer(0:MAX)) READ-ONLY
+
+ job-media-sheets-completed (integer(0:MAX)) READ-ONLY
+
+ attributes-charset (charset) READ-ONLY
+
+ attributes-natural-language READ-ONLY
+ (naturalLanguage)
+
+ Table 9 - Values allowed for Printer Job Template Attributes in
+ the Set-Printer-Attributes Operation
+
+ Printer Job Template Attributes Values allowed
+ for Set
+
+ job-priority-default (integer(1:100)) Any of "xxx-
+ supported"
+
+ job-hold-until-default (type3 keyword | name Any of "xxx-
+ (MAX)) supported"
+
+ job-sheets-default (type3 keyword | name(MAX)) Any of "xxx-
+ supported"
+
+ multiple-document-handling-default (type2 Any of "xxx-
+ keyword) supported"
+
+ copies-default (integer(1:MAX)) Any of "xxx-
+ supported"
+
+
+
+Hastings, et. al. Standards Track [Page 45]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Printer Job Template Attributes Values allowed
+ for Set
+
+ finishings-default (1setOf type2 enum) Any of "xxx-
+ supported"
+
+ sides-default (type2 keyword) Any of "xxx-
+ supported"
+
+ number-up-default (integer(1:MAX)) Any of "xxx-
+ supported"
+
+ orientation-requested-default (type2 enum) Any of "xxx-
+ supported"
+
+ media-default (type3 keyword | name(MAX)) Any of "xxx-
+ supported"
+
+ printer-resolution-default (resolution) Any of "xxx-
+ supported"
+
+ print-quality-default (type2 enum) Any of "xxx-
+ supported"
+
+ job-priority-supported (integer(1:100)) From Get-
+ Printer-
+ Supported-Values
+
+ job-hold-until-supported (1setOf(type3 keyword From Get-
+ | name (MAX))) Printer-
+ Supported-Values
+
+ job-sheets-supported (1setOf(type3 keyword | From Get-
+ name(MAX))) Printer-
+ Supported-Values
+
+ multiple-document-handling-supported (1setOf From Get-
+ type2 keyword) Printer-
+ Supported-Values
+
+ copies-supported (rangeOfInteger(1:MAX)) From Get-
+ Printer-
+ Supported-Values
+
+ finishings-supported (1setOf type2 enum) From Get-
+ Printer-
+ Supported-Values
+
+
+
+
+Hastings, et. al. Standards Track [Page 46]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Printer Job Template Attributes Values allowed
+ for Set
+
+ page-ranges-supported (boolean) From Get-
+ Printer-
+ Supported-Values
+
+ sides-supported (1setOf type2 keyword) From Get-
+ Printer-
+ Supported-Values
+
+ number-up-supported (1setOf (integer(1:MAX) | From Get-
+ rangeOfInteger(1:MAX))) Printer-
+ Supported-Values
+
+ orientation-requested-supported (1setOf type2 From Get-
+ enum) Printer-
+ Supported-Values
+
+ media-supported (1setOf (type3 keyword | From Get-
+ name(MAX))) Printer-
+ Supported-Values
+
+ printer-resolution-supported (1setOf From Get-
+ resolution) Printer-
+ Supported-Values
+
+ print-quality-supported (1setOf type2 enum) From Get-
+ Printer-
+ Supported-Values
+
+ media-ready (type3 keyword | name(MAX)) From Get-
+ Printer-
+ Supported-Values
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 47]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Table 10 - Values allowed for Printer Description Attributes in
+ the Set-Printer-Attributes Operation
+
+ Printer Description Attributes Values allowed for
+ Set
+
+ printer-uri-supported (1setOf uri) READ-ONLY
+
+ uri-authentication-supported (1setOf type2 READ-ONLY
+ keyword)
+
+ uri-security-supported (1setOf type2 READ-ONLY
+ keyword)
+
+ printer-xri-supported (1setOf collection)
+ member attributes:
+
+ xri-uri (uri) any uriScheme of
+ "xri-uri-scheme-
+ supported" from
+ Get-Printer-
+ Attributes
+
+ xri-authentication (type2 keyword) any keyword of
+ "xri-
+ authentication-
+ supported" from
+ Get-Printer-
+ Attributes
+
+ xri-security (type2 keyword) any keyword of
+ "xri-security-
+ supported" from
+ Get-Printer-
+ Attributes
+
+ xri-uri-scheme-supported (1setOf uriScheme) READ-ONLY
+
+ xri-authentication-supported (1setOf type2 READ-ONLY
+ keyword)
+
+ xri-security-supported (1setOf type2 READ-ONLY
+ keyword)
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 48]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Printer Description Attributes Values allowed for
+ Set
+
+ printer-name (name(127)) Any name(127)
+
+ printer-location (text(127)) Any text(127)
+
+ printer-info (text(127)) Any text(127)
+
+ printer-more-info (uri) Any uri
+
+ printer-driver-installer (uri) Any uri
+
+ printer-make-and-model (text(127)) Any text(127)
+
+ printer-more-info-manufacturer (uri) Any uri
+
+ printer-state (type1 enum) READ-ONLY
+
+ printer-state-reasons (1setOf type2 READ-ONLY
+ keyword)
+
+ printer-state-message (text(MAX)) READ-ONLY
+
+ ipp-versions-supported (1setOf type2 From Get-Printer-
+ keyword) Supported-Values
+
+ operations-supported (1setOf type2 enum) From Get-Printer-
+ Supported-Values
+
+ multiple-document-jobs-supported (boolean) From Get-Printer-
+ Supported-Values
+
+ charset-configured (charset) Any of "xxx-
+ supported", use
+ "charset-supported"
+
+ charset-supported (1setOf charset) From Get-Printer-
+ Supported-Values
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 49]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Printer Description Attributes Values allowed for
+ Set
+
+ natural-language-configured Any of "xxx-
+ (naturalLanguage) supported", use
+ "generated-natural-
+ language-supported"
+
+ generated-natural-language-supported From Get-Printer-
+ (1setOf naturalLanguage) Supported-Values
+
+ document-format-default (mimeMediaType) Any of "xxx-
+ supported"
+
+ document-format-supported (1setOf From Get-Printer-
+ mimeMediaType) Supported-Values
+
+ printer-is-accepting-jobs (boolean) READ-ONLY
+
+ queued-job-count (integer(0:MAX)) READ-ONLY
+
+ printer-message-from-operator (text(127)) Any text(127)
+
+ color-supported (boolean) From Get-Printer-
+ Supported-Values
+
+ reference-uri-schemes-supported (1setOf From Get-Printer-
+ uriScheme) Supported-Values
+
+ pdl-override-supported (type2 keyword) From Get-Printer-
+ Supported-Values
+
+ printer-up-time (integer(1:MAX)) READ-ONLY
+
+ printer-current-time (dateTime) Any dateTime **
+
+ multiple-operation-time-out any positive
+ (integer(1:MAX)) integer
+
+ compression-supported (1setOf type3 From Get-Printer-
+ keyword) Supported-Values
+
+ job-k-octets-supported From Get-Printer-
+ (rangeOfInteger(0:MAX)) Supported-Values
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 50]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Printer Description Attributes Values allowed for
+ Set
+
+ job-impressions-supported From-Get-Printer-
+ (rangeOfInteger(0:MAX)) Supported-Values
+
+ job-media-sheets-supported From Get-Printer-
+ (rangeOfInteger(0:MAX)) Supported-Values
+
+ pages-per-minute (integer(0:MAX)) READ-ONLY
+
+ pages-per-minute-color (integer(0:MAX)) READ-ONLY
+
+ printer-settable-attributes-supported From Get-Printer-
+ (1setOf type2 keyword) Supported-Values
+
+ job-settable-attributes-supported (1setOf From Get-Printer-
+ type2 keyword) Supported-Values
+
+ document-format-varying-attributes (1setOf READ-ONLY
+ type2 keyword)
+
+ printer-message-time (integer(MIN:MAX)) READ-ONLY
+
+ printer-message-date-time(dateTime) READ-ONLY
+
+ ** - The "printer-current-time" (dateTime) attribute is settable in
+ order to allow an administrator to correct an incorrect dateTime or
+ time zone.
+
+Appendix B: Attributes returned from Get-Printer-Supported-Values
+ (Normative)
+
+ This Appendix is a normative part of this document and lists all the
+ attributes that are possible for an implementation to return in a
+ Get-Printer-Supported-Values response, i.e., all the "xxx-supported"
+ attributes that can be supplied in a Set-Printer-Attributes request.
+ READ-ONLY attributes MUST NOT be returned in a Get-Printer-
+ Supported-Values response and are indicated in the tables as "READ-
+ ONLY - MUST NOT be returned."
+
+ For the following attributes, the value allowed by the Set-Printer-
+ Attributes operation MUST be a single integer value in the range
+ specified by the value returned by the Get-Printer-Supported-Values
+ operation.
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 51]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Table 11 - Printer Job Template Attributes returned from
+ Get-Printer-Supported-Values
+
+ Printer Job Template Attributes Values Returned
+
+ job-priority-supported (integer(1:100)) rangeOfInteger(1:100)
+
+ For the following attributes, the value allowed by the Set-Printer-
+ Attributes operation MUST be a single rangeOfInteger value whose
+ bounds do not exceed those of the range specified by the value
+ returned by the Get-Printer-Supported-Values operation.
+
+ Table 12 - Printer Job Template Attributes returned from
+ Get-Printer-Supported-Values
+
+ Printer Job Template Attributes Values Returned
+
+ copies-supported (rangeOfInteger(1:MAX)) rangeOfInteger(1:MAX)
+
+ The following table has the same criteria as the last, but is for
+ Printer Description attributes.
+
+ Table 13 - Printer Description Attributes returned from
+ Get-Printer-Supported-Values
+
+ Printer Description Attributes Values allowed for Set
+
+ job-k-octets-supported rangeOfInteger(0:MAX)
+ (rangeOfInteger(0:MAX))
+
+ job-impressions-supported
+ (rangeOfInteger(0:MAX)) rangeOfInteger(0:MAX)
+
+ job-media-sheets-supported rangeOfInteger(0:MAX)
+ (rangeOfInteger(0:MAX))
+
+ For the following attributes, the value allowed by the Set-Printer-
+ Attributes operation MUST be one or more integers and rangeOfInteger
+ values, such that the integer values described by these integers and
+ rangeOfInteger is the same as or a subset of the integers described
+ by the integers and rangeOf Integer of values returned by the Get-
+ Printer-Supported-Values operation.
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 52]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Table 14 - Printer Job Template Attributes returned from
+ Get-Printer-Supported-Values
+
+ Printer Job Template Attributes Values Returned
+
+ number-up-supported (1setOf (integer(1:MAX) 1setOf
+ | rangeOfInteger(1:MAX))) (integer(1:MAX) |
+ rangeOfInteger(1:MA
+ X))
+
+ For the following attributes, the value allowed by the Set-Printer-
+ Attributes operation MUST be one or more values, where each such
+ value matches a value returned by the Get-Printer-Supported-Values
+ operation. A keyword, enum, boolean, charset, naturalLanguage,
+ uriScheme, mimeMediaType or resolution value matches if it is equal.
+ For Job Template attributes, with the attribute syntax 'type3 keyword
+ | name', any 'name' attribute syntax value matches the 'admin-define'
+ out-of-band value, if the implementation allows the administrator to
+ set any name values for the attribute.
+
+ Table 15 - Printer Job Template Attributes returned from
+ Get-Printer-Supported-Values
+
+ Printer Job Template Attributes Values Returned
+
+ job-hold-until-supported (1setOf(type3 1setOf (type3
+ keyword | name (MAX))) keyword | 'admin-
+ define')
+
+ job-sheets-supported (1setOf(type3 keyword 1setOf (type3
+ | name(MAX))) keyword | 'admin-
+ define')
+
+ multiple-document-handling-supported 1setOf type2
+ (1setOf type2 keyword) keyword
+
+ finishings-supported (1setOf type2 enum) 1setOf type2 enum
+
+ page-ranges-supported (boolean) 1setOf boolean **
+
+ sides-supported (1setOf type2 keyword) 1setOf type2
+ keyword
+
+ orientation-requested-supported (1setOf 1setOf type2 enum
+ type2 enum)
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 53]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Printer Job Template Attributes Values Returned
+
+ media-supported (1setOf (type3 keyword | 1setOf (type3
+ name(MAX))) keyword | 'admin-
+ define')
+
+ printer-resolution-supported (1setOf 1setOf resolution
+ resolution)
+
+ print-quality-supported (1setOf type2 enum) 1setOf type2 enum
+
+ ** Note: the Get-Printer-Supported-Values returns a '1setOf boolean'
+ so that all possible values are indicated, while ** Get-Printer-
+ Attributes returns only a single 'boolean' value.
+
+ The following table has the same criteria as the last, but is for
+ Printer Description attributes.
+
+ Table 16 - Printer Description Attributes returned from
+ Get-Printer-Supported-Values
+
+ Printer Description Attributes Values allowed for
+ Set
+
+ printer-uri-supported (1setOf uri) READ-ONLY - MUST
+ NOT be returned
+
+ uri-authentication-supported (1setOf type2 READ-ONLY - MUST
+ keyword) NOT be returned
+
+ uri-security-supported (1setOf type2 READ-ONLY - MUST
+ keyword) NOT be returned
+
+ printer-xri-supported (1setOf collection) MUST NOT be
+ returned; see next
+ three attributes
+ returned with Get-
+ Printer-Attributes:
+
+ xri-uri-scheme-supported (1setOf uriScheme) READ-ONLY - MUST
+ NOT be returned
+
+ xri-authentication-supported (1setOf type2 READ-ONLY - MUST
+ keyword) NOT be returned
+
+ xri-security-supported (1setOf type2 READ-ONLY - MUST
+ keyword) NOT be returned
+
+
+
+
+Hastings, et. al. Standards Track [Page 54]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ Printer Description Attributes Values allowed for
+ Set
+
+ ipp-versions-supported (1setOf type2 1setOf type2
+ keyword) keyword
+
+ operations-supported (1setOf type2 enum) 1setOf type2
+ keyword
+
+ multiple-document-jobs-supported (boolean) 1setOf boolean **
+
+ charset-supported (1setOf charset) 1setOf charset
+
+ generated-natural-language-supported 1setOf
+ (1setOf naturalLanguage) naturalLanguage
+
+ document-format-supported (1setOf 1setOf
+ mimeMediaType) mimeMediaType
+
+ color-supported (boolean) 1setOf boolean **
+
+ reference-uri-schemes-supported (1setOf 1setOf uriScheme
+ uriScheme)
+
+ pdl-override-supported (type2 keyword) 1setOf type2
+ keyword **
+
+ compression-supported (1setOf type3 1setOf type3
+ keyword) keyword
+
+ printer-settable-attributes-supported 1setOf type2
+ (1setOf type2 keyword) keyword
+
+ job-settable-attributes-supported (1setOf 1setOf type2
+ type2 keyword) keyword
+
+ ** Note: the Get-Printer-Supported-Values returns a '1setOf X' so
+ that all possible values are indicated, while Get-Printer-Attributes
+ returns only a single 'X' value.
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 55]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+Appendix C: Description of the Base IPP Documents (Informative)
+
+ The base set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [RFC3196]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0 [RFC2566, RFC2565]. A few OPTIONAL operator
+ operations have been added to IPP/1.1 [RFC2911, RFC2910].
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF IPP working group's major decisions.
+
+ The "Internet Printing Protocol/1.1: Model and Semantics" document
+ describes a simplified model with abstract objects, their attributes,
+ and their operations. The model introduces a Printer and a Job. The
+ Job supports multiple documents per Job. The model document also
+ addresses how security, internationalization, and directory issues
+ are addressed.
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1 [RFC2616]. It also defines the
+ encoding rules for a new Internet MIME media type called
+ "application/ipp". This document also defines the rules for
+ transporting over HTTP, a message body whose Content-Type is
+ "application/ipp". This document defines the 'ipp' scheme for
+ identifying IPP printers and jobs.
+
+ The "Internet Printing Protocol/1.1: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.1 and some of
+ the considerations that may assist them in the design of their client
+
+
+
+
+Hastings, et. al. Standards Track [Page 56]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions are also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+Authors' Addresses
+
+ Carl Kugler
+ IBM
+ P.O. Box 1900
+ Boulder, CO 80301-9191
+
+ Phone: (303) 924-5060
+ EMail: kugler@us.ibm.com
+
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ EMail: hastings@cp10.es.xerox.com
+
+
+ Robert Herriot
+ Consultant
+ 706 Colorado Ave
+ Palo Alto, CA 94303
+
+ Phone: 650-327-4466
+ Fax: 650-327-4466
+ EMail: bob@Herriot.com
+
+
+ Harry Lewis
+ IBM
+ 6300 Diagonal Hwy.
+ Boulder, CO 80301-9191
+
+ Phone: (303) 924-5337
+ EMail: harryl@us.ibm.com
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 57]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+ IPP Web Page: http://www.pwg.org/ipp/
+ IPP Mailing List: ipp@pwg.org
+
+ To subscribe to the ipp mailing list, send the following email:
+
+ 1) send it to majordomo@pwg.org
+ 2) leave the subject line blank
+ 3) put the following two lines in the message body:
+ subscribe ipp
+ end
+
+ Implementers of this specification document are encouraged to join
+ the IPP Mailing List in order to participate in any discussions of
+ clarification issues and review of registration proposals for
+ additional attributes and values. In order to reduce spam the
+ mailing list rejects mail from non-subscribers, so you must subscribe
+ to the mailing list in order to send a question or comment to the
+ mailing list.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 58]
+
+RFC 3380 IPP: Job and Printer Set Operations September 2002
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 59]
+
diff --git a/standards/rfc3381.txt b/standards/rfc3381.txt
new file mode 100644
index 000000000..d7fd60f81
--- /dev/null
+++ b/standards/rfc3381.txt
@@ -0,0 +1,955 @@
+
+
+
+
+
+
+Network Working Group T. Hastings
+Request for Comments: 3381 Xerox Corporation
+Updates: 2910 H. Lewis
+Category: Standards Track IBM Printing Company
+ R. Bergman
+ Hitachi Koki Imaging Solutions
+ September 2002
+
+
+ Internet Printing Protocol (IPP):
+ Job Progress Attributes
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+Abstract
+
+ This document defines four new Job Description attributes for
+ monitoring job progress to be registered as OPTIONAL extensions to
+ the Internet Printing Protocol (IPP/1.0 and IPP/1.1). These
+ attributes are drawn from the PWG Job Monitoring MIB. This document
+ also defines a new "sheet-collate" Job Template attribute to control
+ sheet collation and to help with the interpretation of the job
+ progress attributes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 1]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+Table of Contents
+
+ 1 Introduction.....................................................2
+ 2 Terminology......................................................2
+ 2.1 Conformance Terminology........................................4
+ 2.2 Other terminology..............................................4
+ 3 Job Template attributes..........................................4
+ 3.1 sheet-collate (type2 keyword)..................................4
+ 4 IPP Job Description attributes for monitoring Job Progress.......6
+ 4.1 job-collation-type (type2 enum)................................9
+ 4.2 sheet-completed-copy-number (integer(0:MAX))..................11
+ 4.3 sheet-completed-document-number (integer(0:MAX))..............11
+ 4.4 impressions-completed-current-copy (integer(0:MAX))...........11
+ 5 Conformance Requirements........................................11
+ 6 IANA Considerations.............................................12
+ 6.1 Attributes....................................................
+ 6.2 Keyword Attribute Values......................................
+ 6.3 Enum Attribute Values.........................................
+ 7 Internationalization Considerations.............................12
+ 8 Security Considerations.........................................12
+ 9 References......................................................12
+ 10 Description of the Base IPP Documents..........................13
+ 11 Authors' Addresses.............................................15
+ 12 Full Copyright Statement.......................................16
+
+1 Introduction
+
+ This document defines four new Job Description attributes for
+ monitoring job progress to be registered as OPTIONAL extensions to
+ IPP/1.0 [RFC2566] and IPP/1.1 [RFC2911]. These attributes are drawn
+ from the PWG Job Monitoring MIB [RFC2707]. See section 10 for a
+ description of the base IPP documents. The new Job Description
+ attributes are:
+
+ "job-collation-type" (type2 enum)
+ "sheet-completed-copy-number" (integer(0:MAX))
+ "sheet-completed-document-number" (integer(0:MAX))
+ "impressions-completed-current-copy" (integer(0:MAX))
+
+ This document also defines a new "sheet-collate" Job Template
+ attribute to control sheet collation and to help with the
+ interpretation of the job progress attributes. These new attributes
+ may also be used by themselves in combination with the IPP/1.1 "job-
+ impressions-completed" attribute, as useful job progress monitoring
+ attributes and/or may be passed in an IPP Notification (see [ipp-
+ ntfy]).
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 2]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+2 Terminology
+
+ This section defines terminology used throughout this document.
+
+2.1 Conformance Terminology
+
+ Capitalized terms, such as MUST, MUST NOT, REQUIRED, SHOULD, SHOULD
+ NOT, MAY, NEED NOT, and OPTIONAL, have special meaning relating to
+ conformance, as defined in RFC 2119 [RFC2119] and [RFC2911] section
+ 12.1. If an implementation supports the extension defined in this
+ document, then these terms apply; otherwise, they do not. These
+ terms define conformance to this document only; they do not affect
+ conformance to other documents, unless explicitly stated otherwise.
+
+2.2 Other terminology
+
+ This document uses terms such as Job object (or Job), IPP Printer
+ object (or Printer), "operation", "attribute", "keyword", "support",
+ and "impression". These terms have special meaning and are defined
+ in the model terminology [RFC2911], section 12.2.
+
+3 Job Template attributes
+
+3.1 sheet-collate (type2 keyword)
+
+ +===================+======================+=====================+
+ | Job Attribute |Printer: Default Value| Printer: Supported |
+ | | Attribute | Values Attribute |
+ +===================+======================+=====================+
+ | sheet-collate | sheet-collate-default| sheet-collate- |
+ | (type2 keyword) | (type2 keyword) | supported (1setOf |
+ | | | type2 keyword) |
+ +-------------------+----------------------+---------------------+
+
+ This attribute specifies whether or not the media sheets of each copy
+ of each printed document in a job are to be in sequence, when
+ multiple copies of the document are specified by the 'copies'
+ attribute.
+
+ Standard keyword values are:
+
+ 'uncollated': each print-stream sheet is printed a number of
+ times in succession equal to the value of the 'copies'
+ attribute, followed by the next print-stream sheet.
+
+ 'collated': each copy of each document is printed with the
+ print-stream sheets in sequence, followed by the next document
+ copy.
+
+
+
+Hastings, et. al. Standards Track [Page 3]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+ For example, suppose a document produces two media sheets as output,
+ and "copies" is equal to '6'. For the 'uncollated' case, six copies
+ of the first media sheet are printed, followed by six copies of the
+ second media sheet. For the 'collated' case, one copy of each of the
+ six sheets is printed, followed by another copy of each of the six
+ media sheets.
+
+ Whether the effect of sheet collation is achieved by placing copies
+ of a document in multiple output bins, or in the same output bin with
+ implementation defined document separation, is implementation
+ dependent. Also whether it is achieved by making multiple passes
+ over the job or by using an output sorter, is implementation
+ dependent.
+
+ Note: IPP/1.0 [RFC2566] and IPP/1.1 [RFC2911] are silent on whether
+ or not sheets within documents are collated. The "sheet-collate-
+ supported" Printer attribute permits a Printer object to indicate
+ whether or not it collates sheets with each document and whether it
+ allows the client to control sheet collation. An implementation is
+ able to indicate that it supports uncollated sheets, collated sheets,
+ or both, using the 'uncollated', 'collated', or both 'uncollated' and
+ 'collated' values, respectively.
+
+ This attribute is affected by "multiple-document-handling". The
+ "multiple-document-handling" attribute describes the collation of
+ documents, and the "sheet-collate" attribute describes the semantics
+ of collating individual pages within a document. To better explain
+ the interaction between these two attributes, the term "set" is
+ introduced. A "set" is a logical boundary between the delivered
+ media sheets of a printed job. For example, in the case of a ten
+ page single document with collated pages and a request for 50 copies,
+ each of the 50 printed copies of the document constitutes a "set".
+ In the above example if the pages were uncollated, then 50 copies of
+ each of the individual pages within the document would represent each
+ "set".
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 4]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+ The following table describes the interaction of "sheet-collate" with
+ multiple document handling.
+
+ "sheet- "multiple- Semantics
+ collate" document-
+ handling"
+
+ 'collated' 'single- Each copy of the concatenated
+ document' documents, with their pages in
+ sequence, represents a "set".
+
+ 'collated' 'single- Each copy of the concatenated
+ document-new- documents, with their pages in
+ sheet' sequence, represents a "set".
+
+ 'collated' 'separate- Each copy of each separate
+ documents- document, with its pages in
+ collated- sequence, represents a "set".
+ copies'
+
+ 'collated' 'separate- Each copy of each separate
+ documents- document, with its pages in
+ uncollated- sequence, represents a "set".
+ copies
+
+ 'uncollated' 'single- Each media sheet of the document
+ document' is printed a number of times equal
+ to the "copies" attribute; which
+ constitutes a "set".
+
+ 'uncollated' 'single- Each media sheet of the
+ document-new- concatenated documents is printed
+ sheet' a number of times equal to the
+ "copies" attribute; which
+ constitutes a "set".
+
+ 'uncollated' 'separate- This is a degenerate case, and the
+ documents- printer object MUST reject the job
+ collated- and return the status, "client-
+ copies' error-conflicting-attributes".
+
+ 'uncollated' 'separate- This is a degenerate case, and the
+ documents- printer object MUST reject the job
+ uncollated- and return the status "client-
+ copies error-conflicting-attributes".
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 5]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+ From the above table it is obvious that the implicit value of the
+ "sheet-collate" attribute in a printer that does not support the
+ "sheet-collate" attribute, is 'collated.' The semantics of
+ "multiple-document-handling" are otherwise nonsensical in the case
+ of separate documents.
+
+4 IPP Job Description attributes for monitoring Job Progress
+
+ The following IPP Job Description attributes are proposed to be added
+ to IPP through the type2 registration procedures. They are useful
+ for monitoring the progress of a job. They are also used as
+ attributes in the notification content in a notification report
+ [ipp-ntfy].
+
+ There are a number of Job Description attributes for monitoring the
+ progress of a job. These objects and attributes count the number of
+ K octets, impressions, sheets, and pages requested or completed. For
+ impressions and sheets, "completed" means stacked, unless the
+ implementation is unable to detect when each sheet is stacked, in
+ which case, stacked is approximated when the processing of each sheet
+ is completed. There are objects and attributes for the overall job
+ and for the current copy of the document currently being stacked.
+ For the latter, the rate at which the various objects and attributes
+ count, depends on the sheet and document collation of the job.
+
+ Consider the following four Job Description attributes that are used
+ to monitor the progress of a job's impressions:
+
+ 1. "job-impressions-completed" - counts the total number of
+ impressions stacked for the job (see [RFC2911] section
+ 4.3.18.2).
+
+ 2. "impressions-completed-current-copy" - counts the number of
+ impressions stacked for the current document copy.
+
+ 3. "sheet-completed-copy-number" - identifies the number of the
+ copy for the current document being stacked, where the first
+ copy is 1.
+
+ 4. "sheet-completed-document-number" - identifies the current
+ document within the job that is being stacked, where the first
+ document in a job is 1. NOTE: this attribute SHOULD NOT be
+ implemented for implementations that only support one document
+ per job.
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 6]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+ For each of the three types of job collation, a job with three copies
+ of two documents (1, 2), where each document consists of 3
+ impressions, the four variables have the following values, as each
+ sheet is stacked for one-sided printing:
+
+ "job-collation-type" = 'uncollated-sheets(3)'
+
+ "job- "impressions- "sheet- "sheet-
+ impressions- completed- completed- completed-
+ completed" current-copy" copy-number" document-
+ number"
+
+ 0 0 0 0
+ 1 1 1 1
+ 2 1 2 1
+ 3 1 3 1
+ 4 2 1 1
+ 5 2 2 1
+ 6 2 3 1
+ 7 3 1 1
+ 8 3 2 1
+ 9 3 3 1
+ 10 1 1 2
+ 11 1 2 2
+ 12 1 3 2
+ 13 2 1 2
+ 14 2 2 2
+ 15 2 3 2
+ 16 3 1 2
+ 17 3 2 2
+ 18 3 3 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 7]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+ "job-collation-type" = 'collated-documents(4)'
+
+ "job- "impressions- "sheet- "sheet-
+ impressions- completed- completed- completed-
+ completed" current-copy" copy- document-
+ number" number"
+
+ 0 0 0 0
+ 1 1 1 1
+ 2 2 1 1
+ 3 3 1 1
+ 4 1 1 2
+ 5 2 1 2
+ 6 3 1 2
+ 7 1 2 1
+ 8 2 2 1
+ 9 3 2 1
+ 10 1 2 2
+ 11 2 2 2
+ 12 3 2 2
+ 13 1 3 1
+ 14 2 3 1
+ 15 3 3 1
+ 16 1 3 2
+ 17 2 3 2
+ 18 3 3 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 8]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+ "job-collation-type" = 'uncollated-documents(5)'
+
+ "job- "impressions- "sheet- "sheet-
+ impressions- completed- completed- completed-
+ completed" current-copy" copy-t document-
+ number" number"
+
+ 0 0 0 0
+ 1 1 1 1
+ 2 2 1 1
+ 3 3 1 1
+ 4 1 2 1
+ 5 2 2 1
+ 6 3 2 1
+ 7 1 3 1
+ 8 2 3 1
+ 9 3 3 1
+ 10 1 1 2
+ 11 2 1 2
+ 12 3 1 2
+ 13 1 2 2
+ 14 2 2 2
+ 15 3 2 2
+ 16 1 3 2
+ 17 2 3 2
+ 18 3 3 2
+
+4.1 job-collation-type (type2 enum)
+
+ Job Collation includes sheet collation and document collation. Sheet
+ collation is defined to be the ordering of sheets within a document
+ copy. Document collation is defined to be the ordering of document
+ copies within a multi-document job. The value of the "job-
+ collation-type" is affected by the value of the "sheet-collate" Job
+ Template attribute (see section 3.1), if supplied and supported.
+
+ The Standard enum values are:
+
+ '1' 'other': not one of the defined values
+
+ '2' 'unknown': the collation type is unknown
+
+ '3' 'uncollated-sheets': No collation of the sheets within each
+ document copy, i.e., each sheet of a document that
+ is to produce multiple copies, is replicated before
+ the next sheet in the document is processed and
+ stacked. If the device has an output bin collator,
+ the 'uncollated-sheets(3)' value may actually
+
+
+
+Hastings, et. al. Standards Track [Page 9]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+ produce collated sheets as far as the user is
+ concerned (in the output bins). However, when the
+ job collation is the 'uncollated-sheets(3)' value,
+ job progress is indistinguishable from a monitoring
+ application between a device that has an output bin
+ collator and one that does not.
+
+ '4' 'collated-documents': Collation of the sheets within each
+ document copy is performed within the printing
+ device by making multiple passes over, either the
+ source or an intermediate representation of the
+ document. In addition, when there are multiple
+ documents per job, the i'th copy of each document is
+ stacked before the j'th copy of each document, i.e.,
+ the documents are collated within each job copy.
+ For example, if a job is submitted with documents, A
+ and B, the job is made available to the end user as:
+ A, B, A, B, .... The 'collated-documents(4)' value
+ corresponds to the IPP [RFC2911] 'separate-
+ documents-collated-copies' keyword value of the
+ "multiple-document-handling" attribute.
+
+ If the job's "copies" attribute is '1' (or not
+ supplied), then the "job-collation-type" attribute
+ is defined to be '4'.
+
+ '5' 'uncollated-documents': Collation of the sheets within each
+ document copy is performed within the printing
+ device by making multiple passes over either the
+ source or an intermediate representation of the
+ document. In addition, when there are multiple
+ documents per job, all copies of the first document
+ in the job are stacked before any copied of the next
+ document in the job, i.e., the documents are
+ uncollated within the job. For example, if a job is
+ submitted with documents, A and B, the job is made
+ available to the end user as: A, A, ..., B, B, ....
+ The 'uncollated-documents(5)' value corresponds to
+ the IPP [RFC2911] 'separate-documents-uncollated-
+ copies' keyword value of the "multiple-document-
+ handling" attribute.
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 10]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+4.2 sheet-completed-copy-number (integer(0:MAX))
+
+ The number of the copy being stacked for the current document. This
+ number starts at 0, is set to 1 when the first sheet of the first
+ copy for each document is being stacked and is equal to n where n is
+ the nth sheet stacked in the current document copy. If the value is
+ unknown, the Printer MUST return the 'unknown' out-of-band value (see
+ [RFC2911] section 4.1), rather than the -2 value used in some MIBs
+ [RFC2707].
+
+4.3 sheet-completed-document-number (integer(0:MAX))
+
+ The ordinal number of the document in the job that is currently being
+ stacked. This number starts at 0, increments to 1 when the first
+ sheet of the first document in the job is being stacked, and is equal
+ to n where n is the nth document in the job, starting with 1. If the
+ value is unknown, the Printer MUST return the 'unknown' out-of-band
+ value (see [RFC2911] section 4.1), rather than the -2 value used in
+ some MIBs [RFC2707].
+
+ Implementations that only support one document job SHOULD NOT
+ implement this attribute.
+
+4.4 impressions-completed-current-copy (integer(0:MAX))
+
+ The number of impressions completed by the device for the current
+ copy of the current document so far. For printing, the impressions
+ completed includes interpreting, marking, and stacking the output.
+ For other types of job services, the number of impressions completed
+ includes the number of impressions processed. If the value is
+ unknown, the Printer MUST return the 'unknown' out-of-band value (see
+ [RFC2911] section 4.1), rather than the -2 value used in some MIBs
+ [RFC2707].
+
+ This value MUST be reset to 0 for each document in the job and for
+ each document copy.
+
+5 Conformance Requirements
+
+ This section summarizes the Conformance Requirements detailed in the
+ definitions in this document. In general each of the attributes
+ defined in this document are OPTIONAL for a client and/or a Printer
+ to support, so that client and Printer implementers MAY implement any
+ combination of these attributes.
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 11]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+6 IANA Considerations
+
+ This section contains registration information for IANA to add to the
+ IPP Registry according to the procedures defined in RFC 2911
+ [RFC2911], section 6. The resulting registrations will be published
+ in the http://www.iana.org/assignments/ipp-registrations registry.
+
+6.1 Attributes
+
+ Job Template attributes: Ref. Section:
+ sheet-collate (type2 keyword) RFC 3381 3.1
+ sheet-default (type2 keyword) RFC 3381 3.1
+ sheet-supported (1setOf type2 keyword) RFC 3381 3.1
+
+ Job Description attributes: Ref. Section:
+ job-collation-type (type2 enum) RFC 3381 4.1
+ sheet-completed-copy-number (integer(0:MAX)) RFC 3381 4.2
+ sheet-completed-document-number (integer(0:MAX))RFC 3381 4.3
+ impressions-completed-current-copy (integer(0:MAX))
+ RFC 3381 4.4
+6.2 Keyword Attribute Values
+
+ The following table provides registration information for all of the
+ attributes defined in this document that have keyword values. These
+ keywords are to be registered according to the procedures defined in
+ RFC 2911 [RFC2911] section 6.1.
+
+ sheet-collate (type2 keyword) RFC 3381 3.1
+ 'uncollated' RFC 3381 3.1
+ 'collated' RFC 3381 3.1
+ sheet-collate-default (type2 keyword) RFC 3381 3.1
+ See "sheet-collate" attribute
+ sheet-collate-supported (1setOf type2 keyword) RFC 3381 3.1
+ See "sheet-collate" attribute
+
+6.3 Enum Attribute Values
+
+ The following table provides registration information for all of the
+ attributes defined in this document that have enum values. These
+ enums are to be registered according to the procedures defined in RFC
+ 2911 [RFC2911] section 6.1.
+
+ job-collation-type (type2 enum) RFC 3381 4.1
+ '1' 'other' RFC 3381 4.1
+ '2' 'unknown' RFC 3381 4.1
+ '3' 'uncollated-sheets' RFC 3381 4.1
+ '4' 'collated-documents' RFC 3381 4.1
+ '5' 'uncollated-documents' RFC 3381 4.1
+
+
+
+Hastings, et. al. Standards Track [Page 12]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+7 Internationalization Considerations
+
+ The IPP extensions defined in this document require the same
+ internationalization considerations as any of the Job Template and
+ Job Description attributes defined in IPP/1.1 [RFC2911].
+
+8 Security Considerations
+
+ The IPP extensions defined in this document require the same security
+ considerations as any of the Job Template attributes and Job
+ Description attributes defined in IPP/1.1 [RFC2911].
+
+9 References
+
+9.1 Normative References
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P. and R. Turner,
+ "Internet Printing Protocol/1.1: Encoding and Transport",
+ RFC 2910, September 2000.
+
+ [RFC2911] Hastings, T., Herriot, R., deBry, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.1: Model and
+ Semantics", RFC 2911, September 2000.
+
+9.2 Informative References
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Turner,
+ "Internet Printing Protocol/1.0: Encoding and Transport",
+ RFC 2565, April 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2567] Wright, F.D., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569, April
+ 1999.
+
+ [RFC2707] Bergman, R., Hastings, T., Isaacson, S. and H. Lewis, "PWG
+ Job Monitoring MIB - V1", RFC 2707, November 1999.
+
+
+
+
+Hastings, et. al. Standards Track [Page 13]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+ [RFC3196] Hastings, T., Manros, C., Zehler, P., Kugler, C. and H.
+ Holst, "Internet Printing Protocol/1.1: Implementor's
+ Guide", RFC 3196, November 2001.
+
+ [ipp-ntfy] Herriot, R., Hastings, T., et. al., "Internet Printing
+ Protocol (IPP): Event Notification and Subscriptions",
+ Work in Progress.
+
+10 Description of the Base IPP Documents
+
+ The base set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [RFC3196]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0 [RFC2566, RFC2565]. A few OPTIONAL operator
+ operations have been added to IPP/1.1 [RFC2911, RFC2910].
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF IPP working group's major decisions.
+
+ The "Internet Printing Protocol/1.1: Model and Semantics" document
+ describes a simplified model with abstract objects, their attributes,
+ and their operations. The model introduces a Printer and a Job. The
+ Job supports multiple documents per Job. The model document also
+ addresses how security, internationalization, and directory issues
+ are addressed.
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1 [RFC2616]. It also defines the
+ encoding rules for a new Internet MIME media type called
+ "application/ipp". This document also defines the rules for
+ transporting over HTTP a message body whose Content-Type is
+
+
+
+Hastings, et. al. Standards Track [Page 14]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+ "application/ipp". This document defines the 'ipp' scheme for
+ identifying IPP printers and jobs.
+
+ The "Internet Printing Protocol/1.1: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.1 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+ In addition to the base IPP documents, the "Event Notification
+ Specification" document [ipp-ntfy] defines OPTIONAL operations that
+ allow a client to subscribe to printing related events.
+ Subscriptions include "Per-Job subscriptions" and "Per-Printer
+ subscriptions". Subscriptions are modeled as Subscription objects.
+ Four other operations are defined for subscription objects: get
+ attributes, get subscriptions, renew a subscription, and cancel a
+ subscription.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 15]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+11 Authors' Addresses
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ EMail: hastings@cp10.es.xerox.com
+
+ Harry Lewis
+ IBM
+ 6300 Diagonal Hwy
+ Boulder, CO 80301-9191
+
+ Phone: (303) 924-5337
+ EMail: harryl@us.ibm.com
+
+ Ron Bergman (Editor)
+ Hitachi Koki Imaging Solutions
+ 1757 Tapo Canyon Road
+ Simi Valley, CA 93063-3394
+
+ Phone: 805-578-4421
+ Fax: 805-578-4001
+ EMail: rbergma@hitachi-hkis.com
+
+ IPP Web Page: http://www.pwg.org/ipp/
+ IPP Mailing List: ipp@pwg.org
+
+ To subscribe to the ipp mailing list, send the following email:
+
+ 1) send it to majordomo@pwg.org
+ 2) leave the subject line blank
+ 3) put the following two lines in the message body:
+ subscribe ipp
+ end
+
+ Implementers of this specification document are encouraged to join
+ the IPP Mailing List in order to participate in any discussions of
+ clarification issues and review of registration proposals for
+ additional attributes and values. In order to reduce spam, the
+ mailing list rejects mail from non-subscribers, so you must subscribe
+ to the mailing list in order to send a question or comment to the
+ mailing list.
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 16]
+
+RFC 3381 IPP: Job Progress Attributes September 2002
+
+
+12 Full Copyright Statement
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et. al. Standards Track [Page 17]
+
diff --git a/standards/rfc3382.txt b/standards/rfc3382.txt
new file mode 100644
index 000000000..4181c5bc5
--- /dev/null
+++ b/standards/rfc3382.txt
@@ -0,0 +1,2131 @@
+
+
+
+
+
+
+Network Working Group R. deBry
+Request for Comments: 3382 Utah Valley State College
+Updates: 2910, 2911 R. Herriot
+Category: Standards Track Consultant
+ T. Hastings
+ K. Ocke
+ P. Zehler
+ Xerox Corporation
+ September 2002
+
+
+ Internet Printing Protocol (IPP):
+ The 'collection' attribute syntax
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+Abstract
+
+ This document specifies an OPTIONAL attribute syntax called
+ 'collection' for use with the Internet Printing Protocol (IPP/1.0 and
+ IPP/1.1). A 'collection' is a container holding one or more named
+ values, which are called "member" attributes. A collection allows
+ data to be grouped like a PostScript dictionary or a Java Map. This
+ document also specifies the conformance requirements for a definition
+ document that defines a collection attribute. Finally, this document
+ gives some illustrative example collection attribute definitions that
+ are not intended as actual attribute specifications.
+
+Table of Contents
+
+ 1 Introduction.....................................................3
+ 1.1 Problem Statement..............................................3
+ 1.2 Solution.......................................................3
+ 2 Terminology......................................................4
+ 2.1 Conformance Terminology........................................4
+ 2.2 Other terminology..............................................5
+ 3 Definition of a Collection Attribute.............................5
+ 3.1 Information to Include.........................................5
+
+
+
+deBry, et. al. Standards Track [Page 1]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ 3.2 Nested Collections.............................................9
+ 4 Collection Attributes as Attributes in Operations................9
+ 4.1 General Rules..................................................9
+ 4.2 Unsupported Values.............................................9
+ 5 Example definition of a collection attribute.....................9
+ 5.1 media-col (collection)........................................10
+ 5.1.1 media-color (type3 keyword | name(MAX)......................10
+ 5.1.2 media-size (collection).....................................11
+ 5.2 media-col-default (collection)................................11
+ 5.3 media-col-ready (1setOf collection)...........................12
+ 5.4 media-col-supported (1setOf type2 keyword)....................12
+ 6 A Second Example Definition Of A Collection Attribute...........12
+ 7 Encoding........................................................13
+ 7.1 Additional tags defined for representing a collection
+ attribute value...............................................13
+ 7.2 Example encoding: "media-col" (collection)....................14
+ 8 Legacy issues...................................................20
+ 9 IANA Considerations.............................................20
+ 10 Internationalization Considerations............................20
+ 11 Security Considerations........................................21
+ 12 References.....................................................21
+ Appendix A: Encoding Example of a Simple Collection (Informative).22
+ Appendix B: Encoding Example of 1setOf Collection (Informative)...25
+ Appendix C: Encoding Example of Collection containing 1setOf XXX
+ attribute (Informative)...............................31
+ Appendix D: Description of the Base IPP Documents (Informative)...35
+ Authors' Addresses................................................36
+ Full Copyright Statement..........................................38
+
+Table of Tables
+
+ Table 1 - "media-col" member attributes...........................10
+ Table 2 - "media-size" collection member attributes...............11
+ Table 3 - Tags defined for encoding the 'collection' attribute
+ syntax .................................................13
+ Table 4 - Overview Encoding of "media-col" collection.............15
+ Table 5 - Example Encoding of "media-col" collection..............16
+ Table 6 - Overview Encoding of simple collection..................22
+ Table 7 - Example Encoding of simple collection...................22
+ Table 8 - Overview Encoding of 1setOf collection..................25
+ Table 9 - Example Encoding of 1setOf collection...................26
+ Table 10 - Overview Encoding of collection with 1setOf value......31
+ Table 11 - Example Encoding of collection with 1setOf value.......32
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 2]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+1 Introduction
+
+ This document is an OPTIONAL extension to IPP/1.0 [RFC2565, RFC2566]
+ and IPP/1.1 [RFC2911, RFC2910]. For a description of the base IPP
+ documents see Appendix D.
+
+1.1 Problem Statement
+
+ The IPP Model and Semantics [RFC2911] supports most of the common
+ data structures that are available in programming languages. It
+ lacks a mechanism for grouping several attributes of different types.
+ The Java language uses the Map to solve this problem and PostScript
+ has a dictionary. The new mechanism for grouping attributes together
+ (called 'collection' mechanism) must allow for optional members and
+ the subsequent addition of new members.
+
+ The 'collection' mechanism must be encoded in a manner consistent
+ with existing 1.0 and 1.1 parsing rules (see [RFC2910]). Current 1.0
+ and 1.1 parsers that don't support the 'collection' mechanism must
+ not confuse collections or parts of a collection they receive with
+ other attributes.
+
+1.2 Solution
+
+ The new mechanism is a new IPP attribute syntax called a
+ 'collection'. As such, each collection value is a value of an
+ attribute whose attribute syntax type is defined to be a
+ 'collection'. Such an attribute is called a collection attribute.
+ The name of the collection attribute serves to identify the
+ collection value in an operation request or response, as with any
+ attribute value.
+
+ The 'collection' attribute syntax is a container holding one or more
+ named values (i.e., attributes), which are called member attributes.
+ Each collection attribute definition document lists the mandatory and
+ optional member attributes of each collection value. A collection
+ value is similar to an IPP attribute group in a request or a
+ response, such as the operation attributes group. They both consist
+ of a set of attributes.
+
+ As with any attribute syntax, the document that defines a collection
+ attribute specifies whether the attribute is single-valued
+ (collection) or multi-valued (1setOf collection). If the attribute
+ is multi-valued (1setOf collection), each collection value MUST be a
+ separate instance of a single definition of a collection, i.e., it
+ MUST have the same member attributes except for OPTIONAL member
+ attributes. If we view each collection definition as a separate
+ syntax type, this rule continues the IPP/1.1 notion that each
+
+
+
+deBry, et. al. Standards Track [Page 3]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ attribute has a single type or pattern (e.g., "keyword | name" is a
+ pattern). Without this rule, the supported values would be more
+ difficult to describe and the mechanism defined in item 4 of section
+ 3.1 would not be sufficient.
+
+ The name of each member attribute MUST be unique for a collection
+ attribute, but MAY be the same as the name of a member attribute in
+ another collection attribute and/or MAY be the same as the name of an
+ attribute that is not a member of a collection. The rules for naming
+ member attributes are given in section 3.1.
+
+ Each member attribute can have any attribute syntax type, including
+ 'collection', and can be either single-valued or multi-valued. The
+ length of a collection value is not limited. However, the length of
+ each member attribute MUST NOT exceed the limit of its attribute
+ syntax.
+
+ The member attributes in a collection MAY be in any order in a
+ request or response. When a client sends a collection attribute to
+ the Printer, the order that the Printer stores the member attributes
+ of the collection value and the order returned in a response MAY be
+ different from the order sent by the client.
+
+ A collection value MUST NOT contain two or more member attributes
+ with the same attribute name. Such a collection is mal-formed.
+ Clients MUST NOT submit such malformed requests and Printers MUST NOT
+ return such malformed responses. If such a malformed request is
+ submitted to a Printer, the Printer MUST (depending on
+ implementation) either (1) reject the request with the 'client-
+ error-bad-request' status code (see [RFC2911] section 13.1.4.1), or
+ (2) accept the request and use only one of each duplicate member
+ attributes.
+
+2 Terminology
+
+ This section defines terminology used throughout this document.
+
+2.1 Conformance Terminology
+
+ Capitalized terms, such as MUST, MUST NOT, REQUIRED, SHOULD, SHOULD
+ NOT, MAY, NEED NOT, and OPTIONAL, have special meaning relating to
+ conformance as defined in BCP 14, RFC 2119 [RFC2119] and [RFC2911],
+ section 12.1. If an implementation supports the extension defined in
+ this document, then these terms apply; otherwise, they do not. These
+ terms define conformance to this document only; they do not affect
+ conformance to other documents, unless explicitly stated otherwise.
+
+
+
+
+
+deBry, et. al. Standards Track [Page 4]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+2.2 Other terminology
+
+ This document uses terms such as Job object (or Job), IPP Printer
+ object (or Printer), "operation", "request", response", "attributes",
+ "keywords", and "support". These terms have special meaning and are
+ defined in the model terminology [RFC2911] section 12.2. The
+ following additional terms are introduced in this document:
+
+ collection: an attribute syntax in which each attribute value is a
+ set of attributes, called member attributes.
+
+ member attribute: an attribute that is defined to be used as one
+ of the attributes in a collection.
+
+ collection attribute: an attribute whose definition specifies the
+ 'collection' attribute syntax and each of the member attributes
+ that MAY occur in a collection attribute value.
+
+3 Definition of a Collection Attribute
+
+ This section describes the requirements for any collection attribute
+ definition.
+
+3.1 Information to Include
+
+ When a specification document defines an "xxx" collection attribute,
+ i.e., an attribute whose attribute syntax type is 'collection' or
+ '1setOf collection'; the definition document MUST include the
+ following aspects of the attribute semantics. Suppose the "xxx"
+ collection attribute contains N member attributes named "aaa1",
+ "aaa2", ..., "aaaN" ("aaaI" represents any one of these N member
+ attributes).
+
+ 1. The name of the collection attribute MUST be specified (e.g.,
+ "xxx"). The selection of the name "xxx" MUST follow the same
+ rules for uniqueness as for attributes of any other syntax type,
+ (as defined by IPP/1.1) unless "xxx" is a member attribute of
+ another collection. Then the selection of the name "xxx" MUST
+ follow the rules for uniqueness defined in item 5a) of this list.
+
+ 2. The collection attribute syntax MUST be of type 'collection' or
+ '1setOf collection'.
+
+ 3. The context of the collection attribute MUST be specified, i.e.,
+ whether the attribute is an operation attribute, a Job Template
+ attribute, a Job Description attribute, a Printer Description
+ attribute, a member attribute of a particular collection
+ attribute, etc.
+
+
+
+deBry, et. al. Standards Track [Page 5]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ 4. An "xxx-supported" attribute MUST be specified and it has one of
+ the following two forms:
+
+ a) "xxx-supported" is a "1setOf collection", which enumerates all
+ of the supported collection values of "xxx". If a collection
+ of this form contains a nested collection, it MUST be of the
+ same form.
+
+ For example, "media-size-supported" might have the values {{x-
+ dimension:210, y-dimension:297},{x-dimension:297, y-
+ dimension:420}} to show that it supports two values of "media
+ size": A4 (210x297) and A3 (297x420). It does not support
+ other combinations of "x-dimension" and "y-dimension" member
+ attributes, such as 210x420 or 297x297, and it does not support
+ non-enumerated values, such as 420x595.
+
+ b) "xxx-supported" is a "1setOf type2 keyword", which enumerates
+ the names of all of the member attributes of "xxx": "aaa1",
+ "aaa2", ..., "aaaN". If a collection of this form contains a
+ nested collection, it MAY be of either form. See item 5f)
+ below for details on supported values of member attributes.
+
+ For example, "media-col-supported" might have the keyword
+ values: "media-size" and "media-color".
+
+ 5. The member attributes MUST be defined. For each member attribute,
+ the definition document MUST provide the following information:
+
+ a) The member attribute's name (e.g., "aaa") MUST be unique within
+ the collection being defined and MUST either:
+
+ i) reuse the attribute name of another attribute (that is
+ unique across the entire IPP attribute name space) and
+ have the same syntax and semantics as the reused attribute
+ (if the condition of item 4b) above is met). For example,
+ a member attribute definition could reuse the IPP/1.1
+ "media" attribute.
+
+ ii) potentially occur elsewhere in the entire IPP attribute
+ name space. (if the condition of item 4a) above is met).
+ For example, a member attribute could be "x-dimension",
+ which could potentially occur in another collection or as
+ an attribute outside of a collection.
+
+ iii) be unique across the entire IPP attribute name space (if
+ the condition of item 4b) above is met). For example, a
+ member attribute could be "media-color" which must be
+ unique across the entire IPP attribute name space.
+
+
+
+deBry, et. al. Standards Track [Page 6]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ b) Whether the member attribute is REQUIRED or OPTIONAL for the
+ Printer to support.
+
+ c) Whether the member attribute is REQUIRED or OPTIONAL for the
+ client to supply in a request.
+
+ d) The member attribute's syntax type, which can be any attribute
+ syntax, including '1setOf X', 'collection', and '1setOf
+ collection'. If this attribute name reuses the name of another
+ attribute (case of item a1 above), it MUST have the same
+ attribute syntax, including cardinality (whether or not
+ 1setOf).
+
+ e) The semantics of the "aaa" member attribute. The semantic
+ definition MUST include a description of any constraint or
+ boundary conditions the member attribute places on the
+ associated attribute, especially if the attribute reuses the
+ name of another attribute (case of item a1 above).
+
+ f) The supported values for each "aaaI" member attribute (of the
+ member attributes "aaa1", "aaa2", ..., "aaaN") is specified by
+ one of two mechanisms.
+
+ i) If "xxx-supported" is a "1setOf collection" (see item 4a)
+ above), the value for each "aaaI" is specified in each
+ collection value of "xxx-supported", in the context of
+ other member attributes. That is, "xxx-supported"
+ enumerates all supported values of "xxx".
+
+ ii) If the value of "xxx-supported" is a "1setOf type2
+ keyword" (see item 4b) above), the supported values of
+ "aaaI" are the values specified by either i) the "aaaI-
+ supported" attribute or ii) the definition of the member
+ attribute "aaaI" within the document defining the "xxx"
+ attribute. The values of each member attribute "aaaI" are
+ specified independently of other member attributes, though
+ a Printer is not required to support all combinations of
+ supported values.
+
+ For example, "media-col-supported" might have the keyword
+ values: "media-size" and "media-color". Using the first
+ method for defining supported values (an "aaaI-supported"
+ attribute), the collection values of "media-col" are
+ combinations of values of "media-size-supported" and
+ "media-color-supported". If "media-size-supported" has
+ the values of '210x297' and '297x420' and "media-color-
+ supported" has the values of 'white' and 'pink', the
+
+
+
+
+deBry, et. al. Standards Track [Page 7]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Printer might support only the combinations 'white-
+ 210x297', 'pink-210x297' and 'white-297x420', and not
+ 'pink-297x420'.
+
+ If a collection contains a member "aaaI", whose syntax
+ type is "text", the supported values would probably be
+ defined by the definition of "xxx" rather than by the
+ attribute "aaaI-supported".
+
+ g) the default value of each "aaaI" member attribute if it is
+ OPTIONAL for a client to supply the "aaa" member attribute in a
+ request. The default value is specified by the attribute's
+ definition within a document and MUST be one of the following:
+
+ i) a fixed default
+
+ ii) a mechanism by which the Printer determines default
+
+ iii) an indefinite default that is left to the implementation.
+
+ iv) an attribute that the Printer uses to determine the
+ default
+
+ 6. The default value of "xxx", if a client does not supply it. The
+ default value is specified by the attribute's definition within a
+ document and MUST be one of the following:
+
+ a) a fixed default
+
+ b) a mechanism by which the Printer determines default
+
+ c) an indefinite default that is left to the implementation
+
+ d) a Printer attribute "xxx-default" which is a collection with
+ the same member attributes as "xxx". If optional member
+ attributes are absent, the Printer uses the defaulting rules of
+ item 5g) above.
+
+ 7. The "xxx-ready (1setOf collection)" attribute, if human
+ intervention is required to make many of the supported values
+ available. For example, "media-col" is an attribute which has a
+ "ready" attribute. Most attributes do not have a "ready"
+ attribute.
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 8]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+3.2 Nested Collections
+
+ A member attribute may have a syntax type of 'collection' or '1setOf
+ collection', in which case it is called a nested collection
+ attribute. The rules for a nested collection attribute are the same
+ as for a collection attribute as specified in section 3.1.
+
+4 Collection Attributes as Attributes in Operations
+
+4.1 General Rules
+
+ A collection value is like any other IPP/1.1 value, except that it is
+ structured. The rules for attributes with collection values are the
+ same as for attributes of any other syntax type (see IPP/1.1), be
+ they in any group of a request of a response.
+
+4.2 Unsupported Values
+
+ The rules for returning an unsupported collection attribute are an
+ extension to the current rules:
+
+ 1. If the entire collection attribute is unsupported, then the
+ Printer returns just the collection attribute name with the
+ 'unsupported' out-of-band value (see the beginning of [RFC2911]
+ section 4.1) in the Unsupported Attributes Group.
+
+ 2. If a collection contains unrecognized, unsupported member
+ attributes and/or conflicting values, the attribute returned in
+ the Unsupported Group is a collection containing the unrecognized,
+ unsupported member attributes, and/or conflicting values. The
+ unrecognized member attributes have an out-of-band value of
+ 'unsupported' (see the beginning of [RFC2911] section 4.1). The
+ unsupported member attributes and conflicting values have their
+ unsupported or conflicting values.
+
+5 Example definition of a collection attribute
+
+ In some printing environments, it is desirable to allow the client to
+ select the media by its properties, e.g., weight, color, size, etc.,
+ instead of by name. In IPP/1.1 (see [RFC2911]), the "media (type3
+ keyword | name) Job Template attribute allows selection by name. It
+ is tempting to extend the "media" attribute syntax to include
+ "collection", but then existing clients could not understand default
+ or supported media values that use the collection value. To preserve
+ interoperability, a new attribute MUST BE added, e.g., "media-col
+ (collection)". The following subsections contain a sample definition
+ of a simplified "media-col" attribute. The definition follows the
+ rules in section 3.
+
+
+
+deBry, et. al. Standards Track [Page 9]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ All of the example attribute definitions in this document are
+ illustrative examples, rather than actual definitions. These
+ examples are intended to illustrate how to define collection
+ attributes. Other documents MUST define collection attributes for
+ use in actual interchange. Such definitions may be very similar to
+ the examples in this document, since we attempted to pick useful
+ examples.
+
+ Note: we picked the name "media-col" because the name "media" is
+ already in use. Ordinarily the collection attribute would have a
+ name like any other attribute and would not end in "col".
+
+ The member attributes of "media-col" attribute ("media-color (type 3
+ keyword)" and "media-size (collection)") both follow the naming rules
+ of item 4a3 of section 3, i.e., the names are unique across the
+ entire IPP attribute name space. The member attributes of the
+ "media-size (collection)" member attribute ("x-dimension
+ (integer(0:MAX))" and "y-dimension (integer(0:MAX))") both follow the
+ naming rules of item 4a2 of section 3, i.e., they potentially occur
+ elsewhere in the IPP attribute name space.
+
+5.1 media-col (collection)
+
+ The "media-col" (collection) attribute augments the IPP/1.1 [RFC2911]
+ "media" attribute. This collection attribute enables a client end
+ user to submit a list of media characteristics to the Printer. When
+ the client specifies media using the "media-col" collection
+ attribute, the Printer object MUST match the requested media exactly.
+ The 'collection' consists of the following member attributes:
+
+ Table 1 - "media-col" member attributes
+
+ Attribute name attribute syntax request Printer
+ Support
+
+ media-color type3 keyword | name (MAX) MAY MUST
+
+ media-size collection MUST MUST
+
+ The definitions for the member attributes is given in the following
+ sub-sections:
+
+5.1.1 media-color (type3 keyword | name(MAX)
+
+ This member attribute identifies the color of the media. Valid
+ values are 'red', 'white' and 'blue'.
+
+
+
+
+
+deBry, et. al. Standards Track [Page 10]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ The "media-color-supported" (1setOf (type3 keyword | name(MAX)))
+ Printer attribute identifies the values of this "media-color" member
+ attribute that the Printer supports, i.e., the colors supported.
+
+ If the client omits this member attribute, the Printer determines the
+ value in an implementation dependent manner.
+
+5.1.2 media-size (collection)
+
+ This member attribute identifies the size of the media. The
+ 'collection' consists of the member attributes shown in Table 2:
+
+ Table 2 - "media-size" collection member attributes
+
+ Attribute name attribute syntax request Printer
+ Support
+
+ x-dimension integer (0:MAX) MUST MUST
+
+ y-dimension integer (0:MAX) MUST MUST
+
+ The definitions for the member attributes are given in the following
+ sub-sections:
+
+5.1.2.1 x-dimension (integer(0:MAX))
+
+ This attribute identifies the width of the media in inch units along
+ the X axis.
+
+5.1.2.2 y-dimension (integer(0:MAX))
+
+ This attribute identifies the height of the media in inch units along
+ the Y axis.
+
+ The "media-size-supported" (1setOf collection) Printer attribute
+ identifies the values of this "media-size" member attribute that the
+ Printer supports, i.e., the size combinations supported. The names
+ of the member attributes are the same as the member attributes of the
+ "media-size" collection attribute, namely "x-dimension", and "y-
+ dimension", since they have the same attribute syntax and the same
+ semantics.
+
+5.2 media-col-default (collection)
+
+ The "media-col-default" Printer attribute specifies the media that
+ the Printer uses, if any, if the client omits the "media-col" and
+ "media". Job Template attributes in the Job Creation operation and
+ the PDL do not include a media specification. The member attributes
+
+
+
+deBry, et. al. Standards Track [Page 11]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ are defined in Table 1. A Printer MUST support the same member
+ attributes for this default collection attribute as it supports for
+ the corresponding "media-col" Job Template attribute.
+
+5.3 media-col-ready (1setOf collection)
+
+ The "media-col-ready" Printer attribute identifies the media that are
+ available for use without human intervention, i.e., the media that
+ are ready to be used without human intervention. The collection
+ value MUST have all of the member attributes that are supported in
+ Table 1.
+
+5.4 media-col-supported (1setOf type2 keyword)
+
+ The "media-col-supported" Printer attribute identifies the keyword
+ names of the member attributes supported in the "media-col"
+ collection Job Template attribute, i.e., the keyword names of the
+ member attributes in Table 1 that the Printer supports.
+
+6 A Second Example Definition Of A Collection Attribute
+
+ All of the example attribute definitions in this document are
+ illustrative examples, rather than actual definitions. These
+ examples are intended to illustrate how to define collection
+ attributes. Other documents MUST define collection attributes for
+ use in actual interchange. Such definitions may be very similar to
+ the examples in this document, since we attempted to pick useful
+ examples.
+
+ In some printing environments, it is desirable to allow the client to
+ select the media for the job start sheet. The reason for not adding
+ the 'collection' attribute syntax to the existing "job-sheets" Job
+ Template attribute is the same as for "media". Instead, a new Job
+ Template attribute is introduced, e.g., "job-sheet-col (collection)".
+
+ The member attributes of "job-sheet-col" attribute ("job-sheets (type
+ 3 keyword)" and "media (type3 keyword | name)") both follow the
+ naming rules of item 4a1 of section 3, i.e., they reuse existing IPP
+ attributes. According to the rules, their supported values come from
+ the existing IPP attributes: "job-sheets-supported" and "media-
+ supported". However, their default values do not come from "job-
+ sheets-default" and "media-default", respectively. Rather, the
+ definition of "job-sheet-col" says that "job-sheets (type 3 keyword)"
+ is required and if "media (type3 keyword | name)" is absent, the
+ Printer uses the same media as the rest of the job uses.
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 12]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ If "job-sheet-col" attribute was defined to contain the member
+ attribute "job-sheet-media (type3 keyword | name)" instead of "media
+ (type3 keyword | name)", then the definition would also have to
+ specify a "job-sheet-media-supported (1setOf (type3 keyword | name))"
+ whose values would be independent of "media-supported (1setOf (type3
+ keyword | name))" and would be set separately by a System
+ Administrator.
+
+ The actual text for the definition of the attribute is left as an
+ exercise for the reader.
+
+7 Encoding
+
+ This section defines the additional encoding tags used according to
+ [RFC2910] and gives an example of their use. The encoding tags
+ defined in this document MUST be used by all collection attributes
+ defined in other documents. However, the example of their use is
+ illustrative only.
+
+7.1 Additional tags defined for representing a collection attribute
+ value
+
+ The 'collection' attribute syntax uses the tags defined in Table 3.
+
+ Table 3 - Tags defined for encoding the 'collection' attribute syntax
+
+ Tag name Tag
+ value Meaning
+
+ begCollection 0x34 Begin the collection attribute value.
+
+ endCollection 0x37 End the collection attribute value.
+
+ memberAttrName 0x4A The value is the name of the
+ collection member attribute
+
+ When encoding a collection attribute "xxx" that contains an attribute
+ "aaa" and is not inside another collection, the encoding follows
+ these rules:
+
+ 1. The beginning of the collection is indicated with a value tag that
+ MUST be syntax type 'begCollection' (0x34) with a name length and
+ Name field that represent the name of the collection attribute
+ ("xxx") as with any attribute, followed by a value. The Printer
+ MAY ignore the value and its length MAY be 0. In the future,
+ however, this field MAY contain useful information, such as the
+ collection name (cf. the name of a C struct).
+
+
+
+
+deBry, et. al. Standards Track [Page 13]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ 2. Each member attribute is encoded as a sequence of two or more
+ values that appear to be part of a single multi-valued attribute,
+ i.e., 1setOf. The first value after the 'begCollection' value has
+ the attribute syntax, 'memberAttrName' (0x4A), and its value holds
+ the name of the first member attribute (e.g., "aaa"). The second
+ value holds the first member's attribute value, which can be of
+ any attribute syntax, except 'memberAttrName' or 'endCollection'.
+ If the first member's attribute value is multi-valued, the third
+ value holds the second value of the first member's value.
+ Otherwise, the third value holds the name of second member
+ attribute (e.g., "bbb"), and its attribute syntax is
+ 'memberAttrName'. In this case, the fourth member's value is the
+ value of "bbb".
+
+ Note that the technique of encoding a 'collection' as a '1setOf'
+ makes it easy for a Printer that doesn't support a particular
+ collection attribute (or the collection attribute syntax at all)
+ to simply skip over the entire collection value.
+
+ 3. The end of the collection is indicated with a value tag that MUST
+ be syntax type 'endCollection' (e.g., 0x37) and MAY have a zero
+ name length and a zero value length. In the future, this field
+ MAY contain useful information, such as the collection name that
+ matches the one in the 'begCollection' .
+
+ 4. It is valid to have a member attribute that is itself, a
+ collection attribute, i.e., collections can be nested within
+ collections. This is represented by the occurrence of a member
+ attribute that is of attribute syntax type 'begCollection'. Such
+ a collection is terminated by a matching 'endCollection'. The
+ name of such a member attribute is in the immediately preceding
+ value, whose syntax type is 'memberAttrName'.
+
+ 5. It is valid for a collection attribute to be multi-valued, i.e.,
+ have more than one collection value. If the next attribute
+ immediately following the 'endCollection' has a zero name length
+ and a tag of 'begCollection', then the collection attribute is a
+ multi-valued collection, as with any attribute. This statement
+ applies to collections within collections and collections that are
+ not in collections.
+
+7.2 Example encoding: "media-col" (collection)
+
+ The collection specified in section 5 is used for the encoding
+ example shown in Table 5. The example also shows nested collections,
+ since the "media-size" member attribute is a 'collection. The
+ encoding example represents a blue 4x6-index card and takes 216
+ octets. The Appendices contain more complex examples.
+
+
+
+deBry, et. al. Standards Track [Page 14]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Additional examples have been included in the appendices.
+
+ The overall structure of the two collection values can be pictorially
+ represented as:
+
+ "media-col" =
+ { "media-color" = 'blue';
+ "media-size" =
+ { "x-dimension" = 6;
+ "y-dimension" = 4
+ }
+ },
+
+ The full encoding is in table 5. A simplified view of the encoding
+ looks like this:
+
+ Table 4 - Overview Encoding of "media-col" collection
+
+ Tag Value Name Value
+
+ begCollection media-col ""
+
+ memberAttrName "" media-color
+
+ keyword "" blue
+
+ memberAttrName "" media-size
+
+ begCollection "" ""
+
+ memberAttrName "" x-dimension
+
+ integer "" 6
+
+ memberAttrName "" y-dimension
+
+ integer "" 4
+
+ endCollection "" ""
+
+ endCollection "" ""
+
+
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 15]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Table 5 - Example Encoding of "media-col" collection
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ 0x34 begCollection value-tag beginning of the "media-
+ col" collection attribute
+
+ 0x0009 name- length of (collection)
+ length attribute name
+
+ media-col media-col name name of (collection)
+ attribute
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+ 0x4A memberAttrName value-tag starts a new member
+ attribute: "media-color"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of "media-color"
+ length keyword
+
+ media-color media-color value value is name of 1st
+ member attribute
+
+
+ 0x44 keyword type value-tag keyword type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 16]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ 0x0004 value-
+ length
+
+ blue blue value value of 1st member
+ attribute
+
+
+ 0x4A memberAttrName value-tag starts a new member
+ attribute: "media-size"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000A value- length of "media-size"
+ length keyword
+
+ media-size media-size value Name of 2nd member
+ attribute
+
+ 0x34 begCollection value-tag Beginning of the "media-
+ size" collection attribute
+ which is a sub-collection
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0000 value- collection attribute names
+ length have no value
+
+ no value (since value-
+ length was 0)
+
+ 0x4A memberAttrName value-tag starts a new member
+ attribute: "x-dimension"
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 17]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of "x-dimension"
+ length keyword
+
+ x-dimension x-dimension value name of 1st sub-
+ collection member
+ attribute
+
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0006 value value of 1st sub-
+ collection member
+ attribute
+
+ 0x4A memberAttrName value-tag starts a new member
+ attribute: "y-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of the "y-
+ length dimension" keyword
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 18]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ y-dimension y-dimension value name of 2nd sub-
+ collection member
+ attribute
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0004 value value of 2nd sub-
+ collection member
+ attribute
+
+ 0x37 endCollection value-tag end of the sub-collection
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+ 0x37 endCollection value-tag end of the 1st collection
+ value in 1setOf
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 19]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ no name (since name-length
+ was 0)
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+8 Legacy issues
+
+ IPP 1.x Printers and Clients will gracefully ignore collections and
+ its member attributes if it does not understand the collection. The
+ begCollection and endCollection elements each look like an attribute
+ with an attribute syntax that the recipient doesn't support and so
+ should ignore the entire attribute. The individual member attributes
+ and their values will look like a 1setOf values of the collection
+ attribute, so that the Printer simply ignores the entire attribute
+ and all of its values. Returning unsupported attributes is also
+ simple, since only the name of the collection attribute is returned
+ with the 'unsupported' out-of-band value (see section 4.2).
+
+9 IANA Considerations
+
+ The following table provides registration for the 'collection'
+ attribute syntax defined in this document. This is to be registered
+ according to the procedures in RFC 2911 [RFC2911] section 6.3.
+
+ Tag value: Attribute Syntaxes: Ref. Section:
+ collection RFC 3382 3
+ 0x34 begCollection RFC 3382 7.1
+ 0x37 endCollection RFC 3382 7.1
+ 0x4A memberAttrName RFC 3382 7.1
+
+ The resulting attribute syntax registration will be published in the
+ http://www.iana.org/assignments/ipp-registrations registry.
+
+10 Internationalization Considerations
+
+ This attribute syntax by itself has no impact on
+ internationalization. However, the member attributes that are
+ subsequently defined for use in a collection may have
+ internationalization considerations, as may any attribute, according
+ to [RFC2911].
+
+
+
+
+deBry, et. al. Standards Track [Page 20]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+11 Security Considerations
+
+ This attribute syntax causes no more security concerns than any other
+ attribute syntax. It is only the attributes that are subsequently
+ defined, to use this or any other attribute syntax, that may have
+ security concerns, depending on the semantics of the attribute,
+ according to [RFC2911].
+
+12 References
+
+12.1 Normative References
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P. and R. Turner, "Internet
+ Printing Protocol/1.1: Encoding and Transport", RFC 2910,
+ September 2000.
+
+ [RFC2911] Isaacson, S., deBry, R., Hastings, T., Herriot, R. and P.
+ Powell, "Internet Printing Protocol/1.1: Model and
+ Semantics", RFC 2911, September 2000.
+
+12.2 Informative References
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P. and R. Tuner, "Internet
+ Printing Protocol/1.0: Encoding and Transport", RFC 2565,
+ April 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S. and P.
+ Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569, April
+ 1999.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter,
+ L., Leach, P. and T. Berners-Lee, "Hypertext Transfer
+ Protocol - HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC3196] Hastings, T., Manros, C., Zehler, P., Kugler, C. and H.
+ Holst, "Internet Printing Protocol/1.1: Implementor's
+ Guide", RFC 3196, November 2001.
+
+
+
+deBry, et. al. Standards Track [Page 21]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+Appendix A: Encoding Example of a Simple Collection (Informative)
+
+ The overall structure of the collection value can be pictorially
+ represented as:
+
+ "media-size" =
+ { "x-dimension" = 6;
+ "y-dimension" = 4
+ }
+
+ A simplified view of the encoding would look like this:
+
+ Table 6 - Overview Encoding of simple collection
+
+ Tag Value Name Value
+
+ begCollection media-size ""
+
+ memberAttrName "" x-dimension
+
+ integer "" 6
+
+ memberAttrName "" y-dimension
+
+ integer "" 4
+
+ endCollection "" ""
+
+ Note: "" represents a name or value whose length is 0.
+
+ Table 7 - Example Encoding of simple collection
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ 0x34 begCollection value-tag beginning of the "media-
+ size" collection attribute
+
+ 0x000A name- length of (collection)
+ length attribute name
+
+ media-size media-size name name of (collection)
+ attribute
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 22]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+ 0x4A memberAttrName value-tag starts member attribute:
+ "x-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of "x-dimension"
+ length keyword
+
+ x-dimension x-dimension value name of 1st collection
+ member attribute
+
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0006 value value of 1st collection
+ member attribute
+
+ 0x4A memberAttrName value-tag starts a new member
+ attribute: "y-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+
+
+
+deBry, et. al. Standards Track [Page 23]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ 0x000B value- length of the "y-
+ length dimension" keyword
+
+ y-dimension y-dimension value name of 2nd collection
+ member attribute
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf for
+ length media-size
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0004 value value of 2nd collection
+ member attribute
+
+ 0x37 endCollection value-tag end of the collection
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 24]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+Appendix B: Encoding Example of 1setOf Collection (Informative)
+
+ The overall structure of the collection value can be pictorially
+ represented as:
+
+ "media-size-supported" =
+ { "x-dimension" = 6;
+ "y-dimension" = 4
+ },
+ { "x-dimension" = 3;
+ "y-dimension" = 5
+ };
+
+ A simplified view of the encoding would look like this:
+
+ Table 8 - Overview Encoding of 1setOf collection
+
+ Tag Value Name Value
+
+ begCollection media-size- ""
+ supported
+
+ memberAttrName "" x-dimension
+
+ integer "" 6
+
+ memberAttrName "" y-dimension
+
+ integer "" 4
+
+ endCollection "" ""
+
+ begCollection "" ""
+
+ memberAttrName "" x-dimension
+
+ integer "" 3
+
+ memberAttrName "" y-dimension
+
+ integer "" 5
+
+ endCollection "" ""
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 25]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Table 9 - Example Encoding of 1setOf collection
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ 0x34 begCollection value-tag beginning of the "media-
+ size-supported (1setOf
+ collection" attribute
+
+ 0x00014 name- length of (collection)
+ length attribute name
+
+ media-size- media-size- name name of (collection)
+ supported supported attribute
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+ 0x4A memberAttrName value-tag starts member attribute:
+ "x-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of "x-dimension"
+ length keyword
+
+ x-dimension x-dimension value name of 1st collection
+ member attribute
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 26]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0006 value value of 1st collection
+ member attribute
+
+ 0x4A memberAttrName value-tag starts member attribute:
+ "y-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of the "y-
+ length dimension" keyword
+
+ y-dimension y-dimension value name of 2nd collection
+ member attribute
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0004 value value of 2nd collection
+ member attribute
+
+ 0x37 endCollection value-tag end of the collection
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 27]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+ 0x34 begCollection value-tag beginning of the 2nd
+ member of the 1setOf
+ "sizes-avail " collection
+ attribute
+
+ 0x0000 name- Zero length name indicates
+ length this is member of previous
+ attribute
+
+ name no name (since name-length
+ was 0)
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+ 0x4A memberAttrName value-tag starts member attribute:
+ "x-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of "x-dimension"
+ length keyword
+
+ x-dimension x-dimension value name of 1st collection
+ member attribute
+
+ 0x21 integer type value-tag attribute type
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 28]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0003 value value of 1st collection
+ member attribute
+
+ 0x4A memberAttrName value-tag starts member attribute:
+ "y-dimension"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x000B value- length of the "y-
+ length dimension" keyword
+
+ y-dimension y-dimension value name of 2nd collection
+ member attribute
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0005 value value of 2nd collection
+ member attribute
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 29]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ 0x37 endCollection value-tag end of the 1setOf
+ collection value
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 30]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+Appendix C: Encoding Example of Collection containing 1setOf XXX
+ attribute (Informative)
+
+ The overall structure of the collection value can be pictorially
+ represented as:
+
+ "wagons" =
+ { "colors" = red, blue;
+ "sizes" = 4, 6, 8
+ }
+
+ A simplified view of the encoding would look like this:
+
+ Table 10 - Overview Encoding of collection with 1setOf value
+
+ Tag Value Name Value
+
+ begCollection wagons ""
+
+ memberAttrName "" colors
+
+ keyword "" red
+
+ keyword "" blue
+
+ memberAttrName "" sizes
+
+ integer "" 4
+
+ integer "" 6
+
+ integer "" 8
+
+ endCollection "" ""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 31]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Table 11 - Example Encoding of collection with 1setOf value
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ 0x34 begCollection value-tag beginning of the "wagons"
+ collection attribute
+
+ 0x0005 name- length of (collection)
+ length attribute name
+
+ wagons wagons name name of (collection)
+ attribute
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+ no value (since value-
+ length was 0)
+
+ 0x4A memberAttrName value-tag starts a new member
+ attribute: "colors"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x0006 value- length of "colors" keyword
+ length
+
+ colors colors value value is name of 1st
+ member attribute
+
+ 0x44 keyword type value-tag keyword type
+
+ 0x0000 name- 0 indicates 1setOf wagons
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value-
+ length
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 32]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ blue blue value value of 1st member
+ attribute
+
+ 0x44 keyword type value-tag keyword type
+
+ 0x0000 name- 0 indicates 1setOf wagons
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0003 value-
+ length
+
+ red red value value of 1st member
+ attribute
+
+ 0x4A memberAttrName value-tag starts a new member
+ attribute: "sizes"
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x0005 value- length of "length-avail"
+ length keyword
+
+ sizes sizes value Name of 2nd member
+ attribute
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf wagons
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 33]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ 0x0004 value 1st value for 1setOf
+ integer attribute
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value-
+ length length of an integer = 4
+
+ 0x0006 value 2nd value for 1setOf
+ integer attribute
+
+ 0x21 integer type value-tag attribute type
+
+ 0x0000 name- 0 indicates 1setOf
+ length
+
+ no name (since name-length
+ was 0)
+
+ 0x0004 value- length of an integer = 4
+ length
+
+ 0x0008 value 3rd value for 1setOf
+ integer attribute
+
+ 0x37 endCollection value-tag end of the collection
+
+ 0x0000 name- defined to be 0 for this
+ length type, so part of 1setOf
+
+ no name (since name-length
+ was 0)
+
+ 0x0000 value- defined to be 0 for this
+ length type
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 34]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Octets Symbolic Value Protocol comments
+ field
+
+ no value (since value-
+ length was 0)
+
+Appendix D: Description of the Base IPP Documents (Informative)
+
+ The base set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [RFC3196]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0 [RFC2566, RFC2565]. A few OPTIONAL operator
+ operations have been added to IPP/1.1 [RFC2911, RFC2910].
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF IPP working group's major decisions.
+
+ The "Internet Printing Protocol/1.1: Model and Semantics" document
+ describes a simplified model with abstract objects, their attributes,
+ and their operations. The model introduces a Printer and a Job. The
+ Job supports multiple documents per Job. The model document also
+ addresses how security, internationalization, and directory issues
+ are addressed.
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1 [RFC2616]. It also defines the
+ encoding rules for a new Internet MIME media type called
+ "application/ipp". This document also defines the rules for
+ transporting over HTTP a message body whose Content-Type is
+ "application/ipp". This document defines the 'ipp' scheme for
+ identifying IPP printers and jobs.
+
+
+
+deBry, et. al. Standards Track [Page 35]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ The "Internet Printing Protocol/1.1: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.1 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+Authors' Addresses
+
+ Roger deBry
+ Utah Valley State College
+ Orem, UT 84058
+
+ Phone: (801) 222-8000
+ EMail: debryro@uvsc.edu
+
+
+ Tom Hastings
+ Xerox Corporation
+ 737 Hawaii St. ESAE 231
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-5514
+ EMail: hastings@cp10.es.xerox.com
+
+
+ Robert Herriot
+ Consultant
+ 706 Colorado Ave
+ Palo Alto, CA 94303
+
+ Phone: 650-327-4466
+ Fax: 650-327-4466
+ EMail: bob@herriot.com
+
+
+
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 36]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+ Kirk Ocke
+ Xerox Corp.
+ 800 Phillips Rd
+ M/S 128-30E
+ Webster, NY 14580
+
+ Phone: (585) 442-4832
+ EMail: KOcke@crt.xerox.com
+
+
+ Peter Zehler
+ Xerox Corp.
+ 800 Phillips Rd
+ M/S 128-30E
+ Webster, NY 14580
+
+ Phone: (585) 265-8755
+ EMail: PZehler@crt.xerox.com
+
+ IPP Web Page: http://www.pwg.org/ipp/
+ IPP Mailing List: ipp@pwg.org
+
+ To subscribe to the ipp mailing list, send the following email:
+
+ 1) send it to majordomo@pwg.org
+ 2) leave the subject line blank
+ 3) put the following two lines in the message body:
+ subscribe ipp
+ end
+
+ Implementers of this specification document are encouraged to join
+ the IPP Mailing List in order to participate in any discussions of
+ clarification issues and review of registration proposals for
+ additional attributes and values. In order to reduce spam the
+ mailing list rejects mail from non-subscribers, so you must subscribe
+ to the mailing list in order to send a question or comment to the
+ mailing list.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 37]
+
+RFC 3382 IPP: The 'collection' attribute syntax September 2002
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deBry, et. al. Standards Track [Page 38]
+
diff --git a/standards/rfc3391.txt b/standards/rfc3391.txt
new file mode 100644
index 000000000..00f43d587
--- /dev/null
+++ b/standards/rfc3391.txt
@@ -0,0 +1,1403 @@
+
+
+
+
+
+
+Network Working Group R. Herriot
+Request for Comments: 3391 December 2002
+Category: Informational
+
+
+ The MIME Application/Vnd.pwg-multiplexed Content-Type
+
+Status of this Memo
+
+ This memo provides information for the Internet community. It does
+ not specify an Internet standard of any kind. Distribution of this
+ memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+IESG Note
+
+ The IESG believes use of this media type is only appropriate in
+ situations where the producer is fully aware of the capabilities and
+ limitations of the consumer. In particular, this mechanism is very
+ dependent on the producer knowing when the consumer will need a
+ particular component of a multipart object. But consumers
+ potentially work in many different ways and different consumers may
+ need different things at different times. This mechanism provides no
+ means for a producer to determine the needs of a particular consumer
+ and how they are to be accommodated.
+
+ Alternative mechanisms, such as a protocol based on BEEP which is
+ capable of bidirectional communication between the producer and
+ consumer, should be considered when the capabilities of the consumer
+ are not known by the producer.
+
+Abstract
+
+ The Application/Vnd.pwg-multiplexed content-type, like the
+ Multipart/Related content-type, provides a mechanism for representing
+ objects that consist of multiple components. An
+ Application/Vnd.pwg-multiplexed entity contains a sequence of chunks.
+ Each chunk contains a MIME message or a part of a MIME message. Each
+ MIME message represents a component of the compound object, just as a
+ body part of a Multipart/Related entity represents a component. With
+ a Multipart/Related entity, a body part and its reference in some
+ other body part may be separated by many octets. With an
+ Application/Vnd.pwg-multiplexed entity, a message and its reference
+ in some other message can be made quite close by chunking the message
+ containing the reference. For example, if a long message contains
+
+
+
+Herriot Informational [Page 1]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ references to images and the producer does not know of the need for
+ each image until it generates the reference, then
+ Application/Vnd.pwg-multiplexed allows the consumer to process the
+ reference to the image and the image before it consumes the entire
+ long message. This ability is important in printing and scanning
+ applications. This document defines the Application/Vnd.pwg-
+ multiplexed content-type. It also provides examples of its use.
+
+Table of Contents
+
+ 1. Introduction....................................................2
+ 2. Terminology.....................................................7
+ 3. Details.........................................................9
+ 3.1 Syntax of Application/Vnd.pwg-multiplexed Contents...........10
+ 3.2 Parameters for Application/Vnd.pwg-multiplexed...............12
+ 3.2.1 The "type" Parameter.......................................12
+ 3.2.2 Syntax.....................................................12
+ 4. Handling Application/Vnd.pwg-multiplexed Entities..............12
+ 5. Examples.......................................................13
+ 5.1 Example With Multipart/Related...............................14
+ 5.2 Examples with Application/Vnd.pwg-multiplexed................15
+ 5.2.1 Example Where Each Chunk Has a Complete Message............15
+ 5.2.2 Example of Chunking the Root Message.......................17
+ 5.2.3 Example of Chunking the Several Messages...................18
+ 5.2.4 Example of Chunks with Empty Payloads......................20
+ 6. Security Considerations........................................22
+ 7. Registration Information for Application/Vnd.pwg-multiplexed...22
+ 8. Acknowledgments................................................23
+ 9. References.....................................................23
+ 10. Author's Address..............................................24
+ 11. Full Copyright Statement......................................25
+
+1. Introduction
+
+ The simple MIME content-types, such as "text/plain" provide a
+ mechanism for representing a simple object, such as a text document.
+ The Multipart/Related [RFC2387] content-type provides a mechanism for
+ representing a compound object, such as a text document with two gif
+ images.
+
+ A compound object consists of multiple components. One such
+ component is the root component, which contains references to other
+ components of the compound object. These components may, in turn,
+ contain references to other components of the compound object. For
+ example, a compound object could consist of a root html text
+ component and two gif image components -- each referenced by the root
+ component.
+
+
+
+
+Herriot Informational [Page 2]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ A compound object and a component are both abstractions. For
+ transmission over the wire or writing to storage, each needs a
+ representation. A "Multipart/Related entity" is one possible
+ representation of a compound object, and a "body part" is one
+ possible representation of a component.
+
+ However, the Multipart/Related content-type is not a good solution
+ for applications that require each component to be close to its
+ corresponding reference in the root component. This document defines
+ a new MIME content-type Application/Vnd.pwg-multiplexed that provides
+ a better solution for some applications. The Application/Vnd.pwg-
+ multiplexed content-type, like the Multipart/Related content-type,
+ provides a common mechanism for representing a compound object. A
+ Multipart/Related entity consists of a sequence of body parts
+ separated by boundary strings. Each body part represents a component
+ of the compound object. An Application/Vnd.pwg-multiplexed entity
+ consists of a sequence of chunks, each of whose length is specified
+ in the chunk header. Each chunk contains a message or a part of a
+ message. Each message represents a component of the compound object.
+ Chunks from different messages can be interleaved. HTTP is the
+ typical transport for an Application/Vnd.pwg-multiplexed entity over
+ the wire. An Application/Vnd.pwg-multiplexed entity could be stored
+ in a Microsoft HTML (message/rfc822) file whose suffix is .mht.
+
+ The following paragraphs contain three examples of applications. For
+ each application, there is a discussion of its solution with the
+ Application/Vnd.pwg-multiplexed content-type, the Multipart/Related
+ content-type and BEEP [RFC3080].
+
+ Example 1: a printing application. A Producer creates a print stream
+ that consists of a very long series of page descriptions, each of
+ which references one or more images. The root component is the long
+ series of page descriptions. An image may be referenced from
+ multiple pages descriptions, and there is a mechanism to indicate
+ when there are no additional references to an image (i.e., the image
+ is out of scope). The Producer does not know what images to include
+ with a page until it generates that page. The Consumer is presumed
+ to have enough storage to hold all in-scope images and enough of the
+ root component to process at least one page. The Producer doesn't
+ need any knowledge of the Consumer's storage capabilities in order to
+ create an entity that the Consumer can successfully process.
+ However, the Producer needs to be prudent about the number of images
+ that are in-scope at any time. Of course, a malicious Producer may
+ try to exceed the storage capabilities of the Consumer, and the
+ Consumer must guard against such entities (see section 6). Here are
+ ways to represent this compound object.
+
+
+
+
+
+Herriot Informational [Page 3]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ With the Application/Vnd.pwg-multiplexed content-type, each image
+ is a message and the root component is a message. The Producer
+ breaks the root component message into chunks with each image
+ message occurring shortly before its first reference. When the
+ Consumer encounters a reference, it can assume that it has already
+ received the referenced image in an earlier chunk.
+
+ With the Multipart/Related content-type, each image must either
+ precede or follow the root component.
+
+ If images follow the root component, the Consumer must read all
+ remaining pages of the root component before it can print the
+ first page that references such images. The Consumer must wait
+ to print such a page until it has received the entire root
+ component, and the Consumer may not have the space to hold the
+ remaining pages.
+
+ If images precede the root component, the Producer must
+ determine and send all such images before it sends the root
+ component. The Consumer must, in the best case, wait some
+ additional time before it receives the first page of the root
+ component. In the worse case, the Consumer may not have enough
+ storage for all the images.
+
+ The Multipart/Related solution is not a good solution because
+ of the wait time and because, in some cases, the Consumer may
+ not have sufficient storage for all of the images.
+
+ With BEEP, the images and root component can be sent in separate
+ channels. The Producer can push each image when it encounters the
+ first reference or the Consumer can request it when it encounters
+ the first reference. The over-the-wire stream of octets is
+ similar to an Application/Vnd.pwg-multiplexed entity. However,
+ there is a substantial difference in behavior for a printing
+ application. With the Application/Vnd.pwg-multiplexed content-
+ type, the Producer puts each image message before its first
+ reference so that when the Consumer encounters a reference, the
+ image is guaranteed to be present on the printer. With BEEP, if
+ the Consumer pulls the image, the Consumer has to wait while the
+ image comes over the network. If the Producer pushes the image,
+ BEEP may put the image message after its first reference and the
+ Consumer may still have to wait for the image. A high-speed
+ printer should not have to risk waiting for images; otherwise it
+ cannot run at full speed.
+
+ Example 2: a scanning (fax-like) application. The Producer is a
+ scanner, which scans pages and sends them along with a vnd.pwg-
+ xhtml-print+xml root component that contains references to each page
+
+
+
+Herriot Informational [Page 4]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ image. Each page is referenced exactly once in the root-component.
+ The Consumer is a printer that consumes vnd.pwg-xhtml-print+xml
+ entities and their attachments. That is, the Consumer is not limited
+ to print jobs that come from scanners. A Producer and Consumer are
+ each presumed to have enough storage to hold a few page images and
+ most if not all of the root component. The Producer doesn't need any
+ additional knowledge of the Consumer's storage capabilities in order
+ to create an entity that the Consumer can successfully process. Of
+ course, a malicious Producer may try to exceed the storage
+ capabilities of the Consumer and the Consumer must guard against such
+ entities (see section 6). Here are ways to represent this compound
+ object.
+
+ With the Application/Vnd.pwg-multiplexed content-type, each page
+ image is a message and the root component is a message. The
+ Producer breaks the root component message into chunks with each
+ image message just before or just after its reference.
+
+ With the Multipart/Related content-type, the images cannot precede
+ the root component because the Consumer might not have enough
+ space to store them until the root component arrived. In this
+ case, the printer could fail to print the job correctly and the
+ Producer might not know. Therefore the images must follow the
+ root component, and the Producer must scan all pages before it can
+ send the first page. At the very least, this solution delays the
+ printing of the pages until all have been scanned. In the worst
+ case, the Producer does not have sufficient memory to buffer the
+ images, and the job fails.
+
+ With BEEP, the issues are the same as in the previous example,
+ except that speed is not as important in this case. So BEEP is a
+ viable alternative for this example.
+
+ Example 3: a printing application. A Producer creates a print stream
+ that consists of a series of pages, each of which references zero or
+ more images. Each image is referenced exactly once. The Producer
+ does not know what images to include with a page until it generates
+ that page, and the Producer doesn't know the layout details; the
+ Consumer handles layout. The Producer has enough storage to send the
+ root component and all images. However, it may not have enough
+ storage to hold the entire root component or all octets of any of the
+ images. The Consumer is presumed to have enough storage to render
+ the root component and to render each image. It may not have enough
+ storage to hold the entire root component or all octets of any of the
+ images. The Producer doesn't determine the Consumer's storage
+ capabilities. Rather it arranges the components so that the Consumer
+ is mostly likely to succeed. Of course, a malicious Producer may try
+
+
+
+
+Herriot Informational [Page 5]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ to exceed the storage capabilities of the Consumer, and the Consumer
+ must guard against such entities (see section 6). Here are ways to
+ represent this compound object.
+
+ With the Application/Vnd.pwg-multiplexed content-type, each image
+ is a message and the root component is a message. The Producer
+ breaks the root component message into chunks with each image
+ message just after its reference. The references appear first so
+ that the Consumer knows the location of each image before it
+ processes the image. This strategy minimizes storage needs for
+ Producer and Consumer and provides a good strategy in case of
+ failure. Here are the cases to consider.
+
+ a) When the document consists of vertically aligned blocks where
+ each block contains either lines of text or a single image, the
+ sequence of chunks is the same as the sequence of printable
+ blocks, thus minimizing Consumer buffering needs.
+
+ b) When a block can contain N side-by-side images, the Consumer
+ must buffer N-1 images unless the Producer interleaves the
+ images. If the Producer doesn't interleave the images, and the
+ Consumer runs out of storage before it has received N-1,
+ images, it can print what it has and print the remaining images
+ below; not what the Producer intended, but better than nothing.
+ If the Producer interleaves images, and the Consumer runs out
+ of storage before it has received the bands of N images, the
+ Consumer would print portions of images interleaved with
+ portions of other images. So, a Producer should not interleave
+ images.
+
+ c) When a block contains text and image side-by-side (i.e., run-
+ around text), there are additional buffering requirements.
+ When the Consumer processes the text that follows the
+ reference, it will place some of it next to the image (run-
+ around text) and will place the remaining text after the image.
+ The Producer doesn't know where the run-around ends, and thus
+ doesn't know where to end the text chunk and start the image
+ chunk. If the Producer ends the text too soon, then the
+ Consumer either has to process the entire image (if it has
+ enough storage) in order to get the remaining run-around text,
+ or it ends the run-around text prematurely. If the Producer
+ ends the text too late, then the Consumer may have to store too
+ much text and possibly put the image later than the Producer
+ requested. Because text data requires significantly less
+ storage than image data, a good strategy for Producer is to err
+ on the side of sending too much rather than too little text
+ before the image data.
+
+
+
+
+Herriot Informational [Page 6]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ d) When a block contains text and multiple side-by-side images,
+ the problem becomes a combination of items b) and c) above.
+
+ The Application/Vnd.pwg-multiplexed content-type can be made to
+ work in this example, but a Consumer must have failure strategies
+ and the result may not be quite what the producer intended. With
+ the Multipart/Related content-type, the images cannot precede the
+ root component because the Consumer might not have enough space to
+ store them until the root component arrived. Also, the images
+ cannot follow the root component because the Consumer might not
+ have enough storage for the root component before the first image
+ arrives. So the Multipart/Related content-type is not an
+ acceptable solution for this example.
+
+ With BEEP, the Producer can send the root component on channel 1
+ and the Consumer can request images on even numbered channels when
+ it encounters a reference. This solution allows more flexibility
+ than the Application/Vnd.pwg-multiplexed content-type. If there
+ are side-by-side images and/or run-around text, the Consumer can
+ request bands of each image or run-around text over separate
+ channels.
+
+ In all of these examples, the Application/Vnd.pwg-multiplexed
+ content-type provides a much better solution than Multipart/Related.
+ However, it is evenly matched with BEEP. For applications where
+ speed is important and ordering of the chunks is important in order
+ to avoid printing delays, the Application/Vnd.pwg-multiplexed
+ content-type is best. For applications, where the Consumer needs
+ more control over the ordering of received octets, BEEP is best.
+
+2. Terminology
+
+ This document uses some of the MIME terms that are defined in
+ [RFC2045]. The following are the terms used in this document:
+
+ Entity: the headers and the content. In this document, the term
+ "entity" describes all the octets that represent a compound
+ object.
+
+ Message: an entity as in [RFC2045]. In this document, the term
+ "message" describes all octets that represent one component of a
+ compound object. That is, it has MIME headers and content.
+
+ Body Part: an entity inside a multipart. That is, a body part is
+ the headers and content (i.e., octets) between the multipart
+ boundary strings not including the CRLF at the beginning and end.
+ This document never uses "entity" to mean "body part".
+
+
+
+
+Herriot Informational [Page 7]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ Headers: the initial lines of an entity, message or body part. An
+ empty line (i.e., two adjacent CRLFs) terminates the headers.
+ Sometimes the term "MIME header" is used instead of just "header".
+
+ Content: the part of an entity, message or body part that follows
+ the headers (i.e., follows the two adjacent CRLFs). The content
+ of a body part ends at the octet preceding the CRLF before the
+ multipart boundary string. The content of a message ends at the
+ octets specified by the length field in the Chunk Header.
+
+ This document uses the following additional terms.
+
+ Chunk: a chunk of data, consisting of a chunk header, a chunk
+ payload and a CRLF.
+
+ Chunk Header: the first line of a chunk. The line consists of the
+ "CHK" keyword, the message number, the length and the continuation
+ indicator, each separated by a single space character (ASCII 32).
+ A CRLF terminates the line. Each message in an
+ Application/Vnd.pwg-multiplexed entity has a message number that
+ normally differs from the message numbers of all other messages in
+ the Application/Vnd.pwg-multiplexed entity. The message number 0
+ is reserved for final Chunk Header in the Application/Vnd.pwg-
+ multiplexed entity.
+
+ Chunk Payload: the octets between the Chunk Header and the Chunk
+ Header of the next chunk. The length field in the header's length
+ field specifies the number of octets in the Chunk Payload. The
+ Chunk Payload is either a complete message or a part of a message.
+ The continuation field in the header specifies whether the chunk
+ is the last chunk of the message.
+
+ CRLF: the sequence of octets corresponding to the two US-ASCII
+ characters CR (decimal value 13) and LF (decimal value 10) which,
+ taken together, in this order, denote a line break. A CRLF
+ terminates each chunk in order to provide visual separation from
+ the next chunk header.
+
+ Consumer: the software that receives and processes a MIME entity,
+ e.g., software in a printer or software that reads a file.
+
+ Producer: the software that creates and sends a MIME entity, e.g.,
+ software in a scanner or software that writes a file.
+
+
+
+
+
+
+
+
+Herriot Informational [Page 8]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+3. Details
+
+ The Application/Vnd.pwg-multiplexed content-type, like
+ Multipart/Related, is intended to represent a compound object
+ consisting of several inter-related components. This document does
+ not specify the representation of these relationships, but [RFC2557]
+ contains examples of Multipart/Related entities that use the
+ Content-ID and Content-Location headers to identify body parts and
+ URLs (including the "cid" URL) to reference body parts. It is
+ expected that Application/Vnd.pwg-multiplexed entities would use the
+ patterns described in [RFC2557].
+
+ For an Application/Vnd.pwg-multiplexed entity, there is one parameter
+ for the Content-Type header. It is a "type" parameter, and it is
+ like the "type" parameter for the Multipart/Related content-type.
+ The value of the "type" parameter must be the content-type of the
+ root message and it effectively specifies the type of the compound
+ object.
+
+ An Application/Vnd.pwg-multiplexed entity contains a sequence of
+ chunks. Each chunk consists of a chunk header, a chunk payload and a
+ CRLF.
+
+ - The chunk header consists of a "CHK" keyword followed by the
+ message number, the chunk payload length, whether the chunk is
+ the last chunk of a message and, finally, a CRLF. The length
+ field removes the need for boundary strings that Multipart uses.
+ (See section 3.1 for the syntax of a chunk header).
+
+ - The chunk payload is a sequence of octets that is either a
+ complete message or a part of a message.
+
+ - The CRLF provides visual separation from the following chunk.
+
+ Each message represents a component of the compound object, and a
+ message is intended to have exactly the same representation, octet
+ for octet, as a body part of a Multipart/Related entity that
+ represents the same component. When a message is split across
+ multiple chunks, the chunks need not be contiguous.
+
+ The contents of an Application/Vnd.pwg-multiplexed entity have the
+ following properties:
+
+ 1) The first chunk contains a complete or partial message that (in
+ either case) represents the root component of the compound
+ object.
+
+
+
+
+
+Herriot Informational [Page 9]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ 2) Additional chunks contain messages or partial messages that
+ represent some component of the compound object.
+
+ 3) The final chunk's header contains a message number of 0, a
+ length of 0 and a last-chunk-of-message mark (i.e., the chunk
+ header line is "CHK 0 0 LAST"). The final chunk contains no
+ chunk payload.
+
+ 4) A message can be broken into multiple parts and each break can
+ occur anywhere within the message. Each part of the message is
+ zero or more bytes in length and each part of the message is
+ the contents of its own chunk. The order of the chunks within
+ the Application/Vnd.pwg-multiplexed entity must be the same as
+ the order of the parts within the message.
+
+ 5) A message represents a component of a compound object, and it
+ is intended that it have exactly the same representation, octet
+ for octet, as a body part of a Multipart/Related entity that
+ represents the same component. In particular, the message may
+ contain a Content-Type header to specify the content-type of
+ the message content. Also, the message may contain a Content-
+ ID header and/or Content-Location header to identify a message
+ that is referenced from within another message. If a message
+ contains no Content-Type header, then the message has an
+ implicit content-type of "text/plain; charset=us-ascii", cf.
+ [RFC2045].
+
+ See section 4 for a discussion displaying an Application/Vnd.pwg-
+ multiplexed entity.
+
+3.1 Syntax of Application/Vnd.pwg-multiplexed Contents
+
+ The ABNF [RFC2234] for the contents of an Application/Vnd.pwg-
+ multiplexed entity is:
+
+ contents = *chunk finalChunk
+ chunk = header payload CRLF
+ header = "CHK" SP messageNumber SP length SP isMore CRLF
+ messageNumber = 1..2147483647
+ length = 0..2147483647
+ isMore = "MORE" / "LAST"
+ payload = *OCTET
+ finalChunk = finalHeader CRLF
+ finalHeader = "CHK" SP "0" SP "0" SP "LAST" CRLF
+
+
+
+
+
+
+
+Herriot Informational [Page 10]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ The messageNumber field specifies the message that the chunk is
+ associated with. See the end of this section for more details.
+
+ The length field specifies the number of octets in the chunk payload
+ (represented in ABNF as "payload"). The first octet of the chunk
+ payload is the one immediately following the LF (i.e., final octet)
+ of the chunk header. The last octet of the chunk payload is the one
+ immediately preceding the two octets CRLF that end the chunk.
+
+ The isMore field has a value of "LAST" for the last chunk of a
+ message and "MORE" for all other chunks of a message.
+
+ Normally each message in an Application/Vnd.pwg-multiplexed entity
+ has a unique message number, and a message consists of the
+ concatenation of all the octets from the one or more chunks with the
+ same message number. The isMore field of the chunk header of the
+ last chunk of each message must have a value of "LAST" and the isMore
+ field of the chunk header of all other chunks must have a value of
+ "MORE".
+
+ Two or more messages may have the same message number, though such
+ reuse of message numbers is not recommended. The chunks with the
+ same message number represent a sequence of one or more messages
+ where the isMore field of the chunk header of the last chunk of each
+ message has a value of "LAST". All chunks whose isMore field of the
+ chunk header has the value of "MORE" belong to the same message as
+ the next chunk (in sequence) whose isMore field of the chunk header
+ has the value of "LAST". In other words, if two messages have the
+ same message number, the last chunk of the first message must occur
+ before the first chunk of the second message.
+
+ The behavior of the Consumer is undefined if the final Chunk (i.e.,
+ the Chunk whose chunk header is "CHK 0 0 LAST") occurs before the
+ last chunk of every message occurs.
+
+ Two adjacent chunks usually have different message numbers. However,
+ they may have the same message number. If two adjacent chunks have
+ the same message number, the two chunks could be combined into a
+ single chunk, but they need not be combined.
+
+ The number of octets in a chunk payload may be zero, and an
+ Application/Vnd.pwg-multiplexed entity may contain any number of
+ chunks with zero octets of chunk payload. For example, the last
+ chunk of each message may contain zero octets for programming
+ convenience. As another example, suppose that a particular compound
+ object format requires that referenced messages occur before the root
+ message. This document requires that the first chunk of an
+ Application/Vnd.pwg-multiplexed entity contain the root message or a
+
+
+
+Herriot Informational [Page 11]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ part of it. So, the first chunk contains a chunk payload of zero
+ octets with the first octet of the root message in the second chunk.
+ That is, all of the message headers of the root message are in the
+ second chunk. As an extreme but unlikely example, it would be
+ possible to have a message broken into ten chunks with zero octet
+ chunk payloads in all chunks except for chunks 4 and 7.
+
+3.2 Parameters for Application/Vnd.pwg-multiplexed
+
+ This section defines additional parameters for Application/Vnd.pwg-
+ multiplexed.
+
+3.2.1 The "type" Parameter
+
+ The type parameter must be specified. Its value is the content-type
+ of the "root" message. It permits a Consumer to determine the
+ content-type without reference to the enclosed message. If the value
+ of the type parameter differs from the content-type of the root
+ message, the Consumer's behavior is undefined.
+
+3.2.2 Syntax
+
+ The syntax for "parameter" is:
+
+ parameter := "type" "=" type "/" subtype ; cf. [RFC2045]
+
+4. Handling Application/Vnd.pwg-multiplexed Entities
+
+ The application that handles the Application/Vnd.pwg-multiplexed
+ entity has the responsibility for displaying the entity. However,
+ Application/Vnd.pwg-multiplexed messages may contain Content-
+ Disposition headers that provide suggestions for the display and
+ storage of a message, and in some cases the application may pay
+ attention to such headers.
+
+ As a reminder, Content-Disposition headers [RFC1806] allow the sender
+ to suggest presentation styles for MIME messages. There are two
+ presentation styles, 'inline' and 'attachment'. Content-Disposition
+ headers have a parameter for specifying a suggested file name for
+ storage.
+
+ There are three cases to consider for handling Application/Vnd.pwg-
+ multiplexed entities:
+
+ a) The Consumer recognizes Application/Vnd.pwg-multiplexed and the
+ content-type of the root. The Consumer determines the
+ presentation style for the compound object; it handles the
+ display of the components of the compound object in the context
+
+
+
+Herriot Informational [Page 12]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ of the compound object. In this case, the Content-Disposition
+ header information is redundant or even misleading, and the
+ Consumer shall ignore them for purposes of display. The
+ Consumer may use the suggested file name if the entity is
+ stored.
+
+ b) The Consumer recognizes Application/Vnd.pwg-multiplexed, but
+ not the content-type of the root. The Consumer will give the
+ user the choice of suppressing the entire Application/Vnd.pwg-
+ multiplexed entity or treating the Application/Vnd.pwg-
+ multiplexed entity as a Multipart/Mixed entity where each
+ message is a body part of the Multipart/Mixed entity. In this
+ case (where the entity is not suppressed), the Consumer may
+ find the Content-Disposition information useful for displaying
+ each body part of the resulting Multipart/Mixed entity. If a
+ body part has no Content-Disposition header, the Consumer
+ should display the body part as an attachment.
+
+ c) The Consumer does not recognize Application/Vnd.pwg-
+ multiplexed. The Consumer treats the Application/Vnd.pwg-
+ multiplexed entity as opaque and can do nothing with it.
+
+5. Examples
+
+ This section contains five examples. Each example is a different
+ representation of the same compound object. The compound object has
+ four components: an XHTML text component and three image components.
+ The images are encoded in binary. The string "<<binary data>>" and
+ "<<part of binary data>>" in each example represents all or part of
+ the binary data of each image. Two of the images are potentially
+ side by side and the third image is displayed later in the document.
+ All of the images are identified by Content-Id and two of the images
+ are also identified by a Content-Location. One of the images
+ references the Content-Location.
+
+ The first example shows a Multipart/Related representation of the
+ compound object in order to provide a representation that the reader
+ is familiar with. The remaining examples show Application/Vnd.pwg-
+ multiplexed representations of the same compound object. In the
+ second example, each chunk contains a whole message. In the third
+ example, the XHTML message is split across 3 chunks, and these chunks
+ are interleaved among the three image messages. In the fourth
+ example, the XHTML message is split across 4 chunks, and the two
+ side-by-side images are each split across two chunks. The XHTML
+ chunks are interleaved among the image chunks. In the fifth example,
+ there are chunks with empty payloads and adjacent chunks with the
+ same message number.
+
+
+
+
+Herriot Informational [Page 13]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ The last example may seem to address useless cases, but sometimes it
+ is easier to write software if these cases are allowed. For example,
+ when a buffer fills, it may be easiest to write a chunk and not worry
+ if the previous chunk had the same message number. Likewise, it may
+ be easiest to end a message with an empty chunk. Finally, the
+ Application/Vnd.pwg-multiplexed content-type requires that the first
+ chunk be part of the root message. Sometimes, it is more convenient
+ for the Producer if the root message starts after the occurrence of
+ some attachments. Since a chunk can be empty, the first chunk of the
+ root message can be empty, i.e., it doesn't even contain any headers.
+ Then the first chunk contains a part of the root message, but the
+ Producer doesn't generate any octets for that chunk.
+
+ Each body part of the Multipart/Related entity and each message of
+ the Application/Vnd.pwg-multiplexed entity contain a content-
+ disposition, which the Consumer uses according to the rules in
+ section 4. Note the location of the content-disposition headers in
+ the examples.
+
+5.1 Example With Multipart/Related
+
+ In this example, the compound object is represented as a
+ Multipart/Related entity so that the reader can compare it with the
+ Application/Vnd.pwg-multiplexed entities.
+
+ Content-Type: multipart/related; boundary="boundary-example";
+ type="text/xhtml+xml"
+
+ --boundary-example
+ Content-ID: <49568.44343xxx@foo.com>
+ Content-Type: application/vnd.pwg-xhtml-print+xml
+ Content-Disposition: inline
+
+ <?xml version="1.0"?>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+ <html xmlns="http://www.w3.org/TR/xhtml1">
+ <body>
+ <p>some text
+ <img src="cid:49568.45876xxx@foo.com"/>
+ <img src="http://foo.com/images/image2.gif"/>
+ some more text after the images
+ </p>
+ <p>some more text without images
+ </p>
+ <p>some more text
+ <img src="cid:49568.47333xxx@foo.com"/>
+ </p>
+
+
+
+Herriot Informational [Page 14]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ <p>some final text
+ </p>
+ </body>
+ </html>
+ --boundary-example
+ Content-ID: <49568.45876xxx@foo.com>
+ Content-Location: http://foo.com/images/image1.gif
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+ <<binary data>>
+ --boundary-example
+ Content-ID: <49568.46000xxx@foo.com>
+ Content-Location: http://foo.com/images/image2.gif
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+ <<binary data>>
+ --boundary-example
+ Content-ID: <49568.47333xxx@foo.com>
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+ <<binary data>>
+ --boundary-example--
+
+5.2 Examples with Application/Vnd.pwg-multiplexed
+
+ The four examples in this section show Application/Vnd.pwg-
+ multiplexed representations of the same compound object. Note that
+ each CRLF is represented by a visual line break.
+
+5.2.1 Example Where Each Chunk Has a Complete Message
+
+ In this example, the compound object is represented as an
+ Application/Vnd.pwg-multiplexed entity. Each chunk contains an
+ entire message, i.e., none of the messages are split across multiple
+ chunks. Each message in this example is identical to the
+ corresponding body part in the preceding Multipart/Relate example.
+
+ Content-Type: application/vnd.pwg-multiplexed;
+ type="application/vnd.pwg-xhtml-print+xml"
+
+ CHK 1 550 LAST
+ Content-ID: <49568.44343xxx@foo.com>
+ Content-Type: application/vnd.pwg-xhtml-print+xml
+ Content-Disposition: inline
+
+
+
+
+Herriot Informational [Page 15]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ <?xml version="1.0"?>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+ <html xmlns="http://www.w3.org/TR/xhtml1">
+ <body>
+ <p>some text
+ <img src="cid:49568.45876xxx@foo.com"/>
+ <img src="http://foo.com/images/image2.gif"/>
+ some more text after the images
+ </p>
+ <p>some more text without images
+ </p>
+ <p>some more text
+ <img src="cid:49568.47333xxx@foo.com"/>
+ </p>
+ <p>some final text
+ </p>
+ </body>
+ </html>
+
+ CHK 2 6346 LAST
+ Content-ID: <49568.45876xxx@foo.com>
+ Content-Location: http://foo.com/images/image1.gif
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+ <<binary data>>
+ CHK 3 6401 LAST
+ Content-ID: <49568.46000xxx@foo.com>
+ Content-Location: http://foo.com/images/image2.gif
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+ <<binary data>>
+ CHK 4 7603 LAST
+ Content-ID: <49568.47333xxx@foo.com>
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+ <<binary data>>
+ CHK 0 0 LAST
+
+
+
+
+
+
+
+
+
+
+Herriot Informational [Page 16]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+5.2.2 Example of Chunking the Root Message
+
+ In this example, the compound object is represented as an
+ Application/Vnd.pwg-multiplexed entity. The message containing the
+ XHTML component is split into 3 pieces so that the reference to an
+ image is as close as possible to the beginning of the chunk. The
+ chunk containing the referenced image message occurs just before the
+ chunk with the reference. This minimizes the distance between
+ reference and referenced message.
+
+ Note that there are other possible arrangements (see the third
+ example in section 5.2.3). For example, a sender could split the
+ XHTML message so that the reference to an image is as close as
+ possible to the end of the chunk. Then the chunk containing the
+ referenced image message should occur just after the chunk with the
+ reference. The sender could mix this strategy with the one used in
+ this example.
+
+ Content-Type: application/vnd.pwg-multiplexed;
+ type=" application/vnd.pwg-xhtml-print+xml"
+
+ CHK 1 267 MORE
+ Content-ID: <49568.44343xxx@foo.com>
+ Content-Type: application/vnd.pwg-xhtml-print+xml
+ Content-Disposition: inline
+
+ <?xml version="1.0"?>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+ <html xmlns="http://www.w3.org/TR/xhtml1">
+ <body>
+ <p>some text
+
+ CHK 2 6346 LAST
+ Content-ID: <49568.45876xxx@foo.com>
+ Content-Location: http://foo.com/images/image1.gif
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+ <<binary data>>
+ CHK 3 6401 LAST
+ Content-ID: <49568.46000xxx@foo.com>
+ Content-Location: http://foo.com/images/image2.gif
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+
+
+
+
+
+Herriot Informational [Page 17]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ <<binary data>>
+ CHK 1 166 MORE
+ <img src="cid:49568.45876xxx@foo.com"/>
+ <img src="http://foo.com/images/image2.gif"/>
+ some more text after the images
+ </p>
+ <p>some more text without images
+ </p>
+ <p>some more text
+
+ CHK 4 7603 LAST
+ Content-ID: <49568.47333xxx@foo.com>
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+ <<binary data>>
+ CHK 1 80 LAST
+ <img src="cid:49568.47333xxx@foo.com"/>
+ </p>
+ <p>some final text
+ </p>
+ </body>
+ </html>
+
+ CHK 0 0 LAST
+
+5.2.3 Example of Chunking the Several Messages
+
+ In this example, the compound object is represented as an
+ Application/Vnd.pwg-multiplexed entity. The message containing the
+ XHTML component is split into 4 pieces so that the reference to an
+ image is as close as possible to either the beginning or the end of
+ the chunk. The references to the first and second images closely
+ follow the referenced images. The reference to the third image
+ closely precedes the referenced image. This minimizes the distance
+ between reference and referenced message. In addition, the first two
+ image messages are split into two chunks each.
+
+ Content-Type: application/vnd.pwg-multiplexed;
+ type=" application/vnd.pwg-xhtml-print+xml"
+
+ CHK 1 303 MORE
+ Content-ID: <49568.44343xxx@foo.com>
+ Content-Type: application/vnd.pwg-xhtml-print+xml
+ Content-Disposition: inline
+
+
+
+
+
+
+Herriot Informational [Page 18]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ <?xml version="1.0"?>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+ <html xmlns="http://www.w3.org/TR/xhtml1">
+ <body>
+ <p>some text
+
+ CHK 2 184 MORE
+ Content-ID: <49568.45876xxx@foo.com>
+ Content-Location: http://foo.com/images/image1.gif
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+ <<part of binary data>>
+ CHK 3 200 MORE
+ Content-ID: <49568.46000xxx@foo.com>
+ Content-Location: http://foo.com/images/image2.gif
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+ <<part of binary data>>
+ CHK 1 78 MORE
+ <img src="cid:49568.45876xxx@foo.com"/>
+ <img src="http://foo.com/images/image2.gif"/>
+
+ CHK 2 6162 LAST
+ <<part of binary data>>
+ CHK 3 6201 LAST
+ <<part of binary data>>
+ CHK 1 127 MORE
+ some more text after the images
+ </p>
+ <p>some more text without images
+ </p>
+ <p>some more text
+ <img src="cid:49568.47333xxx@foo.com"/>
+
+ CHK 4 7603 LAST
+ Content-ID: <49568.47333xxx@foo.com>
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+
+
+
+
+
+
+
+
+
+Herriot Informational [Page 19]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ <<binary data>>
+ CHK 1 41 LAST
+ </p>
+ <p>some final text
+ </p>
+ </body>
+ </html>
+
+ CHK 0 0 LAST
+
+5.2.4 Example of Chunks with Empty Payloads
+
+ This example is identical to the previous one, except that some
+ chunks have a chunk payload of zero octets. The root message starts
+ with a chunk whose payload is empty and every message ends with a
+ chunk whose payload is empty. This example also shows two adjacent
+ chunks that are from the same message. These two chunks could be
+ coalesced into a single chunk, but they might be kept separate for
+ programming convenience.
+
+ Content-Type: application/vnd.pwg-multiplexed;
+ type=" application/vnd.pwg-xhtml-print+xml"
+
+ CHK 1 0 MORE
+
+ CHK 2 184 MORE
+ Content-ID: <49568.45876xxx@foo.com>
+ Content-Location: http://foo.com/images/image1.gif
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+ <<part of binary data>>
+ CHK 3 200 MORE
+ Content-ID: <49568.46000xxx@foo.com>
+ Content-Location: http://foo.com/images/image2.gif
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+ <<part of binary data>>
+ CHK 1 303 MORE
+ Content-ID: <49568.44343xxx@foo.com>
+ Content-Type: application/vnd.pwg-xhtml-print+xml
+ Content-Disposition: inline
+
+
+
+
+
+
+
+
+Herriot Informational [Page 20]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ <?xml version="1.0"?>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+ <html xmlns="http://www.w3.org/TR/xhtml1">
+ <body>
+ <p>some text
+
+ CHK 2 6162 MORE
+ <<part of binary data>>
+ CHK 3 6201 MORE
+ <<part of binary data>>
+ CHK 2 0 LAST
+
+ CHK 3 0 LAST
+
+ CHK 1 78 MORE
+ <img src="cid:49568.45876xxx@foo.com"/>
+ <img src="http://foo.com/images/image2.gif"/>
+
+ CHK 4 7603 MORE
+ Content-ID: <49568.47333xxx@foo.com>
+ Content-Type: image/gif
+ Content-Disposition: attachment
+
+ <<binary data>>
+ CHK 4 0 LAST
+
+ CHK 1 127 MORE
+ some more text after the images
+ </p>
+ <p>some more text without images
+ </p>
+ <p>some more text
+ <img src="cid:49568.47333xxx@foo.com"/>
+
+ CHK 1 41 MORE
+ </p>
+ <p>some final text
+ </p>
+ </body>
+ </html>
+
+ CHK 1 0 LAST
+
+ CHK 0 0 LAST
+
+
+
+
+
+
+Herriot Informational [Page 21]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+6. Security Considerations
+
+ There are security considerations that pertain to each message of an
+ Application/Vnd.pwg-multiplexed entity. Those security
+ considerations are described by the document that defines the
+ content-type of the message. They are not addressed in this
+ document.
+
+ There are also security considerations that pertain to the
+ Application/Vnd.pwg-multiplexed entity as a whole. A Producer that
+ is buggy or malicious may send an Application/Vnd.pwg-multiplexed
+ entity that could cause a Consumer to request more storage than it
+ has, even if it has a large amount of storage. A Consumer must be
+ able to deal gracefully with the following scenarios and combinations
+ of them:
+
+ - The chunks of one or more messages are separated by a very large
+ number of octets. In the extreme case some or all of the
+ messages don't terminate, i.e., they don't contain a closing
+ chunk.
+ - A very large number of messages are started and interleaved
+ before their final chunk occurs.
+ - A message contains one or more references to other messages that
+ never occur or don't occur for a large number of octets.
+ - A very large number of referenced messages occur before the
+ Consumer knows that it can discard them.
+
+7. Registration Information for Application/Vnd.pwg-multiplexed
+
+ The following form is copied from RFC 1590, Appendix A.
+
+ To: iana@iana.org
+
+ Subject: Registration of new Media Type
+ application/Vnd.pwg-multiplexed
+ Media Type name: Application
+ Media subtype name: Vendor Tree - vnd.pwg-multiplexed
+ Required parameters: Type, a media type/subtype.
+ Optional parameters: No optional parameters
+ Encoding considerations: Each message of an
+ Application/Vnd.pwg-multiplexed entity can be
+ encoded in any manner allowed by the Content-
+ Type of the message. However, using the
+ reasoning of Multipart, the
+ Application/Vnd.pwg-multiplexed entity cannot
+ be encoded. Otherwise, a message would be
+
+
+
+
+
+Herriot Informational [Page 22]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ encoded twice, once at the message level and
+ once at the Application/Vnd.pwg-multiplexed
+ level.
+ Security considerations: See section 6 (Security
+ Considerations) of RFC 3391.
+ Published specification: RFC 3391.
+ Person & email address to contact for further information:
+
+ Robert Herriot
+ 706 Colorado Ave.
+ Palo Alto, CA 94303
+ USA
+ Phone: 1-650-327-4466
+ Fax: 1-650-327-4466
+ EMail: bob@herriot.com
+
+8. Acknowledgments
+
+ The author gratefully acknowledges the contributions of: Ugo Corda,
+ Dave Crocker, Melinda Sue Grant, Graham Klyne, Carl-Uno Manros, Larry
+ Masinter, Ira McDonald, Chris Newman, Henrik Frystyk Nielsen and Dale
+ R. Worley. In particular, Chris Newman provided invaluable help.
+
+9. References
+
+ [RFC1806] Troost, R. and S. Dorner, "Communicating Presentation
+ Information in Internet Messages: The Content-Disposition
+ Header", RFC 1806, June 1995.
+
+ [RFC1873] Levinson, E. and J. Clark, "Message/External-Body Content-
+ ID Access Type", RFC 1873, December 1995.
+ Levinson, E., "Message/External-Body Content-ID Access
+ Type", Work in Progress.
+
+ [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part One: Format of Internet Message
+ Bodies", RFC 2045, November 1996.
+
+ [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046,
+ November 1996.
+
+ [RFC2234] Crocker, D. and P. Overell, "Augmented BNF for
+ SyntaxSpecifications: ABNF", RFC 2234, November 1997.
+
+ [RFC2387] Levinson, E., "The MIME Multipart/Related Content-type",
+ RFC 2387, August 1998.
+
+
+
+
+Herriot Informational [Page 23]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+ [RFC2392] Levinson, E., "Content-ID and Message-ID Uniform Resource
+ Locators", RFC 2392, August 1998.
+
+ [RFC2557] Palme, J., "MIME Encapsulation of Aggregate Documents, such
+ as HTML (MHTML", RFC 2557, March 1999.
+
+ [RFC2822] Resnick, P., Editor, "Internet Message Format", RFC 2822,
+ April 2001.
+
+ [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core",
+ RFC 3080, March 2001.
+
+10. Author's Address
+
+ Robert Herriot
+ 706 Colorado Ave.
+ Palo Alto, CA 94303
+ USA
+
+ Phone: 1-650-327-4466
+ Fax: 1-650-327-4466
+ EMail: bob@herriot.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot Informational [Page 24]
+
+RFC 3391 Application/Multiplexed December 2002
+
+
+11. Full Copyright Statement
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot Informational [Page 25]
+
diff --git a/standards/rfc3510.txt b/standards/rfc3510.txt
new file mode 100644
index 000000000..c61ce5f2b
--- /dev/null
+++ b/standards/rfc3510.txt
@@ -0,0 +1,899 @@
+
+
+
+
+
+
+Network Working Group R. Herriot
+Request for Comments: 3510 I. McDonald
+Updates: 2910 High North Inc.
+Category: Standards Track April 2003
+
+
+ Internet Printing Protocol/1.1:
+ IPP URL Scheme
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+Abstract
+
+ This memo defines the "ipp" URL (Uniform Resource Locator) scheme.
+ This memo updates IPP/1.1: Encoding and Transport (RFC 2910), by
+ expanding and clarifying Section 5, "IPP URL Scheme", of RFC 2910.
+ An "ipp" URL is used to specify the network location of a print
+ service that supports the IPP Protocol (RFC 2910), or of a network
+ resource (for example, a print job) managed by such a print service.
+
+Table of Contents
+
+ 1. Introduction ............................................... 2
+ 2. Terminology ................................................ 3
+ 2.1. Conformance Terminology .............................. 3
+ 2.2. Model Terminology .................................... 3
+ 3. IPP Model for Printers and Jobs ............................ 3
+ 4. IPP URL Scheme ............................................. 4
+ 4.1. IPP URL Scheme Applicability ......................... 4
+ 4.2. IPP URL Scheme Associated Port ....................... 4
+ 4.3. IPP URL Scheme Associated MIME Type .................. 5
+ 4.4. IPP URL Scheme Character Encoding .................... 5
+ 4.5. IPP URL Scheme Syntax ................................ 5
+ 4.6. IPP URL Examples ..................................... 6
+ 4.6.1. IPP Printer URL Examples ..................... 6
+ 4.6.2. IPP Job URL Examples ......................... 6
+ 4.7. IPP URL Comparisons .................................. 7
+
+
+
+
+Herriot & McDonald Standards Track [Page 1]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+ 5. Conformance Requirements ................................... 8
+ 5.1. IPP Client Conformance Requirements .................. 8
+ 5.2. IPP Printer Conformance Requirements ................. 8
+ 6. IANA Considerations ........................................ 9
+ 7. Internationalization Considerations ........................ 9
+ 8. Security Considerations .................................... 9
+ 9. Intellectual Property Rights ............................... 10
+ 10. Normative References ....................................... 11
+ 11. Informative References ..................................... 11
+ 12. Acknowledgments ............................................ 12
+ Appendix A - Registration of "ipp" URL Scheme .................. 13
+ Authors' Addresses ............................................. 15
+ Full Copyright Statement ....................................... 16
+
+1. Introduction
+
+ This memo conforms to all of the requirements in Registration
+ Procedures for URL Scheme Names [RFC2717]. This memo also follows
+ all of the recommendations in Guidelines for new URL Schemes
+ [RFC2718].
+
+ See section 1, "Introduction", of [RFC2911] and section 1,
+ "Introduction", of [RFC3196] for overview information about IPP. See
+ section 10, "Description of the Base IPP Documents", of [RFC3196] for
+ a full description of the IPP document set.
+
+ This memo updates IPP/1.1: Encoding and Transport (RFC 2910), by
+ expanding and clarifying Section 5, "IPP URL Scheme", of RFC 2910,
+ but does not define any new parameters or other new extensions to the
+ syntax of IPP URLs.
+
+ The IPP URL scheme defined in this document is based on the ABNF for
+ the HTTP URL scheme defined in HTTP [RFC2616], which in turn is
+ derived from the URI Generic Syntax [RFC2396] and further updated for
+ IPv6 by [RFC2732]. An IPP URL is transformed into an HTTP URL
+ according to the rules specified in section 5 of IPP Protocol
+ [RFC2910].
+
+ This document defines IPP URL scheme applicability, associated port
+ (631), associated MIME type ("application/ipp"), character encoding,
+ and syntax.
+
+ This document is laid out as follows:
+
+ - Section 2 defines the terminology used throughout the document.
+
+ - Section 3 supplies references to the IPP Printer and IPP Job
+ object model defined in IPP Model [RFC2911].
+
+
+
+Herriot & McDonald Standards Track [Page 2]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+ - Section 4 specifies the IPP URL scheme.
+
+ - Section 5 specifies the conformance requirements for IPP Clients
+ and IPP Printers that claim conformance to this document.
+
+ - Sections 6, 7, and 8 specify IANA, internationalization, and
+ security considerations.
+
+ - Sections 9, 10, 11, 12, and 13 specify normative references,
+ informative references, acknowledgements, authors' addresses, and
+ full IETF copyright statement.
+
+ - Section 14 (Appendix A) is a completed registration template for
+ the IPP URL Scheme (see section 6.0 of [RFC2717]).
+
+2. Terminology
+
+ This specification document uses the terminology defined in this
+ section.
+
+2.1. Conformance Terminology
+
+ The uppercase terms "MUST", "MUST NOT", "REQUIRED", "SHALL",
+ "SHALL NOT" "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and
+ "OPTIONAL" in this document are to be interpreted as described in
+ [RFC2119]. These terms are used to specify conformance
+ requirements for all implementations (both print clients and print
+ services) of this specification.
+
+2.2. Model Terminology
+
+ See section 12.2, "Model Terminology", in IPP Model [RFC2911].
+
+3. IPP Model for Printers and Jobs
+
+ See section 2, "IPP Objects", section 2.1, "Printer Object", and
+ section 2.2, "Job Object", in [RFC2911] for a full description of
+ the IPP object model and terminology.
+
+ In this document, "IPP Client" means the software (on some
+ hardware platform) that submits, monitors, and/or manages print
+ jobs via the IPP Protocol [RFC2910] to a print spooler, print
+ gateway, or physical printing device.
+
+
+
+
+
+
+
+
+Herriot & McDonald Standards Track [Page 3]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+ In this document, "IPP Printer object" means the software (on some
+ hardware platform) that receives print jobs and/or printer/job
+ operations via the IPP Protocol [RFC2910] from an "IPP Client".
+
+ In this document, "IPP Printer" is a synonym for "IPP Printer
+ object".
+
+ In this document, "IPP Job object" means the set of attributes and
+ documents for one print job instantiated on an "IPP Printer".
+
+ In this document, "IPP Job" is a synonym for "IPP Job object".
+
+ In this document, "IPP URL" means a URL with the "ipp" scheme.
+
+ Note: In this document, "IPP URL" is a synonym for "ipp-URL" (in
+ section 4, "IPP URL Scheme", of this document) and "ipp-URL" (in
+ section 5, "IPP URL Scheme", of [RFC2910]).
+
+4. IPP URL Scheme
+
+4.1. IPP URL Scheme Applicability
+
+ The "ipp" URL scheme MUST only be used to specify absolute URLs
+ (relative IPP URLs are not allowed) for IPP print services and
+ their associated network resources. The "ipp" URL scheme MUST
+ only be used to specify the use of the abstract protocol defined
+ in IPP Model [RFC2911] over an HTTP [RFC2616] transport, as
+ defined in IPP Protocol [RFC2910]. Any other transport binding
+ for the abstract protocol defined in IPP Model [RFC2911] would
+ require a different URL scheme.
+
+ The "ipp" URL scheme allows an IPP client to choose an appropriate
+ IPP print service (for example, from a directory). The IPP client
+ can establish an HTTP connection to the specified IPP print
+ service. The IPP client can send IPP protocol requests (for
+ example, a "Print-Job" request) and receive IPP protocol responses
+ over that HTTP connection.
+
+4.2. IPP URL Scheme Associated Port
+
+ All IPP URLs which do NOT explicitly specify a port MUST be
+ resolved to IANA-assigned well-known port 631, as registered in
+ [IANA-PORTREG].
+
+ See: IANA Port Numbers Registry [IANA-PORTREG].
+ See: IPP Protocol [RFC2910].
+
+
+
+
+
+Herriot & McDonald Standards Track [Page 4]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+4.3. IPP URL Scheme Associated MIME Type
+
+ All IPP URLs MUST be used to specify network print services which
+ support the "application/ipp" MIME media type as registered in
+ [IANA-MIMEREG] for IPP protocol requests and responses.
+
+ See: IANA MIME Media Types Registry [IANA-MIMEREG].
+ See: IPP Protocol [RFC2910].
+
+4.4. IPP URL Scheme Character Encoding
+
+ IPP URLs MUST use [RFC2396] encoding, as do their equivalent HTTP
+ URLs. Characters other than those in the "reserved" and "unsafe"
+ sets [RFC2396] are equivalent to their ""%" HEX HEX" encoding.
+
+4.5. IPP URL Scheme Syntax
+
+ The abstract protocol defined in IPP Model [RFC2911] places a
+ limit of 1023 octets (NOT characters) on the length of a URI (see
+ section 4.1.5, "uri", in [RFC2911]).
+
+ Note: IPP Printers ought to be cautious about depending on URI
+ lengths above 255 bytes, because some older client implementations
+ might not properly support these lengths.
+
+ IPP URLs MUST be represented in absolute form. Absolute URLs MUST
+ always begin with a scheme name followed by a colon. For definitive
+ information on URL syntax and semantics, see "Uniform Resource
+ Identifiers (URI): Generic Syntax and Semantics" [RFC2396]. This
+ specification adopts the definitions of "host", "port", "abs_path",
+ and "query" from [RFC2396], as updated for IPv6 by [RFC2732].
+
+ The IPP URL scheme syntax in ABNF is as follows:
+
+ ipp-URL = "ipp:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
+
+ If the port is empty or not given, port 631 is assumed. The
+ semantics are that the identified resource (see section 5.1.2 of
+ [RFC2616]) is located at the IPP print service listening for HTTP
+ connections on that port of that host, and the Request-URI for the
+ identified resource is 'abs_path'.
+
+ If the 'abs_path' is not present in the URL, it MUST be given as "/"
+ when used as a Request-URI for a resource (see section 5.1.2 of
+ [RFC2616]).
+
+
+
+
+
+
+Herriot & McDonald Standards Track [Page 5]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+4.6. IPP URL Examples
+
+ Note: Literal IPv4 or IPv6 addresses SHOULD NOT be used in IPP URLs.
+
+4.6.1. IPP Printer URL Examples
+
+ The following are examples of well-formed IPP URLs for IPP Printers
+ (for example, to be used as protocol elements in 'printer-uri'
+ operation attributes of 'Print-Job' request messages):
+
+ ipp://example.com
+ ipp://example.com/printer
+ ipp://example.com/printer/tiger
+ ipp://example.com/printer/fox
+ ipp://example.com/printer/tiger/bob
+ ipp://example.com/printer/tiger/ira
+
+ Each of the above URLs are well-formed URLs for IPP Printers and each
+ would reference a logically different IPP Printer, even though some
+ of those IPP Printers might share the same host system. The 'bob' or
+ 'ira' last path components might represent two different physical
+ printer devices, while 'tiger' might represent some grouping of IPP
+ Printers (for example, a load-balancing spooler). Or the 'bob' and
+ 'ira' last path components might represent separate human recipients
+ on the same physical printer device (for example, a physical printer
+ supporting two job queues). In either case, both 'bob' and 'ira'
+ would behave as different and independent IPP Printers.
+
+ The following are examples of well-formed IPP URLs for IPP Printers
+ with (optional) ports and paths:
+
+ ipp://example.com
+ ipp://example.com/~smith/printer
+ ipp://example.com:631/~smith/printer
+
+ The first and second IPP URLs above MUST be resolved to port 631
+ (IANA assigned well-known port for IPP). The second and third IPP
+ URLs above are equivalent (see section 4.7 below).
+
+4.6.2. IPP Job URL Examples
+
+ The following are examples of well-formed IPP URLs for IPP Jobs (for
+ example, to be used as protocol elements in 'job-uri' attributes of
+ 'Print-Job' response messages):
+
+ ipp://example.com/printer/123
+ ipp://example.com/printer/tiger/job123
+
+
+
+
+Herriot & McDonald Standards Track [Page 6]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+ IPP Job URLs are valid and meaningful only until Job completion and
+ possibly an implementation defined optional period of persistence
+ after Job completion (see IPP Model [RFC2911]).
+
+ Ambiguously, section 4.3.1 'job-uri' of IPP Model [RFC2911] states
+ that:
+
+ "the precise format of a Job URI is implementation dependent."
+
+ Thus, the relationship between the value of the "printer-uri"
+ operation attribute used in a 'Print-Job' request and the value of
+ the "job-uri" attribute returned in the corresponding 'Print-Job'
+ response is implementation dependent. Also, section 4.3.3 'job-
+ printer-uri' of IPP Model [RFC2911] states that the 'job-printer-uri'
+ attribute of a Job object:
+
+ "permits a client to identify the Printer object that created this
+ Job object when only the Job object's URI is available to the
+ client."
+
+ However, the above statement is false, because the transform from an
+ IPP Job URL to the corresponding IPP Printer URL is unspecified in
+ either IPP Model [RFC2911] or IPP Protocol [RFC2910].
+
+ IPP Printers that conform to this specification SHOULD only generate
+ IPP Job URLs (for example, in the "job-uri" attribute in a 'Print-
+ Job' response) by appending exactly one path component to the
+ corresponding IPP Printer URL (for interoperability).
+
+4.7. IPP URL Comparisons
+
+ When comparing two IPP URLs to decide if they match or not, an IPP
+ Client MUST use the same rules as those defined for HTTP URI
+ comparisons in [RFC2616], with the sole following exception:
+
+ - A port that is empty or not given MUST be treated as equivalent to
+ the well-known port for that IPP URL (port 631);
+
+ See: Section 3.2.3, "URI Comparison", in [RFC2616].
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot & McDonald Standards Track [Page 7]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+5. Conformance Requirements
+
+5.1. IPP Client Conformance Requirements
+
+ IPP Clients that conform to this specification:
+
+ a) MUST only send IPP protocol connections to the port specified in
+ each given IPP URL (if present) or otherwise to IANA assigned
+ well-known port 631;
+
+ b) MUST only send IPP URLs used as protocol elements in outgoing IPP
+ protocol request messages (for example, in the "printer-uri"
+ operation attribute in a 'Print-Job' request) that conform to the
+ ABNF specified in section 4.5, "IPP URL Scheme Syntax, of this
+ document;
+
+ c) MUST only convert IPP URLs to their corresponding HTTP URL forms
+ according to the rules in section 5, "IPP URL Scheme", in
+ [RFC2910].
+
+5.2. IPP Printer Conformance Requirements
+
+ IPP Printers that conform to this specification:
+
+ a) MUST listen for incoming IPP protocol connections on IANA-assigned
+ well-known port 631, unless explicitly configured by system
+ administrators or site policies;
+
+ b) SHOULD NOT listen for incoming IPP protocol connections on any
+ other port, unless explicitly configured by system administrators
+ or site policies;
+
+ c) SHOULD only accept IPP URLs used as protocol elements in incoming
+ IPP protocol request messages (for example, in the "printer-uri"
+ operation attribute in a 'Print-Job' request) that conform to the
+ ABNF specified in section 4.5, "IPP URL Scheme Syntax", of this
+ document;
+
+ d) SHOULD only send IPP URLs used as protocol elements in outgoing
+ IPP protocol response messages (for example, in the "job-uri"
+ attribute in a 'Print-Job' response) that conform to the ABNF
+ specified in section 4.5, "IPP URL Scheme Syntax", of this
+ document;
+
+ e) SHOULD only generate IPP Job URLs (for example, in the "job-uri"
+ attribute in a 'Print-Job' response) by appending exactly one path
+ component to the corresponding IPP Printer URL (for
+ interoperability);
+
+
+
+Herriot & McDonald Standards Track [Page 8]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+ f) SHOULD NOT use literal IPv6 or IPv4 addresses in configured or
+ locally generated IPP URLs.
+
+6. IANA Considerations
+
+ This IPP URL Scheme specification does not introduce any additional
+ IANA considerations, beyond those described in [RFC2910] and
+ [RFC2911].
+
+ See: Section 6, "IANA Considerations" in [RFC2910]
+ See: Section 6, "IANA Considerations" in [RFC2911].
+
+7. Internationalization Considerations
+
+ This IPP URL Scheme specification does not introduce any additional
+ internationalization considerations, beyond those described in
+ [RFC2910] and [RFC2911].
+
+ See: Section 7, "Internationalization Considerations", in [RFC2910].
+ See: Section 7, "Internationalization Considerations", in [RFC2911].
+
+8. Security Considerations
+
+ This IPP URL Scheme specification does not introduce any additional
+ security considerations, beyond those described in [RFC2910] and
+ [RFC2911], except the following:
+
+ a) An IPP URL might be faked to point to a rogue IPP print service,
+ thus collecting confidential document contents from IPP clients.
+ Server authentication mechanisms and security mechanisms specified
+ in the IPP Protocol [RFC2910] are sufficient to address this
+ threat.
+
+ b) An IPP URL might be used to access an IPP print service by an
+ unauthorized IPP client. Client authentication mechanisms and
+ security mechanisms specified in the IPP Protocol [RFC2910] are
+ sufficient to address this threat.
+
+ c) An IPP URL might be used to access an IPP print service at a print
+ protocol application layer gateway (for example, an IPP to LPD
+ gateway [RFC2569]) causing silent compromise of IPP security
+ mechanisms. There is no practical defense against this threat by
+ a client system. System administrators should avoid such
+ compromising configurations.
+
+ d) An IPP URL does not have parameters to specify the required client
+ authentication mechanism (for example, 'certificate' as defined in
+ section 4.4.2, "uri-authentication-supported", of IPP Model
+
+
+
+Herriot & McDonald Standards Track [Page 9]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+ [RFC2911]) and required security mechanism (for example, 'tls' as
+ defined in section 4.4.3, "uri-security-supported", of IPP Model
+ [RFC2911]). Service discovery or directory protocols might be
+ used to discover the required client authentication and security
+ mechanisms associated with given IPP URLs.
+
+ Historical Note: During the development of this document,
+ consideration was given to the addition of standard IPP URL
+ parameters for the client authentication and security mechanisms.
+ However, based on a strong IETF IPP Working Group consensus, no
+ parameters were added to the "ipp" URL scheme as originally defined
+ in IPP Protocol [RFC2910] in September 2000, for reasons of backwards
+ compatibility with the many currently shipping implementations of
+ IPP/1.1.
+
+ See: Section 8, "Security Considerations", in [RFC2910].
+ See: Section 8, "Security Considerations", in [RFC2911].
+
+9. Intellectual Property Rights
+
+ The IETF takes no position regarding the validity or scope of any
+ intellectual property or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; neither does it represent that it
+ has made any effort to identify any such rights. Information on the
+ IETF's procedures with respect to rights in standards-track and
+ standards-related documentation can be found in BCP-11. Copies of
+ claims of rights made available for publication and any assurances of
+ licenses to be made available, or the result of an attempt made to
+ obtain a general license or permission for the use of such
+ proprietary rights by implementors or users of this specification can
+ be obtained from the IETF Secretariat.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights which may cover technology that may be required to practice
+ this standard. Please address the information to the IETF Executive
+ Director.
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot & McDonald Standards Track [Page 10]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+10. Normative References
+
+ [RFC2234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter,
+ "Uniform Resource Identifiers (URI): Generic Syntax",
+ RFC 2396, August 1998.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P. and T. Berners-Lee, "Hypertext
+ Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC2732] Hinden, R., Carpenter, B. and L. Masinter, "Format for
+ Literal IPv6 Addresses in URL's", RFC 2732, December
+ 1999.
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P., Turner, R. and J.
+ Wenn, "IPP/1.1 Encoding and Transport [IPP Protocol]",
+ RFC 2910, September 2000.
+
+ [RFC2911] Hastings, T., Herriot, R., deBry, R., Isaacson, S. and
+ P. Powell, "IPP/1.1 Model and Semantics [IPP Model]",
+ RFC 2911, September 2000.
+
+ [US-ASCII] Coded Character Set -- 7-bit American Standard Code
+ for Information Interchange, ANSI X3.4-1986.
+
+11. Informative References
+
+ [IANA-MIMEREG] IANA MIME Media Types Registry.
+ ftp://ftp.iana.org/in-notes/iana/assignments/media-
+ types/...
+
+ [IANA-PORTREG] IANA Port Numbers Registry. ftp://ftp.iana.org/in-
+ notes/iana/assignments/port-numbers
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569,
+ April 1999.
+
+ [RFC2717] Petke, R. and I. King, "Registration Procedures for
+ URL Scheme Names", RFC 2717, November 1999.
+
+ [RFC2718] Masinter, L., Alvestrand, H., Zigmond, D. and R.
+ Petke, "Guidelines for new URL Schemes", RFC 2718,
+ November 1999.
+
+
+
+
+Herriot & McDonald Standards Track [Page 11]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+ [RFC3196] Hastings, T., Manros, C., Zehler, P., Kugler, C. and
+ H. Holst, "Internet Printing Protocol/1.1:
+ Implementor's Guide", RFC 3196, November 2001.
+
+12. Acknowledgments
+
+ This document is a product of the Internet Printing Protocol Working
+ Group of the Internet Engineering Task Force (IETF).
+
+ Thanks to Pat Fleming (IBM), Tom Hastings (Xerox), Harry Lewis (IBM),
+ Hugo Parra (Novell), Don Wright (Lexmark), and all the members of the
+ IETF IPP WG.
+
+ Section 5, "IPP URL Scheme", in IPP Protocol [RFC2910] was the
+ primary input to this IPP URL Scheme specification.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot & McDonald Standards Track [Page 12]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+Appendix A - Registration of "ipp" URL Scheme
+
+ Note: The following registration obsoletes section 5, "IPP URL
+ Scheme", of IPP Protocol [RFC2911].
+
+ URL Scheme Name: ipp
+
+ URL Scheme Syntax:
+
+ ipp-URL = "ipp:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
+
+ Character Encoding Considerations:
+
+ IPP URLs MUST use [RFC2396] encoding, as do their equivalent HTTP
+ URLs. Characters other than those in the "reserved" and "unsafe"
+ sets [RFC2396] are equivalent to their ""%" HEX HEX" encoding.
+
+ Intended Usage:
+
+ The intended usage of the "ipp" URL scheme is COMMON.
+
+ An "ipp" URL is used to specify the network location of a print
+ service that supports the IPP Protocol [RFC2910], or of a network
+ resource (for example, a print job) managed by such a print
+ service. An IPP client can choose to establish an HTTP connection
+ to the specified print service for transmission of IPP protocol
+ requests (for example, IPP print job submission requests).
+
+ Applications or Protocols which use this URL scheme:
+
+ See: Section 5, "IPP URL Scheme", in IPP Protocol [RFC2910].
+
+ Interoperability Considerations:
+
+ See: Section 9, "Interoperability with IPP/1.0 Implementations",
+ in IPP Protocol [RFC2910].
+
+ Security Considerations:
+
+ See: Section 8, "Security Considerations", in IPP Protocol
+ [RFC2910].
+
+ Relevant Publications:
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P., Turner, R. and J. Wenn,
+ "IPP/1.1 Encoding and Transport [IPP Protocol]", RFC 2910,
+ September 2000.
+
+
+
+
+Herriot & McDonald Standards Track [Page 13]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter,
+ L., Leach, P. and T. Berners-Lee, "Hypertext Transfer
+ Protocol -- HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC3510] Herriot, R. and I. McDonald, "IPP/1.1: IPP URL Scheme", RFC
+ 3510, April 2003.
+
+ Person & email address to contact for further information:
+
+ Robert Herriot
+ Consultant
+ 706 Colorado Ave
+ Palo Alto, CA 94303
+
+ Phone: +1 650-327-4466
+ EMail: bob@herriot.com
+
+ Ira McDonald
+ High North Inc
+ 221 Ridge Ave
+ Grand Marais, MI 49839
+
+ Phone: +1 906-494-2434
+ EMail: imcdonald@sharplabs.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot & McDonald Standards Track [Page 14]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+Authors' Addresses
+
+ Robert Herriot
+ Consultant
+ 706 Colorado Ave
+ Palo Alto, CA 94303
+
+ Phone: +1 650-327-4466
+ EMail: bob@herriot.com
+
+
+ Ira McDonald
+ High North Inc
+ 221 Ridge Ave
+ Grand Marais, MI 49839
+
+ Phone: +1 906-494-2434
+ EMail: imcdonald@sharplabs.com
+
+ Usage questions and comments on this IPP URL Scheme should be sent
+ directly to the editors at their above addresses (and to the IPP
+ mailing list, if you are a subscriber - see below).
+
+ IPP Web Page: http://www.pwg.org/ipp/
+ IPP Mailing List: ipp@pwg.org
+
+ To subscribe to the IPP mailing list, send the following email:
+
+ 1) send it to majordomo@pwg.org
+
+ 2) leave the subject line blank
+
+ 3) put the following two lines in the message body: subscribe ipp
+
+ Implementers of this specification are encouraged to join the IPP
+ Mailing List in order to participate in any discussions of
+ clarification issues and comments. In order to reduce spam the
+ mailing list rejects mail from non-subscribers, so you must subscribe
+ to the mailing list in order to send a question or comment to the IPP
+ mailing list.
+
+
+
+
+
+
+
+
+
+
+
+Herriot & McDonald Standards Track [Page 15]
+
+RFC 3510 IPP URL Scheme April 2003
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot & McDonald Standards Track [Page 16]
+
diff --git a/standards/rfc3712.txt b/standards/rfc3712.txt
new file mode 100644
index 000000000..f5bb966ea
--- /dev/null
+++ b/standards/rfc3712.txt
@@ -0,0 +1,1851 @@
+
+
+
+
+
+
+Network Working Group P. Fleming
+Request for Comments: 3712 IBM
+Category: Informational I. McDonald
+ High North
+ February 2004
+
+
+ Lightweight Directory Access Protocol (LDAP):
+ Schema for Printer Services
+
+Status of this Memo
+
+ This memo provides information for the Internet community. It does
+ not specify an Internet standard of any kind. Distribution of this
+ memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2004). All Rights Reserved.
+
+Abstract
+
+ This document defines a schema, object classes and attributes, for
+ printers and printer services, for use with directories that support
+ Lightweight Directory Access Protocol v3 (LDAP-TS). This document is
+ based on the printer attributes listed in Appendix E of Internet
+ Printing Protocol/1.1 (IPP) (RFC 2911). A few additional printer
+ attributes are based on definitions in the Printer MIB (RFC 1759).
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 1.1. Rationale for using DirectoryString Syntax . . . . . . . 3
+ 1.2. Rationale for using caseIgnoreMatch. . . . . . . . . . . 4
+ 1.3. Rationale for using caseIgnoreSubstringsMatch. . . . . . 5
+ 2. Terminology and Conventions. . . . . . . . . . . . . . . . . . 5
+ 3. Definition of Object Classes . . . . . . . . . . . . . . . . . 6
+ 3.1. slpServicePrinter. . . . . . . . . . . . . . . . . . . . 6
+ 3.2. printerAbstract. . . . . . . . . . . . . . . . . . . . . 7
+ 3.3. printerService . . . . . . . . . . . . . . . . . . . . . 8
+ 3.4. printerServiceAuxClass . . . . . . . . . . . . . . . . . 8
+ 3.5. printerIPP . . . . . . . . . . . . . . . . . . . . . . . 8
+ 3.6. printerLPR . . . . . . . . . . . . . . . . . . . . . . . 9
+ 4. Definition of Attribute Types. . . . . . . . . . . . . . . . . 9
+ 4.1. printer-uri. . . . . . . . . . . . . . . . . . . . . . . 11
+ 4.2. printer-xri-supported. . . . . . . . . . . . . . . . . . 11
+ 4.3. printer-name . . . . . . . . . . . . . . . . . . . . . . 13
+ 4.4. printer-natural-language-configured. . . . . . . . . . . 13
+
+
+
+Fleming & McDonald Informational [Page 1]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ 4.5. printer-location . . . . . . . . . . . . . . . . . . . . 14
+ 4.6. printer-info . . . . . . . . . . . . . . . . . . . . . . 14
+ 4.7. printer-more-info. . . . . . . . . . . . . . . . . . . . 14
+ 4.8. printer-make-and-model . . . . . . . . . . . . . . . . . 15
+ 4.9. printer-ipp-versions-supported . . . . . . . . . . . . . 15
+ 4.10. printer-multiple-document-jobs-supported . . . . . . . . 16
+ 4.11. printer-charset-configured . . . . . . . . . . . . . . . 16
+ 4.12. printer-charset-supported. . . . . . . . . . . . . . . . 16
+ 4.13. printer-generated-natural-language-supported . . . . . . 17
+ 4.14. printer-document-format-supported. . . . . . . . . . . . 17
+ 4.15. printer-color-supported. . . . . . . . . . . . . . . . . 18
+ 4.16. printer-compression-supported. . . . . . . . . . . . . . 18
+ 4.17. printer-pages-per-minute . . . . . . . . . . . . . . . . 18
+ 4.18. printer-pages-per-minute-color . . . . . . . . . . . . . 19
+ 4.19. printer-finishings-supported . . . . . . . . . . . . . . 19
+ 4.20. printer-number-up-supported. . . . . . . . . . . . . . . 19
+ 4.21. printer-sides-supported. . . . . . . . . . . . . . . . . 20
+ 4.22. printer-media-supported. . . . . . . . . . . . . . . . . 20
+ 4.23. printer-media-local-supported. . . . . . . . . . . . . . 20
+ 4.24. printer-resolution-supported . . . . . . . . . . . . . . 21
+ 4.25. printer-print-quality-supported. . . . . . . . . . . . . 22
+ 4.26. printer-job-priority-supported . . . . . . . . . . . . . 22
+ 4.27. printer-copies-supported . . . . . . . . . . . . . . . . 22
+ 4.28. printer-job-k-octets-supported . . . . . . . . . . . . . 23
+ 4.29. printer-current-operator . . . . . . . . . . . . . . . . 23
+ 4.30. printer-service-person . . . . . . . . . . . . . . . . . 24
+ 4.31. printer-delivery-orientation-supported . . . . . . . . . 24
+ 4.32. printer-stacking-order-supported . . . . . . . . . . . . 24
+ 4.33. printer-output-features-supported. . . . . . . . . . . . 25
+ 4.34. printer-aliases. . . . . . . . . . . . . . . . . . . . . 25
+ 5. Definition of Syntaxes . . . . . . . . . . . . . . . . . . . . 26
+ 6. Definition of Matching Rules . . . . . . . . . . . . . . . . . 26
+ 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 26
+ 7.1. Registration of Object Classes . . . . . . . . . . . . . 26
+ 7.2. Registration of Attribute Types. . . . . . . . . . . . . 27
+ 8. Internationalization Considerations. . . . . . . . . . . . . . 28
+ 9. Security Considerations. . . . . . . . . . . . . . . . . . . . 29
+ 10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 29
+ 10.1. Normative References . . . . . . . . . . . . . . . . . . 29
+ 10.2. Informative References . . . . . . . . . . . . . . . . . 30
+ 11. Acknowledgments. . . . . . . . . . . . . . . . . . . . . . . . 32
+ 12. Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 32
+ 13. Full Copyright Statement . . . . . . . . . . . . . . . . . . . 33
+
+
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 2]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+1. Introduction
+
+ This document defines several object classes to provide Lightweight
+ Directory Access Protocol v3 [LDAP-TS] applications with flexible
+ options in defining printer information using LDAP schema. Classes
+ are provided for defining directory entries with common printer
+ information as well as for extending existing directory entries with
+ SLPv2 [RFC2608], IPP/1.1 [RFC2911], and LPR [RFC1179] specific
+ information.
+
+ The schema defined in this document is based on the printer
+ attributes listed in Appendix E 'Generic Directory Schema' of
+ Internet Printing Protocol/1.1 (IPP) [RFC2911]. A few additional
+ printer attributes are based on definitions in the Printer MIB
+ [RFC1759].
+
+ The schema defined in this document is technically aligned with the
+ stable IANA-registered 'service:printer:' v2.0 template [SLP-PRT],
+ for compatibility with already deployed Service Location Protocol
+ (SLPv2) [RFC2608] service advertising and discovery infrastructure.
+ The attribute syntaxes are technically aligned with the
+ 'service:printer:' v2.0 template - therefore simpler types are
+ sometimes used (for example, 'DirectoryString' [RFC2252] rather than
+ 'labeledURI' [RFC2079] for the 'printer-uri' attribute).
+
+ Please send comments directly to the authors at the addresses listed
+ in Section 13 "Authors' Addresses".
+
+1.1. Rationale for using DirectoryString Syntax
+
+ The attribute syntax 'DirectoryString' (UTF-8 [RFC2279]) defined in
+ [RFC2252] is specified for several groups of string attributes that
+ are defined in this document:
+
+ 1) URI
+ - printer-uri, printer-xri-supported, printer-more-info
+
+ The UTF-8 encoding is forward compatible with any future
+ deployment of (UTF-8 based) IRI (Internationalized Resource
+ Identifiers) [W3C-IRI] currently being developed by the W3C
+ Internationalization Working Group.
+
+ 2) Description
+ - printer-name, printer-location, printer-info,
+ printer-make-and-model
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 3]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ The UTF-8 encoding supports descriptions in any language,
+ conformant with the "IETF Policy on Character Sets and Languages"
+ [RFC2277].
+
+ Note: The printer-natural-language-configured attribute contains
+ a language tag [RFC3066] for these description attributes (for
+ example, to support text-to-speech conversions).
+
+ 3) Keyword
+ - printer-compression-supported, printer-finishings-supported,
+ printer-media-supported, printer-media-local-supported,
+ printer-print-quality-supported
+
+ The UTF-8 encoding is compatible with the current IPP/1.1
+ [RFC2911] definition of the equivalent attributes, most of which
+ have the IPP/1.1 union syntax 'keyword or name'. The keyword
+ attributes defined in this document are extensible by
+ site-specific or vendor-specific 'names' which behave like new
+ 'keywords'
+
+ Note: In IPP/1.1, each value is strongly typed over-the-wire as
+ either 'keyword' or 'name'. This union selector is not preserved
+ in the definitions of these equivalent LDAP attributes.
+
+1.2. Rationale for using caseIgnoreMatch
+
+ The EQUALITY matching rule 'caseIgnoreMatch' defined in [RFC2252] is
+ specified for several groups of string attributes that are defined in
+ this document:
+
+ 1) URI
+
+ These URI attributes specify EQUALITY matching with
+ 'caseIgnoreMatch' (rather than with 'caseExactMatch') in order to
+ conform to the spirit of [RFC2396], which requires case
+ insensitive matching on the host part of a URI versus case
+ sensitive matching on the remainder of a URI.
+
+ These URI attributes follow existing practice of supporting case
+ insensitive equality matching for host names in the
+ associatedDomain attribute defined in [RFC1274].
+
+ Either equality matching rule choice would be a compromise:
+ a) case sensitive whole URI matching may lead to false negative
+ matches and has been shown to be fragile (given deployed client
+ applications that 'pretty up' host names displayed and
+ transferred in URI);
+
+
+
+
+Fleming & McDonald Informational [Page 4]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ b) case insensitive whole URI matching may lead to false positive
+ matches, although it is a dangerous practice to publish URI that
+ differ only by case (for example, in the path elements).
+
+ 2) Description
+
+ Case insensitive equality matching is more user-friendly for
+ description attributes.
+
+ 3) Keyword
+
+ Case insensitive equality matching is more user-friendly for
+ keyword attributes.
+
+1.3. Rationale for using caseIgnoreSubstringsMatch
+
+ The SUBSTR matching rule 'caseIgnoreSubstringsMatch' defined in
+ [RFC2252] is specified for several groups of string attributes that
+ are defined in this document:
+
+ 1) URI
+
+ These URI attributes follow existing practice of supporting case
+ insensitive equality matching for host names in the
+ associatedDomain attribute defined in [RFC1274].
+
+ 2) Description
+
+ Support for case insensitive substring matching is more
+ user-friendly for description attributes.
+
+ 3) Keyword
+
+ Support for case insensitive substring matching is more
+ user-friendly for keyword attributes.
+
+2. Terminology and Conventions
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in BCP 14 [RFC2119].
+
+ Schema definitions are provided using LDAPv3 [LDAP-TS] description
+ formats. Definitions provided here are formatted (line wrapped) for
+ readability.
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 5]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+3. Definition of Object Classes
+
+ We define the following LDAP object classes for use with both generic
+ printer related information and services specific to SLPv2 [RFC2608],
+ IPP/1.1 [RFC2911], and LPR [RFC1179].
+
+ slpServicePrinter - auxiliary class for SLP registered printers
+ printerAbstract - abstract class for all printer classes
+ printerService - structural class for printers
+ printerServiceAuxClass - auxiliary class for printers
+ printerIPP - auxiliary class for IPP printers
+ printerLPR - auxiliary class for LPR printers
+
+ The following are some examples of how applications may choose to use
+ these classes when creating directory entries:
+
+ 1) Use printerService for directory entries containing common
+ printer information.
+
+ 2) Use both printerService and slpServicePrinter for directory
+ entries containing common printer information for SLP registered
+ printers.
+
+ 3) Use printerService, printerLPR and printerIPP for directory
+ entries containing common printer information for printers that
+ support both LPR and IPP.
+
+ 4) Use printerServiceAuxClass and object classes not defined by this
+ document for directory entries containing common printer
+ information. In this example, printerServiceAuxClass is used for
+ extending other structural classes defining printer information
+ with common printer information defined in this document.
+
+ Refer to Section 4 for definition of attribute types referenced by
+ these object classes. We use attribute names instead of OIDs in
+ object class definitions for clarity. Some attribute names described
+ in [RFC2911] have been prefixed with 'printer-' as recommended in
+ [RFC2926] and [SLP-PRT].
+
+3.1. slpServicePrinter
+
+ ( 1.3.18.0.2.6.254
+ NAME 'slpServicePrinter'
+ DESC 'Service Location Protocol (SLP) information.'
+ AUXILIARY
+ SUP slpService
+ )
+
+
+
+
+Fleming & McDonald Informational [Page 6]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ This auxiliary class defines Service Location Protocol (SLPv2)
+ [RFC2608] specific information. It should be used with a structural
+ class such as printerService. It may be used to create new or extend
+ existing directory entries with SLP 'service:printer' abstract
+ service type information as defined in [SLP-PRT]. This object class
+ is derived from 'slpService', the parent class for all SLP services,
+ defined in [RFC2926].
+
+3.2. printerAbstract
+
+ ( 1.3.18.0.2.6.258
+ NAME 'printerAbstract'
+ DESC 'Printer related information.'
+ ABSTRACT
+ SUP top
+ MAY ( printer-name $
+ printer-natural-language-configured $
+ printer-location $ printer-info $ printer-more-info $
+ printer-make-and-model $
+ printer-multiple-document-jobs-supported $
+ printer-charset-configured $ printer-charset-supported $
+ printer-generated-natural-language-supported $
+ printer-document-format-supported $ printer-color-supported $
+ printer-compression-supported $ printer-pages-per-minute $
+ printer-pages-per-minute-color $
+ printer-finishings-supported $ printer-number-up-supported $
+ printer-sides-supported $ printer-media-supported $
+ printer-media-local-supported $
+ printer-resolution-supported $
+ printer-print-quality-supported $
+ printer-job-priority-supported $ printer-copies-supported $
+ printer-job-k-octets-supported $ printer-current-operator $
+ printer-service-person $
+ printer-delivery-orientation-supported $
+ printer-stacking-order-supported $
+ printer-output-features-supported )
+ )
+
+ This abstract class defines printer information. It is a base class
+ for deriving other printer related classes, such as, but not limited
+ to, classes defined in this document. It defines a common set of
+ printer attributes that are not specific to any one type of service,
+ protocol or operating system.
+
+
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 7]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+3.3. printerService
+
+ ( 1.3.18.0.2.6.255
+ NAME 'printerService'
+ DESC 'Printer information.'
+ STRUCTURAL
+ SUP printerAbstract
+ MAY ( printer-uri $ printer-xri-supported )
+ )
+
+ This structural class defines printer information. It is derived
+ from class printerAbstract and thus inherits common printer
+ attributes. This class can be used with or without auxiliary classes
+ to define printer information. Auxiliary classes can be used to
+ extend the common printer information with protocol, service or
+ operating system specific information.
+
+ Note: When extending other structural classes with auxiliary
+ classes, printerService should not be used.
+
+3.4. printerServiceAuxClass
+
+ ( 1.3.18.0.2.6.257
+ NAME 'printerServiceAuxClass'
+ DESC 'Printer information.'
+ AUXILIARY
+ SUP printerAbstract
+ MAY ( printer-uri $ printer-xri-supported )
+ )
+
+ This auxiliary class defines printer information. It is derived from
+ class printerAbstract and thus inherits common printer attributes.
+ This class should be used with a structural class.
+
+3.5. printerIPP
+
+ ( 1.3.18.0.2.6.256
+ NAME 'printerIPP'
+ DESC 'Internet Printing Protocol (IPP) information.'
+ AUXILIARY
+ SUP top
+ MAY ( printer-ipp-versions-supported $
+ printer-multiple-document-jobs-supported )
+ )
+
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 8]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ This auxiliary class defines Internet Printing Protocol (IPP/1.1)
+ [RFC2911] information. It should be used with a structural class
+ such as printerService. It is used to extend structural classes with
+ IPP specific printer information.
+
+3.6. printerLPR
+
+ ( 1.3.18.0.2.6.253
+ NAME 'printerLPR'
+ DESC 'LPR information.'
+ AUXILIARY
+ SUP top
+ MUST ( printer-name )
+ MAY ( printer-aliases)
+ )
+
+ This auxiliary class defines LPR [RFC1179] information. It should be
+ used with a structural class such as printerService. It is used to
+ identify directory entries that support LPR.
+
+4. Definition of Attribute Types
+
+ The following attribute types are referenced by the object classes
+ defined in Section 3.
+
+ The following attribute types reference syntax OIDs defined in
+ Section 6 of [RFC2252] (see Section 5 'Definition of Syntaxes'
+ below).
+
+ The following attribute types reference matching rule names (instead
+ of OIDs) for clarity (see Section 6 below). For optional attributes,
+ if the printer information is not known, the attribute value should
+ not be set. In the following definitions, referenced matching rules
+ are defined in Section 8 of [RFC2252] and/or Section 2 of [RFC3698]
+ (see Section 6 'Definition of Matching Rules' below).
+
+ The following table is a summary of the attribute names defined by
+ this document and their corresponding names from [RFC2911]. Some
+ attribute names described in [RFC2911] have been prefixed with
+ 'printer-' as recommended in [RFC2926], to address the flat namespace
+ for LDAP identifiers.
+
+
+
+
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 9]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ LDAP & SLP Printer Schema IPP Model [RFC2911]
+ ------------------------------ -------------------------------------
+ printer-uri
+ printer-xri-supported
+ [IPP printer-uri-supported]
+ [IPP uri-authentication-supported]
+ [IPP uri-security-supported]
+ printer-name printer-name
+ printer-natural-language-configured
+ natural-language-configured
+ printer-location printer-location
+ printer-info printer-info
+ printer-more-info printer-more-info
+ printer-make-and-model printer-make-and-model
+ printer-ipp-versions-supported ipp-versions-supported
+ printer-multiple-document-jobs-supported
+ multiple-document-jobs-supported
+ printer-charset-configured charset-configured
+ printer-charset-supported charset-supported
+ printer-generated-natural-language-supported
+ generated-natural-language-supported
+ printer-document-format-supported
+ document-format-supported
+ printer-color-supported color-supported
+ printer-compression-supported compression-supported
+ printer-pages-per-minute pages-per-minute
+ printer-pages-per-minute-color pages-per-minute-color
+ printer-finishings-supported finishings-supported
+ printer-number-up-supported number-up-supported
+ printer-sides-supported sides-supported
+ printer-media-supported media-supported
+ printer-media-local-supported [site names from IPP media-supported]
+ printer-resolution-supported printer-resolution-supported
+ printer-print-quality-supported print-quality-supported
+ printer-job-priority-supported job-priority-supported
+ printer-copies-supported copies-supported
+ printer-job-k-octets-supported job-k-octets-supported
+ printer-current-operator
+ printer-service-person
+ printer-delivery-orientation-supported
+ printer-stacking-order-supported
+ printer-output-features-supported
+ printer-aliases
+
+
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 10]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+4.1. printer-uri
+
+ ( 1.3.18.0.2.4.1140
+ NAME 'printer-uri'
+ DESC 'A URI supported by this printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE
+ )
+
+ If the printer-xri-supported LDAP attribute is implemented, then this
+ printer-uri value should be listed in printer-xri-supported.
+
+ Values of URI should conform to [RFC2396], although URI schemes may
+ be defined which do not conform to [RFC2396] (see [RFC2717] and
+ [RFC2718]).
+
+ Note: LDAP application clients should not attempt to use malformed
+ URI values read from this attribute. LDAP administrative clients
+ should not write malformed URI values into this attribute.
+
+ Note: For SLP registered printers, the LDAP printer-uri attribute
+ should be set to the value of the SLP-registered URL of the printer,
+ for interworking with SLPv2 [RFC2608] service discovery.
+
+ Note: See Sections 1.1, 1.2, and 1.3 for rationale for design
+ choices.
+
+4.2. printer-xri-supported
+
+ ( 1.3.18.0.2.4.1107
+ NAME 'printer-xri-supported'
+ DESC 'The unordered list of XRI (extended resource identifiers)
+ supported by this printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ )
+
+ A list of XRI (extended resource identifiers) supported by this
+ printer. Each value of this list should consist of a URI (uniform
+ resource identifier) followed by (optional) authentication and
+ security fields.
+
+ Values of URI should conform to [RFC2396], although URI schemes may
+ be defined which do not conform to [RFC2396] (see [RFC2717] and
+ [RFC2718]).
+
+
+
+Fleming & McDonald Informational [Page 11]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ Note: LDAP application clients should not attempt to use malformed
+ URI values read from this attribute. LDAP administrative clients
+ should not write malformed URI values into this attribute.
+
+ Note: This attribute is based on 'printer-uri-supported', 'uri-
+ authentication-supported', and `'uri-security-supported' (called the
+ 'Three Musketeers' because they are parallel ordered attributes)
+ defined in IPP/1.1 [RFC2911]. This attribute unfolds those IPP/1.1
+ attributes and thus avoids the ordering (and same number of values)
+ constraints of the IPP/1.1 separate attributes.
+
+ Defined keywords for fields include:
+
+ 'uri' (IPP 'printer-uri-supported')
+ 'auth' (IPP 'uri-authentication-supported')
+ 'sec' (IPP 'uri-security-supported')
+
+ A missing 'auth' field should be interpreted to mean 'none'. Per
+ IPP/1.1 [RFC2911], defined values of the 'auth' field include:
+
+ 'none' (no authentication for this URI)
+ 'requesting-user-name' (from operation request)
+ 'basic' (HTTP/1.1 Basic [RFC2617])
+ 'digest' (HTTP/1.1 Basic, [RFC2617])
+ 'certificate' (from certificate)
+
+ A missing 'sec' field should be interpreted to mean 'none'. Per
+ IPP/1.1 [RFC2911], defined values of the 'sec' field include:
+
+ 'none' (no security for this URI)
+ 'ssl3' (Netscape SSL3)
+ 'tls' (IETF TLS/1.0, [RFC2246])
+
+ Each XRI field should be delimited by '<'. For example:
+
+ 'uri=ipp://foo.com< auth=digest< sec=tls<'
+ 'uri=lpr://bar.com< auth=none< sec=none<'
+ 'uri=mailto:printer@foobar.com< auth=none< sec=none<'
+
+ Note: The syntax and delimiter for this attribute are aligned with
+ the equivalent attribute in the 'service:printer:' v2.0 template
+ [SLP-PRT]. Whitespace is permitted after (but not before) the
+ delimiter '<'. Note that this delimiter differs from printer-
+ resolution-supported.
+
+ Note: See Sections 1.1, 1.2, and 1.3 for rationale for design
+ choices.
+
+
+
+
+Fleming & McDonald Informational [Page 12]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+4.3. printer-name
+
+ ( 1.3.18.0.2.4.1135
+ NAME 'printer-name'
+ DESC 'The site-specific administrative name of this printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ SINGLE-VALUE
+ )
+
+ Values of this attribute should be specified in the language
+ specified in printer-natural-language-configured (for example, to
+ support text-to-speech conversions), although the printer's name may
+ be specified in any language. This name may be the last part of the
+ printer's URI or it may be completely unrelated. This name may
+ contain characters that are not allowed in a conventional URI (see
+ [RFC2396]).
+
+4.4. printer-natural-language-configured
+
+ ( 1.3.18.0.2.4.1119
+ NAME 'printer-natural-language-configured'
+ DESC 'The configured natural language in which error and status
+ messages will be generated (by default) by this printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ SINGLE-VALUE
+ )
+
+ Also, a possible natural language for printer string attributes set
+ by operator, system administrator, or manufacturer. Also, the
+ (declared) natural language of the printer-name, printer-location,
+ printer-info, and printer-make-and-model attributes of this printer.
+
+ Values of language tags should conform to "Tags for the
+ Identification of Languages" [RFC3066]. For example:
+
+ 'en-us' (English as spoken in the US)
+ 'fr-fr' (French as spoken in France)
+
+ For consistency with IPP/1.1 [RFC2911], language tags in this
+ attribute should be lowercase normalized.
+
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 13]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+4.5. printer-location
+
+ ( 1.3.18.0.2.4.1136
+ NAME 'printer-location'
+ DESC 'The physical location of this printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ SINGLE-VALUE
+ )
+
+ For example:
+
+ 'Room 123A'
+ 'Second floor of building XYZ'
+
+4.6. printer-info
+
+ ( 1.3.18.0.2.4.1139
+ NAME 'printer-info'
+ DESC 'Descriptive information about this printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ SINGLE-VALUE
+ )
+
+ For example:
+
+ 'This printer can be used for printing color transparencies for
+ HR presentations'
+ 'Out of courtesy for others, please print only small (1-5 page)
+ jobs at this printer'
+ 'This printer is going away on July 1, 1997, please find a new
+ printer'
+
+4.7. printer-more-info
+
+ ( 1.3.18.0.2.4.1134
+ NAME 'printer-more-info'
+ DESC 'A URI for more information about this specific printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE
+ )
+
+
+
+
+
+Fleming & McDonald Informational [Page 14]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ For example, this could be an HTTP type URI referencing an HTML page
+ accessible to a Web Browser. The information obtained from this URI
+ is intended for end user consumption.
+
+ Values of URI should conform to [RFC2396], although URI schemes may
+ be defined which do not conform to [RFC2396] (see [RFC2717] and
+ [RFC2718]).
+
+ Note: LDAP application clients should not attempt to use malformed
+ URI values read from this attribute. LDAP administrative clients
+ should not write malformed URI values into this attribute.
+
+ Note: See Sections 1.1, 1.2, and 1.3 for rationale for design
+ choices.
+
+4.8. printer-make-and-model
+
+ ( 1.3.18.0.2.4.1138
+ NAME 'printer-make-and-model'
+ DESC 'Make and model of this printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ SINGLE-VALUE
+ )
+
+ Note: The printer manufacturer may initially populate this
+ attribute.
+
+4.9. printer-ipp-versions-supported
+
+ ( 1.3.18.0.2.4.1133
+ NAME 'printer-ipp-versions-supported'
+ DESC 'IPP protocol version(s) that this printer supports.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+ The IPP protocol version(s) should include major and minor versions,
+ i.e., the exact version numbers for which this Printer implementation
+ meets the IPP version-specific conformance requirements.
+
+
+
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 15]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+4.10. printer-multiple-document-jobs-supported
+
+ ( 1.3.18.0.2.4.1132
+ NAME 'printer-multiple-document-jobs-supported'
+ DESC 'Indicates whether or not this printer supports more than one
+ document per job.'
+ EQUALITY booleanMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
+ SINGLE-VALUE
+ )
+
+4.11. printer-charset-configured
+
+ ( 1.3.18.0.2.4.1109
+ NAME 'printer-charset-configured'
+ DESC 'The configured charset in which error and status messages will
+ be generated (by default) by this printer.'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63}
+ SINGLE-VALUE
+ )
+
+ Also, a possible charset for printer string attributes set by
+ operator, system administrator, or manufacturer. For example:
+
+ 'utf-8' (ISO 10646/Unicode in UTF-8 transform [RFC2279])
+ 'iso-8859-1' (Latin1)
+
+ Values of charset tags should be defined in the IANA Registry of
+ Coded Character Sets [IANA-CHAR] (see also [RFC2978]) and the
+ '(preferred MIME name)' should be used as the charset tag in this
+ attribute.
+
+ For consistency with IPP/1.1 [RFC2911], charset tags in this
+ attribute should be lowercase normalized.
+
+4.12. printer-charset-supported
+
+ ( 1.3.18.0.2.4.1131
+ NAME 'printer-charset-supported'
+ DESC 'Set of charsets supported for the attribute values of syntax
+ DirectoryString for this directory entry.'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63}
+ )
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 16]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ For example:
+
+ 'utf-8' (ISO 10646/Unicode in UTF-8 transform [RFC2279])
+ 'iso-8859-1' (Latin1)
+
+ Values of charset tags should be defined in the IANA Registry of
+ Coded Character Sets [IANA-CHAR] (see also [RFC2978]) and the
+ '(preferred MIME name)' should be used as the charset tag in this
+ attribute.
+
+ For consistency with IPP/1.1 [RFC2911], charset tags in this
+ attribute should be lowercase normalized.
+
+4.13. printer-generated-natural-language-supported
+
+ ( 1.3.18.0.2.4.1137
+ NAME 'printer-generated-natural-language-supported'
+ DESC 'Natural language(s) supported for this directory entry.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63}
+ )
+
+ Values of language tags should conform to "Tags for the
+ Identification of Languages" [RFC3066]. For example:
+
+ 'en-us' (English as spoken in the US)
+ 'fr-fr' (French as spoken in France)
+
+ For consistency with IPP/1.1 [RFC2911], language tags in this
+ attribute should be lowercase normalized.
+
+4.14. printer-document-format-supported
+
+ ( 1.3.18.0.2.4.1130
+ NAME 'printer-document-format-supported'
+ DESC 'The possible source document formats which may be interpreted
+ and printed by this printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+ Values of document formats should be MIME media types defined in the
+ IANA Registry of MIME Media Types [IANA-MIME] (see also [RFC2048]).
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 17]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+4.15. printer-color-supported
+
+ ( 1.3.18.0.2.4.1129
+ NAME 'printer-color-supported'
+ DESC 'Indicates whether this printer is capable of any type of color
+ printing at all, including highlight color.'
+ EQUALITY booleanMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
+ SINGLE-VALUE
+ )
+
+4.16. printer-compression-supported
+
+ ( 1.3.18.0.2.4.1128
+ NAME 'printer-compression-supported'
+ DESC 'Compression algorithms supported by this printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}
+ )
+
+ Values defined in IPP/1.1 [RFC2911] include:
+
+ 'none' (no compression is used)
+ 'deflate' (public domain ZIP described in [RFC1951])
+ 'gzip' (GNU ZIP described in [RFC1952])
+ 'compress' (UNIX compression described in [RFC1977])
+
+4.17. printer-pages-per-minute
+
+ ( 1.3.18.0.2.4.1127
+ NAME 'printer-pages-per-minute'
+ DESC 'The nominal number of pages per minute which may be output by
+ this printer.'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE
+ )
+
+ This attribute is informative, not a service guarantee. Typically,
+ it is the value used in marketing literature to describe this
+ printer. For example, the value for a simplex or black-and-white
+ print mode.
+
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 18]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+4.18. printer-pages-per-minute-color
+
+ ( 1.3.18.0.2.4.1126
+ NAME 'printer-pages-per-minute-color'
+ DESC 'The nominal number of color pages per minute which may be
+ output by this printer.'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE
+ )
+
+ This attribute is informative, not a service guarantee. Typically,
+ it is the value used in marketing literature to describe this
+ printer.
+
+
+4.19. printer-finishings-supported
+
+ ( 1.3.18.0.2.4.1125
+ NAME 'printer-finishings-supported'
+ DESC 'The possible finishing operations supported by this printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}
+ )
+
+ Values defined in IPP/1.1 [RFC2911] include: 'none', 'staple',
+ 'punch', 'cover', 'bind', 'saddle-stitch', 'edge-stitch',
+ 'staple-top-left', 'staple-bottom-left', 'staple-top-right',
+ 'staple-bottom-right', 'edge-stitch-left', 'edge-stitch-top',
+ 'edge-stitch-right', 'edge-stitch-bottom', 'staple-dual-left',
+ 'staple-dual-top', 'staple-dual-right', 'staple-dual-bottom'.
+
+ Note: Implementations may support other values.
+
+4.20. printer-number-up-supported
+
+ ( 1.3.18.0.2.4.1124
+ NAME 'printer-number-up-supported'
+ DESC 'The possible numbers of print-stream pages to impose upon a
+ single side of an instance of a selected medium.'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ )
+
+
+
+
+
+Fleming & McDonald Informational [Page 19]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ Values defined in IPP/1.1 [RFC2911] include: '1', '2', and '4'.
+
+ Note: Implementations may support other values.
+
+4.21. printer-sides-supported
+
+ ( 1.3.18.0.2.4.1123
+ NAME 'printer-sides-supported'
+ DESC 'The number of impression sides (one or two) and the two-sided
+ impression rotations supported by this printer.'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+ Values defined in IPP/1.1 [RFC2911] include: 'one-sided', 'two-
+ sided-long-edge', 'two-sided-short-edge'.'
+
+4.22. printer-media-supported
+
+ ( 1.3.18.0.2.4.1122
+ NAME 'printer-media-supported'
+ DESC 'The standard names/types/sizes (and optional color suffixes) of
+ the media supported by this printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}
+ )
+
+ Values are defined in IPP/1.1 [RFC2911] or any IANA registered
+ extensions. For example:
+
+ 'iso-a4'
+ 'envelope'
+ 'na-letter-white'
+
+4.23. printer-media-local-supported
+
+ ( 1.3.18.0.2.4.1117
+ NAME 'printer-media-local-supported'
+ DESC 'Site-specific names of media supported by this printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}
+ )
+
+ Values should be in the natural language specified by printer-
+ natural-language-configured.
+
+
+
+
+Fleming & McDonald Informational [Page 20]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ For example:
+
+ 'purchasing-form' (site-specific name)
+
+ as opposed to 'na-letter' (standard keyword from IPP/1.1 [RFC2911])
+ in the printer-media-supported attribute.
+
+4.24. printer-resolution-supported
+
+ ( 1.3.18.0.2.4.1121
+ NAME 'printer-resolution-supported'
+ DESC 'List of resolutions supported for printing documents by this
+ printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}
+ )
+
+ Each resolution value should be a string containing 3 fields:
+ 1) Cross feed direction resolution (positive integer);
+ 2) Feed direction resolution (positive integer);
+ 3) Unit - 'dpi' (dots per inch) or 'dpcm' (dots per centimeter).
+
+ Each resolution field should be delimited by '>'. For example:
+
+ '300> 300> dpi>'
+ '600> 600> dpi>'
+
+ Note: This attribute is based on 'printer-resolution-supported'
+ defined in IPP/1.1 [RFC2911] (which has a binary complex encoding)
+ derived from 'prtMarkerAddressabilityFeedDir',
+ 'prtMarkerAddressabilityXFeedDir', and 'prtMarkerAddressabilityUnit'
+ defined in the Printer MIB [RFC1759] (which have integer encodings).
+
+ Note: The syntax and delimiter for this attribute are aligned with
+ the equivalent attribute in the 'service:printer:' v2.0 template
+ [SLP-PRT]. Whitespace is permitted after (but not before) the
+ delimiter '>'. Note that this delimiter differs from printer-xri-
+ supported.
+
+
+
+
+
+
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 21]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+4.25. printer-print-quality-supported
+
+ ( 1.3.18.0.2.4.1120
+ NAME 'printer-print-quality-supported'
+ DESC 'List of print qualities supported for printing documents on
+ this printer.'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+ Values defined in IPP/1.1 [RFC2911] include:
+
+ 'unknown'
+ 'draft'
+ 'normal'
+ 'high'
+
+4.26. printer-job-priority-supported
+
+ ( 1.3.18.0.2.4.1110
+ NAME 'printer-job-priority-supported'
+ DESC 'Indicates the number of job priority levels supported by this
+ printer.'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE
+ )
+
+ An IPP/1.1 [RFC2911] conformant Printer, which supports job priority,
+ always supports a full range of priorities from '1' to '100' (to
+ ensure consistent behavior), therefore this attribute describes the
+ 'granularity' of priority supported. Values of this attribute are
+ from '1' to '100'.
+
+4.27. printer-copies-supported
+
+ ( 1.3.18.0.2.4.1118
+ NAME 'printer-copies-supported'
+ DESC 'The maximum number of copies of a document that may be printed
+ as a single job on this printer.'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE
+ )
+
+
+
+
+
+Fleming & McDonald Informational [Page 22]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ A positive value indicates the maximum supported copies. A value of
+ '0' indicates no maximum limit. A value of '-1' indicates 'unknown'.
+
+ Note: The syntax and values for this attribute are aligned with the
+ equivalent attribute in the 'service:printer:' v2.0 template [SLP-
+ PRT].
+
+4.28. printer-job-k-octets-supported
+
+ ( 1.3.18.0.2.4.1111
+ NAME 'printer-job-k-octets-supported'
+ DESC 'The maximum size in kilobytes (1,024 octets actually) incoming
+ print job that this printer will accept.'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE
+ )
+
+ A positive value indicates the maximum supported job size. A value
+ of '0' indicates no maximum limit. A value of '-1' indicates
+ 'unknown'.
+
+ Note: The syntax and values for this attribute are aligned with the
+ equivalent attribute in the 'service:printer:' v2.0 template [SLP-
+ PRT].
+
+4.29. printer-current-operator
+
+ ( 1.3.18.0.2.4.1112
+ NAME 'printer-current-operator'
+ DESC 'The identity of the current human operator responsible for
+ operating this printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ SINGLE-VALUE
+ )
+
+ The value of this attribute should include information that would
+ enable other humans to reach the operator, such as a telephone
+ number.
+
+
+
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 23]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+4.30. printer-service-person
+
+ ( 1.3.18.0.2.4.1113
+ NAME 'printer-service-person'
+ DESC 'The identity of the current human service person responsible
+ for servicing this printer.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ SINGLE-VALUE
+ )
+
+ The value of this attribute should include information that would
+ enable other humans to reach the service person, such as a telephone
+ number.
+
+4.31. printer-delivery-orientation-supported
+
+ ( 1.3.18.0.2.4.1114
+ NAME 'printer-delivery-orientation-supported'
+ DESC 'The possible delivery orientations of pages as they are printed
+ and ejected from this printer.'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+ Values defined include:
+
+ 'unknown'
+ 'face-up'
+ 'face-down'
+
+ Note: The syntax and values for this attribute are aligned with the
+ equivalent attribute in the 'service:printer:' v2.0 template [SLP-
+ PRT].
+
+4.32. printer-stacking-order-supported
+
+ ( 1.3.18.0.2.4.1115
+ NAME 'printer-stacking-order-supported'
+ DESC 'The possible stacking order of pages as they are printed and
+ ejected from this printer.'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 24]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ Values defined include:
+
+ 'unknown'
+ 'first-to-last'
+ 'last-to-first'
+
+ Note: The syntax and values for this attribute are aligned with the
+ equivalent attribute in the 'service:printer:' v2.0 template [SLP-
+ PRT].
+
+4.33. printer-output-features-supported
+
+ ( 1.3.18.0.2.4.1116
+ NAME 'printer-output-features-supported'
+ DESC 'The possible output features supported by this printer.'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+ Values defined include:
+
+ 'unknown'
+ 'bursting'
+ 'decollating'
+ 'page-collating'
+ 'offset-stacking'
+
+ Note: The syntax and values for this attribute are aligned with the
+ equivalent attribute in the 'service:printer:' v2.0 template [SLP-
+ PRT].
+
+ Note: Implementations may support other values.
+
+4.34. printer-aliases
+
+ ( 1.3.18.0.2.4.1108
+ NAME 'printer-aliases'
+ DESC 'List of site-specific administrative names of this printer in
+ addition to the value specified for printer-name.'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}
+ )
+
+ Values of this attribute should be specified in the language
+ specified in printer-natural-language-configured (for example, to
+ support text-to-speech conversions), although the printer's alias may
+ be specified in any language.
+
+
+
+Fleming & McDonald Informational [Page 25]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+5. Definition of Syntaxes
+
+ No new attribute syntaxes are defined by this document.
+
+ The attribute types defined in Section 4 of this document reference
+ syntax OIDs defined in Section 6 of [RFC2252], which are summarized
+ below:
+
+ Syntax OID Syntax Description
+ ------------------------------ ------------------
+ 1.3.6.1.4.1.1466.115.121.1.7 Boolean
+ 1.3.6.1.4.1.1466.115.121.1.15 DirectoryString (UTF-8 [RFC2279])
+ 1.3.6.1.4.1.1466.115.121.1.27 Integer
+
+6. Definition of Matching Rules
+
+ No new matching rules are defined by this document.
+
+ The attribute types defined in Section 4 of this document reference
+ matching rules defined in Section 8 of [RFC2252] and/or Section 2 of
+ [RFC3698], which are summarized below:
+
+ Matching Rule OID Matching Rule Name Usage
+ ------------------------------ ------------------ -----
+ 2.5.13.13 booleanMatch EQUALITY
+ 2.5.13.2 caseIgnoreMatch EQUALITY
+ 2.5.13.14 integerMatch EQUALITY
+ 2.5.13.15 integerOrderingMatch ORDERING
+ 2.5.13.4 caseIgnoreSubstringsMatch SUBSTR
+
+7. IANA Considerations
+
+ This document does not define any new syntaxes or matching rules.
+
+ This document does define the following Object Identifier
+ Descriptors. They have been registered by the IANA:
+
+7.1. Registration of Object Classes
+
+ Subject: Request for LDAP Descriptor Registration
+
+ Descriptor (short name): see table below
+
+ Object Identifier: see table below
+
+ Person & email address to contact for further information: see below
+
+ Usage: object class
+
+
+
+Fleming & McDonald Informational [Page 26]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ Specification: RFC3712
+
+ Author/Change Controller:
+
+ Pat Fleming
+ IBM
+ Highway 52 N
+ Rochester, MN 55901
+ USA
+ Phone: +1 507-253-7583
+ EMail: flemingp@us.ibm.com
+
+ Comments:
+
+ Object Class OID
+ ------------------------------------ ---------------------
+ slpServicePrinter 1.3.18.0.2.6.254
+ printerAbstract 1.3.18.0.2.6.258
+ printerService 1.3.18.0.2.6.255
+ printerServiceAuxClass 1.3.18.0.2.6.257
+ printerIPP 1.3.18.0.2.6.256
+ printerLPR 1.3.18.0.2.6.253
+
+7.2. Registration of Attribute Types
+
+ Subject: Request for LDAP Descriptor Registration
+
+ Descriptor (short name): see table below
+
+ Object Identifier: see table below
+
+ Person & email address to contact for further information: see below
+
+ Usage: attribute type
+
+ Specification: RFC3712
+
+ Author/Change Controller:
+
+ Pat Fleming
+ IBM
+ Highway 52 N
+ Rochester, MN 55901
+ USA
+ Phone: +1 507-253-7583
+ EMail: flemingp@us.ibm.com
+
+
+
+
+
+Fleming & McDonald Informational [Page 27]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ Comments:
+
+ Attribute Type OID
+ ------------------------------------ ---------------------
+ printer-uri 1.3.18.0.2.4.1140
+ printer-xri-supported 1.3.18.0.2.4.1107
+ printer-name 1.3.18.0.2.4.1135
+ printer-natural-language-configured 1.3.18.0.2.4.1119
+ printer-location 1.3.18.0.2.4.1136
+ printer-info 1.3.18.0.2.4.1139
+ printer-more-info 1.3.18.0.2.4.1134
+ printer-make-and-model 1.3.18.0.2.4.1138
+ printer-ipp-versions-supported 1.3.18.0.2.4.1133
+ printer-multiple-document-jobs-supported 1.3.18.0.2.4.1132
+ printer-charset-configured 1.3.18.0.2.4.1109
+ printer-charset-supported 1.3.18.0.2.4.1131
+ printer-generated-natural-language-supported 1.3.18.0.2.4.1137
+ printer-document-format-supported 1.3.18.0.2.4.1130
+ printer-color-supported 1.3.18.0.2.4.1129
+ printer-compression-supported 1.3.18.0.2.4.1128
+ printer-pages-per-minute 1.3.18.0.2.4.1127
+ printer-pages-per-minute-color 1.3.18.0.2.4.1126
+ printer-finishings-supported 1.3.18.0.2.4.1125
+ printer-number-up-supported 1.3.18.0.2.4.1124
+ printer-sides-supported 1.3.18.0.2.4.1123
+ printer-media-supported 1.3.18.0.2.4.1122
+ printer-media-local-supported 1.3.18.0.2.4.1117
+ printer-resolution-supported 1.3.18.0.2.4.1121
+ printer-print-quality-supported 1.3.18.0.2.4.1120
+ printer-job-priority-supported 1.3.18.0.2.4.1110
+ printer-copies-supported 1.3.18.0.2.4.1118
+ printer-job-k-octets-supported 1.3.18.0.2.4.1111
+ printer-current-operator 1.3.18.0.2.4.1112
+ printer-service-person 1.3.18.0.2.4.1113
+ printer-delivery-orientation-supported 1.3.18.0.2.4.1114
+ printer-stacking-order-supported 1.3.18.0.2.4.1115
+ printer-output-features-supported 1.3.18.0.2.4.1116
+ printer-aliases 1.3.18.0.2.4.1108
+
+8. Internationalization Considerations
+
+ All text string attributes defined in this document of syntax
+ [RFC2279], as required by [RFC2252].
+
+ A language tag [RFC3066] for all of the text string attributes
+ defined in this document is contained in the printer-natural-
+ language-configured attribute.
+
+
+
+
+Fleming & McDonald Informational [Page 28]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ Therefore, all object classes defined in this document conform to the
+ "IETF Policy on Character Sets and Languages" [RFC2277].
+
+9. Security Considerations
+
+ See [RFC2829] for detailed guidance on authentication methods for
+ LDAP. See [RFC2830] for detailed guidance of using TLS/1.0 [RFC2246]
+ to supply connection confidentiality and data integrity for LDAP
+ sessions.
+
+ As with any LDAP schema, it is important to protect specific entries
+ and attributes with the appropriate access control. It is
+ particularly important that only administrators can modify entries
+ defined in this LDAP printer schema. Otherwise, an LDAP client might
+ be fooled into diverting print service requests from the original
+ printer (or spooler) to a malicious intruder's host system, thus
+ exposing the information in printed documents.
+
+ For additional security considerations of deploying printers in an
+ IPP environment, see Section 8 of [RFC2911].
+
+10. References
+
+10.1. Normative References
+
+ [IANA-CHAR] IANA Registry of Character Sets
+ http://www.iana.org/assignments/charset-reg/...
+
+ [IANA-MIME] IANA Registry of MIME Media Types
+ http://www.iana.org/assignments/media-types/...
+
+ [LDAP-TS] Hodges, J. and R. Morgan, "Lightweight Directory Access
+ Protocol (v3): Technical Specification", RFC 3377,
+ September 2002.
+
+ [RFC1274] Barker, P. and S. Kille, "The COSINE and Internet X.500
+ Schema", RFC 1274, November 1991.
+
+ [RFC1759] Smith, R., Wright, F., Hastings, T., Zilles, S. and J.
+ Gyllenskog, "Printer MIB", RFC 1759, March 1995.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2252] Wahl, M., Coulbeck, T., Howes, T. and S. Kille,
+ "Lightweight Directory Access Protocol (v3): Attribute
+ Syntax Definitions", RFC 2252, December 1997.
+
+
+
+
+Fleming & McDonald Informational [Page 29]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ [RFC2396] Berners-Lee. T., Fielding, R. and L. Masinter, "URI
+ Generic Syntax", RFC 2396, August 1998.
+
+ [RFC2829] Wahl, M., Alvestrand, H., Hodges, J. and R. Morgan,
+ "Authentication Methods for LDAP", RFC 2829, May 2000.
+
+ [RFC2830] Hodges, J., Morgan, R. and M. Wahl, "Lightweight
+ Directory Access Protocol (v3): Extension for Transport
+ Layer Security", RFC 2830, May 2000.
+
+ [RFC2911] Hastings, T., Ed.., Herrito, R., deBry, R., Isaacson, S.
+ and P. Powell, "Internet Printing Protocol/1.1: Model and
+ Semantics", RFC 2911, September 2000.
+
+ [RFC2926] Kempf, J., Moats, R. and P. St. Pierre, "Conversion of
+ LDAP Schemas to and from SLP Templates", RFC 2926,
+ September 2000.
+
+ [RFC3066] Alvestrand, H., "Tags for the Identification of
+ Languages", BCP 47, RFC 3066, January 2001.
+
+ [RFC3698] Zeilenga, K., Ed., "Lightweight Directory Access Protocol
+ (LDAP): Additional Matching Rules", RFC 3698, February
+ 2004.
+
+10.2. Informative References
+
+ [IANA-SLPT] IANA Registry of SLP Templates
+ http://www.iana.org/assignments/svrloc-templates/...
+
+ [RFC1179] McLaughlin, L., "Line Printer Daemon Protocol", RFC 1179,
+ August 1990.
+
+ [RFC1951] Deutsch, P., "DEFLATE Compressed Data Format
+ Specification Version 1.3", RFC 1951, May 1996.
+
+ [RFC1952] Deutsch, P., "GZIP File Format Specification Version
+ 4.3", RFC 1952, May 1996.
+
+ [RFC1977] Schryver, V., "PPP BSD Compression Protocol", RFC 1977,
+ August 1996.
+
+ [RFC2048] Freed, N., Klensin, J. and J. Postel, "Multipurpose
+ Internet Mail Extensions (MIME) Part Four: Registration
+ Procedures", BCP 13, RFC 2048, November 1996.
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 30]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+ [RFC2079] Smith, M., "Definition of an X.500 Attribute Type and an
+ Object Class to Hold Uniform Resource Identifiers
+ (URIs)", RFC 2079, January 1997.
+
+ [RFC2246] Dierks, T. and C. Allen, "TLS Protocol Version 1.0", RFC
+ 2246, January 1999.
+
+ [RFC2277] Alvestrand, H., "IETF Policy on Character Sets and
+ Languages", RFC 2277, January 1998.
+
+ [RFC2279] Yergeau, F., "UTF-8, a Transformation Format of ISO
+ 10646", RFC 2279, January 1998.
+
+ [RFC2608] Guttman, E., Perkins, C., Veizades, J. and M. Day,
+ "Service Location Protocol v2", RFC 2608, June 1999.
+
+ [RFC2609] Guttman, E., Perkins, C. and J. Kempf, "Service Templates
+ and Service: Schemes", RFC 2609, June 1999.
+
+ [RFC2617] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence,
+ S., Leach, P., Luotonen, A. and L. Stewart, "HTTP
+ Authentication: Basic and Digest Access Authentication",
+ RFC 2617, June 1999.
+
+ [RFC2717] Petke, R. and I. King, "Registration Procedures for URL
+ Scheme Names", RFC 2717, November 1999.
+
+ [RFC2718] Masinter, L., Alvestrand, H., Zigmond, D. and R. Petke,
+ "Guidelines for new URL Schemes", BCP 19, RFC 2718,
+ November 1999.
+
+ [RFC2978] Freed, N. and J.Postel, "IANA Charset Registration
+ Procedures", RFC2978, October 2000.
+
+ [SLP-PRT] St. Pierre, Isaacson, McDonald. Definition of the
+ Printer Abstract Service Type v2.0, <durable URL below>,
+ May 2000. Reviewed and approved by IETF SLP Designated
+ Expert, according to Section 5 'IANA Considerations' in
+ [RFC2609].
+
+ Archived in the IANA Registry of SLP Templates [IANA-
+ SLPT] at: http://www.iana.org/assignments/svrloc-
+ templates/printer.2.0.en
+
+ [W3C-IRI] Duerst, Suignard, "Internationalized Resource Identifiers
+ (IRI), Work in Progress.
+
+
+
+
+
+Fleming & McDonald Informational [Page 31]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+11. Acknowledgments
+
+ The editors wish to acknowledge the very significant contributions of
+ Ken Jones (Bytemobile) and Harry Lewis (IBM) during the development
+ of this document.
+
+ Thanks to Patrik Faltstrom (Cisco), Ryan Moats (Lemur Networks),
+ Robert Moore (IBM), Lee Rafalow (IBM), Kimberly Reger (IBM), Kurt
+ Zeilenga (OpenLDAP), and the members of the IETF IPP Working Group,
+ for review comments and help in preparing this document.
+
+12. Authors' Addresses
+
+ Please send comments to the authors at the addresses listed below.
+
+ Pat Fleming
+ IBM
+ Highway 52 N
+ Rochester, MN 55901
+ USA
+
+ Phone: +1 507-253-7583
+ EMail: flemingp@us.ibm.com
+
+
+ Ira McDonald
+ High North Inc
+ 221 Ridge Ave
+ Grand Marais, MI 49839
+ USA
+
+ Phone: +1 906-494-2434
+ Email: imcdonald@sharplabs.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 32]
+
+RFC 3712 LDAP Schema for Printer Services February 2004
+
+
+13. Full Copyright Statement
+
+ Copyright (C) The Internet Society (2004). This document is subject
+ to the rights, licenses and restrictions contained in BCP 78 and
+ except as set forth therein, the authors retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE
+ REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE
+ INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
+ THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed
+ to pertain to the implementation or use of the technology
+ described in this document or the extent to which any license
+ under such rights might or might not be available; nor does it
+ represent that it has made any independent effort to identify any
+ such rights. Information on the procedures with respect to
+ rights in RFC documents can be found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use
+ of such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository
+ at http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention
+ any copyrights, patents or patent applications, or other
+ proprietary rights that may cover technology that may be required
+ to implement this standard. Please address the information to the
+ IETF at ietf-ipr@ietf.org.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+Fleming & McDonald Informational [Page 33]
+
diff --git a/standards/rfc3805.txt b/standards/rfc3805.txt
new file mode 100644
index 000000000..aa008142d
--- /dev/null
+++ b/standards/rfc3805.txt
@@ -0,0 +1,9579 @@
+
+
+
+
+
+
+Network Working Group R. Bergman
+Request for Comments: 3805 Hitachi Printing Solutions
+Obsoletes: 1759 H. Lewis
+Category: Standards Track IBM Corporation
+ I. McDonald
+ High North Inc.
+ June 2004
+
+
+ Printer MIB v2
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2004).
+
+Abstract
+
+ This document provides definitions of models and manageable objects
+ for printing environments. The objects included in this MIB apply to
+ physical, as well as logical entities within a printing device. This
+ document obsoletes RFC 1759.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 1]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+Table of Contents
+
+ 1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . 4
+ 1.1. Network Printing Environment. . . . . . . . . . . . . . 4
+ 1.2. Printer Device Overview . . . . . . . . . . . . . . . . 6
+ 1.3. Categories of Printer Information . . . . . . . . . . . 6
+ 1.3.1. Descriptions. . . . . . . . . . . . . . . . . . 6
+ 1.3.2. Status. . . . . . . . . . . . . . . . . . . . . 6
+ 1.3.3. Alerts. . . . . . . . . . . . . . . . . . . . . 6
+ 1.4. The Internet-Standard Management Framework. . . . . . . 7
+ 1.5. Requirement Levels. . . . . . . . . . . . . . . . . . . 7
+ 2. Printer Model . . . . . . . . . . . . . . . . . . . . . . . . 8
+ 2.1. Overview of the Printer Model . . . . . . . . . . . . . 10
+ 2.2. Printer Sub-Units . . . . . . . . . . . . . . . . . . . 10
+ 2.2.1. General Printer . . . . . . . . . . . . . . . . 10
+ 2.2.1.1. International Considerations. . . . . 10
+ 2.2.2. Inputs. . . . . . . . . . . . . . . . . . . . . 11
+ 2.2.3. Media . . . . . . . . . . . . . . . . . . . . . 12
+ 2.2.4. Outputs . . . . . . . . . . . . . . . . . . . . 12
+ 2.2.5. Finishers . . . . . . . . . . . . . . . . . . . 12
+ 2.2.6. Markers . . . . . . . . . . . . . . . . . . . . 13
+ 2.2.7. Media Paths . . . . . . . . . . . . . . . . . . 13
+ 2.2.8. System Controller . . . . . . . . . . . . . . . 14
+ 2.2.9. Interfaces. . . . . . . . . . . . . . . . . . . 14
+ 2.2.10. Print Job Delivery Channels . . . . . . . . . . 14
+ 2.2.11. Interpreters. . . . . . . . . . . . . . . . . . 15
+ 2.2.12. Console . . . . . . . . . . . . . . . . . . . . 15
+ 2.2.13. Alerts. . . . . . . . . . . . . . . . . . . . . 15
+ 2.2.13.1. Status and Alerts . . . . . . . . . . 16
+ 2.2.13.2. Overall Printer Status. . . . . . . . 16
+ 2.2.13.2.1. Host Resources MIB
+ Printer Status. . . . . . 18
+ 2.2.13.2.2. Sub-unit Status . . . . . 20
+ 2.2.13.3. Alert Tables. . . . . . . . . . . . . 21
+ 2.2.13.4. Alert Table Management. . . . . . . . 21
+ 2.3. Read-Write Objects. . . . . . . . . . . . . . . . . . . 23
+ 2.4. Enumerations. . . . . . . . . . . . . . . . . . . . . . 24
+ 2.4.1. Registering Additional Enumerated Values. . . . 25
+ 3. Groups from other MIB Specifications. . . . . . . . . . . . . 25
+ 3.1. System Group. . . . . . . . . . . . . . . . . . . . . . 25
+ 3.2. System Controller . . . . . . . . . . . . . . . . . . . 25
+ 3.3. Interface Group objects . . . . . . . . . . . . . . . . 26
+ 3.3.1. Interface Types . . . . . . . . . . . . . . . . 26
+ 4. Differences from RFC 1759 . . . . . . . . . . . . . . . . . . 26
+ 5. The IANA Printer MIB. . . . . . . . . . . . . . . . . . . . . 29
+ 6. The Printer MIB . . . . . . . . . . . . . . . . . . . . . . . 56
+ -- Textual conventions for this MIB module. . . . . . . . . . 59
+ -- The General Printer Group. . . . . . . . . . . . . . . . . 67
+
+
+
+Bergman, et al. Standards Track [Page 2]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ -- The Responsible Party group. . . . . . . . . . . . . . . . 70
+ -- The Auxiliary Sheet Group. . . . . . . . . . . . . . . . . 73
+ -- Administrative section (The General V2 Group) . . . . . . 74
+ -- General alert table section (Alert Table V2 Group). . . . 74
+ -- The Cover Table. . . . . . . . . . . . . . . . . . . . . . 75
+ -- The Localization Table . . . . . . . . . . . . . . . . . . 76
+ -- The System Resources Tables. . . . . . . . . . . . . . . . 78
+ -- The Input Group. . . . . . . . . . . . . . . . . . . . . . 81
+ -- The Extended Input Group . . . . . . . . . . . . . . . . . 86
+ -- The Input Media Group. . . . . . . . . . . . . . . . . . . 87
+ -- The Input Switching Group. . . . . . . . . . . . . . . . . 89
+ -- The Output Group . . . . . . . . . . . . . . . . . . . . . 90
+ -- The Extended Output Group. . . . . . . . . . . . . . . . . 93
+ -- The Output Dimensions Group. . . . . . . . . . . . . . . . 95
+ -- The Output Features Group. . . . . . . . . . . . . . . . . 97
+ -- The Marker Group . . . . . . . . . . . . . . . . . . . . . 98
+ -- The Marker Supplies Group. . . . . . . . . . . . . . . . . 104
+ -- The Marker Colorant Group. . . . . . . . . . . . . . . . . 107
+ -- The Media Path Group . . . . . . . . . . . . . . . . . . . 109
+ -- The Print Job Delivery Channel Group . . . . . . . . . . . 113
+ -- The Interpreter Group. . . . . . . . . . . . . . . . . . . 115
+ -- The Console Group. . . . . . . . . . . . . . . . . . . . . 120
+ -- The Alerts Group . . . . . . . . . . . . . . . . . . . . . 125
+ -- Conformance Information. . . . . . . . . . . . . . . . . . 129
+ 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 147
+ 8. Internationalization Considerations . . . . . . . . . . . . . 147
+ 9. Security Considerations . . . . . . . . . . . . . . . . . . . 148
+ 10. References. . . . . . . . . . . . . . . . . . . . . . . . . . 150
+ 10.1. Normative References. . . . . . . . . . . . . . . . . . 150
+ 10.2. Informative References. . . . . . . . . . . . . . . . . 151
+ Appendix A - Glossary of Terms. . . . . . . . . . . . . . . . . . 153
+ Appendix B - Media Size Names . . . . . . . . . . . . . . . . . . 156
+ Appendix C - Media Names. . . . . . . . . . . . . . . . . . . . . 158
+ Appendix D - Roles of Users . . . . . . . . . . . . . . . . . . . 162
+ Appendix E - Overall Printer Status Table . . . . . . . . . . . . 165
+ Appendix F - Participants . . . . . . . . . . . . . . . . . . . . 166
+ Significant Contributors. . . . . . . . . . . . . . . . . . . . . 168
+ Authors' Addresses. . . . . . . . . . . . . . . . . . . . . . . . 170
+ Full Copyright Statement. . . . . . . . . . . . . . . . . . . . . 171
+
+
+
+
+
+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 3]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+1. Introduction
+
+1.1. Network Printing Environment
+
+ The management of producing a printed document, in any computer
+ environment, is a complex subject. Basically, the task can be
+ divided into two overlapping pieces, the management of printing and
+ the management of the printer. Printing encompasses the entire
+ process of producing a printed document from generation of the file
+ to be printed, selection of a printer, choosing printing properties,
+ routing, queuing, resource management, scheduling, and final printing
+ including notifying the user. Most of the printing process is
+ outside the scope of the model presented here; only the management of
+ the printer is covered.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 4]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ Figure 1 - One Printer's View of the Network
+
+ system printer asset user user user
+ manager operator manager
+ O O O O O O
+ /|\ /|\ /|\ /|\ /|\ /|\
+ / \ / \ / \ / \ / \ / \
+ | | | | | |
++---------+ +-------+ +-------+ +-------+ +-----------+ +-----------+
+|configur-| |printer| | asset | |printer| | user | | user |
+|ator | |manager| |manager| |browser| |application| |application|
++---------+ +-------+ +-------+ +-------+ +-----------+ +-----------+
+ ^ ^ ^ ^ | |
+ |R/W |R/W |R |R +-----------+ +-----------+
+ | | | | | spooler | | spooler |
+ | | | | +-----------+ +-----------+
+ | | | | | |
+ | | | | +-----------+ +-----------+
+ | | | | |supervisor | |supervisor |
+ | | | | +-----------+ +-----------+
+ | | | | ^ ^ ^ ^
+ | | | | |R |R/W |R |R/W
+ v v | | | | | |
+================================================== | ===== |
+ | print| print|
+ |SNMP data| data|
+ +-----+ +-------+ PCL| PCL|
+ | MIB |<------>| agent | PostScript| PostScript|
+ +-----+ +-------+ NPAP| NPAP|
+ |unspecified etc.| etc.|
+ +=============+ +-----------------+ | |
+ | |--|channel/interface|<--+ |
+ | | +-----------------+ |
+ | PRINTER | |
+ | | +-----------------+ |
+ | |--|channel/interface|<----------------+
+ +=============+ +-----------------+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 5]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+1.2. Printer Device Overview
+
+ A printer is the physical device that takes media from an input
+ source, produces marks on that media according to some page
+ description or page control language and puts the result in some
+ output destination, possibly with finishing applied. Printers are
+ complex devices that consume supplies, produce waste and may have
+ mechanical problems. In the management of the physical device the
+ description, status and alert information concerning the printer and
+ its various subparts has to be made available to the management
+ application so that it can be reported to the end user, key operators
+ for the replenishment of supplies or the repair or maintenance of the
+ device. The information needed in the management of the physical
+ printer and the management of a printing job overlap highly and many
+ of the tasks in each management area require the same or similar
+ information.
+
+1.3. Categories of Printer Information
+
+ Information about printers is classified into three basic categories:
+ descriptions, status and alerts.
+
+1.3.1. Descriptions
+
+ Descriptions convey information about the configuration and
+ capabilities of the printer and its various sub-units. This
+ information is largely static information and does not generally
+ change during the operation of the system but may change as the
+ printer is repaired, reconfigured or upgraded. The descriptions are
+ one part of the visible state of the printer where state means the
+ condition of being of the printer at any point in time.
+
+1.3.2. Status
+
+ Status is the information regarding the current operating state of
+ the printer and its various sub-units. As an example of the use of
+ status, a management application must be able to determine if the
+ various sub-units are ready to print or are in some state that
+ prevents printing or may prevent printing in the future.
+
+1.3.3. Alerts
+
+ An Alert is the representation of a reportable event in the printer.
+ An event is a change in the state of the printer. Some of those
+ state changes are of interest to a management application and are
+ therefore reportable. Typically, these are the events that affect
+ the printer's ability to print. Alerts usually occur asynchronously
+ to the operation of the computer system(s) to which the printer is
+
+
+
+Bergman, et al. Standards Track [Page 6]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ attached. For convenience below, "alert" will be used for both the
+ event caused by a change in the printer's state and for the
+ representation of that event.
+
+ Alerts can be classified into two basic categories, critical and non-
+ critical. A critical alert is one that is triggered by entry into a
+ state in which the printer is stopped and printing can not continue
+ until the condition that caused the critical alert is eliminated.
+ "Out of paper", "toner empty" and "output bin full" are examples of
+ critical alerts. Non-critical alerts are triggered by those events
+ that enter a state in which printing is not stopped. Such a non-
+ critical state may, at some future time, lead to a state in which
+ printing may be stopped. Examples of these kinds of non-critical
+ alerts are "input media low", "toner low" and "output bin nearly
+ full". Or, a non-critical alert may simply provide information, such
+ as signaling a configuration changed in the printer.
+
+ Description, status and alert information about the printer can be
+ thought of as a database describing the printer. The management
+ application for a printer will want to view the printer data base
+ differently depending on how and for what purposes the information in
+ the database is needed.
+
+1.4. The Internet-Standard Management Framework
+
+ For a detailed overview of the documents that describe the current
+ Internet-Standard Management Framework, please refer to section 7 of
+ RFC 3410 [RFC3410].
+
+ Managed objects are accessed via a virtual information store, termed
+ the Management Information Base or MIB. MIB objects are generally
+ accessed through the Simple Network Management Protocol (SNMP).
+ Objects in the MIB are defined using the mechanisms defined in the
+ Structure of Management Information (SMI). This memo specifies a MIB
+ module that is compliant to the SMIv2, which is described in STD 58,
+ RFC 2578 [RFC2578], STD 58, RFC 2579 [RFC2579] and STD 58, RFC 2580
+ [RFC2580].
+
+1.5. Requirement Levels
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [RFC2119].
+
+ Compliant implementations must follow this specification.
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 7]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+2. Printer Model
+
+ In order to accomplish the management of the printer, an abstract
+ model of the printer is needed to represent the sub-units from which
+ the printer is composed. A printer can be described as consisting of
+ 13 types of sub-units. It is important to note that the sub-units of
+ a printer do not necessarily relate directly to any physically
+ identifiable mechanism. Sub-units can also be a set of definable
+ logical processes, such as interpreters for page description
+ languages or command processors that set various operating modes of
+ the printer.
+
+ Figure 2 shows a block diagram of the printer and its basic 13 sub-
+ units.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 8]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ Figure 2 - Printer Block Diagram
+
+ Physical Connections
+ |
+ +-----------+
+ | |
+ +-------------+ |
+ | Interface |-+
+ | MIB-II |
+ +-------------+
+ |
+ +-----------+
+ | |
+ +-------------+ | +-----------+
+ | Channel |-+ | Operator |
+ | | | Console |
+ +-------------+ +-----------+
+ |
+ +-----------+ +---------+
+ | | | |
+ +-----------+ +-------------+ | +-----------+ |
+ | General | | Interpreter |-+ | Alerts |-+
+ | Printer | | | | |
+ +-----------+ +-------------+ +-----------+
+ |
+ +-------------------------------+
+ | System Controller |
+ | HOST-RESOURCES-MIB |
+ +-------------------------------+
+
+ +------+ +--------+ +--------+
+ | | | | | |
++-------+ | +-------+ +---------+ | +-------+ +--------+ |
+| Input |-+ +--------+| | Marker |-+ +--------+| | Output |-+
+| |===>| |+<==>| |<==>| |+==>| |
++-------+ +--+ +--+ +---------+ +--+ +--+ +--------+
+ \ | || | || \
+ \ | || | || \
+ \ | || | || \
+ +--------+ | |+-------------------------| || +---------+
+ | | | +--------------------------+ || | |
++----------+ | | Media Path |+ +----------+ |
+| Media |-+ +--------------------------------+ | Finisher |-+
+|(optional)| |(optional)|
++----------+ +----------+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 9]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+2.1. Overview of the Printer Model
+
+ The model has three basic parts: (1) the flow of a print file into an
+ interpreter and onto the marker, (2) the flow of media through the
+ marker and (3) the auxiliary sub-units that control and facilitate
+ the two prior flows. The flow of the print data comes through a
+ physical connection on which some form of transport protocol stack is
+ running. The data provided by the transport protocol (interface)
+ appears on a channel, which is the input to an interpreter. The
+ interpreter converts the print data into a form suitable for marking
+ on the media.
+
+ The media resides in Input sub-units from which the media is selected
+ and then transported via a Media Path first to a Marking sub-unit and
+ then onto an Output sub-unit with (optionally) some finishing
+ operations being performed. The auxiliary sub-units facilitate
+ control of the printer, inquiry/control of the operator panel,
+ reporting of alerts and the adaptation of the printer to various
+ natural languages and characters sets. All the software sub-units
+ run on the System Controller that represents the processor, memory
+ and storage systems of the Printer. Each of the sub-units is
+ discussed in more detail below.
+
+ All of the sub-units other than the Alerts report only state
+ information, either a description or a status. The Alerts sub-unit
+ reports event information.
+
+2.2. Printer Sub-Units
+
+ A printer is composed of 13 types of sub-units, called groups. The
+ following sections describe the different types of sub-units.
+
+2.2.1. General Printer
+
+ The general printer sub-unit is responsible for the overall control
+ and status of the printer. There is exactly one general printer sub-
+ unit in a printer. The General Printer Group in the model represents
+ the general printer sub-unit. In addition to the providing the
+ status of the whole printer and allowing the printer to be reset,
+ this Group provides information on the status of the packaging of the
+ printer, in particular, the covers. The general printer sub-unit is
+ usually implemented on the system controller.
+
+2.2.1.1. International Considerations
+
+ The localization portion of the general printer sub-unit is
+ responsible for identifying the natural language, country, and
+ character set in which certain character strings are expressed in
+
+
+
+Bergman, et al. Standards Track [Page 10]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ this MIB. Character sets are identified in this MIB using the
+ IANACharset textual convention imported from the IANA Character Set
+ MIB [CHARMIB].
+
+ There may be one or more localizations supported per printer. The
+ available localizations are specified in the Localization table.
+ Localization SHOULD only be performed on string objects which are
+ named 'xxxDescription' (sub-unit descriptions) or
+ 'prtConsoleDisplayBufferText' (local console text).
+
+ The agent SHALL return all other character strings in coded character
+ sets in which code positions 0-127 (decimal) are US-ASCII [ASCII].
+ The agent SHOULD return all other character strings in the UTF-8
+ [RFC3629] transform of ISO 10646 [ISO10646], to conform with the IETF
+ Policy on Character Sets and Languages [RFC2277]. Control codes
+ (code positions 0-31 and 127 decimal) SHALL NOT be used unless
+ specifically required in the DESCRIPTION of an object.
+
+ The character set portion of the general printer Localization table
+ is responsible for identifying the possible character sets for the
+ operator console, and network management requests for display
+ objects. There may be one or more character sets per printer.
+ Default coded character sets for interpreter unit and output octets
+ are described in the interpreter sub-unit by
+ prtInterpreterDefaultCharSetIn and prtInterpreterDefaultCharSetOut.
+ These input/output character sets may be overridden by commands in
+ the interpreter language itself.
+
+2.2.2. Inputs
+
+ Input sub-units are mechanisms that feed media to be marked on into
+ the printer. A printer contains one or more input sub-units. The
+ Input Group in the model represents these. The model does not
+ distinguish fixed input bins from removable trays, except to report
+ when a removable tray has been removed.
+
+ There are as many input sub-units as there are distinctly selectable
+ input "addresses". For example, if one tray has both a manual and
+ auto feeding option, then this is two input sub-units if these two
+ sources can be (must be) separately selected. However, the above
+ would be considered one input sub-unit if putting a sheet in the
+ manual feed slot overrides feeding from the contents of the tray. In
+ the second case there is no way to separately select or address the
+ manual feed slot.
+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 11]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+2.2.3. Media
+
+ An input sub-unit can hold one or more instances of the media on
+ which marking is to be done. Typically, there is a large set of
+ possible media that can be associated with an input. The Media Group
+ is an extension of the Input Group, which represents media in an
+ input sub-unit. The Media Group only describes the current contents
+ of each input and not the possible content of the input sub-unit.
+
+2.2.4. Outputs
+
+ Output sub-units are mechanisms that receive media that has been
+ marked on. The Output Group in the model represents the one or more
+ output mechanisms contained by a printer. The model does not
+ distinguish fixed output bins from removable output bins, except to
+ report when a removable bin has been removed.
+
+ There are as many output sub-units as there are distinctly selectable
+ output "addresses". Output sub-units can be addressed in two
+ different ways: (1) as a set of "mailboxes" which are addressed by a
+ specific mailbox selector such as a bin number or a bin name, or (2)
+ as a set of "slots" into which multiple copies are collated.
+ Sometimes both modes of using the output sub-units can be used on the
+ same printer. All that is important from the viewpoint of the model
+ is that the output units can be separately selected.
+
+2.2.5. Finishers
+
+ A finisher is a sub-unit that performs some operations on the media
+ other than marking. The Finisher Group in the model represents the
+ finisher sub-units. Some examples of finishing processes are
+ stapling, punching, binding, inserting, or folding. Finishing
+ processes may have supplies associated with the process. Stapling,
+ binding, and punching are examples of processes that have supplies.
+ A printer may have more than one finishing sub-unit and each
+ finishing sub-unit may be associated with one or more output sub-
+ units. Finishers are described in the companion Finisher MIB
+ [RFC3806].
+
+ The model does not specify the exact interaction and sequencing
+ between an output device and its associated finisher. It depends on
+ the type of finishing process and the exact implementation of the
+ printer system. This standard allows for the logical association of
+ a finishing process with an output device but does not put any
+ restrictions on the exact sequence or interaction with the associated
+ output device. The output and finisher sub-units may or may not be
+ separate identifiable physical mechanisms depending on the exact
+
+
+
+
+Bergman, et al. Standards Track [Page 12]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ implementation of a printer. In addition, a single output device may
+ be associated with multiple finishing sub-units and a single
+ finishing sub-unit may be associated with multiple output devices.
+
+2.2.6. Markers
+
+ A marker is the mechanism that produces marks on the print media.
+ The Marker Group in the model represents the marker sub-units and
+ their associated supplies. A printer can contain one or more marking
+ mechanisms. Some examples of multiple marker sub-units are a printer
+ with separate markers for normal and magnetic ink or an image setter
+ that can output to both a proofing device and final film. Each
+ marking device can have its own set of characteristics associated
+ with it, such as marking technology and resolution.
+
+ In this model the marker sub-unit is viewed as very generalized and
+ encompasses all aspects of a marking process. For example, in a
+ xerographic process, the marking process as well as the fusing
+ process would be included in the generalized concept of the marker.
+ With the generalized concept of a marking process, the concept of
+ multiple marking supplies associated with a single marking sub-unit
+ results. For example, in the xerographic process, there is not only
+ a supply of toner, but there can also be other supplies such as a
+ fuser supply (e.g., fuser oil) that can be consumed and replaced
+ separately. In addition there can be multiple supplies of toner for
+ a single marker device, as in a color process.
+
+2.2.7. Media Paths
+
+ The media paths encompass the mechanisms in the printer that move the
+ media through the printer and connect all other media related sub-
+ units: inputs, outputs, markers and finishers. A printer contains
+ one or more media paths. The Media Path Group in the model
+ represents these. The Media Path group has some objects that apply
+ to all paths plus a table of the separate media paths.
+
+ In general, the design of the media paths determines the maximum
+ speed of the printer as well as the maximum media size that the
+ printer can handle. Media paths are complex mechanisms and can
+ contain many different identifiable sub-mechanisms such as media
+ movement devices, media buffers, duplex units and interlocks. Not
+ all of the various sub-mechanisms reside on every media path. For
+ example, one media path may provide printing only on one surface of
+ the media (a simplex path) and another media path may have a sub-
+ mechanism that turns the media over and feeds it a second time
+ through the marker sub-unit (a duplex path). The duplex path may
+
+
+
+
+
+Bergman, et al. Standards Track [Page 13]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ even have a buffer sub-mechanism that allows multiple copies of the
+ obverse side to be held before the reverse side of all the copies is
+ marked.
+
+2.2.8. System Controller
+
+ The System Controller is the sub-unit upon which the software
+ components of the Printer run. The Host Resources MIB [RFC2790]
+ represents the System Controller in the model. The Host Resources
+ MIB allows for the specification of the processor(s), memory, disk
+ storage, file system and other underlying sub-mechanisms of the
+ printer. The controller can range from simple single processor
+ systems to multiprocessor systems. In addition, controllers can have
+ a full range of resources such as hard disks. The printer is modeled
+ to have one system controller even though it may have more than one
+ processor and multiple other resources associated with it.
+
+2.2.9. Interfaces
+
+ An interface is the communications port and associated protocols that
+ are responsible for the transport of data to the printer. A printer
+ has one or more interface sub-units. The interfaces are represented
+ by the Interfaces Group of MIB-II [RFC1213], [RFC2863]. Some
+ examples of interfaces are serial ports (with little or no protocol)
+ and Ethernet ports on which one might run Internet IP, Novell IPX,
+ etc.
+
+2.2.10. Print Job Delivery Channels
+
+ The print job delivery channel sub-units identify the independent
+ sources of print data (here print data is the information that is
+ used to construct printed pages and may have both data and control
+ aspects). A printer may have one or more channels. The channel sub-
+ units are represented by the Print Job Delivery Channel Group in the
+ Model. The electronic path typically identifies each channel and
+ service protocol used to deliver print data to the printer. A
+ channel sub-unit may be independently enabled (allowing print data to
+ flow) or disabled (stopping the flow of print data). It has a
+ current Control Language that can be used to specify which
+ interpreter is to be used for the print data and to query and change
+ environment variables used by the interpreters (and SNMP). There is
+ also a default interpreter that is to be used if an interpreter is
+ not explicitly specified using the Control Language. Print Job
+ Delivery Channel sub-units can, and usually are, based on an
+ underlying interface.
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 14]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+2.2.11. Interpreters
+
+ The interpreter sub-units are responsible for the conversion of a
+ description of intended print instances into images that are to be
+ marked on the media. A printer may have one or more interpreters.
+ The Interpreter Group in the Model represents the interpreter sub-
+ units. Each interpreter is generally implemented with software
+ running on the System Controller sub-unit. The Interpreter Table has
+ one entry per interpreter where the interpreters include both Page
+ Description Language (PDL) Interpreters and Control Language
+ Interpreters.
+
+2.2.12. Console
+
+ Many printers have a console on the printer, the operator console
+ that is used to display and modify the state of the printer. The
+ console can be as simple as a few indicators and switches or as
+ complicated as full screen displays and keyboards. There can be at
+ most one such console. The Console Group in the model represents
+ this console sub-unit. Although most of the information displayed
+ there is also available in the state of the printer as represented by
+ the various Groups, it is useful to be able to query and modify the
+ operator console remotely. For example, a management application
+ might like to display to its user the current message on the operator
+ console of the remote printer or the management application user
+ might like to modify the current message on the operators console of
+ the remote printer. As another example, one might have a remote
+ application that puts up a pseudo console on a workstation screen.
+ Since the rules by which the printer state is mapped onto the console
+ and vice versa are not standardized, it is not possible to reproduce
+ the console state or the action of console buttons and menus.
+ Therefore, the Console Group provides access to the console. The
+ operator console is usually implemented on the system controller with
+ additional hardware for input and display.
+
+2.2.13. Alerts
+
+ The alert sub-unit is responsible for detecting reportable events,
+ making an entry in the alert table and, if and only if the event is a
+ critical event, initiating a trap. The exception to this rule is
+ when the "alertRemovalofBinaryChangeEntry" trap is generated. The
+ alert sub-unit is represented by the Alerts Group and, in particular,
+ the Alert Table. This table contains information on the severity,
+ sub- unit, and detailed location within the sub-unit, alert code and
+ description of each alert that is currently active within the
+ printer. Each reportable event causes an entry to be made in the
+ Alert Table.
+
+
+
+
+Bergman, et al. Standards Track [Page 15]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+2.2.13.1. Status and Alerts
+
+ Summary information about the state of the printer is reported at
+ three separate levels: (1) The status of the printer as a whole is
+ reported in the Host Resources MIB, (2) The status of various sub-
+ units is reported in the principle table of the Group that represents
+ the sub-unit, and (3) Alert codes are reported in the Alert Table.
+
+2.2.13.2. Overall Printer Status
+
+ Of the many states a printer can be in, certain states are more
+ "interesting" because of the distinct actions they are likely to
+ provoke in the administrator. These states may be applied to the
+ printer as a whole, or to a particular sub-unit of the printer.
+ These named states are:
+
+ Non Critical Alert Active - For the printer this means that one or
+ more sub-units have a non-critical alert active. For a sub-unit,
+ this means that the sub-unit has a non-critical alert active.
+
+ Critical Alert Active - For the printer this means that one or more
+ sub-units have a critical alert active. For a sub-unit, this means
+ that the sub-unit has a critical alert active.
+
+ Unavailable - The printer or sub-unit is unavailable for use (this is
+ the same as "broken" or "down" in other terminology). A trained
+ service person is typically necessary to make it available.
+
+ Moving on-line or off-line - The printer is either off-line, in the
+ process of moving off-line or moving back on-line. For example, on
+ printers with motorized hoppers, reloading paper involves a
+ transition to off-line to open the paper bin, filling the hopper and,
+ finally, a transition back to on-line as the paper bin is
+ repositioned for printing.
+
+ Standby - The printer or sub-unit is not immediately available but
+ can accept new instructions.
+
+ Available - The printer or subunit is functioning normally.
+
+ Idle - The printer or subunit is immediately available.
+
+ Active - The printer or subunit is performing its primary function.
+
+ Busy - The printer or subunit is performing a function (not
+ necessarily its primary function) and is not immediately available
+ for its primary function.
+
+
+
+
+Bergman, et al. Standards Track [Page 16]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ The Host Resources MIB [RFC2790] provides three status objects that
+ can be used to describe the status of a printer: (1) hrDeviceStatus
+ in the entry in the hrDeviceTable; (2) hrPrinterStatus in the
+ hrPrinterTable; and (3) hrPrinterDetectedErrorState in the
+ hrPrinterTable. These objects describe many of the states that a
+ printer can be in. The following table shows how the values of the
+ three printer-related objects in the Host Resources MIB relate to the
+ states named above:
+
+ Printer hrDeviceStatus hrPrinterStatus hrPrinterDetected-
+ Status ErrorState
+
+ Idle running(2) idle(3) none set
+
+ Busy/ running(2) printing(4)
+ Active
+
+ Non Critical warning(3) idle(3) or could be: lowPaper,
+ Alert Active printing(4) lowToner, or
+ serviceRequested
+
+ Critical down(5) other(1) could be: jammed,
+ Alert Active noPaper, noToner,
+ coverOpen, or
+ serviceRequested
+
+ Unavailable down(5) other(1)
+
+ Moving off- warning(3) idle(3) or offline
+ line printing(4)
+ Off-line down(5) other(1) offline
+
+ Moving down(5) warmup(5)
+ on-line
+
+ Standby running(2) other(1)
+
+ These named states are only a subset of the possible states - they
+ are not an exhaustive list of the possible states. Nevertheless,
+ several things should be noted. When using these states, it is not
+ possible to detect when both critical and non-critical alerts are
+ pending - if both are pending, the Critical Alert Active state will
+ prevail. In addition, a printer in the Standby state will be
+ represented in the Host Resources MIB with a device status of
+ running(2) and a printer status of other(1), a set of states that
+ don't uniquely distinguish this important printer state.
+
+
+
+
+
+Bergman, et al. Standards Track [Page 17]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ Detailed status per sub-unit is reported in the sub-unit status
+ fields.
+
+2.2.13.2.1. Host Resources MIB Printer Status
+
+ For completeness, the definitions of the Printer Status objects of
+ the Host Resources MIB [RFC2790] are given below:
+
+ hrDeviceStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ unknown(1),
+ running(2),
+ warning(3),
+ testing(4),
+ down(5)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The current operational state of the device
+ described by this row of the table. A value
+ unknown(1) indicates that the current state of the
+ device is unknown. running(2) indicates that the
+ device is up and running and that no unusual error
+ conditions are known. The warning(3) state
+ indicates that agent has been informed of an
+ unusual error condition by the operational software
+ (e.g., a disk device driver) but that the device
+ is still 'operational'. An example would be high
+ number of soft errors on a disk. A value of
+ testing(4), indicates that the device is not
+ available for use because it is in the testing
+ state. The state of down(5) is used only when
+ the agent has been informed that the device is
+ not available for any use."
+ ::= { hrDeviceEntry 5 }
+
+ hrPrinterStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1),
+ unknown(2),
+ idle(3),
+ printing(4),
+ warmup(5)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+
+
+
+Bergman, et al. Standards Track [Page 18]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ "The current status of this printer device. When in the
+ idle(3), printing(4), or warmup(5) state, the corresponding
+ hrDeviceStatus should be running(2) or warning(3). When in
+ the unknown(2) state, the corresponding hrDeviceStatus
+ should be unknown(1)."
+ ::= { hrPrinterEntry 1 }
+
+ hrPrinterDetectedErrorState OBJECT-TYPE
+ SYNTAX OCTET STRING (0..128)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "This object represents any error conditions detected by the
+ printer. The error conditions are encoded as an OCTET STRING
+ with the following definitions:
+
+ Condition Bit #
+
+ lowPaper 0
+ noPaper 1
+ lowToner 2
+ noToner 3
+ doorOpen 4
+ jammed 5
+ offline 6
+ serviceRequested 7
+
+ inputTrayMissing 8
+ outputTrayMissing 9
+ markerSupplyMissing 10
+ outputNearFull 11
+ outputFull 12
+ inputTrayEmpty 13
+ overduePreventMaint 14
+
+ Bit # 15 is not assigned.
+
+ If multiple conditions are currently detected and the
+ hrDeviceStatus would not otherwise be unknown(1) or
+ testing(4), the hrDeviceStatus shall correspond to the worst
+ state of those indicated, where down(5) is worse than
+ warning(3), which is worse than running(2).
+
+ Bits are numbered starting with the most significant bit of
+ the first byte being bit 0, the least significant bit of the
+ first byte being bit 7, the most significant bit of the
+ second byte being bit 8, and so on. A one bit encodes that
+ the condition was detected, while a zero bit encodes that
+
+
+
+Bergman, et al. Standards Track [Page 19]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ the condition was not detected.
+
+ This object is useful for alerting an operator to specific
+ warning or error conditions that may occur, especially those
+ requiring human intervention."
+ ::= { hrPrinterEntry 2 }
+
+2.2.13.2.2. Sub-unit Status
+
+ Sub-unit status is reported in the entries of the principle table in
+ the Group that represents the sub-unit. For sub-units that report a
+ status, there is a status column in the table and the value of this
+ column is always an integer formed in the following way.
+
+ The PrtSubUnitStatusTC is an integer that is the sum of 5 distinct
+ values, Availability, Non-Critical, Critical, On-line, and
+ Transitioning. These values are:
+
+ Availability value
+
+ Available and Idle 0 000'b
+ Available and Standby 2 010'b
+ Available and Active 4 100'b
+ Available and Busy 6 110'b
+ Unavailable and OnRequest 1 001'b
+ Unavailable because Broken 3 011'b
+ Unknown 5 101'b
+
+ Non-Critical
+
+ No Non-Critical Alerts 0
+ Non-Critical Alerts 8
+
+ Critical
+
+ No Critical Alerts 0
+ Critical Alerts 16
+
+ On-Line
+
+ State is On-Line 0
+ State is Off-Line 32
+
+ Transitioning
+
+ At intended state 0
+ Transitioning to intended state 64
+
+
+
+
+Bergman, et al. Standards Track [Page 20]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ For example, an input (tray) that jammed on the next to the last page
+ may show a status of 27 (unavailable because broken (3) + a critical
+ state (16), jammed, and a noncritical state (8), low paper).
+
+2.2.13.3. Alert Tables
+
+ The Alert Group consists of a single table in which all active alerts
+ are represented. This section provides an overview of the table and
+ a description of how it is managed. The basic content of the alert
+ table is the severity (critical or non-critical) of the alert, the
+ Group and entry where a state change caused the alert, additional
+ information about the alert (a more detailed location, an alert code,
+ and a description), and an indication of the level of training needed
+ to service the alert.
+
+ The Alert Table contains some information that is redundant, for
+ example that an event has occurred, and some information that is only
+ represented in the Alert Table, for example the additional
+ information. A single table was used because a single entry in a
+ group could cause more than one alert, for example paper jams in more
+ than one place in a media path. Associating the additional
+ information with the entry in the affected group would only allow one
+ report where associating the additional information with the alert
+ makes multiple reports possible. Every time an alert occurs in the
+ printer, the printer makes one or more entries into the Alert Table.
+ The printer determines if an event is to be classified as critical or
+ non-critical. If the severity of the Alert is "critical", the
+ printer sends a trap or event notification to the host indicating
+ that the table has changed. Whether or not a trap is sent, the
+ management application is expected to poll the printer on a regular
+ basis and to read and parse the table to determine what conditions
+ have changed, in order to provide reliable information to the
+ management application user.
+
+2.2.13.4. Alert Table Management
+
+ The alert tables are sparsely populated tables. This means the
+ tables will only contain entries of the alerts that are currently
+ active and the number of rows, or entries in the table will be
+ dynamic. More than one event can be added or removed from the event
+ tables at a time depending on the implementation of the printer.
+
+ There are basically two kinds of events that produce alerts: binary
+ change events and unary change events. Binary change events come in
+ pairs: the leading edge event and the trailing edge event. The
+ leading edge event enters a state from which there is only one exit;
+ for example, going from running to stopped with a paper jam. The
+ only exit from this state is fixing the paper jam and it is clear
+
+
+
+Bergman, et al. Standards Track [Page 21]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ when that is accomplished. The trailing edge event exits the state
+ that was entered by the leading edge event. In the example above,
+ fixing the paper jam is the trailing edge event.
+
+ It is relatively straightforward to manage binary change events in
+ the Alert Table. Only the leading edge event makes an entry in the
+ alert table. This entry persists in the Alert Table until the
+ trailing edge event occurs at which point this event is signaled by
+ the removal of the leading edge event entry in the Alert Table. That
+ is, a trailing edge event does not create an entry; it removes the
+ corresponding leading edge event. Removing the leading edge entry
+ may cause the unary change event "alertRemovalofBinaryChangeEntry" to
+ be added to the table. With binary change events it is possible to
+ compute the maximum number that can occur at the same time and
+ construct an Alert Table that would hold that many events. There
+ would be no possibility of table overflow and no information about
+ outstanding events would be lost.
+
+ Unfortunately, there are some events that are not binary changes.
+ This other category of event, the unary change event, is illustrated
+ by the configuration change event. With this kind of event the state
+ of the machine has changed, but to a state which is (often) just as
+ valid as the state that was left and from which no return is
+ necessary. For example, an operator may change the paper that is in
+ the primary input source from letter to legal. At some time in the
+ future the paper may be changed back to letter, but it might be
+ changed to executive instead. This is where the problem occurs. It
+ is not obvious how long to keep unary change event entries in the
+ Alert Table. If they were never removed, the Alert Table would
+ continue to grow indefinitely.
+
+ The agent needs to have an algorithm implemented for the management
+ of the alert table, especially in the face of combinations of binary
+ and unary alerts that would overflow the storage capacity of the
+ table. When the table is full and new alerts need to be added, an
+ old alert to be deleted should be chosen using the following rules:
+
+ 1. Find a non-critical unary alert and delete it. If there are
+ multiple non-critical unary alerts, it is suggested that the
+ oldest one is chosen. If there are no non-critical unary alerts,
+ then,
+
+ 2. Find a non-critical binary alert and delete it. If there are
+ multiple non-critical binary alerts, it is suggested that the
+ oldest one is chosen. If there are no non-critical binary alerts,
+ then,
+
+
+
+
+
+Bergman, et al. Standards Track [Page 22]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ 3. Find a critical (binary) alert and delete it. If there are
+ multiple critical alerts, it is suggested that the oldest one be
+ chosen. Agent implementers are encouraged to provide at least
+ enough storage space for the maximum number of critical alerts
+ that could occur simultaneously. Note that all critical alerts
+ are binary.
+
+ In the event that a critical binary alert has been deleted out of the
+ alert table; when space allows and the alert condition still exists,
+ the alert should be re-added to the alert table even if there was no
+ subsequent transition into the associated state. It is recommended
+ that this be done for non-critical binary alerts as well. Note that
+ the new alert entry will not have the same index as the original
+ entry that was moved out of the table.
+
+ Note that because the Alert Index is a monotonically increasing
+ integer there will be gaps in the values in the table when an alert
+ is deleted. The management application may want to re-acquire the
+ Printer state and check for state changes that it did not observe in
+ the Alert Table if such gaps are detected.
+
+2.3. Read-Write Objects
+
+ Some objects in the printer MIB reflect the existence or amount of a
+ given resource within the printer. Some examples of such resources
+ are the size and number of sheets in a paper tray or the existence of
+ certain output options. Some printers have automatic sensors for
+ these resources. Most printers lack sensors for every property of
+ every resource. The management application is allowed to write into
+ objects that hold descriptive or existence values for printers that
+ cannot sense these values. The ability to change the value of a
+ read- write object may depend on the implementation of the agent.
+ Many objects in the MIB are given read-write access, but a printer
+ implementation might only permit a management application to change
+ the value if the printer can not sense the value itself. Note that
+ even though some objects explicitly state the behavior of conditional
+ ability to change values, any read-write object may act this way.
+
+ Generally, an object is given read-write access in the Printer MIB
+ specification if:
+
+ 1. The object involves installation of a resource that some printers
+ cannot themselves detect. Therefore, external means are needed to
+ inform the printer of the installation. (Here external means
+ include using the operator console, or remote management
+ application) and
+
+
+
+
+
+Bergman, et al. Standards Track [Page 23]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ 2. The printer will behave differently if the installation of the
+ resource is reported than the printer would if the installation
+ were not reported; that is, the object is not to be used as a
+ place to put information not used by the printer, i.e., not a
+ "sticky-note". Another way of saying this is that the printer
+ believes that information given it and acts as if the information
+ were true. For example, on a printer that cannot sense the size,
+ if one paper size is loaded, but another size is set into the
+ paper size object, then the printer will use the size that was set
+ as its current paper size in its imaging and paper handling.
+
+ 3. The printer may get hints that it may not know about the existence
+ or properties of certain resources. For example, a paper tray may
+ be removed and re-inserted. When this removal and insertion
+ happens, the printer may either assume that a property, such as
+ the size of paper in the tray, has not changed or the printer may
+ change the value of the associated object to "unknown", as might
+ be done for the amount of paper in the tray. As long as the
+ printer acts according to the value in the object either strategy
+ is acceptable.
+
+ 4. It is an implementation-specific matter as to whether or not MIB
+ object values are persistent across power cycles or cold starts.
+ It is particularly important that the values of the
+ prtMarkerLifeCount object persist throughout the lifetime of the
+ printer. Therefore, if the value of any MIB object persists
+ across power cycles, then the prtMarkerLifeCount object must also
+ persist.
+
+2.4. Enumerations
+
+ Enumerations (enums) are sets of symbolic values defined for use with
+ one or more objects. Commonly used enumeration sets are assigned a
+ symbolic data type name (textual convention), rather than being
+ specified in the SYNTAX clause of each individual object definition.
+
+ Textual conventions defined in the Printer MIB or the companion IANA
+ Printer MIB are extensible by RFC publication or by Designated Expert
+ Review (see the 'IANA Considerations' section of this Printer MIB and
+ the DESCRIPTION clause in MODULE-IDENTITY of IANA Printer MIB). All
+ of these textual conventions are:
+
+ a) used more than once in the Printer MIB itself; or
+
+ b) imported and used in the companion Finisher MIB; or
+
+ c) imported and used in any other, including vendor private, MIB
+ modules.
+
+
+
+Bergman, et al. Standards Track [Page 24]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ The Printer MIB has also defined the following special values for use
+ with objects of the syntax "Integer32" to define conditions that are
+ outside of the normal numeric range: other(-1), unknown(-2), and
+ partial(-3). The 'partial' value means that there is some supply
+ remaining (but the amount is indeterminate) or there is some capacity
+ remaining (but the amount is indeterminate). The Integer32 range
+ field indicates in which objects these special values are valid.
+
+2.4.1. Registering Additional Enumerated Values
+
+ The Printer MIB and the companion IANA Printer MIB each defines one
+ category of textual convention, according to the process employed to
+ control the addition of new enumerations:
+
+ Type 1 - All of the legal values are defined in the Printer MIB.
+ Additional enumerated values require the publication of a new Printer
+ MIB.
+
+ Type 2 - All of the legal values are registered in the IANA Printer
+ MIB. Additional enumerated values require a Designated Expert Review
+ defined in "Guidelines for Writing an IANA Considerations Section in
+ RFCs" [RFC2434]. The Designated Expert will be selected by the IETF
+ Area Director(s) of the Applications Area.
+
+3. Groups from other MIB Specifications
+
+ This section identifies the groups from other MIBs that shall be
+ supported to supplement and complete a printer MIB implementation.
+ The section also describes some of the less obvious characteristics
+ of the Printer MIB structure that are related to the inclusion of
+ these other MIB groups.
+
+3.1. System Group
+
+ All objects in the system group of MIB-II [RFC1213] shall be
+ implemented; however, as described in paragraph 2.4, implementers
+ should carefully consider what constitutes the "system".
+
+3.2. System Controller
+
+ The storage and device groups of the Host Resources MIB [RFC2790]
+ shall be implemented to support the printer(s) system controller, and
+ any supporting devices. If deemed appropriate by the implementer,
+ other groups of the Host Resources MIB (System, Running Software,
+ Running Software Performance, and Installed Software) may be
+ implemented. Because of the structure of the Host Resources MIB, the
+ devices constituting the system controller are at the same level as
+ the printer.
+
+
+
+Bergman, et al. Standards Track [Page 25]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+3.3. Interface Group objects
+
+ All objects in the Interfaces Group of MIB-II [RFC1213] shall be
+ implemented for all print information interfaces to the printer,
+ including non-network interfaces.
+
+3.3.1. Interface Types
+
+ The interfaces group of RFC 1213 [RFC1213] contains only a partial
+ list of interface types that can be specified in the "ifType" object.
+ For a complete list of interface types, refer to the IANA registry at
+ "ftp://ftp.isi.edu/mib/iana.mib/ianaiftype.mib"
+
+4. Differences from RFC 1759
+
+ This document supersedes and replaces RFC 1759. However, a compliant
+ implementation of RFC 1759 is also compliant with this document. The
+ following changes to RFC 1759 are included: (See the printmib
+ REVISION/DESCRIPTION clause for additional details of changes.)
+
+ - Minor editorial corrections and changes. Updated the cover page
+ and added the "SNMP Management Framework" boilerplate to section
+ 1.
+
+ - Updated figure 2 to use MIB names instead of RFC numbers.
+
+ - Updated Coded Character Set description and IANA registration
+ process.
+
+ - Change hrPrinterDetectedErrorState "coverOpen" (bit 4) to
+ "doorOpen" per RFC 2790.
+
+ - Added second octet of hrPrinterDetectedErrorState as partially
+ described and assigned in the updated Host Resources MIB (RFC
+ 2790).
+
+ - Remove fixed association of hrDeviceStatus (warning/down) from
+ hrPrinterDetetctedErrorState per RFC 2790.
+
+ - Instead of showing bit 15 as "not assigned" in the quote from RFC
+ 2790 in the hrPrinterDetectedErrorState object, removed that from
+ the tabular form and added it as a sentence, because the RFC
+ doesn't show bit 15 in the tabular form.
+
+ - Clarified the international considerations.
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 26]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ - Added prtChannelInformation to the Channel Group textual-
+ conventions on a per channel basis to clarify the channel
+ description and enhance interoperability.
+
+ - Deprecated some obsolete channel types.
+
+ - Extended the Alert Table and PrtMarkerSuppliesSupplyUnit textual
+ conventions to include values from the Finisher MIB.
+
+ - Clarified alerts based on unary vs. binary change events.
+
+ - Added (optional) unary change event
+ alertRemovalOfBinaryChangeEntry(1801).
+
+ - Establish a convention for contact information for
+ prtGeneralCurrentOperator and prtGeneralServicePerson.
+
+ - Added prtAuxiliarySheetStartupPage PresentOnOff
+
+ - Added prtAuxiliarySheetBannerPage PresentOnOff
+
+ - Added prtGeneralPrinterName OCTET STRING
+
+ - Added prtGeneralSerialNumber OCTET STRING
+
+ - Added prtInputNextIndex Integer32
+
+ - Added the Input Switching Group
+
+ - Added prtAlertCriticalEvents Counter32
+
+ - Added prtAlertAllEvents Counter32
+
+ - Updated PrtAlertCode enums including generic alert codes.
+
+ - Created five OBJECT-GROUPs (prtAuxilliarySheetGroup,
+ prtInputSwitchingGroup, prtGeneralV2Group, prtAlertTableV2Group,
+ prtChannelV2Group). Added the nine new objects to them
+ (prtAuxiliarySheetStartupPage, prtAuxiliarySheetBannerPage,
+ prtGeneralPrinterName, prtGeneralSerialNumber,
+ prtAlertCriticalEvents, prtAlertAllEvents,
+ prtInputMediaLoadTimeout, prtInputNextIndex,
+ prtChannelInformation). Created one new NOTIFICATION-GROUP
+ (prtAlertTrapGroup) to contain printerV2Alert. Included the new
+ OBJECT-GROUPs and the NOTIFICATION_GROUP in prtMIBCompliance, all
+ in GROUP (not MANDATORY-GROUP) clauses. The nine new objects are
+ optional, i.e., this document is backward compatible with RFC
+ 1759.
+
+
+
+Bergman, et al. Standards Track [Page 27]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ - prtAlertTime is strongly recommended.
+
+ - Deprecated the use of alert codes doorOpen(501) and
+ doorClosed(502), in favor of coverOpened(3) and coverClosed(4).
+
+ - Added the PrtConsoleDisableTC and PrtMarkerAddressabilityUnitTC
+ textual conventions, and changed the PrtConsoleDisable and
+ PrtMarkerAddressabilityUnit objects' syntax to use those TCs, and
+ changed the PrtGeneralEntry and PrtMarkerColorantEntry SEQUENCEs
+ to reflect the new syntax.
+
+ - Added textual conventions "PrtLocalizedDescriptionStringTC" and
+ "PrtConsoleDescriptionStringTC" and updated several objects to use
+ them.
+
+ - Changed most enumerations to textual conventions and therefore
+ changed the SYNTAX of many objects from RFC 1759 to specify the
+ appropriate textual conventions. (28 TCs were added.)
+
+ - Changed the TC names "MediaUnit" to "PrtMediaUnitTC",
+ "CapacityUnit" to "PrtCapacityUnitTC", and "SubUnitStatus" to
+ "PrtSubUnitStatusTC"
+
+ - All objects with a MAX-ACCESS of read-write now have a MIN-ACCESS
+ of read-only.
+
+ - Added 'IANA Considerations' and 'Internationalization
+ Considerations' as top level sections, per IETF guidelines.
+
+ - Updated Security and Copyright sections.
+
+ - Updated references and split into Normative and Informative
+ groups.
+
+ - Added Appendix E - Overall Printer Status Table.
+
+ - Updated participant and contact information.
+
+ - Removed CodedCharSet Textual Convention, replaced with an import
+ of the IANACharset.
+
+ - Removed all comment statements that indicated objects or groups
+ are mandatory or optional. Avoids any potential conflicts with
+ the conformance section.
+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 28]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ - Added text to empty description clauses. (prtStorageRefTable,
+ prtDeviceRefTable, prtMarkerTable, prtMediaPathTable,
+ prtChannelTable, prtInterpreterTable, prtConsoleLightTable, and
+ prtAlertTable)
+
+ - Added "DEFVAL { unknown }" to prtInterpreterDefaultCharSetIn and
+ prtInterpreterDefaultCharSetOut.
+
+ - Changed "...values are expected to remain stable..." to "...values
+ SHOULD remain stable..." in the description clauses for the index
+ object in all tables.
+
+ - Added ranges to all objects with a syntax of Integer32.
+
+ - Revised the description clause for prtAlertGroupIndex.
+
+ - Added additional text to the description clause for
+ prtMediaPathEntry, prtChannelEntry, prtInterpreterEntry, and
+ printerV2Alert.
+
+ - Added text to section 2.4 to explain the usage of textual
+ conventions in this MIB and others. Also added a note defining
+ the common usage of the enumerations 'other(-1)' and 'unknown(-2)'
+
+ - Changed range of prtStorageRefSeqNumber, prtDeviceRefSeqNumber,
+ and prtConsoleLightIndex from (0..65535) to (1..65535) since index
+ values cannot be zero. (Typo in RFC 1759)
+
+ - The PWG Standard for Standardized Media Names is now recommended
+ for the objects prtInputMediaName, prtInputMediaColor, and
+ prtInputMediaType.
+
+ - Added chSMTP(45) to prtChannelTypeTC.
+
+5. The IANA Printer MIB
+
+IANA-PRINTER-MIB DEFINITIONS ::= BEGIN
+ -- http://www.iana.org/assignments/ianaprinter-mib
+
+IMPORTS
+ MODULE-IDENTITY,
+ mib-2
+ FROM SNMPv2-SMI -- [RFC2578]
+ TEXTUAL-CONVENTION
+ FROM SNMPv2-TC; -- [RFC2579]
+
+ianaPrinterMIB MODULE-IDENTITY
+ LAST-UPDATED "200406020000Z" -- June 2, 2004
+
+
+
+Bergman, et al. Standards Track [Page 29]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ ORGANIZATION "IANA"
+ CONTACT-INFO "Internet Assigned Numbers Authority
+ Postal: ICANN
+ 4676 Admiralty Way, Suite 330
+ Marina del Rey, CA 90292
+
+ Tel: +1 310 823 9358
+ E-Mail: iana@iana.org"
+
+ DESCRIPTION "This MIB module defines a set of printing-related
+ TEXTUAL-CONVENTIONs for use in Printer MIB (RFC 3805),
+ Finisher MIB (RFC 3806), and other MIBs which need to
+ specify printing mechanism details.
+
+ Any additions or changes to the contents of this MIB
+ module require either publication of an RFC, or
+ Designated Expert Review as defined in RFC 2434,
+ Guidelines for Writing an IANA Considerations Section
+ in RFCs. The Designated Expert will be selected by
+ the IESG Area Director(s) of the Applications Area.
+
+ Copyright (C) The Internet Society (2004). The
+ initial version of this MIB module was published
+ in RFC 3805. For full legal notices see the RFC
+ itself or see:
+ http://www.ietf.org/copyrights/ianamib.html"
+
+ REVISION "200406020000Z" -- June 2, 2004
+ DESCRIPTION "Original version, published in coordination
+ with Printer MIB (RFC 3805)."
+ ::= { mib-2 109 }
+
+--
+-- Generic TEXTUAL-CONVENTIONs
+--
+
+PrtCoverStatusTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtCoverStatus in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "Values for encoding the state of a particular cover or
+ access panel on the printer case or enclosure."
+ SYNTAX INTEGER {
+ other(1),
+ coverOpen(3),
+ coverClosed(4),
+ interlockOpen(5),
+ interlockClosed(6)
+
+
+
+Bergman, et al. Standards Track [Page 30]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ }
+
+--
+-- General Group TEXTUAL-CONVENTIONs
+--
+
+PrtGeneralResetTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtGeneralReset in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "Values for reading and writing the prtGeneralReset object.
+
+ If a device does not have NVRAM, the device shall none the
+ less respond to a SET with the value resetToNVRAM(5) with a
+ sort of warm reset that resets the device to implementation-
+ defined state that is preferably under control of the system
+ administrator by some means outside the scope of the Printer
+ MIB specification."
+
+ SYNTAX INTEGER {
+ notResetting(3),
+ powerCycleReset(4), -- Cold Start
+ resetToNVRAM(5), -- Warm Start
+ resetToFactoryDefaults(6) -- Reset contents of
+ -- NVRAM to factory
+ -- defaults
+ }
+--
+-- Channel Group TEXTUAL-CONVENTIONs
+--
+
+PrtChannelTypeTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtChannelType in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "This enumeration indicates the type of channel that is
+ receiving jobs."
+ SYNTAX INTEGER {
+ other(1),
+ chSerialPort(3),
+ chParallelPort(4),
+ chIEEE1284Port(5),
+ chSCSIPort(6),
+ chAppleTalkPAP(7),
+ -- AppleTalk Printer
+ -- Access Protocol (PAP)
+ --
+ -- prtChannelInformation entry:
+
+
+
+Bergman, et al. Standards Track [Page 31]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ --
+ -- Printer Name
+ -- Keyword: Name
+ -- Syntax: Name
+ -- Status: Optional
+ -- Multiplicity: Single
+ -- Description: The name of the printer
+ -- within the AppleTalk naming scope
+ chLPDServer(8),
+ -- prtChannelInformation entry:
+ --
+ -- Printer queue name
+ -- Keyword: Queue
+ -- Syntax: Name
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Description: queue name as
+ -- defined in [RFC1179].
+ chNetwareRPrinter(9),
+ -- Novell, Inc.
+ -- For each entry of this type, the
+ -- prtChannelInformation must have a pair of
+ -- keywords. For Netware 3.x channels this must
+ -- be a (PServer, Printer) pair. For Netware
+ -- 4.x channels and for IntranetWare channels
+ -- this must be a (NDSTree, NDSPrinter) pair.
+ --
+ -- prtChannelInformation entries:
+
+ -- Print Server Name
+ -- Keyword: PServer
+ -- Syntax: Name
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Description: The Pserver's SAP name
+ --
+ -- Printer Number
+ -- Keyword: Printer
+ -- Syntax: Integer
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Description: The printer number
+ --
+ -- NDSTree
+ -- Keyword: NDSTree
+ -- Syntax: Name
+ -- Multiplicity: Single
+ -- Description: The tree's SAP name
+
+
+
+Bergman, et al. Standards Track [Page 32]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ --
+ -- NDS Printer object
+ -- Keyword: NDSPrinter
+ -- Syntax: Text (Unicode)
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Description: The fully qualified
+ -- name of the Printer
+ --
+ -- In the Netware 3.x environment, the
+ -- client checks the Bindery object
+ -- representing the named PServer. The
+ -- client then checks for queues which
+ -- are associated with the numbered
+ -- printer. In the 4.x and IntraNetware
+ -- environment, the client looks up the
+ -- queues which are associated with the
+ -- NDS Printer Object in the named Tree.
+ -- Depending on client access rights to
+ -- those queues, the client submits jobs
+ -- to the appropriate queue.
+ chNetwarePServer(10),
+ -- Novell,Inc.
+ -- For each entry of this type, the
+ -- prtChannelInformation must have a pair
+ -- of keywords. For Netware 3.x channels
+ -- this must be a (Server, PServer) pair.
+ -- For Netware 4.x and IntranetWare
+ -- channels, this must be a
+ -- (NDSTree, NDSPServer) pair.
+ --
+ -- prtChannelInformation entries:
+ --
+ -- Server Name
+ -- Keyword: Server
+ -- Syntax: Name
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Description: The SAP name of the
+ -- server for which the PServer is defined.
+ --
+ -- PServer
+ -- Keyword: PServer
+ -- Syntax: Name
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Description: The bindery name of
+ -- the PServer
+
+
+
+Bergman, et al. Standards Track [Page 33]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ --
+ -- NDS Tree
+ -- Keyword: NDSTree
+ -- Syntax: Name
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Description: The NDS Tree name
+ --
+ -- PServer
+ -- Keyword: NDSPServer
+ -- Syntax: Text (Unicode)
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Description: The fully qualified
+ -- name of the PServer object in the tree.
+ --
+ -- In the 3.x environment, the client
+ -- checks the bindery object
+ -- representing the named PServer on the
+ -- named Server. In the 4.x and
+ -- IntranetWare environment,
+ -- the client checks the NDS object
+ -- representing the named PServer in the
+ -- named Tree. In either case, the
+ -- client then checks for all queues
+ -- associated with the Pserver object.
+ -- Depending on client access rights
+ -- to those queues, the client submits
+ -- jobs to the appropriate queue.
+ chPort9100(11),
+ -- DEPRECATED
+ -- (see chPortTCP - 37; chBidirPortTCP - 38)
+ chAppSocket(12),
+ -- A bi-directional, LPD-like, protocol using
+ -- 9101 for control and 9100 for data.
+ -- Adobe Systems, Inc.
+ chFTP(13), -- [RFC959]
+ chTFTP(14), -- [RFC1350]
+ chDLCLLCPort(15),
+ chIBM3270(16), -- IBM Coax
+ chIBM5250(17), -- IBM Twinax
+ chFax(18),
+ chIEEE1394(19),
+ chTransport1(20),
+ -- TCP port 35, for reserved TCP port list see
+ -- [RFC3232]. This RFC should also be
+ -- referenced for other channel
+ -- enumerations utilizing TCP port
+
+
+
+Bergman, et al. Standards Track [Page 34]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ -- numbers 0 through 1024.
+ chCPAP(21), -- TCP port 170
+ -- Digital Equipment Corp.
+ chDCERemoteProcCall(22), -- OSF
+ -- DEPRECATED
+ chONCRemoteProcCall(23), -- SUN Microsystems
+ -- DEPRECATED
+ chOLE(24), -- Microsoft
+ -- DEPRECATED
+ chNamedPipe(25),
+ chPCPrint(26), -- Banyan
+ chServerMessageBlock(27),
+ -- File/Print sharing protocol used by
+ -- various network operating systems
+ -- from IBM 3Com, Microsoft and others
+ --
+ -- prtChannelInformation entry:
+ --
+ -- Service Name
+ -- Keyword: Name
+ -- Syntax: Name
+ -- Status: Optional
+ -- Multiplicity: Single
+ -- Description: The service name of
+ -- the printer
+ chDPMF(28), -- IBM Infoprint
+ chDLLAPI(29), -- Microsoft
+ -- DEPRECATED
+ chVxDAPI(30), -- Microsoft
+ -- DEPRECATED
+ chSystemObjectManager(31), -- IBM
+ chDECLAT(32),
+ -- Digital Equipment Corp.
+ --
+ -- prtChannelInformation entries:
+ --
+ -- Port Name
+ -- Keyword: Port
+ -- Syntax: Name
+ -- Status: Conditionally
+ -- Mandatory
+ -- (see note below)
+ -- Multiplicity: Single
+ -- Description: LAT port name
+ --
+ -- Service Name
+ -- Keyword: Service
+ -- Syntax: Name
+
+
+
+Bergman, et al. Standards Track [Page 35]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ -- Status: Conditionally
+ -- Mandatory
+ -- Multiplicity: Single
+ -- Description: LAT service name
+ --
+ -- The LAT channel may be
+ -- identified by either a port or
+ -- service, so either a
+ -- Port or Service entry must be
+ -- specified, but not both.
+ chNPAP(33),
+ chUSB(34), -- Not in RFC 1759
+ -- Universal Serial Bus
+ chIRDA(35), -- Not in RFC 1759
+ -- Infrared Data Assoc. Prot.
+ chPrintXChange(36), -- Not in RFC 1759
+ -- PrintXChange Protocol
+ chPortTCP(37), -- Not in RFC 1759
+ -- A unidirectional "raw" TCP
+ -- channel that uses an administratively
+ -- assigned TCP port address.
+ --
+ -- prtChannelInformation entry:
+ --
+ -- Port Number
+ -- Keyword: Port
+ -- Syntax: decimal number
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Description: TCP port number
+ chBidirPortTCP(38), -- Not in RFC 1759
+ -- A bi-directional version of chPortTCP
+ --
+ -- prtChannelInformation entries:
+ -- (See chPortTCP)
+ chUNPP(39), -- Not in RFC 1759
+ -- Universal Network Printing
+ -- Protocol(UNPP). A bi-directional,
+ -- multiport network printing
+ -- application protocol available on
+ -- multiple transport protocols.
+ -- Underscore, Inc.
+ -- Contact: info@underscore.com
+ chAppleTalkADSP(40), -- Not in RFC 1759
+ -- AppleTalk Data Stream Protocol.
+ -- ADSP is part of the AppleTalk
+ -- suite of protocols.
+ -- It is a symmetric, connection-
+
+
+
+Bergman, et al. Standards Track [Page 36]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ -- oriented protocol that makes
+ -- possible the establishment
+ -- and maintenance of full-duplex
+ -- streams of data bytes between
+ -- two sockets in an AppleTalk
+ -- internet.
+ -- See [APPLEMAC].
+ chPortSPX(41), -- Not in RFC 1759
+ -- Sequenced Packet Exchange (SPX)
+ -- socket.
+ -- Novell, Inc. Similar to TCP, a
+ -- bi-directional data pipe using
+ -- Novell SPX as a transport.
+ --
+ -- prtChannelInformation entries:
+ --
+ -- Network Number
+ -- Keyword: Net
+ -- Syntax: HexString
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Description: The network number
+ --
+ -- Node Number
+ -- Keyword: Node
+ -- Syntax: HexString
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Description: The node number
+ --
+ -- Socket Number
+ -- Keyword: Socket
+ -- Syntax: HexString
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Description: The SPX socket number
+ --
+ -- There must be exactly one "Net" and
+ -- one "Node" and one "Socket" entry. A
+ -- HexString is a binary value
+ -- represented as a string of
+ -- ASCII characters using hexadecimal
+ -- notation.
+ chPortHTTP(42), -- Not in RFC 1759
+ -- Hypertext Transfer Protocol. See [RFC1945]
+ -- and [RFC2616].
+ chNDPS(43), -- Not in RFC 1759
+ -- Novell, Inc.
+
+
+
+Bergman, et al. Standards Track [Page 37]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ --
+ -- prtChannelInformation entry:
+ --
+ -- Printer Agent Name
+ -- Keyword: PA
+ -- Syntax: Name
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Description: The NDPS Printer
+ -- Agent Name
+ chIPP(44), -- Not in RFC 1759
+ -- Internet Printing Protocol (IPP),
+ -- (IPP/1.1 - see [RFC2910] and [RFC2911])
+ -- also applies to all future versions of IPP.
+ --
+ -- IPP Printer URI
+ -- Keyword: URI
+ -- Syntax: URI (Unicode UTF-8 per
+ -- [RFC2396])
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Default: not applicable
+ -- Description: URI of this IPP Printer
+ -- within Internet naming scope. Unicode
+ -- UTF-8 [RFC3629] string with
+ -- hexadecimal escapes for any non-ASCII
+ -- characters (per [RFC2396]).
+ -- Conformance: An IPP Printer shall list all
+ -- IPP URI it supports (one per IPP Channel
+ -- entry). If a URI contains the 'http:'
+ -- scheme it must have an explicit port.
+ -- See: [RFC3629], [RFC2396], [RFC2910],
+ -- [RFC2911].
+ --
+ -- IPP Printer Client Authentication
+ -- Keyword: Auth
+ -- Syntax: Keyword
+ -- Status: Optional
+ -- Multiplicity: Single
+ -- Default: 'none'
+ -- Description: A client authentication
+ -- mechanism supported for this IPP Printer
+ -- URI:
+ -- 'none'
+ -- no client authentication mechanism
+ -- 'requesting-user-name'
+ -- authenticated user in 'requesting-
+ -- user-name'
+
+
+
+Bergman, et al. Standards Track [Page 38]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ -- 'basic'
+ -- authenticated user via HTTP Basic
+ -- mechanism
+ -- 'digest'
+ -- authenticated user via HTTP Digest
+ -- mechanism
+ -- 'certificate'
+ -- authenticated user via certificate
+ -- mechanism
+ -- Conformance: An IPP Printer should list
+ -- all IPP client authentication mechanisms
+ -- it supports (one per IPP Channel entry).
+ -- See: [RFC2911] and [RFC2910].
+ --
+ -- IPP Printer Security
+ -- Keyword: Security
+ -- Syntax: Keyword
+ -- Status: Optional
+ -- Multiplicity: Single
+ -- Default: 'none'
+ -- Description: A security mechanism
+ -- supported for this IPP Printer URI:
+ -- 'none'
+ -- no security mechanism
+ -- 'ssl3'
+ -- SSL3 secure communications channel
+ -- protocol
+ -- 'tls'
+ -- TLS secure communications channel
+ -- protocol
+ -- Conformance: An IPP Printer should list
+ -- all IPP security mechanisms it supports
+ -- (one per IPP Channel entry).
+ -- See: [RFC2246], [RFC2911].
+ --
+ -- IPP Printer Protocol Version
+ -- Keyword: Version
+ -- Syntax: Keyword
+ -- Status: Optional
+ -- Multiplicity: Multiple
+ -- Default: '1.1'
+ -- Description: All of the IPP protocol
+ -- versions (major.minor) supported for
+ -- this IPP Printer URI:
+ -- '1.0'
+ -- IPP/1.0 conforming Printer
+ -- '1.1'
+ -- IPP/1.1 conforming Printer
+
+
+
+Bergman, et al. Standards Track [Page 39]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ -- Conformance: An IPP Printer should list
+ -- all IPP versions it supports (all listed
+ -- in each IPP Channel entry). An IPP
+ -- Client should select the highest
+ -- numbered version the IPP Client supports
+ -- for use in all IPP Requests (for optimum
+ -- interworking).
+ -- See: [RFC2911].
+ chSMTP(45)
+ -- Print Job submission via Simple Mail
+ -- Transfer Protocol (SMTP) - see [RFC2821]
+ --
+ -- prtChannelInformation entry:
+ --
+ -- Keyword: Mailto
+ -- Syntax: Name
+ -- Status: Mandatory
+ -- Multiplicity: Single
+ -- Default: not applicable
+ -- Description: The SMTP URL of the printer.
+}
+
+--
+-- Interpreter Group TEXTUAL-CONVENTIONs
+--
+
+PrtInterpreterLangFamilyTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtInterpreterLangFamily in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "This enumeration indicates the type of interpreter that is
+ receiving jobs."
+ SYNTAX INTEGER {
+ other(1),
+ unknown(2), -- Not in RFC 1759
+ langPCL(3), -- PCL. Starting with PCL version 5,
+ -- HP-GL/2 is included as part of the
+ -- PCL language.
+ -- PCL and HP-GL/2 are registered
+ -- trademarks of Hewlett-Packard
+ -- Company.
+ langHPGL(4), -- Hewlett-Packard Graphics Language.
+ -- HP-GL is a registered trademark of
+ -- Hewlett-Packard Company.
+ langPJL(5), -- Peripheral Job Language. Appears in
+ -- the data stream between data intended
+ -- for a page description language.
+ -- Hewlett-Packard Co.
+
+
+
+Bergman, et al. Standards Track [Page 40]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ langPS(6), -- PostScript (tm) Language
+ -- Postscript - a trademark of Adobe
+ -- Systems Incorporated which may be
+ -- registered in certain jurisdictions
+ langIPDS(7), -- Intelligent Printer Data Stream
+ -- Bi-directional print data stream for
+ -- documents consisting of data objects
+ -- (text, image, graphics, bar codes),
+ -- resources (fonts, overlays) and page,
+ -- form and finishing instructions.
+ -- Facilitates system level device
+ -- control, document tracking and error
+ -- recovery throughout the print
+ -- process.
+ -- IBM Corporation.
+ langPPDS(8), -- IBM Personal Printer Data Stream.
+ -- Originally called IBM ASCII, the name
+ -- was changed to PPDS when the Laser
+ -- Printer was introduced in 1989.
+ -- Lexmark International, Inc.
+ langEscapeP(9), -- Epson Corp.
+ langEpson(10),
+ langDDIF(11), -- Digital Document Interchange Format
+ -- Digital Equipment Corp., Maynard MA
+ langInterpress(12),
+ -- Xerox Corp.
+ langISO6429(13), -- ISO 6429. Control functions for
+ -- Coded Character Sets (has ASCII
+ -- control characters, plus additional
+ -- controls for
+ -- character imaging devices.)
+ langLineData(14), -- line-data: Lines of data as
+ -- separate ASCII or EBCDIC records
+ -- and containing no control functions
+ -- (no CR, LF, HT, FF, etc.)
+ -- For use with traditional line
+ -- printers. May use CR and/or LF to
+ -- delimit lines, instead of records.
+ -- See ISO 10175 Document Printing
+ -- Application (DPA) [ISO10175].
+ langMODCA(15), -- Mixed Object Document Content
+ -- Architecture
+ -- Definitions that allow the
+ -- composition, interchange, and
+ -- presentation of final form
+ -- documents as a collection of data
+ -- objects (text, image, graphics, bar
+ -- codes), resources (fonts, overlays)
+
+
+
+Bergman, et al. Standards Track [Page 41]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ -- and page, form and finishing
+ -- instructions.
+ -- IBM Corporation.
+ langREGIS(16), -- Remote Graphics Instruction Set,
+ -- Digital Equipment Corp., Maynard MA
+ langSCS(17), -- SNA Character String
+ -- Bi-directional print data stream for
+ -- SNA LU-1 mode of communication.
+ -- IBM
+ langSPDL(18), -- ISO 10180 Standard Page Description
+ -- Language
+ -- ISO Standard
+ langTEK4014(19), -- Tektronix Corp.
+ langPDS(20),
+ langIGP(21), -- Printronix Corp.
+ langCodeV(22), -- Magnum Code-V, Image and printer
+ -- control language used to control
+ -- impact/dot-matrix printers.
+ -- QMS, Inc., Mobile AL
+ langDSCDSE(23), -- DSC-DSE: Data Stream Compatible and
+ -- Emulation Bi-directional print data
+ -- stream for non-SNA (DSC) and SNA LU-3
+ -- 3270 controller (DSE) communications
+ -- IBM
+ langWPS(24), -- Windows Printing System, Resource
+ -- based command/data stream used by
+ -- Microsoft At Work Peripherals.
+ -- Developed by the Microsoft
+ -- Corporation.
+ langLN03(25), -- Early DEC-PPL3, Digital Equipment
+ -- Corp.
+ langCCITT(26),
+ langQUIC(27), -- QUIC (Quality Information Code), Page
+ -- Description Language for laser
+ -- printers. Included graphics, printer
+ -- control capability and emulation of
+ -- other well-known printer.
+ -- QMS, Inc.
+ langCPAP(28), -- Common Printer Access Protocol
+ -- Digital Equipment Corp.
+ langDecPPL(29), -- Digital ANSI-Compliant Printing
+ -- Protocol
+ -- (DEC-PPL)
+ -- Digital Equipment Corp.
+ langSimpleText(30),
+ -- simple-text: character coded data,
+ -- including NUL, CR , LF, HT, and FF
+ -- control characters. See ISO 10175
+
+
+
+Bergman, et al. Standards Track [Page 42]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ -- Document Printing Application (DPA)
+ -- [ISO10175].
+ langNPAP(31), -- Network Printer Alliance Protocol
+ -- (NPAP). This protocol has been
+ -- superseded by the IEEE 1284.1 TIPSI
+ -- Std (ref. LangTIPSI(49)).
+ langDOC(32), -- Document Option Commands, Appears in
+ -- the data stream between data
+ -- intended for a page description.
+ -- QMS, Inc.
+ langimPress(33), -- imPRESS, Page description language
+ -- originally developed for the
+ -- ImageServer product line. A binary
+ -- language providing representations
+ -- of text, simple graphics, and some
+ -- large forms (simple
+ -- bit-map and CCITT group 3/4
+ -- encoded).The
+ -- language was intended to be sent over
+ -- an 8-bit channel and supported early
+ -- document preparation languages (e.g.,
+ -- TeX and TROFF).
+ -- QMS, Inc.
+ langPinwriter(34),
+ -- 24 wire dot matrix printer for
+ -- USA, Europe, and Asia except
+ -- Japan.
+ -- More widely used in Germany, and
+ -- some Asian countries than in US.
+ -- NEC
+ langNPDL(35), -- Page printer for Japanese market.
+ -- NEC
+ langNEC201PL(36), -- Serial printer language used in
+ -- the Japanese market.
+ -- NEC
+ langAutomatic(37),
+ -- Automatic PDL sensing. Automatic
+ -- sensing of the interpreter
+ -- language family by the printer
+ -- examining the document content.
+ -- Which actual interpreter language
+ -- families are sensed depends on
+ -- the printer implementation.
+ langPages(38), -- Page printer Advanced Graphic
+ -- Escape Set
+ -- IBM Japan
+ langLIPS(39), -- LBP Image Processing System
+ langTIFF(40), -- Tagged Image File Format (Aldus)
+
+
+
+Bergman, et al. Standards Track [Page 43]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ langDiagnostic(41),
+ -- A hex dump of the input to the
+ -- interpreter
+ langPSPrinter(42),
+ -- The PostScript Language used for
+ -- control (with any PDLs)
+ -- Adobe Systems Incorporated
+ langCaPSL(43), -- Canon Print Systems Language
+ langEXCL(44), -- Extended Command Language
+ -- Talaris Systems Inc.
+ langLCDS(45), -- Line Conditioned Data Stream
+ -- Xerox Corporation
+ langXES(46), -- Xerox Escape Sequences
+ -- Xerox Corporation
+ langPCLXL(47), -- Not in RFC 1759
+ -- Printer Control Language. Extended
+ -- language features for printing, and
+ -- printer control.
+ -- Hewlett-Packard Co.
+ langART(48), -- Not in RFC 1759
+ -- Advanced Rendering Tools (ART).
+ -- Page Description language
+ -- originally developed for the Laser
+ -- Press printers.
+ -- Technical reference manual: "ART IV
+ -- Reference Manual", No F33M.
+ -- Fuji Xerox Co., Ltd.
+ langTIPSI(49), -- Not in RFC 1759
+ -- Transport Independent Printer
+ -- System Interface (ref. IEEE Std.
+ -- 1284.1)
+ langPrescribe(50), -- Not in RFC 1759
+ -- Page description and printer
+ -- control language. It can be
+ -- described with ordinary ASCII
+ -- Technical reference manual:
+ -- "PRESCRIBE II Programming Manual"
+ langLinePrinter(51), -- Not in RFC 1759
+ -- A simple-text character stream which
+ -- supports the control codes LF, VT,
+ -- FF, and plus Centronics or
+ -- Dataproducts Vertical Format Unit
+ -- (VFU) language is commonly used on
+ -- many older model line and matrix
+ -- printers.
+ langIDP(52), -- Not in RFC 1759
+ -- Imaging Device Protocol
+ -- Apple Computer.
+
+
+
+Bergman, et al. Standards Track [Page 44]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ langXJCL(53), -- Not in RFC 1759
+ -- Xerox Job Control Language (JCL).
+ -- A Job Control language originally
+ -- developed for the LaserPress printers
+ -- and is capable of switching PDLs.
+ -- Technical reference manual:
+ -- "ART IV Reference Manual", No F33M.
+ -- Fuji Xerox Co., Ltd.
+ langPDF(54), -- Not in RFC 1759
+ -- Adobe Portable Document Format
+ -- Adobe Systems, Inc.
+ langRPDL(55), -- Not in RFC 1759
+ -- Ricoh Page Description Language for
+ -- printers.
+ -- Technical manual "RPDL command
+ -- reference" No.307029
+ -- RICOH, Co. LTD
+ langIntermecIPL(56), -- Not in RFC 1759
+ -- Intermec Printer Language for label
+ -- printers.
+ -- Technical Manual: "IPL Programmers
+ -- Reference Manual"
+ -- Intermec Corporation
+ langUBIFingerprint(57), -- Not in RFC 1759
+ -- An intelligent basic-like programming
+ -- language for label printers.
+ -- Reference Manual: "UBI Fingerprint
+ -- 7.1", No. 1-960434-00
+ -- United Barcode Industries
+ langUBIDirectProtocol(58), -- Not in RFC 1759
+ -- An intelligent control language for
+ -- label printers.
+ -- Programmers guide: " UBI Direct
+ -- Protocol", No. 1-960419-00
+ -- United Barcode Industries
+ langFujitsu(59), -- Not in RFC 1759
+ -- Fujitsu Printer Language
+ -- Reference Manual:
+ -- "FM Printer Sequence" No. 80HP-0770
+ -- FUJITSU LIMITED
+ langCGM(60), -- Not in RFC 1759
+ -- Computer Graphics Metafile
+ -- MIME type 'image/cgm'
+ langJPEG(61), -- Not in RFC 1759
+ -- Joint Photographic Experts Group
+ -- MIME type 'image/jpeg'
+ langCALS1(62), -- Not in RFC 1759
+ -- US DOD CALS1 (see MIL-STD-1840)
+
+
+
+Bergman, et al. Standards Track [Page 45]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ -- MIME type 'application/cals-1840'
+ langCALS2(63), -- Not in RFC 1759
+ -- US DOD CALS2 (see MIL-STD-1840)
+ -- MIME type 'application/cals-1840'
+ langNIRS(64), -- Not in RFC 1759
+ -- US DOD NIRS (see MIL-STD-1840)
+ -- MIME type 'application/cals-1840'
+ langC4(65) -- Not in RFC 1759
+ -- US DOD C4 (see MIL-STD-1840)
+ -- MIME type 'application/cals-1840'
+}
+
+--
+-- Input/Output Group TEXTUAL-CONVENTIONs
+--
+
+PrtInputTypeTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtInputType in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The type of technology (discriminated primarily according to
+ feeder mechanism type) employed by a specific component or
+ components."
+ SYNTAX INTEGER {
+ other(1),
+ unknown(2),
+ sheetFeedAutoRemovableTray(3),
+ sheetFeedAutoNonRemovableTray(4),
+ sheetFeedManual(5),
+ continuousRoll(6),
+ continuousFanFold(7)
+ }
+
+PrtOutputTypeTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtOutputType in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The Type of technology supported by this output subunit."
+ SYNTAX INTEGER {
+ other(1),
+ unknown(2),
+ removableBin(3),
+ unRemovableBin(4),
+ continuousRollDevice(5),
+ mailBox(6),
+ continuousFanFold(7)
+ }
+
+
+
+
+Bergman, et al. Standards Track [Page 46]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+--
+-- Marker Group TEXTUAL-CONVENTIONs
+--
+
+PrtMarkerMarkTechTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtMarkerMarkTech in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The type of marking technology used for this marking
+ subunit."
+ SYNTAX INTEGER {
+ other(1),
+ unknown(2),
+ electrophotographicLED(3),
+ electrophotographicLaser(4),
+ electrophotographicOther(5),
+ impactMovingHeadDotMatrix9pin(6),
+ impactMovingHeadDotMatrix24pin(7),
+ impactMovingHeadDotMatrixOther(8),
+ impactMovingHeadFullyFormed(9),
+ impactBand(10),
+ impactOther(11),
+ inkjetAqueous(12),
+ inkjetSolid(13),
+ inkjetOther(14),
+ pen(15),
+ thermalTransfer(16),
+ thermalSensitive(17),
+ thermalDiffusion(18),
+ thermalOther(19),
+ electroerosion(20),
+ electrostatic(21),
+ photographicMicrofiche(22),
+ photographicImagesetter(23),
+ photographicOther(24),
+ ionDeposition(25),
+ eBeam(26),
+ typesetter(27)
+ }
+
+PrtMarkerSuppliesTypeTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtMarkerSuppliesType in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The type of this supply."
+ SYNTAX INTEGER {
+ other(1),
+ unknown(2),
+
+
+
+Bergman, et al. Standards Track [Page 47]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ -- Values for Printer MIB
+ toner(3),
+ wasteToner(4),
+ ink(5),
+ inkCartridge(6),
+ inkRibbon(7),
+ wasteInk(8),
+ opc(9), -- photo conductor
+ developer(10),
+ fuserOil(11),
+ solidWax(12),
+ ribbonWax(13),
+ wasteWax(14),
+ fuser(15), -- Not in RFC 1759
+ coronaWire(16), -- Not in RFC 1759
+ fuserOilWick(17), -- Not in RFC 1759
+ cleanerUnit(18), -- Not in RFC 1759
+ fuserCleaningPad(19), -- Not in RFC 1759
+ transferUnit(20), -- Not in RFC 1759
+ tonerCartridge(21), -- Not in RFC 1759
+ fuserOiler(22), -- Not in RFC 1759
+ -- End of values for Printer MIB
+ -- Values for Finisher MIB
+ water(23), -- Not in RFC 1759
+ wasteWater(24), -- Not in RFC 1759
+ glueWaterAdditive(25),-- Not in RFC 1759
+ wastePaper(26), -- Not in RFC 1759
+ bindingSupply(27), -- Not in RFC 1759
+ bandingSupply(28), -- Not in RFC 1759
+ stitchingWire(29), -- Not in RFC 1759
+ shrinkWrap(30), -- Not in RFC 1759
+ paperWrap(31), -- Not in RFC 1759
+ staples(32), -- Not in RFC 1759
+ inserts(33), -- Not in RFC 1759
+ covers(34) -- Not in RFC 1759
+ -- End of values for Finisher MIB
+ }
+
+--
+-- Media Path TEXTUAL-CONVENTIONs
+--
+
+PrtMediaPathTypeTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtMediaPathType in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The type of the media path for this media path."
+ SYNTAX INTEGER {
+
+
+
+Bergman, et al. Standards Track [Page 48]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ other(1),
+ unknown(2),
+ longEdgeBindingDuplex(3),
+ shortEdgeBindingDuplex(4),
+ simplex(5)
+ }
+
+--
+-- Console Group TEXTUAL-CONVENTIONs
+--
+
+PrtConsoleColorTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtConsoleColor in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The color of this light."
+ SYNTAX INTEGER {
+ other(1),
+ unknown(2),
+ white(3),
+ red(4),
+ green(5),
+ blue(6),
+ cyan(7),
+ magenta(8),
+ yellow(9),
+ orange(10) -- Not in RFC 1759
+ }
+
+PrtConsoleDisableTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtConsoleDisable in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "This value indicates whether or not input is accepted from
+ the operator console. A value of 'enabled' indicates that
+ input is accepted from the console, and a value of 'disabled'
+ indicates that input is not accepted from the console. "
+ SYNTAX INTEGER {
+ enabled(3),
+ disabled(4)
+ }
+
+--
+-- Alert Group TEXTUAL-CONVENTIONs
+--
+
+PrtAlertTrainingLevelTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtAlertTrainingLevel in RFC 1759.
+
+
+
+Bergman, et al. Standards Track [Page 49]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ STATUS current
+ DESCRIPTION
+ "The level of training required to handle this alert, if
+ human intervention is required. The noInterventionRequired
+ value should be used if the event does not require any human
+ intervention. The training level is an enumeration that is
+ determined and assigned by the printer manufacturer based on
+ the information or training required to handle this alert.
+ The printer will break alerts into these different training
+ levels. It is the responsibility of a management application
+ in the system to determine how a particular alert is handled
+ and how and to whom that alert is routed. The following are
+ the four training levels of alerts:
+
+ Field Service - Alerts that typically require advanced
+ training and technical knowledge of the printer and its
+ subunits. An example of a technical person would be a
+ manufacturer's Field Service representative, or other
+ person formally trained by the manufacturer or similar
+ representative.
+ Trained - Alerts that require an intermediate or moderate
+ knowledge of the printer and its subunits. A typical
+ example of such an alert is replacing a toner cartridge.
+ Untrained - Alerts that can be fixed without prior
+ training either because the action to correct the alert
+ is obvious or the printer can help the untrained person
+ fix the problem. A typical example of such an alert is
+ reloading paper trays or emptying output bins on a low
+ end printer.
+ Management - Alerts that have to do with overall operation
+ of and configuration of the printer. Examples of such
+ management events are configuration change of subunits."
+ SYNTAX INTEGER {
+ other(1),
+ unknown(2),
+ untrained(3),
+ trained(4),
+ fieldService(5),
+ management(6),
+ noInterventionRequired(7) -- Not in RFC 1759
+ }
+
+PrtAlertGroupTC ::= TEXTUAL-CONVENTION
+ -- Values in the range 1 to 29 must not be IANA-assigned without
+ -- re-publishing Printer MIB.
+ -- Values of 30 and greater are for use in MIBs that augment
+ -- the Printer MIB, such as the Finisher MIB.
+ -- This TC extracted from prtAlertGroup in RFC 1759.
+
+
+
+Bergman, et al. Standards Track [Page 50]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ STATUS current
+ DESCRIPTION
+ "The type of subunit within the printer model that this alert
+ is related. Input, output, and markers are examples of
+ printer model groups, i.e., examples of types of subunits.
+ Wherever possible, the enumerations match the sub-identifier
+ that identifies the relevant table in the Printer MIB.
+
+ NOTE: Alert type codes have been added for the Host Resources
+ MIB storage table and device table. These additional types
+ are for situations in which the printer's storage and device
+ objects must generate alerts (and possibly traps for critical
+ alerts)."
+ SYNTAX INTEGER {
+ other(1),
+ -- (2) is reserved for conformance information
+ -- Values for Host Resources MIB
+ hostResourcesMIBStorageTable(3),
+ hostResourcesMIBDeviceTable(4),
+ -- Values for Printer MIB
+ generalPrinter(5),
+ cover(6),
+ localization(7),
+ input(8),
+ output(9),
+ marker(10),
+ markerSupplies(11),
+ markerColorant(12),
+ mediaPath(13),
+ channel(14),
+ interpreter(15),
+ consoleDisplayBuffer(16),
+ consoleLights(17),
+ alert(18), -- Not in RFC 1759
+ -- Values (5) to (29) reserved for Printer MIB
+ -- Values for Finisher MIB
+ finDevice(30), -- Not in RFC 1759
+ finSupply(31), -- Not in RFC 1759
+ finSupplyMediaInput(32), -- Not in RFC 1759
+ finAttribute(33) -- Not in RFC 1759
+ -- Values (30) to (39) reserved for Finisher MIB
+ }
+
+PrtAlertCodeTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtAlertCode in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The code that describes the type of alert for this entry in
+
+
+
+Bergman, et al. Standards Track [Page 51]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ the table. Binary change event alerts describe states of the
+ subunit while unary change event alerts describe a single
+ event. The same alert code can be used for a binary change
+ event or a unary change event, depending on implementation.
+ Also, the same alert code can be used to indicate a critical
+ or non-critical (warning) alert, depending on implementation.
+ The value of prtAlertSeverityLevel specifies binary vs. unary
+ and critical vs. non-critical for each event for the
+ implementation.
+
+ While there are some specific codes for many subunits, the
+ generic codes should be used for most subunit alerts. The
+ network management station can then query the subunit
+ specified by prtAlertGroup to determine further subunit
+ status and other subunit information.
+
+ An agent shall not add two entries to the alert table for the
+ same event, one containing a generic event code and the other
+ containing a specific event code; the agent shall add only
+ one entry in the alert table for each event; either generic
+ (preferred) or specific, not both.
+
+ Implementation of the unary change event
+ alertRemovalOfBinaryChangeEntry(1801) is optional. When
+ implemented, this alert code shall indicate to network
+ management stations that the trailing edge of a binary change
+ event has occurred and the corresponding alert entry has been
+ removed from the alert table. As with all events, the
+ alertRemovalOfBinaryChangeEntry(1801) alert shall be placed
+ at the end of the alert table. Such an alert table entry
+ shall specify the following information:
+
+ prtAlertSeverityLevel warningUnaryChangeEvent(4)
+ prtAlertTrainingLevel noInterventionRequired(7)
+ prtAlertGroup alert(18)
+ prtAlertGroupIndex the index of the row in the
+ alert table of the binary
+ change event that this event
+ has removed.
+ prtAlertLocation unknown (-2)
+ prtAlertCode alertRemovalOfBinaryChangeEntry(1801)
+ prtAlertDescription <description or null string>
+ prtAlertTime the value of sysUpTime at
+ the time of the removal of the
+ binary change event from the
+ alert table.
+
+ Optionally, the agent may generate a trap coincident with
+
+
+
+Bergman, et al. Standards Track [Page 52]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ removing the binary change event and placing the unary change
+ event alertRemovalOfBinaryChangeEntry(1801) in the alert
+ table. For such a trap, the prtAlertIndex sent with the above
+ trap parameters shall be the index of the
+ alertRemovalOfBinaryChangeEvent row that was added to the
+ prtAlertTable; not the index of the row that was removed from
+ the prtAlertTable."
+ SYNTAX INTEGER {
+ other(1),
+ -- an event that is not represented
+ -- by one of the alert codes
+ -- specified below.
+ unknown(2),
+ -- The following generic codes are common to
+ -- multiple groups. The NMS may examine the
+ -- prtAlertGroup object to determine what group
+ -- to query for further information.
+ coverOpen(3),
+ coverClosed(4),
+ interlockOpen(5),
+ interlockClosed(6),
+ configurationChange(7),
+ jam(8),
+ subunitMissing(9), -- Not in RFC 1759
+ -- The subunit tray, bin, etc.
+ -- has been removed.
+ subunitLifeAlmostOver(10), -- Not in RFC 1759
+ subunitLifeOver(11), -- Not in RFC 1759
+ subunitAlmostEmpty(12), -- Not in RFC 1759
+ subunitEmpty(13), -- Not in RFC 1759
+ subunitAlmostFull(14), -- Not in RFC 1759
+ subunitFull(15), -- Not in RFC 1759
+ subunitNearLimit(16), -- Not in RFC 1759
+ subunitAtLimit(17), -- Not in RFC 1759
+ subunitOpened(18), -- Not in RFC 1759
+ subunitClosed(19), -- Not in RFC 1759
+ subunitTurnedOn(20), -- Not in RFC 1759
+ subunitTurnedOff(21), -- Not in RFC 1759
+ subunitOffline(22), -- Not in RFC 1759
+ subunitPowerSaver(23), -- Not in RFC 1759
+ subunitWarmingUp(24), -- Not in RFC 1759
+ subunitAdded(25), -- Not in RFC 1759
+ subunitRemoved(26), -- Not in RFC 1759
+ subunitResourceAdded(27), -- Not in RFC 1759
+ subunitResourceRemoved(28), -- Not in RFC 1759
+ subunitRecoverableFailure(29),
+ -- Not in RFC 1759
+ subunitUnrecoverableFailure(30),
+
+
+
+Bergman, et al. Standards Track [Page 53]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ -- Not in RFC 1759
+ subunitRecoverableStorageError(31),
+ -- Not in RFC 1759
+ subunitUnrecoverableStorageError(32),
+ -- Not in RFC 1759
+ subunitMotorFailure(33), -- Not in RFC 1759
+ subunitMemoryExhausted(34), -- Not in RFC 1759
+ subunitUnderTemperature(35), -- Not in RFC 1759
+ subunitOverTemperature(36), -- Not in RFC 1759
+ subunitTimingFailure(37), -- Not in RFC 1759
+ subunitThermistorFailure(38), -- Not in RFC 1759
+
+ -- General Printer group
+ doorOpen(501), -- DEPRECATED
+ -- Use coverOpened(3)
+ doorClosed(502), -- DEPRECATED
+ -- Use coverClosed(4)
+ powerUp(503),
+ powerDown(504),
+ printerNMSReset(505), -- Not in RFC 1759
+ -- The printer has been reset by some
+ -- network management station(NMS)
+ -- writing into 'prtGeneralReset'.
+ printerManualReset(506), -- Not in RFC 1759
+ -- The printer has been reset manually.
+ printerReadyToPrint(507), -- Not in RFC 1759
+ -- The printer is ready to print. (i.e.,
+ -- not warming up, not in power save
+ -- state, not adjusting print quality,
+ -- etc.).
+
+ -- Input Group
+ inputMediaTrayMissing(801),
+ inputMediaSizeChange(802),
+ inputMediaWeightChange(803),
+ inputMediaTypeChange(804),
+ inputMediaColorChange(805),
+ inputMediaFormPartsChange(806),
+ inputMediaSupplyLow(807),
+ inputMediaSupplyEmpty(808),
+ inputMediaChangeRequest(809), -- Not in RFC 1759
+ -- An interpreter has detected that a
+ -- different medium is need in this input
+ -- tray subunit. The prtAlertDescription may
+ -- be used to convey a human readable
+ -- description of the medium required to
+ -- satisfy the request.
+ inputManualInputRequest(810), -- Not in RFC 1759
+
+
+
+Bergman, et al. Standards Track [Page 54]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ -- An interpreter has detected that manual
+ -- input is required in this subunit. The
+ -- prtAlertDescription may be used to convey
+ -- a human readable description of the medium
+ -- required to satisfy the request.
+ inputTrayPositionFailure(811), -- Not in RFC 1759
+ -- The input tray failed to position correctly.
+ inputTrayElevationFailure(812),
+ -- Not in RFC 1759
+ inputCannotFeedSizeSelected(813),
+ -- Not in RFC 1759
+ -- Output Group
+ outputMediaTrayMissing(901),
+ outputMediaTrayAlmostFull(902),
+ outputMediaTrayFull(903),
+ outputMailboxSelectFailure(904),
+ -- Not in RFC 1759
+ -- Marker group
+ markerFuserUnderTemperature(1001),
+ markerFuserOverTemperature(1002),
+ markerFuserTimingFailure(1003),
+ -- Not in RFC 1759
+ markerFuserThermistorFailure(1004),
+ -- Not in RFC 1759
+ markerAdjustingPrintQuality(1005),
+ -- Not in RFC 1759
+ -- Marker Supplies group
+ markerTonerEmpty(1101),
+ markerInkEmpty(1102),
+ markerPrintRibbonEmpty(1103),
+ markerTonerAlmostEmpty(1104),
+ markerInkAlmostEmpty(1105),
+ markerPrintRibbonAlmostEmpty(1106),
+ markerWasteTonerReceptacleAlmostFull(1107),
+ markerWasteInkReceptacleAlmostFull(1108),
+ markerWasteTonerReceptacleFull(1109),
+ markerWasteInkReceptacleFull(1110),
+ markerOpcLifeAlmostOver(1111),
+ markerOpcLifeOver(1112),
+ markerDeveloperAlmostEmpty(1113),
+ markerDeveloperEmpty(1114),
+ markerTonerCartridgeMissing(1115),
+ -- Not in RFC 1759
+ -- Media Path Device Group
+ mediaPathMediaTrayMissing(1301),
+ mediaPathMediaTrayAlmostFull(1302),
+ mediaPathMediaTrayFull(1303),
+ mediaPathCannotDuplexMediaSelected(1304),
+
+
+
+Bergman, et al. Standards Track [Page 55]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ -- Not in RFC 1759
+ -- Interpreter Group
+ interpreterMemoryIncrease(1501),
+ interpreterMemoryDecrease(1502),
+ interpreterCartridgeAdded(1503),
+ interpreterCartridgeDeleted(1504),
+ interpreterResourceAdded(1505),
+ interpreterResourceDeleted(1506),
+ interpreterResourceUnavailable(1507),
+ interpreterComplexPageEncountered(1509),
+ -- Not in RFC 1759
+ -- The interpreter has encountered a page
+ -- that is too complex for the resources that
+ -- are available.
+ -- Alert Group
+ alertRemovalOfBinaryChangeEntry(1801)
+ -- Not in RFC 1759
+ -- A binary change event entry has been
+ -- removed from the alert table. This unary
+ -- change alert table entry is added to the
+ -- end of the alert table.
+ }
+END
+
+6. The Printer MIB
+
+Printer-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, Counter32, Integer32, TimeTicks,
+ NOTIFICATION-TYPE, OBJECT-IDENTITY,
+ mib-2 FROM SNMPv2-SMI -- [RFC2578]
+ TEXTUAL-CONVENTION FROM SNMPv2-TC -- [RFC2579]
+ MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
+ FROM SNMPv2-CONF -- [RFC2580]
+ hrDeviceIndex, hrStorageIndex FROM HOST-RESOURCES-MIB -- [RFC2790]
+ InterfaceIndexOrZero FROM IF-MIB -- [RFC2863]
+ PrtCoverStatusTC, PrtGeneralResetTC, PrtChannelTypeTC,
+ PrtInterpreterLangFamilyTC, PrtInputTypeTC, PrtOutputTypeTC,
+ PrtMarkerMarkTechTC, PrtMarkerSuppliesTypeTC, PrtConsoleColorTC,
+ PrtConsoleDisableTC, PrtMediaPathTypeTC, PrtAlertGroupTC,
+ PrtAlertTrainingLevelTC, PrtAlertCodeTC
+ FROM IANA-PRINTER-MIB
+ IANACharset FROM IANA-CHARSET-MIB;
+
+printmib MODULE-IDENTITY
+ LAST-UPDATED "200406020000Z"
+ ORGANIZATION "PWG IEEE/ISTO Printer Working Group"
+
+
+
+Bergman, et al. Standards Track [Page 56]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ CONTACT-INFO
+ "Harry Lewis
+ IBM
+ Phone (303) 924-5337
+ Email: harryl@us.ibm.com
+ http://www.pwg.org/index.html
+
+ Send comments to the printmib WG using the Printer MIB
+ Project (PMP) Mailing List: pmp@pwg.org
+
+ For further information, access the PWG web page under 'Printer
+ MIB': http://www.pwg.org/
+
+ Implementers of this specification are encouraged to join the
+ pmp mailing list in order to participate in discussions on any
+ clarifications needed and registration proposals being reviewed
+ in order to achieve consensus."
+ DESCRIPTION
+ "The MIB module for management of printers.
+ Copyright (C) The Internet Society (2004). This
+ version of this MIB module was published
+ in RFC 3805. For full legal notices see the RFC itself."
+ REVISION "200406020000Z"
+ DESCRIPTION
+ "Printer MIB v2.
+ Moved all enum groups to be maintained by IANA into new TCs
+ within the ianaPrinterMIB, which is contained in this
+ document.
+ New TCs created from enums defined within RFC 1759 Objects:
+ PrtPrintOrientationTC, PrtLocalizedDescriptionStringTC,
+ PrtConsoleDescriptionStringTC, PrtChannelStateTC,
+ PrtOutputStackingOrderTC, PrtOutputPageDeliveryOrientationTC,
+ PrtMarkerCounterUnitTC, PrtMarkerSuppliesSupplyUnitTC,
+ PrtMarkerSuppliesClassTC, PrtMarkerAddressabilityUnitTC,
+ PrtMarkerColorantRoleTC, PrtMediaPathMaxSpeedPrintUnitTC,
+ PrtInterpreterTwoWayTC, and PrtAlertSeverityLevelTC.
+ The following four TCs have been deprecated:
+ MediaUnit (replaced by PrtMediaUnitTC),
+ CapacityUnit (replaced by PrtCapacityUnitTC),
+ SubUnitStatus (replaced by PrtSubUnitStatusTC),
+ CodedCharSet (replaced by IANACharset in IANA Charset MIB)
+ Five new OBJECT-GROUPs: prtAuxilliarySheetGroup,
+ prtInputSwitchingGroup, prtGeneralV2Group,
+ prtAlertTableV2Group, prtChannelV2Group.
+ Nine new objects added to those groups:
+ prtAuxiliarySheetStartupPage, prtAuxiliarySheetBannerPage,
+ prtGeneralPrinterName, prtGeneralSerialNumber,
+ prtAlertCriticalEvents, prtAlertAllEvents,
+
+
+
+Bergman, et al. Standards Track [Page 57]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ prtInputMediaLoadTimeout, prtInputNextIndex,
+ prtChannelInformation.
+ SYNTAX range changed from (0..65535) to (1..65535) for the
+ index objects prtStorageRefSeqNumber, prtDeviceRefSeqNumber,
+ and prtConsoleLightIndex.
+ SYNTAX range changed from (0..65535) to (0..2147483647) for the
+ objects prtStorageRefIndex and prtDeviceRefIndex to agree
+ with the Host Resources MIB.
+ Defined a range for the objects with a SYNTAX of Integer32:
+ prtOutputDefaultIndex, prtInputMediaDimFeedDirDeclared,
+ prtInputMediaDimXFeedDirDeclared, prtInputMaxCapacity,
+ prtInputCurrentLevel, prtInputMediaDimFeedDirChosen,
+ prtInputMediaDimXFeedDirChosen, prtInputMediaWeight,
+ prtInputMediaFormParts, prtOutputIndex,
+ prtOutputMaxCapacity, prtOutputRemainingCapacity,
+ prtOutputMaxDimFeedDir, prtOutputMaxDimXFeedDir,
+ prtOutputMinDimFeedDir, prtOutputMinDimXFeedDir,
+ prtMarkerAddressibilityFeedDir,
+ prtMarkerAddressibilityXFeedDir, prtMarkerNorthMargin,
+ prtMarkerSouthMargin, prtMarkerWestMargin,
+ prtMarkerEastMargin, prtMarkerSuppliesMaxCapacity,
+ prtMarkerSuppliesLevel, prtMarkerColorantTonality,
+ prtMediaPathMaxSpeed, prtMediaPathMaxMediaFeedDir,
+ prtMediaPathMaxMediaXFeedDir, prtMediaPathMinMediaFeedDir,
+ prtMediaPathMinMediaXFeedDir, prtChannelIndex,
+ prtChannelCurrentJobCntlLangIndex, prtInterpreterIndex,
+ prtChannelDefaultPageDescLangIndex, prtConsoleOnTime,
+ prtInterpreterFeedAddressibility, prtConsoleOffTime,
+ prtInterpreterXFeedAddressibility, prtAlertIndex,
+ prtAlertGroupIndex, prtAlertLocation.
+ Changed SYNTAX from Integer32 to InterfaceIndexOrZero for
+ prtChannelIfIndex.
+ Changed MAX-ACCESS of prtAlertIndex from not-accessible to
+ Read-only and added a compliance statement to allow a
+ MIN-ACCESS of accessible-for-notify.
+ One new NOTIFICATION-GROUP: prtAlertTrapGroup which contains
+ printerV2Alert.
+ In MODULE-COMPLIANCE prtMIBCompliance, new OBJECT-GROUPs and
+ the NOTIFICATION_GROUP, all in GROUP (not MANDATORY-GROUP)
+ clauses. The nine new objects are optional, i.e., this
+ document is backward compatible with RFC 1759."
+ REVISION "199411250000Z"
+ DESCRIPTION
+ "The original version of this MIB, published as RFC1759."
+ ::= { mib-2 43 }
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 58]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+-- TEXTUAL-CONVENTIONs for this MIB module
+--
+-- Generic unspecific TEXTUAL-CONVENTIONs
+--
+
+PrtMediaUnitTC ::= TEXTUAL-CONVENTION
+ -- Replaces MediaUnit in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "Units of measure for media dimensions."
+ SYNTAX INTEGER {
+ tenThousandthsOfInches(3), -- .0001
+ micrometers(4)
+ }
+
+MediaUnit ::= TEXTUAL-CONVENTION
+ -- Replaced by PrtMediaUnitTC.
+ STATUS deprecated
+ DESCRIPTION
+ "Units of measure for media dimensions."
+ SYNTAX INTEGER {
+ tenThousandthsOfInches(3), -- .0001
+ micrometers(4)
+ }
+
+PrtCapacityUnitTC ::= TEXTUAL-CONVENTION
+ -- Replaces CapacityUnit in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "Units of measure for media capacity."
+ SYNTAX INTEGER {
+ other(1), -- New, not in RFC 1759
+ unknown(2), -- New, not in RFC 1759
+ tenThousandthsOfInches(3), -- .0001
+ micrometers(4),
+ sheets(8),
+ feet(16),
+ meters(17),
+ -- Values for Finisher MIB
+ items(18), -- New, not in RFC 1759
+ percent(19) -- New, not in RFC 1759
+ }
+
+CapacityUnit ::= TEXTUAL-CONVENTION
+ -- Replaced by PrtCapacityUnitTC.
+ STATUS deprecated
+ DESCRIPTION
+ "Units of measure for media capacity."
+
+
+
+Bergman, et al. Standards Track [Page 59]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ SYNTAX INTEGER {
+ tenThousandthsOfInches(3), -- .0001
+ micrometers(4),
+ sheets(8),
+ feet(16),
+ meters(17)
+ }
+
+PrtPrintOrientationTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtInterpreterDefaultOrientation in
+ -- RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "A generic representation for printing orientation on a
+ 'page'."
+ SYNTAX INTEGER {
+ other(1),
+ portrait(3),
+ landscape(4)
+ }
+
+PrtSubUnitStatusTC ::= TEXTUAL-CONVENTION
+ -- Replaces SubUnitStatus in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "Status of a printer sub-unit.
+
+ The SubUnitStatus is an integer that is the sum of 5 distinct
+ values, Availability, Non-Critical, Critical, On-line, and
+ Transitioning. These values are:
+
+ Availability Value
+
+ Available and Idle 0 0000'b
+ Available and Standby 2 0010'b
+ Available and Active 4 0100'b
+ Available and Busy 6 0110'b
+ Unavailable and OnRequest 1 0001'b
+ Unavailable because Broken 3 0011'b
+ Unknown 5 0101'b
+
+ Non-Critical
+ No Non-Critical Alerts 0 0000'b
+ Non-Critical Alerts 8 1000'b
+
+ Critical
+
+ No Critical Alerts 0 0000'b
+
+
+
+Bergman, et al. Standards Track [Page 60]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ Critical Alerts 16 1 0000'b
+
+ On-Line
+
+ State is On-Line 0 0000'b
+ State is Off-Line 32 10 0000'b
+
+ Transitioning
+
+ At intended state 0 0000'b
+ Transitioning to intended state 64 100 0000'b"
+
+ SYNTAX INTEGER (0..126)
+
+SubUnitStatus ::= TEXTUAL-CONVENTION
+ -- Replaced by PrtSubUnitStatusTC.
+ STATUS deprecated
+ DESCRIPTION
+ "Status of a printer sub-unit.
+
+ The SubUnitStatus is an integer that is the sum of 5 distinct
+ values, Availability, Non-Critical, Critical, On-line, and
+ Transitioning. These values are:
+
+ Availability Value
+ Available and Idle 0 0000'b
+ Available and Standby 2 0010'b
+ Available and Active 4 0100'b
+ Available and Busy 6 0110'b
+ Unavailable and OnRequest 1 0001'b
+ Unavailable because Broken 3 0011'b
+ Unknown 5 0101'b
+
+ Non-Critical
+ No Non-Critical Alerts 0 0000'b
+ Non-Critical Alerts 8 1000'b
+
+ Critical
+
+ No Critical Alerts 0 0000'b
+ Critical Alerts 16 1 0000'b
+
+ On-Line
+
+ State is On-Line 0 0000'b
+ State is Off-Line 32 10 0000'b
+
+ Transitioning
+
+
+
+Bergman, et al. Standards Track [Page 61]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ At intended state 0 0000'b
+ Transitioning to intended state 64 100 0000'b"
+
+ SYNTAX INTEGER (0..126)
+
+PresentOnOff ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Presence and configuration of a device or feature."
+ SYNTAX INTEGER {
+ other(1),
+ on(3),
+ off(4),
+ notPresent(5)
+ }
+
+PrtLocalizedDescriptionStringTC ::= TEXTUAL-CONVENTION
+ -- This TC did not appear in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "An object MUST use this TEXTUAL-CONVENTION when its
+ 'charset' is controlled by the value of
+ prtGeneralCurrentLocalization."
+ SYNTAX OCTET STRING (SIZE(0..255))
+
+PrtConsoleDescriptionStringTC ::= TEXTUAL-CONVENTION
+ -- This TC did not appear in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "An object MUST use this TEXTUAL-CONVENTION when its
+ 'charset' is controlled by the value of
+ prtConsoleLocalization."
+ SYNTAX OCTET STRING (SIZE(0..255))
+
+CodedCharSet ::= TEXTUAL-CONVENTION
+
+ -- Replaced by IANACharset TEXTUAL-CONVENTION in IANA Charset MIB.
+ STATUS deprecated
+ DESCRIPTION
+ "The original description clause from RFC 1759 [RFC1759] was
+ technically inaccurate and therefore has been deleted."
+ SYNTAX INTEGER {
+ other(1) -- used if the designated coded
+ -- character set is not currently in
+ -- the enumeration
+}
+
+--
+
+
+
+Bergman, et al. Standards Track [Page 62]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+-- Channel Group TEXTUAL-CONVENTIONs
+--
+
+PrtChannelStateTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtChannelState in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The state of this print job delivery channel. The value
+ determines whether print data is allowed through this channel."
+ SYNTAX INTEGER {
+ other(1),
+ printDataAccepted(3),
+ noDataAccepted(4)
+ }
+
+--
+-- Input/Output Group TEXTUAL-CONVENTIONs
+--
+
+PrtOutputStackingOrderTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtOutputStackingOrder in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The current state of the stacking order for the associated
+ output sub-unit. 'firstToLast' means that as pages are output,
+ the front of the next page is placed against the back of the
+ previous page. 'lastToFirst' means that as pages are output,
+ the back of the next page is placed against the front of the
+ previous page."
+ SYNTAX INTEGER {
+ unknown(2),
+ firstToLast(3),
+ lastToFirst(4)
+ }
+
+PrtOutputPageDeliveryOrientationTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtOutputPageDeliveryOrientation
+ -- in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The reading surface that will be 'up' when pages are delivered
+ to the associated output sub-unit. Values are Face-Up and Face
+ Down (Note: interpretation of these values is, in general,
+ context-dependent based on locale; presentation of these values
+ to an end-user should be normalized to the expectations of the
+ user."
+ SYNTAX INTEGER {
+ faceUp(3),
+
+
+
+Bergman, et al. Standards Track [Page 63]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ faceDown(4)
+ }
+
+--
+-- Marker Group TEXTUAL-CONVENTIONs
+--
+
+PrtMarkerCounterUnitTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtMarkerCounterUnit in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The unit that will be used by the printer when reporting
+ counter values for this marking sub-unit. The
+ time units of measure are provided for a device like a
+ strip recorder that does not or cannot track the physical
+ dimensions of the media and does not use characters,
+ lines or sheets."
+
+ SYNTAX INTEGER {
+ tenThousandthsOfInches(3), -- .0001
+ micrometers(4),
+ characters(5),
+ lines(6),
+ impressions(7),
+ sheets(8),
+ dotRow(9),
+ hours(11),
+ feet(16),
+ meters(17)
+ }
+
+PrtMarkerSuppliesSupplyUnitTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtMarkerSuppliesSupplyUnit
+ -- in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "Unit of this marker supply container/receptacle."
+ SYNTAX INTEGER {
+ other(1), -- New, not in RFC 1759
+ unknown(2), -- New, not in RFC 1759
+ tenThousandthsOfInches(3), -- .0001
+ micrometers(4),
+ impressions(7), -- New, not in RFC 1759
+ sheets(8), -- New, not in RFC 1759
+ hours(11), -- New, not in RFC 1759
+ thousandthsOfOunces(12),
+ tenthsOfGrams(13),
+ hundrethsOfFluidOunces(14),
+
+
+
+Bergman, et al. Standards Track [Page 64]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ tenthsOfMilliliters(15),
+ feet(16), -- New, not in RFC 1759
+ meters(17), -- New, not in RFC 1759
+ -- Values for Finisher MIB
+ items(18), -- e.g., #staples. New, not in RFC 1759
+ percent(19) -- New, not in RFC 1759
+ }
+
+PrtMarkerSuppliesClassTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtMarkerSuppliesClass in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "Indicates whether this supply entity represents a supply
+ that is consumed or a receptacle that is filled."
+ SYNTAX INTEGER {
+ other(1),
+ supplyThatIsConsumed(3),
+ receptacleThatIsFilled(4)
+ }
+
+PrtMarkerColorantRoleTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtMarkerColorantRole in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The role played by this colorant."
+ SYNTAX INTEGER { -- Colorant Role
+ other(1),
+ process(3),
+ spot(4)
+ }
+
+PrtMarkerAddressabilityUnitTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtMarkerAddressabilityUnit
+ -- in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The unit of measure of distances, as applied to the marker's
+ resolution."
+ SYNTAX INTEGER {
+ tenThousandthsOfInches(3), -- .0001
+ micrometers(4)
+ }
+
+--
+-- Media Path TEXTUAL-CONVENTIONs
+--
+
+PrtMediaPathMaxSpeedPrintUnitTC ::= TEXTUAL-CONVENTION
+
+
+
+Bergman, et al. Standards Track [Page 65]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ -- This TC was extracted from prtMediaPathMaxSpeedPrintUnit
+ -- in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The unit of measure used in specifying the speed of all
+ media paths in the printer."
+ SYNTAX INTEGER {
+ tenThousandthsOfInchesPerHour(3),-- .0001/hour
+ micrometersPerHour(4),
+ charactersPerHour(5),
+ linesPerHour(6),
+ impressionsPerHour(7),
+ sheetsPerHour(8),
+ dotRowPerHour(9),
+ feetPerHour(16),
+ metersPerHour(17)
+ }
+
+--
+-- Interpreter Group TEXTUAL-CONVENTIONs
+--
+
+PrtInterpreterTwoWayTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtInterpreterTwoWay in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "Indicates whether or not this interpreter returns information
+ back to the host."
+ SYNTAX INTEGER {
+ yes(3),
+ no(4)
+ }
+
+--
+-- Alert Group TEXTUAL-CONVENTIONs
+--
+
+PrtAlertSeverityLevelTC ::= TEXTUAL-CONVENTION
+ -- This TC was extracted from prtAlertSeverityLevel in RFC 1759.
+ STATUS current
+ DESCRIPTION
+ "The level of severity of this alert table entry. The printer
+ determines the severity level assigned to each entry in the
+ table. A critical alert is binary by nature and definition. A
+ warning is defined to be a non-critical alert. The original and
+ most common warning is unary. The binary warning was added later
+ and given a more distinguished name."
+ SYNTAX INTEGER {
+
+
+
+Bergman, et al. Standards Track [Page 66]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ other(1),
+ critical(3),
+ warning(4),
+ warningBinaryChangeEvent(5) -- New, not in RFC 1759
+ }
+
+-- The General Printer Group
+--
+-- The general printer sub-unit is responsible for the overall
+-- control and status of the printer. There is exactly one
+-- general printer sub-unit in a printer.
+
+prtGeneral OBJECT IDENTIFIER ::= { printmib 5 }
+
+prtGeneralTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtGeneralEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table of general information per printer.
+ Objects in this table are defined in various
+ places in the MIB, nearby the groups to
+ which they apply. They are all defined
+ here to minimize the number of tables that would
+ otherwise need to exist."
+ ::= { prtGeneral 1 }
+
+prtGeneralEntry OBJECT-TYPE
+ SYNTAX PrtGeneralEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry exists in this table for each device entry in the
+ host resources MIB device table with a device type of
+ 'printer'.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrDeviceIndex }
+ ::= { prtGeneralTable 1 }
+
+PrtGeneralEntry ::= SEQUENCE {
+ -- Note that not all of the objects in this sequence are in
+ -- the general printer group. The group to which an
+ -- object belongs is tagged with a label "General", "Input"
+ -- "Output", etc. after each entry in the following sequence.
+ --
+ prtGeneralConfigChanges Counter32, -- General
+
+
+
+Bergman, et al. Standards Track [Page 67]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ prtGeneralCurrentLocalization Integer32, -- General
+ prtGeneralReset PrtGeneralResetTC,
+ -- General
+ prtGeneralCurrentOperator OCTET STRING,
+ -- Responsible Party
+ prtGeneralServicePerson OCTET STRING,
+ -- Responsible Party
+ prtInputDefaultIndex Integer32, -- Input
+ prtOutputDefaultIndex Integer32, -- Output
+ prtMarkerDefaultIndex Integer32, -- Marker
+ prtMediaPathDefaultIndex Integer32, -- Media Path
+ prtConsoleLocalization Integer32, -- Console
+ prtConsoleNumberOfDisplayLines Integer32, -- Console
+ prtConsoleNumberOfDisplayChars Integer32, -- Console
+ prtConsoleDisable PrtConsoleDisableTC,
+ -- Console,
+ prtAuxiliarySheetStartupPage PresentOnOff,
+ -- AuxiliarySheet
+ prtAuxiliarySheetBannerPage PresentOnOff,
+ -- AuxiliarySheet
+ prtGeneralPrinterName OCTET STRING,
+ -- General V2
+ prtGeneralSerialNumber OCTET STRING,
+ -- General V2
+ prtAlertCriticalEvents Counter32, -- Alert V2
+ prtAlertAllEvents Counter32 -- Alert V2
+ }
+
+prtGeneralConfigChanges OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Counts configuration changes within the printer. A
+ configuration change is defined to be an action that results in
+ a change to any MIB object other than those that reflect status
+ or level, or those that act as counters or gauges. In addition,
+ any action that results in a row being added or deleted from
+ any table in the Printer MIB is considered a configuration
+ change. Such changes will often affect the capability of the
+ printer to service certain types of print jobs. Management
+ applications may cache infrequently changed configuration
+ information about sub units within the printer. This object
+ should be incremented whenever the agent wishes to notify
+ management applications that any cached configuration
+ information for this device is to be considered 'stale'. At
+ this point, the management application should flush any
+ configuration information cached about this device and fetch
+
+
+
+Bergman, et al. Standards Track [Page 68]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ new configuration information.
+
+ The following are examples of actions that would cause the
+ prtGeneralConfigChanges object to be incremented:
+
+ - Adding an output bin
+ - Changing the media in a sensing input tray
+ - Changing the value of prtInputMediaType
+
+ Note that the prtGeneralConfigChanges counter would not be
+ incremented when an input tray is temporarily removed to load
+ additional paper or when the level of an input device changes.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+
+ ::= { prtGeneralEntry 1 }
+
+prtGeneralCurrentLocalization OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of the prtLocalizationIndex corresponding to the
+ current language, country, and character set to be used for
+ localized string values that are identified as being dependent
+ on the value of this object. Note that this object does not
+ apply to localized strings in the prtConsole group or to any
+ object that is not explicitly identified as being localized
+ according to prtGeneralCurrentLocalization. When an object's
+ 'charset' is controlled by the value of
+ prtGeneralCurrentLocalization, it MUST specify
+ PrtLocalizedDescriptionStringTC as its syntax.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtGeneralEntry 2 }
+
+prtGeneralReset OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly defined
+ -- by this object.
+ SYNTAX PrtGeneralResetTC
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Setting this value to 'powerCycleReset', 'resetToNVRAM', or
+ 'resetToFactoryDefaults' will result in the resetting of the
+ printer. When read, this object will always have the value
+
+
+
+Bergman, et al. Standards Track [Page 69]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ 'notResetting(3)', and a SET of the value 'notResetting' shall
+ have no effect on the printer. Some of the defined values are
+ optional. However, every implementation must support at least
+ the values 'notResetting' and 'resetToNVRAM'."
+ ::= { prtGeneralEntry 3 }
+
+-- The Responsible Party group
+
+prtGeneralCurrentOperator OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..127))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The name of the person who is responsible for operating
+ this printer. It is suggested that this string include
+ information that would enable other humans to reach the
+ operator, such as a phone number. As a convention to
+ facilitate automatic notification of the operator by the
+ agent or network management station, the phone number,
+ fax number or email address should be indicated by the
+ URL schemes 'tel:', 'fax:' and 'mailto:', respectively.
+ If either the phone, fax, or email information is not
+ available, then a line should not be included for this
+ information.
+
+ NOTE: For interoperability purposes, it is advisable to
+ use email addresses formatted according to [RFC2822]
+ requirements.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtGeneralEntry 4 }
+
+prtGeneralServicePerson OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..127))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The name of the person responsible for servicing this
+ printer. It is suggested that this string include
+ information that would enable other humans to reach the
+ service person, such as a phone number. As a convention
+ to facilitate automatic notification of the operator by
+ the agent or network management station, the phone
+ number, fax number or email address should be indicated
+ by the URL schemes 'tel:', 'fax:' and 'mailto:',
+ respectively. If either the phone, fax, or email
+ information is not available, then a line should not
+
+
+
+Bergman, et al. Standards Track [Page 70]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ be included for this information.
+
+ NOTE: For interoperability purposes, it is advisable to use
+ email addresses formatted per [RFC2822] requirements.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+
+ ::= { prtGeneralEntry 5 }
+
+-- Default indexes section
+--
+-- The following four objects are used to specify the indexes of
+-- certain subunits used as defaults during the printing process.
+
+prtInputDefaultIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of prtInputIndex corresponding to the default input
+ sub-unit: that is, this object selects the default source of
+ input media."
+::= { prtGeneralEntry 6 }
+
+prtOutputDefaultIndex OBJECT-TYPE
+ -- A range has been added to the SYNTAX clause that was not in
+ -- RFC 1759. Although this violates SNMP compatibility rules,
+ -- it provides a more reasonable guide for SNMP managers.
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of prtOutputIndex corresponding to the default
+ output sub-unit; that is, this object selects the default
+ output destination."
+::= { prtGeneralEntry 7 }
+
+prtMarkerDefaultIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of prtMarkerIndex corresponding to the
+ default marker sub-unit; that is, this object selects the
+ default marker."
+ ::= { prtGeneralEntry 8 }
+
+
+
+
+Bergman, et al. Standards Track [Page 71]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+prtMediaPathDefaultIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of prtMediaPathIndex corresponding to
+ the default media path; that is, the selection of the
+ default media path."
+ ::= { prtGeneralEntry 9 }
+
+-- Console general section
+--
+-- The following four objects describe overall parameters of the
+-- printer console subsystem.
+
+prtConsoleLocalization OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of the prtLocalizationIndex corresponding to
+ the language, country, and character set to be used for the
+ console. This localization applies both to the actual display
+ on the console as well as the encoding of these console objects
+ in management operations. When an object's 'charset' is
+ controlled by the value of prtConsoleLocalization, it MUST
+ specify PrtConsoleDescriptionStringTC as its syntax.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtGeneralEntry 10 }
+
+prtConsoleNumberOfDisplayLines OBJECT-TYPE
+ SYNTAX Integer32 (0..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of lines on the printer's physical
+ display. This value is 0 if there are no lines on the
+ physical display or if there is no physical display"
+ ::= { prtGeneralEntry 11 }
+
+prtConsoleNumberOfDisplayChars OBJECT-TYPE
+ SYNTAX Integer32 (0..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of characters per line displayed on the physical
+
+
+
+Bergman, et al. Standards Track [Page 72]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ display. This value is 0 if there are no lines on the physical
+ display or if there is no physical display"
+ ::= { prtGeneralEntry 12 }
+
+prtConsoleDisable OBJECT-TYPE
+ -- In RFC 1759, the enumeration values were implicitly defined
+ -- by this object.
+ SYNTAX PrtConsoleDisableTC
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This value indicates how input is (or is not) accepted from
+ the operator console.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtGeneralEntry 13 }
+
+-- The Auxiliary Sheet Group
+--
+-- The auxiliary sheet group allows the administrator to control
+-- the production of auxiliary sheets by the printer. This group
+-- contains only the "prtAuxiliarySheetStartupPage" and
+-- "prtAuxiliarySheetBannerPage" objects.
+
+prtAuxiliarySheetStartupPage OBJECT-TYPE
+ SYNTAX PresentOnOff
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Used to enable or disable printing a startup page. If enabled,
+ a startup page will be printed shortly after power-up, when the
+ device is ready. Typical startup pages include test patterns
+ and/or printer configuration information."
+ ::= { prtGeneralEntry 14 }
+
+prtAuxiliarySheetBannerPage OBJECT-TYPE
+ SYNTAX PresentOnOff
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Used to enable or disable printing banner pages at the
+ beginning of jobs. This is a master switch which applies to all
+ jobs, regardless of interpreter."
+ ::= { prtGeneralEntry 15 }
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 73]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+-- Administrative section (The General V2 Group)
+--
+-- The following two objects are used to specify administrative
+-- information assigned to the printer.
+
+prtGeneralPrinterName OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..127))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "An administrator-specified name for this printer. Depending
+ upon implementation of this printer, the value of this object
+ may or may not be same as the value for the MIB-II 'SysName'
+ object."
+ ::= { prtGeneralEntry 16 }
+
+prtGeneralSerialNumber OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "A recorded serial number for this device that indexes some
+ type device catalog or inventory. This value is usually set by
+ the device manufacturer but the MIB supports the option of
+ writing for this object for site-specific administration of
+ device inventory or tracking."
+ ::= { prtGeneralEntry 17 }
+
+-- General alert table section (Alert Table V2 Group)
+--
+-- The following two objects are used to specify counters
+-- associated with the Alert Table.
+
+prtAlertCriticalEvents OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A running counter of the number of critical alert events that
+ have been recorded in the alert table. The value of this object
+ is RESET in the event of a power cycle operation (i.e., the
+ value is not persistent."
+ ::= { prtGeneralEntry 18 }
+
+prtAlertAllEvents OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+
+
+
+Bergman, et al. Standards Track [Page 74]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ DESCRIPTION
+ "A running counter of the total number of alert event entries
+ (critical and non-critical) that have been recorded in the
+ alert table"
+ ::= { prtGeneralEntry 19 }
+
+-- The Cover Table
+--
+-- The cover portion of the General print sub-unit describes the
+-- covers and interlocks of the printer. The Cover Table has an
+-- entry for each cover and interlock.
+
+prtCover OBJECT IDENTIFIER ::= { printmib 6 }
+
+prtCoverTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtCoverEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table of the covers and interlocks of the printer."
+ ::= { prtCover 1 }
+
+prtCoverEntry OBJECT-TYPE
+ SYNTAX PrtCoverEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Information about a cover or interlock.
+ Entries may exist in the table for each device
+ index with a device type of 'printer'.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrDeviceIndex, prtCoverIndex }
+ ::= { prtCoverTable 1 }
+
+PrtCoverEntry ::= SEQUENCE {
+ prtCoverIndex Integer32,
+ prtCoverDescription PrtLocalizedDescriptionStringTC,
+ prtCoverStatus PrtCoverStatusTC
+ }
+
+prtCoverIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value used by the printer to identify this Cover sub
+
+
+
+Bergman, et al. Standards Track [Page 75]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ unit. Although these values may change due to a major
+ reconfiguration of the device (e.g., the addition of new cover
+ sub-units to the printer), values SHOULD remain stable across
+ successive printer power cycles.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtCoverEntry 1 }
+
+prtCoverDescription OBJECT-TYPE
+ -- In RFC 1759, the SYNTAX was OCTET STRING. This has been changed
+ -- to a TC to better support localization of the object.
+ SYNTAX PrtLocalizedDescriptionStringTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The manufacturer provided cover sub-mechanism name in the
+ localization specified by prtGeneralCurrentLocalization."
+ ::= { prtCoverEntry 2 }
+
+prtCoverStatus OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly defined
+ -- by this object and are now defined in the IANA-PRINTER-MIB. The
+ -- new TC has defined "coverOpen" and "coverClosed" to replace
+ -- "doorOpen" and "doorClosed" in RFC 1759. A name change is not
+ -- formally allowed per SMI rules, but was agreed to by the WG group
+ -- since a door has a more restrictive meaning than a cover and
+ -- Cover group is intended to support doors as a subset of covers.
+
+ SYNTAX PrtCoverStatusTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The status of this cover sub-unit."
+ ::= { prtCoverEntry 3 }
+
+-- The Localization Table
+--
+-- The localization portion of the General printer sub-unit is
+-- responsible for identifying the natural language, country, and
+-- character set in which character strings are expressed. There
+-- may be one or more localizations supported per printer. The
+-- available localizations are represented by the Localization
+-- table.
+
+prtLocalization OBJECT IDENTIFIER ::= { printmib 7 }
+
+prtLocalizationTable OBJECT-TYPE
+
+
+
+Bergman, et al. Standards Track [Page 76]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ SYNTAX SEQUENCE OF PrtLocalizationEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The available localizations in this printer."
+ ::= { prtLocalization 1 }
+
+prtLocalizationEntry OBJECT-TYPE
+ SYNTAX PrtLocalizationEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A description of a localization.
+ Entries may exist in the table for each device
+ index with a device type of 'printer'.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrDeviceIndex, prtLocalizationIndex }
+ ::= { prtLocalizationTable 1 }
+
+PrtLocalizationEntry ::= SEQUENCE {
+ prtLocalizationIndex Integer32,
+ prtLocalizationLanguage OCTET STRING,
+ prtLocalizationCountry OCTET STRING,
+ prtLocalizationCharacterSet IANACharset
+ }
+
+prtLocalizationIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value used by the printer to identify this
+ localization entry. Although these values may change due to a
+ major reconfiguration of the device (e.g., the addition of new
+ localization data to the printer), values SHOULD remain
+ stable across successive printer power cycles.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtLocalizationEntry 1 }
+
+prtLocalizationLanguage OBJECT-TYPE
+ -- Note: The size is fixed, was incorrectly 0..2 in RFC 1759.
+ SYNTAX OCTET STRING (SIZE(2))
+ MAX-ACCESS read-only
+ STATUS current
+
+
+
+Bergman, et al. Standards Track [Page 77]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ DESCRIPTION
+ "A two character language code from ISO 639. Examples en,
+ es, fr, de. NOTE: These examples were shown as upper case in
+ RFC 1759 and are now shown as lower case to agree with ISO 639."
+ ::= { prtLocalizationEntry 2 }
+
+prtLocalizationCountry OBJECT-TYPE
+ -- Note: The size is fixed, was incorrectly 0..2 in RFC 1759.
+ SYNTAX OCTET STRING (SIZE(2))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A two character country code from ISO 3166, a blank string
+ (two space characters) shall indicate that the country is not
+ defined. Examples: US, GB, FR, DE, ..."
+ ::= { prtLocalizationEntry 3 }
+
+prtLocalizationCharacterSet OBJECT-TYPE
+ SYNTAX IANACharset
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The coded character set used for this localization."
+ ::= { prtLocalizationEntry 4 }
+
+-- The System Resources Tables
+--
+-- The Printer MIB makes use of the Host Resources MIB to
+-- define system resources by referencing the storage
+-- and device groups of the print group.
+
+prtStorageRefTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtStorageRefEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table defines which printer, amongst multiple printers
+ serviced by one agent, owns which storage units.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtGeneral 2 }
+
+prtStorageRefEntry OBJECT-TYPE
+ SYNTAX PrtStorageRefEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+
+
+
+Bergman, et al. Standards Track [Page 78]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ "This table will have an entry for each entry in the Host
+ Resources MIB storage table that represents storage associated
+ with a printer managed by this agent.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrStorageIndex, prtStorageRefSeqNumber }
+ ::= { prtStorageRefTable 1 }
+
+PrtStorageRefEntry ::= SEQUENCE {
+ prtStorageRefSeqNumber Integer32,
+ prtStorageRefIndex Integer32
+ }
+
+prtStorageRefSeqNumber OBJECT-TYPE
+ -- NOTE: The range has been changed from RFC 1759, which allowed a
+ -- minumum value of zero. This was incorrect, since zero is not a
+ -- valid index.
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This value will be unique amongst all entries with a common
+ value of hrStorageIndex. This object allows a storage entry to
+ point to the multiple printer devices with which it is
+ associated."
+ ::= { prtStorageRefEntry 1 }
+
+prtStorageRefIndex OBJECT-TYPE
+ -- NOTE: The range has been changed from RFC 1759 to be compatible
+ -- with the defined range of hrDeviceIndex.
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of the hrDeviceIndex of the printer device that this
+ storageEntry is associated with."
+ ::= { prtStorageRefEntry 2 }
+
+prtDeviceRefTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtDeviceRefEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table defines which printer, amongst multiple printers
+ serviced by one agent, is associated with which devices.
+
+ NOTE: The above description has been modified from RFC 1759
+
+
+
+Bergman, et al. Standards Track [Page 79]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ for clarification."
+ ::= { prtGeneral 3 }
+
+prtDeviceRefEntry OBJECT-TYPE
+ SYNTAX PrtDeviceRefEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table will have an entry for each entry in the Host
+ Resources MIB device table that represents a device associated
+ with a printer managed by this agent.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrDeviceIndex, prtDeviceRefSeqNumber }
+ ::= { prtDeviceRefTable 1 }
+
+PrtDeviceRefEntry ::= SEQUENCE {
+ prtDeviceRefSeqNumber Integer32,
+ prtDeviceRefIndex Integer32
+ }
+
+prtDeviceRefSeqNumber OBJECT-TYPE
+ -- NOTE: The range has been changed from RFC 1759, which allowed a
+ -- minumum value of zero. This was incorrect, since zero is not a
+ -- valid index.
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This value will be unique amongst all entries with a common
+ value of hrDeviceIndex. This object allows a device entry to
+ point to the multiple printer devices with which it is
+ associated."
+ ::= { prtDeviceRefEntry 1 }
+
+prtDeviceRefIndex OBJECT-TYPE
+ -- NOTE: The range has been changed from RFC 1759 to be compatible
+ -- with the defined range of hrDeviceIndex.
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of the hrDeviceIndex of the printer device that this
+ deviceEntry is associated with."
+ ::= { prtDeviceRefEntry 2 }
+
+
+
+
+
+Bergman, et al. Standards Track [Page 80]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+-- The Input Group
+--
+-- Input sub-units are managed as a tabular, indexed collection
+-- of possible devices capable of providing media for input to
+-- the printing process. Input sub-units typically have a
+-- location, a type, an identifier, a set of constraints on
+-- possible media sizes and potentially other media
+-- characteristics, and may be capable of indicating current
+-- status or capacity.
+
+prtInput OBJECT IDENTIFIER ::= { printmib 8 }
+
+prtInputTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtInputEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table of the devices capable of providing media for input to
+ the printing process."
+ ::= { prtInput 2 }
+
+prtInputEntry OBJECT-TYPE
+ SYNTAX PrtInputEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Attributes of a device capable of providing media for input to
+ the printing process. Entries may exist in the table for each
+ device index with a device type of 'printer'.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrDeviceIndex, prtInputIndex }
+ ::= { prtInputTable 1 }
+
+PrtInputEntry ::= SEQUENCE {
+ prtInputIndex Integer32,
+ prtInputType PrtInputTypeTC,
+ prtInputDimUnit PrtMediaUnitTC,
+ prtInputMediaDimFeedDirDeclared Integer32,
+ prtInputMediaDimXFeedDirDeclared Integer32,
+ prtInputMediaDimFeedDirChosen Integer32,
+ prtInputMediaDimXFeedDirChosen Integer32,
+ prtInputCapacityUnit PrtCapacityUnitTC,
+ prtInputMaxCapacity Integer32,
+ prtInputCurrentLevel Integer32,
+ prtInputStatus PrtSubUnitStatusTC,
+ prtInputMediaName OCTET STRING,
+
+
+
+Bergman, et al. Standards Track [Page 81]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ prtInputName OCTET STRING,
+ prtInputVendorName OCTET STRING,
+ prtInputModel OCTET STRING,
+ prtInputVersion OCTET STRING,
+ prtInputSerialNumber OCTET STRING,
+ prtInputDescription PrtLocalizedDescriptionStringTC,
+ prtInputSecurity PresentOnOff,
+ prtInputMediaWeight Integer32,
+ prtInputMediaType OCTET STRING,
+ prtInputMediaColor OCTET STRING,
+ prtInputMediaFormParts Integer32,
+ prtInputMediaLoadTimeout Integer32,
+ prtInputNextIndex Integer32
+ }
+
+prtInputIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value used by the printer to identify this input
+ sub-unit. Although these values may change due to a major
+ reconfiguration of the device (e.g., the addition of new input
+ sub-units to the printer), values SHOULD remain stable across
+ successive printer power cycles.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtInputEntry 1 }
+
+prtInputType OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtInputTypeTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of technology (discriminated primarily according to
+ feeder mechanism type) employed by the input sub-unit. Note,
+ the Input Class provides for a descriptor field to further
+ qualify the other choice."
+ ::= { prtInputEntry 2 }
+
+prtInputDimUnit OBJECT-TYPE
+ SYNTAX PrtMediaUnitTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+
+
+
+Bergman, et al. Standards Track [Page 82]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ "The unit of measurement for use calculating and relaying
+ dimensional values for this input sub-unit."
+ ::= { prtInputEntry 3 }
+
+prtInputMediaDimFeedDirDeclared OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object provides the value of the declared dimension, in
+ the feed direction, of the media that is (or, if empty, was or
+ will be) in this input sub-unit. The feed direction is the
+ direction in which the media is fed on this sub-unit. This
+ dimension is measured in input sub-unit dimensional units
+ (controlled by prtInputDimUnit, which uses PrtMediaUnitTC). If
+ this input sub-unit can reliably sense this value, the value is
+ sensed by the printer and may not be changed by management
+ requests. Otherwise, the value may be changed. The value (-1)
+ means other and specifically means that this sub-unit places no
+ restriction on this parameter. The value (-2) indicates
+ unknown."
+ ::= { prtInputEntry 4 }
+
+prtInputMediaDimXFeedDirDeclared OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object provides the value of the declared dimension, in
+ the cross feed direction, of the media that is (or, if empty,
+ was or will be) in this input sub-unit. The cross feed
+ direction is ninety degrees relative to the feed direction
+ associated with this sub-unit. This dimension is measured in
+ input sub-unit dimensional units (controlled by
+ prtInputDimUnit,which uses PrtMediaUnitTC). If this input sub-
+ unit can reliably sense this value, the value is sensed by the
+ printer and may not be changed by management requests.
+ Otherwise, the value may be changed. The value (-1) means other
+ and specifically means that this sub-unit places no restriction
+ on this parameter. The value (-2) indicates unknown."
+ ::= { prtInputEntry 5 }
+
+prtInputMediaDimFeedDirChosen OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+
+
+
+Bergman, et al. Standards Track [Page 83]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ STATUS current
+ DESCRIPTION
+ "The printer will act as if media of the chosen dimension (in
+ the feed direction) is present in this input source. Note that
+ this value will be used even if the input tray is empty. Feed
+ dimension measurements are taken relative to the feed direction
+ associated with that sub-unit and are in input sub-unit
+ dimensional units (controlled by prtInputDimUnit, which uses
+ PrtMediaUnitTC). If the printer supports the declared
+ dimension,the granted dimension is the same as the declared
+ dimension. If not, the granted dimension is set to the closest
+ dimension that the printer supports when the declared dimension
+ is set. The value (-1) means other and specifically indicates
+ that this sub-unit places no restriction on this parameter. The
+ value (-2)indicates unknown."
+ ::= { prtInputEntry 6 }
+
+prtInputMediaDimXFeedDirChosen OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The printer will act as if media of the chosen dimension (in
+ the cross feed direction) is present in this input source. Note
+ that this value will be used even if the input tray is empty.
+ The cross feed direction is ninety degrees relative to the feed
+ direction associated with this sub-unit. This dimension is
+ measured in input sub-unit dimensional units (controlled by
+ prtInputDimUnit, which uses PrtMediaUnitTC). If the printer
+ supports the declare dimension, the granted dimension is the
+ same as the declared dimension. If not, the granted dimension
+ is set to the closest dimension that the printer supports when
+ the declared dimension is set. The value (-1) means other and
+ specifically indicates that this sub-unit places no restriction
+ on this parameter. The value (-2) indicates unknown."
+ ::= { prtInputEntry 7 }
+
+prtInputCapacityUnit OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtCapacityUnitTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The unit of measurement for use in calculating and relaying
+ capacity values for this input sub-unit."
+ ::= { prtInputEntry 8 }
+
+
+
+Bergman, et al. Standards Track [Page 84]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+prtInputMaxCapacity OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum capacity of the input sub-unit in input sub-unit
+ capacity units (PrtCapacityUnitTC). There is no convention
+ associated with the media itself so this value reflects claimed
+ capacity. If this input sub-unit can reliably sense this value,
+ the value is sensed by the printer and may not be changed by
+ management requests; otherwise, the value may be written (by a
+ Remote Control Panel or a Management Application). The value
+ (-1) means other and specifically indicates that the sub-unit
+ places no restrictions on this parameter. The value (-2) means
+ unknown."
+ ::= { prtInputEntry 9 }
+
+prtInputCurrentLevel OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-3..2147483647) -- in capacity units
+ -- (PrtCapacityUnitTC).
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The current capacity of the input sub-unit in input sub-unit
+ capacity units (PrtCapacityUnitTC). If this input sub-unit can
+ reliably sense this value, the value is sensed by the printer
+ and may not be changed by management requests; otherwise, the
+ value may be written (by a Remote Control Panel or a Management
+ Application). The value (-1) means other and specifically
+ indicates that the sub-unit places no restrictions on this
+ parameter. The value (-2) means unknown. The value (-3) means
+ that the printer knows that at least one unit remains."
+ ::= { prtInputEntry 10 }
+
+prtInputStatus OBJECT-TYPE
+ SYNTAX PrtSubUnitStatusTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The current status of this input sub-unit."
+ ::= { prtInputEntry 11 }
+
+prtInputMediaName OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..63))
+ MAX-ACCESS read-write
+ STATUS current
+
+
+
+Bergman, et al. Standards Track [Page 85]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ DESCRIPTION
+ "A description of the media contained in this input sub-unit;
+ This description is to be used by a client to format and
+ Localize a string for display to a human operator. This
+ description is not processed by the printer. It is used to
+ provide information not expressible in terms of the other
+ media attributes (e.g., prtInputMediaDimFeedDirChosen,
+ prtInputMediaDimXFeedDirChosen, prtInputMediaWeight,
+ prtInputMediaType)."
+ -- The following reference was not included in RFC 1759.
+ REFERENCE
+ "The PWG Standardized Media Names specification [PWGMEDIA]
+ contains the recommended values for this object. See also
+ RFC 3805 Appendix C,'Media Names', which lists the values
+ Of standardized media names defined in ISO/IEC 10175."
+ ::= { prtInputEntry 12 }
+
+-- INPUT MEASUREMENT
+--
+-- _______ | |
+-- ^ | |
+-- | | | |
+-- | |_ _ _ _ _ _ _ _| _______________ |direction
+-- | | | ^ v
+-- MaxCapacity | Sheets | |
+-- | | left | CurrentLevel
+-- | | in | |
+-- v | tray | v
+-- _______ +_______________+ _______
+
+-- The Extended Input Group
+
+prtInputName OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..63))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The name assigned to this input sub-unit."
+ ::= { prtInputEntry 13 }
+
+prtInputVendorName OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..63))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The vendor name of this input sub-unit."
+ ::= { prtInputEntry 14 }
+
+
+
+
+Bergman, et al. Standards Track [Page 86]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+prtInputModel OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..63))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The model name of this input sub-unit."
+ ::= { prtInputEntry 15 }
+
+prtInputVersion OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..63))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The version of this input sub-unit."
+ ::= { prtInputEntry 16 }
+
+prtInputSerialNumber OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..32))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The serial number assigned to this input sub-unit."
+ ::= { prtInputEntry 17 }
+
+prtInputDescription OBJECT-TYPE
+ -- In RFC 1759, the SYNTAX was OCTET STRING. This has been changed
+ -- to a TC to better support localization of the object.
+ SYNTAX PrtLocalizedDescriptionStringTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A free-form text description of this input sub-unit in the
+ localization specified by prtGeneralCurrentLocalization."
+ ::= { prtInputEntry 18 }
+
+prtInputSecurity OBJECT-TYPE
+ SYNTAX PresentOnOff
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Indicates if this input sub-unit has some security associated
+ with it."
+ ::= { prtInputEntry 19 }
+
+-- The Input Media Group
+--
+-- The Input Media Group supports identification of media
+-- installed or available for use on a printing device.
+
+
+
+Bergman, et al. Standards Track [Page 87]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+-- Medium resources are identified by name, and include a
+-- collection of characteristic attributes that may further be
+-- used for selection and management of them.
+-- The Input Media group consists of a set of optional
+-- "columns" in the Input Table. In this manner, a minimally
+-- conforming implementation may choose to not support reporting
+-- of media resources if it cannot do so.
+
+prtInputMediaWeight OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The weight of the medium associated with this input sub-unit
+ in grams / per meter squared. The value (-2) means unknown."
+ ::= { prtInputEntry 20 }
+
+prtInputMediaType OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..63))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The name of the type of medium associated with this input sub
+ unit. This name need not be processed by the printer; it might
+ simply be displayed to an operator.
+
+ NOTE: The above description has been modified from RFC 1759."
+ -- The following reference was not included in RFC 1759.
+ REFERENCE
+ "The PWG Standardized Media Names specification [PWGMEDIA],
+ section 3 Media Type Names, contains the recommended values for
+ this object. Implementers may add additional string values.
+ The naming conventions in ISO 9070 are recommended in order to
+ avoid potential name clashes."
+ ::= { prtInputEntry 21 }
+
+prtInputMediaColor OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..63))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The name of the color of the medium associated with
+ this input sub-unit using standardized string values.
+
+ NOTE: The above description has been modified from RFC 1759."
+ -- The following reference was not included in RFC 1759.
+ REFERENCE
+
+
+
+Bergman, et al. Standards Track [Page 88]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ "The PWG Standardized Media Names specification [PWGMEDIA],
+ section 4 Media Color Names, contains the recommended values
+ for this object. Implementers may add additional string values.
+ The naming conventions in ISO 9070 are recommended in order to
+ avoid potential name clashes."
+ ::= { prtInputEntry 22 }
+
+prtInputMediaFormParts OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The number of parts associated with the medium
+ associated with this input sub-unit if the medium is a
+ multi-part form. The value (-1) means other and
+ specifically indicates that the device places no
+ restrictions on this parameter. The value (-2) means
+ unknown."
+ ::= { prtInputEntry 23 }
+
+-- The Input Switching Group
+--
+-- The input switching group allows the administrator to set the
+-- input subunit time-out for the printer and to control the
+-- automatic input subunit switching by the printer when an input
+-- subunit becomes empty.
+
+prtInputMediaLoadTimeout OBJECT-TYPE
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "When the printer is not able to print due to a subunit being
+ empty or the requested media must be manually loaded, the
+ printer will wait for the duration (in seconds) specified by
+ this object. Upon expiration of the time-out, the printer will
+ take the action specified by prtInputNextIndex.
+
+ The event which causes the printer to enter the waiting state
+ is product specific. If the printer is not waiting for manually
+ fed media, it may switch from an empty subunit to a different
+ subunit without waiting for the time-out to expire.
+
+ A value of (-1) implies 'other' or 'infinite' which translates
+ to 'wait forever'. The action which causes printing to continue
+ is product specific. A value of (-2) implies 'unknown'."
+ ::= { prtInputEntry 24 }
+
+
+
+Bergman, et al. Standards Track [Page 89]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+prtInputNextIndex OBJECT-TYPE
+ SYNTAX Integer32 (-3..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of prtInputIndex corresponding to the input subunit
+ which will be used when this input subunit is emptied and the
+ time-out specified by prtInputMediaLoadTimeout expires. A value
+ of zero(0) indicates that auto input switching will not occur
+ when this input subunit is emptied. If the time-out specified
+ by prtInputLoadMediaTimeout expires and this value is zero(0),
+ the job will be aborted. A value of (-1) means other. The
+ value (-2)means 'unknown' and specifically indicates that an
+ implementation specific method will determine the next input
+ subunit to use at the time this subunit is emptied and the time
+ out expires. The value(-3) means input switching is not
+ supported for this subunit."
+ ::= { prtInputEntry 25 }
+
+-- The Output Group
+--
+-- Output sub-units are managed as a tabular, indexed collection
+-- of possible devices capable of receiving media delivered from
+-- the printing process. Output sub-units typically have a
+-- location, a type, an identifier, a set of constraints on
+-- possible media sizes and potentially other characteristics,
+-- and may be capable of indicating current status or capacity.
+
+prtOutput OBJECT IDENTIFIER ::= { printmib 9 }
+
+prtOutputTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtOutputEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table of the devices capable of receiving media delivered
+ from the printing process."
+ ::= { prtOutput 2 }
+
+prtOutputEntry OBJECT-TYPE
+ SYNTAX PrtOutputEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Attributes of a device capable of receiving media delivered
+ from the printing process. Entries may exist in the table for
+ each device index with a device type of 'printer'.
+
+
+
+
+Bergman, et al. Standards Track [Page 90]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrDeviceIndex, prtOutputIndex }
+ ::= { prtOutputTable 1 }
+
+PrtOutputEntry ::= SEQUENCE {
+ prtOutputIndex Integer32,
+ prtOutputType PrtOutputTypeTC,
+ prtOutputCapacityUnit PrtCapacityUnitTC,
+ prtOutputMaxCapacity Integer32,
+ prtOutputRemainingCapacity Integer32,
+ prtOutputStatus PrtSubUnitStatusTC,
+ prtOutputName OCTET STRING,
+ prtOutputVendorName OCTET STRING,
+ prtOutputModel OCTET STRING,
+ prtOutputVersion OCTET STRING,
+ prtOutputSerialNumber OCTET STRING,
+ prtOutputDescription PrtLocalizedDescriptionStringTC,
+ prtOutputSecurity PresentOnOff,
+ prtOutputDimUnit PrtMediaUnitTC,
+ prtOutputMaxDimFeedDir Integer32,
+ prtOutputMaxDimXFeedDir Integer32,
+ prtOutputMinDimFeedDir Integer32,
+ prtOutputMinDimXFeedDir Integer32,
+ prtOutputStackingOrder PrtOutputStackingOrderTC,
+ prtOutputPageDeliveryOrientation
+ PrtOutputPageDeliveryOrientationTC,
+ prtOutputBursting PresentOnOff,
+ prtOutputDecollating PresentOnOff,
+ prtOutputPageCollated PresentOnOff,
+ prtOutputOffsetStacking PresentOnOff
+ }
+
+prtOutputIndex OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value used by this printer to identify this output
+ sub-unit. Although these values may change due to a major
+ reconfiguration of the sub-unit (e.g., the addition of new
+ output devices to the printer), values SHOULD remain stable
+ across successive printer power cycles.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtOutputEntry 1 }
+
+
+
+Bergman, et al. Standards Track [Page 91]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+prtOutputType OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly defined
+ -- by this object.
+ SYNTAX PrtOutputTypeTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of technology supported by this output sub-unit."
+ ::= { prtOutputEntry 2 }
+
+prtOutputCapacityUnit OBJECT-TYPE
+ SYNTAX PrtCapacityUnitTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The unit of measurement for use in calculating and relaying
+ capacity values for this output sub-unit."
+ ::= { prtOutputEntry 3 }
+
+prtOutputMaxCapacity OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum capacity of this output sub-unit in output sub-
+ unit capacity units (PrtCapacityUnitTC). There is no convention
+ associated with the media itself so this value essentially
+ reflects claimed capacity. If this output sub-unit can reliably
+ sense this value, the value is sensed by the printer and may
+ not be changed by management requests; otherwise, the value may
+ be written (by a Remote Control Panel or a Management
+ Application). The value (-1) means other and specifically
+ indicates that the sub-unit places no restrictions on this
+ parameter. The value (-2) means unknown."
+ ::= { prtOutputEntry 4 }
+
+prtOutputRemainingCapacity OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-3..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The remaining capacity of the possible output sub-unit
+ capacity in output sub-unit capacity units
+ (PrtCapacityUnitTC)of this output sub-unit. If this output sub-
+ unit can reliably sense this value, the value is sensed by the
+ printer and may not be modified by management requests;
+
+
+
+Bergman, et al. Standards Track [Page 92]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ otherwise, the value may be written (by a Remote Control Panel
+ or a Management Application). The value (-1) means other and
+ specifically indicates that the sub-unit places no restrictions
+ on this parameter. The value (-2) means unknown. The value
+ (-3) means that the printer knows that there remains capacity
+ for at least one unit."
+ ::= { prtOutputEntry 5 }
+
+prtOutputStatus OBJECT-TYPE
+ SYNTAX PrtSubUnitStatusTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The current status of this output sub-unit."
+ ::= { prtOutputEntry 6 }
+
+-- OUTPUT MEASUREMENT
+--
+-- _______ | | ________
+-- ^ | | ^
+-- | | | |
+-- | | |RemainingCapacity
+-- MaxCapacity| | |
+-- | | | v ^
+-- | |_ _ _ _ _ _ _ _ | _______________ |direction
+-- | | Sheets | |
+-- | | in |
+-- v | Output |
+-- _______ +________________+
+
+-- The Extended Output Group
+
+prtOutputName OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..63))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The name assigned to this output sub-unit."
+ ::= { prtOutputEntry 7 }
+
+prtOutputVendorName OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..63))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The vendor name of this output sub-unit."
+ ::= { prtOutputEntry 8 }
+
+
+
+
+Bergman, et al. Standards Track [Page 93]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+prtOutputModel OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..63))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The model name assigned to this output sub-unit.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtOutputEntry 9 }
+
+prtOutputVersion OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..63))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The version of this output sub-unit."
+ ::= { prtOutputEntry 10 }
+
+prtOutputSerialNumber OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..63))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The serial number assigned to this output sub-unit."
+ ::= { prtOutputEntry 11 }
+
+prtOutputDescription OBJECT-TYPE
+ -- In RFC 1759, the SYNTAX was OCTET STRING. This has been changed
+ -- to a TC to better support localization of the object.
+ SYNTAX PrtLocalizedDescriptionStringTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A free-form text description of this output sub-unit in the
+ localization specified by prtGeneralCurrentLocalization."
+ ::= { prtOutputEntry 12 }
+
+prtOutputSecurity OBJECT-TYPE
+ SYNTAX PresentOnOff
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Indicates if this output sub-unit has some security associated
+ with it and if that security is enabled or not."
+ ::= { prtOutputEntry 13 }
+
+
+
+
+
+Bergman, et al. Standards Track [Page 94]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+-- The Output Dimensions Group
+
+prtOutputDimUnit OBJECT-TYPE
+ SYNTAX PrtMediaUnitTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The unit of measurement for use in calculating and relaying
+ dimensional values for this output sub-unit."
+ ::= { prtOutputEntry 14 }
+
+prtOutputMaxDimFeedDir OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum dimensions supported by this output sub-unit
+ for measurements taken parallel relative to the feed
+ direction associated with that sub-unit in output
+ sub-unit dimensional units (controlled by prtOutputDimUnit,
+ which uses PrtMediaUnitTC). If this output sub-unit can
+ reliably sense this value, the value is sensed by the printer
+ and may not be changed with management protocol operations.
+ The value (-1) means other and specifically indicates that the
+ sub-unit places no restrictions on this parameter. The value
+ (-2) means unknown.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification and to explain the purpose of (-1) and (-2)."
+ ::= { prtOutputEntry 15 }
+
+prtOutputMaxDimXFeedDir OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum dimensions supported by this output sub-unit
+ for measurements taken ninety degrees relative to the
+ feed direction associated with that sub-unit in output
+ sub-unit dimensional units (controlled by prtOutputDimUnit,
+ which uses PrtMediaUnitTC). If this output sub-unit can
+ reliably sense this value, the value is sensed by the printer
+ and may not be changed with management protocol operations.
+ The value (-1) means other and specifically indicates that the
+ sub-unit places no restrictions on this parameter. The value
+ (-2) means unknown.
+
+
+
+Bergman, et al. Standards Track [Page 95]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification and to explain the purpose of (-1) and (-2)."
+ ::= { prtOutputEntry 16 }
+
+prtOutputMinDimFeedDir OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The minimum dimensions supported by this output sub-unit
+ for measurements taken parallel relative to the feed
+ direction associated with that sub-unit in output
+ sub-unit dimensional units (controlled by prtOutputDimUnit,
+ which uses PrtMediaUnitTC). If this output sub-unit can
+ reliably sense this value, the value is sensed by the printer
+ and may not be changed with management protocol operations.
+ The value (-1) means other and specifically indicates that the
+ sub-unit places no restrictions on this parameter. The value
+ (-2) means unknown.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification and to explain the purpose of (-1) and (-2)."
+ ::= { prtOutputEntry 17 }
+
+prtOutputMinDimXFeedDir OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The minimum dimensions supported by this output sub-unit
+ for measurements taken ninety degrees relative to the
+ feed direction associated with that sub-unit in output
+ sub-unit dimensional units (controlled by prtOutputDimUnit,
+ which uses PrtMediaUnitTC). If this output sub-unit can
+ reliably sense this value, the value is sensed by the printer
+ and may not be changed with management protocol operations.
+ The value (-1) means other and specifically indicates that the
+ sub-unit places no restrictions on this parameter. The value
+ (-2) means unknown.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification and to explain the purpose of (-1) and (-2)."
+ ::= { prtOutputEntry 18 }
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 96]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+-- The Output Features Group
+
+prtOutputStackingOrder OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtOutputStackingOrderTC
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The current state of the stacking order for the
+ associated output sub-unit. 'FirstToLast' means
+ that as pages are output the front of the next page is
+ placed against the back of the previous page.
+ 'LasttoFirst' means that as pages are output the back
+ of the next page is placed against the front of the
+ previous page."
+ ::= { prtOutputEntry 19 }
+
+prtOutputPageDeliveryOrientation OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtOutputPageDeliveryOrientationTC
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The reading surface that will be 'up' when pages are
+ delivered to the associated output sub-unit. Values are
+ faceUp and faceDown. (Note: interpretation of these
+ values is in general context-dependent based on locale;
+ presentation of these values to an end-user should be
+ normalized to the expectations of the user)."
+ ::= { prtOutputEntry 20 }
+
+prtOutputBursting OBJECT-TYPE
+ SYNTAX PresentOnOff
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object indicates that the outputting sub-unit supports
+ bursting, and if so, whether the feature is enabled. Bursting
+ is the process by which continuous media is separated into
+ individual sheets, typically by bursting along pre-formed
+ perforations."
+ ::= { prtOutputEntry 21 }
+
+prtOutputDecollating OBJECT-TYPE
+ SYNTAX PresentOnOff
+ MAX-ACCESS read-write
+
+
+
+Bergman, et al. Standards Track [Page 97]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ STATUS current
+ DESCRIPTION
+ "This object indicates that the output supports decollating,
+ and if so, whether the feature is enabled. Decollating is the
+ process by which the individual parts within a multi-part form
+ are separated and sorted into separate stacks for each part."
+ ::= { prtOutputEntry 22 }
+
+prtOutputPageCollated OBJECT-TYPE
+ SYNTAX PresentOnOff
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object indicates that the output sub-unit supports page
+ collation, and if so, whether the feature is enabled. See RFC
+ 3805 Appendix A, Glossary Of Terms, for definition of how this
+ document defines collation.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtOutputEntry 23 }
+
+prtOutputOffsetStacking OBJECT-TYPE
+ SYNTAX PresentOnOff
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object indicates that the output supports offset
+ stacking,and if so, whether the feature is enabled. See RFC
+ 3805 Appendix A, Glossary Of Terms, for how Offset Stacking is
+ defined by this document.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtOutputEntry 24 }
+
+-- The Marker Group
+--
+-- A marker is the mechanism that produces marks on the print
+-- media. The marker sub-units and their associated supplies are
+-- represented by the Marker Group in the model. A printer can
+-- contain one or more marking mechanisms. Some examples of
+-- multiple marker sub-units are: a printer
+-- with separate markers for normal and magnetic ink or an
+-- imagesetter that can output to both a proofing device and
+-- final film. Each marking device can have its own set of
+-- characteristics associated with it, such as marking technology
+-- and resolution.
+
+
+
+Bergman, et al. Standards Track [Page 98]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+prtMarker OBJECT IDENTIFIER ::= { printmib 10 }
+
+-- The printable area margins as listed below define an area of
+-- the print media which is guaranteed to be printable for all
+-- combinations of input, media paths, and interpreters for this
+-- marker.
+
+prtMarkerTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtMarkerEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The marker table provides a description of each marker
+ sub-unit contained within the printer.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMarker 2 }
+
+prtMarkerEntry OBJECT-TYPE
+ SYNTAX PrtMarkerEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Entries in this table define the characteristics and status
+ of each marker sub-unit in the printer.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrDeviceIndex, prtMarkerIndex }
+ ::= { prtMarkerTable 1 }
+
+PrtMarkerEntry ::= SEQUENCE {
+ prtMarkerIndex Integer32,
+ prtMarkerMarkTech PrtMarkerMarkTechTC,
+ prtMarkerCounterUnit PrtMarkerCounterUnitTC,
+ prtMarkerLifeCount Counter32,
+ prtMarkerPowerOnCount Counter32,
+ prtMarkerProcessColorants Integer32,
+ prtMarkerSpotColorants Integer32,
+ prtMarkerAddressabilityUnit PrtMarkerAddressabilityUnitTC,
+ prtMarkerAddressabilityFeedDir Integer32,
+ prtMarkerAddressabilityXFeedDir Integer32,
+ prtMarkerNorthMargin Integer32,
+ prtMarkerSouthMargin Integer32,
+ prtMarkerWestMargin Integer32,
+ prtMarkerEastMargin Integer32,
+ prtMarkerStatus PrtSubUnitStatusTC
+
+
+
+Bergman, et al. Standards Track [Page 99]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ }
+
+prtMarkerIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value used by the printer to identify this marking
+ SubUnit. Although these values may change due to a major
+ reconfiguration of the device (e.g., the addition of new marking
+ sub-units to the printer), values SHOULD remain stable across
+ successive printer power cycles.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMarkerEntry 1 }
+
+prtMarkerMarkTech OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtMarkerMarkTechTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of marking technology used for this marking
+ sub-unit."
+ ::= { prtMarkerEntry 2 }
+
+prtMarkerCounterUnit OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtMarkerCounterUnitTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The unit that will be used by the printer when reporting
+ counter values for this marking sub-unit. The time units of
+ measure are provided for a device like a strip recorder that
+ does not or cannot track the physical dimensions of the media
+ and does not use characters, lines or sheets."
+ ::= { prtMarkerEntry 3 }
+
+prtMarkerLifeCount OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The count of the number of units of measure counted during the
+
+
+
+Bergman, et al. Standards Track [Page 100]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ life of printer using units of measure as specified by
+ prtMarkerCounterUnit.
+
+ Note: This object should be implemented as a persistent object
+ with a reliable value throughout the lifetime of the printer."
+ ::= { prtMarkerEntry 4 }
+
+prtMarkerPowerOnCount OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The count of the number of units of measure counted since the
+ equipment was most recently powered on using units of measure
+ as specified by prtMarkerCounterUnit."
+ ::= { prtMarkerEntry 5 }
+
+prtMarkerProcessColorants OBJECT-TYPE
+ SYNTAX Integer32 (0..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of process colors supported by this marker. A
+ process color of 1 implies monochrome. The value of this
+ object and prtMarkerSpotColorants cannot both be 0. The value
+ of prtMarkerProcessColorants must be 0 or greater.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMarkerEntry 6 }
+
+prtMarkerSpotColorants OBJECT-TYPE
+ SYNTAX Integer32 (0..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of spot colors supported by this marker. The value
+ of this object and prtMarkerProcessColorants cannot both be 0.
+ Must be 0 or greater.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMarkerEntry 7 }
+
+prtMarkerAddressabilityUnit OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtMarkerAddressabilityUnitTC
+
+
+
+Bergman, et al. Standards Track [Page 101]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The unit of measure of distances, as applied to the marker's
+ resolution.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMarkerEntry 8 }
+
+prtMarkerAddressabilityFeedDir OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum number of addressable marking positions in the
+ feed direction per 10000 units of measure specified by
+ prtMarkerAddressabilityUnit. A value of (-1) implies 'other'
+ or 'infinite' while a value of (-2) implies 'unknown'.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMarkerEntry 9 }
+
+prtMarkerAddressabilityXFeedDir OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum number of addressable marking positions in the
+ cross feed direction in 10000 units of measure specified by
+ prtMarkerAddressabilityUnit. A value of (-1) implies 'other'
+ or 'infinite' while a value of (-2) implies 'unknown'.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMarkerEntry 10 }
+
+prtMarkerNorthMargin OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The margin, in units identified by prtMarkerAddressabilityUnit,
+ from the leading edge of the medium as the medium flows through
+
+
+
+Bergman, et al. Standards Track [Page 102]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ the marking engine with the side to be imaged facing the
+ observer. The leading edge is the North edge and the other
+ edges are defined by the normal compass layout of directions
+ with the compass facing the observer. Printing within the area
+ bounded by all four margins is guaranteed for all interpreters.
+ The value (-2) means unknown."
+ ::= { prtMarkerEntry 11 }
+
+prtMarkerSouthMargin OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The margin from the South edge (see prtMarkerNorthMargin) of
+ the medium in units identified by prtMarkerAddressabilityUnit.
+ Printing within the area bounded by all four margins is
+ guaranteed for all interpreters. The value (-2) means unknown."
+ ::= { prtMarkerEntry 12 }
+
+prtMarkerWestMargin OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The margin from the West edge (see prtMarkerNorthMargin) of
+ the medium in units identified by prtMarkerAddressabilityUnit.
+ Printing within the area bounded by all four margins is
+ guaranteed for all interpreters. The value (-2) means unknown."
+ ::= { prtMarkerEntry 13 }
+
+prtMarkerEastMargin OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The margin from the East edge (see prtMarkerNorthMargin) of
+ the medium in units identified by prtMarkerAddressabilityUnit.
+ Printing within the area bounded by all four margins is
+ guaranteed for all interpreters. The value (-2) means unknown."
+ ::= { prtMarkerEntry 14 }
+
+prtMarkerStatus OBJECT-TYPE
+ SYNTAX PrtSubUnitStatusTC
+ MAX-ACCESS read-only
+ STATUS current
+
+
+
+Bergman, et al. Standards Track [Page 103]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ DESCRIPTION
+ "The current status of this marker sub-unit."
+ ::= { prtMarkerEntry 15 }
+
+-- The Marker Supplies Group
+
+prtMarkerSupplies OBJECT IDENTIFIER ::= { printmib 11 }
+
+prtMarkerSuppliesTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtMarkerSuppliesEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table of the marker supplies available on this printer."
+ ::= { prtMarkerSupplies 1 }
+
+prtMarkerSuppliesEntry OBJECT-TYPE
+ SYNTAX PrtMarkerSuppliesEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Attributes of a marker supply. Entries may exist in the table
+ for each device index with a device type of 'printer'.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrDeviceIndex, prtMarkerSuppliesIndex }
+ ::= { prtMarkerSuppliesTable 1 }
+PrtMarkerSuppliesEntry ::= SEQUENCE {
+ prtMarkerSuppliesIndex Integer32,
+ prtMarkerSuppliesMarkerIndex Integer32,
+ prtMarkerSuppliesColorantIndex Integer32,
+ prtMarkerSuppliesClass PrtMarkerSuppliesClassTC,
+ prtMarkerSuppliesType PrtMarkerSuppliesTypeTC,
+ prtMarkerSuppliesDescription PrtLocalizedDescriptionStringTC,
+ prtMarkerSuppliesSupplyUnit PrtMarkerSuppliesSupplyUnitTC,
+ prtMarkerSuppliesMaxCapacity Integer32,
+ prtMarkerSuppliesLevel Integer32
+ }
+
+prtMarkerSuppliesIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value used by the printer to identify this marker
+ supply. Although these values may change due to a major
+ reconfiguration of the device (e.g., the addition of new marker
+
+
+
+Bergman, et al. Standards Track [Page 104]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ supplies to the printer), values SHOULD remain stable across
+ successive printer power cycles.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMarkerSuppliesEntry 1 }
+
+prtMarkerSuppliesMarkerIndex OBJECT-TYPE
+ SYNTAX Integer32 (0..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of prtMarkerIndex corresponding to the marking sub
+ unit with which this marker supply sub-unit is associated."
+ ::= { prtMarkerSuppliesEntry 2 }
+
+prtMarkerSuppliesColorantIndex OBJECT-TYPE
+ SYNTAX Integer32 (0..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of prtMarkerColorantIndex corresponding to the
+ colorant with which this marker supply sub-unit is associated.
+ This value shall be 0 if there is no colorant table or if this
+ supply does not depend on a single specified colorant.
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMarkerSuppliesEntry 3 }
+
+prtMarkerSuppliesClass OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtMarkerSuppliesClassTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Indicates whether this supply entity represents a supply that
+ is consumed or a receptacle that is filled.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMarkerSuppliesEntry 4 }
+
+prtMarkerSuppliesType OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtMarkerSuppliesTypeTC
+ MAX-ACCESS read-only
+
+
+
+Bergman, et al. Standards Track [Page 105]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ STATUS current
+ DESCRIPTION
+ "The type of this supply."
+ ::= { prtMarkerSuppliesEntry 5 }
+
+prtMarkerSuppliesDescription OBJECT-TYPE
+ -- In RFC 1759, the SYNTAX was OCTET STRING. This has been changed
+ -- to a TC to better support localization of the object.
+ SYNTAX PrtLocalizedDescriptionStringTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The description of this supply container/receptacle in the
+ localization specified by prtGeneralCurrentLocalization."
+ ::= { prtMarkerSuppliesEntry 6 }
+
+prtMarkerSuppliesSupplyUnit OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtMarkerSuppliesSupplyUnitTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Unit of measure of this marker supply container/receptacle.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMarkerSuppliesEntry 7 }
+
+prtMarkerSuppliesMaxCapacity OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum capacity of this supply container/receptacle
+ expressed in prtMarkerSuppliesSupplyUnit. If this supply
+ container/receptacle can reliably sense this value, the value
+ is reported by the printer and is read-only; otherwise, the
+ value may be written (by a Remote Control Panel or a Management
+ Application). The value (-1) means other and specifically
+ indicates that the sub-unit places no restrictions on this
+ parameter. The value (-2) means unknown."
+ ::= { prtMarkerSuppliesEntry 8 }
+
+prtMarkerSuppliesLevel OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-3..2147483647)
+
+
+
+Bergman, et al. Standards Track [Page 106]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The current level if this supply is a container; the remaining
+ space if this supply is a receptacle. If this supply
+ container/receptacle can reliably sense this value, the value
+ is reported by the printer and is read-only; otherwise, the
+ value may be written (by a Remote Control Panel or a Management
+ Application). The value (-1) means other and specifically
+ indicates that the sub-unit places no restrictions on this
+ parameter. The value (-2) means unknown. A value of (-3) means
+ that the printer knows that there is some supply/remaining
+ space, respectively."
+ ::= { prtMarkerSuppliesEntry 9 }
+
+-- The Marker Colorant Group
+
+prtMarkerColorant OBJECT IDENTIFIER ::= { printmib 12 }
+
+prtMarkerColorantTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtMarkerColorantEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table of all of the colorants available on the printer."
+ ::= { prtMarkerColorant 1 }
+
+prtMarkerColorantEntry OBJECT-TYPE
+ SYNTAX PrtMarkerColorantEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Attributes of a colorant available on the printer. Entries may
+ exist in the table for each device index with a device type of
+ 'printer'.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrDeviceIndex, prtMarkerColorantIndex }
+ ::= { prtMarkerColorantTable 1 }
+
+PrtMarkerColorantEntry ::= SEQUENCE {
+ prtMarkerColorantIndex Integer32,
+ prtMarkerColorantMarkerIndex Integer32,
+ prtMarkerColorantRole PrtMarkerColorantRoleTC,
+ prtMarkerColorantValue OCTET STRING,
+ prtMarkerColorantTonality Integer32
+ }
+
+
+
+Bergman, et al. Standards Track [Page 107]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+prtMarkerColorantIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value used by the printer to identify this colorant.
+ Although these values may change due to a major reconfiguration
+ of the device (e.g., the addition of new colorants to the
+ printer) , values SHOULD remain stable across successive
+ printer power cycles.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMarkerColorantEntry 1 }
+
+prtMarkerColorantMarkerIndex OBJECT-TYPE
+ SYNTAX Integer32 (0..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of prtMarkerIndex corresponding to the marker sub
+ unit with which this colorant entry is associated."
+ ::= { prtMarkerColorantEntry 2 }
+
+prtMarkerColorantRole OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtMarkerColorantRoleTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The role played by this colorant."
+ ::= { prtMarkerColorantEntry 3 }
+
+prtMarkerColorantValue OBJECT-TYPE
+ -- NOTE: The string length range has been increased from RFC 1759.
+ SYNTAX OCTET STRING (SIZE(0..255))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name of the color of this colorant using standardized
+ string names from ISO 10175 (DPA) and ISO 10180 (SPDL) such as:
+ other
+ unknown
+ white
+ red
+ green
+ blue
+
+
+
+Bergman, et al. Standards Track [Page 108]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ cyan
+ magenta
+ yellow
+ black
+ Implementers may add additional string values. The naming
+ conventions in ISO 9070 are recommended in order to avoid
+ potential name clashes"
+ ::= { prtMarkerColorantEntry 4 }
+
+prtMarkerColorantTonality OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The distinct levels of tonality realizable by a marking sub
+ unit when using this colorant. This value does not include the
+ number of levels of tonal difference that an interpreter can
+ obtain by techniques such as half toning. This value must be at
+ least 2."
+ ::= { prtMarkerColorantEntry 5 }
+
+-- The Media Path Group
+--
+-- The media paths encompass the mechanisms in the printer that
+-- move the media through the printer and connect all other media
+-- related sub-units: inputs, outputs, markers and finishers. A
+-- printer contains one or more media paths. These are
+-- represented by the Media Path Group in the model.
+
+prtMediaPath OBJECT IDENTIFIER ::= { printmib 13 }
+
+prtMediaPathTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtMediaPathEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The media path table includes both physical and logical paths
+ within the printer.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMediaPath 4 }
+
+prtMediaPathEntry OBJECT-TYPE
+ SYNTAX PrtMediaPathEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+
+
+
+Bergman, et al. Standards Track [Page 109]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ DESCRIPTION
+ "Entries may exist in the table for each device index with a
+ device type of 'printer' Each entry defines the physical
+ characteristics of and the status of the media path. The data
+ provided indicates the maximum throughput and the media
+ size limitations of these subunits.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrDeviceIndex, prtMediaPathIndex }
+ ::= { prtMediaPathTable 1 }
+
+PrtMediaPathEntry ::= SEQUENCE {
+ prtMediaPathIndex Integer32,
+ prtMediaPathMaxSpeedPrintUnit PrtMediaPathMaxSpeedPrintUnitTC,
+ prtMediaPathMediaSizeUnit PrtMediaUnitTC,
+ prtMediaPathMaxSpeed Integer32,
+ prtMediaPathMaxMediaFeedDir Integer32,
+ prtMediaPathMaxMediaXFeedDir Integer32,
+ prtMediaPathMinMediaFeedDir Integer32,
+ prtMediaPathMinMediaXFeedDir Integer32,
+ prtMediaPathType PrtMediaPathTypeTC,
+ prtMediaPathDescription PrtLocalizedDescriptionStringTC,
+ prtMediaPathStatus PrtSubUnitStatusTC
+ }
+
+prtMediaPathIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value used by the printer to identify this media
+ path. Although these values may change due to a major
+ reconfiguration of the device (e.g., the addition of new media
+ paths to the printer), values SHOULD remain stable across
+ successive printer power cycles.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMediaPathEntry 1 }
+
+prtMediaPathMaxSpeedPrintUnit OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtMediaPathMaxSpeedPrintUnitTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+
+
+
+Bergman, et al. Standards Track [Page 110]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ "The unit of measure used in specifying the speed of all media
+ paths in the printer."
+ ::= { prtMediaPathEntry 2 }
+
+prtMediaPathMediaSizeUnit OBJECT-TYPE
+ SYNTAX PrtMediaUnitTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The units of measure of media size for use in calculating and
+ relaying dimensional values for all media paths in the
+ printer."
+ ::= { prtMediaPathEntry 3 }
+
+prtMediaPathMaxSpeed OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum printing speed of this media path expressed in
+ prtMediaPathMaxSpeedUnit's. A value of (-1) implies 'other'."
+ ::= { prtMediaPathEntry 4 }
+
+prtMediaPathMaxMediaFeedDir OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum physical media size in the feed direction of this
+ media path expressed in units of measure specified by
+ PrtMediaPathMediaSizeUnit. A value of (-1) implies 'unlimited'
+ a value of (-2) implies 'unknown'.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMediaPathEntry 5 }
+
+prtMediaPathMaxMediaXFeedDir OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum physical media size across the feed direction of
+ this media path expressed in units of measure specified by
+ prtMediaPathMediaSizeUnit. A value of (-2) implies 'unknown'.
+
+
+
+Bergman, et al. Standards Track [Page 111]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMediaPathEntry 6 }
+
+prtMediaPathMinMediaFeedDir OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The minimum physical media size in the feed direction of this
+ media path expressed in units of measure specified by
+ prtMediaPathMediaSizeUnit. A value of (-2) implies 'unknown'.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMediaPathEntry 7 }
+
+prtMediaPathMinMediaXFeedDir OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The minimum physical media size across the feed direction of
+ this media path expressed in units of measure specified by
+ prtMediaPathMediaSizeUnit. A value of (-2) implies 'unknown'.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtMediaPathEntry 8 }
+
+prtMediaPathType OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtMediaPathTypeTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of the media path for this media path."
+ ::= { prtMediaPathEntry 9 }
+
+prtMediaPathDescription OBJECT-TYPE
+ -- In RFC 1759, the SYNTAX was OCTET STRING. This has been changed
+ -- to a TC to better support localization of the object.
+ SYNTAX PrtLocalizedDescriptionStringTC
+ MAX-ACCESS read-only
+ STATUS current
+
+
+
+Bergman, et al. Standards Track [Page 112]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ DESCRIPTION
+ "The manufacturer-provided description of this media path in
+ the localization specified by prtGeneralCurrentLocalization."
+ ::= { prtMediaPathEntry 10 }
+
+prtMediaPathStatus OBJECT-TYPE
+ SYNTAX PrtSubUnitStatusTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The current status of this media path."
+ ::= { prtMediaPathEntry 11 }
+
+-- The Print Job Delivery Channel Group
+--
+-- Print Job Delivery Channels are independent sources of print
+-- data. Here, print data is the term used for the information
+-- that is used to construct printed pages and may have both data
+-- and control aspects. The output of a channel is in a form
+-- suitable for input to one of the interpreters as a
+-- stream. A channel may be independently enabled (allowing
+-- print data to flow) or disabled (stopping the flow of
+-- print data). A printer may have one or more channels.
+--
+-- The Print Job Delivery Channel table describes the
+-- capabilities of the printer and not what is currently being
+-- performed by the printer
+--
+-- Basically, the print job delivery channel abstraction
+-- describes the final processing step of getting the print data
+-- to an interpreter. It might include some level of
+-- decompression or decoding of print stream data.
+-- channel. All of these aspects are hidden in the channel
+-- abstraction.
+--
+-- There are many kinds of print job delivery channels; some of
+-- which are based on networks and others which are not. For
+-- example, a channel can be a serial (or parallel) connection;
+-- it can be a service, such as the UNIX Line Printer Daemon
+-- (LPD), offering services over a network connection; or
+-- it could be a disk drive into which a floppy disk with
+-- the print data is inserted. Each print job delivery channel is
+-- identified by the electronic path and/or service protocol
+-- used to deliver print data to a print data interpreter.
+--
+-- Channel example Implementation
+--
+-- serial port channel bi-directional data channel
+
+
+
+Bergman, et al. Standards Track [Page 113]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+-- parallel port channel often uni-directional channel
+-- IEEE 1284 port channel bi-directional channel
+-- SCSI port channel bi-directional
+-- Apple PAP channel may be based on LocalTalk,
+-- Ethernet or Tokentalk
+-- LPD Server channel TCP/IP based, port 515
+-- Netware Remote Printer SPX/IPX based channel
+-- Netware Print Server SPX/IPX based channel
+--
+-- It is easy to note that this is a mixed bag. There are
+-- some physical connections over which no (or very meager)
+-- protocols are run (e.g., the serial or old parallel ports)
+-- and there are services which often have elaborate
+-- protocols that run over a number of protocol stacks. In
+-- the end, what is important is the delivery of print data
+-- through the channel.
+--
+-- The print job delivery channel sub-units are represented by
+-- the Print Job Delivery Channel Group in the Model. It has a
+-- current print job control language, which can be used to
+-- specify which interpreter is to be used for the print data and
+-- to query and change environment variables used by the
+-- interpreters (and Management Applications). There is also a
+-- default interpreter that is to be used if an interpreter is
+-- not explicitly specified using the Control Language.
+
+-- The first seven items in the Print Job Delivery Channel Table
+-- define the "channel" itself. A channel typically depends on
+-- other protocols and interfaces to provide the data that flows
+-- through the channel.
+--
+-- Control of a print job delivery channel is largely limited to
+-- enabling or disabling the entire channel itself. It is likely
+-- that more control of the process of accessing print data
+-- will be needed over time. Thus, the ChannelType will
+-- allow type-specific data to be associated with each
+-- channel (using ChannelType specific groups in a fashion
+-- analogous to the media specific MIBs that are associated
+-- with the IANAIfType in the Interfaces Table). As a first
+-- step in this direction, each channel will identify the
+-- underlying Interface on which it is based. This is the
+-- eighth object in each row of the table.
+
+
+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 114]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+-- The Print Job Delivery Channel Table
+
+prtChannel OBJECT IDENTIFIER ::= { printmib 14 }
+
+prtChannelTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtChannelEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The channel table represents the set of input data sources
+ which can provide print data to one or more of the
+ interpreters available on a printer.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtChannel 1 }
+
+prtChannelEntry OBJECT-TYPE
+ SYNTAX PrtChannelEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Entries may exist in the table for each device index with a
+ device type of 'printer'. Each channel table entry is
+ characterized by a unique protocol stack and/or addressing.
+ The channel may also have printer dependent features that are
+ associated with a printing language.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrDeviceIndex, prtChannelIndex }
+ ::= { prtChannelTable 1 }
+
+PrtChannelEntry ::= SEQUENCE {
+ prtChannelIndex Integer32,
+ prtChannelType PrtChannelTypeTC,
+ prtChannelProtocolVersion OCTET STRING,
+ prtChannelCurrentJobCntlLangIndex Integer32,
+ prtChannelDefaultPageDescLangIndex Integer32,
+ prtChannelState PrtChannelStateTC,
+ prtChannelIfIndex InterfaceIndexOrZero,
+ prtChannelStatus PrtSubUnitStatusTC,
+ prtChannelInformation OCTET STRING
+ }
+
+prtChannelIndex OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (1..65535)
+
+
+
+Bergman, et al. Standards Track [Page 115]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value used by the printer to identify this data
+ channel. Although these values may change due to a major
+ reconfiguration of the device (e.g., the addition of new data
+ channels to the printer), values SHOULD remain stable across
+ successive printer power cycles.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtChannelEntry 1 }
+
+prtChannelType OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtChannelTypeTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of this print data channel. This object provides the
+ linkage to ChannelType-specific groups that may (conceptually)
+ extend the prtChannelTable with additional details about that
+ channel."
+ ::= { prtChannelEntry 2 }
+
+prtChannelProtocolVersion OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..63))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The version of the protocol used on this channel. The format
+ used for version numbering depends on prtChannelType."
+ ::= { prtChannelEntry 3 }
+
+prtChannelCurrentJobCntlLangIndex OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (0..65535)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of prtInterpreterIndex corresponding to the Control
+ Language Interpreter for this channel. This interpreter defines
+ the syntax used for control functions, such as querying or
+ changing environment variables and identifying job boundaries
+ (e.g., PJL, PostScript, NPAP). A value of zero indicates that
+ there is no current Job Control Language Interpreter for this
+ channel.
+
+
+
+Bergman, et al. Standards Track [Page 116]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtChannelEntry 4 }
+
+prtChannelDefaultPageDescLangIndex OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (0..65535)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of prtInterpreterIndex corresponding to the Page
+ Description Language Interpreter for this channel. This
+ interpreter defines the default Page Description Language
+ interpreter to be used for the print data unless the Control
+ Language is used to select a specific interpreter (e.g., PCL,
+ PostScript Language, auto-sense). A value of zero indicates
+ that there is no default page description language interpreter
+ for this channel.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtChannelEntry 5 }
+
+prtChannelState OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtChannelStateTC
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The state of this print data channel. The value determines
+ whether control information and print data is allowed through
+ this channel or not."
+ ::= { prtChannelEntry 6 }
+
+prtChannelIfIndex OBJECT-TYPE
+ SYNTAX InterfaceIndexOrZero -- Was Integer32 in RFC 1759.
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The value of ifIndex in the ifTable; see the Interfaces Group
+ MIB [RFC2863] which corresponds to this channel.
+ When more than one row of the ifTable is relevant, this is the
+ index of the row representing the topmost layer in the
+ interface hierarchy. A value of zero indicates that no
+ interface is associated with this channel.
+
+ NOTE: The above description has been modified from RFC 1759
+
+
+
+Bergman, et al. Standards Track [Page 117]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ for clarification."
+ ::= { prtChannelEntry 7 }
+
+prtChannelStatus OBJECT-TYPE
+ SYNTAX PrtSubUnitStatusTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The current status of the channel."
+ ::= { prtChannelEntry 8 }
+
+prtChannelInformation OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..255))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Auxiliary information to allow a printing application to use
+ the channel for data submission to the printer. An application
+ capable of using a specific PrtChannelType should be able to
+ use the combined information from the prtChannelInformation and
+ other channel and interface group objects to 'bootstrap' its
+ use of the channel. prtChannelInformation is not intended to
+ provide a general channel description, nor to provide
+ information that is available once the channel is in use.
+
+ The encoding and interpretation of the prtChannelInformation
+ object is specific to channel type. The description of each
+ PrtChannelType enum value for which prtChannelInformation is
+ defined specifies the appropriate encoding and interpretation,
+ including interaction with other objects. For channel types
+ that do not specify a prtChannelInformation value, its value
+ shall be null (0 length).
+
+ When a new PrtChannelType enumeration value is registered, its
+ accompanying description must specify the encoding and
+ interpretation of the prtChannelInformation value for the
+ channel type. prtChannelInformation semantics for an existing
+ PrtChannelType may be added or amended in the same manner as
+ described in section 2.4.1 for type 2 enumeration values.
+
+ The prtChannelInformation specifies values for a collection of
+ channel attributes, represented as text according to the
+ following rules:
+
+ 1. The prtChannelInformation is not affected by localization.
+
+ 2. The prtChannelInformation is a list of entries representing
+ the attribute values. Each entry consists of the following
+
+
+
+Bergman, et al. Standards Track [Page 118]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ items, in order:
+
+ a. A keyword, composed of alphabetic characters (A-Z, a-z)
+ represented by their NVT ASCII [RFC854] codes, that
+ identifies a channel attribute,
+
+ b. The NVT ASCII code for an Equals Sign (=) (code 61) to
+ delimit the keyword,
+
+ c. A data value encoded using rules specific to the
+ PrtChannelType to with the prtChannelInformation applies which
+ must in no case allow an octet with value 10 (the NVT ASCII
+ Line Feed code),
+
+ d. the NVT ASCII code for a Line Feed character (code 10) to
+ delimit the data value.
+
+ No other octets shall be present.
+
+ Keywords are case-sensitive. Conventionally, keywords are
+ capitalized (including each word of a multi-word keyword) and
+ since they occupy space in the prtChannelInformation, they are
+ kept short.
+
+ 3. If a channel attribute has multiple values, it is
+ represented by multiple entries with the same keyword, each
+ specifying one value. Otherwise, there shall be at most one
+ entry for each attribute.
+
+ 4. By default, entries may appear in any order. If there are
+ ordering constraints for particular entries, these must be
+ specified in their definitions.
+
+ 5. The prtChannelInformation value by default consists of text
+ represented by NVT ASCII graphics character codes. However,
+ other representations may be specified:
+
+ a. In cases where the prtChannelInformation value contains
+ information not normally coded in textual form, whatever
+ symbolic representation is conventionally used for the
+ information should be used for encoding the
+ prtChannelInformation value. (For instance, a binary port value
+ might be represented as a decimal number using NVT ASCII
+ codes.) Such encoding must be specified in the definition of
+ the value.
+
+ b. The value may contain textual information in a character set
+ other than NVT ASCII graphics characters. (For instance, an
+
+
+
+Bergman, et al. Standards Track [Page 119]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ identifier might consist of ISO 10646 text encoded using the
+ UTF-8 encoding scheme.) Such a character set and its encoding
+ must be specified in the definition of the value.
+
+ 6. For each PrtChannelType for which prtChannelInformation
+ entries are defined, the descriptive text associated with the
+ PrtChannelType enumeration value shall specify the following
+ information for each entry:
+
+ Title: Brief description phrase, e.g.: 'Port name',
+ 'Service Name', etc.
+
+ Keyword: The keyword value, e.g.: 'Port' or 'Service'
+
+ Syntax: The encoding of the entry value if it cannot be
+ directly represented by NVT ASCII.
+
+ Status: 'Mandatory', 'Optional', or 'Conditionally
+ Mandatory'
+
+ Multiplicity: 'Single' or 'Multiple' to indicate whether the
+ entry may be present multiple times.
+
+ Description: Description of the use of the entry, other
+ information required to complete the definition
+ (e.g.: ordering constraints, interactions between
+ entries).
+
+ Applications that interpret prtChannelInformation should ignore
+ unrecognized entries, so they are not affected if new entry
+ types are added."
+
+ ::= { prtChannelEntry 9 }
+
+-- The Interpreter Group
+--
+-- The interpreter sub-units are responsible for the conversion
+-- of a description of intended print instances into images that
+-- are to be marked on the media. A printer may have one or more
+-- interpreters. The interpreter sub-units are represented by the
+-- Interpreter Group in the Model. Each interpreter is generally
+-- implemented with software running on the System Controller
+-- sub-unit. The Interpreter Table has one entry per interpreter
+-- where the interpreters include both Page Description Language
+-- (PDL) Interpreters and Control Language Interpreters.
+
+prtInterpreter OBJECT IDENTIFIER ::= { printmib 15 }
+
+
+
+
+Bergman, et al. Standards Track [Page 120]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+-- Interpreter Table
+
+prtInterpreterTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtInterpreterEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The interpreter table is a table representing the
+ interpreters in the printer. An entry shall be placed in the
+ interpreter table for each interpreter on the printer.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtInterpreter 1 }
+
+prtInterpreterEntry OBJECT-TYPE
+ SYNTAX PrtInterpreterEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Entries may exist in the table for each device index with a
+ device type of 'printer'. Each table entry provides a complete
+ description of the interpreter, including version information,
+ rendering resolutions, default character sets, output
+ orientation, and communication capabilities.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrDeviceIndex, prtInterpreterIndex }
+ ::= { prtInterpreterTable 1 }
+
+PrtInterpreterEntry ::= SEQUENCE {
+ prtInterpreterIndex Integer32,
+ prtInterpreterLangFamily PrtInterpreterLangFamilyTC,
+ prtInterpreterLangLevel OCTET STRING,
+ prtInterpreterLangVersion OCTET STRING,
+ prtInterpreterDescription PrtLocalizedDescriptionStringTC,
+ prtInterpreterVersion OCTET STRING,
+ prtInterpreterDefaultOrientation PrtPrintOrientationTC,
+ prtInterpreterFeedAddressability Integer32,
+ prtInterpreterXFeedAddressability Integer32,
+ prtInterpreterDefaultCharSetIn IANACharset,
+ prtInterpreterDefaultCharSetOut IANACharset,
+ prtInterpreterTwoWay PrtInterpreterTwoWayTC
+ }
+
+prtInterpreterIndex OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+
+
+
+Bergman, et al. Standards Track [Page 121]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value for each PDL or control language for which
+ there exists an interpreter or emulator in the printer. The
+ value is used to identify this interpreter. Although these
+ values may change due to a major reconfiguration of the device
+ (e.g., the addition of new interpreters to the printer), values
+ SHOULD remain stable across successive printer power cycles.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtInterpreterEntry 1 }
+
+prtInterpreterLangFamily OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtInterpreterLangFamilyTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The family name of a Page Description Language (PDL) or
+ control language which this interpreter in the printer can
+ interpret or emulate.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtInterpreterEntry 2 }
+
+prtInterpreterLangLevel OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..31))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The level of the language which this interpreter is
+ interpreting or emulating. This might contain a value like
+ '5e'for an interpreter which is emulating level 5e of the PCL
+ language. It might contain '2' for an interpreter which is
+ emulating level 2 of the PostScript language. Similarly it
+ might contain '2' for an interpreter which is emulating level 2
+ of the HPGL language."
+ ::= { prtInterpreterEntry 3 }
+
+prtInterpreterLangVersion OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..31))
+ MAX-ACCESS read-only
+ STATUS current
+
+
+
+Bergman, et al. Standards Track [Page 122]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ DESCRIPTION
+ "The date code or version of the language which this
+ interpreter is interpreting or emulating."
+ ::= { prtInterpreterEntry 4 }
+
+prtInterpreterDescription OBJECT-TYPE
+ -- In RFC 1759, the SYNTAX was OCTET STRING. This has been changed
+ -- to a TC to better support localization of the object.
+ SYNTAX PrtLocalizedDescriptionStringTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A string to identify this interpreter in the localization
+ specified by prtGeneralCurrentLocalization as opposed to the
+ language which is being interpreted. It is anticipated that
+ this string will allow manufacturers to unambiguously identify
+ their interpreters."
+ ::= { prtInterpreterEntry 5 }
+
+prtInterpreterVersion OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..31))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The date code, version number, or other product specific
+ information tied to this interpreter. This value is associated
+ with the interpreter, rather than with the version of the
+ language which is being interpreted or emulated."
+ ::= { prtInterpreterEntry 6 }
+
+prtInterpreterDefaultOrientation OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtPrintOrientationTC
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The current orientation default for this interpreter. This
+ value may be overridden for a particular job (e.g., by a
+ command in the input data stream)."
+ ::= { prtInterpreterEntry 7 }
+
+prtInterpreterFeedAddressability OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+
+
+
+Bergman, et al. Standards Track [Page 123]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ "The maximum interpreter addressability in the feed
+ direction in 10000 prtMarkerAddressabilityUnits (as specified
+ by prtMarkerDefaultIndex) for this interpreter. The
+ value (-1) means other and specifically indicates that the
+ sub-unit places no restrictions on this parameter. The value
+ (-2) means unknown.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtInterpreterEntry 8 }
+
+prtInterpreterXFeedAddressability OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum interpreter addressability in the cross feed
+ direction in 10000 prtMarkerAddressabilityUnits (as specified
+ by prtMarkerDefaultIndex) for this interpreter. The
+ value (-1) means other and specifically indicates that the
+ sub-unit places no restrictions on this parameter. The value
+ (-2) means unknown.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtInterpreterEntry 9 }
+
+prtInterpreterDefaultCharSetIn OBJECT-TYPE
+ SYNTAX IANACharset
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The default coded character set for input octets encountered
+ outside a context in which the Page Description Language
+ established the interpretation of the octets. (Input octets are
+ presented to the interpreter through a path defined in the
+ channel group.)"
+ ::= { prtInterpreterEntry 10 }
+
+prtInterpreterDefaultCharSetOut OBJECT-TYPE
+ SYNTAX IANACharset
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The default character set for data coming from this
+ interpreter through the printer's output channel (i.e. the
+ 'backchannel')."
+
+
+
+Bergman, et al. Standards Track [Page 124]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ ::= { prtInterpreterEntry 11 }
+
+prtInterpreterTwoWay OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtInterpreterTwoWayTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Indicates whether or not this interpreter returns information
+ back to the host."
+ ::= { prtInterpreterEntry 12 }
+
+-- The Console Group
+--
+-- Many printers have a console on the printer, the operator
+-- console, that is used to display and modify the state of the
+-- printer. The console can be as simple as a few indicators and
+-- switches or as complicated as full screen displays and
+-- keyboards. There can be at most one such console.
+
+-- The Display Buffer Table
+
+prtConsoleDisplayBuffer OBJECT IDENTIFIER ::= { printmib 16 }
+
+prtConsoleDisplayBufferTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtConsoleDisplayBufferEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Physical display buffer for printer console display or
+ operator panel
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtConsoleDisplayBuffer 5 }
+
+prtConsoleDisplayBufferEntry OBJECT-TYPE
+ SYNTAX PrtConsoleDisplayBufferEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table contains one entry for each physical line on
+ the display. Lines cannot be added or deleted. Entries may
+ exist in the table for each device index with a device type of
+ 'printer'.
+
+ NOTE: The above description has been modified from RFC 1759
+
+
+
+Bergman, et al. Standards Track [Page 125]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ for clarification."
+ INDEX { hrDeviceIndex, prtConsoleDisplayBufferIndex }
+ ::= { prtConsoleDisplayBufferTable 1 }
+
+PrtConsoleDisplayBufferEntry ::= SEQUENCE {
+ prtConsoleDisplayBufferIndex Integer32,
+ prtConsoleDisplayBufferText PrtConsoleDescriptionStringTC
+ }
+
+prtConsoleDisplayBufferIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value for each console line in the printer. The value
+ is used to identify this console line. Although these values
+ may change due to a major reconfiguration of the device (e.g.,
+ the addition of new console lines to the printer). Values
+ SHOULD remain stable across successive printer power cycles.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtConsoleDisplayBufferEntry 1 }
+
+prtConsoleDisplayBufferText OBJECT-TYPE
+ -- In RFC 1759, the SYNTAX was OCTET STRING. This has been changed
+ -- to a TC to better support localization of the object.
+ SYNTAX PrtConsoleDescriptionStringTC
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The content of a line in the logical display buffer of
+ the operator's console of the printer. When a write
+ operation occurs, normally a critical message, to one of
+ the LineText strings, the agent should make that line
+ displayable if a physical display is present. Writing a zero
+ length string clears the line. It is an implementation-
+ specific matter as to whether the agent allows a line to be
+ overwritten before it has been cleared. Printer generated
+ strings shall be in the localization specified by
+ prtConsoleLocalization.Management Application generated strings
+ should be localized by the Management Application."
+ ::= { prtConsoleDisplayBufferEntry 2 }
+
+-- The Console Light Table
+
+prtConsoleLights OBJECT IDENTIFIER ::= { printmib 17 }
+
+
+
+
+Bergman, et al. Standards Track [Page 126]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+prtConsoleLightTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtConsoleLightEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The console light table provides a description and state
+ information for each light present on the printer console.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtConsoleLights 6 }
+
+prtConsoleLightEntry OBJECT-TYPE
+ SYNTAX PrtConsoleLightEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Entries may exist in the table for each device index with a
+ device type of 'printer'.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrDeviceIndex, prtConsoleLightIndex }
+ ::= { prtConsoleLightTable 1 }
+
+PrtConsoleLightEntry ::= SEQUENCE {
+ prtConsoleLightIndex Integer32,
+ prtConsoleOnTime Integer32,
+ prtConsoleOffTime Integer32,
+ prtConsoleColor PrtConsoleColorTC,
+ prtConsoleDescription PrtConsoleDescriptionStringTC
+ }
+
+prtConsoleLightIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535) -- Lower limit invalid in RFC 1759
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value used by the printer to identify this light.
+ Although these values may change due to a major
+ reconfiguration of the device (e.g., the addition of new lights
+ to the printer). Values SHOULD remain stable across successive
+ printer power cycles.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtConsoleLightEntry 1 }
+
+
+
+
+Bergman, et al. Standards Track [Page 127]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+prtConsoleOnTime OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object, in conjunction with prtConsoleOffTime, defines
+ the current status of the light. If both prtConsoleOnTime and
+ prtConsoleOffTime are non-zero, the lamp is blinking and the
+ values presented define the on time and off time, respectively,
+ in milliseconds. If prtConsoleOnTime is zero and
+ prtConsoleOffTime is non-zero, the lamp is off. If
+ prtConsoleOffTime is zero and prtConsoleOnTime is non-zero, the
+ lamp is on. If both values are zero the lamp is off.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtConsoleLightEntry 2 }
+
+prtConsoleOffTime OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object, in conjunction with prtConsoleOnTime, defines the
+ current status of the light. If both prtConsoleOnTime and
+ prtConsoleOffTime are non-zero, the lamp is blinking and the
+ values presented define the on time and off time, respectively,
+ in milliseconds. If prtConsoleOnTime is zero and
+ prtConsoleOffTime is non-zero, the lamp is off. If
+ prtConsoleOffTime is zero and prtConsoleOnTime is non-zero, the
+ lamp is on. If both values are zero the lamp is off.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtConsoleLightEntry 3 }
+
+prtConsoleColor OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtConsoleColorTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The color of this light."
+ ::= { prtConsoleLightEntry 4 }
+
+
+
+
+Bergman, et al. Standards Track [Page 128]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+prtConsoleDescription OBJECT-TYPE
+ -- In RFC 1759, the SYNTAX was OCTET STRING. This has been changed
+ -- to a TC to better support localization of the object.
+ SYNTAX PrtConsoleDescriptionStringTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The vendor description or label of this light in the
+ localization specified by prtConsoleLocalization."
+ ::= { prtConsoleLightEntry 5 }
+
+-- The Alerts Group
+--
+-- The table contains information on the severity, component,
+-- detail location within the component, alert code and
+-- description of each critical alert that is currently active
+-- within the printer. See 2.2.13 for a more complete
+-- description of the alerts table and its management.
+--
+-- Each parameter in the Trap PDU is a full OID which itself is
+-- indexed by the host resources MIB "hrDeviceIndex" object. In
+-- order for a management station to obtain the correct
+-- "hrDeviceIndex" associated with a particular Trap PDU, the
+-- "hrDeviceIndex" value can be extracted from the returned OID
+-- value in the Trap PDU when the PDU is received by the
+-- Management station.
+
+prtAlert OBJECT IDENTIFIER ::= { printmib 18 }
+
+prtAlertTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF PrtAlertEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The prtAlertTable lists all the critical and non-critical
+ alerts currently active in the printer. A critical alert is
+ one that stops the printer from printing immediately and
+ printing can not continue until the critical alert condition
+ is eliminated. Non-critical alerts are those items that do
+ not stop printing but may at some future time.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtAlert 1 }
+
+prtAlertEntry OBJECT-TYPE
+ SYNTAX PrtAlertEntry
+ MAX-ACCESS not-accessible
+
+
+
+Bergman, et al. Standards Track [Page 129]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ STATUS current
+ DESCRIPTION
+ "Entries may exist in the table for each device
+ index with a device type of 'printer'.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ INDEX { hrDeviceIndex, prtAlertIndex }
+ ::= { prtAlertTable 1 }
+
+PrtAlertEntry ::= SEQUENCE {
+ prtAlertIndex Integer32,
+ prtAlertSeverityLevel PrtAlertSeverityLevelTC,
+ prtAlertTrainingLevel PrtAlertTrainingLevelTC,
+ prtAlertGroup PrtAlertGroupTC,
+ prtAlertGroupIndex Integer32,
+ prtAlertLocation Integer32,
+ prtAlertCode PrtAlertCodeTC,
+ prtAlertDescription PrtLocalizedDescriptionStringTC,
+ prtAlertTime TimeTicks
+ }
+
+prtAlertIndex OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined. The MAX-ACCESS has
+ -- been changed from not accessible to allow the object to be
+ -- included (as originally in RFC 1759) in the trap bindings.
+
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The index value used to determine which alerts have been added
+ or removed from the alert table. This is an incrementing
+ integer initialized to 1 when the printer is reset. (i.e., The
+ first event placed in the alert table after a reset of the
+ printer shall have an index value of 1.) When the printer adds
+ an alert to the table, that alert is assigned the next higher
+ integer value from the last item entered into the table. If
+ the index value reaches its maximum value, the next index value
+ used must be 1.
+
+ NOTE: The management application will read the alert table when
+ a trap or event notification occurs or at a periodic rate and
+ then parse the table to determine if any new entries were added
+ by comparing the last known index value with the current
+ highest index value. The management application will then
+ update its copy of the alert table. When the printer discovers
+ that an alert is no longer active, the printer shall remove the
+
+
+
+Bergman, et al. Standards Track [Page 130]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ row for that alert from the table and shall reduce the number
+ of rows in the table. The printer may add or delete any number
+ of rows from the table at any time. The management station can
+ detect when binary change alerts have been deleted by
+ requesting an attribute of each alert, and noting alerts as
+ deleted when that retrieval is not possible. The objects
+ 'prtAlertCriticalEvents'and 'prtAlertAllEvents' in the
+ 'prtGeneralTable' reduce the need for management applications
+ to scan the 'prtAlertTable'.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtAlertEntry 1 }
+
+prtAlertSeverityLevel OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtAlertSeverityLevelTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The level of severity of this alert table entry. The printer
+ determines the severity level assigned to each entry into the
+ table."
+ ::= { prtAlertEntry 2 }
+
+prtAlertTrainingLevel OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtAlertTrainingLevelTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "See TEXTUAL-CONVENTION PrtAlertTrainingLevelTC.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtAlertEntry 3 }
+
+prtAlertGroup OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtAlertGroupTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of sub-unit within the printer model that this alert
+ is related. Input, output, and markers are examples of printer
+
+
+
+Bergman, et al. Standards Track [Page 131]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ model groups, i.e., examples of types of sub-units. Wherever
+ possible, these enumerations match the sub-identifier that
+ identifies the relevant table in the printmib."
+ ::= { prtAlertEntry 4 }
+
+prtAlertGroupIndex OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The low-order index of the row within the table identified
+ by prtAlertGroup that represents the sub-unit of the printer
+ that caused this alert, or -1 if not applicable. The
+ combination of the prtAlertGroup and the prtAlertGroupIndex
+ defines exactly which printer sub-unit caused the alert; for
+ example, Input #3, Output#2, and Marker #1. Every object in
+ this MIB is indexed with hrDeviceIndex and optionally, another
+ index variable. If this other index variable is present in the
+ table that generated the alert, it will be used as the value
+ for this object. Otherwise, this value shall be -1.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtAlertEntry 5 }
+
+prtAlertLocation OBJECT-TYPE
+ -- NOTE: In RFC 1759, the range was not defined.
+ SYNTAX Integer32 (-2..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The sub-unit location that is defined by the printer
+ manufacturer to further refine the location of this alert
+ within the designated sub-unit. The location is used in
+ conjunction with the Group and GroupIndex values; for example,
+ there is an alert in Input #2 at location number 7. The value
+ (-2) indicates unknown.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtAlertEntry 6 }
+
+prtAlertCode OBJECT-TYPE
+ -- NOTE: In RFC 1759, the enumeration values were implicitly
+ -- defined by this object.
+ SYNTAX PrtAlertCodeTC
+ MAX-ACCESS read-only
+
+
+
+Bergman, et al. Standards Track [Page 132]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ STATUS current
+ DESCRIPTION
+ "See associated TEXTUAL-CONVENTION PrtAlertCodeTC.
+
+ NOTE: The above description has been modified from RFC 1759
+ for clarification."
+ ::= { prtAlertEntry 7 }
+
+prtAlertDescription OBJECT-TYPE
+ -- In RFC 1759, the SYNTAX was OCTET STRING. This has been changed
+ -- to a TC to better support localization of the object.
+ SYNTAX PrtLocalizedDescriptionStringTC
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A description of this alert entry in the localization
+ specified by prtGeneralCurrentLocalization. The description is
+ provided by the printer to further elaborate on the enumerated
+ alert or provide information in the case where the code is
+ classified as 'other' or 'unknown'. The printer is required to
+ return a description string but the string may be a null
+ string."
+ ::= { prtAlertEntry 8 }
+
+prtAlertTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time that this alert was
+ generated."
+ ::= { prtAlertEntry 9 }
+
+printerV1Alert OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The value of the enterprise-specific OID in an SNMPv1 trap
+ sent signaling a critical event in the prtAlertTable."
+ ::= { prtAlert 2 }
+
+printerV2AlertPrefix OBJECT IDENTIFIER ::= { printerV1Alert 0 }
+
+printerV2Alert NOTIFICATION-TYPE
+ OBJECTS { prtAlertIndex, prtAlertSeverityLevel, prtAlertGroup,
+ prtAlertGroupIndex, prtAlertLocation, prtAlertCode }
+ STATUS current
+ DESCRIPTION
+ "This trap is sent whenever a critical event is added to the
+
+
+
+Bergman, et al. Standards Track [Page 133]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ prtAlertTable.
+
+ NOTE: The prtAlertIndex object was redundantly included in the
+ bindings of the 'printerV2Alert' notification in RFC 1759, even
+ though the value exists in the instance qualifier of all the
+ other bindings. This object has been retained to provide
+ compatiblity with existing RFC 1759 implementaions."
+ ::= { printerV2AlertPrefix 1 }
+
+-- Note that the SNMPv2 to SNMPv1 translation rules dictate that
+-- the preceding structure will result in SNMPv1 traps of the
+-- following form:
+--
+-- printerAlert TRAP-TYPE
+-- ENTERPRISE printerV1Alert
+-- VARIABLES { prtAlertIndex, prtAlertSeverityLevel,
+-- prtAlertGroup, prtAlertGroupIndex,
+-- prtAlertLocation, prtAlertCode }
+-- DESCRIPTION
+-- "This trap is sent whenever a critical event is added
+-- to the prtAlertTable."
+-- ::= 1
+
+-- Conformance Information
+
+prtMIBConformance OBJECT IDENTIFIER ::= { printmib 2 }
+
+-- compliance statements
+
+prtMIBCompliance MODULE-COMPLIANCE
+
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for agents that implement the
+ printer MIB as defined by RFC 1759."
+ MODULE -- this module
+ MANDATORY-GROUPS { prtGeneralGroup, prtInputGroup,
+ prtOutputGroup,
+ prtMarkerGroup, prtMediaPathGroup,
+ prtChannelGroup, prtInterpreterGroup,
+ prtConsoleGroup, prtAlertTableGroup }
+ OBJECT prtGeneralReset
+ SYNTAX INTEGER {
+ notResetting(3),
+ resetToNVRAM(5)
+ }
+ DESCRIPTION
+ "It is conformant to implement just these two states in this
+
+
+
+Bergman, et al. Standards Track [Page 134]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ object. Any additional states are optional."
+
+ OBJECT prtConsoleOnTime
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtConsoleOffTime
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+ ::= { prtMIBConformance 1 }
+
+prtMIB2Compliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for agents that implement the
+ printer MIB V2."
+ -- The changes from RFC 1759 fall into 2 categories:
+ -- 1. New objects plus existing objects with a MIN-ACCESS of
+ -- read-only are included. Existing objects have been added
+ -- to this category due to feedback from implementers and
+ -- interoperability testing. This allows products to be
+ -- be designed with a higher degree of SNMP security.
+ -- 2. New object groups have been added to include all new
+ -- objects in this MIB. All new object groups are optional.
+ -- Any MIB that is compliant with RFC 1759 will also be
+ -- compliant with this version of the MIB.
+ MODULE -- this module
+ MANDATORY-GROUPS { prtGeneralGroup, prtInputGroup,
+ prtOutputGroup,
+ prtMarkerGroup, prtMediaPathGroup,
+ prtChannelGroup, prtInterpreterGroup,
+ prtConsoleGroup, prtAlertTableGroup }
+ OBJECT prtGeneralReset
+ SYNTAX INTEGER {
+ notResetting(3),
+ resetToNVRAM(5)
+ }
+ DESCRIPTION
+ "It is conformant to implement just these two states in this
+ object. Any additional states are optional."
+
+ OBJECT prtGeneralCurrentLocalization
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+
+
+
+Bergman, et al. Standards Track [Page 135]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ OBJECT prtGeneralCurrentOperator
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtGeneralServicePerson
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtGeneralPrinterName
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtGeneralSerialNumber
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInputDefaultIndex
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInputMediaDimFeedDirDeclared
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInputMaxCapacity
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInputCurrentLevel
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInputMediaName
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInputName
+ MIN-ACCESS read-only
+ DESCRIPTION
+
+
+
+Bergman, et al. Standards Track [Page 136]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInputSecurity
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInputMediaWeight
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInputMediaType
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInputMediaColor
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInputMediaFormParts
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtOutputDefaultIndex
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtOutputMaxCapacity
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtOutputRemainingCapacity
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtOutputName
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtOutputSecurity
+
+
+
+Bergman, et al. Standards Track [Page 137]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtOutputMaxDimFeedDir
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtOutputMaxDimXFeedDir
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtOutputMinDimFeedDir
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtOutputMinDimXFeedDir
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtOutputStackingOrder
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtOutputPageDeliveryOrientation
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtOutputBursting
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtOutputDecollating
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtOutputPageCollated
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+
+
+Bergman, et al. Standards Track [Page 138]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ OBJECT prtOutputOffsetStacking
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtMarkerDefaultIndex
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtMarkerSuppliesMaxCapacity
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtMarkerSuppliesLevel
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtMediaPathDefaultIndex
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtChannelCurrentJobCntlLangIndex
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtChannelDefaultPageDescLangIndex
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtChannelState
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtChannelIfIndex
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInterpreterDefaultOrientation
+ MIN-ACCESS read-only
+ DESCRIPTION
+
+
+
+Bergman, et al. Standards Track [Page 139]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInterpreterDefaultCharSetIn
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInterpreterDefaultCharSetOut
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtConsoleLocalization
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtConsoleDisable
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtConsoleDisplayBufferText
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtConsoleOnTime
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtConsoleOffTime
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtAlertIndex
+ MIN-ACCESS accessible-for-notify
+ DESCRIPTION
+ "It is conformant to implement this object as
+ accessible-for-notify "
+
+ GROUP prtResponsiblePartyGroup
+ DESCRIPTION
+ "This group is unconditionally optional."
+
+ GROUP prtExtendedInputGroup
+
+
+
+Bergman, et al. Standards Track [Page 140]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ DESCRIPTION
+ "This group is unconditionally optional."
+
+ GROUP prtInputMediaGroup
+ DESCRIPTION
+ "This group is unconditionally optional."
+
+ GROUP prtExtendedOutputGroup
+ DESCRIPTION
+ "This group is unconditionally optional."
+
+ GROUP prtOutputDimensionsGroup
+ DESCRIPTION
+ "This group is unconditionally optional."
+
+ GROUP prtOutputFeaturesGroup
+ DESCRIPTION
+ "This group is unconditionally optional."
+
+ GROUP prtMarkerSuppliesGroup
+ DESCRIPTION
+ "This group is unconditionally optional."
+
+ GROUP prtMarkerColorantGroup
+ DESCRIPTION
+ "This group is unconditionally optional."
+
+ GROUP prtAlertTimeGroup
+ DESCRIPTION
+ "This group is unconditionally optional."
+
+ -- the prtResponsiblePartyGroup, prtExtendedInputGroup,
+ -- prtInputMediaGroup, prtExtendedOutputGroup,
+ -- prtOutputDimensionsGroup, prtOutputFeaturesGroup,
+ -- prtMarkerSuppliesGroup, prtMarkerColorantGroup, and the
+ -- prtAlertTimeGroup are completely optional. However, it is
+ -- strongly RECOMMENDED that the prtAlertTimeGroup be implemented.
+
+ -- New to version 2 of this printer MIB:
+ OBJECT prtAuxiliarySheetStartupPage
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtAuxiliarySheetBannerPage
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+
+
+Bergman, et al. Standards Track [Page 141]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ OBJECT prtInputMediaLoadTimeout
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ OBJECT prtInputNextIndex
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "It is conformant to implement this object as read-only"
+
+ GROUP prtAuxiliarySheetGroup
+ DESCRIPTION
+ "This group is unconditionally optional."
+
+ GROUP prtInputSwitchingGroup
+ DESCRIPTION
+ "This group is unconditionally optional."
+
+ GROUP prtGeneralV2Group
+ DESCRIPTION
+ "This group is unconditionally optional."
+
+ GROUP prtAlertTableV2Group
+ DESCRIPTION
+ "This group is unconditionally optional."
+
+ GROUP prtChannelV2Group
+ DESCRIPTION
+ "This group is unconditionally optional."
+
+ GROUP prtAlertTrapGroup
+ DESCRIPTION
+ "This group is unconditionally optional."
+ ::= { prtMIBConformance 3 }
+
+prtMIBGroups OBJECT IDENTIFIER ::= { prtMIBConformance 2 }
+-- These groups are from RFC 1759 and are applicable to Printer MIB V2
+
+prtGeneralGroup OBJECT-GROUP
+ OBJECTS { prtGeneralConfigChanges,
+ prtGeneralCurrentLocalization,
+ prtGeneralReset, prtCoverDescription,
+ prtCoverStatus,
+ prtLocalizationLanguage, prtLocalizationCountry,
+ prtLocalizationCharacterSet, prtStorageRefIndex,
+ prtDeviceRefIndex }
+ STATUS current
+ DESCRIPTION
+
+
+
+Bergman, et al. Standards Track [Page 142]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ "The general printer group."
+ ::= { prtMIBGroups 1 }
+
+prtResponsiblePartyGroup OBJECT-GROUP
+ OBJECTS { prtGeneralCurrentOperator, prtGeneralServicePerson }
+ STATUS current
+ DESCRIPTION
+ "The responsible party group contains contact information for
+ humans responsible for the printer."
+ ::= { prtMIBGroups 2 }
+
+prtInputGroup OBJECT-GROUP
+ OBJECTS { prtInputDefaultIndex, prtInputType, prtInputDimUnit,
+ prtInputMediaDimFeedDirDeclared,
+ prtInputMediaDimXFeedDirDeclared,
+ prtInputMediaDimFeedDirChosen,
+ prtInputMediaDimXFeedDirChosen, prtInputCapacityUnit,
+ prtInputMaxCapacity, prtInputCurrentLevel, prtInputStatus,
+ prtInputMediaName }
+ STATUS current
+ DESCRIPTION
+ "The input group."
+ ::= { prtMIBGroups 3 }
+
+prtExtendedInputGroup OBJECT-GROUP
+ OBJECTS { prtInputName, prtInputVendorName, prtInputModel,
+ prtInputVersion, prtInputSerialNumber,
+ prtInputDescription, prtInputSecurity }
+ STATUS current
+ DESCRIPTION
+ "The extended input group."
+ ::= { prtMIBGroups 4 }
+
+prtInputMediaGroup OBJECT-GROUP
+ OBJECTS { prtInputMediaWeight, prtInputMediaType,
+ prtInputMediaColor, prtInputMediaFormParts }
+ STATUS current
+ DESCRIPTION
+ "The input media group."
+ ::= { prtMIBGroups 5 }
+
+prtOutputGroup OBJECT-GROUP
+ OBJECTS { prtOutputDefaultIndex, prtOutputType,
+ prtOutputCapacityUnit, prtOutputMaxCapacity,
+ prtOutputRemainingCapacity, prtOutputStatus }
+ STATUS current
+ DESCRIPTION
+ "The output group."
+
+
+
+Bergman, et al. Standards Track [Page 143]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ ::= { prtMIBGroups 6 }
+
+prtExtendedOutputGroup OBJECT-GROUP
+ OBJECTS { prtOutputName, prtOutputVendorName, prtOutputModel,
+ prtOutputVersion, prtOutputSerialNumber,
+ prtOutputDescription, prtOutputSecurity }
+ STATUS current
+ DESCRIPTION
+ "The extended output group."
+ ::= { prtMIBGroups 7 }
+
+prtOutputDimensionsGroup OBJECT-GROUP
+ OBJECTS { prtOutputDimUnit, prtOutputMaxDimFeedDir,
+ prtOutputMaxDimXFeedDir, prtOutputMinDimFeedDir,
+ prtOutputMinDimXFeedDir }
+ STATUS current
+ DESCRIPTION
+ "The output dimensions group"
+ ::= { prtMIBGroups 8 }
+
+prtOutputFeaturesGroup OBJECT-GROUP
+ OBJECTS { prtOutputStackingOrder,
+ prtOutputPageDeliveryOrientation, prtOutputBursting,
+ prtOutputDecollating, prtOutputPageCollated,
+ prtOutputOffsetStacking }
+ STATUS current
+ DESCRIPTION
+ "The output features group."
+ ::= { prtMIBGroups 9 }
+
+prtMarkerGroup OBJECT-GROUP
+ OBJECTS { prtMarkerDefaultIndex, prtMarkerMarkTech,
+ prtMarkerCounterUnit, prtMarkerLifeCount,
+ prtMarkerPowerOnCount, prtMarkerProcessColorants,
+ prtMarkerSpotColorants, prtMarkerAddressabilityUnit,
+ prtMarkerAddressabilityFeedDir,
+ prtMarkerAddressabilityXFeedDir, prtMarkerNorthMargin,
+ prtMarkerSouthMargin, prtMarkerWestMargin,
+ prtMarkerEastMargin, prtMarkerStatus }
+ STATUS current
+ DESCRIPTION
+ "The marker group."
+ ::= { prtMIBGroups 10 }
+
+prtMarkerSuppliesGroup OBJECT-GROUP
+ OBJECTS { prtMarkerSuppliesMarkerIndex,
+ prtMarkerSuppliesColorantIndex, prtMarkerSuppliesClass,
+ prtMarkerSuppliesType, prtMarkerSuppliesDescription,
+
+
+
+Bergman, et al. Standards Track [Page 144]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ prtMarkerSuppliesSupplyUnit,
+ prtMarkerSuppliesMaxCapacity, prtMarkerSuppliesLevel }
+ STATUS current
+ DESCRIPTION
+ "The marker supplies group."
+ ::= { prtMIBGroups 11 }
+
+prtMarkerColorantGroup OBJECT-GROUP
+ OBJECTS { prtMarkerColorantMarkerIndex, prtMarkerColorantRole,
+ prtMarkerColorantValue, prtMarkerColorantTonality }
+ STATUS current
+ DESCRIPTION
+ "The marker colorant group."
+ ::= { prtMIBGroups 12 }
+
+prtMediaPathGroup OBJECT-GROUP
+ OBJECTS { prtMediaPathDefaultIndex, prtMediaPathMaxSpeedPrintUnit,
+ prtMediaPathMediaSizeUnit, prtMediaPathMaxSpeed,
+ prtMediaPathMaxMediaFeedDir,
+ prtMediaPathMaxMediaXFeedDir,
+ prtMediaPathMinMediaFeedDir,
+ prtMediaPathMinMediaXFeedDir, prtMediaPathType,
+ prtMediaPathDescription, prtMediaPathStatus}
+ STATUS current
+ DESCRIPTION
+ "The media path group."
+ ::= { prtMIBGroups 13 }
+
+prtChannelGroup OBJECT-GROUP
+ OBJECTS { prtChannelType, prtChannelProtocolVersion,
+ prtChannelCurrentJobCntlLangIndex,
+ prtChannelDefaultPageDescLangIndex, prtChannelState,
+ prtChannelIfIndex, prtChannelStatus
+ }
+ STATUS current
+ DESCRIPTION
+ "The channel group."
+ ::= { prtMIBGroups 14 }
+
+prtInterpreterGroup OBJECT-GROUP
+ OBJECTS { prtInterpreterLangFamily, prtInterpreterLangLevel,
+ prtInterpreterLangVersion, prtInterpreterDescription,
+ prtInterpreterVersion, prtInterpreterDefaultOrientation,
+ prtInterpreterFeedAddressability,
+ prtInterpreterXFeedAddressability,
+ prtInterpreterDefaultCharSetIn,
+ prtInterpreterDefaultCharSetOut, prtInterpreterTwoWay }
+ STATUS current
+
+
+
+Bergman, et al. Standards Track [Page 145]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ DESCRIPTION
+ "The interpreter group."
+ ::= { prtMIBGroups 15 }
+
+prtConsoleGroup OBJECT-GROUP
+ OBJECTS { prtConsoleLocalization, prtConsoleNumberOfDisplayLines,
+ prtConsoleNumberOfDisplayChars, prtConsoleDisable,
+ prtConsoleDisplayBufferText, prtConsoleOnTime,
+ prtConsoleOffTime, prtConsoleColor,
+ prtConsoleDescription }
+ STATUS current
+ DESCRIPTION
+ "The console group."
+ ::= { prtMIBGroups 16 }
+
+prtAlertTableGroup OBJECT-GROUP
+ OBJECTS { prtAlertSeverityLevel, prtAlertTrainingLevel,
+ prtAlertGroup, prtAlertGroupIndex, prtAlertLocation,
+ prtAlertCode, prtAlertDescription }
+ STATUS current
+ DESCRIPTION
+ "The alert table group."
+ ::= { prtMIBGroups 17 }
+
+prtAlertTimeGroup OBJECT-GROUP
+ OBJECTS { prtAlertTime }
+ STATUS current
+ DESCRIPTION
+ "The alert time group. Implementation of prtAlertTime is
+ strongly RECOMMENDED."
+ ::= { prtMIBGroups 18 }
+
+prtMIB2Groups OBJECT IDENTIFIER ::= { prtMIBConformance 4 }
+-- These groups are unique to Printer MIB V2
+
+prtAuxiliarySheetGroup OBJECT-GROUP
+ OBJECTS { prtAuxiliarySheetStartupPage,
+ prtAuxiliarySheetBannerPage }
+ STATUS current
+ DESCRIPTION
+ "The auxiliary sheet group."
+ ::= { prtMIBGroups 19 }
+
+prtInputSwitchingGroup OBJECT-GROUP
+ OBJECTS { prtInputMediaLoadTimeout, prtInputNextIndex }
+ STATUS current
+ DESCRIPTION
+ "The input switching group."
+
+
+
+Bergman, et al. Standards Track [Page 146]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ ::= { prtMIBGroups 20 }
+
+prtGeneralV2Group OBJECT-GROUP
+ OBJECTS { prtGeneralPrinterName, prtGeneralSerialNumber }
+ STATUS current
+ DESCRIPTION
+ "The general printer group with new v2 objects."
+ ::= { prtMIBGroups 21 }
+
+prtAlertTableV2Group OBJECT-GROUP
+ OBJECTS { prtAlertIndex, prtAlertCriticalEvents, prtAlertAllEvents }
+ STATUS current
+ DESCRIPTION
+ "The alert table group with new v2 objects and prtAlertIndex
+ changed to MAX-ACCESS of 'read-only' for inclusion in the trap
+ bindings (as originally defined in RFC 1759)."
+
+ ::= { prtMIBGroups 22 }
+
+prtChannelV2Group OBJECT-GROUP
+ OBJECTS { prtChannelInformation }
+ STATUS current
+ DESCRIPTION
+ "The channel group with a new v2 object."
+ ::= { prtMIBGroups 23 }
+
+prtAlertTrapGroup NOTIFICATION-GROUP
+ NOTIFICATIONS { printerV2Alert }
+ STATUS current
+ DESCRIPTION
+ "The alert trap group."
+ ::= { prtMIBGroups 24 }
+
+END
+
+7. IANA Considerations
+
+ The initial version the IANA Printer MIB defined in section 5 of this
+ document is to be archived by IANA and subsequently maintained
+ according to the Process specified in section 2.4.1 of this document.
+ The most current and authoritative version of the IANA Printer MIB is
+ available at:
+
+ http://www.iana.org/assignments/ianaprinter-mib
+
+8. Internationalization Considerations
+
+ See section 2.2.1.1, 'International Considerations'.
+
+
+
+Bergman, et al. Standards Track [Page 147]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+9. Security Considerations
+
+ There are a number of management objects defined in this MIB module
+ with a MAX-ACCESS clause of read-write and/or read-create. Such
+ objects may be considered sensitive or vulnerable in some network
+ environments. The support for SET operations in a non-secure
+ environment without proper protection can have a negative effect on
+ network operations. These are the tables and objects and their
+ sensitivity/vulnerability:
+
+ prtGeneralTable:
+ prtGeneralCurrentLocalization - Possible data loss
+ prtGeneralReset - Possible data loss
+ prtGeneralCurrentOperator - Possible severe inconvenience
+ prtGeneralServicePerson - Possible severe inconvenience
+ prtInputDefaultIndex - Possible data loss
+ prtOutputDefaultIndex - Possible minor inconvenience
+ prtMarkerDefaultIndex - Possible minor inconvenience
+ prtMediaPathDefaultIndex - Possible minor inconvenience
+ prtConsoleLocalization - Possible severe inconvenience
+ prtConsoleDisable - Possible severe inconvenience
+ prtAuxiliarySheetStartupPage - Possible minor inconvenience
+ prtAuxiliarySheetBannerPage - Possible minor inconvenience
+ prtGeneralPrinterName - Possible severe inconvenience
+ prtGeneralSerialNumber - Possible severe inconvenience
+ prtInputTable:
+ prtInputMediaDimFeedDirDeclared - Possible data loss
+ prtInputMediaDimXFeedDirDeclared - Possible data loss
+ prtInputMaxCapacity - Possible minor inconvenience
+ prtInputCurrentLevel - Possible minor inconvenience
+ prtInputMediaName - Possible minor inconvenience
+ prtInputName - Possible minor inconvenience
+ prtInputSecurity - Possible minor inconvenience
+ prtInputMediaWeight - Possible minor inconvenience
+ prtInputMediaType - Possible minor inconvenience
+ prtInputMediaColor - Possible minor inconvenience
+ prtInputMediaFormParts - Possible minor inconvenience
+ prtInputMediaLoadTimeout - Possible minor inconvenience
+ prtInputNextIndex - Possible minor inconvenience
+ prtOutputTable
+ prtOutputMaxCapacity - Possible minor inconvenience
+ prtOutputRemainingCapacity - Possible minor inconvenience
+ prtOutputName - Possible minor inconvenience
+ prtOutputSecurity - Possible minor inconvenience
+ prtOutputMaxDimFeedDir - Possible minor inconvenience
+ prtOutputMaxDimXFeedDir - Possible minor inconvenience
+ prtOutputMinDimFeedDir - Possible minor inconvenience
+ prtOutputMinDimXFeedDir - Possible minor inconvenience
+
+
+
+Bergman, et al. Standards Track [Page 148]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ prtOutputStackingOrder - Possible minor inconvenience
+ prtOutputPageDeliveryOrientation - Possible minor inconvenience
+ prtOutputBursting - Possible minor inconvenience
+ prtOutputDecollating - Possible minor inconvenience
+ prtOutputPageCollated - Possible minor inconvenience
+ prtOutputOffsetStacking - Possible minor inconvenience
+ prtMarkerSuppliesTable
+ prtMarkerSuppliesMaxCapacity - Possible minor inconvenience
+ prtMarkerSuppliesLevel - Possible minor inconvenience
+ prtChannelTable
+ prtChannelCurrentJobCntlLangIndex - Possible data loss
+ prtChannelDefaultPageDescLangIndex - Possible data loss
+ prtChannelState - Possible minor inconvenience
+ prtChannelIfIndex - Possible minor inconvenience
+ prtInterpreterTable
+ prtInterpreterDefaultOrientation - Possible data loss
+ prtInterpreterDefaultCharSetIn - Possible data loss
+ prtInterpreterDefaultCharSetOut - Possible minor inconvenience
+ prtConsoleDisplayBufferTable
+ prtConsoleDisplayBufferText - Possible minor inconvenience
+ prtConsoleLightTable
+ prtConsoleOnTime - Possible minor inconvenience
+ prtConsoleOffTime - Possible minor inconvenience
+
+ SNMP versions prior to SNMPv3 did not include adequate security.
+ Even if the network itself is secure (for example by using IPSec),
+ even then, there is no control as to who on the secure network is
+ allowed to access and GET/SET (read/change/create/delete) the objects
+ in this MIB module.
+
+ It is RECOMMENDED that implementers consider the security features as
+ provided by the SNMPv3 framework (see [RFC3410], section 8),
+ including full support for the SNMPv3 cryptographic mechanisms (for
+ authentication and privacy).
+
+ Further, deployment of SNMP versions prior to SNMPv3 is NOT
+ RECOMMENDED. Instead, it is RECOMMENDED to deploy SNMPv3 and to
+ enable cryptographic security. It is then a customer/operator
+ responsibility to ensure that the SNMP entity giving access to an
+ instance of this MIB module is properly configured to give access to
+ the objects only to those principals (users) that have legitimate
+ rights to indeed GET or SET (change/create/delete) them.
+
+ Where the operational capability of the printing device are
+ especially vulnerable or difficult to administer, certain objects
+ within this MIB have been tagged as READ-ONLY, preventing
+ modification. Further, for all READ-WRITE objects within the MIB,
+ the working group has included specific conformance guidelines
+
+
+
+Bergman, et al. Standards Track [Page 149]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ stating that vendors are free to implement these objects as READ-
+ ONLY. This conformance allowance should cover cases where specific
+ vendor vulnerabilities may differ from product to product. (See
+ conformance section with regards to MIN-ACCESS clauses).
+
+10. References
+
+10.1. Normative References
+
+ [ASCII] ANSI, "Coded Character Set - 7-bit American Standard Code
+ for Information Interchange", ANSI X3.4-1986.
+
+ [CHARSET] IANA Character Set Registry:
+ http://www.iana.org/assignments/character-sets
+
+ [CHARMIB] IANA Character Set MIB:
+ http://www.iana.org/assignments/ianacharset-mib
+
+ [ISO10175] ISO, "Document Printing Application (DPA)", ISO 10175,
+ 1996.
+
+ [ISO10646] ISO, "Universal Multiple-Octet Coded Character Set (UCS) -
+ Part 1: Architecture and Basic Multilingual Plane", ISO
+ 10646-1, September 2000. ISO, "Universal Multiple-Octet
+ Coded Character Set (UCS) - Part 2: Supplemental Planes",
+ ISO 10646-2, January 2001.
+
+ [PWGMEDIA] IEEE-ISTO PWG "The Printer Working Group Standard for
+ Media Standardized Names", IEEE-ISTO PWG 5101.1-2002.
+
+ [RFC1213] McCloghrie, K. and M. Rose, "Management Information Base
+ for Network Management of TCP/IP-based internets: MIB-II",
+ STD 17, RFC 1213, March 1991.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2277] Alvestrand, H., "IETF Policy on Character Sets and
+ Languages", BCP 18, RFC 2277, January 1998.
+
+ [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO
+ 10646", RFC 3629, November 2003.
+
+
+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 150]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ [RFC2434] Narten, T. and H. Alvestrand, "Guidelines for Writing an
+ IANA Considerations Section in RFCs", BCP 26, RFC 2434,
+ October 1998.
+
+ [RFC2578] McCloghrie, K., Perkins, D., and J. Schoenwaelder,
+ "Structure of Management Information Version 2 (SMIv2)",
+ STD 58, RFC 2578, April 1999.
+
+ [RFC2579] McCloghrie, K., Perkins, D., and J. Schoenwaelder,
+ "Textual Conventions for SMIv2", STD 58, RFC 2579, April
+ 1999.
+
+ [RFC2580] McCloghrie, K., Perkins, D., and J. Schoenwaelder,
+ "Conformance Statements for SMIv2", STD 58, RFC 2580,
+ April 1999.
+
+ [RFC2790] Waldbusser, S. and P. Grillo, "Host Resources MIB", RFC
+ 2790, March 2000.
+
+ [RFC2863] McCloghrie, K. and F. Kastenholz, "The Interfaces Group
+ MIB", RFC 2863, June 2000.
+
+ [RFC3806] Bergman, R., Lewis, H., and I. McDonald, "Printer
+ Finishing MIB", RFC 3806, June 2004.
+
+10.2. Informative References
+
+ [APPLEMAC] Apple staff, "Inside MacIntosh: Networking", 1994.
+
+ [RFC854] Postel, J. and J. Reynolds, "Telnet Protocol
+ Specification", STD 8, RFC 854, May 1983.
+
+ [RFC959] Postel, J. and J. Reynolds, "File Transfer Protocol", STD
+ 9, RFC 959, October 1985.
+
+ [RFC1179] McLaughlin, L., "Line printer daemon protocol", RFC 1179,
+ August 1990.
+
+ [RFC1350] Sollins, K., "The TFTP Protocol (Revision 2)", STD 33, RFC
+ 1350, July 1992.
+
+ [RFC1945] Berners-Lee, T., Fielding, R., and H. Frystyk, "Hypertext
+ Transfer Protocol - HTTP/1.0", RFC 1945, May 1996.
+
+ [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0",
+ RFC 2246, 1999.
+
+
+
+
+
+Bergman, et al. Standards Track [Page 151]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ [RFC2396] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
+ Resource Identifiers (URI): Generic Syntax", RFC 2396,
+ August 1998.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext
+ Transfer Protocol - HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC2821] Klensin, J., Ed., "Simple Mail Transfer Protocol", RFC
+ 2821, April 2001.
+
+ [RFC2822] Resnick, P., Ed., "Internet Message Format", RFC 2822,
+ April 2001.
+
+ [RFC2910] Herriot, R., Ed., Butler, S., Moore, P., Turner, R., and
+ J. Wenn, "Internet Printing Protocol/1.1: Encoding and
+ Transport", RFC 2910, September 2000.
+
+ [RFC2911] Hastings, T., Ed., Herriot, R., deBry, R., Isaacson, S.,
+ and P. Powell, "Internet Printing Protocol/1.1: Model and
+ Semantics", RFC 2911, September 2000.
+
+ [RFC2978] Freed, N. and J. Postel, "IANA Charset Registration
+ Procedures", BCP 19, RFC 2978, October 2000.
+
+ [RFC3232] Reynolds, J., Ed., "Assigned Numbers: RFC 1700 is
+ Replaced by an On-line Database", RFC 3232, January 2002.
+
+ [RFC3285] Gahrns, M. and T. Hain, "Using Microsoft Word to create
+ Internet Drafts and RFCs", RFC 3285, May 2002.
+
+ [RFC3410] Case, J., Mundy, R., Partain, D., and B. Stewart,
+ "Introduction and Applicability Statements for Internet-
+ Standard Management Framework", RFC 3410, December 2002.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 152]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+Appendix A - Glossary of Terms
+
+ Addressability - On the marker, the number of distinct marking units
+ (pels) per unit of addressability unit that can be set; for example,
+ 300 dots per inch is expressed as 300 per 1000 Thousandths Of Inches
+ and 4 dots per millimeter is 4 per 1000 Micrometers. Addressability
+ is not resolution because marks that are one addressability position
+ apart may not be independently resolvable by the eye due to factors
+ such as gain in the area of marks so they overlap or nearly touch.
+
+ Alert - A reportable event for which there is an entry in the alert
+ table.
+
+ Bin - An output sub-unit which may or may not be removable.
+
+ Binary Change Event - An event which comes in pairs; the leading edge
+ event and the trailing edge event. The leading edge event enters a
+ state from which there is only one exit. A binary change event may
+ be critical or non-critical. See unary change event.
+
+ Bursting - The process by which continuous media is separated into
+ individual sheets, typically by bursting along pre-formed
+ perforations.
+
+ Channel - A term used to describe a single source of data which is
+ presented to a printer. The model that we use in describing a
+ printer allows for an arbitrary number of channels. Multiple
+ channels can exist on the same physical port. This is commonly done
+ over Ethernet ports where EtherTalk, TCP/IP, and SPX/IPX protocols
+ can be supplying different data streams simultaneously to a single
+ printer on the same physical port.
+
+ Collation - In multiple copy output, placing the pages from separate
+ copies into separate ordered sets, ready for binding.
+
+ Control Language - A data syntax or language for controlling the
+ printer through the print data channel.
+
+ Critical Alert - An alert triggered by an event which leads to a
+ state in which printing is no longer possible; the printer is
+ stopped.
+
+ Decollating - The process by which the individual parts within a
+ multi-part form are separated and sorted into separate stacks for
+ each part.
+
+ Description - Information about the configuration and capabilities of
+ the printer and its various sub-units.
+
+
+
+Bergman, et al. Standards Track [Page 153]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ DPA - ISO 10175 Document Printing Application standard. A standard
+ for a client server protocol for a print system, including (1)
+ submitting print jobs to and (2) managing print jobs in a spooler.
+
+ Event - A state change in the printer.
+
+ Group - A collection of objects that represent a type of sub-unit of
+ the printer.
+
+ Host Resources MIB - See [RFC2790].
+
+ IANA - Internet Assigned Numbers Authority. See [RFC3232].
+
+ Idempotent - Idempotence is the property of an operation that results
+ in the same state no matter how many times it is executed (at least
+ once). This is a property that is shared by true databases in which
+ operations on data items only change the state of the data item and
+ do not have other side effects. Because the SNMP data model is that
+ of operations on a database, SNMP MIB objects should be assumed to be
+ idempotent. If a MIB object is defined in a non-idempotent way, the
+ this data model can break in subtle ways when faced with packet loss,
+ multiple managers, and other common conditions.
+
+ In order to fulfill the common need for actions to result from
+ SNMP Set operations, SNMP MIB objects can be modeled such that the
+ change in state from one state to another has the side effect of
+ causing an action. It is important to note that with this model,
+ an SNMP operation that sets a value equal to its current value
+ will cause no action. This retains the idempotence of a single
+ command, while allowing actions to be initiated by SNMP SET
+ requests.
+
+ Input - A tray or bin from which instances of the media are obtained
+ and fed into the Media Path.
+
+ Interpreter - The embodiment of an algorithm that processes a data
+ stream consisting of a Page Description Language (PDL) and/or a
+ Control Language.
+
+ Localization - The specification of human language, country, and
+ character set needed to present information to people in their native
+ languages.
+
+ Management Application (a.k.a. Manager) - A program which queries and
+ controls one or more managed nodes.
+
+ Management Station - A physical computer on which one or more
+ management applications can run.
+
+
+
+Bergman, et al. Standards Track [Page 154]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ Media Path - The mechanisms that transport instances of the media
+ from an input, through the marker, possibly through media buffers and
+ duplex pathways, out to the output with optional finishing applied.
+ The inputs and outputs are not part of the Media Path.
+
+ Non-critical Alert - An alert triggered by a reportable event which
+ does not lead to a state in which printing is no longer possible;
+ such an alert may lead to a state from which printing may no longer
+ be possible in the future, such as the low toner state or the alert
+ may be pure informational, such as a configuration change at the
+ printer.
+
+ Output - A bin or stacker which accepts instances of media that have
+ been processed by a printer.
+
+ Page Description Language (PDL) - A data syntax or language for the
+ electronic representation of a document as a sequence of page images.
+
+ Printer - A physical device that takes media from an input source,
+ produces marks on that media according to some page description or
+ page control language and puts the result in some output destination,
+ possibly with finishing applied.
+
+ Printing - The entire process of producing a printed document from
+ generation of the file to be printed, choosing printing properties,
+ selection of a printer, routing, queuing, resource management,
+ scheduling, and finally printing including notifying the user.
+
+ Reportable event - An event that is deemed of interest to a
+ management station watching the printer.
+
+ Status - Information regarding the current operating state of the
+ printer and its various sub-units. This is an abstraction of the
+ exact physical condition of the printer.
+
+ Sub-mechanism - A distinguishable part of a sub-unit.
+
+ Sub-unit - A part of the printer which may be a physical part, such
+ as one of the input sources or a logical part such as an interpreter.
+
+ Tray - An input sub-unit which is typically removable.
+
+ Unary Change Event - An event that indicates a change of state of the
+ printer, but to a state which is (often) just as valid as the state
+ that was left, and from which no return is necessary. See binary
+ change event.
+
+
+
+
+
+Bergman, et al. Standards Track [Page 155]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ Visible state - The portion of the state of the printer that can be
+ examined by a management application.
+
+ Warning - A non-critical alert. See non-critical alert.
+
+Appendix B - Media Size Names
+
+ The PWG Standardized Media Names specification [PWGMEDIA], section 5
+ Self Describing Names, contains the currently recommended media size
+ names. This appendix lists the standardized media size names from
+ ISO/IEC 10175 Document Printing Application (DPA), [ISO10175] as
+ presented in RFC 1759. Management applications are encouraged to use
+ the names from the PWG standard. However, many legacy systems exist
+ that use the DPA names and they are presented here for the
+ convenience of developers.
+
+ A printer implementing the Printer MIB has no knowledge of these
+ names, however; all media sizes in the MIB are given in terms of
+ media dimensions as the values of prtInputMediaDimFeedDirChosen and
+ prtInputMediaDimXFeedDirChosen.
+
+ String name Description
+
+ other
+
+ unknown
+ na-letter or letter North American letter size: 8.5 by 11 inches
+ na-legal or legal North American legal size: 8.5 by 14 inches
+ na-10x13-envelope North American 10x13 envelope
+ size: 10 by 13 inches
+ na-9x12-envelope North American 9x12 envelope
+ size: 9 by 12 inches
+ na-number-10-envelope North American number 10 business envelope
+ size: 4.125 by 9.5 inches
+ na-7x9-envelope North American 7x9 size: 7 by 9 inches
+ na-9x11-envelope North American 9x11 size: 9 by 11 inches
+ na-10x14-envelope North American 10x14 envelope
+ size: 10 by 14 inches
+ na-number-9-envelope North American number 9 business envelope
+ size: 3.875 by 8.875 inches
+ na-6x9-envelope North American 6x9 envelope
+ size: 6 by 9 inches
+ na-10x15-envelope North American 10x15 envelope
+ size: 10 by 15 inches
+ a engineering A size 8.5 inches by 11 inches
+ b engineering B size 11 inches by 17 inches
+ c engineering C size 17 inches by 22 inches
+ d engineering D size 22 inches by 34 inches
+
+
+
+Bergman, et al. Standards Track [Page 156]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ e engineering E size 34 inches by 44 inches
+ iso-a0 ISO A0 size: 841 mm by 1189 mm
+ iso-a1 ISO A1 size: 594 mm by 841 mm
+ iso-a2 ISO A2 size: 420 mm by 594 mm
+ iso-a3 ISO A3 size: 297 mm by 420 mm
+ iso-a4 ISO A4 size: 210 mm by 297 mm
+ iso-a5 ISO A5 size: 148 mm by 210 mm
+ iso-a6 ISO A6 size: 105 mm by 148 mm
+ iso-a7 ISO A7 size: 74 mm by 105 mm
+ iso-a8 ISO A8 size: 52 mm by 74 mm
+ iso-a9 ISO A9 size: 37 mm by 52 mm
+ iso-a10 ISO A10 size: 26 mm by 37 mm
+ iso-b0 ISO B0 size: 1000 mm by 1414 mm
+ iso-b1 ISO B1 size: 707 mm by 1000 mm
+ iso-b2 ISO B2 size: 500 mm by 707 mm
+ iso-b3 ISO B3 size: 353 mm by 500 mm
+ iso-b4 ISO B4 size: 250 mm by 353 mm
+ iso-b5 ISO B5 size: 176 mm by 250 mm
+ iso-b6 ISO B6 size: 125 mm by 176 mm
+ iso-b7 ISO B7 size: 88 mm by 125 mm
+ iso-b8 ISO B8 size: 62 mm by 88 mm
+ iso-b9 ISO B9 size: 44 mm by 62 mm
+ iso-b10 ISO B10 size: 31 mm by 44 mm
+ iso-c0 ISO C0 size: 917 mm by 1297 mm
+ iso-c1 ISO C1 size: 648 mm by 917 mm
+ iso-c2 ISO C2 size: 458 mm by 648 mm
+ iso-c3 ISO C3 size: 324 mm by 458 mm
+ iso-c4 ISO C4 size: 229 mm by 324 mm
+ iso-c5 ISO C5 size: 162 mm by 229 mm
+ iso-c6 ISO C6 size: 114 mm by 162 mm
+ iso-c7 ISO C7 size: 81 mm by 114 mm
+ iso-c8 ISO C8 size: 57 mm by 81 mm
+ iso-designated ISO Designated Long
+ size: 110 mm by 220 mm
+ jis-b0 JIS B0 size 1030 mm by 1456 mm
+ jis-b1 JIS B1 size 728 mm by 1030 mm
+ jis-b2 JIS B2 size 515 mm by 728 mm
+ jis-b3 JIS B3 size 364 mm by 515 mm
+ jis-b4 JIS B4 size 257 mm by 364 mm
+ jis-b5 JIS B5 size 182 mm by 257 mm
+ jis-b6 JIS B6 size 128 mm by 182 mm
+ jis-b7 JIS B7 size 91 mm by 128 mm
+ jis-b8 JIS B8 size 64 mm by 91 mm
+ jis-b9 JIS B9 size 45 mm by 64 mm
+ jis-b10 JIS B10 size 32 mm by 45 mm
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 157]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+Appendix C - Media Names
+
+ For the convenience of management application developers, this
+ appendix lists the standardized media names from ISO/IEC 10175
+ Document Printing Application (DPA), [ISO10175]. Management
+ applications that present a dialogue for choosing media may wish to
+ use these names as an alternative to separately specifying, size,
+ color, and/or type. New names may also be created using this format
+ and the names defined in the PWG Standardized Media Names
+ specification [PWGMEDIA].
+
+ Using standard media names will mean that a single management
+ application dealing with printers from different vendors and under
+ different system mangers will tend to use the same names for the same
+ media. If selection of media by name is used, the attributes (size,
+ type or color) implied by the name must be explicitly mapped to the
+ appropriate object (prtInputMediaDimFeedDirDeclared,
+ prtInputMediaDimXFeedDirDeclared, prtInputMediaType and
+ prtInputMediaColor) in the MIB. The object prtInputMediaName is
+ intended for display to an operator and is purely descriptive. The
+ value in prtInputMediaName is not interpreted by the printer so using
+ a standard name for this value will not change any of the other media
+ attributes nor will it cause an alert if the media in the input sub-
+ unit does not match the name.
+
+ Simple Name Descriptor Text
+
+ other
+ unknown
+ iso-a4-white Specifies the ISO A4 white medium with
+ size: 210 mm by 297 mm as defined in ISO 216
+ iso-a4-coloured Specifies the ISO A4 colored medium with
+ size: 210 mm by 297 mm as defined in ISO 216
+ iso-a4-transparent Specifies the ISO A4 transparent medium with
+ size: 210 mm by 297 mm as defined in ISO 216
+ iso-a3-white Specifies the ISO A3 white medium with
+ size: 297 mm by 420 mm as defined in ISO 216
+ iso-a3-coloured Specifies the ISO A3 colored medium with
+ size: 297 mm by 420 mm as defined in ISO 216
+ iso-a5-white Specifies the ISO A5 white medium with
+ size: 148 mm by 210 mm as defined in ISO 216
+ iso-a5-coloured Specifies the ISO A5 colored medium with
+ size: 148 mm by 210 mm as defined in ISO 216
+ iso-b4-white Specifies the ISO B4 white medium with
+ size: 250 mm by 353 mm as defined in ISO 216
+ iso-b4-coloured Specifies the ISO B4 colored medium with
+ size: 250 mm by 353 mm as defined in ISO 216
+
+
+
+
+Bergman, et al. Standards Track [Page 158]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ iso-b5-white Specifies the ISO B5 white medium with
+ size: 176 mm by 250 mm as defined in ISO 216
+ iso-b5-coloured Specifies the ISO B5 colored medium with
+ size: 176 mm by 250 mm as defined in ISO 216
+ jis-b4-white Specifies the JIS B4 white medium with
+ size: 257 mm by 364 mm as defined in JIS P0138
+ jis-b4-coloured Specifies the JIS B4 colored medium with
+ size: 257 mm by 364 mm as defined in JIS P0138
+ jis-b5-white Specifies the JIS B5 white medium with
+ size: 182 mm by 257 mm as defined in JIS P0138
+ jis-b5-coloured Specifies the JIS B5 colored medium with
+ size: 182 mm by 257 mm as defined in JIS P0138
+
+ The following standard values are defined for North American media:
+
+ na-letter-white Specifies the North American letter white
+ medium with size: 8.5 inches by 11 inches
+ na-letter-coloured Specifies the North American letter colored
+ medium with size: 8.5 inches by 11 inches
+ na-letter-transparent
+ Specifies the North American letter
+ transparent medium with size: 8.5 inches
+ by 11 inches
+ na-legal-white Specifies the North American legal white
+ medium with size: 8.5 inches by 14 inches
+ na-legal-coloured Specifies the North American legal colored
+ medium with size: 8.5 inches by 14 inches
+
+ The following standard values are defined for envelopes:
+
+ iso-b5-envelope Specifies the ISO B5 envelope medium
+ with size: 176 mm by 250 mm
+ as defined in ISO 216 and ISO 269
+ iso-b4-envelope Specifies the ISO B4 envelope medium
+ with size: 250 mm by 353 mm
+ as defined in ISO 216
+ iso-c4-envelope Specifies the ISO C4 envelope medium
+ with size: 229 mm by 324 mm
+ as defined in ISO 216 and ISO 269
+ iso-c5-envelope Specifies the ISO C5 envelope medium
+ with size: 162 mm by 229 mm
+ as defined in ISO 269
+ iso-designated-long-envelope
+ Specifies the ISO Designated Long envelope
+ medium with size: 110 mm by 220 mm
+ as defined in ISO 269
+
+
+
+
+
+Bergman, et al. Standards Track [Page 159]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ na-10x13-envelope Specifies the North American 10x13 envelope
+ medium with size: 10 inches by 13 inches
+ na-9x12-envelope Specifies the North American 9x12 envelope
+ medium with size: 9 inches by 12 inches
+ na-number-10-envelope
+ Specifies the North American number 10
+ business envelope medium with size: 4.125
+ inches by 9.5 inches
+ na-7x9-envelope Specifies the North American 7x9 inch envelope
+
+ na-9x11-envelope Specifies the North American 9x11 inch envelope
+
+ na-10x14-envelope Specifies the North American 10x14 inch envelope
+
+ na-number-9-envelope
+ Specifies the North American number 9
+ business envelope 3.875 by 8.875 inches
+ na-6x9-envelope Specifies the North American 6x9 inch envelope
+
+ na-10x15-envelope Specifies the North American 10x15 inch envelope
+
+ The following standard values are defined for the less commonly
+ used media (white-only):
+
+ iso-a0-white Specifies the ISO A0 white medium
+ with size: 841 mm by 1189 mm
+ as defined in ISO 216
+ iso-a1-white Specifies the ISO A1 white medium
+ with size: 594 mm by 841 mm
+ as defined in ISO 216
+ iso-a2-white Specifies the ISO A2 white medium
+ with size: 420 mm by 594 mm
+ as defined in ISO 216
+ iso-a6-white Specifies the ISO A6 white medium
+ with size: 105 mm by 148 mm
+ as defined in ISO 216
+ iso-a7-white Specifies the ISO A7 white medium
+ with size: 74 mm by 105 mm
+ as defined in ISO 216
+ iso-a8-white Specifies the ISO A8 white medium
+ with size: 52 mm by 74 mm
+ as defined in ISO 216
+ iso-a9-white Specifies the ISO A9 white medium
+ with size: 39 mm by 52 mm
+ as defined in ISO 216
+ iso-a10-white Specifies the ISO A10 white medium
+ with size: 26 mm by 37 mm
+ as defined in ISO 216
+
+
+
+Bergman, et al. Standards Track [Page 160]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ iso-b0-white Specifies the ISO B0 white medium
+ with size: 1000 mm by 1414 mm
+ as defined in ISO 216
+ iso-b1-white Specifies the ISO B1 white medium
+ with size: 707 mm by 1000 mm
+ as defined in ISO 216
+ iso-b2-white Specifies the ISO B2 white medium
+ with size: 500 mm by 707 mm
+ as defined in ISO 216
+ iso-b3-white Specifies the ISO B3 white medium
+ with size: 353 mm by 500 mm
+ as defined in ISO 216
+ iso-b6-white Specifies the ISO B6 white medium
+ with size: 125 mm by 176 mm i
+ as defined in ISO 216
+ iso-b7-white Specifies the ISO B7 white medium
+ with size: 88 mm by 125 mm
+ as defined in ISO 216
+ iso-b8-white Specifies the ISO B8 white medium
+ with size: 62 mm by 88 mm
+ as defined in ISO 216
+ iso-b9-white Specifies the ISO B9 white medium
+ with size: 44 mm by 62 mm
+ as defined in ISO 216
+ iso-b10-white Specifies the ISO B10 white medium
+ with size: 31 mm by 44 mm
+ as defined in ISO 216
+ jis-b0-white Specifies the JIS B0 white medium with size:
+ 1030 mm by 1456 mm
+ jis-b1-white Specifies the JIS B1 white medium with size:
+ 728 mm by 1030 mm
+ jis-b2-white Specifies the JIS B2 white medium with size:
+ 515 mm by 728 mm
+ jis-b3-white Specifies the JIS B3 white medium with size:
+ 364 mm by 515 mm
+ jis-b6-white Specifies the JIS B6 white medium with size:
+ 257 mm by 364 mm
+ jis-b7-white Specifies the JIS B7 white medium with size:
+ 182 mm by 257 mm
+ jis-b8-white Specifies the JIS B8 white medium with size:
+ 128 mm by 182 mm
+ jis-b9-white Specifies the JIS B9 white medium with size:
+ 91 mm by 128 mm
+ jis-b10-white Specifies the JIS B10 white medium with size:
+ 64 mm by 91 mm
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 161]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ The following standard values are defined for engineering media:
+ a Specifies the engineering A size medium with
+ size: 8.5 inches by 11 inches
+ b Specifies the engineering B size medium with
+ size: 11 inches by 17 inches
+ c Specifies the engineering C size medium with
+ size: 17 inches by 22 inches
+ d Specifies the engineering D size medium with
+ size: 22 inches by 34 inches
+ e Specifies the engineering E size medium with
+ size: 34 inches by 44 inches
+
+Appendix D - Roles of Users
+
+ Background
+
+ The need for "Role Models" stemmed in large part from the need to
+ understand the importance of any given proposed object for the MIB.
+ Many times the real world need for a proposed object would be debated
+ within the group; the debate would typically result in the need to
+ describe the potential usage of the object in terms of a "live"
+ person performing some type of printing-related task.
+
+ Determining the value of a proposed object through identification of
+ the associated human users was found to be so common that a more
+ formalized model was required for consistent analysis. The model
+ describing categories of human-oriented tasks is called "Role Models"
+ in this document.
+
+ In developing the Role Models it was necessary to identify the
+ common, primary tasks that humans typically face when interacting
+ with a printer and its related printing system(s). It was expected
+ that certain kinds of tasks would serve to identify the various Role
+ Models.
+
+ In presenting the set of Role Models, the set of "Common Print System
+ Tasks" are first presented, followed by the set of Role Model
+ definitions. Finally, a simple matrix is presented in which Role
+ Models and Tasks are cross-compared.
+
+ Common Print System Tasks
+
+ Upon researching the many tasks encountered by humans in dealing with
+ printers and printing systems, the following were found to be
+ pervasive within any operating environment:
+
+ Printer job state - Determine the status of a job without a printer.
+
+
+
+
+Bergman, et al. Standards Track [Page 162]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ Printer capabilities - Determine the current capabilities of a
+ printer, for example, the available media sizes, two-sided printing,
+ a particular type of interpreter, etc.
+
+ Printer job submission - Submit a print job to a printer.
+
+ Printer job removal - Remove a job from a printer.
+
+ Notification of events - Receive notification of the existence of a
+ defined printer event. An event can be of many types, including
+ warnings, errors, job stage completion (e.g., "job done"), etc.
+
+ Printer configuration - Query the current configuration of a printer.
+
+ Printer consumables - Determine the current state of any and all
+ consumables within a printer.
+
+ Print job identification - Determine the identification of a job
+ within a printer.
+
+ Internal printer status - Determine the current status of the
+ printer.
+
+ Printer identification - Determine the identity of a printer.
+ Printer location - Determine the physical location of a printer.
+
+ Local system configuration - Determine various aspects of the current
+ configuration of the local system involved with the operation of a
+ printer.
+
+ These "tasks" cover a large spectrum of requirements surrounding the
+ operation of a printer in a network environment. This list serves as
+ the basis for defining the various Role Models described below.
+
+ Proposed Role Models
+
+ Following is the list of "Role Models" used to evaluate the
+ requirements for any given Printer MIB object. Note that the keyword
+ enclosed in parentheses represents an abbreviation for the particular
+ Role Model in the matrix described later in this document.
+
+ User (USER) - A person or application that submits print jobs to the
+ printer; typically viewed as the "end user" within the overall
+ printing environment.
+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 163]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ Operator (OP) - A person responsible for maintaining a printer on a
+ day-to-day basis, including such tasks as filling empty media trays,
+ emptying full output trays, replacing toner cartridges, clearing
+ simple paper jams, etc.
+
+ Technician (TECH) - A person responsible for repairing a
+ malfunctioning printer, performing routine preventive maintenance,
+ and other tasks that typically require advanced training on the
+ printer internals. An example of a "technician" would be a
+ manufacturer's Field Service representative, or other person formally
+ trained by the manufacturer or similar representative.
+
+ System Manager (MGR) - A person responsible for configuration and
+ troubleshooting of components involved in the overall printing
+ environment, including printers, print queues and network
+ connectivity issues. This person is typically responsible for
+ ensuring the overall operational integrity of the print system
+ components, and is typically viewed as the central point of
+ coordination among all other Role Models.
+
+ Help Desk (HELP) - A person responsible for supporting Users in
+ their printing needs, including training Users and troubleshooting
+ Users' printing problems.
+
+ Asset Manager (AM) - A person responsible for managing an
+ organization's printing system assets (primarily printers). Such a
+ person needs to be able to identify and track the location of
+ printing assets on an ongoing basis.
+
+ Capacity Planner (CP) - A person responsible for tracking the usage
+ of printing resources on an ongoing basis for the purpose of planning
+ printer acquisitions and/or placement of printers based on usage
+ trends.
+
+ Installer (INST) - A person or application responsible for
+ installing or configuring printing system components on a local
+ system.
+
+ Accountant (ACCT) - A person responsible for tracking the usage of
+ printing resources on an ongoing basis for the purpose of charging
+ Users for resources used.
+
+ Matrix of Common Print System Tasks and Role Models
+
+ To better understand the relationship between the set of defined
+ "Common Print System Tasks" and the various "Role Models," the
+ following matrix is provided.
+
+
+
+
+Bergman, et al. Standards Track [Page 164]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ It is important to recognize that many of the tasks will appear to be
+ applicable to many of the Role Models. However, when considering the
+ actual context of a task, it is very important to realize that often
+ the actual context of a task is such that the Role Model can change.
+
+ For example, it is obvious that a "System Manager" must be able to
+ submit print jobs to a printer; however, when submitting a print job,
+ a person identified as a "System Manager" is actually operating in
+ the context of a "User" in this case; hence, the requirement to
+ submit a print job is not listed as a requirement for a System
+ Manager.
+
+ Conversely, while a "User" must be able to remove a job previously
+ submitted to a printer, an "Operator" is often expected to be able to
+ remove any print job from any printer; hence, print job removal is a
+ (subtly different) requirement for both the "User" and "Operator"
+ Role Models.
+
+ Role Models
+ -----------
+
+ Requirement Area USER OP TECH MGR HELP AM CP INST ACCT
+ Print job status xx xx xx xx xx
+ Printer capabilities xx xx xx
+ Print job submission xx
+ Print job removal xx xx
+ Notification of events xx xx
+ Printer configuration xx xx
+ Printer consumables xx xx xx
+ Print job identification xx xx xx xx xx
+ Internal printer status xx xx xx
+ Printer identification xx xx xx xx xx xx xx
+ Printer location xx
+ Local system configuration xx xx
+
+Appendix E - Overall Printer Status Table
+
+ The Status Table establishes a convention for the top 25 printer
+ errors. The table defines a suggested relationship between various
+ printer states and the variables Printer hrDeviceStatus,
+ hrPrinterStatus, hrPrinterDetectedErrorState, prtAlertGroup,
+ prtAlertCode and various sub-unit status variables (prtInputStatus,
+ prtOutputStatus, prtMarkerStatus, prtMediaPathStatus and
+ prtChannelStatus). This table is the recommended implementation of
+ these variables. It is provided to guide implementors of this MIB
+ and users of the MIB by providing a sample set of states and the
+ variable values that are expected to be produced as result of that
+ state. This information supplements that provided in Section
+
+
+
+Bergman, et al. Standards Track [Page 165]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ 2.2.13.2 "Overall Printer Status". This is not an exhaustive list
+ rather it is a guideline.
+
+ The definition of PrtSubUnitStatusTC specifies that SubUnitStatus is
+ an integer that is the sum of 5 distinct values/states: Availability,
+ Critical, Non-Critical, On-line and Transitioning. Thus when a non-
+ critical alert or alerts are present the values for Availability,
+ On-Line and Transitioning will be summed with the Non- Critical
+ Alerts (8) value.
+
+ The table was generated in landscape format and is located at
+ ftp://ftp.pwg.org/pub/pwg/pmp/contributions/Top25Errors.pdf.
+
+Appendix F - Participants
+
+ The Printer MIB Working Group would like to extend a special thank
+ you to the following individuals that put forth a significant effort
+ to review this document and provide numerous suggestions for
+ improvement.
+
+ David Harrington - Enterasys Networks
+ Juergen Schoenwaelder - TU Braunschweig
+ Bert Wijnen - Lucent Technologies and IETF Op & Mngmt, Area Director
+
+ This version of the Printer MIB would not be possible without the
+ previous work that resulted in RFC 1759. The authors of the Printer
+ MIB version 2 would like to acknowledge the following individuals for
+ their efforts in developing the base for this document. A special
+ recognition is also extended to Steve Waldbusser, who provided
+ significant technical guidance in the development of the architecture
+ of the Printer MIB.
+
+ Joel Gyllenskog - Microworks
+ Tom Hastings - Xerox
+ Jay Martin - Underscore, Inc.
+ Ron Smith - Texas Instruments
+ Steve Waldbusser - Lucent Technologies
+ Don Wright - Lexmark
+ Steve Zilles - Adobe
+
+ The following people attended at least one meeting of the Printer MIB
+ Working Group for version 2; many attended most meetings.
+
+ Ron Bergman - Hitachi Printing Solutions
+ Luis Cubero - Hewlett-Packard
+ Jay Cummings - Novell
+ Andy Davidson - Tektronix
+ Lee Farrell - Canon
+
+
+
+Bergman, et al. Standards Track [Page 166]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ Tom Hastings - Xerox
+ Scott Isaacson - Novell
+ Binnur Al-Kazily - Hewlett-Packard
+ Rick Landau - Digital Equipment Corporation
+ David Kellerman - Northlake Software
+ Harry Lewis - IBM
+ Pete Loya - Hewlett-Packard
+ Jay Martin - Underscore, Inc.
+ Bob Pentecost - Hewlett-Packard
+ Dave Roach - Unisys
+ Stuart Rowley - Kyocera
+ Bob Setterbo - Adobe
+ Mike Timperman - Lexmark
+ Randy Turner - 2Wire, Inc.
+ Bill Wagner - NETsilicon, Inc.
+ Chris Wellens - Interworking Labs
+ Craig Whittle - Sharp Labs
+ Don Wright - Lexmark
+ Lloyd Young - Lexmark
+ Atsushi Yuki - Kyocera
+ Steve Zilles - Adobe
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 167]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+Significant Contributors
+
+ Ray Casterline
+ Lighthouse Solutions, LLC
+
+ Phone: (716) 218-9910
+ EMail: RayCasterline@lhsolutions.com
+
+ Gary Gocek
+
+ Phone: (585) 223-3826
+ EMail: gary@gocek.org
+
+ Thomas N. Hastings
+ Xerox Corporation
+
+ Phone: (310) 333-6413
+ EMail: hastings@cp10.es.xerox.com
+
+ Scott Isaacson
+ Novell
+
+ Phone: (801) 861-7366
+ EMail: sisaacson@novell.com
+
+ Binnur Al-Kazily
+ Hewlett-Packard, Inc.
+
+ Phone: (208) 396-6372
+ EMail: binnur_al-kazily@hp.com
+
+ David Kellerman
+ Northlake Software
+
+ Phone: (503) 228-3383
+ EMail: kellerman@nls.com
+
+ Matt King
+ Lexmark International
+
+ Phone: (859) 232-6907
+ EMail: emking@lexmark.com
+
+ Jay Martin
+ Underscore, Inc.
+
+ Phone: (603) 889-7000
+ EMail: jkm@underscore.com
+
+
+
+Bergman, et al. Standards Track [Page 168]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+
+ Mike McKay
+ Novell, Inc.
+
+ Bob Pentecost
+ Hewlett-Packard
+
+ Phone: (208) 396-3312
+ EMail: bpenteco@boi.hp.com
+
+ Stuart Rowley
+ Kyocera
+
+ Phone: (510) 299-7206
+ EMail: stuart.rowley@kyocera.com
+
+ Gail Songer
+ Peerless Systems Networking
+
+ Phone: (650) 569-4414
+ EMail: gsonger@peerless.com
+
+ Randy Turner
+ 2Wire, Inc.
+
+ Phone (408) 895-1216
+ EMail: rturner@2wire.com
+
+ William Wagner
+ NETsilicon, Inc.
+
+ Phone: (781) 398-4588
+ EMail: WWagner@NetSilicon.com
+
+ Chris Wellens
+ Interworking Labs
+
+ Phone: (408) 685-3190
+ EMail: chrisw@iwl.com
+
+ F.D. Wright
+ Lexmark International
+
+ Phone: (859) 232-4808
+ EMail: don@lexmark.com
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 169]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+ Lloyd Young
+ Lexmark International
+
+ Phone: (859) 232-5150
+ EMail: lpyoung@lexmark.com
+
+ Stephen N. Zilles
+ Adobe Systems, Inc.
+
+ Phone: (415) 962-4766
+ EMail: szilles@adobe.com
+
+Authors' Addresses
+
+ Ron Bergman (Chairman)
+ Hitachi Printing Solutions America
+ 2635 Park Center Drive
+ Simi Valley, CA 93065-6209
+
+ Phone: (805) 578-4421
+ EMail: Ron.Bergman@hitachi-ps.us
+
+
+ Harry Lewis
+ IBM
+ 6300 Diagonal Hwy.
+ Boulder, CO 80301
+
+ Phone (303) 924-5337
+ EMail: harryl@us.ibm.com
+
+
+ Ira McDonald
+ High North Inc
+ P.O. Box 221
+ Grand Marais, MI 49839
+
+ Phone: (906) 494-2434 or (906) 494-2697
+ EMail: imcdonald@sharplabs.com
+
+
+
+
+
+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 170]
+
+RFC 3805 Printer MIB v2 June 2004
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2004). This document is subject
+ to the rights, licenses and restrictions contained in BCP 78, and
+ except as set forth therein, the authors retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the procedures with respect to rights in RFC documents can be
+ found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at ietf-
+ ipr@ietf.org.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+Bergman, et al. Standards Track [Page 171]
+
diff --git a/standards/rfc3808.txt b/standards/rfc3808.txt
new file mode 100644
index 000000000..bca682341
--- /dev/null
+++ b/standards/rfc3808.txt
@@ -0,0 +1,787 @@
+
+
+
+
+
+
+Network Working Group I. McDonald
+Request for Comments: 3808 High North
+Category: Informational June 2004
+
+
+ IANA Charset MIB
+
+Status of this Memo
+
+ This memo provides information for the Internet community. It does
+ not specify an Internet standard of any kind. Distribution of this
+ memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2004).
+
+Abstract
+
+ This memo defines a portion of the Management Information Base (MIB)
+ for use with network management protocols in the Internet community.
+ This IANA Charset MIB is now an IANA registry. In particular, a
+ single textual convention 'IANACharset' is defined that may be used
+ to specify charset labels in MIB objects. 'IANACharset' was
+ extracted from Printer MIB v2 (RFC 3805). 'IANACharset' was
+ originally defined (and mis-named) as 'CodedCharSet' in Printer MIB
+ v1 (RFC 1759). A tool has been written in C, that may be used by
+ IANA to regenerate this IANA Charset MIB, when future charsets are
+ registered in accordance with the IANA Charset Registration
+ Procedures (RFC 2978).
+
+Table of Contents
+
+ 1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . 2
+ 1.1. Conformance Terminology . . . . . . . . . . . . . . . . 2
+ 1.2. Charset Terminology . . . . . . . . . . . . . . . . . . 2
+ 2. The Internet-Standard Management Framework. . . . . . . . . . 2
+ 3. Generation of IANA Charset MIB. . . . . . . . . . . . . . . . 3
+ 4. Definition of IANA Charset MIB. . . . . . . . . . . . . . . . 3
+ 5. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 10
+ 6. Internationalization Considerations . . . . . . . . . . . . . 10
+ 7. Security Considerations . . . . . . . . . . . . . . . . . . . 11
+ 8. Acknowledgements. . . . . . . . . . . . . . . . . . . . . . . 11
+ 9. References. . . . . . . . . . . . . . . . . . . . . . . . . . 11
+ 9.1. Normative References. . . . . . . . . . . . . . . . . . 11
+ 9.2. Informative References. . . . . . . . . . . . . . . . . 12
+ 10. Authors' Addresses. . . . . . . . . . . . . . . . . . . . . . 13
+ 11. Full Copyright Statement. . . . . . . . . . . . . . . . . . . 14
+
+
+
+McDonald Informational [Page 1]
+
+RFC 3808 IANA Charset MIB June 2004
+
+
+1. Introduction
+
+ This IANA Charset MIB [CHARMIB] module defines the single textual
+ convention 'IANACharset'. Once adopted, all future versions of the
+ IANA Charset MIB [CHARMIB] may be machine-generated whenever the IANA
+ Charset Registry [CHARSET] is updated by IANA staff according to the
+ procedures defined in [RFC2978], using the utility [CHARGEN]
+ described in section 3 of this document or any other machine-
+ generation method.
+
+ It is strongly recommended that future updates to the IANA Charset
+ MIB [CHARMIB] be machine-generated (rather than hand-edited) to avoid
+ asynchrony between the IANA Charset Registry [CHARSET] and the IANA
+ Charset MIB [CHARMIB].
+
+ Note: Questions and comments on this IANA Charset MIB [CHARMIB]
+ should be sent to the editor (imcdonald@sharplabs.com) and IANA
+ (iana@iana.org) with a copy to the IETF Charsets mailing list (ietf-
+ charset@iana.org).
+
+1.1. Conformance Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in BCP 14, RFC 2119
+ [RFC2119].
+
+1.2. Charset Terminology
+
+ The following terms are used in this specification, exactly as
+ defined in section 1 'Definitions and Notation' of the IANA Charset
+ Registration Procedures [RFC2978]: "character", "charset", "coded
+ character set (CCS)", and "character encoding scheme (CES)".
+
+2. The Internet-Standard Management Framework
+
+ For a detailed overview of the documents that describe the current
+ Internet-Standard Management Framework, please refer to section 7 of
+ RFC 3410 [RFC3410].
+
+ Managed objects are accessed via a virtual information store, termed
+ the Management Information Base or MIB. MIB objects are generally
+ accessed through the Simple Network Management Protocol (SNMP).
+ Objects in the MIB are defined using the mechanisms defined in the
+ Structure of Management Information (SMI). This memo specifies a MIB
+ module that is compliant to the SMIv2, which is described in STD 58,
+ RFC 2578 [RFC2578], STD 58, RFC 2579 [RFC2579], and STD 58, RFC 2580
+ [RFC2580].
+
+
+
+McDonald Informational [Page 2]
+
+RFC 3808 IANA Charset MIB June 2004
+
+
+3. Generation of IANA Charset MIB
+
+ Intellectual Property: The C language utility 'ianachar.c' [CHARGEN]
+ and the IANA Charset MIB template file [CHARTEMP] are hereby donated
+ by the author (Ira McDonald) to IANA, in perpetuity, free of license
+ or any other restraint.
+
+ The [CHARGEN] utility may be used to generate an updated version of
+ the 'IANACharset' textual convention by reading and parsing the
+ (currently plaintext) IANA Charset Registry [CHARSET].
+
+ This utility parses each charset registration, finding (in order):
+
+ 1) The 'Name' field (which is saved for a fallback - see below);
+
+ 2) The 'MIBenum' field (which contains the IANA-assigned positive
+ decimal enum value); and
+
+ 3) The (usually present) 'Alias' field that begins with 'cs' (that
+ contains the IANA-assigned enum label). If an 'Alias' field is
+ not found, the utility constructs one from the 'Name' field by:
+
+ - Beginning the enum label with a lowercase 'cs' prefix;
+
+ - Copying _only_ alpha/numeric characters from the 'Name' field
+ to the enum label (ignoring punctuation, whitespace, etc.).
+
+4. Definition of IANA Charset MIB
+
+IANA-CHARSET-MIB DEFINITIONS ::= BEGIN
+-- http://www.iana.org/assignments/ianacharset-mib
+
+IMPORTS
+ MODULE-IDENTITY,
+ mib-2
+ FROM SNMPv2-SMI -- [RFC2578]
+ TEXTUAL-CONVENTION
+ FROM SNMPv2-TC; -- [RFC2579]
+
+ianaCharsetMIB MODULE-IDENTITY
+ LAST-UPDATED "200406080000Z"
+ ORGANIZATION "IANA"
+ CONTACT-INFO " Internet Assigned Numbers Authority
+
+ Postal: ICANN
+ 4676 Admiralty Way, Suite 330
+ Marina del Rey, CA 90292
+
+
+
+
+McDonald Informational [Page 3]
+
+RFC 3808 IANA Charset MIB June 2004
+
+
+ Tel: +1 310 823 9358
+ E-Mail: iana@iana.org"
+
+ DESCRIPTION "This MIB module defines the IANACharset
+ TEXTUAL-CONVENTION. The IANACharset TC is used to
+ specify the encoding of string objects defined in
+ a MIB.
+
+ Each version of this MIB will be released based on
+ the IANA Charset Registry file (see RFC 2978) at
+ http://www.iana.org/assignments/character-sets.
+
+ Note: The IANACharset TC, originally defined in
+ RFC 1759, was inaccurately named CodedCharSet.
+
+ Note: Best practice is to define new MIB string
+ objects with invariant UTF-8 (RFC 3629) syntax
+ using the SnmpAdminString TC (defined in RFC 3411)
+ in accordance with IETF Policy on Character Sets and
+ Languages (RFC 2277).
+
+ Copyright (C) The Internet Society (2004). The
+ initial version of this MIB module was published
+ in RFC 3808; for full legal notices see the RFC
+ itself. Supplementary information may be
+ available on
+ http://www.ietf.org/copyrights/ianamib.html."
+
+ -- revision history
+
+ REVISION "200406080000Z"
+ DESCRIPTION "Original version transferred from Printer MIB,
+ generated from the IANA maintained assignments
+ http://www.iana.org/assignments/character-sets."
+
+ ::= { mib-2 106 }
+
+IANACharset ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Specifies an IANA registered 'charset' - coded character set
+ (CCS) plus optional character encoding scheme (CES) - terms
+ defined in 'IANA Charset Registration Procedures' (RFC 2978).
+
+ Objects of this syntax are used to specify the encoding for
+ string objects defined in one or more MIBs. For example, the
+ prtLocalizationCharacterSet, prtInterpreterDefaultCharSetIn, and
+ prtInterpreterDefaultCharSetOut objects defined in Printer MIB.
+
+
+
+McDonald Informational [Page 4]
+
+RFC 3808 IANA Charset MIB June 2004
+
+
+ The current list of 'charset' names and enumerated values
+ is contained in the IANA Character Set Registry at:
+
+ http://www.iana.org/assignments/character-sets
+
+ Enum names are derived from the IANA Charset Registry 'Alias'
+ fields that begin with 'cs' (for character set).
+ Enum values are derived from the parallel 'MIBenum' fields."
+ SYNTAX INTEGER {
+ other(1), -- used if the designated
+ -- character set is not currently
+ -- registered by IANA
+ unknown(2), -- used as a default value
+ csASCII(3),
+ csISOLatin1(4),
+ csISOLatin2(5),
+ csISOLatin3(6),
+ csISOLatin4(7),
+ csISOLatinCyrillic(8),
+ csISOLatinArabic(9),
+ csISOLatinGreek(10),
+ csISOLatinHebrew(11),
+ csISOLatin5(12),
+ csISOLatin6(13),
+ csISOTextComm(14),
+ csHalfWidthKatakana(15),
+ csJISEncoding(16),
+ csShiftJIS(17),
+ csEUCPkdFmtJapanese(18),
+ csEUCFixWidJapanese(19),
+ csISO4UnitedKingdom(20),
+ csISO11SwedishForNames(21),
+ csISO15Italian(22),
+ csISO17Spanish(23),
+ csISO21German(24),
+ csISO60DanishNorwegian(25),
+ csISO69French(26),
+ csISO10646UTF1(27),
+ csISO646basic1983(28),
+ csINVARIANT(29),
+ csISO2IntlRefVersion(30),
+ csNATSSEFI(31),
+ csNATSSEFIADD(32),
+ csNATSDANO(33),
+ csNATSDANOADD(34),
+ csISO10Swedish(35),
+ csKSC56011987(36),
+ csISO2022KR(37),
+
+
+
+McDonald Informational [Page 5]
+
+RFC 3808 IANA Charset MIB June 2004
+
+
+ csEUCKR(38),
+ csISO2022JP(39),
+ csISO2022JP2(40),
+ csISO13JISC6220jp(41),
+ csISO14JISC6220ro(42),
+ csISO16Portuguese(43),
+ csISO18Greek7Old(44),
+ csISO19LatinGreek(45),
+ csISO25French(46),
+ csISO27LatinGreek1(47),
+ csISO5427Cyrillic(48),
+ csISO42JISC62261978(49),
+ csISO47BSViewdata(50),
+ csISO49INIS(51),
+ csISO50INIS8(52),
+ csISO51INISCyrillic(53),
+ csISO54271981(54),
+ csISO5428Greek(55),
+ csISO57GB1988(56),
+ csISO58GB231280(57),
+ csISO61Norwegian2(58),
+ csISO70VideotexSupp1(59),
+ csISO84Portuguese2(60),
+ csISO85Spanish2(61),
+ csISO86Hungarian(62),
+ csISO87JISX0208(63),
+ csISO88Greek7(64),
+ csISO89ASMO449(65),
+ csISO90(66),
+ csISO91JISC62291984a(67),
+ csISO92JISC62991984b(68),
+ csISO93JIS62291984badd(69),
+ csISO94JIS62291984hand(70),
+ csISO95JIS62291984handadd(71),
+ csISO96JISC62291984kana(72),
+ csISO2033(73),
+ csISO99NAPLPS(74),
+ csISO102T617bit(75),
+ csISO103T618bit(76),
+ csISO111ECMACyrillic(77),
+ csa71(78),
+ csa72(79),
+ csISO123CSAZ24341985gr(80),
+ csISO88596E(81),
+ csISO88596I(82),
+ csISO128T101G2(83),
+ csISO88598E(84),
+ csISO88598I(85),
+
+
+
+McDonald Informational [Page 6]
+
+RFC 3808 IANA Charset MIB June 2004
+
+
+ csISO139CSN369103(86),
+ csISO141JUSIB1002(87),
+ csISO143IECP271(88),
+ csISO146Serbian(89),
+ csISO147Macedonian(90),
+ csISO150(91),
+ csISO151Cuba(92),
+ csISO6937Add(93),
+ csISO153GOST1976874(94),
+ csISO8859Supp(95),
+ csISO10367Box(96),
+ csISO158Lap(97),
+ csISO159JISX02121990(98),
+ csISO646Danish(99),
+ csUSDK(100),
+ csDKUS(101),
+ csKSC5636(102),
+ csUnicode11UTF7(103),
+ csISO2022CN(104),
+ csISO2022CNEXT(105),
+ csUTF8(106),
+ csISO885913(109),
+ csISO885914(110),
+ csISO885915(111),
+ csISO885916(112),
+ csGBK(113),
+ csGB18030(114),
+ csOSDEBCDICDF0415(115),
+ csOSDEBCDICDF03IRV(116),
+ csOSDEBCDICDF041(117),
+ csUnicode(1000),
+ csUCS4(1001),
+ csUnicodeASCII(1002),
+ csUnicodeLatin1(1003),
+ csUnicodeIBM1261(1005),
+ csUnicodeIBM1268(1006),
+ csUnicodeIBM1276(1007),
+ csUnicodeIBM1264(1008),
+ csUnicodeIBM1265(1009),
+ csUnicode11(1010),
+ csSCSU(1011),
+ csUTF7(1012),
+ csUTF16BE(1013),
+ csUTF16LE(1014),
+ csUTF16(1015),
+ csCESU8(1016),
+ csUTF32(1017),
+ csUTF32BE(1018),
+
+
+
+McDonald Informational [Page 7]
+
+RFC 3808 IANA Charset MIB June 2004
+
+
+ csUTF32LE(1019),
+ csBOCU1(1020),
+ csWindows30Latin1(2000),
+ csWindows31Latin1(2001),
+ csWindows31Latin2(2002),
+ csWindows31Latin5(2003),
+ csHPRoman8(2004),
+ csAdobeStandardEncoding(2005),
+ csVenturaUS(2006),
+ csVenturaInternational(2007),
+ csDECMCS(2008),
+ csPC850Multilingual(2009),
+ csPCp852(2010),
+ csPC8CodePage437(2011),
+ csPC8DanishNorwegian(2012),
+ csPC862LatinHebrew(2013),
+ csPC8Turkish(2014),
+ csIBMSymbols(2015),
+ csIBMThai(2016),
+ csHPLegal(2017),
+ csHPPiFont(2018),
+ csHPMath8(2019),
+ csHPPSMath(2020),
+ csHPDesktop(2021),
+ csVenturaMath(2022),
+ csMicrosoftPublishing(2023),
+ csWindows31J(2024),
+ csGB2312(2025),
+ csBig5(2026),
+ csMacintosh(2027),
+ csIBM037(2028),
+ csIBM038(2029),
+ csIBM273(2030),
+ csIBM274(2031),
+ csIBM275(2032),
+ csIBM277(2033),
+ csIBM278(2034),
+ csIBM280(2035),
+ csIBM281(2036),
+ csIBM284(2037),
+ csIBM285(2038),
+ csIBM290(2039),
+ csIBM297(2040),
+ csIBM420(2041),
+ csIBM423(2042),
+ csIBM424(2043),
+ csIBM500(2044),
+ csIBM851(2045),
+
+
+
+McDonald Informational [Page 8]
+
+RFC 3808 IANA Charset MIB June 2004
+
+
+ csIBM855(2046),
+ csIBM857(2047),
+ csIBM860(2048),
+ csIBM861(2049),
+ csIBM863(2050),
+ csIBM864(2051),
+ csIBM865(2052),
+ csIBM868(2053),
+ csIBM869(2054),
+ csIBM870(2055),
+ csIBM871(2056),
+ csIBM880(2057),
+ csIBM891(2058),
+ csIBM903(2059),
+ csIBBM904(2060),
+ csIBM905(2061),
+ csIBM918(2062),
+ csIBM1026(2063),
+ csIBMEBCDICATDE(2064),
+ csEBCDICATDEA(2065),
+ csEBCDICCAFR(2066),
+ csEBCDICDKNO(2067),
+ csEBCDICDKNOA(2068),
+ csEBCDICFISE(2069),
+ csEBCDICFISEA(2070),
+ csEBCDICFR(2071),
+ csEBCDICIT(2072),
+ csEBCDICPT(2073),
+ csEBCDICES(2074),
+ csEBCDICESA(2075),
+ csEBCDICESS(2076),
+ csEBCDICUK(2077),
+ csEBCDICUS(2078),
+ csUnknown8BiT(2079),
+ csMnemonic(2080),
+ csMnem(2081),
+ csVISCII(2082),
+ csVIQR(2083),
+ csKOI8R(2084),
+ csHZGB2312(2085),
+ csIBM866(2086),
+ csPC775Baltic(2087),
+ csKOI8U(2088),
+ csIBM00858(2089),
+ csIBM00924(2090),
+ csIBM01140(2091),
+ csIBM01141(2092),
+ csIBM01142(2093),
+
+
+
+McDonald Informational [Page 9]
+
+RFC 3808 IANA Charset MIB June 2004
+
+
+ csIBM01143(2094),
+ csIBM01144(2095),
+ csIBM01145(2096),
+ csIBM01146(2097),
+ csIBM01147(2098),
+ csIBM01148(2099),
+ csIBM01149(2100),
+ csBig5HKSCS(2101),
+ csIBM1047(2102),
+ csPTCP154(2103),
+ csAmiga1251(2104),
+ csKOI7switched(2105),
+ cswindows1250(2250),
+ cswindows1251(2251),
+ cswindows1252(2252),
+ cswindows1253(2253),
+ cswindows1254(2254),
+ cswindows1255(2255),
+ cswindows1256(2256),
+ cswindows1257(2257),
+ cswindows1258(2258),
+ csTIS620(2259),
+ reserved(3000)
+ }
+END
+
+5. IANA Considerations
+
+ IANA has assigned a base arc in the 'mgmt' (standards track) OID tree
+ for the 'ianaCharset' MODULE-IDENTITY defined in the IANA Charset MIB
+ [CHARMIB].
+
+ Whenever any 'charset' is added to the IANA Charset Registry
+ [CHARSET], a new version of the IANA Charset MIB [CHARMIB] may be
+ machine-generated using the C language utility [CHARGEN], described
+ in section 3 of this document or some other utility.
+
+6. Internationalization Considerations
+
+ The IANA Charset MIB [CHARMIB] defines the 'IANACharset' textual
+ convention that may be used in a given MIB module to supply explicit
+ character set labels for one or more text string objects defined in
+ that MIB module.
+
+ For example, the Printer MIB [RFC1759] defines the three character
+ set label objects 'prtLocalizationCharacterSet' (for description and
+ console strings), 'prtInterpreterDefaultCharSetIn' (for received
+
+
+
+
+McDonald Informational [Page 10]
+
+RFC 3808 IANA Charset MIB June 2004
+
+
+ print job input data), and 'prtIntpreterDefaultCharSetOut' (for
+ processed print job output data).
+
+ The IANA Charset MIB [CHARMIB] supports implementation of the best
+ practices specified in "IETF Policy on Character Sets and Languages"
+ [RFC2277].
+
+ Note: The use of the 'SnmpAdminString' textual convention defined in
+ [RFC3411], which has a fixed character set of UTF-8 [RFC3629], is
+ STRONGLY RECOMMENDED in defining new MIB modules. The IANA Charset
+ MIB [CHARMIB] supports locale-specific MIB objects with variable
+ character sets.
+
+7. Security Considerations
+
+ This MIB module does not define any management objects. Instead, it
+ defines a (set of) textual convention(s) which may be used by other
+ MIB modules to define management objects.
+
+ Meaningful security considerations can only be written in the MIB
+ modules that define management objects. Therefore, this document has
+ no impact on the security of the Internet.
+
+8. Acknowledgements
+
+ The editor would like to thank: Bert Wijnen (Lucent) for his
+ original suggestion that the 'IANACharset' textual convention should
+ be extracted from Printer MIB v2 [RFC3805]; Ron Bergman (Hitachi
+ Printing Solutions) and Harry Lewis (IBM) for their many years of
+ effort as editors of Printer MIB v2 [RFC3805].
+
+9. References
+
+9.1. Normative References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2277] Alvestrand, H., "IETF Policy on Character Sets and
+ Languages", RFC 2277, January 1998.
+
+ [RFC2578] McCloghrie, K., Perkins, D., and J. Schoenwaelder,
+ "Structure of Management Information Version 2 (SMIv2)",
+ STD 58, RFC 2578, April 1999.
+
+ [RFC2579] McCloghrie, K., Perkins, D., and J. Schoenwaelder,
+ "Textual Conventions for SMIv2", STD 58, RFC 2579, April
+ 1999.
+
+
+
+McDonald Informational [Page 11]
+
+RFC 3808 IANA Charset MIB June 2004
+
+
+ [RFC2580] McCloghrie, K., Perkins, D., and J. Schoenwaelder,
+ "Conformance Statements for SMIv2", STD 58, RFC 2580,
+ April 1999.
+
+ [RFC2978] Freed, N. and J. Postel, "IANA Charset Registration
+ Procedures", BCP 19, RFC 2978, October 2000.
+
+ [RFC3411] Harrington, D., Presuhn, R., and B. Wijnen, "An
+ Architecture for Describing SNMP Network Management
+ Frameworks", STD 62, RFC 3411, December 2002.
+
+ [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO
+ 10646", RFC 3629, November 2003.
+
+9.2. Informative References
+
+ [CHARGEN] IANA Charset MIB Generation Utility (archived at):
+ ftp://www.pwg.org/pub/pwg/pmp/tools/ianachar.c
+
+ [CHARMIB] IANA Charset MIB (in the future, to be archived at):
+ http://www.iana.org/assignments/ianacharset-mib
+
+ [CHARSET] IANA Charset Registry (archived at):
+ http://www.iana.org/assignments/character-sets
+
+ [CHARTEMP] IANA Charset MIB template file (archived at):
+ ftp://www.pwg.org/pub/pwg/pmp/tools/ianachar.dat
+
+ [RFC1759] Smith, R., Wright, F., Hastings, T., Zilles, S., and J.
+ Gyllenskog. "Printer MIB", RFC 1759, March 1995.
+
+ [RFC3805] Bergman, R., Lewis, H., and I. McDonald, "Printer MIB
+ v2", RFC 3805, June 2004.
+
+ [RFC3410] Case, J., Mundy, P., Partain, D., and B. Stewart,
+ "Introduction and Applicability Statements for
+ Internet-Standard Network Management Framework", RFC
+ 3410, December 2002.
+
+
+
+
+
+
+
+
+
+
+
+
+
+McDonald Informational [Page 12]
+
+RFC 3808 IANA Charset MIB June 2004
+
+
+10. Authors' Addresses
+
+ Ira McDonald
+ High North Inc
+ 221 Ridge Ave
+ Grand Marais, MI 49839
+ USA
+
+ Phone: +1 906 494 2434
+ EMail: imcdonald@sharplabs.com
+
+
+ Internet Assigned Numbers Authority (IANA)
+ ICANN
+ 4676 Admiralty Way, Suite 330
+ Marina del Rey, CA 90292
+ USA
+
+ Phone: +1 310 823 9358
+ EMail: iana@iana.org
+
+ Note: Questions and comments on this IANA Charset MIB [CHARMIB]
+ should be sent to the editor (imcdonald@sharplabs.com) and IANA
+ (iana@iana.org) with a copy to the IETF Charsets mailing list
+ (ietf-charset@iana.org).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+McDonald Informational [Page 13]
+
+RFC 3808 IANA Charset MIB June 2004
+
+
+11. Full Copyright Statement
+
+ Copyright (C) The Internet Society (2004). This document is subject
+ to the rights, licenses and restrictions contained in BCP 78, and
+ except as set forth therein, the authors retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the procedures with respect to rights in RFC documents can be
+ found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at ietf-
+ ipr@ietf.org.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+McDonald Informational [Page 14]
+
diff --git a/standards/rfc3875.txt b/standards/rfc3875.txt
new file mode 100644
index 000000000..41296e1ea
--- /dev/null
+++ b/standards/rfc3875.txt
@@ -0,0 +1,2019 @@
+
+
+
+
+
+
+Network Working Group D. Robinson
+Request for Comments: 3875 K. Coar
+Category: Informational The Apache Software Foundation
+ October 2004
+
+
+ The Common Gateway Interface (CGI) Version 1.1
+
+Status of this Memo
+
+ This memo provides information for the Internet community. It does
+ not specify an Internet standard of any kind. Distribution of this
+ memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2004).
+
+IESG Note
+
+ This document is not a candidate for any level of Internet Standard.
+ The IETF disclaims any knowledge of the fitness of this document for
+ any purpose, and in particular notes that it has not had IETF review
+ for such things as security, congestion control or inappropriate
+ interaction with deployed protocols. The RFC Editor has chosen to
+ publish this document at its discretion. Readers of this document
+ should exercise caution in evaluating its value for implementation
+ and deployment.
+
+Abstract
+
+ The Common Gateway Interface (CGI) is a simple interface for running
+ external programs, software or gateways under an information server
+ in a platform-independent manner. Currently, the supported
+ information servers are HTTP servers.
+
+ The interface has been in use by the World-Wide Web (WWW) since 1993.
+ This specification defines the 'current practice' parameters of the
+ 'CGI/1.1' interface developed and documented at the U.S. National
+ Centre for Supercomputing Applications. This document also defines
+ the use of the CGI/1.1 interface on UNIX(R) and other, similar
+ systems.
+
+
+
+
+
+
+
+
+
+Robinson & Coar Informational [Page 1]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+Table of Contents
+
+ 1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . 4
+ 1.1. Purpose . . . . . . . . . . . . . . . . . . . . . . . . 4
+ 1.2. Requirements . . . . . . . . . . . . . . . . . . . . . . 4
+ 1.3. Specifications . . . . . . . . . . . . . . . . . . . . . 4
+ 1.4. Terminology . . . . . . . . . . . . . . . . . . . . . . 5
+
+ 2. Notational Conventions and Generic Grammar. . . . . . . . . . 5
+ 2.1. Augmented BNF . . . . . . . . . . . . . . . . . . . . . 5
+ 2.2. Basic Rules . . . . . . . . . . . . . . . . . . . . . . 6
+ 2.3. URL Encoding . . . . . . . . . . . . . . . . . . . . . . 7
+
+ 3. Invoking the Script . . . . . . . . . . . . . . . . . . . . . 8
+ 3.1. Server Responsibilities . . . . . . . . . . . . . . . . 8
+ 3.2. Script Selection . . . . . . . . . . . . . . . . . . . . 9
+ 3.3. The Script-URI . . . . . . . . . . . . . . . . . . . . . 9
+ 3.4. Execution . . . . . . . . . . . . . . . . . . . . . . . 10
+
+ 4. The CGI Request . . . . . . . . . . . . . . . . . . . . . . . 10
+ 4.1. Request Meta-Variables . . . . . . . . . . . . . . . . . 10
+ 4.1.1. AUTH_TYPE. . . . . . . . . . . . . . . . . . . . 11
+ 4.1.2. CONTENT_LENGTH . . . . . . . . . . . . . . . . . 12
+ 4.1.3. CONTENT_TYPE . . . . . . . . . . . . . . . . . . 12
+ 4.1.4. GATEWAY_INTERFACE. . . . . . . . . . . . . . . . 13
+ 4.1.5. PATH_INFO. . . . . . . . . . . . . . . . . . . . 13
+ 4.1.6. PATH_TRANSLATED. . . . . . . . . . . . . . . . . 14
+ 4.1.7. QUERY_STRING . . . . . . . . . . . . . . . . . . 15
+ 4.1.8. REMOTE_ADDR. . . . . . . . . . . . . . . . . . . 15
+ 4.1.9. REMOTE_HOST. . . . . . . . . . . . . . . . . . . 16
+ 4.1.10. REMOTE_IDENT . . . . . . . . . . . . . . . . . . 16
+ 4.1.11. REMOTE_USER. . . . . . . . . . . . . . . . . . . 16
+ 4.1.12. REQUEST_METHOD . . . . . . . . . . . . . . . . . 17
+ 4.1.13. SCRIPT_NAME. . . . . . . . . . . . . . . . . . . 17
+ 4.1.14. SERVER_NAME. . . . . . . . . . . . . . . . . . . 17
+ 4.1.15. SERVER_PORT. . . . . . . . . . . . . . . . . . . 18
+ 4.1.16. SERVER_PROTOCOL. . . . . . . . . . . . . . . . . 18
+ 4.1.17. SERVER_SOFTWARE. . . . . . . . . . . . . . . . . 19
+ 4.1.18. Protocol-Specific Meta-Variables . . . . . . . . 19
+ 4.2. Request Message-Body . . . . . . . . . . . . . . . . . . 20
+ 4.3. Request Methods . . . . . . . . . . . . . . . . . . . . 20
+ 4.3.1. GET. . . . . . . . . . . . . . . . . . . . . . . 20
+ 4.3.2. POST . . . . . . . . . . . . . . . . . . . . . . 21
+ 4.3.3. HEAD . . . . . . . . . . . . . . . . . . . . . . 21
+ 4.3.4. Protocol-Specific Methods. . . . . . . . . . . . 21
+ 4.4. The Script Command Line. . . . . . . . . . . . . . . . . 21
+
+
+
+
+
+Robinson & Coar Informational [Page 2]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ 5. NPH Scripts . . . . . . . . . . . . . . . . . . . . . . . . . 22
+ 5.1. Identification . . . . . . . . . . . . . . . . . . . . . 22
+ 5.2. NPH Response . . . . . . . . . . . . . . . . . . . . . . 22
+
+ 6. CGI Response. . . . . . . . . . . . . . . . . . . . . . . . . 23
+ 6.1. Response Handling. . . . . . . . . . . . . . . . . . . . 23
+ 6.2. Response Types . . . . . . . . . . . . . . . . . . . . . 23
+ 6.2.1. Document Response. . . . . . . . . . . . . . . . 23
+ 6.2.2. Local Redirect Response. . . . . . . . . . . . . 24
+ 6.2.3. Client Redirect Response . . . . . . . . . . . . 24
+ 6.2.4. Client Redirect Response with Document . . . . . 24
+ 6.3. Response Header Fields . . . . . . . . . . . . . . . . . 25
+ 6.3.1. Content-Type . . . . . . . . . . . . . . . . . . 25
+ 6.3.2. Location . . . . . . . . . . . . . . . . . . . . 26
+ 6.3.3. Status . . . . . . . . . . . . . . . . . . . . . 26
+ 6.3.4. Protocol-Specific Header Fields. . . . . . . . . 27
+ 6.3.5. Extension Header Fields. . . . . . . . . . . . . 27
+ 6.4. Response Message-Body. . . . . . . . . . . . . . . . . . 28
+
+ 7. System Specifications . . . . . . . . . . . . . . . . . . . . 28
+ 7.1. AmigaDOS . . . . . . . . . . . . . . . . . . . . . . . . 28
+ 7.2. UNIX . . . . . . . . . . . . . . . . . . . . . . . . . . 28
+ 7.3. EBCDIC/POSIX . . . . . . . . . . . . . . . . . . . . . . 29
+
+ 8. Implementation. . . . . . . . . . . . . . . . . . . . . . . . 29
+ 8.1. Recommendations for Servers. . . . . . . . . . . . . . . 29
+ 8.2. Recommendations for Scripts. . . . . . . . . . . . . . . 30
+
+ 9. Security Considerations . . . . . . . . . . . . . . . . . . . 30
+ 9.1. Safe Methods . . . . . . . . . . . . . . . . . . . . . . 30
+ 9.2. Header Fields Containing Sensitive Information . . . . . 31
+ 9.3. Data Privacy . . . . . . . . . . . . . . . . . . . . . . 31
+ 9.4. Information Security Model . . . . . . . . . . . . . . . 31
+ 9.5. Script Interference with the Server. . . . . . . . . . . 31
+ 9.6. Data Length and Buffering Considerations . . . . . . . . 32
+ 9.7. Stateless Processing . . . . . . . . . . . . . . . . . . 32
+ 9.8. Relative Paths . . . . . . . . . . . . . . . . . . . . . 33
+ 9.9. Non-parsed Header Output . . . . . . . . . . . . . . . . 33
+
+ 10. Acknowledgements. . . . . . . . . . . . . . . . . . . . . . . 33
+
+ 11. References. . . . . . . . . . . . . . . . . . . . . . . . . . 33
+ 11.1. Normative References. . . . . . . . . . . . . . . . . . 33
+ 11.2. Informative References. . . . . . . . . . . . . . . . . 34
+
+ 12. Authors' Addresses. . . . . . . . . . . . . . . . . . . . . . 35
+
+ 13. Full Copyright Statement. . . . . . . . . . . . . . . . . . . 36
+
+
+
+Robinson & Coar Informational [Page 3]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+1. Introduction
+
+1.1. Purpose
+
+ The Common Gateway Interface (CGI) [22] allows an HTTP [1], [4]
+ server and a CGI script to share responsibility for responding to
+ client requests. The client request comprises a Uniform Resource
+ Identifier (URI) [11], a request method and various ancillary
+ information about the request provided by the transport protocol.
+
+ The CGI defines the abstract parameters, known as meta-variables,
+ which describe a client's request. Together with a concrete
+ programmer interface this specifies a platform-independent interface
+ between the script and the HTTP server.
+
+ The server is responsible for managing connection, data transfer,
+ transport and network issues related to the client request, whereas
+ the CGI script handles the application issues, such as data access
+ and document processing.
+
+1.2. Requirements
+
+ The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL NOT',
+ 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'MAY' and 'OPTIONAL' in this
+ document are to be interpreted as described in BCP 14, RFC 2119 [3].
+
+ An implementation is not compliant if it fails to satisfy one or more
+ of the 'must' requirements for the protocols it implements. An
+ implementation that satisfies all of the 'must' and all of the
+ 'should' requirements for its features is said to be 'unconditionally
+ compliant'; one that satisfies all of the 'must' requirements but not
+ all of the 'should' requirements for its features is said to be
+ 'conditionally compliant'.
+
+1.3. Specifications
+
+ Not all of the functions and features of the CGI are defined in the
+ main part of this specification. The following phrases are used to
+ describe the features that are not specified:
+
+ 'system-defined'
+ The feature may differ between systems, but must be the same for
+ different implementations using the same system. A system will
+ usually identify a class of operating systems. Some systems are
+ defined in section 7 of this document. New systems may be defined
+ by new specifications without revision of this document.
+
+
+
+
+
+Robinson & Coar Informational [Page 4]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ 'implementation-defined'
+ The behaviour of the feature may vary from implementation to
+ implementation; a particular implementation must document its
+ behaviour.
+
+1.4. Terminology
+
+ This specification uses many terms defined in the HTTP/1.1
+ specification [4]; however, the following terms are used here in a
+ sense which may not accord with their definitions in that document,
+ or with their common meaning.
+
+ 'meta-variable'
+ A named parameter which carries information from the server to the
+ script. It is not necessarily a variable in the operating
+ system's environment, although that is the most common
+ implementation.
+
+ 'script'
+ The software that is invoked by the server according to this
+ interface. It need not be a standalone program, but could be a
+ dynamically-loaded or shared library, or even a subroutine in the
+ server. It might be a set of statements interpreted at run-time,
+ as the term 'script' is frequently understood, but that is not a
+ requirement and within the context of this specification the term
+ has the broader definition stated.
+
+ 'server'
+ The application program that invokes the script in order to
+ service requests from the client.
+
+2. Notational Conventions and Generic Grammar
+
+2.1. Augmented BNF
+
+ All of the mechanisms specified in this document are described in
+ both prose and an augmented Backus-Naur Form (BNF) similar to that
+ used by RFC 822 [13]. Unless stated otherwise, the elements are
+ case-sensitive. This augmented BNF contains the following
+ constructs:
+
+ name = definition
+ The name of a rule and its definition are separated by the equals
+ character ('='). Whitespace is only significant in that
+ continuation lines of a definition are indented.
+
+
+
+
+
+
+Robinson & Coar Informational [Page 5]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ "literal"
+ Double quotation marks (") surround literal text, except for a
+ literal quotation mark, which is surrounded by angle-brackets ('<'
+ and '>').
+
+ rule1 | rule2
+ Alternative rules are separated by a vertical bar ('|').
+
+ (rule1 rule2 rule3)
+ Elements enclosed in parentheses are treated as a single element.
+
+ *rule
+ A rule preceded by an asterisk ('*') may have zero or more
+ occurrences. The full form is 'n*m rule' indicating at least n
+ and at most m occurrences of the rule. n and m are optional
+ decimal values with default values of 0 and infinity respectively.
+
+ [rule]
+ An element enclosed in square brackets ('[' and ']') is optional,
+ and is equivalent to '*1 rule'.
+
+ N rule
+ A rule preceded by a decimal number represents exactly N
+ occurrences of the rule. It is equivalent to 'N*N rule'.
+
+2.2. Basic Rules
+
+ This specification uses a BNF-like grammar defined in terms of
+ characters. Unlike many specifications which define the bytes
+ allowed by a protocol, here each literal in the grammar corresponds
+ to the character it represents. How these characters are represented
+ in terms of bits and bytes within a system are either system-defined
+ or specified in the particular context. The single exception is the
+ rule 'OCTET', defined below.
+
+ The following rules are used throughout this specification to
+ describe basic parsing constructs.
+
+ alpha = lowalpha | hialpha
+ lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" |
+ "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" |
+ "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" |
+ "y" | "z"
+ hialpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" |
+ "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" |
+ "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" |
+ "Y" | "Z"
+
+
+
+
+Robinson & Coar Informational [Page 6]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
+ "8" | "9"
+ alphanum = alpha | digit
+ OCTET = <any 8-bit byte>
+ CHAR = alpha | digit | separator | "!" | "#" | "$" |
+ "%" | "&" | "'" | "*" | "+" | "-" | "." | "`" |
+ "^" | "_" | "{" | "|" | "}" | "~" | CTL
+ CTL = <any control character>
+ SP = <space character>
+ HT = <horizontal tab character>
+ NL = <newline>
+ LWSP = SP | HT | NL
+ separator = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" |
+ "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{" |
+ "}" | SP | HT
+ token = 1*<any CHAR except CTLs or separators>
+ quoted-string = <"> *qdtext <">
+ qdtext = <any CHAR except <"> and CTLs but including LWSP>
+ TEXT = <any printable character>
+
+ Note that newline (NL) need not be a single control character, but
+ can be a sequence of control characters. A system MAY define TEXT to
+ be a larger set of characters than <any CHAR excluding CTLs but
+ including LWSP>.
+
+2.3. URL Encoding
+
+ Some variables and constructs used here are described as being
+ 'URL-encoded'. This encoding is described in section 2 of RFC 2396
+ [2]. In a URL-encoded string an escape sequence consists of a
+ percent character ("%") followed by two hexadecimal digits, where the
+ two hexadecimal digits form an octet. An escape sequence represents
+ the graphic character that has the octet as its code within the
+ US-ASCII [9] coded character set, if it exists. Currently there is
+ no provision within the URI syntax to identify which character set
+ non-ASCII codes represent, so CGI handles this issue on an ad-hoc
+ basis.
+
+ Note that some unsafe (reserved) characters may have different
+ semantics when encoded. The definition of which characters are
+ unsafe depends on the context; see section 2 of RFC 2396 [2], updated
+ by RFC 2732 [7], for an authoritative treatment. These reserved
+ characters are generally used to provide syntactic structure to the
+ character string, for example as field separators. In all cases, the
+ string is first processed with regard to any reserved characters
+ present, and then the resulting data can be URL-decoded by replacing
+ "%" escape sequences by their character values.
+
+
+
+
+Robinson & Coar Informational [Page 7]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ To encode a character string, all reserved and forbidden characters
+ are replaced by the corresponding "%" escape sequences. The string
+ can then be used in assembling a URI. The reserved characters will
+ vary from context to context, but will always be drawn from this set:
+
+ reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" |
+ "," | "[" | "]"
+
+ The last two characters were added by RFC 2732 [7]. In any
+ particular context, a sub-set of these characters will be reserved;
+ the other characters from this set MUST NOT be encoded when a string
+ is URL-encoded in that context. Other basic rules used to describe
+ URI syntax are:
+
+ hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b"
+ | "c" | "d" | "e" | "f"
+ escaped = "%" hex hex
+ unreserved = alpha | digit | mark
+ mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+
+3. Invoking the Script
+
+3.1. Server Responsibilities
+
+ The server acts as an application gateway. It receives the request
+ from the client, selects a CGI script to handle the request, converts
+ the client request to a CGI request, executes the script and converts
+ the CGI response into a response for the client. When processing the
+ client request, it is responsible for implementing any protocol or
+ transport level authentication and security. The server MAY also
+ function in a 'non-transparent' manner, modifying the request or
+ response in order to provide some additional service, such as media
+ type transformation or protocol reduction.
+
+ The server MUST perform translations and protocol conversions on the
+ client request data required by this specification. Furthermore, the
+ server retains its responsibility to the client to conform to the
+ relevant network protocol even if the CGI script fails to conform to
+ this specification.
+
+ If the server is applying authentication to the request, then it MUST
+ NOT execute the script unless the request passes all defined access
+ controls.
+
+
+
+
+
+
+
+
+Robinson & Coar Informational [Page 8]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+3.2. Script Selection
+
+ The server determines which CGI is script to be executed based on a
+ generic-form URI supplied by the client. This URI includes a
+ hierarchical path with components separated by "/". For any
+ particular request, the server will identify all or a leading part of
+ this path with an individual script, thus placing the script at a
+ particular point in the path hierarchy. The remainder of the path,
+ if any, is a resource or sub-resource identifier to be interpreted by
+ the script.
+
+ Information about this split of the path is available to the script
+ in the meta-variables, described below. Support for non-hierarchical
+ URI schemes is outside the scope of this specification.
+
+3.3. The Script-URI
+
+ The mapping from client request URI to choice of script is defined by
+ the particular server implementation and its configuration. The
+ server may allow the script to be identified with a set of several
+ different URI path hierarchies, and therefore is permitted to replace
+ the URI by other members of this set during processing and generation
+ of the meta-variables. The server
+
+ 1. MAY preserve the URI in the particular client request; or
+
+ 2. it MAY select a canonical URI from the set of possible values
+ for each script; or
+
+ 3. it can implement any other selection of URI from the set.
+
+ From the meta-variables thus generated, a URI, the 'Script-URI', can
+ be constructed. This MUST have the property that if the client had
+ accessed this URI instead, then the script would have been executed
+ with the same values for the SCRIPT_NAME, PATH_INFO and QUERY_STRING
+ meta-variables. The Script-URI has the structure of a generic URI as
+ defined in section 3 of RFC 2396 [2], with the exception that object
+ parameters and fragment identifiers are not permitted. The various
+ components of the Script-URI are defined by some of the
+ meta-variables (see below);
+
+ script-URI = <scheme> "://" <server-name> ":" <server-port>
+ <script-path> <extra-path> "?" <query-string>
+
+ where <scheme> is found from SERVER_PROTOCOL, <server-name>,
+ <server-port> and <query-string> are the values of the respective
+ meta-variables. The SCRIPT_NAME and PATH_INFO values, URL-encoded
+ with ";", "=" and "?" reserved, give <script-path> and <extra-path>.
+
+
+
+Robinson & Coar Informational [Page 9]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ See section 4.1.5 for more information about the PATH_INFO
+ meta-variable.
+
+ The scheme and the protocol are not identical as the scheme
+ identifies the access method in addition to the application protocol.
+ For example, a resource accessed using Transport Layer Security (TLS)
+ [14] would have a request URI with a scheme of https when using the
+ HTTP protocol [19]. CGI/1.1 provides no generic means for the script
+ to reconstruct this, and therefore the Script-URI as defined includes
+ the base protocol used. However, a script MAY make use of
+ scheme-specific meta-variables to better deduce the URI scheme.
+
+ Note that this definition also allows URIs to be constructed which
+ would invoke the script with any permitted values for the path-info
+ or query-string, by modifying the appropriate components.
+
+3.4. Execution
+
+ The script is invoked in a system-defined manner. Unless specified
+ otherwise, the file containing the script will be invoked as an
+ executable program. The server prepares the CGI request as described
+ in section 4; this comprises the request meta-variables (immediately
+ available to the script on execution) and request message data. The
+ request data need not be immediately available to the script; the
+ script can be executed before all this data has been received by the
+ server from the client. The response from the script is returned to
+ the server as described in sections 5 and 6.
+
+ In the event of an error condition, the server can interrupt or
+ terminate script execution at any time and without warning. That
+ could occur, for example, in the event of a transport failure between
+ the server and the client; so the script SHOULD be prepared to handle
+ abnormal termination.
+
+4. The CGI Request
+
+ Information about a request comes from two different sources; the
+ request meta-variables and any associated message-body.
+
+4.1. Request Meta-Variables
+
+ Meta-variables contain data about the request passed from the server
+ to the script, and are accessed by the script in a system-defined
+ manner. Meta-variables are identified by case-insensitive names;
+ there cannot be two different variables whose names differ in case
+ only. Here they are shown using a canonical representation of
+ capitals plus underscore ("_"). A particular system can define a
+ different representation.
+
+
+
+Robinson & Coar Informational [Page 10]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ meta-variable-name = "AUTH_TYPE" | "CONTENT_LENGTH" |
+ "CONTENT_TYPE" | "GATEWAY_INTERFACE" |
+ "PATH_INFO" | "PATH_TRANSLATED" |
+ "QUERY_STRING" | "REMOTE_ADDR" |
+ "REMOTE_HOST" | "REMOTE_IDENT" |
+ "REMOTE_USER" | "REQUEST_METHOD" |
+ "SCRIPT_NAME" | "SERVER_NAME" |
+ "SERVER_PORT" | "SERVER_PROTOCOL" |
+ "SERVER_SOFTWARE" | scheme |
+ protocol-var-name | extension-var-name
+ protocol-var-name = ( protocol | scheme ) "_" var-name
+ scheme = alpha *( alpha | digit | "+" | "-" | "." )
+ var-name = token
+ extension-var-name = token
+
+ Meta-variables with the same name as a scheme, and names beginning
+ with the name of a protocol or scheme (e.g., HTTP_ACCEPT) are also
+ defined. The number and meaning of these variables may change
+ independently of this specification. (See also section 4.1.18.)
+
+ The server MAY set additional implementation-defined extension meta-
+ variables, whose names SHOULD be prefixed with "X_".
+
+ This specification does not distinguish between zero-length (NULL)
+ values and missing values. For example, a script cannot distinguish
+ between the two requests http://host/script and http://host/script?
+ as in both cases the QUERY_STRING meta-variable would be NULL.
+
+ meta-variable-value = "" | 1*<TEXT, CHAR or tokens of value>
+
+ An optional meta-variable may be omitted (left unset) if its value is
+ NULL. Meta-variable values MUST be considered case-sensitive except
+ as noted otherwise. The representation of the characters in the
+ meta-variables is system-defined; the server MUST convert values to
+ that representation.
+
+4.1.1. AUTH_TYPE
+
+ The AUTH_TYPE variable identifies any mechanism used by the server to
+ authenticate the user. It contains a case-insensitive value defined
+ by the client protocol or server implementation.
+
+ For HTTP, if the client request required authentication for external
+ access, then the server MUST set the value of this variable from the
+ 'auth-scheme' token in the request Authorization header field.
+
+
+
+
+
+
+Robinson & Coar Informational [Page 11]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ AUTH_TYPE = "" | auth-scheme
+ auth-scheme = "Basic" | "Digest" | extension-auth
+ extension-auth = token
+
+ HTTP access authentication schemes are described in RFC 2617 [5].
+
+4.1.2. CONTENT_LENGTH
+
+ The CONTENT_LENGTH variable contains the size of the message-body
+ attached to the request, if any, in decimal number of octets. If no
+ data is attached, then NULL (or unset).
+
+ CONTENT_LENGTH = "" | 1*digit
+
+ The server MUST set this meta-variable if and only if the request is
+ accompanied by a message-body entity. The CONTENT_LENGTH value must
+ reflect the length of the message-body after the server has removed
+ any transfer-codings or content-codings.
+
+4.1.3. CONTENT_TYPE
+
+ If the request includes a message-body, the CONTENT_TYPE variable is
+ set to the Internet Media Type [6] of the message-body.
+
+ CONTENT_TYPE = "" | media-type
+ media-type = type "/" subtype *( ";" parameter )
+ type = token
+ subtype = token
+ parameter = attribute "=" value
+ attribute = token
+ value = token | quoted-string
+
+ The type, subtype and parameter attribute names are not
+ case-sensitive. Parameter values may be case sensitive. Media types
+ and their use in HTTP are described section 3.7 of the HTTP/1.1
+ specification [4].
+
+ There is no default value for this variable. If and only if it is
+ unset, then the script MAY attempt to determine the media type from
+ the data received. If the type remains unknown, then the script MAY
+ choose to assume a type of application/octet-stream or it may reject
+ the request with an error (as described in section 6.3.3).
+
+ Each media-type defines a set of optional and mandatory parameters.
+ This may include a charset parameter with a case-insensitive value
+ defining the coded character set for the message-body. If the
+
+
+
+
+
+Robinson & Coar Informational [Page 12]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ charset parameter is omitted, then the default value should be
+ derived according to whichever of the following rules is the first to
+ apply:
+
+ 1. There MAY be a system-defined default charset for some
+ media-types.
+
+ 2. The default for media-types of type "text" is ISO-8859-1 [4].
+
+ 3. Any default defined in the media-type specification.
+
+ 4. The default is US-ASCII.
+
+ The server MUST set this meta-variable if an HTTP Content-Type field
+ is present in the client request header. If the server receives a
+ request with an attached entity but no Content-Type header field, it
+ MAY attempt to determine the correct content type, otherwise it
+ should omit this meta-variable.
+
+4.1.4. GATEWAY_INTERFACE
+
+ The GATEWAY_INTERFACE variable MUST be set to the dialect of CGI
+ being used by the server to communicate with the script. Syntax:
+
+ GATEWAY_INTERFACE = "CGI" "/" 1*digit "." 1*digit
+
+ Note that the major and minor numbers are treated as separate
+ integers and hence each may be incremented higher than a single
+ digit. Thus CGI/2.4 is a lower version than CGI/2.13 which in turn
+ is lower than CGI/12.3. Leading zeros MUST be ignored by the script
+ and MUST NOT be generated by the server.
+
+ This document defines the 1.1 version of the CGI interface.
+
+4.1.5. PATH_INFO
+
+ The PATH_INFO variable specifies a path to be interpreted by the CGI
+ script. It identifies the resource or sub-resource to be returned by
+ the CGI script, and is derived from the portion of the URI path
+ hierarchy following the part that identifies the script itself.
+ Unlike a URI path, the PATH_INFO is not URL-encoded, and cannot
+ contain path-segment parameters. A PATH_INFO of "/" represents a
+ single void path segment.
+
+ PATH_INFO = "" | ( "/" path )
+ path = lsegment *( "/" lsegment )
+ lsegment = *lchar
+ lchar = <any TEXT or CTL except "/">
+
+
+
+Robinson & Coar Informational [Page 13]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ The value is considered case-sensitive and the server MUST preserve
+ the case of the path as presented in the request URI. The server MAY
+ impose restrictions and limitations on what values it permits for
+ PATH_INFO, and MAY reject the request with an error if it encounters
+ any values considered objectionable. That MAY include any requests
+ that would result in an encoded "/" being decoded into PATH_INFO, as
+ this might represent a loss of information to the script. Similarly,
+ treatment of non US-ASCII characters in the path is system-defined.
+
+ URL-encoded, the PATH_INFO string forms the extra-path component of
+ the Script-URI (see section 3.3) which follows the SCRIPT_NAME part
+ of that path.
+
+4.1.6. PATH_TRANSLATED
+
+ The PATH_TRANSLATED variable is derived by taking the PATH_INFO
+ value, parsing it as a local URI in its own right, and performing any
+ virtual-to-physical translation appropriate to map it onto the
+ server's document repository structure. The set of characters
+ permitted in the result is system-defined.
+
+ PATH_TRANSLATED = *<any character>
+
+ This is the file location that would be accessed by a request for
+
+ <scheme> "://" <server-name> ":" <server-port> <extra-path>
+
+ where <scheme> is the scheme for the original client request and
+ <extra-path> is a URL-encoded version of PATH_INFO, with ";", "=" and
+ "?" reserved. For example, a request such as the following:
+
+ http://somehost.com/cgi-bin/somescript/this%2eis%2epath%3binfo
+
+ would result in a PATH_INFO value of
+
+ /this.is.the.path;info
+
+ An internal URI is constructed from the scheme, server location and
+ the URL-encoded PATH_INFO:
+
+ http://somehost.com/this.is.the.path%3binfo
+
+ This would then be translated to a location in the server's document
+ repository, perhaps a filesystem path something like this:
+
+ /usr/local/www/htdocs/this.is.the.path;info
+
+ The value of PATH_TRANSLATED is the result of the translation.
+
+
+
+Robinson & Coar Informational [Page 14]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ The value is derived in this way irrespective of whether it maps to a
+ valid repository location. The server MUST preserve the case of the
+ extra-path segment unless the underlying repository supports case-
+ insensitive names. If the repository is only case-aware, case-
+ preserving, or case-blind with regard to document names, the server
+ is not required to preserve the case of the original segment through
+ the translation.
+
+ The translation algorithm the server uses to derive PATH_TRANSLATED
+ is implementation-defined; CGI scripts which use this variable may
+ suffer limited portability.
+
+ The server SHOULD set this meta-variable if the request URI includes
+ a path-info component. If PATH_INFO is NULL, then the
+ PATH_TRANSLATED variable MUST be set to NULL (or unset).
+
+4.1.7. QUERY_STRING
+
+ The QUERY_STRING variable contains a URL-encoded search or parameter
+ string; it provides information to the CGI script to affect or refine
+ the document to be returned by the script.
+
+ The URL syntax for a search string is described in section 3 of RFC
+ 2396 [2]. The QUERY_STRING value is case-sensitive.
+
+ QUERY_STRING = query-string
+ query-string = *uric
+ uric = reserved | unreserved | escaped
+
+ When parsing and decoding the query string, the details of the
+ parsing, reserved characters and support for non US-ASCII characters
+ depends on the context. For example, form submission from an HTML
+ document [18] uses application/x-www-form-urlencoded encoding, in
+ which the characters "+", "&" and "=" are reserved, and the ISO
+ 8859-1 encoding may be used for non US-ASCII characters.
+
+ The QUERY_STRING value provides the query-string part of the
+ Script-URI. (See section 3.3).
+
+ The server MUST set this variable; if the Script-URI does not include
+ a query component, the QUERY_STRING MUST be defined as an empty
+ string ("").
+
+4.1.8. REMOTE_ADDR
+
+ The REMOTE_ADDR variable MUST be set to the network address of the
+ client sending the request to the server.
+
+
+
+
+Robinson & Coar Informational [Page 15]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ REMOTE_ADDR = hostnumber
+ hostnumber = ipv4-address | ipv6-address
+ ipv4-address = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit
+ ipv6-address = hexpart [ ":" ipv4-address ]
+ hexpart = hexseq | ( [ hexseq ] "::" [ hexseq ] )
+ hexseq = 1*4hex *( ":" 1*4hex )
+
+ The format of an IPv6 address is described in RFC 3513 [15].
+
+4.1.9. REMOTE_HOST
+
+ The REMOTE_HOST variable contains the fully qualified domain name of
+ the client sending the request to the server, if available, otherwise
+ NULL. Fully qualified domain names take the form as described in
+ section 3.5 of RFC 1034 [17] and section 2.1 of RFC 1123 [12].
+ Domain names are not case sensitive.
+
+ REMOTE_HOST = "" | hostname | hostnumber
+ hostname = *( domainlabel "." ) toplabel [ "." ]
+ domainlabel = alphanum [ *alphahypdigit alphanum ]
+ toplabel = alpha [ *alphahypdigit alphanum ]
+ alphahypdigit = alphanum | "-"
+
+ The server SHOULD set this variable. If the hostname is not
+ available for performance reasons or otherwise, the server MAY
+ substitute the REMOTE_ADDR value.
+
+4.1.10. REMOTE_IDENT
+
+ The REMOTE_IDENT variable MAY be used to provide identity information
+ reported about the connection by an RFC 1413 [20] request to the
+ remote agent, if available. The server may choose not to support
+ this feature, or not to request the data for efficiency reasons, or
+ not to return available identity data.
+
+ REMOTE_IDENT = *TEXT
+
+ The data returned may be used for authentication purposes, but the
+ level of trust reposed in it should be minimal.
+
+4.1.11. REMOTE_USER
+
+ The REMOTE_USER variable provides a user identification string
+ supplied by client as part of user authentication.
+
+ REMOTE_USER = *TEXT
+
+
+
+
+
+Robinson & Coar Informational [Page 16]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ If the client request required HTTP Authentication [5] (e.g., the
+ AUTH_TYPE meta-variable is set to "Basic" or "Digest"), then the
+ value of the REMOTE_USER meta-variable MUST be set to the user-ID
+ supplied.
+
+4.1.12. REQUEST_METHOD
+
+ The REQUEST_METHOD meta-variable MUST be set to the method which
+ should be used by the script to process the request, as described in
+ section 4.3.
+
+ REQUEST_METHOD = method
+ method = "GET" | "POST" | "HEAD" | extension-method
+ extension-method = "PUT" | "DELETE" | token
+
+ The method is case sensitive. The HTTP methods are described in
+ section 5.1.1 of the HTTP/1.0 specification [1] and section 5.1.1 of
+ the HTTP/1.1 specification [4].
+
+4.1.13. SCRIPT_NAME
+
+ The SCRIPT_NAME variable MUST be set to a URI path (not URL-encoded)
+ which could identify the CGI script (rather than the script's
+ output). The syntax is the same as for PATH_INFO (section 4.1.5)
+
+ SCRIPT_NAME = "" | ( "/" path )
+
+ The leading "/" is not part of the path. It is optional if the path
+ is NULL; however, the variable MUST still be set in that case.
+
+ The SCRIPT_NAME string forms some leading part of the path component
+ of the Script-URI derived in some implementation-defined manner. No
+ PATH_INFO segment (see section 4.1.5) is included in the SCRIPT_NAME
+ value.
+
+4.1.14. SERVER_NAME
+
+ The SERVER_NAME variable MUST be set to the name of the server host
+ to which the client request is directed. It is a case-insensitive
+ hostname or network address. It forms the host part of the
+ Script-URI.
+
+ SERVER_NAME = server-name
+ server-name = hostname | ipv4-address | ( "[" ipv6-address "]" )
+
+
+
+
+
+
+
+Robinson & Coar Informational [Page 17]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ A deployed server can have more than one possible value for this
+ variable, where several HTTP virtual hosts share the same IP address.
+ In that case, the server would use the contents of the request's Host
+ header field to select the correct virtual host.
+
+4.1.15. SERVER_PORT
+
+ The SERVER_PORT variable MUST be set to the TCP/IP port number on
+ which this request is received from the client. This value is used
+ in the port part of the Script-URI.
+
+ SERVER_PORT = server-port
+ server-port = 1*digit
+
+ Note that this variable MUST be set, even if the port is the default
+ port for the scheme and could otherwise be omitted from a URI.
+
+4.1.16. SERVER_PROTOCOL
+
+ The SERVER_PROTOCOL variable MUST be set to the name and version of
+ the application protocol used for this CGI request. This MAY differ
+ from the protocol version used by the server in its communication
+ with the client.
+
+ SERVER_PROTOCOL = HTTP-Version | "INCLUDED" | extension-version
+ HTTP-Version = "HTTP" "/" 1*digit "." 1*digit
+ extension-version = protocol [ "/" 1*digit "." 1*digit ]
+ protocol = token
+
+ Here, 'protocol' defines the syntax of some of the information
+ passing between the server and the script (the 'protocol-specific'
+ features). It is not case sensitive and is usually presented in
+ upper case. The protocol is not the same as the scheme part of the
+ script URI, which defines the overall access mechanism used by the
+ client to communicate with the server. For example, a request that
+ reaches the script with a protocol of "HTTP" may have used an "https"
+ scheme.
+
+ A well-known value for SERVER_PROTOCOL which the server MAY use is
+ "INCLUDED", which signals that the current document is being included
+ as part of a composite document, rather than being the direct target
+ of the client request. The script should treat this as an HTTP/1.0
+ request.
+
+
+
+
+
+
+
+
+Robinson & Coar Informational [Page 18]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+4.1.17. SERVER_SOFTWARE
+
+ The SERVER_SOFTWARE meta-variable MUST be set to the name and version
+ of the information server software making the CGI request (and
+ running the gateway). It SHOULD be the same as the server
+ description reported to the client, if any.
+
+ SERVER_SOFTWARE = 1*( product | comment )
+ product = token [ "/" product-version ]
+ product-version = token
+ comment = "(" *( ctext | comment ) ")"
+ ctext = <any TEXT excluding "(" and ")">
+
+4.1.18. Protocol-Specific Meta-Variables
+
+ The server SHOULD set meta-variables specific to the protocol and
+ scheme for the request. Interpretation of protocol-specific
+ variables depends on the protocol version in SERVER_PROTOCOL. The
+ server MAY set a meta-variable with the name of the scheme to a
+ non-NULL value if the scheme is not the same as the protocol. The
+ presence of such a variable indicates to a script which scheme is
+ used by the request.
+
+ Meta-variables with names beginning with "HTTP_" contain values read
+ from the client request header fields, if the protocol used is HTTP.
+ The HTTP header field name is converted to upper case, has all
+ occurrences of "-" replaced with "_" and has "HTTP_" prepended to
+ give the meta-variable name. The header data can be presented as
+ sent by the client, or can be rewritten in ways which do not change
+ its semantics. If multiple header fields with the same field-name
+ are received then the server MUST rewrite them as a single value
+ having the same semantics. Similarly, a header field that spans
+ multiple lines MUST be merged onto a single line. The server MUST,
+ if necessary, change the representation of the data (for example, the
+ character set) to be appropriate for a CGI meta-variable.
+
+ The server is not required to create meta-variables for all the
+ header fields that it receives. In particular, it SHOULD remove any
+ header fields carrying authentication information, such as
+ 'Authorization'; or that are available to the script in other
+ variables, such as 'Content-Length' and 'Content-Type'. The server
+ MAY remove header fields that relate solely to client-side
+ communication issues, such as 'Connection'.
+
+
+
+
+
+
+
+
+Robinson & Coar Informational [Page 19]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+4.2. Request Message-Body
+
+ Request data is accessed by the script in a system-defined method;
+ unless defined otherwise, this will be by reading the 'standard
+ input' file descriptor or file handle.
+
+ Request-Data = [ request-body ] [ extension-data ]
+ request-body = <CONTENT_LENGTH>OCTET
+ extension-data = *OCTET
+
+ A request-body is supplied with the request if the CONTENT_LENGTH is
+ not NULL. The server MUST make at least that many bytes available
+ for the script to read. The server MAY signal an end-of-file
+ condition after CONTENT_LENGTH bytes have been read or it MAY supply
+ extension data. Therefore, the script MUST NOT attempt to read more
+ than CONTENT_LENGTH bytes, even if more data is available. However,
+ it is not obliged to read any of the data.
+
+ For non-parsed header (NPH) scripts (section 5), the server SHOULD
+ attempt to ensure that the data supplied to the script is precisely
+ as supplied by the client and is unaltered by the server.
+
+ As transfer-codings are not supported on the request-body, the server
+ MUST remove any such codings from the message-body, and recalculate
+ the CONTENT_LENGTH. If this is not possible (for example, because of
+ large buffering requirements), the server SHOULD reject the client
+ request. It MAY also remove content-codings from the message-body.
+
+4.3. Request Methods
+
+ The Request Method, as supplied in the REQUEST_METHOD meta-variable,
+ identifies the processing method to be applied by the script in
+ producing a response. The script author can choose to implement the
+ methods most appropriate for the particular application. If the
+ script receives a request with a method it does not support it SHOULD
+ reject it with an error (see section 6.3.3).
+
+4.3.1. GET
+
+ The GET method indicates that the script should produce a document
+ based on the meta-variable values. By convention, the GET method is
+ 'safe' and 'idempotent' and SHOULD NOT have the significance of
+ taking an action other than producing a document.
+
+ The meaning of the GET method may be modified and refined by
+ protocol-specific meta-variables.
+
+
+
+
+
+Robinson & Coar Informational [Page 20]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+4.3.2. POST
+
+ The POST method is used to request the script perform processing and
+ produce a document based on the data in the request message-body, in
+ addition to meta-variable values. A common use is form submission in
+ HTML [18], intended to initiate processing by the script that has a
+ permanent affect, such a change in a database.
+
+ The script MUST check the value of the CONTENT_LENGTH variable before
+ reading the attached message-body, and SHOULD check the CONTENT_TYPE
+ value before processing it.
+
+4.3.3. HEAD
+
+ The HEAD method requests the script to do sufficient processing to
+ return the response header fields, without providing a response
+ message-body. The script MUST NOT provide a response message-body
+ for a HEAD request. If it does, then the server MUST discard the
+ message-body when reading the response from the script.
+
+4.3.4. Protocol-Specific Methods
+
+ The script MAY implement any protocol-specific method, such as
+ HTTP/1.1 PUT and DELETE; it SHOULD check the value of SERVER_PROTOCOL
+ when doing so.
+
+ The server MAY decide that some methods are not appropriate or
+ permitted for a script, and may handle the methods itself or return
+ an error to the client.
+
+4.4. The Script Command Line
+
+ Some systems support a method for supplying an array of strings to
+ the CGI script. This is only used in the case of an 'indexed' HTTP
+ query, which is identified by a 'GET' or 'HEAD' request with a URI
+ query string that does not contain any unencoded "=" characters. For
+ such a request, the server SHOULD treat the query-string as a
+ search-string and parse it into words, using the rules
+
+ search-string = search-word *( "+" search-word )
+ search-word = 1*schar
+ schar = unreserved | escaped | xreserved
+ xreserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "," |
+ "$"
+
+ After parsing, each search-word is URL-decoded, optionally encoded in
+ a system-defined manner and then added to the command line argument
+ list.
+
+
+
+Robinson & Coar Informational [Page 21]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ If the server cannot create any part of the argument list, then the
+ server MUST NOT generate any command line information. For example,
+ the number of arguments may be greater than operating system or
+ server limits, or one of the words may not be representable as an
+ argument.
+
+ The script SHOULD check to see if the QUERY_STRING value contains an
+ unencoded "=" character, and SHOULD NOT use the command line
+ arguments if it does.
+
+5. NPH Scripts
+
+5.1. Identification
+
+ The server MAY support NPH (Non-Parsed Header) scripts; these are
+ scripts to which the server passes all responsibility for response
+ processing.
+
+ This specification provides no mechanism for an NPH script to be
+ identified on the basis of its output data alone. By convention,
+ therefore, any particular script can only ever provide output of one
+ type (NPH or CGI) and hence the script itself is described as an 'NPH
+ script'. A server with NPH support MUST provide an implementation-
+ defined mechanism for identifying NPH scripts, perhaps based on the
+ name or location of the script.
+
+5.2. NPH Response
+
+ There MUST be a system-defined method for the script to send data
+ back to the server or client; a script MUST always return some data.
+ Unless defined otherwise, this will be the same as for conventional
+ CGI scripts.
+
+ Currently, NPH scripts are only defined for HTTP client requests. An
+ (HTTP) NPH script MUST return a complete HTTP response message,
+ currently described in section 6 of the HTTP specifications [1], [4].
+ The script MUST use the SERVER_PROTOCOL variable to determine the
+ appropriate format for a response. It MUST also take account of any
+ generic or protocol-specific meta-variables in the request as might
+ be mandated by the particular protocol specification.
+
+ The server MUST ensure that the script output is sent to the client
+ unmodified. Note that this requires the script to use the correct
+ character set (US-ASCII [9] and ISO 8859-1 [10] for HTTP) in the
+ header fields. The server SHOULD attempt to ensure that the script
+ output is sent directly to the client, with minimal internal and no
+ transport-visible buffering.
+
+
+
+
+Robinson & Coar Informational [Page 22]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ Unless the implementation defines otherwise, the script MUST NOT
+ indicate in its response that the client can send further requests
+ over the same connection.
+
+6. CGI Response
+
+6.1. Response Handling
+
+ A script MUST always provide a non-empty response, and so there is a
+ system-defined method for it to send this data back to the server.
+ Unless defined otherwise, this will be via the 'standard output' file
+ descriptor.
+
+ The script MUST check the REQUEST_METHOD variable when processing the
+ request and preparing its response.
+
+ The server MAY implement a timeout period within which data must be
+ received from the script. If a server implementation defines such a
+ timeout and receives no data from a script within the timeout period,
+ the server MAY terminate the script process.
+
+6.2. Response Types
+
+ The response comprises a message-header and a message-body, separated
+ by a blank line. The message-header contains one or more header
+ fields. The body may be NULL.
+
+ generic-response = 1*header-field NL [ response-body ]
+
+ The script MUST return one of either a document response, a local
+ redirect response or a client redirect (with optional document)
+ response. In the response definitions below, the order of header
+ fields in a response is not significant (despite appearing so in the
+ BNF). The header fields are defined in section 6.3.
+
+ CGI-Response = document-response | local-redir-response |
+ client-redir-response | client-redirdoc-response
+
+6.2.1. Document Response
+
+ The CGI script can return a document to the user in a document
+ response, with an optional error code indicating the success status
+ of the response.
+
+ document-response = Content-Type [ Status ] *other-field NL
+ response-body
+
+
+
+
+
+Robinson & Coar Informational [Page 23]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ The script MUST return a Content-Type header field. A Status header
+ field is optional, and status 200 'OK' is assumed if it is omitted.
+ The server MUST make any appropriate modifications to the script's
+ output to ensure that the response to the client complies with the
+ response protocol version.
+
+6.2.2. Local Redirect Response
+
+ The CGI script can return a URI path and query-string
+ ('local-pathquery') for a local resource in a Location header field.
+ This indicates to the server that it should reprocess the request
+ using the path specified.
+
+ local-redir-response = local-Location NL
+
+ The script MUST NOT return any other header fields or a message-body,
+ and the server MUST generate the response that it would have produced
+ in response to a request containing the URL
+
+ scheme "://" server-name ":" server-port local-pathquery
+
+6.2.3. Client Redirect Response
+
+ The CGI script can return an absolute URI path in a Location header
+ field, to indicate to the client that it should reprocess the request
+ using the URI specified.
+
+ client-redir-response = client-Location *extension-field NL
+
+ The script MUST not provide any other header fields, except for
+ server-defined CGI extension fields. For an HTTP client request, the
+ server MUST generate a 302 'Found' HTTP response message.
+
+6.2.4. Client Redirect Response with Document
+
+ The CGI script can return an absolute URI path in a Location header
+ field together with an attached document, to indicate to the client
+ that it should reprocess the request using the URI specified.
+
+ client-redirdoc-response = client-Location Status Content-Type
+ *other-field NL response-body
+
+ The Status header field MUST be supplied and MUST contain a status
+ value of 302 'Found', or it MAY contain an extension-code, that is,
+ another valid status code that means client redirection. The server
+ MUST make any appropriate modifications to the script's output to
+ ensure that the response to the client complies with the response
+ protocol version.
+
+
+
+Robinson & Coar Informational [Page 24]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+6.3. Response Header Fields
+
+ The response header fields are either CGI or extension header fields
+ to be interpreted by the server, or protocol-specific header fields
+ to be included in the response returned to the client. At least one
+ CGI field MUST be supplied; each CGI field MUST NOT appear more than
+ once in the response. The response header fields have the syntax:
+
+ header-field = CGI-field | other-field
+ CGI-field = Content-Type | Location | Status
+ other-field = protocol-field | extension-field
+ protocol-field = generic-field
+ extension-field = generic-field
+ generic-field = field-name ":" [ field-value ] NL
+ field-name = token
+ field-value = *( field-content | LWSP )
+ field-content = *( token | separator | quoted-string )
+
+ The field-name is not case sensitive. A NULL field value is
+ equivalent to a field not being sent. Note that each header field in
+ a CGI-Response MUST be specified on a single line; CGI/1.1 does not
+ support continuation lines. Whitespace is permitted between the ":"
+ and the field-value (but not between the field-name and the ":"), and
+ also between tokens in the field-value.
+
+6.3.1. Content-Type
+
+ The Content-Type response field sets the Internet Media Type [6] of
+ the entity body.
+
+ Content-Type = "Content-Type:" media-type NL
+
+ If an entity body is returned, the script MUST supply a Content-Type
+ field in the response. If it fails to do so, the server SHOULD NOT
+ attempt to determine the correct content type. The value SHOULD be
+ sent unmodified to the client, except for any charset parameter
+ changes.
+
+ Unless it is otherwise system-defined, the default charset assumed by
+ the client for text media-types is ISO-8859-1 if the protocol is HTTP
+ and US-ASCII otherwise. Hence the script SHOULD include a charset
+ parameter. See section 3.4.1 of the HTTP/1.1 specification [4] for a
+ discussion of this issue.
+
+
+
+
+
+
+
+
+Robinson & Coar Informational [Page 25]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+6.3.2. Location
+
+ The Location header field is used to specify to the server that the
+ script is returning a reference to a document rather than an actual
+ document (see sections 6.2.3 and 6.2.4). It is either an absolute
+ URI (optionally with a fragment identifier), indicating that the
+ client is to fetch the referenced document, or a local URI path
+ (optionally with a query string), indicating that the server is to
+ fetch the referenced document and return it to the client as the
+ response.
+
+ Location = local-Location | client-Location
+ client-Location = "Location:" fragment-URI NL
+ local-Location = "Location:" local-pathquery NL
+ fragment-URI = absoluteURI [ "#" fragment ]
+ fragment = *uric
+ local-pathquery = abs-path [ "?" query-string ]
+ abs-path = "/" path-segments
+ path-segments = segment *( "/" segment )
+ segment = *pchar
+ pchar = unreserved | escaped | extra
+ extra = ":" | "@" | "&" | "=" | "+" | "$" | ","
+
+ The syntax of an absoluteURI is incorporated into this document from
+ that specified in RFC 2396 [2] and RFC 2732 [7]. A valid absoluteURI
+ always starts with the name of scheme followed by ":"; scheme names
+ start with a letter and continue with alphanumerics, "+", "-" or ".".
+ The local URI path and query must be an absolute path, and not a
+ relative path or NULL, and hence must start with a "/".
+
+ Note that any message-body attached to the request (such as for a
+ POST request) may not be available to the resource that is the target
+ of the redirect.
+
+6.3.3. Status
+
+ The Status header field contains a 3-digit integer result code that
+ indicates the level of success of the script's attempt to handle the
+ request.
+
+ Status = "Status:" status-code SP reason-phrase NL
+ status-code = "200" | "302" | "400" | "501" | extension-code
+ extension-code = 3digit
+ reason-phrase = *TEXT
+
+ Status code 200 'OK' indicates success, and is the default value
+ assumed for a document response. Status code 302 'Found' is used
+ with a Location header field and response message-body. Status code
+
+
+
+Robinson & Coar Informational [Page 26]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ 400 'Bad Request' may be used for an unknown request format, such as
+ a missing CONTENT_TYPE. Status code 501 'Not Implemented' may be
+ returned by a script if it receives an unsupported REQUEST_METHOD.
+
+ Other valid status codes are listed in section 6.1.1 of the HTTP
+ specifications [1], [4], and also the IANA HTTP Status Code Registry
+ [8] and MAY be used in addition to or instead of the ones listed
+ above. The script SHOULD check the value of SERVER_PROTOCOL before
+ using HTTP/1.1 status codes. The script MAY reject with error 405
+ 'Method Not Allowed' HTTP/1.1 requests made using a method it does
+ not support.
+
+ Note that returning an error status code does not have to mean an
+ error condition with the script itself. For example, a script that
+ is invoked as an error handler by the server should return the code
+ appropriate to the server's error condition.
+
+ The reason-phrase is a textual description of the error to be
+ returned to the client for human consumption.
+
+6.3.4. Protocol-Specific Header Fields
+
+ The script MAY return any other header fields that relate to the
+ response message defined by the specification for the SERVER_PROTOCOL
+ (HTTP/1.0 [1] or HTTP/1.1 [4]). The server MUST translate the header
+ data from the CGI header syntax to the HTTP header syntax if these
+ differ. For example, the character sequence for newline (such as
+ UNIX's US-ASCII LF) used by CGI scripts may not be the same as that
+ used by HTTP (US-ASCII CR followed by LF).
+
+ The script MUST NOT return any header fields that relate to
+ client-side communication issues and could affect the server's
+ ability to send the response to the client. The server MAY remove
+ any such header fields returned by the client. It SHOULD resolve any
+ conflicts between header fields returned by the script and header
+ fields that it would otherwise send itself.
+
+6.3.5. Extension Header Fields
+
+ There may be additional implementation-defined CGI header fields,
+ whose field names SHOULD begin with "X-CGI-". The server MAY ignore
+ (and delete) any unrecognised header fields with names beginning "X-
+ CGI-" that are received from the script.
+
+
+
+
+
+
+
+
+Robinson & Coar Informational [Page 27]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+6.4. Response Message-Body
+
+ The response message-body is an attached document to be returned to
+ the client by the server. The server MUST read all the data provided
+ by the script, until the script signals the end of the message-body
+ by way of an end-of-file condition. The message-body SHOULD be sent
+ unmodified to the client, except for HEAD requests or any required
+ transfer-codings, content-codings or charset conversions.
+
+ response-body = *OCTET
+
+7. System Specifications
+
+7.1. AmigaDOS
+
+ Meta-Variables
+ Meta-variables are passed to the script in identically named
+ environment variables. These are accessed by the DOS library
+ routine GetVar(). The flags argument SHOULD be 0. Case is
+ ignored, but upper case is recommended for compatibility with
+ case-sensitive systems.
+
+ The current working directory
+ The current working directory for the script is set to the
+ directory containing the script.
+
+ Character set
+ The US-ASCII character set [9] is used for the definition of
+ meta-variables, header fields and values; the newline (NL)
+ sequence is LF; servers SHOULD also accept CR LF as a newline.
+
+7.2. UNIX
+
+ For UNIX compatible operating systems, the following are defined:
+
+ Meta-Variables
+ Meta-variables are passed to the script in identically named
+ environment variables. These are accessed by the C library
+ routine getenv() or variable environ.
+
+ The command line
+ This is accessed using the argc and argv arguments to main(). The
+ words have any characters which are 'active' in the Bourne shell
+ escaped with a backslash.
+
+ The current working directory
+ The current working directory for the script SHOULD be set to the
+ directory containing the script.
+
+
+
+Robinson & Coar Informational [Page 28]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ Character set
+ The US-ASCII character set [9], excluding NUL, is used for the
+ definition of meta-variables, header fields and CHAR values; TEXT
+ values use ISO-8859-1. The PATH_TRANSLATED value can contain any
+ 8-bit byte except NUL. The newline (NL) sequence is LF; servers
+ should also accept CR LF as a newline.
+
+7.3. EBCDIC/POSIX
+
+ For POSIX compatible operating systems using the EBCDIC character
+ set, the following are defined:
+
+ Meta-Variables
+ Meta-variables are passed to the script in identically named
+ environment variables. These are accessed by the C library
+ routine getenv().
+
+ The command line
+ This is accessed using the argc and argv arguments to main(). The
+ words have any characters which are 'active' in the Bourne shell
+ escaped with a backslash.
+
+ The current working directory
+ The current working directory for the script SHOULD be set to the
+ directory containing the script.
+
+ Character set
+ The IBM1047 character set [21], excluding NUL, is used for the
+ definition of meta-variables, header fields, values, TEXT strings
+ and the PATH_TRANSLATED value. The newline (NL) sequence is LF;
+ servers should also accept CR LF as a newline.
+
+ media-type charset default
+ The default charset value for text (and other implementation-
+ defined) media types is IBM1047.
+
+8. Implementation
+
+8.1. Recommendations for Servers
+
+ Although the server and the CGI script need not be consistent in
+ their handling of URL paths (client URLs and the PATH_INFO data,
+ respectively), server authors may wish to impose consistency. So the
+ server implementation should specify its behaviour for the following
+ cases:
+
+ 1. define any restrictions on allowed path segments, in particular
+ whether non-terminal NULL segments are permitted;
+
+
+
+Robinson & Coar Informational [Page 29]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ 2. define the behaviour for "." or ".." path segments; i.e.,
+ whether they are prohibited, treated as ordinary path segments
+ or interpreted in accordance with the relative URL
+ specification [2];
+
+ 3. define any limits of the implementation, including limits on
+ path or search string lengths, and limits on the volume of
+ header fields the server will parse.
+
+8.2. Recommendations for Scripts
+
+ If the script does not intend processing the PATH_INFO data, then it
+ should reject the request with 404 Not Found if PATH_INFO is not
+ NULL.
+
+ If the output of a form is being processed, check that CONTENT_TYPE
+ is "application/x-www-form-urlencoded" [18] or "multipart/form-data"
+ [16]. If CONTENT_TYPE is blank, the script can reject the request
+ with a 415 'Unsupported Media Type' error, where supported by the
+ protocol.
+
+ When parsing PATH_INFO, PATH_TRANSLATED or SCRIPT_NAME the script
+ should be careful of void path segments ("//") and special path
+ segments ("." and ".."). They should either be removed from the path
+ before use in OS system calls, or the request should be rejected with
+ 404 'Not Found'.
+
+ When returning header fields, the script should try to send the CGI
+ header fields as soon as possible, and should send them before any
+ HTTP header fields. This may help reduce the server's memory
+ requirements.
+
+ Script authors should be aware that the REMOTE_ADDR and REMOTE_HOST
+ meta-variables (see sections 4.1.8 and 4.1.9) may not identify the
+ ultimate source of the request. They identify the client for the
+ immediate request to the server; that client may be a proxy, gateway,
+ or other intermediary acting on behalf of the actual source client.
+
+9. Security Considerations
+
+9.1. Safe Methods
+
+ As discussed in the security considerations of the HTTP
+ specifications [1], [4], the convention has been established that the
+ GET and HEAD methods should be 'safe' and 'idempotent' (repeated
+ requests have the same effect as a single request). See section 9.1
+ of RFC 2616 [4] for a full discussion.
+
+
+
+
+Robinson & Coar Informational [Page 30]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+9.2. Header Fields Containing Sensitive Information
+
+ Some HTTP header fields may carry sensitive information which the
+ server should not pass on to the script unless explicitly configured
+ to do so. For example, if the server protects the script by using
+ the Basic authentication scheme, then the client will send an
+ Authorization header field containing a username and password. The
+ server validates this information and so it should not pass on the
+ password via the HTTP_AUTHORIZATION meta-variable without careful
+ consideration. This also applies to the Proxy-Authorization header
+ field and the corresponding HTTP_PROXY_AUTHORIZATION meta-variable.
+
+9.3. Data Privacy
+
+ Confidential data in a request should be placed in a message-body as
+ part of a POST request, and not placed in the URI or message headers.
+ On some systems, the environment used to pass meta-variables to a
+ script may be visible to other scripts or users. In addition, many
+ existing servers, proxies and clients will permanently record the URI
+ where it might be visible to third parties.
+
+9.4. Information Security Model
+
+ For a client connection using TLS, the security model applies between
+ the client and the server, and not between the client and the script.
+ It is the server's responsibility to handle the TLS session, and thus
+ it is the server which is authenticated to the client, not the CGI
+ script.
+
+ This specification provides no mechanism for the script to
+ authenticate the server which invoked it. There is no enforced
+ integrity on the CGI request and response messages.
+
+9.5. Script Interference with the Server
+
+ The most common implementation of CGI invokes the script as a child
+ process using the same user and group as the server process. It
+ should therefore be ensured that the script cannot interfere with the
+ server process, its configuration, documents or log files.
+
+ If the script is executed by calling a function linked in to the
+ server software (either at compile-time or run-time) then precautions
+ should be taken to protect the core memory of the server, or to
+ ensure that untrusted code cannot be executed.
+
+
+
+
+
+
+
+Robinson & Coar Informational [Page 31]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+9.6. Data Length and Buffering Considerations
+
+ This specification places no limits on the length of the message-body
+ presented to the script. The script should not assume that
+ statically allocated buffers of any size are sufficient to contain
+ the entire submission at one time. Use of a fixed length buffer
+ without careful overflow checking may result in an attacker
+ exploiting 'stack-smashing' or 'stack-overflow' vulnerabilities of
+ the operating system. The script may spool large submissions to disk
+ or other buffering media, but a rapid succession of large submissions
+ may result in denial of service conditions. If the CONTENT_LENGTH of
+ a message-body is larger than resource considerations allow, scripts
+ should respond with an error status appropriate for the protocol
+ version; potentially applicable status codes include 503 'Service
+ Unavailable' (HTTP/1.0 and HTTP/1.1), 413 'Request Entity Too Large'
+ (HTTP/1.1), and 414 'Request-URI Too Large' (HTTP/1.1).
+
+ Similar considerations apply to the server's handling of the CGI
+ response from the script. There is no limit on the length of the
+ header or message-body returned by the script; the server should not
+ assume that statically allocated buffers of any size are sufficient
+ to contain the entire response.
+
+9.7. Stateless Processing
+
+ The stateless nature of the Web makes each script execution and
+ resource retrieval independent of all others even when multiple
+ requests constitute a single conceptual Web transaction. Because of
+ this, a script should not make any assumptions about the context of
+ the user-agent submitting a request. In particular, scripts should
+ examine data obtained from the client and verify that they are valid,
+ both in form and content, before allowing them to be used for
+ sensitive purposes such as input to other applications, commands, or
+ operating system services. These uses include (but are not limited
+ to) system call arguments, database writes, dynamically evaluated
+ source code, and input to billing or other secure processes. It is
+ important that applications be protected from invalid input
+ regardless of whether the invalidity is the result of user error,
+ logic error, or malicious action.
+
+ Authors of scripts involved in multi-request transactions should be
+ particularly cautious about validating the state information;
+ undesirable effects may result from the substitution of dangerous
+ values for portions of the submission which might otherwise be
+ presumed safe. Subversion of this type occurs when alterations are
+ made to data from a prior stage of the transaction that were not
+ meant to be controlled by the client (e.g., hidden HTML form
+ elements, cookies, embedded URLs, etc.).
+
+
+
+Robinson & Coar Informational [Page 32]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+9.8. Relative Paths
+
+ The server should be careful of ".." path segments in the request
+ URI. These should be removed or resolved in the request URI before
+ it is split into the script-path and extra-path. Alternatively, when
+ the extra-path is used to find the PATH_TRANSLATED, care should be
+ taken to avoid the path resolution from providing translated paths
+ outside an expected path hierarchy.
+
+9.9. Non-parsed Header Output
+
+ If a script returns a non-parsed header output, to be interpreted by
+ the client in its native protocol, then the script must address all
+ security considerations relating to that protocol.
+
+10. Acknowledgements
+
+ This work is based on the original CGI interface that arose out of
+ discussions on the 'www-talk' mailing list. In particular, Rob
+ McCool, John Franks, Ari Luotonen, George Phillips and Tony Sanders
+ deserve special recognition for their efforts in defining and
+ implementing the early versions of this interface.
+
+ This document has also greatly benefited from the comments and
+ suggestions made Chris Adie, Dave Kristol and Mike Meyer; also David
+ Morris, Jeremy Madea, Patrick McManus, Adam Donahue, Ross Patterson
+ and Harald Alvestrand.
+
+11. References
+
+11.1 Normative References
+
+ [1] Berners-Lee, T., Fielding, R. and H. Frystyk, "Hypertext
+ Transfer Protocol -- HTTP/1.0", RFC 1945, May 1996.
+
+ [2] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform Resource
+ Identifiers (URI) : Generic Syntax", RFC 2396, August 1998.
+
+ [3] Bradner, S., "Key words for use in RFCs to Indicate Requirements
+ Levels", BCP 14, RFC 2119, March 1997.
+
+ [4] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L.,
+ Leach, P., and T. Berners-Lee, "Hypertext Transfer Protocol --
+ HTTP/1.1", RFC 2616, June 1999.
+
+ [5] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S.,
+ Leach, P., Luotonen, A., and L. Stewart, "HTTP Authentication:
+ Basic and Digest Access Authentication", RFC 2617, June 1999.
+
+
+
+Robinson & Coar Informational [Page 33]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ [6] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046, November
+ 1996.
+
+ [7] Hinden, R., Carpenter, B., and L. Masinter, "Format for Literal
+ IPv6 Addresses in URL's", RFC 2732, December 1999.
+
+ [8] "HTTP Status Code Registry",
+ http://www.iana.org/assignments/http-status-codes, IANA.
+
+ [9] "Information Systems -- Coded Character Sets -- 7-bit American
+ Standard Code for Information Interchange (7-Bit ASCII)", ANSI
+ INCITS.4-1986 (R2002).
+
+ [10] "Information technology -- 8-bit single-byte coded graphic
+ character sets -- Part 1: Latin alphabet No. 1", ISO/IEC
+ 8859-1:1998.
+
+11.2. Informative References
+
+ [11] Berners-Lee, T., "Universal Resource Identifiers in WWW: A
+ Unifying Syntax for the Expression of Names and Addresses of
+ Objects on the Network as used in the World-Wide Web", RFC 1630,
+ June 1994.
+
+ [12] Braden, R., Ed., "Requirements for Internet Hosts -- Application
+ and Support", STD 3, RFC 1123, October 1989.
+
+ [13] Crocker, D., "Standard for the Format of ARPA Internet Text
+ Messages", STD 11, RFC 822, August 1982.
+
+ [14] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC
+ 2246, January 1999.
+
+ [15] Hinden R. and S. Deering, "Internet Protocol Version 6 (IPv6)
+ Addressing Architecture", RFC 3513, April 2003.
+
+ [16] Masinter, L., "Returning Values from Forms:
+ multipart/form-data", RFC 2388, August 1998.
+
+ [17] Mockapetris, P., "Domain Names - Concepts and Facilities", STD
+ 13, RFC 1034, November 1987.
+
+ [18] Raggett, D., Le Hors, A., and I. Jacobs, Eds., "HTML 4.01
+ Specification", W3C Recommendation December 1999,
+ http://www.w3.org/TR/html401/.
+
+ [19] Rescola, E. "HTTP Over TLS", RFC 2818, May 2000.
+
+
+
+Robinson & Coar Informational [Page 34]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+ [20] St. Johns, M., "Identification Protocol", RFC 1413, February
+ 1993.
+
+ [21] IBM National Language Support Reference Manual Volume 2,
+ SE09-8002-01, March 1990.
+
+ [22] "The Common Gateway Interface",
+ http://hoohoo.ncsa.uiuc.edu/cgi/, NCSA, University of Illinois.
+
+12. Authors' Addresses
+
+ David Robinson
+ The Apache Software Foundation
+
+ EMail: drtr@apache.org
+
+
+ Ken A. L. Coar
+ The Apache Software Foundation
+
+ EMail: coar@apache.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Robinson & Coar Informational [Page 35]
+
+RFC 3875 CGI Version 1.1 October 2004
+
+
+13. Full Copyright Statement
+
+ Copyright (C) The Internet Society (2004). This document is subject
+ to the rights, licenses and restrictions contained in BCP 78 and at
+ www.rfc-editor.org, and except as set forth therein, the authors
+ retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+ Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the ISOC's procedures with respect to rights in ISOC Documents can
+ be found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at ietf-
+ ipr@ietf.org.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+Robinson & Coar Informational [Page 36]
+
diff --git a/standards/rfc3986.txt b/standards/rfc3986.txt
new file mode 100644
index 000000000..c56ed4eb7
--- /dev/null
+++ b/standards/rfc3986.txt
@@ -0,0 +1,3419 @@
+
+
+
+
+
+
+Network Working Group T. Berners-Lee
+Request for Comments: 3986 W3C/MIT
+STD: 66 R. Fielding
+Updates: 1738 Day Software
+Obsoletes: 2732, 2396, 1808 L. Masinter
+Category: Standards Track Adobe Systems
+ January 2005
+
+
+ Uniform Resource Identifier (URI): Generic Syntax
+
+Status of This Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2005).
+
+Abstract
+
+ A Uniform Resource Identifier (URI) is a compact sequence of
+ characters that identifies an abstract or physical resource. This
+ specification defines the generic URI syntax and a process for
+ resolving URI references that might be in relative form, along with
+ guidelines and security considerations for the use of URIs on the
+ Internet. The URI syntax defines a grammar that is a superset of all
+ valid URIs, allowing an implementation to parse the common components
+ of a URI reference without knowing the scheme-specific requirements
+ of every possible identifier. This specification does not define a
+ generative grammar for URIs; that task is performed by the individual
+ specifications of each URI scheme.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 1]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4
+ 1.1. Overview of URIs . . . . . . . . . . . . . . . . . . . . 4
+ 1.1.1. Generic Syntax . . . . . . . . . . . . . . . . . 6
+ 1.1.2. Examples . . . . . . . . . . . . . . . . . . . . 7
+ 1.1.3. URI, URL, and URN . . . . . . . . . . . . . . . 7
+ 1.2. Design Considerations . . . . . . . . . . . . . . . . . 8
+ 1.2.1. Transcription . . . . . . . . . . . . . . . . . 8
+ 1.2.2. Separating Identification from Interaction . . . 9
+ 1.2.3. Hierarchical Identifiers . . . . . . . . . . . . 10
+ 1.3. Syntax Notation . . . . . . . . . . . . . . . . . . . . 11
+ 2. Characters . . . . . . . . . . . . . . . . . . . . . . . . . . 11
+ 2.1. Percent-Encoding . . . . . . . . . . . . . . . . . . . . 12
+ 2.2. Reserved Characters . . . . . . . . . . . . . . . . . . 12
+ 2.3. Unreserved Characters . . . . . . . . . . . . . . . . . 13
+ 2.4. When to Encode or Decode . . . . . . . . . . . . . . . . 14
+ 2.5. Identifying Data . . . . . . . . . . . . . . . . . . . . 14
+ 3. Syntax Components . . . . . . . . . . . . . . . . . . . . . . 16
+ 3.1. Scheme . . . . . . . . . . . . . . . . . . . . . . . . . 17
+ 3.2. Authority . . . . . . . . . . . . . . . . . . . . . . . 17
+ 3.2.1. User Information . . . . . . . . . . . . . . . . 18
+ 3.2.2. Host . . . . . . . . . . . . . . . . . . . . . . 18
+ 3.2.3. Port . . . . . . . . . . . . . . . . . . . . . . 22
+ 3.3. Path . . . . . . . . . . . . . . . . . . . . . . . . . . 22
+ 3.4. Query . . . . . . . . . . . . . . . . . . . . . . . . . 23
+ 3.5. Fragment . . . . . . . . . . . . . . . . . . . . . . . . 24
+ 4. Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
+ 4.1. URI Reference . . . . . . . . . . . . . . . . . . . . . 25
+ 4.2. Relative Reference . . . . . . . . . . . . . . . . . . . 26
+ 4.3. Absolute URI . . . . . . . . . . . . . . . . . . . . . . 27
+ 4.4. Same-Document Reference . . . . . . . . . . . . . . . . 27
+ 4.5. Suffix Reference . . . . . . . . . . . . . . . . . . . . 27
+ 5. Reference Resolution . . . . . . . . . . . . . . . . . . . . . 28
+ 5.1. Establishing a Base URI . . . . . . . . . . . . . . . . 28
+ 5.1.1. Base URI Embedded in Content . . . . . . . . . . 29
+ 5.1.2. Base URI from the Encapsulating Entity . . . . . 29
+ 5.1.3. Base URI from the Retrieval URI . . . . . . . . 30
+ 5.1.4. Default Base URI . . . . . . . . . . . . . . . . 30
+ 5.2. Relative Resolution . . . . . . . . . . . . . . . . . . 30
+ 5.2.1. Pre-parse the Base URI . . . . . . . . . . . . . 31
+ 5.2.2. Transform References . . . . . . . . . . . . . . 31
+ 5.2.3. Merge Paths . . . . . . . . . . . . . . . . . . 32
+ 5.2.4. Remove Dot Segments . . . . . . . . . . . . . . 33
+ 5.3. Component Recomposition . . . . . . . . . . . . . . . . 35
+ 5.4. Reference Resolution Examples . . . . . . . . . . . . . 35
+ 5.4.1. Normal Examples . . . . . . . . . . . . . . . . 36
+ 5.4.2. Abnormal Examples . . . . . . . . . . . . . . . 36
+
+
+
+Berners-Lee, et al. Standards Track [Page 2]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ 6. Normalization and Comparison . . . . . . . . . . . . . . . . . 38
+ 6.1. Equivalence . . . . . . . . . . . . . . . . . . . . . . 38
+ 6.2. Comparison Ladder . . . . . . . . . . . . . . . . . . . 39
+ 6.2.1. Simple String Comparison . . . . . . . . . . . . 39
+ 6.2.2. Syntax-Based Normalization . . . . . . . . . . . 40
+ 6.2.3. Scheme-Based Normalization . . . . . . . . . . . 41
+ 6.2.4. Protocol-Based Normalization . . . . . . . . . . 42
+ 7. Security Considerations . . . . . . . . . . . . . . . . . . . 43
+ 7.1. Reliability and Consistency . . . . . . . . . . . . . . 43
+ 7.2. Malicious Construction . . . . . . . . . . . . . . . . . 43
+ 7.3. Back-End Transcoding . . . . . . . . . . . . . . . . . . 44
+ 7.4. Rare IP Address Formats . . . . . . . . . . . . . . . . 45
+ 7.5. Sensitive Information . . . . . . . . . . . . . . . . . 45
+ 7.6. Semantic Attacks . . . . . . . . . . . . . . . . . . . . 45
+ 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 46
+ 9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 46
+ 10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 46
+ 10.1. Normative References . . . . . . . . . . . . . . . . . . 46
+ 10.2. Informative References . . . . . . . . . . . . . . . . . 47
+ A. Collected ABNF for URI . . . . . . . . . . . . . . . . . . . . 49
+ B. Parsing a URI Reference with a Regular Expression . . . . . . 50
+ C. Delimiting a URI in Context . . . . . . . . . . . . . . . . . 51
+ D. Changes from RFC 2396 . . . . . . . . . . . . . . . . . . . . 53
+ D.1. Additions . . . . . . . . . . . . . . . . . . . . . . . 53
+ D.2. Modifications . . . . . . . . . . . . . . . . . . . . . 53
+ Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 60
+ Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 61
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 3]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+1. Introduction
+
+ A Uniform Resource Identifier (URI) provides a simple and extensible
+ means for identifying a resource. This specification of URI syntax
+ and semantics is derived from concepts introduced by the World Wide
+ Web global information initiative, whose use of these identifiers
+ dates from 1990 and is described in "Universal Resource Identifiers
+ in WWW" [RFC1630]. The syntax is designed to meet the
+ recommendations laid out in "Functional Recommendations for Internet
+ Resource Locators" [RFC1736] and "Functional Requirements for Uniform
+ Resource Names" [RFC1737].
+
+ This document obsoletes [RFC2396], which merged "Uniform Resource
+ Locators" [RFC1738] and "Relative Uniform Resource Locators"
+ [RFC1808] in order to define a single, generic syntax for all URIs.
+ It obsoletes [RFC2732], which introduced syntax for an IPv6 address.
+ It excludes portions of RFC 1738 that defined the specific syntax of
+ individual URI schemes; those portions will be updated as separate
+ documents. The process for registration of new URI schemes is
+ defined separately by [BCP35]. Advice for designers of new URI
+ schemes can be found in [RFC2718]. All significant changes from RFC
+ 2396 are noted in Appendix D.
+
+ This specification uses the terms "character" and "coded character
+ set" in accordance with the definitions provided in [BCP19], and
+ "character encoding" in place of what [BCP19] refers to as a
+ "charset".
+
+1.1. Overview of URIs
+
+ URIs are characterized as follows:
+
+ Uniform
+
+ Uniformity provides several benefits. It allows different types
+ of resource identifiers to be used in the same context, even when
+ the mechanisms used to access those resources may differ. It
+ allows uniform semantic interpretation of common syntactic
+ conventions across different types of resource identifiers. It
+ allows introduction of new types of resource identifiers without
+ interfering with the way that existing identifiers are used. It
+ allows the identifiers to be reused in many different contexts,
+ thus permitting new applications or protocols to leverage a pre-
+ existing, large, and widely used set of resource identifiers.
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 4]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ Resource
+
+ This specification does not limit the scope of what might be a
+ resource; rather, the term "resource" is used in a general sense
+ for whatever might be identified by a URI. Familiar examples
+ include an electronic document, an image, a source of information
+ with a consistent purpose (e.g., "today's weather report for Los
+ Angeles"), a service (e.g., an HTTP-to-SMS gateway), and a
+ collection of other resources. A resource is not necessarily
+ accessible via the Internet; e.g., human beings, corporations, and
+ bound books in a library can also be resources. Likewise,
+ abstract concepts can be resources, such as the operators and
+ operands of a mathematical equation, the types of a relationship
+ (e.g., "parent" or "employee"), or numeric values (e.g., zero,
+ one, and infinity).
+
+ Identifier
+
+ An identifier embodies the information required to distinguish
+ what is being identified from all other things within its scope of
+ identification. Our use of the terms "identify" and "identifying"
+ refer to this purpose of distinguishing one resource from all
+ other resources, regardless of how that purpose is accomplished
+ (e.g., by name, address, or context). These terms should not be
+ mistaken as an assumption that an identifier defines or embodies
+ the identity of what is referenced, though that may be the case
+ for some identifiers. Nor should it be assumed that a system
+ using URIs will access the resource identified: in many cases,
+ URIs are used to denote resources without any intention that they
+ be accessed. Likewise, the "one" resource identified might not be
+ singular in nature (e.g., a resource might be a named set or a
+ mapping that varies over time).
+
+ A URI is an identifier consisting of a sequence of characters
+ matching the syntax rule named <URI> in Section 3. It enables
+ uniform identification of resources via a separately defined
+ extensible set of naming schemes (Section 3.1). How that
+ identification is accomplished, assigned, or enabled is delegated to
+ each scheme specification.
+
+ This specification does not place any limits on the nature of a
+ resource, the reasons why an application might seek to refer to a
+ resource, or the kinds of systems that might use URIs for the sake of
+ identifying resources. This specification does not require that a
+ URI persists in identifying the same resource over time, though that
+ is a common goal of all URI schemes. Nevertheless, nothing in this
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 5]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ specification prevents an application from limiting itself to
+ particular types of resources, or to a subset of URIs that maintains
+ characteristics desired by that application.
+
+ URIs have a global scope and are interpreted consistently regardless
+ of context, though the result of that interpretation may be in
+ relation to the end-user's context. For example, "http://localhost/"
+ has the same interpretation for every user of that reference, even
+ though the network interface corresponding to "localhost" may be
+ different for each end-user: interpretation is independent of access.
+ However, an action made on the basis of that reference will take
+ place in relation to the end-user's context, which implies that an
+ action intended to refer to a globally unique thing must use a URI
+ that distinguishes that resource from all other things. URIs that
+ identify in relation to the end-user's local context should only be
+ used when the context itself is a defining aspect of the resource,
+ such as when an on-line help manual refers to a file on the end-
+ user's file system (e.g., "file:///etc/hosts").
+
+1.1.1. Generic Syntax
+
+ Each URI begins with a scheme name, as defined in Section 3.1, that
+ refers to a specification for assigning identifiers within that
+ scheme. As such, the URI syntax is a federated and extensible naming
+ system wherein each scheme's specification may further restrict the
+ syntax and semantics of identifiers using that scheme.
+
+ This specification defines those elements of the URI syntax that are
+ required of all URI schemes or are common to many URI schemes. It
+ thus defines the syntax and semantics needed to implement a scheme-
+ independent parsing mechanism for URI references, by which the
+ scheme-dependent handling of a URI can be postponed until the
+ scheme-dependent semantics are needed. Likewise, protocols and data
+ formats that make use of URI references can refer to this
+ specification as a definition for the range of syntax allowed for all
+ URIs, including those schemes that have yet to be defined. This
+ decouples the evolution of identification schemes from the evolution
+ of protocols, data formats, and implementations that make use of
+ URIs.
+
+ A parser of the generic URI syntax can parse any URI reference into
+ its major components. Once the scheme is determined, further
+ scheme-specific parsing can be performed on the components. In other
+ words, the URI generic syntax is a superset of the syntax of all URI
+ schemes.
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 6]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+1.1.2. Examples
+
+ The following example URIs illustrate several URI schemes and
+ variations in their common syntax components:
+
+ ftp://ftp.is.co.za/rfc/rfc1808.txt
+
+ http://www.ietf.org/rfc/rfc2396.txt
+
+ ldap://[2001:db8::7]/c=GB?objectClass?one
+
+ mailto:John.Doe@example.com
+
+ news:comp.infosystems.www.servers.unix
+
+ tel:+1-816-555-1212
+
+ telnet://192.0.2.16:80/
+
+ urn:oasis:names:specification:docbook:dtd:xml:4.1.2
+
+
+1.1.3. URI, URL, and URN
+
+ A URI can be further classified as a locator, a name, or both. The
+ term "Uniform Resource Locator" (URL) refers to the subset of URIs
+ that, in addition to identifying a resource, provide a means of
+ locating the resource by describing its primary access mechanism
+ (e.g., its network "location"). The term "Uniform Resource Name"
+ (URN) has been used historically to refer to both URIs under the
+ "urn" scheme [RFC2141], which are required to remain globally unique
+ and persistent even when the resource ceases to exist or becomes
+ unavailable, and to any other URI with the properties of a name.
+
+ An individual scheme does not have to be classified as being just one
+ of "name" or "locator". Instances of URIs from any given scheme may
+ have the characteristics of names or locators or both, often
+ depending on the persistence and care in the assignment of
+ identifiers by the naming authority, rather than on any quality of
+ the scheme. Future specifications and related documentation should
+ use the general term "URI" rather than the more restrictive terms
+ "URL" and "URN" [RFC3305].
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 7]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+1.2. Design Considerations
+
+1.2.1. Transcription
+
+ The URI syntax has been designed with global transcription as one of
+ its main considerations. A URI is a sequence of characters from a
+ very limited set: the letters of the basic Latin alphabet, digits,
+ and a few special characters. A URI may be represented in a variety
+ of ways; e.g., ink on paper, pixels on a screen, or a sequence of
+ character encoding octets. The interpretation of a URI depends only
+ on the characters used and not on how those characters are
+ represented in a network protocol.
+
+ The goal of transcription can be described by a simple scenario.
+ Imagine two colleagues, Sam and Kim, sitting in a pub at an
+ international conference and exchanging research ideas. Sam asks Kim
+ for a location to get more information, so Kim writes the URI for the
+ research site on a napkin. Upon returning home, Sam takes out the
+ napkin and types the URI into a computer, which then retrieves the
+ information to which Kim referred.
+
+ There are several design considerations revealed by the scenario:
+
+ o A URI is a sequence of characters that is not always represented
+ as a sequence of octets.
+
+ o A URI might be transcribed from a non-network source and thus
+ should consist of characters that are most likely able to be
+ entered into a computer, within the constraints imposed by
+ keyboards (and related input devices) across languages and
+ locales.
+
+ o A URI often has to be remembered by people, and it is easier for
+ people to remember a URI when it consists of meaningful or
+ familiar components.
+
+ These design considerations are not always in alignment. For
+ example, it is often the case that the most meaningful name for a URI
+ component would require characters that cannot be typed into some
+ systems. The ability to transcribe a resource identifier from one
+ medium to another has been considered more important than having a
+ URI consist of the most meaningful of components.
+
+ In local or regional contexts and with improving technology, users
+ might benefit from being able to use a wider range of characters;
+ such use is not defined by this specification. Percent-encoded
+ octets (Section 2.1) may be used within a URI to represent characters
+ outside the range of the US-ASCII coded character set if this
+
+
+
+Berners-Lee, et al. Standards Track [Page 8]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ representation is allowed by the scheme or by the protocol element in
+ which the URI is referenced. Such a definition should specify the
+ character encoding used to map those characters to octets prior to
+ being percent-encoded for the URI.
+
+1.2.2. Separating Identification from Interaction
+
+ A common misunderstanding of URIs is that they are only used to refer
+ to accessible resources. The URI itself only provides
+ identification; access to the resource is neither guaranteed nor
+ implied by the presence of a URI. Instead, any operation associated
+ with a URI reference is defined by the protocol element, data format
+ attribute, or natural language text in which it appears.
+
+ Given a URI, a system may attempt to perform a variety of operations
+ on the resource, as might be characterized by words such as "access",
+ "update", "replace", or "find attributes". Such operations are
+ defined by the protocols that make use of URIs, not by this
+ specification. However, we do use a few general terms for describing
+ common operations on URIs. URI "resolution" is the process of
+ determining an access mechanism and the appropriate parameters
+ necessary to dereference a URI; this resolution may require several
+ iterations. To use that access mechanism to perform an action on the
+ URI's resource is to "dereference" the URI.
+
+ When URIs are used within information retrieval systems to identify
+ sources of information, the most common form of URI dereference is
+ "retrieval": making use of a URI in order to retrieve a
+ representation of its associated resource. A "representation" is a
+ sequence of octets, along with representation metadata describing
+ those octets, that constitutes a record of the state of the resource
+ at the time when the representation is generated. Retrieval is
+ achieved by a process that might include using the URI as a cache key
+ to check for a locally cached representation, resolution of the URI
+ to determine an appropriate access mechanism (if any), and
+ dereference of the URI for the sake of applying a retrieval
+ operation. Depending on the protocols used to perform the retrieval,
+ additional information might be supplied about the resource (resource
+ metadata) and its relation to other resources.
+
+ URI references in information retrieval systems are designed to be
+ late-binding: the result of an access is generally determined when it
+ is accessed and may vary over time or due to other aspects of the
+ interaction. These references are created in order to be used in the
+ future: what is being identified is not some specific result that was
+ obtained in the past, but rather some characteristic that is expected
+ to be true for future results. In such cases, the resource referred
+ to by the URI is actually a sameness of characteristics as observed
+
+
+
+Berners-Lee, et al. Standards Track [Page 9]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ over time, perhaps elucidated by additional comments or assertions
+ made by the resource provider.
+
+ Although many URI schemes are named after protocols, this does not
+ imply that use of these URIs will result in access to the resource
+ via the named protocol. URIs are often used simply for the sake of
+ identification. Even when a URI is used to retrieve a representation
+ of a resource, that access might be through gateways, proxies,
+ caches, and name resolution services that are independent of the
+ protocol associated with the scheme name. The resolution of some
+ URIs may require the use of more than one protocol (e.g., both DNS
+ and HTTP are typically used to access an "http" URI's origin server
+ when a representation isn't found in a local cache).
+
+1.2.3. Hierarchical Identifiers
+
+ The URI syntax is organized hierarchically, with components listed in
+ order of decreasing significance from left to right. For some URI
+ schemes, the visible hierarchy is limited to the scheme itself:
+ everything after the scheme component delimiter (":") is considered
+ opaque to URI processing. Other URI schemes make the hierarchy
+ explicit and visible to generic parsing algorithms.
+
+ The generic syntax uses the slash ("/"), question mark ("?"), and
+ number sign ("#") characters to delimit components that are
+ significant to the generic parser's hierarchical interpretation of an
+ identifier. In addition to aiding the readability of such
+ identifiers through the consistent use of familiar syntax, this
+ uniform representation of hierarchy across naming schemes allows
+ scheme-independent references to be made relative to that hierarchy.
+
+ It is often the case that a group or "tree" of documents has been
+ constructed to serve a common purpose, wherein the vast majority of
+ URI references in these documents point to resources within the tree
+ rather than outside it. Similarly, documents located at a particular
+ site are much more likely to refer to other resources at that site
+ than to resources at remote sites. Relative referencing of URIs
+ allows document trees to be partially independent of their location
+ and access scheme. For instance, it is possible for a single set of
+ hypertext documents to be simultaneously accessible and traversable
+ via each of the "file", "http", and "ftp" schemes if the documents
+ refer to each other with relative references. Furthermore, such
+ document trees can be moved, as a whole, without changing any of the
+ relative references.
+
+ A relative reference (Section 4.2) refers to a resource by describing
+ the difference within a hierarchical name space between the reference
+ context and the target URI. The reference resolution algorithm,
+
+
+
+Berners-Lee, et al. Standards Track [Page 10]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ presented in Section 5, defines how such a reference is transformed
+ to the target URI. As relative references can only be used within
+ the context of a hierarchical URI, designers of new URI schemes
+ should use a syntax consistent with the generic syntax's hierarchical
+ components unless there are compelling reasons to forbid relative
+ referencing within that scheme.
+
+ NOTE: Previous specifications used the terms "partial URI" and
+ "relative URI" to denote a relative reference to a URI. As some
+ readers misunderstood those terms to mean that relative URIs are a
+ subset of URIs rather than a method of referencing URIs, this
+ specification simply refers to them as relative references.
+
+ All URI references are parsed by generic syntax parsers when used.
+ However, because hierarchical processing has no effect on an absolute
+ URI used in a reference unless it contains one or more dot-segments
+ (complete path segments of "." or "..", as described in Section 3.3),
+ URI scheme specifications can define opaque identifiers by
+ disallowing use of slash characters, question mark characters, and
+ the URIs "scheme:." and "scheme:..".
+
+1.3. Syntax Notation
+
+ This specification uses the Augmented Backus-Naur Form (ABNF)
+ notation of [RFC2234], including the following core ABNF syntax rules
+ defined by that specification: ALPHA (letters), CR (carriage return),
+ DIGIT (decimal digits), DQUOTE (double quote), HEXDIG (hexadecimal
+ digits), LF (line feed), and SP (space). The complete URI syntax is
+ collected in Appendix A.
+
+2. Characters
+
+ The URI syntax provides a method of encoding data, presumably for the
+ sake of identifying a resource, as a sequence of characters. The URI
+ characters are, in turn, frequently encoded as octets for transport
+ or presentation. This specification does not mandate any particular
+ character encoding for mapping between URI characters and the octets
+ used to store or transmit those characters. When a URI appears in a
+ protocol element, the character encoding is defined by that protocol;
+ without such a definition, a URI is assumed to be in the same
+ character encoding as the surrounding text.
+
+ The ABNF notation defines its terminal values to be non-negative
+ integers (codepoints) based on the US-ASCII coded character set
+ [ASCII]. Because a URI is a sequence of characters, we must invert
+ that relation in order to understand the URI syntax. Therefore, the
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 11]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ integer values used by the ABNF must be mapped back to their
+ corresponding characters via US-ASCII in order to complete the syntax
+ rules.
+
+ A URI is composed from a limited set of characters consisting of
+ digits, letters, and a few graphic symbols. A reserved subset of
+ those characters may be used to delimit syntax components within a
+ URI while the remaining characters, including both the unreserved set
+ and those reserved characters not acting as delimiters, define each
+ component's identifying data.
+
+2.1. Percent-Encoding
+
+ A percent-encoding mechanism is used to represent a data octet in a
+ component when that octet's corresponding character is outside the
+ allowed set or is being used as a delimiter of, or within, the
+ component. A percent-encoded octet is encoded as a character
+ triplet, consisting of the percent character "%" followed by the two
+ hexadecimal digits representing that octet's numeric value. For
+ example, "%20" is the percent-encoding for the binary octet
+ "00100000" (ABNF: %x20), which in US-ASCII corresponds to the space
+ character (SP). Section 2.4 describes when percent-encoding and
+ decoding is applied.
+
+ pct-encoded = "%" HEXDIG HEXDIG
+
+ The uppercase hexadecimal digits 'A' through 'F' are equivalent to
+ the lowercase digits 'a' through 'f', respectively. If two URIs
+ differ only in the case of hexadecimal digits used in percent-encoded
+ octets, they are equivalent. For consistency, URI producers and
+ normalizers should use uppercase hexadecimal digits for all percent-
+ encodings.
+
+2.2. Reserved Characters
+
+ URIs include components and subcomponents that are delimited by
+ characters in the "reserved" set. These characters are called
+ "reserved" because they may (or may not) be defined as delimiters by
+ the generic syntax, by each scheme-specific syntax, or by the
+ implementation-specific syntax of a URI's dereferencing algorithm.
+ If data for a URI component would conflict with a reserved
+ character's purpose as a delimiter, then the conflicting data must be
+ percent-encoded before the URI is formed.
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 12]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ reserved = gen-delims / sub-delims
+
+ gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+
+ sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ / "*" / "+" / "," / ";" / "="
+
+ The purpose of reserved characters is to provide a set of delimiting
+ characters that are distinguishable from other data within a URI.
+ URIs that differ in the replacement of a reserved character with its
+ corresponding percent-encoded octet are not equivalent. Percent-
+ encoding a reserved character, or decoding a percent-encoded octet
+ that corresponds to a reserved character, will change how the URI is
+ interpreted by most applications. Thus, characters in the reserved
+ set are protected from normalization and are therefore safe to be
+ used by scheme-specific and producer-specific algorithms for
+ delimiting data subcomponents within a URI.
+
+ A subset of the reserved characters (gen-delims) is used as
+ delimiters of the generic URI components described in Section 3. A
+ component's ABNF syntax rule will not use the reserved or gen-delims
+ rule names directly; instead, each syntax rule lists the characters
+ allowed within that component (i.e., not delimiting it), and any of
+ those characters that are also in the reserved set are "reserved" for
+ use as subcomponent delimiters within the component. Only the most
+ common subcomponents are defined by this specification; other
+ subcomponents may be defined by a URI scheme's specification, or by
+ the implementation-specific syntax of a URI's dereferencing
+ algorithm, provided that such subcomponents are delimited by
+ characters in the reserved set allowed within that component.
+
+ URI producing applications should percent-encode data octets that
+ correspond to characters in the reserved set unless these characters
+ are specifically allowed by the URI scheme to represent data in that
+ component. If a reserved character is found in a URI component and
+ no delimiting role is known for that character, then it must be
+ interpreted as representing the data octet corresponding to that
+ character's encoding in US-ASCII.
+
+2.3. Unreserved Characters
+
+ Characters that are allowed in a URI but do not have a reserved
+ purpose are called unreserved. These include uppercase and lowercase
+ letters, decimal digits, hyphen, period, underscore, and tilde.
+
+ unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 13]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ URIs that differ in the replacement of an unreserved character with
+ its corresponding percent-encoded US-ASCII octet are equivalent: they
+ identify the same resource. However, URI comparison implementations
+ do not always perform normalization prior to comparison (see Section
+ 6). For consistency, percent-encoded octets in the ranges of ALPHA
+ (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), period (%2E),
+ underscore (%5F), or tilde (%7E) should not be created by URI
+ producers and, when found in a URI, should be decoded to their
+ corresponding unreserved characters by URI normalizers.
+
+2.4. When to Encode or Decode
+
+ Under normal circumstances, the only time when octets within a URI
+ are percent-encoded is during the process of producing the URI from
+ its component parts. This is when an implementation determines which
+ of the reserved characters are to be used as subcomponent delimiters
+ and which can be safely used as data. Once produced, a URI is always
+ in its percent-encoded form.
+
+ When a URI is dereferenced, the components and subcomponents
+ significant to the scheme-specific dereferencing process (if any)
+ must be parsed and separated before the percent-encoded octets within
+ those components can be safely decoded, as otherwise the data may be
+ mistaken for component delimiters. The only exception is for
+ percent-encoded octets corresponding to characters in the unreserved
+ set, which can be decoded at any time. For example, the octet
+ corresponding to the tilde ("~") character is often encoded as "%7E"
+ by older URI processing implementations; the "%7E" can be replaced by
+ "~" without changing its interpretation.
+
+ Because the percent ("%") character serves as the indicator for
+ percent-encoded octets, it must be percent-encoded as "%25" for that
+ octet to be used as data within a URI. Implementations must not
+ percent-encode or decode the same string more than once, as decoding
+ an already decoded string might lead to misinterpreting a percent
+ data octet as the beginning of a percent-encoding, or vice versa in
+ the case of percent-encoding an already percent-encoded string.
+
+2.5. Identifying Data
+
+ URI characters provide identifying data for each of the URI
+ components, serving as an external interface for identification
+ between systems. Although the presence and nature of the URI
+ production interface is hidden from clients that use its URIs (and is
+ thus beyond the scope of the interoperability requirements defined by
+ this specification), it is a frequent source of confusion and errors
+ in the interpretation of URI character issues. Implementers have to
+ be aware that there are multiple character encodings involved in the
+
+
+
+Berners-Lee, et al. Standards Track [Page 14]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ production and transmission of URIs: local name and data encoding,
+ public interface encoding, URI character encoding, data format
+ encoding, and protocol encoding.
+
+ Local names, such as file system names, are stored with a local
+ character encoding. URI producing applications (e.g., origin
+ servers) will typically use the local encoding as the basis for
+ producing meaningful names. The URI producer will transform the
+ local encoding to one that is suitable for a public interface and
+ then transform the public interface encoding into the restricted set
+ of URI characters (reserved, unreserved, and percent-encodings).
+ Those characters are, in turn, encoded as octets to be used as a
+ reference within a data format (e.g., a document charset), and such
+ data formats are often subsequently encoded for transmission over
+ Internet protocols.
+
+ For most systems, an unreserved character appearing within a URI
+ component is interpreted as representing the data octet corresponding
+ to that character's encoding in US-ASCII. Consumers of URIs assume
+ that the letter "X" corresponds to the octet "01011000", and even
+ when that assumption is incorrect, there is no harm in making it. A
+ system that internally provides identifiers in the form of a
+ different character encoding, such as EBCDIC, will generally perform
+ character translation of textual identifiers to UTF-8 [STD63] (or
+ some other superset of the US-ASCII character encoding) at an
+ internal interface, thereby providing more meaningful identifiers
+ than those resulting from simply percent-encoding the original
+ octets.
+
+ For example, consider an information service that provides data,
+ stored locally using an EBCDIC-based file system, to clients on the
+ Internet through an HTTP server. When an author creates a file with
+ the name "Laguna Beach" on that file system, the "http" URI
+ corresponding to that resource is expected to contain the meaningful
+ string "Laguna%20Beach". If, however, that server produces URIs by
+ using an overly simplistic raw octet mapping, then the result would
+ be a URI containing "%D3%81%87%A4%95%81@%C2%85%81%83%88". An
+ internal transcoding interface fixes this problem by transcoding the
+ local name to a superset of US-ASCII prior to producing the URI.
+ Naturally, proper interpretation of an incoming URI on such an
+ interface requires that percent-encoded octets be decoded (e.g.,
+ "%20" to SP) before the reverse transcoding is applied to obtain the
+ local name.
+
+ In some cases, the internal interface between a URI component and the
+ identifying data that it has been crafted to represent is much less
+ direct than a character encoding translation. For example, portions
+ of a URI might reflect a query on non-ASCII data, or numeric
+
+
+
+Berners-Lee, et al. Standards Track [Page 15]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ coordinates on a map. Likewise, a URI scheme may define components
+ with additional encoding requirements that are applied prior to
+ forming the component and producing the URI.
+
+ When a new URI scheme defines a component that represents textual
+ data consisting of characters from the Universal Character Set [UCS],
+ the data should first be encoded as octets according to the UTF-8
+ character encoding [STD63]; then only those octets that do not
+ correspond to characters in the unreserved set should be percent-
+ encoded. For example, the character A would be represented as "A",
+ the character LATIN CAPITAL LETTER A WITH GRAVE would be represented
+ as "%C3%80", and the character KATAKANA LETTER A would be represented
+ as "%E3%82%A2".
+
+3. Syntax Components
+
+ The generic URI syntax consists of a hierarchical sequence of
+ components referred to as the scheme, authority, path, query, and
+ fragment.
+
+ URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+
+ hier-part = "//" authority path-abempty
+ / path-absolute
+ / path-rootless
+ / path-empty
+
+ The scheme and path components are required, though the path may be
+ empty (no characters). When authority is present, the path must
+ either be empty or begin with a slash ("/") character. When
+ authority is not present, the path cannot begin with two slash
+ characters ("//"). These restrictions result in five different ABNF
+ rules for a path (Section 3.3), only one of which will match any
+ given URI reference.
+
+ The following are two example URIs and their component parts:
+
+ foo://example.com:8042/over/there?name=ferret#nose
+ \_/ \______________/\_________/ \_________/ \__/
+ | | | | |
+ scheme authority path query fragment
+ | _____________________|__
+ / \ / \
+ urn:example:animal:ferret:nose
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 16]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+3.1. Scheme
+
+ Each URI begins with a scheme name that refers to a specification for
+ assigning identifiers within that scheme. As such, the URI syntax is
+ a federated and extensible naming system wherein each scheme's
+ specification may further restrict the syntax and semantics of
+ identifiers using that scheme.
+
+ Scheme names consist of a sequence of characters beginning with a
+ letter and followed by any combination of letters, digits, plus
+ ("+"), period ("."), or hyphen ("-"). Although schemes are case-
+ insensitive, the canonical form is lowercase and documents that
+ specify schemes must do so with lowercase letters. An implementation
+ should accept uppercase letters as equivalent to lowercase in scheme
+ names (e.g., allow "HTTP" as well as "http") for the sake of
+ robustness but should only produce lowercase scheme names for
+ consistency.
+
+ scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+
+ Individual schemes are not specified by this document. The process
+ for registration of new URI schemes is defined separately by [BCP35].
+ The scheme registry maintains the mapping between scheme names and
+ their specifications. Advice for designers of new URI schemes can be
+ found in [RFC2718]. URI scheme specifications must define their own
+ syntax so that all strings matching their scheme-specific syntax will
+ also match the <absolute-URI> grammar, as described in Section 4.3.
+
+ When presented with a URI that violates one or more scheme-specific
+ restrictions, the scheme-specific resolution process should flag the
+ reference as an error rather than ignore the unused parts; doing so
+ reduces the number of equivalent URIs and helps detect abuses of the
+ generic syntax, which might indicate that the URI has been
+ constructed to mislead the user (Section 7.6).
+
+3.2. Authority
+
+ Many URI schemes include a hierarchical element for a naming
+ authority so that governance of the name space defined by the
+ remainder of the URI is delegated to that authority (which may, in
+ turn, delegate it further). The generic syntax provides a common
+ means for distinguishing an authority based on a registered name or
+ server address, along with optional port and user information.
+
+ The authority component is preceded by a double slash ("//") and is
+ terminated by the next slash ("/"), question mark ("?"), or number
+ sign ("#") character, or by the end of the URI.
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 17]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ authority = [ userinfo "@" ] host [ ":" port ]
+
+ URI producers and normalizers should omit the ":" delimiter that
+ separates host from port if the port component is empty. Some
+ schemes do not allow the userinfo and/or port subcomponents.
+
+ If a URI contains an authority component, then the path component
+ must either be empty or begin with a slash ("/") character. Non-
+ validating parsers (those that merely separate a URI reference into
+ its major components) will often ignore the subcomponent structure of
+ authority, treating it as an opaque string from the double-slash to
+ the first terminating delimiter, until such time as the URI is
+ dereferenced.
+
+3.2.1. User Information
+
+ The userinfo subcomponent may consist of a user name and, optionally,
+ scheme-specific information about how to gain authorization to access
+ the resource. The user information, if present, is followed by a
+ commercial at-sign ("@") that delimits it from the host.
+
+ userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+
+ Use of the format "user:password" in the userinfo field is
+ deprecated. Applications should not render as clear text any data
+ after the first colon (":") character found within a userinfo
+ subcomponent unless the data after the colon is the empty string
+ (indicating no password). Applications may choose to ignore or
+ reject such data when it is received as part of a reference and
+ should reject the storage of such data in unencrypted form. The
+ passing of authentication information in clear text has proven to be
+ a security risk in almost every case where it has been used.
+
+ Applications that render a URI for the sake of user feedback, such as
+ in graphical hypertext browsing, should render userinfo in a way that
+ is distinguished from the rest of a URI, when feasible. Such
+ rendering will assist the user in cases where the userinfo has been
+ misleadingly crafted to look like a trusted domain name
+ (Section 7.6).
+
+3.2.2. Host
+
+ The host subcomponent of authority is identified by an IP literal
+ encapsulated within square brackets, an IPv4 address in dotted-
+ decimal form, or a registered name. The host subcomponent is case-
+ insensitive. The presence of a host subcomponent within a URI does
+ not imply that the scheme requires access to the given host on the
+ Internet. In many cases, the host syntax is used only for the sake
+
+
+
+Berners-Lee, et al. Standards Track [Page 18]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ of reusing the existing registration process created and deployed for
+ DNS, thus obtaining a globally unique name without the cost of
+ deploying another registry. However, such use comes with its own
+ costs: domain name ownership may change over time for reasons not
+ anticipated by the URI producer. In other cases, the data within the
+ host component identifies a registered name that has nothing to do
+ with an Internet host. We use the name "host" for the ABNF rule
+ because that is its most common purpose, not its only purpose.
+
+ host = IP-literal / IPv4address / reg-name
+
+ The syntax rule for host is ambiguous because it does not completely
+ distinguish between an IPv4address and a reg-name. In order to
+ disambiguate the syntax, we apply the "first-match-wins" algorithm:
+ If host matches the rule for IPv4address, then it should be
+ considered an IPv4 address literal and not a reg-name. Although host
+ is case-insensitive, producers and normalizers should use lowercase
+ for registered names and hexadecimal addresses for the sake of
+ uniformity, while only using uppercase letters for percent-encodings.
+
+ A host identified by an Internet Protocol literal address, version 6
+ [RFC3513] or later, is distinguished by enclosing the IP literal
+ within square brackets ("[" and "]"). This is the only place where
+ square bracket characters are allowed in the URI syntax. In
+ anticipation of future, as-yet-undefined IP literal address formats,
+ an implementation may use an optional version flag to indicate such a
+ format explicitly rather than rely on heuristic determination.
+
+ IP-literal = "[" ( IPv6address / IPvFuture ) "]"
+
+ IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
+
+ The version flag does not indicate the IP version; rather, it
+ indicates future versions of the literal format. As such,
+ implementations must not provide the version flag for the existing
+ IPv4 and IPv6 literal address forms described below. If a URI
+ containing an IP-literal that starts with "v" (case-insensitive),
+ indicating that the version flag is present, is dereferenced by an
+ application that does not know the meaning of that version flag, then
+ the application should return an appropriate error for "address
+ mechanism not supported".
+
+ A host identified by an IPv6 literal address is represented inside
+ the square brackets without a preceding version flag. The ABNF
+ provided here is a translation of the text definition of an IPv6
+ literal address provided in [RFC3513]. This syntax does not support
+ IPv6 scoped addressing zone identifiers.
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 19]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ A 128-bit IPv6 address is divided into eight 16-bit pieces. Each
+ piece is represented numerically in case-insensitive hexadecimal,
+ using one to four hexadecimal digits (leading zeroes are permitted).
+ The eight encoded pieces are given most-significant first, separated
+ by colon characters. Optionally, the least-significant two pieces
+ may instead be represented in IPv4 address textual format. A
+ sequence of one or more consecutive zero-valued 16-bit pieces within
+ the address may be elided, omitting all their digits and leaving
+ exactly two consecutive colons in their place to mark the elision.
+
+ IPv6address = 6( h16 ":" ) ls32
+ / "::" 5( h16 ":" ) ls32
+ / [ h16 ] "::" 4( h16 ":" ) ls32
+ / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
+ / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
+ / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
+ / [ *4( h16 ":" ) h16 ] "::" ls32
+ / [ *5( h16 ":" ) h16 ] "::" h16
+ / [ *6( h16 ":" ) h16 ] "::"
+
+ ls32 = ( h16 ":" h16 ) / IPv4address
+ ; least-significant 32 bits of address
+
+ h16 = 1*4HEXDIG
+ ; 16 bits of address represented in hexadecimal
+
+ A host identified by an IPv4 literal address is represented in
+ dotted-decimal notation (a sequence of four decimal numbers in the
+ range 0 to 255, separated by "."), as described in [RFC1123] by
+ reference to [RFC0952]. Note that other forms of dotted notation may
+ be interpreted on some platforms, as described in Section 7.4, but
+ only the dotted-decimal form of four octets is allowed by this
+ grammar.
+
+ IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
+
+ dec-octet = DIGIT ; 0-9
+ / %x31-39 DIGIT ; 10-99
+ / "1" 2DIGIT ; 100-199
+ / "2" %x30-34 DIGIT ; 200-249
+ / "25" %x30-35 ; 250-255
+
+ A host identified by a registered name is a sequence of characters
+ usually intended for lookup within a locally defined host or service
+ name registry, though the URI's scheme-specific semantics may require
+ that a specific registry (or fixed name table) be used instead. The
+ most common name registry mechanism is the Domain Name System (DNS).
+ A registered name intended for lookup in the DNS uses the syntax
+
+
+
+Berners-Lee, et al. Standards Track [Page 20]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ defined in Section 3.5 of [RFC1034] and Section 2.1 of [RFC1123].
+ Such a name consists of a sequence of domain labels separated by ".",
+ each domain label starting and ending with an alphanumeric character
+ and possibly also containing "-" characters. The rightmost domain
+ label of a fully qualified domain name in DNS may be followed by a
+ single "." and should be if it is necessary to distinguish between
+ the complete domain name and some local domain.
+
+ reg-name = *( unreserved / pct-encoded / sub-delims )
+
+ If the URI scheme defines a default for host, then that default
+ applies when the host subcomponent is undefined or when the
+ registered name is empty (zero length). For example, the "file" URI
+ scheme is defined so that no authority, an empty host, and
+ "localhost" all mean the end-user's machine, whereas the "http"
+ scheme considers a missing authority or empty host invalid.
+
+ This specification does not mandate a particular registered name
+ lookup technology and therefore does not restrict the syntax of reg-
+ name beyond what is necessary for interoperability. Instead, it
+ delegates the issue of registered name syntax conformance to the
+ operating system of each application performing URI resolution, and
+ that operating system decides what it will allow for the purpose of
+ host identification. A URI resolution implementation might use DNS,
+ host tables, yellow pages, NetInfo, WINS, or any other system for
+ lookup of registered names. However, a globally scoped naming
+ system, such as DNS fully qualified domain names, is necessary for
+ URIs intended to have global scope. URI producers should use names
+ that conform to the DNS syntax, even when use of DNS is not
+ immediately apparent, and should limit these names to no more than
+ 255 characters in length.
+
+ The reg-name syntax allows percent-encoded octets in order to
+ represent non-ASCII registered names in a uniform way that is
+ independent of the underlying name resolution technology. Non-ASCII
+ characters must first be encoded according to UTF-8 [STD63], and then
+ each octet of the corresponding UTF-8 sequence must be percent-
+ encoded to be represented as URI characters. URI producing
+ applications must not use percent-encoding in host unless it is used
+ to represent a UTF-8 character sequence. When a non-ASCII registered
+ name represents an internationalized domain name intended for
+ resolution via the DNS, the name must be transformed to the IDNA
+ encoding [RFC3490] prior to name lookup. URI producers should
+ provide these registered names in the IDNA encoding, rather than a
+ percent-encoding, if they wish to maximize interoperability with
+ legacy URI resolvers.
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 21]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+3.2.3. Port
+
+ The port subcomponent of authority is designated by an optional port
+ number in decimal following the host and delimited from it by a
+ single colon (":") character.
+
+ port = *DIGIT
+
+ A scheme may define a default port. For example, the "http" scheme
+ defines a default port of "80", corresponding to its reserved TCP
+ port number. The type of port designated by the port number (e.g.,
+ TCP, UDP, SCTP) is defined by the URI scheme. URI producers and
+ normalizers should omit the port component and its ":" delimiter if
+ port is empty or if its value would be the same as that of the
+ scheme's default.
+
+3.3. Path
+
+ The path component contains data, usually organized in hierarchical
+ form, that, along with data in the non-hierarchical query component
+ (Section 3.4), serves to identify a resource within the scope of the
+ URI's scheme and naming authority (if any). The path is terminated
+ by the first question mark ("?") or number sign ("#") character, or
+ by the end of the URI.
+
+ If a URI contains an authority component, then the path component
+ must either be empty or begin with a slash ("/") character. If a URI
+ does not contain an authority component, then the path cannot begin
+ with two slash characters ("//"). In addition, a URI reference
+ (Section 4.1) may be a relative-path reference, in which case the
+ first path segment cannot contain a colon (":") character. The ABNF
+ requires five separate rules to disambiguate these cases, only one of
+ which will match the path substring within a given URI reference. We
+ use the generic term "path component" to describe the URI substring
+ matched by the parser to one of these rules.
+
+ path = path-abempty ; begins with "/" or is empty
+ / path-absolute ; begins with "/" but not "//"
+ / path-noscheme ; begins with a non-colon segment
+ / path-rootless ; begins with a segment
+ / path-empty ; zero characters
+
+ path-abempty = *( "/" segment )
+ path-absolute = "/" [ segment-nz *( "/" segment ) ]
+ path-noscheme = segment-nz-nc *( "/" segment )
+ path-rootless = segment-nz *( "/" segment )
+ path-empty = 0<pchar>
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 22]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ segment = *pchar
+ segment-nz = 1*pchar
+ segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
+ ; non-zero-length segment without any colon ":"
+
+ pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+
+ A path consists of a sequence of path segments separated by a slash
+ ("/") character. A path is always defined for a URI, though the
+ defined path may be empty (zero length). Use of the slash character
+ to indicate hierarchy is only required when a URI will be used as the
+ context for relative references. For example, the URI
+ <mailto:fred@example.com> has a path of "fred@example.com", whereas
+ the URI <foo://info.example.com?fred> has an empty path.
+
+ The path segments "." and "..", also known as dot-segments, are
+ defined for relative reference within the path name hierarchy. They
+ are intended for use at the beginning of a relative-path reference
+ (Section 4.2) to indicate relative position within the hierarchical
+ tree of names. This is similar to their role within some operating
+ systems' file directory structures to indicate the current directory
+ and parent directory, respectively. However, unlike in a file
+ system, these dot-segments are only interpreted within the URI path
+ hierarchy and are removed as part of the resolution process (Section
+ 5.2).
+
+ Aside from dot-segments in hierarchical paths, a path segment is
+ considered opaque by the generic syntax. URI producing applications
+ often use the reserved characters allowed in a segment to delimit
+ scheme-specific or dereference-handler-specific subcomponents. For
+ example, the semicolon (";") and equals ("=") reserved characters are
+ often used to delimit parameters and parameter values applicable to
+ that segment. The comma (",") reserved character is often used for
+ similar purposes. For example, one URI producer might use a segment
+ such as "name;v=1.1" to indicate a reference to version 1.1 of
+ "name", whereas another might use a segment such as "name,1.1" to
+ indicate the same. Parameter types may be defined by scheme-specific
+ semantics, but in most cases the syntax of a parameter is specific to
+ the implementation of the URI's dereferencing algorithm.
+
+3.4. Query
+
+ The query component contains non-hierarchical data that, along with
+ data in the path component (Section 3.3), serves to identify a
+ resource within the scope of the URI's scheme and naming authority
+ (if any). The query component is indicated by the first question
+ mark ("?") character and terminated by a number sign ("#") character
+ or by the end of the URI.
+
+
+
+Berners-Lee, et al. Standards Track [Page 23]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ query = *( pchar / "/" / "?" )
+
+ The characters slash ("/") and question mark ("?") may represent data
+ within the query component. Beware that some older, erroneous
+ implementations may not handle such data correctly when it is used as
+ the base URI for relative references (Section 5.1), apparently
+ because they fail to distinguish query data from path data when
+ looking for hierarchical separators. However, as query components
+ are often used to carry identifying information in the form of
+ "key=value" pairs and one frequently used value is a reference to
+ another URI, it is sometimes better for usability to avoid percent-
+ encoding those characters.
+
+3.5. Fragment
+
+ The fragment identifier component of a URI allows indirect
+ identification of a secondary resource by reference to a primary
+ resource and additional identifying information. The identified
+ secondary resource may be some portion or subset of the primary
+ resource, some view on representations of the primary resource, or
+ some other resource defined or described by those representations. A
+ fragment identifier component is indicated by the presence of a
+ number sign ("#") character and terminated by the end of the URI.
+
+ fragment = *( pchar / "/" / "?" )
+
+ The semantics of a fragment identifier are defined by the set of
+ representations that might result from a retrieval action on the
+ primary resource. The fragment's format and resolution is therefore
+ dependent on the media type [RFC2046] of a potentially retrieved
+ representation, even though such a retrieval is only performed if the
+ URI is dereferenced. If no such representation exists, then the
+ semantics of the fragment are considered unknown and are effectively
+ unconstrained. Fragment identifier semantics are independent of the
+ URI scheme and thus cannot be redefined by scheme specifications.
+
+ Individual media types may define their own restrictions on or
+ structures within the fragment identifier syntax for specifying
+ different types of subsets, views, or external references that are
+ identifiable as secondary resources by that media type. If the
+ primary resource has multiple representations, as is often the case
+ for resources whose representation is selected based on attributes of
+ the retrieval request (a.k.a., content negotiation), then whatever is
+ identified by the fragment should be consistent across all of those
+ representations. Each representation should either define the
+ fragment so that it corresponds to the same secondary resource,
+ regardless of how it is represented, or should leave the fragment
+ undefined (i.e., not found).
+
+
+
+Berners-Lee, et al. Standards Track [Page 24]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ As with any URI, use of a fragment identifier component does not
+ imply that a retrieval action will take place. A URI with a fragment
+ identifier may be used to refer to the secondary resource without any
+ implication that the primary resource is accessible or will ever be
+ accessed.
+
+ Fragment identifiers have a special role in information retrieval
+ systems as the primary form of client-side indirect referencing,
+ allowing an author to specifically identify aspects of an existing
+ resource that are only indirectly provided by the resource owner. As
+ such, the fragment identifier is not used in the scheme-specific
+ processing of a URI; instead, the fragment identifier is separated
+ from the rest of the URI prior to a dereference, and thus the
+ identifying information within the fragment itself is dereferenced
+ solely by the user agent, regardless of the URI scheme. Although
+ this separate handling is often perceived to be a loss of
+ information, particularly for accurate redirection of references as
+ resources move over time, it also serves to prevent information
+ providers from denying reference authors the right to refer to
+ information within a resource selectively. Indirect referencing also
+ provides additional flexibility and extensibility to systems that use
+ URIs, as new media types are easier to define and deploy than new
+ schemes of identification.
+
+ The characters slash ("/") and question mark ("?") are allowed to
+ represent data within the fragment identifier. Beware that some
+ older, erroneous implementations may not handle this data correctly
+ when it is used as the base URI for relative references (Section
+ 5.1).
+
+4. Usage
+
+ When applications make reference to a URI, they do not always use the
+ full form of reference defined by the "URI" syntax rule. To save
+ space and take advantage of hierarchical locality, many Internet
+ protocol elements and media type formats allow an abbreviation of a
+ URI, whereas others restrict the syntax to a particular form of URI.
+ We define the most common forms of reference syntax in this
+ specification because they impact and depend upon the design of the
+ generic syntax, requiring a uniform parsing algorithm in order to be
+ interpreted consistently.
+
+4.1. URI Reference
+
+ URI-reference is used to denote the most common usage of a resource
+ identifier.
+
+ URI-reference = URI / relative-ref
+
+
+
+Berners-Lee, et al. Standards Track [Page 25]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ A URI-reference is either a URI or a relative reference. If the
+ URI-reference's prefix does not match the syntax of a scheme followed
+ by its colon separator, then the URI-reference is a relative
+ reference.
+
+ A URI-reference is typically parsed first into the five URI
+ components, in order to determine what components are present and
+ whether the reference is relative. Then, each component is parsed
+ for its subparts and their validation. The ABNF of URI-reference,
+ along with the "first-match-wins" disambiguation rule, is sufficient
+ to define a validating parser for the generic syntax. Readers
+ familiar with regular expressions should see Appendix B for an
+ example of a non-validating URI-reference parser that will take any
+ given string and extract the URI components.
+
+4.2. Relative Reference
+
+ A relative reference takes advantage of the hierarchical syntax
+ (Section 1.2.3) to express a URI reference relative to the name space
+ of another hierarchical URI.
+
+ relative-ref = relative-part [ "?" query ] [ "#" fragment ]
+
+ relative-part = "//" authority path-abempty
+ / path-absolute
+ / path-noscheme
+ / path-empty
+
+ The URI referred to by a relative reference, also known as the target
+ URI, is obtained by applying the reference resolution algorithm of
+ Section 5.
+
+ A relative reference that begins with two slash characters is termed
+ a network-path reference; such references are rarely used. A
+ relative reference that begins with a single slash character is
+ termed an absolute-path reference. A relative reference that does
+ not begin with a slash character is termed a relative-path reference.
+
+ A path segment that contains a colon character (e.g., "this:that")
+ cannot be used as the first segment of a relative-path reference, as
+ it would be mistaken for a scheme name. Such a segment must be
+ preceded by a dot-segment (e.g., "./this:that") to make a relative-
+ path reference.
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 26]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+4.3. Absolute URI
+
+ Some protocol elements allow only the absolute form of a URI without
+ a fragment identifier. For example, defining a base URI for later
+ use by relative references calls for an absolute-URI syntax rule that
+ does not allow a fragment.
+
+ absolute-URI = scheme ":" hier-part [ "?" query ]
+
+ URI scheme specifications must define their own syntax so that all
+ strings matching their scheme-specific syntax will also match the
+ <absolute-URI> grammar. Scheme specifications will not define
+ fragment identifier syntax or usage, regardless of its applicability
+ to resources identifiable via that scheme, as fragment identification
+ is orthogonal to scheme definition. However, scheme specifications
+ are encouraged to include a wide range of examples, including
+ examples that show use of the scheme's URIs with fragment identifiers
+ when such usage is appropriate.
+
+4.4. Same-Document Reference
+
+ When a URI reference refers to a URI that is, aside from its fragment
+ component (if any), identical to the base URI (Section 5.1), that
+ reference is called a "same-document" reference. The most frequent
+ examples of same-document references are relative references that are
+ empty or include only the number sign ("#") separator followed by a
+ fragment identifier.
+
+ When a same-document reference is dereferenced for a retrieval
+ action, the target of that reference is defined to be within the same
+ entity (representation, document, or message) as the reference;
+ therefore, a dereference should not result in a new retrieval action.
+
+ Normalization of the base and target URIs prior to their comparison,
+ as described in Sections 6.2.2 and 6.2.3, is allowed but rarely
+ performed in practice. Normalization may increase the set of same-
+ document references, which may be of benefit to some caching
+ applications. As such, reference authors should not assume that a
+ slightly different, though equivalent, reference URI will (or will
+ not) be interpreted as a same-document reference by any given
+ application.
+
+4.5. Suffix Reference
+
+ The URI syntax is designed for unambiguous reference to resources and
+ extensibility via the URI scheme. However, as URI identification and
+ usage have become commonplace, traditional media (television, radio,
+ newspapers, billboards, etc.) have increasingly used a suffix of the
+
+
+
+Berners-Lee, et al. Standards Track [Page 27]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ URI as a reference, consisting of only the authority and path
+ portions of the URI, such as
+
+ www.w3.org/Addressing/
+
+ or simply a DNS registered name on its own. Such references are
+ primarily intended for human interpretation rather than for machines,
+ with the assumption that context-based heuristics are sufficient to
+ complete the URI (e.g., most registered names beginning with "www"
+ are likely to have a URI prefix of "http://"). Although there is no
+ standard set of heuristics for disambiguating a URI suffix, many
+ client implementations allow them to be entered by the user and
+ heuristically resolved.
+
+ Although this practice of using suffix references is common, it
+ should be avoided whenever possible and should never be used in
+ situations where long-term references are expected. The heuristics
+ noted above will change over time, particularly when a new URI scheme
+ becomes popular, and are often incorrect when used out of context.
+ Furthermore, they can lead to security issues along the lines of
+ those described in [RFC1535].
+
+ As a URI suffix has the same syntax as a relative-path reference, a
+ suffix reference cannot be used in contexts where a relative
+ reference is expected. As a result, suffix references are limited to
+ places where there is no defined base URI, such as dialog boxes and
+ off-line advertisements.
+
+5. Reference Resolution
+
+ This section defines the process of resolving a URI reference within
+ a context that allows relative references so that the result is a
+ string matching the <URI> syntax rule of Section 3.
+
+5.1. Establishing a Base URI
+
+ The term "relative" implies that a "base URI" exists against which
+ the relative reference is applied. Aside from fragment-only
+ references (Section 4.4), relative references are only usable when a
+ base URI is known. A base URI must be established by the parser
+ prior to parsing URI references that might be relative. A base URI
+ must conform to the <absolute-URI> syntax rule (Section 4.3). If the
+ base URI is obtained from a URI reference, then that reference must
+ be converted to absolute form and stripped of any fragment component
+ prior to its use as a base URI.
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 28]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ The base URI of a reference can be established in one of four ways,
+ discussed below in order of precedence. The order of precedence can
+ be thought of in terms of layers, where the innermost defined base
+ URI has the highest precedence. This can be visualized graphically
+ as follows:
+
+ .----------------------------------------------------------.
+ | .----------------------------------------------------. |
+ | | .----------------------------------------------. | |
+ | | | .----------------------------------------. | | |
+ | | | | .----------------------------------. | | | |
+ | | | | | <relative-reference> | | | | |
+ | | | | `----------------------------------' | | | |
+ | | | | (5.1.1) Base URI embedded in content | | | |
+ | | | `----------------------------------------' | | |
+ | | | (5.1.2) Base URI of the encapsulating entity | | |
+ | | | (message, representation, or none) | | |
+ | | `----------------------------------------------' | |
+ | | (5.1.3) URI used to retrieve the entity | |
+ | `----------------------------------------------------' |
+ | (5.1.4) Default Base URI (application-dependent) |
+ `----------------------------------------------------------'
+
+5.1.1. Base URI Embedded in Content
+
+ Within certain media types, a base URI for relative references can be
+ embedded within the content itself so that it can be readily obtained
+ by a parser. This can be useful for descriptive documents, such as
+ tables of contents, which may be transmitted to others through
+ protocols other than their usual retrieval context (e.g., email or
+ USENET news).
+
+ It is beyond the scope of this specification to specify how, for each
+ media type, a base URI can be embedded. The appropriate syntax, when
+ available, is described by the data format specification associated
+ with each media type.
+
+5.1.2. Base URI from the Encapsulating Entity
+
+ If no base URI is embedded, the base URI is defined by the
+ representation's retrieval context. For a document that is enclosed
+ within another entity, such as a message or archive, the retrieval
+ context is that entity. Thus, the default base URI of a
+ representation is the base URI of the entity in which the
+ representation is encapsulated.
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 29]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ A mechanism for embedding a base URI within MIME container types
+ (e.g., the message and multipart types) is defined by MHTML
+ [RFC2557]. Protocols that do not use the MIME message header syntax,
+ but that do allow some form of tagged metadata to be included within
+ messages, may define their own syntax for defining a base URI as part
+ of a message.
+
+5.1.3. Base URI from the Retrieval URI
+
+ If no base URI is embedded and the representation is not encapsulated
+ within some other entity, then, if a URI was used to retrieve the
+ representation, that URI shall be considered the base URI. Note that
+ if the retrieval was the result of a redirected request, the last URI
+ used (i.e., the URI that resulted in the actual retrieval of the
+ representation) is the base URI.
+
+5.1.4. Default Base URI
+
+ If none of the conditions described above apply, then the base URI is
+ defined by the context of the application. As this definition is
+ necessarily application-dependent, failing to define a base URI by
+ using one of the other methods may result in the same content being
+ interpreted differently by different types of applications.
+
+ A sender of a representation containing relative references is
+ responsible for ensuring that a base URI for those references can be
+ established. Aside from fragment-only references, relative
+ references can only be used reliably in situations where the base URI
+ is well defined.
+
+5.2. Relative Resolution
+
+ This section describes an algorithm for converting a URI reference
+ that might be relative to a given base URI into the parsed components
+ of the reference's target. The components can then be recomposed, as
+ described in Section 5.3, to form the target URI. This algorithm
+ provides definitive results that can be used to test the output of
+ other implementations. Applications may implement relative reference
+ resolution by using some other algorithm, provided that the results
+ match what would be given by this one.
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 30]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+5.2.1. Pre-parse the Base URI
+
+ The base URI (Base) is established according to the procedure of
+ Section 5.1 and parsed into the five main components described in
+ Section 3. Note that only the scheme component is required to be
+ present in a base URI; the other components may be empty or
+ undefined. A component is undefined if its associated delimiter does
+ not appear in the URI reference; the path component is never
+ undefined, though it may be empty.
+
+ Normalization of the base URI, as described in Sections 6.2.2 and
+ 6.2.3, is optional. A URI reference must be transformed to its
+ target URI before it can be normalized.
+
+5.2.2. Transform References
+
+ For each URI reference (R), the following pseudocode describes an
+ algorithm for transforming R into its target URI (T):
+
+ -- The URI reference is parsed into the five URI components
+ --
+ (R.scheme, R.authority, R.path, R.query, R.fragment) = parse(R);
+
+ -- A non-strict parser may ignore a scheme in the reference
+ -- if it is identical to the base URI's scheme.
+ --
+ if ((not strict) and (R.scheme == Base.scheme)) then
+ undefine(R.scheme);
+ endif;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 31]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ if defined(R.scheme) then
+ T.scheme = R.scheme;
+ T.authority = R.authority;
+ T.path = remove_dot_segments(R.path);
+ T.query = R.query;
+ else
+ if defined(R.authority) then
+ T.authority = R.authority;
+ T.path = remove_dot_segments(R.path);
+ T.query = R.query;
+ else
+ if (R.path == "") then
+ T.path = Base.path;
+ if defined(R.query) then
+ T.query = R.query;
+ else
+ T.query = Base.query;
+ endif;
+ else
+ if (R.path starts-with "/") then
+ T.path = remove_dot_segments(R.path);
+ else
+ T.path = merge(Base.path, R.path);
+ T.path = remove_dot_segments(T.path);
+ endif;
+ T.query = R.query;
+ endif;
+ T.authority = Base.authority;
+ endif;
+ T.scheme = Base.scheme;
+ endif;
+
+ T.fragment = R.fragment;
+
+5.2.3. Merge Paths
+
+ The pseudocode above refers to a "merge" routine for merging a
+ relative-path reference with the path of the base URI. This is
+ accomplished as follows:
+
+ o If the base URI has a defined authority component and an empty
+ path, then return a string consisting of "/" concatenated with the
+ reference's path; otherwise,
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 32]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ o return a string consisting of the reference's path component
+ appended to all but the last segment of the base URI's path (i.e.,
+ excluding any characters after the right-most "/" in the base URI
+ path, or excluding the entire base URI path if it does not contain
+ any "/" characters).
+
+5.2.4. Remove Dot Segments
+
+ The pseudocode also refers to a "remove_dot_segments" routine for
+ interpreting and removing the special "." and ".." complete path
+ segments from a referenced path. This is done after the path is
+ extracted from a reference, whether or not the path was relative, in
+ order to remove any invalid or extraneous dot-segments prior to
+ forming the target URI. Although there are many ways to accomplish
+ this removal process, we describe a simple method using two string
+ buffers.
+
+ 1. The input buffer is initialized with the now-appended path
+ components and the output buffer is initialized to the empty
+ string.
+
+ 2. While the input buffer is not empty, loop as follows:
+
+ A. If the input buffer begins with a prefix of "../" or "./",
+ then remove that prefix from the input buffer; otherwise,
+
+ B. if the input buffer begins with a prefix of "/./" or "/.",
+ where "." is a complete path segment, then replace that
+ prefix with "/" in the input buffer; otherwise,
+
+ C. if the input buffer begins with a prefix of "/../" or "/..",
+ where ".." is a complete path segment, then replace that
+ prefix with "/" in the input buffer and remove the last
+ segment and its preceding "/" (if any) from the output
+ buffer; otherwise,
+
+ D. if the input buffer consists only of "." or "..", then remove
+ that from the input buffer; otherwise,
+
+ E. move the first path segment in the input buffer to the end of
+ the output buffer, including the initial "/" character (if
+ any) and any subsequent characters up to, but not including,
+ the next "/" character or the end of the input buffer.
+
+ 3. Finally, the output buffer is returned as the result of
+ remove_dot_segments.
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 33]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ Note that dot-segments are intended for use in URI references to
+ express an identifier relative to the hierarchy of names in the base
+ URI. The remove_dot_segments algorithm respects that hierarchy by
+ removing extra dot-segments rather than treat them as an error or
+ leaving them to be misinterpreted by dereference implementations.
+
+ The following illustrates how the above steps are applied for two
+ examples of merged paths, showing the state of the two buffers after
+ each step.
+
+ STEP OUTPUT BUFFER INPUT BUFFER
+
+ 1 : /a/b/c/./../../g
+ 2E: /a /b/c/./../../g
+ 2E: /a/b /c/./../../g
+ 2E: /a/b/c /./../../g
+ 2B: /a/b/c /../../g
+ 2C: /a/b /../g
+ 2C: /a /g
+ 2E: /a/g
+
+ STEP OUTPUT BUFFER INPUT BUFFER
+
+ 1 : mid/content=5/../6
+ 2E: mid /content=5/../6
+ 2E: mid/content=5 /../6
+ 2C: mid /6
+ 2E: mid/6
+
+ Some applications may find it more efficient to implement the
+ remove_dot_segments algorithm by using two segment stacks rather than
+ strings.
+
+ Note: Beware that some older, erroneous implementations will fail
+ to separate a reference's query component from its path component
+ prior to merging the base and reference paths, resulting in an
+ interoperability failure if the query component contains the
+ strings "/../" or "/./".
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 34]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+5.3. Component Recomposition
+
+ Parsed URI components can be recomposed to obtain the corresponding
+ URI reference string. Using pseudocode, this would be:
+
+ result = ""
+
+ if defined(scheme) then
+ append scheme to result;
+ append ":" to result;
+ endif;
+
+ if defined(authority) then
+ append "//" to result;
+ append authority to result;
+ endif;
+
+ append path to result;
+
+ if defined(query) then
+ append "?" to result;
+ append query to result;
+ endif;
+
+ if defined(fragment) then
+ append "#" to result;
+ append fragment to result;
+ endif;
+
+ return result;
+
+ Note that we are careful to preserve the distinction between a
+ component that is undefined, meaning that its separator was not
+ present in the reference, and a component that is empty, meaning that
+ the separator was present and was immediately followed by the next
+ component separator or the end of the reference.
+
+5.4. Reference Resolution Examples
+
+ Within a representation with a well defined base URI of
+
+ http://a/b/c/d;p?q
+
+ a relative reference is transformed to its target URI as follows.
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 35]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+5.4.1. Normal Examples
+
+ "g:h" = "g:h"
+ "g" = "http://a/b/c/g"
+ "./g" = "http://a/b/c/g"
+ "g/" = "http://a/b/c/g/"
+ "/g" = "http://a/g"
+ "//g" = "http://g"
+ "?y" = "http://a/b/c/d;p?y"
+ "g?y" = "http://a/b/c/g?y"
+ "#s" = "http://a/b/c/d;p?q#s"
+ "g#s" = "http://a/b/c/g#s"
+ "g?y#s" = "http://a/b/c/g?y#s"
+ ";x" = "http://a/b/c/;x"
+ "g;x" = "http://a/b/c/g;x"
+ "g;x?y#s" = "http://a/b/c/g;x?y#s"
+ "" = "http://a/b/c/d;p?q"
+ "." = "http://a/b/c/"
+ "./" = "http://a/b/c/"
+ ".." = "http://a/b/"
+ "../" = "http://a/b/"
+ "../g" = "http://a/b/g"
+ "../.." = "http://a/"
+ "../../" = "http://a/"
+ "../../g" = "http://a/g"
+
+5.4.2. Abnormal Examples
+
+ Although the following abnormal examples are unlikely to occur in
+ normal practice, all URI parsers should be capable of resolving them
+ consistently. Each example uses the same base as that above.
+
+ Parsers must be careful in handling cases where there are more ".."
+ segments in a relative-path reference than there are hierarchical
+ levels in the base URI's path. Note that the ".." syntax cannot be
+ used to change the authority component of a URI.
+
+ "../../../g" = "http://a/g"
+ "../../../../g" = "http://a/g"
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 36]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ Similarly, parsers must remove the dot-segments "." and ".." when
+ they are complete components of a path, but not when they are only
+ part of a segment.
+
+ "/./g" = "http://a/g"
+ "/../g" = "http://a/g"
+ "g." = "http://a/b/c/g."
+ ".g" = "http://a/b/c/.g"
+ "g.." = "http://a/b/c/g.."
+ "..g" = "http://a/b/c/..g"
+
+ Less likely are cases where the relative reference uses unnecessary
+ or nonsensical forms of the "." and ".." complete path segments.
+
+ "./../g" = "http://a/b/g"
+ "./g/." = "http://a/b/c/g/"
+ "g/./h" = "http://a/b/c/g/h"
+ "g/../h" = "http://a/b/c/h"
+ "g;x=1/./y" = "http://a/b/c/g;x=1/y"
+ "g;x=1/../y" = "http://a/b/c/y"
+
+ Some applications fail to separate the reference's query and/or
+ fragment components from the path component before merging it with
+ the base path and removing dot-segments. This error is rarely
+ noticed, as typical usage of a fragment never includes the hierarchy
+ ("/") character and the query component is not normally used within
+ relative references.
+
+ "g?y/./x" = "http://a/b/c/g?y/./x"
+ "g?y/../x" = "http://a/b/c/g?y/../x"
+ "g#s/./x" = "http://a/b/c/g#s/./x"
+ "g#s/../x" = "http://a/b/c/g#s/../x"
+
+ Some parsers allow the scheme name to be present in a relative
+ reference if it is the same as the base URI scheme. This is
+ considered to be a loophole in prior specifications of partial URI
+ [RFC1630]. Its use should be avoided but is allowed for backward
+ compatibility.
+
+ "http:g" = "http:g" ; for strict parsers
+ / "http://a/b/c/g" ; for backward compatibility
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 37]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+6. Normalization and Comparison
+
+ One of the most common operations on URIs is simple comparison:
+ determining whether two URIs are equivalent without using the URIs to
+ access their respective resource(s). A comparison is performed every
+ time a response cache is accessed, a browser checks its history to
+ color a link, or an XML parser processes tags within a namespace.
+ Extensive normalization prior to comparison of URIs is often used by
+ spiders and indexing engines to prune a search space or to reduce
+ duplication of request actions and response storage.
+
+ URI comparison is performed for some particular purpose. Protocols
+ or implementations that compare URIs for different purposes will
+ often be subject to differing design trade-offs in regards to how
+ much effort should be spent in reducing aliased identifiers. This
+ section describes various methods that may be used to compare URIs,
+ the trade-offs between them, and the types of applications that might
+ use them.
+
+6.1. Equivalence
+
+ Because URIs exist to identify resources, presumably they should be
+ considered equivalent when they identify the same resource. However,
+ this definition of equivalence is not of much practical use, as there
+ is no way for an implementation to compare two resources unless it
+ has full knowledge or control of them. For this reason,
+ determination of equivalence or difference of URIs is based on string
+ comparison, perhaps augmented by reference to additional rules
+ provided by URI scheme definitions. We use the terms "different" and
+ "equivalent" to describe the possible outcomes of such comparisons,
+ but there are many application-dependent versions of equivalence.
+
+ Even though it is possible to determine that two URIs are equivalent,
+ URI comparison is not sufficient to determine whether two URIs
+ identify different resources. For example, an owner of two different
+ domain names could decide to serve the same resource from both,
+ resulting in two different URIs. Therefore, comparison methods are
+ designed to minimize false negatives while strictly avoiding false
+ positives.
+
+ In testing for equivalence, applications should not directly compare
+ relative references; the references should be converted to their
+ respective target URIs before comparison. When URIs are compared to
+ select (or avoid) a network action, such as retrieval of a
+ representation, fragment components (if any) should be excluded from
+ the comparison.
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 38]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+6.2. Comparison Ladder
+
+ A variety of methods are used in practice to test URI equivalence.
+ These methods fall into a range, distinguished by the amount of
+ processing required and the degree to which the probability of false
+ negatives is reduced. As noted above, false negatives cannot be
+ eliminated. In practice, their probability can be reduced, but this
+ reduction requires more processing and is not cost-effective for all
+ applications.
+
+ If this range of comparison practices is considered as a ladder, the
+ following discussion will climb the ladder, starting with practices
+ that are cheap but have a relatively higher chance of producing false
+ negatives, and proceeding to those that have higher computational
+ cost and lower risk of false negatives.
+
+6.2.1. Simple String Comparison
+
+ If two URIs, when considered as character strings, are identical,
+ then it is safe to conclude that they are equivalent. This type of
+ equivalence test has very low computational cost and is in wide use
+ in a variety of applications, particularly in the domain of parsing.
+
+ Testing strings for equivalence requires some basic precautions.
+ This procedure is often referred to as "bit-for-bit" or
+ "byte-for-byte" comparison, which is potentially misleading. Testing
+ strings for equality is normally based on pair comparison of the
+ characters that make up the strings, starting from the first and
+ proceeding until both strings are exhausted and all characters are
+ found to be equal, until a pair of characters compares unequal, or
+ until one of the strings is exhausted before the other.
+
+ This character comparison requires that each pair of characters be
+ put in comparable form. For example, should one URI be stored in a
+ byte array in EBCDIC encoding and the second in a Java String object
+ (UTF-16), bit-for-bit comparisons applied naively will produce
+ errors. It is better to speak of equality on a character-for-
+ character basis rather than on a byte-for-byte or bit-for-bit basis.
+ In practical terms, character-by-character comparisons should be done
+ codepoint-by-codepoint after conversion to a common character
+ encoding.
+
+ False negatives are caused by the production and use of URI aliases.
+ Unnecessary aliases can be reduced, regardless of the comparison
+ method, by consistently providing URI references in an already-
+ normalized form (i.e., a form identical to what would be produced
+ after normalization is applied, as described below).
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 39]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ Protocols and data formats often limit some URI comparisons to simple
+ string comparison, based on the theory that people and
+ implementations will, in their own best interest, be consistent in
+ providing URI references, or at least consistent enough to negate any
+ efficiency that might be obtained from further normalization.
+
+6.2.2. Syntax-Based Normalization
+
+ Implementations may use logic based on the definitions provided by
+ this specification to reduce the probability of false negatives.
+ This processing is moderately higher in cost than character-for-
+ character string comparison. For example, an application using this
+ approach could reasonably consider the following two URIs equivalent:
+
+ example://a/b/c/%7Bfoo%7D
+ eXAMPLE://a/./b/../b/%63/%7bfoo%7d
+
+ Web user agents, such as browsers, typically apply this type of URI
+ normalization when determining whether a cached response is
+ available. Syntax-based normalization includes such techniques as
+ case normalization, percent-encoding normalization, and removal of
+ dot-segments.
+
+6.2.2.1. Case Normalization
+
+ For all URIs, the hexadecimal digits within a percent-encoding
+ triplet (e.g., "%3a" versus "%3A") are case-insensitive and therefore
+ should be normalized to use uppercase letters for the digits A-F.
+
+ When a URI uses components of the generic syntax, the component
+ syntax equivalence rules always apply; namely, that the scheme and
+ host are case-insensitive and therefore should be normalized to
+ lowercase. For example, the URI <HTTP://www.EXAMPLE.com/> is
+ equivalent to <http://www.example.com/>. The other generic syntax
+ components are assumed to be case-sensitive unless specifically
+ defined otherwise by the scheme (see Section 6.2.3).
+
+6.2.2.2. Percent-Encoding Normalization
+
+ The percent-encoding mechanism (Section 2.1) is a frequent source of
+ variance among otherwise identical URIs. In addition to the case
+ normalization issue noted above, some URI producers percent-encode
+ octets that do not require percent-encoding, resulting in URIs that
+ are equivalent to their non-encoded counterparts. These URIs should
+ be normalized by decoding any percent-encoded octet that corresponds
+ to an unreserved character, as described in Section 2.3.
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 40]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+6.2.2.3. Path Segment Normalization
+
+ The complete path segments "." and ".." are intended only for use
+ within relative references (Section 4.1) and are removed as part of
+ the reference resolution process (Section 5.2). However, some
+ deployed implementations incorrectly assume that reference resolution
+ is not necessary when the reference is already a URI and thus fail to
+ remove dot-segments when they occur in non-relative paths. URI
+ normalizers should remove dot-segments by applying the
+ remove_dot_segments algorithm to the path, as described in
+ Section 5.2.4.
+
+6.2.3. Scheme-Based Normalization
+
+ The syntax and semantics of URIs vary from scheme to scheme, as
+ described by the defining specification for each scheme.
+ Implementations may use scheme-specific rules, at further processing
+ cost, to reduce the probability of false negatives. For example,
+ because the "http" scheme makes use of an authority component, has a
+ default port of "80", and defines an empty path to be equivalent to
+ "/", the following four URIs are equivalent:
+
+ http://example.com
+ http://example.com/
+ http://example.com:/
+ http://example.com:80/
+
+ In general, a URI that uses the generic syntax for authority with an
+ empty path should be normalized to a path of "/". Likewise, an
+ explicit ":port", for which the port is empty or the default for the
+ scheme, is equivalent to one where the port and its ":" delimiter are
+ elided and thus should be removed by scheme-based normalization. For
+ example, the second URI above is the normal form for the "http"
+ scheme.
+
+ Another case where normalization varies by scheme is in the handling
+ of an empty authority component or empty host subcomponent. For many
+ scheme specifications, an empty authority or host is considered an
+ error; for others, it is considered equivalent to "localhost" or the
+ end-user's host. When a scheme defines a default for authority and a
+ URI reference to that default is desired, the reference should be
+ normalized to an empty authority for the sake of uniformity, brevity,
+ and internationalization. If, however, either the userinfo or port
+ subcomponents are non-empty, then the host should be given explicitly
+ even if it matches the default.
+
+ Normalization should not remove delimiters when their associated
+ component is empty unless licensed to do so by the scheme
+
+
+
+Berners-Lee, et al. Standards Track [Page 41]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ specification. For example, the URI "http://example.com/?" cannot be
+ assumed to be equivalent to any of the examples above. Likewise, the
+ presence or absence of delimiters within a userinfo subcomponent is
+ usually significant to its interpretation. The fragment component is
+ not subject to any scheme-based normalization; thus, two URIs that
+ differ only by the suffix "#" are considered different regardless of
+ the scheme.
+
+ Some schemes define additional subcomponents that consist of case-
+ insensitive data, giving an implicit license to normalizers to
+ convert this data to a common case (e.g., all lowercase). For
+ example, URI schemes that define a subcomponent of path to contain an
+ Internet hostname, such as the "mailto" URI scheme, cause that
+ subcomponent to be case-insensitive and thus subject to case
+ normalization (e.g., "mailto:Joe@Example.COM" is equivalent to
+ "mailto:Joe@example.com", even though the generic syntax considers
+ the path component to be case-sensitive).
+
+ Other scheme-specific normalizations are possible.
+
+6.2.4. Protocol-Based Normalization
+
+ Substantial effort to reduce the incidence of false negatives is
+ often cost-effective for web spiders. Therefore, they implement even
+ more aggressive techniques in URI comparison. For example, if they
+ observe that a URI such as
+
+ http://example.com/data
+
+ redirects to a URI differing only in the trailing slash
+
+ http://example.com/data/
+
+ they will likely regard the two as equivalent in the future. This
+ kind of technique is only appropriate when equivalence is clearly
+ indicated by both the result of accessing the resources and the
+ common conventions of their scheme's dereference algorithm (in this
+ case, use of redirection by HTTP origin servers to avoid problems
+ with relative references).
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 42]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+7. Security Considerations
+
+ A URI does not in itself pose a security threat. However, as URIs
+ are often used to provide a compact set of instructions for access to
+ network resources, care must be taken to properly interpret the data
+ within a URI, to prevent that data from causing unintended access,
+ and to avoid including data that should not be revealed in plain
+ text.
+
+7.1. Reliability and Consistency
+
+ There is no guarantee that once a URI has been used to retrieve
+ information, the same information will be retrievable by that URI in
+ the future. Nor is there any guarantee that the information
+ retrievable via that URI in the future will be observably similar to
+ that retrieved in the past. The URI syntax does not constrain how a
+ given scheme or authority apportions its namespace or maintains it
+ over time. Such guarantees can only be obtained from the person(s)
+ controlling that namespace and the resource in question. A specific
+ URI scheme may define additional semantics, such as name persistence,
+ if those semantics are required of all naming authorities for that
+ scheme.
+
+7.2. Malicious Construction
+
+ It is sometimes possible to construct a URI so that an attempt to
+ perform a seemingly harmless, idempotent operation, such as the
+ retrieval of a representation, will in fact cause a possibly damaging
+ remote operation. The unsafe URI is typically constructed by
+ specifying a port number other than that reserved for the network
+ protocol in question. The client unwittingly contacts a site running
+ a different protocol service, and data within the URI contains
+ instructions that, when interpreted according to this other protocol,
+ cause an unexpected operation. A frequent example of such abuse has
+ been the use of a protocol-based scheme with a port component of
+ "25", thereby fooling user agent software into sending an unintended
+ or impersonating message via an SMTP server.
+
+ Applications should prevent dereference of a URI that specifies a TCP
+ port number within the "well-known port" range (0 - 1023) unless the
+ protocol being used to dereference that URI is compatible with the
+ protocol expected on that well-known port. Although IANA maintains a
+ registry of well-known ports, applications should make such
+ restrictions user-configurable to avoid preventing the deployment of
+ new services.
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 43]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ When a URI contains percent-encoded octets that match the delimiters
+ for a given resolution or dereference protocol (for example, CR and
+ LF characters for the TELNET protocol), these percent-encodings must
+ not be decoded before transmission across that protocol. Transfer of
+ the percent-encoding, which might violate the protocol, is less
+ harmful than allowing decoded octets to be interpreted as additional
+ operations or parameters, perhaps triggering an unexpected and
+ possibly harmful remote operation.
+
+7.3. Back-End Transcoding
+
+ When a URI is dereferenced, the data within it is often parsed by
+ both the user agent and one or more servers. In HTTP, for example, a
+ typical user agent will parse a URI into its five major components,
+ access the authority's server, and send it the data within the
+ authority, path, and query components. A typical server will take
+ that information, parse the path into segments and the query into
+ key/value pairs, and then invoke implementation-specific handlers to
+ respond to the request. As a result, a common security concern for
+ server implementations that handle a URI, either as a whole or split
+ into separate components, is proper interpretation of the octet data
+ represented by the characters and percent-encodings within that URI.
+
+ Percent-encoded octets must be decoded at some point during the
+ dereference process. Applications must split the URI into its
+ components and subcomponents prior to decoding the octets, as
+ otherwise the decoded octets might be mistaken for delimiters.
+ Security checks of the data within a URI should be applied after
+ decoding the octets. Note, however, that the "%00" percent-encoding
+ (NUL) may require special handling and should be rejected if the
+ application is not expecting to receive raw data within a component.
+
+ Special care should be taken when the URI path interpretation process
+ involves the use of a back-end file system or related system
+ functions. File systems typically assign an operational meaning to
+ special characters, such as the "/", "\", ":", "[", and "]"
+ characters, and to special device names like ".", "..", "...", "aux",
+ "lpt", etc. In some cases, merely testing for the existence of such
+ a name will cause the operating system to pause or invoke unrelated
+ system calls, leading to significant security concerns regarding
+ denial of service and unintended data transfer. It would be
+ impossible for this specification to list all such significant
+ characters and device names. Implementers should research the
+ reserved names and characters for the types of storage device that
+ may be attached to their applications and restrict the use of data
+ obtained from URI components accordingly.
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 44]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+7.4. Rare IP Address Formats
+
+ Although the URI syntax for IPv4address only allows the common
+ dotted-decimal form of IPv4 address literal, many implementations
+ that process URIs make use of platform-dependent system routines,
+ such as gethostbyname() and inet_aton(), to translate the string
+ literal to an actual IP address. Unfortunately, such system routines
+ often allow and process a much larger set of formats than those
+ described in Section 3.2.2.
+
+ For example, many implementations allow dotted forms of three
+ numbers, wherein the last part is interpreted as a 16-bit quantity
+ and placed in the right-most two bytes of the network address (e.g.,
+ a Class B network). Likewise, a dotted form of two numbers means
+ that the last part is interpreted as a 24-bit quantity and placed in
+ the right-most three bytes of the network address (Class A), and a
+ single number (without dots) is interpreted as a 32-bit quantity and
+ stored directly in the network address. Adding further to the
+ confusion, some implementations allow each dotted part to be
+ interpreted as decimal, octal, or hexadecimal, as specified in the C
+ language (i.e., a leading 0x or 0X implies hexadecimal; a leading 0
+ implies octal; otherwise, the number is interpreted as decimal).
+
+ These additional IP address formats are not allowed in the URI syntax
+ due to differences between platform implementations. However, they
+ can become a security concern if an application attempts to filter
+ access to resources based on the IP address in string literal format.
+ If this filtering is performed, literals should be converted to
+ numeric form and filtered based on the numeric value, and not on a
+ prefix or suffix of the string form.
+
+7.5. Sensitive Information
+
+ URI producers should not provide a URI that contains a username or
+ password that is intended to be secret. URIs are frequently
+ displayed by browsers, stored in clear text bookmarks, and logged by
+ user agent history and intermediary applications (proxies). A
+ password appearing within the userinfo component is deprecated and
+ should be considered an error (or simply ignored) except in those
+ rare cases where the 'password' parameter is intended to be public.
+
+7.6. Semantic Attacks
+
+ Because the userinfo subcomponent is rarely used and appears before
+ the host in the authority component, it can be used to construct a
+ URI intended to mislead a human user by appearing to identify one
+ (trusted) naming authority while actually identifying a different
+ authority hidden behind the noise. For example
+
+
+
+Berners-Lee, et al. Standards Track [Page 45]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ ftp://cnn.example.com&story=breaking_news@10.0.0.1/top_story.htm
+
+ might lead a human user to assume that the host is 'cnn.example.com',
+ whereas it is actually '10.0.0.1'. Note that a misleading userinfo
+ subcomponent could be much longer than the example above.
+
+ A misleading URI, such as that above, is an attack on the user's
+ preconceived notions about the meaning of a URI rather than an attack
+ on the software itself. User agents may be able to reduce the impact
+ of such attacks by distinguishing the various components of the URI
+ when they are rendered, such as by using a different color or tone to
+ render userinfo if any is present, though there is no panacea. More
+ information on URI-based semantic attacks can be found in [Siedzik].
+
+8. IANA Considerations
+
+ URI scheme names, as defined by <scheme> in Section 3.1, form a
+ registered namespace that is managed by IANA according to the
+ procedures defined in [BCP35]. No IANA actions are required by this
+ document.
+
+9. Acknowledgements
+
+ This specification is derived from RFC 2396 [RFC2396], RFC 1808
+ [RFC1808], and RFC 1738 [RFC1738]; the acknowledgements in those
+ documents still apply. It also incorporates the update (with
+ corrections) for IPv6 literals in the host syntax, as defined by
+ Robert M. Hinden, Brian E. Carpenter, and Larry Masinter in
+ [RFC2732]. In addition, contributions by Gisle Aas, Reese Anschultz,
+ Daniel Barclay, Tim Bray, Mike Brown, Rob Cameron, Jeremy Carroll,
+ Dan Connolly, Adam M. Costello, John Cowan, Jason Diamond, Martin
+ Duerst, Stefan Eissing, Clive D.W. Feather, Al Gilman, Tony Hammond,
+ Elliotte Harold, Pat Hayes, Henry Holtzman, Ian B. Jacobs, Michael
+ Kay, John C. Klensin, Graham Klyne, Dan Kohn, Bruce Lilly, Andrew
+ Main, Dave McAlpin, Ira McDonald, Michael Mealling, Ray Merkert,
+ Stephen Pollei, Julian Reschke, Tomas Rokicki, Miles Sabin, Kai
+ Schaetzl, Mark Thomson, Ronald Tschalaer, Norm Walsh, Marc Warne,
+ Stuart Williams, and Henry Zongaro are gratefully acknowledged.
+
+10. References
+
+10.1. Normative References
+
+ [ASCII] American National Standards Institute, "Coded Character
+ Set -- 7-bit American Standard Code for Information
+ Interchange", ANSI X3.4, 1986.
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 46]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ [RFC2234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [STD63] Yergeau, F., "UTF-8, a transformation format of
+ ISO 10646", STD 63, RFC 3629, November 2003.
+
+ [UCS] International Organization for Standardization,
+ "Information Technology - Universal Multiple-Octet Coded
+ Character Set (UCS)", ISO/IEC 10646:2003, December 2003.
+
+10.2. Informative References
+
+ [BCP19] Freed, N. and J. Postel, "IANA Charset Registration
+ Procedures", BCP 19, RFC 2978, October 2000.
+
+ [BCP35] Petke, R. and I. King, "Registration Procedures for URL
+ Scheme Names", BCP 35, RFC 2717, November 1999.
+
+ [RFC0952] Harrenstien, K., Stahl, M., and E. Feinler, "DoD Internet
+ host table specification", RFC 952, October 1985.
+
+ [RFC1034] Mockapetris, P., "Domain names - concepts and facilities",
+ STD 13, RFC 1034, November 1987.
+
+ [RFC1123] Braden, R., "Requirements for Internet Hosts - Application
+ and Support", STD 3, RFC 1123, October 1989.
+
+ [RFC1535] Gavron, E., "A Security Problem and Proposed Correction
+ With Widely Deployed DNS Software", RFC 1535,
+ October 1993.
+
+ [RFC1630] Berners-Lee, T., "Universal Resource Identifiers in WWW: A
+ Unifying Syntax for the Expression of Names and Addresses
+ of Objects on the Network as used in the World-Wide Web",
+ RFC 1630, June 1994.
+
+ [RFC1736] Kunze, J., "Functional Recommendations for Internet
+ Resource Locators", RFC 1736, February 1995.
+
+ [RFC1737] Sollins, K. and L. Masinter, "Functional Requirements for
+ Uniform Resource Names", RFC 1737, December 1994.
+
+ [RFC1738] Berners-Lee, T., Masinter, L., and M. McCahill, "Uniform
+ Resource Locators (URL)", RFC 1738, December 1994.
+
+ [RFC1808] Fielding, R., "Relative Uniform Resource Locators",
+ RFC 1808, June 1995.
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 47]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046,
+ November 1996.
+
+ [RFC2141] Moats, R., "URN Syntax", RFC 2141, May 1997.
+
+ [RFC2396] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
+ Resource Identifiers (URI): Generic Syntax", RFC 2396,
+ August 1998.
+
+ [RFC2518] Goland, Y., Whitehead, E., Faizi, A., Carter, S., and D.
+ Jensen, "HTTP Extensions for Distributed Authoring --
+ WEBDAV", RFC 2518, February 1999.
+
+ [RFC2557] Palme, J., Hopmann, A., and N. Shelness, "MIME
+ Encapsulation of Aggregate Documents, such as HTML
+ (MHTML)", RFC 2557, March 1999.
+
+ [RFC2718] Masinter, L., Alvestrand, H., Zigmond, D., and R. Petke,
+ "Guidelines for new URL Schemes", RFC 2718, November 1999.
+
+ [RFC2732] Hinden, R., Carpenter, B., and L. Masinter, "Format for
+ Literal IPv6 Addresses in URL's", RFC 2732, December 1999.
+
+ [RFC3305] Mealling, M. and R. Denenberg, "Report from the Joint
+ W3C/IETF URI Planning Interest Group: Uniform Resource
+ Identifiers (URIs), URLs, and Uniform Resource Names
+ (URNs): Clarifications and Recommendations", RFC 3305,
+ August 2002.
+
+ [RFC3490] Faltstrom, P., Hoffman, P., and A. Costello,
+ "Internationalizing Domain Names in Applications (IDNA)",
+ RFC 3490, March 2003.
+
+ [RFC3513] Hinden, R. and S. Deering, "Internet Protocol Version 6
+ (IPv6) Addressing Architecture", RFC 3513, April 2003.
+
+ [Siedzik] Siedzik, R., "Semantic Attacks: What's in a URL?",
+ April 2001, <http://www.giac.org/practical/gsec/
+ Richard_Siedzik_GSEC.pdf>.
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 48]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+Appendix A. Collected ABNF for URI
+
+ URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+
+ hier-part = "//" authority path-abempty
+ / path-absolute
+ / path-rootless
+ / path-empty
+
+ URI-reference = URI / relative-ref
+
+ absolute-URI = scheme ":" hier-part [ "?" query ]
+
+ relative-ref = relative-part [ "?" query ] [ "#" fragment ]
+
+ relative-part = "//" authority path-abempty
+ / path-absolute
+ / path-noscheme
+ / path-empty
+
+ scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+
+ authority = [ userinfo "@" ] host [ ":" port ]
+ userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+ host = IP-literal / IPv4address / reg-name
+ port = *DIGIT
+
+ IP-literal = "[" ( IPv6address / IPvFuture ) "]"
+
+ IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
+
+ IPv6address = 6( h16 ":" ) ls32
+ / "::" 5( h16 ":" ) ls32
+ / [ h16 ] "::" 4( h16 ":" ) ls32
+ / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
+ / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
+ / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
+ / [ *4( h16 ":" ) h16 ] "::" ls32
+ / [ *5( h16 ":" ) h16 ] "::" h16
+ / [ *6( h16 ":" ) h16 ] "::"
+
+ h16 = 1*4HEXDIG
+ ls32 = ( h16 ":" h16 ) / IPv4address
+ IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 49]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ dec-octet = DIGIT ; 0-9
+ / %x31-39 DIGIT ; 10-99
+ / "1" 2DIGIT ; 100-199
+ / "2" %x30-34 DIGIT ; 200-249
+ / "25" %x30-35 ; 250-255
+
+ reg-name = *( unreserved / pct-encoded / sub-delims )
+
+ path = path-abempty ; begins with "/" or is empty
+ / path-absolute ; begins with "/" but not "//"
+ / path-noscheme ; begins with a non-colon segment
+ / path-rootless ; begins with a segment
+ / path-empty ; zero characters
+
+ path-abempty = *( "/" segment )
+ path-absolute = "/" [ segment-nz *( "/" segment ) ]
+ path-noscheme = segment-nz-nc *( "/" segment )
+ path-rootless = segment-nz *( "/" segment )
+ path-empty = 0<pchar>
+
+ segment = *pchar
+ segment-nz = 1*pchar
+ segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
+ ; non-zero-length segment without any colon ":"
+
+ pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+
+ query = *( pchar / "/" / "?" )
+
+ fragment = *( pchar / "/" / "?" )
+
+ pct-encoded = "%" HEXDIG HEXDIG
+
+ unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ reserved = gen-delims / sub-delims
+ gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+ sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ / "*" / "+" / "," / ";" / "="
+
+Appendix B. Parsing a URI Reference with a Regular Expression
+
+ As the "first-match-wins" algorithm is identical to the "greedy"
+ disambiguation method used by POSIX regular expressions, it is
+ natural and commonplace to use a regular expression for parsing the
+ potential five components of a URI reference.
+
+ The following line is the regular expression for breaking-down a
+ well-formed URI reference into its components.
+
+
+
+Berners-Lee, et al. Standards Track [Page 50]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ 12 3 4 5 6 7 8 9
+
+ The numbers in the second line above are only to assist readability;
+ they indicate the reference points for each subexpression (i.e., each
+ paired parenthesis). We refer to the value matched for subexpression
+ <n> as $<n>. For example, matching the above expression to
+
+ http://www.ics.uci.edu/pub/ietf/uri/#Related
+
+ results in the following subexpression matches:
+
+ $1 = http:
+ $2 = http
+ $3 = //www.ics.uci.edu
+ $4 = www.ics.uci.edu
+ $5 = /pub/ietf/uri/
+ $6 = <undefined>
+ $7 = <undefined>
+ $8 = #Related
+ $9 = Related
+
+ where <undefined> indicates that the component is not present, as is
+ the case for the query component in the above example. Therefore, we
+ can determine the value of the five components as
+
+ scheme = $2
+ authority = $4
+ path = $5
+ query = $7
+ fragment = $9
+
+ Going in the opposite direction, we can recreate a URI reference from
+ its components by using the algorithm of Section 5.3.
+
+Appendix C. Delimiting a URI in Context
+
+ URIs are often transmitted through formats that do not provide a
+ clear context for their interpretation. For example, there are many
+ occasions when a URI is included in plain text; examples include text
+ sent in email, USENET news, and on printed paper. In such cases, it
+ is important to be able to delimit the URI from the rest of the text,
+ and in particular from punctuation marks that might be mistaken for
+ part of the URI.
+
+ In practice, URIs are delimited in a variety of ways, but usually
+ within double-quotes "http://example.com/", angle brackets
+ <http://example.com/>, or just by using whitespace:
+
+
+
+Berners-Lee, et al. Standards Track [Page 51]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ http://example.com/
+
+ These wrappers do not form part of the URI.
+
+ In some cases, extra whitespace (spaces, line-breaks, tabs, etc.) may
+ have to be added to break a long URI across lines. The whitespace
+ should be ignored when the URI is extracted.
+
+ No whitespace should be introduced after a hyphen ("-") character.
+ Because some typesetters and printers may (erroneously) introduce a
+ hyphen at the end of line when breaking it, the interpreter of a URI
+ containing a line break immediately after a hyphen should ignore all
+ whitespace around the line break and should be aware that the hyphen
+ may or may not actually be part of the URI.
+
+ Using <> angle brackets around each URI is especially recommended as
+ a delimiting style for a reference that contains embedded whitespace.
+
+ The prefix "URL:" (with or without a trailing space) was formerly
+ recommended as a way to help distinguish a URI from other bracketed
+ designators, though it is not commonly used in practice and is no
+ longer recommended.
+
+ For robustness, software that accepts user-typed URI should attempt
+ to recognize and strip both delimiters and embedded whitespace.
+
+ For example, the text
+
+ Yes, Jim, I found it under "http://www.w3.org/Addressing/",
+ but you can probably pick it up from <ftp://foo.example.
+ com/rfc/>. Note the warning in <http://www.ics.uci.edu/pub/
+ ietf/uri/historical.html#WARNING>.
+
+ contains the URI references
+
+ http://www.w3.org/Addressing/
+ ftp://foo.example.com/rfc/
+ http://www.ics.uci.edu/pub/ietf/uri/historical.html#WARNING
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 52]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+Appendix D. Changes from RFC 2396
+
+D.1. Additions
+
+ An ABNF rule for URI has been introduced to correspond to one common
+ usage of the term: an absolute URI with optional fragment.
+
+ IPv6 (and later) literals have been added to the list of possible
+ identifiers for the host portion of an authority component, as
+ described by [RFC2732], with the addition of "[" and "]" to the
+ reserved set and a version flag to anticipate future versions of IP
+ literals. Square brackets are now specified as reserved within the
+ authority component and are not allowed outside their use as
+ delimiters for an IP literal within host. In order to make this
+ change without changing the technical definition of the path, query,
+ and fragment components, those rules were redefined to directly
+ specify the characters allowed.
+
+ As [RFC2732] defers to [RFC3513] for definition of an IPv6 literal
+ address, which, unfortunately, lacks an ABNF description of
+ IPv6address, we created a new ABNF rule for IPv6address that matches
+ the text representations defined by Section 2.2 of [RFC3513].
+ Likewise, the definition of IPv4address has been improved in order to
+ limit each decimal octet to the range 0-255.
+
+ Section 6, on URI normalization and comparison, has been completely
+ rewritten and extended by using input from Tim Bray and discussion
+ within the W3C Technical Architecture Group.
+
+D.2. Modifications
+
+ The ad-hoc BNF syntax of RFC 2396 has been replaced with the ABNF of
+ [RFC2234]. This change required all rule names that formerly
+ included underscore characters to be renamed with a dash instead. In
+ addition, a number of syntax rules have been eliminated or simplified
+ to make the overall grammar more comprehensible. Specifications that
+ refer to the obsolete grammar rules may be understood by replacing
+ those rules according to the following table:
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 53]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ +----------------+--------------------------------------------------+
+ | obsolete rule | translation |
+ +----------------+--------------------------------------------------+
+ | absoluteURI | absolute-URI |
+ | relativeURI | relative-part [ "?" query ] |
+ | hier_part | ( "//" authority path-abempty / |
+ | | path-absolute ) [ "?" query ] |
+ | | |
+ | opaque_part | path-rootless [ "?" query ] |
+ | net_path | "//" authority path-abempty |
+ | abs_path | path-absolute |
+ | rel_path | path-rootless |
+ | rel_segment | segment-nz-nc |
+ | reg_name | reg-name |
+ | server | authority |
+ | hostport | host [ ":" port ] |
+ | hostname | reg-name |
+ | path_segments | path-abempty |
+ | param | *<pchar excluding ";"> |
+ | | |
+ | uric | unreserved / pct-encoded / ";" / "?" / ":" |
+ | | / "@" / "&" / "=" / "+" / "$" / "," / "/" |
+ | | |
+ | uric_no_slash | unreserved / pct-encoded / ";" / "?" / ":" |
+ | | / "@" / "&" / "=" / "+" / "$" / "," |
+ | | |
+ | mark | "-" / "_" / "." / "!" / "~" / "*" / "'" |
+ | | / "(" / ")" |
+ | | |
+ | escaped | pct-encoded |
+ | hex | HEXDIG |
+ | alphanum | ALPHA / DIGIT |
+ +----------------+--------------------------------------------------+
+
+ Use of the above obsolete rules for the definition of scheme-specific
+ syntax is deprecated.
+
+ Section 2, on characters, has been rewritten to explain what
+ characters are reserved, when they are reserved, and why they are
+ reserved, even when they are not used as delimiters by the generic
+ syntax. The mark characters that are typically unsafe to decode,
+ including the exclamation mark ("!"), asterisk ("*"), single-quote
+ ("'"), and open and close parentheses ("(" and ")"), have been moved
+ to the reserved set in order to clarify the distinction between
+ reserved and unreserved and, hopefully, to answer the most common
+ question of scheme designers. Likewise, the section on
+ percent-encoded characters has been rewritten, and URI normalizers
+ are now given license to decode any percent-encoded octets
+
+
+
+Berners-Lee, et al. Standards Track [Page 54]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ corresponding to unreserved characters. In general, the terms
+ "escaped" and "unescaped" have been replaced with "percent-encoded"
+ and "decoded", respectively, to reduce confusion with other forms of
+ escape mechanisms.
+
+ The ABNF for URI and URI-reference has been redesigned to make them
+ more friendly to LALR parsers and to reduce complexity. As a result,
+ the layout form of syntax description has been removed, along with
+ the uric, uric_no_slash, opaque_part, net_path, abs_path, rel_path,
+ path_segments, rel_segment, and mark rules. All references to
+ "opaque" URIs have been replaced with a better description of how the
+ path component may be opaque to hierarchy. The relativeURI rule has
+ been replaced with relative-ref to avoid unnecessary confusion over
+ whether they are a subset of URI. The ambiguity regarding the
+ parsing of URI-reference as a URI or a relative-ref with a colon in
+ the first segment has been eliminated through the use of five
+ separate path matching rules.
+
+ The fragment identifier has been moved back into the section on
+ generic syntax components and within the URI and relative-ref rules,
+ though it remains excluded from absolute-URI. The number sign ("#")
+ character has been moved back to the reserved set as a result of
+ reintegrating the fragment syntax.
+
+ The ABNF has been corrected to allow the path component to be empty.
+ This also allows an absolute-URI to consist of nothing after the
+ "scheme:", as is present in practice with the "dav:" namespace
+ [RFC2518] and with the "about:" scheme used internally by many WWW
+ browser implementations. The ambiguity regarding the boundary
+ between authority and path has been eliminated through the use of
+ five separate path matching rules.
+
+ Registry-based naming authorities that use the generic syntax are now
+ defined within the host rule. This change allows current
+ implementations, where whatever name provided is simply fed to the
+ local name resolution mechanism, to be consistent with the
+ specification. It also removes the need to re-specify DNS name
+ formats here. Furthermore, it allows the host component to contain
+ percent-encoded octets, which is necessary to enable
+ internationalized domain names to be provided in URIs, processed in
+ their native character encodings at the application layers above URI
+ processing, and passed to an IDNA library as a registered name in the
+ UTF-8 character encoding. The server, hostport, hostname,
+ domainlabel, toplabel, and alphanum rules have been removed.
+
+ The resolving relative references algorithm of [RFC2396] has been
+ rewritten with pseudocode for this revision to improve clarity and
+ fix the following issues:
+
+
+
+Berners-Lee, et al. Standards Track [Page 55]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ o [RFC2396] section 5.2, step 6a, failed to account for a base URI
+ with no path.
+
+ o Restored the behavior of [RFC1808] where, if the reference
+ contains an empty path and a defined query component, the target
+ URI inherits the base URI's path component.
+
+ o The determination of whether a URI reference is a same-document
+ reference has been decoupled from the URI parser, simplifying the
+ URI processing interface within applications in a way consistent
+ with the internal architecture of deployed URI processing
+ implementations. The determination is now based on comparison to
+ the base URI after transforming a reference to absolute form,
+ rather than on the format of the reference itself. This change
+ may result in more references being considered "same-document"
+ under this specification than there would be under the rules given
+ in RFC 2396, especially when normalization is used to reduce
+ aliases. However, it does not change the status of existing
+ same-document references.
+
+ o Separated the path merge routine into two routines: merge, for
+ describing combination of the base URI path with a relative-path
+ reference, and remove_dot_segments, for describing how to remove
+ the special "." and ".." segments from a composed path. The
+ remove_dot_segments algorithm is now applied to all URI reference
+ paths in order to match common implementations and to improve the
+ normalization of URIs in practice. This change only impacts the
+ parsing of abnormal references and same-scheme references wherein
+ the base URI has a non-hierarchical path.
+
+Index
+
+ A
+ ABNF 11
+ absolute 27
+ absolute-path 26
+ absolute-URI 27
+ access 9
+ authority 17, 18
+
+ B
+ base URI 28
+
+ C
+ character encoding 4
+ character 4
+ characters 8, 11
+ coded character set 4
+
+
+
+Berners-Lee, et al. Standards Track [Page 56]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ D
+ dec-octet 20
+ dereference 9
+ dot-segments 23
+
+ F
+ fragment 16, 24
+
+ G
+ gen-delims 13
+ generic syntax 6
+
+ H
+ h16 20
+ hier-part 16
+ hierarchical 10
+ host 18
+
+ I
+ identifier 5
+ IP-literal 19
+ IPv4 20
+ IPv4address 19, 20
+ IPv6 19
+ IPv6address 19, 20
+ IPvFuture 19
+
+ L
+ locator 7
+ ls32 20
+
+ M
+ merge 32
+
+ N
+ name 7
+ network-path 26
+
+ P
+ path 16, 22, 26
+ path-abempty 22
+ path-absolute 22
+ path-empty 22
+ path-noscheme 22
+ path-rootless 22
+ path-abempty 16, 22, 26
+ path-absolute 16, 22, 26
+ path-empty 16, 22, 26
+
+
+
+Berners-Lee, et al. Standards Track [Page 57]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ path-rootless 16, 22
+ pchar 23
+ pct-encoded 12
+ percent-encoding 12
+ port 22
+
+ Q
+ query 16, 23
+
+ R
+ reg-name 21
+ registered name 20
+ relative 10, 28
+ relative-path 26
+ relative-ref 26
+ remove_dot_segments 33
+ representation 9
+ reserved 12
+ resolution 9, 28
+ resource 5
+ retrieval 9
+
+ S
+ same-document 27
+ sameness 9
+ scheme 16, 17
+ segment 22, 23
+ segment-nz 23
+ segment-nz-nc 23
+ sub-delims 13
+ suffix 27
+
+ T
+ transcription 8
+
+ U
+ uniform 4
+ unreserved 13
+ URI grammar
+ absolute-URI 27
+ ALPHA 11
+ authority 18
+ CR 11
+ dec-octet 20
+ DIGIT 11
+ DQUOTE 11
+ fragment 24
+ gen-delims 13
+
+
+
+Berners-Lee, et al. Standards Track [Page 58]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ h16 20
+ HEXDIG 11
+ hier-part 16
+ host 19
+ IP-literal 19
+ IPv4address 20
+ IPv6address 20
+ IPvFuture 19
+ LF 11
+ ls32 20
+ OCTET 11
+ path 22
+ path-abempty 22
+ path-absolute 22
+ path-empty 22
+ path-noscheme 22
+ path-rootless 22
+ pchar 23
+ pct-encoded 12
+ port 22
+ query 24
+ reg-name 21
+ relative-ref 26
+ reserved 13
+ scheme 17
+ segment 23
+ segment-nz 23
+ segment-nz-nc 23
+ SP 11
+ sub-delims 13
+ unreserved 13
+ URI 16
+ URI-reference 25
+ userinfo 18
+ URI 16
+ URI-reference 25
+ URL 7
+ URN 7
+ userinfo 18
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 59]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+Authors' Addresses
+
+ Tim Berners-Lee
+ World Wide Web Consortium
+ Massachusetts Institute of Technology
+ 77 Massachusetts Avenue
+ Cambridge, MA 02139
+ USA
+
+ Phone: +1-617-253-5702
+ Fax: +1-617-258-5999
+ EMail: timbl@w3.org
+ URI: http://www.w3.org/People/Berners-Lee/
+
+
+ Roy T. Fielding
+ Day Software
+ 5251 California Ave., Suite 110
+ Irvine, CA 92617
+ USA
+
+ Phone: +1-949-679-2960
+ Fax: +1-949-679-2972
+ EMail: fielding@gbiv.com
+ URI: http://roy.gbiv.com/
+
+
+ Larry Masinter
+ Adobe Systems Incorporated
+ 345 Park Ave
+ San Jose, CA 95110
+ USA
+
+ Phone: +1-408-536-3024
+ EMail: LMM@acm.org
+ URI: http://larry.masinter.net/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 60]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2005).
+
+ This document is subject to the rights, licenses and restrictions
+ contained in BCP 78, and except as set forth therein, the authors
+ retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the IETF's procedures with respect to rights in IETF Documents can
+ be found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at ietf-
+ ipr@ietf.org.
+
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 61]
+
diff --git a/standards/rfc3995.txt b/standards/rfc3995.txt
new file mode 100644
index 000000000..9a8013b89
--- /dev/null
+++ b/standards/rfc3995.txt
@@ -0,0 +1,5323 @@
+
+
+
+
+
+
+Network Working Group R. Herriot
+Request for Comments: 3995 Global Workflow Solutions
+Category: Standards Track T. Hastings
+Updates: 2911, 2910 Xerox Corporation
+ March 2005
+
+
+ Internet Printing Protocol (IPP):
+ Event Notifications and Subscriptions
+
+Status of This Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2005).
+
+Abstract
+
+ This document describes an OPTIONAL extension to the Internet
+ Printing Protocol/1.1: Model and Semantics (RFC 2911, RFC 2910).
+ This extension allows a client to subscribe to printing related
+ Events. Subscriptions are modeled as Subscription Objects. The
+ Subscription Object specifies that when one of the specified Events
+ occurs, the Printer delivers an asynchronous Event Notification to
+ the specified Notification Recipient via the specified Push or Pull
+ Delivery Method (i.e., protocol).
+
+ A client associates Subscription Objects with a particular Job by
+ performing the Create-Job-Subscriptions operation or by submitting a
+ Job with subscription information. A client associates Subscription
+ Objects with the Printer by performing a Create-Printer-Subscriptions
+ operation. Four other operations are defined for Subscription
+ Objects: Get-Subscriptions-Attributes, Get-Subscriptions, Renew-
+ Subscription, and Cancel-Subscription.
+
+
+
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 1]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 5
+ 1.1. Notification Overview. . . . . . . . . . . . . . . . . . 5
+ 2. Models for Notification. . . . . . . . . . . . . . . . . . . . 8
+ 2.1. Model for Simple Notification (Normative). . . . . . . . 8
+ 2.2. Additional Models for Notification (Informative) . . . . 9
+ 3. Terminology. . . . . . . . . . . . . . . . . . . . . . . . . . 9
+ 3.1. Conformance Terminology. . . . . . . . . . . . . . . . . 9
+ 3.2. Other Terminology. . . . . . . . . . . . . . . . . . . . 10
+ 4. Object Relationships . . . . . . . . . . . . . . . . . . . . . 12
+ 4.1. Printer and Per-Printer Subscription Objects . . . . . . 13
+ 4.2. Printer, Job and Per-Job Subscription Objects. . . . . . 13
+ 5. Subscription Object. . . . . . . . . . . . . . . . . . . . . . 13
+ 5.1. Rules for Support of Subscription Template Attributes. . 14
+ 5.2. Rules for Processing Subscription Template Attributes. . 15
+ 5.3. Subscription Template Attributes . . . . . . . . . . . . 18
+ 5.3.1. notify-recipient-uri (uri) . . . . . . . . . . . 20
+ 5.3.2. notify-pull-method (type2 keyword) . . . . . . . 21
+ 5.3.3. notify-events (1setOf type2 keyword) . . . . . . 22
+ 5.3.4. notify-attributes (1setOf type2 keyword) . . . . 29
+ 5.3.5. notify-user-data (octetString(63)) . . . . . . . 30
+ 5.3.6. notify-charset (charset) . . . . . . . . . . . . 31
+ 5.3.7. notify-natural-language (naturalLanguage). . . . 31
+ 5.3.8. notify-lease-duration (integer(0:67108863)). . . 32
+ 5.3.9. notify-time-interval (integer(0:MAX)). . . . . . 33
+ 5.4. Subscription Description Attributes. . . . . . . . . . . 34
+ 5.4.1. notify-subscription-id (integer (1:MAX)). . . . 35
+ 5.4.2. notify-sequence-number (integer (0:MAX)) . . . . 35
+ 5.4.3. notify-lease-expiration-time (integer(0:MAX)). . 36
+ 5.4.4. notify-printer-up-time (integer(1:MAX)). . . . . 37
+ 5.4.5. notify-printer-uri (uri) . . . . . . . . . . . . 37
+ 5.4.6. notify-job-id (integer(1:MAX)) . . . . . . . . . 37
+ 5.4.7. notify-subscriber-user-name (name(MAX)). . . . . 38
+ 6. Printer Description Attributes Related to Notification . . . . 38
+ 6.1. printer-state-change-time (integer(1:MAX)) . . . . . . . 39
+ 6.2. printer-state-change-date-time (dateTime). . . . . . . . 39
+ 7. New Values for Existing Printer Description Attributes . . . . 39
+ 7.1. operations-supported (1setOf type2 enum) . . . . . . . . 40
+ 8. Attributes Only in Event Notifications . . . . . . . . . . . . 40
+ 8.1. notify-subscribed-event (type2 keyword). . . . . . . . . 40
+ 8.2. notify-text (text(MAX)). . . . . . . . . . . . . . . . . 41
+ 9. Event Notification Content . . . . . . . . . . . . . . . . . . 41
+ 9.1. Content of Machine Consumable Event Notifications. . . . 44
+ 9.1.1. Event Notification Content Common to All Events. 44
+ 9.1.2. Additional Event Notification Content for Job
+ Events . . . . . . . . . . . . . . . . . . . . . 45
+
+
+
+
+Herriot & Hastings Standards Track [Page 2]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ 9.1.3. Additional Event Notification Content for
+ Printer Events . . . . . . . . . . . . . . . . . 46
+ 9.2. Content of Human Consumable Event Notification . . . . . 46
+ 9.2.1. Event Notification Content Common to All Events. 47
+ 9.2.2. Additional Event Notification Content for Job
+ Events . . . . . . . . . . . . . . . . . . . . . 49
+ 9.2.3. Additional Event Notification Content for
+ Printer Events . . . . . . . . . . . . . . . . . 49
+ 10. Delivery Methods . . . . . . . . . . . . . . . . . . . . . . . 50
+ 11. Operations for Notification. . . . . . . . . . . . . . . . . . 52
+ 11.1. Subscription Creation Operations . . . . . . . . . . . . 52
+ 11.1.1. Create-Job-Subscriptions Operation . . . . . . . 52
+ 11.1.2. Create-Printer-Subscriptions operation . . . . . 55
+ 11.1.3. Job Creation Operations - Extensions for
+ Notification . . . . . . . . . . . . . . . . . . 56
+ 11.2 Other Operations. . . . . . . . . . . . . . . . . . . . . 58
+ 11.2.1. Restart-Job Operation - Extensions for
+ Notification . . . . . . . . . . . . . . . . . . 58
+ 11.2.2. Validate-Job Operation - Extensions for
+ Notification . . . . . . . . . . . . . . . . . . 59
+ 11.2.3. Get-Printer-Attributes - Extensions for
+ Notification . . . . . . . . . . . . . . . . . . 59
+ 11.2.4. Get-Subscription-Attributes operation. . . . . . 60
+ 11.2.5. Get-Subscriptions operation. . . . . . . . . . . 63
+ 11.2.6. Renew-Subscription operation . . . . . . . . . . 66
+ 11.2.7. Cancel-Subscription operation. . . . . . . . . . 68
+ 12. Status Codes . . . . . . . . . . . . . . . . . . . . . . . . . 70
+ 12.1. successful-ok-ignored-subscriptions (0x0003) . . . . . . 70
+ 12.2. client-error-ignored-all-subscriptions (0x0414). . . . . 71
+ 13. Status Codes in Subscription Attributes Groups . . . . . . . . 71
+ 13.1. client-error-uri-scheme-not-supported (0x040C) . . . . . 71
+ 13.2. client-error-attributes-or-values-not-supported (0x040B) 71
+ 13.3. client-error-too-many-subscriptions (0x0415) . . . . . . 72
+ 13.4. successful-ok-too-many-events (0x0005) . . . . . . . . . 72
+ 13.5. successful-ok-ignored-or-substituted-attributes (0x0001) 72
+ 14. Encodings of Additional Attribute Tags . . . . . . . . . . . . 72
+ 15. Conformance Requirements . . . . . . . . . . . . . . . . . . . 72
+ 15.1. Conformance requirements for clients . . . . . . . . . . 73
+ 15.2. Conformance requirements for Printers. . . . . . . . . . 73
+ 16. Model for Notification with Cascading Printers (Informative) . 74
+ 17. Distributed Model for Notification (Informative) . . . . . . . 75
+ 18. Extended Notification Recipient (Informative). . . . . . . . . 76
+ 19. Object Model for Notification (Normative). . . . . . . . . . . 77
+ 19.1. Object relationships . . . . . . . . . . . . . . . . . . 78
+ 19.2. Printer Object and Per-Printer Subscription Objects. . . 79
+ 19.3. Job Object and Per-Job Subscription Objects. . . . . . . 79
+ 20. Per-Job versus Per-Printer Subscription Objects (Normative). . 79
+ 21. Normative References . . . . . . . . . . . . . . . . . . . . . 80
+
+
+
+Herriot & Hastings Standards Track [Page 3]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ 22. Informative References . . . . . . . . . . . . . . . . . . . . 80
+ 23. IANA Considerations. . . . . . . . . . . . . . . . . . . . . . 81
+ 23.1. Attribute Registrations. . . . . . . . . . . . . . . . . 82
+ 23.2. Additional Enum Attribute Value Registrations within
+ the IPP registry . . . . . . . . . . . . . . . . . . . . 83
+ 23.3. Operation Registrations. . . . . . . . . . . . . . . . . 83
+ 23.4. Status code Registrations. . . . . . . . . . . . . . . . 83
+ 23.5. Attribute Group tag Registrations. . . . . . . . . . . . 84
+ 23.6. Registration of Events . . . . . . . . . . . . . . . . . 84
+ 23.7. Registration of Event Notification Delivery Methods. . . 85
+ 23.7.1. Requirements for Registration of Event
+ Notification Delivery Methods. . . . . . . . . . 85
+ 23.7.2. Registration Procedure . . . . . . . . . . . . . 86
+ 23.7.3. Delivery Method Document Registrations . . . . . 87
+ 23.7.4. Registration Template. . . . . . . . . . . . . . 88
+ 24. Internationalization Considerations. . . . . . . . . . . . . . 89
+ 25. Security Considerations. . . . . . . . . . . . . . . . . . . . 89
+ 25.1. Client access rights . . . . . . . . . . . . . . . . . . 89
+ 25.2. Printer security threats . . . . . . . . . . . . . . . . 91
+ 25.3. Notification Recipient security threats. . . . . . . . . 91
+ 26. Description of the base IPP documents (Informative). . . . . . 92
+ 27. Contributors . . . . . . . . . . . . . . . . . . . . . . . . . 93
+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 94
+ Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 95
+
+Tables
+
+ Table 1 - Subscription Template Attributes. . . . . . . . . . . . 20
+ Table 2 - Subscription Description Attributes . . . . . . . . . . 35
+ Table 3 - Printer Description Attributes Associated with
+ Notification. . . . . . . . . . . . . . . . . . . . . . 39
+ Table 4 - Operation-id assignments. . . . . . . . . . . . . . . . 40
+ Table 5 - Attributes in Event Notification Content. . . . . . . . 45
+ Table 6 - Additional Event Notification Content for Job Events. . 46
+ Table 7 - Combinations of Events and Subscribed Events for
+ "job-impressions-completed" . . . . . . . . . . . . . . 46
+ Table 8 - Additional Event Notification Content for Printer
+ Events. . . . . . . . . . . . . . . . . . . . . . . . . 46
+ Table 9 - Printer Name in Event Notification Content. . . . . . . 48
+ Table 10 - Event Name in Event Notification Content. . . . . . . . 48
+ Table 11 - Event Time in Event Notification Content. . . . . . . . 48
+ Table 12 - Job Name in Event Notification Content. . . . . . . . . 49
+ Table 13 - Job State in Event Notification Content . . . . . . . . 49
+ Table 14 - Printer State in Event Notification Content . . . . . . 50
+ Table 15 - Information about the Delivery Method . . . . . . . . . 51
+ Table 16 - Printer Conformance Requirements for Operations . . . . 74
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 4]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+Figures
+
+ Figure 1 - Model for Notification. . . . . . . . . . . . . . . . . 9
+ Figure 2 - Model for Notification with Cascading Printers. . . . . 75
+ Figure 3 - Opaque Use of a Notification Server Transparent to the
+ Client. . . . . . . . . . . . . . . . . . . . . . . . . 76
+ Figure 4 - Use of an Extended Notification Recipient transparent
+ to the Printer. . . . . . . . . . . . . . . . . . . . . 77
+ Figure 5 - Object Model for Notification . . . . . . . . . . . . . 78
+
+1. Introduction
+
+ This IPP notification specification is an OPTIONAL extension to
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911,
+ RFC2910]. See Appendix 29 for a description of the base IPP
+ documents. This document in combination with the following documents
+ is intended to meet the most important notification requirements
+ described in [RFC3997]:
+
+ Internet Printing Protocol (IPP): "Job Progress Attributes"
+ [RFC3381]
+
+ Internet Printing Protocol (IPP): "The 'ippget' Delivery Method
+ for Event Notifications" [RFC3996]
+
+ This specification REQUIRES that clients and Printers support the
+ 'ippget' Pull Delivery Method [RFC3996]. Conforming client and
+ Printer implementations MAY support additional Push or Pull Delivery
+ Methods as well. Note: this document does not define any Delivery
+ Methods itself, but it does define the rules for conformance for
+ Delivery Method Documents and their registration with IANA (see
+ section 23.7.3).
+
+ Refer to the Table of Contents for the layout of this document.
+
+1.1. Notification Overview
+
+ This document defines operations that a client can perform in order
+ to create Subscription Objects in a Printer and carry out other
+ operations on them. A Subscription Object represents a Subscription
+ abstraction. The Subscription Object specifies that when one of the
+ specified Events occurs, the Printer delivers an asynchronous Event
+ Notification to the specified Notification Recipient via the
+ specified Delivery Method (i.e., protocol).
+
+ When a client (called a Subscribing Client) performs an operation
+ that creates a Subscription Object, the operation contains one or
+ more Subscription Template Attributes Groups. Each such group holds
+
+
+
+Herriot & Hastings Standards Track [Page 5]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ information used by the Printer to initialize a newly created
+ Subscription Object. The Printer creates one Subscription Object for
+ each Subscription Template Attributes Group in the operation. This
+ group is like the Job Template Attributes group defined in [RFC2911].
+ The following is an example of the information included in a
+ Subscription Template Attributes Group (see section 5 for details on
+ the Subscription Object attributes):
+
+ 1. The names of Subscribed Events that are of interest to the
+ Notification Recipient.
+
+ 2. The address (URL) of one Notification Recipient for a Push
+ Delivery Method or the method for a Pull Delivery Method.
+
+ 3. The Delivery Method (i.e., the protocol) which the Printer uses to
+ deliver the Event Notification.
+
+ 4. Some opaque data that the Printer delivers to the Notification
+ Recipient in the Event Notification. For example, the
+ Notification Recipient might use this opaque data as a forwarding
+ address for the Event Notification.
+
+ 5. The charset to use in text fields within an Event Notification
+
+ 6. The natural language to use in the text fields of the Event
+ Notification
+
+ 7. The requested lease time in seconds for the Subscription Object
+
+ An operation that creates a Subscription Object is called a
+ Subscription Creation Operation. These operations include the
+ following operations (see section 11.1 for further details):
+
+ - Job Creation operation: When a client performs such an
+ operation (Print-Job, Print-URI, and Create-Job), a client can
+ include zero or more Subscription Template Attributes Groups in
+ the request. The Printer creates one Subscription Object for
+ each Subscription Template Attributes Group in the request, and
+ the Printer associates each such Subscription Object with the
+ newly created Job. This document extends these operations'
+ definitions in [RFC2911] by adding Subscription Template
+ Attributes Groups in the request and Subscription Attributes
+ Groups in the response.
+
+ - Create-Job-Subscriptions operation: A client can include one or
+ more Subscription Template Attributes Groups in the request.
+ The Printer creates one Subscription Object for each
+
+
+
+
+Herriot & Hastings Standards Track [Page 6]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Subscription Template Attributes Group and associates each with
+ the job that is the target of this operation.
+
+ - Create-Printer-Subscriptions operation: A client can include
+ one or more Subscription Template Attributes Groups in the
+ request. The Printer creates one Subscription Object for each
+ Subscription Template Attributes Group and associates each with
+ the Printer that is the target of this operation.
+
+ For each of the above operations:
+
+ - the Printer associates a Subscription Object with the Printer
+ or a specific Job. When a Subscription Object is associated
+ with a Job Object, it is called a Per-Job Subscription Object.
+ When a Subscription Object is associated with a Printer Object,
+ it is called a Per-Printer Subscription Object.
+
+ - the response contains one Subscription Attributes Group for
+ each Subscription Template Attributes Group in the request and
+ in the same order. When the Printer successfully creates a
+ Subscription Object, its corresponding Subscription Attributes
+ Group contains the "notify-subscription-id" attribute. This
+ attribute uniquely identifies the Subscription Object and is
+ analogous to a "job-id" for a Job object. Some operations
+ described below use the "notify-subscription-id" to identify
+ the target Subscription Object.
+
+ This document defines the following additional operations (see
+ section 11.2 for further details):
+
+ - Restart-Job operation: When a client performs the Restart-Job
+ operation [RFC2911], the Printer re-uses the same Job and its
+ Subscription Objects.
+
+ - Validate-Job operation: When a client performs this operation, a
+ client can include zero or more Subscription Template Attributes
+ Groups in the request. The Printer determines if it could create
+ one Subscription Object for each Subscription Template Attributes
+ Group in the request. This document extends this operation's
+ definition in [RFC2911] by adding Subscription Template Attributes
+ Groups in the request and Subscription Attributes Groups in the
+ response.
+
+ - Get-Subscription-Attributes operation: This operation allows a
+ client to obtain the specified attributes of a target Subscription
+ Object.
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 7]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ - Get-Subscriptions operation: This operation allows a client to
+ obtain the specified attributes of all Subscription Objects
+ associated with the Printer or a specified Job.
+
+ - Renew-Subscription operation: This operation renews the lease on
+ the target Per-Printer Subscription Object before it expires. A
+ newly created Per-Printer Subscription Object receives an initial
+ lease. It is the duty of the client to use this operation
+ frequently enough to preserve a Per-Printer Subscription Object.
+ The Printer deletes a Per-Printer Subscription Object when its
+ lease expires. A Per-Job Subscription Object last exactly as long
+ as its associated Job Object and thus doesn't have a lease.
+
+ - Cancel-Subscription operation: This operation (1) cancels the
+ lease on the specified Per-Printer Subscription Object and thereby
+ deletes the Per-Printer Subscription Object or (2) deletes the
+ Per-Job Subscription Object.
+
+ When an Event occurs, the Printer finds all Subscription Objects
+ listening for the Event (see section 9 for details on finding such
+ Subscription Objects). For each such Subscription Object, the
+ Printer:
+
+ a) generates an Event Notification with information specified in
+ section 9, AND
+
+ b) either:
+
+ i) If the Delivery Method is a Push Delivery Method as indicated
+ by the presence of the Subscription Object's "notify-
+ recipient-uri" attribute, delivers the Event Notification
+ using the Delivery Method and target address identified in the
+ Subscription Object's "notify-recipient-uri" attribute, OR
+
+ ii) If the Delivery Method is a Pull Delivery Method as indicated
+ by the presence of the Subscription Object's "notify-pull-
+ method" attribute, saves Event Notification for a time period
+ called the Event Life defined by the Delivery Method, i.e.,
+ the Notification Recipient is expected to fetch the Event
+ Notifications.
+
+2. Models for Notification
+
+2.1. Model for Simple Notification (Normative)
+
+ As part of a Subscription Creation Operation, an IPP Printer (i.e.,
+ located in an output device or a server) creates one or more
+ Subscription Objects. In a Subscription Creation Operation, the
+
+
+
+Herriot & Hastings Standards Track [Page 8]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ client specifies the Notification Recipient to which the Printer is
+ to deliver Event Notifications. A Notification Recipient can be the
+ Subscribing Client or a third party.
+
+ Figure 1 shows the Notification model for a simple Client-Printer
+ relationship.
+
+ embedded printer:
+
+ output device or server
+ PDA, desktop, or server +---------------+
+ +--------+ | ########### |
+ | client |-----Subscription ---------># Printer # |
+ +--------+ Creation Operation | # Object # |
+ +------------+ | #####|##### |
+ |Notification| +-------|-------+
+ |Recipient |<----IPP Event Notifications----+
+ +------------+ (Job and/or Printer Events)
+
+ Figure 1 - Model for Notification
+
+2.2. Additional Models for Notification (Informative)
+
+ Additional models have been proposed (see Appendices 16, 17, and 18).
+
+3. Terminology
+
+ This section defines terminology used throughout this document.
+ Other terminology is defined in [RFC2911].
+
+3.1. Conformance Terminology
+
+ Capitalized terms, such as MUST, MUST NOT, REQUIRED, SHOULD, SHOULD
+ NOT, MAY, NEED NOT, and OPTIONAL, have special meaning relating to
+ conformance as defined in RFC 2119 [RFC2119] and [RFC2911] section
+ 12.1. If an implementation supports the extension defined in this
+ document, then these terms apply; otherwise, they do not. These
+ terms define conformance to this document only; they do not affect
+ conformance to other documents, unless explicitly stated otherwise.
+
+ Note: a feature that is OPTIONAL in this document becomes REQUIRED if
+ the Printer implements a Delivery Method that REQUIRES the feature.
+
+ READ-ONLY - an adjective used in an attribute definition to indicate
+ that an IPP Printer MUST NOT allow the attribute's value to be
+ modified.
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 9]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+3.2. Other Terminology
+
+ This document uses the same terminology as [RFC2911], such as
+ "client", "Printer", "attribute", "attribute value", "keyword",
+ "operation", "request", "response", "administrator", "operator", and
+ "support". In addition, the following terms are defined for use in
+ this document and the Delivery Method Documents:
+
+ Compound Event Notification - two or more Event Notifications that a
+ Printer delivers together as a single request or response. The
+ Delivery Method Document specifies whether the Delivery Method
+ supports Compound Event Notifications.
+
+ Delivery Method - the mechanism by which the Printer delivers an
+ Event Notification.
+
+ Delivery Method Document - a document, separate from this document,
+ that defines a Delivery Method.
+
+ Event - some occurrence (either expected or unexpected) within the
+ printing system of a change of state, condition, or configuration of
+ a Job or Printer object. An Event occurs only at one instant in time
+ and does not span the time the physical Event takes place. For
+ example, jam-occurred and jam-cleared are two distinct, instantaneous
+ Events, even though the jam may last for a while.
+
+ Event Life - For a Pull Delivery Method, the length of time in
+ seconds after an Event occurs during which the Printer will retain
+ that Event for delivery in an Event Notification. After the Event
+ Life expires, the Printer will no longer deliver an Event
+ Notification for that Event in such a response.
+
+ Event Notification - the information about an Event that the Printer
+ delivers when an Event occurs.
+
+ Event Notification Attributes Group - The attributes group which is
+ used to deliver an Event Notification in a request (Push Delivery
+ Methods) or a response (Pull Delivery Methods).
+
+ Human Consumable Event Notification - localized text for human
+ consumption only. There is no standardized format and thus programs
+ should not try to parse this text.
+
+ Job Creation operation - One of the operations that creates a Job
+ object: Print-Job, Print-URI and Create-Job. The Restart-Job
+ operation [RFC2911] is not considered a Job Creation operation, since
+ the Printer re-uses the existing Job object. The Validate-Job
+ operation is not considered a Job Creation operation because no Job
+
+
+
+Herriot & Hastings Standards Track [Page 10]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ object is created. Therefore, when a statement also applies to
+ either the Restart-Job and/or the Validate-Job operation, they are
+ mentioned explicitly.
+
+ Job Event - an Event caused by some change in a particular job on the
+ Printer, e.g., 'job-completed'.
+
+ Machine Consumable Event Notification - bytes for program
+ consumption. The bytes are formatted according to the Delivery
+ Method document.
+
+ Notification - when not in the phrases 'Event Notification' and
+ 'Notification Recipient' - the concepts of this specification, i.e.,
+ Events, Subscription Objects, and Event Notifications.
+
+ Notification Recipient - the entity to which the Printer delivers an
+ Event Notification. For Push Delivery Methods, the IPP Printer sends
+ the Notifications to a Notification Recipient. For Pull Delivery
+ Methods, the Notification Recipient is acting in the role of an IPP
+ client and requests Event Notifications and so the terms "client" and
+
+ "Notification Recipient" are used interchangeably with such Delivery
+ Methods. For example, see [RFC3996].
+
+ Per-Job Subscription Object - A Subscription Object that is
+ associated with a single Job. The Create-Job-Subscriptions operation
+ and Job Creation operations create such an object.
+
+ Per-Printer Subscription Object - A Subscription Object that is
+ associated with the Printer as a whole. The Create-Printer-
+ Subscriptions operation creates such an object.
+
+ Printer Event - an Event caused by some change in the Printer that is
+ not specific to a job, e.g., 'printer-state-changed'.
+
+ Pull Delivery Method - The Printer saves Event Notifications for some
+ event life time and expects the Notification Recipient to request
+ Event Notifications. The Printer delivers the Event Notifications in
+ a response to such a request.
+
+ Push Delivery Method -The Printer delivers the Event Notification
+ shortly after an Event occurs.
+
+ Subscribed Event - an Event that the Subscribing Client expresses
+ interest in by making it a value of the "notify-events" attribute on
+ a Subscription Object.
+
+ Subscribed Job Event - a Subscribed Event that is a Job Event.
+
+
+
+Herriot & Hastings Standards Track [Page 11]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Subscribed Printer Event - a Subscribed Event that is a Printer
+ Event.
+
+ Subscribing Client - The client that creates the Subscription Object.
+
+ Subscription Attributes Group - The attributes group in a response
+ that contains Subscription Object attributes.
+
+ Subscription Creation Operation - An operation that creates a
+ Subscription Object: Job Creation operations, Create-Job-
+ Subscriptions operation, Create-Printer-Subscriptions operation. In
+ the context of a Job Creation operation, a Subscription Creation
+ Operation is the part of the Job Creation operation that creates one
+ or more Subscription objects. The Restart-Job operation [RFC2911] is
+ not considered a Subscription Creation Operation, since the Printer
+ re-uses the Job's existing Subscription Objects, rather than creating
+ any new Subscription Objects.
+
+ Subscription Creation Request - The request portion of a Subscription
+ Creation Operation.
+
+ Subscription Description Attributes - Subscription Object attributes
+ that a Printer supplies during a Subscription Creation Operation.
+
+ Subscription Object - An object containing a set of attributes that
+ indicate: the Notification Recipient (for Push Delivery Method
+ only), the Delivery Method, the Subscribed Events that cause the
+ Printer to deliver an Event Notification, and the information to
+ include in an Event Notification.
+
+ Subscription Template Attributes - Subscription Object attributes
+ that a client can supply in a Subscription Creation Operation and
+ associated Printer Object attributes that specify supported and
+ default values for the Subscription Object attributes.
+
+ Subscription Template Attributes Group - The attributes group in a
+ request that contains Subscription Object attributes that are
+ Subscription Template Attributes.
+
+4. Object Relationships
+
+ This section defines the object relationships between the Printer,
+ Job, and Subscription Objects. It does not define the
+ implementation. For an illustration of these relationships, see
+ Appendix 19.
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 12]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+4.1. Printer and Per-Printer Subscription Objects
+
+ 1. A Printer object can be associated with zero or more Per-Printer
+ Subscription Objects.
+
+ 2. Each Per-Printer Subscription Object is associated with exactly
+ one Printer object.
+
+4.2. Printer, Job and Per-Job Subscription Objects
+
+ 1. A Printer object is associated with zero or more Job objects.
+
+ 2. Each Job object is associated with exactly one Printer object.
+
+ 3. A Job object is associated with zero or more Per-Job Subscription
+ Objects.
+
+ 4. Each Per-Job Subscription Object is associated with exactly one
+ Job object.
+
+5. Subscription Object
+
+ A Subscribing Client creates a Subscription Object with a
+ Subscription Creation Operation in order to indicate its interest in
+ certain Events. See section 11 for a description of these
+ operations. When an Event occurs, the Subscription Object specifies
+ to the Printer where to deliver Event Notifications for Push Delivery
+ Methods only, how to deliver them, and what to include in them. See
+ section 9 for details on the contents of an Event Notification.
+
+ Using the IPP Job Template attributes as a model (see [RFC2911]
+ section 4.2), the attributes of a Subscription Object are divided
+ into two categories: Subscription Template Attributes and
+ Subscription Description Attributes.
+
+ Subscription Template attributes are, in turn, like the Job Template
+ attributes, divided into
+
+ 1. Subscription Object attributes that a client can supply in a
+ Subscription Creation Request and
+
+ 2. their associated Printer Object attributes that specify supported
+ and default values for the Subscription Object attributes
+
+ The remainder of this section specifies general rules for
+ Subscription Template Attributes and describes each attribute in a
+ Subscription Object.
+
+
+
+
+Herriot & Hastings Standards Track [Page 13]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+5.1. Rules for Support of Subscription Template Attributes
+
+ Subscription Template Attributes are fundamental to the Notification
+ model described in this specification. The client supplies these
+ attributes in Subscription Creation Operations and the Printer uses
+ these attributes to populate a newly created Subscription Object.
+
+ Subscription Objects attributes that are Subscription Template
+ Attributes conform to the following rules:
+
+ 1. Each attribute's name starts with the prefix string "notify-" and
+ this document calls such attributes "notify-xxx".
+
+ 2. For each "notify-xxx" Subscription Object attribute defined in
+ column 1 of Table 1 in section 5.3, Table 1 specifies
+ corresponding Printer attributes: "notify-xxx-default", "notify-
+ xxx-supported", "yyy-supported" and "notify-max-xxx-supported"
+ defined in column 2 of Table 1. Note "xxx" stands for the same
+ string in each case and "yyy" stands for some other string.
+
+ 3. If a Printer supports "notify-xxx" in column 1 of Table 1, then
+ the Printer MUST support all associated attributes specified in
+ column 2 of Table 1. For example, Table 1 shows that if the
+ Printer supports "notify-events", it MUST support "notify-events-
+ default", "notify-events-supported" and "notify-max-events-
+ supported".
+
+ 4. If a Printer does not support "notify-xxx" in column 1 of Table 1,
+ then the Printer MUST NOT support any associated "notify-yyy"
+ attributes specified in column 2 of Table 1. For example, Table 1
+ shows that if the Printer doesn't support "notify-events", it MUST
+ NOT support "notify-events-default", "notify-events-supported" and
+ "notify-max-events-supported". Note this rule does not apply to
+ attributes whose names do not start with the string "notify-" and
+ are thus defined in another object and used by other attributes.
+
+ 5. Most "notify-xxx" attributes have a corresponding "yyy-supported"
+ attribute that specifies the supported values for "notify-xxx".
+ Column 2 of Table 1 specifies the name of each "yyy-supported"
+ attribute. The naming rules of IPP/1.1 (see [RFC2911]) are used
+ when "yyy-supported" is "notify-xxx-supported".
+
+ 6. Some "notify-xxx" attributes have a corresponding "notify-xxx-
+ default" attribute that specifies the value for "notify-xxx" if
+ the client does not supply it. Column 2 of Table 1 specifies the
+ name of each "notify-xxx-default" attribute. The naming rules of
+ IPP/1.1 (see [RFC2911]) are used.
+
+
+
+
+Herriot & Hastings Standards Track [Page 14]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ If a client wishes to present an end user with a list of supported
+ values from which to choose, the client SHOULD query the Printer for
+ its supported value attributes. The client SHOULD also query the
+ default value attributes. If the client then limits selectable
+ values to only those values that are supported, the client can
+ guarantee that the values supplied by the client in the create
+ request all fall within the set of supported values at the Printer.
+ When querying the Printer, the client MAY enumerate each attribute by
+ name in the Get-Printer-Attributes Request, or the client MAY just
+ supply the 'subscription-template' group name in order to get the
+ complete set of supported attributes (both supported and default
+ attributes - see section 11.2.3).
+
+5.2. Rules for Processing Subscription Template Attributes
+
+ This section defines a detailed set of rules that a Printer follows
+ when it processes Subscription Template Attributes in a Subscription
+ Creation Request. These rules are similar to the rules for
+ processing Operation attributes in [RFC2911]. That is, the Printer
+ may or may not support an attribute and a client may or may not
+ supply the attribute. Some combinations of these cases are OK.
+ Others return warnings or errors, and perhaps a list of unsupported
+ attributes.
+
+ A Printer MUST implement the following behavior for processing
+ Subscription Template Attributes in a Subscription Creation Request:
+
+ 1. If a client supplies a "notify-xxx" attribute from column 1 of
+ Table 1 and the Printer supports it and its value, the Printer
+ MUST populate the attribute on the created Subscription Object.
+
+ 2. If a client supplies a "notify-xxx" attribute from column 1 of
+ Table 1 and the Printer doesn't support it or its value, the
+ Printer MUST NOT populate the attribute on the created
+ Subscription Object with it. The Printer MUST do one of the
+ following:
+
+ a) If the value of the "notify-xxx" attribute is unsupported, the
+ Printer MUST return the attribute with its value in the
+ Subscription Attributes Group of the response.
+
+ b) If "notify-xxx" is an unsupported attribute, the Printer MUST
+ return the attribute in the Subscription Attributes Group of
+ the response with the 'unsupported' out-of-band value.
+
+ Note: The rules of this step are the same as for Unsupported
+ Attributes [RFC2911] section 3.1.7. except that the unsupported
+ attributes are returned in the Subscription Attributes Group
+
+
+
+Herriot & Hastings Standards Track [Page 15]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ rather than the Unsupported Attributes Group because Subscription
+ Creation Operations can create more than one Subscription Object).
+
+ 3. If a client is REQUIRED to supply a "notify-xxx" attribute from
+ column 1 of Table 1 and the Printer doesn't support the supplied
+ value, the Printer MUST NOT create a Subscription Object. The
+ rules for Unsupported Attributes in step #2 still apply.
+
+ 4. If a client does not supply a "notify-xxx" attribute from column 1
+ of Table 1 and the attribute is REQUIRED for the client to supply,
+ the Printer MUST reject the Subscription Creation Operation
+ (including Job Creation operations) without creating a
+ Subscription Object, and MUST return in the response:
+
+ a) the status code 'client-error-bad-request' AND
+
+ b) no Subscription Attribute Groups.
+
+ 5. If a client does not supply a "notify-xxx" attribute from column 1
+ of Table 1 that is OPTIONAL for the client to supply, and column 2
+ of Table 1 either:
+
+ a) specifies a "notify-xxx-default" attribute, the Printer MUST
+ behave as if the client had supplied the "notify-xxx-default"
+ attribute (see step #1) and populate the Subscription object
+ with the value of the "notify-xxx-default" attribute as part of
+ the Subscription Creation operation (unlike Job Template
+ attributes where the Printer does not populate the Job object
+ with defaults - see [RFC2911]) OR
+
+ b) does not specify a "notify-xxx-default" attribute, the Printer
+ MUST populate the "notify-xxx" attribute on the Subscription
+ Object according to the definition of the "notify-xxx"
+ attribute in a section 5.3. For some attributes, the "notify-
+ xxx" is populated with the value of some other attribute, and
+ for others, the "notify-xxx" is NOT populated on the
+ Subscription object at all.
+
+ 6. A Printer MUST create a Subscription Object for each Subscription
+ Template Attributes group in a request unless the Printer:
+
+ a) encounters some attributes in a Subscription Template
+ Attributes Group that require the Printer not to create the
+ Subscription Object OR
+
+ b) would create a Per-Job Subscription Object when it doesn't have
+ space for another Per-Job Subscription Object OR
+
+
+
+
+Herriot & Hastings Standards Track [Page 16]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ c) would create a Per-Printer Subscription Object when it doesn't
+ have space for another Per-Printer Subscription Object.
+
+ 7. A response MUST contain one Subscription Attributes Group for each
+ Subscription Template Attributes Group in the request (and in the
+ same order) whether the Printer creates a Subscription Object from
+ the Subscription Template Attributes Group or not. However, the
+ attributes in each Subscription Attributes Group can be in any
+ order.
+
+ 8. The Printer MUST populate each Subscription Attributes Group of
+ the response such that each contains:
+
+ a) the "notify-subscription-id" attribute (see section 5.4.1), if
+ and only if the Printer creates a Subscription Object.
+
+ b) the "notify-lease-duration" attribute (see section 5.3.8), if
+ and only if the Printer creates a Per-Printer Subscription
+ Object. The value of this attribute is the value of the
+ Subscription Object's "notify-lease-duration" attribute. This
+ value MAY be different from the client-supplied value (see
+ section 5.3.8). If a client supplies this attribute in the
+ creation of a Per-Job Subscription Object, it MUST appear in
+ this group with the out-of-band value 'unsupported' to indicate
+ that the Printer doesn't support it in this context.
+
+ c) all of the unsupported Subscription Template Attributes from
+ step #2. Note, they are not returned in the Unsupported
+ Attributes Group in order to separate the unsupported
+ attributes for each Subscription Object.
+
+ d) the "notify-status-code" attribute if the Printer does not
+ create the Subscription Object or if there are unsupported
+ attributes from step #2. The possible values of the "notify-
+ status-code" attribute are shown below (see section 13 for more
+ details). The Printer returns the first value in the list
+ below that describes the status.
+
+ 'client-error-uri-scheme-not-supported': the Subscription
+ Object was not created because the scheme of the "notify-
+ recipient-uri" attribute is not supported. See section 13.1
+ for more details about this status code. See step #3 in
+ this section for the case that causes this error, and the
+ resulting step #6a) that causes the Printer not to create
+ the Subscription Object.
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 17]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ 'client-error-attributes-or-values-not-supported': the
+ Subscription Object was not created because the method of
+ the "notify-pull-method" attribute is not supported. See
+ section 13.1 for more details about this status code. See
+ step #3 in this section for the case that causes this error,
+ and the resulting step #6a) that causes the Printer not to
+ create the Subscription Object.
+
+ 'client-error-too-many-subscriptions': the Subscription
+ Object was not created because the Printer has no space for
+ additional Subscription Objects. The client MAY try again
+ later. See section 13.3 for more details about this status
+ code. See steps #6b) and #6c) in this section for the cases
+ that causes this error.
+
+ 'successful-ok-too-many-events': the Subscription Object was
+ created without the "notify-events" values included in this
+ Subscription Attributes Group because the "notify-events"
+ attribute contains too many values. See section 13.4 for
+ more details about this status code. See step #2 in this
+ section and section 5.3.3 for the cases that cause this
+ status code.
+
+ 'successful-ok-ignored-or-substituted-attributes': the
+ Subscription Object was created but some supplied
+ Subscription Template Attributes are unsupported. These
+ unsupported attributes are also in the Subscription
+ Attributes Group. See section 13.5 for more details about
+ this status code. See step #2 in this section for the cases
+ that cause this status code.
+
+ 9. The Printer MUST validate all Subscription Template Attributes and
+ MUST return all unsupported attributes and values in the
+ corresponding Subscription Attributes Group of the response (see
+ step #2) unless it determines that it could not create additional
+ Subscription Objects because of condition #6b) or condition #6c).
+ Then, the Printer NEED NOT validate these additional Subscription
+ Template Attributes and the client MUST NOT expect to find
+ unsupported attributes from step #2 in such additional
+ Subscription Attribute Groups.
+
+5.3. Subscription Template Attributes
+
+ This section contains the Subscription Template Attributes defined
+ for the Subscription and Printer objects.
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 18]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Table 1 below shows the Subscription Template Attributes and has two
+ columns:
+
+ - Attribute in Subscription Object: the name and attribute syntax of
+ each Subscription Object Attribute that is a Subscription Template
+ Attribute
+
+ - Default and Supported Printer Attributes: the default attribute
+ and supported Printer attributes that are associated with the
+ attribute in column 1.
+
+ The "notify-recipient-uri" attribute is for use with Push Delivery
+ Methods. The "notify-pull-method" attribute is for use with Pull
+ Delivery Methods.
+
+ For Push Delivery Methods, a Printer MUST support all attributes in
+ Table 1 below except for "notify-pull-method" and "notify-attributes"
+ (and "notify-pull-method-supported" and "notify-attributes-
+ supported"). For Pull Delivery Methods, a Printer MUST support all
+ attributes in Table 1 below except for "notify-recipient-uri" and
+ "notify-attributes" (and "notify-schemes-supported" and "notify-
+ attributes-supported"). If a Printer supports both Push and Pull
+ Delivery Methods, then it MUST support both "notify-recipient-uri"
+ and "notify-pull-method" attributes.
+
+ For Pull Delivery Methods, a client MUST supply "notify-recipient-
+ uri" and MAY omit any of the rest of the attributes in column 1 of
+ Table 1 in a Subscription Creation Request. For Push Delivery
+ Methods, a client MUST supply "notify-pull-method" and MAY omit any
+ of the rest of the attributes in column 1 of Table 1 in a
+ Subscription Creation Request. A client MUST NOT supply both
+ "notify-recipient-uri" and "notify-pull-method" attributes in the
+ same Subscription Creation Request.
+
+ Note: The Default and Supported Printer attributes listed in column
+ 2 of Table 1 do not have separate sections in this specification
+ defining their semantics. Instead, the section for the corresponding
+ Subscription Object attribute (column 1 of Table 1) contains the
+ semantics of these Printer attributes. This approach follows the
+ precedence of the Job Template attributes in section 4.2 of [RFC2911]
+ where the corresponding "xxx-default" and "xxx-supported" Printer
+ attributes are defined in the same section as the "xxx" Job
+ attribute.
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 19]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Table 1 - Subscription Template Attributes
+
+ Attribute in Subscription Default and Supported Printer
+ Object Attributes
+
+ notify-recipient-uri (uri) * notify-schemes-supported (1setOf
+ uriScheme)
+ notify-pull-method (type2 notify-pull-method-supported (1setOf
+ keyword) ** type2 keyword)
+ notify-events (1setOf type2 notify-events-default (1setOf type2
+ keyword) keyword)
+ notify-events-supported (1setOf type2
+ keyword)
+ notify-max-events-supported
+ (integer(2:MAX))
+
+ notify-attributes (1setOf notify-attributes-supported (1setOf
+ type2 keyword) type2 keyword)
+ notify-user-data
+ (octetString(63))
+ notify-charset (charset) charset-supported (1setOf charset)
+ notify-natural-language generated-natural-language-supported
+ (naturalLanguage) (1setOf naturalLanguage)
+ notify-lease-duration notify-lease-duration-default
+ (integer(0:MAX)) (integer(0:67108863))
+ notify-lease-duration-supported
+ (1setOf (integer(0: 67108863) |
+ rangeOfInteger(0:67108863)))
+ notify-time-interval
+ (integer(0:MAX))
+
+ * "notify-recipient-uri" is for Push Delivery Methods only.
+ ** "notify-pull-method" is for Pull Delivery Methods only.
+
+5.3.1. notify-recipient-uri (uri)
+
+ This attribute's value is a URL, which is a special case of a URI.
+ Its value consists of a scheme and an address. The address specifies
+ the Notification Recipient and the scheme specifies the Push Delivery
+ Method for each Event Notification associated with this Subscription
+ Object.
+
+ If a Printer supports any Push Delivery Methods, a Printer MUST
+ support this attribute and return the value as supplied by the client
+ (no case conversion or other canonicalization) in any operation
+ response that includes this attribute.
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 20]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ For a Push Delivery Method, a client MUST supply this attribute in a
+ Subscription Creation Operation. Thus there is no need for a default
+ Printer attribute.
+
+ The URI scheme of the value of this attribute on a Subscription
+ object MUST be a value of the "notify-schemes-supported (1setOf
+ uriScheme)" Printer attribute (see section 5.3.1.1). Note: According
+ to [RFC2396] the ":" terminates the scheme and so is not part of the
+ scheme. Therefore, values of the "notify-schemes-supported" Printer
+ attribute do not include the ":" character.
+
+ If the client supplies an unsupported scheme in the value of this
+ attribute, then the Printer MUST NOT create the Subscription Object
+ and MUST return the "notify-status-code" attribute with the 'client-
+ error-uri-scheme-not-supported' value in the Subscription Attributes
+ Group in the response.
+
+5.3.1.1. notify-schemes-supported (1setOf uriScheme)
+
+ This attribute contains the URI schemes supported in the "notify-
+ recipient-uri" Subscription Template attribute. See sections 5.1 and
+ 5.2 for the behavior of "xxx-supported" Subscription Template Printer
+ attributes.
+
+5.3.2. notify-pull-method (type2 keyword)
+
+ This attribute's value is a type2 keyword indicating which Pull
+ Delivery Method is to be used.
+
+ Since a Printer MUST support the 'ippget' Pull Delivery Method
+ [RFC3996] (see section 15), a Printer MUST support this attribute and
+ return the value as supplied by the client in any operation response
+ that includes this attribute.
+
+ For a Pull Delivery Method, a client MUST supply this attribute in a
+ Subscription Creation Operation. Thus there is no need for a default
+ Printer attribute.
+
+ The keyword value of this attribute on a Subscription object MUST be
+ a value of the "notify-pull-method-supported (1setOf type2 keyword)"
+ Printer attribute.
+
+ If the client supplies an unsupported method in the value of this
+ attribute, then the Printer MUST NOT create the Subscription Object
+ and MUST return the "notify-status-code" attribute with the 'client-
+ error-attributes-or-values-not-supported' value in the Subscription
+ Attributes Group in the response.
+
+
+
+
+Herriot & Hastings Standards Track [Page 21]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+5.3.2.1. notify-pull-method-supported (1setOf type2 keyword)
+
+ See sections 5.1 and 5.2 for the behavior of "xxx-supported"
+ Subscription Template Printer attributes.
+
+5.3.3. notify-events (1setOf type2 keyword)
+
+ This attribute contains a set of Subscribed Events. When an Event
+ occurs and it "matches" a value of this attribute, the Printer
+ delivers an Event Notification using information in the Subscription
+ Object. The details of "matching" are described subsection 5.3.3.5.
+
+ A Printer MUST support this attribute.
+
+ A client MAY supply this attribute in a Subscription Creation
+ Operation. If the client does not supply this attribute in
+ Subscription Creation Operation, the Printer MUST populate this
+ attribute on the Subscription Object with its "notify-events-default"
+ attribute value.
+
+ Each keyword value of this attribute on a Subscription Object MUST be
+ a value of the "notify-events-supported (1setOf type2 keyword)"
+ Printer attribute.
+
+ The number of values of this attribute MUST NOT exceed the value of
+ the "notify-max-events-supported" attribute. A Printer MUST support
+ at least 2 values per Subscription Object. If the number of values
+ supplied by a client in a Subscription Creation Operation exceeds the
+ value of this attribute, the Printer MUST treat extra values as
+ unsupported values and MUST use the value of 'successful-ok-too-
+ many-events' for the "notify-status-code" attribute in the
+ Subscription Attributes Group of the response.
+
+5.3.3.1. notify-events-default (1setOf type2 keyword)
+
+ See sections 5.1 and 5.2 for the behavior of "xxx-default"
+ Subscription Template Printer attributes.
+
+5.3.3.2. notify-events-supported (1setOf type2 keyword)
+
+ See sections 5.1 and 5.2 for the behavior of "xxx-supported"
+ Subscription Template Printer attributes.
+
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 22]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+5.3.3.3. notify-max-events-supported (integer(2:MAX))
+
+ This attribute specified the maximum number of events that the
+ Printer supports for the "notify-events" Subscription Template
+ attribute. See sections 5.1 and 5.2 for the behavior of "xxx-
+ supported" Subscription Template Printer attributes.
+
+5.3.3.4. Standard Values for Subscribed Events
+
+ Each value of this attribute is a keyword and it specifies a
+ Subscribed Event that represents certain changes. Some keywords
+ represent a subset of changes of another keyword, e.g., 'job-
+ completed' is an Event value which is a sub-value of 'job-state-
+ change'. See section 5.3.3.5 for the case where this attribute
+ contains both a value and a sub-value.
+
+ The values in this section are divided into three categories: No
+ Events, Job Events and Printer Events.
+
+ A Printer MUST support the Events indicated as "REQUIRED" and MAY
+ support the Events indicated as "OPTIONAL".
+
+5.3.3.4.1. No Events
+
+ The standard and only keyword value for No Events is:
+
+ 'none': REQUIRED - no Event Notifications for any Events. As the
+ sole value of "notify-events-supported", this value means that the
+ Printer does not support the delivery of Event Notifications. As
+ the sole value of "notify-events-default", this value means that a
+ client MUST specify the "notify-events" attribute in order for a
+ Subscription Creation Operation to succeed. If the Printer
+ receives this value as the sole value of a Subscription Creation
+ Operation, it does not create a Subscription Object. If a Printer
+ receives this value with other values of a Subscription Creation
+ Operation, the Printer MUST treat this value as an unsupported
+ value.
+
+5.3.3.4.2. Subscribed Printer Events
+
+ The standard keyword values for Subscribed Printer Events are:
+
+ 'printer-state-changed': REQUIRED - the Printer changed state from
+ any state to any other state. Specifically, the value of the
+ Printer's "printer-state", "printer-state-reasons" or "printer-
+ is-accepting-jobs" attributes changed.
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 23]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ This Subscribed Event value has the following sub-values:
+ 'printer-restarted' and 'printer-shutdown'. A client can listen
+ for any of these sub-values if it doesn't want to listen to all
+ printer-state changes:
+
+ 'printer-restarted': OPTIONAL - when the printer is powered
+ up.
+
+ 'printer-shutdown': OPTIONAL - when the device is being
+ powered down.
+
+ 'printer-stopped: REQUIRED - when the printer stops printing,
+ i.e., the value of the "printer-state" Printer attribute
+ becomes 'stopped'.
+
+ 'printer-config-changed': OPTIONAL - when the configuration of a
+ Printer has changed, i.e., the value of the "printer-message-
+ from-operator" or any "configuration" Printer attribute has
+ changed. A "configuration" Printer attribute is an attribute
+ which can change value because of some human interaction either
+ direct or indirect, and which is not covered by one of the other
+ Events in this section. Examples of "configuration" Printer
+ attributes are any of the Job Template attributes, such as "xxx-
+ supported", "xxx-ready" and "xxx-default". The client has to
+ perform a Get-Printer-Attributes to find out the new values of
+ these changed attributes. This Event is useful for GUI clients
+ and drivers to update the available printer capabilities to the
+ user.
+
+ This Event value has the following sub-values: 'printer-media-
+ changed' and 'printer-finishings-changed'. A client can listen
+ for any of these sub-values if it doesn't want to listen to all
+ printer-configuration changes:
+
+ 'printer-media-changed': OPTIONAL - when the media loaded on
+ a printer has been changed, i.e., the "media-ready"
+ attribute has changed. This Event includes two cases: an
+ input tray that goes empty and an input tray that receives
+ additional media of the same type or of a different type.
+ The client must check the "media-ready" Printer attribute
+ (see [RFC2911] section 4.2.11) separately to find out what
+ changed.
+
+ 'printer-finishings-changed': OPTIONAL - when the finisher on
+ a printer has been changed, i.e., the "finishings-ready"
+ attribute has changed. This Event includes two cases: a
+ finisher that goes empty and a finisher that is refilled
+ (even if it is not full). The client must check the
+
+
+
+Herriot & Hastings Standards Track [Page 24]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ "finishings-ready" Printer attribute separately to find out
+ what changed.
+
+ 'printer-queue-order-changed': OPTIONAL - the order of jobs in the
+ Printer's queue has changed, so that an application that is
+ monitoring the queue can perform a Get-Jobs operation to determine
+ the new order. This Event does not include when a job enters the
+ queue (the 'job-created' Event covers that) and does not include
+ when a job leaves the queue (the 'job-completed' Event covers
+ that).
+
+5.3.3.4.3. Subscribed Job Events
+
+ The standard keyword values for Subscribed Job Events are:
+
+ 'job-state-changed': REQUIRED - the job has changed from any state
+ to any other state. Specifically, the Printer delivers this Event
+ whenever the value of the "job-state" attribute or "job-state-
+ reasons" attribute changes. When a Job is removed from the Job
+ Retention or Job History phases (see [RFC2911] section 4.3.7.1),
+ no Event is generated.
+
+ This Event value has the following sub-values: 'job-created',
+ 'job-completed' and 'job-stopped'. A client can listen for any of
+ these sub-values if it doesn't want to listen to all 'job-state
+ changes'.
+
+ 'job-created': REQUIRED - the Printer has accepted a Job
+ Creation operation, a Restart-Job operation [RFC2911], or any
+ job operation that creates a Job object from an existing Job
+ object. The Printer populates the job's "time-at-creation"
+ attribute value (see [RFC2911] section 4.3.14.1). The Printer
+ puts the job in the 'pending', 'pending-held' or 'processing'
+ states.
+
+ 'job-completed': REQUIRED - the job has reached one of the
+ completed states, i.e., the value of the job's "job-state"
+ attribute has changed to: 'completed', 'aborted', or
+ 'canceled'. The Job's "time-at-completed" and "date-time-at-
+ completed" (if supported) attributes are set (see [RFC2911]
+ section 4.3.14). When a Job completes, a Notification
+ Recipient MAY query the Job using the Get-Job-Attributes
+ operation. To allow such a query, the Printer retains the Job
+ in the Job Retention and/or the Job History phases (see
+ [RFC2911] section 4.3.7.1) for a suitable amount of time that
+ depends on implementation and the Delivery Methods supported.
+ The Printer also delivers this Event when a Job is removed with
+ the Purge-Job operation (see [RFC2911] section 3.2.9). In this
+
+
+
+Herriot & Hastings Standards Track [Page 25]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ case, the Event Notification MUST report the 'job-state' as
+ 'canceled' and the Job object is no longer present for query.
+
+ 'job-stopped: OPTIONAL - when the job stops printing, i.e.,
+ the value of the "job-state" Job attribute becomes
+ 'processing-stopped'.
+
+ 'job-config-changed': OPTIONAL - when the configuration of a job has
+ changed, i.e., the value of the "job-message-from-operator" or any
+ of the "configuration" Job attributes have changed. A
+ "configuration" Job attribute is an attribute that can change
+ value because of some human interaction either direct or indirect.
+ Examples of "configuration" Job attributes are any of the job
+ template attributes and the "job-name" attribute. The client
+ performs a Get-Job-Attributes to find out the new values of the
+ changed attributes. This Event is useful for GUI clients and
+ drivers to update the job information to the user.
+
+ 'job-progress': OPTIONAL - when the Printer has completed Printing a
+ sheet. See the separate [RFC3381] specification for additional
+ attributes that a Printer MAY deliver in an Event Notification
+ caused by this Event. The "notify-time-interval" attribute
+ affects this Event by causing the Printer NOT to deliver an Event
+ Notification every time a 'job-progress' Events occurs. See
+ section 5.3.9 for full details.
+
+5.3.3.5. Rules for Matching of Subscribed Events
+
+ When an Event occurs, the Printer MUST find each Subscription object
+ whose "notify-events" attribute "matches" the Event. The rules for
+ "matching" of Subscribed Events are described separately for Printer
+ Events and for Job Events. This section also describes some special
+ cases.
+
+5.3.3.5.1. Rules for Matching of Printer Events
+
+ Given that the Printer causes Printer Event E to occur, for each
+ Per-Job or Per-Printer Subscription S in the Printer, if E equals a
+ value of this attribute in S or E is a sub-value of a value of this
+ attribute in S, the Printer MUST generate an Event Notification.
+
+ Consider the example. There are three Subscription Objects each with
+ the Subscribed Printer Event 'printer-state-changed'. Subscription
+ Object A is a Per-Printer Subscription Object. Subscription Object B
+ is a Per-Job Subscription Object for Job 1, and Subscription Object C
+ is a Per-Job Subscription Object for Job 2. When the Printer enters
+ the 'stopped' state, the Printer delivers an Event Notification to
+ the Notification Recipients of Subscription Objects A, B, and C
+
+
+
+Herriot & Hastings Standards Track [Page 26]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ because this is a Printer Event. Note if Job 1 has already
+ completed, the Printer would not deliver an Event Notification for
+ its Subscription Object, even if Job 1 is retained in the Job
+ Retention and/or the Job History phases (see [RFC2911] section
+ 4.3.7.1).
+
+5.3.3.5.2. Rules for Matching of Job Events
+
+ Given that Job J causes Job Event E to occur:
+
+ 1. For each Per-Printer Subscription S in the Printer, if E equals a
+ value of this attribute in S or E is a sub-value of a value of
+ this attribute in S, the Printer MUST generate an Event
+ Notification.
+
+ 2. For each Per-Job Subscription S associated with Job J, if E equals
+ a value of this attribute in S or E is a sub-value of a value of
+ this attribute in S, the Printer MUST generate an Event
+ Notification.
+
+ 3. For each Per-Job Subscription S that is NOT associated Job J, if E
+ equals a value of this attribute in S or E is a sub-value of a
+ value of this attribute in, the Printer MUST NOT generate an Event
+ Notification from S.
+
+ Consider the example: There are three Subscription Objects listening
+ for the Job Event 'job-completed'. Subscription Object A is a Per-
+ Printer Subscription Object. Subscription Object B is a Per-Job
+ Subscription Object for Job 1, and Subscription Object C is a Per-Job
+ Subscription Object for Job 2. In addition, Per-Printer Subscription
+ Object D is listening for the Job Event 'job-state-changed'. When
+ Job 1 completes, the Printer delivers an Event Notification to the
+ Notification Recipient of Subscription Object A (because it is Per-
+ Printer) and Subscription Object B because it is a Per-Job
+ Subscription Object associated with the Job generating the Event.
+ The Printer also delivers an Event Notification to the Notification
+ Recipient of Subscription Object D because 'job-completed' is a sub-
+ value of 'job-state-changed' - the value that Subscription Object D
+ is listening for. The Printer does not deliver an Event Notification
+ to the Notification Recipients of Subscription Object C because it is
+ a Per-Job Subscription Object associated with some Job other than the
+ Job generating the Event.
+
+5.3.3.5.3. Special Cases for Matching Rules
+
+ This section contains two rules for the special case where a single
+ Event produces multiple Event Notifications destined for the same
+ Notification Recipient. These two rules clarify whether a Printer
+
+
+
+Herriot & Hastings Standards Track [Page 27]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ should send multiple Event Notifications or consolidate them into a
+ single Event Notification.
+
+ If an Event matches Subscribed Events in two different Subscription
+ Objects and the Printer would deliver two identical Event
+ Notifications (except for the "notify-subscription-id" attribute) to
+ the same Notification Recipient using the same Delivery Method, the
+ Printer MUST deliver both Event Notifications. That is, the Printer
+ MUST NOT try to consolidate seemingly identical Event Notifications
+ that occur in separate Subscription objects. Incidentally, the
+ Printer MUST NOT reject Subscription Creation Operations that would
+ create this scenario.
+
+ Consider the example: At the time a Job completes, there are two
+ Per-Printer Subscription Objects A and B with the same Notification
+ Recipient R. Subscription Object A has the Subscribed Job Event
+ 'job-state-changed'. Subscription Object B has the Subscribed Job
+ Event 'job-completed'. Both Subscription Objects match the Event
+ 'job-completed'. The Printer delivers two Event Notifications to the
+ Notification Recipient R. One with the value of 'job-state-changed'
+ for the "notify-subscribed-event" attribute and the other with the
+ value of 'job-completed' for the "notify-subscribed-event"
+ attribute.
+
+ If an Event matches two Subscribed Events in a single Subscription
+ object (e.g., a value and its sub-value), a Printer MAY deliver one
+ Event Notification for each matched value in the Subscription Object
+ or it MAY deliver only a single Event Notification. The rules in
+ sections 5.3.3.5.1 and 5.3.3.5.2 are purposefully flexible about the
+ number of Event Notifications sent when Event E matches two or more
+ values in a Subscription Object.
+
+ Consider the example: At the time a Job completes, a Subscription
+ Object A has two Subscribed Job Events 'job-state-changed' and 'job-
+ completed'. Both Subscribed Job Events match the Event 'job-
+ completed'. The Printer delivers either one or two Event
+ Notifications to the Notification Recipient of Subscription Object A,
+ depending on implementation. If it delivers two Event Notifications,
+ one has the value of 'job-state-changed' for the "notify-
+ subscribed-event" attribute, and the other has the value of 'job-
+ completed' for the "notify-subscribed-event" attribute. If it
+ delivers one Event Notification, it has the value of either 'job-
+ state-changed' or 'job-completed' for the "notify-subscribed-event"
+ attribute, depending on implementation. The algorithm for choosing
+ such a value is implementation dependent.
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 28]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+5.3.4. notify-attributes (1setOf type2 keyword)
+
+ This attribute contains a set of attribute names. When a Printer
+ delivers a Machine Consumable Event Notification, it includes a fixed
+ set of attributes (see section 9.1). If this attribute is present
+ and the Event Notification is Machine Consumable, the Printer also
+ includes the attributes specified by this attribute.
+
+ A Printer MAY support this attribute.
+
+ A client MAY supply this attribute in a Subscription Creation
+ Operation. If the client does not supply this attribute in
+ Subscription Creation Operation or the Printer does not support this
+ attribute, the Subscription Object either (1) MAY contain the
+ "notify-attributes" attribute with a 'none' value or (2) NEED NOT
+ contain the attribute at all. There is no "notify-attributes-
+ default" Printer attribute.
+
+ Each keyword value of this attribute on a Subscription Object MUST be
+ a value of the "notify-attributes-supported (1setOf type2 keyword)"
+ Printer attribute (see section 5.3.4.1). The "notify-attributes-
+ supported" MAY contain any Printer attribute, Job attribute or
+ Subscription Object attribute that the Printer supports in an Event
+ Notification. It MUST NOT contain any of the attributes in Section
+ 9.1 that a Printer automatically puts in an Event Notification; it
+ would be redundant. If a client supplies an attribute in Section
+ 9.1, the Printer MUST treat it as an unsupported attribute value of
+ the "notify-attributes" attribute.
+
+ The following rules apply to each keyword value N of the "notify-
+ attributes" attribute: If the value N names:
+
+ a) a Subscription attribute, the Printer MUST use the attribute N in
+ the Subscription Object that is being used to generate the Event
+ Notification.
+
+ b) a Job attribute and the Printer is generating an Event
+ Notification from a Per-Job Subscription Object S, the Printer
+ MUST use the attribute N in the Job object associated with S.
+
+ c) a Job attribute and the Printer is generating an Event
+ Notification from a Per-Printer Subscription Object and the Event
+ is:
+
+ - a Job Event, the Printer MUST use the attribute N in the Job
+ object that caused the Event.
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 29]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ - a Printer Event, the Printer MUST use the attribute N in the
+ active Job.
+
+ If a Printer supports this attribute and a Subscription Object
+ contains this attribute and the Delivery Method generates a Machine
+ Consumable Event Notification, the Printer MUST include in each Event
+ Notification:
+
+ a) the attributes specified in section 9.1 and
+
+ b) each attribute named by this attribute.
+
+ The Printer MUST NOT use this attribute to generate a Human
+ Consumable Event Notification.
+
+5.3.4.1. notify-attributes-supported (1setOf type2 keyword)
+
+ See sections 5.1 and 5.2 for the behavior of "xxx-supported"
+ Subscription Template Printer attributes.
+
+5.3.5. notify-user-data (octetString(63))
+
+ This attribute contains opaque data that some Delivery Methods
+ include in each Machine Consumable Event Notification. The opaque
+ data might contain, for example:
+
+ - the identity of the Subscriber
+
+ - a path or index to some Subscriber information
+
+ - a key that identifies to the Notification Recipient the ultimate
+ recipient of the Event Notification
+
+ - the id for a Notification Recipient that had previously registered
+ with an Instant Messaging Service
+
+ A Printer MUST support this attribute.
+
+ A client MAY supply this attribute in a Subscription Creation
+ Operation. If the client does not supply this attribute in the
+ Subscription Creation Operation, the Subscription Object either (1)
+ MAY contain the "notify-user-data" attribute with a zero length value
+ or (2) NEED NOT contain the attribute at all. There is no "notify-
+ user-data-default" Printer attribute.
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 30]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ There is no "notify-user-data-supported" Printer attribute. Rather,
+ any octetString whose length does not exceed 63 octets is a supported
+ value. If the length exceeds 63 octets, the Printer MUST treat it as
+ an unsupported value.
+
+5.3.6. notify-charset (charset)
+
+ This attribute specifies the charset to be used in the Event
+ Notification content sent to the Notification Recipient, whether the
+ Event Notification content is Machine Consumable or Human Consumable.
+
+ A Printer MUST support this attribute.
+
+ A client MAY supply this attribute in a Subscription Creation
+ Operation. If the client does not supply this attribute in
+ Subscription Creation Operation or supplies an unsupported value, the
+ Printer MUST populate this attribute in the Subscription Object with
+ the value of the "attributes-charset" operation attribute, which is a
+ REQUIRED attribute in all IPP requests (see [RFC2911]). If the value
+ of the "attributes-charset" attribute is unsupported, the Printer
+ MUST populate this attribute in the Subscription Object with the
+ value of the Printer's "charset-configured" attribute. There is no
+ "notify-charset-default" Printer attribute.
+
+ The value of this attribute on a Subscription Object MUST be a value
+ of the "charset-supported (1setOf charset)" Printer attribute.
+
+5.3.7. notify-natural-language (naturalLanguage)
+
+ This attribute specifies the natural language to be used in any human
+ consumable text in the Event Notification content sent to the
+ Notification Recipient, whether the Event Notification content is
+ Machine Consumable or Human Consumable.
+
+ A Printer MUST support this attribute.
+
+ A client MAY supply this attribute in a Subscription Creation
+ Operation. If the client does not supply this attribute in
+ Subscription Creation Operation or supplies an unsupported value, the
+ Printer MUST populate this attribute in the Subscription Object with
+ the value of the "attributes-natural-language" operation attribute,
+ which is a REQUIRED attribute in all IPP requests (see [RFC2911]
+ section 3.1.4). If the value of the "attributes-natural-language"
+ attribute is unsupported, the Printer MUST populate this attribute in
+ the Subscription Object with the value of the Printer's "natural-
+ language-configured" attribute (see [RFC2911] section 4.4.19). There
+ is no "notify-natural-language-default" Printer attribute.
+
+
+
+
+Herriot & Hastings Standards Track [Page 31]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ The value of this attribute on a Subscription Object MUST be a value
+ of the "generated-natural-language-supported (1setOf type2
+ naturalLanguage)" Printer attribute (see [RFC2911] section 4.4.20).
+
+5.3.8. notify-lease-duration (integer(0:67108863))
+
+ This attribute specifies the duration of the lease (in seconds)
+ associated with the Per-Printer Subscription Object at the time the
+ Subscription Object was created or the lease was renewed. The
+ duration of the lease is infinite if the value is 0, i.e., the lease
+ never expires. See section 5.4.3 on "notify-lease-expiration-time
+ (integer(0:MAX))" for more details.
+
+ This attribute is not present on a Per-Job Subscription Object
+ because the Subscription Object lasts exactly as long as the
+ associated Job object. See discussion of the 'job-completed' event
+ in section 5.3.3.4.3 about retention of the Job object after
+ completion.
+
+ A Printer MUST support this attribute.
+
+ For a Subscription Object Creation operation of a Per-Job
+ Subscription Object, the client MUST NOT supply this attribute. If
+ the client does supply this attribute, the Printer MUST treat it as
+ an unsupported attribute.
+
+ For a Subscription Creation Operation of a Per-Printer Subscription
+ Object or a Renew-Subscription operation, a client MAY supply this
+ attribute. If the client does not supply this attribute, the Printer
+ MUST populate this attribute with its "notify-lease-duration-default"
+ (0:67108863) attribute value. If the client supplies this attribute
+ with an unsupported value, the Printer MUST populate this attribute
+ with a supported value, and this value SHOULD be as close as possible
+ to the value requested by the client. Note: this rule implies that a
+ Printer doesn't assign the value of 0 (infinite) unless the client
+ requests it.
+
+ After the Printer has populated this attribute with a supported
+ value, the value represents the "granted duration" of the lease in
+ seconds and the Printer updates the value of the Subscription
+ Object's "notify-lease-expiration-time" attribute as specified in
+ section 5.4.3.
+
+ The value of this attribute on a Subscription Object MUST be a value
+ of the "notify-lease-duration-supported" (1setOf (integer(0:67108863)
+ | rangeOfInteger(0:67108863))) Printer attribute.
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 32]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ A Printer MAY require authentication in order to return the value of
+ 0 (the lease never expires) as one of the values of "notify-lease-
+ duration-supported", and to allow 0 as a value of the "notify-lease-
+ duration" attribute.
+
+ Note: The maximum value 67,108,863 is 2 raised to the 26 power minus
+ 1 and is about 2 years in seconds. The value is considerably less
+ than MAX so that there is virtually no chance of an overflow when the
+ Printer adds it to the Printer's "printer-up-time" attribute value
+ (see [RFC2911] section 4.4.29) to produce the "notify-lease-
+ expiration-time" Subscription Description attribute value (see
+ section 5.4.3).
+
+5.3.8.1. notify-lease-duration-default (integer(0:67108863))
+
+ See sections 5.1 and 5.2 for the behavior of "xxx-default"
+ Subscription Template Printer attributes.
+
+5.3.8.2. notify-lease-duration-supported (1setOf (integer(0: 67108863) |
+ rangeOfInteger(0:67108863)))
+
+ See sections 5.1 and 5.2 for the behavior of "xxx-supported"
+ Subscription Template Printer attributes.
+
+5.3.9. notify-time-interval (integer(0:MAX))
+
+ The 'job-progress' Event occurs each time that a Printer completes a
+ sheet. Some Notification Recipients do not want to receive an Event
+ Notification every time this Event occurs. This attribute allows a
+ Subscribing Client to request how often it wants to receive Event
+ Notifications for 'job-progress' Events. The value of this attribute
+ MAY be any nonnegative integer (0,MAX) indicating the minimum number
+ of seconds between 'job-progress' Event Notifications.
+
+ The Printer MUST support this attribute if and only if the Printer
+ supports the 'job-progress' Event.
+
+ A client MAY supply this attribute in a Subscription Creation
+ Operation. If the client does not supply this attribute in the
+ Subscription Creation Operation, the Subscription Object either (1)
+ MAY contain the "notify-time-interval" attribute with a '0' value or
+ (2) NEED NOT contain this attribute at all. There is no "notify-
+ time-interval-default" Printer attribute.
+
+ There is no "notify-time-interval-supported" Printer attribute.
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 33]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ If the 'job-progress' Event occurs and a Subscription Object contains
+ the 'job-progress' Event as a value of the 'notify-events' attribute,
+ there are two cases to consider:
+
+ 1. This attribute is not present on the Subscription Object or has
+ the value of 0. The Printer MUST generate and deliver an Event
+ Notification (as is the case with other Events).
+
+ 2. This attribute is present with a nonzero value of N:
+
+ a) If the Printer has not sent an Event Notification for the
+ 'job-progress' Event for the associated Subscription Object
+ within the past N seconds, the Printer MUST deliver an Event
+ Notification for the Event that just occurred. Note when the
+ Printer completes the first page of a Job, this rule implies
+ that the Printer delivers an Event Notification for a Per-Job
+ Subscription Object.
+
+ b) Otherwise, the Printer MUST NOT generate or deliver an Event
+ Notification for the associated Subscription Object. The
+ Printer MUST NOT increase the value of the "notify-sequence-
+ number" Subscription Object attribute (i.e., the sequence of
+ values of the "notify-sequence-number" attribute counts the
+ Event Notifications that the Printer sent and not the Events
+ that do not cause an Event Notification to be sent).
+
+ It is RECOMMENDED that a Subscribing Client use this attribute when
+ it subscribes to the 'job-progress' Event, and that the value be
+ sufficiently large to limit the frequency with which the Printer
+ delivers Event Notifications requests.
+
+ This attribute MUST NOT effect any Events other than 'job-progress'.
+
+5.4. Subscription Description Attributes
+
+ Subscription Description Attributes are those attributes that a
+ Printer adds to a Subscription Object at the time of its creation.
+
+ A Printer MUST support all attributes in this Table 2.
+
+ A client MUST NOT supply the attributes in Table 2 in a Subscription
+ Template Attributes Group of a Subscription Creation Operation.
+ There are no corresponding default or supported attributes.
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 34]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Table 2 - Subscription Description Attributes
+
+ Subscription Object attributes:
+
+ notify-subscription-id (integer(1:MAX))
+ notify-sequence-number (integer(0:MAX))
+ notify-lease-expiration-time (integer(0:MAX))
+ notify-printer-up-time (integer(1:MAX))
+ notify-printer-uri (uri)
+ notify-job-id (integer(1:MAX))
+ notify-subscriber-user-name (name(MAX))
+
+5.4.1. notify-subscription-id (integer (1:MAX))
+
+ This attribute identifies a Subscription Object instance with a
+ number that is unique within the context of the Printer. The Printer
+ generates this value at the time it creates the Subscription Object.
+
+ A Printer MUST support this attribute.
+
+ The Printer MAY assign the value of this attribute sequentially as it
+ creates Subscription Objects. However, if there is no security on
+ Subscription objects, sequential assignment exposes the system to a
+ passive traffic monitoring threat.
+
+ The Printer SHOULD avoid re-using recent values of this attribute
+ during continuous operation of the Printer as well as across power
+ cycles. Then a Subscribing Client is unlikely to find that a stale
+ reference accesses a new Subscription Object.
+
+ The 0 value is not permitted in order to allow for compatibility with
+ "job-id" and with MIB table index values, which are recommended not
+ to be 0.
+
+5.4.2. notify-sequence-number (integer (0:MAX))
+
+ The value of this attribute indicates the number of times that the
+ Printer has generated and attempted to deliver an Event Notification
+ for this Subscription object. When an Event Notification contains
+ this attribute, the Notification Recipient can determine whether it
+ missed some Event Notifications (i.e., numbers skipped) or received
+ duplicates (i.e., same number twice).
+
+ A Printer MUST support this attribute.
+
+ When the Printer creates a Subscription Object, it MUST populate this
+ attribute with a value of 0. This value indicates that the Printer
+ has not sent any Event Notifications for this Subscription Object.
+
+
+
+Herriot & Hastings Standards Track [Page 35]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Each time the Printer delivers a newly generated Event Notification,
+ it MUST increase the value of this attribute by 1. For some Delivery
+ Methods, the Printer MUST include this attribute in each Event
+ Notification, and the value MUST be the value after it is increased
+ by 1. That is, the value of this attribute in the first Event
+ Notification after Subscription object creation MUST be 1, the second
+ MUST be 2, etc. If a Delivery Method is defined such that the
+ Notification Recipient returns a response, the Printer can re-try
+ delivering an Event Notification a certain number of times with the
+ same sequence number when the Notification Recipient fails to return
+ a response.
+
+ If a Subscription Object lasts long enough to reach the value of MAX,
+ its next value MUST be 0, i.e., it wraps.
+
+5.4.3. notify-lease-expiration-time (integer(0:MAX))
+
+ This attribute specifies the time in the future when the lease on the
+ Per-Printer Subscription Object will expire, i.e., the "printer-up-
+ time" value at which the lease will expire. If the value is 0, the
+ lease never expires.
+
+ A Printer MUST support this attribute.
+
+ When the Printer creates a Per-Job Subscription Object, this
+ attribute MUST NOT be present - the Subscription Object lasts exactly
+ as long as the associated Job object. See also the discussion of the
+ 'job-completed' event in section 5.3.3.4.3 about retention of the Job
+ object after completion so that a Notification Recipient can query
+ the Job object after receiving the 'job-completed' Event
+ Notification.
+
+ When the Printer creates a Per-Printer Subscription Object, it
+ populates this attribute with a value that is the sum of the values
+ of the Printer's "printer-up-time" attribute and the Subscription
+ Object's "notify-lease-duration" attribute with the following
+ exception. If the value of the Subscription Object's "notify-lease-
+ duration" attribute is 0 (i.e., no expiration time), then the value
+ of this attribute MUST be set to 0 (i.e., no expiration time).
+
+ When the Printer powers up, it MUST populate this attribute in each
+ persistent Subscription Object with a value using the algorithm in
+ the previous paragraph.
+
+ When the "printer-up-time" equals the value of this attribute, the
+ Printer MUST delete the Subscription Object. A client can extend a
+ lease of a Per-Printer Subscription Object with the Renew-
+ Subscription operation (see section 11.2.6).
+
+
+
+Herriot & Hastings Standards Track [Page 36]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Note: In order to compute the number of seconds remaining in a lease
+ for a Per-Printer Subscription Object, a client can subtract the
+ Subscription's "notify-printer-up-time" attribute (see section 5.4.4)
+ from the Subscription's "notify-lease-expiration-time" attribute.
+
+5.4.4. notify-printer-up-time (integer(1:MAX))
+
+ This attribute is an alias for the Printer's "printer-up-time"
+ attribute " (see [RFC2911] section 4.4.29). In other words, when
+ this attribute is queried with the Get-Subscriptions or Get-
+ Subscription-Attributes operations (see sections 11.2.4 and 11.2.5),
+ the value returned is the current value of the Printer's "printer-
+ up-time" attribute, rather than the time at which the Subscription
+ Object was created.
+
+ A Printer MUST support this attribute.
+
+ When the Printer creates a Per-Job Subscription Object, this
+ attribute MUST NOT be present. When the Printer creates a Per-
+ Printer Subscription Object, this attribute MUST be present.
+
+ Note: this attribute exists in a Per-Printer Subscription Object so
+ that a client using the Get-Subscription-Attributes or Get-
+ Subscription operations can convert the Per-Printer Subscription's
+ "notify-lease-expiration-time" attribute to wall clock time with one
+ request. If the value of the "notify-lease-expiration-time"
+ attribute is not 0 (i.e., no expiration time), then the difference
+ between the "notify-lease-expiration-time" attribute and the
+ "notify-printer-up-time" is the remaining number of seconds on the
+ lease from the current time.
+
+5.4.5. notify-printer-uri (uri)
+
+ This attribute identifies the Printer object that created this
+ Subscription Object.
+
+ A Printer MUST support this attribute.
+
+ During a Subscription Creation Operation, the Printer MUST populate
+ this attribute with the value of the "printer-uri" operation
+ attribute in the request. From the Printer URI, the client can, for
+ example, determine what security scheme was used.
+
+5.4.6. notify-job-id (integer(1:MAX))
+
+ This attribute specifies whether the containing Subscription Object
+ is a Per-Job or Per-Printer Subscription Object, and for Per-Job
+ Subscription Objects, it specifies the associated Job.
+
+
+
+Herriot & Hastings Standards Track [Page 37]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ A Printer MUST support this attribute.
+
+ If this attribute is not present, the Subscription Object MUST be a
+ Per-Printer Subscription. If this attribute is present, the
+ Subscription Object MUST be a Per-Job Subscription Object and this
+ attribute MUST identify the Job with which the Subscription Object is
+ associated.
+
+ Note: This attribute could be useful to a Notification Recipient that
+ receives an Event Notification generated from a Per-Job Subscription
+ Object and caused by a Printer Event. The Event Notification gives
+ access to the Printer and the Subscription Object. The Event
+ Notification gives access to the associated Job only via this
+ attribute. See discussion of the 'job-completed' event in section
+ 5.3.3.4.3 about retention of the Job object after completion so that
+ a Notification Recipient can query the Job object after receiving the
+ 'job-completed' Event Notification.
+
+5.4.7. notify-subscriber-user-name (name(MAX))
+
+ This attribute contains the name of the user who performed the
+ Subscription Creation Operation.
+
+ A Printer MUST support this attribute.
+
+ The Printer MUST populates this attribute with the most authenticated
+ printable name that it can obtain from the authentication service
+ over which the Subscription Creation Operation was received. The
+ Printer uses the same mechanism for determining the value of this
+ attribute as it does for a Job's "job-originating-user-name" (see
+ [RFC2911] section 4.3.6).
+
+ Note: To help with authentication, a Subscription Object may have
+ additional private attributes about the user, e.g., a credential of a
+ principal. Such private attributes are implementation-dependent and
+ not defined in this document.
+
+6. Printer Description Attributes Related to Notification
+
+ This section defines the Printer Description attributes that are
+ related to Notification. Table 3 lists the Printer Description
+ attributes, indicates the Printer support required for conformance,
+ and whether or not the attribute is READ-ONLY (see section 3.1):
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 38]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Table 3 - Printer Description Attributes Associated with Notification
+
+ Printer object attributes: REQUIRED READ-ONLY
+
+ printer-state-change-time (integer(1:MAX)) No Yes
+ printer-state-change-date-time (dateTime) No Yes
+
+6.1. printer-state-change-time (integer(1:MAX))
+
+ This OPTIONAL attribute records the most recent time at which the
+ 'printer-state-changed' Printer Event occurred whether or not any
+ Subscription objects were listening for this event. This attribute
+ helps a client or operator to determine how long the Printer has been
+ in its current state.
+
+ A Printer MAY support this attribute and if so, the attribute MUST be
+ READ-ONLY.
+
+ On power-up, the Printer MUST populate this attribute with the value
+ of its "printer-up-time" attribute, so that it always has a value.
+ Whenever the 'printer-state-changed' Printer Event occurs, the
+ Printer MUST update this attribute with the value of the Printer's
+ "printer-up-time" attribute.
+
+6.2. printer-state-change-date-time (dateTime)
+
+ This OPTIONAL attribute records the most recent time at which the
+ 'printer-state-changed' Printer Event occurred whether or not there
+ were any Subscription Objects listening for this event. This
+ attribute helps a client or operator to determine how long the
+ Printer has been in its current state.
+
+ A Printer MAY support this attribute and if so, the attribute MUST be
+ READ-ONLY.
+
+ On power-up, the Printer MUST populate this attribute with the value
+ of its "printer-current-time" attribute, so that it always has a
+ value (see [RFC2911] section 4.4.30 on "printer-current-time").
+ Whenever the 'printer-state-changed' Printer Event occurs, the
+ Printer MUST update this attribute with the value of the Printer's
+ "printer-current-time" attribute.
+
+7. New Values for Existing Printer Description Attributes
+
+ This section contains those attributes for which additional values
+ are added.
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 39]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+7.1. operations-supported (1setOf type2 enum)
+
+ The following "operation-id" values are added in order to support the
+ new operations defined in this document:
+
+ Table 4 - Operation-id assignments
+
+ Value Operation Name
+
+ 0x0016 Create-Printer-Subscriptions
+ 0x0017 Create-Job-Subscriptions
+ 0x0018 Get-Subscription-Attributes
+ 0x0019 Get-Subscriptions
+ 0x001A Renew-Subscription
+ 0x001B Cancel-Subscription
+
+8. Attributes Only in Event Notifications
+
+ This section contains those attributes that exist only in Event
+ Notifications and do not exist in any objects.
+
+8.1. notify-subscribed-event (type2 keyword)
+
+ This attribute indicates the Subscribed Event that caused the Printer
+ to deliver this Event Notification. This attribute exists only in
+ Event Notifications.
+
+ This attribute MUST contain one of the values of the "notify-events"
+ attribute in the Subscription Object, i.e., one of the Subscribed
+ Event values. Its value is the Subscribed Event that "matches" the
+ Event that caused the Printer to deliver this Event Notification.
+ This Subscribed Event value may be identical to the Event or the
+ Event may be a sub-value of the Subscribed Event. For example, the
+ 'job-completed' Event (which is a sub-event of the 'job-state-
+ changed' event) would cause the Printer to deliver an Event
+ Notification for either the 'job-completed' or 'job-state-changed'
+ Subscribed Events and to deliver the 'job-completed' or 'job-state-
+ changed' value for this attribute, respectively. See section 5.3.3.5
+ for the "matching" rules of Subscribed Events and for additional
+ examples.
+
+ The Delivery Method Document specifies whether the Printer includes
+ the value of this attribute in an Event Notification.
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 40]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+8.2. notify-text (text(MAX))
+
+ This attribute contains a Human Consumable text message (see section
+ 9.2). This message describes the Event and is encoded as plain text,
+ i.e., 'text/plain' with the charset specified by Subscription
+ Object's "notify-charset" attribute.
+
+ Note: this attribute contains a text message only and must not
+ contain any encoding information, such as 'text/plain'. The
+ 'text/plain' encoding is implicit and thus the charset must be
+ specified by an alternate mechanism, namely the "notify-charset"
+ attribute.
+
+ The Delivery Method Document specifies whether the Printer includes
+ this attribute in an Event Notification.
+
+9. Event Notification Content
+
+ This section defines the Event Notification content that the Printer
+ delivers when an Event occurs.
+
+ When an Event occurs, the Printer MUST find each Subscription object
+ whose "notify-events" attribute "matches" the Event. See section
+ 5.3.3.5 for details on "matching". For each matched Subscription
+ Object, the Printer MUST create an Event Notification with the
+ content and format that the Delivery Method Document specifies. The
+ content contains the value of attributes specified by the Delivery
+ Method Document. The Printer obtains the values immediately after
+ the Event occurs. For example, if the "printer-state" attribute
+ changes from 'idle' to 'processing', the Event 'printer-state-
+ changed' occurs and the Printer puts various attributes into the
+ Event Notification, including "printer-up-time" and "printer-state"
+ with the values that they have immediately after the Event occurs,
+ i.e., the value of "printer-state" is 'processing'.
+
+ Event Notification Ordering:
+
+ When a Printer delivers Event Notifications, the Event Notifications
+ from any given Subscription Object MUST be in time stamp order, i.e.,
+ in order of increasing "printer-up-time" attribute value in the Event
+ Notification (see Table 5). These Event Notifications MAY be
+ interleaved with those from other Subscription Objects, as long as
+ those others are also in time stamp order. The Printer MUST observe
+ these ordering requirements whether delivering multiple pending
+ Events as multiple separate Event Notifications or together in a
+ single Compound Event Notification.
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 41]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ If a Subscribing Client wants the Printer to deliver certain Event
+ Notifications in time stamp order, the Subscribing Client uses a
+ single Subscription Object. Even so, depending on the underlying
+ transport, the actual order that a Notification Recipient receives
+ separate Event Notifications may differ from the order sent by the
+ Printer (e.g., email).
+
+ Example: Consider two Per-Printer Subscription Objects: SO1 and SO2.
+ SO1 requests 'job-state-changed' events and SO2 requests 'printer-
+ state-changed' events. The number in parens is the time stamp. The
+ following Event Notification sequences are the only ones that conform
+ to the ordering requirements for the Printer to deliver the Event
+ Notifications:
+
+ (a) SO1: 'job-created' (1000), SO1: 'job-stopped' (1005), SO1:
+ 'job-completed' (1009), SO2: 'printer-stopped' (1005)
+
+ (b) SO1: 'job-created' (1000), SO1: 'job-stopped' (1005), SO2:
+ 'printer-stopped' (1005), SO1: 'job-completed' (1009)
+
+ (c) SO1: 'job-created' (1000), SO2: 'printer-stopped' (1005), SO1:
+ 'job-stopped' (1005), SO1: 'job-completed' (1009)
+
+ (d) SO2: 'printer-stopped (1005), SO1: 'job-created' (1000), SO1:
+ 'job-stopped' (1005), SO1: 'job-completed' (1009)
+
+ Examples (b) and (c) are interleaved; examples (a) and (d) are not
+ interleaved and are not appropriate for some Delivery Methods.
+
+ If two different Events occur simultaneously, or nearly so (e.g.,
+ "printer-up-time" has the same value for both), the Printer MUST
+ create a separate Event Notification for each Event, even if the
+ associated Subscription Object is the same for both Events. However,
+ the Printer MAY combine these distinct Event Notifications into a
+ single Compound Event Notification if the Delivery Method supports
+ Compound Event Notifications. For example, suppose that two nearly-
+ simultaneously Events represent two successive 'printer-state-
+ changed' Events, one from 'idle' to 'processing' and another from
+ 'processing' to 'stopped'. These two Events have the same name but
+ are different instances of the Event. Then the Printer MUST create a
+ separate Event Notification for each Event and SHOULD accurately
+ report the "printer-state" of the first Event as 'processing' and the
+ second Event as 'stopped'.
+
+ If a Subscription Object contains more than one Subscribed Event, and
+ several Events occur in quick succession each matching a different
+ Subscribed Event in the Subscription Object, the Printer MUST NOT
+ generate a single Event Notification from several of these Events,
+
+
+
+Herriot & Hastings Standards Track [Page 42]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ but MAY combine distinct Event Notifications into a single Compound
+ Event Notification if the Delivery Method supports Compound Event
+ Notifications.
+
+ After the Printer has created the Event Notification, the Printer
+ delivers it via either a:
+
+ Push Delivery Method: The Printer delivers the Event Notification
+ shortly after an Event occurs. For some Push Delivery Methods,
+ the Notification Recipient MUST deliver a response; for others it
+ MUST NOT deliver a response.
+
+ Pull Delivery Method: The Printer saves Event Notifications for
+ some Event Life and expects the Notification Recipient to request
+ Event Notifications. The Printer returns the Event Notifications
+ in a response to such a request.
+
+ If an error that meets the following conditions occurs, the Printer
+ MUST cancel the Subscription Object.
+
+ a) the error occurs during the delivering of an Event Notification
+ generated from Subscription Object S AND
+
+ b) the error would continue to occur every time the Printer delivers
+ an Event Notification generated from Subscription Object S in the
+ future.
+
+ For example, if the address of the "notify-recipient-uri" of
+ Subscription Object A references a non-existent target and the
+ Printer determines this fact, it MUST delete Subscription Object A.
+
+ The next two sections describe the values that a Printer delivers in
+ the content of Machine Consumable and Human Consumable Event
+ Notifications, respectively.
+
+ The tables in the sub-sections of this section contain the following
+ columns:
+
+ a) Source Value: the name of the attribute that supplies the value
+ for the Event Notification. Asterisks in this field refer to a
+ note below the table.
+
+ b) Delivers: if the Printer supports the value (column 1) on the
+ Source Object (column 3) the Delivery Method MUST specify:
+
+ MUST: that the Printer MUST deliver the value.
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 43]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ SHOULD: either that the Printer MUST deliver the value or that
+ the value is incompatible with the Delivery Method.
+
+ MAY: that the Printer MUST, SHOULD, MAY, MUST NOT, SHOULD NOT,
+ or NEED NOT deliver the value. The Delivery Method specifies
+ the level of conformance for the Printer.
+
+ c) Source Object: the object from which the source value comes. If
+ the object is "Event Notification", the Printer fabricates the
+ value when it delivers the Event Notification. See section 8.
+
+9.1. Content of Machine Consumable Event Notifications
+
+ This section defines the attributes that a Delivery Method MUST
+ mention in a Delivery Method Document when specifying the Machine
+ Consumable Event Notification's contents.
+
+ This document does not define the order of attributes in Event
+ Notifications. However, Delivery Method Documents MAY define the
+ order of some or all of the attributes.
+
+ A Delivery Method Document MUST specify additional attributes (if
+ any) that a Printer implementation delivers in a Machine Consumable
+ Event Notification.
+
+ Notification Recipients MUST be able to accept Event Notifications
+ containing attributes they do not recognize. What a Notification
+ Recipient does with an unrecognized attribute is implementation-
+ dependent. Notification Recipients MAY attempt to display
+ unrecognized attributes anyway or MAY ignore them.
+
+ The next three sections define the attributes in Event Notification
+ Contents that are:
+
+ 1. for all Events
+
+ 2. for Job Events only
+
+ 3. for Printer Events only
+
+9.1.1. Event Notification Content Common to All Events
+
+ This section lists the attributes that a Delivery Method Document
+ MUST specify for all Events.
+
+ Table 5 lists potential values in each Event Notification.
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 44]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Table 5 - Attributes in Event Notification Content
+
+ Source Value Delivers Source Object
+
+ notify-subscription-id (integer(1:MAX)) MUST Subscription
+ notify-printer-uri (uri) MUST Subscription
+ notify-subscribed-event (type2 keyword) MUST Event
+ Notification
+ printer-up-time (integer(MIN:MAX)) MUST Printer
+ printer-current-time (dateTime) * MUST Printer
+ notify-sequence-number (integer (0:MAX)) SHOULD Subscription
+ notify-charset (charset) SHOULD Subscription
+ notify-natural-language (naturalLanguage) SHOULD Subscription
+ notify-user-data (octetString(63)) ** SHOULD Subscription
+ notify-text (text) SHOULD Event
+ Notification
+ attributes from the "notify-attributes" MAY Printer
+ attribute ***
+ attributes from the "notify-attributes" MAY Job
+ attribute ***
+ attributes from the "notify-attributes" MAY Subscription
+ attribute ***
+
+ *A Printer MUST deliver this value only if and only if it supports
+ the Printer's "printer-current-time" attribute.
+
+ ** If the Subscription Object does not contain a "notify-user-data"
+ attribute and the Delivery Method Document REQUIRES the Printer to
+ deliver the "notify-user-data" source value in the Event
+ Notification, the Printer MUST deliver an octet-string of length 0.
+
+ *** The last three rows represent additional attributes that a client
+ MAY request via the "notify-attributes" attribute. A Printer MAY
+ support the "notify-attributes" attribute. The Delivery Method MUST
+ say that the Printer MUST, SHOULD, MAY, MUST NOT, SHOULD NOT, or NEED
+ NOT support the "notify-attributes" attribute and specific values of
+ this attribute. The Delivery Method MAY say that support for the
+ "notify-attributes" is conditioned on support of the attribute by the
+ Printer or it MAY say that Printer MUST support the "notify-
+ attributes" attribute if the Printer supports the Delivery Method.
+
+9.1.2. Additional Event Notification Content for Job Events
+
+ This section lists the additional attributes that a Delivery Method
+ Document MUST specify for Job Events. See Table 6.
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 45]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Table 6 - Additional Event Notification Content for Job Events
+
+ Source Value Delivers Source
+ Object
+
+ job-id (integer(1:MAX)) MUST Job
+ job-state (type1 enum) MUST Job
+ job-state-reasons (1setOf type2 keyword) MUST Job
+ job-impressions-completed (integer(0:MAX)) * MUST Job
+
+ * The Printer MUST deliver the "job-impressions-completed" attribute
+ in an Event Notification only for the combinations of Events and
+ Subscribed Events shown in Table 7.
+
+ Table 7 - Combinations of Events and Subscribed Events for "job-
+ impressions-completed"
+
+ Job Event Subscribed Job Event
+
+ 'job-progress' 'job-progress'
+ 'job-completed' 'job-completed'
+ 'job-completed' 'job-state-changed'
+
+9.1.3. Additional Event Notification Content for Printer Events
+
+ This section lists the additional attributes that a Delivery Method
+ Document MUST specify for Printer Events. See Table 8.
+
+ Table 8 - Additional Event Notification Content for Printer Events
+
+ Source Value Delivers Source Object
+
+ printer-state (type1 enum) MUST Printer
+ printer-state-reasons (1setOf type2 MUST Printer
+ keyword)
+ printer-is-accepting-jobs (boolean) MUST Printer
+
+9.2. Content of Human Consumable Event Notification
+
+ This section defines the information that a Delivery Method MUST
+ mention in a Delivery Method Document when specifying the Human
+ Consumable Event Notifications contents or the value of the "notify-
+ text" attribute.
+
+ Such a Delivery Method MUST specify the following information and a
+ Printer SHOULD deliver it:
+
+ a) the Printer name (see Table 9)
+
+
+
+Herriot & Hastings Standards Track [Page 46]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ b) the time of the Event (see Table 11)
+
+ c) for Printer Events only:
+
+ i) the Event (see Table 10) and/or Printer state information (see
+ Table 14)
+
+ d) for Job Events only:
+
+ i) the job identity (see Table 12)
+
+ ii) the Event (see Table 10) and/or Job state information (see
+ Table 13)
+
+ The subsections of this section specify the attributes that a Printer
+ MUST use to obtain this information.
+
+ A Delivery Method Document MUST specify additional information (if
+ any) that a Printer implementation delivers in a Human Consumable
+ Event Notification or in the "notify-text" attribute.
+
+ A client MUST NOT request additional attributes via the "notify-
+ attributes" attribute because this attribute works only for Machine
+ Consumable Event Notifications.
+
+ Notification Recipients MUST NOT expect to be able to parse the Human
+ Consumable Event Notification contents or the value of the "notify-
+ text" attribute.
+
+ The next three sections define the attributes in Event Notification
+ Contents that are:
+
+ a) for all Events
+ b) for Job Events only
+ c) for Printer Events only
+
+9.2.1. Event Notification Content Common to All Events
+
+ This section lists the source of the information that a Delivery
+ Method MUST specify for all Events.
+
+ There is a separate table for each piece of information. Each row in
+ the table represents a source value for the information and the
+ values are listed in order of preference, with the first one being
+ the preferred one. An implementation SHOULD use the source value
+ from the earliest row in each table. It MAY use the source value
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 47]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ from another row instead, or it MAY combine the source values from
+ several rows. An implementation is free to determine the best way to
+ present this information.
+
+ In all tables of this section, all rows contain a "MAY" in order to
+ state that the Delivery Method specifies the conformance.
+
+ Table 9 lists the source of the information for the Printer Name.
+ The "printer-name" is more user-friendly unless the Notification
+ Recipient is in a place where the Printer name is not meaningful.
+ For example, an implementation could have the intelligence to deliver
+ the value of the "printer-name" attribute to a Notification Recipient
+ that can access the Printer via value of the "printer-name" attribute
+ and otherwise deliver the value of the "notify-printer-uri"
+ attribute.
+
+ Table 9 - Printer Name in Event Notification Content
+
+ Source Value Delivers Source Object
+
+ printer-name (name(127)) MAY Printer
+ notify-printer-uri (uri) MAY Subscription
+
+
+ Table 10 lists the source of the information for the Event name. A
+ Printer MAY combine this information with state information described
+ for Jobs in Table 13 or for Printers in Table 14.
+
+ Table 10 - Event Name in Event Notification Content
+
+ Source Value Delivers Source Object
+
+ notify-subscribed-event (type2 keyword) MAY Subscription
+
+ Table 11 lists the source of the information for the time that the
+ Event occurred. A Printer can deliver this value only if it supports
+ the Printer's "printer-current-time" attribute. If a Printer does
+ not support the "printer-current-time" attribute, it MUST NOT deliver
+ the "printer-up-time" value instead, since it is not an allowed
+ option for human consumable information.
+
+ Table 11 - Event Time in Event Notification Content
+
+ Source Value Delivers Source Object
+
+ printer-current-time (dateTime) MAY Printer
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 48]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+9.2.2. Additional Event Notification Content for Job Events
+
+ This section lists the source of the additional information that a
+ Delivery Method MUST specify for Job Events.
+
+ Table 12 lists the source of the information for the job name. The
+ "job-name" is likely more meaningful to a user than "job-id".
+
+ Table 12 - Job Name in Event Notification Content
+
+ Source Value Delivers Source Object
+
+ job-name (name(MAX)) MAY Job
+ job-id (integer(1:MAX)) MAY Job
+
+ Table 13 lists the source of the information for the job state. If a
+ Printer supports the "job-state-message" and "job-detailed-state-
+ message" attributes, it SHOULD use those attributes for the job state
+ information, otherwise, it should fabricate such information from the
+ "job-state" and "job-state-reasons". For some Events, a Printer MAY
+ combine this information with Event information.
+
+ Table 13 - Job State in Event Notification Content
+
+ Source Value Delivers Source
+ Object
+
+ job-state-message (text(MAX)) MAY Job
+ job-detailed-status-messages (1setOf text(MAX)) MAY Job
+ job-state (type1 enum) MAY Job
+ job-state-reasons (1setOf type2 keyword) MAY Job
+
+9.2.3. Additional Event Notification Content for Printer Events
+
+ This section lists the source of the additional information that a
+ Delivery Method MUST specify for Printer Events.
+
+ Table 14 lists the source of the information for the printer state.
+ If a Printer supports the "printer-state-message", it SHOULD use that
+ attribute for the job state information, otherwise it SHOULD
+ fabricate such information from the "printer-state" and "printer-
+ state-reasons". For some Events, a Printer MAY combine this
+ information with Event information.
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 49]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Table 14 - Printer State in Event Notification Content
+
+ Source Value Delivers Source
+ Object
+
+ printer-state-message (text(MAX)) MAY Printer
+ printer-state (type1 enum) MAY Printer
+ printer-state-reasons (1setOf type2 keyword) MAY Printer
+ printer-is-accepting-jobs (boolean) MAY Printer
+
+10. Delivery Methods
+
+ A Delivery Method is the mechanism, i.e., protocol, by which the
+ Printer delivers an Event Notification to a Notification Recipient.
+ There are several potential Delivery Methods for Event Notifications,
+ standardized, as well as proprietary. This specification REQUIRES
+ that the 'ippget' Pull Delivery Method [RFC3996] be supported.
+ Conforming implementations MAY support additional Push or Pull
+ Delivery Methods as well. This document does not define any of these
+ delivery mechanisms. Each Delivery Method MUST be defined in a
+ Delivery Method Document that is separate from this document. New
+ Delivery Methods will be created as needed using an extension to the
+ registration procedures defined in [RFC2911]. Such documents are
+ registered with IANA (see section 23.7.3).
+
+ The following sorts of Delivery Methods are possible:
+
+ - The Notification Recipient polls for Event Notifications at
+ intervals directed by the Printer
+
+ - The Printer delivers Event Notifications to the Notification
+ Recipient using http as the transport.
+
+ - The Printer delivers an email message.
+
+ This section specifies how to define a Delivery Method Document and
+ what to put in such a document.
+
+ A Delivery Method Document MUST contain an exact copy of the
+ following paragraph, caption and table. In addition, column 2 of the
+ table in the Delivery Method Document MUST contain answers to
+ questions in column 1 for the Delivery Method. Also, the Delivery
+ Method document MUST contain a reference to this document and call
+ that reference [RFC3995] because the table contains an [RFC3995]
+ reference.
+
+ If a Printer supports this Delivery Method, the following are its
+ characteristics.
+
+
+
+Herriot & Hastings Standards Track [Page 50]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Table 15 - Information about the Delivery Method
+
+ Document Method Conformance Requirement Delivery Method
+ Realization
+
+ 1. What is the URL scheme name for the Push Delivery Method or the
+ keyword method name for the Pull Delivery Method?
+
+ 2. Is the Delivery Method REQUIRED, RECOMMENDED, or OPTIONAL for an
+ IPP Printer to support?
+
+ 3. What transport and delivery protocols does the Printer use to
+ deliver the Event Notification Content, i.e., what is the entire
+ network stack?
+
+ 4. Can several Event Notifications be combined into a Compound Event
+ Notification?
+
+ 5. Is the Delivery Method initiated by the Notification Recipient
+ (pull), or by the Printer (push)?
+
+ 6. Is the Event Notification content Machine Consumable or Human
+ Consumable?
+
+ 7. What section in this document answers the following question?
+ For a Machine Consumable Event Notification, what is the
+ representation and encoding of values defined in section 9.1 of
+ [RFC3995] and the conformance requirements thereof? For a Human
+ Consumable Event Notification, what is the representation and
+ encoding of pieces of information defined in section 9.2 of
+ [RFC3995] and the conformance requirements thereof?
+
+ 8. What are the latency and reliability of the transport and
+ delivery protocol?
+
+ 9. What are the security aspects of the transport and delivery
+ protocol, e.g., how it is handled in firewalls?
+
+ 10. What are the content length restrictions?
+
+ 11. What are the additional values or pieces of information that a
+ Printer delivers in an Event Notification content and the
+ conformance requirements thereof?
+
+ 12. What are the additional Subscription Template and/or
+ Subscription Description attributes and the conformance
+ requirements thereof?
+
+
+
+
+Herriot & Hastings Standards Track [Page 51]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ 13. What are the additional Printer Description attributes and the
+ conformance requirements thereof?
+
+11. Operations for Notification
+
+ This section defines all of the operations for Notification. Section
+ 7.1 assigns the "operation-id" for each operation. The following two
+ sub-sections define Subscription Creation Operations, and other
+ operations.
+
+11.1. Subscription Creation Operations
+
+ This section defines the Subscription Creation Operations. The first
+ section on Create-Job-Subscriptions gives most of the information.
+ The other Subscription Creation Operations refer to the section on
+ Create-Job-Subscriptions, even though the Create-Job-Subscriptions
+ operation is the only OPTIONAL operation in this document (see
+ section 12).
+
+ A Printer MUST support Create-Printer-Subscriptions and the
+ Subscription Template Attributes Group in Job Creation operations.
+ It MAY support Create-Job-Subscriptions operations.
+
+11.1.1. Create-Job-Subscriptions Operation
+
+ The operation creates one or more Per-Job Subscription Objects. The
+ client supplies one or more Subscription Template Attributes Groups
+ each containing one or more of Subscription Template Attributes
+ (defined in section 5.3).
+
+ Except for errors, the Printer MUST create exactly one Per-Job
+ Subscription Object from each Subscription Template Attributes Group
+ in the request, even if the newly created Subscription Object would
+ have identical behavior to some existing Subscription Object. The
+ Printer MUST associate each newly created Per-Job Subscription Object
+ with the target Job, which is specified by the "notify-job-id"
+ operation attribute.
+
+ The Printer MUST accept the request in any of the target job's 'not-
+ completed' states, i.e., 'pending', 'pending-held', 'processing', or
+ 'processing-stopped'. The Printer MUST NOT change the job's "job-
+ state" attribute because of this operation. If the target job is in
+ any of the 'completed' states, i.e., 'completed', 'canceled', or
+ 'aborted, then the Printer MUST reject the request and return the
+ 'client-error-not-possible' status code; the response MUST NOT
+ contain any Subscription Attribute Groups.
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 52]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Access Rights: To create Per-Job Subscription Objects, the
+ authenticated user (see [RFC2911] section 8.3) performing this
+ operation MUST (1) be the job owner, (2) have Operator or
+ Administrator access rights for this Printer (see [RFC2911] sections
+ 1 and 8.5), or (3) be otherwise authorized by the Printer's
+ administrator-configured security policy to create Per-Job
+ Subscription Objects for the target job. Otherwise the Printer MUST
+ reject the operation and return: the 'client-error-forbidden',
+ 'client-error-not-authenticated', or 'client-error-not-authorized'
+ status code as appropriate.
+
+11.1.1.1. Create-Job-Subscriptions Request
+
+ The following groups of attributes are part of the Create-Job-
+ Subscriptions Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.1.
+
+ Target:
+ The "printer-uri" attribute which defines the target for this
+ operation as described in [RFC2911] section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" attribute SHOULD be supplied by the
+ client as described in [RFC2911] section 8.3.
+
+11.1.1.1.1. notify-job-id (integer(1:MAX))
+
+ The client MUST supply this attribute and it MUST specify the Job
+ object to associate the Per-Job Subscription with. The value of
+ "notify-job-id" MUST be the value of the "job-id" of the associated
+ Job object. If the client does not supply this attribute, the
+ Printer MUST reject this request with a 'client-error-bad-request'
+ status code.
+
+ Group 2-N: Subscription Template Attributes
+
+ For each occurrence of this group:
+
+ The client MUST supply one or more Subscription Template
+ Attributes in any order. See section 5.3 for a description of
+ each such attribute. See section 5.2 for details on processing
+ these attributes.
+
+
+
+
+Herriot & Hastings Standards Track [Page 53]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+11.1.1.2. Create-Job-Subscriptions Response
+
+ The Printer MUST return to the client the following sets of
+ attributes as part of a Create-Job-Subscriptions response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ In addition to the REQUIRED status code returned in every
+ response, the response OPTIONALLY includes a "status-message"
+ (text(255)) and/or a "detailed-status-message" (text(MAX))
+ operation attribute as described in [RFC2911] sections 13 and
+ 3.1.6.
+
+ In this group, the Printer can return any status codes defined in
+ [RFC2911] and section 12. The following is a description of the
+ important status codes:
+
+ successful-ok: the Printer created all Subscription Objects
+ requested (see [RFC2911]).
+
+ successful-ok-ignored-subscriptions: the Printer created some
+ Subscription Objects requested but some failed. The
+ Subscription Attributes Groups with a "notify-status-code"
+ attribute are the ones that failed (see section 12.1).
+
+ client-error-ignored-all-subscriptions: the Printer created no
+ Subscription Objects requested and all failed. The
+ Subscription Attributes Groups with a "notify-status-code"
+ attribute are the ones that failed (see section 12.2).
+
+ client-error-not-possible: For this operation and other Per-Job
+ Subscription operations, this error can occur because the
+ specified Job has already completed (see [RFC2911], whether or
+ not the Job is retained in the Job Retention and/or Job History
+ phases (see [RFC2911] section 4.3.7.1).
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911] section 3.1.7 for details on returning Unsupported
+ Attributes. This group does not contain any unsupported
+ Subscription Template Attributes; they are returned in the
+ Subscription Attributes Group (see below).
+
+
+
+
+Herriot & Hastings Standards Track [Page 54]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Group 3-N: Subscription Attributes
+
+ These groups MUST be returned unless the Printer is unable to
+ interpret the entire request, e.g., the "status-code" parameter
+ returned in Group 1 has the value: 'client-error-bad-request'.
+
+ "notify-status-code" (type2 enum):
+ Indicates the status of this subscription (see section 13 for
+ the status code definitions). Section 5.2 defines when this
+ attribute MUST be present in this group.
+
+ See section 5.2 for details on the contents of each occurrence of
+ this group.
+
+11.1.2. Create-Printer-Subscriptions operation
+
+ The operation is identical to Create-Job-Subscriptions with
+ exceptions noted in this section.
+
+ The operation creates Per-Printer Subscription Objects instead of
+ Per-Job Subscription Objects, and associates each newly created Per-
+ Printer Subscription Object with the Printer specified by the
+ operation target rather than with a specific Job.
+
+ The Printer MUST accept the request in any of its states, i.e.,
+ 'idle', 'processing', or 'stopped'. The Printer MUST NOT change its
+ "printer-state" attribute because of this operation.
+
+ Access Rights: To create Per-Printer Subscription Objects, the
+ authenticated user (see [RFC2911] section 8.3) performing this
+ operation MUST have (1) Operator or Administrator access rights for
+ this Printer (see [RFC2911] sections 1 and 8.5), or (2) be otherwise
+ authorized by the Printer's administrator-configured security policy
+ to create Per-Printer Subscription Objects for this Printer.
+ Otherwise, the Printer MUST reject the operation and return: the
+ 'client-error-forbidden', 'client-error-not-authenticated', or
+ 'client-error-not-authorized' status code as appropriate.
+
+11.1.2.1. Create-Printer-Subscriptions Request
+
+ The groups are identical to the Create-Job-Subscriptions (see section
+ 11.1.1.1) except that the Operation Attributes group MUST NOT contain
+ the "notify-job-id" attribute. If the client does supply the
+ "notify-job-id" attribute, then the Printer MUST treat it as any
+ other unsupported Operation attribute and MUST return it in the
+ Unsupported Attributes group.
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 55]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+11.1.2.2. Create-Printer-Subscriptions Response
+
+ The groups are identical to the Create-Job-Subscriptions (see section
+ 11.1.1.2).
+
+11.1.3. Job Creation Operations - Extensions for Notification
+
+ This document extends the Job Creation operations (see section 3.2)
+ to create Subscription Objects as a part of the operation.
+
+ The Job Creation operations are identical to Create-Job-Subscriptions
+ operation with exceptions noted in this section.
+
+ Unlike the Create-Job-Subscriptions operation, a Job Creation
+ operation associates the newly created Subscription Objects with the
+ Job object created by this operation. The operation succeeds if and
+ only if the Job creation succeeds. If the Printer does not create
+ some or all of the requested Subscription Objects, the Printer MUST
+ return a 'successful-ok-ignored-subscriptions' status-code instead
+ of a 'successful-ok' status-code, but the Printer MUST NOT reject the
+ operation because of a failure to create Subscription Objects.
+
+ If the Job Creation operation includes a Job Template group, the
+ client MUST supply it after the Operation Attributes group and before
+ the first Subscription Template Attributes Group.
+
+ If a Printer does not support this Notification specification, then
+ it MUST treat the Subscription Attributes Group like an unknown group
+ and ignore it (see [RFC2911] section 5.2.2). Because the Printer
+ ignores the Subscription Attributes Group, it doesn't return them in
+ the response either, thus indicating to the client that the Printer
+ doesn't support Notification.
+
+ After completion of a successful Job Creation operation, the Printer
+ generates a 'job-created' event (see section 5.3.3.4.3).
+
+ Access Rights: To create Per-Job Subscription Objects, the
+ authenticated user (see [RFC2911] section 8.3) performing this
+ operation MUST either have permission to create Jobs on the Printer
+ or have Operator or Administrator access rights for this Printer (see
+ [RFC2911] sections 1 and 8.5). Otherwise the Printer MUST reject the
+ operation and return: the 'client-error-forbidden', 'client-error-
+ not-authenticated', or 'client-error-not-authorized' status code as
+ appropriate.
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 56]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+11.1.3.1. Job Creation Request
+
+ The groups for this operation are sufficiently different from the
+ Create-Job-Subscriptions operation that they are all presented here.
+ The following groups of attributes are supplied as part of a Job
+ Creation Request:
+
+ Group 1: Operation Attributes
+
+ Same as defined in [RFC2911] for Print-Job, Print-URI, and
+ Create-Job requests.
+
+ Group 2: Job Template Attributes
+
+ The client OPTIONALLY supplies a set of Job Template attributes as
+ defined in [RFC2911] section 4.2.
+
+ Group 3 to N: Subscription Template Attributes
+
+ The same as Group 2-N in Create-Job-Subscriptions. See section
+ 11.1.1.1.
+
+ Group N+1: Document Content (Print-Job only)
+
+ The client MUST supply the document data to be processed.
+
+11.1.3.2. Job Creation Response
+
+ The Printer MUST return to the client the following sets of
+ attributes as part of a Print-Job, Print-URI, and Create-Job
+ Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+
+ As defined in [RFC2911] for Print-Job, Print-URI, and Create-
+ Job requests.
+
+ In this group, the Printer can return any status codes defined
+ in [RFC2911] and section 12. The following is a description of
+ the important status codes:
+
+ successful-ok: the Printer created the Job and all
+ Subscription Objects requested (see [RFC2911].
+
+ successful-ok-ignored-subscriptions: the Printer created
+ the Job and not all of the Subscription Objects requested
+
+
+
+Herriot & Hastings Standards Track [Page 57]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ (see section 12.1). This status-code hides 'successful-ok-
+ xxx' status-codes that could reveal problems in Job
+ creation. The Printer MUST NOT return the 'client-error-
+ ignored-all-subscriptions' status code for Job Creation
+ operations because the Printer returns an error status-code
+ only when it fails to create a Job.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911] section 3.1.7 for details on returning Unsupported
+ Attributes. This group does not contain any unsupported
+ Subscription Template Attributes; they are returned in the
+ Subscription Attributes Group (see below).
+
+ Group 3: Job Object Attributes
+
+ The "job-id" of the Job Object just created, etc., as defined in
+ [RFC2911] for Print-Job, Print-URI, and Create-Job requests.
+
+ Group 4 to N: Subscription Attributes
+
+ These groups MUST be returned if and only if the client supplied
+ Subscription Template Attributes and the operation was accepted.
+
+ See section 5.2 for details on the contents of each occurrence of
+ this group.
+
+11.2. Other Operations
+
+ This section defines other operations on Subscription objects.
+
+11.2.1. Restart-Job Operation - Extensions for Notification
+
+ The Restart-Job operation [RFC2911] is neither a Job Creation
+ operation nor a Subscription Creation operation (see section 3.2).
+
+ For the Restart-Job operation, the client MUST NOT supply any Job
+ Subscription Attributes Groups. The Printer MUST treat any supplied
+ Job Subscription Attributes as unsupported attributes.
+
+ For this operation, the Printer does not return a job-id or any
+ Subscription Attributes groups because the Printer reuses the
+ existing Job object with the same job-id and the existing Per-Job
+ Subscription Objects with the same subscription-ids. However, after
+
+
+
+Herriot & Hastings Standards Track [Page 58]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ successful completion of this operation, the Printer generates a
+ 'job-created' event (see section 5.3.3.4.3).
+
+11.2.2. Validate-Job Operation - Extensions for Notification
+
+ A client can test whether one or more Subscription Objects could be
+ created using the Validate-Job operation. The client supplies one or
+ more Subscription Template Attributes Groups (defined in section
+ 5.3), just as in a Job Creation request.
+
+ A Printer MUST support this extension to this operation.
+
+ The Printer MUST accept requests that are identical to the Job
+ Creation request defined in section 11.1.3.1, except that the request
+ MUST NOT contain document data.
+
+ The Printer MUST return the same groups and attributes as the Print-
+ Job operation (section 11.1.3.1) with the following exceptions. The
+ Printer MUST NOT return a Job Object Attributes Group because no Job
+ is created. The Printer MUST NOT return the "notify-subscription-id"
+ attribute in any Subscription Attribute Group because no Subscription
+ Object is created.
+
+ If the Printer would succeed in creating a Subscription Object, the
+ corresponding Subscription Attributes Group either has no 'status-
+ code' attribute or a 'status-code' attribute with a value of
+ 'successful-ok-too-many-events' or 'successful-ok-ignored-or-
+ substituted-attributes' (see sections 5.2 and 13). The status-codes
+ have the same meaning as in Job Creation except the results state
+ what "would happen".
+
+ The Printer MUST validate Subscription Template Attributes Groups in
+ the same manner as the Job Creation operations.
+
+11.2.3. Get-Printer-Attributes - Extensions for Notification
+
+ This operation is extended so that it returns Printer attributes
+ defined in this document.
+
+ A Printer MUST support this extension to this operation.
+
+ In addition to the requirements of [RFC2911] section 3.2.5, a Printer
+ MUST support the following additional values for the "requested-
+ attributes" Operation attribute in this operation and return such
+ attributes in the Printer Object Attributes group of its response.
+
+ 1. Subscription Template Attributes: Each supported attribute in
+ column 2 of Table 1.
+
+
+
+Herriot & Hastings Standards Track [Page 59]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ 2. New Printer Description Attributes: Each supported attribute in
+ section 6.
+
+ 3. New Group Name: The 'subscription-template' group name, which
+ names all supported Subscription Template Attribute in column 2 of
+ Table 1. This group name is also used in the Get-Subscription-
+ Attributes and Get-Subscriptions operation with an analogous
+ meaning.
+
+ 4. Extended Group Name: The 'all' group name, which names all Printer
+ attributes according to [RFC2911] section 3.2.5. In this
+ extension 'all' names all attributes specified in [RFC2911] plus
+ those named in items 1 and 2 of this list.
+
+11.2.4. Get-Subscription-Attributes operation
+
+ This operation allows a client to request the values of the
+ attributes of a Subscription Object.
+
+ A Printer MUST support this operation.
+
+ This operation is almost identical to the Get-Job-Attributes
+ operation (see [RFC2911] section 3.3.4). The only differences are
+ that the operation is directed at a Subscription Object rather than a
+ Job object, and the returned attribute group contains Subscription
+ Object attributes rather than Job object attributes.
+
+ Access Rights: The authenticated user (see [RFC2911] section 8.3)
+ performing this operation MUST (1) be the Subscription Object owner,
+ (2) have Operator or Administrator access rights for this Printer
+ (see [RFC2911] sections 1 and 8.5), or (3) be otherwise authorized by
+ the Printer's administrator-configured security policy to query the
+ Subscription Object for the target job. Otherwise the Printer MUST
+ reject the operation and return: the 'client-error-forbidden',
+ 'client-error-not-authenticated', or 'client-error-not-authorized'
+ status code as appropriate. Furthermore, the Printer's security
+ policy MAY limit which attributes are returned, in a manner similar
+ to the Get-Job-Attributes operation (see [RFC2911] end of section
+ 3.3.4.2).
+
+11.2.4.1. Get-Subscription-Attributes Request
+
+ The following groups of attributes are part of the Get-Subscription-
+ Attributes request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+
+
+
+Herriot & Hastings Standards Track [Page 60]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section [RFC2911] 3.1.4.1.
+
+ Target:
+ The "printer-uri" attribute which defines the target for this
+ operation as described in [RFC2911] section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" attribute SHOULD be supplied by the
+ client as described in [RFC2911] section 8.3.
+
+11.2.4.1.1. "notify-subscription-id" (integer (1:MAX))
+
+ The client MUST supply this attribute. The Printer MUST support this
+ attribute. This attribute specifies the Subscription Object from
+ which the client is requesting attributes. If the client omits this
+ attribute, the Printer MUST reject this request with the 'client-
+ error-bad-request' status code.
+
+11.2.4.1.2. "requested-attributes" (1setOf keyword)
+
+ The client OPTIONALLY supplies this attribute. The Printer MUST
+ support this attribute. This attribute specifies the attributes of
+ the specified Subscription Object that the Printer MUST return in the
+ response. Each value of this attribute is either an attribute name
+ (defined in sections 5.3 and 5.4) or an attribute group name. The
+ attribute group names are:
+
+ - 'subscription-template': all attributes that are both defined in
+ section 5.3 and present on the specified Subscription Object
+ (column 1 of Table 1).
+
+ - 'subscription-description': all attributes that are both defined
+ in section 5.4 and present on the specified Subscription Object
+ (Table 2).
+
+ - 'all': all attributes that are present on the specified
+ Subscription Object.
+
+ A Printer MUST support all these group names.
+
+ If the client omits this attribute, the Printer MUST respond as if
+ this attribute had been supplied with a value of 'all'.
+
+11.2.4.2. Get-Subscription-Attributes Response
+
+ The Printer returns the following sets of attributes as part of the
+ Get-Subscription-Attributes Response:
+
+
+
+Herriot & Hastings Standards Track [Page 61]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ Same as [RFC2911].
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2. The
+ "attributes-natural-language" MAY be the natural language of the
+ Subscription Object, rather than the one requested.
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911] section 3.1.7 and section 3.2.5.2 for details on
+ returning Unsupported Attributes.
+
+ The response NEED NOT contain the "requested-attributes" operation
+ attribute with any supplied keyword values that were requested by
+ the client but are not supported by the IPP object. If the
+ Printer object does return unsupported attributes referenced in
+ the "requested-attributes" operation attribute, the values of the
+ "requested-attributes" attribute returned MUST include only the
+ unsupported keywords that were requested by the client. If the
+ client had requested a group name, such as 'all', the resulting
+ unsupported attributes returned MUST NOT include attribute keyword
+ names described in the standard but not supported by the
+ implementation.
+
+ Group 3: Subscription Attributes
+
+ This group contains a set of attributes with their current values.
+ Each attribute returned in this group:
+
+ a) MUST be specified by the "requested-attributes" attribute in the
+ request, AND
+
+ b) MUST be present on the specified Subscription Object AND
+
+ c) MUST NOT be restricted by the security policy in force. For
+ example, a Printer MAY prohibit a client who is not the creator of
+ a Subscription Object from seeing some or all of its attributes.
+ See [RFC2911] end of section 3.3.4.2 and section 8.
+
+ The Printer can return the attributes of the Subscription Object
+ in any order. The client MUST accept the attributes in any order.
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 62]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+11.2.5. Get-Subscriptions operation
+
+ This operation allows a client to retrieve the values of attributes
+ of all Subscription Objects belonging to a Job or Printer.
+
+ A Printer MUST supported this operation.
+
+ This operation is similar to the Get-Subscription-Attributes
+ operation, except that this Get-Subscriptions operation returns
+ attributes from possibly more than one object.
+
+ This operation is similar to the Get-Jobs operation (see [RFC2911]
+ section 3.2.6), except that the operation returns Subscription
+ Objects rather than Job objects.
+
+ Access Rights: To query Per-Job Subscription Objects of the
+ specified job (client supplied the "notify-job-id" operation
+ attribute - see section 11.2.5.1.1), the authenticated user (see
+ [RFC2911] section 8.3) performing this operation MUST (1) be the
+ Subscription Object owner, (2) have Operator or Administrator access
+ rights for this Printer (see [RFC2911] sections 1 and 8.5), or (3) be
+ otherwise authorized by the Printer's administrator-configured
+ security policy to query the Subscription Object for the target job.
+ To query Per-Printer Subscription Objects of the Printer (client
+ omits the "notify-job-id" operation attribute - see section
+ 11.2.5.1.1), the authenticated user (see [RFC2911] section 8.3)
+ performing this operation MUST (1) have Operator or Administrator
+ access rights for this Printer (see [RFC2911] sections 1 and 8.5), or
+ (2) be otherwise authorized by the Printer's administrator-configured
+ security policy to query Per-Printer Subscription Objects for the
+ target Printer. Otherwise the Printer MUST reject the operation and
+ return: the 'client-error-forbidden', 'client-error-not-
+ authenticated', or 'client-error-not-authorized' status code as
+ appropriate. Furthermore, the Printer's security policy MAY limit
+ which attributes are returned, in a manner similar to the Get-Jobs
+ and Get-Printer-Attributes operations (see [RFC2911] end of sections
+ 3.2.6.2 and 3.2.5.2).
+
+11.2.5.1. Get-Subscriptions Request
+
+ The following groups of attributes are part of the Get-Subscriptions
+ request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.1.
+
+
+
+Herriot & Hastings Standards Track [Page 63]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Target:
+ The "printer-uri" attribute which defines the target for this
+ operation as described in [RFC2911] section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" attribute SHOULD be supplied by the
+ client as described in [RFC2911] section 8.3.
+
+11.2.5.1.1. "notify-job-id" (integer(1:MAX))
+
+ If the client specifies this attribute, the Printer returns the
+ specified attributes of all Per-Job Subscription Objects associated
+ with the Job whose "job-id" attribute value equals the value of this
+ attribute. If the client does not specify this attribute, the
+ Printer returns the specified attributes of all Per-Printer
+ Subscription Objects. Note: there is no way to get all Per-Job
+
+ Subscriptions known to the Printer in a single operation. A Get-Jobs
+ operation followed by a Get-Subscriptions operation for each Job will
+ return all Per-Job Subscriptions.
+
+11.2.5.1.2. "limit" (integer(1:MAX))
+
+ The client OPTIONALLY supplies this attribute. The Printer MUST
+ support this attribute. It is an integer value that determines the
+ maximum number of Subscription Objects that a client will receive
+ from the Printer even if the "my-subscriptions" attribute constrains
+ which Subscription Objects are returned. The limit is a "stateless
+ limit" in that if the value supplied by the client is 'N', then only
+ the first 'N' Subscription Objects are returned in the Get-
+ Subscriptions Response. There is no mechanism to allow for the next
+ 'M' Subscription Objects after the first 'N' Subscription Objects.
+ If the client does not supply this attribute, the Printer responds
+ with all applicable Subscription Objects.
+
+11.2.5.1.3. "requested-attributes" (1setOf type2 keyword)
+
+ The client OPTIONALLY supplies this attribute. The Printer MUST
+ support this attribute. This attribute specifies the attributes of
+ the specified Subscription Objects that the Printer MUST return in
+ the response. Each value of this attribute is either an attribute
+ name (defined in sections 5.3 and 5.4) or an attribute group name
+ (defined in section 11.2.4.1). If the client omits this attribute,
+ the Printer MUST respond as if the client had supplied this attribute
+ with the one value: 'notify-subscription-id'.
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 64]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+11.2.5.1.4. "my-subscriptions" (boolean)
+
+ The client OPTIONALLY supplies this attribute. The Printer MUST
+ support this attribute. If the value is 'false', the Printer MUST
+ consider the Subscription Objects from all users as candidates. If
+ the value is 'true', the Printer MUST return the Subscription Objects
+ created by the requesting user of this request. If the client does
+ not supply this attribute, the Printer MUST respond as if the client
+ had supplied the attribute with a value of 'false'. The means for
+ authenticating the requesting user and matching the Subscription
+ Objects is similar to that for Jobs which is described in [RFC2911]
+ section 8.
+
+11.2.5.2 Get-Subscriptions Response
+
+ The Printer returns the following sets of attributes as part of the
+ Get-Subscriptions Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ Same as [RFC2911].
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2.
+
+ Group 2: Unsupported Attributes
+
+ Same as for Get-Subscription-Attributes.
+
+ Groups 3 to N: Subscription Attributes
+
+ The Printer responds with one Subscription Attributes Group for
+ each requested Subscription Object (see the "notify-job-id"
+ attribute in the Operation Attributes Group of this operation).
+
+ The Printer returns Subscription Objects in any order.
+
+ If the "limit" attribute is present in the Operation Attributes
+ group of the request, the number of Subscription Attributes Groups
+ in the response MUST NOT exceed the value of the "limit"
+ attribute.
+
+ It there are no Subscription Objects associated with the specified
+ Job or Printer, the Printer MUST return zero Subscription
+ Attributes Groups and it MUST NOT treat this case as an error,
+
+
+
+
+Herriot & Hastings Standards Track [Page 65]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ i.e., the status-code MUST be 'successful-ok' unless something
+ else causes the status code to have some other value.
+
+ See the Group 3 response (Subscription Attributes Group) of the
+ Get-Subscription-Attributes operation (section 11.2.4.2) for the
+ attributes that a Printer returns in this group.
+
+11.2.6. Renew-Subscription operation
+
+ This operation allows a client to request the Printer to extend the
+ lease on a Per-Printer Subscription Object.
+
+ The Printer MUST support this operation.
+
+ The Printer MUST accept this request for a Per-Printer Subscription
+ Object in any of the target Printer's states, i.e., 'idle',
+ 'processing', or 'stopped', but MUST NOT change the Printer's
+ "printer-state" attribute.
+
+ The Printer MUST reject this request for a Per-Job Subscription
+ Object because it has no lease (see section 5.4.3). The status code
+ returned MUST be 'client-error-not-possible'.
+
+ Access Rights: The authenticated user (see [RFC2911] section 8.3)
+ performing this operation MUST (1) be the owner of the Per-Printer
+ Subscription Object, (2) have Operator or Administrator access rights
+ for the Printer (see [RFC2911] sections 1 and 8.5), or (3) be
+ otherwise authorized by the Printer's administrator-configured
+ security policy to renew Per-Printer Subscription Objects for the
+ target Printer. Otherwise, the Printer MUST reject the operation and
+ return: the 'client-error-forbidden', 'client-error-not-
+ authenticated', or 'client-error-not-authorized' status code as
+ appropriate.
+
+11.2.6.1. Renew-Subscription Request
+
+ The following groups of attributes are part of the Renew-Subscription
+ Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.1.
+
+ Target:
+ The "printer-uri" attribute which defines the target for this
+ operation as described in [RFC2911] section 3.1.5.
+
+
+
+Herriot & Hastings Standards Track [Page 66]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in [RFC2911] section 8.3.
+
+11.2.6.1.1. "notify-subscription-id" (integer (1:MAX))
+
+ The client MUST supply this attribute. The Printer MUST support this
+ attribute. This attribute specifies the Per-Printer Subscription
+ Object whose lease the Printer MUST renew. If the client omits this
+ attribute, the Printer MUST reject this request with the 'client-
+ error-bad-request' status code.
+
+ Group 2: Subscription Template Attributes
+
+11.2.6.1.2. "notify-lease-duration" (integer(0:MAX))
+
+ The client MAY supply this attribute. It indicates the number of
+ seconds to renew the lease for the specified Subscription Object. A
+ value of 0 requests an infinite lease (which MAY require Operator
+ access rights). If the client omits this attribute, the Printer MUST
+ use the value of the Printer's "notify-lease-duration-default"
+ attribute. See section 5.3.8 for more details.
+
+11.2.6.2. Renew-Subscription Response
+
+ The Printer returns the following sets of attributes as part of the
+ Renew-Subscription Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ Same as [RFC2911].
+
+ The following are some of the status codes returned (see
+ [RFC2911]:
+
+ successful-ok: The operation successfully renewed the lease
+ on the Subscription Object for the requested duration.
+
+ successful-ok-ignored-or-substituted-attributes: The
+ operation successfully renewed the lease on the Subscription
+ Object for some duration other than the amount requested.
+
+ client-error-not-possible: The operation failed because the
+ "notify-subscription-id" Operation attribute identified a
+ Per-Job Subscription Object.
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 67]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ client-error-not-found: The operation failed because the
+ "notify-subscription-id" Operation attribute identified a
+ non-existent Subscription Object.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2. The
+ "attributes-natural-language" MAY be the natural language of the
+ Subscription Object, rather than the one requested.
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911] section 3.1.7 for details on returning Unsupported
+ Attributes.
+
+ Group 3: Subscription Attributes
+
+ The Printer MUST return the following Subscription Attribute:
+
+11.2.6.2.1. "notify-lease-duration" (integer(0:MAX))
+
+ The value of this attribute MUST be the number of seconds that the
+ Printer has granted for the lease of the Subscription Object (see
+ section 5.3.8 for details, such as the value of this attribute when
+ the Printer doesn't support the requested value).
+
+11.2.7. Cancel-Subscription operation
+
+ This operation allows a client to delete a Subscription Object and
+ stop the Printer from delivering more Event Notifications. Once
+ performed, there is no way to reference the Subscription Object.
+
+ A Printer MUST supported this operation.
+
+ The Printer MUST accept this request in any of the target Printer's
+ states, i.e., 'idle', 'processing', or 'stopped', but MUST NOT change
+ the Printer's "printer-state" attribute.
+
+ If the specified Subscription Object is a Per-Job Subscription
+ Object, the Printer MUST accept this request in any of the target
+ Job's states, but MUST NOT change the Job's "job-state" attribute or
+ affect the Job.
+
+ Note: There is no way to change any attributes on a Subscription
+ Object, except the "notify-lease-duration" attribute (using the
+ Renew-Subscription operation). In order to change other attributes,
+ a client performs a Subscription Creation Operation and Cancel-
+ Subscription operation on the old Subscription Object. If the client
+
+
+
+Herriot & Hastings Standards Track [Page 68]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ wants to avoid missing Event Notifications, it performs the
+ Subscription Creation Operation first. If this order would create
+ too many Subscription Objects on the Printer, the client reverses the
+ order.
+
+ Access Rights: The authenticated user (see [RFC2911] section 8.3)
+ performing this operation MUST (1) be the owner of the Subscription
+ Object, (2) have Operator or Administrator access rights for the
+ Printer (see [RFC2911] sections 1 and 8.5), or (3) be otherwise
+ authorized by the Printer's administrator-configured security policy
+ to cancel the target Subscription Object. Otherwise, the Printer
+ MUST reject the operation and return: the 'client-error-forbidden',
+ 'client-error-not-authenticated', or 'client-error-not-authorized'
+ status code as appropriate.
+
+11.2.7.1. Cancel-Subscription Request
+
+ The following groups of attributes are part of the Cancel-
+ Subscription Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.1.
+
+ Target:
+ The "printer-uri" attribute which defines the target for this
+ operation as described in [RFC2911] section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" attribute SHOULD be supplied by the
+ client as described in [RFC2911] section 8.3.
+
+11.2.7.1.1. "notify-subscription-id" (integer (1:MAX))
+
+ The client MUST supply this attribute. The Printer MUST support this
+ attribute. This attribute specifies the Subscription Object that the
+ Printer MUST cancel. If the client omits this attribute, the Printer
+ MUST reject this request with the 'client-error-bad-request' status
+ code.
+
+
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 69]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+11.2.7.2. Cancel-Subscription Response
+
+ The Printer returns the following sets of attributes as part of the
+ Cancel-Subscription Response:
+
+ Group 1: Operation Attributes
+
+ Status Message:
+ Same as [RFC2911].
+
+ The following are some of the status codes returned (see
+ [RFC2911]:
+
+ successful-ok: The operation successfully canceled
+ (deleted) the Subscription Object.
+
+ client-error-not-found: The operation failed because the
+ "notify-subscription-id" Operation attribute identified a
+ non-existent Subscription Object.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes as described in [RFC2911] section 3.1.4.2. The
+ "attributes-natural-language" MAY be the natural language of the
+ Subscription Object, rather than the one requested.
+
+ Group 2: Unsupported Attributes
+
+ See [RFC2911] section 3.1.7 for details on returning Unsupported
+ Attributes.
+
+12. Status Codes
+
+ The following status codes are defined as extensions for Notification
+ and are returned as the value of the "status-code" parameter in the
+ Operation Attributes Group of a response (see [RFC2911] section
+ 3.1.6.1). Operations in this document can also return the status
+ codes defined in section 13 of [RFC2911]. The 'successful-ok' status
+ code is an example of such a status code.
+
+12.1. successful-ok-ignored-subscriptions (0x0003)
+
+ The Subscription Creation Operation was unable to create all
+ requested Subscription Objects.
+
+ For a Create-Job-Subscriptions or Create-Printer-Subscriptions
+ operation, this status code means that the Printer created one or
+
+
+
+
+Herriot & Hastings Standards Track [Page 70]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ more Subscription Objects, but not all requested Subscription
+ Objects.
+
+ For a Job Creation operation, this status code means that the Printer
+ created the Job along with zero or more Subscription Objects. The
+ Printer returns this status code even if other job attributes are
+ unsupported or in conflict. That is, if an IPP Printer finds a
+ warning that would allow it to return 'successful-ok-ignored-
+ subscriptions' and either 'successful-ok-ignored-or-substituted-
+ attributes' and/or 'successful-ok-conflicting-attributes', it MUST
+ return 'successful-ok-ignored-subscriptions'.
+
+12.2. client-error-ignored-all-subscriptions (0x0414)
+
+ This status code is the same as 'successful-ok-ignored-subscriptions'
+ except that only the Create-Job-Subscriptions and Create-Printer-
+ Subscriptions operation return it. They return this status code only
+ when the Printer creates zero Subscription Objects.
+
+13. Status Codes in Subscription Attributes Groups
+
+ This section contains values of the "notify-status-code" (type2 enum)
+ attribute that the Printer returns in a Subscription Attributes Group
+ in a response when the corresponding Subscription Object:
+
+ 1. is not created or
+
+ 2. is created and some of the client-supplied attributes are not
+ supported.
+
+ The following sections are ordered in decreasing order of importance
+ of the status-codes.
+
+13.1. client-error-uri-scheme-not-supported (0x040C)
+
+ This status code is defined in [RFC2911]. This document extends its
+ meaning and allows it to be in a Subscription Attributes Group of a
+ response.
+
+ The scheme of the client-supplied URI in a "notify-recipient-uri"
+ Subscription Template Attribute in a Subscription Creation Operation
+ is not supported. See section 5.3.1.
+
+13.2. client-error-attributes-or-values-not-supported (0x040B)
+
+ This status code is defined in [RFC2911]. This document extends its
+ meaning and allows it to be in a Subscription Attributes Group of a
+ response.
+
+
+
+Herriot & Hastings Standards Track [Page 71]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ The method of the client-supplied keyword in a "notify-pull-method"
+ Subscription Template Attribute in a Subscription Creation Operation
+ is not supported. See section 5.3.2.
+
+13.3. client-error-too-many-subscriptions (0x0415)
+
+ The number of Subscription Objects supported by the Printer would be
+ exceeded if this Subscription Object were created (see section 5.2).
+
+13.4. successful-ok-too-many-events (0x0005)
+
+ The client supplied more Events in the "notify-events" operation
+ attribute of a Subscription Creation Operation than the Printer
+ supports, as indicated in its "notify-max-events-supported" Printer
+ attribute (see section 5.3.3).
+
+13.5. successful-ok-ignored-or-substituted-attributes (0x0001)
+
+ This status code is defined in [RFC2911]. This document extends its
+ meaning to include unsupported Subscription Template Attributes and
+ it can appear in a Subscription Attributes Group.
+
+14. Encodings of Additional Attribute Tags
+
+ This section assigns values to two attributes tags as extensions to
+ the encoding defined in [RFC2910]).
+
+ The "subscription-attributes-tag" delimits Subscription Template
+ Attributes Groups in requests and Subscription Attributes Groups in
+ responses.
+
+ The "event-notification-attributes-tag" delimits Event Notifications
+ in Delivery Methods that use an IPP-like encoding.
+
+ The following table specifies the values for the delimiter tags:
+
+ Tag Value (Hex) Meaning
+
+ 0x06 "subscription-attributes-tag"
+ 0x07 "event-notification-attributes-tag"
+
+15. Conformance Requirements
+
+ It is OPTIONAL for IPP clients and Printers to implement this Event
+ Notification specification.
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 72]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+15.1. Conformance requirements for clients
+
+ If this Event Notification specification is implemented by a client,
+ the client MUST support the 'ippget' Pull Delivery Method and meet
+ the conformance requirements as defined in [RFC3996] for clients. A
+ client MAY support additional Delivery Methods.
+
+15.2. Conformance requirements for Printers
+
+ If this Event Notification specification is implemented by a Printer,
+ the Printer MUST:
+
+ - meet the Conformance Requirements detailed in section 5 of
+ [RFC2911].
+
+ - support the Subscription Template Attributes Group in requests and
+ the Subscription Attributes Group in responses.
+
+ - support all of the following attributes:
+
+ a. REQUIRED Subscription Object attributes in section 5.
+ b. REQUIRED Printer Description object attributes in section 6.
+ c. REQUIRED attributes in Event Notification content in section 8.
+
+ - support the 'ippget' Pull Delivery Method and meet the conformance
+ requirements as defined in [RFC3996] for Printers. The Printer
+ MAY support additional Push and Pull Delivery Methods.
+
+ - deliver Event Notifications that conform to the requirements of
+ section 9 and the requirements of the Delivery Method Document for
+ each supported Delivery Method (the conformance requirements for
+ Delivery Method Documents is specified in section 10).
+
+ - for all of the Job Creation Operations that the Printer supports,
+ MUST support the REQUIRED extensions for notification defined in
+ section 11.1.3.
+
+ - meet the conformance requirements for operations as described in
+ Table 16 and meet the requirements for Printers as specified in
+ the indicated sub-sections of section 11:
+
+
+
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 73]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Table 16 - Printer Conformance Requirements for Operations
+
+ Operation Printer
+ Conformance
+ Requirements
+
+ Create-Printer-Subscriptions (section 11.1.2) REQUIRED
+ Create-Job-Subscriptions (section 11.1.1) OPTIONAL
+ Get-Subscription-Attributes (section 11.2.3) REQUIRED
+ Get-Subscriptions (section 11.2.5) REQUIRED
+ Renew-Subscription (section 11.2.6) REQUIRED
+ Cancel-Subscription (section 11.2.7) REQUIRED
+
+16. Model for Notification with Cascading Printers (Informative)
+
+ With this model (see Figure 2 below), there is an intervening Print
+ server between the human user and the output-device. So the system
+ effectively has two Printer objects. There are two cases to
+ consider.
+
+ 1. When the Printer 1 (in the server) generates Events, the system
+ behaves like the client and Printer in Figure 1. In this case,
+ Printer 1 delivers Event Notifications that are shown as Event
+ Notifications (A) of Figure 2.
+
+ 2. When the Printer 2 (in the output-device) generates Events, there
+ are two possible system configurations:
+
+ a) Printer 1 forwards the client-supplied Subscription Creation
+ Operations to the downstream Printer 2 and lets Printer 2
+ deliver the Event Notifications directly to the Notification
+ Recipients supplied by the Client (Event Notifications(C) in
+ the diagram).
+
+ b) Printer 1 performs the client-supplied Subscription Creation
+ Operations and also forwards the Subscription Creation
+ Operations to Printer 2 with the Notification Recipient changed
+ to be the Printer 1. When an Event occurs in Printer 2,
+ Printer 2 delivers the Event Notification (B) to Notification
+ Recipient of Printer 1, which relays the received Event
+ Notification (B) to the client-supplied Notification Recipient
+ (as Event Notifications(A) in the diagram). Note, when a
+ client performs a Subscription Creation Operation, Printer 1
+ need not forward the Subscription Creation Operation to Printer
+ 2 if it would create a duplicate Subscription Object on Printer
+ 2.
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 74]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Note: when Printer 1 is forwarding Subscription Creation Operations
+ to Printer 2, it may request Printer 2 to create additional
+ Subscription Objects (called "piggy-backing"). Piggy-backing is
+ useful when:
+
+ - Device A is configured to accept (IPP or non-IPP) requests from
+ other servers.
+
+ - Server S wants to receive Job Events that the client didn't
+ request and Server S wants these Events for jobs it submits and
+ not for other jobs.
+
+ server S device A
+ +------------+ +------------+
+ | | | |
+ +--------+ Subscription | ###########| | ###########|
+ | client |--Creation ----># Printer #| Subscription | # Printer #|
+ +--------+ Operation | # Object 1#|---Creation------|># Object 2#|
+ | ###|#######| Operation | ####|#|####|
+ +----|---^---+ +-----|-|----+
+ +--------+ Event | | | |
+ |Notific-|<-Notifications(A)-+ +-- Event Notifications(B)--+ |
+ |ation Re|<-------------Event Notifications(C)-----------------+
+ |cipient |
+ +--------+
+
+ Figure 2 - Model for Notification with Cascading Printers
+
+17. Distributed Model for Notification (Informative)
+
+ A Printer implementation could use some other remote notification
+ server to provide some or most of the service. For example, the
+ remote notification server could deliver Event Notifications using
+ Delivery Methods that are not directly supported by the output device
+ or Printer object. Or, the remote notification server could store
+ Subscription Objects (passed to it from the output device in response
+ to Subscription Creation requests), accept Events, format the Event
+ Notification in the natural language of the Notification Recipient,
+ and deliver the Event Notifications to the Notification Recipient(s).
+
+ Figure 3 shows this partitioning. The interface between the output
+ device (or Printer object) and the remote notification server is
+ outside the scope of this document and is intended to be transparent
+ to the client and this document.
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 75]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ ***********************
+ *
+ * Printer in combination
+ * with the distributed
+ * Notification Server)
+ *
+ * output device or server
+ * +---------------+
+ PDA, desktop, or server * + ########### +
+ +--------+ * | # # |
+ | client |---IPP Subscription--------># Printer # |
+ +--------+ Creation operation * | # Object # |
+ * | #####|##### |
+ * +-------|-------+
+ * | Subscriptions
+ * | OR Event
+ +------------+ * | Notifications
+ |Notification| IPP-defined * +------v--------+
+ |Recipient |<--Event Notifications---| Notification |
+ +------------+ * | Server |
+ * +---------------+
+ *
+ *************************
+ *** = Implementation configuration opaque boundary
+
+ Figure 3 - Opaque Use of a Notification Server Transparent to the
+ Client
+
+18. Extended Notification Recipient (Informative)
+
+ The model allows for an extended Notification Recipient that is
+ itself a notification server that forwards each Event Notification to
+ another recipient (called the Ultimate Notification Recipient in this
+ section). The Delivery Method to the Ultimate Recipient is probably
+ different from the Delivery Method used by the Printer to the
+ extended Notification Recipient.
+
+ This extended Notification Recipient is transparent to the Printer
+ but not to the client.
+
+ When a client performs a Subscription Creation Operation, it
+ specifies the extended Notification Recipient as it would any
+ Notification Recipient. In addition, the client specifies the
+ Ultimate Notification Recipient in the Subscription Creation
+ Operation in a manner specified by the extended Notification
+ Recipient. Typically, it is either some bytes in the value of
+ "notify-user-data" or some additional parameter in the value of
+ "notify-recipient-uri". The client also subscribes directly with the
+
+
+
+Herriot & Hastings Standards Track [Page 76]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ extended Notification Recipient (by means outside this document),
+ since it is a notification server in its own right.
+
+ The IPP Printer treats the extended Notification Recipient like any
+ other Notification Recipient and the IPP Printer is not aware of the
+ forwarding. The Delivery Method that the extended Notification
+ Recipient uses for delivering the Event Notification to the Ultimate
+ Notification Recipient is beyond the scope of this document and is
+ transparent to the IPP Printer.
+
+ Examples of this extended Notification Recipient are paging,
+ immediate messaging services, general notification services, and NOS
+ vendors' infrastructure. Figure 4 shows this approach.
+
+ PDA, desktop, or server server or output device
+ +---------------+
+ +--------+ | ########### |
+ | client |---Subscription Creation -----------># Printer # |
+ +--------+ Operation | # Object # |
+ | #####|##### |
+ +------------+ +------------+ IPP-defined +-------|-------+
+ |Ultimate | any |Notification|<--Event Notifications----+
+ |Notification|<----|Recipient |
+ |Recipient | +------------+
+ +------------+ (Notification Server)
+
+ Figure 4 - Use of an Extended Notification Recipient transparent to
+ the Printer
+
+19. Object Model for Notification (Normative)
+
+ This section describes the Notification object model that adds a
+ Subscription Object which together with the Job and Printer object
+ provide the complete Notification semantics.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 77]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ The object relationships can be seen pictorially as:
+
+ Subscription Objects (Per-Printer Subscriptions) Printer object
+ +----+ +------------+
+ | s1 |<--------------------------------------------->| |
+ +----++ | |
+ | s2 |<-------------------------------------------->| p1 |
+ +----++ | |
+ | s3 |<------------------------------------------->| |
+ +----+ +------------+
+ Job objects
+ +---------+
+ | |
+ +----+ | j1 |
+ | s4 |<------->| |
+ +----+ | |
+ | | s4 is a Per-Job Subscription Object
+ ++--------++
+ | |
+ +----+ | j2 |
+ | s5 |<------>| |
+ +----++ | |
+ | s6 |<----->| | s5 and s6 are Per-Job Subscription
+ +----+ ++--------++ Objects
+ | |
+ | j3 |
+ | |
+ | | <----> indicates association
+ +---------+
+
+ Figure 5 - Object Model for Notification
+
+ s1, s2, and s3 are Per-Printer Subscription Objects and can identify
+ Printer and/or Job Events.
+
+ s4, s5, and s6 are Per-Job Subscription Objects and can identify
+ Printer and/or Job Events.
+
+19.1. Object relationships
+
+ This sub-section defines the object relationships between the
+ Printer, Job, and Subscription Objects by example. Whether Per-
+ Printer Subscription Objects are actually contained in a Printer
+ object or are just bi-directionally associated with them in some way
+ is IMPLEMENTATION DEPENDENT and is transparent to the client.
+ Similarly, whether Per-Job Subscription Objects are actually
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 78]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ contained in a Job object or are just bi-directionally associated
+ with them in some way is IMPLEMENTATION DEPENDENT and is transparent
+ to the client. The object relationships are defined as follows:
+
+19.2. Printer Object and Per-Printer Subscription Objects
+
+ 1. The Printer object contains (is associated with) zero or more
+ Per-Printer Subscription Objects (p1 contains s1-s3 Per-Printer
+ Subscription Objects).
+
+ 2. Each Per-Printer Subscription Object (s1, s2, and s3) is contained
+ in (or is associated with) exactly one Printer object (p1).
+
+19.3. Job Object and Per-Job Subscription Objects
+
+ 1. A Job object (j1, j2, j3) is associated with zero or more Per-Job
+ Subscription Objects (s4-s6). Job j1 is associated with Per-Job
+ Subscription Object s4, Job j2 is associated with Per-Job
+ Subscription Objects s5 and s6, and Job j3 is not associated with
+ any Per-Job Subscription Object.
+
+ 2. Each Per-Job Subscription Object is associated with exactly one
+ Job object.
+
+20. Per-Job versus Per-Printer Subscription Objects (Normative)
+
+ Per-Job and Per-Printer Subscription Objects are quite similar.
+ Either type of Subscription Object can subscribe to Job Events,
+ Printer Events, or both. Both types of Subscription Objects can be
+ queried using the Get-Subscriptions and Get-Subscription-Attributes
+ operations and canceled using the Cancel-Subscription operation.
+ Both types of Subscription Objects create Subscription Objects which
+ have the same Subscription Object attributes defined. However, there
+ are some semantic differences between Per-Job Subscription Objects
+ and Per-Printer Subscription Objects. A Per-Job Subscription Object
+ is established by the client when submitting a job and after creating
+ the job using the Create-Job-Subscriptions operation by specifying
+ the "job-id" of the Job with the "notify-job-id" attribute. A Per-
+ Printer Subscription Object is established between a client and a
+ Printer using the Create-Printer-Subscriptions operation. Some
+ specific differences are:
+
+ 1. A client usually creates one or more Per-Job Subscription Objects
+ as part of the Job Creation operations (Create-Job, Print-Job, and
+ Print-URI), rather than using the OPTIONAL Create-Job-
+ Subscriptions operation, especially since Printer implementations
+ NEED NOT support the Create-Job-Subscriptions operation, since it
+ is OPTIONAL.
+
+
+
+Herriot & Hastings Standards Track [Page 79]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ 2. For Per-Job Subscription Objects, the Subscription Object is only
+ valid while the job is "not-complete" (see sections 5.4.3) while
+ for the Per-Printer Subscription Objects, the Subscription Object
+ is valid until the time (in seconds) that the Printer returned in
+ the "notify-lease-expiration-time" operation attribute.
+
+ 3. Job Events in a Per-Job Subscription Object apply only to "one
+ job" (the Job created by the Job Creation operation or references
+ by the Create-Job-Subscriptions operation) while Job Events in a
+ Per-Printer Subscription Object apply to ALL jobs contained in the
+ IPP Printer.
+
+21. Normative References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119 , March 1997.
+
+ [RFC2396] Berners-Lee, T., Fielding, R., and L. Masinter,
+ "Uniform Resource Identifiers (URI): Generic
+ Syntax", RFC 2396, August 1998.
+
+ [RFC2717] Petke, R. and I. King, "Registration Procedures for
+ URL Scheme Names", RFC 2717, November 1999.
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P., and R. Turner,
+ "Internet Printing Protocol/1.1: Encoding and
+ Transport", RFC 2910, September 2000.
+
+ [RFC2911] deBry, R., Hastings, T., Herriot, R., Isaacson, S.,
+ and P. Powell, "Internet Printing Protocol/1.1:
+ Model and Semantics", RFC 2911, September 2000.
+
+ [RFC3381] Hastings, T., Lewis, H., and R. Bergman, "IPP: Job
+ Progress Attributes", RFC 3381, September 2002.
+
+ [RFC3996] Herriot, R., Hastings, T., and H. Lewis, "Internet
+ Printing Protocol (IPP): The 'ippget' Delivery
+ Method for Event Notifications", RFC 3996, March
+ 2005.
+
+22. Informative References
+
+ [IANA-CON] Narten, T. and H. Alvestrand, "Guidelines for
+ Writing an IANA Considerations Section in RFCs",
+ BCP 26, RFC 2434, October 1998.
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 80]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P., and R. Turner,
+ "Internet Printing Protocol/1.0: Encoding and
+ Transport", RFC 2565, April 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S.,
+ and P. Powell, "Internet Printing Protocol/1.0:
+ Model and Semantics", RFC 2566, April 1999.
+
+ [RFC2567] Wright, D., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure and Model
+ and Protocol for the Internet Printing Protocol",
+ RFC 2568, April 1999.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N., and J.
+ Martin, "Mapping between LPD and IPP Protocols",
+ RFC 2569, April 1999.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P., and T. Berners-Lee,
+ "Hypertext Transfer Protocol - HTTP/1.1", RFC 2616,
+ June 1999.
+
+ [RFC3196] Hastings, T., Manros, C., Zehler, P., Kugler, C.,
+ and H. Holst, "Internet Printing Protocol/1.1:
+ Implementer's Guide", RFC 3196, November 2001.
+
+ [RFC3997] Hastings, T., Editor, deBry, R., and H. Lewis,
+ "Internet Printing Protocol (IPP): Requirements for
+ IPP Notifications", RFC 3997, March 2005.
+
+23. IANA Considerations
+
+ This section contains the registration information that IANA added to
+ the IPP Registry according to the procedures defined in RFC 2911
+ [RFC2911] section 6 to cover the definitions in this document. In
+ addition, this section defines how Events and Delivery Methods will
+ be registered when they are defined in other documents. The
+ resulting registrations have been published in the
+ http://www.iana.org/assignments/ipp-registrations registry.
+
+
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 81]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+23.1. Attribute Registrations
+
+ The following table lists all the attributes defined in this
+ document. These have been registered according to the procedures in
+ RFC 2911 [RFC2911] section 6.2.
+
+ Subscription Template attributes: Reference Section
+ --------------------------------- --------- -------
+ notify-attributes (1setOf type2 keyword) [RFC3995] 5.3.4
+ notify-attributes-supported (1setOf type2 keyword)
+ [RFC3995] 5.3.4.1
+ notify-charset (charset) [RFC3995] 5.3.6
+ notify-events (1setOf type2 keyword) [RFC3995] 5.3.3
+ notify-events-default (1setOf type2 keyword) [RFC3995] 5.3.3.1
+ notify-events-supported (1setOf type2 keyword) [RFC3995] 5.3.3.2
+ notify-lease-duration (integer(0:67108863)) [RFC3995] 5.3.8
+ notify-lease-duration-default (integer(0:67108863))
+ [RFC3995] 5.3.8.1
+ notify-lease-duration-supported (1setOf (integer(0: 67108863) |
+ rangeOfInteger(0:67108863))) [RFC3995] 5.3.8.2
+ notify-max-events-supported (integer(2:MAX)) [RFC3995] 5.3.3.3
+ notify-natural-language (naturalLanguage) [RFC3995] 5.3.7
+ notify-pull-method (type2 keyword) [RFC3995] 5.3.2
+ notify-pull-method-supported (1setOf type2 keyword)
+ [RFC3995] 5.3.2.1
+ notify-recipient-uri (uri) [RFC3995] 5.3.1
+ notify-schemes-supported (1setOf uriScheme) [RFC3995] 5.3.1.1
+ notify-time-interval (integer(0:MAX)) [RFC3995] 5.3.9
+ notify-user-data (octetString(63)) [RFC3995] 5.3.5
+
+ Subscription Description Attributes:
+ notify-job-id (integer(1:MAX)) [RFC3995] 5.4.6
+ notify-lease-expiration-time (integer(0:MAX)) [RFC3995] 5.4.3
+ notify-printer-up-time (integer(1:MAX)) [RFC3995] 5.4.4
+ notify-printer-uri (uri) [RFC3995] 5.4.5
+ notify-sequence-number (integer (0:MAX)) [RFC3995] 5.4.2
+ notify-subscriber-user-name (name(MAX)) [RFC3995] 5.4.7
+ notify-subscription-id (integer (1:MAX)) [RFC3995] 5.4.1
+
+ Printer Description Attributes:
+ printer-state-change-date-time (dateTime) [RFC3995] 6.2
+ printer-state-change-time (integer(1:MAX)) [RFC3995] 6.1
+
+ Attributes Only in Event Notifications
+ notify-subscribed-event (type2 keyword) [RFC3995] 8.1
+ notify-text (text(MAX)) [RFC3995] 8.2
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 82]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+23.2. Additional Enum Attribute Value Registrations within the IPP
+ registry
+
+ The following table lists all the new enum attribute values defined
+ in this document. These have been registered within the IPP registry
+ according to the procedures in RFC 2911 [RFC2911] section 6.1.
+
+ Attribute
+ Value Name Reference Section
+ ------ ----------------------------- --------- -------
+ operations-supported (1setOf type2 enum) [RFC2911] 4.4.15
+ 0x0016 Create-Printer-Subscriptions [RFC3995] 7.1
+ 0x0017 Create-Job-Subscriptions [RFC3995] 7.1
+ 0x0018 Get-Subscription-Attributes [RFC3995] 7.1
+ 0x0019 Get-Subscriptions [RFC3995] 7.1
+ 0x001A Renew-Subscription [RFC3995] 7.1
+ 0x001B Cancel-Subscription [RFC3995] 7.1
+
+23.3. Operation Registrations
+
+ The following table lists all of the operations defined in this
+ document. These have been registered according to the procedures in
+ RFC 2911 [RFC2911] section 6.4.
+
+ Operation Name Reference Section
+ --------------------------------- --------- -------
+ Cancel-Subscription [RFC3995] 11.2.7
+ Create-Job - Extensions [RFC3995] 11.1.3
+ Create-Job-Subscriptions [RFC3995] 11.1.1
+ Create-Printer-Subscriptions [RFC3995] 11.1.2
+ Get-Printer-Attributes - Extensions [RFC3995] 11.2.3
+ Get-Subscription-Attributes [RFC3995] 11.2.4
+ Get-Subscriptions [RFC3995] 11.2.5
+ Print-Job - Extensions [RFC3995] 11.1.3
+ Print-URI - Extensions [RFC3995] 11.1.3
+ Renew-Subscription [RFC3995] 11.2.6
+ Validate-Job Operation - Extensions [RFC3995] 11.2.2
+
+23.4. Status code Registrations
+
+ The following table lists all the status codes defined in this
+ document. These have been registered according to the procedures in
+ RFC 2911 [RFC2911] section 6.6.
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 83]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Value Status Code Name Reference Section
+ ----- ---------------------------- --------- -------
+ 0x0000:0x00FF - Successful:
+ 0x0003 successful-ok-ignored-subscriptions [RFC3995] 12.1
+ 0x0005 successful-ok-too-many-events [RFC3995] 13.4
+
+ 0x0400:0x04FF - Client Error:
+ 0x0414 client-error-ignored-all-subscriptions [RFC3995] 12.2
+ 0x0415 client-error-too-many-subscriptions [RFC3995] 13.3
+
+23.5. Attribute Group tag Registrations
+
+ The following table lists all the attribute group tags defined in
+ this document. These have been registered according to the
+ procedures in RFC 2911 [RFC2911] section 6.5.
+
+ Value Attribute Group Tag Name Reference Section
+ ----- -------------------------------- -------- -------
+ 0x06 subscription-attributes-tag [RFC3995] 14
+ 0x07 event-notification-attributes-tag [RFC3995] 14
+
+23.6. Registration of Events
+
+ The following table lists all the Events defined in this document as
+ type2 keywords to be used with the "notify-events", "notify-events-
+ default", and "notify-events-supported" Subscription Template
+ attributes (see section 5.3.3)). Rather than creating a separate
+ section in the IPP Registry for Events, these event keywords have
+ been registered according to the procedures of [RFC2911] section 7.1
+ as additional keyword attribute values for use with the "notify-
+ events" Subscription Template attribute (see section 5.3.3), i.e.,
+ registered as keyword values for the "notify-events", "notify-
+ events-default", and "notify-events-supported" attributes:
+
+ Attribute (attribute syntax)
+ Value Reference Section
+ --------------------- --------- -------
+ notify-events (1setOf type2 keyword) [RFC3995] 5.3.3
+ notify-events-default (1setOf type2 keyword) [RFC3995] 5.3.3.1
+ notify-events-supported (1setOf type2 keyword) [RFC3995] 5.3.3.2
+ notify-subscribed-event (type2 keyword) [RFC3995] 8.1
+ No Events:
+ none [RFC3995] 5.3.3.4.1
+ Printer Events:
+ printer-state-changed [RFC3995] 5.3.3.4.2
+ printer-restarted [RFC3995] 5.3.3.4.2
+ printer-shutdown [RFC3995] 5.3.3.4.2
+ printer-stopped [RFC3995] 5.3.3.4.2
+
+
+
+Herriot & Hastings Standards Track [Page 84]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ printer-config-changed [RFC3995] 5.3.3.4.2
+ printer-media-changed [RFC3995] 5.3.3.4.2
+ printer-finishings-changed [RFC3995] 5.3.3.4.2
+ printer-queue-order-changed [RFC3995] 5.3.3.4.2
+ Job Events:
+ job-state-changed [RFC3995] 5.3.3.4.3
+ job-created [RFC3995] 5.3.3.4.3
+ job-completed [RFC3995] 5.3.3.4.3
+ job-stopped [RFC3995] 5.3.3.4.3
+ job-config-changed [RFC3995] 5.3.3.4.3
+ job-progress [RFC3995] 5.3.3.4.3
+
+23.7. Registration of Event Notification Delivery Methods
+
+ This section describes the requirements and procedures for
+ registration and publication of Event Notification Delivery Methods
+ and for the submission of such proposals.
+
+23.7.1. Requirements for Registration of Event Notification Delivery
+ Methods
+
+ Registered IPP Event Notification Delivery Methods are expected to
+ follow a number of requirements described below.
+
+23.7.1.1. Required Characteristics
+
+ A Delivery Method Document MUST either (1) contain all of the
+ semantics of the Delivery Method or (2) contain the IPP Delivery
+ Method registration requirements and a profile of some other protocol
+ that in combination is the Delivery Method (e.g., mailto). The
+ Delivery Method Document (and any documents it requires) MUST define
+ either (1) a URL for a Push Delivery Method that the meets the
+ requirements of [RFC2717]. or (2) a keyword for a Pull Delivery
+ method.
+
+ IPP Event Notification Delivery Method Documents MUST meet the
+ requirements of this document (see sections 9 and 10).
+
+ In addition, a Delivery Method Document MUST contain the following
+ information:
+
+ Type of registration: IPP Event Notification Delivery Method
+ Name of this delivery method:
+ Proposed URL scheme name of this Push Delivery Method or the
+ keyword name of this Pull Delivery Method:
+ Name of proposer:
+ Address of proposer:
+
+
+
+
+Herriot & Hastings Standards Track [Page 85]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Email address of proposer:
+ Is this delivery method REQUIRED or OPTIONAL for conformance to
+ the IPP Event Notification and Subscriptions document:
+ Is this delivery method defining Machine Consumable and/or Human
+ Consumable content:
+
+23.7.1.2. Naming Requirements
+
+ Exactly one (URL scheme or keyword) name MUST be assigned to each
+ Delivery Method.
+
+ Each assigned name MUST uniquely identify a single Delivery Method.
+ All Push Delivery Method names MUST conform to the rules for URL
+ scheme names, according to [RFC2396] and [RFC2717] for schemes in the
+ IETF tree. All Pull Delivery Method names MUST conform to the rules
+ for keywords according to [RFC2911].
+
+23.7.1.3. Functionality Requirements
+
+ Delivery Methods MUST function as a protocol that is capable of
+ delivering (push or pull) IPP Event Notifications to Notification
+ Recipients.
+
+23.7.1.4. Usage and Implementation Requirements
+
+ Use of a large number of Delivery Methods may hamper
+ interoperability. However, the use of a large number of undocumented
+ and/or unlabeled Delivery Methods hampers interoperability even more.
+
+ A Delivery Method should therefore be registered ONLY if it adds
+ significant functionality that is valuable to a large community, OR
+ if it documents existing practice in a large community. Note that
+ Delivery Methods registered for the second reason should be
+ explicitly marked as being of limited or specialized use and should
+ only be used with prior bilateral agreement.
+
+23.7.1.5. Publication Requirements
+
+ Delivery Method Documents MUST be published in a standards track,
+ informational, or experimental RFCs.
+
+23.7.2. Registration Procedure
+
+ The IPP WG is developing a small number of Delivery Methods which are
+ intended to be published as standards track RFCs. However, some
+ parties may wish to register additional Delivery Methods in the
+ future. This section describes the procedures for these additional
+ Delivery Methods.
+
+
+
+Herriot & Hastings Standards Track [Page 86]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+23.7.2.1. Present the proposal to the Community
+
+ First the Delivery Method Document MUST be an Internet-Draft with a
+ target category of standards track, informational, or experimental.
+ The same MUST be true for any documents that it references.
+
+ Deliver the proposed Delivery Method Document proposal to the
+ "ipp@pwg.org" mailing list. This mailing list has been established
+ by [RFC2911] for reviewing proposed registrations and discussing
+ other IPP matters. Proposed Delivery Method Documents are not
+ formally registered and MUST NOT be used until approved.
+
+ The intent of the public posting is to solicit comments and feedback
+ on the definition and suitability of the Delivery Method and the name
+ chosen for it over a four week period.
+
+23.7.2.2. Delivery Method Reviewer
+
+ The Delivery Method Reviewer is the same person who has been
+ appointed by the IETF Application Area Director(s) as the IPP
+ Designated Expert according to [RFC2911] and [IANA-CON]. When the
+ four week period is over and the IPP Designated Expert is convinced
+ that consensus has been achieved, the IPP Designated Expert either
+ approves the request for registration or rejects it. Rejection may
+ occur because of significant objections raised on the list or
+ objections raised externally.
+
+ Decisions made by the Reviewer must be posted to the ipp@pwg.org
+ mailing list within 14 days. Decisions made by the Reviewer may be
+ appealed to the IESG.
+
+23.7.2.3. IANA Registration
+
+ Provided that the Delivery Method registration proposal has either
+ passed review or has been successfully appealed to the IESG, the IANA
+ will be notified by the delivery method reviewer and asked to
+ register the Delivery Method and make it available to the community.
+
+23.7.3. Delivery Method Document Registrations
+
+ Each Push Delivery Method Document defines a URI scheme. Such a URI
+ scheme is used in a URI value of the "notification-recipient" (uri)
+ Subscription Template attribute (see section 5.3.1) and the uriScheme
+ value of the "notify-schemes-supported" (1setOf uriScheme 5.3.1.1)
+ Printer attribute(see section ). Rather than creating a separate
+ section in the IPP Registry for Delivery Methods, Push Delivery
+ Methods will be registered as an additional value of the "notify-
+ schemes-supported" Printer attribute. These uriScheme values will be
+
+
+
+Herriot & Hastings Standards Track [Page 87]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ registered according to the procedures of [RFC2911] section 7.1 for
+ additional attribute values. Therefore, the IPP Registry entry for a
+ Push Delivery Method will be of the form:
+
+ Attribute
+ Value Ref. Section
+ --------------------- -------- -------
+ notify-schemes-supported (1setOf uriScheme) [RFC3995] 5.3.1.1
+ <scheme name> RFC xxxx m.n
+
+ Each Pull Delivery Method Document defines a keyword method which is
+ registered as an additional value of the "notify-pull-method" and
+ "notify-pull-method-supported" Printer attributes. These keyword
+ values will be registered according to the procedures of [RFC2911]
+ section 7.1 for additional attribute values. Therefore, the IPP
+ Registry entry for a Pull Delivery Method will be of the form:
+
+ Attribute
+ Value Ref. Section
+ --------------------- -------- -------
+ notify-pull-method (type2 keyword) [RFC3995] 5.3.2
+ notify-pull-method-supported (1setOf type2 keyword)
+ [RFC3995] 5.3.2.1
+ <method keyword name> RFC xxxx m.n
+
+23.7.4. Registration Template
+
+ To: ipp@pwg.org
+ Subject: Registration of a new Delivery Method
+
+ Delivery Method name:
+
+ (All Push Delivery Method names must be suitable for use as the value
+ of a URL scheme in the IETF tree and all Pull Delivery Method names
+ must be suitable IPP keywords according to [RFC2911])
+
+ Published specification(s):
+
+ (A specification for the Delivery Method must be openly available
+ that accurately describes what is being registered.)
+
+ Person & email address to contact for further information:
+
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 88]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+24. Internationalization Considerations
+
+ This IPP Notification specification continues support for the
+ internationalization of [RFC2911] of attributes containing text
+ strings and names. Allowing a Subscribing Client to specify a
+ different natural language and charset for each Subscription Object
+ increases the internationalization support.
+
+ The Printer MUST be able to localize the content of Human Consumable
+ Event Notifications and to localize the value of "notify-text"
+ attribute in Machine Consumable Event Notifications that it delivers
+ to Notification Recipients. For localization, the Printer MUST use
+ the value of the "notify-charset" attribute and the "notify-natural-
+ language" attribute in the Subscription Object supplied by the
+ Subscribing Client.
+
+25. Security Considerations
+
+ Clients submitting Notification requests to the IPP Printer have the
+ same security issues as submitting an IPP/1.1 print job request (see
+ [RFC2911] section 3.2.1 and section 8). The same mechanisms used by
+ IPP/1.1 can therefore be used by the client Notification submission.
+ Operations that require authentication can use the HTTP
+ authentication. Operations that require privacy can use the HTTP/TLS
+ privacy. As with IPP/1.1 Print Job Objects, if there is no security
+ on Subscription Objects, sequential assignment of subscription-ids
+ exposes the system to a passive traffic monitoring threat.
+
+25.1. Client access rights
+
+ The Subscription Object access control model is the same as the
+ access control model for Job objects. The client MUST have the
+ following access rights for the indicated Subscription operations:
+
+ 1. Create-Job-Subscriptions (see section 11.1.1): A Per-Job
+ Subscription object is associated with a Job. To create Per-Job
+ Subscription Objects, the authenticated user (see [RFC2911]
+ section 8.3) performing this operation MUST (1) be the job owner,
+ (2) have Operator or Administrator access rights for this Printer
+ (see [RFC2911] sections 1 and 8.5), or (3) be otherwise authorized
+ by the Printer's administrator-configured security policy to
+ create Per-Job Subscription Objects for the target job.
+
+ 2. Create-Printer-Subscriptions (see section 11.1.2): A Per-Printer
+ Subscription object is associated with the Printer. To create
+ Per-Printer Subscription Objects, the authenticated user (see
+ [RFC2911] section 8.3) performing this operation MUST (1) have
+ Operator or Administrator access rights for this Printer (see
+
+
+
+Herriot & Hastings Standards Track [Page 89]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ [RFC2911] sections 1 and 8.5) or (2) be otherwise authorized by
+ the Printer's administrator-configured security policy to create
+ Per-Printer Subscription Objects for this Printer.
+
+ 3. Get-Subscription-Attributes (see section 11.2.4): The access
+ control model for this operation is the same as that of the Get-
+ Job-Attributes operation (see [RFC2911] section 3.3.4). The
+ primary difference is that a Get-Subscription-Attributes operation
+ is directed at a Subscription Object rather than at a Job object,
+ and a returned attribute group contains Subscription Object
+ attributes rather than Job object attributes. To query the
+ specified Subscription Object, the authenticated user (see
+ [RFC2911] section 8.3) performing this operation MUST (1) be the
+ Subscription Object owner, (2) have Operator or Administrator
+ access rights for this Printer (see [RFC2911] sections 1 and 8.5),
+ or (3) be otherwise authorized by the Printer's administrator-
+ configured security policy to query the Subscription Object for
+ the target job. Furthermore, the Printer's security policy MAY
+ limit which attributes are returned, in a manner similar to the
+ Get-Job-Attributes operation (see [RFC2911] end of section
+ 3.3.4.2).
+
+ 4. Get-Subscriptions (see section 11.2.5): The access control model
+ for this operation is the same as that of the Get-Jobs operation
+ (see [RFC2911] section 3.2.6). The primary difference is that the
+ operation is directed at Subscription Objects rather than at Job
+ objects, and the returned attribute groups contain Subscription
+ Object attributes rather than Job object attributes. To query
+ Per-Job Subscription Objects of the specified job (client supplied
+ the "notify-job-id" operation attribute - see section 11.2.5.1.1),
+ the authenticated user (see [RFC2911] section 8.3) performing this
+ operation MUST (1) be the Subscription Object owner, (2) have
+ Operator or Administrator access rights for this Printer (see
+ [RFC2911] sections 1 and 8.5), or (3) be otherwise authorized by
+ the Printer's administrator-configured security policy to query
+ the Subscription Object for the target job. To query Per-Printer
+ Subscription Objects of the Printer (client omits the "notify-
+ job-id" operation attribute - see section 11.2.5.1.1), the
+ authenticated user (see [RFC2911] section 8.3) performing this
+ operation MUST (1) have Operator or Administrator access rights
+ for this Printer (see [RFC2911] sections 1 and 8.5), or (2) be
+ otherwise authorized by the Printer's administrator-configured
+ security policy to query Per-Printer Subscription Objects for the
+ target Printer. Furthermore, the Printer's security policy MAY
+ limit which attributes are returned, in a manner similar to the
+ Get-Job-Attributes operation (see [RFC2911] end of section
+ 3.2.6.2).
+
+
+
+
+Herriot & Hastings Standards Track [Page 90]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ 5. Renew-Subscriptions (see section 11.2.6): The authenticated user
+ (see [RFC2911] section 8.3) performing this operation MUST (1) be
+ the owner of the Per-Printer Subscription Object, (2) have
+ Operator or Administrator access rights for the Printer (see
+ [RFC2911] sections 1 and 8.5), or (3) be otherwise authorized by
+ the Printer's administrator-configured security policy to renew
+ Per-Printer Subscription Objects for the target Printer
+
+ 6. Cancel-Subscription (see section 11.2.7): The authenticated user
+ (see [RFC2911] section 8.3) performing this operation MUST (1) be
+ the owner of the Subscription Object, (2) have Operator or
+ Administrator access rights for the Printer (see [RFC2911]
+ sections 1 and 8.5), or (3) be otherwise authorized by the
+ Printer's administrator-configured security policy to cancel the
+ target Subscription Object.
+
+ The standard security concerns (delivery to the right user, privacy
+ of content, tamper proof content) apply to each Delivery Method.
+ Some Delivery Methods are more secure than others. Each Delivery
+ Method Document MUST discuss its Security Considerations.
+
+25.2. Printer security threats
+
+ Notification trap door: If a Printer supports the OPTIONAL "notify-
+ attributes" Subscription Template attribute (see section 5.3.4) where
+ the client can request that the Printer return any specified Job,
+ Printer, and Subscription object attributes, the Printer MUST apply
+ the same security policy to these requested attributes in the Get-
+ Notifications request as it does for the Get-Jobs, Get-Job-
+ Attributes, Get-Printer-Attributes, and Get-Subscription-Attributes
+ requests.
+
+25.3. Notification Recipient security threats
+
+ Unwanted Events Notifications (spam): For any Push Delivery Method,
+ by far the biggest security concern is the abuse of notification:
+ delivering unwanted Event Notifications to third parties (i.e.,
+ spam). The problem is made worse by notification addresses that may
+ be redistributed to multiple parties. There exist scenarios where
+ third party notification is used (see Scenario #2 and #3 in
+ [RFC3997]). Any fully secure solution would require active agreement
+ of all recipients before delivering anything.
+
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 91]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+26. Description of the base IPP documents (Informative)
+
+ The base set of IPP documents includes:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [RFC3196]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ The "Design Goals for an Internet Printing Protocol" document takes a
+ broad look at distributed printing functionality, and it enumerates
+ real-life scenarios that help to clarify the features that need to be
+ included in a printing protocol for the Internet. It identifies
+ requirements for three types of users: end users, operators, and
+ administrators. It calls out a subset of end user requirements that
+ are satisfied in IPP/1.0 [RFC2566, RFC2565]. A few OPTIONAL operator
+ operations have been added to IPP/1.1 [RFC2911, RFC2910].
+
+ The "Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol" document describes IPP from a high level
+ view, defines a roadmap for the various documents that form the suite
+ of IPP specification documents, and gives background and rationale
+ for the IETF IPP working group's major decisions.
+
+ The "Internet Printing Protocol/1.1: Model and Semantics" document
+ describes a simplified model with abstract objects, their attributes,
+ and their operations. The model introduces a Printer and a Job. The
+ Job supports multiple documents per Job. The model document also
+ addresses how security, internationalization, and directory issues
+ are addressed.
+
+ The "Internet Printing Protocol/1.1: Encoding and Transport" document
+ is a formal mapping of the abstract operations and attributes defined
+ in the model document onto HTTP/1.1 [RFC2616]. It also defines the
+ encoding rules for a new Internet MIME media type called
+ "application/ipp". This document also defines the rules for
+ transporting over HTTP a message body whose Content-Type is
+ "application/ipp". This document defines the 'ipp' scheme for
+ identifying IPP printers and jobs.
+
+ The "Internet Printing Protocol/1.1: Implementer's Guide" document
+ gives insight and advice to implementers of IPP clients and IPP
+ objects. It is intended to help them understand IPP/1.1 and some of
+ the considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+
+
+
+Herriot & Hastings Standards Track [Page 92]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ The "Mapping between LPD and IPP Protocols" document gives some
+ advice to implementers of gateways between IPP and LPD (Line Printer
+ Daemon) implementations.
+
+27. Contributors
+
+ The following people made significant contributions to the design and
+ review of this specification:
+
+ Scott A. Isaacson
+ Novell, Inc.
+ 122 E 1700 S
+ Provo, UT 84606
+
+ Phone: 801-861-7366
+ Fax: 801-861-2517
+ EMail: sisaacson@novell.com
+
+
+ Roger deBry
+ Utah Valley State College
+ Orem, UT 84058
+
+ Phone: 801-863-8848
+ EMail: debryro@uvsc.edu
+
+
+ Jay Martin
+ Underscore Inc.
+ 9 Jacqueline St.
+ Hudson, NH 03051-5308
+
+ Phone: 603-889-7000
+ Fax: 775-414-0245
+ EMail: jkm@underscore.com
+
+
+ Michael Shepherd
+ Xerox Corporation
+ 800 Phillips Road MS 128-51E
+ Webster, NY 14450
+
+ Phone: 716-422-2338
+ Fax: 716-265-8871
+ EMail: mshepherd@usa.xerox.com
+
+
+
+Herriot & Hastings Standards Track [Page 93]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+ Ron Bergman
+ Ricoh Printing Systems America
+ 1757 Tapo Canyon Road
+ Simi Valley, CA 93063-3394
+
+ Phone: 805-578-4421
+ Fax: 805-578-4001
+ EMail: ron.bergman@rpsa.ricoh.com
+
+Authors' Addresses
+
+ Robert Herriot
+ Global Workflow Solutions
+ 706 Colorado Ave.
+ Palo Alto, CA 94303
+
+ Phone: 650-324-4000
+ EMail: bob@herriot.com
+
+
+ Tom Hastings
+ Xerox Corporation
+ 701 S Aviation Blvd, ESAE 242
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-6342
+ EMail: hastings@cp10.es.xerox.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 94]
+
+RFC 3995 IPP: Event Notifications and Subscriptions March 2005
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2005).
+
+ This document is subject to the rights, licenses and restrictions
+ contained in BCP 78, and except as set forth therein, the authors
+ retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the procedures with respect to rights in RFC documents can be
+ found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at ietf-
+ ipr@ietf.org.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+Herriot & Hastings Standards Track [Page 95]
+
diff --git a/standards/rfc3996.txt b/standards/rfc3996.txt
new file mode 100644
index 000000000..c2a2a86d6
--- /dev/null
+++ b/standards/rfc3996.txt
@@ -0,0 +1,1739 @@
+
+
+
+
+
+
+Network Working Group R. Herriot
+Request for Comments: 3996 Global Workflow Solutions
+Updates: 2911 T. Hastings
+Category: Standards Track Xerox Corp.
+ H. Lewis
+ IBM Corp.
+ March 2005
+
+
+ Internet Printing Protocol (IPP):
+ The 'ippget' Delivery Method for Event Notifications
+
+Status of This Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2005).
+
+Abstract
+
+ This document describes an extension to the Internet Printing
+ Protocol1.1: Model and Semantics (RFC 2911, RFC 2910). This document
+ specifies the 'ippget' Pull Delivery Method for use with the
+ "Internet Printing Protocol (IPP): Event Notifications and
+ Subscriptions" specification (RFC 3995). This IPPGET Delivery Method
+ is REQUIRED for all clients and Printers that support RFC 3995. The
+ Notification Recipient, acting as a client, fetches (pulls) Event
+ Notifications by using the Get-Notifications operation defined in
+ this document.
+
+Table of Contents
+
+ 1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 2.1. Conformance Terminology . . . . . . . . . . . . . . . . 4
+ 2.2. Other Terminology . . . . . . . . . . . . . . . . . . . 4
+ 3. Model and Operation . . . . . . . . . . . . . . . . . . . . . 4
+ 4. General Information . . . . . . . . . . . . . . . . . . . . . 5
+ 5. Get-Notifications Operation . . . . . . . . . . . . . . . . . 7
+ 5.1. Get-Notifications Request . . . . . . . . . . . . . . . 8
+ 5.1.1. notify-subscription-ids (1setOf integer(1:MAX)) 8
+ 5.1.2. notify-sequence-numbers (1setOf integer(1:MAX)) 9
+
+
+
+Herriot, et al. Standards Track [Page 1]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ 5.1.3. notify-wait (boolean) . . . . . . . . . . . . . 10
+ 5.2. Get-Notifications Response. . . . . . . . . . . . . . . 10
+ 5.2.1. notify-get-interval (integer(0:MAX)). . . . . . 13
+ 5.2.2. printer-up-time (integer(1:MAX)). . . . . . . . 14
+ 6. Additional Information about Subscription Template Attributes 17
+ 6.1. notify-pull-method (type2 keyword). . . . . . . . . . . 17
+ 7. Subscription Description Attributes . . . . . . . . . . . . . 18
+ 8. Additional Printer Description Attributes . . . . . . . . . . 18
+ 8.1. ippget-event-life (integer(15:MAX)) . . . . . . . . . . 18
+ 9. New Values for Existing Printer Description Attributes. . . . 19
+ 9.1. notify-pull-method-supported (1setOf type2 keyword) . . 19
+ 9.2. operations-supported (1setOf type2 enum). . . . . . . . 19
+ 10. New Status Codes. . . . . . . . . . . . . . . . . . . . . . . 19
+ 10.1. successful-ok-events-complete (0x0007) . . . . . . . . 20
+ 11. Encoding and Transport. . . . . . . . . . . . . . . . . . . . 20
+ 12. Conformance Requirements. . . . . . . . . . . . . . . . . . . 21
+ 12.1. Conformance for IPP Printers . . . . . . . . . . . . . 21
+ 12.2. Conformance for IPP Clients. . . . . . . . . . . . . . 22
+ 13. Normative References. . . . . . . . . . . . . . . . . . . . . 23
+ 14. Informative References. . . . . . . . . . . . . . . . . . . . 23
+ 15. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 24
+ 15.1. Attribute Registrations. . . . . . . . . . . . . . . . 24
+ 15.2. Delivery Method and Additional Keyword Attribute Value
+ registrations for Existing Attributes. . . . . . . . . 24
+ 15.3. Additional Enum Attribute Values . . . . . . . . . . . 25
+ 15.4. Operation Registrations. . . . . . . . . . . . . . . . 25
+ 15.5. Status Code Registrations. . . . . . . . . . . . . . . 25
+ 16. Internationalization Considerations . . . . . . . . . . . . . 25
+ 17. Security Considerations . . . . . . . . . . . . . . . . . . . 26
+ 17.1. Notification Recipient Client Access Rights. . . . . . 26
+ 17.2. Printer Security Threats . . . . . . . . . . . . . . . 27
+ 17.3. Notification Recipient Security Threats. . . . . . . . 27
+ 17.4. Security Requirements for Printers . . . . . . . . . . 27
+ 17.5. Security Requirements for clients. . . . . . . . . . . 28
+ 18. Description of Base IPP Documents (Informative) . . . . . . . 28
+ 19. Contributors. . . . . . . . . . . . . . . . . . . . . . . . . 29
+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 30
+ Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 31
+
+Table of Tables
+
+ Table 1. Information about the Delivery Method. . . . . . . . . . 5
+ Table 2. Combinations of "notify-wait", "status-code", and
+ "notify-get-interval". . . . . . . . . . . . . . . . . . 13
+ Table 3. Attributes in Event Notification Content . . . . . . . . 15
+ Table 4. Additional Attributes in Event Notification Content for
+ Job Events . . . . . . . . . . . . . . . . . . . . . . . 16
+
+
+
+
+Herriot, et al. Standards Track [Page 2]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ Table 5. Combinations of Events and Subscribed Events for "job-
+ impressions-completed" . . . . . . . . . . . . . . . . . 17
+ Table 6. Additional Attributes in Event Notification Content for
+ Printer Events . . . . . . . . . . . . . . . . . . . . . 17
+ Table 7. Operation-id Assignments . . . . . . . . . . . . . . . . 19
+ Table 8. The "event-notification-attributes-tag" Value. . . . . . 21
+
+1. Introduction
+
+ This document describes an extension to the Internet Printing
+ Protocol/1.1: Model and Semantics [RFC 2911], [RFC 2910]. This
+ document specifies the 'ippget' Pull Delivery Method for use with the
+ "Internet Printing Protocol (IPP): Event Notifications and
+ Subscriptions" specification [RFC3995]. This IPPGET Delivery Method
+ is REQUIRED for all clients and Printers that support [RFC3995]. The
+ Notification Recipient, acting as a client, fetches (pulls) Event
+ Notifications by using the Get-Notifications operation defined in
+ this document. For a description of the base IPP documents, see
+ section 21 of this document. For a description of the IPP Event
+ Notification Model, see [RFC3995].
+
+ With this Pull Delivery Method, when an Event occurs, the Printer
+ saves the Event Notification for a period of time called the Event
+ Life. The Notification Recipient fetches (pulls) the Event
+ Notifications by using the Get-Notifications operation. This
+ operation causes the Printer to return all Event Notifications held
+ for the specified Subscription object(s). If the Notification
+ Recipient has selected the Event Wait Mode option to wait for
+ additional Event Notifications, the Printer MAY continue to return
+ Event Notifications to the Notification Recipient as asynchronous
+ Get-Notification responses as Events occur using the transaction
+ originated by the Notification Recipient.
+
+ The Notification Recipient can terminate Event Wait Mode (without
+ closing the connection) by supplying the "notify-wait" (boolean)
+ attribute with a 'false' value in a subsequent Get-Notifications
+ request. Similarly, the Printer can terminate Event Wait Mode
+ (without closing the connection) by returning the "notify-get-
+ interval" (integer) operation attribute in a Get-Notifications
+ response that tells the Notification Recipient how long to wait
+ before trying again.
+
+2. Terminology
+
+ This section defines the following terms that are used throughout
+ this document:
+
+
+
+
+
+Herriot, et al. Standards Track [Page 3]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+2.1. Conformance Terminology
+
+ Capitalized terms such as MUST, MUST NOT, REQUIRED, SHOULD, SHOULD
+ NOT, MAY, NEED NOT, and OPTIONAL have special meaning relating to
+ conformance as defined in [RFC2119] and [RFC2911], section 12.1. If
+ an implementation supports the extension defined in this document,
+ then these terms apply; otherwise, they do not. These terms define
+ conformance to this document only; they do not affect conformance to
+ other documents, unless it is explicitly stated otherwise.
+
+2.2. Other terminology
+
+ This document uses the same terminology as [RFC2911], including
+ "client", "Printer", "Job", "attribute", "attribute value",
+ "keyword", "operation", "request", "response", and "support", with
+ the same meanings. This document also uses terminology defined in
+ [RFC3995], such as "Subscription (object)", "Notification Recipient",
+ "Event", "Event Notification", "Compound Event Notification", "Event
+ Life", and "Event Notification Attribute Group", with the same
+ meanings. In addition, this document defines the following terms for
+ use in this document:
+
+ Event Wait Mode: The mode requested by a Notification Recipient
+ client in its Get-Notifications Request and granted by a Printer
+ to keep the connection open while the Printer sends subsequent
+ Get-Notification operation responses to the Notification
+ Recipient in the form of Event Notifications as they occur.
+
+3. Model and Operation
+
+ In a Subscription Creation Operation, when the "notify-pull-method"
+ attribute is present and has the "ippget" keyword value, the client
+ is requesting that the Printer use the "ippget" Pull Delivery Method
+ for the Event Notifications associated with the new Subscription
+ Object.
+
+ When an Event occurs, the Printer MUST generate an Event Notification
+ and MUST assign it the Event Life. The Printer MUST hold an Event
+ Notification for its assigned Event Life.
+
+ When a Notification Recipient wants to receive Event Notifications
+ for a Subscription object, it performs the Get-Notifications
+ operation supplying the Subscription object's subscription-id, which
+ causes the Printer to return all un-expired Event Notifications held
+ for that Subscription object. If the Notification Recipient has
+ selected the Event Wait Mode option to wait for additional Event
+ Notifications, the response to the Get-Notifications request
+ continues indefinitely as the Printer continues to send Event
+
+
+
+Herriot, et al. Standards Track [Page 4]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ Notifications in the response as Events occur for that Subscription
+ object.
+
+ When the Notification Recipient requests Event Notifications for
+ Per-Job Subscription Objects, the Notification Recipient typically
+ performs the Get-Notifications operation within a second of
+ performing the Subscription Creation operation. Because the Printer
+ MUST save Event Notifications for at least 15 seconds (see section
+ 8.1), the Notification Recipient is unlikely to miss any Event
+ Notifications that occur between the Subscription Creation and the
+ Get-Notifications operation.
+
+ The 'ippget' Delivery Method is designed primarily for (1) a client
+ that wants to get Events (from the job's Per-Job Subscription object)
+ for a job that it has submitted and (2) a privileged client that
+ wants to get all job or printer Events from a Per-Printer
+ Subscription object.
+
+4. General Information
+
+ If a Printer supports this Delivery Method, the following are its
+ characteristics.
+
+ Table 1. Information about the Delivery Method
+
+ Document Method Conformance Requirement Delivery Method
+ Realization
+
+ 1. What is the URL scheme name for the 'ippget' keyword method
+ Push Delivery Method, or the keyword name
+ method name for the Pull Delivery
+ Method?
+
+ 2. Is the Delivery Method REQUIRED, REQUIRED
+ RECOMMENDED, or OPTIONAL for an IPP
+ Printer to support?
+
+ 3. What transport and delivery protocols IPP with one new
+ does the Printer use to deliver the operation.
+ Event Notification Content; i.e.,
+ what is the entire network stack?
+
+ 4. Can several Event Notifications be Yes.
+ combined into a Compound Event
+ Notification?
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 5]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ 5. Is the Delivery Method initiated by This Delivery Method is
+ the Notification Recipient (pull), a pull method with
+ or by the Printer (push)? aspects of a push
+ method, though the
+ Printer does not
+ initiate the operation.
+
+ 6. Is the Event Notification content Machine Consumable.
+ Machine Consumable or Human
+ Consumable?
+
+ 7. What section in this document answers Section 5.
+ the following questions? For a Machine
+ Consumable Event Notification, what is
+ the representation and encoding of
+ values defined in section 9.1 of
+ [RFC3995], and what are the
+ conformance requirements thereof? For
+ a Human Consumable Event Notification,
+ what is the representation and
+ encoding of pieces of information
+ defined in section 9.2 of
+ [RFC3995], and the conformance
+ requirements thereof?
+
+ 8. What are the latency and reliability Same as IPP and the
+ of the transport and delivery underlying HTTP
+ protocol? transport.
+
+ 9. What are the security aspects of the Same as IPP and the
+ transport and delivery protocol; underlying HTTP
+ e.g., how it is handled in transport and in the
+ firewalls? same direction, so no
+ new firewall
+ considerations.
+
+ 10. What are the content length None.
+ restrictions?
+
+ 11. What are the additional values or None.
+ pieces of information that a Printer
+ sends in an Event Notification content
+ and the conformance requirements
+ thereof?
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 6]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ 12. What are the additional Subscription None.
+ Template and/or Subscription
+ Description attributes and the
+ conformance requirements thereof?
+
+ 13. What are the additional Printer "ipp-event-life"
+ Description attributes and the (integer (15: MAX))
+ conformance requirements thereof?
+
+5. Get-Notifications Operation
+
+ This operation is issued by a client acting in the role of a
+ Notification Recipient requesting the Printer to return all Event
+ Notifications held for the identified Subscription object(s).
+
+ A Printer MUST support this operation, MUST accept the request in any
+ state (see [RFC2911] "printer-state" and "printer-state-reasons"
+ attributes), and MUST remain in the same state with the same
+ "printer-state-reasons" values.
+
+ When a Printer performs this operation, it MUST return all and only
+ those Event Notifications
+
+ 1. whose associated Subscription Object's "notify-subscription-id"
+ Subscription Description attribute equals one of the values of
+ the "notify-subscription-ids" (1setOf integer(1:MAX)) operation
+ attribute AND
+
+ 2. whose associated Subscription Object contains the "notify-pull-
+ method" attribute and it has the 'ippget' keyword value, AND
+
+ 3. whose "notify-sequence-number" is equal to or greater than the
+ corresponding value of the "notify-sequence-numbers" (1setOf
+ integer(1:MAX)) operation attribute if supplied AND
+
+ 4. whose Event Life has not yet expired AND
+
+ 5. where the Notification Recipient client has read-access rights to
+ the identified Subscription Object (see Access Rights paragraph
+ below).
+
+ The Notification Recipient client MUST either (a) request Event Wait
+ Mode by supplying the "notify-wait" operation attribute with a 'true'
+ value or (b) suppress Event Wait Mode by omitting the "notify-wait"
+ operation attribute or by supplying it with a 'false' value. To
+ terminate Event Wait Mode subsequently, the Notification Recipient
+ client MUST close the connection. To terminate Event Wait Mode, the
+ Printer MUST either (a) return the "notify-get-interval" operation
+
+
+
+Herriot, et al. Standards Track [Page 7]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ attribute in a Get-Notifications response (RECOMMENDED behavior) or
+ (b) close the connection. The "notify-get-interval" operation
+ attributes tell the Notification Recipient how long to wait before
+ trying a subsequent Get-Notifications request.
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation MUST be (1) the owner of each Subscription
+ Object identified by the "notify-subscription-ids" operation
+ attribute (see section 5.1.1), (2) an operator or administrator of
+ the Printer (see [RFC2911], sections 1 and 8.5), or (3) otherwise
+ authorized by the Printer's administrator-configured security policy
+ to request Event Notifications from the target Subscription
+ Object(s). Otherwise, the IPP Printer MUST reject the operation and
+ return: 'client-error-forbidden', 'client-error-not-authenticated',
+ or 'client-error-not-authorized' status code, as appropriate.
+ Furthermore, the Printer's security policy MAY limit the attributes
+ returned by the Get-Notifications operation, in a manner similar to
+ that of the Get-Job-Attributes operation (see [RFC2911], end of
+ section 3.3.4.2).
+
+5.1. Get-Notifications Request
+
+ The following groups of attributes are part of the Get-Notifications
+ Request:
+
+ Group 1: Operation Attributes
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes, as described in [RFC2911], section 3.1.4.1.
+
+ Target:
+ The "printer-uri" (uri) operation attribute that is the target
+ for this operation as described in [RFC2911], section 3.1.5.
+
+ Requesting User Name:
+ The "requesting-user-name" (name(MAX)) attribute SHOULD be
+ supplied by the client as described in [RFC2911], section 8.3.
+
+5.1.1. notify-subscription-ids (1setOf integer(1:MAX))
+
+ This attribute identifies one or more Subscription objects for which
+ Events are requested. The client MUST supply this attribute with at
+ least one value. The Printer object MUST support this attribute with
+ multiple values.
+
+ If no Subscription Object exists with the supplied identifier, or if
+ the identified Subscription Object does not contain the "notify-
+
+
+
+Herriot, et al. Standards Track [Page 8]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ pull-method" attribute with the 'ippget' keyword value, the Printer
+ MUST return the 'client-error-not-found' status code.
+
+ Note: The name of both the "notify-subscription-ids" and
+ "notify-sequence-numbers" end in 's', as they are multi-valued.
+ However, there are other occurrences of these attribute names
+ without the 's' that are single valued.
+
+5.1.2. notify-sequence-numbers (1setOf integer(1:MAX))
+
+ This attribute specifies one or more of the lowest Event Notification
+ sequence number values for the Subscription objects identified by the
+ corresponding values of the "notify-subscription-ids" operation
+ attribute. The Notification Recipient SHOULD supply this attribute,
+ and the number of values SHOULD be the same as that of the "notify-
+ subscriptions-ids" attribute. The Printer MUST support this
+ attribute with multiple values.
+
+ The Printer MUST NOT return Notification Events with lower sequence
+ numbers for the corresponding Subscription object. Therefore, by
+ supplying the proper values for this attribute the Notification
+ Recipient can prevent getting the same Event Notifications from a
+ Subscription object that were returned on a previous Get-
+ Notifications request. The Notification Recipient SHOULD remember
+ the highest "notify-sequence-number" value returned for each
+ Subscription object requested and SHOULD pass that value for each
+ requested Subscription object on the next Get-Notifications request.
+
+ If the Notification Recipient supplies fewer values for this
+ attribute (including omitting this attribute) than it does for the
+ "notify-subscription-ids" operation attribute, the Printer assumes a
+ '1' value for each missing value. A value of '1' causes the Printer
+ to return any un-expired Event Notification for that Subscription
+ object, as '1' is the lowest possible sequence number. If the
+ Notification Recipient supplies more values for this attribute than
+ the number of values for the "notify-subscription-ids" operation
+ attribute, the Printer ignores the extra values.
+
+ Note: If a Notification Recipient performs two consecutive Get-
+ Notifications operations with the same value for "notify-sequence-
+ number" (or omits the attribute), the time stamp value of the first
+ Event Notification in the second Get-Notifications Response may be
+ less than that of the time stamp of the last Event Notification in
+ the first Get-Notification Response. This happens because the
+ Printer sends all unexpired Event Notifications with an equal or
+ higher sequence number according to the ordering specified in
+ [RFC3995], and some Event Notifications from the first Get-
+
+
+
+
+Herriot, et al. Standards Track [Page 9]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ Notifications operation may not have expired by the time the second
+ Get-Notifications operation occurs.
+
+5.1.3. notify-wait (boolean)
+
+ This value indicates whether the Notification Recipient wants Event
+ Wait Mode. The client MAY supply this attribute. The Printer object
+ MUST support both values of this attribute.
+
+ If the client supplies the 'false' value or omits this attribute, the
+ client is not requesting Event Wait Mode. If the value is 'true',
+ the client is requesting Event Wait Mode. See the beginning of
+ section 5.2 for the rules for Event Wait Mode.
+
+5.2. Get-Notifications Response
+
+ The Printer has the following options for responding to a Get-
+ Notifications Request:
+
+ 1. The Printer can reject the request and return the 'server-error-
+ busy' status code if the Printer is too busy to accept this
+ operation at this time. In this case, the Printer MUST return
+ the "get-notify-interval" operation attribute to indicate when
+ the client SHOULD try again.
+
+ 2. If the Notification Recipient did not request Event Wait Mode
+ ("notify-wait-mode" = 'false' or omitted), the Printer MUST
+ immediately return whatever Event Notifications it currently
+ holds in the requested Subscription object(s) and MUST return the
+ "notify-get-interval" operation attribute with the number of
+ seconds from now, at which the Notification Recipient SHOULD
+ repeat the Get-Notifications Request to get future Event
+ Notifications.
+
+ 3. If the Notification Recipient requested Event Wait Mode
+ ("notify-wait-mode" = 'true'), the Printer MUST immediately
+ return whatever Event Notifications it currently holds in the
+ requested Subscription object(s) and MUST continue to return
+ Event Notifications as they occur until all the requested
+ Subscription Objects are canceled. A Subscription Object is
+ canceled either via the Cancel-Subscription operation or by the
+ Printer (e.g., the Subscription Object is canceled when the
+ associated Job completes and is no longer in the Job Retention or
+ Job History phase; see the "ippget-event-life (integer(15:MAX))"
+ attribute discussion in section 8.1).
+
+ However, the Printer MAY decide to terminate Event Wait Mode at
+ any time, including in the first response. In this case, the
+
+
+
+Herriot, et al. Standards Track [Page 10]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ Printer MUST return the "notify-get-interval" operation
+ attribute. This attribute indicates that the Printer wishes to
+ leave Event Wait Mode and the number of seconds in the future
+ that the Notification Recipient SHOULD try the Get-Notifications
+ operation again. The Notification Recipient MUST accept this
+ response and MUST disconnect. If the Notification Recipient does
+ not disconnect, the Printer SHOULD do so.
+
+ From the Notification Recipient's view, the response appears as an
+ initial burst of data, which includes the Operation Attributes Group
+ and one Event Notification Attributes Group per Event Notification
+ that the Printer is holding. After the initial burst of data, if the
+ Notification Recipient has selected the Event Wait Mode option to
+ wait for additional Event Notifications, the Notification Recipient
+ receives occasional Event Notification Attribute Groups. Proxy
+ servers may delay some Event Notifications or cause time-outs to
+ occur. The client MUST be prepared to perform the Get-Notifications
+ operation again when time-outs occur.
+
+ Each attribute is encoded by using the IPP rules for encoding
+ attributes [RFC2910] and MAY be encoded in any order. Note: the
+ Get-Jobs response in [RFC2911] acts as a model for encoding multiple
+ groups of attributes. See section 11 for the encoding and transport
+ rules.
+
+ The following groups of attributes are part of the Get-Notifications
+ Response:
+
+ Group 1: Operation Attributes
+
+ Status Message: In addition to the REQUIRED status code returned
+ in every response, the response OPTIONALLY includes a "status-
+ message" (text(255)) and/or a "detailed-status-message"
+ (text(MAX)) operation attribute, as described in [RFC2911],
+ sections 13 and 3.1.6.
+
+ The Printer can return any status codes defined in [RFC2911].
+ If the status code is not 'successful-xxx', the Printer MUST
+ NOT return any Event Notification Attribute groups. The
+ following are descriptions of the important status codes:
+
+ successful-ok: The response contains all Event Notification
+ associated with the specified subscription-ids that had
+ been supplied in the "notify-subscription-ids" operation
+ attribute in the request. If the requested Subscription
+ Objects have no associated Event Notification, the
+ response MUST contain zero Event Notifications.
+
+
+
+
+Herriot, et al. Standards Track [Page 11]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ successful-ok-events-complete: Indicates when this return
+ is the last return for all Subscription objects that
+ match the request, whether or not Event Notifications are
+ returned. This condition occurs for Event Wait Mode with
+ Notification Recipients waiting for responses when (1)
+ the Subscription Object is canceled with a Cancel-
+ Subscription operation, (2) the Subscription Object is
+ deleted, when the Per-Printer Subscription lease time
+ expires, or (3) the 'job-completed' event occurs for a
+ Per-Job Subscription. This condition also occurs for a
+ Get-Notifications request that a Notification Recipient
+ makes after the job completes, but before the Event Life
+ expires. See section 10.1.
+ client-error-not-found: The Printer has no Subscription
+ Objects whose "notify-subscription-id" attribute equals
+ any of the values of the "notify-subscription-ids"
+ operation attribute supplied, or the identified
+ Subscription Object does not contain the "notify-pull-
+ method" attribute with the 'ippget' keyword value.
+ server-error-busy: The Printer is too busy to accept this
+ operation. The Printer SHOULD return the "notify-get-
+ interval" operation attribute in the Operation Attributes
+ of the response; then the Notification Recipient SHOULD
+ wait for the number of seconds specified by the "notify-
+ get-interval" operation attribute before performing this
+ operation again. If the "notify-get-interval" Operation
+ Attribute is not present, the Notification Recipient
+ SHOULD use the normal network back-off algorithms to
+ determine when to perform this operation again.
+
+ Natural Language and Character Set:
+ The "attributes-charset" and "attributes-natural-language"
+ attributes, as described in [RFC2911], section 3.1.4.2.
+
+ The Printer MUST use the values of "notify-charset" and
+ "notify-natural-language", respectively, from one Subscription
+ Object associated with the Event Notifications in this
+ response.
+
+ Normally, there is only one matched Subscription Object, or the
+ value of the "notify-charset" and "notify-natural-language"
+ attributes is the same in all Subscription Objects. If not,
+ the Printer MUST pick one Subscription Object from which to
+ obtain the value of these attributes. The algorithm for
+ picking the Subscription Object is implementation dependent.
+ The choice of natural language is not critical, because 'text'
+ and 'name' values can override the "attributes-natural-
+ language" operation attribute. The Printer's choice of charset
+
+
+
+Herriot, et al. Standards Track [Page 12]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ is critical because a bad choice may leave it unable to send
+ some 'text' and 'name' values accurately.
+
+5.2.1. notify-get-interval (integer(0:MAX))
+
+ The value of this operation attribute is the number of seconds that
+ the Notification Recipient SHOULD wait before trying the Get-
+ Notifications operation again. The Printer MUST return this
+ operation attribute if (1) it is too busy to return events, (2) the
+ Notification Recipient client did not request Event Wait Mode, or (3)
+ the Printer is terminating Event Wait Mode. The client MUST accept
+ this attribute and SHOULD reissue the Get-Notifications operation
+ (with or without "notify-wait" = 'true') at the indicated number of
+ seconds in the future in order to get more Event Notifications This
+ value is intended to help the client be a good network citizen.
+
+ The value of this attribute MUST be at least as large as that of the
+ Printer's "ippget-event-life" Printer Description attribute (see
+ section 8.1). The Printer MAY return a value that is larger than
+ that of the "ippget-event-life" Printer Description attribute
+ provided that the Printer increases the Event Life for this
+ Subscription object so that Notification Recipients taking account of
+ the larger value and polling with a longer interval will not miss
+ events. Note: Implementing such an algorithm requires some hidden
+ attributes in the Subscription object that are IMPLEMENTATION
+ DEPENDENT.
+
+ If the Printer wants to remain in Event Wait Mode, then the Printer
+ MUST NOT return this attribute in the response.
+
+ Here is a complete table of combinations of "notify-wait", "status-
+ code", "notify-get-interval", and Event Notification Attributes
+ Groups for Get-Notification initial (Wait and No Wait) Responses and
+ subsequent Event Wait Mode Responses (which may stay in Event Wait
+ Mode or may request the Notification Recipient to leave Event Wait
+ Mode):
+
+ Table 2. Combinations of "notify-wait", "status-code", and
+ "notify-get-interval"
+
+ Client sends: Printer returns: Printer Event
+ returns: Notification
+ "notify-wait" "status-code" "notify-get- Attribute
+ interval" Groups
+
+ 1. 'false'* 'successful-ok' MUST return N maybe
+ 2. 'false'* 'not-found' MUST NOT MUST NOT
+ 3. 'false'* 'busy' MUST return N MUST NOT
+
+
+
+Herriot, et al. Standards Track [Page 13]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ 4. 'false'* 'events- MUST NOT 'job-
+ complete' completed'
+ 5. 'true' 'successful-ok' MUST NOT MUST
+ 6. 'true' 'successful-ok' MUST return N maybe
+ 7. 'true' 'not-found' MUST NOT MUST NOT
+ 8. 'true' 'busy' MUST return N MUST NOT
+ 9. 'true' 'events- MUST NOT 'job-
+ complete' completed' or
+ maybe other
+ * 'false' or client omits the "notify-wait" attribute.
+
+ Explanation:
+
+ 1-4: Client does not request Event Wait Mode.
+ 5-9: Client requests Event Wait Mode.
+ 2,7: Subscription object not found, or was canceled earlier;
+ client should NOT try again.
+ 3,8: Server busy, tells client to try later; client should try
+ again in N seconds.
+ 4: Client polled after job completed, but before Event Life
+ expired, and got the 'job-completed' event, so the client
+ shouldn't bother trying again; client should NOT try
+ again later.
+ 5: Printer returns one or more Event Notifications and is OK
+ to stay in Event Wait Mode; the client waits for more
+ Event Notifications to be returned.
+ 6: Printer wants to leave Event Wait mode. Can happen on
+ the first response (with or without Event Notifications)
+ or happen on a subsequent response with or without Event
+ Notifications; the client SHOULD try again in N seconds.
+ 9: Either (1) the printer returns 'job-completed' event, or
+ (2) the Subscription Object was canceled by either a
+ Cancel-Job or a Per-Printer Subscription expired without
+ being renewed. For case (1), at least one Event
+ Notification MUST be returned; for case (2), it is
+ unlikely that any Event Notifications are returned, and
+ the client should NOT try again.
+
+5.2.2. printer-up-time (integer(1:MAX))
+
+ The value of this attribute is the Printer's "printer-up-time"
+ attribute at the time when the Printer sends this response. The
+ Printer MUST return this attribute. Because each Event Notification
+ also contains the value of this attribute when the event occurred,
+ the value of this attribute lets a Notification Recipient know when
+ each Event Notification occurred relative to the time of this
+ response.
+
+
+
+
+Herriot, et al. Standards Track [Page 14]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ Group 2: Unsupported Attributes
+ See [RFC2911], section 3.1.7, for details on returning
+ Unsupported Attributes.
+
+ Group 3 through N: Event Notification Attributes
+ The Printer responds with one Event Notification Attributes
+ Group per matched Event Notification. The entire response is
+ considered a single Compound Event Notification (see
+ [RFC3995]). The matched Event Notifications are all un-expired
+ Event Notifications associated with the matched Subscription
+ Objects and MUST follow the "Event Notification Ordering"
+ requirements for Event Notifications within a Compound Event
+ Notification specified in [RFC3995] section 9. In other words,
+ the Printer MUST order these Event Notification groups in
+ ascending time stamp (and sequence number) order for a
+ Subscription object. If Event Notifications for multiple
+ Subscription objects are being returned, the Notification
+ Events for the next Subscription object follow in ascending
+ time stamp order, etc.
+
+ Each Event Notification Group MUST contain all of attributes
+ specified in section 9.1 ("Content of Machine Consumable Event
+ Notifications") of [RFC3995], with exceptions denoted by
+ asterisks in the tables below.
+
+ The tables below are identical to those in section 9.1
+ ("Content of Machine Consumable Event Notifications") of
+ [RFC3995], except that each cell in the "Sends" column is a
+ "MUST".
+
+ If more than one Event Notification is being returned and the
+ status of each is not the same, then the Printer MUST return a
+ "notify-status-code" attribute in each Event Notification
+ Attributes group to indicate the differing status values.
+
+ For an Event Notification for all Events, the Printer includes
+ the attributes shown in Table 3.
+
+ Table 3. Attributes in Event Notification Content
+
+ Source Value Sends Source Object
+
+ notify-subscription-id (integer(1:MAX)) MUST Subscription
+ notify-printer-uri (uri) MUST Subscription
+ notify-subscribed-event (type2 keyword) MUST Event
+ Notification
+ printer-up-time (integer(1:MAX)) * MUST Printer
+ printer-current-time (dateTime) MUST ** Printer
+
+
+
+Herriot, et al. Standards Track [Page 15]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ notify-sequence-number (integer (0:MAX)) MUST Subscription
+ notify-charset (charset) MUST Subscription
+ notify-natural-language (naturalLanguage) MUST Subscription
+ notify-user-data (octetString(63)) MUST *** Subscription
+ notify-text (text) MUST Event
+ Notification
+ attributes from the "notify-attributes" MUST **** Printer
+ attribute
+ attributes from the "notify-attributes" MUST **** Job
+ attribute
+ attributes from the "notify-attributes" MUST **** Subscription
+ attribute
+
+ * As specified in [RFC3995] section 9, the value of the
+ "printer-up-time" attribute sent in each Event Notification
+ MUST be the time at which the Event occurred, not the time at
+ which the Event Notification was sent.
+
+ ** The Printer MUST send the "printer-current-time" attribute
+ if and only if it supports the "printer-current-time" attribute
+ on the Printer object.
+
+ *** If the associated Subscription Object does not contain a
+ "notify-user-data" attribute, the Printer MUST send an
+ octet-string of length 0.
+
+ **** If the "notify-attributes" attribute is present on the
+ Subscription Object, the Printer MUST send all attributes
+ specified by the "notify-attributes" attribute. Note: If the
+ Printer doesn't support the "notify-attributes" attribute, it
+ is not present on the associated Subscription Object.
+
+ For Event Notifications for Job Events, the Printer includes
+ the additional attributes shown in Table 4.
+
+ Table 4. Additional Attributes in Event Notification Content for
+ Job Events
+
+ Source Value Sends Source Object
+
+ job-id (integer(1:MAX)) MUST Job
+ job-state (type1 enum) MUST Job
+ job-state-reasons (1setOf type2 keyword) MUST Job
+ job-impressions-completed (integer(0:MAX)) MUST * Job
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 16]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ * The Printer MUST send the "job-impressions-completed" attribute
+ in an Event Notification only for the combinations of Events and
+ Subscribed Events shown in Table 5.
+
+ Table 5. Combinations of Events and Subscribed Events for
+ "job-impressions-completed"
+
+ Job Event Subscribed Job Event
+
+ 'job-progress' 'job-progress'
+ 'job-completed' 'job-completed'
+ 'job-completed' 'job-state-changed'
+
+ For Event Notification for Printer Events, the Printer includes
+ the additional attributes shown in Table 6.
+
+ Table 6. Additional Attributes in Event Notification Content for
+ Printer Events
+
+ Source Value Sends Source
+ Object
+
+ printer-state (type1 enum) MUST Printer
+ printer-state-reasons (1setOf type2 keyword) MUST Printer
+ printer-is-accepting-jobs (boolean) MUST Printer
+
+6. Additional Information about Subscription Template Attributes
+
+ The 'ippget' Delivery Method does not define any addition
+ Subscription Template attributes and has the conformance requirements
+ for Subscription Template attributes defined in [RFC3995]. This
+ section defines additional information about Subscription Template
+ attributes defined in [RFC3995].
+
+6.1. notify-pull-method (type2 keyword)
+
+ This Subscription Template attribute identifies the Pull Delivery
+ Method to be used for the Subscription Object (see [RFC3995]). To
+ support the 'ippget' Pull Delivery Method defined in this document,
+ the Printer MUST support this attribute with the following keyword
+ value:
+
+ 'ippget': Indicates that the 'ippget' Pull Delivery Method is to
+ be used for this Subscription Object.
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 17]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+7. Subscription Description Attributes
+
+ The 'ippget' Delivery Method has the conformance requirements for
+ Subscription Description attributes defined in [RFC3995]. The
+ 'ippget' Delivery Method does not define any addition Subscription
+ Description attributes.
+
+8. Additional Printer Description Attributes
+
+ This section defines additional Printer Description attributes for
+ use with the 'ippget' Delivery Method.
+
+8.1. ippget-event-life (integer(15:MAX))
+
+ This Printer Description attribute specifies the Event Life value
+ that the Printer assigns to each Event; i.e., the number of seconds
+ after an Event occurs during which a Printer will return that Event
+ in an Event Notification in a Get-Notifications response. After the
+ Event Life expires for the Event, the Printer MAY no longer return an
+ Event Notification for that Event in a Get-Notifications response.
+
+ The Printer MUST support this attribute if it supports the 'ippget'
+ Delivery Method. The value MUST be 15 or more (at least 15 seconds),
+ and 60 (seconds) is the RECOMMENDED value to align with the PWG Job
+ Monitoring MIB [RFC2707] jmGeneralJobPersistence and
+ jmGeneralAttributePersistence objects.
+
+ For example, assume the following:
+
+ 1. A client performs a Job Creation operation that creates a
+ Subscription Object associated with the 'ippget' Delivery Method;
+
+ 2. An Event associated with the new Job occurs immediately after the
+ Subscription Object is created;
+
+ 3. the same client or some other client performs a Get-Notifications
+ operation so that the client is connected N seconds after the Job
+ Creation operation.
+
+ Then, if N is less than the value of this attribute, the client(s)
+ performing the Get-Notifications operations can expect not to miss
+ any Event-Notifications, barring some unforeseen lack of memory space
+ in the Printer. Note: The client MUST initiate the Get-
+ Notifications at a time that is sufficiently less that N seconds to
+ account for network latency so that it is connected to the Printer
+ before N seconds elapses.
+
+
+
+
+
+Herriot, et al. Standards Track [Page 18]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ If a Printer supports the 'ippget' Delivery Method, it MUST keep
+ 'completed', 'canceled', or 'aborted' Job objects in the Job
+ Retention and/or Job History phases for at least as long as this
+ attribute's value. The Printer MAY retain jobs longer that this
+ value. See [RFC2911], section 4.3.7.1, and the discussion in
+ [RFC3995] (regarding the 'job-completed' event). The latter explains
+ that a Notification Recipient can query the Job after receiving a
+ 'job-completed' Event Notification in order to find out other
+ information about the job that is 'completed', 'aborted', or
+ 'canceled'. However, this attribute has no effect on the Cancel-
+ Subscription operation, which deletes the Subscription object
+ immediately whether or not it contains the "notify-pull-method"
+ attribute with the 'ippget' keyword value. Immediately thereafter,
+ subsequent Get-Notifications Responses MUST NOT contain Event
+ Notifications associated with the canceled Subscription object.
+
+9. New Values for Existing Printer Description Attributes
+
+ This section defines additional values for existing Printer
+ Description attributes as defined in [RFC3995].
+
+9.1. notify-pull-method-supported (1setOf type2 keyword)
+
+ The following keyword value for the "notify-pull-method-supported"
+ attribute is added in order to support the new Delivery Method
+ defined in this document:
+
+ 'ippget': The IPP Notification Pull Delivery Method defined in
+ this document.
+
+9.2. operations-supported (1setOf type2 enum)
+
+ Table 7 lists the "operation-id" value defined in order to support
+ the new Get-Notifications operation defined in this document.
+
+ Table 7. Operation-id Assignments
+
+ Value Operation Name
+
+ 0x001C Get-Notifications
+
+10. New Status Codes
+
+ The following status code is defined as an extension for this
+ Delivery Method and is returned as the status code of the Get-
+ Notifications operation in Group 1 or Group 3 to N (see section 5.2).
+
+
+
+
+
+Herriot, et al. Standards Track [Page 19]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+10.1. successful-ok-events-complete (0x0007)
+
+ The Printer MUST return the 'successful-ok-events-complete' status
+ code to indicate when this Get-Notifications response is the last
+ response for a Subscription object, whether or not there are Event
+ Notifications being returned. This condition occurs for Event Wait
+ Mode with Notification Recipients waiting for responses when (1) the
+ Subscription Object is canceled with a Cancel-Subscription operation,
+ (2) the Subscription object is deleted, when the Per-Printer
+ Subscription lease time expires, or (3) the 'job-completed' event
+ occurs for a Per-Job Subscription. This condition also occurs for a
+ Get-Notifications request that a Notification Recipient makes after
+ the job completes, but before the Event Life expires.
+
+11. Encoding and Transport
+
+ This section defines the encoding and transport considerations for
+ this Delivery Method based on [RFC2910].
+
+ The encoding of a Get-Notifications Response is modeled after the
+ Get-Jobs Response (see [RFC2911]). In a Get-Notifications Response,
+ each Event Notification Attributes Group MUST start with an 'event-
+ notification-attributes-tag' (see the section "Encodings of
+ Additional Attribute Tags" in [RFC3995]), and end with an 'end-of-
+ attributes-tag'. In addition, for Event Wait Mode the multi-
+ part/related is used to separate each multiple response (in time) to
+ a single Get-Notifications Request.
+
+ The Printer returns Get-Notification Response as follows:
+
+ 1. If the Notification Recipient client did not request Event Wait
+ Mode ("notify-wait" = 'false' or omitted), the Printer ends the
+ response with an 'end-of-attributes-tag' (see [RFC2911], Get-Jobs
+ encoding), as with any operation response.
+
+ 2. If the Notification Recipient client requests Event Wait Mode
+ ("notify-wait" = 'true') and the Printer wishes to honor the
+ request, the Printer MUST return the response as an
+ application/ipp part inside a multi-part/related MIME media type.
+ When one or more additional Events occur, the Printer returns
+ each as an additional Event Notification Group using a separate
+ application/ipp part under the multi-part/related type.
+
+ 3. If the client requested Event Wait Mode ("notify-wait" = 'true'),
+ but the Printer does not wish to honor the request in the initial
+ response and wants the client explicitly polled for Event
+ Notifications, the Printer MUST return the "notify-get-interval"
+ operation attribute (see section 5.2.1). The Printer returns the
+
+
+
+Herriot, et al. Standards Track [Page 20]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ response as an application/ipp part that MAY be inside an multi-
+ part/related type. The client MUST accept this response and
+ reissue the Get-Notifications request in the future indicated by
+ the value of the "notify-get-interval" attribute value.
+
+ 4. If the client requested Event Wait Mode ("notify-wait" = 'true'),
+ and the Printer initially honored the request but later wishes to
+ leave Event Wait Mode, the Printer MUST return the "notify-get-
+ interval" operation attribute (see section 5.2.1). The Printer
+ returns the response as an application/ipp part that MUST be
+ inside an multi-part/related type.
+
+ NOTE: If a Notification Recipient fails to receive a response, it
+ can ask the Printer for the same Event Notifications again. The
+ Notification Recipient will receive the same Event Notifications that
+ it should have received the first time, except for those Event
+ Notifications that have expired in the meantime.
+
+ The Printer MAY chunk the responses, but this has no significance to
+ the IPP semantics.
+
+ This notification delivery method uses the IPP transport and encoding
+ [RFC2910] for the Get-Notifications operation with the following
+ extension, allocated in [RFC3995]:
+
+ Table 8. The "event-notification-attributes-tag" Value
+
+ Tag Value (Hex) Meaning
+
+ 0x07 "event-notification-attributes-tag"
+
+12. Conformance Requirements
+
+ This section lists the conformance requirements for clients and
+ Printers.
+
+12.1. Conformance for IPP Printers
+
+ It is OPTIONAL for a Printer to support IPP Notifications as defined
+ in [RFC3995]. However, if a Printer supports IPP Notifications, the
+ Printer MUST support the 'ippget' Delivery Method, as defined in this
+ document, as one of its Delivery Methods. IPP Printers that conform
+ to this specification
+
+ 1. MUST meet the conformance requirements defined in [RFC3995] for a
+ Pull Delivery Method;
+
+
+
+
+
+Herriot, et al. Standards Track [Page 21]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ 2. MUST support the Get-Notifications operation defined in section
+ 5, including Event Wait Mode;
+
+ 3. MUST support the Subscription Template object attributes, as
+ defined in section 6;
+
+ 4. MUST support the Subscription Description object attributes, as
+ defined in section 7;
+
+ 5. MUST support the "ippget-event-life" Printer Description
+ attribute defined in section 8.1, including retaining jobs in the
+ Job Retention and/or Job History phases for at least as long as
+ the value specified by the Printer's "ippget-event-life";
+
+ 6. MUST support the additional values for IPP/1.1 Printer
+ Description attributes defined in section 9;
+
+ 7. MUST support the 'successful-ok-events-complete' status code, as
+ described in section 10.1;
+
+ 8. MUST listen for the IPP Get-Notifications operation requests on
+ IANA-assigned well-known port 631, unless explicitly configured
+ by system administrators or site policies;
+
+ 9. SHOULD NOT listen for IPP Get-Notifications operation requests on
+ any other port, unless explicitly configured by system
+ administrators or site policies; and
+
+ 10. MUST meet the security conformance requirements stated in section
+ 18.4.
+
+12.2. Conformance for IPP Clients
+
+ It is OPTIONAL for an IPP Client to support IPP Notifications as
+ defined in [RFC3995]. However, if a client supports IPP
+ Notifications, the client MUST support the 'ippget' Delivery Method
+ as defined in this document as one of its Delivery Methods. IPP
+ Clients that conform to this specification:
+
+ 1. MUST create Subscription Objects by sending Subscription Creation
+ operation requests containing the "notify-pull-method" attribute
+ (as opposed to the "notify-recipient-uri" attribute) using the
+ 'ippget' keyword value (see sections 6.1 and 15.2);
+
+ 2. MUST send IPP Get-Notifications operation requests (see section
+ 5.1) via the port specified in the associated 'ipp' URL (if
+ present) or otherwise via IANA-assigned well-known port 631;
+
+
+
+
+Herriot, et al. Standards Track [Page 22]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ 3. MUST convert the associated 'ipp' URLs for use in IPP Get-
+ Notifications operation to their corresponding 'http' URL forms
+ for use in the HTTP layer, according to the rules in section 5,
+ "IPP URL Scheme", in [RFC2910]; and
+
+ 4. MUST meet the security conformance requirements stated in section
+ 18.5.
+
+13. Normative References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P., Turner, R., and J.
+ Wenn, "Internet Printing Protocol/1.1: Encoding and
+ Transport", RFC 2910, September 2000.
+
+ [RFC2911] Hastings, T., Herriot, R., deBry, R., Isaacson, S., and
+ P. Powell, "Internet Printing Protocol/1.1: Model and
+ Semantics", RFC 2911, September 2000.
+
+ [RFC3995] Herriot, R. and T. Hastings, "Internet Printing Protocol
+ (IPP): Event Notifications and Subscriptions", RFC 3995,
+ March 2005.
+
+14. Informative References
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P., and R. Turner,
+ "Internet Printing Protocol/1.0: Encoding and
+ Transport", RFC 2565, April 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S., and
+ P. Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2567] Wright, F., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure of the Model
+ and Protocol for the Internet Printing Protocol", RFC
+ 2568, April 1999.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N., and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569, April
+ 1999.
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 23]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext
+ Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC2707] Bergman, R., Hastings, T., Isaacson, S., and H. Lewis,
+ "Job Monitoring MIB - V1.0", RFC 2707, November 1999.
+
+ [RFC3196] Hastings, T., Manros, C., Zehler, P., Kugler, C., and H.
+ Holst, "Internet Printing Protocol/1.1: Implementor's
+ Guide", RFC 3196, November 2001.
+
+ [RFC3997] Hastings, T., Ed., deBry, R., and H. Lewis, "Internet
+ Printing Protocol (IPP): Requirements for IPP
+ Notifications", RFC 3997, March 2005.
+
+15. IANA Considerations
+
+ This section contains the exact information that the IANA has added
+ to the IPP Registries according to the procedures defined in
+ [RFC2911], section 6. These registrations have been published in the
+ http://www.iana.org/assignments/ipp-registrations registry.
+
+15.1. Attribute Registrations
+
+ The following table lists the attributes defined in this document.
+ This has been registered according to the procedures in RFC 2911
+ [RFC2911] section 6.2.
+
+ Printer Description attributes: Reference Section
+ ------------------------------- --------- -------
+ ippget-event-life (integer(15:MAX)) [RFC3996] 8.1
+
+15.2. Delivery Method and Additional Keyword Attribute Value
+ Registrations for Existing Attributes
+
+ This section lists additional keyword attribute value registrations
+ for use with existing attributes defined in other documents. These
+ have been registered according to the procedures in [RFC2911],
+ section 6.1. According to [RFC3995], section 24.7.3, Pull Delivery
+ Method registrations are the keyword attribute value registrations
+ for the "notify-pull-method" and "notify-pull-method-supported"
+ attributes.
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 24]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ Attribute (attribute syntax)
+ Values Reference Section
+ ----------------------- --------- -------
+ notify-pull-method (type2 keyword) [RFC3995] 5.3.2
+ notify-pull-method-supported (1setOf type2 keyword)
+ [RFC3995] 5.3.2.1
+ ippget [RFC3996] 9.1
+
+15.3. Additional Enum Attribute Values
+
+ The following table lists the enum attribute values defined in this
+ document. These have been registered according to the procedures in
+ [RFC2911], section 6.1.
+
+ Attribute (attribute syntax)
+ Value Name Reference Section
+ ------ ----------------------------- --------- -------
+ operations-supported (1setOf type2 enum) [RFC2911] 4.4.15
+ 0x001C Get-Notifications [RFC3996] 9.2
+
+15.4. Operation Registrations
+
+ The following table lists the operations defined in this document.
+ This has been registered according to the procedures in RFC 2911
+ [RFC2911] section 6.4.
+
+ Operations: Reference Section
+ ----------- --------- -------
+ Get-Notifications [RFC3996] 5
+
+15.5. Status Code Registrations
+
+ The following table lists the status codes defined in this document.
+ This has been registered according to the procedures in [RFC2911],
+ section 6.6.
+
+ Status codes: Reference Section
+ ------------- --------- -------
+ successful-ok-events-complete (0x0007) [RFC3996] 10.1
+
+16. Internationalization Considerations
+
+ The IPP Printer MUST localize the "notify-text" attribute as
+ specified in section 14 of [RFC3995].
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 25]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ In addition, when the client receives the Get-Notifications response,
+ it is expected to localize the attributes that have the 'keyword'
+ attribute syntax according to the charset and natural language
+ requested in the Get-Notifications request.
+
+17. Security Considerations
+
+ The IPP Model and Semantics document [RFC2911, section 8] discusses
+ high-level security requirements (Client Authentication, Server
+ Authentication and Operation Privacy). The IPP Transport and
+ Encoding document [RFC2910, section 8] discusses the security
+ requirements for the IPP protocol. Client Authentication is the
+ mechanism by which the client proves its identity to the server in a
+ secure manner. Server Authentication is the mechanism by which the
+ server proves its identity to the client in a secure manner.
+ Operation Privacy is defined as a mechanism for protecting operations
+ from eavesdropping.
+
+ The 'ippget' Delivery Method with its Get-Notifications operations
+ leverages the security mechanism that are used in IPP/1.1 [RFC2910
+ and RFC2911] without adding any additional security mechanisms in
+ order to maintain the same security support as IPP/1.1.
+
+ The access control model for the Get-Notifications operation defined
+ in this document is the same as the access control model for the
+ Get-Job-Attributes operation (see [RFC2911], section 3.2.6). The
+ primary difference is that a Get-Notifications operation is directed
+ at Subscription Objects rather than at Job objects, and a returned
+ attribute group contains Event Notification attributes rather than
+ Job object attributes.
+
+17.1. Notification Recipient Client Access Rights
+
+ The Notification Recipient client MUST have the following access
+ rights to the Subscription object(s) targeted by the Get-
+ Notifications operation request:
+
+ The authenticated user (see [RFC2911], section 8.3) performing
+ this operation MUST be (1) the owner of each Subscription Object
+ identified by the "notify-subscription-ids" operation attribute
+ (see section 5.1.1), (2) an operator or administrator of the
+ Printer (see [RFC2911], sections 1 and 8.5), or (3) otherwise
+ authorized by the Printer's administrator-configured security
+ policy to request Event Notifications from the target Subscription
+ Object(s). Furthermore, the Printer's security policy MAY limit
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 26]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ the attributes returned by the Get-Notifications operation, in a
+ manner similar to that of the Get-Job-Attributes operation (see
+ [RFC2911], end of section 3.3.4.2).
+
+17.2. Printer Security Threats
+
+ Because the Get-Notifications operation is sent in the same direction
+ as are Job Creation operations, usually by the same client, this
+ Event Notification Delivery Method poses no additional
+ authentication, authorization, privacy, firewall, or port assignment
+ issues above those for the IPP Get-Job-Attributes and Get-Printer-
+ Attributes operations (see [RFC2911], sections 3.2.6 and 3.2.5).
+
+17.3. Notification Recipient Security Threats
+
+ Unwanted Events Notifications (spam): Unlike Push Event Notification
+ Delivery Methods in which the IPP Printer initiates the Event
+ Notification, with the Pull Delivery Method defined in this document,
+ the Notification Recipient is the client that initiates the Get-
+ Notifications operation (see section 5). Therefore, with this method
+ there is no chance of "spam" notifications.
+
+ Note: When a client stays connected to a Printer by using the Event
+ Wait Mode (see section 5.1.3) in order to receive Event Notifications
+ as they occur, it can close down the IPP connection at any time and
+ so can avoid future unwanted Event Notifications at any time.
+
+ It is true that the client has control over whether to ask for Event
+ Notifications. However, if the client subscribes to an event and
+ does a Get-Notifications request, it gets all events for the
+ Subscription Object in the sequence number range (see section 5.1.2),
+ not just those it wants. If a client subscribes to a Per-Printer
+ Subscription job event, such as 'job-completed', and someone then
+ starts and cancels thousands of jobs, the client would have to
+ receive these events in addition to those it is interested in. A
+ client can protect itself better by subscribing to its own jobs by
+ using a Per-Job Subscription, rather than create a Per-Printer
+ subscription whose Job events apply to all jobs.
+
+17.4. Security Requirements for Printers
+
+ For the Get-Notifications operation defined in this document, the
+ same Printer conformance requirements apply for supporting and using
+ Client Authentication, Server Authentication and Operation Privacy as
+ stated in [RFC2910] section 8 for all IPP operations.
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 27]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+17.5. Security Requirements for Clients
+
+ For the Get-Notifications operation defined in this document, the
+ same client conformance requirements apply for supporting and using
+ Client Authentication, Server Authentication, and Operation Privacy
+ as stated in [RFC2910], section 8, for all IPP operations.
+
+18. Description of Base IPP Documents (Informative)
+
+ The base set of IPP documents includes the following:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [RFC3196]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ "Design Goals for an Internet Printing Protocol" takes a broad look
+ at distributed printing functionality, and it enumerates real-life
+ scenarios that help clarify the features that need to be included in
+ a printing protocol for the Internet. It identifies requirements for
+ three types of users: end users, operators, and administrators. It
+ calls out a subset of end user requirements that are satisfied in
+ IPP/1.0 [RFC2566, RFC2565]. A few OPTIONAL operator operations have
+ been added to IPP/1.1.
+
+ "Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol" describes IPP from a high-level view, defines a
+ roadmap for the various documents that form the suite of IPP
+ specification documents, and gives background and rationale for the
+ IETF working group's major decisions.
+
+ "Internet Printing Protocol/1.1: Model and Semantics" describes a
+ simplified model with abstract objects, their attributes, and their
+ operations that are independent of encoding and transport. It
+ introduces a Printer and a Job object. The Job object optionally
+ supports multiple documents per Job. It also addresses security,
+ internationalization, and directory issues.
+
+ "Internet Printing Protocol/1.1: Encoding and Transport" is a formal
+ mapping of the abstract operations and attributes defined in the
+ model document onto HTTP/1.1 [RFC2616]. It defines the encoding
+ rules for a new Internet MIME media type called "application/ipp".
+ This document also defines the rules for transporting over HTTP a
+ message body whose Content-Type is "application/ipp". This document
+ defines the 'ipp' scheme for identifying IPP printers and jobs.
+
+
+
+Herriot, et al. Standards Track [Page 28]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+ "Internet Printing Protocol/1.1: Implementer's Guide" gives insight
+ and advice to implementers of IPP clients and IPP objects. It is
+ intended to help them understand IPP/1.1 and some of the
+ considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ "Mapping between LPD and IPP Protocols" gives some advice to
+ implementers of gateways between IPP and LPD (Line Printer Daemon)
+ implementations.
+
+19. Contributors
+
+ Carl Kugler and Harry Lewis contributed the basic idea of in-band
+ "smart polling" coupled with multiple responses for a single
+ operation on the same connection, with one response for each event as
+ it occurs. Without their continual persuasion, we would not have
+ arrived at this Delivery Method specification and would not have been
+ able to agree on a single REQUIRED Delivery Method for IPP.
+
+ Carl Kugler
+ IBM Corporation
+ 6300 Diagonal Highway
+ Boulder, CO 80301
+
+ EMail: kugler@us.ibm.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 29]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+Authors' Addresses
+
+ Robert Herriot
+ Global Workflow Solutions
+ 706 Colorado Ave.
+ Palo Alto, CA 94303
+
+ Phone: 650-324-4000
+ EMail: bob@herriot.com
+
+
+ Thomas N. Hastings
+ Xerox Corporation
+ 710 S Aviation Blvd. ESAE 242
+ El Segundo CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-6342
+ EMail: hastings@cp10.es.xerox.com
+
+
+ Harry Lewis
+ IBM Corporation
+ 6300 Diagonal Hwy
+ Boulder, CO 80301
+
+ Phone: (303) 924-5337
+ EMail: harryl@us.ibm.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 30]
+
+RFC 3996 IPP: The 'ippget' Delivery Method March 2005
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2005).
+
+ This document is subject to the rights, licenses and restrictions
+ contained in BCP 78, and except as set forth therein, the authors
+ retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the procedures with respect to rights in RFC documents can be
+ found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at ietf-
+ ipr@ietf.org.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+Herriot, et al. Standards Track [Page 31]
+
diff --git a/standards/rfc3997.txt b/standards/rfc3997.txt
new file mode 100644
index 000000000..3dc0e1eb5
--- /dev/null
+++ b/standards/rfc3997.txt
@@ -0,0 +1,955 @@
+
+
+
+
+
+
+Network Working Group T. Hastings, Ed.
+Request for Comments: 3997 Xerox Corporation
+Category: Informational R. K. deBry
+ Utah Valley State College
+ H. Lewis
+ IBM Corporation
+ March 2005
+
+
+ Internet Printing Protocol (IPP):
+ Requirements for IPP Notifications
+
+Status of This Memo
+
+ This memo provides information for the Internet community. It does
+ not specify an Internet standard of any kind. Distribution of this
+ memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2005).
+
+Abstract
+
+ This document is one of a set of documents that together describe all
+ aspects of the Internet Printing Protocol (IPP). IPP is an
+ application-level protocol that can be used for distributed printing
+ on the Internet. There are multiple parts to IPP, but the primary
+ architectural components are the Model, the Protocol, and an
+ interface to Directory Services. This document provides a statement
+ of the requirements for notifications as an optional part of an IPP
+ Service.
+
+Table of Contents
+
+ 1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . 2
+ 2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 2
+ 3. Scenarios . . . . . . . . . . . . . . . . . . . . . . . . . . 6
+ 4. Requirements. . . . . . . . . . . . . . . . . . . . . . . . . 10
+ 5. Security Considerations for IPP Notifications Requirements. . 12
+ 6. Internationalization Considerations . . . . . . . . . . . . . 13
+ 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 13
+ 8. References. . . . . . . . . . . . . . . . . . . . . . . . . . 14
+ 8.1. Normative References. . . . . . . . . . . . . . . . . . 14
+ 8.2. Informative References. . . . . . . . . . . . . . . . . 14
+ 9. Appendix A: Description of the Base IPP Documents . . . . . . 15
+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 16
+ Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 17
+
+
+
+Hastings, et al. Informational [Page 1]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+1. Introduction
+
+ This document is one of a set of documents that together describe all
+ aspects of the Internet Printing Protocol (IPP). IPP is an
+ application level protocol that can be used for distributed printing
+ on the Internet. There are multiple parts to IPP, but the primary
+ architectural components are the Model, the Protocol, and an
+ interface to Directory Services. This document provides a statement
+ of the requirements for notifications as an optional part of an IPP
+ Service. See section 10 for a description of the base IPP documents.
+
+ The scope of this requirements document covers functionality used by
+ the following kinds of IPP Users: End Users, Print Administrators,
+ and Operators. See [RFC3995] for the extensions to the Internet
+ Printing Protocol/1.0 (IPP) [RFC2565], [RFC2566], IPP/1.1 [RFC2911],
+ [RFC2910], and future versions.
+
+2. Terminology
+
+ It is necessary to define a set of terms to be able to clearly
+ express the requirements for notification services in an IPP System.
+
+2.1. Job-Submitting End User
+
+ A human end user who submits a print job to an IPP Printer. This
+ person may or may not be within the same security domain as the
+ Printer. This person may or may not be geographically near the
+ printer.
+
+2.2. Administrator
+
+ A human user who established policy for and configures the print
+ system.
+
+2.3. Operator
+
+ A human user who carries out the policy established by the
+ Administrator and controls the day-to-day running of the print
+ system.
+
+2.4. Job-Submitting Application
+
+ An application (for example, a batch application), acting on behalf
+ of a Job Submitting End User, that submits a print job to an IPP
+ Printer. The application may or may not be within the same security
+ domain as the Printer. This application may or may not be
+ geographically near the printer.
+
+
+
+
+Hastings, et al. Informational [Page 2]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+2.5. Security Domain
+
+ For the purposes of this discussion, the set of network components
+ that can communicate without going through a proxy or firewall. A
+ security domain may be geographically very large; for example,
+ anywhere within example.com.
+
+2.6. IPP Client
+
+ The software component that sends IPP requests to an IPP Printer
+ object and accepts IPP responses from an IPP Printer.
+
+2.7. Job Recipient
+
+ A human who is the ultimate consumer of the print job. In many cases
+ this will be the same person as the Job-Submitting End User, but this
+ need not always be the case. For example, if I use IPP to print a
+ document on a printer in a business partner's office, I am the Job-
+ Submitting End User, and the person whom I intend the document for in
+ my business partner's office is the Job Recipient. Since one of the
+ goals of IPP is to be able to print near the Job Recipient, we would
+ normally expect that person to be in the same security domain as, and
+ geographically near, the Printer. However, this may not always be
+ the case. For example, I submit a print job across the Internet to a
+ XYZ's print shop. I am both the Submitting End User and the Job
+ Recipient, but I am neither near nor in the same security domain as
+ the Printer.
+
+2.8. Job Recipient Proxy
+
+ A person acting on behalf of the Job Recipient. The Job Recipient
+ Proxy physically picks up the printed document from the Printer if
+ the Job Recipient cannot do so. The Proxy is by definition
+ geographically near and in the same security domain as the printer.
+ For example, I submit a print job from home to be printed on a
+ printer at work. I'd like my secretary to pick up the print job and
+ put it on my desk. In this case, I am acting as both a Job-
+ Submitting End User and a Job Recipient. My secretary is acting as a
+ Job Recipient Proxy.
+
+2.9. Notification Subscriber
+
+ A client that requests the IPP Printer to send Event Notifications to
+ one or more Notification Recipients. A Notification Subscriber may
+ be a Job-Submitting End User or an End User, an Operator, or an
+ Administrator that is not submitting a job.
+
+
+
+
+
+Hastings, et al. Informational [Page 3]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+2.10. Notification Source
+
+ The entity that sends Event Notifications.
+
+2.11. Notification Recipient
+
+ The entity that receives IPP Notifications about Job and/or Printer
+ events. A Notification Recipient may be a Job Submitting End User, a
+ Job-Submitting Application, a Job Recipient, a Job Recipient Proxy,
+ an Operator, an Administrator, etc., and his or her representative,
+ log file, usage statistics-gathering application, or other active or
+ passive entities.
+
+2.12. Notification Recipient Agent
+
+ A program that receives Event Notifications on behalf of the
+ Notification Recipient. The agent may take some action on behalf of
+ the recipient, forward the notification to the recipient via some
+ alternative means (for example, page the recipient), or queue the
+ notification for later retrieval by the recipient.
+
+2.13. Event
+
+ An Event is an occurrence (either expected or unexpected) within the
+ printing system of a change of state, condition, or configuration of
+ a Job or Printer object.
+
+2.14. Event Notification
+
+ When an event occurs, an Event Notification is generated that fully
+ describes the event (what the event was, where it occurred, when it
+ occurred, etc.). Event Notifications are delivered to all the
+ Notification Recipients that are subscribed to that Event, if any.
+ The Event Notification is delivered to the address of the
+ Notification Recipient by using the notification delivery method
+ defined in the subscription. However, an Event Notification is sent
+ ONLY if there is a corresponding subscription.
+
+2.15. Notification Subscription
+
+ A Notification Subscription is a request by a Notification Subscriber
+ to the IPP Printer to send Event Notifications to specified
+ Notification Recipient(s) when an event occurs.
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 4]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+2.16. Notification Attributes
+
+ IPP Objects (for example, a print job) from which notification are
+ being sent may have associated attributes. A user may want to have
+ one or more of these returned along with a particular notification.
+ In general, these may include any attribute associated with the
+ object emitting the notification. Examples include the following:
+
+ number-of-intervening jobs
+ job-k-octets
+ job-k-octets processed
+ job impressions
+ job-impressions-interpreted
+ job-impressions-completed
+ impressionsCompletedCurrentCopy (job MIB)
+ sheetCompletedCopyNumber (job MIB)
+ sheetsCompletedDocumentNumber (job MIB)
+ Copies-requested
+ Copy-type
+ Output-destination
+ Job-state-reasons
+ Job ID
+ Printer URI
+ Subscription ID (for job independent subscription)
+
+2.17. Notification Delivery Method (or Delivery Method for Short)
+
+ Event Notifications are delivered by using a Delivery Method. An
+ example of a Delivery Method is email.
+
+2.18. Immediate Notification
+
+ Notifications sent to the Notification Recipient or the Notification
+ Recipient's agent in such a way that the notification arrives
+ immediately, within the limits of common addressing, routing, network
+ congestion, and quality of service.
+
+2.19. Store-and-Forward Notification
+
+ Notifications that are not necessarily delivered to Notification
+ Recipients immediately but are queued for delivery by an intermediate
+ network application, for later retrieval. Email is an example of a
+ store-and-forward notification delivery method.
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 5]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+2.20. Reliable Delivery of Notifications
+
+ Notifications that are delivered by a reliable delivery of packets or
+ character stream, with acknowledgement and retry, so that delivery of
+ the notification is guaranteed within determinate time limits. For
+ example, if the Notification Recipient has logged off and gone home
+ for the day, an immediate notification cannot be guaranteed, even
+ when sent over a reliable transport, because there is nothing there
+ to catch it. Guaranteed delivery requires both store-and-forward
+ notification and a reliable transport.
+
+2.21. Notification over Unreliable Transport
+
+ Notifications are delivered via the fundamental transport address and
+ routing framework, but no acknowledgement or retry is required.
+ Process-to-process communications, if involved, are unconstrained.
+
+2.22. Human-Consumable Notification
+
+ Notifications intended to be consumed by human end users only. Email
+ would be an example of a Human-Consumable Notification, though it
+ could also contain Machine-Consumable Notification.
+
+2.23. Machine-Consumable Notification
+
+ Notifications that are intended for consumption by a program only,
+ such as an IPP Client. Machine-Consumable Notifications may not
+ contain human-readable information. Do we need both human and
+ machine? Machine readable is intended for application-to-application
+ only. The Notification Recipient could process the machine-readable
+ Event Notification into human-readable format.
+
+2.24. Mixed Notification
+
+ A mixed notification contains both Human-Consumable and Machine-
+ Consumable information.
+
+3. Scenarios
+
+ 1. Sitting in my office, I submit a print job to the printer down
+ the hall. I am in the same security domain as the printer and,
+ of course, geographically near. I want to know immediately when
+ my print job will be completed (or if there is a problem)
+ because the document I am working on is urgent. I submit the
+ print job with the following attributes:
+
+
+
+
+
+
+Hastings, et al. Informational [Page 6]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+ - Notification Recipient: Me
+ - Notification Events: All
+ - Notification Attributes: Job-state-reason
+ - Notification Type: Immediate
+
+ 2. Working from home, I submit a print job to the same printer as
+ in the previous example. However, I am not at work, I cannot
+ physically get the print file or do anything with it. It can
+ wait until I get to work this afternoon. However, I'd like my
+ secretary to pick up the output and put it on my desk so that it
+ doesn't get lost or misfiled. I'd also like a store-and-forward
+ notification sent to my email so that when I get to work I can
+ tell whether there was a problem with the print job. I submit a
+ print job with the following attributes:
+
+ - Notification Recipient: My secretary
+ - Notification Events: Print complete
+ - Notification Type: Immediate
+
+ - Notification Recipient: Me
+ - Notification Events: Print complete
+ - Notification Attributes: Impressions completed
+ - Notification Type: Store and forward
+
+ 3. Sitting in my office, I submit a print job to a client at an
+ engineering firm my company works with on a daily basis. The
+ engineering firm is in Belgium. I would like my client to know
+ when the print job is complete so that she can pick it up from
+ the printer in her building. It is important that she review it
+ right away and send her comments back to me. I submit the print
+ job with the following attributes:
+
+ - Notification Recipient: Client at engineering firm
+ - Notification Events: Print complete
+ - Notification Type: Immediate
+ - Notification Language: French
+
+ 4. From a hotel room, I send a print job to a Kinko's store in the
+ town I am working in, in order to get a printed report for the
+ meeting I am attending in the morning. As I'm going out to
+ dinner after I get this job submitted, an immediate notification
+ won't do me much good. However, I'd like to check in the
+ morning before I drive to the Kinko's store to see whether the
+ file has been printed. An email notification is sufficient for
+ this purpose. I submit the print job with the following
+ attributes:
+
+
+
+
+
+Hastings, et al. Informational [Page 7]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+ - Notification Recipient: Me
+ - Notification Events: Print complete
+ - Notification Type: Store and forward
+
+ 5. I am printing a large, complex print file. I want to have some
+ immediate feedback on the progress of the print job as it
+ prints. I submit the print job with the following attributes:
+
+ - Notification Recipient: Me
+ - Notification Type: Immediate
+ - Notification Events: All state transitions
+ - Notification Attributes: Impression completed
+
+ 6. I am an operator and one of my duties is to keep the printer
+ running. I subscribe independently from a job submission so
+ that my subscription outlasts any particular job. I subscribe
+ with the following attributes:
+
+ - Notification Recipient: Me
+ - Notification Type: Immediate
+ - Notification Events: All Printer state transitions
+ - Notification Attributes: Printer state, printer state
+ reasons, device powering up, device powering down
+
+ 7. I am a usage statistics gathering application. I subscribe
+ independently from a job submission so that my subscription
+ outlasts any particular job. My subscription may persist across
+ power cycles. I subscribe with the following attributes:
+
+ - Notification Recipient: Me
+ - Notification Type: Immediate
+ - Notification Events: Job completion
+ - Notification Attributes: Impression completed, sheets
+ completed, time submitted, time started, time completed, job
+ owner, job size in octets, etc.
+
+ 8. I am a client application program that displays a list of jobs
+ currently queued for printing on a printer. I display the
+ "job-name", "job-state", "job-state-reasons", "page-count", and
+ "intervening-jobs", either for the user's jobs or for all jobs.
+ The window displaying the job list remains open for an
+ independent amount of time, and it is desired that it represent
+ the current state of the queue. It is desired that the
+ application only perform a slow poll in order to recover from
+ any missed notifications. So the event delivery mechanism
+ provides the means to update the screen on all needed changes,
+ including querying for some attributes that may not be delivered
+ in the Notification.
+
+
+
+Hastings, et al. Informational [Page 8]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+ 9. I am a client application program that displays a list of
+ printers. For each Printer, I display the current state and
+ configuration. The window displaying the printer list remains
+ open for an independent amount of time, and it is desired that
+ it represent the current state of each printer. It is desired
+ that the application only need to perform a slow poll in order
+ to recover from any missed notifications. So the event delivery
+ mechanism provides the means to update the screen on all needed
+ changes, including querying for some attributes that may not be
+ delivered in the Notification.
+
+ 10. I am an IPP Server that controls one or more devices and that
+ implements an IPP Printer object to represent each device. I
+ want to support IPP Notification for each of the IPP Printer
+ objects that I implement. Many of these devices do not support
+ notification (or IPP). So I need to support the IPP
+ Notification semantics specified for each IPP Printer object
+ myself on behalf of each of the devices that each of the IPP
+ Printer objects represents. When I accept an IPP job creation
+ requests, I convert it to what the device will accept. In some
+ cases, I must poll the devices in order to be informed of their
+ job and device state and state changes to be able to send IPP
+ Notifications to subscribed Notification Recipients.
+
+ 11. I am an IPP Server that controls one or more devices and that
+ implements an IPP Printer object to represent each device. I
+ want to support IPP Notification for each of the IPP Printer
+ objects that I implement. These devices all support IPP,
+ including IPP Notification. I would like the design choice for
+ supporting IPP Notification for these objects either (1) by
+ forwarding the notification to the IPP Printers that I, alone,
+ control and have them send the notifications to the intended
+ Notification Recipients without my involvement, or (2) by
+ replacing the notification submitted with the Job to indicate me
+ as the Notification Recipient; in turn I will forward
+ Notifications to the Notification Recipients requested by my
+ clients. Most of the rest of the contents of the IPP Job I send
+ to the IPP Printers I control will be the same as those that I
+ receive from my IPP clients.
+
+ 12. I am an IPP Server that controls one or more devices and that
+ implements an IPP Printer object to represent each device. I
+ want to support IPP Notification for each of the IPP Printer
+ objects that I implement. These devices all support IPP,
+ including IPP Notification. Because these IPP Printers MAY also
+ be controlled by other servers (using IPP or other protocols), I
+ only want job events for the jobs that I send, but I do want
+ Printer events all the time, so that I can show proper Printer
+
+
+
+Hastings, et al. Informational [Page 9]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+ state to my clients. So I subscribe to these IPP Printers for
+ Printer events with a long-standing subscription, with myself as
+ the Notification Recipient. When I get a Job Creation request,
+ I decide to which IPP Printer to send the job. When I do so, I
+ also add a job subscription for Job events, with me as the
+ Notification Recipient to the job's job subscriptions supplied
+ by my clients (this usage is called "piggybacking"). These IPP
+ Printers automatically remove their job subscriptions when the
+ job finishes, as for all job subscriptions, so that I no longer
+ get Job events when my jobs are completed.
+
+4. Requirements
+
+ The following requirements are intended to be met by the IPP
+ Notification specification (not the implementation). The following
+ are true for the resulting IPP Notification Specification document:
+
+ 1. It must indicate which of these requirements are REQUIRED and
+ which are OPTIONAL for a conforming implementation to support.
+ See [RFC2911], section 12.1, for the definition of these
+ important conformance terms.
+
+ 2. It must be designed so that an IPP Printer can transparently
+ support the IPP Notification semantics by using third-party
+ notification services that exist today or that may be
+ standardized in the future.
+
+ 3. It must define a means for a Job-Submitting End User to specify
+ zero or more Notification Recipients when submitting a print job.
+ A Submitter will not be able to prevent out-of-band subscriptions
+ from authorized persons, such as Operators.
+
+ 4. It must define a means, when specifying a Notification Recipient,
+ for a Notification Subscriber to specify one or more notification
+ events for that Notification Recipient, subject to administrative
+ and security policy restrictions. Any of the following
+ constitute Job or Printer Events for which a Job Submitting End
+ User can specify that notifications be sent:
+
+ - Any standard Printer MIB alert
+ - Job Received (transition from Unknown to Pending)
+ - Job Started (transition from Pending to Processing)
+ - Page Complete (page is stacked)
+ - Collated Copy Complete (last sheet of collated copy is
+ stacked)
+
+
+
+
+
+
+Hastings, et al. Informational [Page 10]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+ - Job Complete (transition from Processing or Processing-stopped
+ to Completed)
+ - Job Aborted (transition from Pending, Pending-held,
+ - Processing, or Processing-stopped to Aborted)
+ - Job Canceled (transition from Pending, Pending-held,
+ - Processing, or Processing-held to Canceled)
+ - Other job state changes, such as paused, purged
+ - Device problems for which the job is destined
+ - Job (interpreter) issues
+
+ 5. It must define how an End User or Operator subscribes for
+
+ - any set of Job Events for a specific job, or
+ - any set of Printer Events while a specific job is not
+ complete.
+
+ 6. It must define how an End User or Operator subscribes for the
+ following without having to submit a Job:
+
+ - Any set of Printer Events for a defined period.
+ - Any set of Job Events for all jobs, with no control over
+ which jobs.
+
+ 7. It must define how the Notification Subscriber is able to
+ specify either immediate or store-and-forward notification
+ independently for each Notification Recipient. The means may be
+ explicit, or implied by the method of delivery chosen by the Job
+ Submitting End User.
+
+ 8. It must define common delivery methods: e.g., email.
+
+ 9. It must define how an IPP Printer validates its ability to
+ deliver an Event by using the specified delivery scheme. If it
+ does not support the specified scheme, or if the specified
+ scheme is invalid for some reason, then the IPP Printer accepts
+ and performs the request anyway and indicates the unsupported
+ attribute values. There is no requirement for the IPP Printer
+ receiving the print request to validate the identity of a
+ Notification Recipient, or the ability of the system to deliver
+ an event to that recipient as requested (for example, if the
+ Notification Recipient is not at work today).
+
+ 10. It must define a class of IPP event notification delivery
+ methods that can flow through corporate firewalls. However, an
+ IPP printer need not test to guarantee delivery of the
+ notification through a firewall before accepting a print job.
+
+
+
+
+
+Hastings, et al. Informational [Page 11]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+ 11. It may define a means to deliver a notification to the
+ submitting client when the delivery of an event notification to
+ a specified Notification Recipient fails. A fallback means of
+ subscribers to determine whether notifications have failed
+ (i.e., polling) may be provided.
+
+ 12. It must define a mechanism for localizing Human-Consumable
+ Notifications by the Notification Source.
+
+ 13. It may define a way to specify whether event delivery requires
+ acknowledgement back to the Notification Source.
+
+ 14. There must be a mechanism defined so that job-independent
+ subscriptions do not become stale and do not require human
+ intervention to be removed. However, a subscription must not be
+ deemed stale only if it is unable to deliver an Event
+ Notification, as temporary Notification delivery problems must
+ be tolerated.
+
+ 15. A mechanism must be defined so that an Event Subscriber is able
+ to add an Event Subscription to a Job after the Job has been
+ submitted.
+
+ 16. A mechanism must be defined so that a client is able to cancel
+ an Event Subscription on a job or printer after the job has been
+ submitted.
+
+ 17. A mechanism must be defined so that a client can obtain the set
+ of current Subscriptions.
+
+5. Security Considerations for IPP Notifications Requirements
+
+ By far the biggest security concern is the abuse of notification:
+ sending unwanted notifications sent to third parties (i.e., spam).
+ The problem is made worse by notification addresses that may be
+ redistributed to multiple parties (e.g., mailing lists). Scenarios
+ exist in which third-party notification is required (see scenarios 2
+ and 3). The fully secure solution would require active agreement of
+ all recipients before anything is sent out. However, requirement 9
+ ("There is no requirement for an IPP Printer receiving the print
+ request to validate the identity of an event recipient") argues
+ against this. Certain systems may decide to disallow third-party
+ notifications (a traditional fax model).
+
+ The same security issues are present when Clients submit notification
+ requests to the IPP Printer as when they submit an IPP/1.1 print job
+ request. The same mechanisms used by IPP/1.1 can therefore be used
+
+
+
+
+Hastings, et al. Informational [Page 12]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+ by the client notification submission. Operations that require
+ authentication can use the HTTP authentication. Operations that
+ require privacy can use the HTTP/TLS privacy.
+
+ The notification access control model should be similar to the IPP
+ access control model. Creating a notification subscription is
+ associated with a user. Only the creator or an operator can cancel
+ the subscription. The system may limit the listing of items to items
+ owned by the user. Some subscriptions (e.g., those that have a
+ lifetime longer than a job) can be done only by privileged users
+ (operators and/or administrators), if that is the authorization
+ policy.
+
+ The standard security concerns (delivery to the right user, privacy
+ of content, tamper-proof content) apply to the notification delivery.
+ IPP should use the security mechanism of the delivery method used.
+ Some delivery mechanisms are more secure than others. Therefore,
+ sensitive notifications should use the delivery method that has the
+ strongest security.
+
+6. Internationalization Considerations
+
+ The Human-Consumable Notification must be localized to the natural
+ language and charset that Notification Subscriber specifies within
+ the choice of natural languages and charsets that the IPP Printer
+ supports.
+
+ The Machine-Consumable Notification data uses the "application/ipp"
+ MIME media type. It contains attributes whose text values are
+ required to be in the natural language and charset that the
+ Notification Subscriber specifies within the choice of natural
+ languages and charsets that the IPP Printer supports. See [RFC2566].
+
+7. IANA Considerations
+
+ Some notification delivery methods have been registered with IANA for
+ use in URLs. These will be defined in other documents.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 13]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+8. References
+
+8.1. Normative References
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P., Turner, R., and J.
+ Wenn, "Internet Printing Protocol/1.1: Encoding and
+ Transport", RFC 2910, September 2000.
+
+ [RFC2911] Hastings, T., Herriot, R., deBry, R., Isaacson, S., and
+ P. Powell, "Internet Printing Protocol/1.1: Model and
+ Semantics", RFC 2911, September 2000.
+
+ [RFC3995] Herriot, R. and T. Hastings, "Internet Printing Protocol
+ (IPP): Event Notifications and Subscriptions", RFC 3995,
+ March 2005.
+
+8.2. Informative References
+
+ [RFC2565] Herriot, R., Butler, S., Moore, P., and R. Turner,
+ "Internet Printing Protocol/1.0: Encoding and Transport",
+ RFC 2565, April 1999.
+
+ [RFC2566] deBry, R., Hastings, T., Herriot, R., Isaacson, S., and
+ P. Powell, "Internet Printing Protocol/1.0: Model and
+ Semantics", RFC 2566, April 1999.
+
+ [RFC2567] Wright, F., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure of the Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N., and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569, April
+ 1999.
+
+ [RFC2639] Hastings, T., Manros, C., Zehler, P., Kugler, C., and H.
+ Holst, "Internet Printing Protocol/1.1: Implementor's
+ Guide", RFC 3196, November 2001.
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 14]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+9. Appendix A: Description of the Base IPP Documents
+
+ The base set of IPP documents includes the following:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [RFC3196]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ "Design Goals for an Internet Printing Protocol" takes a broad look
+ at distributed printing functionality, and it enumerates real-life
+ scenarios that help clarify the features that need to be included in
+ a printing protocol for the Internet. It identifies requirements for
+ three types of users: end users, operators, and administrators. It
+ calls out a subset of end-user requirements that are satisfied in
+ IPP/1.0 [RFC2566], [RFC2565]. A few OPTIONAL operator operations
+ have been added to IPP/1.1 [RFC2911], [RFC2910].
+
+ "Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol" describes IPP from a high-level view, defines a
+ roadmap for the various documents that form the suite of IPP
+ specification documents, and gives background and rationale for the
+ IETF IPP working group's major decisions.
+
+ "Internet Printing Protocol/1.1: Model and Semantics" describes a
+ simplified model with abstract objects, their attributes, and their
+ operations. The model introduces a Printer and a Job. The Job
+ supports multiple documents per Job. The model document also
+ addresses security, internationalization, and directory issues.
+
+ "Internet Printing Protocol/1.1: Encoding and Transport" is a formal
+ mapping of the abstract operations and attributes defined in the
+ model document onto HTTP/1.1 [RFC2616]. It also defines the encoding
+ rules for a new Internet MIME media type called "application/ipp".
+ This document also defines the rules for transporting over HTTP a
+ message body whose Content-Type is "application/ipp". This document
+ defines the "ipp" scheme for identifying IPP printers and jobs.
+
+ "Internet Printing Protocol/1.1: Implementer's Guide" gives insight
+ and advice to implementers of IPP clients and IPP objects. It is
+ intended to help them understand IPP/1.1 and some of the
+ considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+
+
+Hastings, et al. Informational [Page 15]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+ "Mapping between LPD and IPP Protocols" gives some advice to
+ implementers of gateways between IPP and LPD (Line Printer Daemon )
+ implementations.
+
+Authors' Addresses
+
+ Tom Hastings (editor)
+ Xerox Corporation
+ 701 S Aviation Blvd, ESAE 242
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-6342
+ EMail: hastings@cp10.es.xerox.com
+
+
+ Roger deBry
+ Utah Valley State College
+
+ Phone: (801) 863-8848
+ EMail: debryro@uvsc.edu
+
+
+ Harry Lewis
+ IBM Corporation
+ 6300 Diagonal Hwy
+ Boulder, CO 80301
+
+ Phone: (303) 924-5337
+ EMail: harryl@us.ibm.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 16]
+
+RFC 3997 IPP: Notification Requirements March 2005
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2005).
+
+ This document is subject to the rights, licenses and restrictions
+ contained in BCP 78, and except as set forth therein, the authors
+ retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the procedures with respect to rights in RFC documents can be
+ found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at ietf-
+ ipr@ietf.org.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+Hastings, et al. Informational [Page 17]
+
diff --git a/standards/rfc3998.txt b/standards/rfc3998.txt
new file mode 100644
index 000000000..f2ba35f80
--- /dev/null
+++ b/standards/rfc3998.txt
@@ -0,0 +1,2579 @@
+
+
+
+
+
+
+Network Working Group C. Kugler
+Request for Comments: 3998 H. Lewis
+Category: Standards Track IBM Corporation
+ T. Hastings, Ed.
+ Xerox Corporation
+ March 2005
+
+
+ Internet Printing Protocol (IPP):
+ Job and Printer Administrative Operations
+
+Status of This Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2005).
+
+Abstract
+
+ This document specifies the following 16 additional OPTIONAL system
+ administration operations for use with the Internet Printing
+ Protocol/1.1 (IPP), plus a few associated attributes, values, and
+ status codes, and using the IPP Printer object to manage printer
+ fan-out and fan-in.
+
+ Printer operations: Job operations:
+ Enable-Printer and Disable-Printer Reprocess-Job
+ Pause-Printer-After-Current-Job Cancel-Current-Job
+ Hold-New-Jobs and Release-Held-New-Jobs Suspend-Current-Job
+ Deactivate-Printer and Activate-Printer Resume-Job
+ Restart-Printer Promote-Job
+ Shutdown-Printer and Startup-Printer Schedule-Job-After
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 1]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+Table of Contents
+
+ 1. Introduction.................................................. 4
+ 2. Terminology................................................... 4
+ 2.1. Conformance Terminology................................. 4
+ 2.2. Other Terminology....................................... 5
+ 3. Definition of the Printer Operations.......................... 6
+ 3.1. The Disable and Enable Printer Operations............... 7
+ 3.1.1. Disable-Printer Operation....................... 7
+ 3.1.2. Enable-Printer Operation........................ 8
+ 3.2. The Pause and Resume Printer Operations................. 8
+ 3.2.1. Pause-Printer-After-Current-Job Operation....... 9
+ 3.3. Hold and Release New Jobs Operations.................... 11
+ 3.3.1. Hold-New-Jobs Operation......................... 11
+ 3.3.2. Release-Held-New-Jobs Operation................. 12
+ 3.4. Deactivate and Activate Printer Operations.............. 12
+ 3.4.1. Deactivate-Printer Operation.................... 13
+ 3.4.2. Activate-Printer Operation...................... 13
+ 3.5. Restart-Printer, Shutdown-Printer,
+ and Startup-Printer Operations.......................... 14
+ 3.5.1. Restart-Printer Operation....................... 14
+ 3.5.2. Shutdown-Printer Operation...................... 14
+ 3.5.3. Startup-Printer Operation....................... 15
+ 4. Definition of the Job Operations.............................. 16
+ 4.1. Reprocess-Job Operation................................. 17
+ 4.2. Cancel-Current-Job Operation............................ 17
+ 4.3. Suspend and Resume Job Operations....................... 18
+ 4.3.1. Suspend-Current-Job Operation................... 19
+ 4.3.2. Resume-Job Operation............................ 20
+ 4.4. Job Scheduling Operations............................... 20
+ 4.4.1. Promote-Job Operation........................... 20
+ 4.4.2. Schedule-Job-After Operation.................... 21
+ 5. Additional Status Codes....................................... 23
+ 5.1. 'server-error-printer-is-deactivated' (0x050A).......... 23
+ 6. Use of Operation Attributes
+ That Are Messages from the Operator........................... 23
+ 7. New Printer Description Attributes............................ 26
+ 7.1. subordinate-printers-supported (1setOf uri)............. 26
+ 7.2. parent-printers-supported (1setOf uri).................. 26
+ 8. Additional Values for
+ the "printer-state-reasons" Printer Description Attribute..... 26
+ 8.1. 'hold-new-jobs' Value................................... 27
+ 8.2. 'deactivated' Value..................................... 27
+ 9. Additional Values for
+ the "job-state-reasons" Job Description attribute............. 27
+ 9.1. 'job-suspended' Value................................... 27
+ 10. Use of the Printer Object to Represent
+ IPP Printer Fan-Out and IPP Printer Fan-In.................... 27
+
+
+
+Kugler, et al. Standards Track [Page 2]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ 10.1. IPP Printer Fan-Out..................................... 28
+ 10.2. IPP Printer Fan-In...................................... 28
+ 10.3. Printer Object Attributes Used
+ to Represent Printer Fan-Out and Printer Fan-In......... 29
+ 10.4. Subordinate Printer URI................................. 29
+ 10.5. Printer Object Attributes Used
+ to Represent Output Device Fan-Out...................... 30
+ 10.6. Figures to Show All Possible Configurations............. 30
+ 10.7. Forwarding Requests..................................... 33
+ 10.7.1. Forwarding Requests
+ that Affect Printer Objects..................... 33
+ 10.7.2. Forwarding Requests that Affect Jobs............ 35
+ 10.8. Additional Attributes to Help with Fan-Out.............. 37
+ 10.8.1. output-device-assigned (name(127))
+ Job Description Attribute - from [RFC2911]...... 37
+ 10.8.2. original-requesting-user-name (name(MAX))
+ Operation and Job Description Attribute......... 37
+ 10.8.3. requesting-user-name (name(MAX))
+ Operation Attribute - Additional Semantics...... 38
+ 10.8.4. job-originating-user-name (name(MAX))
+ Job Description Attribute -
+ Additional Semantics............................ 38
+ 11. Conformance Requirements...................................... 38
+ 12. Normative References.......................................... 39
+ 13. Informative References........................................ 40
+ 14. IANA Considerations........................................... 40
+ 14.1. Attribute Registrations................................. 41
+ 14.2. Attribute Value Registrations........................... 41
+ 14.3. Additional Enum Attribute Value Registrations........... 41
+ 14.4. Operation Registrations................................. 42
+ 14.5. Status Code Registrations............................... 43
+ 15. Internationalization Considerations........................... 43
+ 16. Security Considerations....................................... 43
+ 17. Summary of Base IPP Documents................................. 44
+ Authors' Addresses................................................ 45
+ Full Copyright Statement.......................................... 46
+
+List of Tables
+
+ Table 1. Printer Operation Operation-Id Assignments.............. 6
+ Table 2. Pause and Resume Printer Operations..................... 9
+ Table 3. State Transition Table for
+ Pause-Printer-After-Current-Job Operation............... 10
+ Table 4. Job Operation Operation-Id Assignments.................. 16
+ Table 5. Operation Attribute Support for Printer Operations...... 24
+ Table 6. Operation Attribute Support for Job Operations.......... 25
+ Table 7. Forwarding Operations that Affect Printer Objects....... 34
+ Table 8. Forwarding Operations that Affect Jobs Objects.......... 36
+
+
+
+Kugler, et al. Standards Track [Page 3]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Table 9. Conformance Requirement Dependencies for Operations..... 38
+ Table 10. Conformance Requirement Dependencies
+ for "printer-state-reasons" Values...................... 39
+ Table 11. Conformance Requirement Dependencies
+ for "job-state-reasons" Values.......................... 39
+
+List of Figures
+
+ Figure 1. Embedded Printer Object................................ 31
+ Figure 2. Hosted Printer Object.................................. 31
+ Figure 3. Output Device Fan-Out.................................. 31
+ Figure 4. Chained IPP Printer Objects............................ 32
+ Figure 5. IPP Printer Object Fan-Out............................. 32
+ Figure 6. IPP Printer Object Fan-In.............................. 33
+
+1. Introduction
+
+ The Internet Printing Protocol (IPP) is an application level protocol
+ that can be used for distributed printing using Internet tools and
+ technologies. IPP version 1.1 ([RFC2911, RFC2910]) focuses on end-
+ user functionality, with a few administrative operations included.
+ This document defines additional OPTIONAL end user, operator, and
+ administrator operations used to control Jobs and Printers. In
+ addition, this document extends the semantic model of the Printer
+ object by allowing them to be configured into trees and/or inverted
+ trees that represent Printer object Fan-Out and Printer object Fan-
+ In, respectively. The special case of a tree with only a single
+ Subordinate node represents Chained Printers. This document is a
+ registration proposal for an extension to IPP/1.0 and IPP/1.1
+ following the registration procedures in those documents.
+
+ The requirements and use cases for this document are defined in
+ [RFC3239].
+
+2. Terminology
+
+ This section defines the terminology used throughout this document.
+
+2.1. Conformance Terminology
+
+ Capitalized terms such as MUST, MUST NOT, REQUIRED, SHOULD, SHOULD
+ NOT, MAY, NEED NOT, and OPTIONAL have special meaning relating to
+ conformance as defined in RFC 2119 [RFC2119] and [RFC2911], section
+ 12.1. If an implementation supports the extension defined in this
+ document, then these terms apply; otherwise, they do not. These
+ terms define conformance to this document only; they do not affect
+ conformance to other documents, unless explicitly stated otherwise.
+
+
+
+
+Kugler, et al. Standards Track [Page 4]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+2.2. Other Terminology
+
+ This document uses terms such as "client", "Printer", "Job",
+ "attributes", "keywords", "operation", and "support". These terms
+ have special meaning and are defined in the model terminology
+ ([RFC2911], section 12.2).
+
+ In addition, the following capitalized terms are defined:
+
+ IPP Printer object (or Printer for short) - A software abstraction
+ defined by [RFC2911].
+
+ Printer Operation - An operation whose target is an IPP Printer
+ object and whose effect is on the Printer object.
+
+ Output Device - The physical imaging mechanism that an IPP Printer
+ controls. Note: although this term is capitalized in this
+ specification (but not in [RFC2911]), there is no formal object
+ called an Output Device defined in this document (or in [RFC2911]).
+
+ Output Device Fan-Out - A configuration in which an IPP Printer
+ controls more than one Output Device.
+
+ Printer Fan-Out - A configuration in which an IPP Printer object
+ controls more than one Subordinate IPP Printer object.
+
+ Printer Fan-In - A configuration in which an IPP Printer object is
+ controlled by more than one IPP Printer object.
+
+ Subordinate Printer - An IPP Printer object that is controlled by
+ another IPP Printer object. Such a Subordinate Printer MAY have zero
+ or more Subordinate Printers.
+
+ Leaf Printer - An IPP Printer object that has no Subordinate
+ Printers.
+
+ Non-Leaf Printer - An IPP Printer object that has one or more
+ Subordinate Printers. A Non-Leaf Printer is also called a Parent
+ Printer.
+
+ Chained Printer - a Non-Leaf Printer that has exactly one Subordinate
+ Printer.
+
+ Job Creation operations - IPP operations that create a Job object:
+ Print-Job, Print-URI, and Create-Job.
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 5]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+3. Definition of the Printer Operations
+
+ All Printer Operations are directed at Printer objects. A client
+ MUST always supply the "printer-uri" operation attribute in order to
+ identify the correct target of the operation. These descriptions
+ assume all of the common semantics of the IPP/1.1 Model and Semantics
+ document ([RFC2911], section 3.1).
+
+ The Printer Operations defined in this document are summarized in
+ Table 1.
+
+ Table 1. Printer Operation Operation-Id Assignments
+
+ Operation Name Operation-Id Brief Description
+ --------------------------------------------------------------------
+ Enable-Printer 0x22 Allows the target Printer to accept
+ Job Creation operations.
+
+ Disable-Printer 0x23 Prevents the target Printer from
+ accepting Job Creation operations.
+
+ Pause-Printer- 0x24 Pauses the Printer after the current
+ After-Current- job has been sent to the Output
+ Job Device.
+
+ Hold-New-Jobs 0x25 Finishes processing all currently
+ pending jobs. Any new jobs are
+ placed in the 'pending-held' state.
+
+ Release-Held- 0x26 Releases all jobs to the 'pending'
+ New-Jobs state that had been held by the
+ effect of a previous Hold-New-Jobs
+ operation and condition the Printer
+ so that it no longer holds new jobs.
+
+ Deactivate- 0x27 Puts the Printer into a read-only
+ Printer deactivated state.
+
+ Activate- 0x28 Restores the Printer to normal
+ Printer activity.
+
+ Restart-Printer 0x29 Restarts the target Printer and re-
+ initializes the software.
+
+ Shutdown- 0x2A Shuts down the target Printer so that
+ Printer it cannot be restarted or queried.
+
+
+
+
+
+Kugler, et al. Standards Track [Page 6]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Startup-Printer 0x2B Starts up the instance of the Printer
+ object.
+
+ All of the operations in this document are OPTIONAL for an IPP object
+ to support. Unless the specification of an OPTIONAL operation
+ requires support of another OPTIONAL operation, conforming
+ implementations may support any combination of these operations.
+ Many of the operations come in pairs, so both are REQUIRED if either
+ one is implemented.
+
+3.1. The Disable and Enable Printer Operations
+
+ This section defines the OPTIONAL Disable-Printer and Enable-Printer
+ operations that stop and start the IPP Printer object from accepting
+ new IPP jobs. If either of these operations are supported, both MUST
+ be supported.
+
+ These operations allow the operator to control whether the Printer
+ will accept new Job Creation (Print-Job, Print-URI, and Create-Job)
+ operations. These operations have no other effect on the Printer, so
+ the Printer continues to accept all other operations and continues to
+ schedule and process jobs normally. In other words, these operations
+ control the "input of new jobs" to the IPP Printer, and the Pause and
+ Resume operations (see section 3.2) independently control the "output
+ of new jobs" from the IPP Printer to the Output Device.
+
+3.1.1. Disable-Printer Operation
+
+ This OPTIONAL operation allows a client to stop the Printer object
+ from accepting new jobs; i.e., it causes the Printer to reject
+ subsequent Job Creation operations and return the 'server-error-not-
+ accepting-jobs' status code. The Printer still accepts all other
+ operations, including Validate-Job, Send-Document, and Send-URI
+ operations. Thus a Disable-Printer operation allows a client to
+ continue submitting multiple documents of a multiple document job if
+ the Create-Job operation had already been accepted. All previously
+ created or submitted Jobs and all Jobs currently processing continue
+ unaffected.
+
+ The IPP Printer MUST accept the request in any state. The Printer
+ sets the value of its "printer-is-accepting-jobs" READ-ONLY Printer
+ Description attribute to 'false' (see [RFC2911], section 4.4.20), no
+ matter what the previous value was. This operation has no immediate
+ or direct effect on the Printer's "printer-state" and "printer-
+ state-reasons" attributes.
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 7]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be an operator or administrator of the
+ Printer object (see [RFC2911] sections 1 and 8.5).
+
+ The Disable-Printer Request and Disable-Printer Response have the
+ same attribute groups and attributes as do the Pause-Printer
+ operation (see [RFC2911], sections 3.2.7.1 and 3.2.7.2), including
+ the new "printer-message-from-operator" operation attribute (see
+ section 6).
+
+3.1.2. Enable-Printer Operation
+
+ This OPTIONAL operation allows a client to start the Printer object
+ accepting jobs; i.e., it causes the Printer to accept subsequent Job
+ Creation operations. The Printer still accepts all other operations.
+ All previously submitted and currently processing Jobs continue
+ unaffected.
+
+ The IPP Printer MUST accept the request in any state. The Printer
+ sets the value of its "printer-is-accepting-jobs" READ-ONLY Printer
+ Description attribute to 'true' (see [RFC2911], section 4.4.20), no
+ matter what the previous value was. This operation has no immediate
+ or direct effect on the Printer's "printer-state" and "printer-
+ state-reasons" attributes.
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be an operator or administrator of the
+ Printer object (see [RFC2911] sections 1 and 8.5).
+
+ The Enable-Printer Request and Enable-Printer Response have the same
+ attribute groups and attributes as does the Pause-Printer operation
+ (see [RFC2911], sections 3.2.8.1 and 3.2.8.2), including the new
+ "printer-message-from-operator" operation attribute (see section 6).
+
+3.2. The Pause and Resume Printer Operations
+
+ This section leaves the OPTIONAL IPP/1.1 Pause-Printer (see
+ [RFC2911], sections 3.2.7) ambiguous as to whether it stops the
+ Printer immediately or after the current job. It also defines the
+ OPTIONAL Pause-Printer-After-Current-Job operation as following the
+ current job. These operations affect the scheduling of IPP jobs. If
+ either of these Pause Printer operations are supported, then the
+ Resume-Printer operation MUST be supported.
+
+ These operations allow the operator to control whether the Printer
+ will send new IPP jobs to the associated Output Device(s) that the
+ IPP Printer object represents. These operations have no other effect
+ on the Printer, so the Printer continues to accept all operations.
+
+
+
+Kugler, et al. Standards Track [Page 8]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ In other words, these operations control the "output of new jobs" to
+ the Output Device(s), and the Disable and Enable Printer Operations
+ (see section 3.1) independently control the "input of new jobs" to
+ the IPP Printer.
+
+ Table 2. Pause and Resume Printer Operations
+
+ Pause and Resume Printers Description
+ --------------------------------------------------------------------
+ IPP/1.1 Pause Printer Stops the IPP Printer from sending
+ new IPP Jobs to the Output Device(s)
+ either immediately or after the
+ current job completes, depending on
+ implementation, as defined in
+ [RFC2911].
+
+ Pause-Printer-After- Stops the IPP Printer from sending
+ Current-Job new IPP Jobs to the Output Device(s)
+ after the current jobs finish.
+
+ Resume-Printer Starts the IPP Printer sending IPP
+ Jobs to the Output Device again.
+
+3.2.1. Pause-Printer-After-Current-Job Operation
+
+ This OPTIONAL operation allows a client to stop the Printer object
+ from sending IPP jobs to any of its Output Devices or Subordinate
+ Printers. If the IPP Printer is in the middle of sending an IPP job
+ to an Output Device or Subordinate Printer, the IPP Printer MUST
+ complete sending that Job. However, after receiving this operation,
+ the IPP Printer MUST NOT send any additional IPP jobs to any of its
+ Output Devices or Subordinate Printers. In addition, after having
+ received this operation, the IPP Printer MUST NOT start processing
+ any more jobs, so additional jobs MUST NOT enter the 'processing'
+ state.
+
+ If the IPP Printer is not sending an IPP Job to the Output Device or
+ Subordinate Printer (whether or not the Output Device or Subordinate
+ Printer is busy processing any jobs), the IPP Printer object
+ transitions immediately to the 'stopped' state by setting its
+ "printer-state" attribute to 'stopped', removing the 'moving-to-
+ paused' value, if present, from its "printer-state-reasons"
+ attribute, and adding the 'paused' value to its "printer-state-
+ reasons" attribute.
+
+ If the implementation will take appreciable time to complete sending
+ an IPP job that it has started sending to an Output Device or
+ Subordinate Printer, the IPP Printer adds the 'moving-to-paused'
+
+
+
+Kugler, et al. Standards Track [Page 9]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ value to the Printer object's "printer-state-reasons" attribute (see
+ section [RFC2911], 4.4.12). When the IPP Printer has completed
+ sending IPP jobs that it was in the process of sending, the Printer
+ object transitions to the 'stopped' state by setting its "printer-
+ state" attribute to 'stopped', removing the 'moving-to-paused' value,
+ if present, from its "printer-state-reasons" attribute, and adding
+ the 'paused' value to its "printer-state-reasons" attribute.
+
+ This operation MUST NOT affect the acceptance of Job Creation
+ requests (see Disable-Printer Operation, section 3.1.1).
+
+ For any jobs that are 'pending' or 'pending-held', the 'printer-
+ stopped' values of the jobs' "job-state-reasons" attribute also
+ apply. However, the IPP Printer NEED NOT update those jobs' "job-
+ state-reasons" attributes and only have to return the 'printer-
+ stopped' value when those jobs are queried by using the Get-Job-
+ Attributes or Get-Jobs operations (so-called "lazy evaluation").
+
+ The IPP Printer MUST accept the request in any state and transition
+ the Printer to the indicated new "printer-state", and it MUST add the
+ indicated value to "printer-state-reasons" attribute before returning
+ as follows:
+
+ Table 3. State Transition Table for Pause-Printer-After-Current-Job
+ Operation
+
+ Current New "printer IPP Printer's response status
+ "printer- "printer- -state- code and action (REQUIRED/
+ state" state" reasons" OPTIONAL state transition for
+ a Printer to support):
+ --------------------------------------------------------------------
+ 'idle' 'stopped' 'paused' REQUIRED: 'successful-ok'
+
+ 'processing' 'processing' 'moving- OPTIONAL: 'successful-ok';
+ to- Later, when the IPP Printer
+ paused' has finished sending IPP jobs
+ to an Output Device, the
+ "printer-state" becomes
+ 'stopped', and the 'paused'
+ value replaces the 'moving-to-
+ paused' value in the "printer-
+ state-reasons" attribute
+
+ 'processing' 'stopped' 'paused' REQUIRED: 'successful-ok';
+ the IPP Printer wasn't in the
+ middle of sending an IPP job
+ to an Output Device
+
+
+
+
+Kugler, et al. Standards Track [Page 10]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ 'stopped' 'stopped' 'paused' REQUIRED: 'successful-ok'
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be an operator or administrator of the
+ Printer object (see [RFC2911], sections 1 and 8.5).
+
+ The Pause-Printer-After-Current-Job Request and Pause-Printer-After-
+ Current-Job Response have the same attribute groups and attributes as
+ does the Pause-Printer operation (see [RFC2911], sections 3.2.7.1 and
+ 3.2.7.2), including the new "printer-message-from-operator" operation
+ attribute (see section 6).
+
+3.3. Hold and Release New Jobs Operations
+
+ This section defines operations to condition the Printer to hold any
+ new jobs and to release them.
+
+3.3.1. Hold-New-Jobs Operation
+
+ This OPTIONAL operation allows a client to condition the Printer to
+ complete the current 'pending' and 'processing' IPP Jobs but not to
+ start processing any subsequently created IPP Jobs. If the IPP
+ Printer is in the middle of sending an IPP job to an Output Device or
+ Subordinate Printer, the IPP Printer MUST complete sending that Job.
+ Furthermore, the IPP Printer MUST send all of the current 'pending'
+ IPP Jobs to the Output Device(s) or Subordinate IPP Printer
+ object(s). Any subsequently received Job Creation operations will
+ cause the IPP Printer to put the Job into the 'pending-held' state,
+ with the 'job-held-on-create' value being added to the job's "job-
+ state-reasons" attribute. Thus all newly accepted jobs will be
+ automatically held by the Printer.
+
+ When the Printer completes all the 'pending' and 'processing' jobs,
+ it enters the 'idle' state as usual. An operator monitoring Printer
+ state changes will know when the Printer has completed all current
+ jobs because the Printer enters the 'idle' state.
+
+ This operation MUST NOT affect the acceptance of Job Creation
+ requests (see Disable-Printer Operation, section 3.1.1), except to
+ put the Jobs into the 'pending-held' state, instead of the 'pending'
+ or 'processing' state.
+
+ The IPP Printer MUST accept the request in any state, MUST NOT
+ transition the Printer to any other "printer-state", and MUST add the
+ 'hold-new-jobs' value to the Printer's "printer-state-reasons"
+ attribute (whether the value was present or not).
+
+
+
+
+
+Kugler, et al. Standards Track [Page 11]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be an operator or administrator of the
+ Printer object (see [RFC2911], sections 1 and 8.5).
+
+ The Hold-New-Jobs Request and Hold-New-Jobs Response have the same
+ attribute groups and attributes as does the Pause-Printer operation
+ (see [RFC2911], sections 3.2.7.1 and 3.2.7.2), including the new
+ "printer-message-from-operator" operation attribute (see section 6).
+
+3.3.2. Release-Held-New-Jobs Operation
+
+ This OPTIONAL operation allows a client to undo the effect of a
+ previous Hold-New-Jobs operation. In particular, the Printer
+ releases all the jobs that it held as a consequence of a Hold-New-
+ Jobs operations; i.e., while the 'hold-new-jobs' value was present in
+ the Printer's "printer-state-reasons" attribute. In addition, the
+ Printer MUST accept this request in any state, MUST NOT transition
+ the Printer to any other "printer-state", and MUST remove the 'hold-
+ new-jobs' value from its "printer-state-reasons" attribute (whether
+ the value was present or not) so that the Printer no longer holds
+ newly created jobs.
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be an operator or administrator of the
+ Printer object (see [RFC2911], sections 1 and 8.5).
+
+ The Release-Held-New-Jobs Request and Release-Held-New-Jobs Response
+ have the same attribute groups and attributes as the Pause-Printer
+ operation (see [RFC2911], sections 3.2.7.1 and 3.2.7.2), including
+ the new "printer-message-from-operator" operation attribute (see
+ section 6).
+
+3.4. Deactivate and Activate Printer Operations
+
+ This section defines the OPTIONAL Deactivate-Printer and Activate-
+ Printer operations that stop and start the IPP Printer object from
+ accepting all requests except queries and performing work. If either
+ of these operations are supported, both MUST be supported.
+
+ These operations allow the operator to put the Printer into a dormant
+ read-only condition and to take it out of this condition.
+
+
+
+
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 12]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+3.4.1. Deactivate-Printer Operation
+
+ This OPTIONAL operation allows a client to stop the Printer object
+ from sending IPP jobs to any of its Output Devices or Subordinate
+ Printers (Pause-Printer-After-Current-Job) and to stop the Printer
+ object from accepting any requests but query requests. The Printer
+ performs a Disable-Printer and a Pause-Printer-After-Current-Job
+ operation immediately. If these two operations cannot be completed
+ immediately, it includes use of all of the "printer-state-reasons".
+ In addition, the Printer MUST immediately reject all requests, except
+ for Activate-Printer, queries (Get-Printer-Attributes, Get-Job-
+ Attributes, Get-Jobs, etc.), Send-Document, and Send-URI (so that
+ partial job submission can be completed, see section 3.1.1). The
+ Printer MUST then return the 'server-error-service-unavailable'
+ status code.
+
+ The IPP Printer MUST accept the request in any state. Immediately,
+ the Printer MUST set the 'deactivated' value in its "printer-state-
+ reasons" attribute. Note: neither the Disable-Printer nor the
+ Pause-Printer-After-Current-Job set the 'deactivated' value.
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be an operator or administrator of the
+ Printer object (see [RFC2911], sections 1 and 8.5).
+
+ The Deactivate-Printer Request and Deactivate-Printer Response have
+ the same attribute groups and attributes as does the Pause-Printer
+ operation (see [RFC2911], sections 3.2.7.1 and 3.2.7.2), including
+ the new "printer-message-from-operator" operation attribute (see
+ section 6).
+
+3.4.2. Activate-Printer Operation
+
+ This OPTIONAL operation allows a client to undo the effects of the
+ Deactivate-Printer; i.e., it allows the Printer object to start
+ sending IPP jobs to any of its Output Devices or Subordinate Printers
+ (Pause-Printer-After-Current-Job) and starts the Printer object from
+ accepting any requests. The Printer performs an Enable-Printer and a
+ Resume-Printer operation immediately. In addition, the Printer MUST
+ immediately start accepting all requests.
+
+ The IPP Printer MUST accept the request in any state. The Printer
+ MUST immediately remove the 'deactivated' value from its "printer-
+ state-reasons" attribute (whether it is present or not).
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be an operator or administrator of the
+ Printer object (see [RFC2911], sections 1 and 8.5).
+
+
+
+Kugler, et al. Standards Track [Page 13]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ The Activate-Printer Request and Activate-Printer Response have the
+ same attribute groups and attributes as the Pause-Printer operation
+ (see [RFC2911], sections 3.2.7.1 and 3.2.7.2), including the new
+ "printer-message-from-operator" operation attribute (see section 6).
+
+3.5. Restart-Printer, Shutdown-Printer, and Startup-Printer Operations
+
+ This section defines the OPTIONAL Restart-Printer, Shutdown-Printer,
+ and Startup-Printer operations that initialize, shutdown, and start
+ up the Printer object, respectively. Each of these operations is
+ OPTIONAL, and any combination MAY be supported.
+
+3.5.1. Restart-Printer Operation
+
+ This OPTIONAL operation allows a client to restart a Printer object
+ whose operation is in need of initialization because of incorrect or
+ erratic behavior; i.e., perform the effect of a software re-boot.
+ The implementation MUST attempt to save any information about Jobs
+ and the Printer object before re-initializing. However, this
+ operation MAY have drastic consequences on the running system, so the
+ client SHOULD first try the Deactivate-Printer operation to minimize
+ the effect on the current state of the system. The effects of
+ previous Disable-Printer, Pause Printer, and Deactivate-Printer
+ operations are lost.
+
+ The IPP Printer MUST accept the request in any state. The Printer
+ object MUST initialize its Printer's "printer-state" to 'idle',
+ remove the state reasons from its "printer-state-reasons" attribute,
+ and change its "printer-is-accepting-jobs" attribute to 'true'.
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be an operator or administrator of the
+ Printer object (see [RFC2911], sections 1 and 8.5).
+
+ The Restart-Printer Request and Restart-Printer Response have the
+ same attribute groups and attributes as does the Pause-Printer
+ operation (see [RFC2911], sections 3.2.8.1 and 3.2.8.2), including
+ the new "printer-message-from-operator" operation attribute (see
+ section 6).
+
+3.5.2. Shutdown-Printer Operation
+
+ This OPTIONAL operation allows a client to shutdown a Printer; i.e.,
+ to stop processing jobs without losing any jobs and to make the
+ Printer object unavailable for any operations using the IPP protocol.
+ There is no way to bring the instance of the Printer object back to
+ being used, except for the Startup-Printer (see section 3.5.3), which
+ starts up a new instance of the Printer object for hosted
+
+
+
+Kugler, et al. Standards Track [Page 14]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ implementations. The purpose of Shutdown-Printer is to shutdown the
+ Printer for an extended period, not to reset the device(s) or modify
+ a Printer attribute. See Restart-Printer (section 3.5.1) and
+ Startup-Printer (section 3.5.3) for the way to initialize the
+ software. See the Disable-Printer operation (section 3.1) for a way
+ for the client to stop the Printer from accepting Job Creation
+ requests without stopping processing or shutting down.
+
+ The Printer MUST add the 'shutdown' value (see [RFC2911], section
+ 4.4.11) immediately to its "printer-state-reasons" Printer
+ Description attribute. It then performs a Deactivate-Printer
+ operation (see section 3.4.1), which in turn performs Disable-Printer
+ and Pause-Printer-After-Current-Job operations).
+
+ Note: To shutdown the Printer after all the currently submitted jobs
+ have completed, the operator issues a Disable-Printer operation (see
+ section 3.1.1) and then waits until all the jobs have completed. The
+ Printer goes into the 'idle' state before issuing the Shutdown-
+ Printer operation.
+
+ The Printer object MUST accept this operation in any state and
+ transition the Printer object through the "printer-states" and
+ "printer-state-reasons" defined for the Pause-Printer-After-Current-
+ Job operation until the activity is completed and the Printer object
+ disappears.
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be an operator or administrator of the
+ Printer object (see [RFC2911], sections 1 and 8.5).
+
+ The Shutdown-Printer Request and Shutdown-Printer Response have the
+ same attribute groups and attributes as does the Pause-Printer
+ operation (see [RFC2911], sections 3.2.7.1 and 3.2.7.2), including
+ the new "printer-message-from-operator" operation attribute (see
+ section 6).
+
+3.5.3. Startup-Printer operation
+
+ This OPTIONAL operation allows a client to start up an instance of a
+ Printer object, provided that there isn't one already initiated. The
+ purpose of Startup-Printer is to allow a hosted implementation of the
+ IPP Printer object (i.e., a Server that implements an IPP Printer on
+ behalf of a networked or local Output Device) to be started after the
+ host is available (by means outside this document). See section
+ 3.5.1 for the way to initialize the software or reset the Output
+ Device(s) when the IPP Printer object has already been initiated.
+
+
+
+
+
+Kugler, et al. Standards Track [Page 15]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ The host MUST accept this operation only when the Printer object has
+ not been initiated. If the Printer object already exists, the host
+ must return the 'client-error-not-possible' status code.
+
+ The result of this operation MUST be with the Printer object's
+ "printer-state" set to 'idle', the state reasons removed from its
+ "printer-state-reasons" attribute, and its "printer-is-accepting-
+ jobs" attribute set to 'false'. Then the operator can reconfigure
+ the Printer before performing an Enable-Printer operation. However,
+ when a Printer is first powered up, it is RECOMMENDED that its
+ "printer-is-accepting-jobs" attribute be set to 'true' in order to
+ achieve easy "out of the box" operation.
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be an operator or administrator of the
+ Printer object (see [RFC2911], sections 1 and 8.5).
+
+ The Shutdown-Printer Request and Shutdown-Printer Response have the
+ same attribute groups and attributes as does the Pause-Printer
+ operation (see [RFC2911] sections 3.2.7.1 and 3.2.7.2), including the
+ new "printer-message-from-operator" operation attribute (see section
+ 6).
+
+4. Definition of the Job Operations
+
+ All Job operations are directed at Job objects. A client MUST always
+ supply some means to identify the Job object in order to select the
+ correct target of the operation. That job identification MAY either
+ be a single Job URI or a combination of a Printer URI and a Job ID.
+ The IPP object implementation MUST support both forms of
+ identification for every job.
+
+ The Job Operations defined in this document are summarized in Table
+ 4.
+
+ Table 4. Job Operation Operation-Id Assignments
+
+ Operation Name Operation-Id Brief description
+ --------------------------------------------------------------------
+ Reprocess-Job 0x2C Creates a copy of a completed target
+ job with a new Job ID and processes it.
+
+ Cancel-Current- 0x2D Cancels the current job on the target
+ Job Printer or the specified job if it is
+ the current job.
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 16]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Suspend- 0x2E Suspends the current processing job on
+ Current-Job the target Printer or the specified
+ job if it is the current job, allowing
+ other jobs to be processed instead.
+
+ Resume-Job 0x2F Resumes the suspended target job.
+
+ Promote-Job 0x30 Promotes the pending target job to be
+ next after the current job(s) complete.
+
+ Schedule-Job- 0x31 Schedules the target job immediately
+ After after the specified job, all other
+ scheduling factors being equal.
+
+4.1. Reprocess-Job Operation
+
+ This OPTIONAL operation is a create job operation that allows a
+ client to re-process a copy of a job that had been retained in the
+ queue after processing was completed, canceled, or aborted (see
+ [RFC2911], section 4.3.7.2). This operation is the same as the
+ Restart-Job operation (see [RFC2911], section 3.3.7), except that the
+ Printer creates a new job that is a copy of the target job and the
+ target job is unchanged. New values are assigned to the "job-uri"
+ and "job-id" attributes. The new job's Job Description attributes
+ that track job progress, such as "job-impressions-completed", "job-
+ media-sheets-completed", and "job-k-octets-processed", are
+ initialized to 0, as with any create job operation. The target job
+ moves to the Job History after a suitable period, independent of
+ whether one or more Reprocess-Job operations have been performed upon
+ it.
+
+ If the Set-Job-Attributes operation is supported, then the "job-
+ hold-until" operation attribute MUST be supported with at least the
+ 'indefinite' value, so that a client can modify the new job before it
+ is scheduled for processing by using the Set-Job-Attributes
+ operation. After modifying the job, the client can release the job
+ for processing by using the Release-Job operation specifying the
+ newly assigned "job-uri" or "job-id" for the new job.
+
+4.2. Cancel-Current-Job Operation
+
+ This OPTIONAL operation allows a client to cancel the current job on
+ the target Printer or the specified job if it is the current job on
+ the Printer. See [RFC2911], section 3.3.3, for the semantics of
+ canceling a job. Since a Job might already be marking by the time a
+ Cancel-Current-Job is received, some media sheet pages might print
+ before the job is actually terminated.
+
+
+
+
+Kugler, et al. Standards Track [Page 17]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ If the client does not supply a "job-id" operation attribute, the
+ Printer MUST accept the request and cancel the current job if there
+ is a current job in the 'processing' or 'processing-stopped' state;
+ otherwise, it MUST reject the request and return the 'client-error-
+ not-possible' status code. If more than one job is in the
+ 'processing' or 'processing-stopped' state, the one that is marking
+ is canceled, and the others are unaffected.
+
+ Warning: On a shared printer, there is a race condition. Between
+ the time when a user issues this operation and the time of its
+ acceptance, the current job might change to a different job. If the
+ user or operator is authenticated to cancel the new job, the wrong
+ job is canceled. To prevent this race from canceling the wrong job,
+ the client MAY supply the "job-id" operation attribute, which is
+ checked against the current job's job-id. If the job identified by
+ the "job-id" attribute is not the current job on the Printer (i.e.,
+ is not in the 'processing' or 'processing-stopped' state), the
+ Printer MUST reject this operation and return the 'client-error-not-
+ possible' status code. Otherwise, the Printer cancels the specified
+ job.
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must either be the job owner (as determined
+ in the Job Creation operation) or an operator or administrator of the
+ Printer object (see [RFC2911], sections 1 and 8.5).
+
+ The Cancel-Current-Job Request and Cancel-Current-Job Response have
+ the same attribute groups and attributes as does the Resume-Printer
+ operation (see [RFC2911], section 3.2.8), including the new "job-
+ message-from-operator" operation attribute (see section 6), with the
+ addition of the following Group 1 Operation attribute in the request:
+
+ "job-id" (integer(1:MAX)):
+ The client OPTIONALLY supplies this Operation attribute to verify
+ that the identified job is still the current job on the target
+ Printer object. The IPP object MUST support this operation
+ attribute if it supports this operation.
+
+4.3. Suspend and Resume Job Operations
+
+ This section defines the Suspend-Current-Job and Resume-Job
+ operations. These operations allow an operator or user to suspend a
+ job while it is processing, allowing other jobs to be processed, and
+ to resume the suspended job at a later point without losing any of
+ the output.
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 18]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ If either of these operations is supported, both MUST be supported.
+
+ The Hold-Job and Release-Job operations ([RFC2911], section 3.3.5)
+ are for holding and releasing held jobs, not suspending and resuming
+ suspended jobs.
+
+4.3.1. Suspend-Current-Job Operation
+
+ This OPTIONAL operation allows a client to stop the current job on
+ the target Printer or the specified job if it is the current job on
+ the Printer, to allow other jobs to be processed instead. The
+ Printer moves the current job or the target job to the 'processing-
+ stopped' state and sets the 'job-suspended' value (see section 9.1)
+ in the job's "job-state-reasons" attribute and processes other jobs.
+
+ If the client does not supply a "job-id" operation attribute, the
+ Printer MUST accept the request and suspend the current job if there
+ is a current job in the 'processing' or 'processing-stopped' state.
+ Otherwise, it MUST reject the request and return the 'client-error-
+ not-possible' status code. If more than one job is in the
+ 'processing' or 'processing-stopped' state, all of them are
+ suspended.
+
+ Warning: On a shared printer, there is a race condition. Between
+ the time when a user issues this operation and the time of its
+ acceptance, the current job might change to a different job. If the
+ user or operator is authenticated to suspend the new job, the wrong
+ job is suspended. To prevent this race from pausing the wrong job,
+ the client MAY supply the "job-id" operation attribute, which is
+ checked against the current job's job-id. If the job identified by
+ the "job-id" attribute is not the current job on the Printer (i.e.,
+ is not in the 'processing' or 'processing-stopped' state), the
+ Printer MUST reject this operation and return the 'client-error-not-
+ possible' status code. Otherwise, the Printer suspends the specified
+ job and processed other jobs.
+
+ The Printer MUST reject a Suspend-Current-Job request (and return the
+ 'client-error-not-possible') for a job that has been suspended, i.e.,
+ for a job in the 'processing-stopped' state, with the 'job-suspended'
+ value in its "job-state-reasons" attribute.
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be either the job owner (as determined
+ in the Job Creation operation) or an operator or administrator of the
+ Printer object (see [RFC2911], sections 1 and 8.5).
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 19]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ The Suspend-Current-Job Request and Suspend-Current-Job Response have
+ the same attribute groups and attributes as does the Pause-Printer
+ operation (see [RFC2911], section 3.2.8 ), including the new "job-
+ message-from-operator" operation attribute (see section 6), with the
+ addition of the following Group 1 Operation attribute in the request:
+
+ "job-id" (integer(1:MAX)):
+ The client OPTIONALLY supplies this Operation attribute to verify
+ that the identified job is still the current job on the target
+ Printer object. The IPP object MUST support this operation
+ attribute if it supports this operation.
+
+4.3.2. Resume-Job Operation
+
+ This OPTIONAL operation allows a client to resume the target job at
+ the point where it was suspended. The Printer moves the target job
+ to the 'pending' state and removes the 'job-suspended' value from the
+ job's "job-state-reasons" attribute.
+
+ If the target job is not in the 'processing-stopped' state, with the
+ 'job-suspended' value in the job's "job-state-reasons" attribute, the
+ Printer MUST reject the request and return the 'client-error-not-
+ possible' status code, since the job was not suspended.
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be either the job owner (as determined
+ in the Job Creation operation) or an operator or administrator of the
+ Printer object (see [RFC2911], sections 1 and 8.5).
+
+ The Resume-Job Request and Resume-Job Response have the same
+ attribute groups and attributes as the Release-Job operation (see
+ [RFC2911], section 3.3.6), including the new "job-message-from-
+ operator" operation attribute (see section 6).
+
+4.4. Job Scheduling Operations
+
+ This section defines jobs that allow an operator to control the
+ scheduling of jobs.
+
+4.4.1. Promote-Job Operation
+
+ This OPTIONAL operation allows a client to make the pending target
+ job be processed next after the current job completes. This
+ operation is especially useful in a production printing environment
+ where the operator is involved in job scheduling.
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 20]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ If the target job is in the 'pending' state, this operation does not
+ change the job's state but causes the job to be processed after the
+ current job(s) complete. If the target job is not in the 'pending'
+ state, the Printer MUST reject the request and return the 'client-
+ error-not-possible' status code.
+
+ If the Printer implements the "job-priority" Job Template attribute
+ (see [RFC2911], section 4.2.1), the Printer sets the job's "job-
+ priority" to the highest value supported (so that the job will print
+ before any of the other pending jobs). The Printer returns the
+ target job immediately after the current job(s) in a Get-Jobs
+ response (see [RFC2911], section 3.2.6) for the 'not-completed' jobs.
+
+ When the current job is completed, canceled, suspended (see section
+ 4.3.1), or aborted, the target of this operation is processed next.
+
+ If a client issues this request (again) before the target of the
+ operation of the original request started processing, the target of
+ this new request is processed first.
+
+ IPP is specified not to require queues for job scheduling, as there
+ are other implementation techniques for scheduling multiple jobs,
+ such as re-evaluating a criteria function for each job on a
+ scheduling cycle. However, if an implementation does implement
+ queues for jobs, then the Promote-Job operation puts the specified
+ job at the front of the queue. A subsequent Promote-Job operation
+ prior to the processing of the first job puts that specified job at
+ the front of the queue, so that it is "in front" of the previously
+ promoted job.
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be an operator or administrator of the
+ Printer object (see [RFC2911], sections 1 and 8.5).
+
+ The Promote-Job Request and Promote-Job Response have the same
+ attribute groups and attributes as does the Cancel-Job operation (see
+ [RFC2911], section 3.3.3), including the new "job-message-from-
+ operator" operation attribute (see section 6).
+
+4.4.2. Schedule-Job-After Operation
+
+ This OPTIONAL operation allows a client to request that the Printer
+ schedule the target job so that it will be processed immediately
+ after the specified predecessor job, all other scheduling factors
+ being equal. This operation is specially useful in a production
+ printing environment where the operator is involved in job
+ scheduling.
+
+
+
+
+Kugler, et al. Standards Track [Page 21]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ If the target job is in the 'pending' state, this operation does not
+ change the job's state but causes the job to be processed after the
+ preceding job completes. The preceding job can be in the target
+ 'pending', 'processing', or 'processing-stopped' state. If the
+ target job is not in the 'pending' state, or if the predecessor job
+ is not in the 'pending', 'processing', or 'processing-stopped' state,
+ the Printer MUST reject the request, and it returns the 'client-
+ error-not-possible' status code, as the job cannot have its position
+ changed.
+
+ If the Printer implements the "job-priority" Job Template attribute
+ (see [RFC2911], section 4.2.1), the Printer sets the job's "job-
+ priority" to that of the predecessor job (so that the job will print
+ after the predecessor job). The Printer returns the target job
+ immediately after the predecessor in a Get-Jobs response (see
+ [RFC2911], section 3.2.6) for the 'not-completed' jobs.
+
+ When the predecessor job completes processing or is canceled or
+ aborted while processing, the target of this operation is processed
+ next.
+
+ If the client does not supply a predecessor job, this operation has
+ the same semantics as Promote-Job (see section 4.4).
+
+ IPP is specified not to require queues for job scheduling, as there
+ are other implementation techniques for scheduling multiple jobs,
+ such as re-evaluating a criteria function for each job on a
+ scheduling cycle. However, if an implementation does implement
+ queues for jobs, then the Schedule-Job-After operation puts the
+ specified job immediately after the specified job in the queue. A
+ subsequent Schedule-Job-After operation specifying the same job will
+ cause its target job to be placed after that job, even though it is
+ between the first target job and the specified job. For example,
+ suppose the job queue consisted of jobs A, B, C, D, and E, in that
+ order. A Schedule-Job-After with job E as the target and B as the
+ specified job would result in the following queue: A, B, E, C, D. A
+ subsequent Schedule-Job-After with Job D as the target and B as the
+ specified job would result in the following queue: A, B, D, E, C.
+
+ In other words, the link between the two jobs in a Schedule-Job-After
+ operation is not retained; i.e., there is no attribute on either job
+ that points to the other job as a result of this operation.
+
+ Access Rights: The authenticated user (see [RFC2911], section 8.3)
+ performing this operation must be an operator or administrator of the
+ Printer object (see [RFC2911], sections 1 and 8.5).
+
+
+
+
+
+Kugler, et al. Standards Track [Page 22]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ The Schedule-Job-After Request have the same attribute groups and
+ attributes as does the Cancel-Job operation (see [RFC2911], section
+ 3.3.3), plus the new "job-message-from-operator" operation attribute
+ (see section 6). In addition, the following operation attribute is
+ defined:
+
+ "predecessor-job-id":
+ The client OPTIONALLY supplies this attribute. The Printer MUST
+ support it, if it supports this operation. This attribute
+ specifies the job after which the target job is to be processed.
+ If the client omits this attribute, the Printer MUST process the
+ target job next, i.e., after the current job, if there is one.
+
+ The Schedule-Job-After Response has the same attribute groups,
+ attributes, and status codes as does the Cancel-Job operation (see
+ [RFC2911], section 3.3.3). The following status codes have
+ particular meaning for this operation:
+
+ 'client-error-not-possible' - The target job was not in the 'pending'
+ state, or the predecessor job was not in the 'pending', 'processing',
+ or 'processing-stopped' state.
+
+ 'client-error-not-found' - Either the target job or the predecessor
+ job was not found.
+
+5. Additional Status Codes
+
+ This section defines new status codes used by the operations defined
+ in this document.
+
+5.1. 'server-error-printer-is-deactivated' (0x050A)
+
+ The Printer has been deactivated by the Deactivate-Printer operation
+ and is only accepting the Activate-Printer (see section 3.5.1), Get-
+ Job-Attributes, Get-Jobs, Get-Printer-Attributes, and any other Get-
+ Xxxx operations. An operator can perform the Activate-Printer
+ operation to allow the Printer to accept other operations.
+
+6. Use of Operation Attributes That Are Messages from the Operator
+
+ This section summarizes the usage of the "printer-message-from-
+ operator" and "job-message-from-operator" operation attributes
+ [RFC3380] that set the corresponding Printer and Job Description
+ attributes (see [RFC2911] for the definition of these). These
+ operation attributes are defined for most of the Printer and Job
+ operations that operators are likely to perform, respectively, so
+ that operators can indicate the reasons for their actions.
+
+
+
+
+Kugler, et al. Standards Track [Page 23]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Table 5 shows the operation attributes defined for use with the
+ Printer Operations.
+
+ Table 5. Operation Attribute Support for Printer Operations
+
+ Operation Attribute A B
+ ---------------------------------------------
+ attributes-charset REQ REQ
+ attributes-natural-language REQ REQ
+ printer-uri REQ REQ
+ requesting-user-name REQ REQ
+ printer-message-from-operator Note OPT
+
+ Legend:
+ A: Get-Printer-Attributes, Set-Printer-Attributes
+ B: All other Printer administrative operations, including, but
+ not limited to, Pause-Printer, Pause-Printer-After-Current-
+ Job, Resume-Printer, Hold-New-Jobs, Release-Held-New-Jobs,
+ Purge-Jobs, Enable-Print, Disable-Printer, Restart-
+ Printer, Shutdown-Printer, and Startup-Printer.
+ REQ: REQUIRED for a Printer to support.
+ OPT: OPTIONAL for a Printer to support; the Printer ignores the
+ attribute if it is not supported.
+ Note: According to [RFC3380], the Client MUST NOT supply the
+ "printer-message-from-operator" operation attribute in a
+ Get-Printer-Attributes or Set-Printer-Attributes operation;
+ the Printer MUST ignore this operation attribute in these
+ two operations. Instead, when it is used by an
+ operator, the client MUST supply the
+ "printer-message-from-operator" as (one of the) explicit
+ attributes being set on the Printer object with the
+ Set-Printer-Attributes operation.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 24]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Table 6 shows the operation attributes defined for use with the Job
+ operations.
+
+ Table 6. Operation Attribute Support for Job Operations
+
+ Operation Attribute A B C F
+ ---------------------------------------------------------
+ attributes-charset REQ REQ REQ REQ
+ attributes-natural-language REQ REQ REQ REQ
+ printer-uri REQ REQ REQ REQ
+ job-uri REQ REQ REQ
+ job-id REQ REQ REQ REQ
+ requesting-user-name REQ REQ REQ REQ
+ job-message-from-operator OPT OPT OPT Note
+ message** OPT OPT OPT n/a
+ job-hold-until n/a n/a OPT* n/a
+
+ Legend:
+ A: Cancel-Job, Resume-Job, Restart-Job, Promote-Job, Schedule-Job-
+ After
+ B: Cancel-Current-Job, Suspend-Current-Job
+ C: Hold-Job, Release-Job, Reprocess-Job
+ F: Get-Job-Attributes, Set-Job-Attributes
+
+ REQ; REQUIRED for a Printer to support.
+ OPT: OPTIONAL for a Printer to support; the Printer ignores the
+ attribute if it is supplied, but not supported.
+ n/a: not applicable for use with the operation; the Printer ignores
+ the attribute.
+ Note: According to [RFC3380], the Client MUST NOT supply the "job-
+ message-from-operator" operation attribute in a Get-Job-
+ Attributes or Set-Job-Attributes operation; the Printer MUST
+ ignore this operation attribute in these two operations.
+ Instead, when used by an operator, the client MUST supply the
+ "job-message-from-operator" as (one of the) explicit attributes
+ being set on the Job object with the Set-Job-Attributes
+ operation.
+ *: The Printer MUST support the "job-hold-until" operation
+ attribute if it supports the "job-hold-until" Job Template
+ attribute. For the Reprocess-Job operation, the client can
+ hold the job and then modify the job before releasing it to
+ be processed.
+ **: In [RFC2911], the "message" operation attribute is defined to
+ contain a message to the operator, but [RFC2911] does not
+ define a Job Description attribute to store the message.
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 25]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+7. New Printer Description Attributes
+
+ The following new Printer Description attributes are needed to
+ support the new operations defined in this document and the concepts
+ of Printer Fan-Out (see section 10).
+
+7.1. subordinate-printers-supported (1setOf uri)
+
+ This Printer attribute is REQUIRED if an implementation supports
+ Subordinate Printers (see section 10) and contains the URIs of the
+ immediate Subordinate Printer object(s) associated with this Printer
+ object. Each Non-Leaf Printer object MUST support this Printer
+ Description attribute. A Leaf Printer object either does not support
+ the "subordinate-printers-supported" attribute or does so with the
+ 'no-value' out-of-band value (see [RFC2911], section 4.1), depending
+ on the implementation.
+
+ The precise format of the Subordinate Printer URIs is implementation
+ dependent (see section 10.4).
+
+ If the Printer object does not have an associated Output Device, the
+ Printer MAY automatically copy the value of the Subordinate Printer
+ object's "printer-name" attribute to the Job object's "output-
+ device-assigned" attribute (see [RFC2911], section 4.3.13). The
+ "output-device-assigned" Job attribute identifies the Output Device
+ to which the Printer object has assigned a job; for example, when a
+ single Printer object is supporting Device Fan-Out or Printer Fan-
+ Out.
+
+7.2. parent-printers-supported (1setOf uri)
+
+ This Printer attribute is REQUIRED if an implementation supports
+ Subordinate Printers (see section 10) and contains the URI of the
+ Non-Leaf printer object(s) for which this Printer object is the
+ immediate Subordinate; i.e., this Printer's immediate "parent" or
+ "parents". Each Subordinate Printer object MUST support this Printer
+ Description attribute. A Printer that has no parents either does not
+ support the "parent-printers-supported" attribute or does so with the
+ 'no-value' out-of-band value (see [RFC2911], section 4.1), depending
+ on the implementation.
+
+8. Additional Values for the "printer-state-reasons" Printer
+ Description Attribute
+
+ This section defines additional values for the "printer-state-
+ reasons" Printer Description attribute.
+
+
+
+
+
+Kugler, et al. Standards Track [Page 26]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+8.1. 'hold-new-jobs' Value
+
+ 'hold-new-jobs': The operator has issued the Hold-New-Jobs operation
+ (see section 3.3.1) or other means, but the output-device(s) are
+ taking an appreciable time to stop. Later, when all output has
+ stopped, the "printer-state" becomes 'stopped', and the 'paused'
+ value replaces the 'moving-to-paused' value in the "printer-
+ state-reasons" attribute. This value MUST be supported if the
+ Hold-New-Jobs operation is supported and the implementation takes
+ significant time to pause a device in certain circumstances.
+
+8.2. 'deactivated' Value
+
+ 'deactivated': A client has issued a Deactivate-Printer operation
+ for the Printer object (see section 3.4.1), and the Printer is in
+ the process of becoming deactivated or has become deactivated.
+ The Printer MUST reject all requests except for Activate-Printer,
+ queries (Get-Printer-Attributes, Get-Job-Attributes, Get-Jobs,
+ etc.), Send-Document, and Send-URI (so that partial job submission
+ can be completed; see section 3.1.1), and then return the
+ 'server-error-service-unavailable' status code.
+
+9. Additional Values for the "job-state-reasons" Job Description
+ Attribute
+
+ This section defines additional values for the "job-state-reasons"
+ Job Description attribute.
+
+9.1. 'job-suspended' Value
+
+ 'job-suspended': While job processing has been suspended by the
+ Suspend-Current-Job operation, other jobs can be processed on the
+ Printer. The Job can be resumed with the Resume-Job operation,
+ which removes this value.
+
+10. Use of the Printer Object to Represent IPP Printer Fan-Out and IPP
+ Printer Fan-In
+
+ This section defines how the Printer object MAY be used to represent
+ IPP Printer Fan-Out and IPP Printer Fan-In. In Fan-Out, an IPP
+ Printer is used to represent other IPP Printer objects. In Fan-In,
+ several IPP Printer objects are used to represent another IPP Printer
+ object.
+
+
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 27]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+10.1. IPP Printer Fan-Out
+
+ The IPP/1.1 Model and Semantics introduces the semantic concept of an
+ IPP Printer object that represents more than one Output Device (see
+ [RFC2911], section 2.1). This concept is called "Output Device Fan-
+ Out". However, with Fan-Out there was no way to represent the
+ individual states of the Output Devices or to perform operations on a
+ specific Output Device. This document generalizes the semantics of
+ the Printer object to represent Subordinate Fan-Out Output Devices
+ such as IPP Printer objects. This concept is called "Printer object
+ Fan-Out". A Printer object that has a Subordinate Printer object is
+ called a Non-Leaf Printer object. Thus, a Non-Leaf Printer object
+ supports one or more Subordinate Printer objects in order to
+ represent Printer object Fan-Out. A Printer object that does not
+ have any Subordinate Printer objects is called a Leaf Printer object.
+
+ Each Non-Leaf Printer object submits jobs to its immediate
+ Subordinate Printers and otherwise controls the Subordinate Printers
+ by using IPP or other protocols. Whether pending jobs are kept in
+ the Non-Leaf Printer until a Subordinate Printer can accept them or
+ are kept in the Subordinate Printers depends on implementation and/or
+ configuration policy. Furthermore, a Subordinate Printer object MAY,
+ in turn, have Subordinate Printer objects. Thus a Printer object can
+ be both a Non-Leaf Printer and a Subordinate Printer.
+
+ A Subordinate Printer object MUST be a conforming Printer object, so
+ it MUST support all of the REQUIRED [RFC2911] operations and
+ attributes. However, with access control, the Subordinate Printer
+ MAY be configured so that end-user clients are not permitted to
+ perform any operations (or just Get-Printer-Attributes) while one or
+ more Non-Leaf Printer object(s) are permitted to perform any
+ operation.
+
+10.2. IPP Printer Fan-In
+
+ The IPP/1.1 Model and Semantics did not preclude the semantic concept
+ of multiple IPP Printer objects that represent a single Output Device
+ (see [RFC2911], section 2.1). However, there was no way for the
+ client to determine whether there was a Fan-In configuration; nor was
+ there a way to perform operations on the Subordinate device. This
+ specification generalizes the semantics of the Printer object to
+ allow several Non-Leaf IPP Printer objects to represent a single
+ Subordinate Printer object. Thus a Non-Leaf Printer object MAY share
+ a Subordinate Printer object with one or more other Non-Leaf Printer
+ objects in order to represent IPP Printer Fan-In.
+
+ As with Fan-Out (see section 10.1), when a Printer object is a Non-
+ Leaf Printer, it MUST NOT have an associated Output Device. As with
+
+
+
+Kugler, et al. Standards Track [Page 28]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Fan-Out, a Leaf Printer object has one or more associated Output
+ Devices. As with Fan-Out, the Non-Leaf Printer objects submit jobs
+ to their Subordinate Printer objects and otherwise control the
+ Subordinate Printer. As with Fan-Out, whether pending jobs are kept
+ in the Non-Leaf Printers until the Subordinate Printer can accept
+ them or are kept in the Subordinate Printer depends on the
+ implementation and/or configuration policy.
+
+10.3. Printer Object Attributes Used to Represent Printer Fan-Out and
+ Printer Fan-In
+
+ The following Printer Description attributes are defined to represent
+ the relationship between Printer object(s) and their Subordinate
+ Printer object(s):
+
+ 1. "subordinate-printers-supported" (1setOf uri) - Contains the
+ URI of the immediate Subordinate Printer object(s).
+
+ 2. "parent-printers-supported (1setOf uri) - Contains the URI of
+ the Non-Leaf printer object(s) for which this Printer object is
+ the immediate Subordinate; i.e., this Printer's immediate
+ "parent" or "parents".
+
+10.4. Subordinate Printer URI
+
+ Each Subordinate Printer object has a URI used as the target of each
+ operation on the Subordinate Printer. The means to configure URIs
+ for Subordinate Printer objects is implementation-dependent, as are
+ all URIs. However, there are two distinct approaches:
+
+ a. When the implementation seeks to make sure that no operation on
+ a Subordinate Printer object "sneaks by" the parent Printer
+ object (or that no Subordinate Printer is fronting for a device
+ that is not networked), the host part of the URI specifies the
+ host of the parent Printer. Then the parent Printer object can
+ easily reflect the state of the Subordinate Printer objects in
+ the parent's Printer object state and state reasons as the
+ operation passes "through" the parent Printer object.
+
+ b. When the Subordinate Printer is networked and the
+ implementation allows operations to go directly to the
+ Subordinate Printer (with proper access control) without
+ knowledge of the parent Printer object, the host part of the
+ URI is different from the host part of the parent Printer
+ object. In this a case, the parent Printer object MAY keep its
+ "printer-state" and "printer-state-reasons" up to date, either
+ by polling the Subordinate Printer object or by subscribing to
+ events with the Subordinate Printer object (see [RFC3995] for
+
+
+
+Kugler, et al. Standards Track [Page 29]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ means to subscribe to event notification when the Subordinate
+ Printer object supports IPP notification). Alternatively, the
+ parent Printer MAY wait until its "printer-state" and
+ "printer-state-reasons" attributes are queried and then query
+ all its Subordinate Printers in order to return the correct
+ values.
+
+10.5. Printer Object Attributes Used to Represent Output Device Fan-Out
+
+ Only Leaf IPP Printer objects are allowed to have one or more
+ associated Output Devices. Each Leaf Printer object MAY support the
+ "output-devices-supported" (1setOf name(127)) to indicate the user-
+ friendly name(s) of the Output Device(s) that the Leaf Printer object
+ represents. It is RECOMMENDED that each Leaf Printer object have
+ only one associated Output Device, so that the individual Output
+ Devices can be represented completely and controlled completely by
+ clients. In other words, the Leaf Printer's "output-devices-
+ supported" attribute SHOULD have only one value.
+
+ Non-Leaf Printer MUST NOT have associated Output Devices. However, a
+ Non-Leaf Printer SHOULD support an "output-devices-supported" (1setOf
+ name(127)) Printer Description attribute that contains all the values
+ of its immediate Subordinate Printers. As these Subordinate Printers
+ MAY be Leaf or Non-Leaf, the same rules apply to them. Thus any
+ Non-Leaf Printer SHOULD have an "output-devices-supported" (1setOf
+ name(127)) attribute that contains all the values of the Output
+ Devices associated with Leaf Printers of its complete sub-tree.
+
+ When a configuration of Printers and Output Devices is added, moved,
+ or changed, there can be moments when the tree structure is not
+ consistent; i.e., times when a Non-Leaf Printer's "subordinate-
+ printers-supported" does not agree with the Subordinate Printer's
+ "parent-printers-supported". Therefore, the operator SHOULD first
+ Deactivate all Printers being configured in this way, update all
+ pointer attributes, and then reactivate them. A useful client tool
+ would validate a tree structure before Activating the Printers
+ involved.
+
+10.6. Figures to Show All Possible Configurations
+
+ Figures 1, 2, and 3 are taken from [RFC2911] to show the
+ configurations possible with IPP/1.0 and IPP/1.1 where all Printer
+ objects are Leaf Printer objects. The remaining figures show
+ additional configurations using Non-Leaf and Leaf Printer objects.
+
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 30]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Legend:
+
+ ----> indicates a network protocol with the direction of its requests
+
+ ##### indicates a Printer object that is either
+ embedded in an Output Device, or
+ hosted in a server.
+ The Printer object might or might not be capable
+ of queuing/spooling.
+
+ any indicates any network protocol or direct
+ connect, including IPP.
+
+ Output Device
+ +---------------+
+ | ########### |
+ O +--------+ | # (Leaf) # |
+ /|\ | client |------------IPP-----------------># Printer # |
+ / \ +--------+ | # Object # |
+ | ########### |
+ +---------------+
+
+ Figure 1. Embedded Printer Object
+
+
+ ########### Output Device
+ O +--------+ # (Leaf) # +---------------+
+ /|\ | client |---IPP----># Printer #---any->| |
+ / \ +--------+ # object # | |
+ ########### +---------------+
+
+ Figure 2. Hosted Printer Object
+
+
+ +---------------+
+ | |
+ +->| Output Device |
+ ########### any/ | |
+ O +--------+ # (Leaf) # / +---------------+
+ /|\ | client |---IPP----># Printer #--*
+ / \ +--------+ # Object # \ +---------------+
+ ########### any\ | |
+ +->| Output Device |
+ | |
+ +---------------+
+
+ Figure 3. Output Device Fan-Out
+
+
+
+
+Kugler, et al. Standards Track [Page 31]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ ########### ###########
+ O +--------+ # Non-Leaf# # subord. #
+ /|\ | client |---IPP----># Printer #---IPP----># Printer #
+ / \ +--------+ # object # # object #
+ ########### ###########
+
+ The Subordinate Printer can be a Non-Leaf Printer, as in Figures 4
+ through 6, or can be a Leaf Printer, as in Figures 1 through 3.
+
+ Figure 4. Chained IPP Printer Objects
+
+
+ +------IPP--------------------->###########
+ / +---># subord. #
+ / / # Printer #
+ / ########### IPP # object #
+ O +--------+ # Non-Leaf# / ###########
+ /|\ | client |---IPP----># Printer #--*
+ / \ +--------+ # object # \
+ \ ########### IPP ###########
+ \ \ # subord. #
+ \ +---># Printer #
+ +------IPP---------------------># object #
+ ###########
+
+ The Subordinate Printer can be a Non-Leaf Printer, as in Figures 4
+ through 6, or can be a Leaf Printer, as in Figures 1 through 3.
+
+ Figure 5. IPP Printer Object Fan-Out
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 32]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ ###########
+ # Non-Leaf#
+ +---># Printer #-+
+ / # object # \
+ IPP ########### \ ###########
+ O +--------+ / +-IPP-># subord. #
+ /|\ | client |--+-----------IPP---------------># Printer #
+ / \ +--------+ \ +-IPP-># object #
+ IPP ########### / ###########
+ \ # Non-Leaf# /
+ +---># Printer #-+
+ # object #
+ ###########
+
+ The Subordinate Printer can be a Non-Leaf Printer, as in Figures 4
+ through 6, or can be a Leaf Printer, as in Figures 1 through 3.
+
+ Figure 6. IPP Printer Object Fan-In
+
+10.7. Forwarding Requests
+
+ This section describes the forwarding of Job and Printer requests to
+ Subordinate Printer objects.
+
+10.7.1. Forwarding Requests that Affect Printer Objects
+
+ In Printer Fan-Out, Printer Fan-In, and Chained Printers, the Non-
+ Leaf IPP Printer object MUST NOT forward the operations that affect
+ Printer objects to its Subordinate Printer objects. If a client
+ seeks to explicitly target a Subordinate Printer, the client MUST
+ specify the URI of the Subordinate Printer. The client can determine
+ the URI of any Subordinate Printers by querying the Printer's
+ "subordinate-printers-supported (1setOf uri) attribute (see section
+ 7.1).
+
+ Table 7 lists the operations that affect Printer objects and the
+ forwarding behavior that a Non-Leaf Printer MUST exhibit to its
+ immediate Subordinate Printers. Operations that affect jobs have a
+ different forwarding rule (see section 10.7.2 and Table 8):
+
+
+
+
+
+
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 33]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Table 7. Forwarding Operations that Affect Printer Objects
+
+ Printer Operation Non-Leaf Printer Action
+ ---------------------------------------------------------------
+ Printer Operations:
+
+ Enable-Printer MUST NOT forward to any of its Subordinate
+ Printers
+ Disable-Printer MUST NOT forward to any of its Subordinate
+ Printers
+ Hold-New-Jobs MUST NOT forward to any of its Subordinate
+ Printers
+ Release-Held-New- MUST NOT forward to any of its Subordinate
+ Jobs Printers
+ Deactivate-Printer MUST NOT forward to any of its Subordinate
+ Printers
+ Activate-Printer MUST NOT forward to any of its Subordinate
+ Printers
+ Restart-Printer MUST NOT forward to any of its Subordinate
+ Printers
+ Shutdown-Printer MUST NOT forward to any of its Subordinate
+ Printers
+ Startup-Printer MUST NOT forward to any of its Subordinate
+ Printers
+
+ IPP/1.1 Printer See [RFC2911]
+ Operations:
+
+ Get-Printer- MUST NOT forward to any of its Subordinate
+ Attributes Printers
+ Pause-Printer MUST NOT forward to any of its Subordinate
+ Printers
+ Resume-Printer MUST NOT forward to any of its Subordinate
+ Printers
+
+ Set Operations: See [RFC3380]
+
+ Set-Printer- MUST NOT forward to any of its Subordinate
+ Attributes Printers
+
+
+
+
+
+
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 34]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+10.7.2. Forwarding Requests that Affect Jobs
+
+ Unlike Printer Operations that only affect Printer objects (see
+ section 10.7.1), a Non-Leaf Printer object MUST forward operations
+ that directly affect jobs to the appropriate Job object(s) in one or
+ more of its immediate Subordinate Printer objects. Forwarding is
+ REQUIRED since the purpose of this Job operation is to affect the
+ indicated job, which may have been forwarded itself. This forwarding
+ MAY be immediate or queued, depending on the operation and the
+ implementation. For example, a Non-Leaf Printer object MAY
+ queue/spool jobs, feeding a job at a time to its Subordinate
+ Printer(s), or MAY forward jobs immediately to one of its Subordinate
+ Printers. In either case, the Non-Leaf Printer object forwards Job
+ Creation operations to one of its Subordinate Printers. Only the
+ time of forwarding of the Job Creation operations depends on whether
+ the policy is to queue/spool jobs in the Non-Leaf Printer or the
+ Subordinate Printer.
+
+ When a Non-Leaf Printer object creates a Job object in its
+ Subordinate Printer, whether that Non-Leaf Printer object keeps a
+ fully formed Job object or just keeps a mapping from the "job-ids"
+ that it assigned to those assigned by its Subordinate Printer object
+ is IMPLEMENTATION-DEPENDENT. In either case, the Non-Leaf Printer
+ MUST be able to accept and carry out future Job operations that
+ specify the "job-id" that the Non-Leaf Printer assigned and returned
+ to the job submitting client.
+
+ Table 8 lists the operations that directly affect jobs and the
+ forwarding behavior that a Non-Leaf Printer MUST exhibit to its
+ Subordinate Printers.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 35]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Table 8. Forwarding Operations that Affect Jobs Objects
+
+ Operation Non-Leaf Printer action
+ ---------------------------------------------------------------
+ Job operations:
+
+ Reprocess-Job MUST forward to the appropriate Job in one of
+ its Subordinate Printers
+ Cancel-Current- MUST NOT forward
+ Job
+ Resume-Job MUST forward to the appropriate Job in one of
+ its Subordinate Printers
+ Promote-Job MUST forward to the appropriate Job in one of
+ its Subordinate Printers
+
+ IPP/1.1 Printer
+ operations:
+
+ Print-Job MUST forward immediately or queue to the
+ appropriate Subordinate Printer
+ Print-URI MUST forward immediately or queue to the
+ appropriate Subordinate Printer
+ Validate-Job MUST forward to the appropriate Subordinate
+ Printer
+ Create-Job MUST forward immediately or queue to the
+ appropriate Subordinate Printer
+ Get-Jobs MUST forward to all its Subordinate Printers
+ Purge-Jobs MUST forward to all its Subordinate Printers
+
+ IPP/1.1 Job
+ operations:
+
+ Send-Document MUST forward immediately or queue to the
+ appropriate Job in one of its Subordinate
+ Printers
+ Send-URI MUST forward immediately or queue to the
+ appropriate Job in one of its Subordinate
+ Printers
+ Cancel-Job MUST forward to the appropriate Job in one of
+ its Subordinate Printers
+ Get-Job- MUST forward to the appropriate Job in one of
+ Attributes its Subordinate Printers if the Non-Leaf
+ Printer doesn't know the complete status of the
+ Job object
+ Hold-Job MUST forward to the appropriate Job in one of
+ its Subordinate Printers
+ Release-Job MUST forward to the appropriate Job in one of
+ its Subordinate Printers
+
+
+
+Kugler, et al. Standards Track [Page 36]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Restart-Job MUST forward to the appropriate Job in one of
+ its Subordinate Printers
+
+ IPP Set operations: See [RFC3380]
+
+ Set-Job- MUST forward to the appropriate Job in one of
+ Attributes its Subordinate Printers
+
+ When a Printer receives a request that REQUIRES forwarding, it does
+ so on a "best efforts basis" and returns a response to its client
+ without waiting for responses from any of its Subordinate Printers.
+ Such forwarded requests could fail.
+
+10.8. Additional Attributes to Help with Fan-Out
+
+ The following operation and Job Description attributes are defined to
+ help represent Job relationships for Fan-Out and forwarding of jobs.
+
+10.8.1. output-device-assigned (name(127)) Job Description Attribute -
+ from [RFC2911]
+
+ [RFC2911] defines "output-device-assigned" as follows: "This
+ attribute identifies the Output Device to which the Printer object
+ has assigned this job. If an Output Device implements an embedded
+ Printer object, the Printer object NEED NOT set this attribute. If a
+ print server implements a Printer object, the value MAY be empty
+ (zero-length string) or not returned until the Printer object assigns
+ an Output Device to the job. This attribute is particularly useful
+ when a single Printer object supports multiple devices (so called
+ "Device Fan-Out" see [RFC2911] section 2.1)." See also section 10.1
+ in this specification.
+
+10.8.2. original-requesting-user-name (name(MAX)) Operation and Job
+ Description Attribute
+
+ The operation attribute containing the user name of the original
+ user; i.e., corresponding to the "requesting-user-name" operation
+ attribute (see [RFC2911], section 3.2.1.1) that the original client
+ supplied to the first Printer object. The Printer copies the
+ "original-requesting-user-name" operation attribute to the
+ corresponding Job Description attribute.
+
+
+
+
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 37]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+10.8.3. requesting-user-name (name(MAX)) Operation Attribute -
+ Additional Semantics
+
+ The IPP/1.1 "requesting-user-name" operation attribute (see [RFC2911]
+ section 3.2.1.1) is updated by each client to be itself on each hop;
+ i.e., the "requesting-user-name" represents the client forwarding the
+ request, not the original client.
+
+10.8.4. job-originating-user-name (name(MAX)) Job Description Attribute
+ - Additional Semantics
+
+ The "job-originating-user-name" Job Description attribute (see
+ [RFC2911], section 4.3.6) remains as the authenticated original user,
+ not the parent Printer's authenticated host, and is forwarded by each
+ client without changing the value.
+
+11. Conformance Requirements
+
+ The Job and Printer Administrative operations defined in this
+ document are OPTIONAL operations. However, some operations MUST be
+ implemented if others are implemented, as shown in Table 9.
+
+ Table 9. Conformance Requirement Dependencies for Operations
+
+ Operations REQUIRED If any of these operations are
+ supported:
+ --------------------------------------------------------------------
+ Enable-Printer Disable-Printer
+ Disable-Printer Enable-Printer
+ Pause-Printer Resume-Printer
+ Resume-Printer Pause-Printer,
+ Pause-Printer-After-Current-Job
+ Hold-New-Jobs Release-Held-New-Jobs
+ Release-Held-New-Jobs Hold-New-Jobs
+ Activate-Printer, Deactivate-Printer
+ Disable-Printer,
+ Pause-Printer-After-Current-Job
+ Deactivate-Printer, Activate-Printer
+ Enable-Printer,
+ Resume-Printer
+ Restart-Printer none
+ Shutdown-Printer none
+ Startup-Printer none
+ Reprocess-Job none
+ Cancel-Current-Job none
+ Resume-Job Suspend-Current-Job
+ Suspend-Current-Job Resume-Job
+
+
+
+
+Kugler, et al. Standards Track [Page 38]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Promote-Job none
+ Schedule-Job-After Promote-Job
+
+ Tables 10 and 11 list the "printer-state-reasons" and "job-state-
+ reasons" values that are REQUIRED if the indicated operations are
+ supported.
+
+ Table 10. Conformance Requirement Dependencies for
+ "printer-state-reasons" Values
+
+ "printer-state- Conformance If any of the following Printer
+ reasons" values: Requirement Operations are supported:
+ --------------------------------------------------------------------
+ 'paused' REQUIRED Pause-Printer,
+ Pause-Printer-After-Current-Job,
+ or Deactivate-Printer
+ 'hold-new-jobs' REQUIRED Hold-New-Jobs
+ 'moving-to-paused' OPTIONAL Pause-Printer,
+ Pause-Printer-After-Current-Job,
+ Deactivate-Printer
+ 'deactivated' REQUIRED Deactivate-Printer
+
+
+ Table 11. Conformance Requirement Dependencies for "job-state-
+ reasons" Values
+
+ "job-state-reasons" Conformance If any of the following Job
+ values: Requirement operations are supported:
+
+ 'job-suspended' REQUIRED Suspend-Current-Job
+ 'printer-stopped' REQUIRED Always REQUIRED
+
+12. Normative References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0",
+ RFC 2246, January 1999.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext
+ Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC2910] Herriot, R., Butler, S., Moore, P., Turner, R., and J.
+ Wenn, "Internet Printing Protocol/1.1: Encoding and
+ Transport", RFC 2910, September 2000.
+
+
+
+
+Kugler, et al. Standards Track [Page 39]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ [RFC2911] Hastings, T., Herriot, R., deBry, R., Isaacson, S., and P.
+ Powell, "Internet Printing Protocol/1.1: Model and
+ Semantics", RFC 2911, September 2000.
+
+ [RFC3380] Hastings, T., Herriot, R., Kugler, C., and H. Lewis,
+ "Internet Printing Protocol (IPP): Job and Printer Set
+ Operations", RFC 3380, September 2002.
+
+13. Informative References
+
+ [RFC2567] Wright, F., "Design Goals for an Internet Printing
+ Protocol", RFC 2567, April 1999.
+
+ [RFC2568] Zilles, S., "Rationale for the Structure of the Model and
+ Protocol for the Internet Printing Protocol", RFC 2568,
+ April 1999.
+
+ [RFC2569] Herriot, R., Hastings, T., Jacobs, N., and J. Martin,
+ "Mapping between LPD and IPP Protocols", RFC 2569, April
+ 1999.
+
+ [RFC3196] Hastings, T., Manros, C., Zehler, P., Kugler, C., and H.
+ Holst, "Internet Printing Protocol/1.1: Implementor's
+ Guide", RFC 3196, November 2001.
+
+ [RFC3239] Kugler, C., Lewis, H., and T. Hastings, "Internet Printing
+ Protocol (IPP): Requirements for Job, Printer, and Device
+ Administrative Operations", RFC 3239, February 2002.
+
+ [RFC3995] Herriot, R. and T. Hastings, "Internet Printing Protocol
+ (IPP): Event Notifications and Subscriptions", RFC 3995,
+ February 2005.
+
+14. IANA Considerations
+
+ This section contains the registration information that IANA added to
+ the IPP Registry according to the procedures defined in [RFC2911],
+ section 6, to cover the definitions in this document. The resulting
+ registrations have been published as additions to the
+ http://www.iana.org/assignments/ipp-registrations file.
+
+
+
+
+
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 40]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+14.1. Attribute Registrations
+
+ The following table lists all the attributes defined in this
+ document. These have been registered according to the procedures in
+ [RFC2911], section 6.2.
+
+ Name Reference Section
+ -------------------------------------- --------- -------
+ Job Description attributes:
+ original-requesting-user-name (name(MAX)) [RFC3998] 10.8.2
+
+ Printer Description attributes:
+ subordinate-printers-supported (1setOf uri) [RFC3998] 7.1
+ parent-printers-supported (1setOf uri) [RFC3998] 7.2
+
+ Operation attributes:
+ original-requesting-user-name (name(MAX)) [RFC3998] 10.8.2
+
+14.2. Attribute Value Registrations
+
+ This section lists the additional values defined in this document for
+ existing attributes.
+
+ Attribute
+ Value Reference Section
+ --------------------- --------- -------
+ job-state-reasons (1setOf type2 keyword)
+ job-suspended [RFC3998] 9.1
+
+
+ printer-state-reasons (1setOf type2 keyword)
+ hold-new-jobs [RFC3998] 8.1
+ deactivated [RFC3998] 8.2
+
+14.3. Additional Enum Attribute Value Registrations
+
+ The following table lists all the new enum attribute values defined
+ in this document. These have been registered according to the
+ procedures in [RFC2911], section 6.1.
+
+
+
+
+
+
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 41]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Attribute (attribute syntax)
+ Value Name Reference Section
+ ------- -------------------- --------- -------
+ operations-supported (1setOf type2 enum) [RFC2911] 4.4.1
+ 0x0022 Enable-Printer [RFC3998] 3
+ 0x0023 Disable-Printer [RFC3998] 3
+ 0x0024 Pause-Printer-After-Current-Job [RFC3998] 3
+ 0x0025 Hold-New-Jobs [RFC3998] 3
+ 0x0026 Release-Held-New-Jobs [RFC3998] 3
+ 0x0027 Deactivate-Printer [RFC3998] 3
+ 0x0028 Activate-Printer [RFC3998] 3
+ 0x0029 Restart-Printer [RFC3998] 3
+ 0x002A Shutdown-Printer [RFC3998] 3
+ 0x002B Startup-Printer [RFC3998] 3
+ 0x002C Reprocess-Job [RFC3998] 4
+ 0x002D Cancel-Current-Job [RFC3998] 4
+ 0x002E Suspend-Current-Job [RFC3998] 4
+ 0x002F Resume-Job [RFC3998] 4
+ 0x0030 Promote-Job [RFC3998] 4
+ 0x0031 Schedule-Job-After [RFC3998] 4
+
+14.4. Operation Registrations
+
+ The following table lists all the operations defined in this
+ document. These have been registered according to the procedures in
+ [RFC2911], section 6.4.
+
+ Name Reference Section
+ ----------------------------- --------- -------
+ Activate-Printer [RFC3998] 3.4.2
+ Cancel-Current-Job [RFC3998] 4.2
+ Deactivate-Printer [RFC3998] 3.4.1
+ Disable-Printer [RFC3998] 3.1.1
+ Enable-Printer [RFC3998] 3.1.2
+ Hold-New-Jobs [RFC3998] 3.3.1
+ Pause-Printer-After-Current-Job [RFC3998] 3.2.1
+ Promote-Job [RFC3998] 4.4.1
+ Release-Held-New-Jobs [RFC3998] 3.3.2
+ Reprocess-Job [RFC3998] 4.1
+ Restart-Printer [RFC3998] 3.5.1
+ Resume-Job [RFC3998] 4.3.2
+ Schedule-Job-After [RFC3998] 4.4.2
+ Shutdown-Printer [RFC3998] 3.5.2
+ Startup-Printer [RFC3998] 3.5.3
+ Suspend-Current-Job [RFC3998] 4.3.1
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 42]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+14.5. Status Code Registrations
+
+ The following table lists the status code defined in this document.
+ This has been registered according to the procedures in [RFC2911],
+ section 6.6.
+
+ Value Name Reference Section
+ ------ ------------------------ --------- -------
+ 0x0000:0x00FF - "successful"
+ none at this time
+
+ 0x0100:0x01FF - "informational"
+ none at this time
+
+ 0x0300:0x03FF - "redirection" See RFC 2911 Errata
+ none at this time
+
+ 0x0400:0x04FF - "client-error"
+ none at this time
+
+ 0x0500:0x05FF - "server-error"
+ 0x050A server-error-printer-is-deactivated [RFC3998] 5.1
+
+15. Internationalization Considerations
+
+ This document has the same localization considerations as [RFC2911].
+
+16. Security Considerations
+
+ The IPP Model and Semantics document [RFC2911] discusses high level
+ security requirements (Client Authentication, Server Authentication,
+ and Operation Privacy). Client Authentication is the mechanism by
+ which the client proves its identity to the server in a secure
+ manner. Server Authentication is the mechanism by which the server
+ proves its identity to the client in a secure manner. Operation
+ Privacy is defined as a mechanism for protecting operations from
+ eavesdropping.
+
+ Printer operations defined in this specification (see section 3), as
+ well as Pause-Printer, Resume-Printer, and Purge-Job (defined in
+ [RFC2911]) are intended for use by an operator and/or administrator.
+ Job operations defined in this specification (see section 4) and
+ Cancel-Job, Hold-Job, and Release-Job (defined in [RFC2911]) are
+ intended for use by the job owner, operator, or administrator of the
+ Printer object. These operator and administrator operations affect
+ service for all users.
+
+
+
+
+
+Kugler, et al. Standards Track [Page 43]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ Inappropriate use of an administrative operation by an
+ unauthenticated end user can affect the quality of service for all
+ users. Therefore, IPP Printer implementations MUST support both
+ successful certificate-based TLS [RFC2246] client authentication and
+ successful operator/administrator authorization (see [RFC2911],
+ sections 5.2.7 and 8, and [RFC2910]) to perform the administrative
+ operations defined in this document. [RFC2910] requires the IPP
+ Printer to support the minimum cipher suite specified for TLS/1.0.
+ The means for authorizing an operator or administrator of the Printer
+ object are outside the scope of this specification, RFC 2910, and RFC
+ 2911.
+
+ The use of TLS and Client Authentication solves the Denial of
+ Service, Man in the Middle, and Masquerading security threats.
+
+17. Summary of Base IPP Documents
+
+ The base set of IPP documents includes the following:
+
+ Design Goals for an Internet Printing Protocol [RFC2567]
+ Rationale for the Structure and Model and Protocol for the
+ Internet Printing Protocol [RFC2568]
+ Internet Printing Protocol/1.1: Model and Semantics [RFC2911]
+ Internet Printing Protocol/1.1: Encoding and Transport [RFC2910]
+ Internet Printing Protocol/1.1: Implementer's Guide [RFC3196]
+ Mapping between LPD and IPP Protocols [RFC2569]
+
+ "Design Goals for an Internet Printing Protocol" takes a broad look
+ at distributed printing functionality, and it enumerates real-life
+ scenarios that help clarify the features that have to be included in
+ a printing protocol for the Internet. It identifies requirements for
+ three types of users: end users, operators, and administrators. It
+ calls out a subset of end user requirements that are satisfied in
+ IPP/1.0. A few OPTIONAL operator operations have been added to
+ IPP/1.1.
+
+ "Rationale for the Structure and Model and Protocol for the Internet
+ Printing Protocol" describes IPP from a high level view, defines a
+ roadmap for the various documents that form the suite of IPP
+ specification documents, and gives background and rationale for the
+ IETF working group's major decisions.
+
+ "Internet Printing Protocol/1.1: Model and Semantics" describes a
+ simplified model with abstract objects, their attributes, and their
+ operations that are independent of encoding and transport. It
+ introduces a Printer and a Job object. The Job object optionally
+ supports multiple documents per Job. It also addresses security,
+ internationalization, and directory issues.
+
+
+
+Kugler, et al. Standards Track [Page 44]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+ "Internet Printing Protocol/1.1: Encoding and Transport" is a formal
+ mapping of the abstract operations and attributes defined in the
+ model document onto HTTP/1.1 [RFC2616]. It defines the encoding
+ rules for a new Internet MIME media type called "application/ipp".
+ This document also defines the rules for transporting over HTTP a
+ message body whose Content-Type is "application/ipp". This document
+ defines the 'ippget' scheme for identifying IPP printers and jobs.
+
+ "Internet Printing Protocol/1.1: Implementer's Guide" gives insight
+ and advice to implementers of IPP clients and IPP objects. It is
+ intended to help them understand IPP/1.1 and some of the
+ considerations that may assist them in the design of their client
+ and/or IPP object implementations. For example, a typical order of
+ processing requests is given, including error checking. Motivation
+ for some of the specification decisions is also included.
+
+ "Mapping between LPD and IPP Protocols" gives some advice to
+ implementers of gateways between IPP and LPD (Line Printer Daemon)
+ implementations.
+
+Authors' Addresses
+
+ Carl Kugler
+ IBM Corporation, 003G
+ 6300 Diagonal Hwy
+ Boulder, CO 80301
+
+ Phone: (303) 924-5060
+ EMail: kugler@us.ibm.com
+
+
+ Tom Hastings, editor
+ Xerox Corporation
+ 701 S Aviation Blvd. ESAE 242
+ El Segundo, CA 90245
+
+ Phone: 310-333-6413
+ Fax: 310-333-6342
+ EMail: hastings@cp10.es.xerox.com
+
+
+ Harry Lewis
+ IBM Corporation
+ 6300 Diagonal Hwy
+ Boulder, CO 80301
+
+ Phone: (303) 924-5337
+ EMail: harryl@us.ibm.com
+
+
+
+Kugler, et al. Standards Track [Page 45]
+
+RFC 3998 IPP: Job and Printer Operations March 2005
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2005).
+
+ This document is subject to the rights, licenses and restrictions
+ contained in BCP 78, and except as set forth therein, the authors
+ retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the procedures with respect to rights in RFC documents can be
+ found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at ietf-
+ ipr@ietf.org.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+Kugler, et al. Standards Track [Page 46]
+
diff --git a/standards/rfc4122.txt b/standards/rfc4122.txt
new file mode 100644
index 000000000..31ceaab4b
--- /dev/null
+++ b/standards/rfc4122.txt
@@ -0,0 +1,1795 @@
+
+
+
+
+
+
+Network Working Group P. Leach
+Request for Comments: 4122 Microsoft
+Category: Standards Track M. Mealling
+ Refactored Networks, LLC
+ R. Salz
+ DataPower Technology, Inc.
+ July 2005
+
+
+ A Universally Unique IDentifier (UUID) URN Namespace
+
+Status of This Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2005).
+
+Abstract
+
+ This specification defines a Uniform Resource Name namespace for
+ UUIDs (Universally Unique IDentifier), also known as GUIDs (Globally
+ Unique IDentifier). A UUID is 128 bits long, and can guarantee
+ uniqueness across space and time. UUIDs were originally used in the
+ Apollo Network Computing System and later in the Open Software
+ Foundation's (OSF) Distributed Computing Environment (DCE), and then
+ in Microsoft Windows platforms.
+
+ This specification is derived from the DCE specification with the
+ kind permission of the OSF (now known as The Open Group).
+ Information from earlier versions of the DCE specification have been
+ incorporated into this document.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Leach, et al. Standards Track [Page 1]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2
+ 2. Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 3. Namespace Registration Template . . . . . . . . . . . . . . . 3
+ 4. Specification . . . . . . . . . . . . . . . . . . . . . . . . 5
+ 4.1. Format. . . . . . . . . . . . . . . . . . . . . . . . . . 5
+ 4.1.1. Variant. . . . . . . . . . . . . . . . . . . . . . 6
+ 4.1.2. Layout and Byte Order. . . . . . . . . . . . . . . 6
+ 4.1.3. Version. . . . . . . . . . . . . . . . . . . . . . 7
+ 4.1.4. Timestamp. . . . . . . . . . . . . . . . . . . . . 8
+ 4.1.5. Clock Sequence . . . . . . . . . . . . . . . . . . 8
+ 4.1.6. Node . . . . . . . . . . . . . . . . . . . . . . . 9
+ 4.1.7. Nil UUID . . . . . . . . . . . . . . . . . . . . . 9
+ 4.2. Algorithms for Creating a Time-Based UUID . . . . . . . . 9
+ 4.2.1. Basic Algorithm. . . . . . . . . . . . . . . . . . 10
+ 4.2.2. Generation Details . . . . . . . . . . . . . . . . 12
+ 4.3. Algorithm for Creating a Name-Based UUID. . . . . . . . . 13
+ 4.4. Algorithms for Creating a UUID from Truly Random or
+ Pseudo-Random Numbers . . . . . . . . . . . . . . . . . . 14
+ 4.5. Node IDs that Do Not Identify the Host. . . . . . . . . . 15
+ 5. Community Considerations . . . . . . . . . . . . . . . . . . . 15
+ 6. Security Considerations . . . . . . . . . . . . . . . . . . . 16
+ 7. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 16
+ 8. Normative References . . . . . . . . . . . . . . . . . . . . . 16
+ A. Appendix A - Sample Implementation . . . . . . . . . . . . . . 18
+ B. Appendix B - Sample Output of utest . . . . . . . . . . . . . 29
+ C. Appendix C - Some Name Space IDs . . . . . . . . . . . . . . . 30
+
+1. Introduction
+
+ This specification defines a Uniform Resource Name namespace for
+ UUIDs (Universally Unique IDentifier), also known as GUIDs (Globally
+ Unique IDentifier). A UUID is 128 bits long, and requires no central
+ registration process.
+
+ The information here is meant to be a concise guide for those wishing
+ to implement services using UUIDs as URNs. Nothing in this document
+ should be construed to override the DCE standards that defined UUIDs.
+
+ There is an ITU-T Recommendation and ISO/IEC Standard [3] that are
+ derived from earlier versions of this document. Both sets of
+ specifications have been aligned, and are fully technically
+ compatible. In addition, a global registration function is being
+ provided by the Telecommunications Standardisation Bureau of ITU-T;
+ for details see <http://www.itu.int/ITU-T/asn1/uuid.html>.
+
+
+
+
+
+Leach, et al. Standards Track [Page 2]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+2. Motivation
+
+ One of the main reasons for using UUIDs is that no centralized
+ authority is required to administer them (although one format uses
+ IEEE 802 node identifiers, others do not). As a result, generation
+ on demand can be completely automated, and used for a variety of
+ purposes. The UUID generation algorithm described here supports very
+ high allocation rates of up to 10 million per second per machine if
+ necessary, so that they could even be used as transaction IDs.
+
+ UUIDs are of a fixed size (128 bits) which is reasonably small
+ compared to other alternatives. This lends itself well to sorting,
+ ordering, and hashing of all sorts, storing in databases, simple
+ allocation, and ease of programming in general.
+
+ Since UUIDs are unique and persistent, they make excellent Uniform
+ Resource Names. The unique ability to generate a new UUID without a
+ registration process allows for UUIDs to be one of the URNs with the
+ lowest minting cost.
+
+3. Namespace Registration Template
+
+ Namespace ID: UUID
+ Registration Information:
+ Registration date: 2003-10-01
+
+ Declared registrant of the namespace:
+ JTC 1/SC6 (ASN.1 Rapporteur Group)
+
+ Declaration of syntactic structure:
+ A UUID is an identifier that is unique across both space and time,
+ with respect to the space of all UUIDs. Since a UUID is a fixed
+ size and contains a time field, it is possible for values to
+ rollover (around A.D. 3400, depending on the specific algorithm
+ used). A UUID can be used for multiple purposes, from tagging
+ objects with an extremely short lifetime, to reliably identifying
+ very persistent objects across a network.
+
+ The internal representation of a UUID is a specific sequence of
+ bits in memory, as described in Section 4. To accurately
+ represent a UUID as a URN, it is necessary to convert the bit
+ sequence to a string representation.
+
+ Each field is treated as an integer and has its value printed as a
+ zero-filled hexadecimal digit string with the most significant
+ digit first. The hexadecimal values "a" through "f" are output as
+ lower case characters and are case insensitive on input.
+
+
+
+
+Leach, et al. Standards Track [Page 3]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ The formal definition of the UUID string representation is
+ provided by the following ABNF [7]:
+
+ UUID = time-low "-" time-mid "-"
+ time-high-and-version "-"
+ clock-seq-and-reserved
+ clock-seq-low "-" node
+ time-low = 4hexOctet
+ time-mid = 2hexOctet
+ time-high-and-version = 2hexOctet
+ clock-seq-and-reserved = hexOctet
+ clock-seq-low = hexOctet
+ node = 6hexOctet
+ hexOctet = hexDigit hexDigit
+ hexDigit =
+ "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" /
+ "a" / "b" / "c" / "d" / "e" / "f" /
+ "A" / "B" / "C" / "D" / "E" / "F"
+
+ The following is an example of the string representation of a UUID as
+ a URN:
+
+ urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6
+
+ Relevant ancillary documentation:
+ [1][2]
+ Identifier uniqueness considerations:
+ This document specifies three algorithms to generate UUIDs: the
+ first leverages the unique values of 802 MAC addresses to
+ guarantee uniqueness, the second uses pseudo-random number
+ generators, and the third uses cryptographic hashing and
+ application-provided text strings. As a result, the UUIDs
+ generated according to the mechanisms here will be unique from all
+ other UUIDs that have been or will be assigned.
+
+ Identifier persistence considerations:
+ UUIDs are inherently very difficult to resolve in a global sense.
+ This, coupled with the fact that UUIDs are temporally unique
+ within their spatial context, ensures that UUIDs will remain as
+ persistent as possible.
+
+ Process of identifier assignment:
+ Generating a UUID does not require that a registration authority
+ be contacted. One algorithm requires a unique value over space
+ for each generator. This value is typically an IEEE 802 MAC
+ address, usually already available on network-connected hosts.
+ The address can be assigned from an address block obtained from
+ the IEEE registration authority. If no such address is available,
+
+
+
+Leach, et al. Standards Track [Page 4]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ or privacy concerns make its use undesirable, Section 4.5
+ specifies two alternatives. Another approach is to use version 3
+ or version 4 UUIDs as defined below.
+
+ Process for identifier resolution:
+ Since UUIDs are not globally resolvable, this is not applicable.
+
+ Rules for Lexical Equivalence:
+ Consider each field of the UUID to be an unsigned integer as shown
+ in the table in section Section 4.1.2. Then, to compare a pair of
+ UUIDs, arithmetically compare the corresponding fields from each
+ UUID in order of significance and according to their data type.
+ Two UUIDs are equal if and only if all the corresponding fields
+ are equal.
+
+ As an implementation note, equality comparison can be performed on
+ many systems by doing the appropriate byte-order canonicalization,
+ and then treating the two UUIDs as 128-bit unsigned integers.
+
+ UUIDs, as defined in this document, can also be ordered
+ lexicographically. For a pair of UUIDs, the first one follows the
+ second if the most significant field in which the UUIDs differ is
+ greater for the first UUID. The second precedes the first if the
+ most significant field in which the UUIDs differ is greater for
+ the second UUID.
+
+ Conformance with URN Syntax:
+ The string representation of a UUID is fully compatible with the
+ URN syntax. When converting from a bit-oriented, in-memory
+ representation of a UUID into a URN, care must be taken to
+ strictly adhere to the byte order issues mentioned in the string
+ representation section.
+
+ Validation mechanism:
+ Apart from determining whether the timestamp portion of the UUID
+ is in the future and therefore not yet assignable, there is no
+ mechanism for determining whether a UUID is 'valid'.
+
+ Scope:
+ UUIDs are global in scope.
+
+4. Specification
+
+4.1. Format
+
+ The UUID format is 16 octets; some bits of the eight octet variant
+ field specified below determine finer structure.
+
+
+
+
+Leach, et al. Standards Track [Page 5]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+4.1.1. Variant
+
+ The variant field determines the layout of the UUID. That is, the
+ interpretation of all other bits in the UUID depends on the setting
+ of the bits in the variant field. As such, it could more accurately
+ be called a type field; we retain the original term for
+ compatibility. The variant field consists of a variable number of
+ the most significant bits of octet 8 of the UUID.
+
+ The following table lists the contents of the variant field, where
+ the letter "x" indicates a "don't-care" value.
+
+ Msb0 Msb1 Msb2 Description
+
+ 0 x x Reserved, NCS backward compatibility.
+
+ 1 0 x The variant specified in this document.
+
+ 1 1 0 Reserved, Microsoft Corporation backward
+ compatibility
+
+ 1 1 1 Reserved for future definition.
+
+ Interoperability, in any form, with variants other than the one
+ defined here is not guaranteed, and is not likely to be an issue in
+ practice.
+
+4.1.2. Layout and Byte Order
+
+ To minimize confusion about bit assignments within octets, the UUID
+ record definition is defined only in terms of fields that are
+ integral numbers of octets. The fields are presented with the most
+ significant one first.
+
+ Field Data Type Octet Note
+ #
+
+ time_low unsigned 32 0-3 The low field of the
+ bit integer timestamp
+
+ time_mid unsigned 16 4-5 The middle field of the
+ bit integer timestamp
+
+ time_hi_and_version unsigned 16 6-7 The high field of the
+ bit integer timestamp multiplexed
+ with the version number
+
+
+
+
+
+Leach, et al. Standards Track [Page 6]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ clock_seq_hi_and_rese unsigned 8 8 The high field of the
+ rved bit integer clock sequence
+ multiplexed with the
+ variant
+
+ clock_seq_low unsigned 8 9 The low field of the
+ bit integer clock sequence
+
+ node unsigned 48 10-15 The spatially unique
+ bit integer node identifier
+
+ In the absence of explicit application or presentation protocol
+ specification to the contrary, a UUID is encoded as a 128-bit object,
+ as follows:
+
+ The fields are encoded as 16 octets, with the sizes and order of the
+ fields defined above, and with each field encoded with the Most
+ Significant Byte first (known as network byte order). Note that the
+ field names, particularly for multiplexed fields, follow historical
+ practice.
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | time_low |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | time_mid | time_hi_and_version |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |clk_seq_hi_res | clk_seq_low | node (0-1) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | node (2-5) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+4.1.3. Version
+
+ The version number is in the most significant 4 bits of the time
+ stamp (bits 4 through 7 of the time_hi_and_version field).
+
+ The following table lists the currently-defined versions for this
+ UUID variant.
+
+ Msb0 Msb1 Msb2 Msb3 Version Description
+
+ 0 0 0 1 1 The time-based version
+ specified in this document.
+
+ 0 0 1 0 2 DCE Security version, with
+ embedded POSIX UIDs.
+
+
+
+Leach, et al. Standards Track [Page 7]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ 0 0 1 1 3 The name-based version
+ specified in this document
+ that uses MD5 hashing.
+
+ 0 1 0 0 4 The randomly or pseudo-
+ randomly generated version
+ specified in this document.
+
+ 0 1 0 1 5 The name-based version
+ specified in this document
+ that uses SHA-1 hashing.
+
+ The version is more accurately a sub-type; again, we retain the term
+ for compatibility.
+
+4.1.4. Timestamp
+
+ The timestamp is a 60-bit value. For UUID version 1, this is
+ represented by Coordinated Universal Time (UTC) as a count of 100-
+ nanosecond intervals since 00:00:00.00, 15 October 1582 (the date of
+ Gregorian reform to the Christian calendar).
+
+ For systems that do not have UTC available, but do have the local
+ time, they may use that instead of UTC, as long as they do so
+ consistently throughout the system. However, this is not recommended
+ since generating the UTC from local time only needs a time zone
+ offset.
+
+ For UUID version 3 or 5, the timestamp is a 60-bit value constructed
+ from a name as described in Section 4.3.
+
+ For UUID version 4, the timestamp is a randomly or pseudo-randomly
+ generated 60-bit value, as described in Section 4.4.
+
+4.1.5. Clock Sequence
+
+ For UUID version 1, the clock sequence is used to help avoid
+ duplicates that could arise when the clock is set backwards in time
+ or if the node ID changes.
+
+ If the clock is set backwards, or might have been set backwards
+ (e.g., while the system was powered off), and the UUID generator can
+ not be sure that no UUIDs were generated with timestamps larger than
+ the value to which the clock was set, then the clock sequence has to
+ be changed. If the previous value of the clock sequence is known, it
+ can just be incremented; otherwise it should be set to a random or
+ high-quality pseudo-random value.
+
+
+
+
+Leach, et al. Standards Track [Page 8]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ Similarly, if the node ID changes (e.g., because a network card has
+ been moved between machines), setting the clock sequence to a random
+ number minimizes the probability of a duplicate due to slight
+ differences in the clock settings of the machines. If the value of
+ clock sequence associated with the changed node ID were known, then
+ the clock sequence could just be incremented, but that is unlikely.
+
+ The clock sequence MUST be originally (i.e., once in the lifetime of
+ a system) initialized to a random number to minimize the correlation
+ across systems. This provides maximum protection against node
+ identifiers that may move or switch from system to system rapidly.
+ The initial value MUST NOT be correlated to the node identifier.
+
+ For UUID version 3 or 5, the clock sequence is a 14-bit value
+ constructed from a name as described in Section 4.3.
+
+ For UUID version 4, clock sequence is a randomly or pseudo-randomly
+ generated 14-bit value as described in Section 4.4.
+
+4.1.6. Node
+
+ For UUID version 1, the node field consists of an IEEE 802 MAC
+ address, usually the host address. For systems with multiple IEEE
+ 802 addresses, any available one can be used. The lowest addressed
+ octet (octet number 10) contains the global/local bit and the
+ unicast/multicast bit, and is the first octet of the address
+ transmitted on an 802.3 LAN.
+
+ For systems with no IEEE address, a randomly or pseudo-randomly
+ generated value may be used; see Section 4.5. The multicast bit must
+ be set in such addresses, in order that they will never conflict with
+ addresses obtained from network cards.
+
+ For UUID version 3 or 5, the node field is a 48-bit value constructed
+ from a name as described in Section 4.3.
+
+ For UUID version 4, the node field is a randomly or pseudo-randomly
+ generated 48-bit value as described in Section 4.4.
+
+4.1.7. Nil UUID
+
+ The nil UUID is special form of UUID that is specified to have all
+ 128 bits set to zero.
+
+4.2. Algorithms for Creating a Time-Based UUID
+
+ Various aspects of the algorithm for creating a version 1 UUID are
+ discussed in the following sections.
+
+
+
+Leach, et al. Standards Track [Page 9]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+4.2.1. Basic Algorithm
+
+ The following algorithm is simple, correct, and inefficient:
+
+ o Obtain a system-wide global lock
+
+ o From a system-wide shared stable store (e.g., a file), read the
+ UUID generator state: the values of the timestamp, clock sequence,
+ and node ID used to generate the last UUID.
+
+ o Get the current time as a 60-bit count of 100-nanosecond intervals
+ since 00:00:00.00, 15 October 1582.
+
+ o Get the current node ID.
+
+ o If the state was unavailable (e.g., non-existent or corrupted), or
+ the saved node ID is different than the current node ID, generate
+ a random clock sequence value.
+
+ o If the state was available, but the saved timestamp is later than
+ the current timestamp, increment the clock sequence value.
+
+ o Save the state (current timestamp, clock sequence, and node ID)
+ back to the stable store.
+
+ o Release the global lock.
+
+ o Format a UUID from the current timestamp, clock sequence, and node
+ ID values according to the steps in Section 4.2.2.
+
+ If UUIDs do not need to be frequently generated, the above algorithm
+ may be perfectly adequate. For higher performance requirements,
+ however, issues with the basic algorithm include:
+
+ o Reading the state from stable storage each time is inefficient.
+
+ o The resolution of the system clock may not be 100-nanoseconds.
+
+ o Writing the state to stable storage each time is inefficient.
+
+ o Sharing the state across process boundaries may be inefficient.
+
+ Each of these issues can be addressed in a modular fashion by local
+ improvements in the functions that read and write the state and read
+ the clock. We address each of them in turn in the following
+ sections.
+
+
+
+
+
+Leach, et al. Standards Track [Page 10]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+4.2.1.1. Reading Stable Storage
+
+ The state only needs to be read from stable storage once at boot
+ time, if it is read into a system-wide shared volatile store (and
+ updated whenever the stable store is updated).
+
+ If an implementation does not have any stable store available, then
+ it can always say that the values were unavailable. This is the
+ least desirable implementation because it will increase the frequency
+ of creation of new clock sequence numbers, which increases the
+ probability of duplicates.
+
+ If the node ID can never change (e.g., the net card is inseparable
+ from the system), or if any change also reinitializes the clock
+ sequence to a random value, then instead of keeping it in stable
+ store, the current node ID may be returned.
+
+4.2.1.2. System Clock Resolution
+
+ The timestamp is generated from the system time, whose resolution may
+ be less than the resolution of the UUID timestamp.
+
+ If UUIDs do not need to be frequently generated, the timestamp can
+ simply be the system time multiplied by the number of 100-nanosecond
+ intervals per system time interval.
+
+ If a system overruns the generator by requesting too many UUIDs
+ within a single system time interval, the UUID service MUST either
+ return an error, or stall the UUID generator until the system clock
+ catches up.
+
+ A high resolution timestamp can be simulated by keeping a count of
+ the number of UUIDs that have been generated with the same value of
+ the system time, and using it to construct the low order bits of the
+ timestamp. The count will range between zero and the number of
+ 100-nanosecond intervals per system time interval.
+
+ Note: If the processors overrun the UUID generation frequently,
+ additional node identifiers can be allocated to the system, which
+ will permit higher speed allocation by making multiple UUIDs
+ potentially available for each time stamp value.
+
+4.2.1.3. Writing Stable Storage
+
+ The state does not always need to be written to stable store every
+ time a UUID is generated. The timestamp in the stable store can be
+ periodically set to a value larger than any yet used in a UUID. As
+ long as the generated UUIDs have timestamps less than that value, and
+
+
+
+Leach, et al. Standards Track [Page 11]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ the clock sequence and node ID remain unchanged, only the shared
+ volatile copy of the state needs to be updated. Furthermore, if the
+ timestamp value in stable store is in the future by less than the
+ typical time it takes the system to reboot, a crash will not cause a
+ reinitialization of the clock sequence.
+
+4.2.1.4. Sharing State Across Processes
+
+ If it is too expensive to access shared state each time a UUID is
+ generated, then the system-wide generator can be implemented to
+ allocate a block of time stamps each time it is called; a per-
+ process generator can allocate from that block until it is exhausted.
+
+4.2.2. Generation Details
+
+ Version 1 UUIDs are generated according to the following algorithm:
+
+ o Determine the values for the UTC-based timestamp and clock
+ sequence to be used in the UUID, as described in Section 4.2.1.
+
+ o For the purposes of this algorithm, consider the timestamp to be a
+ 60-bit unsigned integer and the clock sequence to be a 14-bit
+ unsigned integer. Sequentially number the bits in a field,
+ starting with zero for the least significant bit.
+
+ o Set the time_low field equal to the least significant 32 bits
+ (bits zero through 31) of the timestamp in the same order of
+ significance.
+
+ o Set the time_mid field equal to bits 32 through 47 from the
+ timestamp in the same order of significance.
+
+ o Set the 12 least significant bits (bits zero through 11) of the
+ time_hi_and_version field equal to bits 48 through 59 from the
+ timestamp in the same order of significance.
+
+ o Set the four most significant bits (bits 12 through 15) of the
+ time_hi_and_version field to the 4-bit version number
+ corresponding to the UUID version being created, as shown in the
+ table above.
+
+ o Set the clock_seq_low field to the eight least significant bits
+ (bits zero through 7) of the clock sequence in the same order of
+ significance.
+
+
+
+
+
+
+
+Leach, et al. Standards Track [Page 12]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ o Set the 6 least significant bits (bits zero through 5) of the
+ clock_seq_hi_and_reserved field to the 6 most significant bits
+ (bits 8 through 13) of the clock sequence in the same order of
+ significance.
+
+ o Set the two most significant bits (bits 6 and 7) of the
+ clock_seq_hi_and_reserved to zero and one, respectively.
+
+ o Set the node field to the 48-bit IEEE address in the same order of
+ significance as the address.
+
+4.3. Algorithm for Creating a Name-Based UUID
+
+ The version 3 or 5 UUID is meant for generating UUIDs from "names"
+ that are drawn from, and unique within, some "name space". The
+ concept of name and name space should be broadly construed, and not
+ limited to textual names. For example, some name spaces are the
+ domain name system, URLs, ISO Object IDs (OIDs), X.500 Distinguished
+ Names (DNs), and reserved words in a programming language. The
+ mechanisms or conventions used for allocating names and ensuring
+ their uniqueness within their name spaces are beyond the scope of
+ this specification.
+
+ The requirements for these types of UUIDs are as follows:
+
+ o The UUIDs generated at different times from the same name in the
+ same namespace MUST be equal.
+
+ o The UUIDs generated from two different names in the same namespace
+ should be different (with very high probability).
+
+ o The UUIDs generated from the same name in two different namespaces
+ should be different with (very high probability).
+
+ o If two UUIDs that were generated from names are equal, then they
+ were generated from the same name in the same namespace (with very
+ high probability).
+
+ The algorithm for generating a UUID from a name and a name space are
+ as follows:
+
+ o Allocate a UUID to use as a "name space ID" for all UUIDs
+ generated from names in that name space; see Appendix C for some
+ pre-defined values.
+
+ o Choose either MD5 [4] or SHA-1 [8] as the hash algorithm; If
+ backward compatibility is not an issue, SHA-1 is preferred.
+
+
+
+
+Leach, et al. Standards Track [Page 13]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ o Convert the name to a canonical sequence of octets (as defined by
+ the standards or conventions of its name space); put the name
+ space ID in network byte order.
+
+ o Compute the hash of the name space ID concatenated with the name.
+
+ o Set octets zero through 3 of the time_low field to octets zero
+ through 3 of the hash.
+
+ o Set octets zero and one of the time_mid field to octets 4 and 5 of
+ the hash.
+
+ o Set octets zero and one of the time_hi_and_version field to octets
+ 6 and 7 of the hash.
+
+ o Set the four most significant bits (bits 12 through 15) of the
+ time_hi_and_version field to the appropriate 4-bit version number
+ from Section 4.1.3.
+
+ o Set the clock_seq_hi_and_reserved field to octet 8 of the hash.
+
+ o Set the two most significant bits (bits 6 and 7) of the
+ clock_seq_hi_and_reserved to zero and one, respectively.
+
+ o Set the clock_seq_low field to octet 9 of the hash.
+
+ o Set octets zero through five of the node field to octets 10
+ through 15 of the hash.
+
+ o Convert the resulting UUID to local byte order.
+
+4.4. Algorithms for Creating a UUID from Truly Random or
+ Pseudo-Random Numbers
+
+ The version 4 UUID is meant for generating UUIDs from truly-random or
+ pseudo-random numbers.
+
+ The algorithm is as follows:
+
+ o Set the two most significant bits (bits 6 and 7) of the
+ clock_seq_hi_and_reserved to zero and one, respectively.
+
+ o Set the four most significant bits (bits 12 through 15) of the
+ time_hi_and_version field to the 4-bit version number from
+ Section 4.1.3.
+
+ o Set all the other bits to randomly (or pseudo-randomly) chosen
+ values.
+
+
+
+Leach, et al. Standards Track [Page 14]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ See Section 4.5 for a discussion on random numbers.
+
+4.5. Node IDs that Do Not Identify the Host
+
+ This section describes how to generate a version 1 UUID if an IEEE
+ 802 address is not available, or its use is not desired.
+
+ One approach is to contact the IEEE and get a separate block of
+ addresses. At the time of writing, the application could be found at
+ <http://standards.ieee.org/regauth/oui/pilot-ind.html>, and the cost
+ was US$550.
+
+ A better solution is to obtain a 47-bit cryptographic quality random
+ number and use it as the low 47 bits of the node ID, with the least
+ significant bit of the first octet of the node ID set to one. This
+ bit is the unicast/multicast bit, which will never be set in IEEE 802
+ addresses obtained from network cards. Hence, there can never be a
+ conflict between UUIDs generated by machines with and without network
+ cards. (Recall that the IEEE 802 spec talks about transmission
+ order, which is the opposite of the in-memory representation that is
+ discussed in this document.)
+
+ For compatibility with earlier specifications, note that this
+ document uses the unicast/multicast bit, instead of the arguably more
+ correct local/global bit.
+
+ Advice on generating cryptographic-quality random numbers can be
+ found in RFC1750 [5].
+
+ In addition, items such as the computer's name and the name of the
+ operating system, while not strictly speaking random, will help
+ differentiate the results from those obtained by other systems.
+
+ The exact algorithm to generate a node ID using these data is system
+ specific, because both the data available and the functions to obtain
+ them are often very system specific. A generic approach, however, is
+ to accumulate as many sources as possible into a buffer, use a
+ message digest such as MD5 [4] or SHA-1 [8], take an arbitrary 6
+ bytes from the hash value, and set the multicast bit as described
+ above.
+
+5. Community Considerations
+
+ The use of UUIDs is extremely pervasive in computing. They comprise
+ the core identifier infrastructure for many operating systems
+ (Microsoft Windows) and applications (the Mozilla browser) and in
+ many cases, become exposed to the Web in many non-standard ways.
+
+
+
+
+Leach, et al. Standards Track [Page 15]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ This specification attempts to standardize that practice as openly as
+ possible and in a way that attempts to benefit the entire Internet.
+
+6. Security Considerations
+
+ Do not assume that UUIDs are hard to guess; they should not be used
+ as security capabilities (identifiers whose mere possession grants
+ access), for example. A predictable random number source will
+ exacerbate the situation.
+
+ Do not assume that it is easy to determine if a UUID has been
+ slightly transposed in order to redirect a reference to another
+ object. Humans do not have the ability to easily check the integrity
+ of a UUID by simply glancing at it.
+
+ Distributed applications generating UUIDs at a variety of hosts must
+ be willing to rely on the random number source at all hosts. If this
+ is not feasible, the namespace variant should be used.
+
+7. Acknowledgments
+
+ This document draws heavily on the OSF DCE specification for UUIDs.
+ Ted Ts'o provided helpful comments, especially on the byte ordering
+ section which we mostly plagiarized from a proposed wording he
+ supplied (all errors in that section are our responsibility,
+ however).
+
+ We are also grateful to the careful reading and bit-twiddling of Ralf
+ S. Engelschall, John Larmouth, and Paul Thorpe. Professor Larmouth
+ was also invaluable in achieving coordination with ISO/IEC.
+
+8. Normative References
+
+ [1] Zahn, L., Dineen, T., and P. Leach, "Network Computing
+ Architecture", ISBN 0-13-611674-4, January 1990.
+
+ [2] "DCE: Remote Procedure Call", Open Group CAE Specification C309,
+ ISBN 1-85912-041-5, August 1994.
+
+ [3] ISO/IEC 9834-8:2004 Information Technology, "Procedures for the
+ operation of OSI Registration Authorities: Generation and
+ registration of Universally Unique Identifiers (UUIDs) and their
+ use as ASN.1 Object Identifier components" ITU-T Rec. X.667,
+ 2004.
+
+ [4] Rivest, R., "The MD5 Message-Digest Algorithm ", RFC 1321, April
+ 1992.
+
+
+
+
+Leach, et al. Standards Track [Page 16]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ [5] Eastlake, D., 3rd, Schiller, J., and S. Crocker, "Randomness
+ Requirements for Security", BCP 106, RFC 4086, June 2005.
+
+ [6] Moats, R., "URN Syntax", RFC 2141, May 1997.
+
+ [7] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [8] National Institute of Standards and Technology, "Secure Hash
+ Standard", FIPS PUB 180-1, April 1995,
+ <http://www.itl.nist.gov/fipspubs/fip180-1.htm>.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Leach, et al. Standards Track [Page 17]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+Appendix A. Appendix A - Sample Implementation
+
+ This implementation consists of 5 files: uuid.h, uuid.c, sysdep.h,
+ sysdep.c and utest.c. The uuid.* files are the system independent
+ implementation of the UUID generation algorithms described above,
+ with all the optimizations described above except efficient state
+ sharing across processes included. The code has been tested on Linux
+ (Red Hat 4.0) with GCC (2.7.2), and Windows NT 4.0 with VC++ 5.0.
+ The code assumes 64-bit integer support, which makes it much clearer.
+
+ All the following source files should have the following copyright
+ notice included:
+
+copyrt.h
+
+/*
+** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
+** Digital Equipment Corporation, Maynard, Mass.
+** Copyright (c) 1998 Microsoft.
+** To anyone who acknowledges that this file is provided "AS IS"
+** without any express or implied warranty: permission to use, copy,
+** modify, and distribute this file for any purpose is hereby
+** granted without fee, provided that the above copyright notices and
+** this notice appears in all source code copies, and that none of
+** the names of Open Software Foundation, Inc., Hewlett-Packard
+** Company, Microsoft, or Digital Equipment Corporation be used in
+** advertising or publicity pertaining to distribution of the software
+** without specific, written prior permission. Neither Open Software
+** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
+** Equipment Corporation makes any representations about the
+** suitability of this software for any purpose.
+*/
+
+
+uuid.h
+
+#include "copyrt.h"
+#undef uuid_t
+typedef struct {
+ unsigned32 time_low;
+ unsigned16 time_mid;
+ unsigned16 time_hi_and_version;
+ unsigned8 clock_seq_hi_and_reserved;
+ unsigned8 clock_seq_low;
+ byte node[6];
+} uuid_t;
+
+
+
+
+Leach, et al. Standards Track [Page 18]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+/* uuid_create -- generate a UUID */
+int uuid_create(uuid_t * uuid);
+
+/* uuid_create_md5_from_name -- create a version 3 (MD5) UUID using a
+ "name" from a "name space" */
+void uuid_create_md5_from_name(
+ uuid_t *uuid, /* resulting UUID */
+ uuid_t nsid, /* UUID of the namespace */
+ void *name, /* the name from which to generate a UUID */
+ int namelen /* the length of the name */
+);
+
+/* uuid_create_sha1_from_name -- create a version 5 (SHA-1) UUID
+ using a "name" from a "name space" */
+void uuid_create_sha1_from_name(
+
+ uuid_t *uuid, /* resulting UUID */
+ uuid_t nsid, /* UUID of the namespace */
+ void *name, /* the name from which to generate a UUID */
+ int namelen /* the length of the name */
+);
+
+/* uuid_compare -- Compare two UUID's "lexically" and return
+ -1 u1 is lexically before u2
+ 0 u1 is equal to u2
+ 1 u1 is lexically after u2
+ Note that lexical ordering is not temporal ordering!
+*/
+int uuid_compare(uuid_t *u1, uuid_t *u2);
+
+
+uuid.c
+
+#include "copyrt.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include "sysdep.h"
+#include "uuid.h"
+
+/* various forward declarations */
+static int read_state(unsigned16 *clockseq, uuid_time_t *timestamp,
+ uuid_node_t *node);
+static void write_state(unsigned16 clockseq, uuid_time_t timestamp,
+ uuid_node_t node);
+static void format_uuid_v1(uuid_t *uuid, unsigned16 clockseq,
+ uuid_time_t timestamp, uuid_node_t node);
+
+
+
+Leach, et al. Standards Track [Page 19]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+static void format_uuid_v3or5(uuid_t *uuid, unsigned char hash[16],
+ int v);
+static void get_current_time(uuid_time_t *timestamp);
+static unsigned16 true_random(void);
+
+/* uuid_create -- generator a UUID */
+int uuid_create(uuid_t *uuid)
+{
+ uuid_time_t timestamp, last_time;
+ unsigned16 clockseq;
+ uuid_node_t node;
+ uuid_node_t last_node;
+ int f;
+
+ /* acquire system-wide lock so we're alone */
+ LOCK;
+ /* get time, node ID, saved state from non-volatile storage */
+ get_current_time(&timestamp);
+ get_ieee_node_identifier(&node);
+ f = read_state(&clockseq, &last_time, &last_node);
+
+ /* if no NV state, or if clock went backwards, or node ID
+ changed (e.g., new network card) change clockseq */
+ if (!f || memcmp(&node, &last_node, sizeof node))
+ clockseq = true_random();
+ else if (timestamp < last_time)
+ clockseq++;
+
+ /* save the state for next time */
+ write_state(clockseq, timestamp, node);
+
+ UNLOCK;
+
+ /* stuff fields into the UUID */
+ format_uuid_v1(uuid, clockseq, timestamp, node);
+ return 1;
+}
+
+/* format_uuid_v1 -- make a UUID from the timestamp, clockseq,
+ and node ID */
+void format_uuid_v1(uuid_t* uuid, unsigned16 clock_seq,
+ uuid_time_t timestamp, uuid_node_t node)
+{
+ /* Construct a version 1 uuid with the information we've gathered
+ plus a few constants. */
+ uuid->time_low = (unsigned long)(timestamp & 0xFFFFFFFF);
+ uuid->time_mid = (unsigned short)((timestamp >> 32) & 0xFFFF);
+ uuid->time_hi_and_version =
+
+
+
+Leach, et al. Standards Track [Page 20]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ (unsigned short)((timestamp >> 48) & 0x0FFF);
+ uuid->time_hi_and_version |= (1 << 12);
+ uuid->clock_seq_low = clock_seq & 0xFF;
+ uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
+ uuid->clock_seq_hi_and_reserved |= 0x80;
+ memcpy(&uuid->node, &node, sizeof uuid->node);
+}
+
+/* data type for UUID generator persistent state */
+typedef struct {
+ uuid_time_t ts; /* saved timestamp */
+ uuid_node_t node; /* saved node ID */
+ unsigned16 cs; /* saved clock sequence */
+} uuid_state;
+
+static uuid_state st;
+
+/* read_state -- read UUID generator state from non-volatile store */
+int read_state(unsigned16 *clockseq, uuid_time_t *timestamp,
+ uuid_node_t *node)
+{
+ static int inited = 0;
+ FILE *fp;
+
+ /* only need to read state once per boot */
+ if (!inited) {
+ fp = fopen("state", "rb");
+ if (fp == NULL)
+ return 0;
+ fread(&st, sizeof st, 1, fp);
+ fclose(fp);
+ inited = 1;
+ }
+ *clockseq = st.cs;
+ *timestamp = st.ts;
+ *node = st.node;
+ return 1;
+}
+
+/* write_state -- save UUID generator state back to non-volatile
+ storage */
+void write_state(unsigned16 clockseq, uuid_time_t timestamp,
+ uuid_node_t node)
+{
+ static int inited = 0;
+ static uuid_time_t next_save;
+ FILE* fp;
+
+
+
+
+Leach, et al. Standards Track [Page 21]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ if (!inited) {
+ next_save = timestamp;
+ inited = 1;
+ }
+
+ /* always save state to volatile shared state */
+ st.cs = clockseq;
+ st.ts = timestamp;
+ st.node = node;
+ if (timestamp >= next_save) {
+ fp = fopen("state", "wb");
+ fwrite(&st, sizeof st, 1, fp);
+ fclose(fp);
+ /* schedule next save for 10 seconds from now */
+ next_save = timestamp + (10 * 10 * 1000 * 1000);
+ }
+}
+
+/* get-current_time -- get time as 60-bit 100ns ticks since UUID epoch.
+ Compensate for the fact that real clock resolution is
+ less than 100ns. */
+void get_current_time(uuid_time_t *timestamp)
+{
+ static int inited = 0;
+ static uuid_time_t time_last;
+ static unsigned16 uuids_this_tick;
+ uuid_time_t time_now;
+
+ if (!inited) {
+ get_system_time(&time_now);
+ uuids_this_tick = UUIDS_PER_TICK;
+ inited = 1;
+ }
+
+ for ( ; ; ) {
+ get_system_time(&time_now);
+
+ /* if clock reading changed since last UUID generated, */
+ if (time_last != time_now) {
+ /* reset count of uuids gen'd with this clock reading */
+ uuids_this_tick = 0;
+ time_last = time_now;
+ break;
+ }
+ if (uuids_this_tick < UUIDS_PER_TICK) {
+ uuids_this_tick++;
+ break;
+ }
+
+
+
+Leach, et al. Standards Track [Page 22]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ /* going too fast for our clock; spin */
+ }
+ /* add the count of uuids to low order bits of the clock reading */
+ *timestamp = time_now + uuids_this_tick;
+}
+
+/* true_random -- generate a crypto-quality random number.
+ **This sample doesn't do that.** */
+static unsigned16 true_random(void)
+{
+ static int inited = 0;
+ uuid_time_t time_now;
+
+ if (!inited) {
+ get_system_time(&time_now);
+ time_now = time_now / UUIDS_PER_TICK;
+ srand((unsigned int)
+ (((time_now >> 32) ^ time_now) & 0xffffffff));
+ inited = 1;
+ }
+
+ return rand();
+}
+
+/* uuid_create_md5_from_name -- create a version 3 (MD5) UUID using a
+ "name" from a "name space" */
+void uuid_create_md5_from_name(uuid_t *uuid, uuid_t nsid, void *name,
+ int namelen)
+{
+ MD5_CTX c;
+ unsigned char hash[16];
+ uuid_t net_nsid;
+
+ /* put name space ID in network byte order so it hashes the same
+ no matter what endian machine we're on */
+ net_nsid = nsid;
+ net_nsid.time_low = htonl(net_nsid.time_low);
+ net_nsid.time_mid = htons(net_nsid.time_mid);
+ net_nsid.time_hi_and_version = htons(net_nsid.time_hi_and_version);
+
+ MD5Init(&c);
+ MD5Update(&c, &net_nsid, sizeof net_nsid);
+ MD5Update(&c, name, namelen);
+ MD5Final(hash, &c);
+
+ /* the hash is in network byte order at this point */
+ format_uuid_v3or5(uuid, hash, 3);
+}
+
+
+
+Leach, et al. Standards Track [Page 23]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+void uuid_create_sha1_from_name(uuid_t *uuid, uuid_t nsid, void *name,
+ int namelen)
+{
+ SHA_CTX c;
+ unsigned char hash[20];
+ uuid_t net_nsid;
+
+ /* put name space ID in network byte order so it hashes the same
+ no matter what endian machine we're on */
+ net_nsid = nsid;
+ net_nsid.time_low = htonl(net_nsid.time_low);
+ net_nsid.time_mid = htons(net_nsid.time_mid);
+ net_nsid.time_hi_and_version = htons(net_nsid.time_hi_and_version);
+
+ SHA1_Init(&c);
+ SHA1_Update(&c, &net_nsid, sizeof net_nsid);
+ SHA1_Update(&c, name, namelen);
+ SHA1_Final(hash, &c);
+
+ /* the hash is in network byte order at this point */
+ format_uuid_v3or5(uuid, hash, 5);
+}
+
+/* format_uuid_v3or5 -- make a UUID from a (pseudo)random 128-bit
+ number */
+void format_uuid_v3or5(uuid_t *uuid, unsigned char hash[16], int v)
+{
+ /* convert UUID to local byte order */
+ memcpy(uuid, hash, sizeof *uuid);
+ uuid->time_low = ntohl(uuid->time_low);
+ uuid->time_mid = ntohs(uuid->time_mid);
+ uuid->time_hi_and_version = ntohs(uuid->time_hi_and_version);
+
+ /* put in the variant and version bits */
+ uuid->time_hi_and_version &= 0x0FFF;
+ uuid->time_hi_and_version |= (v << 12);
+ uuid->clock_seq_hi_and_reserved &= 0x3F;
+ uuid->clock_seq_hi_and_reserved |= 0x80;
+}
+
+/* uuid_compare -- Compare two UUID's "lexically" and return */
+#define CHECK(f1, f2) if (f1 != f2) return f1 < f2 ? -1 : 1;
+int uuid_compare(uuid_t *u1, uuid_t *u2)
+{
+ int i;
+
+ CHECK(u1->time_low, u2->time_low);
+ CHECK(u1->time_mid, u2->time_mid);
+
+
+
+Leach, et al. Standards Track [Page 24]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ CHECK(u1->time_hi_and_version, u2->time_hi_and_version);
+ CHECK(u1->clock_seq_hi_and_reserved, u2->clock_seq_hi_and_reserved);
+ CHECK(u1->clock_seq_low, u2->clock_seq_low)
+ for (i = 0; i < 6; i++) {
+ if (u1->node[i] < u2->node[i])
+ return -1;
+ if (u1->node[i] > u2->node[i])
+ return 1;
+ }
+ return 0;
+}
+#undef CHECK
+
+
+sysdep.h
+
+#include "copyrt.h"
+/* remove the following define if you aren't running WIN32 */
+#define WININC 0
+
+#ifdef WININC
+#include <windows.h>
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/sysinfo.h>
+#endif
+
+#include "global.h"
+/* change to point to where MD5 .h's live; RFC 1321 has sample
+ implementation */
+#include "md5.h"
+
+/* set the following to the number of 100ns ticks of the actual
+ resolution of your system's clock */
+#define UUIDS_PER_TICK 1024
+
+/* Set the following to a calls to get and release a global lock */
+#define LOCK
+#define UNLOCK
+
+typedef unsigned long unsigned32;
+typedef unsigned short unsigned16;
+typedef unsigned char unsigned8;
+typedef unsigned char byte;
+
+/* Set this to what your compiler uses for 64-bit data type */
+#ifdef WININC
+
+
+
+Leach, et al. Standards Track [Page 25]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+#define unsigned64_t unsigned __int64
+#define I64(C) C
+#else
+#define unsigned64_t unsigned long long
+#define I64(C) C##LL
+#endif
+
+typedef unsigned64_t uuid_time_t;
+typedef struct {
+ char nodeID[6];
+} uuid_node_t;
+
+void get_ieee_node_identifier(uuid_node_t *node);
+void get_system_time(uuid_time_t *uuid_time);
+void get_random_info(char seed[16]);
+
+
+sysdep.c
+
+#include "copyrt.h"
+#include <stdio.h>
+#include "sysdep.h"
+
+/* system dependent call to get IEEE node ID.
+ This sample implementation generates a random node ID. */
+void get_ieee_node_identifier(uuid_node_t *node)
+{
+ static inited = 0;
+ static uuid_node_t saved_node;
+ char seed[16];
+ FILE *fp;
+
+ if (!inited) {
+ fp = fopen("nodeid", "rb");
+ if (fp) {
+ fread(&saved_node, sizeof saved_node, 1, fp);
+ fclose(fp);
+ }
+ else {
+ get_random_info(seed);
+ seed[0] |= 0x01;
+ memcpy(&saved_node, seed, sizeof saved_node);
+ fp = fopen("nodeid", "wb");
+ if (fp) {
+ fwrite(&saved_node, sizeof saved_node, 1, fp);
+ fclose(fp);
+ }
+ }
+
+
+
+Leach, et al. Standards Track [Page 26]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ inited = 1;
+ }
+
+ *node = saved_node;
+}
+
+/* system dependent call to get the current system time. Returned as
+ 100ns ticks since UUID epoch, but resolution may be less than
+ 100ns. */
+#ifdef _WINDOWS_
+
+void get_system_time(uuid_time_t *uuid_time)
+{
+ ULARGE_INTEGER time;
+
+ /* NT keeps time in FILETIME format which is 100ns ticks since
+ Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582.
+ The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec)
+ + 18 years and 5 leap days. */
+ GetSystemTimeAsFileTime((FILETIME *)&time);
+ time.QuadPart +=
+
+ (unsigned __int64) (1000*1000*10) // seconds
+ * (unsigned __int64) (60 * 60 * 24) // days
+ * (unsigned __int64) (17+30+31+365*18+5); // # of days
+ *uuid_time = time.QuadPart;
+}
+
+/* Sample code, not for use in production; see RFC 1750 */
+void get_random_info(char seed[16])
+{
+ MD5_CTX c;
+ struct {
+ MEMORYSTATUS m;
+ SYSTEM_INFO s;
+ FILETIME t;
+ LARGE_INTEGER pc;
+ DWORD tc;
+ DWORD l;
+ char hostname[MAX_COMPUTERNAME_LENGTH + 1];
+ } r;
+
+ MD5Init(&c);
+ GlobalMemoryStatus(&r.m);
+ GetSystemInfo(&r.s);
+ GetSystemTimeAsFileTime(&r.t);
+ QueryPerformanceCounter(&r.pc);
+ r.tc = GetTickCount();
+
+
+
+Leach, et al. Standards Track [Page 27]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+ r.l = MAX_COMPUTERNAME_LENGTH + 1;
+ GetComputerName(r.hostname, &r.l);
+ MD5Update(&c, &r, sizeof r);
+ MD5Final(seed, &c);
+}
+
+#else
+
+void get_system_time(uuid_time_t *uuid_time)
+{
+ struct timeval tp;
+
+ gettimeofday(&tp, (struct timezone *)0);
+
+ /* Offset between UUID formatted times and Unix formatted times.
+ UUID UTC base time is October 15, 1582.
+ Unix base time is January 1, 1970.*/
+ *uuid_time = ((unsigned64)tp.tv_sec * 10000000)
+ + ((unsigned64)tp.tv_usec * 10)
+ + I64(0x01B21DD213814000);
+}
+
+/* Sample code, not for use in production; see RFC 1750 */
+void get_random_info(char seed[16])
+{
+ MD5_CTX c;
+ struct {
+ struct sysinfo s;
+ struct timeval t;
+ char hostname[257];
+ } r;
+
+ MD5Init(&c);
+ sysinfo(&r.s);
+ gettimeofday(&r.t, (struct timezone *)0);
+ gethostname(r.hostname, 256);
+ MD5Update(&c, &r, sizeof r);
+ MD5Final(seed, &c);
+}
+
+#endif
+
+utest.c
+
+#include "copyrt.h"
+#include "sysdep.h"
+#include <stdio.h>
+#include "uuid.h"
+
+
+
+Leach, et al. Standards Track [Page 28]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+uuid_t NameSpace_DNS = { /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */
+ 0x6ba7b810,
+ 0x9dad,
+ 0x11d1,
+ 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
+};
+
+/* puid -- print a UUID */
+void puid(uuid_t u)
+{
+ int i;
+
+ printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid,
+ u.time_hi_and_version, u.clock_seq_hi_and_reserved,
+ u.clock_seq_low);
+ for (i = 0; i < 6; i++)
+ printf("%2.2x", u.node[i]);
+ printf("\n");
+}
+
+/* Simple driver for UUID generator */
+void main(int argc, char **argv)
+{
+ uuid_t u;
+ int f;
+
+ uuid_create(&u);
+ printf("uuid_create(): "); puid(u);
+
+ f = uuid_compare(&u, &u);
+ printf("uuid_compare(u,u): %d\n", f); /* should be 0 */
+ f = uuid_compare(&u, &NameSpace_DNS);
+ printf("uuid_compare(u, NameSpace_DNS): %d\n", f); /* s.b. 1 */
+ f = uuid_compare(&NameSpace_DNS, &u);
+ printf("uuid_compare(NameSpace_DNS, u): %d\n", f); /* s.b. -1 */
+ uuid_create_md5_from_name(&u, NameSpace_DNS, "www.widgets.com", 15);
+ printf("uuid_create_md5_from_name(): "); puid(u);
+}
+
+Appendix B. Appendix B - Sample Output of utest
+
+ uuid_create(): 7d444840-9dc0-11d1-b245-5ffdce74fad2
+ uuid_compare(u,u): 0
+ uuid_compare(u, NameSpace_DNS): 1
+ uuid_compare(NameSpace_DNS, u): -1
+ uuid_create_md5_from_name(): e902893a-9d22-3c7e-a7b8-d6e313b71d9f
+
+
+
+
+
+Leach, et al. Standards Track [Page 29]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+Appendix C. Appendix C - Some Name Space IDs
+
+ This appendix lists the name space IDs for some potentially
+ interesting name spaces, as initialized C structures and in the
+ string representation defined above.
+
+ /* Name string is a fully-qualified domain name */
+ uuid_t NameSpace_DNS = { /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */
+ 0x6ba7b810,
+ 0x9dad,
+ 0x11d1,
+ 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
+ };
+
+ /* Name string is a URL */
+ uuid_t NameSpace_URL = { /* 6ba7b811-9dad-11d1-80b4-00c04fd430c8 */
+ 0x6ba7b811,
+ 0x9dad,
+ 0x11d1,
+ 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
+ };
+
+ /* Name string is an ISO OID */
+ uuid_t NameSpace_OID = { /* 6ba7b812-9dad-11d1-80b4-00c04fd430c8 */
+ 0x6ba7b812,
+ 0x9dad,
+ 0x11d1,
+ 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
+ };
+
+ /* Name string is an X.500 DN (in DER or a text output format) */
+ uuid_t NameSpace_X500 = { /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 */
+ 0x6ba7b814,
+ 0x9dad,
+ 0x11d1,
+ 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
+ };
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Leach, et al. Standards Track [Page 30]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+Authors' Addresses
+
+ Paul J. Leach
+ Microsoft
+ 1 Microsoft Way
+ Redmond, WA 98052
+ US
+
+ Phone: +1 425-882-8080
+ EMail: paulle@microsoft.com
+
+
+ Michael Mealling
+ Refactored Networks, LLC
+ 1635 Old Hwy 41
+ Suite 112, Box 138
+ Kennesaw, GA 30152
+ US
+
+ Phone: +1-678-581-9656
+ EMail: michael@refactored-networks.com
+ URI: http://www.refactored-networks.com
+
+
+ Rich Salz
+ DataPower Technology, Inc.
+ 1 Alewife Center
+ Cambridge, MA 02142
+ US
+
+ Phone: +1 617-864-0455
+ EMail: rsalz@datapower.com
+ URI: http://www.datapower.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Leach, et al. Standards Track [Page 31]
+
+RFC 4122 A UUID URN Namespace July 2005
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2005).
+
+ This document is subject to the rights, licenses and restrictions
+ contained in BCP 78, and except as set forth therein, the authors
+ retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the procedures with respect to rights in RFC documents can be
+ found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at ietf-
+ ipr@ietf.org.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+Leach, et al. Standards Track [Page 32]
+
diff --git a/standards/rfc4234.txt b/standards/rfc4234.txt
new file mode 100644
index 000000000..74d4c44f4
--- /dev/null
+++ b/standards/rfc4234.txt
@@ -0,0 +1,899 @@
+
+
+
+
+
+
+Network Working Group D. Crocker, Ed.
+Request for Comments: 4234 Brandenburg InternetWorking
+Obsoletes: 2234 P. Overell
+Category: Standards Track THUS plc.
+ October 2005
+
+
+ Augmented BNF for Syntax Specifications: ABNF
+
+Status of This Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2005).
+
+Abstract
+
+ Internet technical specifications often need to define a formal
+ syntax. Over the years, a modified version of Backus-Naur Form
+ (BNF), called Augmented BNF (ABNF), has been popular among many
+ Internet specifications. The current specification documents ABNF.
+ It balances compactness and simplicity, with reasonable
+ representational power. The differences between standard BNF and
+ ABNF involve naming rules, repetition, alternatives, order-
+ independence, and value ranges. This specification also supplies
+ additional rule definitions and encoding for a core lexical analyzer
+ of the type common to several Internet specifications.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 1]
+
+RFC 4234 ABNF October 2005
+
+
+Table of Contents
+
+ 1. INTRODUCTION ....................................................2
+ 2. RULE DEFINITION .................................................3
+ 2.1. Rule Naming ................................................3
+ 2.2. Rule Form ..................................................3
+ 2.3. Terminal Values ............................................4
+ 2.4. External Encodings .........................................5
+ 3. OPERATORS .......................................................6
+ 3.1. Concatenation: Rule1 Rule2 ................................6
+ 3.2. Alternatives: Rule1 / Rule2 ...............................6
+ 3.3. Incremental Alternatives: Rule1 =/ Rule2 ...................7
+ 3.4. Value Range Alternatives: %c##-## .........................7
+ 3.5. Sequence Group: (Rule1 Rule2) .............................8
+ 3.6. Variable Repetition: *Rule ................................8
+ 3.7. Specific Repetition: nRule ................................9
+ 3.8. Optional Sequence: [RULE] .................................9
+ 3.9. Comment: ; Comment ........................................9
+ 3.10. Operator Precedence .......................................9
+ 4. ABNF DEFINITION OF ABNF ........................................10
+ 5. SECURITY CONSIDERATIONS ........................................11
+ 6. References .....................................................11
+ 6.1. Normative References ......................................11
+ 6.2. Informative References ....................................11
+ Appendix A. ACKNOWLEDGEMENTS .....................................13
+ Appendix B. APPENDIX - CORE ABNF OF ABNF .........................13
+ B.1. Core Rules ...............................................13
+ B.2. Common Encoding ..........................................14
+
+1. INTRODUCTION
+
+ Internet technical specifications often need to define a formal
+ syntax and are free to employ whatever notation their authors deem
+ useful. Over the years, a modified version of Backus-Naur Form
+ (BNF), called Augmented BNF (ABNF), has been popular among many
+ Internet specifications. It balances compactness and simplicity,
+ with reasonable representational power. In the early days of the
+ Arpanet, each specification contained its own definition of ABNF.
+ This included the email specifications, [RFC733] and then [RFC822],
+ which came to be the common citations for defining ABNF. The current
+ document separates those definitions to permit selective reference.
+ Predictably, it also provides some modifications and enhancements.
+
+ The differences between standard BNF and ABNF involve naming rules,
+ repetition, alternatives, order-independence, and value ranges.
+ Appendix B supplies rule definitions and encoding for a core lexical
+ analyzer of the type common to several Internet specifications. It
+ is provided as a convenience and is otherwise separate from the meta
+
+
+
+Crocker & Overell Standards Track [Page 2]
+
+RFC 4234 ABNF October 2005
+
+
+ language defined in the body of this document, and separate from its
+ formal status.
+
+ Changes since [RFC2234]:
+
+ In Section 3.7, the phrase: "That is, exactly <N> occurrences of
+ <element>." was corrected to: "That is, exactly <n> occurrences of
+ <element>."
+
+ Some continuation comment lines needed to be corrected to begin
+ with comment character (";").
+
+2. RULE DEFINITION
+
+2.1. Rule Naming
+
+ The name of a rule is simply the name itself; that is, a sequence of
+ characters, beginning with an alphabetic character, and followed by a
+ combination of alphabetics, digits, and hyphens (dashes).
+
+ NOTE:
+
+ Rule names are case-insensitive
+
+ The names <rulename>, <Rulename>, <RULENAME>, and <rUlENamE> all
+ refer to the same rule.
+
+ Unlike original BNF, angle brackets ("<", ">") are not required.
+ However, angle brackets may be used around a rule name whenever their
+ presence facilitates in discerning the use of a rule name. This is
+ typically restricted to rule name references in free-form prose, or
+ to distinguish partial rules that combine into a string not separated
+ by white space, such as shown in the discussion about repetition,
+ below.
+
+2.2. Rule Form
+
+ A rule is defined by the following sequence:
+
+ name = elements crlf
+
+ where <name> is the name of the rule, <elements> is one or more rule
+ names or terminal specifications, and <crlf> is the end-of-line
+ indicator (carriage return followed by line feed). The equal sign
+ separates the name from the definition of the rule. The elements
+ form a sequence of one or more rule names and/or value definitions,
+ combined according to the various operators defined in this document,
+ such as alternative and repetition.
+
+
+
+Crocker & Overell Standards Track [Page 3]
+
+RFC 4234 ABNF October 2005
+
+
+ For visual ease, rule definitions are left aligned. When a rule
+ requires multiple lines, the continuation lines are indented. The
+ left alignment and indentation are relative to the first lines of the
+ ABNF rules and need not match the left margin of the document.
+
+2.3. Terminal Values
+
+ Rules resolve into a string of terminal values, sometimes called
+ characters. In ABNF, a character is merely a non-negative integer.
+ In certain contexts, a specific mapping (encoding) of values into a
+ character set (such as ASCII) will be specified.
+
+ Terminals are specified by one or more numeric characters, with the
+ base interpretation of those characters indicated explicitly. The
+ following bases are currently defined:
+
+ b = binary
+
+ d = decimal
+
+ x = hexadecimal
+
+ Hence:
+
+ CR = %d13
+
+ CR = %x0D
+
+ respectively specify the decimal and hexadecimal representation of
+ [US-ASCII] for carriage return.
+
+ A concatenated string of such values is specified compactly, using a
+ period (".") to indicate a separation of characters within that
+ value. Hence:
+
+ CRLF = %d13.10
+
+ ABNF permits the specification of literal text strings directly,
+ enclosed in quotation-marks. Hence:
+
+ command = "command string"
+
+ Literal text strings are interpreted as a concatenated set of
+ printable characters.
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 4]
+
+RFC 4234 ABNF October 2005
+
+
+ NOTE:
+
+ ABNF strings are case-insensitive and the character set for these
+ strings is us-ascii.
+
+ Hence:
+
+ rulename = "abc"
+
+ and:
+
+ rulename = "aBc"
+
+ will match "abc", "Abc", "aBc", "abC", "ABc", "aBC", "AbC", and
+ "ABC".
+
+ To specify a rule that IS case SENSITIVE, specify the characters
+ individually.
+
+ For example:
+
+ rulename = %d97 %d98 %d99
+
+ or
+
+ rulename = %d97.98.99
+
+ will match only the string that comprises only the lowercased
+ characters, abc.
+
+2.4. External Encodings
+
+ External representations of terminal value characters will vary
+ according to constraints in the storage or transmission environment.
+ Hence, the same ABNF-based grammar may have multiple external
+ encodings, such as one for a 7-bit US-ASCII environment, another for
+ a binary octet environment, and still a different one when 16-bit
+ Unicode is used. Encoding details are beyond the scope of ABNF,
+ although Appendix A (Core) provides definitions for a 7-bit US-ASCII
+ environment as has been common to much of the Internet.
+
+ By separating external encoding from the syntax, it is intended that
+ alternate encoding environments can be used for the same syntax.
+
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 5]
+
+RFC 4234 ABNF October 2005
+
+
+3. OPERATORS
+
+3.1. Concatenation: Rule1 Rule2
+
+ A rule can define a simple, ordered string of values (i.e., a
+ concatenation of contiguous characters) by listing a sequence of rule
+ names. For example:
+
+ foo = %x61 ; a
+
+ bar = %x62 ; b
+
+ mumble = foo bar foo
+
+ So that the rule <mumble> matches the lowercase string "aba".
+
+ LINEAR WHITE SPACE: Concatenation is at the core of the ABNF parsing
+ model. A string of contiguous characters (values) is parsed
+ according to the rules defined in ABNF. For Internet specifications,
+ there is some history of permitting linear white space (space and
+ horizontal tab) to be freely and implicitly interspersed around major
+ constructs, such as delimiting special characters or atomic strings.
+
+ NOTE:
+
+ This specification for ABNF does not provide for implicit
+ specification of linear white space.
+
+ Any grammar that wishes to permit linear white space around
+ delimiters or string segments must specify it explicitly. It is
+ often useful to provide for such white space in "core" rules that are
+ then used variously among higher-level rules. The "core" rules might
+ be formed into a lexical analyzer or simply be part of the main
+ ruleset.
+
+3.2. Alternatives: Rule1 / Rule2
+
+ Elements separated by a forward slash ("/") are alternatives.
+ Therefore,
+
+ foo / bar
+
+ will accept <foo> or <bar>.
+
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 6]
+
+RFC 4234 ABNF October 2005
+
+
+ NOTE:
+
+ A quoted string containing alphabetic characters is a special form
+ for specifying alternative characters and is interpreted as a
+ non-terminal representing the set of combinatorial strings with
+ the contained characters, in the specified order but with any
+ mixture of upper and lower case.
+
+3.3. Incremental Alternatives: Rule1 =/ Rule2
+
+ It is sometimes convenient to specify a list of alternatives in
+ fragments. That is, an initial rule may match one or more
+ alternatives, with later rule definitions adding to the set of
+ alternatives. This is particularly useful for otherwise, independent
+ specifications that derive from the same parent rule set, such as
+ often occurs with parameter lists. ABNF permits this incremental
+ definition through the construct:
+
+ oldrule =/ additional-alternatives
+
+ So that the rule set
+
+ ruleset = alt1 / alt2
+
+ ruleset =/ alt3
+
+ ruleset =/ alt4 / alt5
+
+ is the same as specifying
+
+ ruleset = alt1 / alt2 / alt3 / alt4 / alt5
+
+3.4. Value Range Alternatives: %c##-##
+
+ A range of alternative numeric values can be specified compactly,
+ using dash ("-") to indicate the range of alternative values. Hence:
+
+ DIGIT = %x30-39
+
+ is equivalent to:
+
+ DIGIT = "0" / "1" / "2" / "3" / "4" / "5" / "6" /
+
+ "7" / "8" / "9"
+
+ Concatenated numeric values and numeric value ranges cannot be
+ specified in the same string. A numeric value may use the dotted
+ notation for concatenation or it may use the dash notation to specify
+
+
+
+Crocker & Overell Standards Track [Page 7]
+
+RFC 4234 ABNF October 2005
+
+
+ one value range. Hence, to specify one printable character between
+ end of line sequences, the specification could be:
+
+ char-line = %x0D.0A %x20-7E %x0D.0A
+
+3.5. Sequence Group: (Rule1 Rule2)
+
+ Elements enclosed in parentheses are treated as a single element,
+ whose contents are STRICTLY ORDERED. Thus,
+
+ elem (foo / bar) blat
+
+ matches (elem foo blat) or (elem bar blat), and
+
+ elem foo / bar blat
+
+ matches (elem foo) or (bar blat).
+
+ NOTE:
+
+ It is strongly advised that grouping notation be used, rather than
+ relying on the proper reading of "bare" alternations, when
+ alternatives consist of multiple rule names or literals.
+
+ Hence, it is recommended that the following form be used:
+
+ (elem foo) / (bar blat)
+
+ It will avoid misinterpretation by casual readers.
+
+ The sequence group notation is also used within free text to set off
+ an element sequence from the prose.
+
+3.6. Variable Repetition: *Rule
+
+ The operator "*" preceding an element indicates repetition. The full
+ form is:
+
+ <a>*<b>element
+
+ where <a> and <b> are optional decimal values, indicating at least
+ <a> and at most <b> occurrences of the element.
+
+ Default values are 0 and infinity so that *<element> allows any
+ number, including zero; 1*<element> requires at least one;
+ 3*3<element> allows exactly 3 and 1*2<element> allows one or two.
+
+
+
+
+
+Crocker & Overell Standards Track [Page 8]
+
+RFC 4234 ABNF October 2005
+
+
+3.7. Specific Repetition: nRule
+
+ A rule of the form:
+
+ <n>element
+
+ is equivalent to
+
+ <n>*<n>element
+
+ That is, exactly <n> occurrences of <element>. Thus, 2DIGIT is a 2-
+ digit number, and 3ALPHA is a string of three alphabetic characters.
+
+3.8. Optional Sequence: [RULE]
+
+ Square brackets enclose an optional element sequence:
+
+ [foo bar]
+
+ is equivalent to
+
+ *1(foo bar).
+
+3.9. Comment: ; Comment
+
+ A semi-colon starts a comment that continues to the end of line.
+ This is a simple way of including useful notes in parallel with the
+ specifications.
+
+3.10. Operator Precedence
+
+ The various mechanisms described above have the following precedence,
+ from highest (binding tightest) at the top, to lowest (loosest) at
+ the bottom:
+
+ Strings, Names formation
+
+ Comment
+
+ Value range
+
+ Repetition
+
+ Grouping, Optional
+
+ Concatenation
+
+ Alternative
+
+
+
+Crocker & Overell Standards Track [Page 9]
+
+RFC 4234 ABNF October 2005
+
+
+ Use of the alternative operator, freely mixed with concatenations,
+ can be confusing.
+
+ Again, it is recommended that the grouping operator be used to
+ make explicit concatenation groups.
+
+4. ABNF DEFINITION OF ABNF
+
+ NOTES:
+
+ 1. This syntax requires a formatting of rules that is relatively
+ strict. Hence, the version of a ruleset included in a
+ specification might need preprocessing to ensure that it can be
+ interpreted by an ABNF parser.
+
+ 2. This syntax uses the rules provided in Appendix B (Core).
+
+ rulelist = 1*( rule / (*c-wsp c-nl) )
+
+ rule = rulename defined-as elements c-nl
+ ; continues if next line starts
+ ; with white space
+
+ rulename = ALPHA *(ALPHA / DIGIT / "-")
+
+ defined-as = *c-wsp ("=" / "=/") *c-wsp
+ ; basic rules definition and
+ ; incremental alternatives
+
+ elements = alternation *c-wsp
+
+ c-wsp = WSP / (c-nl WSP)
+
+ c-nl = comment / CRLF
+ ; comment or newline
+
+ comment = ";" *(WSP / VCHAR) CRLF
+
+ alternation = concatenation
+ *(*c-wsp "/" *c-wsp concatenation)
+
+ concatenation = repetition *(1*c-wsp repetition)
+
+ repetition = [repeat] element
+
+ repeat = 1*DIGIT / (*DIGIT "*" *DIGIT)
+
+
+
+
+
+Crocker & Overell Standards Track [Page 10]
+
+RFC 4234 ABNF October 2005
+
+
+ element = rulename / group / option /
+ char-val / num-val / prose-val
+
+ group = "(" *c-wsp alternation *c-wsp ")"
+
+ option = "[" *c-wsp alternation *c-wsp "]"
+
+ char-val = DQUOTE *(%x20-21 / %x23-7E) DQUOTE
+ ; quoted string of SP and VCHAR
+ ; without DQUOTE
+
+ num-val = "%" (bin-val / dec-val / hex-val)
+
+ bin-val = "b" 1*BIT
+ [ 1*("." 1*BIT) / ("-" 1*BIT) ]
+ ; series of concatenated bit values
+ ; or single ONEOF range
+
+ dec-val = "d" 1*DIGIT
+ [ 1*("." 1*DIGIT) / ("-" 1*DIGIT) ]
+
+ hex-val = "x" 1*HEXDIG
+ [ 1*("." 1*HEXDIG) / ("-" 1*HEXDIG) ]
+
+ prose-val = "<" *(%x20-3D / %x3F-7E) ">"
+ ; bracketed string of SP and VCHAR
+ ; without angles
+ ; prose description, to be used as
+ ; last resort
+
+5. SECURITY CONSIDERATIONS
+
+ Security is truly believed to be irrelevant to this document.
+
+6. References
+
+6.1. Normative References
+
+ [US-ASCII] American National Standards Institute, "Coded Character
+ Set -- 7-bit American Standard Code for Information
+ Interchange", ANSI X3.4, 1986.
+
+6.2. Informative References
+
+ [RFC2234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+
+
+
+
+Crocker & Overell Standards Track [Page 11]
+
+RFC 4234 ABNF October 2005
+
+
+ [RFC733] Crocker, D., Vittal, J., Pogran, K., and D. Henderson,
+ "Standard for the format of ARPA network text messages",
+ RFC 733, November 1977.
+
+ [RFC822] Crocker, D., "Standard for the format of ARPA Internet
+ text messages", STD 11, RFC 822, August 1982.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 12]
+
+RFC 4234 ABNF October 2005
+
+
+Appendix A. ACKNOWLEDGEMENTS
+
+ The syntax for ABNF was originally specified in RFC 733. Ken L.
+ Harrenstien, of SRI International, was responsible for re-coding the
+ BNF into an augmented BNF that makes the representation smaller and
+ easier to understand.
+
+ This recent project began as a simple effort to cull out the portion
+ of RFC 822 that has been repeatedly cited by non-email specification
+ writers, namely the description of augmented BNF. Rather than simply
+ and blindly converting the existing text into a separate document,
+ the working group chose to give careful consideration to the
+ deficiencies, as well as benefits, of the existing specification and
+ related specifications made available over the last 15 years, and
+ therefore to pursue enhancement. This turned the project into
+ something rather more ambitious than was first intended.
+ Interestingly, the result is not massively different from that
+ original, although decisions, such as removing the list notation,
+ came as a surprise.
+
+ This "separated" version of the specification was part of the DRUMS
+ working group, with significant contributions from Jerome Abela,
+ Harald Alvestrand, Robert Elz, Roger Fajman, Aviva Garrett, Tom
+ Harsch, Dan Kohn, Bill McQuillan, Keith Moore, Chris Newman, Pete
+ Resnick, and Henning Schulzrinne.
+
+ Julian Reschke warrants a special thanks for converting the Draft
+ Standard version to XML source form.
+
+Appendix B. APPENDIX - CORE ABNF OF ABNF
+
+ This Appendix is provided as a convenient core for specific grammars.
+ The definitions may be used as a core set of rules.
+
+B.1. Core Rules
+
+ Certain basic rules are in uppercase, such as SP, HTAB, CRLF, DIGIT,
+ ALPHA, etc.
+
+ ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+
+ BIT = "0" / "1"
+
+ CHAR = %x01-7F
+ ; any 7-bit US-ASCII character,
+ ; excluding NUL
+
+
+
+
+
+Crocker & Overell Standards Track [Page 13]
+
+RFC 4234 ABNF October 2005
+
+
+ CR = %x0D
+ ; carriage return
+
+ CRLF = CR LF
+ ; Internet standard newline
+
+ CTL = %x00-1F / %x7F
+ ; controls
+
+ DIGIT = %x30-39
+ ; 0-9
+
+ DQUOTE = %x22
+ ; " (Double Quote)
+
+ HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
+
+ HTAB = %x09
+ ; horizontal tab
+
+ LF = %x0A
+ ; linefeed
+
+ LWSP = *(WSP / CRLF WSP)
+ ; linear white space (past newline)
+
+ OCTET = %x00-FF
+ ; 8 bits of data
+
+ SP = %x20
+
+ VCHAR = %x21-7E
+ ; visible (printing) characters
+
+ WSP = SP / HTAB
+ ; white space
+
+B.2. Common Encoding
+
+ Externally, data are represented as "network virtual ASCII" (namely,
+ 7-bit US-ASCII in an 8-bit field), with the high (8th) bit set to
+ zero. A string of values is in "network byte order", in which the
+ higher-valued bytes are represented on the left-hand side and are
+ sent over the network first.
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 14]
+
+RFC 4234 ABNF October 2005
+
+
+Authors' Addresses
+
+ Dave Crocker (editor)
+ Brandenburg InternetWorking
+ 675 Spruce Dr.
+ Sunnyvale, CA 94086
+ US
+
+ Phone: +1.408.246.8253
+ EMail: dcrocker@bbiw.net
+
+
+ Paul Overell
+ THUS plc.
+ 1/2 Berkeley Square
+ 99 Berkeley Street
+ Glasgow
+ G3 7HR
+ UK
+
+ EMail: paul.overell@thus.net
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 15]
+
+RFC 4234 ABNF October 2005
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2005).
+
+ This document is subject to the rights, licenses and restrictions
+ contained in BCP 78, and except as set forth therein, the authors
+ retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the procedures with respect to rights in RFC documents can be
+ found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at ietf-
+ ipr@ietf.org.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 16]
+
diff --git a/standards/rfc4646.txt b/standards/rfc4646.txt
new file mode 100644
index 000000000..466d54744
--- /dev/null
+++ b/standards/rfc4646.txt
@@ -0,0 +1,3307 @@
+
+
+
+
+
+
+Network Working Group A. Phillips, Ed.
+Request for Comments: 4646 Yahoo! Inc.
+BCP: 47 M. Davis, Ed.
+Obsoletes: 3066 Google
+Category: Best Current Practice September 2006
+
+
+ Tags for Identifying Languages
+
+Status of This Memo
+
+ This document specifies an Internet Best Current Practices for the
+ Internet Community, and requests discussion and suggestions for
+ improvements. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2005).
+
+Abstract
+
+ This document describes the structure, content, construction, and
+ semantics of language tags for use in cases where it is desirable to
+ indicate the language used in an information object. It also
+ describes how to register values for use in language tags and the
+ creation of user-defined extensions for private interchange. This
+ document, in combination with RFC 4647, replaces RFC 3066, which
+ replaced RFC 1766.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 1]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+Table of Contents
+
+ 1. Introduction ....................................................3
+ 2. The Language Tag ................................................4
+ 2.1. Syntax .....................................................4
+ 2.2. Language Subtag Sources and Interpretation .................7
+ 2.2.1. Primary Language Subtag .............................8
+ 2.2.2. Extended Language Subtags ..........................10
+ 2.2.3. Script Subtag ......................................11
+ 2.2.4. Region Subtag ......................................11
+ 2.2.5. Variant Subtags ....................................13
+ 2.2.6. Extension Subtags ..................................14
+ 2.2.7. Private Use Subtags ................................16
+ 2.2.8. Preexisting RFC 3066 Registrations .................16
+ 2.2.9. Classes of Conformance .............................17
+ 3. Registry Format and Maintenance ................................18
+ 3.1. Format of the IANA Language Subtag Registry ...............18
+ 3.2. Language Subtag Reviewer ..................................24
+ 3.3. Maintenance of the Registry ...............................24
+ 3.4. Stability of IANA Registry Entries ........................25
+ 3.5. Registration Procedure for Subtags ........................29
+ 3.6. Possibilities for Registration ............................32
+ 3.7. Extensions and Extensions Registry ........................34
+ 3.8. Initialization of the Registries ..........................37
+ 4. Formation and Processing of Language Tags ......................38
+ 4.1. Choice of Language Tag ....................................38
+ 4.2. Meaning of the Language Tag ...............................40
+ 4.3. Length Considerations .....................................41
+ 4.3.1. Working with Limited Buffer Sizes ..................42
+ 4.3.2. Truncation of Language Tags ........................43
+ 4.4. Canonicalization of Language Tags .........................44
+ 4.5. Considerations for Private Use Subtags ....................45
+ 5. IANA Considerations ............................................46
+ 5.1. Language Subtag Registry ..................................46
+ 5.2. Extensions Registry .......................................47
+ 6. Security Considerations ........................................48
+ 7. Character Set Considerations ...................................48
+ 8. Changes from RFC 3066 ..........................................49
+ 9. References .....................................................52
+ 9.1. Normative References ......................................52
+ 9.2. Informative References ....................................53
+ Appendix A. Acknowledgements ......................................55
+ Appendix B. Examples of Language Tags (Informative) ...............56
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 2]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+1. Introduction
+
+ Human beings on our planet have, past and present, used a number of
+ languages. There are many reasons why one would want to identify the
+ language used when presenting or requesting information.
+
+ A user's language preferences often need to be identified so that
+ appropriate processing can be applied. For example, the user's
+ language preferences in a Web browser can be used to select Web pages
+ appropriately. Language preferences can also be used to select among
+ tools (such as dictionaries) to assist in the processing or
+ understanding of content in different languages.
+
+ In addition, knowledge about the particular language used by some
+ piece of information content might be useful or even required by some
+ types of processing; for example, spell-checking, computer-
+ synthesized speech, Braille transcription, or high-quality print
+ renderings.
+
+ One means of indicating the language used is by labeling the
+ information content with an identifier or "tag". These tags can be
+ used to specify user preferences when selecting information content,
+ or for labeling additional attributes of content and associated
+ resources.
+
+ Tags can also be used to indicate additional language attributes of
+ content. For example, indicating specific information about the
+ dialect, writing system, or orthography used in a document or
+ resource may enable the user to obtain information in a form that
+ they can understand, or it can be important in processing or
+ rendering the given content into an appropriate form or style.
+
+ This document specifies a particular identifier mechanism (the
+ language tag) and a registration function for values to be used to
+ form tags. It also defines a mechanism for private use values and
+ future extension.
+
+ This document, in combination with [RFC4647], replaces [RFC3066],
+ which replaced [RFC1766]. For a list of changes in this document,
+ see Section 8.
+
+ The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [RFC2119].
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 3]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+2. The Language Tag
+
+ Language tags are used to help identify languages, whether spoken,
+ written, signed, or otherwise signaled, for the purpose of
+ communication. This includes constructed and artificial languages,
+ but excludes languages not intended primarily for human
+ communication, such as programming languages.
+
+2.1. Syntax
+
+ The language tag is composed of one or more parts, known as
+ "subtags". Each subtag consists of a sequence of alphanumeric
+ characters. Subtags are distinguished and separated from one another
+ by a hyphen ("-", ABNF [RFC4234] %x2D). A language tag consists of a
+ "primary language" subtag and a (possibly empty) series of subsequent
+ subtags, each of which refines or narrows the range of languages
+ identified by the overall tag.
+
+ Usually, each type of subtag is distinguished by length, position in
+ the tag, and content: subtags can be recognized solely by these
+ features. The only exception to this is a fixed list of
+ grandfathered tags registered under RFC 3066 [RFC3066]. This makes
+ it possible to construct a parser that can extract and assign some
+ semantic information to the subtags, even if the specific subtag
+ values are not recognized. Thus, a parser need not have an up-to-
+ date copy (or any copy at all) of the subtag registry to perform most
+ searching and matching operations.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 4]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The syntax of the language tag in ABNF [RFC4234] is:
+
+ Language-Tag = langtag
+ / privateuse ; private use tag
+ / grandfathered ; grandfathered registrations
+
+ langtag = (language
+ ["-" script]
+ ["-" region]
+ *("-" variant)
+ *("-" extension)
+ ["-" privateuse])
+
+ language = (2*3ALPHA [ extlang ]) ; shortest ISO 639 code
+ / 4ALPHA ; reserved for future use
+ / 5*8ALPHA ; registered language subtag
+
+ extlang = *3("-" 3ALPHA) ; reserved for future use
+
+ script = 4ALPHA ; ISO 15924 code
+
+ region = 2ALPHA ; ISO 3166 code
+ / 3DIGIT ; UN M.49 code
+
+ variant = 5*8alphanum ; registered variants
+ / (DIGIT 3alphanum)
+
+ extension = singleton 1*("-" (2*8alphanum))
+
+ singleton = %x41-57 / %x59-5A / %x61-77 / %x79-7A / DIGIT
+ ; "a"-"w" / "y"-"z" / "A"-"W" / "Y"-"Z" / "0"-"9"
+ ; Single letters: x/X is reserved for private use
+
+ privateuse = ("x"/"X") 1*("-" (1*8alphanum))
+
+ grandfathered = 1*3ALPHA 1*2("-" (2*8alphanum))
+ ; grandfathered registration
+ ; Note: i is the only singleton
+ ; that starts a grandfathered tag
+
+ alphanum = (ALPHA / DIGIT) ; letters and numbers
+
+ Figure 1: Language Tag ABNF
+
+ Note: There is a subtlety in the ABNF for 'variant': variants
+ starting with a digit MAY be four characters long, while those
+ starting with a letter MUST be at least five characters long.
+
+
+
+
+Phillips & Davis Best Current Practice [Page 5]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ All subtags have a maximum length of eight characters and whitespace
+ is not permitted in a language tag. For examples of language tags,
+ see Appendix B.
+
+ Note that although [RFC4234] refers to octets, the language tags
+ described in this document are sequences of characters from the
+ US-ASCII [ISO646] repertoire. Language tags MAY be used in documents
+ and applications that use other encodings, so long as these encompass
+ the US-ASCII repertoire. An example of this would be an XML document
+ that uses the UTF-16LE [RFC2781] encoding of [Unicode].
+
+ The tags and their subtags, including private use and extensions, are
+ to be treated as case insensitive: there exist conventions for the
+ capitalization of some of the subtags, but these MUST NOT be taken to
+ carry meaning.
+
+ For example:
+
+ o [ISO639-1] recommends that language codes be written in lowercase
+ ('mn' Mongolian).
+
+ o [ISO3166-1] recommends that country codes be capitalized ('MN'
+ Mongolia).
+
+ o [ISO15924] recommends that script codes use lowercase with the
+ initial letter capitalized ('Cyrl' Cyrillic).
+
+ However, in the tags defined by this document, the uppercase US-ASCII
+ letters in the range 'A' through 'Z' are considered equivalent and
+ mapped directly to their US-ASCII lowercase equivalents in the range
+ 'a' through 'z'. Thus, the tag "mn-Cyrl-MN" is not distinct from
+ "MN-cYRL-mn" or "mN-cYrL-Mn" (or any other combination), and each of
+ these variations conveys the same meaning: Mongolian written in the
+ Cyrillic script as used in Mongolia.
+
+ Although case distinctions do not carry meaning in language tags,
+ consistent formatting and presentation of the tags will aid users.
+ The format of the tags and subtags in the registry is RECOMMENDED.
+ In this format, all non-initial two-letter subtags are uppercase, all
+ non-initial four-letter subtags are titlecase, and all other subtags
+ are lowercase.
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 6]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+2.2. Language Subtag Sources and Interpretation
+
+ The namespace of language tags and their subtags is administered by
+ the Internet Assigned Numbers Authority (IANA) [RFC2860] according to
+ the rules in Section 5 of this document. The Language Subtag
+ Registry maintained by IANA is the source for valid subtags: other
+ standards referenced in this section provide the source material for
+ that registry.
+
+ Terminology in this section:
+
+ o Tag or tags refers to a complete language tag, such as
+ "fr-Latn-CA". Examples of tags in this document are enclosed in
+ double-quotes ("en-US").
+
+ o Subtag refers to a specific section of a tag, delimited by hyphen,
+ such as the subtag 'Latn' in "fr-Latn-CA". Examples of subtags in
+ this document are enclosed in single quotes ('Latn').
+
+ o Code or codes refers to values defined in external standards (and
+ that are used as subtags in this document). For example, 'Latn'
+ is an [ISO15924] script code that was used to define the 'Latn'
+ script subtag for use in a language tag. Examples of codes in
+ this document are enclosed in single quotes ('en', 'Latn').
+
+ The definitions in this section apply to the various subtags within
+ the language tags defined by this document, excepting those
+ "grandfathered" tags defined in Section 2.2.8.
+
+ Language tags are designed so that each subtag type has unique length
+ and content restrictions. These make identification of the subtag's
+ type possible, even if the content of the subtag itself is
+ unrecognized. This allows tags to be parsed and processed without
+ reference to the latest version of the underlying standards or the
+ IANA registry and makes the associated exception handling when
+ parsing tags simpler.
+
+ Subtags in the IANA registry that do not come from an underlying
+ standard can only appear in specific positions in a tag.
+ Specifically, they can only occur as primary language subtags or as
+ variant subtags.
+
+ Note that sequences of private use and extension subtags MUST occur
+ at the end of the sequence of subtags and MUST NOT be interspersed
+ with subtags defined elsewhere in this document.
+
+ Single-letter and single-digit subtags are reserved for current or
+ future use. These include the following current uses:
+
+
+
+Phillips & Davis Best Current Practice [Page 7]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ o The single-letter subtag 'x' is reserved to introduce a sequence
+ of private use subtags. The interpretation of any private use
+ subtags is defined solely by private agreement and is not defined
+ by the rules in this section or in any standard or registry
+ defined in this document.
+
+ o All other single-letter subtags are reserved to introduce
+ standardized extension subtag sequences as described in
+ Section 3.7.
+
+ The single-letter subtag 'i' is used by some grandfathered tags, such
+ as "i-enochian", where it always appears in the first position and
+ cannot be confused with an extension.
+
+2.2.1. Primary Language Subtag
+
+ The primary language subtag is the first subtag in a language tag
+ (with the exception of private use and certain grandfathered tags)
+ and cannot be omitted. The following rules apply to the primary
+ language subtag:
+
+ 1. All two-character language subtags were defined in the IANA
+ registry according to the assignments found in the standard ISO
+ 639 Part 1, "ISO 639-1:2002, Codes for the representation of
+ names of languages -- Part 1: Alpha-2 code" [ISO639-1], or using
+ assignments subsequently made by the ISO 639 Part 1 maintenance
+ agency or governing standardization bodies.
+
+ 2. All three-character language subtags were defined in the IANA
+ registry according to the assignments found in ISO 639 Part 2,
+ "ISO 639-2:1998 - Codes for the representation of names of
+ languages -- Part 2: Alpha-3 code - edition 1" [ISO639-2], or
+ assignments subsequently made by the ISO 639 Part 2 maintenance
+ agency or governing standardization bodies.
+
+ 3. The subtags in the range 'qaa' through 'qtz' are reserved for
+ private use in language tags. These subtags correspond to codes
+ reserved by ISO 639-2 for private use. These codes MAY be used
+ for non-registered primary language subtags (instead of using
+ private use subtags following 'x-'). Please refer to Section 4.5
+ for more information on private use subtags.
+
+ 4. All four-character language subtags are reserved for possible
+ future standardization.
+
+ 5. All language subtags of 5 to 8 characters in length in the IANA
+ registry were defined via the registration process in Section 3.5
+ and MAY be used to form the primary language subtag. At the time
+
+
+
+Phillips & Davis Best Current Practice [Page 8]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ this document was created, there were no examples of this kind of
+ subtag and future registrations of this type will be discouraged:
+ primary languages are strongly RECOMMENDED for registration with
+ ISO 639, and proposals rejected by ISO 639/RA will be closely
+ scrutinized before they are registered with IANA.
+
+ 6. The single-character subtag 'x' as the primary subtag indicates
+ that the language tag consists solely of subtags whose meaning is
+ defined by private agreement. For example, in the tag "x-fr-CH",
+ the subtags 'fr' and 'CH' SHOULD NOT be taken to represent the
+ French language or the country of Switzerland (or any other value
+ in the IANA registry) unless there is a private agreement in
+ place to do so. See Section 4.5.
+
+ 7. The single-character subtag 'i' is used by some grandfathered
+ tags (see Section 2.2.8) such as "i-klingon" and "i-bnn". (Other
+ grandfathered tags have a primary language subtag in their first
+ position.)
+
+ 8. Other values MUST NOT be assigned to the primary subtag except by
+ revision or update of this document.
+
+ Note: For languages that have both an ISO 639-1 two-character code
+ and an ISO 639-2 three-character code, only the ISO 639-1 two-
+ character code is defined in the IANA registry.
+
+ Note: For languages that have no ISO 639-1 two-character code and for
+ which the ISO 639-2/T (Terminology) code and the ISO 639-2/B
+ (Bibliographic) codes differ, only the Terminology code is defined in
+ the IANA registry. At the time this document was created, all
+ languages that had both kinds of three-character code were also
+ assigned a two-character code; it is not expected that future
+ assignments of this nature will occur.
+
+ Note: To avoid problems with versioning and subtag choice as
+ experienced during the transition between RFC 1766 and RFC 3066, as
+ well as the canonical nature of subtags defined by this document, the
+ ISO 639 Registration Authority Joint Advisory Committee (ISO 639/
+ RA-JAC) has included the following statement in [iso639.prin]:
+
+ "A language code already in ISO 639-2 at the point of freezing ISO
+ 639-1 shall not later be added to ISO 639-1. This is to ensure
+ consistency in usage over time, since users are directed in Internet
+ applications to employ the alpha-3 code when an alpha-2 code for that
+ language is not available."
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 9]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ In order to avoid instability in the canonical form of tags, if a
+ two-character code is added to ISO 639-1 for a language for which a
+ three-character code was already included in ISO 639-2, the two-
+ character code MUST NOT be registered. See Section 3.4.
+
+ For example, if some content were tagged with 'haw' (Hawaiian), which
+ currently has no two-character code, the tag would not be invalidated
+ if ISO 639-1 were to assign a two-character code to the Hawaiian
+ language at a later date.
+
+ For example, one of the grandfathered IANA registrations is
+ "i-enochian". The subtag 'enochian' could be registered in the IANA
+ registry as a primary language subtag (assuming that ISO 639 does not
+ register this language first), making tags such as "enochian-AQ" and
+ "enochian-Latn" valid.
+
+2.2.2. Extended Language Subtags
+
+ The following rules apply to the extended language subtags:
+
+ 1. Three-letter subtags immediately following the primary subtag are
+ reserved for future standardization, anticipating work that is
+ currently under way on ISO 639.
+
+ 2. Extended language subtags MUST follow the primary subtag and
+ precede any other subtags.
+
+ 3. There MAY be up to three extended language subtags.
+
+ 4. Extended language subtags MUST NOT be registered or used to form
+ language tags. Their syntax is described here so that
+ implementations can be compatible with any future revision of
+ this document that does provide for their registration.
+
+ Extended language subtag records, once they appear in the registry,
+ MUST include exactly one 'Prefix' field indicating an appropriate
+ language subtag or sequence of subtags that MUST always appear as a
+ prefix to the extended language subtag.
+
+ Example: In a future revision or update of this document, the tag
+ "zh-gan" (registered under RFC 3066) might become a valid non-
+ grandfathered (that is, redundant) tag in which the subtag 'gan'
+ might represent the Chinese dialect 'Gan'.
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 10]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+2.2.3. Script Subtag
+
+ Script subtags are used to indicate the script or writing system
+ variations that distinguish the written forms of a language or its
+ dialects. The following rules apply to the script subtags:
+
+ 1. All four-character subtags were defined according to
+ [ISO15924]--"Codes for the representation of names of scripts":
+ alpha-4 script codes, or subsequently assigned by the ISO 15924
+ maintenance agency or governing standardization bodies, denoting
+ the script or writing system used in conjunction with this
+ language.
+
+ 2. Script subtags MUST immediately follow the primary language
+ subtag and all extended language subtags and MUST occur before
+ any other type of subtag described below.
+
+ 3. The script subtags 'Qaaa' through 'Qabx' are reserved for private
+ use in language tags. These subtags correspond to codes reserved
+ by ISO 15924 for private use. These codes MAY be used for non-
+ registered script values. Please refer to Section 4.5 for more
+ information on private use subtags.
+
+ 4. Script subtags MUST NOT be registered using the process in
+ Section 3.5 of this document. Variant subtags MAY be considered
+ for registration for that purpose.
+
+ 5. There MUST be at most one script subtag in a language tag, and
+ the script subtag SHOULD be omitted when it adds no
+ distinguishing value to the tag or when the primary language
+ subtag's record includes a Suppress-Script field listing the
+ applicable script subtag.
+
+ Example: "sr-Latn" represents Serbian written using the Latin script.
+
+2.2.4. Region Subtag
+
+ Region subtags are used to indicate linguistic variations associated
+ with or appropriate to a specific country, territory, or region.
+ Typically, a region subtag is used to indicate regional dialects or
+ usage, or region-specific spelling conventions. A region subtag can
+ also be used to indicate that content is expressed in a way that is
+ appropriate for use throughout a region, for instance, Spanish
+ content tailored to be useful throughout Latin America.
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 11]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The following rules apply to the region subtags:
+
+ 1. Region subtags MUST follow any language, extended language, or
+ script subtags and MUST precede all other subtags.
+
+ 2. All two-character subtags following the primary subtag were
+ defined in the IANA registry according to the assignments found
+ in [ISO3166-1] ("Codes for the representation of names of
+ countries and their subdivisions -- Part 1: Country codes") using
+ the list of alpha-2 country codes, or using assignments
+ subsequently made by the ISO 3166 maintenance agency or governing
+ standardization bodies.
+
+ 3. All three-character subtags consisting of digit (numeric)
+ characters following the primary subtag were defined in the IANA
+ registry according to the assignments found in UN Standard
+ Country or Area Codes for Statistical Use [UN_M.49] or
+ assignments subsequently made by the governing standards body.
+ Note that not all of the UN M.49 codes are defined in the IANA
+ registry. The following rules define which codes are entered
+ into the registry as valid subtags:
+
+ A. UN numeric codes assigned to 'macro-geographical
+ (continental)' or sub-regions MUST be registered in the
+ registry. These codes are not associated with an assigned
+ ISO 3166 alpha-2 code and represent supra-national areas,
+ usually covering more than one nation, state, province, or
+ territory.
+
+ B. UN numeric codes for 'economic groupings' or 'other
+ groupings' MUST NOT be registered in the IANA registry and
+ MUST NOT be used to form language tags.
+
+ C. UN numeric codes for countries or areas with ambiguous ISO
+ 3166 alpha-2 codes, when entered into the registry, MUST be
+ defined according to the rules in Section 3.4 and MUST be
+ used to form language tags that represent the country or
+ region for which they are defined.
+
+ D. UN numeric codes for countries or areas for which there is an
+ associated ISO 3166 alpha-2 code in the registry MUST NOT be
+ entered into the registry and MUST NOT be used to form
+ language tags. Note that the ISO 3166-based subtag in the
+ registry MUST actually be associated with the UN M.49 code in
+ question.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 12]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ E. UN numeric codes and ISO 3166 alpha-2 codes for countries or
+ areas listed as eligible for registration in [RFC4645] but
+ not presently registered MAY be entered into the IANA
+ registry via the process described in Section 3.5. Once
+ registered, these codes MAY be used to form language tags.
+
+ F. All other UN numeric codes for countries or areas that do not
+ have an associated ISO 3166 alpha-2 code MUST NOT be entered
+ into the registry and MUST NOT be used to form language tags.
+ For more information about these codes, see Section 3.4.
+
+ 4. Note: The alphanumeric codes in Appendix X of the UN document
+ MUST NOT be entered into the registry and MUST NOT be used to
+ form language tags. (At the time this document was created,
+ these values matched the ISO 3166 alpha-2 codes.)
+
+ 5. There MUST be at most one region subtag in a language tag and the
+ region subtag MAY be omitted, as when it adds no distinguishing
+ value to the tag.
+
+ 6. The region subtags 'AA', 'QM'-'QZ', 'XA'-'XZ', and 'ZZ' are
+ reserved for private use in language tags. These subtags
+ correspond to codes reserved by ISO 3166 for private use. These
+ codes MAY be used for private use region subtags (instead of
+ using a private use subtag sequence). Please refer to
+ Section 4.5 for more information on private use subtags.
+
+ "de-CH" represents German ('de') as used in Switzerland ('CH').
+
+ "sr-Latn-CS" represents Serbian ('sr') written using Latin script
+ ('Latn') as used in Serbia and Montenegro ('CS').
+
+ "es-419" represents Spanish ('es') appropriate to the UN-defined
+ Latin America and Caribbean region ('419').
+
+2.2.5. Variant Subtags
+
+ Variant subtags are used to indicate additional, well-recognized
+ variations that define a language or its dialects that are not
+ covered by other available subtags. The following rules apply to the
+ variant subtags:
+
+ 1. Variant subtags are not associated with any external standard.
+ Variant subtags and their meanings are defined by the
+ registration process defined in Section 3.5.
+
+ 2. Variant subtags MUST follow all of the other defined subtags, but
+ precede any extension or private use subtag sequences.
+
+
+
+Phillips & Davis Best Current Practice [Page 13]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ 3. More than one variant MAY be used to form the language tag.
+
+ 4. Variant subtags MUST be registered with IANA according to the
+ rules in Section 3.5 of this document before being used to form
+ language tags. In order to distinguish variants from other types
+ of subtags, registrations MUST meet the following length and
+ content restrictions:
+
+ 1. Variant subtags that begin with a letter (a-z, A-Z) MUST be
+ at least five characters long.
+
+ 2. Variant subtags that begin with a digit (0-9) MUST be at
+ least four characters long.
+
+ Variant subtag records in the language subtag registry MAY include
+ one or more 'Prefix' fields, which indicate the language tag or tags
+ that would make a suitable prefix (with other subtags, as
+ appropriate) in forming a language tag with the variant. For
+ example, the subtag 'nedis' has a Prefix of "sl", making it suitable
+ to form language tags such as "sl-nedis" and "sl-IT-nedis", but not
+ suitable for use in a tag such as "zh-nedis" or "it-IT-nedis".
+
+ "sl-nedis" represents the Natisone or Nadiza dialect of Slovenian.
+
+ "de-CH-1996" represents German as used in Switzerland and as written
+ using the spelling reform beginning in the year 1996 C.E.
+
+ Most variants that share a prefix are mutually exclusive. For
+ example, the German orthographic variations '1996' and '1901' SHOULD
+ NOT be used in the same tag, as they represent the dates of different
+ spelling reforms. A variant that can meaningfully be used in
+ combination with another variant SHOULD include a 'Prefix' field in
+ its registry record that lists that other variant. For example, if
+ another German variant 'example' were created that made sense to use
+ with '1996', then 'example' should include two Prefix fields: "de"
+ and "de-1996".
+
+2.2.6. Extension Subtags
+
+ Extensions provide a mechanism for extending language tags for use in
+ various applications. See Section 3.7. The following rules apply to
+ extensions:
+
+ 1. Extension subtags are separated from the other subtags defined
+ in this document by a single-character subtag ("singleton").
+ The singleton MUST be one allocated to a registration authority
+ via the mechanism described in Section 3.7 and MUST NOT be the
+ letter 'x', which is reserved for private use subtag sequences.
+
+
+
+Phillips & Davis Best Current Practice [Page 14]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ 2. Note: Private use subtag sequences starting with the singleton
+ subtag 'x' are described in Section 2.2.7 below.
+
+ 3. An extension MUST follow at least a primary language subtag.
+ That is, a language tag cannot begin with an extension.
+ Extensions extend language tags, they do not override or replace
+ them. For example, "a-value" is not a well-formed language tag,
+ while "de-a-value" is.
+
+ 4. Each singleton subtag MUST appear at most one time in each tag
+ (other than as a private use subtag). That is, singleton
+ subtags MUST NOT be repeated. For example, the tag
+ "en-a-bbb-a-ccc" is invalid because the subtag 'a' appears
+ twice. Note that the tag "en-a-bbb-x-a-ccc" is valid because
+ the second appearance of the singleton 'a' is in a private use
+ sequence.
+
+ 5. Extension subtags MUST meet all of the requirements for the
+ content and format of subtags defined in this document.
+
+ 6. Extension subtags MUST meet whatever requirements are set by the
+ document that defines their singleton prefix and whatever
+ requirements are provided by the maintaining authority.
+
+ 7. Each extension subtag MUST be from two to eight characters long
+ and consist solely of letters or digits, with each subtag
+ separated by a single '-'.
+
+ 8. Each singleton MUST be followed by at least one extension
+ subtag. For example, the tag "tlh-a-b-foo" is invalid because
+ the first singleton 'a' is followed immediately by another
+ singleton 'b'.
+
+ 9. Extension subtags MUST follow all language, extended language,
+ script, region, and variant subtags in a tag.
+
+ 10. All subtags following the singleton and before another singleton
+ are part of the extension. Example: In the tag "fr-a-Latn", the
+ subtag 'Latn' does not represent the script subtag 'Latn'
+ defined in the IANA Language Subtag Registry. Its meaning is
+ defined by the extension 'a'.
+
+ 11. In the event that more than one extension appears in a single
+ tag, the tag SHOULD be canonicalized as described in
+ Section 4.4.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 15]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ For example, if the prefix singleton 'r' and the shown subtags were
+ defined, then the following tag would be a valid example:
+ "en-Latn-GB-boont-r-extended-sequence-x-private".
+
+2.2.7. Private Use Subtags
+
+ Private use subtags are used to indicate distinctions in language
+ important in a given context by private agreement. The following
+ rules apply to private use subtags:
+
+ 1. Private use subtags are separated from the other subtags defined
+ in this document by the reserved single-character subtag 'x'.
+
+ 2. Private use subtags MUST conform to the format and content
+ constraints defined in the ABNF for all subtags.
+
+ 3. Private use subtags MUST follow all language, extended language,
+ script, region, variant, and extension subtags in the tag.
+ Another way of saying this is that all subtags following the
+ singleton 'x' MUST be considered private use. Example: The
+ subtag 'US' in the tag "en-x-US" is a private use subtag.
+
+ 4. A tag MAY consist entirely of private use subtags.
+
+ 5. No source is defined for private use subtags. Use of private use
+ subtags is by private agreement only.
+
+ 6. Private use subtags are NOT RECOMMENDED where alternatives exist
+ or for general interchange. See Section 4.5 for more information
+ on private use subtag choice.
+
+ For example: Users who wished to utilize codes from the Ethnologue
+ publication of SIL International for language identification might
+ agree to exchange tags such as "az-Arab-x-AZE-derbend". This example
+ contains two private use subtags. The first is 'AZE' and the second
+ is 'derbend'.
+
+2.2.8. Preexisting RFC 3066 Registrations
+
+ Existing IANA-registered language tags from RFC 1766 and/or RFC 3066
+ maintain their validity. These tags will be maintained in the
+ registry in records of either the "grandfathered" or "redundant"
+ type. Grandfathered tags contain one or more subtags that are not
+ defined in the Language Subtag Registry (see Section 3). Redundant
+ tags consist entirely of subtags defined above and whose independent
+ registration is superseded by this document. For more information,
+ see Section 3.8.
+
+
+
+
+Phillips & Davis Best Current Practice [Page 16]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ It is important to note that all language tags formed under the
+ guidelines in this document were either legal, well-formed tags or
+ could have been registered under RFC 3066.
+
+2.2.9. Classes of Conformance
+
+ Implementations sometimes need to describe their capabilities with
+ regard to the rules and practices described in this document. There
+ are two classes of conforming implementations described by this
+ document: "well-formed" processors and "validating" processors.
+ Claims of conformance SHOULD explicitly reference one of these
+ definitions.
+
+ An implementation that claims to check for well-formed language tags
+ MUST:
+
+ o Check that the tag and all of its subtags, including extension and
+ private use subtags, conform to the ABNF or that the tag is on the
+ list of grandfathered tags.
+
+ o Check that singleton subtags that identify extensions do not
+ repeat. For example, the tag "en-a-xx-b-yy-a-zz" is not well-
+ formed.
+
+ Well-formed processors are strongly encouraged to implement the
+ canonicalization rules contained in Section 4.4.
+
+ An implementation that claims to be validating MUST:
+
+ o Check that the tag is well-formed.
+
+ o Specify the particular registry date for which the implementation
+ performs validation of subtags.
+
+ o Check that either the tag is a grandfathered tag, or that all
+ language, script, region, and variant subtags consist of valid
+ codes for use in language tags according to the IANA registry as
+ of the particular date specified by the implementation.
+
+ o Specify which, if any, extension RFCs as defined in Section 3.7
+ are supported, including version, revision, and date.
+
+ o For any such extensions supported, check that all subtags used in
+ that extension are valid.
+
+ o For variant and extended language subtags, if the registry
+ contains one or more 'Prefix' fields for that subtag, check that
+ the tag matches at least one prefix. The tag matches if all the
+
+
+
+Phillips & Davis Best Current Practice [Page 17]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ subtags in the 'Prefix' also appear in the tag. For example, the
+ prefix "es-CO" matches the tag "es-Latn-CO-x-private" because both
+ the 'es' language subtag and 'CO' region subtag appear in the tag.
+
+3. Registry Format and Maintenance
+
+ This section defines the Language Subtag Registry and the maintenance
+ and update procedures associated with it, as well as a registry for
+ extensions to language tags (Section 3.7).
+
+ The Language Subtag Registry contains a comprehensive list of all of
+ the subtags valid in language tags. This allows implementers a
+ straightforward and reliable way to validate language tags. The
+ Language Subtag Registry will be maintained so that, except for
+ extension subtags, it is possible to validate all of the subtags that
+ appear in a language tag under the provisions of this document or its
+ revisions or successors. In addition, the meaning of the various
+ subtags will be unambiguous and stable over time. (The meaning of
+ private use subtags, of course, is not defined by the IANA registry.)
+
+3.1. Format of the IANA Language Subtag Registry
+
+ The IANA Language Subtag Registry ("the registry") consists of a text
+ file that is machine readable in the format described in this
+ section, plus copies of the registration forms approved in accordance
+ with the process described in Section 3.5. The existing registration
+ forms for grandfathered and redundant tags taken from RFC 3066 will
+ be maintained as part of the obsolete RFC 3066 registry. The
+ remaining set of initial subtags will not have registration forms
+ created for them.
+
+ The registry is in the text format described below. This format was
+ based on the record-jar format described in [record-jar].
+
+ Each line of text is limited to 72 characters, including all
+ whitespace. Records are separated by lines containing only the
+ sequence "%%" (%x25.25).
+
+ Each field can be viewed as a single, logical line of ASCII
+ characters, comprising a field-name and a field-body separated by a
+ COLON character (%x3A). For convenience, the field-body portion of
+ this conceptual entity can be split into a multiple-line
+ representation; this is called "folding". The format of the registry
+ is described by the following ABNF (per [RFC4234]):
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 18]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ registry = record *("%%" CRLF record)
+ record = 1*( field-name *SP ":" *SP field-body CRLF )
+ field-name = (ALPHA / DIGIT) [*(ALPHA / DIGIT / "-") (ALPHA / DIGIT)]
+ field-body = *(ASCCHAR/LWSP)
+ ASCCHAR = %x21-25 / %x27-7E / UNICHAR ; Note: AMPERSAND is %x26
+ UNICHAR = "&#x" 2*6HEXDIG ";"
+
+ Figure 2: Registry Format ABNF
+
+ The sequence '..' (%x2E.2E) in a field-body denotes a range of
+ values. Such a range represents all subtags of the same length that
+ are in alphabetic or numeric order within that range, including the
+ values explicitly mentioned. For example 'a..c' denotes the values
+ 'a', 'b', and 'c' and '11..13' denotes the values '11', '12', and
+ '13'.
+
+ Characters from outside the US-ASCII [ISO646] repertoire, as well as
+ the AMPERSAND character ("&", %x26) when it occurs in a field-body,
+ are represented by a "Numeric Character Reference" using hexadecimal
+ notation in the style used by [XML10] (see
+ <http://www.w3.org/TR/REC-xml/#dt-charref>). This consists of the
+ sequence "&#x" (%x26.23.78) followed by a hexadecimal representation
+ of the character's code point in [ISO10646] followed by a closing
+ semicolon (%x3B). For example, the EURO SIGN, U+20AC, would be
+ represented by the sequence "&#x20AC;". Note that the hexadecimal
+ notation MAY have between two and six digits.
+
+ All fields whose field-body contains a date value use the "full-date"
+ format specified in [RFC3339]. For example: "2004-06-28" represents
+ June 28, 2004, in the Gregorian calendar.
+
+ The first record in the file contains the single field whose field-
+ name is "File-Date" (see Figure 3). The field-body of this record
+ contains the last modification date of this copy of the registry,
+ making it possible to compare different versions of the registry.
+ The registry on the IANA website is the most current. Versions with
+ an older date than that one are not up-to-date.
+
+ File-Date: 2004-06-28
+ %%
+
+ Figure 3: Example of the File-Date Record
+
+ Subsequent records represent subtags in the registry. Each of the
+ fields in each record MUST occur no more than once, unless otherwise
+ noted below. Each record MUST contain the following fields:
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 19]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ o 'Type'
+
+ * Type's field-value MUST consist of one of the following
+ strings: "language", "extlang", "script", "region", "variant",
+ "grandfathered", and "redundant" and denotes the type of tag or
+ subtag.
+
+ o Either 'Subtag' or 'Tag'
+
+ * Subtag's field-value contains the subtag being defined. This
+ field MUST only appear in records of whose 'Type' has one of
+ these values: "language", "extlang", "script", "region", or
+ "variant".
+
+ * Tag's field-value contains a complete language tag. This field
+ MUST only appear in records whose 'Type' has one of these
+ values: "grandfathered" or "redundant". Note that the field-
+ value will always follow the 'grandfathered' production in the
+ ABNF in Section 2.1
+
+ o Description
+
+ * Description's field-value contains a non-normative description
+ of the subtag or tag.
+
+ o Added
+
+ * Added's field-value contains the date the record was added to
+ the registry.
+
+ The 'Subtag' or 'Tag' field MUST use lowercase letters to form the
+ subtag or tag, with two exceptions. Subtags whose 'Type' field is
+ 'script' (in other words, subtags defined by ISO 15924) MUST use
+ titlecase. Subtags whose 'Type' field is 'region' (in other words,
+ subtags defined by ISO 3166) MUST use uppercase. These exceptions
+ mirror the use of case in the underlying standards.
+
+ The field 'Description' MAY appear more than one time and contains a
+ description of the tag or subtag in the record. At least one of the
+ 'Description' fields MUST be written or transcribed into the Latin
+ script; the same or additional fields MAY also include a description
+ in a non-Latin script. The 'Description' field is used for
+ identification purposes and SHOULD NOT be taken to represent the
+ actual native name of the language or variation or to be in any
+ particular language. Most descriptions are taken directly from
+ source standards such as ISO 639 or ISO 3166.
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 20]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ Note: Descriptions in registry entries that correspond to ISO 639,
+ ISO 15924, ISO 3166, or UN M.49 codes are intended only to indicate
+ the meaning of that identifier as defined in the source standard at
+ the time it was added to the registry. The description does not
+ replace the content of the source standard itself. The descriptions
+ are not intended to be the English localized names for the subtags.
+ Localization or translation of language tag and subtag descriptions
+ is out of scope of this document.
+
+ Each record MAY also contain the following fields:
+
+ o Preferred-Value
+
+ * For fields of type 'language', 'extlang', 'script', 'region',
+ and 'variant', 'Preferred-Value' contains the subtag of the
+ same 'Type' that is preferred for forming the language tag.
+
+ * For fields of type 'grandfathered' and 'redundant', a canonical
+ mapping to a complete language tag.
+
+ o Deprecated
+
+ * Deprecated's field-value contains the date the record was
+ deprecated.
+
+ o Prefix
+
+ * Prefix's field-value contains a language tag with which this
+ subtag MAY be used to form a new language tag, perhaps with
+ other subtags as well. This field MUST only appear in records
+ whose 'Type' field-value is 'variant' or 'extlang'. For
+ example, the 'Prefix' for the variant 'nedis' is 'sl', meaning
+ that the tags "sl-nedis" and "sl-IT-nedis" might be appropriate
+ while the tag "is-nedis" is not.
+
+ o Comments
+
+ * Comments contains additional information about the subtag, as
+ deemed appropriate for understanding the registry and
+ implementing language tags using the subtag or tag.
+
+ o Suppress-Script
+
+ * Suppress-Script contains a script subtag that SHOULD NOT be
+ used to form language tags with the associated primary language
+ subtag. This field MUST only appear in records whose 'Type'
+ field-value is 'language'. See Section 4.1.
+
+
+
+
+Phillips & Davis Best Current Practice [Page 21]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The field 'Deprecated' MAY be added to any record via the maintenance
+ process described in Section 3.3 or via the registration process
+ described in Section 3.5. Usually, the addition of a 'Deprecated'
+ field is due to the action of one of the standards bodies, such as
+ ISO 3166, withdrawing a code. In some historical cases, it might not
+ have been possible to reconstruct the original deprecation date. For
+ these cases, an approximate date appears in the registry. Although
+ valid in language tags, subtags and tags with a 'Deprecated' field
+ are deprecated and validating processors SHOULD NOT generate these
+ subtags. Note that a record that contains a 'Deprecated' field and
+ no corresponding 'Preferred-Value' field has no replacement mapping.
+
+ The field 'Preferred-Value' contains a mapping between the record in
+ which it appears and another tag or subtag. The value in this field
+ is STRONGLY RECOMMENDED as the best choice to represent the value of
+ this record when selecting a language tag. These values form three
+ groups:
+
+ 1. ISO 639 language codes that were later withdrawn in favor of
+ other codes. These values are mostly a historical curiosity.
+
+ 2. ISO 3166 region codes that have been withdrawn in favor of a new
+ code. This sometimes happens when a country changes its name or
+ administration in such a way that warrants a new region code.
+
+ 3. Tags grandfathered from RFC 3066. In many cases, these tags have
+ become obsolete because the values they represent were later
+ encoded by ISO 639.
+
+ Records that contain a 'Preferred-Value' field MUST also have a
+ 'Deprecated' field. This field contains a date of deprecation.
+ Thus, a language tag processor can use the registry to construct the
+ valid, non-deprecated set of subtags for a given date. In addition,
+ for any given tag, a processor can construct the set of valid
+ language tags that correspond to that tag for all dates up to the
+ date of the registry. The ability to do these mappings MAY be
+ beneficial to applications that are matching, selecting, for
+ filtering content based on its language tags.
+
+ Note that 'Preferred-Value' mappings in records of type 'region'
+ sometimes do not represent exactly the same meaning as the original
+ value. There are many reasons for a country code to be changed, and
+ the effect this has on the formation of language tags will depend on
+ the nature of the change in question.
+
+ In particular, the 'Preferred-Value' field does not imply retagging
+ content that uses the affected subtag.
+
+
+
+
+Phillips & Davis Best Current Practice [Page 22]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The field 'Preferred-Value' MUST NOT be modified once created in the
+ registry. The field MAY be added to records of type "grandfathered"
+ and "region" according to the rules in Section 3.3. Otherwise the
+ field MUST NOT be added to any record already in the registry.
+
+ The 'Preferred-Value' field in records of type "grandfathered" and
+ "redundant" contains whole language tags that are strongly
+ RECOMMENDED for use in place of the record's value. In many cases,
+ the mappings were created by deprecation of the tags during the
+ period before this document was adopted. For example, the tag
+ "no-nyn" was deprecated in favor of the ISO 639-1-defined language
+ code 'nn'.
+
+ Records of type 'variant' MAY have more than one field of type
+ 'Prefix'. Additional fields of this type MAY be added to a 'variant'
+ record via the registration process.
+
+ Records of type 'extlang' MUST have _exactly_ one 'Prefix' field.
+
+ The field-value of the 'Prefix' field consists of a language tag
+ whose subtags are appropriate to use with this subtag. For example,
+ the variant subtag '1996' has a 'Prefix' field of "de". This means
+ that tags starting with the sequence "de-" are appropriate with this
+ subtag, so "de-Latg-1996" and "de-CH-1996" are both acceptable, while
+ the tag "fr-1996" is an inappropriate choice.
+
+ The field of type 'Prefix' MUST NOT be removed from any record. The
+ field-value for this type of field MUST NOT be modified.
+
+ The field 'Comments' MAY appear more than once per record. This
+ field MAY be inserted or changed via the registration process and no
+ guarantee of stability is provided. The content of this field is not
+ restricted, except by the need to register the information, the
+ suitability of the request, and by reasonable practical size
+ limitations.
+
+ The field 'Suppress-Script' MUST only appear in records whose 'Type'
+ field-value is 'language'. This field MUST NOT appear more than one
+ time in a record. This field indicates a script used to write the
+ overwhelming majority of documents for the given language and that
+ therefore adds no distinguishing information to a language tag. It
+ helps ensure greater compatibility between the language tags
+ generated according to the rules in this document and language tags
+ and tag processors or consumers based on RFC 3066. For example,
+ virtually all Icelandic documents are written in the Latin script,
+ making the subtag 'Latn' redundant in the tag "is-Latn".
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 23]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+3.2. Language Subtag Reviewer
+
+ The Language Subtag Reviewer is appointed by the IESG for an
+ indefinite term, subject to removal or replacement at the IESG's
+ discretion. The Language Subtag Reviewer moderates the ietf-
+ languages mailing list, responds to requests for registration, and
+ performs the other registry maintenance duties described in
+ Section 3.3. Only the Language Subtag Reviewer is permitted to
+ request IANA to change, update, or add records to the Language Subtag
+ Registry.
+
+ The performance or decisions of the Language Subtag Reviewer MAY be
+ appealed to the IESG under the same rules as other IETF decisions
+ (see [RFC2026]). The IESG can reverse or overturn the decision of
+ the Language Subtag Reviewer, provide guidance, or take other
+ appropriate actions.
+
+3.3. Maintenance of the Registry
+
+ Maintenance of the registry requires that as codes are assigned or
+ withdrawn by ISO 639, ISO 15924, ISO 3166, and UN M.49, the Language
+ Subtag Reviewer MUST evaluate each change, determine whether it
+ conflicts with existing registry entries, and submit the information
+ to IANA for inclusion in the registry. If a change takes place and
+ the Language Subtag Reviewer does not do this in a timely manner,
+ then any interested party MAY use the procedure in Section 3.5 to
+ register the appropriate update.
+
+ Note: The redundant and grandfathered entries together are the
+ complete list of tags registered under [RFC3066]. The redundant tags
+ are those that can now be formed using the subtags defined in the
+ registry together with the rules of Section 2.2. The grandfathered
+ entries include those that can never be legal under those same
+ provisions.
+
+ The set of redundant and grandfathered tags is permanent and stable:
+ new entries in this section MUST NOT be added and existing entries
+ MUST NOT be removed. Records of type 'grandfathered' MAY have their
+ type converted to 'redundant'; see item 12 in Section 3.6 for more
+ information. The decision-making process about which tags were
+ initially grandfathered and which were made redundant is described in
+ [RFC4645].
+
+ RFC 3066 tags that were deprecated prior to the adoption of this
+ document are part of the list of grandfathered tags, and their
+ component subtags were not included as registered variants (although
+ they remain eligible for registration). For example, the tag
+ "art-lojban" was deprecated in favor of the language subtag 'jbo'.
+
+
+
+Phillips & Davis Best Current Practice [Page 24]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The Language Subtag Reviewer MUST ensure that new subtags meet the
+ requirements in Section 4.1 or submit an appropriate alternate subtag
+ as described in that section. When either a change or addition to
+ the registry is needed, the Language Subtag Reviewer MUST prepare the
+ complete record, including all fields, and forward it to IANA for
+ insertion into the registry. Each record being modified or inserted
+ MUST be forwarded in a separate message.
+
+ If a record represents a new subtag that does not currently exist in
+ the registry, then the message's subject line MUST include the word
+ "INSERT". If the record represents a change to an existing subtag,
+ then the subject line of the message MUST include the word "MODIFY".
+ The message MUST contain both the record for the subtag being
+ inserted or modified and the new File-Date record. Here is an
+ example of what the body of the message might contain:
+
+ LANGUAGE SUBTAG MODIFICATION
+ File-Date: 2005-01-02
+ %%
+ Type: variant
+ Subtag: nedis
+ Description: Natisone dialect
+ Description: Nadiza dialect
+ Added: 2003-10-09
+ Prefix: sl
+ Comments: This is a comment shown
+ as an example.
+ %%
+
+ Figure 4: Example of a Language Subtag Modification Form
+
+ Whenever an entry is created or modified in the registry, the
+ 'File-Date' record at the start of the registry is updated to reflect
+ the most recent modification date in the [RFC3339] "full-date"
+ format.
+
+ Before forwarding a new registration to IANA, the Language Subtag
+ Reviewer MUST ensure that values in the 'Subtag' field match case
+ according to the description in Section 3.1.
+
+3.4. Stability of IANA Registry Entries
+
+ The stability of entries and their meaning in the registry is
+ critical to the long-term stability of language tags. The rules in
+ this section guarantee that a specific language tag's meaning is
+ stable over time and will not change.
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 25]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ These rules specifically deal with how changes to codes (including
+ withdrawal and deprecation of codes) maintained by ISO 639, ISO
+ 15924, ISO 3166, and UN M.49 are reflected in the IANA Language
+ Subtag Registry. Assignments to the IANA Language Subtag Registry
+ MUST follow the following stability rules:
+
+ 1. Values in the fields 'Type', 'Subtag', 'Tag', 'Added',
+ 'Deprecated' and 'Preferred-Value' MUST NOT be changed and are
+ guaranteed to be stable over time.
+
+ 2. Values in the 'Description' field MUST NOT be changed in a way
+ that would invalidate previously-existing tags. They MAY be
+ broadened somewhat in scope, changed to add information, or
+ adapted to the most common modern usage. For example, countries
+ occasionally change their official names; a historical example
+ of this would be "Upper Volta" changing to "Burkina Faso".
+
+ 3. Values in the field 'Prefix' MAY be added to records of type
+ 'variant' via the registration process.
+
+ 4. Values in the field 'Prefix' MAY be modified, so long as the
+ modifications broaden the set of prefixes. That is, a prefix
+ MAY be replaced by one of its own prefixes. For example, the
+ prefix "en-US" could be replaced by "en", but not by the
+ prefixes "en-Latn", "fr", or "en-US-boont". If one of those
+ prefixes were needed, a new Prefix SHOULD be registered.
+
+ 5. Values in the field 'Prefix' MUST NOT be removed.
+
+ 6. The field 'Comments' MAY be added, changed, modified, or removed
+ via the registration process or any of the processes or
+ considerations described in this section.
+
+ 7. The field 'Suppress-Script' MAY be added or removed via the
+ registration process.
+
+ 8. Codes assigned by ISO 639, ISO 15924, and ISO 3166 that do not
+ conflict with existing subtags of the associated type and whose
+ meaning is not the same as an existing subtag of the same type
+ are entered into the IANA registry as new records.
+
+ 9. Codes assigned by ISO 639, ISO 15924, or ISO 3166 that are
+ withdrawn by their respective maintenance or registration
+ authority remain valid in language tags. A 'Deprecated' field
+ containing the date of withdrawal is added to the record. If a
+ new record of the same type is added that represents a
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 26]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ replacement value, then a 'Preferred-Value' field MAY also be
+ added. The registration process MAY be used to add comments
+ about the withdrawal of the code by the respective standard.
+
+ Example
+ The region code 'TL' was assigned to the country 'Timor-
+ Leste', replacing the code 'TP' (which was assigned to 'East
+ Timor' when it was under administration by Portugal). The
+ subtag 'TP' remains valid in language tags, but its record
+ contains the a 'Preferred-Value' of 'TL' and its field
+ 'Deprecated' contains the date the new code was assigned
+ ('2004-07-06').
+
+ 10. Codes assigned by ISO 639, ISO 15924, or ISO 3166 that conflict
+ with existing subtags of the associated type, including subtags
+ that are deprecated, MUST NOT be entered into the registry. The
+ following additional considerations apply to subtag values that
+ are reassigned:
+
+ A. For ISO 639 codes, if the newly assigned code's meaning is
+ not represented by a subtag in the IANA registry, the
+ Language Subtag Reviewer, as described in Section 3.5, SHALL
+ prepare a proposal for entering in the IANA registry as soon
+ as practical a registered language subtag as an alternate
+ value for the new code. The form of the registered language
+ subtag will be at the discretion of the Language Subtag
+ Reviewer and MUST conform to other restrictions on language
+ subtags in this document.
+
+ B. For all subtags whose meaning is derived from an external
+ standard (i.e., ISO 639, ISO 15924, ISO 3166, or UN M.49),
+ if a new meaning is assigned to an existing code and the new
+ meaning broadens the meaning of that code, then the meaning
+ for the associated subtag MAY be changed to match. The
+ meaning of a subtag MUST NOT be narrowed, however, as this
+ can result in an unknown proportion of the existing uses of
+ a subtag becoming invalid. Note: ISO 639 maintenance
+ agency/registration authority (MA/RA) has adopted a similar
+ stability policy.
+
+ C. For ISO 15924 codes, if the newly assigned code's meaning is
+ not represented by a subtag in the IANA registry, the
+ Language Subtag Reviewer, as described in Section 3.5, SHALL
+ prepare a proposal for entering in the IANA registry as soon
+ as practical a registered variant subtag as an alternate
+ value for the new code. The form of the registered variant
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 27]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ subtag will be at the discretion of the Language Subtag
+ Reviewer and MUST conform to other restrictions on variant
+ subtags in this document.
+
+ D. For ISO 3166 codes, if the newly assigned code's meaning is
+ associated with the same UN M.49 code as another 'region'
+ subtag, then the existing region subtag remains as the
+ preferred value for that region and no new entry is created.
+ A comment MAY be added to the existing region subtag
+ indicating the relationship to the new ISO 3166 code.
+
+ E. For ISO 3166 codes, if the newly assigned code's meaning is
+ associated with a UN M.49 code that is not represented by an
+ existing region subtag, then the Language Subtag Reviewer,
+ as described in Section 3.5, SHALL prepare a proposal for
+ entering the appropriate UN M.49 country code as an entry in
+ the IANA registry.
+
+ F. For ISO 3166 codes, if there is no associated UN numeric
+ code, then the Language Subtag Reviewer SHALL petition the
+ UN to create one. If there is no response from the UN
+ within ninety days of the request being sent, the Language
+ Subtag Reviewer SHALL prepare a proposal for entering in the
+ IANA registry as soon as practical a registered variant
+ subtag as an alternate value for the new code. The form of
+ the registered variant subtag will be at the discretion of
+ the Language Subtag Reviewer and MUST conform to other
+ restrictions on variant subtags in this document. This
+ situation is very unlikely to ever occur.
+
+ 11. UN M.49 has codes for both countries and areas (such as '276'
+ for Germany) and geographical regions and sub-regions (such as
+ '150' for Europe). UN M.49 country or area codes for which
+ there is no corresponding ISO 3166 code SHOULD NOT be
+ registered, except as a surrogate for an ISO 3166 code that is
+ blocked from registration by an existing subtag. If such a code
+ becomes necessary, then the registration authority for ISO 3166
+ SHOULD first be petitioned to assign a code to the region. If
+ the petition for a code assignment by ISO 3166 is refused or not
+ acted on in a timely manner, the registration process described
+ in Section 3.5 MAY then be used to register the corresponding UN
+ M.49 code. At the time this document was written, there were
+ only four such codes: 830 (Channel Islands), 831 (Guernsey), 832
+ (Jersey), and 833 (Isle of Man). This way, UN M.49 codes remain
+ available as the value of last resort in cases where ISO 3166
+ reassigns a deprecated value in the registry.
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 28]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ 12. Stability provisions apply to grandfathered tags with this
+ exception: should all of the subtags in a grandfathered tag
+ become valid subtags in the IANA registry, then the field 'Type'
+ in that record is changed from 'grandfathered' to 'redundant'.
+ Note that this will not affect language tags that match the
+ grandfathered tag, since these tags will now match valid
+ generative subtag sequences. For example, if the subtag 'gan'
+ in the language tag "zh-gan" were to be registered as an
+ extended language subtag, then the grandfathered tag "zh-gan"
+ would be deprecated (but existing content or implementations
+ that use "zh-gan" would remain valid).
+
+3.5. Registration Procedure for Subtags
+
+ The procedure given here MUST be used by anyone who wants to use a
+ subtag not currently in the IANA Language Subtag Registry.
+
+ Only subtags of type 'language' and 'variant' will be considered for
+ independent registration of new subtags. Handling of subtags needed
+ for stability and subtags necessary to keep the registry synchronized
+ with ISO 639, ISO 15924, ISO 3166, and UN M.49 within the limits
+ defined by this document are described in Section 3.3. Stability
+ provisions are described in Section 3.4.
+
+ This procedure MAY also be used to register or alter the information
+ for the 'Description', 'Comments', 'Deprecated', or 'Prefix' fields
+ in a subtag's record as described in Section 3.4. Changes to all
+ other fields in the IANA registry are NOT permitted.
+
+ Registering a new subtag or requesting modifications to an existing
+ tag or subtag starts with the requester filling out the registration
+ form reproduced below. Note that each response is not limited in
+ size so that the request can adequately describe the registration.
+ The fields in the "Record Requested" section SHOULD follow the
+ requirements in Section 3.1.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 29]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ LANGUAGE SUBTAG REGISTRATION FORM
+ 1. Name of requester:
+ 2. E-mail address of requester:
+ 3. Record Requested:
+
+ Type:
+ Subtag:
+ Description:
+ Prefix:
+ Preferred-Value:
+ Deprecated:
+ Suppress-Script:
+ Comments:
+
+ 4. Intended meaning of the subtag:
+ 5. Reference to published description
+ of the language (book or article):
+ 6. Any other relevant information:
+
+ Figure 5: The Language Subtag Registration Form
+
+ The subtag registration form MUST be sent to
+ <ietf-languages@iana.org> for a two-week review period before it can
+ be submitted to IANA. (This is an open list and can be joined by
+ sending a request to <ietf-languages-request@iana.org>.)
+
+ Variant subtags are usually registered for use with a particular
+ range of language tags. For example, the subtag 'rozaj' is intended
+ for use with language tags that start with the primary language
+ subtag "sl", since Resian is a dialect of Slovenian. Thus, the
+ subtag 'rozaj' would be appropriate in tags such as "sl-Latn-rozaj"
+ or "sl-IT-rozaj". This information is stored in the 'Prefix' field
+ in the registry. Variant registration requests SHOULD include at
+ least one 'Prefix' field in the registration form.
+
+ Extended language subtags are reserved for future standardization.
+ These subtags will be REQUIRED to include exactly one 'Prefix' field
+ once they are allowed for registration.
+
+ The 'Prefix' field for a given registered subtag exists in the IANA
+ registry as a guide to usage. Additional prefixes MAY be added by
+ filing an additional registration form. In that form, the "Any other
+ relevant information:" field MUST indicate that it is the addition of
+ a prefix.
+
+ Requests to add a prefix to a variant subtag that imply a different
+ semantic meaning will probably be rejected. For example, a request
+ to add the prefix "de" to the subtag 'nedis' so that the tag
+
+
+
+Phillips & Davis Best Current Practice [Page 30]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ "de-nedis" represented some German dialect would be rejected. The
+ 'nedis' subtag represents a particular Slovenian dialect and the
+ additional registration would change the semantic meaning assigned to
+ the subtag. A separate subtag SHOULD be proposed instead.
+
+ The 'Description' field MUST contain a description of the tag being
+ registered written or transcribed into the Latin script; it MAY also
+ include a description in a non-Latin script. Non-ASCII characters
+ MUST be escaped using the syntax described in Section 3.1. The
+ 'Description' field is used for identification purposes and doesn't
+ necessarily represent the actual native name of the language or
+ variation or to be in any particular language.
+
+ While the 'Description' field itself is not guaranteed to be stable
+ and errata corrections MAY be undertaken from time to time, attempts
+ to provide translations or transcriptions of entries in the registry
+ itself will probably be frowned upon by the community or rejected
+ outright, as changes of this nature have an impact on the provisions
+ in Section 3.4.
+
+ When the two-week period has passed, the Language Subtag Reviewer
+ either forwards the record to be inserted or modified to
+ iana@iana.org according to the procedure described in Section 3.3, or
+ rejects the request because of significant objections raised on the
+ list or due to problems with constraints in this document (which MUST
+ be explicitly cited). The Language Subtag Reviewer MAY also extend
+ the review period in two-week increments to permit further
+ discussion. The Language Subtag Reviewer MUST indicate on the list
+ whether the registration has been accepted, rejected, or extended
+ following each two-week period.
+
+ Note that the Language Subtag Reviewer MAY raise objections on the
+ list if he or she so desires. The important thing is that the
+ objection MUST be made publicly.
+
+ The applicant is free to modify a rejected application with
+ additional information and submit it again; this restarts the two-
+ week comment period.
+
+ Decisions made by the Language Subtag Reviewer MAY be appealed to the
+ IESG [RFC2028] under the same rules as other IETF decisions
+ [RFC2026].
+
+ All approved registration forms are available online in the directory
+ http://www.iana.org/numbers.html under "languages".
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 31]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ Updates or changes to existing records follow the same procedure as
+ new registrations. The Language Subtag Reviewer decides whether
+ there is consensus to update the registration following the two-week
+ review period; normally, objections by the original registrant will
+ carry extra weight in forming such a consensus.
+
+ Registrations are permanent and stable. Once registered, subtags
+ will not be removed from the registry and will remain a valid way in
+ which to specify a specific language or variant.
+
+ Note: The purpose of the "Description" in the registration form is to
+ aid people trying to verify whether a language is registered or what
+ language or language variation a particular subtag refers to. In
+ most cases, reference to an authoritative grammar or dictionary of
+ that language will be useful; in cases where no such work exists,
+ other well-known works describing that language or in that language
+ MAY be appropriate. The Language Subtag Reviewer decides what
+ constitutes "good enough" reference material. This requirement is
+ not intended to exclude particular languages or dialects due to the
+ size of the speaker population or lack of a standardized orthography.
+ Minority languages will be considered equally on their own merits.
+
+3.6. Possibilities for Registration
+
+ Possibilities for registration of subtags or information about
+ subtags include:
+
+ o Primary language subtags for languages not listed in ISO 639 that
+ are not variants of any listed or registered language MAY be
+ registered. At the time this document was created, there were no
+ examples of this form of subtag. Before attempting to register a
+ language subtag, there MUST be an attempt to register the language
+ with ISO 639. Subtags MUST NOT be registered for codes that exist
+ in ISO 639-1 or ISO 639-2, that are under consideration by the ISO
+ 639 maintenance or registration authorities, or that have never
+ been attempted for registration with those authorities. If ISO
+ 639 has previously rejected a language for registration, it is
+ reasonable to assume that there must be additional, very
+ compelling evidence of need before it will be registered in the
+ IANA registry (to the extent that it is very unlikely that any
+ subtags will be registered of this type).
+
+ o Dialect or other divisions or variations within a language, its
+ orthography, writing system, regional or historical usage,
+ transliteration or other transformation, or distinguishing
+ variation MAY be registered as variant subtags. An example is the
+ 'rozaj' subtag (the Resian dialect of Slovenian).
+
+
+
+
+Phillips & Davis Best Current Practice [Page 32]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ o The addition or maintenance of fields (generally of an
+ informational nature) in Tag or Subtag records as described in
+ Section 3.1 and subject to the stability provisions in
+ Section 3.4. This includes descriptions, comments, deprecation
+ and preferred values for obsolete or withdrawn codes, or the
+ addition of script or extlang information to primary language
+ subtags.
+
+ o The addition of records and related field value changes necessary
+ to reflect assignments made by ISO 639, ISO 15924, ISO 3166, and
+ UN M.49 as described in Section 3.4.
+
+ Subtags proposed for registration that would cause all or part of a
+ grandfathered tag to become redundant but whose meaning conflicts
+ with or alters the meaning of the grandfathered tag MUST be rejected.
+
+ This document leaves the decision on what subtags or changes to
+ subtags are appropriate (or not) to the registration process
+ described in Section 3.5.
+
+ Note: four-character primary language subtags are reserved to allow
+ for the possibility of alpha4 codes in some future addition to the
+ ISO 639 family of standards.
+
+ ISO 639 defines a maintenance agency for additions to and changes in
+ the list of languages in ISO 639. This agency is:
+
+ International Information Centre for Terminology (Infoterm)
+ Aichholzgasse 6/12, AT-1120
+ Wien, Austria
+ Phone: +43 1 26 75 35 Ext. 312 Fax: +43 1 216 32 72
+
+ ISO 639-2 defines a maintenance agency for additions to and changes
+ in the list of languages in ISO 639-2. This agency is:
+
+ Library of Congress
+ Network Development and MARC Standards Office
+ Washington, D.C. 20540 USA
+ Phone: +1 202 707 6237 Fax: +1 202 707 0115
+ URL: http://www.loc.gov/standards/iso639-2
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 33]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The maintenance agency for ISO 3166 (country codes) is:
+
+ ISO 3166 Maintenance Agency
+ c/o International Organization for Standardization
+ Case postale 56
+ CH-1211 Geneva 20 Switzerland
+ Phone: +41 22 749 72 33 Fax: +41 22 749 73 49
+ URL: http://www.iso.org/iso/en/prods-services/iso3166ma/index.html
+
+ The registration authority for ISO 15924 (script codes) is:
+
+ Unicode Consortium Box 391476
+ Mountain View, CA 94039-1476, USA
+ URL: http://www.unicode.org/iso15924
+
+ The Statistics Division of the United Nations Secretariat maintains
+ the Standard Country or Area Codes for Statistical Use and can be
+ reached at:
+
+ Statistical Services Branch
+ Statistics Division
+ United Nations, Room DC2-1620
+ New York, NY 10017, USA
+
+ Fax: +1-212-963-0623
+ E-mail: statistics@un.org
+ URL: http://unstats.un.org/unsd/methods/m49/m49alpha.htm
+
+3.7. Extensions and Extensions Registry
+
+ Extension subtags are those introduced by single-character subtags
+ ("singletons") other than 'x'. They are reserved for the generation
+ of identifiers that contain a language component and are compatible
+ with applications that understand language tags.
+
+ The structure and form of extensions are defined by this document so
+ that implementations can be created that are forward compatible with
+ applications that might be created using singletons in the future.
+ In addition, defining a mechanism for maintaining singletons will
+ lend stability to this document by reducing the likely need for
+ future revisions or updates.
+
+ Single-character subtags are assigned by IANA using the "IETF
+ Consensus" policy defined by [RFC2434]. This policy requires the
+ development of an RFC, which SHALL define the name, purpose,
+ processes, and procedures for maintaining the subtags. The
+ maintaining or registering authority, including name, contact email,
+
+
+
+
+Phillips & Davis Best Current Practice [Page 34]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ discussion list email, and URL location of the registry, MUST be
+ indicated clearly in the RFC. The RFC MUST specify or include each
+ of the following:
+
+ o The specification MUST reference the specific version or revision
+ of this document that governs its creation and MUST reference this
+ section of this document.
+
+ o The specification and all subtags defined by the specification
+ MUST follow the ABNF and other rules for the formation of tags and
+ subtags as defined in this document. In particular, it MUST
+ specify that case is not significant and that subtags MUST NOT
+ exceed eight characters in length.
+
+ o The specification MUST specify a canonical representation.
+
+ o The specification of valid subtags MUST be available over the
+ Internet and at no cost.
+
+ o The specification MUST be in the public domain or available via a
+ royalty-free license acceptable to the IETF and specified in the
+ RFC.
+
+ o The specification MUST be versioned, and each version of the
+ specification MUST be numbered, dated, and stable.
+
+ o The specification MUST be stable. That is, extension subtags,
+ once defined by a specification, MUST NOT be retracted or change
+ in meaning in any substantial way.
+
+ o The specification MUST include in a separate section the
+ registration form reproduced in this section (below) to be used in
+ registering the extension upon publication as an RFC.
+
+ o IANA MUST be informed of changes to the contact information and
+ URL for the specification.
+
+ IANA will maintain a registry of allocated single-character
+ (singleton) subtags. This registry MUST use the record-jar format
+ described by the ABNF in Section 3.1. Upon publication of an
+ extension as an RFC, the maintaining authority defined in the RFC
+ MUST forward this registration form to iesg@ietf.org, who MUST
+ forward the request to iana@iana.org. The maintaining authority of
+ the extension MUST maintain the accuracy of the record by sending an
+ updated full copy of the record to iana@iana.org with the subject
+ line "LANGUAGE TAG EXTENSION UPDATE" whenever content changes. Only
+ the 'Comments', 'Contact_Email', 'Mailing_List', and 'URL' fields MAY
+ be modified in these updates.
+
+
+
+Phillips & Davis Best Current Practice [Page 35]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ Failure to maintain this record, maintain the corresponding registry,
+ or meet other conditions imposed by this section of this document MAY
+ be appealed to the IESG [RFC2028] under the same rules as other IETF
+ decisions (see [RFC2026]) and MAY result in the authority to maintain
+ the extension being withdrawn or reassigned by the IESG.
+
+ %%
+ Identifier:
+ Description:
+ Comments:
+ Added:
+ RFC:
+ Authority:
+ Contact_Email:
+ Mailing_List:
+ URL:
+ %%
+
+ Figure 6: Format of Records in the Language Tag Extensions Registry
+
+ 'Identifier' contains the single-character subtag (singleton)
+ assigned to the extension. The Internet-Draft submitted to define
+ the extension SHOULD specify which letter or digit to use, although
+ the IESG MAY change the assignment when approving the RFC.
+
+ 'Description' contains the name and description of the extension.
+
+ 'Comments' is an OPTIONAL field and MAY contain a broader description
+ of the extension.
+
+ 'Added' contains the date the RFC was published in the "full-date"
+ format specified in [RFC3339]. For example: 2004-06-28 represents
+ June 28, 2004, in the Gregorian calendar.
+
+ 'RFC' contains the RFC number assigned to the extension.
+
+ 'Authority' contains the name of the maintaining authority for the
+ extension.
+
+ 'Contact_Email' contains the email address used to contact the
+ maintaining authority.
+
+ 'Mailing_List' contains the URL or subscription email address of the
+ mailing list used by the maintaining authority.
+
+ 'URL' contains the URL of the registry for this extension.
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 36]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The determination of whether an Internet-Draft meets the above
+ conditions and the decision to grant or withhold such authority rests
+ solely with the IESG and is subject to the normal review and appeals
+ process associated with the RFC process.
+
+ Extension authors are strongly cautioned that many (including most
+ well-formed) processors will be unaware of any special relationships
+ or meaning inherent in the order of extension subtags. Extension
+ authors SHOULD avoid subtag relationships or canonicalization
+ mechanisms that interfere with matching or with length restrictions
+ that sometimes exist in common protocols where the extension is used.
+ In particular, applications MAY truncate the subtags in doing
+ matching or in fitting into limited lengths, so it is RECOMMENDED
+ that the most significant information be in the most significant
+ (left-most) subtags and that the specification gracefully handle
+ truncated subtags.
+
+ When a language tag is to be used in a specific, known, protocol, it
+ is RECOMMENDED that the language tag not contain extensions not
+ supported by that protocol. In addition, note that some protocols
+ MAY impose upper limits on the length of the strings used to store or
+ transport the language tag.
+
+3.8. Initialization of the Registries
+
+ Upon adoption of this document, an initial version of the Language
+ Subtag Registry containing the various subtags initially valid in a
+ language tag is necessary. This collection of subtags, along with a
+ description of the process used to create it, is described by
+ [RFC4645]. IANA SHALL publish the initial version of the registry
+ described by this document from the content of [RFC4645]. Once
+ published by IANA, the maintenance procedures, rules, and
+ registration processes described in this document will be available
+ for new registrations or updates.
+
+ Registrations that are in process under the rules defined in
+ [RFC3066] when this document is adopted MAY be completed under the
+ former rules, at the discretion of the Language Tag Reviewer (as
+ described in [RFC3066]). Until the IESG officially appoints a
+ Language Subtag Reviewer, the existing Language Tag Reviewer SHALL
+ serve as the Language Subtag Reviewer.
+
+ Any new registrations submitted using the RFC 3066 forms or format
+ after the adoption of this document and publication of the registry
+ by IANA MUST be rejected.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 37]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ An initial version of the Language Tag Extensions Registry described
+ in Section 3.7 is also needed. The Language Tag Extensions Registry
+ SHALL be initialized with a single record containing a single field
+ of type "File-Date" as a placeholder for future assignments.
+
+4. Formation and Processing of Language Tags
+
+ This section addresses how to use the information in the registry
+ with the tag syntax to choose, form, and process language tags.
+
+4.1. Choice of Language Tag
+
+ One is sometimes faced with the choice between several possible tags
+ for the same body of text.
+
+ Interoperability is best served when all users use the same language
+ tag in order to represent the same language. If an application has
+ requirements that make the rules here inapplicable, then that
+ application risks damaging interoperability. It is strongly
+ RECOMMENDED that users not define their own rules for language tag
+ choice.
+
+ Subtags SHOULD only be used where they add useful distinguishing
+ information; extraneous subtags interfere with the meaning,
+ understanding, and processing of language tags. In particular, users
+ and implementations SHOULD follow the 'Prefix' and 'Suppress-Script'
+ fields in the registry (defined in Section 3.1): these fields provide
+ guidance on when specific additional subtags SHOULD (and SHOULD NOT)
+ be used in a language tag.
+
+ Of particular note, many applications can benefit from the use of
+ script subtags in language tags, as long as the use is consistent for
+ a given context. Script subtags were not formally defined in RFC
+ 3066 and their use can affect matching and subtag identification by
+ implementations of RFC 3066, as these subtags appear between the
+ primary language and region subtags. For example, if a user requests
+ content in an implementation of Section 2.5 of [RFC3066] using the
+ language range "en-US", content labeled "en-Latn-US" will not match
+ the request. Therefore, it is important to know when script subtags
+ will customarily be used and when they ought not be used. In the
+ registry, the Suppress-Script field helps ensure greater
+ compatibility between the language tags generated according to the
+ rules in this document and language tags and tag processors or
+ consumers based on RFC 3066 by defining when users SHOULD NOT include
+ a script subtag with a particular primary language subtag.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 38]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ Extended language subtags (type 'extlang' in the registry; see
+ Section 3.1) also appear between the primary language and region
+ subtags and are reserved for future standardization. Applications
+ might benefit from their judicious use in forming language tags in
+ the future. Similar recommendations are expected to apply to their
+ use as apply to script subtags.
+
+ Standards, protocols, and applications that reference this document
+ normatively but apply different rules to the ones given in this
+ section MUST specify how the procedure varies from the one given
+ here.
+
+ The choice of subtags used to form a language tag SHOULD be guided by
+ the following rules:
+
+ 1. Use as precise a tag as possible, but no more specific than is
+ justified. Avoid using subtags that are not important for
+ distinguishing content in an application.
+
+ * For example, 'de' might suffice for tagging an email written
+ in German, while "de-CH-1996" is probably unnecessarily
+ precise for such a task.
+
+ 2. The script subtag SHOULD NOT be used to form language tags unless
+ the script adds some distinguishing information to the tag. The
+ field 'Suppress-Script' in the primary language record in the
+ registry indicates which script subtags do not add distinguishing
+ information for most applications.
+
+ * For example, the subtag 'Latn' should not be used with the
+ primary language 'en' because nearly all English documents are
+ written in the Latin script and it adds no distinguishing
+ information. However, if a document were written in English
+ mixing Latin script with another script such as Braille
+ ('Brai'), then it might be appropriate to choose to indicate
+ both scripts to aid in content selection, such as the
+ application of a style sheet.
+
+ 3. If a tag or subtag has a 'Preferred-Value' field in its registry
+ entry, then the value of that field SHOULD be used to form the
+ language tag in preference to the tag or subtag in which the
+ preferred value appears.
+
+ * For example, use 'he' for Hebrew in preference to 'iw'.
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 39]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ 4. The 'und' (Undetermined) primary language subtag SHOULD NOT be
+ used to label content, even if the language is unknown. Omitting
+ the language tag altogether is preferred to using a tag with a
+ primary language subtag of 'und'. The 'und' subtag MAY be useful
+ for protocols that require a language tag to be provided. The
+ 'und' subtag MAY also be useful when matching language tags in
+ certain situations.
+
+ 5. The 'mul' (Multiple) primary language subtag SHOULD NOT be used
+ whenever the protocol allows the separate tags for multiple
+ languages, as is the case for the Content-Language header in
+ HTTP. The 'mul' subtag conveys little useful information:
+ content in multiple languages SHOULD individually tag the
+ languages where they appear or otherwise indicate the actual
+ language in preference to the 'mul' subtag.
+
+ 6. The same variant subtag SHOULD NOT be used more than once within
+ a language tag.
+
+ * For example, do not use "de-DE-1901-1901".
+
+ To ensure consistent backward compatibility, this document contains
+ several provisions to account for potential instability in the
+ standards used to define the subtags that make up language tags.
+ These provisions mean that no language tag created under the rules in
+ this document will become obsolete.
+
+4.2. Meaning of the Language Tag
+
+ The relationship between the tag and the information it relates to is
+ defined by the context in which the tag appears. Accordingly, this
+ section gives only possible examples of its usage.
+
+ o For a single information object, the associated language tags
+ might be interpreted as the set of languages that is necessary for
+ a complete comprehension of the complete object. Example: Plain
+ text documents.
+
+ o For an aggregation of information objects, the associated language
+ tags could be taken as the set of languages used inside components
+ of that aggregation. Examples: Document stores and libraries.
+
+ o For information objects whose purpose is to provide alternatives,
+ the associated language tags could be regarded as a hint that the
+ content is provided in several languages and that one has to
+ inspect each of the alternatives in order to find its language or
+ languages. In this case, the presence of multiple tags might not
+ mean that one needs to be multi-lingual to get complete
+
+
+
+Phillips & Davis Best Current Practice [Page 40]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ understanding of the document. Example: MIME multipart/
+ alternative.
+
+ o In markup languages, such as HTML and XML, language information
+ can be added to each part of the document identified by the markup
+ structure (including the whole document itself). For example, one
+ could write <span lang="fr">C'est la vie.</span> inside a
+ Norwegian document; the Norwegian-speaking user could then access
+ a French-Norwegian dictionary to find out what the marked section
+ meant. If the user were listening to that document through a
+ speech synthesis interface, this formation could be used to signal
+ the synthesizer to appropriately apply French text-to-speech
+ pronunciation rules to that span of text, instead of applying the
+ inappropriate Norwegian rules.
+
+ Language tags are related when they contain a similar sequence of
+ subtags. For example, if a language tag B contains language tag A as
+ a prefix, then B is typically "narrower" or "more specific" than A.
+ Thus, "zh-Hant-TW" is more specific than "zh-Hant".
+
+ This relationship is not guaranteed in all cases: specifically,
+ languages that begin with the same sequence of subtags are NOT
+ guaranteed to be mutually intelligible, although they might be. For
+ example, the tag "az" shares a prefix with both "az-Latn"
+ (Azerbaijani written using the Latin script) and "az-Cyrl"
+ (Azerbaijani written using the Cyrillic script). A person fluent in
+ one script might not be able to read the other, even though the text
+ might be identical. Content tagged as "az" most probably is written
+ in just one script and thus might not be intelligible to a reader
+ familiar with the other script.
+
+4.3. Length Considerations
+
+ [RFC3066] did not provide an upper limit on the size of language
+ tags. While RFC 3066 did define the semantics of particular subtags
+ in such a way that most language tags consisted of language and
+ region subtags with a combined total length of up to six characters,
+ larger registered tags were not only possible but were actually
+ registered.
+
+ Neither the language tag syntax nor other requirements in this
+ document impose a fixed upper limit on the number of subtags in a
+ language tag (and thus an upper bound on the size of a tag). The
+ language tag syntax suggests that, depending on the specific
+ language, more subtags (and thus a longer tag) are sometimes
+ necessary to completely identify the language for certain
+ applications; thus, it is possible to envision long or complex subtag
+ sequences.
+
+
+
+Phillips & Davis Best Current Practice [Page 41]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+4.3.1. Working with Limited Buffer Sizes
+
+ Some applications and protocols are forced to allocate fixed buffer
+ sizes or otherwise limit the length of a language tag. A conformant
+ implementation or specification MAY refuse to support the storage of
+ language tags that exceed a specified length. Any such limitation
+ SHOULD be clearly documented, and such documentation SHOULD include
+ what happens to longer tags (for example, whether an error value is
+ generated or the language tag is truncated). A protocol that allows
+ tags to be truncated at an arbitrary limit, without giving any
+ indication of what that limit is, has the potential for causing harm
+ by changing the meaning of tags in substantial ways.
+
+ In practice, most language tags do not require more than a few
+ subtags and will not approach reasonably sized buffer limitations;
+ see Section 4.1.
+
+ Some specifications or protocols have limits on tag length but do not
+ have a fixed length limitation. For example, [RFC2231] has no
+ explicit length limitation: the length available for the language tag
+ is constrained by the length of other header components (such as the
+ charset's name) coupled with the 76-character limit in [RFC2047].
+ Thus, the "limit" might be 50 or more characters, but it could
+ potentially be quite small.
+
+ The considerations for assigning a buffer limit are:
+
+ Implementations SHOULD NOT truncate language tags unless the
+ meaning of the tag is purposefully being changed, or unless the
+ tag does not fit into a limited buffer size specified by a
+ protocol for storage or transmission.
+
+ Implementations SHOULD warn the user when a tag is truncated since
+ truncation changes the semantic meaning of the tag.
+
+ Implementations of protocols or specifications that are space
+ constrained but do not have a fixed limit SHOULD use the longest
+ possible tag in preference to truncation.
+
+ Protocols or specifications that specify limited buffer sizes for
+ language tags MUST allow for language tags of up to 33 characters.
+
+ Protocols or specifications that specify limited buffer sizes for
+ language tags SHOULD allow for language tags of at least 42
+ characters.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 42]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The following illustration shows how the 42-character recommendation
+ was derived. The combination of language and extended language
+ subtags was chosen for future compatibility. At up to 15 characters,
+ this combination is longer than the longest possible primary language
+ subtag (8 characters):
+
+ language = 3 (ISO 639-2; ISO 639-1 requires 2)
+ extlang1 = 4 (each subsequent subtag includes '-')
+ extlang2 = 4 (unlikely: needs prefix="language-extlang1")
+ extlang3 = 4 (extremely unlikely)
+ script = 5 (if not suppressed: see Section 4.1)
+ region = 4 (UN M.49; ISO 3166 requires 3)
+ variant1 = 9 (MUST have language as a prefix)
+ variant2 = 9 (MUST have language-variant1 as a prefix)
+
+ total = 42 characters
+
+ Figure 7: Derivation of the Limit on Tag Length
+
+4.3.2. Truncation of Language Tags
+
+ Truncation of a language tag alters the meaning of the tag, and thus
+ SHOULD be avoided. However, truncation of language tags is sometimes
+ necessary due to limited buffer sizes. Such truncation MUST NOT
+ permit a subtag to be chopped off in the middle or the formation of
+ invalid tags (for example, one ending with the "-" character).
+
+ This means that applications or protocols that truncate tags MUST do
+ so by progressively removing subtags along with their preceding "-"
+ from the right side of the language tag until the tag is short enough
+ for the given buffer. If the resulting tag ends with a single-
+ character subtag, that subtag and its preceding "-" MUST also be
+ removed. For example:
+
+ Tag to truncate: zh-Latn-CN-variant1-a-extend1-x-wadegile-private1
+ 1. zh-Latn-CN-variant1-a-extend1-x-wadegile
+ 2. zh-Latn-CN-variant1-a-extend1
+ 3. zh-Latn-CN-variant1
+ 4. zh-Latn-CN
+ 5. zh-Latn
+ 6. zh
+
+ Figure 8: Example of Tag Truncation
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 43]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+4.4. Canonicalization of Language Tags
+
+ Since a particular language tag is sometimes used by many processes,
+ language tags SHOULD always be created or generated in a canonical
+ form.
+
+ A language tag is in canonical form when:
+
+ 1. The tag is well-formed according the rules in Section 2.1 and
+ Section 2.2.
+
+ 2. Subtags of type 'Region' that have a Preferred-Value mapping in
+ the IANA registry (see Section 3.1) SHOULD be replaced with their
+ mapped value. Note: In rare cases, the mapped value will also
+ have a Preferred-Value.
+
+ 3. Redundant or grandfathered tags that have a Preferred-Value
+ mapping in the IANA registry (see Section 3.1) MUST be replaced
+ with their mapped value. These items either are deprecated
+ mappings created before the adoption of this document (such as
+ the mapping of "no-nyn" to "nn" or "i-klingon" to "tlh") or are
+ the result of later registrations or additions to this document
+ (for example, "zh-guoyu" might be mapped to a language-extlang
+ combination such as "zh-cmn" by some future update of this
+ document).
+
+ 4. Other subtags that have a Preferred-Value mapping in the IANA
+ registry (see Section 3.1) MUST be replaced with their mapped
+ value. These items consist entirely of clerical corrections to
+ ISO 639-1 in which the deprecated subtags have been maintained
+ for compatibility purposes.
+
+ 5. If more than one extension subtag sequence exists, the extension
+ sequences are ordered into case-insensitive ASCII order by
+ singleton subtag.
+
+ Example: The language tag "en-A-aaa-B-ccc-bbb-x-xyz" is in canonical
+ form, while "en-B-ccc-bbb-A-aaa-X-xyz" is well-formed but not in
+ canonical form.
+
+ Example: The language tag "en-BU" (English as used in Burma) is not
+ canonical because the 'BU' subtag has a canonical mapping to 'MM'
+ (Myanmar), although the tag "en-BU" maintains its validity.
+
+ Canonicalization of language tags does not imply anything about the
+ use of upper or lowercase letters when processing or comparing
+ subtags (and as described in Section 2.1). All comparisons MUST be
+ performed in a case-insensitive manner.
+
+
+
+Phillips & Davis Best Current Practice [Page 44]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ When performing canonicalization of language tags, processors MAY
+ regularize the case of the subtags (that is, this process is
+ OPTIONAL), following the case used in the registry. Note that this
+ corresponds to the following casing rules: uppercase all non-initial
+ two-letter subtags; titlecase all non-initial four-letter subtags;
+ lowercase everything else.
+
+ Note: Case folding of ASCII letters in certain locales, unless
+ carefully handled, sometimes produces non-ASCII character values.
+ The Unicode Character Database file "SpecialCasing.txt" defines the
+ specific cases that are known to cause problems with this. In
+ particular, the letter 'i' (U+0069) in Turkish and Azerbaijani is
+ uppercased to U+0130 (LATIN CAPITAL LETTER I WITH DOT ABOVE).
+ Implementers SHOULD specify a locale-neutral casing operation to
+ ensure that case folding of subtags does not produce this value,
+ which is illegal in language tags. For example, if one were to
+ uppercase the region subtag 'in' using Turkish locale rules, the
+ sequence U+0130 U+004E would result instead of the expected 'IN'.
+
+ Note: if the field 'Deprecated' appears in a registry record without
+ an accompanying 'Preferred-Value' field, then that tag or subtag is
+ deprecated without a replacement. Validating processors SHOULD NOT
+ generate tags that include these values, although the values are
+ canonical when they appear in a language tag.
+
+ An extension MUST define any relationships that exist between the
+ various subtags in the extension and thus MAY define an alternate
+ canonicalization scheme for the extension's subtags. Extensions MAY
+ define how the order of the extension's subtags are interpreted. For
+ example, an extension could define that its subtags are in canonical
+ order when the subtags are placed into ASCII order: that is,
+ "en-a-aaa-bbb-ccc" instead of "en-a-ccc-bbb-aaa". Another extension
+ might define that the order of the subtags influences their semantic
+ meaning (so that "en-b-ccc-bbb-aaa" has a different value from
+ "en-b-aaa-bbb-ccc"). However, extension specifications SHOULD be
+ designed so that they are tolerant of the typical processes described
+ in Section 3.7.
+
+4.5. Considerations for Private Use Subtags
+
+ Private use subtags, like all other subtags, MUST conform to the
+ format and content constraints in the ABNF. Private use subtags have
+ no meaning outside the private agreement between the parties that
+ intend to use or exchange language tags that employ them. The same
+ subtags MAY be used with a different meaning under a separate private
+ agreement. They SHOULD NOT be used where alternatives exist and
+ SHOULD NOT be used in content or protocols intended for general use.
+
+
+
+
+Phillips & Davis Best Current Practice [Page 45]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ Private use subtags are simply useless for information exchange
+ without prior arrangement. The value and semantic meaning of private
+ use tags and of the subtags used within such a language tag are not
+ defined by this document.
+
+ Subtags defined in the IANA registry as having a specific private use
+ meaning convey more information that a purely private use tag
+ prefixed by the singleton subtag 'x'. For applications, this
+ additional information MAY be useful.
+
+ For example, the region subtags 'AA', 'ZZ', and in the ranges
+ 'QM'-'QZ' and 'XA'-'XZ' (derived from ISO 3166 private use codes) MAY
+ be used to form a language tag. A tag such as "zh-Hans-XQ" conveys a
+ great deal of public, interchangeable information about the language
+ material (that it is Chinese in the simplified Chinese script and is
+ suitable for some geographic region 'XQ'). While the precise
+ geographic region is not known outside of private agreement, the tag
+ conveys far more information than an opaque tag such as "x-someLang",
+ which contains no information about the language subtag or script
+ subtag outside of the private agreement.
+
+ However, in some cases content tagged with private use subtags MAY
+ interact with other systems in a different and possibly unsuitable
+ manner compared to tags that use opaque, privately defined subtags,
+ so the choice of the best approach sometimes depends on the
+ particular domain in question.
+
+5. IANA Considerations
+
+ This section deals with the processes and requirements necessary for
+ IANA to undertake to maintain the subtag and extension registries as
+ defined by this document and in accordance with the requirements of
+ [RFC2434].
+
+ The impact on the IANA maintainers of the two registries defined by
+ this document will be a small increase in the frequency of new
+ entries or updates.
+
+5.1. Language Subtag Registry
+
+ Upon adoption of this document, the registry will be initialized by a
+ companion document: [RFC4645]. The criteria and process for
+ selecting the initial set of records are described in that document.
+ The initial set of records represents no impact on IANA, since the
+ work to create it will be performed externally.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 46]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The new registry MUST be listed under "Language Tags" at
+ <http://www.iana.org/numbers.html>, replacing the existing
+ registrations defined by [RFC3066]. The existing set of registration
+ forms and RFC 3066 registrations MUST be relabeled as "Language Tags
+ (Obsolete)" and maintained (but not added to or modified).
+
+ Future work on the Language Subtag Registry SHALL be limited to
+ inserting or replacing whole records preformatted for IANA by the
+ Language Subtag Reviewer as described in Section 3.3 of this document
+ and archiving the forwarded registration form.
+
+ Each record MUST be sent to iana@iana.org with a subject line
+ indicating whether the enclosed record is an insertion of a new
+ record (indicated by the word "INSERT" in the subject line) or a
+ replacement of an existing record (indicated by the word "MODIFY" in
+ the subject line). Records MUST NOT be deleted from the registry.
+ IANA MUST place any inserted or modified records into the appropriate
+ section of the language subtag registry, grouping the records by
+ their 'Type' field. Inserted records MAY be placed anywhere in the
+ appropriate section; there is no guarantee of the order of the
+ records beyond grouping them together by 'Type'. Modified records
+ MUST overwrite the record they replace.
+
+ Included in any request to insert or modify records MUST be a new
+ File-Date record. This record MUST be placed first in the registry.
+ In the event that the File-Date record present in the registry has a
+ later date than the record being inserted or modified, the existing
+ record MUST be preserved.
+
+5.2. Extensions Registry
+
+ The Language Tag Extensions Registry will also be generated and sent
+ to IANA as described in Section 3.7. This registry can contain at
+ most 35 records, and thus changes to this registry are expected to be
+ very infrequent.
+
+ Future work by IANA on the Language Tag Extensions Registry is
+ limited to two cases. First, the IESG MAY request that new records
+ be inserted into this registry from time to time. These requests
+ MUST include the record to insert in the exact format described in
+ Section 3.7. In addition, there MAY be occasional requests from the
+ maintaining authority for a specific extension to update the contact
+ information or URLs in the record. These requests MUST include the
+ complete, updated record. IANA is not responsible for validating the
+ information provided, only that it is properly formatted. It should
+ reasonably be seen to come from the maintaining authority named in
+ the record present in the registry.
+
+
+
+
+Phillips & Davis Best Current Practice [Page 47]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+6. Security Considerations
+
+ Language tags used in content negotiation, like any other information
+ exchanged on the Internet, might be a source of concern because they
+ might be used to infer the nationality of the sender, and thus
+ identify potential targets for surveillance.
+
+ This is a special case of the general problem that anything sent is
+ visible to the receiving party and possibly to third parties as well.
+ It is useful to be aware that such concerns can exist in some cases.
+
+ The evaluation of the exact magnitude of the threat, and any possible
+ countermeasures, is left to each application protocol (see BCP 72
+ [RFC3552] for best current practice guidance on security threats and
+ defenses).
+
+ The language tag associated with a particular information item is of
+ no consequence whatsoever in determining whether that content might
+ contain possible homographs. The fact that a text is tagged as being
+ in one language or using a particular script subtag provides no
+ assurance whatsoever that it does not contain characters from scripts
+ other than the one(s) associated with or specified by that language
+ tag.
+
+ Since there is no limit to the number of variant, private use, and
+ extension subtags, and consequently no limit on the possible length
+ of a tag, implementations need to guard against buffer overflow
+ attacks. See Section 4.3 for details on language tag truncation,
+ which can occur as a consequence of defenses against buffer overflow.
+
+ Although the specification of valid subtags for an extension (see
+ Section 3.7) MUST be available over the Internet, implementations
+ SHOULD NOT mechanically depend on it being always accessible, to
+ prevent denial-of-service attacks.
+
+7. Character Set Considerations
+
+ The syntax in this document requires that language tags use only the
+ characters A-Z, a-z, 0-9, and HYPHEN-MINUS, which are present in most
+ character sets, so the composition of language tags should not have
+ any character set issues.
+
+ Rendering of characters based on the content of a language tag is not
+ addressed in this memo. Historically, some languages have relied on
+ the use of specific character sets or other information in order to
+ infer how a specific character should be rendered (notably this
+ applies to language- and culture-specific variations of Han
+ ideographs as used in Japanese, Chinese, and Korean). When language
+
+
+
+Phillips & Davis Best Current Practice [Page 48]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ tags are applied to spans of text, rendering engines sometimes use
+ that information in deciding which font to use in the absence of
+ other information, particularly where languages with distinct writing
+ traditions use the same characters.
+
+8. Changes from RFC 3066
+
+ The main goals for this revision of language tags were the following:
+
+ *Compatibility.* All RFC 3066 language tags (including those in the
+ IANA registry) remain valid in this specification. The changes in
+ this document represent additional constraints on language tags.
+ That is, in no case is the syntax more permissive and processors
+ based on the ABNF and other provisions of RFC 3066 (such as those
+ described in [XMLSchema]) will be able to process the tags described
+ by this document. In addition, this document defines language tags
+ in such as way as to ensure future compatibility.
+
+ *Stability.* Because of changes in the past in the underlying ISO
+ standards, a valid RFC 3066 language tag could become invalid or have
+ its meaning change. This has the potential of invalidating content
+ that may have an extensive shelf-life. In this specification, once a
+ language tag is valid, it remains valid forever.
+
+ *Validity.* The structure of language tags defined by this document
+ makes it possible to determine if a particular tag is well-formed
+ without regard for the actual content or "meaning" of the tag as a
+ whole. This is important because the registry grows and underlying
+ standards change over time. In addition, it must be possible to
+ determine if a tag is valid (or not) for a given point in time in
+ order to provide reproducible, testable results. This process must
+ not be error-prone; otherwise implementations might give different
+ results. By having an authoritative registry with specific
+ versioning information, the validity of language tags at any point in
+ time can be precisely determined (instead of interpolating values
+ from many separate sources).
+
+ *Utility.* It is sometimes important to be able to differentiate
+ between written forms of a language -- for many implementations this
+ is more important than distinguishing between the spoken variants of
+ a language. Languages are written in a wide variety of different
+ scripts, so this document provides for the generative use of ISO
+ 15924 script codes. Like the generative use of ISO language and
+ country codes in RFC 3066, this allows combinations to be produced
+ without resorting to the registration process. The addition of UN
+ M.49 codes provides for the generation of language tags with regional
+ scope, which is also required by some applications.
+
+
+
+
+Phillips & Davis Best Current Practice [Page 49]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The recast of the registry from containing whole language tags to
+ subtags is a key part of this. An important feature of RFC 3066 was
+ that it allowed generative use of subtags. This allows people to
+ meaningfully use generated tags, without the delays in registering
+ whole tags or the need to register all of the combinations that might
+ be useful.
+
+ The choice of placing the extended language and script subtags
+ between the primary language and region subtags was widely debated.
+ This design was chosen because the prevalent matching and content
+ negotiation schemes rely on the subtags being arranged in order of
+ increasing specificity. That is, the subtags that mark a greater
+ barrier to mutual intelligibility appear left-most in a tag. For
+ example, when selecting content written in Azerbaijani, the script
+ (Arabic, Cyrillic, or Latin) represents a greater barrier to
+ understanding than any regional variations (those associated with
+ Azerbaijan or Iran, for example). Individuals who prefer documents
+ in a particular script, but can deal with the minor regional
+ differences, can therefore select appropriate content. Applications
+ that do not deal with written content will continue to omit these
+ subtags.
+
+ *Extensibility.* Because of the widespread use of language tags, it
+ is disruptive to have periodic revisions of the core specification,
+ even in the face of demonstrated need. The extension mechanism
+ provides for a way for independent RFCs to define extensions to
+ language tags. These extensions have a very constrained, well-
+ defined structure that prevents extensions from interfering with
+ implementations of language tags defined in this document.
+
+ The document also anticipates features of ISO 639-3 with the addition
+ of the extended language subtags, as well as the possibility of other
+ ISO 639 parts becoming useful for the formation of language tags in
+ the future.
+
+ The use and definition of private use tags have also been modified,
+ to allow people to use private use subtags to extend or modify
+ defined tags and to move as much information as possible out of
+ private use and into the regular structure.
+
+ The goal for each of these modifications is to reduce or eliminate
+ the need for future revisions of this document.
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 50]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ The specific changes in this document to meet these goals are:
+
+ o Defines the ABNF and rules for subtags so that the category of all
+ subtags can be determined without reference to the registry.
+
+ o Adds the concept of well-formed vs. validating processors,
+ defining the rules by which an implementation can claim to be one
+ or the other.
+
+ o Replaces the IANA language tag registry with a language subtag
+ registry that provides a complete list of valid subtags in the
+ IANA registry. This allows for robust implementation and ease of
+ maintenance. The language subtag registry becomes the canonical
+ source for forming language tags.
+
+ o Provides a process that guarantees stability of language tags, by
+ handling reuse of values by ISO 639, ISO 15924, and ISO 3166 in
+ the event that they register a previously used value for a new
+ purpose.
+
+ o Allows ISO 15924 script code subtags and allows them to be used
+ generatively. Defines a method for indicating in the registry
+ when script subtags are necessary for a given language tag.
+
+ o Adds the concept of a variant subtag and allows variants to be
+ used generatively.
+
+ o Adds the ability to use a class of UN M.49 tags for supra-national
+ regions and to resolve conflicts in the assignment of ISO 3166
+ codes.
+
+ o Defines the private use tags in ISO 639, ISO 15924, and ISO 3166
+ as the mechanism for creating private use language, script, and
+ region subtags, respectively.
+
+ o Adds a well-defined extension mechanism.
+
+ o Defines an extended language subtag, possibly for use with certain
+ anticipated features of ISO 639-3.
+
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 51]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+9. References
+
+9.1. Normative References
+
+ [ISO10646] International Organization for Standardization,
+ "ISO/IEC 10646:2003. Information technology --
+ Universal Multiple-Octet Coded Character Set (UCS)",
+ 2003.
+
+ [ISO15924] International Organization for Standardization, "ISO
+ 15924:2004. Information and documentation -- Codes for
+ the representation of names of scripts", January 2004.
+
+ [ISO3166-1] International Organization for Standardization, "ISO
+ 3166-1:1997. Codes for the representation of names of
+ countries and their subdivisions -- Part 1: Country
+ codes", 1997.
+
+ [ISO639-1] International Organization for Standardization, "ISO
+ 639-1:2002. Codes for the representation of names of
+ languages -- Part 1: Alpha-2 code", 2002.
+
+ [ISO639-2] International Organization for Standardization, "ISO
+ 639-2:1998. Codes for the representation of names of
+ languages -- Part 2: Alpha-3 code, first edition",
+ 1998.
+
+ [ISO646] International Organization for Standardization,
+ "ISO/IEC 646:1991, Information technology -- ISO 7-bit
+ coded character set for information interchange.",
+ 1991.
+
+ [RFC2026] Bradner, S., "The Internet Standards Process --
+ Revision 3", BCP 9, RFC 2026, October 1996.
+
+ [RFC2028] Hovey, R. and S. Bradner, "The Organizations Involved
+ in the IETF Standards Process", BCP 11, RFC 2028,
+ October 1996.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2434] Narten, T. and H. Alvestrand, "Guidelines for Writing
+ an IANA Considerations Section in RFCs", BCP 26,
+ RFC 2434, October 1998.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 52]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ [RFC2860] Carpenter, B., Baker, F., and M. Roberts, "Memorandum
+ of Understanding Concerning the Technical Work of the
+ Internet Assigned Numbers Authority", RFC 2860,
+ June 2000.
+
+ [RFC3339] Klyne, G., Ed. and C. Newman, "Date and Time on the
+ Internet: Timestamps", RFC 3339, July 2002.
+
+ [RFC4234] Crocker, D., Ed. and P. Overell, "Augmented BNF for
+ Syntax Specifications: ABNF", RFC 4234, October 2005.
+
+ [UN_M.49] Statistics Division, United Nations, "Standard Country
+ or Area Codes for Statistical Use", UN Standard
+ Country or Area Codes for Statistical Use, Revision 4
+ (United Nations publication, Sales No. 98.XVII.9,
+ June 1999.
+
+9.2. Informative References
+
+ [RFC1766] Alvestrand, H., "Tags for the Identification of
+ Languages", RFC 1766, March 1995.
+
+ [RFC2047] Moore, K., "MIME (Multipurpose Internet Mail
+ Extensions) Part Three: Message Header Extensions for
+ Non-ASCII Text", RFC 2047, November 1996.
+
+ [RFC2231] Freed, N. and K. Moore, "MIME Parameter Value and
+ Encoded Word Extensions: Character Sets, Languages,
+ and Continuations", RFC 2231, November 1997.
+
+ [RFC2781] Hoffman, P. and F. Yergeau, "UTF-16, an encoding of
+ ISO 10646", RFC 2781, February 2000.
+
+ [RFC3066] Alvestrand, H., "Tags for the Identification of
+ Languages", BCP 47, RFC 3066, January 2001.
+
+ [RFC3552] Rescorla, E. and B. Korver, "Guidelines for Writing
+ RFC Text on Security Considerations", BCP 72,
+ RFC 3552, July 2003.
+
+ [RFC4645] Ewell, D., Ed., "Initial Language Subtag Registry",
+ RFC 4645, September 2006.
+
+ [RFC4647] Phillips, A., Ed. and M. Davis, Ed., "Matching of
+ Language Tags", BCP 47, RFC 4647, September 2006.
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 53]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ [Unicode] Unicode Consortium, "The Unicode Standard, Version
+ 5.0", Boston, MA, Addison-Wesley, 2007. ISBN 0-321-
+ 48091-0.
+
+ [XML10] Bray (et al), T., "Extensible Markup Language (XML)
+ 1.0", 02 2004.
+
+ [XMLSchema] Biron, P., Ed. and A. Malhotra, Ed., "XML Schema Part
+ 2: Datatypes Second Edition", 10 2004, <
+ http://www.w3.org/TR/xmlschema-2/>.
+
+ [iso639.prin] ISO 639 Joint Advisory Committee, "ISO 639 Joint
+ Advisory Committee: Working principles for ISO 639
+ maintenance", March 2000, <http://www.loc.gov/
+ standards/iso639-2/iso639jac_n3r.html>.
+
+ [record-jar] Raymond, E., "The Art of Unix Programming", 2003,
+ <urn:isbn:0-13-142901-9>.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 54]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+Appendix A. Acknowledgements
+
+ Any list of contributors is bound to be incomplete; please regard the
+ following as only a selection from the group of people who have
+ contributed to make this document what it is today.
+
+ The contributors to RFC 3066 and RFC 1766, the precursors of this
+ document, made enormous contributions directly or indirectly to this
+ document and are generally responsible for the success of language
+ tags.
+
+ The following people (in alphabetical order) contributed to this
+ document or to RFCs 1766 and 3066:
+
+ Glenn Adams, Harald Tveit Alvestrand, Tim Berners-Lee, Marc Blanchet,
+ Nathaniel Borenstein, Karen Broome, Eric Brunner, Sean M. Burke, M.T.
+ Carrasco Benitez, Jeremy Carroll, John Clews, Jim Conklin, Peter
+ Constable, John Cowan, Mark Crispin, Dave Crocker, Elwyn Davies,
+ Martin Duerst, Frank Ellerman, Michael Everson, Doug Ewell, Ned
+ Freed, Tim Goodwin, Dirk-Willem van Gulik, Marion Gunn, Joel Halpren,
+ Elliotte Rusty Harold, Paul Hoffman, Scott Hollenbeck, Richard
+ Ishida, Olle Jarnefors, Kent Karlsson, John Klensin, Erkki
+ Kolehmainen, Alain LaBonte, Eric Mader, Ira McDonald, Keith Moore,
+ Chris Newman, Masataka Ohta, Dylan Pierce, Randy Presuhn, George
+ Rhoten, Felix Sasaki, Markus Scherer, Keld Jorn Simonsen, Thierry
+ Sourbier, Otto Stolz, Tex Texin, Andrea Vine, Rhys Weatherley, Misha
+ Wolf, Francois Yergeau and many, many others.
+
+ Very special thanks must go to Harald Tveit Alvestrand, who
+ originated RFCs 1766 and 3066, and without whom this document would
+ not have been possible. Special thanks must go to Michael Everson,
+ who has served as Language Tag Reviewer for almost the complete
+ period since the publication of RFC 1766. Special thanks to Doug
+ Ewell, for his production of the first complete subtag registry, and
+ his work in producing a test parser for verifying language tags.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 55]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+Appendix B. Examples of Language Tags (Informative)
+
+ Simple language subtag:
+
+ de (German)
+
+ fr (French)
+
+ ja (Japanese)
+
+ i-enochian (example of a grandfathered tag)
+
+ Language subtag plus Script subtag:
+
+ zh-Hant (Chinese written using the Traditional Chinese script)
+
+ zh-Hans (Chinese written using the Simplified Chinese script)
+
+ sr-Cyrl (Serbian written using the Cyrillic script)
+
+ sr-Latn (Serbian written using the Latin script)
+
+ Language-Script-Region:
+
+ zh-Hans-CN (Chinese written using the Simplified script as used in
+ mainland China)
+
+ sr-Latn-CS (Serbian written using the Latin script as used in
+ Serbia and Montenegro)
+
+ Language-Variant:
+
+ sl-rozaj (Resian dialect of Slovenian
+
+ sl-nedis (Nadiza dialect of Slovenian)
+
+ Language-Region-Variant:
+
+ de-CH-1901 (German as used in Switzerland using the 1901 variant
+ [orthography])
+
+ sl-IT-nedis (Slovenian as used in Italy, Nadiza dialect)
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 56]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ Language-Script-Region-Variant:
+
+ sl-Latn-IT-nedis (Nadiza dialect of Slovenian written using the
+ Latin script as used in Italy. Note that this tag is NOT
+ RECOMMENDED because subtag 'sl' has a Suppress-Script value of
+ 'Latn')
+
+ Language-Region:
+
+ de-DE (German for Germany)
+
+ en-US (English as used in the United States)
+
+ es-419 (Spanish appropriate for the Latin America and Caribbean
+ region using the UN region code)
+
+ Private use subtags:
+
+ de-CH-x-phonebk
+
+ az-Arab-x-AZE-derbend
+
+ Extended language subtags (examples ONLY: extended languages MUST be
+ defined by revision or update to this document):
+
+ zh-min
+
+ zh-min-nan-Hant-CN
+
+ Private use registry values:
+
+ x-whatever (private use using the singleton 'x')
+
+ qaa-Qaaa-QM-x-southern (all private tags)
+
+ de-Qaaa (German, with a private script)
+
+ sr-Latn-QM (Serbian, Latin-script, private region)
+
+ sr-Qaaa-CS (Serbian, private script, for Serbia and Montenegro)
+
+ Tags that use extensions (examples ONLY: extensions MUST be defined
+ by revision or update to this document or by RFC):
+
+ en-US-u-islamCal
+
+ zh-CN-a-myExt-x-private
+
+
+
+
+Phillips & Davis Best Current Practice [Page 57]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+ en-a-myExt-b-another
+
+ Some Invalid Tags:
+
+ de-419-DE (two region tags)
+
+ a-DE (use of a single-character subtag in primary position; note
+ that there are a few grandfathered tags that start with "i-" that
+ are valid)
+
+ ar-a-aaa-b-bbb-a-ccc (two extensions with same single-letter
+ prefix)
+
+Authors' Addresses
+
+ Addison Phillips (Editor)
+ Yahoo! Inc.
+
+ EMail: addison@inter-locale.com
+
+
+ Mark Davis (Editor)
+ Google
+
+ EMail: mark.davis@macchiato.com or mark.davis@google.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 58]
+
+RFC 4646 Tags for Identifying Languages September 2006
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2006).
+
+ This document is subject to the rights, licenses and restrictions
+ contained in BCP 78, and except as set forth therein, the authors
+ retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the procedures with respect to rights in RFC documents can be
+ found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at
+ ietf-ipr@ietf.org.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is provided by the IETF
+ Administrative Support Activity (IASA).
+
+
+
+
+
+
+
+Phillips & Davis Best Current Practice [Page 59]
+
diff --git a/standards/rfctohtml.c b/standards/rfctohtml.c
new file mode 100644
index 000000000..2d0c08677
--- /dev/null
+++ b/standards/rfctohtml.c
@@ -0,0 +1,504 @@
+/*
+ * "$Id$"
+ *
+ * RFC file to HTML conversion program.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Convert a man page to HTML.
+ * put_entity() - Put a single character, using entities as needed.
+ * put_line() - Put a whole string for a line.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <cups/string-private.h>
+#include <stdlib.h>
+#include <cups/file.h>
+
+
+/*
+ * Local functions...
+ */
+
+void put_entity(cups_file_t *fp, int ch);
+void put_line(cups_file_t *fp, const char *line);
+
+
+/*
+ * 'main()' - Convert a man page to HTML.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ cups_file_t *infile, /* Input file */
+ *outfile; /* Output file */
+ char line[1024], /* Line from file */
+ *lineptr, /* Pointer into line */
+ title[2048], /* Title string */
+ *titleptr, /* Pointer into title */
+ name[1024], /* Heading anchor name */
+ *nameptr; /* Pointer into anchor name */
+ int rfc, /* RFC # */
+ inheading, /* Inside a heading? */
+ inpre, /* Inside preformatted text? */
+ intoc, /* Inside table-of-contents? */
+ toclevel, /* Current table-of-contents level */
+ linenum; /* Current line on page */
+
+
+ /*
+ * Check arguments...
+ */
+
+ if (argc > 3)
+ {
+ fputs("Usage: rfctohtml [rfcNNNN.txt [rfcNNNN.html]]\n", stderr);
+ return (1);
+ }
+
+ /*
+ * Open files as needed...
+ */
+
+ if (argc > 1)
+ {
+ if ((infile = cupsFileOpen(argv[1], "r")) == NULL)
+ {
+ perror(argv[1]);
+ return (1);
+ }
+ }
+ else
+ infile = cupsFileOpenFd(0, "r");
+
+ if (argc > 2)
+ {
+ if ((outfile = cupsFileOpen(argv[2], "w")) == NULL)
+ {
+ perror(argv[2]);
+ cupsFileClose(infile);
+ return (1);
+ }
+ }
+ else
+ outfile = cupsFileOpenFd(1, "w");
+
+ /*
+ * Read from input and write the output...
+ */
+
+ cupsFilePuts(outfile,
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" "
+ "\"http://www.w3.org/TR/html4/loose.dtd\">\n"
+ "<html>\n"
+ "<!-- SECTION: Specifications -->\n"
+ "<head>\n"
+ "\t<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"../cups-printable.css\">\n");
+
+ /*
+ * Skip the initial header stuff (working group ID, RFC #, authors, and
+ * copyright...
+ */
+
+ linenum = 0;
+ rfc = 0;
+
+ while (cupsFileGets(infile, line, sizeof(line)))
+ {
+ linenum ++;
+
+ if (line[0])
+ break;
+ }
+
+ while (cupsFileGets(infile, line, sizeof(line)))
+ {
+ linenum ++;
+
+ if (!line[0])
+ break;
+ else if (!_cups_strncasecmp(line, "Request for Comments:", 21))
+ rfc = atoi(line + 21);
+ }
+
+ /*
+ * Read the document title...
+ */
+
+ while (cupsFileGets(infile, line, sizeof(line)))
+ {
+ linenum ++;
+
+ if (line[0])
+ break;
+ }
+
+ for (lineptr = line; isspace(*lineptr & 255); lineptr ++);
+
+ snprintf(title, sizeof(title), "RFC %d: %s", rfc, lineptr);
+ titleptr = title + strlen(title);
+
+ while (cupsFileGets(infile, line, sizeof(line)))
+ {
+ linenum ++;
+
+ if (!line[0])
+ break;
+ else
+ {
+ for (lineptr = line; isspace(*lineptr & 255); lineptr ++);
+
+ snprintf(titleptr, sizeof(title) - (titleptr - title), " %s", lineptr);
+ titleptr += strlen(titleptr);
+ }
+ }
+
+ cupsFilePrintf(outfile, "\t<title>%s</title>\n"
+ "</head>\n"
+ "<body>\n"
+ "<h1 class='title'>%s</h1>\n", title, title);
+
+ /*
+ * Read the rest of the file...
+ */
+
+ inheading = 0;
+ inpre = 0;
+ intoc = 0;
+ toclevel = 0;
+
+ while (cupsFileGets(infile, line, sizeof(line)))
+ {
+ linenum ++;
+
+ if (!line[0])
+ {
+ if (linenum > 50)
+ continue;
+
+ if (inpre)
+ {
+ cupsFilePuts(outfile, "</pre>\n");
+ inpre = 0;
+ }
+
+ if (inheading)
+ {
+ if (inheading < 0)
+ cupsFilePuts(outfile, "</h2>\n");
+ else
+ cupsFilePrintf(outfile, "</a></h%d>\n", inheading);
+
+ inheading = 0;
+ }
+ }
+ else if ((line[0] == ' ' ||
+ (!isupper(line[0] & 255) && !isdigit(line[0] & 255) &&
+ !strstr(line, "[Page "))) && !inheading)
+ {
+ if (inheading)
+ {
+ if (inheading < 0)
+ cupsFilePuts(outfile, "</h2>\n");
+ else
+ cupsFilePrintf(outfile, "</a></h%d>\n", inheading);
+
+ inheading = 0;
+ }
+
+ for (lineptr = line; *lineptr == ' '; lineptr ++);
+
+ if (intoc)
+ {
+ char *temp; /* Temporary pointer into line */
+ int level; /* Heading level */
+
+
+ if (isdigit(*lineptr & 255))
+ {
+ strlcpy(name, lineptr, sizeof(name));
+
+ for (nameptr = name, level = -1; *nameptr;)
+ if (isdigit(*nameptr & 255))
+ {
+ while (isdigit(*nameptr & 255))
+ nameptr ++;
+
+ level ++;
+ }
+ else if (*nameptr == ' ')
+ {
+ *nameptr = '\0';
+ break;
+ }
+ else
+ nameptr ++;
+
+ while (toclevel > level)
+ {
+ cupsFilePuts(outfile, "\n</ul>");
+ toclevel --;
+ }
+
+ while (toclevel < level)
+ {
+ cupsFilePuts(outfile, "\n<ul style=\"list-style-type: none;\">\n");
+ toclevel ++;
+ }
+
+ cupsFilePrintf(outfile, "\n<%s><a href=\"#s%s\">", toclevel ? "li" : "p",
+ name);
+ }
+
+ temp = lineptr + strlen(lineptr) - 1;
+
+ while (temp > lineptr)
+ if (*temp == ' ' || !isdigit(*temp & 255))
+ break;
+ else
+ temp --;
+
+ if (*temp == ' ')
+ {
+ while (temp > lineptr)
+ if (*temp != ' ' && *temp != '.')
+ break;
+ else
+ *temp-- = '\0';
+ }
+ else
+ temp = NULL;
+
+ if (isdigit(*lineptr & 255))
+ put_line(outfile, lineptr);
+ else
+ put_line(outfile, lineptr - 1);
+
+ if (temp)
+ cupsFilePuts(outfile, "</a>");
+ }
+ else if (!inpre)
+ {
+ cupsFilePuts(outfile, "\n<pre>");
+ put_line(outfile, line);
+ inpre = 1;
+ }
+ else
+ {
+ cupsFilePutChar(outfile, '\n');
+ put_line(outfile, line);
+ }
+ }
+ else if (strstr(line, "[Page "))
+ {
+ /*
+ * Skip page footer and header...
+ */
+
+ cupsFileGets(infile, line, sizeof(line));
+ cupsFileGets(infile, line, sizeof(line));
+ cupsFileGets(infile, line, sizeof(line));
+ cupsFileGets(infile, line, sizeof(line));
+ linenum = 3;
+ }
+ else if (isdigit(line[0] & 255) && !inheading)
+ {
+ int level; /* Heading level */
+
+
+ if (intoc)
+ {
+ while (toclevel > 0)
+ {
+ cupsFilePuts(outfile, "\n</ul>");
+ toclevel --;
+ }
+
+ cupsFilePutChar(outfile, '\n');
+ intoc = 0;
+ }
+
+ if (inpre)
+ {
+ cupsFilePuts(outfile, "</pre>\n");
+ inpre = 0;
+ }
+
+ strlcpy(name, line, sizeof(name));
+ for (nameptr = name, level = 1; *nameptr;)
+ if (isdigit(*nameptr & 255))
+ {
+ while (isdigit(*nameptr & 255))
+ nameptr ++;
+
+ level ++;
+ }
+ else if (*nameptr == ' ')
+ {
+ *nameptr = '\0';
+ break;
+ }
+ else
+ nameptr ++;
+
+ cupsFilePrintf(outfile, "\n<h%d class='title'><a name='s%s'>", level,
+ name);
+ put_line(outfile, line);
+
+ intoc = 0;
+ inheading = level;
+ }
+ else
+ {
+ if (intoc)
+ {
+ while (toclevel > 0)
+ {
+ cupsFilePuts(outfile, "\n</ul>");
+ toclevel --;
+ }
+
+ cupsFilePutChar(outfile, '\n');
+ intoc = 0;
+ }
+
+ if (!inheading)
+ {
+ cupsFilePuts(outfile, "\n<h2 class='title'>");
+ inheading = -1;
+ }
+
+ put_line(outfile, line);
+
+ intoc = !_cups_strcasecmp(line, "Table of Contents");
+ toclevel = 0;
+ }
+ }
+
+ if (inpre)
+ cupsFilePuts(outfile, "</pre>\n");
+
+ if (inheading)
+ {
+ if (inheading < 0)
+ cupsFilePuts(outfile, "</h2>\n");
+ else
+ cupsFilePrintf(outfile, "</a></h%d>\n", inheading);
+ }
+
+ cupsFilePuts(outfile, "</body>\n"
+ "</html>\n");
+
+ /*
+ * Close files...
+ */
+
+ cupsFileClose(infile);
+ cupsFileClose(outfile);
+
+ /*
+ * Return with no errors...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'put_entity()' - Put a single character, using entities as needed.
+ */
+
+void
+put_entity(cups_file_t *fp, /* I - File */
+ int ch) /* I - Character */
+{
+ if (ch == '&')
+ cupsFilePuts(fp, "&amp;");
+ else if (ch == '<')
+ cupsFilePuts(fp, "&lt;");
+ else
+ cupsFilePutChar(fp, ch);
+}
+
+
+/*
+ * 'put_line()' - Put a whole string for a line.
+ */
+
+void
+put_line(cups_file_t *fp, /* I - File */
+ const char *s) /* I - String */
+{
+ int whitespace, /* Saw whitespace */
+ i, /* Looping var */
+ len; /* Length of keyword */
+ static const char * const keywords[] =/* Special keywords to boldface */
+ {
+ "MAY",
+ "MUST",
+ "NEED",
+ "NOT",
+ "OPTIONAL",
+ "OPTIONALLY",
+ "RECOMMENDED",
+ "REQUIRED",
+ "SHALL",
+ "SHOULD"
+ };
+
+
+ whitespace = 1;
+
+ while (*s)
+ {
+ if (*s == ' ')
+ whitespace = 1;
+
+ if (whitespace && isupper(*s & 255))
+ {
+ whitespace = 0;
+
+ for (i = 0; i < (int)(sizeof(keywords) / sizeof(sizeof(keywords[0]))); i ++)
+ {
+ len = strlen(keywords[i]);
+ if (!strncmp(s, keywords[i], len) &&
+ (isspace(s[len] & 255) || ispunct(s[len] & 255) || !*s))
+ {
+ cupsFilePrintf(fp, "<b>%s</b>", keywords[i]);
+ s += len;
+ break;
+ }
+ }
+
+ if (i >= (int)(sizeof(keywords) / sizeof(sizeof(keywords[0]))))
+ put_entity(fp, *s++);
+ }
+ else
+ {
+ if (*s != ' ')
+ whitespace = 0;
+
+ put_entity(fp, *s++);
+ }
+ }
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/standards/wake-on-lan.pdf b/standards/wake-on-lan.pdf
new file mode 100644
index 000000000..07d97f443
--- /dev/null
+++ b/standards/wake-on-lan.pdf
Binary files differ
diff --git a/standards/wd-ippmailto10-20050519.pdf b/standards/wd-ippmailto10-20050519.pdf
new file mode 100644
index 000000000..1ec8c996f
--- /dev/null
+++ b/standards/wd-ippmailto10-20050519.pdf
Binary files differ
diff --git a/systemv/Dependencies b/systemv/Dependencies
new file mode 100644
index 000000000..a7aa88c31
--- /dev/null
+++ b/systemv/Dependencies
@@ -0,0 +1,108 @@
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+cancel.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+cancel.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+cancel.o: ../cups/language.h ../cups/string-private.h ../config.h
+cancel.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+cancel.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+cancel.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+cancel.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+cancel.o: ../cups/thread-private.h
+cupsaccept.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+cupsaccept.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+cupsaccept.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+cupsaccept.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+cupsaccept.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+cupsaccept.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+cupsaccept.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+cupsaccept.o: ../cups/transcode.h ../cups/thread-private.h
+cupsaddsmb.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+cupsaddsmb.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+cupsaddsmb.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+cupsaddsmb.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+cupsaddsmb.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+cupsaddsmb.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+cupsaddsmb.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+cupsaddsmb.o: ../cups/transcode.h ../cups/thread-private.h
+cupsaddsmb.o: ../cups/adminutil.h
+cupsctl.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+cupsctl.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+cupsctl.o: ../cups/language.h ../cups/string-private.h ../config.h
+cupsctl.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+cupsctl.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+cupsctl.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+cupsctl.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+cupsctl.o: ../cups/thread-private.h ../cups/adminutil.h
+cupstestdsc.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+cupstestdsc.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+cupstestdsc.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+cupstestdsc.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+cupstestdsc.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+cupstestdsc.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+cupstestdsc.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+cupstestdsc.o: ../cups/transcode.h ../cups/thread-private.h
+cupstestppd.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+cupstestppd.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+cupstestppd.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+cupstestppd.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+cupstestppd.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+cupstestppd.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+cupstestppd.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+cupstestppd.o: ../cups/transcode.h ../cups/thread-private.h ../cups/dir.h
+cupstestppd.o: ../cups/ppd-private.h ../cups/raster.h ../cups/ppd.h
+lp.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+lp.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+lp.o: ../cups/language.h ../cups/string-private.h ../config.h
+lp.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+lp.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+lp.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+lp.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+lp.o: ../cups/thread-private.h
+lpadmin.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+lpadmin.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+lpadmin.o: ../cups/language.h ../cups/string-private.h ../config.h
+lpadmin.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+lpadmin.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+lpadmin.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+lpadmin.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+lpadmin.o: ../cups/thread-private.h
+lpinfo.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+lpinfo.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+lpinfo.o: ../cups/language.h ../cups/string-private.h ../config.h
+lpinfo.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+lpinfo.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+lpinfo.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+lpinfo.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+lpinfo.o: ../cups/thread-private.h
+lpmove.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+lpmove.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+lpmove.o: ../cups/language.h ../cups/string-private.h ../config.h
+lpmove.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+lpmove.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+lpmove.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+lpmove.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+lpmove.o: ../cups/thread-private.h
+lpoptions.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+lpoptions.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+lpoptions.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+lpoptions.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+lpoptions.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+lpoptions.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+lpoptions.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+lpoptions.o: ../cups/transcode.h ../cups/thread-private.h
+lppasswd.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+lppasswd.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+lppasswd.o: ../cups/language.h ../cups/string-private.h ../config.h
+lppasswd.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+lppasswd.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+lppasswd.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+lppasswd.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+lppasswd.o: ../cups/thread-private.h ../cups/md5-private.h
+lpstat.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+lpstat.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+lpstat.o: ../cups/language.h ../cups/string-private.h ../config.h
+lpstat.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+lpstat.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+lpstat.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+lpstat.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+lpstat.o: ../cups/thread-private.h
diff --git a/systemv/Makefile b/systemv/Makefile
new file mode 100644
index 000000000..06414a02d
--- /dev/null
+++ b/systemv/Makefile
@@ -0,0 +1,293 @@
+#
+# "$Id$"
+#
+# System V commands makefile for CUPS.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 1997-2006 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+TARGETS = cancel cupsaccept cupsaddsmb cupsctl cupstestdsc cupstestppd \
+ lp lpadmin lpinfo lpmove lpoptions lppasswd lpstat
+OBJS = cancel.o cupsaccept.o cupsaddsmb.o cupsctl.o cupstestdsc.o \
+ cupstestppd.o lp.o lpadmin.o lpinfo.o lpmove.o lpoptions.o \
+ lppasswd.o lpstat.o
+
+
+#
+# Make all targets...
+#
+
+all: $(TARGETS)
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Clean all object files...
+#
+
+clean:
+ $(RM) $(OBJS) $(TARGETS)
+ $(RM) accept cupsdisable cupsenable cupsreject reject
+
+
+#
+# Update dependencies (without system header dependencies...)
+#
+
+depend:
+ makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+
+
+#
+# Install programs...
+#
+
+install-exec:
+ echo Installing System V admin printing commands in $(SBINDIR)
+ $(INSTALL_DIR) -m 755 $(SBINDIR)
+ $(INSTALL_BIN) cupsaccept $(SBINDIR)
+ $(INSTALL_BIN) cupsaddsmb $(SBINDIR)
+ $(INSTALL_BIN) cupsctl $(SBINDIR)
+ $(INSTALL_BIN) lpadmin $(SBINDIR)
+ $(INSTALL_BIN) lpinfo $(SBINDIR)
+ $(INSTALL_BIN) lpmove $(SBINDIR)
+ $(RM) $(SBINDIR)/accept
+ $(LN) cupsaccept $(SBINDIR)/accept
+ $(RM) $(SBINDIR)/cupsdisable
+ $(LN) cupsaccept $(SBINDIR)/cupsdisable
+ $(RM) $(SBINDIR)/cupsenable
+ $(LN) cupsaccept $(SBINDIR)/cupsenable
+ $(RM) $(SBINDIR)/cupsreject
+ $(LN) cupsaccept $(SBINDIR)/cupsreject
+ $(RM) $(SBINDIR)/reject
+ $(LN) cupsaccept $(SBINDIR)/reject
+ echo Installing System V user printing commands in $(BINDIR)
+ $(INSTALL_DIR) -m 755 $(BINDIR)
+ $(INSTALL_BIN) cancel $(BINDIR)
+ $(INSTALL_BIN) cupstestdsc $(BINDIR)
+ $(INSTALL_BIN) cupstestppd $(BINDIR)
+ $(INSTALL_BIN) lp $(BINDIR)
+ $(INSTALL_BIN) lpoptions $(BINDIR)
+ $(INSTALL_BIN) lpstat $(BINDIR)
+ $(INSTALL_BIN) lppasswd $(BINDIR)
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ for file in $(TARGETS); do \
+ cp $$file $(SYMROOT); \
+ done \
+ fi
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall all targets...
+#
+
+uninstall:
+ $(RM) $(BINDIR)/cancel
+ $(RM) $(BINDIR)/cupstestdsc
+ $(RM) $(BINDIR)/cupstestppd
+ $(RM) $(BINDIR)/lp
+ $(RM) $(BINDIR)/lpoptions
+ $(RM) $(BINDIR)/lppasswd
+ $(RM) $(BINDIR)/lpstat
+ -$(RMDIR) $(BINDIR)
+ $(RM) $(SBINDIR)/accept
+ $(RM) $(SBINDIR)/cupsaccept
+ $(RM) $(SBINDIR)/cupsaddsmb
+ $(RM) $(SBINDIR)/cupsaccept
+ $(RM) $(SBINDIR)/cupsdisable
+ $(RM) $(SBINDIR)/cupsenable
+ $(RM) $(SBINDIR)/cupsreject
+ $(RM) $(SBINDIR)/lpadmin
+ $(RM) $(SBINDIR)/lpinfo
+ $(RM) $(SBINDIR)/lpmove
+ $(RM) $(SBINDIR)/reject
+ -$(RMDIR) $(SBINDIR)
+
+
+#
+# cancel
+#
+
+cancel: cancel.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cancel cancel.o $(LIBS)
+
+
+#
+# cupsaccept
+#
+
+cupsaccept: cupsaccept.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cupsaccept cupsaccept.o $(LIBS)
+ for file in accept cupsenable cupsdisable cupsreject reject; do \
+ $(RM) $$file; \
+ $(LN) cupsaccept $$file; \
+ done
+
+
+#
+# cupsaddsmb
+#
+
+cupsaddsmb: cupsaddsmb.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cupsaddsmb cupsaddsmb.o $(LIBS)
+
+
+#
+# cupsctl
+#
+
+cupsctl: cupsctl.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cupsctl cupsctl.o $(LIBS)
+
+
+#
+# cupstestdsc
+#
+
+cupstestdsc: cupstestdsc.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ cupstestdsc.o $(LIBS)
+
+
+#
+# cupstestppd
+#
+
+cupstestppd: cupstestppd.o ../cups/$(LIBCUPS) ../filter/$(LIBCUPSIMAGE)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ cupstestppd.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS)
+
+cupstestppd-static: cupstestppd.o ../cups/$(LIBCUPSSTATIC) ../filter/libcupsimage.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ cupstestppd.o ../filter/libcupsimage.a \
+ ../cups/$(LIBCUPSSTATIC) $(IMGLIBS) $(LIBGSSAPI) $(LIBS) $(LIBZ)
+
+
+#
+# lp
+#
+
+lp: lp.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lp lp.o $(LIBS)
+
+
+#
+# lpadmin
+#
+
+lpadmin: lpadmin.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpadmin lpadmin.o $(LIBZ) $(LIBS)
+
+
+#
+# lpinfo
+#
+
+lpinfo: lpinfo.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpinfo lpinfo.o $(LIBS)
+
+
+#
+# lpmove
+#
+
+lpmove: lpmove.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpmove lpmove.o $(LIBS)
+
+
+#
+# lpoptions
+#
+
+lpoptions: lpoptions.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpoptions lpoptions.o $(LIBZ) $(LIBS)
+
+
+#
+# lppasswd
+#
+
+lppasswd: lppasswd.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lppasswd lppasswd.o $(LIBZ) $(LIBS)
+
+
+#
+# lpstat
+#
+
+lpstat: lpstat.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o lpstat lpstat.o $(LIBS)
+
+
+#
+# Dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id$".
+#
diff --git a/systemv/cancel.c b/systemv/cancel.c
new file mode 100644
index 000000000..9307e1943
--- /dev/null
+++ b/systemv/cancel.c
@@ -0,0 +1,376 @@
+/*
+ * "$Id$"
+ *
+ * "cancel" command for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Parse options and cancel jobs.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * '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 */
+ int num_dests; /* Number of destinations */
+ cups_dest_t *dests; /* Destinations */
+ char *dest, /* Destination printer */
+ *job, /* Job ID pointer */
+ *user; /* Cancel jobs for a user */
+ int purge; /* Purge or cancel jobs? */
+ char uri[1024]; /* Printer or job URI */
+ ipp_t *request; /* IPP request */
+ ipp_t *response; /* IPP response */
+ ipp_op_t op; /* Operation */
+
+
+ _cupsSetLocale(argv);
+
+ /*
+ * Setup to cancel individual print jobs...
+ */
+
+ op = IPP_CANCEL_JOB;
+ purge = 0;
+ dest = NULL;
+ user = NULL;
+ http = NULL;
+ num_dests = 0;
+ dests = NULL;
+
+
+ /*
+ * Process command-line arguments...
+ */
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-' && argv[i][1])
+ switch (argv[i][1])
+ {
+ case 'E' : /* Encrypt */
+#ifdef HAVE_SSL
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+
+ if (http)
+ httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
+#else
+ _cupsLangPrintf(stderr,
+ _("%s: Sorry, no encryption support."), argv[0]);
+#endif /* HAVE_SSL */
+ break;
+
+ case 'U' : /* Username */
+ if (argv[i][2] != '\0')
+ cupsSetUser(argv[i] + 2);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected username after "
+ "\"-U\" option."), argv[0]);
+ return (1);
+ }
+
+ cupsSetUser(argv[i]);
+ }
+ break;
+
+ case 'a' : /* Cancel all jobs */
+ purge = 1;
+ op = IPP_PURGE_JOBS;
+ break;
+
+ case 'h' : /* Connect to host */
+ if (http != NULL)
+ {
+ httpClose(http);
+ http = NULL;
+ }
+
+ if (argv[i][2] != '\0')
+ cupsSetServer(argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected hostname after "
+ "\"-h\" option."), argv[0]);
+ return (1);
+ }
+ else
+ cupsSetServer(argv[i]);
+ }
+ break;
+
+ case 'u' : /* Username */
+ op = IPP_PURGE_JOBS;
+
+ if (argv[i][2] != '\0')
+ user = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected username after "
+ "\"-u\" option."), argv[0]);
+ return (1);
+ }
+ else
+ user = argv[i];
+ }
+ break;
+
+ default :
+ _cupsLangPrintf(stderr,
+ _("%s: Error - unknown option \"%c\"."),
+ argv[0], argv[i][1]);
+ return (1);
+ }
+ else
+ {
+ /*
+ * Cancel a job or printer...
+ */
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if (!strcmp(argv[i], "-"))
+ {
+ /*
+ * Delete the current job...
+ */
+
+ dest = "";
+ job_id = 0;
+ }
+ else if (cupsGetDest(argv[i], NULL, num_dests, dests) != NULL)
+ {
+ /*
+ * Delete the current job on the named destination...
+ */
+
+ dest = argv[i];
+ job_id = 0;
+ }
+ else if ((job = strrchr(argv[i], '-')) != NULL && isdigit(job[1] & 255))
+ {
+ /*
+ * Delete the specified job ID.
+ */
+
+ dest = NULL;
+ op = IPP_CANCEL_JOB;
+ job_id = atoi(job + 1);
+ }
+ else if (isdigit(argv[i][0] & 255))
+ {
+ /*
+ * Delete the specified job ID.
+ */
+
+ dest = NULL;
+ op = IPP_CANCEL_JOB;
+ job_id = atoi(argv[i]);
+ }
+ else
+ {
+ /*
+ * Bad printer name!
+ */
+
+ _cupsLangPrintf(stderr,
+ _("%s: Error - unknown destination \"%s\"."),
+ argv[0], argv[i]);
+ return (1);
+ }
+
+ /*
+ * For Solaris LP compatibility, ignore a destination name after
+ * cancelling a specific job ID...
+ */
+
+ if (job_id && (i + 1) < argc &&
+ cupsGetDest(argv[i + 1], NULL, num_dests, dests) != NULL)
+ i ++;
+
+ /*
+ * Open a connection to the server...
+ */
+
+ if (http == NULL)
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Unable to connect to server."), argv[0]);
+ return (1);
+ }
+
+ /*
+ * 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 = ippNewRequest(op);
+
+ if (dest)
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, 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);
+ }
+
+ if (user)
+ {
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+ ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
+ }
+ else
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, cupsUser());
+
+ if (op == IPP_PURGE_JOBS)
+ ippAddBoolean(request, IPP_TAG_OPERATION, "purge-jobs", purge);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if (op == IPP_PURGE_JOBS && (!user || _cups_strcasecmp(user, cupsUser())))
+ response = cupsDoRequest(http, request, "/admin/");
+ else
+ response = cupsDoRequest(http, request, "/jobs/");
+
+ if (response == NULL ||
+ response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, _("%s: %s failed: %s"), argv[0],
+ op == IPP_PURGE_JOBS ? "purge-jobs" : "cancel-job",
+ cupsLastErrorString());
+
+ if (response)
+ ippDelete(response);
+
+ return (1);
+ }
+
+ ippDelete(response);
+ }
+
+ if (num_dests == 0 && op == IPP_PURGE_JOBS)
+ {
+ /*
+ * Open a connection to the server...
+ */
+
+ if (http == NULL)
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ _cupsLangPrintf(stderr, _("%s: Unable to contact server."), argv[0]);
+ return (1);
+ }
+
+ /*
+ * 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 = ippNewRequest(op);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, "ipp://localhost/printers/");
+
+ if (user)
+ {
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+ ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
+ }
+ else
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, cupsUser());
+
+ ippAddBoolean(request, IPP_TAG_OPERATION, "purge-jobs", purge);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ response = cupsDoRequest(http, request, "/admin/");
+
+ if (response == NULL ||
+ response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, _("%s: %s failed: %s"), argv[0],
+ op == IPP_PURGE_JOBS ? "purge-jobs" : "cancel-job",
+ cupsLastErrorString());
+
+ if (response)
+ ippDelete(response);
+
+ return (1);
+ }
+
+ ippDelete(response);
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/cupsaccept.c b/systemv/cupsaccept.c
new file mode 100644
index 000000000..784138ee2
--- /dev/null
+++ b/systemv/cupsaccept.c
@@ -0,0 +1,239 @@
+/*
+ * "$Id$"
+ *
+ * "cupsaccept", "cupsdisable", "cupsenable", and "cupsreject" commands for
+ * CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Parse options and accept/reject jobs or disable/enable printers.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * 'main()' - Parse options and accept/reject jobs or disable/enable printers.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ char *command, /* Command to do */
+ uri[1024], /* Printer URI */
+ *reason; /* Reason for reject/disable */
+ ipp_t *request; /* IPP request */
+ ipp_op_t op; /* Operation */
+ int cancel; /* Cancel jobs? */
+
+
+ _cupsSetLocale(argv);
+
+ /*
+ * See what operation we're supposed to do...
+ */
+
+ if ((command = strrchr(argv[0], '/')) != NULL)
+ command ++;
+ else
+ command = argv[0];
+
+ cancel = 0;
+
+ if (!strcmp(command, "cupsaccept") || !strcmp(command, "accept"))
+ op = CUPS_ACCEPT_JOBS;
+ else if (!strcmp(command, "cupsreject") || !strcmp(command, "reject"))
+ op = CUPS_REJECT_JOBS;
+ else if (!strcmp(command, "cupsdisable") || !strcmp(command, "disable"))
+ op = IPP_PAUSE_PRINTER;
+ else if (!strcmp(command, "cupsenable") || !strcmp(command, "enable"))
+ op = IPP_RESUME_PRINTER;
+ else
+ {
+ _cupsLangPrintf(stderr, _("%s: Don't know what to do."), command);
+ return (1);
+ }
+
+ reason = NULL;
+
+ /*
+ * Process command-line arguments...
+ */
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'E' : /* Encrypt */
+#ifdef HAVE_SSL
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+#else
+ _cupsLangPrintf(stderr,
+ _("%s: Sorry, no encryption support."), command);
+#endif /* HAVE_SSL */
+ break;
+
+ case 'U' : /* Username */
+ if (argv[i][2] != '\0')
+ cupsSetUser(argv[i] + 2);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected username after "
+ "\"-U\" option."), command);
+ return (1);
+ }
+
+ cupsSetUser(argv[i]);
+ }
+ break;
+
+ case 'c' : /* Cancel jobs */
+ cancel = 1;
+ break;
+
+ case 'h' : /* Connect to host */
+ if (argv[i][2] != '\0')
+ cupsSetServer(argv[i] + 2);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected hostname after "
+ "\"-h\" option."), command);
+ return (1);
+ }
+
+ cupsSetServer(argv[i]);
+ }
+ break;
+
+ case 'r' : /* Reason for cancellation */
+ if (argv[i][2] != '\0')
+ reason = argv[i] + 2;
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected reason text after "
+ "\"-r\" option."), command);
+ return (1);
+ }
+
+ reason = argv[i];
+ }
+ break;
+
+ case '-' :
+ if (!strcmp(argv[i], "--hold"))
+ op = IPP_HOLD_NEW_JOBS;
+ else if (!strcmp(argv[i], "--release"))
+ op = IPP_RELEASE_HELD_NEW_JOBS;
+ else
+ {
+ _cupsLangPrintf(stderr, _("%s: Error - unknown option \"%s\"."),
+ command, argv[i]);
+ return (1);
+ }
+ break;
+
+ default :
+ _cupsLangPrintf(stderr, _("%s: Error - unknown option \"%c\"."),
+ command, argv[i][1]);
+ return (1);
+ }
+ }
+ else
+ {
+ /*
+ * Accept/disable/enable/reject a destination...
+ */
+
+ request = ippNewRequest(op);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/printers/%s", argv[i]);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, cupsUser());
+
+ if (reason != NULL)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
+ "printer-state-message", NULL, reason);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/admin/"));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Operation failed: %s"),
+ command, ippErrorString(cupsLastError()));
+ return (1);
+ }
+
+ /*
+ * Cancel all jobs if requested...
+ */
+
+ if (cancel)
+ {
+ /*
+ * Build an IPP_PURGE_JOBS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ request = ippNewRequest(IPP_PURGE_JOBS);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/admin/"));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
+ return (1);
+ }
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/cupsaddsmb.c b/systemv/cupsaddsmb.c
new file mode 100644
index 000000000..2f2c0e700
--- /dev/null
+++ b/systemv/cupsaddsmb.c
@@ -0,0 +1,303 @@
+/*
+ * "$Id$"
+ *
+ * "cupsaddsmb" command for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2001-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Export printers on the command-line.
+ * export_dest() - Export a destination to SAMBA.
+ * usage() - Show program usage and exit...
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include <cups/adminutil.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+/*
+ * Local globals...
+ */
+
+int Verbosity = 0;
+const char *SAMBAUser,
+ *SAMBAPassword,
+ *SAMBAServer;
+
+
+/*
+ * Local functions...
+ */
+
+int export_dest(http_t *http, const char *dest);
+void usage(void);
+
+
+/*
+ * 'main()' - Export printers on the command-line.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i, j; /* Looping vars */
+ int status; /* Status from export_dest() */
+ int export_all; /* Export all printers? */
+ http_t *http; /* Connection to server */
+ int num_dests; /* Number of printers */
+ cups_dest_t *dests; /* Printers */
+
+
+ _cupsSetLocale(argv);
+
+ /*
+ * Parse command-line arguments...
+ */
+
+ export_all = 0;
+ http = NULL;
+ SAMBAUser = cupsUser();
+ SAMBAPassword = NULL;
+ SAMBAServer = NULL;
+
+ for (i = 1; i < argc; i ++)
+ if (!strcmp(argv[i], "-E"))
+ {
+#ifdef HAVE_SSL
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+#else
+ _cupsLangPrintf(stderr,
+ _("%s: Sorry, no encryption support."),
+ argv[0]);
+#endif /* HAVE_SSL */
+ }
+ else if (!strcmp(argv[i], "-H"))
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ SAMBAServer = argv[i];
+ }
+ else if (!strcmp(argv[i], "-U"))
+ {
+ char *sep; /* Separator for password */
+
+
+ i ++;
+ if (i >= argc)
+ usage();
+
+ SAMBAUser = argv[i];
+
+ if ((sep = strchr(argv[i], '%')) != NULL)
+ {
+ /*
+ * Nul-terminate the username at the first % and point the
+ * password at the rest...
+ */
+
+ *sep++ = '\0';
+
+ SAMBAPassword = sep;
+ }
+ }
+ else if (!strcmp(argv[i], "-a"))
+ export_all = 1;
+ else if (!strcmp(argv[i], "-h"))
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ cupsSetServer(argv[i]);
+ }
+ else if (!strcmp(argv[i], "-v"))
+ Verbosity = 1;
+ else if (argv[i][0] != '-')
+ {
+ if (!http)
+ {
+ /*
+ * Connect to the server...
+ */
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ _cupsLangPrintf(stderr, _("%s: Unable to connect to server."),
+ argv[0]);
+ exit(1);
+ }
+ }
+
+ if (SAMBAServer == NULL)
+ {
+ SAMBAServer = cupsServer();
+
+ if (SAMBAServer[0] == '/') /* Use localhost instead of domain socket */
+ SAMBAServer = "localhost";
+ }
+
+ if ((status = export_dest(http, argv[i])) != 0)
+ return (status);
+ }
+ else
+ usage();
+
+ /*
+ * Connect to the server...
+ */
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ _cupsLangPrintf(stderr, _("%s: Unable to connect to server."), argv[0]);
+ exit(1);
+ }
+
+ /*
+ * See if the user specified "-a"...
+ */
+
+ if (export_all)
+ {
+ /*
+ * Export all printers...
+ */
+
+ if (SAMBAServer == NULL)
+ {
+ SAMBAServer = cupsServer();
+
+ if (SAMBAServer[0] == '/') /* Use localhost instead of domain socket */
+ SAMBAServer = "localhost";
+ }
+
+ num_dests = cupsGetDests2(http, &dests);
+
+ for (j = 0, status = 0; j < num_dests; j ++)
+ if (!dests[j].instance)
+ {
+ if ((status = export_dest(http, dests[j].name)) != 0)
+ break;
+ }
+
+ cupsFreeDests(num_dests, dests);
+
+ if (status)
+ return (status);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'export_dest()' - Export a destination to SAMBA.
+ */
+
+int /* O - 0 on success, non-zero on error */
+export_dest(http_t *http, /* I - Connection to server */
+ const char *dest) /* I - Destination to export */
+{
+ int status; /* Status of export */
+ char ppdfile[1024], /* PPD file for printer drivers */
+ prompt[1024]; /* Password prompt */
+ int tries; /* Number of tries */
+
+
+ /*
+ * Get the Windows PPD file for the printer...
+ */
+
+ if (!cupsAdminCreateWindowsPPD(http, dest, ppdfile, sizeof(ppdfile)))
+ {
+ _cupsLangPrintf(stderr,
+ _("cupsaddsmb: No PPD file for printer \"%s\" - %s"),
+ dest, cupsLastErrorString());
+ return (1);
+ }
+
+ /*
+ * Try to export it...
+ */
+
+ for (status = 0, tries = 0; !status && tries < 3; tries ++)
+ {
+ /*
+ * Get the password, as needed...
+ */
+
+ if (!SAMBAPassword)
+ {
+ snprintf(prompt, sizeof(prompt),
+ _cupsLangString(cupsLangDefault(),
+ _("Password for %s required to access %s via "
+ "SAMBA: ")),
+ SAMBAUser, SAMBAServer);
+
+ if ((SAMBAPassword = cupsGetPassword(prompt)) == NULL)
+ break;
+ }
+
+ status = cupsAdminExportSamba(dest, ppdfile, SAMBAServer,
+ SAMBAUser, SAMBAPassword,
+ Verbosity ? stderr : NULL);
+
+ if (!status && cupsLastError() == IPP_NOT_FOUND)
+ break;
+ }
+
+ unlink(ppdfile);
+
+ return (!status);
+}
+
+
+/*
+ * 'usage()' - Show program usage and exit...
+ */
+
+void
+usage(void)
+{
+ _cupsLangPuts(stdout, _("Usage: cupsaddsmb [options] printer1 ... printerN"));
+ _cupsLangPuts(stdout, _(" cupsaddsmb [options] -a"));
+ _cupsLangPuts(stdout, "");
+ _cupsLangPuts(stdout, _("Options:"));
+ _cupsLangPuts(stdout, _(" -E Encrypt the connection to "
+ "the server."));
+ _cupsLangPuts(stdout, _(" -H samba-server Use the named SAMBA "
+ "server."));
+ _cupsLangPuts(stdout, _(" -U samba-user Authenticate using the "
+ "named SAMBA user."));
+ _cupsLangPuts(stdout, _(" -a Export all printers."));
+ _cupsLangPuts(stdout, _(" -h cups-server Use the named CUPS "
+ "server."));
+ _cupsLangPuts(stdout, _(" -v Be verbose (show "
+ "commands)."));
+
+ exit(1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/cupsctl.c b/systemv/cupsctl.c
new file mode 100644
index 000000000..eabc6e479
--- /dev/null
+++ b/systemv/cupsctl.c
@@ -0,0 +1,235 @@
+/*
+ * "$Id$"
+ *
+ * Scheduler control program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2006-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Get/set server settings.
+ * usage() - Show program usage.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include <cups/adminutil.h>
+
+
+/*
+ * Local functions...
+ */
+
+static void usage(const char *opt);
+
+
+/*
+ * 'main()' - Get/set server settings.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i, /* Looping var */
+ num_settings; /* Number of settings */
+ cups_option_t *settings; /* Settings */
+ const char *opt; /* Current option character */
+ http_t *http; /* Connection to server */
+
+
+ /*
+ * Process the command-line...
+ */
+
+ _cupsSetLocale(argv);
+
+ num_settings = 0;
+ settings = NULL;
+
+ for (i = 1; i < argc; i ++)
+ {
+ if (argv[i][0] == '-')
+ {
+ if (argv[i][1] == '-')
+ {
+ if (!strcmp(argv[i], "--debug-logging"))
+ num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, "1",
+ num_settings, &settings);
+ else if (!strcmp(argv[i], "--no-debug-logging"))
+ num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, "0",
+ num_settings, &settings);
+ else if (!strcmp(argv[i], "--remote-admin"))
+ num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, "1",
+ num_settings, &settings);
+ else if (!strcmp(argv[i], "--no-remote-admin"))
+ num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, "0",
+ num_settings, &settings);
+ else if (!strcmp(argv[i], "--remote-any"))
+ num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY, "1",
+ num_settings, &settings);
+ else if (!strcmp(argv[i], "--no-remote-any"))
+ num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY, "0",
+ num_settings, &settings);
+ else if (!strcmp(argv[i], "--remote-printers"))
+ num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS, "1",
+ num_settings, &settings);
+ else if (!strcmp(argv[i], "--no-remote-printers"))
+ num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS, "0",
+ num_settings, &settings);
+ else if (!strcmp(argv[i], "--share-printers"))
+ num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, "1",
+ num_settings, &settings);
+ else if (!strcmp(argv[i], "--no-share-printers"))
+ num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, "0",
+ num_settings, &settings);
+ else if (!strcmp(argv[i], "--user-cancel-any"))
+ num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, "1",
+ num_settings, &settings);
+ else if (!strcmp(argv[i], "--no-user-cancel-any"))
+ num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, "0",
+ num_settings, &settings);
+ else
+ usage(argv[i]);
+ }
+ else
+ {
+ for (opt = argv[i] + 1; *opt; opt ++)
+ switch (*opt)
+ {
+ case 'E' :
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+ break;
+
+ case 'U' :
+ i ++;
+ if (i >= argc)
+ usage(NULL);
+
+ cupsSetUser(argv[i]);
+ break;
+
+ case 'h' :
+ i ++;
+ if (i >= argc)
+ usage(NULL);
+
+ cupsSetServer(argv[i]);
+ break;
+
+ default :
+ usage(opt);
+ break;
+ }
+ }
+ }
+ else if (strchr(argv[i], '='))
+ num_settings = cupsParseOptions(argv[i], num_settings, &settings);
+ else
+ usage(argv[i]);
+ }
+
+ if (cupsGetOption("Listen", num_settings, settings) ||
+ cupsGetOption("Port", num_settings, settings))
+ {
+ _cupsLangPuts(stderr, _("cupsctl: Cannot set Listen or Port directly."));
+ return (1);
+ }
+
+ /*
+ * Connect to the server using the defaults...
+ */
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ _cupsLangPrintf(stderr, _("cupsctl: Unable to connect to server: %s"),
+ strerror(errno));
+ return (1);
+ }
+
+ /*
+ * Set the current configuration if we have anything on the command-line...
+ */
+
+ if (num_settings > 0)
+ {
+ if (!cupsAdminSetServerSettings(http, num_settings, settings))
+ {
+ _cupsLangPrintf(stderr, "cupsctl: %s", cupsLastErrorString());
+ return (1);
+ }
+ }
+ else if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
+ {
+ _cupsLangPrintf(stderr, "cupsctl: %s", cupsLastErrorString());
+ return (1);
+ }
+ else
+ {
+ for (i = 0; i < num_settings; i ++)
+ _cupsLangPrintf(stdout, "%s=%s", settings[i].name, settings[i].value);
+ }
+
+ cupsFreeOptions(num_settings, settings);
+ return (0);
+}
+
+
+/*
+ * 'usage()' - Show program usage.
+ */
+
+static void
+usage(const char *opt) /* I - Option character/string */
+{
+ if (opt)
+ {
+ if (*opt == '-')
+ _cupsLangPrintf(stderr, _("cupsctl: Unknown option \"%s\""), opt);
+ else
+ _cupsLangPrintf(stderr, _("cupsctl: Unknown option \"-%c\""), *opt);
+ }
+
+ _cupsLangPuts(stdout, _("Usage: cupsctl [options] [param=value ... "
+ "paramN=valueN]"));
+ _cupsLangPuts(stdout, "");
+ _cupsLangPuts(stdout, _("Options:"));
+ _cupsLangPuts(stdout, "");
+ _cupsLangPuts(stdout, _(" -E Enable encryption."));
+ _cupsLangPuts(stdout, _(" -U username Specify username."));
+ _cupsLangPuts(stdout, _(" -h server[:port] Specify server "
+ "address."));
+ _cupsLangPuts(stdout, "");
+ _cupsLangPuts(stdout, _(" --[no-]debug-logging Turn debug logging "
+ "on/off."));
+ _cupsLangPuts(stdout, _(" --[no-]remote-admin Turn remote "
+ "administration on/off."));
+ _cupsLangPuts(stdout, _(" --[no-]remote-any Allow/prevent access "
+ "from the Internet."));
+ _cupsLangPuts(stdout, _(" --[no-]remote-printers Show/hide remote "
+ "printers."));
+ _cupsLangPuts(stdout, _(" --[no-]share-printers Turn printer sharing "
+ "on/off."));
+ _cupsLangPuts(stdout, _(" --[no-]user-cancel-any Allow/prevent users to "
+ "cancel any job."));
+
+ exit(1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/cupstestdsc.c b/systemv/cupstestdsc.c
new file mode 100644
index 000000000..ad04881ae
--- /dev/null
+++ b/systemv/cupstestdsc.c
@@ -0,0 +1,442 @@
+/*
+ * "$Id$"
+ *
+ * DSC test program for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2006 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * PostScript is a trademark of Adobe Systems, Inc.
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry for test program.
+ * check() - Check a file for conformance.
+ * usage() - Show program usage.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * Local functions...
+ */
+
+static int check_file(const char *filename);
+static void usage(void);
+
+
+/*
+ * 'main()' - Main entry for test program.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ int status; /* Status of tests */
+ int num_files; /* Number of files tested */
+
+
+ _cupsSetLocale(argv);
+
+ /*
+ * Collect command-line arguments...
+ */
+
+ for (i = 1, num_files = 0, status = 0; i < argc; i ++)
+ if (argv[i][0] == '-')
+ {
+ if (argv[i][1])
+ {
+ /*
+ * Currently the only supported option is "-h" (help)...
+ */
+
+ usage();
+ }
+ else
+ {
+ num_files ++;
+ status += check_file("(stdin)");
+ }
+ }
+ else
+ {
+ num_files ++;
+ status += check_file(argv[i]);
+ }
+
+ if (!num_files)
+ usage();
+
+ return (status);
+}
+
+
+/*
+ * 'check()' - Check a file for conformance.
+ */
+
+static int /* O - 0 on success, 1 on failure */
+check_file(const char *filename) /* I - File to read from */
+{
+ int i; /* Looping var */
+ cups_file_t *fp; /* File */
+ char line[1024]; /* Line from file */
+ int ch; /* Current character */
+ size_t bytes; /* Length of line */
+ int status; /* Status of test */
+ int linenum; /* Line number */
+ int binary; /* File contains binary data? */
+ float version; /* DSC version */
+ int lbrt[4]; /* Bounding box */
+ char page_label[256]; /* Page label string */
+ int page_number; /* Page number */
+ int last_page_number; /* Last page number seen */
+ int level; /* Embedded document level */
+ int saw_bounding_box, /* %%BoundingBox seen? */
+ saw_pages, /* %%Pages seen? */
+ saw_end_comments, /* %%EndComments seen? */
+ saw_begin_prolog, /* %%BeginProlog seen? */
+ saw_end_prolog, /* %%EndProlog seen? */
+ saw_begin_setup, /* %%BeginSetup seen? */
+ saw_end_setup, /* %%EndSetup seen? */
+ saw_page, /* %%Page seen? */
+ saw_trailer, /* %%Trailer seen? */
+ saw_long_line; /* Saw long lines? */
+
+
+ /*
+ * Open the file...
+ */
+
+ if (!strcmp(filename, "(stdin)"))
+ fp = cupsFileStdin();
+ else
+ fp = cupsFileOpen(filename, "r");
+
+ if (!fp)
+ {
+ perror(filename);
+ return (1);
+ }
+
+ /*
+ * Scan the file...
+ */
+
+ binary = 0;
+ last_page_number = 0;
+ level = 0;
+ linenum = 0;
+ saw_begin_prolog = 0;
+ saw_begin_setup = 0;
+ saw_bounding_box = 0;
+ saw_end_comments = 0;
+ saw_end_prolog = 0;
+ saw_end_setup = 0;
+ saw_long_line = 0;
+ saw_page = 0;
+ saw_pages = 0;
+ saw_trailer = 0;
+ status = 0;
+ version = 0.0f;
+
+ /* TODO: Fixme */
+ printf("%s: ", filename);
+ fflush(stdout);
+
+ while ((bytes = cupsFileGetLine(fp, line, sizeof(line))) > 0)
+ {
+ linenum ++;
+
+ if (bytes > 255)
+ {
+ if (!saw_long_line)
+ {
+ if (!status)
+ _cupsLangPuts(stdout, _("FAIL"));
+
+ status ++;
+ _cupsLangPrintf(stdout,
+ _(" Line %d is longer than 255 characters (%d).\n"
+ " REF: Page 25, Line Length"),
+ linenum, (int)bytes);
+ }
+
+ saw_long_line ++;
+ }
+
+ if (linenum == 1)
+ {
+ if (strncmp(line, "%!PS-Adobe-", 11))
+ {
+ if (!status)
+ _cupsLangPuts(stdout, _("FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" Missing %!PS-Adobe-3.0 on first line.\n"
+ " REF: Page 17, 3.1 Conforming Documents"));
+ cupsFileClose(fp);
+ return (1);
+ }
+ else
+ version = atof(line + 11);
+ }
+ else if (level > 0)
+ {
+ if (!strncmp(line, "%%BeginDocument:", 16))
+ level ++;
+ else if (!strncmp(line, "%%EndDocument", 13))
+ level --;
+ }
+ else if (saw_trailer)
+ {
+ if (!strncmp(line, "%%Pages:", 8))
+ {
+ if (atoi(line + 8) <= 0)
+ {
+ if (!status)
+ _cupsLangPuts(stdout, _("FAIL"));
+
+ status ++;
+ _cupsLangPrintf(stdout,
+ _(" Bad %%%%Pages: on line %d.\n"
+ " REF: Page 43, %%%%Pages:"),
+ linenum);
+ }
+ else
+ saw_pages = 1;
+ }
+ else if (!strncmp(line, "%%BoundingBox:", 14))
+ {
+ if (sscanf(line + 14, "%d%d%d%d", lbrt + 0, lbrt + 1, lbrt + 2,
+ lbrt + 3) != 4)
+ {
+ if (!status)
+ _cupsLangPuts(stdout, _("FAIL"));
+
+ status ++;
+ _cupsLangPrintf(stdout, _(" Bad %%%%BoundingBox: on line %d.\n"
+ " REF: Page 39, %%%%BoundingBox:"),
+ linenum);
+ }
+ else
+ saw_bounding_box = 1;
+ }
+ }
+ else if (!saw_end_comments)
+ {
+ if (!strncmp(line, "%%EndComments", 13))
+ saw_end_comments = 1;
+ else if (line[0] != '%')
+ saw_end_comments = -1;
+ else if (!strncmp(line, "%%Pages:", 8))
+ {
+ if (strstr(line + 8, "(atend)"))
+ saw_pages = -1;
+ else if (atoi(line + 8) <= 0)
+ {
+ if (!status)
+ _cupsLangPuts(stdout, _("FAIL"));
+
+ status ++;
+ _cupsLangPrintf(stdout, _(" Bad %%%%Pages: on line %d.\n"
+ " REF: Page 43, %%%%Pages:"),
+ linenum);
+ }
+ else
+ saw_pages = 1;
+ }
+ else if (!strncmp(line, "%%BoundingBox:", 14))
+ {
+ if (strstr(line, "(atend)"))
+ saw_bounding_box = -1;
+ else if (sscanf(line + 14, "%d%d%d%d", lbrt + 0, lbrt + 1, lbrt + 2,
+ lbrt + 3) != 4)
+ {
+ if (!status)
+ _cupsLangPuts(stdout, _("FAIL"));
+
+ status ++;
+ _cupsLangPrintf(stdout, _(" Bad %%%%BoundingBox: on line %d.\n"
+ " REF: Page 39, %%%%BoundingBox:"),
+ linenum);
+ }
+ else
+ saw_bounding_box = 1;
+ }
+ }
+ else if (saw_begin_prolog && !saw_end_prolog)
+ {
+ if (!strncmp(line, "%%EndProlog", 11))
+ saw_end_prolog = 1;
+ }
+ else if (saw_begin_setup && !saw_end_setup)
+ {
+ if (!strncmp(line, "%%EndSetup", 10))
+ saw_end_setup = 1;
+ }
+ else if (saw_end_comments)
+ {
+ if (!strncmp(line, "%%Page:", 7))
+ {
+ if (sscanf(line + 7, "%255s%d", page_label, &page_number) != 2 ||
+ page_number != (last_page_number + 1) || page_number < 1)
+ {
+ if (!status)
+ _cupsLangPuts(stdout, _("FAIL"));
+
+ status ++;
+ _cupsLangPrintf(stdout, _(" Bad %%%%Page: on line %d.\n"
+ " REF: Page 53, %%%%Page:"),
+ linenum);
+ }
+ else
+ {
+ last_page_number = page_number;
+ saw_page = 1;
+ }
+ }
+ else if (!strncmp(line, "%%BeginProlog", 13))
+ saw_begin_prolog = 1;
+ else if (!strncmp(line, "%%BeginSetup", 12))
+ saw_begin_setup = 1;
+ else if (!strncmp(line, "%%BeginDocument:", 16))
+ level ++;
+ else if (!strncmp(line, "%%EndDocument", 13))
+ level --;
+ else if (!strncmp(line, "%%Trailer", 9))
+ saw_trailer = 1;
+ }
+
+ for (i = 0; !binary && i < bytes; i ++)
+ {
+ ch = line[i];
+
+ if ((ch < ' ' || (ch & 0x80)) && ch != '\n' && ch != '\r' && ch != '\t')
+ binary = 1;
+ }
+ }
+
+ if (saw_bounding_box <= 0)
+ {
+ if (!status)
+ _cupsLangPuts(stdout, _("FAIL"));
+
+ status ++;
+ _cupsLangPuts(stdout, _(" Missing or bad %%BoundingBox: comment.\n"
+ " REF: Page 39, %%BoundingBox:"));
+ }
+
+ if (saw_pages <= 0)
+ {
+ if (!status)
+ _cupsLangPuts(stdout, _("FAIL"));
+
+ status ++;
+ _cupsLangPuts(stdout, _(" Missing or bad %%Pages: comment.\n"
+ " REF: Page 43, %%Pages:"));
+ }
+
+ if (!saw_end_comments)
+ {
+ if (!status)
+ _cupsLangPuts(stdout, _("FAIL"));
+
+ status ++;
+ _cupsLangPuts(stdout, _(" Missing %%EndComments comment."
+ " REF: Page 41, %%EndComments"));
+ }
+
+ if (!saw_page)
+ {
+ if (!status)
+ _cupsLangPuts(stdout, _("FAIL"));
+
+ status ++;
+ _cupsLangPuts(stdout, _(" Missing or bad %%Page: comments.\n"
+ " REF: Page 53, %%Page:"));
+ }
+
+ if (level < 0)
+ {
+ if (!status)
+ _cupsLangPuts(stdout, _("FAIL"));
+
+ status ++;
+ _cupsLangPuts(stdout, _(" Too many %%EndDocument comments."));
+ }
+ else if (level > 0)
+ {
+ if (!status)
+ _cupsLangPuts(stdout, _("FAIL"));
+
+ status ++;
+ _cupsLangPuts(stdout, _(" Too many %%BeginDocument comments."));
+ }
+
+ if (saw_long_line > 1)
+ _cupsLangPrintf(stderr,
+ _(" Saw %d lines that exceeded 255 characters."),
+ saw_long_line);
+
+ if (!status)
+ _cupsLangPuts(stdout, _("PASS"));
+
+ if (binary)
+ _cupsLangPuts(stdout, _(" Warning: file contains binary data."));
+
+ if (version < 3.0f)
+ _cupsLangPrintf(stdout,
+ _(" Warning: obsolete DSC version %.1f in file."),
+ version);
+
+ if (saw_end_comments < 0)
+ _cupsLangPuts(stdout, _(" Warning: no %%EndComments comment in file."));
+
+ cupsFileClose(fp);
+
+ return (status);
+}
+
+
+/*
+ * 'usage()' - Show program usage.
+ */
+
+static void
+usage(void)
+{
+ _cupsLangPuts(stdout, _("Usage: cupstestdsc [options] filename.ps [... "
+ "filename.ps]"));
+ _cupsLangPuts(stdout, _(" cupstestdsc [options] -"));
+ _cupsLangPuts(stdout, "");
+ _cupsLangPuts(stdout, _("Options:"));
+ _cupsLangPuts(stdout, "");
+ _cupsLangPuts(stdout, _(" -h Show program usage"));
+ _cupsLangPuts(stdout, "");
+ _cupsLangPuts(stdout, _("Note: this program only validates the DSC comments, "
+ "not the PostScript itself."));
+
+ exit(1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/cupstestppd.c b/systemv/cupstestppd.c
new file mode 100644
index 000000000..09cd39228
--- /dev/null
+++ b/systemv/cupstestppd.c
@@ -0,0 +1,3795 @@
+/*
+ * "$Id$"
+ *
+ * PPD test program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * PostScript is a trademark of Adobe Systems, Inc.
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry for test program.
+ * check_basics() - Check for CR LF, mixed line endings, and blank
+ * lines.
+ * check_constraints() - Check UIConstraints in the PPD file.
+ * check_case() - Check that there are no duplicate groups, options,
+ * or choices that differ only by case.
+ * check_defaults() - Check default option keywords in the PPD file.
+ * check_duplex() - Check duplex keywords in the PPD file.
+ * check_filters() - Check filters in the PPD file.
+ * check_profiles() - Check ICC color profiles in the PPD file.
+ * check_sizes() - Check media sizes in the PPD file.
+ * check_translations() - Check translations in the PPD file.
+ * show_conflicts() - Show option conflicts in a PPD file.
+ * test_raster() - Test PostScript commands for raster printers.
+ * usage() - Show program usage.
+ * valid_path() - Check whether a path has the correct capitalization.
+ * valid_utf8() - Check whether a string contains valid UTF-8 text.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include <cups/dir.h>
+#include <cups/ppd-private.h>
+#include <cups/raster.h>
+#include <math.h>
+#ifdef WIN32
+# define X_OK 0
+#endif /* WIN32 */
+
+
+/*
+ * Error warning overrides...
+ */
+
+enum
+{
+ WARN_NONE = 0,
+ WARN_CONSTRAINTS = 1,
+ WARN_DEFAULTS = 2,
+ WARN_FILTERS = 4,
+ WARN_PROFILES = 8,
+ WARN_TRANSLATIONS = 16,
+ WARN_DUPLEX = 32,
+ WARN_SIZES = 64,
+ WARN_FILENAME = 128,
+ WARN_ALL = 255
+};
+
+
+/*
+ * Error codes...
+ */
+
+enum
+{
+ ERROR_NONE = 0,
+ ERROR_USAGE,
+ ERROR_FILE_OPEN,
+ ERROR_PPD_FORMAT,
+ ERROR_CONFORMANCE
+};
+
+
+/*
+ * Line endings...
+ */
+
+enum
+{
+ EOL_NONE = 0,
+ EOL_CR,
+ EOL_LF,
+ EOL_CRLF
+};
+
+
+/*
+ * File permissions...
+ */
+
+#define MODE_WRITE 0022 /* Group/other write */
+#define MODE_MASK 0555 /* Owner/group/other read+exec/search */
+#define MODE_DATAFILE 0444 /* Owner/group/other read */
+#define MODE_DIRECTORY 0555 /* Owner/group/other read+search */
+#define MODE_PROGRAM 0555 /* Owner/group/other read+exec */
+
+
+/*
+ * Local functions...
+ */
+
+static void check_basics(const char *filename);
+static int check_constraints(ppd_file_t *ppd, int errors, int verbose,
+ int warn);
+static int check_case(ppd_file_t *ppd, int errors, int verbose);
+static int check_defaults(ppd_file_t *ppd, int errors, int verbose,
+ int warn);
+static int check_duplex(ppd_file_t *ppd, int errors, int verbose,
+ int warn);
+static int check_filters(ppd_file_t *ppd, const char *root, int errors,
+ int verbose, int warn);
+static int check_profiles(ppd_file_t *ppd, const char *root, int errors,
+ int verbose, int warn);
+static int check_sizes(ppd_file_t *ppd, int errors, int verbose, int warn);
+static int check_translations(ppd_file_t *ppd, int errors, int verbose,
+ int warn);
+static void show_conflicts(ppd_file_t *ppd, const char *prefix);
+static int test_raster(ppd_file_t *ppd, int verbose);
+static void usage(void);
+static int valid_path(const char *keyword, const char *path, int errors,
+ int verbose, int warn);
+static int valid_utf8(const char *s);
+
+
+/*
+ * 'main()' - Main entry for test program.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i, j, k, m, n; /* Looping vars */
+ int len; /* Length of option name */
+ char *opt; /* Option character */
+ const char *ptr; /* Pointer into string */
+ int files; /* Number of files */
+ int verbose; /* Want verbose output? */
+ int warn; /* Which errors to just warn about */
+ int ignore; /* Which errors to ignore */
+ int status; /* Exit status */
+ int errors; /* Number of conformance errors */
+ int ppdversion; /* PPD spec version in PPD file */
+ ppd_status_t error; /* Status of ppdOpen*() */
+ int line; /* Line number for error */
+ char *root; /* Root directory */
+ int xdpi, /* X resolution */
+ ydpi; /* Y resolution */
+ ppd_file_t *ppd; /* PPD file record */
+ ppd_attr_t *attr; /* PPD attribute */
+ ppd_size_t *size; /* Size record */
+ ppd_group_t *group; /* UI group */
+ ppd_option_t *option; /* Standard UI option */
+ ppd_group_t *group2; /* UI group */
+ ppd_option_t *option2; /* Standard UI option */
+ ppd_choice_t *choice; /* Standard UI option choice */
+ struct lconv *loc; /* Locale data */
+ static char *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
+ static char *sections[] = { "ANY", "DOCUMENT", "EXIT",
+ "JCL", "PAGE", "PROLOG" };
+
+
+ _cupsSetLocale(argv);
+ loc = localeconv();
+
+ /*
+ * Display PPD files for each file listed on the command-line...
+ */
+
+ ppdSetConformance(PPD_CONFORM_STRICT);
+
+ verbose = 0;
+ ppd = NULL;
+ files = 0;
+ status = ERROR_NONE;
+ root = "";
+ warn = WARN_NONE;
+ ignore = WARN_NONE;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-' && argv[i][1])
+ {
+ for (opt = argv[i] + 1; *opt; opt ++)
+ switch (*opt)
+ {
+ case 'I' : /* Ignore errors */
+ i ++;
+
+ if (i >= argc)
+ usage();
+
+ if (!strcmp(argv[i], "none"))
+ ignore = WARN_NONE;
+ else if (!strcmp(argv[i], "filename"))
+ ignore |= WARN_FILENAME;
+ else if (!strcmp(argv[i], "filters"))
+ ignore |= WARN_FILTERS;
+ else if (!strcmp(argv[i], "profiles"))
+ ignore |= WARN_PROFILES;
+ else if (!strcmp(argv[i], "all"))
+ ignore = WARN_FILTERS | WARN_PROFILES;
+ else
+ usage();
+ break;
+
+ case 'R' : /* Alternate root directory */
+ i ++;
+
+ if (i >= argc)
+ usage();
+
+ root = argv[i];
+ break;
+
+ case 'W' : /* Turn errors into warnings */
+ i ++;
+
+ if (i >= argc)
+ usage();
+
+ if (!strcmp(argv[i], "none"))
+ warn = WARN_NONE;
+ else if (!strcmp(argv[i], "constraints"))
+ warn |= WARN_CONSTRAINTS;
+ else if (!strcmp(argv[i], "defaults"))
+ warn |= WARN_DEFAULTS;
+ else if (!strcmp(argv[i], "duplex"))
+ warn |= WARN_DUPLEX;
+ else if (!strcmp(argv[i], "filters"))
+ warn |= WARN_FILTERS;
+ else if (!strcmp(argv[i], "profiles"))
+ warn |= WARN_PROFILES;
+ else if (!strcmp(argv[i], "sizes"))
+ warn |= WARN_SIZES;
+ else if (!strcmp(argv[i], "translations"))
+ warn |= WARN_TRANSLATIONS;
+ else if (!strcmp(argv[i], "all"))
+ warn = WARN_ALL;
+ else
+ usage();
+ break;
+
+ case 'q' : /* Quiet mode */
+ if (verbose > 0)
+ {
+ _cupsLangPuts(stderr,
+ _("cupstestppd: The -q option is incompatible "
+ "with the -v option."));
+ return (1);
+ }
+
+ verbose --;
+ break;
+
+ case 'r' : /* Relaxed mode */
+ ppdSetConformance(PPD_CONFORM_RELAXED);
+ break;
+
+ case 'v' : /* Verbose mode */
+ if (verbose < 0)
+ {
+ _cupsLangPuts(stderr,
+ _("cupstestppd: The -v option is incompatible "
+ "with the -q option."));
+ return (1);
+ }
+
+ verbose ++;
+ break;
+
+ default :
+ usage();
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Open the PPD file...
+ */
+
+ if (files && verbose >= 0)
+ puts("");
+
+ files ++;
+
+ if (argv[i][0] == '-')
+ {
+ /*
+ * Read from stdin...
+ */
+
+ ppd = ppdOpen(stdin);
+
+ if (verbose >= 0)
+ printf("%s:", (ppd && ppd->pcfilename) ? ppd->pcfilename : "(stdin)");
+ }
+ else
+ {
+ /*
+ * Read from a file...
+ */
+
+ if (verbose >= 0)
+ printf("%s:", argv[i]);
+
+ ppd = ppdOpenFile(argv[i]);
+ }
+
+ if (ppd == NULL)
+ {
+ error = ppdLastError(&line);
+
+ if (error <= PPD_ALLOC_ERROR)
+ {
+ status = ERROR_FILE_OPEN;
+
+ if (verbose >= 0)
+ {
+ _cupsLangPuts(stdout, _(" FAIL"));
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Unable to open PPD file - %s"),
+ strerror(errno));
+ }
+ }
+ else
+ {
+ status = ERROR_PPD_FORMAT;
+
+ if (verbose >= 0)
+ {
+ _cupsLangPuts(stdout, _(" FAIL"));
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Unable to open PPD file - "
+ "%s on line %d."),
+ ppdErrorString(error), line);
+
+ switch (error)
+ {
+ case PPD_MISSING_PPDADOBE4 :
+ _cupsLangPuts(stdout,
+ _(" REF: Page 42, section "
+ "5.2."));
+ break;
+ case PPD_MISSING_VALUE :
+ _cupsLangPuts(stdout,
+ _(" REF: Page 20, section "
+ "3.4."));
+ break;
+ case PPD_BAD_OPEN_GROUP :
+ case PPD_NESTED_OPEN_GROUP :
+ _cupsLangPuts(stdout,
+ _(" REF: Pages 45-46, section "
+ "5.2."));
+ break;
+ case PPD_BAD_OPEN_UI :
+ case PPD_NESTED_OPEN_UI :
+ _cupsLangPuts(stdout,
+ _(" REF: Pages 42-45, section "
+ "5.2."));
+ break;
+ case PPD_BAD_ORDER_DEPENDENCY :
+ _cupsLangPuts(stdout,
+ _(" REF: Pages 48-49, section "
+ "5.2."));
+ break;
+ case PPD_BAD_UI_CONSTRAINTS :
+ _cupsLangPuts(stdout,
+ _(" REF: Pages 52-54, section "
+ "5.2."));
+ break;
+ case PPD_MISSING_ASTERISK :
+ _cupsLangPuts(stdout,
+ _(" REF: Page 15, section "
+ "3.2."));
+ break;
+ case PPD_LINE_TOO_LONG :
+ _cupsLangPuts(stdout,
+ _(" REF: Page 15, section "
+ "3.1."));
+ break;
+ case PPD_ILLEGAL_CHARACTER :
+ _cupsLangPuts(stdout,
+ _(" REF: Page 15, section "
+ "3.1."));
+ break;
+ case PPD_ILLEGAL_MAIN_KEYWORD :
+ _cupsLangPuts(stdout,
+ _(" REF: Pages 16-17, section "
+ "3.2."));
+ break;
+ case PPD_ILLEGAL_OPTION_KEYWORD :
+ _cupsLangPuts(stdout,
+ _(" REF: Page 19, section "
+ "3.3."));
+ break;
+ case PPD_ILLEGAL_TRANSLATION :
+ _cupsLangPuts(stdout,
+ _(" REF: Page 27, section "
+ "3.5."));
+ break;
+ default :
+ break;
+ }
+
+ check_basics(argv[i]);
+ }
+ }
+
+ continue;
+ }
+
+ /*
+ * Show the header and then perform basic conformance tests (limited
+ * only by what the CUPS PPD functions actually load...)
+ */
+
+ errors = 0;
+ ppdversion = 43;
+
+ if (verbose > 0)
+ _cupsLangPuts(stdout,
+ _("\n DETAILED CONFORMANCE TEST RESULTS"));
+
+ if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL &&
+ attr->value)
+ ppdversion = (int)(10 * _cupsStrScand(attr->value, NULL, loc) + 0.5);
+
+ for (j = 0; j < ppd->num_filters; j ++)
+ if (strstr(ppd->filters[j], "application/vnd.cups-raster"))
+ {
+ if (!test_raster(ppd, verbose))
+ errors ++;
+ break;
+ }
+
+ /*
+ * Look for default keywords with no matching option...
+ */
+
+ if (!(warn & WARN_DEFAULTS))
+ errors = check_defaults(ppd, errors, verbose, 0);
+
+ if ((attr = ppdFindAttr(ppd, "DefaultImageableArea", NULL)) == NULL)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED DefaultImageableArea\n"
+ " REF: Page 102, section 5.15."));
+ }
+
+ errors ++;
+ }
+ else if (ppdPageSize(ppd, attr->value) == NULL &&
+ strcmp(attr->value, "Unknown"))
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** BAD DefaultImageableArea %s\n"
+ " REF: Page 102, section 5.15."),
+ attr->value);
+ }
+
+ errors ++;
+ }
+ else
+ {
+ if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS DefaultImageableArea"));
+ }
+
+ if ((attr = ppdFindAttr(ppd, "DefaultPaperDimension", NULL)) == NULL)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED DefaultPaperDimension\n"
+ " REF: Page 103, section 5.15."));
+ }
+
+ errors ++;
+ }
+ else if (ppdPageSize(ppd, attr->value) == NULL &&
+ strcmp(attr->value, "Unknown"))
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** BAD DefaultPaperDimension %s\n"
+ " REF: Page 103, section 5.15."),
+ attr->value);
+ }
+
+ errors ++;
+ }
+ else if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS DefaultPaperDimension"));
+
+ for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
+ for (k = 0, option = group->options;
+ k < group->num_options;
+ k ++, option ++)
+ {
+ /*
+ * Verify that we have a default choice...
+ */
+
+ if (option->defchoice[0])
+ {
+ if (ppdFindChoice(option, option->defchoice) == NULL &&
+ strcmp(option->defchoice, "Unknown"))
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** BAD Default%s %s\n"
+ " REF: Page 40, section 4.5."),
+ option->keyword, option->defchoice);
+ }
+
+ errors ++;
+ }
+ else if (verbose > 0)
+ _cupsLangPrintf(stdout,
+ _(" PASS Default%s"),
+ option->keyword);
+ }
+ else
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** REQUIRED Default%s\n"
+ " REF: Page 40, section 4.5."),
+ option->keyword);
+ }
+
+ errors ++;
+ }
+ }
+
+ if ((attr = ppdFindAttr(ppd, "FileVersion", NULL)) != NULL)
+ {
+ for (ptr = attr->value; *ptr; ptr ++)
+ if (!isdigit(*ptr & 255) && *ptr != '.')
+ break;
+
+ if (*ptr)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Bad FileVersion \"%s\"\n"
+ " REF: Page 56, section 5.3."),
+ attr->value);
+ }
+
+ errors ++;
+ }
+ else if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS FileVersion"));
+ }
+ else
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED FileVersion\n"
+ " REF: Page 56, section 5.3."));
+ }
+
+ errors ++;
+ }
+
+ if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL)
+ {
+ ptr = attr->value;
+ if (*ptr == '4' && ptr[1] == '.')
+ {
+
+ for (ptr += 2; *ptr; ptr ++)
+ if (!isdigit(*ptr & 255))
+ break;
+ }
+
+ if (*ptr)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Bad FormatVersion \"%s\"\n"
+ " REF: Page 56, section 5.3."),
+ attr->value);
+ }
+
+ errors ++;
+ }
+ else if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS FormatVersion"));
+ }
+ else
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED FormatVersion\n"
+ " REF: Page 56, section 5.3."));
+ }
+
+ errors ++;
+ }
+
+ if (ppd->lang_encoding != NULL)
+ {
+ if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS LanguageEncoding"));
+ }
+ else if (ppdversion > 40)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED LanguageEncoding\n"
+ " REF: Pages 56-57, section 5.3."));
+ }
+
+ errors ++;
+ }
+
+ if (ppd->lang_version != NULL)
+ {
+ if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS LanguageVersion"));
+ }
+ else
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED LanguageVersion\n"
+ " REF: Pages 57-58, section 5.3."));
+ }
+
+ errors ++;
+ }
+
+ if (ppd->manufacturer != NULL)
+ {
+ if (!_cups_strncasecmp(ppd->manufacturer, "Hewlett-Packard", 15) ||
+ !_cups_strncasecmp(ppd->manufacturer, "Hewlett Packard", 15))
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** BAD Manufacturer (should be "
+ "\"HP\")\n"
+ " REF: Page 211, table D.1."));
+ }
+
+ errors ++;
+ }
+ else if (!_cups_strncasecmp(ppd->manufacturer, "OkiData", 7) ||
+ !_cups_strncasecmp(ppd->manufacturer, "Oki Data", 8))
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** BAD Manufacturer (should be "
+ "\"Oki\")\n"
+ " REF: Page 211, table D.1."));
+ }
+
+ errors ++;
+ }
+ else if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS Manufacturer"));
+ }
+ else if (ppdversion >= 43)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED Manufacturer\n"
+ " REF: Pages 58-59, section 5.3."));
+ }
+
+ errors ++;
+ }
+
+ if (ppd->modelname != NULL)
+ {
+ for (ptr = ppd->modelname; *ptr; ptr ++)
+ if (!isalnum(*ptr & 255) && !strchr(" ./-+", *ptr))
+ break;
+
+ if (*ptr)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** BAD ModelName - \"%c\" not "
+ "allowed in string.\n"
+ " REF: Pages 59-60, section 5.3."),
+ *ptr);
+ }
+
+ errors ++;
+ }
+ else if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS ModelName"));
+ }
+ else
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED ModelName\n"
+ " REF: Pages 59-60, section 5.3."));
+ }
+
+ errors ++;
+ }
+
+ if (ppd->nickname != NULL)
+ {
+ if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS NickName"));
+ }
+ else
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED NickName\n"
+ " REF: Page 60, section 5.3."));
+ }
+
+ errors ++;
+ }
+
+ if (ppdFindOption(ppd, "PageSize") != NULL)
+ {
+ if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS PageSize"));
+ }
+ else
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED PageSize\n"
+ " REF: Pages 99-100, section 5.14."));
+ }
+
+ errors ++;
+ }
+
+ if (ppdFindOption(ppd, "PageRegion") != NULL)
+ {
+ if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS PageRegion"));
+ }
+ else
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED PageRegion\n"
+ " REF: Page 100, section 5.14."));
+ }
+
+ errors ++;
+ }
+
+ if (ppd->pcfilename != NULL)
+ {
+ if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS PCFileName"));
+ }
+ else if (!(ignore & WARN_FILENAME))
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED PCFileName\n"
+ " REF: Pages 61-62, section 5.3."));
+ }
+
+ errors ++;
+ }
+
+ if (ppd->product != NULL)
+ {
+ if (ppd->product[0] != '(' ||
+ ppd->product[strlen(ppd->product) - 1] != ')')
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** BAD Product - not \"(string)\".\n"
+ " REF: Page 62, section 5.3."));
+ }
+
+ errors ++;
+ }
+ else if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS Product"));
+ }
+ else
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED Product\n"
+ " REF: Page 62, section 5.3."));
+ }
+
+ errors ++;
+ }
+
+ if ((attr = ppdFindAttr(ppd, "PSVersion", NULL)) != NULL &&
+ attr->value != NULL)
+ {
+ char junkstr[255]; /* Temp string */
+ int junkint; /* Temp integer */
+
+
+ if (sscanf(attr->value, "(%[^)])%d", junkstr, &junkint) != 2)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** BAD PSVersion - not \"(string) "
+ "int\".\n"
+ " REF: Pages 62-64, section 5.3."));
+ }
+
+ errors ++;
+ }
+ else if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS PSVersion"));
+ }
+ else
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED PSVersion\n"
+ " REF: Pages 62-64, section 5.3."));
+ }
+
+ errors ++;
+ }
+
+ if (ppd->shortnickname != NULL)
+ {
+ if (strlen(ppd->shortnickname) > 31)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** BAD ShortNickName - longer "
+ "than 31 chars.\n"
+ " REF: Pages 64-65, section 5.3."));
+ }
+
+ errors ++;
+ }
+ else if (verbose > 0)
+ _cupsLangPuts(stdout, _(" PASS ShortNickName"));
+ }
+ else if (ppdversion >= 43)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED ShortNickName\n"
+ " REF: Page 64-65, section 5.3."));
+ }
+
+ errors ++;
+ }
+
+ if (ppd->patches != NULL && strchr(ppd->patches, '\"') &&
+ strstr(ppd->patches, "*End"))
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** BAD JobPatchFile attribute in file\n"
+ " REF: Page 24, section 3.4."));
+ }
+
+ errors ++;
+ }
+
+ /*
+ * Check for page sizes without the corresponding ImageableArea or
+ * PaperDimension values...
+ */
+
+ if (ppd->num_sizes == 0)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** REQUIRED PageSize\n"
+ " REF: Page 41, section 5.\n"
+ " REF: Page 99, section 5.14."));
+ }
+
+ errors ++;
+ }
+ else
+ {
+ for (j = 0, size = ppd->sizes; j < ppd->num_sizes; j ++, size ++)
+ {
+ /*
+ * Don't check custom size...
+ */
+
+ if (!strcmp(size->name, "Custom"))
+ continue;
+
+ /*
+ * Check for ImageableArea...
+ */
+
+ if (size->left == 0.0 && size->bottom == 0.0 &&
+ size->right == 0.0 && size->top == 0.0)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** REQUIRED ImageableArea for "
+ "PageSize %s\n"
+ " REF: Page 41, section 5.\n"
+ " REF: Page 102, section 5.15."),
+ size->name);
+ }
+
+ errors ++;
+ }
+
+ /*
+ * Check for PaperDimension...
+ */
+
+ if (size->width == 0.0 && size->length == 0.0)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** REQUIRED PaperDimension "
+ "for PageSize %s\n"
+ " REF: Page 41, section 5.\n"
+ " REF: Page 103, section 5.15."),
+ size->name);
+ }
+
+ errors ++;
+ }
+ }
+ }
+
+ /*
+ * Check for valid Resolution, JCLResolution, or SetResolution values...
+ */
+
+ if ((option = ppdFindOption(ppd, "Resolution")) == NULL)
+ if ((option = ppdFindOption(ppd, "JCLResolution")) == NULL)
+ option = ppdFindOption(ppd, "SetResolution");
+
+ if (option != NULL)
+ {
+ for (j = option->num_choices, choice = option->choices;
+ j > 0;
+ j --, choice ++)
+ {
+ /*
+ * Verify that all resolution options are of the form NNNdpi
+ * or NNNxNNNdpi...
+ */
+
+ xdpi = strtol(choice->choice, (char **)&ptr, 10);
+ if (ptr > choice->choice && xdpi > 0)
+ {
+ if (*ptr == 'x')
+ ydpi = strtol(ptr + 1, (char **)&ptr, 10);
+ else
+ ydpi = xdpi;
+ }
+ else
+ ydpi = xdpi;
+
+ if (xdpi <= 0 || xdpi > 99999 || ydpi <= 0 || ydpi > 99999 ||
+ strcmp(ptr, "dpi"))
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Bad %s choice %s\n"
+ " REF: Page 84, section 5.9"),
+ option->keyword, choice->choice);
+ }
+
+ errors ++;
+ }
+ }
+ }
+
+ if ((attr = ppdFindAttr(ppd, "1284DeviceID", NULL)) &&
+ strcmp(attr->name, "1284DeviceID"))
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** %s must be 1284DeviceID\n"
+ " REF: Page 72, section 5.5"),
+ attr->name);
+ }
+
+ errors ++;
+ }
+
+ errors = check_case(ppd, errors, verbose);
+
+ if (!(warn & WARN_CONSTRAINTS))
+ errors = check_constraints(ppd, errors, verbose, 0);
+
+ if (!(warn & WARN_FILTERS) && !(ignore & WARN_FILTERS))
+ errors = check_filters(ppd, root, errors, verbose, 0);
+
+ if (!(warn & WARN_PROFILES) && !(ignore & WARN_PROFILES))
+ errors = check_profiles(ppd, root, errors, verbose, 0);
+
+ if (!(warn & WARN_SIZES))
+ errors = check_sizes(ppd, errors, verbose, 0);
+
+ if (!(warn & WARN_TRANSLATIONS))
+ errors = check_translations(ppd, errors, verbose, 0);
+
+ if (!(warn & WARN_DUPLEX))
+ errors = check_duplex(ppd, errors, verbose, 0);
+
+ if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL &&
+ attr->value)
+ {
+ /*
+ * This file contains localizations, check for conformance of the
+ * base translation...
+ */
+
+ if ((attr = ppdFindAttr(ppd, "LanguageEncoding", NULL)) != NULL)
+ {
+ if (!attr->value || strcmp(attr->value, "ISOLatin1"))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Bad LanguageEncoding %s - "
+ "must be ISOLatin1."),
+ attr->value ? attr->value : "(null)");
+
+ errors ++;
+ }
+
+ if (!ppd->lang_version || strcmp(ppd->lang_version, "English"))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Bad LanguageVersion %s - "
+ "must be English."),
+ ppd->lang_version ? ppd->lang_version : "(null)");
+
+ errors ++;
+ }
+
+ /*
+ * Loop through all options and choices...
+ */
+
+ for (option = ppdFirstOption(ppd);
+ option;
+ option = ppdNextOption(ppd))
+ {
+ /*
+ * Check for special characters outside A0 to BF, F7, or F8
+ * that are used for languages other than English.
+ */
+
+ for (ptr = option->text; *ptr; ptr ++)
+ if ((*ptr & 0x80) && (*ptr & 0xe0) != 0xa0 &&
+ (*ptr & 0xff) != 0xf7 && (*ptr & 0xff) != 0xf8)
+ break;
+
+ if (*ptr)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Default translation "
+ "string for option %s contains 8-bit "
+ "characters."),
+ option->keyword);
+
+ errors ++;
+ }
+
+ for (j = 0; j < option->num_choices; j ++)
+ {
+ /*
+ * Check for special characters outside A0 to BF, F7, or F8
+ * that are used for languages other than English.
+ */
+
+ for (ptr = option->choices[j].text; *ptr; ptr ++)
+ if ((*ptr & 0x80) && (*ptr & 0xe0) != 0xa0 &&
+ (*ptr & 0xff) != 0xf7 && (*ptr & 0xff) != 0xf8)
+ break;
+
+ if (*ptr)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Default translation "
+ "string for option %s choice %s contains "
+ "8-bit characters."),
+ option->keyword,
+ option->choices[j].choice);
+
+ errors ++;
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Final pass/fail notification...
+ */
+
+ if (errors)
+ status = ERROR_CONFORMANCE;
+ else if (!verbose)
+ _cupsLangPuts(stdout, _(" PASS"));
+
+ if (verbose >= 0)
+ {
+ check_basics(argv[i]);
+
+ if (warn & WARN_DEFAULTS)
+ errors = check_defaults(ppd, errors, verbose, 1);
+
+ if (warn & WARN_CONSTRAINTS)
+ errors = check_constraints(ppd, errors, verbose, 1);
+
+ if ((warn & WARN_FILTERS) && !(ignore & WARN_FILTERS))
+ errors = check_filters(ppd, root, errors, verbose, 1);
+
+ if ((warn & WARN_PROFILES) && !(ignore & WARN_PROFILES))
+ errors = check_profiles(ppd, root, errors, verbose, 1);
+
+ if (warn & WARN_SIZES)
+ errors = check_sizes(ppd, errors, verbose, 1);
+ else
+ errors = check_sizes(ppd, errors, verbose, 2);
+
+ if (warn & WARN_TRANSLATIONS)
+ errors = check_translations(ppd, errors, verbose, 1);
+
+ if (warn & WARN_DUPLEX)
+ errors = check_duplex(ppd, errors, verbose, 1);
+
+ /*
+ * Look for legacy duplex keywords...
+ */
+
+ if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL)
+ if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
+ option = ppdFindOption(ppd, "KD03Duplex");
+
+ if (option)
+ _cupsLangPrintf(stdout,
+ _(" WARN Duplex option keyword %s may not "
+ "work as expected and should be named Duplex.\n"
+ " REF: Page 122, section 5.17"),
+ option->keyword);
+
+ /*
+ * Look for default keywords with no corresponding option...
+ */
+
+ for (j = 0; j < ppd->num_attrs; j ++)
+ {
+ attr = ppd->attrs[j];
+
+ if (!strcmp(attr->name, "DefaultColorSpace") ||
+ !strcmp(attr->name, "DefaultColorSep") ||
+ !strcmp(attr->name, "DefaultFont") ||
+ !strcmp(attr->name, "DefaultHalftoneType") ||
+ !strcmp(attr->name, "DefaultImageableArea") ||
+ !strcmp(attr->name, "DefaultLeadingEdge") ||
+ !strcmp(attr->name, "DefaultOutputOrder") ||
+ !strcmp(attr->name, "DefaultPaperDimension") ||
+ !strcmp(attr->name, "DefaultResolution") ||
+ !strcmp(attr->name, "DefaultScreenProc") ||
+ !strcmp(attr->name, "DefaultTransfer"))
+ continue;
+
+ if (!strncmp(attr->name, "Default", 7) &&
+ !ppdFindOption(ppd, attr->name + 7))
+ _cupsLangPrintf(stdout,
+ _(" WARN %s has no corresponding "
+ "options."),
+ attr->name);
+ }
+
+ if (ppdversion < 43)
+ {
+ _cupsLangPrintf(stdout,
+ _(" WARN Obsolete PPD version %.1f.\n"
+ " REF: Page 42, section 5.2."),
+ 0.1f * ppdversion);
+ }
+
+ if (!ppd->lang_encoding && ppdversion < 41)
+ {
+ _cupsLangPuts(stdout,
+ _(" WARN LanguageEncoding required by PPD "
+ "4.3 spec.\n"
+ " REF: Pages 56-57, section 5.3."));
+ }
+
+ if (!ppd->manufacturer && ppdversion < 43)
+ {
+ _cupsLangPuts(stdout,
+ _(" WARN Manufacturer required by PPD "
+ "4.3 spec.\n"
+ " REF: Pages 58-59, section 5.3."));
+ }
+
+ /*
+ * Treat a PCFileName attribute longer than 12 characters as
+ * a warning and not a hard error...
+ */
+
+ if (!(ignore & WARN_FILENAME) && ppd->pcfilename)
+ {
+ if (strlen(ppd->pcfilename) > 12)
+ {
+ _cupsLangPuts(stdout,
+ _(" WARN PCFileName longer than 8.3 in "
+ "violation of PPD spec.\n"
+ " REF: Pages 61-62, section "
+ "5.3."));
+ }
+
+ if (!_cups_strcasecmp(ppd->pcfilename, "unused.ppd"))
+ _cupsLangPuts(stdout,
+ _(" WARN PCFileName should contain a "
+ "unique filename.\n"
+ " REF: Pages 61-62, section "
+ "5.3."));
+ }
+
+ if (!ppd->shortnickname && ppdversion < 43)
+ {
+ _cupsLangPuts(stdout,
+ _(" WARN ShortNickName required by PPD "
+ "4.3 spec.\n"
+ " REF: Pages 64-65, section 5.3."));
+ }
+
+ /*
+ * Check the Protocols line and flag PJL + BCP since TBCP is
+ * usually used with PJL...
+ */
+
+ if (ppd->protocols)
+ {
+ if (strstr(ppd->protocols, "PJL") &&
+ strstr(ppd->protocols, "BCP") &&
+ !strstr(ppd->protocols, "TBCP"))
+ {
+ _cupsLangPuts(stdout,
+ _(" WARN Protocols contains both PJL "
+ "and BCP; expected TBCP.\n"
+ " REF: Pages 78-79, section 5.7."));
+ }
+
+ if (strstr(ppd->protocols, "PJL") &&
+ (!ppd->jcl_begin || !ppd->jcl_end || !ppd->jcl_ps))
+ {
+ _cupsLangPuts(stdout,
+ _(" WARN Protocols contains PJL but JCL "
+ "attributes are not set.\n"
+ " REF: Pages 78-79, section 5.7."));
+ }
+ }
+
+ /*
+ * Check for options with a common prefix, e.g. Duplex and Duplexer,
+ * which are errors according to the spec but won't cause problems
+ * with CUPS specifically...
+ */
+
+ for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
+ for (k = 0, option = group->options;
+ k < group->num_options;
+ k ++, option ++)
+ {
+ len = (int)strlen(option->keyword);
+
+ for (m = 0, group2 = ppd->groups;
+ m < ppd->num_groups;
+ m ++, group2 ++)
+ for (n = 0, option2 = group2->options;
+ n < group2->num_options;
+ n ++, option2 ++)
+ if (option != option2 &&
+ len < (int)strlen(option2->keyword) &&
+ !strncmp(option->keyword, option2->keyword, len))
+ {
+ _cupsLangPrintf(stdout,
+ _(" WARN %s shares a common "
+ "prefix with %s\n"
+ " REF: Page 15, section "
+ "3.2."),
+ option->keyword, option2->keyword);
+ }
+ }
+ }
+
+ if (verbose > 0)
+ {
+ if (errors)
+ _cupsLangPrintf(stdout, _(" %d ERRORS FOUND"), errors);
+ else
+ _cupsLangPuts(stdout, _(" NO ERRORS FOUND"));
+ }
+
+ /*
+ * Then list the options, if "-v" was provided...
+ */
+
+ if (verbose > 1)
+ {
+ _cupsLangPrintf(stdout,
+ "\n"
+ " language_level = %d\n"
+ " color_device = %s\n"
+ " variable_sizes = %s\n"
+ " landscape = %d",
+ ppd->language_level,
+ ppd->color_device ? "TRUE" : "FALSE",
+ ppd->variable_sizes ? "TRUE" : "FALSE",
+ ppd->landscape);
+
+ switch (ppd->colorspace)
+ {
+ case PPD_CS_CMYK :
+ _cupsLangPuts(stdout, " colorspace = PPD_CS_CMYK");
+ break;
+ case PPD_CS_CMY :
+ _cupsLangPuts(stdout, " colorspace = PPD_CS_CMY");
+ break;
+ case PPD_CS_GRAY :
+ _cupsLangPuts(stdout, " colorspace = PPD_CS_GRAY");
+ break;
+ case PPD_CS_RGB :
+ _cupsLangPuts(stdout, " colorspace = PPD_CS_RGB");
+ break;
+ default :
+ _cupsLangPuts(stdout, " colorspace = <unknown>");
+ break;
+ }
+
+ _cupsLangPrintf(stdout, " num_emulations = %d",
+ ppd->num_emulations);
+ for (j = 0; j < ppd->num_emulations; j ++)
+ _cupsLangPrintf(stdout, " emulations[%d] = %s",
+ j, ppd->emulations[j].name);
+
+ _cupsLangPrintf(stdout, " lang_encoding = %s",
+ ppd->lang_encoding);
+ _cupsLangPrintf(stdout, " lang_version = %s",
+ ppd->lang_version);
+ _cupsLangPrintf(stdout, " modelname = %s", ppd->modelname);
+ _cupsLangPrintf(stdout, " ttrasterizer = %s",
+ ppd->ttrasterizer == NULL ? "None" : ppd->ttrasterizer);
+ _cupsLangPrintf(stdout, " manufacturer = %s",
+ ppd->manufacturer);
+ _cupsLangPrintf(stdout, " product = %s", ppd->product);
+ _cupsLangPrintf(stdout, " nickname = %s", ppd->nickname);
+ _cupsLangPrintf(stdout, " shortnickname = %s",
+ ppd->shortnickname);
+ _cupsLangPrintf(stdout, " patches = %d bytes",
+ ppd->patches == NULL ? 0 : (int)strlen(ppd->patches));
+
+ _cupsLangPrintf(stdout, " num_groups = %d", ppd->num_groups);
+ for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
+ {
+ _cupsLangPrintf(stdout, " group[%d] = %s",
+ j, group->text);
+
+ for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
+ {
+ _cupsLangPrintf(stdout,
+ " options[%d] = %s (%s) %s %s %.0f "
+ "(%d choices)",
+ k, option->keyword, option->text, uis[option->ui],
+ sections[option->section], option->order,
+ option->num_choices);
+
+ if (!strcmp(option->keyword, "PageSize") ||
+ !strcmp(option->keyword, "PageRegion"))
+ {
+ for (m = option->num_choices, choice = option->choices;
+ m > 0;
+ m --, choice ++)
+ {
+ size = ppdPageSize(ppd, choice->choice);
+
+ if (size == NULL)
+ _cupsLangPrintf(stdout,
+ " %s (%s) = ERROR%s",
+ choice->choice, choice->text,
+ !strcmp(option->defchoice, choice->choice)
+ ? " *" : "");
+ else
+ _cupsLangPrintf(stdout,
+ " %s (%s) = %.2fx%.2fin "
+ "(%.1f,%.1f,%.1f,%.1f)%s",
+ choice->choice, choice->text,
+ size->width / 72.0, size->length / 72.0,
+ size->left / 72.0, size->bottom / 72.0,
+ size->right / 72.0, size->top / 72.0,
+ !strcmp(option->defchoice, choice->choice)
+ ? " *" : "");
+ }
+ }
+ else
+ {
+ for (m = option->num_choices, choice = option->choices;
+ m > 0;
+ m --, choice ++)
+ {
+ _cupsLangPrintf(stdout, " %s (%s)%s",
+ choice->choice, choice->text,
+ !strcmp(option->defchoice, choice->choice)
+ ? " *" : "");
+ }
+ }
+ }
+ }
+
+ _cupsLangPrintf(stdout, " num_consts = %d",
+ ppd->num_consts);
+ for (j = 0; j < ppd->num_consts; j ++)
+ _cupsLangPrintf(stdout,
+ " consts[%d] = *%s %s *%s %s",
+ j, ppd->consts[j].option1, ppd->consts[j].choice1,
+ ppd->consts[j].option2, ppd->consts[j].choice2);
+
+ _cupsLangPrintf(stdout, " num_profiles = %d",
+ ppd->num_profiles);
+ for (j = 0; j < ppd->num_profiles; j ++)
+ _cupsLangPrintf(stdout,
+ " profiles[%d] = %s/%s %.3f %.3f "
+ "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]",
+ j, ppd->profiles[j].resolution,
+ ppd->profiles[j].media_type,
+ ppd->profiles[j].gamma, ppd->profiles[j].density,
+ ppd->profiles[j].matrix[0][0],
+ ppd->profiles[j].matrix[0][1],
+ ppd->profiles[j].matrix[0][2],
+ ppd->profiles[j].matrix[1][0],
+ ppd->profiles[j].matrix[1][1],
+ ppd->profiles[j].matrix[1][2],
+ ppd->profiles[j].matrix[2][0],
+ ppd->profiles[j].matrix[2][1],
+ ppd->profiles[j].matrix[2][2]);
+
+ _cupsLangPrintf(stdout, " num_fonts = %d", ppd->num_fonts);
+ for (j = 0; j < ppd->num_fonts; j ++)
+ _cupsLangPrintf(stdout, " fonts[%d] = %s",
+ j, ppd->fonts[j]);
+
+ _cupsLangPrintf(stdout, " num_attrs = %d", ppd->num_attrs);
+ for (j = 0; j < ppd->num_attrs; j ++)
+ _cupsLangPrintf(stdout,
+ " attrs[%d] = %s %s%s%s: \"%s\"", j,
+ ppd->attrs[j]->name, ppd->attrs[j]->spec,
+ ppd->attrs[j]->text[0] ? "/" : "",
+ ppd->attrs[j]->text,
+ ppd->attrs[j]->value ?
+ ppd->attrs[j]->value : "(null)");
+ }
+
+ ppdClose(ppd);
+ }
+
+ if (!files)
+ usage();
+
+ return (status);
+}
+
+
+/*
+ * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
+ */
+
+static void
+check_basics(const char *filename) /* I - PPD file to check */
+{
+ cups_file_t *fp; /* File pointer */
+ int ch; /* Current character */
+ int col, /* Current column */
+ whitespace; /* Only seen whitespace? */
+ int eol; /* Line endings */
+ int linenum; /* Line number */
+ int mixed; /* Mixed line endings? */
+
+
+ if ((fp = cupsFileOpen(filename, "r")) == NULL)
+ return;
+
+ linenum = 1;
+ col = 0;
+ eol = EOL_NONE;
+ mixed = 0;
+ whitespace = 1;
+
+ while ((ch = cupsFileGetChar(fp)) != EOF)
+ {
+ if (ch == '\r' || ch == '\n')
+ {
+ if (ch == '\n')
+ {
+ if (eol == EOL_NONE)
+ eol = EOL_LF;
+ else if (eol != EOL_LF)
+ mixed = 1;
+ }
+ else if (ch == '\r')
+ {
+ if (cupsFilePeekChar(fp) == '\n')
+ {
+ cupsFileGetChar(fp);
+
+ if (eol == EOL_NONE)
+ eol = EOL_CRLF;
+ else if (eol != EOL_CRLF)
+ mixed = 1;
+ }
+ else if (eol == EOL_NONE)
+ eol = EOL_CR;
+ else if (eol != EOL_CR)
+ mixed = 1;
+ }
+
+ if (col > 0 && whitespace)
+ _cupsLangPrintf(stdout,
+ _(" WARN Line %d only contains whitespace."),
+ linenum);
+
+ linenum ++;
+ col = 0;
+ whitespace = 1;
+ }
+ else
+ {
+ if (ch != ' ' && ch != '\t')
+ whitespace = 0;
+
+ col ++;
+ }
+ }
+
+ if (mixed)
+ _cupsLangPuts(stdout,
+ _(" WARN File contains a mix of CR, LF, and "
+ "CR LF line endings."));
+
+ if (eol == EOL_CRLF)
+ _cupsLangPuts(stdout,
+ _(" WARN Non-Windows PPD files should use lines "
+ "ending with only LF, not CR LF."));
+
+ cupsFileClose(fp);
+}
+
+
+/*
+ * 'check_constraints()' - Check UIConstraints in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_constraints(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int i; /* Looping var */
+ const char *prefix; /* WARN/FAIL prefix */
+ ppd_const_t *c; /* Current UIConstraints data */
+ ppd_attr_t *constattr; /* Current cupsUIConstraints attribute */
+ const char *vptr; /* Pointer into constraint value */
+ char option[PPD_MAX_NAME],
+ /* Option name/MainKeyword */
+ choice[PPD_MAX_NAME],
+ /* Choice/OptionKeyword */
+ *ptr; /* Pointer into option or choice */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ ppd_option_t *o; /* PPD option */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+
+ /*
+ * See what kind of constraint data we have in the PPD...
+ */
+
+ if ((constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL)) != NULL)
+ {
+ /*
+ * Check new-style cupsUIConstraints data...
+ */
+
+ for (; constattr;
+ constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL))
+ {
+ if (!constattr->value)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Empty cupsUIConstraints %s"),
+ prefix, constattr->spec);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ for (i = 0, vptr = strchr(constattr->value, '*');
+ vptr;
+ i ++, vptr = strchr(vptr + 1, '*'));
+
+ if (i == 0)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Bad cupsUIConstraints %s: \"%s\""),
+ prefix, constattr->spec, constattr->value);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ cupsArraySave(ppd->sorted_attrs);
+
+ if (constattr->spec[0] &&
+ !ppdFindAttr(ppd, "cupsUIResolver", constattr->spec))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing cupsUIResolver %s"),
+ prefix, constattr->spec);
+
+ if (!warn)
+ errors ++;
+ }
+
+ cupsArrayRestore(ppd->sorted_attrs);
+
+ num_options = 0;
+ options = NULL;
+
+ for (vptr = strchr(constattr->value, '*');
+ vptr;
+ vptr = strchr(vptr, '*'))
+ {
+ /*
+ * Extract "*Option Choice" or just "*Option"...
+ */
+
+ for (vptr ++, ptr = option; *vptr && !isspace(*vptr & 255); vptr ++)
+ if (ptr < (option + sizeof(option) - 1))
+ *ptr++ = *vptr;
+
+ *ptr = '\0';
+
+ while (isspace(*vptr & 255))
+ vptr ++;
+
+ if (*vptr == '*')
+ choice[0] = '\0';
+ else
+ {
+ for (ptr = choice; *vptr && !isspace(*vptr & 255); vptr ++)
+ if (ptr < (choice + sizeof(choice) - 1))
+ *ptr++ = *vptr;
+
+ *ptr = '\0';
+ }
+
+ if (!_cups_strncasecmp(option, "Custom", 6) && !_cups_strcasecmp(choice, "True"))
+ {
+ _cups_strcpy(option, option + 6);
+ strcpy(choice, "Custom");
+ }
+
+ if ((o = ppdFindOption(ppd, option)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing option %s in "
+ "cupsUIConstraints %s: \"%s\""),
+ prefix, option, constattr->spec, constattr->value);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ if (choice[0] && !ppdFindChoice(o, choice))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing choice *%s %s in "
+ "cupsUIConstraints %s: \"%s\""),
+ prefix, option, choice, constattr->spec,
+ constattr->value);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ if (choice[0])
+ num_options = cupsAddOption(option, choice, num_options, &options);
+ else
+ {
+ for (i = 0; i < o->num_choices; i ++)
+ if (_cups_strcasecmp(o->choices[i].choice, "None") &&
+ _cups_strcasecmp(o->choices[i].choice, "Off") &&
+ _cups_strcasecmp(o->choices[i].choice, "False"))
+ {
+ num_options = cupsAddOption(option, o->choices[i].choice,
+ num_options, &options);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Resolvers must list at least two options...
+ */
+
+ if (num_options < 2)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s cupsUIResolver %s does not list at least "
+ "two different options."),
+ prefix, constattr->spec);
+
+ if (!warn)
+ errors ++;
+ }
+
+ /*
+ * Test the resolver...
+ */
+
+ if (!cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s cupsUIResolver %s causes a loop."),
+ prefix, constattr->spec);
+
+ if (!warn)
+ errors ++;
+ }
+
+ cupsFreeOptions(num_options, options);
+ }
+ }
+ else
+ {
+ /*
+ * Check old-style [Non]UIConstraints data...
+ */
+
+ for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
+ {
+ if (!_cups_strncasecmp(c->option1, "Custom", 6) &&
+ !_cups_strcasecmp(c->choice1, "True"))
+ {
+ strcpy(option, c->option1 + 6);
+ strcpy(choice, "Custom");
+ }
+ else
+ {
+ strcpy(option, c->option1);
+ strcpy(choice, c->choice1);
+ }
+
+ if ((o = ppdFindOption(ppd, option)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing option %s in "
+ "UIConstraints \"*%s %s *%s %s\"."),
+ prefix, c->option1,
+ c->option1, c->choice1, c->option2, c->choice2);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (choice[0] && !ppdFindChoice(o, choice))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing choice *%s %s in "
+ "UIConstraints \"*%s %s *%s %s\"."),
+ prefix, c->option1, c->choice1,
+ c->option1, c->choice1, c->option2, c->choice2);
+
+ if (!warn)
+ errors ++;
+ }
+
+ if (!_cups_strncasecmp(c->option2, "Custom", 6) &&
+ !_cups_strcasecmp(c->choice2, "True"))
+ {
+ strcpy(option, c->option2 + 6);
+ strcpy(choice, "Custom");
+ }
+ else
+ {
+ strcpy(option, c->option2);
+ strcpy(choice, c->choice2);
+ }
+
+ if ((o = ppdFindOption(ppd, option)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing option %s in "
+ "UIConstraints \"*%s %s *%s %s\"."),
+ prefix, c->option2,
+ c->option1, c->choice1, c->option2, c->choice2);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (choice[0] && !ppdFindChoice(o, choice))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing choice *%s %s in "
+ "UIConstraints \"*%s %s *%s %s\"."),
+ prefix, c->option2, c->choice2,
+ c->option1, c->choice1, c->option2, c->choice2);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+ }
+
+ return (errors);
+}
+
+
+/*
+ * 'check_case()' - Check that there are no duplicate groups, options,
+ * or choices that differ only by case.
+ */
+
+static int /* O - Errors found */
+check_case(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Errors found */
+ int verbose) /* I - Verbosity level */
+{
+ int i, j; /* Looping vars */
+ ppd_group_t *groupa, /* First group */
+ *groupb; /* Second group */
+ ppd_option_t *optiona, /* First option */
+ *optionb; /* Second option */
+ ppd_choice_t *choicea, /* First choice */
+ *choiceb; /* Second choice */
+
+
+ /*
+ * Check that the groups do not have any duplicate names...
+ */
+
+ for (i = ppd->num_groups, groupa = ppd->groups; i > 1; i --, groupa ++)
+ for (j = i - 1, groupb = groupa + 1; j > 0; j --, groupb ++)
+ if (!_cups_strcasecmp(groupa->name, groupb->name))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Group names %s and %s differ only "
+ "by case."),
+ groupa->name, groupb->name);
+
+ errors ++;
+ }
+
+ /*
+ * Check that the options do not have any duplicate names...
+ */
+
+ for (optiona = ppdFirstOption(ppd); optiona; optiona = ppdNextOption(ppd))
+ {
+ cupsArraySave(ppd->options);
+ for (optionb = ppdNextOption(ppd); optionb; optionb = ppdNextOption(ppd))
+ if (!_cups_strcasecmp(optiona->keyword, optionb->keyword))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Option names %s and %s differ only "
+ "by case."),
+ optiona->keyword, optionb->keyword);
+
+ errors ++;
+ }
+ cupsArrayRestore(ppd->options);
+
+ /*
+ * Then the choices...
+ */
+
+ for (i = optiona->num_choices, choicea = optiona->choices;
+ i > 1;
+ i --, choicea ++)
+ for (j = i - 1, choiceb = choicea + 1; j > 0; j --, choiceb ++)
+ if (!strcmp(choicea->choice, choiceb->choice))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Multiple occurrences of %s "
+ "choice name %s."),
+ optiona->keyword, choicea->choice);
+
+ errors ++;
+
+ choicea ++;
+ i --;
+ break;
+ }
+ else if (!_cups_strcasecmp(choicea->choice, choiceb->choice))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** %s choice names %s and %s "
+ "differ only by case."),
+ optiona->keyword, choicea->choice, choiceb->choice);
+
+ errors ++;
+ }
+ }
+
+ /*
+ * Return the number of errors found...
+ */
+
+ return (errors);
+}
+
+
+/*
+ * 'check_defaults()' - Check default option keywords in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_defaults(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int j, k; /* Looping vars */
+ ppd_attr_t *attr; /* PPD attribute */
+ ppd_option_t *option; /* Standard UI option */
+ const char *prefix; /* WARN/FAIL prefix */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ ppdMarkDefaults(ppd);
+ if (ppdConflicts(ppd))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Default choices conflicting."), prefix);
+
+ show_conflicts(ppd, prefix);
+
+ if (!warn)
+ errors ++;
+ }
+
+ for (j = 0; j < ppd->num_attrs; j ++)
+ {
+ attr = ppd->attrs[j];
+
+ if (!strcmp(attr->name, "DefaultColorSpace") ||
+ !strcmp(attr->name, "DefaultFont") ||
+ !strcmp(attr->name, "DefaultHalftoneType") ||
+ !strcmp(attr->name, "DefaultImageableArea") ||
+ !strcmp(attr->name, "DefaultLeadingEdge") ||
+ !strcmp(attr->name, "DefaultOutputOrder") ||
+ !strcmp(attr->name, "DefaultPaperDimension") ||
+ !strcmp(attr->name, "DefaultResolution") ||
+ !strcmp(attr->name, "DefaultTransfer"))
+ continue;
+
+ if (!strncmp(attr->name, "Default", 7))
+ {
+ if ((option = ppdFindOption(ppd, attr->name + 7)) != NULL &&
+ strcmp(attr->value, "Unknown"))
+ {
+ /*
+ * Check that the default option value matches a choice...
+ */
+
+ for (k = 0; k < option->num_choices; k ++)
+ if (!strcmp(option->choices[k].choice, attr->value))
+ break;
+
+ if (k >= option->num_choices)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s %s %s does not exist."),
+ prefix, attr->name, attr->value);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+ }
+ }
+
+ return (errors);
+}
+
+
+/*
+ * 'check_duplex()' - Check duplex keywords in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_duplex(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Error found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int i; /* Looping var */
+ ppd_option_t *option; /* PPD option */
+ ppd_choice_t *choice; /* Current choice */
+ const char *prefix; /* Message prefix */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ /*
+ * Check for a duplex option, and for standard values...
+ */
+
+ if ((option = ppdFindOption(ppd, "Duplex")) != NULL)
+ {
+ if (!ppdFindChoice(option, "None"))
+ {
+ if (verbose >= 0)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s REQUIRED %s does not define "
+ "choice None.\n"
+ " REF: Page 122, section 5.17"),
+ prefix, option->keyword);
+ }
+
+ if (!warn)
+ errors ++;
+ }
+
+ for (i = option->num_choices, choice = option->choices;
+ i > 0;
+ i --, choice ++)
+ if (strcmp(choice->choice, "None") &&
+ strcmp(choice->choice, "DuplexNoTumble") &&
+ strcmp(choice->choice, "DuplexTumble") &&
+ strcmp(choice->choice, "SimplexTumble"))
+ {
+ if (verbose >= 0)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Bad %s choice %s.\n"
+ " REF: Page 122, section 5.17"),
+ prefix, option->keyword, choice->choice);
+ }
+
+ if (!warn)
+ errors ++;
+ }
+ }
+
+ return (errors);
+}
+
+
+/*
+ * 'check_filters()' - Check filters in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_filters(ppd_file_t *ppd, /* I - PPD file */
+ const char *root, /* I - Root directory */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int i; /* Looping var */
+ ppd_attr_t *attr; /* PPD attribute */
+ const char *ptr; /* Pointer into string */
+ char super[16], /* Super-type for filter */
+ type[256], /* Type for filter */
+ program[1024], /* Program/filter name */
+ pathprog[1024]; /* Complete path to program/filter */
+ int cost; /* Cost of filter */
+ const char *prefix; /* WARN/FAIL prefix */
+ struct stat fileinfo; /* File information */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ /*
+ * cupsFilter
+ */
+
+ for (i = 0; i < ppd->num_filters; i ++)
+ {
+ if (sscanf(ppd->filters[i], "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type,
+ &cost, program) != 4)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad cupsFilter value \"%s\"."),
+ prefix, ppd->filters[i]);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (strcmp(program, "-"))
+ {
+ if (program[0] == '/')
+ snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
+ else
+ {
+ if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
+ ptr = CUPS_SERVERBIN;
+
+ if (*ptr == '/' || !*root)
+ snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
+ program);
+ else
+ snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
+ program);
+ }
+
+ if (stat(pathprog, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
+ prefix, "cupsFilter", pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_PROGRAM)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad permissions on %s file \"%s\"."),
+ prefix, "cupsFilter", pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("cupsFilter", pathprog, errors, verbose, warn);
+ }
+ }
+
+ /*
+ * cupsPreFilter
+ */
+
+ for (attr = ppdFindAttr(ppd, "cupsPreFilter", NULL);
+ attr;
+ attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
+ {
+ if (strcmp(attr->name, "cupsPreFilter"))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad spelling of %s - should be %s."),
+ prefix, attr->name, "cupsPreFilter");
+
+ if (!warn)
+ errors ++;
+ }
+
+ if (!attr->value ||
+ sscanf(attr->value, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type,
+ &cost, program) != 4)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad cupsPreFilter value \"%s\"."),
+ prefix, attr->value ? attr->value : "");
+
+ if (!warn)
+ errors ++;
+ }
+ else if (strcmp(program, "-"))
+ {
+ if (program[0] == '/')
+ snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
+ else
+ {
+ if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
+ ptr = CUPS_SERVERBIN;
+
+ if (*ptr == '/' || !*root)
+ snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
+ program);
+ else
+ snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
+ program);
+ }
+
+ if (stat(pathprog, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
+ prefix, "cupsPreFilter", pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_PROGRAM)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad permissions on %s file \"%s\"."),
+ prefix, "cupsPreFilter", pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("cupsPreFilter", pathprog, errors, verbose, warn);
+ }
+ }
+
+#ifdef __APPLE__
+ /*
+ * APDialogExtension
+ */
+
+ for (attr = ppdFindAttr(ppd, "APDialogExtension", NULL);
+ attr != NULL;
+ attr = ppdFindNextAttr(ppd, "APDialogExtension", NULL))
+ {
+ if (strcmp(attr->name, "APDialogExtension"))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad spelling of %s - should be %s."),
+ prefix, attr->name, "APDialogExtension");
+
+ if (!warn)
+ errors ++;
+ }
+
+ snprintf(pathprog, sizeof(pathprog), "%s%s", root,
+ attr->value ? attr->value : "(null)");
+
+ if (!attr->value || stat(pathprog, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
+ prefix, "APDialogExtension", pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad permissions on %s file \"%s\"."),
+ prefix, "APDialogExtension", pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("APDialogExtension", pathprog, errors, verbose,
+ warn);
+ }
+
+ /*
+ * APPrinterIconPath
+ */
+
+ if ((attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL)
+ {
+ if (strcmp(attr->name, "APPrinterIconPath"))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad spelling of %s - should be %s."),
+ prefix, attr->name, "APPrinterIconPath");
+
+ if (!warn)
+ errors ++;
+ }
+
+ snprintf(pathprog, sizeof(pathprog), "%s%s", root,
+ attr->value ? attr->value : "(null)");
+
+ if (!attr->value || stat(pathprog, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
+ prefix, "APPrinterIconPath", pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_DATAFILE)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad permissions on %s file \"%s\"."),
+ prefix, "APPrinterIconPath", pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("APPrinterIconPath", pathprog, errors, verbose,
+ warn);
+ }
+
+ /*
+ * APPrinterLowInkTool
+ */
+
+ if ((attr = ppdFindAttr(ppd, "APPrinterLowInkTool", NULL)) != NULL)
+ {
+ if (strcmp(attr->name, "APPrinterLowInkTool"))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad spelling of %s - should be %s."),
+ prefix, attr->name, "APPrinterLowInkTool");
+
+ if (!warn)
+ errors ++;
+ }
+
+ snprintf(pathprog, sizeof(pathprog), "%s%s", root,
+ attr->value ? attr->value : "(null)");
+
+ if (!attr->value || stat(pathprog, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
+ prefix, "APPrinterLowInkTool", pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad permissions on %s file \"%s\"."),
+ prefix, "APPrinterLowInkTool", pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("APPrinterLowInkTool", pathprog, errors, verbose,
+ warn);
+ }
+
+ /*
+ * APPrinterUtilityPath
+ */
+
+ if ((attr = ppdFindAttr(ppd, "APPrinterUtilityPath", NULL)) != NULL)
+ {
+ if (strcmp(attr->name, "APPrinterUtilityPath"))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad spelling of %s - should be %s."),
+ prefix, attr->name, "APPrinterUtilityPath");
+
+ if (!warn)
+ errors ++;
+ }
+
+ snprintf(pathprog, sizeof(pathprog), "%s%s", root,
+ attr->value ? attr->value : "(null)");
+
+ if (!attr->value || stat(pathprog, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
+ prefix, "APPrinterUtilityPath", pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad permissions on %s file \"%s\"."),
+ prefix, "APPrinterUtilityPath", pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("APPrinterUtilityPath", pathprog, errors, verbose,
+ warn);
+ }
+
+ /*
+ * APScanAppBundleID and APScanAppPath
+ */
+
+ if ((attr = ppdFindAttr(ppd, "APScanAppPath", NULL)) != NULL)
+ {
+ if (strcmp(attr->name, "APScanAppPath"))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad spelling of %s - should be %s."),
+ prefix, attr->name, "APScanAppPath");
+
+ if (!warn)
+ errors ++;
+ }
+
+ if (!attr->value || stat(attr->value, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
+ prefix, "APScanAppPath",
+ attr->value ? attr->value : "<NULL>");
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad permissions on %s file \"%s\"."),
+ prefix, "APScanAppPath", attr->value);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("APScanAppPath", attr->value, errors, verbose,
+ warn);
+
+ if (ppdFindAttr(ppd, "APScanAppBundleID", NULL))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Cannot provide both "
+ "APScanAppPath and APScanAppBundleID."),
+ prefix);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+#endif /* __APPLE__ */
+
+ return (errors);
+}
+
+
+/*
+ * 'check_profiles()' - Check ICC color profiles in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_profiles(ppd_file_t *ppd, /* I - PPD file */
+ const char *root, /* I - Root directory */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int i; /* Looping var */
+ ppd_attr_t *attr; /* PPD attribute */
+ const char *ptr; /* Pointer into string */
+ const char *prefix; /* WARN/FAIL prefix */
+ char filename[1024]; /* Profile filename */
+ struct stat fileinfo; /* File information */
+ int num_profiles = 0; /* Number of profiles */
+ unsigned hash, /* Current hash value */
+ hashes[1000]; /* Hash values of profile names */
+ const char *specs[1000]; /* Specifiers for profiles */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
+ attr;
+ attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
+ {
+ /*
+ * Check for valid selector...
+ */
+
+ for (i = 0, ptr = strchr(attr->spec, '.'); ptr; ptr = strchr(ptr + 1, '.'))
+ i ++;
+
+ if (!attr->value || i < 2)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad cupsICCProfile %s."),
+ prefix, attr->spec);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ /*
+ * Check for valid profile filename...
+ */
+
+ if (attr->value[0] == '/')
+ snprintf(filename, sizeof(filename), "%s%s", root, attr->value);
+ else
+ {
+ if ((ptr = getenv("CUPS_DATADIR")) == NULL)
+ ptr = CUPS_DATADIR;
+
+ if (*ptr == '/' || !*root)
+ snprintf(filename, sizeof(filename), "%s%s/profiles/%s", root, ptr,
+ attr->value);
+ else
+ snprintf(filename, sizeof(filename), "%s/%s/profiles/%s", root, ptr,
+ attr->value);
+ }
+
+ if (stat(filename, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
+ prefix, "cupsICCProfile", filename);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_DATAFILE)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad permissions on %s file \"%s\"."),
+ prefix, "cupsICCProfile", filename);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("cupsICCProfile", filename, errors, verbose, warn);
+
+ /*
+ * Check for hash collisions...
+ */
+
+ hash = _ppdHashName(attr->spec);
+
+ if (num_profiles > 0)
+ {
+ for (i = 0; i < num_profiles; i ++)
+ if (hashes[i] == hash)
+ break;
+
+ if (i < num_profiles)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s cupsICCProfile %s hash value "
+ "collides with %s."), prefix, attr->spec,
+ specs[i]);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+
+ /*
+ * Remember up to 1000 profiles...
+ */
+
+ if (num_profiles < 1000)
+ {
+ hashes[num_profiles] = hash;
+ specs[num_profiles] = attr->spec;
+ num_profiles ++;
+ }
+ }
+
+ return (errors);
+}
+
+
+/*
+ * 'check_sizes()' - Check media sizes in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_sizes(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int i; /* Looping var */
+ ppd_size_t *size; /* Current size */
+ int width, /* Custom width */
+ length; /* Custom length */
+ const char *prefix; /* WARN/FAIL prefix */
+ ppd_option_t *page_size, /* PageSize option */
+ *page_region; /* PageRegion option */
+ _pwg_media_t *pwg_media; /* PWG media */
+ char buf[1024]; /* PapeSize name that is supposed to be */
+ const char *ptr; /* Pointer into string */
+ int width_2540ths, /* PageSize width in 2540ths */
+ length_2540ths; /* PageSize length in 2540ths */
+ int is_ok; /* Flag for PageSize name verification */
+ double width_tmp, /* Width after rounded up */
+ length_tmp, /* Length after rounded up */
+ width_inch, /* Width in inches */
+ length_inch, /* Length in inches */
+ width_mm, /* Width in millimeters */
+ length_mm; /* Length in millimeters */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ if ((page_size = ppdFindOption(ppd, "PageSize")) == NULL && warn != 2)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Missing REQUIRED PageSize option.\n"
+ " REF: Page 99, section 5.14."),
+ prefix);
+
+ if (!warn)
+ errors ++;
+ }
+
+ if ((page_region = ppdFindOption(ppd, "PageRegion")) == NULL && warn != 2)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Missing REQUIRED PageRegion option.\n"
+ " REF: Page 100, section 5.14."),
+ prefix);
+
+ if (!warn)
+ errors ++;
+ }
+
+ for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
+ {
+ /*
+ * Check that the size name is standard...
+ */
+
+ if (!strcmp(size->name, "Custom"))
+ {
+ /*
+ * Skip custom page size...
+ */
+
+ continue;
+ }
+ else if (warn != 2 && size->name[0] == 'w' &&
+ sscanf(size->name, "w%dh%d", &width, &length) == 2)
+ {
+ /*
+ * Validate device-specific size wNNNhNNN should have proper width and
+ * length...
+ */
+
+ if (fabs(width - size->width) >= 1.0 ||
+ fabs(length - size->length) >= 1.0)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Size \"%s\" has unexpected dimensions "
+ "(%gx%g)."),
+ prefix, size->name, size->width, size->length);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+
+ /*
+ * Verify that the size is defined for both PageSize and PageRegion...
+ */
+
+ if (warn != 2 && !ppdFindChoice(page_size, size->name))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Size \"%s\" defined for %s but not for "
+ "%s."),
+ prefix, size->name, "PageRegion", "PageSize");
+
+ if (!warn)
+ errors ++;
+ }
+ else if (warn != 2 && !ppdFindChoice(page_region, size->name))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Size \"%s\" defined for %s but not for "
+ "%s."),
+ prefix, size->name, "PageSize", "PageRegion");
+
+ if (!warn)
+ errors ++;
+ }
+
+ /*
+ * Verify that the size name is Adobe standard name if it's a standard size
+ * and the dementional name if it's not a standard size. Suffix should be
+ * .Fullbleed, etc., or numeric, e.g., Letter, Letter.Fullbleed,
+ * Letter.Transverse, Letter1, Letter2, 4x8, 55x91mm, 55x91mm.Fullbleed, etc.
+ */
+
+ if (warn != 0)
+ {
+ is_ok = 1;
+ width_2540ths = (size->length > size->width) ?
+ _PWG_FROMPTS(size->width) :
+ _PWG_FROMPTS(size->length);
+ length_2540ths = (size->length > size->width) ?
+ _PWG_FROMPTS(size->length) :
+ _PWG_FROMPTS(size->width);
+ pwg_media = _pwgMediaForSize(width_2540ths, length_2540ths);
+
+ if (pwg_media && pwg_media->ppd)
+ {
+ strlcpy(buf, pwg_media->ppd, sizeof(buf));
+
+ if (size->left == 0 && size->bottom == 0 &&
+ size->right == size->width && size->top == size->length)
+ {
+ snprintf(buf, sizeof(buf), "%s.Fullbleed", pwg_media->ppd);
+ if (strcmp(size->name, buf))
+ is_ok = 0;
+ }
+ else if (size->width > size->length)
+ {
+ if ((ptr = pwg_media->ppd + strlen(pwg_media->ppd) - 7)
+ >= pwg_media->ppd && !strcmp(ptr, "Rotated"))
+ {
+ if (strcmp(size->name, buf))
+ is_ok = 0;
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf), "%sRotated", pwg_media->ppd);
+ if (strcmp(size->name, buf))
+ {
+ snprintf(buf, sizeof(buf), "%s.Transverse", pwg_media->ppd);
+ if (strcmp(size->name, buf))
+ is_ok = 0;
+ }
+ }
+ }
+ else
+ {
+ if ((!strncmp(size->name, pwg_media->ppd, strlen(pwg_media->ppd))))
+ {
+ for (ptr = size->name + strlen(pwg_media->ppd); *ptr; ptr ++)
+ {
+ if (!isdigit(*ptr & 255))
+ {
+ is_ok = 0;
+ break;
+ }
+ }
+ }
+ else
+ is_ok = 0;
+ }
+
+ if (!is_ok)
+ _cupsLangPrintf(stdout,
+ _(" %s Size \"%s\" should be the Adobe "
+ "standard name \"%s\"."),
+ prefix, size->name, buf);
+ }
+ else
+ {
+ width_tmp = (fabs(size->width - ceil(size->width)) < 0.1) ?
+ ceil(size->width) : size->width;
+ length_tmp = (fabs(size->length - ceil(size->length)) < 0.1) ?
+ ceil(size->length) : size->length;
+
+ if (fmod(width_tmp, 18.0) == 0.0 && fmod(length_tmp, 18.0) == 0.0)
+ {
+ width_inch = width_tmp / 72.0;
+ length_inch = length_tmp / 72.0;
+
+ snprintf(buf, sizeof(buf), "%gx%g", width_inch, length_inch);
+ }
+ else
+ {
+ width_mm = size->width / 72.0 * 25.4;
+ length_mm = size->length / 72.0 * 25.4;
+
+ snprintf(buf, sizeof(buf), "%.0fx%.0fmm", width_mm, length_mm);
+ }
+
+ if (size->left == 0 && size->bottom == 0 &&
+ size->right == size->width && size->top == size->length)
+ strlcat(buf, ".Fullbleed", sizeof(buf));
+ else if (size->width > size->length)
+ strlcat(buf, ".Transverse", sizeof(buf));
+
+ if (strcmp(size->name, buf))
+ _cupsLangPrintf(stdout,
+ _(" %s Size \"%s\" should be \"%s\"."),
+ prefix, size->name, buf);
+ }
+ }
+ }
+
+ return (errors);
+}
+
+
+/*
+ * 'check_translations()' - Check translations in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_translations(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int j; /* Looping var */
+ ppd_attr_t *attr; /* PPD attribute */
+ cups_array_t *languages; /* Array of languages */
+ int langlen; /* Length of language */
+ char *language, /* Current language */
+ keyword[PPD_MAX_NAME], /* Localization keyword (full) */
+ llkeyword[PPD_MAX_NAME],/* Localization keyword (base) */
+ ckeyword[PPD_MAX_NAME], /* Custom option keyword (full) */
+ cllkeyword[PPD_MAX_NAME];
+ /* Custom option keyword (base) */
+ ppd_option_t *option; /* Standard UI option */
+ ppd_coption_t *coption; /* Custom option */
+ ppd_cparam_t *cparam; /* Custom parameter */
+ char ll[3]; /* Base language */
+ const char *prefix; /* WARN/FAIL prefix */
+ const char *text; /* Pointer into UI text */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ if ((languages = _ppdGetLanguages(ppd)) != NULL)
+ {
+ /*
+ * This file contains localizations, check them...
+ */
+
+ for (language = (char *)cupsArrayFirst(languages);
+ language;
+ language = (char *)cupsArrayNext(languages))
+ {
+ langlen = (int)strlen(language);
+ if (langlen != 2 && langlen != 5)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad language \"%s\"."),
+ prefix, language);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ if (!strcmp(language, "en"))
+ continue;
+
+ strlcpy(ll, language, sizeof(ll));
+
+ /*
+ * Loop through all options and choices...
+ */
+
+ for (option = ppdFirstOption(ppd);
+ option;
+ option = ppdNextOption(ppd))
+ {
+ if (!strcmp(option->keyword, "PageRegion"))
+ continue;
+
+ snprintf(keyword, sizeof(keyword), "%s.Translation", language);
+ snprintf(llkeyword, sizeof(llkeyword), "%s.Translation", ll);
+
+ if ((attr = ppdFindAttr(ppd, keyword, option->keyword)) == NULL &&
+ (attr = ppdFindAttr(ppd, llkeyword, option->keyword)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Missing \"%s\" translation "
+ "string for option %s."),
+ prefix, language, option->keyword);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (!valid_utf8(attr->text))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad UTF-8 \"%s\" translation "
+ "string for option %s."),
+ prefix, language, option->keyword);
+
+ if (!warn)
+ errors ++;
+ }
+
+ snprintf(keyword, sizeof(keyword), "%s.%s", language,
+ option->keyword);
+ snprintf(llkeyword, sizeof(llkeyword), "%s.%s", ll,
+ option->keyword);
+
+ for (j = 0; j < option->num_choices; j ++)
+ {
+ /*
+ * First see if this choice is a number; if so, don't require
+ * translation...
+ */
+
+ for (text = option->choices[j].text; *text; text ++)
+ if (!strchr("0123456789-+.", *text))
+ break;
+
+ if (!*text)
+ continue;
+
+ /*
+ * Check custom choices differently...
+ */
+
+ if (!_cups_strcasecmp(option->choices[j].choice, "Custom") &&
+ (coption = ppdFindCustomOption(ppd,
+ option->keyword)) != NULL)
+ {
+ snprintf(ckeyword, sizeof(ckeyword), "%s.Custom%s",
+ language, option->keyword);
+
+ if ((attr = ppdFindAttr(ppd, ckeyword, "True")) != NULL &&
+ !valid_utf8(attr->text))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad UTF-8 \"%s\" "
+ "translation string for option %s, "
+ "choice %s."),
+ prefix, language,
+ ckeyword + 1 + strlen(language),
+ "True");
+
+ if (!warn)
+ errors ++;
+ }
+
+ if (_cups_strcasecmp(option->keyword, "PageSize"))
+ {
+ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+ cparam;
+ cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
+ {
+ snprintf(ckeyword, sizeof(ckeyword), "%s.ParamCustom%s",
+ language, option->keyword);
+ snprintf(cllkeyword, sizeof(cllkeyword), "%s.ParamCustom%s",
+ ll, option->keyword);
+
+ if ((attr = ppdFindAttr(ppd, ckeyword,
+ cparam->name)) == NULL &&
+ (attr = ppdFindAttr(ppd, cllkeyword,
+ cparam->name)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Missing \"%s\" "
+ "translation string for option %s, "
+ "choice %s."),
+ prefix, language,
+ ckeyword + 1 + strlen(language),
+ cparam->name);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (!valid_utf8(attr->text))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad UTF-8 \"%s\" "
+ "translation string for option %s, "
+ "choice %s."),
+ prefix, language,
+ ckeyword + 1 + strlen(language),
+ cparam->name);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+ }
+ }
+ else if ((attr = ppdFindAttr(ppd, keyword,
+ option->choices[j].choice)) == NULL &&
+ (attr = ppdFindAttr(ppd, llkeyword,
+ option->choices[j].choice)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Missing \"%s\" "
+ "translation string for option %s, "
+ "choice %s."),
+ prefix, language, option->keyword,
+ option->choices[j].choice);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (!valid_utf8(attr->text))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad UTF-8 \"%s\" "
+ "translation string for option %s, "
+ "choice %s."),
+ prefix, language, option->keyword,
+ option->choices[j].choice);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+ }
+ }
+
+ /*
+ * Verify that we have the base language for each localized one...
+ */
+
+ for (language = (char *)cupsArrayFirst(languages);
+ language;
+ language = (char *)cupsArrayNext(languages))
+ if (language[2])
+ {
+ /*
+ * Lookup the base language...
+ */
+
+ cupsArraySave(languages);
+
+ strlcpy(ll, language, sizeof(ll));
+
+ if (!cupsArrayFind(languages, ll) &&
+ strcmp(ll, "zh") && strcmp(ll, "en"))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s No base translation \"%s\" "
+ "is included in file."), prefix, ll);
+
+ if (!warn)
+ errors ++;
+ }
+
+ cupsArrayRestore(languages);
+ }
+
+ /*
+ * Free memory used for the languages...
+ */
+
+ _ppdFreeLanguages(languages);
+ }
+
+ return (errors);
+}
+
+
+/*
+ * 'show_conflicts()' - Show option conflicts in a PPD file.
+ */
+
+static void
+show_conflicts(ppd_file_t *ppd, /* I - PPD to check */
+ const char *prefix) /* I - Prefix string */
+{
+ int i, j; /* Looping variables */
+ ppd_const_t *c; /* Current constraint */
+ ppd_option_t *o1, *o2; /* Options */
+ ppd_choice_t *c1, *c2; /* Choices */
+
+
+ /*
+ * Loop through all of the UI constraints and report any options
+ * that conflict...
+ */
+
+ for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
+ {
+ /*
+ * Grab pointers to the first option...
+ */
+
+ o1 = ppdFindOption(ppd, c->option1);
+
+ if (o1 == NULL)
+ continue;
+ else if (c->choice1[0] != '\0')
+ {
+ /*
+ * This constraint maps to a specific choice.
+ */
+
+ c1 = ppdFindChoice(o1, c->choice1);
+ }
+ else
+ {
+ /*
+ * This constraint applies to any choice for this option.
+ */
+
+ for (j = o1->num_choices, c1 = o1->choices; j > 0; j --, c1 ++)
+ if (c1->marked)
+ break;
+
+ if (j == 0 ||
+ !_cups_strcasecmp(c1->choice, "None") ||
+ !_cups_strcasecmp(c1->choice, "Off") ||
+ !_cups_strcasecmp(c1->choice, "False"))
+ c1 = NULL;
+ }
+
+ /*
+ * Grab pointers to the second option...
+ */
+
+ o2 = ppdFindOption(ppd, c->option2);
+
+ if (o2 == NULL)
+ continue;
+ else if (c->choice2[0] != '\0')
+ {
+ /*
+ * This constraint maps to a specific choice.
+ */
+
+ c2 = ppdFindChoice(o2, c->choice2);
+ }
+ else
+ {
+ /*
+ * This constraint applies to any choice for this option.
+ */
+
+ for (j = o2->num_choices, c2 = o2->choices; j > 0; j --, c2 ++)
+ if (c2->marked)
+ break;
+
+ if (j == 0 ||
+ !_cups_strcasecmp(c2->choice, "None") ||
+ !_cups_strcasecmp(c2->choice, "Off") ||
+ !_cups_strcasecmp(c2->choice, "False"))
+ c2 = NULL;
+ }
+
+ /*
+ * If both options are marked then there is a conflict...
+ */
+
+ if (c1 != NULL && c1->marked && c2 != NULL && c2->marked)
+ _cupsLangPrintf(stdout,
+ _(" %s \"%s %s\" conflicts with \"%s %s\"\n"
+ " (constraint=\"%s %s %s %s\")."),
+ prefix, o1->keyword, c1->choice, o2->keyword, c2->choice,
+ c->option1, c->choice1, c->option2, c->choice2);
+ }
+}
+
+
+/*
+ * 'test_raster()' - Test PostScript commands for raster printers.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+test_raster(ppd_file_t *ppd, /* I - PPD file */
+ int verbose) /* I - Verbosity */
+{
+ cups_page_header2_t header; /* Page header */
+
+
+ ppdMarkDefaults(ppd);
+ if (cupsRasterInterpretPPD(&header, ppd, 0, NULL, 0))
+ {
+ if (!verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Default option code cannot be "
+ "interpreted: %s"), cupsRasterErrorString());
+
+ return (0);
+ }
+
+ /*
+ * Try a test of custom page size code, if available...
+ */
+
+ if (!ppdPageSize(ppd, "Custom.612x792"))
+ return (1);
+
+ ppdMarkOption(ppd, "PageSize", "Custom.612x792");
+
+ if (cupsRasterInterpretPPD(&header, ppd, 0, NULL, 0))
+ {
+ if (!verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Default option code cannot be "
+ "interpreted: %s"), cupsRasterErrorString());
+
+ return (0);
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'usage()' - Show program usage.
+ */
+
+static void
+usage(void)
+{
+ _cupsLangPuts(stdout, _("Usage: cupstestppd [options] filename1.ppd[.gz] "
+ "[... filenameN.ppd[.gz]]"));
+ _cupsLangPuts(stdout, _(" program | cupstestppd [options] -"));
+ _cupsLangPuts(stdout, "");
+ _cupsLangPuts(stdout, _("Options:"));
+ _cupsLangPuts(stdout, "");
+ _cupsLangPuts(stdout, _(" -I {filename,filters,none,profiles}"));
+ _cupsLangPuts(stdout, _(" Ignore specific warnings."));
+ _cupsLangPuts(stdout, _(" -R root-directory Set alternate root."));
+ _cupsLangPuts(stdout, _(" -W {all,none,constraints,defaults,duplex,"
+ "filters,profiles,sizes,translations}"));
+ _cupsLangPuts(stdout, _(" Issue warnings instead of "
+ "errors."));
+ _cupsLangPuts(stdout, _(" -q Run silently."));
+ _cupsLangPuts(stdout, _(" -r Use 'relaxed' open mode."));
+ _cupsLangPuts(stdout, _(" -v Be slightly verbose."));
+ _cupsLangPuts(stdout, _(" -vv Be very verbose."));
+
+ exit(ERROR_USAGE);
+}
+
+
+/*
+ * 'valid_path()' - Check whether a path has the correct capitalization.
+ */
+
+static int /* O - Errors found */
+valid_path(const char *keyword, /* I - Keyword using path */
+ const char *path, /* I - Path to check */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ cups_dir_t *dir; /* Current directory */
+ cups_dentry_t *dentry; /* Current directory entry */
+ char temp[1024], /* Temporary path */
+ *ptr; /* Pointer into temporary path */
+ const char *prefix; /* WARN/FAIL prefix */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ /*
+ * Loop over the components of the path, checking that the entry exists with
+ * the same capitalization...
+ */
+
+ strlcpy(temp, path, sizeof(temp));
+
+ while ((ptr = strrchr(temp, '/')) != NULL)
+ {
+ /*
+ * Chop off the trailing component so temp == dirname and ptr == basename.
+ */
+
+ *ptr++ = '\0';
+
+ /*
+ * Try opening the directory containing the base name...
+ */
+
+ if (temp[0])
+ dir = cupsDirOpen(temp);
+ else
+ dir = cupsDirOpen("/");
+
+ if (!dir)
+ dentry = NULL;
+ else
+ {
+ while ((dentry = cupsDirRead(dir)) != NULL)
+ {
+ if (!strcmp(dentry->filename, ptr))
+ break;
+ }
+
+ cupsDirClose(dir);
+ }
+
+ /*
+ * Display an error if the filename doesn't exist with the same
+ * capitalization...
+ */
+
+ if (!dentry)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s %s file \"%s\" has the wrong "
+ "capitalization."), prefix, keyword, path);
+
+ if (!warn)
+ errors ++;
+
+ break;
+ }
+ }
+
+ return (errors);
+}
+
+
+/*
+ * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
+ */
+
+static int /* O - 1 if valid, 0 if not */
+valid_utf8(const char *s) /* I - String to check */
+{
+ while (*s)
+ {
+ if (*s & 0x80)
+ {
+ /*
+ * Check for valid UTF-8 sequence...
+ */
+
+ if ((*s & 0xc0) == 0x80)
+ return (0); /* Illegal suffix byte */
+ else if ((*s & 0xe0) == 0xc0)
+ {
+ /*
+ * 2-byte sequence...
+ */
+
+ s ++;
+
+ if ((*s & 0xc0) != 0x80)
+ return (0); /* Missing suffix byte */
+ }
+ else if ((*s & 0xf0) == 0xe0)
+ {
+ /*
+ * 3-byte sequence...
+ */
+
+ s ++;
+
+ if ((*s & 0xc0) != 0x80)
+ return (0); /* Missing suffix byte */
+
+ s ++;
+
+ if ((*s & 0xc0) != 0x80)
+ return (0); /* Missing suffix byte */
+ }
+ else if ((*s & 0xf8) == 0xf0)
+ {
+ /*
+ * 4-byte sequence...
+ */
+
+ s ++;
+
+ if ((*s & 0xc0) != 0x80)
+ return (0); /* Missing suffix byte */
+
+ s ++;
+
+ if ((*s & 0xc0) != 0x80)
+ return (0); /* Missing suffix byte */
+
+ s ++;
+
+ if ((*s & 0xc0) != 0x80)
+ return (0); /* Missing suffix byte */
+ }
+ else
+ return (0); /* Bad sequence */
+ }
+
+ s ++;
+ }
+
+ return (1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/lp.c b/systemv/lp.c
new file mode 100644
index 000000000..98a7d3980
--- /dev/null
+++ b/systemv/lp.c
@@ -0,0 +1,723 @@
+/*
+ * "$Id$"
+ *
+ * "lp" command for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Parse options and send files for printing.
+ * restart_job() - Restart a job.
+ * set_job_attrs() - Set job attributes.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * Local functions.
+ */
+
+int restart_job(const char *command, int job_id);
+int set_job_attrs(const char *command, int job_id, int num_options,
+ cups_option_t *options);
+
+
+/*
+ * '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 vars */
+ int job_id; /* Job ID */
+ char *printer, /* Printer name */
+ *instance, /* Instance name */
+ *val, /* Option value */
+ *title; /* Job title */
+ int priority; /* Job priority (1-100) */
+ int num_copies; /* Number of copies per file */
+ int num_files; /* Number of files to print */
+ const char *files[1000]; /* Files to print */
+ cups_dest_t *dest; /* Selected destination */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ int end_options; /* No more options? */
+ int silent; /* Silent or verbose output? */
+ char buffer[8192]; /* Copy buffer */
+
+
+#ifdef __sun
+ /*
+ * Solaris does some rather strange things to re-queue remote print
+ * jobs. On bootup, the "lp" command is run as "printd" to re-spool
+ * any remote jobs in /var/spool/print. Since CUPS doesn't need this
+ * nonsense, we just need to add the necessary check here to prevent
+ * lp from causing boot problems...
+ */
+
+ if ((val = strrchr(argv[0], '/')) != NULL)
+ val ++;
+ else
+ val = argv[0];
+
+ if (!strcmp(val, "printd"))
+ return (0);
+#endif /* __sun */
+
+ _cupsSetLocale(argv);
+
+ silent = 0;
+ printer = NULL;
+ dest = NULL;
+ num_options = 0;
+ options = NULL;
+ num_files = 0;
+ title = NULL;
+ job_id = 0;
+ end_options = 0;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-' && argv[i][1] && !end_options)
+ switch (argv[i][1])
+ {
+ case 'E' : /* Encrypt */
+#ifdef HAVE_SSL
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+#else
+ _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
+ argv[0]);
+#endif /* HAVE_SSL */
+ break;
+
+ case 'U' : /* Username */
+ if (argv[i][2] != '\0')
+ cupsSetUser(argv[i] + 2);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected username after \"-U\" "
+ "option."), argv[0]);
+ return (1);
+ }
+
+ cupsSetUser(argv[i]);
+ }
+ break;
+
+ case 'c' : /* Copy to spool dir (always enabled) */
+ break;
+
+ case 'd' : /* Destination printer or class */
+ if (argv[i][2] != '\0')
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected destination after "
+ "\"-d\" option."), argv[0]);
+ return (1);
+ }
+
+ printer = argv[i];
+ }
+
+ if ((instance = strrchr(printer, '/')) != NULL)
+ *instance++ = '\0';
+
+ if ((dest = cupsGetNamedDest(NULL, printer, instance)) != 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 'f' : /* Form */
+ if (!argv[i][2])
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected form after \"-f\" "
+ "option."),
+ argv[0]);
+ return (1);
+ }
+ }
+
+ _cupsLangPrintf(stderr, _("%s: Warning - form option ignored."),
+ argv[0]);
+ break;
+
+ case 'h' : /* Destination host */
+ if (argv[i][2] != '\0')
+ cupsSetServer(argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected hostname after "
+ "\"-h\" option."), argv[0]);
+ return (1);
+ }
+
+ cupsSetServer(argv[i]);
+ }
+ break;
+
+ case 'i' : /* Change job */
+ if (argv[i][2])
+ val = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Expected job ID after \"-i\" option."),
+ argv[0]);
+ return (1);
+ }
+
+ val = argv[i];
+ }
+
+ if (num_files > 0)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - cannot print files and alter "
+ "jobs simultaneously."), argv[0]);
+ return (1);
+ }
+
+ if (strrchr(val, '-') != NULL)
+ job_id = atoi(strrchr(val, '-') + 1);
+ else
+ job_id = atoi(val);
+
+ if (job_id < 0)
+ {
+ _cupsLangPrintf(stderr, _("%s: Error - bad job ID."), argv[0]);
+ break;
+ }
+ break;
+
+ case 'm' : /* Send email when job is done */
+#ifdef __sun
+ case 'p' : /* Notify on completion */
+#endif /* __sun */
+ case 'w' : /* Write to console or email */
+ {
+ char email[1024]; /* EMail address */
+
+
+ snprintf(email, sizeof(email), "mailto:%s@%s", cupsUser(),
+ httpGetHostname(NULL, buffer, sizeof(buffer)));
+ num_options = cupsAddOption("notify-recipient-uri", email,
+ num_options, &options);
+ }
+
+ silent = 1;
+ break;
+
+ case 'n' : /* Number of copies */
+ if (argv[i][2] != '\0')
+ num_copies = atoi(argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected copies after "
+ "\"-n\" option."), argv[0]);
+ return (1);
+ }
+
+ num_copies = atoi(argv[i]);
+ }
+
+ sprintf(buffer, "%d", num_copies);
+ num_options = cupsAddOption("copies", buffer, num_options,
+ &options);
+ break;
+
+ case 'o' : /* Option */
+ if (argv[i][2] != '\0')
+ num_options = cupsParseOptions(argv[i] + 2, num_options,
+ &options);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected option=value after "
+ "\"-o\" option."), argv[0]);
+ return (1);
+ }
+
+ num_options = cupsParseOptions(argv[i], num_options, &options);
+ }
+ break;
+
+#ifndef __sun
+ case 'p' : /* Queue priority */
+#endif /* !__sun */
+ case 'q' : /* Queue priority */
+ if (argv[i][2] != '\0')
+ priority = atoi(argv[i] + 2);
+ else
+ {
+ if ((i + 1) >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected priority after "
+ "\"-%c\" option."), argv[0], argv[i][1]);
+ return (1);
+ }
+
+ i ++;
+
+ priority = atoi(argv[i]);
+ }
+
+ /*
+ * For 100% Solaris compatibility, need to add:
+ *
+ * priority = 99 * (39 - priority) / 39 + 1;
+ *
+ * However, to keep CUPS lp the same across all platforms
+ * we will break compatibility this far...
+ */
+
+ if (priority < 1 || priority > 100)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - priority must be between 1 and "
+ "100."), argv[0]);
+ return (1);
+ }
+
+ sprintf(buffer, "%d", priority);
+ num_options = cupsAddOption("job-priority", buffer, num_options,
+ &options);
+ break;
+
+ case 's' : /* Silent */
+ silent = 1;
+ break;
+
+ case 't' : /* Title */
+ if (argv[i][2] != '\0')
+ title = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected title after "
+ "\"-t\" option."), argv[0]);
+ return (1);
+ }
+
+ title = argv[i];
+ }
+ break;
+
+ case 'y' : /* mode-list */
+ if (!argv[i][2])
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected mode list after "
+ "\"-y\" option."), argv[0]);
+ return (1);
+ }
+ }
+
+ _cupsLangPrintf(stderr,
+ _("%s: Warning - mode option ignored."), argv[0]);
+ break;
+
+ case 'H' : /* Hold job */
+ if (argv[i][2])
+ val = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected hold name after "
+ "\"-H\" option."), argv[0]);
+ return (1);
+ }
+
+ val = argv[i];
+ }
+
+ if (!strcmp(val, "hold"))
+ num_options = cupsAddOption("job-hold-until", "indefinite",
+ num_options, &options);
+ else if (!strcmp(val, "resume") ||
+ !strcmp(val, "release"))
+ num_options = cupsAddOption("job-hold-until", "no-hold",
+ num_options, &options);
+ else if (!strcmp(val, "immediate"))
+ {
+ num_options = cupsAddOption("job-hold-until", "no-hold",
+ num_options, &options);
+ num_options = cupsAddOption("job-priority", "100",
+ num_options, &options);
+ }
+ else if (!strcmp(val, "restart"))
+ {
+ if (job_id < 1)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Need job ID (\"-i jobid\") before "
+ "\"-H restart\"."), argv[0]);
+ return (1);
+ }
+
+ if (restart_job(argv[0], job_id))
+ return (1);
+ }
+ else
+ num_options = cupsAddOption("job-hold-until", val,
+ num_options, &options);
+ break;
+
+ case 'P' : /* Page list */
+ if (argv[i][2])
+ val = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected page list after "
+ "\"-P\" option."), argv[0]);
+ return (1);
+ }
+
+ val = argv[i];
+ }
+
+ num_options = cupsAddOption("page-ranges", val, num_options,
+ &options);
+ break;
+
+ case 'S' : /* character set */
+ if (!argv[i][2])
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected character set after "
+ "\"-S\" option."), argv[0]);
+ return (1);
+ }
+ }
+
+ _cupsLangPrintf(stderr,
+ _("%s: Warning - character set option ignored."),
+ argv[0]);
+ break;
+
+ case 'T' : /* Content-Type */
+ if (!argv[i][2])
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected content type after "
+ "\"-T\" option."), argv[0]);
+ return (1);
+ }
+ }
+
+ _cupsLangPrintf(stderr,
+ _("%s: Warning - content type option ignored."),
+ argv[0]);
+ break;
+
+ case '-' : /* Stop processing options */
+ end_options = 1;
+ break;
+
+ default :
+ _cupsLangPrintf(stderr, _("%s: Error - unknown option \"%c\"."),
+ argv[0], argv[i][1]);
+ return (1);
+ }
+ else if (!strcmp(argv[i], "-"))
+ {
+ if (num_files || job_id)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - cannot print from stdin if files or a "
+ "job ID are provided."), argv[0]);
+ return (1);
+ }
+
+ break;
+ }
+ else if (num_files < 1000 && job_id == 0)
+ {
+ /*
+ * Print a file...
+ */
+
+ if (access(argv[i], R_OK) != 0)
+ {
+ _cupsLangPrintf(stderr, _("%s: Error - unable to access \"%s\" - %s"),
+ argv[0], 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, _("%s: Error - too many files - \"%s\"."),
+ argv[0], argv[i]);
+
+ /*
+ * See if we are altering an existing job...
+ */
+
+ if (job_id)
+ return (set_job_attrs(argv[0], job_id, num_options, options));
+
+ /*
+ * See if we have any files to print; if not, print from stdin...
+ */
+
+ if (printer == NULL)
+ {
+ if ((dest = cupsGetNamedDest(NULL, NULL, NULL)) != 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 && !cupsGetNamedDest(NULL, printer, NULL))
+ _cupsLangPrintf(stderr,
+ _("%s: Error - %s environment variable names "
+ "non-existent destination \"%s\"."), argv[0], val,
+ printer);
+ else if (cupsLastError() == IPP_NOT_FOUND)
+ _cupsLangPrintf(stderr,
+ _("%s: Error - no default destination available."),
+ argv[0]);
+ else
+ _cupsLangPrintf(stderr, _("%s: Error - scheduler not responding."),
+ argv[0]);
+
+ return (1);
+ }
+
+ if (num_files > 0)
+ job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options);
+ else if ((job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, printer,
+ title ? title : "(stdin)",
+ num_options, options)) > 0)
+ {
+ http_status_t status; /* Write status */
+ const char *format; /* Document format */
+ ssize_t bytes; /* Bytes read */
+
+
+ if (cupsGetOption("raw", num_options, options))
+ format = CUPS_FORMAT_RAW;
+ else if ((format = cupsGetOption("document-format", num_options,
+ options)) == NULL)
+ format = CUPS_FORMAT_AUTO;
+
+ status = cupsStartDocument(CUPS_HTTP_DEFAULT, printer, job_id, NULL,
+ format, 1);
+
+ while (status == HTTP_CONTINUE &&
+ (bytes = read(0, buffer, sizeof(buffer))) > 0)
+ status = cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, bytes);
+
+ if (status != HTTP_CONTINUE)
+ {
+ _cupsLangPrintf(stderr, _("%s: Error - unable to queue from stdin - %s."),
+ argv[0], httpStatus(status));
+ return (1);
+ }
+
+ if (cupsFinishDocument(CUPS_HTTP_DEFAULT, printer) != IPP_OK)
+ job_id = 0;
+ }
+
+ if (job_id < 1)
+ {
+ _cupsLangPrintf(stderr, "%s: %s", argv[0], cupsLastErrorString());
+ return (1);
+ }
+ else if (!silent)
+ _cupsLangPrintf(stdout, _("request id is %s-%d (%d file(s))"),
+ printer, job_id, num_files);
+
+ return (0);
+}
+
+
+/*
+ * 'restart_job()' - Restart a job.
+ */
+
+int /* O - Exit status */
+restart_job(const char *command, /* I - Command name */
+ int job_id) /* I - Job ID */
+{
+ ipp_t *request; /* IPP request */
+ char uri[HTTP_MAX_URI]; /* URI for job */
+
+
+ request = ippNewRequest(IPP_RESTART_JOB);
+
+ 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());
+
+ ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/jobs"));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'set_job_attrs()' - Set job attributes.
+ */
+
+int /* O - Exit status */
+set_job_attrs(const char *command, /* I - Command name */
+ int job_id, /* I - Job ID */
+ int num_options,/* I - Number of options */
+ cups_option_t *options) /* I - Options */
+{
+ ipp_t *request; /* IPP request */
+ char uri[HTTP_MAX_URI]; /* URI for job */
+
+
+ if (num_options == 0)
+ return (0);
+
+ request = ippNewRequest(IPP_SET_JOB_ATTRIBUTES);
+
+ 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());
+
+ cupsEncodeOptions(request, num_options, options);
+
+ ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/jobs"));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/lpadmin.c b/systemv/lpadmin.c
new file mode 100644
index 000000000..b1e04575c
--- /dev/null
+++ b/systemv/lpadmin.c
@@ -0,0 +1,1521 @@
+/*
+ * "$Id$"
+ *
+ * "lpadmin" command for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Parse options and configure the scheduler.
+ * add_printer_to_class() - Add a printer to a class.
+ * default_printer() - Set the default printing destination.
+ * delete_printer() - Delete a printer from the system.
+ * delete_printer_from_class() - Delete a printer from a class.
+ * delete_printer_option() - Delete a printer option.
+ * enable_printer() - Enable a printer.
+ * get_printer_type() - Determine the printer type and URI.
+ * set_printer_options() - Set the printer options and/or file.
+ * validate_name() - Make sure the printer name only contains
+ * valid chars.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * Local functions...
+ */
+
+static int add_printer_to_class(http_t *http, char *printer, char *pclass);
+static int default_printer(http_t *http, char *printer);
+static int delete_printer(http_t *http, char *printer);
+static int delete_printer_from_class(http_t *http, char *printer,
+ char *pclass);
+static int delete_printer_option(http_t *http, char *printer,
+ char *option);
+static int enable_printer(http_t *http, char *printer);
+static cups_ptype_t get_printer_type(http_t *http, char *printer, char *uri,
+ size_t urisize);
+static int set_printer_options(http_t *http, char *printer,
+ int num_options, cups_option_t *options,
+ char *file);
+static int validate_name(const char *name);
+
+
+/*
+ * 'main()' - Parse options and configure the scheduler.
+ */
+
+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 */
+ char *printer, /* Destination printer */
+ *pclass, /* Printer class name */
+ *val; /* Pointer to allow/deny value */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ char *file; /* New PPD file/interface script */
+
+
+ _cupsSetLocale(argv);
+
+ http = NULL;
+ printer = NULL;
+ num_options = 0;
+ options = NULL;
+ file = NULL;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1])
+ {
+ case 'c' : /* Add printer to class */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption());
+
+ if (http == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("lpadmin: Unable to connect to server: %s"),
+ strerror(errno));
+ return (1);
+ }
+ }
+
+ if (printer == NULL)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Unable to add a printer to the class:\n"
+ " You must specify a printer name "
+ "first."));
+ return (1);
+ }
+
+ if (argv[i][2])
+ pclass = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected class name after \"-c\" "
+ "option."));
+ return (1);
+ }
+
+ pclass = argv[i];
+ }
+
+ if (!validate_name(pclass))
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Class name can only contain printable "
+ "characters."));
+ return (1);
+ }
+
+ if (add_printer_to_class(http, printer, pclass))
+ return (1);
+ break;
+
+ case 'd' : /* Set as default destination */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption());
+
+ if (http == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("lpadmin: Unable to connect to server: %s"),
+ strerror(errno));
+ return (1);
+ }
+ }
+
+ if (argv[i][2])
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected printer name after \"-d\" "
+ "option."));
+ return (1);
+ }
+
+ printer = argv[i];
+ }
+
+ if (!validate_name(printer))
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Printer name can only contain "
+ "printable characters."));
+ return (1);
+ }
+
+ if (default_printer(http, printer))
+ return (1);
+
+ i = argc;
+ break;
+
+ case 'h' : /* Connect to host */
+ if (http)
+ {
+ httpClose(http);
+ http = NULL;
+ }
+
+ if (argv[i][2] != '\0')
+ cupsSetServer(argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected hostname after \"-h\" "
+ "option."));
+ return (1);
+ }
+
+ cupsSetServer(argv[i]);
+ }
+ break;
+
+ case 'i' : /* Use the specified interface script */
+ if (argv[i][2])
+ file = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected interface after \"-i\" "
+ "option."));
+ return (1);
+ }
+
+ file = argv[i];
+ }
+ break;
+
+ case 'E' : /* Enable the printer */
+ if (printer == NULL)
+ {
+#ifdef HAVE_SSL
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+
+ if (http)
+ httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
+#else
+ _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
+ argv[0]);
+#endif /* HAVE_SSL */
+ break;
+ }
+
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption());
+
+ if (http == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("lpadmin: Unable to connect to server: %s"),
+ strerror(errno));
+ return (1);
+ }
+ }
+
+ if (enable_printer(http, printer))
+ return (1);
+ break;
+
+ case 'm' : /* Use the specified standard script/PPD file */
+ if (argv[i][2])
+ num_options = cupsAddOption("ppd-name", argv[i] + 2, num_options,
+ &options);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected model after \"-m\" "
+ "option."));
+ return (1);
+ }
+
+ num_options = cupsAddOption("ppd-name", argv[i], num_options,
+ &options);
+ }
+ break;
+
+ case 'o' : /* Set option */
+ if (argv[i][2])
+ num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected name=value after \"-o\" "
+ "option."));
+ return (1);
+ }
+
+ num_options = cupsParseOptions(argv[i], num_options, &options);
+ }
+ break;
+
+ case 'p' : /* Add/modify a printer */
+ if (argv[i][2])
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected printer after \"-p\" "
+ "option."));
+ return (1);
+ }
+
+ printer = argv[i];
+ }
+
+ if (!validate_name(printer))
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Printer name can only contain "
+ "printable characters."));
+ return (1);
+ }
+ break;
+
+ case 'r' : /* Remove printer from class */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption());
+
+ if (http == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("lpadmin: Unable to connect to server: %s"),
+ strerror(errno));
+ return (1);
+ }
+ }
+
+ if (printer == NULL)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Unable to remove a printer from the "
+ "class:\n"
+ " You must specify a printer name "
+ "first."));
+ return (1);
+ }
+
+ if (argv[i][2])
+ pclass = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected class after \"-r\" "
+ "option."));
+ return (1);
+ }
+
+ pclass = argv[i];
+ }
+
+ if (!validate_name(pclass))
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Class name can only contain printable "
+ "characters."));
+ return (1);
+ }
+
+ if (delete_printer_from_class(http, printer, pclass))
+ return (1);
+ break;
+
+ case 'R' : /* Remove option */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption());
+
+ if (http == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("lpadmin: Unable to connect to server: %s"),
+ strerror(errno));
+ return (1);
+ }
+ }
+
+ if (printer == NULL)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Unable to delete option:\n"
+ " You must specify a printer name "
+ "first."));
+ return (1);
+ }
+
+ if (argv[i][2])
+ val = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected name after \"-R\" "
+ "option."));
+ return (1);
+ }
+
+ val = argv[i];
+ }
+
+ if (delete_printer_option(http, printer, val))
+ return (1);
+ break;
+
+ case 'U' : /* Username */
+ if (argv[i][2] != '\0')
+ cupsSetUser(argv[i] + 2);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected username after "
+ "\"-U\" option."), argv[0]);
+ return (1);
+ }
+
+ cupsSetUser(argv[i]);
+ }
+ break;
+
+ case 'u' : /* Allow/deny users */
+ if (argv[i][2])
+ val = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected allow/deny:userlist after "
+ "\"-u\" option."));
+ return (1);
+ }
+
+ val = argv[i];
+ }
+
+ if (!_cups_strncasecmp(val, "allow:", 6))
+ num_options = cupsAddOption("requesting-user-name-allowed",
+ val + 6, num_options, &options);
+ else if (!_cups_strncasecmp(val, "deny:", 5))
+ num_options = cupsAddOption("requesting-user-name-denied",
+ val + 5, num_options, &options);
+ else
+ {
+ _cupsLangPrintf(stderr,
+ _("lpadmin: Unknown allow/deny option \"%s\"."),
+ val);
+ return (1);
+ }
+ break;
+
+ case 'v' : /* Set the device-uri attribute */
+ if (argv[i][2])
+ num_options = cupsAddOption("device-uri", argv[i] + 2,
+ num_options, &options);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected device URI after \"-v\" "
+ "option."));
+ return (1);
+ }
+
+ num_options = cupsAddOption("device-uri", argv[i],
+ num_options, &options);
+ }
+ break;
+
+ case 'x' : /* Delete a printer */
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption());
+
+ if (http == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("lpadmin: Unable to connect to server: %s"),
+ strerror(errno));
+ return (1);
+ }
+ }
+
+ if (argv[i][2])
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected printer or class after "
+ "\"-x\" option."));
+ return (1);
+ }
+
+ printer = argv[i];
+ }
+
+ if (!validate_name(printer))
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Printer name can only contain "
+ "printable characters."));
+ return (1);
+ }
+
+ if (delete_printer(http, printer))
+ return (1);
+
+ i = argc;
+ break;
+
+ case 'D' : /* Set the printer-info attribute */
+ if (argv[i][2])
+ num_options = cupsAddOption("printer-info", argv[i] + 2,
+ num_options, &options);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected description after "
+ "\"-D\" option."));
+ return (1);
+ }
+
+ num_options = cupsAddOption("printer-info", argv[i],
+ num_options, &options);
+ }
+ break;
+
+ case 'I' : /* Set the supported file types (ignored) */
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected file type(s) after \"-I\" "
+ "option."));
+ return (1);
+ }
+
+ _cupsLangPuts(stderr,
+ _("lpadmin: Warning - content type list ignored."));
+ break;
+
+ case 'L' : /* Set the printer-location attribute */
+ if (argv[i][2])
+ num_options = cupsAddOption("printer-location", argv[i] + 2,
+ num_options, &options);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected location after \"-L\" "
+ "option."));
+ return (1);
+ }
+
+ num_options = cupsAddOption("printer-location", argv[i],
+ num_options, &options);
+ }
+ break;
+
+ case 'P' : /* Use the specified PPD file */
+ if (argv[i][2])
+ file = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Expected PPD after \"-P\" option."));
+ return (1);
+ }
+
+ file = argv[i];
+ }
+ break;
+
+ default :
+ _cupsLangPrintf(stderr,
+ _("lpadmin: Unknown option \"%c\"."), argv[i][1]);
+ return (1);
+ }
+ else
+ {
+ _cupsLangPrintf(stderr, _("lpadmin: Unknown argument \"%s\"."),
+ argv[i]);
+ return (1);
+ }
+
+ /*
+ * Set options as needed...
+ */
+
+ if (num_options || file)
+ {
+ if (!http)
+ {
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ if (http == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("lpadmin: Unable to connect to server: %s"),
+ strerror(errno));
+ return (1);
+ }
+ }
+
+ if (printer == NULL)
+ {
+ _cupsLangPuts(stderr,
+ _("lpadmin: Unable to set the printer options:\n"
+ " You must specify a printer name first."));
+ return (1);
+ }
+
+ if (set_printer_options(http, printer, num_options, options, file))
+ return (1);
+ }
+
+ if (printer == NULL)
+ {
+ _cupsLangPuts(stdout,
+ _("Usage:\n"
+ "\n"
+ " lpadmin [-h server] -d destination\n"
+ " lpadmin [-h server] -x destination\n"
+ " lpadmin [-h server] -p printer [-c add-class] "
+ "[-i interface] [-m model]\n"
+ " [-r remove-class] [-v device] "
+ "[-D description]\n"
+ " [-P ppd-file] [-o name=value]\n"
+ " [-u allow:user,user] "
+ "[-u deny:user,user]"));
+ }
+
+ if (http)
+ httpClose(http);
+
+ return (0);
+}
+
+
+/*
+ * 'add_printer_to_class()' - Add a printer to a class.
+ */
+
+static int /* O - 0 on success, 1 on fail */
+add_printer_to_class(http_t *http, /* I - Server connection */
+ char *printer, /* I - Printer to add */
+ char *pclass) /* I - Class to add to */
+{
+ int i; /* Looping var */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr, /* Current attribute */
+ *members; /* Members in class */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ DEBUG_printf(("add_printer_to_class(%p, \"%s\", \"%s\")\n", http,
+ printer, pclass));
+
+ /*
+ * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ */
+
+ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/classes/%s", pclass);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ response = cupsDoRequest(http, request, "/");
+
+ /*
+ * Build a CUPS_ADD_MODIFY_CLASS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ * member-uris
+ */
+
+ request = ippNewRequest(CUPS_ADD_MODIFY_CLASS);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ /*
+ * See if the printer is already in the class...
+ */
+
+ if (response != NULL &&
+ (members = ippFindAttribute(response, "member-names",
+ IPP_TAG_NAME)) != NULL)
+ for (i = 0; i < members->num_values; i ++)
+ if (_cups_strcasecmp(printer, members->values[i].string.text) == 0)
+ {
+ _cupsLangPrintf(stderr,
+ _("lpadmin: Printer %s is already a member of class "
+ "%s."), printer, pclass);
+ ippDelete(request);
+ ippDelete(response);
+ return (0);
+ }
+
+ /*
+ * OK, the printer isn't part of the class, so add it...
+ */
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/printers/%s", printer);
+
+ if (response != NULL &&
+ (members = ippFindAttribute(response, "member-uris",
+ IPP_TAG_URI)) != NULL)
+ {
+ /*
+ * Add the printer to the existing list...
+ */
+
+ attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "member-uris", members->num_values + 1, NULL, NULL);
+ for (i = 0; i < members->num_values; i ++)
+ attr->values[i].string.text =
+ _cupsStrAlloc(members->values[i].string.text);
+
+ attr->values[i].string.text = _cupsStrAlloc(uri);
+ }
+ else
+ ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", NULL,
+ uri);
+
+ /*
+ * Then send the request...
+ */
+
+ ippDelete(response);
+
+ ippDelete(cupsDoRequest(http, request, "/admin/"));
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
+
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/*
+ * 'default_printer()' - Set the default printing destination.
+ */
+
+static int /* O - 0 on success, 1 on fail */
+default_printer(http_t *http, /* I - Server connection */
+ char *printer) /* I - Printer name */
+{
+ ipp_t *request; /* IPP Request */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ DEBUG_printf(("default_printer(%p, \"%s\")\n", http, printer));
+
+ /*
+ * Build a CUPS_SET_DEFAULT request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ */
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/printers/%s", printer);
+
+ request = ippNewRequest(CUPS_SET_DEFAULT);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ippDelete(cupsDoRequest(http, request, "/admin/"));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
+
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/*
+ * 'delete_printer()' - Delete a printer from the system...
+ */
+
+static int /* O - 0 on success, 1 on fail */
+delete_printer(http_t *http, /* I - Server connection */
+ char *printer) /* I - Printer to delete */
+{
+ ipp_t *request; /* IPP Request */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ DEBUG_printf(("delete_printer(%p, \"%s\")\n", http, printer));
+
+ /*
+ * Build a CUPS_DELETE_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ */
+
+ request = ippNewRequest(CUPS_DELETE_PRINTER);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/printers/%s", printer);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ippDelete(cupsDoRequest(http, request, "/admin/"));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
+
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/*
+ * 'delete_printer_from_class()' - Delete a printer from a class.
+ */
+
+static int /* O - 0 on success, 1 on fail */
+delete_printer_from_class(
+ http_t *http, /* I - Server connection */
+ char *printer, /* I - Printer to remove */
+ char *pclass) /* I - Class to remove from */
+{
+ int i, j, k; /* Looping vars */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr, /* Current attribute */
+ *members; /* Members in class */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ DEBUG_printf(("delete_printer_from_class(%p, \"%s\", \"%s\")\n", http,
+ printer, pclass));
+
+ /*
+ * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ */
+
+ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", 0, "/classes/%s", pclass);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/classes/")) == NULL ||
+ response->request.status.status_code == IPP_NOT_FOUND)
+ {
+ _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
+
+ ippDelete(response);
+
+ return (1);
+ }
+
+ /*
+ * See if the printer is already in the class...
+ */
+
+ if ((members = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) == NULL)
+ {
+ _cupsLangPuts(stderr, _("lpadmin: No member names were seen."));
+
+ ippDelete(response);
+
+ return (1);
+ }
+
+ for (i = 0; i < members->num_values; i ++)
+ if (!_cups_strcasecmp(printer, members->values[i].string.text))
+ break;
+
+ if (i >= members->num_values)
+ {
+ _cupsLangPrintf(stderr,
+ _("lpadmin: Printer %s is not a member of class %s."),
+ printer, pclass);
+
+ ippDelete(response);
+
+ return (1);
+ }
+
+ if (members->num_values == 1)
+ {
+ /*
+ * Build a CUPS_DELETE_CLASS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ */
+
+ request = ippNewRequest(CUPS_DELETE_CLASS);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, cupsUser());
+ }
+ else
+ {
+ /*
+ * Build a CUPS_ADD_MODIFY_CLASS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ * member-uris
+ */
+
+ request = ippNewRequest(CUPS_ADD_MODIFY_CLASS);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, cupsUser());
+
+ /*
+ * Delete the printer from the class...
+ */
+
+ members = ippFindAttribute(response, "member-uris", IPP_TAG_URI);
+ attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "member-uris", members->num_values - 1, NULL, NULL);
+
+ for (j = 0, k = 0; j < members->num_values; j ++)
+ if (j != i)
+ attr->values[k ++].string.text =
+ _cupsStrAlloc(members->values[j].string.text);
+ }
+
+ /*
+ * Then send the request...
+ */
+
+ ippDelete(response);
+
+ ippDelete(cupsDoRequest(http, request, "/admin/"));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
+
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/*
+ * 'delete_printer_option()' - Delete a printer option.
+ */
+
+static int /* O - 0 on success, 1 on fail */
+delete_printer_option(http_t *http, /* I - Server connection */
+ char *printer, /* I - Printer */
+ char *option) /* I - Option to delete */
+{
+ ipp_t *request; /* IPP request */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ /*
+ * Build a CUPS_ADD_MODIFY_PRINTER or CUPS_ADD_MODIFY_CLASS request, which
+ * requires the following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ * option with deleteAttr tag
+ */
+
+ if (get_printer_type(http, printer, uri, sizeof(uri)) &
+ (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ request = ippNewRequest(CUPS_ADD_MODIFY_CLASS);
+ else
+ request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, cupsUser());
+ ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_DELETEATTR, option, 0);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ippDelete(cupsDoRequest(http, request, "/admin/"));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
+
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/*
+ * 'enable_printer()' - Enable a printer...
+ */
+
+static int /* O - 0 on success, 1 on fail */
+enable_printer(http_t *http, /* I - Server connection */
+ char *printer) /* I - Printer to enable */
+{
+ ipp_t *request; /* IPP Request */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ DEBUG_printf(("enable_printer(%p, \"%s\")\n", http, printer));
+
+ /*
+ * Build a CUPS_ADD_MODIFY_PRINTER or CUPS_ADD_MODIFY_CLASS request, which
+ * require the following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ * printer-state
+ * printer-is-accepting-jobs
+ */
+
+ if (get_printer_type(http, printer, uri, sizeof(uri)) &
+ (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ request = ippNewRequest(CUPS_ADD_MODIFY_CLASS);
+ else
+ request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, cupsUser());
+ ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
+ IPP_PRINTER_IDLE);
+ ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ippDelete(cupsDoRequest(http, request, "/admin/"));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
+
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/*
+ * 'get_printer_type()' - Determine the printer type and URI.
+ */
+
+static cups_ptype_t /* O - printer-type value */
+get_printer_type(http_t *http, /* I - Server connection */
+ char *printer, /* I - Printer name */
+ char *uri, /* I - URI buffer */
+ size_t urisize) /* I - Size of URI buffer */
+{
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* printer-type attribute */
+ cups_ptype_t type; /* printer-type value */
+
+
+ /*
+ * Build a GET_PRINTER_ATTRIBUTES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requested-attributes
+ * requesting-user-name
+ */
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, urisize, "ipp", NULL, "localhost",
+ ippPort(), "/printers/%s", printer);
+
+ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "printer-type");
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, cupsUser());
+
+ /*
+ * Do the request...
+ */
+
+ response = cupsDoRequest(http, request, "/");
+ if ((attr = ippFindAttribute(response, "printer-type",
+ IPP_TAG_ENUM)) != NULL)
+ {
+ type = (cups_ptype_t)attr->values[0].integer;
+
+ if (type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, urisize, "ipp", NULL,
+ "localhost", ippPort(), "/classes/%s", printer);
+ }
+ else
+ type = CUPS_PRINTER_LOCAL;
+
+ ippDelete(response);
+
+ return (type);
+}
+
+
+/*
+ * 'set_printer_options()' - Set the printer options.
+ */
+
+static int /* O - 0 on success, 1 on fail */
+set_printer_options(
+ http_t *http, /* I - Server connection */
+ char *printer, /* I - Printer */
+ int num_options, /* I - Number of options */
+ cups_option_t *options, /* I - Options */
+ char *file) /* I - PPD file/interface script */
+{
+ ipp_t *request; /* IPP Request */
+ const char *ppdfile; /* PPD filename */
+ int ppdchanged; /* PPD changed? */
+ ppd_file_t *ppd; /* PPD file */
+ ppd_choice_t *choice; /* Marked choice */
+ char uri[HTTP_MAX_URI], /* URI for printer/class */
+ line[1024], /* Line from PPD file */
+ keyword[1024], /* Keyword from Default line */
+ *keyptr, /* Pointer into keyword... */
+ tempfile[1024]; /* Temporary filename */
+ cups_file_t *in, /* PPD file */
+ *out; /* Temporary file */
+ const char *protocol, /* Old protocol option */
+ *customval, /* Custom option value */
+ *boolval; /* Boolean value */
+ int wrote_ipp_supplies = 0, /* Wrote cupsIPPSupplies keyword? */
+ wrote_snmp_supplies = 0;/* Wrote cupsSNMPSupplies keyword? */
+
+
+ DEBUG_printf(("set_printer_options(http=%p, printer=\"%s\", num_options=%d, "
+ "options=%p, file=\"%s\")\n", http, printer, num_options,
+ options, file));
+
+ /*
+ * Build a CUPS_ADD_MODIFY_PRINTER or CUPS_ADD_MODIFY_CLASS request, which
+ * requires the following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ * other options
+ */
+
+ if (get_printer_type(http, printer, uri, sizeof(uri)) &
+ (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ request = ippNewRequest(CUPS_ADD_MODIFY_CLASS);
+ else
+ request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, cupsUser());
+
+ /*
+ * Add the options...
+ */
+
+ cupsEncodeOptions2(request, num_options, options, IPP_TAG_PRINTER);
+
+ if ((protocol = cupsGetOption("protocol", num_options, options)) != NULL)
+ {
+ if (!_cups_strcasecmp(protocol, "bcp"))
+ ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
+ NULL, "bcp");
+ else if (!_cups_strcasecmp(protocol, "tbcp"))
+ ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
+ NULL, "tbcp");
+ }
+
+ if (file)
+ ppdfile = file;
+ else if (request->request.op.operation_id == CUPS_ADD_MODIFY_PRINTER)
+ ppdfile = cupsGetPPD(printer);
+ else
+ ppdfile = NULL;
+
+ if (ppdfile != NULL)
+ {
+ /*
+ * Set default options in the PPD file...
+ */
+
+ ppd = ppdOpenFile(ppdfile);
+ ppdMarkDefaults(ppd);
+ cupsMarkOptions(ppd, num_options, options);
+
+ if ((out = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL)
+ {
+ _cupsLangPrintError(NULL, _("lpadmin: Unable to create temporary file"));
+ ippDelete(request);
+ if (ppdfile != file)
+ unlink(ppdfile);
+ return (1);
+ }
+
+ if ((in = cupsFileOpen(ppdfile, "r")) == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("lpadmin: Unable to open PPD file \"%s\" - %s"),
+ ppdfile, strerror(errno));
+ ippDelete(request);
+ if (ppdfile != file)
+ unlink(ppdfile);
+ cupsFileClose(out);
+ unlink(tempfile);
+ return (1);
+ }
+
+ ppdchanged = 0;
+
+ while (cupsFileGets(in, line, sizeof(line)))
+ {
+ if (!strncmp(line, "*cupsIPPSupplies:", 17) &&
+ (boolval = cupsGetOption("cupsIPPSupplies", num_options,
+ options)) != NULL)
+ {
+ wrote_ipp_supplies = 1;
+ cupsFilePrintf(out, "*cupsIPPSupplies: %s\n",
+ (!_cups_strcasecmp(boolval, "true") ||
+ !_cups_strcasecmp(boolval, "yes") ||
+ !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
+ }
+ else if (!strncmp(line, "*cupsSNMPSupplies:", 18) &&
+ (boolval = cupsGetOption("cupsSNMPSupplies", num_options,
+ options)) != NULL)
+ {
+ wrote_snmp_supplies = 1;
+ cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n",
+ (!_cups_strcasecmp(boolval, "true") ||
+ !_cups_strcasecmp(boolval, "yes") ||
+ !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
+ }
+ 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';
+ while (isspace(*keyptr & 255))
+ keyptr ++;
+
+ if (!strcmp(keyword, "PageRegion") ||
+ !strcmp(keyword, "PageSize") ||
+ !strcmp(keyword, "PaperDimension") ||
+ !strcmp(keyword, "ImageableArea"))
+ {
+ if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) == NULL)
+ choice = ppdFindMarkedChoice(ppd, "PageRegion");
+ }
+ else
+ choice = ppdFindMarkedChoice(ppd, keyword);
+
+ if (choice && strcmp(choice->choice, keyptr))
+ {
+ if (strcmp(choice->choice, "Custom"))
+ {
+ cupsFilePrintf(out, "*Default%s: %s\n", keyword, choice->choice);
+ ppdchanged = 1;
+ }
+ else if ((customval = cupsGetOption(keyword, num_options,
+ options)) != NULL)
+ {
+ cupsFilePrintf(out, "*Default%s: %s\n", keyword, customval);
+ ppdchanged = 1;
+ }
+ else
+ cupsFilePrintf(out, "%s\n", line);
+ }
+ else
+ cupsFilePrintf(out, "%s\n", line);
+ }
+ }
+
+ if (!wrote_ipp_supplies &&
+ (boolval = cupsGetOption("cupsIPPSupplies", num_options,
+ options)) != NULL)
+ {
+ cupsFilePrintf(out, "*cupsIPPSupplies: %s\n",
+ (!_cups_strcasecmp(boolval, "true") ||
+ !_cups_strcasecmp(boolval, "yes") ||
+ !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
+ }
+
+ if (!wrote_snmp_supplies &&
+ (boolval = cupsGetOption("cupsSNMPSupplies", num_options,
+ options)) != NULL)
+ {
+ cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n",
+ (!_cups_strcasecmp(boolval, "true") ||
+ !_cups_strcasecmp(boolval, "yes") ||
+ !_cups_strcasecmp(boolval, "on")) ? "True" : "False");
+ }
+
+ cupsFileClose(in);
+ cupsFileClose(out);
+ ppdClose(ppd);
+
+ /*
+ * Do the request...
+ */
+
+ ippDelete(cupsDoFileRequest(http, request, "/admin/",
+ ppdchanged ? tempfile : file));
+
+ /*
+ * Clean up temp files... (TODO: catch signals in case we CTRL-C during
+ * lpadmin)
+ */
+
+ if (ppdfile != file)
+ unlink(ppdfile);
+ unlink(tempfile);
+ }
+ else
+ {
+ /*
+ * No PPD file - just set the options...
+ */
+
+ ippDelete(cupsDoRequest(http, request, "/admin/"));
+ }
+
+ /*
+ * Check the response...
+ */
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString());
+
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/*
+ * 'validate_name()' - Make sure the printer name only contains valid chars.
+ */
+
+static int /* O - 0 if name is no good, 1 if name is good */
+validate_name(const char *name) /* I - Name to check */
+{
+ const char *ptr; /* Pointer into name */
+
+
+ /*
+ * Scan the whole name...
+ */
+
+ for (ptr = name; *ptr; ptr ++)
+ if (*ptr == '@')
+ break;
+ else if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' ||
+ *ptr == '#')
+ return (0);
+
+ /*
+ * All the characters are good; validate the length, too...
+ */
+
+ return ((ptr - name) < 128);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/lpinfo.c b/systemv/lpinfo.c
new file mode 100644
index 000000000..acfe50108
--- /dev/null
+++ b/systemv/lpinfo.c
@@ -0,0 +1,498 @@
+/*
+ * "$Id$"
+ *
+ * "lpinfo" command for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Parse options and show information.
+ * device_cb - Device callback.
+ * show_devices() - Show available devices.
+ * show_models() - Show available PPDs.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * Local functions...
+ */
+
+static void device_cb(const char *device_clas, const char *device_id,
+ const char *device_info,
+ const char *device_make_and_model,
+ const char *device_uri, const char *device_location,
+ void *user_data);
+static int show_devices(int long_status, int timeout,
+ const char *include_schemes,
+ const char *exclude_schemes);
+static int show_models(int long_status,
+ const char *device_id, const char *language,
+ const char *make_model, const char *product,
+ const char *include_schemes,
+ const char *exclude_schemes);
+
+
+/*
+ * 'main()' - Parse options and show status information.
+ */
+
+int
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ int long_status; /* Long listing? */
+ const char *device_id, /* 1284 device ID */
+ *language, /* Language */
+ *make_model, /* Make and model */
+ *product, /* Product */
+ *include_schemes, /* Schemes to include */
+ *exclude_schemes; /* Schemes to exclude */
+ int timeout; /* Device timeout */
+
+
+ _cupsSetLocale(argv);
+
+ long_status = 0;
+ device_id = NULL;
+ language = NULL;
+ make_model = NULL;
+ product = NULL;
+ include_schemes = CUPS_INCLUDE_ALL;
+ exclude_schemes = CUPS_EXCLUDE_NONE;
+ timeout = CUPS_TIMEOUT_DEFAULT;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1])
+ {
+ case 'E' : /* Encrypt */
+#ifdef HAVE_SSL
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+#else
+ _cupsLangPrintf(stderr,
+ _("%s: Sorry, no encryption support."),
+ argv[0]);
+#endif /* HAVE_SSL */
+ break;
+
+ case 'h' : /* Connect to host */
+ if (argv[i][2] != '\0')
+ cupsSetServer(argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("Error: need hostname after \"-h\" option."));
+ return (1);
+ }
+
+ cupsSetServer(argv[i]);
+ }
+ break;
+
+ case 'l' : /* Show long listing */
+ long_status = 1;
+ break;
+
+ case 'm' : /* Show models */
+ if (show_models(long_status, device_id, language, make_model,
+ product, include_schemes, exclude_schemes))
+ return (1);
+ break;
+
+ case 'v' : /* Show available devices */
+ if (show_devices(long_status, timeout, include_schemes,
+ exclude_schemes))
+ return (1);
+ break;
+
+ case '-' : /* --something */
+ if (!strcmp(argv[i], "--device-id"))
+ {
+ i ++;
+
+ if (i < argc)
+ device_id = argv[i];
+ else
+ {
+ _cupsLangPuts(stderr,
+ _("lpinfo: Expected 1284 device ID string "
+ "after \"--device-id\"."));
+ return (1);
+ }
+ }
+ else if (!strncmp(argv[i], "--device-id=", 12) && argv[i][12])
+ {
+ device_id = argv[i] + 12;
+ }
+ else if (!strcmp(argv[i], "--exclude-schemes"))
+ {
+ i ++;
+
+ if (i < argc)
+ exclude_schemes = argv[i];
+ else
+ {
+ _cupsLangPuts(stderr,
+ _("lpinfo: Expected scheme list after "
+ "\"--exclude-schemes\"."));
+ return (1);
+ }
+ }
+ else if (!strncmp(argv[i], "--exclude-schemes=", 18) && argv[i][18])
+ {
+ exclude_schemes = argv[i] + 18;
+ }
+ else if (!strcmp(argv[i], "--include-schemes"))
+ {
+ i ++;
+
+ if (i < argc)
+ include_schemes = argv[i];
+ else
+ {
+ _cupsLangPuts(stderr,
+ _("lpinfo: Expected scheme list after "
+ "\"--include-schemes\"."));
+ return (1);
+ }
+ }
+ else if (!strncmp(argv[i], "--include-schemes=", 18) && argv[i][18])
+ {
+ include_schemes = argv[i] + 18;
+ }
+ else if (!strcmp(argv[i], "--language"))
+ {
+ i ++;
+ if (i < argc)
+ language = argv[i];
+ else
+ {
+ _cupsLangPuts(stderr,
+ _("lpinfo: Expected language after "
+ "\"--language\"."));
+ return (1);
+ }
+ }
+ else if (!strncmp(argv[i], "--language=", 11) && argv[i][11])
+ {
+ language = argv[i] + 11;
+ }
+ else if (!strcmp(argv[i], "--make-and-model"))
+ {
+ i ++;
+ if (i < argc)
+ make_model= argv[i];
+ else
+ {
+ _cupsLangPuts(stderr,
+ _("lpinfo: Expected make and model after "
+ "\"--make-and-model\"."));
+ return (1);
+ }
+ }
+ else if (!strncmp(argv[i], "--make-and-model=", 17) && argv[i][17])
+ {
+ make_model = argv[i] + 17;
+ }
+ else if (!strcmp(argv[i], "--product"))
+ {
+ i ++;
+ if (i < argc)
+ product = argv[i];
+ else
+ {
+ _cupsLangPuts(stderr,
+ _("lpinfo: Expected product string after "
+ "\"--product\"."));
+ return (1);
+ }
+ }
+ else if (!strncmp(argv[i], "--product=", 10) && argv[i][10])
+ {
+ product = argv[i] + 10;
+ }
+ else if (!strcmp(argv[i], "--timeout"))
+ {
+ i ++;
+ if (i < argc)
+ timeout = atoi(argv[i]);
+ else
+ {
+ _cupsLangPuts(stderr,
+ _("lpinfo: Expected timeout after "
+ "\"--timeout\"."));
+ return (1);
+ }
+ }
+ else if (!strncmp(argv[i], "--timeout=", 10) && argv[i][10])
+ {
+ timeout = atoi(argv[i] + 10);
+ }
+ else
+ {
+ _cupsLangPrintf(stderr, _("lpinfo: Unknown option \"%s\"."),
+ argv[i]);
+ return (1);
+ }
+ break;
+
+ default :
+ _cupsLangPrintf(stderr, _("lpinfo: Unknown option \"%c\"."),
+ argv[i][1]);
+ return (1);
+ }
+ else
+ {
+ _cupsLangPrintf(stderr, _("lpinfo: Unknown argument \"%s\"."),
+ argv[i]);
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'device_cb()' - Device callback.
+ */
+
+static void
+device_cb(
+ const char *device_class, /* I - device-class string */
+ const char *device_id, /* I - device-id string */
+ const char *device_info, /* I - device-info string */
+ const char *device_make_and_model, /* I - device-make-and-model string */
+ const char *device_uri, /* I - device-uri string */
+ const char *device_location, /* I - device-location string */
+ void *user_data) /* I - User data */
+{
+ int *long_status; /* Show verbose info? */
+
+
+ /*
+ * Display the device...
+ */
+
+ long_status = (int *)user_data;
+
+ if (*long_status)
+ {
+ _cupsLangPrintf(stdout,
+ _("Device: uri = %s\n"
+ " class = %s\n"
+ " info = %s\n"
+ " make-and-model = %s\n"
+ " device-id = %s\n"
+ " location = %s"),
+ device_uri, device_class, device_info,
+ device_make_and_model, device_id, device_location);
+ }
+ else
+ _cupsLangPrintf(stdout, "%s %s", device_class, device_uri);
+}
+
+
+/*
+ * 'show_devices()' - Show available devices.
+ */
+
+static int /* O - 0 on success, 1 on failure */
+show_devices(
+ int long_status, /* I - Long status report? */
+ int timeout, /* I - Timeout */
+ const char *include_schemes, /* I - List of schemes to include */
+ const char *exclude_schemes) /* I - List of schemes to exclude */
+{
+ if (cupsGetDevices(CUPS_HTTP_DEFAULT, timeout, include_schemes,
+ exclude_schemes, device_cb, &long_status) != IPP_OK)
+ {
+ _cupsLangPrintf(stderr, "lpinfo: %s", cupsLastErrorString());
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'show_models()' - Show available PPDs.
+ */
+
+static int /* O - 0 on success, 1 on failure */
+show_models(
+ int long_status, /* I - Long status report? */
+ const char *device_id, /* I - 1284 device ID */
+ const char *language, /* I - Language */
+ const char *make_model, /* I - Make and model */
+ const char *product, /* I - Product */
+ const char *include_schemes, /* I - List of schemes to include */
+ const char *exclude_schemes) /* I - List of schemes to exclude */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *ppd_device_id, /* Pointer to ppd-device-id */
+ *ppd_language, /* Pointer to ppd-natural-language */
+ *ppd_make_model, /* Pointer to ppd-make-and-model */
+ *ppd_name; /* Pointer to ppd-name */
+ cups_option_t option; /* in/exclude-schemes option */
+
+
+ /*
+ * Build a CUPS_GET_PPDS request...
+ */
+
+ request = ippNewRequest(CUPS_GET_PPDS);
+
+ if (device_id)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-device-id",
+ NULL, device_id);
+ if (language)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "ppd-language",
+ NULL, language);
+ if (make_model)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-make-and-model",
+ NULL, make_model);
+ if (product)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-product",
+ NULL, product);
+
+ if (include_schemes)
+ {
+ option.name = "include-schemes";
+ option.value = (char *)include_schemes;
+
+ cupsEncodeOptions2(request, 1, &option, IPP_TAG_OPERATION);
+ }
+
+ if (exclude_schemes)
+ {
+ option.name = "exclude-schemes";
+ option.value = (char *)exclude_schemes;
+
+ cupsEncodeOptions2(request, 1, &option, IPP_TAG_OPERATION);
+ }
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
+ {
+ /*
+ * Loop through the device list and display them...
+ */
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, "lpinfo: %s", cupsLastErrorString());
+ ippDelete(response);
+ return (1);
+ }
+
+ for (attr = response->attrs; attr != NULL; attr = attr->next)
+ {
+ /*
+ * Skip leading attributes until we hit a PPD...
+ */
+
+ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+ attr = attr->next;
+
+ if (attr == NULL)
+ break;
+
+ /*
+ * Pull the needed attributes from this PPD...
+ */
+
+ ppd_device_id = "NONE";
+ ppd_language = NULL;
+ ppd_make_model = NULL;
+ ppd_name = NULL;
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
+ {
+ if (!strcmp(attr->name, "ppd-device-id") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ ppd_device_id = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "ppd-natural-language") &&
+ attr->value_tag == IPP_TAG_LANGUAGE)
+ ppd_language = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "ppd-make-and-model") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ ppd_make_model = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "ppd-name") &&
+ attr->value_tag == IPP_TAG_NAME)
+ ppd_name = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (ppd_language == NULL || ppd_make_model == NULL || ppd_name == NULL)
+ {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ /*
+ * Display the device...
+ */
+
+ if (long_status)
+ {
+ _cupsLangPrintf(stdout,
+ _("Model: name = %s\n"
+ " natural_language = %s\n"
+ " make-and-model = %s\n"
+ " device-id = %s"),
+ ppd_name, ppd_language, ppd_make_model, ppd_device_id);
+ }
+ else
+ _cupsLangPrintf(stdout, "%s %s", ppd_name, ppd_make_model);
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ _cupsLangPrintf(stderr, "lpinfo: %s", cupsLastErrorString());
+
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/lpmove.c b/systemv/lpmove.c
new file mode 100644
index 000000000..54424894f
--- /dev/null
+++ b/systemv/lpmove.c
@@ -0,0 +1,213 @@
+/*
+ * "$Id$"
+ *
+ * "lpmove" command for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Parse options and move jobs.
+ * move_job() - Move a job.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * Local functions...
+ */
+
+static int move_job(http_t *http, const char *src, int jobid,
+ const char *dest);
+
+
+/*
+ * 'main()' - Parse options and show status information.
+ */
+
+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 *job; /* Job name */
+ int jobid; /* Job ID */
+ int num_dests; /* Number of destinations */
+ cups_dest_t *dests; /* Destinations */
+ const char *src, /* Original queue */
+ *dest; /* New destination */
+
+
+ _cupsSetLocale(argv);
+
+ dest = NULL;
+ dests = NULL;
+ job = NULL;
+ jobid = 0;
+ num_dests = 0;
+ src = NULL;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1])
+ {
+ case 'E' : /* Encrypt */
+#ifdef HAVE_SSL
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+
+#else
+ _cupsLangPrintf(stderr,
+ _("%s: Sorry, no encryption support."),
+ argv[0]);
+#endif /* HAVE_SSL */
+ break;
+
+ case 'h' : /* Connect to host */
+ if (argv[i][2] != '\0')
+ cupsSetServer(argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("Error: need hostname after \"-h\" option."));
+ return (1);
+ }
+
+ cupsSetServer(argv[i]);
+ }
+ break;
+
+ default :
+ _cupsLangPrintf(stderr, _("lpmove: Unknown option \"%c\"."),
+ argv[i][1]);
+ return (1);
+ }
+ else if (!jobid && !src)
+ {
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if ((job = strrchr(argv[i], '-')) != NULL &&
+ cupsGetDest(argv[i], NULL, num_dests, dests) == NULL)
+ jobid = atoi(job + 1);
+ else if (isdigit(argv[i][0] & 255) &&
+ !cupsGetDest(argv[i], NULL, num_dests, dests))
+ jobid = atoi(argv[i]);
+ else
+ src = argv[i];
+ }
+ else if (dest == NULL)
+ dest = argv[i];
+ else
+ {
+ _cupsLangPrintf(stderr, _("lpmove: Unknown argument \"%s\"."), argv[i]);
+ return (1);
+ }
+
+ if ((!jobid && !src) || !dest)
+ {
+ _cupsLangPuts(stdout, _("Usage: lpmove job/src dest"));
+ return (1);
+ }
+
+ http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
+
+ if (http == NULL)
+ {
+ _cupsLangPrintf(stderr, _("lpmove: Unable to connect to server: %s"),
+ strerror(errno));
+ return (1);
+ }
+
+ return (move_job(http, src, jobid, dest));
+}
+
+
+/*
+ * 'move_job()' - Move a job.
+ */
+
+static int /* O - 0 on success, 1 on error */
+move_job(http_t *http, /* I - HTTP connection to server */
+ const char *src, /* I - Source queue */
+ int jobid, /* I - Job ID */
+ const char *dest) /* I - Destination queue */
+{
+ ipp_t *request; /* IPP Request */
+ char job_uri[HTTP_MAX_URI], /* job-uri */
+ printer_uri[HTTP_MAX_URI]; /* job-printer-uri */
+
+
+ if (!http)
+ return (1);
+
+ /*
+ * Build a CUPS_MOVE_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * job-uri/printer-uri
+ * job-printer-uri
+ * requesting-user-name
+ */
+
+ request = ippNewRequest(CUPS_MOVE_JOB);
+
+ if (jobid)
+ {
+ snprintf(job_uri, sizeof(job_uri), "ipp://localhost/jobs/%d", jobid);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL,
+ job_uri);
+ }
+ else
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL,
+ "localhost", 0, "/printers/%s", src);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
+ job_uri);
+ }
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
+ "ipp", NULL, "localhost", 0, "/printers/%s", dest);
+ ippAddString(request, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri",
+ NULL, printer_uri);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ ippDelete(cupsDoRequest(http, request, "/jobs"));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, "lpmove: %s", cupsLastErrorString());
+ return (1);
+ }
+ else
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/lpoptions.c b/systemv/lpoptions.c
new file mode 100644
index 000000000..907a39dee
--- /dev/null
+++ b/systemv/lpoptions.c
@@ -0,0 +1,565 @@
+/*
+ * "$Id$"
+ *
+ * Printer option program for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Main entry.
+ * list_group() - List printer-specific options from the PPD group.
+ * list_options() - List printer-specific options from the PPD file.
+ * usage() - Show program usage and exit.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * Local functions...
+ */
+
+static void list_group(ppd_file_t *ppd, ppd_group_t *group);
+static void list_options(cups_dest_t *dest);
+static void usage(void);
+
+
+/*
+ * 'main()' - Main entry.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i, j; /* Looping vars */
+ int changes; /* Did we make changes? */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ int num_dests; /* Number of destinations */
+ cups_dest_t *dests; /* Destinations */
+ cups_dest_t *dest; /* Current destination */
+ char *printer, /* Printer name */
+ *instance, /* Instance name */
+ *option; /* Current option */
+
+
+ _cupsSetLocale(argv);
+
+ /*
+ * Loop through the command-line arguments...
+ */
+
+ dest = NULL;
+ num_dests = 0;
+ dests = NULL;
+ num_options = 0;
+ options = NULL;
+ changes = 0;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'd' : /* -d printer */
+ if (argv[i][2])
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ printer = argv[i];
+ }
+
+ if ((instance = strrchr(printer, '/')) != NULL)
+ *instance++ = '\0';
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if (num_dests == 0 || !dests ||
+ (dest = cupsGetDest(printer, instance, num_dests,
+ dests)) == NULL)
+ {
+ _cupsLangPuts(stderr, _("lpoptions: Unknown printer or class."));
+ return (1);
+ }
+
+ /*
+ * Set the default destination...
+ */
+
+ for (j = 0; j < num_dests; j ++)
+ dests[j].is_default = 0;
+
+ dest->is_default = 1;
+
+ cupsSetDests(num_dests, dests);
+
+ 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 'h' : /* -h server */
+ if (argv[i][2])
+ cupsSetServer(argv[i] + 2);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ cupsSetServer(argv[i]);
+ }
+ break;
+
+ case 'E' : /* Encrypt connection */
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+ break;
+
+ case 'l' : /* -l (list options) */
+ if (dest == NULL)
+ {
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
+ dest = dests;
+ }
+
+ if (dest == NULL)
+ _cupsLangPuts(stderr, _("lpoptions: No printers."));
+ else
+ list_options(dest);
+
+ changes = -1;
+ break;
+
+ case 'o' : /* -o option[=value] */
+ if (dest == NULL)
+ {
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
+ dest = dests;
+
+ if (dest == NULL)
+ {
+ _cupsLangPuts(stderr, _("lpoptions: No printers."));
+ return (1);
+ }
+
+ 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 (argv[i][2])
+ num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ num_options = cupsParseOptions(argv[i], num_options, &options);
+ }
+
+ changes = 1;
+ break;
+
+ case 'p' : /* -p printer */
+ if (argv[i][2])
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ 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)
+ {
+ num_dests = cupsAddDest(printer, instance, num_dests, &dests);
+ dest = cupsGetDest(printer, instance, num_dests, dests);
+
+ if (dest == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("lpoptions: Unable to add printer or "
+ "instance: %s"),
+ strerror(errno));
+ return (1);
+ }
+ }
+
+ 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 'r' : /* -r option (remove) */
+ if (dest == NULL)
+ {
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
+ dest = dests;
+
+ if (dest == NULL)
+ {
+ _cupsLangPuts(stderr, _("lpoptions: No printers."));
+ return (1);
+ }
+
+ 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 (argv[i][2])
+ option = argv[i] + 2;
+ else
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ option = argv[i];
+ }
+
+ for (j = 0; j < num_options; j ++)
+ if (!_cups_strcasecmp(options[j].name, option))
+ {
+ /*
+ * Remove this option...
+ */
+
+ num_options --;
+
+ if (j < num_options)
+ memcpy(options + j, options + j + 1,
+ sizeof(cups_option_t) * (num_options - j));
+ break;
+ }
+
+ changes = 1;
+ break;
+
+ case 'x' : /* -x printer */
+ if (argv[i][2])
+ printer = argv[i] + 2;
+ else
+ {
+ i ++;
+ if (i >= argc)
+ usage();
+
+ 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)
+ {
+ cupsFreeOptions(dest->num_options, dest->options);
+
+ /*
+ * If we are "deleting" the default printer, then just set the
+ * number of options to 0; if it is also the system default
+ * then cupsSetDests() will remove it for us...
+ */
+
+ if (dest->is_default)
+ {
+ dest->num_options = 0;
+ dest->options = NULL;
+ }
+ else
+ {
+ num_dests --;
+
+ j = dest - dests;
+ if (j < num_dests)
+ memcpy(dest, dest + 1, (num_dests - j) * sizeof(cups_dest_t));
+ }
+ }
+
+ cupsSetDests(num_dests, dests);
+ dest = NULL;
+ changes = -1;
+ break;
+
+ default :
+ usage();
+ }
+ }
+ else
+ usage();
+
+ if (num_dests == 0)
+ num_dests = cupsGetDests(&dests);
+
+ if (dest == NULL)
+ {
+ if ((dest = cupsGetDest(NULL, NULL, 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);
+ }
+ }
+
+ if (dest == NULL)
+ return (0);
+
+ if (changes > 0)
+ {
+ /*
+ * Set printer options...
+ */
+
+ cupsFreeOptions(dest->num_options, dest->options);
+
+ dest->num_options = num_options;
+ dest->options = options;
+
+ cupsSetDests(num_dests, dests);
+ }
+ else if (changes == 0)
+ {
+ char buffer[10240], /* String for options */
+ *ptr; /* Pointer into string */
+
+ num_options = dest->num_options;
+ options = dest->options;
+
+ for (i = 0, ptr = buffer;
+ ptr < (buffer + sizeof(buffer) - 1) && i < num_options;
+ i ++)
+ {
+ if (i)
+ *ptr++ = ' ';
+
+ if (!options[i].value[0])
+ strlcpy(ptr, options[i].name, sizeof(buffer) - (ptr - buffer));
+ else if (strchr(options[i].value, ' ') != NULL ||
+ strchr(options[i].value, '\t') != NULL)
+ snprintf(ptr, sizeof(buffer) - (ptr - buffer), "%s=\'%s\'",
+ options[i].name, options[i].value);
+ else
+ snprintf(ptr, sizeof(buffer) - (ptr - buffer), "%s=%s",
+ options[i].name, options[i].value);
+
+ ptr += strlen(ptr);
+ }
+
+ _cupsLangPuts(stdout, buffer);
+ }
+
+ return (0);
+}
+
+/*
+ * 'list_group()' - List printer-specific options from the PPD group.
+ */
+
+static void
+list_group(ppd_file_t *ppd, /* I - PPD file */
+ ppd_group_t *group) /* I - Group to show */
+{
+ int i, j; /* Looping vars */
+ ppd_option_t *option; /* Current option */
+ ppd_choice_t *choice; /* Current choice */
+ ppd_group_t *subgroup; /* Current subgroup */
+ char buffer[10240], /* Option string buffer */
+ *ptr; /* Pointer into option string */
+
+
+ for (i = group->num_options, option = group->options; i > 0; i --, option ++)
+ {
+ if (!_cups_strcasecmp(option->keyword, "PageRegion"))
+ continue;
+
+ snprintf(buffer, sizeof(buffer), "%s/%s:", option->keyword, option->text);
+
+ for (j = option->num_choices, choice = option->choices,
+ ptr = buffer + strlen(buffer);
+ j > 0 && ptr < (buffer + sizeof(buffer) - 1);
+ j --, choice ++)
+ {
+ if (!_cups_strcasecmp(choice->choice, "Custom"))
+ {
+ ppd_coption_t *coption; /* Custom option */
+ ppd_cparam_t *cparam; /* Custom parameter */
+ static const char * const types[] =
+ { /* Parameter types */
+ "CURVE",
+ "INTEGER",
+ "INVCURVE",
+ "PASSCODE",
+ "PASSWORD",
+ "POINTS",
+ "REAL",
+ "STRING"
+ };
+
+
+ if ((coption = ppdFindCustomOption(ppd, option->keyword)) == NULL ||
+ cupsArrayCount(coption->params) == 0)
+ snprintf(ptr, sizeof(buffer) - (ptr - buffer), " %sCustom",
+ choice->marked ? "*" : "");
+ else if (!_cups_strcasecmp(option->keyword, "PageSize") ||
+ !_cups_strcasecmp(option->keyword, "PageRegion"))
+ snprintf(ptr, sizeof(buffer) - (ptr - buffer),
+ " %sCustom.WIDTHxHEIGHT", choice->marked ? "*" : "");
+ else
+ {
+ cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+
+ if (cupsArrayCount(coption->params) == 1)
+ snprintf(ptr, sizeof(buffer) - (ptr - buffer), " %sCustom.%s",
+ choice->marked ? "*" : "", types[cparam->type]);
+ else
+ {
+ const char *prefix; /* Prefix string */
+
+
+ if (choice->marked)
+ prefix = " *{";
+ else
+ prefix = " {";
+
+ while (cparam)
+ {
+ snprintf(ptr, sizeof(buffer) - (ptr - buffer), "%s%s=%s", prefix,
+ cparam->name, types[cparam->type]);
+ cparam = (ppd_cparam_t *)cupsArrayNext(coption->params);
+ prefix = " ";
+ ptr += strlen(ptr);
+ }
+
+ if (ptr < (buffer + sizeof(buffer) - 1))
+ strlcpy(ptr, "}", sizeof(buffer) - (ptr - buffer));
+ }
+ }
+ }
+ else if (choice->marked)
+ snprintf(ptr, sizeof(buffer) - (ptr - buffer), " *%s", choice->choice);
+ else
+ snprintf(ptr, sizeof(buffer) - (ptr - buffer), " %s", choice->choice);
+
+ ptr += strlen(ptr);
+ }
+
+ _cupsLangPuts(stdout, buffer);
+ }
+
+ for (i = group->num_subgroups, subgroup = group->subgroups; i > 0; i --, subgroup ++)
+ list_group(ppd, subgroup);
+}
+
+
+/*
+ * 'list_options()' - List printer-specific options from the PPD file.
+ */
+
+static void
+list_options(cups_dest_t *dest) /* I - Destination to list */
+{
+ int i; /* Looping var */
+ const char *filename; /* PPD filename */
+ ppd_file_t *ppd; /* PPD data */
+ ppd_group_t *group; /* Current group */
+
+
+ if ((filename = cupsGetPPD(dest->name)) == NULL)
+ {
+ _cupsLangPrintf(stderr, _("lpoptions: Unable to get PPD file for %s: %s"),
+ dest->name, cupsLastErrorString());
+ return;
+ }
+
+ if ((ppd = ppdOpenFile(filename)) == NULL)
+ {
+ unlink(filename);
+ _cupsLangPrintf(stderr, _("lpoptions: Unable to open PPD file for %s."),
+ dest->name);
+ return;
+ }
+
+ ppdMarkDefaults(ppd);
+ cupsMarkOptions(ppd, dest->num_options, dest->options);
+
+ for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
+ list_group(ppd, group);
+
+ ppdClose(ppd);
+ unlink(filename);
+}
+
+
+/*
+ * 'usage()' - Show program usage and exit.
+ */
+
+static void
+usage(void)
+{
+ _cupsLangPuts(stdout,
+ _("Usage: lpoptions [-h server] [-E] -d printer\n"
+ " lpoptions [-h server] [-E] [-p printer] -l\n"
+ " lpoptions [-h server] [-E] -p printer -o "
+ "option[=value] ...\n"
+ " lpoptions [-h server] [-E] -x printer"));
+
+ exit(1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/lppasswd.c b/systemv/lppasswd.c
new file mode 100644
index 000000000..0a7e4b8d0
--- /dev/null
+++ b/systemv/lppasswd.c
@@ -0,0 +1,489 @@
+/*
+ * "$Id$"
+ *
+ * MD5 password program for CUPS.
+ *
+ * Copyright 2007-2010 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Add, change, or delete passwords from the MD5 password file.
+ * usage() - Show program usage.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include <cups/md5-private.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef WIN32
+# include <unistd.h>
+# include <signal.h>
+#endif /* !WIN32 */
+
+
+/*
+ * Operations...
+ */
+
+#define ADD 0
+#define CHANGE 1
+#define DELETE 2
+
+
+/*
+ * Local functions...
+ */
+
+static void usage(FILE *fp);
+
+
+/*
+ * 'main()' - Add, change, or delete passwords from the MD5 password file.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ char *opt; /* Option pointer */
+ const char *username; /* Pointer to username */
+ const char *groupname; /* Pointer to group name */
+ int op; /* Operation (add, change, delete) */
+ const char *passwd; /* Password string */
+ FILE *infile, /* Input file */
+ *outfile; /* Output file */
+ char line[256], /* Line from file */
+ userline[17], /* User from line */
+ groupline[17], /* Group from line */
+ md5line[33], /* MD5-sum from line */
+ md5new[33]; /* New MD5 sum */
+ char passwdmd5[1024], /* passwd.md5 file */
+ passwdold[1024], /* passwd.old file */
+ passwdnew[1024]; /* passwd.tmp file */
+ char *newpass, /* new password */
+ *oldpass; /* old password */
+ int flag; /* Password check flags... */
+ int fd; /* Password file descriptor */
+ int error; /* Write error */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+ cups_lang_t *lang; /* Language info */
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Signal action */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET*/
+
+
+ _cupsSetLocale(argv);
+ lang = cupsLangDefault();
+
+ /*
+ * Check to see if stdin, stdout, and stderr are still open...
+ */
+
+ if (fcntl(0, F_GETFD, &i) ||
+ fcntl(1, F_GETFD, &i) ||
+ fcntl(2, F_GETFD, &i))
+ {
+ /*
+ * No, return exit status 2 and don't try to send any output since
+ * someone is trying to bypass the security on the server.
+ */
+
+ return (2);
+ }
+
+ /*
+ * Find the server directory...
+ */
+
+ snprintf(passwdmd5, sizeof(passwdmd5), "%s/passwd.md5", cg->cups_serverroot);
+ snprintf(passwdold, sizeof(passwdold), "%s/passwd.old", cg->cups_serverroot);
+ snprintf(passwdnew, sizeof(passwdnew), "%s/passwd.new", cg->cups_serverroot);
+
+ /*
+ * Find the default system group...
+ */
+
+ if (getgrnam(CUPS_DEFAULT_GROUP))
+ groupname = CUPS_DEFAULT_GROUP;
+ else
+ groupname = "unknown";
+
+ endgrent();
+
+ username = NULL;
+ op = CHANGE;
+
+ /*
+ * Parse command-line options...
+ */
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ for (opt = argv[i] + 1; *opt; opt ++)
+ switch (*opt)
+ {
+ case 'a' : /* Add */
+ op = ADD;
+ break;
+ case 'x' : /* Delete */
+ op = DELETE;
+ break;
+ case 'g' : /* Group */
+ i ++;
+ if (i >= argc)
+ usage(stderr);
+
+ groupname = argv[i];
+ break;
+ case 'h' : /* Help */
+ usage(stdout);
+ break;
+ default : /* Bad option */
+ usage(stderr);
+ break;
+ }
+ else if (!username)
+ username = argv[i];
+ else
+ usage(stderr);
+
+ /*
+ * See if we are trying to add or delete a password when we aren't logged in
+ * as root...
+ */
+
+ if (getuid() && getuid() != geteuid() && (op != CHANGE || username))
+ {
+ _cupsLangPuts(stderr,
+ _("lppasswd: Only root can add or delete passwords."));
+ return (1);
+ }
+
+ /*
+ * Fill in missing info...
+ */
+
+ if (!username)
+ username = cupsUser();
+
+ oldpass = newpass = NULL;
+
+ /*
+ * Obtain old and new password _before_ locking the database
+ * to keep users from locking the file indefinitely.
+ */
+
+ if (op == CHANGE && getuid())
+ {
+ if ((passwd = cupsGetPassword(_("Enter old password:"))) == NULL)
+ return (1);
+
+ if ((oldpass = strdup(passwd)) == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("lppasswd: Unable to copy password string: %s"),
+ strerror(errno));
+ return (1);
+ }
+ }
+
+ /*
+ * Now get the new password, if necessary...
+ */
+
+ if (op != DELETE)
+ {
+ if ((passwd = cupsGetPassword(
+ _cupsLangString(lang, _("Enter password:")))) == NULL)
+ return (1);
+
+ if ((newpass = strdup(passwd)) == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("lppasswd: Unable to copy password string: %s"),
+ strerror(errno));
+ return (1);
+ }
+
+ if ((passwd = cupsGetPassword(
+ _cupsLangString(lang, _("Enter password again:")))) == NULL)
+ return (1);
+
+ if (strcmp(passwd, newpass) != 0)
+ {
+ _cupsLangPuts(stderr,
+ _("lppasswd: Sorry, passwords don't match."));
+ return (1);
+ }
+
+ /*
+ * Check that the password contains at least one letter and number.
+ */
+
+ flag = 0;
+
+ for (passwd = newpass; *passwd; passwd ++)
+ if (isdigit(*passwd & 255))
+ flag |= 1;
+ else if (isalpha(*passwd & 255))
+ flag |= 2;
+
+ /*
+ * Only allow passwords that are at least 6 chars, have a letter and
+ * a number, and don't contain the username.
+ */
+
+ if (strlen(newpass) < 6 || strstr(newpass, username) != NULL || flag != 3)
+ {
+ _cupsLangPuts(stderr, _("lppasswd: Sorry, password rejected."));
+ _cupsLangPuts(stderr, _("Your password must be at least 6 characters "
+ "long, cannot contain your username, and must "
+ "contain at least one letter and number."));
+ return (1);
+ }
+ }
+
+ /*
+ * Ignore SIGHUP, SIGINT, SIGTERM, and SIGXFSZ (if defined) for the
+ * remainder of the time so that we won't end up with bogus password
+ * files...
+ */
+
+#ifndef WIN32
+# if defined(HAVE_SIGSET)
+ sigset(SIGHUP, SIG_IGN);
+ sigset(SIGINT, SIG_IGN);
+ sigset(SIGTERM, SIG_IGN);
+# ifdef SIGXFSZ
+ sigset(SIGXFSZ, SIG_IGN);
+# endif /* SIGXFSZ */
+# elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_IGN;
+
+ sigaction(SIGHUP, &action, NULL);
+ sigaction(SIGINT, &action, NULL);
+ sigaction(SIGTERM, &action, NULL);
+# ifdef SIGXFSZ
+ sigaction(SIGXFSZ, &action, NULL);
+# endif /* SIGXFSZ */
+# else
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+# ifdef SIGXFSZ
+ signal(SIGXFSZ, SIG_IGN);
+# endif /* SIGXFSZ */
+# endif
+#endif /* !WIN32 */
+
+ /*
+ * Open the output file.
+ */
+
+ if ((fd = open(passwdnew, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0)
+ {
+ if (errno == EEXIST)
+ _cupsLangPuts(stderr, _("lppasswd: Password file busy."));
+ else
+ _cupsLangPrintf(stderr, _("lppasswd: Unable to open password file: %s"),
+ strerror(errno));
+
+ return (1);
+ }
+
+ if ((outfile = fdopen(fd, "w")) == NULL)
+ {
+ _cupsLangPrintf(stderr, _("lppasswd: Unable to open password file: %s"),
+ strerror(errno));
+
+ unlink(passwdnew);
+
+ return (1);
+ }
+
+ setbuf(outfile, NULL);
+
+ /*
+ * Open the existing password file and create a new one...
+ */
+
+ infile = fopen(passwdmd5, "r");
+ if (infile == NULL && errno != ENOENT && op != ADD)
+ {
+ _cupsLangPrintf(stderr, _("lppasswd: Unable to open password file: %s"),
+ strerror(errno));
+
+ fclose(outfile);
+
+ unlink(passwdnew);
+
+ return (1);
+ }
+
+ /*
+ * Read lines from the password file; the format is:
+ *
+ * username:group:MD5-sum
+ */
+
+ error = 0;
+ userline[0] = '\0';
+ groupline[0] = '\0';
+ md5line[0] = '\0';
+
+ if (infile)
+ {
+ while (fgets(line, sizeof(line), infile) != NULL)
+ {
+ if (sscanf(line, "%16[^:]:%16[^:]:%32s", userline, groupline, md5line) != 3)
+ continue;
+
+ if (strcmp(username, userline) == 0 &&
+ strcmp(groupname, groupline) == 0)
+ break;
+
+ if (fputs(line, outfile) == EOF)
+ {
+ _cupsLangPrintf(stderr,
+ _("lppasswd: Unable to write to password file: %s"),
+ strerror(errno));
+ error = 1;
+ break;
+ }
+ }
+
+ if (!error)
+ {
+ while (fgets(line, sizeof(line), infile) != NULL)
+ if (fputs(line, outfile) == EOF)
+ {
+ _cupsLangPrintf(stderr,
+ _("lppasswd: Unable to write to password file: %s"),
+ strerror(errno));
+ error = 1;
+ break;
+ }
+ }
+ }
+
+ if (op == CHANGE &&
+ (strcmp(username, userline) || strcmp(groupname, groupline)))
+ {
+ _cupsLangPrintf(stderr,
+ _("lppasswd: user \"%s\" and group \"%s\" do not exist."),
+ username, groupname);
+ error = 1;
+ }
+ else if (op != DELETE)
+ {
+ if (oldpass &&
+ strcmp(httpMD5(username, "CUPS", oldpass, md5new), md5line) != 0)
+ {
+ _cupsLangPuts(stderr, _("lppasswd: Sorry, password doesn't match."));
+ error = 1;
+ }
+ else
+ {
+ snprintf(line, sizeof(line), "%s:%s:%s\n", username, groupname,
+ httpMD5(username, "CUPS", newpass, md5new));
+ if (fputs(line, outfile) == EOF)
+ {
+ _cupsLangPrintf(stderr,
+ _("lppasswd: Unable to write to password file: %s"),
+ strerror(errno));
+ error = 1;
+ }
+ }
+ }
+
+ /*
+ * Close the files...
+ */
+
+ if (infile)
+ fclose(infile);
+
+ if (fclose(outfile) == EOF)
+ error = 1;
+
+ /*
+ * Error out gracefully as needed...
+ */
+
+ if (error)
+ {
+ _cupsLangPuts(stderr, _("lppasswd: Password file not updated."));
+
+ unlink(passwdnew);
+
+ return (1);
+ }
+
+ /*
+ * Save old passwd file
+ */
+
+ unlink(passwdold);
+ if (link(passwdmd5, passwdold) && errno != ENOENT)
+ {
+ _cupsLangPrintf(stderr,
+ _("lppasswd: failed to backup old password file: %s"),
+ strerror(errno));
+ unlink(passwdnew);
+ return (1);
+ }
+
+ /*
+ * Install new password file
+ */
+
+ if (rename(passwdnew, passwdmd5) < 0)
+ {
+ _cupsLangPrintf(stderr, _("lppasswd: failed to rename password file: %s"),
+ strerror(errno));
+ unlink(passwdnew);
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'usage()' - Show program usage.
+ */
+
+static void
+usage(FILE *fp) /* I - File to send usage to */
+{
+ if (getuid())
+ _cupsLangPuts(fp, _("Usage: lppasswd [-g groupname]"));
+ else
+ _cupsLangPuts(fp,
+ _("Usage: lppasswd [-g groupname] [username]\n"
+ " lppasswd [-g groupname] -a [username]\n"
+ " lppasswd [-g groupname] -x [username]"));
+
+ exit(1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/systemv/lpstat.c b/systemv/lpstat.c
new file mode 100644
index 000000000..53039660d
--- /dev/null
+++ b/systemv/lpstat.c
@@ -0,0 +1,2051 @@
+/*
+ * "$Id$"
+ *
+ * "lpstat" command for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * main() - Parse options and show status information.
+ * check_dest() - Verify that the named destination(s) exists.
+ * match_list() - Match a name from a list of comma or space-separated
+ * names.
+ * show_accepting() - Show acceptance status.
+ * show_classes() - Show printer classes.
+ * show_default() - Show default destination.
+ * show_devices() - Show printer devices.
+ * show_jobs() - Show active print jobs.
+ * show_printers() - Show printers.
+ * show_scheduler() - Show scheduler status.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+
+
+/*
+ * Local functions...
+ */
+
+static void check_dest(const char *command, const char *name,
+ int *num_dests, cups_dest_t **dests);
+static int match_list(const char *list, const char *name);
+static int show_accepting(const char *printers, int num_dests,
+ cups_dest_t *dests);
+static int show_classes(const char *dests);
+static void show_default(cups_dest_t *dest);
+static int show_devices(const char *printers, int num_dests,
+ cups_dest_t *dests);
+static int show_jobs(const char *dests, const char *users, int long_status,
+ int ranking, const char *which);
+static int show_printers(const char *printers, int num_dests,
+ cups_dest_t *dests, int long_status);
+static void show_scheduler(void);
+
+
+/*
+ * 'main()' - Parse options and show status information.
+ */
+
+int
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i, /* Looping var */
+ status; /* Exit status */
+ int num_dests; /* Number of user destinations */
+ cups_dest_t *dests; /* User destinations */
+ int long_status; /* Long status report? */
+ int ranking; /* Show job ranking? */
+ const char *which; /* Which jobs to show? */
+ char op; /* Last operation on command-line */
+
+
+ _cupsSetLocale(argv);
+
+ /*
+ * Parse command-line options...
+ */
+
+ num_dests = 0;
+ dests = NULL;
+ long_status = 0;
+ ranking = 0;
+ status = 0;
+ which = "not-completed";
+ op = 0;
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1])
+ {
+ case 'D' : /* Show description */
+ long_status = 1;
+ break;
+
+ case 'E' : /* Encrypt */
+#ifdef HAVE_SSL
+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
+#else
+ _cupsLangPrintf(stderr,
+ _("%s: Sorry, no encryption support."),
+ argv[0]);
+#endif /* HAVE_SSL */
+ break;
+
+ case 'H' : /* Show server and port */
+ if (cupsServer()[0] == '/')
+ _cupsLangPuts(stdout, cupsServer());
+ else
+ _cupsLangPrintf(stdout, "%s:%d", cupsServer(), ippPort());
+ break;
+
+ case 'P' : /* Show paper types */
+ op = 'P';
+ break;
+
+ case 'R' : /* Show ranking */
+ ranking = 1;
+ break;
+
+ case 'S' : /* Show charsets */
+ op = 'S';
+ if (!argv[i][2])
+ i ++;
+ break;
+
+ case 'U' : /* Username */
+ if (argv[i][2])
+ cupsSetUser(argv[i] + 2);
+ else
+ {
+ i ++;
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected username after "
+ "\"-U\" option."),
+ argv[0]);
+ return (1);
+ }
+
+ cupsSetUser(argv[i]);
+ }
+ break;
+
+ case 'W' : /* Show which jobs? */
+ if (argv[i][2])
+ which = argv[i] + 2;
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - need \"completed\", "
+ "\"not-completed\", or \"all\" after "
+ "\"-W\" option."),
+ argv[0]);
+ return (1);
+ }
+
+ which = argv[i];
+ }
+
+ if (strcmp(which, "completed") && strcmp(which, "not-completed") &&
+ strcmp(which, "all"))
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - need \"completed\", "
+ "\"not-completed\", or \"all\" after "
+ "\"-W\" option."),
+ argv[0]);
+ return (1);
+ }
+ break;
+
+ case 'a' : /* Show acceptance status */
+ op = 'a';
+
+ if (argv[i][2])
+ {
+ check_dest(argv[0], argv[i] + 2, &num_dests, &dests);
+
+ status |= show_accepting(argv[i] + 2, num_dests, dests);
+ }
+ else if ((i + 1) < argc && argv[i + 1][0] != '-')
+ {
+ i ++;
+
+ check_dest(argv[0], argv[i], &num_dests, &dests);
+
+ status |= show_accepting(argv[i], num_dests, dests);
+ }
+ else
+ {
+ if (num_dests <= 1)
+ {
+ cupsFreeDests(num_dests, dests);
+ num_dests = cupsGetDests(&dests);
+ }
+
+ status |= show_accepting(NULL, num_dests, dests);
+ }
+ break;
+
+#ifdef __sgi
+ case 'b' : /* Show both the local and remote status */
+ op = 'b';
+
+ if (argv[i][2])
+ {
+ /*
+ * The local and remote status are separated by a blank line;
+ * since all CUPS jobs are networked, we only output the
+ * second list for now... In the future, we might further
+ * emulate this by listing the remote server's queue, but
+ * for now this is enough to make the SGI printstatus program
+ * happy...
+ */
+
+ check_dest(argv[0], argv[i] + 2, &num_dests, &dests);
+
+ puts("");
+ status |= show_jobs(argv[i] + 2, NULL, 3, ranking, which);
+ }
+ else
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected destination after "
+ "\"-b\" option."),
+ argv[0]);
+
+ return (1);
+ }
+ break;
+#endif /* __sgi */
+
+ case 'c' : /* Show classes and members */
+ op = 'c';
+
+ if (argv[i][2])
+ {
+ check_dest(argv[0], argv[i] + 2, &num_dests, &dests);
+
+ status |= show_classes(argv[i] + 2);
+ }
+ else if ((i + 1) < argc && argv[i + 1][0] != '-')
+ {
+ i ++;
+
+ check_dest(argv[0], argv[i], &num_dests, &dests);
+
+ status |= show_classes(argv[i]);
+ }
+ else
+ status |= show_classes(NULL);
+ break;
+
+ case 'd' : /* Show default destination */
+ op = 'd';
+
+ if (num_dests != 1 || !dests[0].is_default)
+ {
+ cupsFreeDests(num_dests, dests);
+
+ dests = cupsGetNamedDest(CUPS_HTTP_DEFAULT, NULL, NULL);
+ num_dests = dests ? 1 : 0;
+ }
+
+ show_default(dests);
+ break;
+
+ case 'f' : /* Show forms */
+ op = 'f';
+ if (!argv[i][2])
+ i ++;
+ break;
+
+ case 'h' : /* Connect to host */
+ if (argv[i][2])
+ cupsSetServer(argv[i] + 2);
+ else
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Error - expected hostname after "
+ "\"-h\" option."),
+ argv[0]);
+ return (1);
+ }
+
+ cupsSetServer(argv[i]);
+ }
+ break;
+
+ case 'l' : /* Long status or long job status */
+#ifdef __sgi
+ op = 'l';
+
+ if (argv[i][2])
+ {
+ check_dest(argv[0], argv[i] + 2, &num_dests, &dests);
+
+ status |= show_jobs(argv[i] + 2, NULL, 3, ranking, which);
+ }
+ else
+#endif /* __sgi */
+ long_status = 2;
+ break;
+
+ case 'o' : /* Show jobs by destination */
+ op = 'o';
+
+ if (argv[i][2])
+ {
+ check_dest(argv[0], argv[i] + 2, &num_dests, &dests);
+
+ status |= show_jobs(argv[i] + 2, NULL, long_status, ranking,
+ which);
+ }
+ else if ((i + 1) < argc && argv[i + 1][0] != '-')
+ {
+ i ++;
+
+ check_dest(argv[0], argv[i], &num_dests, &dests);
+
+ status |= show_jobs(argv[i], NULL, long_status, ranking, which);
+ }
+ else
+ status |= show_jobs(NULL, NULL, long_status, ranking, which);
+ break;
+
+ case 'p' : /* Show printers */
+ op = 'p';
+
+ if (argv[i][2])
+ {
+ check_dest(argv[0], argv[i] + 2, &num_dests, &dests);
+
+ status |= show_printers(argv[i] + 2, num_dests, dests,
+ long_status);
+ }
+ else if ((i + 1) < argc && argv[i + 1][0] != '-')
+ {
+ i ++;
+
+ check_dest(argv[0], argv[i], &num_dests, &dests);
+
+ status |= show_printers(argv[i], num_dests, dests, long_status);
+ }
+ else
+ {
+ if (num_dests <= 1)
+ {
+ cupsFreeDests(num_dests, dests);
+ num_dests = cupsGetDests(&dests);
+ }
+
+ status |= show_printers(NULL, num_dests, dests, long_status);
+ }
+ break;
+
+ case 'r' : /* Show scheduler status */
+ op = 'r';
+
+ show_scheduler();
+ break;
+
+ case 's' : /* Show summary */
+ op = 's';
+
+ if (num_dests <= 1)
+ {
+ cupsFreeDests(num_dests, dests);
+ num_dests = cupsGetDests(&dests);
+ }
+
+ show_default(cupsGetDest(NULL, NULL, num_dests, dests));
+ status |= show_classes(NULL);
+ status |= show_devices(NULL, num_dests, dests);
+ break;
+
+ case 't' : /* Show all info */
+ op = 't';
+
+ if (num_dests <= 1)
+ {
+ cupsFreeDests(num_dests, dests);
+ num_dests = cupsGetDests(&dests);
+ }
+
+ show_scheduler();
+ show_default(cupsGetDest(NULL, NULL, num_dests, dests));
+ status |= show_classes(NULL);
+ status |= show_devices(NULL, num_dests, dests);
+ status |= show_accepting(NULL, num_dests, dests);
+ status |= show_printers(NULL, num_dests, dests, long_status);
+ status |= show_jobs(NULL, NULL, long_status, ranking, which);
+ break;
+
+ case 'u' : /* Show jobs by user */
+ op = 'u';
+
+ if (argv[i][2])
+ status |= show_jobs(NULL, argv[i] + 2, long_status, ranking,
+ which);
+ else if ((i + 1) < argc && argv[i + 1][0] != '-')
+ {
+ i ++;
+ status |= show_jobs(NULL, argv[i], long_status, ranking, which);
+ }
+ else
+ status |= show_jobs(NULL, NULL, long_status, ranking, which);
+ break;
+
+ case 'v' : /* Show printer devices */
+ op = 'v';
+
+ if (argv[i][2])
+ {
+ check_dest(argv[0], argv[i] + 2, &num_dests, &dests);
+
+ status |= show_devices(argv[i] + 2, num_dests, dests);
+ }
+ else if ((i + 1) < argc && argv[i + 1][0] != '-')
+ {
+ i ++;
+
+ check_dest(argv[0], argv[i], &num_dests, &dests);
+
+ status |= show_devices(argv[i], num_dests, dests);
+ }
+ else
+ {
+ if (num_dests <= 1)
+ {
+ cupsFreeDests(num_dests, dests);
+ num_dests = cupsGetDests(&dests);
+ }
+
+ status |= show_devices(NULL, num_dests, dests);
+ }
+ break;
+
+ default :
+ _cupsLangPrintf(stderr,
+ _("%s: Error - unknown option \"%c\"."),
+ argv[0], argv[i][1]);
+ return (1);
+ }
+ else
+ {
+ status |= show_jobs(argv[i], NULL, long_status, ranking, which);
+ op = 'o';
+ }
+
+ if (!op)
+ status |= show_jobs(NULL, cupsUser(), long_status, ranking, which);
+
+ return (status);
+}
+
+
+/*
+ * 'check_dest()' - Verify that the named destination(s) exists.
+ */
+
+static void
+check_dest(const char *command, /* I - Command name */
+ const char *name, /* I - List of printer/class names */
+ int *num_dests, /* IO - Number of destinations */
+ cups_dest_t **dests) /* IO - Destinations */
+{
+ const char *dptr; /* Pointer into name */
+ char *pptr, /* Pointer into printer */
+ printer[1024]; /* Current printer/class name */
+
+
+ /*
+ * Load the destination list as necessary...
+ */
+
+ if (*num_dests <= 1)
+ {
+ if (*num_dests)
+ cupsFreeDests(*num_dests, *dests);
+
+ if (strchr(name, ','))
+ *num_dests = cupsGetDests(dests);
+ else
+ {
+ strlcpy(printer, name, sizeof(printer));
+ if ((pptr = strchr(printer, '/')) != NULL)
+ *pptr++ = '\0';
+
+ if ((*dests = cupsGetNamedDest(CUPS_HTTP_DEFAULT, printer, pptr)) == NULL)
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Invalid destination name in list \"%s\"."),
+ command, name);
+ exit(1);
+ }
+ else
+ {
+ *num_dests = 1;
+ return;
+ }
+ }
+ }
+
+ /*
+ * Scan the name string for printer/class name(s)...
+ */
+
+ for (dptr = name; *dptr;)
+ {
+ /*
+ * Skip leading whitespace and commas...
+ */
+
+ while (isspace(*dptr & 255) || *dptr == ',')
+ dptr ++;
+
+ if (!*dptr)
+ break;
+
+ /*
+ * Extract a single destination name from the name string...
+ */
+
+ for (pptr = printer; !isspace(*dptr & 255) && *dptr != ',' && *dptr;)
+ {
+ if ((pptr - printer) < (sizeof(printer) - 1))
+ *pptr++ = *dptr++;
+ else
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Invalid destination name in list \"%s\"."),
+ command, name);
+ exit(1);
+ }
+ }
+
+ *pptr = '\0';
+
+ /*
+ * Check the destination...
+ */
+
+ if (!cupsGetDest(printer, NULL, *num_dests, *dests))
+ {
+ _cupsLangPrintf(stderr,
+ _("%s: Unknown destination \"%s\"."), command, printer);
+ exit(1);
+ }
+ }
+}
+
+
+/*
+ * 'match_list()' - Match a name from a list of comma or space-separated names.
+ */
+
+static int /* O - 1 on match, 0 on no match */
+match_list(const char *list, /* I - List of names */
+ const char *name) /* I - Name to find */
+{
+ const char *nameptr; /* Pointer into name */
+
+
+ /*
+ * An empty list always matches...
+ */
+
+ if (!list || !*list)
+ return (1);
+
+ while (*list)
+ {
+ /*
+ * Skip leading whitespace and commas...
+ */
+
+ while (isspace(*list & 255) || *list == ',')
+ list ++;
+
+ if (!*list)
+ break;
+
+ /*
+ * Compare names...
+ */
+
+ for (nameptr = name;
+ *nameptr && *list && tolower(*nameptr & 255) == tolower(*list & 255);
+ nameptr ++, list ++);
+
+ if (!*nameptr && (!*list || *list == ',' || isspace(*list & 255)))
+ return (1);
+
+ while (*list && !isspace(*list & 255) && *list != ',')
+ list ++;
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'show_accepting()' - Show acceptance status.
+ */
+
+static int /* O - 0 on success, 1 on fail */
+show_accepting(const char *printers, /* I - Destinations */
+ int num_dests, /* I - Number of user-defined dests */
+ cups_dest_t *dests) /* I - User-defined destinations */
+{
+ int i; /* Looping var */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *printer, /* Printer name */
+ *message; /* Printer device URI */
+ int accepting; /* Accepting requests? */
+ time_t ptime; /* Printer state time */
+ struct tm *pdate; /* Printer state date & time */
+ char printer_state_time[255];/* Printer state time */
+ static const char *pattrs[] = /* Attributes we need for printers... */
+ {
+ "printer-name",
+ "printer-state-change-time",
+ "printer-state-message",
+ "printer-is-accepting-jobs"
+ };
+
+
+ DEBUG_printf(("show_accepting(printers=\"%s\")\n", printers));
+
+ if (printers != NULL && !strcmp(printers, "all"))
+ printers = NULL;
+
+ /*
+ * Build a CUPS_GET_PRINTERS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ * requesting-user-name
+ */
+
+ request = ippNewRequest(CUPS_GET_PRINTERS);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
+ NULL, pattrs);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
+ {
+ DEBUG_puts("show_accepting: request succeeded...");
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
+ ippDelete(response);
+ return (1);
+ }
+
+ /*
+ * Loop through the printers returned in the list and display
+ * their devices...
+ */
+
+ 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 printer...
+ */
+
+ printer = NULL;
+ message = NULL;
+ accepting = 1;
+ ptime = 0;
+
+ 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;
+ else if (!strcmp(attr->name, "printer-state-change-time") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ ptime = (time_t)attr->values[0].integer;
+ else if (!strcmp(attr->name, "printer-state-message") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ message = attr->values[0].string.text;
+ else 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;
+ }
+
+ /*
+ * Display the printer entry if needed...
+ */
+
+ if (match_list(printers, printer))
+ {
+ pdate = localtime(&ptime);
+ strftime(printer_state_time, sizeof(printer_state_time), "%c", pdate);
+
+ if (accepting)
+ _cupsLangPrintf(stdout, _("%s accepting requests since %s"),
+ printer, printer_state_time);
+ else
+ {
+ _cupsLangPrintf(stdout, _("%s not accepting requests since %s -"),
+ printer, printer_state_time);
+ _cupsLangPrintf(stdout, _("\t%s"),
+ (message == NULL || !*message) ?
+ "reason unknown" : message);
+ }
+
+ for (i = 0; i < num_dests; i ++)
+ if (!_cups_strcasecmp(dests[i].name, printer) && dests[i].instance)
+ {
+ if (accepting)
+ _cupsLangPrintf(stdout, _("%s/%s accepting requests since %s"),
+ printer, dests[i].instance, printer_state_time);
+ else
+ {
+ _cupsLangPrintf(stdout,
+ _("%s/%s not accepting requests since %s -"),
+ printer, dests[i].instance, printer_state_time);
+ _cupsLangPrintf(stdout, _("\t%s"),
+ (message == NULL || !*message) ?
+ "reason unknown" : message);
+ }
+ }
+ }
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'show_classes()' - Show printer classes.
+ */
+
+static int /* O - 0 on success, 1 on fail */
+show_classes(const char *dests) /* I - Destinations */
+{
+ int i; /* Looping var */
+ ipp_t *request, /* IPP Request */
+ *response, /* IPP Response */
+ *response2; /* IPP response from remote server */
+ http_t *http2; /* Remote server */
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *printer, /* Printer class name */
+ *printer_uri; /* Printer class URI */
+ ipp_attribute_t *members; /* Printer members */
+ char method[HTTP_MAX_URI], /* Request method */
+ username[HTTP_MAX_URI], /* Username:password */
+ server[HTTP_MAX_URI], /* Server name */
+ resource[HTTP_MAX_URI]; /* Resource name */
+ int port; /* Port number */
+ static const char *cattrs[] = /* Attributes we need for classes... */
+ {
+ "printer-name",
+ "printer-uri-supported",
+ "member-names"
+ };
+
+
+ DEBUG_printf(("show_classes(dests=\"%s\")\n", dests));
+
+ if (dests != NULL && !strcmp(dests, "all"))
+ dests = NULL;
+
+ /*
+ * Build a CUPS_GET_CLASSES request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ * requesting-user-name
+ */
+
+ request = ippNewRequest(CUPS_GET_CLASSES);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(cattrs) / sizeof(cattrs[0]),
+ NULL, cattrs);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
+ {
+ DEBUG_puts("show_classes: request succeeded...");
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
+ ippDelete(response);
+ return (1);
+ }
+
+ /*
+ * Loop through the printers returned in the list and display
+ * their devices...
+ */
+
+ 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;
+ printer_uri = NULL;
+ members = NULL;
+
+ 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, "printer-uri-supported") &&
+ attr->value_tag == IPP_TAG_URI)
+ printer_uri = attr->values[0].string.text;
+
+ if (!strcmp(attr->name, "member-names") &&
+ attr->value_tag == IPP_TAG_NAME)
+ members = attr;
+
+ attr = attr->next;
+ }
+
+ /*
+ * If this is a remote class, grab the class info from the
+ * remote server...
+ */
+
+ response2 = NULL;
+ if (members == NULL && printer_uri != NULL)
+ {
+ httpSeparateURI(HTTP_URI_CODING_ALL, printer_uri, method, sizeof(method),
+ username, sizeof(username), server, sizeof(server),
+ &port, resource, sizeof(resource));
+
+ if (!_cups_strcasecmp(server, cupsServer()))
+ http2 = CUPS_HTTP_DEFAULT;
+ else
+ http2 = httpConnectEncrypt(server, port, cupsEncryption());
+
+ /*
+ * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
+ * following attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requested-attributes
+ */
+
+ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, printer_uri);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ sizeof(cattrs) / sizeof(cattrs[0]),
+ NULL, cattrs);
+
+ if ((response2 = cupsDoRequest(http2, request, "/")) != NULL)
+ members = ippFindAttribute(response2, "member-names", IPP_TAG_NAME);
+
+ if (http2)
+ httpClose(http2);
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (printer == NULL)
+ {
+ if (response2)
+ ippDelete(response2);
+
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ /*
+ * Display the printer entry if needed...
+ */
+
+ if (match_list(dests, printer))
+ {
+ _cupsLangPrintf(stdout, _("members of class %s:"), printer);
+
+ if (members)
+ {
+ for (i = 0; i < members->num_values; i ++)
+ _cupsLangPrintf(stdout, "\t%s", members->values[i].string.text);
+ }
+ else
+ _cupsLangPuts(stdout, "\tunknown");
+ }
+
+ if (response2)
+ ippDelete(response2);
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'show_default()' - Show default destination.
+ */
+
+static void
+show_default(cups_dest_t *dest) /* I - Default destination */
+{
+ const char *printer, /* Printer name */
+ *val; /* Environment variable name */
+
+
+ if (dest)
+ {
+ if (dest->instance)
+ _cupsLangPrintf(stdout, _("system default destination: %s/%s"),
+ dest->name, dest->instance);
+ else
+ _cupsLangPrintf(stdout, _("system default destination: %s"),
+ dest->name);
+ }
+ else
+ {
+ 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)
+ _cupsLangPrintf(stdout,
+ _("lpstat: error - %s environment variable names "
+ "non-existent destination \"%s\"."),
+ val, printer);
+ else
+ _cupsLangPuts(stdout, _("no system default destination"));
+ }
+}
+
+
+/*
+ * 'show_devices()' - Show printer devices.
+ */
+
+static int /* O - 0 on success, 1 on fail */
+show_devices(const char *printers, /* I - Destinations */
+ int num_dests, /* I - Number of user-defined dests */
+ cups_dest_t *dests) /* I - User-defined destinations */
+{
+ int i; /* Looping var */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *printer, /* Printer name */
+ *uri, /* Printer URI */
+ *device; /* Printer device URI */
+ static const char *pattrs[] = /* Attributes we need for printers... */
+ {
+ "printer-name",
+ "printer-uri-supported",
+ "device-uri"
+ };
+
+
+ DEBUG_printf(("show_devices(printers=\"%s\")\n", printers));
+
+ if (printers != NULL && !strcmp(printers, "all"))
+ printers = NULL;
+
+ /*
+ * Build a CUPS_GET_PRINTERS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ * requesting-user-name
+ */
+
+ request = ippNewRequest(CUPS_GET_PRINTERS);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
+ NULL, pattrs);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
+ {
+ DEBUG_puts("show_devices: request succeeded...");
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
+ ippDelete(response);
+ return (1);
+ }
+
+ /*
+ * Loop through the printers returned in the list and display
+ * their devices...
+ */
+
+ 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 = NULL;
+ uri = NULL;
+
+ 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, "printer-uri-supported") &&
+ attr->value_tag == IPP_TAG_URI)
+ uri = attr->values[0].string.text;
+
+ if (!strcmp(attr->name, "device-uri") &&
+ attr->value_tag == IPP_TAG_URI)
+ device = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (printer == NULL)
+ {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ /*
+ * Display the printer entry if needed...
+ */
+
+ if (match_list(printers, printer))
+ {
+#ifdef __osf__ /* Compaq/Digital like to do it their own way... */
+ char scheme[HTTP_MAX_URI], /* Components of printer URI */
+ username[HTTP_MAX_URI],
+ hostname[HTTP_MAX_URI],
+ resource[HTTP_MAX_URI];
+ int port;
+
+
+ if (device == NULL)
+ {
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
+ username, sizeof(username), hostname,
+ sizeof(hostname), &port, resource, sizeof(resource));
+ _cupsLangPrintf(stdout,
+ _("Output for printer %s is sent to remote "
+ "printer %s on %s"),
+ printer, strrchr(resource, '/') + 1, hostname);
+ }
+ else if (!strncmp(device, "file:", 5))
+ _cupsLangPrintf(stdout,
+ _("Output for printer %s is sent to %s"),
+ printer, device + 5);
+ else
+ _cupsLangPrintf(stdout,
+ _("Output for printer %s is sent to %s"),
+ printer, device);
+
+ for (i = 0; i < num_dests; i ++)
+ if (!_cups_strcasecmp(printer, dests[i].name) && dests[i].instance)
+ {
+ if (device == NULL)
+ _cupsLangPrintf(stdout,
+ _("Output for printer %s/%s is sent to "
+ "remote printer %s on %s"),
+ printer, dests[i].instance,
+ strrchr(resource, '/') + 1, hostname);
+ else if (!strncmp(device, "file:", 5))
+ _cupsLangPrintf(stdout,
+ _("Output for printer %s/%s is sent to %s"),
+ printer, dests[i].instance, device + 5);
+ else
+ _cupsLangPrintf(stdout,
+ _("Output for printer %s/%s is sent to %s"),
+ printer, dests[i].instance, device);
+ }
+#else
+ if (device == NULL)
+ _cupsLangPrintf(stdout, _("device for %s: %s"),
+ printer, uri);
+ else if (!strncmp(device, "file:", 5))
+ _cupsLangPrintf(stdout, _("device for %s: %s"),
+ printer, device + 5);
+ else
+ _cupsLangPrintf(stdout, _("device for %s: %s"),
+ printer, device);
+
+ for (i = 0; i < num_dests; i ++)
+ if (!_cups_strcasecmp(printer, dests[i].name) && dests[i].instance)
+ {
+ if (device == NULL)
+ _cupsLangPrintf(stdout, _("device for %s/%s: %s"),
+ printer, dests[i].instance, uri);
+ else if (!strncmp(device, "file:", 5))
+ _cupsLangPrintf(stdout, _("device for %s/%s: %s"),
+ printer, dests[i].instance, device + 5);
+ else
+ _cupsLangPrintf(stdout, _("device for %s/%s: %s"),
+ printer, dests[i].instance, device);
+ }
+#endif /* __osf__ */
+ }
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'show_jobs()' - Show active print jobs.
+ */
+
+static int /* O - 0 on success, 1 on fail */
+show_jobs(const char *dests, /* I - Destinations */
+ const char *users, /* I - Users */
+ int long_status, /* I - Show long status? */
+ int ranking, /* I - Show job ranking? */
+ const char *which) /* I - Show which jobs? */
+{
+ int i; /* Looping var */
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ ipp_attribute_t *attr, /* Current attribute */
+ *reasons; /* Job state reasons attribute */
+ const char *dest, /* Pointer into job-printer-uri */
+ *username, /* Pointer to job-originating-user-name */
+ *title, /* Pointer to job-name */
+ *message; /* Pointer to job-printer-state-message */
+ int rank, /* Rank in queue */
+ jobid, /* job-id */
+ size; /* job-k-octets */
+ time_t jobtime; /* time-at-creation */
+ struct tm *jobdate; /* Date & time */
+ char temp[255], /* Temporary buffer */
+ date[255]; /* Date buffer */
+ static const char *jattrs[] = /* Attributes we need for jobs... */
+ {
+ "job-id",
+ "job-k-octets",
+ "job-name",
+ "job-originating-user-name",
+ "job-printer-state-message",
+ "job-printer-uri",
+ "job-state-reasons",
+ "time-at-creation"
+ };
+
+
+ DEBUG_printf(("show_jobs(dests=\"%s\", users=\"%s\", long_status=%d, "
+ "ranking=%d, which=\"%s\")\n", dests, users, long_status,
+ ranking, which));
+
+ if (dests != NULL && !strcmp(dests, "all"))
+ dests = NULL;
+
+ /*
+ * Build a IPP_GET_JOBS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requested-attributes
+ * requesting-user-name
+ * which-jobs
+ */
+
+ request = ippNewRequest(IPP_GET_JOBS);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, "ipp://localhost/");
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(jattrs) / sizeof(jattrs[0]),
+ NULL, jattrs);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs",
+ NULL, which);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
+ {
+ /*
+ * Loop through the job list and display them...
+ */
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
+ ippDelete(response);
+ return (1);
+ }
+
+ rank = -1;
+
+ 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;
+ size = 0;
+ username = NULL;
+ dest = NULL;
+ jobtime = 0;
+ title = "no title";
+ message = NULL;
+ reasons = NULL;
+
+ while (attr != NULL && attr->group_tag == IPP_TAG_JOB)
+ {
+ if (!strcmp(attr->name, "job-id") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ jobid = attr->values[0].integer;
+ else if (!strcmp(attr->name, "job-k-octets") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ size = attr->values[0].integer;
+ else if (!strcmp(attr->name, "time-at-creation") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ jobtime = attr->values[0].integer;
+ else if (!strcmp(attr->name, "job-printer-state-message") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ message = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "job-printer-uri") &&
+ attr->value_tag == IPP_TAG_URI)
+ {
+ if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL)
+ dest ++;
+ }
+ else if (!strcmp(attr->name, "job-originating-user-name") &&
+ attr->value_tag == IPP_TAG_NAME)
+ username = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "job-name") &&
+ attr->value_tag == IPP_TAG_NAME)
+ title = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "job-state-reasons") &&
+ attr->value_tag == IPP_TAG_KEYWORD)
+ reasons = attr;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (dest == NULL || jobid == 0)
+ {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ /*
+ * Display the job...
+ */
+
+ rank ++;
+
+ if (match_list(dests, dest) && match_list(users, username))
+ {
+ jobdate = localtime(&jobtime);
+ snprintf(temp, sizeof(temp), "%s-%d", dest, jobid);
+
+ if (long_status == 3)
+ {
+ /*
+ * Show the consolidated output format for the SGI tools...
+ */
+
+ if (!strftime(date, sizeof(date), "%b %d %H:%M", jobdate))
+ strcpy(date, "Unknown");
+
+ _cupsLangPrintf(stdout, "%s;%s;%d;%s;%s",
+ temp, username ? username : "unknown",
+ size, title ? title : "unknown", date);
+ }
+ else
+ {
+ if (!strftime(date, sizeof(date), "%c", jobdate))
+ strcpy(date, "Unknown");
+
+ if (ranking)
+ _cupsLangPrintf(stdout, "%3d %-21s %-13s %8.0f %s",
+ rank, temp, username ? username : "unknown",
+ 1024.0 * size, date);
+ else
+ _cupsLangPrintf(stdout, "%-23s %-13s %8.0f %s",
+ temp, username ? username : "unknown",
+ 1024.0 * size, date);
+ if (long_status)
+ {
+ if (message)
+ _cupsLangPrintf(stdout, _("\tStatus: %s"), message);
+
+ if (reasons)
+ {
+ char alerts[1024], /* Alerts string */
+ *aptr; /* Pointer into alerts string */
+
+ for (i = 0, aptr = alerts; i < reasons->num_values; i ++)
+ {
+ if (i)
+ snprintf(aptr, sizeof(alerts) - (aptr - alerts), " %s",
+ reasons->values[i].string.text);
+ else
+ strlcpy(alerts, reasons->values[i].string.text,
+ sizeof(alerts));
+
+ aptr += strlen(aptr);
+ }
+
+ _cupsLangPrintf(stdout, _("\tAlerts: %s"), alerts);
+ }
+
+ _cupsLangPrintf(stdout, _("\tqueued for %s"), dest);
+ }
+ }
+ }
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'show_printers()' - Show printers.
+ */
+
+static int /* O - 0 on success, 1 on fail */
+show_printers(const char *printers, /* I - Destinations */
+ int num_dests, /* I - Number of user-defined dests */
+ cups_dest_t *dests, /* I - User-defined destinations */
+ int long_status) /* I - Show long status? */
+{
+ int i, j; /* Looping vars */
+ ipp_t *request, /* IPP Request */
+ *response, /* IPP Response */
+ *jobs; /* IPP Get Jobs response */
+ ipp_attribute_t *attr, /* Current attribute */
+ *jobattr, /* Job ID attribute */
+ *reasons; /* Job state reasons attribute */
+ const char *printer, /* Printer name */
+ *message, /* Printer state message */
+ *description, /* Description of printer */
+ *location, /* Location of printer */
+ *make_model, /* Make and model of printer */
+ *uri; /* URI of printer */
+ ipp_attribute_t *allowed, /* requesting-user-name-allowed */
+ *denied; /* requestint-user-name-denied */
+ ipp_pstate_t pstate; /* Printer state */
+ cups_ptype_t ptype; /* Printer type */
+ time_t ptime; /* Printer state time */
+ struct tm *pdate; /* Printer state date & time */
+ int jobid; /* Job ID of current job */
+ char printer_uri[HTTP_MAX_URI],
+ /* Printer URI */
+ printer_state_time[255];/* Printer state time */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+ static const char *pattrs[] = /* Attributes we need for printers... */
+ {
+ "printer-name",
+ "printer-state",
+ "printer-state-message",
+ "printer-state-reasons",
+ "printer-state-change-time",
+ "printer-type",
+ "printer-info",
+ "printer-location",
+ "printer-make-and-model",
+ "printer-uri-supported",
+ "requesting-user-name-allowed",
+ "requesting-user-name-denied"
+ };
+ static const char *jattrs[] = /* Attributes we need for jobs... */
+ {
+ "job-id",
+ "job-state"
+ };
+
+
+ DEBUG_printf(("show_printers(printers=\"%s\", num_dests=%d, dests=%p, "
+ "long_status=%d)\n", printers, num_dests, dests, long_status));
+
+ if (printers != NULL && !strcmp(printers, "all"))
+ printers = NULL;
+
+ /*
+ * Build a CUPS_GET_PRINTERS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * requested-attributes
+ * requesting-user-name
+ */
+
+ request = ippNewRequest(CUPS_GET_PRINTERS);
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
+ NULL, pattrs);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, cupsUser());
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
+ {
+ DEBUG_puts("show_printers: request succeeded...");
+
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ {
+ _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
+ ippDelete(response);
+ return (1);
+ }
+
+ /*
+ * 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;
+ ptime = 0;
+ ptype = CUPS_PRINTER_LOCAL;
+ pstate = IPP_PRINTER_IDLE;
+ message = NULL;
+ description = NULL;
+ location = NULL;
+ make_model = NULL;
+ reasons = NULL;
+ uri = NULL;
+ jobid = 0;
+ allowed = NULL;
+ denied = NULL;
+
+ 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;
+ else if (!strcmp(attr->name, "printer-state") &&
+ attr->value_tag == IPP_TAG_ENUM)
+ pstate = (ipp_pstate_t)attr->values[0].integer;
+ else if (!strcmp(attr->name, "printer-type") &&
+ attr->value_tag == IPP_TAG_ENUM)
+ ptype = (cups_ptype_t)attr->values[0].integer;
+ else if (!strcmp(attr->name, "printer-state-message") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ message = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "printer-state-change-time") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ ptime = (time_t)attr->values[0].integer;
+ else if (!strcmp(attr->name, "printer-info") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ description = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "printer-location") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ location = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "printer-make-and-model") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ make_model = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "printer-uri-supported") &&
+ attr->value_tag == IPP_TAG_URI)
+ uri = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "printer-state-reasons") &&
+ attr->value_tag == IPP_TAG_KEYWORD)
+ reasons = attr;
+ else if (!strcmp(attr->name, "requesting-user-name-allowed") &&
+ attr->value_tag == IPP_TAG_NAME)
+ allowed = attr;
+ else if (!strcmp(attr->name, "requesting-user-name-denied") &&
+ attr->value_tag == IPP_TAG_NAME)
+ denied = attr;
+
+ attr = attr->next;
+ }
+
+ /*
+ * See if we have everything needed...
+ */
+
+ if (printer == NULL)
+ {
+ if (attr == NULL)
+ break;
+ else
+ continue;
+ }
+
+ /*
+ * Display the printer entry if needed...
+ */
+
+ if (match_list(printers, printer))
+ {
+ /*
+ * If the printer state is "IPP_PRINTER_PROCESSING", then grab the
+ * current job for the printer.
+ */
+
+ if (pstate == IPP_PRINTER_PROCESSING)
+ {
+ /*
+ * Build an IPP_GET_JOBS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * limit
+ * requested-attributes
+ */
+
+ request = ippNewRequest(IPP_GET_JOBS);
+
+ request->request.op.operation_id = IPP_GET_JOBS;
+ request->request.op.request_id = 1;
+
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ sizeof(jattrs) / sizeof(jattrs[0]), NULL, jattrs);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
+ "ipp", NULL, "localhost", 0, "/printers/%s", printer);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, printer_uri);
+
+ if ((jobs = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
+ {
+ /*
+ * Get the current active job on this queue...
+ */
+
+ ipp_jstate_t jobstate = IPP_JOB_PENDING;
+ jobid = 0;
+
+ for (jobattr = jobs->attrs; jobattr; jobattr = jobattr->next)
+ {
+ if (!jobattr->name)
+ {
+ if (jobstate == IPP_JOB_PROCESSING)
+ break;
+ else
+ continue;
+ }
+
+ if (!strcmp(jobattr->name, "job-id") &&
+ jobattr->value_tag == IPP_TAG_INTEGER)
+ jobid = jobattr->values[0].integer;
+ else if (!strcmp(jobattr->name, "job-state") &&
+ jobattr->value_tag == IPP_TAG_ENUM)
+ jobstate = jobattr->values[0].integer;
+ }
+
+ if (jobstate != IPP_JOB_PROCESSING)
+ jobid = 0;
+
+ ippDelete(jobs);
+ }
+ }
+
+ /*
+ * Display it...
+ */
+
+ pdate = localtime(&ptime);
+ strftime(printer_state_time, sizeof(printer_state_time), "%c", pdate);
+
+ switch (pstate)
+ {
+ case IPP_PRINTER_IDLE :
+ _cupsLangPrintf(stdout,
+ _("printer %s is idle. enabled since %s"),
+ printer, printer_state_time);
+ break;
+ case IPP_PRINTER_PROCESSING :
+ _cupsLangPrintf(stdout,
+ _("printer %s now printing %s-%d. "
+ "enabled since %s"),
+ printer, printer, jobid, printer_state_time);
+ break;
+ case IPP_PRINTER_STOPPED :
+ _cupsLangPrintf(stdout,
+ _("printer %s disabled since %s -"),
+ printer, printer_state_time);
+ break;
+ }
+
+ if ((message && *message) || pstate == IPP_PRINTER_STOPPED)
+ {
+ if (!message || !*message)
+ _cupsLangPuts(stdout, _("\treason unknown"));
+ else
+ _cupsLangPrintf(stdout, "\t%s", message);
+ }
+
+ if (long_status > 1)
+ {
+ _cupsLangPuts(stdout, _("\tForm mounted:"));
+ _cupsLangPuts(stdout, _("\tContent types: any"));
+ _cupsLangPuts(stdout, _("\tPrinter types: unknown"));
+ }
+
+ if (long_status)
+ {
+ _cupsLangPrintf(stdout, _("\tDescription: %s"),
+ description ? description : "");
+
+ if (reasons)
+ {
+ char alerts[1024], /* Alerts string */
+ *aptr; /* Pointer into alerts string */
+
+ for (i = 0, aptr = alerts; i < reasons->num_values; i ++)
+ {
+ if (i)
+ snprintf(aptr, sizeof(alerts) - (aptr - alerts), " %s",
+ reasons->values[i].string.text);
+ else
+ strlcpy(alerts, reasons->values[i].string.text,
+ sizeof(alerts));
+
+ aptr += strlen(aptr);
+ }
+
+ _cupsLangPrintf(stdout, _("\tAlerts: %s"), alerts);
+ }
+ }
+ if (long_status > 1)
+ {
+ _cupsLangPrintf(stdout, _("\tLocation: %s"),
+ location ? location : "");
+
+ if (ptype & CUPS_PRINTER_REMOTE)
+ {
+ _cupsLangPuts(stdout, _("\tConnection: remote"));
+
+ if (make_model && !strstr(make_model, "System V Printer") &&
+ !strstr(make_model, "Raw Printer") && uri)
+ _cupsLangPrintf(stdout, _("\tInterface: %s.ppd"),
+ uri);
+ }
+ else
+ {
+ _cupsLangPuts(stdout, _("\tConnection: direct"));
+
+ if (make_model && strstr(make_model, "System V Printer"))
+ _cupsLangPrintf(stdout,
+ _("\tInterface: %s/interfaces/%s"),
+ cg->cups_serverroot, printer);
+ else if (make_model && !strstr(make_model, "Raw Printer"))
+ _cupsLangPrintf(stdout,
+ _("\tInterface: %s/ppd/%s.ppd"),
+ cg->cups_serverroot, printer);
+ }
+ _cupsLangPuts(stdout, _("\tOn fault: no alert"));
+ _cupsLangPuts(stdout, _("\tAfter fault: continue"));
+ /* TODO update to use printer-error-policy */
+ if (allowed)
+ {
+ _cupsLangPuts(stdout, _("\tUsers allowed:"));
+ for (j = 0; j < allowed->num_values; j ++)
+ _cupsLangPrintf(stdout, "\t\t%s",
+ allowed->values[j].string.text);
+ }
+ else if (denied)
+ {
+ _cupsLangPuts(stdout, _("\tUsers denied:"));
+ for (j = 0; j < denied->num_values; j ++)
+ _cupsLangPrintf(stdout, "\t\t%s",
+ denied->values[j].string.text);
+ }
+ else
+ {
+ _cupsLangPuts(stdout, _("\tUsers allowed:"));
+ _cupsLangPuts(stdout, _("\t\t(all)"));
+ }
+ _cupsLangPuts(stdout, _("\tForms allowed:"));
+ _cupsLangPuts(stdout, _("\t\t(none)"));
+ _cupsLangPuts(stdout, _("\tBanner required"));
+ _cupsLangPuts(stdout, _("\tCharset sets:"));
+ _cupsLangPuts(stdout, _("\t\t(none)"));
+ _cupsLangPuts(stdout, _("\tDefault pitch:"));
+ _cupsLangPuts(stdout, _("\tDefault page size:"));
+ _cupsLangPuts(stdout, _("\tDefault port settings:"));
+ }
+
+ for (i = 0; i < num_dests; i ++)
+ if (!_cups_strcasecmp(printer, dests[i].name) && dests[i].instance)
+ {
+ switch (pstate)
+ {
+ case IPP_PRINTER_IDLE :
+ _cupsLangPrintf(stdout,
+ _("printer %s/%s is idle. "
+ "enabled since %s"),
+ printer, dests[i].instance,
+ printer_state_time);
+ break;
+ case IPP_PRINTER_PROCESSING :
+ _cupsLangPrintf(stdout,
+ _("printer %s/%s now printing %s-%d. "
+ "enabled since %s"),
+ printer, dests[i].instance, printer, jobid,
+ printer_state_time);
+ break;
+ case IPP_PRINTER_STOPPED :
+ _cupsLangPrintf(stdout,
+ _("printer %s/%s disabled since %s -"),
+ printer, dests[i].instance,
+ printer_state_time);
+ break;
+ }
+
+ if ((message && *message) || pstate == IPP_PRINTER_STOPPED)
+ {
+ if (!message || !*message)
+ _cupsLangPuts(stdout, _("\treason unknown"));
+ else
+ _cupsLangPrintf(stdout, "\t%s", message);
+ }
+
+ if (long_status > 1)
+ {
+ _cupsLangPuts(stdout, _("\tForm mounted:"));
+ _cupsLangPuts(stdout, _("\tContent types: any"));
+ _cupsLangPuts(stdout, _("\tPrinter types: unknown"));
+ }
+
+ if (long_status)
+ {
+ _cupsLangPrintf(stdout, _("\tDescription: %s"),
+ description ? description : "");
+
+ if (reasons)
+ {
+ char alerts[1024], /* Alerts string */
+ *aptr; /* Pointer into alerts string */
+
+ for (i = 0, aptr = alerts; i < reasons->num_values; i ++)
+ {
+ if (i)
+ snprintf(aptr, sizeof(alerts) - (aptr - alerts), " %s",
+ reasons->values[i].string.text);
+ else
+ strlcpy(alerts, reasons->values[i].string.text,
+ sizeof(alerts));
+
+ aptr += strlen(aptr);
+ }
+
+ _cupsLangPrintf(stdout, _("\tAlerts: %s"), alerts);
+ }
+ }
+ if (long_status > 1)
+ {
+ _cupsLangPrintf(stdout, _("\tLocation: %s"),
+ location ? location : "");
+
+ if (ptype & CUPS_PRINTER_REMOTE)
+ {
+ _cupsLangPuts(stdout, _("\tConnection: remote"));
+
+ if (make_model && !strstr(make_model, "System V Printer") &&
+ !strstr(make_model, "Raw Printer") && uri)
+ _cupsLangPrintf(stdout, _("\tInterface: %s.ppd"), uri);
+ }
+ else
+ {
+ _cupsLangPuts(stdout, _("\tConnection: direct"));
+
+ if (make_model && strstr(make_model, "System V Printer"))
+ _cupsLangPrintf(stdout,
+ _("\tInterface: %s/interfaces/%s"),
+ cg->cups_serverroot, printer);
+ else if (make_model && !strstr(make_model, "Raw Printer"))
+ _cupsLangPrintf(stdout,
+ _("\tInterface: %s/ppd/%s.ppd"),
+ cg->cups_serverroot, printer);
+ }
+ _cupsLangPuts(stdout, _("\tOn fault: no alert"));
+ _cupsLangPuts(stdout, _("\tAfter fault: continue"));
+ /* TODO update to use printer-error-policy */
+ if (allowed)
+ {
+ _cupsLangPuts(stdout, _("\tUsers allowed:"));
+ for (j = 0; j < allowed->num_values; j ++)
+ _cupsLangPrintf(stdout, "\t\t%s",
+ allowed->values[j].string.text);
+ }
+ else if (denied)
+ {
+ _cupsLangPuts(stdout, _("\tUsers denied:"));
+ for (j = 0; j < denied->num_values; j ++)
+ _cupsLangPrintf(stdout, "\t\t%s",
+ denied->values[j].string.text);
+ }
+ else
+ {
+ _cupsLangPuts(stdout, _("\tUsers allowed:"));
+ _cupsLangPuts(stdout, _("\t\t(all)"));
+ }
+ _cupsLangPuts(stdout, _("\tForms allowed:"));
+ _cupsLangPuts(stdout, _("\t\t(none)"));
+ _cupsLangPuts(stdout, _("\tBanner required"));
+ _cupsLangPuts(stdout, _("\tCharset sets:"));
+ _cupsLangPuts(stdout, _("\t\t(none)"));
+ _cupsLangPuts(stdout, _("\tDefault pitch:"));
+ _cupsLangPuts(stdout, _("\tDefault page size:"));
+ _cupsLangPuts(stdout, _("\tDefault port settings:"));
+ }
+ }
+ }
+
+ if (attr == NULL)
+ break;
+ }
+
+ ippDelete(response);
+ }
+ else
+ {
+ _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'show_scheduler()' - Show scheduler status.
+ */
+
+static void
+show_scheduler(void)
+{
+ http_t *http; /* Connection to server */
+
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) != NULL)
+ {
+ _cupsLangPuts(stdout, _("scheduler is running"));
+ httpClose(http);
+ }
+ else
+ _cupsLangPuts(stdout, _("scheduler is not running"));
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/templates/Makefile b/templates/Makefile
new file mode 100644
index 000000000..0abd47d9d
--- /dev/null
+++ b/templates/Makefile
@@ -0,0 +1,204 @@
+#
+# "$Id$"
+#
+# Template makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1993-2007 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+#
+# Template files...
+#
+
+FILES = \
+ add-class.tmpl \
+ add-printer.tmpl \
+ add-rss-subscription.tmpl \
+ admin.tmpl \
+ choose-device.tmpl \
+ choose-make.tmpl \
+ choose-model.tmpl \
+ choose-serial.tmpl \
+ choose-uri.tmpl \
+ class.tmpl \
+ class-added.tmpl \
+ class-confirm.tmpl \
+ class-deleted.tmpl \
+ class-jobs-header.tmpl \
+ class-modified.tmpl \
+ classes.tmpl \
+ classes-header.tmpl \
+ command.tmpl \
+ edit-config.tmpl \
+ error.tmpl \
+ error-op.tmpl \
+ header.tmpl \
+ help-header.tmpl \
+ help-trailer.tmpl \
+ help-printable.tmpl \
+ job-cancel.tmpl \
+ job-hold.tmpl \
+ job-move.tmpl \
+ job-moved.tmpl \
+ job-release.tmpl \
+ job-restart.tmpl \
+ jobs.tmpl \
+ jobs-header.tmpl \
+ list-available-printers.tmpl \
+ modify-class.tmpl \
+ modify-printer.tmpl \
+ norestart.tmpl \
+ option-boolean.tmpl \
+ option-conflict.tmpl \
+ option-header.tmpl \
+ option-pickmany.tmpl \
+ option-pickone.tmpl \
+ option-trailer.tmpl \
+ pager.tmpl \
+ printer.tmpl \
+ printer-accept.tmpl \
+ printer-added.tmpl \
+ printer-configured.tmpl \
+ printer-confirm.tmpl \
+ printer-default.tmpl \
+ printer-deleted.tmpl \
+ printer-jobs-header.tmpl \
+ printer-modified.tmpl \
+ printer-purge.tmpl \
+ printer-reject.tmpl \
+ printer-start.tmpl \
+ printer-stop.tmpl \
+ printers.tmpl \
+ printers-header.tmpl \
+ restart.tmpl \
+ samba-export.tmpl \
+ samba-exported.tmpl \
+ search.tmpl \
+ set-printer-options-header.tmpl \
+ set-printer-options-trailer.tmpl \
+ subscription-added.tmpl \
+ subscription-canceled.tmpl \
+ test-page.tmpl \
+ trailer.tmpl \
+ users.tmpl
+
+
+#
+# Make everything...
+#
+
+all:
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Clean all config and object files...
+#
+
+clean:
+
+
+#
+# Dummy depend...
+#
+
+depend:
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data: $(INSTALL_LANGUAGES)
+ $(INSTALL_DIR) -m 755 $(DATADIR)/templates
+ for file in $(FILES); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/templates; \
+ done
+
+install-languages:
+ for lang in $(LANGUAGES); do \
+ if test -d $$lang; then \
+ $(INSTALL_DIR) -m 755 $(DATADIR)/templates/$$lang; \
+ for file in $(FILES); do \
+ $(INSTALL_DATA) $$lang/$$file $(DATADIR)/templates/$$lang >/dev/null 2>&1 || true; \
+ done \
+ fi \
+ done
+
+install-langbundle:
+
+
+#
+# Install programs...
+#
+
+install-exec:
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall files...
+#
+
+uninstall: $(UNINSTALL_LANGUAGES)
+ for file in $(FILES); do \
+ $(RM) $(DATADIR)/templates/$$file; \
+ done
+ -$(RMDIR) $(DATADIR)/templates
+
+uninstall-languages:
+ for lang in $(LANGUAGES); do \
+ for file in $(FILES); do \
+ $(RM) $(DATADIR)/templates/$$lang/$$file; \
+ done \
+ $(RMDIR) $(DATADIR)/templates/$$lang; \
+ done
+
+uninstall-langbundle:
+
+
+#
+# End of "$Id$".
+#
diff --git a/templates/add-class.tmpl b/templates/add-class.tmpl
new file mode 100644
index 000000000..eaf52d73d
--- /dev/null
+++ b/templates/add-class.tmpl
@@ -0,0 +1,40 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Add Class</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Name:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(May contain any printable characters except "/", "#", and space)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Description:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Human-readable description such as "HP LaserJet with Duplexer")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Location:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Human-readable location such as "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Members:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Add Class"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/add-printer.tmpl b/templates/add-printer.tmpl
new file mode 100644
index 000000000..361958b67
--- /dev/null
+++ b/templates/add-printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Add Printer</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+{?current_make!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE" VALUE="{current_make}">:}
+{?current_make_and_model!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{current_make_and_model}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Name:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?template_name}"><BR>
+<SMALL>(May contain any printable characters except "/", "#", and space)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Description:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_INFO}"><BR>
+<SMALL>(Human-readable description such as "HP LaserJet with Duplexer")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Location:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_LOCATION}"><BR>
+<SMALL>(Human-readable location such as "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Connection:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Sharing:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+Share This Printer</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Continue"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/add-rss-subscription.tmpl b/templates/add-rss-subscription.tmpl
new file mode 100644
index 000000000..17e3fa0d3
--- /dev/null
+++ b/templates/add-rss-subscription.tmpl
@@ -0,0 +1,44 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
+
+<H2 CLASS="title">Add RSS Subscription</H2>
+
+<TABLE SUMMARY="Add RSS Subscription form">
+<TR>
+<TH CLASS="label">Name:</TH>
+<TD COLSPAN="5"><INPUT TYPE="TEXT" NAME="SUBSCRIPTION_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?SUBSCRIPTION_NAME}"><BR>
+<SMALL>(May contain any printable characters except space, "/", "?", and "#")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Queue:</TH>
+<TD COLSPAN="5"><SELECT NAME="PRINTER_URI" SIZE="10"><OPTION VALUE="#ALL#"{?PRINTER_URI=#ALL#? SELECTED:}>All Queues</OPTION>{[printer_name]<OPTION VALUE="{printer_uri_supported}"{?PRINTER_URI={printer_uri_supported}? SELECTED:}>{printer_name}</OPTION>}</SELECT></TD>
+</TR>
+<TR VALIGN="TOP">
+<TH CLASS="label">Events:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CREATED" {?EVENT_JOB_CREATED}>Job Created<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_COMPLETED" {?EVENT_JOB_COMPLETED}>Job Completed<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_STOPPED" {?EVENT_JOB_STOPPED}>Job Stopped<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CONFIG_CHANGED" {?EVENT_JOB_CONFIG_CHANGED}>Job Options Changed</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_STOPPED" {?EVENT_PRINTER_STOPPED}>Queue Stopped<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_ADDED" {?EVENT_PRINTER_ADDED}>Queue Added<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_MODIFIED" {?EVENT_PRINTER_MODIFIED}>Queue Modified<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_DELETED" {?EVENT_PRINTER_DELETED}>Queue Deleted</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STARTED" {?EVENT_SERVER_STARTED}>Server Started<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STOPPED" {?EVENT_SERVER_STOPPED}>Server Stopped<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_RESTARTED" {?EVENT_SERVER_RESTARTED}>Server Restarted<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_AUDIT" {?EVENT_SERVER_AUDIT}>Server Security Auditing</TD>
+</TR>
+<TR>
+<TH CLASS="label">Maximum Events in Feed:</TH>
+<TD COLSPAN="5"><INPUT TYPE="NUMBER" NAME="MAX_EVENTS" SIZE="4" MAXLENGTH="4" VALUE="{MAX_EVENTS?{MAX_EVENTS}:20}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD COLSPAN="5"><INPUT TYPE="SUBMIT" VALUE="Add RSS Subscription"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/admin.tmpl b/templates/admin.tmpl
new file mode 100644
index 000000000..477da139e
--- /dev/null
+++ b/templates/admin.tmpl
@@ -0,0 +1,110 @@
+<TABLE CLASS="indent" SUMMARY="Administration Tasks">
+<TR><TD VALIGN="TOP">
+
+<H2 CLASS="title">Printers</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Add Printer"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Find New Printers"></FORM>
+<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Manage Printers"></FORM>
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Export Printers to Samba"></FORM>:}
+</P>
+
+<H2 CLASS="title">Classes</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Add Class"></FORM>
+<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Manage Classes"></FORM>
+</P>
+
+<H2 CLASS="title">Jobs</H2>
+
+<P>
+<FORM ACTION="/jobs/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Manage Jobs"></FORM>
+</P>
+
+</TD><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TD VALIGN="TOP">
+
+<H2 CLASS="title">Server</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Edit Configuration File"></FORM>
+<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="View Access Log"></FORM>
+<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="View Error Log"></FORM>
+<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="View Page Log"></FORM>
+</P>
+
+{SETTINGS_ERROR?<P>{SETTINGS_MESSAGE}</P>
+<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+
+{ADVANCEDSETTINGS?<P><B>Server Settings\:</B></P>
+
+<P><A HREF="/admin/">Advanced <SMALL>&#x25bc;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="HIDDEN" NAME="ADVANCEDSETTINGS" VALUE="YES">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Show printers shared by other systems<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protocols\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_CUPS" {?browse_remote_cups}> CUPS
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_LDAP" {?browse_remote_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_SLP" {?browse_remote_slp}> SLP:}<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Share printers connected to this system<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Max clients\:
+<INPUT TYPE="TEXT" NAME="MAX_CLIENTS" VALUE="{?max_clients}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protocols\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_CUPS" {?browse_local_cups}> CUPS
+{HAVE_DNSSD?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_DNSSD" {?browse_local_dnssd}> DNS-SD:}
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_LDAP" {?browse_local_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_SLP" {?browse_local_slp}> SLP:}<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Allow printing from the Internet<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="BROWSE_WEB_IF" {?browse_web_if}> Advertise web interface<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Allow remote administration<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Use Kerberos authentication (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Allow users to cancel any job (not just their own)<BR>
+<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_HISTORY" {?preserve_job_history}> Preserve job history<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Number of jobs\:
+<INPUT TYPE="TEXT" NAME="MAX_JOBS" VALUE="{?max_jobs}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_FILES" {?preserve_job_files}> Preserve job print files<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Save debugging information for troubleshooting<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Max log file size\:
+<INPUT TYPE="TEXT" NAME="MAX_LOG_SIZE" VALUE="{?max_log_size}" SIZE="6"></P>
+
+:<P><B>Server Settings:</B></P>
+
+<P><A HREF="/admin/?ADVANCEDSETTINGS=YES">Advanced <SMALL>&#x25b6;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Show printers shared by other systems<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Share printers connected to this system<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Allow printing from the Internet<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Allow remote administration<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Use Kerberos authentication (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Allow users to cancel any job (not just their own)<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Save debugging information for troubleshooting</P>
+
+}
+<P><INPUT TYPE="SUBMIT" NAME="CHANGESETTINGS" VALUE="Change Settings"></P>
+
+</FORM>}
+
+</TD></TR>
+</TABLE>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">RSS Subscriptions</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Add RSS Subscription"></FORM>
+</P>
+
+</DIV>
+
+{notify_subscription_id?<TABLE CLASS="list" SUMMARY="RSS Subscriptions">
+<THEAD><TR><TH>Name</TH><TH>Events</TH><TH>Queue Name</TH></TR></THEAD>
+<TBODY>{[notify_subscription_id]
+<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Cancel RSS Subscription"></FORM>&nbsp;</TD><TD>{notify_events}</TD><TD NOWRAP>&nbsp;{notify_printer_name?{notify_printer_name}:All Queues}</TD></TR>}
+</TBODY>
+</TABLE>:}
diff --git a/templates/choose-device.tmpl b/templates/choose-device.tmpl
new file mode 100644
index 000000000..c5ab251b5
--- /dev/null
+++ b/templates/choose-device.tmpl
@@ -0,0 +1,53 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Add Printer}</H2>
+
+{CUPS_GET_DEVICES_DONE?<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+{op=add-printer?:<TR>
+<TH CLASS="label">Current Connection\:</TH>
+<TD><INPUT TYPE="RADIO" NAME="DEVICE_URI" VALUE="{current_device_uri}" CHECKED>
+{current_device_uri}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Local Printers\:</TH>
+<TD>
+{[device_uri]{device_class!network?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}}
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Discovered Network Printers\:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}:}}
+</TD>
+</TR>
+<TR>
+<TR>
+<TH CLASS="label">Other Network Printers\:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?:<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+}:}}
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Continue"></TD>
+</TR>
+</TABLE>
+
+</FORM>:<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Busy Indicator"> Looking for printers...</P>}
+
+</DIV>
diff --git a/templates/choose-make.tmpl b/templates/choose-make.tmpl
new file mode 100644
index 000000000..65096ad9a
--- /dev/null
+++ b/templates/choose-make.tmpl
@@ -0,0 +1,64 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Add Printer}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Name:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Description:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Location:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Connection:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Sharing:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+{?printer_is_shared=?Do Not:{?printer_is_shared=0?Do Not:}} Share This Printer</TD>
+</TR>
+<TR>
+<TH CLASS="label">Make:</TH>
+<TD>
+<SELECT NAME="PPD_MAKE" SIZE="10">
+{[ppd_make]<OPTION VALUE="{ppd_make}" {?current_make={ppd_make}?SELECTED:}>{ppd_make}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Continue"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>&nbsp;</TD>
+</TR>
+<TR>
+<TH CLASS="label">Or Provide a PPD File:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?Add Printer:Modify Printer}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/choose-model.tmpl b/templates/choose-model.tmpl
new file mode 100644
index 000000000..992cd01fd
--- /dev/null
+++ b/templates/choose-model.tmpl
@@ -0,0 +1,60 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Add Printer}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Name:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Description:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Location:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Connection:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Sharing:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+{?printer_is_shared=?Do Not:{?printer_is_shared=0?Do Not:}} Share This Printer</TD>
+</TR>
+<TR>
+<TH CLASS="label">Make:</TH>
+<TD>{PPD_MAKE} <INPUT TYPE="SUBMIT" NAME="SELECT_MAKE" VALUE="Select Another Make/Manufacturer"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Model:</TH>
+<TD>
+<SELECT NAME="PPD_NAME" SIZE="10">
+{op=add-printer?:<OPTION VALUE="__no_change__" SELECTED>Current Driver - {current_make_and_model}</OPTION>:}
+{[ppd_name]<OPTION VALUE="{ppd_name}" {op=modify-printer?:{?current_make_and_model={ppd_make_and_model}?SELECTED:}}>{ppd_make_and_model} ({ppd_natural_language})
+}</SELECT>
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Or Provide a PPD File:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?Add Printer:Modify Printer}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/choose-serial.tmpl b/templates/choose-serial.tmpl
new file mode 100644
index 000000000..56a14a4cb
--- /dev/null
+++ b/templates/choose-serial.tmpl
@@ -0,0 +1,52 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Add Printer}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Connection:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Baud Rate:</TH>
+<TD><SELECT NAME="BAUDRATE">
+{[baudrates]<OPTION {?baudrate={baudrates}?SELECTED:}>{baudrates}}
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Parity:</TH>
+<TD><SELECT NAME="PARITY">
+<OPTION VALUE="none" {?parity=none?SELECTED:}>None
+<OPTION VALUE="even" {?parity=even?SELECTED:}>Even
+<OPTION VALUE="odd" {?parity=odd?SELECTED:}>Odd
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Data Bits:</TH>
+<TD><SELECT NAME="BITS">
+<OPTION {?bits=8?SELECTED:}>8
+<OPTION {?bits=7?SELECTED:}>7
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Flow Control:</TH>
+<TD><SELECT NAME="FLOW">
+<OPTION VALUE="none" {?flow=none?SELECTED:}>None
+<OPTION VALUE="soft" {?flow=soft?SELECTED:}>XON/XOFF (Software)
+<OPTION VALUE="hard" {?flow=hard?SELECTED:}>RTS/CTS (Hardware)
+<OPTION VALUE="dtrdsr" {?flow=dtrdsr?SELECTED:}>DTR/DSR (Hardware)
+</SELECT></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Continue"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/choose-uri.tmpl b/templates/choose-uri.tmpl
new file mode 100644
index 000000000..45d84de19
--- /dev/null
+++ b/templates/choose-uri.tmpl
@@ -0,0 +1,44 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Add Printer}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Connection:</TH>
+<TD><INPUT TYPE="URL" SIZE="60" MAXLENGTH="1023" NAME="DEVICE_URI" VALUE="{current_device_uri?{current_device_uri}:{device_uri}}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>Examples:
+<PRE>
+ http://hostname:631/ipp/
+ http://hostname:631/ipp/port1
+
+ ipp://hostname/ipp/
+ ipp://hostname/ipp/port1
+
+ lpd://hostname/queue
+
+ socket://hostname
+ socket://hostname:9100
+</PRE>
+
+<P>See <A HREF="/help/network.html" TARGET="_blank">"Network
+Printers"</A> for the correct URI to use with your printer.</P>
+
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Continue"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/class-added.tmpl b/templates/class-added.tmpl
new file mode 100644
index 000000000..c062a16d5
--- /dev/null
+++ b/templates/class-added.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Add Class</H2>
+
+<P>Class <A HREF="/classes/{printer_name}">{printer_name}</A> has been added
+successfully.
+
+</DIV>
diff --git a/templates/class-confirm.tmpl b/templates/class-confirm.tmpl
new file mode 100644
index 000000000..5f0277cb5
--- /dev/null
+++ b/templates/class-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Delete Class {printer_name}</H2>
+
+<P><B>Warning:</B> Are you sure you want to delete class
+{printer_name}?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Delete Class"></FORM></P>
+
+</DIV>
diff --git a/templates/class-deleted.tmpl b/templates/class-deleted.tmpl
new file mode 100644
index 000000000..a4ad46a0a
--- /dev/null
+++ b/templates/class-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Delete Class {printer_name}</H2>
+
+<P>Class {printer_name} has been deleted successfully.
+
+</DIV> \ No newline at end of file
diff --git a/templates/class-jobs-header.tmpl b/templates/class-jobs-header.tmpl
new file mode 100644
index 000000000..ba46f1026
--- /dev/null
+++ b/templates/class-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">Jobs</H3>
+</DIV>
diff --git a/templates/class-modified.tmpl b/templates/class-modified.tmpl
new file mode 100644
index 000000000..fe42c907b
--- /dev/null
+++ b/templates/class-modified.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modify Class {printer_name}</H2>
+
+<P>Class <A HREF="/classes/{printer_name}">{printer_name}</A> has been
+modified successfully.
+
+</DIV> \ No newline at end of file
diff --git a/templates/class.tmpl b/templates/class.tmpl
new file mode 100644
index 000000000..477e0e8ed
--- /dev/null
+++ b/templates/class.tmpl
@@ -0,0 +1,44 @@
+<DIV CLASS="indent">
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?Idle:{printer_state=4?Processing:Paused}},
+{printer_is_accepting_jobs=0?Rejecting Jobs:Accepting Jobs},
+{server_is_sharing_printers=0?Not:{printer_is_shared=0?Not:}} Shared{default_name={printer_name}?, Server Default:})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">Maintenance</OPTION>
+<OPTION VALUE="print-test-page">Print Test Page</OPTION>
+{printer_state=5?<OPTION VALUE="start-class">Resume Class</OPTION>:<OPTION VALUE="stop-class">Pause Class</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Accept Jobs</OPTION>:<OPTION VALUE="reject-jobs">Reject Jobs</OPTION>}
+<OPTION VALUE="move-jobs">Move All Jobs</OPTION>
+<OPTION VALUE="purge-jobs">Cancel All Jobs</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="1">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">Administration</OPTION>
+<OPTION VALUE="modify-class">Modify Class</OPTION>
+<OPTION VALUE="delete-class">Delete Class</OPTION>
+<OPTION VALUE="set-class-options">Set Default Options</OPTION>
+<OPTION VALUE="set-as-default">Set As Server Default</OPTION>
+<OPTION VALUE="set-allowed-users">Set Allowed Users</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Description:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Location:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Members:</TH><TD>{?member_uris=?None:{member_uris}}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Defaults:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:unknown}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/classes-header.tmpl b/templates/classes-header.tmpl
new file mode 100644
index 000000000..7ac98fbdd
--- /dev/null
+++ b/templates/classes-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?No classes:Showing {#printer_name} of {total} class{total=1?:es}}.</P>
diff --git a/templates/classes.tmpl b/templates/classes.tmpl
new file mode 100644
index 000000000..51e454fb1
--- /dev/null
+++ b/templates/classes.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Class List">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Queue Name <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Queue Name <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Description</TH><TH>Location</TH><TH>Members</TH><TH>Status</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{?member_uris=?None:{member_uris}}</TD><TD>{printer_state=3?Idle:{printer_state=4?Processing:Paused}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/command.tmpl b/templates/command.tmpl
new file mode 100644
index 000000000..9a87439ca
--- /dev/null
+++ b/templates/command.tmpl
@@ -0,0 +1,12 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{title} On {printer_name}</H2>
+
+<P>{job_state>5?:<IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16"
+ALIGN="ABSMIDDLE" ALT="Busy Indicator"> }Printer command job
+{job_state=3?pending:{job_state=4?held:
+{job_state=5?processing:{job_state=6?stopped:
+{job_state=7?canceled:{job_state=8?aborted:completed}}}}}}{job_state=9?:{job_printer_state_message?,
+<EM>"{job_printer_state_message}"</EM>:}}</P>
+
+</DIV>
diff --git a/templates/de/add-class.tmpl b/templates/de/add-class.tmpl
new file mode 100644
index 000000000..2753bb919
--- /dev/null
+++ b/templates/de/add-class.tmpl
@@ -0,0 +1,40 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Klasse hinzuf&uuml;gen</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Name:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Darf alle druckbaren Zeichen au&szlig;er "/", "#", und Leerzeichen enthalten)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Beschreibung:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(F&uuml;r Menschen lesbare Beschreibung wie "HP LaserJet with Duplexer")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Ort:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(F&uuml;r Menschen lesbarer Ort wie "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Mitglieder:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Klasse hinzuf&uuml;gen"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/de/add-printer.tmpl b/templates/de/add-printer.tmpl
new file mode 100644
index 000000000..15380b97b
--- /dev/null
+++ b/templates/de/add-printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Drucker hinzuf&uuml;gen</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+{?current_make!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE" VALUE="{current_make}">:}
+{?current_make_and_model!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{current_make_and_model}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Name:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?template_name}"><BR>
+<SMALL>(Darf alle druckbaren Zeichen au&szlig;er "/", "#", und Leerzeichen enthalten)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Beschreibung:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_INFO}"><BR>
+<SMALL>(F&uuml;r Menschen lesbare Beschreibung wie "HP LaserJet with Duplexer")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Ort:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_LOCATION}"><BR>
+<SMALL>(F&uuml;r Menschen lesbarer Ort wie "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Verbindung:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Freigabe:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+Diesen Drucker freigeben</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Weiter"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/de/add-rss-subscription.tmpl b/templates/de/add-rss-subscription.tmpl
new file mode 100644
index 000000000..6b92facb2
--- /dev/null
+++ b/templates/de/add-rss-subscription.tmpl
@@ -0,0 +1,44 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
+
+<H2 CLASS="title">RSS Subskription hinzuf&uuml;gen</H2>
+
+<TABLE SUMMARY="Forumlar zum Hinzufügen einer RSS Subskription">
+<TR>
+<TH CLASS="label">Name:</TH>
+<TD COLSPAN="5"><INPUT TYPE="TEXT" NAME="SUBSCRIPTION_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?SUBSCRIPTION_NAME}"><BR>
+<SMALL>(Darf alle druckbaren Zeichen au&szlig;er Leerzeichen, "/", "?", und "#" enthalten)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Warteschlange:</TH>
+<TD COLSPAN="5"><SELECT NAME="PRINTER_URI" SIZE="10"><OPTION VALUE="#ALL#"{?PRINTER_URI=#ALL#? SELECTED:}>Alle Warteschlangen</OPTION>{[printer_name]<OPTION VALUE="{printer_uri_supported}"{?PRINTER_URI={printer_uri_supported}? SELECTED:}>{printer_name}</OPTION>}</SELECT></TD>
+</TR>
+<TR VALIGN="TOP">
+<TH CLASS="label">Ereignisse:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CREATED" {?EVENT_JOB_CREATED}>Auftrag Erstellt<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_COMPLETED" {?EVENT_JOB_COMPLETED}>Auftrag Abgeschlossen<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_STOPPED" {?EVENT_JOB_STOPPED}>Auftrag Gestoppt<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CONFIG_CHANGED" {?EVENT_JOB_CONFIG_CHANGED}>Auftrags Parameter Ge&auml;ndert</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_STOPPED" {?EVENT_PRINTER_STOPPED}>Warteschlange Gestoppt<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_ADDED" {?EVENT_PRINTER_ADDED}>Warteschlange Hinzugef&uuml;gt<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_MODIFIED" {?EVENT_PRINTER_MODIFIED}>Warteschlange Ge&auml;ndert<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_DELETED" {?EVENT_PRINTER_DELETED}>Warteschlange Gel&ouml;scht</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STARTED" {?EVENT_SERVER_STARTED}>Server Gestartet<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STOPPED" {?EVENT_SERVER_STOPPED}>Server Gestoppt<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_RESTARTED" {?EVENT_SERVER_RESTARTED}>Server Neu Gestartet<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_AUDIT" {?EVENT_SERVER_AUDIT}>Server Sicherheits Pr&uuml;fung</TD>
+</TR>
+<TR>
+<TH CLASS="label">Maximale Ereignisse in Durchf&uuml;hrung:</TH>
+<TD COLSPAN="5"><INPUT TYPE="NUMBER" NAME="MAX_EVENTS" SIZE="4" MAXLENGTH="4" VALUE="{MAX_EVENTS?{MAX_EVENTS}:20}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD COLSPAN="5"><INPUT TYPE="SUBMIT" VALUE="RSS Subskription hinzuf&uuml;gen"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/de/admin.tmpl b/templates/de/admin.tmpl
new file mode 100644
index 000000000..1ad132691
--- /dev/null
+++ b/templates/de/admin.tmpl
@@ -0,0 +1,110 @@
+<TABLE CLASS="indent" SUMMARY="Administrative T&auml;tigkeiten">
+<TR><TD VALIGN="TOP">
+
+<H2 CLASS="title">Drucker</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Drucker hinzuf&uuml;gen"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Verf&uuml;gbare Drucker auflisten"></FORM>
+<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Drucker verwalten"></FORM>
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Drucker f&uuml;r Samba freigeben"></FORM>:}
+</P>
+
+<H2 CLASS="title">Klassen</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Klasse hinzuf&uuml;gen"></FORM>
+<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Klassen verwalten"></FORM>
+</P>
+
+<H2 CLASS="title">Druckauftr&auml;ge</H2>
+
+<P>
+<FORM ACTION="/jobs/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Auftr&auml;ge verwalten"></FORM>
+</P>
+
+</TD><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TD VALIGN="TOP">
+
+<H2 CLASS="title">Server</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Konfigurationsdatei bearbeiten"></FORM>
+<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Zugriffsprotokoll betrachten"></FORM>
+<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Fehlerprotokoll betrachten"></FORM>
+<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Seitenprotokoll betrachten"></FORM>
+</P>
+
+{SETTINGS_ERROR?<P>{SETTINGS_MESSAGE}</P>
+<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+
+{ADVANCEDSETTINGS?<P><B>Erweiterte Servereinstellungen\:</B></P>
+
+<P><A HREF="/admin/">Erweitert <SMALL>&#x25bc;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="HIDDEN" NAME="ADVANCEDSETTINGS" VALUE="YES">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Zeige freigegebene Drucker von anderen Systemen<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protokolle\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_CUPS" {?browse_remote_cups}> CUPS
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_LDAP" {?browse_remote_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_SLP" {?browse_remote_slp}> SLP:}<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Freigeben von Druckern welche mit diesem System verbunden sind<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Klienten maximal\:
+<INPUT TYPE="TEXT" NAME="MAX_CLIENTS" VALUE="{?max_clients}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protokolle\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_CUPS" {?browse_local_cups}> CUPS
+{HAVE_DNSSD?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_DNSSD" {?browse_local_dnssd}> DNS-SD:}
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_LDAP" {?browse_local_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_SLP" {?browse_local_slp}> SLP:}<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Erlaube Drucken vom Internet aus<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="BROWSE_WEB_IF" {?browse_web_if}> Ver&ouml;ffentliche Webinterface<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Erlaube entfernte Verwaltung<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Benutze Kerberos Authentifizierung (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Erlaube Benutzern jeden Auftrag abzubrechen (nicht nur die Eigenen)<BR>
+<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_HISTORY" {?preserve_job_history}> Auftragsverlauf aufbewahren<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Anzahl der Auftr&auml;ge\:
+<INPUT TYPE="TEXT" NAME="MAX_JOBS" VALUE="{?max_jobs}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_FILES" {?preserve_job_files}> Dateien von Druckauftr&auml;gen aufbewahren<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Speichere Fehlerinformationen f&uuml;r Fehlersuche<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Maximale Gr&ouml;&szlig;e der Protokolldatei\:
+<INPUT TYPE="TEXT" NAME="MAX_LOG_SIZE" VALUE="{?max_log_size}" SIZE="6"></P>
+
+:<P><B>Grundlegende Servereinstellungen:</B></P>
+
+<P><A HREF="/admin/?ADVANCEDSETTINGS=YES">Erweitert <SMALL>&#x25b6;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Zeige freigegebene Drucker von anderen Systemen<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Freigeben von Druckern welche mit diesem System verbunden sind<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Erlaube Drucken vom Internet aus<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Erlaube entfernte Verwaltung<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Benutze Kerberos Authentifizierung (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Erlaube Benutzern jeden Auftrag abzubrechen (nicht nur die Eigenen)<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Speichere Fehlerinformationen f&uuml;r Fehlersuche</P>
+
+}
+<P><INPUT TYPE="SUBMIT" NAME="CHANGESETTINGS" VALUE="Einstellungen &auml;ndern"></P>
+
+</FORM>}
+
+</TD></TR>
+</TABLE>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">RSS Subskriptionen</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="RSS Subskription hinzuf&uuml;gen"></FORM>
+</P>
+
+</DIV>
+
+{notify_subscription_id?<TABLE CLASS="list" SUMMARY=">RSS Subskriptionen">
+<THEAD><TR><TH>Name</TH><TH>Ereignis</TH><TH>Warteschlange</TH></TR></THEAD>
+<TBODY>{[notify_subscription_id]
+<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="RSS Subskription k&uuml;ndigen"></FORM>&nbsp;</TD><TD>{notify_events}</TD><TD NOWRAP>&nbsp;{notify_printer_name?{notify_printer_name}:Alle Warteschlangen}</TD></TR>}
+</TBODY>
+</TABLE>:}
diff --git a/templates/de/choose-device.tmpl b/templates/de/choose-device.tmpl
new file mode 100644
index 000000000..3be8a350c
--- /dev/null
+++ b/templates/de/choose-device.tmpl
@@ -0,0 +1,54 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?{printer_name} &auml;ndern:Drucker hinzuf&uuml;gen}</H2>
+
+{CUPS_GET_DEVICES_DONE?:<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Busy Indicator"> Suche nach Druckern...</P>}
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+{op=add-printer?:<TR>
+<TH CLASS="label">Aktuelle Verbindung:</TH>
+<TD><INPUT TYPE="RADIO" NAME="DEVICE_URI" VALUE="{current_device_uri}" CHECKED>
+{current_device_uri}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Lokale Drucker:</TH>
+<TD>
+{[device_uri]{device_class!network?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unbekannt?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unbekannt?({device_make_and_model}):}<BR>
+:}}
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Entdeckte Netzwerkdrucker:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unbekannt?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unbekannt?({device_make_and_model}):}<BR>
+:}:}}
+</TD>
+</TR>
+<TR>
+<TR>
+<TH CLASS="label">Andere Netzwerkdrucker:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?:<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unbekannt?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unbekannt?({device_make_and_model}):}<BR>
+}:}}
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Weiter"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/de/choose-make.tmpl b/templates/de/choose-make.tmpl
new file mode 100644
index 000000000..6d572a6b2
--- /dev/null
+++ b/templates/de/choose-make.tmpl
@@ -0,0 +1,64 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?{printer_name} &auml;ndern:Drucker hinzuf&uuml;gen}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Name:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Beschreibung:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Ort:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Verbindung:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Freigabe:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+Diesen Drucker {?printer_is_shared=?nicht:{?printer_is_shared=0?nicht:}} freigeben</TD>
+</TR>
+<TR>
+<TH CLASS="label">Marke:</TH>
+<TD>
+<SELECT NAME="PPD_MAKE" SIZE="10">
+{[ppd_make]<OPTION VALUE="{ppd_make}" {?current_make={ppd_make}?SELECTED:}>{ppd_make}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Weiter"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>&nbsp;</TD>
+</TR>
+<TR>
+<TH CLASS="label">Oder stellen Sie eine PPD Datei bereit:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?Drucker hinzuf&uuml;gen:Drucker &auml;ndern}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/de/choose-model.tmpl b/templates/de/choose-model.tmpl
new file mode 100644
index 000000000..2f5bb18d8
--- /dev/null
+++ b/templates/de/choose-model.tmpl
@@ -0,0 +1,60 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?{printer_name} &auml;ndern:Drucker hinzuf&uuml;gen}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Name:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Beschreibung:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Ort:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Verbindung:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Freigabe:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+Diesen Drucker {?printer_is_shared=?nicht:{?printer_is_shared=0?nicht:}} freigeben</TD>
+</TR>
+<TR>
+<TH CLASS="label">Marke:</TH>
+<TD>{PPD_MAKE} <INPUT TYPE="SUBMIT" NAME="SELECT_MAKE" VALUE="Andere(n) Marke/Hersteller ausw&auml;hlen"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Modell:</TH>
+<TD>
+<SELECT NAME="PPD_NAME" SIZE="10">
+{op=add-printer?:<OPTION VALUE="__no_change__" SELECTED>Aktueller Treiber - {current_make_and_model}</OPTION>:}
+{[ppd_name]<OPTION VALUE="{ppd_name}" {op=modify-printer?:{?current_make_and_model={ppd_make_and_model}?SELECTED:}}>{ppd_make_and_model} ({ppd_natural_language})
+}</SELECT>
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Oder stellen Sie eine PPD Datei bereit:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?Drucker hinzuf&uuml;gen:Drucker &auml;ndern}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/de/choose-serial.tmpl b/templates/de/choose-serial.tmpl
new file mode 100644
index 000000000..a6f0044b5
--- /dev/null
+++ b/templates/de/choose-serial.tmpl
@@ -0,0 +1,52 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?{printer_name} &auml;ndern:Drucker hinzuf&uuml;gen}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Verbindung:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Baud Rate:</TH>
+<TD><SELECT NAME="BAUDRATE">
+{[baudrates]<OPTION {?baudrate={baudrates}?SELECTED:}>{baudrates}}
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Parit&auml;t:</TH>
+<TD><SELECT NAME="PARITY">
+<OPTION VALUE="none" {?parity=none?SELECTED:}>Keine
+<OPTION VALUE="even" {?parity=even?SELECTED:}>Gerade
+<OPTION VALUE="odd" {?parity=odd?SELECTED:}>Ungerade
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Daten Bits:</TH>
+<TD><SELECT NAME="BITS">
+<OPTION {?bits=8?SELECTED:}>8
+<OPTION {?bits=7?SELECTED:}>7
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Flu&szlig;kontrolle:</TH>
+<TD><SELECT NAME="FLOW">
+<OPTION VALUE="none" {?flow=none?SELECTED:}>None
+<OPTION VALUE="soft" {?flow=soft?SELECTED:}>XON/XOFF (Software)
+<OPTION VALUE="hard" {?flow=hard?SELECTED:}>RTS/CTS (Hardware)
+<OPTION VALUE="dtrdsr" {?flow=dtrdsr?SELECTED:}>DTR/DSR (Hardware)
+</SELECT></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Weiter"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/de/choose-uri.tmpl b/templates/de/choose-uri.tmpl
new file mode 100644
index 000000000..0633fd6cd
--- /dev/null
+++ b/templates/de/choose-uri.tmpl
@@ -0,0 +1,44 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?{printer_name} &auml;ndern:Drucker hinzuf&uuml;gen}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Verbindung:</TH>
+<TD><INPUT TYPE="URL" SIZE="60" MAXLENGTH="1024" NAME="DEVICE_URI" VALUE="{current_device_uri?{current_device_uri}:{device_uri}}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>Beispiele:
+<PRE>
+ http://Hostname:631/ipp/
+ http://Hostname:631/ipp/Anschluss1
+
+ ipp://Hostname/ipp/
+ ipp://Hostname/ipp/Anschluss1
+
+ lpd://Hostname/Warteschlange
+
+ socket://Hostname
+ socket://Hostname:9100
+</PRE>
+
+<P>Bitte lesen Sie <A HREF="/help/network.html" TARGET="_blank">"Netzwerk
+Drucker"</A> um die korrekte URI f&uuml;r Ihren Drucker zu benutzen.</P>
+
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Weiter"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/de/class-added.tmpl b/templates/de/class-added.tmpl
new file mode 100644
index 000000000..3b05769a3
--- /dev/null
+++ b/templates/de/class-added.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Klasse hinzuf&uuml;gen</H2>
+
+<P>Die Klasse <A HREF="/classes/{printer_name}">{printer_name}</A> wurde erfolgreich
+hinzugef&uuml;gt.
+
+</DIV>
diff --git a/templates/de/class-confirm.tmpl b/templates/de/class-confirm.tmpl
new file mode 100644
index 000000000..5e0223cff
--- /dev/null
+++ b/templates/de/class-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Klasse {printer_name} l&ouml;schen</H2>
+
+<P><B>Warnung:</B> Sind Sie sicher, dass Sie die Klasse
+{printer_name} l&ouml;schen wollen?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Klasse l&ouml;schen"></FORM></P>
+
+</DIV>
diff --git a/templates/de/class-deleted.tmpl b/templates/de/class-deleted.tmpl
new file mode 100644
index 000000000..9357924c1
--- /dev/null
+++ b/templates/de/class-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Klasse {printer_name} l&ouml;schen</H2>
+
+<P>Die Klasse {printer_name} wurde erfolgreich gel&ouml;scht.
+
+</DIV>
diff --git a/templates/de/class-jobs-header.tmpl b/templates/de/class-jobs-header.tmpl
new file mode 100644
index 000000000..4f3de9340
--- /dev/null
+++ b/templates/de/class-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">Auftr&auml;ge</H3>
+</DIV>
diff --git a/templates/de/class-modified.tmpl b/templates/de/class-modified.tmpl
new file mode 100644
index 000000000..b5ad0daec
--- /dev/null
+++ b/templates/de/class-modified.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Klasse {printer_name} &auml;ndern</H2>
+
+<P>Die Klasse <A HREF="/classes/{printer_name}">{printer_name}</A> wurde
+erfolgreich ge&auml;ndert.
+
+</DIV>
diff --git a/templates/de/class.tmpl b/templates/de/class.tmpl
new file mode 100644
index 000000000..61a89dc7e
--- /dev/null
+++ b/templates/de/class.tmpl
@@ -0,0 +1,44 @@
+<DIV CLASS="indent">
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?Frei:{printer_state=4?Besch&auml;ftigt:Angehalten}},
+{printer_is_accepting_jobs=0?Auftr&auml;ge werden ablehnt:Auftr&auml;ge werden akzeptiert},
+{server_is_sharing_printers=0?Nicht:{printer_is_shared=0?Nicht:}} Freigegeben{default_name={printer_name}?, Standarddrucker:})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">Wartung</OPTION>
+<OPTION VALUE="print-test-page">Drucke Testseite</OPTION>
+{printer_state=5?<OPTION VALUE="start-class">Klasse starten</OPTION>:<OPTION VALUE="stop-class">Klasse stoppen</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Auftr&auml;ge akzeptieren</OPTION>:<OPTION VALUE="reject-jobs">Auftr&auml;ge ablehnen</OPTION>}
+<OPTION VALUE="move-jobs">Alle Auftr&auml;ge verschieben</OPTION>
+<OPTION VALUE="purge-jobs">Alle Auftr&auml;ge abbrechen</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="1">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">Administration</OPTION>
+<OPTION VALUE="modify-class">Klasse &auml;ndern</OPTION>
+<OPTION VALUE="delete-class">Klasse l&ouml;schen</OPTION>
+<OPTION VALUE="set-class-options">Standardeinstellungen festlegen</OPTION>
+<OPTION VALUE="set-as-default">Als Standard festlegen</OPTION>
+<OPTION VALUE="set-allowed-users">Erlaubte Benutzer festlegen</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Beschreibung:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Ort:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Mitglieder:</TH><TD>{?member_uris=?None:{member_uris}}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Standardeinstellungen:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:unbekannt}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/de/classes-header.tmpl b/templates/de/classes-header.tmpl
new file mode 100644
index 000000000..5fa4d4ae3
--- /dev/null
+++ b/templates/de/classes-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?Keine Klassen:Zeige {#printer_name} von {total} Klasse{total=1?:n}}.</P>
diff --git a/templates/de/classes.tmpl b/templates/de/classes.tmpl
new file mode 100644
index 000000000..1a919a80e
--- /dev/null
+++ b/templates/de/classes.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Class List">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Wartweschlange <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Warteschlange <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Beschreibung</TH><TH>Ort</TH><TH>Mitglieder</TH><TH>Status</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{?member_uris=?Keine:{member_uris}}</TD><TD>{printer_state=3?Frei:{printer_state=4?Besch&auml;ftigt:Angehalten}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/de/command.tmpl b/templates/de/command.tmpl
new file mode 100644
index 000000000..45e8dce56
--- /dev/null
+++ b/templates/de/command.tmpl
@@ -0,0 +1,12 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{title} auf {printer_name}</H2>
+
+<P>{job_state>5?:<IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16"
+ALIGN="ABSMIDDLE" ALT="Busy Indicator"> }Drucker Befehlsauftrag
+{job_state=3?unerledigt:{job_state=4?gehalten:
+{job_state=5?verarbeite:{job_state=6?gestoppt:
+{job_state=7?gel&ouml;scht:{job_state=8?abgebrochen:beendet}}}}}}{job_state=9?:{job_printer_state_message?,
+<EM>"{job_printer_state_message}"</EM>:}}</P>
+
+</DIV>
diff --git a/templates/de/edit-config.tmpl b/templates/de/edit-config.tmpl
new file mode 100644
index 000000000..f2913138b
--- /dev/null
+++ b/templates/de/edit-config.tmpl
@@ -0,0 +1,24 @@
+<SCRIPT TYPE="text/javascript">
+function reset_config()
+{
+ document.cups.CUPSDCONF.value = "{?cupsdconf_default}";
+}
+</SCRIPT>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Konfigurationsdatei &auml;ndern</H2>
+
+<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+
+<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
+
+<P><INPUT TYPE="SUBMIT" NAME="SAVECHANGES" VALUE="&Auml;nderungen speichern">
+<INPUT TYPE="BUTTON" VALUE="Standard Konfigurationsdatei verwenden"
+onClick="reset_config();"></P>
+
+</FORM>
+
+</DIV>
diff --git a/templates/de/error-op.tmpl b/templates/de/error-op.tmpl
new file mode 100644
index 000000000..d47e73089
--- /dev/null
+++ b/templates/de/error-op.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{?title} {?printer_name} Error</H2>
+
+<P>Fehler:</P>
+
+<BLOCKQUOTE>Unbekannte Operation "{op}"!</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/de/error.tmpl b/templates/de/error.tmpl
new file mode 100644
index 000000000..1a7f6503c
--- /dev/null
+++ b/templates/de/error.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{?title} {?printer_name} Error</H2>
+
+<P>{?message?{message}:Fehler:}</P>
+
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/de/header.tmpl.in b/templates/de/header.tmpl.in
new file mode 100644
index 000000000..09a48164f
--- /dev/null
+++ b/templates/de/header.tmpl.in
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{title} - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+ {refresh_page?<META HTTP-EQUIV="Refresh" CONTENT="{refresh_page}">:}
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="unsel"><A HREF="/">&nbsp;&nbsp;Startseite&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=admin?:un}sel"><A HREF="/admin">&nbsp;&nbsp;Verwaltung&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=classes?:un}sel"><A HREF="/classes/">&nbsp;&nbsp;Klassen&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=help?:un}sel"><A HREF="/help/">&nbsp;&nbsp;Online-Hilfe&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=jobs?:un}sel"><A HREF="/jobs/">&nbsp;&nbsp;Auftr&auml;ge&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=printers?:un}sel"><A HREF="/printers/">&nbsp;&nbsp;Drucker&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Search Help"
+VALUE="{SECTION=help?{?QUERY}:}" AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+<TR><TD COLSPAN="9">&nbsp;</TD></TR>
+</TABLE>
diff --git a/templates/de/help-header.tmpl b/templates/de/help-header.tmpl
new file mode 100644
index 000000000..a2d68a58a
--- /dev/null
+++ b/templates/de/help-header.tmpl
@@ -0,0 +1,51 @@
+<DIV CLASS="indent">
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET">
+{TOPIC?<INPUT TYPE="HIDDEN" NAME="TOPIC" VALUE="{TOPIC}">:}
+
+<P ALIGN="CENTER"><B>Suche in
+{HELPTITLE?{HELPTITLE}:{TOPIC?{TOPIC}:allen Dokumenten}}:</B> <INPUT
+TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER=""
+AUTOSAVE="org.cups.help" RESULTS="20">
+<INPUT TYPE="SUBMIT" NAME="SEARCH" VALUE="Suchen">
+<INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="Leeren"></P>
+
+</FORM>
+
+<!-- Bookmarks -->
+<DIV CLASS="sidebar"><TABLE CLASS="inset" SUMMARY="Inhalt">
+<TR><TD>
+
+<H3 CLASS="title">Online Hilfe Dokumente</H3>
+
+<P CLASS="l0"><A HREF="/help/{QUERY??QUERY={QUERY}:}">Alle Dokumente</A></P>
+<HR>
+
+{[BMTEXT]<P CLASS="l{BMINDENT}"><A HREF="{BMLINK}">{BMTEXT}</A></P>
+}
+</TD></TR>
+</TABLE></DIV>
+
+{QUERY?<P>Suchergebnisse in {HELPFILE?{HELPTITLE}:{TOPIC?{TOPIC}:allen Dokumenten}}\:</P>
+{QTEXT?<UL>
+{[QTEXT]<LI><A HREF="{QLINK}">{QTEXT}</A>{QPTEXT? (in <I><A HREF="{QPLINK}">{QPTEXT}</A></I>):}</LI>}
+{QTEXT?</UL>:}
+:<P>Keine &Uuml;bereinstimmung gefunden.</P>}
+<HR NOSHADE>:}
+{HELPTITLE?<H1>{HELPTITLE}</H1>
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="PRINTABLE" VALUE="YES"><INPUT TYPE="SUBMIT" VALUE="Druckversion anzeigen"></FORM>:
+
+<H1>CUPS Hilfeseiten</H1>
+
+<P>Dies ist das CUPS online Hilfesystem. Geben Sie Ihren Suchbegriff
+oben ein oder klicken Sie auf einen der Dokumentationslinks
+um sich die Online Hilfe Informationen anzeigen zu lassen.</P>
+
+<P>Wenn Sie noch unerfahren im Umgang mit CUPS sind, lesen Sie die "<a
+href="/help/overview.html">CUPS &Uuml;bersicht</a>".
+Erfahrene Benutzer sollten "<a href="/help/whatsnew.html">Was ist neu in CUPS
+1.4</a>" lesen.</P>
+
+<P>Die <A HREF="http://www.cups.org/">CUPS Webseite</A> bietet
+ebenfalls viele Angebote inklusive Diskussionsforen f&uuml; Benutzer,
+Antworten auf h&auml;ufig gestellte Fragen, und ein Formular für
+Fehlerberichte und W&uuml;nsche.</P>}
diff --git a/templates/de/help-printable.tmpl b/templates/de/help-printable.tmpl
new file mode 100644
index 000000000..2463c1630
--- /dev/null
+++ b/templates/de/help-printable.tmpl
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{HELPTITLE}</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups-printable.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
diff --git a/templates/de/help-trailer.tmpl b/templates/de/help-trailer.tmpl
new file mode 100644
index 000000000..4c1ebed85
--- /dev/null
+++ b/templates/de/help-trailer.tmpl
@@ -0,0 +1 @@
+</DIV>
diff --git a/templates/de/job-cancel.tmpl b/templates/de/job-cancel.tmpl
new file mode 100644
index 000000000..9bf6f3883
--- /dev/null
+++ b/templates/de/job-cancel.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Auftrag {job_id} l&ouml;schen</H2>
+
+<P><A HREF="{job_printer_uri}">Auftrag {job_id}</A> wurde gel&ouml;scht.
+
+</DIV>
diff --git a/templates/de/job-hold.tmpl b/templates/de/job-hold.tmpl
new file mode 100644
index 000000000..aaddb20b6
--- /dev/null
+++ b/templates/de/job-hold.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Auftrag {job_id} anhalten</H2>
+
+<P><A HREF="{job_printer_uri}">Auftrag {job_id}</A> wurde vom Drucken abgehalten.
+
+</DIV>
diff --git a/templates/de/job-move.tmpl b/templates/de/job-move.tmpl
new file mode 100644
index 000000000..67c57dd31
--- /dev/null
+++ b/templates/de/job-move.tmpl
@@ -0,0 +1,27 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
+
+<H2 CLASS="title">{job_id?Auftrag {job_id} verschieben:Alle Auftr&auml;ge verschieben}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">Neues Ziel:</TH>
+<TD>
+<SELECT NAME="JOB_PRINTER_URI" SIZE="10">
+{[job_printer_uri]<OPTION VALUE="{job_printer_uri}">{job_printer_name}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{job_id?Auftrag verschieben:Auftr&auml;ge verschieben}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+
+</DIV>
diff --git a/templates/de/job-moved.tmpl b/templates/de/job-moved.tmpl
new file mode 100644
index 000000000..ad9624ea6
--- /dev/null
+++ b/templates/de/job-moved.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{job_id?Auftrag {job_id} verschieben:Alle Auftr&auml;ge verschieben}</H2>
+
+<P>{job_id?<A HREF="/jobs/{job_id}">Auftrag {job_id}</A>:Alle Auftr&auml;ge} nach
+<A HREF="{job_printer_uri}">{job_printer_name}</A> verschoben.</P>
+
+</DIV>
diff --git a/templates/de/job-release.tmpl b/templates/de/job-release.tmpl
new file mode 100644
index 000000000..e1d4227fe
--- /dev/null
+++ b/templates/de/job-release.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Auftrag {job_id} freigeben</H2>
+
+<P><A HREF="{job_printer_uri}">Auftrag {job_id}</A> wurde zum Drucken freigegeben.
+
+</DIV>
diff --git a/templates/de/job-restart.tmpl b/templates/de/job-restart.tmpl
new file mode 100644
index 000000000..b4876978f
--- /dev/null
+++ b/templates/de/job-restart.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Auftrag {job_id} neu starten</H2>
+
+<P><A HREF="{job_printer_uri}">Auftrag {job_id}</A> wurde neu gestartet.
+
+</DIV>
diff --git a/templates/de/jobs-header.tmpl b/templates/de/jobs-header.tmpl
new file mode 100644
index 000000000..6565af41e
--- /dev/null
+++ b/templates/de/jobs-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">{?which_jobs=?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Aktive Auftr&auml;ge anzeigen"></FORM>}
+{?which_jobs=completed?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="completed"><INPUT TYPE="SUBMIT" VALUE="Fertige Auftr&auml;ge anzeigen"></FORM>}
+{?which_jobs=all?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="all"><INPUT TYPE="SUBMIT" VALUE="Alle Auftr&auml;ge anzeigen"></FORM>}</DIV>
+
+<P ALIGN="CENTER">{total=0?Keine Auftr&auml;ge:Zeige {#job_id} von {total} {?which_jobs=?aktiven:{which_jobs=all?:beendeten}} {total=1?Auftrag:Auftr&auml;gen}}.</P>
diff --git a/templates/de/jobs.tmpl b/templates/de/jobs.tmpl
new file mode 100644
index 000000000..94a60b0aa
--- /dev/null
+++ b/templates/de/jobs.tmpl
@@ -0,0 +1,37 @@
+{#job_id=0?:
+<TABLE CLASS="list" SUMMARY="Auftragsliste">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> ID <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> ID <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Name</TH><TH>Benutzer</TH><TH>Gr&ouml;&szlig;e</TH><TH>Seiten</TH><TH>Status</TH><TH>Kontrolle</TH></TR>
+</THEAD>
+<TBODY>
+{[job_id]
+<TR VALIGN="TOP">
+<TD><A HREF="{job_printer_uri}">{job_printer_name}</A>-{job_id}&nbsp;</TD>
+<TD>{?job_name=?Unbekannt:{job_name}}&nbsp;</TD>
+<TD>{job_originating_user_name}&nbsp;</TD>
+<TD>{job_k_octets}k&nbsp;</TD>
+<TD>{job_media_sheets_completed=0?Unbekannt:{?job_media_sheets_completed}}&nbsp;</TD>
+<TD>{job_state=3?unerledigt seit<BR>{time_at_creation}:{job_state=4?angehalten seit<BR>{time_at_creation}:
+{job_state=5?verarbeitet seit<BR>{time_at_processing}:{job_state=6?gestoppt:
+{job_state=7?gel&ouml;scht am<BR>{time_at_completed}:{job_state=8?abgebrochen:beendet am<BR>{time_at_completed}}}}}}}&nbsp;{job_printer_state_message?<BR>
+<EM>"{job_printer_state_message}"</EM>:}</TD>
+<TD>
+{job_preserved>0?{job_state>5?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Auftrag neu drucken"></FORM>:}:}
+{job_state=4?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Auftrag freigeben"></FORM>:}
+{job_state=3?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Auftrag anhalten"></FORM>:}
+{job_state<7?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Auftrag l&ouml;schen"></FORM>
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Auftrag verschieben"></FORM>:}
+&nbsp;</TD>
+</TR>
+}
+</TBODY>
+</TABLE>
+}
diff --git a/templates/de/list-available-printers.tmpl b/templates/de/list-available-printers.tmpl
new file mode 100644
index 000000000..08a04522a
--- /dev/null
+++ b/templates/de/list-available-printers.tmpl
@@ -0,0 +1,11 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Verf&uuml;gbare Drucker</H2>
+
+{#device_uri=0?<P>Keine Drucker gefunden.</P>
+:<UL>{[device_uri]
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Diesen Drucker hinzuf&uuml;gen"></FORM>
+{device_make_and_model} ({device_info})</LI>
+}</UL>}
+
+</DIV>
diff --git a/templates/de/modify-class.tmpl b/templates/de/modify-class.tmpl
new file mode 100644
index 000000000..2e0bae80d
--- /dev/null
+++ b/templates/de/modify-class.tmpl
@@ -0,0 +1,34 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Klasse {printer_name} &auml;ndern</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Beschreibung:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Ort:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Mitglieder:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Klasse &auml;ndern"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/de/modify-printer.tmpl b/templates/de/modify-printer.tmpl
new file mode 100644
index 000000000..d128471d7
--- /dev/null
+++ b/templates/de/modify-printer.tmpl
@@ -0,0 +1,42 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{printer_name} &auml;ndern</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Beschreibung:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(F&uuml;r Menschen lesbare Beschreibung wie "HP LaserJet with Duplexer")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Ort:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(F&uuml;r Menschen lesbarer Ort wie "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Verbindung:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Freigabe:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+Diesen Drucker freigeben</TD>
+</TR>
+<TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Weiter"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/de/norestart.tmpl b/templates/de/norestart.tmpl
new file mode 100644
index 000000000..fb22b154e
--- /dev/null
+++ b/templates/de/norestart.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Change Settings</H2>
+
+<P>Der Server wurde nicht neu gestartet, da die Konfiguration
+nicht ge&auml;ndert wurde...</P>
+
+</DIV>
diff --git a/templates/de/option-boolean.tmpl b/templates/de/option-boolean.tmpl
new file mode 100644
index 000000000..e832ee102
--- /dev/null
+++ b/templates/de/option-boolean.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD>
+{[choices]<INPUT TYPE="RADIO" NAME="{keyword-1}" {choices={defchoice-1}?CHECKED:} VALUE="{choices}">{text}}
+</TD>
+</TR>
diff --git a/templates/de/option-conflict.tmpl b/templates/de/option-conflict.tmpl
new file mode 100644
index 000000000..eac3c0de0
--- /dev/null
+++ b/templates/de/option-conflict.tmpl
@@ -0,0 +1,7 @@
+<P><B>Error:</B> The following options are conflicting:</P>
+
+<UL>
+{[ckeyword]<LI><A HREF="#{ckeyword}">{ckeytext}</A>: {cchoice}</LI>
+}</UL>
+
+<P>Bitte &auml;ndern sie eine oder mehrere Einstellungen um die Konflikte zu l&ouml;sen.</P>
diff --git a/templates/de/option-header.tmpl b/templates/de/option-header.tmpl
new file mode 100644
index 000000000..464726a50
--- /dev/null
+++ b/templates/de/option-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="tab" ID="{group_id}">
+
+<H3 ALIGN="CENTER">{group}</H3>
+
+<TABLE WIDTH="100%">
diff --git a/templates/de/option-pickmany.tmpl b/templates/de/option-pickmany.tmpl
new file mode 100644
index 000000000..0da75e5d2
--- /dev/null
+++ b/templates/de/option-pickmany.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" MULTIPLE SIZE="10">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT></TD>
+</TR>
diff --git a/templates/de/option-pickone.tmpl b/templates/de/option-pickone.tmpl
new file mode 100644
index 000000000..111397ce9
--- /dev/null
+++ b/templates/de/option-pickone.tmpl
@@ -0,0 +1,18 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" ID="select-{keyword}" ONCHANGE="update_paramtable('{keyword}')">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT>
+{iscustom=1?<TABLE NAME="paramtable" id="{keyword}-params">{[params]
+<TR><TH CLASS="sublabel">{paramtext}:</TH>
+<TD>{params=Units?<SELECT NAME="{keyword-1}.{params}">
+<OPTION VALUE="pt"{paramvalue=pt? SELECTED:}>Punkte</OPTION>
+<OPTION VALUE="mm"{paramvalue=mm? SELECTED:}>Millimeter</OPTION>
+<OPTION VALUE="cm"{paramvalue=cm? SELECTED:}>Zentimeter</OPTION>
+<OPTION VALUE="in"{paramvalue=in? SELECTED:}>Zoll</OPTION>
+<OPTION VALUE="ft"{paramvalue=ft? SELECTED:}>Fu&szlig;</OPTION>
+<OPTION VALUE="m"{paramvalue=m? SELECTED:}>Meter</OPTION>
+</SELECT>:<INPUT TYPE="{inputtype}" NAME="{keyword-1}.{params}" VALUE="{paramvalue}">}</TD></TR>
+}</TABLE>
+</TD>:}
+</TR>
diff --git a/templates/de/option-trailer.tmpl b/templates/de/option-trailer.tmpl
new file mode 100644
index 000000000..87adedb44
--- /dev/null
+++ b/templates/de/option-trailer.tmpl
@@ -0,0 +1,5 @@
+</TABLE>
+
+<P ALIGN="CENTER"><INPUT TYPE="SUBMIT" VALUE="Standardeinstellungen festlegen"></P>
+
+</DIV>
diff --git a/templates/de/pager.tmpl b/templates/de/pager.tmpl
new file mode 100644
index 000000000..6bc63d673
--- /dev/null
+++ b/templates/de/pager.tmpl
@@ -0,0 +1,6 @@
+<TABLE CLASS="inset" SUMMARY="Seitenverwaltung">
+<TR>
+ <TD WIDTH="50%">{PREV?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{PREV}"><INPUT TYPE="SUBMIT" VALUE="&#x25c0; Vorherige anzeigen"></FORM>:&nbsp;}</TD>
+ <TD WIDTH="50%" ALIGN="RIGHT">{NEXT?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{NEXT}"><INPUT TYPE="SUBMIT" VALUE="N&auml;chste anzeigen &#x25b6;"></FORM>:&nbsp;}</TD>
+</TR>
+</TABLE>
diff --git a/templates/de/printer-accept.tmpl b/templates/de/printer-accept.tmpl
new file mode 100644
index 000000000..25045fa03
--- /dev/null
+++ b/templates/de/printer-accept.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Auftr&auml;ge von {is_class?Klasse:Drucker} {printer_name} akzeptieren</H2>
+
+<P>{is_class?Klasse:Drucker} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+aktzeptiert jetzt Auftr&auml;ge.</P>
+
+</DIV>
diff --git a/templates/de/printer-added.tmpl b/templates/de/printer-added.tmpl
new file mode 100644
index 000000000..fe712beaa
--- /dev/null
+++ b/templates/de/printer-added.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Drucker hinzuf&uuml;gen</H2>
+
+<P>Drucker <A HREF="/printers/{printer_name}">{printer_name}</A> wurde erfolgreich
+hinzuf&uuml;gt.
+
+</DIV>
diff --git a/templates/de/printer-configured.tmpl b/templates/de/printer-configured.tmpl
new file mode 100644
index 000000000..60e27c2a5
--- /dev/null
+++ b/templates/de/printer-configured.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Standardeinstellungen f&uuml;r {printer_name} festlegen</H2>
+
+<P>Standardeinstellungen f&uuml;r {OP=set-class-options?Klasse <A HREF="/classes/{printer_name}">:Drucker <A HREF="/printers/{printer_name}">}{printer_name}</A>
+wurden erfolgreich gesetzt.
+
+</DIV>
diff --git a/templates/de/printer-confirm.tmpl b/templates/de/printer-confirm.tmpl
new file mode 100644
index 000000000..030f6524a
--- /dev/null
+++ b/templates/de/printer-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Drucker {printer_name} l&ouml;schen</H2>
+
+<P><B>Warnung:</B> Sind Sie sicher, dass Sie den Drucker
+{printer_name} l&ouml;schen wollen?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Drucker l&ouml;schen"></FORM></P>
+
+</DIV>
diff --git a/templates/de/printer-default.tmpl b/templates/de/printer-default.tmpl
new file mode 100644
index 000000000..ac2221f62
--- /dev/null
+++ b/templates/de/printer-default.tmpl
@@ -0,0 +1,13 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{is_class?Klasse:Drucker} {printer_name} als Standard festlegen</H2>
+
+<P>{is_class?Klasse:Drucker} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+wurde zum Standarddrucker für diesen Server gemacht.</P>
+
+<BLOCKQUOTE><B>Notiz:</B> Die Einstellungen des Standarddruckers
+welche von Benutzern mittels dem <TT>lpoptions</TT> Befehl gesetzt wurden,
+&uuml;berschreiben diese Einstellung.</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/de/printer-deleted.tmpl b/templates/de/printer-deleted.tmpl
new file mode 100644
index 000000000..604611303
--- /dev/null
+++ b/templates/de/printer-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Drucker {printer_name} l&ouml;schen</H2>
+
+<P>Drucker {printer_name} wurde erfolgreich gel&ouml;scht.
+
+</DIV>
diff --git a/templates/de/printer-jobs-header.tmpl b/templates/de/printer-jobs-header.tmpl
new file mode 100644
index 000000000..4f3de9340
--- /dev/null
+++ b/templates/de/printer-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">Auftr&auml;ge</H3>
+</DIV>
diff --git a/templates/de/printer-modified.tmpl b/templates/de/printer-modified.tmpl
new file mode 100644
index 000000000..b6e10bd4e
--- /dev/null
+++ b/templates/de/printer-modified.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Drucker {printer_name} &auml;ndern</H2>
+
+<P>Drucker <A HREF="/printers/{printer_name}">{printer_name}</A> wurde
+erfolgreich ge&auml;ndert.
+
+</DIV>
diff --git a/templates/de/printer-purge.tmpl b/templates/de/printer-purge.tmpl
new file mode 100644
index 000000000..1ff63ac0f
--- /dev/null
+++ b/templates/de/printer-purge.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Auftr&auml;ge f&uuml;r {is_class?die Klasse:den Drucker} {printer_name} verwerfen</H2>
+
+<P>Auftr&auml;ge f&uuml;r {is_class?die Klasse:den Drucker} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+wurden verworfen.</P>
+
+</DIV>
diff --git a/templates/de/printer-reject.tmpl b/templates/de/printer-reject.tmpl
new file mode 100644
index 000000000..1a5de730f
--- /dev/null
+++ b/templates/de/printer-reject.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Auftr&auml;ge f&uuml;r {is_class?die Klasse:den Drucker} {printer_name} ablehnen</H2>
+
+<P>{is_class?Die Klasse:Der Drucker} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+akzeptiert keine weiteren Auftr&auml;ge.</P>
+
+</DIV>
diff --git a/templates/de/printer-start.tmpl b/templates/de/printer-start.tmpl
new file mode 100644
index 000000000..7a78568e6
--- /dev/null
+++ b/templates/de/printer-start.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{is_class?Die Klasse:Den Drucker} {printer_name} fortfahren</H2>
+
+<P>{is_class?Die Klassen:Der Drucker} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+wird fortgesetzt.</P>
+
+</DIV>
diff --git a/templates/de/printer-stop.tmpl b/templates/de/printer-stop.tmpl
new file mode 100644
index 000000000..b304bd929
--- /dev/null
+++ b/templates/de/printer-stop.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{is_class?Die Klasse:Den Drucker} {printer_name} anhalten</H2>
+
+<P>{is_class?Die Klasse:Der Drucker} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+wurde angehalten.</P>
+
+</DIV>
diff --git a/templates/de/printer.tmpl b/templates/de/printer.tmpl
new file mode 100644
index 000000000..ffc58e919
--- /dev/null
+++ b/templates/de/printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?Frei:{printer_state=4?Besch&auml;ftigt:Angehalten}},
+{printer_is_accepting_jobs=0?Auftr&auml;ge werden ablehnt:Auftr&auml;ge werden akzeptiert},
+{server_is_sharing_printers=0?Nicht:{printer_is_shared=0?Nicht:}} freigegeben{default_name={printer_name}?, Standarddrucker:})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">Wartung</OPTION>
+<OPTION VALUE="print-test-page">Testseite drucken</OPTION>
+{printer_commands~.*Clean.*?<OPTION VALUE="clean-print-heads">Druckk&ouml;pfe reinigen</OPTION>:}
+{printer_commands~.*PrintSelfTestPage.*?<OPTION VALUE="print-self-test-page">Selbsttest-Seite drucken</OPTION>:}
+{printer_state=5?<OPTION VALUE="start-printer">Drucker starten</OPTION>:<OPTION VALUE="stop-printer">Drucker stoppen</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Auftr&auml;ge akzeptieren</OPTION>:<OPTION VALUE="reject-jobs">Auftr&auml;ge ablehnen</OPTION>}
+<OPTION VALUE="move-jobs">Alle Auftr&auml;ge verschieben</OPTION>
+<OPTION VALUE="purge-jobs">Alle Auftr&auml;ge abbrechen</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">Administration</OPTION>
+<OPTION VALUE="modify-printer">Drucker &auml;ndern</OPTION>
+<OPTION VALUE="delete-printer">Drucker l&ouml;schen</OPTION>
+<OPTION VALUE="set-printer-options">Standardeinstellungen festlegen</OPTION>
+<OPTION VALUE="set-as-default">Als Standard festlegen</OPTION>
+<OPTION VALUE="set-allowed-users">Erlaubte Benutzer festlegen</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Beschreibung:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Ort:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Treiber:</TH><TD>{printer_make_and_model} ({color_supported=1?color:grayscale}{sides_supported?, 2-sided printing:})<BR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Verbindung:</TH><TD>{device_uri}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Einstellungen:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:unknown}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/de/printers-header.tmpl b/templates/de/printers-header.tmpl
new file mode 100644
index 000000000..d07f783f9
--- /dev/null
+++ b/templates/de/printers-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?Keine Drucker:Zeige {#printer_name} von {total} Drucker}.</P>
diff --git a/templates/de/printers.tmpl b/templates/de/printers.tmpl
new file mode 100644
index 000000000..2180a0818
--- /dev/null
+++ b/templates/de/printers.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Druckerliste">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Queue Name <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Queue Name <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Beschreibung</TH><TH>Ort</TH><TH>Marke und Modell</TH><TH>Status</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{printer_make_and_model}</TD><TD>{printer_state=3?Frei:{printer_state=4?Besch&auml;ftigt:Angehalten}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/de/restart.tmpl b/templates/de/restart.tmpl
new file mode 100644
index 000000000..245300f9c
--- /dev/null
+++ b/templates/de/restart.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Einstellungen &auml;ndern</H2>
+
+<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Busy Indicator"> Bitte warten Sie w&auml;hrend der Server neu startet...</P>
+
+</DIV>
diff --git a/templates/de/samba-export.tmpl b/templates/de/samba-export.tmpl
new file mode 100644
index 000000000..ab2b0c60c
--- /dev/null
+++ b/templates/de/samba-export.tmpl
@@ -0,0 +1,55 @@
+<SCRIPT TYPE="text/javascript"><!--
+function select_printers() {
+ var list = document.export_samba.EXPORT_NAME;
+ var sel = document.export_samba.EXPORT_ALL.checked;
+
+ for (i = 0; i < list.length; i ++) {
+ list.options[i].selected = sel;
+ }
+}
+--></SCRIPT>
+
+<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
+
+<H2 CLASS="title">Drucker f&uuml;r Samba freigeben</H2>
+
+{error?<P>Kann Drucker nicht f&uuml;r Samba freigeben\:</P>
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+<P>Consult the <A HREF="/admin/log/error_log"
+TARGET="_blank">Fehlerprotokoll</A> Datei um mehr Informationen zu erhalten.</P>:
+<P>Diese Seite erlaubt es Ihnen Drucker f&uuml;r Samba bereitzustellen
+damit auf diese mittels Windows Clients &uuml;ber die Desktopsymbole
+<VAR>Netzwerk Nachbarn</VAR> oder <VAR>Netzwerkumgebung</VAR>
+zugegriffen werden kann. Sie müssen zuerst einen
+Windows PostScript Druckerteiber installieren wie diese in der Hilfe f&uuml;r <A
+HREF="/help/man-cupsaddsmb.html"
+TARGET="_blank">cupsaddsmb(8)</A> beschrieben ist.</P>}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Drucker:</TH>
+<TD>
+<SELECT NAME="EXPORT_NAME" SIZE="10" MULTIPLE>
+{[printer_name]<OPTION VALUE="{printer_name}"{export_all? SELECTED:{printer_export? SELECTED:}}>{printer_name}}
+</SELECT><BR>
+<INPUT TYPE="CHECKBOX" NAME="EXPORT_ALL"{export_all? CHECKED:}
+onChange="select_printers()"> Alle Drucker freigeben
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Samba Benutzername:</TH>
+<TD><INPUT TYPE="TEXT" NAME="USERNAME" VALUE="{?USERNAME}"> (ben&ouml;tigt)</TD>
+</TR>
+<TR>
+<TH CLASS="label">Samba Passwort:</TH>
+<TD><INPUT TYPE="PASSWORD" NAME="PASSWORD" VALUE=""> (ben&ouml;tigt)</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Drucker f&uuml;r Samba freigeben"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/de/samba-exported.tmpl b/templates/de/samba-exported.tmpl
new file mode 100644
index 000000000..cf5db8894
--- /dev/null
+++ b/templates/de/samba-exported.tmpl
@@ -0,0 +1 @@
+<P>Drucker wurden erfolgreich f&uuml;r Samba freigegeben.</P>
diff --git a/templates/de/search.tmpl b/templates/de/search.tmpl
new file mode 100644
index 000000000..a462ae0b0
--- /dev/null
+++ b/templates/de/search.tmpl
@@ -0,0 +1,10 @@
+<FORM ACTION="/{SECTION}/{?SEARCH_DEST}" METHOD="GET">
+{WHICH_JOBS?<INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{WHICH_JOBS}">:}
+{ORDER?<INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{ORDER}">:}
+
+<P ALIGN="CENTER"><B>Suche in
+{SEARCH_DEST?{SEARCH_DEST}:{SECTION=classes?Klassen:{SECTION=jobs?Auftr&auml;gen:Drucker}}}:</B>
+<INPUT TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER="" AUTOSAVE="org.cups.{SECTION}" RESULTS="20"> <INPUT
+TYPE="SUBMIT" VALUE="Suchen"> <INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="Leeren"></P>
+
+</FORM>
diff --git a/templates/de/set-printer-options-header.tmpl b/templates/de/set-printer-options-header.tmpl
new file mode 100644
index 000000000..75f9f4ff2
--- /dev/null
+++ b/templates/de/set-printer-options-header.tmpl
@@ -0,0 +1,26 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Standardeinstellungen f&uuml;r {printer_name} festlegen</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Drucker nach Standardeinstellungen fragen">:}
+
+<SCRIPT TYPE="text/javascript"><!--
+function update_paramtable(option)
+{
+ var cb = document.getElementById("select-" + option)
+ var paramstable = document.getElementById(option + "-params");
+ if (cb.value == "Custom")
+ paramstable.style.display = "table";
+ else
+ paramstable.style.display = "none";
+}
+--></SCRIPT>
+
+<H3 CLASS="title">{[group_id]
+<A HREF="#{group_id}">{group}</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</H3>
+
+<DIV CLASS="tabs">
diff --git a/templates/de/set-printer-options-trailer.tmpl b/templates/de/set-printer-options-trailer.tmpl
new file mode 100644
index 000000000..11adc7012
--- /dev/null
+++ b/templates/de/set-printer-options-trailer.tmpl
@@ -0,0 +1,16 @@
+</DIV>
+
+<SCRIPT TYPE="text/javascript"><!--
+// Hide custom options parameters for browsers that understand Javascript
+var paramtables = document.getElementsByName("paramtable");
+for (var i = 0; i < paramtables.length; i++)
+{
+ var opt = paramtables[i].id.substr(0, paramtables[i].id.lastIndexOf("-"));
+ var cb = document.getElementById("select-" + opt);
+ if (cb.value != "Custom")
+ paramtables[i].style.display = "none";
+}
+--></SCRIPT>
+</FORM>
+
+</DIV>
diff --git a/templates/de/subscription-added.tmpl b/templates/de/subscription-added.tmpl
new file mode 100644
index 000000000..fe4f1cd42
--- /dev/null
+++ b/templates/de/subscription-added.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>Subskription {subscription_name} wurde erfolgreich hinzugef&uuml;gt.</P>
+
+</DIV>
diff --git a/templates/de/subscription-canceled.tmpl b/templates/de/subscription-canceled.tmpl
new file mode 100644
index 000000000..56f7a977e
--- /dev/null
+++ b/templates/de/subscription-canceled.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>Subskription #{notify_subscription_id} wurde gek&uuml;ndigt.</P>
+
+</DIV>
diff --git a/templates/de/test-page.tmpl b/templates/de/test-page.tmpl
new file mode 100644
index 000000000..82ce97166
--- /dev/null
+++ b/templates/de/test-page.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Print Test Page On {printer_name}</H2>
+
+<P>Testseite gesendet; Auftrags ID ist <A HREF="/{SECTION}/{printer_name}">
+{printer_name}-{job_id}</A>.</P>
+
+</DIV>
diff --git a/templates/de/trailer.tmpl b/templates/de/trailer.tmpl
new file mode 100644
index 000000000..74f62ad7e
--- /dev/null
+++ b/templates/de/trailer.tmpl
@@ -0,0 +1,8 @@
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS und das CUPS Logo sind
+eingetragene Warenzeichen der <A HREF="http://www.apple.com">Apple Inc.</A> CUPS
+ist urheberrechtlich gesch&uuml;tzt 2007-2011 von Apple Inc, alle Rechte vorbehalten.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/templates/de/users.tmpl b/templates/de/users.tmpl
new file mode 100644
index 000000000..0704e8754
--- /dev/null
+++ b/templates/de/users.tmpl
@@ -0,0 +1,30 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
+
+<H2 CLASS="title">Erlaubte Benutzer f&uuml;r {printer_name}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">Benutzer:</TH>
+<TD>
+<INPUT TYPE='TEXT' NAME='users' SIZE='60' VALUE='{?requesting_user_name_allowed}{?requesting_user_name_denied}'>
+<BR>
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-allowed' {requesting_user_name_allowed?checked:}>Erlaube diesen Benutzern zu drucken
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-denied' {requesting_user_name_denied?checked:}>Verweigere diesen Benutzern zu drucken
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>
+<INPUT TYPE="SUBMIT" VALUE="Erlaubte Benutzer festlegen">
+</TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/edit-config.tmpl b/templates/edit-config.tmpl
new file mode 100644
index 000000000..8947382b1
--- /dev/null
+++ b/templates/edit-config.tmpl
@@ -0,0 +1,24 @@
+<SCRIPT TYPE="text/javascript">
+function reset_config()
+{
+ document.cups.CUPSDCONF.value = "{?cupsdconf_default}";
+}
+</SCRIPT>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Edit Configuration File</H2>
+
+<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+
+<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
+
+<P><INPUT TYPE="SUBMIT" NAME="SAVECHANGES" VALUE="Save Changes">
+<INPUT TYPE="BUTTON" VALUE="Use Default Configuration File"
+onClick="reset_config();"></P>
+
+</FORM>
+
+</DIV>
diff --git a/templates/error-op.tmpl b/templates/error-op.tmpl
new file mode 100644
index 000000000..feaed0f90
--- /dev/null
+++ b/templates/error-op.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{?title} {?printer_name} Error</H2>
+
+<P>Error:</P>
+
+<BLOCKQUOTE>Unknown operation "{op}"!</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/error.tmpl b/templates/error.tmpl
new file mode 100644
index 000000000..ff30a4c6c
--- /dev/null
+++ b/templates/error.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{?title} {?printer_name} Error</H2>
+
+<P>{?message?{message}:Error:}</P>
+
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/es/add-class.tmpl b/templates/es/add-class.tmpl
new file mode 100644
index 000000000..f7e79fa89
--- /dev/null
+++ b/templates/es/add-class.tmpl
@@ -0,0 +1,40 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">A&ntilde;adir clase</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Nombre:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Puede contener cualquier car&aacute;cter imprimible excepto "/", "#", y espacio)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Descripci&oacute;n:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Descripci&oacute;n f&aacute;cilmente le&iacute;ble tal como "HP LaserJet de doble cara")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Ubicaci&oacute;n:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Ubicaci&oacute;n f&aacute;cilmente le&iacute;ble tal como "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Miembros:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="A&ntilde;adir clase"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/es/add-printer.tmpl b/templates/es/add-printer.tmpl
new file mode 100644
index 000000000..eedc3db40
--- /dev/null
+++ b/templates/es/add-printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">A&ntilde;adir impresora</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+{?current_make!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE" VALUE="{current_make}">:}
+{?current_make_and_model!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{current_make_and_model}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Nombre:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?template_name}"><BR>
+<SMALL>(Puede contener cualquier car&aacute;cter imprimible excepto "/", "#", y espacio)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Descripci&oacute;n:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_INFO}"><BR>
+<SMALL>(Descripci&oacute;n f&aacute;cilmente le&iacute;ble tal como "HP LaserJet de doble cara")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Ubicaci&oacute;n:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_LOCATION}"><BR>
+<SMALL>(Ubicaci&oacute;n f&aacute;cilmente le&iacute;ble tal como "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Conexi&oacute;n:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Compartici&oacute;n:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+Compartir esta impresora</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Siguiente"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/es/add-rss-subscription.tmpl b/templates/es/add-rss-subscription.tmpl
new file mode 100644
index 000000000..d17c86eef
--- /dev/null
+++ b/templates/es/add-rss-subscription.tmpl
@@ -0,0 +1,44 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
+
+<H2 CLASS="title">A&ntilde;adir subscripci&oacute;n RSS</H2>
+
+<TABLE SUMMARY="Add RSS Subscription form">
+<TR>
+<TH CLASS="label">Nombre:</TH>
+<TD COLSPAN="5"><INPUT TYPE="TEXT" NAME="SUBSCRIPTION_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?SUBSCRIPTION_NAME}"><BR>
+<SMALL>(Puede contener cualquier car&aacute;cter imprimible excepto espacio, "/", "?", y "#"))</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Cola:</TH>
+<TD COLSPAN="5"><SELECT NAME="PRINTER_URI" SIZE="10"><OPTION VALUE="#ALL#"{?PRINTER_URI=#ALL#? SELECTED:}>Todas las colas</OPTION>{[printer_name]<OPTION VALUE="{printer_uri_supported}"{?PRINTER_URI={printer_uri_supported}? SELECTED:}>{printer_name}</OPTION>}</SELECT></TD>
+</TR>
+<TR VALIGN="TOP">
+<TH CLASS="label">Eventos:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CREATED" {?EVENT_JOB_CREATED}>Trabajo creado<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_COMPLETED" {?EVENT_JOB_COMPLETED}>Trabajo completado<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_STOPPED" {?EVENT_JOB_STOPPED}>Trabajo parado<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CONFIG_CHANGED" {?EVENT_JOB_CONFIG_CHANGED}>Opciones de trabajo cambiadas</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_STOPPED" {?EVENT_PRINTER_STOPPED}>Cola parada<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_ADDED" {?EVENT_PRINTER_ADDED}>Cola a&ntilde;adida<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_MODIFIED" {?EVENT_PRINTER_MODIFIED}>Cola modificada<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_DELETED" {?EVENT_PRINTER_DELETED}>Cola borrada</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STARTED" {?EVENT_SERVER_STARTED}>Servidor iniciado<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STOPPED" {?EVENT_SERVER_STOPPED}>Servidor parado<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_RESTARTED" {?EVENT_SERVER_RESTARTED}>Servidor reiniciado<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_AUDIT" {?EVENT_SERVER_AUDIT}>Auditor&iacute;a de seguridad del servidor</TD>
+</TR>
+<TR>
+<TH CLASS="label">N&uacute;mero m&aacute;ximo de eventos del canal:</TH>
+<TD COLSPAN="5"><INPUT TYPE="NUMBER" NAME="MAX_EVENTS" SIZE="4" MAXLENGTH="4" VALUE="{MAX_EVENTS?{MAX_EVENTS}:20}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD COLSPAN="5"><INPUT TYPE="SUBMIT" VALUE="A&ntilde;adir subscripci&oacute;n RSS"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/es/admin.tmpl b/templates/es/admin.tmpl
new file mode 100644
index 000000000..53e5d34d8
--- /dev/null
+++ b/templates/es/admin.tmpl
@@ -0,0 +1,110 @@
+<TABLE CLASS="indent" SUMMARY="Tareas de administraci&oacute;n">
+<TR><TD VALIGN="TOP">
+
+<H2 CLASS="title">Impresoras</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="A&ntilde;adir impresora"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Encontrar nuevas impresoras"></FORM>
+<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Administrar impresoras"></FORM>
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Exportar impresoras a Samba"></FORM>:}
+</P>
+
+<H2 CLASS="title">Clases</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="A&ntilde;adir clase"></FORM>
+<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Administrar clases"></FORM>
+</P>
+
+<H2 CLASS="title">Trabajos</H2>
+
+<P>
+<FORM ACTION="/jobs/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Administrar trabajos"></FORM>
+</P>
+
+</TD><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TD VALIGN="TOP">
+
+<H2 CLASS="title">Servidor</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Editar archivo configuraci&oacute;n"></FORM>
+<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Ver archivo de registro de accesos"></FORM>
+<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Ver archivo de registro de errores"></FORM>
+<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Ver archivo de registro de p&aacute;ginas"></FORM>
+</P>
+
+{SETTINGS_ERROR?<P>{SETTINGS_MESSAGE}</P>
+<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+
+{ADVANCEDSETTINGS?<P><B>Configuraci&oacute;n del servidor\:</B></P>
+
+<P><A HREF="/admin/">Avanzada <SMALL>&#x25bc;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="HIDDEN" NAME="ADVANCEDSETTINGS" VALUE="YES">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Mostrar impresoras compartidas por otros sistemas<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protocolos\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_CUPS" {?browse_remote_cups}> CUPS
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_LDAP" {?browse_remote_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_SLP" {?browse_remote_slp}> SLP:}<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Compartir impresoras conectadas a este sistema<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;N&uacute;mero m&aacute;ximo de clientes\:
+<INPUT TYPE="TEXT" NAME="MAX_CLIENTS" VALUE="{?max_clients}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protocolos\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_CUPS" {?browse_local_cups}> CUPS
+{HAVE_DNSSD?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_DNSSD" {?browse_local_dnssd}> DNS-SD:}
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_LDAP" {?browse_local_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_SLP" {?browse_local_slp}> SLP:}<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Permitir la impresi&oacute;n desde Internet<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="BROWSE_WEB_IF" {?browse_web_if}> Anunciar la interfaz web<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Permitir administraci&oacute;n remota<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Usar autentificaci&oacute;n Kerberos (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Permitir a los usuarios cancelar cualquier trabajo (no s&oacute;lo los suyos propios)<BR>
+<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_HISTORY" {?preserve_job_history}> Preservar el historial de trabajos<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;N&uacute;mero de trabajos\:
+<INPUT TYPE="TEXT" NAME="MAX_JOBS" VALUE="{?max_jobs}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_FILES" {?preserve_job_files}> Preservar los archivos de impresi&oacute;n de trabajos<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Guardar informaci&oacute;n de depuraci&oacute;n para b&uacute;squeda de problemas<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Tama&ntilde;o m&aacute;ximo del archivo de registro\:
+<INPUT TYPE="TEXT" NAME="MAX_LOG_SIZE" VALUE="{?max_log_size}" SIZE="6"></P>
+
+:<P><B>Configuraci&oacute;n del servidor:</B></P>
+
+<P><A HREF="/admin/?ADVANCEDSETTINGS=YES">Avanzada <SMALL>&#x25b6;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Mostrar impresoras compartidas por otros sistemas<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Compartir impresoras conectadas a este sistema<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Permitir la impresi&oacute;n desde Internet<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Permitir administraci&oacute;n remota<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Usar autentificaci&oacute;n Kerberos (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Permitir a los usuarios cancelar cualquier trabajo (no s&oacute;lo los suyos propios)<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Guardar informaci&oacute;n de depuraci&oacute;n para b&uacute;squeda de problemas</P>
+
+}
+<P><INPUT TYPE="SUBMIT" NAME="CHANGESETTINGS" VALUE="Cambiar configuraci&oacute;n"></P>
+
+</FORM>}
+
+</TD></TR>
+</TABLE>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Subscripciones RSS</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="A&ntilde;adir subscripci&oacute;n RSS"></FORM>
+</P>
+
+</DIV>
+
+{notify_subscription_id?<TABLE CLASS="list" SUMMARY="Subscripciones RSS">
+<THEAD><TR><TH>Nombre</TH><TH>Eventos</TH><TH>Nombre de la cola</TH></TR></THEAD>
+<TBODY>{[notify_subscription_id]
+<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Cancelar subscripci&oacute;n RSS"></FORM>&nbsp;</TD><TD>{notify_events}</TD><TD NOWRAP>&nbsp;{notify_printer_name?{notify_printer_name}:Todas las colas}</TD></TR>}
+</TBODY>
+</TABLE>:}
diff --git a/templates/es/choose-device.tmpl b/templates/es/choose-device.tmpl
new file mode 100644
index 000000000..9f314fdf6
--- /dev/null
+++ b/templates/es/choose-device.tmpl
@@ -0,0 +1,54 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modificar {printer_name}:A&ntilde;adir impresora}</H2>
+
+{CUPS_GET_DEVICES_DONE?:<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Busy Indicator"> Buscando impresoras...</P>}
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+{op=add-printer?:<TR>
+<TH CLASS="label">Conexi&oacute;n actual:</TH>
+<TD><INPUT TYPE="RADIO" NAME="DEVICE_URI" VALUE="{current_device_uri}" CHECKED>
+{current_device_uri}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Impresoras locales:</TH>
+<TD>
+{[device_uri]{device_class!network?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}}
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Impresoras en red descubiertas:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}:}}
+</TD>
+</TR>
+<TR>
+<TR>
+<TH CLASS="label">Otras impresoras en red:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?:<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+}:}}
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Siguiente"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/es/choose-make.tmpl b/templates/es/choose-make.tmpl
new file mode 100644
index 000000000..c846de4df
--- /dev/null
+++ b/templates/es/choose-make.tmpl
@@ -0,0 +1,64 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modificar {printer_name}:A&ntilde;adir impresora}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Nombre:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Descripci&oacute;n:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Ubicaci&oacute;n:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Conexi&oacute;n:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Compartici&oacute;n:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+{?printer_is_shared=?No:{?printer_is_shared=0?No:}} compartir esta impresora</TD>
+</TR>
+<TR>
+<TH CLASS="label">Marca:</TH>
+<TD>
+<SELECT NAME="PPD_MAKE" SIZE="10">
+{[ppd_make]<OPTION VALUE="{ppd_make}" {?current_make={ppd_make}?SELECTED:}>{ppd_make}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Siguiente"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>&nbsp;</TD>
+</TR>
+<TR>
+<TH CLASS="label">O proporcione un archivo PPD:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?A&ntilde;adir impresora:Modificar impresora}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/es/choose-model.tmpl b/templates/es/choose-model.tmpl
new file mode 100644
index 000000000..497d4b1d1
--- /dev/null
+++ b/templates/es/choose-model.tmpl
@@ -0,0 +1,60 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modificar {printer_name}:A&ntilde;adir impresora}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Nombre:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Descripci&oacute;n:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Ubicaci&oacute;n:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Conexi&oacute;n:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Compartici&oacute;n:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+{?printer_is_shared=?No:{?printer_is_shared=0?No:}} compartir esta impresora</TD>
+</TR>
+<TR>
+<TH CLASS="label">Marca:</TH>
+<TD>{PPD_MAKE} <INPUT TYPE="SUBMIT" NAME="SELECT_MAKE" VALUE="Seleccione otra marca/fabricante"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Modelo:</TH>
+<TD>
+<SELECT NAME="PPD_NAME" SIZE="10">
+{op=add-printer?:<OPTION VALUE="__no_change__" SELECTED>Controlador actual - {current_make_and_model}</OPTION>:}
+{[ppd_name]<OPTION VALUE="{ppd_name}" {op=modify-printer?:{?current_make_and_model={ppd_make_and_model}?SELECTED:}}>{ppd_make_and_model} ({ppd_natural_language})
+}</SELECT>
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">O proporcione un archivo PPD:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?A&ntilde;adir impresora:Modificar impresora}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/es/choose-serial.tmpl b/templates/es/choose-serial.tmpl
new file mode 100644
index 000000000..e296fb95f
--- /dev/null
+++ b/templates/es/choose-serial.tmpl
@@ -0,0 +1,52 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modificar {printer_name}:A&ntilde;adir impresora}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Conexi&ocaute;n:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Baudios:</TH>
+<TD><SELECT NAME="BAUDRATE">
+{[baudrates]<OPTION {?baudrate={baudrates}?SELECTED:}>{baudrates}}
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Paridad:</TH>
+<TD><SELECT NAME="PARITY">
+<OPTION VALUE="none" {?parity=none?SELECTED:}>Sin paridad
+<OPTION VALUE="even" {?parity=even?SELECTED:}>Par
+<OPTION VALUE="odd" {?parity=odd?SELECTED:}>Impar
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Bits de datos:</TH>
+<TD><SELECT NAME="BITS">
+<OPTION {?bits=8?SELECTED:}>8
+<OPTION {?bits=7?SELECTED:}>7
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Control de flujo:</TH>
+<TD><SELECT NAME="FLOW">
+<OPTION VALUE="none" {?flow=none?SELECTED:}>Ninguno
+<OPTION VALUE="soft" {?flow=soft?SELECTED:}>XON/XOFF (Software)
+<OPTION VALUE="hard" {?flow=hard?SELECTED:}>RTS/CTS (Hardware)
+<OPTION VALUE="dtrdsr" {?flow=dtrdsr?SELECTED:}>DTR/DSR (Hardware)
+</SELECT></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Siguiente"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/es/choose-uri.tmpl b/templates/es/choose-uri.tmpl
new file mode 100644
index 000000000..46ea17b13
--- /dev/null
+++ b/templates/es/choose-uri.tmpl
@@ -0,0 +1,44 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modificar {printer_name}:A&ntilde;adir impresora}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Conexi&oacute;n:</TH>
+<TD><INPUT TYPE="URL" SIZE="60" MAXLENGTH="1023" NAME="DEVICE_URI" VALUE="{current_device_uri?{current_device_uri}:{device_uri}}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>Ejemplos:
+<PRE>
+ http://nombre_ordenador:631/ipp/
+ http://nombre_ordenador:631/ipp/puerto1
+
+ ipp://nombre_ordenador/ipp/
+ ipp://nombre_ordenador/ipp/puerto1
+
+ lpd://nombre_ordenador/cola
+
+ socket://nombre_ordenador
+ socket://nombre_ordenador:9100
+</PRE>
+
+<P>Vea <A HREF="/help/network.html" TARGET="_blank">"Impresoras
+en red"</A> para escoger el URI adecuado a usar con su impresora.</P>
+
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Siguiente"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/es/class-added.tmpl b/templates/es/class-added.tmpl
new file mode 100644
index 000000000..867c8d928
--- /dev/null
+++ b/templates/es/class-added.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">A&ntilde;adir clase</H2>
+
+<P>Se ha a&ntilde;adido con &eacute;xito la clase <A HREF="/classes/{printer_name}">{printer_name}</A>.
+
+</DIV>
diff --git a/templates/es/class-confirm.tmpl b/templates/es/class-confirm.tmpl
new file mode 100644
index 000000000..a30ff726f
--- /dev/null
+++ b/templates/es/class-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Borrar clase {printer_name}</H2>
+
+<P><B>Advertencia:</B> &iquest;Est&aacute; seguro de querer borrar la clase
+{printer_name}?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Borrar clase"></FORM></P>
+
+</DIV>
diff --git a/templates/es/class-deleted.tmpl b/templates/es/class-deleted.tmpl
new file mode 100644
index 000000000..ced78ad70
--- /dev/null
+++ b/templates/es/class-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Borrar clase {printer_name}</H2>
+
+<P>Se ha borrado con &eacute;xito la clase {printer_name}.
+
+</DIV> \ No newline at end of file
diff --git a/templates/es/class-jobs-header.tmpl b/templates/es/class-jobs-header.tmpl
new file mode 100644
index 000000000..f25951b7a
--- /dev/null
+++ b/templates/es/class-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">Trabajos</H3>
+</DIV>
diff --git a/templates/es/class-modified.tmpl b/templates/es/class-modified.tmpl
new file mode 100644
index 000000000..d5ae2a72c
--- /dev/null
+++ b/templates/es/class-modified.tmpl
@@ -0,0 +1,6 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modificar clase {printer_name}</H2>
+
+<P>Se ha modificado con &eacute;xito la clase <A HREF="/classes/{printer_name}">{printer_name}</A>.
+</DIV> \ No newline at end of file
diff --git a/templates/es/class.tmpl b/templates/es/class.tmpl
new file mode 100644
index 000000000..5eea4f195
--- /dev/null
+++ b/templates/es/class.tmpl
@@ -0,0 +1,44 @@
+<DIV CLASS="indent">
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?inactiva:{printer_state=4?procesando:en pausa}},
+{printer_is_accepting_jobs=0?rechazando trabajos:aceptando trabajos},
+{server_is_sharing_printers=0?no:{printer_is_shared=0?no:}} compartida{default_name={printer_name}?, predeterminada del servidor:})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">Mantenimiento</OPTION>
+<OPTION VALUE="print-test-page">Imprimir p&aacute;gina de prueba</OPTION>
+{printer_state=5?<OPTION VALUE="start-class">Reanudar impresora</OPTION>:<OPTION VALUE="stop-class">Pausar impresora</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Aceptar trabajos</OPTION>:<OPTION VALUE="reject-jobs">Rechazar trabajos</OPTION>}
+<OPTION VALUE="move-jobs">Mover todos los trabajos</OPTION>
+<OPTION VALUE="purge-jobs">Cancelar todos los trabajos</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="1">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">Administraci&oacute;n</OPTION>
+<OPTION VALUE="modify-class">Modificar clase</OPTION>
+<OPTION VALUE="delete-class">Borrar clase</OPTION>
+<OPTION VALUE="set-class-options">Establecer opciones predeterminadas</OPTION>
+<OPTION VALUE="set-as-default">Poner como predeterminada del servidor</OPTION>
+<OPTION VALUE="set-allowed-users">Establecer usuarios permitidos</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Descripci&oacute;n:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Ubicaci&oacute;n:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Miembros:</TH><TD>{?member_uris=?Ninguno:{member_uris}}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Opciones predeterminadas:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:desconocido}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/es/classes-header.tmpl b/templates/es/classes-header.tmpl
new file mode 100644
index 000000000..714ab89c4
--- /dev/null
+++ b/templates/es/classes-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?No hay clases:Mostrando {#printer_name} de {total} clase{total=1?:s}}.</P>
diff --git a/templates/es/classes.tmpl b/templates/es/classes.tmpl
new file mode 100644
index 000000000..6fde7bf62
--- /dev/null
+++ b/templates/es/classes.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Lista de clases">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Nombre de la cola <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Nombre de la cola <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Descripci&oacute;n</TH><TH>Ubicaci&oacute;n</TH><TH>Miembros</TH><TH>Estado</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{?member_uris=?Ninguna:{member_uris}}</TD><TD>{printer_state=3?Inactiva:{printer_state=4?Procesando:En pausa}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/es/command.tmpl b/templates/es/command.tmpl
new file mode 100644
index 000000000..ba50560fa
--- /dev/null
+++ b/templates/es/command.tmpl
@@ -0,0 +1,12 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{title} en {printer_name}</H2>
+
+<P>{job_state>5?:<IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16"
+ALIGN="ABSMIDDLE" ALT="Indicador de ocupado"> }Trabajo de comando de impresora
+{job_state=3?pendiente:{job_state=4?retenido:
+{job_state=5?procesando:{job_state=6?parado:
+{job_state=7?cancelado:{job_state=8?anulado:completado}}}}}}{job_state=9?:{job_printer_state_message?,
+<EM>"{job_printer_state_message}"</EM>:}}</P>
+
+</DIV>
diff --git a/templates/es/edit-config.tmpl b/templates/es/edit-config.tmpl
new file mode 100644
index 000000000..a0c663436
--- /dev/null
+++ b/templates/es/edit-config.tmpl
@@ -0,0 +1,24 @@
+<SCRIPT TYPE="text/javascript">
+function reset_config()
+{
+ document.cups.CUPSDCONF.value = "{?cupsdconf_default}";
+}
+</SCRIPT>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Editar archivo de configuraci&oacute;n</H2>
+
+<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+
+<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
+
+<P><INPUT TYPE="SUBMIT" NAME="SAVECHANGES" VALUE="Guardar cambios">
+<INPUT TYPE="BUTTON" VALUE="Usar archivo de configuraci&oacute;n predeterminado"
+onClick="reset_config();"></P>
+
+</FORM>
+
+</DIV>
diff --git a/templates/es/error-op.tmpl b/templates/es/error-op.tmpl
new file mode 100644
index 000000000..d584108e8
--- /dev/null
+++ b/templates/es/error-op.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Error en {?printer_name}: {?title}</H2>
+
+<P>Error:</P>
+
+<BLOCKQUOTE>Operaci&oacute;n desconocida "{op}".</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/es/error.tmpl b/templates/es/error.tmpl
new file mode 100644
index 000000000..650bc3260
--- /dev/null
+++ b/templates/es/error.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Error en {?printer_name}: {?title}</H2>
+
+<P>{?message?{message}:Error:}</P>
+
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/es/header.tmpl.in b/templates/es/header.tmpl.in
new file mode 100644
index 000000000..b6c63b431
--- /dev/null
+++ b/templates/es/header.tmpl.in
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{title} - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+ {refresh_page?<META HTTP-EQUIV="Refresh" CONTENT="{refresh_page}">:}
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="unsel"><A HREF="/">&nbsp;&nbsp;Inicio&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=admin?:un}sel"><A HREF="/admin">&nbsp;&nbsp;Administraci&oacute;n&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=classes?:un}sel"><A HREF="/classes/">&nbsp;&nbsp;Clases&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=help?:un}sel"><A HREF="/help/">&nbsp;&nbsp;Ayuda&nbsp;en&nbsp;l&iacute;nea&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=jobs?:un}sel"><A HREF="/jobs/">&nbsp;&nbsp;Trabajos&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=printers?:un}sel"><A HREF="/printers/">&nbsp;&nbsp;Impresoras&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Buscar en la ayuda"
+VALUE="{SECTION=help?{?QUERY}:}" AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+<TR><TD COLSPAN="9">&nbsp;</TD></TR>
+</TABLE>
diff --git a/templates/es/help-header.tmpl b/templates/es/help-header.tmpl
new file mode 100644
index 000000000..d513ca319
--- /dev/null
+++ b/templates/es/help-header.tmpl
@@ -0,0 +1,51 @@
+<DIV CLASS="indent">
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET">
+{TOPIC?<INPUT TYPE="HIDDEN" NAME="TOPIC" VALUE="{TOPIC}">:}
+
+<P ALIGN="CENTER"><B>Buscar en
+{HELPTITLE?{HELPTITLE}:{TOPIC?{TOPIC}:todos los documentos}}:</B> <INPUT
+TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER=""
+AUTOSAVE="org.cups.help" RESULTS="20">
+<INPUT TYPE="SUBMIT" NAME="SEARCH" VALUE="Buscar">
+<INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="Borrar"></P>
+
+</FORM>
+
+<!-- Bookmarks -->
+<DIV CLASS="sidebar"><TABLE CLASS="inset" SUMMARY="Contenidos">
+<TR><TD>
+
+<H3 CLASS="title">Documentos de ayuda en l&iacute;nea</H3>
+
+<P CLASS="l0"><A HREF="/help/{QUERY??QUERY={QUERY}:}">Todos los documentos</A></P>
+<HR>
+
+{[BMTEXT]<P CLASS="l{BMINDENT}"><A HREF="{BMLINK}">{BMTEXT}</A></P>
+}
+</TD></TR>
+</TABLE></DIV>
+
+{QUERY?<P>Buscar resultados en {HELPFILE?{HELPTITLE}:{TOPIC?{TOPIC}:todos los documentos}}\:</P>
+{QTEXT?<UL>
+{[QTEXT]<LI><A HREF="{QLINK}">{QTEXT}</A>{QPTEXT? (in <I><A HREF="{QPLINK}">{QPTEXT}</A></I>):}</LI>}
+{QTEXT?</UL>:}
+:<P>No hay coincidencias.</P>}
+<HR NOSHADE>:}
+{HELPTITLE?<H1>{HELPTITLE}</H1>
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="PRINTABLE" VALUE="YES"><INPUT TYPE="SUBMIT" VALUE="Ver versi&oacute;n imprimible"></FORM>:
+
+<H1>Ayuda en l&iacute;nea</H1>
+
+<P>Esta es la interfaz de ayuda en l&iacute;nea de CUPS. Introduzca las palabras
+a buscar aqu&iacute; encima o haga clic en cualquiera de los enlaces de la
+documentaci&oacute;n para visualizar la informaci&oacute;n de ayuda en l&iacute;nea.</P>
+
+<P>Si es nuevo en CUPS, lea la p&aacute;gina "<a
+href="/help/overview.html">Informaci&oacute;n general de CUPS</a>". Los usuarios veteranos
+deber&iacute;an leer la p&aacute;gina "<a href="/help/whatsnew.html">Qu&eacute; hay de nuevo en CUPS
+1.4</a>".</P>
+
+<P>La <A HREF="http://www.cups.org/">p&aacute;gina de inicio de CUPS</A> tambi&eacute;n
+proporciona muchos recursos, incluyendo foros de discusi&oacute;n de usuarios, respuestas
+a preguntas frecuentes, y un formulario para el env&iacute;o de informes de errores y
+peticiones de mejoras.</P>}
diff --git a/templates/es/help-printable.tmpl b/templates/es/help-printable.tmpl
new file mode 100644
index 000000000..2463c1630
--- /dev/null
+++ b/templates/es/help-printable.tmpl
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{HELPTITLE}</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups-printable.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
diff --git a/templates/es/help-trailer.tmpl b/templates/es/help-trailer.tmpl
new file mode 100644
index 000000000..4c1ebed85
--- /dev/null
+++ b/templates/es/help-trailer.tmpl
@@ -0,0 +1 @@
+</DIV>
diff --git a/templates/es/job-cancel.tmpl b/templates/es/job-cancel.tmpl
new file mode 100644
index 000000000..6a414274c
--- /dev/null
+++ b/templates/es/job-cancel.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Cancelar trabajo {job_id}</H2>
+
+<P>Se ha cancelado el <A HREF="{job_printer_uri}">Trabajo {job_id}</A>.
+
+</DIV>
diff --git a/templates/es/job-hold.tmpl b/templates/es/job-hold.tmpl
new file mode 100644
index 000000000..3136f9d8c
--- /dev/null
+++ b/templates/es/job-hold.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Retener trabajo {job_id}</H2>
+
+<P>Se ha retenido el <A HREF="{job_printer_uri}">Trabajo {job_id}</A>.
+
+</DIV>
diff --git a/templates/es/job-move.tmpl b/templates/es/job-move.tmpl
new file mode 100644
index 000000000..e6aac39a5
--- /dev/null
+++ b/templates/es/job-move.tmpl
@@ -0,0 +1,27 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
+
+<H2 CLASS="title">{job_id?Mover trabajo {job_id}:Mover todos los trabajos}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">Nuevo destino:</TH>
+<TD>
+<SELECT NAME="JOB_PRINTER_URI" SIZE="10">
+{[job_printer_uri]<OPTION VALUE="{job_printer_uri}">{job_printer_name}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{job_id?Mover trabajo:Mover trabajos}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+
+</DIV>
diff --git a/templates/es/job-moved.tmpl b/templates/es/job-moved.tmpl
new file mode 100644
index 000000000..8eb7a9816
--- /dev/null
+++ b/templates/es/job-moved.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{job_id?Mover trabajo {job_id}:Mover todos los trabajos}</H2>
+
+<P>Se {job_id?ha movido el <A HREF="/jobs/{job_id}">Trabajo {job_id}</A>:han movido todos los trabajos} a
+<A HREF="{job_printer_uri}">{job_printer_name}</A>.</P>
+
+</DIV>
diff --git a/templates/es/job-release.tmpl b/templates/es/job-release.tmpl
new file mode 100644
index 000000000..d925e5fe5
--- /dev/null
+++ b/templates/es/job-release.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Liberar trabajo {job_id}</H2>
+
+<P>Se ha liberado el <A HREF="{job_printer_uri}">Trabajo {job_id}</A>.
+
+</DIV>
diff --git a/templates/es/job-restart.tmpl b/templates/es/job-restart.tmpl
new file mode 100644
index 000000000..ee6c8e598
--- /dev/null
+++ b/templates/es/job-restart.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Reimprimir trabajo {job_id}</H2>
+
+<P>Se ha reiniciado el <A HREF="{job_printer_uri}">Trabajo {job_id}</A>.
+
+</DIV>
diff --git a/templates/es/jobs-header.tmpl b/templates/es/jobs-header.tmpl
new file mode 100644
index 000000000..fe8b51fa8
--- /dev/null
+++ b/templates/es/jobs-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">{?which_jobs=?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Mostrar trabajos activos"></FORM>}
+{?which_jobs=completed?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="completed"><INPUT TYPE="SUBMIT" VALUE="Mostrar trabajos completados"></FORM>}
+{?which_jobs=all?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="all"><INPUT TYPE="SUBMIT" VALUE="Mostrar todos los trabajos"></FORM>}</DIV>
+
+<P ALIGN="CENTER">{total=0?No hay trabajos:Mostrando {#job_id} de {total} trabajo{total=1?:s}{?which_jobs=? activo{total=1?:s}:{which_jobs=all?: completado{total=1?:s}}}}.</P>
diff --git a/templates/es/jobs.tmpl b/templates/es/jobs.tmpl
new file mode 100644
index 000000000..e1bc195b5
--- /dev/null
+++ b/templates/es/jobs.tmpl
@@ -0,0 +1,37 @@
+{#job_id=0?:
+<TABLE CLASS="list" SUMMARY="Lista de trabajos">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> ID <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> ID <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Nombre</TH><TH>Usuario</TH><TH>Tama&ntilde;o</TH><TH>P&aacute;ginas</TH><TH>Estado</TH><TH>Control</TH></TR>
+</THEAD>
+<TBODY>
+{[job_id]
+<TR VALIGN="TOP">
+<TD><A HREF="{job_printer_uri}">{job_printer_name}</A>-{job_id}&nbsp;</TD>
+<TD>{?job_name=?Desconocido:{job_name}}&nbsp;</TD>
+<TD>{job_originating_user_name}&nbsp;</TD>
+<TD>{job_k_octets}k&nbsp;</TD>
+<TD>{job_media_sheets_completed=0?Desconocido:{?job_media_sheets_completed}}&nbsp;</TD>
+<TD>{job_state=3?pendiente desde<BR>{time_at_creation}:{job_state=4?retenido desde<BR>{time_at_creation}:
+{job_state=5?en proceso desde<BR>{time_at_processing}:{job_state=6?parado:
+{job_state=7?cancelado el<BR>{time_at_completed}:{job_state=8?anulado:completado el<BR>{time_at_completed}}}}}}}&nbsp;{job_printer_state_message?<BR>
+<EM>"{job_printer_state_message}"</EM>:}</TD>
+<TD>
+{job_preserved>0?{job_state>5?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Reimprimir trabajo"></FORM>:}:}
+{job_state=4?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Liberar trabajo"></FORM>:}
+{job_state=3?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Retener trabajo"></FORM>:}
+{job_state<7?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Cancelar trabajo"></FORM>
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Mover trabajo"></FORM>:}
+&nbsp;</TD>
+</TR>
+}
+</TBODY>
+</TABLE>
+}
diff --git a/templates/es/list-available-printers.tmpl b/templates/es/list-available-printers.tmpl
new file mode 100644
index 000000000..51e0eb982
--- /dev/null
+++ b/templates/es/list-available-printers.tmpl
@@ -0,0 +1,11 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Impresoras disponibles</H2>
+
+{#device_uri=0?<P>No se encuentran impresoras.</P>
+:<UL>{[device_uri]
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="A&ntilde;adir esta impresora"></FORM>
+{device_make_and_model} ({device_info})</LI>
+}</UL>}
+
+</DIV>
diff --git a/templates/es/modify-class.tmpl b/templates/es/modify-class.tmpl
new file mode 100644
index 000000000..a50b2bb72
--- /dev/null
+++ b/templates/es/modify-class.tmpl
@@ -0,0 +1,34 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modificar clase {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Descripci&oacute;n:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Ubicaci&oacute;n:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Miembros:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Modificar clase"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/es/modify-printer.tmpl b/templates/es/modify-printer.tmpl
new file mode 100644
index 000000000..3c09da09e
--- /dev/null
+++ b/templates/es/modify-printer.tmpl
@@ -0,0 +1,42 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modificar {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Descripci&oacute;n:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Descripci&oacute;n f&aacute;cilmente le&iacute;ble tal como "HP LaserJet de doble cara")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Ubicaci&oacute;n:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Ubicaci&oacute;n f&aacute;cilmente le&iacute;ble tal como "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Conexi&oacute;n:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Compartida:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+Compartir esta impresora</TD>
+</TR>
+<TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Siguiente"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/es/norestart.tmpl b/templates/es/norestart.tmpl
new file mode 100644
index 000000000..ac0f96bab
--- /dev/null
+++ b/templates/es/norestart.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Cambiar especificaciones</H2>
+
+<p>No se ha reiniciado el servidor debido a que no se han hecho
+cambios en la configuraci&oacute;n...</p>
+
+</DIV>
diff --git a/templates/es/option-boolean.tmpl b/templates/es/option-boolean.tmpl
new file mode 100644
index 000000000..e832ee102
--- /dev/null
+++ b/templates/es/option-boolean.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD>
+{[choices]<INPUT TYPE="RADIO" NAME="{keyword-1}" {choices={defchoice-1}?CHECKED:} VALUE="{choices}">{text}}
+</TD>
+</TR>
diff --git a/templates/es/option-conflict.tmpl b/templates/es/option-conflict.tmpl
new file mode 100644
index 000000000..adeb4363e
--- /dev/null
+++ b/templates/es/option-conflict.tmpl
@@ -0,0 +1,7 @@
+<P><B>Error:</B> Las siguientes opciones est&aacute;n en conflicto:</P>
+
+<UL>
+{[ckeyword]<LI><A HREF="#{ckeyword}">{ckeytext}</A>: {cchoice}</LI>
+}</UL>
+
+<P>Cambie una o m&aacute;s de las opciones para resolver el problema.</P>
diff --git a/templates/es/option-header.tmpl b/templates/es/option-header.tmpl
new file mode 100644
index 000000000..464726a50
--- /dev/null
+++ b/templates/es/option-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="tab" ID="{group_id}">
+
+<H3 ALIGN="CENTER">{group}</H3>
+
+<TABLE WIDTH="100%">
diff --git a/templates/es/option-pickmany.tmpl b/templates/es/option-pickmany.tmpl
new file mode 100644
index 000000000..0da75e5d2
--- /dev/null
+++ b/templates/es/option-pickmany.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" MULTIPLE SIZE="10">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT></TD>
+</TR>
diff --git a/templates/es/option-pickone.tmpl b/templates/es/option-pickone.tmpl
new file mode 100644
index 000000000..40fd124c4
--- /dev/null
+++ b/templates/es/option-pickone.tmpl
@@ -0,0 +1,18 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" ID="select-{keyword}" ONCHANGE="update_paramtable('{keyword}')">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT>
+{iscustom=1?<TABLE NAME="paramtable" id="{keyword}-params">{[params]
+<TR><TH CLASS="sublabel">{paramtext}:</TH>
+<TD>{params=Units?<SELECT NAME="{keyword-1}.{params}">
+<OPTION VALUE="pt"{paramvalue=pt? SELECTED:}>Puntos</OPTION>
+<OPTION VALUE="mm"{paramvalue=mm? SELECTED:}>Mil&iacute;metros</OPTION>
+<OPTION VALUE="cm"{paramvalue=cm? SELECTED:}>Cent&iacute;metros</OPTION>
+<OPTION VALUE="in"{paramvalue=in? SELECTED:}>Pulgadas</OPTION>
+<OPTION VALUE="ft"{paramvalue=ft? SELECTED:}>Pies</OPTION>
+<OPTION VALUE="m"{paramvalue=m? SELECTED:}>Metros</OPTION>
+</SELECT>:<INPUT TYPE="{inputtype}" NAME="{keyword-1}.{params}" VALUE="{paramvalue}">}</TD></TR>
+}</TABLE>
+</TD>:}
+</TR>
diff --git a/templates/es/option-trailer.tmpl b/templates/es/option-trailer.tmpl
new file mode 100644
index 000000000..ff8f2b239
--- /dev/null
+++ b/templates/es/option-trailer.tmpl
@@ -0,0 +1,5 @@
+</TABLE>
+
+<P ALIGN="CENTER"><INPUT TYPE="SUBMIT" VALUE="Cambiar opciones predeterminadas"></P>
+
+</DIV> \ No newline at end of file
diff --git a/templates/es/pager.tmpl b/templates/es/pager.tmpl
new file mode 100644
index 000000000..5f27c1060
--- /dev/null
+++ b/templates/es/pager.tmpl
@@ -0,0 +1,6 @@
+<TABLE CLASS="inset" SUMMARY="Barra de paginaci&oacute;n">
+<TR>
+ <TD WIDTH="50%">{PREV?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{PREV}"><INPUT TYPE="SUBMIT" VALUE="&#x25c0; Mostrar anteriores"></FORM>:&nbsp;}</TD>
+ <TD WIDTH="50%" ALIGN="RIGHT">{NEXT?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{NEXT}"><INPUT TYPE="SUBMIT" VALUE="Mostrar siguientes &#x25b6;"></FORM>:&nbsp;}</TD>
+</TR>
+</TABLE>
diff --git a/templates/es/printer-accept.tmpl b/templates/es/printer-accept.tmpl
new file mode 100644
index 000000000..63fab1b4c
--- /dev/null
+++ b/templates/es/printer-accept.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Aceptar trabajos de la {is_class?clase:impresora} {printer_name}</H2>
+
+<P>La {is_class?clase:impresora} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+ahora acepta trabajos.</P>
+
+</DIV>
diff --git a/templates/es/printer-added.tmpl b/templates/es/printer-added.tmpl
new file mode 100644
index 000000000..88c565bcf
--- /dev/null
+++ b/templates/es/printer-added.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">A&ntilde;adir impresora</H2>
+
+<P>Se ha a&ntilde;adido con &eacute;xito la impresora <A HREF="/printers/{printer_name}">{printer_name}</A>.
+
+</DIV>
diff --git a/templates/es/printer-configured.tmpl b/templates/es/printer-configured.tmpl
new file mode 100644
index 000000000..d382264f9
--- /dev/null
+++ b/templates/es/printer-configured.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Cambiar opciones predeterminadas de {printer_name}</H2>
+
+<P>Se han establecido con &eacute;xito las opciones predeterminadas de la
+{OP=set-class-options?clase <A HREF="/classes/{printer_name}">:impresora <A HREF="/printers/{printer_name}">}{printer_name}</A>.
+
+</DIV>
diff --git a/templates/es/printer-confirm.tmpl b/templates/es/printer-confirm.tmpl
new file mode 100644
index 000000000..1de104a63
--- /dev/null
+++ b/templates/es/printer-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Borrar impresora {printer_name}</H2>
+
+<P><B>Advertencia:</B> &iquest;Est&aacute; seguro de querer borrar la impresora
+{printer_name}?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Borrar impresora"></FORM></P>
+
+</DIV>
diff --git a/templates/es/printer-default.tmpl b/templates/es/printer-default.tmpl
new file mode 100644
index 000000000..68b61f267
--- /dev/null
+++ b/templates/es/printer-default.tmpl
@@ -0,0 +1,13 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Poner la {is_class?clase:impresora} {printer_name} como predeterminada</H2>
+
+<P>Se ha puesto como predeterminada en el servidor la {is_class?clase:impresora} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>.</P>
+
+<BLOCKQUOTE><B>Nota:</B> cualquier opci&oacute;n de usuario
+que haya sido activada por mediaci&oacute;n del comando
+<TT>lpoptions</TT> tiene mayor preferencia que este ajuste
+predeterminado.</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/es/printer-deleted.tmpl b/templates/es/printer-deleted.tmpl
new file mode 100644
index 000000000..8bf7db61e
--- /dev/null
+++ b/templates/es/printer-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Borrar impresora {printer_name}</H2>
+
+<P>Se ha borrado con &eacute;xito la impresora {printer_name}.
+
+</DIV>
diff --git a/templates/es/printer-jobs-header.tmpl b/templates/es/printer-jobs-header.tmpl
new file mode 100644
index 000000000..f25951b7a
--- /dev/null
+++ b/templates/es/printer-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">Trabajos</H3>
+</DIV>
diff --git a/templates/es/printer-modified.tmpl b/templates/es/printer-modified.tmpl
new file mode 100644
index 000000000..9035dce4f
--- /dev/null
+++ b/templates/es/printer-modified.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modificar impresora {printer_name}</H2>
+
+<P>Se ha modificado con &eacute;xito la impresora <A HREF="/printers/{printer_name}">{printer_name}</A>.
+
+</DIV> \ No newline at end of file
diff --git a/templates/es/printer-purge.tmpl b/templates/es/printer-purge.tmpl
new file mode 100644
index 000000000..b26bb4610
--- /dev/null
+++ b/templates/es/printer-purge.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Purgar trabajos de la {is_class?clase:impresora} {printer_name}</H2>
+
+<P>Se han purgado todos los trabajos de la {is_class?clase:impresora} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>.</P>
+
+</DIV> \ No newline at end of file
diff --git a/templates/es/printer-reject.tmpl b/templates/es/printer-reject.tmpl
new file mode 100644
index 000000000..637e13e00
--- /dev/null
+++ b/templates/es/printer-reject.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Rechazar trabajos de la {is_class?clase:impresora} {printer_name}</H2>
+
+<P>La {is_class?clase:impresora} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+ya no acepta trabajos.</P>
+
+</DIV>
diff --git a/templates/es/printer-start.tmpl b/templates/es/printer-start.tmpl
new file mode 100644
index 000000000..117afcdb0
--- /dev/null
+++ b/templates/es/printer-start.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Reanudar la {is_class?clase:impresora} {printer_name}</H2>
+
+<P>La {is_class?clase:impresora} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+ha sido reanudada.</P>
+
+</DIV> \ No newline at end of file
diff --git a/templates/es/printer-stop.tmpl b/templates/es/printer-stop.tmpl
new file mode 100644
index 000000000..af374941e
--- /dev/null
+++ b/templates/es/printer-stop.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Pausar la {is_class?clase:impresora} {printer_name}</H2>
+
+<P>La {is_class?clase:impresora} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+ha sido puesta en pausa.</P>
+
+</DIV> \ No newline at end of file
diff --git a/templates/es/printer.tmpl b/templates/es/printer.tmpl
new file mode 100644
index 000000000..f7642ac0c
--- /dev/null
+++ b/templates/es/printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?inactiva:{printer_state=4?procesando:en pausa}},
+{printer_is_accepting_jobs=0?rechazando trabajos:aceptando trabajos},
+{server_is_sharing_printers=0?no:{printer_is_shared=0?no:}} compartida{default_name={printer_name}?, predeterminada del servidor:})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">Mantenimiento</OPTION>
+<OPTION VALUE="print-test-page">Imprimir p&aacute;gina de prueba</OPTION>
+{printer_commands~.*Clean.*?<OPTION VALUE="clean-print-heads">Limpiar cabezales de impresi&oacute;n</OPTION>:}
+{printer_commands~.*PrintSelfTestPage.*?<OPTION VALUE="print-self-test-page">Imprimir p&aacute;gina de auto prueba</OPTION>:}
+{printer_state=5?<OPTION VALUE="start-printer">Reanudar impresora</OPTION>:<OPTION VALUE="stop-printer">Pausar impresora</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Aceptar trabajos</OPTION>:<OPTION VALUE="reject-jobs">Rechazar trabajos</OPTION>}
+<OPTION VALUE="move-jobs">Mover todos los trabajos</OPTION>
+<OPTION VALUE="purge-jobs">Cancelar todos los trabajos</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">Administraci&oacute;n</OPTION>
+<OPTION VALUE="modify-printer">Modificar impresora</OPTION>
+<OPTION VALUE="delete-printer">Borrar impresora</OPTION>
+<OPTION VALUE="set-printer-options">Establecer opciones predeterminadas</OPTION>
+<OPTION VALUE="set-as-default">Poner como predeterminada del servidor</OPTION>
+<OPTION VALUE="set-allowed-users">Establecer usuarios permitidos</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Descripci&oacute;n:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Ubicaci&oacute;n:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Controlador:</TH><TD>{printer_make_and_model} ({color_supported=1?color:escala de grises}{sides_supported?, d&uacute;plex:})<BR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Conexi&oacute;n:</TH><TD>{device_uri}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Opciones predeterminadas:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:desconocido}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/es/printers-header.tmpl b/templates/es/printers-header.tmpl
new file mode 100644
index 000000000..7280687bc
--- /dev/null
+++ b/templates/es/printers-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?No hay impresoras:Mostrando {#printer_name} de {total} impresora{total=1?:s}}.</P>
diff --git a/templates/es/printers.tmpl b/templates/es/printers.tmpl
new file mode 100644
index 000000000..6b97fd9e6
--- /dev/null
+++ b/templates/es/printers.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Lista de impresoras">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Nombre de la cola <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Nombre de la cola <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Descripci&oacute;n</TH><TH>Ubicaci&oacute;n</TH><TH>Marca y modelo</TH><TH>Estado</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{printer_make_and_model}</TD><TD>{printer_state=3?Inactiva:{printer_state=4?Procesando:En pausa}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/es/restart.tmpl b/templates/es/restart.tmpl
new file mode 100644
index 000000000..607351d2b
--- /dev/null
+++ b/templates/es/restart.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Cambiar especificaciones</H2>
+
+<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Indicador de ocupado"> Por favor espere mientras se reinicia el servidor...</P>
+
+</DIV>
diff --git a/templates/es/samba-export.tmpl b/templates/es/samba-export.tmpl
new file mode 100644
index 000000000..0036372ed
--- /dev/null
+++ b/templates/es/samba-export.tmpl
@@ -0,0 +1,55 @@
+<SCRIPT TYPE="text/javascript"><!--
+function select_printers() {
+ var list = document.export_samba.EXPORT_NAME;
+ var sel = document.export_samba.EXPORT_ALL.checked;
+
+ for (i = 0; i < list.length; i ++) {
+ list.options[i].selected = sel;
+ }
+}
+--></SCRIPT>
+
+<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
+
+<H2 CLASS="title">Exportar impresoras a Samba</H2>
+
+{error?<P>No se han podido exportar las impresoras a Samba\:</P>
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+<P>Consulte el archivo <A HREF="/admin/log/error_log"
+TARGET="_blank">error_log</A> para m&aacute;s informaci&oacute;n.</P>:
+<P>Esta p&aacute;gina le permite exportar las impresoras a Samba para que
+los clientes Windows puedan acceder a ellas por los iconos de su
+escritorio <VAR>Entorno de red</VAR> o <VAR>Sitios de red</VAR>. Debe haber instalado
+previamente el controlador de impresora PostScript de Windows
+como se describe en la p&aacute;gina del manual
+<A HREF="/help/man-cupsaddsmb.html"
+TARGET="_blank">cupsaddsmb(8)</A>.</P>}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Impresoras:</TH>
+<TD>
+<SELECT NAME="EXPORT_NAME" SIZE="10" MULTIPLE>
+{[printer_name]<OPTION VALUE="{printer_name}"{export_all? SELECTED:{printer_export? SELECTED:}}>{printer_name}}
+</SELECT><BR>
+<INPUT TYPE="CHECKBOX" NAME="EXPORT_ALL"{export_all? CHECKED:}
+onChange="select_printers()"> Exportar todas las impresoras
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Nombre de usuario Samba:</TH>
+<TD><INPUT TYPE="TEXT" NAME="USERNAME" VALUE="{?USERNAME}"> (necesario)</TD>
+</TR>
+<TR>
+<TH CLASS="label">Contrase&ntilde;a Samba:</TH>
+<TD><INPUT TYPE="PASSWORD" NAME="PASSWORD" VALUE=""> (necesaria)</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Exportar impresoras a Samba"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/es/samba-exported.tmpl b/templates/es/samba-exported.tmpl
new file mode 100644
index 000000000..a54925d3c
--- /dev/null
+++ b/templates/es/samba-exported.tmpl
@@ -0,0 +1 @@
+<P>Se han exportado las impresoras a samba con &eacute;xito.</P>
diff --git a/templates/es/search.tmpl b/templates/es/search.tmpl
new file mode 100644
index 000000000..3f430689c
--- /dev/null
+++ b/templates/es/search.tmpl
@@ -0,0 +1,10 @@
+<FORM ACTION="/{SECTION}/{?SEARCH_DEST}" METHOD="GET">
+{WHICH_JOBS?<INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{WHICH_JOBS}">:}
+{ORDER?<INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{ORDER}">:}
+
+<P ALIGN="CENTER"><B>Buscar en
+{SEARCH_DEST?{SEARCH_DEST}:{SECTION=classes?clases:{SECTION=jobs?trabajos:impresoras}}}:</B>
+<INPUT TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER="" AUTOSAVE="org.cups.{SECTION}" RESULTS="20"> <INPUT
+TYPE="SUBMIT" VALUE="Buscar"> <INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="Borrar"></P>
+
+</FORM>
diff --git a/templates/es/set-printer-options-header.tmpl b/templates/es/set-printer-options-header.tmpl
new file mode 100644
index 000000000..8a2740b3b
--- /dev/null
+++ b/templates/es/set-printer-options-header.tmpl
@@ -0,0 +1,26 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Establecer opciones predeterminadas de {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Consultar a la impresora las opciones predeterminadas">:}
+
+<SCRIPT TYPE="text/javascript"><!--
+function update_paramtable(option)
+{
+ var cb = document.getElementById("select-" + option)
+ var paramstable = document.getElementById(option + "-params");
+ if (cb.value == "Custom")
+ paramstable.style.display = "table";
+ else
+ paramstable.style.display = "none";
+}
+--></SCRIPT>
+
+<H3 CLASS="title">{[group_id]
+<A HREF="#{group_id}">{group}</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</H3>
+
+<DIV CLASS="tabs">
diff --git a/templates/es/set-printer-options-trailer.tmpl b/templates/es/set-printer-options-trailer.tmpl
new file mode 100644
index 000000000..11adc7012
--- /dev/null
+++ b/templates/es/set-printer-options-trailer.tmpl
@@ -0,0 +1,16 @@
+</DIV>
+
+<SCRIPT TYPE="text/javascript"><!--
+// Hide custom options parameters for browsers that understand Javascript
+var paramtables = document.getElementsByName("paramtable");
+for (var i = 0; i < paramtables.length; i++)
+{
+ var opt = paramtables[i].id.substr(0, paramtables[i].id.lastIndexOf("-"));
+ var cb = document.getElementById("select-" + opt);
+ if (cb.value != "Custom")
+ paramtables[i].style.display = "none";
+}
+--></SCRIPT>
+</FORM>
+
+</DIV>
diff --git a/templates/es/subscription-added.tmpl b/templates/es/subscription-added.tmpl
new file mode 100644
index 000000000..87ce96ae0
--- /dev/null
+++ b/templates/es/subscription-added.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>Se ha a&ntilde;adido con &eacute;xito la subscripci&oacute;n {subscription_name}.</P>
+
+</DIV>
diff --git a/templates/es/subscription-canceled.tmpl b/templates/es/subscription-canceled.tmpl
new file mode 100644
index 000000000..d6ac1711b
--- /dev/null
+++ b/templates/es/subscription-canceled.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>La subscripci&oacute;n #{notify_subscription_id} ha sido cancelada.</P>
+
+</DIV>
diff --git a/templates/es/test-page.tmpl b/templates/es/test-page.tmpl
new file mode 100644
index 000000000..763dab556
--- /dev/null
+++ b/templates/es/test-page.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Imprimir p&aacute;gina de prueba en {printer_name}</H2>
+
+<P>P&aacute;gina de prueba enviada; el n&uacute;mero del trabajo es el <A HREF="/{SECTION}/{printer_name}">
+{printer_name}-{job_id}</A>.</P>
+
+</DIV>
diff --git a/templates/es/trailer.tmpl b/templates/es/trailer.tmpl
new file mode 100644
index 000000000..3bd550b06
--- /dev/null
+++ b/templates/es/trailer.tmpl
@@ -0,0 +1,8 @@
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS y el logo de CUPS son marcas registradas de
+<A HREF="http://www.apple.com">Apple, Inc.</A> Los derechos de copia de CUPS
+2007-2011 son de Apple Inc. Todos los derechos reservados.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/templates/es/users.tmpl b/templates/es/users.tmpl
new file mode 100644
index 000000000..a8a645e6f
--- /dev/null
+++ b/templates/es/users.tmpl
@@ -0,0 +1,30 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
+
+<H2 CLASS="title">Usuarios permitidos para {printer_name}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">Usuarios:</TH>
+<TD>
+<INPUT TYPE='TEXT' NAME='users' SIZE='60' VALUE='{?requesting_user_name_allowed}{?requesting_user_name_denied}'>
+<BR>
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-allowed' {requesting_user_name_allowed?checked:}>Permitir a estos usuarios imprimir
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-denied' {requesting_user_name_denied?checked:}>Evitar que estos usuarios impriman
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>
+<INPUT TYPE="SUBMIT" VALUE="Establecer usuarios permitidos">
+</TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/eu/add-class.tmpl b/templates/eu/add-class.tmpl
new file mode 100644
index 000000000..bd7436ae2
--- /dev/null
+++ b/templates/eu/add-class.tmpl
@@ -0,0 +1,40 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Gehitu klasea</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Izena:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Inprimatu daitekeen edozein karaktere eduki dezake, "/", "#" eta zuriunea izan ezik)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Deskripzioa:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Gizakiek irakurtzeko deskripzioa, adibidez "HP LaserJet Duplexatzailearekin")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Kokalekua:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Gizakiek irakurtzeko kokalekua, adibidez "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Kideak:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Gehitu klasea"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/eu/add-printer.tmpl b/templates/eu/add-printer.tmpl
new file mode 100644
index 000000000..312da1e6e
--- /dev/null
+++ b/templates/eu/add-printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Gehitu inprimagailua</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+{?current_make!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE" VALUE="{current_make}">:}
+{?current_make_and_model!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{current_make_and_model}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Izena:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?template_name}"><BR>
+<SMALL>(Inprimatu daitekeen edozein karaktere eduki dezake, "/", "#" eta zuriunea izan ezik)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Deskripzioa:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_INFO}"><BR>
+<SMALL>(izakiek irakurtzeko deskripzioa, adibidez "HP LaserJet Duplexatzailearekin")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Kokalekua:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_LOCATION}"><BR>
+<SMALL>(izakiek irakurtzeko kokalekua, adibidez "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Konexioa:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Partekatzea:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}">
+Partekatu inprimagailu hau</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Jarraitu"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/eu/add-rss-subscription.tmpl b/templates/eu/add-rss-subscription.tmpl
new file mode 100644
index 000000000..86025a2dc
--- /dev/null
+++ b/templates/eu/add-rss-subscription.tmpl
@@ -0,0 +1,44 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
+
+<H2 CLASS="title">Gehitu RSS harpidetza</H2>
+
+<TABLE SUMMARY="RSS harpidetza gehitzeko inprimakia">
+<TR>
+<TH CLASS="label">Izena:</TH>
+<TD COLSPAN="5"><INPUT TYPE="TEXT" NAME="SUBSCRIPTION_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?SUBSCRIPTION_NAME}"><BR>
+<SMALL>(Inprimatu daitekeen edozein karaktere eduki dezake, "/", "#" eta zuriunea izan ezik)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Ilara:</TH>
+<TD COLSPAN="5"><SELECT NAME="PRINTER_URI" SIZE="10"><OPTION VALUE="#ALL#"{?PRINTER_URI=#ALL#? SELECTED:}>Ilara guztiak</OPTION>{[printer_name]<OPTION VALUE="{printer_uri_supported}"{?PRINTER_URI={printer_uri_supported}? SELECTED:}>{printer_name}</OPTION>}</SELECT></TD>
+</TR>
+<TR VALIGN="TOP">
+<TH CLASS="label">Gertaerak:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CREATED" {?EVENT_JOB_CREATED}>Lana sortuta<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_COMPLETED" {?EVENT_JOB_COMPLETED}>Lana burututa<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_STOPPED" {?EVENT_JOB_STOPPED}>Lana geldituta<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CONFIG_CHANGED" {?EVENT_JOB_CONFIG_CHANGED}>Lanaren aukerak aldatuta</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_STOPPED" {?EVENT_PRINTER_STOPPED}>Ilara geldituta<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_ADDED" {?EVENT_PRINTER_ADDED}>Ilara gehituta<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_MODIFIED" {?EVENT_PRINTER_MODIFIED}>Ilara aldatuta<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_DELETED" {?EVENT_PRINTER_DELETED}>Ilara ezabatuta</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STARTED" {?EVENT_SERVER_STARTED}>Zerbitzaria abiarazita<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STOPPED" {?EVENT_SERVER_STOPPED}>Zerbitzaria geldituta<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_RESTARTED" {?EVENT_SERVER_RESTARTED}>Zerbitzaria berrabiarazita<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_AUDIT" {?EVENT_SERVER_AUDIT}>Zerbitzariko segurtasun auditoretza</TD>
+</TR>
+<TR>
+<TH CLASS="label">Gehienezko gertaerak iturrian:</TH>
+<TD COLSPAN="5"><INPUT TYPE="NUMBER" NAME="MAX_EVENTS" SIZE="4" MAXLENGTH="4" VALUE="{MAX_EVENTS?{MAX_EVENTS}:20}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD COLSPAN="5"><INPUT TYPE="SUBMIT" VALUE="Gehitu RSS harpidetza"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/eu/admin.tmpl b/templates/eu/admin.tmpl
new file mode 100644
index 000000000..8b5ecddcb
--- /dev/null
+++ b/templates/eu/admin.tmpl
@@ -0,0 +1,110 @@
+<TABLE CLASS="indent" SUMMARY="Administrazioko atazak">
+<TR><TD VALIGN="TOP">
+
+<H2 CLASS="title">Inprimagailuak</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Gehitu inprimagailua"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Bilatu inprimagailu berriak"></FORM>
+<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Kudeatu inprimagailuak"></FORM>
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Esportatu inprimagailuak Samba-ra"></FORM>:}
+</P>
+
+<H2 CLASS="title">Klaseak</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Gehitu klasea"></FORM>
+<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Kudeatu klaseak"></FORM>
+</P>
+
+<H2 CLASS="title">Lanak</H2>
+
+<P>
+<FORM ACTION="/jobs/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Kudeatu lanak"></FORM>
+</P>
+
+</TD><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TD VALIGN="TOP">
+
+<H2 CLASS="title">Zerbitzaria</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Editatu konfigurazioko fitxategia"></FORM>
+<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Ikusi atzipenen egunkaria"></FORM>
+<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Ikusi erroreen egunkaria"></FORM>
+<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Ikusi orrialdeen egunkaria"></FORM>
+</P>
+
+{SETTINGS_ERROR?<P>{SETTINGS_MESSAGE}</P>
+<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+
+{ADVANCEDSETTINGS?<P><B>Zerbitzariaren ezarpenak\:</B></P>
+
+<P><A HREF="/admin/">Aurreratua <SMALL>&#x25bc;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="HIDDEN" NAME="ADVANCEDSETTINGS" VALUE="YES">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Erakutsi beste sistemekin partekatutako inprimagailuak<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protokoloak\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_CUPS" {?browse_remote_cups}> CUPS
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_LDAP" {?browse_remote_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_SLP" {?browse_remote_slp}> SLP:}<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Partekatu sistema honekin konektatutako inprimagailuak<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gehienezko bezeroak\:
+<INPUT TYPE="TEXT" NAME="MAX_CLIENTS" VALUE="{?max_clients}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protokoloak\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_CUPS" {?browse_local_cups}> CUPS
+{HAVE_DNSSD?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_DNSSD" {?browse_local_dnssd}> DNS-SD:}
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_LDAP" {?browse_local_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_SLP" {?browse_local_slp}> SLP:}<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Baimendu Internetetik inprimatzea<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="BROWSE_WEB_IF" {?browse_web_if}> Jakinarazi web interfazea<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Baimendu urruneko administrazioa<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Erabili Kerberos autentifikazioa (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">MEG</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Baimendu erabiltzaileek edozein lan bertan uztea (beraien lanetaz gain)<BR>
+<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_HISTORY" {?preserve_job_history}> Mantendu lanen historia<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Lan kopurua\:
+<INPUT TYPE="TEXT" NAME="MAX_JOBS" VALUE="{?max_jobs}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_FILES" {?preserve_job_files}> Mantendu lanen inprimatzeko fitxategiak<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Gorde arazketako informazioa arazoak konpontzeko<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Egunkari fitxategiaren gehienezko tamaina\:
+<INPUT TYPE="TEXT" NAME="MAX_LOG_SIZE" VALUE="{?max_log_size}" SIZE="6"></P>
+
+:<P><B>Zerbitzariaren ezarpenak:</B></P>
+
+<P><A HREF="/admin/?ADVANCEDSETTINGS=YES">Aurreratua <SMALL>&#x25b6;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Erakutsi beste sistemekin partekatutako inprimagailuak<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Partekatu sistema honekin konektatutako inprimagailuak<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Baimendu Internetetik inprimatzea<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Baimendu urruneko administrazioa<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Erabili Kerberos autentifikazioa (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">MEG</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Baimendu erabiltzaileek edozein lan bertan uztea (beraien lanetaz gain)<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Gorde arazketako informazioa arazoak konpontzeko</P>
+
+}
+<P><INPUT TYPE="SUBMIT" NAME="CHANGESETTINGS" VALUE="Aldatu ezarpenak"></P>
+
+</FORM>}
+
+</TD></TR>
+</TABLE>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">RSS harpidetzak</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Gehitu RSS harpidetza"></FORM>
+</P>
+
+</DIV>
+
+{notify_subscription_id?<TABLE CLASS="list" SUMMARY="RSS harpidetzak">
+<THEAD><TR><TH>Izena</TH><TH>Gertaerak</TH><TH>Ilararen izena</TH></TR></THEAD>
+<TBODY>{[notify_subscription_id]
+<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Utzi RSS harpidetza"></FORM>&nbsp;</TD><TD>{notify_events}</TD><TD NOWRAP>&nbsp;{notify_printer_name?{notify_printer_name}:Ilara guztiak}</TD></TR>}
+</TBODY>
+</TABLE>:}
diff --git a/templates/eu/choose-device.tmpl b/templates/eu/choose-device.tmpl
new file mode 100644
index 000000000..36b7b86b7
--- /dev/null
+++ b/templates/eu/choose-device.tmpl
@@ -0,0 +1,54 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Aldatu {printer_name}:Gehitu inprimagailua}</H2>
+
+{CUPS_GET_DEVICES_DONE?:<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Busy Indicator"> Inprimagailuak bilatzen...</P>}
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+{op=add-printer?:<TR>
+<TH CLASS="label">Uneko konexioa:</TH>
+<TD><INPUT TYPE="RADIO" NAME="DEVICE_URI" VALUE="{current_device_uri}" CHECKED>
+{current_device_uri}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Inprimagailu lokalak:</TH>
+<TD>
+{[device_uri]{device_class!network?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}}
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Aurkitutako sareko inprimagailuak:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}:}}
+</TD>
+</TR>
+<TR>
+<TR>
+<TH CLASS="label">Beste sareko inprimagailuak:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?:<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+}:}}
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Jarraitu"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/eu/choose-make.tmpl b/templates/eu/choose-make.tmpl
new file mode 100644
index 000000000..9fb389764
--- /dev/null
+++ b/templates/eu/choose-make.tmpl
@@ -0,0 +1,64 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Aldatu {printer_name}:Gehitu inprimagailua}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Izena:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Deskripzioa:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Kokalekua:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Konexioa:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Partekatzea:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+{?printer_is_shared=?Ez:{?printer_is_shared=0?Ez:}} partekatu inprimagailu hau</TD>
+</TR>
+<TR>
+<TH CLASS="label">Marka:</TH>
+<TD>
+<SELECT NAME="PPD_MAKE" SIZE="10">
+{[ppd_make]<OPTION VALUE="{ppd_make}" {?current_make={ppd_make}?SELECTED:}>{ppd_make}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Jarraitu"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>&nbsp;</TD>
+</TR>
+<TR>
+<TH CLASS="label">edo eman PPD fitxategia:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?Gehitu inprimagailua:Aldatu inprimagailua}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/eu/choose-model.tmpl b/templates/eu/choose-model.tmpl
new file mode 100644
index 000000000..5824932b7
--- /dev/null
+++ b/templates/eu/choose-model.tmpl
@@ -0,0 +1,60 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Aldatu {printer_name}:Gehitu inprimagailua}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Izena:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Deskripzioa:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Kokalekua:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Konexioa:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Partekatzea:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+{?printer_is_shared=?Ez:{?printer_is_shared=0?Ez:}} partekatu inprimagailu hau</TD>
+</TR>
+<TR>
+<TH CLASS="label">Marka:</TH>
+<TD>{PPD_MAKE} <INPUT TYPE="SUBMIT" NAME="SELECT_MAKE" VALUE="Hautatu beste marka/hornitzailea"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Modeloa:</TH>
+<TD>
+<SELECT NAME="PPD_NAME" SIZE="10">
+{op=add-printer?:<OPTION VALUE="__no_change__" SELECTED>Uneko kontrolatzailea - {current_make_and_model}</OPTION>:}
+{[ppd_name]<OPTION VALUE="{ppd_name}" {op=modify-printer?:{?current_make_and_model={ppd_make_and_model}?SELECTED:}}>{ppd_make_and_model} ({ppd_natural_language})
+}</SELECT>
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">edo eman PPD fitxategia:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?Gehitu inprimagailua:Aldatu inprimagailua}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/eu/choose-serial.tmpl b/templates/eu/choose-serial.tmpl
new file mode 100644
index 000000000..a4dbba2e5
--- /dev/null
+++ b/templates/eu/choose-serial.tmpl
@@ -0,0 +1,52 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Aldatu {printer_name}:Gehitu inprimagailua}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Konexioa:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Baudio-emaria:</TH>
+<TD><SELECT NAME="BAUDRATE">
+{[baudrates]<OPTION {?baudrate={baudrates}?SELECTED:}>{baudrates}}
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Paritatea:</TH>
+<TD><SELECT NAME="PARITY">
+<OPTION VALUE="none" {?parity=none?SELECTED:}>Bat ere ez
+<OPTION VALUE="even" {?parity=even?SELECTED:}>Bikoitia
+<OPTION VALUE="odd" {?parity=odd?SELECTED:}>Bakoitia
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Datuen bit-ak:</TH>
+<TD><SELECT NAME="BITS">
+<OPTION {?bits=8?SELECTED:}>8
+<OPTION {?bits=7?SELECTED:}>7
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Fluxu-kontrola:</TH>
+<TD><SELECT NAME="FLOW">
+<OPTION VALUE="none" {?flow=none?SELECTED:}>Bat ere ez
+<OPTION VALUE="soft" {?flow=soft?SELECTED:}>XON/XOFF (Ssftwarea)
+<OPTION VALUE="hard" {?flow=hard?SELECTED:}>RTS/CTS (hardwarea)
+<OPTION VALUE="dtrdsr" {?flow=dtrdsr?SELECTED:}>DTR/DSR (hardwarea)
+</SELECT></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Jarraitu"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/eu/choose-uri.tmpl b/templates/eu/choose-uri.tmpl
new file mode 100644
index 000000000..4b1fd677b
--- /dev/null
+++ b/templates/eu/choose-uri.tmpl
@@ -0,0 +1,43 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Aldatu {printer_name}:Gehitu inprimagailua}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Konexioa:</TH>
+<TD><INPUT TYPE="URL" SIZE="60" MAXLENGTH="1023" NAME="DEVICE_URI" VALUE="{current_device_uri?{current_device_uri}:{device_uri}}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>Adibideak:
+<PRE>
+ http://ostalari_izena:631/ipp/
+ http://ostalari_izena:631/ipp/ataka1
+
+ ipp://ostalari_izena/ipp/
+ ipp://ostalari_izena/ipp/ataka1
+
+ lpd://ostalari_izena/ilara
+
+ socket://ostalari_izena
+ socket://ostalari_izena:9100
+</PRE>
+
+<P>Ikusi <A HREF="/help/network.html" TARGET="_blank">"Sareko inprimagailuak"</A> URI zuzena erabiltzeko inprimagailuarekin.</P>
+
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Jarraitu"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/eu/class-added.tmpl b/templates/eu/class-added.tmpl
new file mode 100644
index 000000000..e0dfa891b
--- /dev/null
+++ b/templates/eu/class-added.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Gehitu klasea</H2>
+
+<P><A HREF="/classes/{printer_name}">{printer_name}</A> klasea ongi gehitu da.
+
+</DIV>
diff --git a/templates/eu/class-confirm.tmpl b/templates/eu/class-confirm.tmpl
new file mode 100644
index 000000000..f4a1a6f40
--- /dev/null
+++ b/templates/eu/class-confirm.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ezabatu {printer_name} klasea</H2>
+
+<P><B>Abisua:</B> ziur zaude {printer_name} klasea ezabatu nahi duzula?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Ezabatu klasea"></FORM></P>
+
+</DIV>
diff --git a/templates/eu/class-deleted.tmpl b/templates/eu/class-deleted.tmpl
new file mode 100644
index 000000000..5e39282a7
--- /dev/null
+++ b/templates/eu/class-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ezabatu {printer_name} klasea</H2>
+
+<P>{printer_name} klasea ongi ezabatu da.
+
+</DIV>
diff --git a/templates/eu/class-jobs-header.tmpl b/templates/eu/class-jobs-header.tmpl
new file mode 100644
index 000000000..89144751f
--- /dev/null
+++ b/templates/eu/class-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">Lanak</H3>
+</DIV>
diff --git a/templates/eu/class-modified.tmpl b/templates/eu/class-modified.tmpl
new file mode 100644
index 000000000..9397bcc8a
--- /dev/null
+++ b/templates/eu/class-modified.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Aldatu {printer_name} klasea</H2>
+
+<P><A HREF="/classes/{printer_name}">{printer_name}</A> klasea ongi aldatu da.
+
+</DIV>
diff --git a/templates/eu/class.tmpl b/templates/eu/class.tmpl
new file mode 100644
index 000000000..b3c68ca84
--- /dev/null
+++ b/templates/eu/class.tmpl
@@ -0,0 +1,44 @@
+<DIV CLASS="indent">
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?Inaktiboa:{printer_state=4?Prozesatzen:Pausatuta}},
+{printer_is_accepting_jobs=0?Lanak ukatzen:Lanak onartzen},
+{default_name={printer_name}?, zerbitzariaren lehenetsiak:} partekatuta {server_is_sharing_printers=0?ez:{printer_is_shared=0?ez:}} daude)</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">Mantenimendua</OPTION>
+<OPTION VALUE="print-test-page">Inprimatu probako orrialdea</OPTION>
+{printer_state=5?<OPTION VALUE="start-class">Jarraitu klasea</OPTION>:<OPTION VALUE="stop-class">Pausatu klasea</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Onartu lanak</OPTION>:<OPTION VALUE="reject-jobs">Ukatu lanak</OPTION>}
+<OPTION VALUE="move-jobs">Aldatu lan guztiak lekuz</OPTION>
+<OPTION VALUE="purge-jobs">Bertan behera utzi lan guztiak</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="1">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">Administrazioa</OPTION>
+<OPTION VALUE="modify-class">Aldatu klasea</OPTION>
+<OPTION VALUE="delete-class">Ezabatu klasea</OPTION>
+<OPTION VALUE="set-class-options">Ezarri aukera lehenetsiak</OPTION>
+<OPTION VALUE="set-as-default">Ezarri zerbitzari lehenetsi gisa</OPTION>
+<OPTION VALUE="set-allowed-users">Ezarri baimendutako erabiltzaileak</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Deskripzioa:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Kokalekua:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Kideak:</TH><TD>{?member_uris=?Bat ere ez:{member_uris}}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Aukera lehenetsiak:</TH><TD>job-sheets={job_sheets_default}
+papera={media_default?{media_default}:ezezaguna}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/eu/classes-header.tmpl b/templates/eu/classes-header.tmpl
new file mode 100644
index 000000000..a8e24b4bc
--- /dev/null
+++ b/templates/eu/classes-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?Klaserik ez:{#printer_name}/{total} klase erakusten}.</P>
diff --git a/templates/eu/classes.tmpl b/templates/eu/classes.tmpl
new file mode 100644
index 000000000..4cab59926
--- /dev/null
+++ b/templates/eu/classes.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Klaseen zerrenda">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Ilararen izena <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Ilararen izena <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Deskripzioa</TH><TH>Kokalekua</TH><TH>Kideak</TH><TH>Egoera</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{?member_uris=?Bat ere ez:{member_uris}}</TD><TD>{printer_state=3?Inaktibo:{printer_state=4?Prozesatzen:Pausatuta}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/eu/command.tmpl b/templates/eu/command.tmpl
new file mode 100644
index 000000000..0157b34bc
--- /dev/null
+++ b/templates/eu/command.tmpl
@@ -0,0 +1,12 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{title} {printer_name} inprimagailuan</H2>
+
+<P>{job_state>5?:<IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16"
+ALIGN="ABSMIDDLE" ALT="Lanpetuta egoeraren adierazlea"> }Inprimagailuaren lanaren komandoa
+{job_state=3?zain:{job_state=4?eutsita:
+{job_state=5?processing:{job_state=6?geldituta:
+{job_state=7?bertan behera utzita:{job_state=8?abortatuta:burututa}}}}}}{job_state=9?:{job_printer_state_message?,
+<EM>"{job_printer_state_message}"</EM>:}}</P>
+
+</DIV>
diff --git a/templates/eu/edit-config.tmpl b/templates/eu/edit-config.tmpl
new file mode 100644
index 000000000..4b2ba7bca
--- /dev/null
+++ b/templates/eu/edit-config.tmpl
@@ -0,0 +1,24 @@
+<SCRIPT TYPE="text/javascript">
+function reset_config()
+{
+ document.cups.CUPSDCONF.value = "{?cupsdconf_default}";
+}
+</SCRIPT>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Editatu konfigurazioko fitxategia</H2>
+
+<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+
+<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
+
+<P><INPUT TYPE="SUBMIT" NAME="SAVECHANGES" VALUE="Gorde aldaketak">
+<INPUT TYPE="BUTTON" VALUE="Erabili konfigurazioko fitxategi lehenetsia"
+onClick="reset_config();"></P>
+
+</FORM>
+
+</DIV>
diff --git a/templates/eu/error-op.tmpl b/templates/eu/error-op.tmpl
new file mode 100644
index 000000000..605cc63f9
--- /dev/null
+++ b/templates/eu/error-op.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{?printer_name} errorea: {?title}</H2>
+
+<P>Errorea:</P>
+
+<BLOCKQUOTE>"{op}" eragiketa ezezaguna.</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/eu/error.tmpl b/templates/eu/error.tmpl
new file mode 100644
index 000000000..76dc6a0a8
--- /dev/null
+++ b/templates/eu/error.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{?printer_name} errorea: {?title}</H2>
+
+<P>{?message?{message}:Errorea:}</P>
+
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/eu/header.tmpl.in b/templates/eu/header.tmpl.in
new file mode 100644
index 000000000..19a04e048
--- /dev/null
+++ b/templates/eu/header.tmpl.in
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{title} - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+ {refresh_page?<META HTTP-EQUIV="Refresh" CONTENT="{refresh_page}">:}
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="unsel"><A HREF="/">&nbsp;&nbsp;Hasiera&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=admin?:un}sel"><A HREF="/admin">&nbsp;&nbsp;Administrazioa&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=classes?:un}sel"><A HREF="/classes/">&nbsp;&nbsp;Klaseak&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=help?:un}sel"><A HREF="/help/">&nbsp;&nbsp;Lineako&nbsp;laguntza&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=jobs?:un}sel"><A HREF="/jobs/">&nbsp;&nbsp;Lanak&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=printers?:un}sel"><A HREF="/printers/">&nbsp;&nbsp;Inprimagailuak&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Bilatu laguntzan"
+VALUE="{SECTION=help?{?QUERY}:}" AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+<TR><TD COLSPAN="9">&nbsp;</TD></TR>
+</TABLE>
diff --git a/templates/eu/help-header.tmpl b/templates/eu/help-header.tmpl
new file mode 100644
index 000000000..c87c76742
--- /dev/null
+++ b/templates/eu/help-header.tmpl
@@ -0,0 +1,49 @@
+<DIV CLASS="indent">
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET">
+{TOPIC?<INPUT TYPE="HIDDEN" NAME="TOPIC" VALUE="{TOPIC}">:}
+
+<P ALIGN="CENTER"><B>Bilatu
+{HELPTITLE?{HELPTITLE}:{TOPIC?{TOPIC}:dokumentu guztietan}}:</B> <INPUT
+TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER=""
+AUTOSAVE="org.cups.help" RESULTS="20">
+<INPUT TYPE="SUBMIT" NAME="SEARCH" VALUE="Bilatu">
+<INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="Garbitu"></P>
+
+</FORM>
+
+<!-- Bookmarks -->
+<DIV CLASS="sidebar"><TABLE CLASS="inset" SUMMARY="Edukia">
+<TR><TD>
+
+<H3 CLASS="title">Lineako laguntzaren dokumentuak</H3>
+
+<P CLASS="l0"><A HREF="/help/{QUERY??QUERY={QUERY}:}">Dokumentu guztiak</A></P>
+<HR>
+
+{[BMTEXT]<P CLASS="l{BMINDENT}"><A HREF="{BMLINK}">{BMTEXT}</A></P>
+}
+</TD></TR>
+</TABLE></DIV>
+
+{QUERY?<P>Bilaketaren emaitzak {HELPFILE?{HELPTITLE}:{TOPIC?{TOPIC}:dokumentu guztietan}}\:</P>
+{QTEXT?<UL>
+{[QTEXT]<LI><A HREF="{QLINK}">{QTEXT}</A>{QPTEXT? (in <I><A HREF="{QPLINK}">{QPTEXT}</A></I>):}</LI>}
+{QTEXT?</UL>:}
+:<P>Ez da bat datorrenik aurkitu.</P>}
+<HR NOSHADE>:}
+{HELPTITLE?<H1>{HELPTITLE}</H1>
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="PRINTABLE" VALUE="YES"><INPUT TYPE="SUBMIT" VALUE="Ikusi bertsio inprimagarria"></FORM>:
+
+<H1>Lineako laguntza</H1>
+
+<P>Hau CUPSen lineako laguntzaren interfazea da. Sartu bilatzeko hitzak gainean
+edo klik egin dokumentazioaren edozein esteketan lineako laguntzaren informazioa bistaratzeko.</P>
+
+<P>CUPSekin hasiberria bazara, irakurri "<a
+href="/help/overview.html">CUPSen gainbegiraketa</a>" orrialdea. Erabiltzaile adituek
+ "<a href="/help/whatsnew.html">CUPS 1.4 bertsioko berrikuntzak</a>" orrialdea irakurri beharko lukete.</P>
+
+<P><A HREF="http://www.cups.org/">CUPSen webgune nagusia</A>k
+hainbat baliabide eskaintzen ditu: erabiltzaileek eztabaidatzeko foruak, maiz egindako
+galderei (MEG edo FAQ) erantzunak, eta akatsei buruz berri emateko edo eginbideak eskatzeko
+inprimakia.</P>}
diff --git a/templates/eu/help-printable.tmpl b/templates/eu/help-printable.tmpl
new file mode 100644
index 000000000..2463c1630
--- /dev/null
+++ b/templates/eu/help-printable.tmpl
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{HELPTITLE}</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups-printable.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
diff --git a/templates/eu/help-trailer.tmpl b/templates/eu/help-trailer.tmpl
new file mode 100644
index 000000000..4c1ebed85
--- /dev/null
+++ b/templates/eu/help-trailer.tmpl
@@ -0,0 +1 @@
+</DIV>
diff --git a/templates/eu/job-cancel.tmpl b/templates/eu/job-cancel.tmpl
new file mode 100644
index 000000000..ec432ebb4
--- /dev/null
+++ b/templates/eu/job-cancel.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Utzi {job_id} lana</H2>
+
+<P><A HREF="{job_printer_uri}">{job_id} lana</A> bertan behera utzi da.
+
+</DIV>
diff --git a/templates/eu/job-hold.tmpl b/templates/eu/job-hold.tmpl
new file mode 100644
index 000000000..177ac160f
--- /dev/null
+++ b/templates/eu/job-hold.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Eutsi {job_id} lana</H2>
+
+<P><A HREF="{job_printer_uri}">{job_id} lana</A> inprimatzetik eutsi da.
+
+</DIV>
diff --git a/templates/eu/job-move.tmpl b/templates/eu/job-move.tmpl
new file mode 100644
index 000000000..f337353b2
--- /dev/null
+++ b/templates/eu/job-move.tmpl
@@ -0,0 +1,27 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
+
+<H2 CLASS="title">{job_id?Aldatu {job_id} lana lekuz:Aldatu lan guztiak lekuz}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">Helburu berria:</TH>
+<TD>
+<SELECT NAME="JOB_PRINTER_URI" SIZE="10">
+{[job_printer_uri]<OPTION VALUE="{job_printer_uri}">{job_printer_name}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{job_id?Aldatu lana lekuz:Aldatu lanak lekuz}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+
+</DIV>
diff --git a/templates/eu/job-moved.tmpl b/templates/eu/job-moved.tmpl
new file mode 100644
index 000000000..47f31caf9
--- /dev/null
+++ b/templates/eu/job-moved.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{job_id?Aldatu {job_id} lana lekuz:Aldatu lan guztiak lekuz}</H2>
+
+<P>{job_id?<A HREF="/jobs/{job_id}">{job_id} lana</A> hona eraman da:Lan guztiak hona eraman dira}:
+<A HREF="/{is_class?classes:printers}/{job_printer_name}">{job_printer_name}</A>.</P>
+
+</DIV>
diff --git a/templates/eu/job-release.tmpl b/templates/eu/job-release.tmpl
new file mode 100644
index 000000000..40f7f2b37
--- /dev/null
+++ b/templates/eu/job-release.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Askatu {job_id} lana</H2>
+
+<P><A HREF="{job_printer_uri}">{job_id} lana</A> inprimatzetik askatu egin da.
+
+</DIV>
diff --git a/templates/eu/job-restart.tmpl b/templates/eu/job-restart.tmpl
new file mode 100644
index 000000000..5868c50d2
--- /dev/null
+++ b/templates/eu/job-restart.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Inprimatu berriro {job_id} lana</H2>
+
+<P><A HREF="{job_printer_uri}">{job_id} lana</A> berriro hasi da.
+
+</DIV>
diff --git a/templates/eu/jobs-header.tmpl b/templates/eu/jobs-header.tmpl
new file mode 100644
index 000000000..664f0ebf7
--- /dev/null
+++ b/templates/eu/jobs-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">{?which_jobs=?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Erakutsi lan aktiboak"></FORM>}
+{?which_jobs=completed?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="completed"><INPUT TYPE="SUBMIT" VALUE="Erakutsi burututako lanak"></FORM>}
+{?which_jobs=all?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="all"><INPUT TYPE="SUBMIT" VALUE="Erakutsi lan guztiak"></FORM>}</DIV>
+
+<P ALIGN="CENTER">{total=0?Lanik ez: {#job_id}/{total} lan {?which_jobs=?aktiboak:{which_jobs=all?:burututakoak}} erakusten}.</P>
diff --git a/templates/eu/jobs.tmpl b/templates/eu/jobs.tmpl
new file mode 100644
index 000000000..3071f6d40
--- /dev/null
+++ b/templates/eu/jobs.tmpl
@@ -0,0 +1,37 @@
+{#job_id=0?:
+<TABLE CLASS="list" SUMMARY="Lanen zerrenda">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> ID <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> ID <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Izena</TH><TH>Erabiltzailea</TH><TH>Tamaina</TH><TH>Orrialdeak</TH><TH>Egoera</TH><TH>Kontrola</TH></TR>
+</THEAD>
+<TBODY>
+{[job_id]
+<TR VALIGN="TOP">
+<TD><A HREF="{job_printer_uri}">{job_printer_name}</A>-{job_id}&nbsp;</TD>
+<TD>{?job_name=?Ezezaguna:{job_name}}&nbsp;</TD>
+<TD>{job_originating_user_name}&nbsp;</TD>
+<TD>{job_k_octets}k&nbsp;</TD>
+<TD>{job_media_sheets_completed=0?Ezezaguna:{?job_media_sheets_completed}}&nbsp;</TD>
+<TD>{job_state=3?noiztik zain<BR>{time_at_creation}:{job_state=4?noiztik eutsita<BR>{time_at_creation}:
+{job_state=5?noiztik prozesatzen<BR>{time_at_processing}:{job_state=6?geldituta:
+{job_state=7?bertan behera utzita<BR>{time_at_completed}:{job_state=8?abortatuta:burututa<BR>{time_at_completed}}}}}}}&nbsp;{job_printer_state_message?<BR>
+<EM>"{job_printer_state_message}"</EM>:}</TD>
+<TD>
+{job_preserved>0?{job_state>5?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Inprimatu berriro lana"></FORM>:}:}
+{job_state=4?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Askatu lana"></FORM>:}
+{job_state=3?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Eutsi lana"></FORM>:}
+{job_state<7?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Utzi lana"></FORM>
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Aldatu lana lekuz"></FORM>:}
+&nbsp;</TD>
+</TR>
+}
+</TBODY>
+</TABLE>
+}
diff --git a/templates/eu/list-available-printers.tmpl b/templates/eu/list-available-printers.tmpl
new file mode 100644
index 000000000..c8a397f3e
--- /dev/null
+++ b/templates/eu/list-available-printers.tmpl
@@ -0,0 +1,11 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Inprimagailu erabilgarriak</H2>
+
+{#device_uri=0?<P>Ez da inprimagailurik aurkitu.</P>
+:<UL>{[device_uri]
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Gehitu inprimagailu hau"></FORM>
+{device_make_and_model} ({device_info})</LI>
+}</UL>}
+
+</DIV>
diff --git a/templates/eu/modify-class.tmpl b/templates/eu/modify-class.tmpl
new file mode 100644
index 000000000..bce650341
--- /dev/null
+++ b/templates/eu/modify-class.tmpl
@@ -0,0 +1,34 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Aldatu {printer_name} klasea</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Deskripzioa:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Kokalekua:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Kideak:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Aldatu klasea"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/eu/modify-printer.tmpl b/templates/eu/modify-printer.tmpl
new file mode 100644
index 000000000..9b0417a54
--- /dev/null
+++ b/templates/eu/modify-printer.tmpl
@@ -0,0 +1,42 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Aldatu {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Deskripzioa:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Gizakiek irakurtzeko deskripzioa, adibidez "HP LaserJet duplexatzailearekin")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Kokalekua:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Gizakiek irakurtzeko kokalekua, adibidez "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Konexioa:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Partekatzea:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}">
+Partekatu inprimagailu hau</TD>
+</TR>
+<TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Jarraitu"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/eu/norestart.tmpl b/templates/eu/norestart.tmpl
new file mode 100644
index 000000000..5ed12b6be
--- /dev/null
+++ b/templates/eu/norestart.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Aldatu ezarpenak</H2>
+
+<P>Zerbitzaria ez da berrabiarazi konfigurazioaren aldaketarik ez delako egin...</P>
+
+</DIV>
diff --git a/templates/eu/option-boolean.tmpl b/templates/eu/option-boolean.tmpl
new file mode 100644
index 000000000..e832ee102
--- /dev/null
+++ b/templates/eu/option-boolean.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD>
+{[choices]<INPUT TYPE="RADIO" NAME="{keyword-1}" {choices={defchoice-1}?CHECKED:} VALUE="{choices}">{text}}
+</TD>
+</TR>
diff --git a/templates/eu/option-conflict.tmpl b/templates/eu/option-conflict.tmpl
new file mode 100644
index 000000000..617858ccb
--- /dev/null
+++ b/templates/eu/option-conflict.tmpl
@@ -0,0 +1,7 @@
+<P><B>Errorea:</B> honako aukerak gatazkan daude:</P>
+
+<UL>
+{[ckeyword]<LI><A HREF="#{ckeyword}">{ckeytext}</A>: {cchoice}</LI>
+}</UL>
+
+<P>Aldatu aukera bat edo gehiago gatazkak ebazteko.</P>
diff --git a/templates/eu/option-header.tmpl b/templates/eu/option-header.tmpl
new file mode 100644
index 000000000..464726a50
--- /dev/null
+++ b/templates/eu/option-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="tab" ID="{group_id}">
+
+<H3 ALIGN="CENTER">{group}</H3>
+
+<TABLE WIDTH="100%">
diff --git a/templates/eu/option-pickmany.tmpl b/templates/eu/option-pickmany.tmpl
new file mode 100644
index 000000000..067075aec
--- /dev/null
+++ b/templates/eu/option-pickmany.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" MULTIPLE SIZE="10">
+{[choices]<OPTION {choices={defchoice}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT></TD>
+</TR>
diff --git a/templates/eu/option-pickone.tmpl b/templates/eu/option-pickone.tmpl
new file mode 100644
index 000000000..70866dfb5
--- /dev/null
+++ b/templates/eu/option-pickone.tmpl
@@ -0,0 +1,18 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" ID="select-{keyword}" ONCHANGE="update_paramtable('{keyword}')">
+{[choices]<OPTION {choices={defchoice}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT>
+{iscustom=1?<TABLE NAME="paramtable" id="{keyword}-params">{[params]
+<TR><TH CLASS="sublabel">{paramtext}:</TH>
+<TD>{params=Units?<SELECT NAME="{keyword-1}.{params}">
+<OPTION VALUE="pt"{paramvalue=pt? SELECTED:}>Puntuak</OPTION>
+<OPTION VALUE="mm"{paramvalue=mm? SELECTED:}>Milimetroak</OPTION>
+<OPTION VALUE="cm"{paramvalue=cm? SELECTED:}>Zentimetroak</OPTION>
+<OPTION VALUE="in"{paramvalue=in? SELECTED:}>Hatzak</OPTION>
+<OPTION VALUE="ft"{paramvalue=ft? SELECTED:}>Oinak</OPTION>
+<OPTION VALUE="m"{paramvalue=m? SELECTED:}>Metroak</OPTION>
+</SELECT>:<INPUT TYPE="{inputtype}" NAME="{keyword-1}.{params}" VALUE="{paramvalue}">}</TD></TR>
+}</TABLE>
+</TD>:}
+</TR>
diff --git a/templates/eu/option-trailer.tmpl b/templates/eu/option-trailer.tmpl
new file mode 100644
index 000000000..d80296a5f
--- /dev/null
+++ b/templates/eu/option-trailer.tmpl
@@ -0,0 +1,5 @@
+</TABLE>
+
+<P ALIGN="CENTER"><INPUT TYPE="SUBMIT" VALUE="Ezarri aukera lehenetsiak"></P>
+
+</DIV>
diff --git a/templates/eu/pager.tmpl b/templates/eu/pager.tmpl
new file mode 100644
index 000000000..901b0ff0e
--- /dev/null
+++ b/templates/eu/pager.tmpl
@@ -0,0 +1,6 @@
+<TABLE CLASS="inset" SUMMARY="Orrikatzeko barra">
+<TR>
+ <TD WIDTH="50%">{PREV?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{PREV}"><INPUT TYPE="SUBMIT" VALUE="&#x25c0; Erakutsi aurrekoak"></FORM>:&nbsp;}</TD>
+ <TD WIDTH="50%" ALIGN="RIGHT">{NEXT?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{NEXT}"><INPUT TYPE="SUBMIT" VALUE="Erakutsi hurrengoa &#x25b6;"></FORM>:&nbsp;}</TD>
+</TR>
+</TABLE>
diff --git a/templates/eu/printer-accept.tmpl b/templates/eu/printer-accept.tmpl
new file mode 100644
index 000000000..5bc9da689
--- /dev/null
+++ b/templates/eu/printer-accept.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Onartu lanak {printer_name} {is_class?klasean:inprimagailuan} </H2>
+
+<P><A HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A> {is_class?klasea:inprimagailua}
+lanak onartzen ari da orain.</P>
+
+</DIV>
diff --git a/templates/eu/printer-added.tmpl b/templates/eu/printer-added.tmpl
new file mode 100644
index 000000000..17e9c02bb
--- /dev/null
+++ b/templates/eu/printer-added.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Gehitu inprimagailua</H2>
+
+<P><A HREF="/printers/{printer_name}">{printer_name}</A> inprimagailua ongi gehitu da.
+
+</DIV>
diff --git a/templates/eu/printer-configured.tmpl b/templates/eu/printer-configured.tmpl
new file mode 100644
index 000000000..66e6f41d1
--- /dev/null
+++ b/templates/eu/printer-configured.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ezarri {printer_name}(r)en aukera lehenetsiak</H2>
+
+<P>{OP=set-class-options?<A HREF="/classes/{printer_name}">{printer_name} klasea:<A HREF="/printers/{printer_name}">{printer_name} inprimagailua}</A>ren
+aukera lehenetsiak ongi ezarri dira.
+
+</DIV>
diff --git a/templates/eu/printer-confirm.tmpl b/templates/eu/printer-confirm.tmpl
new file mode 100644
index 000000000..d72d24010
--- /dev/null
+++ b/templates/eu/printer-confirm.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ezabatu {printer_name} inprimagailua</H2>
+
+<P><B>Abisua:</B> ziur zaude {printer_name} inprimagailua ezabatzea nahi duzula?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Ezabatu inprimagailua"></FORM></P>
+
+</DIV>
diff --git a/templates/eu/printer-default.tmpl b/templates/eu/printer-default.tmpl
new file mode 100644
index 000000000..0834a3ab4
--- /dev/null
+++ b/templates/eu/printer-default.tmpl
@@ -0,0 +1,11 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ezarri {printer_name} {is_class?klasea:inprimagailua} lehenetsi gisa</H2>
+
+<P><A HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+{is_class?klasea:inprimagailua} zerbitzarian inprimagailu lehenetsi gisa ezarri da.</P>
+
+<BLOCKQUOTE><B>Oharra:</B> <TT>lpoptions</TT> komandoaren bidez ezarritako edozein
+erabiltzailek ezarpen lehenetsi hau gainidatz dezake.</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/eu/printer-deleted.tmpl b/templates/eu/printer-deleted.tmpl
new file mode 100644
index 000000000..b2b72075f
--- /dev/null
+++ b/templates/eu/printer-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ezabatu {printer_name} inprimagailua</H2>
+
+<P>{printer_name} inprimagailua ongi ezabatu da.
+
+</DIV>
diff --git a/templates/eu/printer-jobs-header.tmpl b/templates/eu/printer-jobs-header.tmpl
new file mode 100644
index 000000000..89144751f
--- /dev/null
+++ b/templates/eu/printer-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">Lanak</H3>
+</DIV>
diff --git a/templates/eu/printer-modified.tmpl b/templates/eu/printer-modified.tmpl
new file mode 100644
index 000000000..80aa65be3
--- /dev/null
+++ b/templates/eu/printer-modified.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Aldatu {printer_name} inprimagailua</H2>
+
+<P><A HREF="/printers/{printer_name}">{printer_name}</A> inprimagailua
+ongi aldatu da.
+
+</DIV>
diff --git a/templates/eu/printer-purge.tmpl b/templates/eu/printer-purge.tmpl
new file mode 100644
index 000000000..0977c8b04
--- /dev/null
+++ b/templates/eu/printer-purge.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Kendu lanak {printer_name} {is_class?klasetik:inprimagailutik}</H2>
+
+<P><A HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+{is_class?klaseko:inprimagailuko} lan guztiak kendu dira.</P>
+
+</DIV>
diff --git a/templates/eu/printer-reject.tmpl b/templates/eu/printer-reject.tmpl
new file mode 100644
index 000000000..178ef8b8e
--- /dev/null
+++ b/templates/eu/printer-reject.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ukatu lanak {printer_name} {is_class?klasean:inprimagailuan} </H2>
+
+<P><A HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+{is_class?klaseak:inprimagailuak} ez du lan gehiago onartuko.</P>
+
+</DIV>
diff --git a/templates/eu/printer-start.tmpl b/templates/eu/printer-start.tmpl
new file mode 100644
index 000000000..4403344e3
--- /dev/null
+++ b/templates/eu/printer-start.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Jarraitu {printer_name} {is_class?klasea:inprimagailua}</H2>
+
+<P><A HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+{is_class?klaseak:inprimagailuak} jarraitu egin du.</P>
+
+</DIV>
diff --git a/templates/eu/printer-stop.tmpl b/templates/eu/printer-stop.tmpl
new file mode 100644
index 000000000..2338e87bf
--- /dev/null
+++ b/templates/eu/printer-stop.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Pausatu {printer_name} {is_class?klasea:inprimagailua}</H2>
+
+<P><A HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+{is_class?klasea:inprimagailua} pausatu egin da.</P>
+
+</DIV>
diff --git a/templates/eu/printer.tmpl b/templates/eu/printer.tmpl
new file mode 100644
index 000000000..ac984ebd0
--- /dev/null
+++ b/templates/eu/printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?inaktibo:{printer_state=4?prozesatzen:pausatuta}},
+{printer_is_accepting_jobs=0?lanak ukatzen:lanak onartzen},
+{default_name={printer_name}?, Zerbitzariaren lehenetsia:} partekatuta {server_is_sharing_printers=0?ez:{printer_is_shared=0?ez:}} dago)</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">Mantenimendua</OPTION>
+<OPTION VALUE="print-test-page">Inprimatu probako orrialdea</OPTION>
+{printer_commands~.*Clean.*?<OPTION VALUE="clean-print-heads">Garbitu inprimagailuaren buruak</OPTION>:}
+{printer_commands~.*PrintSelfTestPage.*?<OPTION VALUE="print-self-test-page">Inprimatu auto-probako orrialdea</OPTION>:}
+{printer_state=5?<OPTION VALUE="start-printer">Jarraitu inprimagailua</OPTION>:<OPTION VALUE="stop-printer">Pausatu inprimagailua</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Onartu lanak</OPTION>:<OPTION VALUE="reject-jobs">Ukatu lanak</OPTION>}
+<OPTION VALUE="move-jobs">Aldatu lan guztiak lekuz</OPTION>
+<OPTION VALUE="purge-jobs">Utzi lan guztiak</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">Administrazioa</OPTION>
+<OPTION VALUE="modify-printer">Aldatu inprimagailua</OPTION>
+<OPTION VALUE="delete-printer">Ezabatu inprimagailua</OPTION>
+<OPTION VALUE="set-printer-options">Ezarri aukera lehenetsiak</OPTION>
+<OPTION VALUE="set-as-default">Ezarri zerbitzari lehenetsi gisa</OPTION>
+<OPTION VALUE="set-allowed-users">Ezarri baimendutako erabiltzaileak</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Deskripzioa:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Kokalekua:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Kontrolatzailea:</TH><TD>{printer_make_and_model} ({color_supported=1?kolorea:gris-eskala}{sides_supported?, 2 aldeetan inprimatzea:})<BR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Konexioa:</TH><TD>{device_uri}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Lehenetsiak:</TH><TD>lanen orriak={job_sheets_default}
+euskarria={media_default?{media_default}:ezezaguna}
+{sides_default?aldeak={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/eu/printers-header.tmpl b/templates/eu/printers-header.tmpl
new file mode 100644
index 000000000..ba6d22fca
--- /dev/null
+++ b/templates/eu/printers-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?Inprimagailurik ez:{#printer_name}/{total} inprimagailu erakusten}.</P>
diff --git a/templates/eu/printers.tmpl b/templates/eu/printers.tmpl
new file mode 100644
index 000000000..541589102
--- /dev/null
+++ b/templates/eu/printers.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Inprimagailuen zerrenda">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Ilararen izena <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Ilararen izena <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Deskripzioa</TH><TH>Kokalekua</TH><TH>Marka eta modeloa</TH><TH>Egoera</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{printer_make_and_model}</TD><TD>{printer_state=3?Inaktibo:{printer_state=4?Prozesatzen:Pausatuta}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/eu/restart.tmpl b/templates/eu/restart.tmpl
new file mode 100644
index 000000000..d599c228f
--- /dev/null
+++ b/templates/eu/restart.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Aldatu ezarpenak</H2>
+
+<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Lanpetutako egoeraren adierazlea"> Itxaron zerbitzaria berrabiatzen den bitartean...</P>
+
+</DIV>
diff --git a/templates/eu/samba-export.tmpl b/templates/eu/samba-export.tmpl
new file mode 100644
index 000000000..b6851f86b
--- /dev/null
+++ b/templates/eu/samba-export.tmpl
@@ -0,0 +1,54 @@
+<SCRIPT TYPE="text/javascript"><!--
+function select_printers() {
+ var list = document.export_samba.EXPORT_NAME;
+ var sel = document.export_samba.EXPORT_ALL.checked;
+
+ for (i = 0; i < list.length; i ++) {
+ list.options[i].selected = sel;
+ }
+}
+--></SCRIPT>
+
+<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
+
+<H2 CLASS="title">Esportatu inprimagailuak Samba-ra</H2>
+
+{error?<P>Ezin dira inprimagailuak Samba-ra esportatu\:</P>
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+<P>Begiratu <A HREF="/admin/log/error_log"
+TARGET="_blank">error_log</A> fitxategia informazio gehiagorako.</P>:
+<P>
+Orrialde honek inprimagailuak Samba-ra esportatzea baimentzen du, horrela
+Windows sistemako bezeroek inprimagailu horiek atzi daitezke haien
+mahaigaineko <VAR>Auzoko sareak</VAR> edo <VAR>Sareko lekuak</VAR> ikonoen bidez.
+Aurrenik Windows-eko inprimagailuen PostScript kontrolatzaileak instalatu
+behar dira, <A HREF="/help/man-cupsaddsmb.html" TARGET="_blank">cupsaddsmb(8)</A> eskuliburuko orrialdean
+azaltzen den bezala.</P>}
+<TABLE>
+<TR>
+<TH CLASS="label">Inprimagailuak:</TH>
+<TD>
+<SELECT NAME="EXPORT_NAME" SIZE="10" MULTIPLE>
+{[printer_name]<OPTION VALUE="{printer_name}"{export_all? SELECTED:{printer_export? SELECTED:}}>{printer_name}}
+</SELECT><BR>
+<INPUT TYPE="CHECKBOX" NAME="EXPORT_ALL"{export_all? CHECKED:}
+onChange="select_printers()"> Esportatu inprimagailu guztiak
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Samba-ko erabiltzaile-izena:</TH>
+<TD><INPUT TYPE="TEXT" NAME="USERNAME" VALUE="{?USERNAME}"> (beharrezkoa)</TD>
+</TR>
+<TR>
+<TH CLASS="label">Samba-ko pasahitza:</TH>
+<TD><INPUT TYPE="PASSWORD" NAME="PASSWORD" VALUE=""> (beharrezkoa)</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Esportatu inprimagailuak Samba-ra"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/eu/samba-exported.tmpl b/templates/eu/samba-exported.tmpl
new file mode 100644
index 000000000..3a8f6584b
--- /dev/null
+++ b/templates/eu/samba-exported.tmpl
@@ -0,0 +1 @@
+<P>Inprimagailuak ongi esportatu dira Samba-ra.</P>
diff --git a/templates/eu/search.tmpl b/templates/eu/search.tmpl
new file mode 100644
index 000000000..421173560
--- /dev/null
+++ b/templates/eu/search.tmpl
@@ -0,0 +1,10 @@
+<FORM ACTION="/{SECTION}/{?SEARCH_DEST}" METHOD="GET">
+{WHICH_JOBS?<INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{WHICH_JOBS}">:}
+{ORDER?<INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{ORDER}">:}
+
+<P ALIGN="CENTER"><B>Bilatu
+{SEARCH_DEST?{SEARCH_DEST}:{SECTION=classes?klasetan:{SECTION=jobs?lanetan:inprimgailuetan}}}:</B>
+<INPUT TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER="" AUTOSAVE="org.cups.{SECTION}" RESULTS="20"> <INPUT
+TYPE="SUBMIT" VALUE="Bilatu"> <INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="Garbitu"></P>
+
+</FORM>
diff --git a/templates/eu/set-printer-options-header.tmpl b/templates/eu/set-printer-options-header.tmpl
new file mode 100644
index 000000000..89b548b2f
--- /dev/null
+++ b/templates/eu/set-printer-options-header.tmpl
@@ -0,0 +1,26 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ezarri {printer_name}(r)en aukera lehenetsiak</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Kontsultatu inprimagailuaren aukera lehenetsiei buruz">:}
+
+<SCRIPT TYPE="text/javascript"><!--
+function update_paramtable(option)
+{
+ var cb = document.getElementById("select-" + option)
+ var paramstable = document.getElementById(option + "-params");
+ if (cb.value == "Custom")
+ paramstable.style.display = "table";
+ else
+ paramstable.style.display = "none";
+}
+--></SCRIPT>
+
+<H3 CLASS="title">{[group_id]
+<A HREF="#{group_id}">{group}</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</H3>
+
+<DIV CLASS="tabs">
diff --git a/templates/eu/set-printer-options-trailer.tmpl b/templates/eu/set-printer-options-trailer.tmpl
new file mode 100644
index 000000000..11adc7012
--- /dev/null
+++ b/templates/eu/set-printer-options-trailer.tmpl
@@ -0,0 +1,16 @@
+</DIV>
+
+<SCRIPT TYPE="text/javascript"><!--
+// Hide custom options parameters for browsers that understand Javascript
+var paramtables = document.getElementsByName("paramtable");
+for (var i = 0; i < paramtables.length; i++)
+{
+ var opt = paramtables[i].id.substr(0, paramtables[i].id.lastIndexOf("-"));
+ var cb = document.getElementById("select-" + opt);
+ if (cb.value != "Custom")
+ paramtables[i].style.display = "none";
+}
+--></SCRIPT>
+</FORM>
+
+</DIV>
diff --git a/templates/eu/subscription-added.tmpl b/templates/eu/subscription-added.tmpl
new file mode 100644
index 000000000..43ee5fcbd
--- /dev/null
+++ b/templates/eu/subscription-added.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P> {subscription_name} harpidetza ongi landu da.</P>
+
+</DIV>
diff --git a/templates/eu/subscription-canceled.tmpl b/templates/eu/subscription-canceled.tmpl
new file mode 100644
index 000000000..71b0dbd0d
--- /dev/null
+++ b/templates/eu/subscription-canceled.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>{notify_subscription_id}. harpidetza bertan behera utzi da.</P>
+
+</DIV>
diff --git a/templates/eu/test-page.tmpl b/templates/eu/test-page.tmpl
new file mode 100644
index 000000000..bf5c77a69
--- /dev/null
+++ b/templates/eu/test-page.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Inprimatu probako orrialdea hemen: {printer_name}</H2>
+
+<P>Probako orrialdea bidalita; lanaren IDa <A HREF="/{SECTION}/{printer_name}">{printer_name}-{job_id}</A> da.</P>
+
+</DIV>
diff --git a/templates/eu/trailer.tmpl b/templates/eu/trailer.tmpl
new file mode 100644
index 000000000..92df00523
--- /dev/null
+++ b/templates/eu/trailer.tmpl
@@ -0,0 +1,8 @@
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS eta CUPSen logotipoa <A HREF="http://www.apple.com">Apple Inc.</A>en
+marka errejistratuak dira. CUPSen copyright-a: 2007-2011 Apple
+Inc. eskubide guztiak gordeta.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/templates/eu/users.tmpl b/templates/eu/users.tmpl
new file mode 100644
index 000000000..ba0ee968b
--- /dev/null
+++ b/templates/eu/users.tmpl
@@ -0,0 +1,30 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
+
+<H2 CLASS="title"> {printer_name}(e)n baimendutako erabiltzaile guztiak</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">Erabiltzaileak:</TH>
+<TD>
+<INPUT TYPE='TEXT' NAME='users' SIZE='60' VALUE='{?requesting_user_name_allowed}{?requesting_user_name_denied}'>
+<BR>
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-allowed' {requesting_user_name_allowed?checked:}>Baimendu erabiltzaileak inprimatzea
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-denied' {requesting_user_name_denied?checked:}>Saihestu erabiltzaile hauek inprimatzetik
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>
+<INPUT TYPE="SUBMIT" VALUE="Ezarri baimendutako erabiltzaileak">
+</TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/header.tmpl.in b/templates/header.tmpl.in
new file mode 100644
index 000000000..a383725c5
--- /dev/null
+++ b/templates/header.tmpl.in
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{title} - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+ {refresh_page?<META HTTP-EQUIV="Refresh" CONTENT="{refresh_page}">:}
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="unsel"><A HREF="/">&nbsp;&nbsp;Home&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=admin?:un}sel"><A HREF="/admin">&nbsp;&nbsp;Administration&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=classes?:un}sel"><A HREF="/classes/">&nbsp;&nbsp;Classes&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=help?:un}sel"><A HREF="/help/">&nbsp;&nbsp;Online&nbsp;Help&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=jobs?:un}sel"><A HREF="/jobs/">&nbsp;&nbsp;Jobs&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=printers?:un}sel"><A HREF="/printers/">&nbsp;&nbsp;Printers&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Search Help"
+VALUE="{SECTION=help?{?QUERY}:}" AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+<TR><TD COLSPAN="9">&nbsp;</TD></TR>
+</TABLE>
diff --git a/templates/help-header.tmpl b/templates/help-header.tmpl
new file mode 100644
index 000000000..17afce738
--- /dev/null
+++ b/templates/help-header.tmpl
@@ -0,0 +1,51 @@
+<DIV CLASS="indent">
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET">
+{TOPIC?<INPUT TYPE="HIDDEN" NAME="TOPIC" VALUE="{TOPIC}">:}
+
+<P ALIGN="CENTER"><B>Search in
+{HELPTITLE?{HELPTITLE}:{TOPIC?{TOPIC}:All Documents}}:</B> <INPUT
+TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER=""
+AUTOSAVE="org.cups.help" RESULTS="20">
+<INPUT TYPE="SUBMIT" NAME="SEARCH" VALUE="Search">
+<INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="Clear"></P>
+
+</FORM>
+
+<!-- Bookmarks -->
+<DIV CLASS="sidebar"><TABLE CLASS="inset" SUMMARY="Contents">
+<TR><TD>
+
+<H3 CLASS="title">Online Help Documents</H3>
+
+<P CLASS="l0"><A HREF="/help/{QUERY??QUERY={QUERY}:}">All Documents</A></P>
+<HR>
+
+{[BMTEXT]<P CLASS="l{BMINDENT}"><A HREF="{BMLINK}">{BMTEXT}</A></P>
+}
+</TD></TR>
+</TABLE></DIV>
+
+{QUERY?<P>Search Results in {HELPFILE?{HELPTITLE}:{TOPIC?{TOPIC}:All Documents}}\:</P>
+{QTEXT?<UL>
+{[QTEXT]<LI><A HREF="{QLINK}">{QTEXT}</A>{QPTEXT? (in <I><A HREF="{QPLINK}">{QPTEXT}</A></I>):}</LI>}
+{QTEXT?</UL>:}
+:<P>No matches found.</P>}
+<HR NOSHADE>:}
+{HELPTITLE?<H1>{HELPTITLE}</H1>
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="PRINTABLE" VALUE="YES"><INPUT TYPE="SUBMIT" VALUE="View Printable Version"></FORM>:
+
+<H1>Online Help</H1>
+
+<P>This is the CUPS online help interface. Enter search words
+above or click on any of the documentation links to display
+online help information.</P>
+
+<P>If you are new to CUPS, read the "<a
+href="/help/overview.html">Overview of CUPS</a>" page. Veteran users
+should read the "<a href="/help/whatsnew.html">What's New in CUPS
+1.4</a>" page.</P>
+
+<P>The <A HREF="http://www.cups.org/">CUPS home page</A> also
+provides many resources including user discussion forums, answers
+to frequently-asked questions, and a form for submitting bug
+reports and feature requests.</P>}
diff --git a/templates/help-printable.tmpl b/templates/help-printable.tmpl
new file mode 100644
index 000000000..2463c1630
--- /dev/null
+++ b/templates/help-printable.tmpl
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{HELPTITLE}</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups-printable.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
diff --git a/templates/help-trailer.tmpl b/templates/help-trailer.tmpl
new file mode 100644
index 000000000..4c1ebed85
--- /dev/null
+++ b/templates/help-trailer.tmpl
@@ -0,0 +1 @@
+</DIV>
diff --git a/templates/id/add-class.tmpl b/templates/id/add-class.tmpl
new file mode 100644
index 000000000..55f90ad2e
--- /dev/null
+++ b/templates/id/add-class.tmpl
@@ -0,0 +1,40 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Tambah Kelas</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Nama:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Karakter apa saja yang dapat dicetak, kecuali "/", "#", dan spasi)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Deskripsi:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Deskripsi yang mudah dibaca, seperti "HP LaserJet dengan Duplexer")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Lokasi:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Lokasi yang mudah dibaca, seperti "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Anggota:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Tambah Kelas"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/id/add-printer.tmpl b/templates/id/add-printer.tmpl
new file mode 100644
index 000000000..5c7c7ccdd
--- /dev/null
+++ b/templates/id/add-printer.tmpl
@@ -0,0 +1,43 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Add Printer</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{?current_make!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE" VALUE="{current_make}">:}
+{?current_make_and_model!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{current_make_and_model}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Nama:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?template_name}"><BR>
+<SMALL>(Karakter apa saja yang dapat dicetak, kecuali "/", "#", dan spasi)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Deskripsi:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_INFO}"><BR>
+<SMALL>(Deskripsi yang mudah dibaca, seperti "HP LaserJet dengan Duplexer")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Location:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_LOCATION}"><BR>
+<SMALL>(Lokasi yang mudah dibaca, seperti "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Koneksi:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Berbagi:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+Berbagi Pencetak Ini</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Lanjut"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/id/add-rss-subscription.tmpl b/templates/id/add-rss-subscription.tmpl
new file mode 100644
index 000000000..bf8f9644b
--- /dev/null
+++ b/templates/id/add-rss-subscription.tmpl
@@ -0,0 +1,44 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
+
+<H2 CLASS="title">Tambah Subskripsi RSS</H2>
+
+<TABLE SUMMARY="Add RSS Subscription form">
+<TR>
+<TH CLASS="label">Nama:</TH>
+<TD COLSPAN="5"><INPUT TYPE="TEXT" NAME="SUBSCRIPTION_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?SUBSCRIPTION_NAME}"><BR>
+<SMALL>(Karakter apa saja yang dapat dicetak, kecuali "/", "#", dan spasi)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Antrian:</TH>
+<TD COLSPAN="5"><SELECT NAME="PRINTER_URI" SIZE="10"><OPTION VALUE="#ALL#"{?PRINTER_URI=#ALL#? SELECTED:}>Semua Antrian</OPTION>{[printer_name]<OPTION VALUE="{printer_uri_supported}"{?PRINTER_URI={printer_uri_supported}? SELECTED:}>{printer_name}</OPTION>}</SELECT></TD>
+</TR>
+<TR VALIGN="TOP">
+<TH CLASS="label">Kejadian:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CREATED" {?EVENT_JOB_CREATED}>Tugas Dibuat<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_COMPLETED" {?EVENT_JOB_COMPLETED}>Tugas Selesai<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_STOPPED" {?EVENT_JOB_STOPPED}>Tugas Berhenti<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CONFIG_CHANGED" {?EVENT_JOB_CONFIG_CHANGED}>Opsi Tugas Berubah</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_STOPPED" {?EVENT_PRINTER_STOPPED}>Antrian Berhenti<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_ADDED" {?EVENT_PRINTER_ADDED}>Antrian Ditambah<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_MODIFIED" {?EVENT_PRINTER_MODIFIED}>Antrian Berubah<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_DELETED" {?EVENT_PRINTER_DELETED}>Antrian Dihapus</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STARTED" {?EVENT_SERVER_STARTED}>Server Dimulai<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STOPPED" {?EVENT_SERVER_STOPPED}>Server Berhenti<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_RESTARTED" {?EVENT_SERVER_RESTARTED}>Server Dijalankan Ulang<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_AUDIT" {?EVENT_SERVER_AUDIT}>Audit Keamanan Server</TD>
+</TR>
+<TR>
+<TH CLASS="label">Maksimal Kejadian dalam Berita:</TH>
+<TD COLSPAN="5"><INPUT TYPE="NUMBER" NAME="MAX_EVENTS" SIZE="4" MAXLENGTH="4" VALUE="{MAX_EVENTS?{MAX_EVENTS}:20}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD COLSPAN="5"><INPUT TYPE="SUBMIT" VALUE="Tambah Subskripsi RSS"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/id/admin.tmpl b/templates/id/admin.tmpl
new file mode 100644
index 000000000..9106d6518
--- /dev/null
+++ b/templates/id/admin.tmpl
@@ -0,0 +1,110 @@
+<TABLE CLASS="indent" SUMMARY="Administration Tasks">
+<TR><TD VALIGN="TOP">
+
+<H2 CLASS="title">Pencetak</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Tambah Pencetak"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Cari Pencetak Baru"></FORM>
+<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Atur Pencetak"></FORM>
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Ekspor Pencetak ke Samba"></FORM>:}
+</P>
+
+<H2 CLASS="title">Kelas</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Tambah Kelas"></FORM>
+<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Atur Kelas"></FORM>
+</P>
+
+<H2 CLASS="title">Tugas</H2>
+
+<P>
+<FORM ACTION="/jobs/" METHDO="GET"><INPUT TYPE="SUBMIT" VALUE="Atur Tugas"></FORM>
+</P>
+
+</TD><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TD VALIGN="TOP">
+
+<H2 CLASS="title">Server</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Sunting Berkas Konfigurasi"></FORM>
+<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Lihat Log Akses"></FORM>
+<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Lihat Log Kesalahan"></FORM>
+<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Lihat Log Halaman"></FORM>
+</P>
+
+{SETTINGS_ERROR?<P>{SETTINGS_MESSAGE}</P>
+<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+
+{ADVANCEDSETTINGS?<P><B>Pengaturan Server\:</B></P>
+
+<P><A HREF="/admin/">Lanjutan <SMALL>&#x25bc;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="HIDDEN" NAME="ADVANCEDSETTINGS" VALUE="YES">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Lihat pencetak yang dibagikan oleh sistem lain<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protokol\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_CUPS" {?browse_remote_cups}> CUPS
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_LDAP" {?browse_remote_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_SLP" {?browse_remote_slp}> SLP:}<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Bagikan pencetak yang terhubung ke sistem ini<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Klien maks.\:
+<INPUT TYPE="TEXT" NAME="MAX_CLIENTS" VALUE="{?max_clients}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protokol\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_CUPS" {?browse_local_cups}> CUPS
+{HAVE_DNSSD?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_DNSSD" {?browse_local_dnssd}> DNS-SD:}
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_LDAP" {?browse_local_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_SLP" {?browse_local_slp}> SLP:}<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Perbolehkan mencetak dari Internet<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="BROWSE_WEB_IF" {?browse_web_if}> Advertise web interface<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Perbolehkan administrasi dari jarak jauh<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Gunakan otentikasi Kerberos (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Perbolehkan pengguna biasa untuk membatalkan semua tugas (termasuk tugas orang lain)<BR>
+<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_HISTORY" {?preserve_job_history}> Catat histori tugas<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Banyaknya tugas\:
+<INPUT TYPE="TEXT" NAME="MAX_JOBS" VALUE="{?max_jobs}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_FILES" {?preserve_job_files}> Catat berkas tugas cetak<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Simpan informasi kesalahan untuk mencari dan memecahkan masalah<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ukuran maks. berkas log\:
+<INPUT TYPE="TEXT" NAME="MAX_LOG_SIZE" VALUE="{?max_log_size}" SIZE="6"></P>
+
+:<P><B>Pengaturan Server:</B></P>
+
+<P><A HREF="/admin/?ADVANCEDSETTINGS=YES">Lanjutan <SMALL>&#x25b6;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Lihat pencetak yang dibagikan oleh sistem lain<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Bagikan pencetak yang terhubung ke sistem ini<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Perbolehkan mencetak dari Internet<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Perbolehkan administrasi dari jarak jauh<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Gunakan otentikasi Kerberos (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Perbolehkan pengguna biasa untuk membatalkan semua tugas (termasuk tugas orang lain)<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Save debugging information for troubleshooting</P>
+
+}
+<P><INPUT TYPE="SUBMIT" NAME="CHANGESETTINGS" VALUE="Ubah Pengaturan"></P>
+
+</FORM>}
+
+</TD></TR>
+</TABLE>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Subskripsi RSS</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Tambah Subskripsi RSS"></FORM>
+</P>
+
+</DIV>
+
+{notify_subscription_id?<TABLE CLASS="list" SUMMARY="RSS Subscriptions">
+<THEAD><TR><TH>Nama</TH><TH>Kejadian</TH><TH>Nama Antrian</TH></TR></THEAD>
+<TBODY>{[notify_subscription_id]
+<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Cancel RSS Subscription"></FORM>&nbsp;</TD><TD>{notify_events}</TD><TD NOWRAP>&nbsp;{notify_printer_name?{notify_printer_name}:Semua Antrian}</TD></TR>}
+</TBODY>
+</TABLE>:}
diff --git a/templates/id/choose-device.tmpl b/templates/id/choose-device.tmpl
new file mode 100644
index 000000000..8f812a5e4
--- /dev/null
+++ b/templates/id/choose-device.tmpl
@@ -0,0 +1,54 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Ubah {printer_name}:Tambah Pencetak}</H2>
+
+{CUPS_GET_DEVICES_DONE?:<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Busy Indicator"> Mencari pencetak...</P>}
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+{op=add-printer?:<TR>
+<TH CLASS="label">Koneksi yang Ada:</TH>
+<TD><INPUT TYPE="RADIO" NAME="DEVICE_URI" VALUE="{current_device_uri}" CHECKED>
+{current_device_uri}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Pencetak Lokal:</TH>
+<TD>
+{[device_uri]{device_class!network?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}}
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Pencetak Jaringan yang Ditemukan:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}:}}
+</TD>
+</TR>
+<TR>
+<TR>
+<TH CLASS="label">Pencetak Jaringan Lainnya:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?:<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+}:}}
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Lanjut"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/id/choose-make.tmpl b/templates/id/choose-make.tmpl
new file mode 100644
index 000000000..d04338fcc
--- /dev/null
+++ b/templates/id/choose-make.tmpl
@@ -0,0 +1,64 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Ubah {printer_name}:Tambah Pencetak}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Nama:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Deskripsi:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Lokasi:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Koneksi:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Berbagi:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+{?printer_is_shared=?Do Not:{?printer_is_shared=0?Do Not:}} Share This Printer</TD>
+</TR>
+<TR>
+<TH CLASS="label">Buatan:</TH>
+<TD>
+<SELECT NAME="PPD_MAKE" SIZE="10">
+{[ppd_make]<OPTION VALUE="{ppd_make}" {?current_make={ppd_make}?SELECTED:}>{ppd_make}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Lanjut"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>&nbsp;</TD>
+</TR>
+<TR>
+<TH CLASS="label">Atau, Sediakan Berkas PPD:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?Tambah Pencetak:Ubah Pencetak}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/id/choose-model.tmpl b/templates/id/choose-model.tmpl
new file mode 100644
index 000000000..c4cfdb9d0
--- /dev/null
+++ b/templates/id/choose-model.tmpl
@@ -0,0 +1,60 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Tambah Pencetak}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Nama:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Deskripsi:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Lokasi:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Koneksi:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Berbagi:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+{?printer_is_shared=?Jangan:{?printer_is_shared=0?Jangan:}} Berbagi Pencetak Ini</TD>
+</TR>
+<TR>
+<TH CLASS="label">Pembuat:</TH>
+<TD>{PPD_MAKE} <INPUT TYPE="SUBMIT" NAME="SELECT_MAKE" VALUE="Pilih Manufaktur/Pembuat Lainnya"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Model:</TH>
+<TD>
+<SELECT NAME="PPD_NAME" SIZE="10">
+{op=add-printer?:<OPTION VALUE="__no_change__" SELECTED>Penggerak Saat Ini - {current_make_and_model}</OPTION>:}
+{[ppd_name]<OPTION VALUE="{ppd_name}" {op=modify-printer?:{?current_make_and_model={ppd_make_and_model}?SELECTED:}}>{ppd_make_and_model} ({ppd_natural_language})
+}</SELECT>
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Atau Sediakan Berkas PPD:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?Tambah Pencetak:Ubah Pencetak}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/id/choose-serial.tmpl b/templates/id/choose-serial.tmpl
new file mode 100644
index 000000000..19de16c4f
--- /dev/null
+++ b/templates/id/choose-serial.tmpl
@@ -0,0 +1,52 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Tambah Pencetak}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Koneksi:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Kecepatan Data:</TH>
+<TD><SELECT NAME="BAUDRATE">
+{[baudrates]<OPTION {?baudrate={baudrates}?SELECTED:}>{baudrates}}
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Paritas:</TH>
+<TD><SELECT NAME="PARITY">
+<OPTION VALUE="none" {?parity=none?SELECTED:}>Nihil
+<OPTION VALUE="even" {?parity=even?SELECTED:}>Genap
+<OPTION VALUE="odd" {?parity=odd?SELECTED:}>Ganjil
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Bit Data:</TH>
+<TD><SELECT NAME="BITS">
+<OPTION {?bits=8?SELECTED:}>8
+<OPTION {?bits=7?SELECTED:}>7
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Kendali Aliran Data:</TH>
+<TD><SELECT NAME="FLOW">
+<OPTION VALUE="none" {?flow=none?SELECTED:}>Nihil
+<OPTION VALUE="soft" {?flow=soft?SELECTED:}>XON/XOFF (Peranti Lunak)
+<OPTION VALUE="hard" {?flow=hard?SELECTED:}>RTS/CTS (Peranti Keras)
+<OPTION VALUE="dtrdsr" {?flow=dtrdsr?SELECTED:}>DTR/DSR (Peranti Keras)
+</SELECT></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Lanjut"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/id/choose-uri.tmpl b/templates/id/choose-uri.tmpl
new file mode 100644
index 000000000..4391b9114
--- /dev/null
+++ b/templates/id/choose-uri.tmpl
@@ -0,0 +1,43 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Tambah Pencetak}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Koneksi:</TH>
+<TD><INPUT TYPE="URL" SIZE="60" MAXLENGTH="1023" NAME="DEVICE_URI" VALUE="{current_device_uri?{current_device_uri}:{device_uri}}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>Contoh:
+<PRE>
+ http://hostname:631/ipp/
+ http://hostname:631/ipp/port1
+
+ ipp://hostname/ipp/
+ ipp://hostname/ipp/port1
+
+ lpd://hostname/queue
+
+ socket://hostname
+ socket://hostname:9100
+</PRE>
+
+<P>Lihat <A HREF="/help/network.html" TARGET="_blank">"Pencetak Jaringan"</A> untuk URI yang tepat bagi pencetak Anda.</P>
+
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Lanjut"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/id/class-added.tmpl b/templates/id/class-added.tmpl
new file mode 100644
index 000000000..12c408f84
--- /dev/null
+++ b/templates/id/class-added.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Tambah Kelas</H2>
+
+<P>Kelas <A HREF="/classes/{printer_name}">{printer_name}</A> telah berhasil ditambahkan.
+
+</DIV>
diff --git a/templates/id/class-confirm.tmpl b/templates/id/class-confirm.tmpl
new file mode 100644
index 000000000..3805b9177
--- /dev/null
+++ b/templates/id/class-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Hapus Kelas {printer_name}</H2>
+
+<P><B>Peringatan:</B> Anda yakin untuk menghapus kelas
+{printer_name}?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Hapus Kelas"></FORM></P>
+
+</DIV>
diff --git a/templates/id/class-deleted.tmpl b/templates/id/class-deleted.tmpl
new file mode 100644
index 000000000..30320cbe3
--- /dev/null
+++ b/templates/id/class-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Hapus Kelas {printer_name}</H2>
+
+<P>Kelas {printer_name} telah berhasil dihapus.
+
+</DIV>
diff --git a/templates/id/class-jobs-header.tmpl b/templates/id/class-jobs-header.tmpl
new file mode 100644
index 000000000..e6ca44714
--- /dev/null
+++ b/templates/id/class-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">Tugas</H3>
+</DIV>
diff --git a/templates/id/class-modified.tmpl b/templates/id/class-modified.tmpl
new file mode 100644
index 000000000..d2fdded39
--- /dev/null
+++ b/templates/id/class-modified.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ubah Kelas {printer_name}</H2>
+
+<P>Kelas <A HREF="/classes/{printer_name}">{printer_name}</A> telah berhasil diubah.
+
+</DIV>
diff --git a/templates/id/class.tmpl b/templates/id/class.tmpl
new file mode 100644
index 000000000..af2178736
--- /dev/null
+++ b/templates/id/class.tmpl
@@ -0,0 +1,44 @@
+<DIV CLASS="indent">
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?Idle:{printer_state=4?Memproses:Ditahan}},
+{printer_is_accepting_jobs=0?Menolak Tugas:Menerima Tugas},
+{server_is_sharing_printers=0?Jangan:{printer_is_shared=0?Jangan:}} Berbagi{default_name={printer_name}?, Server Baku:})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">Perawatan</OPTION>
+<OPTION VALUE="print-test-page">Halaman Uji Cetak</OPTION>
+{printer_state=5?<OPTION VALUE="start-class">Resume Kelas</OPTION>:<OPTION VALUE="stop-class">Tahan Kelas</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Terima Tugas</OPTION>:<OPTION VALUE="reject-jobs">Tolak Tugas</OPTION>}
+<OPTION VALUE="move-jobs">Pindahkan Semua Tugas</OPTION>
+<OPTION VALUE="purge-jobs">Batalkan Semua Tugas</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Lakukan!" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="1">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">Administrasi</OPTION>
+<OPTION VALUE="modify-class">Ubah Kelas</OPTION>
+<OPTION VALUE="delete-class">Hapus Kelas</OPTION>
+<OPTION VALUE="set-class-options">Atur Opsi Baku</OPTION>
+<OPTION VALUE="set-as-default">Atur Sebagai Server Baku</OPTION>
+<OPTION VALUE="set-allowed-users">Atur Pengguna yang Diperbolehkan</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Lakukan!" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Deskripsi:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Lokasi:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Anggota:</TH><TD>{?member_uris=?None:{member_uris}}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Baku:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:unknown}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/id/classes-header.tmpl b/templates/id/classes-header.tmpl
new file mode 100644
index 000000000..da891a3c7
--- /dev/null
+++ b/templates/id/classes-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?Tidak ada kelas:Menampilkan {#printer_name} dari {total} kelas{total=1?:}}.</P>
diff --git a/templates/id/classes.tmpl b/templates/id/classes.tmpl
new file mode 100644
index 000000000..c8e9b5f28
--- /dev/null
+++ b/templates/id/classes.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Class List">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Nama Antrian <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Nama Antrian <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Deskripsi</TH><TH>Lokasi</TH><TH>Anggota</TH><TH>Status</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{?member_uris=?Nihil:{member_uris}}</TD><TD>{printer_state=3?Idle:{printer_state=4?Memproses:Ditahan}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/id/command.tmpl b/templates/id/command.tmpl
new file mode 100644
index 000000000..b38d2c985
--- /dev/null
+++ b/templates/id/command.tmpl
@@ -0,0 +1,12 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{title} Pada {printer_name}</H2>
+
+<P>{job_state>5?:<IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16"
+ALIGN="ABSMIDDLE" ALT="Indikator Kesibukan"> }Perintah tugas pencetak
+{job_state=3?pending:{job_state=4?held:
+{job_state=5?processing:{job_state=6?stopped:
+{job_state=7?canceled:{job_state=8?aborted:completed}}}}}}{job_state=9?:{job_printer_state_message?,
+<EM>"{job_printer_state_message}"</EM>:}}</P>
+
+</DIV>
diff --git a/templates/id/edit-config.tmpl b/templates/id/edit-config.tmpl
new file mode 100644
index 000000000..6701f84ac
--- /dev/null
+++ b/templates/id/edit-config.tmpl
@@ -0,0 +1,24 @@
+<SCRIPT TYPE="text/javascript">
+function reset_config()
+{
+ document.cups.CUPSDCONF.value = "{?cupsdconf_default}";
+}
+</SCRIPT>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Sunting Berkas Konfigurasi</H2>
+
+<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+
+<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
+
+<P><INPUT TYPE="SUBMIT" NAME="SAVECHANGES" VALUE="Simpan Perubahan">
+<INPUT TYPE="BUTTON" VALUE="Gunakan Konfigurasi Baku"
+onClick="reset_config();"></P>
+
+</FORM>
+
+</DIV>
diff --git a/templates/id/error-op.tmpl b/templates/id/error-op.tmpl
new file mode 100644
index 000000000..2611c5dee
--- /dev/null
+++ b/templates/id/error-op.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Kesalahan {?title} {?printer_name}</H2>
+
+<P>Kesalahan:</P>
+
+<BLOCKQUOTE>Operasi tak dikenal "{op}"!</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/id/error.tmpl b/templates/id/error.tmpl
new file mode 100644
index 000000000..c74bd7096
--- /dev/null
+++ b/templates/id/error.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Kesalahan {?title} {?printer_name}</H2>
+
+<P>{?message?{message}:Kesalahan:}</P>
+
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/id/header.tmpl.in b/templates/id/header.tmpl.in
new file mode 100644
index 000000000..b45d870cb
--- /dev/null
+++ b/templates/id/header.tmpl.in
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{title} - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+ {refresh_page?<META HTTP-EQUIV="Refresh" CONTENT="{refresh_page}">:}
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="unsel"><A HREF="/">&nbsp;&nbsp;Home&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=admin?:un}sel"><A HREF="/admin">&nbsp;&nbsp;Administrasi&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=classes?:un}sel"><A HREF="/classes/">&nbsp;&nbsp;Kelas&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=help?:un}sel"><A HREF="/help/">&nbsp;&nbsp;Bantuan&nbsp;Langsung&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=jobs?:un}sel"><A HREF="/jobs/">&nbsp;&nbsp;Tugas&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=printers?:un}sel"><A HREF="/printers/">&nbsp;&nbsp;Pencetak&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Search Help"
+VALUE="{SECTION=help?{?QUERY}:}" AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+<TR><TD COLSPAN="9">&nbsp;</TD></TR>
+</TABLE>
diff --git a/templates/id/help-header.tmpl b/templates/id/help-header.tmpl
new file mode 100644
index 000000000..e28b52781
--- /dev/null
+++ b/templates/id/help-header.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET">
+{TOPIC?<INPUT TYPE="HIDDEN" NAME="TOPIC" VALUE="{TOPIC}">:}
+
+<P ALIGN="CENTER"><B>Mencari di
+{HELPTITLE?{HELPTITLE}:{TOPIC?{TOPIC}:Semua Dokumen}}:</B> <INPUT
+TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER=""
+AUTOSAVE="org.cups.help" RESULTS="20">
+<INPUT TYPE="SUBMIT" NAME="SEARCH" VALUE="Cari">
+<INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="Bersihkan"></P>
+
+</FORM>
+
+<!-- Bookmarks -->
+<DIV CLASS="sidebar"><TABLE CLASS="inset" SUMMARY="Contents">
+<TR><TD>
+
+<H3 CLASS="title">Dokumen Bantuan Langsung</H3>
+
+<P CLASS="l0"><A HREF="/help/{QUERY??QUERY={QUERY}:}">Semua Dokumen</A></P>
+<HR>
+
+{[BMTEXT]<P CLASS="l{BMINDENT}"><A HREF="{BMLINK}">{BMTEXT}</A></P>
+}
+</TD></TR>
+</TABLE></DIV>
+
+{QUERY?<P>Hasil Pencarian di {HELPFILE?{HELPTITLE}:{TOPIC?{TOPIC}:Semua Dokumen}}\:</P>
+{QTEXT?<UL>
+{[QTEXT]<LI><A HREF="{QLINK}">{QTEXT}</A>{QPTEXT? (di <I><A HREF="{QPLINK}">{QPTEXT}</A></I>):}</LI>}
+{QTEXT?</UL>:}
+:<P>Tidak ada yang cocok.</P>}
+<HR NOSHADE>:}
+{HELPTITLE?<H1>{HELPTITLE}</H1>
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="PRINTABLE" VALUE="YES"><INPUT TYPE="SUBMIT" VALUE="Lihat Versi Cetak"></FORM>:
+
+<H1>Bantuan Langsung</H1>
+
+<P>Ini adalah antarmuka bantuan langsung milik CUPS. Masukkan kata yang hendak dicari pada kotak
+di atas atau klik salah satu taut dokumen untuk melihat informasi bantuan langsung tersebut.</P>
+
+<P>Apabila Anda adalah pengguna baru CUPS, bacalah halaman "<a
+href="/help/overview.html">Ikhtisar CUPS</a>". Bagi yang sudah berpengalaman, dapat
+membaca halaman "<a href="/help/whatsnew.html">Apa yang Baru di CUPS
+1.4</a>".</P>
+
+<P><A HREF="http://www.cups.org/">Laman CUPS</A> juga menyediakan berbagai sumber termasuk forum, jawaban untuk pertanyaan-pertanyaan yang sering diajukan, serta formulir untuk mengirim laporan kode hama dan permintaan fitur baru.</P>}
diff --git a/templates/id/help-printable.tmpl b/templates/id/help-printable.tmpl
new file mode 100644
index 000000000..2463c1630
--- /dev/null
+++ b/templates/id/help-printable.tmpl
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{HELPTITLE}</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups-printable.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
diff --git a/templates/id/help-trailer.tmpl b/templates/id/help-trailer.tmpl
new file mode 100644
index 000000000..4c1ebed85
--- /dev/null
+++ b/templates/id/help-trailer.tmpl
@@ -0,0 +1 @@
+</DIV>
diff --git a/templates/id/job-cancel.tmpl b/templates/id/job-cancel.tmpl
new file mode 100644
index 000000000..d3d604719
--- /dev/null
+++ b/templates/id/job-cancel.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Batalkan Tugas {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Tugas {job_id}</A> telah dibatalkan.
+
+</DIV>
diff --git a/templates/id/job-hold.tmpl b/templates/id/job-hold.tmpl
new file mode 100644
index 000000000..ab2dd5937
--- /dev/null
+++ b/templates/id/job-hold.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Tahan Tugas {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Tugas {job_id}</A> telah ditahan untuk dicetak.
+
+</DIV>
diff --git a/templates/id/job-move.tmpl b/templates/id/job-move.tmpl
new file mode 100644
index 000000000..9ec881a04
--- /dev/null
+++ b/templates/id/job-move.tmpl
@@ -0,0 +1,27 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
+
+<H2 CLASS="title">{job_id?Pindahkan Tugas {job_id}:Pindahkan Semua Tugas}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">Tujuan Baru:</TH>
+<TD>
+<SELECT NAME="JOB_PRINTER_URI" SIZE="10">
+{[job_printer_uri]<OPTION VALUE="{job_printer_uri}">{job_printer_name}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{job_id?Pindahkan Tugas:Pindahkan Tugas}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+
+</DIV>
diff --git a/templates/id/job-moved.tmpl b/templates/id/job-moved.tmpl
new file mode 100644
index 000000000..c52c31296
--- /dev/null
+++ b/templates/id/job-moved.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{job_id?Pindahkan Tugas {job_id}:Pindahkan Semua Tugas}</H2>
+
+<P>{job_id?<A HREF="/jobs/{job_id}">Tugas {job_id}</A>:Semua tugas} dipindahkan ke
+<A HREF="/{is_class?classes:printers}/{job_printer_name}">{job_printer_name}</A>.</P>
+
+</DIV>
diff --git a/templates/id/job-release.tmpl b/templates/id/job-release.tmpl
new file mode 100644
index 000000000..a447ae19b
--- /dev/null
+++ b/templates/id/job-release.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Lepaskan Tugas {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Tugas {job_id}</A> telah dilepas untuk dicetak.
+
+</DIV>
diff --git a/templates/id/job-restart.tmpl b/templates/id/job-restart.tmpl
new file mode 100644
index 000000000..c54601c87
--- /dev/null
+++ b/templates/id/job-restart.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Cetak Ulang Tugas {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Tugas {job_id}</A> telah dilaksanakan ulang.
+
+</DIV>
diff --git a/templates/id/jobs-header.tmpl b/templates/id/jobs-header.tmpl
new file mode 100644
index 000000000..3cba80c58
--- /dev/null
+++ b/templates/id/jobs-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">{?which_jobs=?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Lihat Tugas yang Aktif"></FORM>}
+{?which_jobs=completed?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="completed"><INPUT TYPE="SUBMIT" VALUE="Lihat Tugas yang Diselesaikan"></FORM>}
+{?which_jobs=all?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="all"><INPUT TYPE="SUBMIT" VALUE="Lihat Semua Tugas"></FORM>}</DIV>
+
+<P ALIGN="CENTER">{total=0?Tidak ada tugas:Menampilkan {#job_id} dari {total} tugas {?which_jobs=?yang aktif:{which_jobs=all?:yang diselesaikan}} {total=1?:}}.</P>
diff --git a/templates/id/jobs.tmpl b/templates/id/jobs.tmpl
new file mode 100644
index 000000000..1cd13a0ec
--- /dev/null
+++ b/templates/id/jobs.tmpl
@@ -0,0 +1,36 @@
+{#job_id=0?:
+<TABLE CLASS="list" SUMMARY="Job List">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> ID <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> ID <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Nama</TH><TH>Pengguna</TH><TH>Ukuran</TH><TH>Halaman</TH><TH>Status</TH><TH>Kontrol</TH></TR>
+</THEAD>
+<TBODY>
+{[job_id]
+<TR VALIGN="TOP">
+<TD><A HREF="{job_printer_uri}">{job_printer_name}</A>-{job_id}&nbsp;</TD>
+<TD>{?job_name=?Tak Dikenal:{job_name}}&nbsp;</TD>
+<TD>{job_originating_user_name}&nbsp;</TD>
+<TD>{job_k_octets}k&nbsp;</TD>
+<TD>{job_media_sheets_completed=0?Tak Dikenal:{?job_media_sheets_completed}}&nbsp;</TD>
+<TD>{job_state=3?ditunda sejak<BR>{time_at_creation}:{job_state=4?ditahan sejak<BR>{time_at_creation}:
+{job_state=5?diproses sejak<BR>{time_at_processing}:{job_state=6?dihentikan:
+{job_state=7?dibatalkan pada<BR>{time_at_completed}:{job_state=8?dibatalkan:diselesaikan pada<BR>{time_at_completed}}}}}}}&nbsp;{job_printer_state_message?<BR>
+<EM>"{job_printer_state_message}"</EM>:}</TD>
+<TD>
+{job_preserved>0?{job_state>5?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}"><INPUT TYPE="SUBMIT" VALUE="Reprint Job"></FORM>:}:}
+{job_state=4?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Release Job"></FORM>:}
+{job_state=3?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Hold Job"></FORM>:}
+{job_state<7?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Cancel Job"></FORM>
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Move Job"></FORM>:}
+&nbsp;</TD>
+</TR>
+}
+</TBODY>
+</TABLE>
+}
diff --git a/templates/id/list-available-printers.tmpl b/templates/id/list-available-printers.tmpl
new file mode 100644
index 000000000..f3ca39fd9
--- /dev/null
+++ b/templates/id/list-available-printers.tmpl
@@ -0,0 +1,11 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Pencetak yang Ada</H2>
+
+{#device_uri=0?<P>Tidak ada pencetak.</P>
+:<UL>{[device_uri]
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Tambah Pencetak Ini"></FORM>
+{device_make_and_model} ({device_info})</LI>
+}</UL>}
+
+</DIV>
diff --git a/templates/id/modify-class.tmpl b/templates/id/modify-class.tmpl
new file mode 100644
index 000000000..db2d65e26
--- /dev/null
+++ b/templates/id/modify-class.tmpl
@@ -0,0 +1,34 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ubah Kelas {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Deskripsi:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Lokasi:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Anggota:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Ubah Kelas"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/id/modify-printer.tmpl b/templates/id/modify-printer.tmpl
new file mode 100644
index 000000000..9bdb0c4f1
--- /dev/null
+++ b/templates/id/modify-printer.tmpl
@@ -0,0 +1,38 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ubah {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Deskripsi:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Deskripsi yang mudah dibaca, seperti "HP LaserJet dengan Pendupleks")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Lokasi:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Deskripsi yang mudah dibaca, seperti "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Koneksi:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Berbagi:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+Berbagi Pencetak Ini</TD>
+</TR>
+<TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Lanjut"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/id/norestart.tmpl b/templates/id/norestart.tmpl
new file mode 100644
index 000000000..f39d9f259
--- /dev/null
+++ b/templates/id/norestart.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ubah Pengaturan</H2>
+
+<P>Server tidak dijalankan ulang karena tidak ada perubahan yang terjadi...</P>
+
+</DIV>
diff --git a/templates/id/option-boolean.tmpl b/templates/id/option-boolean.tmpl
new file mode 100644
index 000000000..e832ee102
--- /dev/null
+++ b/templates/id/option-boolean.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD>
+{[choices]<INPUT TYPE="RADIO" NAME="{keyword-1}" {choices={defchoice-1}?CHECKED:} VALUE="{choices}">{text}}
+</TD>
+</TR>
diff --git a/templates/id/option-conflict.tmpl b/templates/id/option-conflict.tmpl
new file mode 100644
index 000000000..71e2bcca8
--- /dev/null
+++ b/templates/id/option-conflict.tmpl
@@ -0,0 +1,7 @@
+<P><B>Kesalahan:</B> Opsi berikut ini konflik:</P>
+
+<UL>
+{[ckeyword]<LI><A HREF="#{ckeyword}">{ckeytext}</A>: {cchoice}</LI>
+}</UL>
+
+<P>Silakan ubah satu atau lebih opsi yang ada untuk memperbaiki masalah ini.</P>
diff --git a/templates/id/option-header.tmpl b/templates/id/option-header.tmpl
new file mode 100644
index 000000000..464726a50
--- /dev/null
+++ b/templates/id/option-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="tab" ID="{group_id}">
+
+<H3 ALIGN="CENTER">{group}</H3>
+
+<TABLE WIDTH="100%">
diff --git a/templates/id/option-pickmany.tmpl b/templates/id/option-pickmany.tmpl
new file mode 100644
index 000000000..0da75e5d2
--- /dev/null
+++ b/templates/id/option-pickmany.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" MULTIPLE SIZE="10">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT></TD>
+</TR>
diff --git a/templates/id/option-pickone.tmpl b/templates/id/option-pickone.tmpl
new file mode 100644
index 000000000..8ee71b316
--- /dev/null
+++ b/templates/id/option-pickone.tmpl
@@ -0,0 +1,18 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" ID="select-{keyword}" ONCHANGE="update_paramtable('{keyword}')">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT>
+{iscustom=1?<TABLE NAME="paramtable" id="{keyword}-params">{[params]
+<TR><TH CLASS="sublabel">{paramtext}:</TH>
+<TD>{params=Units?<SELECT NAME="{keyword-1}.{params}">
+<OPTION VALUE="pt"{paramvalue=pt? SELECTED:}>Poin</OPTION>
+<OPTION VALUE="mm"{paramvalue=mm? SELECTED:}>Milimeter</OPTION>
+<OPTION VALUE="cm"{paramvalue=cm? SELECTED:}>Sentimeter</OPTION>
+<OPTION VALUE="in"{paramvalue=in? SELECTED:}>Inci</OPTION>
+<OPTION VALUE="ft"{paramvalue=ft? SELECTED:}>Kaki</OPTION>
+<OPTION VALUE="m"{paramvalue=m? SELECTED:}>Meter</OPTION>
+</SELECT>:<INPUT TYPE="{inputtype}" NAME="{keyword-1}.{params}" VALUE="{paramvalue}">}</TD></TR>
+}</TABLE>
+</TD>:}
+</TR>
diff --git a/templates/id/option-trailer.tmpl b/templates/id/option-trailer.tmpl
new file mode 100644
index 000000000..a403a981f
--- /dev/null
+++ b/templates/id/option-trailer.tmpl
@@ -0,0 +1,5 @@
+</TABLE>
+
+<P ALIGN="CENTER"><INPUT TYPE="SUBMIT" VALUE="Atur Opsi Baku"></P>
+
+</DIV>
diff --git a/templates/id/pager.tmpl b/templates/id/pager.tmpl
new file mode 100644
index 000000000..00b6340c3
--- /dev/null
+++ b/templates/id/pager.tmpl
@@ -0,0 +1,6 @@
+<TABLE CLASS="inset" SUMMARY="Paging Bar">
+<TR>
+ <TD WIDTH="50%">{PREV?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{PREV}"><INPUT TYPE="SUBMIT" VALUE="&#x25c0; Sebelumnya"></FORM>:&nbsp;}</TD>
+ <TD WIDTH="50%" ALIGN="RIGHT">{NEXT?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{NEXT}"><INPUT TYPE="SUBMIT" VALUE="Selanjutnya &#x25b6;"></FORM>:&nbsp;}</TD>
+</TR>
+</TABLE>
diff --git a/templates/id/printer-accept.tmpl b/templates/id/printer-accept.tmpl
new file mode 100644
index 000000000..bba229a81
--- /dev/null
+++ b/templates/id/printer-accept.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Terima Tugas dari {is_class?Kelas:Pencetak} {printer_name}</H2>
+
+<P>{is_class?Kelas:Pencetak} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+kini menerima tugas.</P>
+
+</DIV>
diff --git a/templates/id/printer-added.tmpl b/templates/id/printer-added.tmpl
new file mode 100644
index 000000000..636496a9a
--- /dev/null
+++ b/templates/id/printer-added.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Tambah Pencetak</H2>
+
+<P>Pencetak <A HREF="/printers/{printer_name}">{printer_name}</A> telah berhasil ditambahkan.
+
+</DIV>
diff --git a/templates/id/printer-configured.tmpl b/templates/id/printer-configured.tmpl
new file mode 100644
index 000000000..c2c817928
--- /dev/null
+++ b/templates/id/printer-configured.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Atur Opsi Baku untuk {printer_name}</H2>
+
+<P>Opsi baku {OP=set-class-options?kelas <A HREF="/classes/{printer_name}">:pencetak <A HREF="/printers/{printer_name}">}{printer_name}</A>
+telah berhasil ditetapkan.
+
+</DIV>
diff --git a/templates/id/printer-confirm.tmpl b/templates/id/printer-confirm.tmpl
new file mode 100644
index 000000000..e6d89d616
--- /dev/null
+++ b/templates/id/printer-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Hapus Pencetak {printer_name}</H2>
+
+<P><B>Peringatan:</B> Anda yakin untuk menghapus
+{printer_name}?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Hapus Pencetak"></FORM></P>
+
+</DIV>
diff --git a/templates/id/printer-default.tmpl b/templates/id/printer-default.tmpl
new file mode 100644
index 000000000..2bbedae09
--- /dev/null
+++ b/templates/id/printer-default.tmpl
@@ -0,0 +1,11 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Atur {is_class?Kelas:Pencetak} {printer_name} sebagai Baku</H2>
+
+<P>{is_class?Kelas:Pencetak} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+telah dijadikan pencetak utama pada server.</P>
+
+<BLOCKQUOTE><B>Catatan:</B> Semua pengguna yang diatur melalui perintah <TT>lpoptions</TT> akan ditimpa oleh pengaturan ini.</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/id/printer-deleted.tmpl b/templates/id/printer-deleted.tmpl
new file mode 100644
index 000000000..e4492ea24
--- /dev/null
+++ b/templates/id/printer-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Hapus Pencetak {printer_name}</H2>
+
+<P>Pencetak {printer_name} telah berhasil dihapus.
+
+</DIV>
diff --git a/templates/id/printer-jobs-header.tmpl b/templates/id/printer-jobs-header.tmpl
new file mode 100644
index 000000000..e6ca44714
--- /dev/null
+++ b/templates/id/printer-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">Tugas</H3>
+</DIV>
diff --git a/templates/id/printer-modified.tmpl b/templates/id/printer-modified.tmpl
new file mode 100644
index 000000000..16a7ad349
--- /dev/null
+++ b/templates/id/printer-modified.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ubah Pencetak {printer_name}</H2>
+
+<P>Pencetak <A HREF="/printers/{printer_name}">{printer_name}</A> telah berhasil diubah.
+
+</DIV>
diff --git a/templates/id/printer-purge.tmpl b/templates/id/printer-purge.tmpl
new file mode 100644
index 000000000..5dff3ef14
--- /dev/null
+++ b/templates/id/printer-purge.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Bersihkan Tugas untuk {is_class?Kelas:Pencetak} {printer_name}</H2>
+
+<P>{is_class?Kelas:Pencetak} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+telah dibersihkan dari semua tugas.</P>
+
+</DIV>
diff --git a/templates/id/printer-reject.tmpl b/templates/id/printer-reject.tmpl
new file mode 100644
index 000000000..616dbf009
--- /dev/null
+++ b/templates/id/printer-reject.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Tolak Tugas untuk {is_class?Kelas:Pencetak} {printer_name}</H2>
+
+<P>{is_class?Kelas:Pencetak} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+tidak lagi menerima tugas.</P>
+
+</DIV>
diff --git a/templates/id/printer-start.tmpl b/templates/id/printer-start.tmpl
new file mode 100644
index 000000000..ca3d95a5f
--- /dev/null
+++ b/templates/id/printer-start.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Menjalankan Ulang {is_class?Kelas:Pencetak} {printer_name}</H2>
+
+<P>{is_class?Kelas:Pencetak} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+telah dijalankan lagi.</P>
+
+</DIV>
diff --git a/templates/id/printer-stop.tmpl b/templates/id/printer-stop.tmpl
new file mode 100644
index 000000000..ca022e002
--- /dev/null
+++ b/templates/id/printer-stop.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Menghentikan {is_class?Kelas:Pencetak} {printer_name}</H2>
+
+<P>{is_class?Kelas:Pencetak} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+telah dihentikan.</P>
+
+</DIV>
diff --git a/templates/id/printer.tmpl b/templates/id/printer.tmpl
new file mode 100644
index 000000000..4c56b6761
--- /dev/null
+++ b/templates/id/printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?Menganggur:{printer_state=4?Memproses:Berhenti}},
+{printer_is_accepting_jobs=0?Menolak Tugas:Menerima Tugas},
+{server_is_sharing_printers=0?Tidak:{printer_is_shared=0?Tidak:}} Berbagi{default_name={printer_name}?, Server Baku:})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">Perawatan</OPTION>
+<OPTION VALUE="print-test-page">Cetak Halaman Uji</OPTION>
+{printer_commands~.*Clean.*?<OPTION VALUE="clean-print-heads">Bersihkan Kepala Pencetak</OPTION>:}
+{printer_commands~.*PrintSelfTestPage.*?<OPTION VALUE="print-self-test-page">Cetak Halaman Uji-Sendiri</OPTION>:}
+{printer_state=5?<OPTION VALUE="start-printer">Resume Pencetak</OPTION>:<OPTION VALUE="stop-printer">Tahan Pencetak</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Terima Tugas</OPTION>:<OPTION VALUE="reject-jobs">Tolak Tugas</OPTION>}
+<OPTION VALUE="move-jobs">Pindahkan Semua TUgas</OPTION>
+<OPTION VALUE="purge-jobs">Batalkan Semua Tugas</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Lakukan!" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">Administrasi</OPTION>
+<OPTION VALUE="modify-printer">Ubah Pencetak</OPTION>
+<OPTION VALUE="delete-printer">Hapus Pencetak</OPTION>
+<OPTION VALUE="set-printer-options">Atur Opsi Baku</OPTION>
+<OPTION VALUE="set-as-default">Atus Sebagai Server Baku</OPTION>
+<OPTION VALUE="set-allowed-users">Atur Pengguna yang Diperbolehkan</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Lakukan!" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Deskripsi:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Lokasi:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Penggerak:</TH><TD>{printer_make_and_model} ({color_supported=1?warna:skala abu-abu}{sides_supported?, cetak 2-sisi:})<BR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Koneksi:</TH><TD>{device_uri}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Baku:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:tak dikenal}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/id/printers-header.tmpl b/templates/id/printers-header.tmpl
new file mode 100644
index 000000000..b1a00fcd4
--- /dev/null
+++ b/templates/id/printers-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?Tidak ada pencetak:Menampilkan {#printer_name} dari {total} pencetak{total=1?:}}.</P>
diff --git a/templates/id/printers.tmpl b/templates/id/printers.tmpl
new file mode 100644
index 000000000..3aa4d0da6
--- /dev/null
+++ b/templates/id/printers.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Printer List">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Nama Antrian <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Nama Antrian <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Deskripsi</TH><TH>Lokasi</TH><TH>Pembuat dan Model</TH><TH>Status</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{printer_make_and_model}</TD><TD>{printer_state=3?Menganggur:{printer_state=4?Memproses:Berhenti}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/id/restart.tmpl b/templates/id/restart.tmpl
new file mode 100644
index 000000000..fde1b06ba
--- /dev/null
+++ b/templates/id/restart.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ubah Pengaturan</H2>
+
+<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Indikator Kesibukan"> Silakan tunggu selagi server dijalankan ulang...</P>
+
+</DIV>
diff --git a/templates/id/samba-export.tmpl b/templates/id/samba-export.tmpl
new file mode 100644
index 000000000..4d9e17519
--- /dev/null
+++ b/templates/id/samba-export.tmpl
@@ -0,0 +1,55 @@
+<SCRIPT TYPE="text/javascript"><!--
+function select_printers() {
+ var list = document.export_samba.EXPORT_NAME;
+ var sel = document.export_samba.EXPORT_ALL.checked;
+
+ for (i = 0; i < list.length; i ++) {
+ list.options[i].selected = sel;
+ }
+}
+--></SCRIPT>
+
+<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
+
+<H2 CLASS="title">Ekspor Pencetak ke Samba</H2>
+
+{error?<P>Tak dapat mengekspor pencetak ke Samba\:</P>
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+<P>Rujuklah berkas <A HREF="/admin/log/error_log"
+TARGET="_blank">error_log</A> untuk informasi lebih lanjut.</P>:
+<P>Di halaman ini, Anda dapat mengekspor pencetak untuk Samba, sehingga
+klien Windows dapat mengakses pencetak-pencetak tersebut melalui ikon
+<VAR>Network Neighborhood</VAR> atau <VAR>Network Places</VAR> yang ada
+di desktop mereka. Namun, sebelumnya Anda harus memasang penggerak
+pencetak PostScript Windows seperti yang dijelaskan pada halaman
+manual <A HREF="/help/man-cupsaddsmb.html"
+TARGET="_blank">cupsaddsmb(8)</A>.</P>}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Pencetak:</TH>
+<TD>
+<SELECT NAME="EXPORT_NAME" SIZE="10" MULTIPLE>
+{[printer_name]<OPTION VALUE="{printer_name}"{export_all? SELECTED:{printer_export? SELECTED:}}>{printer_name}}
+</SELECT><BR>
+<INPUT TYPE="CHECKBOX" NAME="EXPORT_ALL"{export_all? CHECKED:}
+onChange="select_printers()"> Ekspor Semua Pencetak
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Nama Pengguna Samba:</TH>
+<TD><INPUT TYPE="TEXT" NAME="USERNAME" VALUE="{?USERNAME}"> (diperlukan)</TD>
+</TR>
+<TR>
+<TH CLASS="label">Sandi Samba:</TH>
+<TD><INPUT TYPE="PASSWORD" NAME="PASSWORD" VALUE=""> (diperlukan)</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Ekspor Pencetak ke Samba"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/id/samba-exported.tmpl b/templates/id/samba-exported.tmpl
new file mode 100644
index 000000000..8fa811100
--- /dev/null
+++ b/templates/id/samba-exported.tmpl
@@ -0,0 +1 @@
+<P>Pencetak berhasil diekspor ke Samba.</P>
diff --git a/templates/id/search.tmpl b/templates/id/search.tmpl
new file mode 100644
index 000000000..9dc2e5d54
--- /dev/null
+++ b/templates/id/search.tmpl
@@ -0,0 +1,10 @@
+<FORM ACTION="/{SECTION}/{?SEARCH_DEST}" METHOD="GET">
+{WHICH_JOBS?<INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{WHICH_JOBS}">:}
+{ORDER?<INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{ORDER}">:}
+
+<P ALIGN="CENTER"><B>Cari di
+{SEARCH_DEST?{SEARCH_DEST}:{SECTION=classes?Kelas:{SECTION=jobs?Tugas:Pencetak}}}:</B>
+<INPUT TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER="" AUTOSAVE="org.cups.{SECTION}" RESULTS="20"> <INPUT
+TYPE="SUBMIT" VALUE="Cari"> <INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="Bersihkan"></P>
+
+</FORM>
diff --git a/templates/id/set-printer-options-header.tmpl b/templates/id/set-printer-options-header.tmpl
new file mode 100644
index 000000000..017e2c475
--- /dev/null
+++ b/templates/id/set-printer-options-header.tmpl
@@ -0,0 +1,26 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Atur Opsi Baku untuk {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Kuiri Pencetak untuk Opsi Baku">:}
+
+<SCRIPT TYPE="text/javascript"><!--
+function update_paramtable(option)
+{
+ var cb = document.getElementById("select-" + option)
+ var paramstable = document.getElementById(option + "-params");
+ if (cb.value == "Custom")
+ paramstable.style.display = "table";
+ else
+ paramstable.style.display = "none";
+}
+--></SCRIPT>
+
+<H3 CLASS="title">{[group_id]
+<A HREF="#{group_id}">{group}</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</H3>
+
+<DIV CLASS="tabs">
diff --git a/templates/id/set-printer-options-trailer.tmpl b/templates/id/set-printer-options-trailer.tmpl
new file mode 100644
index 000000000..11adc7012
--- /dev/null
+++ b/templates/id/set-printer-options-trailer.tmpl
@@ -0,0 +1,16 @@
+</DIV>
+
+<SCRIPT TYPE="text/javascript"><!--
+// Hide custom options parameters for browsers that understand Javascript
+var paramtables = document.getElementsByName("paramtable");
+for (var i = 0; i < paramtables.length; i++)
+{
+ var opt = paramtables[i].id.substr(0, paramtables[i].id.lastIndexOf("-"));
+ var cb = document.getElementById("select-" + opt);
+ if (cb.value != "Custom")
+ paramtables[i].style.display = "none";
+}
+--></SCRIPT>
+</FORM>
+
+</DIV>
diff --git a/templates/id/subscription-added.tmpl b/templates/id/subscription-added.tmpl
new file mode 100644
index 000000000..70abc79f8
--- /dev/null
+++ b/templates/id/subscription-added.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>Subskripsi {subscription_name} telah berhasil ditambahkan.</P>
+
+</DIV>
diff --git a/templates/id/subscription-canceled.tmpl b/templates/id/subscription-canceled.tmpl
new file mode 100644
index 000000000..ba7b0e15e
--- /dev/null
+++ b/templates/id/subscription-canceled.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>Subskripsi #{notify_subscription_id} telah dibatalkan.</P>
+
+</DIV>
diff --git a/templates/id/test-page.tmpl b/templates/id/test-page.tmpl
new file mode 100644
index 000000000..5b1492ea1
--- /dev/null
+++ b/templates/id/test-page.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Cetak Halaman Uji pada {printer_name}</H2>
+
+<P>Halaman uji telah dikirim; ID tugas adalah <A HREF="/{SECTION}/{printer_name}">
+{printer_name}-{job_id}</A>.</P>
+
+</DIV>
diff --git a/templates/id/trailer.tmpl b/templates/id/trailer.tmpl
new file mode 100644
index 000000000..eb53dddb9
--- /dev/null
+++ b/templates/id/trailer.tmpl
@@ -0,0 +1,8 @@
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS dan logo CUPS adalah merek dagang dari
+<A HREF="http://www.apple.com">Apple Inc.</A> Hak Cipta CUPS adalah 2007-2011 Apple
+Inc. Semua hak terpelihara.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/templates/id/users.tmpl b/templates/id/users.tmpl
new file mode 100644
index 000000000..fe9107050
--- /dev/null
+++ b/templates/id/users.tmpl
@@ -0,0 +1,30 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
+
+<H2 CLASS="title">Pengguna yang Diperbolehkan Bagi {printer_name}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">Pengguna:</TH>
+<TD>
+<INPUT TYPE='TEXT' NAME='users' SIZE='60' VALUE='{?requesting_user_name_allowed}{?requesting_user_name_denied}'>
+<BR>
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-allowed' {requesting_user_name_allowed?checked:}>Perbolehkan pengguna ini untuk mencetak
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-denied' {requesting_user_name_denied?checked:}>Larang pengguna ini untuk mencetak
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>
+<INPUT TYPE="SUBMIT" VALUE="Atur Pengguna yang Diperbolehkan">
+</TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/it/add-class.tmpl b/templates/it/add-class.tmpl
new file mode 100644
index 000000000..cff0d45bc
--- /dev/null
+++ b/templates/it/add-class.tmpl
@@ -0,0 +1,40 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Aggiungi classe</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Nome:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Può contenere qualsiasi carattere stampabile eccetto "/", "#", e spazio)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Descrizione:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Descrizione esplicativa del tipo "HP LaserJet con Duplexer")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Posizione:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Posizione esplicativa del tipo "Laboratorio 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Membri:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Aggiungi classe"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/it/add-printer.tmpl b/templates/it/add-printer.tmpl
new file mode 100644
index 000000000..3bf0906fa
--- /dev/null
+++ b/templates/it/add-printer.tmpl
@@ -0,0 +1,43 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Aggiungi stampante</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{?current_make!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE" VALUE="{current_make}">:}
+{?current_make_and_model!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{current_make_and_model}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Nome:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?template_name}"><BR>
+<SMALL>(Può contenere qualsiasi carattere stampabile eccetto "/", "#", e spazio)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Descrizione:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_INFO}"><BR>
+<SMALL>(Descrizione esplicativa del tipo "HP LaserJet con Duplexer")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Posizione:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_LOCATION}"><BR>
+<SMALL>(Posizione esplicativa del tipo "Laboratorio 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Connessione:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Condivisione:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+Condividi la stampante</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Continua"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/it/add-rss-subscription.tmpl b/templates/it/add-rss-subscription.tmpl
new file mode 100644
index 000000000..c85e45f0f
--- /dev/null
+++ b/templates/it/add-rss-subscription.tmpl
@@ -0,0 +1,44 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
+
+<H2 CLASS="title">Aggiungi iscrizione RSS</H2>
+
+<TABLE SUMMARY="Aggiungi modulo d'iscrizione RSS">
+<TR>
+<TH CLASS="label">Nome:</TH>
+<TD COLSPAN="5"><INPUT TYPE="TEXT" NAME="SUBSCRIPTION_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?SUBSCRIPTION_NAME}"><BR>
+<SMALL>(Può contenere qualsiasi carattere eccetto spazio, "/", "?", e "#")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Coda:</TH>
+<TD COLSPAN="5"><SELECT NAME="PRINTER_URI" SIZE="10"><OPTION VALUE="#ALL#"{?PRINTER_URI=#ALL#? SELECTED:}>Tutte le code</OPTION>{[printer_name]<OPTION VALUE="{printer_uri_supported}"{?PRINTER_URI={printer_uri_supported}? SELECTED:}>{printer_name}</OPTION>}</SELECT></TD>
+</TR>
+<TR VALIGN="TOP">
+<TH CLASS="label">Eventi:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CREATED" {?EVENT_JOB_CREATED}>Stampa creata<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_COMPLETED" {?EVENT_JOB_COMPLETED}>Stampa completata<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_STOPPED" {?EVENT_JOB_STOPPED}>Stampa fermata<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CONFIG_CHANGED" {?EVENT_JOB_CONFIG_CHANGED}>Opzioni di stampa modificate</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_STOPPED" {?EVENT_PRINTER_STOPPED}>Coda fermata<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_ADDED" {?EVENT_PRINTER_ADDED}>Coda aggiunta<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_MODIFIED" {?EVENT_PRINTER_MODIFIED}>Coda modificata<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_DELETED" {?EVENT_PRINTER_DELETED}>Coda eliminata</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STARTED" {?EVENT_SERVER_STARTED}>Server avviato<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STOPPED" {?EVENT_SERVER_STOPPED}>Server fermato<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_RESTARTED" {?EVENT_SERVER_RESTARTED}>Server riavviato<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_AUDIT" {?EVENT_SERVER_AUDIT}>Controllo di sicurezza del server</TD>
+</TR>
+<TR>
+<TH CLASS="label">N. massimo di eventi nella fonte:</TH>
+<TD COLSPAN="5"><INPUT TYPE="NUMBER" NAME="MAX_EVENTS" SIZE="4" MAXLENGTH="4" VALUE="{MAX_EVENTS?{MAX_EVENTS}:20}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD COLSPAN="5"><INPUT TYPE="SUBMIT" VALUE="Aggiungi iscrizione RSS"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/it/admin.tmpl b/templates/it/admin.tmpl
new file mode 100644
index 000000000..355c51fcc
--- /dev/null
+++ b/templates/it/admin.tmpl
@@ -0,0 +1,110 @@
+<TABLE CLASS="indent" SUMMARY="Operazioni di amministrazione">
+<TR><TD VALIGN="TOP">
+
+<H2 CLASS="title">Stampanti</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Aggiungi stampante"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Trova nuove stampanti"></FORM>
+<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Gestisci stampanti"></FORM>
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Esporta stampanti a Samba"></FORM>:}
+</P>
+
+<H2 CLASS="title">Classi</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Aggiungi classe"></FORM>
+<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Gestisci classi"></FORM>
+</P>
+
+<H2 CLASS="title">Stampe</H2>
+
+<P>
+<FORM ACTION="/jobs/" METHDO="GET"><INPUT TYPE="SUBMIT" VALUE="Gestisci stampe"></FORM>
+</P>
+
+</TD><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TD VALIGN="TOP">
+
+<H2 CLASS="title">Server</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Modifica file di configurazione"></FORM>
+<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Mostra registro degli accessi"></FORM>
+<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Visualizza registro di errore"></FORM>
+<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Visualizza registro delle pagine"></FORM>
+</P>
+
+{SETTINGS_ERROR?<P>{SETTINGS_MESSAGE}</P>
+<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+
+{ADVANCEDSETTINGS?<P><B>Impostazioni del server\:</B></P>
+
+<P><A HREF="/admin/">Avanzate <SMALL>&#x25bc;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="HIDDEN" NAME="ADVANCEDSETTINGS" VALUE="YES">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Mostra stampanti condivise da altri sistemi<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protocolli\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_CUPS" {?browse_remote_cups}> CUPS
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_LDAP" {?browse_remote_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_SLP" {?browse_remote_slp}> SLP:}<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Condividi le stampanti connesse al sistema<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;N. massimo di client\:
+<INPUT TYPE="TEXT" NAME="MAX_CLIENTS" VALUE="{?max_clients}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protocolli\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_CUPS" {?browse_local_cups}> CUPS
+{HAVE_DNSSD?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_DNSSD" {?browse_local_dnssd}> DNS-SD:}
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_LDAP" {?browse_local_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_SLP" {?browse_local_slp}> SLP:}<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Consenti stampa da Internet<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="BROWSE_WEB_IF" {?browse_web_if}> Pubblica l'interfaccia web<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Consenti amministrazione remota<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Usa autenticazione Kerberos (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Consenti agli utenti di annullare ogni stampa (non solo le proprie)<BR>
+<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_HISTORY" {?preserve_job_history}> Mantieni lo storico delle stampe<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Numero di stampe\:
+<INPUT TYPE="TEXT" NAME="MAX_JOBS" VALUE="{?max_jobs}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_FILES" {?preserve_job_files}> Conserva i file di stampa<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Salva informazioni di debug per la risoluzione di problemi<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Dim. massima file di registro\:
+<INPUT TYPE="TEXT" NAME="MAX_LOG_SIZE" VALUE="{?max_log_size}" SIZE="6"></P>
+
+:<P><B>Impostazioni server:</B></P>
+
+<P><A HREF="/admin/?ADVANCEDSETTINGS=YES">Avanzate <SMALL>&#x25b6;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Mostra stampanti condivise da altri sistemi<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Condividi stampanti connesse al sistema<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Consenti la stampa da Internet<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Consenti amministrazione remota<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Utilizza autenticazione Kerberos (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Consenti agli utenti di annullare ogni stampa (non solo le proprie)<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Salva le informazioni di debug per la risoluzione di problemi</P>
+
+}
+<P><INPUT TYPE="SUBMIT" NAME="CHANGESETTINGS" VALUE="Cambia impostazioni"></P>
+
+</FORM>}
+
+</TD></TR>
+</TABLE>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Iscrizioni RSS</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Aggiungi iscrizione RSS"></FORM>
+</P>
+
+</DIV>
+
+{notify_subscription_id?<TABLE CLASS="list" SUMMARY="Iscrizioni RSS">
+<THEAD><TR><TH>Nome</TH><TH>Eventi</TH><TH>Nome coda</TH></TR></THEAD>
+<TBODY>{[notify_subscription_id]
+<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Annulla iscrizione RSS"></FORM>&nbsp;</TD><TD>{notify_events}</TD><TD NOWRAP>&nbsp;{notify_printer_name?{notify_printer_name}:Tutte le code}</TD></TR>}
+</TBODY>
+</TABLE>:}
diff --git a/templates/it/choose-device.tmpl b/templates/it/choose-device.tmpl
new file mode 100644
index 000000000..3420fdfe1
--- /dev/null
+++ b/templates/it/choose-device.tmpl
@@ -0,0 +1,54 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modifica {printer_name}:Aggiungi stampante}</H2>
+
+{CUPS_GET_DEVICES_DONE?:<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Busy Indicator"> Ricerca stampanti...</P>}
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+{op=add-printer?:<TR>
+<TH CLASS="label">Connessione attuale:</TH>
+<TD><INPUT TYPE="RADIO" NAME="DEVICE_URI" VALUE="{current_device_uri}" CHECKED>
+{current_device_uri}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Stampanti locali:</TH>
+<TD>
+{[device_uri]{device_class!network?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}}
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Stampanti di rete rilevate:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}:}}
+</TD>
+</TR>
+<TR>
+<TR>
+<TH CLASS="label">Altre stampante di reti:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?:<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+}:}}
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Continua"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/it/choose-make.tmpl b/templates/it/choose-make.tmpl
new file mode 100644
index 000000000..3bb4c78c4
--- /dev/null
+++ b/templates/it/choose-make.tmpl
@@ -0,0 +1,64 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Aggiungi stampante}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Nome:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Descrizione:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Posizione:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Connessione:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Condivisione:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+{?printer_is_shared=?Do Not:{?printer_is_shared=0?Do Not:}} Condividi questa stampante</TD>
+</TR>
+<TR>
+<TH CLASS="label">Crea:</TH>
+<TD>
+<SELECT NAME="PPD_MAKE" SIZE="10">
+{[ppd_make]<OPTION VALUE="{ppd_make}" {?current_make={ppd_make}?SELECTED:}>{ppd_make}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Continua"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>&nbsp;</TD>
+</TR>
+<TR>
+<TH CLASS="label">Or Provide a PPD File:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?Add Printer:Modify Printer}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/it/choose-model.tmpl b/templates/it/choose-model.tmpl
new file mode 100644
index 000000000..d7e935769
--- /dev/null
+++ b/templates/it/choose-model.tmpl
@@ -0,0 +1,60 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Aggiungi stampante}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Nome:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Descrizione:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Posizione:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Connessione:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Condivisione:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+{?printer_is_shared=?Do Not:{?printer_is_shared=0?Do Not:}} Condividi stampante</TD>
+</TR>
+<TR>
+<TH CLASS="label">Crea:</TH>
+<TD>{PPD_MAKE} <INPUT TYPE="SUBMIT" NAME="SELECT_MAKE" VALUE="Select Another Make/Manufacturer"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Modello:</TH>
+<TD>
+<SELECT NAME="PPD_NAME" SIZE="10">
+{op=add-printer?:<OPTION VALUE="__no_change__" SELECTED>Driver corrente - {current_make_and_model}</OPTION>:}
+{[ppd_name]<OPTION VALUE="{ppd_name}" {op=modify-printer?:{?current_make_and_model={ppd_make_and_model}?SELECTED:}}>{ppd_make_and_model} ({ppd_natural_language})
+}</SELECT>
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">O fornisci un file PPD:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?Add Printer:Modifica stampante}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/it/choose-serial.tmpl b/templates/it/choose-serial.tmpl
new file mode 100644
index 000000000..106393adb
--- /dev/null
+++ b/templates/it/choose-serial.tmpl
@@ -0,0 +1,52 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modifica {printer_name}:Aggiungi stampante}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Connessione:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Velocit&agrave;:</TH>
+<TD><SELECT NAME="BAUDRATE">
+{[baudrates]<OPTION {?baudrate={baudrates}?SELECTED:}>{baudrates}}
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Parit&agrave;:</TH>
+<TD><SELECT NAME="PARITY">
+<OPTION VALUE="none" {?parity=none?SELECTED:}>Ne
+<OPTION VALUE="even" {?parity=even?SELECTED:}>Even
+<OPTION VALUE="odd" {?parity=odd?SELECTED:}>Odd
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Data Bits:</TH>
+<TD><SELECT NAME="BITS">
+<OPTION {?bits=8?SELECTED:}>8
+<OPTION {?bits=7?SELECTED:}>7
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Flow Control:</TH>
+<TD><SELECT NAME="FLOW">
+<OPTION VALUE="none" {?flow=none?SELECTED:}>None
+<OPTION VALUE="soft" {?flow=soft?SELECTED:}>XON/XOFF (Software)
+<OPTION VALUE="hard" {?flow=hard?SELECTED:}>RTS/CTS (Hardware)
+<OPTION VALUE="dtrdsr" {?flow=dtrdsr?SELECTED:}>DTR/DSR (Hardware)
+</SELECT></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Continue"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/it/choose-uri.tmpl b/templates/it/choose-uri.tmpl
new file mode 100644
index 000000000..81b153a0a
--- /dev/null
+++ b/templates/it/choose-uri.tmpl
@@ -0,0 +1,44 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modifica {printer_name}:Aggiungi stampante}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Connection:</TH>
+<TD><INPUT TYPE="URL" SIZE="60" MAXLENGTH="1023" NAME="DEVICE_URI" VALUE="{current_device_uri?{current_device_uri}:{device_uri}}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>Esempi:
+<PRE>
+ http://hostname:631/ipp/
+ http://hostname:631/ipp/port1
+
+ ipp://hostname/ipp/
+ ipp://hostname/ipp/port1
+
+ lpd://hostname/queue
+
+ socket://hostname
+ socket://hostname:9100
+</PRE>
+
+<P>Vedere <A HREF="/help/network.html" TARGET="_blank">"Stampanti di
+rete"</A> per l'URI corretto da utilizzare la stampante.</P>
+
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Continua"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/it/class-added.tmpl b/templates/it/class-added.tmpl
new file mode 100644
index 000000000..fcccaa320
--- /dev/null
+++ b/templates/it/class-added.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Aggiungi classe</H2>
+
+<P>Class <A HREF="/classes/{printer_name}">{printer_name}</A> è stata aggiunta
+correttamente.
+
+</DIV>
diff --git a/templates/it/class-confirm.tmpl b/templates/it/class-confirm.tmpl
new file mode 100644
index 000000000..4e99f4574
--- /dev/null
+++ b/templates/it/class-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Elimina classe {printer_name}</H2>
+
+<P><B>Warning:</B> Sei sicuro di voler eliminare la classe
+{printer_name}?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Elimina classe"></FORM></P>
+
+</DIV>
diff --git a/templates/it/class-deleted.tmpl b/templates/it/class-deleted.tmpl
new file mode 100644
index 000000000..ce2365436
--- /dev/null
+++ b/templates/it/class-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Elimina classe {printer_name}</H2>
+
+<P>La classe {printer_name} è stata eliminata correttamente.
+
+</DIV>
diff --git a/templates/it/class-jobs-header.tmpl b/templates/it/class-jobs-header.tmpl
new file mode 100644
index 000000000..12a936ea9
--- /dev/null
+++ b/templates/it/class-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">Stampe</H3>
+</DIV>
diff --git a/templates/it/class-modified.tmpl b/templates/it/class-modified.tmpl
new file mode 100644
index 000000000..04d4c8490
--- /dev/null
+++ b/templates/it/class-modified.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modifica classe {printer_name}</H2>
+
+<P>La classe <A HREF="/classes/{printer_name}">{printer_name}</A> è stata
+modificata correttamente.
+
+</DIV>
diff --git a/templates/it/class.tmpl b/templates/it/class.tmpl
new file mode 100644
index 000000000..0089c9346
--- /dev/null
+++ b/templates/it/class.tmpl
@@ -0,0 +1,44 @@
+<DIV CLASS="indent">
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?Idle:{printer_state=4?Processing:Paused}},
+{printer_is_accepting_jobs=0?Rejecting Jobs:Accepting Jobs},
+{server_is_sharing_printers=0?Not:{printer_is_shared=0?Not:}} Shared{default_name={printer_name}?, Server Default:})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">Manutenzione</OPTION>
+<OPTION VALUE="print-test-page">Stampa pagina di prova</OPTION>
+{printer_state=5?<OPTION VALUE="start-class">Ripristina classe</OPTION>:<OPTION VALUE="stop-class">Sospendi classe</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Accetta stampe</OPTION>:<OPTION VALUE="reject-jobs">Rifiuta stampe</OPTION>}
+<OPTION VALUE="move-jobs">Sposta tutte le stampe</OPTION>
+<OPTION VALUE="purge-jobs">Annulla tuttte le stampe</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Vai" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="1">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">Amministrazione</OPTION>
+<OPTION VALUE="modify-class">Modifica classe</OPTION>
+<OPTION VALUE="delete-class">Elimina classe</OPTION>
+<OPTION VALUE="set-class-options">Imposta opzioni predefinite</OPTION>
+<OPTION VALUE="set-as-default">Imposta come predefiniti del server</OPTION>
+<OPTION VALUE="set-allowed-users">Imposta utenti autorizzati</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Vai" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Descrizione:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Posizione:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Membri:</TH><TD>{?member_uris=?None:{member_uris}}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Predefiniti:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:unknown}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/it/classes-header.tmpl b/templates/it/classes-header.tmpl
new file mode 100644
index 000000000..943537f89
--- /dev/null
+++ b/templates/it/classes-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?Nessuna classe:Mostrat{total=1?a:e} {#printer_name} di {total} class{total=1?e:i}}.</P> \ No newline at end of file
diff --git a/templates/it/classes.tmpl b/templates/it/classes.tmpl
new file mode 100644
index 000000000..bfa5bdf27
--- /dev/null
+++ b/templates/it/classes.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Elenco classi">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Nome coda <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Nome coda <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Descrizione</TH><TH>Posizione</TH><TH>Membri</TH><TH>Stato</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{?member_uris=?None:{member_uris}}</TD><TD>{printer_state=3?In attesa:{printer_state=4?Elaborazion in corso:Sospesa}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/it/command.tmpl b/templates/it/command.tmpl
new file mode 100644
index 000000000..80d44f634
--- /dev/null
+++ b/templates/it/command.tmpl
@@ -0,0 +1,12 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{title} su {printer_name}</H2>
+
+<P>{job_state>5?:<IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16"
+ALIGN="ABSMIDDLE" ALT="Indicatore di occupato"> }Printer command job
+{job_state=3?pendente:{job_state=4?held:
+{job_state=5?elaborazione in corso:{job_state=6?fermata:
+{job_state=7?annullata:{job_state=8?aborted:completed}}}}}}{job_state=9?:{job_printer_state_message?,
+<EM>"{job_printer_state_message}"</EM>:}}</P>
+
+</DIV>
diff --git a/templates/it/edit-config.tmpl b/templates/it/edit-config.tmpl
new file mode 100644
index 000000000..c8d8ea8a9
--- /dev/null
+++ b/templates/it/edit-config.tmpl
@@ -0,0 +1,24 @@
+<SCRIPT TYPE="text/javascript">
+function reset_config()
+{
+ document.cups.CUPSDCONF.value = "{?cupsdconf_default}";
+}
+</SCRIPT>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modifica file di configurazione</H2>
+
+<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+
+<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
+
+<P><INPUT TYPE="SUBMIT" NAME="SAVECHANGES" VALUE="Salva modifiche">
+<INPUT TYPE="BUTTON" VALUE="Utilizza file di configurazione predefinito"
+onClick="reset_config();"></P>
+
+</FORM>
+
+</DIV>
diff --git a/templates/it/error-op.tmpl b/templates/it/error-op.tmpl
new file mode 100644
index 000000000..c6cdfa80e
--- /dev/null
+++ b/templates/it/error-op.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{?title} {?printer_name} Errore</H2>
+
+<P>Errore:</P>
+
+<BLOCKQUOTE>Operazione sconosciuta "{op}"!</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/it/error.tmpl b/templates/it/error.tmpl
new file mode 100644
index 000000000..b0e7a4b37
--- /dev/null
+++ b/templates/it/error.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{?title} {?printer_name} Errore</H2>
+
+<P>{?message?{message}:Error:}</P>
+
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/it/help-header.tmpl b/templates/it/help-header.tmpl
new file mode 100644
index 000000000..39c39e532
--- /dev/null
+++ b/templates/it/help-header.tmpl
@@ -0,0 +1,50 @@
+<DIV CLASS="indent">
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET">
+{TOPIC?<INPUT TYPE="HIDDEN" NAME="TOPIC" VALUE="{TOPIC}">:}
+
+<P ALIGN="CENTER"><B>Cerca in
+{HELPTITLE?{HELPTITLE}:{TOPIC?{TOPIC}:Tutti i documenti}}:</B> <INPUT
+TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER=""
+AUTOSAVE="org.cups.help" RESULTS="20">
+<INPUT TYPE="SUBMIT" NAME="SEARCH" VALUE="Cerca">
+<INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="Cancella"></P>
+
+</FORM>
+
+<!-- Bookmarks -->
+<DIV CLASS="sidebar"><TABLE CLASS="inset" SUMMARY="Contenuti">
+<TR><TD>
+
+<H3 CLASS="title">Documenti di guida in linea</H3>
+
+<P CLASS="l0"><A HREF="/help/{QUERY??QUERY={QUERY}:}">Tutti i documenti</A></P>
+<HR>
+
+{[BMTEXT]<P CLASS="l{BMINDENT}"><A HREF="{BMLINK}">{BMTEXT}</A></P>
+}
+</TD></TR>
+</TABLE></DIV>
+
+{QUERY?<P>Cerca risultati in {HELPFILE?{HELPTITLE}:{TOPIC?{TOPIC}:Tutti i documenti}}\:</P>
+{QTEXT?<UL>
+{[QTEXT]<LI><A HREF="{QLINK}">{QTEXT}</A>{QPTEXT? (in <I><A HREF="{QPLINK}">{QPTEXT}</A></I>):}</LI>}
+{QTEXT?</UL>:}
+:<P>Nessuna corrispondenza trovata.</P>}
+<HR NOSHADE>:}
+{HELPTITLE?<H1>{HELPTITLE}</H1>
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="PRINTABLE" VALUE="YES"><INPUT TYPE="SUBMIT" VALUE="Visualizza versione stampabile"></FORM>:
+
+<H1>Guida in linea</H1>
+
+<P>Questa è l'interfaccia di guida in linea di CUPS. Inserisci in alto i termini da ricercare
+o fai clic su qualsiasi collegamento della documentazione per visualizzare
+informazioni della guida in linea.</P>
+
+<P>Se sei nuovo di CUPS, leggi la pagina "<a
+href="/help/overview.html">Panoramica di CUPS</a>". Gli utenti esperti
+dovrebbero leggere la pagina "<a href="/help/whatsnew.html">Cosa c'è di nuovo in CUPS
+1.4</a>".</P>
+
+<P>La <A HREF="http://www.cups.org/">pagina principale di CUPS</A> fornisce
+inoltre molte risorse tra le quali forum di discussione per gli utenti, risposte
+alle domande frequenti, e un modulo per segnalare bug e richiede nuove funzionalità.</P>}
diff --git a/templates/it/help-printable.tmpl b/templates/it/help-printable.tmpl
new file mode 100644
index 000000000..2463c1630
--- /dev/null
+++ b/templates/it/help-printable.tmpl
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{HELPTITLE}</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups-printable.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
diff --git a/templates/it/help-trailer.tmpl b/templates/it/help-trailer.tmpl
new file mode 100644
index 000000000..4c1ebed85
--- /dev/null
+++ b/templates/it/help-trailer.tmpl
@@ -0,0 +1 @@
+</DIV>
diff --git a/templates/it/job-cancel.tmpl b/templates/it/job-cancel.tmpl
new file mode 100644
index 000000000..766881ea7
--- /dev/null
+++ b/templates/it/job-cancel.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Annulla la stampa {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">La stampa {job_id}</A> è stata annullata.
+
+</DIV>
diff --git a/templates/it/job-hold.tmpl b/templates/it/job-hold.tmpl
new file mode 100644
index 000000000..ac2d8199c
--- /dev/null
+++ b/templates/it/job-hold.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Blocca la stampa {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">La stampa {job_id}</A> è stata bloccata.
+
+</DIV>
diff --git a/templates/it/job-move.tmpl b/templates/it/job-move.tmpl
new file mode 100644
index 000000000..0a52ba2f2
--- /dev/null
+++ b/templates/it/job-move.tmpl
@@ -0,0 +1,27 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
+
+<H2 CLASS="title">{job_id?Sposta la stampa {job_id}:Sposta tutte le stampe}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">Nuova destinazione:</TH>
+<TD>
+<SELECT NAME="JOB_PRINTER_URI" SIZE="10">
+{[job_printer_uri]<OPTION VALUE="{job_printer_uri}">{job_printer_name}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{job_id?Sposta stampa:Sposta stampe}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+
+</DIV>
diff --git a/templates/it/job-moved.tmpl b/templates/it/job-moved.tmpl
new file mode 100644
index 000000000..98be4fe7d
--- /dev/null
+++ b/templates/it/job-moved.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{job_id?Sposta stampa {job_id}:Sposta tutte le stampe}</H2>
+
+<P>{job_id?<A HREF="/jobs/{job_id}">La stampa {job_id}</A>:Tutte le stampe} {job_id?è stata:sono state} spostat{job_id?a:e} su
+<A HREF="/{is_class?classes:printers}/{job_printer_name}">{job_printer_name}</A>.</P>
+
+</DIV>
diff --git a/templates/it/job-release.tmpl b/templates/it/job-release.tmpl
new file mode 100644
index 000000000..c6520fdd5
--- /dev/null
+++ b/templates/it/job-release.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Rilascia la stampa {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">La stampa {job_id}</A> è stata rilasciata.
+
+</DIV>
diff --git a/templates/it/job-restart.tmpl b/templates/it/job-restart.tmpl
new file mode 100644
index 000000000..59d9aa6b5
--- /dev/null
+++ b/templates/it/job-restart.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ripeti la stampa {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">La stampa {job_id}</A> è stata riavviata.
+
+</DIV>
diff --git a/templates/it/jobs-header.tmpl b/templates/it/jobs-header.tmpl
new file mode 100644
index 000000000..38538d12f
--- /dev/null
+++ b/templates/it/jobs-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">{?which_jobs=?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Mostra stampe attive"></FORM>}
+{?which_jobs=completed?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="completed"><INPUT TYPE="SUBMIT" VALUE="Mostra stampe completate"></FORM>}
+{?which_jobs=all?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="all"><INPUT TYPE="SUBMIT" VALUE="Mostra tutte le stampe"></FORM>}</DIV>
+
+<P ALIGN="CENTER">{total=0?Nessuna stampa:Mostrat{total=1?a:e} {#job_id} di {total} stamp{total=1?a:e} {?which_jobs=?attiva:{which_jobs=all?:completata}} }.</P>
diff --git a/templates/it/jobs.tmpl b/templates/it/jobs.tmpl
new file mode 100644
index 000000000..494c1eebd
--- /dev/null
+++ b/templates/it/jobs.tmpl
@@ -0,0 +1,37 @@
+{#job_id=0?:
+<TABLE CLASS="list" SUMMARY="Elenco stampe">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> ID <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> ID <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Nome</TH><TH>Utente</TH><TH>Dimensione</TH><TH>Pagine</TH><TH>Stato</TH><TH>Controllo</TH></TR>
+</THEAD>
+<TBODY>
+{[job_id]
+<TR VALIGN="TOP">
+<TD><A HREF="{job_printer_uri}">{job_printer_name}</A>-{job_id}&nbsp;</TD>
+<TD>{?job_name=?Unknown:{job_name}}&nbsp;</TD>
+<TD>{job_originating_user_name}&nbsp;</TD>
+<TD>{job_k_octets}k&nbsp;</TD>
+<TD>{job_media_sheets_completed=0?Unknown:{?job_media_sheets_completed}}&nbsp;</TD>
+<TD>{job_state=3?pending since<BR>{time_at_creation}:{job_state=4?held since<BR>{time_at_creation}:
+{job_state=5?processing since<BR>{time_at_processing}:{job_state=6?stopped:
+{job_state=7?canceled at<BR>{time_at_completed}:{job_state=8?aborted:completed at<BR>{time_at_completed}}}}}}}&nbsp;{job_printer_state_message?<BR>
+<EM>"{job_printer_state_message}"</EM>:}</TD>
+<TD>
+{job_preserved>0?{job_state>5?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Ripeti stampa"></FORM>:}:}
+{job_state=4?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Release Job"></FORM>:}
+{job_state=3?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Hold Job"></FORM>:}
+{job_state<7?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Annulla stampa"></FORM>
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Sposta stampa"></FORM>:}
+&nbsp;</TD>
+</TR>
+}
+</TBODY>
+</TABLE>
+}
diff --git a/templates/it/list-available-printers.tmpl b/templates/it/list-available-printers.tmpl
new file mode 100644
index 000000000..147d6103c
--- /dev/null
+++ b/templates/it/list-available-printers.tmpl
@@ -0,0 +1,11 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Stampanti disponibili</H2>
+
+{#device_uri=0?<P>Nessuna stampante trovata.</P>
+:<UL>{[device_uri]
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Stampante locale"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Aggiungi stampante"></FORM>
+{device_make_and_model} ({device_info})</LI>
+}</UL>}
+
+</DIV>
diff --git a/templates/it/modify-class.tmpl b/templates/it/modify-class.tmpl
new file mode 100644
index 000000000..065f2b91a
--- /dev/null
+++ b/templates/it/modify-class.tmpl
@@ -0,0 +1,34 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modifica classe {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Descrizione:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Posizione:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Membri:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Modifica classe"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/it/modify-printer.tmpl b/templates/it/modify-printer.tmpl
new file mode 100644
index 000000000..a6303f298
--- /dev/null
+++ b/templates/it/modify-printer.tmpl
@@ -0,0 +1,38 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modifica {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Descrizione:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Descrizione esplicativa del tipo "HP LaserJet con Duplexer")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Posizione:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Posizione esplicativa del tipo "Laboratorio 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Connessione:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Condivisione:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+Condividi stampante</TD>
+</TR>
+<TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Continua"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/it/norestart.tmpl b/templates/it/norestart.tmpl
new file mode 100644
index 000000000..924d533f2
--- /dev/null
+++ b/templates/it/norestart.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Cambia impostazioni</H2>
+
+<P>Il server non è stato riavviato poiché nessuna modifica è stata apportata alla configurazione...</P>
+
+</DIV>
diff --git a/templates/it/option-boolean.tmpl b/templates/it/option-boolean.tmpl
new file mode 100644
index 000000000..e832ee102
--- /dev/null
+++ b/templates/it/option-boolean.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD>
+{[choices]<INPUT TYPE="RADIO" NAME="{keyword-1}" {choices={defchoice-1}?CHECKED:} VALUE="{choices}">{text}}
+</TD>
+</TR>
diff --git a/templates/it/option-conflict.tmpl b/templates/it/option-conflict.tmpl
new file mode 100644
index 000000000..6d3b97538
--- /dev/null
+++ b/templates/it/option-conflict.tmpl
@@ -0,0 +1,7 @@
+<P><B>Errore:</B> Le seguenti opzioni sono in conflitto:</P>
+
+<UL>
+{[ckeyword]<LI><A HREF="#{ckeyword}">{ckeytext}</A></LI>
+}</UL>
+
+<P>Cambia una o più opzioni per risolvere i conflitti.</P>
diff --git a/templates/it/option-header.tmpl b/templates/it/option-header.tmpl
new file mode 100644
index 000000000..464726a50
--- /dev/null
+++ b/templates/it/option-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="tab" ID="{group_id}">
+
+<H3 ALIGN="CENTER">{group}</H3>
+
+<TABLE WIDTH="100%">
diff --git a/templates/it/option-pickmany.tmpl b/templates/it/option-pickmany.tmpl
new file mode 100644
index 000000000..0da75e5d2
--- /dev/null
+++ b/templates/it/option-pickmany.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" MULTIPLE SIZE="10">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT></TD>
+</TR>
diff --git a/templates/it/option-pickone.tmpl b/templates/it/option-pickone.tmpl
new file mode 100644
index 000000000..c21fc71ba
--- /dev/null
+++ b/templates/it/option-pickone.tmpl
@@ -0,0 +1,18 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" ID="select-{keyword}" ONCHANGE="update_paramtable('{keyword}')">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT>
+{iscustom=1?<TABLE NAME="paramtable" id="{keyword}-params">{[params]
+<TR><TH CLASS="sublabel">{paramtext}:</TH>
+<TD>{params=Units?<SELECT NAME="{keyword-1}.{params}">
+<OPTION VALUE="pt"{paramvalue=pt? SELECTED:}>Punti</OPTION>
+<OPTION VALUE="mm"{paramvalue=mm? SELECTED:}>Millimetri</OPTION>
+<OPTION VALUE="cm"{paramvalue=cm? SELECTED:}>Centimetri</OPTION>
+<OPTION VALUE="in"{paramvalue=in? SELECTED:}>Pollici</OPTION>
+<OPTION VALUE="ft"{paramvalue=ft? SELECTED:}>Piedi</OPTION>
+<OPTION VALUE="m"{paramvalue=m? SELECTED:}>Metri</OPTION>
+</SELECT>:<INPUT TYPE="{inputtype}" NAME="{keyword-1}.{params}" VALUE="{paramvalue}">}</TD></TR>
+}</TABLE>
+</TD>:}
+</TR>
diff --git a/templates/it/option-trailer.tmpl b/templates/it/option-trailer.tmpl
new file mode 100644
index 000000000..ddbde0bc9
--- /dev/null
+++ b/templates/it/option-trailer.tmpl
@@ -0,0 +1,5 @@
+</TABLE>
+
+<P ALIGN="CENTER"><INPUT TYPE="SUBMIT" VALUE="Imposta opzioni predefinite"></P>
+
+</DIV> \ No newline at end of file
diff --git a/templates/it/pager.tmpl b/templates/it/pager.tmpl
new file mode 100644
index 000000000..019646f95
--- /dev/null
+++ b/templates/it/pager.tmpl
@@ -0,0 +1,6 @@
+<TABLE CLASS="inset" SUMMARY="Barra di paginazione">
+<TR>
+ <TD WIDTH="50%">{PREV?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{PREV}"><INPUT TYPE="SUBMIT" VALUE="&#x25c0; Mostra precedente"></FORM>:&nbsp;}</TD>
+ <TD WIDTH="50%" ALIGN="RIGHT">{NEXT?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{NEXT}"><INPUT TYPE="SUBMIT" VALUE="Mostra successiva &#x25b6;"></FORM>:&nbsp;}</TD>
+</TR>
+</TABLE>
diff --git a/templates/it/printer-accept.tmpl b/templates/it/printer-accept.tmpl
new file mode 100644
index 000000000..bbf718ae5
--- /dev/null
+++ b/templates/it/printer-accept.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Accetta stampe su {is_class?Class:Printer} {printer_name}</H2>
+
+<P>{is_class?Class:Printer} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+accetta stampe.</P>
+
+</DIV>
diff --git a/templates/it/printer-added.tmpl b/templates/it/printer-added.tmpl
new file mode 100644
index 000000000..682dfa7e9
--- /dev/null
+++ b/templates/it/printer-added.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Aggiungi stampante</H2>
+
+<P>Printer <A HREF="/printers/{printer_name}">{printer_name}</A> è stata aggiunta correttamente.
+
+</DIV>
diff --git a/templates/it/printer-configured.tmpl b/templates/it/printer-configured.tmpl
new file mode 100644
index 000000000..cfcbf6506
--- /dev/null
+++ b/templates/it/printer-configured.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Imposta le opzioni predefinite per {printer_name}</H2>
+
+<P>{OP=set-class-options?Class <A HREF="/classes/{printer_name}">:Printer <A HREF="/printers/{printer_name}">}{printer_name}</A>
+default options have been set successfully.
+
+</DIV>
diff --git a/templates/it/printer-confirm.tmpl b/templates/it/printer-confirm.tmpl
new file mode 100644
index 000000000..e23071c9f
--- /dev/null
+++ b/templates/it/printer-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Elimina stampante {printer_name}</H2>
+
+<P><B>Avviso:</B> Sei sicuro di voler eliminare la stampante
+{printer_name}?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Elimina stampante"></FORM></P>
+
+</DIV>
diff --git a/templates/it/printer-default.tmpl b/templates/it/printer-default.tmpl
new file mode 100644
index 000000000..fe44138fb
--- /dev/null
+++ b/templates/it/printer-default.tmpl
@@ -0,0 +1,12 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Imposta {is_class?Class:Printer} {printer_name} come predefinita</H2>
+
+<P>{is_class?Class:Printer} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+è la stampante predefinita su questo server.</P>
+
+<BLOCKQUOTE><B>Note:</B> Qualsiasi utente predefinito impostato attraverso
+il comando <TT>lpoptions</TT> scavalcherà questa impostazione predefinita.</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/it/printer-deleted.tmpl b/templates/it/printer-deleted.tmpl
new file mode 100644
index 000000000..4698805d8
--- /dev/null
+++ b/templates/it/printer-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Elimina la stampante {printer_name}</H2>
+
+<P>La stampante {printer_name} è stata eliminata correttamente.
+
+</DIV>
diff --git a/templates/it/printer-jobs-header.tmpl b/templates/it/printer-jobs-header.tmpl
new file mode 100644
index 000000000..12a936ea9
--- /dev/null
+++ b/templates/it/printer-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">Stampe</H3>
+</DIV>
diff --git a/templates/it/printer-modified.tmpl b/templates/it/printer-modified.tmpl
new file mode 100644
index 000000000..2a34e89d8
--- /dev/null
+++ b/templates/it/printer-modified.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modifica la stampante {printer_name}</H2>
+
+<P>La stampante <A HREF="/printers/{printer_name}">{printer_name}</A> è stata
+modificata correttamente.
+
+</DIV> \ No newline at end of file
diff --git a/templates/it/printer-purge.tmpl b/templates/it/printer-purge.tmpl
new file mode 100644
index 000000000..8cf7c1461
--- /dev/null
+++ b/templates/it/printer-purge.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Purge Jobs On {is_class?Class:Printer} {printer_name}</H2>
+
+<P>{is_class?Class:Printer} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+has been purged of all jobs.</P>
+
+</DIV> \ No newline at end of file
diff --git a/templates/it/printer-reject.tmpl b/templates/it/printer-reject.tmpl
new file mode 100644
index 000000000..02f4ce950
--- /dev/null
+++ b/templates/it/printer-reject.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Rifiuta stampe su {is_class?Class:Printer} {printer_name}</H2>
+
+<P>{is_class?Class:Printer} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+non accetta alcuna stampa.</P>
+
+</DIV>
diff --git a/templates/it/printer-start.tmpl b/templates/it/printer-start.tmpl
new file mode 100644
index 000000000..b7f2edc5f
--- /dev/null
+++ b/templates/it/printer-start.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ripristina {is_class?Class:Printer} {printer_name}</H2>
+
+<P>{is_class?Class:Printer} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+è stata ripristinata.</P>
+
+</DIV> \ No newline at end of file
diff --git a/templates/it/printer-stop.tmpl b/templates/it/printer-stop.tmpl
new file mode 100644
index 000000000..ef091180c
--- /dev/null
+++ b/templates/it/printer-stop.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Sospendi {is_class?Class:Printer} {printer_name}</H2>
+
+<P>{is_class?Class:Printer} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+è stata sospesa.</P>
+
+</DIV> \ No newline at end of file
diff --git a/templates/it/printer.tmpl b/templates/it/printer.tmpl
new file mode 100644
index 000000000..78fc08bea
--- /dev/null
+++ b/templates/it/printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?Idle:{printer_state=4?Processing:Paused}},
+{printer_is_accepting_jobs=0?Rejecting Jobs:Accepting Jobs},
+{server_is_sharing_printers=0?Not:{printer_is_shared=0?Not:}} Shared{default_name={printer_name}?, Server Default:})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">Maintenance</OPTION>
+<OPTION VALUE="print-test-page">Print Test Page</OPTION>
+{printer_commands~.*Clean.*?<OPTION VALUE="clean-print-heads">Clean Print Heads</OPTION>:}
+{printer_commands~.*PrintSelfTestPage.*?<OPTION VALUE="print-self-test-page">Print Self Test Page</OPTION>:}
+{printer_state=5?<OPTION VALUE="start-printer">Resume Printer</OPTION>:<OPTION VALUE="stop-printer">Pause Printer</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Accept Jobs</OPTION>:<OPTION VALUE="reject-jobs">Reject Jobs</OPTION>}
+<OPTION VALUE="move-jobs">Move All Jobs</OPTION>
+<OPTION VALUE="purge-jobs">Cancel All Jobs</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">Administration</OPTION>
+<OPTION VALUE="modify-printer">Modify Printer</OPTION>
+<OPTION VALUE="delete-printer">Delete Printer</OPTION>
+<OPTION VALUE="set-printer-options">Set Default Options</OPTION>
+<OPTION VALUE="set-as-default">Set As Server Default</OPTION>
+<OPTION VALUE="set-allowed-users">Set Allowed Users</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Description:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Location:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Driver:</TH><TD>{printer_make_and_model} ({color_supported=1?color:grayscale}{sides_supported?, 2-sided printing:})<BR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Connection:</TH><TD>{device_uri}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Defaults:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:unknown}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV> \ No newline at end of file
diff --git a/templates/it/printers-header.tmpl b/templates/it/printers-header.tmpl
new file mode 100644
index 000000000..e10112df7
--- /dev/null
+++ b/templates/it/printers-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?Nessuna stampante:Mostrat{total=1?a:e} {#printer_name} di {total} stampant{total=1?e:i}}.</P>
diff --git a/templates/it/printers.tmpl b/templates/it/printers.tmpl
new file mode 100644
index 000000000..87efb6d96
--- /dev/null
+++ b/templates/it/printers.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Elenco stampanti">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Nome coda <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Nome coda <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Descrizione</TH><TH>Posizione</TH><TH>Marca e modello</TH><TH>Stato</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{printer_make_and_model}</TD><TD>{printer_state=3?Idle:{printer_state=4?Processing:Paused}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/it/restart.tmpl b/templates/it/restart.tmpl
new file mode 100644
index 000000000..3d6424867
--- /dev/null
+++ b/templates/it/restart.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Cambia impostazioni</H2>
+
+<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Indicatore di occupato"> Attendi il riavvio del server...</P>
+
+</DIV>
diff --git a/templates/it/samba-export.tmpl b/templates/it/samba-export.tmpl
new file mode 100644
index 000000000..bce7469d0
--- /dev/null
+++ b/templates/it/samba-export.tmpl
@@ -0,0 +1,54 @@
+<SCRIPT TYPE="text/javascript"><!--
+function select_printers() {
+ var list = document.export_samba.EXPORT_NAME;
+ var sel = document.export_samba.EXPORT_ALL.checked;
+
+ for (i = 0; i < list.length; i ++) {
+ list.options[i].selected = sel;
+ }
+}
+--></SCRIPT>
+
+<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
+
+<H2 CLASS="title">Esporta stampanti a Samba</H2>
+
+{error?<P>Impossibile esportare stampanti a Samba\:</P>
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+<P>Consulta il file <A HREF="/admin/log/error_log"
+TARGET="_blank">error_log</A> per ulteriori informazioni.</P>:
+<P>Questa pagina ti consente di esportare stampanti a Samba in modo che
+i client Windows possano accedervi dalle icone <VAR>Risorse di rete</VAR>
+sui loro desktop. Devi installare preventivamente i driver per stampanti
+Windows PostScript come descritto nella pagina di manuale <A
+HREF="/help/man-cupsaddsmb.html"
+TARGET="_blank">cupsaddsmb(8)</A>.</P>}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Stampanti:</TH>
+<TD>
+<SELECT NAME="EXPORT_NAME" SIZE="10" MULTIPLE>
+{[printer_name]<OPTION VALUE="{printer_name}"{export_all? SELECTED:{printer_export? SELECTED:}}>{printer_name}}
+</SELECT><BR>
+<INPUT TYPE="CHECKBOX" NAME="EXPORT_ALL"{export_all? CHECKED:}
+onChange="select_printers()"> Esporta tutte le stampanti
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Nome utente Samba:</TH>
+<TD><INPUT TYPE="TEXT" NAME="USERNAME" VALUE="{?USERNAME}"> (richiesto)</TD>
+</TR>
+<TR>
+<TH CLASS="label">Password Samba:</TH>
+<TD><INPUT TYPE="PASSWORD" NAME="PASSWORD" VALUE=""> (richiesto)</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Esporta stampanti a Samba"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/it/samba-exported.tmpl b/templates/it/samba-exported.tmpl
new file mode 100644
index 000000000..d75f2d821
--- /dev/null
+++ b/templates/it/samba-exported.tmpl
@@ -0,0 +1 @@
+<P>Stampanti esportate a samba correttamente.</P>
diff --git a/templates/it/search.tmpl b/templates/it/search.tmpl
new file mode 100644
index 000000000..c71a9dd73
--- /dev/null
+++ b/templates/it/search.tmpl
@@ -0,0 +1,10 @@
+<FORM ACTION="/{SECTION}/{?SEARCH_DEST}" METHOD="GET">
+{WHICH_JOBS?<INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{WHICH_JOBS}">:}
+{ORDER?<INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{ORDER}">:}
+
+<P ALIGN="CENTER"><B>Cerca in
+{SEARCH_DEST?{SEARCH_DEST}:{SECTION=classes?Classi:{SECTION=jobs?Stampe:Stampanti}}}:</B>
+<INPUT TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER="" AUTOSAVE="org.cups.{SECTION}" RESULTS="20"> <INPUT
+TYPE="SUBMIT" VALUE="Cerca"> <INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="Cancella"></P>
+
+</FORM>
diff --git a/templates/it/set-printer-options-header.tmpl b/templates/it/set-printer-options-header.tmpl
new file mode 100644
index 000000000..b0867cedb
--- /dev/null
+++ b/templates/it/set-printer-options-header.tmpl
@@ -0,0 +1,26 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Imposta opzioni predefinite per {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Interroga stampante per opzioni predefinite">:}
+
+<SCRIPT TYPE="text/javascript"><!--
+function update_paramtable(option)
+{
+ var cb = document.getElementById("select-" + option)
+ var paramstable = document.getElementById(option + "-params");
+ if (cb.value == "Custom")
+ paramstable.style.display = "table";
+ else
+ paramstable.style.display = "none";
+}
+--></SCRIPT>
+
+<H3 CLASS="title">{[group_id]
+<A HREF="#{group_id}">{group}</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</H3>
+
+<DIV CLASS="tabs">
diff --git a/templates/it/set-printer-options-trailer.tmpl b/templates/it/set-printer-options-trailer.tmpl
new file mode 100644
index 000000000..11adc7012
--- /dev/null
+++ b/templates/it/set-printer-options-trailer.tmpl
@@ -0,0 +1,16 @@
+</DIV>
+
+<SCRIPT TYPE="text/javascript"><!--
+// Hide custom options parameters for browsers that understand Javascript
+var paramtables = document.getElementsByName("paramtable");
+for (var i = 0; i < paramtables.length; i++)
+{
+ var opt = paramtables[i].id.substr(0, paramtables[i].id.lastIndexOf("-"));
+ var cb = document.getElementById("select-" + opt);
+ if (cb.value != "Custom")
+ paramtables[i].style.display = "none";
+}
+--></SCRIPT>
+</FORM>
+
+</DIV>
diff --git a/templates/it/subscription-added.tmpl b/templates/it/subscription-added.tmpl
new file mode 100644
index 000000000..baec73dec
--- /dev/null
+++ b/templates/it/subscription-added.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>L'iscrizione {subscription_name} è stata aggiunta correttamente.</P>
+
+</DIV>
diff --git a/templates/it/subscription-canceled.tmpl b/templates/it/subscription-canceled.tmpl
new file mode 100644
index 000000000..b8a94aa13
--- /dev/null
+++ b/templates/it/subscription-canceled.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>L'iscrizione #{notify_subscription_id} è stata annullata.</P>
+
+</DIV>
diff --git a/templates/it/test-page.tmpl b/templates/it/test-page.tmpl
new file mode 100644
index 000000000..409ebf617
--- /dev/null
+++ b/templates/it/test-page.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Stampa pagina di prova su {printer_name}</H2>
+
+<P>Pagina di prova inviata; l'ID della stampa è <A HREF="/{SECTION}/{printer_name}">
+{printer_name}-{job_id}</A>.</P>
+
+</DIV>
diff --git a/templates/it/trailer.tmpl b/templates/it/trailer.tmpl
new file mode 100644
index 000000000..303b5b86b
--- /dev/null
+++ b/templates/it/trailer.tmpl
@@ -0,0 +1,8 @@
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS e il logo CUPS sono marchi di
+<A HREF="http://www.apple.com">Apple Inc.</A> CUPS è un copyright 2007-2011 Apple
+Inc. Tutti i diritti sono riservati.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/templates/it/users.tmpl b/templates/it/users.tmpl
new file mode 100644
index 000000000..34d8adb10
--- /dev/null
+++ b/templates/it/users.tmpl
@@ -0,0 +1,30 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
+
+<H2 CLASS="title">Utenti autorizzati per {printer_name}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">Utenti:</TH>
+<TD>
+<INPUT TYPE='TEXT' NAME='users' SIZE='60' VALUE='{?requesting_user_name_allowed}{?requesting_user_name_denied}'>
+<BR>
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-allowed' {requesting_user_name_allowed?checked:}>Consenti a questi utenti di stampare
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-denied' {requesting_user_name_denied?checked:}>Vieta a questi utenti di stampare
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>
+<INPUT TYPE="SUBMIT" VALUE="Imposta utenti autorizzati">
+</TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/ja/add-class.tmpl b/templates/ja/add-class.tmpl
new file mode 100644
index 000000000..11108ccfe
--- /dev/null
+++ b/templates/ja/add-class.tmpl
@@ -0,0 +1,40 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">クラスã®è¿½åŠ </H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">åå‰:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>("/"ã€"#"ã€ã‚¹ãƒšãƒ¼ã‚¹ã‚’除ã文字をå«ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">説明:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>("HP LaserJet with Duplexer" ã®ã‚ˆã†ã«äººãŒèª­ã¿ã‚„ã™ã„説明)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">場所:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>("Lab 1" ã®ã‚ˆã†ã«äººãŒèª­ã¿ã‚„ã™ã„場所)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">メンãƒãƒ¼:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="クラスã®è¿½åŠ "></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/ja/add-printer.tmpl b/templates/ja/add-printer.tmpl
new file mode 100644
index 000000000..f054254aa
--- /dev/null
+++ b/templates/ja/add-printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">æ–°ã—ã„プリンターã®è¿½åŠ </H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+{?current_make!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE" VALUE="{current_make}">:}
+{?current_make_and_model!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{current_make_and_model}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">åå‰:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?template_name}"><BR>
+<SMALL>("/"ã€"#"ã€ã‚¹ãƒšãƒ¼ã‚¹ã‚’除ã文字をå«ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">説明:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_INFO}"><BR>
+<SMALL>("HP LaserJet with Duplexer" ã®ã‚ˆã†ã«äººãŒèª­ã¿ã‚„ã™ã„説明)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">場所:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_LOCATION}"><BR>
+<SMALL>("Lab 1" ã®ã‚ˆã†ã«äººãŒèª­ã¿ã‚„ã™ã„場所)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">接続:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">共有:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+ã“ã®ãƒ—リンターを共有ã™ã‚‹</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="続ã‘ã‚‹"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/ja/add-rss-subscription.tmpl b/templates/ja/add-rss-subscription.tmpl
new file mode 100644
index 000000000..c5afeb068
--- /dev/null
+++ b/templates/ja/add-rss-subscription.tmpl
@@ -0,0 +1,44 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
+
+<H2 CLASS="title">RSS 購読を追加</H2>
+
+<TABLE SUMMARY="RSS 購読フォームを追加">
+<TR>
+<TH CLASS="label">åå‰:</TH>
+<TD COLSPAN="5"><INPUT TYPE="TEXT" NAME="SUBSCRIPTION_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?SUBSCRIPTION_NAME}"><BR>
+<SMALL>("/"ã€"?"ã€"#"ã€ã‚¹ãƒšãƒ¼ã‚¹ã‚’除ã文字をå«ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">キュー:</TH>
+<TD COLSPAN="5"><SELECT NAME="PRINTER_URI" SIZE="10"><OPTION VALUE="#ALL#"{?PRINTER_URI=#ALL#? SELECTED:}>ã™ã¹ã¦ã®ã‚­ãƒ¥ãƒ¼</OPTION>{[printer_name]<OPTION VALUE="{printer_uri_supported}"{?PRINTER_URI={printer_uri_supported}? SELECTED:}>{printer_name}</OPTION>}</SELECT></TD>
+</TR>
+<TR VALIGN="TOP">
+<TH CLASS="label">イベント:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CREATED" {?EVENT_JOB_CREATED}>ジョブãŒä½œæˆã•ã‚ŒãŸ<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_COMPLETED" {?EVENT_JOB_COMPLETED}>ジョブãŒå®Œäº†ã—ãŸ<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_STOPPED" {?EVENT_JOB_STOPPED}>ジョブãŒåœæ­¢ã—ãŸ<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CONFIG_CHANGED" {?EVENT_JOB_CONFIG_CHANGED}>ジョブオプションãŒå¤‰æ›´ã•ã‚ŒãŸ</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_STOPPED" {?EVENT_PRINTER_STOPPED}>キューãŒåœæ­¢ã—ãŸ<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_ADDED" {?EVENT_PRINTER_ADDED}>キューãŒè¿½åŠ ã•ã‚ŒãŸ<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_MODIFIED" {?EVENT_PRINTER_MODIFIED}>キューãŒå¤‰æ›´ã•ã‚ŒãŸ<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_DELETED" {?EVENT_PRINTER_DELETED}>キューãŒå‰Šé™¤ã•ã‚ŒãŸ</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STARTED" {?EVENT_SERVER_STARTED}>サーãƒãƒ¼ãŒé–‹å§‹ã—ãŸ<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STOPPED" {?EVENT_SERVER_STOPPED}>サーãƒãƒ¼ãŒåœæ­¢ã—ãŸ<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_RESTARTED" {?EVENT_SERVER_RESTARTED}>サーãƒãƒ¼ãŒå†èµ·å‹•ã—ãŸ<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_AUDIT" {?EVENT_SERVER_AUDIT}>サーãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚’監査中</TD>
+</TR>
+<TR>
+<TH CLASS="label">フィード内ã®æœ€å¤§ã‚¤ãƒ™ãƒ³ãƒˆæ•°:</TH>
+<TD COLSPAN="5"><INPUT TYPE="NUMBER" NAME="MAX_EVENTS" SIZE="4" MAXLENGTH="4" VALUE="{MAX_EVENTS?{MAX_EVENTS}:20}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD COLSPAN="5"><INPUT TYPE="SUBMIT" VALUE="RSS 購読を追加"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/ja/admin.tmpl b/templates/ja/admin.tmpl
new file mode 100644
index 000000000..e1e022951
--- /dev/null
+++ b/templates/ja/admin.tmpl
@@ -0,0 +1,110 @@
+<TABLE CLASS="indent" SUMMARY="管ç†è€…タスク">
+<TR><TD VALIGN="TOP">
+
+<H2 CLASS="title">プリンター</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="プリンターã®è¿½åŠ "></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="æ–°ã—ã„プリンターã®æ¤œç´¢"></FORM>
+<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="プリンターã®ç®¡ç†"></FORM>
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="プリンターを Samba ã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ"></FORM>:}
+</P>
+
+<H2 CLASS="title">クラス</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="クラスã®è¿½åŠ "></FORM>
+<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="クラスã®ç®¡ç†"></FORM>
+</P>
+
+<H2 CLASS="title">ジョブ</H2>
+
+<P>
+<FORM ACTION="/jobs/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="ジョブã®ç®¡ç†"></FORM>
+</P>
+
+</TD><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TD VALIGN="TOP">
+
+<H2 CLASS="title">サーãƒãƒ¼</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="設定ファイルã®ç·¨é›†"></FORM>
+<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="アクセスログã®è¡¨ç¤º"></FORM>
+<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="エラーログã®è¡¨ç¤º"></FORM>
+<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="ページログã®è¡¨ç¤º"></FORM>
+</P>
+
+{SETTINGS_ERROR?<P>{SETTINGS_MESSAGE}</P>
+<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+
+{ADVANCEDSETTINGS?<P><B>サーãƒãƒ¼è¨­å®š\:</B></P>
+
+<P><A HREF="/admin/">詳細 <SMALL>&#x25bc;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="HIDDEN" NAME="ADVANCEDSETTINGS" VALUE="YES">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> ã»ã‹ã®ã‚·ã‚¹ãƒ†ãƒ ã§å…±æœ‰ã•ã‚Œã¦ã„るプリンターを表示<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;プロトコル\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_CUPS" {?browse_remote_cups}> CUPS
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_LDAP" {?browse_remote_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_SLP" {?browse_remote_slp}> SLP:}<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> ã“ã®ã‚·ã‚¹ãƒ†ãƒ ã«æŽ¥ç¶šã•ã‚Œã¦ã„るプリンターを共有<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最大クライアント数\:
+<INPUT TYPE="TEXT" NAME="MAX_CLIENTS" VALUE="{?max_clients}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;プロトコル\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_CUPS" {?browse_local_cups}> CUPS
+{HAVE_DNSSD?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_DNSSD" {?browse_local_dnssd}> DNS-SD:}
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_LDAP" {?browse_local_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_SLP" {?browse_local_slp}> SLP:}<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> インターãƒãƒƒãƒˆã‹ã‚‰ã®å°åˆ·ã‚’許å¯<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="BROWSE_WEB_IF" {?browse_web_if}> ウェブインターフェイスを公開<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> リモート管ç†ã‚’許å¯<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Kerberos èªè¨¼ã‚’使用 (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> 所有者以外ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã‚‚ジョブã®ã‚­ãƒ£ãƒ³ã‚»ãƒ«ã‚’許å¯<BR>
+<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_HISTORY" {?preserve_job_history}> ジョブã®å±¥æ­´ã‚’ä¿å­˜<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最大ジョブ数\:
+<INPUT TYPE="TEXT" NAME="MAX_JOBS" VALUE="{?max_jobs}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_FILES" {?preserve_job_files}> ジョブã®å°åˆ·ãƒ•ã‚¡ã‚¤ãƒ«ã‚’ä¿å­˜<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> トラブルシューティングã®ãŸã‚ã«ãƒ‡ãƒãƒƒã‚°æƒ…報をä¿å­˜<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最大ログファイルサイズ\:
+<INPUT TYPE="TEXT" NAME="MAX_LOG_SIZE" VALUE="{?max_log_size}" SIZE="6"></P>
+
+:<P><B>サーãƒãƒ¼è¨­å®š\:</B></P>
+
+<P><A HREF="/admin/?ADVANCEDSETTINGS=YES">詳細 <SMALL>&#x25b6;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> ã»ã‹ã®ã‚·ã‚¹ãƒ†ãƒ ã§å…±æœ‰ã•ã‚Œã¦ã„るプリンターを表示<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> ã“ã®ã‚·ã‚¹ãƒ†ãƒ ã«æŽ¥ç¶šã•ã‚Œã¦ã„るプリンターを共有<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> インターãƒãƒƒãƒˆã‹ã‚‰ã®å°åˆ·ã‚’許å¯<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> リモート管ç†ã‚’許å¯<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Kerberos èªè¨¼ã‚’使用 (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> 所有者以外ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã‚‚ジョブã®ã‚­ãƒ£ãƒ³ã‚»ãƒ«ã‚’許å¯<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> トラブルシューティングã®ãŸã‚ã«ãƒ‡ãƒãƒƒã‚°æƒ…報をä¿å­˜</P>
+
+}
+<P><INPUT TYPE="SUBMIT" NAME="CHANGESETTINGS" VALUE="設定ã®å¤‰æ›´"></P>
+
+</FORM>}
+
+</TD></TR>
+</TABLE>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">RSS 購読</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="RSS 購読ã®è¿½åŠ "></FORM>
+</P>
+
+</DIV>
+
+{notify_subscription_id?<TABLE CLASS="list" SUMMARY="RSS 購読">
+<THEAD><TR><TH>åå‰</TH><TH>イベント</TH><TH>キューå</TH></TR></THEAD>
+<TBODY>{[notify_subscription_id]
+<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="RSS 購読ã®ã‚­ãƒ£ãƒ³ã‚»ãƒ«"></FORM>&nbsp;</TD><TD>{notify_events}</TD><TD NOWRAP>&nbsp;{notify_printer_name?{notify_printer_name}:ã™ã¹ã¦ã®ã‚­ãƒ¥ãƒ¼}</TD></TR>}
+</TBODY>
+</TABLE>:}
diff --git a/templates/ja/choose-device.tmpl b/templates/ja/choose-device.tmpl
new file mode 100644
index 000000000..05700c3c7
--- /dev/null
+++ b/templates/ja/choose-device.tmpl
@@ -0,0 +1,54 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?{printer_name}ã®å¤‰æ›´:プリンターã®è¿½åŠ }</H2>
+
+{CUPS_GET_DEVICES_DONE?:<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Busy Indicator"> プリンターを探ã—ã¦ã„ã¾ã™...</P>}
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+{op=add-printer?:<TR>
+<TH CLASS="label">ç¾åœ¨ã®æŽ¥ç¶š:</TH>
+<TD><INPUT TYPE="RADIO" NAME="DEVICE_URI" VALUE="{current_device_uri}" CHECKED>
+{current_device_uri}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">ローカルプリンター:</TH>
+<TD>
+{[device_uri]{device_class!network?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}}
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">発見ã•ã‚ŒãŸãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ—リンター:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}:}}
+</TD>
+</TR>
+<TR>
+<TR>
+<TH CLASS="label">ãã®ä»–ã®ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ—リンター:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?:<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+}:}}
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="続ã‘ã‚‹"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/ja/choose-make.tmpl b/templates/ja/choose-make.tmpl
new file mode 100644
index 000000000..c800d9818
--- /dev/null
+++ b/templates/ja/choose-make.tmpl
@@ -0,0 +1,64 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?{printer_name}ã®å¤‰æ›´:プリンターã®è¿½åŠ }</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">åå‰:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">説明:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">場所:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">接続:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">共有:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+ã“ã®ãƒ—リンターを共有{?printer_is_shared=?ã—ãªã„:{?printer_is_shared=0?ã—ãªã„:ã™ã‚‹}} </TD>
+</TR>
+<TR>
+<TH CLASS="label">メーカー:</TH>
+<TD>
+<SELECT NAME="PPD_MAKE" SIZE="10">
+{[ppd_make]<OPTION VALUE="{ppd_make}" {?current_make={ppd_make}?SELECTED:}>{ppd_make}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="続ã‘ã‚‹"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>&nbsp;</TD>
+</TR>
+<TR>
+<TH CLASS="label">ã¾ãŸã¯ PPD ファイルをæä¾›:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?プリンターã®è¿½åŠ :プリンターã®å¤‰æ›´}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/ja/choose-model.tmpl b/templates/ja/choose-model.tmpl
new file mode 100644
index 000000000..20011b4d5
--- /dev/null
+++ b/templates/ja/choose-model.tmpl
@@ -0,0 +1,60 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?{printer_name}ã®è¿½åŠ :プリンターã®è¿½åŠ }</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">åå‰:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">説明:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">場所:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">接続:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">共有:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+ã“ã®ãƒ—リンターを共有{?printer_is_shared=?ã—ãªã„:{?printer_is_shared=0?ã—ãªã„:ã™ã‚‹}} </TD>
+</TR>
+<TR>
+<TH CLASS="label">メーカー:</TH>
+<TD>{PPD_MAKE} <INPUT TYPE="SUBMIT" NAME="SELECT_MAKE" VALUE="ä»–ã®ãƒ¡ãƒ¼ã‚«ãƒ¼/製造元をé¸æŠž"></TD>
+</TR>
+<TR>
+<TH CLASS="label">モデル:</TH>
+<TD>
+<SELECT NAME="PPD_NAME" SIZE="10">
+{op=add-printer?:<OPTION VALUE="__no_change__" SELECTED>ç¾åœ¨ã®ãƒ‰ãƒ©ã‚¤ãƒãƒ¼ - {current_make_and_model}</OPTION>:}
+{[ppd_name]<OPTION VALUE="{ppd_name}" {op=modify-printer?:{?current_make_and_model={ppd_make_and_model}?SELECTED:}}>{ppd_make_and_model} ({ppd_natural_language})
+}</SELECT>
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">ã¾ãŸã¯ PPD ファイルをæä¾›:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?プリンターã®è¿½åŠ :プリンターã®å¤‰æ›´}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/ja/choose-serial.tmpl b/templates/ja/choose-serial.tmpl
new file mode 100644
index 000000000..924b84a74
--- /dev/null
+++ b/templates/ja/choose-serial.tmpl
@@ -0,0 +1,52 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?{printer_name}ã®å¤‰æ›´:プリンターã®è¿½åŠ }</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">接続:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">ボーレート:</TH>
+<TD><SELECT NAME="BAUDRATE">
+{[baudrates]<OPTION {?baudrate={baudrates}?SELECTED:}>{baudrates}}
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">パリティ:</TH>
+<TD><SELECT NAME="PARITY">
+<OPTION VALUE="none" {?parity=none?SELECTED:}>ãªã—
+<OPTION VALUE="even" {?parity=even?SELECTED:}>å¶æ•°
+<OPTION VALUE="odd" {?parity=odd?SELECTED:}>奇数
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">データビット:</TH>
+<TD><SELECT NAME="BITS">
+<OPTION {?bits=8?SELECTED:}>8
+<OPTION {?bits=7?SELECTED:}>7
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">フロー制御:</TH>
+<TD><SELECT NAME="FLOW">
+<OPTION VALUE="none" {?flow=none?SELECTED:}>ãªã—
+<OPTION VALUE="soft" {?flow=soft?SELECTED:}>XON/XOFF (ソフトウェア)
+<OPTION VALUE="hard" {?flow=hard?SELECTED:}>RTS/CTS (ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢)
+<OPTION VALUE="dtrdsr" {?flow=dtrdsr?SELECTED:}>DTR/DSR (ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢)
+</SELECT></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="続ã‘ã‚‹"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/ja/choose-uri.tmpl b/templates/ja/choose-uri.tmpl
new file mode 100644
index 000000000..48978edf6
--- /dev/null
+++ b/templates/ja/choose-uri.tmpl
@@ -0,0 +1,43 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?{printer_name}ã®å¤‰æ›´:プリンターã®è¿½åŠ }</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">接続:</TH>
+<TD><INPUT TYPE="URL" SIZE="60" MAXLENGTH="1024" NAME="DEVICE_URI" VALUE="{current_device_uri?{current_device_uri}:{device_uri}}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>例:
+<PRE>
+ http://hostname:631/ipp/
+ http://hostname:631/ipp/port1
+
+ ipp://hostname/ipp/
+ ipp://hostname/ipp/port1
+
+ lpd://hostname/queue
+
+ socket://hostname
+ socket://hostname:9100
+</PRE>
+
+<P>ã‚ãªãŸã®ãƒ—リンターã«ãµã•ã‚ã—ã„ URI ã«ã¤ã„ã¦ã¯ã€<A HREF="/help/network.html" TARGET="_blank">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ—リンター"</A>ã‚’å‚ç…§ã—ã¦ãã ã•ã„。</P>
+
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="続ã‘ã‚‹"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/ja/class-added.tmpl b/templates/ja/class-added.tmpl
new file mode 100644
index 000000000..284aa9fb8
--- /dev/null
+++ b/templates/ja/class-added.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">クラスã®è¿½åŠ </H2>
+
+<P>クラス <A HREF="/classes/{printer_name}">{printer_name}</A> ã¯æ­£ã—ã追加ã•ã‚Œã¾ã—ãŸã€‚
+
+</DIV>
diff --git a/templates/ja/class-confirm.tmpl b/templates/ja/class-confirm.tmpl
new file mode 100644
index 000000000..e50b6a90a
--- /dev/null
+++ b/templates/ja/class-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">クラス {printer_name} ã®å‰Šé™¤</H2>
+
+<P><B>警告:</B> 本当ã«ã‚¯ãƒ©ã‚¹
+{printer_name} を削除ã—ã¦ã‚‚良ã„ã§ã™ã‹ï¼Ÿ</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="クラスã®å‰Šé™¤"></FORM></P>
+
+</DIV>
diff --git a/templates/ja/class-deleted.tmpl b/templates/ja/class-deleted.tmpl
new file mode 100644
index 000000000..415693791
--- /dev/null
+++ b/templates/ja/class-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">クラス {printer_name} ã®å‰Šé™¤</H2>
+
+<P>クラス {printer_name} ã¯æ­£ã—ã削除ã•ã‚Œã¾ã—ãŸã€‚
+
+</DIV>
diff --git a/templates/ja/class-jobs-header.tmpl b/templates/ja/class-jobs-header.tmpl
new file mode 100644
index 000000000..1d5d887cd
--- /dev/null
+++ b/templates/ja/class-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">ジョブ</H3>
+</DIV>
diff --git a/templates/ja/class-modified.tmpl b/templates/ja/class-modified.tmpl
new file mode 100644
index 000000000..ef14ee4eb
--- /dev/null
+++ b/templates/ja/class-modified.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">クラス {printer_name} ã®å¤‰æ›´</H2>
+
+<P>Class <A HREF="/classes/{printer_name}">{printer_name}</A> ã¯æ­£ã—ã変更ã•ã‚Œã¾ã—ãŸã€‚
+
+</DIV>
diff --git a/templates/ja/class.tmpl b/templates/ja/class.tmpl
new file mode 100644
index 000000000..c28407642
--- /dev/null
+++ b/templates/ja/class.tmpl
@@ -0,0 +1,44 @@
+<DIV CLASS="indent">
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?待機中:{printer_state=4?処ç†ä¸­:åœæ­¢}},
+{printer_is_accepting_jobs=0?ジョブを拒å¦ä¸­:ジョブをå—ã‘付ã‘中},
+{server_is_sharing_printers=0?éž:{printer_is_shared=0?éž:}}共有{default_name={printer_name}?, デフォルトプリンター:})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">メンテナンス</OPTION>
+<OPTION VALUE="print-test-page">テストページã®å°åˆ·</OPTION>
+{printer_state=5?<OPTION VALUE="start-class">クラスã®é–‹å§‹</OPTION>:<OPTION VALUE="stop-class">クラスã®åœæ­¢</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">ジョブをå—ã‘付ã‘</OPTION>:<OPTION VALUE="reject-jobs">ジョブを拒å¦</OPTION>}
+<OPTION VALUE="move-jobs">ã™ã¹ã¦ã®ã‚¸ãƒ§ãƒ–ã®ç§»å‹•</OPTION>
+<OPTION VALUE="purge-jobs">ã™ã¹ã¦ã®ã‚¸ãƒ§ãƒ–をキャンセル</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="1">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">管ç†</OPTION>
+<OPTION VALUE="modify-class">クラスã®å¤‰æ›´</OPTION>
+<OPTION VALUE="delete-class">クラスã®å‰Šé™¤</OPTION>
+<OPTION VALUE="set-class-options">デフォルトオプションã®è¨­å®š</OPTION>
+<OPTION VALUE="set-as-default">デフォルトプリンターã®è¨­å®š</OPTION>
+<OPTION VALUE="set-allowed-users">許å¯ã™ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®è¨­å®š</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">説明:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">場所:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">メンãƒãƒ¼:</TH><TD>{?member_uris=?None:{member_uris}}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">デフォルト:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:unknown}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/ja/classes-header.tmpl b/templates/ja/classes-header.tmpl
new file mode 100644
index 000000000..506603cd5
--- /dev/null
+++ b/templates/ja/classes-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?クラスã¯ã‚ã‚Šã¾ã›ã‚“:{total} 個ã®ã‚¯ãƒ©ã‚¹ã®ã†ã¡ {#printer_name} 個を表示中}。</P>
diff --git a/templates/ja/classes.tmpl b/templates/ja/classes.tmpl
new file mode 100644
index 000000000..82d13d661
--- /dev/null
+++ b/templates/ja/classes.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="クラスã®ãƒªã‚¹ãƒˆ">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> キューå <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> キューå <SMALL>&#x25bc;</SMALL>}</A></TH><TH>説明</TH><TH>場所</TH><TH>メンãƒãƒ¼</TH><TH>状態</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{?member_uris=?None:{member_uris}}</TD><TD>{printer_state=3?待機中:{printer_state=4?処ç†ä¸­:åœæ­¢}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/ja/command.tmpl b/templates/ja/command.tmpl
new file mode 100644
index 000000000..3b8afbf23
--- /dev/null
+++ b/templates/ja/command.tmpl
@@ -0,0 +1,12 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{printer_name} ã® {title}</H2>
+
+<P>{job_state>5?:<IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16"
+ALIGN="ABSMIDDLE" ALT="Busy Indicator"> }プリンタージョブ
+{job_state=3?ペンディング中:{job_state=4?ホールド中:
+{job_state=5?処ç†ä¸­:{job_state=6?åœæ­¢ä¸­:
+{job_state=7?キャンセル:{job_state=8?破棄:完了}}}}}}{job_state=9?:{job_printer_state_message?,
+<EM>"{job_printer_state_message}"</EM>:}}</P>
+
+</DIV>
diff --git a/templates/ja/edit-config.tmpl b/templates/ja/edit-config.tmpl
new file mode 100644
index 000000000..a05a55479
--- /dev/null
+++ b/templates/ja/edit-config.tmpl
@@ -0,0 +1,24 @@
+<SCRIPT TYPE="text/javascript">
+function reset_config()
+{
+ document.cups.CUPSDCONF.value = "{?cupsdconf_default}";
+}
+</SCRIPT>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">設定ファイルã®è¨­å®š</H2>
+
+<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+
+<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
+
+<P><INPUT TYPE="SUBMIT" NAME="SAVECHANGES" VALUE="設定ã®ä¿å­˜">
+<INPUT TYPE="BUTTON" VALUE="デフォルトã®è¨­å®šãƒ•ã‚¡ã‚¤ãƒ«ã‚’使用"
+onClick="reset_config();"></P>
+
+</FORM>
+
+</DIV>
diff --git a/templates/ja/error-op.tmpl b/templates/ja/error-op.tmpl
new file mode 100644
index 000000000..81c8fbbdf
--- /dev/null
+++ b/templates/ja/error-op.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{?title} {?printer_name} エラー</H2>
+
+<P>エラー:</P>
+
+<BLOCKQUOTE>"{op}" ã¯æœªçŸ¥ã®æ“作ã§ã™ï¼</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/ja/error.tmpl b/templates/ja/error.tmpl
new file mode 100644
index 000000000..f10c38870
--- /dev/null
+++ b/templates/ja/error.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{?title} {?printer_name} エラー</H2>
+
+<P>{?message?{message}:エラー:}</P>
+
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/ja/header.tmpl.in b/templates/ja/header.tmpl.in
new file mode 100644
index 000000000..ec64a744d
--- /dev/null
+++ b/templates/ja/header.tmpl.in
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{title} - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+ {refresh_page?<META HTTP-EQUIV="Refresh" CONTENT="{refresh_page}">:}
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="unsel" NOWRAP><A HREF="/">&nbsp;&nbsp;ホーム&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=admin?:un}sel" NOWRAP><A HREF="/admin">&nbsp;&nbsp;管ç†&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=classes?:un}sel" NOWRAP><A HREF="/classes/">&nbsp;&nbsp;クラス&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=help?:un}sel" NOWRAP><A HREF="/help/">&nbsp;&nbsp;ヘルプ&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=jobs?:un}sel" NOWRAP><A HREF="/jobs/">&nbsp;&nbsp;ジョブ&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=printers?:un}sel" NOWRAP><A HREF="/printers/">&nbsp;プリンター&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Search Help"
+VALUE="{SECTION=help?{?QUERY}:}" AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+<TR><TD COLSPAN="9">&nbsp;</TD></TR>
+</TABLE>
diff --git a/templates/ja/help-header.tmpl b/templates/ja/help-header.tmpl
new file mode 100644
index 000000000..ee0e5f018
--- /dev/null
+++ b/templates/ja/help-header.tmpl
@@ -0,0 +1,51 @@
+<DIV CLASS="indent">
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET">
+{TOPIC?<INPUT TYPE="HIDDEN" NAME="TOPIC" VALUE="{TOPIC}">:}
+
+<P ALIGN="CENTER"><B>
+{HELPTITLE?{HELPTITLE}:{TOPIC?{TOPIC}:ã™ã¹ã¦ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆ}内を検索:</B> <INPUT
+TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER=""
+AUTOSAVE="org.cups.help" RESULTS="20">
+<INPUT TYPE="SUBMIT" NAME="SEARCH" VALUE="検索">
+<INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="クリア"></P>
+
+</FORM>
+
+<!-- Bookmarks -->
+<DIV CLASS="sidebar"><TABLE CLASS="inset" SUMMARY="Contents">
+<TR><TD>
+
+<H3 CLASS="title">オンラインヘルプドキュメント</H3>
+
+<P CLASS="l0"><A HREF="/help/{QUERY??QUERY={QUERY}:}">ã™ã¹ã¦ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆ</A></P>
+<HR>
+
+{[BMTEXT]<P CLASS="l{BMINDENT}"><A HREF="{BMLINK}">{BMTEXT}</A></P>
+}
+</TD></TR>
+</TABLE></DIV>
+
+{QUERY?<P>{HELPFILE?{HELPTITLE}:{TOPIC?{TOPIC}:ã™ã¹ã¦ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®æ¤œç´¢çµæžœ}}\:</P>
+{QTEXT?<UL>
+{[QTEXT]<LI><A HREF="{QLINK}">{QTEXT}</A>{QPTEXT? (in <I><A HREF="{QPLINK}">{QPTEXT}</A></I>):}</LI>}
+{QTEXT?</UL>:}
+:<P>マッãƒã™ã‚‹ã‚‚ã®ã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚</P>}
+<HR NOSHADE>:}
+{HELPTITLE?<H1>{HELPTITLE}</H1>
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="PRINTABLE" VALUE="YES"><INPUT TYPE="SUBMIT" VALUE="å°åˆ·å¯èƒ½ãªãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®è¡¨ç¤º"></FORM>:
+
+<H1>オンラインヘルプ</H1>
+
+<P>ã“ã‚Œã¯ã€CUPS ã®ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ãƒ˜ãƒ«ãƒ—インターフェイスã§ã™ã€‚
+オンラインヘルプ情報を表示ã™ã‚‹ã«ã¯ã€æ¤œç´¢èªžå¥ã‚’上ã«å…¥åŠ›ã™ã‚‹ã‹ã€
+ドキュメントリンクã®ã„ãšã‚Œã‹ã‚’クリックã—ã¦ãã ã•ã„。</P>
+
+<P>ã‚ãªãŸãŒ CUPS ã«ã¤ã„ã¦åˆå¿ƒè€…ãªã‚‰ã€ "<a
+href="/help/overview.html">CUPS ã®æ¦‚è¦</a>" を読んã§ãã ã•ã„。
+上級ユーザーã¯ã€ "<a href="/help/whatsnew.html">CUPS 1.4 ã®æ–°æ©Ÿèƒ½</a>"
+を読むã¹ãã§ã™ã€‚</P>
+
+<P><A HREF="http://www.cups.org/">CUPS ホームページ</A> ã§ã‚‚ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼
+ディスカッションフォーラムã€FAQã€ãƒã‚°å ±å‘Šã‚„機能リクエストを申請ã™ã‚‹
+フォームã¨ã„ã£ãŸã€å¤šãã®ãƒªã‚½ãƒ¼ã‚¹ã‚’æä¾›ã—ã¦ã„ã¾ã™ã€‚</P>}
+
diff --git a/templates/ja/help-printable.tmpl b/templates/ja/help-printable.tmpl
new file mode 100644
index 000000000..2463c1630
--- /dev/null
+++ b/templates/ja/help-printable.tmpl
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{HELPTITLE}</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups-printable.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
diff --git a/templates/ja/help-trailer.tmpl b/templates/ja/help-trailer.tmpl
new file mode 100644
index 000000000..4c1ebed85
--- /dev/null
+++ b/templates/ja/help-trailer.tmpl
@@ -0,0 +1 @@
+</DIV>
diff --git a/templates/ja/job-cancel.tmpl b/templates/ja/job-cancel.tmpl
new file mode 100644
index 000000000..16e44d82f
--- /dev/null
+++ b/templates/ja/job-cancel.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">ジョブ {job_id}ã®ã‚­ãƒ£ãƒ³ã‚»ãƒ«</H2>
+
+<P><A HREF="{job_printer_uri}">ジョブ {job_id}</A> ã¯ã‚­ãƒ£ãƒ³ã‚»ãƒ«ã•ã‚Œã¾ã—ãŸã€‚
+
+</DIV>
diff --git a/templates/ja/job-hold.tmpl b/templates/ja/job-hold.tmpl
new file mode 100644
index 000000000..4aec1b226
--- /dev/null
+++ b/templates/ja/job-hold.tmpl
@@ -0,0 +1,6 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">ジョブ {job_id} ã®ä¿ç•™</H2>
+
+<P><A HREF="{job_printer_uri}">ジョブ {job_id}</A> ã¯å°åˆ·ã‚’ä¿ç•™ã•ã‚Œã¾ã—ãŸã€‚
+</DIV>
diff --git a/templates/ja/job-move.tmpl b/templates/ja/job-move.tmpl
new file mode 100644
index 000000000..54da7e038
--- /dev/null
+++ b/templates/ja/job-move.tmpl
@@ -0,0 +1,27 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
+
+<H2 CLASS="title">{job_id?ジョブ {job_id} ã®ç§»å‹•:ã™ã¹ã¦ã®ã‚¸ãƒ§ãƒ–ã®ç§»å‹•}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">æ–°ã—ã„宛先:</TH>
+<TD>
+<SELECT NAME="JOB_PRINTER_URI" SIZE="10">
+{[job_printer_uri]<OPTION VALUE="{job_printer_uri}">{job_printer_name}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{job_id?ジョブã®ç§»å‹•:ジョブã®ç§»å‹•}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+
+</DIV>
diff --git a/templates/ja/job-moved.tmpl b/templates/ja/job-moved.tmpl
new file mode 100644
index 000000000..d6b3445c1
--- /dev/null
+++ b/templates/ja/job-moved.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{job_id?ジョブ {job_id} ã®ç§»å‹•:ã™ã¹ã¦ã®ã‚¸ãƒ§ãƒ–ã®ç§»å‹•}</H2>
+
+<P>{job_id?<A HREF="/jobs/{job_id}">ジョブ {job_id}</A>:ã™ã¹ã¦ã®ã‚¸ãƒ§ãƒ–} ã¯
+<A HREF="/{is_class?classes:printers}/{job_printer_name}">{job_printer_name}</A>ã«ç§»å‹•ã—ã¾ã—ãŸã€‚</P>
+
+</DIV>
diff --git a/templates/ja/job-release.tmpl b/templates/ja/job-release.tmpl
new file mode 100644
index 000000000..fd9f89dd2
--- /dev/null
+++ b/templates/ja/job-release.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">ジョブ {job_id} ã®è§£æ”¾</H2>
+
+<P><A HREF="{job_printer_uri}">ジョブ {job_id}</A> ã¯å°åˆ·ã‹ã‚‰è§£æ”¾ã•ã‚Œã¾ã—ãŸã€‚
+
+</DIV>
diff --git a/templates/ja/job-restart.tmpl b/templates/ja/job-restart.tmpl
new file mode 100644
index 000000000..493a4ace7
--- /dev/null
+++ b/templates/ja/job-restart.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">ジョブ {job_id} ã®å†å°åˆ·</H2>
+
+<P><A HREF="{job_printer_uri}">ジョブ {job_id}</A> ã¯å†å°åˆ·ã•ã‚Œã¾ã—ãŸã€‚
+
+</DIV>
diff --git a/templates/ja/jobs-header.tmpl b/templates/ja/jobs-header.tmpl
new file mode 100644
index 000000000..76095b4e6
--- /dev/null
+++ b/templates/ja/jobs-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">{?which_jobs=?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="アクティブãªã‚¸ãƒ§ãƒ–を表示"></FORM>}
+{?which_jobs=completed?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="completed"><INPUT TYPE="SUBMIT" VALUE="完了ã—ãŸã‚¸ãƒ§ãƒ–を表示"></FORM>}
+{?which_jobs=all?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="all"><INPUT TYPE="SUBMIT" VALUE="ã™ã¹ã¦ã®ã‚¸ãƒ§ãƒ–を表示"></FORM>}</DIV>
+
+<P ALIGN="CENTER">{total=0?ジョブã¯ã‚ã‚Šã¾ã›ã‚“:{total} 個ã®{?which_jobs=?アクティブãª:{which_jobs=all?:完了ã—ãŸ}}ジョブã®ã†ã¡ {#job_id} 個を表示中}。</P>
diff --git a/templates/ja/jobs.tmpl b/templates/ja/jobs.tmpl
new file mode 100644
index 000000000..bff543aea
--- /dev/null
+++ b/templates/ja/jobs.tmpl
@@ -0,0 +1,37 @@
+{#job_id=0?:
+<TABLE CLASS="list" SUMMARY="ジョブã®ãƒªã‚¹ãƒˆ">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> ID <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> ID <SMALL>&#x25bc;</SMALL>}</A></TH><TH>åå‰</TH><TH>ユーザー</TH><TH>サイズ</TH><TH>ページ</TH><TH>状態</TH><TH>制御</TH></TR>
+</THEAD>
+<TBODY>
+{[job_id]
+<TR VALIGN="TOP">
+<TD><A HREF="{job_printer_uri}">{job_printer_name}</A>-{job_id}&nbsp;</TD>
+<TD>{?job_name=?未知:{job_name}}&nbsp;</TD>
+<TD>{job_originating_user_name}&nbsp;</TD>
+<TD>{job_k_octets}k&nbsp;</TD>
+<TD>{job_media_sheets_completed=0?ä¸æ˜Ž:{?job_media_sheets_completed}}&nbsp;</TD>
+<TD>{job_state=3?{time_at_creation}<BR>ã‹ã‚‰ä¿ç•™ä¸­:{job_state=4?held since<BR>{time_at_creation}:
+{job_state=5?{time_at_processing}<BR>ã‹ã‚‰å‡¦ç†ä¸­:{job_state=6?stopped:
+{job_state=7?{time_at_completed}<BR>ã«ã‚­ãƒ£ãƒ³ã‚»ãƒ«:{job_state=8?{time_at_completed}ã«ä¸­æ–­:ã«å®Œäº†}}}}}}&nbsp;{job_printer_state_message?<BR>
+<EM>"{job_printer_state_message}"</EM>:}</TD>
+<TD>
+{job_preserved>0?{job_state>5?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="ジョブã®å†å°åˆ·"></FORM>:}:}
+{job_state=4?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="ジョブを解放"></FORM>:}
+{job_state=3?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="ジョブをä¿ç•™"></FORM>:}
+{job_state<7?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="ジョブをキャンセル"></FORM>
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="ジョブを移動"></FORM>:}
+&nbsp;</TD>
+</TR>
+}
+</TBODY>
+</TABLE>
+}
diff --git a/templates/ja/list-available-printers.tmpl b/templates/ja/list-available-printers.tmpl
new file mode 100644
index 000000000..f70b5aac0
--- /dev/null
+++ b/templates/ja/list-available-printers.tmpl
@@ -0,0 +1,11 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">利用å¯èƒ½ãªãƒ—リンター</H2>
+
+{#device_uri=0?<P>プリンターãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。</P>
+:<UL>{[device_uri]
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="ã“ã®ãƒ—リンターを追加"></FORM>
+{device_make_and_model} ({device_info})</LI>
+}</UL>}
+
+</DIV>
diff --git a/templates/ja/modify-class.tmpl b/templates/ja/modify-class.tmpl
new file mode 100644
index 000000000..a41010f3f
--- /dev/null
+++ b/templates/ja/modify-class.tmpl
@@ -0,0 +1,34 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">クラス {printer_name} ã®å¤‰æ›´</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">説明:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">場所:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">メンãƒãƒ¼:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="クラスã®å¤‰æ›´"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/ja/modify-printer.tmpl b/templates/ja/modify-printer.tmpl
new file mode 100644
index 000000000..d8ef5f04b
--- /dev/null
+++ b/templates/ja/modify-printer.tmpl
@@ -0,0 +1,42 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">プリンター {printer_name} ã®å¤‰æ›´</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">説明:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>("HP LaserJet with Duplexer" ã®ã‚ˆã†ã«äººãŒèª­ã¿ã‚„ã™ã„説明)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">場所:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>("Lab 1" ã®ã‚ˆã†ã«äººãŒèª­ã¿ã‚„ã™ã„場所)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">接続:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">共有:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+ã“ã®ãƒ—リンターを共有ã™ã‚‹</TD>
+</TR>
+<TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="続ã‘ã‚‹"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/ja/norestart.tmpl b/templates/ja/norestart.tmpl
new file mode 100644
index 000000000..474043318
--- /dev/null
+++ b/templates/ja/norestart.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">設定変更</H2>
+
+<P>設定ã«ä½•ã‚‚変更ãŒè¡Œã‚ã‚Œãªã‹ã£ãŸãŸã‚ã€ã‚µãƒ¼ãƒãƒ¼ã¯å†èµ·å‹•ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸ...</P>
+
+</DIV>
diff --git a/templates/ja/option-boolean.tmpl b/templates/ja/option-boolean.tmpl
new file mode 100644
index 000000000..e832ee102
--- /dev/null
+++ b/templates/ja/option-boolean.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD>
+{[choices]<INPUT TYPE="RADIO" NAME="{keyword-1}" {choices={defchoice-1}?CHECKED:} VALUE="{choices}">{text}}
+</TD>
+</TR>
diff --git a/templates/ja/option-conflict.tmpl b/templates/ja/option-conflict.tmpl
new file mode 100644
index 000000000..4f782ac80
--- /dev/null
+++ b/templates/ja/option-conflict.tmpl
@@ -0,0 +1,7 @@
+<P><B>エラー:</B> 以下ã®ã‚ªãƒ—ションã¯ç«¶åˆã—ã¾ã™:</P>
+
+<UL>
+{[ckeyword]<LI><A HREF="#{ckeyword}">{ckeytext}</A>: {cchoice}</LI>
+}</UL>
+
+<P>競åˆã‚’解決ã™ã‚‹ãŸã‚ã«ã€1 ã¤ä»¥ä¸Šã®ã‚ªãƒ—ションを変更ã—ã¦ãã ã•ã„。</P>
diff --git a/templates/ja/option-header.tmpl b/templates/ja/option-header.tmpl
new file mode 100644
index 000000000..464726a50
--- /dev/null
+++ b/templates/ja/option-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="tab" ID="{group_id}">
+
+<H3 ALIGN="CENTER">{group}</H3>
+
+<TABLE WIDTH="100%">
diff --git a/templates/ja/option-pickmany.tmpl b/templates/ja/option-pickmany.tmpl
new file mode 100644
index 000000000..0da75e5d2
--- /dev/null
+++ b/templates/ja/option-pickmany.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" MULTIPLE SIZE="10">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT></TD>
+</TR>
diff --git a/templates/ja/option-pickone.tmpl b/templates/ja/option-pickone.tmpl
new file mode 100644
index 000000000..514e2abc2
--- /dev/null
+++ b/templates/ja/option-pickone.tmpl
@@ -0,0 +1,18 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" ID="select-{keyword}" ONCHANGE="update_paramtable('{keyword}')">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT>
+{iscustom=1?<TABLE NAME="paramtable" id="{keyword}-params">{[params]
+<TR><TH CLASS="sublabel">{paramtext}:</TH>
+<TD>{params=Units?<SELECT NAME="{keyword-1}.{params}">
+<OPTION VALUE="pt"{paramvalue=pt? SELECTED:}>ãƒã‚¤ãƒ³ãƒˆ</OPTION>
+<OPTION VALUE="mm"{paramvalue=mm? SELECTED:}>ミリメートル</OPTION>
+<OPTION VALUE="cm"{paramvalue=cm? SELECTED:}>センãƒãƒ¡ãƒ¼ãƒˆãƒ«</OPTION>
+<OPTION VALUE="in"{paramvalue=in? SELECTED:}>インãƒ</OPTION>
+<OPTION VALUE="ft"{paramvalue=ft? SELECTED:}>フィート</OPTION>
+<OPTION VALUE="m"{paramvalue=m? SELECTED:}>メートル</OPTION>
+</SELECT>:<INPUT TYPE="{inputtype}" NAME="{keyword-1}.{params}" VALUE="{paramvalue}">}</TD></TR>
+}</TABLE>
+</TD>:}
+</TR>
diff --git a/templates/ja/option-trailer.tmpl b/templates/ja/option-trailer.tmpl
new file mode 100644
index 000000000..da2db1e09
--- /dev/null
+++ b/templates/ja/option-trailer.tmpl
@@ -0,0 +1,5 @@
+</TABLE>
+
+<P ALIGN="CENTER"><INPUT TYPE="SUBMIT" VALUE="デフォルトオプションã®è¨­å®š"></P>
+
+</DIV> \ No newline at end of file
diff --git a/templates/ja/pager.tmpl b/templates/ja/pager.tmpl
new file mode 100644
index 000000000..ebba3a004
--- /dev/null
+++ b/templates/ja/pager.tmpl
@@ -0,0 +1,6 @@
+<TABLE CLASS="inset" SUMMARY="Paging Bar">
+<TR>
+ <TD WIDTH="50%">{PREV?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{PREV}"><INPUT TYPE="SUBMIT" VALUE="&#x25c0; å‰ã‚’表示"></FORM>:&nbsp;}</TD>
+ <TD WIDTH="50%" ALIGN="RIGHT">{NEXT?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{NEXT}"><INPUT TYPE="SUBMIT" VALUE="次を表示 &#x25b6;"></FORM>:&nbsp;}</TD>
+</TR>
+</TABLE>
diff --git a/templates/ja/printer-accept.tmpl b/templates/ja/printer-accept.tmpl
new file mode 100644
index 000000000..f13c66267
--- /dev/null
+++ b/templates/ja/printer-accept.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{is_class?クラス:プリンター} {printer_name} ã®ã‚¸ãƒ§ãƒ–ã®å—ã‘付ã‘</H2>
+
+<P>{is_class?クラス:プリンター} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+ã¯ã‚¸ãƒ§ãƒ–ã‚’å—ã‘付ã‘るよã†ã«ãªã‚Šã¾ã—ãŸã€‚</P>
+
+</DIV>
diff --git a/templates/ja/printer-added.tmpl b/templates/ja/printer-added.tmpl
new file mode 100644
index 000000000..c07a832b8
--- /dev/null
+++ b/templates/ja/printer-added.tmpl
@@ -0,0 +1,6 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">プリンターã®è¿½åŠ </H2>
+
+<P>プリンター <A HREF="/printers/{printer_name}">{printer_name}</A> ã¯æ­£ã—ã追加ã•ã‚Œã¾ã—ãŸã€‚
+</DIV>
diff --git a/templates/ja/printer-configured.tmpl b/templates/ja/printer-configured.tmpl
new file mode 100644
index 000000000..d6b2bf1a4
--- /dev/null
+++ b/templates/ja/printer-configured.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{printer_name} ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã‚ªãƒ—ションã®è¨­å®š</H2>
+
+<P>{OP=set-class-options?クラス <A HREF="/classes/{printer_name}">:プリンター <A HREF="/printers/{printer_name}">}{printer_name}</A> ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã‚ªãƒ—ションã¯æ­£ã—ã設定ã•ã‚Œã¾ã—ãŸã€‚
+
+</DIV>
diff --git a/templates/ja/printer-confirm.tmpl b/templates/ja/printer-confirm.tmpl
new file mode 100644
index 000000000..6fdb52cab
--- /dev/null
+++ b/templates/ja/printer-confirm.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">プリンター {printer_name} ã®å‰Šé™¤</H2>
+
+<P><B>警告:</B> 本当ã«ãƒ—リンター {printer_name} を削除ã—ã¦ã‚ˆã„ã§ã™ã‹ï¼Ÿ</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="プリンターã®å‰Šé™¤"></FORM></P>
+
+</DIV>
diff --git a/templates/ja/printer-default.tmpl b/templates/ja/printer-default.tmpl
new file mode 100644
index 000000000..aa04c2ee9
--- /dev/null
+++ b/templates/ja/printer-default.tmpl
@@ -0,0 +1,12 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{is_class?クラス:プリンター} {printer_name} をデフォルトã«è¨­å®š</H2>
+
+<P>{is_class?クラス:プリンター} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+をサーãƒãƒ¼ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆãƒ—リンターã«è¨­å®šã—ã¾ã—ãŸã€‚</P>
+
+<BLOCKQUOTE><B>注æ„:</B> <TT>lpoptions</TT> コマンドã§è¨­å®šã•ã‚ŒãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã¯ã€ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆè¨­å®šã‚’上書ãã—ã¾ã™ã€‚
+</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/ja/printer-deleted.tmpl b/templates/ja/printer-deleted.tmpl
new file mode 100644
index 000000000..17cf44c15
--- /dev/null
+++ b/templates/ja/printer-deleted.tmpl
@@ -0,0 +1,6 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">プリンター {printer_name} ã®å‰Šé™¤</H2>
+
+<P>プリンター {printer_name} ã¯æ­£ã—ã削除ã•ã‚Œã¾ã—ãŸã€‚
+</DIV>
diff --git a/templates/ja/printer-jobs-header.tmpl b/templates/ja/printer-jobs-header.tmpl
new file mode 100644
index 000000000..1d5d887cd
--- /dev/null
+++ b/templates/ja/printer-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">ジョブ</H3>
+</DIV>
diff --git a/templates/ja/printer-modified.tmpl b/templates/ja/printer-modified.tmpl
new file mode 100644
index 000000000..63997bb4c
--- /dev/null
+++ b/templates/ja/printer-modified.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">プリンター {printer_name} ã®å¤‰æ›´</H2>
+
+<P>プリンター <A HREF="/printers/{printer_name}">{printer_name}</A> ã¯æ­£ã—ã変更ã•ã‚Œã¾ã—ãŸã€‚
+
+</DIV>
diff --git a/templates/ja/printer-purge.tmpl b/templates/ja/printer-purge.tmpl
new file mode 100644
index 000000000..0546412a8
--- /dev/null
+++ b/templates/ja/printer-purge.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{is_class?クラス:プリンター} {printer_name} ジョブã®å…¨å‰Šé™¤</H2>
+
+<P>{is_class?クラス:プリンター} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+ã¯ã™ã¹ã¦ã®ã‚¸ãƒ§ãƒ–を削除ã—ã¾ã—ãŸã€‚</P>
+
+</DIV>
diff --git a/templates/ja/printer-reject.tmpl b/templates/ja/printer-reject.tmpl
new file mode 100644
index 000000000..ba7cc524c
--- /dev/null
+++ b/templates/ja/printer-reject.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{is_class?クラス:プリンター} {printer_name} ã®ã‚¸ãƒ§ãƒ–ã®æ‹’å¦</H2>
+
+<P>{is_class?クラス:プリンター} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+ã¯ã‚¸ãƒ§ãƒ–ã‚’å—ã‘付ã‘ãªããªã‚Šã¾ã—ãŸã€‚</P>
+
+</DIV>
diff --git a/templates/ja/printer-start.tmpl b/templates/ja/printer-start.tmpl
new file mode 100644
index 000000000..5c0eea19f
--- /dev/null
+++ b/templates/ja/printer-start.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{is_class?クラス:プリンター} {printer_name} ã®å†é–‹</H2>
+
+<P>{is_class?クラス:プリンター} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+ã¯å†é–‹ã—ã¾ã—ãŸã€‚</P>
+
+</DIV>
diff --git a/templates/ja/printer-stop.tmpl b/templates/ja/printer-stop.tmpl
new file mode 100644
index 000000000..8499b2ea7
--- /dev/null
+++ b/templates/ja/printer-stop.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{is_class?クラス:プリンター} {printer_name} ã®åœæ­¢</H2>
+
+<P>{is_class?クラス:プリンター} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+ã¯åœæ­¢ã—ã¾ã—ãŸã€‚</P>
+</DIV>
diff --git a/templates/ja/printer.tmpl b/templates/ja/printer.tmpl
new file mode 100644
index 000000000..fbd9c5ad0
--- /dev/null
+++ b/templates/ja/printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?待機中:{printer_state=4?処ç†ä¸­:一時åœæ­¢ä¸­}},
+{printer_is_accepting_jobs=0?ジョブを拒å¦ä¸­:ジョブをå—ã‘付ã‘中},
+{server_is_sharing_printers=0?éž:{printer_is_shared=0?éž:}}共有{default_name={printer_name}?, デフォルトプリンター:})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">メンテナンス</OPTION>
+<OPTION VALUE="print-test-page">テストページã®å°åˆ·</OPTION>
+{printer_commands~.*Clean.*?<OPTION VALUE="clean-print-heads">ヘッドクリーニング</OPTION>:}
+{printer_commands~.*PrintSelfTestPage.*?<OPTION VALUE="print-self-test-page">自己テストページã®å°åˆ·</OPTION>:}
+{printer_state=5?<OPTION VALUE="start-printer">プリンターを開始</OPTION>:<OPTION VALUE="stop-printer">プリンターã®åœæ­¢</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">ジョブをå—ã‘付ã‘</OPTION>:<OPTION VALUE="reject-jobs">ジョブを拒å¦</OPTION>}
+<OPTION VALUE="move-jobs">ã™ã¹ã¦ã®ã‚¸ãƒ§ãƒ–を移動</OPTION>
+<OPTION VALUE="purge-jobs">ã™ã¹ã¦ã®ã‚¸ãƒ§ãƒ–をキャンセル</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">管ç†</OPTION>
+<OPTION VALUE="modify-printer">プリンターã®å¤‰æ›´</OPTION>
+<OPTION VALUE="delete-printer">プリンターã®å‰Šé™¤</OPTION>
+<OPTION VALUE="set-printer-options">プリンターオプションã®å¤‰æ›´</OPTION>
+<OPTION VALUE="set-as-default">デフォルトプリンターã«è¨­å®š</OPTION>
+<OPTION VALUE="set-allowed-users">許å¯ã™ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®è¨­å®š</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">説明:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">場所:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">プリンタードライãƒãƒ¼:</TH><TD>{printer_make_and_model} ({color_supported=1?カラー:白黒}{sides_supported?, 両é¢å¯:})<BR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">接続先:</TH><TD>{device_uri}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">デフォルト設定:</TH><TD>ãƒãƒŠãƒ¼={job_sheets_default}
+用紙サイズ={media_default?{media_default}:unknown}
+{sides_default?両é¢æŒ‡å®š={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/ja/printers-header.tmpl b/templates/ja/printers-header.tmpl
new file mode 100644
index 000000000..1342eff42
--- /dev/null
+++ b/templates/ja/printers-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?プリンターã¯ã‚ã‚Šã¾ã›ã‚“:{total} å°ã®ãƒ—リンターã®ã†ã¡ {#printer_name} å°ã‚’表示中}。</P>
diff --git a/templates/ja/printers.tmpl b/templates/ja/printers.tmpl
new file mode 100644
index 000000000..3fb9a37e8
--- /dev/null
+++ b/templates/ja/printers.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Printer List">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> キューå<SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL>キューå<SMALL>&#x25bc;</SMALL>}</A></TH><TH>説明</TH><TH>場所</TH><TH>メーカーã¨ãƒ¢ãƒ‡ãƒ«</TH><TH>状態</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{printer_make_and_model}</TD><TD>{printer_state=3?å¾…æ©Ÿ:{printer_state=4?Processing:åœæ­¢ä¸­}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/ja/restart.tmpl b/templates/ja/restart.tmpl
new file mode 100644
index 000000000..ec74fac83
--- /dev/null
+++ b/templates/ja/restart.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">設定ã®å¤‰æ›´</H2>
+
+<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Busy Indicator"> サーãƒãƒ¼ãŒå†èµ·å‹•ã™ã‚‹ã‚ã„ã ã€ã—ã°ã‚‰ããŠå¾…ã¡ãã ã•ã„...</P>
+
+</DIV>
diff --git a/templates/ja/samba-export.tmpl b/templates/ja/samba-export.tmpl
new file mode 100644
index 000000000..74b7991e3
--- /dev/null
+++ b/templates/ja/samba-export.tmpl
@@ -0,0 +1,56 @@
+<SCRIPT TYPE="text/javascript"><!--
+function select_printers() {
+ var list = document.export_samba.EXPORT_NAME;
+ var sel = document.export_samba.EXPORT_ALL.checked;
+
+ for (i = 0; i < list.length; i ++) {
+ list.options[i].selected = sel;
+ }
+}
+--></SCRIPT>
+
+<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
+
+<H2 CLASS="title">プリンターを Samba ã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ</H2>
+
+{error?<P>プリンターを Samba ã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“\:</P>
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+<P>より詳細ãªæƒ…å ±ã«ã¤ã„ã¦ã¯ <A HREF="/admin/log/error_log"
+TARGET="_blank">error_log</A> ファイルをå‚ç…§ã—ã¦ãã ã•ã„。</P>:
+<P>ã“ã®ãƒšãƒ¼ã‚¸ã¯ã€Windows クライアントãŒãƒ‡ã‚¹ã‚¯ãƒˆãƒƒãƒ—上ã®
+<VAR>マイãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯</VAR> ã‚„ <VAR>ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®å ´æ‰€</VAR>
+アイコン経由ã§ã‚¢ã‚¯ã‚»ã‚¹ã§ãるよã†ã€ãƒ—リンター㮠Samba
+ã¸ã®ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã‚’許å¯ã—ã¾ã™ã€‚<A
+HREF="/help/man-cupsaddsmb.html"
+TARGET="_blank">cupsaddsmb(8)</A> man ページã«æ›¸ã‹ã‚Œã¦ã„るよã†ã«ã€
+事å‰ã« Windows PostScript ドライãƒãƒ¼ã‚’インストールã—ã¦ãŠãå¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚
+</P>}
+
+<TABLE>
+<TR>
+<TH CLASS="label">プリンター:</TH>
+<TD>
+<SELECT NAME="EXPORT_NAME" SIZE="10" MULTIPLE>
+{[printer_name]<OPTION VALUE="{printer_name}"{export_all? SELECTED:{printer_export? SELECTED:}}>{printer_name}}
+</SELECT><BR>
+<INPUT TYPE="CHECKBOX" NAME="EXPORT_ALL"{export_all? CHECKED:}
+onChange="select_printers()"> ã™ã¹ã¦ã®ãƒ—リンターをエクスãƒãƒ¼ãƒˆ
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Samba ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼å:</TH>
+<TD><INPUT TYPE="TEXT" NAME="USERNAME" VALUE="{?USERNAME}"> (required)</TD>
+</TR>
+<TR>
+<TH CLASS="label">Samba ã®ãƒ‘スワード:</TH>
+<TD><INPUT TYPE="PASSWORD" NAME="PASSWORD" VALUE=""> (required)</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="プリンターを Samba ã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/ja/samba-exported.tmpl b/templates/ja/samba-exported.tmpl
new file mode 100644
index 000000000..f67ddd928
--- /dev/null
+++ b/templates/ja/samba-exported.tmpl
@@ -0,0 +1 @@
+<P>プリンター㯠Samba ã«æ­£ã—ãエクスãƒãƒ¼ãƒˆã•ã‚Œã¾ã—ãŸã€‚</P>
diff --git a/templates/ja/search.tmpl b/templates/ja/search.tmpl
new file mode 100644
index 000000000..3e819952c
--- /dev/null
+++ b/templates/ja/search.tmpl
@@ -0,0 +1,10 @@
+<FORM ACTION="/{SECTION}/{?SEARCH_DEST}" METHOD="GET">
+{WHICH_JOBS?<INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{WHICH_JOBS}">:}
+{ORDER?<INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{ORDER}">:}
+
+<P ALIGN="CENTER"><B>
+{SEARCH_DEST?{SEARCH_DEST}:{SECTION=classes?クラス:{SECTION=jobs?ジョブ:プリンター}}} 内を検索:</B>
+<INPUT TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER="" AUTOSAVE="org.cups.{SECTION}" RESULTS="20"> <INPUT
+TYPE="SUBMIT" VALUE="検索"> <INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="クリア"></P>
+
+</FORM>
diff --git a/templates/ja/set-printer-options-header.tmpl b/templates/ja/set-printer-options-header.tmpl
new file mode 100644
index 000000000..b5896f071
--- /dev/null
+++ b/templates/ja/set-printer-options-header.tmpl
@@ -0,0 +1,26 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{printer_name} ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã‚ªãƒ—ション変更</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="プリンターã«ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã‚ªãƒ—ションをå•ã„åˆã‚ã›ã‚‹">:}
+
+<SCRIPT TYPE="text/javascript"><!--
+function update_paramtable(option)
+{
+ var cb = document.getElementById("select-" + option)
+ var paramstable = document.getElementById(option + "-params");
+ if (cb.value == "Custom")
+ paramstable.style.display = "table";
+ else
+ paramstable.style.display = "none";
+}
+--></SCRIPT>
+
+<H3 CLASS="title">{[group_id]
+<A HREF="#{group_id}">{group}</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</H3>
+
+<DIV CLASS="tabs">
diff --git a/templates/ja/set-printer-options-trailer.tmpl b/templates/ja/set-printer-options-trailer.tmpl
new file mode 100644
index 000000000..11adc7012
--- /dev/null
+++ b/templates/ja/set-printer-options-trailer.tmpl
@@ -0,0 +1,16 @@
+</DIV>
+
+<SCRIPT TYPE="text/javascript"><!--
+// Hide custom options parameters for browsers that understand Javascript
+var paramtables = document.getElementsByName("paramtable");
+for (var i = 0; i < paramtables.length; i++)
+{
+ var opt = paramtables[i].id.substr(0, paramtables[i].id.lastIndexOf("-"));
+ var cb = document.getElementById("select-" + opt);
+ if (cb.value != "Custom")
+ paramtables[i].style.display = "none";
+}
+--></SCRIPT>
+</FORM>
+
+</DIV>
diff --git a/templates/ja/subscription-added.tmpl b/templates/ja/subscription-added.tmpl
new file mode 100644
index 000000000..e4ab98cf9
--- /dev/null
+++ b/templates/ja/subscription-added.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>{subscription_name} ã®è³¼èª­ã¯æ­£ã—ã追加ã•ã‚Œã¾ã—ãŸã€‚</P>
+
+</DIV>
diff --git a/templates/ja/subscription-canceled.tmpl b/templates/ja/subscription-canceled.tmpl
new file mode 100644
index 000000000..8787dad2b
--- /dev/null
+++ b/templates/ja/subscription-canceled.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>購読 #{notify_subscription_id} ã¯ã‚­ãƒ£ãƒ³ã‚»ãƒ«ã•ã‚Œã¾ã—ãŸã€‚</P>
+
+</DIV>
diff --git a/templates/ja/test-page.tmpl b/templates/ja/test-page.tmpl
new file mode 100644
index 000000000..6cdaa8751
--- /dev/null
+++ b/templates/ja/test-page.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{printer_name} ã®ãƒ†ã‚¹ãƒˆãƒšãƒ¼ã‚¸å°åˆ·</H2>
+
+<P>テストページをé€ä¿¡ã—ã¾ã—ãŸ; ジョブ ID 㯠<A HREF="/{SECTION}/{printer_name}">
+{printer_name}-{job_id}</A> ã§ã™ã€‚</P>
+
+</DIV>
diff --git a/templates/ja/trailer.tmpl b/templates/ja/trailer.tmpl
new file mode 100644
index 000000000..100d9f7ad
--- /dev/null
+++ b/templates/ja/trailer.tmpl
@@ -0,0 +1,8 @@
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS and the CUPS logo are trademarks of
+<A HREF="http://www.apple.com">Apple Inc.</A> CUPS is copyright 2007-2011 Apple
+Inc. All rights reserved.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/templates/ja/users.tmpl b/templates/ja/users.tmpl
new file mode 100644
index 000000000..b998c6b2b
--- /dev/null
+++ b/templates/ja/users.tmpl
@@ -0,0 +1,30 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
+
+<H2 CLASS="title">{printer_name} ã«è¨±å¯ã™ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">ユーザー:</TH>
+<TD>
+<INPUT TYPE='TEXT' NAME='users' SIZE='60' VALUE='{?requesting_user_name_allowed}{?requesting_user_name_denied}'>
+<BR>
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-allowed' {requesting_user_name_allowed?checked:}>ã“れらã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®å°åˆ·ã‚’許å¯
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-denied' {requesting_user_name_denied?checked:}>ã“れらã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®å°åˆ·ã‚’ç¦æ­¢
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>
+<INPUT TYPE="SUBMIT" VALUE="許å¯ã™ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®è¨­å®š">
+</TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/job-cancel.tmpl b/templates/job-cancel.tmpl
new file mode 100644
index 000000000..3e8fd4dad
--- /dev/null
+++ b/templates/job-cancel.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Cancel Job {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Job {job_id}</A> has been canceled.
+
+</DIV>
diff --git a/templates/job-hold.tmpl b/templates/job-hold.tmpl
new file mode 100644
index 000000000..58ce97fc9
--- /dev/null
+++ b/templates/job-hold.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Hold Job {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Job {job_id}</A> has been held from printing.
+
+</DIV>
diff --git a/templates/job-move.tmpl b/templates/job-move.tmpl
new file mode 100644
index 000000000..6ef0ff12e
--- /dev/null
+++ b/templates/job-move.tmpl
@@ -0,0 +1,27 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
+
+<H2 CLASS="title">{job_id?Move Job {job_id}:Move All Jobs}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">New Destination:</TH>
+<TD>
+<SELECT NAME="JOB_PRINTER_URI" SIZE="10">
+{[job_printer_uri]<OPTION VALUE="{job_printer_uri}">{job_printer_name}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{job_id?Move Job:Move Jobs}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+
+</DIV>
diff --git a/templates/job-moved.tmpl b/templates/job-moved.tmpl
new file mode 100644
index 000000000..c4db09696
--- /dev/null
+++ b/templates/job-moved.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{job_id?Move Job {job_id}:Move All Jobs}</H2>
+
+<P>{job_id?<A HREF="/jobs/{job_id}">Job {job_id}</A>:All jobs} moved to
+<A HREF="/{is_class?classes:printers}/{job_printer_name}">{job_printer_name}</A>.</P>
+
+</DIV>
diff --git a/templates/job-release.tmpl b/templates/job-release.tmpl
new file mode 100644
index 000000000..8eb9a9667
--- /dev/null
+++ b/templates/job-release.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Release Job {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Job {job_id}</A> has been released for printing.
+
+</DIV>
diff --git a/templates/job-restart.tmpl b/templates/job-restart.tmpl
new file mode 100644
index 000000000..b91ced926
--- /dev/null
+++ b/templates/job-restart.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Reprint Job {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Job {job_id}</A> has been restarted.
+
+</DIV>
diff --git a/templates/jobs-header.tmpl b/templates/jobs-header.tmpl
new file mode 100644
index 000000000..e7547ba7b
--- /dev/null
+++ b/templates/jobs-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">{?which_jobs=?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Show Active Jobs"></FORM>}
+{?which_jobs=completed?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="completed"><INPUT TYPE="SUBMIT" VALUE="Show Completed Jobs"></FORM>}
+{?which_jobs=all?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="all"><INPUT TYPE="SUBMIT" VALUE="Show All Jobs"></FORM>}</DIV>
+
+<P ALIGN="CENTER">{total=0?No jobs:Showing {#job_id} of {total} {?which_jobs=?active:{which_jobs=all?:completed}} job{total=1?:s}}.</P>
diff --git a/templates/jobs.tmpl b/templates/jobs.tmpl
new file mode 100644
index 000000000..625059f62
--- /dev/null
+++ b/templates/jobs.tmpl
@@ -0,0 +1,36 @@
+{#job_id=0?:
+<TABLE CLASS="list" SUMMARY="Job List">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> ID <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> ID <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Name</TH><TH>User</TH><TH>Size</TH><TH>Pages</TH><TH>State</TH><TH>Control</TH></TR>
+</THEAD>
+<TBODY>
+{[job_id]
+<TR VALIGN="TOP">
+<TD><A HREF="{job_printer_uri}">{job_printer_name}</A>-{job_id}&nbsp;</TD>
+<TD>{?job_name=?Unknown:{job_name}}&nbsp;</TD>
+<TD>{?job_originating_user_name=?Withheld:{job_originating_user_name}}&nbsp;</TD>
+<TD>{job_k_octets}k&nbsp;</TD>
+<TD>{job_media_sheets_completed=0?Unknown:{?job_media_sheets_completed}}&nbsp;</TD>
+<TD>{job_state=3?pending since<BR>{time_at_creation}:{job_state=4?held since<BR>{time_at_creation}:
+{job_state=5?processing since<BR>{time_at_processing}:{job_state=6?stopped:
+{job_state=7?canceled at<BR>{time_at_completed}:{job_state=8?aborted:completed at<BR>{time_at_completed}}}}}}}&nbsp;{job_printer_state_message?<BR>
+<EM>"{job_printer_state_message}"</EM>:}</TD>
+<TD>
+{job_preserved>0?{job_state>5?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}"><INPUT TYPE="SUBMIT" VALUE="Reprint Job"></FORM>:}:}
+{job_state=4?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Release Job"></FORM>:}
+{job_state=3?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Hold Job"></FORM>:}
+{job_state<7?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Cancel Job"></FORM>
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="Move Job"></FORM>:}
+&nbsp;</TD>
+</TR>
+}
+</TBODY>
+</TABLE>
+}
diff --git a/templates/list-available-printers.tmpl b/templates/list-available-printers.tmpl
new file mode 100644
index 000000000..a594439ee
--- /dev/null
+++ b/templates/list-available-printers.tmpl
@@ -0,0 +1,11 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Available Printers</H2>
+
+{#device_uri=0?<P>No printers found.</P>
+:<UL>{[device_uri]
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Local Printer"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Add This Printer"></FORM>
+{device_make_and_model} ({device_info})</LI>
+}</UL>}
+
+</DIV>
diff --git a/templates/modify-class.tmpl b/templates/modify-class.tmpl
new file mode 100644
index 000000000..31f7b9ce3
--- /dev/null
+++ b/templates/modify-class.tmpl
@@ -0,0 +1,34 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modify Class {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Description:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Location:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Members:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Modify Class"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/modify-printer.tmpl b/templates/modify-printer.tmpl
new file mode 100644
index 000000000..bdf3df604
--- /dev/null
+++ b/templates/modify-printer.tmpl
@@ -0,0 +1,42 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modify {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Description:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Human-readable description such as "HP LaserJet with Duplexer")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Location:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Human-readable location such as "Lab 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Connection:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Sharing:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+Share This Printer</TD>
+</TR>
+<TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Continue"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/norestart.tmpl b/templates/norestart.tmpl
new file mode 100644
index 000000000..6b3120337
--- /dev/null
+++ b/templates/norestart.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Change Settings</H2>
+
+<P>The server was not restarted because no changes were made to
+the configuration...</P>
+
+</DIV>
diff --git a/templates/option-boolean.tmpl b/templates/option-boolean.tmpl
new file mode 100644
index 000000000..e832ee102
--- /dev/null
+++ b/templates/option-boolean.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD>
+{[choices]<INPUT TYPE="RADIO" NAME="{keyword-1}" {choices={defchoice-1}?CHECKED:} VALUE="{choices}">{text}}
+</TD>
+</TR>
diff --git a/templates/option-conflict.tmpl b/templates/option-conflict.tmpl
new file mode 100644
index 000000000..3772295a8
--- /dev/null
+++ b/templates/option-conflict.tmpl
@@ -0,0 +1,7 @@
+<P><B>Error:</B> The following options are conflicting:</P>
+
+<UL>
+{[ckeyword]<LI><A HREF="#{ckeyword}">{ckeytext}</A>: {cchoice}</LI>
+}</UL>
+
+<P>Please change one or more of the options to resolve the conflicts.</P>
diff --git a/templates/option-header.tmpl b/templates/option-header.tmpl
new file mode 100644
index 000000000..464726a50
--- /dev/null
+++ b/templates/option-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="tab" ID="{group_id}">
+
+<H3 ALIGN="CENTER">{group}</H3>
+
+<TABLE WIDTH="100%">
diff --git a/templates/option-pickmany.tmpl b/templates/option-pickmany.tmpl
new file mode 100644
index 000000000..0da75e5d2
--- /dev/null
+++ b/templates/option-pickmany.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" MULTIPLE SIZE="10">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT></TD>
+</TR>
diff --git a/templates/option-pickone.tmpl b/templates/option-pickone.tmpl
new file mode 100644
index 000000000..890ef4e7d
--- /dev/null
+++ b/templates/option-pickone.tmpl
@@ -0,0 +1,18 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" ID="select-{keyword}" ONCHANGE="update_paramtable('{keyword}')">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT>
+{iscustom=1?<TABLE NAME="paramtable" id="{keyword}-params">{[params]
+<TR><TH CLASS="sublabel">{paramtext}:</TH>
+<TD>{params=Units?<SELECT NAME="{keyword-1}.{params}">
+<OPTION VALUE="pt"{paramvalue=pt? SELECTED:}>Points</OPTION>
+<OPTION VALUE="mm"{paramvalue=mm? SELECTED:}>Millimeters</OPTION>
+<OPTION VALUE="cm"{paramvalue=cm? SELECTED:}>Centimeters</OPTION>
+<OPTION VALUE="in"{paramvalue=in? SELECTED:}>Inches</OPTION>
+<OPTION VALUE="ft"{paramvalue=ft? SELECTED:}>Feet</OPTION>
+<OPTION VALUE="m"{paramvalue=m? SELECTED:}>Meters</OPTION>
+</SELECT>:<INPUT TYPE="{inputtype}" NAME="{keyword-1}.{params}" VALUE="{paramvalue}">}</TD></TR>
+}</TABLE>
+</TD>:}
+</TR>
diff --git a/templates/option-trailer.tmpl b/templates/option-trailer.tmpl
new file mode 100644
index 000000000..17c928109
--- /dev/null
+++ b/templates/option-trailer.tmpl
@@ -0,0 +1,5 @@
+</TABLE>
+
+<P ALIGN="CENTER"><INPUT TYPE="SUBMIT" VALUE="Set Default Options"></P>
+
+</DIV> \ No newline at end of file
diff --git a/templates/pager.tmpl b/templates/pager.tmpl
new file mode 100644
index 000000000..ebd688d51
--- /dev/null
+++ b/templates/pager.tmpl
@@ -0,0 +1,6 @@
+<TABLE CLASS="inset" SUMMARY="Paging Bar">
+<TR>
+ <TD WIDTH="50%">{PREV?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{PREV}"><INPUT TYPE="SUBMIT" VALUE="&#x25c0; Show Previous"></FORM>:&nbsp;}</TD>
+ <TD WIDTH="50%" ALIGN="RIGHT">{NEXT?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{NEXT}"><INPUT TYPE="SUBMIT" VALUE="Show Next &#x25b6;"></FORM>:&nbsp;}</TD>
+</TR>
+</TABLE>
diff --git a/templates/pl/add-class.tmpl b/templates/pl/add-class.tmpl
new file mode 100644
index 000000000..d1f4b66bf
--- /dev/null
+++ b/templates/pl/add-class.tmpl
@@ -0,0 +1,40 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Dodawanie klasy</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Nazwa:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Może zawierać wszystkie drukowalne znaki, oprócz "/", "#" i spacji)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Opis:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Opis czytelny dla człowieka, taki jak "HP LaserJet z dupleksem")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Położenie:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Położenie czytelne dla człowieka, takie jak "Laboratorium 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Członkowie:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Dodaj klasÄ™"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/pl/add-printer.tmpl b/templates/pl/add-printer.tmpl
new file mode 100644
index 000000000..45b50a0d4
--- /dev/null
+++ b/templates/pl/add-printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Dodawanie drukarki</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+{?current_make!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE" VALUE="{current_make}">:}
+{?current_make_and_model!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{current_make_and_model}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Nazwa:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?template_name}"><BR>
+<SMALL>(Może zawierać wszystkie drukowalne znaki, oprócz "/", "#" i spacji)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Opis:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_INFO}"><BR>
+<SMALL>(Opis czytelny dla człowieka, taki jak "HP LaserJet z dupleksem")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Położenie:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127" VALUE="{?PRINTER_LOCATION}"><BR>
+<SMALL>(Położenie czytelne dla człowieka, takie jak "Laboratorium 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Połączenie:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Współdzielenie:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+Współdzielenie tej drukarki</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Kontynuuj"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/pl/add-rss-subscription.tmpl b/templates/pl/add-rss-subscription.tmpl
new file mode 100644
index 000000000..f11ba610a
--- /dev/null
+++ b/templates/pl/add-rss-subscription.tmpl
@@ -0,0 +1,44 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
+
+<H2 CLASS="title">Dodawanie subskrypcji RSS</H2>
+
+<TABLE SUMMARY="Formularz dodawania subskrypcji RSS">
+<TR>
+<TH CLASS="label">Nazwa:</TH>
+<TD COLSPAN="5"><INPUT TYPE="TEXT" NAME="SUBSCRIPTION_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?SUBSCRIPTION_NAME}"><BR>
+<SMALL>(Może zawierać wszystkie drukowalne znaki, oprócz spacji, "/", "?" i "#")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Kolejka:</TH>
+<TD COLSPAN="5"><SELECT NAME="PRINTER_URI" SIZE="10"><OPTION VALUE="#ALL#"{?PRINTER_URI=#ALL#? SELECTED:}>Wszystkie kolejki</OPTION>{[printer_name]<OPTION VALUE="{printer_uri_supported}"{?PRINTER_URI={printer_uri_supported}? SELECTED:}>{printer_name}</OPTION>}</SELECT></TD>
+</TR>
+<TR VALIGN="TOP">
+<TH CLASS="label">Zdarzenia:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CREATED" {?EVENT_JOB_CREATED}>Utworzono zadanie<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_COMPLETED" {?EVENT_JOB_COMPLETED}>Ukończono zadanie<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_STOPPED" {?EVENT_JOB_STOPPED}>Zatrzymano zadanie<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CONFIG_CHANGED" {?EVENT_JOB_CONFIG_CHANGED}>Zmieniono opcje zadania</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_STOPPED" {?EVENT_PRINTER_STOPPED}>Zatrzymano kolejkÄ™<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_ADDED" {?EVENT_PRINTER_ADDED}>Dodano kolejkÄ™<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_MODIFIED" {?EVENT_PRINTER_MODIFIED}>Zmodyfikowano kolejkÄ™<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_DELETED" {?EVENT_PRINTER_DELETED}>Usunięto kolejkę</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STARTED" {?EVENT_SERVER_STARTED}>Uruchomiono serwer<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STOPPED" {?EVENT_SERVER_STOPPED}>Zatrzymano serwer<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_RESTARTED" {?EVENT_SERVER_RESTARTED}>Ponownie uruchomiono serwer<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_AUDIT" {?EVENT_SERVER_AUDIT}>Audytowanie bezpieczeństwa serwera</TD>
+</TR>
+<TR>
+<TH CLASS="label">Maksymalna liczba zdarzeń w kanale:</TH>
+<TD COLSPAN="5"><INPUT TYPE="NUMBER" NAME="MAX_EVENTS" SIZE="4" MAXLENGTH="4" VALUE="{MAX_EVENTS?{MAX_EVENTS}:20}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD COLSPAN="5"><INPUT TYPE="SUBMIT" VALUE="Dodaj subskrypcjÄ™ RSS"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/pl/admin.tmpl b/templates/pl/admin.tmpl
new file mode 100644
index 000000000..b997357be
--- /dev/null
+++ b/templates/pl/admin.tmpl
@@ -0,0 +1,110 @@
+<TABLE CLASS="indent" SUMMARY="Zadania administracji">
+<TR><TD VALIGN="TOP">
+
+<H2 CLASS="title">Drukarki</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Dodawanie drukarki"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Wyszukiwanie nowych drukarek"></FORM>
+<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="ZarzÄ…dzanie drukarkami"></FORM>
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="Eksportowanie drukarek do Samby"></FORM>:}
+</P>
+
+<H2 CLASS="title">Klasy</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Dodawanie klasy"></FORM>
+<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="ZarzÄ…dzanie klasami"></FORM>
+</P>
+
+<H2 CLASS="title">Zadania</H2>
+
+<P>
+<FORM ACTION="/jobs/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="ZarzÄ…dzanie zadaniami"></FORM>
+</P>
+
+</TD><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TD VALIGN="TOP">
+
+<H2 CLASS="title">Serwery</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Modyfikowanie pliku konfiguracji"></FORM>
+<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Przeglądanie dziennika dostępu"></FORM>
+<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Przeglądanie dziennika błędów"></FORM>
+<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="PrzeglÄ…danie dziennika stron"></FORM>
+</P>
+
+{SETTINGS_ERROR?<P>{SETTINGS_MESSAGE}</P>
+<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+
+{ADVANCEDSETTINGS?<P><B>Ustawienia serwera\:</B></P>
+
+<P><A HREF="/admin/">Zaawansowane <SMALL>&#x25bc;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="HIDDEN" NAME="ADVANCEDSETTINGS" VALUE="YES">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Wyświetlanie drukarek współdzielonych przez inne systemy<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protokoły\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_CUPS" {?browse_remote_cups}> CUPS
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_LDAP" {?browse_remote_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_SLP" {?browse_remote_slp}> SLP:}<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Współdzielenie drukarek podłączonych do tego systemu<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Maksymalna liczba klientów\:
+<INPUT TYPE="TEXT" NAME="MAX_CLIENTS" VALUE="{?max_clients}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protokoły\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_CUPS" {?browse_local_cups}> CUPS
+{HAVE_DNSSD?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_DNSSD" {?browse_local_dnssd}> DNS-SD:}
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_LDAP" {?browse_local_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_SLP" {?browse_local_slp}> SLP:}<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Zezwolenie na drukowanie z Internetu<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="BROWSE_WEB_IF" {?browse_web_if}> Rozgłaszanie interfejsu WWW<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Zezwolenie na zdalnÄ… administracjÄ™<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Używanie uwierzytelniania Kerberosa (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Zezwolenie użytkownikom na anulowanie każdego zadania (nie tylko ich własnego)<BR>
+<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_HISTORY" {?preserve_job_history}> Przechowywanie plików zadań<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Liczba zadań\:
+<INPUT TYPE="TEXT" NAME="MAX_JOBS" VALUE="{?max_jobs}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_FILES" {?preserve_job_files}> Przechowywanie plików wydruków zadań<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Zapisywanie informacji debugowania do naprawiania problemów<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Maksymalny rozmiar pliku dziennika\:
+<INPUT TYPE="TEXT" NAME="MAX_LOG_SIZE" VALUE="{?max_log_size}" SIZE="6"></P>
+
+:<P><B>Ustawienia serwera:</B></P>
+
+<P><A HREF="/admin/?ADVANCEDSETTINGS=YES">Zaawansowane <SMALL>&#x25b6;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Wyświetlanie drukarek współdzielonych przez inne systemy<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Współdzielenie drukarek połączonych do tego systemu<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Zezwolenie na drukowanie z Internetu<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Zezwolenie na zdalnÄ… administracjÄ™<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Używanie uwierzytelniania Kerberosa (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Zezwolenie użytkownikom na anulowanie każdego zadania (nie tylko ich własnego)<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Zapisywanie informacji debugowania do naprawiania problemów</P>
+
+}
+<P><INPUT TYPE="SUBMIT" NAME="CHANGESETTINGS" VALUE="Zmień ustawienia"></P>
+
+</FORM>}
+
+</TD></TR>
+</TABLE>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Subskrypcje RSS</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Dodawanie subskrypcji RSS"></FORM>
+</P>
+
+</DIV>
+
+{notify_subscription_id?<TABLE CLASS="list" SUMMARY="Subskrypcje RSS">
+<THEAD><TR><TH>Name</TH><TH>Zdarzenia</TH><TH>Nazwa kolejki</TH></TR></THEAD>
+<TBODY>{[notify_subscription_id]
+<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Anuluj subskrypcjÄ™ RSS"></FORM>&nbsp;</TD><TD>{notify_events}</TD><TD NOWRAP>&nbsp;{notify_printer_name?{notify_printer_name}:Wszystkie kolejki}</TD></TR>}
+</TBODY>
+</TABLE>:}
diff --git a/templates/pl/choose-device.tmpl b/templates/pl/choose-device.tmpl
new file mode 100644
index 000000000..445745624
--- /dev/null
+++ b/templates/pl/choose-device.tmpl
@@ -0,0 +1,54 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modyfikowanie {printer_name}:Dodawanie drukarki}</H2>
+
+{CUPS_GET_DEVICES_DONE?:<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Busy Indicator"> Wyszukiwanie drukarek...</P>}
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+{op=add-printer?:<TR>
+<TH CLASS="label">Bieżące połączenie:</TH>
+<TD><INPUT TYPE="RADIO" NAME="DEVICE_URI" VALUE="{current_device_uri}" CHECKED>
+{current_device_uri}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Lokalne drukarki:</TH>
+<TD>
+{[device_uri]{device_class!network?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}}
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Wykryte drukarki sieciowe:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}:}}
+</TD>
+</TR>
+<TR>
+<TR>
+<TH CLASS="label">Inne drukarki sieciowe:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?:<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+}:}}
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Kontynuuj"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/pl/choose-make.tmpl b/templates/pl/choose-make.tmpl
new file mode 100644
index 000000000..c0ec622a7
--- /dev/null
+++ b/templates/pl/choose-make.tmpl
@@ -0,0 +1,64 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modify {printer_name}:Dodawanie drukarki}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Nazwa:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Opis:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Położenie:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Połączenie:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Współdzielenie:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+{?printer_is_shared=?Do Not:{?printer_is_shared=0?Do Not:}} Współdzielenie tej drukarki</TD>
+</TR>
+<TR>
+<TH CLASS="label">Producent:</TH>
+<TD>
+<SELECT NAME="PPD_MAKE" SIZE="10">
+{[ppd_make]<OPTION VALUE="{ppd_make}" {?current_make={ppd_make}?SELECTED:}>{ppd_make}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Kontynuuj"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>&nbsp;</TD>
+</TR>
+<TR>
+<TH CLASS="label">Lub podaj plik PPD:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?Dodaj drukarkÄ™:Zmodyfikuj drukarkÄ™}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/pl/choose-model.tmpl b/templates/pl/choose-model.tmpl
new file mode 100644
index 000000000..9438cee56
--- /dev/null
+++ b/templates/pl/choose-model.tmpl
@@ -0,0 +1,60 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modyfikowanie {printer_name}:Dodawanie drukarki}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Nazwa:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Opis:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Położenie:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Połączenie:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Współdzielenie:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+{?printer_is_shared=?Nie:{?printer_is_shared=0?Nie:}} współdziel tej drukarki</TD>
+</TR>
+<TR>
+<TH CLASS="label">Producent:</TH>
+<TD>{PPD_MAKE} <INPUT TYPE="SUBMIT" NAME="SELECT_MAKE" VALUE="Wybierz innego producenta"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Model:</TH>
+<TD>
+<SELECT NAME="PPD_NAME" SIZE="10">
+{op=add-printer?:<OPTION VALUE="__no_change__" SELECTED>Bieżący sterownik - {current_make_and_model}</OPTION>:}
+{[ppd_name]<OPTION VALUE="{ppd_name}" {op=modify-printer?:{?current_make_and_model={ppd_make_and_model}?SELECTED:}}>{ppd_make_and_model} ({ppd_natural_language})
+}</SELECT>
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Lub podaj plik PPD:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?Dodaj drukarkÄ™:Zmodyfikuj drukarkÄ™}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/pl/choose-serial.tmpl b/templates/pl/choose-serial.tmpl
new file mode 100644
index 000000000..8bbf8c8c2
--- /dev/null
+++ b/templates/pl/choose-serial.tmpl
@@ -0,0 +1,52 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modyfikowanie {printer_name}:Dodawanie drukarki}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Połączenie:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Prędkość w baudach:</TH>
+<TD><SELECT NAME="BAUDRATE">
+{[baudrates]<OPTION {?baudrate={baudrates}?SELECTED:}>{baudrates}}
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Równorzędność:</TH>
+<TD><SELECT NAME="PARITY">
+<OPTION VALUE="none" {?parity=none?SELECTED:}>None
+<OPTION VALUE="even" {?parity=even?SELECTED:}>Even
+<OPTION VALUE="odd" {?parity=odd?SELECTED:}>Odd
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Bity danych:</TH>
+<TD><SELECT NAME="BITS">
+<OPTION {?bits=8?SELECTED:}>8
+<OPTION {?bits=7?SELECTED:}>7
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Kontrola przepływu:</TH>
+<TD><SELECT NAME="FLOW">
+<OPTION VALUE="none" {?flow=none?SELECTED:}>Brak
+<OPTION VALUE="soft" {?flow=soft?SELECTED:}>XON/XOFF (programowa)
+<OPTION VALUE="hard" {?flow=hard?SELECTED:}>RTS/CTS (sprzętowa)
+<OPTION VALUE="dtrdsr" {?flow=dtrdsr?SELECTED:}>DTR/DSR (sprzętowa)
+</SELECT></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Kontynuuj"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/pl/choose-uri.tmpl b/templates/pl/choose-uri.tmpl
new file mode 100644
index 000000000..88201b925
--- /dev/null
+++ b/templates/pl/choose-uri.tmpl
@@ -0,0 +1,44 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Modyfikowanie {printer_name}:Dodawanie drukarki}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Połączenie:</TH>
+<TD><INPUT TYPE="URL" SIZE="60" MAXLENGTH="1024" NAME="DEVICE_URI" VALUE="{current_device_uri?{current_device_uri}:{device_uri}}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>Przykłady:
+<PRE>
+ http://nazwakomputera:631/ipp/
+ http://nazwakomputera:631/ipp/port1
+
+ ipp://nazwakomputera/ipp/
+ ipp://nazwakomputera/ipp/port1
+
+ lpd://nazwakomputera/kolejka
+
+ socket://nazwakomputera
+ socket://nazwakomputera:9100
+</PRE>
+
+<P>Proszę zobaczyć <A HREF="/help/network.html" TARGET="_blank">"Drukarki
+sieciowe"</A>, aby uzyskać poprawne URI dla drukarki.</P>
+
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Kontynuuj"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/pl/class-added.tmpl b/templates/pl/class-added.tmpl
new file mode 100644
index 000000000..2bee7d8ca
--- /dev/null
+++ b/templates/pl/class-added.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Dodawanie klasy</H2>
+
+<P>Klasa <A HREF="/classes/{printer_name}">{printer_name}</A> została pomyślnie
+dodana.
+
+</DIV>
diff --git a/templates/pl/class-confirm.tmpl b/templates/pl/class-confirm.tmpl
new file mode 100644
index 000000000..55cb5ed4e
--- /dev/null
+++ b/templates/pl/class-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Usuwanie klasy {printer_name}</H2>
+
+<P><B>Ostrzeżenie:</B> Usunąć klasę
+{printer_name}?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Usuń klasę"></FORM></P>
+
+</DIV>
diff --git a/templates/pl/class-deleted.tmpl b/templates/pl/class-deleted.tmpl
new file mode 100644
index 000000000..1a78c903e
--- /dev/null
+++ b/templates/pl/class-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Usuwanie klasy {printer_name}</H2>
+
+<P>Klasa {printer_name} została pomyślnie usunięta.
+
+</DIV>
diff --git a/templates/pl/class-jobs-header.tmpl b/templates/pl/class-jobs-header.tmpl
new file mode 100644
index 000000000..83dcfbcd5
--- /dev/null
+++ b/templates/pl/class-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">Zadania</H3>
+</DIV>
diff --git a/templates/pl/class-modified.tmpl b/templates/pl/class-modified.tmpl
new file mode 100644
index 000000000..be91caaed
--- /dev/null
+++ b/templates/pl/class-modified.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modyfikowanie klasy {printer_name}</H2>
+
+<P>Klasa <A HREF="/classes/{printer_name}">{printer_name}</A> została
+pomyślnie zmodyfikowana.
+
+</DIV>
diff --git a/templates/pl/class.tmpl b/templates/pl/class.tmpl
new file mode 100644
index 000000000..5c015ac5c
--- /dev/null
+++ b/templates/pl/class.tmpl
@@ -0,0 +1,44 @@
+<DIV CLASS="indent">
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?Bezczynna:{printer_state=4?Przetwarzanie:Wstrzymane}},
+{printer_is_accepting_jobs=0?Odrzucanie zadań:Akceptowanie zadań},
+{server_is_sharing_printers=0?Nie:{printer_is_shared=0?Nie:}} Współdzielona{default_name={printer_name}?, Domyślne serwera:})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">Konserwacja</OPTION>
+<OPTION VALUE="print-test-page">Drukowanie strony próbnej</OPTION>
+{printer_state=5?<OPTION VALUE="start-class">Wznów klasę</OPTION>:<OPTION VALUE="stop-class">Wstrzymaj klasę</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Akceptuj zadania</OPTION>:<OPTION VALUE="reject-jobs">Odrzucaj zadania</OPTION>}
+<OPTION VALUE="move-jobs">PrzenieÅ› wszystkie zadania</OPTION>
+<OPTION VALUE="purge-jobs">Anuluj wszystkie zadania</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Przejdź" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="1">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">Administracja</OPTION>
+<OPTION VALUE="modify-class">Zmodyfikuj klasÄ™</OPTION>
+<OPTION VALUE="delete-class">Usuń klasę</OPTION>
+<OPTION VALUE="set-class-options">Ustaw domyślne opcje</OPTION>
+<OPTION VALUE="set-as-default">Ustaw jako domyślne serwera</OPTION>
+<OPTION VALUE="set-allowed-users">Ustaw zezwolonych użytkowników</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Przejdź" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Opis:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Położenie:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Członkowie:</TH><TD>{?member_uris=?None:{member_uris}}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Domyślne:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:unknown}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/pl/classes-header.tmpl b/templates/pl/classes-header.tmpl
new file mode 100644
index 000000000..8482fd19c
--- /dev/null
+++ b/templates/pl/classes-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?Brak klas:Wyświetlanie {#printer_name} z {total} klas{total=1?:es}}.</P>
diff --git a/templates/pl/classes.tmpl b/templates/pl/classes.tmpl
new file mode 100644
index 000000000..1d8c766da
--- /dev/null
+++ b/templates/pl/classes.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Lista klas">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Nazwa kolejki <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Nazwa kolejki <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Opis</TH><TH>Położenie</TH><TH>Members</TH><TH>Stan</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{?member_uris=?Brak:{member_uris}}</TD><TD>{printer_state=3?Idle:{printer_state=4?Przetwarzanie:Wstrzymane}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/pl/command.tmpl b/templates/pl/command.tmpl
new file mode 100644
index 000000000..9a87439ca
--- /dev/null
+++ b/templates/pl/command.tmpl
@@ -0,0 +1,12 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{title} On {printer_name}</H2>
+
+<P>{job_state>5?:<IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16"
+ALIGN="ABSMIDDLE" ALT="Busy Indicator"> }Printer command job
+{job_state=3?pending:{job_state=4?held:
+{job_state=5?processing:{job_state=6?stopped:
+{job_state=7?canceled:{job_state=8?aborted:completed}}}}}}{job_state=9?:{job_printer_state_message?,
+<EM>"{job_printer_state_message}"</EM>:}}</P>
+
+</DIV>
diff --git a/templates/pl/edit-config.tmpl b/templates/pl/edit-config.tmpl
new file mode 100644
index 000000000..3688ee24c
--- /dev/null
+++ b/templates/pl/edit-config.tmpl
@@ -0,0 +1,24 @@
+<SCRIPT TYPE="text/javascript">
+function reset_config()
+{
+ document.cups.CUPSDCONF.value = "{?cupsdconf_default}";
+}
+</SCRIPT>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modyfikowanie pliku konfiguracji</H2>
+
+<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+
+<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
+
+<P><INPUT TYPE="SUBMIT" NAME="SAVECHANGES" VALUE="Zapisz zmiany">
+<INPUT TYPE="BUTTON" VALUE="Użyj domyślnego pliku konfiguracji"
+onClick="reset_config();"></P>
+
+</FORM>
+
+</DIV>
diff --git a/templates/pl/error-op.tmpl b/templates/pl/error-op.tmpl
new file mode 100644
index 000000000..b9e5f7194
--- /dev/null
+++ b/templates/pl/error-op.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{?title} {?printer_name} BÅ‚Ä…d</H2>
+
+<P>BÅ‚Ä…d:</P>
+
+<BLOCKQUOTE>Nieznana operacja "{op}"!</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/pl/error.tmpl b/templates/pl/error.tmpl
new file mode 100644
index 000000000..f9992930b
--- /dev/null
+++ b/templates/pl/error.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{?title} {?printer_name} BÅ‚Ä…d</H2>
+
+<P>{?message?{message}:BÅ‚Ä…d:}</P>
+
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/pl/header.tmpl.in b/templates/pl/header.tmpl.in
new file mode 100644
index 000000000..ca1774b89
--- /dev/null
+++ b/templates/pl/header.tmpl.in
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{title} - CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+ {refresh_page?<META HTTP-EQUIV="Refresh" CONTENT="{refresh_page}">:}
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="unsel"><A HREF="/">&nbsp;&nbsp;Strona domowa&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=admin?:un}sel"><A HREF="/admin">&nbsp;&nbsp;Administracja&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=classes?:un}sel"><A HREF="/classes/">&nbsp;&nbsp;Klasy&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=help?:un}sel"><A HREF="/help/">&nbsp;&nbsp;Pomoc&nbsp;online&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=jobs?:un}sel"><A HREF="/jobs/">&nbsp;&nbsp;Zadania&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=printers?:un}sel"><A HREF="/printers/">&nbsp;&nbsp;Drukarki&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="Search Help"
+VALUE="{SECTION=help?{?QUERY}:}" AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+<TR><TD COLSPAN="9">&nbsp;</TD></TR>
+</TABLE>
diff --git a/templates/pl/help-header.tmpl b/templates/pl/help-header.tmpl
new file mode 100644
index 000000000..98b21676b
--- /dev/null
+++ b/templates/pl/help-header.tmpl
@@ -0,0 +1,51 @@
+<DIV CLASS="indent">
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET">
+{TOPIC?<INPUT TYPE="HIDDEN" NAME="TOPIC" VALUE="{TOPIC}">:}
+
+<P ALIGN="CENTER"><B>Wyszukaj w
+{HELPTITLE?{HELPTITLE}:{TOPIC?{TOPIC}:Wszystkie dokumenty}}:</B> <INPUT
+TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER=""
+AUTOSAVE="org.cups.help" RESULTS="20">
+<INPUT TYPE="SUBMIT" NAME="SEARCH" VALUE="Znajdź">
+<INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="Wyczyść"></P>
+
+</FORM>
+
+<!-- Zakładki -->
+<DIV CLASS="sidebar"><TABLE CLASS="inset" SUMMARY="Zawartość">
+<TR><TD>
+
+<H3 CLASS="title">Dokumenty pomocy online</H3>
+
+<P CLASS="l0"><A HREF="/help/{QUERY??QUERY={QUERY}:}">Wszystkie dokumenty</A></P>
+<HR>
+
+{[BMTEXT]<P CLASS="l{BMINDENT}"><A HREF="{BMLINK}">{BMTEXT}</A></P>
+}
+</TD></TR>
+</TABLE></DIV>
+
+{QUERY?<P>Wyniki wyszukiwania w {HELPFILE?{HELPTITLE}:{TOPIC?{TOPIC}:Wszystkie dokumenty}}\:</P>
+{QTEXT?<UL>
+{[QTEXT]<LI><A HREF="{QLINK}">{QTEXT}</A>{QPTEXT? (in <I><A HREF="{QPLINK}">{QPTEXT}</A></I>):}</LI>}
+{QTEXT?</UL>:}
+:<P>Nie znaleziono.</P>}
+<HR NOSHADE>:}
+{HELPTITLE?<H1>{HELPTITLE}</H1>
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="PRINTABLE" VALUE="YES"><INPUT TYPE="SUBMIT" VALUE="Wyświetl wersję do druku"></FORM>:
+
+<H1>Pomoc online</H1>
+
+<P>To jest interfejs pomocy online CUPS. Należy podać wyszukiwane słowa
+powyżej lub kliknąć jeden z odnośników do dokumentacji, aby wyświetlić
+informacje o pomocy online.</P>
+
+<P>Nowi użytkownicy CUPS powinni przeczytać stronę "<a
+href="/help/overview.html">Przegląd CUPS</a>". Zaawansowani użytkownicy
+powinni przeczytać stronę "<a href="/help/whatsnew.html">Co nowego w CUPS
+1.4</a>".</P>
+
+<P><A HREF="http://www.cups.org/">Strona domowa CUPS</A> także
+dostarcza wiele zasobów, w tym fora dyskusyjne użytkowników, odpowiedzi
+na najczęściej zadawane pytania oraz formularz do wysyłania raportów
+błędów i próśb o nowe funkcje.</P>}
diff --git a/templates/pl/help-printable.tmpl b/templates/pl/help-printable.tmpl
new file mode 100644
index 000000000..2463c1630
--- /dev/null
+++ b/templates/pl/help-printable.tmpl
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{HELPTITLE}</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups-printable.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
diff --git a/templates/pl/help-trailer.tmpl b/templates/pl/help-trailer.tmpl
new file mode 100644
index 000000000..4c1ebed85
--- /dev/null
+++ b/templates/pl/help-trailer.tmpl
@@ -0,0 +1 @@
+</DIV>
diff --git a/templates/pl/job-cancel.tmpl b/templates/pl/job-cancel.tmpl
new file mode 100644
index 000000000..bcfffcf0d
--- /dev/null
+++ b/templates/pl/job-cancel.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Anulowanie zadania {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Zadanie {job_id}</A> zostało anulowane.
+
+</DIV>
diff --git a/templates/pl/job-hold.tmpl b/templates/pl/job-hold.tmpl
new file mode 100644
index 000000000..8827d9e28
--- /dev/null
+++ b/templates/pl/job-hold.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Wstrzymywanie zadania {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Drukowanie zadania {job_id}</A> zostało wstrzymane.
+
+</DIV>
diff --git a/templates/pl/job-move.tmpl b/templates/pl/job-move.tmpl
new file mode 100644
index 000000000..bd77beeb2
--- /dev/null
+++ b/templates/pl/job-move.tmpl
@@ -0,0 +1,27 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
+
+<H2 CLASS="title">{job_id?Przenoszenie zadanie {job_id}:Przenoszenie wszystkich zadań}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">Nowe miejsce docelowe:</TH>
+<TD>
+<SELECT NAME="JOB_PRINTER_URI" SIZE="10">
+{[job_printer_uri]<OPTION VALUE="{job_printer_uri}">{job_printer_name}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{job_id?PrzenieÅ› zadanie:PrzenieÅ› zadania}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+
+</DIV>
diff --git a/templates/pl/job-moved.tmpl b/templates/pl/job-moved.tmpl
new file mode 100644
index 000000000..bd3db7686
--- /dev/null
+++ b/templates/pl/job-moved.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{job_id?Przenoszenie zadania {job_id}:Przenoszenie wszystkich zadań}</H2>
+
+<P>{job_id?<A HREF="/jobs/{job_id}">Zadanie {job_id}</A>:Wszystkie zadania} zostało przeniesione do
+<A HREF="{job_printer_uri}">{job_printer_name}</A>.</P>
+
+</DIV>
diff --git a/templates/pl/job-release.tmpl b/templates/pl/job-release.tmpl
new file mode 100644
index 000000000..09bffda03
--- /dev/null
+++ b/templates/pl/job-release.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Zwalnianie zadania {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Drukowanie zadania {job_id}</A> zostało zwolnione.
+
+</DIV>
diff --git a/templates/pl/job-restart.tmpl b/templates/pl/job-restart.tmpl
new file mode 100644
index 000000000..6edf8b247
--- /dev/null
+++ b/templates/pl/job-restart.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ponowne drukowanie zadania {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Zadanie {job_id}</A> zostało ponownie uruchomione.
+
+</DIV>
diff --git a/templates/pl/jobs-header.tmpl b/templates/pl/jobs-header.tmpl
new file mode 100644
index 000000000..ea8718d12
--- /dev/null
+++ b/templates/pl/jobs-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">{?which_jobs=?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Wyświetl aktywne zadania"></FORM>}
+{?which_jobs=completed?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="completed"><INPUT TYPE="SUBMIT" VALUE="Wyświetl zakończone zadania"></FORM>}
+{?which_jobs=all?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="all"><INPUT TYPE="SUBMIT" VALUE="Wyświetl wszystkie zadania"></FORM>}</DIV>
+
+<P ALIGN="CENTER">{total=0?Brak zadań:Wyświetlanie {#job_id} z {total} {?which_jobs=?aktywnych:{which_jobs=all?:zakończonych}} zadań{total=1?:s}}.</P>
diff --git a/templates/pl/jobs.tmpl b/templates/pl/jobs.tmpl
new file mode 100644
index 000000000..665bdffbd
--- /dev/null
+++ b/templates/pl/jobs.tmpl
@@ -0,0 +1,37 @@
+{#job_id=0?:
+<TABLE CLASS="list" SUMMARY="Lista zadań">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Identyfikator <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Identyfikator <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Nazwa</TH><TH>Użytkownik</TH><TH>Rozmiar</TH><TH>Strony</TH><TH>Stan</TH><TH>Kontrola</TH></TR>
+</THEAD>
+<TBODY>
+{[job_id]
+<TR VALIGN="TOP">
+<TD><A HREF="{job_printer_uri}">{job_printer_name}</A>-{job_id}&nbsp;</TD>
+<TD>{?job_name=?Unknown:{job_name}}&nbsp;</TD>
+<TD>{job_originating_user_name}&nbsp;</TD>
+<TD>{job_k_octets}k&nbsp;</TD>
+<TD>{job_media_sheets_completed=0?Unknown:{?job_media_sheets_completed}}&nbsp;</TD>
+<TD>{job_state=3?oczekiwanie od<BR>{time_at_creation}:{job_state=4?wstrzymane od<BR>{time_at_creation}:
+{job_state=5?przetwarzanie od<BR>{time_at_processing}:{job_state=6?zatrzymano:
+{job_state=7?anulowano o<BR>{time_at_completed}:{job_state=8?przerwano:zakończono o<BR>{time_at_completed}}}}}}}&nbsp;{job_printer_state_message?<BR>
+<EM>"{job_printer_state_message}"</EM>:}</TD>
+<TD>
+{job_preserved>0?{job_state>5?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Ponownie wydrukuj zadanie"></FORM>:}:}
+{job_state=4?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Zwolnij zadanie"></FORM>:}
+{job_state=3?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Wstrzymaj zadanie"></FORM>:}
+{job_state<7?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Anuluj zadanie"></FORM>
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="PrzenieÅ› zadanie"></FORM>:}
+&nbsp;</TD>
+</TR>
+}
+</TBODY>
+</TABLE>
+}
diff --git a/templates/pl/list-available-printers.tmpl b/templates/pl/list-available-printers.tmpl
new file mode 100644
index 000000000..aad6a49fa
--- /dev/null
+++ b/templates/pl/list-available-printers.tmpl
@@ -0,0 +1,11 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Dostępne drukarki</H2>
+
+{#device_uri=0?<P>Nie znaleziono drukarek.</P>
+:<UL>{[device_uri]
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Lokalna drukarka"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Dodaj tÄ™ drukarkÄ™"></FORM>
+{device_make_and_model} ({device_info})</LI>
+}</UL>}
+
+</DIV>
diff --git a/templates/pl/modify-class.tmpl b/templates/pl/modify-class.tmpl
new file mode 100644
index 000000000..b8a213076
--- /dev/null
+++ b/templates/pl/modify-class.tmpl
@@ -0,0 +1,34 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modyfikowanie klasy {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Opis:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Położenie:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Członkowie:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Zmodyfikuj klasÄ™"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/pl/modify-printer.tmpl b/templates/pl/modify-printer.tmpl
new file mode 100644
index 000000000..a63f4781c
--- /dev/null
+++ b/templates/pl/modify-printer.tmpl
@@ -0,0 +1,42 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modyfikowanie {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Opis:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Opis czytelny dla człowieka, taki jak "HP LaserJet z dupleksem")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Położenie:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(Położenie czytelne dla człowieka, takie jak "Laboratorium 1")</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Połączenie:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Współdzielenie:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+Share This Printer</TD>
+</TR>
+<TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Kontynuuj"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/pl/norestart.tmpl b/templates/pl/norestart.tmpl
new file mode 100644
index 000000000..d29b0f4c7
--- /dev/null
+++ b/templates/pl/norestart.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Zmienianie ustawień</H2>
+
+<P>Serwer nie został ponownie uruchomiony, ponieważ nie wprowadzono żadnych zmian do
+konfiguracji...</P>
+
+</DIV>
diff --git a/templates/pl/option-boolean.tmpl b/templates/pl/option-boolean.tmpl
new file mode 100644
index 000000000..e832ee102
--- /dev/null
+++ b/templates/pl/option-boolean.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD>
+{[choices]<INPUT TYPE="RADIO" NAME="{keyword-1}" {choices={defchoice-1}?CHECKED:} VALUE="{choices}">{text}}
+</TD>
+</TR>
diff --git a/templates/pl/option-conflict.tmpl b/templates/pl/option-conflict.tmpl
new file mode 100644
index 000000000..708ba4c2f
--- /dev/null
+++ b/templates/pl/option-conflict.tmpl
@@ -0,0 +1,7 @@
+<P><B>Błąd:</B> następujące opcje są w konflikcie ze sobą:</P>
+
+<UL>
+{[ckeyword]<LI><A HREF="#{ckeyword}">{ckeytext}</A>: {cchoice}</LI>
+}</UL>
+
+<P>Proszę zmienić jedną lub więcej opcji, aby rozwiązać konflikt.</P>
diff --git a/templates/pl/option-header.tmpl b/templates/pl/option-header.tmpl
new file mode 100644
index 000000000..464726a50
--- /dev/null
+++ b/templates/pl/option-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="tab" ID="{group_id}">
+
+<H3 ALIGN="CENTER">{group}</H3>
+
+<TABLE WIDTH="100%">
diff --git a/templates/pl/option-pickmany.tmpl b/templates/pl/option-pickmany.tmpl
new file mode 100644
index 000000000..0da75e5d2
--- /dev/null
+++ b/templates/pl/option-pickmany.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" MULTIPLE SIZE="10">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT></TD>
+</TR>
diff --git a/templates/pl/option-pickone.tmpl b/templates/pl/option-pickone.tmpl
new file mode 100644
index 000000000..598fe1007
--- /dev/null
+++ b/templates/pl/option-pickone.tmpl
@@ -0,0 +1,18 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" ID="select-{keyword}" ONCHANGE="update_paramtable('{keyword}')">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT>
+{iscustom=1?<TABLE NAME="paramtable" id="{keyword}-params">{[params]
+<TR><TH CLASS="sublabel">{paramtext}:</TH>
+<TD>{params=Units?<SELECT NAME="{keyword-1}.{params}">
+<OPTION VALUE="pt"{paramvalue=pt? SELECTED:}>Punkty</OPTION>
+<OPTION VALUE="mm"{paramvalue=mm? SELECTED:}>Milimetry</OPTION>
+<OPTION VALUE="cm"{paramvalue=cm? SELECTED:}>Centymetry</OPTION>
+<OPTION VALUE="in"{paramvalue=in? SELECTED:}>Cale</OPTION>
+<OPTION VALUE="ft"{paramvalue=ft? SELECTED:}>Stopy</OPTION>
+<OPTION VALUE="m"{paramvalue=m? SELECTED:}>Metry</OPTION>
+</SELECT>:<INPUT TYPE="{inputtype}" NAME="{keyword-1}.{params}" VALUE="{paramvalue}">}</TD></TR>
+}</TABLE>
+</TD>:}
+</TR>
diff --git a/templates/pl/option-trailer.tmpl b/templates/pl/option-trailer.tmpl
new file mode 100644
index 000000000..21eec5678
--- /dev/null
+++ b/templates/pl/option-trailer.tmpl
@@ -0,0 +1,5 @@
+</TABLE>
+
+<P ALIGN="CENTER"><INPUT TYPE="SUBMIT" VALUE="Ustaw domyślne opcje"></P>
+
+</DIV>
diff --git a/templates/pl/pager.tmpl b/templates/pl/pager.tmpl
new file mode 100644
index 000000000..ce3515e57
--- /dev/null
+++ b/templates/pl/pager.tmpl
@@ -0,0 +1,6 @@
+<TABLE CLASS="inset" SUMMARY="Pasek stron">
+<TR>
+ <TD WIDTH="50%">{PREV?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{PREV}"><INPUT TYPE="SUBMIT" VALUE="&#x25c0; Wyświetl poprzednie"></FORM>:&nbsp;}</TD>
+ <TD WIDTH="50%" ALIGN="RIGHT">{NEXT?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{NEXT}"><INPUT TYPE="SUBMIT" VALUE="Wyświetl następne &#x25b6;"></FORM>:&nbsp;}</TD>
+</TR>
+</TABLE>
diff --git a/templates/pl/printer-accept.tmpl b/templates/pl/printer-accept.tmpl
new file mode 100644
index 000000000..6589b60f3
--- /dev/null
+++ b/templates/pl/printer-accept.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Akceptowanie zadań na {is_class?klasie:drukarce} {printer_name}</H2>
+
+<P>{is_class?Klasa:Drukarka} <A
+HREF="/{is_class?klasy:drukarki}/{printer_name}">{printer_name}</A>
+akceptujÄ… zadania.</P>
+
+</DIV>
diff --git a/templates/pl/printer-added.tmpl b/templates/pl/printer-added.tmpl
new file mode 100644
index 000000000..e217ee4f0
--- /dev/null
+++ b/templates/pl/printer-added.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Dodawanie drukarki</H2>
+
+<P>Drukarka <A HREF="/printers/{printer_name}">{printer_name}</A> została
+pomyślnie dodana.
+
+</DIV>
diff --git a/templates/pl/printer-configured.tmpl b/templates/pl/printer-configured.tmpl
new file mode 100644
index 000000000..994ed3461
--- /dev/null
+++ b/templates/pl/printer-configured.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ustawianie domyślnych opcji dla {printer_name}</H2>
+
+<P>Domyślne opcje {OP=set-class-options?klasy <A HREF="/classes/{printer_name}">:drukarki <A HREF="/printers/{printer_name}">}{printer_name}</A>
+zostały pomyślnie ustawione.
+
+</DIV>
diff --git a/templates/pl/printer-confirm.tmpl b/templates/pl/printer-confirm.tmpl
new file mode 100644
index 000000000..73f860128
--- /dev/null
+++ b/templates/pl/printer-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Usuwanie drukarki {printer_name}</H2>
+
+<P><B>Ostrzeżenie:</B> usunąć drukarkę
+{printer_name}?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Usuń drukarkę"></FORM></P>
+
+</DIV>
diff --git a/templates/pl/printer-default.tmpl b/templates/pl/printer-default.tmpl
new file mode 100644
index 000000000..541de9d99
--- /dev/null
+++ b/templates/pl/printer-default.tmpl
@@ -0,0 +1,13 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ustawianie {is_class?klasy:drukarki} {printer_name} jako domyślnej</H2>
+
+<P>{is_class?Klasa:Drukarka} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+została ustawiona jako domyślna drukarka serwera.</P>
+
+<BLOCKQUOTE><B>Uwaga:</B> każda domyśla opcja użytkownika ustawiona przez
+polecenie <TT>lpoptions</TT> zostanie zastąpiona tym domyślnym
+ustawieniem.</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/pl/printer-deleted.tmpl b/templates/pl/printer-deleted.tmpl
new file mode 100644
index 000000000..26e170b13
--- /dev/null
+++ b/templates/pl/printer-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Usuwanie drukarki {printer_name}</H2>
+
+<P>Drukarka {printer_name} została pomyślnie usunięta.
+
+</DIV>
diff --git a/templates/pl/printer-jobs-header.tmpl b/templates/pl/printer-jobs-header.tmpl
new file mode 100644
index 000000000..83dcfbcd5
--- /dev/null
+++ b/templates/pl/printer-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">Zadania</H3>
+</DIV>
diff --git a/templates/pl/printer-modified.tmpl b/templates/pl/printer-modified.tmpl
new file mode 100644
index 000000000..9bf074dbc
--- /dev/null
+++ b/templates/pl/printer-modified.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modyfikowanie drukarki {printer_name}</H2>
+
+<P>Drukarka <A HREF="/printers/{printer_name}">{printer_name}</A> została
+pomyślnie zmodyfikowana.
+
+</DIV>
diff --git a/templates/pl/printer-purge.tmpl b/templates/pl/printer-purge.tmpl
new file mode 100644
index 000000000..065217511
--- /dev/null
+++ b/templates/pl/printer-purge.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Czyszczenie zadań na {is_class?klasie:drukarce} {printer_name}</H2>
+
+<P>{is_class?Klasa:Drukarka} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+została wyczyszczona ze wszystkich zadań.</P>
+
+</DIV>
diff --git a/templates/pl/printer-reject.tmpl b/templates/pl/printer-reject.tmpl
new file mode 100644
index 000000000..038f8bab2
--- /dev/null
+++ b/templates/pl/printer-reject.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Odrzucanie zadań na {is_class?klasie:drukarce} {printer_name}</H2>
+
+<P>{is_class?Klasa:Drukarka} <A
+HREF="/{is_class?Klasy:Drukarki}/{printer_name}">{printer_name}</A>
+nie akceptuje zadań.</P>
+
+</DIV>
diff --git a/templates/pl/printer-start.tmpl b/templates/pl/printer-start.tmpl
new file mode 100644
index 000000000..e291f49d9
--- /dev/null
+++ b/templates/pl/printer-start.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Wznawianie {is_class?klasy:drukarki} {printer_name}</H2>
+
+<P>{is_class?Klasa:Drukarka} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+została wznowiona.</P>
+
+</DIV>
diff --git a/templates/pl/printer-stop.tmpl b/templates/pl/printer-stop.tmpl
new file mode 100644
index 000000000..06f94f699
--- /dev/null
+++ b/templates/pl/printer-stop.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Wstrzymywanie {is_class?klasy:drukarki} {printer_name}</H2>
+
+<P>{is_class?Klasa:Drukarka} <A
+HREF="/{is_class?Klasy:Drukarki}/{printer_name}">{printer_name}</A>
+została wstrzymana.</P>
+
+</DIV>
diff --git a/templates/pl/printer.tmpl b/templates/pl/printer.tmpl
new file mode 100644
index 000000000..c62b857a0
--- /dev/null
+++ b/templates/pl/printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?Bezczynna:{printer_state=4?Przetwarzanie:Wstrzymana}},
+{printer_is_accepting_jobs=0?Odrzucanie zadań:Akceptowanie zadań},
+{server_is_sharing_printers=0?Nie:{printer_is_shared=0?Nie:}} Współdzielona{default_name={printer_name}?, Domyślne serwera:})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">Konserwacja</OPTION>
+<OPTION VALUE="print-test-page">Wydrukuj stronę próbną</OPTION>
+{printer_commands~.*Clean.*?<OPTION VALUE="clean-print-heads">Wyczyść głowice drukujące</OPTION>:}
+{printer_commands~.*PrintSelfTestPage.*?<OPTION VALUE="print-self-test-page">Wydrukuj własną stronę próbną</OPTION>:}
+{printer_state=5?<OPTION VALUE="start-printer">Wznów drukarkę</OPTION>:<OPTION VALUE="stop-printer">Wstrzymaj drukarkę</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Akceptuj zadania</OPTION>:<OPTION VALUE="reject-jobs">Odrzucaj zadania</OPTION>}
+<OPTION VALUE="move-jobs">PrzenieÅ› wszystkie zadania</OPTION>
+<OPTION VALUE="purge-jobs">Anuluj wszystkie zadania</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Przejdź" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">Administracja</OPTION>
+<OPTION VALUE="modify-printer">Zmodyfikuj drukarkÄ™</OPTION>
+<OPTION VALUE="delete-printer">Usuń drukarkę</OPTION>
+<OPTION VALUE="set-printer-options">Ustaw domyślne opcje</OPTION>
+<OPTION VALUE="set-as-default">Ustaw jako domyślne serwera</OPTION>
+<OPTION VALUE="set-allowed-users">Ustaw zezwolonych użytkowników</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Przejdź" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Opis:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Położenie:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Sterownik:</TH><TD>{printer_make_and_model} ({color_supported=1?color:grayscale}{sides_supported?, 2-sided printing:})<BR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Połączenie:</TH><TD>{device_uri}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Domyślne:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:unknown}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/pl/printers-header.tmpl b/templates/pl/printers-header.tmpl
new file mode 100644
index 000000000..6a06c7f59
--- /dev/null
+++ b/templates/pl/printers-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?Brak drukarek:Wyświetlanie {#printer_name} z {total} drukarek{total=1?:s}}.</P>
diff --git a/templates/pl/printers.tmpl b/templates/pl/printers.tmpl
new file mode 100644
index 000000000..810ecb4a5
--- /dev/null
+++ b/templates/pl/printers.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Lista drukarek">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Nazwa kolejki <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Nazwa kolejki <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Opis</TH><TH>Położenie</TH><TH>Producent i model</TH><TH>Stan</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{printer_make_and_model}</TD><TD>{printer_state=3?Bezczynna:{printer_state=4?Przetwarzanie:Wstrzymana}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/pl/restart.tmpl b/templates/pl/restart.tmpl
new file mode 100644
index 000000000..6965e6b50
--- /dev/null
+++ b/templates/pl/restart.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Zmienianie ustawień</H2>
+
+<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Wskaźnik zajętości"> Proszę czekać, trwa ponowne uruchamianie serwera...</P>
+
+</DIV>
diff --git a/templates/pl/samba-export.tmpl b/templates/pl/samba-export.tmpl
new file mode 100644
index 000000000..691a30bb0
--- /dev/null
+++ b/templates/pl/samba-export.tmpl
@@ -0,0 +1,55 @@
+<SCRIPT TYPE="text/javascript"><!--
+function select_printers() {
+ var list = document.export_samba.EXPORT_NAME;
+ var sel = document.export_samba.EXPORT_ALL.checked;
+
+ for (i = 0; i < list.length; i ++) {
+ list.options[i].selected = sel;
+ }
+}
+--></SCRIPT>
+
+<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
+
+<H2 CLASS="title">Eksportowanie drukarek do Samby</H2>
+
+{error?<P>Nie można wyeksportować drukarek do Samby\:</P>
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+<P>Proszę zobaczyć plik <A HREF="/admin/log/error_log"
+TARGET="_blank">error_log</A>, aby uzyskać więcej informacji.</P>:
+<P>Ta strona umożliwia wyeksportowanie drukarek do Samby, aby
+klienci Windows mogli mieć do nich dostęp przez ikonę <VAR>Otoczenie
+sieciowe</VAR> lub <VAR>Miejsca sieciowe</VAR> na pulpitach.
+Należy wcześniej zainstalować sterowniki drukarki Windows PostScript,
+tak jak opisano na stronie podręcznika <A
+HREF="/help/man-cupsaddsmb.html"
+TARGET="_blank">cupsaddsmb(8)</A>.</P>}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Drukarki:</TH>
+<TD>
+<SELECT NAME="EXPORT_NAME" SIZE="10" MULTIPLE>
+{[printer_name]<OPTION VALUE="{printer_name}"{export_all? SELECTED:{printer_export? SELECTED:}}>{printer_name}}
+</SELECT><BR>
+<INPUT TYPE="CHECKBOX" NAME="EXPORT_ALL"{export_all? CHECKED:}
+onChange="select_printers()"> Wyeksportuj wszystkie drukarki
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Nazwa użytkownika Samby:</TH>
+<TD><INPUT TYPE="TEXT" NAME="USERNAME" VALUE="{?USERNAME}"> (wymagana)</TD>
+</TR>
+<TR>
+<TH CLASS="label">Hasło Samby:</TH>
+<TD><INPUT TYPE="PASSWORD" NAME="PASSWORD" VALUE=""> (wymagane)</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Wyeksportuj drukarki do Samby"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/pl/samba-exported.tmpl b/templates/pl/samba-exported.tmpl
new file mode 100644
index 000000000..55ba02866
--- /dev/null
+++ b/templates/pl/samba-exported.tmpl
@@ -0,0 +1 @@
+<P>Pomyślnie wyeksportowano drukarki do Samby.</P>
diff --git a/templates/pl/search.tmpl b/templates/pl/search.tmpl
new file mode 100644
index 000000000..0851d8516
--- /dev/null
+++ b/templates/pl/search.tmpl
@@ -0,0 +1,10 @@
+<FORM ACTION="/{SECTION}/{?SEARCH_DEST}" METHOD="GET">
+{WHICH_JOBS?<INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{WHICH_JOBS}">:}
+{ORDER?<INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{ORDER}">:}
+
+<P ALIGN="CENTER"><B>Znajdź w
+{SEARCH_DEST?{SEARCH_DEST}:{SECTION=classes?klasach:{SECTION=jobs?zadaniach:drukarkach}}}:</B>
+<INPUT TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER="" AUTOSAVE="org.cups.{SECTION}" RESULTS="20"> <INPUT
+TYPE="SUBMIT" VALUE="Znajdź"> <INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="Wyczyść"></P>
+
+</FORM>
diff --git a/templates/pl/set-printer-options-header.tmpl b/templates/pl/set-printer-options-header.tmpl
new file mode 100644
index 000000000..58e5b85d1
--- /dev/null
+++ b/templates/pl/set-printer-options-header.tmpl
@@ -0,0 +1,26 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Ustawianie domyślnych opcji dla {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Pobierz domyślne ustawienia drukarki">:}
+
+<SCRIPT TYPE="text/javascript"><!--
+function update_paramtable(option)
+{
+ var cb = document.getElementById("select-" + option)
+ var paramstable = document.getElementById(option + "-params");
+ if (cb.value == "Custom")
+ paramstable.style.display = "table";
+ else
+ paramstable.style.display = "none";
+}
+--></SCRIPT>
+
+<H3 CLASS="title">{[group_id]
+<A HREF="#{group_id}">{group}</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</H3>
+
+<DIV CLASS="tabs">
diff --git a/templates/pl/set-printer-options-trailer.tmpl b/templates/pl/set-printer-options-trailer.tmpl
new file mode 100644
index 000000000..c1183e18e
--- /dev/null
+++ b/templates/pl/set-printer-options-trailer.tmpl
@@ -0,0 +1,16 @@
+</DIV>
+
+<SCRIPT TYPE="text/javascript"><!--
+// Ukryj własne parametry opcji dla przeglądarek rozumiejących JavaScript
+var paramtables = document.getElementsByName("paramtable");
+for (var i = 0; i < paramtables.length; i++)
+{
+ var opt = paramtables[i].id.substr(0, paramtables[i].id.lastIndexOf("-"));
+ var cb = document.getElementById("select-" + opt);
+ if (cb.value != "Custom")
+ paramtables[i].style.display = "none";
+}
+--></SCRIPT>
+</FORM>
+
+</DIV>
diff --git a/templates/pl/subscription-added.tmpl b/templates/pl/subscription-added.tmpl
new file mode 100644
index 000000000..af87082b1
--- /dev/null
+++ b/templates/pl/subscription-added.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>Subskrypcja {subscription_name} została pomyślnie dodana.</P>
+
+</DIV>
diff --git a/templates/pl/subscription-canceled.tmpl b/templates/pl/subscription-canceled.tmpl
new file mode 100644
index 000000000..58ce44c7a
--- /dev/null
+++ b/templates/pl/subscription-canceled.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>Subskrypcja #{notify_subscription_id} została usunięta.</P>
+
+</DIV>
diff --git a/templates/pl/test-page.tmpl b/templates/pl/test-page.tmpl
new file mode 100644
index 000000000..346a6d2fc
--- /dev/null
+++ b/templates/pl/test-page.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Drukowanie strony próbnej na {printer_name}</H2>
+
+<P>Wysłano stronę próbną; identyfikator zadania to <A HREF="/{SECTION}/{printer_name}">
+{printer_name}-{job_id}</A>.</P>
+
+</DIV>
diff --git a/templates/pl/trailer.tmpl b/templates/pl/trailer.tmpl
new file mode 100644
index 000000000..5f2602b23
--- /dev/null
+++ b/templates/pl/trailer.tmpl
@@ -0,0 +1,8 @@
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS i logo CUPS
+sÄ… znakami handlowymi <A HREF="http://www.apple.com">Apple Inc.</A> CUPS
+copyright 2007-2011 Apple Inc. Wszystkie prawa zastrzeżone.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/templates/pl/users.tmpl b/templates/pl/users.tmpl
new file mode 100644
index 000000000..5cb754952
--- /dev/null
+++ b/templates/pl/users.tmpl
@@ -0,0 +1,30 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
+
+<H2 CLASS="title">Zezwoleni użytkownicy dla {printer_name}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">Użytkownicy:</TH>
+<TD>
+<INPUT TYPE='TEXT' NAME='users' SIZE='60' VALUE='{?requesting_user_name_allowed}{?requesting_user_name_denied}'>
+<BR>
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-allowed' {requesting_user_name_allowed?checked:}>Pozwól tym użytkownikom drukować
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-denied' {requesting_user_name_denied?checked:}>Nie pozwalaj tym użytkownikom drukować
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>
+<INPUT TYPE="SUBMIT" VALUE="Ustaw zezwolonych użytkowników">
+</TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/printer-accept.tmpl b/templates/printer-accept.tmpl
new file mode 100644
index 000000000..3e987ce64
--- /dev/null
+++ b/templates/printer-accept.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Accept Jobs On {is_class?Class:Printer} {printer_name}</H2>
+
+<P>{is_class?Class:Printer} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+is now accepting jobs.</P>
+
+</DIV>
diff --git a/templates/printer-added.tmpl b/templates/printer-added.tmpl
new file mode 100644
index 000000000..9a6e798e9
--- /dev/null
+++ b/templates/printer-added.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Add Printer</H2>
+
+<P>Printer <A HREF="/printers/{printer_name}">{printer_name}</A> has been added
+successfully.
+
+</DIV>
diff --git a/templates/printer-configured.tmpl b/templates/printer-configured.tmpl
new file mode 100644
index 000000000..6f8104e23
--- /dev/null
+++ b/templates/printer-configured.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Set Default Options for {printer_name}</H2>
+
+<P>{OP=set-class-options?Class <A HREF="/classes/{printer_name}">:Printer <A HREF="/printers/{printer_name}">}{printer_name}</A>
+default options have been set successfully.
+
+</DIV>
diff --git a/templates/printer-confirm.tmpl b/templates/printer-confirm.tmpl
new file mode 100644
index 000000000..fce9e3494
--- /dev/null
+++ b/templates/printer-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Delete Printer {printer_name}</H2>
+
+<P><B>Warning:</B> Are you sure you want to delete printer
+{printer_name}?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Delete Printer"></FORM></P>
+
+</DIV>
diff --git a/templates/printer-default.tmpl b/templates/printer-default.tmpl
new file mode 100644
index 000000000..72a7b5ea8
--- /dev/null
+++ b/templates/printer-default.tmpl
@@ -0,0 +1,13 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Set {is_class?Class:Printer} {printer_name} As Default</H2>
+
+<P>{is_class?Class:Printer} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+has been made the default printer on the server.</P>
+
+<BLOCKQUOTE><B>Note:</B> Any user default that has been set via
+the <TT>lpoptions</TT> command will override this default
+setting.</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/printer-deleted.tmpl b/templates/printer-deleted.tmpl
new file mode 100644
index 000000000..d8a31ae61
--- /dev/null
+++ b/templates/printer-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Delete Printer {printer_name}</H2>
+
+<P>Printer {printer_name} has been deleted successfully.
+
+</DIV>
diff --git a/templates/printer-jobs-header.tmpl b/templates/printer-jobs-header.tmpl
new file mode 100644
index 000000000..ba46f1026
--- /dev/null
+++ b/templates/printer-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">Jobs</H3>
+</DIV>
diff --git a/templates/printer-modified.tmpl b/templates/printer-modified.tmpl
new file mode 100644
index 000000000..b61e8e34a
--- /dev/null
+++ b/templates/printer-modified.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Modify Printer {printer_name}</H2>
+
+<P>Printer <A HREF="/printers/{printer_name}">{printer_name}</A> has been
+modified successfully.
+
+</DIV> \ No newline at end of file
diff --git a/templates/printer-purge.tmpl b/templates/printer-purge.tmpl
new file mode 100644
index 000000000..8cf7c1461
--- /dev/null
+++ b/templates/printer-purge.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Purge Jobs On {is_class?Class:Printer} {printer_name}</H2>
+
+<P>{is_class?Class:Printer} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+has been purged of all jobs.</P>
+
+</DIV> \ No newline at end of file
diff --git a/templates/printer-reject.tmpl b/templates/printer-reject.tmpl
new file mode 100644
index 000000000..5f1c79195
--- /dev/null
+++ b/templates/printer-reject.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Reject Jobs On {is_class?Class:Printer} {printer_name}</H2>
+
+<P>{is_class?Class:Printer} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+is no longer accepting jobs.</P>
+
+</DIV>
diff --git a/templates/printer-start.tmpl b/templates/printer-start.tmpl
new file mode 100644
index 000000000..3eaed13d1
--- /dev/null
+++ b/templates/printer-start.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Resume {is_class?Class:Printer} {printer_name}</H2>
+
+<P>{is_class?Class:Printer} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+has been resumed.</P>
+
+</DIV> \ No newline at end of file
diff --git a/templates/printer-stop.tmpl b/templates/printer-stop.tmpl
new file mode 100644
index 000000000..b74e87135
--- /dev/null
+++ b/templates/printer-stop.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Pause {is_class?Class:Printer} {printer_name}</H2>
+
+<P>{is_class?Class:Printer} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+has been paused.</P>
+
+</DIV> \ No newline at end of file
diff --git a/templates/printer.tmpl b/templates/printer.tmpl
new file mode 100644
index 000000000..78fc08bea
--- /dev/null
+++ b/templates/printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?Idle:{printer_state=4?Processing:Paused}},
+{printer_is_accepting_jobs=0?Rejecting Jobs:Accepting Jobs},
+{server_is_sharing_printers=0?Not:{printer_is_shared=0?Not:}} Shared{default_name={printer_name}?, Server Default:})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">Maintenance</OPTION>
+<OPTION VALUE="print-test-page">Print Test Page</OPTION>
+{printer_commands~.*Clean.*?<OPTION VALUE="clean-print-heads">Clean Print Heads</OPTION>:}
+{printer_commands~.*PrintSelfTestPage.*?<OPTION VALUE="print-self-test-page">Print Self Test Page</OPTION>:}
+{printer_state=5?<OPTION VALUE="start-printer">Resume Printer</OPTION>:<OPTION VALUE="stop-printer">Pause Printer</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Accept Jobs</OPTION>:<OPTION VALUE="reject-jobs">Reject Jobs</OPTION>}
+<OPTION VALUE="move-jobs">Move All Jobs</OPTION>
+<OPTION VALUE="purge-jobs">Cancel All Jobs</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">Administration</OPTION>
+<OPTION VALUE="modify-printer">Modify Printer</OPTION>
+<OPTION VALUE="delete-printer">Delete Printer</OPTION>
+<OPTION VALUE="set-printer-options">Set Default Options</OPTION>
+<OPTION VALUE="set-as-default">Set As Server Default</OPTION>
+<OPTION VALUE="set-allowed-users">Set Allowed Users</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Description:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Location:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Driver:</TH><TD>{printer_make_and_model} ({color_supported=1?color:grayscale}{sides_supported?, 2-sided printing:})<BR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Connection:</TH><TD>{device_uri}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Defaults:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:unknown}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV> \ No newline at end of file
diff --git a/templates/printers-header.tmpl b/templates/printers-header.tmpl
new file mode 100644
index 000000000..5196be1d8
--- /dev/null
+++ b/templates/printers-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?No printers:Showing {#printer_name} of {total} printer{total=1?:s}}.</P>
diff --git a/templates/printers.tmpl b/templates/printers.tmpl
new file mode 100644
index 000000000..e0a3228d0
--- /dev/null
+++ b/templates/printers.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="Printer List">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Queue Name <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Queue Name <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Description</TH><TH>Location</TH><TH>Make and Model</TH><TH>Status</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{printer_make_and_model}</TD><TD>{printer_state=3?Idle:{printer_state=4?Processing:Paused}}{printer_state_message? - "{printer_state_message}":}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/restart.tmpl b/templates/restart.tmpl
new file mode 100644
index 000000000..bdfca876f
--- /dev/null
+++ b/templates/restart.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Change Settings</H2>
+
+<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Busy Indicator"> Please stand by while the server restarts...</P>
+
+</DIV>
diff --git a/templates/ru/Makefile b/templates/ru/Makefile
new file mode 100644
index 000000000..28f82eaca
--- /dev/null
+++ b/templates/ru/Makefile
@@ -0,0 +1,201 @@
+#
+# "$Id$"
+#
+# Template makefile for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1993-2007 by Easy Software Products.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+#
+# Template files...
+#
+
+FILES = \
+ add-class.tmpl \
+ add-printer.tmpl \
+ add-rss-subscription.tmpl \
+ admin.tmpl \
+ choose-device.tmpl \
+ choose-make.tmpl \
+ choose-model.tmpl \
+ choose-serial.tmpl \
+ choose-uri.tmpl \
+ class.tmpl \
+ class-added.tmpl \
+ class-confirm.tmpl \
+ class-deleted.tmpl \
+ class-jobs-header.tmpl \
+ class-modified.tmpl \
+ classes.tmpl \
+ classes-header.tmpl \
+ command.tmpl \
+ edit-config.tmpl \
+ error.tmpl \
+ error-op.tmpl \
+ header.tmpl \
+ help-header.tmpl \
+ help-trailer.tmpl \
+ help-printable.tmpl \
+ job-cancel.tmpl \
+ job-hold.tmpl \
+ job-move.tmpl \
+ job-moved.tmpl \
+ job-release.tmpl \
+ job-restart.tmpl \
+ jobs.tmpl \
+ jobs-header.tmpl \
+ list-available-printers.tmpl \
+ modify-class.tmpl \
+ modify-printer.tmpl \
+ norestart.tmpl \
+ option-boolean.tmpl \
+ option-conflict.tmpl \
+ option-header.tmpl \
+ option-pickmany.tmpl \
+ option-pickone.tmpl \
+ option-trailer.tmpl \
+ pager.tmpl \
+ printer.tmpl \
+ printer-accept.tmpl \
+ printer-added.tmpl \
+ printer-configured.tmpl \
+ printer-confirm.tmpl \
+ printer-default.tmpl \
+ printer-deleted.tmpl \
+ printer-jobs-header.tmpl \
+ printer-modified.tmpl \
+ printer-purge.tmpl \
+ printer-reject.tmpl \
+ printer-start.tmpl \
+ printer-stop.tmpl \
+ printers.tmpl \
+ printers-header.tmpl \
+ restart.tmpl \
+ samba-export.tmpl \
+ samba-exported.tmpl \
+ search.tmpl \
+ set-printer-options-header.tmpl \
+ set-printer-options-trailer.tmpl \
+ subscription-added.tmpl \
+ subscription-canceled.tmpl \
+ test-page.tmpl \
+ trailer.tmpl \
+ users.tmpl
+
+
+#
+# Make everything...
+#
+
+all:
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Clean all config and object files...
+#
+
+clean:
+
+
+#
+# Dummy depend...
+#
+
+depend:
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data: $(INSTALL_LANGUAGES)
+ $(INSTALL_DIR) -m 755 $(DATADIR)/templates
+ for file in $(FILES); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/templates; \
+ done
+
+install-languages:
+ for lang in $(LANGUAGES); do \
+ if test -d $$lang; then \
+ $(INSTALL_DIR) -m 755 $(DATADIR)/templates/$$lang; \
+ for file in $(FILES); do \
+ $(INSTALL_DATA) $$lang/$$file $(DATADIR)/templates/$$lang 2>/dev/null || true; \
+ done \
+ fi \
+ done
+
+
+
+#
+# Install programs...
+#
+
+install-exec:
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Uninstall files...
+#
+
+uninstall: $(UNINSTALL_LANGUAGES)
+ for file in $(FILES); do \
+ $(RM) $(DATADIR)/templates/$$file; \
+ done
+ -$(RMDIR) $(DATADIR)/templates
+
+uninstall-languages:
+ for lang in $(LANGUAGES); do \
+ for file in $(FILES); do \
+ $(RM) $(DATADIR)/templates/$$lang/$$file; \
+ done \
+ $(RMDIR) $(DATADIR)/templates/$$lang; \
+ done
+
+
+#
+# End of "$Id$".
+#
diff --git a/templates/ru/add-class.tmpl b/templates/ru/add-class.tmpl
new file mode 100644
index 000000000..41a7f9868
--- /dev/null
+++ b/templates/ru/add-class.tmpl
@@ -0,0 +1,40 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">ÐÐ¾Ð²Ð°Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð°</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Ðазвание:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(может Ñодержать любые Ñимволы кроме «/», «#» и пробела)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">ОпиÑание:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(раÑширенное опиÑание группы, например, «ДуплекÑный принтер»)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">РаÑположение:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(меÑтоположение группы, например, «Кабинет 55»)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">СоÑтав группы:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Добавить группу"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/ru/add-printer.tmpl b/templates/ru/add-printer.tmpl
new file mode 100644
index 000000000..2d040189c
--- /dev/null
+++ b/templates/ru/add-printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Добавление принтера</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+{?current_make!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE" VALUE="{current_make}">:}
+{?current_make_and_model!?<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{current_make_and_model}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Ðазвание:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?template_name}"><BR>
+<SMALL>(может Ñодержать любые Ñимволы кроме «/», «#» и пробела)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">ОпиÑание:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(раÑширенное опиÑание принтера, например, «HP LaserJet Ñ Ð´ÑƒÐ¿Ð»ÐµÐºÑной печатью»)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">РаÑположение:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(меÑтоположение принтера, например, «Кабинет 55»)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Подключение:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">СовмеÑтный доÑтуп:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+Разрешить ÑовмеÑтный доÑтуп к Ñтому принтеру</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Продолжить"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/ru/add-rss-subscription.tmpl b/templates/ru/add-rss-subscription.tmpl
new file mode 100644
index 000000000..6ff4ff2cd
--- /dev/null
+++ b/templates/ru/add-rss-subscription.tmpl
@@ -0,0 +1,44 @@
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription">
+
+<H2 CLASS="title">Добавление подпиÑки по RSS</H2>
+
+<TABLE SUMMARY="Добавление подпиÑки по RSS">
+<TR>
+<TH CLASS="label">Ðазвание:</TH>
+<TD COLSPAN="5"><INPUT TYPE="TEXT" NAME="SUBSCRIPTION_NAME" SIZE="40" MAXLENGTH="127" VALUE="{?SUBSCRIPTION_NAME}"><BR>
+<SMALL>(может Ñодержать любые Ñимволы кроме «/», «#» и пробела)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Очередь:</TH>
+<TD COLSPAN="5"><SELECT NAME="PRINTER_URI" SIZE="10"><OPTION VALUE="#ALL#"{?PRINTER_URI=#ALL#? SELECTED:}>Ð’Ñе очереди</OPTION>{[printer_name]<OPTION VALUE="{printer_uri_supported}"{?PRINTER_URI={printer_uri_supported}? SELECTED:}>{printer_name}</OPTION>}</SELECT></TD>
+</TR>
+<TR VALIGN="TOP">
+<TH CLASS="label">СобытиÑ:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CREATED" {?EVENT_JOB_CREATED}>Ðовое задание<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_COMPLETED" {?EVENT_JOB_COMPLETED}>Задание напечатано<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_STOPPED" {?EVENT_JOB_STOPPED}>Задание оÑтановлено<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_JOB_CONFIG_CHANGED" {?EVENT_JOB_CONFIG_CHANGED}>Изменены параметров заданиÑ</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_STOPPED" {?EVENT_PRINTER_STOPPED}>Очередь оÑтановлена<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_ADDED" {?EVENT_PRINTER_ADDED}>Очередь добавлена<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_MODIFIED" {?EVENT_PRINTER_MODIFIED}>Очередь изменена<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_PRINTER_DELETED" {?EVENT_PRINTER_DELETED}>Очередь удалена</TD>
+<TD>&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+<TD><INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STARTED" {?EVENT_SERVER_STARTED}>Сервер запущен<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_STOPPED" {?EVENT_SERVER_STOPPED}>Сервер оÑтановлен<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_RESTARTED" {?EVENT_SERVER_RESTARTED}>Сервер перезапущен<BR>
+<INPUT TYPE="CHECKBOX" NAME="EVENT_SERVER_AUDIT" {?EVENT_SERVER_AUDIT}>Проверка безопаÑноÑти Ñервера</TD>
+</TR>
+<TR>
+<TH CLASS="label">КоличеÑтво Ñобытий в ленте:</TH>
+<TD COLSPAN="5"><INPUT TYPE="NUMBER" NAME="MAX_EVENTS" SIZE="4" MAXLENGTH="4" VALUE="{MAX_EVENTS?{MAX_EVENTS}:20}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD COLSPAN="5"><INPUT TYPE="SUBMIT" VALUE="Добавить подпиÑку по RSS"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/ru/admin.tmpl b/templates/ru/admin.tmpl
new file mode 100644
index 000000000..22d9de064
--- /dev/null
+++ b/templates/ru/admin.tmpl
@@ -0,0 +1,110 @@
+<TABLE CLASS="indent" SUMMARY="ÐдминиÑтрирование">
+<TR><TD VALIGN="TOP">
+
+<H2 CLASS="title">Принтеры</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="SUBMIT" VALUE="Добавить принтер"></FORM>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="find-new-printers"><INPUT TYPE="SUBMIT" VALUE="Ðайти новый принтер"></FORM>
+<FORM ACTION="/printers/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Управление принтерами"></FORM>
+{have_samba?<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba"><INPUT TYPE="SUBMIT" VALUE="ЭкÑпортировать принтер в Samba"></FORM>:}
+</P>
+
+<H2 CLASS="title">Группы</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-class"><INPUT TYPE="SUBMIT" VALUE="Добавить группу"></FORM>
+<FORM ACTION="/classes/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Управление группами"></FORM>
+</P>
+
+<H2 CLASS="title">ЗаданиÑ</H2>
+
+<P>
+<FORM ACTION="/jobs/" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Управление заданиÑми"></FORM>
+</P>
+
+</TD><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TD VALIGN="TOP">
+
+<H2 CLASS="title">Сервер</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server"><INPUT TYPE="SUBMIT" VALUE="Редактировать конфигурационный файл"></FORM>
+<FORM ACTION="/admin/log/access_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Показать журнал заданий"></FORM>
+<FORM ACTION="/admin/log/error_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Показать журнал ошибок"></FORM>
+<FORM ACTION="/admin/log/page_log" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Показать журнал Ñтраниц"></FORM>
+</P>
+
+{SETTINGS_ERROR?<P>{SETTINGS_MESSAGE}</P>
+<BLOCKQUOTE>{SETTINGS_ERROR}</BLOCKQUOTE>:
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+
+{ADVANCEDSETTINGS?<P><B>Параметры Ñервера\:</B></P>
+
+<P><A HREF="/admin/">Дополнительные параметры <SMALL>&#x25bc;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="HIDDEN" NAME="ADVANCEDSETTINGS" VALUE="YES">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Показать принтеры, иÑпользующиеÑÑ Ð² других ÑиÑтемах<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Протоколы\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_CUPS" {?browse_remote_cups}> CUPS
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_LDAP" {?browse_remote_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_REMOTE_SLP" {?browse_remote_slp}> SLP:}<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Разрешить ÑовмеÑтный доÑтуп к принтерам, подключенным к Ñтой ÑиÑтеме<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;МакÑимальное количеÑтво клиентов\:
+<INPUT TYPE="TEXT" NAME="MAX_CLIENTS" VALUE="{?max_clients}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Протоколы\:
+<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_CUPS" {?browse_local_cups}> CUPS
+{HAVE_DNSSD?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_DNSSD" {?browse_local_dnssd}> DNS-SD:}
+{HAVE_LDAP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_LDAP" {?browse_local_ldap}> LDAP:}
+{HAVE_LIBSLP?<INPUT TYPE="CHECKBOX" NAME="BROWSE_LOCAL_SLP" {?browse_local_slp}> SLP:}<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Разрешить печать из Интернета<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="BROWSE_WEB_IF" {?browse_web_if}> ÐнонÑировать веб-интерфейÑ<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Разрешить удаленное админиÑтрирование<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Разрешить аунтентификацию Kerberos (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Разрешить пользователÑм отменÑÑ‚ÑŒ любое задание (не только их ÑобÑтвенное)<BR>
+<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_HISTORY" {?preserve_job_history}> ВеÑти журнал заданий<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;КоличеÑтво заданий\:
+<INPUT TYPE="TEXT" NAME="MAX_JOBS" VALUE="{?max_jobs}" SIZE="6"><BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="PRESERVE_JOB_FILES" {?preserve_job_files}> СохранÑÑ‚ÑŒ Ñодержимое заданий<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}>СохранÑÑ‚ÑŒ отладочную информацию в журнале<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;МакÑимальный размер журнала ошибок\:
+<INPUT TYPE="TEXT" NAME="MAX_LOG_SIZE" VALUE="{?max_log_size}" SIZE="6"></P>
+
+:<P><B>Параметры Ñервера:</B></P>
+
+<P><A HREF="/admin/?ADVANCEDSETTINGS=YES">Дополнительные параметры <SMALL>&#x25b6;</SMALL></A><BR>
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Показать принтеры, иÑпользующиеÑÑ Ð² других ÑиÑтемах<BR>
+<INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Разрешить ÑовмеÑтный доÑтуп к принтерам, подключенным к Ñтой ÑиÑтеме<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE="CHECKBOX" NAME="REMOTE_ANY" {?remote_any}> Разрешить печать из Интернета<BR>
+<INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Разрешить удаленное админиÑтрирование<BR>
+{have_gssapi?<INPUT TYPE="CHECKBOX" NAME="KERBEROS" {?kerberos}> Разрешить аунтентификацию Kerberos (<A HREF="/help/kerberos.html?TOPIC=Getting+Started">FAQ</A>)<BR>:}
+<INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Разрешить пользователÑм отменÑÑ‚ÑŒ любое задание (не только их ÑобÑтвенное)<BR>
+<INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> СохранÑÑ‚ÑŒ отладочную информацию в журнале</P>
+
+}
+<P><INPUT TYPE="SUBMIT" NAME="CHANGESETTINGS" VALUE="Сохранить"></P>
+
+</FORM>}
+
+</TD></TR>
+</TABLE>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">ПодпиÑка по RSS</H2>
+
+<P>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-rss-subscription"><INPUT TYPE="SUBMIT" VALUE="Добавить подпиÑку по RSS"></FORM>
+</P>
+
+</DIV>
+
+{notify_subscription_id?<TABLE CLASS="list" SUMMARY="ПодпиÑки по RSS">
+<THEAD><TR><TH>Ðазвание</TH><TH>СобытиÑ</TH><TH>Очередь</TH></TR></THEAD>
+<TBODY>{[notify_subscription_id]
+<TR><TD><A HREF="{notify_recipient_uri}">{notify_recipient_name}</A><BR>
+<FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-subscription"><INPUT TYPE="HIDDEN" NAME="notify_subscription_id" VALUE="{notify_subscription_id}"><INPUT TYPE="SUBMIT" VALUE="Отменить подпиÑку по RSS"></FORM>&nbsp;</TD><TD>{notify_events}</TD><TD NOWRAP>&nbsp;{notify_printer_name?{notify_printer_name}:Ð’Ñе очереди}</TD></TR>}
+</TBODY>
+</TABLE>:}
diff --git a/templates/ru/choose-device.tmpl b/templates/ru/choose-device.tmpl
new file mode 100644
index 000000000..3df36db86
--- /dev/null
+++ b/templates/ru/choose-device.tmpl
@@ -0,0 +1,54 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Изменение {printer_name}:Добавление принтера}</H2>
+
+{CUPS_GET_DEVICES_DONE?:<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Busy Indicator"> ПоиÑк принтеров...</P>}
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+{op=add-printer?:<TR>
+<TH CLASS="label">Текущее подключение:</TH>
+<TD><INPUT TYPE="RADIO" NAME="DEVICE_URI" VALUE="{current_device_uri}" CHECKED>
+{current_device_uri}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">Локальные принтеры:</TH>
+<TD>
+{[device_uri]{device_class!network?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}}
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Обнаруженные Ñетевые принтеры:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+:}:}}
+</TD>
+</TR>
+<TR>
+<TR>
+<TH CLASS="label">Другие Ñетевые принтеры:</TH>
+<TD>
+{[device_uri]{device_class=network?{device_uri~[a-z]+://?:<INPUT TYPE="RADIO" NAME="DEVICE_URI"
+VALUE="{device_uri}{?device_make_and_model!Unknown?|{device_make_and_model}:}">
+{device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}<BR>
+}:}}
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Продолжить"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/ru/choose-make.tmpl b/templates/ru/choose-make.tmpl
new file mode 100644
index 000000000..a87d6bf27
--- /dev/null
+++ b/templates/ru/choose-make.tmpl
@@ -0,0 +1,64 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Изменение {printer_name}:Добавление принтера}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Ðазвание:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">ОпиÑание:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">РаÑположение:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Подключение:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">СовмеÑтный доÑтуп:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+{?printer_is_shared=?Ðет ÑовмеÑтного доÑтупа:{?printer_is_shared=0?Ðет ÑовмеÑтного доÑтупа:Разрешен ÑовмеÑтный доÑтуп}} к Ñтому принтеру</TD>
+</TR>
+<TR>
+<TH CLASS="label">Создать:</TH>
+<TD>
+<SELECT NAME="PPD_MAKE" SIZE="10">
+{[ppd_make]<OPTION VALUE="{ppd_make}" {?current_make={ppd_make}?SELECTED:}>{ppd_make}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Продолжить"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>&nbsp;</TD>
+</TR>
+<TR>
+<TH CLASS="label">или иÑпользовать файл PPD:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?Добавить принтер:Сохранить}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/ru/choose-model.tmpl b/templates/ru/choose-model.tmpl
new file mode 100644
index 000000000..9d434f1c3
--- /dev/null
+++ b/templates/ru/choose-model.tmpl
@@ -0,0 +1,59 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Изменение {printer_name}:Добавление принтера}</H2>
+
+<FORM METHOD="POST" ACTION="/admin" ENCTYPE="multipart/form-data">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<TABLE>
+{op=modify-printer?:<TR>
+<TH CLASS="label">Ðазвание:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">{printer_name}</TD>
+</TR>}
+<TR>
+<TH CLASS="label">ОпиÑание:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{printer_info}">{printer_info}</TD>
+</TR>
+<TR>
+<TH CLASS="label">РаÑположение:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="{printer_location}">{printer_location}</TD>
+</TR>
+<TR>
+<TH CLASS="label">Подключение:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">СовмеÑтный доÑтуп:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="PRINTER_IS_SHARED" VALUE="{?printer_is_shared}">
+{?printer_is_shared=?Ðет ÑовмеÑтного доÑтупа:{?printer_is_shared=0?Ðет ÑовмеÑтного доÑтупа:Разрешен ÑовмеÑтный доÑтуп}} к Ñтому принтеру</TD></TR>
+<TR>
+<TH CLASS="label">Создать:</TH>
+<TD>{PPD_MAKE} <INPUT TYPE="SUBMIT" NAME="SELECT_MAKE" VALUE="Выбрать модель"></TD>
+</TR>
+<TR>
+<TH CLASS="label">Модель:</TH>
+<TD>
+<SELECT NAME="PPD_NAME" SIZE="10">
+{op=add-printer?:<OPTION VALUE="__no_change__" SELECTED>Текущий драйвер — {current_make_and_model}</OPTION>:}
+{[ppd_name]<OPTION VALUE="{ppd_name}" {op=modify-printer?:{?current_make_and_model={ppd_make_and_model}?SELECTED:}}>{ppd_make_and_model} ({ppd_natural_language})
+}</SELECT>
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">или иÑпользовать файл PPD:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="262144"><INPUT
+TYPE="FILE" NAME="PPD_FILE"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{op=add-printer?Добавить принтер:Сохранить}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/ru/choose-serial.tmpl b/templates/ru/choose-serial.tmpl
new file mode 100644
index 000000000..21e4bf87f
--- /dev/null
+++ b/templates/ru/choose-serial.tmpl
@@ -0,0 +1,52 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Изменение {printer_name}:Добавление принтера}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Подключение:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">СкороÑÑ‚ÑŒ передачи:</TH>
+<TD><SELECT NAME="BAUDRATE">
+{[baudrates]<OPTION {?baudrate={baudrates}?SELECTED:}>{baudrates}}
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Печать Ñтраниц:</TH>
+<TD><SELECT NAME="PARITY">
+<OPTION VALUE="none" {?parity=none?SELECTED:}>Ð’Ñе
+<OPTION VALUE="even" {?parity=even?SELECTED:}>Только четные
+<OPTION VALUE="odd" {?parity=odd?SELECTED:}>Только нечетные
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Биты данных:</TH>
+<TD><SELECT NAME="BITS">
+<OPTION {?bits=8?SELECTED:}>8
+<OPTION {?bits=7?SELECTED:}>7
+</SELECT></TD>
+</TR>
+<TR>
+<TH CLASS="label">Управление:</TH>
+<TD><SELECT NAME="FLOW">
+<OPTION VALUE="none" {?flow=none?SELECTED:}>Ðет
+<OPTION VALUE="soft" {?flow=soft?SELECTED:}>XON/XOFF (программное)
+<OPTION VALUE="hard" {?flow=hard?SELECTED:}>RTS/CTS (аппаратное)
+<OPTION VALUE="dtrdsr" {?flow=dtrdsr?SELECTED:}>DTR/DSR (аппаратное)
+</SELECT></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Продолжить"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/ru/choose-uri.tmpl b/templates/ru/choose-uri.tmpl
new file mode 100644
index 000000000..17e5e94f6
--- /dev/null
+++ b/templates/ru/choose-uri.tmpl
@@ -0,0 +1,43 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{op=modify-printer?Изменение {printer_name}:Добавление принтера}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{printer_name?<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">:}
+<INPUT TYPE="HIDDEN" NAME="CURRENT_MAKE_AND_MODEL" VALUE="{?current_make_and_model}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">Подключение:</TH>
+<TD><INPUT TYPE="URL" SIZE="60" MAXLENGTH="1024" NAME="DEVICE_URI" VALUE="{current_device_uri?{current_device_uri}:{device_uri}}"></TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>Примеры:
+<PRE>
+ http://hostname:631/ipp/
+ http://hostname:631/ipp/port1
+
+ ipp://hostname/ipp/
+ ipp://hostname/ipp/port1
+
+ lpd://hostname/queue
+
+ socket://hostname
+ socket://hostname:9100
+</PRE>
+
+<P>Смотрите раздел «<A HREF="/help/network.html" TARGET="_blank">Сетевые принтеры</A>» Ð´Ð»Ñ Ð²Ñ‹ÑÑÐ½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð¾Ð³Ð¾ адреÑа вашего принтера.</P>
+
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Продолжить"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/ru/class-added.tmpl b/templates/ru/class-added.tmpl
new file mode 100644
index 000000000..298dfb928
--- /dev/null
+++ b/templates/ru/class-added.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">ÐÐ¾Ð²Ð°Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð°</H2>
+
+<P>Группа «<A HREF="/classes/{printer_name}">{printer_name}</A>» уÑпешно добавлена.
+
+</DIV>
diff --git a/templates/ru/class-confirm.tmpl b/templates/ru/class-confirm.tmpl
new file mode 100644
index 000000000..5bef5bf07
--- /dev/null
+++ b/templates/ru/class-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Удаление группы {printer_name}</H2>
+
+<P><B>Предупреждение:</B> вы дейÑтвительно хотите удалить группу
+«{printer_name}»?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="op" VALUE="delete-class"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Удалить группу"></FORM></P>
+
+</DIV>
diff --git a/templates/ru/class-deleted.tmpl b/templates/ru/class-deleted.tmpl
new file mode 100644
index 000000000..0ddd4d541
--- /dev/null
+++ b/templates/ru/class-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Удаление группы {printer_name}</H2>
+
+<P>Группа «{printer_name}» уÑпешно удалена.
+
+</DIV> \ No newline at end of file
diff --git a/templates/ru/class-jobs-header.tmpl b/templates/ru/class-jobs-header.tmpl
new file mode 100644
index 000000000..8487cbbda
--- /dev/null
+++ b/templates/ru/class-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">ЗаданиÑ</H3>
+</DIV>
diff --git a/templates/ru/class-modified.tmpl b/templates/ru/class-modified.tmpl
new file mode 100644
index 000000000..94df570f4
--- /dev/null
+++ b/templates/ru/class-modified.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Изменение группы {printer_name}</H2>
+
+<P>Группа «<A HREF="/classes/{printer_name}">{printer_name}</A>» уÑпешно изменена.
+
+</DIV> \ No newline at end of file
diff --git a/templates/ru/class.tmpl b/templates/ru/class.tmpl
new file mode 100644
index 000000000..70dd90a79
--- /dev/null
+++ b/templates/ru/class.tmpl
@@ -0,0 +1,44 @@
+<DIV CLASS="indent">
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?в ожидании:{printer_state=4?печать:приоÑтановлен}},
+{printer_is_accepting_jobs=0?не принимает заданиÑ:принимает заданиÑ},
+{server_is_sharing_printers=0?нет ÑовмеÑтного доÑтупа:{printer_is_shared=0?нет ÑовмеÑтного доÑтупа:разрешен ÑовмеÑтный доÑтуп}})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">ОбÑлуживание</OPTION>
+<OPTION VALUE="print-test-page">Печать пробной Ñтраницы</OPTION>
+{printer_state=5?<OPTION VALUE="start-class">Данные группы</OPTION>:<OPTION VALUE="stop-class">ПриоÑтановить группу</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Принимать заданиÑ</OPTION>:<OPTION VALUE="reject-jobs">Ðе принимать заданиÑ</OPTION>}
+<OPTION VALUE="move-jobs">ПеремеÑтить вÑе заданиÑ</OPTION>
+<OPTION VALUE="purge-jobs">Отменить вÑе заданиÑ</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Сохранить" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="ÐдминиÑтрирование">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="1">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">ÐдминиÑтрирование</OPTION>
+<OPTION VALUE="modify-class">Изменить группу</OPTION>
+<OPTION VALUE="delete-class">Удалить группу</OPTION>
+<OPTION VALUE="set-class-options">УÑтановить параметры по умолчанию</OPTION>
+<OPTION VALUE="set-as-default">УÑтановить как принтер по умолчанию</OPTION>
+<OPTION VALUE="set-allowed-users">СпиÑок разрешенных пользователей</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Сохранить" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">ОпиÑание:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">РаÑположение:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">СоÑтав:</TH><TD>{?member_uris=?Ðет принтеров:{member_uris}}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">По умолчанию:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:неизвеÑтный}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/ru/classes-header.tmpl b/templates/ru/classes-header.tmpl
new file mode 100644
index 000000000..53b3db328
--- /dev/null
+++ b/templates/ru/classes-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?Ðет групп:Группа {#printer_name} из {total}.</P>
diff --git a/templates/ru/classes.tmpl b/templates/ru/classes.tmpl
new file mode 100644
index 000000000..151ccad79
--- /dev/null
+++ b/templates/ru/classes.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="СпиÑок групп">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Очередь <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Очередь <SMALL>&#x25bc;</SMALL>}</A></TH><TH>ОпиÑание</TH><TH>РаÑположение</TH><TH>СоÑтав</TH><TH>СтатуÑ</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{?member_uris=?Ðет принтеров:{member_uris}}</TD><TD>{printer_state=3?Ð’ ожидании:{printer_state=4?Печатает:ПриоÑтановлена}}{printer_state_message?: {printer_state_message}:}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/ru/command.tmpl b/templates/ru/command.tmpl
new file mode 100644
index 000000000..4dc7b4e6e
--- /dev/null
+++ b/templates/ru/command.tmpl
@@ -0,0 +1,12 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{title} Ð´Ð»Ñ {printer_name}</H2>
+
+<P>{job_state>5?:<IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16"
+ALIGN="ABSMIDDLE" ALT="Индикатор занÑтоÑти"> }Обработка заданиÑ
+{job_state=3?в очереди:{job_state=4?удерживаетÑÑ:
+{job_state=5?обрабатываетÑÑ:{job_state=6?оÑтановлено:
+{job_state=7?отменено:{job_state=8?прервано:завершено}}}}}}{job_state=9?:{job_printer_state_message?,
+<EM>"{job_printer_state_message}"</EM>:}}</P>
+
+</DIV>
diff --git a/templates/ru/edit-config.tmpl b/templates/ru/edit-config.tmpl
new file mode 100644
index 000000000..d194059d8
--- /dev/null
+++ b/templates/ru/edit-config.tmpl
@@ -0,0 +1,24 @@
+<SCRIPT TYPE="text/javascript">
+function reset_config()
+{
+ document.cups.CUPSDCONF.value = "{?cupsdconf_default}";
+}
+</SCRIPT>
+
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Редактирование конфигурационного файла</H2>
+
+<FORM NAME="cups" METHOD="POST" ACTION="/admin/">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+
+<TEXTAREA NAME="CUPSDCONF" COLS="80" ROWS="25">{CUPSDCONF}</TEXTAREA>
+
+<P><INPUT TYPE="SUBMIT" NAME="SAVECHANGES" VALUE="Сохранить изменениÑ">
+<INPUT TYPE="BUTTON" VALUE="СброÑить вÑе изменениÑ"
+onClick="reset_config();"></P>
+
+</FORM>
+
+</DIV>
diff --git a/templates/ru/error-op.tmpl b/templates/ru/error-op.tmpl
new file mode 100644
index 000000000..29fce86b7
--- /dev/null
+++ b/templates/ru/error-op.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{?title} {?printer_name} — ошибка</H2>
+
+<P>Ошибка:</P>
+
+<BLOCKQUOTE>ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Â«{op}»!</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/ru/error.tmpl b/templates/ru/error.tmpl
new file mode 100644
index 000000000..9a780b19e
--- /dev/null
+++ b/templates/ru/error.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{?title} {?printer_name} — ошибка</H2>
+
+<P>{?message?{message}:Ошибка:}</P>
+
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/ru/header.tmpl.in b/templates/ru/header.tmpl.in
new file mode 100644
index 000000000..4fbdbe033
--- /dev/null
+++ b/templates/ru/header.tmpl.in
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{title} — CUPS @CUPS_VERSION@@CUPS_REVISION@</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+ {refresh_page?<META HTTP-EQUIV="Refresh" CONTENT="{refresh_page}">:}
+</HEAD>
+<BODY>
+<TABLE CLASS="page" SUMMARY="{title}">
+<TR><TD CLASS="body">
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" SUMMARY="">
+<TR HEIGHT="36">
+<TD><A HREF="http://www.cups.org/" TARGET="_blank"><IMG
+SRC="/images/left.gif" WIDTH="64" HEIGHT="36" BORDER="0" ALT=""></A></TD>
+<TD CLASS="unsel"><A HREF="/">&nbsp;&nbsp;Ðачало&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=admin?:un}sel"><A HREF="/admin">&nbsp;&nbsp;ÐдминиÑтрирование&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=classes?:un}sel"><A HREF="/classes/">&nbsp;&nbsp;Группы&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=help?:un}sel"><A HREF="/help/">&nbsp;&nbsp;Справка&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=jobs?:un}sel"><A HREF="/jobs/">&nbsp;&nbsp;ЗаданиÑ&nbsp;&nbsp;</A></TD>
+<TD CLASS="{SECTION=printers?:un}sel"><A HREF="/printers/">&nbsp;&nbsp;Принтеры&nbsp;&nbsp;</A></TD>
+<TD CLASS="unsel" WIDTH="100%"><FORM ACTION="/help/" METHOD="GET"><INPUT
+TYPE="SEARCH" NAME="QUERY" SIZE="20" PLACEHOLDER="ПоиÑк по Ñправке"
+VALUE="{SECTION=help?{?QUERY}:}" AUTOSAVE="org.cups.help" RESULTS="20"></FORM></TD>
+<TD><IMG SRC="/images/right.gif" WIDTH="4" HEIGHT="36" ALT=""></TD>
+</TR>
+<TR><TD COLSPAN="9">&nbsp;</TD></TR>
+</TABLE>
diff --git a/templates/ru/help-header.tmpl b/templates/ru/help-header.tmpl
new file mode 100644
index 000000000..6adbae380
--- /dev/null
+++ b/templates/ru/help-header.tmpl
@@ -0,0 +1,46 @@
+<DIV CLASS="indent">
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET">
+{TOPIC?<INPUT TYPE="HIDDEN" NAME="TOPIC" VALUE="{TOPIC}">:}
+
+<P ALIGN="CENTER"><B>ПоиÑк
+{HELPTITLE?в {HELPTITLE}:{TOPIC?в {TOPIC}:по Ñправке}}:</B> <INPUT
+TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER=""
+AUTOSAVE="org.cups.help" RESULTS="20">
+<INPUT TYPE="SUBMIT" NAME="SEARCH" VALUE="ПоиÑк">
+<INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="ОчиÑтить"></P>
+
+</FORM>
+
+<!-- Bookmarks -->
+<DIV CLASS="sidebar"><TABLE CLASS="inset" SUMMARY="Содержание">
+<TR><TD>
+
+<H3 CLASS="title">ДокументациÑ</H3>
+
+<P CLASS="l0"><A HREF="/help/{QUERY??QUERY={QUERY}:}">Ð’Ñе разделы</A></P>
+<HR>
+
+{[BMTEXT]<P CLASS="l{BMINDENT}"><A HREF="{BMLINK}">{BMTEXT}</A></P>
+}
+</TD></TR>
+</TABLE></DIV>
+
+{QUERY?<P>Результаты поиÑка в {HELPFILE?{HELPTITLE}:{TOPIC?{TOPIC}:вÑей Ñправке}}\:</P>
+{QTEXT?<UL>
+{[QTEXT]<LI><A HREF="{QLINK}">{QTEXT}</A>{QPTEXT? (in <I><A HREF="{QPLINK}">{QPTEXT}</A></I>):}</LI>}
+{QTEXT?</UL>:}
+:<P>Ðе найдено Ñовпадений.</P>}
+<HR NOSHADE>:}
+{HELPTITLE?<H1>{HELPTITLE}</H1>
+<FORM ACTION="/help/{?HELPFILE}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="PRINTABLE" VALUE="YES"><INPUT TYPE="SUBMIT" VALUE="Показать верÑию Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸"></FORM>:
+
+<H1>Справка</H1>
+
+<P>Это Ñправка CUPS. Введите выше Ñлова Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка в Ñправке и нажмите «ПоиÑк», чтобы показать результаты поиÑка.</P>
+
+<P>ЕÑли вы пока мало знакомы Ñ CUPS, прочтите раздел «<a
+href="/help/overview.html">Введение в CUPS</a>». Опытные пользователи
+могут обратитьÑÑ Ðº разделу <nobr>«<a href="/help/whatsnew.html">Что нового в CUPS 1.4</a>»</nobr>.</P>
+
+<P><A HREF="http://www.cups.org/">Веб-Ñайт CUPS</A> Ñодержит большое количеÑтво реÑурÑов Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»ÐµÐ¹, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ñ„Ð¾Ñ€ÑƒÐ¼, ответы
+на чаÑто задаваемые вопроÑÑ‹ и форму Ð´Ð»Ñ Ñ€ÐµÐ³Ð¸Ñтрации ошибок и пожеланий.</P>}
diff --git a/templates/ru/help-printable.tmpl b/templates/ru/help-printable.tmpl
new file mode 100644
index 000000000..2463c1630
--- /dev/null
+++ b/templates/ru/help-printable.tmpl
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+ <TITLE>{HELPTITLE}</TITLE>
+ <LINK REL="STYLESHEET" TYPE="text/css" HREF="/cups-printable.css">
+ <LINK REL="SHORTCUT ICON" HREF="/images/cups-icon.png" TYPE="image/png">
+</HEAD>
+<BODY>
diff --git a/templates/ru/help-trailer.tmpl b/templates/ru/help-trailer.tmpl
new file mode 100644
index 000000000..4c1ebed85
--- /dev/null
+++ b/templates/ru/help-trailer.tmpl
@@ -0,0 +1 @@
+</DIV>
diff --git a/templates/ru/job-cancel.tmpl b/templates/ru/job-cancel.tmpl
new file mode 100644
index 000000000..cba564469
--- /dev/null
+++ b/templates/ru/job-cancel.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Отмена Ð·Ð°Ð´Ð°Ð½Ð¸Ñ {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Задание {job_id}</A> отменено.
+
+</DIV>
diff --git a/templates/ru/job-hold.tmpl b/templates/ru/job-hold.tmpl
new file mode 100644
index 000000000..162e4a46e
--- /dev/null
+++ b/templates/ru/job-hold.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">ПриоÑтановка Ð·Ð°Ð´Ð°Ð½Ð¸Ñ {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Задание {job_id}</A> приоÑтановлено.
+
+</DIV>
diff --git a/templates/ru/job-move.tmpl b/templates/ru/job-move.tmpl
new file mode 100644
index 000000000..598e4db74
--- /dev/null
+++ b/templates/ru/job-move.tmpl
@@ -0,0 +1,27 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/{SECTION}/{job_id?:{printer_name}}">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{job_id?<INPUT TYPE="HIDDEN" NAME="JOB_ID" VALUE="{job_id}">:}
+
+<H2 CLASS="title">{job_id?Перемещение Ð·Ð°Ð´Ð°Ð½Ð¸Ñ {job_id}:Перемещение вÑех заданий}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">ПеремеÑтить на принтер:</TH>
+<TD>
+<SELECT NAME="JOB_PRINTER_URI" SIZE="10">
+{[job_printer_uri]<OPTION VALUE="{job_printer_uri}">{job_printer_name}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="{job_id?ПеремеÑтить задание:ПеремеÑтить вÑе заданиÑ}"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+
+</DIV>
diff --git a/templates/ru/job-moved.tmpl b/templates/ru/job-moved.tmpl
new file mode 100644
index 000000000..1755491dd
--- /dev/null
+++ b/templates/ru/job-moved.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">{job_id?Перемещение Ð·Ð°Ð´Ð°Ð½Ð¸Ñ {job_id}:Перемещение вÑех заданий}</H2>
+
+<P>{job_id?<A HREF="/jobs/{job_id}">Задание {job_id}</A>:Ð’Ñе заданиÑ} перемещены на принтер «<A HREF="{job_printer_uri}">{job_printer_name}</A>».</P>
+
+</DIV>
diff --git a/templates/ru/job-release.tmpl b/templates/ru/job-release.tmpl
new file mode 100644
index 000000000..876c85ba1
--- /dev/null
+++ b/templates/ru/job-release.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Разблокирование Ð·Ð°Ð´Ð°Ð½Ð¸Ñ {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Ð—Ð°Ð´Ð°Ð½Ð¸Ñ {job_id}</A> разблокировано.
+
+</DIV>
diff --git a/templates/ru/job-restart.tmpl b/templates/ru/job-restart.tmpl
new file mode 100644
index 000000000..490fc3a37
--- /dev/null
+++ b/templates/ru/job-restart.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">ПерезапуÑк Ð·Ð°Ð´Ð°Ð½Ð¸Ñ {job_id}</H2>
+
+<P><A HREF="{job_printer_uri}">Задание {job_id}</A> запущено заново.
+
+</DIV>
diff --git a/templates/ru/jobs-header.tmpl b/templates/ru/jobs-header.tmpl
new file mode 100644
index 000000000..d9ee96043
--- /dev/null
+++ b/templates/ru/jobs-header.tmpl
@@ -0,0 +1,6 @@
+<DIV CLASS="indent">{?which_jobs=?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="SUBMIT" VALUE="Показать активные заданиÑ"></FORM>}
+{?which_jobs=completed?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="completed"><INPUT TYPE="SUBMIT" VALUE="Показать завершенные заданиÑ"></FORM>}
+{?which_jobs=all?:<FORM ACTION="{?printer_name=?/jobs:{printer_uri_supported}}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="which_jobs" VALUE="all"><INPUT TYPE="SUBMIT" VALUE="Показать вÑе заданиÑ"></FORM>}</DIV>
+
+<P ALIGN="CENTER">{total=0?Ðет заданий:Задание {#job_id} из {total} {?which_jobs=?активных:{which_jobs=all?:завершенных}}.</P>
+
diff --git a/templates/ru/jobs.tmpl b/templates/ru/jobs.tmpl
new file mode 100644
index 000000000..c2226f67e
--- /dev/null
+++ b/templates/ru/jobs.tmpl
@@ -0,0 +1,37 @@
+{#job_id=0?:
+<TABLE CLASS="list" SUMMARY="ЗаданиÑ">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Ðомер <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> ID <SMALL>&#x25bc;</SMALL>}</A></TH><TH>Ðазвание</TH><TH>Пользователь</TH><TH>Размер</TH><TH>Страниц</TH><TH>СтатуÑ</TH><TH>Управление</TH></TR>
+</THEAD>
+<TBODY>
+{[job_id]
+<TR VALIGN="TOP">
+<TD><A HREF="{job_printer_uri}">{job_printer_name}</A>-{job_id}&nbsp;</TD>
+<TD>{?job_name=?ÐеизвеÑтное:{job_name}}&nbsp;</TD>
+<TD>{job_originating_user_name}&nbsp;</TD>
+<TD>{job_k_octets}k&nbsp;</TD>
+<TD>{job_media_sheets_completed=0?ÐеизвеÑтно:{?job_media_sheets_completed}}&nbsp;</TD>
+<TD>{job_state=3?Ð’ очереди<BR>{time_at_creation}:{job_state=4?ПриоÑтановлено Ñ<BR>{time_at_creation}:
+{job_state=5?Создано<BR>{time_at_processing}:{job_state=6?ОÑтановлено:
+{job_state=7?Отменено<BR>{time_at_completed}:{job_state=8?Прервано:Завершено<BR>{time_at_completed}}}}}}}&nbsp;{job_printer_state_message?<BR>
+<EM>"{job_printer_state_message}"</EM>:}</TD>
+<TD>
+{job_preserved>0?{job_state>5?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="restart-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="ПерезапуÑтить"></FORM>:}:}
+{job_state=4?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="release-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Продолжить"></FORM>:}
+{job_state=3?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="hold-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="ПриоÑтановить"></FORM>:}
+{job_state<7?
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="cancel-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="HIDDEN" NAME="job_printer_uri" VALUE="{job_printer_uri}">
+<INPUT TYPE="SUBMIT" VALUE="Отменить"></FORM>
+<FORM ACTION="/jobs/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="move-job"><INPUT TYPE="HIDDEN" NAME="job_id" VALUE="{job_id}"><INPUT TYPE="SUBMIT" VALUE="ПеремеÑтить"></FORM>:}
+&nbsp;</TD>
+</TR>
+}
+</TBODY>
+</TABLE>
+}
diff --git a/templates/ru/list-available-printers.tmpl b/templates/ru/list-available-printers.tmpl
new file mode 100644
index 000000000..161562845
--- /dev/null
+++ b/templates/ru/list-available-printers.tmpl
@@ -0,0 +1,11 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">ДоÑтупные принтеры</H2>
+
+{#device_uri=0?<P>Ðе обнаружено ни одного принтера.</P>
+:<UL>{[device_uri]
+<LI><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="add-printer"><INPUT TYPE="HIDDEN" NAME="TEMPLATE_NAME" VALUE="{template_name}"><INPUT TYPE="HIDDEN" NAME="PRINTER_LOCATION" VALUE="Сетевой принтер"><INPUT TYPE="HIDDEN" NAME="PRINTER_INFO" VALUE="{device_make_and_model}"><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}"><INPUT TYPE="SUBMIT" VALUE="Добавить Ñтот принтер"></FORM>
+{device_make_and_model} ({device_info})</LI>
+}</UL>}
+
+</DIV>
diff --git a/templates/ru/modify-class.tmpl b/templates/ru/modify-class.tmpl
new file mode 100644
index 000000000..a85698a52
--- /dev/null
+++ b/templates/ru/modify-class.tmpl
@@ -0,0 +1,34 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Изменение группы {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">ОпиÑание:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">РаÑположение:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"></TD>
+</TR>
+<TR>
+<TH CLASS="label">СоÑтав группы:</TH>
+<TD>
+<SELECT NAME="MEMBER_URIS" SIZE="10" MULTIPLE>
+{[member_uris]<OPTION VALUE="{member_uris}" {?member_selected}>{member_names}}
+</SELECT>
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Изменить группу"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV> \ No newline at end of file
diff --git a/templates/ru/modify-printer.tmpl b/templates/ru/modify-printer.tmpl
new file mode 100644
index 000000000..6277b5d6f
--- /dev/null
+++ b/templates/ru/modify-printer.tmpl
@@ -0,0 +1,42 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Изменение принтера {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+<INPUT TYPE="HIDDEN" NAME="BAUDRATE" VALUE="{?baudrate}">
+<INPUT TYPE="HIDDEN" NAME="BITS" VALUE="{?bits}">
+<INPUT TYPE="HIDDEN" NAME="PARITY" VALUE="{?parity}">
+<INPUT TYPE="HIDDEN" NAME="FLOW" VALUE="{?flow}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+
+<TABLE>
+<TR>
+<TH CLASS="label">ОпиÑание:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_INFO" VALUE="{?printer_info}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(раÑширенное опиÑание принтера, например, «HP LaserJet Ñ Ð´ÑƒÐ¿Ð»ÐµÐºÑной печатью»)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">РаÑположение:</TH>
+<TD><INPUT TYPE="TEXT" NAME="PRINTER_LOCATION" VALUE="{?printer_location}" SIZE="40" MAXLENGTH="127"><BR>
+<SMALL>(меÑтоположение принтера, например, «Кабинет 55»)</SMALL></TD>
+</TR>
+<TR>
+<TH CLASS="label">Подключение:</TH>
+<TD><INPUT TYPE="HIDDEN" NAME="DEVICE_URI" VALUE="{device_uri}">{device_uri}</TD>
+</TR>
+<TR>
+<TH CLASS="label">СовмеÑтный доÑтуп:</TH>
+<TD><INPUT TYPE="CHECKBOX" NAME="PRINTER_IS_SHARED" {PRINTER_IS_SHARED=1?CHECKED:}>
+Разрешить ÑовмеÑтный доÑтуп к Ñтому принтеру</TD>
+</TR>
+<TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Продолжить"></TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/ru/norestart.tmpl b/templates/ru/norestart.tmpl
new file mode 100644
index 000000000..0b74c036b
--- /dev/null
+++ b/templates/ru/norestart.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Применение изменений</H2>
+
+<P>Сервер не был перезапущен, поÑкольку не произошло изменений в конфигурации...</P>
+
+</DIV>
diff --git a/templates/ru/option-boolean.tmpl b/templates/ru/option-boolean.tmpl
new file mode 100644
index 000000000..e832ee102
--- /dev/null
+++ b/templates/ru/option-boolean.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD>
+{[choices]<INPUT TYPE="RADIO" NAME="{keyword-1}" {choices={defchoice-1}?CHECKED:} VALUE="{choices}">{text}}
+</TD>
+</TR>
diff --git a/templates/ru/option-conflict.tmpl b/templates/ru/option-conflict.tmpl
new file mode 100644
index 000000000..9497fb777
--- /dev/null
+++ b/templates/ru/option-conflict.tmpl
@@ -0,0 +1,7 @@
+<P><B>Ошибка:</B> Ñледующие параметры конфликтуют:</P>
+
+<UL>
+{[ckeyword]<LI><A HREF="#{ckeyword}">{ckeytext}</A>: {cchoice}</LI>
+}</UL>
+
+<P>Измените один или неÑколько параметров Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, чтобы избежать конфликта.</P>
diff --git a/templates/ru/option-header.tmpl b/templates/ru/option-header.tmpl
new file mode 100644
index 000000000..464726a50
--- /dev/null
+++ b/templates/ru/option-header.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="tab" ID="{group_id}">
+
+<H3 ALIGN="CENTER">{group}</H3>
+
+<TABLE WIDTH="100%">
diff --git a/templates/ru/option-pickmany.tmpl b/templates/ru/option-pickmany.tmpl
new file mode 100644
index 000000000..0da75e5d2
--- /dev/null
+++ b/templates/ru/option-pickmany.tmpl
@@ -0,0 +1,6 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" MULTIPLE SIZE="10">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT></TD>
+</TR>
diff --git a/templates/ru/option-pickone.tmpl b/templates/ru/option-pickone.tmpl
new file mode 100644
index 000000000..49a9929ae
--- /dev/null
+++ b/templates/ru/option-pickone.tmpl
@@ -0,0 +1,18 @@
+<TR>
+<TH {conflicted=1?CLASS="conflict":CLASS="label"} WIDTH="50%"><A NAME="{keyword}">{keytext}</A>:</TH>
+<TD><SELECT NAME="{keyword}" ID="select-{keyword}" ONCHANGE="update_paramtable('{keyword}')">
+{[choices]<OPTION {choices={defchoice-1}?SELECTED:} VALUE="{choices}">{text}}
+</SELECT>
+{iscustom=1?<TABLE NAME="paramtable" id="{keyword}-params">{[params]
+<TR><TH CLASS="sublabel">{paramtext}:</TH>
+<TD>{params=Units?<SELECT NAME="{keyword-1}.{params}">
+<OPTION VALUE="pt"{paramvalue=pt? SELECTED:}>Пункты</OPTION>
+<OPTION VALUE="mm"{paramvalue=mm? SELECTED:}>Миллиметры</OPTION>
+<OPTION VALUE="cm"{paramvalue=cm? SELECTED:}>Сантиметры</OPTION>
+<OPTION VALUE="in"{paramvalue=in? SELECTED:}>Дюймы</OPTION>
+<OPTION VALUE="ft"{paramvalue=ft? SELECTED:}>Футы</OPTION>
+<OPTION VALUE="m"{paramvalue=m? SELECTED:}>Метры</OPTION>
+</SELECT>:<INPUT TYPE="{inputtype}" NAME="{keyword-1}.{params}" VALUE="{paramvalue}">}</TD></TR>
+}</TABLE>
+</TD>:}
+</TR>
diff --git a/templates/ru/option-trailer.tmpl b/templates/ru/option-trailer.tmpl
new file mode 100644
index 000000000..15a314276
--- /dev/null
+++ b/templates/ru/option-trailer.tmpl
@@ -0,0 +1,5 @@
+</TABLE>
+
+<P ALIGN="CENTER"><INPUT TYPE="SUBMIT" VALUE="Сохранить параметры по умолчанию"></P>
+
+</DIV>
diff --git a/templates/ru/pager.tmpl b/templates/ru/pager.tmpl
new file mode 100644
index 000000000..fb1d2fae4
--- /dev/null
+++ b/templates/ru/pager.tmpl
@@ -0,0 +1,6 @@
+<TABLE CLASS="inset" SUMMARY="ПроÑмотр по Ñтраницам">
+<TR>
+ <TD WIDTH="50%">{PREV?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{PREV}"><INPUT TYPE="SUBMIT" VALUE="&#x25c0; Предворительный проÑмотр"></FORM>:&nbsp;}</TD>
+ <TD WIDTH="50%" ALIGN="RIGHT">{NEXT?<FORM ACTION="{THISURL}" METHOD="GET"><INPUT TYPE="HIDDEN" NAME="QUERY" VALUE="{?QUERY}"><INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{?ORDER}"><INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{?WHICH_JOBS}"><INPUT TYPE="HIDDEN" NAME="FIRST" VALUE="{NEXT}"><INPUT TYPE="SUBMIT" VALUE="Показать Ñледующую &#x25b6;"></FORM>:&nbsp;}</TD>
+</TR>
+</TABLE>
diff --git a/templates/ru/printer-accept.tmpl b/templates/ru/printer-accept.tmpl
new file mode 100644
index 000000000..24d100d48
--- /dev/null
+++ b/templates/ru/printer-accept.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Прием заданий {is_class?в группу:на принтер} {printer_name}</H2>
+
+<P>{is_class?Группа:Принтер} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+теперь принимает заданиÑ.</P>
+
+</DIV>
diff --git a/templates/ru/printer-added.tmpl b/templates/ru/printer-added.tmpl
new file mode 100644
index 000000000..eda0748c0
--- /dev/null
+++ b/templates/ru/printer-added.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Добавление принтера</H2>
+
+<P>Принтер «<A HREF="/printers/{printer_name}">{printer_name}</A>» уÑпешно
+добавлен.
+
+</DIV>
diff --git a/templates/ru/printer-configured.tmpl b/templates/ru/printer-configured.tmpl
new file mode 100644
index 000000000..33c4c143f
--- /dev/null
+++ b/templates/ru/printer-configured.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">ÐаÑтройки по умолчанию Ð´Ð»Ñ {printer_name}</H2>
+
+<P>{OP=set-class-options?Группа <A HREF="/classes/{printer_name}">:Принтер <A HREF="/printers/{printer_name}">}{printer_name}</A>
+теперь иÑпользуют параметры по умолчанию.
+
+</DIV>
diff --git a/templates/ru/printer-confirm.tmpl b/templates/ru/printer-confirm.tmpl
new file mode 100644
index 000000000..c57356d07
--- /dev/null
+++ b/templates/ru/printer-confirm.tmpl
@@ -0,0 +1,10 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Удаление принтера {printer_name}</H2>
+
+<P><B>Предупреждение:</B> вы дейÑтвительно хотите удалить принтер
+«{printer_name}»?</P>
+
+<P ALIGN="CENTER"><FORM ACTION="/admin/" METHOD="POST"><INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}"><INPUT TYPE="HIDDEN" NAME="OP" VALUE="delete-printer"><INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}"><INPUT TYPE="SUBMIT" NAME="confirm" VALUE="Удалить принтер"></FORM></P>
+
+</DIV>
diff --git a/templates/ru/printer-default.tmpl b/templates/ru/printer-default.tmpl
new file mode 100644
index 000000000..6297d79ed
--- /dev/null
+++ b/templates/ru/printer-default.tmpl
@@ -0,0 +1,12 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">УÑтановка {is_class?группы:принтера} {printer_name} по умолчанию</H2>
+
+<P>{is_class?Группа:Принтер} <A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>
+уÑтановлены на Ñервере по умолчанию Ð´Ð»Ñ Ð½Ð¾Ð²Ñ‹Ñ… заданий.</P>
+
+<BLOCKQUOTE><B>Примечание:</B> вы можете переопределить Ñто поведение Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ команды
+ <TT>lpoptions</TT>.</BLOCKQUOTE>
+
+</DIV>
diff --git a/templates/ru/printer-deleted.tmpl b/templates/ru/printer-deleted.tmpl
new file mode 100644
index 000000000..97fd8bd8c
--- /dev/null
+++ b/templates/ru/printer-deleted.tmpl
@@ -0,0 +1,7 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Удаление принтера {printer_name}</H2>
+
+<P>Принтер «{printer_name}» уÑпешно удален.
+
+</DIV>
diff --git a/templates/ru/printer-jobs-header.tmpl b/templates/ru/printer-jobs-header.tmpl
new file mode 100644
index 000000000..8487cbbda
--- /dev/null
+++ b/templates/ru/printer-jobs-header.tmpl
@@ -0,0 +1,3 @@
+<DIV CLASS="indent">
+<H3 CLASS="title">ЗаданиÑ</H3>
+</DIV>
diff --git a/templates/ru/printer-modified.tmpl b/templates/ru/printer-modified.tmpl
new file mode 100644
index 000000000..be27e5e7f
--- /dev/null
+++ b/templates/ru/printer-modified.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Изменение принтера {printer_name}</H2>
+
+<P>Параметры принтера «<A HREF="/printers/{printer_name}">{printer_name}</A>» уÑпешно
+изменены.
+
+</DIV> \ No newline at end of file
diff --git a/templates/ru/printer-purge.tmpl b/templates/ru/printer-purge.tmpl
new file mode 100644
index 000000000..44fda0d1f
--- /dev/null
+++ b/templates/ru/printer-purge.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">ОчиÑтка вÑех заданий Ð´Ð»Ñ {is_class?группы:принтера} {printer_name}</H2>
+
+<P>Ð’Ñе Ð·Ð°Ð´Ð°Ð½Ð¸Ñ Ð´Ð»Ñ {is_class?группы:принтера} «<A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>»
+очищены.</P>
+
+</DIV>
diff --git a/templates/ru/printer-reject.tmpl b/templates/ru/printer-reject.tmpl
new file mode 100644
index 000000000..488203c92
--- /dev/null
+++ b/templates/ru/printer-reject.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Отмена заданий Ð´Ð»Ñ {is_class?группы:принтера} {printer_name}</H2>
+
+<P>{is_class?Группа:Принтер} «<A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>»
+больше не принимает заданиÑ.</P>
+
+</DIV>
diff --git a/templates/ru/printer-start.tmpl b/templates/ru/printer-start.tmpl
new file mode 100644
index 000000000..69ffa7ef5
--- /dev/null
+++ b/templates/ru/printer-start.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Возобновить работу {is_class?группы:принтера} {printer_name}</H2>
+
+<P>{is_class?Группа:Принтер} «<A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>»
+теперь принимают заданиÑ.</P>
+
+</DIV>
diff --git a/templates/ru/printer-stop.tmpl b/templates/ru/printer-stop.tmpl
new file mode 100644
index 000000000..3fecd1e73
--- /dev/null
+++ b/templates/ru/printer-stop.tmpl
@@ -0,0 +1,9 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">ПриоÑтановить {is_class?группу:принтер} {printer_name}</H2>
+
+<P>{is_class?Группа:Принтер} «<A
+HREF="/{is_class?classes:printers}/{printer_name}">{printer_name}</A>»
+{is_class?была приоÑтановлена:был приоÑтановлен}.</P>
+
+</DIV>
diff --git a/templates/ru/printer.tmpl b/templates/ru/printer.tmpl
new file mode 100644
index 000000000..5128d004c
--- /dev/null
+++ b/templates/ru/printer.tmpl
@@ -0,0 +1,47 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title"><A HREF="{printer_uri_supported}">{printer_name}</A>
+({printer_state=3?в ожидании:{printer_state=4?печать:приоÑтановлен}},
+{printer_is_accepting_jobs=0?не принимает заданиÑ:принимает заданиÑ},
+{server_is_sharing_printers=0?нет ÑовмеÑтного доÑтупа:{printer_is_shared=0?нет ÑовмеÑтного доÑтупа:разрешен ÑовмеÑтный доÑтуп}})</H2>
+
+<FORM METHOD="POST" ACTION="{printer_uri_supported}" NAME="maintenance">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<SELECT NAME="OP" ONCHANGE="document.maintenance.submit();">
+<OPTION VALUE="">ОбÑлуживание</OPTION>
+<OPTION VALUE="print-test-page">Печать пробной Ñтраницы</OPTION>
+{printer_commands~.*Clean.*?<OPTION VALUE="clean-print-heads">ОчиÑтить головки</OPTION>:}
+{printer_commands~.*PrintSelfTestPage.*?<OPTION VALUE="print-self-test-page">Печать пробной Ñтраницы принтера</OPTION>:}
+{printer_state=5?<OPTION VALUE="start-printer">Возобновить печать</OPTION>:<OPTION VALUE="stop-printer">ПриоÑтановить принтер</OPTION>}
+{printer_is_accepting_jobs=0?<OPTION VALUE="accept-jobs">Принимать заданиÑ</OPTION>:<OPTION VALUE="reject-jobs">Ðе принимать заданиÑ</OPTION>}
+<OPTION VALUE="move-jobs">ПеремеÑтить вÑе заданиÑ</OPTION>
+<OPTION VALUE="purge-jobs">Закрыть вÑе заданиÑ</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<FORM METHOD="POST" ACTION="{admin_uri}" NAME="administration">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="printer_name" VALUE="{printer_name}">
+<SELECT NAME="OP" ONCHANGE="document.administration.submit();">
+<OPTION VALUE="">ÐдминиÑтрирование</OPTION>
+<OPTION VALUE="modify-printer">Изменить принтер</OPTION>
+<OPTION VALUE="delete-printer">Удалить принтер</OPTION>
+<OPTION VALUE="set-printer-options">УÑтановить параметры по умолчанию</OPTION>
+<OPTION VALUE="set-as-default">УÑтановить как принтер по умолчанию</OPTION>
+<OPTION VALUE="set-allowed-users">СпиÑок разрешенных пользователей</OPTION>
+</SELECT>
+<INPUT TYPE="SUBMIT" VALUE="Go" STYLE="display: none;">
+</FORM>
+
+<TABLE SUMMARY="{printer_name}">
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">ОпиÑание:</TH><TD>{printer_info}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">РаÑположение:</TH><TD>{printer_location}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Драйвер:</TH><TD>{printer_make_and_model} ({color_supported=1?цветной:черно-белый}{sides_supported?, дуплекÑÐ½Ð°Ñ Ð¿ÐµÑ‡Ð°Ñ‚ÑŒ:})<BR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">Подключение:</TH><TD>{device_uri}</TD></TR>
+<TR><TH ALIGN="RIGHT" VALIGN="TOP">По умолчанию:</TH><TD>job-sheets={job_sheets_default}
+media={media_default?{media_default}:неизвеÑтный}
+{sides_default?sides={sides_default}:}</TD></TR>
+</TABLE>
+
+</DIV>
diff --git a/templates/ru/printers-header.tmpl b/templates/ru/printers-header.tmpl
new file mode 100644
index 000000000..866245913
--- /dev/null
+++ b/templates/ru/printers-header.tmpl
@@ -0,0 +1 @@
+<P ALIGN="CENTER">{total=0?Ðет принтеров:Принтер {#printer_name} из {total}.</P>
diff --git a/templates/ru/printers.tmpl b/templates/ru/printers.tmpl
new file mode 100644
index 000000000..694658677
--- /dev/null
+++ b/templates/ru/printers.tmpl
@@ -0,0 +1,11 @@
+{#printer_name=0?:
+<TABLE CLASS="list" SUMMARY="СпиÑок принтеров">
+<THEAD>
+<TR><TH><A HREF="{THISURL}?QUERY={?QUERY}&amp;WHICH_JOBS={?WHICH_JOBS}&amp;FIRST={FIRST}&amp;ORDER={ORDER=dec?asc:dec}">{ORDER=dec?<SMALL>&#x25b2;</SMALL> Очередь <SMALL>&#x25b2;</SMALL>:<SMALL>&#x25bc;</SMALL> Очередь <SMALL>&#x25bc;</SMALL>}</A></TH><TH>ОпиÑание</TH><TH>РаÑположение</TH><TH>Драйвер</TH><TH>СтатуÑ</TH></TR>
+</THEAD>
+<TBODY>
+{[printer_name]
+<TR><TD><A HREF="{printer_uri_supported}">{printer_name}</A></TD><TD>{printer_info}</TD><TD>{printer_location}</TD><TD>{printer_make_and_model}</TD><TD>{printer_state=3?Ð’ ожидании:{printer_state=4?Печатает:ПриоÑтановлен}}{printer_state_message?: {printer_state_message}:}</TD></TR>
+}
+</TBODY>
+</TABLE></DIV>}
diff --git a/templates/ru/restart.tmpl b/templates/ru/restart.tmpl
new file mode 100644
index 000000000..1b8132dd3
--- /dev/null
+++ b/templates/ru/restart.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Применение изменений параметров</H2>
+
+<P><IMG SRC="/images/wait.gif" WIDTH="16" HEIGHT="16" ALIGN="ABSMIDDLE"
+ALT="Ожидание">ДождитеÑÑŒ перезагрузки Ñервера...</P>
+
+</DIV>
diff --git a/templates/ru/samba-export.tmpl b/templates/ru/samba-export.tmpl
new file mode 100644
index 000000000..22a3acb15
--- /dev/null
+++ b/templates/ru/samba-export.tmpl
@@ -0,0 +1,54 @@
+<SCRIPT TYPE="text/javascript"><!--
+function select_printers() {
+ var list = document.export_samba.EXPORT_NAME;
+ var sel = document.export_samba.EXPORT_ALL.checked;
+
+ for (i = 0; i < list.length; i ++) {
+ list.options[i].selected = sel;
+ }
+}
+--></SCRIPT>
+
+<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
+
+<H2 CLASS="title">ЭкÑпорт принтеров в Samba</H2>
+
+{error?<P>Ðевозможно ÑкÑпортировать принтеры в Samba\:</P>
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+<P>ПоÑмотрите файл «<A HREF="/admin/log/error_log"
+TARGET="_blank">error_log</A>».</P>:
+<P>Эта Ñтраница позволÑет добавить принтеры в Samba так, чтобы
+клиенты Windows могли получить доÑтуп к ним через значок <VAR>Сетевое окружение</VAR> на их
+рабочем Ñтоле. Ð’Ñ‹ должны уÑтановить на Windows драйвер принтера PostScript
+как опиÑано на Ñтранице руководÑтва <A
+HREF="/help/man-cupsaddsmb.html"
+TARGET="_blank">cupsaddsmb(8)</A>.</P>}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Принтеры:</TH>
+<TD>
+<SELECT NAME="EXPORT_NAME" SIZE="10" MULTIPLE>
+{[printer_name]<OPTION VALUE="{printer_name}"{export_all? SELECTED:{printer_export? SELECTED:}}>{printer_name}}
+</SELECT><BR>
+<INPUT TYPE="CHECKBOX" NAME="EXPORT_ALL"{export_all? CHECKED:}
+onChange="select_printers()"> ЭкÑпортировать вÑе принтеры
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Samba:</TH>
+<TD><INPUT TYPE="TEXT" NAME="USERNAME" VALUE="{?USERNAME}"> (обÑзательный параметр)</TD>
+</TR>
+<TR>
+<TH CLASS="label">Пароль Samba:</TH>
+<TD><INPUT TYPE="PASSWORD" NAME="PASSWORD" VALUE=""> (обÑзательный параметр)</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="ЭкÑпортировать принтеры в Samba"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/ru/samba-exported.tmpl b/templates/ru/samba-exported.tmpl
new file mode 100644
index 000000000..179b2ad8a
--- /dev/null
+++ b/templates/ru/samba-exported.tmpl
@@ -0,0 +1 @@
+<P>Принтеры уÑпешно ÑкÑпортированы в Samba.</P>
diff --git a/templates/ru/search.tmpl b/templates/ru/search.tmpl
new file mode 100644
index 000000000..64266599d
--- /dev/null
+++ b/templates/ru/search.tmpl
@@ -0,0 +1,10 @@
+<FORM ACTION="/{SECTION}/{?SEARCH_DEST}" METHOD="GET">
+{WHICH_JOBS?<INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{WHICH_JOBS}">:}
+{ORDER?<INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{ORDER}">:}
+
+<P ALIGN="CENTER"><B>ПоиÑк
+{SEARCH_DEST?на {SEARCH_DEST}:{SECTION=classes?группы:{SECTION=jobs?заданиÑ:принтера}}}:</B>
+<INPUT TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER="" AUTOSAVE="org.cups.{SECTION}" RESULTS="20"> <INPUT
+TYPE="SUBMIT" VALUE="ПоиÑк"> <INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="ОчиÑтить"></P>
+
+</FORM>
diff --git a/templates/ru/set-printer-options-header.tmpl b/templates/ru/set-printer-options-header.tmpl
new file mode 100644
index 000000000..e5c79dd44
--- /dev/null
+++ b/templates/ru/set-printer-options-header.tmpl
@@ -0,0 +1,26 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">УÑтановить параметры по умолчанию Ð´Ð»Ñ {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð¿Ñ€Ð¸Ð½Ñ‚ÐµÑ€Ð° Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð² по умолчанию">:}
+
+<SCRIPT TYPE="text/javascript"><!--
+function update_paramtable(option)
+{
+ var cb = document.getElementById("select-" + option)
+ var paramstable = document.getElementById(option + "-params");
+ if (cb.value == "Custom")
+ paramstable.style.display = "table";
+ else
+ paramstable.style.display = "none";
+}
+--></SCRIPT>
+
+<H3 CLASS="title">{[group_id]
+<A HREF="#{group_id}">{group}</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</H3>
+
+<DIV CLASS="tabs">
diff --git a/templates/ru/set-printer-options-trailer.tmpl b/templates/ru/set-printer-options-trailer.tmpl
new file mode 100644
index 000000000..11adc7012
--- /dev/null
+++ b/templates/ru/set-printer-options-trailer.tmpl
@@ -0,0 +1,16 @@
+</DIV>
+
+<SCRIPT TYPE="text/javascript"><!--
+// Hide custom options parameters for browsers that understand Javascript
+var paramtables = document.getElementsByName("paramtable");
+for (var i = 0; i < paramtables.length; i++)
+{
+ var opt = paramtables[i].id.substr(0, paramtables[i].id.lastIndexOf("-"));
+ var cb = document.getElementById("select-" + opt);
+ if (cb.value != "Custom")
+ paramtables[i].style.display = "none";
+}
+--></SCRIPT>
+</FORM>
+
+</DIV>
diff --git a/templates/ru/subscription-added.tmpl b/templates/ru/subscription-added.tmpl
new file mode 100644
index 000000000..6727217b6
--- /dev/null
+++ b/templates/ru/subscription-added.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>ПодпиÑка «{subscription_name}» была уÑпешно добавлена.</P>
+
+</DIV>
diff --git a/templates/ru/subscription-canceled.tmpl b/templates/ru/subscription-canceled.tmpl
new file mode 100644
index 000000000..205f993e9
--- /dev/null
+++ b/templates/ru/subscription-canceled.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>ПодпиÑка «#{notify_subscription_id}» была отменена.</P>
+
+</DIV>
diff --git a/templates/ru/test-page.tmpl b/templates/ru/test-page.tmpl
new file mode 100644
index 000000000..7330b80fb
--- /dev/null
+++ b/templates/ru/test-page.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Печать пробной Ñтраницы на {printer_name}</H2>
+
+<P>ÐŸÑ€Ð¾Ð±Ð½Ð°Ñ Ñтраница отправлена на печать. Ðомер Ð·Ð°Ð´Ð°Ð½Ð¸Ñ Â«<A HREF="/{SECTION}/{printer_name}">
+{printer_name}-{job_id}</A>».</P>
+
+</DIV>
diff --git a/templates/ru/trailer.tmpl b/templates/ru/trailer.tmpl
new file mode 100644
index 000000000..fa4ad012d
--- /dev/null
+++ b/templates/ru/trailer.tmpl
@@ -0,0 +1,6 @@
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS а также логотип CUPS ÑвлÑÑŽÑ‚ÑÑ Ð·Ð°Ñ€ÐµÐ³Ð¸Ñтрированными торговыми марками <A HREF="http://www.apple.com">Apple Inc.</A> ÐвторÑкие права на CUPS принадлежат (2007-2011) компании Apple Inc. Ð’Ñе права защищены.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/templates/ru/users.tmpl b/templates/ru/users.tmpl
new file mode 100644
index 000000000..c5b357501
--- /dev/null
+++ b/templates/ru/users.tmpl
@@ -0,0 +1,30 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
+
+<H2 CLASS="title">ДоÑтуп пользователей на {printer_name}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">Пользователи:</TH>
+<TD>
+<INPUT TYPE='TEXT' NAME='users' SIZE='60' VALUE='{?requesting_user_name_allowed}{?requesting_user_name_denied}'>
+<BR>
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-allowed' {requesting_user_name_allowed?checked:}>Разрешить Ñтим пользователÑм печать
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-denied' {requesting_user_name_denied?checked:}>Запретить Ñтим пользователÑм печать
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>
+<INPUT TYPE="SUBMIT" VALUE="Сохранить">
+</TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/templates/samba-export.tmpl b/templates/samba-export.tmpl
new file mode 100644
index 000000000..6515a4d3a
--- /dev/null
+++ b/templates/samba-export.tmpl
@@ -0,0 +1,55 @@
+<SCRIPT TYPE="text/javascript"><!--
+function select_printers() {
+ var list = document.export_samba.EXPORT_NAME;
+ var sel = document.export_samba.EXPORT_ALL.checked;
+
+ for (i = 0; i < list.length; i ++) {
+ list.options[i].selected = sel;
+ }
+}
+--></SCRIPT>
+
+<FORM METHOD="POST" ACTION="/admin/" NAME="export_samba">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="export-samba">
+
+<H2 CLASS="title">Export Printers to Samba</H2>
+
+{error?<P>Unable to export printers to Samba\:</P>
+<BLOCKQUOTE>{error}</BLOCKQUOTE>
+<P>Consult the <A HREF="/admin/log/error_log"
+TARGET="_blank">error_log</A> file for more information.</P>:
+<P>This page allows you to export printers to Samba so that
+Windows clients can access them through the <VAR>Network
+Neighborhood</VAR> or <VAR>Network Places</VAR> icons on their
+desktop. You must previously install the Windows PostScript
+printer drivers as described in the <A
+HREF="/help/man-cupsaddsmb.html"
+TARGET="_blank">cupsaddsmb(8)</A> man page.</P>}
+
+<TABLE>
+<TR>
+<TH CLASS="label">Printers:</TH>
+<TD>
+<SELECT NAME="EXPORT_NAME" SIZE="10" MULTIPLE>
+{[printer_name]<OPTION VALUE="{printer_name}"{export_all? SELECTED:{printer_export? SELECTED:}}>{printer_name}}
+</SELECT><BR>
+<INPUT TYPE="CHECKBOX" NAME="EXPORT_ALL"{export_all? CHECKED:}
+onChange="select_printers()"> Export All Printers
+</TD>
+</TR>
+<TR>
+<TH CLASS="label">Samba Username:</TH>
+<TD><INPUT TYPE="TEXT" NAME="USERNAME" VALUE="{?USERNAME}"> (required)</TD>
+</TR>
+<TR>
+<TH CLASS="label">Samba Password:</TH>
+<TD><INPUT TYPE="PASSWORD" NAME="PASSWORD" VALUE=""> (required)</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD><INPUT TYPE="SUBMIT" VALUE="Export Printers to Samba"></TD>
+</TR>
+</TABLE>
+
+</FORM>
diff --git a/templates/samba-exported.tmpl b/templates/samba-exported.tmpl
new file mode 100644
index 000000000..6fa8eb4a6
--- /dev/null
+++ b/templates/samba-exported.tmpl
@@ -0,0 +1 @@
+<P>Printers exported to samba successfully.</P>
diff --git a/templates/search.tmpl b/templates/search.tmpl
new file mode 100644
index 000000000..755269ea3
--- /dev/null
+++ b/templates/search.tmpl
@@ -0,0 +1,10 @@
+<FORM ACTION="/{SECTION}/{?SEARCH_DEST}" METHOD="GET">
+{WHICH_JOBS?<INPUT TYPE="HIDDEN" NAME="WHICH_JOBS" VALUE="{WHICH_JOBS}">:}
+{ORDER?<INPUT TYPE="HIDDEN" NAME="ORDER" VALUE="{ORDER}">:}
+
+<P ALIGN="CENTER"><B>Search in
+{SEARCH_DEST?{SEARCH_DEST}:{SECTION=classes?Classes:{SECTION=jobs?Jobs:Printers}}}:</B>
+<INPUT TYPE="SEARCH" NAME="QUERY" VALUE="{?QUERY}" SIZE="40" PLACEHOLDER="" AUTOSAVE="org.cups.{SECTION}" RESULTS="20"> <INPUT
+TYPE="SUBMIT" VALUE="Search"> <INPUT TYPE="SUBMIT" NAME="CLEAR" VALUE="Clear"></P>
+
+</FORM>
diff --git a/templates/set-printer-options-header.tmpl b/templates/set-printer-options-header.tmpl
new file mode 100644
index 000000000..3e7db4669
--- /dev/null
+++ b/templates/set-printer-options-header.tmpl
@@ -0,0 +1,26 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Set Default Options for {printer_name}</H2>
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+{HAVE_AUTOCONFIGURE?<INPUT TYPE="SUBMIT" NAME="AUTOCONFIGURE" VALUE="Query Printer for Default Options">:}
+
+<SCRIPT TYPE="text/javascript"><!--
+function update_paramtable(option)
+{
+ var cb = document.getElementById("select-" + option)
+ var paramstable = document.getElementById(option + "-params");
+ if (cb.value == "Custom")
+ paramstable.style.display = "table";
+ else
+ paramstable.style.display = "none";
+}
+--></SCRIPT>
+
+<H3 CLASS="title">{[group_id]
+<A HREF="#{group_id}">{group}</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</H3>
+
+<DIV CLASS="tabs">
diff --git a/templates/set-printer-options-trailer.tmpl b/templates/set-printer-options-trailer.tmpl
new file mode 100644
index 000000000..11adc7012
--- /dev/null
+++ b/templates/set-printer-options-trailer.tmpl
@@ -0,0 +1,16 @@
+</DIV>
+
+<SCRIPT TYPE="text/javascript"><!--
+// Hide custom options parameters for browsers that understand Javascript
+var paramtables = document.getElementsByName("paramtable");
+for (var i = 0; i < paramtables.length; i++)
+{
+ var opt = paramtables[i].id.substr(0, paramtables[i].id.lastIndexOf("-"));
+ var cb = document.getElementById("select-" + opt);
+ if (cb.value != "Custom")
+ paramtables[i].style.display = "none";
+}
+--></SCRIPT>
+</FORM>
+
+</DIV>
diff --git a/templates/subscription-added.tmpl b/templates/subscription-added.tmpl
new file mode 100644
index 000000000..c288b3649
--- /dev/null
+++ b/templates/subscription-added.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>Subscription {subscription_name} has been added successfully.</P>
+
+</DIV>
diff --git a/templates/subscription-canceled.tmpl b/templates/subscription-canceled.tmpl
new file mode 100644
index 000000000..86f2c1069
--- /dev/null
+++ b/templates/subscription-canceled.tmpl
@@ -0,0 +1,5 @@
+<DIV CLASS="indent">
+
+<P>Subscription #{notify_subscription_id} has been canceled.</P>
+
+</DIV>
diff --git a/templates/test-page.tmpl b/templates/test-page.tmpl
new file mode 100644
index 000000000..59e314a8d
--- /dev/null
+++ b/templates/test-page.tmpl
@@ -0,0 +1,8 @@
+<DIV CLASS="indent">
+
+<H2 CLASS="title">Print Test Page On {printer_name}</H2>
+
+<P>Test page sent; job ID is <A HREF="/{SECTION}/{printer_name}">
+{printer_name}-{job_id}</A>.</P>
+
+</DIV>
diff --git a/templates/trailer.tmpl b/templates/trailer.tmpl
new file mode 100644
index 000000000..100d9f7ad
--- /dev/null
+++ b/templates/trailer.tmpl
@@ -0,0 +1,8 @@
+</TD></TR>
+<TR><TD>&nbsp;</TD></TR>
+<TR><TD CLASS="trailer">CUPS and the CUPS logo are trademarks of
+<A HREF="http://www.apple.com">Apple Inc.</A> CUPS is copyright 2007-2011 Apple
+Inc. All rights reserved.</TD></TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/templates/users.tmpl b/templates/users.tmpl
new file mode 100644
index 000000000..0889f3f31
--- /dev/null
+++ b/templates/users.tmpl
@@ -0,0 +1,30 @@
+<DIV CLASS="indent">
+
+<FORM METHOD="POST" ACTION="/admin">
+<INPUT TYPE="HIDDEN" NAME="org.cups.sid" VALUE="{$org.cups.sid}">
+<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{OP}">
+<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
+{IS_CLASS?<INPUT TYPE="HIDDEN" NAME="IS_CLASS" VALUE="{IS_CLASS}">:}
+
+<H2 CLASS="title">Allowed Users For {printer_name}</H2>
+
+<TABLE>
+<TR>
+<TH CLASS="label">Users:</TH>
+<TD>
+<INPUT TYPE='TEXT' NAME='users' SIZE='60' VALUE='{?requesting_user_name_allowed}{?requesting_user_name_denied}'>
+<BR>
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-allowed' {requesting_user_name_allowed?checked:}>Allow these users to print
+<INPUT TYPE='RADIO' NAME='type' VALUE='requesting-user-name-denied' {requesting_user_name_denied?checked:}>Prevent these users from printing
+</TD>
+</TR>
+<TR>
+<TD></TD>
+<TD>
+<INPUT TYPE="SUBMIT" VALUE="Set Allowed Users">
+</TD>
+</TR>
+</TABLE>
+
+</FORM>
+</DIV>
diff --git a/test/4.1-requests.test b/test/4.1-requests.test
new file mode 100644
index 000000000..e2eb79ca6
--- /dev/null
+++ b/test/4.1-requests.test
@@ -0,0 +1,159 @@
+#
+# "$Id: 4.1-requests.test 9084 2010-04-07 06:54:31Z mike $"
+#
+# Verify that the server requires the following attributes:
+#
+# attributes-charset
+# attributes-natural-language
+# printer-uri/job-uri
+#
+{
+ # The name of the test...
+ NAME "No Attributes"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # What statuses are OK?
+ STATUS client-error-bad-request
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Charset Attribute"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+
+ # What statuses are OK?
+ STATUS client-error-bad-request
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Language Attribute"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR language attributes-natural-language en
+
+ # What statuses are OK?
+ STATUS client-error-bad-request
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Language + Charset Attributes"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR language attributes-natural-language en
+ ATTR charset attributes-charset utf-8
+
+ # What statuses are OK?
+ STATUS client-error-bad-request
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Charset + Language Attributes"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+
+ # What statuses are OK?
+ STATUS client-error-bad-request
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Charset + Language + Printer URI Attributes"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Charset + Language + Job URI Attributes"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri job-uri $scheme://$hostname:$port/jobs
+
+ # What statuses are OK?
+ STATUS client-error-bad-request
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Bad IPP Version"
+
+ # The operation to use
+ OPERATION get-jobs
+
+ # The version number to use
+ VERSION 0.0
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri ipp://localhost/printers
+
+ # What statuses are OK?
+ STATUS server-error-version-not-supported
+}
+#
+# End of "$Id: 4.1-requests.test 9084 2010-04-07 06:54:31Z mike $"
+#
diff --git a/test/4.2-cups-printer-ops.test b/test/4.2-cups-printer-ops.test
new file mode 100644
index 000000000..5fa828eb6
--- /dev/null
+++ b/test/4.2-cups-printer-ops.test
@@ -0,0 +1,327 @@
+#
+# "$Id: 4.2-cups-printer-ops.test 9084 2010-04-07 06:54:31Z mike $"
+#
+# Verify that the CUPS printer operations work.
+#
+{
+ # The name of the test...
+ NAME "Add Printer Test1"
+
+ # The operation to use
+ OPERATION cups-add-printer
+ RESOURCE /admin/
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ FILE testhp.ppd
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Verify Printer Test1 Added"
+
+ # The operation to use
+ OPERATION get-printer-attributes
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Delete Printer Test1"
+
+ # The operation to use
+ OPERATION cups-delete-printer
+ RESOURCE /admin/
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Verify Printer Test1 Deleted"
+
+ # The operation to use
+ OPERATION get-printer-attributes
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ # What statuses are OK?
+ STATUS client-error-not-found
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Subscribe to Printer Events"
+
+ # The operation to use
+ OPERATION Create-Printer-Subscription
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/
+ ATTR name requesting-user-name $user
+
+ GROUP subscription
+ ATTR uri notify-recipient-uri testnotify://
+ ATTR keyword notify-events printer-added,printer-modified,printer-deleted
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT notify-subscription-id
+}
+{
+ # The name of the test...
+ NAME "Add Printer Test2"
+
+ # The operation to use
+ OPERATION cups-add-printer
+ RESOURCE /admin/
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test2
+
+ FILE testhp.ppd
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Verify Printer Test2 Added"
+
+ # The operation to use
+ OPERATION get-printer-attributes
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test2
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Modify Printer Test2"
+
+ # The operation to use
+ OPERATION cups-add-printer
+ RESOURCE /admin/
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test2
+
+ GROUP printer
+ ATTR uri device-uri file:/tmp/Test2
+ ATTR enum printer-state 3
+ ATTR boolean printer-is-accepting-jobs true
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Re-Add Printer Test1"
+
+ # The operation to use
+ OPERATION cups-add-printer
+ RESOURCE /admin/
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ GROUP printer
+ ATTR uri device-uri file:/tmp/Test1
+ ATTR enum printer-state 3
+ ATTR boolean printer-is-accepting-jobs true
+
+ FILE testps.ppd
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Verify Printer Test1 Re-Added"
+
+ # The operation to use
+ OPERATION get-printer-attributes
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Get Default Printer with no default set"
+
+ # The operation to use
+ OPERATION cups-get-default
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+
+ # What statuses are OK?
+ STATUS client-error-not-found
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Set Default Printer to Test1"
+
+ # The operation to use
+ OPERATION cups-set-default
+ RESOURCE /admin/
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Get Default Printer"
+
+ # The operation to use
+ OPERATION cups-get-default
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT printer-name
+ EXPECT printer-uri-supported
+}
+{
+ # The name of the test...
+ NAME "Get IPP/2.x Attributes for Printer Test1"
+
+ # The operation to use
+ OPERATION get-printer-attributes
+ RESOURCE /
+
+ # The IPP version to use
+ VERSION 2.0
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT media-col-default
+}
+
+#
+# End of "$Id: 4.2-cups-printer-ops.test 9084 2010-04-07 06:54:31Z mike $"
+#
diff --git a/test/4.3-job-ops.test b/test/4.3-job-ops.test
new file mode 100644
index 000000000..e82de18dc
--- /dev/null
+++ b/test/4.3-job-ops.test
@@ -0,0 +1,330 @@
+#
+# "$Id: 4.3-job-ops.test 9084 2010-04-07 06:54:31Z mike $"
+#
+# Verify that the IPP job operations work.
+#
+{
+ # The name of the test...
+ NAME "Print PostScript Job with bad job-sheets value to Test1"
+
+ # The operation to use
+ OPERATION print-job
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR name requesting-user-name $user
+ ATTR name job-sheets "none\,none"
+
+ FILE testfile.ps
+
+ # What statuses are OK?
+ STATUS client-error-bad-request
+}
+{
+ # The name of the test...
+ NAME "Print PostScript Job to Test1"
+
+ # The operation to use
+ OPERATION print-job
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR name requesting-user-name $user
+
+ FILE testfile.ps
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-id
+}
+{
+ # The name of the test...
+ NAME "Get Job Attributes"
+
+ # The operation to use
+ OPERATION get-job-attributes
+ RESOURCE /jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR integer job-id $job-id
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-id
+ EXPECT job-uri
+ EXPECT job-state
+}
+{
+ # The name of the test...
+ NAME "Print JPEG Job to Test2"
+
+ # The operation to use
+ OPERATION print-job
+ RESOURCE /printers/Test2
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test2
+ ATTR name requesting-user-name $user
+
+ GROUP subscription
+ ATTR uri notify-recipient-uri testnotify:///
+
+ FILE testfile.jpg
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-id
+ EXPECT notify-subscription-id
+}
+{
+ # The name of the test...
+ NAME "Get Job Attributes"
+
+ # The operation to use
+ OPERATION get-job-attributes
+ RESOURCE /jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test2
+ ATTR integer job-id $job-id
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-id
+ EXPECT job-uri
+ EXPECT job-state
+}
+{
+ # The name of the test...
+ NAME "Print Text Job to Test1"
+
+ # The operation to use
+ OPERATION print-job
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR name requesting-user-name $user
+
+ FILE testfile.txt
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-id
+}
+{
+ # The name of the test...
+ NAME "Print PDF Job to Test1"
+
+ # The operation to use
+ OPERATION print-job
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR name requesting-user-name $user
+
+ GROUP job
+ ATTR keyword job-hold-until weekend
+
+ FILE testfile.pdf
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-id
+}
+{
+ # The name of the test...
+ NAME "Hold Job on Test1"
+
+ # The operation to use
+ OPERATION hold-job
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Release Job on Test1"
+
+ # The operation to use
+ OPERATION release-job
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Print Held Image Job to Test1"
+
+ # The operation to use
+ OPERATION print-job
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+ ATTR name requesting-user-name $user
+ GROUP job
+ ATTR keyword job-hold-until indefinite
+
+ FILE testfile.jpg
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-id
+}
+{
+ # The name of the test...
+ NAME "Cancel Job"
+
+ # The operation to use
+ OPERATION cancel-job
+ RESOURCE /jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri job-uri $method://$hostname:$port/jobs/$job-id
+ ATTR name requesting-user-name $user
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Get Job List on Test1"
+
+ # The operation to use
+ OPERATION get-jobs
+ RESOURCE /printers/Test1
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $method://$hostname:$port/printers/Test1
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT !job-printer-uri
+}
+{
+ # The name of the test...
+ NAME "Get All Jobs"
+
+ # The operation to use
+ OPERATION get-jobs
+ RESOURCE /jobs
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $scheme://$hostname:$port/
+ ATTR keyword requested-attributes all
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT job-uri
+ EXPECT job-id
+ EXPECT job-state
+ EXPECT job-printer-uri
+}
+
+#
+# End of "$Id: 4.3-job-ops.test 9084 2010-04-07 06:54:31Z mike $"
+#
diff --git a/test/4.4-subscription-ops.test b/test/4.4-subscription-ops.test
new file mode 100644
index 000000000..720add80d
--- /dev/null
+++ b/test/4.4-subscription-ops.test
@@ -0,0 +1,153 @@
+#
+# "$Id: 4.4-subscription-ops.test 9352 2010-11-06 04:55:26Z mike $"
+#
+# Verify that the CUPS subscription operations work.
+#
+{
+ # The name of the test...
+ NAME "Add Printer Subscription w/Lease"
+
+ # The operation to use
+ OPERATION Create-Printer-Subscription
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1
+ ATTR name requesting-user-name $user
+
+ GROUP subscription
+ ATTR uri notify-recipient-uri testnotify://
+ ATTR keyword notify-events printer-state-changed
+ ATTR integer notify-lease-duration 5
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT notify-subscription-id
+ DISPLAY notify-subscription-id
+}
+{
+ # The name of the test...
+ NAME "Verify Subscription Expiration"
+
+ # Delay test for 7 seconds to allow lease to expire...
+ DELAY 7
+
+ # The operation to use
+ OPERATION Get-Subscription-Attributes
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1
+ ATTR integer notify-subscription-id $notify-subscription-id
+ ATTR name requesting-user-name $user
+
+ # What statuses are OK?
+ STATUS client-error-not-found
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+{
+ # The name of the test...
+ NAME "Add 2 Printer Subscriptions w/Lease"
+
+ # The operation to use
+ OPERATION Create-Printer-Subscription
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1
+ ATTR name requesting-user-name $user
+
+ GROUP subscription
+ ATTR uri notify-recipient-uri testnotify://
+ ATTR keyword notify-events printer-state-changed
+ ATTR integer notify-lease-duration 5
+
+ GROUP subscription
+ ATTR uri notify-recipient-uri testnotify://
+ ATTR keyword notify-events printer-config-changed
+ ATTR integer notify-lease-duration 5
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT notify-subscription-id
+ DISPLAY notify-subscription-id
+}
+{
+ # The name of the test...
+ NAME "List Printer Subscriptions"
+
+ # The operation to use
+ OPERATION Get-Subscriptions
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1
+ ATTR name requesting-user-name $user
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+ EXPECT notify-subscription-id
+ DISPLAY notify-subscription-id
+ EXPECT notify-printer-uri
+ DISPLAY notify-printer-uri
+ EXPECT notify-events
+ DISPLAY notify-events
+}
+{
+ # The name of the test...
+ NAME "Check MaxSubscriptions limits"
+
+ # The operation to use
+ OPERATION Create-Printer-Subscription
+ RESOURCE /
+
+ # The attributes to send
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1
+ ATTR name requesting-user-name $user
+
+ GROUP subscription
+ ATTR uri notify-recipient-uri testnotify://
+ ATTR keyword notify-events printer-state-changed
+ ATTR integer notify-lease-duration 5
+
+ # What statuses are OK?
+ STATUS client-error-too-many-subscriptions
+
+ # What attributes do we expect?
+ EXPECT attributes-charset
+ EXPECT attributes-natural-language
+}
+
+#
+# End of "$Id: 4.4-subscription-ops.test 9352 2010-11-06 04:55:26Z mike $"
+#
diff --git a/test/5.1-lpadmin.sh b/test/5.1-lpadmin.sh
new file mode 100755
index 000000000..c96ccfcf6
--- /dev/null
+++ b/test/5.1-lpadmin.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lpadmin command.
+#
+# Copyright 2007-2009 by Apple Inc.
+# Copyright 1997-2005 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+echo "Add Printer Test"
+echo ""
+echo " lpadmin -p Test3 -v file:/dev/null -E -m drv:///sample.drv/deskjet.ppd"
+../systemv/lpadmin -p Test3 -v file:/dev/null -E -m drv:///sample.drv/deskjet.ppd 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "Modify Printer Test"
+echo ""
+echo " lpadmin -p Test3 -v file:/tmp/Test3 -o PageSize=A4"
+../systemv/lpadmin -p Test3 -v file:/tmp/Test3 -o PageSize=A4 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "Delete Printer Test"
+echo ""
+echo " lpadmin -x Test3"
+../systemv/lpadmin -x Test3 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.2-lpc.sh b/test/5.2-lpc.sh
new file mode 100755
index 000000000..c1a3f6ce2
--- /dev/null
+++ b/test/5.2-lpc.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lpc command.
+#
+# Copyright 2007 by Apple Inc.
+# Copyright 1997-2005 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+echo "LPC Test"
+echo ""
+echo " lpc status"
+../berkeley/lpc status 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.3-lpq.sh b/test/5.3-lpq.sh
new file mode 100755
index 000000000..ef895ebc3
--- /dev/null
+++ b/test/5.3-lpq.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lpq command.
+#
+# Copyright 2007 by Apple Inc.
+# Copyright 1997-2005 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+echo "LPQ Test"
+echo ""
+echo " lpq -P Test1"
+../berkeley/lpq -P Test1 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.4-lpstat.sh b/test/5.4-lpstat.sh
new file mode 100755
index 000000000..83c8585bb
--- /dev/null
+++ b/test/5.4-lpstat.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lpstat command.
+#
+# Copyright 2007-2009 by Apple Inc.
+# Copyright 1997-2005 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+echo "LPSTAT Test"
+echo ""
+echo " lpstat -t"
+../systemv/lpstat -t 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "LPSTAT Test"
+echo ""
+echo " lpstat -H"
+server="`../systemv/lpstat -H 2>&1`"
+if test $? != 0 -o "x$server" != xlocalhost:8631; then
+ echo " FAILED ($server)"
+ exit 1
+else
+ echo " PASSED ($server)"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.5-lp.sh b/test/5.5-lp.sh
new file mode 100755
index 000000000..53b7bcbdd
--- /dev/null
+++ b/test/5.5-lp.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lp command.
+#
+# Copyright 2007-2009 by Apple Inc.
+# Copyright 1997-2005 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+echo "LP Default Test"
+echo ""
+echo " lp testfile.pdf"
+../systemv/lp testfile.pdf 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "LP Destination Test"
+echo ""
+echo " lp -d Test2 testfile.jpg"
+../systemv/lp -d Test2 testfile.jpg 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "LP Options Test"
+echo ""
+echo " lp -d Test1 -P 1-4 -o job-sheets=classified,classified testfile.pdf"
+../systemv/lp -d Test1 -P 1-4 -o job-sheets=classified,classified testfile.pdf 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "LP Flood Test ($1 times in parallel)"
+echo ""
+echo " lp -d Test1 testfile.jpg"
+echo " lp -d Test2 testfile.jpg"
+i=0
+while test $i -lt $1; do
+ echo " flood copy $i..." 1>&2
+
+ j=1
+ while test $j -le $2; do
+ ../systemv/lp -d test-$j testfile.jpg 2>&1
+ j=`expr $j + 1`
+ done
+
+ ../systemv/lp -d Test1 testfile.jpg 2>&1 &
+ ../systemv/lp -d Test2 testfile.jpg 2>&1 &
+ lppid=$!
+
+ i=`expr $i + 1`
+done
+wait $lppid
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+./waitjobs.sh
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.6-lpr.sh b/test/5.6-lpr.sh
new file mode 100755
index 000000000..b92a27d09
--- /dev/null
+++ b/test/5.6-lpr.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lpr command.
+#
+# Copyright 2007-2009 by Apple Inc.
+# Copyright 1997-2005 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+echo "LPR Default Test"
+echo ""
+echo " lpr testfile.pdf"
+../berkeley/lpr testfile.pdf 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "LPR Destination Test"
+echo ""
+echo " lpr -P Test2 testfile.jpg"
+../berkeley/lpr -P Test2 testfile.jpg 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "LPR Options Test"
+echo ""
+echo " lpr -P Test1 -o number-up=4 -o job-sheets=standard,none testfile.pdf"
+../berkeley/lpr -P Test1 -o number-up=4 -o job-sheets=standard,none testfile.pdf 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "LPR Flood Test ($1 times in parallel)"
+echo ""
+echo " lpr -P Test1 testfile.jpg"
+echo " lpr -P Test2 testfile.jpg"
+i=0
+while test $i -lt $1; do
+ echo " flood copy $i..." 1>&2
+
+ j=1
+ while test $j -le $2; do
+ ../berkeley/lpr -P test-$j testfile.jpg 2>&1
+ j=`expr $j + 1`
+ done
+
+ ../berkeley/lpr -P Test1 testfile.jpg 2>&1 &
+ ../berkeley/lpr -P Test2 testfile.jpg 2>&1 &
+ lprpid=$!
+
+ i=`expr $i + 1`
+done
+wait $lppid
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+./waitjobs.sh
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.7-lprm.sh b/test/5.7-lprm.sh
new file mode 100755
index 000000000..e1ba395df
--- /dev/null
+++ b/test/5.7-lprm.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lprm command.
+#
+# Copyright 2007 by Apple Inc.
+# Copyright 1997-2005 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+echo "LPRM Current Test"
+echo ""
+echo " lpr -o job-hold-until=indefinite testfile.jpg"
+../berkeley/lpr -o job-hold-until=indefinite testfile.jpg 2>&1
+echo " lprm"
+../berkeley/lprm 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "LPRM Destination Test"
+echo ""
+echo " lpr -P Test1 -o job-hold-until=indefinite testfile.jpg"
+../berkeley/lpr -P Test1 -o job-hold-until=indefinite testfile.jpg 2>&1
+echo " lprm Test1"
+../berkeley/lprm Test1 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.8-cancel.sh b/test/5.8-cancel.sh
new file mode 100755
index 000000000..ddc346040
--- /dev/null
+++ b/test/5.8-cancel.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the cancel command.
+#
+# Copyright 2007-2008 by Apple Inc.
+# Copyright 1997-2006 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+echo "Cancel Destination Test"
+echo ""
+echo " lp -d Test1 -o job-hold-until=indefinite testfile.jpg"
+../systemv/lp -d Test1 -o job-hold-until=indefinite testfile.jpg 2>&1
+echo " cancel Test1"
+../systemv/cancel Test1 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "Cancel All Test"
+echo ""
+echo " cancel -a"
+../systemv/cancel -a 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/5.9-lpinfo.sh b/test/5.9-lpinfo.sh
new file mode 100755
index 000000000..d9bff8308
--- /dev/null
+++ b/test/5.9-lpinfo.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Test the lpinfo command.
+#
+# Copyright 2007-2008 by Apple Inc.
+# Copyright 1997-2005 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+echo "LPINFO Devices Test"
+echo ""
+echo " lpinfo -v"
+../systemv/lpinfo -v 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "LPINFO Drivers Test"
+echo ""
+echo " lpinfo -m"
+../systemv/lpinfo -m 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+echo "LPINFO Drivers Test"
+echo ""
+echo " lpinfo -m | grep -q sample.drv"
+../systemv/lpinfo -m | grep -q sample.drv 2>&1
+if test $? != 0; then
+ echo " FAILED"
+ exit 1
+else
+ echo " PASSED"
+fi
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/test/Dependencies b/test/Dependencies
new file mode 100644
index 000000000..1c2966362
--- /dev/null
+++ b/test/Dependencies
@@ -0,0 +1,19 @@
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+ippserver.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ippserver.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h
+ippserver.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
+ippserver.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
+ippserver.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+ippserver.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+ippserver.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+ippserver.o: ../cups/transcode.h ../cups/thread-private.h
+ipptool.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
+ipptool.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
+ipptool.o: ../cups/language.h ../cups/string-private.h ../config.h
+ipptool.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
+ipptool.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+ipptool.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+ipptool.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+ipptool.o: ../cups/thread-private.h ../cups/file-private.h
+ipptool.o: ../cups/cups-private.h
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 000000000..24b2d84bc
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,181 @@
+#
+# "$Id$"
+#
+# IPP test makefile for CUPS.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 1997-2006 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+include ../Makedefs
+
+
+#
+# Sample test files.
+#
+
+TESTFILES = \
+ create-printer-subscription.test \
+ get-completed-jobs.test \
+ get-jobs.test \
+ ipp-1.1.test \
+ ipp-2.0.test \
+ ipp-2.1.test \
+ testfile.jpg \
+ testfile.pdf \
+ testfile.ps \
+ testfile.txt
+OBJS = \
+ ippserver.o \
+ ipptool.o
+TARGETS = \
+ ippserver \
+ ipptool \
+ ipptool-static
+
+
+#
+# Make all targets...
+#
+
+all: $(TARGETS)
+
+
+#
+# Make library targets...
+#
+
+libs:
+
+
+#
+# Make unit tests...
+#
+
+unittests:
+
+
+#
+# Clean all object files...
+#
+
+clean:
+ $(RM) $(TARGETS) $(OBJS)
+
+
+#
+# Update dependencies (without system header dependencies...)
+#
+
+depend:
+ makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1
+
+
+#
+# Install all targets...
+#
+
+install: all install-data install-headers install-libs install-exec
+
+
+#
+# Install data files...
+#
+
+install-data:
+ echo Installing sample ipptool files in $(DATADIR)/ipptool...
+ $(INSTALL_DIR) -m 755 $(DATADIR)/ipptool
+ for file in $(TESTFILES); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/ipptool; \
+ done
+
+
+#
+# Install programs...
+#
+
+install-exec:
+ echo Installing ipptool in $(BINDIR)...
+ $(INSTALL_DIR) -m 755 $(BINDIR)
+ $(INSTALL_BIN) ipptool $(BINDIR)
+ if test "x$(SYMROOT)" != "x"; then \
+ $(INSTALL_DIR) $(SYMROOT); \
+ cp ipptool $(SYMROOT); \
+ fi
+
+
+#
+# Install headers...
+#
+
+install-headers:
+
+
+#
+# Install libraries...
+#
+
+install-libs:
+
+
+#
+# Unnstall all targets...
+#
+
+uninstall:
+
+
+#
+# ippserver
+#
+
+ippserver: ippserver.o ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ ippserver.o ../cups/$(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# ippserver-shared
+#
+
+ippserver-shared: ippserver.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ ippserver.o $(LIBS)
+
+
+#
+# ipptool
+#
+
+ipptool: ipptool.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ ipptool.o $(LIBS)
+
+
+#
+# ipptool-static
+#
+
+ipptool-static: ipptool.o ../cups/$(LIBCUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ ipptool.o ../cups/$(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+
+
+#
+# Dependencies...
+#
+
+include Dependencies
+
+
+#
+# End of "$Id$".
+#
diff --git a/test/create-job-format.test b/test/create-job-format.test
new file mode 100644
index 000000000..87d94a5b6
--- /dev/null
+++ b/test/create-job-format.test
@@ -0,0 +1,56 @@
+# Print a test page using create-job + send-document, specifying the
+# document format.
+{
+ # The name of the test...
+ NAME "Print test page using create-job"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION create-job
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ GROUP job
+ ATTR integer copies 1
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
+{
+ # The name of the test...
+ NAME "... and send-document"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION send-document
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+ ATTR mimetype document-format application/postscript
+ ATTR boolean last-document true
+
+ FILE ../data/testprint.ps
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
diff --git a/test/create-job-sheets.test b/test/create-job-sheets.test
new file mode 100644
index 000000000..d15bb7d4b
--- /dev/null
+++ b/test/create-job-sheets.test
@@ -0,0 +1,55 @@
+# Test create-job + send-document with job-sheets attribute
+{
+ # The name of the test...
+ NAME "Print test page using create-job"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION create-job
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ GROUP job
+ ATTR integer copies 1
+ ATTR name job-sheets standard
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
+{
+ # The name of the test...
+ NAME "... and send-document"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION send-document
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+ ATTR boolean last-document true
+
+ FILE ../data/testprint.ps
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
diff --git a/test/create-job-timeout.test b/test/create-job-timeout.test
new file mode 100644
index 000000000..514924d42
--- /dev/null
+++ b/test/create-job-timeout.test
@@ -0,0 +1,54 @@
+# Print a test page using create-job + send-document, but don't send
+# last-document = true
+{
+ # The name of the test...
+ NAME "Print test page using create-job"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION create-job
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ GROUP job
+ ATTR integer copies 1
+ ATTR name job-sheets unclassified,unclassified
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
+{
+ # The name of the test...
+ NAME "... and send-document"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION send-document
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+ ATTR mimetype document-format application/octet-stream
+
+ FILE ../data/testprint.ps
+
+ # What statuses are OK?
+ STATUS successful-ok
+}
diff --git a/test/create-job.test b/test/create-job.test
new file mode 100644
index 000000000..61336c63b
--- /dev/null
+++ b/test/create-job.test
@@ -0,0 +1,52 @@
+# Print a test page using create-job + send-document
+{
+ # The name of the test...
+ NAME "Print test page using create-job"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION create-job
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ GROUP job
+ ATTR integer copies 1
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
+{
+ # The name of the test...
+ NAME "... and send-document"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION send-document
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+ ATTR boolean last-document true
+
+ FILE ../data/testprint.ps
+
+ # What statuses are OK?
+ STATUS successful-ok
+}
diff --git a/test/create-printer-subscription.test b/test/create-printer-subscription.test
new file mode 100644
index 000000000..19f5c85f5
--- /dev/null
+++ b/test/create-printer-subscription.test
@@ -0,0 +1,49 @@
+#
+# "$Id: create-printer-subscription.test 9084 2010-04-07 06:54:31Z mike $"
+#
+# Create a printer subscription.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 2001-2006 by Easy Software Products. All rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# Usage:
+#
+# ./ipptool -d recipient=uri printer-uri create-printer-subscription.test
+#
+
+
+{
+ # The name of the test...
+ NAME "Create a printer subscription"
+
+ # The operation to use
+ OPERATION Create-Printer-Subscription
+
+ # The attributes to send
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ GROUP subscription-attributes-tag
+ ATTR uri notify-recipient $recipient
+ ATTR keyword notify-events printer-state-changed
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT notify-subscription-id OF-TYPE integer WITH-VALUE >0
+ DISPLAY notify-subscription-id
+}
+
+
+#
+# End of "$Id: create-printer-subscription.test 9084 2010-04-07 06:54:31Z mike $"
+#
diff --git a/test/get-completed-jobs.test b/test/get-completed-jobs.test
new file mode 100644
index 000000000..7b5696c48
--- /dev/null
+++ b/test/get-completed-jobs.test
@@ -0,0 +1,51 @@
+#
+# "$Id: get-completed-jobs.test 9086 2010-04-07 18:46:04Z mike $"
+#
+# Get list of completed jobs.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 2001-2006 by Easy Software Products. All rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# Usage:
+#
+# ./ipptool printer-uri get-completed-jobs.test
+#
+
+
+{
+ # The name of the test...
+ NAME "Get completed jobs"
+
+ # The operation to use
+ OPERATION Get-Jobs
+
+ # Attributes, starting in the operation group...
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR keyword which-jobs completed
+ ATTR keyword requested-attributes
+ job-id,job-state,job-name,job-originating-user-name,job-media-sheets-completed
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes to display
+ DISPLAY job-id
+ DISPLAY job-state
+ DISPLAY job-name
+ DISPLAY job-originating-user-name
+ DISPLAY job-media-sheets-completed
+}
+
+
+#
+# End of "$Id: get-completed-jobs.test 9086 2010-04-07 18:46:04Z mike $".
+#
diff --git a/test/get-devices.test b/test/get-devices.test
new file mode 100644
index 000000000..76bb5ec76
--- /dev/null
+++ b/test/get-devices.test
@@ -0,0 +1,21 @@
+# Get devices using CUPS-get-devices
+{
+ # The name of the test...
+ NAME "Get devices using CUPS-get-devices"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION CUPS-get-devices
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
diff --git a/test/get-job-attributes.test b/test/get-job-attributes.test
new file mode 100644
index 000000000..ba62bd7f3
--- /dev/null
+++ b/test/get-job-attributes.test
@@ -0,0 +1,27 @@
+# Test get-job-attributes by sending a print job, getting the attributes,
+# and cancelling it.
+{
+ # The name of the test...
+ NAME "Get job info with get-job-attributes"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION get-job-attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri job-uri $uri
+# ATTR keyword requested-attributes job-media-sheets-completed,job-state
+
+ # What statuses are OK?
+ #STATUS ok
+ #STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-uri
+ EXPECT job-state
+}
diff --git a/test/get-job-attributes2.test b/test/get-job-attributes2.test
new file mode 100644
index 000000000..6a8673f88
--- /dev/null
+++ b/test/get-job-attributes2.test
@@ -0,0 +1,28 @@
+# Test get-job-attributes
+{
+ # The name of the test...
+ NAME "get-job-attributes"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION get-job-attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri job-uri $uri
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-uri
+ EXPECT job-state
+ EXPECT time-at-creation
+ EXPECT time-at-completed
+ EXPECT time-at-processing
+}
diff --git a/test/get-jobs.test b/test/get-jobs.test
new file mode 100644
index 000000000..4da5f6a7a
--- /dev/null
+++ b/test/get-jobs.test
@@ -0,0 +1,53 @@
+#
+# "$Id: get-jobs.test 9702 2011-04-20 21:16:08Z mike $"
+#
+# Get list of not-completed jobs.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 2001-2006 by Easy Software Products. All rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# Usage:
+#
+# ./ipptool printer-uri get-jobs.test
+#
+
+
+{
+ # The name of the test...
+ NAME "Get pending jobs"
+
+ # The operation to use
+ OPERATION Get-Jobs
+
+ # Attributes, starting in the operation group...
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR keyword requested-attributes
+ job-id,job-state,job-name,job-originating-user-name,job-media-sheets,job-media-sheets-completed,job-impressions,job-impressions-completed
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes to display
+ DISPLAY job-id
+ DISPLAY job-state
+ DISPLAY job-name
+ DISPLAY job-originating-user-name
+ DISPLAY job-impressions
+ DISPLAY job-impressions-completed
+ DISPLAY job-media-sheets
+ DISPLAY job-media-sheets-completed
+}
+
+
+#
+# End of "$Id: get-jobs.test 9702 2011-04-20 21:16:08Z mike $".
+#
diff --git a/test/get-ppd-printer.test b/test/get-ppd-printer.test
new file mode 100644
index 000000000..4f723f88b
--- /dev/null
+++ b/test/get-ppd-printer.test
@@ -0,0 +1,20 @@
+# Get printer PPD file using CUPS-Get-PPD
+{
+ # The name of the test...
+ NAME "Get printer PPD file using CUPS-Get-PPD"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION CUPS-Get-PPD
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ # What statuses are OK?
+ STATUS successful-ok
+}
diff --git a/test/get-ppd.test b/test/get-ppd.test
new file mode 100644
index 000000000..24a935e4d
--- /dev/null
+++ b/test/get-ppd.test
@@ -0,0 +1,20 @@
+# Get PPD file using CUPS-get-ppd
+{
+ # The name of the test...
+ NAME "Get PPD file using CUPS-get-ppd"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION CUPS-get-ppd
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR name ppd-name $ENV[ppd-name]
+
+ # What statuses are OK?
+ STATUS successful-ok
+}
diff --git a/test/get-ppds-drv-only.test b/test/get-ppds-drv-only.test
new file mode 100644
index 000000000..ccb1828d0
--- /dev/null
+++ b/test/get-ppds-drv-only.test
@@ -0,0 +1,24 @@
+# Get drv-based PPD files using CUPS-Get-PPDs
+{
+ # The name of the test...
+ NAME "Get drv-based PPD files using CUPS-Get-PPDs"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION CUPS-Get-PPDs
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name include-schemes drv
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ EXPECT ppd-name
+}
diff --git a/test/get-ppds-language.test b/test/get-ppds-language.test
new file mode 100644
index 000000000..2ed011866
--- /dev/null
+++ b/test/get-ppds-language.test
@@ -0,0 +1,21 @@
+# Get PPD files using CUPS-Get-PPDs and language
+{
+ # The name of the test...
+ NAME "Get PPD files using CUPS-Get-PPDs and language"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION CUPS-Get-PPDs
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR language ppd-natural-language $ENV[language]
+
+ # What statuses are OK?
+ STATUS successful-ok
+}
diff --git a/test/get-ppds-make-and-model.test b/test/get-ppds-make-and-model.test
new file mode 100644
index 000000000..c57b14736
--- /dev/null
+++ b/test/get-ppds-make-and-model.test
@@ -0,0 +1,21 @@
+# Get PPD files using CUPS-Get-PPDs and model
+{
+ # The name of the test...
+ NAME "Get PPD files using CUPS-Get-PPDs and model"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION CUPS-Get-PPDs
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR text ppd-make-and-model $ENV[model]
+
+ # What statuses are OK?
+ STATUS successful-ok
+}
diff --git a/test/get-ppds-make.test b/test/get-ppds-make.test
new file mode 100644
index 000000000..ac3f736e4
--- /dev/null
+++ b/test/get-ppds-make.test
@@ -0,0 +1,21 @@
+# Get PPD files using CUPS-Get-PPDs and make
+{
+ # The name of the test...
+ NAME "Get PPD files using CUPS-Get-PPDs and make"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION CUPS-Get-PPDs
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR text ppd-make $ENV[make]
+
+ # What statuses are OK?
+ STATUS successful-ok
+}
diff --git a/test/get-ppds-product.test b/test/get-ppds-product.test
new file mode 100644
index 000000000..b0535f7e1
--- /dev/null
+++ b/test/get-ppds-product.test
@@ -0,0 +1,21 @@
+# Get PPD files using CUPS-Get-PPDs and Product
+{
+ # The name of the test...
+ NAME "Get PPD files using CUPS-Get-PPDs and Product"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION CUPS-Get-PPDs
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR text ppd-product $ENV[product]
+
+ # What statuses are OK?
+ STATUS successful-ok
+}
diff --git a/test/get-ppds-psversion.test b/test/get-ppds-psversion.test
new file mode 100644
index 000000000..b7f93b670
--- /dev/null
+++ b/test/get-ppds-psversion.test
@@ -0,0 +1,21 @@
+# Get PPD files using CUPS-Get-PPDs and PSVersion
+{
+ # The name of the test...
+ NAME "Get PPD files using CUPS-Get-PPDs and PSVersion"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION CUPS-Get-PPDs
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR text ppd-psversion $ENV[psversion]
+
+ # What statuses are OK?
+ STATUS successful-ok
+}
diff --git a/test/get-ppds.test b/test/get-ppds.test
new file mode 100644
index 000000000..90f59eb6e
--- /dev/null
+++ b/test/get-ppds.test
@@ -0,0 +1,21 @@
+# Get PPD files using CUPS-get-ppds
+{
+ # The name of the test...
+ NAME "Get PPD files using CUPS-get-ppds"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION CUPS-get-ppds
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
diff --git a/test/get-printer-attributes-2.0.test b/test/get-printer-attributes-2.0.test
new file mode 100644
index 000000000..c123c3e10
--- /dev/null
+++ b/test/get-printer-attributes-2.0.test
@@ -0,0 +1,48 @@
+# Get printer attributes using get-printer-attributes
+{
+ # The name of the test...
+ NAME "Get printer attributes using get-printer-attributes"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION get-printer-attributes
+
+ # The version to use
+ VERSION 2.0
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR keyword requested-attributes printer-defaults,printer-description,media-col-database
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT charset-configured
+ EXPECT charset-supported
+ EXPECT compression-supported
+ EXPECT document-format-default
+ EXPECT document-format-supported
+ EXPECT generated-natural-language-supported
+ EXPECT ipp-versions-supported
+ EXPECT media-col-default
+ EXPECT natural-language-configured
+ EXPECT operations-supported
+ EXPECT printer-info
+ EXPECT printer-is-accepting-jobs
+ EXPECT printer-location
+ EXPECT printer-make-and-model
+ EXPECT printer-more-info
+ EXPECT printer-name
+ EXPECT printer-state
+ EXPECT printer-state-reasons
+ EXPECT printer-up-time
+ EXPECT printer-uri-supported
+ EXPECT uri-authentication-supported
+ EXPECT uri-security-supported
+}
diff --git a/test/get-printer-attributes.test b/test/get-printer-attributes.test
new file mode 100644
index 000000000..5940017a0
--- /dev/null
+++ b/test/get-printer-attributes.test
@@ -0,0 +1,38 @@
+# Get printer attributes using get-printer-attributes
+{
+ # The name of the test...
+ NAME "Get printer attributes using Get-Printer-Attributes"
+
+ # The operation to use
+ OPERATION Get-Printer-Attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ # What statuses are OK?
+ STATUS successful-ok
+
+ # What attributes do we expect?
+ EXPECT charset-configured
+ EXPECT charset-supported
+ EXPECT compression-supported
+ EXPECT document-format-default
+ EXPECT document-format-supported
+ EXPECT generated-natural-language-supported
+ EXPECT ipp-versions-supported
+ EXPECT natural-language-configured
+ EXPECT operations-supported
+ EXPECT pdl-override-supported
+ EXPECT printer-is-accepting-jobs
+ EXPECT printer-name
+ EXPECT printer-state
+ EXPECT printer-state-reasons
+ EXPECT printer-up-time
+ EXPECT printer-uri-supported
+ EXPECT queued-job-count
+ EXPECT uri-authentication-supported
+ EXPECT uri-security-supported
+}
diff --git a/test/get-printers.test b/test/get-printers.test
new file mode 100644
index 000000000..54f8df4c8
--- /dev/null
+++ b/test/get-printers.test
@@ -0,0 +1,19 @@
+# Get printer attributes using get-printer-attributes
+{
+ # The name of the test...
+ NAME "CUPS-Get-Printers"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION CUPS-Get-Printers
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+
+ # What statuses are OK?
+ STATUS successful-ok
+}
diff --git a/test/get-subscriptions.test b/test/get-subscriptions.test
new file mode 100644
index 000000000..686059dfa
--- /dev/null
+++ b/test/get-subscriptions.test
@@ -0,0 +1,21 @@
+# Get subscriptions using Get-Subscriptions
+{
+ # The name of the test...
+ NAME "Get subscriptions using Get-Subscriptions"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION Get-Subscriptions
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
diff --git a/test/ipp-1.1.test b/test/ipp-1.1.test
new file mode 100644
index 000000000..cca171f54
--- /dev/null
+++ b/test/ipp-1.1.test
@@ -0,0 +1,748 @@
+#
+# "$Id: ipp-1.1.test 9405 2010-12-08 07:13:22Z mike $"
+#
+# IPP/1.1 test suite.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 2001-2006 by Easy Software Products. All rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# Usage:
+#
+# ./ipptool -f filename -t printer-uri ipp-1.1.test
+#
+
+# Test that a request-id value of 0 is not accepted.
+#
+# Required by: RFC 2911 section 3.1.1
+{
+ NAME "3.1.1: Bad request-id value 0"
+ REQUEST-ID 0
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ STATUS client-error-bad-request
+ EXPECT !printer-uri-supported
+}
+
+
+# Test that the first two attributes must be attributes-charset and
+# attributes-natural-language.
+#
+# Required by: RFC 2911 section 3.1.4
+{
+ NAME "3.1.4: No Operation Attributes"
+ REQUEST-ID random
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+
+ STATUS client-error-bad-request
+ EXPECT !printer-uri-supported
+}
+{
+ NAME "3.1.4: attributes-charset"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR uri printer-uri $uri
+
+ STATUS client-error-bad-request
+ EXPECT !printer-uri-supported
+}
+{
+ NAME "3.1.4: attributes-natural-language"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ STATUS client-error-bad-request
+ EXPECT !printer-uri-supported
+}
+{
+ NAME "3.1.4: attributes-natural-language + attributes-charset"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR charset attributes-charset utf-8
+ ATTR uri printer-uri $uri
+
+ STATUS client-error-bad-request
+ EXPECT !printer-uri-supported
+}
+{
+ NAME "3.1.4: attributes-charset + attributes-natural-language"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ STATUS successful-ok
+ EXPECT printer-uri-supported OF-TYPE uri
+}
+
+
+# Test that bad IPP versions are not supported.
+#
+# Required by: RFC 2911 section 3.1.8
+{
+ # The name of the test...
+ NAME "3.1.8: Unsupported IPP version 0.0"
+ VERSION 0.0
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+
+ STATUS server-error-version-not-supported
+ EXPECT !printer-uri-supported
+}
+
+
+# Test that printer operations require the printer-uri operation attribute.
+#
+# Required by: RFC 2911 section 3.2
+{
+ NAME "3.2: No printer-uri operation attribute"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+
+ STATUS client-error-bad-request
+ EXPECT !printer-uri-supported
+}
+
+
+# Test Print-Job operation
+#
+# Required by: RFC 2911 section 3.2.1
+{
+ NAME "3.2.1: Print-Job Operation"
+ OPERATION Print-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR name job-name $filename
+ ATTR boolean ipp-attribute-fidelity false
+ ATTR name document-name $filename
+ ATTR keyword compression none
+ ATTR mimeMediaType document-format application/octet-stream
+ FILE $filename
+
+ STATUS successful-ok
+ STATUS client-error-document-format-not-supported
+ EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag
+ EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE >0
+ EXPECT job-state OF-TYPE enum COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE 3,4,5,6,7,8,9
+ EXPECT job-state-reasons OF-TYPE keyword IN-GROUP job-attributes-tag
+ EXPECT ?job-state-message OF-TYPE text IN-GROUP job-attributes-tag
+ EXPECT ?number-of-intervening-jobs OF-TYPE integer
+ IN-GROUP job-attributes-tag WITH-VALUE >-1
+}
+
+# Test Get-Printer-Attributes operation
+#
+# Required by: RFC 2911 section 3.2.5
+{
+ NAME "3.2.5: Get-Printer-Attributes Operation (default)"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR mimeMediaType document-format application/octet-stream
+
+ STATUS successful-ok
+
+ # Job template attributes
+ EXPECT ?copies-default OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?copies-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag
+ EXPECT ?finishings-default OF-TYPE enum IN-GROUP printer-attributes-tag
+ EXPECT ?finishings-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 3
+ EXPECT ?job-hold-until-default OF-TYPE keyword|name IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?job-hold-until-supported OF-TYPE keyword|name IN-GROUP printer-attributes-tag WITH-VALUE no-hold
+ EXPECT ?job-priority-default OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0,<101
+ EXPECT ?job-priority-supported OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0,<101
+ EXPECT ?job-sheets-default OF-TYPE keyword|name IN-GROUP printer-attributes-tag
+ EXPECT ?job-sheets-supported OF-TYPE keyword|name IN-GROUP printer-attributes-tag WITH-VALUE none
+ EXPECT ?media-default OF-TYPE keyword|name IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?media-ready OF-TYPE keyword|name IN-GROUP printer-attributes-tag
+ EXPECT ?media-supported OF-TYPE keyword|name IN-GROUP printer-attributes-tag
+ EXPECT ?multiple-document-handling-default OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE "/^(single-document|separate-documents-uncollated-copies|separate-documents-collated-copies|single-document-new-sheet)$$/"
+ EXPECT ?multiple-document-handling-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE "/^(single-document|separate-documents-uncollated-copies|separate-documents-collated-copies|single-document-new-sheet)$$/"
+ EXPECT ?number-up-default OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?number-up-supported OF-TYPE integer|rangeOfInteger IN-GROUP printer-attributes-tag WITH-VALUE >0
+ EXPECT ?number-up-supported WITH-VALUE 1
+ EXPECT ?orientation-requested-default OF-TYPE enum,no-value IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE no-value,3,4,5,6
+ EXPECT ?orientation-requested-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 3,4,5,6
+ EXPECT ?pages-ranges-supported OF-TYPE boolean IN-GROUP printer-attributes-tag
+ EXPECT ?print-quality-default OF-TYPE enum IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE 3,4,5
+ EXPECT ?print-quality-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 3,4,5
+ EXPECT ?printer-resolution-default OF-TYPE resolution IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-resolution-supported OF-TYPE resolution IN-GROUP printer-attributes-tag
+ EXPECT ?sides-default OF-TYPE keyword IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^(one-sided|two-sided-long-edge|two-sided-short-edge)$$/"
+ EXPECT ?sides-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE "/^(one-sided|two-sided-long-edge|two-sided-short-edge)$$/"
+
+ # Printer description attributes
+ EXPECT ?color-supported OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?job-impressions-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?job-k-octets-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?job-media-sheets-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?multiple-document-jobs-supported OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?multiple-operation-time-out OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?pages-per-minute OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?pages-per-minute-color OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-driver-installer OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-info OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-location OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-make-and-model OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-message-from-operator OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT ?printer-more-info OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-more-info-manufacturer OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-state-message OF-TYPE text IN-GROUP printer-attributes-tag
+ EXPECT ?reference-uri-schemes-supported OF-TYPE uriScheme IN-GROUP printer-attributes-tag
+ EXPECT charset-configured OF-TYPE charset IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT charset-supported OF-TYPE charset IN-GROUP printer-attributes-tag WITH-VALUE utf-8
+ EXPECT compression-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE none
+ EXPECT document-format-default OF-TYPE mimeMediaType IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT document-format-supported OF-TYPE mimeMediaType IN-GROUP printer-attributes-tag
+ EXPECT generated-natural-language-supported OF-TYPE naturalLanguage IN-GROUP printer-attributes-tag
+ EXPECT ipp-versions-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE 1.1
+ EXPECT natural-language-configured OF-TYPE naturalLanguage IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT operations-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 0x0002 # Print-Job
+ EXPECT operations-supported WITH-VALUE 0x0004 # Validate-Job
+ EXPECT operations-supported WITH-VALUE 0x0008 # Cancel-Job
+ EXPECT operations-supported WITH-VALUE 0x0009 # Get-Job-Attributes
+ EXPECT operations-supported WITH-VALUE 0x000a # Get-Jobs
+ EXPECT operations-supported WITH-VALUE 0x000b # Get-Printer-Attributes
+ EXPECT pdl-override-supported OF-TYPE keyword IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT printer-is-accepting-jobs OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT printer-name OF-TYPE name IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{1,127}$$/"
+ EXPECT printer-state OF-TYPE enum IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE 3,4,5
+ EXPECT printer-state-reasons OF-TYPE keyword IN-GROUP printer-attributes-tag
+ EXPECT printer-up-time OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT printer-uri-supported OF-TYPE uri IN-GROUP printer-attributes-tag SAME-COUNT-AS uri-security-supported
+ EXPECT queued-job-count OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT uri-authentication-supported OF-TYPE keyword IN-GROUP printer-attributes-tag
+ EXPECT uri-security-supported OF-TYPE keyword IN-GROUP printer-attributes-tag SAME-COUNT-AS uri-authentication-supported
+}
+
+
+# Test Get-Printer-Attributes operation with requested-attributes
+#
+# Required by: RFC 2911 section 3.2.5
+{
+ NAME "3.2.5: Get-Printer-Attributes Operation (requested-attributes)"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR mimeMediaType document-format application/octet-stream
+ ATTR keyword requested-attributes printer-uri-supported
+
+ STATUS successful-ok
+
+ EXPECT printer-uri-supported OF-TYPE uri IN-GROUP printer-attributes-tag
+ EXPECT !printer-name
+}
+
+
+# Test Get-Jobs operation
+#
+# Required by: RFC 2911 section 3.2.6
+{
+ NAME "3.2.6: Get-Jobs Operation (default)"
+ OPERATION Get-Jobs
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ STATUS successful-ok
+ EXPECT job-id OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT job-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT !job-printer-uri
+ EXPECT !job-more-info
+ EXPECT !job-name
+ EXPECT !job-originating-user-name
+ EXPECT !job-state
+ EXPECT !job-state-reasons
+ EXPECT !job-state-message
+ EXPECT !job-detailed-status-messages
+ EXPECT !number-of-documents
+ EXPECT !output-device-assigned
+ EXPECT !time-at-creation
+ EXPECT !time-at-processing
+ EXPECT !time-at-completed
+ EXPECT !job-printer-up-time
+ EXPECT !date-time-at-creation
+ EXPECT !date-time-at-processing
+ EXPECT !date-time-at-completed
+ EXPECT !number-of-intervening-jobs
+ EXPECT !job-message-from-operator
+ EXPECT !job-k-octets
+ EXPECT !job-impressions
+ EXPECT !job-media-sheets
+ EXPECT !job-k-octets-processed
+ EXPECT !job-impressions-completed
+ EXPECT !job-media-sheets-completed
+
+ EXPECT !copies
+ EXPECT !finishings
+ EXPECT !job-hold-until
+ EXPECT !job-priority
+ EXPECT !job-sheets
+ EXPECT !media
+ EXPECT !multiple-document-handling
+ EXPECT !number-up
+ EXPECT !orientation-requested
+ EXPECT !pages-ranges
+ EXPECT !print-quality
+ EXPECT !printer-resolution
+ EXPECT !sides
+}
+
+
+# Test Get-Jobs operation
+#
+# Required by: RFC 2911 section 3.2.6
+{
+ NAME "3.2.6: Get-Jobs Operation (requested-attributes)"
+ OPERATION Get-Jobs
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR keyword requested-attributes all
+
+ STATUS successful-ok
+ EXPECT job-id OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT job-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-printer-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-more-info OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-name OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-originating-user-name OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-state OF-TYPE enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >2,<10
+ EXPECT job-state-reasons OF-TYPE keyword IN-GROUP job-attributes-tag
+ EXPECT ?job-state-message OF-TYPE text IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-detailed-status-messages OF-TYPE text IN-GROUP job-attributes-tag
+ EXPECT ?number-of-documents OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?output-device-assigned OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT time-at-creation OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE no-value,>-1
+ EXPECT time-at-processing OF-TYPE no-value,integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE no-value,>-1
+ EXPECT time-at-completed OF-TYPE no-value,integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE no-value,>-1
+ EXPECT job-printer-up-time OF-TYPE no-value,integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?date-time-at-creation OF-TYPE no-value,dateTime IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?date-time-at-processing OF-TYPE no-value,dateTime IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?date-time-at-completed OF-TYPE no-value,dateTime IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?number-of-intervening-jobs OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-message-from-operator OF-TYPE text IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-k-octets OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-impressions OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-media-sheets OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-k-octets-processed OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-impressions-completed OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-media-sheets-completed OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+
+ EXPECT ?copies OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?finishings OF-TYPE enum IN-GROUP job-attributes-tag
+ EXPECT ?job-hold-until OF-TYPE keyword|name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-priority OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0,<101
+ EXPECT ?job-sheets OF-TYPE keyword|name IN-GROUP job-attributes-tag
+ EXPECT ?media OF-TYPE keyword|name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?multiple-document-handling OF-TYPE keyword IN-GROUP job-attributes-tag WITH-VALUE "/^(single-document|separate-documents-uncollated-copies|separate-documents-collated-copies|single-document-new-sheet)$$/"
+ EXPECT ?number-up OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?orientation-requested OF-TYPE enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE 3,4,5,6
+ EXPECT ?pages-ranges OF-TYPE rangeOfInteger IN-GROUP job-attributes-tag
+ EXPECT ?print-quality OF-TYPE enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE 3,4,5
+ EXPECT ?printer-resolution OF-TYPE resolution IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?sides OF-TYPE keyword IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE "/^(one-sided|two-sided-long-edge|two-sided-short-edge)$$/"
+}
+
+
+# Test Get-Jobs operation
+#
+# Required by: RFC 2911 section 3.2.6
+{
+ NAME "3.2.6: Get-Jobs Operation (my-jobs)"
+ OPERATION Get-Jobs
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR boolean my-jobs true
+
+ STATUS successful-ok
+ EXPECT job-id OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT job-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT !job-printer-uri
+ EXPECT !job-more-info
+ EXPECT !job-name
+ EXPECT !job-originating-user-name
+ EXPECT !job-state
+ EXPECT !job-state-reasons
+ EXPECT !job-state-message
+ EXPECT !job-detailed-status-messages
+ EXPECT !number-of-documents
+ EXPECT !output-device-assigned
+ EXPECT !time-at-creation
+ EXPECT !time-at-processing
+ EXPECT !time-at-completed
+ EXPECT !job-printer-up-time
+ EXPECT !date-time-at-creation
+ EXPECT !date-time-at-processing
+ EXPECT !date-time-at-completed
+ EXPECT !number-of-intervening-jobs
+ EXPECT !job-message-from-operator
+ EXPECT !job-k-octets
+ EXPECT !job-impressions
+ EXPECT !job-media-sheets
+ EXPECT !job-k-octets-processed
+ EXPECT !job-impressions-completed
+ EXPECT !job-media-sheets-completed
+
+ EXPECT !copies
+ EXPECT !finishings
+ EXPECT !job-hold-until
+ EXPECT !job-priority
+ EXPECT !job-sheets
+ EXPECT !media
+ EXPECT !multiple-document-handling
+ EXPECT !number-up
+ EXPECT !orientation-requested
+ EXPECT !pages-ranges
+ EXPECT !print-quality
+ EXPECT !printer-resolution
+ EXPECT !sides
+}
+
+
+# Test Get-Jobs operation
+#
+# Required by: RFC 2911 section 3.2.6
+{
+ # Skip this test when doing authenticated printing since we'll always
+ # use the authenticated username over the requesting-user-name value.
+ SKIP-IF-DEFINED uriuser
+
+ NAME "3.2.6: Get-Jobs Operation (my-jobs different user)"
+ OPERATION Get-Jobs
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name not-$user
+ ATTR boolean my-jobs true
+
+ STATUS successful-ok
+ EXPECT !job-id
+ EXPECT !job-uri
+ EXPECT !job-printer-uri
+ EXPECT !job-more-info
+ EXPECT !job-name
+ EXPECT !job-originating-user-name
+ EXPECT !job-state
+ EXPECT !job-state-reasons
+ EXPECT !job-state-message
+ EXPECT !job-detailed-status-messages
+ EXPECT !number-of-documents
+ EXPECT !output-device-assigned
+ EXPECT !time-at-creation
+ EXPECT !time-at-processing
+ EXPECT !time-at-completed
+ EXPECT !job-printer-up-time
+ EXPECT !date-time-at-creation
+ EXPECT !date-time-at-processing
+ EXPECT !date-time-at-completed
+ EXPECT !number-of-intervening-jobs
+ EXPECT !job-message-from-operator
+ EXPECT !job-k-octets
+ EXPECT !job-impressions
+ EXPECT !job-media-sheets
+ EXPECT !job-k-octets-processed
+ EXPECT !job-impressions-completed
+ EXPECT !job-media-sheets-completed
+
+ EXPECT !copies
+ EXPECT !finishings
+ EXPECT !job-hold-until
+ EXPECT !job-priority
+ EXPECT !job-sheets
+ EXPECT !media
+ EXPECT !multiple-document-handling
+ EXPECT !number-up
+ EXPECT !orientation-requested
+ EXPECT !pages-ranges
+ EXPECT !print-quality
+ EXPECT !printer-resolution
+ EXPECT !sides
+}
+
+
+# Test Get-Jobs operation
+#
+# Required by: RFC 2911 section 3.2.6
+{
+ NAME "3.2.6: Get-Jobs Operation (which-jobs=not-completed)"
+ OPERATION Get-Jobs
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR keyword which-jobs not-completed
+
+ STATUS successful-ok
+ EXPECT job-id OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT job-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT !job-printer-uri
+ EXPECT !job-more-info
+ EXPECT !job-name
+ EXPECT !job-originating-user-name
+ EXPECT !job-state
+ EXPECT !job-state-reasons
+ EXPECT !job-state-message
+ EXPECT !job-detailed-status-messages
+ EXPECT !number-of-documents
+ EXPECT !output-device-assigned
+ EXPECT !time-at-creation
+ EXPECT !time-at-processing
+ EXPECT !time-at-completed
+ EXPECT !job-printer-up-time
+ EXPECT !date-time-at-creation
+ EXPECT !date-time-at-processing
+ EXPECT !date-time-at-completed
+ EXPECT !number-of-intervening-jobs
+ EXPECT !job-message-from-operator
+ EXPECT !job-k-octets
+ EXPECT !job-impressions
+ EXPECT !job-media-sheets
+ EXPECT !job-k-octets-processed
+ EXPECT !job-impressions-completed
+ EXPECT !job-media-sheets-completed
+
+ EXPECT !copies
+ EXPECT !finishings
+ EXPECT !job-hold-until
+ EXPECT !job-priority
+ EXPECT !job-sheets
+ EXPECT !media
+ EXPECT !multiple-document-handling
+ EXPECT !number-up
+ EXPECT !orientation-requested
+ EXPECT !pages-ranges
+ EXPECT !print-quality
+ EXPECT !printer-resolution
+ EXPECT !sides
+}
+
+
+
+# Test Get-Jobs operation
+#
+# Required by: RFC 2911 section 3.2.6
+{
+ NAME "3.2.6: Get-Jobs Operation (which-jobs=completed)"
+ OPERATION Get-Jobs
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR keyword which-jobs completed
+ DELAY 20
+
+ STATUS successful-ok
+ EXPECT job-id OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT job-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT !job-printer-uri
+ EXPECT !job-more-info
+ EXPECT !job-name
+ EXPECT !job-originating-user-name
+ EXPECT !job-state
+ EXPECT !job-state-reasons
+ EXPECT !job-state-message
+ EXPECT !job-detailed-status-messages
+ EXPECT !number-of-documents
+ EXPECT !output-device-assigned
+ EXPECT !time-at-creation
+ EXPECT !time-at-processing
+ EXPECT !time-at-completed
+ EXPECT !job-printer-up-time
+ EXPECT !date-time-at-creation
+ EXPECT !date-time-at-processing
+ EXPECT !date-time-at-completed
+ EXPECT !number-of-intervening-jobs
+ EXPECT !job-message-from-operator
+ EXPECT !job-k-octets
+ EXPECT !job-impressions
+ EXPECT !job-media-sheets
+ EXPECT !job-k-octets-processed
+ EXPECT !job-impressions-completed
+ EXPECT !job-media-sheets-completed
+
+ EXPECT !copies
+ EXPECT !finishings
+ EXPECT !job-hold-until
+ EXPECT !job-priority
+ EXPECT !job-sheets
+ EXPECT !media
+ EXPECT !multiple-document-handling
+ EXPECT !number-up
+ EXPECT !orientation-requested
+ EXPECT !pages-ranges
+ EXPECT !print-quality
+ EXPECT !printer-resolution
+ EXPECT !sides
+}
+
+
+# Test Cancel-Job operation
+#
+# Required by: RFC 2911 section 3.3.3
+{
+ NAME "3.3.3: Cancel-Job Operation (completed job)"
+ OPERATION Cancel-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ STATUS client-error-not-possible
+}
+
+
+# Test Print-Job operation
+#
+# Required by: RFC 2911 section 3.2.1
+{
+ NAME "3.2.1: Print-Job Operation"
+ OPERATION Print-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR name job-name $filename
+ ATTR boolean ipp-attribute-fidelity false
+ ATTR name document-name $filename
+ ATTR keyword compression none
+ ATTR mimeMediaType document-format application/octet-stream
+ FILE $filename
+
+ STATUS successful-ok
+ STATUS client-error-document-format-not-supported
+ EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag
+ EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE >0
+ EXPECT job-state OF-TYPE enum COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE 3,4,5,6,7,8,9
+ EXPECT job-state-reasons OF-TYPE keyword IN-GROUP job-attributes-tag
+ EXPECT ?job-state-message OF-TYPE text IN-GROUP job-attributes-tag
+ EXPECT ?number-of-intervening-jobs OF-TYPE integer
+ IN-GROUP job-attributes-tag WITH-VALUE >-1
+}
+
+
+# Test Cancel-Job operation
+#
+# Required by: RFC 2911 section 3.3.3
+{
+ NAME "3.3.3: Cancel-Job Operation (pending/processing job)"
+ OPERATION Cancel-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ STATUS successful-ok
+ STATUS client-error-not-possible
+}
+
+
+# Test Get-Job-Attributes operation
+#
+# Required by: RFC 2911 section 3.3.4
+{
+ NAME "3.3.4: Get-Job-Attributes Operation"
+ OPERATION Get-Job-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ STATUS successful-ok
+ EXPECT job-id OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT job-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-printer-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-more-info OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-name OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-originating-user-name OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-state OF-TYPE enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >2,<10
+ EXPECT job-state-reasons OF-TYPE keyword IN-GROUP job-attributes-tag
+ EXPECT ?job-state-message OF-TYPE text IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-detailed-status-messages OF-TYPE text IN-GROUP job-attributes-tag
+ EXPECT ?number-of-documents OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?output-device-assigned OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT time-at-creation OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE no-value,>-1
+ EXPECT time-at-processing OF-TYPE no-value,integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE no-value,>-1
+ EXPECT time-at-completed OF-TYPE no-value,integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE no-value,>-1
+ EXPECT job-printer-up-time OF-TYPE no-value,integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?date-time-at-creation OF-TYPE no-value,dateTime IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?date-time-at-processing OF-TYPE no-value,dateTime IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?date-time-at-completed OF-TYPE no-value,dateTime IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?number-of-intervening-jobs OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-message-from-operator OF-TYPE text IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-k-octets OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-impressions OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-media-sheets OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-k-octets-processed OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-impressions-completed OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-media-sheets-completed OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1
+
+ EXPECT ?copies OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?finishings OF-TYPE enum IN-GROUP job-attributes-tag
+ EXPECT ?job-hold-until OF-TYPE keyword|name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?job-priority OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0,<101
+ EXPECT ?job-sheets OF-TYPE keyword|name IN-GROUP job-attributes-tag
+ EXPECT ?media OF-TYPE keyword|name IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?multiple-document-handling OF-TYPE keyword IN-GROUP job-attributes-tag WITH-VALUE "/^(single-document|separate-documents-uncollated-copies|separate-documents-collated-copies|single-document-new-sheet)$$/"
+ EXPECT ?number-up OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT ?orientation-requested OF-TYPE enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE 3,4,5,6
+ EXPECT ?pages-ranges OF-TYPE rangeOfInteger IN-GROUP job-attributes-tag
+ EXPECT ?print-quality OF-TYPE enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE 3,4,5
+ EXPECT ?printer-resolution OF-TYPE resolution IN-GROUP job-attributes-tag COUNT 1
+ EXPECT ?sides OF-TYPE keyword IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE "/^(one-sided|two-sided-long-edge|two-sided-short-edge)$$/"
+}
+
+
+#
+# End of "$Id: ipp-1.1.test 9405 2010-12-08 07:13:22Z mike $".
+#
diff --git a/test/ipp-2.0.test b/test/ipp-2.0.test
new file mode 100644
index 000000000..9b4e6875f
--- /dev/null
+++ b/test/ipp-2.0.test
@@ -0,0 +1,80 @@
+#
+# "$Id: ipp-2.0.test 9238 2010-08-11 21:21:46Z mike $"
+#
+# IPP/2.0 test suite.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 2001-2006 by Easy Software Products. All rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# Usage:
+#
+# ./ipptool -V 2.0 -f filename -t printer-uri ipp-2.0.test
+#
+
+# Do all of the IPP/1.1 tests as an IPP/2.0 client
+#
+# Required by: PWG 5100.10 section 4.3
+INCLUDE "ipp-1.1.test"
+
+
+# Regular expression for PWG media size names (eek!)
+DEFINE MEDIA_REGEX "/^((custom|na|asme|roc|oe)_[a-z0-9][-a-z0-9]*_([1-9][0-9]*(\.[0-9]*[1-9])?|0\.[0-9]*[1-9])x([1-9][0-9]*(\.[0-9]*[1-9])?|0\.[0-9]*[1-9])in|(custom|iso|jis|jpn|prc|om)_[a-z0-9][-a-z0-9]*_([1-9][0-9]*(\.[0-9]*[1-9])?|0\.[0-9]*[1-9])x([1-9][0-9]*(\.[0-9]*[1-9])?|0\.[0-9]*[1-9])mm)$$/"
+
+
+# Test required printer description attribute support.
+#
+# Required by: PWG 5100.10 section 6.2
+{
+ NAME "PWG 5100.10 section 6.2 - Required Printer Description Attributes"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR mimeMediaType document-format application/octet-stream
+
+ STATUS successful-ok
+
+ # Figure out capabilities
+ EXPECT color-supported OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE true DEFINE-MATCH PRINTER_IS_COLOR
+
+ # Job template attributes
+ EXPECT copies-default OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+ EXPECT copies-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag
+ EXPECT finishings-default OF-TYPE enum IN-GROUP printer-attributes-tag
+ EXPECT finishings-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 3
+ EXPECT media-default OF-TYPE keyword|name IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "$MEDIA_REGEX"
+ EXPECT media-supported OF-TYPE keyword|name IN-GROUP printer-attributes-tag WITH-VALUE "$MEDIA_REGEX"
+ EXPECT orientation-requested-default OF-TYPE enum,no-value IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE no-value,3,4,5,6
+ EXPECT orientation-requested-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 3,4,5,6
+ EXPECT output-bin-default OF-TYPE keyword|name IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT output-bin-supported OF-TYPE keyword|name IN-GROUP printer-attributes-tag
+ EXPECT print-quality-default OF-TYPE enum IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE 3,4,5
+ EXPECT print-quality-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 3,4,5
+ EXPECT printer-resolution-default OF-TYPE resolution IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT printer-resolution-supported OF-TYPE resolution IN-GROUP printer-attributes-tag
+ EXPECT sides-default OF-TYPE keyword IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^(one-sided|two-sided-long-edge|two-sided-short-edge)$$/"
+ EXPECT sides-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE "/^(one-sided|two-sided-long-edge|two-sided-short-edge)$$/"
+
+ # Printer description attributes
+ EXPECT color-supported OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT pages-per-minute OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT pages-per-minute-color OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 IF-DEFINED PRINTER_IS_COLOR
+ EXPECT !pages-per-minute-color IF-NOT-DEFINED PRINTER_IS_COLOR
+ EXPECT printer-info OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT printer-location OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT printer-make-and-model OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
+ EXPECT printer-more-info OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
+}
+
+
+#
+# End of "$Id: ipp-2.0.test 9238 2010-08-11 21:21:46Z mike $".
+#
diff --git a/test/ipp-2.1.test b/test/ipp-2.1.test
new file mode 100644
index 000000000..7cb8c49fd
--- /dev/null
+++ b/test/ipp-2.1.test
@@ -0,0 +1,95 @@
+#
+# "$Id: ipp-2.1.test 9230 2010-08-10 00:02:02Z mike $"
+#
+# IPP/2.1 test suite.
+#
+# Copyright 2007-2010 by Apple Inc.
+# Copyright 2001-2006 by Easy Software Products. All rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+# Usage:
+#
+# ./ipptool -V 2.1 {-d PRINTER_IS_COLOR=1} -f filename -t printer-uri ipp-2.1.test
+#
+
+# Do all of the IPP/1.1 and IPP/2.0 tests as an IPP/2.1 client
+INCLUDE "ipp-2.0.test"
+
+
+# Test required printer description attribute support.
+#
+# Required by: PWG 5100.10 section 6.3
+{
+ NAME "PWG 5100.10 section 6.3 - Required Printer Description Attributes"
+ OPERATION Get-Printer-Attributes
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR mimeMediaType document-format application/octet-stream
+
+ STATUS successful-ok
+
+ # Job template attributes
+ EXPECT job-hold-until-default OF-TYPE keyword|name IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT job-hold-until-supported OF-TYPE keyword|name IN-GROUP printer-attributes-tag WITH-VALUE no-hold
+ EXPECT job-priority-default OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0,<101
+ EXPECT job-priority-supported OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0,<101
+ EXPECT job-settable-attributes-supported OF-TYPE keyword IN-GROUP printer-attributes-tag
+ EXPECT job-sheets-default OF-TYPE keyword|name IN-GROUP printer-attributes-tag
+ EXPECT job-sheets-supported OF-TYPE keyword|name IN-GROUP printer-attributes-tag WITH-VALUE none
+ EXPECT media-col-default OF-TYPE collection IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT media-col-supported OF-TYPE keyword IN-GROUP printer-attributes-tag
+ EXPECT media-col-supported WITH-VALUE media-size
+ EXPECT media-default OF-TYPE keyword|name IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT media-supported OF-TYPE keyword|name IN-GROUP printer-attributes-tag
+
+ # Subscription attributes
+ EXPECT notify-events-default OF-TYPE keyword IN-GROUP printer-attributes-tag
+ EXPECT notify-events-supported OF-TYPE keyword IN-GROUP printer-attributes-tag
+ EXPECT notify-lease-duration-default OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT notify-lease-duration-supported OF-TYPE integer|rangeOfInteger IN-GROUP printer-attributes-tag
+ EXPECT notify-max-events-supported OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >1
+ EXPECT notify-pull-method-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE ippget
+
+ # Printer description attributes
+ EXPECT ippget-event-life OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT multiple-operation-time-out OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
+
+ EXPECT operations-supported WITH-VALUE 0x0005 # Create-Job
+ EXPECT operations-supported WITH-VALUE 0x0006 # Send-Document
+ EXPECT operations-supported WITH-VALUE 0x000C # Hold-Job
+ EXPECT operations-supported WITH-VALUE 0x000D # Release-Job
+ EXPECT operations-supported WITH-VALUE 0x000E # Restart-Job
+ EXPECT operations-supported WITH-VALUE 0x0010 # Pause-Printer
+ EXPECT operations-supported WITH-VALUE 0x0011 # Resume-Printer
+ EXPECT operations-supported WITH-VALUE 0x0012 # Purge-Jobs
+ EXPECT operations-supported WITH-VALUE 0x0013 # Set-Printer-Attributes
+ EXPECT operations-supported WITH-VALUE 0x0014 # Set-Job-Attributes
+ EXPECT operations-supported WITH-VALUE 0x0015 # Get-Printer-Supported-Values
+ EXPECT operations-supported WITH-VALUE 0x0016 # Create-Printer-Subscriptions
+ EXPECT operations-supported WITH-VALUE 0x0018 # Get-Subscription-Attributes
+ EXPECT operations-supported WITH-VALUE 0x0019 # Get-Subscriptions
+ EXPECT operations-supported WITH-VALUE 0x001A # Renew-Subscription
+ EXPECT operations-supported WITH-VALUE 0x001B # Cancel-Subscription
+ EXPECT operations-supported WITH-VALUE 0x001C # Get-Notifications
+ EXPECT operations-supported WITH-VALUE 0x0022 # Enable-Printer
+ EXPECT operations-supported WITH-VALUE 0x0023 # Disable-Printer
+
+ EXPECT ?printer-alert OF-TYPE octetString IN-GROUP printer-attributes-tag
+ EXPECT ?printer-alert-description OF-TYPE text IN-GROUP printer-attributes-tag SAME-COUNT-AS printer-alert
+ EXPECT printer-settable-attributes-supported OF-TYPE keyword IN-GROUP printer-attributes-tag
+ EXPECT printer-state-change-time OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT printer-state-reasons OF-TYPE keyword IN-GROUP printer-attributes-tag
+}
+
+
+#
+# End of "$Id: ipp-2.1.test 9230 2010-08-10 00:02:02Z mike $".
+#
diff --git a/test/ipp-backend.test b/test/ipp-backend.test
new file mode 100644
index 000000000..c2642d375
--- /dev/null
+++ b/test/ipp-backend.test
@@ -0,0 +1,22 @@
+# Get printer attributes using get-printer-attributes
+{
+ # The name of the test...
+ NAME "Get printer attributes using get-printer-attributes"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION get-printer-attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR keyword requested-attributes com.apple.print.recoverable-message,copies-supported,document-format-supported,marker-colors,marker-levels,marker-message,marker-names,marker-types,printer-is-accepting-jobs,printer-state,printer-state-message,printer-state-reasons
+
+ # What statuses are OK?
+ STATUS successful-ok
+ STATUS successful-ok-ignored-or-substituted-attributes
+}
diff --git a/test/ippserver.c b/test/ippserver.c
new file mode 100644
index 000000000..0a8495962
--- /dev/null
+++ b/test/ippserver.c
@@ -0,0 +1,4380 @@
+/*
+ * "$Id$"
+ *
+ * Sample IPP/2.0 server for CUPS.
+ *
+ * Copyright 2010-2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry to the sample server.
+ * clean_jobs() - Clean out old (completed) jobs.
+ * compare_jobs() - Compare two jobs.
+ * copy_attribute() - Copy a single attribute.
+ * copy_attributes() - Copy attributes from one request to another.
+ * copy_job_attrs() - Copy job attributes to the response.
+ * create_client() - Accept a new network connection and create a
+ * client object.
+ * create_job() - Create a new job object from a Print-Job or
+ * Create-Job request.
+ * create_listener() - Create a listener socket.
+ * create_media_col() - Create a media-col value.
+ * create_printer() - Create, register, and listen for connections
+ * to a printer object.
+ * create_requested_array() - Create an array for requested-attributes.
+ * debug_attributes() - Print attributes in a request or response.
+ * delete_client() - Close the socket and free all memory used by
+ * a client object.
+ * delete_job() - Remove from the printer and free all memory
+ * used by a job object.
+ * delete_printer() - Unregister, close listen sockets, and free
+ * all memory used by a printer object.
+ * dnssd_callback() - Handle Bonjour registration events.
+ * find_job() - Find a job specified in a request.
+ * html_escape() - Write a HTML-safe string.
+ * html_printf() - Send formatted text to the client, quoting
+ * as needed.
+ * ipp_cancel_job() - Cancel a job.
+ * ipp_create_job() - Create a job object.
+ * ipp_get_job_attributes() - Get the attributes for a job object.
+ * ipp_get_jobs() - Get a list of job objects.
+ * ipp_get_printer_attributes() - Get the attributes for a printer object.
+ * ipp_print_job() - Create a job object with an attached
+ * document.
+ * ipp_send_document() - Add an attached document to a job object
+ * created with Create-Job.
+ * ipp_validate_job() - Validate job creation attributes.
+ * process_client() - Process client requests on a thread.
+ * process_http() - Process a HTTP request.
+ * process_ipp() - Process an IPP request.
+ * process_job() - Process a print job.
+ * register_printer() - Register a printer object via Bonjour.
+ * respond_http() - Send a HTTP response.
+ * respond_ipp() - Send an IPP response.
+ * run_printer() - Run the printer service.
+ * usage() - Show program usage.
+ * valid_job_attributes() - Determine whether the job attributes are
+ * valid.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#ifdef HAVE_DNSSD
+# include <dns_sd.h>
+#endif /* HAVE_DNSSD */
+#include <sys/stat.h>
+#include <poll.h>
+#ifdef HAVE_SYS_MOUNT_H
+# include <sys/mount.h>
+#endif /* HAVE_SYS_MOUNT_H */
+#ifdef HAVE_SYS_STATFS_H
+# include <sys/statfs.h>
+#endif /* HAVE_SYS_STATFS_H */
+#ifdef HAVE_SYS_STATVFS_H
+# include <sys/statvfs.h>
+#endif /* HAVE_SYS_STATVFS_H */
+#ifdef HAVE_SYS_VFS_H
+# include <sys/vfs.h>
+#endif /* HAVE_SYS_VFS_H */
+
+
+/*
+ * Constants...
+ */
+
+enum _ipp_preasons_e /* printer-state-reasons bit values */
+{
+ _IPP_PRINTER_NONE = 0x0000, /* none */
+ _IPP_PRINTER_OTHER = 0x0001, /* other */
+ _IPP_PRINTER_COVER_OPEN = 0x0002, /* cover-open */
+ _IPP_PRINTER_INPUT_TRAY_MISSING = 0x0004,
+ /* input-tray-missing */
+ _IPP_PRINTER_MARKER_SUPPLY_EMPTY = 0x0008,
+ /* marker-supply-empty */
+ _IPP_PRINTER_MARKER_SUPPLY_LOW = 0x0010,
+ /* marker-suply-low */
+ _IPP_PRINTER_MARKER_WASTE_ALMOST_FULL = 0x0020,
+ /* marker-waste-almost-full */
+ _IPP_PRINTER_MARKER_WASTE_FULL = 0x0040,
+ /* marker-waste-full */
+ _IPP_PRINTER_MEDIA_EMPTY = 0x0080, /* media-empty */
+ _IPP_PRINTER_MEDIA_JAM = 0x0100, /* media-jam */
+ _IPP_PRINTER_MEDIA_LOW = 0x0200, /* media-low */
+ _IPP_PRINTER_MEDIA_NEEDED = 0x0400, /* media-needed */
+ _IPP_PRINTER_MOVING_TO_PAUSED = 0x0800,
+ /* moving-to-paused */
+ _IPP_PRINTER_PAUSED = 0x1000, /* paused */
+ _IPP_PRINTER_SPOOL_AREA_FULL = 0x2000,/* spool-area-full */
+ _IPP_PRINTER_TONER_EMPTY = 0x4000, /* toner-empty */
+ _IPP_PRINTER_TONER_LOW = 0x8000 /* toner-low */
+};
+typedef unsigned int _ipp_preasons_t; /* Bitfield for printer-state-reasons */
+
+typedef enum _ipp_media_class_e
+{
+ _IPP_GENERAL, /* General-purpose size */
+ _IPP_PHOTO_ONLY, /* Photo-only size */
+ _IPP_ENV_ONLY /* Envelope-only size */
+} _ipp_media_class_t;
+
+static const char * const media_supported[] =
+{ /* media-supported values */
+ "iso_a4_210x297mm", /* A4 */
+ "iso_a5_148x210mm", /* A5 */
+ "iso_a6_105x148mm", /* A6 */
+ "iso_dl_110x220mm", /* DL */
+ "na_legal_8.5x14in", /* Legal */
+ "na_letter_8.5x11in", /* Letter */
+ "na_number-10_4.125x9.5in", /* #10 */
+ "na_index-3x5_3x5in", /* 3x5 */
+ "oe_photo-l_3.5x5in", /* L */
+ "na_index-4x6_4x6in", /* 4x6 */
+ "na_5x7_5x7in" /* 5x7 */
+};
+static const int media_col_sizes[][3] =
+{ /* media-col-database sizes */
+ { 21000, 29700, _IPP_GENERAL }, /* A4 */
+ { 14800, 21000, _IPP_PHOTO_ONLY }, /* A5 */
+ { 10500, 14800, _IPP_PHOTO_ONLY }, /* A6 */
+ { 11000, 22000, _IPP_ENV_ONLY }, /* DL */
+ { 21590, 35560, _IPP_GENERAL }, /* Legal */
+ { 21590, 27940, _IPP_GENERAL }, /* Letter */
+ { 10477, 24130, _IPP_ENV_ONLY }, /* #10 */
+ { 7630, 12700, _IPP_PHOTO_ONLY }, /* 3x5 */
+ { 8890, 12700, _IPP_PHOTO_ONLY }, /* L */
+ { 10160, 15240, _IPP_PHOTO_ONLY }, /* 4x6 */
+ { 12700, 17780, _IPP_PHOTO_ONLY } /* 5x7 */
+};
+static const char * const media_type_supported[] =
+ /* media-type-supported values */
+{
+ "auto",
+ "cardstock",
+ "envelope",
+ "labels",
+ "other",
+ "photographic-glossy",
+ "photographic-high-gloss",
+ "photographic-matte",
+ "photographic-satin",
+ "photographic-semi-gloss",
+ "stationery",
+ "stationery-letterhead",
+ "transparency"
+};
+
+
+/*
+ * Structures...
+ */
+
+typedef struct _ipp_job_s _ipp_job_t;
+
+typedef struct _ipp_printer_s /**** Printer data ****/
+{
+ int ipv4, /* IPv4 listener */
+ ipv6; /* IPv6 listener */
+#ifdef HAVE_DNSSD
+ DNSServiceRef common_ref, /* Shared service connection */
+ ipp_ref, /* Bonjour IPP service */
+ http_ref, /* Bonjour HTTP service */
+ printer_ref; /* Bonjour LPD service */
+ TXTRecordRef ipp_txt; /* Bonjour IPP TXT record */
+ char *dnssd_name; /* printer-dnssd-name */
+#endif /* HAVE_DNSSD */
+ char *name, /* printer-name */
+ *icon, /* Icon filename */
+ *directory, /* Spool directory */
+ *hostname, /* Hostname */
+ *uri; /* printer-uri-supported */
+ int port; /* Port */
+ size_t urilen; /* Length of printer URI */
+ ipp_t *attrs; /* Static attributes */
+ ipp_pstate_t state; /* printer-state value */
+ _ipp_preasons_t state_reasons; /* printer-state-reasons values */
+ cups_array_t *jobs; /* Jobs */
+ _ipp_job_t *active_job; /* Current active/pending job */
+ int next_job_id; /* Next job-id value */
+ _cups_rwlock_t rwlock; /* Printer lock */
+} _ipp_printer_t;
+
+struct _ipp_job_s /**** Job data ****/
+{
+ int id; /* Job ID */
+ char *name, /* job-name */
+ *username, /* job-originating-user-name */
+ *format; /* document-format */
+ ipp_jstate_t state; /* job-state value */
+ time_t processing, /* time-at-processing value */
+ completed; /* time-at-completed value */
+ ipp_t *attrs; /* Static attributes */
+ int cancel; /* Non-zero when job canceled */
+ char *filename; /* Print file name */
+ int fd; /* Print file descriptor */
+ _ipp_printer_t *printer; /* Printer */
+};
+
+typedef struct _ipp_client_s /**** Client data ****/
+{
+ http_t http; /* HTTP connection */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ time_t start; /* Request start time */
+ http_state_t operation; /* Request operation */
+ ipp_op_t operation_id; /* IPP operation-id */
+ char uri[1024]; /* Request URI */
+ http_addr_t addr; /* Client address */
+ _ipp_printer_t *printer; /* Printer */
+ _ipp_job_t *job; /* Current job, if any */
+} _ipp_client_t;
+
+
+/*
+ * Local functions...
+ */
+
+static void clean_jobs(_ipp_printer_t *printer);
+static int compare_jobs(_ipp_job_t *a, _ipp_job_t *b);
+static ipp_attribute_t *copy_attribute(ipp_t *to, ipp_attribute_t *attr,
+ ipp_tag_t group_tag, int quickcopy);
+static void copy_attributes(ipp_t *to, ipp_t *from, cups_array_t *ra,
+ ipp_tag_t group_tag, int quickcopy);
+static void copy_job_attributes(_ipp_client_t *client,
+ _ipp_job_t *job, cups_array_t *ra);
+static _ipp_client_t *create_client(_ipp_printer_t *printer, int sock);
+static _ipp_job_t *create_job(_ipp_client_t *client);
+static int create_listener(int family, int *port);
+static ipp_t *create_media_col(const char *media, const char *type,
+ int width, int length, int margins);
+static _ipp_printer_t *create_printer(const char *servername,
+ const char *name, const char *location,
+ const char *make, const char *model,
+ const char *icon,
+ const char *docformats, int ppm,
+ int ppm_color, int duplex, int port,
+#ifdef HAVE_DNSSD
+ const char *regtype,
+#endif /* HAVE_DNSSD */
+ const char *directory);
+static cups_array_t *create_requested_array(_ipp_client_t *client);
+static void debug_attributes(const char *title, ipp_t *ipp);
+static void delete_client(_ipp_client_t *client);
+static void delete_job(_ipp_job_t *job);
+static void delete_printer(_ipp_printer_t *printer);
+#ifdef HAVE_DNSSD
+static void dnssd_callback(DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ DNSServiceErrorType errorCode,
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ _ipp_printer_t *printer);
+#endif /* HAVE_DNSSD */
+static _ipp_job_t *find_job(_ipp_client_t *client);
+static void html_escape(_ipp_client_t *client, const char *s,
+ size_t slen);
+static void html_printf(_ipp_client_t *client, const char *format,
+ ...)
+# ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+# endif /* __GNUC__ */
+;
+static void ipp_cancel_job(_ipp_client_t *client);
+#if 0
+static void ipp_create_job(_ipp_client_t *client);
+#endif /* 0 */
+static void ipp_get_job_attributes(_ipp_client_t *client);
+static void ipp_get_jobs(_ipp_client_t *client);
+static void ipp_get_printer_attributes(_ipp_client_t *client);
+static void ipp_print_job(_ipp_client_t *client);
+#if 0
+static void ipp_send_document(_ipp_client_t *client);
+#endif /* 0 */
+static void ipp_validate_job(_ipp_client_t *client);
+static void *process_client(_ipp_client_t *client);
+static int process_http(_ipp_client_t *client);
+static int process_ipp(_ipp_client_t *client);
+static void *process_job(_ipp_job_t *job);
+#ifdef HAVE_DNSSD
+static int register_printer(_ipp_printer_t *printer,
+ const char *location, const char *make,
+ const char *model, const char *formats,
+ const char *adminurl, int color,
+ int duplex, const char *regtype);
+#endif /* HAVE_DNSSD */
+static int respond_http(_ipp_client_t *client, http_status_t code,
+ const char *type, size_t length);
+static void respond_ipp(_ipp_client_t *client, ipp_status_t status,
+ const char *message, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 3, 4)))
+#endif /* __GNUC__ */
+;
+static void run_printer(_ipp_printer_t *printer);
+static void usage(int status);
+static int valid_job_attributes(_ipp_client_t *client);
+
+
+/*
+ * Globals...
+ */
+
+static int KeepFiles = 0,
+ Verbosity = 0;
+
+
+/*
+ * 'main()' - Main entry to the sample server.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ const char *opt, /* Current option character */
+ *servername = NULL, /* Server host name */
+ *name = NULL, /* Printer name */
+ *location = "", /* Location of printer */
+ *make = "Test", /* Manufacturer */
+ *model = "Printer", /* Model */
+ *icon = "printer.png", /* Icon file */
+ *formats = "application/pdf,image/jpeg";
+ /* Supported formats */
+#ifdef HAVE_DNSSD
+ const char *regtype = "_ipp._tcp"; /* Bonjour service type */
+#endif /* HAVE_DNSSD */
+ int port = 8631, /* Port number (0 = auto) TODO: FIX */
+ duplex = 0, /* Duplex mode */
+ ppm = 10, /* Pages per minute for mono */
+ ppm_color = 0; /* Pages per minute for color */
+ char directory[1024] = ""; /* Spool directory */
+ _ipp_printer_t *printer; /* Printer object */
+
+
+ /*
+ * Parse command-line arguments...
+ */
+
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-')
+ {
+ for (opt = argv[i] + 1; *opt; opt ++)
+ switch (*opt)
+ {
+ case '2' : /* -2 (enable 2-sided printing) */
+ duplex = 1;
+ break;
+
+ case 'M' : /* -M manufacturer */
+ i ++;
+ if (i >= argc)
+ usage(1);
+ make = argv[i];
+ break;
+
+ case 'd' : /* -d spool-directory */
+ i ++;
+ if (i >= argc)
+ usage(1);
+ strlcpy(directory, argv[i], sizeof(directory));
+ break;
+
+ case 'f' : /* -f type/subtype[,...] */
+ i ++;
+ if (i >= argc)
+ usage(1);
+ formats = argv[i];
+ break;
+
+ case 'h' : /* -h (show help) */
+ usage(0);
+ break;
+
+ case 'i' : /* -i icon.png */
+ i ++;
+ if (i >= argc)
+ usage(1);
+ icon = argv[i];
+ break;
+
+ case 'k' : /* -k (keep files) */
+ KeepFiles = 1;
+ break;
+
+ case 'l' : /* -l location */
+ i ++;
+ if (i >= argc)
+ usage(1);
+ location = argv[i];
+ break;
+
+ case 'm' : /* -m model */
+ i ++;
+ if (i >= argc)
+ usage(1);
+ model = argv[i];
+ break;
+
+ case 'n' : /* -n hostname */
+ i ++;
+ if (i >= argc)
+ usage(1);
+ servername = argv[i];
+ break;
+
+ case 'p' : /* -p port */
+ i ++;
+ if (i >= argc || !isdigit(argv[i][0] & 255))
+ usage(1);
+ port = atoi(argv[i]);
+ break;
+
+#ifdef HAVE_DNSSD
+ case 'r' : /* -r regtype */
+ i ++;
+ if (i >= argc)
+ usage(1);
+ regtype = argv[i];
+ break;
+#endif /* HAVE_DNSSD */
+
+ case 's' : /* -s speed[,color-speed] */
+ i ++;
+ if (i >= argc)
+ usage(1);
+ if (sscanf(argv[i], "%d,%d", &ppm, &ppm_color) < 1)
+ usage(1);
+ break;
+
+ case 'v' : /* -v (be verbose) */
+ Verbosity ++;
+ break;
+
+ default : /* Unknown */
+ fprintf(stderr, "Unknown option \"-%c\".\n", *opt);
+ usage(1);
+ break;
+ }
+ }
+ else if (!name)
+ {
+ name = argv[i];
+ }
+ else
+ {
+ fprintf(stderr, "Unexpected command-line argument \"%s\"\n", argv[i]);
+ usage(1);
+ }
+
+ if (!name)
+ usage(1);
+
+ /*
+ * Apply defaults as needed...
+ */
+
+ if (!directory[0])
+ {
+ snprintf(directory, sizeof(directory), "/tmp/ippserver.%d", (int)getpid());
+
+ if (mkdir(directory, 0777) && errno != EEXIST)
+ {
+ fprintf(stderr, "Unable to create spool directory \"%s\": %s\n",
+ directory, strerror(errno));
+ usage(1);
+ }
+
+ if (Verbosity)
+ fprintf(stderr, "Using spool directory \"%s\".\n", directory);
+ }
+
+ /*
+ * Create the printer...
+ */
+
+ if ((printer = create_printer(servername, name, location, make, model, icon,
+ formats, ppm, ppm_color, duplex, port,
+#ifdef HAVE_DNSSD
+ regtype,
+#endif /* HAVE_DNSSD */
+ directory)) == NULL)
+ return (1);
+
+ /*
+ * Run the print service...
+ */
+
+ run_printer(printer);
+
+ /*
+ * Destroy the printer and exit...
+ */
+
+ delete_printer(printer);
+
+ return (0);
+}
+
+
+/*
+ * 'clean_jobs()' - Clean out old (completed) jobs.
+ */
+
+static void
+clean_jobs(_ipp_printer_t *printer) /* I - Printer */
+{
+ _ipp_job_t *job; /* Current job */
+ time_t cleantime; /* Clean time */
+
+
+ if (cupsArrayCount(printer->jobs) == 0)
+ return;
+
+ cleantime = time(NULL) - 60;
+
+ _cupsRWLockWrite(&(printer->rwlock));
+ for (job = (_ipp_job_t *)cupsArrayFirst(printer->jobs);
+ job;
+ job = (_ipp_job_t *)cupsArrayNext(printer->jobs))
+ if (job->completed && job->completed < cleantime)
+ {
+ cupsArrayRemove(printer->jobs, job);
+ delete_job(job);
+ }
+ else
+ break;
+ _cupsRWUnlock(&(printer->rwlock));
+}
+
+
+/*
+ * 'compare_jobs()' - Compare two jobs.
+ */
+
+static int /* O - Result of comparison */
+compare_jobs(_ipp_job_t *a, /* I - First job */
+ _ipp_job_t *b) /* I - Second job */
+{
+ return (b->id - a->id);
+}
+
+
+/*
+ * 'copy_attribute()' - Copy a single attribute.
+ */
+
+static ipp_attribute_t * /* O - New attribute */
+copy_attribute(
+ ipp_t *to, /* O - Destination request/response */
+ ipp_attribute_t *attr, /* I - Attribute to copy */
+ ipp_tag_t group_tag, /* I - Group to put the copy in */
+ int quickcopy) /* I - Do a quick copy? */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *toattr; /* Destination attribute */
+
+
+ if (Verbosity && attr->name)
+ {
+ char buffer[2048]; /* Attribute value */
+
+ _ippAttrString(attr, buffer, sizeof(buffer));
+
+ fprintf(stderr, "Copying %s (%s%s) %s\n", attr->name,
+ attr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attr->value_tag & ~IPP_TAG_COPY), buffer);
+ }
+
+ switch (attr->value_tag & ~IPP_TAG_COPY)
+ {
+ case IPP_TAG_ZERO :
+ toattr = ippAddSeparator(to);
+ break;
+
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ toattr = ippAddIntegers(to, group_tag, attr->value_tag,
+ attr->name, attr->num_values, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].integer = attr->values[i].integer;
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ toattr = ippAddBooleans(to, group_tag, attr->name,
+ attr->num_values, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].boolean = attr->values[i].boolean;
+ break;
+
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ toattr = ippAddStrings(to, group_tag,
+ (ipp_tag_t)(attr->value_tag | quickcopy),
+ attr->name, attr->num_values, NULL, NULL);
+
+ if (quickcopy)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].string.text = attr->values[i].string.text;
+ }
+ else
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].string.text =
+ _cupsStrAlloc(attr->values[i].string.text);
+ }
+ break;
+
+ case IPP_TAG_DATE :
+ toattr = ippAddDate(to, group_tag, attr->name,
+ attr->values[0].date);
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ toattr = ippAddResolutions(to, group_tag, attr->name,
+ attr->num_values, IPP_RES_PER_INCH,
+ NULL, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].resolution.xres = attr->values[i].resolution.xres;
+ toattr->values[i].resolution.yres = attr->values[i].resolution.yres;
+ toattr->values[i].resolution.units = attr->values[i].resolution.units;
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ toattr = ippAddRanges(to, group_tag, attr->name,
+ attr->num_values, NULL, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].range.lower = attr->values[i].range.lower;
+ toattr->values[i].range.upper = attr->values[i].range.upper;
+ }
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ toattr = ippAddStrings(to, group_tag,
+ (ipp_tag_t)(attr->value_tag | quickcopy),
+ attr->name, attr->num_values, NULL, NULL);
+
+ if (quickcopy)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].string.charset = attr->values[i].string.charset;
+ toattr->values[i].string.text = attr->values[i].string.text;
+ }
+ }
+ else
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (!i)
+ toattr->values[i].string.charset =
+ _cupsStrAlloc(attr->values[i].string.charset);
+ else
+ toattr->values[i].string.charset =
+ toattr->values[0].string.charset;
+
+ toattr->values[i].string.text =
+ _cupsStrAlloc(attr->values[i].string.text);
+ }
+ }
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ toattr = ippAddCollections(to, group_tag, attr->name,
+ attr->num_values, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].collection = attr->values[i].collection;
+ attr->values[i].collection->use ++;
+ }
+ break;
+
+ case IPP_TAG_STRING :
+ if (quickcopy)
+ {
+ toattr = ippAddOctetString(to, group_tag, attr->name, NULL, 0);
+ toattr->value_tag |= quickcopy;
+ toattr->values[0].unknown.data = attr->values[0].unknown.data;
+ toattr->values[0].unknown.length = attr->values[0].unknown.length;
+ }
+ else
+ toattr = ippAddOctetString(to, attr->group_tag, attr->name,
+ attr->values[0].unknown.data,
+ attr->values[0].unknown.length);
+ break;
+
+ default :
+ toattr = ippAddIntegers(to, group_tag, attr->value_tag,
+ attr->name, attr->num_values, NULL);
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].unknown.length = attr->values[i].unknown.length;
+
+ if (toattr->values[i].unknown.length > 0)
+ {
+ if ((toattr->values[i].unknown.data =
+ malloc(toattr->values[i].unknown.length)) == NULL)
+ toattr->values[i].unknown.length = 0;
+ else
+ memcpy(toattr->values[i].unknown.data,
+ attr->values[i].unknown.data,
+ toattr->values[i].unknown.length);
+ }
+ }
+ break; /* anti-compiler-warning-code */
+ }
+
+ return (toattr);
+}
+
+
+/*
+ * 'copy_attributes()' - Copy attributes from one request to another.
+ */
+
+static void
+copy_attributes(ipp_t *to, /* I - Destination request */
+ ipp_t *from, /* I - Source request */
+ cups_array_t *ra, /* I - Requested attributes */
+ ipp_tag_t group_tag, /* I - Group to copy */
+ int quickcopy) /* I - Do a quick copy? */
+{
+ ipp_attribute_t *fromattr; /* Source attribute */
+
+
+ if (!to || !from)
+ return;
+
+ for (fromattr = from->attrs; fromattr; fromattr = fromattr->next)
+ {
+ /*
+ * Filter attributes as needed...
+ */
+
+ if ((group_tag != IPP_TAG_ZERO && fromattr->group_tag != group_tag &&
+ fromattr->group_tag != IPP_TAG_ZERO) || !fromattr->name)
+ continue;
+
+ if (!ra || cupsArrayFind(ra, fromattr->name))
+ copy_attribute(to, fromattr, fromattr->group_tag, quickcopy);
+ }
+}
+
+
+/*
+ * 'copy_job_attrs()' - Copy job attributes to the response.
+ */
+
+static void
+copy_job_attributes(
+ _ipp_client_t *client, /* I - Client */
+ _ipp_job_t *job, /* I - Job */
+ cups_array_t *ra) /* I - requested-attributes */
+{
+ copy_attributes(client->response, job->attrs, ra, IPP_TAG_ZERO, 0);
+
+ if (!ra || cupsArrayFind(ra, "job-printer-up-time"))
+ ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "job-printer-up-time", (int)time(NULL));
+
+ if (!ra || cupsArrayFind(ra, "job-state"))
+ ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_ENUM,
+ "job-state", job->state);
+
+ if (!ra || cupsArrayFind(ra, "job-state-reasons"))
+ {
+ switch (job->state)
+ {
+ case IPP_JOB_PENDING :
+ ippAddString(client->response, IPP_TAG_JOB,
+ IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ NULL, "none");
+ break;
+
+ case IPP_JOB_HELD :
+ if (job->fd >= 0)
+ ippAddString(client->response, IPP_TAG_JOB,
+ IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ NULL, "job-incoming");
+ else if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_ZERO))
+ ippAddString(client->response, IPP_TAG_JOB,
+ IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ NULL, "job-hold-until-specified");
+ break;
+
+ case IPP_JOB_PROCESSING :
+ if (job->cancel)
+ ippAddString(client->response, IPP_TAG_JOB,
+ IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ NULL, "processing-to-stop-point");
+ else
+ ippAddString(client->response, IPP_TAG_JOB,
+ IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ NULL, "job-printing");
+ break;
+
+ case IPP_JOB_STOPPED :
+ ippAddString(client->response, IPP_TAG_JOB,
+ IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ NULL, "job-stopped");
+ break;
+
+ case IPP_JOB_CANCELED :
+ ippAddString(client->response, IPP_TAG_JOB,
+ IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ NULL, "job-canceled-by-user");
+ break;
+
+ case IPP_JOB_ABORTED :
+ ippAddString(client->response, IPP_TAG_JOB,
+ IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ NULL, "aborted-by-system");
+ break;
+
+ case IPP_JOB_COMPLETED :
+ ippAddString(client->response, IPP_TAG_JOB,
+ IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ NULL, "job-completed-successfully");
+ break;
+ }
+ }
+
+ if (!ra || cupsArrayFind(ra, "time-at-completed"))
+ ippAddInteger(client->response, IPP_TAG_JOB,
+ job->completed ? IPP_TAG_INTEGER : IPP_TAG_NOVALUE,
+ "time-at-completed", job->completed);
+
+ if (!ra || cupsArrayFind(ra, "time-at-processing"))
+ ippAddInteger(client->response, IPP_TAG_JOB,
+ job->processing ? IPP_TAG_INTEGER : IPP_TAG_NOVALUE,
+ "time-at-processing", job->processing);
+}
+
+
+/*
+ * 'create_client()' - Accept a new network connection and create a client
+ * object.
+ */
+
+static _ipp_client_t * /* O - Client */
+create_client(_ipp_printer_t *printer, /* I - Printer */
+ int sock) /* I - Listen socket */
+{
+ _ipp_client_t *client; /* Client */
+ int val; /* Parameter value */
+ socklen_t addrlen; /* Length of address */
+
+
+ if ((client = calloc(1, sizeof(_ipp_client_t))) == NULL)
+ {
+ perror("Unable to allocate memory for client");
+ return (NULL);
+ }
+
+ client->printer = printer;
+ client->http.activity = time(NULL);
+ client->http.hostaddr = &(client->addr);
+ client->http.blocking = 1;
+
+ /*
+ * Accept the client and get the remote address...
+ */
+
+ addrlen = sizeof(http_addr_t);
+
+ if ((client->http.fd = accept(sock, (struct sockaddr *)&(client->addr),
+ &addrlen)) < 0)
+ {
+ perror("Unable to accept client connection");
+
+ free(client);
+
+ return (NULL);
+ }
+
+ httpAddrString(&(client->addr), client->http.hostname,
+ sizeof(client->http.hostname));
+
+ if (Verbosity)
+ fprintf(stderr, "Accepted connection from %s (%s)\n", client->http.hostname,
+ client->http.hostaddr->addr.sa_family == AF_INET ? "IPv4" : "IPv6");
+
+ /*
+ * Using TCP_NODELAY improves responsiveness, especially on systems
+ * with a slow loopback interface. Since we write large buffers
+ * when sending print files and requests, there shouldn't be any
+ * performance penalty for this...
+ */
+
+ val = 1;
+ setsockopt(client->http.fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val,
+ sizeof(val));
+
+ return (client);
+}
+
+
+/*
+ * 'create_job()' - Create a new job object from a Print-Job or Create-Job
+ * request.
+ */
+
+static _ipp_job_t * /* O - Job */
+create_job(_ipp_client_t *client) /* I - Client */
+{
+ _ipp_job_t *job; /* Job */
+ ipp_attribute_t *attr; /* Job attribute */
+ char uri[1024]; /* job-uri value */
+
+
+ _cupsRWLockWrite(&(client->printer->rwlock));
+ if (client->printer->active_job &&
+ client->printer->active_job->state < IPP_JOB_CANCELED)
+ {
+ /*
+ * Only accept a single job at a time...
+ */
+
+ _cupsRWLockWrite(&(client->printer->rwlock));
+ return (NULL);
+ }
+
+ /*
+ * Allocate and initialize the job object...
+ */
+
+ if ((job = calloc(1, sizeof(_ipp_job_t))) == NULL)
+ {
+ perror("Unable to allocate memory for job");
+ return (NULL);
+ }
+
+ job->printer = client->printer;
+ job->attrs = client->request;
+ job->state = IPP_JOB_HELD;
+ job->fd = -1;
+ client->request = NULL;
+
+ /*
+ * Set all but the first two attributes to the job attributes group...
+ */
+
+ for (attr = job->attrs->attrs->next->next; attr; attr = attr->next)
+ attr->group_tag = IPP_TAG_JOB;
+
+ /*
+ * Get the requesting-user-name, document format, and priority...
+ */
+
+ if ((attr = ippFindAttribute(job->attrs, "requesting-user-name",
+ IPP_TAG_NAME)) != NULL)
+ {
+ _cupsStrFree(attr->name);
+ attr->name = _cupsStrAlloc("job-originating-user-name");
+ }
+ else
+ attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME | IPP_TAG_COPY,
+ "job-originating-user-name", NULL, "anonymous");
+
+ if (attr)
+ job->username = attr->values[0].string.text;
+ else
+ job->username = "anonymous";
+
+ if ((attr = ippFindAttribute(job->attrs, "document-format",
+ IPP_TAG_MIMETYPE)) != NULL)
+ job->format = attr->values[0].string.text;
+ else
+ job->format = "application/octet-stream";
+
+ /*
+ * Add job description attributes and add to the jobs array...
+ */
+
+ job->id = client->printer->next_job_id ++;
+
+ snprintf(uri, sizeof(uri), "%s/%d", client->printer->uri, job->id);
+
+ ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, uri);
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL,
+ client->printer->uri);
+ ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation",
+ (int)time(NULL));
+
+ cupsArrayAdd(client->printer->jobs, job);
+ client->printer->active_job = job;
+
+ _cupsRWUnlock(&(client->printer->rwlock));
+
+ return (job);
+}
+
+
+/*
+ * 'create_listener()' - Create a listener socket.
+ */
+
+static int /* O - Listener socket or -1 on error */
+create_listener(int family, /* I - Address family */
+ int *port) /* IO - Port number */
+{
+ int sock, /* Listener socket */
+ val; /* Socket value */
+ http_addr_t address; /* Listen address */
+ socklen_t addrlen; /* Length of listen address */
+
+
+ if ((sock = socket(family, SOCK_STREAM, 0)) < 0)
+ return (-1);
+
+ val = 1;
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+
+#ifdef IPV6_V6ONLY
+ if (family == AF_INET6)
+ setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
+#endif /* IPV6_V6ONLY */
+
+ if (!*port)
+ {
+ /*
+ * Get the auto-assigned port number for the IPv4 socket...
+ */
+
+ /* TODO: This code does not appear to work - port is always 0... */
+ addrlen = sizeof(address);
+ if (getsockname(sock, (struct sockaddr *)&address, &addrlen))
+ {
+ perror("getsockname() failed");
+ *port = 8631;
+ }
+ else
+ *port = _httpAddrPort(&address);
+
+ fprintf(stderr, "Listening on port %d.\n", *port);
+ }
+
+ memset(&address, 0, sizeof(address));
+ address.addr.sa_family = family;
+ _httpAddrSetPort(&address, *port);
+
+ if (bind(sock, (struct sockaddr *)&address, httpAddrLength(&address)))
+ {
+ close(sock);
+ return (-1);
+ }
+
+ if (listen(sock, 5))
+ {
+ close(sock);
+ return (-1);
+ }
+
+ return (sock);
+}
+
+
+/*
+ * 'create_media_col()' - Create a media-col value.
+ */
+
+static ipp_t * /* O - media-col collection */
+create_media_col(const char *media, /* I - Media name */
+ const char *type, /* I - Nedua type */
+ int width, /* I - x-dimension in 2540ths */
+ int length, /* I - y-dimension in 2540ths */
+ int margins) /* I - Value for margins */
+{
+ ipp_t *media_col = ippNew(), /* media-col value */
+ *media_size = ippNew(); /* media-size value */
+ char media_key[256]; /* media-key value */
+
+
+ ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "x-dimension",
+ width);
+ ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "y-dimension",
+ length);
+
+ snprintf(media_key, sizeof(media_key), "%s_%s%s", media, type,
+ margins == 0 ? "_borderless" : "");
+
+ ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-key", NULL,
+ media_key);
+ ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size);
+ ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-bottom-margin", margins);
+ ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-left-margin", margins);
+ ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-right-margin", margins);
+ ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-top-margin", margins);
+ ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type",
+ NULL, type);
+
+ ippDelete(media_size);
+
+ return (media_col);
+}
+
+
+/*
+ * 'create_printer()' - Create, register, and listen for connections to a
+ * printer object.
+ */
+
+static _ipp_printer_t * /* O - Printer */
+create_printer(const char *servername, /* I - Server hostname (NULL for default) */
+ const char *name, /* I - printer-name */
+ const char *location, /* I - printer-location */
+ const char *make, /* I - printer-make-and-model */
+ const char *model, /* I - printer-make-and-model */
+ const char *icon, /* I - printer-icons */
+ const char *docformats, /* I - document-format-supported */
+ int ppm, /* I - Pages per minute in grayscale */
+ int ppm_color, /* I - Pages per minute in color (0 for gray) */
+ int duplex, /* I - 1 = duplex, 0 = simplex */
+ int port, /* I - Port for listeners or 0 for auto */
+#ifdef HAVE_DNSSD
+ const char *regtype, /* I - Bonjour service type */
+#endif /* HAVE_DNSSD */
+ const char *directory) /* I - Spool directory */
+{
+ int i, j; /* Looping vars */
+ _ipp_printer_t *printer; /* Printer */
+ char hostname[256], /* Hostname */
+ uri[1024], /* Printer URI */
+ icons[1024], /* printer-icons URI */
+ adminurl[1024], /* printer-more-info URI */
+ device_id[1024],/* printer-device-id */
+ make_model[128];/* printer-make-and-model */
+ int num_formats; /* Number of document-format-supported values */
+ char *defformat, /* document-format-default value */
+ *formats[100], /* document-format-supported values */
+ *ptr; /* Pointer into string */
+ const char *prefix; /* Prefix string */
+ int num_database; /* Number of database values */
+ ipp_attribute_t *media_col_database;
+ /* media-col-database value */
+ ipp_t *media_col_default;
+ /* media-col-default value */
+ ipp_value_t *media_col_value;
+ /* Current media-col-database value */
+ int k_supported; /* Maximum file size supported */
+#ifdef HAVE_STATVFS
+ struct statvfs spoolinfo; /* FS info for spool directory */
+ double spoolsize; /* FS size */
+#elif defined(HAVE_STATFS)
+ struct statfs spoolinfo; /* FS info for spool directory */
+ double spoolsize; /* FS size */
+#endif /* HAVE_STATVFS */
+ static const int orients[4] = /* orientation-requested-supported values */
+ {
+ IPP_PORTRAIT,
+ IPP_LANDSCAPE,
+ IPP_REVERSE_LANDSCAPE,
+ IPP_REVERSE_PORTRAIT
+ };
+ static const char * const versions[] =/* ipp-versions-supported values */
+ {
+ "1.0",
+ "1.1",
+ "2.0"
+ };
+ static const int ops[] = /* operations-supported values */
+ {
+ IPP_PRINT_JOB,
+ IPP_VALIDATE_JOB,
+ IPP_CREATE_JOB,
+ IPP_SEND_DOCUMENT,
+ IPP_CANCEL_JOB,
+ IPP_GET_JOB_ATTRIBUTES,
+ IPP_GET_JOBS,
+ IPP_GET_PRINTER_ATTRIBUTES
+ };
+ static const char * const charsets[] =/* charset-supported values */
+ {
+ "us-ascii",
+ "utf-8"
+ };
+ static const char * const job_creation[] =
+ { /* job-creation-attributes-supported values */
+ "copies",
+ "ipp-attribute-fidelity",
+ "job-name",
+ "job-priority",
+ "media",
+ "media-col",
+ "multiple-document-handling",
+ "orientation-requested",
+ "print-quality",
+ "sides"
+ };
+ static const char * const media_col_supported[] =
+ { /* media-col-supported values */
+ "media-bottom-margin",
+ "media-left-margin",
+ "media-right-margin",
+ "media-size",
+ "media-top-margin",
+ "media-type"
+ };
+ static const int media_xxx_margin_supported[] =
+ { /* media-xxx-margin-supported values */
+ 0,
+ 635
+ };
+ static const char * const multiple_document_handling[] =
+ { /* multiple-document-handling-supported values */
+ "separate-documents-uncollated-copies",
+ "separate-documents-collated-copies"
+ };
+ static const int print_quality_supported[] =
+ { /* print-quality-supported values */
+ IPP_QUALITY_DRAFT,
+ IPP_QUALITY_NORMAL,
+ IPP_QUALITY_HIGH
+ };
+ static const char * const sides_supported[] =
+ { /* sides-supported values */
+ "one-sided",
+ "two-sided-long-edge",
+ "two-sided-short-edge"
+ };
+ static const char * const which_jobs[] =
+ { /* which-jobs-supported values */
+ "completed",
+ "not-completed",
+ "aborted",
+ "all",
+ "canceled",
+ "pending",
+ "pending-held",
+ "processing",
+ "processing-stopped"
+ };
+
+
+ /*
+ * Allocate memory for the printer...
+ */
+
+ if ((printer = calloc(1, sizeof(_ipp_printer_t))) == NULL)
+ {
+ perror("Unable to allocate memory for printer");
+ return (NULL);
+ }
+
+ printer->ipv4 = -1;
+ printer->ipv6 = -1;
+ printer->name = _cupsStrAlloc(name);
+#ifdef HAVE_DNSSD
+ printer->dnssd_name = _cupsStrRetain(printer->name);
+#endif /* HAVE_DNSSD */
+ printer->directory = _cupsStrAlloc(directory);
+ printer->hostname = _cupsStrAlloc(servername ? servername :
+ httpGetHostname(NULL, hostname,
+ sizeof(hostname)));
+ printer->port = port;
+ printer->state = IPP_PRINTER_IDLE;
+ printer->state_reasons = _IPP_PRINTER_NONE;
+ printer->jobs = cupsArrayNew((cups_array_func_t)compare_jobs, NULL);
+ printer->next_job_id = 1;
+
+ httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ printer->hostname, printer->port, "/ipp");
+ printer->uri = _cupsStrAlloc(uri);
+ printer->urilen = strlen(uri);
+
+ _cupsRWInit(&(printer->rwlock));
+
+ /*
+ * Create the listener sockets...
+ */
+
+ if ((printer->ipv4 = create_listener(AF_INET, &(printer->port))) < 0)
+ {
+ perror("Unable to create IPv4 listener");
+ goto bad_printer;
+ }
+
+ if ((printer->ipv6 = create_listener(AF_INET6, &(printer->port))) < 0)
+ {
+ perror("Unable to create IPv6 listener");
+ goto bad_printer;
+ }
+
+ /*
+ * Prepare values for the printer attributes...
+ */
+
+ httpAssembleURI(HTTP_URI_CODING_ALL, icons, sizeof(icons), "http", NULL,
+ printer->hostname, printer->port, "/icon.png");
+ httpAssembleURI(HTTP_URI_CODING_ALL, adminurl, sizeof(adminurl), "http", NULL,
+ printer->hostname, printer->port, "/");
+
+ if (Verbosity)
+ {
+ fprintf(stderr, "printer-more-info=\"%s\"\n", adminurl);
+ fprintf(stderr, "printer-uri=\"%s\"\n", uri);
+ }
+
+ snprintf(make_model, sizeof(make_model), "%s %s", make, model);
+
+ num_formats = 1;
+ formats[0] = strdup(docformats);
+ defformat = formats[0];
+ for (ptr = strchr(formats[0], ','); ptr; ptr = strchr(ptr, ','))
+ {
+ *ptr++ = '\0';
+ formats[num_formats++] = ptr;
+
+ if (!_cups_strcasecmp(ptr, "application/octet-stream"))
+ defformat = ptr;
+ }
+
+ snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;", make, model);
+ ptr = device_id + strlen(device_id);
+ prefix = "CMD:";
+ for (i = 0; i < num_formats; i ++)
+ {
+ if (!_cups_strcasecmp(formats[i], "application/pdf"))
+ snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%sPDF", prefix);
+ else if (!_cups_strcasecmp(formats[i], "application/postscript"))
+ snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%sPS", prefix);
+ else if (!_cups_strcasecmp(formats[i], "application/vnd.hp-PCL"))
+ snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%sPCL", prefix);
+ else if (!_cups_strcasecmp(formats[i], "image/jpeg"))
+ snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%sJPEG", prefix);
+ else if (!_cups_strcasecmp(formats[i], "image/png"))
+ snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%sPNG", prefix);
+ else if (_cups_strcasecmp(formats[i], "application/octet-stream"))
+ snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%s%s", prefix,
+ formats[i]);
+
+ ptr += strlen(ptr);
+ prefix = ",";
+ }
+ strlcat(device_id, ";", sizeof(device_id));
+
+ /*
+ * Get the maximum spool size based on the size of the filesystem used for
+ * the spool directory. If the host OS doesn't support the statfs call
+ * or the filesystem is larger than 2TiB, always report INT_MAX.
+ */
+
+#ifdef HAVE_STATVFS
+ if (statvfs(printer->directory, &spoolinfo))
+ k_supported = INT_MAX;
+ else if ((spoolsize = (double)spoolinfo.f_frsize *
+ spoolinfo.f_blocks / 1024) > INT_MAX)
+ k_supported = INT_MAX;
+ else
+ k_supported = (int)spoolsize;
+
+#elif defined(HAVE_STATFS)
+ if (statfs(printer->directory, &spoolinfo))
+ k_supported = INT_MAX;
+ else if ((spoolsize = (double)spoolinfo.f_bsize *
+ spoolinfo.f_blocks / 1024) > INT_MAX)
+ k_supported = INT_MAX;
+ else
+ k_supported = (int)spoolsize;
+
+#else
+ k_supported = INT_MAX;
+#endif /* HAVE_STATVFS */
+
+ /*
+ * Create the printer attributes. This list of attributes is sorted to improve
+ * performance when the client provides a requested-attributes attribute...
+ */
+
+ printer->attrs = ippNew();
+
+ /* charset-configured */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
+ "charset-configured", NULL, "utf-8");
+
+ /* charset-supported */
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
+ "charset-supported", sizeof(charsets) / sizeof(charsets[0]),
+ NULL, charsets);
+
+ /* color-supported */
+ ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "color-supported",
+ ppm_color > 0);
+
+ /* compression-supported */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "compression-supported", NULL, "none");
+
+ /* copies-default */
+ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "copies-default", 1);
+
+ /* copies-supported */
+ ippAddRange(printer->attrs, IPP_TAG_PRINTER, "copies-supported", 1, 999);
+
+ /* document-format-default */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
+ "document-format-default", NULL, defformat);
+
+ /* document-format-supported */
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
+ "document-format-supported", num_formats, NULL,
+ (const char * const *)formats);
+
+ /* finishings-default */
+ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "finishings-default", IPP_FINISHINGS_NONE);
+
+ /* finishings-supported */
+ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "finishings-supported", IPP_FINISHINGS_NONE);
+
+ /* generated-natural-language-supported */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE | IPP_TAG_COPY,
+ "generated-natural-language-supported", NULL, "en");
+
+ /* ipp-versions-supported */
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "ipp-versions-supported",
+ sizeof(versions) / sizeof(versions[0]), NULL, versions);
+
+ /* job-creation-attributes-supported */
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "job-creation-attributes-supported",
+ sizeof(job_creation) / sizeof(job_creation[0]),
+ NULL, job_creation);
+
+ /* job-k-octets-supported */
+ ippAddRange(printer->attrs, IPP_TAG_PRINTER, "job-k-octets-supported", 0,
+ k_supported);
+
+ /* job-priority-default */
+ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-priority-default", 50);
+
+ /* job-priority-supported */
+ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-priority-supported", 100);
+
+ /* job-sheets-default */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
+ "job-sheets-default", NULL, "none");
+
+ /* job-sheets-supported */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
+ "job-sheets-supported", NULL, "none");
+
+ /* media-bottom-margin-supported */
+ ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-bottom-margin-supported",
+ (int)(sizeof(media_xxx_margin_supported) /
+ sizeof(media_xxx_margin_supported[0])),
+ media_xxx_margin_supported);
+
+ /* media-col-database */
+ for (num_database = 0, i = 0;
+ i < (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0]));
+ i ++)
+ {
+ if (media_col_sizes[i][2] == _IPP_ENV_ONLY)
+ num_database += 2; /* auto + envelope */
+ else if (media_col_sizes[i][2] == _IPP_PHOTO_ONLY)
+ num_database += 12; /* auto + photographic-* + borderless */
+ else
+ num_database += (int)(sizeof(media_type_supported) /
+ sizeof(media_type_supported[0])) + 6;
+ /* All types + borderless */
+ }
+
+ media_col_database = ippAddCollections(printer->attrs, IPP_TAG_PRINTER,
+ "media-col-database", num_database,
+ NULL);
+ for (media_col_value = media_col_database->values, i = 0;
+ i < (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0]));
+ i ++)
+ {
+ for (j = 0;
+ j < (int)(sizeof(media_type_supported) /
+ sizeof(media_type_supported[0]));
+ j ++)
+ {
+ if (media_col_sizes[i][2] == _IPP_ENV_ONLY &&
+ strcmp(media_type_supported[j], "auto") &&
+ strcmp(media_type_supported[j], "envelope"))
+ continue;
+ else if (media_col_sizes[i][2] == _IPP_PHOTO_ONLY &&
+ strcmp(media_type_supported[j], "auto") &&
+ strncmp(media_type_supported[j], "photographic-", 13))
+ continue;
+
+ media_col_value->collection =
+ create_media_col(media_supported[i], media_type_supported[j],
+ media_col_sizes[i][0], media_col_sizes[i][1],
+ media_xxx_margin_supported[1]);
+ media_col_value ++;
+
+ if (media_col_sizes[i][2] != _IPP_ENV_ONLY &&
+ (!strcmp(media_type_supported[j], "auto") ||
+ !strncmp(media_type_supported[j], "photographic-", 13)))
+ {
+ /*
+ * Add borderless version for this combination...
+ */
+
+ media_col_value->collection =
+ create_media_col(media_supported[i], media_type_supported[j],
+ media_col_sizes[i][0], media_col_sizes[i][1],
+ media_xxx_margin_supported[0]);
+ media_col_value ++;
+ }
+ }
+ }
+
+ /* media-col-default */
+ media_col_default = create_media_col(media_supported[0],
+ media_type_supported[0],
+ media_col_sizes[0][0],
+ media_col_sizes[0][1],
+ media_xxx_margin_supported[1]);
+
+ ippAddCollection(printer->attrs, IPP_TAG_PRINTER, "media-col-default",
+ media_col_default);
+ ippDelete(media_col_default);
+
+ /* media-col-supported */
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "media-col-supported",
+ (int)(sizeof(media_col_supported) /
+ sizeof(media_col_supported[0])), NULL,
+ media_col_supported);
+
+ /* media-default */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "media-default", NULL, media_supported[0]);
+
+ /* media-left-margin-supported */
+ ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-left-margin-supported",
+ (int)(sizeof(media_xxx_margin_supported) /
+ sizeof(media_xxx_margin_supported[0])),
+ media_xxx_margin_supported);
+
+ /* media-right-margin-supported */
+ ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-right-margin-supported",
+ (int)(sizeof(media_xxx_margin_supported) /
+ sizeof(media_xxx_margin_supported[0])),
+ media_xxx_margin_supported);
+
+ /* media-supported */
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "media-supported",
+ (int)(sizeof(media_supported) / sizeof(media_supported[0])),
+ NULL, media_supported);
+
+ /* media-top-margin-supported */
+ ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "media-top-margin-supported",
+ (int)(sizeof(media_xxx_margin_supported) /
+ sizeof(media_xxx_margin_supported[0])),
+ media_xxx_margin_supported);
+
+ /* multiple-document-handling-supported */
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "multiple-document-handling-supported",
+ sizeof(multiple_document_handling) /
+ sizeof(multiple_document_handling[0]), NULL,
+ multiple_document_handling);
+
+ /* multiple-document-jobs-supported */
+ ippAddBoolean(printer->attrs, IPP_TAG_PRINTER,
+ "multiple-document-jobs-supported", 0);
+
+ /* natural-language-configured */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE | IPP_TAG_COPY,
+ "natural-language-configured", NULL, "en");
+
+ /* number-up-default */
+ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "number-up-default", 1);
+
+ /* number-up-supported */
+ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "number-up-supported", 1);
+
+ /* operations-supported */
+ ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "operations-supported", sizeof(ops) / sizeof(ops[0]), ops);
+
+ /* orientation-requested-default */
+ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE,
+ "orientation-requested-default", 0);
+
+ /* orientation-requested-supported */
+ ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "orientation-requested-supported", 4, orients);
+
+ /* output-bin-default */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "output-bin-default", NULL, "face-down");
+
+ /* output-bin-supported */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "output-bin-supported", NULL, "face-down");
+
+ /* pages-per-minute */
+ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "pages-per-minute", ppm);
+
+ /* pages-per-minute-color */
+ if (ppm_color > 0)
+ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "pages-per-minute-color", ppm_color);
+
+ /* pdl-override-supported */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "pdl-override-supported", NULL, "attempted");
+
+ /* print-quality-default */
+ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "print-quality-default", IPP_QUALITY_NORMAL);
+
+ /* print-quality-supported */
+ ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "print-quality-supported",
+ (int)(sizeof(print_quality_supported) /
+ sizeof(print_quality_supported[0])),
+ print_quality_supported);
+
+ /* printer-device-id */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-device-id", NULL, device_id);
+
+ /* printer-icons */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "printer-icons", NULL, icons);
+
+ /* printer-is-accepting-jobs */
+ ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "printer-is-accepting-jobs",
+ 1);
+
+ /* printer-info */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
+ NULL, name);
+
+ /* printer-location */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-location", NULL, location);
+
+ /* printer-make-and-model */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, make_model);
+
+ /* printer-more-info */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "printer-more-info", NULL, adminurl);
+
+ /* printer-name */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name",
+ NULL, name);
+
+ /* printer-resolution-default */
+ ippAddResolution(printer->attrs, IPP_TAG_PRINTER,
+ "printer-resolution-default", IPP_RES_PER_INCH, 600, 600);
+
+ /* printer-resolution-supported */
+ ippAddResolution(printer->attrs, IPP_TAG_PRINTER,
+ "printer-resolution-supported", IPP_RES_PER_INCH, 600, 600);
+
+ /* printer-uri-supported */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "printer-uri-supported", NULL, uri);
+
+ /* sides-default */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "sides-default", NULL, "one-sided");
+
+ /* sides-supported */
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "sides-supported", duplex ? 3 : 1, NULL, sides_supported);
+
+ /* uri-authentication-supported */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "uri-authentication-supported", NULL, "none");
+
+ /* uri-security-supported */
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "uri-security-supported", NULL, "none");
+
+ /* which-jobs-supported */
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "which-jobs-supported",
+ sizeof(which_jobs) / sizeof(which_jobs[0]), NULL, which_jobs);
+
+ free(formats[0]);
+
+ debug_attributes("Printer", printer->attrs);
+
+#ifdef HAVE_DNSSD
+ /*
+ * Register the printer with Bonjour...
+ */
+
+ if (!register_printer(printer, location, make, model, docformats, adminurl,
+ ppm_color > 0, duplex, regtype))
+ goto bad_printer;
+#endif /* HAVE_DNSSD */
+
+ /*
+ * Return it!
+ */
+
+ return (printer);
+
+
+ /*
+ * If we get here we were unable to create the printer...
+ */
+
+ bad_printer:
+
+ delete_printer(printer);
+ return (NULL);
+}
+
+
+/*
+ * 'create_requested_array()' - Create an array for requested-attributes.
+ */
+
+static cups_array_t * /* O - requested-attributes array */
+create_requested_array(
+ _ipp_client_t *client) /* I - Client */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *requested; /* requested-attributes attribute */
+ cups_array_t *ra; /* Requested attributes array */
+ char *value; /* Current value */
+
+
+ /*
+ * Get the requested-attributes attribute, and return NULL if we don't
+ * have one...
+ */
+
+ if ((requested = ippFindAttribute(client->request, "requested-attributes",
+ IPP_TAG_KEYWORD)) == NULL)
+ return (NULL);
+
+ /*
+ * If the attribute contains a single "all" keyword, return NULL...
+ */
+
+ if (requested->num_values == 1 &&
+ !strcmp(requested->values[0].string.text, "all"))
+ return (NULL);
+
+ /*
+ * Create an array using "strcmp" as the comparison function...
+ */
+
+ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+
+ for (i = 0; i < requested->num_values; i ++)
+ {
+ value = requested->values[i].string.text;
+
+ if (!strcmp(value, "job-template"))
+ {
+ cupsArrayAdd(ra, "copies");
+ cupsArrayAdd(ra, "copies-default");
+ cupsArrayAdd(ra, "copies-supported");
+ cupsArrayAdd(ra, "finishings");
+ cupsArrayAdd(ra, "finishings-default");
+ cupsArrayAdd(ra, "finishings-supported");
+ cupsArrayAdd(ra, "job-hold-until");
+ cupsArrayAdd(ra, "job-hold-until-default");
+ cupsArrayAdd(ra, "job-hold-until-supported");
+ cupsArrayAdd(ra, "job-priority");
+ cupsArrayAdd(ra, "job-priority-default");
+ cupsArrayAdd(ra, "job-priority-supported");
+ cupsArrayAdd(ra, "job-sheets");
+ cupsArrayAdd(ra, "job-sheets-default");
+ cupsArrayAdd(ra, "job-sheets-supported");
+ cupsArrayAdd(ra, "media");
+ cupsArrayAdd(ra, "media-col");
+ cupsArrayAdd(ra, "media-col-default");
+ cupsArrayAdd(ra, "media-col-supported");
+ cupsArrayAdd(ra, "media-default");
+ cupsArrayAdd(ra, "media-source-supported");
+ cupsArrayAdd(ra, "media-supported");
+ cupsArrayAdd(ra, "media-type-supported");
+ cupsArrayAdd(ra, "multiple-document-handling");
+ cupsArrayAdd(ra, "multiple-document-handling-default");
+ cupsArrayAdd(ra, "multiple-document-handling-supported");
+ cupsArrayAdd(ra, "number-up");
+ cupsArrayAdd(ra, "number-up-default");
+ cupsArrayAdd(ra, "number-up-supported");
+ cupsArrayAdd(ra, "orientation-requested");
+ cupsArrayAdd(ra, "orientation-requested-default");
+ cupsArrayAdd(ra, "orientation-requested-supported");
+ cupsArrayAdd(ra, "page-ranges");
+ cupsArrayAdd(ra, "page-ranges-supported");
+ cupsArrayAdd(ra, "printer-resolution");
+ cupsArrayAdd(ra, "printer-resolution-default");
+ cupsArrayAdd(ra, "printer-resolution-supported");
+ cupsArrayAdd(ra, "print-quality");
+ cupsArrayAdd(ra, "print-quality-default");
+ cupsArrayAdd(ra, "print-quality-supported");
+ cupsArrayAdd(ra, "sides");
+ cupsArrayAdd(ra, "sides-default");
+ cupsArrayAdd(ra, "sides-supported");
+ }
+ else if (!strcmp(value, "job-description"))
+ {
+ cupsArrayAdd(ra, "date-time-at-completed");
+ cupsArrayAdd(ra, "date-time-at-creation");
+ cupsArrayAdd(ra, "date-time-at-processing");
+ cupsArrayAdd(ra, "job-detailed-status-message");
+ cupsArrayAdd(ra, "job-document-access-errors");
+ cupsArrayAdd(ra, "job-id");
+ cupsArrayAdd(ra, "job-impressions");
+ cupsArrayAdd(ra, "job-impressions-completed");
+ cupsArrayAdd(ra, "job-k-octets");
+ cupsArrayAdd(ra, "job-k-octets-processed");
+ cupsArrayAdd(ra, "job-media-sheets");
+ cupsArrayAdd(ra, "job-media-sheets-completed");
+ cupsArrayAdd(ra, "job-message-from-operator");
+ cupsArrayAdd(ra, "job-more-info");
+ cupsArrayAdd(ra, "job-name");
+ cupsArrayAdd(ra, "job-originating-user-name");
+ cupsArrayAdd(ra, "job-printer-up-time");
+ cupsArrayAdd(ra, "job-printer-uri");
+ cupsArrayAdd(ra, "job-state");
+ cupsArrayAdd(ra, "job-state-message");
+ cupsArrayAdd(ra, "job-state-reasons");
+ cupsArrayAdd(ra, "job-uri");
+ cupsArrayAdd(ra, "number-of-documents");
+ cupsArrayAdd(ra, "number-of-intervening-jobs");
+ cupsArrayAdd(ra, "output-device-assigned");
+ cupsArrayAdd(ra, "time-at-completed");
+ cupsArrayAdd(ra, "time-at-creation");
+ cupsArrayAdd(ra, "time-at-processing");
+ }
+ else if (!strcmp(value, "printer-description"))
+ {
+ cupsArrayAdd(ra, "charset-configured");
+ cupsArrayAdd(ra, "charset-supported");
+ cupsArrayAdd(ra, "color-supported");
+ cupsArrayAdd(ra, "compression-supported");
+ cupsArrayAdd(ra, "document-format-default");
+ cupsArrayAdd(ra, "document-format-supported");
+ cupsArrayAdd(ra, "generated-natural-language-supported");
+ cupsArrayAdd(ra, "ipp-versions-supported");
+ cupsArrayAdd(ra, "job-impressions-supported");
+ cupsArrayAdd(ra, "job-k-octets-supported");
+ cupsArrayAdd(ra, "job-media-sheets-supported");
+ cupsArrayAdd(ra, "multiple-document-jobs-supported");
+ cupsArrayAdd(ra, "multiple-operation-time-out");
+ cupsArrayAdd(ra, "natural-language-configured");
+ cupsArrayAdd(ra, "notify-attributes-supported");
+ cupsArrayAdd(ra, "notify-lease-duration-default");
+ cupsArrayAdd(ra, "notify-lease-duration-supported");
+ cupsArrayAdd(ra, "notify-max-events-supported");
+ cupsArrayAdd(ra, "notify-events-default");
+ cupsArrayAdd(ra, "notify-events-supported");
+ cupsArrayAdd(ra, "notify-pull-method-supported");
+ cupsArrayAdd(ra, "notify-schemes-supported");
+ cupsArrayAdd(ra, "operations-supported");
+ cupsArrayAdd(ra, "pages-per-minute");
+ cupsArrayAdd(ra, "pages-per-minute-color");
+ cupsArrayAdd(ra, "pdl-override-supported");
+ cupsArrayAdd(ra, "printer-alert");
+ cupsArrayAdd(ra, "printer-alert-description");
+ cupsArrayAdd(ra, "printer-current-time");
+ cupsArrayAdd(ra, "printer-driver-installer");
+ cupsArrayAdd(ra, "printer-info");
+ cupsArrayAdd(ra, "printer-is-accepting-jobs");
+ cupsArrayAdd(ra, "printer-location");
+ cupsArrayAdd(ra, "printer-make-and-model");
+ cupsArrayAdd(ra, "printer-message-from-operator");
+ cupsArrayAdd(ra, "printer-more-info");
+ cupsArrayAdd(ra, "printer-more-info-manufacturer");
+ cupsArrayAdd(ra, "printer-name");
+ cupsArrayAdd(ra, "printer-state");
+ cupsArrayAdd(ra, "printer-state-message");
+ cupsArrayAdd(ra, "printer-state-reasons");
+ cupsArrayAdd(ra, "printer-up-time");
+ cupsArrayAdd(ra, "printer-uri-supported");
+ cupsArrayAdd(ra, "queued-job-count");
+ cupsArrayAdd(ra, "reference-uri-schemes-supported");
+ cupsArrayAdd(ra, "uri-authentication-supported");
+ cupsArrayAdd(ra, "uri-security-supported");
+ }
+ else if (!strcmp(value, "printer-defaults"))
+ {
+ cupsArrayAdd(ra, "copies-default");
+ cupsArrayAdd(ra, "document-format-default");
+ cupsArrayAdd(ra, "finishings-default");
+ cupsArrayAdd(ra, "job-hold-until-default");
+ cupsArrayAdd(ra, "job-priority-default");
+ cupsArrayAdd(ra, "job-sheets-default");
+ cupsArrayAdd(ra, "media-default");
+ cupsArrayAdd(ra, "media-col-default");
+ cupsArrayAdd(ra, "number-up-default");
+ cupsArrayAdd(ra, "orientation-requested-default");
+ cupsArrayAdd(ra, "sides-default");
+ }
+ else if (!strcmp(value, "subscription-template"))
+ {
+ cupsArrayAdd(ra, "notify-attributes");
+ cupsArrayAdd(ra, "notify-charset");
+ cupsArrayAdd(ra, "notify-events");
+ cupsArrayAdd(ra, "notify-lease-duration");
+ cupsArrayAdd(ra, "notify-natural-language");
+ cupsArrayAdd(ra, "notify-pull-method");
+ cupsArrayAdd(ra, "notify-recipient-uri");
+ cupsArrayAdd(ra, "notify-time-interval");
+ cupsArrayAdd(ra, "notify-user-data");
+ }
+ else
+ cupsArrayAdd(ra, value);
+ }
+
+ return (ra);
+}
+
+
+/*
+ * 'debug_attributes()' - Print attributes in a request or response.
+ */
+
+static void
+debug_attributes(const char *title, /* I - Title */
+ ipp_t *ipp) /* I - Request/response */
+{
+ ipp_tag_t group_tag; /* Current group */
+ ipp_attribute_t *attr; /* Current attribute */
+ char buffer[2048]; /* String buffer for value */
+
+
+ if (Verbosity <= 1)
+ return;
+
+ fprintf(stderr, "%s:\n", title);
+ for (attr = ipp->attrs, group_tag = IPP_TAG_ZERO; attr; attr = attr->next)
+ {
+ if (attr->group_tag != group_tag)
+ {
+ group_tag = attr->group_tag;
+ fprintf(stderr, " %s\n", ippTagString(group_tag));
+ }
+
+ if (attr->name)
+ {
+ _ippAttrString(attr, buffer, sizeof(buffer));
+ fprintf(stderr, " %s (%s%s) %s\n", attr->name,
+ attr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attr->value_tag), buffer);
+ }
+ }
+}
+
+
+/*
+ * 'delete_client()' - Close the socket and free all memory used by a client
+ * object.
+ */
+
+static void
+delete_client(_ipp_client_t *client) /* I - Client */
+{
+ if (Verbosity)
+ fprintf(stderr, "Closing connection from %s (%s)\n", client->http.hostname,
+ client->http.hostaddr->addr.sa_family == AF_INET ? "IPv4" : "IPv6");
+
+ /*
+ * Flush pending writes before closing...
+ */
+
+ httpFlushWrite(&(client->http));
+
+ if (client->http.fd >= 0)
+ close(client->http.fd);
+
+ /*
+ * Free memory...
+ */
+
+ httpClearCookie(&(client->http));
+ httpClearFields(&(client->http));
+
+ ippDelete(client->request);
+
+ ippDelete(client->response);
+
+ free(client);
+}
+
+
+/*
+ * 'delete_job()' - Remove from the printer and free all memory used by a job
+ * object.
+ */
+
+static void
+delete_job(_ipp_job_t *job) /* I - Job */
+{
+ if (Verbosity)
+ fprintf(stderr, "Removing job #%d from history.\n", job->id);
+
+ ippDelete(job->attrs);
+
+ if (job->filename)
+ {
+ if (!KeepFiles)
+ unlink(job->filename);
+
+ free(job->filename);
+ }
+
+ free(job);
+}
+
+
+/*
+ * 'delete_printer()' - Unregister, close listen sockets, and free all memory
+ * used by a printer object.
+ */
+
+static void
+delete_printer(_ipp_printer_t *printer) /* I - Printer */
+{
+ if (printer->ipv4 >= 0)
+ close(printer->ipv4);
+
+ if (printer->ipv6 >= 0)
+ close(printer->ipv6);
+
+#if HAVE_DNSSD
+ if (printer->printer_ref)
+ DNSServiceRefDeallocate(printer->printer_ref);
+
+ if (printer->ipp_ref)
+ DNSServiceRefDeallocate(printer->ipp_ref);
+
+ if (printer->http_ref)
+ DNSServiceRefDeallocate(printer->http_ref);
+
+ if (printer->common_ref)
+ DNSServiceRefDeallocate(printer->common_ref);
+
+ TXTRecordDeallocate(&(printer->ipp_txt));
+
+ if (printer->dnssd_name)
+ _cupsStrFree(printer->dnssd_name);
+#endif /* HAVE_DNSSD */
+
+ if (printer->name)
+ _cupsStrFree(printer->name);
+ if (printer->icon)
+ _cupsStrFree(printer->icon);
+ if (printer->directory)
+ _cupsStrFree(printer->directory);
+ if (printer->hostname)
+ _cupsStrFree(printer->hostname);
+ if (printer->uri)
+ _cupsStrFree(printer->uri);
+
+ ippDelete(printer->attrs);
+ cupsArrayDelete(printer->jobs);
+
+ free(printer);
+}
+
+
+#ifdef HAVE_DNSSD
+/*
+ * 'dnssd_callback()' - Handle Bonjour registration events.
+ */
+
+static void
+dnssd_callback(
+ DNSServiceRef sdRef, /* I - Service reference */
+ DNSServiceFlags flags, /* I - Status flags */
+ DNSServiceErrorType errorCode, /* I - Error, if any */
+ const char *name, /* I - Service name */
+ const char *regtype, /* I - Service type */
+ const char *domain, /* I - Domain for service */
+ _ipp_printer_t *printer) /* I - Printer */
+{
+ if (errorCode)
+ {
+ fprintf(stderr, "DNSServiceRegister for %s failed with error %d.\n",
+ regtype, (int)errorCode);
+ return;
+ }
+ else if (_cups_strcasecmp(name, printer->dnssd_name))
+ {
+ if (Verbosity)
+ fprintf(stderr, "Now using DNS-SD service name \"%s\".\n", name);
+
+ /* No lock needed since only the main thread accesses/changes this */
+ _cupsStrFree(printer->dnssd_name);
+ printer->dnssd_name = _cupsStrAlloc(name);
+ }
+}
+#endif /* HAVE_DNSSD */
+
+
+/*
+ * 'find_job()' - Find a job specified in a request.
+ */
+
+static _ipp_job_t * /* O - Job or NULL */
+find_job(_ipp_client_t *client) /* I - Client */
+{
+ ipp_attribute_t *attr; /* job-id or job-uri attribute */
+ _ipp_job_t key, /* Job search key */
+ *job; /* Matching job, if any */
+
+
+ key.id = 0;
+
+ if ((attr = ippFindAttribute(client->request, "job-uri",
+ IPP_TAG_URI)) != NULL)
+ {
+ if (!strncmp(attr->values[0].string.text, client->printer->uri,
+ client->printer->urilen) &&
+ attr->values[0].string.text[client->printer->urilen] == '/')
+ key.id = atoi(attr->values[0].string.text + client->printer->urilen + 1);
+ }
+ else if ((attr = ippFindAttribute(client->request, "job-id",
+ IPP_TAG_INTEGER)) != NULL)
+ key.id = attr->values[0].integer;
+
+ _cupsRWLockRead(&(client->printer->rwlock));
+ job = (_ipp_job_t *)cupsArrayFind(client->printer->jobs, &key);
+ _cupsRWUnlock(&(client->printer->rwlock));
+
+ return (job);
+}
+
+
+/*
+ * 'html_escape()' - Write a HTML-safe string.
+ */
+
+static void
+html_escape(_ipp_client_t *client, /* I - Client */
+ const char *s, /* I - String to write */
+ size_t slen) /* I - Number of characters to write */
+{
+ const char *start, /* Start of segment */
+ *end; /* End of string */
+
+
+ start = s;
+ end = s + (slen > 0 ? slen : strlen(s));
+
+ while (*s && s < end)
+ {
+ if (*s == '&' || *s == '<')
+ {
+ if (s > start)
+ httpWrite2(&(client->http), start, s - start);
+
+ if (*s == '&')
+ httpWrite2(&(client->http), "&amp;", 5);
+ else
+ httpWrite2(&(client->http), "&lt;", 4);
+
+ start = s + 1;
+ }
+
+ s ++;
+ }
+
+ if (s > start)
+ httpWrite2(&(client->http), start, s - start);
+}
+
+
+/*
+ * 'html_printf()' - Send formatted text to the client, quoting as needed.
+ */
+
+static void
+html_printf(_ipp_client_t *client, /* I - Client */
+ const char *format, /* I - Printf-style format string */
+ ...) /* I - Additional arguments as needed */
+{
+ va_list ap; /* Pointer to arguments */
+ const char *start; /* Start of string */
+ char size, /* Size character (h, l, L) */
+ type; /* Format type character */
+ int width, /* Width of field */
+ prec; /* Number of characters of precision */
+ char tformat[100], /* Temporary format string for sprintf() */
+ *tptr, /* Pointer into temporary format */
+ temp[1024]; /* Buffer for formatted numbers */
+ char *s; /* Pointer to string */
+
+
+ /*
+ * Loop through the format string, formatting as needed...
+ */
+
+ va_start(ap, format);
+ start = format;
+
+ while (*format)
+ {
+ if (*format == '%')
+ {
+ if (format > start)
+ httpWrite2(&(client->http), start, format - start);
+
+ tptr = tformat;
+ *tptr++ = *format++;
+
+ if (*format == '%')
+ {
+ httpWrite2(&(client->http), "%", 1);
+ format ++;
+ continue;
+ }
+ else if (strchr(" -+#\'", *format))
+ *tptr++ = *format++;
+
+ if (*format == '*')
+ {
+ /*
+ * Get width from argument...
+ */
+
+ format ++;
+ width = va_arg(ap, int);
+
+ snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
+ tptr += strlen(tptr);
+ }
+ else
+ {
+ width = 0;
+
+ while (isdigit(*format & 255))
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ width = width * 10 + *format++ - '0';
+ }
+ }
+
+ if (*format == '.')
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ format ++;
+
+ if (*format == '*')
+ {
+ /*
+ * Get precision from argument...
+ */
+
+ format ++;
+ prec = va_arg(ap, int);
+
+ snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
+ tptr += strlen(tptr);
+ }
+ else
+ {
+ prec = 0;
+
+ while (isdigit(*format & 255))
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ prec = prec * 10 + *format++ - '0';
+ }
+ }
+ }
+
+ if (*format == 'l' && format[1] == 'l')
+ {
+ size = 'L';
+
+ if (tptr < (tformat + sizeof(tformat) - 2))
+ {
+ *tptr++ = 'l';
+ *tptr++ = 'l';
+ }
+
+ format += 2;
+ }
+ else if (*format == 'h' || *format == 'l' || *format == 'L')
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ size = *format++;
+ }
+ else
+ size = 0;
+
+
+ if (!*format)
+ {
+ start = format;
+ break;
+ }
+
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ type = *format++;
+ *tptr = '\0';
+ start = format;
+
+ switch (type)
+ {
+ case 'E' : /* Floating point formats */
+ case 'G' :
+ case 'e' :
+ case 'f' :
+ case 'g' :
+ if ((width + 2) > sizeof(temp))
+ break;
+
+ sprintf(temp, tformat, va_arg(ap, double));
+
+ httpWrite2(&(client->http), temp, strlen(temp));
+ break;
+
+ case 'B' : /* Integer formats */
+ case 'X' :
+ case 'b' :
+ case 'd' :
+ case 'i' :
+ case 'o' :
+ case 'u' :
+ case 'x' :
+ if ((width + 2) > sizeof(temp))
+ break;
+
+# ifdef HAVE_LONG_LONG
+ if (size == 'L')
+ sprintf(temp, tformat, va_arg(ap, long long));
+ else
+# endif /* HAVE_LONG_LONG */
+ if (size == 'l')
+ sprintf(temp, tformat, va_arg(ap, long));
+ else
+ sprintf(temp, tformat, va_arg(ap, int));
+
+ httpWrite2(&(client->http), temp, strlen(temp));
+ break;
+
+ case 'p' : /* Pointer value */
+ if ((width + 2) > sizeof(temp))
+ break;
+
+ sprintf(temp, tformat, va_arg(ap, void *));
+
+ httpWrite2(&(client->http), temp, strlen(temp));
+ break;
+
+ case 'c' : /* Character or character array */
+ if (width <= 1)
+ {
+ temp[0] = va_arg(ap, int);
+ temp[1] = '\0';
+ html_escape(client, temp, 1);
+ }
+ else
+ html_escape(client, va_arg(ap, char *), (size_t)width);
+ break;
+
+ case 's' : /* String */
+ if ((s = va_arg(ap, char *)) == NULL)
+ s = "(null)";
+
+ html_escape(client, s, strlen(s));
+ break;
+ }
+ }
+ else
+ format ++;
+ }
+
+ if (format > start)
+ httpWrite2(&(client->http), start, format - start);
+
+ va_end(ap);
+}
+
+
+/*
+ * 'ipp_cancel_job()' - Cancel a job.
+ */
+
+static void
+ipp_cancel_job(_ipp_client_t *client) /* I - Client */
+{
+ _ipp_job_t *job; /* Job information */
+
+
+ /*
+ * Get the job...
+ */
+
+ if ((job = find_job(client)) == NULL)
+ return;
+
+ /*
+ * See if the job is already completed, canceled, or aborted; if so,
+ * we can't cancel...
+ */
+
+ switch (job->state)
+ {
+ case IPP_JOB_CANCELED :
+ respond_ipp(client, IPP_NOT_POSSIBLE,
+ "Job #%d is already canceled - can\'t cancel.", job->id);
+ break;
+
+ case IPP_JOB_ABORTED :
+ respond_ipp(client, IPP_NOT_POSSIBLE,
+ "Job #%d is already aborted - can\'t cancel.", job->id);
+ break;
+
+ case IPP_JOB_COMPLETED :
+ respond_ipp(client, IPP_NOT_POSSIBLE,
+ "Job #%d is already completed - can\'t cancel.", job->id);
+ break;
+
+ default :
+ /*
+ * Cancel the job...
+ */
+
+ _cupsRWLockWrite(&(client->printer->rwlock));
+
+ if (job->state == IPP_JOB_PROCESSING ||
+ (job->state == IPP_JOB_HELD && job->fd >= 0))
+ job->cancel = 1;
+ else
+ {
+ job->state = IPP_JOB_CANCELED;
+ job->completed = time(NULL);
+ }
+
+ _cupsRWUnlock(&(client->printer->rwlock));
+
+ respond_ipp(client, IPP_OK, NULL);
+ break;
+ }
+}
+
+
+#if 0
+/*
+ * 'ipp_create_job()' - Create a job object.
+ */
+
+static void
+ipp_create_job(_ipp_client_t *client) /* I - Client */
+{
+}
+#endif /* 0 */
+
+
+/*
+ * 'ipp_get_job_attributes()' - Get the attributes for a job object.
+ */
+
+static void
+ipp_get_job_attributes(
+ _ipp_client_t *client) /* I - Client */
+{
+ _ipp_job_t *job; /* Job */
+ cups_array_t *ra; /* requested-attributes */
+
+
+ if ((job = find_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_NOT_FOUND, "Job not found.");
+ return;
+ }
+
+ respond_ipp(client, IPP_OK, NULL);
+
+ ra = create_requested_array(client);
+ copy_job_attributes(client, job, ra);
+ cupsArrayDelete(ra);
+}
+
+
+/*
+ * 'ipp_get_jobs()' - Get a list of job objects.
+ */
+
+static void
+ipp_get_jobs(_ipp_client_t *client) /* I - Client */
+{
+ ipp_attribute_t *attr; /* Current attribute */
+ int job_comparison; /* Job comparison */
+ ipp_jstate_t job_state; /* job-state value */
+ int first_job_id, /* First job ID */
+ limit, /* Maximum number of jobs to return */
+ count; /* Number of jobs that match */
+ const char *username; /* Username */
+ _ipp_job_t *job; /* Current job pointer */
+ cups_array_t *ra; /* Requested attributes array */
+
+
+ /*
+ * See if the "which-jobs" attribute have been specified...
+ */
+
+ if ((attr = ippFindAttribute(client->request, "which-jobs",
+ IPP_TAG_KEYWORD)) != NULL)
+ fprintf(stderr, "%s Get-Jobs which-jobs=%s", client->http.hostname,
+ attr->values[0].string.text);
+
+ if (!attr || !strcmp(attr->values[0].string.text, "not-completed"))
+ {
+ job_comparison = -1;
+ job_state = IPP_JOB_STOPPED;
+ }
+ else if (!strcmp(attr->values[0].string.text, "completed"))
+ {
+ job_comparison = 1;
+ job_state = IPP_JOB_CANCELED;
+ }
+ else if (!strcmp(attr->values[0].string.text, "aborted"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_ABORTED;
+ }
+ else if (!strcmp(attr->values[0].string.text, "all"))
+ {
+ job_comparison = 1;
+ job_state = IPP_JOB_PENDING;
+ }
+ else if (!strcmp(attr->values[0].string.text, "canceled"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_CANCELED;
+ }
+ else if (!strcmp(attr->values[0].string.text, "pending"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_PENDING;
+ }
+ else if (!strcmp(attr->values[0].string.text, "pending-held"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_HELD;
+ }
+ else if (!strcmp(attr->values[0].string.text, "processing"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_PROCESSING;
+ }
+ else if (!strcmp(attr->values[0].string.text, "processing-stopped"))
+ {
+ job_comparison = 0;
+ job_state = IPP_JOB_STOPPED;
+ }
+ else
+ {
+ respond_ipp(client, IPP_ATTRIBUTES,
+ "The which-jobs value \"%s\" is not supported.",
+ attr->values[0].string.text);
+ ippAddString(client->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
+ "which-jobs", NULL, attr->values[0].string.text);
+ return;
+ }
+
+ /*
+ * See if they want to limit the number of jobs reported...
+ */
+
+ if ((attr = ippFindAttribute(client->request, "limit",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ limit = attr->values[0].integer;
+
+ fprintf(stderr, "%s Get-Jobs limit=%d", client->http.hostname, limit);
+ }
+ else
+ limit = 0;
+
+ if ((attr = ippFindAttribute(client->request, "first-job-id",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ first_job_id = attr->values[0].integer;
+
+ fprintf(stderr, "%s Get-Jobs first-job-id=%d", client->http.hostname,
+ first_job_id);
+ }
+ else
+ first_job_id = 1;
+
+ /*
+ * See if we only want to see jobs for a specific user...
+ */
+
+ username = NULL;
+
+ if ((attr = ippFindAttribute(client->request, "my-jobs",
+ IPP_TAG_BOOLEAN)) != NULL)
+ {
+ fprintf(stderr, "%s Get-Jobs my-jobs=%s\n", client->http.hostname,
+ attr->values[0].boolean ? "true" : "false");
+
+ if (attr->values[0].boolean)
+ {
+ if ((attr = ippFindAttribute(client->request, "requesting-user-name",
+ IPP_TAG_NAME)) == NULL)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST,
+ "Need requesting-user-name with my-jobs.");
+ return;
+ }
+
+ username = attr->values[0].string.text;
+
+ fprintf(stderr, "%s Get-Jobs requesting-user-name=\"%s\"\n",
+ client->http.hostname, username);
+ }
+ }
+
+ /*
+ * OK, build a list of jobs for this printer...
+ */
+
+ if ((ra = create_requested_array(client)) == NULL &&
+ !ippFindAttribute(client->request, "requested-attributes",
+ IPP_TAG_KEYWORD))
+ {
+ /*
+ * IPP conformance - Get-Jobs has a default requested-attributes value of
+ * "job-id" and "job-uri".
+ */
+
+ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+ cupsArrayAdd(ra, "job-id");
+ cupsArrayAdd(ra, "job-uri");
+ }
+
+ respond_ipp(client, IPP_OK, NULL);
+
+ _cupsRWLockRead(&(client->printer->rwlock));
+
+ for (count = 0, job = (_ipp_job_t *)cupsArrayFirst(client->printer->jobs);
+ (limit <= 0 || count < limit) && job;
+ job = (_ipp_job_t *)cupsArrayNext(client->printer->jobs))
+ {
+ /*
+ * Filter out jobs that don't match...
+ */
+
+ if ((job_comparison < 0 && job->state > job_state) ||
+ (job_comparison == 0 && job->state != job_state) ||
+ (job_comparison > 0 && job->state < job_state) ||
+ job->id < first_job_id ||
+ (username && job->username && _cups_strcasecmp(username, job->username)))
+ continue;
+
+ if (count > 0)
+ ippAddSeparator(client->response);
+
+ count ++;
+ copy_job_attributes(client, job, ra);
+ }
+
+ cupsArrayDelete(ra);
+
+ _cupsRWUnlock(&(client->printer->rwlock));
+}
+
+
+/*
+ * 'ipp_get_printer_attributes()' - Get the attributes for a printer object.
+ */
+
+static void
+ipp_get_printer_attributes(
+ _ipp_client_t *client) /* I - Client */
+{
+ cups_array_t *ra; /* Requested attributes array */
+ _ipp_printer_t *printer; /* Printer */
+
+
+ /*
+ * Send the attributes...
+ */
+
+ ra = create_requested_array(client);
+ printer = client->printer;
+
+ respond_ipp(client, IPP_OK, NULL);
+
+ _cupsRWLockRead(&(printer->rwlock));
+
+ copy_attributes(client->response, printer->attrs, ra, IPP_TAG_ZERO,
+ IPP_TAG_COPY);
+
+ if (!ra || cupsArrayFind(ra, "printer-state"))
+ ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "printer-state", printer->state);
+
+ if (!ra || cupsArrayFind(ra, "printer-state-reasons"))
+ {
+ if (printer->state_reasons == _IPP_PRINTER_NONE)
+ ippAddString(client->response, IPP_TAG_PRINTER,
+ IPP_TAG_KEYWORD | IPP_TAG_COPY, "printer-state-reasons",
+ NULL, "none");
+ else
+ {
+ int num_reasons = 0;/* Number of reasons */
+ const char *reasons[32]; /* Reason strings */
+
+ if (printer->state_reasons & _IPP_PRINTER_OTHER)
+ reasons[num_reasons ++] = "other";
+ if (printer->state_reasons & _IPP_PRINTER_COVER_OPEN)
+ reasons[num_reasons ++] = "cover-open";
+ if (printer->state_reasons & _IPP_PRINTER_INPUT_TRAY_MISSING)
+ reasons[num_reasons ++] = "input-tray-missing";
+ if (printer->state_reasons & _IPP_PRINTER_MARKER_SUPPLY_EMPTY)
+ reasons[num_reasons ++] = "marker-supply-empty-warning";
+ if (printer->state_reasons & _IPP_PRINTER_MARKER_SUPPLY_LOW)
+ reasons[num_reasons ++] = "marker-supply-low-report";
+ if (printer->state_reasons & _IPP_PRINTER_MARKER_WASTE_ALMOST_FULL)
+ reasons[num_reasons ++] = "marker-waste-almost-full-report";
+ if (printer->state_reasons & _IPP_PRINTER_MARKER_WASTE_FULL)
+ reasons[num_reasons ++] = "marker-waste-full-warning";
+ if (printer->state_reasons & _IPP_PRINTER_MEDIA_EMPTY)
+ reasons[num_reasons ++] = "media-empty-warning";
+ if (printer->state_reasons & _IPP_PRINTER_MEDIA_JAM)
+ reasons[num_reasons ++] = "media-jam-warning";
+ if (printer->state_reasons & _IPP_PRINTER_MEDIA_LOW)
+ reasons[num_reasons ++] = "media-low-report";
+ if (printer->state_reasons & _IPP_PRINTER_MEDIA_NEEDED)
+ reasons[num_reasons ++] = "media-needed-report";
+ if (printer->state_reasons & _IPP_PRINTER_MOVING_TO_PAUSED)
+ reasons[num_reasons ++] = "moving-to-paused";
+ if (printer->state_reasons & _IPP_PRINTER_PAUSED)
+ reasons[num_reasons ++] = "paused";
+ if (printer->state_reasons & _IPP_PRINTER_SPOOL_AREA_FULL)
+ reasons[num_reasons ++] = "spool-area-full";
+ if (printer->state_reasons & _IPP_PRINTER_TONER_EMPTY)
+ reasons[num_reasons ++] = "toner-empty-warning";
+ if (printer->state_reasons & _IPP_PRINTER_TONER_LOW)
+ reasons[num_reasons ++] = "toner-low-report";
+
+ ippAddStrings(client->response, IPP_TAG_PRINTER,
+ IPP_TAG_KEYWORD | IPP_TAG_COPY, "printer-state-reasons",
+ num_reasons, NULL, reasons);
+ }
+ }
+
+ if (!ra || cupsArrayFind(ra, "printer-up-time"))
+ ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "printer-up-time", (int)time(NULL));
+
+ if (!ra || cupsArrayFind(ra, "queued-job-count"))
+ ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "queued-job-count",
+ printer->active_job &&
+ printer->active_job->state < IPP_JOB_CANCELED);
+
+ _cupsRWUnlock(&(printer->rwlock));
+
+ cupsArrayDelete(ra);
+}
+
+
+/*
+ * 'ipp_print_job()' - Create a job object with an attached document.
+ */
+
+static void
+ipp_print_job(_ipp_client_t *client) /* I - Client */
+{
+ _ipp_job_t *job; /* New job */
+ char filename[1024], /* Filename buffer */
+ buffer[4096]; /* Copy buffer */
+ ssize_t bytes; /* Bytes read */
+ cups_array_t *ra; /* Attributes to send in response */
+
+
+ /*
+ * Validate print job attributes...
+ */
+
+ if (!valid_job_attributes(client))
+ {
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * Do we have a file to print?
+ */
+
+ if (client->http.state == HTTP_POST_SEND)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST, "No file in request.");
+ return;
+ }
+
+ /*
+ * Print the job...
+ */
+
+ if ((job = create_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_PRINTER_BUSY, "Currently printing another job.");
+ return;
+ }
+
+ /*
+ * Create a file for the request data...
+ */
+
+ if (!_cups_strcasecmp(job->format, "image/jpeg"))
+ snprintf(filename, sizeof(filename), "%s/%d.jpg",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "image/png"))
+ snprintf(filename, sizeof(filename), "%s/%d.png",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "application/pdf"))
+ snprintf(filename, sizeof(filename), "%s/%d.pdf",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "application/postscript"))
+ snprintf(filename, sizeof(filename), "%s/%d.ps",
+ client->printer->directory, job->id);
+ else
+ snprintf(filename, sizeof(filename), "%s/%d.prn",
+ client->printer->directory, job->id);
+
+ if ((job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
+ {
+ job->state = IPP_JOB_ABORTED;
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to create print file: %s", strerror(errno));
+ return;
+ }
+
+ while ((bytes = httpRead2(&(client->http), buffer, sizeof(buffer))) > 0)
+ {
+ if (write(job->fd, buffer, bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+ }
+
+ if (bytes < 0)
+ {
+ /*
+ * Got an error while reading the print data, so abort this job.
+ */
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to read print file.");
+ return;
+ }
+
+ if (close(job->fd))
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to write print file: %s",
+ strerror(error));
+ return;
+ }
+
+ job->fd = -1;
+ job->filename = strdup(filename);
+ job->state = IPP_JOB_PENDING;
+
+ /*
+ * Process the job...
+ */
+
+ if (!_cupsThreadCreate((_cups_thread_func_t)process_job, job))
+ {
+ job->state = IPP_JOB_ABORTED;
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to process job.");
+ return;
+ }
+
+ /*
+ * Return the job info...
+ */
+
+ respond_ipp(client, IPP_OK, NULL);
+
+ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+ cupsArrayAdd(ra, "job-id");
+ cupsArrayAdd(ra, "job-state");
+ cupsArrayAdd(ra, "job-state-reasons");
+ cupsArrayAdd(ra, "job-uri");
+
+ copy_job_attributes(client, job, ra);
+ cupsArrayDelete(ra);
+}
+
+
+#if 0
+/*
+ * 'ipp_send_document()' - Add an attached document to a job object created with
+ * Create-Job.
+ */
+
+static void
+ipp_send_document(_ipp_client_t *client)/* I - Client */
+{
+}
+#endif /* 0 */
+
+
+/*
+ * 'ipp_validate_job()' - Validate job creation attributes.
+ */
+
+static void
+ipp_validate_job(_ipp_client_t *client) /* I - Client */
+{
+}
+
+
+/*
+ * 'process_client()' - Process client requests on a thread.
+ */
+
+static void * /* O - Exit status */
+process_client(_ipp_client_t *client) /* I - Client */
+{
+ /*
+ * Loop until we are out of requests or timeout (30 seconds)...
+ */
+
+ while (httpWait(&(client->http), 30000))
+ if (!process_http(client))
+ break;
+
+ /*
+ * Close the conection to the client and return...
+ */
+
+ delete_client(client);
+
+ return (NULL);
+}
+
+
+/*
+ * 'process_http()' - Process a HTTP request.
+ */
+
+int /* O - 1 on success, 0 on failure */
+process_http(_ipp_client_t *client) /* I - Client connection */
+{
+ char line[4096], /* Line from client... */
+ operation[64], /* Operation code from socket */
+ uri[1024], /* URI */
+ version[64], /* HTTP version number string */
+ *ptr; /* Pointer into strings */
+ int major, minor; /* HTTP version numbers */
+ http_status_t status; /* Transfer status */
+ ipp_state_t state; /* State of IPP transfer */
+
+
+ /*
+ * Abort if we have an error on the connection...
+ */
+
+ if (client->http.error)
+ return (0);
+
+ /*
+ * Clear state variables...
+ */
+
+ httpClearFields(&(client->http));
+ ippDelete(client->request);
+ ippDelete(client->response);
+
+ client->http.activity = time(NULL);
+ client->http.version = HTTP_1_1;
+ client->http.keep_alive = HTTP_KEEPALIVE_OFF;
+ client->http.data_encoding = HTTP_ENCODE_LENGTH;
+ client->http.data_remaining = 0;
+ client->request = NULL;
+ client->response = NULL;
+ client->operation = HTTP_WAITING;
+
+ /*
+ * Read a request from the connection...
+ */
+
+ while ((ptr = httpGets(line, sizeof(line) - 1, &(client->http))) != NULL)
+ if (*ptr)
+ break;
+
+ if (!ptr)
+ return (0);
+
+ /*
+ * Parse the request line...
+ */
+
+ fprintf(stderr, "%s %s\n", client->http.hostname, line);
+
+ switch (sscanf(line, "%63s%1023s%63s", operation, uri, version))
+ {
+ case 1 :
+ fprintf(stderr, "%s Bad request line.\n", client->http.hostname);
+ respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ return (0);
+
+ case 2 :
+ client->http.version = HTTP_0_9;
+ break;
+
+ case 3 :
+ if (sscanf(version, "HTTP/%d.%d", &major, &minor) != 2)
+ {
+ fprintf(stderr, "%s Bad HTTP version.\n", client->http.hostname);
+ respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ return (0);
+ }
+
+ if (major < 2)
+ {
+ client->http.version = (http_version_t)(major * 100 + minor);
+ if (client->http.version == HTTP_1_1)
+ client->http.keep_alive = HTTP_KEEPALIVE_ON;
+ else
+ client->http.keep_alive = HTTP_KEEPALIVE_OFF;
+ }
+ else
+ {
+ respond_http(client, HTTP_NOT_SUPPORTED, NULL, 0);
+ return (0);
+ }
+ break;
+ }
+
+ /*
+ * Handle full URLs in the request line...
+ */
+
+ if (!strncmp(client->uri, "http:", 5) || !strncmp(client->uri, "ipp:", 4))
+ {
+ char scheme[32], /* Method/scheme */
+ userpass[128], /* Username:password */
+ hostname[HTTP_MAX_HOST];/* Hostname */
+ int port; /* Port number */
+
+ /*
+ * Separate the URI into its components...
+ */
+
+ if (httpSeparateURI(HTTP_URI_CODING_MOST, uri, scheme, sizeof(scheme),
+ userpass, sizeof(userpass),
+ hostname, sizeof(hostname), &port,
+ client->uri, sizeof(client->uri)) < HTTP_URI_OK)
+ {
+ fprintf(stderr, "%s Bad URI \"%s\".\n", client->http.hostname, uri);
+ respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ return (0);
+ }
+ }
+ else
+ {
+ /*
+ * Decode URI
+ */
+
+ if (!_httpDecodeURI(client->uri, uri, sizeof(client->uri)))
+ {
+ fprintf(stderr, "%s Bad URI \"%s\".\n", client->http.hostname, uri);
+ respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ return (0);
+ }
+ }
+
+ /*
+ * Process the request...
+ */
+
+ if (!strcmp(operation, "GET"))
+ client->http.state = HTTP_GET;
+ else if (!strcmp(operation, "POST"))
+ client->http.state = HTTP_POST;
+ else if (!strcmp(operation, "OPTIONS"))
+ client->http.state = HTTP_OPTIONS;
+ else if (!strcmp(operation, "HEAD"))
+ client->http.state = HTTP_HEAD;
+ else
+ {
+ fprintf(stderr, "%s Bad operation \"%s\".\n", client->http.hostname,
+ operation);
+ respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ return (0);
+ }
+
+ client->start = time(NULL);
+ client->operation = client->http.state;
+ client->http.status = HTTP_OK;
+
+ /*
+ * Parse incoming parameters until the status changes...
+ */
+
+ while ((status = httpUpdate(&(client->http))) == HTTP_CONTINUE);
+
+ if (status != HTTP_OK)
+ {
+ respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ return (0);
+ }
+
+ if (!client->http.fields[HTTP_FIELD_HOST][0] &&
+ client->http.version >= HTTP_1_1)
+ {
+ /*
+ * HTTP/1.1 and higher require the "Host:" field...
+ */
+
+ respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ return (0);
+ }
+
+ /*
+ * Handle HTTP Upgrade...
+ */
+
+ if (!_cups_strcasecmp(client->http.fields[HTTP_FIELD_CONNECTION], "Upgrade"))
+ {
+ if (!respond_http(client, HTTP_NOT_IMPLEMENTED, NULL, 0))
+ return (0);
+ }
+
+ /*
+ * Handle HTTP Expect...
+ */
+
+ if (client->http.expect &&
+ (client->operation == HTTP_POST || client->operation == HTTP_PUT))
+ {
+ if (client->http.expect == HTTP_CONTINUE)
+ {
+ /*
+ * Send 100-continue header...
+ */
+
+ if (!respond_http(client, HTTP_CONTINUE, NULL, 0))
+ return (0);
+ }
+ else
+ {
+ /*
+ * Send 417-expectation-failed header...
+ */
+
+ if (!respond_http(client, HTTP_EXPECTATION_FAILED, NULL, 0))
+ return (0);
+
+ httpPrintf(&(client->http), "Content-Length: 0\r\n");
+ httpPrintf(&(client->http), "\r\n");
+ httpFlushWrite(&(client->http));
+ client->http.data_encoding = HTTP_ENCODE_LENGTH;
+ }
+ }
+
+ /*
+ * Handle new transfers...
+ */
+
+ switch (client->operation)
+ {
+ case HTTP_OPTIONS :
+ /*
+ * Do HEAD/OPTIONS command...
+ */
+
+ return (respond_http(client, HTTP_OK, NULL, 0));
+
+ case HTTP_HEAD :
+ if (!strcmp(client->uri, "/icon.png"))
+ return (respond_http(client, HTTP_OK, "image/png", 0));
+ else if (!strcmp(client->uri, "/"))
+ return (respond_http(client, HTTP_OK, "text/html", 0));
+ else
+ return (respond_http(client, HTTP_NOT_FOUND, NULL, 0));
+ break;
+
+ case HTTP_GET :
+ if (!strcmp(client->uri, "/icon.png"))
+ {
+ /*
+ * Send PNG icon file.
+ */
+
+ int fd; /* Icon file */
+ struct stat fileinfo; /* Icon file information */
+ char buffer[4096]; /* Copy buffer */
+ ssize_t bytes; /* Bytes */
+
+ if (!stat(client->printer->icon, &fileinfo) &&
+ (fd = open(client->printer->icon, O_RDONLY)) >= 0)
+ {
+ if (!respond_http(client, HTTP_OK, "image/png", fileinfo.st_size))
+ {
+ close(fd);
+ return (0);
+ }
+
+ while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
+ httpWrite2(&(client->http), buffer, bytes);
+
+ httpFlushWrite(&(client->http));
+
+ close(fd);
+ }
+ else
+ return (respond_http(client, HTTP_NOT_FOUND, NULL, 0));
+ }
+ else if (!strcmp(client->uri, "/"))
+ {
+ /*
+ * Show web status page...
+ */
+
+ if (!respond_http(client, HTTP_OK, "text/html", 0))
+ return (0);
+
+ html_printf(client,
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" "
+ "\"http://www.w3.org/TR/html4/strict.dtd\">\n"
+ "<html>\n"
+ "<head>\n"
+ "<title>%s</title>\n"
+ "<link rel=\"SHORTCUT ICON\" href=\"/icon.png\" "
+ "type=\"image/png\">\n"
+ "</head>\n"
+ "<body>\n"
+ "</body>\n"
+ "<h1>%s</h1>\n"
+ "<p>%s, %d job(s).</p>\n"
+ "</body>\n"
+ "</html>\n",
+ client->printer->name, client->printer->name,
+ client->printer->state == IPP_PRINTER_IDLE ? "Idle" :
+ client->printer->state == IPP_PRINTER_PROCESSING ?
+ "Printing" : "Stopped",
+ cupsArrayCount(client->printer->jobs));
+ httpWrite2(&(client->http), "", 0);
+
+ return (1);
+ }
+ else
+ return (respond_http(client, HTTP_NOT_FOUND, NULL, 0));
+ break;
+
+ case HTTP_POST :
+ if (client->http.data_remaining < 0 ||
+ (!client->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
+ client->http.data_encoding == HTTP_ENCODE_LENGTH))
+ {
+ /*
+ * Negative content lengths are invalid...
+ */
+
+ return (respond_http(client, HTTP_BAD_REQUEST, NULL, 0));
+ }
+
+ if (strcmp(client->http.fields[HTTP_FIELD_CONTENT_TYPE],
+ "application/ipp"))
+ {
+ /*
+ * Not an IPP request...
+ */
+
+ return (respond_http(client, HTTP_BAD_REQUEST, NULL, 0));
+ }
+
+ /*
+ * Read the IPP request...
+ */
+
+ client->request = ippNew();
+
+ while ((state = ippRead(&(client->http), client->request)) != IPP_DATA)
+ if (state == IPP_ERROR)
+ {
+ fprintf(stderr, "%s IPP read error (%s).\n", client->http.hostname,
+ ippOpString(client->request->request.op.operation_id));
+ respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ return (0);
+ }
+
+ /*
+ * Now that we have the IPP request, process the request...
+ */
+
+ return (process_ipp(client));
+
+ default :
+ break; /* Anti-compiler-warning-code */
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'process_ipp()' - Process an IPP request.
+ */
+
+static int /* O - 1 on success, 0 on error */
+process_ipp(_ipp_client_t *client) /* I - Client */
+{
+ ipp_tag_t group; /* Current group tag */
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_attribute_t *charset; /* Character set attribute */
+ ipp_attribute_t *language; /* Language attribute */
+ ipp_attribute_t *uri; /* Printer URI attribute */
+
+
+ debug_attributes("Request", client->request);
+
+ /*
+ * First build an empty response message for this request...
+ */
+
+ client->operation_id = client->request->request.op.operation_id;
+ client->response = ippNew();
+
+ client->response->request.status.version[0] =
+ client->request->request.op.version[0];
+ client->response->request.status.version[1] =
+ client->request->request.op.version[1];
+ client->response->request.status.request_id =
+ client->request->request.op.request_id;
+
+ /*
+ * Then validate the request header and required attributes...
+ */
+
+ if (client->request->request.any.version[0] < 1 ||
+ client->request->request.any.version[0] > 2)
+ {
+ /*
+ * Return an error, since we only support IPP 1.x and 2.x.
+ */
+
+ respond_ipp(client, IPP_VERSION_NOT_SUPPORTED,
+ "Bad request version number %d.%d.",
+ client->request->request.any.version[0],
+ client->request->request.any.version[1]);
+ }
+ else if (client->request->request.any.request_id <= 0)
+ respond_ipp(client, IPP_BAD_REQUEST, "Bad request-id %d.",
+ client->request->request.any.request_id);
+ else if (!client->request->attrs)
+ respond_ipp(client, IPP_BAD_REQUEST, "No attributes in request.");
+ else
+ {
+ /*
+ * Make sure that the attributes are provided in the correct order and
+ * don't repeat groups...
+ */
+
+ for (attr = client->request->attrs, group = attr->group_tag;
+ attr;
+ attr = attr->next)
+ if (attr->group_tag < group && attr->group_tag != IPP_TAG_ZERO)
+ {
+ /*
+ * Out of order; return an error...
+ */
+
+ respond_ipp(client, IPP_BAD_REQUEST,
+ "Attribute groups are out of order (%x < %x).",
+ attr->group_tag, group);
+ break;
+ }
+ else
+ group = attr->group_tag;
+
+ if (!attr)
+ {
+ /*
+ * Then make sure that the first three attributes are:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri/job-uri
+ */
+
+ attr = client->request->attrs;
+ if (attr && attr->name &&
+ !strcmp(attr->name, "attributes-charset") &&
+ (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_CHARSET)
+ charset = attr;
+ else
+ charset = NULL;
+
+ if (attr)
+ attr = attr->next;
+
+ if (attr && attr->name &&
+ !strcmp(attr->name, "attributes-natural-language") &&
+ (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_LANGUAGE)
+ language = attr;
+ else
+ language = NULL;
+
+ if ((attr = ippFindAttribute(client->request, "printer-uri",
+ IPP_TAG_URI)) != NULL)
+ uri = attr;
+ else if ((attr = ippFindAttribute(client->request, "job-uri",
+ IPP_TAG_URI)) != NULL)
+ uri = attr;
+ else
+ uri = NULL;
+
+ ippAddString(client->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL,
+ charset ? charset->values[0].string.text : "utf-8");
+
+ ippAddString(client->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL,
+ language ? language->values[0].string.text : "en");
+
+ if (charset &&
+ _cups_strcasecmp(charset->values[0].string.text, "us-ascii") &&
+ _cups_strcasecmp(charset->values[0].string.text, "utf-8"))
+ {
+ /*
+ * Bad character set...
+ */
+
+ respond_ipp(client, IPP_BAD_REQUEST,
+ "Unsupported character set \"%s\".",
+ charset->values[0].string.text);
+ }
+ else if (!charset || !language || !uri)
+ {
+ /*
+ * Return an error, since attributes-charset,
+ * attributes-natural-language, and printer-uri/job-uri are required
+ * for all operations.
+ */
+
+ respond_ipp(client, IPP_BAD_REQUEST, "Missing required attributes.");
+ }
+ else if (strcmp(uri->values[0].string.text, client->printer->uri) &&
+ strncmp(uri->values[0].string.text, client->printer->uri,
+ client->printer->urilen))
+ {
+ respond_ipp(client, IPP_NOT_FOUND, "%s %s not found.", uri->name,
+ uri->values[0].string.text);
+ }
+ else
+ {
+ /*
+ * Try processing the operation...
+ */
+
+ if (client->http.expect == HTTP_CONTINUE)
+ {
+ /*
+ * Send 100-continue header...
+ */
+
+ if (!respond_http(client, HTTP_CONTINUE, NULL, 0))
+ return (0);
+ }
+
+ switch (client->request->request.op.operation_id)
+ {
+ case IPP_PRINT_JOB :
+ ipp_print_job(client);
+ break;
+
+ case IPP_VALIDATE_JOB :
+ ipp_validate_job(client);
+ break;
+
+ case IPP_CANCEL_JOB :
+ ipp_cancel_job(client);
+ break;
+
+ case IPP_GET_JOB_ATTRIBUTES :
+ ipp_get_job_attributes(client);
+ break;
+
+ case IPP_GET_JOBS :
+ ipp_get_jobs(client);
+ break;
+
+ case IPP_GET_PRINTER_ATTRIBUTES :
+ ipp_get_printer_attributes(client);
+ break;
+
+ default :
+ respond_ipp(client, IPP_OPERATION_NOT_SUPPORTED,
+ "Operation not supported.");
+ break;
+ }
+ }
+ }
+ }
+
+ /*
+ * Send the HTTP header and return...
+ */
+
+ if (client->http.state != HTTP_POST_SEND)
+ httpFlush(&(client->http)); /* Flush trailing (junk) data */
+
+ return (respond_http(client, HTTP_OK, "application/ipp",
+ ippLength(client->response)));
+}
+
+
+/*
+ * 'process_job()' - Process a print job.
+ */
+
+static void * /* O - Thread exit status */
+process_job(_ipp_job_t *job) /* I - Job */
+{
+ job->state = IPP_JOB_PROCESSING;
+ job->printer->state = IPP_PRINTER_PROCESSING;
+
+ sleep(5);
+
+ if (job->cancel)
+ job->state = IPP_JOB_CANCELED;
+ else
+ job->state = IPP_JOB_COMPLETED;
+
+ job->completed = time(NULL);
+ job->printer->state = IPP_PRINTER_IDLE;
+ job->printer->active_job = NULL;
+
+ return (NULL);
+}
+
+
+#ifdef HAVE_DNSSD
+/*
+ * 'register_printer()' - Register a printer object via Bonjour.
+ */
+
+static int /* O - 1 on success, 0 on error */
+register_printer(
+ _ipp_printer_t *printer, /* I - Printer */
+ const char *location, /* I - Location */
+ const char *make, /* I - Manufacturer */
+ const char *model, /* I - Model name */
+ const char *formats, /* I - Supported formats */
+ const char *adminurl, /* I - Web interface URL */
+ int color, /* I - 1 = color, 0 = monochrome */
+ int duplex, /* I - 1 = duplex, 0 = simplex */
+ const char *regtype) /* I - Service type */
+{
+ DNSServiceErrorType error; /* Error from Bonjour */
+ char make_model[256],/* Make and model together */
+ product[256]; /* Product string */
+
+
+ /*
+ * Build the TXT record for IPP...
+ */
+
+ snprintf(make_model, sizeof(make_model), "%s %s", make, model);
+ snprintf(product, sizeof(product), "(%s)", model);
+
+ TXTRecordCreate(&(printer->ipp_txt), 1024, NULL);
+ TXTRecordSetValue(&(printer->ipp_txt), "txtvers", 1, "1");
+ TXTRecordSetValue(&(printer->ipp_txt), "qtotal", 1, "1");
+ TXTRecordSetValue(&(printer->ipp_txt), "rp", 3, "ipp");
+ TXTRecordSetValue(&(printer->ipp_txt), "ty", (uint8_t)strlen(make_model),
+ make_model);
+ TXTRecordSetValue(&(printer->ipp_txt), "adminurl", (uint8_t)strlen(adminurl),
+ adminurl);
+ TXTRecordSetValue(&(printer->ipp_txt), "note", (uint8_t)strlen(location),
+ location);
+ TXTRecordSetValue(&(printer->ipp_txt), "priority", 1, "0");
+ TXTRecordSetValue(&(printer->ipp_txt), "product", (uint8_t)strlen(product),
+ product);
+ TXTRecordSetValue(&(printer->ipp_txt), "pdl", (uint8_t)strlen(formats),
+ formats);
+ TXTRecordSetValue(&(printer->ipp_txt), "Color", 1, color ? "T" : "F");
+ TXTRecordSetValue(&(printer->ipp_txt), "Duplex", 1, duplex ? "T" : "F");
+ TXTRecordSetValue(&(printer->ipp_txt), "usb_MFG", (uint8_t)strlen(make),
+ make);
+ TXTRecordSetValue(&(printer->ipp_txt), "usb_MDL", (uint8_t)strlen(model),
+ model);
+ TXTRecordSetValue(&(printer->ipp_txt), "air", 4, "none");
+
+ /*
+ * Create a shared service reference for Bonjour...
+ */
+
+ if ((error = DNSServiceCreateConnection(&(printer->common_ref)))
+ != kDNSServiceErr_NoError)
+ {
+ fprintf(stderr, "Unable to create mDNSResponder connection: %d\n", error);
+ return (0);
+ }
+
+ /*
+ * Register the _printer._tcp (LPD) service type with a port number of 0 to
+ * defend our service name but not actually support LPD...
+ */
+
+ printer->printer_ref = printer->common_ref;
+
+ if ((error = DNSServiceRegister(&(printer->printer_ref),
+ kDNSServiceFlagsShareConnection,
+ 0 /* interfaceIndex */, printer->dnssd_name,
+ "_printer._tcp", NULL /* domain */,
+ NULL /* host */, 0 /* port */, 0 /* txtLen */,
+ NULL /* txtRecord */,
+ (DNSServiceRegisterReply)dnssd_callback,
+ printer)) != kDNSServiceErr_NoError)
+ {
+ fprintf(stderr, "Unable to register \"%s._printer._tcp\": %d\n",
+ printer->dnssd_name, error);
+ return (0);
+ }
+
+ /*
+ * Then register the _ipp._tcp (IPP) service type with the real port number to
+ * advertise our IPP printer...
+ */
+
+ printer->ipp_ref = printer->common_ref;
+
+ if ((error = DNSServiceRegister(&(printer->ipp_ref),
+ kDNSServiceFlagsShareConnection,
+ 0 /* interfaceIndex */, printer->dnssd_name,
+ regtype, NULL /* domain */,
+ NULL /* host */, htons(printer->port),
+ TXTRecordGetLength(&(printer->ipp_txt)),
+ TXTRecordGetBytesPtr(&(printer->ipp_txt)),
+ (DNSServiceRegisterReply)dnssd_callback,
+ printer)) != kDNSServiceErr_NoError)
+ {
+ fprintf(stderr, "Unable to register \"%s.%s\": %d\n",
+ printer->dnssd_name, regtype, error);
+ return (0);
+ }
+
+ /*
+ * Similarly, register the _http._tcp,_printer (HTTP) service type with the
+ * real port number to advertise our IPP printer...
+ */
+
+ printer->http_ref = printer->common_ref;
+
+ if ((error = DNSServiceRegister(&(printer->http_ref),
+ kDNSServiceFlagsShareConnection,
+ 0 /* interfaceIndex */, printer->dnssd_name,
+ "_http._tcp,_printer", NULL /* domain */,
+ NULL /* host */, htons(printer->port),
+ 0 /* txtLen */, NULL, /* txtRecord */
+ (DNSServiceRegisterReply)dnssd_callback,
+ printer)) != kDNSServiceErr_NoError)
+ {
+ fprintf(stderr, "Unable to register \"%s.%s\": %d\n",
+ printer->dnssd_name, regtype, error);
+ return (0);
+ }
+
+ return (1);
+}
+#endif /* HAVE_DNSSD */
+
+
+/*
+ * 'respond_http()' - Send a HTTP response.
+ */
+
+int /* O - 1 on success, 0 on failure */
+respond_http(_ipp_client_t *client, /* I - Client */
+ http_status_t code, /* I - HTTP status of response */
+ const char *type, /* I - MIME type of response */
+ size_t length) /* I - Length of response */
+{
+ char message[1024]; /* Text message */
+
+
+ fprintf(stderr, "%s %s\n", client->http.hostname, httpStatus(code));
+
+ if (code == HTTP_CONTINUE)
+ {
+ /*
+ * 100-continue doesn't send any headers...
+ */
+
+ return (httpPrintf(&(client->http), "HTTP/%d.%d 100 Continue\r\n\r\n",
+ client->http.version / 100,
+ client->http.version % 100) > 0);
+ }
+
+ /*
+ * Format an error message...
+ */
+
+ if (!type && !length && code != HTTP_OK)
+ {
+ snprintf(message, sizeof(message), "%d - %s\n", code, httpStatus(code));
+
+ type = "text/plain";
+ length = strlen(message);
+ }
+ else
+ message[0] = '\0';
+
+ /*
+ * Send the HTTP status header...
+ */
+
+ httpFlushWrite(&(client->http));
+
+ client->http.data_encoding = HTTP_ENCODE_FIELDS;
+
+ if (httpPrintf(&(client->http), "HTTP/%d.%d %d %s\r\n", client->http.version / 100,
+ client->http.version % 100, code, httpStatus(code)) < 0)
+ return (0);
+
+ /*
+ * Follow the header with the response fields...
+ */
+
+ if (httpPrintf(&(client->http), "Date: %s\r\n", httpGetDateString(time(NULL))) < 0)
+ return (0);
+
+ if (client->http.keep_alive && client->http.version >= HTTP_1_0)
+ {
+ if (httpPrintf(&(client->http),
+ "Connection: Keep-Alive\r\n"
+ "Keep-Alive: timeout=10\r\n") < 0)
+ return (0);
+ }
+
+ if (code == HTTP_METHOD_NOT_ALLOWED || client->operation == HTTP_OPTIONS)
+ {
+ if (httpPrintf(&(client->http), "Allow: GET, HEAD, OPTIONS, POST\r\n") < 0)
+ return (0);
+ }
+
+ if (type)
+ {
+ if (!strcmp(type, "text/html"))
+ {
+ if (httpPrintf(&(client->http),
+ "Content-Type: text/html; charset=utf-8\r\n") < 0)
+ return (0);
+ }
+ else if (httpPrintf(&(client->http), "Content-Type: %s\r\n", type) < 0)
+ return (0);
+ }
+
+ if (length == 0 && !message[0])
+ {
+ if (httpPrintf(&(client->http), "Transfer-Encoding: chunked\r\n\r\n") < 0)
+ return (0);
+ }
+ else if (httpPrintf(&(client->http), "Content-Length: " CUPS_LLFMT "\r\n\r\n",
+ CUPS_LLCAST length) < 0)
+ return (0);
+
+ if (httpFlushWrite(&(client->http)) < 0)
+ return (0);
+
+ /*
+ * Send the response data...
+ */
+
+ if (message[0])
+ {
+ /*
+ * Send a plain text message.
+ */
+
+ if (httpPrintf(&(client->http), "%s", message) < 0)
+ return (0);
+ }
+ else if (client->response)
+ {
+ /*
+ * Send an IPP response...
+ */
+
+ debug_attributes("Response", client->response);
+
+ client->http.data_encoding = HTTP_ENCODE_LENGTH;
+ client->http.data_remaining = (off_t)ippLength(client->response);
+ client->response->state = IPP_IDLE;
+
+ if (ippWrite(&(client->http), client->response) != IPP_DATA)
+ return (0);
+ }
+ else
+ client->http.data_encoding = HTTP_ENCODE_CHUNKED;
+
+ /*
+ * Flush the data and return...
+ */
+
+ return (httpFlushWrite(&(client->http)) >= 0);
+}
+
+
+/*
+ * 'respond_ipp()' - Send an IPP response.
+ */
+
+static void
+respond_ipp(_ipp_client_t *client, /* I - Client */
+ ipp_status_t status, /* I - status-code */
+ const char *message, /* I - printf-style status-message */
+ ...) /* I - Additional args as needed */
+{
+ va_list ap; /* Pointer to additional args */
+ char formatted[1024]; /* Formatted errror message */
+
+
+ client->response->request.status.status_code = status;
+
+ if (!client->response->attrs)
+ {
+ ippAddString(client->response, IPP_TAG_OPERATION,
+ IPP_TAG_CHARSET | IPP_TAG_COPY, "attributes-charset", NULL,
+ "utf-8");
+ ippAddString(client->response, IPP_TAG_OPERATION,
+ IPP_TAG_LANGUAGE | IPP_TAG_COPY, "attributes-natural-language",
+ NULL, "en-us");
+ }
+
+ if (message)
+ {
+ va_start(ap, message);
+ vsnprintf(formatted, sizeof(formatted), message, ap);
+ va_end(ap);
+
+ ippAddString(client->response, IPP_TAG_OPERATION, IPP_TAG_TEXT,
+ "status-message", NULL, formatted);
+ }
+ else
+ formatted[0] = '\0';
+
+ fprintf(stderr, "%s %s %s (%s)\n", client->http.hostname,
+ ippOpString(client->operation_id), ippErrorString(status), formatted);
+}
+
+
+/*
+ * 'run_printer()' - Run the printer service.
+ */
+
+static void
+run_printer(_ipp_printer_t *printer) /* I - Printer */
+{
+ int num_fds; /* Number of file descriptors */
+ struct pollfd polldata[3]; /* poll() data */
+ int timeout; /* Timeout for poll() */
+ _ipp_client_t *client; /* New client */
+
+
+ /*
+ * Setup poll() data for the Bonjour service socket and IPv4/6 listeners...
+ */
+
+ polldata[0].fd = printer->ipv4;
+ polldata[0].events = POLLIN;
+
+ polldata[1].fd = printer->ipv6;
+ polldata[1].events = POLLIN;
+
+ num_fds = 2;
+
+#ifdef HAVE_DNSSD
+ polldata[num_fds ].fd = DNSServiceRefSockFD(printer->common_ref);
+ polldata[num_fds ++].events = POLLIN;
+#endif /* HAVE_DNSSD */
+
+ /*
+ * Loop until we are killed or have a hard error...
+ */
+
+ for (;;)
+ {
+ if (cupsArrayCount(printer->jobs))
+ timeout = 10;
+ else
+ timeout = -1;
+
+ if (poll(polldata, num_fds, timeout) < 0 && errno != EINTR)
+ {
+ perror("poll() failed");
+ break;
+ }
+
+ if (polldata[0].revents & POLLIN)
+ {
+ if ((client = create_client(printer, printer->ipv4)) != NULL)
+ {
+ if (!_cupsThreadCreate((_cups_thread_func_t)process_client, client))
+ {
+ perror("Unable to create client thread");
+ delete_client(client);
+ }
+ }
+ }
+
+ if (polldata[1].revents & POLLIN)
+ {
+ if ((client = create_client(printer, printer->ipv6)) != NULL)
+ {
+ if (!_cupsThreadCreate((_cups_thread_func_t)process_client, client))
+ {
+ perror("Unable to create client thread");
+ delete_client(client);
+ }
+ }
+ }
+
+#ifdef HAVE_DNSSD
+ if (polldata[2].revents & POLLIN)
+ DNSServiceProcessResult(printer->common_ref);
+#endif /* HAVE_DNSSD */
+
+ /*
+ * Clean out old jobs...
+ */
+
+ clean_jobs(printer);
+ }
+}
+
+
+/*
+ * 'usage()' - Show program usage.
+ */
+
+static void
+usage(int status) /* O - Exit status */
+{
+ if (!status)
+ {
+ puts(CUPS_SVERSION " - Copyright 2010 by Apple Inc. All rights reserved.");
+ puts("");
+ }
+
+ puts("Usage: ippserver [options] \"name\"");
+ puts("");
+ puts("Options:");
+ puts("-2 Supports 2-sided printing (default=1-sided)");
+ puts("-M manufacturer Manufacturer name (default=Test)");
+ printf("-d spool-directory Spool directory "
+ "(default=/tmp/ippserver.%d)\n", (int)getpid());
+ puts("-f type/subtype[,...] List of supported types "
+ "(default=application/pdf,image/jpeg)");
+ puts("-h Show program help");
+ puts("-i iconfile.png PNG icon file (default=printer.png)");
+ puts("-l location Location of printer (default=empty string)");
+ puts("-m model Model name (default=Printer)");
+ puts("-n hostname Hostname for printer");
+ puts("-p port Port number (default=auto)");
+ puts("-r regtype Bonjour service type (default=_ipp._tcp)");
+ puts("-s speed[,color-speed] Speed in pages per minute (default=10,0)");
+ puts("-v[vvv] Be (very) verbose");
+
+ exit(status);
+}
+
+
+/*
+ * 'valid_job_attributes()' - Determine whether the job attributes are valid.
+ *
+ * When one or more job attributes are invalid, this function adds a suitable
+ * response and attributes to the unsupported group.
+ */
+
+static int /* O - 1 if valid, 0 if not */
+valid_job_attributes(
+ _ipp_client_t *client) /* I - Client */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *attr, /* Current attribute */
+ *supported; /* document-format-supported */
+ const char *format = NULL; /* document-format value */
+ int valid = 1; /* Valid attributes? */
+
+
+ /*
+ * Check operation attributes...
+ */
+
+#define respond_unsupported(client, attr) \
+ if (valid) \
+ { \
+ respond_ipp(client, IPP_ATTRIBUTES, "Unsupported %s %s%s value.", \
+ attr->name, attr->num_values > 1 ? "1setOf " : "", \
+ ippTagString(attr->value_tag)); \
+ valid = 0; \
+ } \
+ copy_attribute(client->response, attr, IPP_TAG_UNSUPPORTED_GROUP, 0)
+
+ if ((attr = ippFindAttribute(client->request, "compression",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ /*
+ * If compression is specified, only accept "none"...
+ */
+
+ if (attr->num_values != 1 || attr->value_tag != IPP_TAG_KEYWORD ||
+ strcmp(attr->values[0].string.text, "none"))
+ {
+ respond_unsupported(client, attr);
+ }
+ else
+ fprintf(stderr, "%s Print-Job compression=\"%s\"\n",
+ client->http.hostname, attr->values[0].string.text);
+ }
+
+ /*
+ * Is it a format we support?
+ */
+
+ if ((attr = ippFindAttribute(client->request, "document-format",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attr->num_values != 1 || attr->value_tag != IPP_TAG_MIMETYPE)
+ {
+ respond_unsupported(client, attr);
+ }
+ else
+ {
+ format = attr->values[0].string.text;
+
+ fprintf(stderr, "%s %s document-format=\"%s\"\n",
+ client->http.hostname,
+ ippOpString(client->request->request.op.operation_id), format);
+ }
+ }
+ else
+ format = "application/octet-stream";
+
+ if (!strcmp(format, "application/octet-stream") &&
+ client->request->request.op.operation_id != IPP_VALIDATE_JOB)
+ {
+ /*
+ * Auto-type the file using the first 4 bytes of the file...
+ */
+
+ unsigned char header[4]; /* First 4 bytes of file */
+
+ memset(header, 0, sizeof(header));
+ _httpPeek(&(client->http), (char *)header, sizeof(header));
+
+ if (!memcmp(header, "%PDF", 4))
+ format = "application/pdf";
+ else if (!memcmp(header, "%!", 2))
+ format = "application/postscript";
+ else if (!memcmp(header, "\377\330\377", 3) &&
+ header[3] >= 0xe0 && header[3] <= 0xef)
+ format = "image/jpeg";
+ else if (!memcmp(header, "\211PNG", 4))
+ format = "image/png";
+
+ if (format)
+ fprintf(stderr, "%s %s Auto-typed document-format=\"%s\"\n",
+ client->http.hostname,
+ ippOpString(client->request->request.op.operation_id), format);
+
+ if (!attr)
+ ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
+ "document-format", NULL, format);
+ else
+ {
+ _cupsStrFree(attr->values[0].string.text);
+ attr->values[0].string.text = _cupsStrAlloc(format);
+ }
+ }
+
+ if ((supported = ippFindAttribute(client->printer->attrs,
+ "document-format-supported",
+ IPP_TAG_MIMETYPE)) != NULL)
+ {
+ for (i = 0; i < supported->num_values; i ++)
+ if (!_cups_strcasecmp(format, supported->values[i].string.text))
+ break;
+
+ if (i >= supported->num_values)
+ {
+ respond_unsupported(client, attr);
+ }
+ }
+
+ /*
+ * Check the various job template attributes...
+ */
+
+ if ((attr = ippFindAttribute(client->request, "copies",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attr->num_values != 1 || attr->value_tag != IPP_TAG_INTEGER ||
+ attr->values[0].integer < 1 || attr->values[0].integer > 999)
+ {
+ respond_unsupported(client, attr);
+ }
+ }
+
+ if ((attr = ippFindAttribute(client->request, "ipp-attribute-fidelity",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attr->num_values != 1 || attr->value_tag != IPP_TAG_BOOLEAN)
+ {
+ respond_unsupported(client, attr);
+ }
+ }
+
+ if ((attr = ippFindAttribute(client->request, "job-hold-until",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attr->num_values != 1 ||
+ (attr->value_tag != IPP_TAG_NAME &&
+ attr->value_tag != IPP_TAG_NAMELANG &&
+ attr->value_tag != IPP_TAG_KEYWORD) ||
+ strcmp(attr->values[0].string.text, "no-hold"))
+ {
+ respond_unsupported(client, attr);
+ }
+ }
+
+ if ((attr = ippFindAttribute(client->request, "job-name",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attr->num_values != 1 ||
+ (attr->value_tag != IPP_TAG_NAME &&
+ attr->value_tag != IPP_TAG_NAMELANG))
+ {
+ respond_unsupported(client, attr);
+ }
+ }
+
+ if ((attr = ippFindAttribute(client->request, "job-priority",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attr->num_values != 1 || attr->value_tag != IPP_TAG_INTEGER ||
+ attr->values[0].integer < 1 || attr->values[0].integer > 100)
+ {
+ respond_unsupported(client, attr);
+ }
+ }
+
+ if ((attr = ippFindAttribute(client->request, "job-sheets",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attr->num_values != 1 ||
+ (attr->value_tag != IPP_TAG_NAME &&
+ attr->value_tag != IPP_TAG_NAMELANG &&
+ attr->value_tag != IPP_TAG_KEYWORD) ||
+ strcmp(attr->values[0].string.text, "none"))
+ {
+ respond_unsupported(client, attr);
+ }
+ }
+
+ if ((attr = ippFindAttribute(client->request, "media",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attr->num_values != 1 ||
+ (attr->value_tag != IPP_TAG_NAME &&
+ attr->value_tag != IPP_TAG_NAMELANG &&
+ attr->value_tag != IPP_TAG_KEYWORD))
+ {
+ respond_unsupported(client, attr);
+ }
+ else
+ {
+ for (i = 0;
+ i < (int)(sizeof(media_supported) / sizeof(media_supported[0]));
+ i ++)
+ if (!strcmp(attr->values[0].string.text, media_supported[i]))
+ break;
+
+ if (i >= (int)(sizeof(media_supported) / sizeof(media_supported[0])))
+ {
+ respond_unsupported(client, attr);
+ }
+ }
+ }
+
+ if ((attr = ippFindAttribute(client->request, "media-col",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attr->num_values != 1 || attr->value_tag != IPP_TAG_BEGIN_COLLECTION)
+ {
+ respond_unsupported(client, attr);
+ }
+ /* TODO: check for valid media-col */
+ }
+
+ if ((attr = ippFindAttribute(client->request, "multiple-document-handling",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attr->num_values != 1 || attr->value_tag != IPP_TAG_KEYWORD ||
+ (strcmp(attr->values[0].string.text,
+ "separate-documents-uncollated-copies") &&
+ strcmp(attr->values[0].string.text,
+ "separate-documents-collated-copies")))
+ {
+ respond_unsupported(client, attr);
+ }
+ }
+
+ if ((attr = ippFindAttribute(client->request, "orientation-requested",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attr->num_values != 1 || attr->value_tag != IPP_TAG_ENUM ||
+ attr->values[0].integer < IPP_PORTRAIT ||
+ attr->values[0].integer > IPP_REVERSE_PORTRAIT)
+ {
+ respond_unsupported(client, attr);
+ }
+ }
+
+ if ((attr = ippFindAttribute(client->request, "page-ranges",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ respond_unsupported(client, attr);
+ }
+
+ if ((attr = ippFindAttribute(client->request, "print-quality",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attr->num_values != 1 || attr->value_tag != IPP_TAG_ENUM ||
+ attr->values[0].integer < IPP_QUALITY_DRAFT ||
+ attr->values[0].integer > IPP_QUALITY_HIGH)
+ {
+ respond_unsupported(client, attr);
+ }
+ }
+
+ if ((attr = ippFindAttribute(client->request, "printer-resolution",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ respond_unsupported(client, attr);
+ }
+
+ if ((attr = ippFindAttribute(client->request, "sides",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attr->num_values != 1 || attr->value_tag != IPP_TAG_KEYWORD)
+ {
+ respond_unsupported(client, attr);
+ }
+
+ if ((supported = ippFindAttribute(client->printer->attrs, "sides",
+ IPP_TAG_KEYWORD)) != NULL)
+ {
+ for (i = 0; i < supported->num_values; i ++)
+ if (!strcmp(attr->values[0].string.text,
+ supported->values[i].string.text))
+ break;
+
+ if (i >= supported->num_values)
+ {
+ respond_unsupported(client, attr);
+ }
+ }
+ else
+ {
+ respond_unsupported(client, attr);
+ }
+ }
+
+ return (valid);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/test/ipptool.c b/test/ipptool.c
new file mode 100644
index 000000000..e2bbe9f4d
--- /dev/null
+++ b/test/ipptool.c
@@ -0,0 +1,4921 @@
+/*
+ * "$Id$"
+ *
+ * ipptool command for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Parse options and do tests.
+ * compare_vars() - Compare two variables.
+ * do_tests() - Do tests as specified in the test file.
+ * expand_variables() - Expand variables in a string.
+ * expect_matches() - Return true if the tag matches the specification.
+ * get_collection() - Get a collection value from the current test file.
+ * get_filename() - Get a filename based on the current test file.
+ * get_token() - Get a token from a file.
+ * get_variable() - Get the value of a variable.
+ * iso_date() - Return an ISO 8601 date/time string for the given IPP
+ * dateTime value.
+ * password_cb() - Password callback for authenticated tests.
+ * print_attr() - Print an attribute on the screen.
+ * print_col() - Print a collection attribute on the screen.
+ * print_csv() - Print a line of CSV text.
+ * print_fatal_error() - Print a fatal error message.
+ * print_line() - Print a line of formatted or CSV text.
+ * print_test_error() - Print a test error message.
+ * print_xml_header() - Print a standard XML plist header.
+ * print_xml_string() - Print an XML string with escaping.
+ * print_xml_trailer() - Print the XML trailer with success/fail value.
+ * set_variable() - Set a variable value.
+ * timeout_cb() - Handle HTTP timeouts.
+ * usage() - Show program usage.
+ * validate_attr() - Determine whether an attribute is valid.
+ * with_value() - Test a WITH-VALUE predicate.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <cups/cups-private.h>
+#include <cups/file-private.h>
+#include <regex.h>
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif /* !O_BINARY */
+
+
+/*
+ * Types...
+ */
+
+typedef enum _cups_transfer_e /**** How to send request data ****/
+{
+ _CUPS_TRANSFER_AUTO, /* Chunk for files, length for static */
+ _CUPS_TRANSFER_CHUNKED, /* Chunk always */
+ _CUPS_TRANSFER_LENGTH /* Length always */
+} _cups_transfer_t;
+
+typedef enum _cups_output_e /**** Output mode ****/
+{
+ _CUPS_OUTPUT_QUIET, /* No output */
+ _CUPS_OUTPUT_TEST, /* Traditional CUPS test output */
+ _CUPS_OUTPUT_PLIST, /* XML plist test output */
+ _CUPS_OUTPUT_LIST, /* Tabular list output */
+ _CUPS_OUTPUT_CSV /* Comma-separated values output */
+} _cups_output_t;
+
+typedef struct _cups_expect_s /**** Expected attribute info ****/
+{
+ int optional, /* Optional attribute? */
+ not_expect; /* Don't expect attribute? */
+ char *name, /* Attribute name */
+ *of_type, /* Type name */
+ *same_count_as, /* Parallel attribute name */
+ *if_defined, /* Only required if variable defined */
+ *if_not_defined, /* Only required if variable is not defined */
+ *with_value, /* Attribute must include this value */
+ *define_match, /* Variable to define on match */
+ *define_no_match, /* Variable to define on no-match */
+ *define_value; /* Variable to define with value */
+ int with_regex, /* WITH-VALUE is a regular expression */
+ count; /* Expected count if > 0 */
+ ipp_tag_t in_group; /* IN-GROUP value */
+} _cups_expect_t;
+
+typedef struct _cups_status_s /**** Status info ****/
+{
+ ipp_status_t status; /* Expected status code */
+ char *if_defined, /* Only if variable is defined */
+ *if_not_defined; /* Only if variable is not defined */
+} _cups_status_t;
+
+typedef struct _cups_var_s /**** Variable ****/
+{
+ char *name, /* Name of variable */
+ *value; /* Value of variable */
+} _cups_var_t;
+
+typedef struct _cups_vars_s /**** Set of variables ****/
+{
+ const char *uri, /* URI for printer */
+ *filename; /* Filename */
+ char scheme[64], /* Scheme from URI */
+ userpass[256], /* Username/password from URI */
+ hostname[256], /* Hostname from URI */
+ resource[1024]; /* Resource path from URI */
+ int port; /* Port number from URI */
+ http_encryption_t encryption; /* Encryption for connection? */
+ double timeout; /* Timeout for connection */
+ int family; /* Address family */
+ cups_array_t *vars; /* Array of variables */
+} _cups_vars_t;
+
+
+/*
+ * Globals...
+ */
+
+_cups_transfer_t Transfer = _CUPS_TRANSFER_AUTO;
+ /* How to transfer requests */
+_cups_output_t Output = _CUPS_OUTPUT_LIST;
+ /* Output mode */
+int IgnoreErrors = 0, /* Ignore errors? */
+ Verbosity = 0, /* Show all attributes? */
+ Version = 11, /* Default IPP version */
+ XMLHeader = 0; /* 1 if header is written */
+char *Password = NULL; /* Password from URI */
+const char * const URIStatusStrings[] = /* URI status strings */
+{
+ "URI too large",
+ "Bad arguments to function",
+ "Bad resource in URI",
+ "Bad port number in URI",
+ "Bad hostname/address in URI",
+ "Bad username in URI",
+ "Bad scheme in URI",
+ "Bad/empty URI",
+ "OK",
+ "Missing scheme in URI",
+ "Unknown scheme in URI",
+ "Missing resource in URI"
+};
+
+
+/*
+ * Local functions...
+ */
+
+static int compare_vars(_cups_var_t *a, _cups_var_t *b);
+static int do_tests(_cups_vars_t *vars, const char *testfile);
+static void expand_variables(_cups_vars_t *vars, char *dst, const char *src,
+ size_t dstsize)
+#ifdef __GNUC__
+__attribute((nonnull(1,2,3)))
+#endif /* __GNUC__ */
+;
+static int expect_matches(_cups_expect_t *expect, ipp_tag_t value_tag);
+static ipp_t *get_collection(_cups_vars_t *vars, FILE *fp, int *linenum);
+static char *get_filename(const char *testfile, char *dst, const char *src,
+ size_t dstsize);
+static char *get_token(FILE *fp, char *buf, int buflen,
+ int *linenum);
+static char *get_variable(_cups_vars_t *vars, const char *name);
+static char *iso_date(ipp_uchar_t *date);
+static const char *password_cb(const char *prompt);
+static void print_attr(ipp_attribute_t *attr, ipp_tag_t *group);
+static void print_col(ipp_t *col);
+static void print_csv(ipp_attribute_t *attr, int num_displayed,
+ char **displayed, size_t *widths);
+static void print_fatal_error(const char *s, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 1, 2)))
+#endif /* __GNUC__ */
+;
+static void print_line(ipp_attribute_t *attr, int num_displayed,
+ char **displayed, size_t *widths);
+static void print_test_error(const char *s, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 1, 2)))
+#endif /* __GNUC__ */
+;
+static void print_xml_header(void);
+static void print_xml_string(const char *element, const char *s);
+static void print_xml_trailer(int success, const char *message);
+static void set_variable(_cups_vars_t *vars, const char *name,
+ const char *value);
+static int timeout_cb(http_t *http, void *user_data);
+static void usage(void);
+static int validate_attr(ipp_attribute_t *attr, int print);
+static int with_value(char *value, int regex, ipp_attribute_t *attr,
+ int report);
+
+
+/*
+ * 'main()' - Parse options and do tests.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ int status; /* Status of tests... */
+ char *opt, /* Current option */
+ name[1024], /* Name/value buffer */
+ *value, /* Pointer to value */
+ filename[1024], /* Real filename */
+ testname[1024]; /* Real test filename */
+ const char *testfile; /* Test file to use */
+ int interval, /* Test interval in microseconds */
+ repeat; /* Repeat count */
+ _cups_vars_t vars; /* Variables */
+ http_uri_status_t uri_status; /* URI separation status */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Global data */
+
+
+
+ /*
+ * Initialize the locale and variables...
+ */
+
+ _cupsSetLocale(argv);
+
+ memset(&vars, 0, sizeof(vars));
+ vars.family = AF_UNSPEC;
+ vars.vars = cupsArrayNew((cups_array_func_t)compare_vars, NULL);
+
+ /*
+ * We need at least:
+ *
+ * ipptool URI testfile
+ */
+
+ interval = 0;
+ repeat = 0;
+ status = 0;
+ testfile = NULL;
+
+ for (i = 1; i < argc; i ++)
+ {
+ if (argv[i][0] == '-')
+ {
+ for (opt = argv[i] + 1; *opt; opt ++)
+ {
+ switch (*opt)
+ {
+ case '4' : /* Connect using IPv4 only */
+ vars.family = AF_INET;
+ break;
+
+#ifdef AF_INET6
+ case '6' : /* Connect using IPv6 only */
+ vars.family = AF_INET6;
+ break;
+#endif /* AF_INET6 */
+
+ case 'C' : /* Enable HTTP chunking */
+ Transfer = _CUPS_TRANSFER_CHUNKED;
+ break;
+
+ case 'E' : /* Encrypt with TLS */
+#ifdef HAVE_SSL
+ vars.encryption = HTTP_ENCRYPT_REQUIRED;
+#else
+ _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
+ argv[0]);
+#endif /* HAVE_SSL */
+ break;
+
+ case 'I' : /* Ignore errors */
+ IgnoreErrors = 1;
+ break;
+
+ case 'L' : /* Disable HTTP chunking */
+ Transfer = _CUPS_TRANSFER_LENGTH;
+ break;
+
+ case 'S' : /* Encrypt with SSL */
+#ifdef HAVE_SSL
+ vars.encryption = HTTP_ENCRYPT_ALWAYS;
+#else
+ _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
+ argv[0]);
+#endif /* HAVE_SSL */
+ break;
+
+ case 'T' : /* Set timeout */
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("ipptool: Missing timeout for \"-T\"."));
+ usage();
+ }
+
+ vars.timeout = _cupsStrScand(argv[i], NULL, localeconv());
+ break;
+
+ case 'V' : /* Set IPP version */
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("ipptool: Missing version for \"-V\"."));
+ usage();
+ }
+
+ if (!strcmp(argv[i], "1.0"))
+ Version = 10;
+ else if (!strcmp(argv[i], "1.1"))
+ Version = 11;
+ else if (!strcmp(argv[i], "2.0"))
+ Version = 20;
+ else if (!strcmp(argv[i], "2.1"))
+ Version = 21;
+ else if (!strcmp(argv[i], "2.2"))
+ Version = 22;
+ else
+ {
+ _cupsLangPrintf(stderr,
+ _("ipptool: Bad version %s for \"-V\"."),
+ argv[i]);
+ usage();
+ }
+ break;
+
+ case 'X' : /* Produce XML output */
+ Output = _CUPS_OUTPUT_PLIST;
+
+ if (interval || repeat)
+ {
+ _cupsLangPuts(stderr, _("ipptool: \"-i\" and \"-n\" are "
+ "incompatible with -X\"."));
+ usage();
+ }
+ break;
+
+ case 'c' : /* CSV output */
+ Output = _CUPS_OUTPUT_CSV;
+ break;
+
+ case 'd' : /* Define a variable */
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("ipptool: Missing name=value for \"-d\"."));
+ usage();
+ }
+
+ strlcpy(name, argv[i], sizeof(name));
+ if ((value = strchr(name, '=')) != NULL)
+ *value++ = '\0';
+ else
+ value = name + strlen(name);
+
+ set_variable(&vars, name, value);
+ break;
+
+ case 'f' : /* Set the default test filename */
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("ipptool: Missing filename for \"-f\"."));
+ usage();
+ }
+
+ if (access(argv[i], 0) && argv[i][0] != '/')
+ {
+ snprintf(filename, sizeof(filename), "%s/ipptool/%s",
+ cg->cups_datadir, argv[i]);
+ if (access(argv[i], 0))
+ vars.filename = argv[i];
+ else
+ vars.filename = filename;
+ }
+ else
+ vars.filename = argv[i];
+ break;
+
+ case 'i' : /* Test every N seconds */
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("ipptool: Missing seconds for \"-i\"."));
+ usage();
+ }
+ else
+ {
+ interval = (int)(_cupsStrScand(argv[i], NULL, localeconv()) *
+ 1000000.0);
+ if (interval <= 0)
+ {
+ _cupsLangPuts(stderr,
+ _("ipptool: Invalid seconds for \"-i\"."));
+ usage();
+ }
+ }
+
+ if (Output == _CUPS_OUTPUT_PLIST && interval)
+ {
+ _cupsLangPuts(stderr, _("ipptool: \"-i\" is incompatible with "
+ "\"-X\"."));
+ usage();
+ }
+ break;
+
+ case 'l' : /* List as a table */
+ Output = _CUPS_OUTPUT_LIST;
+ break;
+
+ case 'n' : /* Repeat count */
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("ipptool: Missing count for \"-n\"."));
+ usage();
+ }
+ else
+ repeat = atoi(argv[i]);
+
+ if (Output == _CUPS_OUTPUT_PLIST && repeat)
+ {
+ _cupsLangPuts(stderr, _("ipptool: \"-n\" is incompatible with "
+ "\"-X\"."));
+ usage();
+ }
+ break;
+
+ case 'q' : /* Be quiet */
+ Output = _CUPS_OUTPUT_QUIET;
+ break;
+
+ case 't' : /* CUPS test output */
+ Output = _CUPS_OUTPUT_TEST;
+ break;
+
+ case 'v' : /* Be verbose */
+ Verbosity ++;
+ break;
+
+ default :
+ _cupsLangPrintf(stderr, _("ipptool: Unknown option \"-%c\"."),
+ *opt);
+ usage();
+ break;
+ }
+ }
+ }
+ else if (!strncmp(argv[i], "ipp://", 6) || !strncmp(argv[i], "http://", 7)
+#ifdef HAVE_SSL
+ || !strncmp(argv[i], "ipps://", 7)
+ || !strncmp(argv[i], "https://", 8)
+#endif /* HAVE_SSL */
+ )
+ {
+ /*
+ * Set URI...
+ */
+
+ if (vars.uri)
+ {
+ _cupsLangPuts(stderr, _("ipptool: May only specify a single URI."));
+ usage();
+ }
+
+#ifdef HAVE_SSL
+ if (!strncmp(argv[i], "ipps://", 7) || !strncmp(argv[i], "https://", 8))
+ vars.encryption = HTTP_ENCRYPT_ALWAYS;
+#endif /* HAVE_SSL */
+
+ vars.uri = argv[i];
+ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, vars.uri,
+ vars.scheme, sizeof(vars.scheme),
+ vars.userpass, sizeof(vars.userpass),
+ vars.hostname, sizeof(vars.hostname),
+ &(vars.port),
+ vars.resource, sizeof(vars.resource));
+
+ if (uri_status != HTTP_URI_OK)
+ {
+ _cupsLangPrintf(stderr, _("ipptool: Bad URI - %s."),
+ URIStatusStrings[uri_status - HTTP_URI_OVERFLOW]);
+ return (1);
+ }
+
+ if (vars.userpass[0])
+ {
+ if ((Password = strchr(vars.userpass, ':')) != NULL)
+ *Password++ = '\0';
+
+ cupsSetUser(vars.userpass);
+ cupsSetPasswordCB(password_cb);
+ set_variable(&vars, "uriuser", vars.userpass);
+ }
+ }
+ else
+ {
+ /*
+ * Run test...
+ */
+
+ if (!vars.uri)
+ {
+ _cupsLangPuts(stderr, _("ipptool: URI required before test file."));
+ usage();
+ }
+
+ if (access(argv[i], 0) && argv[i][0] != '/')
+ {
+ snprintf(testname, sizeof(testname), "%s/ipptool/%s", cg->cups_datadir,
+ argv[i]);
+ if (access(testname, 0))
+ testfile = argv[i];
+ else
+ testfile = testname;
+ }
+ else
+ testfile = argv[i];
+
+ if (!do_tests(&vars, testfile))
+ status = 1;
+ }
+ }
+
+ if (!vars.uri || !testfile)
+ usage();
+
+ /*
+ * Loop if the interval is set...
+ */
+
+ if (Output == _CUPS_OUTPUT_PLIST)
+ print_xml_trailer(!status, NULL);
+ else if (interval > 0 && repeat > 0)
+ {
+ while (repeat > 1)
+ {
+ usleep(interval);
+ do_tests(&vars, testfile);
+ repeat --;
+ }
+ }
+ else if (interval > 0)
+ {
+ for (;;)
+ {
+ usleep(interval);
+ do_tests(&vars, testfile);
+ }
+ }
+
+ /*
+ * Exit...
+ */
+
+ return (status);
+}
+
+
+/*
+ * 'compare_vars()' - Compare two variables.
+ */
+
+static int /* O - Result of comparison */
+compare_vars(_cups_var_t *a, /* I - First variable */
+ _cups_var_t *b) /* I - Second variable */
+{
+ return (_cups_strcasecmp(a->name, b->name));
+}
+
+
+/*
+ * 'do_tests()' - Do tests as specified in the test file.
+ */
+
+static int /* 1 = success, 0 = failure */
+do_tests(_cups_vars_t *vars, /* I - Variables */
+ const char *testfile) /* I - Test file to use */
+{
+ int i, /* Looping var */
+ linenum, /* Current line number */
+ pass, /* Did we pass the test? */
+ prev_pass = 1, /* Did we pass the previous test? */
+ request_id, /* Current request ID */
+ show_header = 1, /* Show the test header? */
+ ignore_errors, /* Ignore test failures? */
+ skip_previous = 0; /* Skip on previous test failure? */
+ http_t *http = NULL; /* HTTP connection to server */
+ FILE *fp = NULL; /* Test file */
+ char resource[512], /* Resource for request */
+ token[1024], /* Token from file */
+ *tokenptr, /* Pointer into token */
+ temp[1024]; /* Temporary string */
+ ipp_t *request = NULL; /* IPP request */
+ ipp_t *response = NULL; /* IPP response */
+ char attr[128]; /* Attribute name */
+ ipp_op_t op; /* Operation */
+ ipp_tag_t group; /* Current group */
+ ipp_tag_t value; /* Current value type */
+ ipp_attribute_t *attrptr, /* Attribute pointer */
+ *found, /* Found attribute */
+ *lastcol = NULL; /* Last collection attribute */
+ char name[1024]; /* Name of test */
+ char filename[1024]; /* Filename */
+ _cups_transfer_t transfer; /* To chunk or not to chunk */
+ int version, /* IPP version number to use */
+ skip_test; /* Skip this test? */
+ int num_statuses = 0; /* Number of valid status codes */
+ _cups_status_t statuses[100], /* Valid status codes */
+ *last_status; /* Last STATUS (for predicates) */
+ int num_expects = 0; /* Number of expected attributes */
+ _cups_expect_t expects[200], /* Expected attributes */
+ *expect, /* Current expected attribute */
+ *last_expect; /* Last EXPECT (for predicates) */
+ int num_displayed = 0; /* Number of displayed attributes */
+ char *displayed[200]; /* Displayed attributes */
+ size_t widths[200]; /* Width of columns */
+
+
+ /*
+ * Open the test file...
+ */
+
+ if ((fp = fopen(testfile, "r")) == NULL)
+ {
+ print_fatal_error("Unable to open test file %s - %s", testfile,
+ strerror(errno));
+ pass = 0;
+ goto test_exit;
+ }
+
+ /*
+ * Connect to the server...
+ */
+
+ if ((http = _httpCreate(vars->hostname, vars->port, NULL, vars->encryption,
+ vars->family)) == NULL)
+ {
+ print_fatal_error("Unable to connect to %s on port %d - %s", vars->hostname,
+ vars->port, strerror(errno));
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (httpReconnect(http))
+ {
+ print_fatal_error("Unable to connect to %s on port %d - %s", vars->hostname,
+ vars->port, strerror(errno));
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (vars->timeout > 0.0)
+ httpSetTimeout(http, vars->timeout, timeout_cb, NULL);
+
+ /*
+ * Loop on tests...
+ */
+
+ CUPS_SRAND(time(NULL));
+
+ pass = 1;
+ linenum = 1;
+ request_id = (CUPS_RAND() % 1000) * 137 + 1;
+
+ while (get_token(fp, token, sizeof(token), &linenum) != NULL)
+ {
+ /*
+ * Expect an open brace...
+ */
+
+ if (!strcmp(token, "DEFINE"))
+ {
+ /*
+ * DEFINE name value
+ */
+
+ if (get_token(fp, attr, sizeof(attr), &linenum) &&
+ get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ expand_variables(vars, token, temp, sizeof(token));
+ set_variable(vars, attr, token);
+ }
+ else
+ {
+ print_fatal_error("Missing DEFINE name and/or value on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ continue;
+ }
+ else if (!strcmp(token, "DEFINE-DEFAULT"))
+ {
+ /*
+ * DEFINE-DEFAULT name value
+ */
+
+ if (get_token(fp, attr, sizeof(attr), &linenum) &&
+ get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ expand_variables(vars, token, temp, sizeof(token));
+ if (!get_variable(vars, attr))
+ set_variable(vars, attr, token);
+ }
+ else
+ {
+ print_fatal_error("Missing DEFINE-DEFAULT name and/or value on line "
+ "%d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ continue;
+ }
+ else if (!strcmp(token, "IGNORE-ERRORS"))
+ {
+ /*
+ * IGNORE-ERRORS yes
+ * IGNORE-ERRORS no
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum) &&
+ (!_cups_strcasecmp(temp, "yes") || !_cups_strcasecmp(temp, "no")))
+ {
+ IgnoreErrors = !_cups_strcasecmp(temp, "yes");
+ }
+ else
+ {
+ print_fatal_error("Missing IGNORE-ERRORS value on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ continue;
+ }
+ else if (!strcmp(token, "INCLUDE"))
+ {
+ /*
+ * INCLUDE "filename"
+ * INCLUDE <filename>
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ /*
+ * Map the filename to and then run the tests...
+ */
+
+ if (!do_tests(vars, get_filename(testfile, filename, temp,
+ sizeof(filename))))
+ {
+ pass = 0;
+
+ if (!IgnoreErrors)
+ goto test_exit;
+ }
+ }
+ else
+ {
+ print_fatal_error("Missing INCLUDE filename on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ show_header = 1;
+ continue;
+ }
+ else if (!strcmp(token, "INCLUDE-IF-DEFINED"))
+ {
+ /*
+ * INCLUDE-IF-DEFINED name "filename"
+ * INCLUDE-IF-DEFINED name <filename>
+ */
+
+ if (get_token(fp, attr, sizeof(attr), &linenum) &&
+ get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ /*
+ * Map the filename to and then run the tests...
+ */
+
+ if (get_variable(vars, attr) &&
+ !do_tests(vars, get_filename(testfile, filename, temp,
+ sizeof(filename))))
+ {
+ pass = 0;
+
+ if (!IgnoreErrors)
+ goto test_exit;
+ }
+ }
+ else
+ {
+ print_fatal_error("Missing INCLUDE-IF-DEFINED name or filename on line "
+ "%d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ show_header = 1;
+ continue;
+ }
+ else if (!strcmp(token, "INCLUDE-IF-NOT-DEFINED"))
+ {
+ /*
+ * INCLUDE-IF-NOT-DEFINED name "filename"
+ * INCLUDE-IF-NOT-DEFINED name <filename>
+ */
+
+ if (get_token(fp, attr, sizeof(attr), &linenum) &&
+ get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ /*
+ * Map the filename to and then run the tests...
+ */
+
+ if (!get_variable(vars, attr) &&
+ !do_tests(vars, get_filename(testfile, filename, temp,
+ sizeof(filename))))
+ {
+ pass = 0;
+
+ if (!IgnoreErrors)
+ goto test_exit;
+ }
+ }
+ else
+ {
+ print_fatal_error("Missing INCLUDE-IF-NOT-DEFINED name or filename on "
+ "line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ show_header = 1;
+ continue;
+ }
+ else if (!strcmp(token, "SKIP-IF-DEFINED"))
+ {
+ /*
+ * SKIP-IF-DEFINED variable
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (get_variable(vars, temp))
+ goto test_exit;
+ }
+ else
+ {
+ print_fatal_error("Missing SKIP-IF-DEFINED variable on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!strcmp(token, "SKIP-IF-NOT-DEFINED"))
+ {
+ /*
+ * SKIP-IF-NOT-DEFINED variable
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (!get_variable(vars, temp))
+ goto test_exit;
+ }
+ else
+ {
+ print_fatal_error("Missing SKIP-IF-NOT-DEFINED variable on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!strcmp(token, "TRANSFER"))
+ {
+ /*
+ * TRANSFER auto
+ * TRANSFER chunked
+ * TRANSFER length
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (!strcmp(temp, "auto"))
+ Transfer = _CUPS_TRANSFER_AUTO;
+ else if (!strcmp(temp, "chunked"))
+ Transfer = _CUPS_TRANSFER_CHUNKED;
+ else if (!strcmp(temp, "length"))
+ Transfer = _CUPS_TRANSFER_LENGTH;
+ else
+ {
+ print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp,
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else
+ {
+ print_fatal_error("Missing TRANSFER value on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ continue;
+ }
+ else if (!strcmp(token, "VERSION"))
+ {
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (!strcmp(temp, "1.0"))
+ Version = 10;
+ else if (!strcmp(temp, "1.1"))
+ Version = 11;
+ else if (!strcmp(temp, "2.0"))
+ Version = 20;
+ else if (!strcmp(temp, "2.1"))
+ Version = 21;
+ else if (!strcmp(temp, "2.2"))
+ Version = 22;
+ else
+ {
+ print_fatal_error("Bad VERSION \"%s\" on line %d.", temp, linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else
+ {
+ print_fatal_error("Missing VERSION number on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ continue;
+ }
+ else if (strcmp(token, "{"))
+ {
+ print_fatal_error("Unexpected token %s seen on line %d.", token, linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ /*
+ * Initialize things...
+ */
+
+ if (show_header)
+ {
+ if (Output == _CUPS_OUTPUT_PLIST)
+ print_xml_header();
+ else if (Output == _CUPS_OUTPUT_TEST)
+ printf("\"%s\":\n", testfile);
+
+ show_header = 0;
+ }
+
+ strlcpy(resource, vars->resource, sizeof(resource));
+
+ request_id ++;
+ request = ippNew();
+ op = (ipp_op_t)0;
+ group = IPP_TAG_ZERO;
+ ignore_errors = IgnoreErrors;
+ last_expect = NULL;
+ last_status = NULL;
+ filename[0] = '\0';
+ skip_test = 0;
+ version = Version;
+ transfer = Transfer;
+
+ strlcpy(name, testfile, sizeof(name));
+ if (strrchr(name, '.') != NULL)
+ *strrchr(name, '.') = '\0';
+
+ /*
+ * Parse until we see a close brace...
+ */
+
+ while (get_token(fp, token, sizeof(token), &linenum) != NULL)
+ {
+ if (_cups_strcasecmp(token, "COUNT") &&
+ _cups_strcasecmp(token, "DEFINE-MATCH") &&
+ _cups_strcasecmp(token, "DEFINE-NO-MATCH") &&
+ _cups_strcasecmp(token, "DEFINE-VALUE") &&
+ _cups_strcasecmp(token, "IF-DEFINED") &&
+ _cups_strcasecmp(token, "IF-NOT-DEFINED") &&
+ _cups_strcasecmp(token, "IN-GROUP") &&
+ _cups_strcasecmp(token, "OF-TYPE") &&
+ _cups_strcasecmp(token, "SAME-COUNT-AS") &&
+ _cups_strcasecmp(token, "WITH-VALUE"))
+ last_expect = NULL;
+
+ if (_cups_strcasecmp(token, "IF-DEFINED") &&
+ _cups_strcasecmp(token, "IF-NOT-DEFINED"))
+ last_status = NULL;
+
+ if (!strcmp(token, "}"))
+ break;
+ else if (!strcmp(token, "{") && lastcol)
+ {
+ /*
+ * Another collection value
+ */
+
+ ipp_t *col = get_collection(vars, fp, &linenum);
+ /* Collection value */
+
+ if (col)
+ {
+ ipp_attribute_t *tempcol; /* Pointer to new buffer */
+
+
+ /*
+ * Reallocate memory...
+ */
+
+ if ((tempcol = realloc(lastcol, sizeof(ipp_attribute_t) +
+ (lastcol->num_values + 1) *
+ sizeof(ipp_value_t))) == NULL)
+ {
+ print_fatal_error("Unable to allocate memory on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (tempcol != lastcol)
+ {
+ /*
+ * Reset pointers in the list...
+ */
+
+ if (request->prev)
+ request->prev->next = tempcol;
+ else
+ request->attrs = tempcol;
+
+ lastcol = request->current = request->last = tempcol;
+ }
+
+ lastcol->values[lastcol->num_values].collection = col;
+ lastcol->num_values ++;
+ }
+ else
+ {
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!strcmp(token, "DEFINE"))
+ {
+ /*
+ * DEFINE name value
+ */
+
+ if (get_token(fp, attr, sizeof(attr), &linenum) &&
+ get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ expand_variables(vars, token, temp, sizeof(token));
+ set_variable(vars, attr, token);
+ }
+ else
+ {
+ print_fatal_error("Missing DEFINE name and/or value on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!strcmp(token, "IGNORE-ERRORS"))
+ {
+ /*
+ * IGNORE-ERRORS yes
+ * IGNORE-ERRORS no
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum) &&
+ (!_cups_strcasecmp(temp, "yes") || !_cups_strcasecmp(temp, "no")))
+ {
+ ignore_errors = !_cups_strcasecmp(temp, "yes");
+ }
+ else
+ {
+ print_fatal_error("Missing IGNORE-ERRORS value on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ continue;
+ }
+ else if (!_cups_strcasecmp(token, "NAME"))
+ {
+ /*
+ * Name of test...
+ */
+
+ get_token(fp, name, sizeof(name), &linenum);
+ }
+ else if (!strcmp(token, "REQUEST-ID"))
+ {
+ /*
+ * REQUEST-ID #
+ * REQUEST-ID random
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (isdigit(temp[0] & 255))
+ request_id = atoi(temp);
+ else if (!_cups_strcasecmp(temp, "random"))
+ request_id = (CUPS_RAND() % 1000) * 137 + 1;
+ else
+ {
+ print_fatal_error("Bad REQUEST-ID value \"%s\" on line %d.", temp,
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else
+ {
+ print_fatal_error("Missing REQUEST-ID value on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!strcmp(token, "SKIP-IF-DEFINED"))
+ {
+ /*
+ * SKIP-IF-DEFINED variable
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (get_variable(vars, temp))
+ skip_test = 1;
+ }
+ else
+ {
+ print_fatal_error("Missing SKIP-IF-DEFINED value on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!strcmp(token, "SKIP-IF-NOT-DEFINED"))
+ {
+ /*
+ * SKIP-IF-NOT-DEFINED variable
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (!get_variable(vars, temp))
+ skip_test = 1;
+ }
+ else
+ {
+ print_fatal_error("Missing SKIP-IF-NOT-DEFINED value on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!strcmp(token, "SKIP-PREVIOUS-ERROR"))
+ {
+ /*
+ * SKIP-PREVIOUS-ERROR yes
+ * SKIP-PREVIOUS-ERROR no
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum) &&
+ (!_cups_strcasecmp(temp, "yes") || !_cups_strcasecmp(temp, "no")))
+ {
+ skip_previous = !_cups_strcasecmp(temp, "yes");
+ }
+ else
+ {
+ print_fatal_error("Missing SKIP-PREVIOUS-ERROR value on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ continue;
+ }
+ else if (!strcmp(token, "TRANSFER"))
+ {
+ /*
+ * TRANSFER auto
+ * TRANSFER chunked
+ * TRANSFER length
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (!strcmp(temp, "auto"))
+ transfer = _CUPS_TRANSFER_AUTO;
+ else if (!strcmp(temp, "chunked"))
+ transfer = _CUPS_TRANSFER_CHUNKED;
+ else if (!strcmp(temp, "length"))
+ transfer = _CUPS_TRANSFER_LENGTH;
+ else
+ {
+ print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp,
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else
+ {
+ print_fatal_error("Missing TRANSFER value on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "VERSION"))
+ {
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (!strcmp(temp, "0.0"))
+ version = 0;
+ else if (!strcmp(temp, "1.0"))
+ version = 10;
+ else if (!strcmp(temp, "1.1"))
+ version = 11;
+ else if (!strcmp(temp, "2.0"))
+ version = 20;
+ else if (!strcmp(temp, "2.1"))
+ version = 21;
+ else if (!strcmp(temp, "2.2"))
+ version = 22;
+ else
+ {
+ print_fatal_error("Bad VERSION \"%s\" on line %d.", temp, linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else
+ {
+ print_fatal_error("Missing VERSION number on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "RESOURCE"))
+ {
+ /*
+ * Resource name...
+ */
+
+ if (!get_token(fp, resource, sizeof(resource), &linenum))
+ {
+ print_fatal_error("Missing RESOURCE path on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "OPERATION"))
+ {
+ /*
+ * Operation...
+ */
+
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing OPERATION code on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if ((op = ippOpValue(token)) == (ipp_op_t)-1 &&
+ (op = strtol(token, NULL, 0)) == 0)
+ {
+ print_fatal_error("Bad OPERATION code \"%s\" on line %d.", token,
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "GROUP"))
+ {
+ /*
+ * Attribute group...
+ */
+
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing GROUP tag on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if ((value = ippTagValue(token)) < 0)
+ {
+ print_fatal_error("Bad GROUP tag \"%s\" on line %d.", token, linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (value == group)
+ ippAddSeparator(request);
+
+ group = value;
+ }
+ else if (!_cups_strcasecmp(token, "DELAY"))
+ {
+ /*
+ * Delay before operation...
+ */
+
+ double delay;
+
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing DELAY value on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if ((delay = _cupsStrScand(token, NULL, localeconv())) <= 0.0)
+ {
+ print_fatal_error("Bad DELAY value \"%s\" on line %d.", token,
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ else
+ {
+ if (Output == _CUPS_OUTPUT_TEST)
+ printf(" [%g second delay]\n", delay);
+
+ usleep((int)(1000000.0 * delay));
+ }
+ }
+ else if (!_cups_strcasecmp(token, "ATTR"))
+ {
+ /*
+ * Attribute...
+ */
+
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing ATTR value tag on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if ((value = ippTagValue(token)) == IPP_TAG_ZERO)
+ {
+ print_fatal_error("Bad ATTR value tag \"%s\" on line %d.", token,
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (!get_token(fp, attr, sizeof(attr), &linenum))
+ {
+ print_fatal_error("Missing ATTR name on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (!get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ print_fatal_error("Missing ATTR value on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ expand_variables(vars, token, temp, sizeof(token));
+
+ switch (value)
+ {
+ case IPP_TAG_BOOLEAN :
+ if (!_cups_strcasecmp(token, "true"))
+ ippAddBoolean(request, group, attr, 1);
+ else
+ ippAddBoolean(request, group, attr, atoi(token));
+ break;
+
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ if (!strchr(token, ','))
+ ippAddInteger(request, group, value, attr,
+ strtol(token, &tokenptr, 0));
+ else
+ {
+ int values[100], /* Values */
+ num_values = 1; /* Number of values */
+
+ values[0] = strtol(token, &tokenptr, 10);
+ while (tokenptr && *tokenptr &&
+ num_values < (int)(sizeof(values) / sizeof(values[0])))
+ {
+ if (*tokenptr == ',')
+ tokenptr ++;
+ else if (!isdigit(*tokenptr & 255) && *tokenptr != '-')
+ break;
+
+ values[num_values] = strtol(tokenptr, &tokenptr, 0);
+ num_values ++;
+ }
+
+ ippAddIntegers(request, group, value, attr, num_values, values);
+ }
+
+ if (!tokenptr || *tokenptr)
+ {
+ print_fatal_error("Bad %s value \"%s\" on line %d.",
+ ippTagString(value), token, linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ {
+ int xres, /* X resolution */
+ yres; /* Y resolution */
+ char *ptr; /* Pointer into value */
+
+ xres = yres = strtol(token, (char **)&ptr, 10);
+ if (ptr > token && xres > 0)
+ {
+ if (*ptr == 'x')
+ yres = strtol(ptr + 1, (char **)&ptr, 10);
+ }
+
+ if (ptr <= token || xres <= 0 || yres <= 0 || !ptr ||
+ (_cups_strcasecmp(ptr, "dpi") && _cups_strcasecmp(ptr, "dpc") &&
+ _cups_strcasecmp(ptr, "other")))
+ {
+ print_fatal_error("Bad resolution value \"%s\" on line %d.",
+ token, linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (!_cups_strcasecmp(ptr, "dpi"))
+ ippAddResolution(request, group, attr, IPP_RES_PER_INCH,
+ xres, yres);
+ else if (!_cups_strcasecmp(ptr, "dpc"))
+ ippAddResolution(request, group, attr, IPP_RES_PER_CM,
+ xres, yres);
+ else
+ ippAddResolution(request, group, attr, (ipp_res_t)0,
+ xres, yres);
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ {
+ int lowers[4], /* Lower value */
+ uppers[4], /* Upper values */
+ num_vals; /* Number of values */
+
+
+ num_vals = sscanf(token, "%d-%d,%d-%d,%d-%d,%d-%d",
+ lowers + 0, uppers + 0,
+ lowers + 1, uppers + 1,
+ lowers + 2, uppers + 2,
+ lowers + 3, uppers + 3);
+
+ if ((num_vals & 1) || num_vals == 0)
+ {
+ print_fatal_error("Bad rangeOfInteger value \"%s\" on line "
+ "%d.", token, linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ ippAddRanges(request, group, attr, num_vals / 2, lowers,
+ uppers);
+ }
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ if (!strcmp(token, "{"))
+ {
+ ipp_t *col = get_collection(vars, fp, &linenum);
+ /* Collection value */
+
+ if (col)
+ {
+ lastcol = ippAddCollection(request, group, attr, col);
+ ippDelete(col);
+ }
+ else
+ {
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else
+ {
+ print_fatal_error("Bad ATTR collection value on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ break;
+
+ default :
+ print_fatal_error("Unsupported ATTR value tag %s on line %d.",
+ ippTagString(value), linenum);
+ pass = 0;
+ goto test_exit;
+
+ 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_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ if (!strchr(token, ','))
+ ippAddString(request, group, value, attr, NULL, token);
+ else
+ {
+ /*
+ * Multiple string values...
+ */
+
+ int num_values; /* Number of values */
+ char *values[100], /* Values */
+ *ptr; /* Pointer to next value */
+
+
+ values[0] = token;
+ num_values = 1;
+
+ for (ptr = strchr(token, ','); ptr; ptr = strchr(ptr, ','))
+ {
+ *ptr++ = '\0';
+ values[num_values] = ptr;
+ num_values ++;
+ }
+
+ ippAddStrings(request, group, value, attr, num_values,
+ NULL, (const char **)values);
+ }
+ break;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "FILE"))
+ {
+ /*
+ * File...
+ */
+
+ if (!get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ print_fatal_error("Missing FILE filename on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ expand_variables(vars, token, temp, sizeof(token));
+ get_filename(testfile, filename, token, sizeof(filename));
+ }
+ else if (!_cups_strcasecmp(token, "STATUS"))
+ {
+ /*
+ * Status...
+ */
+
+ if (num_statuses >= (int)(sizeof(statuses) / sizeof(statuses[0])))
+ {
+ print_fatal_error("Too many STATUS's on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing STATUS code on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if ((statuses[num_statuses].status = ippErrorValue(token))
+ == (ipp_status_t)-1 &&
+ (statuses[num_statuses].status = strtol(token, NULL, 0)) == 0)
+ {
+ print_fatal_error("Bad STATUS code \"%s\" on line %d.", token,
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ last_status = statuses + num_statuses;
+ num_statuses ++;
+
+ last_status->if_defined = NULL;
+ last_status->if_not_defined = NULL;
+ }
+ else if (!_cups_strcasecmp(token, "EXPECT"))
+ {
+ /*
+ * Expected attributes...
+ */
+
+ if (num_expects >= (int)(sizeof(expects) / sizeof(expects[0])))
+ {
+ print_fatal_error("Too many EXPECT's on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing EXPECT name on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ last_expect = expects + num_expects;
+ num_expects ++;
+
+ memset(last_expect, 0, sizeof(_cups_expect_t));
+
+ if (token[0] == '!')
+ {
+ last_expect->not_expect = 1;
+ last_expect->name = strdup(token + 1);
+ }
+ else if (token[0] == '?')
+ {
+ last_expect->optional = 1;
+ last_expect->name = strdup(token + 1);
+ }
+ else
+ last_expect->name = strdup(token);
+ }
+ else if (!_cups_strcasecmp(token, "COUNT"))
+ {
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing COUNT number on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if ((i = atoi(token)) <= 0)
+ {
+ print_fatal_error("Bad COUNT \"%s\" on line %d.", token, linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (last_expect)
+ last_expect->count = i;
+ else
+ {
+ print_fatal_error("COUNT without a preceding EXPECT on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "DEFINE-MATCH"))
+ {
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing DEFINE-MATCH variable on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (last_expect)
+ last_expect->define_match = strdup(token);
+ else
+ {
+ print_fatal_error("DEFINE-MATCH without a preceding EXPECT on line "
+ "%d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "DEFINE-NO-MATCH"))
+ {
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing DEFINE-NO-MATCH variable on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (last_expect)
+ last_expect->define_no_match = strdup(token);
+ else
+ {
+ print_fatal_error("DEFINE-NO-MATCH without a preceding EXPECT on "
+ "line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "DEFINE-VALUE"))
+ {
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing DEFINE-VALUE variable on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (last_expect)
+ last_expect->define_value = strdup(token);
+ else
+ {
+ print_fatal_error("DEFINE-VALUE without a preceding EXPECT on line "
+ "%d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "OF-TYPE"))
+ {
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing OF-TYPE value tag(s) on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (last_expect)
+ last_expect->of_type = strdup(token);
+ else
+ {
+ print_fatal_error("OF-TYPE without a preceding EXPECT on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "IN-GROUP"))
+ {
+ ipp_tag_t in_group; /* IN-GROUP value */
+
+
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing IN-GROUP group tag on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if ((in_group = ippTagValue(token)) == (ipp_tag_t)-1)
+ {
+ }
+ else if (last_expect)
+ last_expect->in_group = in_group;
+ else
+ {
+ print_fatal_error("IN-GROUP without a preceding EXPECT on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "SAME-COUNT-AS"))
+ {
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing SAME-COUNT-AS name on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (last_expect)
+ last_expect->same_count_as = strdup(token);
+ else
+ {
+ print_fatal_error("SAME-COUNT-AS without a preceding EXPECT on line "
+ "%d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "IF-DEFINED"))
+ {
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing IF-DEFINED name on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (last_expect)
+ last_expect->if_defined = strdup(token);
+ else if (last_status)
+ last_status->if_defined = strdup(token);
+ else
+ {
+ print_fatal_error("IF-DEFINED without a preceding EXPECT or STATUS "
+ "on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "IF-NOT-DEFINED"))
+ {
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing IF-NOT-DEFINED name on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (last_expect)
+ last_expect->if_not_defined = strdup(token);
+ else if (last_status)
+ last_status->if_not_defined = strdup(token);
+ else
+ {
+ print_fatal_error("IF-NOT-DEFINED without a preceding EXPECT or STATUS "
+ "on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "WITH-VALUE"))
+ {
+ if (!get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ print_fatal_error("Missing WITH-VALUE value on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (last_expect)
+ {
+ /*
+ * Expand any variables in the value and then save it.
+ */
+
+ expand_variables(vars, token, temp, sizeof(token));
+
+ tokenptr = token + strlen(token) - 1;
+
+ if (token[0] == '/' && tokenptr > token && *tokenptr == '/')
+ {
+ /*
+ * WITH-VALUE is a POSIX extended regular expression.
+ */
+
+ last_expect->with_value = calloc(1, tokenptr - token);
+ last_expect->with_regex = 1;
+
+ if (last_expect->with_value)
+ memcpy(last_expect->with_value, token + 1, tokenptr - token - 1);
+ }
+ else
+ {
+ /*
+ * WITH-VALUE is a literal value...
+ */
+
+ last_expect->with_value = strdup(token);
+ }
+ }
+ else
+ {
+ print_fatal_error("WITH-VALUE without a preceding EXPECT on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "DISPLAY"))
+ {
+ /*
+ * Display attributes...
+ */
+
+ if (num_displayed >= (int)(sizeof(displayed) / sizeof(displayed[0])))
+ {
+ print_fatal_error("Too many DISPLAY's on line %d", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing DISPLAY name on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ displayed[num_displayed] = strdup(token);
+ num_displayed ++;
+ }
+ else
+ {
+ print_fatal_error("Unexpected token %s seen on line %d.", token,
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+
+ /*
+ * Submit the IPP request...
+ */
+
+ request->request.op.version[0] = version / 10;
+ request->request.op.version[1] = version % 10;
+ request->request.op.operation_id = op;
+ request->request.op.request_id = request_id;
+
+ if (Output == _CUPS_OUTPUT_PLIST)
+ {
+ puts("<dict>");
+ puts("<key>Name</key>");
+ print_xml_string("string", name);
+ puts("<key>Operation</key>");
+ print_xml_string("string", ippOpString(op));
+ puts("<key>RequestAttributes</key>");
+ puts("<array>");
+ if (request->attrs)
+ {
+ puts("<dict>");
+ for (attrptr = request->attrs, group = attrptr->group_tag;
+ attrptr;
+ attrptr = attrptr->next)
+ print_attr(attrptr, &group);
+ puts("</dict>");
+ }
+ puts("</array>");
+ }
+ else if (Output == _CUPS_OUTPUT_TEST)
+ {
+ if (Verbosity)
+ {
+ printf(" %s:\n", ippOpString(op));
+
+ for (attrptr = request->attrs; attrptr; attrptr = attrptr->next)
+ print_attr(attrptr, NULL);
+ }
+
+ printf(" %-69.69s [", name);
+ fflush(stdout);
+ }
+
+ if ((skip_previous && !prev_pass) || skip_test)
+ {
+ ippDelete(request);
+ request = NULL;
+
+ if (Output == _CUPS_OUTPUT_PLIST)
+ {
+ puts("<key>Successful</key>");
+ puts("<true />");
+ puts("<key>StatusCode</key>");
+ print_xml_string("string", "skip");
+ puts("<key>ResponseAttributes</key>");
+ puts("<dict>");
+ puts("</dict>");
+ }
+ else if (Output == _CUPS_OUTPUT_TEST)
+ puts("SKIP]");
+
+ goto skip_error;
+ }
+
+ if (transfer == _CUPS_TRANSFER_CHUNKED ||
+ (transfer == _CUPS_TRANSFER_AUTO && filename[0]))
+ {
+ /*
+ * Send request using chunking...
+ */
+
+ http_status_t status = cupsSendRequest(http, request, resource, 0);
+
+ if (status == HTTP_CONTINUE && filename[0])
+ {
+ int fd; /* File to send */
+ char buffer[8192]; /* Copy buffer */
+ ssize_t bytes; /* Bytes read/written */
+
+ if ((fd = open(filename, O_RDONLY | O_BINARY)) >= 0)
+ {
+ while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
+ if ((status = cupsWriteRequestData(http, buffer,
+ bytes)) != HTTP_CONTINUE)
+ break;
+ }
+ else
+ {
+ snprintf(buffer, sizeof(buffer), "%s: %s", filename, strerror(errno));
+ _cupsSetError(IPP_INTERNAL_ERROR, buffer, 0);
+
+ status = HTTP_ERROR;
+ }
+ }
+
+ ippDelete(request);
+
+ if (status == HTTP_CONTINUE)
+ response = cupsGetResponse(http, resource);
+ else
+ response = NULL;
+ }
+ else if (filename[0])
+ response = cupsDoFileRequest(http, request, resource, filename);
+ else
+ response = cupsDoRequest(http, request, resource);
+
+ request = NULL;
+ prev_pass = 1;
+
+ if (!response)
+ prev_pass = pass = 0;
+ else
+ {
+ if (http->version != HTTP_1_1)
+ prev_pass = pass = 0;
+
+ if (response->request.status.request_id != request_id)
+ prev_pass = pass = 0;
+
+ if (version &&
+ (response->request.status.version[0] != (version / 10) ||
+ response->request.status.version[1] != (version % 10)))
+ prev_pass = pass = 0;
+
+ if ((attrptr = ippFindAttribute(response, "job-id",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ snprintf(temp, sizeof(temp), "%d", attrptr->values[0].integer);
+ set_variable(vars, "job-id", temp);
+ }
+
+ if ((attrptr = ippFindAttribute(response, "job-uri",
+ IPP_TAG_URI)) != NULL)
+ set_variable(vars, "job-uri", attrptr->values[0].string.text);
+
+ if ((attrptr = ippFindAttribute(response, "notify-subscription-id",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ snprintf(temp, sizeof(temp), "%d", attrptr->values[0].integer);
+ set_variable(vars, "notify-subscription-id", temp);
+ }
+
+ attrptr = response->attrs;
+ if (!attrptr || !attrptr->name ||
+ attrptr->value_tag != IPP_TAG_CHARSET ||
+ attrptr->group_tag != IPP_TAG_OPERATION ||
+ attrptr->num_values != 1 ||
+ strcmp(attrptr->name, "attributes-charset"))
+ prev_pass = pass = 0;
+
+ if (attrptr)
+ {
+ attrptr = attrptr->next;
+ if (!attrptr || !attrptr->name ||
+ attrptr->value_tag != IPP_TAG_LANGUAGE ||
+ attrptr->group_tag != IPP_TAG_OPERATION ||
+ attrptr->num_values != 1 ||
+ strcmp(attrptr->name, "attributes-natural-language"))
+ prev_pass = pass = 0;
+ }
+
+ if ((attrptr = ippFindAttribute(response, "status-message",
+ IPP_TAG_ZERO)) != NULL &&
+ (attrptr->value_tag != IPP_TAG_TEXT ||
+ attrptr->group_tag != IPP_TAG_OPERATION ||
+ attrptr->num_values != 1 ||
+ (attrptr->value_tag == IPP_TAG_TEXT &&
+ strlen(attrptr->values[0].string.text) > 255)))
+ prev_pass = pass = 0;
+
+ if ((attrptr = ippFindAttribute(response, "detailed-status-message",
+ IPP_TAG_ZERO)) != NULL &&
+ (attrptr->value_tag != IPP_TAG_TEXT ||
+ attrptr->group_tag != IPP_TAG_OPERATION ||
+ attrptr->num_values != 1 ||
+ (attrptr->value_tag == IPP_TAG_TEXT &&
+ strlen(attrptr->values[0].string.text) > 1023)))
+ prev_pass = pass = 0;
+
+ for (attrptr = response->attrs, group = attrptr->group_tag;
+ attrptr;
+ attrptr = attrptr->next)
+ {
+ if (attrptr->group_tag < group && attrptr->group_tag != IPP_TAG_ZERO)
+ {
+ prev_pass = pass = 0;
+ break;
+ }
+
+ if (!validate_attr(attrptr, 0))
+ {
+ prev_pass = pass = 0;
+ break;
+ }
+ }
+
+ for (i = 0; i < num_statuses; i ++)
+ {
+ if (statuses[i].if_defined &&
+ !get_variable(vars, statuses[i].if_defined))
+ continue;
+
+ if (statuses[i].if_not_defined &&
+ get_variable(vars, statuses[i].if_not_defined))
+ continue;
+
+ if (response->request.status.status_code == statuses[i].status)
+ break;
+ }
+
+ if (i == num_statuses && num_statuses > 0)
+ prev_pass = pass = 0;
+ else
+ {
+ for (i = num_expects, expect = expects; i > 0; i --, expect ++)
+ {
+ if (expect->if_defined && !get_variable(vars, expect->if_defined))
+ continue;
+
+ if (expect->if_not_defined &&
+ get_variable(vars, expect->if_not_defined))
+ continue;
+
+ found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
+
+ if ((found && expect->not_expect) ||
+ (!found && !(expect->not_expect || expect->optional)) ||
+ (found && !expect_matches(expect, found->value_tag)) ||
+ (found && expect->in_group &&
+ found->group_tag != expect->in_group))
+ {
+ if (expect->define_no_match)
+ set_variable(vars, expect->define_no_match, "1");
+ else if (!expect->define_match)
+ prev_pass = pass = 0;
+
+ continue;
+ }
+
+ if (found &&
+ !with_value(expect->with_value, expect->with_regex, found, 0))
+ {
+ if (expect->define_no_match)
+ set_variable(vars, expect->define_no_match, "1");
+ else if (!expect->define_match)
+ prev_pass = pass = 0;
+
+ continue;
+ }
+
+ if (found && expect->count > 0 && found->num_values != expect->count)
+ {
+ if (expect->define_no_match)
+ set_variable(vars, expect->define_no_match, "1");
+ else if (!expect->define_match)
+ prev_pass = pass = 0;
+
+ continue;
+ }
+
+ if (found && expect->same_count_as)
+ {
+ attrptr = ippFindAttribute(response, expect->same_count_as,
+ IPP_TAG_ZERO);
+
+ if (!attrptr || attrptr->num_values != found->num_values)
+ {
+ if (expect->define_no_match)
+ set_variable(vars, expect->define_no_match, "1");
+ else if (!expect->define_match)
+ prev_pass = pass = 0;
+
+ continue;
+ }
+ }
+
+ if (found && expect->define_match)
+ set_variable(vars, expect->define_match, "1");
+
+ if (found && expect->define_value)
+ {
+ _ippAttrString(found, token, sizeof(token));
+ set_variable(vars, expect->define_value, token);
+ }
+ }
+ }
+ }
+
+ if (Output == _CUPS_OUTPUT_PLIST)
+ {
+ puts("<key>Successful</key>");
+ puts(prev_pass ? "<true />" : "<false />");
+ puts("<key>StatusCode</key>");
+ print_xml_string("string", ippErrorString(cupsLastError()));
+ puts("<key>ResponseAttributes</key>");
+ puts("<array>");
+ puts("<dict>");
+ for (attrptr = response ? response->attrs : NULL,
+ group = attrptr ? attrptr->group_tag : IPP_TAG_ZERO;
+ attrptr;
+ attrptr = attrptr->next)
+ print_attr(attrptr, &group);
+ puts("</dict>");
+ puts("</array>");
+ }
+ else if (Output == _CUPS_OUTPUT_TEST)
+ {
+ puts(prev_pass ? "PASS]" : "FAIL]");
+
+ if (Verbosity && response)
+ {
+ printf(" RECEIVED: %lu bytes in response\n",
+ (unsigned long)ippLength(response));
+ printf(" status-code = %x (%s)\n", cupsLastError(),
+ ippErrorString(cupsLastError()));
+
+ for (attrptr = response->attrs;
+ attrptr != NULL;
+ attrptr = attrptr->next)
+ {
+ print_attr(attrptr, NULL);
+ }
+ }
+ }
+ else if (!prev_pass)
+ fprintf(stderr, "%s\n", cupsLastErrorString());
+
+ if (prev_pass && Output != _CUPS_OUTPUT_PLIST &&
+ Output != _CUPS_OUTPUT_QUIET && !Verbosity && num_displayed > 0)
+ {
+ if (Output >= _CUPS_OUTPUT_LIST)
+ {
+ size_t width; /* Length of value */
+
+
+ for (i = 0; i < num_displayed; i ++)
+ {
+ widths[i] = strlen(displayed[i]);
+
+ for (attrptr = ippFindAttribute(response, displayed[i], IPP_TAG_ZERO);
+ attrptr;
+ attrptr = ippFindNextAttribute(response, displayed[i],
+ IPP_TAG_ZERO))
+ {
+ width = _ippAttrString(attrptr, NULL, 0);
+ if (width > widths[i])
+ widths[i] = width;
+ }
+ }
+
+ if (Output == _CUPS_OUTPUT_CSV)
+ print_csv(NULL, num_displayed, displayed, widths);
+ else
+ print_line(NULL, num_displayed, displayed, widths);
+
+ attrptr = response->attrs;
+
+ while (attrptr)
+ {
+ while (attrptr && attrptr->group_tag <= IPP_TAG_OPERATION)
+ attrptr = attrptr->next;
+
+ if (attrptr)
+ {
+ if (Output == _CUPS_OUTPUT_CSV)
+ print_csv(attrptr, num_displayed, displayed, widths);
+ else
+ print_line(attrptr, num_displayed, displayed, widths);
+
+ while (attrptr && attrptr->group_tag > IPP_TAG_OPERATION)
+ attrptr = attrptr->next;
+ }
+ }
+ }
+ else
+ {
+ for (attrptr = response->attrs;
+ attrptr != NULL;
+ attrptr = attrptr->next)
+ {
+ if (attrptr->name)
+ {
+ for (i = 0; i < num_displayed; i ++)
+ {
+ if (!strcmp(displayed[i], attrptr->name))
+ {
+ print_attr(attrptr, NULL);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (!prev_pass)
+ {
+ if (Output == _CUPS_OUTPUT_PLIST)
+ {
+ puts("<key>Errors</key>");
+ puts("<array>");
+ }
+
+ if (http->version != HTTP_1_1)
+ print_test_error("Bad HTTP version (%d.%d)", http->version / 100,
+ http->version % 100);
+
+ if (!response)
+ print_test_error("IPP request failed with status %s (%s)",
+ ippErrorString(cupsLastError()),
+ cupsLastErrorString());
+ else
+ {
+ if (version &&
+ (response->request.status.version[0] != (version / 10) ||
+ response->request.status.version[1] != (version % 10)))
+ print_test_error("Bad version %d.%d in response - expected %d.%d "
+ "(RFC 2911 section 3.1.8).",
+ response->request.status.version[0],
+ response->request.status.version[1],
+ version / 10, version % 10);
+
+ if (response->request.status.request_id != request_id)
+ print_test_error("Bad request ID %d in response - expected %d "
+ "(RFC 2911 section 3.1.1)",
+ response->request.status.request_id, request_id);
+
+ attrptr = response->attrs;
+ if (!attrptr)
+ print_test_error("Missing first attribute \"attributes-charset "
+ "(charset)\" in group operation-attributes-tag "
+ "(RFC 2911 section 3.1.4).");
+ else
+ {
+ if (!attrptr->name ||
+ attrptr->value_tag != IPP_TAG_CHARSET ||
+ attrptr->group_tag != IPP_TAG_OPERATION ||
+ attrptr->num_values != 1 ||
+ strcmp(attrptr->name, "attributes-charset"))
+ print_test_error("Bad first attribute \"%s (%s%s)\" in group %s, "
+ "expected \"attributes-charset (charset)\" in "
+ "group operation-attributes-tag (RFC 2911 section "
+ "3.1.4).",
+ attrptr->name ? attrptr->name : "(null)",
+ attrptr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attrptr->value_tag),
+ ippTagString(attrptr->group_tag));
+
+ attrptr = attrptr->next;
+ if (!attrptr)
+ print_test_error("Missing second attribute \"attributes-natural-"
+ "language (naturalLanguage)\" in group "
+ "operation-attributes-tag (RFC 2911 section "
+ "3.1.4).");
+ else if (!attrptr->name ||
+ attrptr->value_tag != IPP_TAG_LANGUAGE ||
+ attrptr->group_tag != IPP_TAG_OPERATION ||
+ attrptr->num_values != 1 ||
+ strcmp(attrptr->name, "attributes-natural-language"))
+ print_test_error("Bad first attribute \"%s (%s%s)\" in group %s, "
+ "expected \"attributes-natural-language "
+ "(naturalLanguage)\" in group "
+ "operation-attributes-tag (RFC 2911 section "
+ "3.1.4).",
+ attrptr->name ? attrptr->name : "(null)",
+ attrptr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attrptr->value_tag),
+ ippTagString(attrptr->group_tag));
+ }
+
+ if ((attrptr = ippFindAttribute(response, "status-message",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attrptr->value_tag != IPP_TAG_TEXT)
+ print_test_error("status-message (text(255)) has wrong value tag "
+ "%s (RFC 2911 section 3.1.6.2).",
+ ippTagString(attrptr->value_tag));
+ if (attrptr->group_tag != IPP_TAG_OPERATION)
+ print_test_error("status-message (text(255)) has wrong group tag "
+ "%s (RFC 2911 section 3.1.6.2).",
+ ippTagString(attrptr->group_tag));
+ if (attrptr->num_values != 1)
+ print_test_error("status-message (text(255)) has %d values "
+ "(RFC 2911 section 3.1.6.2).",
+ attrptr->num_values);
+ if (attrptr->value_tag == IPP_TAG_TEXT &&
+ strlen(attrptr->values[0].string.text) > 255)
+ print_test_error("status-message (text(255)) has bad length %d"
+ " (RFC 2911 section 3.1.6.2).",
+ (int)strlen(attrptr->values[0].string.text));
+ }
+
+ if ((attrptr = ippFindAttribute(response, "detailed-status-message",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (attrptr->value_tag != IPP_TAG_TEXT)
+ print_test_error("detailed-status-message (text(MAX)) has wrong "
+ "value tag %s (RFC 2911 section 3.1.6.3).",
+ ippTagString(attrptr->value_tag));
+ if (attrptr->group_tag != IPP_TAG_OPERATION)
+ print_test_error("detailed-status-message (text(MAX)) has wrong "
+ "group tag %s (RFC 2911 section 3.1.6.3).",
+ ippTagString(attrptr->group_tag));
+ if (attrptr->num_values != 1)
+ print_test_error("detailed-status-message (text(MAX)) has %d values"
+ " (RFC 2911 section 3.1.6.3).",
+ attrptr->num_values);
+ if (attrptr->value_tag == IPP_TAG_TEXT &&
+ strlen(attrptr->values[0].string.text) > 1023)
+ print_test_error("detailed-status-message (text(MAX)) has bad "
+ "length %d (RFC 2911 section 3.1.6.3).",
+ (int)strlen(attrptr->values[0].string.text));
+ }
+
+ for (attrptr = response->attrs, group = attrptr->group_tag;
+ attrptr;
+ attrptr = attrptr->next)
+ {
+ if (attrptr->group_tag < group && attrptr->group_tag != IPP_TAG_ZERO)
+ print_test_error("Attribute groups out of order (%s < %s)",
+ ippTagString(attrptr->group_tag),
+ ippTagString(group));
+
+ validate_attr(attrptr, 1);
+ }
+
+ for (i = 0; i < num_statuses; i ++)
+ {
+ if (statuses[i].if_defined &&
+ !get_variable(vars, statuses[i].if_defined))
+ continue;
+
+ if (statuses[i].if_not_defined &&
+ get_variable(vars, statuses[i].if_not_defined))
+ continue;
+
+ if (response->request.status.status_code == statuses[i].status)
+ break;
+ }
+
+ if (i == num_statuses && num_statuses > 0)
+ {
+ for (i = 0; i < num_statuses; i ++)
+ {
+ if (statuses[i].if_defined &&
+ !get_variable(vars, statuses[i].if_defined))
+ continue;
+
+ if (statuses[i].if_not_defined &&
+ get_variable(vars, statuses[i].if_not_defined))
+ continue;
+
+ print_test_error("EXPECTED: STATUS %s (got %s)",
+ ippErrorString(statuses[i].status),
+ ippErrorString(cupsLastError()));
+ }
+
+ if ((attrptr = ippFindAttribute(response, "status-message",
+ IPP_TAG_TEXT)) != NULL)
+ print_test_error("status-message=\"%s\"",
+ attrptr->values[0].string.text);
+ }
+
+ for (i = num_expects, expect = expects; i > 0; i --, expect ++)
+ {
+ if (expect->define_match || expect->define_no_match)
+ continue;
+
+ if (expect->if_defined && !get_variable(vars, expect->if_defined))
+ continue;
+
+ if (expect->if_not_defined &&
+ get_variable(vars, expect->if_not_defined))
+ continue;
+
+ found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
+
+ if (found && expect->not_expect)
+ print_test_error("NOT EXPECTED: %s", expect->name);
+ else if (!found && !(expect->not_expect || expect->optional))
+ print_test_error("EXPECTED: %s", expect->name);
+ else if (found)
+ {
+ if (!expect_matches(expect, found->value_tag))
+ print_test_error("EXPECTED: %s OF-TYPE %s (got %s)",
+ expect->name, expect->of_type,
+ ippTagString(found->value_tag));
+
+ if (expect->in_group && found->group_tag != expect->in_group)
+ print_test_error("EXPECTED: %s IN-GROUP %s (got %s).",
+ expect->name, ippTagString(expect->in_group),
+ ippTagString(found->group_tag));
+
+ if (!with_value(expect->with_value, expect->with_regex, found, 0))
+ {
+ if (expect->with_regex)
+ print_test_error("EXPECTED: %s WITH-VALUE /%s/",
+ expect->name, expect->with_value);
+ else
+ print_test_error("EXPECTED: %s WITH-VALUE \"%s\"",
+ expect->name, expect->with_value);
+
+ with_value(expect->with_value, expect->with_regex, found, 1);
+ }
+
+ if (expect->count > 0 && found->num_values != expect->count)
+ {
+ print_test_error("EXPECTED: %s COUNT %d (got %d)", expect->name,
+ expect->count, found->num_values);
+ }
+
+ if (expect->same_count_as)
+ {
+ attrptr = ippFindAttribute(response, expect->same_count_as,
+ IPP_TAG_ZERO);
+
+ if (!attrptr)
+ print_test_error("EXPECTED: %s (%d values) SAME-COUNT-AS %s "
+ "(not returned)", expect->name,
+ found->num_values, expect->same_count_as);
+ else if (attrptr->num_values != found->num_values)
+ print_test_error("EXPECTED: %s (%d values) SAME-COUNT-AS %s "
+ "(%d values)", expect->name, found->num_values,
+ expect->same_count_as, attrptr->num_values);
+ }
+ }
+ }
+ }
+
+ if (Output == _CUPS_OUTPUT_PLIST)
+ puts("</array>");
+ }
+
+ if (Output == _CUPS_OUTPUT_PLIST)
+ puts("</dict>");
+
+ skip_error:
+
+ ippDelete(response);
+ response = NULL;
+
+ for (i = 0; i < num_statuses; i ++)
+ {
+ if (statuses[i].if_defined)
+ free(statuses[i].if_defined);
+ if (statuses[i].if_not_defined)
+ free(statuses[i].if_not_defined);
+ }
+ num_statuses = 0;
+
+ for (i = num_expects, expect = expects; i > 0; i --, expect ++)
+ {
+ free(expect->name);
+ if (expect->of_type)
+ free(expect->of_type);
+ if (expect->same_count_as)
+ free(expect->same_count_as);
+ if (expect->if_defined)
+ free(expect->if_defined);
+ if (expect->if_not_defined)
+ free(expect->if_not_defined);
+ if (expect->with_value)
+ free(expect->with_value);
+ if (expect->define_match)
+ free(expect->define_match);
+ if (expect->define_no_match)
+ free(expect->define_no_match);
+ if (expect->define_value)
+ free(expect->define_value);
+ }
+ num_expects = 0;
+
+ for (i = 0; i < num_displayed; i ++)
+ free(displayed[i]);
+ num_displayed = 0;
+
+ if (!ignore_errors && !prev_pass)
+ break;
+ }
+
+ test_exit:
+
+ if (fp)
+ fclose(fp);
+
+ httpClose(http);
+ ippDelete(request);
+ ippDelete(response);
+
+ for (i = 0; i < num_statuses; i ++)
+ {
+ if (statuses[i].if_defined)
+ free(statuses[i].if_defined);
+ if (statuses[i].if_not_defined)
+ free(statuses[i].if_not_defined);
+ }
+
+ for (i = num_expects, expect = expects; i > 0; i --, expect ++)
+ {
+ free(expect->name);
+ if (expect->of_type)
+ free(expect->of_type);
+ if (expect->same_count_as)
+ free(expect->same_count_as);
+ if (expect->if_defined)
+ free(expect->if_defined);
+ if (expect->if_not_defined)
+ free(expect->if_not_defined);
+ if (expect->with_value)
+ free(expect->with_value);
+ if (expect->define_match)
+ free(expect->define_match);
+ if (expect->define_no_match)
+ free(expect->define_no_match);
+ if (expect->define_value)
+ free(expect->define_value);
+ }
+
+ for (i = 0; i < num_displayed; i ++)
+ free(displayed[i]);
+
+ return (pass);
+}
+
+
+/*
+ * 'expand_variables()' - Expand variables in a string.
+ */
+
+static void
+expand_variables(_cups_vars_t *vars, /* I - Variables */
+ char *dst, /* I - Destination string buffer */
+ const char *src, /* I - Source string */
+ size_t dstsize) /* I - Size of destination buffer */
+{
+ char *dstptr, /* Pointer into destination */
+ *dstend, /* End of destination */
+ temp[256], /* Temporary string */
+ *tempptr; /* Pointer into temporary string */
+ const char *value; /* Value to substitute */
+
+
+ dstptr = dst;
+ dstend = dst + dstsize - 1;
+
+ while (*src && dstptr < dstend)
+ {
+ if (*src == '$')
+ {
+ /*
+ * Substitute a string/number...
+ */
+
+ if (!strncmp(src, "$$", 2))
+ {
+ value = "$";
+ src += 2;
+ }
+ else if (!strncmp(src, "$ENV[", 5))
+ {
+ strlcpy(temp, src + 5, sizeof(temp));
+
+ for (tempptr = temp; *tempptr; tempptr ++)
+ if (*tempptr == ']')
+ break;
+
+ if (*tempptr)
+ *tempptr++ = '\0';
+
+ value = getenv(temp);
+ src += tempptr - temp + 5;
+ }
+ else if (vars)
+ {
+ strlcpy(temp, src + 1, sizeof(temp));
+
+ for (tempptr = temp; *tempptr; tempptr ++)
+ if (!isalnum(*tempptr & 255) && *tempptr != '-' && *tempptr != '_')
+ break;
+
+ if (*tempptr)
+ *tempptr = '\0';
+
+ if (!strcmp(temp, "uri"))
+ value = vars->uri;
+ else if (!strcmp(temp, "filename"))
+ value = vars->filename;
+ else if (!strcmp(temp, "scheme") || !strcmp(temp, "method"))
+ value = vars->scheme;
+ else if (!strcmp(temp, "username"))
+ value = vars->userpass;
+ else if (!strcmp(temp, "hostname"))
+ value = vars->hostname;
+ else if (!strcmp(temp, "port"))
+ {
+ snprintf(temp, sizeof(temp), "%d", vars->port);
+ value = temp;
+ }
+ else if (!strcmp(temp, "resource"))
+ value = vars->resource;
+ else if (!strcmp(temp, "user"))
+ value = cupsUser();
+ else
+ value = get_variable(vars, temp);
+
+ src += tempptr - temp + 1;
+ }
+ else
+ {
+ value = "$";
+ src ++;
+ }
+
+ if (value)
+ {
+ strlcpy(dstptr, value, dstend - dstptr + 1);
+ dstptr += strlen(dstptr);
+ }
+ }
+ else
+ *dstptr++ = *src++;
+ }
+
+ *dstptr = '\0';
+}
+
+
+/*
+ * 'expect_matches()' - Return true if the tag matches the specification.
+ */
+
+static int /* O - 1 if matches, 0 otherwise */
+expect_matches(
+ _cups_expect_t *expect, /* I - Expected attribute */
+ ipp_tag_t value_tag) /* I - Value tag for attribute */
+{
+ int match; /* Match? */
+ char *of_type, /* Type name to match */
+ *next, /* Next name to match */
+ sep; /* Separator character */
+
+
+ /*
+ * If we don't expect a particular type, return immediately...
+ */
+
+ if (!expect->of_type)
+ return (1);
+
+ /*
+ * Parse the "of_type" value since the string can contain multiple attribute
+ * types separated by "," or "|"...
+ */
+
+ for (of_type = expect->of_type, match = 0; !match && *of_type; of_type = next)
+ {
+ /*
+ * Find the next separator, and set it (temporarily) to nul if present.
+ */
+
+ for (next = of_type; *next && *next != '|' && *next != ','; next ++);
+
+ if ((sep = *next) != '\0')
+ *next = '\0';
+
+ /*
+ * Support some meta-types to make it easier to write the test file.
+ */
+
+ if (!strcmp(of_type, "text"))
+ match = value_tag == IPP_TAG_TEXTLANG || value_tag == IPP_TAG_TEXT;
+ else if (!strcmp(of_type, "name"))
+ match = value_tag == IPP_TAG_NAMELANG || value_tag == IPP_TAG_NAME;
+ else if (!strcmp(of_type, "collection"))
+ match = value_tag == IPP_TAG_BEGIN_COLLECTION;
+ else
+ match = value_tag == ippTagValue(of_type);
+
+ /*
+ * Restore the separator if we have one...
+ */
+
+ if (sep)
+ *next++ = sep;
+ }
+
+ return (match);
+}
+
+
+/*
+ * 'get_collection()' - Get a collection value from the current test file.
+ */
+
+static ipp_t * /* O - Collection value */
+get_collection(_cups_vars_t *vars, /* I - Variables */
+ FILE *fp, /* I - File to read from */
+ int *linenum) /* IO - Line number */
+{
+ char token[1024], /* Token from file */
+ temp[1024], /* Temporary string */
+ attr[128]; /* Attribute name */
+ ipp_tag_t value; /* Current value type */
+ ipp_t *col = ippNew(); /* Collection value */
+ ipp_attribute_t *lastcol = NULL; /* Last collection attribute */
+
+
+ while (get_token(fp, token, sizeof(token), linenum) != NULL)
+ {
+ if (!strcmp(token, "}"))
+ break;
+ else if (!strcmp(token, "{") && lastcol)
+ {
+ /*
+ * Another collection value
+ */
+
+ ipp_t *subcol = get_collection(vars, fp, linenum);
+ /* Collection value */
+
+ if (subcol)
+ {
+ ipp_attribute_t *tempcol; /* Pointer to new buffer */
+
+
+ /*
+ * Reallocate memory...
+ */
+
+ if ((tempcol = realloc(lastcol, sizeof(ipp_attribute_t) +
+ (lastcol->num_values + 1) *
+ sizeof(ipp_value_t))) == NULL)
+ {
+ print_fatal_error("Unable to allocate memory on line %d.", *linenum);
+ goto col_error;
+ }
+
+ if (tempcol != lastcol)
+ {
+ /*
+ * Reset pointers in the list...
+ */
+
+ if (col->prev)
+ col->prev->next = tempcol;
+ else
+ col->attrs = tempcol;
+
+ lastcol = col->current = col->last = tempcol;
+ }
+
+ lastcol->values[lastcol->num_values].collection = subcol;
+ lastcol->num_values ++;
+ }
+ else
+ goto col_error;
+ }
+ else if (!_cups_strcasecmp(token, "MEMBER"))
+ {
+ /*
+ * Attribute...
+ */
+
+ lastcol = NULL;
+
+ if (!get_token(fp, token, sizeof(token), linenum))
+ {
+ print_fatal_error("Missing MEMBER value tag on line %d.", *linenum);
+ goto col_error;
+ }
+
+ if ((value = ippTagValue(token)) == IPP_TAG_ZERO)
+ {
+ print_fatal_error("Bad MEMBER value tag \"%s\" on line %d.", token,
+ *linenum);
+ goto col_error;
+ }
+
+ if (!get_token(fp, attr, sizeof(attr), linenum))
+ {
+ print_fatal_error("Missing MEMBER name on line %d.", *linenum);
+ goto col_error;
+ }
+
+ if (!get_token(fp, temp, sizeof(temp), linenum))
+ {
+ print_fatal_error("Missing MEMBER value on line %d.", *linenum);
+ goto col_error;
+ }
+
+ expand_variables(vars, token, temp, sizeof(token));
+
+ switch (value)
+ {
+ case IPP_TAG_BOOLEAN :
+ if (!_cups_strcasecmp(token, "true"))
+ ippAddBoolean(col, IPP_TAG_ZERO, attr, 1);
+ else
+ ippAddBoolean(col, IPP_TAG_ZERO, attr, atoi(token));
+ break;
+
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ ippAddInteger(col, IPP_TAG_ZERO, value, attr, atoi(token));
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ {
+ int xres, /* X resolution */
+ yres; /* Y resolution */
+ char units[6]; /* Units */
+
+ if (sscanf(token, "%dx%d%5s", &xres, &yres, units) != 3 ||
+ (_cups_strcasecmp(units, "dpi") && _cups_strcasecmp(units, "dpc") &&
+ _cups_strcasecmp(units, "other")))
+ {
+ print_fatal_error("Bad resolution value \"%s\" on line %d.",
+ token, *linenum);
+ goto col_error;
+ }
+
+ if (!_cups_strcasecmp(units, "dpi"))
+ ippAddResolution(col, IPP_TAG_ZERO, attr, xres, yres,
+ IPP_RES_PER_INCH);
+ else if (!_cups_strcasecmp(units, "dpc"))
+ ippAddResolution(col, IPP_TAG_ZERO, attr, xres, yres,
+ IPP_RES_PER_CM);
+ else
+ ippAddResolution(col, IPP_TAG_ZERO, attr, xres, yres,
+ (ipp_res_t)0);
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ {
+ int lowers[4], /* Lower value */
+ uppers[4], /* Upper values */
+ num_vals; /* Number of values */
+
+
+ num_vals = sscanf(token, "%d-%d,%d-%d,%d-%d,%d-%d",
+ lowers + 0, uppers + 0,
+ lowers + 1, uppers + 1,
+ lowers + 2, uppers + 2,
+ lowers + 3, uppers + 3);
+
+ if ((num_vals & 1) || num_vals == 0)
+ {
+ print_fatal_error("Bad rangeOfInteger value \"%s\" on line %d.",
+ token, *linenum);
+ goto col_error;
+ }
+
+ ippAddRanges(col, IPP_TAG_ZERO, attr, num_vals / 2, lowers,
+ uppers);
+ }
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ if (!strcmp(token, "{"))
+ {
+ ipp_t *subcol = get_collection(vars, fp, linenum);
+ /* Collection value */
+
+ if (subcol)
+ {
+ lastcol = ippAddCollection(col, IPP_TAG_ZERO, attr, subcol);
+ ippDelete(subcol);
+ }
+ else
+ goto col_error;
+ }
+ else
+ {
+ print_fatal_error("Bad collection value on line %d.", *linenum);
+ goto col_error;
+ }
+ break;
+
+ default :
+ if (!strchr(token, ','))
+ ippAddString(col, IPP_TAG_ZERO, value, attr, NULL, token);
+ else
+ {
+ /*
+ * Multiple string values...
+ */
+
+ int num_values; /* Number of values */
+ char *values[100], /* Values */
+ *ptr; /* Pointer to next value */
+
+
+ values[0] = token;
+ num_values = 1;
+
+ for (ptr = strchr(token, ','); ptr; ptr = strchr(ptr, ','))
+ {
+ *ptr++ = '\0';
+ values[num_values] = ptr;
+ num_values ++;
+ }
+
+ ippAddStrings(col, IPP_TAG_ZERO, value, attr, num_values,
+ NULL, (const char **)values);
+ }
+ break;
+ }
+ }
+ }
+
+ return (col);
+
+ /*
+ * If we get here there was a parse error; free memory and return.
+ */
+
+ col_error:
+
+ ippDelete(col);
+
+ return (NULL);
+}
+
+
+/*
+ * 'get_filename()' - Get a filename based on the current test file.
+ */
+
+static char * /* O - Filename */
+get_filename(const char *testfile, /* I - Current test file */
+ char *dst, /* I - Destination filename */
+ const char *src, /* I - Source filename */
+ size_t dstsize) /* I - Size of destination buffer */
+{
+ char *dstptr; /* Pointer into destination */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Global data */
+
+
+ if (*src == '<' && src[strlen(src) - 1] == '>')
+ {
+ /*
+ * Map <filename> to CUPS_DATADIR/ipptool/filename...
+ */
+
+ snprintf(dst, dstsize, "%s/ipptool/%s", cg->cups_datadir, src + 1);
+ dstptr = dst + strlen(dst) - 1;
+ if (*dstptr == '>')
+ *dstptr = '\0';
+ }
+ else if (*src == '/' || !strchr(testfile, '/'))
+ {
+ /*
+ * Use the path as-is...
+ */
+
+ strlcpy(dst, src, dstsize);
+ }
+ else
+ {
+ /*
+ * Make path relative to testfile...
+ */
+
+ strlcpy(dst, testfile, dstsize);
+ if ((dstptr = strrchr(dst, '/')) != NULL)
+ dstptr ++;
+ else
+ dstptr = dst; /* Should never happen */
+
+ strlcpy(dstptr, src, dstsize - (dstptr - dst));
+ }
+
+ return (dst);
+}
+
+
+/*
+ * 'get_token()' - Get a token from a file.
+ */
+
+static char * /* O - Token from file or NULL on EOF */
+get_token(FILE *fp, /* I - File to read from */
+ char *buf, /* I - Buffer to read into */
+ int buflen, /* I - Length of buffer */
+ int *linenum) /* IO - Current line number */
+{
+ int ch, /* Character from file */
+ quote; /* Quoting character */
+ char *bufptr, /* Pointer into buffer */
+ *bufend; /* End of buffer */
+
+
+ for (;;)
+ {
+ /*
+ * Skip whitespace...
+ */
+
+ while (isspace(ch = getc(fp)))
+ {
+ if (ch == '\n')
+ (*linenum) ++;
+ }
+
+ /*
+ * Read a token...
+ */
+
+ if (ch == EOF)
+ return (NULL);
+ else if (ch == '\'' || ch == '\"')
+ {
+ /*
+ * Quoted text or regular expression...
+ */
+
+ quote = ch;
+ bufptr = buf;
+ bufend = buf + buflen - 1;
+
+ while ((ch = getc(fp)) != EOF)
+ {
+ if (ch == '\\')
+ {
+ /*
+ * Escape next character...
+ */
+
+ if (bufptr < bufend)
+ *bufptr++ = ch;
+
+ if ((ch = getc(fp)) != EOF && bufptr < bufend)
+ *bufptr++ = ch;
+ }
+ else if (ch == quote)
+ break;
+ else if (bufptr < bufend)
+ *bufptr++ = ch;
+ }
+
+ *bufptr = '\0';
+
+ return (buf);
+ }
+ else if (ch == '#')
+ {
+ /*
+ * Comment...
+ */
+
+ while ((ch = getc(fp)) != EOF)
+ if (ch == '\n')
+ break;
+
+ (*linenum) ++;
+ }
+ else
+ {
+ /*
+ * Whitespace delimited text...
+ */
+
+ ungetc(ch, fp);
+
+ bufptr = buf;
+ bufend = buf + buflen - 1;
+
+ while ((ch = getc(fp)) != EOF)
+ if (isspace(ch) || ch == '#')
+ break;
+ else if (bufptr < bufend)
+ *bufptr++ = ch;
+
+ if (ch == '#')
+ ungetc(ch, fp);
+ else if (ch == '\n')
+ (*linenum) ++;
+
+ *bufptr = '\0';
+
+ return (buf);
+ }
+ }
+}
+
+
+/*
+ * 'get_variable()' - Get the value of a variable.
+ */
+
+static char * /* O - Value or NULL */
+get_variable(_cups_vars_t *vars, /* I - Variables */
+ const char *name) /* I - Variable name */
+{
+ _cups_var_t key, /* Search key */
+ *match; /* Matching variable, if any */
+
+
+ key.name = (char *)name;
+ match = cupsArrayFind(vars->vars, &key);
+
+ return (match ? match->value : NULL);
+}
+
+
+/*
+ * 'iso_date()' - Return an ISO 8601 date/time string for the given IPP dateTime
+ * value.
+ */
+
+static char * /* O - ISO 8601 date/time string */
+iso_date(ipp_uchar_t *date) /* I - IPP (RFC 1903) date/time value */
+{
+ unsigned year = (date[0] << 8) + date[1];
+ /* Year */
+ static char buffer[255]; /* String buffer */
+
+
+ if (date[9] == 0 && date[10] == 0)
+ snprintf(buffer, sizeof(buffer), "%04u-%02u-%02uT%02u:%02u:%02uZ",
+ year, date[2], date[3], date[4], date[5], date[6]);
+ else
+ snprintf(buffer, sizeof(buffer), "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u",
+ year, date[2], date[3], date[4], date[5], date[6],
+ date[8], date[9], date[10]);
+
+ return (buffer);
+}
+
+
+/*
+ * 'password_cb()' - Password callback for authenticated tests.
+ */
+
+static const char * /* O - Password */
+password_cb(const char *prompt) /* I - Prompt (unused) */
+{
+ (void)prompt;
+
+ return (Password);
+}
+
+
+/*
+ * 'print_attr()' - Print an attribute on the screen.
+ */
+
+static void
+print_attr(ipp_attribute_t *attr, /* I - Attribute to print */
+ ipp_tag_t *group) /* IO - Current group */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *colattr; /* Collection attribute */
+
+
+ if (Output == _CUPS_OUTPUT_PLIST)
+ {
+ if (!attr->name || (group && *group != attr->group_tag))
+ {
+ puts("</dict>");
+ puts("<dict>");
+
+ if (group)
+ *group = attr->group_tag;
+ }
+
+ if (!attr->name)
+ return;
+
+ print_xml_string("key", attr->name);
+ if (attr->num_values > 1)
+ puts("<array>");
+ }
+ else if (Output == _CUPS_OUTPUT_TEST)
+ {
+ if (!attr->name)
+ {
+ puts(" -- separator --");
+ return;
+ }
+
+ printf(" %s (%s%s) = ", attr->name,
+ attr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attr->value_tag));
+ }
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ for (i = 0; i < attr->num_values; i ++)
+ if (Output == _CUPS_OUTPUT_PLIST)
+ printf("<integer>%d</integer>\n", attr->values[i].integer);
+ else
+ printf("%d ", attr->values[i].integer);
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ for (i = 0; i < attr->num_values; i ++)
+ if (Output == _CUPS_OUTPUT_PLIST)
+ puts(attr->values[i].boolean ? "<true />" : "<false />");
+ else if (attr->values[i].boolean)
+ fputs("true ", stdout);
+ else
+ fputs("false ", stdout);
+ break;
+
+ case IPP_TAG_RANGE :
+ for (i = 0; i < attr->num_values; i ++)
+ if (Output == _CUPS_OUTPUT_PLIST)
+ printf("<dict><key>lower</key><integer>%d</integer>"
+ "<key>upper</key><integer>%d</integer></dict>\n",
+ attr->values[i].range.lower, attr->values[i].range.upper);
+ else
+ printf("%d-%d ", attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ for (i = 0; i < attr->num_values; i ++)
+ if (Output == _CUPS_OUTPUT_PLIST)
+ printf("<dict><key>xres</key><integer>%d</integer>"
+ "<key>yres</key><integer>%d</integer>"
+ "<key>units</key><string>%s</string></dict>\n",
+ attr->values[i].resolution.xres,
+ attr->values[i].resolution.yres,
+ attr->values[i].resolution.units == IPP_RES_PER_INCH ?
+ "dpi" : "dpc");
+ else
+ printf("%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_DATE :
+ for (i = 0; i < attr->num_values; i ++)
+ if (Output == _CUPS_OUTPUT_PLIST)
+ printf("<date>%s</date>\n", iso_date(attr->values[i].date));
+ else
+ printf("%s ", iso_date(attr->values[i].date));
+ break;
+
+ case IPP_TAG_STRING :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_URI :
+ case IPP_TAG_MIMETYPE :
+ case IPP_TAG_LANGUAGE :
+ for (i = 0; i < attr->num_values; i ++)
+ if (Output == _CUPS_OUTPUT_PLIST)
+ print_xml_string("string", attr->values[i].string.text);
+ else
+ printf("\"%s\" ", attr->values[i].string.text);
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ for (i = 0; i < attr->num_values; i ++)
+ if (Output == _CUPS_OUTPUT_PLIST)
+ {
+ fputs("<dict><key>language</key><string>", stdout);
+ print_xml_string(NULL, attr->values[i].string.charset);
+ fputs("</string><key>string</key><string>", stdout);
+ print_xml_string(NULL, attr->values[i].string.text);
+ puts("</string></dict>");
+ }
+ else
+ printf("\"%s\"(%s) ", attr->values[i].string.text,
+ attr->values[i].string.charset);
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (Output == _CUPS_OUTPUT_PLIST)
+ {
+ puts("<dict>");
+ for (colattr = attr->values[i].collection->attrs;
+ colattr;
+ colattr = colattr->next)
+ print_attr(colattr, NULL);
+ puts("</dict>");
+ }
+ else
+ {
+ if (i)
+ putchar(' ');
+
+ print_col(attr->values[i].collection);
+ }
+ }
+ break;
+
+ default :
+ if (Output == _CUPS_OUTPUT_PLIST)
+ printf("<string>&lt;&lt;%s&gt;&gt;</string>\n",
+ ippTagString(attr->value_tag));
+ else
+ fputs(ippTagString(attr->value_tag), stdout);
+ break;
+ }
+
+ if (Output == _CUPS_OUTPUT_PLIST)
+ {
+ if (attr->num_values > 1)
+ puts("</array>");
+ }
+ else
+ putchar('\n');
+}
+
+
+/*
+ * 'print_col()' - Print a collection attribute on the screen.
+ */
+
+static void
+print_col(ipp_t *col) /* I - Collection attribute to print */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *attr; /* Current attribute in collection */
+
+
+ fputs("{ ", stdout);
+ for (attr = col->attrs; attr; attr = attr->next)
+ {
+ printf("%s (%s%s) = ", attr->name, attr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attr->value_tag));
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ for (i = 0; i < attr->num_values; i ++)
+ printf("%d ", attr->values[i].integer);
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ for (i = 0; i < attr->num_values; i ++)
+ if (attr->values[i].boolean)
+ printf("true ");
+ else
+ printf("false ");
+ break;
+
+ case IPP_TAG_NOVALUE :
+ printf("novalue");
+ break;
+
+ case IPP_TAG_RANGE :
+ for (i = 0; i < attr->num_values; i ++)
+ printf("%d-%d ", attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ for (i = 0; i < attr->num_values; i ++)
+ printf("%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_STRING :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_URI :
+ case IPP_TAG_MIMETYPE :
+ case IPP_TAG_LANGUAGE :
+ for (i = 0; i < attr->num_values; i ++)
+ printf("\"%s\" ", attr->values[i].string.text);
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ for (i = 0; i < attr->num_values; i ++)
+ printf("\"%s\",%s ", attr->values[i].string.text,
+ attr->values[i].string.charset);
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ print_col(attr->values[i].collection);
+ putchar(' ');
+ }
+ break;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+ }
+
+ putchar('}');
+}
+
+
+/*
+ * 'print_csv()' - Print a line of CSV text.
+ */
+
+static void
+print_csv(
+ ipp_attribute_t *attr, /* I - First attribute for line */
+ int num_displayed, /* I - Number of attributes to display */
+ char **displayed, /* I - Attributes to display */
+ size_t *widths) /* I - Column widths */
+{
+ int i; /* Looping var */
+ size_t maxlength; /* Max length of all columns */
+ char *buffer, /* String buffer */
+ *bufptr; /* Pointer into buffer */
+ ipp_attribute_t *current; /* Current attribute */
+
+
+ /*
+ * Get the maximum string length we have to show and allocate...
+ */
+
+ for (i = 1, maxlength = widths[0]; i < num_displayed; i ++)
+ if (widths[i] > maxlength)
+ maxlength = widths[i];
+
+ maxlength += 2;
+
+ if ((buffer = malloc(maxlength)) == NULL)
+ return;
+
+ /*
+ * Loop through the attributes to display...
+ */
+
+ if (attr)
+ {
+ for (i = 0; i < num_displayed; i ++)
+ {
+ if (i)
+ putchar(',');
+
+ buffer[0] = '\0';
+
+ for (current = attr; current; current = current->next)
+ {
+ if (!current->name)
+ break;
+ else if (!strcmp(current->name, displayed[i]))
+ {
+ _ippAttrString(current, buffer, maxlength);
+ break;
+ }
+ }
+
+ if (strchr(buffer, ',') != NULL || strchr(buffer, '\"') != NULL ||
+ strchr(buffer, '\\') != NULL)
+ {
+ putchar('\"');
+ for (bufptr = buffer; *bufptr; bufptr ++)
+ {
+ if (*bufptr == '\\' || *bufptr == '\"')
+ putchar('\\');
+ putchar(*bufptr);
+ }
+ putchar('\"');
+ }
+ else
+ fputs(buffer, stdout);
+ }
+ putchar('\n');
+ }
+ else
+ {
+ for (i = 0; i < num_displayed; i ++)
+ {
+ if (i)
+ putchar(',');
+
+ fputs(displayed[i], stdout);
+ }
+ putchar('\n');
+ }
+
+ free(buffer);
+}
+
+
+/*
+ * 'print_fatal_error()' - Print a fatal error message.
+ */
+
+static void
+print_fatal_error(const char *s, /* I - Printf-style format string */
+ ...) /* I - Additional arguments as needed */
+{
+ char buffer[10240]; /* Format buffer */
+ va_list ap; /* Pointer to arguments */
+
+
+ /*
+ * Format the error message...
+ */
+
+ va_start(ap, s);
+ vsnprintf(buffer, sizeof(buffer), s, ap);
+ va_end(ap);
+
+ /*
+ * Then output it...
+ */
+
+ if (Output == _CUPS_OUTPUT_PLIST)
+ {
+ print_xml_header();
+ print_xml_trailer(0, buffer);
+ }
+ else
+ _cupsLangPrintf(stderr, "ipptool: %s", buffer);
+}
+
+
+/*
+ * 'print_line()' - Print a line of formatted or CSV text.
+ */
+
+static void
+print_line(
+ ipp_attribute_t *attr, /* I - First attribute for line */
+ int num_displayed, /* I - Number of attributes to display */
+ char **displayed, /* I - Attributes to display */
+ size_t *widths) /* I - Column widths */
+{
+ int i; /* Looping var */
+ size_t maxlength; /* Max length of all columns */
+ char *buffer; /* String buffer */
+ ipp_attribute_t *current; /* Current attribute */
+
+
+ /*
+ * Get the maximum string length we have to show and allocate...
+ */
+
+ for (i = 1, maxlength = widths[0]; i < num_displayed; i ++)
+ if (widths[i] > maxlength)
+ maxlength = widths[i];
+
+ maxlength += 2;
+
+ if ((buffer = malloc(maxlength)) == NULL)
+ return;
+
+ /*
+ * Loop through the attributes to display...
+ */
+
+ if (attr)
+ {
+ for (i = 0; i < num_displayed; i ++)
+ {
+ if (i)
+ putchar(' ');
+
+ buffer[0] = '\0';
+
+ for (current = attr; current; current = current->next)
+ {
+ if (!current->name)
+ break;
+ else if (!strcmp(current->name, displayed[i]))
+ {
+ _ippAttrString(current, buffer, maxlength);
+ break;
+ }
+ }
+
+ printf("%*s", (int)-widths[i], buffer);
+ }
+ putchar('\n');
+ }
+ else
+ {
+ for (i = 0; i < num_displayed; i ++)
+ {
+ if (i)
+ putchar(' ');
+
+ printf("%*s", (int)-widths[i], displayed[i]);
+ }
+ putchar('\n');
+
+ for (i = 0; i < num_displayed; i ++)
+ {
+ if (i)
+ putchar(' ');
+
+ memset(buffer, '-', widths[i]);
+ buffer[widths[i]] = '\0';
+ fputs(buffer, stdout);
+ }
+ putchar('\n');
+ }
+
+ free(buffer);
+}
+
+
+/*
+ * 'print_test_error()' - Print a test error message.
+ */
+
+static void
+print_test_error(const char *s, /* I - Printf-style format string */
+ ...) /* I - Additional arguments as needed */
+{
+ char buffer[10240]; /* Format buffer */
+ va_list ap; /* Pointer to arguments */
+
+
+ /*
+ * Format the error message...
+ */
+
+ va_start(ap, s);
+ vsnprintf(buffer, sizeof(buffer), s, ap);
+ va_end(ap);
+
+ /*
+ * Then output it...
+ */
+
+ if (Output == _CUPS_OUTPUT_PLIST)
+ print_xml_string("string", buffer);
+ else
+ printf(" %s\n", buffer);
+}
+
+
+/*
+ * 'print_xml_header()' - Print a standard XML plist header.
+ */
+
+static void
+print_xml_header(void)
+{
+ if (!XMLHeader)
+ {
+ puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ puts("<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
+ puts("<plist version=\"1.0\">");
+ puts("<dict>");
+ puts("<key>Transfer</key>");
+ printf("<string>%s</string>\n",
+ Transfer == _CUPS_TRANSFER_AUTO ? "auto" :
+ Transfer == _CUPS_TRANSFER_CHUNKED ? "chunked" : "length");
+ puts("<key>Tests</key>");
+ puts("<array>");
+
+ XMLHeader = 1;
+ }
+}
+
+
+/*
+ * 'print_xml_string()' - Print an XML string with escaping.
+ */
+
+static void
+print_xml_string(const char *element, /* I - Element name or NULL */
+ const char *s) /* I - String to print */
+{
+ if (element)
+ printf("<%s>", element);
+
+ while (*s)
+ {
+ if (*s == '&')
+ fputs("&amp;", stdout);
+ else if (*s == '<')
+ fputs("&lt;", stdout);
+ else if (*s == '>')
+ fputs("&gt;", stdout);
+ else
+ putchar(*s);
+
+ s ++;
+ }
+
+ if (element)
+ printf("</%s>\n", element);
+}
+
+
+/*
+ * 'print_xml_trailer()' - Print the XML trailer with success/fail value.
+ */
+
+static void
+print_xml_trailer(int success, /* I - 1 on success, 0 on failure */
+ const char *message) /* I - Error message or NULL */
+{
+ if (XMLHeader)
+ {
+ puts("</array>");
+ puts("<key>Successful</key>");
+ puts(success ? "<true />" : "<false />");
+ if (message)
+ {
+ puts("<key>ErrorMessage</key>");
+ print_xml_string("string", message);
+ }
+ puts("</dict>");
+ puts("</plist>");
+
+ XMLHeader = 0;
+ }
+}
+
+
+/*
+ * 'set_variable()' - Set a variable value.
+ */
+
+static void
+set_variable(_cups_vars_t *vars, /* I - Variables */
+ const char *name, /* I - Variable name */
+ const char *value) /* I - Value string */
+{
+ _cups_var_t key, /* Search key */
+ *var; /* New variable */
+
+
+ key.name = (char *)name;
+ if ((var = cupsArrayFind(vars->vars, &key)) != NULL)
+ {
+ free(var->value);
+ var->value = strdup(value);
+ }
+ else if ((var = malloc(sizeof(_cups_var_t))) == NULL)
+ {
+ print_fatal_error("Unable to allocate memory for variable \"%s\".", name);
+ exit(1);
+ }
+ else
+ {
+ var->name = strdup(name);
+ var->value = strdup(value);
+
+ cupsArrayAdd(vars->vars, var);
+ }
+}
+
+
+/*
+ * 'timeout_cb()' - Handle HTTP timeouts.
+ */
+
+static int /* O - 1 to continue, 0 to cancel */
+timeout_cb(http_t *http, /* I - Connection to server (unused) */
+ void *user_data) /* I - User data (unused) */
+{
+ (void)http;
+ (void)user_data;
+
+ return (0);
+}
+
+
+/*
+ * 'usage()' - Show program usage.
+ */
+
+static void
+usage(void)
+{
+ _cupsLangPuts(stderr, _("Usage: ipptool [options] URI filename [ ... "
+ "filenameN ]"));
+ _cupsLangPuts(stderr, _("Options:"));
+ _cupsLangPuts(stderr, _(" -4 Connect using IPv4."));
+ _cupsLangPuts(stderr, _(" -6 Connect using IPv6."));
+ _cupsLangPuts(stderr, _(" -C Send requests using "
+ "chunking (default)."));
+ _cupsLangPuts(stderr, _(" -E Test with TLS "
+ "encryption."));
+ _cupsLangPuts(stderr, _(" -I Ignore errors."));
+ _cupsLangPuts(stderr, _(" -L Send requests using "
+ "content-length."));
+ _cupsLangPuts(stderr, _(" -S Test with SSL "
+ "encryption."));
+ _cupsLangPuts(stderr, _(" -T Set the receive/send "
+ "timeout in seconds."));
+ _cupsLangPuts(stderr, _(" -V version Set default IPP "
+ "version."));
+ _cupsLangPuts(stderr, _(" -X Produce XML plist instead "
+ "of plain text."));
+ _cupsLangPuts(stderr, _(" -d name=value Set named variable to "
+ "value."));
+ _cupsLangPuts(stderr, _(" -f filename Set default request "
+ "filename."));
+ _cupsLangPuts(stderr, _(" -i seconds Repeat the last file with "
+ "the given time interval."));
+ _cupsLangPuts(stderr, _(" -n count Repeat the last file the "
+ "given number of times."));
+ _cupsLangPuts(stderr, _(" -q Be quiet - no output "
+ "except errors."));
+ _cupsLangPuts(stderr, _(" -t Produce a test report."));
+ _cupsLangPuts(stderr, _(" -v Show all attributes sent "
+ "and received."));
+
+ exit(1);
+}
+
+
+/*
+ * 'validate_attr()' - Determine whether an attribute is valid.
+ */
+
+static int /* O - 1 if valid, 0 otherwise */
+validate_attr(ipp_attribute_t *attr, /* I - Attribute to validate */
+ int print) /* I - 1 = report issues to stdout */
+{
+ int i; /* Looping var */
+ char scheme[64], /* Scheme from URI */
+ userpass[256], /* Username/password from URI */
+ hostname[256], /* Hostname from URI */
+ resource[1024]; /* Resource from URI */
+ int port, /* Port number from URI */
+ uri_status, /* URI separation status */
+ valid = 1; /* Is the attribute valid? */
+ const char *ptr; /* Pointer into string */
+ ipp_attribute_t *colattr; /* Collection attribute */
+ regex_t re; /* Regular expression */
+ ipp_uchar_t *date; /* Current date value */
+
+
+ /*
+ * Skip separators.
+ */
+
+ if (!attr->name)
+ return (1);
+
+ /*
+ * Validate the attribute name.
+ */
+
+ for (ptr = attr->name; *ptr; ptr ++)
+ if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' && *ptr != '_')
+ break;
+
+ if (*ptr || ptr == attr->name)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad attribute name - invalid character (RFC "
+ "2911 section 4.1.3).", attr->name);
+ }
+
+ if ((ptr - attr->name) > 255)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad attribute name - bad length (RFC 2911 "
+ "section 4.1.3).", attr->name);
+ }
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (attr->values[i].boolean != 0 &&
+ attr->values[i].boolean != 1)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad boolen value %d (RFC 2911 section "
+ "4.1.10).", attr->name, attr->values[i].boolean);
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_ENUM :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (attr->values[i].integer < 1)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad enum value %d - out of range "
+ "(RFC 2911 section 4.1.4).", attr->name,
+ attr->values[i].integer);
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_STRING :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (attr->values[i].unknown.length > 1023)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad octetString value - bad length %d "
+ "(RFC 2911 section 4.1.10).", attr->name,
+ attr->values[i].unknown.length);
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_DATE :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ date = attr->values[i].date;
+
+ if (date[2] < 1 || date[2] > 12)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime month %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[2]);
+ else
+ break;
+ }
+
+ if (date[3] < 1 || date[3] > 31)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime day %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[3]);
+ else
+ break;
+ }
+
+ if (date[4] > 23)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime hours %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[4]);
+ else
+ break;
+ }
+
+ if (date[5] > 59)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime minutes %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[5]);
+ else
+ break;
+ }
+
+ if (date[6] > 60)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime seconds %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[6]);
+ else
+ break;
+ }
+
+ if (date[7] > 9)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime deciseconds %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[7]);
+ else
+ break;
+ }
+
+ if (date[8] != '-' && date[8] != '+')
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime UTC sign '%c' (RFC 2911 "
+ "section 4.1.13).", attr->name, date[8]);
+ else
+ break;
+ }
+
+ if (date[9] > 11)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime UTC hours %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[9]);
+ else
+ break;
+ }
+
+ if (date[10] > 59)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad dateTime UTC minutes %u (RFC 2911 "
+ "section 4.1.13).", attr->name, date[10]);
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (attr->values[i].resolution.xres <= 0)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad resolution value %dx%d%s - cross "
+ "feed resolution must be positive (RFC 2911 "
+ "section 4.1.13).", attr->name,
+ attr->values[i].resolution.xres,
+ attr->values[i].resolution.yres,
+ attr->values[i].resolution.units ==
+ IPP_RES_PER_INCH ? "dpi" :
+ attr->values[i].resolution.units ==
+ IPP_RES_PER_CM ? "dpc" : "unknown");
+ else
+ break;
+ }
+
+ if (attr->values[i].resolution.yres <= 0)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad resolution value %dx%d%s - feed "
+ "resolution must be positive (RFC 2911 section "
+ "4.1.13).", attr->name,
+ attr->values[i].resolution.xres,
+ attr->values[i].resolution.yres,
+ attr->values[i].resolution.units ==
+ IPP_RES_PER_INCH ? "dpi" :
+ attr->values[i].resolution.units ==
+ IPP_RES_PER_CM ? "dpc" : "unknown");
+ else
+ break;
+ }
+
+ if (attr->values[i].resolution.units != IPP_RES_PER_INCH &&
+ attr->values[i].resolution.units != IPP_RES_PER_CM)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad resolution value %dx%d%s - bad "
+ "units value (RFC 2911 section 4.1.13).",
+ attr->name, attr->values[i].resolution.xres,
+ attr->values[i].resolution.yres,
+ attr->values[i].resolution.units ==
+ IPP_RES_PER_INCH ? "dpi" :
+ attr->values[i].resolution.units ==
+ IPP_RES_PER_CM ? "dpc" : "unknown");
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (attr->values[i].range.lower > attr->values[i].range.upper)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad rangeOfInteger value %d-%d - lower "
+ "greater than upper (RFC 2911 section 4.1.13).",
+ attr->name, attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ for (colattr = attr->values[i].collection->attrs;
+ colattr;
+ colattr = colattr->next)
+ {
+ if (!validate_attr(colattr, 0))
+ {
+ valid = 0;
+ break;
+ }
+ }
+
+ if (colattr && print)
+ {
+ print_test_error("\"%s\": Bad collection value.", attr->name);
+
+ while (colattr)
+ {
+ validate_attr(colattr, print);
+ colattr = colattr->next;
+ }
+ }
+ }
+ break;
+
+ case IPP_TAG_TEXT :
+ case IPP_TAG_TEXTLANG :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ for (ptr = attr->values[i].string.text; *ptr; ptr ++)
+ {
+ if ((*ptr & 0xe0) == 0xc0)
+ {
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ }
+ else if ((*ptr & 0xf0) == 0xe0)
+ {
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ }
+ else if ((*ptr & 0xf8) == 0xf0)
+ {
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ }
+ else if (*ptr & 0x80)
+ break;
+ }
+
+ if (*ptr)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad text value \"%s\" - bad UTF-8 "
+ "sequence (RFC 2911 section 4.1.1).", attr->name,
+ attr->values[i].string.text);
+ else
+ break;
+ }
+
+ if ((ptr - attr->values[i].string.text) > 1023)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad text value \"%s\" - bad length %d "
+ "(RFC 2911 section 4.1.1).", attr->name,
+ attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_NAME :
+ case IPP_TAG_NAMELANG :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ for (ptr = attr->values[i].string.text; *ptr; ptr ++)
+ {
+ if ((*ptr & 0xe0) == 0xc0)
+ {
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ }
+ else if ((*ptr & 0xf0) == 0xe0)
+ {
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ }
+ else if ((*ptr & 0xf8) == 0xf0)
+ {
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ ptr ++;
+ if ((*ptr & 0xc0) != 0x80)
+ break;
+ }
+ else if (*ptr & 0x80)
+ break;
+ }
+
+ if (*ptr)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad name value \"%s\" - bad UTF-8 "
+ "sequence (RFC 2911 section 4.1.2).", attr->name,
+ attr->values[i].string.text);
+ else
+ break;
+ }
+
+ if ((ptr - attr->values[i].string.text) > 1023)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad name value \"%s\" - bad length %d "
+ "(RFC 2911 section 4.1.2).", attr->name,
+ attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_KEYWORD :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ for (ptr = attr->values[i].string.text; *ptr; ptr ++)
+ if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' &&
+ *ptr != '_')
+ break;
+
+ if (*ptr || ptr == attr->values[i].string.text)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad keyword value \"%s\" - invalid "
+ "character (RFC 2911 section 4.1.3).",
+ attr->name, attr->values[i].string.text);
+ else
+ break;
+ }
+
+ if ((ptr - attr->values[i].string.text) > 255)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad keyword value \"%s\" - bad "
+ "length %d (RFC 2911 section 4.1.3).",
+ attr->name, attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_URI :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL,
+ attr->values[i].string.text,
+ scheme, sizeof(scheme),
+ userpass, sizeof(userpass),
+ hostname, sizeof(hostname),
+ &port, resource, sizeof(resource));
+
+ if (uri_status < HTTP_URI_OK)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad URI value \"%s\" - %s "
+ "(RFC 2911 section 4.1.5).", attr->name,
+ attr->values[i].string.text,
+ URIStatusStrings[uri_status -
+ HTTP_URI_OVERFLOW]);
+ else
+ break;
+ }
+
+ if (strlen(attr->values[i].string.text) > 1023)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad URI value \"%s\" - bad length %d "
+ "(RFC 2911 section 4.1.5).", attr->name,
+ attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_URISCHEME :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ ptr = attr->values[i].string.text;
+ if (islower(*ptr & 255))
+ {
+ for (ptr ++; *ptr; ptr ++)
+ if (!islower(*ptr & 255) && !isdigit(*ptr & 255) &&
+ *ptr != '+' && *ptr != '-' && *ptr != '.')
+ break;
+ }
+
+ if (*ptr || ptr == attr->values[i].string.text)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad uriScheme value \"%s\" - bad "
+ "characters (RFC 2911 section 4.1.6).",
+ attr->name, attr->values[i].string.text);
+ else
+ break;
+ }
+
+ if ((ptr - attr->values[i].string.text) > 63)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad uriScheme value \"%s\" - bad "
+ "length %d (RFC 2911 section 4.1.6).",
+ attr->name, attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_CHARSET :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ for (ptr = attr->values[i].string.text; *ptr; ptr ++)
+ if (!isprint(*ptr & 255) || isupper(*ptr & 255) ||
+ isspace(*ptr & 255))
+ break;
+
+ if (*ptr || ptr == attr->values[i].string.text)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad charset value \"%s\" - bad "
+ "characters (RFC 2911 section 4.1.7).",
+ attr->name, attr->values[i].string.text);
+ else
+ break;
+ }
+
+ if ((ptr - attr->values[i].string.text) > 40)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad charset value \"%s\" - bad "
+ "length %d (RFC 2911 section 4.1.7).",
+ attr->name, attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+ break;
+
+ case IPP_TAG_LANGUAGE :
+ /*
+ * The following regular expression is derived from the ABNF for
+ * language tags in RFC 4646. All I can say is that this is the
+ * easiest way to check the values...
+ */
+
+ if ((i = regcomp(&re,
+ "^("
+ "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
+ /* language */
+ "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */
+ "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */
+ "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */
+ "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */
+ "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */
+ "|"
+ "x(-[a-z0-9]{1,8})+" /* privateuse */
+ "|"
+ "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
+ ")$",
+ REG_NOSUB | REG_EXTENDED)) != 0)
+ {
+ char temp[256]; /* Temporary error string */
+
+ regerror(i, &re, temp, sizeof(temp));
+ print_fatal_error("Unable to compile naturalLanguage regular "
+ "expression: %s.", temp);
+ }
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad naturalLanguage value \"%s\" - bad "
+ "characters (RFC 2911 section 4.1.8).",
+ attr->name, attr->values[i].string.text);
+ else
+ break;
+ }
+
+ if (strlen(attr->values[i].string.text) > 63)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad naturalLanguage value \"%s\" - bad "
+ "length %d (RFC 2911 section 4.1.8).",
+ attr->name, attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+
+ regfree(&re);
+ break;
+
+ case IPP_TAG_MIMETYPE :
+ /*
+ * The following regular expression is derived from the ABNF for
+ * language tags in RFC 2045 and 4288. All I can say is that this is
+ * the easiest way to check the values...
+ */
+
+ if ((i = regcomp(&re,
+ "^"
+ "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
+ "/"
+ "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
+ "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
+ "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
+ /* value */
+ "$",
+ REG_NOSUB | REG_EXTENDED)) != 0)
+ {
+ char temp[256]; /* Temporary error string */
+
+ regerror(i, &re, temp, sizeof(temp));
+ print_fatal_error("Unable to compile mimeMediaType regular "
+ "expression: %s.", temp);
+ }
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad mimeMediaType value \"%s\" - bad "
+ "characters (RFC 2911 section 4.1.9).",
+ attr->name, attr->values[i].string.text);
+ else
+ break;
+ }
+
+ if (strlen(attr->values[i].string.text) > 255)
+ {
+ valid = 0;
+
+ if (print)
+ print_test_error("\"%s\": Bad mimeMediaType value \"%s\" - bad "
+ "length %d (RFC 2911 section 4.1.9).",
+ attr->name, attr->values[i].string.text,
+ (int)strlen(attr->values[i].string.text));
+ else
+ break;
+ }
+ }
+ break;
+
+ default :
+ break;
+ }
+
+ return (valid);
+}
+
+
+/*
+ * 'with_value()' - Test a WITH-VALUE predicate.
+ */
+
+static int /* O - 1 on match, 0 on non-match */
+with_value(char *value, /* I - Value string */
+ int regex, /* I - Value is a regular expression */
+ ipp_attribute_t *attr, /* I - Attribute to compare */
+ int report) /* I - 1 = report failures */
+{
+ int i; /* Looping var */
+ char *valptr; /* Pointer into value */
+
+
+ /*
+ * NULL matches everything.
+ */
+
+ if (!value || !*value)
+ return (1);
+
+ /*
+ * Compare the value string to the attribute value.
+ */
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ char op, /* Comparison operator */
+ *nextptr; /* Next pointer */
+ int intvalue; /* Integer value */
+
+
+ valptr = value;
+ if (!strncmp(valptr, "no-value,", 9))
+ valptr += 9;
+
+ while (isspace(*valptr & 255) || isdigit(*valptr & 255) ||
+ *valptr == '-' || *valptr == ',' || *valptr == '<' ||
+ *valptr == '=' || *valptr == '>')
+ {
+ op = '=';
+ while (*valptr && !isdigit(*valptr & 255) && *valptr != '-')
+ {
+ if (*valptr == '<' || *valptr == '>' || *valptr == '=')
+ op = *valptr;
+ valptr ++;
+ }
+
+ if (!*valptr)
+ break;
+
+ intvalue = strtol(valptr, &nextptr, 0);
+ if (nextptr == valptr)
+ break;
+ valptr = nextptr;
+
+ switch (op)
+ {
+ case '=' :
+ if (attr->values[i].integer == intvalue)
+ return (1);
+ break;
+ case '<' :
+ if (attr->values[i].integer < intvalue)
+ return (1);
+ break;
+ case '>' :
+ if (attr->values[i].integer > intvalue)
+ return (1);
+ break;
+ }
+ }
+ }
+
+ if (report)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ print_test_error("GOT: %s=%d", attr->name, attr->values[i].integer);
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ char op, /* Comparison operator */
+ *nextptr; /* Next pointer */
+ int intvalue; /* Integer value */
+
+
+ valptr = value;
+ if (!strncmp(valptr, "no-value,", 9))
+ valptr += 9;
+
+ while (isspace(*valptr & 255) || isdigit(*valptr & 255) ||
+ *valptr == '-' || *valptr == ',' || *valptr == '<' ||
+ *valptr == '=' || *valptr == '>')
+ {
+ op = '=';
+ while (*valptr && !isdigit(*valptr & 255) && *valptr != '-')
+ {
+ if (*valptr == '<' || *valptr == '>' || *valptr == '=')
+ op = *valptr;
+ valptr ++;
+ }
+
+ if (!*valptr)
+ break;
+
+ intvalue = strtol(valptr, &nextptr, 0);
+ if (nextptr == valptr)
+ break;
+ valptr = nextptr;
+
+ switch (op)
+ {
+ case '=' :
+ if (attr->values[i].range.lower == intvalue ||
+ attr->values[i].range.upper == intvalue)
+ return (1);
+ break;
+ case '<' :
+ if (attr->values[i].range.upper < intvalue)
+ return (1);
+ break;
+ case '>' :
+ if (attr->values[i].range.upper > intvalue)
+ return (1);
+ break;
+ }
+ }
+ }
+
+ if (report)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ print_test_error("GOT: %s=%d-%d", attr->name,
+ attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ }
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (!strcmp(value, "true") == attr->values[i].boolean)
+ return (1);
+ }
+
+ if (report)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ print_test_error("GOT: %s=%s", attr->name,
+ attr->values[i].boolean ? "true" : "false");
+ }
+ break;
+
+ case IPP_TAG_NOVALUE :
+ return (!strcmp(value, "no-value") || !strncmp(value, "no-value,", 9));
+
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ case IPP_TAG_NAME :
+ case IPP_TAG_NAMELANG :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ if (regex)
+ {
+ /*
+ * Value is an extended, case-sensitive POSIX regular expression...
+ */
+
+ regex_t re; /* Regular expression */
+
+ if ((i = regcomp(&re, value, REG_EXTENDED | REG_NOSUB)) != 0)
+ {
+ char temp[256]; /* Temporary string */
+
+ regerror(i, &re, temp, sizeof(temp));
+
+ print_fatal_error("Unable to compile WITH-VALUE regular expression "
+ "\"%s\" - %s", value, temp);
+ return (0);
+ }
+
+ /*
+ * See if ALL of the values match the given regular expression.
+ */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
+ {
+ if (report)
+ print_test_error("GOT: %s=\"%s\"", attr->name,
+ attr->values[i].string.text);
+ else
+ break;
+ }
+ }
+
+ regfree(&re);
+
+ return (i == attr->num_values);
+ }
+ else
+ {
+ /*
+ * Value is a literal string, see if at least one value matches the
+ * literal string...
+ */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (!strcmp(value, attr->values[i].string.text))
+ return (1);
+ }
+
+ if (report)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ print_test_error("GOT: %s=\"%s\"", attr->name,
+ attr->values[i].string.text);
+ }
+ }
+ break;
+
+ default :
+ break;
+ }
+
+ return (0);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/test/print-job-hold.test b/test/print-job-hold.test
new file mode 100644
index 000000000..d70e523e7
--- /dev/null
+++ b/test/print-job-hold.test
@@ -0,0 +1,41 @@
+# Test print-job and job-hold-until attribute
+{
+ # The name of the test...
+ NAME "Print-Job w/job-hold-until=indefinite"
+
+ # The operation to use
+ OPERATION Print-Job
+
+ # Attributes, starting in the operation group...
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR keyword job-hold-until indefinite
+ ATTR name job-name $filename
+
+ FILE $filename
+
+ # What statuses are OK?
+ STATUS successful-ok
+ STATUS successful-ok-ignored-or-substituted-attributes
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
+{
+ NAME "Release-Job"
+ OPERATION Release-Job
+
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ # What statuses are OK?
+ STATUS successful-ok
+}
diff --git a/test/print-job-media-col.test b/test/print-job-media-col.test
new file mode 100644
index 000000000..cafd291fb
--- /dev/null
+++ b/test/print-job-media-col.test
@@ -0,0 +1,46 @@
+# Print a test page using Print-Job + media-col
+#
+# Usage:
+#
+# ./ipptest -f filename ipp://... print-job-media-col.test
+{
+ # The name of the test...
+ NAME "Print test page using Print-Job + media-col"
+
+ # The operation to use
+ OPERATION Print-Job
+
+ # Attributes, starting in the operation group...
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR mimetype document-format application/octet-stream
+
+ GROUP job-attributes-tag
+ ATTR collection media-col {
+ MEMBER collection media-size {
+ # 4x6
+ MEMBER integer x-dimension 10160
+ MEMBER integer y-dimension 15240
+ }
+
+ # Borderless
+ MEMBER integer media-left-margin 0
+ MEMBER integer media-right-margin 0
+ MEMBER integer media-top-margin 0
+ MEMBER integer media-bottom-margin 0
+ }
+ ATTR enum print-quality 5
+
+ FILE $filename
+
+ # What statuses are OK?
+ STATUS successful-ok
+ STATUS successful-ok-ignored-or-substituted-attributes
+
+ # What attributes do we expect?
+ EXPECT job-id OF-TYPE integer WITH-VALUE >0
+ EXPECT job-uri OF-TYPE uri
+}
diff --git a/test/print-job.test b/test/print-job.test
new file mode 100644
index 000000000..a830a1244
--- /dev/null
+++ b/test/print-job.test
@@ -0,0 +1,28 @@
+# Print a test page using print-job
+{
+ # The name of the test...
+ NAME "Print file using Print-Job"
+
+ # The operation to use
+ OPERATION Print-Job
+
+ # Attributes, starting in the operation group...
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ GROUP job-attributes-tag
+ ATTR integer copies 1
+
+ FILE $filename
+
+ # What statuses are OK?
+ STATUS successful-ok
+ STATUS successful-ok-ignored-or-substituted-attributes
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
diff --git a/test/print-uri.test b/test/print-uri.test
new file mode 100644
index 000000000..aaa7d392e
--- /dev/null
+++ b/test/print-uri.test
@@ -0,0 +1,27 @@
+# Print a file using Print-URI
+{
+ # The name of the test...
+ NAME "Print file using Print-URI"
+
+ # The operation to use
+ OPERATION Print-URI
+
+ # Attributes, starting in the operation group...
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR uri document-uri file://$filename
+
+ GROUP job-attributes-tag
+ ATTR integer copies 1
+
+ # What statuses are OK?
+ STATUS successful-ok
+ STATUS successful-ok-ignored-or-substituted-attributes
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
diff --git a/test/printer.opacity b/test/printer.opacity
new file mode 100644
index 000000000..595854a24
--- /dev/null
+++ b/test/printer.opacity
Binary files differ
diff --git a/test/printer.png b/test/printer.png
new file mode 100644
index 000000000..18c05db10
--- /dev/null
+++ b/test/printer.png
Binary files differ
diff --git a/test/run-stp-tests.sh b/test/run-stp-tests.sh
new file mode 100755
index 000000000..5af52a30f
--- /dev/null
+++ b/test/run-stp-tests.sh
@@ -0,0 +1,870 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Perform the complete set of IPP compliance tests specified in the
+# CUPS Software Test Plan.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2007 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+argcount=$#
+
+#
+# Make the IPP test program...
+#
+
+make
+
+#
+# Solaris has a non-POSIX grep in /bin...
+#
+
+if test -x /usr/xpg4/bin/grep; then
+ GREP=/usr/xpg4/bin/grep
+else
+ GREP=grep
+fi
+
+#
+# Figure out the proper echo options...
+#
+
+if (echo "testing\c"; echo 1,2,3) | $GREP c >/dev/null; then
+ ac_n=-n
+ ac_c=
+else
+ ac_n=
+ ac_c='\c'
+fi
+
+#
+# Greet the tester...
+#
+
+echo "Welcome to the CUPS Automated Test Script."
+echo ""
+echo "Before we begin, it is important that you understand that the larger"
+echo "tests require significant amounts of RAM and disk space. If you"
+echo "attempt to run one of the big tests on a system that lacks sufficient"
+echo "disk and virtual memory, the UNIX kernel might decide to kill one or"
+echo "more system processes that you've grown attached to, like the X"
+echo "server. The question you may want to ask yourself before running a"
+echo "large test is: Do you feel lucky?"
+echo ""
+echo "OK, now that we have the Dirty Harry quote out of the way, please"
+echo "choose the type of test you wish to perform:"
+echo ""
+echo "0 - No testing, keep the scheduler running for me (all systems)"
+echo "1 - Basic conformance test, no load testing (all systems)"
+echo "2 - Basic conformance test, some load testing (minimum 256MB VM, 50MB disk)"
+echo "3 - Basic conformance test, extreme load testing (minimum 1GB VM, 500MB disk)"
+echo "4 - Basic conformance test, torture load testing (minimum 2GB VM, 1GB disk)"
+echo ""
+echo $ac_n "Enter the number of the test you wish to perform: [1] $ac_c"
+
+if test $# -gt 0; then
+ testtype=$1
+ shift
+else
+ read testtype
+fi
+echo ""
+
+case "$testtype" in
+ 0)
+ echo "Running in test mode (0)"
+ nprinters1=0
+ nprinters2=0
+ pjobs=0
+ pprinters=0
+ ;;
+ 2)
+ echo "Running the medium tests (2)"
+ nprinters1=10
+ nprinters2=20
+ pjobs=20
+ pprinters=10
+ ;;
+ 3)
+ echo "Running the extreme tests (3)"
+ nprinters1=500
+ nprinters2=1000
+ pjobs=100
+ pprinters=50
+ ;;
+ 4)
+ echo "Running the torture tests (4)"
+ nprinters1=10000
+ nprinters2=20000
+ pjobs=200
+ pprinters=100
+ ;;
+ *)
+ echo "Running the timid tests (1)"
+ nprinters1=0
+ nprinters2=0
+ pjobs=10
+ pprinters=0
+ ;;
+esac
+
+#
+# See if we want to do SSL testing...
+#
+
+echo ""
+echo "Now you can choose whether to create a SSL/TLS encryption key and"
+echo "certificate for testing; these tests currently require the OpenSSL"
+echo "tools:"
+echo ""
+echo "0 - Do not do SSL/TLS encryption tests"
+echo "1 - Test but do not require encryption"
+echo "2 - Test and require encryption"
+echo ""
+echo $ac_n "Enter the number of the SSL/TLS tests to perform: [0] $ac_c"
+
+if test $# -gt 0; then
+ ssltype=$1
+ shift
+else
+ read ssltype
+fi
+echo ""
+
+case "$ssltype" in
+ 1)
+ echo "Will test but not require encryption (1)"
+ ;;
+ 2)
+ echo "Will test and require encryption (2)"
+ ;;
+ *)
+ echo "Not using SSL/TLS (0)"
+ ssltype=0
+ ;;
+esac
+
+#
+# Information for the server/tests...
+#
+
+user="$USER"
+if test -z "$user"; then
+ if test -x /usr/ucb/whoami; then
+ user=`/usr/ucb/whoami`
+ else
+ user=`whoami`
+ fi
+
+ if test -z "$user"; then
+ user="unknown"
+ fi
+fi
+
+port=8631
+cwd=`pwd`
+root=`dirname $cwd`
+
+#
+# Make sure that the LPDEST and PRINTER environment variables are
+# not included in the environment that is passed to the tests. These
+# will usually cause tests to fail erroneously...
+#
+
+unset LPDEST
+unset PRINTER
+
+#
+# See if we want to use valgrind...
+#
+
+echo ""
+echo "This test script can use the Valgrind software from:"
+echo ""
+echo " http://developer.kde.org/~sewardj/"
+echo ""
+echo $ac_n "Enter Y to use Valgrind or N to not use Valgrind: [N] $ac_c"
+
+if test $# -gt 0; then
+ usevalgrind=$1
+ shift
+else
+ read usevalgrind
+fi
+echo ""
+
+case "$usevalgrind" in
+ Y* | y*)
+ valgrind="valgrind --tool=memcheck --log-file=/tmp/cups-$user/log/valgrind.%p --error-limit=no --leak-check=yes --trace-children=yes --read-var-info=yes"
+ echo "Using Valgrind; log files can be found in /tmp/cups-$user/log..."
+ ;;
+
+ *)
+ valgrind=""
+ ;;
+esac
+
+#
+# Start by creating temporary directories for the tests...
+#
+
+echo "Creating directories for test..."
+
+rm -rf /tmp/cups-$user
+mkdir /tmp/cups-$user
+mkdir /tmp/cups-$user/bin
+mkdir /tmp/cups-$user/bin/backend
+mkdir /tmp/cups-$user/bin/driver
+mkdir /tmp/cups-$user/bin/filter
+mkdir /tmp/cups-$user/certs
+mkdir /tmp/cups-$user/share
+mkdir /tmp/cups-$user/share/banners
+mkdir /tmp/cups-$user/share/drv
+mkdir /tmp/cups-$user/share/locale
+for file in ../locale/cups_*.po; do
+ loc=`basename $file .po | cut -c 6-`
+ mkdir /tmp/cups-$user/share/locale/$loc
+ ln -s $root/locale/cups_$loc.po /tmp/cups-$user/share/locale/$loc
+ ln -s $root/locale/ppdc_$loc.po /tmp/cups-$user/share/locale/$loc
+done
+mkdir /tmp/cups-$user/share/mime
+mkdir /tmp/cups-$user/share/model
+mkdir /tmp/cups-$user/share/ppdc
+mkdir /tmp/cups-$user/interfaces
+mkdir /tmp/cups-$user/log
+mkdir /tmp/cups-$user/ppd
+mkdir /tmp/cups-$user/spool
+mkdir /tmp/cups-$user/spool/temp
+mkdir /tmp/cups-$user/ssl
+
+ln -s $root/backend/dnssd /tmp/cups-$user/bin/backend
+ln -s $root/backend/http /tmp/cups-$user/bin/backend
+ln -s $root/backend/ipp /tmp/cups-$user/bin/backend
+ln -s $root/backend/lpd /tmp/cups-$user/bin/backend
+ln -s $root/backend/mdns /tmp/cups-$user/bin/backend
+ln -s $root/backend/parallel /tmp/cups-$user/bin/backend
+ln -s $root/backend/pseudo /tmp/cups-$user/bin/backend
+ln -s $root/backend/serial /tmp/cups-$user/bin/backend
+ln -s $root/backend/snmp /tmp/cups-$user/bin/backend
+ln -s $root/backend/socket /tmp/cups-$user/bin/backend
+ln -s $root/backend/usb /tmp/cups-$user/bin/backend
+ln -s $root/cgi-bin /tmp/cups-$user/bin
+ln -s $root/monitor /tmp/cups-$user/bin
+ln -s $root/notifier /tmp/cups-$user/bin
+ln -s $root/scheduler /tmp/cups-$user/bin/daemon
+ln -s $root/filter/bannertops /tmp/cups-$user/bin/filter
+ln -s $root/filter/commandtops /tmp/cups-$user/bin/filter
+ln -s $root/filter/gziptoany /tmp/cups-$user/bin/filter
+ln -s $root/filter/hpgltops /tmp/cups-$user/bin/filter
+ln -s $root/filter/pstops /tmp/cups-$user/bin/filter
+ln -s $root/filter/rastertoepson /tmp/cups-$user/bin/filter
+ln -s $root/filter/rastertohp /tmp/cups-$user/bin/filter
+ln -s $root/filter/rastertolabel /tmp/cups-$user/bin/filter
+ln -s $root/filter/rastertopwg /tmp/cups-$user/bin/filter
+ln -s $root/filter/texttops /tmp/cups-$user/bin/filter
+
+ln -s $root/data/classified /tmp/cups-$user/share/banners
+ln -s $root/data/confidential /tmp/cups-$user/share/banners
+ln -s $root/data/secret /tmp/cups-$user/share/banners
+ln -s $root/data/standard /tmp/cups-$user/share/banners
+ln -s $root/data/topsecret /tmp/cups-$user/share/banners
+ln -s $root/data/unclassified /tmp/cups-$user/share/banners
+ln -s $root/data /tmp/cups-$user/share/charmaps
+ln -s $root/data /tmp/cups-$user/share/charsets
+ln -s $root/data /tmp/cups-$user/share
+ln -s $root/fonts /tmp/cups-$user/share
+ln -s $root/ppdc/sample.drv /tmp/cups-$user/share/drv
+ln -s $root/conf/mime.types /tmp/cups-$user/share/mime
+ln -s $root/conf/mime.convs /tmp/cups-$user/share/mime
+ln -s $root/data/*.h /tmp/cups-$user/share/ppdc
+ln -s $root/data/*.defs /tmp/cups-$user/share/ppdc
+ln -s $root/templates /tmp/cups-$user/share
+
+if test -f $root/filter/imagetops; then
+ ln -s $root/filter/imagetops /tmp/cups-$user/bin/filter
+fi
+
+if test -f $root/filter/imagetoraster; then
+ ln -s $root/filter/imagetoraster /tmp/cups-$user/bin/filter
+fi
+
+#
+# Mac OS X filters and configuration files...
+#
+
+if test `uname` = Darwin; then
+ ln -s /usr/libexec/cups/filter/cgpdfto* /tmp/cups-$user/bin/filter
+ ln -s /usr/libexec/cups/filter/cgbannertopdf /tmp/cups-$user/bin/filter
+ ln -s /usr/libexec/cups/filter/cgimagetopdf /tmp/cups-$user/bin/filter
+ ln -s /usr/libexec/cups/filter/cgtexttopdf /tmp/cups-$user/bin/filter
+ ln -s /usr/libexec/cups/filter/nsimagetopdf /tmp/cups-$user/bin/filter
+ ln -s /usr/libexec/cups/filter/nstexttopdf /tmp/cups-$user/bin/filter
+ ln -s /usr/libexec/cups/filter/pictwpstops /tmp/cups-$user/bin/filter
+ ln -s /usr/libexec/cups/filter/pstoappleps /tmp/cups-$user/bin/filter
+ ln -s /usr/libexec/cups/filter/pstocupsraster /tmp/cups-$user/bin/filter
+ ln -s /usr/libexec/cups/filter/pstopdffilter /tmp/cups-$user/bin/filter
+ ln -s /usr/libexec/cups/filter/rastertourf /tmp/cups-$user/bin/filter
+ ln -s /usr/libexec/cups/filter/xhtmltopdf /tmp/cups-$user/bin/filter
+
+ if test -f /private/etc/cups/apple.types; then
+ ln -s /private/etc/cups/apple.* /tmp/cups-$user/share/mime
+ elif test -f /usr/share/cups/mime/apple.types; then
+ ln -s /usr/share/cups/mime/apple.* /tmp/cups-$user/share/mime
+ fi
+else
+ ln -s $root/filter/pdftops /tmp/cups-$user/bin/filter
+fi
+
+#
+# Then create the necessary config files...
+#
+
+echo "Creating cupsd.conf for test..."
+
+if test $ssltype = 2; then
+ encryption="Encryption Required"
+else
+ encryption=""
+fi
+
+cat >/tmp/cups-$user/cupsd.conf <<EOF
+Browsing Off
+FileDevice yes
+Printcap
+Listen 127.0.0.1:$port
+User $user
+ServerRoot /tmp/cups-$user
+StateDir /tmp/cups-$user
+ServerBin /tmp/cups-$user/bin
+CacheDir /tmp/cups-$user/share
+DataDir /tmp/cups-$user/share
+FontPath /tmp/cups-$user/share/fonts
+PassEnv LOCALEDIR
+DocumentRoot $root/doc
+RequestRoot /tmp/cups-$user/spool
+TempDir /tmp/cups-$user/spool/temp
+MaxSubscriptions 3
+MaxLogSize 0
+AccessLog /tmp/cups-$user/log/access_log
+ErrorLog /tmp/cups-$user/log/error_log
+PageLog /tmp/cups-$user/log/page_log
+AccessLogLevel actions
+LogLevel debug2
+LogTimeFormat usecs
+PreserveJobHistory Yes
+<Policy default>
+<Limit All>
+Order Deny,Allow
+Deny from all
+Allow from 127.0.0.1
+$encryption
+</Limit>
+</Policy>
+EOF
+
+#
+# Setup lots of test queues - half with PPD files, half without...
+#
+
+echo "Creating printers.conf for test..."
+
+i=1
+while test $i -le $nprinters1; do
+ cat >>/tmp/cups-$user/printers.conf <<EOF
+<Printer test-$i>
+Accepting Yes
+DeviceURI file:/dev/null
+Info Test PS printer $i
+JobSheets none none
+Location CUPS test suite
+State Idle
+StateMessage Printer $1 is idle.
+</Printer>
+EOF
+
+ cp testps.ppd /tmp/cups-$user/ppd/test-$i.ppd
+
+ i=`expr $i + 1`
+done
+
+while test $i -le $nprinters2; do
+ cat >>/tmp/cups-$user/printers.conf <<EOF
+<Printer test-$i>
+Accepting Yes
+DeviceURI file:/dev/null
+Info Test raw printer $i
+JobSheets none none
+Location CUPS test suite
+State Idle
+StateMessage Printer $1 is idle.
+</Printer>
+EOF
+
+ i=`expr $i + 1`
+done
+
+if test -f /tmp/cups-$user/printers.conf; then
+ cp /tmp/cups-$user/printers.conf /tmp/cups-$user/printers.conf.orig
+else
+ touch /tmp/cups-$user/printers.conf.orig
+fi
+
+#
+# Setup the paths...
+#
+
+echo "Setting up environment variables for test..."
+
+if test "x$LD_LIBRARY_PATH" = x; then
+ LD_LIBRARY_PATH="$root/cups:$root/filter:$root/cgi-bin:$root/scheduler:$root/driver:$root/ppdc"
+else
+ LD_LIBRARY_PATH="$root/cups:$root/filter:$root/cgi-bin:$root/scheduler:$root/driver:$root/ppdc:$LD_LIBRARY_PATH"
+fi
+
+export LD_LIBRARY_PATH
+
+LD_PRELOAD="$root/cups/libcups.so.2:$root/filter/libcupsimage.so.2:$root/cgi-bin/libcupscgi.so.1:$root/scheduler/libcupsmime.so.1:$root/driver/libcupsdriver.so.1:$root/ppdc/libcupsppdc.so.1"
+if test `uname` = SunOS -a -r /usr/lib/libCrun.so.1; then
+ LD_PRELOAD="/usr/lib/libCrun.so.1:$LD_PRELOAD"
+fi
+export LD_PRELOAD
+
+if test "x$DYLD_LIBRARY_PATH" = x; then
+ DYLD_LIBRARY_PATH="$root/cups:$root/filter:$root/cgi-bin:$root/scheduler:$root/driver:$root/ppdc"
+else
+ DYLD_LIBRARY_PATH="$root/cups:$root/filter:$root/cgi-bin:$root/scheduler:$root/driver:$root/ppdc:$DYLD_LIBRARY_PATH"
+fi
+
+export DYLD_LIBRARY_PATH
+
+if test "x$SHLIB_PATH" = x; then
+ SHLIB_PATH="$root/cups:$root/filter:$root/cgi-bin:$root/scheduler:$root/driver:$root/ppdc"
+else
+ SHLIB_PATH="$root/cups:$root/filter:$root/cgi-bin:$root/scheduler:$root/driver:$root/ppdc:$SHLIB_PATH"
+fi
+
+export SHLIB_PATH
+
+CUPS_DISABLE_APPLE_DEFAULT=yes; export CUPS_DISABLE_APPLE_DEFAULT
+CUPS_SERVER=localhost:8631; export CUPS_SERVER
+CUPS_SERVERROOT=/tmp/cups-$user; export CUPS_SERVERROOT
+CUPS_STATEDIR=/tmp/cups-$user; export CUPS_STATEDIR
+CUPS_DATADIR=/tmp/cups-$user/share; export CUPS_DATADIR
+LOCALEDIR=/tmp/cups-$user/share/locale; export LOCALEDIR
+
+#
+# Set a new home directory to avoid getting user options mixed in...
+#
+
+HOME=/tmp/cups-$user
+export HOME
+
+#
+# Force POSIX locale for tests...
+#
+
+LANG=C
+export LANG
+
+LC_MESSAGES=C
+export LC_MESSAGES
+
+#
+# Start the server; run as foreground daemon in the background...
+#
+
+echo "Starting scheduler:"
+echo " $valgrind ../scheduler/cupsd -c /tmp/cups-$user/cupsd.conf -f >/tmp/cups-$user/log/debug_log 2>&1 &"
+echo ""
+
+if test `uname` = Darwin -a "x$valgrind" = x; then
+ DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib \
+ $valgrind ../scheduler/cupsd -c /tmp/cups-$user/cupsd.conf -f >/tmp/cups-$user/log/debug_log 2>&1 &
+else
+ $valgrind ../scheduler/cupsd -c /tmp/cups-$user/cupsd.conf -f >/tmp/cups-$user/log/debug_log 2>&1 &
+fi
+
+cupsd=$!
+
+if test "x$testtype" = x0; then
+ # Not running tests...
+ echo "Scheduler is PID $cupsd and is listening on port 8631."
+ echo ""
+
+ # Create a helper script to run programs with...
+ runcups="/tmp/cups-$user/runcups"
+
+ echo "#!/bin/sh" >$runcups
+ echo "# Helper script for running CUPS test instance." >>$runcups
+ echo "" >>$runcups
+ echo "# Set required environment variables..." >>$runcups
+ echo "CUPS_DATADIR=\"$CUPS_DATADIR\"; export CUPS_DATADIR" >>$runcups
+ echo "CUPS_SERVER=\"$CUPS_SERVER\"; export CUPS_SERVER" >>$runcups
+ echo "CUPS_SERVERROOT=\"$CUPS_SERVERROOT\"; export CUPS_SERVERROOT" >>$runcups
+ echo "CUPS_STATEDIR=\"$CUPS_STATEDIR\"; export CUPS_STATEDIR" >>$runcups
+ echo "DYLD_LIBRARY_PATH=\"$DYLD_LIBRARY_PATH\"; export DYLD_LIBRARY_PATH" >>$runcups
+ echo "LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH\"; export LD_LIBRARY_PATH" >>$runcups
+ echo "LD_PRELOAD=\"$LD_PRELOAD\"; export LD_PRELOAD" >>$runcups
+ echo "LOCALEDIR=\"$LOCALEDIR\"; export LOCALEDIR" >>$runcups
+ echo "SHLIB_PATH=\"$SHLIB_PATH\"; export SHLIB_PATH" >>$runcups
+ echo "" >>$runcups
+ echo "# Run command..." >>$runcups
+ echo "exec \"\$@\"" >>$runcups
+
+ chmod +x $runcups
+
+ echo "The $runcups helper script can be used to test programs"
+ echo "with the server."
+ exit 0
+fi
+
+if test $argcount -eq 0; then
+ echo "Scheduler is PID $cupsd; run debugger now if you need to."
+ echo ""
+ echo $ac_n "Press ENTER to continue... $ac_c"
+ read junk
+else
+ echo "Scheduler is PID $cupsd."
+ sleep 2
+fi
+
+IPP_PORT=$port; export IPP_PORT
+
+while true; do
+ running=`../systemv/lpstat -r 2>/dev/null`
+ if test "x$running" = "xscheduler is running"; then
+ break
+ fi
+
+ echo "Waiting for scheduler to become ready..."
+ sleep 10
+done
+
+#
+# Create the test report source file...
+#
+
+date=`date "+%Y-%m-%d"`
+strfile=/tmp/cups-$user/cups-str-1.5-$date-$user.html
+
+rm -f $strfile
+cat str-header.html >$strfile
+
+#
+# Run the IPP tests...
+#
+
+echo ""
+echo "Running IPP compliance tests..."
+
+echo "<H1>1 - IPP Compliance Tests</H1>" >>$strfile
+echo "<P>This section provides the results to the IPP compliance tests" >>$strfile
+echo "outlined in the CUPS Software Test Plan. These tests were run on" >>$strfile
+echo `date "+%Y-%m-%d"` by $user on `hostname`. >>$strfile
+echo "<PRE>" >>$strfile
+
+fail=0
+for file in 4*.test; do
+ echo "Performing $file..."
+ echo "" >>$strfile
+
+ ./ipptool -t ipp://localhost:$port/printers $file | tee -a $strfile
+ status=$?
+
+ if test $status != 0; then
+ echo Test failed.
+ fail=`expr $fail + 1`
+ fi
+done
+
+echo "</PRE>" >>$strfile
+
+#
+# Run the command tests...
+#
+
+echo ""
+echo "Running command tests..."
+
+echo "<H1>2 - Command Tests</H1>" >>$strfile
+echo "<P>This section provides the results to the command tests" >>$strfile
+echo "outlined in the CUPS Software Test Plan. These tests were run on" >>$strfile
+echo $date by $user on `hostname`. >>$strfile
+echo "<PRE>" >>$strfile
+
+for file in 5*.sh; do
+ echo "Performing $file..."
+ echo "" >>$strfile
+ echo "\"$file\":" >>$strfile
+
+ sh $file $pjobs $pprinters | tee -a $strfile
+ status=$?
+
+ if test $status != 0; then
+ echo Test failed.
+ fail=`expr $fail + 1`
+ fi
+done
+
+echo "</PRE>" >>$strfile
+
+#
+# Stop the server...
+#
+
+kill $cupsd
+
+#
+# Append the log files for post-mortim...
+#
+
+echo "<H1>3 - Log Files</H1>" >>$strfile
+
+#
+# Verify counts...
+#
+
+echo "Test Summary"
+echo ""
+echo "<H2>Summary</H2>" >>$strfile
+
+# Job control files
+count=`ls -1 /tmp/cups-$user/spool | wc -l`
+count=`expr $count - 1`
+if test $count != 0; then
+ echo "FAIL: $count job control files were not purged."
+ echo "<P>FAIL: $count job control files were not purged.</P>" >>$strfile
+ fail=`expr $fail + 1`
+else
+ echo "PASS: All job control files purged."
+ echo "<P>PASS: All job control files purged.</P>" >>$strfile
+fi
+
+# Pages printed on Test1 (within 1 page for timing-dependent cancel issues)
+count=`$GREP '^Test1 ' /tmp/cups-$user/log/page_log | awk 'BEGIN{count=0}{count=count+$7}END{print count}'`
+expected=`expr $pjobs \* 2 + 34`
+expected2=`expr $expected + 2`
+if test $count -lt $expected -a $count -gt $expected2; then
+ echo "FAIL: Printer 'Test1' produced $count page(s), expected $expected."
+ echo "<P>FAIL: Printer 'Test1' produced $count page(s), expected $expected.</P>" >>$strfile
+ fail=`expr $fail + 1`
+else
+ echo "PASS: Printer 'Test1' correctly produced $count page(s)."
+ echo "<P>PASS: Printer 'Test1' correctly produced $count page(s).</P>" >>$strfile
+fi
+
+# Paged printed on Test2
+count=`$GREP '^Test2 ' /tmp/cups-$user/log/page_log | awk 'BEGIN{count=0}{count=count+$7}END{print count}'`
+expected=`expr $pjobs \* 2 + 3`
+if test $count != $expected; then
+ echo "FAIL: Printer 'Test2' produced $count page(s), expected $expected."
+ echo "<P>FAIL: Printer 'Test2' produced $count page(s), expected $expected.</P>" >>$strfile
+ fail=`expr $fail + 1`
+else
+ echo "PASS: Printer 'Test2' correctly produced $count page(s)."
+ echo "<P>PASS: Printer 'Test2' correctly produced $count page(s).</P>" >>$strfile
+fi
+
+# Requests logged
+count=`wc -l /tmp/cups-$user/log/access_log | awk '{print $1}'`
+expected=`expr 37 + 18 + $pjobs \* 8 + $pprinters \* $pjobs \* 4`
+if test $count != $expected; then
+ echo "FAIL: $count requests logged, expected $expected."
+ echo "<P>FAIL: $count requests logged, expected $expected.</P>" >>$strfile
+ fail=`expr $fail + 1`
+else
+ echo "PASS: $count requests logged."
+ echo "<P>PASS: $count requests logged.</P>" >>$strfile
+fi
+
+# Did CUPS-Get-Default get logged?
+if $GREP -q CUPS-Get-Default /tmp/cups-$user/log/access_log; then
+ echo "FAIL: CUPS-Get-Default logged with 'AccessLogLevel actions'"
+ echo "<P>FAIL: CUPS-Get-Default logged with 'AccessLogLevel actions'</P>" >>$strfile
+ echo "<PRE>" >>$strfile
+ $GREP CUPS-Get-Default /tmp/cups-$user/log/access_log | sed -e '1,$s/&/&amp;/g' -e '1,$s/</&lt;/g' >>$strfile
+ echo "</PRE>" >>$strfile
+ fail=`expr $fail + 1`
+else
+ echo "PASS: CUPS-Get-Default not logged."
+ echo "<P>PASS: CUPS-Get-Default not logged.</P>" >>$strfile
+fi
+
+# Emergency log messages
+count=`$GREP '^X ' /tmp/cups-$user/log/error_log | wc -l | awk '{print $1}'`
+if test $count != 0; then
+ echo "FAIL: $count emergency messages, expected 0."
+ $GREP '^X ' /tmp/cups-$user/log/error_log
+ echo "<P>FAIL: $count emergency messages, expected 0.</P>" >>$strfile
+ echo "<PRE>" >>$strfile
+ $GREP '^X ' /tmp/cups-$user/log/error_log | sed -e '1,$s/&/&amp;/g' -e '1,$s/</&lt;/g' >>$strfile
+ echo "</PRE>" >>$strfile
+ fail=`expr $fail + 1`
+else
+ echo "PASS: $count emergency messages."
+ echo "<P>PASS: $count emergency messages.</P>" >>$strfile
+fi
+
+# Alert log messages
+count=`$GREP '^A ' /tmp/cups-$user/log/error_log | wc -l | awk '{print $1}'`
+if test $count != 0; then
+ echo "FAIL: $count alert messages, expected 0."
+ $GREP '^A ' /tmp/cups-$user/log/error_log
+ echo "<P>FAIL: $count alert messages, expected 0.</P>" >>$strfile
+ echo "<PRE>" >>$strfile
+ $GREP '^A ' /tmp/cups-$user/log/error_log | sed -e '1,$s/&/&amp;/g' -e '1,$s/</&lt;/g' >>$strfile
+ echo "</PRE>" >>$strfile
+ fail=`expr $fail + 1`
+else
+ echo "PASS: $count alert messages."
+ echo "<P>PASS: $count alert messages.</P>" >>$strfile
+fi
+
+# Critical log messages
+count=`$GREP '^C ' /tmp/cups-$user/log/error_log | wc -l | awk '{print $1}'`
+if test $count != 0; then
+ echo "FAIL: $count critical messages, expected 0."
+ $GREP '^C ' /tmp/cups-$user/log/error_log
+ echo "<P>FAIL: $count critical messages, expected 0.</P>" >>$strfile
+ echo "<PRE>" >>$strfile
+ $GREP '^C ' /tmp/cups-$user/log/error_log | sed -e '1,$s/&/&amp;/g' -e '1,$s/</&lt;/g' >>$strfile
+ echo "</PRE>" >>$strfile
+ fail=`expr $fail + 1`
+else
+ echo "PASS: $count critical messages."
+ echo "<P>PASS: $count critical messages.</P>" >>$strfile
+fi
+
+# Error log messages
+count=`$GREP '^E ' /tmp/cups-$user/log/error_log | wc -l | awk '{print $1}'`
+if test $count != 18; then
+ echo "FAIL: $count error messages, expected 18."
+ $GREP '^E ' /tmp/cups-$user/log/error_log
+ echo "<P>FAIL: $count error messages, expected 18.</P>" >>$strfile
+ echo "<PRE>" >>$strfile
+ $GREP '^E ' /tmp/cups-$user/log/error_log | sed -e '1,$s/&/&amp;/g' -e '1,$s/</&lt;/g' >>$strfile
+ echo "</PRE>" >>$strfile
+ fail=`expr $fail + 1`
+else
+ echo "PASS: $count error messages."
+ echo "<P>PASS: $count error messages.</P>" >>$strfile
+fi
+
+# Warning log messages
+count=`$GREP '^W ' /tmp/cups-$user/log/error_log | wc -l | awk '{print $1}'`
+if test $count != 9; then
+ echo "FAIL: $count warning messages, expected 9."
+ $GREP '^W ' /tmp/cups-$user/log/error_log
+ echo "<P>FAIL: $count warning messages, expected 9.</P>" >>$strfile
+ echo "<PRE>" >>$strfile
+ $GREP '^W ' /tmp/cups-$user/log/error_log | sed -e '1,$s/&/&amp;/g' -e '1,$s/</&lt;/g' >>$strfile
+ echo "</PRE>" >>$strfile
+ fail=`expr $fail + 1`
+else
+ echo "PASS: $count warning messages."
+ echo "<P>PASS: $count warning messages.</P>" >>$strfile
+fi
+
+# Notice log messages
+count=`$GREP '^N ' /tmp/cups-$user/log/error_log | wc -l | awk '{print $1}'`
+if test $count != 0; then
+ echo "FAIL: $count notice messages, expected 0."
+ $GREP '^N ' /tmp/cups-$user/log/error_log
+ echo "<P>FAIL: $count notice messages, expected 0.</P>" >>$strfile
+ echo "<PRE>" >>$strfile
+ $GREP '^N ' /tmp/cups-$user/log/error_log | sed -e '1,$s/&/&amp;/g' -e '1,$s/</&lt;/g' >>$strfile
+ echo "</PRE>" >>$strfile
+ fail=`expr $fail + 1`
+else
+ echo "PASS: $count notice messages."
+ echo "<P>PASS: $count notice messages.</P>" >>$strfile
+fi
+
+# Info log messages
+count=`$GREP '^I ' /tmp/cups-$user/log/error_log | wc -l | awk '{print $1}'`
+if test $count = 0; then
+ echo "FAIL: $count info messages, expected more than 0."
+ echo "<P>FAIL: $count info messages, expected more than 0.</P>" >>$strfile
+ fail=`expr $fail + 1`
+else
+ echo "PASS: $count info messages."
+ echo "<P>PASS: $count info messages.</P>" >>$strfile
+fi
+
+# Debug log messages
+count=`$GREP '^D ' /tmp/cups-$user/log/error_log | wc -l | awk '{print $1}'`
+if test $count = 0; then
+ echo "FAIL: $count debug messages, expected more than 0."
+ echo "<P>FAIL: $count debug messages, expected more than 0.</P>" >>$strfile
+ fail=`expr $fail + 1`
+else
+ echo "PASS: $count debug messages."
+ echo "<P>PASS: $count debug messages.</P>" >>$strfile
+fi
+
+# Debug2 log messages
+count=`$GREP '^d ' /tmp/cups-$user/log/error_log | wc -l | awk '{print $1}'`
+if test $count = 0; then
+ echo "FAIL: $count debug2 messages, expected more than 0."
+ echo "<P>FAIL: $count debug2 messages, expected more than 0.</P>" >>$strfile
+ fail=`expr $fail + 1`
+else
+ echo "PASS: $count debug2 messages."
+ echo "<P>PASS: $count debug2 messages.</P>" >>$strfile
+fi
+
+# Log files...
+echo "<H2>access_log</H2>" >>$strfile
+echo "<PRE>" >>$strfile
+sed -e '1,$s/&/&amp;/g' -e '1,$s/</&lt;/g' /tmp/cups-$user/log/access_log >>$strfile
+echo "</PRE>" >>$strfile
+
+echo "<H2>error_log</H2>" >>$strfile
+echo "<PRE>" >>$strfile
+$GREP -v '^d' /tmp/cups-$user/log/error_log | sed -e '1,$s/&/&amp;/g' -e '1,$s/</&lt;/g' >>$strfile
+echo "</PRE>" >>$strfile
+
+echo "<H2>page_log</H2>" >>$strfile
+echo "<PRE>" >>$strfile
+sed -e '1,$s/&/&amp;/g' -e '1,$s/</&lt;/g' /tmp/cups-$user/log/page_log >>$strfile
+echo "</PRE>" >>$strfile
+
+#
+# Format the reports and tell the user where to find them...
+#
+
+cat str-trailer.html >>$strfile
+
+echo ""
+
+if test $fail != 0; then
+ echo "$fail tests failed."
+ cp /tmp/cups-$user/log/error_log error_log-$date-$user
+ cp $strfile .
+else
+ echo "All tests were successful."
+fi
+
+echo "Log files can be found in /tmp/cups-$user/log."
+echo "A HTML report was created in $strfile."
+echo ""
+
+if test $fail != 0; then
+ echo "Copies of the error_log and `basename $strfile` files are in"
+ echo "`pwd`."
+ echo ""
+
+ exit 1
+fi
+
+#
+# End of "$Id$"
+#
diff --git a/test/set-attrs-hold.test b/test/set-attrs-hold.test
new file mode 100644
index 000000000..377819ae4
--- /dev/null
+++ b/test/set-attrs-hold.test
@@ -0,0 +1,180 @@
+# Test print-job and later job-hold-until attribute
+{
+ # The name of the test...
+ NAME "Disable printer..."
+
+ # The resource to use for the POST
+ RESOURCE /admin/
+
+ # The operation to use
+ OPERATION pause-printer
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
+
+{
+ # The name of the test...
+ NAME "Print job"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION print-job
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR mimetype document-format application/postscript
+
+ GROUP job
+ ATTR integer copies 1
+
+ FILE ../data/testprint.ps
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-id
+ EXPECT job-uri
+}
+
+{
+ # The name of the test...
+ NAME "Get job attrs"
+
+ # The resource to use for the POST
+ RESOURCE /
+
+ # The operation to use
+ OPERATION get-job-attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-state
+ EXPECT job-hold-until
+}
+
+{
+ # The name of the test...
+ NAME "Set job attrs with job-hold-until"
+
+ # The resource to use for the POST
+ # RESOURCE /admin
+
+ # The operation to use
+ OPERATION set-job-attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ GROUP job
+ ATTR name job-hold-until 00:30:00
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
+
+{
+ # The name of the test...
+ NAME "Get job attrs again"
+
+ # The resource to use for the POST
+ RESOURCE /
+
+ # The operation to use
+ OPERATION get-job-attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-state
+ EXPECT job-hold-until
+}
+
+{
+ # The name of the test...
+ NAME "Enable printer..."
+
+ # The resource to use for the POST
+ RESOURCE /admin/
+
+ # The operation to use
+ OPERATION resume-printer
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+}
+
+{
+ # The name of the test...
+ NAME "Get job attrs (last time)"
+
+ # The resource to use for the POST
+ RESOURCE /
+
+ # The operation to use
+ OPERATION get-job-attributes
+
+ # Attributes, starting in the operation group...
+ GROUP operation
+ ATTR charset attributes-charset utf-8
+ ATTR language attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+
+ # What statuses are OK?
+ STATUS ok
+ STATUS ok-subst
+
+ # What attributes do we expect?
+ EXPECT job-state
+ EXPECT job-hold-until
+}
diff --git a/test/str-header.html b/test/str-header.html
new file mode 100644
index 000000000..84f0d9b73
--- /dev/null
+++ b/test/str-header.html
@@ -0,0 +1,30 @@
+<HTML>
+<HEAD>
+ <META NAME="Description" CONTENT="CUPS Test Report">
+ <META NAME="COPYRIGHT" CONTENT="Copyright 2007-2010, All Rights Reserved">
+ <META NAME="DOCNUMBER" CONTENT="CUPS-STR-1.5">
+ <META NAME="Author" CONTENT="Apple Inc.">
+ <TITLE>CUPS 1.5 Software Test Report</TITLE>
+ <STYLE TYPE="text/css"><!--
+ PRE {
+ font-size: 80%;
+ margin-left: 2em;
+ }
+ --></STYLE>
+</HEAD>
+<BODY>
+
+<H1>CUPS 1.5 Software Test Report</H1>
+
+<P>This software test report provides detailed test results that
+are used to evaluate the stability and compliance of CUPS Version 1.5.
+
+<H2>Document Overview</H2>
+
+<P>This software test plan is organized into the following sections:
+
+<UL>
+ <LI>1 - IPP Compliance Tests</LI>
+ <LI>2 - Command Tests</LI>
+ <LI>3 - Log Files</LI>
+</UL>
diff --git a/test/str-trailer.html b/test/str-trailer.html
new file mode 100644
index 000000000..e04310fdd
--- /dev/null
+++ b/test/str-trailer.html
@@ -0,0 +1,2 @@
+</BODY>
+</HTML>
diff --git a/test/testfile.jpg b/test/testfile.jpg
new file mode 100644
index 000000000..418cb9359
--- /dev/null
+++ b/test/testfile.jpg
Binary files differ
diff --git a/test/testfile.pdf b/test/testfile.pdf
new file mode 100644
index 000000000..433577179
--- /dev/null
+++ b/test/testfile.pdf
Binary files differ
diff --git a/test/testfile.ps b/test/testfile.ps
new file mode 100644
index 000000000..d02503a1b
--- /dev/null
+++ b/test/testfile.ps
@@ -0,0 +1,598 @@
+%!PS-Adobe-3.0
+%%BoundingBox: 0 0 612 792
+%%Pages: 1
+%%LanguageLevel: 1
+%%DocumentData: Clean7Bit
+%%DocumentSuppliedResources: procset testprint/1.3
+%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman
+%%Creator: Michael Sweet, Apple Inc.
+%%CreationDate: D:20070606214000+0500
+%%Title: Test Page
+%%EndComments
+%%BeginProlog
+%%BeginResource procset testprint 1.3 0
+%
+% PostScript test page for CUPS.
+%
+% Copyright 2007-2011 Apple Inc.
+% Copyright 1993-2007 Easy Software Products
+%
+% These coded instructions, statements, and computer programs are the
+% property of Apple Inc. and are protected by Federal copyright law.
+% Distribution and use rights are outlined in the file "LICENSE.txt"
+% which is included with the CUPS source distribution.
+%
+/SEXTANT { % Draw a color wheel sextant...
+ % (name) white radius r g b SEXTANT -
+ % Loop through 100 shades...
+ 0 0.010101 0.98 {
+ % Set the color...
+ dup 0.75 le { % Get "white" value
+ % Start from black
+ dup 0.75 div % val2 = val / 0.75
+
+ 0 index 5 index mul % R = R * val2
+ 1 index 5 index mul % G = G * val2
+ 2 index 5 index mul % B = B * val2
+
+ 4 -1 roll pop % Discard val2
+ } {
+ % Fade to white
+ dup neg 1 add 4 mul % val2 = (1 - val) * 4
+
+ 0 index 5 index mul % R = R * val2
+ 1 index neg 1 add add % + (1 - val2)
+ 1 index 5 index mul % G = G * val2
+ 2 index neg 1 add add % + (1 - val2)
+ 2 index 5 index mul % B = B * val2
+ 3 index neg 1 add add % + (1 - val2)
+
+ 4 -1 roll pop % Discard val2
+ } ifelse
+ setrgbcolor % Set the color...
+
+ % Draw the polygon...
+ newpath % Start a new path...
+ dup 5 index mul % r1 = radius * val
+ 0 0 3 -1 roll 0 60 arc % Draw the inner arc
+
+ dup 0.010101 add 5 index mul% r2 = (radius + 0.010101) * val
+ 0 0 3 -1 roll 60 0 arcn % Draw the outer arc
+
+ closepath % Close the path
+ fill % Fill it...
+
+ pop % Pop value...
+ } for
+
+ % Draw a line around the polygons...
+ pop pop pop dup % Pop R, G, B, start
+ 0 setgray % Black
+ newpath
+ 0 0 moveto % Center
+ 0 0 3 -1 roll 0 60 arc % Arc around octant
+ closepath % Back to center
+ stroke % Stroke it...
+
+ % Draw the label...
+ dup % Save radius
+ dup 30 cos mul % X = radius * cos(30)
+ exch 30 sin mul % Y = radius * sin(30)
+ moveto % Position label
+
+ gsave
+ 30 rotate % Rotate label
+ dup 0.05 mul % Offset to the right
+ exch -0.05 mul % and down...
+ rmoveto % Offset label
+ show % Show label
+ grestore
+} bind def
+/CENTER { % Draw centered text
+ % (name) CENTER -
+ dup stringwidth pop % Get the width of the string
+ 0.5 mul neg 0 rmoveto % Shift left 1/2 of the distance
+ show % Show the string
+} bind def
+/RIGHT { % Draw right-justified text
+ % (name) RIGHT -
+ dup stringwidth pop % Get the width of the string
+ neg 0 rmoveto % Shift left the entire distance
+ show % Show the string
+} bind def
+/NUMBER { % Draw a number
+ % power n NUMBER -
+ 1 index 1 eq { % power == 1?
+ round cvi exch pop % Convert "n" to integer
+ } {
+ 1 index mul round exch div % Truncate extra decimal places
+ } ifelse
+ 100 string cvs show % Convert to a string and show it...
+} bind def
+/CUPSLOGO { % Draw the CUPS logo
+ % height CUPSLOGO
+ % Start with a big C...
+ /Helvetica findfont 1 index scalefont setfont
+ 0 setgray
+ 0 0 moveto
+ (C) show
+
+ % Then "UNIX Printing System" much smaller...
+ /Helvetica-Bold findfont 1 index 9 div scalefont setfont
+ 0.25 mul
+ dup dup 2.0 mul moveto
+ (UNIX) show
+ dup dup 1.6 mul moveto
+ (Printing) show
+ dup 1.2 mul moveto
+ (System) show
+} bind def
+%%EndResource
+%%EndProlog
+%%Page: 1 1
+gsave
+
+ % Determine the imageable area and device resolution...
+ initclip newpath clippath pathbbox % Get bounding rectangle
+ 72 div /pageTop exch def % Get top margin in inches
+ 72 div /pageRight exch def % Get right margin in inches
+ 72 div /pageBottom exch def % Get bottom margin in inches
+ 72 div /pageLeft exch def % Get left margin in inches
+
+ 4 setlinewidth % Draw wide lines
+ 0 setgray closepath stroke % Draw a clipping rectangle
+
+ /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft
+ /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom
+
+ 72 72 dtransform % Get device resolution per inch
+ /yResolution exch abs def % yResolution = abs(yres)
+ /xResolution exch abs def % xResolution = abs(xres)
+
+ % Figure out the sizes of things...
+ /wheelSize % size of wheels
+ pageWidth pageHeight lt
+ { pageWidth 9 mul }
+ { pageHeight 7 mul }
+ ifelse def
+
+ % Create fonts...
+ /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold
+ pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33)
+
+ /mediumFont /Helvetica findfont % mediumFont = Helvetica
+ pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5)
+
+ /smallFont /Times-Roman findfont % smallFont = Times-Roman
+ pageHeight scalefont def % size = pageHeight (nominally 11)
+
+ % Draw rulers along the edges...
+ /CENTIMETER 72 2.54 div def
+ /MILLIMETER 72 25.4 div def
+
+ /Times-Roman findfont % Font for ruler numbers
+ 11 scalefont setfont % 11 points
+
+ gsave % Left side inches
+ pageLeft 72 mul 0 translate % Offset left edge
+
+ 1 setlinewidth % Draw normal lines
+ 72 72 pageTop 72 mul { % Height inches
+ dup dup
+ 0 exch moveto 24 0 rlineto stroke % Draw tic mark
+ 24 exch pageHeight sub moveto % Draw number
+ 72 div cvi 10 string cvs RIGHT
+ } for
+
+ 0.5 setlinewidth % Draw thin lines
+ 18 18 pageTop 72 mul { % 1/4 inches
+ 0 exch moveto 15 0 rlineto stroke % Draw tic mark
+ } for
+
+ 9 9 pageTop 72 mul { % 1/8 inches
+ 0 exch moveto 6 0 rlineto stroke % Draw tic mark
+ } for
+ grestore
+
+ gsave % Bottom inches
+ 0 pageBottom 72 mul translate % Offset bottom edge
+
+ 1 setlinewidth % Draw normal lines
+ 72 72 pageRight 72 mul { % Width inches
+ dup dup
+ 0 moveto 0 24 rlineto stroke % Draw tic mark
+ 3 add 27 pageHeight sub moveto % Draw number
+ 72 div cvi 10 string cvs show
+ } for
+
+ 0.5 setlinewidth % Draw thin lines
+ 18 18 pageRight 72 mul { % 1/4 inches
+ 0 moveto 0 15 rlineto stroke % Draw tic mark
+ } for
+
+ 9 9 pageRight 72 mul { % 1/8 inches
+ 0 moveto 0 6 rlineto stroke % Draw tic mark
+ } for
+ grestore
+
+ gsave % Right side centimeters
+ pageRight 72 mul 0 translate % Offset right edge
+
+ 1 setlinewidth % Draw normal lines
+ CENTIMETER CENTIMETER
+ pageTop 72 mul { % Height centimeters
+ 0 exch moveto -24 0 rlineto stroke% Draw tic mark
+ } for
+ 1 1 pageTop 2.54 mul { % Height labels
+ dup
+ -24 exch CENTIMETER mul
+ pageHeight sub moveto % Draw number
+ cvi 10 string cvs show
+ } for
+
+ 0.5 setlinewidth % Draw thin lines
+ 0 0.5 CENTIMETER mul
+ pageTop 72 mul { % 1/2 centimeters
+ 0 exch moveto -15 0 rlineto stroke% Draw tic mark
+ } for
+ 0 MILLIMETER pageTop 72 mul { % Millimeters
+ 0 exch moveto -6 0 rlineto stroke % Draw tic mark
+ } for
+ grestore
+
+ gsave % Top centimeters
+ 0 pageTop 72 mul translate % Offset top edge
+
+ 1 setlinewidth % Draw normal lines
+ CENTIMETER CENTIMETER
+ pageRight 72 mul { % Width centimeters
+ 0 moveto 0 -24 rlineto stroke % Draw tic mark
+ } for
+ 1 1 pageRight 2.54 mul { % Width labels
+ dup
+ CENTIMETER mul 3 add -24 moveto % Draw number
+ cvi 10 string cvs show
+ } for
+
+ 0.5 setlinewidth % Draw thin lines
+ 0 0.5 CENTIMETER mul
+ pageRight 72 mul { % 1/2 centimeters
+ 0 moveto 0 -15 rlineto stroke % Draw tic mark
+ } for
+ 0 MILLIMETER pageRight 72 mul { % Millimeters
+ 0 moveto 0 -6 rlineto stroke % Draw tic mark
+ } for
+ grestore
+
+ % Offset page to account for lower-left margin...
+ pageLeft 72 mul
+ pageBottom 72 mul
+ translate
+
+ % Set text font and color...
+ mediumFont setfont % Font
+ 0 setgray % Color
+ 1 setlinewidth % Draw normal lines
+
+ % Draw the color wheel...
+ gsave
+ % Position the wheel on the left side...
+ pageWidth 18 mul % x = pageWidth * 1/4 * 72
+ pageHeight 54 mul % y = pageHeight * 3/4 * 72
+ translate
+
+ % Size the wheel...
+ wheelSize
+
+ % Draw the colors...
+ dup (C) 3 -1 roll 0 1 1 SEXTANT 60 rotate
+ dup (M) 3 -1 roll 1 0 1 SEXTANT 60 rotate
+ dup (Y) 3 -1 roll 1 1 0 SEXTANT 60 rotate
+ dup (R) 3 -1 roll 1 0 0 SEXTANT 60 rotate
+ dup (G) 3 -1 roll 0 1 0 SEXTANT 60 rotate
+ dup (B) 3 -1 roll 0 0 1 SEXTANT 60 rotate
+
+ pop
+ grestore
+
+ % Label the color wheel...
+ pageWidth 18 mul % x = pageWidth * 1/4 * 72
+ pageHeight 43 mul % y = pageHeight * 19/32 * 72
+ moveto % Position the text
+ (Color Wheel) CENTER % Show the text centered
+
+ % Draw the gray ramp...
+ gsave
+ % Position the gray ramp in the center...
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 54 mul % y = pageHeight * 3/4 * 72
+ wheelSize sub % - wheelSize
+ translate
+
+ % Loop through 100 shades...
+ 0 0.010101 0.98 {
+ % Set the color...
+ dup setgray % Set the grayscale...
+
+ % Draw the polygon...
+ newpath % Start a new path...
+
+ wheelSize -0.2 mul % X = -wheelSize / 5
+ 1 index 2 mul wheelSize mul % Y = val * 2 * wheelSize
+ moveto % Move there...
+
+ wheelSize 0.4 mul 0 rlineto % Right side...
+
+ wheelSize 0.2 mul % X = wheelSize / 5
+ 1 index 0.010101 add 2 mul wheelSize mul
+ % Y = (val + 0.010101) * 2 * wheelSize
+ lineto % Move there...
+
+ wheelSize -0.4 mul 0 rlineto % Left side...
+
+ closepath % Close the path
+ fill % Fill it...
+
+ pop % Pop value...
+ } for
+
+ 0 setgray % Black
+
+ newpath % Start a new path
+ wheelSize -0.2 mul 0 moveto % Bottom left
+ wheelSize 0.4 mul 0 rlineto % Bottom right
+ 0 wheelSize 2 mul rlineto % Upper right
+ wheelSize -0.4 mul 0 rlineto % Upper left
+ closepath % Close the path
+ stroke % Stroke it...
+
+ 0 wheelSize -0.2 mul moveto % Center bottom for label
+ (K) CENTER % Center K at bottom
+
+ 0 wheelSize 2.05 mul moveto % Center top for label
+ (W) CENTER % Center W at top
+ grestore
+
+ % Label the gray ramp...
+ pageWidth 36 mul % x = pageWidth * 1/2 * 72
+ pageHeight 43 mul % y = pageHeight * 19/32 * 72
+ moveto % Position the text
+ (Gray Ramp) CENTER % Show the text centered
+
+
+ % Draw radial lines...
+ gsave
+ 0 setlinewidth % 1 pixel lines
+
+ % Position the lines on the left side...
+ pageWidth 54 mul % x = pageWidth * 3/4 * 72
+ pageHeight 54 mul % y = pageHeight * 3/4 * 72
+ translate
+
+ % Size the wheel...
+ wheelSize
+
+ % Loop at 1 degree increments
+ 0 1 359 {
+ pop % Discard angle - not used
+ 0 0 moveto % Start line at the center
+ dup 0 lineto % Draw to the radius
+ 1 rotate % Rotate 1 degree
+ } for
+
+ pop % Discard radius - not needed anymore
+ stroke % Draw lines...
+
+ grestore
+
+ % Label the lines...
+ pageWidth 54 mul % x = pageWidth * 3/4 * 72
+ pageHeight 43 mul % y = pageHeight * 19/32 * 72
+ moveto % Position the text
+ (1 Degree Radial Lines) CENTER % Show the text centered
+
+ % Imageable area...
+ pageHeight 15 mul % Height of imageable area
+
+ pageWidth 4.5 mul % x = pageWidth * 1/16 * 72
+ pageHeight 35.5 mul % y = pageHeight * 1/2 * 72
+ 2 index sub % y -= height
+ pageWidth 28 mul % width = pageWidth * 1/4 * 72
+ 3 index % height
+ 0.5 setgray rectfill % Draw a shadow
+
+ pageWidth 4 mul % x = pageWidth * 1/16 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ 2 index sub % y -= height
+ pageWidth 28 mul % width = pageWidth * 3/8 * 72
+ 3 index % height
+ 4 copy 1 setgray rectfill % Clear the box to white
+ 0 setgray rectstroke % Draw a black box around it...
+
+ pop % Discard height
+
+ % Label the imageable area...
+ pageWidth 4 mul % x = pageWidth * 1/16 * 72
+ pageHeight 37 mul % y = pageHeight * 1/2 * 72
+ moveto % Position the text
+ mediumFont setfont % Font
+ (Imageable Area) show % Show the text
+
+ smallFont setfont % Font
+ pageWidth 14 mul % x = pageWidth * 3/16 * 72
+ pageHeight 36 mul % y = pageWidth * 1/2 * 72
+ pageHeight -2 mul add % y -= 2 * smallFont height
+
+ % Page Size inches
+ 2 copy moveto % Move to x & y
+ (Page Size: ) RIGHT % Label
+ 100 pageWidth NUMBER % pageWidth
+ (x) show % "x"
+ 100 pageHeight NUMBER % pageHeight
+ (in) show % "in"
+
+ % Page Size millimeters
+ pageHeight sub % Move down...
+
+ 2 copy moveto % Move to x & y
+ 10 pageWidth 25.4 mul NUMBER % pageWidth
+ (x) show % "x"
+ 10 pageHeight 25.4 mul NUMBER % pageHeight
+ (mm) show % "mm"
+
+ % Lower-left inches
+ pageHeight 2 mul sub % Move down...
+
+ 2 copy moveto % Move to x & y
+ (Lower-Left: ) RIGHT % Label
+ 100 pageLeft NUMBER % pageLeft
+ (x) show % "x"
+ 100 pageBottom NUMBER % pageBottom
+ (in) show % "in"
+
+ % Lower-left millimeters
+ pageHeight sub % Move down...
+
+ 2 copy moveto % Move to x & y
+ 10 pageLeft 25.4 mul NUMBER % pageLeft
+ (x) show % "x"
+ 10 pageBottom 25.4 mul NUMBER % pageBottom
+ (mm) show % "mm"
+
+ % Upper-right inches
+ pageHeight 2 mul sub % Move down...
+
+ 2 copy moveto % Move to x & y
+ (Upper-Right: ) RIGHT % Label
+ 100 pageRight NUMBER % pageRight
+ (x) show % "x"
+ 100 pageTop NUMBER % pageTop
+ (in) show % "in"
+
+ % Upper-right millimeters
+ pageHeight sub % Move down...
+
+ 2 copy moveto % Move to x & y
+ 10 pageRight 25.4 mul NUMBER % pageRight
+ (x) show % "x"
+ 10 pageTop 25.4 mul NUMBER % pageTop
+ (mm) show % "mm"
+
+ % Resolution dots-per-inch
+ pageHeight 2 mul sub % Move down...
+
+ 2 copy moveto % Move to x & y
+ (Resolution: ) RIGHT % Label
+ 1 xResolution NUMBER % xResolution
+ (x) show % "x"
+ 1 yResolution NUMBER % yResolution
+ (dpi) show % "dpi"
+
+ % Resolution dots-per-meter
+ pageHeight sub % Move down...
+
+ moveto % Move to x & y
+ 1 xResolution 39.27 mul NUMBER % xResolution
+ (x) show % "x"
+ 1 yResolution 39.27 mul NUMBER % yResolution
+ (dpm) show % "dpm"
+
+ % Interpreter Information...
+ pageHeight 15 mul % Height of interpreter information
+
+ pageWidth 40.5 mul % x = pageWidth * 9/16 * 72
+ pageHeight 35.5 mul % y = pageHeight * 1/2 * 72
+ 2 index sub % y -= height
+ pageWidth 28 mul % width = pageWidth * 1/4 * 72
+ 3 index % height
+ 0.5 setgray rectfill % Draw a shadow
+
+ pageWidth 40 mul % x = pageWidth * 9/16 * 72
+ pageHeight 36 mul % y = pageHeight * 1/2 * 72
+ 2 index sub % y -= height
+ pageWidth 28 mul % width = pageWidth * 3/8 * 72
+ 3 index % height
+ 4 copy 1 setgray rectfill % Clear the box to white
+ 0 setgray rectstroke % Draw a black box around it...
+
+ pop % Discard height
+
+ % Label the interpreter info...
+ pageWidth 40 mul % x = pageWidth * 9/16 * 72
+ pageHeight 37 mul % y = pageHeight * 1/2 * 72
+ moveto % Position the text
+ mediumFont setfont % Font
+ (Interpreter Information) show % Show the text
+
+ smallFont setfont % Font
+ pageWidth 49 mul % x = pageWidth * 11/16 * 72
+ pageHeight 36 mul % y = pageWidth * 1/2 * 72
+ pageHeight 2 mul sub % y -= 2 * smallFont height
+
+ % Language level
+ 2 copy moveto % Move to x & y
+ (PostScript: ) RIGHT % Label
+ (Level ) show % "Level "
+ 1 languagelevel NUMBER % Language level
+
+ % Version
+ pageHeight 2 mul sub % Move down...
+ 2 copy moveto % Move to x & y
+ (Version: ) RIGHT % Label
+ version show % Version
+ ( \() show % " ("
+ 1 revision NUMBER % Revision
+ (\)) show % ")"
+
+ % Product
+ pageHeight 2 mul sub % Move down...
+ 2 copy moveto % Move to x & y
+ (Product: ) RIGHT % Label
+ product show % Product name
+
+ % Serial Number
+ pageHeight 2 mul sub % Move down...
+ moveto % Move to x & y
+ (Serial #: ) RIGHT % Label
+ 1 serialnumber NUMBER % S/N
+
+ % Draw the label at the top...
+ pageWidth 36 mul % Center of page
+ pageHeight 66 mul % Top of page (11/12ths)
+ moveto % Position text
+ bigFont setfont % Font
+ (Printer Test Page) CENTER % Show text centered
+
+ % Draw the copyright notice at the bottom...
+ pageWidth 17 mul % Center of page
+ pageHeight 10 mul % Bottom of page
+ moveto % Position text
+ (Printed Using CUPS v1.3.x) show
+
+ pageWidth 17 mul % Left side of page
+ pageHeight 8 mul % Move down...
+ 2 copy moveto % Position text
+ smallFont setfont % Font
+ (Copyright 2007 Apple Inc., All Rights Reserved. CUPS and the CUPS logo are the trademark) show
+ pageHeight 2 add sub % Move down...
+ 2 copy moveto % Position text
+ (property of Apple Inc., 1 Infinite Loop, Cupertino, CA 95014, USA.) show
+ pageHeight 2 mul 4 add sub % Move down...
+ moveto % Position text
+ (Need help? Contact your operating system vendor or visit "http://www.cups.org/".) show
+
+ % Then the CUPS logo....
+ gsave
+ pageWidth 4 mul
+ pageHeight 4 mul
+ translate
+ pageWidth 15 mul CUPSLOGO
+ grestore
+
+% Show the page...
+grestore
+showpage
+%
+% End of "$Id: testfile.ps 9771 2011-05-12 05:21:56Z mike $".
+%
+%%EOF
diff --git a/test/testfile.txt b/test/testfile.txt
new file mode 100644
index 000000000..46bbf0848
--- /dev/null
+++ b/test/testfile.txt
@@ -0,0 +1,60 @@
+All work and no play makes Johhny a dull boy. All work and no
+play makes Johhny a dull boy. All work and no play makes Johhny
+a dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy. All
+work and no play makes Johhny a dull boy. All work and no play
+makes Johhny a dull boy. All work and no play makes Johhny a
+dull boy. All work and no play makes Johhny a dull boy.
diff --git a/test/testhp.ppd b/test/testhp.ppd
new file mode 100644
index 000000000..bc32a1288
--- /dev/null
+++ b/test/testhp.ppd
@@ -0,0 +1,187 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Test HP PPD file for CUPS.
+*%
+*% Copyright 2007-2011 by Apple Inc.
+*% Copyright 1997-2005 by Easy Software Products.
+*%
+*% These coded instructions, statements, and computer programs are the
+*% property of Apple Inc. 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
+*% file is missing or damaged, see the license at "http://www.cups.org/".
+*%
+*FormatVersion: "4.3"
+*FileVersion: "1.1"
+*LanguageVersion: English
+*LanguageEncoding: ISOLatin1
+*PCFileName: "TESTHP.PPD"
+*Manufacturer: "ESP"
+*Product: "(CUPS v1.5)"
+*cupsVersion: 1.1
+*cupsManualCopies: True
+*cupsFilter: "application/vnd.cups-raster 50 rastertohp"
+*cupsFilter2: "application/vnd.cups-raster application/vnd.hp-pcl 50 rastertohp"
+*ModelName: "Test HP Printer"
+*ShortNickName: "Test HP Printer"
+*NickName: "Test HP Printer CUPS v1.1"
+*PSVersion: "(3010.000) 550"
+*LanguageLevel: "3"
+*ColorDevice: True
+*DefaultColorSpace: RGB
+*FileSystem: False
+*Throughput: "1"
+*LandscapeOrientation: Plus90
+*VariablePaperSize: False
+*TTRasterizer: Type42
+
+*UIConstraints: *PageSize Executive *InputSlot Envelope
+*UIConstraints: *PageSize Letter *InputSlot Envelope
+*UIConstraints: *PageSize Legal *InputSlot Envelope
+*UIConstraints: *PageSize Tabloid *InputSlot Envelope
+*UIConstraints: *PageSize A3 *InputSlot Envelope
+*UIConstraints: *PageSize A4 *InputSlot Envelope
+*UIConstraints: *PageSize A5 *InputSlot Envelope
+*UIConstraints: *PageSize B5 *InputSlot Envelope
+*UIConstraints: *Resolution 600dpi *ColorModel CMYK
+
+*OpenUI *PageSize/Media Size: PickOne
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize Letter/US Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal/US Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize Executive/US Executive: "<</PageSize[522 756]/ImagingBBox null>>setpagedevice"
+*PageSize Tabloid/US Tabloid: "<</PageSize[792 1224]/ImagingBBox null>>setpagedevice"
+*PageSize A3/A3: "<</PageSize[842 1191]/ImagingBBox null>>setpagedevice"
+*PageSize A4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageSize A5/A5: "<</PageSize[421 595]/ImagingBBox null>>setpagedevice"
+*PageSize B5/B5 (JIS): "<</PageSize[516 729]/ImagingBBox null>>setpagedevice"
+*PageSize EnvISOB5/Envelope B5: "<</PageSize[499 709]/ImagingBBox null>>setpagedevice"
+*PageSize Env10/Envelope #10: "<</PageSize[297 684]/ImagingBBox null>>setpagedevice"
+*PageSize EnvC5/Envelope C5: "<</PageSize[459 649]/ImagingBBox null>>setpagedevice"
+*PageSize EnvDL/Envelope DL: "<</PageSize[312 624]/ImagingBBox null>>setpagedevice"
+*PageSize EnvMonarch/Envelope Monarch: "<</PageSize[279 540]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter/US Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal/US Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion Executive/US Executive: "<</PageSize[522 756]/ImagingBBox null>>setpagedevice"
+*PageRegion Tabloid/US Tabloid: "<</PageSize[792 1224]/ImagingBBox null>>setpagedevice"
+*PageRegion A3/A3: "<</PageSize[842 1191]/ImagingBBox null>>setpagedevice"
+*PageRegion A4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageRegion A5/A5: "<</PageSize[421 595]/ImagingBBox null>>setpagedevice"
+*PageRegion B5/B5 (JIS): "<</PageSize[516 729]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvISOB5/Envelope B5: "<</PageSize[499 709]/ImagingBBox null>>setpagedevice"
+*PageRegion Env10/Envelope #10: "<</PageSize[297 684]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvC5/Envelope C5: "<</PageSize[459 649]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvDL/Envelope DL: "<</PageSize[312 624]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvMonarch/Envelope Monarch: "<</PageSize[279 540]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: Letter
+*ImageableArea Letter/US Letter: "18 36 594 756"
+*ImageableArea Legal/US Legal: "18 36 594 972"
+*ImageableArea Executive/US Executive: "18 36 504 684"
+*ImageableArea Tabloid/US Tabloid: "18 36 774 1188"
+*ImageableArea A3/A3: "18 36 824 1155"
+*ImageableArea A4/A4: "18 36 577 806"
+*ImageableArea A5/A5: "18 36 403 559"
+*ImageableArea B5/JIS B5: "18 36 498 693"
+*ImageableArea EnvISOB5/B5 (ISO): "18 36 463 673"
+*ImageableArea Env10/Com-10: "18 36 279 648"
+*ImageableArea EnvC5/EnvC5: "18 36 441 613"
+*ImageableArea EnvDL/EnvDL: "18 36 294 588"
+*ImageableArea EnvMonarch/Envelope Monarch: "18 36 261 504"
+
+*DefaultPaperDimension: Letter
+*PaperDimension Letter/US Letter: "612 792"
+*PaperDimension Legal/US Legal: "612 1008"
+*PaperDimension Executive/US Executive: "522 756"
+*PaperDimension Tabloid/US Tabloid: "792 1224"
+*PaperDimension A3/A3: "842 1191"
+*PaperDimension A4/A4: "595 842"
+*PaperDimension A5/A5: "421 595"
+*PaperDimension B5/B5 (JIS): "516 729"
+*PaperDimension EnvISOB5/Envelope B5: "499 709"
+*PaperDimension Env10/Envelope #10: "297 684"
+*PaperDimension EnvC5/Envelope C5: "459 649"
+*PaperDimension EnvDL/Envelope DL: "312 624"
+*PaperDimension EnvMonarch/Envelope Monarch: "279 540"
+
+*OpenUI *MediaType/Media Type: PickOne
+*OrderDependency: 10 AnySetup *MediaType
+*DefaultMediaType: Plain
+*MediaType Plain/Plain Paper: "<</MediaType(Plain)/cupsMediaType 0>>setpagedevice"
+*MediaType Bond/Bond Paper: "<</MediaType(Bond)/cupsMediaType 1>>setpagedevice"
+*MediaType Special/Special Paper: "<</MediaType(Special)/cupsMediaType 2>>setpagedevice"
+*MediaType Transparency/Transparency: "<</MediaType(Transparency)/cupsMediaType 3>>setpagedevice"
+*MediaType Glossy/Glossy Paper: "<</MediaType(Glossy)/cupsMediaType 4>>setpagedevice"
+*CloseUI: *MediaType
+
+*OpenUI *InputSlot/Media Source: PickOne
+*OrderDependency: 10 AnySetup *InputSlot
+*DefaultInputSlot: Tray
+*InputSlot Tray/Tray: "<</cupsMediaPosition 1>>setpagedevice"
+*InputSlot Manual/Manual Feed: "<</cupsMediaPosition 2>>setpagedevice"
+*InputSlot Envelope/Envelope Feed: "<</cupsMediaPosition 3>>setpagedevice"
+*CloseUI: *InputSlot
+
+*OpenUI *Resolution/Output Resolution: PickOne
+*OrderDependency: 20 AnySetup *Resolution
+*DefaultResolution: 100dpi
+*Resolution 75dpi/75 DPI: "<</HWResolution[75 75]>>setpagedevice"
+*Resolution 100dpi/100 DPI: "<</HWResolution[100 100]>>setpagedevice"
+*CloseUI: *Resolution
+
+*OpenUI *ColorModel/Output Mode: PickOne
+*OrderDependency: 10 AnySetup *ColorModel
+*DefaultColorModel: CMYK
+*ColorModel CMYK/CMYK Color: "<</cupsColorOrder 1/cupsColorSpace 8/cupsCompression 2>>setpagedevice"
+*ColorModel RGB/CMY Color: "<</cupsColorOrder 1/cupsColorSpace 4/cupsCompression 2>>setpagedevice"
+*ColorModel Gray/Grayscale: "<</cupsColorOrder 0/cupsColorSpace 3/cupsCompression 2>>setpagedevice"
+*CloseUI: *ColorModel
+
+*DefaultFont: Courier
+*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM
+*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM
+*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM
+*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM
+*Font Bookman-Demi: Standard "(001.004S)" Standard ROM
+*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM
+*Font Bookman-Light: Standard "(001.004S)" Standard ROM
+*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM
+*Font Courier: Standard "(002.004S)" Standard ROM
+*Font Courier-Bold: Standard "(002.004S)" Standard ROM
+*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM
+*Font Courier-Oblique: Standard "(002.004S)" Standard ROM
+*Font Helvetica: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM
+*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM
+*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM
+*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM
+*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM
+*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM
+*Font Palatino-Bold: Standard "(001.005S)" Standard ROM
+*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM
+*Font Palatino-Italic: Standard "(001.005S)" Standard ROM
+*Font Palatino-Roman: Standard "(001.005S)" Standard ROM
+*Font Symbol: Special "(001.007S)" Special ROM
+*Font Times-Bold: Standard "(001.007S)" Standard ROM
+*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM
+*Font Times-Italic: Standard "(001.007S)" Standard ROM
+*Font Times-Roman: Standard "(001.007S)" Standard ROM
+*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM
+*Font ZapfDingbats: Special "(001.004S)" Standard ROM
+*%
+*% End of "$Id$".
+*%
diff --git a/test/testps.ppd b/test/testps.ppd
new file mode 100644
index 000000000..a200c4a50
--- /dev/null
+++ b/test/testps.ppd
@@ -0,0 +1,183 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Test PS PPD file for CUPS.
+*%
+*% Copyright 2007-2011 by Apple Inc.
+*% Copyright 1997-2005 by Easy Software Products.
+*%
+*% These coded instructions, statements, and computer programs are the
+*% property of Apple Inc. 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
+*% file is missing or damaged, see the license at "http://www.cups.org/".
+*%
+*FormatVersion: "4.3"
+*FileVersion: "1.1"
+*LanguageVersion: English
+*LanguageEncoding: ISOLatin1
+*PCFileName: "TESTPS.PPD"
+*Manufacturer: "ESP"
+*Product: "(CUPS v1.1)"
+*ModelName: "Test PS Printer"
+*ShortNickName: "Test PS Printer"
+*NickName: "Test PS Printer CUPS v1.1"
+*PSVersion: "(3010.000) 550"
+*LanguageLevel: "3"
+*ColorDevice: True
+*DefaultColorSpace: RGB
+*FileSystem: False
+*Throughput: "1"
+*LandscapeOrientation: Plus90
+*VariablePaperSize: False
+*TTRasterizer: Type42
+
+*UIConstraints: *PageSize Executive *InputSlot Envelope
+*UIConstraints: *PageSize Letter *InputSlot Envelope
+*UIConstraints: *PageSize Legal *InputSlot Envelope
+*UIConstraints: *PageSize Tabloid *InputSlot Envelope
+*UIConstraints: *PageSize A3 *InputSlot Envelope
+*UIConstraints: *PageSize A4 *InputSlot Envelope
+*UIConstraints: *PageSize A5 *InputSlot Envelope
+*UIConstraints: *PageSize B5 *InputSlot Envelope
+*UIConstraints: *Resolution 600dpi *ColorModel CMYK
+
+*OpenUI *PageSize/Media Size: PickOne
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize Letter/US Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageSize Legal/US Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageSize Executive/US Executive: "<</PageSize[522 756]/ImagingBBox null>>setpagedevice"
+*PageSize Tabloid/US Tabloid: "<</PageSize[792 1224]/ImagingBBox null>>setpagedevice"
+*PageSize A3/A3: "<</PageSize[842 1191]/ImagingBBox null>>setpagedevice"
+*PageSize A4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageSize A5/A5: "<</PageSize[421 595]/ImagingBBox null>>setpagedevice"
+*PageSize B5/B5 (JIS): "<</PageSize[516 729]/ImagingBBox null>>setpagedevice"
+*PageSize EnvISOB5/Envelope B5: "<</PageSize[499 709]/ImagingBBox null>>setpagedevice"
+*PageSize Env10/Envelope #10: "<</PageSize[297 684]/ImagingBBox null>>setpagedevice"
+*PageSize EnvC5/Envelope C5: "<</PageSize[459 649]/ImagingBBox null>>setpagedevice"
+*PageSize EnvDL/Envelope DL: "<</PageSize[312 624]/ImagingBBox null>>setpagedevice"
+*PageSize EnvMonarch/Envelope Monarch: "<</PageSize[279 540]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageSize
+
+*OpenUI *PageRegion: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter/US Letter: "<</PageSize[612 792]/ImagingBBox null>>setpagedevice"
+*PageRegion Legal/US Legal: "<</PageSize[612 1008]/ImagingBBox null>>setpagedevice"
+*PageRegion Executive/US Executive: "<</PageSize[522 756]/ImagingBBox null>>setpagedevice"
+*PageRegion Tabloid/US Tabloid: "<</PageSize[792 1224]/ImagingBBox null>>setpagedevice"
+*PageRegion A3/A3: "<</PageSize[842 1191]/ImagingBBox null>>setpagedevice"
+*PageRegion A4/A4: "<</PageSize[595 842]/ImagingBBox null>>setpagedevice"
+*PageRegion A5/A5: "<</PageSize[421 595]/ImagingBBox null>>setpagedevice"
+*PageRegion B5/B5 (JIS): "<</PageSize[516 729]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvISOB5/Envelope B5: "<</PageSize[499 709]/ImagingBBox null>>setpagedevice"
+*PageRegion Env10/Envelope #10: "<</PageSize[297 684]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvC5/Envelope C5: "<</PageSize[459 649]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvDL/Envelope DL: "<</PageSize[312 624]/ImagingBBox null>>setpagedevice"
+*PageRegion EnvMonarch/Envelope Monarch: "<</PageSize[279 540]/ImagingBBox null>>setpagedevice"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: Letter
+*ImageableArea Letter/US Letter: "18 36 594 756"
+*ImageableArea Legal/US Legal: "18 36 594 972"
+*ImageableArea Executive/US Executive: "18 36 504 684"
+*ImageableArea Tabloid/US Tabloid: "18 36 774 1188"
+*ImageableArea A3/A3: "18 36 824 1155"
+*ImageableArea A4/A4: "18 36 577 806"
+*ImageableArea A5/A5: "18 36 403 559"
+*ImageableArea B5/JIS B5: "18 36 498 693"
+*ImageableArea EnvISOB5/B5 (ISO): "18 36 463 673"
+*ImageableArea Env10/Com-10: "18 36 279 648"
+*ImageableArea EnvC5/EnvC5: "18 36 441 613"
+*ImageableArea EnvDL/EnvDL: "18 36 294 588"
+*ImageableArea EnvMonarch/Envelope Monarch: "18 36 261 504"
+
+*DefaultPaperDimension: Letter
+*PaperDimension Letter/US Letter: "612 792"
+*PaperDimension Legal/US Legal: "612 1008"
+*PaperDimension Executive/US Executive: "522 756"
+*PaperDimension Tabloid/US Tabloid: "792 1224"
+*PaperDimension A3/A3: "842 1191"
+*PaperDimension A4/A4: "595 842"
+*PaperDimension A5/A5: "421 595"
+*PaperDimension B5/B5 (JIS): "516 729"
+*PaperDimension EnvISOB5/Envelope B5: "499 709"
+*PaperDimension Env10/Envelope #10: "297 684"
+*PaperDimension EnvC5/Envelope C5: "459 649"
+*PaperDimension EnvDL/Envelope DL: "312 624"
+*PaperDimension EnvMonarch/Envelope Monarch: "279 540"
+
+*OpenUI *MediaType/Media Type: PickOne
+*OrderDependency: 10 AnySetup *MediaType
+*DefaultMediaType: Plain
+*MediaType Plain/Plain Paper: "<</MediaType(Plain)/cupsMediaType 0>>setpagedevice"
+*MediaType Bond/Bond Paper: "<</MediaType(Bond)/cupsMediaType 1>>setpagedevice"
+*MediaType Special/Special Paper: "<</MediaType(Special)/cupsMediaType 2>>setpagedevice"
+*MediaType Transparency/Transparency: "<</MediaType(Transparency)/cupsMediaType 3>>setpagedevice"
+*MediaType Glossy/Glossy Paper: "<</MediaType(Glossy)/cupsMediaType 4>>setpagedevice"
+*CloseUI: *MediaType
+
+*OpenUI *InputSlot/Media Source: PickOne
+*OrderDependency: 10 AnySetup *InputSlot
+*DefaultInputSlot: Tray
+*InputSlot Tray/Tray: "<</cupsMediaPosition 1>>setpagedevice"
+*InputSlot Manual/Manual Feed: "<</cupsMediaPosition 2>>setpagedevice"
+*InputSlot Envelope/Envelope Feed: "<</cupsMediaPosition 3>>setpagedevice"
+*CloseUI: *InputSlot
+
+*OpenUI *Resolution/Output Resolution: PickOne
+*OrderDependency: 20 AnySetup *Resolution
+*DefaultResolution: 100dpi
+*Resolution 75dpi/75 DPI: "<</HWResolution[75 75]>>setpagedevice"
+*Resolution 100dpi/100 DPI: "<</HWResolution[100 100]>>setpagedevice"
+*CloseUI: *Resolution
+
+*OpenUI *ColorModel/Output Mode: PickOne
+*OrderDependency: 10 AnySetup *ColorModel
+*DefaultColorModel: CMYK
+*ColorModel CMYK/CMYK Color: "<</cupsColorOrder 1/cupsColorSpace 8/cupsCompression 2>>setpagedevice"
+*ColorModel RGB/CMY Color: "<</cupsColorOrder 1/cupsColorSpace 4/cupsCompression 2>>setpagedevice"
+*ColorModel Gray/Grayscale: "<</cupsColorOrder 0/cupsColorSpace 3/cupsCompression 2>>setpagedevice"
+*CloseUI: *ColorModel
+
+*DefaultFont: Courier
+*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM
+*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM
+*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM
+*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM
+*Font Bookman-Demi: Standard "(001.004S)" Standard ROM
+*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM
+*Font Bookman-Light: Standard "(001.004S)" Standard ROM
+*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM
+*Font Courier: Standard "(002.004S)" Standard ROM
+*Font Courier-Bold: Standard "(002.004S)" Standard ROM
+*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM
+*Font Courier-Oblique: Standard "(002.004S)" Standard ROM
+*Font Helvetica: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM
+*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM
+*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM
+*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM
+*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM
+*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM
+*Font Palatino-Bold: Standard "(001.005S)" Standard ROM
+*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM
+*Font Palatino-Italic: Standard "(001.005S)" Standard ROM
+*Font Palatino-Roman: Standard "(001.005S)" Standard ROM
+*Font Symbol: Special "(001.007S)" Special ROM
+*Font Times-Bold: Standard "(001.007S)" Standard ROM
+*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM
+*Font Times-Italic: Standard "(001.007S)" Standard ROM
+*Font Times-Roman: Standard "(001.007S)" Standard ROM
+*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM
+*Font ZapfDingbats: Special "(001.004S)" Standard ROM
+*%
+*% End of "$Id$".
+*%
diff --git a/test/waitjobs.sh b/test/waitjobs.sh
new file mode 100755
index 000000000..7a79fb69b
--- /dev/null
+++ b/test/waitjobs.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+#
+# "$Id$"
+#
+# Script to wait for jobs to complete.
+#
+# Copyright 2008-2009 by Apple Inc.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+#
+# Get timeout from command-line
+#
+
+if test $# = 1; then
+ timeout=$1
+else
+ timeout=360
+fi
+
+#
+# Figure out the proper echo options...
+#
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ ac_n=-n
+ ac_c=
+else
+ ac_n=
+ ac_c='\c'
+fi
+
+echo $ac_n "Waiting for jobs to complete...$ac_c"
+oldjobs=0
+
+while test $timeout -gt 0; do
+ jobs=`../systemv/lpstat 2>/dev/null | wc -l | tr -d ' '`
+ if test $jobs = 0; then
+ break
+ fi
+
+ if test $jobs != $oldjobs; then
+ echo $ac_n "$jobs...$ac_c"
+ oldjobs=$jobs
+ fi
+
+ sleep 5
+ timeout=`expr $timeout - 5`
+done
+
+echo ""
+
+#
+# End of "$Id$".
+#
diff --git a/tools/checkglobals b/tools/checkglobals
new file mode 100755
index 000000000..4d15387ea
--- /dev/null
+++ b/tools/checkglobals
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# Check for global symbols that don't need to be made global...
+#
+
+for file in *.o; do
+ functions=""
+
+ for function in `nm -g $file | grep "T " | awk '{print $3}'`; do
+ found=""
+ for file2 in *.o; do
+ if test "$file" = "$file2"; then
+ continue;
+ fi
+
+ found=`nm -g $file2 | grep $function`
+ if test "$found" != ""; then
+ break;
+ fi
+ done
+
+ if test -z "$found"; then
+ functions="$functions $function"
+ fi
+ done
+
+ if test -z "$functions"; then
+ echo "$file: OK"
+ else
+ echo "$file: $functions"
+ fi
+done
diff --git a/tools/listpublic b/tools/listpublic
new file mode 100755
index 000000000..d864e7ee6
--- /dev/null
+++ b/tools/listpublic
@@ -0,0 +1,12 @@
+#!/bin/sh
+#
+# List public API symbols...
+#
+
+for function in `nm -g *.so | grep "T " | awk '{print $3}' | grep -v '^_' | sort`; do
+ found=`grep $function\( *.h | grep -v DEPRECATED`
+
+ if test "x$found" != x; then
+ echo $function
+ fi
+done
diff --git a/tools/makeipptoolpkg b/tools/makeipptoolpkg
new file mode 100755
index 000000000..6d34c5602
--- /dev/null
+++ b/tools/makeipptoolpkg
@@ -0,0 +1,84 @@
+#!/bin/sh
+#
+# "$Id: makeipptoolpkg 9543 2011-02-17 23:43:53Z mike $"
+#
+# Make an ipptool package for CUPS.
+#
+# Copyright 2007-2011 by Apple Inc.
+# Copyright 1997-2007 by Easy Software Products, all rights reserved.
+#
+# These coded instructions, statements, and computer programs are the
+# property of Apple Inc. 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
+# file is missing or damaged, see the license at "http://www.cups.org/".
+#
+
+# Make sure we are running in the right directory...
+if test ! -f tools/makeipptoolpkg; then
+ echo "Run this script from the top-level CUPS source directory, e.g.:"
+ echo ""
+ echo " tools/makeipptoolpkg $*"
+ echo ""
+ exit 1
+fi
+
+if test $# = 0; then
+ echo Updating to get snapshot version...
+ svn up
+ rev=`svnversion . | sed -e '1,$s/[a-zA-Z]//g'`
+ fileversion="1.5svn-r$rev"
+ version=snapshots
+else
+ fileversion=$1
+ version=$1
+fi
+
+if (svn st | grep -qv '^\?'); then
+ echo Local changes remain:
+ svn st | grep -v '^\?'
+ exit 1
+fi
+
+echo Creating package directory...
+pkgdir="ipptool-$fileversion"
+
+test -d $pkgdir && rm -r $pkgdir
+mkdir $pkgdir || exit 1
+
+echo Copying package files
+cp IPPTOOL.txt LICENSE.txt $pkgdir
+cp doc/help/man-ipptool*.html $pkgdir
+cp test/create-printer-subscription.test $pkgdir
+cp test/get-completed-jobs.test test/get-jobs.test $pkgdir
+cp test/get-printer-attributes.test $pkgdir
+cp test/ipp-[12].*.test $pkgdir
+cp test/ipptool-static $pkgdir/ipptool
+cp test/testfile.* $pkgdir
+
+if test `uname` = Darwin; then
+ echo Creating disk image...
+ pkgfile="$pkgdir-macosx-universal.dmg"
+ test -f $pkgfile && rm $pkgfile
+ hdiutil create -srcfolder $pkgdir $pkgfile
+ #sudo chown `whoami` $pkgfile
+else
+ echo Creating archive...
+ pkgfile="$pkgdir-`uname`-`uname -m`.tar.gz"
+ tar czf $pkgfile $pkgdir || exit 1
+fi
+
+if test -x /usr/bin/md5sum; then
+ (md5sum $pkgfile | awk '{print $1, "'$fileversion' cups/'$version'/" $2}')
+elif test -x /sbin/md5; then
+ (md5 $pkgfile | awk '{print $4, "'$fileversion' cups/'$version'/" substr($2, 2, length($2) - 2)}')
+fi
+
+echo Removing temporary files...
+rm -r $pkgdir
+
+echo "Done!"
+
+#
+# End of "$Id: makeipptoolpkg 9543 2011-02-17 23:43:53Z mike $".
+#
diff --git a/tools/makesrcdist b/tools/makesrcdist
new file mode 100755
index 000000000..786a2043b
--- /dev/null
+++ b/tools/makesrcdist
@@ -0,0 +1,91 @@
+#!/bin/sh
+#
+# "$Id: makesrcdist 9086 2010-04-07 18:46:04Z mike $"
+#
+# makesrcdist - make a source distribution of CUPS.
+#
+
+# Make sure we are running in the right directory...
+if test ! -f tools/makesrcdist; then
+ echo "Run this script from the top-level CUPS source directory, e.g.:"
+ echo ""
+ echo " tools/makesrcdist $*"
+ echo ""
+ exit 1
+fi
+
+if test $# = 0; then
+ echo Updating for snapshot...
+ svn up
+ rev=`svnversion . | sed -e '1,$s/[a-zA-Z]//g'`
+ version="1.5svn"
+ revision="-r$rev"
+ fileversion="1.5svn-r$rev"
+ fileurl="http://ftp.easysw.com/pub/cups/test/cups-$fileversion-source.tar."
+ url="."
+else
+ echo Creating tag for release...
+ rev="1"
+ version=$1
+ revision=""
+ fileversion=$1
+ fileurl="http://ftp.easysw.com/pub/cups/$version/cups-$fileversion-source.tar."
+ url="https://svn.easysw.com/public/cups/tags/release-$version"
+
+ svn copy https://svn.easysw.com/public/cups/trunk "$url" \
+ -m "Tag $version" || exit 1
+fi
+
+fileurl=`echo $fileurl | sed -e '1,$s/\\//\\\\\\//g'`
+
+echo Exporting $fileversion...
+rm -rf /tmp/cups-$version
+svn export $url /tmp/cups-$version
+
+echo Updating version information...
+cd /tmp/cups-$version/config-scripts
+
+sed -e '1,$s/^CUPS_VERSION=.*/CUPS_VERSION='$version'/' \
+ -e '1,$s/^CUPS_REVISION=.*/CUPS_REVISION='$revision'/' \
+ <cups-common.m4 >cups-common.m4.new
+mv cups-common.m4.new cups-common.m4
+cd ..
+
+echo Configuring...
+autoconf -f
+rm -rf autom4te*.cache
+rm -rf standards
+rm -rf tools
+cd ..
+
+echo -n Archiving...gz
+sed -e '1,$s/@CUPS_VERSION@/'$version'/' \
+ -e '1,$s/^Release:.*/Release: '$rev'/' \
+ -e '1,$s/^Source:.*/Source: '$fileurl'gz/' \
+ <cups-$version/packaging/cups.spec.in \
+ >cups-$version/packaging/cups.spec
+tar czf cups-$fileversion-source.tar.gz cups-$version
+
+echo -n ...bz2
+sed -e '1,$s/@CUPS_VERSION@/'$version'/' \
+ -e '1,$s/^Release:.*/Release: '$rev'/' \
+ -e '1,$s/^Source:.*/Source: '$fileurl'bz2/' \
+ <cups-$version/packaging/cups.spec.in \
+ >cups-$version/packaging/cups.spec
+tar cjf cups-$fileversion-source.tar.bz2 cups-$version
+echo "..."
+
+if test -x /usr/bin/md5sum; then
+ (cd /tmp; md5sum cups-$fileversion-source.tar.* | awk '{print $1, "'$fileversion' cups/'$fileversion'/" $2}')
+elif test -x /sbin/md5; then
+ (cd /tmp; md5 cups-$fileversion-source.tar.* | awk '{print $4, "'$fileversion' cups/'$fileversion'/" substr($2, 2, length($2) - 2)}')
+fi
+
+echo Removing temporary files...
+rm -rf cups-$version
+
+echo "Done!"
+
+#
+# End of "$Id: makesrcdist 9086 2010-04-07 18:46:04Z mike $".
+#
diff --git a/tools/pdftops-darwin.sh b/tools/pdftops-darwin.sh
new file mode 100755
index 000000000..07d3224c5
--- /dev/null
+++ b/tools/pdftops-darwin.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+#
+# Script to simulate Xpdf/Poppler's pdftops program.
+#
+
+options=""
+
+while test $# -gt 0; do
+ option="$1"
+ shift
+
+ case "$option" in
+ -expand)
+ options="$options fit-to-page"
+ ;;
+ -h)
+ echo "Usage: pdftops [options] filename"
+ echo "Options:"
+ echo " -expand"
+ echo " -h"
+ echo " -level1"
+ echo " -level2"
+ echo " -level3"
+ echo " -noembtt"
+ echo " -origpagesizes"
+ echo " -paperw width-points"
+ echo " -paperh length-points"
+ echo ""
+ echo "THIS IS A COMPATIBILITY WRAPPER"
+ exit 0
+ ;;
+ -paperw | -paperh)
+ # Ignore width/length in points
+ shift
+ ;;
+ -*)
+ # Ignore everything else
+ ;;
+ *)
+ /usr/libexec/cups/filter/cgpdftops job user title 1 "$options" "$option"
+ exit $?
+ ;;
+ esac
+done
diff --git a/tools/products.php b/tools/products.php
new file mode 100755
index 000000000..9c2e7430e
--- /dev/null
+++ b/tools/products.php
@@ -0,0 +1,50 @@
+#!/usr/bin/php -f
+<?php
+
+$fp = popen("zgrep '^\\*Product:' /Library/Printers/PPDs/Contents/Resources/*.gz", "r");
+$files = array();
+$maxlen = 0;
+
+while ($line = fgets($fp, 1024))
+{
+ $data = explode(":", $line);
+ if (array_key_exists($data[0], $files))
+ $files[$data[0]] ++;
+ else
+ $files[$data[0]] = 1;
+
+ $data = explode("\"", $line);
+ if (strlen($data[1]) > $maxlen)
+ $maxlen = strlen($data[1]);
+}
+
+pclose($fp);
+
+arsort($files);
+
+$current_count = 0;
+$current_files = 0;
+
+foreach ($files as $file => $count)
+{
+ if ($current_count == 0)
+ print(basename($file) . " => $count products\n");
+
+ if ($count != $current_count)
+ {
+ if ($current_count != 0)
+ print("$current_files PPDs with $current_count products.\n");
+
+ $current_count = $count;
+ $current_files = 1;
+ }
+ else
+ $current_files ++;
+}
+
+if ($current_count != 0)
+ print("$current_files PPDs with $current_count products.\n");
+
+print("Maximum length of Product string: $maxlen\n");
+
+?>
diff --git a/tools/testosx b/tools/testosx
new file mode 100755
index 000000000..4547977f2
--- /dev/null
+++ b/tools/testosx
@@ -0,0 +1,137 @@
+#!/bin/sh
+# Make sure we are running in the right directory...
+if test ! -f tools/testosx; then
+ echo "Run this script from the top-level CUPS source directory, e.g.:"
+ echo ""
+ echo " sudo tools/testosx [version]"
+ echo ""
+ exit 1
+fi
+
+if test `whoami` != root; then
+ echo "Run this script with sudo, e.g.:"
+ echo ""
+ echo " sudo tools/testosx [version]"
+ echo ""
+ exit 1
+fi
+
+# Get the current working copy version...
+rev=`svnversion . | awk -F: '{print $NF}' | sed -e '1,$s/[a-zA-Z]*//g'`
+
+if test $# = 0; then
+ version="1.5svn-r$rev"
+else
+ version=$1
+fi
+
+# Setup an install directory...
+user=`whoami`
+topdir=`pwd`
+pkgdir="/tmp/cups.pkg-$user"
+
+echo Building package using temp directory $pkgdir...
+rm -rf $pkgdir
+mkdir -p $pkgdir/Package
+mkdir -p $pkgdir/Resources
+
+# Install resource files into the Resources directory...
+echo Installing resource files...
+cp packaging/LICENSE.rtf $pkgdir/Resources/ReadMe.rtf
+sed -e '1,$s/@CUPS_VERSION@/'$version'/g' \
+ <packaging/WELCOME.rtf >$pkgdir/Resources/Welcome.rtf
+cp packaging/installer.tif $pkgdir/Resources/background.tif
+
+if test -x /bin/launchctl; then
+ cat >$pkgdir/Resources/preflight <<EOF
+#!/bin/sh
+# Tell launchd to stop cupsd...
+if test "x`whoami`" = xroot; then
+ sudo launchctl unload /System/Library/LaunchDaemons/org.cups.cupsd.plist || exit 0
+ sudo launchctl unload /System/Library/LaunchDaemons/org.cups.cups-lpd.plist || exit 0
+fi
+killall cupsd || exit 0
+EOF
+else
+ cat >$pkgdir/Resources/preflight <<EOF
+#!/bin/sh
+# Stop any running cupsd processes...
+killall cupsd || exit 0
+EOF
+fi
+
+chmod 755 $pkgdir/Resources/preflight
+
+if test -x /bin/launchctl; then
+ cat >$pkgdir/Resources/postflight <<EOF
+#!/bin/sh
+
+# Remove old xinetd config file, we use launchd now...
+rm -f /etc/xinetd.d/cups-lpd
+
+# Tell launchd to reload cupsd...
+if test "x`whoami`" = xroot; then
+ sudo launchctl load /System/Library/LaunchDaemons/org.cups.cupsd.plist
+ sudo launchctl load /System/Library/LaunchDaemons/org.cups.cupsd-lpd.plist || exit 0
+fi
+EOF
+else
+ cat >$pkgdir/Resources/postflight <<EOF
+#!/bin/sh
+
+# Start cupsd...
+/usr/sbin/cupsd
+EOF
+fi
+
+chmod 755 $pkgdir/Resources/postflight
+
+case `uname -r` in
+ 8.* | 9.*)
+ cp packaging/InstallationCheck $pkgdir/Resources
+ chmod 755 $pkgdir/Resources/InstallationCheck
+ ;;
+esac
+
+# Tag the current revision in the plist and web interface files...
+for file in packaging/cups-desc.plist packaging/cups-info.plist \
+ doc/index.html templates/header.tmpl; do
+ echo Updating $file...
+ sed -e '1,$s/@CUPS_VERSION@/'$version'/g' \
+ -e '1,$s/@CUPS_REVISION@//g' \
+ -e '1,$s/@CUPS_RELEASE@/1.5.'$rev'/g' \
+ <$file.in >$file
+done
+
+# Install CUPS into the Package directory...
+#make INSTALL=$topdir/install-sh BUILDROOT=$pkgdir/Package install
+make BUILDROOT=$pkgdir/Package install || exit 1
+
+# Figure out where PackageMaker is installled...
+if test -d /Developer/Applications/Utilities/PackageMaker.app; then
+ PackageMaker=/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker
+else
+ PackageMaker=/Developer/Applications/PackageMaker.app/Contents/MacOS/PackageMaker
+fi
+
+# Create the package...
+echo Creating MacOS X package...
+rm -rf cups.pkg
+echo $PackageMaker -build -v -p cups.pkg \
+ -f $pkgdir/Package \
+ -r $pkgdir/Resources \
+ -d packaging/cups-desc.plist \
+ -i packaging/cups-info.plist
+$PackageMaker -build -v -p cups.pkg \
+ -f $pkgdir/Package \
+ -r $pkgdir/Resources \
+ -d packaging/cups-desc.plist \
+ -i packaging/cups-info.plist
+
+# Create a disk image...
+echo Creating MacOS X disk image...
+hdiutil create -ov -srcfolder cups.pkg cups-$version.dmg
+
+# Cleanup temp files...
+echo Removing temporary files...
+#rm -rf $pkgdir
diff --git a/tools/testrpm b/tools/testrpm
new file mode 100755
index 000000000..7d4e9e4a3
--- /dev/null
+++ b/tools/testrpm
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# "$Id: testrpm 5304 2006-03-18 01:21:37Z mike $"
+#
+# Test script for making RPMs...
+#
+
+# Make sure we are running in the right directory...
+if test ! -f tools/testrpm; then
+ echo "Run this script from the top-level CUPS source directory, e.g.:"
+ echo ""
+ echo " tools/testrpm [rpmbuild options]"
+ echo ""
+ exit 1
+fi
+
+# Strip command-line arguments so we don't create a release tag...
+args="$*"
+shift $#
+
+# Get a snapshot of the current source...
+. tools/makesrcdist
+
+# Build the RPM...
+echo Building rpm...
+rm -f /usr/src/redhat/RPMS/i386/cups*.rpm
+rm -f /usr/src/redhat/SRPMS/cups*.rpm
+rpmbuild -ta $args cups-$fileversion-source.tar.bz2
+
+#
+# End of "$Id: testrpm 5304 2006-03-18 01:21:37Z mike $".
+#
diff --git a/vc2005/cups.sln b/vc2005/cups.sln
new file mode 100644
index 000000000..e510e163c
--- /dev/null
+++ b/vc2005/cups.sln
@@ -0,0 +1,78 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcups2", "libcups2.vcproj", "{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcupsimage2", "libcupsimage2.vcproj", "{CB4AA6F2-3E84-45BE-B505-95CD375E1234}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testfile", "testfile.vcproj", "{CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testhttp", "testhttp.vcproj", "{90B0058C-8393-411F-BD3B-E2C831D4E883}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cupstestppd", "cupstestppd.vcproj", "{6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234} = {CB4AA6F2-3E84-45BE-B505-95CD375E1234}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|Win32.Build.0 = Debug|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|x64.ActiveCfg = Debug|x64
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|x64.Build.0 = Debug|x64
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|Win32.ActiveCfg = Debug|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|Win32.Build.0 = Debug|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|x64.ActiveCfg = Debug|x64
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|x64.Build.0 = Debug|x64
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Debug|Win32.Build.0 = Debug|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Debug|x64.ActiveCfg = Debug|x64
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Debug|x64.Build.0 = Debug|x64
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Release|Win32.ActiveCfg = Release|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Release|Win32.Build.0 = Release|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Release|x64.ActiveCfg = Release|x64
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Release|x64.Build.0 = Release|x64
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Debug|Win32.Build.0 = Debug|Win32
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Debug|x64.ActiveCfg = Debug|x64
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Debug|x64.Build.0 = Debug|x64
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|Win32.ActiveCfg = Debug|Win32
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|Win32.Build.0 = Debug|Win32
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|x64.ActiveCfg = Debug|x64
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|x64.Build.0 = Debug|x64
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Debug|Win32.ActiveCfg = Debug|Win32
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Debug|Win32.Build.0 = Debug|Win32
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Debug|x64.ActiveCfg = Debug|x64
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Debug|x64.Build.0 = Debug|x64
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Release|Win32.ActiveCfg = Debug|Win32
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Release|Win32.Build.0 = Debug|Win32
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Release|x64.ActiveCfg = Debug|x64
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Release|x64.Build.0 = Debug|x64
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Debug|Win32.Build.0 = Debug|Win32
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Debug|x64.ActiveCfg = Debug|x64
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Debug|x64.Build.0 = Debug|x64
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Release|Win32.ActiveCfg = Release|Win32
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Release|Win32.Build.0 = Release|Win32
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Release|x64.ActiveCfg = Release|x64
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/vc2005/cupstestppd.vcproj b/vc2005/cupstestppd.vcproj
new file mode 100644
index 000000000..479afcc1d
--- /dev/null
+++ b/vc2005/cupstestppd.vcproj
@@ -0,0 +1,356 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="cupstestppd"
+ ProjectGUID="{6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}"
+ RootNamespace="cupstestppd"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..;..\vcnet"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..;..\vcnet"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..;..\vcnet"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..;..\vcnet"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\systemv\cupstestppd.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vc2005/ipptool.vcproj b/vc2005/ipptool.vcproj
new file mode 100644
index 000000000..271187b54
--- /dev/null
+++ b/vc2005/ipptool.vcproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="cupstestppd"
+ ProjectGUID="{B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}"
+ RootNamespace="ipptool"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet;.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\vcnet;.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\test\ipptool.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vc2005/libcups2.vcproj b/vc2005/libcups2.vcproj
new file mode 100644
index 000000000..049818580
--- /dev/null
+++ b/vc2005/libcups2.vcproj
@@ -0,0 +1,1611 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="libcups2"
+ ProjectGUID="{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib advapi32.lib"
+ OutputFile="$(OutDir)\libcups2.dll"
+ LinkIncremental="2"
+ ModuleDefinitionFile="..\cups\libcups2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\libcups2.pdb"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)\libcups2.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib advapi32.lib"
+ OutputFile="$(OutDir)\libcups2.dll"
+ LinkIncremental="2"
+ ModuleDefinitionFile="..\cups\libcups2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\libcups2.pdb"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)\libcups2.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib advapi32.lib"
+ OutputFile="$(OutDir)\libcups2.dll"
+ LinkIncremental="1"
+ ModuleDefinitionFile="..\cups\libcups2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="libcups2.pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ImportLibrary="$(OutDir)\libcups2.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot; &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib advapi32.lib"
+ OutputFile="$(OutDir)\libcups2.dll"
+ LinkIncremental="1"
+ ModuleDefinitionFile="..\cups\libcups2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="libcups2.pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ImportLibrary="$(OutDir)\libcups2.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot; &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\cups\adminutil.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\array.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\attr.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\auth.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\backend.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\conflicts.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\custom.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\dest.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\dir.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\emit.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\encode.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\file.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\getdevices.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\getputfile.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\globals.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\http-addr.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\http-addrlist.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\http-support.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\http.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\ipp-support.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\ipp.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\langprintf.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\language.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\localize.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\mark.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\md5.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\md5passwd.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\notify.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\options.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\page.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\ppd.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\pwg-file.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\pwg-media.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\pwg-ppd.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\request.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\snmp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\snprintf.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\sspi.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\string.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\tempfile.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\thread.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\transcode.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\usersys.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\util.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\cups\adminutil.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\array.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\backend.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\cups-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\cups.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\debug-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\dir.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\file-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\file.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\http-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\http.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\ipp-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\ipp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\language-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\language.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\md5-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\ppd-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\ppd.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\pwg-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\sspi-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\string-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\thread-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\transcode.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\versioning.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vc2005/libcupsimage2.vcproj b/vc2005/libcupsimage2.vcproj
new file mode 100644
index 000000000..bb1f9efb4
--- /dev/null
+++ b/vc2005/libcupsimage2.vcproj
@@ -0,0 +1,395 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="libcupsimage2"
+ ProjectGUID="{CB4AA6F2-3E84-45BE-B505-95CD375E1234}"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ OutputFile="$(OutDir)\libcupsimage2.dll"
+ LinkIncremental="2"
+ ModuleDefinitionFile="..\filter\libcupsimage2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\libcupsimage2.pdb"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)\libcupsimage2.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ OutputFile="$(OutDir)\libcupsimage2.dll"
+ LinkIncremental="2"
+ ModuleDefinitionFile="..\filter\libcupsimage2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\libcupsimage2.pdb"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)\libcupsimage2.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ OutputFile="$(OutDir)\libcupsimage2.dll"
+ LinkIncremental="1"
+ ModuleDefinitionFile="..\filter\libcupsimage2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="libcupsimage2.pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ImportLibrary="$(OutDir)\libcupsimage2.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot; &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ OutputFile="$(OutDir)\libcupsimage2.dll"
+ LinkIncremental="1"
+ ModuleDefinitionFile="..\filter\libcupsimage2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="libcupsimage2.pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ImportLibrary="$(OutDir)\libcupsimage2.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot; &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D7521234}"
+ >
+ <File
+ RelativePath="..\filter\error.c"
+ >
+ </File>
+ <File
+ RelativePath="..\filter\interpret.c"
+ >
+ </File>
+ <File
+ RelativePath="..\filter\raster.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE521234}"
+ >
+ <File
+ RelativePath="..\cups\raster.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121A1234}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vc2005/testfile.vcproj b/vc2005/testfile.vcproj
new file mode 100644
index 000000000..edebe6333
--- /dev/null
+++ b/vc2005/testfile.vcproj
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="testfile"
+ ProjectGUID="{CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet;.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="Debug\testfile.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/testfile.pdb"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\vcnet;.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="testfile.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\cups\testfile.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vc2005/testhttp.vcproj b/vc2005/testhttp.vcproj
new file mode 100644
index 000000000..77501a2d7
--- /dev/null
+++ b/vc2005/testhttp.vcproj
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="testhttp"
+ ProjectGUID="{90B0058C-8393-411F-BD3B-E2C831D4E883}"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet;.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="Debug\testhttp.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/testhttp.pdb"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\vcnet;.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="testhttp.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\cups\testhttp.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vcnet/config.h b/vcnet/config.h
new file mode 100644
index 000000000..09c0ce184
--- /dev/null
+++ b/vcnet/config.h
@@ -0,0 +1,788 @@
+/*
+ * "$Id$"
+ *
+ * Configuration file for CUPS on Windows.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPS_CONFIG_H_
+#define _CUPS_CONFIG_H_
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <io.h>
+#include <direct.h>
+
+
+/*
+ * Microsoft renames the POSIX functions to _name, and introduces
+ * a broken compatibility layer using the original names. As a result,
+ * random crashes can occur when, for example, strdup() allocates memory
+ * from a different heap than used by malloc() and free().
+ *
+ * To avoid moronic problems like this, we #define the POSIX function
+ * names to the corresponding non-standard Microsoft names.
+ */
+
+#define access _access
+#define close _close
+#define fileno _fileno
+#define lseek _lseek
+#define mkdir(d,p) _mkdir(d)
+#define open _open
+#define read _read
+#define rmdir _rmdir
+#define snprintf _snprintf
+#define strdup _strdup
+#define unlink _unlink
+#define vsnprintf _vsnprintf
+#define write _write
+
+
+/*
+ * Map the POSIX sleep() and usleep() functions to the Win32 Sleep() function...
+ */
+
+#define sleep(X) Sleep(1000 * (X))
+#define usleep(X) Sleep((X)/1000)
+
+
+/*
+ * Map various parameters to Posix style system calls
+ */
+
+# define F_OK 00
+# define W_OK 02
+# define R_OK 04
+# define O_RDONLY _O_RDONLY
+# define O_WRONLY _O_WRONLY
+# define O_CREATE _O_CREAT
+# define O_TRUNC _O_TRUNC
+
+
+/*
+ * Compiler stuff...
+ */
+
+#undef const
+#undef __CHAR_UNSIGNED__
+
+
+/*
+ * Version of software...
+ */
+
+#define CUPS_SVERSION "CUPS v1.5.0"
+#define CUPS_MINIMAL "CUPS/1.5.0"
+
+
+/*
+ * Default user and groups...
+ */
+
+#define CUPS_DEFAULT_USER ""
+#define CUPS_DEFAULT_GROUP ""
+#define CUPS_DEFAULT_SYSTEM_GROUPS ""
+#define CUPS_DEFAULT_PRINTOPERATOR_AUTH ""
+
+
+/*
+ * Default file permissions...
+ */
+
+#define CUPS_DEFAULT_CONFIG_FILE_PERM 0644
+#define CUPS_DEFAULT_LOG_FILE_PERM 0644
+
+
+/*
+ * Default logging settings...
+ */
+
+#define CUPS_DEFAULT_LOG_LEVEL "warn"
+#define CUPS_DEFAULT_ACCESS_LOG_LEVEL "actions"
+
+
+/*
+ * Default fatal error settings...
+ */
+
+#define CUPS_DEFAULT_FATAL_ERRORS "config"
+
+
+/*
+ * Default browsing settings...
+ */
+
+#define CUPS_DEFAULT_BROWSING 1
+#define CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS "CUPS dnssd"
+#define CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS ""
+#define CUPS_DEFAULT_BROWSE_SHORT_NAMES 1
+#define CUPS_DEFAULT_DEFAULT_SHARED 1
+#define CUPS_DEFAULT_IMPLICIT_CLASSES 1
+#define CUPS_DEFAULT_USE_NETWORK_DEFAULT 0
+
+
+/*
+ * Default IPP port...
+ */
+
+#define CUPS_DEFAULT_IPP_PORT 631
+
+
+/*
+ * Default printcap file...
+ */
+
+#define CUPS_DEFAULT_PRINTCAP ""
+
+
+/*
+ * Default Samba and LPD config files...
+ */
+
+#define CUPS_DEFAULT_SMB_CONFIG_FILE ""
+#define CUPS_DEFAULT_LPD_CONFIG_FILE ""
+
+
+/*
+ * Default MaxCopies value...
+ */
+
+#define CUPS_DEFAULT_MAX_COPIES 9999
+
+
+/*
+ * 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_BINDIR "C:/CUPS/bin"
+#define CUPS_CACHEDIR "C:/CUPS/cache"
+#define CUPS_DATADIR "C:/CUPS/share"
+#define CUPS_DOCROOT "C:/CUPS/share/doc"
+#define CUPS_FONTPATH "C:/CUPS/share/fonts"
+#define CUPS_LOCALEDIR "C:/CUPS/locale"
+#define CUPS_LOGDIR "C:/CUPS/logs"
+#define CUPS_REQUESTS "C:/CUPS/spool"
+#define CUPS_SBINDIR "C:/CUPS/sbin"
+#define CUPS_SERVERBIN "C:/CUPS/lib"
+#define CUPS_SERVERROOT "C:/CUPS/etc"
+#define CUPS_STATEDIR "C:/CUPS/run"
+
+
+/*
+ * 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 */
+/* #undef HAVE_PAM_SET_ITEM */
+/* #undef HAVE_PAM_SETCRED */
+
+
+/*
+ * Do we have <shadow.h>?
+ */
+
+/* #undef HAVE_SHADOW_H */
+
+
+/*
+ * Do we have <crypt.h>?
+ */
+
+/* #undef HAVE_CRYPT_H */
+
+
+/*
+ * Do we have <scsi/sg.h>?
+ */
+
+/* #undef HAVE_SCSI_SG_H */
+
+
+/*
+ * Use <string.h>, <strings.h>, and/or <bstring.h>?
+ */
+
+#define HAVE_STRING_H 1
+/* #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?
+ */
+
+#define HAVE_STRDUP 1
+/* #undef HAVE_STRLCAT */
+/* #undef HAVE_STRLCPY */
+
+
+/*
+ * Do we have the geteuid() function?
+ */
+
+/* #undef HAVE_GETEUID */
+
+
+/*
+ * Do we have the setpgid() function?
+ */
+
+/* #undef HAVE_SETPGID */
+
+
+/*
+ * Do we have the vsyslog() function?
+ */
+
+/* #undef HAVE_VSYSLOG */
+
+
+/*
+ * Do we have the (v)snprintf() functions?
+ */
+
+#define HAVE_SNPRINTF 1
+#define HAVE_VSNPRINTF 1
+
+
+/*
+ * 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 POSIX ACL functions?
+ */
+
+/* #undef HAVE_ACL_INIT */
+
+
+/*
+ * 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 */
+#define HAVE_SSPISSL
+#define HAVE_SSL
+
+
+/*
+ * What Security framework headers do we have?
+ */
+
+/* #undef HAVE_AUTHORIZATION_H */
+/* #undef HAVE_SECPOLICY_H */
+/* #undef HAVE_SECPOLICYPRIV_H */
+/* #undef HAVE_SECBASEPRIV_H */
+/* #undef HAVE_SECIDENTITYSEARCHPRIV_H */
+
+
+/*
+ * Do we have the SecIdentitySearchCreateWithPolicy function?
+ */
+
+/* #undef HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY */
+
+
+/*
+ * Do we have the SecPolicyCreateSSL function?
+ */
+
+/* #undef HAVE_SECPOLICYCREATESSL */
+
+
+/*
+ * Do we have the SecPolicyCreateSSL function?
+ */
+
+/* #undef HAVE_SECPOLICYCREATESSL */
+
+
+/*
+ * Do we have the cssmErrorString function?
+ */
+
+/* #undef HAVE_CSSMERRORSTRING */
+
+
+/*
+ * Do we have the SLP library?
+ */
+
+/* #undef HAVE_LIBSLP */
+
+
+/*
+ * Do we have an LDAP library?
+ */
+
+/* #undef HAVE_LDAP */
+/* #undef HAVE_OPENLDAP */
+/* #undef HAVE_MOZILLA_LDAP */
+/* #undef HAVE_LDAP_SSL_H */
+/* #undef HAVE_LDAP_SSL */
+/* #undef HAVE_LDAP_REBIND_PROC */
+
+
+/*
+ * Do we have libpaper?
+ */
+
+/* #undef HAVE_LIBPAPER */
+
+
+/*
+ * Do we have DNS Service Discovery (aka Bonjour)?
+ */
+
+#define HAVE_DNSSD 1
+
+
+/*
+ * Does the "stat" structure contain the "st_gen" member?
+ */
+
+/* #undef HAVE_ST_GEN */
+
+
+/*
+ * Do we have <sys/ioctl.h>?
+ */
+
+/* #undef HAVE_SYS_IOCTL_H */
+
+
+/*
+ * 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()?
+ */
+
+#define HAVE_GETADDRINFO 1
+
+
+/*
+ * Do we have getnameinfo()?
+ */
+
+#define HAVE_GETNAMEINFO 1
+
+
+/*
+ * Do we have getifaddrs()?
+ */
+
+/* #undef HAVE_GETIFADDRS */
+
+
+/*
+ * Do we have hstrerror()?
+ */
+
+/* #undef HAVE_HSTRERROR */
+
+
+/*
+ * Do we have res_init()?
+ */
+
+/* #undef HAVE_RES_INIT */
+
+
+/*
+ * Do we have <resolv.h>
+ */
+
+/* #undef HAVE_RESOLV_H */
+
+
+/*
+ * Do we have the <sys/sockio.h> 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 */
+
+
+/*
+ * Do we have launchd support?
+ */
+
+/* #undef HAVE_LAUNCH_H */
+/* #undef HAVE_LAUNCHD */
+
+
+/*
+ * Various scripting languages...
+ */
+
+/* #undef HAVE_JAVA */
+#define CUPS_JAVA ""
+/* #undef HAVE_PERL */
+#define CUPS_PERL ""
+/* #undef HAVE_PHP */
+#define CUPS_PHP ""
+/* #undef HAVE_PYTHON */
+#define CUPS_PYTHON ""
+
+
+/*
+ * Location of the poppler/Xpdf pdftops program...
+ */
+
+/* #undef HAVE_PDFTOPS */
+#define CUPS_PDFTOPS ""
+
+
+/*
+ * Location of the Ghostscript gs program...
+ */
+
+/* #undef HAVE_GHOSTSCRIPT */
+#define CUPS_GHOSTSCRIPT ""
+
+
+/*
+ * Do we have Darwin's CoreFoundation and SystemConfiguration frameworks?
+ */
+
+/* #undef HAVE_COREFOUNDATION */
+/* #undef HAVE_SYSTEMCONFIGURATION */
+
+
+/*
+ * Do we have CoreFoundation public and private headers?
+ */
+
+/* #undef HAVE_COREFOUNDATION_H */
+/* #undef HAVE_CFPRIV_H */
+/* #undef HAVE_CFBUNDLEPRIV_H */
+
+
+/*
+ * Do we have ApplicationServices public headers?
+ */
+
+/* #undef HAVE_APPLICATIONSERVICES_H */
+
+
+/*
+ * Do we have the SCDynamicStoreCopyComputerName function?
+ */
+
+/* #undef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME */
+
+
+/*
+ * Do we have Mac OS X 10.4's mbr_XXX functions?
+ */
+
+/* #undef HAVE_MEMBERSHIP_H */
+/* #undef HAVE_MEMBERSHIPPRIV_H */
+/* #undef HAVE_MBR_UID_TO_UUID */
+
+
+/*
+ * Do we have Darwin's notify_post header and function?
+ */
+
+/* #undef HAVE_NOTIFY_H */
+/* #undef HAVE_NOTIFY_POST */
+
+
+/*
+ * Do we have Darwin's IOKit private headers?
+ */
+
+/* #undef HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H */
+
+
+/*
+ * Do we have DBUS?
+ */
+
+/* #undef HAVE_DBUS */
+/* #undef HAVE_DBUS_MESSAGE_ITER_INIT_APPEND */
+
+
+/*
+ * Do we have the GSSAPI support library (for Kerberos support)?
+ */
+
+/* #undef HAVE_GSS_ACQUIRE_CRED_EX_F */
+/* #undef HAVE_GSS_C_NT_HOSTBASED_SERVICE */
+/* #undef HAVE_GSS_GSSAPI_H */
+/* #undef HAVE_GSS_GSSAPI_SPI_H */
+/* #undef HAVE_GSSAPI */
+/* #undef HAVE_GSSAPI_GENERIC_H */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+/* #undef HAVE_GSSAPI_H */
+/* #undef HAVE_GSSAPI_KRB5_H */
+/* #undef HAVE_KRB5_H */
+
+
+/*
+ * Default GSS service name...
+ */
+
+#define CUPS_DEFAULT_GSSSERVICENAME "host"
+
+
+/*
+ * Select/poll interfaces...
+ */
+
+/* #undef HAVE_POLL */
+/* #undef HAVE_EPOLL */
+/* #undef HAVE_KQUEUE */
+
+
+/*
+ * Do we have the <dlfcn.h> header?
+ */
+
+/* #undef HAVE_DLFCN_H */
+
+
+/*
+ * Do we have <sys/param.h>?
+ */
+
+/* #undef HAVE_SYS_PARAM_H */
+
+
+/*
+ * Do we have <sys/ucred.h>?
+ */
+
+/* #undef HAVE_SYS_UCRED_H */
+
+
+/*
+ * Do we have removefile()?
+ */
+
+/* #undef HAVE_REMOVEFILE */
+
+
+/*
+ * Do we have <sandbox.h>?
+ */
+
+/* #undef HAVE_SANDBOX_H */
+
+
+/*
+ * Which random number generator function to use...
+ */
+
+/* #undef HAVE_ARC4RANDOM */
+/* #undef HAVE_RANDOM */
+/* #undef HAVE_LRAND48 */
+
+#ifdef HAVE_ARC4RANDOM
+# define CUPS_RAND() arc4random()
+# define CUPS_SRAND(v) arc4random_stir()
+#elif defined(HAVE_RANDOM)
+# define CUPS_RAND() random()
+# define CUPS_SRAND(v) srandom(v)
+#elif defined(HAVE_LRAND48)
+# define CUPS_RAND() lrand48()
+# define CUPS_SRAND(v) srand48(v)
+#else
+# define CUPS_RAND() rand()
+# define CUPS_SRAND(v) srand(v)
+#endif /* HAVE_ARC4RANDOM */
+
+
+/*
+ * Do we have vproc_transaction_begin/end?
+ */
+
+/* #undef HAVE_VPROC_TRANSACTION_BEGIN */
+
+
+/*
+ * Do we have libusb?
+ */
+
+/* #undef HAVE_USB_H */
+
+
+/*
+ * Do we have libwrap and tcpd.h?
+ */
+
+/* #undef HAVE_TCPD_H */
+
+
+/*
+ * Do we have <iconv.h>?
+ */
+
+/* #undef HAVE_ICONV_H */
+
+
+/*
+ * Do we have statfs or statvfs and one of the corresponding headers?
+ */
+
+/* #undef HAVE_STATFS */
+/* #undef HAVE_STATVFS */
+/* #undef HAVE_SYS_MOUNT_H */
+/* #undef HAVE_SYS_STATFS_H */
+/* #undef HAVE_SYS_STATVFS_H */
+/* #undef HAVE_SYS_VFS_H */
+
+
+/*
+ * Location of Mac OS X localization bundle, if any.
+ */
+
+/* #undef CUPS_BUNDLEDIR */
+
+
+/*
+ * Do we have the ColorSyncRegisterDevice function?
+ */
+
+/* #undef HAVE_COLORSYNCREGISTERDEVICE */
+
+
+/*
+ * Do we have XPC?
+ */
+
+/* #undef HAVE_XPC */
+
+
+#endif /* !_CUPS_CONFIG_H_ */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/vcnet/cups.sln b/vcnet/cups.sln
new file mode 100644
index 000000000..9dabb8926
--- /dev/null
+++ b/vcnet/cups.sln
@@ -0,0 +1,91 @@
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcups2", "libcups2.vcproj", "{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcupsimage2", "libcupsimage2.vcproj", "{CB4AA6F2-3E84-45BE-B505-95CD375E1234}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testfile", "testfile.vcproj", "{CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testhttp", "testhttp.vcproj", "{90B0058C-8393-411F-BD3B-E2C831D4E883}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cupstestppd", "cupstestppd.vcproj", "{6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234} = {CB4AA6F2-3E84-45BE-B505-95CD375E1234}
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ipptool", "ipptool.vcproj", "{B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|Win32.Build.0 = Debug|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|x64.ActiveCfg = Debug|x64
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|x64.Build.0 = Debug|x64
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|Win32.ActiveCfg = Release|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|Win32.Build.0 = Release|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|x64.ActiveCfg = Debug|x64
+ {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|x64.Build.0 = Debug|x64
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Debug|Win32.Build.0 = Debug|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Debug|x64.ActiveCfg = Debug|x64
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Debug|x64.Build.0 = Debug|x64
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Release|Win32.ActiveCfg = Release|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Release|Win32.Build.0 = Release|Win32
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Release|x64.ActiveCfg = Release|x64
+ {CB4AA6F2-3E84-45BE-B505-95CD375E1234}.Release|x64.Build.0 = Release|x64
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Debug|Win32.Build.0 = Debug|Win32
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Debug|x64.ActiveCfg = Debug|x64
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Debug|x64.Build.0 = Debug|x64
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|Win32.ActiveCfg = Release|Win32
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|Win32.Build.0 = Release|Win32
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|x64.ActiveCfg = Debug|x64
+ {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|x64.Build.0 = Debug|x64
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Debug|Win32.ActiveCfg = Debug|Win32
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Debug|Win32.Build.0 = Debug|Win32
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Debug|x64.ActiveCfg = Debug|x64
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Debug|x64.Build.0 = Debug|x64
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Release|Win32.ActiveCfg = Release|Win32
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Release|Win32.Build.0 = Release|Win32
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Release|x64.ActiveCfg = Debug|x64
+ {90B0058C-8393-411F-BD3B-E2C831D4E883}.Release|x64.Build.0 = Debug|x64
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Debug|Win32.Build.0 = Debug|Win32
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Debug|x64.ActiveCfg = Debug|x64
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Debug|x64.Build.0 = Debug|x64
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Release|Win32.ActiveCfg = Release|Win32
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Release|Win32.Build.0 = Release|Win32
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Release|x64.ActiveCfg = Release|x64
+ {6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}.Release|x64.Build.0 = Release|x64
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Debug|Win32.Build.0 = Debug|Win32
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Debug|x64.ActiveCfg = Debug|x64
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Debug|x64.Build.0 = Debug|x64
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Release|Win32.ActiveCfg = Release|Win32
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Release|Win32.Build.0 = Release|Win32
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Release|x64.ActiveCfg = Release|x64
+ {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/vcnet/cupstestppd.vcproj b/vcnet/cupstestppd.vcproj
new file mode 100644
index 000000000..8c3416963
--- /dev/null
+++ b/vcnet/cupstestppd.vcproj
@@ -0,0 +1,353 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="cupstestppd"
+ ProjectGUID="{6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}"
+ RootNamespace="cupstestppd"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..;..\vcnet"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..;..\vcnet"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..;..\vcnet"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..;..\vcnet"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\systemv\cupstestppd.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vcnet/ipptool.vcproj b/vcnet/ipptool.vcproj
new file mode 100644
index 000000000..6c59af17f
--- /dev/null
+++ b/vcnet/ipptool.vcproj
@@ -0,0 +1,385 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="ipptool"
+ ProjectGUID="{B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}"
+ RootNamespace="ipptool"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet;..;..\vcnet\regex"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\vcnet;..;..\vcnet\regex"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet;..;..\vcnet\regex"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\vcnet;..;..\vcnet\regex"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\regex\debug.c"
+ >
+ </File>
+ <File
+ RelativePath="..\test\ipptool.c"
+ >
+ </File>
+ <File
+ RelativePath=".\regex\regcomp.c"
+ >
+ </File>
+ <File
+ RelativePath=".\regex\regerror.c"
+ >
+ </File>
+ <File
+ RelativePath=".\regex\regexec.c"
+ >
+ </File>
+ <File
+ RelativePath=".\regex\regfree.c"
+ >
+ </File>
+ <File
+ RelativePath=".\regex\split.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\regex\regex.h"
+ >
+ </File>
+ <File
+ RelativePath=".\regex\regex2.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vcnet/libcups2.vcproj b/vcnet/libcups2.vcproj
new file mode 100644
index 000000000..e5d04af72
--- /dev/null
+++ b/vcnet/libcups2.vcproj
@@ -0,0 +1,1608 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="libcups2"
+ ProjectGUID="{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib advapi32.lib"
+ OutputFile="$(OutDir)\libcups2.dll"
+ LinkIncremental="2"
+ ModuleDefinitionFile="..\cups\libcups2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\libcups2.pdb"
+ SubSystem="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(OutDir)\libcups2.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib advapi32.lib"
+ OutputFile="$(OutDir)\libcups2.dll"
+ LinkIncremental="2"
+ ModuleDefinitionFile="..\cups\libcups2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\libcups2.pdb"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)\libcups2.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib advapi32.lib"
+ OutputFile="$(OutDir)\libcups2.dll"
+ LinkIncremental="1"
+ ModuleDefinitionFile="..\cups\libcups2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="libcups2.pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(OutDir)\libcups2.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib advapi32.lib"
+ OutputFile="$(OutDir)\libcups2.dll"
+ LinkIncremental="1"
+ ModuleDefinitionFile="..\cups\libcups2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="libcups2.pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ImportLibrary="$(OutDir)\libcups2.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot; &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\cups\adminutil.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\array.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\attr.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\auth.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\backend.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\conflicts.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\custom.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\dest.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\dir.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\emit.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\encode.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\file.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\getdevices.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\getputfile.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\globals.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\http-addr.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\http-addrlist.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\http-support.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\http.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\ipp-support.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\ipp.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\langprintf.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\language.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\localize.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\mark.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\md5.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\md5passwd.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\notify.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\options.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\page.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\ppd.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\pwg-file.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\pwg-media.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\pwg-ppd.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\request.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\snmp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\snprintf.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\sspi.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\string.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\tempfile.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\thread.c"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\transcode.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\usersys.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\cups\util.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\cups\adminutil.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\array.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\backend.h"
+ >
+ </File>
+ <File
+ RelativePath=".\config.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\cups.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\debug.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\dir.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\file-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\file.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\globals.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\http-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\http.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\i18n.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\ipp-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\ipp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\language.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\md5-apple.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\md5.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\normalize.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\ppd.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\pwg-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\sspi-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\string.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\thread-private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\cups\transcode.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vcnet/libcupsimage2.vcproj b/vcnet/libcupsimage2.vcproj
new file mode 100644
index 000000000..23f3f5b91
--- /dev/null
+++ b/vcnet/libcupsimage2.vcproj
@@ -0,0 +1,388 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="libcupsimage2"
+ ProjectGUID="{CB4AA6F2-3E84-45BE-B505-95CD375E1234}"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ OutputFile="$(OutDir)\libcupsimage2.dll"
+ LinkIncremental="2"
+ ModuleDefinitionFile="..\filter\libcupsimage2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\libcupsimage2.pdb"
+ SubSystem="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(OutDir)\libcupsimage2.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ OutputFile="$(OutDir)\libcupsimage2.dll"
+ LinkIncremental="2"
+ ModuleDefinitionFile="..\filter\libcupsimage2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\libcupsimage2.pdb"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)\libcupsimage2.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ OutputFile="$(OutDir)\libcupsimage2.dll"
+ LinkIncremental="1"
+ ModuleDefinitionFile="..\filter\libcupsimage2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="libcupsimage2.pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(OutDir)\libcupsimage2.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories="..\vcnet,.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ OutputFile="$(OutDir)\libcupsimage2.dll"
+ LinkIncremental="1"
+ ModuleDefinitionFile="..\filter\libcupsimage2.def"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="libcupsimage2.pdb"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ImportLibrary="$(OutDir)\libcupsimage2.lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot; &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D7521234}"
+ >
+ <File
+ RelativePath="..\filter\error.c"
+ >
+ </File>
+ <File
+ RelativePath="..\filter\interpret.c"
+ >
+ </File>
+ <File
+ RelativePath="..\filter\raster.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE521234}"
+ >
+ <File
+ RelativePath="..\cups\raster.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121A1234}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vcnet/regex/COPYRIGHT b/vcnet/regex/COPYRIGHT
new file mode 100644
index 000000000..30c1f7a48
--- /dev/null
+++ b/vcnet/regex/COPYRIGHT
@@ -0,0 +1,20 @@
+Copyright 1992, 1993, 1994, 1997 Henry Spencer. All rights reserved.
+This software is not subject to any license of the American Telephone
+and Telegraph Company or of the Regents of the University of California.
+
+Permission is granted to anyone to use this software for any purpose on
+any computer system, and to alter it and redistribute it, subject
+to the following restrictions:
+
+1. The author is not responsible for the consequences of use of this
+ software, no matter how awful, even if they arise from flaws in it.
+
+2. The origin of this software must not be misrepresented, either by
+ explicit claim or by omission. Since few users ever read sources,
+ credits must appear in the documentation.
+
+3. Altered versions must be plainly marked as such, and must not be
+ misrepresented as being the original software. Since few users
+ ever read sources, credits must appear in the documentation.
+
+4. This notice may not be removed or altered.
diff --git a/vcnet/regex/Makefile b/vcnet/regex/Makefile
new file mode 100644
index 000000000..3882b3786
--- /dev/null
+++ b/vcnet/regex/Makefile
@@ -0,0 +1,130 @@
+# You probably want to take -DREDEBUG out of CFLAGS, and put something like
+# -O in, *after* testing (-DREDEBUG strengthens testing by enabling a lot of
+# internal assertion checking and some debugging facilities).
+# Put -Dconst= in for a pre-ANSI compiler.
+# Do not take -DPOSIX_MISTAKE out.
+# REGCFLAGS isn't important to you (it's for my use in some special contexts).
+CFLAGS=-I. -DPOSIX_MISTAKE -DREDEBUG $(REGCFLAGS)
+
+# If you have a pre-ANSI compiler, put -o into MKHFLAGS. If you want
+# the Berkeley __P macro, put -b in.
+MKHFLAGS=
+
+# Flags for linking but not compiling, if any.
+LDFLAGS=
+
+# Extra libraries for linking, if any.
+LIBS=
+
+# Internal stuff, should not need changing.
+OBJPRODN=regcomp.o regexec.o regerror.o regfree.o
+OBJS=$(OBJPRODN) split.o debug.o main.o
+H=cclass.h cname.h regex2.h utils.h
+REGSRC=regcomp.c regerror.c regexec.c regfree.c
+ALLSRC=$(REGSRC) engine.c debug.c main.c split.c
+
+# Stuff that matters only if you're trying to lint the package.
+LINTFLAGS=-I. -Dstatic= -Dconst= -DREDEBUG
+LINTC=regcomp.c regexec.c regerror.c regfree.c debug.c main.c
+JUNKLINT=possible pointer alignment|null effect
+
+# arrangements to build forward-reference header files
+.SUFFIXES: .ih .h
+.c.ih:
+ sh ./mkh $(MKHFLAGS) -p $< >$@
+
+default: r
+
+lib: purge $(OBJPRODN)
+ rm -f libregex.a
+ ar crv libregex.a $(OBJPRODN)
+
+purge:
+ rm -f *.o
+
+# stuff to build regex.h
+REGEXH=regex.h
+REGEXHSRC=regex2.h $(REGSRC)
+$(REGEXH): $(REGEXHSRC) mkh
+ sh ./mkh $(MKHFLAGS) -i _REGEX_H_ $(REGEXHSRC) >regex.tmp
+ cmp -s regex.tmp regex.h 2>/dev/null || cp regex.tmp regex.h
+ rm -f regex.tmp
+
+# dependencies
+$(OBJPRODN) debug.o: utils.h regex.h regex2.h
+regcomp.o: cclass.h cname.h regcomp.ih
+regexec.o: engine.c engine.ih
+regerror.o: regerror.ih
+debug.o: debug.ih
+main.o: main.ih
+
+# tester
+re: $(OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
+
+# regression test
+r: re tests
+ ./re <tests
+ ./re -el <tests
+ ./re -er <tests
+
+# 57 variants, and other stuff, for development use -- not useful to you
+ra: ./re tests
+ -./re <tests
+ -./re -el <tests
+ -./re -er <tests
+
+rx: ./re tests
+ ./re -x <tests
+ ./re -x -el <tests
+ ./re -x -er <tests
+
+t: ./re tests
+ -time ./re <tests
+ -time ./re -cs <tests
+ -time ./re -el <tests
+ -time ./re -cs -el <tests
+
+l: $(LINTC)
+ lint $(LINTFLAGS) -h $(LINTC) 2>&1 | egrep -v '$(JUNKLINT)' | tee lint
+
+fullprint:
+ ti README WHATSNEW notes todo | list
+ ti *.h | list
+ list *.c
+ list regex.3 regex.7
+
+print:
+ ti README WHATSNEW notes todo | list
+ ti *.h | list
+ list reg*.c engine.c
+
+
+mf.tmp: Makefile
+ sed '/^REGEXH=/s/=.*/=regex.h/' Makefile | sed '/#DEL$$/d' >$@
+
+DTRH=cclass.h cname.h regex2.h utils.h
+PRE=COPYRIGHT README WHATSNEW
+POST=mkh regex.3 regex.7 tests $(DTRH) $(ALLSRC) fake/*.[ch]
+FILES=$(PRE) Makefile $(POST)
+DTR=$(PRE) Makefile=mf.tmp $(POST)
+dtr: $(FILES) mf.tmp
+ makedtr $(DTR) >$@
+ rm mf.tmp
+
+cio: $(FILES)
+ cio $(FILES)
+
+rdf: $(FILES)
+ rcsdiff -c $(FILES) 2>&1 | p
+
+# various forms of cleanup
+tidy:
+ rm -f junk* core core.* *.core dtr *.tmp lint
+
+clean: tidy
+ rm -f *.o *.s *.ih re libregex.a
+
+# don't do this one unless you know what you're doing
+spotless: clean
+ rm -f mkh regex.h
diff --git a/vcnet/regex/README b/vcnet/regex/README
new file mode 100644
index 000000000..e6ce37344
--- /dev/null
+++ b/vcnet/regex/README
@@ -0,0 +1,32 @@
+alpha3.8 release.
+Tue Aug 10 15:51:48 EDT 1999
+henry@spsystems.net (formerly henry@zoo.toronto.edu)
+
+See WHATSNEW for change listing.
+
+installation notes:
+--------
+Read the comments at the beginning of Makefile before running.
+
+Utils.h contains some things that just might have to be modified on
+some systems, as well as a nested include (ugh) of <assert.h>.
+
+The "fake" directory contains quick-and-dirty fakes for some header
+files and routines that old systems may not have. Note also that
+-DUSEBCOPY will make utils.h substitute bcopy() for memmove().
+
+After that, "make r" will build regcomp.o, regexec.o, regfree.o,
+and regerror.o (the actual routines), bundle them together into a test
+program, and run regression tests on them. No output is good output.
+
+"make lib" builds just the .o files for the actual routines (when
+you're happy with testing and have adjusted CFLAGS for production),
+and puts them together into libregex.a. You can pick up either the
+library or *.o ("make lib" makes sure there are no other .o files left
+around to confuse things).
+
+Main.c, debug.c, split.c are used for regression testing but are not part
+of the RE routines themselves.
+
+Regex.h goes in /usr/include. All other .h files are internal only.
+--------
diff --git a/vcnet/regex/WHATSNEW b/vcnet/regex/WHATSNEW
new file mode 100644
index 000000000..12953433d
--- /dev/null
+++ b/vcnet/regex/WHATSNEW
@@ -0,0 +1,108 @@
+New in alpha3.8: Bug fix for signed/unsigned mixup, found and fixed
+by the FreeBSD folks.
+
+New in alpha3.7: A bit of cleanup aimed at maximizing portability,
+possibly at slight cost in efficiency. "ul" suffixes and "unsigned long"
+no longer appear, in particular.
+
+New in alpha3.6: A couple more portability glitches fixed.
+
+New in alpha3.5: Active development of this code has been stopped --
+I'm working on a complete reimplementation -- but folks have found some
+minor portability glitches and the like, hence this release to fix them.
+One penalty: slightly reduced compatibility with old compilers, because
+the ANSI C `unsigned long' type and `ul' constant suffix are used in a
+few places (I could avoid this but it would be considerably more work).
+
+New in alpha3.4: The complex bug alluded to below has been fixed (in a
+slightly kludgey temporary way that may hurt efficiency a bit; this is
+another "get it out the door for 4.4" release). The tests at the end of
+the tests file have accordingly been uncommented. The primary sign of
+the bug was that something like a?b matching ab matched b rather than ab.
+(The bug was essentially specific to this exact situation, else it would
+have shown up earlier.)
+
+New in alpha3.3: The definition of word boundaries has been altered
+slightly, to more closely match the usual programming notion that "_"
+is an alphabetic. Stuff used for pre-ANSI systems is now in a subdir,
+and the makefile no longer alludes to it in mysterious ways. The
+makefile has generally been cleaned up some. Fixes have been made
+(again!) so that the regression test will run without -DREDEBUG, at
+the cost of weaker checking. A workaround for a bug in some folks'
+<assert.h> has been added. And some more things have been added to
+tests, including a couple right at the end which are commented out
+because the code currently flunks them (complex bug; fix coming).
+Plus the usual minor cleanup.
+
+New in alpha3.2: Assorted bits of cleanup and portability improvement
+(the development base is now a BSDI system using GCC instead of an ancient
+Sun system, and the newer compiler exposed some glitches). Fix for a
+serious bug that affected REs using many [] (including REG_ICASE REs
+because of the way they are implemented), *sometimes*, depending on
+memory-allocation patterns. The header-file prototypes no longer name
+the parameters, avoiding possible name conflicts. The possibility that
+some clot has defined CHAR_MIN as (say) `-128' instead of `(-128)' is
+now handled gracefully. "uchar" is no longer used as an internal type
+name (too many people have the same idea). Still the same old lousy
+performance, alas.
+
+New in alpha3.1: Basically nothing, this release is just a bookkeeping
+convenience. Stay tuned.
+
+New in alpha3.0: Performance is no better, alas, but some fixes have been
+made and some functionality has been added. (This is basically the "get
+it out the door in time for 4.4" release.) One bug fix: regfree() didn't
+free the main internal structure (how embarrassing). It is now possible
+to put NULs in either the RE or the target string, using (resp.) a new
+REG_PEND flag and the old REG_STARTEND flag. The REG_NOSPEC flag to
+regcomp() makes all characters ordinary, so you can match a literal
+string easily (this will become more useful when performance improves!).
+There are now primitives to match beginnings and ends of words, although
+the syntax is disgusting and so is the implementation. The REG_ATOI
+debugging interface has changed a bit. And there has been considerable
+internal cleanup of various kinds.
+
+New in alpha2.3: Split change list out of README, and moved flags notes
+into Makefile. Macro-ized the name of regex(7) in regex(3), since it has
+to change for 4.4BSD. Cleanup work in engine.c, and some new regression
+tests to catch tricky cases thereof.
+
+New in alpha2.2: Out-of-date manpages updated. Regerror() acquires two
+small extensions -- REG_ITOA and REG_ATOI -- which avoid debugging kludges
+in my own test program and might be useful to others for similar purposes.
+The regression test will now compile (and run) without REDEBUG. The
+BRE \$ bug is fixed. Most uses of "uchar" are gone; it's all chars now.
+Char/uchar parameters are now written int/unsigned, to avoid possible
+portability problems with unpromoted parameters. Some unsigned casts have
+been introduced to minimize portability problems with shifting into sign
+bits.
+
+New in alpha2.1: Lots of little stuff, cleanup and fixes. The one big
+thing is that regex.h is now generated, using mkh, rather than being
+supplied in the distribution; due to circularities in dependencies,
+you have to build regex.h explicitly by "make h". The two known bugs
+have been fixed (and the regression test now checks for them), as has a
+problem with assertions not being suppressed in the absence of REDEBUG.
+No performance work yet.
+
+New in alpha2: Backslash-anything is an ordinary character, not an
+error (except, of course, for the handful of backslashed metacharacters
+in BREs), which should reduce script breakage. The regression test
+checks *where* null strings are supposed to match, and has generally
+been tightened up somewhat. Small bug fixes in parameter passing (not
+harmful, but technically errors) and some other areas. Debugging
+invoked by defining REDEBUG rather than not defining NDEBUG.
+
+New in alpha+3: full prototyping for internal routines, using a little
+helper program, mkh, which extracts prototypes given in stylized comments.
+More minor cleanup. Buglet fix: it's CHAR_BIT, not CHAR_BITS. Simple
+pre-screening of input when a literal string is known to be part of the
+RE; this does wonders for performance.
+
+New in alpha+2: minor bits of cleanup. Notably, the number "32" for the
+word width isn't hardwired into regexec.c any more, the public header
+file prototypes the functions if __STDC__ is defined, and some small typos
+in the manpages have been fixed.
+
+New in alpha+1: improvements to the manual pages, and an important
+extension, the REG_STARTEND option to regexec().
diff --git a/vcnet/regex/cclass.h b/vcnet/regex/cclass.h
new file mode 100644
index 000000000..0c293028e
--- /dev/null
+++ b/vcnet/regex/cclass.h
@@ -0,0 +1,31 @@
+/* character-class table */
+static struct cclass {
+ char *name;
+ char *chars;
+ char *multis;
+} cclasses[] = {
+ "alnum", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789", "",
+ "alpha", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+ "",
+ "blank", " \t", "",
+ "cntrl", "\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\
+\25\26\27\30\31\32\33\34\35\36\37\177", "",
+ "digit", "0123456789", "",
+ "graph", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ "",
+ "lower", "abcdefghijklmnopqrstuvwxyz",
+ "",
+ "print", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ",
+ "",
+ "punct", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ "",
+ "space", "\t\n\v\f\r ", "",
+ "upper", "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ "",
+ "xdigit", "0123456789ABCDEFabcdef",
+ "",
+ NULL, 0, ""
+};
diff --git a/vcnet/regex/cname.h b/vcnet/regex/cname.h
new file mode 100644
index 000000000..02e86e912
--- /dev/null
+++ b/vcnet/regex/cname.h
@@ -0,0 +1,102 @@
+/* character-name table */
+static struct cname {
+ char *name;
+ char code;
+} cnames[] = {
+ "NUL", '\0',
+ "SOH", '\001',
+ "STX", '\002',
+ "ETX", '\003',
+ "EOT", '\004',
+ "ENQ", '\005',
+ "ACK", '\006',
+ "BEL", '\007',
+ "alert", '\007',
+ "BS", '\010',
+ "backspace", '\b',
+ "HT", '\011',
+ "tab", '\t',
+ "LF", '\012',
+ "newline", '\n',
+ "VT", '\013',
+ "vertical-tab", '\v',
+ "FF", '\014',
+ "form-feed", '\f',
+ "CR", '\015',
+ "carriage-return", '\r',
+ "SO", '\016',
+ "SI", '\017',
+ "DLE", '\020',
+ "DC1", '\021',
+ "DC2", '\022',
+ "DC3", '\023',
+ "DC4", '\024',
+ "NAK", '\025',
+ "SYN", '\026',
+ "ETB", '\027',
+ "CAN", '\030',
+ "EM", '\031',
+ "SUB", '\032',
+ "ESC", '\033',
+ "IS4", '\034',
+ "FS", '\034',
+ "IS3", '\035',
+ "GS", '\035',
+ "IS2", '\036',
+ "RS", '\036',
+ "IS1", '\037',
+ "US", '\037',
+ "space", ' ',
+ "exclamation-mark", '!',
+ "quotation-mark", '"',
+ "number-sign", '#',
+ "dollar-sign", '$',
+ "percent-sign", '%',
+ "ampersand", '&',
+ "apostrophe", '\'',
+ "left-parenthesis", '(',
+ "right-parenthesis", ')',
+ "asterisk", '*',
+ "plus-sign", '+',
+ "comma", ',',
+ "hyphen", '-',
+ "hyphen-minus", '-',
+ "period", '.',
+ "full-stop", '.',
+ "slash", '/',
+ "solidus", '/',
+ "zero", '0',
+ "one", '1',
+ "two", '2',
+ "three", '3',
+ "four", '4',
+ "five", '5',
+ "six", '6',
+ "seven", '7',
+ "eight", '8',
+ "nine", '9',
+ "colon", ':',
+ "semicolon", ';',
+ "less-than-sign", '<',
+ "equals-sign", '=',
+ "greater-than-sign", '>',
+ "question-mark", '?',
+ "commercial-at", '@',
+ "left-square-bracket", '[',
+ "backslash", '\\',
+ "reverse-solidus", '\\',
+ "right-square-bracket", ']',
+ "circumflex", '^',
+ "circumflex-accent", '^',
+ "underscore", '_',
+ "low-line", '_',
+ "grave-accent", '`',
+ "left-brace", '{',
+ "left-curly-bracket", '{',
+ "vertical-line", '|',
+ "right-brace", '}',
+ "right-curly-bracket", '}',
+ "tilde", '~',
+ "DEL", '\177',
+ NULL, 0,
+};
diff --git a/vcnet/regex/debug.c b/vcnet/regex/debug.c
new file mode 100644
index 000000000..99ce7da6d
--- /dev/null
+++ b/vcnet/regex/debug.c
@@ -0,0 +1,242 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+#include "debug.ih"
+
+/*
+ - regprint - print a regexp for debugging
+ == void regprint(regex_t *r, FILE *d);
+ */
+void
+regprint(r, d)
+regex_t *r;
+FILE *d;
+{
+ register struct re_guts *g = r->re_g;
+ register int i;
+ register int c;
+ register int last;
+ int nincat[NC];
+
+ fprintf(d, "%ld states, %d categories", (long)g->nstates,
+ g->ncategories);
+ fprintf(d, ", first %ld last %ld", (long)g->firststate,
+ (long)g->laststate);
+ if (g->iflags&USEBOL)
+ fprintf(d, ", USEBOL");
+ if (g->iflags&USEEOL)
+ fprintf(d, ", USEEOL");
+ if (g->iflags&BAD)
+ fprintf(d, ", BAD");
+ if (g->nsub > 0)
+ fprintf(d, ", nsub=%ld", (long)g->nsub);
+ if (g->must != NULL)
+ fprintf(d, ", must(%ld) `%*s'", (long)g->mlen, (int)g->mlen,
+ g->must);
+ if (g->backrefs)
+ fprintf(d, ", backrefs");
+ if (g->nplus > 0)
+ fprintf(d, ", nplus %ld", (long)g->nplus);
+ fprintf(d, "\n");
+ s_print(g, d);
+ for (i = 0; i < g->ncategories; i++) {
+ nincat[i] = 0;
+ for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+ if (g->categories[c] == i)
+ nincat[i]++;
+ }
+ fprintf(d, "cc0#%d", nincat[0]);
+ for (i = 1; i < g->ncategories; i++)
+ if (nincat[i] == 1) {
+ for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+ if (g->categories[c] == i)
+ break;
+ fprintf(d, ", %d=%s", i, regchar(c));
+ }
+ fprintf(d, "\n");
+ for (i = 1; i < g->ncategories; i++)
+ if (nincat[i] != 1) {
+ fprintf(d, "cc%d\t", i);
+ last = -1;
+ for (c = CHAR_MIN; c <= CHAR_MAX+1; c++) /* +1 does flush */
+ if (c <= CHAR_MAX && g->categories[c] == i) {
+ if (last < 0) {
+ fprintf(d, "%s", regchar(c));
+ last = c;
+ }
+ } else {
+ if (last >= 0) {
+ if (last != c-1)
+ fprintf(d, "-%s",
+ regchar(c-1));
+ last = -1;
+ }
+ }
+ fprintf(d, "\n");
+ }
+}
+
+/*
+ - s_print - print the strip for debugging
+ == static void s_print(register struct re_guts *g, FILE *d);
+ */
+static void
+s_print(g, d)
+register struct re_guts *g;
+FILE *d;
+{
+ register sop *s;
+ register cset *cs;
+ register int i;
+ register int done = 0;
+ register sop opnd;
+ register int col = 0;
+ register int last;
+ register sopno offset = 2;
+# define GAP() { if (offset % 5 == 0) { \
+ if (col > 40) { \
+ fprintf(d, "\n\t"); \
+ col = 0; \
+ } else { \
+ fprintf(d, " "); \
+ col++; \
+ } \
+ } else \
+ col++; \
+ offset++; \
+ }
+
+ if (OP(g->strip[0]) != OEND)
+ fprintf(d, "missing initial OEND!\n");
+ for (s = &g->strip[1]; !done; s++) {
+ opnd = OPND(*s);
+ switch (OP(*s)) {
+ case OEND:
+ fprintf(d, "\n");
+ done = 1;
+ break;
+ case OCHAR:
+ if (strchr("\\|()^$.[+*?{}!<> ", (char)opnd) != NULL)
+ fprintf(d, "\\%c", (char)opnd);
+ else
+ fprintf(d, "%s", regchar((char)opnd));
+ break;
+ case OBOL:
+ fprintf(d, "^");
+ break;
+ case OEOL:
+ fprintf(d, "$");
+ break;
+ case OBOW:
+ fprintf(d, "\\{");
+ break;
+ case OEOW:
+ fprintf(d, "\\}");
+ break;
+ case OANY:
+ fprintf(d, ".");
+ break;
+ case OANYOF:
+ fprintf(d, "[(%ld)", (long)opnd);
+ cs = &g->sets[opnd];
+ last = -1;
+ for (i = 0; i < g->csetsize+1; i++) /* +1 flushes */
+ if (CHIN(cs, i) && i < g->csetsize) {
+ if (last < 0) {
+ fprintf(d, "%s", regchar(i));
+ last = i;
+ }
+ } else {
+ if (last >= 0) {
+ if (last != i-1)
+ fprintf(d, "-%s",
+ regchar(i-1));
+ last = -1;
+ }
+ }
+ fprintf(d, "]");
+ break;
+ case OBACK_:
+ fprintf(d, "(\\<%ld>", (long)opnd);
+ break;
+ case O_BACK:
+ fprintf(d, "<%ld>\\)", (long)opnd);
+ break;
+ case OPLUS_:
+ fprintf(d, "(+");
+ if (OP(*(s+opnd)) != O_PLUS)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case O_PLUS:
+ if (OP(*(s-opnd)) != OPLUS_)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, "+)");
+ break;
+ case OQUEST_:
+ fprintf(d, "(?");
+ if (OP(*(s+opnd)) != O_QUEST)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case O_QUEST:
+ if (OP(*(s-opnd)) != OQUEST_)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, "?)");
+ break;
+ case OLPAREN:
+ fprintf(d, "((<%ld>", (long)opnd);
+ break;
+ case ORPAREN:
+ fprintf(d, "<%ld>))", (long)opnd);
+ break;
+ case OCH_:
+ fprintf(d, "<");
+ if (OP(*(s+opnd)) != OOR2)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case OOR1:
+ if (OP(*(s-opnd)) != OOR1 && OP(*(s-opnd)) != OCH_)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, "|");
+ break;
+ case OOR2:
+ fprintf(d, "|");
+ if (OP(*(s+opnd)) != OOR2 && OP(*(s+opnd)) != O_CH)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case O_CH:
+ if (OP(*(s-opnd)) != OOR1)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, ">");
+ break;
+ default:
+ fprintf(d, "!%d(%d)!", OP(*s), opnd);
+ break;
+ }
+ if (!done)
+ GAP();
+ }
+}
+
+/*
+ - regchar - make a character printable
+ == static char *regchar(int ch);
+ */
+static char * /* -> representation */
+regchar(ch)
+int ch;
+{
+ static char buf[10];
+
+ if (isprint(ch) || ch == ' ')
+ sprintf(buf, "%c", ch);
+ else
+ sprintf(buf, "\\%o", ch);
+ return(buf);
+}
diff --git a/vcnet/regex/debug.ih b/vcnet/regex/debug.ih
new file mode 100644
index 000000000..5f40ff791
--- /dev/null
+++ b/vcnet/regex/debug.ih
@@ -0,0 +1,14 @@
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === debug.c === */
+void regprint(regex_t *r, FILE *d);
+static void s_print(register struct re_guts *g, FILE *d);
+static char *regchar(int ch);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
diff --git a/vcnet/regex/engine.c b/vcnet/regex/engine.c
new file mode 100644
index 000000000..0b88dcf1e
--- /dev/null
+++ b/vcnet/regex/engine.c
@@ -0,0 +1,1019 @@
+/*
+ * The matching engine and friends. This file is #included by regexec.c
+ * after suitable #defines of a variety of macros used herein, so that
+ * different state representations can be used without duplicating masses
+ * of code.
+ */
+
+#ifdef SNAMES
+#define matcher smatcher
+#define fast sfast
+#define slow sslow
+#define dissect sdissect
+#define backref sbackref
+#define step sstep
+#define print sprint
+#define at sat
+#define match smat
+#endif
+#ifdef LNAMES
+#define matcher lmatcher
+#define fast lfast
+#define slow lslow
+#define dissect ldissect
+#define backref lbackref
+#define step lstep
+#define print lprint
+#define at lat
+#define match lmat
+#endif
+
+/* another structure passed up and down to avoid zillions of parameters */
+struct match {
+ struct re_guts *g;
+ int eflags;
+ regmatch_t *pmatch; /* [nsub+1] (0 element unused) */
+ char *offp; /* offsets work from here */
+ char *beginp; /* start of string -- virtual NUL precedes */
+ char *endp; /* end of string -- virtual NUL here */
+ char *coldp; /* can be no match starting before here */
+ char **lastpos; /* [nplus+1] */
+ STATEVARS;
+ states st; /* current states */
+ states fresh; /* states for a fresh start */
+ states tmp; /* temporary */
+ states empty; /* empty set of states */
+};
+
+#include "engine.ih"
+
+#ifdef REDEBUG
+#define SP(t, s, c) print(m, t, s, c, stdout)
+#define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2)
+#define NOTE(str) { if (m->eflags&REG_TRACE) printf("=%s\n", (str)); }
+#else
+#define SP(t, s, c) /* nothing */
+#define AT(t, p1, p2, s1, s2) /* nothing */
+#define NOTE(s) /* nothing */
+#endif
+
+/*
+ - matcher - the actual matching engine
+ == static int matcher(register struct re_guts *g, char *string, \
+ == size_t nmatch, regmatch_t pmatch[], int eflags);
+ */
+static int /* 0 success, REG_NOMATCH failure */
+matcher(g, string, nmatch, pmatch, eflags)
+register struct re_guts *g;
+char *string;
+size_t nmatch;
+regmatch_t pmatch[];
+int eflags;
+{
+ register char *endp;
+ register size_t i;
+ struct match mv;
+ register struct match *m = &mv;
+ register char *dp;
+ const register sopno gf = g->firststate+1; /* +1 for OEND */
+ const register sopno gl = g->laststate;
+ char *start;
+ char *stop;
+
+ /* simplify the situation where possible */
+ if (g->cflags&REG_NOSUB)
+ nmatch = 0;
+ if (eflags&REG_STARTEND) {
+ start = string + pmatch[0].rm_so;
+ stop = string + pmatch[0].rm_eo;
+ } else {
+ start = string;
+ stop = start + strlen(start);
+ }
+ if (stop < start)
+ return(REG_INVARG);
+
+ /* prescreening; this does wonders for this rather slow code */
+ if (g->must != NULL) {
+ for (dp = start; dp < stop; dp++)
+ if (*dp == g->must[0] && stop - dp >= g->mlen &&
+ memcmp(dp, g->must, (size_t)g->mlen) == 0)
+ break;
+ if (dp == stop) /* we didn't find g->must */
+ return(REG_NOMATCH);
+ }
+
+ /* match struct setup */
+ m->g = g;
+ m->eflags = eflags;
+ m->pmatch = NULL;
+ m->lastpos = NULL;
+ m->offp = string;
+ m->beginp = start;
+ m->endp = stop;
+ STATESETUP(m, 4);
+ SETUP(m->st);
+ SETUP(m->fresh);
+ SETUP(m->tmp);
+ SETUP(m->empty);
+ CLEAR(m->empty);
+
+ /* this loop does only one repetition except for backrefs */
+ for (;;) {
+ endp = fast(m, start, stop, gf, gl);
+ if (endp == NULL) { /* a miss */
+ STATETEARDOWN(m);
+ return(REG_NOMATCH);
+ }
+ if (nmatch == 0 && !g->backrefs)
+ break; /* no further info needed */
+
+ /* where? */
+ assert(m->coldp != NULL);
+ for (;;) {
+ NOTE("finding start");
+ endp = slow(m, m->coldp, stop, gf, gl);
+ if (endp != NULL)
+ break;
+ assert(m->coldp < m->endp);
+ m->coldp++;
+ }
+ if (nmatch == 1 && !g->backrefs)
+ break; /* no further info needed */
+
+ /* oh my, he wants the subexpressions... */
+ if (m->pmatch == NULL)
+ m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
+ sizeof(regmatch_t));
+ if (m->pmatch == NULL) {
+ STATETEARDOWN(m);
+ return(REG_ESPACE);
+ }
+ for (i = 1; i <= m->g->nsub; i++)
+ m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
+ if (!g->backrefs && !(m->eflags&REG_BACKR)) {
+ NOTE("dissecting");
+ dp = dissect(m, m->coldp, endp, gf, gl);
+ } else {
+ if (g->nplus > 0 && m->lastpos == NULL)
+ m->lastpos = (char **)malloc((g->nplus+1) *
+ sizeof(char *));
+ if (g->nplus > 0 && m->lastpos == NULL) {
+ free(m->pmatch);
+ STATETEARDOWN(m);
+ return(REG_ESPACE);
+ }
+ NOTE("backref dissect");
+ dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
+ }
+ if (dp != NULL)
+ break;
+
+ /* uh-oh... we couldn't find a subexpression-level match */
+ assert(g->backrefs); /* must be back references doing it */
+ assert(g->nplus == 0 || m->lastpos != NULL);
+ for (;;) {
+ if (dp != NULL || endp <= m->coldp)
+ break; /* defeat */
+ NOTE("backoff");
+ endp = slow(m, m->coldp, endp-1, gf, gl);
+ if (endp == NULL)
+ break; /* defeat */
+ /* try it on a shorter possibility */
+#ifndef NDEBUG
+ for (i = 1; i <= m->g->nsub; i++) {
+ assert(m->pmatch[i].rm_so == -1);
+ assert(m->pmatch[i].rm_eo == -1);
+ }
+#endif
+ NOTE("backoff dissect");
+ dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
+ }
+ assert(dp == NULL || dp == endp);
+ if (dp != NULL) /* found a shorter one */
+ break;
+
+ /* despite initial appearances, there is no match here */
+ NOTE("false alarm");
+ start = m->coldp + 1; /* recycle starting later */
+ assert(start <= stop);
+ }
+
+ /* fill in the details if requested */
+ if (nmatch > 0) {
+ pmatch[0].rm_so = m->coldp - m->offp;
+ pmatch[0].rm_eo = endp - m->offp;
+ }
+ if (nmatch > 1) {
+ assert(m->pmatch != NULL);
+ for (i = 1; i < nmatch; i++)
+ if (i <= m->g->nsub)
+ pmatch[i] = m->pmatch[i];
+ else {
+ pmatch[i].rm_so = -1;
+ pmatch[i].rm_eo = -1;
+ }
+ }
+
+ if (m->pmatch != NULL)
+ free((char *)m->pmatch);
+ if (m->lastpos != NULL)
+ free((char *)m->lastpos);
+ STATETEARDOWN(m);
+ return(0);
+}
+
+/*
+ - dissect - figure out what matched what, no back references
+ == static char *dissect(register struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst);
+ */
+static char * /* == stop (success) always */
+dissect(m, start, stop, startst, stopst)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ register int i;
+ register sopno ss; /* start sop of current subRE */
+ register sopno es; /* end sop of current subRE */
+ register char *sp; /* start of string matched by it */
+ register char *stp; /* string matched by it cannot pass here */
+ register char *rest; /* start of rest of string */
+ register char *tail; /* string unmatched by rest of RE */
+ register sopno ssub; /* start sop of subsubRE */
+ register sopno esub; /* end sop of subsubRE */
+ register char *ssp; /* start of string matched by subsubRE */
+ register char *sep; /* end of string matched by subsubRE */
+ register char *oldssp; /* previous ssp */
+ register char *dp;
+
+ AT("diss", start, stop, startst, stopst);
+ sp = start;
+ for (ss = startst; ss < stopst; ss = es) {
+ /* identify end of subRE */
+ es = ss;
+ switch (OP(m->g->strip[es])) {
+ case OPLUS_:
+ case OQUEST_:
+ es += OPND(m->g->strip[es]);
+ break;
+ case OCH_:
+ while (OP(m->g->strip[es]) != O_CH)
+ es += OPND(m->g->strip[es]);
+ break;
+ }
+ es++;
+
+ /* figure out what it matched */
+ switch (OP(m->g->strip[ss])) {
+ case OEND:
+ assert(nope);
+ break;
+ case OCHAR:
+ sp++;
+ break;
+ case OBOL:
+ case OEOL:
+ case OBOW:
+ case OEOW:
+ break;
+ case OANY:
+ case OANYOF:
+ sp++;
+ break;
+ case OBACK_:
+ case O_BACK:
+ assert(nope);
+ break;
+ /* cases where length of match is hard to find */
+ case OQUEST_:
+ stp = stop;
+ for (;;) {
+ /* how long could this one be? */
+ rest = slow(m, sp, stp, ss, es);
+ assert(rest != NULL); /* it did match */
+ /* could the rest match the rest? */
+ tail = slow(m, rest, stop, es, stopst);
+ if (tail == stop)
+ break; /* yes! */
+ /* no -- try a shorter match for this one */
+ stp = rest - 1;
+ assert(stp >= sp); /* it did work */
+ }
+ ssub = ss + 1;
+ esub = es - 1;
+ /* did innards match? */
+ if (slow(m, sp, rest, ssub, esub) != NULL) {
+ dp = dissect(m, sp, rest, ssub, esub);
+ assert(dp == rest);
+ } else /* no */
+ assert(sp == rest);
+ sp = rest;
+ break;
+ case OPLUS_:
+ stp = stop;
+ for (;;) {
+ /* how long could this one be? */
+ rest = slow(m, sp, stp, ss, es);
+ assert(rest != NULL); /* it did match */
+ /* could the rest match the rest? */
+ tail = slow(m, rest, stop, es, stopst);
+ if (tail == stop)
+ break; /* yes! */
+ /* no -- try a shorter match for this one */
+ stp = rest - 1;
+ assert(stp >= sp); /* it did work */
+ }
+ ssub = ss + 1;
+ esub = es - 1;
+ ssp = sp;
+ oldssp = ssp;
+ for (;;) { /* find last match of innards */
+ sep = slow(m, ssp, rest, ssub, esub);
+ if (sep == NULL || sep == ssp)
+ break; /* failed or matched null */
+ oldssp = ssp; /* on to next try */
+ ssp = sep;
+ }
+ if (sep == NULL) {
+ /* last successful match */
+ sep = ssp;
+ ssp = oldssp;
+ }
+ assert(sep == rest); /* must exhaust substring */
+ assert(slow(m, ssp, sep, ssub, esub) == rest);
+ dp = dissect(m, ssp, sep, ssub, esub);
+ assert(dp == sep);
+ sp = rest;
+ break;
+ case OCH_:
+ stp = stop;
+ for (;;) {
+ /* how long could this one be? */
+ rest = slow(m, sp, stp, ss, es);
+ assert(rest != NULL); /* it did match */
+ /* could the rest match the rest? */
+ tail = slow(m, rest, stop, es, stopst);
+ if (tail == stop)
+ break; /* yes! */
+ /* no -- try a shorter match for this one */
+ stp = rest - 1;
+ assert(stp >= sp); /* it did work */
+ }
+ ssub = ss + 1;
+ esub = ss + OPND(m->g->strip[ss]) - 1;
+ assert(OP(m->g->strip[esub]) == OOR1);
+ for (;;) { /* find first matching branch */
+ if (slow(m, sp, rest, ssub, esub) == rest)
+ break; /* it matched all of it */
+ /* that one missed, try next one */
+ assert(OP(m->g->strip[esub]) == OOR1);
+ esub++;
+ assert(OP(m->g->strip[esub]) == OOR2);
+ ssub = esub + 1;
+ esub += OPND(m->g->strip[esub]);
+ if (OP(m->g->strip[esub]) == OOR2)
+ esub--;
+ else
+ assert(OP(m->g->strip[esub]) == O_CH);
+ }
+ dp = dissect(m, sp, rest, ssub, esub);
+ assert(dp == rest);
+ sp = rest;
+ break;
+ case O_PLUS:
+ case O_QUEST:
+ case OOR1:
+ case OOR2:
+ case O_CH:
+ assert(nope);
+ break;
+ case OLPAREN:
+ i = OPND(m->g->strip[ss]);
+ assert(0 < i && i <= m->g->nsub);
+ m->pmatch[i].rm_so = sp - m->offp;
+ break;
+ case ORPAREN:
+ i = OPND(m->g->strip[ss]);
+ assert(0 < i && i <= m->g->nsub);
+ m->pmatch[i].rm_eo = sp - m->offp;
+ break;
+ default: /* uh oh */
+ assert(nope);
+ break;
+ }
+ }
+
+ assert(sp == stop);
+ return(sp);
+}
+
+/*
+ - backref - figure out what matched what, figuring in back references
+ == static char *backref(register struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst, sopno lev);
+ */
+static char * /* == stop (success) or NULL (failure) */
+backref(m, start, stop, startst, stopst, lev)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+sopno lev; /* PLUS nesting level */
+{
+ register int i;
+ register sopno ss; /* start sop of current subRE */
+ register char *sp; /* start of string matched by it */
+ register sopno ssub; /* start sop of subsubRE */
+ register sopno esub; /* end sop of subsubRE */
+ register char *ssp; /* start of string matched by subsubRE */
+ register char *dp;
+ register size_t len;
+ register int hard;
+ register sop s;
+ register regoff_t offsave;
+ register cset *cs;
+
+ AT("back", start, stop, startst, stopst);
+ sp = start;
+
+ /* get as far as we can with easy stuff */
+ hard = 0;
+ for (ss = startst; !hard && ss < stopst; ss++)
+ switch (OP(s = m->g->strip[ss])) {
+ case OCHAR:
+ if (sp == stop || *sp++ != (char)OPND(s))
+ return(NULL);
+ break;
+ case OANY:
+ if (sp == stop)
+ return(NULL);
+ sp++;
+ break;
+ case OANYOF:
+ cs = &m->g->sets[OPND(s)];
+ if (sp == stop || !CHIN(cs, *sp++))
+ return(NULL);
+ break;
+ case OBOL:
+ if ( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
+ (sp < m->endp && *(sp-1) == '\n' &&
+ (m->g->cflags&REG_NEWLINE)) )
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case OEOL:
+ if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
+ (sp < m->endp && *sp == '\n' &&
+ (m->g->cflags&REG_NEWLINE)) )
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case OBOW:
+ if (( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
+ (sp < m->endp && *(sp-1) == '\n' &&
+ (m->g->cflags&REG_NEWLINE)) ||
+ (sp > m->beginp &&
+ !ISWORD(*(sp-1))) ) &&
+ (sp < m->endp && ISWORD(*sp)) )
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case OEOW:
+ if (( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
+ (sp < m->endp && *sp == '\n' &&
+ (m->g->cflags&REG_NEWLINE)) ||
+ (sp < m->endp && !ISWORD(*sp)) ) &&
+ (sp > m->beginp && ISWORD(*(sp-1))) )
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case O_QUEST:
+ break;
+ case OOR1: /* matches null but needs to skip */
+ ss++;
+ s = m->g->strip[ss];
+ do {
+ assert(OP(s) == OOR2);
+ ss += OPND(s);
+ } while (OP(s = m->g->strip[ss]) != O_CH);
+ /* note that the ss++ gets us past the O_CH */
+ break;
+ default: /* have to make a choice */
+ hard = 1;
+ break;
+ }
+ if (!hard) { /* that was it! */
+ if (sp != stop)
+ return(NULL);
+ return(sp);
+ }
+ ss--; /* adjust for the for's final increment */
+
+ /* the hard stuff */
+ AT("hard", sp, stop, ss, stopst);
+ s = m->g->strip[ss];
+ switch (OP(s)) {
+ case OBACK_: /* the vilest depths */
+ i = OPND(s);
+ assert(0 < i && i <= m->g->nsub);
+ if (m->pmatch[i].rm_eo == -1)
+ return(NULL);
+ assert(m->pmatch[i].rm_so != -1);
+ len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
+ assert(stop - m->beginp >= len);
+ if (sp > stop - len)
+ return(NULL); /* not enough left to match */
+ ssp = m->offp + m->pmatch[i].rm_so;
+ if (memcmp(sp, ssp, len) != 0)
+ return(NULL);
+ while (m->g->strip[ss] != SOP(O_BACK, i))
+ ss++;
+ return(backref(m, sp+len, stop, ss+1, stopst, lev));
+ break;
+ case OQUEST_: /* to null or not */
+ dp = backref(m, sp, stop, ss+1, stopst, lev);
+ if (dp != NULL)
+ return(dp); /* not */
+ return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev));
+ break;
+ case OPLUS_:
+ assert(m->lastpos != NULL);
+ assert(lev+1 <= m->g->nplus);
+ m->lastpos[lev+1] = sp;
+ return(backref(m, sp, stop, ss+1, stopst, lev+1));
+ break;
+ case O_PLUS:
+ if (sp == m->lastpos[lev]) /* last pass matched null */
+ return(backref(m, sp, stop, ss+1, stopst, lev-1));
+ /* try another pass */
+ m->lastpos[lev] = sp;
+ dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev);
+ if (dp == NULL)
+ return(backref(m, sp, stop, ss+1, stopst, lev-1));
+ else
+ return(dp);
+ break;
+ case OCH_: /* find the right one, if any */
+ ssub = ss + 1;
+ esub = ss + OPND(s) - 1;
+ assert(OP(m->g->strip[esub]) == OOR1);
+ for (;;) { /* find first matching branch */
+ dp = backref(m, sp, stop, ssub, esub, lev);
+ if (dp != NULL)
+ return(dp);
+ /* that one missed, try next one */
+ if (OP(m->g->strip[esub]) == O_CH)
+ return(NULL); /* there is none */
+ esub++;
+ assert(OP(m->g->strip[esub]) == OOR2);
+ ssub = esub + 1;
+ esub += OPND(m->g->strip[esub]);
+ if (OP(m->g->strip[esub]) == OOR2)
+ esub--;
+ else
+ assert(OP(m->g->strip[esub]) == O_CH);
+ }
+ break;
+ case OLPAREN: /* must undo assignment if rest fails */
+ i = OPND(s);
+ assert(0 < i && i <= m->g->nsub);
+ offsave = m->pmatch[i].rm_so;
+ m->pmatch[i].rm_so = sp - m->offp;
+ dp = backref(m, sp, stop, ss+1, stopst, lev);
+ if (dp != NULL)
+ return(dp);
+ m->pmatch[i].rm_so = offsave;
+ return(NULL);
+ break;
+ case ORPAREN: /* must undo assignment if rest fails */
+ i = OPND(s);
+ assert(0 < i && i <= m->g->nsub);
+ offsave = m->pmatch[i].rm_eo;
+ m->pmatch[i].rm_eo = sp - m->offp;
+ dp = backref(m, sp, stop, ss+1, stopst, lev);
+ if (dp != NULL)
+ return(dp);
+ m->pmatch[i].rm_eo = offsave;
+ return(NULL);
+ break;
+ default: /* uh oh */
+ assert(nope);
+ break;
+ }
+
+ /* "can't happen" */
+ assert(nope);
+ /* NOTREACHED */
+ return((char *)NULL); /* dummy */
+}
+
+/*
+ - fast - step through the string at top speed
+ == static char *fast(register struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst);
+ */
+static char * /* where tentative match ended, or NULL */
+fast(m, start, stop, startst, stopst)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ register states st = m->st;
+ register states fresh = m->fresh;
+ register states tmp = m->tmp;
+ register char *p = start;
+ register int c = (start == m->beginp) ? OUT : *(start-1);
+ register int lastc; /* previous c */
+ register int flagch;
+ register int i;
+ register char *coldp; /* last p after which no match was underway */
+
+ CLEAR(st);
+ SET1(st, startst);
+ st = step(m->g, startst, stopst, st, NOTHING, st);
+ ASSIGN(fresh, st);
+ SP("start", st, *p);
+ coldp = NULL;
+ for (;;) {
+ /* next character */
+ lastc = c;
+ c = (p == m->endp) ? OUT : *p;
+ if (EQ(st, fresh))
+ coldp = p;
+
+ /* is there an EOL and/or BOL between lastc and c? */
+ flagch = '\0';
+ i = 0;
+ if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
+ (lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
+ flagch = BOL;
+ i = m->g->nbol;
+ }
+ if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
+ (c == OUT && !(m->eflags&REG_NOTEOL)) ) {
+ flagch = (flagch == BOL) ? BOLEOL : EOL;
+ i += m->g->neol;
+ }
+ if (i != 0) {
+ for (; i > 0; i--)
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("boleol", st, c);
+ }
+
+ /* how about a word boundary? */
+ if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+ (c != OUT && ISWORD(c)) ) {
+ flagch = BOW;
+ }
+ if ( (lastc != OUT && ISWORD(lastc)) &&
+ (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
+ flagch = EOW;
+ }
+ if (flagch == BOW || flagch == EOW) {
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("boweow", st, c);
+ }
+
+ /* are we done? */
+ if (ISSET(st, stopst) || p == stop)
+ break; /* NOTE BREAK OUT */
+
+ /* no, we must deal with this character */
+ ASSIGN(tmp, st);
+ ASSIGN(st, fresh);
+ assert(c != OUT);
+ st = step(m->g, startst, stopst, tmp, c, st);
+ SP("aft", st, c);
+ assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
+ p++;
+ }
+
+ assert(coldp != NULL);
+ m->coldp = coldp;
+ if (ISSET(st, stopst))
+ return(p+1);
+ else
+ return(NULL);
+}
+
+/*
+ - slow - step through the string more deliberately
+ == static char *slow(register struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst);
+ */
+static char * /* where it ended */
+slow(m, start, stop, startst, stopst)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ register states st = m->st;
+ register states empty = m->empty;
+ register states tmp = m->tmp;
+ register char *p = start;
+ register int c = (start == m->beginp) ? OUT : *(start-1);
+ register int lastc; /* previous c */
+ register int flagch;
+ register int i;
+ register char *matchp; /* last p at which a match ended */
+
+ AT("slow", start, stop, startst, stopst);
+ CLEAR(st);
+ SET1(st, startst);
+ SP("sstart", st, *p);
+ st = step(m->g, startst, stopst, st, NOTHING, st);
+ matchp = NULL;
+ for (;;) {
+ /* next character */
+ lastc = c;
+ c = (p == m->endp) ? OUT : *p;
+
+ /* is there an EOL and/or BOL between lastc and c? */
+ flagch = '\0';
+ i = 0;
+ if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
+ (lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
+ flagch = BOL;
+ i = m->g->nbol;
+ }
+ if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
+ (c == OUT && !(m->eflags&REG_NOTEOL)) ) {
+ flagch = (flagch == BOL) ? BOLEOL : EOL;
+ i += m->g->neol;
+ }
+ if (i != 0) {
+ for (; i > 0; i--)
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("sboleol", st, c);
+ }
+
+ /* how about a word boundary? */
+ if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+ (c != OUT && ISWORD(c)) ) {
+ flagch = BOW;
+ }
+ if ( (lastc != OUT && ISWORD(lastc)) &&
+ (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
+ flagch = EOW;
+ }
+ if (flagch == BOW || flagch == EOW) {
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("sboweow", st, c);
+ }
+
+ /* are we done? */
+ if (ISSET(st, stopst))
+ matchp = p;
+ if (EQ(st, empty) || p == stop)
+ break; /* NOTE BREAK OUT */
+
+ /* no, we must deal with this character */
+ ASSIGN(tmp, st);
+ ASSIGN(st, empty);
+ assert(c != OUT);
+ st = step(m->g, startst, stopst, tmp, c, st);
+ SP("saft", st, c);
+ assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
+ p++;
+ }
+
+ return(matchp);
+}
+
+
+/*
+ - step - map set of states reachable before char to set reachable after
+ == static states step(register struct re_guts *g, sopno start, sopno stop, \
+ == register states bef, int ch, register states aft);
+ == #define BOL (OUT+1)
+ == #define EOL (BOL+1)
+ == #define BOLEOL (BOL+2)
+ == #define NOTHING (BOL+3)
+ == #define BOW (BOL+4)
+ == #define EOW (BOL+5)
+ == #define CODEMAX (BOL+5) // highest code used
+ == #define NONCHAR(c) ((c) > CHAR_MAX)
+ == #define NNONCHAR (CODEMAX-CHAR_MAX)
+ */
+static states
+step(g, start, stop, bef, ch, aft)
+register struct re_guts *g;
+sopno start; /* start state within strip */
+sopno stop; /* state after stop state within strip */
+register states bef; /* states reachable before */
+int ch; /* character or NONCHAR code */
+register states aft; /* states already known reachable after */
+{
+ register cset *cs;
+ register sop s;
+ register sopno pc;
+ register onestate here; /* note, macros know this name */
+ register sopno look;
+ register long i;
+
+ for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
+ s = g->strip[pc];
+ switch (OP(s)) {
+ case OEND:
+ assert(pc == stop-1);
+ break;
+ case OCHAR:
+ /* only characters can match */
+ assert(!NONCHAR(ch) || ch != (char)OPND(s));
+ if (ch == (char)OPND(s))
+ FWD(aft, bef, 1);
+ break;
+ case OBOL:
+ if (ch == BOL || ch == BOLEOL)
+ FWD(aft, bef, 1);
+ break;
+ case OEOL:
+ if (ch == EOL || ch == BOLEOL)
+ FWD(aft, bef, 1);
+ break;
+ case OBOW:
+ if (ch == BOW)
+ FWD(aft, bef, 1);
+ break;
+ case OEOW:
+ if (ch == EOW)
+ FWD(aft, bef, 1);
+ break;
+ case OANY:
+ if (!NONCHAR(ch))
+ FWD(aft, bef, 1);
+ break;
+ case OANYOF:
+ cs = &g->sets[OPND(s)];
+ if (!NONCHAR(ch) && CHIN(cs, ch))
+ FWD(aft, bef, 1);
+ break;
+ case OBACK_: /* ignored here */
+ case O_BACK:
+ FWD(aft, aft, 1);
+ break;
+ case OPLUS_: /* forward, this is just an empty */
+ FWD(aft, aft, 1);
+ break;
+ case O_PLUS: /* both forward and back */
+ FWD(aft, aft, 1);
+ i = ISSETBACK(aft, OPND(s));
+ BACK(aft, aft, OPND(s));
+ if (!i && ISSETBACK(aft, OPND(s))) {
+ /* oho, must reconsider loop body */
+ pc -= OPND(s) + 1;
+ INIT(here, pc);
+ }
+ break;
+ case OQUEST_: /* two branches, both forward */
+ FWD(aft, aft, 1);
+ FWD(aft, aft, OPND(s));
+ break;
+ case O_QUEST: /* just an empty */
+ FWD(aft, aft, 1);
+ break;
+ case OLPAREN: /* not significant here */
+ case ORPAREN:
+ FWD(aft, aft, 1);
+ break;
+ case OCH_: /* mark the first two branches */
+ FWD(aft, aft, 1);
+ assert(OP(g->strip[pc+OPND(s)]) == OOR2);
+ FWD(aft, aft, OPND(s));
+ break;
+ case OOR1: /* done a branch, find the O_CH */
+ if (ISSTATEIN(aft, here)) {
+ for (look = 1;
+ OP(s = g->strip[pc+look]) != O_CH;
+ look += OPND(s))
+ assert(OP(s) == OOR2);
+ FWD(aft, aft, look);
+ }
+ break;
+ case OOR2: /* propagate OCH_'s marking */
+ FWD(aft, aft, 1);
+ if (OP(g->strip[pc+OPND(s)]) != O_CH) {
+ assert(OP(g->strip[pc+OPND(s)]) == OOR2);
+ FWD(aft, aft, OPND(s));
+ }
+ break;
+ case O_CH: /* just empty */
+ FWD(aft, aft, 1);
+ break;
+ default: /* ooooops... */
+ assert(nope);
+ break;
+ }
+ }
+
+ return(aft);
+}
+
+#ifdef REDEBUG
+/*
+ - print - print a set of states
+ == #ifdef REDEBUG
+ == static void print(struct match *m, char *caption, states st, \
+ == int ch, FILE *d);
+ == #endif
+ */
+static void
+print(m, caption, st, ch, d)
+struct match *m;
+char *caption;
+states st;
+int ch;
+FILE *d;
+{
+ register struct re_guts *g = m->g;
+ register int i;
+ register int first = 1;
+
+ if (!(m->eflags&REG_TRACE))
+ return;
+
+ fprintf(d, "%s", caption);
+ if (ch != '\0')
+ fprintf(d, " %s", pchar(ch));
+ for (i = 0; i < g->nstates; i++)
+ if (ISSET(st, i)) {
+ fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
+ first = 0;
+ }
+ fprintf(d, "\n");
+}
+
+/*
+ - at - print current situation
+ == #ifdef REDEBUG
+ == static void at(struct match *m, char *title, char *start, char *stop, \
+ == sopno startst, sopno stopst);
+ == #endif
+ */
+static void
+at(m, title, start, stop, startst, stopst)
+struct match *m;
+char *title;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ if (!(m->eflags&REG_TRACE))
+ return;
+
+ printf("%s %s-", title, pchar(*start));
+ printf("%s ", pchar(*stop));
+ printf("%ld-%ld\n", (long)startst, (long)stopst);
+}
+
+#ifndef PCHARDONE
+#define PCHARDONE /* never again */
+/*
+ - pchar - make a character printable
+ == #ifdef REDEBUG
+ == static char *pchar(int ch);
+ == #endif
+ *
+ * Is this identical to regchar() over in debug.c? Well, yes. But a
+ * duplicate here avoids having a debugging-capable regexec.o tied to
+ * a matching debug.o, and this is convenient. It all disappears in
+ * the non-debug compilation anyway, so it doesn't matter much.
+ */
+static char * /* -> representation */
+pchar(ch)
+int ch;
+{
+ static char pbuf[10];
+
+ if (isprint(ch) || ch == ' ')
+ sprintf(pbuf, "%c", ch);
+ else
+ sprintf(pbuf, "\\%o", ch);
+ return(pbuf);
+}
+#endif
+#endif
+
+#undef matcher
+#undef fast
+#undef slow
+#undef dissect
+#undef backref
+#undef step
+#undef print
+#undef at
+#undef match
diff --git a/vcnet/regex/engine.ih b/vcnet/regex/engine.ih
new file mode 100644
index 000000000..cc98334e7
--- /dev/null
+++ b/vcnet/regex/engine.ih
@@ -0,0 +1,35 @@
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === engine.c === */
+static int matcher(register struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
+static char *dissect(register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
+static char *backref(register struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev);
+static char *fast(register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
+static char *slow(register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
+static states step(register struct re_guts *g, sopno start, sopno stop, register states bef, int ch, register states aft);
+#define BOL (OUT+1)
+#define EOL (BOL+1)
+#define BOLEOL (BOL+2)
+#define NOTHING (BOL+3)
+#define BOW (BOL+4)
+#define EOW (BOL+5)
+#define CODEMAX (BOL+5) /* highest code used */
+#define NONCHAR(c) ((c) > CHAR_MAX)
+#define NNONCHAR (CODEMAX-CHAR_MAX)
+#ifdef REDEBUG
+static void print(struct match *m, char *caption, states st, int ch, FILE *d);
+#endif
+#ifdef REDEBUG
+static void at(struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst);
+#endif
+#ifdef REDEBUG
+static char *pchar(int ch);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
diff --git a/vcnet/regex/main.c b/vcnet/regex/main.c
new file mode 100644
index 000000000..0221e7713
--- /dev/null
+++ b/vcnet/regex/main.c
@@ -0,0 +1,510 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <assert.h>
+
+#include "main.ih"
+
+char *progname;
+int debug = 0;
+int line = 0;
+int status = 0;
+
+int copts = REG_EXTENDED;
+int eopts = 0;
+regoff_t startoff = 0;
+regoff_t endoff = 0;
+
+
+extern int split();
+extern void regprint();
+
+/*
+ - main - do the simple case, hand off to regress() for regression
+ */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ regex_t re;
+# define NS 10
+ regmatch_t subs[NS];
+ char erbuf[100];
+ int err;
+ size_t len;
+ int c;
+ int errflg = 0;
+ register int i;
+ extern int optind;
+ extern char *optarg;
+
+ progname = argv[0];
+
+ while ((c = getopt(argc, argv, "c:e:S:E:x")) != EOF)
+ switch (c) {
+ case 'c': /* compile options */
+ copts = options('c', optarg);
+ break;
+ case 'e': /* execute options */
+ eopts = options('e', optarg);
+ break;
+ case 'S': /* start offset */
+ startoff = (regoff_t)atoi(optarg);
+ break;
+ case 'E': /* end offset */
+ endoff = (regoff_t)atoi(optarg);
+ break;
+ case 'x': /* Debugging. */
+ debug++;
+ break;
+ case '?':
+ default:
+ errflg++;
+ break;
+ }
+ if (errflg) {
+ fprintf(stderr, "usage: %s ", progname);
+ fprintf(stderr, "[-c copt][-C][-d] [re]\n");
+ exit(2);
+ }
+
+ if (optind >= argc) {
+ regress(stdin);
+ exit(status);
+ }
+
+ err = regcomp(&re, argv[optind++], copts);
+ if (err) {
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "error %s, %d/%d `%s'\n",
+ eprint(err), len, sizeof(erbuf), erbuf);
+ exit(status);
+ }
+ regprint(&re, stdout);
+
+ if (optind >= argc) {
+ regfree(&re);
+ exit(status);
+ }
+
+ if (eopts&REG_STARTEND) {
+ subs[0].rm_so = startoff;
+ subs[0].rm_eo = strlen(argv[optind]) - endoff;
+ }
+ err = regexec(&re, argv[optind], (size_t)NS, subs, eopts);
+ if (err) {
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "error %s, %d/%d `%s'\n",
+ eprint(err), len, sizeof(erbuf), erbuf);
+ exit(status);
+ }
+ if (!(copts&REG_NOSUB)) {
+ len = (int)(subs[0].rm_eo - subs[0].rm_so);
+ if (subs[0].rm_so != -1) {
+ if (len != 0)
+ printf("match `%.*s'\n", len,
+ argv[optind] + subs[0].rm_so);
+ else
+ printf("match `'@%.1s\n",
+ argv[optind] + subs[0].rm_so);
+ }
+ for (i = 1; i < NS; i++)
+ if (subs[i].rm_so != -1)
+ printf("(%d) `%.*s'\n", i,
+ (int)(subs[i].rm_eo - subs[i].rm_so),
+ argv[optind] + subs[i].rm_so);
+ }
+ exit(status);
+}
+
+/*
+ - regress - main loop of regression test
+ == void regress(FILE *in);
+ */
+void
+regress(in)
+FILE *in;
+{
+ char inbuf[1000];
+# define MAXF 10
+ char *f[MAXF];
+ int nf;
+ int i;
+ char erbuf[100];
+ size_t ne;
+ char *badpat = "invalid regular expression";
+# define SHORT 10
+ char *bpname = "REG_BADPAT";
+ regex_t re;
+
+ while (fgets(inbuf, sizeof(inbuf), in) != NULL) {
+ line++;
+ if (inbuf[0] == '#' || inbuf[0] == '\n')
+ continue; /* NOTE CONTINUE */
+ inbuf[strlen(inbuf)-1] = '\0'; /* get rid of stupid \n */
+ if (debug)
+ fprintf(stdout, "%d:\n", line);
+ nf = split(inbuf, f, MAXF, "\t\t");
+ if (nf < 3) {
+ fprintf(stderr, "bad input, line %d\n", line);
+ exit(1);
+ }
+ for (i = 0; i < nf; i++)
+ if (strcmp(f[i], "\"\"") == 0)
+ f[i] = "";
+ if (nf <= 3)
+ f[3] = NULL;
+ if (nf <= 4)
+ f[4] = NULL;
+ try(f[0], f[1], f[2], f[3], f[4], options('c', f[1]));
+ if (opt('&', f[1])) /* try with either type of RE */
+ try(f[0], f[1], f[2], f[3], f[4],
+ options('c', f[1]) &~ REG_EXTENDED);
+ }
+
+ ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf));
+ if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) {
+ fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n",
+ erbuf, badpat);
+ status = 1;
+ }
+ ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, (size_t)SHORT);
+ if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' ||
+ ne != strlen(badpat)+1) {
+ fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n",
+ erbuf, SHORT-1, badpat);
+ status = 1;
+ }
+ ne = regerror(REG_ITOA|REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf));
+ if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname)+1) {
+ fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n",
+ erbuf, bpname);
+ status = 1;
+ }
+ re.re_endp = bpname;
+ ne = regerror(REG_ATOI, &re, erbuf, sizeof(erbuf));
+ if (atoi(erbuf) != (int)REG_BADPAT) {
+ fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n",
+ erbuf, (long)REG_BADPAT);
+ status = 1;
+ } else if (ne != strlen(erbuf)+1) {
+ fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n",
+ erbuf, (long)REG_BADPAT);
+ status = 1;
+ }
+}
+
+/*
+ - try - try it, and report on problems
+ == void try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
+ */
+void
+try(f0, f1, f2, f3, f4, opts)
+char *f0;
+char *f1;
+char *f2;
+char *f3;
+char *f4;
+int opts; /* may not match f1 */
+{
+ regex_t re;
+# define NSUBS 10
+ regmatch_t subs[NSUBS];
+# define NSHOULD 15
+ char *should[NSHOULD];
+ int nshould;
+ char erbuf[100];
+ int err;
+ int len;
+ char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
+ register int i;
+ char *grump;
+ char f0copy[1000];
+ char f2copy[1000];
+
+ strcpy(f0copy, f0);
+ re.re_endp = (opts&REG_PEND) ? f0copy + strlen(f0copy) : NULL;
+ fixstr(f0copy);
+ err = regcomp(&re, f0copy, opts);
+ if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
+ /* unexpected error or wrong error */
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "%d: %s error %s, %d/%d `%s'\n",
+ line, type, eprint(err), len,
+ sizeof(erbuf), erbuf);
+ status = 1;
+ } else if (err == 0 && opt('C', f1)) {
+ /* unexpected success */
+ fprintf(stderr, "%d: %s should have given REG_%s\n",
+ line, type, f2);
+ status = 1;
+ err = 1; /* so we won't try regexec */
+ }
+
+ if (err != 0) {
+ regfree(&re);
+ return;
+ }
+
+ strcpy(f2copy, f2);
+ fixstr(f2copy);
+
+ if (options('e', f1)&REG_STARTEND) {
+ if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL)
+ fprintf(stderr, "%d: bad STARTEND syntax\n", line);
+ subs[0].rm_so = strchr(f2, '(') - f2 + 1;
+ subs[0].rm_eo = strchr(f2, ')') - f2;
+ }
+ err = regexec(&re, f2copy, NSUBS, subs, options('e', f1));
+
+ if (err != 0 && (f3 != NULL || err != REG_NOMATCH)) {
+ /* unexpected error or wrong error */
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "%d: %s exec error %s, %d/%d `%s'\n",
+ line, type, eprint(err), len,
+ sizeof(erbuf), erbuf);
+ status = 1;
+ } else if (err != 0) {
+ /* nothing more to check */
+ } else if (f3 == NULL) {
+ /* unexpected success */
+ fprintf(stderr, "%d: %s exec should have failed\n",
+ line, type);
+ status = 1;
+ err = 1; /* just on principle */
+ } else if (opts&REG_NOSUB) {
+ /* nothing more to check */
+ } else if ((grump = check(f2, subs[0], f3)) != NULL) {
+ fprintf(stderr, "%d: %s %s\n", line, type, grump);
+ status = 1;
+ err = 1;
+ }
+
+ if (err != 0 || f4 == NULL) {
+ regfree(&re);
+ return;
+ }
+
+ for (i = 1; i < NSHOULD; i++)
+ should[i] = NULL;
+ nshould = split(f4, should+1, NSHOULD-1, ",");
+ if (nshould == 0) {
+ nshould = 1;
+ should[1] = "";
+ }
+ for (i = 1; i < NSUBS; i++) {
+ grump = check(f2, subs[i], should[i]);
+ if (grump != NULL) {
+ fprintf(stderr, "%d: %s $%d %s\n", line,
+ type, i, grump);
+ status = 1;
+ err = 1;
+ }
+ }
+
+ regfree(&re);
+}
+
+/*
+ - options - pick options out of a regression-test string
+ == int options(int type, char *s);
+ */
+int
+options(type, s)
+int type; /* 'c' compile, 'e' exec */
+char *s;
+{
+ register char *p;
+ register int o = (type == 'c') ? copts : eopts;
+ register char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
+
+ for (p = s; *p != '\0'; p++)
+ if (strchr(legal, *p) != NULL)
+ switch (*p) {
+ case 'b':
+ o &= ~REG_EXTENDED;
+ break;
+ case 'i':
+ o |= REG_ICASE;
+ break;
+ case 's':
+ o |= REG_NOSUB;
+ break;
+ case 'n':
+ o |= REG_NEWLINE;
+ break;
+ case 'm':
+ o &= ~REG_EXTENDED;
+ o |= REG_NOSPEC;
+ break;
+ case 'p':
+ o |= REG_PEND;
+ break;
+ case '^':
+ o |= REG_NOTBOL;
+ break;
+ case '$':
+ o |= REG_NOTEOL;
+ break;
+ case '#':
+ o |= REG_STARTEND;
+ break;
+ case 't': /* trace */
+ o |= REG_TRACE;
+ break;
+ case 'l': /* force long representation */
+ o |= REG_LARGE;
+ break;
+ case 'r': /* force backref use */
+ o |= REG_BACKR;
+ break;
+ }
+ return(o);
+}
+
+/*
+ - opt - is a particular option in a regression string?
+ == int opt(int c, char *s);
+ */
+int /* predicate */
+opt(c, s)
+int c;
+char *s;
+{
+ return(strchr(s, c) != NULL);
+}
+
+/*
+ - fixstr - transform magic characters in strings
+ == void fixstr(register char *p);
+ */
+void
+fixstr(p)
+register char *p;
+{
+ if (p == NULL)
+ return;
+
+ for (; *p != '\0'; p++)
+ if (*p == 'N')
+ *p = '\n';
+ else if (*p == 'T')
+ *p = '\t';
+ else if (*p == 'S')
+ *p = ' ';
+ else if (*p == 'Z')
+ *p = '\0';
+}
+
+/*
+ - check - check a substring match
+ == char *check(char *str, regmatch_t sub, char *should);
+ */
+char * /* NULL or complaint */
+check(str, sub, should)
+char *str;
+regmatch_t sub;
+char *should;
+{
+ register int len;
+ register int shlen;
+ register char *p;
+ static char grump[500];
+ register char *at = NULL;
+
+ if (should != NULL && strcmp(should, "-") == 0)
+ should = NULL;
+ if (should != NULL && should[0] == '@') {
+ at = should + 1;
+ should = "";
+ }
+
+ /* check rm_so and rm_eo for consistency */
+ if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) ||
+ (sub.rm_so != -1 && sub.rm_eo == -1) ||
+ (sub.rm_so != -1 && sub.rm_so < 0) ||
+ (sub.rm_eo != -1 && sub.rm_eo < 0) ) {
+ sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
+ (long)sub.rm_eo);
+ return(grump);
+ }
+
+ /* check for no match */
+ if (sub.rm_so == -1 && should == NULL)
+ return(NULL);
+ if (sub.rm_so == -1)
+ return("did not match");
+
+ /* check for in range */
+ if (sub.rm_eo > strlen(str)) {
+ sprintf(grump, "start %ld end %ld, past end of string",
+ (long)sub.rm_so, (long)sub.rm_eo);
+ return(grump);
+ }
+
+ len = (int)(sub.rm_eo - sub.rm_so);
+ shlen = (int)strlen(should);
+ p = str + sub.rm_so;
+
+ /* check for not supposed to match */
+ if (should == NULL) {
+ sprintf(grump, "matched `%.*s'", len, p);
+ return(grump);
+ }
+
+ /* check for wrong match */
+ if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
+ sprintf(grump, "matched `%.*s' instead", len, p);
+ return(grump);
+ }
+ if (shlen > 0)
+ return(NULL);
+
+ /* check null match in right place */
+ if (at == NULL)
+ return(NULL);
+ shlen = strlen(at);
+ if (shlen == 0)
+ shlen = 1; /* force check for end-of-string */
+ if (strncmp(p, at, shlen) != 0) {
+ sprintf(grump, "matched null at `%.20s'", p);
+ return(grump);
+ }
+ return(NULL);
+}
+
+/*
+ - eprint - convert error number to name
+ == static char *eprint(int err);
+ */
+static char *
+eprint(err)
+int err;
+{
+ static char epbuf[100];
+ size_t len;
+
+ len = regerror(REG_ITOA|err, (regex_t *)NULL, epbuf, sizeof(epbuf));
+ assert(len <= sizeof(epbuf));
+ return(epbuf);
+}
+
+/*
+ - efind - convert error name to number
+ == static int efind(char *name);
+ */
+static int
+efind(name)
+char *name;
+{
+ static char efbuf[100];
+ size_t n;
+ regex_t re;
+
+ sprintf(efbuf, "REG_%s", name);
+ assert(strlen(efbuf) < sizeof(efbuf));
+ re.re_endp = efbuf;
+ (void) regerror(REG_ATOI, &re, efbuf, sizeof(efbuf));
+ return(atoi(efbuf));
+}
diff --git a/vcnet/regex/main.ih b/vcnet/regex/main.ih
new file mode 100644
index 000000000..5a0118ac4
--- /dev/null
+++ b/vcnet/regex/main.ih
@@ -0,0 +1,19 @@
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === main.c === */
+void regress(FILE *in);
+void try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
+int options(int type, char *s);
+int opt(int c, char *s);
+void fixstr(register char *p);
+char *check(char *str, regmatch_t sub, char *should);
+static char *eprint(int err);
+static int efind(char *name);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
diff --git a/vcnet/regex/mkh b/vcnet/regex/mkh
new file mode 100644
index 000000000..252b246c7
--- /dev/null
+++ b/vcnet/regex/mkh
@@ -0,0 +1,76 @@
+#! /bin/sh
+# mkh - pull headers out of C source
+PATH=/bin:/usr/bin ; export PATH
+
+# egrep pattern to pick out marked lines
+egrep='^ =([ ]|$)'
+
+# Sed program to process marked lines into lines for the header file.
+# The markers have already been removed. Two things are done here: removal
+# of backslashed newlines, and some fudging of comments. The first is done
+# because -o needs to have prototypes on one line to strip them down.
+# Getting comments into the output is tricky; we turn C++-style // comments
+# into /* */ comments, after altering any existing */'s to avoid trouble.
+peel=' /\\$/N
+ /\\\n[ ]*/s///g
+ /\/\//s;\*/;* /;g
+ /\/\//s;//\(.*\);/*\1 */;'
+
+for a
+do
+ case "$a" in
+ -o) # old (pre-function-prototype) compiler
+ # add code to comment out argument lists
+ peel="$peel
+ "'/^\([^#\/][^\/]*[a-zA-Z0-9_)]\)(\(.*\))/s;;\1(/*\2*/);'
+ shift
+ ;;
+ -b) # funny Berkeley __P macro
+ peel="$peel
+ "'/^\([^#\/][^\/]*[a-zA-Z0-9_)]\)(\(.*\))/s;;\1 __P((\2));'
+ shift
+ ;;
+ -s) # compiler doesn't like `static foo();'
+ # add code to get rid of the `static'
+ peel="$peel
+ "'/^static[ ][^\/]*[a-zA-Z0-9_)](.*)/s;static.;;'
+ shift
+ ;;
+ -p) # private declarations
+ egrep='^ ==([ ]|$)'
+ shift
+ ;;
+ -i) # wrap in #ifndef, argument is name
+ ifndef="$2"
+ shift ; shift
+ ;;
+ *) break
+ ;;
+ esac
+done
+
+if test " $ifndef" != " "
+then
+ echo "#ifndef $ifndef"
+ echo "#define $ifndef /* never again */"
+fi
+echo "/* ========= begin header generated by $0 ========= */"
+echo '#ifdef __cplusplus'
+echo 'extern "C" {'
+echo '#endif'
+for f
+do
+ echo
+ echo "/* === $f === */"
+ egrep "$egrep" $f | sed 's/^ ==*[ ]//;s/^ ==*$//' | sed "$peel"
+ echo
+done
+echo '#ifdef __cplusplus'
+echo '}'
+echo '#endif'
+echo "/* ========= end header generated by $0 ========= */"
+if test " $ifndef" != " "
+then
+ echo "#endif"
+fi
+exit 0
diff --git a/vcnet/regex/regcomp.c b/vcnet/regex/regcomp.c
new file mode 100644
index 000000000..5df5d53fc
--- /dev/null
+++ b/vcnet/regex/regcomp.c
@@ -0,0 +1,1603 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+#include "cclass.h"
+#include "cname.h"
+
+/*
+ * parse structure, passed up and down to avoid global variables and
+ * other clumsinesses
+ */
+struct parse {
+ char *next; /* next character in RE */
+ char *end; /* end of string (-> NUL normally) */
+ int error; /* has an error been seen? */
+ sop *strip; /* malloced strip */
+ sopno ssize; /* malloced strip size (allocated) */
+ sopno slen; /* malloced strip length (used) */
+ int ncsalloc; /* number of csets allocated */
+ struct re_guts *g;
+# define NPAREN 10 /* we need to remember () 1-9 for back refs */
+ sopno pbegin[NPAREN]; /* -> ( ([0] unused) */
+ sopno pend[NPAREN]; /* -> ) ([0] unused) */
+};
+
+#include "regcomp.ih"
+
+static char nuls[10]; /* place to point scanner in event of error */
+
+/*
+ * macros for use with parse structure
+ * BEWARE: these know that the parse structure is named `p' !!!
+ */
+#define PEEK() (*p->next)
+#define PEEK2() (*(p->next+1))
+#define MORE() (p->next < p->end)
+#define MORE2() (p->next+1 < p->end)
+#define SEE(c) (MORE() && PEEK() == (c))
+#define SEETWO(a, b) (MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b))
+#define EAT(c) ((SEE(c)) ? (NEXT(), 1) : 0)
+#define EATTWO(a, b) ((SEETWO(a, b)) ? (NEXT2(), 1) : 0)
+#define NEXT() (p->next++)
+#define NEXT2() (p->next += 2)
+#define NEXTn(n) (p->next += (n))
+#define GETNEXT() (*p->next++)
+#define SETERROR(e) seterr(p, (e))
+#define REQUIRE(co, e) ((co) || SETERROR(e))
+#define MUSTSEE(c, e) (REQUIRE(MORE() && PEEK() == (c), e))
+#define MUSTEAT(c, e) (REQUIRE(MORE() && GETNEXT() == (c), e))
+#define MUSTNOTSEE(c, e) (REQUIRE(!MORE() || PEEK() != (c), e))
+#define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd))
+#define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos)
+#define AHEAD(pos) dofwd(p, pos, HERE()-(pos))
+#define ASTERN(sop, pos) EMIT(sop, HERE()-pos)
+#define HERE() (p->slen)
+#define THERE() (p->slen - 1)
+#define THERETHERE() (p->slen - 2)
+#define DROP(n) (p->slen -= (n))
+
+#ifndef NDEBUG
+static int never = 0; /* for use in asserts; shuts lint up */
+#else
+#define never 0 /* some <assert.h>s have bugs too */
+#endif
+
+/*
+ - regcomp - interface for parser and compilation
+ = extern int regcomp(regex_t *, const char *, int);
+ = #define REG_BASIC 0000
+ = #define REG_EXTENDED 0001
+ = #define REG_ICASE 0002
+ = #define REG_NOSUB 0004
+ = #define REG_NEWLINE 0010
+ = #define REG_NOSPEC 0020
+ = #define REG_PEND 0040
+ = #define REG_DUMP 0200
+ */
+int /* 0 success, otherwise REG_something */
+regcomp(preg, pattern, cflags)
+regex_t *preg;
+const char *pattern;
+int cflags;
+{
+ struct parse pa;
+ register struct re_guts *g;
+ register struct parse *p = &pa;
+ register int i;
+ register size_t len;
+#ifdef REDEBUG
+# define GOODFLAGS(f) (f)
+#else
+# define GOODFLAGS(f) ((f)&~REG_DUMP)
+#endif
+
+ cflags = GOODFLAGS(cflags);
+ if ((cflags&REG_EXTENDED) && (cflags&REG_NOSPEC))
+ return(REG_INVARG);
+
+ if (cflags&REG_PEND) {
+ if (preg->re_endp < pattern)
+ return(REG_INVARG);
+ len = preg->re_endp - pattern;
+ } else
+ len = strlen((char *)pattern);
+
+ /* do the mallocs early so failure handling is easy */
+ g = (struct re_guts *)malloc(sizeof(struct re_guts) +
+ (NC-1)*sizeof(cat_t));
+ if (g == NULL)
+ return(REG_ESPACE);
+ p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */
+ p->strip = (sop *)malloc(p->ssize * sizeof(sop));
+ p->slen = 0;
+ if (p->strip == NULL) {
+ free((char *)g);
+ return(REG_ESPACE);
+ }
+
+ /* set things up */
+ p->g = g;
+ p->next = (char *)pattern; /* convenience; we do not modify it */
+ p->end = p->next + len;
+ p->error = 0;
+ p->ncsalloc = 0;
+ for (i = 0; i < NPAREN; i++) {
+ p->pbegin[i] = 0;
+ p->pend[i] = 0;
+ }
+ g->csetsize = NC;
+ g->sets = NULL;
+ g->setbits = NULL;
+ g->ncsets = 0;
+ g->cflags = cflags;
+ g->iflags = 0;
+ g->nbol = 0;
+ g->neol = 0;
+ g->must = NULL;
+ g->mlen = 0;
+ g->nsub = 0;
+ g->ncategories = 1; /* category 0 is "everything else" */
+ g->categories = &g->catspace[-(CHAR_MIN)];
+ (void) memset((char *)g->catspace, 0, NC*sizeof(cat_t));
+ g->backrefs = 0;
+
+ /* do it */
+ EMIT(OEND, 0);
+ g->firststate = THERE();
+ if (cflags&REG_EXTENDED)
+ p_ere(p, OUT);
+ else if (cflags&REG_NOSPEC)
+ p_str(p);
+ else
+ p_bre(p, OUT, OUT);
+ EMIT(OEND, 0);
+ g->laststate = THERE();
+
+ /* tidy up loose ends and fill things in */
+ categorize(p, g);
+ stripsnug(p, g);
+ findmust(p, g);
+ g->nplus = pluscount(p, g);
+ g->magic = MAGIC2;
+ preg->re_nsub = g->nsub;
+ preg->re_g = g;
+ preg->re_magic = MAGIC1;
+#ifndef REDEBUG
+ /* not debugging, so can't rely on the assert() in regexec() */
+ if (g->iflags&BAD)
+ SETERROR(REG_ASSERT);
+#endif
+
+ /* win or lose, we're done */
+ if (p->error != 0) /* lose */
+ regfree(preg);
+ return(p->error);
+}
+
+/*
+ - p_ere - ERE parser top level, concatenation and alternation
+ == static void p_ere(register struct parse *p, int stop);
+ */
+static void
+p_ere(p, stop)
+register struct parse *p;
+int stop; /* character this ERE should end at */
+{
+ register char c;
+ register sopno prevback;
+ register sopno prevfwd;
+ register sopno conc;
+ register int first = 1; /* is this the first alternative? */
+
+ for (;;) {
+ /* do a bunch of concatenated expressions */
+ conc = HERE();
+ while (MORE() && (c = PEEK()) != '|' && c != stop)
+ p_ere_exp(p);
+ REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */
+
+ if (!EAT('|'))
+ break; /* NOTE BREAK OUT */
+
+ if (first) {
+ INSERT(OCH_, conc); /* offset is wrong */
+ prevfwd = conc;
+ prevback = conc;
+ first = 0;
+ }
+ ASTERN(OOR1, prevback);
+ prevback = THERE();
+ AHEAD(prevfwd); /* fix previous offset */
+ prevfwd = HERE();
+ EMIT(OOR2, 0); /* offset is very wrong */
+ }
+
+ if (!first) { /* tail-end fixups */
+ AHEAD(prevfwd);
+ ASTERN(O_CH, prevback);
+ }
+
+ assert(!MORE() || SEE(stop));
+}
+
+/*
+ - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op
+ == static void p_ere_exp(register struct parse *p);
+ */
+static void
+p_ere_exp(p)
+register struct parse *p;
+{
+ register char c;
+ register sopno pos;
+ register int count;
+ register int count2;
+ register sopno subno;
+ int wascaret = 0;
+
+ assert(MORE()); /* caller should have ensured this */
+ c = GETNEXT();
+
+ pos = HERE();
+ switch (c) {
+ case '(':
+ REQUIRE(MORE(), REG_EPAREN);
+ p->g->nsub++;
+ subno = p->g->nsub;
+ if (subno < NPAREN)
+ p->pbegin[subno] = HERE();
+ EMIT(OLPAREN, subno);
+ if (!SEE(')'))
+ p_ere(p, ')');
+ if (subno < NPAREN) {
+ p->pend[subno] = HERE();
+ assert(p->pend[subno] != 0);
+ }
+ EMIT(ORPAREN, subno);
+ MUSTEAT(')', REG_EPAREN);
+ break;
+#ifndef POSIX_MISTAKE
+ case ')': /* happens only if no current unmatched ( */
+ /*
+ * You may ask, why the ifndef? Because I didn't notice
+ * this until slightly too late for 1003.2, and none of the
+ * other 1003.2 regular-expression reviewers noticed it at
+ * all. So an unmatched ) is legal POSIX, at least until
+ * we can get it fixed.
+ */
+ SETERROR(REG_EPAREN);
+ break;
+#endif
+ case '^':
+ EMIT(OBOL, 0);
+ p->g->iflags |= USEBOL;
+ p->g->nbol++;
+ wascaret = 1;
+ break;
+ case '$':
+ EMIT(OEOL, 0);
+ p->g->iflags |= USEEOL;
+ p->g->neol++;
+ break;
+ case '|':
+ SETERROR(REG_EMPTY);
+ break;
+ case '*':
+ case '+':
+ case '?':
+ SETERROR(REG_BADRPT);
+ break;
+ case '.':
+ if (p->g->cflags&REG_NEWLINE)
+ nonnewline(p);
+ else
+ EMIT(OANY, 0);
+ break;
+ case '[':
+ p_bracket(p);
+ break;
+ case '\\':
+ REQUIRE(MORE(), REG_EESCAPE);
+ c = GETNEXT();
+ ordinary(p, c);
+ break;
+ case '{': /* okay as ordinary except if digit follows */
+ REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT);
+ /* FALLTHROUGH */
+ default:
+ ordinary(p, c);
+ break;
+ }
+
+ if (!MORE())
+ return;
+ c = PEEK();
+ /* we call { a repetition if followed by a digit */
+ if (!( c == '*' || c == '+' || c == '?' ||
+ (c == '{' && MORE2() && isdigit(PEEK2())) ))
+ return; /* no repetition, we're done */
+ NEXT();
+
+ REQUIRE(!wascaret, REG_BADRPT);
+ switch (c) {
+ case '*': /* implemented as +? */
+ /* this case does not require the (y|) trick, noKLUDGE */
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ INSERT(OQUEST_, pos);
+ ASTERN(O_QUEST, pos);
+ break;
+ case '+':
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ break;
+ case '?':
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, pos); /* offset slightly wrong */
+ ASTERN(OOR1, pos); /* this one's right */
+ AHEAD(pos); /* fix the OCH_ */
+ EMIT(OOR2, 0); /* offset very wrong... */
+ AHEAD(THERE()); /* ...so fix it */
+ ASTERN(O_CH, THERETHERE());
+ break;
+ case '{':
+ count = p_count(p);
+ if (EAT(',')) {
+ if (isdigit(PEEK())) {
+ count2 = p_count(p);
+ REQUIRE(count <= count2, REG_BADBR);
+ } else /* single number with comma */
+ count2 = INFINITY;
+ } else /* just a single number */
+ count2 = count;
+ repeat(p, pos, count, count2);
+ if (!EAT('}')) { /* error heuristics */
+ while (MORE() && PEEK() != '}')
+ NEXT();
+ REQUIRE(MORE(), REG_EBRACE);
+ SETERROR(REG_BADBR);
+ }
+ break;
+ }
+
+ if (!MORE())
+ return;
+ c = PEEK();
+ if (!( c == '*' || c == '+' || c == '?' ||
+ (c == '{' && MORE2() && isdigit(PEEK2())) ) )
+ return;
+ SETERROR(REG_BADRPT);
+}
+
+/*
+ - p_str - string (no metacharacters) "parser"
+ == static void p_str(register struct parse *p);
+ */
+static void
+p_str(p)
+register struct parse *p;
+{
+ REQUIRE(MORE(), REG_EMPTY);
+ while (MORE())
+ ordinary(p, GETNEXT());
+}
+
+/*
+ - p_bre - BRE parser top level, anchoring and concatenation
+ == static void p_bre(register struct parse *p, register int end1, \
+ == register int end2);
+ * Giving end1 as OUT essentially eliminates the end1/end2 check.
+ *
+ * This implementation is a bit of a kludge, in that a trailing $ is first
+ * taken as an ordinary character and then revised to be an anchor. The
+ * only undesirable side effect is that '$' gets included as a character
+ * category in such cases. This is fairly harmless; not worth fixing.
+ * The amount of lookahead needed to avoid this kludge is excessive.
+ */
+static void
+p_bre(p, end1, end2)
+register struct parse *p;
+register int end1; /* first terminating character */
+register int end2; /* second terminating character */
+{
+ register sopno start = HERE();
+ register int first = 1; /* first subexpression? */
+ register int wasdollar = 0;
+
+ if (EAT('^')) {
+ EMIT(OBOL, 0);
+ p->g->iflags |= USEBOL;
+ p->g->nbol++;
+ }
+ while (MORE() && !SEETWO(end1, end2)) {
+ wasdollar = p_simp_re(p, first);
+ first = 0;
+ }
+ if (wasdollar) { /* oops, that was a trailing anchor */
+ DROP(1);
+ EMIT(OEOL, 0);
+ p->g->iflags |= USEEOL;
+ p->g->neol++;
+ }
+
+ REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */
+}
+
+/*
+ - p_simp_re - parse a simple RE, an atom possibly followed by a repetition
+ == static int p_simp_re(register struct parse *p, int starordinary);
+ */
+static int /* was the simple RE an unbackslashed $? */
+p_simp_re(p, starordinary)
+register struct parse *p;
+int starordinary; /* is a leading * an ordinary character? */
+{
+ register int c;
+ register int count;
+ register int count2;
+ register sopno pos;
+ register int i;
+ register sopno subno;
+# define BACKSL (1<<CHAR_BIT)
+
+ pos = HERE(); /* repetion op, if any, covers from here */
+
+ assert(MORE()); /* caller should have ensured this */
+ c = GETNEXT();
+ if (c == '\\') {
+ REQUIRE(MORE(), REG_EESCAPE);
+ c = BACKSL | (unsigned char)GETNEXT();
+ }
+ switch (c) {
+ case '.':
+ if (p->g->cflags&REG_NEWLINE)
+ nonnewline(p);
+ else
+ EMIT(OANY, 0);
+ break;
+ case '[':
+ p_bracket(p);
+ break;
+ case BACKSL|'{':
+ SETERROR(REG_BADRPT);
+ break;
+ case BACKSL|'(':
+ p->g->nsub++;
+ subno = p->g->nsub;
+ if (subno < NPAREN)
+ p->pbegin[subno] = HERE();
+ EMIT(OLPAREN, subno);
+ /* the MORE here is an error heuristic */
+ if (MORE() && !SEETWO('\\', ')'))
+ p_bre(p, '\\', ')');
+ if (subno < NPAREN) {
+ p->pend[subno] = HERE();
+ assert(p->pend[subno] != 0);
+ }
+ EMIT(ORPAREN, subno);
+ REQUIRE(EATTWO('\\', ')'), REG_EPAREN);
+ break;
+ case BACKSL|')': /* should not get here -- must be user */
+ case BACKSL|'}':
+ SETERROR(REG_EPAREN);
+ break;
+ case BACKSL|'1':
+ case BACKSL|'2':
+ case BACKSL|'3':
+ case BACKSL|'4':
+ case BACKSL|'5':
+ case BACKSL|'6':
+ case BACKSL|'7':
+ case BACKSL|'8':
+ case BACKSL|'9':
+ i = (c&~BACKSL) - '0';
+ assert(i < NPAREN);
+ if (p->pend[i] != 0) {
+ assert(i <= p->g->nsub);
+ EMIT(OBACK_, i);
+ assert(p->pbegin[i] != 0);
+ assert(OP(p->strip[p->pbegin[i]]) == OLPAREN);
+ assert(OP(p->strip[p->pend[i]]) == ORPAREN);
+ (void) dupl(p, p->pbegin[i]+1, p->pend[i]);
+ EMIT(O_BACK, i);
+ } else
+ SETERROR(REG_ESUBREG);
+ p->g->backrefs = 1;
+ break;
+ case '*':
+ REQUIRE(starordinary, REG_BADRPT);
+ /* FALLTHROUGH */
+ default:
+ ordinary(p, (char)c); /* takes off BACKSL, if any */
+ break;
+ }
+
+ if (EAT('*')) { /* implemented as +? */
+ /* this case does not require the (y|) trick, noKLUDGE */
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ INSERT(OQUEST_, pos);
+ ASTERN(O_QUEST, pos);
+ } else if (EATTWO('\\', '{')) {
+ count = p_count(p);
+ if (EAT(',')) {
+ if (MORE() && isdigit(PEEK())) {
+ count2 = p_count(p);
+ REQUIRE(count <= count2, REG_BADBR);
+ } else /* single number with comma */
+ count2 = INFINITY;
+ } else /* just a single number */
+ count2 = count;
+ repeat(p, pos, count, count2);
+ if (!EATTWO('\\', '}')) { /* error heuristics */
+ while (MORE() && !SEETWO('\\', '}'))
+ NEXT();
+ REQUIRE(MORE(), REG_EBRACE);
+ SETERROR(REG_BADBR);
+ }
+ } else if (c == (unsigned char)'$') /* $ (but not \$) ends it */
+ return(1);
+
+ return(0);
+}
+
+/*
+ - p_count - parse a repetition count
+ == static int p_count(register struct parse *p);
+ */
+static int /* the value */
+p_count(p)
+register struct parse *p;
+{
+ register int count = 0;
+ register int ndigits = 0;
+
+ while (MORE() && isdigit(PEEK()) && count <= DUPMAX) {
+ count = count*10 + (GETNEXT() - '0');
+ ndigits++;
+ }
+
+ REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR);
+ return(count);
+}
+
+/*
+ - p_bracket - parse a bracketed character list
+ == static void p_bracket(register struct parse *p);
+ *
+ * Note a significant property of this code: if the allocset() did SETERROR,
+ * no set operations are done.
+ */
+static void
+p_bracket(p)
+register struct parse *p;
+{
+ register cset *cs = allocset(p);
+ register int invert = 0;
+
+ /* Dept of Truly Sickening Special-Case Kludges */
+ if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) {
+ EMIT(OBOW, 0);
+ NEXTn(6);
+ return;
+ }
+ if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) {
+ EMIT(OEOW, 0);
+ NEXTn(6);
+ return;
+ }
+
+ if (EAT('^'))
+ invert++; /* make note to invert set at end */
+ if (EAT(']'))
+ CHadd(cs, ']');
+ else if (EAT('-'))
+ CHadd(cs, '-');
+ while (MORE() && PEEK() != ']' && !SEETWO('-', ']'))
+ p_b_term(p, cs);
+ if (EAT('-'))
+ CHadd(cs, '-');
+ MUSTEAT(']', REG_EBRACK);
+
+ if (p->error != 0) /* don't mess things up further */
+ return;
+
+ if (p->g->cflags&REG_ICASE) {
+ register int i;
+ register int ci;
+
+ for (i = p->g->csetsize - 1; i >= 0; i--)
+ if (CHIN(cs, i) && isalpha(i)) {
+ ci = othercase(i);
+ if (ci != i)
+ CHadd(cs, ci);
+ }
+ if (cs->multis != NULL)
+ mccase(p, cs);
+ }
+ if (invert) {
+ register int i;
+
+ for (i = p->g->csetsize - 1; i >= 0; i--)
+ if (CHIN(cs, i))
+ CHsub(cs, i);
+ else
+ CHadd(cs, i);
+ if (p->g->cflags&REG_NEWLINE)
+ CHsub(cs, '\n');
+ if (cs->multis != NULL)
+ mcinvert(p, cs);
+ }
+
+ assert(cs->multis == NULL); /* xxx */
+
+ if (nch(p, cs) == 1) { /* optimize singleton sets */
+ ordinary(p, firstch(p, cs));
+ freeset(p, cs);
+ } else
+ EMIT(OANYOF, freezeset(p, cs));
+}
+
+/*
+ - p_b_term - parse one term of a bracketed character list
+ == static void p_b_term(register struct parse *p, register cset *cs);
+ */
+static void
+p_b_term(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register char c;
+ register char start, finish;
+ register int i;
+
+ /* classify what we've got */
+ switch ((MORE()) ? PEEK() : '\0') {
+ case '[':
+ c = (MORE2()) ? PEEK2() : '\0';
+ break;
+ case '-':
+ SETERROR(REG_ERANGE);
+ return; /* NOTE RETURN */
+ break;
+ default:
+ c = '\0';
+ break;
+ }
+
+ switch (c) {
+ case ':': /* character class */
+ NEXT2();
+ REQUIRE(MORE(), REG_EBRACK);
+ c = PEEK();
+ REQUIRE(c != '-' && c != ']', REG_ECTYPE);
+ p_b_cclass(p, cs);
+ REQUIRE(MORE(), REG_EBRACK);
+ REQUIRE(EATTWO(':', ']'), REG_ECTYPE);
+ break;
+ case '=': /* equivalence class */
+ NEXT2();
+ REQUIRE(MORE(), REG_EBRACK);
+ c = PEEK();
+ REQUIRE(c != '-' && c != ']', REG_ECOLLATE);
+ p_b_eclass(p, cs);
+ REQUIRE(MORE(), REG_EBRACK);
+ REQUIRE(EATTWO('=', ']'), REG_ECOLLATE);
+ break;
+ default: /* symbol, ordinary character, or range */
+/* xxx revision needed for multichar stuff */
+ start = p_b_symbol(p);
+ if (SEE('-') && MORE2() && PEEK2() != ']') {
+ /* range */
+ NEXT();
+ if (EAT('-'))
+ finish = '-';
+ else
+ finish = p_b_symbol(p);
+ } else
+ finish = start;
+/* xxx what about signed chars here... */
+ REQUIRE(start <= finish, REG_ERANGE);
+ for (i = start; i <= finish; i++)
+ CHadd(cs, i);
+ break;
+ }
+}
+
+/*
+ - p_b_cclass - parse a character-class name and deal with it
+ == static void p_b_cclass(register struct parse *p, register cset *cs);
+ */
+static void
+p_b_cclass(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register char *sp = p->next;
+ register struct cclass *cp;
+ register size_t len;
+ register char *u;
+ register char c;
+
+ while (MORE() && isalpha(PEEK()))
+ NEXT();
+ len = p->next - sp;
+ for (cp = cclasses; cp->name != NULL; cp++)
+ if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+ break;
+ if (cp->name == NULL) {
+ /* oops, didn't find it */
+ SETERROR(REG_ECTYPE);
+ return;
+ }
+
+ u = cp->chars;
+ while ((c = *u++) != '\0')
+ CHadd(cs, c);
+ for (u = cp->multis; *u != '\0'; u += strlen(u) + 1)
+ MCadd(p, cs, u);
+}
+
+/*
+ - p_b_eclass - parse an equivalence-class name and deal with it
+ == static void p_b_eclass(register struct parse *p, register cset *cs);
+ *
+ * This implementation is incomplete. xxx
+ */
+static void
+p_b_eclass(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register char c;
+
+ c = p_b_coll_elem(p, '=');
+ CHadd(cs, c);
+}
+
+/*
+ - p_b_symbol - parse a character or [..]ed multicharacter collating symbol
+ == static char p_b_symbol(register struct parse *p);
+ */
+static char /* value of symbol */
+p_b_symbol(p)
+register struct parse *p;
+{
+ register char value;
+
+ REQUIRE(MORE(), REG_EBRACK);
+ if (!EATTWO('[', '.'))
+ return(GETNEXT());
+
+ /* collating symbol */
+ value = p_b_coll_elem(p, '.');
+ REQUIRE(EATTWO('.', ']'), REG_ECOLLATE);
+ return(value);
+}
+
+/*
+ - p_b_coll_elem - parse a collating-element name and look it up
+ == static char p_b_coll_elem(register struct parse *p, int endc);
+ */
+static char /* value of collating element */
+p_b_coll_elem(p, endc)
+register struct parse *p;
+int endc; /* name ended by endc,']' */
+{
+ register char *sp = p->next;
+ register struct cname *cp;
+ register int len;
+
+ while (MORE() && !SEETWO(endc, ']'))
+ NEXT();
+ if (!MORE()) {
+ SETERROR(REG_EBRACK);
+ return(0);
+ }
+ len = p->next - sp;
+ for (cp = cnames; cp->name != NULL; cp++)
+ if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+ return(cp->code); /* known name */
+ if (len == 1)
+ return(*sp); /* single character */
+ SETERROR(REG_ECOLLATE); /* neither */
+ return(0);
+}
+
+/*
+ - othercase - return the case counterpart of an alphabetic
+ == static char othercase(int ch);
+ */
+static char /* if no counterpart, return ch */
+othercase(ch)
+int ch;
+{
+ assert(isalpha(ch));
+ if (isupper(ch))
+ return(tolower(ch));
+ else if (islower(ch))
+ return(toupper(ch));
+ else /* peculiar, but could happen */
+ return(ch);
+}
+
+/*
+ - bothcases - emit a dualcase version of a two-case character
+ == static void bothcases(register struct parse *p, int ch);
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+bothcases(p, ch)
+register struct parse *p;
+int ch;
+{
+ register char *oldnext = p->next;
+ register char *oldend = p->end;
+ char bracket[3];
+
+ assert(othercase(ch) != ch); /* p_bracket() would recurse */
+ p->next = bracket;
+ p->end = bracket+2;
+ bracket[0] = ch;
+ bracket[1] = ']';
+ bracket[2] = '\0';
+ p_bracket(p);
+ assert(p->next == bracket+2);
+ p->next = oldnext;
+ p->end = oldend;
+}
+
+/*
+ - ordinary - emit an ordinary character
+ == static void ordinary(register struct parse *p, register int ch);
+ */
+static void
+ordinary(p, ch)
+register struct parse *p;
+register int ch;
+{
+ register cat_t *cap = p->g->categories;
+
+ if ((p->g->cflags&REG_ICASE) && isalpha(ch) && othercase(ch) != ch)
+ bothcases(p, ch);
+ else {
+ EMIT(OCHAR, (unsigned char)ch);
+ if (cap[ch] == 0)
+ cap[ch] = p->g->ncategories++;
+ }
+}
+
+/*
+ - nonnewline - emit REG_NEWLINE version of OANY
+ == static void nonnewline(register struct parse *p);
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+nonnewline(p)
+register struct parse *p;
+{
+ register char *oldnext = p->next;
+ register char *oldend = p->end;
+ char bracket[4];
+
+ p->next = bracket;
+ p->end = bracket+3;
+ bracket[0] = '^';
+ bracket[1] = '\n';
+ bracket[2] = ']';
+ bracket[3] = '\0';
+ p_bracket(p);
+ assert(p->next == bracket+3);
+ p->next = oldnext;
+ p->end = oldend;
+}
+
+/*
+ - repeat - generate code for a bounded repetition, recursively if needed
+ == static void repeat(register struct parse *p, sopno start, int from, int to);
+ */
+static void
+repeat(p, start, from, to)
+register struct parse *p;
+sopno start; /* operand from here to end of strip */
+int from; /* repeated from this number */
+int to; /* to this number of times (maybe INFINITY) */
+{
+ register sopno finish = HERE();
+# define N 2
+# define INF 3
+# define REP(f, t) ((f)*8 + (t))
+# define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
+ register sopno copy;
+
+ if (p->error != 0) /* head off possible runaway recursion */
+ return;
+
+ assert(from <= to);
+
+ switch (REP(MAP(from), MAP(to))) {
+ case REP(0, 0): /* must be user doing this */
+ DROP(finish-start); /* drop the operand */
+ break;
+ case REP(0, 1): /* as x{1,1}? */
+ case REP(0, N): /* as x{1,n}? */
+ case REP(0, INF): /* as x{1,}? */
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, start); /* offset is wrong... */
+ repeat(p, start+1, 1, to);
+ ASTERN(OOR1, start);
+ AHEAD(start); /* ... fix it */
+ EMIT(OOR2, 0);
+ AHEAD(THERE());
+ ASTERN(O_CH, THERETHERE());
+ break;
+ case REP(1, 1): /* trivial case */
+ /* done */
+ break;
+ case REP(1, N): /* as x?x{1,n-1} */
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, start);
+ ASTERN(OOR1, start);
+ AHEAD(start);
+ EMIT(OOR2, 0); /* offset very wrong... */
+ AHEAD(THERE()); /* ...so fix it */
+ ASTERN(O_CH, THERETHERE());
+ copy = dupl(p, start+1, finish+1);
+ assert(copy == finish+4);
+ repeat(p, copy, 1, to-1);
+ break;
+ case REP(1, INF): /* as x+ */
+ INSERT(OPLUS_, start);
+ ASTERN(O_PLUS, start);
+ break;
+ case REP(N, N): /* as xx{m-1,n-1} */
+ copy = dupl(p, start, finish);
+ repeat(p, copy, from-1, to-1);
+ break;
+ case REP(N, INF): /* as xx{n-1,INF} */
+ copy = dupl(p, start, finish);
+ repeat(p, copy, from-1, to);
+ break;
+ default: /* "can't happen" */
+ SETERROR(REG_ASSERT); /* just in case */
+ break;
+ }
+}
+
+/*
+ - seterr - set an error condition
+ == static int seterr(register struct parse *p, int e);
+ */
+static int /* useless but makes type checking happy */
+seterr(p, e)
+register struct parse *p;
+int e;
+{
+ if (p->error == 0) /* keep earliest error condition */
+ p->error = e;
+ p->next = nuls; /* try to bring things to a halt */
+ p->end = nuls;
+ return(0); /* make the return value well-defined */
+}
+
+/*
+ - allocset - allocate a set of characters for []
+ == static cset *allocset(register struct parse *p);
+ */
+static cset *
+allocset(p)
+register struct parse *p;
+{
+ register int no = p->g->ncsets++;
+ register size_t nc;
+ register size_t nbytes;
+ register cset *cs;
+ register size_t css = (size_t)p->g->csetsize;
+ register int i;
+
+ if (no >= p->ncsalloc) { /* need another column of space */
+ p->ncsalloc += CHAR_BIT;
+ nc = p->ncsalloc;
+ assert(nc % CHAR_BIT == 0);
+ nbytes = nc / CHAR_BIT * css;
+ if (p->g->sets == NULL)
+ p->g->sets = (cset *)malloc(nc * sizeof(cset));
+ else
+ p->g->sets = (cset *)realloc((char *)p->g->sets,
+ nc * sizeof(cset));
+ if (p->g->setbits == NULL)
+ p->g->setbits = (uch *)malloc(nbytes);
+ else {
+ p->g->setbits = (uch *)realloc((char *)p->g->setbits,
+ nbytes);
+ /* xxx this isn't right if setbits is now NULL */
+ for (i = 0; i < no; i++)
+ p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT);
+ }
+ if (p->g->sets != NULL && p->g->setbits != NULL)
+ (void) memset((char *)p->g->setbits + (nbytes - css),
+ 0, css);
+ else {
+ no = 0;
+ SETERROR(REG_ESPACE);
+ /* caller's responsibility not to do set ops */
+ }
+ }
+
+ assert(p->g->sets != NULL); /* xxx */
+ cs = &p->g->sets[no];
+ cs->ptr = p->g->setbits + css*((no)/CHAR_BIT);
+ cs->mask = 1 << ((no) % CHAR_BIT);
+ cs->hash = 0;
+ cs->smultis = 0;
+ cs->multis = NULL;
+
+ return(cs);
+}
+
+/*
+ - freeset - free a now-unused set
+ == static void freeset(register struct parse *p, register cset *cs);
+ */
+static void
+freeset(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register size_t i;
+ register cset *top = &p->g->sets[p->g->ncsets];
+ register size_t css = (size_t)p->g->csetsize;
+
+ for (i = 0; i < css; i++)
+ CHsub(cs, i);
+ if (cs == top-1) /* recover only the easy case */
+ p->g->ncsets--;
+}
+
+/*
+ - freezeset - final processing on a set of characters
+ == static int freezeset(register struct parse *p, register cset *cs);
+ *
+ * The main task here is merging identical sets. This is usually a waste
+ * of time (although the hash code minimizes the overhead), but can win
+ * big if REG_ICASE is being used. REG_ICASE, by the way, is why the hash
+ * is done using addition rather than xor -- all ASCII [aA] sets xor to
+ * the same value!
+ */
+static int /* set number */
+freezeset(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register uch h = cs->hash;
+ register size_t i;
+ register cset *top = &p->g->sets[p->g->ncsets];
+ register cset *cs2;
+ register size_t css = (size_t)p->g->csetsize;
+
+ /* look for an earlier one which is the same */
+ for (cs2 = &p->g->sets[0]; cs2 < top; cs2++)
+ if (cs2->hash == h && cs2 != cs) {
+ /* maybe */
+ for (i = 0; i < css; i++)
+ if (!!CHIN(cs2, i) != !!CHIN(cs, i))
+ break; /* no */
+ if (i == css)
+ break; /* yes */
+ }
+
+ if (cs2 < top) { /* found one */
+ freeset(p, cs);
+ cs = cs2;
+ }
+
+ return((int)(cs - p->g->sets));
+}
+
+/*
+ - firstch - return first character in a set (which must have at least one)
+ == static int firstch(register struct parse *p, register cset *cs);
+ */
+static int /* character; there is no "none" value */
+firstch(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register size_t i;
+ register size_t css = (size_t)p->g->csetsize;
+
+ for (i = 0; i < css; i++)
+ if (CHIN(cs, i))
+ return((char)i);
+ assert(never);
+ return(0); /* arbitrary */
+}
+
+/*
+ - nch - number of characters in a set
+ == static int nch(register struct parse *p, register cset *cs);
+ */
+static int
+nch(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register size_t i;
+ register size_t css = (size_t)p->g->csetsize;
+ register int n = 0;
+
+ for (i = 0; i < css; i++)
+ if (CHIN(cs, i))
+ n++;
+ return(n);
+}
+
+/*
+ - mcadd - add a collating element to a cset
+ == static void mcadd(register struct parse *p, register cset *cs, \
+ == register char *cp);
+ */
+static void
+mcadd(p, cs, cp)
+register struct parse *p;
+register cset *cs;
+register char *cp;
+{
+ register size_t oldend = cs->smultis;
+
+ cs->smultis += strlen(cp) + 1;
+ if (cs->multis == NULL)
+ cs->multis = malloc(cs->smultis);
+ else
+ cs->multis = realloc(cs->multis, cs->smultis);
+ if (cs->multis == NULL) {
+ SETERROR(REG_ESPACE);
+ return;
+ }
+
+ (void) strcpy(cs->multis + oldend - 1, cp);
+ cs->multis[cs->smultis - 1] = '\0';
+}
+
+/*
+ - mcsub - subtract a collating element from a cset
+ == static void mcsub(register cset *cs, register char *cp);
+ */
+static void
+mcsub(cs, cp)
+register cset *cs;
+register char *cp;
+{
+ register char *fp = mcfind(cs, cp);
+ register size_t len = strlen(fp);
+
+ assert(fp != NULL);
+ (void) memmove(fp, fp + len + 1,
+ cs->smultis - (fp + len + 1 - cs->multis));
+ cs->smultis -= len;
+
+ if (cs->smultis == 0) {
+ free(cs->multis);
+ cs->multis = NULL;
+ return;
+ }
+
+ cs->multis = realloc(cs->multis, cs->smultis);
+ assert(cs->multis != NULL);
+}
+
+/*
+ - mcin - is a collating element in a cset?
+ == static int mcin(register cset *cs, register char *cp);
+ */
+static int
+mcin(cs, cp)
+register cset *cs;
+register char *cp;
+{
+ return(mcfind(cs, cp) != NULL);
+}
+
+/*
+ - mcfind - find a collating element in a cset
+ == static char *mcfind(register cset *cs, register char *cp);
+ */
+static char *
+mcfind(cs, cp)
+register cset *cs;
+register char *cp;
+{
+ register char *p;
+
+ if (cs->multis == NULL)
+ return(NULL);
+ for (p = cs->multis; *p != '\0'; p += strlen(p) + 1)
+ if (strcmp(cp, p) == 0)
+ return(p);
+ return(NULL);
+}
+
+/*
+ - mcinvert - invert the list of collating elements in a cset
+ == static void mcinvert(register struct parse *p, register cset *cs);
+ *
+ * This would have to know the set of possibilities. Implementation
+ * is deferred.
+ */
+static void
+mcinvert(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ assert(cs->multis == NULL); /* xxx */
+}
+
+/*
+ - mccase - add case counterparts of the list of collating elements in a cset
+ == static void mccase(register struct parse *p, register cset *cs);
+ *
+ * This would have to know the set of possibilities. Implementation
+ * is deferred.
+ */
+static void
+mccase(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ assert(cs->multis == NULL); /* xxx */
+}
+
+/*
+ - isinsets - is this character in any sets?
+ == static int isinsets(register struct re_guts *g, int c);
+ */
+static int /* predicate */
+isinsets(g, c)
+register struct re_guts *g;
+int c;
+{
+ register uch *col;
+ register int i;
+ register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+ register unsigned uc = (unsigned char)c;
+
+ for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+ if (col[uc] != 0)
+ return(1);
+ return(0);
+}
+
+/*
+ - samesets - are these two characters in exactly the same sets?
+ == static int samesets(register struct re_guts *g, int c1, int c2);
+ */
+static int /* predicate */
+samesets(g, c1, c2)
+register struct re_guts *g;
+int c1;
+int c2;
+{
+ register uch *col;
+ register int i;
+ register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+ register unsigned uc1 = (unsigned char)c1;
+ register unsigned uc2 = (unsigned char)c2;
+
+ for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+ if (col[uc1] != col[uc2])
+ return(0);
+ return(1);
+}
+
+/*
+ - categorize - sort out character categories
+ == static void categorize(struct parse *p, register struct re_guts *g);
+ */
+static void
+categorize(p, g)
+struct parse *p;
+register struct re_guts *g;
+{
+ register cat_t *cats = g->categories;
+ register int c;
+ register int c2;
+ register cat_t cat;
+
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+ if (cats[c] == 0 && isinsets(g, c)) {
+ cat = g->ncategories++;
+ cats[c] = cat;
+ for (c2 = c+1; c2 <= CHAR_MAX; c2++)
+ if (cats[c2] == 0 && samesets(g, c, c2))
+ cats[c2] = cat;
+ }
+}
+
+/*
+ - dupl - emit a duplicate of a bunch of sops
+ == static sopno dupl(register struct parse *p, sopno start, sopno finish);
+ */
+static sopno /* start of duplicate */
+dupl(p, start, finish)
+register struct parse *p;
+sopno start; /* from here */
+sopno finish; /* to this less one */
+{
+ register sopno ret = HERE();
+ register sopno len = finish - start;
+
+ assert(finish >= start);
+ if (len == 0)
+ return(ret);
+ enlarge(p, p->ssize + len); /* this many unexpected additions */
+ assert(p->ssize >= p->slen + len);
+ (void) memcpy((char *)(p->strip + p->slen),
+ (char *)(p->strip + start), (size_t)len*sizeof(sop));
+ p->slen += len;
+ return(ret);
+}
+
+/*
+ - doemit - emit a strip operator
+ == static void doemit(register struct parse *p, sop op, size_t opnd);
+ *
+ * It might seem better to implement this as a macro with a function as
+ * hard-case backup, but it's just too big and messy unless there are
+ * some changes to the data structures. Maybe later.
+ */
+static void
+doemit(p, op, opnd)
+register struct parse *p;
+sop op;
+size_t opnd;
+{
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ /* deal with oversize operands ("can't happen", more or less) */
+ assert(opnd < 1<<OPSHIFT);
+
+ /* deal with undersized strip */
+ if (p->slen >= p->ssize)
+ enlarge(p, (p->ssize+1) / 2 * 3); /* +50% */
+ assert(p->slen < p->ssize);
+
+ /* finally, it's all reduced to the easy case */
+ p->strip[p->slen++] = SOP(op, opnd);
+}
+
+/*
+ - doinsert - insert a sop into the strip
+ == static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos);
+ */
+static void
+doinsert(p, op, opnd, pos)
+register struct parse *p;
+sop op;
+size_t opnd;
+sopno pos;
+{
+ register sopno sn;
+ register sop s;
+ register int i;
+
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ sn = HERE();
+ EMIT(op, opnd); /* do checks, ensure space */
+ assert(HERE() == sn+1);
+ s = p->strip[sn];
+
+ /* adjust paren pointers */
+ assert(pos > 0);
+ for (i = 1; i < NPAREN; i++) {
+ if (p->pbegin[i] >= pos) {
+ p->pbegin[i]++;
+ }
+ if (p->pend[i] >= pos) {
+ p->pend[i]++;
+ }
+ }
+
+ memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos],
+ (HERE()-pos-1)*sizeof(sop));
+ p->strip[pos] = s;
+}
+
+/*
+ - dofwd - complete a forward reference
+ == static void dofwd(register struct parse *p, sopno pos, sop value);
+ */
+static void
+dofwd(p, pos, value)
+register struct parse *p;
+register sopno pos;
+sop value;
+{
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ assert(value < 1<<OPSHIFT);
+ p->strip[pos] = OP(p->strip[pos]) | value;
+}
+
+/*
+ - enlarge - enlarge the strip
+ == static void enlarge(register struct parse *p, sopno size);
+ */
+static void
+enlarge(p, size)
+register struct parse *p;
+register sopno size;
+{
+ register sop *sp;
+
+ if (p->ssize >= size)
+ return;
+
+ sp = (sop *)realloc(p->strip, size*sizeof(sop));
+ if (sp == NULL) {
+ SETERROR(REG_ESPACE);
+ return;
+ }
+ p->strip = sp;
+ p->ssize = size;
+}
+
+/*
+ - stripsnug - compact the strip
+ == static void stripsnug(register struct parse *p, register struct re_guts *g);
+ */
+static void
+stripsnug(p, g)
+register struct parse *p;
+register struct re_guts *g;
+{
+ g->nstates = p->slen;
+ g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop));
+ if (g->strip == NULL) {
+ SETERROR(REG_ESPACE);
+ g->strip = p->strip;
+ }
+}
+
+/*
+ - findmust - fill in must and mlen with longest mandatory literal string
+ == static void findmust(register struct parse *p, register struct re_guts *g);
+ *
+ * This algorithm could do fancy things like analyzing the operands of |
+ * for common subsequences. Someday. This code is simple and finds most
+ * of the interesting cases.
+ *
+ * Note that must and mlen got initialized during setup.
+ */
+static void
+findmust(p, g)
+struct parse *p;
+register struct re_guts *g;
+{
+ register sop *scan;
+ sop *start;
+ register sop *newstart;
+ register sopno newlen;
+ register sop s;
+ register char *cp;
+ register sopno i;
+
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ /* find the longest OCHAR sequence in strip */
+ newlen = 0;
+ scan = g->strip + 1;
+ do {
+ s = *scan++;
+ switch (OP(s)) {
+ case OCHAR: /* sequence member */
+ if (newlen == 0) /* new sequence */
+ newstart = scan - 1;
+ newlen++;
+ break;
+ case OPLUS_: /* things that don't break one */
+ case OLPAREN:
+ case ORPAREN:
+ break;
+ case OQUEST_: /* things that must be skipped */
+ case OCH_:
+ scan--;
+ do {
+ scan += OPND(s);
+ s = *scan;
+ /* assert() interferes w debug printouts */
+ if (OP(s) != O_QUEST && OP(s) != O_CH &&
+ OP(s) != OOR2) {
+ g->iflags |= BAD;
+ return;
+ }
+ } while (OP(s) != O_QUEST && OP(s) != O_CH);
+ /* fallthrough */
+ default: /* things that break a sequence */
+ if (newlen > g->mlen) { /* ends one */
+ start = newstart;
+ g->mlen = newlen;
+ }
+ newlen = 0;
+ break;
+ }
+ } while (OP(s) != OEND);
+
+ if (g->mlen == 0) /* there isn't one */
+ return;
+
+ /* turn it into a character string */
+ g->must = malloc((size_t)g->mlen + 1);
+ if (g->must == NULL) { /* argh; just forget it */
+ g->mlen = 0;
+ return;
+ }
+ cp = g->must;
+ scan = start;
+ for (i = g->mlen; i > 0; i--) {
+ while (OP(s = *scan++) != OCHAR)
+ continue;
+ assert(cp < g->must + g->mlen);
+ *cp++ = (char)OPND(s);
+ }
+ assert(cp == g->must + g->mlen);
+ *cp++ = '\0'; /* just on general principles */
+}
+
+/*
+ - pluscount - count + nesting
+ == static sopno pluscount(register struct parse *p, register struct re_guts *g);
+ */
+static sopno /* nesting depth */
+pluscount(p, g)
+struct parse *p;
+register struct re_guts *g;
+{
+ register sop *scan;
+ register sop s;
+ register sopno plusnest = 0;
+ register sopno maxnest = 0;
+
+ if (p->error != 0)
+ return(0); /* there may not be an OEND */
+
+ scan = g->strip + 1;
+ do {
+ s = *scan++;
+ switch (OP(s)) {
+ case OPLUS_:
+ plusnest++;
+ break;
+ case O_PLUS:
+ if (plusnest > maxnest)
+ maxnest = plusnest;
+ plusnest--;
+ break;
+ }
+ } while (OP(s) != OEND);
+ if (plusnest != 0)
+ g->iflags |= BAD;
+ return(maxnest);
+}
diff --git a/vcnet/regex/regcomp.ih b/vcnet/regex/regcomp.ih
new file mode 100644
index 000000000..0776e7185
--- /dev/null
+++ b/vcnet/regex/regcomp.ih
@@ -0,0 +1,51 @@
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regcomp.c === */
+static void p_ere(register struct parse *p, int stop);
+static void p_ere_exp(register struct parse *p);
+static void p_str(register struct parse *p);
+static void p_bre(register struct parse *p, register int end1, register int end2);
+static int p_simp_re(register struct parse *p, int starordinary);
+static int p_count(register struct parse *p);
+static void p_bracket(register struct parse *p);
+static void p_b_term(register struct parse *p, register cset *cs);
+static void p_b_cclass(register struct parse *p, register cset *cs);
+static void p_b_eclass(register struct parse *p, register cset *cs);
+static char p_b_symbol(register struct parse *p);
+static char p_b_coll_elem(register struct parse *p, int endc);
+static char othercase(int ch);
+static void bothcases(register struct parse *p, int ch);
+static void ordinary(register struct parse *p, register int ch);
+static void nonnewline(register struct parse *p);
+static void repeat(register struct parse *p, sopno start, int from, int to);
+static int seterr(register struct parse *p, int e);
+static cset *allocset(register struct parse *p);
+static void freeset(register struct parse *p, register cset *cs);
+static int freezeset(register struct parse *p, register cset *cs);
+static int firstch(register struct parse *p, register cset *cs);
+static int nch(register struct parse *p, register cset *cs);
+static void mcadd(register struct parse *p, register cset *cs, register char *cp);
+static void mcsub(register cset *cs, register char *cp);
+static int mcin(register cset *cs, register char *cp);
+static char *mcfind(register cset *cs, register char *cp);
+static void mcinvert(register struct parse *p, register cset *cs);
+static void mccase(register struct parse *p, register cset *cs);
+static int isinsets(register struct re_guts *g, int c);
+static int samesets(register struct re_guts *g, int c1, int c2);
+static void categorize(struct parse *p, register struct re_guts *g);
+static sopno dupl(register struct parse *p, sopno start, sopno finish);
+static void doemit(register struct parse *p, sop op, size_t opnd);
+static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos);
+static void dofwd(register struct parse *p, sopno pos, sop value);
+static void enlarge(register struct parse *p, sopno size);
+static void stripsnug(register struct parse *p, register struct re_guts *g);
+static void findmust(register struct parse *p, register struct re_guts *g);
+static sopno pluscount(register struct parse *p, register struct re_guts *g);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
diff --git a/vcnet/regex/regerror.c b/vcnet/regex/regerror.c
new file mode 100644
index 000000000..9ddd25ca9
--- /dev/null
+++ b/vcnet/regex/regerror.c
@@ -0,0 +1,126 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regerror.ih"
+
+/*
+ = #define REG_OKAY 0
+ = #define REG_NOMATCH 1
+ = #define REG_BADPAT 2
+ = #define REG_ECOLLATE 3
+ = #define REG_ECTYPE 4
+ = #define REG_EESCAPE 5
+ = #define REG_ESUBREG 6
+ = #define REG_EBRACK 7
+ = #define REG_EPAREN 8
+ = #define REG_EBRACE 9
+ = #define REG_BADBR 10
+ = #define REG_ERANGE 11
+ = #define REG_ESPACE 12
+ = #define REG_BADRPT 13
+ = #define REG_EMPTY 14
+ = #define REG_ASSERT 15
+ = #define REG_INVARG 16
+ = #define REG_ATOI 255 // convert name to number (!)
+ = #define REG_ITOA 0400 // convert number to name (!)
+ */
+static struct rerr {
+ int code;
+ char *name;
+ char *explain;
+} rerrs[] = {
+ REG_OKAY, "REG_OKAY", "no errors detected",
+ REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match",
+ REG_BADPAT, "REG_BADPAT", "invalid regular expression",
+ REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element",
+ REG_ECTYPE, "REG_ECTYPE", "invalid character class",
+ REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)",
+ REG_ESUBREG, "REG_ESUBREG", "invalid backreference number",
+ REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced",
+ REG_EPAREN, "REG_EPAREN", "parentheses not balanced",
+ REG_EBRACE, "REG_EBRACE", "braces not balanced",
+ REG_BADBR, "REG_BADBR", "invalid repetition count(s)",
+ REG_ERANGE, "REG_ERANGE", "invalid character range",
+ REG_ESPACE, "REG_ESPACE", "out of memory",
+ REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid",
+ REG_EMPTY, "REG_EMPTY", "empty (sub)expression",
+ REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug",
+ REG_INVARG, "REG_INVARG", "invalid argument to regex routine",
+ -1, "", "*** unknown regexp error code ***",
+};
+
+/*
+ - regerror - the interface to error numbers
+ = extern size_t regerror(int, const regex_t *, char *, size_t);
+ */
+/* ARGSUSED */
+size_t
+regerror(
+int errcode,
+const regex_t *preg,
+char *errbuf,
+size_t errbuf_size)
+{
+ register struct rerr *r;
+ register size_t len;
+ register int target = errcode &~ REG_ITOA;
+ register char *s;
+ char convbuf[50];
+
+ if (errcode == REG_ATOI)
+ s = regatoi(preg, convbuf);
+ else {
+ for (r = rerrs; r->code >= 0; r++)
+ if (r->code == target)
+ break;
+
+ if (errcode&REG_ITOA) {
+ if (r->code >= 0)
+ (void) strcpy(convbuf, r->name);
+ else
+ sprintf(convbuf, "REG_0x%x", target);
+ assert(strlen(convbuf) < sizeof(convbuf));
+ s = convbuf;
+ } else
+ s = r->explain;
+ }
+
+ len = strlen(s) + 1;
+ if (errbuf_size > 0) {
+ if (errbuf_size > len)
+ (void) strcpy(errbuf, s);
+ else {
+ (void) strncpy(errbuf, s, errbuf_size-1);
+ errbuf[errbuf_size-1] = '\0';
+ }
+ }
+
+ return(len);
+}
+
+/*
+ - regatoi - internal routine to implement REG_ATOI
+ == static char *regatoi(const regex_t *preg, char *localbuf);
+ */
+static char *
+regatoi(preg, localbuf)
+const regex_t *preg;
+char *localbuf;
+{
+ register struct rerr *r;
+
+ for (r = rerrs; r->code >= 0; r++)
+ if (strcmp(r->name, preg->re_endp) == 0)
+ break;
+ if (r->code < 0)
+ return("0");
+
+ sprintf(localbuf, "%d", r->code);
+ return(localbuf);
+}
diff --git a/vcnet/regex/regerror.ih b/vcnet/regex/regerror.ih
new file mode 100644
index 000000000..2cb668c24
--- /dev/null
+++ b/vcnet/regex/regerror.ih
@@ -0,0 +1,12 @@
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regerror.c === */
+static char *regatoi(const regex_t *preg, char *localbuf);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
diff --git a/vcnet/regex/regex.3 b/vcnet/regex/regex.3
new file mode 100644
index 000000000..bc747096d
--- /dev/null
+++ b/vcnet/regex/regex.3
@@ -0,0 +1,509 @@
+.TH REGEX 3 "25 Sept 1997"
+.BY "Henry Spencer"
+.de ZR
+.\" one other place knows this name: the SEE ALSO section
+.IR regex (7) \\$1
+..
+.SH NAME
+regcomp, regexec, regerror, regfree \- regular-expression library
+.SH SYNOPSIS
+.ft B
+.\".na
+#include <sys/types.h>
+.br
+#include <regex.h>
+.HP 10
+int regcomp(regex_t\ *preg, const\ char\ *pattern, int\ cflags);
+.HP
+int\ regexec(const\ regex_t\ *preg, const\ char\ *string,
+size_t\ nmatch, regmatch_t\ pmatch[], int\ eflags);
+.HP
+size_t\ regerror(int\ errcode, const\ regex_t\ *preg,
+char\ *errbuf, size_t\ errbuf_size);
+.HP
+void\ regfree(regex_t\ *preg);
+.\".ad
+.ft
+.SH DESCRIPTION
+These routines implement POSIX 1003.2 regular expressions (``RE''s);
+see
+.ZR .
+.I Regcomp
+compiles an RE written as a string into an internal form,
+.I regexec
+matches that internal form against a string and reports results,
+.I regerror
+transforms error codes from either into human-readable messages,
+and
+.I regfree
+frees any dynamically-allocated storage used by the internal form
+of an RE.
+.PP
+The header
+.I <regex.h>
+declares two structure types,
+.I regex_t
+and
+.IR regmatch_t ,
+the former for compiled internal forms and the latter for match reporting.
+It also declares the four functions,
+a type
+.IR regoff_t ,
+and a number of constants with names starting with ``REG_''.
+.PP
+.I Regcomp
+compiles the regular expression contained in the
+.I pattern
+string,
+subject to the flags in
+.IR cflags ,
+and places the results in the
+.I regex_t
+structure pointed to by
+.IR preg .
+.I Cflags
+is the bitwise OR of zero or more of the following flags:
+.IP REG_EXTENDED \w'REG_EXTENDED'u+2n
+Compile modern (``extended'') REs,
+rather than the obsolete (``basic'') REs that
+are the default.
+.IP REG_BASIC
+This is a synonym for 0,
+provided as a counterpart to REG_EXTENDED to improve readability.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+.IP REG_NOSPEC
+Compile with recognition of all special characters turned off.
+All characters are thus considered ordinary,
+so the ``RE'' is a literal string.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+REG_EXTENDED and REG_NOSPEC may not be used
+in the same call to
+.IR regcomp .
+.IP REG_ICASE
+Compile for matching that ignores upper/lower case distinctions.
+See
+.ZR .
+.IP REG_NOSUB
+Compile for matching that need only report success or failure,
+not what was matched.
+.IP REG_NEWLINE
+Compile for newline-sensitive matching.
+By default, newline is a completely ordinary character with no special
+meaning in either REs or strings.
+With this flag,
+`[^' bracket expressions and `.' never match newline,
+a `^' anchor matches the null string after any newline in the string
+in addition to its normal function,
+and the `$' anchor matches the null string before any newline in the
+string in addition to its normal function.
+.IP REG_PEND
+The regular expression ends,
+not at the first NUL,
+but just before the character pointed to by the
+.I re_endp
+member of the structure pointed to by
+.IR preg .
+The
+.I re_endp
+member is of type
+.IR const\ char\ * .
+This flag permits inclusion of NULs in the RE;
+they are considered ordinary characters.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+.PP
+When successful,
+.I regcomp
+returns 0 and fills in the structure pointed to by
+.IR preg .
+One member of that structure
+(other than
+.IR re_endp )
+is publicized:
+.IR re_nsub ,
+of type
+.IR size_t ,
+contains the number of parenthesized subexpressions within the RE
+(except that the value of this member is undefined if the
+REG_NOSUB flag was used).
+If
+.I regcomp
+fails, it returns a non-zero error code;
+see DIAGNOSTICS.
+.PP
+.I Regexec
+matches the compiled RE pointed to by
+.I preg
+against the
+.IR string ,
+subject to the flags in
+.IR eflags ,
+and reports results using
+.IR nmatch ,
+.IR pmatch ,
+and the returned value.
+The RE must have been compiled by a previous invocation of
+.IR regcomp .
+The compiled form is not altered during execution of
+.IR regexec ,
+so a single compiled RE can be used simultaneously by multiple threads.
+.PP
+By default,
+the NUL-terminated string pointed to by
+.I string
+is considered to be the text of an entire line,
+with the NUL indicating the end of the line.
+(That is,
+any other end-of-line marker is considered to have been removed
+and replaced by the NUL.)
+The
+.I eflags
+argument is the bitwise OR of zero or more of the following flags:
+.IP REG_NOTBOL \w'REG_STARTEND'u+2n
+The first character of
+the string
+is not the beginning of a line, so the `^' anchor should not match before it.
+This does not affect the behavior of newlines under REG_NEWLINE.
+.IP REG_NOTEOL
+The NUL terminating
+the string
+does not end a line, so the `$' anchor should not match before it.
+This does not affect the behavior of newlines under REG_NEWLINE.
+.IP REG_STARTEND
+The string is considered to start at
+\fIstring\fR\ + \fIpmatch\fR[0].\fIrm_so\fR
+and to have a terminating NUL located at
+\fIstring\fR\ + \fIpmatch\fR[0].\fIrm_eo\fR
+(there need not actually be a NUL at that location),
+regardless of the value of
+.IR nmatch .
+See below for the definition of
+.IR pmatch
+and
+.IR nmatch .
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+Note that a non-zero \fIrm_so\fR does not imply REG_NOTBOL;
+REG_STARTEND affects only the location of the string,
+not how it is matched.
+.PP
+See
+.ZR
+for a discussion of what is matched in situations where an RE or a
+portion thereof could match any of several substrings of
+.IR string .
+.PP
+Normally,
+.I regexec
+returns 0 for success and the non-zero code REG_NOMATCH for failure.
+Other non-zero error codes may be returned in exceptional situations;
+see DIAGNOSTICS.
+.PP
+If REG_NOSUB was specified in the compilation of the RE,
+or if
+.I nmatch
+is 0,
+.I regexec
+ignores the
+.I pmatch
+argument (but see below for the case where REG_STARTEND is specified).
+Otherwise,
+.I pmatch
+points to an array of
+.I nmatch
+structures of type
+.IR regmatch_t .
+Such a structure has at least the members
+.I rm_so
+and
+.IR rm_eo ,
+both of type
+.I regoff_t
+(a signed arithmetic type at least as large as an
+.I off_t
+and a
+.IR ssize_t ),
+containing respectively the offset of the first character of a substring
+and the offset of the first character after the end of the substring.
+Offsets are measured from the beginning of the
+.I string
+argument given to
+.IR regexec .
+An empty substring is denoted by equal offsets,
+both indicating the character following the empty substring.
+.PP
+The 0th member of the
+.I pmatch
+array is filled in to indicate what substring of
+.I string
+was matched by the entire RE.
+Remaining members report what substring was matched by parenthesized
+subexpressions within the RE;
+member
+.I i
+reports subexpression
+.IR i ,
+with subexpressions counted (starting at 1) by the order of their opening
+parentheses in the RE, left to right.
+Unused entries in the array\(emcorresponding either to subexpressions that
+did not participate in the match at all, or to subexpressions that do not
+exist in the RE (that is, \fIi\fR\ > \fIpreg\fR\->\fIre_nsub\fR)\(emhave both
+.I rm_so
+and
+.I rm_eo
+set to \-1.
+If a subexpression participated in the match several times,
+the reported substring is the last one it matched.
+(Note, as an example in particular, that when the RE `(b*)+' matches `bbb',
+the parenthesized subexpression matches the three `b's and then
+an infinite number of empty strings following the last `b',
+so the reported substring is one of the empties.)
+.PP
+If REG_STARTEND is specified,
+.I pmatch
+must point to at least one
+.I regmatch_t
+(even if
+.I nmatch
+is 0 or REG_NOSUB was specified),
+to hold the input offsets for REG_STARTEND.
+Use for output is still entirely controlled by
+.IR nmatch ;
+if
+.I nmatch
+is 0 or REG_NOSUB was specified,
+the value of
+.IR pmatch [0]
+will not be changed by a successful
+.IR regexec .
+.PP
+.I Regerror
+maps a non-zero
+.I errcode
+from either
+.I regcomp
+or
+.I regexec
+to a human-readable, printable message.
+If
+.I preg
+is non-NULL,
+the error code should have arisen from use of
+the
+.I regex_t
+pointed to by
+.IR preg ,
+and if the error code came from
+.IR regcomp ,
+it should have been the result from the most recent
+.I regcomp
+using that
+.IR regex_t .
+.RI ( Regerror
+may be able to supply a more detailed message using information
+from the
+.IR regex_t .)
+.I Regerror
+places the NUL-terminated message into the buffer pointed to by
+.IR errbuf ,
+limiting the length (including the NUL) to at most
+.I errbuf_size
+bytes.
+If the whole message won't fit,
+as much of it as will fit before the terminating NUL is supplied.
+In any case,
+the returned value is the size of buffer needed to hold the whole
+message (including terminating NUL).
+If
+.I errbuf_size
+is 0,
+.I errbuf
+is ignored but the return value is still correct.
+.PP
+If the
+.I errcode
+given to
+.I regerror
+is first ORed with REG_ITOA,
+the ``message'' that results is the printable name of the error code,
+e.g. ``REG_NOMATCH'',
+rather than an explanation thereof.
+If
+.I errcode
+is REG_ATOI,
+then
+.I preg
+shall be non-NULL and the
+.I re_endp
+member of the structure it points to
+must point to the printable name of an error code;
+in this case, the result in
+.I errbuf
+is the decimal digits of
+the numeric value of the error code
+(0 if the name is not recognized).
+REG_ITOA and REG_ATOI are intended primarily as debugging facilities;
+they are extensions,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+Be warned also that they are considered experimental and changes are possible.
+.PP
+.I Regfree
+frees any dynamically-allocated storage associated with the compiled RE
+pointed to by
+.IR preg .
+The remaining
+.I regex_t
+is no longer a valid compiled RE
+and the effect of supplying it to
+.I regexec
+or
+.I regerror
+is undefined.
+.PP
+None of these functions references global variables except for tables
+of constants;
+all are safe for use from multiple threads if the arguments are safe.
+.SH IMPLEMENTATION CHOICES
+There are a number of decisions that 1003.2 leaves up to the implementor,
+either by explicitly saying ``undefined'' or by virtue of them being
+forbidden by the RE grammar.
+This implementation treats them as follows.
+.PP
+See
+.ZR
+for a discussion of the definition of case-independent matching.
+.PP
+There is no particular limit on the length of REs,
+except insofar as memory is limited.
+Memory usage is approximately linear in RE size, and largely insensitive
+to RE complexity, except for bounded repetitions.
+See BUGS for one short RE using them
+that will run almost any system out of memory.
+.PP
+A backslashed character other than one specifically given a magic meaning
+by 1003.2 (such magic meanings occur only in obsolete [``basic''] REs)
+is taken as an ordinary character.
+.PP
+Any unmatched [ is a REG_EBRACK error.
+.PP
+Equivalence classes cannot begin or end bracket-expression ranges.
+The endpoint of one range cannot begin another.
+.PP
+RE_DUP_MAX, the limit on repetition counts in bounded repetitions, is 255.
+.PP
+A repetition operator (?, *, +, or bounds) cannot follow another
+repetition operator.
+A repetition operator cannot begin an expression or subexpression
+or follow `^' or `|'.
+.PP
+`|' cannot appear first or last in a (sub)expression or after another `|',
+i.e. an operand of `|' cannot be an empty subexpression.
+An empty parenthesized subexpression, `()', is legal and matches an
+empty (sub)string.
+An empty string is not a legal RE.
+.PP
+A `{' followed by a digit is considered the beginning of bounds for a
+bounded repetition, which must then follow the syntax for bounds.
+A `{' \fInot\fR followed by a digit is considered an ordinary character.
+.PP
+`^' and `$' beginning and ending subexpressions in obsolete (``basic'')
+REs are anchors, not ordinary characters.
+.SH SEE ALSO
+grep(1), regex(7)
+.PP
+POSIX 1003.2, sections 2.8 (Regular Expression Notation)
+and
+B.5 (C Binding for Regular Expression Matching).
+.SH DIAGNOSTICS
+Non-zero error codes from
+.I regcomp
+and
+.I regexec
+include the following:
+.PP
+.nf
+.ta \w'REG_ECOLLATE'u+3n
+REG_NOMATCH regexec() failed to match
+REG_BADPAT invalid regular expression
+REG_ECOLLATE invalid collating element
+REG_ECTYPE invalid character class
+REG_EESCAPE \e applied to unescapable character
+REG_ESUBREG invalid backreference number
+REG_EBRACK brackets [ ] not balanced
+REG_EPAREN parentheses ( ) not balanced
+REG_EBRACE braces { } not balanced
+REG_BADBR invalid repetition count(s) in { }
+REG_ERANGE invalid character range in [ ]
+REG_ESPACE ran out of memory
+REG_BADRPT ?, *, or + operand invalid
+REG_EMPTY empty (sub)expression
+REG_ASSERT ``can't happen''\(emyou found a bug
+REG_INVARG invalid argument, e.g. negative-length string
+.fi
+.SH HISTORY
+Written by Henry Spencer,
+henry@zoo.toronto.edu.
+.SH BUGS
+This is an alpha release with known defects.
+Please report problems.
+.PP
+There is one known functionality bug.
+The implementation of internationalization is incomplete:
+the locale is always assumed to be the default one of 1003.2,
+and only the collating elements etc. of that locale are available.
+.PP
+The back-reference code is subtle and doubts linger about its correctness
+in complex cases.
+.PP
+.I Regexec
+performance is poor.
+This will improve with later releases.
+.I Nmatch
+exceeding 0 is expensive;
+.I nmatch
+exceeding 1 is worse.
+.I Regexec
+is largely insensitive to RE complexity \fIexcept\fR that back
+references are massively expensive.
+RE length does matter; in particular, there is a strong speed bonus
+for keeping RE length under about 30 characters,
+with most special characters counting roughly double.
+.PP
+.I Regcomp
+implements bounded repetitions by macro expansion,
+which is costly in time and space if counts are large
+or bounded repetitions are nested.
+An RE like, say,
+`((((a{1,100}){1,100}){1,100}){1,100}){1,100}'
+will (eventually) run almost any existing machine out of swap space.
+.PP
+There are suspected problems with response to obscure error conditions.
+Notably,
+certain kinds of internal overflow,
+produced only by truly enormous REs or by multiply nested bounded repetitions,
+are probably not handled well.
+.PP
+Due to a mistake in 1003.2, things like `a)b' are legal REs because `)' is
+a special character only in the presence of a previous unmatched `('.
+This can't be fixed until the spec is fixed.
+.PP
+The standard's definition of back references is vague.
+For example, does
+`a\e(\e(b\e)*\e2\e)*d' match `abbbd'?
+Until the standard is clarified,
+behavior in such cases should not be relied on.
+.PP
+The implementation of word-boundary matching is a bit of a kludge,
+and bugs may lurk in combinations of word-boundary matching and anchoring.
diff --git a/vcnet/regex/regex.7 b/vcnet/regex/regex.7
new file mode 100644
index 000000000..0fa180269
--- /dev/null
+++ b/vcnet/regex/regex.7
@@ -0,0 +1,235 @@
+.TH REGEX 7 "25 Oct 1995"
+.BY "Henry Spencer"
+.SH NAME
+regex \- POSIX 1003.2 regular expressions
+.SH DESCRIPTION
+Regular expressions (``RE''s),
+as defined in POSIX 1003.2, come in two forms:
+modern REs (roughly those of
+.IR egrep ;
+1003.2 calls these ``extended'' REs)
+and obsolete REs (roughly those of
+.IR ed ;
+1003.2 ``basic'' REs).
+Obsolete REs mostly exist for backward compatibility in some old programs;
+they will be discussed at the end.
+1003.2 leaves some aspects of RE syntax and semantics open;
+`\(dg' marks decisions on these aspects that
+may not be fully portable to other 1003.2 implementations.
+.PP
+A (modern) RE is one\(dg or more non-empty\(dg \fIbranches\fR,
+separated by `|'.
+It matches anything that matches one of the branches.
+.PP
+A branch is one\(dg or more \fIpieces\fR, concatenated.
+It matches a match for the first, followed by a match for the second, etc.
+.PP
+A piece is an \fIatom\fR possibly followed
+by a single\(dg `*', `+', `?', or \fIbound\fR.
+An atom followed by `*' matches a sequence of 0 or more matches of the atom.
+An atom followed by `+' matches a sequence of 1 or more matches of the atom.
+An atom followed by `?' matches a sequence of 0 or 1 matches of the atom.
+.PP
+A \fIbound\fR is `{' followed by an unsigned decimal integer,
+possibly followed by `,'
+possibly followed by another unsigned decimal integer,
+always followed by `}'.
+The integers must lie between 0 and RE_DUP_MAX (255\(dg) inclusive,
+and if there are two of them, the first may not exceed the second.
+An atom followed by a bound containing one integer \fIi\fR
+and no comma matches
+a sequence of exactly \fIi\fR matches of the atom.
+An atom followed by a bound
+containing one integer \fIi\fR and a comma matches
+a sequence of \fIi\fR or more matches of the atom.
+An atom followed by a bound
+containing two integers \fIi\fR and \fIj\fR matches
+a sequence of \fIi\fR through \fIj\fR (inclusive) matches of the atom.
+.PP
+An atom is a regular expression enclosed in `()' (matching a match for the
+regular expression),
+an empty set of `()' (matching the null string)\(dg,
+a \fIbracket expression\fR (see below), `.'
+(matching any single character), `^' (matching the null string at the
+beginning of a line), `$' (matching the null string at the
+end of a line), a `\e' followed by one of the characters
+`^.[$()|*+?{\e'
+(matching that character taken as an ordinary character),
+a `\e' followed by any other character\(dg
+(matching that character taken as an ordinary character,
+as if the `\e' had not been present\(dg),
+or a single character with no other significance (matching that character).
+A `{' followed by a character other than a digit is an ordinary
+character, not the beginning of a bound\(dg.
+It is illegal to end an RE with `\e'.
+.PP
+A \fIbracket expression\fR is a list of characters enclosed in `[]'.
+It normally matches any single character from the list (but see below).
+If the list begins with `^',
+it matches any single character
+(but see below) \fInot\fR from the rest of the list.
+If two characters in the list are separated by `\-', this is shorthand
+for the full \fIrange\fR of characters between those two (inclusive) in the
+collating sequence,
+e.g. `[0\-9]' in ASCII matches any decimal digit.
+It is illegal\(dg for two ranges to share an
+endpoint, e.g. `a\-c\-e'.
+Ranges are very collating-sequence-dependent,
+and portable programs should avoid relying on them.
+.PP
+To include a literal `]' in the list, make it the first character
+(following a possible `^').
+To include a literal `\-', make it the first or last character,
+or the second endpoint of a range.
+To use a literal `\-' as the first endpoint of a range,
+enclose it in `[.' and `.]' to make it a collating element (see below).
+With the exception of these and some combinations using `[' (see next
+paragraphs), all other special characters, including `\e', lose their
+special significance within a bracket expression.
+.PP
+Within a bracket expression, a collating element (a character,
+a multi-character sequence that collates as if it were a single character,
+or a collating-sequence name for either)
+enclosed in `[.' and `.]' stands for the
+sequence of characters of that collating element.
+The sequence is a single element of the bracket expression's list.
+A bracket expression containing a multi-character collating element
+can thus match more than one character,
+e.g. if the collating sequence includes a `ch' collating element,
+then the RE `[[.ch.]]*c' matches the first five characters
+of `chchcc'.
+.PP
+Within a bracket expression, a collating element enclosed in `[=' and
+`=]' is an equivalence class, standing for the sequences of characters
+of all collating elements equivalent to that one, including itself.
+(If there are no other equivalent collating elements,
+the treatment is as if the enclosing delimiters were `[.' and `.]'.)
+For example, if o and \o'o^' are the members of an equivalence class,
+then `[[=o=]]', `[[=\o'o^'=]]', and `[o\o'o^']' are all synonymous.
+An equivalence class may not\(dg be an endpoint
+of a range.
+.PP
+Within a bracket expression, the name of a \fIcharacter class\fR enclosed
+in `[:' and `:]' stands for the list of all characters belonging to that
+class.
+Standard character class names are:
+.PP
+.RS
+.nf
+.ta 3c 6c 9c
+alnum digit punct
+alpha graph space
+blank lower upper
+cntrl print xdigit
+.fi
+.RE
+.PP
+These stand for the character classes defined in
+.IR ctype (3).
+A locale may provide others.
+A character class may not be used as an endpoint of a range.
+.PP
+There are two special cases\(dg of bracket expressions:
+the bracket expressions `[[:<:]]' and `[[:>:]]' match the null string at
+the beginning and end of a word respectively.
+A word is defined as a sequence of
+word characters
+which is neither preceded nor followed by
+word characters.
+A word character is an
+.I alnum
+character (as defined by
+.IR ctype (3))
+or an underscore.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+.PP
+In the event that an RE could match more than one substring of a given
+string,
+the RE matches the one starting earliest in the string.
+If the RE could match more than one substring starting at that point,
+it matches the longest.
+Subexpressions also match the longest possible substrings, subject to
+the constraint that the whole match be as long as possible,
+with subexpressions starting earlier in the RE taking priority over
+ones starting later.
+Note that higher-level subexpressions thus take priority over
+their lower-level component subexpressions.
+.PP
+Match lengths are measured in characters, not collating elements.
+A null string is considered longer than no match at all.
+For example,
+`bb*' matches the three middle characters of `abbbc',
+`(wee|week)(knights|nights)' matches all ten characters of `weeknights',
+when `(.*).*' is matched against `abc' the parenthesized subexpression
+matches all three characters, and
+when `(a*)*' is matched against `bc' both the whole RE and the parenthesized
+subexpression match the null string.
+.PP
+If case-independent matching is specified,
+the effect is much as if all case distinctions had vanished from the
+alphabet.
+When an alphabetic that exists in multiple cases appears as an
+ordinary character outside a bracket expression, it is effectively
+transformed into a bracket expression containing both cases,
+e.g. `x' becomes `[xX]'.
+When it appears inside a bracket expression, all case counterparts
+of it are added to the bracket expression, so that (e.g.) `[x]'
+becomes `[xX]' and `[^x]' becomes `[^xX]'.
+.PP
+No particular limit is imposed on the length of REs\(dg.
+Programs intended to be portable should not employ REs longer
+than 256 bytes,
+as an implementation can refuse to accept such REs and remain
+POSIX-compliant.
+.PP
+Obsolete (``basic'') regular expressions differ in several respects.
+`|', `+', and `?' are ordinary characters and there is no equivalent
+for their functionality.
+The delimiters for bounds are `\e{' and `\e}',
+with `{' and `}' by themselves ordinary characters.
+The parentheses for nested subexpressions are `\e(' and `\e)',
+with `(' and `)' by themselves ordinary characters.
+`^' is an ordinary character except at the beginning of the
+RE or\(dg the beginning of a parenthesized subexpression,
+`$' is an ordinary character except at the end of the
+RE or\(dg the end of a parenthesized subexpression,
+and `*' is an ordinary character if it appears at the beginning of the
+RE or the beginning of a parenthesized subexpression
+(after a possible leading `^').
+Finally, there is one new type of atom, a \fIback reference\fR:
+`\e' followed by a non-zero decimal digit \fId\fR
+matches the same sequence of characters
+matched by the \fId\fRth parenthesized subexpression
+(numbering subexpressions by the positions of their opening parentheses,
+left to right),
+so that (e.g.) `\e([bc]\e)\e1' matches `bb' or `cc' but not `bc'.
+.SH SEE ALSO
+regex(3)
+.PP
+POSIX 1003.2, section 2.8 (Regular Expression Notation).
+.SH HISTORY
+Written by Henry Spencer, based on the 1003.2 spec.
+.SH BUGS
+Having two kinds of REs is a botch.
+.PP
+The current 1003.2 spec says that `)' is an ordinary character in
+the absence of an unmatched `(';
+this was an unintentional result of a wording error,
+and change is likely.
+Avoid relying on it.
+.PP
+Back references are a dreadful botch,
+posing major problems for efficient implementations.
+They are also somewhat vaguely defined
+(does
+`a\e(\e(b\e)*\e2\e)*d' match `abbbd'?).
+Avoid using them.
+.PP
+1003.2's specification of case-independent matching is vague.
+The ``one case implies all cases'' definition given above
+is current consensus among implementors as to the right interpretation.
+.PP
+The syntax for word boundaries is incredibly ugly.
diff --git a/vcnet/regex/regex.h b/vcnet/regex/regex.h
new file mode 100644
index 000000000..6918a5521
--- /dev/null
+++ b/vcnet/regex/regex.h
@@ -0,0 +1,74 @@
+#ifndef _REGEX_H_
+#define _REGEX_H_ /* never again */
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regex2.h === */
+typedef long regoff_t;
+typedef struct {
+ int re_magic;
+ size_t re_nsub; /* number of parenthesized subexpressions */
+ const char *re_endp; /* end pointer for REG_PEND */
+ struct re_guts *re_g; /* none of your business :-) */
+} regex_t;
+typedef struct {
+ regoff_t rm_so; /* start of match */
+ regoff_t rm_eo; /* end of match */
+} regmatch_t;
+
+
+/* === regcomp.c === */
+extern int regcomp(regex_t *, const char *, int);
+#define REG_BASIC 0000
+#define REG_EXTENDED 0001
+#define REG_ICASE 0002
+#define REG_NOSUB 0004
+#define REG_NEWLINE 0010
+#define REG_NOSPEC 0020
+#define REG_PEND 0040
+#define REG_DUMP 0200
+
+
+/* === regerror.c === */
+#define REG_OKAY 0
+#define REG_NOMATCH 1
+#define REG_BADPAT 2
+#define REG_ECOLLATE 3
+#define REG_ECTYPE 4
+#define REG_EESCAPE 5
+#define REG_ESUBREG 6
+#define REG_EBRACK 7
+#define REG_EPAREN 8
+#define REG_EBRACE 9
+#define REG_BADBR 10
+#define REG_ERANGE 11
+#define REG_ESPACE 12
+#define REG_BADRPT 13
+#define REG_EMPTY 14
+#define REG_ASSERT 15
+#define REG_INVARG 16
+#define REG_ATOI 255 /* convert name to number (!) */
+#define REG_ITOA 0400 /* convert number to name (!) */
+extern size_t regerror(int, const regex_t *, char *, size_t);
+
+
+/* === regexec.c === */
+extern int regexec(const regex_t *, const char *, size_t, regmatch_t [], int);
+#define REG_NOTBOL 00001
+#define REG_NOTEOL 00002
+#define REG_STARTEND 00004
+#define REG_TRACE 00400 /* tracing of execution */
+#define REG_LARGE 01000 /* force large representation */
+#define REG_BACKR 02000 /* force use of backref code */
+
+
+/* === regfree.c === */
+extern void regfree(regex_t *);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
+#endif
diff --git a/vcnet/regex/regex2.h b/vcnet/regex/regex2.h
new file mode 100644
index 000000000..58fd8d8a4
--- /dev/null
+++ b/vcnet/regex/regex2.h
@@ -0,0 +1,134 @@
+/*
+ * First, the stuff that ends up in the outside-world include file
+ = typedef off_t regoff_t;
+ = typedef struct {
+ = int re_magic;
+ = size_t re_nsub; // number of parenthesized subexpressions
+ = const char *re_endp; // end pointer for REG_PEND
+ = struct re_guts *re_g; // none of your business :-)
+ = } regex_t;
+ = typedef struct {
+ = regoff_t rm_so; // start of match
+ = regoff_t rm_eo; // end of match
+ = } regmatch_t;
+ */
+/*
+ * internals of regex_t
+ */
+#define MAGIC1 ((('r'^0200)<<8) | 'e')
+
+/*
+ * The internal representation is a *strip*, a sequence of
+ * operators ending with an endmarker. (Some terminology etc. is a
+ * historical relic of earlier versions which used multiple strips.)
+ * Certain oddities in the representation are there to permit running
+ * the machinery backwards; in particular, any deviation from sequential
+ * flow must be marked at both its source and its destination. Some
+ * fine points:
+ *
+ * - OPLUS_ and O_PLUS are *inside* the loop they create.
+ * - OQUEST_ and O_QUEST are *outside* the bypass they create.
+ * - OCH_ and O_CH are *outside* the multi-way branch they create, while
+ * OOR1 and OOR2 are respectively the end and the beginning of one of
+ * the branches. Note that there is an implicit OOR2 following OCH_
+ * and an implicit OOR1 preceding O_CH.
+ *
+ * In state representations, an operator's bit is on to signify a state
+ * immediately *preceding* "execution" of that operator.
+ */
+typedef long sop; /* strip operator */
+typedef long sopno;
+#define OPRMASK 0x7c000000
+#define OPDMASK 0x03ffffff
+#define OPSHIFT (26)
+#define OP(n) ((n)&OPRMASK)
+#define OPND(n) ((n)&OPDMASK)
+#define SOP(op, opnd) ((op)|(opnd))
+/* operators meaning operand */
+/* (back, fwd are offsets) */
+#define OEND (1<<OPSHIFT) /* endmarker - */
+#define OCHAR (2<<OPSHIFT) /* character unsigned char */
+#define OBOL (3<<OPSHIFT) /* left anchor - */
+#define OEOL (4<<OPSHIFT) /* right anchor - */
+#define OANY (5<<OPSHIFT) /* . - */
+#define OANYOF (6<<OPSHIFT) /* [...] set number */
+#define OBACK_ (7<<OPSHIFT) /* begin \d paren number */
+#define O_BACK (8<<OPSHIFT) /* end \d paren number */
+#define OPLUS_ (9<<OPSHIFT) /* + prefix fwd to suffix */
+#define O_PLUS (10<<OPSHIFT) /* + suffix back to prefix */
+#define OQUEST_ (11<<OPSHIFT) /* ? prefix fwd to suffix */
+#define O_QUEST (12<<OPSHIFT) /* ? suffix back to prefix */
+#define OLPAREN (13<<OPSHIFT) /* ( fwd to ) */
+#define ORPAREN (14<<OPSHIFT) /* ) back to ( */
+#define OCH_ (15<<OPSHIFT) /* begin choice fwd to OOR2 */
+#define OOR1 (16<<OPSHIFT) /* | pt. 1 back to OOR1 or OCH_ */
+#define OOR2 (17<<OPSHIFT) /* | pt. 2 fwd to OOR2 or O_CH */
+#define O_CH (18<<OPSHIFT) /* end choice back to OOR1 */
+#define OBOW (19<<OPSHIFT) /* begin word - */
+#define OEOW (20<<OPSHIFT) /* end word - */
+
+/*
+ * Structure for [] character-set representation. Character sets are
+ * done as bit vectors, grouped 8 to a byte vector for compactness.
+ * The individual set therefore has both a pointer to the byte vector
+ * and a mask to pick out the relevant bit of each byte. A hash code
+ * simplifies testing whether two sets could be identical.
+ *
+ * This will get trickier for multicharacter collating elements. As
+ * preliminary hooks for dealing with such things, we also carry along
+ * a string of multi-character elements, and decide the size of the
+ * vectors at run time.
+ */
+typedef struct {
+ uch *ptr; /* -> uch [csetsize] */
+ uch mask; /* bit within array */
+ uch hash; /* hash code */
+ size_t smultis;
+ char *multis; /* -> char[smulti] ab\0cd\0ef\0\0 */
+} cset;
+/* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */
+#define CHadd(cs, c) ((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (c))
+#define CHsub(cs, c) ((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (c))
+#define CHIN(cs, c) ((cs)->ptr[(uch)(c)] & (cs)->mask)
+#define MCadd(p, cs, cp) mcadd(p, cs, cp) /* regcomp() internal fns */
+#define MCsub(p, cs, cp) mcsub(p, cs, cp)
+#define MCin(p, cs, cp) mcin(p, cs, cp)
+
+/* stuff for character categories */
+typedef unsigned char cat_t;
+
+/*
+ * main compiled-expression structure
+ */
+struct re_guts {
+ int magic;
+# define MAGIC2 ((('R'^0200)<<8)|'E')
+ sop *strip; /* malloced area for strip */
+ int csetsize; /* number of bits in a cset vector */
+ int ncsets; /* number of csets in use */
+ cset *sets; /* -> cset [ncsets] */
+ uch *setbits; /* -> uch[csetsize][ncsets/CHAR_BIT] */
+ int cflags; /* copy of regcomp() cflags argument */
+ sopno nstates; /* = number of sops */
+ sopno firststate; /* the initial OEND (normally 0) */
+ sopno laststate; /* the final OEND */
+ int iflags; /* internal flags */
+# define USEBOL 01 /* used ^ */
+# define USEEOL 02 /* used $ */
+# define BAD 04 /* something wrong */
+ int nbol; /* number of ^ used */
+ int neol; /* number of $ used */
+ int ncategories; /* how many character categories */
+ cat_t *categories; /* ->catspace[-CHAR_MIN] */
+ char *must; /* match must contain this string */
+ int mlen; /* length of must */
+ size_t nsub; /* copy of re_nsub */
+ int backrefs; /* does it use back references? */
+ sopno nplus; /* how deep does it nest +s? */
+ /* catspace must be last */
+ cat_t catspace[1]; /* actually [NC] */
+};
+
+/* misc utilities */
+#define OUT (CHAR_MAX+1) /* a non-character value */
+#define ISWORD(c) (isalnum(c) || (c) == '_')
diff --git a/vcnet/regex/regexec.c b/vcnet/regex/regexec.c
new file mode 100644
index 000000000..dcb11b285
--- /dev/null
+++ b/vcnet/regex/regexec.c
@@ -0,0 +1,138 @@
+/*
+ * the outer shell of regexec()
+ *
+ * This file includes engine.c *twice*, after muchos fiddling with the
+ * macros that code uses. This lets the same code operate on two different
+ * representations for state sets.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+static int nope = 0; /* for use in asserts; shuts lint up */
+
+/* macros for manipulating states, small version */
+#define states unsigned
+#define states1 unsigned /* for later use in regexec() decision */
+#define CLEAR(v) ((v) = 0)
+#define SET0(v, n) ((v) &= ~((unsigned)1 << (n)))
+#define SET1(v, n) ((v) |= (unsigned)1 << (n))
+#define ISSET(v, n) ((v) & ((unsigned)1 << (n)))
+#define ASSIGN(d, s) ((d) = (s))
+#define EQ(a, b) ((a) == (b))
+#define STATEVARS int dummy /* dummy version */
+#define STATESETUP(m, n) /* nothing */
+#define STATETEARDOWN(m) /* nothing */
+#define SETUP(v) ((v) = 0)
+#define onestate unsigned
+#define INIT(o, n) ((o) = (unsigned)1 << (n))
+#define INC(o) ((o) <<= 1)
+#define ISSTATEIN(v, o) ((v) & (o))
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define FWD(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) << (n))
+#define BACK(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) >> (n))
+#define ISSETBACK(v, n) ((v) & ((unsigned)here >> (n)))
+/* function names */
+#define SNAMES /* engine.c looks after details */
+
+#include "engine.c"
+
+/* now undo things */
+#undef states
+#undef CLEAR
+#undef SET0
+#undef SET1
+#undef ISSET
+#undef ASSIGN
+#undef EQ
+#undef STATEVARS
+#undef STATESETUP
+#undef STATETEARDOWN
+#undef SETUP
+#undef onestate
+#undef INIT
+#undef INC
+#undef ISSTATEIN
+#undef FWD
+#undef BACK
+#undef ISSETBACK
+#undef SNAMES
+
+/* macros for manipulating states, large version */
+#define states char *
+#define CLEAR(v) memset(v, 0, m->g->nstates)
+#define SET0(v, n) ((v)[n] = 0)
+#define SET1(v, n) ((v)[n] = 1)
+#define ISSET(v, n) ((v)[n])
+#define ASSIGN(d, s) memcpy(d, s, m->g->nstates)
+#define EQ(a, b) (memcmp(a, b, m->g->nstates) == 0)
+#define STATEVARS int vn; char *space
+#define STATESETUP(m, nv) { (m)->space = malloc((nv)*(m)->g->nstates); \
+ if ((m)->space == NULL) return(REG_ESPACE); \
+ (m)->vn = 0; }
+#define STATETEARDOWN(m) { free((m)->space); }
+#define SETUP(v) ((v) = &m->space[m->vn++ * m->g->nstates])
+#define onestate int
+#define INIT(o, n) ((o) = (n))
+#define INC(o) ((o)++)
+#define ISSTATEIN(v, o) ((v)[o])
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define FWD(dst, src, n) ((dst)[here+(n)] |= (src)[here])
+#define BACK(dst, src, n) ((dst)[here-(n)] |= (src)[here])
+#define ISSETBACK(v, n) ((v)[here - (n)])
+/* function names */
+#define LNAMES /* flag */
+
+#include "engine.c"
+
+/*
+ - regexec - interface for matching
+ = extern int regexec(const regex_t *, const char *, size_t, \
+ = regmatch_t [], int);
+ = #define REG_NOTBOL 00001
+ = #define REG_NOTEOL 00002
+ = #define REG_STARTEND 00004
+ = #define REG_TRACE 00400 // tracing of execution
+ = #define REG_LARGE 01000 // force large representation
+ = #define REG_BACKR 02000 // force use of backref code
+ *
+ * We put this here so we can exploit knowledge of the state representation
+ * when choosing which matcher to call. Also, by this point the matchers
+ * have been prototyped.
+ */
+int /* 0 success, REG_NOMATCH failure */
+regexec(preg, string, nmatch, pmatch, eflags)
+const regex_t *preg;
+const char *string;
+size_t nmatch;
+regmatch_t pmatch[];
+int eflags;
+{
+ register struct re_guts *g = preg->re_g;
+#ifdef REDEBUG
+# define GOODFLAGS(f) (f)
+#else
+# define GOODFLAGS(f) ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND))
+#endif
+
+ if (preg->re_magic != MAGIC1 || g->magic != MAGIC2)
+ return(REG_BADPAT);
+ assert(!(g->iflags&BAD));
+ if (g->iflags&BAD) /* backstop for no-debug case */
+ return(REG_BADPAT);
+ eflags = GOODFLAGS(eflags);
+
+ if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags&REG_LARGE))
+ return(smatcher(g, (char *)string, nmatch, pmatch, eflags));
+ else
+ return(lmatcher(g, (char *)string, nmatch, pmatch, eflags));
+}
diff --git a/vcnet/regex/regfree.c b/vcnet/regex/regfree.c
new file mode 100644
index 000000000..9a6acf173
--- /dev/null
+++ b/vcnet/regex/regfree.c
@@ -0,0 +1,37 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+/*
+ - regfree - free everything
+ = extern void regfree(regex_t *);
+ */
+void
+regfree(preg)
+regex_t *preg;
+{
+ register struct re_guts *g;
+
+ if (preg->re_magic != MAGIC1) /* oops */
+ return; /* nice to complain, but hard */
+
+ g = preg->re_g;
+ if (g == NULL || g->magic != MAGIC2) /* oops again */
+ return;
+ preg->re_magic = 0; /* mark it invalid */
+ g->magic = 0; /* mark it invalid */
+
+ if (g->strip != NULL)
+ free((char *)g->strip);
+ if (g->sets != NULL)
+ free((char *)g->sets);
+ if (g->setbits != NULL)
+ free((char *)g->setbits);
+ if (g->must != NULL)
+ free(g->must);
+ free((char *)g);
+}
diff --git a/vcnet/regex/split.c b/vcnet/regex/split.c
new file mode 100644
index 000000000..188bdb775
--- /dev/null
+++ b/vcnet/regex/split.c
@@ -0,0 +1,316 @@
+#include <stdio.h>
+#include <string.h>
+
+/*
+ - split - divide a string into fields, like awk split()
+ = int split(char *string, char *fields[], int nfields, char *sep);
+ */
+int /* number of fields, including overflow */
+split(string, fields, nfields, sep)
+char *string;
+char *fields[]; /* list is not NULL-terminated */
+int nfields; /* number of entries available in fields[] */
+char *sep; /* "" white, "c" single char, "ab" [ab]+ */
+{
+ register char *p = string;
+ register char c; /* latest character */
+ register char sepc = sep[0];
+ register char sepc2;
+ register int fn;
+ register char **fp = fields;
+ register char *sepp;
+ register int trimtrail;
+
+ /* white space */
+ if (sepc == '\0') {
+ while ((c = *p++) == ' ' || c == '\t')
+ continue;
+ p--;
+ trimtrail = 1;
+ sep = " \t"; /* note, code below knows this is 2 long */
+ sepc = ' ';
+ } else
+ trimtrail = 0;
+ sepc2 = sep[1]; /* now we can safely pick this up */
+
+ /* catch empties */
+ if (*p == '\0')
+ return(0);
+
+ /* single separator */
+ if (sepc2 == '\0') {
+ fn = nfields;
+ for (;;) {
+ *fp++ = p;
+ fn--;
+ if (fn == 0)
+ break;
+ while ((c = *p++) != sepc)
+ if (c == '\0')
+ return(nfields - fn);
+ *(p-1) = '\0';
+ }
+ /* we have overflowed the fields vector -- just count them */
+ fn = nfields;
+ for (;;) {
+ while ((c = *p++) != sepc)
+ if (c == '\0')
+ return(fn);
+ fn++;
+ }
+ /* not reached */
+ }
+
+ /* two separators */
+ if (sep[2] == '\0') {
+ fn = nfields;
+ for (;;) {
+ *fp++ = p;
+ fn--;
+ while ((c = *p++) != sepc && c != sepc2)
+ if (c == '\0') {
+ if (trimtrail && **(fp-1) == '\0')
+ fn++;
+ return(nfields - fn);
+ }
+ if (fn == 0)
+ break;
+ *(p-1) = '\0';
+ while ((c = *p++) == sepc || c == sepc2)
+ continue;
+ p--;
+ }
+ /* we have overflowed the fields vector -- just count them */
+ fn = nfields;
+ while (c != '\0') {
+ while ((c = *p++) == sepc || c == sepc2)
+ continue;
+ p--;
+ fn++;
+ while ((c = *p++) != '\0' && c != sepc && c != sepc2)
+ continue;
+ }
+ /* might have to trim trailing white space */
+ if (trimtrail) {
+ p--;
+ while ((c = *--p) == sepc || c == sepc2)
+ continue;
+ p++;
+ if (*p != '\0') {
+ if (fn == nfields+1)
+ *p = '\0';
+ fn--;
+ }
+ }
+ return(fn);
+ }
+
+ /* n separators */
+ fn = 0;
+ for (;;) {
+ if (fn < nfields)
+ *fp++ = p;
+ fn++;
+ for (;;) {
+ c = *p++;
+ if (c == '\0')
+ return(fn);
+ sepp = sep;
+ while ((sepc = *sepp++) != '\0' && sepc != c)
+ continue;
+ if (sepc != '\0') /* it was a separator */
+ break;
+ }
+ if (fn < nfields)
+ *(p-1) = '\0';
+ for (;;) {
+ c = *p++;
+ sepp = sep;
+ while ((sepc = *sepp++) != '\0' && sepc != c)
+ continue;
+ if (sepc == '\0') /* it wasn't a separator */
+ break;
+ }
+ p--;
+ }
+
+ /* not reached */
+}
+
+#ifdef TEST_SPLIT
+
+
+/*
+ * test program
+ * pgm runs regression
+ * pgm sep splits stdin lines by sep
+ * pgm str sep splits str by sep
+ * pgm str sep n splits str by sep n times
+ */
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char buf[512];
+ register int n;
+# define MNF 10
+ char *fields[MNF];
+
+ if (argc > 4)
+ for (n = atoi(argv[3]); n > 0; n--) {
+ (void) strcpy(buf, argv[1]);
+ }
+ else if (argc > 3)
+ for (n = atoi(argv[3]); n > 0; n--) {
+ (void) strcpy(buf, argv[1]);
+ (void) split(buf, fields, MNF, argv[2]);
+ }
+ else if (argc > 2)
+ dosplit(argv[1], argv[2]);
+ else if (argc > 1)
+ while (fgets(buf, sizeof(buf), stdin) != NULL) {
+ buf[strlen(buf)-1] = '\0'; /* stomp newline */
+ dosplit(buf, argv[1]);
+ }
+ else
+ regress();
+
+ exit(0);
+}
+
+dosplit(string, seps)
+char *string;
+char *seps;
+{
+# define NF 5
+ char *fields[NF];
+ register int nf;
+
+ nf = split(string, fields, NF, seps);
+ print(nf, NF, fields);
+}
+
+print(nf, nfp, fields)
+int nf;
+int nfp;
+char *fields[];
+{
+ register int fn;
+ register int bound;
+
+ bound = (nf > nfp) ? nfp : nf;
+ printf("%d:\t", nf);
+ for (fn = 0; fn < bound; fn++)
+ printf("\"%s\"%s", fields[fn], (fn+1 < nf) ? ", " : "\n");
+}
+
+#define RNF 5 /* some table entries know this */
+struct {
+ char *str;
+ char *seps;
+ int nf;
+ char *fi[RNF];
+} tests[] = {
+ "", " ", 0, { "" },
+ " ", " ", 2, { "", "" },
+ "x", " ", 1, { "x" },
+ "xy", " ", 1, { "xy" },
+ "x y", " ", 2, { "x", "y" },
+ "abc def g ", " ", 5, { "abc", "def", "", "g", "" },
+ " a bcd", " ", 4, { "", "", "a", "bcd" },
+ "a b c d e f", " ", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d ", " ", 6, { "", "a", "b", "c", "d " },
+
+ "", " _", 0, { "" },
+ " ", " _", 2, { "", "" },
+ "x", " _", 1, { "x" },
+ "x y", " _", 2, { "x", "y" },
+ "ab _ cd", " _", 2, { "ab", "cd" },
+ " a_b c ", " _", 5, { "", "a", "b", "c", "" },
+ "a b c_d e f", " _", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d ", " _", 6, { "", "a", "b", "c", "d " },
+
+ "", " _~", 0, { "" },
+ " ", " _~", 2, { "", "" },
+ "x", " _~", 1, { "x" },
+ "x y", " _~", 2, { "x", "y" },
+ "ab _~ cd", " _~", 2, { "ab", "cd" },
+ " a_b c~", " _~", 5, { "", "a", "b", "c", "" },
+ "a b_c d~e f", " _~", 6, { "a", "b", "c", "d", "e f" },
+ "~a b c d ", " _~", 6, { "", "a", "b", "c", "d " },
+
+ "", " _~-", 0, { "" },
+ " ", " _~-", 2, { "", "" },
+ "x", " _~-", 1, { "x" },
+ "x y", " _~-", 2, { "x", "y" },
+ "ab _~- cd", " _~-", 2, { "ab", "cd" },
+ " a_b c~", " _~-", 5, { "", "a", "b", "c", "" },
+ "a b_c-d~e f", " _~-", 6, { "a", "b", "c", "d", "e f" },
+ "~a-b c d ", " _~-", 6, { "", "a", "b", "c", "d " },
+
+ "", " ", 0, { "" },
+ " ", " ", 2, { "", "" },
+ "x", " ", 1, { "x" },
+ "xy", " ", 1, { "xy" },
+ "x y", " ", 2, { "x", "y" },
+ "abc def g ", " ", 4, { "abc", "def", "g", "" },
+ " a bcd", " ", 3, { "", "a", "bcd" },
+ "a b c d e f", " ", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d ", " ", 6, { "", "a", "b", "c", "d " },
+
+ "", "", 0, { "" },
+ " ", "", 0, { "" },
+ "x", "", 1, { "x" },
+ "xy", "", 1, { "xy" },
+ "x y", "", 2, { "x", "y" },
+ "abc def g ", "", 3, { "abc", "def", "g" },
+ "\t a bcd", "", 2, { "a", "bcd" },
+ " a \tb\t c ", "", 3, { "a", "b", "c" },
+ "a b c d e ", "", 5, { "a", "b", "c", "d", "e" },
+ "a b\tc d e f", "", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d e f ", "", 6, { "a", "b", "c", "d", "e f " },
+
+ NULL, NULL, 0, { NULL },
+};
+
+regress()
+{
+ char buf[512];
+ register int n;
+ char *fields[RNF+1];
+ register int nf;
+ register int i;
+ register int printit;
+ register char *f;
+
+ for (n = 0; tests[n].str != NULL; n++) {
+ (void) strcpy(buf, tests[n].str);
+ fields[RNF] = NULL;
+ nf = split(buf, fields, RNF, tests[n].seps);
+ printit = 0;
+ if (nf != tests[n].nf) {
+ printf("split `%s' by `%s' gave %d fields, not %d\n",
+ tests[n].str, tests[n].seps, nf, tests[n].nf);
+ printit = 1;
+ } else if (fields[RNF] != NULL) {
+ printf("split() went beyond array end\n");
+ printit = 1;
+ } else {
+ for (i = 0; i < nf && i < RNF; i++) {
+ f = fields[i];
+ if (f == NULL)
+ f = "(NULL)";
+ if (strcmp(f, tests[n].fi[i]) != 0) {
+ printf("split `%s' by `%s', field %d is `%s', not `%s'\n",
+ tests[n].str, tests[n].seps,
+ i, fields[i], tests[n].fi[i]);
+ printit = 1;
+ }
+ }
+ }
+ if (printit)
+ print(nf, RNF, fields);
+ }
+}
+#endif
diff --git a/vcnet/regex/tests b/vcnet/regex/tests
new file mode 100644
index 000000000..e4d928dad
--- /dev/null
+++ b/vcnet/regex/tests
@@ -0,0 +1,477 @@
+# regular expression test set
+# Lines are at least three fields, separated by one or more tabs. "" stands
+# for an empty field. First field is an RE. Second field is flags. If
+# C flag given, regcomp() is expected to fail, and the third field is the
+# error name (minus the leading REG_).
+#
+# Otherwise it is expected to succeed, and the third field is the string to
+# try matching it against. If there is no fourth field, the match is
+# expected to fail. If there is a fourth field, it is the substring that
+# the RE is expected to match. If there is a fifth field, it is a comma-
+# separated list of what the subexpressions should match, with - indicating
+# no match for that one. In both the fourth and fifth fields, a (sub)field
+# starting with @ indicates that the (sub)expression is expected to match
+# a null string followed by the stuff after the @; this provides a way to
+# test where null strings match. The character `N' in REs and strings
+# is newline, `S' is space, `T' is tab, `Z' is NUL.
+#
+# The full list of flags:
+# - placeholder, does nothing
+# b RE is a BRE, not an ERE
+# & try it as both an ERE and a BRE
+# C regcomp() error expected, third field is error name
+# i REG_ICASE
+# m ("mundane") REG_NOSPEC
+# s REG_NOSUB (not really testable)
+# n REG_NEWLINE
+# ^ REG_NOTBOL
+# $ REG_NOTEOL
+# # REG_STARTEND (see below)
+# p REG_PEND
+#
+# For REG_STARTEND, the start/end offsets are those of the substring
+# enclosed in ().
+
+# basics
+a & a a
+abc & abc abc
+abc|de - abc abc
+a|b|c - abc a
+
+# parentheses and perversions thereof
+a(b)c - abc abc
+a\(b\)c b abc abc
+a( C EPAREN
+a( b a( a(
+a\( - a( a(
+a\( bC EPAREN
+a\(b bC EPAREN
+a(b C EPAREN
+a(b b a(b a(b
+# gag me with a right parenthesis -- 1003.2 goofed here (my fault, partly)
+a) - a) a)
+) - ) )
+# end gagging (in a just world, those *should* give EPAREN)
+a) b a) a)
+a\) bC EPAREN
+\) bC EPAREN
+a()b - ab ab
+a\(\)b b ab ab
+
+# anchoring and REG_NEWLINE
+^abc$ & abc abc
+a^b - a^b
+a^b b a^b a^b
+a$b - a$b
+a$b b a$b a$b
+^ & abc @abc
+$ & abc @
+^$ & "" @
+$^ - "" @
+\($\)\(^\) b "" @
+# stop retching, those are legitimate (although disgusting)
+^^ - "" @
+$$ - "" @
+b$ & abNc
+b$ &n abNc b
+^b$ & aNbNc
+^b$ &n aNbNc b
+^$ &n aNNb @Nb
+^$ n abc
+^$ n abcN @
+$^ n aNNb @Nb
+\($\)\(^\) bn aNNb @Nb
+^^ n^ aNNb @Nb
+$$ n aNNb @NN
+^a ^ a
+a$ $ a
+^a ^n aNb
+^b ^n aNb b
+a$ $n bNa
+b$ $n bNa b
+a*(^b$)c* - b b
+a*\(^b$\)c* b b b
+
+# certain syntax errors and non-errors
+| C EMPTY
+| b | |
+* C BADRPT
+* b * *
++ C BADRPT
+? C BADRPT
+"" &C EMPTY
+() - abc @abc
+\(\) b abc @abc
+a||b C EMPTY
+|ab C EMPTY
+ab| C EMPTY
+(|a)b C EMPTY
+(a|)b C EMPTY
+(*a) C BADRPT
+(+a) C BADRPT
+(?a) C BADRPT
+({1}a) C BADRPT
+\(\{1\}a\) bC BADRPT
+(a|*b) C BADRPT
+(a|+b) C BADRPT
+(a|?b) C BADRPT
+(a|{1}b) C BADRPT
+^* C BADRPT
+^* b * *
+^+ C BADRPT
+^? C BADRPT
+^{1} C BADRPT
+^\{1\} bC BADRPT
+
+# metacharacters, backslashes
+a.c & abc abc
+a[bc]d & abd abd
+a\*c & a*c a*c
+a\\b & a\b a\b
+a\\\*b & a\*b a\*b
+a\bc & abc abc
+a\ &C EESCAPE
+a\\bc & a\bc a\bc
+\{ bC BADRPT
+a\[b & a[b a[b
+a[b &C EBRACK
+# trailing $ is a peculiar special case for the BRE code
+a$ & a a
+a$ & a$
+a\$ & a
+a\$ & a$ a$
+a\\$ & a
+a\\$ & a$
+a\\$ & a\$
+a\\$ & a\ a\
+
+# back references, ugh
+a\(b\)\2c bC ESUBREG
+a\(b\1\)c bC ESUBREG
+a\(b*\)c\1d b abbcbbd abbcbbd bb
+a\(b*\)c\1d b abbcbd
+a\(b*\)c\1d b abbcbbbd
+^\(.\)\1 b abc
+a\([bc]\)\1d b abcdabbd abbd b
+a\(\([bc]\)\2\)*d b abbccd abbccd
+a\(\([bc]\)\2\)*d b abbcbd
+# actually, this next one probably ought to fail, but the spec is unclear
+a\(\(b\)*\2\)*d b abbbd abbbd
+# here is a case that no NFA implementation does right
+\(ab*\)[ab]*\1 b ababaaa ababaaa a
+# check out normal matching in the presence of back refs
+\(a\)\1bcd b aabcd aabcd
+\(a\)\1bc*d b aabcd aabcd
+\(a\)\1bc*d b aabd aabd
+\(a\)\1bc*d b aabcccd aabcccd
+\(a\)\1bc*[ce]d b aabcccd aabcccd
+^\(a\)\1b\(c\)*cd$ b aabcccd aabcccd
+
+# ordinary repetitions
+ab*c & abc abc
+ab+c - abc abc
+ab?c - abc abc
+a\(*\)b b a*b a*b
+a\(**\)b b ab ab
+a\(***\)b bC BADRPT
+*a b *a *a
+**a b a a
+***a bC BADRPT
+
+# the dreaded bounded repetitions
+{ & { {
+{abc & {abc {abc
+{1 C BADRPT
+{1} C BADRPT
+a{b & a{b a{b
+a{1}b - ab ab
+a\{1\}b b ab ab
+a{1,}b - ab ab
+a\{1,\}b b ab ab
+a{1,2}b - aab aab
+a\{1,2\}b b aab aab
+a{1 C EBRACE
+a\{1 bC EBRACE
+a{1a C EBRACE
+a\{1a bC EBRACE
+a{1a} C BADBR
+a\{1a\} bC BADBR
+a{,2} - a{,2} a{,2}
+a\{,2\} bC BADBR
+a{,} - a{,} a{,}
+a\{,\} bC BADBR
+a{1,x} C BADBR
+a\{1,x\} bC BADBR
+a{1,x C EBRACE
+a\{1,x bC EBRACE
+a{300} C BADBR
+a\{300\} bC BADBR
+a{1,0} C BADBR
+a\{1,0\} bC BADBR
+ab{0,0}c - abcac ac
+ab\{0,0\}c b abcac ac
+ab{0,1}c - abcac abc
+ab\{0,1\}c b abcac abc
+ab{0,3}c - abbcac abbc
+ab\{0,3\}c b abbcac abbc
+ab{1,1}c - acabc abc
+ab\{1,1\}c b acabc abc
+ab{1,3}c - acabc abc
+ab\{1,3\}c b acabc abc
+ab{2,2}c - abcabbc abbc
+ab\{2,2\}c b abcabbc abbc
+ab{2,4}c - abcabbc abbc
+ab\{2,4\}c b abcabbc abbc
+((a{1,10}){1,10}){1,10} - a a a,a
+
+# multiple repetitions
+a** &C BADRPT
+a++ C BADRPT
+a?? C BADRPT
+a*+ C BADRPT
+a*? C BADRPT
+a+* C BADRPT
+a+? C BADRPT
+a?* C BADRPT
+a?+ C BADRPT
+a{1}{1} C BADRPT
+a*{1} C BADRPT
+a+{1} C BADRPT
+a?{1} C BADRPT
+a{1}* C BADRPT
+a{1}+ C BADRPT
+a{1}? C BADRPT
+a*{b} - a{b} a{b}
+a\{1\}\{1\} bC BADRPT
+a*\{1\} bC BADRPT
+a\{1\}* bC BADRPT
+
+# brackets, and numerous perversions thereof
+a[b]c & abc abc
+a[ab]c & abc abc
+a[^ab]c & adc adc
+a[]b]c & a]c a]c
+a[[b]c & a[c a[c
+a[-b]c & a-c a-c
+a[^]b]c & adc adc
+a[^-b]c & adc adc
+a[b-]c & a-c a-c
+a[b &C EBRACK
+a[] &C EBRACK
+a[1-3]c & a2c a2c
+a[3-1]c &C ERANGE
+a[1-3-5]c &C ERANGE
+a[[.-.]--]c & a-c a-c
+a[1- &C ERANGE
+a[[. &C EBRACK
+a[[.x &C EBRACK
+a[[.x. &C EBRACK
+a[[.x.] &C EBRACK
+a[[.x.]] & ax ax
+a[[.x,.]] &C ECOLLATE
+a[[.one.]]b & a1b a1b
+a[[.notdef.]]b &C ECOLLATE
+a[[.].]]b & a]b a]b
+a[[:alpha:]]c & abc abc
+a[[:notdef:]]c &C ECTYPE
+a[[: &C EBRACK
+a[[:alpha &C EBRACK
+a[[:alpha:] &C EBRACK
+a[[:alpha,:] &C ECTYPE
+a[[:]:]]b &C ECTYPE
+a[[:-:]]b &C ECTYPE
+a[[:alph:]] &C ECTYPE
+a[[:alphabet:]] &C ECTYPE
+[[:alnum:]]+ - -%@a0X- a0X
+[[:alpha:]]+ - -%@aX0- aX
+[[:blank:]]+ - aSSTb SST
+[[:cntrl:]]+ - aNTb NT
+[[:digit:]]+ - a019b 019
+[[:graph:]]+ - Sa%bS a%b
+[[:lower:]]+ - AabC ab
+[[:print:]]+ - NaSbN aSb
+[[:punct:]]+ - S%-&T %-&
+[[:space:]]+ - aSNTb SNT
+[[:upper:]]+ - aBCd BC
+[[:xdigit:]]+ - p0f3Cq 0f3C
+a[[=b=]]c & abc abc
+a[[= &C EBRACK
+a[[=b &C EBRACK
+a[[=b= &C EBRACK
+a[[=b=] &C EBRACK
+a[[=b,=]] &C ECOLLATE
+a[[=one=]]b & a1b a1b
+
+# complexities
+a(((b)))c - abc abc
+a(b|(c))d - abd abd
+a(b*|c)d - abbd abbd
+# just gotta have one DFA-buster, of course
+a[ab]{20} - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab
+# and an inline expansion in case somebody gets tricky
+a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab] - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab
+# and in case somebody just slips in an NFA...
+a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab](wee|week)(knights|night) - aaaaabaaaabaaaabaaaabweeknights aaaaabaaaabaaaabaaaabweeknights
+# fish for anomalies as the number of states passes 32
+12345678901234567890123456789 - a12345678901234567890123456789b 12345678901234567890123456789
+123456789012345678901234567890 - a123456789012345678901234567890b 123456789012345678901234567890
+1234567890123456789012345678901 - a1234567890123456789012345678901b 1234567890123456789012345678901
+12345678901234567890123456789012 - a12345678901234567890123456789012b 12345678901234567890123456789012
+123456789012345678901234567890123 - a123456789012345678901234567890123b 123456789012345678901234567890123
+# and one really big one, beyond any plausible word width
+1234567890123456789012345678901234567890123456789012345678901234567890 - a1234567890123456789012345678901234567890123456789012345678901234567890b 1234567890123456789012345678901234567890123456789012345678901234567890
+# fish for problems as brackets go past 8
+[ab][cd][ef][gh][ij][kl][mn] - xacegikmoq acegikm
+[ab][cd][ef][gh][ij][kl][mn][op] - xacegikmoq acegikmo
+[ab][cd][ef][gh][ij][kl][mn][op][qr] - xacegikmoqy acegikmoq
+[ab][cd][ef][gh][ij][kl][mn][op][q] - xacegikmoqy acegikmoq
+
+# subtleties of matching
+abc & xabcy abc
+a\(b\)?c\1d b acd
+aBc i Abc Abc
+a[Bc]*d i abBCcd abBCcd
+0[[:upper:]]1 &i 0a1 0a1
+0[[:lower:]]1 &i 0A1 0A1
+a[^b]c &i abc
+a[^b]c &i aBc
+a[^b]c &i adc adc
+[a]b[c] - abc abc
+[a]b[a] - aba aba
+[abc]b[abc] - abc abc
+[abc]b[abd] - abd abd
+a(b?c)+d - accd accd
+(wee|week)(knights|night) - weeknights weeknights
+(we|wee|week|frob)(knights|night|day) - weeknights weeknights
+a[bc]d - xyzaaabcaababdacd abd
+a[ab]c - aaabc abc
+abc s abc abc
+a* & b @b
+
+# Let's have some fun -- try to match a C comment.
+# first the obvious, which looks okay at first glance...
+/\*.*\*/ - /*x*/ /*x*/
+# but...
+/\*.*\*/ - /*x*/y/*z*/ /*x*/y/*z*/
+# okay, we must not match */ inside; try to do that...
+/\*([^*]|\*[^/])*\*/ - /*x*/ /*x*/
+/\*([^*]|\*[^/])*\*/ - /*x*/y/*z*/ /*x*/
+# but...
+/\*([^*]|\*[^/])*\*/ - /*x**/y/*z*/ /*x**/y/*z*/
+# and a still fancier version, which does it right (I think)...
+/\*([^*]|\*+[^*/])*\*+/ - /*x*/ /*x*/
+/\*([^*]|\*+[^*/])*\*+/ - /*x*/y/*z*/ /*x*/
+/\*([^*]|\*+[^*/])*\*+/ - /*x**/y/*z*/ /*x**/
+/\*([^*]|\*+[^*/])*\*+/ - /*x****/y/*z*/ /*x****/
+/\*([^*]|\*+[^*/])*\*+/ - /*x**x*/y/*z*/ /*x**x*/
+/\*([^*]|\*+[^*/])*\*+/ - /*x***x/y/*z*/ /*x***x/y/*z*/
+
+# subexpressions
+.* - abc abc -
+a(b)(c)d - abcd abcd b,c
+a(((b)))c - abc abc b,b,b
+a(b|(c))d - abd abd b,-
+a(b*|c|e)d - abbd abbd bb
+a(b*|c|e)d - acd acd c
+a(b*|c|e)d - ad ad @d
+a(b?)c - abc abc b
+a(b?)c - ac ac @c
+a(b+)c - abc abc b
+a(b+)c - abbbc abbbc bbb
+a(b*)c - ac ac @c
+(a|ab)(bc([de]+)f|cde) - abcdef abcdef a,bcdef,de
+# the regression tester only asks for 9 subexpressions
+a(b)(c)(d)(e)(f)(g)(h)(i)(j)k - abcdefghijk abcdefghijk b,c,d,e,f,g,h,i,j
+a(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)l - abcdefghijkl abcdefghijkl b,c,d,e,f,g,h,i,j,k
+a([bc]?)c - abc abc b
+a([bc]?)c - ac ac @c
+a([bc]+)c - abc abc b
+a([bc]+)c - abcc abcc bc
+a([bc]+)bc - abcbc abcbc bc
+a(bb+|b)b - abb abb b
+a(bbb+|bb+|b)b - abb abb b
+a(bbb+|bb+|b)b - abbb abbb bb
+a(bbb+|bb+|b)bb - abbb abbb b
+(.*).* - abcdef abcdef abcdef
+(a*)* - bc @b @b
+
+# do we get the right subexpression when it is used more than once?
+a(b|c)*d - ad ad -
+a(b|c)*d - abcd abcd c
+a(b|c)+d - abd abd b
+a(b|c)+d - abcd abcd c
+a(b|c?)+d - ad ad @d
+a(b|c?)+d - abcd abcd @d
+a(b|c){0,0}d - ad ad -
+a(b|c){0,1}d - ad ad -
+a(b|c){0,1}d - abd abd b
+a(b|c){0,2}d - ad ad -
+a(b|c){0,2}d - abcd abcd c
+a(b|c){0,}d - ad ad -
+a(b|c){0,}d - abcd abcd c
+a(b|c){1,1}d - abd abd b
+a(b|c){1,1}d - acd acd c
+a(b|c){1,2}d - abd abd b
+a(b|c){1,2}d - abcd abcd c
+a(b|c){1,}d - abd abd b
+a(b|c){1,}d - abcd abcd c
+a(b|c){2,2}d - acbd acbd b
+a(b|c){2,2}d - abcd abcd c
+a(b|c){2,4}d - abcd abcd c
+a(b|c){2,4}d - abcbd abcbd b
+a(b|c){2,4}d - abcbcd abcbcd c
+a(b|c){2,}d - abcd abcd c
+a(b|c){2,}d - abcbd abcbd b
+a(b+|((c)*))+d - abd abd @d,@d,-
+a(b+|((c)*))+d - abcd abcd @d,@d,-
+
+# check out the STARTEND option
+[abc] &# a(b)c b
+[abc] &# a(d)c
+[abc] &# a(bc)d b
+[abc] &# a(dc)d c
+. &# a()c
+b.*c &# b(bc)c bc
+b.* &# b(bc)c bc
+.*c &# b(bc)c bc
+
+# plain strings, with the NOSPEC flag
+abc m abc abc
+abc m xabcy abc
+abc m xyz
+a*b m aba*b a*b
+a*b m ab
+"" mC EMPTY
+
+# cases involving NULs
+aZb & a a
+aZb &p a
+aZb &p# (aZb) aZb
+aZ*b &p# (ab) ab
+a.b &# (aZb) aZb
+a.* &# (aZb)c aZb
+
+# word boundaries (ick)
+[[:<:]]a & a a
+[[:<:]]a & ba
+[[:<:]]a & -a a
+a[[:>:]] & a a
+a[[:>:]] & ab
+a[[:>:]] & a- a
+[[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc abc
+[[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc-q abc
+[[:<:]]a.c[[:>:]] & axc-dayc-dazce-abc axc
+[[:<:]]b.c[[:>:]] & a_bxc-byc_d-bzc-q bzc
+[[:<:]].x..[[:>:]] & y_xa_-_xb_y-_xc_-axdc _xc_
+[[:<:]]a_b[[:>:]] & x_a_b
+
+# past problems, and suspected problems
+(A[1])|(A[2])|(A[3])|(A[4])|(A[5])|(A[6])|(A[7])|(A[8])|(A[9])|(A[A]) - A1 A1
+abcdefghijklmnop i abcdefghijklmnop abcdefghijklmnop
+abcdefghijklmnopqrstuv i abcdefghijklmnopqrstuv abcdefghijklmnopqrstuv
+(ALAK)|(ALT[AB])|(CC[123]1)|(CM[123]1)|(GAMC)|(LC[23][EO ])|(SEM[1234])|(SL[ES][12])|(SLWW)|(SLF )|(SLDT)|(VWH[12])|(WH[34][EW])|(WP1[ESN]) - CC11 CC11
+CC[13]1|a{21}[23][EO][123][Es][12]a{15}aa[34][EW]aaaaaaa[X]a - CC11 CC11
+Char \([a-z0-9_]*\)\[.* b Char xyz[k Char xyz[k xyz
+a?b - ab ab
+-\{0,1\}[0-9]*$ b -5 -5
+a*a*a*a*a*a*a* & aaaaaa aaaaaa
diff --git a/vcnet/regex/utils.h b/vcnet/regex/utils.h
new file mode 100644
index 000000000..1a997ac8f
--- /dev/null
+++ b/vcnet/regex/utils.h
@@ -0,0 +1,22 @@
+/* utility definitions */
+#ifdef _POSIX2_RE_DUP_MAX
+#define DUPMAX _POSIX2_RE_DUP_MAX
+#else
+#define DUPMAX 255
+#endif
+#define INFINITY (DUPMAX + 1)
+#define NC (CHAR_MAX - CHAR_MIN + 1)
+typedef unsigned char uch;
+
+/* switch off assertions (if not already off) if no REDEBUG */
+#ifndef REDEBUG
+#ifndef NDEBUG
+#define NDEBUG /* no assertions please */
+#endif
+#endif
+#include <assert.h>
+
+/* for old systems with bcopy() but no memmove() */
+#ifdef USEBCOPY
+#define memmove(d, s, c) bcopy(s, d, c)
+#endif
diff --git a/vcnet/testfile.vcproj b/vcnet/testfile.vcproj
new file mode 100644
index 000000000..070dd6b1c
--- /dev/null
+++ b/vcnet/testfile.vcproj
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="testfile"
+ ProjectGUID="{CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet;.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="Debug\testfile.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/testfile.pdb"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\vcnet;.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="testfile.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\cups\testfile.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vcnet/testhttp.vcproj b/vcnet/testhttp.vcproj
new file mode 100755
index 000000000..c041ebb75
--- /dev/null
+++ b/vcnet/testhttp.vcproj
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="testhttp"
+ ProjectGUID="{90B0058C-8393-411F-BD3B-E2C831D4E883}"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\vcnet;.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="Debug\testhttp.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/testhttp.pdb"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\vcnet;.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="testhttp.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\cups\testhttp.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/xcode/CUPS.xcodeproj/project.pbxproj b/xcode/CUPS.xcodeproj/project.pbxproj
new file mode 100644
index 000000000..5cc40ed70
--- /dev/null
+++ b/xcode/CUPS.xcodeproj/project.pbxproj
@@ -0,0 +1,4614 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 273BF6D91333B6260022CAAB /* Tests */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 273BF6DA1333B6270022CAAB /* Build configuration list for PBXAggregateTarget "Tests" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 726AD704135E8AA1002C930D /* PBXTargetDependency */,
+ 273BF6DE1333B6370022CAAB /* PBXTargetDependency */,
+ 278C58D6136B641D00836530 /* PBXTargetDependency */,
+ 270CCDB2135E3CDE00007BE2 /* PBXTargetDependency */,
+ );
+ name = Tests;
+ productName = Tests;
+ };
+ 274FF5DE13332D3000317ECB /* All */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 274FF5DF13332D3100317ECB /* Build configuration list for PBXAggregateTarget "All" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 274FF5E313332D4300317ECB /* PBXTargetDependency */,
+ 72F75A711336FACD004BB496 /* PBXTargetDependency */,
+ 274FF5E513332D4300317ECB /* PBXTargetDependency */,
+ 274FF622133331D300317ECB /* PBXTargetDependency */,
+ 276684131337FA8D000D33D0 /* PBXTargetDependency */,
+ 2766836B1337AA25000D33D0 /* PBXTargetDependency */,
+ 274FF5E713332D4300317ECB /* PBXTargetDependency */,
+ 274FF6E21333B33F00317ECB /* PBXTargetDependency */,
+ 72F75A731336FACD004BB496 /* PBXTargetDependency */,
+ 274FF6391333348400317ECB /* PBXTargetDependency */,
+ 274FF5E913332D4300317ECB /* PBXTargetDependency */,
+ 274FF648133335A300317ECB /* PBXTargetDependency */,
+ 274FF65E13333A3400317ECB /* PBXTargetDependency */,
+ 274FF67213333AE400317ECB /* PBXTargetDependency */,
+ 724379531333FECE009631B9 /* PBXTargetDependency */,
+ 724379111333E4EA009631B9 /* PBXTargetDependency */,
+ 276683FF1337F7C5000D33D0 /* PBXTargetDependency */,
+ 7243792B1333E962009631B9 /* PBXTargetDependency */,
+ 276683D71337B24A000D33D0 /* PBXTargetDependency */,
+ 276683D91337B24A000D33D0 /* PBXTargetDependency */,
+ 276683DB1337B24A000D33D0 /* PBXTargetDependency */,
+ 276683DD1337B24A000D33D0 /* PBXTargetDependency */,
+ 276683DF1337B24A000D33D0 /* PBXTargetDependency */,
+ 7258EAEF13459ADA009286F1 /* PBXTargetDependency */,
+ 720DD6D11358FDBE0064AA82 /* PBXTargetDependency */,
+ 7243793F1333FD23009631B9 /* PBXTargetDependency */,
+ 724379C31333FF7D009631B9 /* PBXTargetDependency */,
+ );
+ name = All;
+ productName = All;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 270CCDB9135E3D0900007BE2 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72F75A4C1336F31B004BB496 /* libcups_static.a */; };
+ 270CCDBA135E3D0900007BE2 /* libcupsmime.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220FAC13330B2200FCA411 /* libcupsmime.dylib */; };
+ 270CCDBC135E3D3E00007BE2 /* testmime.c in Sources */ = {isa = PBXBuildFile; fileRef = 270CCDBB135E3D3E00007BE2 /* testmime.c */; };
+ 273BF6C71333B5370022CAAB /* testcups.c in Sources */ = {isa = PBXBuildFile; fileRef = 273BF6C61333B5370022CAAB /* testcups.c */; };
+ 273BF6CE1333B5950022CAAB /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 273BF6CB1333B5950022CAAB /* CoreFoundation.framework */; };
+ 273BF6CF1333B5950022CAAB /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 273BF6CC1333B5950022CAAB /* libiconv.dylib */; };
+ 273BF6D01333B5950022CAAB /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 273BF6CD1333B5950022CAAB /* libz.dylib */; };
+ 273BF6D31333B5C30022CAAB /* Kerberos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 273BF6D11333B5C30022CAAB /* Kerberos.framework */; };
+ 273BF6D41333B5C30022CAAB /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 273BF6D21333B5C30022CAAB /* Security.framework */; };
+ 273BF6D71333B5F60022CAAB /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 273BF6D51333B5F60022CAAB /* libresolv.dylib */; };
+ 273BF6D81333B5F60022CAAB /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 273BF6D61333B5F60022CAAB /* SystemConfiguration.framework */; };
+ 274FF5D913332CC700317ECB /* cups-driverd.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF5D613332CC700317ECB /* cups-driverd.cxx */; };
+ 274FF5DA13332CC700317ECB /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 274FF5D713332CC700317ECB /* util.c */; };
+ 274FF5DD13332D0600317ECB /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 274FF60A1333315100317ECB /* ppdc-array.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF5F51333315100317ECB /* ppdc-array.cxx */; };
+ 274FF60B1333315100317ECB /* ppdc-attr.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF5F61333315100317ECB /* ppdc-attr.cxx */; };
+ 274FF60C1333315100317ECB /* ppdc-catalog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF5F71333315100317ECB /* ppdc-catalog.cxx */; };
+ 274FF60D1333315100317ECB /* ppdc-choice.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF5F81333315100317ECB /* ppdc-choice.cxx */; };
+ 274FF60E1333315100317ECB /* ppdc-constraint.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF5F91333315100317ECB /* ppdc-constraint.cxx */; };
+ 274FF60F1333315100317ECB /* ppdc-driver.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF5FA1333315100317ECB /* ppdc-driver.cxx */; };
+ 274FF6101333315100317ECB /* ppdc-file.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF5FB1333315100317ECB /* ppdc-file.cxx */; };
+ 274FF6111333315100317ECB /* ppdc-filter.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF5FC1333315100317ECB /* ppdc-filter.cxx */; };
+ 274FF6121333315100317ECB /* ppdc-font.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF5FD1333315100317ECB /* ppdc-font.cxx */; };
+ 274FF6131333315100317ECB /* ppdc-group.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF5FE1333315100317ECB /* ppdc-group.cxx */; };
+ 274FF6141333315100317ECB /* ppdc-import.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF5FF1333315100317ECB /* ppdc-import.cxx */; };
+ 274FF6151333315100317ECB /* ppdc-mediasize.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF6001333315100317ECB /* ppdc-mediasize.cxx */; };
+ 274FF6161333315100317ECB /* ppdc-message.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF6011333315100317ECB /* ppdc-message.cxx */; };
+ 274FF6171333315100317ECB /* ppdc-option.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF6021333315100317ECB /* ppdc-option.cxx */; };
+ 274FF6181333315100317ECB /* ppdc-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 274FF6031333315100317ECB /* ppdc-private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 274FF6191333315100317ECB /* ppdc-profile.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF6041333315100317ECB /* ppdc-profile.cxx */; };
+ 274FF61A1333315100317ECB /* ppdc-shared.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF6051333315100317ECB /* ppdc-shared.cxx */; };
+ 274FF61B1333315100317ECB /* ppdc-source.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF6061333315100317ECB /* ppdc-source.cxx */; };
+ 274FF61C1333315100317ECB /* ppdc-string.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF6071333315100317ECB /* ppdc-string.cxx */; };
+ 274FF61D1333315100317ECB /* ppdc-variable.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 274FF6081333315100317ECB /* ppdc-variable.cxx */; };
+ 274FF61E1333315100317ECB /* ppdc.h in Headers */ = {isa = PBXBuildFile; fileRef = 274FF6091333315100317ECB /* ppdc.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 274FF6231333321400317ECB /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 274FF6241333323B00317ECB /* libcupsppdc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 274FF5EE133330C800317ECB /* libcupsppdc.dylib */; };
+ 274FF6321333334A00317ECB /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 274FF6361333344400317ECB /* cups-deviced.c in Sources */ = {isa = PBXBuildFile; fileRef = 274FF6351333344400317ECB /* cups-deviced.c */; };
+ 274FF6371333345900317ECB /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 274FF5D713332CC700317ECB /* util.c */; };
+ 274FF64A1333398D00317ECB /* cups-exec.c in Sources */ = {isa = PBXBuildFile; fileRef = 274FF6491333398D00317ECB /* cups-exec.c */; };
+ 274FF658133339D300317ECB /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 274FF65C133339FC00317ECB /* cups-lpd.c in Sources */ = {isa = PBXBuildFile; fileRef = 274FF65B133339FC00317ECB /* cups-lpd.c */; };
+ 274FF66E13333AB500317ECB /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 274FF67013333ACF00317ECB /* cups-polld.c in Sources */ = {isa = PBXBuildFile; fileRef = 274FF66F13333ACF00317ECB /* cups-polld.c */; };
+ 274FF68513333B4300317ECB /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 274FF68613333B4300317ECB /* libcupsmime.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220FAC13330B2200FCA411 /* libcupsmime.dylib */; };
+ 274FF68813333B6E00317ECB /* cupsfilter.c in Sources */ = {isa = PBXBuildFile; fileRef = 274FF68713333B6E00317ECB /* cupsfilter.c */; };
+ 274FF68B1333B1C400317ECB /* adminutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EB51333052D00FCA411 /* adminutil.c */; };
+ 274FF68C1333B1C400317ECB /* array.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EB81333056300FCA411 /* array.c */; };
+ 274FF68D1333B1C400317ECB /* attr.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EBA1333056300FCA411 /* attr.c */; };
+ 274FF68E1333B1C400317ECB /* auth.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EBB1333056300FCA411 /* auth.c */; };
+ 274FF68F1333B1C400317ECB /* backchannel.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EBC1333056300FCA411 /* backchannel.c */; };
+ 274FF6901333B1C400317ECB /* backend.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EBD1333056300FCA411 /* backend.c */; };
+ 274FF6911333B1C400317ECB /* conflicts.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EBF1333056300FCA411 /* conflicts.c */; };
+ 274FF6921333B1C400317ECB /* custom.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EC21333056300FCA411 /* custom.c */; };
+ 274FF6931333B1C400317ECB /* debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220ED1133305BB00FCA411 /* debug.c */; };
+ 274FF6941333B1C400317ECB /* dest.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220ED2133305BB00FCA411 /* dest.c */; };
+ 274FF6951333B1C400317ECB /* dir.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220ED3133305BB00FCA411 /* dir.c */; };
+ 274FF6961333B1C400317ECB /* emit.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220ED5133305BB00FCA411 /* emit.c */; };
+ 274FF6971333B1C400317ECB /* encode.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220ED6133305BB00FCA411 /* encode.c */; };
+ 274FF6981333B1C400317ECB /* file.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220ED8133305BB00FCA411 /* file.c */; };
+ 274FF6991333B1C400317ECB /* getdevices.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EDA133305BB00FCA411 /* getdevices.c */; };
+ 274FF69A1333B1C400317ECB /* getifaddrs.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EDB133305BB00FCA411 /* getifaddrs.c */; };
+ 274FF69B1333B1C400317ECB /* getputfile.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EDC133305BB00FCA411 /* getputfile.c */; };
+ 274FF69C1333B1C400317ECB /* globals.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EDD133305BB00FCA411 /* globals.c */; };
+ 274FF69D1333B1C400317ECB /* http-addr.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EDE133305BB00FCA411 /* http-addr.c */; };
+ 274FF69E1333B1C400317ECB /* http-addrlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EDF133305BB00FCA411 /* http-addrlist.c */; };
+ 274FF69F1333B1C400317ECB /* http-support.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EE1133305BB00FCA411 /* http-support.c */; };
+ 274FF6A01333B1C400317ECB /* http.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EE2133305BB00FCA411 /* http.c */; };
+ 274FF6A11333B1C400317ECB /* ipp-support.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EE5133305BB00FCA411 /* ipp-support.c */; };
+ 274FF6A21333B1C400317ECB /* ipp.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EE6133305BB00FCA411 /* ipp.c */; };
+ 274FF6A31333B1C400317ECB /* langprintf.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EE8133305BB00FCA411 /* langprintf.c */; };
+ 274FF6A41333B1C400317ECB /* language.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EEA133305BB00FCA411 /* language.c */; };
+ 274FF6A51333B1C400317ECB /* localize.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EEC133305BB00FCA411 /* localize.c */; };
+ 274FF6A61333B1C400317ECB /* mark.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EED133305BB00FCA411 /* mark.c */; };
+ 274FF6A71333B1C400317ECB /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EEF133305BB00FCA411 /* md5.c */; };
+ 274FF6A81333B1C400317ECB /* md5passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EF0133305BB00FCA411 /* md5passwd.c */; };
+ 274FF6A91333B1C400317ECB /* notify.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EF1133305BB00FCA411 /* notify.c */; };
+ 274FF6AA1333B1C400317ECB /* options.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EF2133305BB00FCA411 /* options.c */; };
+ 274FF6AB1333B1C400317ECB /* page.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EF3133305BB00FCA411 /* page.c */; };
+ 274FF6AC1333B1C400317ECB /* ppd-cache.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EF4133305BB00FCA411 /* ppd-cache.c */; };
+ 274FF6AD1333B1C400317ECB /* ppd.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EF6133305BB00FCA411 /* ppd.c */; };
+ 274FF6AE1333B1C400317ECB /* pwg-media.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EF8133305BB00FCA411 /* pwg-media.c */; };
+ 274FF6AF1333B1C400317ECB /* request.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EFB133305BB00FCA411 /* request.c */; };
+ 274FF6B01333B1C400317ECB /* sidechannel.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EFC133305BB00FCA411 /* sidechannel.c */; };
+ 274FF6B11333B1C400317ECB /* snmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EFF133305BB00FCA411 /* snmp.c */; };
+ 274FF6B21333B1C400317ECB /* snprintf.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F00133305BB00FCA411 /* snprintf.c */; };
+ 274FF6B31333B1C400317ECB /* string.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F02133305BB00FCA411 /* string.c */; };
+ 274FF6B41333B1C400317ECB /* tempfile.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F03133305BB00FCA411 /* tempfile.c */; };
+ 274FF6B51333B1C400317ECB /* thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F05133305BB00FCA411 /* thread.c */; };
+ 274FF6B61333B1C400317ECB /* transcode.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F06133305BB00FCA411 /* transcode.c */; };
+ 274FF6B71333B1C400317ECB /* usersys.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F08133305BB00FCA411 /* usersys.c */; };
+ 274FF6B81333B1C400317ECB /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F09133305BB00FCA411 /* util.c */; };
+ 274FF6BA1333B1C400317ECB /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F49133306BB00FCA411 /* CoreFoundation.framework */; };
+ 274FF6BB1333B1C400317ECB /* Kerberos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F55133308EA00FCA411 /* Kerberos.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ 274FF6BC1333B1C400317ECB /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F4B133306BB00FCA411 /* Security.framework */; };
+ 274FF6BD1333B1C400317ECB /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F4C133306BB00FCA411 /* SystemConfiguration.framework */; };
+ 274FF6BE1333B1C400317ECB /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F51133308C100FCA411 /* libiconv.dylib */; };
+ 274FF6BF1333B1C400317ECB /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F53133308CB00FCA411 /* libresolv.dylib */; };
+ 274FF6C01333B1C400317ECB /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F4A133306BB00FCA411 /* libz.dylib */; };
+ 274FF6C21333B1C400317ECB /* adminutil.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EB71333056300FCA411 /* adminutil.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6C31333B1C400317ECB /* array.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EB91333056300FCA411 /* array.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6C41333B1C400317ECB /* backend.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EBE1333056300FCA411 /* backend.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6C51333B1C400317ECB /* cups.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EC11333056300FCA411 /* cups.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6C61333B1C400317ECB /* dir.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220ED4133305BB00FCA411 /* dir.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6C71333B1C400317ECB /* file.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220ED9133305BB00FCA411 /* file.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6C81333B1C400317ECB /* http.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EE3133305BB00FCA411 /* http.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6C91333B1C400317ECB /* ipp.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EE7133305BB00FCA411 /* ipp.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6CA1333B1C400317ECB /* language.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EEB133305BB00FCA411 /* language.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6CB1333B1C400317ECB /* ppd.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EF7133305BB00FCA411 /* ppd.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6CD1333B1C400317ECB /* sidechannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EFD133305BB00FCA411 /* sidechannel.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6CE1333B1C400317ECB /* transcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220F07133305BB00FCA411 /* transcode.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6CF1333B1C400317ECB /* versioning.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220F0A133305BB00FCA411 /* versioning.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6D01333B1C400317ECB /* cups-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EC01333056300FCA411 /* cups-private.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6D11333B1C400317ECB /* debug-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EC31333056300FCA411 /* debug-private.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6D21333B1C400317ECB /* file-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220ED7133305BB00FCA411 /* file-private.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6D31333B1C400317ECB /* http-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EE0133305BB00FCA411 /* http-private.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6D41333B1C400317ECB /* ipp-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EE4133305BB00FCA411 /* ipp-private.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6D51333B1C400317ECB /* language-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EE9133305BB00FCA411 /* language-private.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6D61333B1C400317ECB /* md5-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EEE133305BB00FCA411 /* md5-private.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6D71333B1C400317ECB /* ppd-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EF5133305BB00FCA411 /* ppd-private.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6D81333B1C400317ECB /* pwg-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EF9133305BB00FCA411 /* pwg-private.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6D91333B1C400317ECB /* snmp-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EFE133305BB00FCA411 /* snmp-private.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6DA1333B1C400317ECB /* string-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220F01133305BB00FCA411 /* string-private.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6DB1333B1C400317ECB /* thread-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220F04133305BB00FCA411 /* thread-private.h */; settings = {ATTRIBUTES = (); }; };
+ 274FF6DC1333B1C400317ECB /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220F471333063D00FCA411 /* config.h */; settings = {ATTRIBUTES = (); }; };
+ 276683671337A9E0000D33D0 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 276683691337AA00000D33D0 /* cupsctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 276683681337AA00000D33D0 /* cupsctl.c */; };
+ 276683B11337AD06000D33D0 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 276683B21337AD06000D33D0 /* libcupsppdc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 274FF5EE133330C800317ECB /* libcupsppdc.dylib */; };
+ 276683B71337AD23000D33D0 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 276683B81337AD23000D33D0 /* libcupsppdc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 274FF5EE133330C800317ECB /* libcupsppdc.dylib */; };
+ 276683B91337AD31000D33D0 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 276683BA1337AD31000D33D0 /* libcupsppdc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 274FF5EE133330C800317ECB /* libcupsppdc.dylib */; };
+ 276683C31337B1B3000D33D0 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 276683C41337B1B3000D33D0 /* libcupsppdc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 274FF5EE133330C800317ECB /* libcupsppdc.dylib */; };
+ 276683C91337B1C1000D33D0 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 276683CA1337B1C1000D33D0 /* libcupsppdc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 274FF5EE133330C800317ECB /* libcupsppdc.dylib */; };
+ 276683CD1337B201000D33D0 /* ppdc.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 276683CC1337B201000D33D0 /* ppdc.cxx */; };
+ 276683CF1337B20D000D33D0 /* ppdhtml.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 276683CE1337B20D000D33D0 /* ppdhtml.cxx */; };
+ 276683D11337B21A000D33D0 /* ppdi.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 276683D01337B21A000D33D0 /* ppdi.cxx */; };
+ 276683D31337B228000D33D0 /* ppdmerge.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 276683D21337B228000D33D0 /* ppdmerge.cxx */; };
+ 276683D51337B237000D33D0 /* ppdpo.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 276683D41337B237000D33D0 /* ppdpo.cxx */; };
+ 276683E21337B29C000D33D0 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 276683E51337B2BE000D33D0 /* libcupsimage.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72F75A611336F9A3004BB496 /* libcupsimage.dylib */; };
+ 276683FA1337F7A9000D33D0 /* ipptool.c in Sources */ = {isa = PBXBuildFile; fileRef = 276683F91337F7A9000D33D0 /* ipptool.c */; };
+ 276683FD1337F7B8000D33D0 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 2766840F1337FA38000D33D0 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 276684111337FA7C000D33D0 /* cupsaddsmb.c in Sources */ = {isa = PBXBuildFile; fileRef = 276684101337FA7C000D33D0 /* cupsaddsmb.c */; };
+ 278C58D9136B645C00836530 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72F75A4C1336F31B004BB496 /* libcups_static.a */; };
+ 278C58DE136B645C00836530 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 278C58DA136B645C00836530 /* CoreFoundation.framework */; };
+ 278C58DF136B645C00836530 /* Kerberos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 278C58DB136B645C00836530 /* Kerberos.framework */; };
+ 278C58E1136B645C00836530 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 278C58DD136B645C00836530 /* SystemConfiguration.framework */; };
+ 278C58E3136B647200836530 /* testhttp.c in Sources */ = {isa = PBXBuildFile; fileRef = 278C58E2136B647200836530 /* testhttp.c */; };
+ 278C58E4136B649200836530 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72F75A4C1336F31B004BB496 /* libcups_static.a */; };
+ 278C58E9136B64B000836530 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 278C58E5136B64AF00836530 /* CoreFoundation.framework */; };
+ 278C58EA136B64B000836530 /* Kerberos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 278C58E6136B64B000836530 /* Kerberos.framework */; };
+ 278C58EB136B64B000836530 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 278C58E7136B64B000836530 /* Security.framework */; };
+ 278C58EC136B64B000836530 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 278C58E8136B64B000836530 /* SystemConfiguration.framework */; };
+ 278C58F6136B652300836530 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 278C58F4136B652300836530 /* Security.framework */; };
+ 720DD6CD1358FD720064AA82 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 720DD6D31358FDDE0064AA82 /* snmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 720DD6D21358FDDE0064AA82 /* snmp.c */; };
+ 720DD6D413590AB90064AA82 /* ieee1284.c in Sources */ = {isa = PBXBuildFile; fileRef = 724379CA1334000E009631B9 /* ieee1284.c */; };
+ 72220EB61333052D00FCA411 /* adminutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EB51333052D00FCA411 /* adminutil.c */; };
+ 72220EC41333056300FCA411 /* adminutil.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EB71333056300FCA411 /* adminutil.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 72220EC51333056300FCA411 /* array.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EB81333056300FCA411 /* array.c */; };
+ 72220EC61333056300FCA411 /* array.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EB91333056300FCA411 /* array.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 72220EC71333056300FCA411 /* attr.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EBA1333056300FCA411 /* attr.c */; };
+ 72220EC81333056300FCA411 /* auth.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EBB1333056300FCA411 /* auth.c */; };
+ 72220EC91333056300FCA411 /* backchannel.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EBC1333056300FCA411 /* backchannel.c */; };
+ 72220ECA1333056300FCA411 /* backend.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EBD1333056300FCA411 /* backend.c */; };
+ 72220ECB1333056300FCA411 /* backend.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EBE1333056300FCA411 /* backend.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 72220ECC1333056300FCA411 /* conflicts.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EBF1333056300FCA411 /* conflicts.c */; };
+ 72220ECD1333056300FCA411 /* cups-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EC01333056300FCA411 /* cups-private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 72220ECE1333056300FCA411 /* cups.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EC11333056300FCA411 /* cups.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 72220ECF1333056300FCA411 /* custom.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EC21333056300FCA411 /* custom.c */; };
+ 72220ED01333056300FCA411 /* debug-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EC31333056300FCA411 /* debug-private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 72220F0B133305BB00FCA411 /* debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220ED1133305BB00FCA411 /* debug.c */; };
+ 72220F0C133305BB00FCA411 /* dest.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220ED2133305BB00FCA411 /* dest.c */; };
+ 72220F0D133305BB00FCA411 /* dir.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220ED3133305BB00FCA411 /* dir.c */; };
+ 72220F0E133305BB00FCA411 /* dir.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220ED4133305BB00FCA411 /* dir.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 72220F0F133305BB00FCA411 /* emit.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220ED5133305BB00FCA411 /* emit.c */; };
+ 72220F10133305BB00FCA411 /* encode.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220ED6133305BB00FCA411 /* encode.c */; };
+ 72220F11133305BB00FCA411 /* file-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220ED7133305BB00FCA411 /* file-private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 72220F12133305BB00FCA411 /* file.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220ED8133305BB00FCA411 /* file.c */; };
+ 72220F13133305BB00FCA411 /* file.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220ED9133305BB00FCA411 /* file.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 72220F14133305BB00FCA411 /* getdevices.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EDA133305BB00FCA411 /* getdevices.c */; };
+ 72220F15133305BB00FCA411 /* getifaddrs.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EDB133305BB00FCA411 /* getifaddrs.c */; };
+ 72220F16133305BB00FCA411 /* getputfile.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EDC133305BB00FCA411 /* getputfile.c */; };
+ 72220F17133305BB00FCA411 /* globals.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EDD133305BB00FCA411 /* globals.c */; };
+ 72220F18133305BB00FCA411 /* http-addr.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EDE133305BB00FCA411 /* http-addr.c */; };
+ 72220F19133305BB00FCA411 /* http-addrlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EDF133305BB00FCA411 /* http-addrlist.c */; };
+ 72220F1A133305BB00FCA411 /* http-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EE0133305BB00FCA411 /* http-private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 72220F1B133305BB00FCA411 /* http-support.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EE1133305BB00FCA411 /* http-support.c */; };
+ 72220F1C133305BB00FCA411 /* http.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EE2133305BB00FCA411 /* http.c */; };
+ 72220F1D133305BB00FCA411 /* http.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EE3133305BB00FCA411 /* http.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 72220F1E133305BB00FCA411 /* ipp-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EE4133305BB00FCA411 /* ipp-private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 72220F1F133305BB00FCA411 /* ipp-support.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EE5133305BB00FCA411 /* ipp-support.c */; };
+ 72220F20133305BB00FCA411 /* ipp.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EE6133305BB00FCA411 /* ipp.c */; };
+ 72220F21133305BB00FCA411 /* ipp.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EE7133305BB00FCA411 /* ipp.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 72220F22133305BB00FCA411 /* langprintf.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EE8133305BB00FCA411 /* langprintf.c */; };
+ 72220F23133305BB00FCA411 /* language-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EE9133305BB00FCA411 /* language-private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 72220F24133305BB00FCA411 /* language.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EEA133305BB00FCA411 /* language.c */; };
+ 72220F25133305BB00FCA411 /* language.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EEB133305BB00FCA411 /* language.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 72220F26133305BB00FCA411 /* localize.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EEC133305BB00FCA411 /* localize.c */; };
+ 72220F27133305BB00FCA411 /* mark.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EED133305BB00FCA411 /* mark.c */; };
+ 72220F28133305BB00FCA411 /* md5-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EEE133305BB00FCA411 /* md5-private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 72220F29133305BB00FCA411 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EEF133305BB00FCA411 /* md5.c */; };
+ 72220F2A133305BB00FCA411 /* md5passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EF0133305BB00FCA411 /* md5passwd.c */; };
+ 72220F2B133305BB00FCA411 /* notify.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EF1133305BB00FCA411 /* notify.c */; };
+ 72220F2C133305BB00FCA411 /* options.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EF2133305BB00FCA411 /* options.c */; };
+ 72220F2D133305BB00FCA411 /* page.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EF3133305BB00FCA411 /* page.c */; };
+ 72220F2E133305BB00FCA411 /* ppd-cache.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EF4133305BB00FCA411 /* ppd-cache.c */; };
+ 72220F2F133305BB00FCA411 /* ppd-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EF5133305BB00FCA411 /* ppd-private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 72220F30133305BB00FCA411 /* ppd.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EF6133305BB00FCA411 /* ppd.c */; };
+ 72220F31133305BB00FCA411 /* ppd.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EF7133305BB00FCA411 /* ppd.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 72220F32133305BB00FCA411 /* pwg-media.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EF8133305BB00FCA411 /* pwg-media.c */; };
+ 72220F33133305BB00FCA411 /* pwg-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EF9133305BB00FCA411 /* pwg-private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 72220F35133305BB00FCA411 /* request.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EFB133305BB00FCA411 /* request.c */; };
+ 72220F36133305BB00FCA411 /* sidechannel.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EFC133305BB00FCA411 /* sidechannel.c */; };
+ 72220F37133305BB00FCA411 /* sidechannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EFD133305BB00FCA411 /* sidechannel.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 72220F38133305BB00FCA411 /* snmp-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EFE133305BB00FCA411 /* snmp-private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 72220F39133305BB00FCA411 /* snmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EFF133305BB00FCA411 /* snmp.c */; };
+ 72220F3A133305BB00FCA411 /* snprintf.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F00133305BB00FCA411 /* snprintf.c */; };
+ 72220F3B133305BB00FCA411 /* string-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220F01133305BB00FCA411 /* string-private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 72220F3C133305BB00FCA411 /* string.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F02133305BB00FCA411 /* string.c */; };
+ 72220F3D133305BB00FCA411 /* tempfile.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F03133305BB00FCA411 /* tempfile.c */; };
+ 72220F3E133305BB00FCA411 /* thread-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220F04133305BB00FCA411 /* thread-private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 72220F3F133305BB00FCA411 /* thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F05133305BB00FCA411 /* thread.c */; };
+ 72220F40133305BB00FCA411 /* transcode.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F06133305BB00FCA411 /* transcode.c */; };
+ 72220F41133305BB00FCA411 /* transcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220F07133305BB00FCA411 /* transcode.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 72220F42133305BB00FCA411 /* usersys.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F08133305BB00FCA411 /* usersys.c */; };
+ 72220F43133305BB00FCA411 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F09133305BB00FCA411 /* util.c */; };
+ 72220F44133305BB00FCA411 /* versioning.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220F0A133305BB00FCA411 /* versioning.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 72220F481333063D00FCA411 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220F471333063D00FCA411 /* config.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 72220F4D133306BB00FCA411 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F49133306BB00FCA411 /* CoreFoundation.framework */; };
+ 72220F4E133306BB00FCA411 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F4A133306BB00FCA411 /* libz.dylib */; };
+ 72220F4F133306BB00FCA411 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F4B133306BB00FCA411 /* Security.framework */; };
+ 72220F50133306BB00FCA411 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F4C133306BB00FCA411 /* SystemConfiguration.framework */; };
+ 72220F52133308C100FCA411 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F51133308C100FCA411 /* libiconv.dylib */; };
+ 72220F54133308CB00FCA411 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F53133308CB00FCA411 /* libresolv.dylib */; };
+ 72220F56133308EA00FCA411 /* Kerberos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F55133308EA00FCA411 /* Kerberos.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ 72220F6613330A7000FCA411 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 72220F6813330A8500FCA411 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F6713330A8500FCA411 /* ApplicationServices.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ 72220F9013330B0C00FCA411 /* auth.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F6913330B0C00FCA411 /* auth.c */; };
+ 72220F9113330B0C00FCA411 /* banners.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F6B13330B0C00FCA411 /* banners.c */; };
+ 72220F9213330B0C00FCA411 /* cert.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F6D13330B0C00FCA411 /* cert.c */; };
+ 72220F9313330B0C00FCA411 /* classes.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F6F13330B0C00FCA411 /* classes.c */; };
+ 72220F9413330B0C00FCA411 /* client.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F7113330B0C00FCA411 /* client.c */; };
+ 72220F9513330B0C00FCA411 /* conf.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F7313330B0C00FCA411 /* conf.c */; };
+ 72220F9613330B0C00FCA411 /* dirsvc.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F7613330B0C00FCA411 /* dirsvc.c */; };
+ 72220F9713330B0C00FCA411 /* env.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F7813330B0C00FCA411 /* env.c */; };
+ 72220F9813330B0C00FCA411 /* ipp.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F7913330B0C00FCA411 /* ipp.c */; };
+ 72220F9913330B0C00FCA411 /* job.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F7A13330B0C00FCA411 /* job.c */; };
+ 72220F9A13330B0C00FCA411 /* listen.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F7C13330B0C00FCA411 /* listen.c */; };
+ 72220F9B13330B0C00FCA411 /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F7D13330B0C00FCA411 /* log.c */; };
+ 72220F9C13330B0C00FCA411 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F7E13330B0C00FCA411 /* main.c */; };
+ 72220F9D13330B0C00FCA411 /* network.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F7F13330B0C00FCA411 /* network.c */; };
+ 72220F9E13330B0C00FCA411 /* policy.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F8113330B0C00FCA411 /* policy.c */; };
+ 72220F9F13330B0C00FCA411 /* printers.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F8313330B0C00FCA411 /* printers.c */; };
+ 72220FA013330B0C00FCA411 /* process.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F8513330B0C00FCA411 /* process.c */; };
+ 72220FA113330B0C00FCA411 /* quotas.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F8613330B0C00FCA411 /* quotas.c */; };
+ 72220FA313330B0C00FCA411 /* select.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F8813330B0C00FCA411 /* select.c */; };
+ 72220FA413330B0C00FCA411 /* server.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F8913330B0C00FCA411 /* server.c */; };
+ 72220FA513330B0C00FCA411 /* statbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F8A13330B0C00FCA411 /* statbuf.c */; };
+ 72220FA613330B0C00FCA411 /* subscriptions.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F8C13330B0C00FCA411 /* subscriptions.c */; };
+ 72220FA713330B0C00FCA411 /* sysman.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F8E13330B0C00FCA411 /* sysman.c */; };
+ 72220FB613330BCE00FCA411 /* filter.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220FB213330BCE00FCA411 /* filter.c */; };
+ 72220FB713330BCE00FCA411 /* mime.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220FB313330BCE00FCA411 /* mime.c */; };
+ 72220FB813330BCE00FCA411 /* mime.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220FB413330BCE00FCA411 /* mime.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 72220FB913330BCE00FCA411 /* type.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220FB513330BCE00FCA411 /* type.c */; };
+ 72220FBA13330BEE00FCA411 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 72220FBF13330C1000FCA411 /* libcupsmime.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220FAC13330B2200FCA411 /* libcupsmime.dylib */; };
+ 7234F4201378A16F00D3E9C9 /* array-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 7234F41F1378A16F00D3E9C9 /* array-private.h */; };
+ 724379081333E4A5009631B9 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 7243790D1333E4E3009631B9 /* ipp.c in Sources */ = {isa = PBXBuildFile; fileRef = 7243790A1333E4E3009631B9 /* ipp.c */; };
+ 7243790E1333E4E3009631B9 /* network.c in Sources */ = {isa = PBXBuildFile; fileRef = 7243790B1333E4E3009631B9 /* network.c */; };
+ 7243790F1333E4E3009631B9 /* snmp-supplies.c in Sources */ = {isa = PBXBuildFile; fileRef = 7243790C1333E4E3009631B9 /* snmp-supplies.c */; };
+ 724379131333E516009631B9 /* runloop.c in Sources */ = {isa = PBXBuildFile; fileRef = 724379121333E516009631B9 /* runloop.c */; };
+ 724379221333E928009631B9 /* network.c in Sources */ = {isa = PBXBuildFile; fileRef = 7243790B1333E4E3009631B9 /* network.c */; };
+ 724379231333E928009631B9 /* runloop.c in Sources */ = {isa = PBXBuildFile; fileRef = 724379121333E516009631B9 /* runloop.c */; };
+ 724379241333E928009631B9 /* snmp-supplies.c in Sources */ = {isa = PBXBuildFile; fileRef = 7243790C1333E4E3009631B9 /* snmp-supplies.c */; };
+ 724379271333E93D009631B9 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 724379291333E952009631B9 /* lpd.c in Sources */ = {isa = PBXBuildFile; fileRef = 724379281333E952009631B9 /* lpd.c */; };
+ 7243793B1333FB9D009631B9 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 7243793D1333FD19009631B9 /* socket.c in Sources */ = {isa = PBXBuildFile; fileRef = 7243793C1333FD19009631B9 /* socket.c */; };
+ 724379401333FD4B009631B9 /* network.c in Sources */ = {isa = PBXBuildFile; fileRef = 7243790B1333E4E3009631B9 /* network.c */; };
+ 724379411333FD4B009631B9 /* runloop.c in Sources */ = {isa = PBXBuildFile; fileRef = 724379121333E516009631B9 /* runloop.c */; };
+ 724379421333FD4B009631B9 /* snmp-supplies.c in Sources */ = {isa = PBXBuildFile; fileRef = 7243790C1333E4E3009631B9 /* snmp-supplies.c */; };
+ 724379511333FEBB009631B9 /* dnssd.c in Sources */ = {isa = PBXBuildFile; fileRef = 724379501333FEBB009631B9 /* dnssd.c */; };
+ 724379561333FF04009631B9 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 724379661333FF3B009631B9 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 724379681333FF3B009631B9 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 724379671333FF3B009631B9 /* IOKit.framework */; };
+ 724379C71333FFC7009631B9 /* usb.c in Sources */ = {isa = PBXBuildFile; fileRef = 724379C51333FFC7009631B9 /* usb.c */; };
+ 724379C91333FFF3009631B9 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 724379C81333FFF3009631B9 /* CoreFoundation.framework */; };
+ 724379CB1334000E009631B9 /* ieee1284.c in Sources */ = {isa = PBXBuildFile; fileRef = 724379CA1334000E009631B9 /* ieee1284.c */; };
+ 7258EAED134594EB009286F1 /* rastertopwg.c in Sources */ = {isa = PBXBuildFile; fileRef = 7258EAEC134594EB009286F1 /* rastertopwg.c */; };
+ 7258EAF413459B6D009286F1 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 7258EAF513459B6D009286F1 /* libcupsimage.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72F75A611336F9A3004BB496 /* libcupsimage.dylib */; };
+ 7263EE2713330D2800BA4D44 /* libpam.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7263EE2613330D2800BA4D44 /* libpam.dylib */; };
+ 7263EE2C13330D5C00BA4D44 /* Kerberos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7263EE2913330D5C00BA4D44 /* Kerberos.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ 7263EE2D13330D5C00BA4D44 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7263EE2A13330D5C00BA4D44 /* Security.framework */; };
+ 7263EE2E13330D5C00BA4D44 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7263EE2B13330D5C00BA4D44 /* SystemConfiguration.framework */; };
+ 7263EE3013330DC100BA4D44 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7263EE2F13330DC100BA4D44 /* IOKit.framework */; };
+ 7263EE3213330E1E00BA4D44 /* libpthread.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7263EE3113330E1E00BA4D44 /* libpthread.dylib */; };
+ 7263EE3413330E3C00BA4D44 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7263EE3313330E3C00BA4D44 /* libresolv.dylib */; };
+ 7263EE3613330E4E00BA4D44 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7263EE3513330E4E00BA4D44 /* CoreFoundation.framework */; };
+ 7263EE3813330E7500BA4D44 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7263EE3713330E7500BA4D44 /* libz.dylib */; };
+ 7263EE3A13330EC500BA4D44 /* libldap.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7263EE3913330EC500BA4D44 /* libldap.dylib */; };
+ 726AD702135E8A90002C930D /* ippserver.c in Sources */ = {isa = PBXBuildFile; fileRef = 726AD701135E8A90002C930D /* ippserver.c */; };
+ 726AD707135E8B11002C930D /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72F75A4C1336F31B004BB496 /* libcups_static.a */; };
+ 726AD708135E8B11002C930D /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F49133306BB00FCA411 /* CoreFoundation.framework */; };
+ 726AD709135E8B11002C930D /* Kerberos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F55133308EA00FCA411 /* Kerberos.framework */; };
+ 726AD70A135E8B11002C930D /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F53133308CB00FCA411 /* libresolv.dylib */; };
+ 726AD70B135E8B11002C930D /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F4A133306BB00FCA411 /* libz.dylib */; };
+ 726AD70C135E8B11002C930D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F4B133306BB00FCA411 /* Security.framework */; };
+ 726AD70D135E8B11002C930D /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F4C133306BB00FCA411 /* SystemConfiguration.framework */; };
+ 726AD70E135E8B5E002C930D /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220F51133308C100FCA411 /* libiconv.dylib */; };
+ 7271883D1374AB14001A2036 /* mime-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 7271883C1374AB14001A2036 /* mime-private.h */; };
+ 72C16CB9137B195D007E4BF4 /* file.c in Sources */ = {isa = PBXBuildFile; fileRef = 72C16CB8137B195D007E4BF4 /* file.c */; };
+ 72F75A5C1336F988004BB496 /* cupstestppd.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F75A5B1336F988004BB496 /* cupstestppd.c */; };
+ 72F75A671336FA38004BB496 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; };
+ 72F75A6C1336FA8A004BB496 /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F75A691336FA8A004BB496 /* error.c */; };
+ 72F75A6D1336FA8A004BB496 /* interpret.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F75A6A1336FA8A004BB496 /* interpret.c */; };
+ 72F75A6E1336FA8A004BB496 /* raster.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F75A6B1336FA8A004BB496 /* raster.c */; };
+ 72F75A6F1336FAB6004BB496 /* raster.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220EFA133305BB00FCA411 /* raster.h */; settings = {ATTRIBUTES = (Public, ); }; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 270CCDB1135E3CDE00007BE2 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 270CCDA6135E3C9E00007BE2;
+ remoteInfo = testmime;
+ };
+ 270CCDB5135E3CF700007BE2 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220FAB13330B2200FCA411;
+ remoteInfo = libcupsmime;
+ };
+ 270CCDB7135E3CFD00007BE2 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF6891333B1C400317ECB;
+ remoteInfo = libcups_static;
+ };
+ 273BF6C81333B5410022CAAB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF6891333B1C400317ECB;
+ remoteInfo = libcups_static;
+ };
+ 273BF6DD1333B6370022CAAB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 273BF6BC1333B5000022CAAB;
+ remoteInfo = testcups;
+ };
+ 274FF5DB13332CF900317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 274FF5E213332D4300317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 274FF5E413332D4300317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220FAB13330B2200FCA411;
+ remoteInfo = libcupsmime;
+ };
+ 274FF5E613332D4300317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220F5A13330A5A00FCA411;
+ remoteInfo = cupsd;
+ };
+ 274FF5E813332D4300317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF5CB13332B1F00317ECB;
+ remoteInfo = "cups-driverd";
+ };
+ 274FF5F2133330FD00317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 274FF61F1333316200317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF5ED133330C800317ECB;
+ remoteInfo = libcupsppdc;
+ };
+ 274FF621133331D300317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF5ED133330C800317ECB;
+ remoteInfo = libcupsppdc;
+ };
+ 274FF6331333335200317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 274FF6381333348400317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF6281333333600317ECB;
+ remoteInfo = "cups-deviced";
+ };
+ 274FF647133335A300317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF63D1333358B00317ECB;
+ remoteInfo = "cups-exec";
+ };
+ 274FF659133339D900317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 274FF65D13333A3400317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF64E133339C400317ECB;
+ remoteInfo = "cups-lpd";
+ };
+ 274FF66C13333AAD00317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 274FF67113333AE400317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF66213333A9B00317ECB;
+ remoteInfo = "cups-polld";
+ };
+ 274FF68113333B3C00317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 274FF68313333B3C00317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220FAB13330B2200FCA411;
+ remoteInfo = libcupsmime;
+ };
+ 274FF6E11333B33F00317ECB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF67713333B2F00317ECB;
+ remoteInfo = cupsfilter;
+ };
+ 276683651337A9D6000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 2766836A1337AA25000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2766835B1337A9B6000D33D0;
+ remoteInfo = cupsctl;
+ };
+ 276683AD1337ACF9000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 276683AF1337ACF9000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF5ED133330C800317ECB;
+ remoteInfo = libcupsppdc;
+ };
+ 276683B31337AD18000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 276683B51337AD18000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF5ED133330C800317ECB;
+ remoteInfo = libcupsppdc;
+ };
+ 276683BB1337AE49000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 276683BD1337AE49000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF5ED133330C800317ECB;
+ remoteInfo = libcupsppdc;
+ };
+ 276683BF1337B1AD000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 276683C11337B1AD000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF5ED133330C800317ECB;
+ remoteInfo = libcupsppdc;
+ };
+ 276683C51337B1BC000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 276683C71337B1BC000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF5ED133330C800317ECB;
+ remoteInfo = libcupsppdc;
+ };
+ 276683D61337B24A000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2766836F1337AC79000D33D0;
+ remoteInfo = ppdc;
+ };
+ 276683D81337B24A000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2766837C1337AC8C000D33D0;
+ remoteInfo = ppdhtml;
+ };
+ 276683DA1337B24A000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 276683891337AC97000D33D0;
+ remoteInfo = ppdi;
+ };
+ 276683DC1337B24A000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 276683961337ACA2000D33D0;
+ remoteInfo = ppdmerge;
+ };
+ 276683DE1337B24A000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 276683A31337ACAB000D33D0;
+ remoteInfo = ppdpo;
+ };
+ 276683E01337B299000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 276683E31337B2BA000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72F75A601336F9A3004BB496;
+ remoteInfo = libcupsimage;
+ };
+ 276683FB1337F7B3000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 276683FE1337F7C5000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 276683EF1337F78E000D33D0;
+ remoteInfo = ipptool;
+ };
+ 2766840D1337FA31000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 276684121337FA8D000D33D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 276684031337FA1D000D33D0;
+ remoteInfo = cupsaddsmb;
+ };
+ 278C58D5136B641D00836530 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 278C58CA136B640300836530;
+ remoteInfo = testhttp;
+ };
+ 278C58D7136B642F00836530 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF6891333B1C400317ECB;
+ remoteInfo = libcups_static;
+ };
+ 720DD6CE1358FD790064AA82 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 720DD6D01358FDBE0064AA82 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 720DD6C11358FD5F0064AA82;
+ remoteInfo = snmp;
+ };
+ 72220F6413330A6500FCA411 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 72220FBB13330C0500FCA411 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 72220FBD13330C0B00FCA411 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220FAB13330B2200FCA411;
+ remoteInfo = libcupsmime;
+ };
+ 724379061333E49B009631B9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 724379101333E4EA009631B9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 724378FC1333E43E009631B9;
+ remoteInfo = ipp;
+ };
+ 724379251333E932009631B9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 7243792A1333E962009631B9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 724379171333E532009631B9;
+ remoteInfo = lpd;
+ };
+ 724379391333FB95009631B9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 7243793E1333FD23009631B9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7243792F1333FB85009631B9;
+ remoteInfo = socket;
+ };
+ 724379521333FECE009631B9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 724379461333FEA9009631B9;
+ remoteInfo = dnssd;
+ };
+ 724379541333FEFE009631B9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 724379641333FF2E009631B9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 724379C21333FF7D009631B9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7243795A1333FF1D009631B9;
+ remoteInfo = usb;
+ };
+ 7258EAEE13459ADA009286F1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7258EAE1134594C4009286F1;
+ remoteInfo = rastertopwg;
+ };
+ 7258EAF013459B67009286F1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 7258EAF213459B67009286F1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72F75A601336F9A3004BB496;
+ remoteInfo = libcupsimage;
+ };
+ 726AD703135E8AA1002C930D /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 726AD6F6135E88F0002C930D;
+ remoteInfo = ippserver;
+ };
+ 726AD705135E8AC5002C930D /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 274FF6891333B1C400317ECB;
+ remoteInfo = libcups_static;
+ };
+ 72F75A651336FA30004BB496 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72220EAD1333047D00FCA411;
+ remoteInfo = libcups;
+ };
+ 72F75A701336FACD004BB496 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72F75A601336F9A3004BB496;
+ remoteInfo = libcupsimage;
+ };
+ 72F75A721336FACD004BB496 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 72BF96371333042100B1EAD7 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72F75A511336F950004BB496;
+ remoteInfo = cupstestppd;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 270CCDA5135E3C9E00007BE2 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 273BF6BB1333B5000022CAAB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 274FF5CA13332B1F00317ECB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 274FF6271333333600317ECB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 274FF63C1333358B00317ECB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 274FF64D133339C400317ECB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 274FF66113333A9B00317ECB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 274FF67613333B2F00317ECB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 2766835A1337A9B6000D33D0 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 2766836E1337AC79000D33D0 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 2766837B1337AC8C000D33D0 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 276683881337AC97000D33D0 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 276683951337ACA2000D33D0 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 276683A21337ACAB000D33D0 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 276683EE1337F78E000D33D0 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 276684021337FA1D000D33D0 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 278C58C9136B640300836530 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 720DD6C01358FD5F0064AA82 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 72220F5913330A5A00FCA411 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 724378FB1333E43E009631B9 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 724379161333E532009631B9 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7243792E1333FB85009631B9 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 724379451333FEA9009631B9 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 724379591333FF1D009631B9 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7258EAE0134594C4009286F1 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 726AD6F5135E88F0002C930D /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 72F75A501336F950004BB496 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 270CCDA7135E3C9E00007BE2 /* testmime */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testmime; sourceTree = BUILT_PRODUCTS_DIR; };
+ 270CCDBB135E3D3E00007BE2 /* testmime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = testmime.c; path = ../scheduler/testmime.c; sourceTree = "<group>"; };
+ 2732E089137A3F5200FAFEF6 /* cancel.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cancel.c; path = ../systemv/cancel.c; sourceTree = "<group>"; };
+ 2732E08A137A3F5200FAFEF6 /* cupsaccept.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cupsaccept.c; path = ../systemv/cupsaccept.c; sourceTree = "<group>"; };
+ 2732E08B137A3F5200FAFEF6 /* cupstestdsc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cupstestdsc.c; path = ../systemv/cupstestdsc.c; sourceTree = "<group>"; };
+ 2732E08C137A3F5200FAFEF6 /* lp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lp.c; path = ../systemv/lp.c; sourceTree = "<group>"; };
+ 2732E08D137A3F5200FAFEF6 /* lpadmin.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lpadmin.c; path = ../systemv/lpadmin.c; sourceTree = "<group>"; };
+ 2732E08E137A3F5200FAFEF6 /* lpinfo.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lpinfo.c; path = ../systemv/lpinfo.c; sourceTree = "<group>"; };
+ 2732E08F137A3F5200FAFEF6 /* lpmove.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lpmove.c; path = ../systemv/lpmove.c; sourceTree = "<group>"; };
+ 2732E090137A3F5200FAFEF6 /* lpoptions.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lpoptions.c; path = ../systemv/lpoptions.c; sourceTree = "<group>"; };
+ 2732E091137A3F5200FAFEF6 /* lppasswd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lppasswd.c; path = ../systemv/lppasswd.c; sourceTree = "<group>"; };
+ 2732E092137A3F5200FAFEF6 /* lpstat.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lpstat.c; path = ../systemv/lpstat.c; sourceTree = "<group>"; };
+ 273BF6BD1333B5000022CAAB /* testcups */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testcups; sourceTree = BUILT_PRODUCTS_DIR; };
+ 273BF6C61333B5370022CAAB /* testcups.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = testcups.c; path = ../cups/testcups.c; sourceTree = "<group>"; };
+ 273BF6CB1333B5950022CAAB /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; };
+ 273BF6CC1333B5950022CAAB /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = SDKs/MacOSX10.6.sdk/usr/lib/libiconv.dylib; sourceTree = DEVELOPER_DIR; };
+ 273BF6CD1333B5950022CAAB /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = SDKs/MacOSX10.6.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
+ 273BF6D11333B5C30022CAAB /* Kerberos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kerberos.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Kerberos.framework; sourceTree = DEVELOPER_DIR; };
+ 273BF6D21333B5C30022CAAB /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; };
+ 273BF6D51333B5F60022CAAB /* libresolv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libresolv.dylib; path = SDKs/MacOSX10.6.sdk/usr/lib/libresolv.dylib; sourceTree = DEVELOPER_DIR; };
+ 273BF6D61333B5F60022CAAB /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; };
+ 274FF5CC13332B1F00317ECB /* cups-driverd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "cups-driverd"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 274FF5D613332CC700317ECB /* cups-driverd.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "cups-driverd.cxx"; path = "../scheduler/cups-driverd.cxx"; sourceTree = "<group>"; };
+ 274FF5D713332CC700317ECB /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = util.c; path = ../scheduler/util.c; sourceTree = "<group>"; };
+ 274FF5D813332CC700317ECB /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = util.h; path = ../scheduler/util.h; sourceTree = "<group>"; };
+ 274FF5EE133330C800317ECB /* libcupsppdc.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libcupsppdc.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+ 274FF5F51333315100317ECB /* ppdc-array.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-array.cxx"; path = "../ppdc/ppdc-array.cxx"; sourceTree = "<group>"; };
+ 274FF5F61333315100317ECB /* ppdc-attr.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-attr.cxx"; path = "../ppdc/ppdc-attr.cxx"; sourceTree = "<group>"; };
+ 274FF5F71333315100317ECB /* ppdc-catalog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-catalog.cxx"; path = "../ppdc/ppdc-catalog.cxx"; sourceTree = "<group>"; };
+ 274FF5F81333315100317ECB /* ppdc-choice.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-choice.cxx"; path = "../ppdc/ppdc-choice.cxx"; sourceTree = "<group>"; };
+ 274FF5F91333315100317ECB /* ppdc-constraint.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-constraint.cxx"; path = "../ppdc/ppdc-constraint.cxx"; sourceTree = "<group>"; };
+ 274FF5FA1333315100317ECB /* ppdc-driver.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-driver.cxx"; path = "../ppdc/ppdc-driver.cxx"; sourceTree = "<group>"; };
+ 274FF5FB1333315100317ECB /* ppdc-file.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-file.cxx"; path = "../ppdc/ppdc-file.cxx"; sourceTree = "<group>"; };
+ 274FF5FC1333315100317ECB /* ppdc-filter.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-filter.cxx"; path = "../ppdc/ppdc-filter.cxx"; sourceTree = "<group>"; };
+ 274FF5FD1333315100317ECB /* ppdc-font.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-font.cxx"; path = "../ppdc/ppdc-font.cxx"; sourceTree = "<group>"; };
+ 274FF5FE1333315100317ECB /* ppdc-group.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-group.cxx"; path = "../ppdc/ppdc-group.cxx"; sourceTree = "<group>"; };
+ 274FF5FF1333315100317ECB /* ppdc-import.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-import.cxx"; path = "../ppdc/ppdc-import.cxx"; sourceTree = "<group>"; };
+ 274FF6001333315100317ECB /* ppdc-mediasize.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-mediasize.cxx"; path = "../ppdc/ppdc-mediasize.cxx"; sourceTree = "<group>"; };
+ 274FF6011333315100317ECB /* ppdc-message.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-message.cxx"; path = "../ppdc/ppdc-message.cxx"; sourceTree = "<group>"; };
+ 274FF6021333315100317ECB /* ppdc-option.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-option.cxx"; path = "../ppdc/ppdc-option.cxx"; sourceTree = "<group>"; };
+ 274FF6031333315100317ECB /* ppdc-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "ppdc-private.h"; path = "../ppdc/ppdc-private.h"; sourceTree = "<group>"; };
+ 274FF6041333315100317ECB /* ppdc-profile.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-profile.cxx"; path = "../ppdc/ppdc-profile.cxx"; sourceTree = "<group>"; };
+ 274FF6051333315100317ECB /* ppdc-shared.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-shared.cxx"; path = "../ppdc/ppdc-shared.cxx"; sourceTree = "<group>"; };
+ 274FF6061333315100317ECB /* ppdc-source.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-source.cxx"; path = "../ppdc/ppdc-source.cxx"; sourceTree = "<group>"; };
+ 274FF6071333315100317ECB /* ppdc-string.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-string.cxx"; path = "../ppdc/ppdc-string.cxx"; sourceTree = "<group>"; };
+ 274FF6081333315100317ECB /* ppdc-variable.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ppdc-variable.cxx"; path = "../ppdc/ppdc-variable.cxx"; sourceTree = "<group>"; };
+ 274FF6091333315100317ECB /* ppdc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ppdc.h; path = ../ppdc/ppdc.h; sourceTree = "<group>"; };
+ 274FF6291333333600317ECB /* cups-deviced */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "cups-deviced"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 274FF6351333344400317ECB /* cups-deviced.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "cups-deviced.c"; path = "../scheduler/cups-deviced.c"; sourceTree = "<group>"; };
+ 274FF63E1333358B00317ECB /* cups-exec */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "cups-exec"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 274FF6491333398D00317ECB /* cups-exec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "cups-exec.c"; path = "../scheduler/cups-exec.c"; sourceTree = "<group>"; };
+ 274FF64F133339C400317ECB /* cups-lpd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "cups-lpd"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 274FF65B133339FC00317ECB /* cups-lpd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "cups-lpd.c"; path = "../scheduler/cups-lpd.c"; sourceTree = "<group>"; };
+ 274FF66313333A9B00317ECB /* cups-polld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "cups-polld"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 274FF66F13333ACF00317ECB /* cups-polld.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "cups-polld.c"; path = "../scheduler/cups-polld.c"; sourceTree = "<group>"; };
+ 274FF67813333B2F00317ECB /* cupsfilter */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cupsfilter; sourceTree = BUILT_PRODUCTS_DIR; };
+ 274FF68713333B6E00317ECB /* cupsfilter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cupsfilter.c; path = ../scheduler/cupsfilter.c; sourceTree = "<group>"; };
+ 276683561337A8C5000D33D0 /* cups.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = cups.strings; path = ../locale/cups.strings; sourceTree = "<group>"; };
+ 2766835C1337A9B6000D33D0 /* cupsctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cupsctl; sourceTree = BUILT_PRODUCTS_DIR; };
+ 276683681337AA00000D33D0 /* cupsctl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cupsctl.c; path = ../systemv/cupsctl.c; sourceTree = "<group>"; };
+ 276683701337AC79000D33D0 /* ppdc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ppdc; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2766837D1337AC8C000D33D0 /* ppdhtml */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ppdhtml; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2766838A1337AC97000D33D0 /* ppdi */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ppdi; sourceTree = BUILT_PRODUCTS_DIR; };
+ 276683971337ACA2000D33D0 /* ppdmerge */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ppdmerge; sourceTree = BUILT_PRODUCTS_DIR; };
+ 276683A41337ACAB000D33D0 /* ppdpo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ppdpo; sourceTree = BUILT_PRODUCTS_DIR; };
+ 276683CC1337B201000D33D0 /* ppdc.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ppdc.cxx; path = ../ppdc/ppdc.cxx; sourceTree = "<group>"; };
+ 276683CE1337B20D000D33D0 /* ppdhtml.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ppdhtml.cxx; path = ../ppdc/ppdhtml.cxx; sourceTree = "<group>"; };
+ 276683D01337B21A000D33D0 /* ppdi.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ppdi.cxx; path = ../ppdc/ppdi.cxx; sourceTree = "<group>"; };
+ 276683D21337B228000D33D0 /* ppdmerge.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ppdmerge.cxx; path = ../ppdc/ppdmerge.cxx; sourceTree = "<group>"; };
+ 276683D41337B237000D33D0 /* ppdpo.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ppdpo.cxx; path = ../ppdc/ppdpo.cxx; sourceTree = "<group>"; };
+ 276683F01337F78E000D33D0 /* ipptool */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ipptool; sourceTree = BUILT_PRODUCTS_DIR; };
+ 276683F91337F7A9000D33D0 /* ipptool.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ipptool.c; path = ../test/ipptool.c; sourceTree = "<group>"; };
+ 276684041337FA1D000D33D0 /* cupsaddsmb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cupsaddsmb; sourceTree = BUILT_PRODUCTS_DIR; };
+ 276684101337FA7C000D33D0 /* cupsaddsmb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cupsaddsmb.c; path = ../systemv/cupsaddsmb.c; sourceTree = "<group>"; };
+ 278C58CB136B640300836530 /* testhttp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testhttp; sourceTree = BUILT_PRODUCTS_DIR; };
+ 278C58DA136B645C00836530 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; };
+ 278C58DB136B645C00836530 /* Kerberos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kerberos.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Kerberos.framework; sourceTree = DEVELOPER_DIR; };
+ 278C58DD136B645C00836530 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; };
+ 278C58E2136B647200836530 /* testhttp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = testhttp.c; path = ../cups/testhttp.c; sourceTree = "<group>"; };
+ 278C58E5136B64AF00836530 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
+ 278C58E6136B64B000836530 /* Kerberos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kerberos.framework; path = /System/Library/Frameworks/Kerberos.framework; sourceTree = "<absolute>"; };
+ 278C58E7136B64B000836530 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
+ 278C58E8136B64B000836530 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = "<absolute>"; };
+ 278C58F4136B652300836530 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; };
+ 27D3037C134148CB00F022B1 /* libcups_s.exp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.exports; name = libcups_s.exp; path = ../cups/libcups_s.exp; sourceTree = "<group>"; };
+ 27D3037D134148CB00F022B1 /* libcups2.def */ = {isa = PBXFileReference; lastKnownFileType = text; name = libcups2.def; path = ../cups/libcups2.def; sourceTree = "<group>"; };
+ 720DD6C21358FD5F0064AA82 /* snmp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = snmp; sourceTree = BUILT_PRODUCTS_DIR; };
+ 720DD6D21358FDDE0064AA82 /* snmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = snmp.c; path = ../backend/snmp.c; sourceTree = "<group>"; };
+ 72220EAE1333047D00FCA411 /* libcups.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libcups.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+ 72220EB51333052D00FCA411 /* adminutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = adminutil.c; path = ../cups/adminutil.c; sourceTree = "<group>"; };
+ 72220EB71333056300FCA411 /* adminutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = adminutil.h; path = ../cups/adminutil.h; sourceTree = "<group>"; };
+ 72220EB81333056300FCA411 /* array.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = array.c; path = ../cups/array.c; sourceTree = "<group>"; };
+ 72220EB91333056300FCA411 /* array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = array.h; path = ../cups/array.h; sourceTree = "<group>"; };
+ 72220EBA1333056300FCA411 /* attr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = attr.c; path = ../cups/attr.c; sourceTree = "<group>"; };
+ 72220EBB1333056300FCA411 /* auth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = auth.c; path = ../cups/auth.c; sourceTree = "<group>"; };
+ 72220EBC1333056300FCA411 /* backchannel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = backchannel.c; path = ../cups/backchannel.c; sourceTree = "<group>"; };
+ 72220EBD1333056300FCA411 /* backend.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = backend.c; path = ../cups/backend.c; sourceTree = "<group>"; };
+ 72220EBE1333056300FCA411 /* backend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = backend.h; path = ../cups/backend.h; sourceTree = "<group>"; };
+ 72220EBF1333056300FCA411 /* conflicts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = conflicts.c; path = ../cups/conflicts.c; sourceTree = "<group>"; };
+ 72220EC01333056300FCA411 /* cups-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "cups-private.h"; path = "../cups/cups-private.h"; sourceTree = "<group>"; };
+ 72220EC11333056300FCA411 /* cups.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cups.h; path = ../cups/cups.h; sourceTree = "<group>"; };
+ 72220EC21333056300FCA411 /* custom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = custom.c; path = ../cups/custom.c; sourceTree = "<group>"; };
+ 72220EC31333056300FCA411 /* debug-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "debug-private.h"; path = "../cups/debug-private.h"; sourceTree = "<group>"; };
+ 72220ED1133305BB00FCA411 /* debug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = debug.c; path = ../cups/debug.c; sourceTree = "<group>"; };
+ 72220ED2133305BB00FCA411 /* dest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dest.c; path = ../cups/dest.c; sourceTree = "<group>"; };
+ 72220ED3133305BB00FCA411 /* dir.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dir.c; path = ../cups/dir.c; sourceTree = "<group>"; };
+ 72220ED4133305BB00FCA411 /* dir.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dir.h; path = ../cups/dir.h; sourceTree = "<group>"; };
+ 72220ED5133305BB00FCA411 /* emit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = emit.c; path = ../cups/emit.c; sourceTree = "<group>"; };
+ 72220ED6133305BB00FCA411 /* encode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = encode.c; path = ../cups/encode.c; sourceTree = "<group>"; };
+ 72220ED7133305BB00FCA411 /* file-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "file-private.h"; path = "../cups/file-private.h"; sourceTree = "<group>"; };
+ 72220ED8133305BB00FCA411 /* file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = file.c; path = ../cups/file.c; sourceTree = "<group>"; };
+ 72220ED9133305BB00FCA411 /* file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = file.h; path = ../cups/file.h; sourceTree = "<group>"; };
+ 72220EDA133305BB00FCA411 /* getdevices.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = getdevices.c; path = ../cups/getdevices.c; sourceTree = "<group>"; };
+ 72220EDB133305BB00FCA411 /* getifaddrs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = getifaddrs.c; path = ../cups/getifaddrs.c; sourceTree = "<group>"; };
+ 72220EDC133305BB00FCA411 /* getputfile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = getputfile.c; path = ../cups/getputfile.c; sourceTree = "<group>"; };
+ 72220EDD133305BB00FCA411 /* globals.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = globals.c; path = ../cups/globals.c; sourceTree = "<group>"; };
+ 72220EDE133305BB00FCA411 /* http-addr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "http-addr.c"; path = "../cups/http-addr.c"; sourceTree = "<group>"; };
+ 72220EDF133305BB00FCA411 /* http-addrlist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "http-addrlist.c"; path = "../cups/http-addrlist.c"; sourceTree = "<group>"; };
+ 72220EE0133305BB00FCA411 /* http-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "http-private.h"; path = "../cups/http-private.h"; sourceTree = "<group>"; };
+ 72220EE1133305BB00FCA411 /* http-support.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "http-support.c"; path = "../cups/http-support.c"; sourceTree = "<group>"; };
+ 72220EE2133305BB00FCA411 /* http.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = http.c; path = ../cups/http.c; sourceTree = "<group>"; };
+ 72220EE3133305BB00FCA411 /* http.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = http.h; path = ../cups/http.h; sourceTree = "<group>"; };
+ 72220EE4133305BB00FCA411 /* ipp-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "ipp-private.h"; path = "../cups/ipp-private.h"; sourceTree = "<group>"; };
+ 72220EE5133305BB00FCA411 /* ipp-support.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "ipp-support.c"; path = "../cups/ipp-support.c"; sourceTree = "<group>"; };
+ 72220EE6133305BB00FCA411 /* ipp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ipp.c; path = ../cups/ipp.c; sourceTree = "<group>"; };
+ 72220EE7133305BB00FCA411 /* ipp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ipp.h; path = ../cups/ipp.h; sourceTree = "<group>"; };
+ 72220EE8133305BB00FCA411 /* langprintf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = langprintf.c; path = ../cups/langprintf.c; sourceTree = "<group>"; };
+ 72220EE9133305BB00FCA411 /* language-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "language-private.h"; path = "../cups/language-private.h"; sourceTree = "<group>"; };
+ 72220EEA133305BB00FCA411 /* language.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = language.c; path = ../cups/language.c; sourceTree = "<group>"; };
+ 72220EEB133305BB00FCA411 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../cups/language.h; sourceTree = "<group>"; };
+ 72220EEC133305BB00FCA411 /* localize.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = localize.c; path = ../cups/localize.c; sourceTree = "<group>"; };
+ 72220EED133305BB00FCA411 /* mark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mark.c; path = ../cups/mark.c; sourceTree = "<group>"; };
+ 72220EEE133305BB00FCA411 /* md5-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "md5-private.h"; path = "../cups/md5-private.h"; sourceTree = "<group>"; };
+ 72220EEF133305BB00FCA411 /* md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md5.c; path = ../cups/md5.c; sourceTree = "<group>"; };
+ 72220EF0133305BB00FCA411 /* md5passwd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md5passwd.c; path = ../cups/md5passwd.c; sourceTree = "<group>"; };
+ 72220EF1133305BB00FCA411 /* notify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = notify.c; path = ../cups/notify.c; sourceTree = "<group>"; };
+ 72220EF2133305BB00FCA411 /* options.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = options.c; path = ../cups/options.c; sourceTree = "<group>"; };
+ 72220EF3133305BB00FCA411 /* page.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = page.c; path = ../cups/page.c; sourceTree = "<group>"; };
+ 72220EF4133305BB00FCA411 /* ppd-cache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "ppd-cache.c"; path = "../cups/ppd-cache.c"; sourceTree = "<group>"; };
+ 72220EF5133305BB00FCA411 /* ppd-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "ppd-private.h"; path = "../cups/ppd-private.h"; sourceTree = "<group>"; };
+ 72220EF6133305BB00FCA411 /* ppd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ppd.c; path = ../cups/ppd.c; sourceTree = "<group>"; };
+ 72220EF7133305BB00FCA411 /* ppd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ppd.h; path = ../cups/ppd.h; sourceTree = "<group>"; };
+ 72220EF8133305BB00FCA411 /* pwg-media.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "pwg-media.c"; path = "../cups/pwg-media.c"; sourceTree = "<group>"; };
+ 72220EF9133305BB00FCA411 /* pwg-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "pwg-private.h"; path = "../cups/pwg-private.h"; sourceTree = "<group>"; };
+ 72220EFA133305BB00FCA411 /* raster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = raster.h; path = ../cups/raster.h; sourceTree = "<group>"; };
+ 72220EFB133305BB00FCA411 /* request.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = request.c; path = ../cups/request.c; sourceTree = "<group>"; };
+ 72220EFC133305BB00FCA411 /* sidechannel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sidechannel.c; path = ../cups/sidechannel.c; sourceTree = "<group>"; };
+ 72220EFD133305BB00FCA411 /* sidechannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sidechannel.h; path = ../cups/sidechannel.h; sourceTree = "<group>"; };
+ 72220EFE133305BB00FCA411 /* snmp-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "snmp-private.h"; path = "../cups/snmp-private.h"; sourceTree = "<group>"; };
+ 72220EFF133305BB00FCA411 /* snmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = snmp.c; path = ../cups/snmp.c; sourceTree = "<group>"; };
+ 72220F00133305BB00FCA411 /* snprintf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = snprintf.c; path = ../cups/snprintf.c; sourceTree = "<group>"; };
+ 72220F01133305BB00FCA411 /* string-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "string-private.h"; path = "../cups/string-private.h"; sourceTree = "<group>"; };
+ 72220F02133305BB00FCA411 /* string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = string.c; path = ../cups/string.c; sourceTree = "<group>"; };
+ 72220F03133305BB00FCA411 /* tempfile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tempfile.c; path = ../cups/tempfile.c; sourceTree = "<group>"; };
+ 72220F04133305BB00FCA411 /* thread-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "thread-private.h"; path = "../cups/thread-private.h"; sourceTree = "<group>"; };
+ 72220F05133305BB00FCA411 /* thread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = thread.c; path = ../cups/thread.c; sourceTree = "<group>"; };
+ 72220F06133305BB00FCA411 /* transcode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = transcode.c; path = ../cups/transcode.c; sourceTree = "<group>"; };
+ 72220F07133305BB00FCA411 /* transcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = transcode.h; path = ../cups/transcode.h; sourceTree = "<group>"; };
+ 72220F08133305BB00FCA411 /* usersys.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = usersys.c; path = ../cups/usersys.c; sourceTree = "<group>"; };
+ 72220F09133305BB00FCA411 /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = util.c; path = ../cups/util.c; sourceTree = "<group>"; };
+ 72220F0A133305BB00FCA411 /* versioning.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = versioning.h; path = ../cups/versioning.h; sourceTree = "<group>"; };
+ 72220F471333063D00FCA411 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
+ 72220F49133306BB00FCA411 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; };
+ 72220F4A133306BB00FCA411 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = SDKs/MacOSX10.6.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
+ 72220F4B133306BB00FCA411 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; };
+ 72220F4C133306BB00FCA411 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; };
+ 72220F51133308C100FCA411 /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = SDKs/MacOSX10.6.sdk/usr/lib/libiconv.dylib; sourceTree = DEVELOPER_DIR; };
+ 72220F53133308CB00FCA411 /* libresolv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libresolv.dylib; path = SDKs/MacOSX10.6.sdk/usr/lib/libresolv.dylib; sourceTree = DEVELOPER_DIR; };
+ 72220F55133308EA00FCA411 /* Kerberos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kerberos.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Kerberos.framework; sourceTree = DEVELOPER_DIR; };
+ 72220F5B13330A5A00FCA411 /* cupsd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cupsd; sourceTree = BUILT_PRODUCTS_DIR; };
+ 72220F6713330A8500FCA411 /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/ApplicationServices.framework; sourceTree = DEVELOPER_DIR; };
+ 72220F6913330B0C00FCA411 /* auth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = auth.c; path = ../scheduler/auth.c; sourceTree = SOURCE_ROOT; };
+ 72220F6A13330B0C00FCA411 /* auth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = auth.h; path = ../scheduler/auth.h; sourceTree = SOURCE_ROOT; };
+ 72220F6B13330B0C00FCA411 /* banners.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = banners.c; path = ../scheduler/banners.c; sourceTree = SOURCE_ROOT; };
+ 72220F6C13330B0C00FCA411 /* banners.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = banners.h; path = ../scheduler/banners.h; sourceTree = SOURCE_ROOT; };
+ 72220F6D13330B0C00FCA411 /* cert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cert.c; path = ../scheduler/cert.c; sourceTree = SOURCE_ROOT; };
+ 72220F6E13330B0C00FCA411 /* cert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cert.h; path = ../scheduler/cert.h; sourceTree = SOURCE_ROOT; };
+ 72220F6F13330B0C00FCA411 /* classes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = classes.c; path = ../scheduler/classes.c; sourceTree = SOURCE_ROOT; };
+ 72220F7013330B0C00FCA411 /* classes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = classes.h; path = ../scheduler/classes.h; sourceTree = SOURCE_ROOT; };
+ 72220F7113330B0C00FCA411 /* client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = client.c; path = ../scheduler/client.c; sourceTree = SOURCE_ROOT; };
+ 72220F7213330B0C00FCA411 /* client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = client.h; path = ../scheduler/client.h; sourceTree = SOURCE_ROOT; };
+ 72220F7313330B0C00FCA411 /* conf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = conf.c; path = ../scheduler/conf.c; sourceTree = SOURCE_ROOT; };
+ 72220F7413330B0C00FCA411 /* conf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = conf.h; path = ../scheduler/conf.h; sourceTree = SOURCE_ROOT; };
+ 72220F7513330B0C00FCA411 /* cupsd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cupsd.h; path = ../scheduler/cupsd.h; sourceTree = SOURCE_ROOT; };
+ 72220F7613330B0C00FCA411 /* dirsvc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dirsvc.c; path = ../scheduler/dirsvc.c; sourceTree = SOURCE_ROOT; };
+ 72220F7713330B0C00FCA411 /* dirsvc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dirsvc.h; path = ../scheduler/dirsvc.h; sourceTree = SOURCE_ROOT; };
+ 72220F7813330B0C00FCA411 /* env.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = env.c; path = ../scheduler/env.c; sourceTree = SOURCE_ROOT; };
+ 72220F7913330B0C00FCA411 /* ipp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ipp.c; path = ../scheduler/ipp.c; sourceTree = SOURCE_ROOT; };
+ 72220F7A13330B0C00FCA411 /* job.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = job.c; path = ../scheduler/job.c; sourceTree = SOURCE_ROOT; };
+ 72220F7B13330B0C00FCA411 /* job.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = job.h; path = ../scheduler/job.h; sourceTree = SOURCE_ROOT; };
+ 72220F7C13330B0C00FCA411 /* listen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = listen.c; path = ../scheduler/listen.c; sourceTree = SOURCE_ROOT; };
+ 72220F7D13330B0C00FCA411 /* log.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = log.c; path = ../scheduler/log.c; sourceTree = SOURCE_ROOT; };
+ 72220F7E13330B0C00FCA411 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = ../scheduler/main.c; sourceTree = SOURCE_ROOT; };
+ 72220F7F13330B0C00FCA411 /* network.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = network.c; path = ../scheduler/network.c; sourceTree = SOURCE_ROOT; };
+ 72220F8013330B0C00FCA411 /* network.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = network.h; path = ../scheduler/network.h; sourceTree = SOURCE_ROOT; };
+ 72220F8113330B0C00FCA411 /* policy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = policy.c; path = ../scheduler/policy.c; sourceTree = SOURCE_ROOT; };
+ 72220F8213330B0C00FCA411 /* policy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = policy.h; path = ../scheduler/policy.h; sourceTree = SOURCE_ROOT; };
+ 72220F8313330B0C00FCA411 /* printers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = printers.c; path = ../scheduler/printers.c; sourceTree = SOURCE_ROOT; };
+ 72220F8413330B0C00FCA411 /* printers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = printers.h; path = ../scheduler/printers.h; sourceTree = SOURCE_ROOT; };
+ 72220F8513330B0C00FCA411 /* process.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = process.c; path = ../scheduler/process.c; sourceTree = SOURCE_ROOT; };
+ 72220F8613330B0C00FCA411 /* quotas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quotas.c; path = ../scheduler/quotas.c; sourceTree = SOURCE_ROOT; };
+ 72220F8813330B0C00FCA411 /* select.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = select.c; path = ../scheduler/select.c; sourceTree = SOURCE_ROOT; };
+ 72220F8913330B0C00FCA411 /* server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = server.c; path = ../scheduler/server.c; sourceTree = SOURCE_ROOT; };
+ 72220F8A13330B0C00FCA411 /* statbuf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = statbuf.c; path = ../scheduler/statbuf.c; sourceTree = SOURCE_ROOT; };
+ 72220F8B13330B0C00FCA411 /* statbuf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = statbuf.h; path = ../scheduler/statbuf.h; sourceTree = SOURCE_ROOT; };
+ 72220F8C13330B0C00FCA411 /* subscriptions.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = subscriptions.c; path = ../scheduler/subscriptions.c; sourceTree = SOURCE_ROOT; };
+ 72220F8D13330B0C00FCA411 /* subscriptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = subscriptions.h; path = ../scheduler/subscriptions.h; sourceTree = SOURCE_ROOT; };
+ 72220F8E13330B0C00FCA411 /* sysman.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sysman.c; path = ../scheduler/sysman.c; sourceTree = SOURCE_ROOT; };
+ 72220F8F13330B0C00FCA411 /* sysman.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sysman.h; path = ../scheduler/sysman.h; sourceTree = SOURCE_ROOT; };
+ 72220FAC13330B2200FCA411 /* libcupsmime.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libcupsmime.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+ 72220FB213330BCE00FCA411 /* filter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = filter.c; path = ../scheduler/filter.c; sourceTree = "<group>"; };
+ 72220FB313330BCE00FCA411 /* mime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mime.c; path = ../scheduler/mime.c; sourceTree = "<group>"; };
+ 72220FB413330BCE00FCA411 /* mime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mime.h; path = ../scheduler/mime.h; sourceTree = "<group>"; };
+ 72220FB513330BCE00FCA411 /* type.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = type.c; path = ../scheduler/type.c; sourceTree = "<group>"; };
+ 7234F41F1378A16F00D3E9C9 /* array-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "array-private.h"; path = "../cups/array-private.h"; sourceTree = "<group>"; };
+ 724378FD1333E43E009631B9 /* ipp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ipp; sourceTree = BUILT_PRODUCTS_DIR; };
+ 724379091333E4E3009631B9 /* backend-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "backend-private.h"; path = "../backend/backend-private.h"; sourceTree = "<group>"; };
+ 7243790A1333E4E3009631B9 /* ipp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ipp.c; path = ../backend/ipp.c; sourceTree = "<group>"; };
+ 7243790B1333E4E3009631B9 /* network.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = network.c; path = ../backend/network.c; sourceTree = "<group>"; };
+ 7243790C1333E4E3009631B9 /* snmp-supplies.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "snmp-supplies.c"; path = "../backend/snmp-supplies.c"; sourceTree = "<group>"; };
+ 724379121333E516009631B9 /* runloop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = runloop.c; path = ../backend/runloop.c; sourceTree = "<group>"; };
+ 724379181333E532009631B9 /* lpd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lpd; sourceTree = BUILT_PRODUCTS_DIR; };
+ 724379281333E952009631B9 /* lpd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lpd.c; path = ../backend/lpd.c; sourceTree = "<group>"; };
+ 724379301333FB85009631B9 /* socket */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = socket; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7243793C1333FD19009631B9 /* socket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = socket.c; path = ../backend/socket.c; sourceTree = "<group>"; };
+ 724379471333FEA9009631B9 /* dnssd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnssd; sourceTree = BUILT_PRODUCTS_DIR; };
+ 724379501333FEBB009631B9 /* dnssd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd.c; path = ../backend/dnssd.c; sourceTree = "<group>"; };
+ 7243795B1333FF1D009631B9 /* usb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = usb; sourceTree = BUILT_PRODUCTS_DIR; };
+ 724379671333FF3B009631B9 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = SDKs/MacOSX10.7.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; };
+ 724379C41333FFC7009631B9 /* usb-darwin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "usb-darwin.c"; path = "../backend/usb-darwin.c"; sourceTree = "<group>"; };
+ 724379C51333FFC7009631B9 /* usb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = usb.c; path = ../backend/usb.c; sourceTree = "<group>"; };
+ 724379C81333FFF3009631B9 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = SDKs/MacOSX10.7.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; };
+ 724379CA1334000E009631B9 /* ieee1284.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ieee1284.c; path = ../backend/ieee1284.c; sourceTree = "<group>"; };
+ 7258EAE2134594C4009286F1 /* rastertopwg */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rastertopwg; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7258EAEC134594EB009286F1 /* rastertopwg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rastertopwg.c; path = ../filter/rastertopwg.c; sourceTree = "<group>"; };
+ 7263EE2613330D2800BA4D44 /* libpam.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpam.dylib; path = SDKs/MacOSX10.6.sdk/usr/lib/libpam.dylib; sourceTree = DEVELOPER_DIR; };
+ 7263EE2913330D5C00BA4D44 /* Kerberos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kerberos.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Kerberos.framework; sourceTree = DEVELOPER_DIR; };
+ 7263EE2A13330D5C00BA4D44 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; };
+ 7263EE2B13330D5C00BA4D44 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; };
+ 7263EE2F13330DC100BA4D44 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; };
+ 7263EE3113330E1E00BA4D44 /* libpthread.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpthread.dylib; path = SDKs/MacOSX10.6.sdk/usr/lib/libpthread.dylib; sourceTree = DEVELOPER_DIR; };
+ 7263EE3313330E3C00BA4D44 /* libresolv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libresolv.dylib; path = SDKs/MacOSX10.6.sdk/usr/lib/libresolv.dylib; sourceTree = DEVELOPER_DIR; };
+ 7263EE3513330E4E00BA4D44 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = SDKs/MacOSX10.6.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; };
+ 7263EE3713330E7500BA4D44 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = SDKs/MacOSX10.6.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
+ 7263EE3913330EC500BA4D44 /* libldap.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libldap.dylib; path = SDKs/MacOSX10.6.sdk/usr/lib/libldap.dylib; sourceTree = DEVELOPER_DIR; };
+ 726AD6F7135E88F0002C930D /* ippserver */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ippserver; sourceTree = BUILT_PRODUCTS_DIR; };
+ 726AD701135E8A90002C930D /* ippserver.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ippserver.c; path = ../test/ippserver.c; sourceTree = "<group>"; };
+ 7271881613746EA8001A2036 /* bannertops.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = bannertops.c; path = ../filter/bannertops.c; sourceTree = "<group>"; };
+ 7271881713746EA8001A2036 /* commandtops.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = commandtops.c; path = ../filter/commandtops.c; sourceTree = "<group>"; };
+ 7271881813746EA8001A2036 /* common.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = common.c; path = ../filter/common.c; sourceTree = "<group>"; };
+ 7271881913746EA8001A2036 /* common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = common.h; path = ../filter/common.h; sourceTree = "<group>"; };
+ 7271881A13746EA8001A2036 /* gziptoany.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = gziptoany.c; path = ../filter/gziptoany.c; sourceTree = "<group>"; };
+ 7271881B13746EA8001A2036 /* imagetops.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = imagetops.c; path = ../filter/imagetops.c; sourceTree = "<group>"; };
+ 7271881C13746EA8001A2036 /* imagetoraster.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = imagetoraster.c; path = ../filter/imagetoraster.c; sourceTree = "<group>"; };
+ 7271881D13746EA8001A2036 /* pdftops.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pdftops.c; path = ../filter/pdftops.c; sourceTree = "<group>"; };
+ 7271881E13746EA8001A2036 /* pstext.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pstext.c; path = ../filter/pstext.c; sourceTree = "<group>"; };
+ 7271881F13746EA8001A2036 /* pstext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = pstext.h; path = ../filter/pstext.h; sourceTree = "<group>"; };
+ 7271882013746EA8001A2036 /* pstops.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pstops.c; path = ../filter/pstops.c; sourceTree = "<group>"; };
+ 7271882113746EA8001A2036 /* rastertoepson.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = rastertoepson.c; path = ../filter/rastertoepson.c; sourceTree = "<group>"; };
+ 7271882213746EA8001A2036 /* rastertohp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = rastertohp.c; path = ../filter/rastertohp.c; sourceTree = "<group>"; };
+ 7271882313746EA8001A2036 /* rastertolabel.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = rastertolabel.c; path = ../filter/rastertolabel.c; sourceTree = "<group>"; };
+ 7271882413746EA8001A2036 /* textcommon.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = textcommon.c; path = ../filter/textcommon.c; sourceTree = "<group>"; };
+ 7271882513746EA8001A2036 /* textcommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = textcommon.h; path = ../filter/textcommon.h; sourceTree = "<group>"; };
+ 7271882613746EA8001A2036 /* texttops.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = texttops.c; path = ../filter/texttops.c; sourceTree = "<group>"; };
+ 7271882B137498E4001A2036 /* image-bmp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "image-bmp.c"; path = "../filter/image-bmp.c"; sourceTree = "<group>"; };
+ 7271882C137498E4001A2036 /* image-colorspace.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "image-colorspace.c"; path = "../filter/image-colorspace.c"; sourceTree = "<group>"; };
+ 7271882D137498E4001A2036 /* image-gif.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "image-gif.c"; path = "../filter/image-gif.c"; sourceTree = "<group>"; };
+ 7271882E137498E4001A2036 /* image-jpeg.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "image-jpeg.c"; path = "../filter/image-jpeg.c"; sourceTree = "<group>"; };
+ 7271882F137498E4001A2036 /* image-photocd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "image-photocd.c"; path = "../filter/image-photocd.c"; sourceTree = "<group>"; };
+ 72718830137498E4001A2036 /* image-pix.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "image-pix.c"; path = "../filter/image-pix.c"; sourceTree = "<group>"; };
+ 72718831137498E4001A2036 /* image-png.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "image-png.c"; path = "../filter/image-png.c"; sourceTree = "<group>"; };
+ 72718832137498E4001A2036 /* image-pnm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "image-pnm.c"; path = "../filter/image-pnm.c"; sourceTree = "<group>"; };
+ 72718833137498E4001A2036 /* image-private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "image-private.h"; path = "../filter/image-private.h"; sourceTree = "<group>"; };
+ 72718834137498E4001A2036 /* image-sgi.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "image-sgi.c"; path = "../filter/image-sgi.c"; sourceTree = "<group>"; };
+ 72718835137498E4001A2036 /* image-sgi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "image-sgi.h"; path = "../filter/image-sgi.h"; sourceTree = "<group>"; };
+ 72718836137498E4001A2036 /* image-sgilib.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "image-sgilib.c"; path = "../filter/image-sgilib.c"; sourceTree = "<group>"; };
+ 72718837137498E4001A2036 /* image-sun.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "image-sun.c"; path = "../filter/image-sun.c"; sourceTree = "<group>"; };
+ 72718838137498E4001A2036 /* image-tiff.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "image-tiff.c"; path = "../filter/image-tiff.c"; sourceTree = "<group>"; };
+ 72718839137498E4001A2036 /* image-zoom.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "image-zoom.c"; path = "../filter/image-zoom.c"; sourceTree = "<group>"; };
+ 7271883A137498E4001A2036 /* image.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = image.c; path = ../filter/image.c; sourceTree = "<group>"; };
+ 7271883B137498E4001A2036 /* image.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = image.h; path = ../filter/image.h; sourceTree = "<group>"; };
+ 7271883C1374AB14001A2036 /* mime-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "mime-private.h"; path = "../scheduler/mime-private.h"; sourceTree = "<group>"; };
+ 72C16CB8137B195D007E4BF4 /* file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = file.c; path = ../scheduler/file.c; sourceTree = SOURCE_ROOT; };
+ 72F75A4C1336F31B004BB496 /* libcups_static.a */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libcups_static.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 72F75A521336F950004BB496 /* cupstestppd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cupstestppd; sourceTree = BUILT_PRODUCTS_DIR; };
+ 72F75A5B1336F988004BB496 /* cupstestppd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cupstestppd.c; path = ../systemv/cupstestppd.c; sourceTree = "<group>"; };
+ 72F75A611336F9A3004BB496 /* libcupsimage.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libcupsimage.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+ 72F75A691336FA8A004BB496 /* error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = error.c; path = ../filter/error.c; sourceTree = "<group>"; };
+ 72F75A6A1336FA8A004BB496 /* interpret.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = interpret.c; path = ../filter/interpret.c; sourceTree = "<group>"; };
+ 72F75A6B1336FA8A004BB496 /* raster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = raster.c; path = ../filter/raster.c; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 270CCDA4135E3C9E00007BE2 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 278C58E9136B64B000836530 /* CoreFoundation.framework in Frameworks */,
+ 278C58EA136B64B000836530 /* Kerberos.framework in Frameworks */,
+ 278C58EB136B64B000836530 /* Security.framework in Frameworks */,
+ 278C58EC136B64B000836530 /* SystemConfiguration.framework in Frameworks */,
+ 270CCDB9135E3D0900007BE2 /* libcups_static.a in Frameworks */,
+ 270CCDBA135E3D0900007BE2 /* libcupsmime.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 273BF6BA1333B5000022CAAB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 278C58E4136B649200836530 /* libcups_static.a in Frameworks */,
+ 273BF6CE1333B5950022CAAB /* CoreFoundation.framework in Frameworks */,
+ 273BF6D31333B5C30022CAAB /* Kerberos.framework in Frameworks */,
+ 273BF6D41333B5C30022CAAB /* Security.framework in Frameworks */,
+ 273BF6D81333B5F60022CAAB /* SystemConfiguration.framework in Frameworks */,
+ 273BF6CF1333B5950022CAAB /* libiconv.dylib in Frameworks */,
+ 273BF6D71333B5F60022CAAB /* libresolv.dylib in Frameworks */,
+ 273BF6D01333B5950022CAAB /* libz.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF5C913332B1F00317ECB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF5DD13332D0600317ECB /* libcups.dylib in Frameworks */,
+ 274FF6241333323B00317ECB /* libcupsppdc.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF5EB133330C800317ECB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF6231333321400317ECB /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF6261333333600317ECB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF6321333334A00317ECB /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF63B1333358B00317ECB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF64C133339C400317ECB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF658133339D300317ECB /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF66013333A9B00317ECB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF66E13333AB500317ECB /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF67513333B2F00317ECB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF68513333B4300317ECB /* libcups.dylib in Frameworks */,
+ 274FF68613333B4300317ECB /* libcupsmime.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF6B91333B1C400317ECB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF6BA1333B1C400317ECB /* CoreFoundation.framework in Frameworks */,
+ 274FF6BB1333B1C400317ECB /* Kerberos.framework in Frameworks */,
+ 274FF6BC1333B1C400317ECB /* Security.framework in Frameworks */,
+ 274FF6BD1333B1C400317ECB /* SystemConfiguration.framework in Frameworks */,
+ 274FF6BE1333B1C400317ECB /* libiconv.dylib in Frameworks */,
+ 274FF6BF1333B1C400317ECB /* libresolv.dylib in Frameworks */,
+ 274FF6C01333B1C400317ECB /* libz.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 276683591337A9B6000D33D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683671337A9E0000D33D0 /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2766836D1337AC79000D33D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683B11337AD06000D33D0 /* libcups.dylib in Frameworks */,
+ 276683B21337AD06000D33D0 /* libcupsppdc.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2766837A1337AC8C000D33D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683B71337AD23000D33D0 /* libcups.dylib in Frameworks */,
+ 276683B81337AD23000D33D0 /* libcupsppdc.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 276683871337AC97000D33D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683B91337AD31000D33D0 /* libcups.dylib in Frameworks */,
+ 276683BA1337AD31000D33D0 /* libcupsppdc.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 276683941337ACA2000D33D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683C31337B1B3000D33D0 /* libcups.dylib in Frameworks */,
+ 276683C41337B1B3000D33D0 /* libcupsppdc.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 276683A11337ACAB000D33D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683C91337B1C1000D33D0 /* libcups.dylib in Frameworks */,
+ 276683CA1337B1C1000D33D0 /* libcupsppdc.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 276683ED1337F78E000D33D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683FD1337F7B8000D33D0 /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 276684011337FA1D000D33D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2766840F1337FA38000D33D0 /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 278C58C8136B640300836530 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 278C58DE136B645C00836530 /* CoreFoundation.framework in Frameworks */,
+ 278C58DF136B645C00836530 /* Kerberos.framework in Frameworks */,
+ 278C58F6136B652300836530 /* Security.framework in Frameworks */,
+ 278C58E1136B645C00836530 /* SystemConfiguration.framework in Frameworks */,
+ 278C58D9136B645C00836530 /* libcups_static.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 720DD6BF1358FD5F0064AA82 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 720DD6CD1358FD720064AA82 /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72220EAB1333047D00FCA411 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72220F4D133306BB00FCA411 /* CoreFoundation.framework in Frameworks */,
+ 72220F56133308EA00FCA411 /* Kerberos.framework in Frameworks */,
+ 72220F4F133306BB00FCA411 /* Security.framework in Frameworks */,
+ 72220F50133306BB00FCA411 /* SystemConfiguration.framework in Frameworks */,
+ 72220F52133308C100FCA411 /* libiconv.dylib in Frameworks */,
+ 72220F54133308CB00FCA411 /* libresolv.dylib in Frameworks */,
+ 72220F4E133306BB00FCA411 /* libz.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72220F5813330A5A00FCA411 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72220F6813330A8500FCA411 /* ApplicationServices.framework in Frameworks */,
+ 7263EE3613330E4E00BA4D44 /* CoreFoundation.framework in Frameworks */,
+ 7263EE3013330DC100BA4D44 /* IOKit.framework in Frameworks */,
+ 7263EE2C13330D5C00BA4D44 /* Kerberos.framework in Frameworks */,
+ 7263EE2D13330D5C00BA4D44 /* Security.framework in Frameworks */,
+ 7263EE2E13330D5C00BA4D44 /* SystemConfiguration.framework in Frameworks */,
+ 72220F6613330A7000FCA411 /* libcups.dylib in Frameworks */,
+ 72220FBF13330C1000FCA411 /* libcupsmime.dylib in Frameworks */,
+ 7263EE3A13330EC500BA4D44 /* libldap.dylib in Frameworks */,
+ 7263EE2713330D2800BA4D44 /* libpam.dylib in Frameworks */,
+ 7263EE3213330E1E00BA4D44 /* libpthread.dylib in Frameworks */,
+ 7263EE3413330E3C00BA4D44 /* libresolv.dylib in Frameworks */,
+ 7263EE3813330E7500BA4D44 /* libz.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72220FA913330B2200FCA411 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72220FBA13330BEE00FCA411 /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724378FA1333E43E009631B9 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724379081333E4A5009631B9 /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724379151333E532009631B9 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724379271333E93D009631B9 /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7243792D1333FB85009631B9 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7243793B1333FB9D009631B9 /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724379441333FEA9009631B9 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724379561333FF04009631B9 /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724379581333FF1D009631B9 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724379C91333FFF3009631B9 /* CoreFoundation.framework in Frameworks */,
+ 724379681333FF3B009631B9 /* IOKit.framework in Frameworks */,
+ 724379661333FF3B009631B9 /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7258EADF134594C4009286F1 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7258EAF413459B6D009286F1 /* libcups.dylib in Frameworks */,
+ 7258EAF513459B6D009286F1 /* libcupsimage.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 726AD6F4135E88F0002C930D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 726AD70E135E8B5E002C930D /* libiconv.dylib in Frameworks */,
+ 726AD707135E8B11002C930D /* libcups_static.a in Frameworks */,
+ 726AD708135E8B11002C930D /* CoreFoundation.framework in Frameworks */,
+ 726AD709135E8B11002C930D /* Kerberos.framework in Frameworks */,
+ 726AD70A135E8B11002C930D /* libresolv.dylib in Frameworks */,
+ 726AD70B135E8B11002C930D /* libz.dylib in Frameworks */,
+ 726AD70C135E8B11002C930D /* Security.framework in Frameworks */,
+ 726AD70D135E8B11002C930D /* SystemConfiguration.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72F75A4F1336F950004BB496 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683E51337B2BE000D33D0 /* libcupsimage.dylib in Frameworks */,
+ 276683E21337B29C000D33D0 /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72F75A5E1336F9A3004BB496 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72F75A671336FA38004BB496 /* libcups.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 273BF6B81333B4A90022CAAB /* tests */ = {
+ isa = PBXGroup;
+ children = (
+ 273BF6C61333B5370022CAAB /* testcups.c */,
+ 278C58E2136B647200836530 /* testhttp.c */,
+ 270CCDBB135E3D3E00007BE2 /* testmime.c */,
+ );
+ name = tests;
+ sourceTree = "<group>";
+ };
+ 274FF5D513332C2C00317ECB /* daemon */ = {
+ isa = PBXGroup;
+ children = (
+ 274FF66F13333ACF00317ECB /* cups-polld.c */,
+ 274FF6351333344400317ECB /* cups-deviced.c */,
+ 274FF5D613332CC700317ECB /* cups-driverd.cxx */,
+ 274FF6491333398D00317ECB /* cups-exec.c */,
+ 274FF65B133339FC00317ECB /* cups-lpd.c */,
+ 274FF5D713332CC700317ECB /* util.c */,
+ 274FF5D813332CC700317ECB /* util.h */,
+ );
+ name = daemon;
+ sourceTree = "<group>";
+ };
+ 274FF5F41333310400317ECB /* libcupsppdc */ = {
+ isa = PBXGroup;
+ children = (
+ 274FF5F51333315100317ECB /* ppdc-array.cxx */,
+ 274FF5F61333315100317ECB /* ppdc-attr.cxx */,
+ 274FF5F71333315100317ECB /* ppdc-catalog.cxx */,
+ 274FF5F81333315100317ECB /* ppdc-choice.cxx */,
+ 274FF5F91333315100317ECB /* ppdc-constraint.cxx */,
+ 274FF5FA1333315100317ECB /* ppdc-driver.cxx */,
+ 274FF5FB1333315100317ECB /* ppdc-file.cxx */,
+ 274FF5FC1333315100317ECB /* ppdc-filter.cxx */,
+ 274FF5FD1333315100317ECB /* ppdc-font.cxx */,
+ 274FF5FE1333315100317ECB /* ppdc-group.cxx */,
+ 274FF5FF1333315100317ECB /* ppdc-import.cxx */,
+ 274FF6001333315100317ECB /* ppdc-mediasize.cxx */,
+ 274FF6011333315100317ECB /* ppdc-message.cxx */,
+ 274FF6021333315100317ECB /* ppdc-option.cxx */,
+ 274FF6031333315100317ECB /* ppdc-private.h */,
+ 274FF6041333315100317ECB /* ppdc-profile.cxx */,
+ 274FF6051333315100317ECB /* ppdc-shared.cxx */,
+ 274FF6061333315100317ECB /* ppdc-source.cxx */,
+ 274FF6071333315100317ECB /* ppdc-string.cxx */,
+ 274FF6081333315100317ECB /* ppdc-variable.cxx */,
+ );
+ name = libcupsppdc;
+ sourceTree = "<group>";
+ };
+ 274FF67313333B0A00317ECB /* commands */ = {
+ isa = PBXGroup;
+ children = (
+ 2732E089137A3F5200FAFEF6 /* cancel.c */,
+ 2732E08A137A3F5200FAFEF6 /* cupsaccept.c */,
+ 276684101337FA7C000D33D0 /* cupsaddsmb.c */,
+ 276683681337AA00000D33D0 /* cupsctl.c */,
+ 274FF68713333B6E00317ECB /* cupsfilter.c */,
+ 2732E08B137A3F5200FAFEF6 /* cupstestdsc.c */,
+ 72F75A5B1336F988004BB496 /* cupstestppd.c */,
+ 726AD701135E8A90002C930D /* ippserver.c */,
+ 276683F91337F7A9000D33D0 /* ipptool.c */,
+ 2732E08C137A3F5200FAFEF6 /* lp.c */,
+ 2732E08D137A3F5200FAFEF6 /* lpadmin.c */,
+ 2732E08E137A3F5200FAFEF6 /* lpinfo.c */,
+ 2732E08F137A3F5200FAFEF6 /* lpmove.c */,
+ 2732E090137A3F5200FAFEF6 /* lpoptions.c */,
+ 2732E091137A3F5200FAFEF6 /* lppasswd.c */,
+ 2732E092137A3F5200FAFEF6 /* lpstat.c */,
+ );
+ name = commands;
+ sourceTree = "<group>";
+ };
+ 276683CB1337B1CC000D33D0 /* ppdc tools */ = {
+ isa = PBXGroup;
+ children = (
+ 276683CC1337B201000D33D0 /* ppdc.cxx */,
+ 276683CE1337B20D000D33D0 /* ppdhtml.cxx */,
+ 276683D01337B21A000D33D0 /* ppdi.cxx */,
+ 276683D21337B228000D33D0 /* ppdmerge.cxx */,
+ 276683D41337B237000D33D0 /* ppdpo.cxx */,
+ );
+ name = "ppdc tools";
+ sourceTree = "<group>";
+ };
+ 72220EAF1333047D00FCA411 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 72220F5B13330A5A00FCA411 /* cupsd */,
+ 274FF5CC13332B1F00317ECB /* cups-driverd */,
+ 274FF6291333333600317ECB /* cups-deviced */,
+ 274FF63E1333358B00317ECB /* cups-exec */,
+ 274FF64F133339C400317ECB /* cups-lpd */,
+ 274FF66313333A9B00317ECB /* cups-polld */,
+ 274FF67813333B2F00317ECB /* cupsfilter */,
+ 273BF6BD1333B5000022CAAB /* testcups */,
+ 724378FD1333E43E009631B9 /* ipp */,
+ 724379181333E532009631B9 /* lpd */,
+ 724379301333FB85009631B9 /* socket */,
+ 724379471333FEA9009631B9 /* dnssd */,
+ 7243795B1333FF1D009631B9 /* usb */,
+ 72F75A521336F950004BB496 /* cupstestppd */,
+ 2766835C1337A9B6000D33D0 /* cupsctl */,
+ 276683701337AC79000D33D0 /* ppdc */,
+ 2766837D1337AC8C000D33D0 /* ppdhtml */,
+ 2766838A1337AC97000D33D0 /* ppdi */,
+ 276683971337ACA2000D33D0 /* ppdmerge */,
+ 276683A41337ACAB000D33D0 /* ppdpo */,
+ 276683F01337F78E000D33D0 /* ipptool */,
+ 276684041337FA1D000D33D0 /* cupsaddsmb */,
+ 7258EAE2134594C4009286F1 /* rastertopwg */,
+ 720DD6C21358FD5F0064AA82 /* snmp */,
+ 270CCDA7135E3C9E00007BE2 /* testmime */,
+ 726AD6F7135E88F0002C930D /* ippserver */,
+ 278C58CB136B640300836530 /* testhttp */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 72220EB41333050100FCA411 /* libcups */ = {
+ isa = PBXGroup;
+ children = (
+ 276683561337A8C5000D33D0 /* cups.strings */,
+ 27D3037C134148CB00F022B1 /* libcups_s.exp */,
+ 27D3037D134148CB00F022B1 /* libcups2.def */,
+ 72220EB51333052D00FCA411 /* adminutil.c */,
+ 72220EB81333056300FCA411 /* array.c */,
+ 72220EBA1333056300FCA411 /* attr.c */,
+ 72220EBB1333056300FCA411 /* auth.c */,
+ 72220EBC1333056300FCA411 /* backchannel.c */,
+ 72220EBD1333056300FCA411 /* backend.c */,
+ 72220EBF1333056300FCA411 /* conflicts.c */,
+ 72220EC21333056300FCA411 /* custom.c */,
+ 72220ED1133305BB00FCA411 /* debug.c */,
+ 72220ED2133305BB00FCA411 /* dest.c */,
+ 72220ED3133305BB00FCA411 /* dir.c */,
+ 72220ED4133305BB00FCA411 /* dir.h */,
+ 72220ED5133305BB00FCA411 /* emit.c */,
+ 72220ED6133305BB00FCA411 /* encode.c */,
+ 72220ED8133305BB00FCA411 /* file.c */,
+ 72220EDA133305BB00FCA411 /* getdevices.c */,
+ 72220EDB133305BB00FCA411 /* getifaddrs.c */,
+ 72220EDC133305BB00FCA411 /* getputfile.c */,
+ 72220EDD133305BB00FCA411 /* globals.c */,
+ 72220EDE133305BB00FCA411 /* http-addr.c */,
+ 72220EDF133305BB00FCA411 /* http-addrlist.c */,
+ 72220EE1133305BB00FCA411 /* http-support.c */,
+ 72220EE2133305BB00FCA411 /* http.c */,
+ 72220EE5133305BB00FCA411 /* ipp-support.c */,
+ 72220EE6133305BB00FCA411 /* ipp.c */,
+ 72220EE8133305BB00FCA411 /* langprintf.c */,
+ 72220EEA133305BB00FCA411 /* language.c */,
+ 72220EEC133305BB00FCA411 /* localize.c */,
+ 72220EED133305BB00FCA411 /* mark.c */,
+ 72220EEF133305BB00FCA411 /* md5.c */,
+ 72220EF0133305BB00FCA411 /* md5passwd.c */,
+ 72220EF1133305BB00FCA411 /* notify.c */,
+ 72220EF2133305BB00FCA411 /* options.c */,
+ 72220EF3133305BB00FCA411 /* page.c */,
+ 72220EF4133305BB00FCA411 /* ppd-cache.c */,
+ 72220EF6133305BB00FCA411 /* ppd.c */,
+ 72220EF8133305BB00FCA411 /* pwg-media.c */,
+ 72220EFB133305BB00FCA411 /* request.c */,
+ 72220EFC133305BB00FCA411 /* sidechannel.c */,
+ 72220EFF133305BB00FCA411 /* snmp.c */,
+ 72220F00133305BB00FCA411 /* snprintf.c */,
+ 72220F02133305BB00FCA411 /* string.c */,
+ 72220F03133305BB00FCA411 /* tempfile.c */,
+ 72220F05133305BB00FCA411 /* thread.c */,
+ 72220F06133305BB00FCA411 /* transcode.c */,
+ 72220F08133305BB00FCA411 /* usersys.c */,
+ 72220F09133305BB00FCA411 /* util.c */,
+ );
+ name = libcups;
+ sourceTree = "<group>";
+ };
+ 72220F45133305D000FCA411 /* Public Headers */ = {
+ isa = PBXGroup;
+ children = (
+ 72220EB71333056300FCA411 /* adminutil.h */,
+ 72220EB91333056300FCA411 /* array.h */,
+ 72220EBE1333056300FCA411 /* backend.h */,
+ 72220EC11333056300FCA411 /* cups.h */,
+ 72220ED9133305BB00FCA411 /* file.h */,
+ 72220EE3133305BB00FCA411 /* http.h */,
+ 72220EE7133305BB00FCA411 /* ipp.h */,
+ 72220EEB133305BB00FCA411 /* language.h */,
+ 72220FB413330BCE00FCA411 /* mime.h */,
+ 72220EF7133305BB00FCA411 /* ppd.h */,
+ 274FF6091333315100317ECB /* ppdc.h */,
+ 72220EFA133305BB00FCA411 /* raster.h */,
+ 72220EFD133305BB00FCA411 /* sidechannel.h */,
+ 72220F07133305BB00FCA411 /* transcode.h */,
+ 72220F0A133305BB00FCA411 /* versioning.h */,
+ );
+ name = "Public Headers";
+ sourceTree = "<group>";
+ };
+ 72220F461333060C00FCA411 /* Private Headers */ = {
+ isa = PBXGroup;
+ children = (
+ 72220F471333063D00FCA411 /* config.h */,
+ 7234F41F1378A16F00D3E9C9 /* array-private.h */,
+ 72220EC01333056300FCA411 /* cups-private.h */,
+ 72220EC31333056300FCA411 /* debug-private.h */,
+ 72220ED7133305BB00FCA411 /* file-private.h */,
+ 72220EE0133305BB00FCA411 /* http-private.h */,
+ 72220EE4133305BB00FCA411 /* ipp-private.h */,
+ 72220EE9133305BB00FCA411 /* language-private.h */,
+ 72220EEE133305BB00FCA411 /* md5-private.h */,
+ 7271883C1374AB14001A2036 /* mime-private.h */,
+ 72220EF5133305BB00FCA411 /* ppd-private.h */,
+ 72220EF9133305BB00FCA411 /* pwg-private.h */,
+ 72220EFE133305BB00FCA411 /* snmp-private.h */,
+ 72220F01133305BB00FCA411 /* string-private.h */,
+ 72220F04133305BB00FCA411 /* thread-private.h */,
+ );
+ name = "Private Headers";
+ sourceTree = "<group>";
+ };
+ 72220F5D13330A5A00FCA411 /* cupsd */ = {
+ isa = PBXGroup;
+ children = (
+ 72220F6913330B0C00FCA411 /* auth.c */,
+ 72220F6A13330B0C00FCA411 /* auth.h */,
+ 72220F6B13330B0C00FCA411 /* banners.c */,
+ 72220F6C13330B0C00FCA411 /* banners.h */,
+ 72220F6D13330B0C00FCA411 /* cert.c */,
+ 72220F6E13330B0C00FCA411 /* cert.h */,
+ 72220F6F13330B0C00FCA411 /* classes.c */,
+ 72220F7013330B0C00FCA411 /* classes.h */,
+ 72220F7113330B0C00FCA411 /* client.c */,
+ 72220F7213330B0C00FCA411 /* client.h */,
+ 72220F7313330B0C00FCA411 /* conf.c */,
+ 72220F7413330B0C00FCA411 /* conf.h */,
+ 72220F7513330B0C00FCA411 /* cupsd.h */,
+ 72220F7613330B0C00FCA411 /* dirsvc.c */,
+ 72220F7713330B0C00FCA411 /* dirsvc.h */,
+ 72220F7813330B0C00FCA411 /* env.c */,
+ 72C16CB8137B195D007E4BF4 /* file.c */,
+ 72220F7913330B0C00FCA411 /* ipp.c */,
+ 72220F7A13330B0C00FCA411 /* job.c */,
+ 72220F7B13330B0C00FCA411 /* job.h */,
+ 72220F7C13330B0C00FCA411 /* listen.c */,
+ 72220F7D13330B0C00FCA411 /* log.c */,
+ 72220F7E13330B0C00FCA411 /* main.c */,
+ 72220F7F13330B0C00FCA411 /* network.c */,
+ 72220F8013330B0C00FCA411 /* network.h */,
+ 72220F8113330B0C00FCA411 /* policy.c */,
+ 72220F8213330B0C00FCA411 /* policy.h */,
+ 72220F8313330B0C00FCA411 /* printers.c */,
+ 72220F8413330B0C00FCA411 /* printers.h */,
+ 72220F8513330B0C00FCA411 /* process.c */,
+ 72220F8613330B0C00FCA411 /* quotas.c */,
+ 72220F8813330B0C00FCA411 /* select.c */,
+ 72220F8913330B0C00FCA411 /* server.c */,
+ 72220F8A13330B0C00FCA411 /* statbuf.c */,
+ 72220F8B13330B0C00FCA411 /* statbuf.h */,
+ 72220F8C13330B0C00FCA411 /* subscriptions.c */,
+ 72220F8D13330B0C00FCA411 /* subscriptions.h */,
+ 72220F8E13330B0C00FCA411 /* sysman.c */,
+ 72220F8F13330B0C00FCA411 /* sysman.h */,
+ );
+ name = cupsd;
+ path = .;
+ sourceTree = "<group>";
+ };
+ 72220FB013330B3400FCA411 /* libcupsmime */ = {
+ isa = PBXGroup;
+ children = (
+ 72220FB213330BCE00FCA411 /* filter.c */,
+ 72220FB313330BCE00FCA411 /* mime.c */,
+ 72220FB513330BCE00FCA411 /* type.c */,
+ );
+ name = libcupsmime;
+ sourceTree = "<group>";
+ };
+ 72220FB113330B4A00FCA411 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 278C58F4136B652300836530 /* Security.framework */,
+ 278C58E5136B64AF00836530 /* CoreFoundation.framework */,
+ 278C58E6136B64B000836530 /* Kerberos.framework */,
+ 278C58E7136B64B000836530 /* Security.framework */,
+ 278C58E8136B64B000836530 /* SystemConfiguration.framework */,
+ 278C58DA136B645C00836530 /* CoreFoundation.framework */,
+ 278C58DB136B645C00836530 /* Kerberos.framework */,
+ 278C58DD136B645C00836530 /* SystemConfiguration.framework */,
+ 72220FAC13330B2200FCA411 /* libcupsmime.dylib */,
+ 72220EAE1333047D00FCA411 /* libcups.dylib */,
+ 72F75A611336F9A3004BB496 /* libcupsimage.dylib */,
+ 274FF5EE133330C800317ECB /* libcupsppdc.dylib */,
+ 724379C81333FFF3009631B9 /* CoreFoundation.framework */,
+ 724379671333FF3B009631B9 /* IOKit.framework */,
+ 273BF6D51333B5F60022CAAB /* libresolv.dylib */,
+ 273BF6D61333B5F60022CAAB /* SystemConfiguration.framework */,
+ 273BF6D11333B5C30022CAAB /* Kerberos.framework */,
+ 273BF6D21333B5C30022CAAB /* Security.framework */,
+ 273BF6CB1333B5950022CAAB /* CoreFoundation.framework */,
+ 273BF6CC1333B5950022CAAB /* libiconv.dylib */,
+ 273BF6CD1333B5950022CAAB /* libz.dylib */,
+ 7263EE3913330EC500BA4D44 /* libldap.dylib */,
+ 7263EE3713330E7500BA4D44 /* libz.dylib */,
+ 7263EE3513330E4E00BA4D44 /* CoreFoundation.framework */,
+ 7263EE3313330E3C00BA4D44 /* libresolv.dylib */,
+ 7263EE3113330E1E00BA4D44 /* libpthread.dylib */,
+ 7263EE2F13330DC100BA4D44 /* IOKit.framework */,
+ 7263EE2913330D5C00BA4D44 /* Kerberos.framework */,
+ 7263EE2A13330D5C00BA4D44 /* Security.framework */,
+ 7263EE2B13330D5C00BA4D44 /* SystemConfiguration.framework */,
+ 7263EE2613330D2800BA4D44 /* libpam.dylib */,
+ 72220F6713330A8500FCA411 /* ApplicationServices.framework */,
+ 72220F49133306BB00FCA411 /* CoreFoundation.framework */,
+ 72220F55133308EA00FCA411 /* Kerberos.framework */,
+ 72220F4B133306BB00FCA411 /* Security.framework */,
+ 72220F4C133306BB00FCA411 /* SystemConfiguration.framework */,
+ 72220F51133308C100FCA411 /* libiconv.dylib */,
+ 72220F53133308CB00FCA411 /* libresolv.dylib */,
+ 72220F4A133306BB00FCA411 /* libz.dylib */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 724378F71333E3CE009631B9 /* backends */ = {
+ isa = PBXGroup;
+ children = (
+ 724379091333E4E3009631B9 /* backend-private.h */,
+ 724379501333FEBB009631B9 /* dnssd.c */,
+ 724379CA1334000E009631B9 /* ieee1284.c */,
+ 7243790A1333E4E3009631B9 /* ipp.c */,
+ 724379281333E952009631B9 /* lpd.c */,
+ 7243790B1333E4E3009631B9 /* network.c */,
+ 724379121333E516009631B9 /* runloop.c */,
+ 720DD6D21358FDDE0064AA82 /* snmp.c */,
+ 7243790C1333E4E3009631B9 /* snmp-supplies.c */,
+ 7243793C1333FD19009631B9 /* socket.c */,
+ 724379C51333FFC7009631B9 /* usb.c */,
+ 724379C41333FFC7009631B9 /* usb-darwin.c */,
+ );
+ name = backends;
+ sourceTree = "<group>";
+ };
+ 7258EADC134594A8009286F1 /* filters */ = {
+ isa = PBXGroup;
+ children = (
+ 7271881613746EA8001A2036 /* bannertops.c */,
+ 7271881713746EA8001A2036 /* commandtops.c */,
+ 7271881813746EA8001A2036 /* common.c */,
+ 7271881913746EA8001A2036 /* common.h */,
+ 7271881A13746EA8001A2036 /* gziptoany.c */,
+ 7271881B13746EA8001A2036 /* imagetops.c */,
+ 7271881C13746EA8001A2036 /* imagetoraster.c */,
+ 7271881D13746EA8001A2036 /* pdftops.c */,
+ 7271881E13746EA8001A2036 /* pstext.c */,
+ 7271881F13746EA8001A2036 /* pstext.h */,
+ 7271882013746EA8001A2036 /* pstops.c */,
+ 7271882113746EA8001A2036 /* rastertoepson.c */,
+ 7271882213746EA8001A2036 /* rastertohp.c */,
+ 7271882313746EA8001A2036 /* rastertolabel.c */,
+ 7258EAEC134594EB009286F1 /* rastertopwg.c */,
+ 7271882413746EA8001A2036 /* textcommon.c */,
+ 7271882513746EA8001A2036 /* textcommon.h */,
+ 7271882613746EA8001A2036 /* texttops.c */,
+ );
+ name = filters;
+ sourceTree = "<group>";
+ };
+ 7271882A1374988C001A2036 /* Unused */ = {
+ isa = PBXGroup;
+ children = (
+ 7271882B137498E4001A2036 /* image-bmp.c */,
+ 7271882C137498E4001A2036 /* image-colorspace.c */,
+ 7271882D137498E4001A2036 /* image-gif.c */,
+ 7271882E137498E4001A2036 /* image-jpeg.c */,
+ 7271882F137498E4001A2036 /* image-photocd.c */,
+ 72718830137498E4001A2036 /* image-pix.c */,
+ 72718831137498E4001A2036 /* image-png.c */,
+ 72718832137498E4001A2036 /* image-pnm.c */,
+ 72718833137498E4001A2036 /* image-private.h */,
+ 72718834137498E4001A2036 /* image-sgi.c */,
+ 72718835137498E4001A2036 /* image-sgi.h */,
+ 72718836137498E4001A2036 /* image-sgilib.c */,
+ 72718837137498E4001A2036 /* image-sun.c */,
+ 72718838137498E4001A2036 /* image-tiff.c */,
+ 72718839137498E4001A2036 /* image-zoom.c */,
+ 7271883A137498E4001A2036 /* image.c */,
+ 7271883B137498E4001A2036 /* image.h */,
+ );
+ name = Unused;
+ sourceTree = "<group>";
+ };
+ 72BF96351333042100B1EAD7 = {
+ isa = PBXGroup;
+ children = (
+ 72F75A4C1336F31B004BB496 /* libcups_static.a */,
+ 72220FB113330B4A00FCA411 /* Frameworks */,
+ 72220F45133305D000FCA411 /* Public Headers */,
+ 72220F461333060C00FCA411 /* Private Headers */,
+ 72220EB41333050100FCA411 /* libcups */,
+ 72F75A681336FA42004BB496 /* libcupsimage */,
+ 72220FB013330B3400FCA411 /* libcupsmime */,
+ 274FF5F41333310400317ECB /* libcupsppdc */,
+ 724378F71333E3CE009631B9 /* backends */,
+ 274FF67313333B0A00317ECB /* commands */,
+ 72220F5D13330A5A00FCA411 /* cupsd */,
+ 274FF5D513332C2C00317ECB /* daemon */,
+ 7258EADC134594A8009286F1 /* filters */,
+ 276683CB1337B1CC000D33D0 /* ppdc tools */,
+ 273BF6B81333B4A90022CAAB /* tests */,
+ 72220EAF1333047D00FCA411 /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ 72F75A681336FA42004BB496 /* libcupsimage */ = {
+ isa = PBXGroup;
+ children = (
+ 7271882A1374988C001A2036 /* Unused */,
+ 72F75A691336FA8A004BB496 /* error.c */,
+ 72F75A6A1336FA8A004BB496 /* interpret.c */,
+ 72F75A6B1336FA8A004BB496 /* raster.c */,
+ );
+ name = libcupsimage;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 274FF5EC133330C800317ECB /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF61E1333315100317ECB /* ppdc.h in Headers */,
+ 274FF6181333315100317ECB /* ppdc-private.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF6C11333B1C400317ECB /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF6C21333B1C400317ECB /* adminutil.h in Headers */,
+ 274FF6C31333B1C400317ECB /* array.h in Headers */,
+ 274FF6C41333B1C400317ECB /* backend.h in Headers */,
+ 274FF6D01333B1C400317ECB /* cups-private.h in Headers */,
+ 274FF6D11333B1C400317ECB /* debug-private.h in Headers */,
+ 274FF6D21333B1C400317ECB /* file-private.h in Headers */,
+ 274FF6D31333B1C400317ECB /* http-private.h in Headers */,
+ 274FF6D41333B1C400317ECB /* ipp-private.h in Headers */,
+ 274FF6D51333B1C400317ECB /* language-private.h in Headers */,
+ 274FF6D61333B1C400317ECB /* md5-private.h in Headers */,
+ 274FF6D71333B1C400317ECB /* ppd-private.h in Headers */,
+ 274FF6D81333B1C400317ECB /* pwg-private.h in Headers */,
+ 274FF6D91333B1C400317ECB /* snmp-private.h in Headers */,
+ 274FF6DA1333B1C400317ECB /* string-private.h in Headers */,
+ 274FF6DB1333B1C400317ECB /* thread-private.h in Headers */,
+ 274FF6DC1333B1C400317ECB /* config.h in Headers */,
+ 274FF6C51333B1C400317ECB /* cups.h in Headers */,
+ 274FF6C61333B1C400317ECB /* dir.h in Headers */,
+ 274FF6C71333B1C400317ECB /* file.h in Headers */,
+ 274FF6C81333B1C400317ECB /* http.h in Headers */,
+ 274FF6C91333B1C400317ECB /* ipp.h in Headers */,
+ 274FF6CA1333B1C400317ECB /* language.h in Headers */,
+ 274FF6CB1333B1C400317ECB /* ppd.h in Headers */,
+ 274FF6CD1333B1C400317ECB /* sidechannel.h in Headers */,
+ 274FF6CE1333B1C400317ECB /* transcode.h in Headers */,
+ 274FF6CF1333B1C400317ECB /* versioning.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72220EAC1333047D00FCA411 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72220EC41333056300FCA411 /* adminutil.h in Headers */,
+ 72220EC61333056300FCA411 /* array.h in Headers */,
+ 72220ECB1333056300FCA411 /* backend.h in Headers */,
+ 72220ECE1333056300FCA411 /* cups.h in Headers */,
+ 72220F0E133305BB00FCA411 /* dir.h in Headers */,
+ 72220F13133305BB00FCA411 /* file.h in Headers */,
+ 72220F1D133305BB00FCA411 /* http.h in Headers */,
+ 72220F21133305BB00FCA411 /* ipp.h in Headers */,
+ 72220F25133305BB00FCA411 /* language.h in Headers */,
+ 72220F31133305BB00FCA411 /* ppd.h in Headers */,
+ 72220F37133305BB00FCA411 /* sidechannel.h in Headers */,
+ 72220F41133305BB00FCA411 /* transcode.h in Headers */,
+ 72220F44133305BB00FCA411 /* versioning.h in Headers */,
+ 72220ECD1333056300FCA411 /* cups-private.h in Headers */,
+ 72220ED01333056300FCA411 /* debug-private.h in Headers */,
+ 72220F11133305BB00FCA411 /* file-private.h in Headers */,
+ 72220F1A133305BB00FCA411 /* http-private.h in Headers */,
+ 72220F1E133305BB00FCA411 /* ipp-private.h in Headers */,
+ 72220F23133305BB00FCA411 /* language-private.h in Headers */,
+ 72220F28133305BB00FCA411 /* md5-private.h in Headers */,
+ 72220F2F133305BB00FCA411 /* ppd-private.h in Headers */,
+ 72220F33133305BB00FCA411 /* pwg-private.h in Headers */,
+ 72220F38133305BB00FCA411 /* snmp-private.h in Headers */,
+ 72220F3B133305BB00FCA411 /* string-private.h in Headers */,
+ 72220F3E133305BB00FCA411 /* thread-private.h in Headers */,
+ 72220F481333063D00FCA411 /* config.h in Headers */,
+ 7234F4201378A16F00D3E9C9 /* array-private.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72220FAA13330B2200FCA411 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72220FB813330BCE00FCA411 /* mime.h in Headers */,
+ 7271883D1374AB14001A2036 /* mime-private.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72F75A5F1336F9A3004BB496 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72F75A6F1336FAB6004BB496 /* raster.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 270CCDA6135E3C9E00007BE2 /* testmime */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 270CCDAF135E3C9E00007BE2 /* Build configuration list for PBXNativeTarget "testmime" */;
+ buildPhases = (
+ 270CCDA3135E3C9E00007BE2 /* Sources */,
+ 270CCDA4135E3C9E00007BE2 /* Frameworks */,
+ 270CCDA5135E3C9E00007BE2 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 270CCDB8135E3CFD00007BE2 /* PBXTargetDependency */,
+ 270CCDB6135E3CF700007BE2 /* PBXTargetDependency */,
+ );
+ name = testmime;
+ productName = testmime;
+ productReference = 270CCDA7135E3C9E00007BE2 /* testmime */;
+ productType = "com.apple.product-type.tool";
+ };
+ 273BF6BC1333B5000022CAAB /* testcups */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 273BF6C31333B5000022CAAB /* Build configuration list for PBXNativeTarget "testcups" */;
+ buildPhases = (
+ 273BF6B91333B5000022CAAB /* Sources */,
+ 273BF6BA1333B5000022CAAB /* Frameworks */,
+ 273BF6BB1333B5000022CAAB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 273BF6C91333B5410022CAAB /* PBXTargetDependency */,
+ );
+ name = testcups;
+ productName = testcups;
+ productReference = 273BF6BD1333B5000022CAAB /* testcups */;
+ productType = "com.apple.product-type.tool";
+ };
+ 274FF5CB13332B1F00317ECB /* cups-driverd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 274FF5D213332B1F00317ECB /* Build configuration list for PBXNativeTarget "cups-driverd" */;
+ buildPhases = (
+ 274FF5C813332B1F00317ECB /* Sources */,
+ 274FF5C913332B1F00317ECB /* Frameworks */,
+ 274FF5CA13332B1F00317ECB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 274FF5DC13332CF900317ECB /* PBXTargetDependency */,
+ 274FF6201333316200317ECB /* PBXTargetDependency */,
+ );
+ name = "cups-driverd";
+ productName = "cups-driverd";
+ productReference = 274FF5CC13332B1F00317ECB /* cups-driverd */;
+ productType = "com.apple.product-type.tool";
+ };
+ 274FF5ED133330C800317ECB /* libcupsppdc */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 274FF5EF133330C800317ECB /* Build configuration list for PBXNativeTarget "libcupsppdc" */;
+ buildPhases = (
+ 274FF5EA133330C800317ECB /* Sources */,
+ 274FF5EB133330C800317ECB /* Frameworks */,
+ 274FF5EC133330C800317ECB /* Headers */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 274FF5F3133330FD00317ECB /* PBXTargetDependency */,
+ );
+ name = libcupsppdc;
+ productName = libcupsppdc;
+ productReference = 274FF5EE133330C800317ECB /* libcupsppdc.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+ 274FF6281333333600317ECB /* cups-deviced */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 274FF62F1333333600317ECB /* Build configuration list for PBXNativeTarget "cups-deviced" */;
+ buildPhases = (
+ 274FF6251333333600317ECB /* Sources */,
+ 274FF6261333333600317ECB /* Frameworks */,
+ 274FF6271333333600317ECB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 274FF6341333335200317ECB /* PBXTargetDependency */,
+ );
+ name = "cups-deviced";
+ productName = "cups-deviced";
+ productReference = 274FF6291333333600317ECB /* cups-deviced */;
+ productType = "com.apple.product-type.tool";
+ };
+ 274FF63D1333358B00317ECB /* cups-exec */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 274FF6441333358C00317ECB /* Build configuration list for PBXNativeTarget "cups-exec" */;
+ buildPhases = (
+ 274FF63A1333358B00317ECB /* Sources */,
+ 274FF63B1333358B00317ECB /* Frameworks */,
+ 274FF63C1333358B00317ECB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "cups-exec";
+ productName = "cups-exec";
+ productReference = 274FF63E1333358B00317ECB /* cups-exec */;
+ productType = "com.apple.product-type.tool";
+ };
+ 274FF64E133339C400317ECB /* cups-lpd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 274FF655133339C400317ECB /* Build configuration list for PBXNativeTarget "cups-lpd" */;
+ buildPhases = (
+ 274FF64B133339C400317ECB /* Sources */,
+ 274FF64C133339C400317ECB /* Frameworks */,
+ 274FF64D133339C400317ECB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 274FF65A133339D900317ECB /* PBXTargetDependency */,
+ );
+ name = "cups-lpd";
+ productName = "cups-lpd";
+ productReference = 274FF64F133339C400317ECB /* cups-lpd */;
+ productType = "com.apple.product-type.tool";
+ };
+ 274FF66213333A9B00317ECB /* cups-polld */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 274FF66913333A9B00317ECB /* Build configuration list for PBXNativeTarget "cups-polld" */;
+ buildPhases = (
+ 274FF65F13333A9B00317ECB /* Sources */,
+ 274FF66013333A9B00317ECB /* Frameworks */,
+ 274FF66113333A9B00317ECB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 274FF66D13333AAD00317ECB /* PBXTargetDependency */,
+ );
+ name = "cups-polld";
+ productName = "cups-polld";
+ productReference = 274FF66313333A9B00317ECB /* cups-polld */;
+ productType = "com.apple.product-type.tool";
+ };
+ 274FF67713333B2F00317ECB /* cupsfilter */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 274FF67E13333B2F00317ECB /* Build configuration list for PBXNativeTarget "cupsfilter" */;
+ buildPhases = (
+ 274FF67413333B2F00317ECB /* Sources */,
+ 274FF67513333B2F00317ECB /* Frameworks */,
+ 274FF67613333B2F00317ECB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 274FF68213333B3C00317ECB /* PBXTargetDependency */,
+ 274FF68413333B3C00317ECB /* PBXTargetDependency */,
+ );
+ name = cupsfilter;
+ productName = cupsfilter;
+ productReference = 274FF67813333B2F00317ECB /* cupsfilter */;
+ productType = "com.apple.product-type.tool";
+ };
+ 274FF6891333B1C400317ECB /* libcups_static */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 274FF6DD1333B1C400317ECB /* Build configuration list for PBXNativeTarget "libcups_static" */;
+ buildPhases = (
+ 274FF68A1333B1C400317ECB /* Sources */,
+ 274FF6B91333B1C400317ECB /* Frameworks */,
+ 274FF6C11333B1C400317ECB /* Headers */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = libcups_static;
+ productName = libcups;
+ productReference = 72F75A4C1336F31B004BB496 /* libcups_static.a */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+ 2766835B1337A9B6000D33D0 /* cupsctl */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 276683621337A9B6000D33D0 /* Build configuration list for PBXNativeTarget "cupsctl" */;
+ buildPhases = (
+ 276683581337A9B6000D33D0 /* Sources */,
+ 276683591337A9B6000D33D0 /* Frameworks */,
+ 2766835A1337A9B6000D33D0 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 276683661337A9D6000D33D0 /* PBXTargetDependency */,
+ );
+ name = cupsctl;
+ productName = cupsctl;
+ productReference = 2766835C1337A9B6000D33D0 /* cupsctl */;
+ productType = "com.apple.product-type.tool";
+ };
+ 2766836F1337AC79000D33D0 /* ppdc */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 276683761337AC79000D33D0 /* Build configuration list for PBXNativeTarget "ppdc" */;
+ buildPhases = (
+ 2766836C1337AC79000D33D0 /* Sources */,
+ 2766836D1337AC79000D33D0 /* Frameworks */,
+ 2766836E1337AC79000D33D0 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 276683AE1337ACF9000D33D0 /* PBXTargetDependency */,
+ 276683B01337ACF9000D33D0 /* PBXTargetDependency */,
+ );
+ name = ppdc;
+ productName = ppdc;
+ productReference = 276683701337AC79000D33D0 /* ppdc */;
+ productType = "com.apple.product-type.tool";
+ };
+ 2766837C1337AC8C000D33D0 /* ppdhtml */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 276683831337AC8C000D33D0 /* Build configuration list for PBXNativeTarget "ppdhtml" */;
+ buildPhases = (
+ 276683791337AC8C000D33D0 /* Sources */,
+ 2766837A1337AC8C000D33D0 /* Frameworks */,
+ 2766837B1337AC8C000D33D0 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 276683B41337AD18000D33D0 /* PBXTargetDependency */,
+ 276683B61337AD18000D33D0 /* PBXTargetDependency */,
+ );
+ name = ppdhtml;
+ productName = ppdhtml;
+ productReference = 2766837D1337AC8C000D33D0 /* ppdhtml */;
+ productType = "com.apple.product-type.tool";
+ };
+ 276683891337AC97000D33D0 /* ppdi */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 276683901337AC97000D33D0 /* Build configuration list for PBXNativeTarget "ppdi" */;
+ buildPhases = (
+ 276683861337AC97000D33D0 /* Sources */,
+ 276683871337AC97000D33D0 /* Frameworks */,
+ 276683881337AC97000D33D0 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 276683BC1337AE49000D33D0 /* PBXTargetDependency */,
+ 276683BE1337AE49000D33D0 /* PBXTargetDependency */,
+ );
+ name = ppdi;
+ productName = ppdi;
+ productReference = 2766838A1337AC97000D33D0 /* ppdi */;
+ productType = "com.apple.product-type.tool";
+ };
+ 276683961337ACA2000D33D0 /* ppdmerge */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2766839D1337ACA2000D33D0 /* Build configuration list for PBXNativeTarget "ppdmerge" */;
+ buildPhases = (
+ 276683931337ACA2000D33D0 /* Sources */,
+ 276683941337ACA2000D33D0 /* Frameworks */,
+ 276683951337ACA2000D33D0 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 276683C01337B1AD000D33D0 /* PBXTargetDependency */,
+ 276683C21337B1AD000D33D0 /* PBXTargetDependency */,
+ );
+ name = ppdmerge;
+ productName = ppdmerge;
+ productReference = 276683971337ACA2000D33D0 /* ppdmerge */;
+ productType = "com.apple.product-type.tool";
+ };
+ 276683A31337ACAB000D33D0 /* ppdpo */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 276683AA1337ACAB000D33D0 /* Build configuration list for PBXNativeTarget "ppdpo" */;
+ buildPhases = (
+ 276683A01337ACAB000D33D0 /* Sources */,
+ 276683A11337ACAB000D33D0 /* Frameworks */,
+ 276683A21337ACAB000D33D0 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 276683C61337B1BC000D33D0 /* PBXTargetDependency */,
+ 276683C81337B1BC000D33D0 /* PBXTargetDependency */,
+ );
+ name = ppdpo;
+ productName = ppdpo;
+ productReference = 276683A41337ACAB000D33D0 /* ppdpo */;
+ productType = "com.apple.product-type.tool";
+ };
+ 276683EF1337F78E000D33D0 /* ipptool */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 276683F61337F78F000D33D0 /* Build configuration list for PBXNativeTarget "ipptool" */;
+ buildPhases = (
+ 276683EC1337F78E000D33D0 /* Sources */,
+ 276683ED1337F78E000D33D0 /* Frameworks */,
+ 276683EE1337F78E000D33D0 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 276683FC1337F7B3000D33D0 /* PBXTargetDependency */,
+ );
+ name = ipptool;
+ productName = ipptool;
+ productReference = 276683F01337F78E000D33D0 /* ipptool */;
+ productType = "com.apple.product-type.tool";
+ };
+ 276684031337FA1D000D33D0 /* cupsaddsmb */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2766840A1337FA1E000D33D0 /* Build configuration list for PBXNativeTarget "cupsaddsmb" */;
+ buildPhases = (
+ 276684001337FA1D000D33D0 /* Sources */,
+ 276684011337FA1D000D33D0 /* Frameworks */,
+ 276684021337FA1D000D33D0 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 2766840E1337FA31000D33D0 /* PBXTargetDependency */,
+ );
+ name = cupsaddsmb;
+ productName = cupsaddsmb;
+ productReference = 276684041337FA1D000D33D0 /* cupsaddsmb */;
+ productType = "com.apple.product-type.tool";
+ };
+ 278C58CA136B640300836530 /* testhttp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 278C58D3136B640300836530 /* Build configuration list for PBXNativeTarget "testhttp" */;
+ buildPhases = (
+ 278C58C7136B640300836530 /* Sources */,
+ 278C58C8136B640300836530 /* Frameworks */,
+ 278C58C9136B640300836530 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 278C58D8136B642F00836530 /* PBXTargetDependency */,
+ );
+ name = testhttp;
+ productName = testhttp;
+ productReference = 278C58CB136B640300836530 /* testhttp */;
+ productType = "com.apple.product-type.tool";
+ };
+ 720DD6C11358FD5F0064AA82 /* snmp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 720DD6CB1358FD600064AA82 /* Build configuration list for PBXNativeTarget "snmp" */;
+ buildPhases = (
+ 720DD6BE1358FD5F0064AA82 /* Sources */,
+ 720DD6BF1358FD5F0064AA82 /* Frameworks */,
+ 720DD6C01358FD5F0064AA82 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 720DD6CF1358FD790064AA82 /* PBXTargetDependency */,
+ );
+ name = snmp;
+ productName = snmp;
+ productReference = 720DD6C21358FD5F0064AA82 /* snmp */;
+ productType = "com.apple.product-type.tool";
+ };
+ 72220EAD1333047D00FCA411 /* libcups */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 72220EB21333047D00FCA411 /* Build configuration list for PBXNativeTarget "libcups" */;
+ buildPhases = (
+ 72220EAA1333047D00FCA411 /* Sources */,
+ 72220EAB1333047D00FCA411 /* Frameworks */,
+ 72220EAC1333047D00FCA411 /* Headers */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = libcups;
+ productName = libcups;
+ productReference = 72220EAE1333047D00FCA411 /* libcups.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+ 72220F5A13330A5A00FCA411 /* cupsd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 72220F6113330A5A00FCA411 /* Build configuration list for PBXNativeTarget "cupsd" */;
+ buildPhases = (
+ 72220F5713330A5A00FCA411 /* Sources */,
+ 72220F5813330A5A00FCA411 /* Frameworks */,
+ 72220F5913330A5A00FCA411 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 72220FBE13330C0B00FCA411 /* PBXTargetDependency */,
+ 72220F6513330A6500FCA411 /* PBXTargetDependency */,
+ );
+ name = cupsd;
+ productName = cupsd;
+ productReference = 72220F5B13330A5A00FCA411 /* cupsd */;
+ productType = "com.apple.product-type.tool";
+ };
+ 72220FAB13330B2200FCA411 /* libcupsmime */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 72220FAD13330B2300FCA411 /* Build configuration list for PBXNativeTarget "libcupsmime" */;
+ buildPhases = (
+ 72220FA813330B2200FCA411 /* Sources */,
+ 72220FA913330B2200FCA411 /* Frameworks */,
+ 72220FAA13330B2200FCA411 /* Headers */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 72220FBC13330C0500FCA411 /* PBXTargetDependency */,
+ );
+ name = libcupsmime;
+ productName = libcupsmime;
+ productReference = 72220FAC13330B2200FCA411 /* libcupsmime.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+ 724378FC1333E43E009631B9 /* ipp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 724379031333E43E009631B9 /* Build configuration list for PBXNativeTarget "ipp" */;
+ buildPhases = (
+ 724378F91333E43E009631B9 /* Sources */,
+ 724378FA1333E43E009631B9 /* Frameworks */,
+ 724378FB1333E43E009631B9 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 724379071333E49B009631B9 /* PBXTargetDependency */,
+ );
+ name = ipp;
+ productName = ipp;
+ productReference = 724378FD1333E43E009631B9 /* ipp */;
+ productType = "com.apple.product-type.tool";
+ };
+ 724379171333E532009631B9 /* lpd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7243791E1333E532009631B9 /* Build configuration list for PBXNativeTarget "lpd" */;
+ buildPhases = (
+ 724379141333E532009631B9 /* Sources */,
+ 724379151333E532009631B9 /* Frameworks */,
+ 724379161333E532009631B9 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 724379261333E932009631B9 /* PBXTargetDependency */,
+ );
+ name = lpd;
+ productName = lpd;
+ productReference = 724379181333E532009631B9 /* lpd */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7243792F1333FB85009631B9 /* socket */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 724379361333FB85009631B9 /* Build configuration list for PBXNativeTarget "socket" */;
+ buildPhases = (
+ 7243792C1333FB85009631B9 /* Sources */,
+ 7243792D1333FB85009631B9 /* Frameworks */,
+ 7243792E1333FB85009631B9 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 7243793A1333FB95009631B9 /* PBXTargetDependency */,
+ );
+ name = socket;
+ productName = socket;
+ productReference = 724379301333FB85009631B9 /* socket */;
+ productType = "com.apple.product-type.tool";
+ };
+ 724379461333FEA9009631B9 /* dnssd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7243794D1333FEA9009631B9 /* Build configuration list for PBXNativeTarget "dnssd" */;
+ buildPhases = (
+ 724379431333FEA9009631B9 /* Sources */,
+ 724379441333FEA9009631B9 /* Frameworks */,
+ 724379451333FEA9009631B9 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 724379551333FEFE009631B9 /* PBXTargetDependency */,
+ );
+ name = dnssd;
+ productName = dnssd;
+ productReference = 724379471333FEA9009631B9 /* dnssd */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7243795A1333FF1D009631B9 /* usb */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 724379611333FF1D009631B9 /* Build configuration list for PBXNativeTarget "usb" */;
+ buildPhases = (
+ 724379571333FF1D009631B9 /* Sources */,
+ 724379581333FF1D009631B9 /* Frameworks */,
+ 724379591333FF1D009631B9 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 724379651333FF2E009631B9 /* PBXTargetDependency */,
+ );
+ name = usb;
+ productName = usb;
+ productReference = 7243795B1333FF1D009631B9 /* usb */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7258EAE1134594C4009286F1 /* rastertopwg */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7258EAE9134594C4009286F1 /* Build configuration list for PBXNativeTarget "rastertopwg" */;
+ buildPhases = (
+ 7258EADE134594C4009286F1 /* Sources */,
+ 7258EADF134594C4009286F1 /* Frameworks */,
+ 7258EAE0134594C4009286F1 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 7258EAF113459B67009286F1 /* PBXTargetDependency */,
+ 7258EAF313459B67009286F1 /* PBXTargetDependency */,
+ );
+ name = rastertopwg;
+ productName = rastertopwg;
+ productReference = 7258EAE2134594C4009286F1 /* rastertopwg */;
+ productType = "com.apple.product-type.tool";
+ };
+ 726AD6F6135E88F0002C930D /* ippserver */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 726AD6FE135E88F1002C930D /* Build configuration list for PBXNativeTarget "ippserver" */;
+ buildPhases = (
+ 726AD6F3135E88F0002C930D /* Sources */,
+ 726AD6F4135E88F0002C930D /* Frameworks */,
+ 726AD6F5135E88F0002C930D /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 726AD706135E8AC5002C930D /* PBXTargetDependency */,
+ );
+ name = ippserver;
+ productName = ippserver;
+ productReference = 726AD6F7135E88F0002C930D /* ippserver */;
+ productType = "com.apple.product-type.tool";
+ };
+ 72F75A511336F950004BB496 /* cupstestppd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 72F75A581336F951004BB496 /* Build configuration list for PBXNativeTarget "cupstestppd" */;
+ buildPhases = (
+ 72F75A4E1336F950004BB496 /* Sources */,
+ 72F75A4F1336F950004BB496 /* Frameworks */,
+ 72F75A501336F950004BB496 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 276683E41337B2BA000D33D0 /* PBXTargetDependency */,
+ 276683E11337B299000D33D0 /* PBXTargetDependency */,
+ );
+ name = cupstestppd;
+ productName = cupstestppd;
+ productReference = 72F75A521336F950004BB496 /* cupstestppd */;
+ productType = "com.apple.product-type.tool";
+ };
+ 72F75A601336F9A3004BB496 /* libcupsimage */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 72F75A621336F9A3004BB496 /* Build configuration list for PBXNativeTarget "libcupsimage" */;
+ buildPhases = (
+ 72F75A5D1336F9A3004BB496 /* Sources */,
+ 72F75A5E1336F9A3004BB496 /* Frameworks */,
+ 72F75A5F1336F9A3004BB496 /* Headers */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 72F75A661336FA30004BB496 /* PBXTargetDependency */,
+ );
+ name = libcupsimage;
+ productName = libcupsimage;
+ productReference = 72F75A611336F9A3004BB496 /* libcupsimage.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 72BF96371333042100B1EAD7 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0410;
+ ORGANIZATIONNAME = "Apple Inc.";
+ };
+ buildConfigurationList = 72BF963A1333042100B1EAD7 /* Build configuration list for PBXProject "CUPS" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 72BF96351333042100B1EAD7;
+ productRefGroup = 72220EAF1333047D00FCA411 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 274FF5DE13332D3000317ECB /* All */,
+ 273BF6D91333B6260022CAAB /* Tests */,
+ 72220EAD1333047D00FCA411 /* libcups */,
+ 274FF6891333B1C400317ECB /* libcups_static */,
+ 72F75A601336F9A3004BB496 /* libcupsimage */,
+ 72220FAB13330B2200FCA411 /* libcupsmime */,
+ 274FF5ED133330C800317ECB /* libcupsppdc */,
+ 276684031337FA1D000D33D0 /* cupsaddsmb */,
+ 2766835B1337A9B6000D33D0 /* cupsctl */,
+ 72220F5A13330A5A00FCA411 /* cupsd */,
+ 274FF5CB13332B1F00317ECB /* cups-driverd */,
+ 274FF6281333333600317ECB /* cups-deviced */,
+ 274FF63D1333358B00317ECB /* cups-exec */,
+ 274FF64E133339C400317ECB /* cups-lpd */,
+ 274FF66213333A9B00317ECB /* cups-polld */,
+ 274FF67713333B2F00317ECB /* cupsfilter */,
+ 72F75A511336F950004BB496 /* cupstestppd */,
+ 724379461333FEA9009631B9 /* dnssd */,
+ 724378FC1333E43E009631B9 /* ipp */,
+ 726AD6F6135E88F0002C930D /* ippserver */,
+ 276683EF1337F78E000D33D0 /* ipptool */,
+ 724379171333E532009631B9 /* lpd */,
+ 2766836F1337AC79000D33D0 /* ppdc */,
+ 2766837C1337AC8C000D33D0 /* ppdhtml */,
+ 276683891337AC97000D33D0 /* ppdi */,
+ 276683961337ACA2000D33D0 /* ppdmerge */,
+ 276683A31337ACAB000D33D0 /* ppdpo */,
+ 7258EAE1134594C4009286F1 /* rastertopwg */,
+ 720DD6C11358FD5F0064AA82 /* snmp */,
+ 7243792F1333FB85009631B9 /* socket */,
+ 273BF6BC1333B5000022CAAB /* testcups */,
+ 278C58CA136B640300836530 /* testhttp */,
+ 270CCDA6135E3C9E00007BE2 /* testmime */,
+ 7243795A1333FF1D009631B9 /* usb */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 270CCDA3135E3C9E00007BE2 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 270CCDBC135E3D3E00007BE2 /* testmime.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 273BF6B91333B5000022CAAB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 273BF6C71333B5370022CAAB /* testcups.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF5C813332B1F00317ECB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF5D913332CC700317ECB /* cups-driverd.cxx in Sources */,
+ 274FF5DA13332CC700317ECB /* util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF5EA133330C800317ECB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF60A1333315100317ECB /* ppdc-array.cxx in Sources */,
+ 274FF60B1333315100317ECB /* ppdc-attr.cxx in Sources */,
+ 274FF60C1333315100317ECB /* ppdc-catalog.cxx in Sources */,
+ 274FF60D1333315100317ECB /* ppdc-choice.cxx in Sources */,
+ 274FF60E1333315100317ECB /* ppdc-constraint.cxx in Sources */,
+ 274FF60F1333315100317ECB /* ppdc-driver.cxx in Sources */,
+ 274FF6101333315100317ECB /* ppdc-file.cxx in Sources */,
+ 274FF6111333315100317ECB /* ppdc-filter.cxx in Sources */,
+ 274FF6121333315100317ECB /* ppdc-font.cxx in Sources */,
+ 274FF6131333315100317ECB /* ppdc-group.cxx in Sources */,
+ 274FF6141333315100317ECB /* ppdc-import.cxx in Sources */,
+ 274FF6151333315100317ECB /* ppdc-mediasize.cxx in Sources */,
+ 274FF6161333315100317ECB /* ppdc-message.cxx in Sources */,
+ 274FF6171333315100317ECB /* ppdc-option.cxx in Sources */,
+ 274FF6191333315100317ECB /* ppdc-profile.cxx in Sources */,
+ 274FF61A1333315100317ECB /* ppdc-shared.cxx in Sources */,
+ 274FF61B1333315100317ECB /* ppdc-source.cxx in Sources */,
+ 274FF61C1333315100317ECB /* ppdc-string.cxx in Sources */,
+ 274FF61D1333315100317ECB /* ppdc-variable.cxx in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF6251333333600317ECB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF6361333344400317ECB /* cups-deviced.c in Sources */,
+ 274FF6371333345900317ECB /* util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF63A1333358B00317ECB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF64A1333398D00317ECB /* cups-exec.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF64B133339C400317ECB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF65C133339FC00317ECB /* cups-lpd.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF65F13333A9B00317ECB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF67013333ACF00317ECB /* cups-polld.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF67413333B2F00317ECB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF68813333B6E00317ECB /* cupsfilter.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 274FF68A1333B1C400317ECB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 274FF68B1333B1C400317ECB /* adminutil.c in Sources */,
+ 274FF68C1333B1C400317ECB /* array.c in Sources */,
+ 274FF68D1333B1C400317ECB /* attr.c in Sources */,
+ 274FF68E1333B1C400317ECB /* auth.c in Sources */,
+ 274FF68F1333B1C400317ECB /* backchannel.c in Sources */,
+ 274FF6901333B1C400317ECB /* backend.c in Sources */,
+ 274FF6911333B1C400317ECB /* conflicts.c in Sources */,
+ 274FF6921333B1C400317ECB /* custom.c in Sources */,
+ 274FF6931333B1C400317ECB /* debug.c in Sources */,
+ 274FF6941333B1C400317ECB /* dest.c in Sources */,
+ 274FF6951333B1C400317ECB /* dir.c in Sources */,
+ 274FF6961333B1C400317ECB /* emit.c in Sources */,
+ 274FF6971333B1C400317ECB /* encode.c in Sources */,
+ 274FF6981333B1C400317ECB /* file.c in Sources */,
+ 274FF6991333B1C400317ECB /* getdevices.c in Sources */,
+ 274FF69A1333B1C400317ECB /* getifaddrs.c in Sources */,
+ 274FF69B1333B1C400317ECB /* getputfile.c in Sources */,
+ 274FF69C1333B1C400317ECB /* globals.c in Sources */,
+ 274FF69D1333B1C400317ECB /* http-addr.c in Sources */,
+ 274FF69E1333B1C400317ECB /* http-addrlist.c in Sources */,
+ 274FF69F1333B1C400317ECB /* http-support.c in Sources */,
+ 274FF6A01333B1C400317ECB /* http.c in Sources */,
+ 274FF6A11333B1C400317ECB /* ipp-support.c in Sources */,
+ 274FF6A21333B1C400317ECB /* ipp.c in Sources */,
+ 274FF6A31333B1C400317ECB /* langprintf.c in Sources */,
+ 274FF6A41333B1C400317ECB /* language.c in Sources */,
+ 274FF6A51333B1C400317ECB /* localize.c in Sources */,
+ 274FF6A61333B1C400317ECB /* mark.c in Sources */,
+ 274FF6A71333B1C400317ECB /* md5.c in Sources */,
+ 274FF6A81333B1C400317ECB /* md5passwd.c in Sources */,
+ 274FF6A91333B1C400317ECB /* notify.c in Sources */,
+ 274FF6AA1333B1C400317ECB /* options.c in Sources */,
+ 274FF6AB1333B1C400317ECB /* page.c in Sources */,
+ 274FF6AC1333B1C400317ECB /* ppd-cache.c in Sources */,
+ 274FF6AD1333B1C400317ECB /* ppd.c in Sources */,
+ 274FF6AE1333B1C400317ECB /* pwg-media.c in Sources */,
+ 274FF6AF1333B1C400317ECB /* request.c in Sources */,
+ 274FF6B01333B1C400317ECB /* sidechannel.c in Sources */,
+ 274FF6B11333B1C400317ECB /* snmp.c in Sources */,
+ 274FF6B21333B1C400317ECB /* snprintf.c in Sources */,
+ 274FF6B31333B1C400317ECB /* string.c in Sources */,
+ 274FF6B41333B1C400317ECB /* tempfile.c in Sources */,
+ 274FF6B51333B1C400317ECB /* thread.c in Sources */,
+ 274FF6B61333B1C400317ECB /* transcode.c in Sources */,
+ 274FF6B71333B1C400317ECB /* usersys.c in Sources */,
+ 274FF6B81333B1C400317ECB /* util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 276683581337A9B6000D33D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683691337AA00000D33D0 /* cupsctl.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2766836C1337AC79000D33D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683CD1337B201000D33D0 /* ppdc.cxx in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 276683791337AC8C000D33D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683CF1337B20D000D33D0 /* ppdhtml.cxx in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 276683861337AC97000D33D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683D11337B21A000D33D0 /* ppdi.cxx in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 276683931337ACA2000D33D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683D31337B228000D33D0 /* ppdmerge.cxx in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 276683A01337ACAB000D33D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683D51337B237000D33D0 /* ppdpo.cxx in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 276683EC1337F78E000D33D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276683FA1337F7A9000D33D0 /* ipptool.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 276684001337FA1D000D33D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 276684111337FA7C000D33D0 /* cupsaddsmb.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 278C58C7136B640300836530 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 278C58E3136B647200836530 /* testhttp.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 720DD6BE1358FD5F0064AA82 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 720DD6D413590AB90064AA82 /* ieee1284.c in Sources */,
+ 720DD6D31358FDDE0064AA82 /* snmp.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72220EAA1333047D00FCA411 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72220EB61333052D00FCA411 /* adminutil.c in Sources */,
+ 72220EC51333056300FCA411 /* array.c in Sources */,
+ 72220EC71333056300FCA411 /* attr.c in Sources */,
+ 72220EC81333056300FCA411 /* auth.c in Sources */,
+ 72220EC91333056300FCA411 /* backchannel.c in Sources */,
+ 72220ECA1333056300FCA411 /* backend.c in Sources */,
+ 72220ECC1333056300FCA411 /* conflicts.c in Sources */,
+ 72220ECF1333056300FCA411 /* custom.c in Sources */,
+ 72220F0B133305BB00FCA411 /* debug.c in Sources */,
+ 72220F0C133305BB00FCA411 /* dest.c in Sources */,
+ 72220F0D133305BB00FCA411 /* dir.c in Sources */,
+ 72220F0F133305BB00FCA411 /* emit.c in Sources */,
+ 72220F10133305BB00FCA411 /* encode.c in Sources */,
+ 72220F12133305BB00FCA411 /* file.c in Sources */,
+ 72220F14133305BB00FCA411 /* getdevices.c in Sources */,
+ 72220F15133305BB00FCA411 /* getifaddrs.c in Sources */,
+ 72220F16133305BB00FCA411 /* getputfile.c in Sources */,
+ 72220F17133305BB00FCA411 /* globals.c in Sources */,
+ 72220F18133305BB00FCA411 /* http-addr.c in Sources */,
+ 72220F19133305BB00FCA411 /* http-addrlist.c in Sources */,
+ 72220F1B133305BB00FCA411 /* http-support.c in Sources */,
+ 72220F1C133305BB00FCA411 /* http.c in Sources */,
+ 72220F1F133305BB00FCA411 /* ipp-support.c in Sources */,
+ 72220F20133305BB00FCA411 /* ipp.c in Sources */,
+ 72220F22133305BB00FCA411 /* langprintf.c in Sources */,
+ 72220F24133305BB00FCA411 /* language.c in Sources */,
+ 72220F26133305BB00FCA411 /* localize.c in Sources */,
+ 72220F27133305BB00FCA411 /* mark.c in Sources */,
+ 72220F29133305BB00FCA411 /* md5.c in Sources */,
+ 72220F2A133305BB00FCA411 /* md5passwd.c in Sources */,
+ 72220F2B133305BB00FCA411 /* notify.c in Sources */,
+ 72220F2C133305BB00FCA411 /* options.c in Sources */,
+ 72220F2D133305BB00FCA411 /* page.c in Sources */,
+ 72220F2E133305BB00FCA411 /* ppd-cache.c in Sources */,
+ 72220F30133305BB00FCA411 /* ppd.c in Sources */,
+ 72220F32133305BB00FCA411 /* pwg-media.c in Sources */,
+ 72220F35133305BB00FCA411 /* request.c in Sources */,
+ 72220F36133305BB00FCA411 /* sidechannel.c in Sources */,
+ 72220F39133305BB00FCA411 /* snmp.c in Sources */,
+ 72220F3A133305BB00FCA411 /* snprintf.c in Sources */,
+ 72220F3C133305BB00FCA411 /* string.c in Sources */,
+ 72220F3D133305BB00FCA411 /* tempfile.c in Sources */,
+ 72220F3F133305BB00FCA411 /* thread.c in Sources */,
+ 72220F40133305BB00FCA411 /* transcode.c in Sources */,
+ 72220F42133305BB00FCA411 /* usersys.c in Sources */,
+ 72220F43133305BB00FCA411 /* util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72220F5713330A5A00FCA411 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72220F9013330B0C00FCA411 /* auth.c in Sources */,
+ 72220F9113330B0C00FCA411 /* banners.c in Sources */,
+ 72220F9213330B0C00FCA411 /* cert.c in Sources */,
+ 72220F9313330B0C00FCA411 /* classes.c in Sources */,
+ 72220F9413330B0C00FCA411 /* client.c in Sources */,
+ 72220F9513330B0C00FCA411 /* conf.c in Sources */,
+ 72220F9613330B0C00FCA411 /* dirsvc.c in Sources */,
+ 72220F9713330B0C00FCA411 /* env.c in Sources */,
+ 72220F9813330B0C00FCA411 /* ipp.c in Sources */,
+ 72220F9913330B0C00FCA411 /* job.c in Sources */,
+ 72220F9A13330B0C00FCA411 /* listen.c in Sources */,
+ 72220F9B13330B0C00FCA411 /* log.c in Sources */,
+ 72220F9C13330B0C00FCA411 /* main.c in Sources */,
+ 72220F9D13330B0C00FCA411 /* network.c in Sources */,
+ 72220F9E13330B0C00FCA411 /* policy.c in Sources */,
+ 72220F9F13330B0C00FCA411 /* printers.c in Sources */,
+ 72220FA013330B0C00FCA411 /* process.c in Sources */,
+ 72220FA113330B0C00FCA411 /* quotas.c in Sources */,
+ 72220FA313330B0C00FCA411 /* select.c in Sources */,
+ 72220FA413330B0C00FCA411 /* server.c in Sources */,
+ 72220FA513330B0C00FCA411 /* statbuf.c in Sources */,
+ 72220FA613330B0C00FCA411 /* subscriptions.c in Sources */,
+ 72220FA713330B0C00FCA411 /* sysman.c in Sources */,
+ 72C16CB9137B195D007E4BF4 /* file.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72220FA813330B2200FCA411 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72220FB613330BCE00FCA411 /* filter.c in Sources */,
+ 72220FB713330BCE00FCA411 /* mime.c in Sources */,
+ 72220FB913330BCE00FCA411 /* type.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724378F91333E43E009631B9 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7243790D1333E4E3009631B9 /* ipp.c in Sources */,
+ 7243790E1333E4E3009631B9 /* network.c in Sources */,
+ 7243790F1333E4E3009631B9 /* snmp-supplies.c in Sources */,
+ 724379131333E516009631B9 /* runloop.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724379141333E532009631B9 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724379221333E928009631B9 /* network.c in Sources */,
+ 724379231333E928009631B9 /* runloop.c in Sources */,
+ 724379241333E928009631B9 /* snmp-supplies.c in Sources */,
+ 724379291333E952009631B9 /* lpd.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7243792C1333FB85009631B9 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724379401333FD4B009631B9 /* network.c in Sources */,
+ 724379411333FD4B009631B9 /* runloop.c in Sources */,
+ 724379421333FD4B009631B9 /* snmp-supplies.c in Sources */,
+ 7243793D1333FD19009631B9 /* socket.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724379431333FEA9009631B9 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724379511333FEBB009631B9 /* dnssd.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724379571333FF1D009631B9 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724379C71333FFC7009631B9 /* usb.c in Sources */,
+ 724379CB1334000E009631B9 /* ieee1284.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7258EADE134594C4009286F1 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7258EAED134594EB009286F1 /* rastertopwg.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 726AD6F3135E88F0002C930D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 726AD702135E8A90002C930D /* ippserver.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72F75A4E1336F950004BB496 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72F75A5C1336F988004BB496 /* cupstestppd.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72F75A5D1336F9A3004BB496 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72F75A6C1336FA8A004BB496 /* error.c in Sources */,
+ 72F75A6D1336FA8A004BB496 /* interpret.c in Sources */,
+ 72F75A6E1336FA8A004BB496 /* raster.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 270CCDB2135E3CDE00007BE2 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 270CCDA6135E3C9E00007BE2 /* testmime */;
+ targetProxy = 270CCDB1135E3CDE00007BE2 /* PBXContainerItemProxy */;
+ };
+ 270CCDB6135E3CF700007BE2 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220FAB13330B2200FCA411 /* libcupsmime */;
+ targetProxy = 270CCDB5135E3CF700007BE2 /* PBXContainerItemProxy */;
+ };
+ 270CCDB8135E3CFD00007BE2 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF6891333B1C400317ECB /* libcups_static */;
+ targetProxy = 270CCDB7135E3CFD00007BE2 /* PBXContainerItemProxy */;
+ };
+ 273BF6C91333B5410022CAAB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF6891333B1C400317ECB /* libcups_static */;
+ targetProxy = 273BF6C81333B5410022CAAB /* PBXContainerItemProxy */;
+ };
+ 273BF6DE1333B6370022CAAB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 273BF6BC1333B5000022CAAB /* testcups */;
+ targetProxy = 273BF6DD1333B6370022CAAB /* PBXContainerItemProxy */;
+ };
+ 274FF5DC13332CF900317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 274FF5DB13332CF900317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF5E313332D4300317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 274FF5E213332D4300317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF5E513332D4300317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220FAB13330B2200FCA411 /* libcupsmime */;
+ targetProxy = 274FF5E413332D4300317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF5E713332D4300317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220F5A13330A5A00FCA411 /* cupsd */;
+ targetProxy = 274FF5E613332D4300317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF5E913332D4300317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF5CB13332B1F00317ECB /* cups-driverd */;
+ targetProxy = 274FF5E813332D4300317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF5F3133330FD00317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 274FF5F2133330FD00317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF6201333316200317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF5ED133330C800317ECB /* libcupsppdc */;
+ targetProxy = 274FF61F1333316200317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF622133331D300317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF5ED133330C800317ECB /* libcupsppdc */;
+ targetProxy = 274FF621133331D300317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF6341333335200317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 274FF6331333335200317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF6391333348400317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF6281333333600317ECB /* cups-deviced */;
+ targetProxy = 274FF6381333348400317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF648133335A300317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF63D1333358B00317ECB /* cups-exec */;
+ targetProxy = 274FF647133335A300317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF65A133339D900317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 274FF659133339D900317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF65E13333A3400317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF64E133339C400317ECB /* cups-lpd */;
+ targetProxy = 274FF65D13333A3400317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF66D13333AAD00317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 274FF66C13333AAD00317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF67213333AE400317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF66213333A9B00317ECB /* cups-polld */;
+ targetProxy = 274FF67113333AE400317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF68213333B3C00317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 274FF68113333B3C00317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF68413333B3C00317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220FAB13330B2200FCA411 /* libcupsmime */;
+ targetProxy = 274FF68313333B3C00317ECB /* PBXContainerItemProxy */;
+ };
+ 274FF6E21333B33F00317ECB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF67713333B2F00317ECB /* cupsfilter */;
+ targetProxy = 274FF6E11333B33F00317ECB /* PBXContainerItemProxy */;
+ };
+ 276683661337A9D6000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 276683651337A9D6000D33D0 /* PBXContainerItemProxy */;
+ };
+ 2766836B1337AA25000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2766835B1337A9B6000D33D0 /* cupsctl */;
+ targetProxy = 2766836A1337AA25000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683AE1337ACF9000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 276683AD1337ACF9000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683B01337ACF9000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF5ED133330C800317ECB /* libcupsppdc */;
+ targetProxy = 276683AF1337ACF9000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683B41337AD18000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 276683B31337AD18000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683B61337AD18000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF5ED133330C800317ECB /* libcupsppdc */;
+ targetProxy = 276683B51337AD18000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683BC1337AE49000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 276683BB1337AE49000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683BE1337AE49000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF5ED133330C800317ECB /* libcupsppdc */;
+ targetProxy = 276683BD1337AE49000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683C01337B1AD000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 276683BF1337B1AD000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683C21337B1AD000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF5ED133330C800317ECB /* libcupsppdc */;
+ targetProxy = 276683C11337B1AD000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683C61337B1BC000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 276683C51337B1BC000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683C81337B1BC000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF5ED133330C800317ECB /* libcupsppdc */;
+ targetProxy = 276683C71337B1BC000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683D71337B24A000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2766836F1337AC79000D33D0 /* ppdc */;
+ targetProxy = 276683D61337B24A000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683D91337B24A000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2766837C1337AC8C000D33D0 /* ppdhtml */;
+ targetProxy = 276683D81337B24A000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683DB1337B24A000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 276683891337AC97000D33D0 /* ppdi */;
+ targetProxy = 276683DA1337B24A000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683DD1337B24A000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 276683961337ACA2000D33D0 /* ppdmerge */;
+ targetProxy = 276683DC1337B24A000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683DF1337B24A000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 276683A31337ACAB000D33D0 /* ppdpo */;
+ targetProxy = 276683DE1337B24A000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683E11337B299000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 276683E01337B299000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683E41337B2BA000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72F75A601336F9A3004BB496 /* libcupsimage */;
+ targetProxy = 276683E31337B2BA000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683FC1337F7B3000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 276683FB1337F7B3000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276683FF1337F7C5000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 276683EF1337F78E000D33D0 /* ipptool */;
+ targetProxy = 276683FE1337F7C5000D33D0 /* PBXContainerItemProxy */;
+ };
+ 2766840E1337FA31000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 2766840D1337FA31000D33D0 /* PBXContainerItemProxy */;
+ };
+ 276684131337FA8D000D33D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 276684031337FA1D000D33D0 /* cupsaddsmb */;
+ targetProxy = 276684121337FA8D000D33D0 /* PBXContainerItemProxy */;
+ };
+ 278C58D6136B641D00836530 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 278C58CA136B640300836530 /* testhttp */;
+ targetProxy = 278C58D5136B641D00836530 /* PBXContainerItemProxy */;
+ };
+ 278C58D8136B642F00836530 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF6891333B1C400317ECB /* libcups_static */;
+ targetProxy = 278C58D7136B642F00836530 /* PBXContainerItemProxy */;
+ };
+ 720DD6CF1358FD790064AA82 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 720DD6CE1358FD790064AA82 /* PBXContainerItemProxy */;
+ };
+ 720DD6D11358FDBE0064AA82 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 720DD6C11358FD5F0064AA82 /* snmp */;
+ targetProxy = 720DD6D01358FDBE0064AA82 /* PBXContainerItemProxy */;
+ };
+ 72220F6513330A6500FCA411 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 72220F6413330A6500FCA411 /* PBXContainerItemProxy */;
+ };
+ 72220FBC13330C0500FCA411 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 72220FBB13330C0500FCA411 /* PBXContainerItemProxy */;
+ };
+ 72220FBE13330C0B00FCA411 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220FAB13330B2200FCA411 /* libcupsmime */;
+ targetProxy = 72220FBD13330C0B00FCA411 /* PBXContainerItemProxy */;
+ };
+ 724379071333E49B009631B9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 724379061333E49B009631B9 /* PBXContainerItemProxy */;
+ };
+ 724379111333E4EA009631B9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 724378FC1333E43E009631B9 /* ipp */;
+ targetProxy = 724379101333E4EA009631B9 /* PBXContainerItemProxy */;
+ };
+ 724379261333E932009631B9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 724379251333E932009631B9 /* PBXContainerItemProxy */;
+ };
+ 7243792B1333E962009631B9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 724379171333E532009631B9 /* lpd */;
+ targetProxy = 7243792A1333E962009631B9 /* PBXContainerItemProxy */;
+ };
+ 7243793A1333FB95009631B9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 724379391333FB95009631B9 /* PBXContainerItemProxy */;
+ };
+ 7243793F1333FD23009631B9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7243792F1333FB85009631B9 /* socket */;
+ targetProxy = 7243793E1333FD23009631B9 /* PBXContainerItemProxy */;
+ };
+ 724379531333FECE009631B9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 724379461333FEA9009631B9 /* dnssd */;
+ targetProxy = 724379521333FECE009631B9 /* PBXContainerItemProxy */;
+ };
+ 724379551333FEFE009631B9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 724379541333FEFE009631B9 /* PBXContainerItemProxy */;
+ };
+ 724379651333FF2E009631B9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 724379641333FF2E009631B9 /* PBXContainerItemProxy */;
+ };
+ 724379C31333FF7D009631B9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7243795A1333FF1D009631B9 /* usb */;
+ targetProxy = 724379C21333FF7D009631B9 /* PBXContainerItemProxy */;
+ };
+ 7258EAEF13459ADA009286F1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7258EAE1134594C4009286F1 /* rastertopwg */;
+ targetProxy = 7258EAEE13459ADA009286F1 /* PBXContainerItemProxy */;
+ };
+ 7258EAF113459B67009286F1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 7258EAF013459B67009286F1 /* PBXContainerItemProxy */;
+ };
+ 7258EAF313459B67009286F1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72F75A601336F9A3004BB496 /* libcupsimage */;
+ targetProxy = 7258EAF213459B67009286F1 /* PBXContainerItemProxy */;
+ };
+ 726AD704135E8AA1002C930D /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 726AD6F6135E88F0002C930D /* ippserver */;
+ targetProxy = 726AD703135E8AA1002C930D /* PBXContainerItemProxy */;
+ };
+ 726AD706135E8AC5002C930D /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 274FF6891333B1C400317ECB /* libcups_static */;
+ targetProxy = 726AD705135E8AC5002C930D /* PBXContainerItemProxy */;
+ };
+ 72F75A661336FA30004BB496 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72220EAD1333047D00FCA411 /* libcups */;
+ targetProxy = 72F75A651336FA30004BB496 /* PBXContainerItemProxy */;
+ };
+ 72F75A711336FACD004BB496 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72F75A601336F9A3004BB496 /* libcupsimage */;
+ targetProxy = 72F75A701336FACD004BB496 /* PBXContainerItemProxy */;
+ };
+ 72F75A731336FACD004BB496 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72F75A511336F950004BB496 /* cupstestppd */;
+ targetProxy = 72F75A721336FACD004BB496 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 270CCDAD135E3C9E00007BE2 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 270CCDAE135E3C9E00007BE2 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 273BF6C41333B5000022CAAB /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 273BF6C51333B5000022CAAB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 273BF6DB1333B6270022CAAB /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 273BF6DC1333B6270022CAAB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 274FF5D313332B1F00317ECB /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/daemon;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 274FF5D413332B1F00317ECB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/daemon;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 274FF5E013332D3100317ECB /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 274FF5E113332D3100317ECB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 274FF5F0133330C800317ECB /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = "";
+ INSTALL_PATH = /usr/lib;
+ PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/cups;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/include/cups;
+ };
+ name = Debug;
+ };
+ 274FF5F1133330C800317ECB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = "";
+ INSTALL_PATH = /usr/lib;
+ PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/cups;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/include/cups;
+ };
+ name = Release;
+ };
+ 274FF6301333333600317ECB /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/daemon;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 274FF6311333333600317ECB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/daemon;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 274FF6451333358C00317ECB /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/daemon;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 274FF6461333358C00317ECB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/daemon;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 274FF656133339C400317ECB /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/daemon;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 274FF657133339C400317ECB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/daemon;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 274FF66A13333A9B00317ECB /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/daemon;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 274FF66B13333A9B00317ECB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/daemon;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 274FF67F13333B2F00317ECB /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 274FF68013333B2F00317ECB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 274FF6DE1333B1C400317ECB /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_EXTENSION = a;
+ EXECUTABLE_PREFIX = "";
+ INSTALL_PATH = /usr/local/lib;
+ PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/cups;
+ PRODUCT_NAME = libcups_static;
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/include/cups;
+ STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = static;
+ };
+ name = Debug;
+ };
+ 274FF6DF1333B1C400317ECB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_EXTENSION = a;
+ EXECUTABLE_PREFIX = "";
+ INSTALL_PATH = /usr/local/lib;
+ PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/cups;
+ PRODUCT_NAME = libcups_static;
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/include/cups;
+ STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = static;
+ };
+ name = Release;
+ };
+ 276683631337A9B6000D33D0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 276683641337A9B6000D33D0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 276683771337AC79000D33D0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 276683781337AC79000D33D0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 276683841337AC8C000D33D0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 276683851337AC8C000D33D0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 276683911337AC97000D33D0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 276683921337AC97000D33D0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 2766839E1337ACA2000D33D0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 2766839F1337ACA2000D33D0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 276683AB1337ACAB000D33D0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 276683AC1337ACAB000D33D0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 276683F71337F78F000D33D0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 276683F81337F78F000D33D0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 2766840B1337FA1E000D33D0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 2766840C1337FA1E000D33D0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 278C58D1136B640300836530 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 278C58D2136B640300836530 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 720DD6C91358FD5F0064AA82 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/backend;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 720DD6CA1358FD5F0064AA82 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/backend;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 72220EB01333047D00FCA411 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = "";
+ INSTALL_PATH = /usr/lib;
+ PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/cups;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/include/cups;
+ };
+ name = Debug;
+ };
+ 72220EB11333047D00FCA411 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = "";
+ INSTALL_PATH = /usr/lib;
+ PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/cups;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PUBLIC_HEADERS_FOLDER_PATH = /usr/include/cups;
+ };
+ name = Release;
+ };
+ 72220F6213330A5A00FCA411 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 72220F6313330A5A00FCA411 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 72220FAE13330B2300FCA411 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = "";
+ INSTALL_PATH = /usr/lib;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 72220FAF13330B2300FCA411 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = "";
+ INSTALL_PATH = /usr/lib;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 724379041333E43E009631B9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_MODE_FLAG = "u+rwX,go-rwX";
+ INSTALL_PATH = /usr/libexec/cups/backend;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 724379051333E43E009631B9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_MODE_FLAG = "u+rwX,go-rwX";
+ INSTALL_PATH = /usr/libexec/cups/backend;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 7243791F1333E532009631B9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/backend;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 724379201333E532009631B9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/backend;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 724379371333FB85009631B9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/backend;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 724379381333FB85009631B9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/backend;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 7243794E1333FEA9009631B9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/backend;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 7243794F1333FEA9009631B9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/backend;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 724379621333FF1D009631B9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/backend;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 724379631333FF1D009631B9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/backend;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 7258EAEA134594C4009286F1 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/filter;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 7258EAEB134594C4009286F1 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec/cups/filter;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 726AD6FF135E88F1002C930D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 726AD700135E88F1002C930D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 72BF963C1333042100B1EAD7 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(NATIVE_ARCH_ACTUAL)";
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_SHADOW = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_PARAMETER = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ .,
+ ..,
+ );
+ OTHER_CFLAGS = (
+ "-D_CUPS_SOURCE",
+ "-Wno-shorten-64-to-32",
+ );
+ };
+ name = Debug;
+ };
+ 72BF963D1333042100B1EAD7 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_SHADOW = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_PARAMETER = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ .,
+ ..,
+ );
+ OTHER_CFLAGS = (
+ "-D_CUPS_SOURCE",
+ "-Wno-shorten-64-to-32",
+ );
+ };
+ name = Release;
+ };
+ 72F75A591336F951004BB496 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 72F75A5A1336F951004BB496 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 72F75A631336F9A3004BB496 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = "";
+ INSTALL_PATH = /usr/lib;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 72F75A641336F9A3004BB496 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = "";
+ INSTALL_PATH = /usr/lib;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 270CCDAF135E3C9E00007BE2 /* Build configuration list for PBXNativeTarget "testmime" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 270CCDAD135E3C9E00007BE2 /* Debug */,
+ 270CCDAE135E3C9E00007BE2 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 273BF6C31333B5000022CAAB /* Build configuration list for PBXNativeTarget "testcups" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 273BF6C41333B5000022CAAB /* Debug */,
+ 273BF6C51333B5000022CAAB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 273BF6DA1333B6270022CAAB /* Build configuration list for PBXAggregateTarget "Tests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 273BF6DB1333B6270022CAAB /* Debug */,
+ 273BF6DC1333B6270022CAAB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 274FF5D213332B1F00317ECB /* Build configuration list for PBXNativeTarget "cups-driverd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 274FF5D313332B1F00317ECB /* Debug */,
+ 274FF5D413332B1F00317ECB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 274FF5DF13332D3100317ECB /* Build configuration list for PBXAggregateTarget "All" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 274FF5E013332D3100317ECB /* Debug */,
+ 274FF5E113332D3100317ECB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 274FF5EF133330C800317ECB /* Build configuration list for PBXNativeTarget "libcupsppdc" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 274FF5F0133330C800317ECB /* Debug */,
+ 274FF5F1133330C800317ECB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 274FF62F1333333600317ECB /* Build configuration list for PBXNativeTarget "cups-deviced" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 274FF6301333333600317ECB /* Debug */,
+ 274FF6311333333600317ECB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 274FF6441333358C00317ECB /* Build configuration list for PBXNativeTarget "cups-exec" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 274FF6451333358C00317ECB /* Debug */,
+ 274FF6461333358C00317ECB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 274FF655133339C400317ECB /* Build configuration list for PBXNativeTarget "cups-lpd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 274FF656133339C400317ECB /* Debug */,
+ 274FF657133339C400317ECB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 274FF66913333A9B00317ECB /* Build configuration list for PBXNativeTarget "cups-polld" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 274FF66A13333A9B00317ECB /* Debug */,
+ 274FF66B13333A9B00317ECB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 274FF67E13333B2F00317ECB /* Build configuration list for PBXNativeTarget "cupsfilter" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 274FF67F13333B2F00317ECB /* Debug */,
+ 274FF68013333B2F00317ECB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 274FF6DD1333B1C400317ECB /* Build configuration list for PBXNativeTarget "libcups_static" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 274FF6DE1333B1C400317ECB /* Debug */,
+ 274FF6DF1333B1C400317ECB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 276683621337A9B6000D33D0 /* Build configuration list for PBXNativeTarget "cupsctl" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 276683631337A9B6000D33D0 /* Debug */,
+ 276683641337A9B6000D33D0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 276683761337AC79000D33D0 /* Build configuration list for PBXNativeTarget "ppdc" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 276683771337AC79000D33D0 /* Debug */,
+ 276683781337AC79000D33D0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 276683831337AC8C000D33D0 /* Build configuration list for PBXNativeTarget "ppdhtml" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 276683841337AC8C000D33D0 /* Debug */,
+ 276683851337AC8C000D33D0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 276683901337AC97000D33D0 /* Build configuration list for PBXNativeTarget "ppdi" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 276683911337AC97000D33D0 /* Debug */,
+ 276683921337AC97000D33D0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2766839D1337ACA2000D33D0 /* Build configuration list for PBXNativeTarget "ppdmerge" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2766839E1337ACA2000D33D0 /* Debug */,
+ 2766839F1337ACA2000D33D0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 276683AA1337ACAB000D33D0 /* Build configuration list for PBXNativeTarget "ppdpo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 276683AB1337ACAB000D33D0 /* Debug */,
+ 276683AC1337ACAB000D33D0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 276683F61337F78F000D33D0 /* Build configuration list for PBXNativeTarget "ipptool" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 276683F71337F78F000D33D0 /* Debug */,
+ 276683F81337F78F000D33D0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2766840A1337FA1E000D33D0 /* Build configuration list for PBXNativeTarget "cupsaddsmb" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2766840B1337FA1E000D33D0 /* Debug */,
+ 2766840C1337FA1E000D33D0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 278C58D3136B640300836530 /* Build configuration list for PBXNativeTarget "testhttp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 278C58D1136B640300836530 /* Debug */,
+ 278C58D2136B640300836530 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 720DD6CB1358FD600064AA82 /* Build configuration list for PBXNativeTarget "snmp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 720DD6C91358FD5F0064AA82 /* Debug */,
+ 720DD6CA1358FD5F0064AA82 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72220EB21333047D00FCA411 /* Build configuration list for PBXNativeTarget "libcups" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72220EB01333047D00FCA411 /* Debug */,
+ 72220EB11333047D00FCA411 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72220F6113330A5A00FCA411 /* Build configuration list for PBXNativeTarget "cupsd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72220F6213330A5A00FCA411 /* Debug */,
+ 72220F6313330A5A00FCA411 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72220FAD13330B2300FCA411 /* Build configuration list for PBXNativeTarget "libcupsmime" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72220FAE13330B2300FCA411 /* Debug */,
+ 72220FAF13330B2300FCA411 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 724379031333E43E009631B9 /* Build configuration list for PBXNativeTarget "ipp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 724379041333E43E009631B9 /* Debug */,
+ 724379051333E43E009631B9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7243791E1333E532009631B9 /* Build configuration list for PBXNativeTarget "lpd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7243791F1333E532009631B9 /* Debug */,
+ 724379201333E532009631B9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 724379361333FB85009631B9 /* Build configuration list for PBXNativeTarget "socket" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 724379371333FB85009631B9 /* Debug */,
+ 724379381333FB85009631B9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7243794D1333FEA9009631B9 /* Build configuration list for PBXNativeTarget "dnssd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7243794E1333FEA9009631B9 /* Debug */,
+ 7243794F1333FEA9009631B9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 724379611333FF1D009631B9 /* Build configuration list for PBXNativeTarget "usb" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 724379621333FF1D009631B9 /* Debug */,
+ 724379631333FF1D009631B9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7258EAE9134594C4009286F1 /* Build configuration list for PBXNativeTarget "rastertopwg" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7258EAEA134594C4009286F1 /* Debug */,
+ 7258EAEB134594C4009286F1 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 726AD6FE135E88F1002C930D /* Build configuration list for PBXNativeTarget "ippserver" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 726AD6FF135E88F1002C930D /* Debug */,
+ 726AD700135E88F1002C930D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72BF963A1333042100B1EAD7 /* Build configuration list for PBXProject "CUPS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72BF963C1333042100B1EAD7 /* Debug */,
+ 72BF963D1333042100B1EAD7 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72F75A581336F951004BB496 /* Build configuration list for PBXNativeTarget "cupstestppd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72F75A591336F951004BB496 /* Debug */,
+ 72F75A5A1336F951004BB496 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72F75A621336F9A3004BB496 /* Build configuration list for PBXNativeTarget "libcupsimage" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72F75A631336F9A3004BB496 /* Debug */,
+ 72F75A641336F9A3004BB496 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 72BF96371333042100B1EAD7 /* Project object */;
+}
diff --git a/xcode/config.h b/xcode/config.h
new file mode 100644
index 000000000..6574617cc
--- /dev/null
+++ b/xcode/config.h
@@ -0,0 +1,736 @@
+/* config.h. Generated from config.h.in by configure. */
+/*
+ * "$Id$"
+ *
+ * Configuration file for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPS_CONFIG_H_
+#define _CUPS_CONFIG_H_
+
+/*
+ * Version of software...
+ */
+
+#define CUPS_SVERSION "CUPS v1.5.0"
+#define CUPS_MINIMAL "CUPS/1.5.0"
+
+
+/*
+ * Default user and groups...
+ */
+
+#define CUPS_DEFAULT_USER "_lp"
+#define CUPS_DEFAULT_GROUP "_lp"
+#define CUPS_DEFAULT_SYSTEM_GROUPS "admin"
+#define CUPS_DEFAULT_PRINTOPERATOR_AUTH "@AUTHKEY(system.print.operator) @admin @lpadmin"
+
+
+/*
+ * Default file permissions...
+ */
+
+#define CUPS_DEFAULT_CONFIG_FILE_PERM 0644
+#define CUPS_DEFAULT_LOG_FILE_PERM 0644
+
+
+/*
+ * Default logging settings...
+ */
+
+#define CUPS_DEFAULT_LOG_LEVEL "warn"
+#define CUPS_DEFAULT_ACCESS_LOG_LEVEL "actions"
+
+
+/*
+ * Default fatal error settings...
+ */
+
+#define CUPS_DEFAULT_FATAL_ERRORS "config"
+
+
+/*
+ * Default browsing settings...
+ */
+
+#define CUPS_DEFAULT_BROWSING 1
+#define CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS "CUPS dnssd"
+#define CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS ""
+#define CUPS_DEFAULT_BROWSE_SHORT_NAMES 1
+#define CUPS_DEFAULT_DEFAULT_SHARED 1
+#define CUPS_DEFAULT_IMPLICIT_CLASSES 1
+#define CUPS_DEFAULT_USE_NETWORK_DEFAULT 0
+
+
+/*
+ * Default IPP port...
+ */
+
+#define CUPS_DEFAULT_IPP_PORT 631
+
+
+/*
+ * Default printcap file...
+ */
+
+#define CUPS_DEFAULT_PRINTCAP "/Library/Preferences/org.cups.printers.plist"
+
+
+/*
+ * Default Samba and LPD config files...
+ */
+
+#define CUPS_DEFAULT_SMB_CONFIG_FILE ""
+#define CUPS_DEFAULT_LPD_CONFIG_FILE "launchd:///System/Library/LaunchDaemons/org.cups.cups-lpd.plist"
+
+
+/*
+ * Default MaxCopies value...
+ */
+
+#define CUPS_DEFAULT_MAX_COPIES 9999
+
+
+/*
+ * Do we have domain socket support, and if so what is the default one?
+ */
+
+#define CUPS_DEFAULT_DOMAINSOCKET "/private/var/run/cupsd"
+
+
+/*
+ * Default WebInterface value...
+ */
+
+#define CUPS_DEFAULT_WEBIF 0
+
+
+/*
+ * Where are files stored?
+ *
+ * Note: These are defaults, which can be overridden by environment
+ * variables at run-time...
+ */
+
+#define CUPS_BINDIR "/usr/bin"
+#define CUPS_CACHEDIR "/private/var/spool/cups/cache"
+#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 "/private/var/log/cups"
+#define CUPS_REQUESTS "/private/var/spool/cups"
+#define CUPS_SBINDIR "/usr/sbin"
+#define CUPS_SERVERBIN "/usr/libexec/cups"
+#define CUPS_SERVERROOT "/private/etc/cups"
+#define CUPS_STATEDIR "/private/etc/cups"
+
+
+/*
+ * Do we have various image libraries?
+ */
+
+/* #undef HAVE_LIBPNG */
+#define HAVE_LIBZ 1
+/* #undef HAVE_LIBJPEG */
+/* #undef HAVE_LIBTIFF */
+
+
+/*
+ * Do we have PAM stuff?
+ */
+
+#ifndef HAVE_LIBPAM
+#define HAVE_LIBPAM 1
+#endif /* !HAVE_LIBPAM */
+
+/* #undef HAVE_PAM_PAM_APPL_H */
+#define HAVE_PAM_SET_ITEM 1
+#define HAVE_PAM_SETCRED 1
+
+
+/*
+ * Do we have <shadow.h>?
+ */
+
+/* #undef HAVE_SHADOW_H */
+
+
+/*
+ * Do we have <crypt.h>?
+ */
+
+/* #undef HAVE_CRYPT_H */
+
+
+/*
+ * Do we have <scsi/sg.h>?
+ */
+
+/* #undef HAVE_SCSI_SG_H */
+
+
+/*
+ * Use <string.h>, <strings.h>, and/or <bstring.h>?
+ */
+
+#define HAVE_STRING_H 1
+#define HAVE_STRINGS_H 1
+/* #undef HAVE_BSTRING_H */
+
+/*
+ * Do we have the long long type?
+ */
+
+#define HAVE_LONG_LONG 1
+
+#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?
+ */
+
+#define HAVE_STRTOLL 1
+
+#ifndef HAVE_STRTOLL
+# define strtoll(nptr,endptr,base) strtol((nptr), (endptr), (base))
+#endif /* !HAVE_STRTOLL */
+
+/*
+ * Do we have the strXXX() functions?
+ */
+
+#define HAVE_STRDUP 1
+#define HAVE_STRLCAT 1
+#define HAVE_STRLCPY 1
+
+
+/*
+ * Do we have the geteuid() function?
+ */
+
+#define HAVE_GETEUID 1
+
+
+/*
+ * Do we have the setpgid() function?
+ */
+
+#define HAVE_SETPGID 1
+
+
+/*
+ * Do we have the vsyslog() function?
+ */
+
+#define HAVE_VSYSLOG 1
+
+
+/*
+ * Do we have the (v)snprintf() functions?
+ */
+
+#define HAVE_SNPRINTF 1
+#define HAVE_VSNPRINTF 1
+
+
+/*
+ * What signal functions to use?
+ */
+
+#define HAVE_SIGSET 1
+#define HAVE_SIGACTION 1
+
+
+/*
+ * What wait functions to use?
+ */
+
+#define HAVE_WAITPID 1
+#define HAVE_WAIT3 1
+
+
+/*
+ * Do we have the mallinfo function and malloc.h?
+ */
+
+/* #undef HAVE_MALLINFO */
+/* #undef HAVE_MALLOC_H */
+
+
+/*
+ * Do we have the POSIX ACL functions?
+ */
+
+#define HAVE_ACL_INIT 1
+
+
+/*
+ * Do we have the langinfo.h header file?
+ */
+
+#define HAVE_LANGINFO_H 1
+
+
+/*
+ * Which encryption libraries do we have?
+ */
+
+#define HAVE_CDSASSL 1
+/* #undef HAVE_GNUTLS */
+/* #undef HAVE_LIBSSL */
+#define HAVE_SSL 1
+
+
+/*
+ * What Security framework headers do we have?
+ */
+
+#define HAVE_AUTHORIZATION_H 1
+#define HAVE_SECCERTIFICATE_H 1
+#define HAVE_SECITEM_H 1
+/* #undef HAVE_SECITEMPRIV_H */
+#define HAVE_SECPOLICY_H 1
+/* #undef HAVE_SECPOLICYPRIV_H */
+/* #undef HAVE_SECBASEPRIV_H */
+/* #undef HAVE_SECIDENTITYSEARCHPRIV_H */
+
+
+/*
+ * Do we have the SecCertificateCopyData function?
+ */
+
+#define HAVE_SECCERTIFICATECOPYDATA 1
+
+
+/*
+ * Do we have the SecIdentitySearchCreateWithPolicy function?
+ */
+
+#define HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY 1
+
+
+/*
+ * Do we have the SecPolicyCreateSSL function?
+ */
+
+#define HAVE_SECPOLICYCREATESSL 1
+
+
+/*
+ * Do we have the SecPolicyCreateSSL function?
+ */
+
+#define HAVE_SECPOLICYCREATESSL 1
+
+
+/*
+ * Do we have the cssmErrorString function?
+ */
+
+#define HAVE_CSSMERRORSTRING 1
+
+
+/*
+ * Do we have the SLP library?
+ */
+
+/* #undef HAVE_LIBSLP */
+
+
+/*
+ * Do we have an LDAP library?
+ */
+
+#define HAVE_LDAP 1
+#define HAVE_OPENLDAP 1
+/* #undef HAVE_MOZILLA_LDAP */
+/* #undef HAVE_LDAP_SSL_H */
+/* #undef HAVE_LDAP_SSL */
+#define HAVE_LDAP_REBIND_PROC 1
+
+
+/*
+ * Do we have libpaper?
+ */
+
+/* #undef HAVE_LIBPAPER */
+
+
+/*
+ * Do we have DNS Service Discovery (aka Bonjour)?
+ */
+
+#define HAVE_DNSSD 1
+
+
+/*
+ * Do we have <sys/ioctl.h>?
+ */
+
+#define HAVE_SYS_IOCTL_H 1
+
+
+/*
+ * Does the "stat" structure contain the "st_gen" member?
+ */
+
+#define HAVE_ST_GEN 1
+
+
+/*
+ * Does the "tm" structure contain the "tm_gmtoff" member?
+ */
+
+#define HAVE_TM_GMTOFF 1
+
+
+/*
+ * Do we have rresvport_af()?
+ */
+
+#define HAVE_RRESVPORT_AF 1
+
+
+/*
+ * Do we have getaddrinfo()?
+ */
+
+#define HAVE_GETADDRINFO 1
+
+
+/*
+ * Do we have getnameinfo()?
+ */
+
+#define HAVE_GETNAMEINFO 1
+
+
+/*
+ * Do we have getifaddrs()?
+ */
+
+#define HAVE_GETIFADDRS 1
+
+
+/*
+ * Do we have hstrerror()?
+ */
+
+#define HAVE_HSTRERROR 1
+
+
+/*
+ * Do we have res_init()?
+ */
+
+#define HAVE_RES_INIT 1
+
+
+/*
+ * Do we have <resolv.h>
+ */
+
+#define HAVE_RESOLV_H 1
+
+
+/*
+ * Do we have the <sys/sockio.h> header file?
+ */
+
+#define HAVE_SYS_SOCKIO_H 1
+
+
+/*
+ * 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?
+ */
+
+#define HAVE_PTHREAD_H 1
+
+
+/*
+ * Do we have launchd support?
+ */
+
+#define HAVE_LAUNCH_H 1
+#define HAVE_LAUNCHD 1
+
+
+/*
+ * Various scripting languages...
+ */
+
+#define HAVE_JAVA 1
+#define CUPS_JAVA "/usr/bin/java"
+#define HAVE_PERL 1
+#define CUPS_PERL "/usr/bin/perl"
+#define HAVE_PHP 1
+#define CUPS_PHP "/usr/bin/php"
+#define HAVE_PYTHON 1
+#define CUPS_PYTHON "/usr/bin/python"
+
+
+/*
+ * Location of the poppler/Xpdf pdftops program...
+ */
+
+/* #undef HAVE_PDFTOPS */
+#define CUPS_PDFTOPS ""
+
+
+/*
+ * Location of the Ghostscript gs program...
+ */
+
+/* #undef HAVE_GHOSTSCRIPT */
+#define CUPS_GHOSTSCRIPT ""
+
+
+/*
+ * Do we have Darwin's CoreFoundation and SystemConfiguration frameworks?
+ */
+
+#define HAVE_COREFOUNDATION 1
+#define HAVE_SYSTEMCONFIGURATION 1
+
+
+/*
+ * Do we have CoreFoundation public and private headers?
+ */
+
+#define HAVE_COREFOUNDATION_H 1
+/* #undef HAVE_CFPRIV_H */
+/* #undef HAVE_CFBUNDLEPRIV_H */
+
+
+/*
+ * Do we have ApplicationServices public headers?
+ */
+
+#define HAVE_APPLICATIONSERVICES_H 1
+
+
+/*
+ * Do we have the SCDynamicStoreCopyComputerName function?
+ */
+
+#define HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME 1
+
+
+/*
+ * Do we have MacOSX 10.4's mbr_XXX functions?
+ */
+
+#define HAVE_MEMBERSHIP_H 1
+/* #undef HAVE_MEMBERSHIPPRIV_H */
+#define HAVE_MBR_UID_TO_UUID 1
+
+
+/*
+ * Do we have Darwin's notify_post header and function?
+ */
+
+#define HAVE_NOTIFY_H 1
+#define HAVE_NOTIFY_POST 1
+
+
+/*
+ * Do we have DBUS?
+ */
+
+/* #undef HAVE_DBUS */
+/* #undef HAVE_DBUS_MESSAGE_ITER_INIT_APPEND */
+
+
+/*
+ * Do we have the AppleTalk/at_proto.h header?
+ */
+
+/* #undef HAVE_APPLETALK_AT_PROTO_H */
+
+
+/*
+ * Do we have the GSSAPI support library (for Kerberos support)?
+ */
+
+/* #undef HAVE_GSS_ACQUIRE_CRED_EX_F */
+#define HAVE_GSS_C_NT_HOSTBASED_SERVICE 1
+/* #undef HAVE_GSS_GSSAPI_H */
+/* #undef HAVE_GSS_GSSAPI_SPI_H */
+#define HAVE_GSSAPI 1
+#define HAVE_GSSAPI_H 1
+#define HAVE_GSSAPI_GSSAPI_H 1
+#define HAVE_GSSAPI_GSSAPI_GENERIC_H 1
+#define HAVE_GSSAPI_GSSAPI_KRB5_H 1
+#define HAVE_KRB5_H 1
+
+
+/*
+ * Default GSS service name...
+ */
+
+#define CUPS_DEFAULT_GSSSERVICENAME "host"
+
+
+/*
+ * Select/poll interfaces...
+ */
+
+#define HAVE_POLL 1
+/* #undef HAVE_EPOLL */
+#define HAVE_KQUEUE 1
+
+
+/*
+ * Do we have the <dlfcn.h> header?
+ */
+
+#define HAVE_DLFCN_H 1
+
+
+/*
+ * Do we have <sys/param.h>?
+ */
+
+#define HAVE_SYS_PARAM_H 1
+
+
+/*
+ * Do we have <sys/ucred.h>?
+ */
+
+#define HAVE_SYS_UCRED_H 1
+
+
+/*
+ * Do we have removefile()?
+ */
+
+#define HAVE_REMOVEFILE 1
+
+
+/*
+ * Do we have <sandbox.h>?
+ */
+
+#define HAVE_SANDBOX_H 1
+
+
+/*
+ * Which random number generator function to use...
+ */
+
+#define HAVE_ARC4RANDOM 1
+#define HAVE_RANDOM 1
+#define HAVE_LRAND48 1
+
+#ifdef HAVE_ARC4RANDOM
+# define CUPS_RAND() arc4random()
+# define CUPS_SRAND(v) arc4random_stir()
+#elif defined(HAVE_RANDOM)
+# define CUPS_RAND() random()
+# define CUPS_SRAND(v) srandom(v)
+#elif defined(HAVE_LRAND48)
+# define CUPS_RAND() lrand48()
+# define CUPS_SRAND(v) srand48(v)
+#else
+# define CUPS_RAND() rand()
+# define CUPS_SRAND(v) srand(v)
+#endif /* HAVE_ARC4RANDOM */
+
+
+/*
+ * Do we have vproc_transaction_begin/end?
+ */
+
+#define HAVE_VPROC_TRANSACTION_BEGIN 1
+
+
+/*
+ * Do we have libusb?
+ */
+
+/* #undef HAVE_USB_H */
+
+
+/*
+ * Do we have libwrap and tcpd.h?
+ */
+
+/* #undef HAVE_TCPD_H */
+
+
+/*
+ * Do we have <iconv.h>?
+ */
+
+#define HAVE_ICONV_H 1
+
+
+/*
+ * Do we have statfs or statvfs and one of the corresponding headers?
+ */
+
+#define HAVE_STATFS 1
+#define HAVE_STATVFS 1
+#define HAVE_SYS_MOUNT_H 1
+/* #undef HAVE_SYS_STATFS_H */
+#define HAVE_SYS_STATVFS_H 1
+/* #undef HAVE_SYS_VFS_H */
+
+
+/*
+ * Location of Mac OS X localization bundle, if any.
+ */
+
+#define CUPS_BUNDLEDIR "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/PrintCore.framework/Versions/A"
+
+
+/*
+ * Do we have the ColorSyncRegisterDevice function?
+ */
+
+#define HAVE_COLORSYNCREGISTERDEVICE 1
+
+
+/*
+ * Do we have XPC?
+ */
+
+/* #undef HAVE_XPC */
+
+
+#endif /* !_CUPS_CONFIG_H_ */
+
+/*
+ * End of "$Id$".
+ */